pax_global_header00006660000000000000000000000064136052114470014515gustar00rootroot0000000000000052 comment=092b7f2f7dfab0f9ea7cbb6c1db2e5dffd2c1045 connectome-workbench-1.4.2/000077500000000000000000000000001360521144700156335ustar00rootroot00000000000000connectome-workbench-1.4.2/.gitignore000066400000000000000000000001111360521144700176140ustar00rootroot00000000000000*.kdev4 CMakeLists.txt.user* build release debug *.kate-swp .DS_Store *~ connectome-workbench-1.4.2/.travis.yml000066400000000000000000000011711360521144700177440ustar00rootroot00000000000000language: cpp dist: bionic notifications: email: false cache: - apt - ccache git: depth: 3 addons: apt: packages: - qtbase5-dev - libqt5opengl5-dev - zlib1g-dev - libosmesa6-dev - libssl-dev - libqwt-dev - libfreetype6-dev - libftgl-dev env: global: - OMP_NUM_THREADS=4 before_install: - mkdir ../build - cd ../build script: - cmake -D CMAKE_CXX_FLAGS="-W -Wall -Wno-narrowing" -D CMAKE_BUILD_TYPE=Release -D WORKBENCH_MESA_DIR=/usr ../workbench/src - make -j 4 - ctest connectome-workbench-1.4.2/Doxyfile000066400000000000000000000016651360521144700173510ustar00rootroot00000000000000PROJECT_NAME = Caret7 OUTPUT_DIRECTORY = ../documentation OUTPUT_LANGUAGE = English EXTRACT_ALL = YES EXTRACT_PRIVATE = YES HAVE_DOT = YES DOT_PATH = /usr/local/graphviz-2.14/bin CLASS_GRAPH = YES CALL_GRAPH = NO CALLER_GRAPH = NO COLLABORATION_GRAPH = NO DIRECTORY_GRAPH = YES SOURCE_BROWSER = YES ALPHABETICAL_INDEX = YES JAVADOC_AUTOBRIEF = YES GENERATE_HTML = YES GENERATE_LATEX = NO GENERATE_MAN = NO GENERATE_RTF = NO CREATE_SUBDIRS = YES SUBGROUPING = YES INPUT = \ src/Algorithms \ src/Annotations \ src/Brain \ src/Charting \ src/Cifti \ src/CommandLine \ src/Commands \ src/Common \ src/Desktop \ src/Files \ src/FilesBase \ src/FtglFont \ src/Gifti \ src/Graphics \ src/GuiQt \ src/Nifti \ src/OSMesaDummy \ src/Operations \ src/OperationsBase \ src/Palette \ src/Quazip \ src/Qwt \ src/Scenes \ src/Tests \ src/Xml FILE_PATTERNS = *.cxx *.h connectome-workbench-1.4.2/LICENSE000066400000000000000000000432541360521144700166500ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser General Public License instead of this License. connectome-workbench-1.4.2/README000066400000000000000000000111101360521144700165050ustar00rootroot00000000000000Connectome Workbench requires QT5 to compile. Recommended is version 5.6 or later (due to an issue with the toolbar size on earlier versions). It is highly recommended to compile with OSMesa, which allow the -show-scene command and the "render pixmap" image capture method to work. Use it by setting the *cmake* variable WORKBENCH_MESA_DIR, such that ${WORKBENCH_MESA_DIR}/include/GL/osmesa.h exists. It is compiled using cmake, for example, on linux you can do: mkdir build cd build cmake -D CMAKE_BUILD_TYPE=Release -D WORKBENCH_MESA_DIR=/usr -D WORKBENCH_USE_QT5=TRUE ../workbench/src nice make -j8 For other OSes, see http://www.cmake.org/cmake/help/runningcmake.html Note the -j flag of "make" is used in the example to speed up the build by compiling multiple source files at the same time. If you have a different number of cores/hardware threads or want to reduce the load, adjust it accordingly. The "nice" command is not needed, it is used to make the compilation have less priority than other processes. This produces 3 executables, 2 of which are useful to the end user (Desktop/wb_view, CommandLine/wb_command), and one for running internal tests (Tests/test_driver). To run the (few) tests available: ctest #OR make test To install wb_view, wb_command, wb_shortcuts, and the bash completion script to the default locations: make install It should be noted that wb_import, provided in the HCP binary releases of Connectome Workbench, is actually part of caret5 (http://brainvis.wustl.edu/wiki/index.php/Caret:Download). Connectome Workbench itself is licensed under GPLv2 or later, copyright 2014-2018 Washington University School of Medicine, see LICENSE file Some source files are licensed under an MIT license (Expat), for easier code reuse in non-GPL projects: Files/SurfaceResamplingHelper.cxx Cifti/examples/* CommandLine/wb_shortcuts CommandLine/bashcomplete_wb_* Copyright (C) 2014-2018 Washington University School of Medicine Some included code/files are from third party sources, with the following licenses: kloewe/*: Copyright (c) 2012-2017 Kristian Loewe, Christian Borgelt licensed under MIT (Expat), see kloewe/dot/LICENSE and kloewe/cpuinfo/LICENSE Quazip/*: QuaZIP 0.6, http://quazip.sourceforge.net/ Copyright (C) 2005-2012 Sergey A. Tachenov Copyright (C) 1998-2010 Gilles Vollant Copyright (C) 2009-2010 Mathias Svensson Copyright (C) 2007-2008 Even Rouault Copyright (c) 1990-2000 Info-ZIP licensed under LGPLv2 and zlib, see Quazip/COPYING, Quazip/quazip.h, Quazip/zip.h and Quazip/unzip.c Qwt/*: Copyright (C) 1997 Josef Wilgen Copyright (C) 2002 Uwe Rathmann Qwt 6.0.1, http://qwt.sourceforge.net/ licensed under Qwt license v1.0 (LGPLv2.1, with exceptions), see src/Qwt/COPYING some unneeded files removed FtglFont/*: FTGL library Copyright (C) 2001-2004 Henry Maddocks Copyright (C) 2008 Daniel Remenak Copyright (C) 2008 Éric Beets Copyright (C) 2008 Sam Hocevar Copyright (C) 2008 Sean Morrison licensed under Expat, see FtglFont/COPYING GLMath/* Copyright (c) 2005 - 2014 G-Truc Creation licensed under "Happy Bunny" or Expat, see GLMath/copying.txt Common/Base64.*, Common/DataCompressZLib.*, Common/MathFunctions.*, Nifti/Matrix4x4.cxx: use code from VTK, http://www.kitware.com/opensource/vtk.html or http://www.vtk.org/ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen originally licensed under BSD 3-clause, see http://www.kitware.com/Copyright.htm or http://www.vtk.org/VTK/project/license.html GuiQt/WuQDialog.cxx, Brain/FtglFontTextRenderer.cxx: copied some code from from QT4, https://qt-project.org/ Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). originally licensed LGPLv2.1 (or GPLv3, or a commercial license) modified to change some UI behaviors otherwise hardcoded into QT classes Files/SignedDistanceHelper.cxx, Files/RibbonMappingHelper.cxx: make use of PNPOLY, http://www.ecse.rpi.edu/~wrf/Research/Short_Notes/pnpoly.html Copyright (c) 1970-2003, Wm. Randolph Franklin originally licensed with 3-clause BSD/MIT license, see files in question rewritten for different argument types, modified Resources/FtglFonts/Vera*.ttf Copyright (c) 2003 Bitstream, Inc. licensed under Bitstream-Vera (basically, modification of fonts requires calling them something else), see debian/copyright file Files/PaletteFile.cxx copied some palette definitions from matplotlib and its original sources Copyright (c) 2012-2016 Matplotlib Development Team Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and The Pennsylvania State University licensed apache-2 and MDT (bsd-like) connectome-workbench-1.4.2/README_BUGS.txt000066400000000000000000000015271360521144700201560ustar00rootroot00000000000000 ********************************************************************************** CMake Error in Tests/CMakeLists.txt: No known features for CXX compiler "Clang" version 4.0.0. --------------------------------------------------------------------------------- CMake does not recognize the compiler and it fails to find the compiler's features. We have seen this problem with Clang 4.0.0 and Qt 5.7.0 on Mac OS X. It is a documented Qt bug. Qt Bug 5466: https://bugreports.qt.io/browse/QTBUG-54666 The solution with Qt 5.7.0 is: (1) Edit /lib/cmake/Qt5Core/Qt5CoreConfigExtras.cmake (2) Comment out the line "set_property(TARGET Qt5::Core PROPERTY INTERFACE_COMPILE_FEATURES cxx_decltype)" by placing a "#" at the beginning of the line. ********************************************************************************** connectome-workbench-1.4.2/build_scripts/000077500000000000000000000000001360521144700205015ustar00rootroot00000000000000connectome-workbench-1.4.2/build_scripts/commandhtml.sh000077500000000000000000000127651360521144700233560ustar00rootroot00000000000000#!/bin/bash exe=wb_command outDir='.' function command_to_page_name () { echo "command""$1"".html" } #make a page containing just the text output, no links, substituting special characters as needed function make_basic_command_page () { local commandName="$1" local outPage="$outDir/`command_to_page_name $commandName`" echo '' > "$outPage" echo '' >> "$outPage" echo "wb_command $commandName help information" >> "$outPage" echo '
' >> "$outPage"
    #body
    echo "`$exe $commandName`" | sed 's//\>/g' >> "$outPage"
    #end page
    echo '
' >> "$outPage" echo '' >> "$outPage" } #start main page - note that this assumes a particular order of the listed info commands, change and add as needed initialText=`$exe` startPage="wb_command_help.html" #page header echo '' > "$outDir/$startPage" echo '' >> "$outDir/$startPage" echo 'wb_command help information' >> "$outDir/$startPage" echo '
' >> "$outDir/$startPage"
#body
infoLine=`echo "$initialText" | grep -n Information | cut -f1 -d:`
#include -help line as plain text
echo -n "$initialText" | head -n $((infoLine + 1)) >> "$outDir/$startPage"
#-arguments-help
make_basic_command_page "-arguments-help"
echo -n '' >> "$outDir/$startPage"
echo "$initialText" | grep -- -arguments-help >> "$outDir/$startPage"
echo -n '' >> "$outDir/$startPage"
#-global-options
make_basic_command_page "-global-options"
echo -n '' >> "$outDir/$startPage"
echo "$initialText" | grep -- -global-options >> "$outDir/$startPage"
echo -n '' >> "$outDir/$startPage"
#-parallel-help
make_basic_command_page "-parallel-help"
echo -n '' >> "$outDir/$startPage"
echo "$initialText" | grep -- -parallel-help >> "$outDir/$startPage"
echo -n '' >> "$outDir/$startPage"
#-cifti-help
make_basic_command_page "-cifti-help"
echo -n '' >> "$outDir/$startPage"
echo "$initialText" | grep -- -cifti-help >> "$outDir/$startPage"
echo -n '' >> "$outDir/$startPage"
#-gifti-help
make_basic_command_page "-gifti-help"
echo -n '' >> "$outDir/$startPage"
echo "$initialText" | grep -- -gifti-help >> "$outDir/$startPage"
echo -n '' >> "$outDir/$startPage"
#-volume-help
make_basic_command_page "-volume-help"
echo -n '' >> "$outDir/$startPage"
echo "$initialText" | grep -- -volume-help >> "$outDir/$startPage"
echo -n '' >> "$outDir/$startPage"
#-version
echo "$initialText" | grep -- -version >> "$outDir/$startPage"
#-list-commands
#special code to make page below
echo -n '' >> "$outDir/$startPage"
echo "$initialText" | grep -- -list-commands >> "$outDir/$startPage"
echo -n '' >> "$outDir/$startPage"
#-list-deprecated-commands
#again, special code below
echo -n '' >> "$outDir/$startPage"
echo "$initialText" | grep -- -list-deprecated-commands >> "$outDir/$startPage"
echo -n '' >> "$outDir/$startPage"
#-all-commands-help - takes 2 lines!
make_basic_command_page "-all-commands-help"
echo -n '' >> "$outDir/$startPage"
echo "$initialText" | grep -A 1 -- -all-commands-help >> "$outDir/$startPage"
echo -n '' >> "$outDir/$startPage"
#remainder of help info
allCommandsLine=`echo "$initialText" | grep -n -- -all-commands-help | cut -f1 -d:`
echo "$initialText" | tail -n +$((allCommandsLine+2)) >> "$outDir/$startPage"
#end main page
echo '
' >> "$outDir/$startPage" echo '' >> "$outDir/$startPage" #-list-commands page, and its subpages outPage="$outDir/`command_to_page_name -list-commands`" #header echo '' > "$outPage" echo '' >> "$outPage" echo 'wb_command -list-commands help information' >> "$outPage" echo '
' >> "$outPage"
#body
readarray -t lines < <($exe -list-commands)
for ((i = 0; i < ${#lines[@]}; ++i))
do
    thisCommand=`echo ${lines[$i]} | cut -f1 -d' '`
    make_basic_command_page "$thisCommand"
    echo ''"${lines[$i]}"'' >> "$outPage"
done
#end -list-commands page
echo '
' >> "$outPage" echo '' >> "$outPage" #-list-deprecated-commands page, and its subpages outPage="$outDir/`command_to_page_name -list-deprecated-commands`" #header echo '' > "$outPage" echo '' >> "$outPage" echo 'wb_command -list-deprecated-commands help information' >> "$outPage" echo '
' >> "$outPage"
#body
readarray -t lines < <($exe -list-deprecated-commands)
for ((i = 0; i < ${#lines[@]}; ++i))
do
    thisCommand=`echo ${lines[$i]} | cut -f1 -d' '`
    make_basic_command_page "$thisCommand"
    echo ''"${lines[$i]}"'' >> "$outPage"
done
#end -list-deprecated-commands page
echo '
' >> "$outPage" echo '' >> "$outPage" connectome-workbench-1.4.2/build_scripts/doxygen.sh000077500000000000000000000012741360521144700225210ustar00rootroot00000000000000#!/bin/sh # # This file is executed by (via "launchd") # /System/Library/LaunchDaemons/edu.wustl.caret7.doxygen.plist # # # File for capturing standard error # BUILD_ROOT_DIR=/mnt/myelin/caret7_documentation ERROR_FILE=${BUILD_ROOT_DIR}/result_doxygen.txt rm -f ${ERROR_FILE} # # If something fails, keep going # set noon # # Run the build script # echo "Starting doxygen generation" >> ${ERROR_FILE} 2>&1 ${BUILD_ROOT_DIR}/caret7_source/build_scripts/doxygen_aux.sh >> ${ERROR_FILE} 2>&1 echo "Finished doxygen generation" >> ${ERROR_FILE} 2>&1 # # Send output as email # cat ${ERROR_FILE} | mail -v -s 'Caret7 Doxygen Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu echo "Sent mail" connectome-workbench-1.4.2/build_scripts/doxygen_aux.sh000077500000000000000000000015301360521144700233710ustar00rootroot00000000000000#!/bin/sh # # This file is executed by (via "launchd") # /System/Library/LaunchDaemons/edu.wustl.caret7.doxygen.plist # # (1) Update source code from repository # (2) Build doxygen documentation # # # Go to correct directory # MAIN_DIR=/mnt/myelin/caret7_documentation SOURCE_DIR=${MAIN_DIR}/caret7_source DOCUMENTATION_DIR=${MAIN_DIR}/documentation BUILD_DIR=${MAIN_DIR}/build # # Remove existing documentation directory # rm -rf ${DOCUMENTATION_DIR} # # Go to the source directory which contains Doxyfile # Doxyfile is read by doxygen and contains configuration information # cd ${SOURCE_DIR} # # Update source from repository # echo "UPDATING SOURCE FROM GIT REPOSITORY" git pull -u # # Generate doxygen documentation # echo "Generating Documentation" /Applications/Doxygen.app/Contents/Resources/doxygen echo "SCRIPT COMPLETED SUCCESSFULLY" connectome-workbench-1.4.2/build_scripts/mac64_copy_library_to_workbench.sh000077500000000000000000000056551360521144700273070ustar00rootroot00000000000000#!/bin/sh # # Usage: # # This script copies a library to a Workbench Mac App's # directory for extra libraries needed by the App's executable. # The path to the library then needs to be changed # in the executable from its original path to a path # relative to the executable. # # # Uncomment to print debug information # ##debug_flag=1 # # Input library that is copied for executable # #executable_input=/Users/caret/caret7_development/mac64/build/Desktop/wb_view.app/Contents/MacOS/wb_view #library_input=/opt/local/lib/libomp/libomp.dylib library_input=$1 executable_input=$2 # # Extract need paths # exe_path_name=${executable_input} exe_name=`basename ${exe_path_name}` macos_dir_path=`dirname ${exe_path_name}` contents_dir_path=`dirname ${macos_dir_path}` app_name=${exe_name}.app if [ $debug_flag ]; then echo "Executable name: ${exe_name}" echo "MacOS directory: ${macos_dir_path}" echo "Contents directory: ${contents_dir_path}" fi echo "INSTALLING LIBRARY: ${library_input}" echo " INTO: ${executable_input}" # # Name and path to directory in the App to # which the library is inserted. # workbench_lib_dir_name=WorkbenchLibs workbench_lib_dir_path_name=${contents_dir_path}/${workbench_lib_dir_name} # # Full path and just name of library # lib_path_name=${library_input} lib_name=`basename ${library_input}` if [ $debug_flag ]; then echo "library full path: ${lib_path_name}" echo "library name (no path): ${lib_name}" fi #exit # # Does app's "Content" directory exist? # if [ -d "${contents_dir_path}" ]; then if [ $debug_flag ]; then echo "App Contents found" fi # # Does the Workbench library directory exist in the app's content # If not create it # if [ ! -d "${workbench_lib_dir_path_name}" ]; then if [ $debug_flag ]; then echo "Making directory ${workbench_lib_dir_path_name}" fi mkdir ${workbench_lib_dir_path_name} fi # # Verify Workbench library directory exists # if [ -d "${workbench_lib_dir_path_name}" ]; then if [ $debug_flag ]; then echo "lib dir exists" fi # # Copy the library to the App's Workbench library directory # if [ $debug_flag ]; then cp -v ${lib_path_name} ${workbench_lib_dir_path_name} else cp ${lib_path_name} ${workbench_lib_dir_path_name} fi # # Change the path of the library inside of executable. # old_name=${lib_path_name} new_name="@executable_path/../${workbench_lib_dir_name}/${lib_name}" if [ $debug_flag ]; then echo "old name: ${old_name}" echo "new name: ${new_name}" fi install_name_tool -change ${old_name} ${new_name} ${exe_path_name} else echo "ERROR: App Lib Directory with name \""${wb_view_lib_dir}"\" not found" fi else echo "ERROR: App Contents Directory with name \""${contents_dir_path}"\" not found" fi connectome-workbench-1.4.2/build_scripts/windows32.bat000077500000000000000000000015311360521144700230330ustar00rootroot00000000000000@echo=off set CMD=c:\Windows\system32\cmd.exe REM REM Go to correct directory REM set BUILD_DIR=c:\dev7\windows32 cd %BUILD_DIR% REM REM Go into source directory REM cd caret7_source echo "Caret7 Windows32 Build Result" REM REM Grab the latest Sources REM c:\cygwin\bin\git.exe reset --hard HEAD c:\cygwin\bin\git.exe fetch c:\cygwin\bin\git.exe reset --hard origin/master REM REM Build caret REM cd build_scripts/windows32 %CMD% /c build.bat cd .. cd .. set DIST_DIR=caret@myelin1:/mainpool/storage/distribution/caret7_distribution/workbench/bin_windows32 echo "Copying Files" c:\cygwin\bin\scp build/Desktop/wb_view.exe %DIST_DIR% c:\cygwin\bin\scp build/CommandLine/wb_command.exe %DIST_DIR% c:\cygwin\bin\scp src/CommandLine/wb_shortcuts %DIST_DIR% c:\cygwin\bin\scp src/CommandLine/bashcomplete_wb_command %DIST_DIR% echo "Finished Copying Files" connectome-workbench-1.4.2/build_scripts/windows32/000077500000000000000000000000001360521144700223405ustar00rootroot00000000000000connectome-workbench-1.4.2/build_scripts/windows32/README.txt000077500000000000000000000002461360521144700240430ustar00rootroot00000000000000setup_env.bat -sets up the build environment build.bat -sets up environment, runs cmake, and builds the release version of caret c7env32.bat - sets up environment connectome-workbench-1.4.2/build_scripts/windows32/build.bat000077500000000000000000000013331360521144700241320ustar00rootroot00000000000000@echo off if [%MACHINE%]==[] call setup_env.bat set OLD_DIR=%CD% REM rd /q/s %DIR%\caret7_source\build md %DIR%\caret7_source\build cd /d %DIR%\caret7_source\build REMcmake -G "NMake Makefiles JOM" -DCMAKE_BUILD_TYPE=Release ../src REM -DFREETYPE_INCLUDE_DIR_freetype2=C:\dev32\install\FreeType-2.4.8\include\freetype2 REM -DFREETYPE_INCLUDE_DIR_ft2build=C:\dev32\install\FreeType-2.4.8\include REM -DFREETYPE_LIBRARY=C:\dev32\install\FreeType-2.4.8\lib\freetype.lib cmake ^ -DWORKBENCH_FREETYPE_DIR=C:\dev32\install\FreeType-2.4.8\lib ^ -DZLIB_ROOT=C:\dev32\install\zlib ^ -G "NMake Makefiles JOM" ^ -DCMAKE_BUILD_TYPE=Release ^ ../src jom -j8 cd /d %OLD_DIR% set OLD_DIR= connectome-workbench-1.4.2/build_scripts/windows32/c7env32.bat000077500000000000000000000003421360521144700242210ustar00rootroot00000000000000set PATH=C:\dev32\install\Qt\bin;C:\QtSDK\QtCreator\bin;C:\Program Files (x86)\CMake 2.8\bin;%PATH% set QTDIR=C:\dev32\install\Qt set ZLIB_LIB_DIR=C:\dev32\install\zlib\lib set ZLIB_INCLUDE_DIR=C:\dev32\install\zlib\includeconnectome-workbench-1.4.2/build_scripts/windows32/c7env32mgw.bat000077500000000000000000000004151360521144700247350ustar00rootroot00000000000000set PATH=C:\QtSDK\Desktop\Qt\4.7.4\mingw\bin;C:\QtSDK\QtCreator\bin;C:\QtSDK\mingw\bin;C:\Program Files (x86)\CMake 2.8\bin;%PATH% set QTDIR=C:\QtSDK\Desktop\Qt\4.7.4\mingw set ZLIB_LIB_DIR=C:\dev32\install\zlib\lib set ZLIB_INCLUDE_DIR=C:\dev32\install\zlib\includeconnectome-workbench-1.4.2/build_scripts/windows32/env.bat000077500000000000000000000006141360521144700236240ustar00rootroot00000000000000@echo off rem isn't batch awesome, no else statments... IF [%1]==[] ( set DIR "." ) IF NOT [%1]==[] ( set DIR=%1 ) IF [%2]==[] ( set MACHINE X86 ) IF NOT [%2]==[] ( set MACHINE=%2 ) IF NOT [%INITVS%]==[%MACHINE%] ( echo "Setting %MACHINE% bit compiler variables" set INITVS=%MACHINE% call "c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" %MACHINE% )connectome-workbench-1.4.2/build_scripts/windows32/launchcmdmgw.bat000077500000000000000000000000361360521144700255030ustar00rootroot00000000000000call c7env32mgw.bat cmd.exe connectome-workbench-1.4.2/build_scripts/windows32/launchcmdvs.bat000077500000000000000000000001011360521144700253320ustar00rootroot00000000000000call c7env32.bat call env.bat "c:\dev7\windows32" x86 cmd.exe connectome-workbench-1.4.2/build_scripts/windows32/launchqtcreatorvs.bat000077500000000000000000000001071360521144700266010ustar00rootroot00000000000000call c7env32.bat call env.bat "c:\dev7\windows32" x86 qtcreator.exe connectome-workbench-1.4.2/build_scripts/windows32/launchvs.bat000077500000000000000000000001041360521144700246510ustar00rootroot00000000000000call c7env32.bat call env.bat "c:\dev7\windows32" x86 devenv.exe connectome-workbench-1.4.2/build_scripts/windows32/luanchqtcreatormgw.bat000077500000000000000000000000421360521144700267410ustar00rootroot00000000000000call c7env32mgw.bat qtcreator.execonnectome-workbench-1.4.2/build_scripts/windows32/setup_env.bat000077500000000000000000000000661360521144700250450ustar00rootroot00000000000000call c7env32.bat call env.bat "c:\dev7\windows32" x86connectome-workbench-1.4.2/build_scripts/windows32_remote.sh000077500000000000000000000003771360521144700242610ustar00rootroot00000000000000#!/bin/sh ssh -v caret@winbuild 'c:\dev7\windows32\caret7_source\build_scripts\windows32.bat' > $PWD/remote_launch_windows32.txt 2>&1 cat $PWD/remote_launch_windows32.txt | mailx -s 'Caret7 Windows 32 Build Result' john@brainvis.wustl.edu tsc5yc@mst.edu connectome-workbench-1.4.2/icons/000077500000000000000000000000001360521144700167465ustar00rootroot00000000000000connectome-workbench-1.4.2/icons/linux/000077500000000000000000000000001360521144700201055ustar00rootroot00000000000000connectome-workbench-1.4.2/icons/linux/workbench_128x128x32.png000066400000000000000000000614301360521144700241530ustar00rootroot00000000000000PNG  IHDR>a IDATxXUɂ.̊ QDs9$ 9IR QD%'IbE9mZK;owϝ=}<-R_?O,??O,??O,??O,?7 R}GƟ;c ڎ}c3٘)ǙL3Ik1Ul{J*>߾}؇<,䵓/*,g6@*9taRۿ$Rة}#cQ>0l ~qwB/g,^n:Ɗ+WfZO),Vd_v5WZJcfͻeu$MOJoعo5lYfʕ+Y.]ؼy˒E5#-V._7|׭~ikVr +u$"K˲z} r\ƍ܌GFF_nL4޲0Ϗ>e%e?/fW  XQfdVVXL}Wn޼9GGWwcs{h:ACK&07C@ʺ?\qqMLԩSmnn.]?Tc42eʔllt=MbcNfca-Zgf`;O1Hbdfvu\;++ $\;;;u|_hHhxA -eLIE}ʏÌV hhx3 CI3dR1 SUc1w-6lI q(*)~ցNA=Pr,#1C.ʌa=zPZR(,(=9-#k <-۶yN:m#Lf`P,%.SQQWJKy-D߸+xc~)QTd#9u)Q`,2eyqBa@Ξ)GV❆& !y ؘHJeF c0}|ёJ<5 0h}j T~46Sv}K,?M;P ,৫_&֋`G{[,x{1[ 2Br3` #i!%-+ &!U%(ShiEα 83%EPJ 13(AJ=|Y\VƬoW[kqb﷒ʑ}PTPh9kwJ2?0 =ӧW tW0&΢׭ͲwsGc\ _T恢 L kvvI@T\ *jcV HmGMU)bc㙲mBL M-281KOkEKm1 NBfZĉ,l7Tm'N ]|r,a6o˘S>^z\heM bnQ><}D0XئP0uT''|ߗtzVLp|njkv&ŰPl߶*P5 , Wp*X VdUJ74 `iəA_KJ*Ӄ/RQӥhi>N\EUMR`ai+3x␗\AwbLbn=.]<tƷy&cq:IXW m8rrrHƇh | dbea>u ׂĶʒC.'" }+~.bC^NPKcbICP `]fywhk{<=?&'3QRr Ms wjw y}< P(R3}HEѱ||[ f0`ώcַXq;]} #ǘj_e}ٔ tfOFL! 6_ gggfb=Bjב%7.,8 WqU>/9iȇi-}+Q Yy,lxظlaS[axbkkKcxxe z<23Pt4.՝è 6BuS }"A3tahKviRV=zqUwMq֭[,02::wI7( w(6"Fj& Y%yˉ"ӝSSҠ#N Jr]ئPՎ=Ζ*u^8dOu@m>fkq"Gvu`C{^;yHVg{) 0G2k`ka_`aINc#6ou aᡣv 2ecwu m`x,^c (~}[Ev|nIؙA] "y1LQ|C'y'uq#y/d`mcMAEEҲ PP)3;PQTUW L/BH]tr*E቏&磷i>ث f|wZ42\3ᡱ!R㢐9i? S`Xm$Dރ)n 1v$ήcW;QxvNxx*M%5V)c-~?/~G;i;d7MX\q\N|~3N-}2̇ dʏ>tgspfj062$@LcZ'=g+SXlLPX3ڏkCEYBE  ާˏ,^4M5׈#傩: PQUHK)(AFF 48\]I$ ٳX aXNn @zV;j=uRHVY/[>-B(-Ab8?Jy\=&sqOı *N>Ut*/ENx 89ԂA<1wU"^7#]X[[? 'g?T{g5Uh#<$E!Əy0\ƅ>5(LNFqal eEA \e6\lZv 1f/TL;cLFW&uOss<[1 RXh $g}K=˒_t7&nSOfco@z׫^ܫ#8nYҲZTמG]k/zky0-<ɍ^\$ҌkhN UW2 pE܁8UT/ц(.v9hұȶ 2=Ÿ4xOݴ}6zxQcCi0bh؋x9.4wti*VV#1*]3HVF>̢(8^0;۶n +ei'͘_ c'و4Tl+=fbܺ`111KHBIF ڢ@__/:ۚނF4661nbཽ:;TWKhm?j' o@kz"iܴ؍*?$ed`db+K 0`Y &+]FMe 1 *ƿ)OacL#bnr~ ]쨷 MFəӤG|,ϐ3;UE n߁mWCsىf*Ź Tt`~، 'Q^߈bJJQSY=$Pp.$I(CNg'_E[^m-?`gwdJ ~0Y%Ogy $;NH턞-+a$F%DY+j"EB/7B9xĉ%[1Aa:9;8 [p[ԪIBH;DG8Q%@b ! "T#S6 4gҝ 2Ig~Ű/=]pbz?K];ZÑu{ ~j8+;'x [ uw0ੀÁ>hF3?AN!Zr75;pkxpJhI&2Jy60ȃ PPֆ fp! ANae HMz*puNH\cEhpKLLBzZ:>|}#ܼyD7 'hi/$Z gსOE\L/ aeOt)Wk^󥒓iifjXEAۥ5ϻNGt;܀SCj5D?#@jP`Dž+pYgm17+BGe ܹ÷#2yԿ,g{,NGU2T~02X8wbF}pXA‰o ]`U™3'B32VQS}C+H ".lƊ́h$ Q#Tx}?~{w t06G@= ` H[ܳ |xe+GyѸ)c`=I@ k 3ʚH5\DF ^@W[+ЕK6r8{ e8]}Q nՁku჉c\ܻ'~_+{ ;dLsc/#Â!60{ ߏ0^-fj߂kP.%Q˪ lP߽ mR5~eÇL$o|%ɍ0p}ׯx-.T@hMh$'>GוABU],EtX(RRq)7Ỹ\.0. `dj z...$f*{(0P 1ݗ_~zԍs$FcI î8nҘ]1xk.|Lcd=?fΘ/GߴpϜ4*ë¯#fׅS-d> <BT\_;q~ \spp8oω׹qxx}o`l#nfCm4wŋx<= Gб%=B@|f$zT{)(AYN`/y('OGOB;"=!%"-Ғ`nnKKK4B ,09 O2 7`1qa~:FQ-8a*1oQT\Yit4;8 S+7X@Oz";X|\.1?R|ȉƝG0RA`L7|R0RHxyA@c7BF' b5;)\3lW2q1H }( CƽHŎ吓<4 I$l`bbj pvv1y&Btyxʅ0R͋z[%'hp!)^[*-'ߒ'&?`l{7gfib悰3mII*Bh-jkΈGL,K^c}}X[!8^8@ߧTa IDATد xDMܬ 7ޚmlo5(*Ex̍KGqsx ;1i{I@bln— iE=t[aaK%2:q.5S܎;`,,$$ -UUUhjةO=c9,4ހKD>ŋ f\`x.7fb+ssfAj"Zok;w} J@GrllqJnXc/3,КS$aGn!Nς_`bcIY#/Rt/ڣH~ `ō3$&yB= G9 'ģ\ [K{\Sě(Bafع4jxt4##)F/  8u ǡ,Mb Rqq8x$Ez`mT|؈% q11hiiS3}t#%Atj=5>Ko0BJM\/- /=\xv>b(ӓ/!;DΥhkmQRRJ4!'P OiCw{3Fmz أ[c\;oāw1h6ih،s$p>:]<ƒ/qzĴ[~$ Fs1Ń]s>Ƌ8ކmظ8dJV Ư'pR , 7Ѧز~ 6m!AAP$vp_ 1Wx_M7] 1_dp w (GdW_X,VEltXzɓSRIxxfb 0P[T"M.4x/tسn \7z!a44 (T;@kǣ8e֛_PEpnr|)PÃ`~WpKɆasNδ n)3.O\t|*>[&p\ٙj>|[R-aم8Ń%ܱ"EFw#RaJwÅxn5Z^kHsůȚQ]t[p-z(jkn+י7neվ$r:qLݧV.\G碵hI; apsfXL94Vի8x Ciap&4Dz@(<뾃h .^3P22p_f*>3ùE@ZpC4^Sڼo'ɓC"T>|5{L%g6< qO LWagKʰH5‚hk -y @u*)!UrTHHÐ T>B2YQƅ3pd,db+&[<ōW qcb ZBqDϻwnk 3@G { Gv@n`zijX&$`2~ q;~r9k>?F m Ma4[wQZ|⪮p?BpV:\7`x~2HrEҕ rS%M'vdkttuBB;GD޼yC7Q^Vb<#$&Ŏ:Mk6^[ō; 6/k\|2i ˰B@" N?y뿗/b#юڪ2,ABK;o3w$=| rr ^ZpB$I0&Ԕ#'Ht^›ׯ믿bp`uu1z[ 7xTčx|۞ /3"pMT9E(=Uk!B1 n7Q% '(̏қMuGȷ@4Js!MRDLr@\2‰ œc" 9=O%ܻ{]]052b_\mHgNgr,fƫ켇;gl|l 1fX<_tLD 2uy}ZD)i@JJ&\5CM  ݻwx5>x8VZ Zj1 N2ڬv}x^qW҄h;߂ޫqRvt(5 r 8#r!lnJx Lb.=gEQ'=2妥 ٪,.&Ld3 C؈ + M7SHCCCЈZn7mڬ_{, ##H|<䧆C?^:465SeeD1zX~v*3a=Ð? c.JcO?gOxM%ډaıcHIWkG\n7M18/'K]$|e8))HNL@Ol12#\Im8f '8kWrpm A/0xpc؇wDG᪬@cC=\ļo#PBWp .P حs0[ 0Ӏ*nU_7-I\^q~*.'F^nx1s{qG,)A.6aXr=V\Ea J렌ߓcb`2 >SK%wx>|{|pb7.twrȶ+% g`(+h%?{n" ހ4x]-S;!m3|I0OP~_o/ vՐcUSE'O|7E͛Wx5>{ H/}yvbHz.>EO=‚(ЇQ0߃~Œ]ތ}a .p$=|pn T [QRZC7 ɋ|r ͮK89s>TM^@A?5p3 ;ElHċ @6555tϿцL" >r0j oلF1 ˔R`g =##ثɢO }Ds%Xtt!K73y \n>FUŢX,m۱s=6/M]«p}\F_Z.+,Bjhyr%2gqg**۞B2=h%U#x`% #-G5n+ "y׮S5u=h gb20ذyfYU XS+`%/yd六q_WuLS{٤M\A*,:9F7$v fjEbr8`llu]d/hU_O#]@Wp9|%B= p~6nm00uIG.&Fq:#!= e0m!"[Kd7kL$!,&Sh 061=By.j5%BTGx%<{Dcx>֦ė<`VĨVwG\wMk1&w7<}*/B.i@Zxq" ={I| ]>a :D~~.֢p j -9`׮Rmu0JO$I(<B&H 2/Mw@D7 ;V˘#<8Qpv-`BPOqGane 9ⅭBd\s"( "f2郩7 ОW7|.vX,aǰq lL(ISEԳRR۱az[7m05M7JTTo'D<~=W zĜ^"~ȔL _ 0dWH6T@uC|1탷q!WfIs1 `?(<4v?7HyENn&,L-iܔ6Wu& GF3\ >4HK <p}e(ػh+#)-K:0O@\dʣht 8XkN87ژ6 ~iY{\=69=nbGg>!vP^ \r"\l}4hwM/^J5+wY-شa%v***`4DDEcl۶ܹƍf^ׯ~FFm>zϟއa(UXbbT9g3AH~wׅ8CǺ[+޿%ꨇXп{&J7ݓz?.C{8qDܺ7-cIևR7˘gOCe}hFv6֡s`qLaȩjx(Jmh,T]4 .$F!F zmw=]3*IWK6 򩰰q0.Ɩ~<lamm]#"{ zQh6€tZ'@|$Z{56ԡ=+fHM?I)$P?7O a !{#Z4fvf#IW{zF9M#yT淯 9=(\+Ή̃Ȓ4H/ƣ`3\}:ZQU]I|1WC u𽇅 YP ޻*"Bh D5eeWt6 P7A^|7MMyy$ D~ O]#44FF4(K ; F%%%A\͛7 lY0؏5pť8c i FZ°Wޅu$A5XT"P#f9#q"625M璒ĸOj\x1M֗/_(233:B\R‚s9%YT$ A%wdehI+qů*|@||ME9xlkm8֯[!c7nŭ\9O޿@as8~8aJ/e'KKpH+Us C I==K$0D? L&22znķxKo3>4ϔW vjE+L ݳ L qCQp􇥭]ijgi:DLL_p$BETrO.1NmRV|LLLct? S~O!*"!$$A dHNoQǦ<9 )>p^RH1_47b# I-)TBb0Px>^Ԝg[vyԐA !17(zH]UXv3J1+*Oǩ}5?I?<GG26HBRp׈*j2&*II8wFt27"}aMl Da{$!,4Spt1Z ^&. 7ŋ T6њ/Bhz׌ e*s@;sBzY+?8=D}Uܾ=L ^G0\XFthӯҢ:9:m uh_[ JpV ΏBK~Ċ^F0-i!r#% 9i"+ Pm :{/mm/UAP GƑLClE܈ƽG]E(A IDAT ,x3<|sx o$z՛[Cz/oo=,++ÙӧL=tTY@}yaDw‹虨fh&`RX'bO(,G}]9&tp{/]kvzX#O <{JƠ |/WT v@@܀OO/buugq0`~ #R"ЕoddL/WOZohlB`Jy:</x /qFW!WUTكkP,IRr&o$>4$Yc;(c=yQO30p KFޅ֖o[ah`?1;OPUeѦ [lmC;0D%sDPPH0 A(mٶ plgf0Zν9U_ծi4e$߰~42ޢp{`ƈCw[(cy1blHx3-`vqEPr" oc{u\PEf"Wxm$\E}[degsլ ,7^}BNi&lԹ˙+V!riBGxzf.僿N33Œ?gD#]g Xw 445`|(D$ yÅTy {yuy6żqj5/B4&샫P\\7?ěG())sY͸w4c1/ǘ1OÆ SFʨjB6=( ;Tx*yͼ6,ZTg /vv)4ZK C@ 6{b"9ԹkJڵkx9_ \eF0[}KewpE.'w,.n ~WζO kz ZXm>]>?vTG=ؼe r B&u\?l=v2=m(rc3?b<&TX;?=ntth|wJ*>e@Fhn}4y֬{"ù~UGp\6ϵXcciֲ7D 0Zچ̽kƍX,oVVV2WAOO:nfJH;'NJ'\1޺u# V/L-5u!qW4@E\'![^mS׊$n\ǯBKqFQ-Iiq *ZLLߦ l7É9b4CEn362"Xmi"EȻ"CfY5 Pr!QY%p3R3"^z }x 0*_m`!͡} rZ䓎H$'DCgW-hxx߽4v>q3<]{XzlfS@*eʴ_pp0N Cud tfz YYYs0iS_ q!$RQl`|`.Z$y!$x=KNݏOQqlV/fZR+]+Kq[RЊL0H ;G7l3>p"xēבu9B_ % ӹK=1D"Gݞ <1ikKOjjAP^O ִpɡ_mȀV˚+//;sw x%CuM->xKpH.RR!(ht = =/6w ^]ǘ-Llb!ͺWog30$ lBk;&jjf1ؼjo݁w o#1wPm]n e7bc) V]ا K`k>U܁)+AEMmeו3[xt2)m@;Zb&(Η@@ @P|*#BS<UNjؗ@eu`Z,zj(Hx-HR=yJXMͧM Q~E]:@Ieo'#*2B}BdT@7gq]\'RٹHbLf2wCobU075$]35J͋$-u"=e-syJ;X0s1 &[c[6dCy;F;w|3fX ! ,.|T; =ؗ LEv?WvC83/Tέ<' =RA=]I4 1-MUXy`c7036~3!)qBD |f &&iRp $Ξ)y# c0oV;'Mhk!S*$C _vck  e=:X|e\.y+g:PWGBbq(ATbn^.=~za ܀oC2 0g*%_k#NʷC2/mG;k%442j)20j;#_5Ġ ?4T2 Qx Ʀ]냍ۢn5lM_B͕pP7J9_{ϲH`dI >PWbfL : If" VS'i>|4BYi )=[L5[L&t'/\^|ߠ.8t=ջJJcz1?>ǛjEFF5g/ZBN^vHݽd $$ǚ `@_,ff3$׿TuH2GL X$A-r+(+ڇ4t6y )GTA"۷dY!lcIQHKX0X%C"0^g+yFPwu?u8ʪֵ{x(%[HO@pqqf==bP6[Ƹ3 //ـJK˘säD!4d9ӺUQ)ʙ-cZ7\+qP^&!-%9Dko|lf[.$$&gΪ+,,lU8 qVTC~^-2F`̙4GG{,Ƭ٪P6öZȯ |_SSK';ZA1>s^_ ҷ #{?FdctfU "zGux)JObwNxvrC&akcŻ3gY0荗L&Ap7٣^~(CT?~" 9^zm݀`y}{2 q(r}vI p W{[X/Р:gkk!h]BBDF]º~O}E&FutJoktttEUis%Sh/Sb٘:C3bJfT#=yό^# Wbk,*mM{yS6֌YsdfJ15x54]  ߄?5w< )}|xb*2:8:1`xccJ'F/\1pdR<}e,r 't1# `db Kkx9#=3X]k0ZbH53586An\4MƪIڨ%0Vq@B[!h=E~v' ÙM2PTT7njZv#G-N|+WbQ۶ 7nTM#1b-&ͫ7!.6Xn*D]Vg{ &72f!55=9nCH;foq#x?Oo^;Οp_3g@v Ձ5DnnFxSSy(xP`ee%RRLiHu*.j]E\h3MV!-G"na$&bXE,3t1j+f,4i\q-Ǝlj}yv}[[Qoa䶒e>}a 8h`HD))9YHMWnd5Hܛ60ja!1_\sxΞ=\N&^~!f^%x5o/zEG!us1!)W1_ieJދHf>.lDBL[ǺV8BbRS_Nkܓ\nS}Ρ >.&ee(*,r3L`$E/&/rleڄs5=`h!?!4ǘ&V+7gqW`IDweUbރ.ˇQ@ H*i5÷#$4)['))O' G颯ӞWjjhbʈ0\N' 7Pn\MVCJw|Gjkֿ\5!C8' PRv pz0)Y{+>iϚ"߀W`yy(6noٰ#&%,4[mg`!,qW ~Bxx+1AHHGC8@ Vd+9q;{XƋ d(E7Ly9#fq~^UhM<-b 3yi7}`GQq H?Bs}~g@p sOsз}bth- Qu46z`Ҥi j`FJ>\m? aÆ͛7?->2;)9:׿m߾ۣoA?w뺍5O41B=7X FfU-PlF>¢Bދ U  G`Ӭ0ݶܮ)$"B`ukxܝf1S4Z$&&@ UV"˞s)fҕXR|۷4 (QxDT:P= [4`).VüY͛>} 8eW޽W*(|Bjku "8.A$N M)6+N n\1;!-!VG;gF"3555-7@iisr?v̙%gjkxlc\MA h`|%b5`_jPN(K :Tys0! RBt7`|C!3=Œ{3PfN37g3}CV䪙 W-6}昿D0@4p@> Qݺutdh1ND{7iku2c:u& /fۺN=>ố)j_Z A> dHmˢ f =讓0ؽՑPQVi" GhX3;f/B6Vwa:c([]ܺyJEIk`&s ܴ]n]&ƿyFiHĿОLh/)n/0)/֗ONF]ػqcYߌ1z\hL51bq 'kw\ |bg](?#z1覙 U˝BrU ƍ9#gP &5dW_Msޕ߉]d}}=IdIqLM5- . !'۫JY|9h`qVLIct&չS, g {qG u_ c[どM)@afWw_x @);X2%ȴw^ZoQGsEG:Ww?+>h]%mQ0@ɟ˴WZV^ax>K}Saڲ|,LNm Os: coc܇$=>y#,ajb*̜1qQaq$7G:wF8䔔T޵F I7\XeGr""¹H_TTā@3y ?&'' a]]m!mN[ٷrKxpEK3K ào0\ɬi>a"tiv=v( L\(MF݈ FhP@f u-- pt~]>o1Y\PLlPl VVS(-QHwp/P?^Q`iܸqm5mw#nh߀!F5T0'5:L]N+/] oQ ߇'󠯯_Ѝ~\ݏ/(JII1iv_]ـ=UЀHIDAT3>1oԑlVϔ ŧJqPP)dgghcc-[lʔ)222ee[wtk?|t:u$jD2uȤdd~=l}C##Dnڹ$'!5=r/OOX[YASK40WH()) >md5vwYZc}5_s܈:+ppvlps}@cc*@mQRV?~|3jqEK-`na#X0lP U* 4)_~鳔+LS]5~|~A1GA~TӷeoGi&牉 Rq;cuCirTٳwoטXQlL,{O ;oGLCkȯk? xa8?ҿxﶘ 4+޽{Iĭ[ϭ^A9tm,{}3" ɯ?!tH:@tC:!tH:@| ĪIENDB`connectome-workbench-1.4.2/icons/linux/workbench_32x32x32.png000066400000000000000000000050471360521144700240010ustar00rootroot00000000000000PNG  IHDR szz IDATXW TSW~/l*Gt,QD;jE:H."[Hb@YB$@A@FQ*E=:vvlvdI'xVy)t(z!'djW?rB5j(V!#Bi4y\z!ݒ]<0UMyg4e2~ t:۞;w":'꘶)DC[ןڏuknicsҒRRA4׫- +/_fMXN?688`ccc!i{΀coen.fjbnggb'"þ m>s+= 'f=v-:Z d0"<<0}tO?m¥/͙"7z%BtٔCl͎ONJUc;Q.) 9dFH$bhɐ</$yf[)Esu9kFZ[]7T1#F/p7g͑@lS@Q^Z+xR^LNKx@HH0g26#@,[l!َuĘ⋣_OYd`H+Ts" Rƚj *tg1{mPA^הlm 46a-G'`5_N, ,T|vzl~҂g=؄x@[8iJ9nBRJʓp4o@\kA-[\Hŧ =mp$]u4 y&^Yd}g֑m9 ;@QJw;b'p?7rPI~ )v'rlA l7gQAneKg(q@ ݼBQ?;N>$re3KaVMۄUF:+(ڝHcV"j\TFz`"\p<]2RY _}U #VCPwZӐy0t$TW1XVe!ݰqAnی93-AJ17{B([e L\jY1Jk)8 *0zak! @36V4I:UXCq:K![Ġ[aEHv+yh| I?٧4J3b=v{)ϔ@5fںҢ2kt FUƺ~xپ^>XcDǵ8}?t5\a%ކ!\D.=&EڎjO%5bO(+p6[%Yc PdƒۅX+[ CmjU8/lޅPGVЌmejuj+3q"pR1㑟~`yP nz¦ljFyDyd,Rh7ֿ`dGQU"<:\=(w/+}S+a1֞ IqEz͏LNfs@ r`\)%"x ? BT4PNVw'60e>boTG?W _r*SB]Npqp6< ]?gKӳ.^C+1jrstSPx&,"ha=ҿATI.\ Yf[~Y[Pm[V 1{`IlsxK,ul!4L 6-_LɑTp?{T͸3jF{'gɧԑeTf\>8{ |aD?//9Gh/xЍs(ꗌSSScġ8YVVA9gߑz粌ԸIEhiPQ;;`~R[)/WNH^on=Ƃ=wrpqW)7#ky*p8yM3ΘقE^dU)aD\rhvԸ{A܂/ssLCC^f+f-3;w[م9^|=F4U w7mTŊ&|r~PvoaG,STX8Y}JQ25AأY[!TX,lBnnF 0z8GR ^O,LOO'% M+!9B,E"J(dRRY@C$&$p /oALlM3q6|}e$~t{hhcܒ >sSnFO_oo/f?zIENDB`connectome-workbench-1.4.2/icons/mac/000077500000000000000000000000001360521144700175065ustar00rootroot00000000000000connectome-workbench-1.4.2/icons/mac/data_file.icns000066400000000000000000006737521360521144700223200ustar00rootroot00000000000000icnswTOC His32s8mkil32ul8mkit32ct8mk@ic08Jic09xis32Ɓ+:_No{5 sYfvY@vxxulnze!jo}u_uIp]bfUu炀ijvCu^ysy{O[wY0\~X0 ,+̀rM+=_No{5 sYfvY@vxxulnze!jo}u_uIp]bfUv炀ijwCu^ysy{O[w[0\~X0 ,+̀rM+:_No{5 sYfvY@vxxulnze!jo}u_uIp]bfUu炀ijvCu^ysy{O[wY0\~X0 ,+̀rMs8mkSš͛0i*\J6!1dER Sil32uů +G& J@ldukTpMvly9*6bn\{G)Lbe7lL= VI{bʺua{Rb`dž`Byv~{^Qk~;j_tfuHLft9_]y[a]zӃFzZo= rohMZ4݌cnGRr`Z]7)ZܤُsʄoySbjI[JXK9/0q~pgW]SKAH:b_4r^inyPBhqq^MWVyfx}l~p^UWjWl`dovNqЯwhwfn~iqڏZ]{P.5wƄz`֤zl`k]mB}~j_\T!&PW\u`<жÊ EV5Uů +G( J@ldukTpMvly9*6bo\{G)Lbe7lL= VI{bʻva{Rbadž`Byv~{^Qk~;j_ufuHLft9_]y[b]zӃFzZo= rohMZ4ݍcoGRraZ]7)ZܤُsʄoySbjI[JXK9/0q~pgW]SKAI:c_4r^inyPChqq^MWVyfxl~q^UWjWl`eovNqѰwhwfn~iqڏZ]{P.5xƄz`פzl`k]mB}~j_\T!&PW]u`<жÊ EV5Uů +G& J@ldukTpMvly9*6bn\{G)Lbe7lL= VI{bʺua{Rb`dž`Byv~{^Qk~;j_tfuHLft9_]y[a]zӃFzZo= rohMZ4݌cnGRr`Z]7)ZܤُsʄoySbjI[JXK9/0q~pgW]SKAH:b_4r^inyPBhqq^MWVyfx}l~p^UWjWl`dovNqЯwhwfn~iqڏZ]{P.5wƄz`֤zl`k]mB}~j_\T!&PW\u`<жÊ EV5Ul8mk*;BKlU 7Gfcj@# " +x]Z x  \u hJ  bʞv56N  :BUKit32c        f8 f9 # mS\\by `y^W[SkF3 $s< } \Fw+N*+oOn^_oM)`HVfammogYaL)'';) >bYZ`fL+ ( HhXH3=I9$ ?cclwYOg{n  (  ?cs[9Jg]@$>QX\rVCfy5 ,PWH;;[tyI9gaM;#-@TUCQnjNCVpųp3 .>^jkWcwyAEXON?.5APYDGyoIDGNhse: 23fder]qb4ENXU@14DRQ:YD12>\vkZF=VkY^\QgytI6I_dfzR!8NFB\iboL:[e]D:JX]D.ICDkQ1FDUP>A @%Ymx}6D[_M;HJVqOIMKkx|`[s}ƴiN% 3iK E"6Nd}ˁ=JbSAJEIHuPDMUi̹\cdir~rjk7*j<H/9>=7HTsw6ZVMKFB@^pbOZkyĭVLae›yiRJJfbmHH00.1CKFIKeQKcVLHFHPas][XbvoXW@StpºTniehta(P >[6u?DrzTNWjVL^slQM}°zvЮp>S@¯tsfuM9JNpĴʽȍCHQ^oPTb~cIۦy}ː{ewIT snbeN;81Ľȵ`>KW`uJ]f^wku˺ȨpVmɳVYZǐyy[C*Hɺƣ]CQYpzyQ\[xvQ[m}ѿcLùYZAx[Ck̯ӆCLSazwYV]czɢb:]s~}uɦUXʖeVX(tlþΡgu]̢~yqܫ\IRVqu~Ga^g}LHkqpitֻy[^~uV׶K\ bȚb{{mϜs~wlޣRNW`z|iOianoHWghhjqzήccaZ`ݗ,_;qWPVk~ӗusi]NWYs}ORkkv͜_H_abfhov|żu~wɚ> [ s^Kj|tvY[xҏonVyࣃgP_e{eKstˀER[\acfmrttyæoӍ*_7r|Rfvxlyq`ڍhil趉nKeewԾ_Fs}ƾ~GOY[`adjnnq{|eo_IY~yjcWowvrrpRo`i绔vEiowSBv۳U=PU[^^`eikt}‡fȩZaR^UzJ{^[idi^ahĀjatj~߶}{;et}8Vt]@FGQUYYZ`flwƌsiw#a%ginz`uUqPPi{d|ln|Ɓq7\t~ϬXAbxTJTDADJS\^cjov{xq˜cMb SttrxvRuξ{|VA]qtj~jo¸xBTo}ĮP\sFIhbE117I[dilsxttжѳlg_5lbmleH?|ؐn}}a:[`pmlnxjltuhWdv˟isEJieF0=TK@UvzxxvطĂNwRiýfblVE_fv}e;Rbztafjhza`wpĒpisą†}vFNcMioyri}nN{e\TGJdڿ~}ƴɶb>YhVUxyvhcn{Sg֣Lb\HU2$tT m{rmsrIla;DєlfĨg9GKA@Moģ{ݯ[C^i`hvmm4TwuZhY< RWv B "8ôddQia@9}opl?:G?:8KrѶuԳ\Jkfhwpq˷rLYy]mwpT&>/x^fkfgĽZmvYQf`G8\snN4E@921Go׮n̼fKqgoΫα~kWhjsT>` x al]W~rɅN`cQb`IH7g؜go9?>6.&(@]nPxqxħǪ~tȺ{c}{ru&=y`5Wyrg~ĿsS^aR[aNQI5FkЇuÙTHO>-+%&0@S~→uX͖j|qwõwkrS?Ew7u3 ddPxȿvUXfh[YM\bR]fU>Z|UTO37DKGB97K`vԎL˖›߾pknjsыV`A1dl]jy x li]asf^WfͭaJSdS^mGI\dVZlrlbM>DZgx˃AK60Qdw۔WԙuӨwknke{w\>?a|mgs !zWf"X{ghZXspb\VgnFG[bZZeqtnbUIHNnk<3+2?KMF>91.--,+1>aܝ]ܯmt׷mdl_cҾu8Glo~'?z[n._s|jhZ]zƭ^kslidLC\d[Xajoqja]QGKfi<+%1FJD@815:;71*'"Bުs¾~yTŶw{hPo];TyŰmzYk(c_eegZci̻YarkV@XaVPRTU]hmscI9?`uO1/IJA826<>=842/#<۸©xyprVN{ǹPYW:\ٻm| zYl&VYcgmZior׼]Inh\\[XIGQLAIepXNAATqฒ{`84CC:28ADC>:525.GÒͣ{tlb8TνdKq؝dBZr~z\g;LOaijVixyۺd6OY|y}gUWEXz~eA5\td\UFAKaɽ|X>745?FIHD@<9<:Ko]A/,ɻN\Μs]c˿yx`;`UDPcmiqߣp9Psj{]]di:Fed\VJCCOgКH+9?FKMKGCBDGDIZhŃyx[?1:6\Ż]Oǭu[z)NJy bKjg?@a||BNykypzT<[bXQJFBDPfqM43IOTQNLKLNQOU^tjWWD>A@ABopLnZ{p" R rOho;HN>m~mʥׅHQ]RLJIFECHd•d=;OW[YTTWXY`t|eTQLG"EFHAMӺQc{yWƉ?X-z \Ghd6zY@a{uս˵͟[aTLZLKLLF>8@RcqphΗPRRZ]a_`dghorbMJOQRQLJMNLCHm[\xpilygg|4Fz`;`M@|a@Ynij}xacf`KQKTJNOLGDHU]dr֘{tqdZbhkqsqkc[TTVVUPMPTUQJ=lʛf]bnprtU`}DŽy z\iCCFjBWkmdX\aadPktWigTX6PNOSTX\^dhosͮ`fqv~}{re[XZZXSQV[]UUCGТqfYsmtxWhz`ǀy xRl'8U³wosKXtxr`eknm\]dQ[mbE=>QNUW_ggn|~~uΥҏ[nx~sicb_[XX_cb[XCLѣzXLvhuiJgl)y bv1[οvds|W[|~c\gpul_TPZl\`D:QPVZ^gb]{`aaw~޳ŐXs~rkgc_^cijdZ_A`ɢRJsmnugbe-Aw6D+SЮrϱg^py{ucg]OtQ@LXZX\lhenimjݦSƅ֊bwtke`bkol^aXMſ^Rd^rb[| r+hֳݼoUata`Ylj\JUTVewl{wgde~p}ޕi{}ofabjnc[Z\Ԧ`qZGVMgI{L &uQ6BkeA˷sKYhssp|zy`\d~MycGLMPUOI]iaU_jTlޠn~pf`_cbXS[ogQYyw˹h5rc1Z.w tok^;I̷UVwbmdjw{`VijsrrZ]eZOVXC7HXTMONSMlxzqf^\[WMRopguc\ɼU4eLv s3dWFH? FfMĞob[^u}oY\iZ͟rd`_wʹaakSHEMQh}轀yypf\ZTQLjjvvUôxK;L?,jAtҿrta?gwtv_^gpcؼpj_jo{ӬhTTftz|~Ɇkxna]XNQSvy]fX}ɲcG>/o7[ujZPA<2Rq`fn{awugwpģjiϪ{\`ny|wƇfc_ZSKVbp|TOƵc`~cK<+`>;9?KPQWXZ^futaBYŗudl~qr٨vafx{{՛^XUNLbu]´Z>PXC2"]+B_yMdθɃsx]qx]ٮgmpqߒLPJQuvIXu\GA@HL?.Y#O_~xo[PYO\f[Tرfdlsa8Ifpqj̤p#5DNUftswpsxXjs{UQZghUMR¾gE,B;Y9D1w؁ .<ay  (0Rd_UPeĽ%T@b (9b{n=wĻwWa|"-UkudȹVrh' 4S\a|̽{y||}xlK$+3>Uz|cP?7:6+  DWirkZIIJ?'   ) >bYZ`fL+ ( HhXH3=I9$ >cclwYOg{n  (  ?cs\9Jg]@$>QX]sVCfy5 ,PWH;;[tyI9gaM;#.@TUCQnjNCVqųq4 .=^jkWcwzAEXON?.5APZEGzoIDGNise: 23fder]qc5ENXV@14DSQ:YD12>\vkZF=VkY]\QgytI6I_df{R!8NEB\jbpL:[e]D:IX]D.IDDkQ2FDUP>A @%Ynx}6D[_N;IJVqOIMKkx|`[s}ǵiN% 3iK E"6Od}ˁ=JbSAKEJGvPDNVi͸\cdir~qjk7*j<H/9>=7HTrw6ZWMJGB@^pbPZkyŭVLae›ziRJJfbmHH00.1CKFIKeQKcVLHFHPas][XbvoXW@TtpúTnjehta(P =[6u?Dr{UNWjVL^slQM}°{wЮp?S@°tsfuM9JNpĴʽɍCHR^oPTb}cIܦy~ː|ewIT snbeN;81Ľȵ`>LW`uJ]f^wju̺ɨpVmȳVYZǐyy[C*Hɺƣ]CQYpzyQ\[x³vQ[m}ҿcLùZZAx[Ck̯ӆCLSazwYV]c{ɢb:]s~}uɦUXʖeVX(tlþ΢gu]̢~yqܫ\ISVqv~Ga^g}LHkqpiuֻy[^~uV׷L\ cțc{{mϜs~wlޣRNWaz|iOianoHWghgkqzήccaZ`ݘ+_;rWQVk~җusi]NWZt}ORlkv͜_H_abehov|żv~wɚ> \ s^Kk}tvY\xҏonVyᢃgP_f|fKst̀ER[\acfmrttyçoӍ*_7r|Rfvxlyq`ڍhil鷉nKefwԾ_Fs}Ǿ~GOY[`adjnnq{|en _IYyjcWowvrrpRo`i輔wEiowSBv۳U=PU[^^`eikt}‡fȪZaR^UzJ{^[idi^ahŀjatj~ස}z:et}8Vt]@FGQUYYZ`fkwnjtiv#a%ginzauUqPPhzc|mn|Ɓq7\t~ЬXAcxTJTDADJS\^cjov{xq̜dMb TttrxvRuξ||VA]quj~jo¸xBTo}ŮQ[sFIhbE117I[dilsxttжѳlg^6lcnleH?|ؐn}}a:[`pllnxkltuhWev˟irEJifF0=TK@UvzxxwطłNxRiľfclVE_fv}e;Rbztafkiza`wpĒpisą†}vFMcMhozri}nN{eYhVTxyvhcn{Sg֣Lb\HU2$tT m{rmtrIla/x^fkfgĽZmvYQf`G8\smN4E@921Go׮nͽfKqgoΫα~kWijrT>` x al\W~rɅM`cQb`IH7fלgo9?>6.&(@]nPxqxħǪ~tȺ{c}{ru&=y`5Wyrg~ĿtS_bR[aNQI5FkЇuÙTGO>-+%&0@S~→uY͖j|qwõvkrS?Ew7u4 ddPxȿvVXgi[YM\bR]fU>QdwܔWԚuӨwkoke{w\>?a|mgs !zWg&Y{ghZXspb]VfnFG[bZZeqtnbUIHNnk<3+2?KMF>91.--,+1>aܜ]ܰmtطmdl_cҾu8Glo~'?z[n-_s|jhZ]zƭ]ktlidMC\d[Xbjoqka]QGLfi<+%1FJD@815:;71*'"Bߪsþ~yTŶw{hPo];TzưmzYk(c`degZciͻYarlW@XaVPRTU^imscI9?`uO2/IJA826<>=842/#<ܹéxyqrVN{ǹPYW:]ڻm| zYl&VYchnZior׼]Inh\\[XJGQLAIepXN@ASqฒ{`84CC:28ADC>:526.GÒΣ{tlb8TνdKq؝eBZr~z\g;LOaijVixyܻd6OZ|y|gUWEXz~eA5\td\UFAKaɽ|X>745?EIHD@<9<:Kp]A0,ɻN\Νt]c̿xx`;aVDPcmiq~ߤp9Psjz]]ci:Fed\VJCCOgКG+9?FKMKGCBDGDIZhŃyx[?1:6\Ż]Oǭu[y)NJy bKkg?@a||CNykyqzT=[aXQJFBDPfqL43IOTQNLKLNQOU^tjWWD>A@BCoqLnY{p" R rOhn;HN>mnʥׅHQ]RLJIFECHd–d=;OW[YTTWXY`t|eTQLG"EFHBNӺQc{yWƉ?X-z \Gge7zZ@a{tս˵͟[aTLZLKLLF>8@RcqpiΗPRRZ]a_`dghorbMJOQRQLJMNLCHm[]woilygg–|4Fz`;`MA|a@Ynik}xacf`KQKTJNOLGDHU]dr֘{tqdZbhkqsrlc[TTUVUPMPTUQJ=lʛe]bnprtU`}DŽy z\iCCFjCWkmdX\`bdPktWifTX6PNOSTX\^dhosͮ`fqv~}{re[XZZXSQV[]UUCGТpfZsmtxWhz`ǀy xRk+9T³xpsKYtxr`ekom\]dQ[mbE=>QNUW_ggn|~~uΦҏ[nx~sicb_[XX_cb[XCLѣzXLviuiJgl)y bv2[οvds|W[|~c\gpul_TPZl\`D:QPVZ^gb]{`abx~ݳƐXs}rkgc_^cijdZ_A`ɢRJsmnvhbe-Aw6D+SЮrϲg^qy{ucg]OtQ@LXZX\lhenimjݦSƅ֊bwtke`bkol^bXMſ^Rd^rc[| r+hִ޽oUatb`Ylj\JUTVewl{wgdfq~Œޕi{}ofabjnc[Z\Ԧ`qZGVMgJ{M &uQ6BjeA˷sKZhssp|zy`\d~MzcGLMPUOI]iaU_jUlޠn~pf`_cbXS[ogRYyw˹h6sc1Z.w tok^;I̷VVwbmdjw{`VijsrrZ]eZOVXC7HXTMONTNlxzqf^\[WMRopgud\ɼU4eLv s3dWFH? GgMŞob[_v~pY\iZ͟rda_xʹaakSHEMRi}轀yypf\ZTQLjjvvUôxL;L?,j@tҿrta?gwtv`^gpcػpj_jo{ӬhTUgt{|}Ɇkxna]XNQSwy]fX}ɲdH>/o7[vjZPA<1Rq`fn{avugwpţjiϪ|\`ny}xƇfc_ZSKVbq}TOƵc`dK<,`>;9?KQRWXZ^futaBYŗvdl~qqبvafx{{՛^XUNLbu\´Z>PXC2#]+B_yMdθɃsx]qx]ٯgmorߒLPJQuvIXu\GA@HL?.Y#O_~xoZPYO\f[Tرfdlsa8Ifpqj̤p"6ENVfttwpsxXjs{UQ[ghUMR¾gE,B;Y9D1w؁ .<ay  (0Rd_UPeĽ%T@b (:b{n=wĻwXa|"-UkudȹVuh' 4S\a|̽{z|xlK$+3>Uz|cP?7:6+ !EWirlZIIJ?'  ;I7BH-SBSer+c5UW@x}bLqg-B#ǶeYz L/75yޔ;`!  ^6/; B$          f8 f9 # mS\\by `y^W[SkF3 $s< } \Fw+N*+oOn^_oM)`HVfammogYaL)'';) >bYZ`fL+ ( HhXH3=I9$ ?cclwYOg{n  (  ?cs[9Jg]@$>QX\rVCfy5 ,PWH;;[tyI9gaM;#-@TUCQnjNCVpųp3 .>^jkWcwyAEXON?.5APYDGyoIDGNhse: 23fder]qb4ENXU@14DRQ:YD12>\vkZF=VkY]\QgytI6I_dfzR!8NFB\iboL:[e]D:JX]D.ICDkQ1FDUP>A @%Ymx}6D[_M;HJVqOIMKkx|`[s}ƴiN% 3iK E"6Nd}ˁ=JbSAJEIHuPDMUi̹\cdir~rjk7*j<H/9>=7HTsw6ZVMKFB@^pbOZkyĭVLae›yiRJJfbmHH00.1CKFIKeQKcVLHFHPas][XbvoXW@StpºTniehta(P >[6u?DrzTNWjVL^slQM}°zvЮp>S@¯tsfuM9JNpĴʽȍCHR^oPTb~cIۦy}ː{ewIT snbeN;81Ľȵ`>KW`uJ]f^wku˺ȨpVmɳVYZǐyy[C*Hɺƣ]CQYpzyQ\[xvQ[m}ѿcLùYZAx[Ck̯ӆCLSazwYV]czɢb:]s~}uɦUXʖeVX(tlþΡgu]̢~yqܫ\IRVqu~Ga^g}LHkqpitֻy[^~uV׶K\ bȚb{{mϜs~wlޣRNW`z|iOianoHWghhjqzήccaZ`ݗ,_;qWPVk~җusi]NWYs}ORkkv͜_H_abfhov|żu~wɚ> [ s^Kj|tvY[xҏonVyࣃgP_e{eKstˀER[\acfmrttyæoӍ*_7r|Rfvxlyq`ڍhil趉nKeewԾ_Fs}ƾ~GOY[`adjnnq{|eo_IY~yjcWowvrrpRo`i缔vEiowSBv۳U=PU[^^`eikt}‡fȩZaR^UzJ{^[idi^ahĀjatj~߶}{;et}8Vt]@FGQUYYZ`flwƌsiw#a%ginz`uUqPPi{c|ln|Ɓq7\t~ϬXAbxTJTDADJS\^cjov{xq˜cMb SttrxvRuξ{|VA]qtj~jo¸xBTo}ĮP\sFIhbE117I[dilsxttжѳlg_5lbmleH?|ؐn}}a:[`pmlnxjltuhWdv˟isEJieF0=TK@UvzxxvطĂNwRiýfblVE_fv}e;Rbztafjhza`wpĒpisą†}vFNcMioyri}nN{e\TGJdڿ~}ƴɶb>YhVUxyvhcn{Sg֣Lb\HU2$tT m{rmsrIla;DєlfĨg9GKA@Moģ{ݯ[C^i`hvmm4TwuZhY< RWv B "8ôddQia@9}opl?:G?:8KrѶuԳ\Jkfhwpq˷rLYy]mwpT&>/x^fkfgĽZmvYQf`G8\snN4E@921Go׮n̼fKqgoΫα~kWhjsT>` x al]W~rɅN`cQb`IH7g؜go9?>6.&(@]nPxqxħǪ~tȺ{c}{ru&=y`5Wyrg~ĿsS^aR[aNQI5FkЇuÙTHO>-+%&0@S~→uX͖j|qwõwkrS?Ew7u3 ddPxȿvUXfh[YM\bR]fU>Z|UTO37DKGB97K`vԎL˖›߾pknjsыV`A1dl]jy x li]asf^WfͭaJSdS^mGI\dVZlrlbM>DZgx˃AK60Qdw۔WԙuӨwknke{w\>?a|mgs !zWf"X{ghZXspb\VgnFG[bZZeqtnbUIHNnk<3+2?KMF>91.--,+1>aܝ]ܯmt׷mdl_cҾu8Glo~'?z[n._s|jhZ]zƭ^kslidLC\d[Xajoqja]QGKfi<+%1FJD@815:;71*'"Bުs¾~yTŶw{hPo];TyŰmzYk(c_eegZci̻YarkV@XaVPRTU]hmscI9?`uO1/IJA826<>=842/#<۸©xyprVN{ǹPYW:\ٻm| zYl&VYcgmZior׼]Inh\\[XIGQLAIepXNABTqฒ{`84CC:28ADC>:525.GÒͣ{tlb8TνdKq؝dBZr~z\g;LOaijVixyۺd6OY|y}gUWEXz~eA5\td\UFAKaɽ|X>745?FIHD@<9<:Ko]A/,ɻN\Μs]c˿xx`;`UDPcmiqߣp9Psj{]]di:Fed\VJCCOgКH+9?FKMKGCBDGDIZhŃyx[?1:6\Ż]Oǭu[z)NJy bKjg?@a||BNykypzT<[bXQJFBDPfqM43IOTQNLKLNQOU^tjWWD>A@ABopLnZ{p" R rOho;HN>m~mɥׅHQ]RLJIFECHd•d=;OW[YTTWXY`t|eTQLG"EFHAMӺQc{yWƉ?X-z \Ghd6zY@a{uս˵͟[aTLZLKLLF>8@RcqphΗPRRZ]a_`dghorbMJOQRQLJMNLCHm[\xpilygg|4Fz`;`M@|a@Ynij}xacf`KQKTJNOLGDHU]dr֘{tqdZbhkqsqkc[TTUVUPMPTUQJ=lʛf]bnprtU`}DŽy z\iCCFjBWkmdX\aadPktWigTX6PNOSTX\^dhosͮ`fqv~}{re[XZZXSQV[]UUCGТqfYsmtxWhz`ǀy xRl'8U³wosKXtxr`eknm\]dQ[mbE=>QNUW_ggn|~~uΥҏ[nx~sicb_[XX_cb[XCLѣzXLviuiJgl)y bv1[οvds|W[|~c\gpul_TPZl\`D:QPVZ^gb]{`abw~޲ŐXs~rkgc_^cijdZ_A`ɢRJsmnugbe-Aw6D+SЮrϱg^py{ucg]OtQ@LXZX\lhenimjݦSƅ֊bwtke`bkol^aXMſ^Rd^rb[| r+hֳݼoUata`Ylj\JUTVewl{wgde~p}ޕi{}ofabjnc[Z\Ԧ`qZGVMgI{L &uQ6BkeA˷sKYhssp|zy`\d~MycGLMPUOI]iaU_jTlޠn~pf`_cbXS[ogQYyw˹h5rc1Z.w tok^;I̷UVwbmdjw{`VijsrrZ]eZOVXC7HXTMONSMlxzqf^\[WMRopguc\ɼU4eLv s3dWFH? FfMĞob[^u}oY\iZ͟rd`_wʹaakSHEMQh}轀yypf\ZTQLjjvvUôxK;L?,jAtҿrta?gwtv_^gpcؼpi_jo{ӬhTTftz|~Ɇkxna]XNQSvy]fX}ɲcG>/o7[ujZPA<2Rq`fn{awugwpģjiϪ{\`ny|wƇfc_ZSKVbp|TOƵc`~cK<+`>;9?KPQWXZ^futaBYŗudl~qr٨vafx{{՛^XUNLbu]´Z>PXC2"]+B_yMdθɃsx]qx]ٮgmpqߒLPJQuvIXu\GA@HL?.Y#O_~xo[PYO\f[Tرfdlsa8Ifpqj̤p#5DNUftswpsxXjs{UQZghUMR¾gE,B;Y9D1w؁ .<ay  (0Rd_UPeĽ%T@b (:b{n=wĻwWa|"-UkudȹVrh' 4S\a|̽{y||}xlK$+3>Uz|cP?7:6+  DWirkZIIJ?'   Xf-!JL;1(7ӸRsQ |䶆V#,Q6àq2]ϞO[ lDݒ/ Hz|oV=(lקq!:{ Iyn dg-lFQZu x(d6! \::5}=_)7yJ*^2uQRE%9Yq3D+F:D:B?CHA`SofnVlDZ2F(i@{\LK:_%l6kc  &HyB'_lNb# Auc 8[߳yK3MvΨC""2W{2LA4(U|.>BoR? XGůUS[IJ*$:7鶪O{7@Hkk?<kktq݋m6nƶد-mR;`zv x#=\% oYRڱ#&?>ҹЪn_;j;$}*}+(}'}/LtY"$].9⦅%{_a݊]hk5'SN{<_ t jM{-4%TńtY۟R6#v\喊x:'HO3^&0::m,L%3:qVE t]~Iv6Wٯ) |ʸ2]G4(6w‹$"AEv m[D;Vh[}چN|3HS:KtxU'D;77;_"e?Yqxl+@IDATx ]W}&sߠ'˖yb-π0CB* N;Uݽ:ԪUITHXI36b01`#yy7~(lٱ,ѹ {}asnR@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!3gn p8p0 NjfkeBAl[km9gkW[b$-|>dzdݰ 9>sl[5.j@!"}gϺ\ͮ牭]l}2__3zc7>{ 6Z~ .w.??O>ڷVsY/{m_aֲ",fυ|g+VXcw?SO?wsr%;^{ͬ_~{YK0.>+!V<"Y|ի^??222z]wuv.%Kt !fF vagc83F w~O_K7<|&1E!jh;{;?#\n݂u?<{/ˮBauwuWaÆ._666nҥ>{S>x>rs{衇 <|.uĂ\`02{ǺGwÍ7[x㍟emVm,}*!c;ukד{=sOp!O:3`Ń[ouvmAA`fff7phDX]pvk֬!=wy`vvvs#%sFƉL{oJv ]oibφdKb,0`ٲecI CK+l7:2:3Iƒƒ%4  !~x纔-\h^kA lbx=wwwG1s#3 ~~wޞ{|386!aHd?HO.3+:u3: Ve]eARD;Ymc׼5]Db~w-][7n1kXxgE`n{[n@5ݢ]u 7N?[xp+Wx ʘ9F>S6Iǯ}oGG/3&Ab'YJvbZKm?Yd滑ёފ8w}|x߹xtIvwK/x&1܇B.܀j$~xko2߭_ [Ff"ÓN:3<ʋ/c^{E C-Qψ9 ڐ3l<6/7܈?>.?jْ?]|n.u4Vxj*qzքgd3ccݺ5O|&dxMPM8Ѽ24%D/[If@|VD!QnੵO 7!HQG5aWjʕʹ+ܔã9.4 t /.M ew-; L/OroUGbYX8ah<_k_.d2 h~uSSmRr'n5'ky vO=T;N(> wBv(;~ %FDpAF?i'%?0w+X}._@r>>\X?٪Y{ˮ׉bMD{ssSFG`Y.x__2KYdH]w}vI57>"B9q[(!qxW6]<ēL )\|.00#YooeC?4<}i;҆57|ww\>ѫza xw.6\C99V}< 2IhpUWRNKR&8taCB",JyfN$ ($0@ Ǹu}_S6ld !  زv$DF ' ^q A=+GVhvrN̟P%:ɾ&By-٘\)ȭ|be@,F?qcI6n5|X"agMiÏGl-%8,,0N~?)1Cs"Yr I!q6\b#eKŻ-nonDGd8#joո`|&@P2?%A#]]K*  ]+qHhc#o10'!od|'H<{0^{.N~}uI4}p1lh ,hPlJ?:3!o{. QBX6#暛ౚ-@et?6&c@T֟PX zKB}^Ww.Na>s3-${}n U6!0@PM|A?A)r!_nr ΋(4K^!C%a{/%gX .+ynm.v4$#ykxX[O6^1'y`\w:Szsù6V [P!4!vmg'ȜuQ{i6Ǘ7XY R!'U%װO^E|9aSXB`{!;oam6^xW3K )ɺN9.sﺻ+~94#W;s;c-y'k׽Yl׍ ~/\t9Gpq2Y{cou] ;{ԑGr>{e ģ=چwf h /GQ9SޮN^`&W҆He;!PݬXnq'C<8K?u}?fy4R"lY} q-mP6h>~}iC0]BRxA02"=sWR`-/1%/1)- o=bק_s5C1?wguD>df! $ "|FRZ,N4zrJ"&k+h(x"?>qY,Q2kibf!"|}B%\2}vںrP`xO+'-%/co~> )qg";V376 Xa]uU+Wd͢c;ِS`Sz cr ZI@gJ7ƒ2o}[[ALdFEha2Q H,s;r 9Ϲ!߀껕'"ы O|ι‚;<|ZDjY :?c ?vOV7Cua^ޙYtDcm+m{ug%g[#'4H%1N6~D;=DDn$FZeu]Ku =ķ_Fo %EFܓpۏu`3`Y%Dk9Vp(x=tw NI3{o,C[G~yrr{ի_\>6lq4DKMHGwd.xÍMD H!KoAlDt-r!-BD;:K&E E PC=up?ȣMشEChޏ0xje,B>q}^b_O.ܧZ^KL̙`!.BV]mz{ّEE*5܇:?k|G;@>#Kɜ{3qv",gFZ kD57\ ;p,]X|SP[  wË@rh}'fFzG$,pW=0s2O^PT/h)xAp=>=I0@(Ƣ=b#L?w^'ؿYf @@d)XOV7\ s<q7QOג,2ʱ V8('Kyg+_۽:^r.LG.XGb N+^WCx!a~ތaAA%Qo~̧{"ZGeR9߂`齲os"Pl`tabl}ƬG1!G{'+0腞,:U'5KśȎ(hYw"2!xV@͖Ev "%'F$4hBvJ.*Pe_0ٕcIH^j/a⼈&^^_8OY61Ɉς x~FGZ៧Zx~m^JM'nOʞs\q7j8ӳSAO1YX|dԾ+6#+BdΕۻeY k\lx7+i}Fzow_ju:=k^O{"v-!#d&fa|V Dm6̨N!@K&b;}A:h萉[,.vmHҊ}H8ʖLPHhf8r]CH2|1u]m^,9n:nM|&8oÅ#ܿ{“q0=> QVOHz KC6 PD!F"繇EBg!εl#5`rfc'8Xe!H_#,W}Zg=S@~$ @$! ЬC#@==OtXIeCԹ9sݖX򈁺x$^B6JnPFq\FTy ֜7Ax7= _rC) fgc`2"03ߪi[F`˸tA6$$>kS!xsï}kaYYq!.B! ȂEnYf!k+';bq-c&>(I艽Jy,*1ǟx;Sۆ_կ~ooM }5/$ä# h"#6}E5i9`~71u%?#O2pvlB4Z^74$P]fX5VZgF(d@t~״WǸ&yG6 !2ŋ4Xqh<99 |Uk,_uҪJ=G`r8sQgm[eZ b X f~˚<ԓlJdM֢NE.x;Zˆ 1G={Ai BWqR_^ c)xpCxK~ghLQ!›27|߾ e wY:̥֑o&@dnDf)/fI{D!h6! ^-^8R*T#;DxDC.˵sm7<H[u;} Oh1m쓟9 E;YxOщCg"R #D!D $ۉ wN}&%k6$~Kx:pa:0m$LVqunR9nc,x#MDYKXHG>yđ-g`ODXr wcrr qAV^zu $yԑ]U y+\}r˭/ FmB(ˌ>aby%CD1ӅrLvjgDW @hRWyѫK-j&;u N5:fou\ulnmbm #i$tVַSb:\ $ k~ͪBDa8 7O!QPG_. l^'|&^LZud$ V7Ɉp-L2wg "b+"|7 s瀘-R{ lc3a,YI,~'a,Jȳ-o$9":=b~YguH *6VމMJ`Xb> 7~maCH+i?q/v$!In tzS! o~ \;GiE~E" d<$zkef',mltO<b~a?(dv ا]zxw/r/F?l{@Y'lo ![m.ZhcweQŷ~G#NqN'g\TH8cғf!͐(}׼l rzQQ'ru9泲wrLێ+/()4vh{:_}yrb6$"W@(tDBfD77[{xV G;|O;QfdnicnDCoK6G?˹uJ9D\'.2y]ez~,eGq5!LH䘉7|VRrWBa]kp|B~Qf8|2F&$FP|rdK"#_F rzrICp3-B) 2.`</{SQς8&7Uۭ"PUh| ۯvuH {Pߗn%Q"=HNf ukŹ}ADCڠ ?*Epv-hUmc#!".*ӂ;cY !/:-<좃˚+'BϜgɮy`M +$鈍i+s&LNN6˾#^{܃X'@^=# =- 'F+ OQؐiì='n!B > oyx`|-v©\Vj5JOoXe,h",:87i\?%Ugh3OWU'G49YL5hd5:"J B!F OϫXfU&2/ķyH"@l_,OOtG= oy>k4qh '"\@RD"> p0pC/rظ?gB%kL#3}zqdͦJVv5<:N3HE cy2Om=+g鑝ֹ2K` ^FKB>w_w}s{"B|D@9Uuų17@۴lWu>[lU[{Wg>K<mYmwb=S[qE3!Cݏ"}Qcla woZl6|N"9R':Yz!`Dm^疨B,qeuv^+ЁC.φոo{Z1/!m/>׼ר#׹ xBB":$#@<p"! Mn!׶>p-pr%jDCPKdݿ| 2!$KO_`Q#aR'hDfS/F q";1}*D ު YyN yI>l" "Ba |%ؐgSӞTYa@Y< tIywC#-r@Swuhķ2B:D+͜[6ן5w#H~?6w" kK:$(4Gе2:bno<+j1O@羉Lڣ.;^cVj;apos\Ir@~u-Ɍ_j4&Ϲ'n=:ίۖdYufmF! :2#gw,}!| _hx־dRWO@\gq/H9{vK@S,s}'Ѳ{Cb;c&`靀ic VL{3Ѧܞ&'hC3hMґ:9R Թۈ&isviur0l h숡 $ԁ1<SeќkYCt "_+'[=ܫϠφZ\iA&}pb{g1V^=0{U^mlL͝L=BB96dtPޭ5)<~V1wyWX:̒*qpR|梯cu#wŵK9bwQr==ܣŋE:6e$KmCt!Z#{Ͽ[y#Շ<[Ohv,"b{'Zk?Plx]J0@"Op3mkdy=D`E wR,8Y-ګPd#Q2IK>^r9 _#`8f"T@)-%χ3RN\~{>tHn#$b\`4"8;e4CqY559Ӯs@>YkP'"xHmUz 9%:F2l^x%'+IP1 Un1!Rbz$w 1^1qۯ0|O( o(ґ[9[y< d#c'~NǝH'w0`u7Z!<z-8f"q>D{ s/oeAnfX=$6Vnt=][WgBuW/NL=dxP}##ܹK1WyxU,\DžYN{ >#Cx?ljD!5#)cm|8ӕYaӶ:e`$Vt|%b\ꉸ g: LL,HV,n!ɀ5FBMRK.& }-F6!\@DD:?!)ZP$gu?N>FD9eMfC~eXKA=HNE.sɅ[~\̈́˽ÆG`8?-[ڟ WIeu*zO DyJXi|fq]Cc*%ڎ֑$ wfnֱĪZpĕ! kǺy #"N?I|6)|1 d5M{Wr+cH&WDq:%=Ȅ=,BTX3Gv}_8ϓ9>f@^N\ U`!Ey'gyF<'KF7+;=+=0!\qQ3.FNn7  ӀYLq}/G^VxfK`awHkkfg'(ȇu%$݋VOndW0Cݼ 2ܣEC~O# 6 Z8fhBJ, Nrt$M_e7mECzklkBc /!ٷbdxLzY+WN7IHe_`,.[3Jb-^~=T$c\3?tL;FT^M?lC~;V`eІPFAFN=1 <ȣ+GS\O5 "δNd%ȿ#_ky>Jv^aKJǛjֆKKroSS7L-I8'aр!lkBq* ի_$GPY|9m@ qR^> 7 ЁC :aAzޅ߽]/ϧ6I>lBAvm˿s rR<3=GpFƫs*V_onJ^(b~~/:y!n~!pXw_]^quUWX)##}%Љm7,'ɶW/_y-gb[q@||^{v$04@hPB7(S_9r)zn4xƒp<~,:D>0 \Q9MMq "@,}ǔQn k]ƺ7re~MwzbWR !L\‚CpH(f}MC  <a=۴ySCv%pHp%×ނlvi2"@Oy~o\Yzn^Xh)-챜S[ˀ@Yu\;ү9n,;}hM,2Y'>:uI"xEaH+O0͆lA,4-_pyu_M<§dFr$L4+Q(kcj|ӟnp\9anaE&PǪL.1Y{'\g$e" ILP ~Yss@/⺺%@*g@1m2h Jݱoɺ{\}yF>򈭧#z"t,\<4j=V&!:lE`kP.wA4!Bw;n> .@ĸOEG{>Ofxs2_LH<#:PytXwpl\]6! !j.IqO N0e2pdU醉rvigB!}8B@ނ\ϼA0g$ E@2){6^ɢ}Hd೹7/`lm v f״;W`r?B}њX"dO!lb QW~K>.By XtPO iČ?!iC28@S\Do>xT=;\X͖;Ȗ4?[7]/ᡬWrʕNŏOL?aFzA^#6ӄ&4OΝGn$g3I n qsy~s -96Dy;hn}2;f)1Z7{ㅽ ٖD[?GFδscᇙ3DC 6iYyf>[aH/ 40y1EIDAT 8'^Issz";v)ر7^ ]V)8Lf7g&龫2f6naqӋ3w4On]oD Cmgr [E\v %%y#Hs꿝 <wxswYNE~?O.ɾhck"s;m.@8}! o8'pu}vG` g zq腠϶UQ~[$,H~.CvW]uhG0ʅ+fr2@48H@ p{u^u@lcٞ8T[A[gtw& >l&''ߓ/ayX 桞6d#' hxyy yڰ$ IĄy-yqxWT]ˎD; Uˏ@wGD^b'"y/"?n$"E nOr$a'iN5eF߿2<ޗ!şM`xB/yy)9mj4~,΋3/6Cgו  ۆ l}_/<]pT&ѧ[fRҥ !~?!r^_^/,U΄@=35vl[z! 9!X+917th,H0P2pl "$S0H2ugJ"r˛?i(i;WC6x#^tE>G^X_q>yʏࡠFͯBx"}g0+ߖ|65+gMDy[f[C?Fu[@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P@!P?k @>jIIENDB`ic09xډPNG  IHDRx$iCCPICC Profile8UoT>oR? XGůUS[IJ*$:7鶪O{7@Hkk?<kktq݋m6nƶد-mR;`zv x#=\% oYRڱ#&?>ҹЪn_;j;$}*}+(}'}/LtY"$].9⦅%{_a݊]hk5'SN{<_ t jM{-4%TńtY۟R6#v\喊x:'HO3^&0::m,L%3:qVE t]~Iv6Wٯ) |ʸ2]G4(6w‹$"AEv m[D;Vh[}چN|3HS:KtxU'D;77;_"e?Yqxl+@IDATxْG ¾7fL V&;bz^GsWhL ]F#8dwsþH|,ib"2GDFf0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 @` 0 #8;rO諦Os : /b^Rβs^5}Ǒrp @EG`Ep7B򏙱1?VN?i qpyI;4"NmU9?>O秐eF`x6>v B!4gS ,yUS; #0nz^߇v?88 ~w99QS};yڎ zIiU.҃>G9$GWehLXy^9=~t=qpX_pGɷt.]~TR6HN\?ydn5:<~ݻw߿ƍoRUR G<#jrv<iq :Х/^ٵï/2(~!6Fk3lzFnx'mZe*ˊ)]*8 #pԏq ^Q!5=9vVE98 l'q;r7N~'N}{ooo+[ۋ )n$lnnd'{zׯ w濻yyBɟ|>Vvconoo9^8qwA}$f ޽{?~(=VI-K)Z[@EtV鞖jDhl` 0x:C|z]qded=|3(www;v=i3~ƶot^Yc})c641#]\&:l>};9ybT8JD88q3S>k5 f_'}B7ް N\GTǚO ;SOG29}E3[dzֶ6%os/iŬz΀_mz俞zZ0^ pqun00 at:kAS^@;#a DknVuϒS;3 3MKzZ9 |w/Xp<᩸S&D8)r)[[9xUsyؾέϟY :h#ЭcOYV qEs6;ﮯ;amcs`kcӽq7z_Oz=]͌kCsW~ww/nwH;&[W 2:XY>i4_4@E`1#pԵe(!S<̕pSۛg66NIŅۋC?Ԍfq~S@H ̠,Nwqd8ߧIO̞;8̖.*O&N'?gϞ"3S\>=*Lv8nhh :Xxoͤ׃x;:4x'^D'7'EOiS3jRmp;n2~,tuOvzv!}zFF6;~x؃{y)75Mo\6𝥷Kztl~GׂGjڇy'8qDsyd<@x23*_o ^pqg}VeZ._s8S>v*M3o7@qK#zr*}mi@?Lċqboljfx9tS~*}kY_:` 4ۙrA JA{8˭4^b![TW$;wΝ:v}ۉ|:x29{zxtP|-ұUҕY:S6uOg#=gD쥸[)jk׮~ۿn^ 6sNF}I;?|s1xmO]qa\mW#\i>{vֻqP9gvٹx8P!ojf)vi{[1~ì}ʼ <6kqqt^>l^o;Yߎ,#ǙtJ<lKs>fyҠ[Ro;\^hԃʇg؅a$[I7ʾ7&Y]'nͤ7<;B{D<+9tNU &BwqT_c^ 8M<~^ 7ݕ̂q.ge{÷lxaWqg~ b9ôd 0<5imTPwmm&Q~09p{;?L"h#dF6|) OTy-ހ=v?vu#zĽzٿ̓AnJt qX:\aV9,f?ܴ#vʕ<>3f,ގ@JO%1}>Fk}vG$qx:6 hr@6 `2g@vg%(rfoJb lo7݌w2@^󸡁üHa^H_gՠnN(vx "0}!k)oU@d3@Q^YtofI|X>噼̈́q((&+y);q8:[_` ?efUΞՁ֭fiAOHqKG="G=y%^.r~e;K~)]+la Xe)\H'4t-Yᢼ}P@Bv3=RJ-aN&)ۏܛ9[k@V?nLz#ݽu7f|S{Cn@jȱlGזs%e@kL:@G` ^S+Fm}P 6'ȩ/f1 V%rhlS|+6C2-G89ɚg)A@Uyɼ'o^u?N%A@9vI7̶2GXB`@wۓ Wr/_'ZBˉEFw/m#_rfr 'Ǔ|ưX(9 j&ocYL9¿zOy |he2?8+4n <# ưErh9g]rk_:{v^N}B_QE}ߦ9z6(|>z`v]o7s~7881'yfٿgyÌY;Y,D\ӗ >{\38⑴{ONï{dl^rIml >y#//7}9q~DmKx+.wڨlT*%ܱ'WF;Mܵ,Yz#C,p¦eK-Oek"ļ4)|b BXq> Ǎ\rW\9d"}y:õs#=ȣ;q&(̾x }vHcZ?sc:]-?{̙yVB 111ۜKӘݹ'lh8Gfw8̷tϰAMxt$fb^ToNy}c[y;;kXg4('c]-gyʑql\+MoޓBhcܙ`7fޅnYrrL29 ]rVᡍ|+ikFtU:w7 ? 0΍G(&&NDC.,_{pzV7v=`sdog3{nkO%!"u<d2@zmv v/rͪFv #0?9x$X5Nw?GqfZ]GCQci<_L>vwfeӾr6FC_H#_9C\}ˠf [f}Q>s-rٰF?/~*OtM~'Q^1{:-4|lԳa).Ӿ6Ł.oOзԇ[;ü)gVhţ+a3D镆d x- E 9Vx=>Os{ɓ!zL >WDE;|eiY04Y^9/$s'_gݼe<8+gi^`9YNd9)u֦8Ksd^z# 8܌J9?93 }9(hnrJ%ny 961eI֏%9^fwKzr|,dd-矼/)| zjBCGi[mzQ0g8sG)?imf[˺ Dn_,d`>8yn3_ʭQu>Ux+oTVsݛ=8u"{{7`tVJjf q?' ~'f.0t@Xl.F~ #0/)zdoɨ7w}o\t8f/8U+3+#1^9 @|_z<-7Fuxp=.ǡ xjl;rx4@SmӆZ-BﴘE졋aUat6@튷O`b-Lq/LХ}96;M5{n9tӥ1&\vNeu@?p[ӓ>zp!Gy|).̀`\wNk0%:!OhԼa܇Ɠ'ASNI_{V̤szMdJ20o3E;k61x1Ë,ܘQ\t_?ۣyggϓ"J8c1ޡo^96 TCaE4f'Z!Wr޴{5s4~p9-39(QRj,WRNd̉ÛD&sfh_:T%~A/`H 9Úg]9F޹{gA ίH7L}+m]`m׮UW.|s6   eo_2ҋ  8?V [ν > 9 4j88ZNR\W/"*G#z%0O.'S9n#j]v]>ҁ1Jvx1lm WQ8/y#=Q  Xt-[#rqhN+Mݫ~~Yp84̈́rqO~.N7#~q5\_:T|RxVREy%p=ZԥYMs`gڮ&8zLdHZBCY"d$p;:F[jgsLք@|ҮU+YmJ#gOrN6? R/>r 2o'Mdl~S##S?܂:vԷAGP(u}lPJYmW@"0W`eؖ7+\=[ou%gqn򘕚ՙ  ~Z9ԛ'߁Yp,iwsXb ML*EN::ƫSt<L" 4Uo zHS;MG+~XKfA4񚩫s;#38SthS1n/Owڼã[VkMb=,r褉o {]nREKw3 8,NXlJ}Tw3(xgB˲|Q]0GѮÁOtؿ,=ύQ2q}J?mzP`/2q+(Gb9i8,ł65i>7_[2^g%`FVֿ-O ɊQ{Rub)36Mg^mcp4聀G >{wbqvtpҾǗ%堬gu>+!x6yCsxDIŬ?9,r_$$h$%8ޮ η:ߋi?yoYWy"9n T#+%wR1ü|?1 zvʌ/l /]Sz/L[Y{Ћ-©cSY;.r23vnpvJG훏2܎9<8n*o_-ǡ_λmK('a#w?S>y)tJMqTMvпg;r Wie0_OE?\ ^EѿC: }l&`TH>m8KbEށqEMO#O[Nb伜ϲݴ)+O~)޷_NP/E8?(dOKš/ ۫~ay#y;޵,'fq]*FnMq9U$X93yTVm3IN^)*?Gpr-0>Қwn׾lu/\Tfl[T T&LmLeXzQ*}h\ kߘ(+bҡS>V@c~ mٸ5}o |e-bȒo*@ Ȅz"b:5\MJvt߳)KrfV|b7vi  g3X:Wz!u_B_4/ENǔ#7 KOA*' p>6]m2E kkGrPQMs9?<9ZNi^Ur Exp^‰OνUfD;/cS dE!,x'RO[u,ܵ8i93}"AιF7eaЇ\-t~}{# Ylv+L8*'LOۅ|s9^zUeFdӭbi* Wh;An,|]xu9#_2L; S͛^7_򫯾 b|g;]2+aR]:.@#0җa#$_5FM ?Kbl/@N{-ir>'wX35d9m&rscD}ho\ 쏮fS-DH~.M3SW[}%_:ʼn&Xryn%,[bd{9p~(-T@GcyWڃkwnvܺyk[kqtkk\Ouέ22y㟴'WT+m¢Y=#)<Ԭ_}Fc² u]}>S@9Ӻ֢KHqM/&Z:<|w^_'g0mOj鞖.F( cg4&ϠQtҎo,/V1Lc&xn/Ks 1uOZ"K2ɕ1JrӠq4K:2ZPN6J#B f0Çztw1Ý1$>ɤ :V/o+Bhr>ћgY_e'1qiԏURߡL>nwٝ;o3|׮]c3{sՀ6 _INzW}kr `?1x6>I3}q\V(N7r qmP΃ъa$_0\m+␕azPof)U.t&uQVCVA:M'+x-s"98mk!rԫ~>aONq/V$:NNbд ?۝!W%xi A^m2\nu {&UF8L-tl;O XhrE H zyaazO2lΞ;wlw`5÷Bn/h:& iy}]#<7A2U㳪{+lAz:x2F|쬷1f≒d[n܉!/_j/^s~kS\`k 8!ǜ\})X^j!}Z@}׬t>7W2+.r>Z|"$}B@VcyEN@g<►OS%~މ^;n/K=SA@gi/04 ,sе!\ucS*R^xh_(頮Mה@.+~D?<3x&ofUp/'|^o%𴕁>.Ē,KE7+U; ~cz HOwS(gf.g:Yh F?B%2d6oKY}{CKڗq)iEޒy zQ3o~h:O6fd/~-'Lrٌh# eȤ=XiOCtKYq- EI\ 3ˣD!,VEȜsZO`*]&oꆚqd{V[$#k|/Uocd?c`/5V=i]N-kWw;arec8Gp hˡű3:4"a[+ r29~VЗQnsZ[v90#m6 6ă8{8S>{k׿@`ňND#K} G0FxeІ6W^=K}6c<{XbV.5+Lg{˿(g3fvN;.cmMvL]g!uDFYG}v{ev9t4w}um鰔uF OC$3R7Na>DW}$ lLulUtETC9."$f;L^T6 L 2>O \PNw$H;kAZv@` :`,`t 6(AaXX K8Bϻ/h^,t Dsfy/ Y-Cce1auQgk0YCjvKYT9 %]^ֆļ|pN++q|v'zi2g&Y#کAma_<l:o;`8]9I7|ѫ.sNˍf\j?P;:ttyG::v j!(f޴10 xM#Ô뚊U\nIlek5uڃMv'<Ξ=UН ߷/??{Z;>{\x{J^ 躾8گۿۦq?`䰍  ƨKyŴ8yȣn1c͊=#hY }*2F,-Fv3x~xOarJ8^>|l=ԣWzGF^̮(9awcnWSǏ>:۪ZN>;gU ^bAocز9m=g9w<'~rrjumtt𴁕u9{#]ϗg> p RT8tXt%?޹mr`ʢIj_0@M;sӰ=Φ{/SfRVٷ*R@W7/^<x<5D'px*xWK?5bOYo#zò̆0K<|6dcG ;Xs]8qh`ѕry,9NkppPihʼnS;A62#{as"|txbf/3oAY>u9:-Ԇ,2ѻOKiw6#r 2|i]] +@B_˟5N9ǵ|*/!c3u "|UԾ[qq}@#]-[XQ}w;C\ٱUJt˧{P#J-WВ>"n{w>38{ }*迸ȞJ1*^'u:ۏ{־ ci1rW\O\?Y>Еwb8H jxȰ3\r>xS^!mAq"f ZeewY j9t6oiu|ؖ< T&-vTD Tk9Xr<=v9_tW.o~4Oio*=~lħeP> .U橼"cul diɜK!ɰsmi/kwѪjK|b1uR.<s9cDϩF[0=HgA6HKY:_.uK`=DV0k>@;mC[c{**ݎ?sg~?!Y1p'B2 A%籀7oxsHc8/|Δ$U~T @Ym\G,*‚xy*Ckg?gwv?o^8|ERnc̕I} `Yxvs;{eE'5nU7>{l]bFL(QkS_N篜2SU8x-xlM_ u3b^NLj\y'Wb?L|/S 3֓qU01:v#<]y+R#Ѷz} dbώ[rXjUnC7L]߱[xn64;"7hqy}:3)Y Tweڠ/?>괇Wpq2omq!ؓr9Or-r-`&}6&tIN1ZkIox4]ܒyTr~+XpM᳑kg/K.qis#oZ `): l+E0fGN9JKW>}_^FE` ^Sbm9:xPKo@k@IDAT ο`29ldD>\硇WАyj'4[N9S}9%sGeG(^: =>^9xUyfFo7 r> O62^l &'" NG(+zor}y…?şRכfEi 𬍃^}H:K` q G-+RHe?\f6L{1NeɈyV V V w{nRNpp?x;D>k )G O6Ȱ3TH]]Y>:{%txlU7N|l9^Z8L6D=@Z ;5 J>8V81A?-gjۘJ瘖RFMV7VvM"k&:8G69<8FKs.3uMMty:IGwҖ#2ۨZ(wME+Y,ͦG' ^U"K9kߙL\2 Gh WӵkO?G,Yx׏~(8?V8~;5 X!:c8-/ىIQ/㿝(=.q7n?~.x1ѦzO7Rye+X٦u9 dimJ\XrG~2%9 i#Eǜv%'YM˵S{:Of3v@J֦7Q.̪(Ӧe *9m6v<=pn@+7AOlդ|X[Y8XpN+ B l`B']h³ }׳]}eV<~퍜?=,29m NZ΋ڊn~W>KVk)x=r^o'`w pSHNſ_*u +WV?8cj|Kqgw~g-[8t2dOJq,HeEbɑ!&.׶ڤrRNCSedk: 62蓓덈x,Jw2,Y\~Nh^nЁNf{fxMn: {^te&`^Osh+p6hhsqKd7 U HkX\}mA|iyzzP\NǺi)NR8z+r4BpBWe"k_?}뛌i_# @dGZj0RZ2ce3.&7#۝\賓cNVnH yM `naPW6wR/0,2e }xV-~xgIt--ʩꋕV,f8Q3ϲƓK_"4ɼ[}~kYX^X:ās0w)A s=g4RrLuClW̌@MیnړWW=YŰ#^^-CcF>A'ֵ_L.:jWOؠ>y*G+WelYzqh'עlMVY7{'O][*7 >]e ,Ƌ6ӆvK);>#&qI;|sg}7_{'p>íüaod )_쿎j_` cjqw:7oycoyw%96?N; ?Vl|hˠ&*gXJit6gE@v`6̙}{8 |Ihsis C؁\);ȷsgcȳ<\pWG$/7(շx5m [ip1xK*I@q~y~}渂09zyq9Mꋳ^z~X }pkOO1*O^RA|F:+z'ˏ~Э{o{l {{ݤoߋ!4K_EYߙa*#Ű l=:L;4 KxK;2ě^ TN%Ϩa9/c~<3h@ޖ?.<٣%Y;6~Q5v7_r)sr 5-=ToӗՉy ѣ1An׼.oͣ.VZA ]Go[F/8lE))Ќ6ósϹU$zOznp5H.+gG2Ec8f}22xp+1J:yrz;/cn\Ϯ?mo׿ŒҗebT?W 1xNhhIZ4)3d'cPɏ?Lf7S}7csv!y}-c8X#2V^X:3>N/mcij/@z1qtiYdmw[pk,j``o~?jAxvrщ\yt7gen^un~A`D~~/Y8HeE͙~l}~?=NIx9ѲG}>;e˴c-Gޏ^urjoj䋙TPXލ&U&2bm˲YGY^?t uʥffLΊf*B-ͣy6.h'-9k7 MM~z4v bw0h~ t8}DT z-sc6wܡIkFl{C*vh2h)ʷGYغ4oœ2l;Uֳq|s#`n\{n{YbR{:a^sMG^Jk3 ~[qwԭ3}nكPZ7 X:~&/Mdrwo7.Y@h%8'SE2'ґWW^'(bԿP u:~00~gLC~ G1N?mx28c59#Nս|Ƭ>ێ }# / *6ehjPj$;s%,sgV}dVksx.rn޸vZЖLz]qKխy|2Ulՙ{?ݗ)/SN߇m8$n]&E/yAZ:4z:ExBTx4MAwiwhy[ǹuMC^])vݧG7?fnI_ 3@-6Agkċ=dr|9%Dtdr!uL+ i0hON\5³gCTrkk'O| 74((<Wc/G3+'t?Zѿ!#b[1^J<ót2D5g6X _r)aOM;~ORKl,1Gm`2 '+'a?d\]Q.ɛҒ[_дOKђV4-iLV+5p 017>} #_'!gkYm_rE䁻(r ώrt2D7_;͊9ι㖃ds} A~9 M|8}!{`q,:yA;kBӀ+K^z|ك`uΩ"K2H8싱^˥]?vA'ȏuqr_\ԋA@_ Tppy9<-,2rM7!ky6!s1F}l7rڑzm/2NeF1LFkRACK8' 6?XF zFC{i͍|;vL~:3֖V^ճkU.Hɀ4dt.J未C;uYe=984|+/}2ㅮχi]룼nAO&H2>nZrM:E}]89ђk쭛-TٽNXsN $u~&?<&~52J^xN,62!]ӹ7n7LTۺt]`p/sqy2qۿ˭OD'W?ʳxxզ X)G7 'hi?XXE#uўaL>"#}F(4FJ-؀k˜ŐT6!/שDaQ)&,/,<,c{h2p9KF-2l-oGK[oƾuWCغp c='#R݇hsS|COjg<ѳeЦ:#mlWcXYbA8wdny.y~:GZi]˪+γt=Z:d]F>7R})/} ]-b idi|] /B`Xպ. r^^oxKvcbOb&}`Ty?/ϣI1@v%}%汋]x1E0y!t;)Z2[~ȡLzRx6/xtҺ5Rtxh#AoyV^ Do [{BI6-my^];e y;mK}}v׆ J=W{r[ft-u #G!p&S '`_o®V7D/y!~Cl;%gJ#ASe=*Jakgh1F!ƳeӞ%Kf,7V}6ѭBA= H ,"̟U]?1xANL̊*G^?NSTosNO%^̒;,b0|觌bFl:h cԴ1Z5Z!CZe⯜a|SZ#AcEb ,iļ<d+ՆhcPgr*w^.坢)KdϏF: Fzp0!(-1?ndd*B;XQ]re7D~#=o3GAYXoF Uڕa ڨ1Sз7KD0G>ȡ-^'R6]YC6v);me̦8^:hGY.Z9.#'YqM,R|K[y?O "C{gc}<58cF}*z]q_b=o ow;_ ܌L_f_N2y]Gx,` kS],F2|޿Wb~o@\I/y 'a2e,cpdhmcШcV&3N!azuͻ T@q%:DȉۆvRǫW}G4fΗ軼䟖0弄ykh,ZƣŞ|W:%O' sqxN]*Ҧ->$ӎ0K91:?Kt$CחkBtL\! 896xiK2_|BaKlKoOǮoz}:ɯ/{r `T'X-#^;xJP{ mސχֳyqQ>mdIxx7 dڞU`5S7,~ۧy`ԕV#qzGu=Kt+|)1,q8?K/81I0){bI2hW(qSuc14a͌v-y˰MQ^b}޿rri,@vͧP2(8ySVYj^/{O4m]=LNZ Gϒ}|hRvrODc~1`F;VX3hloE-śc,wuwNΟ fΥ/@M =4:CAxHɂO|rVub_q]u]Z`0a_x49:2=R2€!"eDv{ w=֝ޓdx/LA9;H_^v.t'Zv& .D;*g> B_HFS 0?O9qz<*4t^<<dgw}vw[[21굟Nk'q=\zxeH7I;GN>7[v9R'[~)~xmYՠ!&fu7KtvYaNl>+)j&CtKW_7LJvL}ڭ {@zs }xepp{I؊gdSY pKqOWGAIeIG<㞈Gb!0/x;AL;sO?{w>~#qc?C"2> 6H < ȨzC]G6P3Pݖ?P3nh]:!xW |:K?CȌ-d7P?Q4rd*(9rʴyemN菵t^:oxJTL |c!}#z} tikG<a'&81ǹQF߮CR599{}_^)FKX8vY`7^h*uMLӮcu/Sl%FQ|H[o@w5>9Neu?jaw)3DӶl$E\yP6މ;9jV Ŏl[W_}[EW]RaH/)EC` ~3ChsQ8}<ҏ~16*#P qh6J1:¨m۫{ˌ}9m\b105r@]fc2!Xffd3@tf`/z ߦ78xW>w8tN+֒>oaE T,9 r >Y;I</vޓ&X8^Ń^GXL-_NYE bɖsB=@{k+8*sG_[UU9>Oƭ:bt?> .|AqT5>\0ГnҾ4࡟ 2 熎%CRpչ2A=xWk <-~f+A磌G 9t'6xwr*7_|gW+.L OT]Іt 1iF`A y~f8l&+ǽ7b < g\81<ۀ0k cŠ3F0Ӫ]O'1bLgl=Z#Ά@F}drA\PmPr匘i;+].m]Lɣ.:vppPN/rɹ9xBm\LKŋ'eZ:.Tq~):Y%uǻ;wF?sө<C׎n_4GbЂ^}ֳp5qɈtN[_@1Y02V Z_z JjZ}sT1߇(|A]׮^+~r ċx}>wpތ n P ŖxE\dUL]J/n?$y?F0+R",@Ym~&?+u/T~+qs |.tw~jӏc(ψ.ݝzyIxTq$dXp C`J!SÃlHvD//]FS}i+xO$G)6RUjp1÷drԟRܥď~P΍-M c Kp#m:iT$ѯ|NƤS5;RD#vf0-Y{Ϳe2 &ǔHT98#^9ѕWjg07v-g ?wxwݗ2dk-W%#&/ pUY킯AZ;.tShϢ /}Gf8uo^iNWqW!#&=9CzG7 :X%Gh/\ȽN _Aw Zӌ߾Z2Q:םk9qW92^ ܻF9G428/ïVBoGap96`Swg%Ws*JWj\3qa ,.J֖`_X 6xMٮ>>c[>11"f?oo tZQ4# hɃVOv$2.5vUGgper34K| EO?DoWsr_ۊ(d?:Q1|a{';]TЏ.< Q8smdrUnmt;9rkK:uH N4bq~#6J/d,K? Jv]gԟnM'n5ge!~br` TpƇU^]OEw fg~E+?-Xq3ck[/_át: \ruTo*&,xb p88LwG4);(e;¡& ~41Pvt`wᄅſOHw)Z48`2C7xt h S7wxfa {CZ95p城}6ܧǓzA^{* R|׏k4o>Q??}pN@PЀ.ypƶ)q=nͼBl!链 +Uf#{suUV&Y鯛W/m,d\ldN|IE k梍Cn=\$\%>s0?!}<:3d? ?+8,j=c1N c7lNc2 |RF#= hlNaڿկpRB1/|ɇr`,Z63.sT^é'B]-̢pW<ow  ˢ)4ѭFmH90ySQ77emozv}8kLmÇW|9g+xi,/Qソ} MۧO}t {ڦO Y*Dn[,"L N]m-(p`DKi@ הwZh)gOlbqGrm[^3xp2kCOTV4/{[^rbG1d!`T^n;{ʥ;OBk zq,yye0x򐱺\^Ǐ]La`у8 >T |[V_ \*¯_g_?j 7|fKq꿓(}>vQrC OAky]_F/r쭛|^W8_w &Ԝ8{9 8:$Nfqu xҦ|z?_y=pZp+}8 X89M}65mW_#vVT8ṚOW|䘫,*…Gl,=uxwgbF[ w|>_u[Phtݺ!ED}K:'@׹0Lho6n*3}WSmNq|%×LWBYi=z޶I70{⚼1ކwN7#ɃC<2?Y鍞9 )y˟:z235 M0i[k@'}1|~ۅ۵</y&WTD\7dBӽx:4pk4_|ś1׳8%kYoݼqFlc71D_+{si3!~7/޽{/_=G)ZL8:]NA8"'k)NNE?|G^PpW</ dȀ/>"aea}lGxOKGw}gvwdN+wVƫ2CtR8 K_=om'l+?|D.u}WnӷcYr? ztM?h~*^G,?JwEn_6`8blo>Df@? \HoN x&z2V ݌ M)L n%F~D6!OֳSSSQ'xAz&$ߺ}94@٩wxN~.mbq1r/Y {& z\?xp(m->:fu:~bW=U4f1 K""G mwʹ`[]Suv9-<=ux=}6Wߟ'ǜ q G6T`YWNtNjnQn7S-+z{zN&~5w:p12 T^YnN 'թ'Ǥf1ʂ<1cStN3zx0VūN 64mƭ kolP;q-}aqSGl%`C(y cṀ[q'y ;,ѿ$N;~Sr2gׯ _( Zw>u/Ņ'EkW-C#H2|vcΓ8. =WuE^qT8}th8&;x縻 O:?BfWMp_,-t':/м6yr~ZPzɉŷ(wmD0?״K tYdy־_aMKt| ڌkP><<\]X>dY O ^\x־3=8s1'3uζmzr`NWOqyC!?wyE> 1H^lYlmWh7}Q}KNuBEmקDw y; 09Uz=/+L!~A>vN,%MI~cz˧x~8:|BDoTL|X8>c bT/9_z>'WH7 f:#i 7;T8f_m +.W`u0~|;D@guvN_ MsZCӨSûջ<{oWV./0!W"+H?xS咮uGVGO]G:lt F}\aӆK!82EWWxpx1,͉nt!6/mՅzrbn<⵼x;=0~|!z n:NK`ϧ<ʋ` J0C9q3[3GK~XWS'#\pbpg2wḴ+;?t{~UЭo 8@"a*PT_6fa{zk['{w]oogBy-Z_T 9C:9t}cO3ȁU^1W^9-8YW~bVC8%W1"P]|x.}ׅqqt'z6 &`6@w6u=xwl¸VWf܍s;<]Zs%j CҎΏSn|x[#|bCr]D{JG y`ʫh«]0Nxi(_Mvf>d+m RD#}:}uX޻Ilx pnCxT=X|v;h>C[fOŒa@g՝$G@IDATtZw@x,@9$ܞ[ _+!'WH[7߼+_z{oqW }[ de+u67vT ^ENmc@8#E-{J:q!:Wk: >BS{hqw(V[և+c }%COEk< udh$fJ q*=K hd\l!jo^tۼ> Gqv_>ТFr 蔷ªe mlR[eJ۶U귋 g$YzmFcUz/lrays =P躲&><omF1x8Egsu>s?}/]tGi73&)FDBm$_6R;y% &:ݓb|/?BF ӯsbGwr&̆ZP--hsF,}W&ǀX`Vޕ x_gLӢ~h4:Bt!ZESg9W)cPaޯ 'YX#EiTO|sOs%NM;mC9m tE'9y2|>`<)R|[8vM츐oz;~mz-?3Z -A_~lT=SVWw*YXcaW)|Ui0anEF7~ge|4ȉwYS5|CȖT@ .s5y͘xS̅՟?Сڹpʓ~mKuwMxL݉Ǽeid84sග9 F[dڵܕWw#*8b=@ef~N_hWvfqmJxG< ah f M+|R?h*ryoyʰx&OCk#_xiϦr`d·fn:+wdN:>.\tIQQ;WC1FN8}N 8;S}>M m>Mm>:Ib,gBh܍nja9c Ճ8n8VfԢcfsCc1/6jЮYh+xRrtѺ: ԢOx.s5^Iq@OkTWh}iћ]Wh/nx,6ů^ԧcP~{5T{.H,[I8!U6E8WqUNfr_x:1ƫj]3ްUJݰ# d OduBPݫFlj[姌w ӆ/xVlfn9eKG9 i"ݡ[6V|ZgѠG7vocA^az&U@N? 'q}&`lOQgOQOAeUK8ޗb6~i|쇱 }O ϼ'j1Yx -o{E319X7Bw,΢pifw8"o1Sǟ.< 6) =- Q ;"8aN  ݭtJwK3m{bk#O:a= 9 0+C}syѣ Qt-nh+ʟ=b'L`'x~?ܧ./NKoq<\Iz +iǩia\=W{>PO@[hY k*`3A?y}&ux-t? Wk7uƼ2ҫ<8Ӟ} ^tG+o%W|)_Nekoh <홀cg\O`r׳/^!=p#ENN:q2y/ v9boQ=8ΒCr4u*[85' Oݨ1pQv#8exDi«gSfqw>v磭Jk*gd;+/^?,= @Kz| ` O|W芞byȿ߆IbQ߉v߷dyd0>*sgXm=4ۮYg&{yd@m%?8WR p,1 m>O¤l@%X?j{/dav8Hvpֈ9aGϼ{đt!Wh 6,0vGAA[Db.4Е kxʅ|[š]Y>Bĩ>f$3474oi/5ƶ'@E/t+_5.=S_}> |q(4~vStVFG-9{@(<1:Ȏ}M>Gx\ce ~SkF@ yn %ŒO?0//y5mdtNۂV9A]=raTb߼cɜ>ƃ}pgwXPuݸ⟫lbѣzq1_d<8_ ϒ[#IdOHRY5pU1'jB$螋 _~Em0ɉI}d'e蜓~^a*05X)|m3Ї3P9mʜ)q~ \97N=yMh+r.f>E=Bv^Bi#0ꄡ O âV_ӏ;ȅ7D{7 mD:k7ϓmt]ݢ!] 'ֲ|6WӿxOzq+~"2|u:ECfA~xO0gmΓI@*|T@r~`O>* U!G stSY/gϟ?s -/\Flr%VNqvGgDY4p3xu7j{կ~7 8osql_b~^| ZAg[lc,ٚg;-0\*b8*nOr +rphznNAPS8rԡ8Z>b#%tZmSFOouɃՆ!GW\3ϐpToCeT,<mСsم yl6%/x @Nws/ 'omr*Š2ThI_*β'8͙h&{*R+^|\ ,^peHP(?#ItgPT`E_ W@Ѩ_Ț`V'O^%s+(oC~t:4DW~ w:_\hIE8VNbnQ2+qHWiJǟ)@e..,@/=gM{x_ÅV /0n'1^̓i)m 3+73WȧJmՏ 4sI~#\TXئxm)|t( ^O()\ F:xH?FOOt&I7Q@p/C[ tScu>lR: x !`u9Ib7ɞ;gm)6՜[gO\'^' xoo۾;r7<0uv{4uuWf a'WUS \ ZVÁQ >.ur8EW6b7)! .<t2/~|N}Хc8|}9o߁׿1u+N /<ocDFCO \ ^a:V6e8)Girxwθ8|eES?>"|pՏ,Yԭr |ڔ©'7^V}JӱɎoŤ3ע>Q]ѷ+{7] 鋏G66#]tx)|0m녀 S% 9|M| 3NIt ??9qdl_Kn leOa Op6Vâ$މ9~o߉^dbџY/3Nq5(Xz![śa*3:JYk㐪asW_RbB#:`uR?'-Z导|."7}=,EF}lmn/NU~ Dzz-nK?Nq)'DB8/ˇj/(ORM&੼KW}wJWAj>Y~72wyOg#`g~ *HN':Ɨ0c6RcOa0< EkRNLlpSy/IKgaS8y¤rOmڷ2mmdahS聿,.SE 6H :ŋ^jںAGN&Ջ>zl31oA^?:z.ء*mW6#xēW?~Fc~2Lj}y_E8-B:G25[e9lYK) r㭼oY{#Ct=ߥȸ1WoPN!X|2z3:*۠ͅˇ)@ʎ6 p>g0'yF<|w]po-Itd$7G5l<=|:M>_D3+1DEt0*#'cl邜u >wqU;J1rm<|5:1y')gYۨ\=^=ٺiS=`ӎMΧ0mClչviU]iSޥ{CS8|(kKNn:.edvkN>i#0Nz_tc ݂< ІG2 _و / 뭑ey_[ ڎ7edOva~hȱl64+SʇT/ gF>: +ntd3׺^aյ){tgSQ^;}+smR8H裫lX=noc?21'Cl~/E#_6ʫ|λ~`rpY 08: o8ϗLߊt' EΖ0c ;g>uTπc1ELH^QBc?خ8o|;}}WP9|K:Wm.xM dVȨ-M|@+:4oM [>7';G3zY+B}Ճ# E)ڻܕJ|BK >ӯW̮~ͽ`uGS2@FwV|Ճ6 Bi:߈.V:%/a Ń^iT?|K?5GPބXS8VwkT~Ɍuƶm'j]|m˗=0sxsB7o^uGYLJiO`M_ ؙ6֗Eݿvڽ~ό'n&)ɿ 5܆ 7:gg˳f2[5Nva3dϷÊ{a;F++8i}9:A^P\| DAkȬy1OS1<9m6En88z4 xD.MHh}8dFH:u">o0"E4N]|GG.|P'*/8lcdB=8pLqx y?~G>pn~U5->:M<=ʂ9FŁ־(U6m |qN9] fľ{t~[q~?tMՉġzow6#G6oz8J(n)#\m"ݾpO\y`fɐKQpQp>//ˡ9_Ey{ݺ~&oh3(pɞ8_RYT>C///fB873ľCT'~Pjcl aKpo:Q0kpqCe Y٩gӡNP9`;UR02\ߺ']X},Vf8e.<>V'h~5}O,FE q`~@} NWWW*o6_Y/[_ȴk(lex*GૼN!|"ofTp\o.n_ʋ;:j;BVǫ[Dxmmkk]SQ,S\2xW@|n0I0=A~ӺO)<< ~)WLvuꤼKkXю8e :%8ʦN`ݹu8T|oo{&vs /jҳ m~iN<6LZֻ[qoV^+>;73/0q|Az/͕f!za:cL5*8:8r9^p0q\YdG}##\: <8Ҕ_ⅳK˅{?WGOkt~/zt>ρ ud#lF\큯|M]%=:]n*Se'^NiWn2!Ah#`/}9ljYTOuYՃ/13o6pس>tlА7"J-|f6z`Uʩ˭<|;D9??!L]f)kZ-6e#_ضhO~QZY^՟v|ڷб'ytg|[զ`w|?ϝahyy&^>~ C6}؍@f7NsПLDK/'~)[of9nuƕ1MQ(2Ocz Sc&F.RF({?O_c֟2C}a8aU#A\>ʭSW^xGSX5{ 2ωju::Íbbr#߾kB[>W 3f U+|ONg'9 RtGpws3-nϼ4T״cX=8GGyt5ɑ1YR*G]2f|'cT<УrhOFr*7x7YͶϿWG}'Yo{Jg_xPY Ӿ7|`*|qÁVul?se{WMM>aX|3CPE> N~] 3wn߹y[1/?uGW <9h u7|lZ^7{ыķ\u0Lv m LRx Ă(ku[p}KWxŊcPXeF1sfP>GQgP6>x_@_C i 28~ I^<\A!>k`ҋДn%=G۱0Wݸ!u'CP|Fu>O ~|fu#x ̏?8w~qKY|s"(DA]:`V_sUqpe .{+4FY2^o|O@[{ܼ68Ut}\ =qi-$Fu]w}GOMH0 +NՇyȏHA+Qx};:bl`|Oz08.ܽ{-/{|^~/>$tJ) >̝ M7w5V|&|,u_rʛW\R H@vsuCG1#3xWZx SWCa5"u5Z91q=QTkw0 Ő[MҩS'9[/#^/Wiho*#i([д[x}|A`8$muNhU{s7o<m?t\>8[ݥ 'e?̥O@ \=\ʳx&`s/}Bm嵮 :K-Běٜd>CՇqK^DܢC5O+Cy߱I{1Fstuqnso2ֆ:6 OȤ=KȬ>)Lej3 k ˟_4ha ڇMxܔ/UtBCģohcW7rb eGWVO!2&ƻ$='}s{80Y9W}8n*/hGS /^Dt6Z€;QI7hHu)yb?qtӱNOymNϱ{LM^ǃ1FqCM@ݚE}X EnMlrnWث :odEI`։KW_vK׮_{!9EUL9$, a4u;سp/0|R8t ѾvTGPccCe}9WW^@5z1lKd}i,ҫi/L~1u~>t.O|lpA_c[{1r;<񽡍50K&sH^lF—WlRS)=?ERa^u1(>ǂl#z?7H~hX |nx= Wxsnn-NB95#e4x.5vKt=0|OC_^յ,mY>rV8@˟Q8o7-߅S_ZtuaX\\~io@9iϳN!SCuTzp|ƀy'I6}<8M@R UW~Wn\-fN-.b ʈ|S)߭:Up|mD":0wUbm?NVZ'&}|Oc3ugc/a^]~lpm†ظ1*d˷\_ڀ'#U'o+0hqKw[6)W/ v ?G6 ; y(X<8fE +|>~_qƽ}k/Lan t`Rsb3¦߽lG51iOjb!cV*I1&澬8[0^GXQP'ŏU' #mڷ8 iœWk<o}ly\+#=w-|s\J_`WZ:ѡ آhƩp{IS_z)V?ߧnߍGk|\7 PgnW>sChd~lbvn{>\b͹]asz֩楋 ~_AvN _4}3|h/|amDE:SWx<0g,ct%?82G$Q4>Eͣ߀wm%~t}h6t: ,~n y ' S6 N6<TݹL@^Qd`*lO]jRA28h4 PnTǠ⯎n05(m舥Xe[׾oMO> ڧ}΍`*kucs=a%cÁRG? :`Fs(q<e܍/D¦By]A.XHWCy_?_[yŸh~u6 t\% '6u~hl& RC>5zs=pjܒ/iۦ<^{ŞL+-/dXխ46uq൭Ks E<,ͪBo 8=/קGǵi?u0<3^JZ&12I%Yվ4+Zze񷐨curu&p MuO_1P\W7 p[tHCQCq vcK2ֈ `KW]*}MҠkX°Fiyxw> h:jcR^],ByV5z$4fF+4W&mn> 㦷6GsOal7\eQ`ps}˳rȻ6c+|86{B\ѯQt_h^XjSh5,DoÇҕ >nUko"\~OK+OS0I~+ EdMs:b^85q˒營@IDATϰ7y4R Lь\έ˙wׂ~G{ `-86ͷ|1DPۼ ȕ\|.;◲IlvW3+di$9#X#g_ݛ')m?\fQZOgÓt5b'~Gi/>rq凃4*'W.[L{,x'ޔ] u%x^}''ʥT7mP#Ìat /e _x;n YCN+ (4]4_/֩+.ci(O]3ޡ'XS_71{E_@z5 xeE%hcT:4ӑ[cplD3Us y+G6kl ^7um__'$Iv5fx>y:z0bU&i||giw[cKW<&7L~ƀ 5j;gIc[蔋5bh v;sE'9XCx #ʫo4Oi+EyuV =W{Nu{5kgOw{/+W|ȴLg6-xzn LL̓-ݻȼ-sm7L(jOΜ>gâ! N'ν䜰[YЛ`a:-Ϧ䱴)w2i*2 ;#zc~暷:S%e;O>+0 `|:Nmק|˅}Z/,\9= O)[m"N 9L; % OƳ }m?|akQxeţ~ a>䳐k7A1M<ܳ> of{R~>JEzPqЁ>=][vɠ:濕|' q>Flyϙ} 6e§H0xA%h .c-ŒD^(Ed_p+ߠmg8h?&rS`S~plu _U]T ߓ+,Fނ\ l~V<(/F<~*4<3nS"r:-NiI_qBQ~^ i+ܠGiLi<;.N`a4F>{Q?d \{gx6-_6tnH9^c;%㞷k)W'Wha>`N!V[/@ʩX xz~ڪ lDm.顱|E8sySy0? Q5g=P qov_Tizyoo>?W˿tKa??qFDYnpnyn&NL;Ϭ3y?V;nsaT /2c6yMxʃ1[W€:jyW >iTɢ}9&˫|Q:Ys_W/Շr X= VڀhkbD}j)7ё~Ԍ~uE4s\]/^\= zeo?0Ս|iFeڿ`OpgukN:Kf=|sz@v~[P'/5LeVGOB.{OmZzr Y~ayouZYko&LM*=c[:rmM7\.6m~zU/_^4OIBq;Uyto9Ut\~̇ұ9a1."Go{ut<&R7A_xwB߯щ8O> 2OdA'x/L<̤L`FW |"$T )AYp2q4:&?`˛vah򍎮Jy3,eQPͶ}KA]ofH1̾ U*+Kʃ~dm嵿|:'7pQa2Rg _~k᥏oЈ)CoGS7g / F[_2*W}Н62?NF[[@4#a ` Ret?ce2*Xu.RJ:iO.mephd&OG%),j3kgy_4k+ce4SϮ}*x~~/Ek|> p ϥ;}/zW/hiBnoKOg+|7Gs&T* *^${)n&ߕLw Iy%,ڳ=ebU'm)ͤfL5N0klq3: ?tF>hh,]2u` X,NFxC"@ц>2fџ2 E૬x/W,|W':*CG1 = 媐›E7cN:Vgp]xmkrNyz=x,TrWgs.WGO޹o:xՕ؁h٠5'Ӯ <+pa/~m)>iW.i? *ʍתU?mM6L欹f|~Â_WoqU~A-XB' cQ@_V/s qC̹ 2Q4*մj OF2?u-?ݏm8xyOrە5[< _A2w2۰pWAliT;<<ӑ ѵCS|Mjd z6`y*K).Gޝ,[v]uBYWJI-tm=^</ !Z pږRy73s;es|Δg<Xkvm`wjwLDVq%!{wWӺJ:vl/KK߁s%_eSvL-1a }t N]R\)4OLسKl逧MD^k'B̉ ޲v#F6iw\).5??t _)y;{ %@;C_ og71 Dov ܙHhwiB}PڒdrX)eg!H&Է@{?c m _]NwoKFkvA]T2 .!NpYpqG$믮~&A%/㇔W*3k;WDc>j)$DRS =f'l/G$>`:]mf pܙ19Y6WmX[-mv}ƪw9߸Z>sN`ߎ[?IH,1|Ny1c5p8cL^ڇnRxo B& s|$L' Akb]0M2ĐָS&hDx')ilTY0lVsKvз36r\ܝ8=l͂tlIƽQNTVukٱoUp&qlٝ6Y~w@o "泯_綿dR`59<rulqA/u"f5W܂nb|%}GmhJ:D<N6\}X;hg> JgW_x7-2v](Єgc|g[XldjڼpGށ:d+Md>@JSh+6޲&qy6]{?&[7yS,:O25Vs+U>0͵Γ'#⩍VYY=nRelWyђ 3pmw(}W[-c:9z:sHe]1X9ۏΕy3/%2_>;| C KmmL3 k^4o^~ȺQx|'O3߃I%j%G }.Gy҈ G ?LpL04-iBliѦl/L7~b9wS#UK]2a; ` FerkYtMP0t784$}2|/YLNx,?6\eo*ʡkbхBxtK-=k?6>-VIff2]q\+Xc&ѡ}J=<)Gةo#@SK}i}syy^!.>YBC1+sU髐Ihd@{xSߡ-&І<"_?FϸGV'4WC-pad > naj7x;zw:8SSۧ9ss)+vlmM0b/ڏqp$wepКS/3-jwm d~uyS d.? Fp|L,-kNO :eG6L/4''W&,6GH!'3 .\EݿwW7]FI&&6N[HY `@&)Z4AـĶ}ԻHY" .Oku46LS/U0xI~PxޕCgi|a9dXn|g3Ǔ_)&p-h٦ fd\:Wim!y,vG!?RG QtR`,6`~O>ߜp t$.٫w&/![N __ q=~oq tcI%8f/u~mw9d!eޣ'Y邉UL'^߇ES[ Ӎ9Bzh%覆[t&J2IKMLcG0Tl_,R7gБJ4G'U?AX/^_ml.|sU nox3gWY)G诎/:+]أ'^д˵>plF w y.w/w6WXdNN69$Mfq+]~%?wi_#KJk{:}ƿ) eJ~ 0r&; Il¦2;Xy$6 $c܋C9YI3?؟ǟsH uNvt~9*M#3NT6sU݇w?HIOKI{>):?] Xu4jlvYvBO8~yPJLyZ\8uqi;u-^4g6E~u~0]מ&_ ^Cp<0z''N_[FC?Z˹>Ckʆ0C6y8/AOO|.?:s>g+Meq˯4}/kK ;n^d׾o\FВw:iOv,{Nu*RHd2*Æ:<+qN*O.]d \ %yVn땣 mɆ?mnna{_i*ksTm0zqy6c<29Tg~iF.d7=w7|̃ľu5x󅋭yQUua}n>Nl~~U| uޱ׾c;pb3g!o[{'Gw*'M&hH^&{ `d >czJtdl&lAqK$2YMtp }M*1+~e3) _obxW΋TʍʡF`#DyU>pQKdV\k NY>G_ົ3](m",/jii|^QՎgAwƖhU s[ hko3SN^&_~vP1#׌k}=bTVGWi~_e_.,/T\ޞӷ+>>1G렃+ Щ 7 bw[ڬ<h `$upr킎|H"#6Ӗ" 'ާYC? _<0aģY6Ν{Ƙ(Pr S;ҽ&?)]?Ɇ9>]m<6t]{ЭF  .S'݉Qx wBPp?$Yl>2 S΢hV87'lWSV^>g eajR?lacߌo؜YxF[fՖW_ݖ.p,vU%./ўm妝ڬu!Wʆ:hG=o.X?7C7}D3$Sp+Glܿ5<;b`JyV_^.pk2WtwÔR N5> Li[el8r>Oer鬃֖_M;g~fwJu}$:ӏ M+7865n} qw鬃 ݹ+ȗÀ>~GYwIV F|y_q_x}H{Hx?xsXo |ʽOy/vabK7&~rZEY[Rv$m,Jt p:2޿~{Dք3dfmcK)37kxcO9צ F6ym.0hGwxSr}Г_%J &%8tJ I V@€+ldyapKΙTuhBF'ѫ6&u ޞKkµ_&/:h'mЬ\e(Y4bʋ+IS:Jmr!NzZ4[^t)d{.xxX;D^ &Z@dG%8hOFO%GiVf9FuS_ǷG>:8|^vE lOSҭ1CW8]h&үƗrМclm_uriӹî`C]ܥ]|19#~d~kX};hyWo'Bnd+BCMk0}}o`y0ݽ#"dݔџ߫." h9Kpz/Q͏DA"7 {@`r&-K{nPv"vDbRt"u)Ip.nm27g:neܕ0PbJ>: M8+oH6o3L/Qi !îGۥ'W?k7X~_Gةm273~<$ÞsZќ( wރo´ډP?}ʙO6n[>插[ݱ!GmSƛʈ7:9c訃i-esi7L,Vq|:,ҞA=_|- _k&+ӝ gy/<[3Ǔ 䞻StE/7<$oyId1zFpQ2ҕxҷP:%)śOrn> ^ w9n{4XL%(wOOϜ+uLhMy_ :P4l6*Ƶ1n31L Sq?6`͡WIh@돱”Lc+=:Oc{rׯ2lKh3ZfaJ Zrvu.yfe13n wʥwɏ)cc@ W g k >>+(/ě2al@J'JONF}ڧf 5J+w#EGstx_a^zJ nK}xQx.]mmywʝFy.tԶ1[94mW:'Q[[T)[]M%BoP3ݤʬl,]G'2Qwpw_\,'e:͂WD'!|Ll?jц_vb_?ۺysxj_l{tW`FhғlN*%J>l6.{>7|h:.|ӱ^VpFԄ|]WyW8=@ڀlTցZFļ;EV+p.lx@,Y;wtL?ņ`[oa-9LGccWYA-@(Nvky$%;k j+֎l` r?GmའCE'/qa#dk^?xճus_h/ ,x5Wқuljg1;߼1 2_?4/ G's׿Cp|fJ5PIm>'GٟO~?H0f+y \{$ft06.KnE yL OѷnV d1ydvRv"xU}~Sʩ,Ne"s'i` SjoNFnsWxxbիr GT=|~NFG!])@ΧtqNK4TlF*:[ŭv8fw㜭%`Е(t_їʏhhWٔ105-: ?J\ͅZږ9&&̀|ه~xӟ4I/LcYNO`zIxϽW0+Ӧ/КY@CD+,LNA~`+uE W`w ><49LW6ڥkݳm$5/2y zHEkK`CUӽ|,O02<8[h5iY/9Ap. ?Ix*<:IdWG gr1^9g;6dK4ʬo6Iެ7UZm섳pcwc.*;|xH;}0=jUx`x|VX9젙x;vB+;7)Z[t8"my0XWѐksj[t ukz9L kvi&_qЮ<1Ӄu#Sօ&{ٻEd޻vYfšV}`P_? :xw޹Ay{PWFs=d/տ=#KGNdYƧ{FOTWͼUJǻ9dyWxK ~)\foE\8KqHGJ+Ki8%‘:, $K7"w[⩣%莆10]>4dß[~Ęo\j˻5f/+vSVv83r̉]\e>m 0,ȿӹ:SO[ۓ~7 2䫍mh0#68Ɇvmӻx]P.:+H-ysfP_ '<ql^d Oߨ__sQ,baA t_]~Y Lmebj|.>Q;yF \>`@]m׬ՉrG^M:+l _g.mߤwcRa\I͋?tG՝LD_֖tY?XIB8q;=k(]wIM0)=[!tY, 3*2JwX^v2TkVca6yˉ]~/+WZ|n-ʚ)ݺ6&|P= 'ѯQ.V>4ڙ-:IZyy[`Nygn~gw_H9㭧˜՘CjF~P@zqO}3*ڥ,?I<0N^2I%Hpe:@@@g&Բ/>+'#Lf勞TM|e> (;@_Yg LWtE ah?c_?<]^;ŝ.,0lǦ=!HxHpJ߸1=xѧYv:{}rN|ۼa Ӽw"<3g?+mTLi69՝c O*#p{ 郜h4޲yc4LZ']W v@IDATJ0ʿsQ=^S/ OsF-_ᯍV)柸feK = X= u%?~c||NBkzbN]e4//<{>ҋ~lr+JR6E ^jy% J:w~Po'gd6|u&1.=%z]-Ȝ4 pA cBi ~f2 vԫUANT: o^ . =2@Ahv st Ƞއf![xO—r,JNh3V oyW矹b8~*L, i7~*.k?/},AMl[`L;{|2!+Mteo2dsgS <bĢ+7>J&y|nԕ6~xxqrW{[:E6ܣY`OOl[ ;SE&<˗-Г%8s.6d7rCmr)7zᓙtS98h߃&u|jH/6 >KJ7edwY>?덡XoeO;p JW\^>pKkl8i.ԯI4'3LL]K+gB lA<}3:l yqɼU] > L&m}ܶv_RJ5qvuR臎N?8Ȗvۛ~;tz{zd/qгIЛ+8]|١gCRdy+>h ݦϪ}|:w*O~A[2|6ޛ[_Mzn]Ά憘n[YCVlSEGs%#Kڕs|RǮ6>\s%/R+.?qAgc >=,Y\Nd1NYz+Ƌ }/[ÊgN+#d26Zb0*ou!]Q: RfRöWc@u݅ c$nx|WBA{B\,GpC5JEw_NN8Ruw{,+`lNinD) >sȮ0,:&0s%ł GOE&5U&z蒕1\8#FrDXzNwedsbY9|q-aujwPGL-2MVcc2~?z/7N{h]=L?C16Zxe=_iol8K|sXyi]IcogCjʭdڲ2gHcv&3MAss`!:ƀy&=/y2_6s_EiUf.>sl^>tKËC~g/iӥm}S0< mOt-N GxWJXs]Ax2+˗Q呂u V2 -cKcoͼ6g8ʰe~/Y{pxೋg>]1~G?OQ*:ix`yoK|7W% 3~EP Z3k$k`вb2xicM¯='c'[gk.RgʓOAM=cѝndVG2IJtȴ?Ol-=rظsu³~~6 o *=}x -~dhY;pK>}m֞ݒCy@+ePx kwS㓗RGmHވ~ѧS;,Pf& ,''ICP`(7>z8Osu}R`Dmԓ"ut~W MoS`ʓn6 L rwX8{c{j8haG8y8tGl8ld!mم|>Xv=ӿ M_2_2MC7p@Ck~)f<7rLrQR],>z.L77_YՋ#㊅o恬>6sWhooj&hF0GFn SߒA9فu03^m™6xSGʯ.lJi/KՇ =z.xEzG@ï/:]rhdܽ!4G/}+!?¡.ZpM:S4&O)DdEK{?dkzBۑY^ Yh2κ~l )BNդ>O7/W^Ck f6ko( G [K}JH3m/- 5u%`mns@[Pۀg1q ^I,@s#tQ2:rzYtd|襾6kCReXii2OLF4Ygg҇ޒ\6<#:6.[p"`ي}I 4v}E/Óit]AC]"ԱG;ذ<=^-p~vuhr[ѵea+W˓| < |U'bޢ\K9t%ؖaOgie]&̎?2?+9w*&W9s<-Nr;pLXGߚxFSJ$u*}2{󉃷n ZC,dZotx֚#>pEÁ7r:\7kUӱ'5֔El9c/#+K? f V^k^4yH9 Τ4N/^ڀh-hBnm[mv|p^'Mu0ּx1e&L #!U3бpzfk̤&+*6oE³ƒm~74_„J kq0+*)FȌ.xH{7A ;1|Y-Gc䳩=v,d[Z>pxwӕ|$`qc<:晇7XV3t?m6ДF{Ͷr''NkBݺ[]NmV]* ޶/E:Z*cn|47g|.6U=Ay+s]/|ןgAΫ\׃S4|++7jQF.^qT` |4]1үP@G;32~rɥ-|ۉn7]84]7ҁO+o.+[ҫ|޽wŏp')}́s >0^O9\8s֝_wL]C7l |T p%{]]-<zy&ƅ!(w+c2uIEqȂnpW<]Łmpw<͝P3g&a@2&!o>4!|DAaۇ} V6ۋ\]]IuhI`k!o\σx^Goѿ~ `+ՙK#ܣJ}-q8ܐ/~]˦qOO >ǙO護ߺwͼy_gό39 /.&]_\f3#(0_ ΤԶ2d˝kSpDֵס—hՅmyW>{]J'ei\~%tYLM7F߼!)jFٝUkQ&ɧܦc\Oǂ^Yᗷ>&;>_y,(ثQ'Gzi]Y:J =fᳵp gIVemEߑ+tb|*+:n֟3"6;{vi[6L~teyf+vXI< hMg}X[ڥ 9FApZ/0X5ӡK$`~hzO暸mFVxr7yV颇婼nWg2y6]䙇9+hR-|\z~Jp,yz BK^}_ :zF&[pF緒^ 7z0s9Vd:+؍uf1? mƮA9|N&ғs yG*Hsu|ί IY; n6id{FEhY:wl=lѕL*0ҩ}"ޝG-6_ɍ{x٬k^614ᱹqûzp5{:;ks'k{~j>z袯<1`KyXhc|H l: ]'^yLu+]9~ rA印}{(w~ӗP&@jzp! #R2 \S};|7N&_H,b,@e ,fY:AOJ&EL r^#OAL~x;-cPJ lqu%`Kxӹw,w9=wx>z3cg[$/fV.նd|(8AL89KM0|$;E/Kxavx0tͫƦpvyʭk'ӓg^9GTy6`Ӫ_݅/̭]5|vm8 yw\ |(:X_{*qγq84; bHLQt5꠮oi+C]#ǎmp9 dDnx7^v}#._!B}hCN.?a>9s? :\: ~7*>y^^EwLcWW|/7Nx}䗟 ӭL>8{p6 &Ca|Ra;L@P"69:L ʴ`z/[f=- n,di&OIhYH}8cC)A.4`717u6{Bl&dM=RѓXu,TY$~2?㤃>#`cٻ,2gə1<346GG=laIgl ^,˻rV94蟗kiX'NDmj ~My2mk3:Kz({8D8-`o|؁32-=wtҖmTS  )1߾@>LX*~mVYx8wKY. cxbR}>AO_䘯H~Z鸛7~!+nAQ+lUye/ov恿˿Eqw$Łq`j&A,<'yYX/ϋ}CZDBCONd^WK 'b|QH#).szm*66NݜԞdQN8I `HoCǹܶrY$ *btH5h,)KS+\hGـLJR)Mn 0;aw9.»G6}. gldY#y8ʜۘ9+ JkY38',Ix*r,LM#hGv~^rUՍUۯ+)e}xO6} ?klh̦ ŢOľ1U`5WN|Owz4Y4\q߫nKW94f]io2Wl$C|;;K}{@ǿb͓lF>}±͸8}ye|bL6jY}ry%M`cste ϗN+O$ϦTͯpheԫkԛ#~%Y')\ d OrV6}i0t,cMikx8! WCx|?׽CoaɬT_7<8E ']Wfyx? 5EiLgD^7CVp߉eɿ)^f|n;ZبT?1 $;}Ivfys5zM,P|( )X,qŵ7_<6HC&Gq94aw| _WXD;Dcx&glTmGG1 說X+gLp~I.l3;| > >AC٠\WU<m\ÉV-viAZW‡Q>GHMT\hSl[>X&Ћ}e )S="SLW An낌^nyLCGyqLW4#/@LŃu望8Fw"oa@oʌi:7̂}7Zf҇C6bIa[~lven)ɥ u=kA.{Q‡lWE]=g,:~}G3=[sA~|&6ukQ } /8FOEM_ ^ -=1%lk^ԩwUS_vbf2RW6??s9DV^XW;rhy\];*N‚Cei<8'7 og)<&>;':hd`pq@V`@49g򞚿ۿ¤Z0_?`7Ʈ7'lcu`XN8Xa K|  <`H $n72֕{ gp57\>o_<4G-'|;՚>лlsq`SLn,ٛW2w{UNpΣvVOe58yI<~U #~tZxa?~vo׏C3:rKRX}[Y/>ˆcc$uqVcNr˫6oWFtwS)ʓ,~{ǯroldט;Ew2~͵uc-:vǟ|S^^SpJOO>3)9x7m͡fКy(#;9~|.^4)2G7~̫G$9>/q?N@zK 79#QgnZn=_gh6(-iJ=7=ME>8-KG\MppEf=S9sl]0(Φ-}39o>fWG4N]:|~.npgV[eee6NE_ÎGjU[5ɊzմMe#3V_%xx|{³H~{|4WM,ZÅ;/'>M^W;۹/OtK߸Z|k>Jór-I{xtW.wV4wqPYM֬.\~S§:*7ed֠ʫ WyW_Q/>Nu/r|~2~//Pyk᫠-|^'n5 8q{s+-[Nhyh&`捀P <@|0Ƶ3=`IЉ`xPJbMTi?;ëiSë]ζi3KsNa[^_ll#2m]yu j|=F..ngCQhW:' ^M}VyjɾduJ{d\L:nI6mwӷUeeCl&=9d}~x~u`Jcdy2pק'eB% su>TG$Q9cSA4jl JƴON֍z M}/VcG^h4z8<ش{y]uvY7W7Cľ^JG[*^ŸxZ6NFvVG|k'>9bf7r ǟd<~q.a?3sɷ|490˥ ~nE[gy'xփ)P;Fx0< كO8OjފSi=: W,`@ڲܱKcP`J\igK򙀮TM|Ξل,K)1JW+ 1IZ"!Ϸ2k6)1ɕ$>4F7 =~`aC.wkS ?7:D=ޱR,Wt #6w[S{MS'}Vl@o:K}<蠔K67=|#CObF?R|CoduIdg[%MS[o/ʿt+}u^á{m^;M̿fi+іɯb}<;l3&O(V΍=w{7Ɇ(K$zkW奬VF.URȻ왘N 6bH6/yO~2~/s18|.=u<0«g[|ϛ~;N_u$oA?Aͩr$^7uBvݾ@K^58$}J:xN3c /tGlY~C/WlsG)|KײA'+>[ }?)m0]^^yEjm9ʛLih>dvu!X|eWRq?p'ڹ꯬dTFm݀=IeV;/{ ćCjY}I;&C7ptT'/[̎QJ`ƿ7T7쎷Ӂd3aXi/Eu'GԘP6VWwo@aRCK]4uCW3vΫyw/ݽ9_zf BIƭ!pQY+o3~/rCKyC,oNPn_߾(#R6Tw*0:ьq_7ox1Ó?#oq"w:ീ &4fL0זZNc¶I[n 24_&dWY.ENz? ɢv} We3ODf>Sy,>rl_M~ux\?#+ϥNeDϰ';gi|%Y߅-wKr3~=ݢx%VgGTl ǎٌ9#Rq#|`$pѲtgcv%K\W5&! yI^GTSCeUb=v6Cvw%p<ӷO6XEp~6p/S\*Œ^t+#y/3gN NشvI\>t38Kh/%kn-n@O:X24躭><){s5meK0}H.Տ>bO*xEݳNW.j/?\^1_ܓmҠx~b}N2Zf8%x.|.|N^!Hu`[¿_|Mz^rI2ftN0*4@ gv 9rlo㛌`+RֽUV>0]9[\Z/p~eMƴe7v#'yCwo/E-Ɇ|mu86igS%W|b8L `Jm.ą:zۻ-᝭Eq'Ks֦ԯLp.Q }Vy3_&5{6pr>6MSMWrm9rXϋƒLᑻqiI}+XuGf(ieQ$~V/{T>/6Ƶה{Pb.츴ז1$˛[nM_W9?+wqVB_"<>䗍5-%X|m1uQ_9x{xzI[η>tU3W/{ }ݟ}}'nMJύi+?uzNtmq#oQI~}BY6~ޱ/yА^6a`F﵍mϑ&w4K|[8ngK䒒 1ptN IK}tI]d];(a/|/ގC~ Iǒߘ~9U/Yv3>2`Kϸٜ٠7t ߙВ3{-:Ob-~J8+N'9^J}vΎo6nupM0g=['<ٔ@{-S୧)}訫h꿯Bu5ȼqjv0<Toc'w 6H =\8؞AG`IwH\e[d,+ >s2O%S, 0=/#kr$S=˰%G~rҋm_ܡ.upM{!۝&;mY3#^;os[)nϬkh9l+e}Ɵ2+C]]C:ܿ$.>ԃ{G+?46vcıGXf4`_Mpr3_N~=y_\`7q7w!``ȥɸ,P2jS)"/ Z-}\dJ)^#o/ #\̙o! &&>c t\WxBM8\ݗvaNW0/|K7DXOY獯o1\B^ǝ~h6)3`"xmp"E"jCɎ@.qWsPZ-m> VF?{TfneYk=sċ4Л$3M=3RVЋ:{zX ) /5^|1tƽ$ b;kN~N_%/(]FOɴ|./>e3W;c?YE LP/y_~;NuqiN/&t霪$?Pl^yOGqb@IDAT.lA 8khH>:r-ɥJ?0%8ˮ__>sz wi+!F o>ۯKxgW[Yi[ԤL/_vK6 Jmp,zJ髝ȯ䕒RƓ.g>Hlmp(>l=tUʮqK^Ͼ~h'3~|";|DֻG?zDnLEL]E+ vcn5NVog|\x 6\3Bs=&g";Mh&3t_ׁ<|`lQiaWS"|LF}Go ^Y_&3 zJh$9_O~zͫݷ]wum^ Ve;%ͦ&`WFw>D kE?W4Nv8D_Ύ`EFyd69 dž`x[|4wqK曝{M_˨ _ҮSir'.1hrtYt3-oL LЯfr|q)hZ ݽŋyջ )X{{zf3^_]_(@e~>xۂ-h-BMx{ʤ^v}erC>p&pv-}bM9$lbj^v/[pvȆ5dWfs d_DdY1ꯏپ.p>G^ 0]%i=⃓2I.)=ƿ//Gc,)w_sr1xɒqBIݒ>,n~!Y_^H`]![C@&,pLXtK=3@m8&}ɍVvO0M. %}EIYV֣^.:ݫE{~7q(W7^INBʃ-m,;zeG|Ğ6!2g|!MIJ?T“յ᠇יn2)L#{U=4|Nn,:/k]لMfwah÷t7'01 }t[1s0x{weqqfQF)v{qqʝ+}È^v?&8tuDnZ?'W;ٌ?;cdKV1a.i&9>%YҎStw/>?vz4'ݘ҈d/=_G6GXKDϙ~TchgS?82O~r GL\;i3Ms9vI^Vw远S 6.hW{L6:@juE(u__#3ɣ_Ϣ7y+ nwl2:utT6I[_٢z,K|A&0Ÿ6~N`xJ.WglD#^hJ ?]z*<'66+p2}iV&1JX8G &smxYSQ7}; 7DזDҽ-Ğwxm#t{MJ}ѭIk+`bٝy=֐Tt>ϾxbFl"U~8}}x#ꋯyvꋎ˻t]?{}ԥ_0y1~?'\0o 5˥m{wȭ$WK>ƣ৯K;dv|~7MqDn)/+οѱSܿG~4^Y7^{bg\S6.`ts2}7)XƇn0,( J *4vBl&eK$hz<{w񜫓^>Nt-%<9=-^tBq% 2H/ 8|MHJki-h#ɬ+~lp>=Hd-:/7=uJ`e&xXлka-}[FGaxmp,w րO>GƦm*W[ݸ_QdD Qg1<}Vݮl.,C ;b*z쌮D/ӯam:;{Ҡ:{d36|/%WZ[Ncf8WLƣY[3[#lY0tX"=Zmݯbn'中3yѸ2O2MC8Gsڣx7^#?3+?0򳗿_;?חB6˩{}:wf+xߏ 娟$~wpLȵ<_2' FBNjHrhRxD2Kgxh+]2dS lLOv5!GY fW<|:C٬ ?؜%rVWv%;^-Lq6[ dW2+/'%KJ`޽_>pó{𳹹R7f[\uK']ugbc|d\&? }҇ qֺ `yҩ|̟:F|TAs.i pve+G;ctKvLvcW4S<]6$[QP2;29'd9gȮp⫣S#9}<`쭾px&Y15"Yًy7o}Ye9쵥d4γL}|qL -,Ywgnx.R2`2J"xAv^eڴ// XO]k1$7u `4VnL)-N2f=tv// /|ޢ}sC>o-~Z+`h%'=O] 7m981u96ȍ釟}*?K\kWg2[#g_}+;(ҝ ?>*֘`FGRkJQ((fI x $>J8[ KySjnq QO(xԧLn:Ѐ/,S"ӓWy)l^qwgCvzq{LNvX`f`O'K`{9mO_X`c+\ow#zv.HԸ __.]aF+$ >ulp%kc|n@YFGVgfkTwa\(;J#c_}}^J~d$1z4gĎ~03JuznWMk]);%}9*֚/YȆ?IZG:骤+u^ /)+dKxdEGQOszɞpЊ~k[24Yz:!m<~zmcdŇS8ܢcz'Hy_O+'1XyY@pJi`pt6EJڙgVa/ R UG[H6`\=xED~f}^4 w I<ػnSƠ>-铢/Lp}$2}6[p|Bj܂jسoqW{iiaQ2+Y, PB2q5jn17N:gl|}ڏ~ W_N7r=eG=d28 8_؊ݲ񯾥=r9O>>'d7k-?~9lgL62zo`sR"}49q8kKӦ ?rŧrl+M%e8,9r蠇6y[.z/7sט|:w ɀg:'6o 9ׇt5Gn6G(?c_E8͸ )v~n5 pҀK3!Q 6и ^6&`dIXn .֗EM"ɈQ]͋ۏv W+L;f+e ai"[Kt"S6Zƃ|>K`7tO~?pDkҮqc>}pdDӸ\ҏ1MT?>"ď;HxW o&u 0]&2qԕxm Hן4̩L 0:WMk߈-g٩V 2xC[gA/^N1pn\1ps,4=,ϡ8`^ƞK.Wu4K|wR_fsɮ%`-&>`œO%#?ƕCaOzW)a|OƳc9IS>J6G1|&?b'6n>coQh<0l.3_o]]%WZ?,w.Y#K/f(X1s\Iv9nɇN98ɀ>ze\)Z^'?hd{ӜQt;mV\%cq'ګ !7>3cؼ?F{/&iPb>4gKcW3/Gl0M3\@wRTF\[zo\J-WLݞCG09%$g mtK`dJ({3:$\FIF-:^a_]{_qgNoned;=<03=*scJd¡4V3l,)odgLBx٢G |ia_{UlG-y֋1t8W5h5f~:Kw8GW[oĜǩ3$N6&n{_"s+Y/kSt+0O\ӳy>bMc͝8/>r5}q 89^A]pl^xh@NFi$Xݪ|6 &\O.}Z?eVZ$x19 vrtK?^[yOxJkGcy_U!E'[Ƴqm (y೹1 Mn`d{Ƌ>9/Op,\Rϖ/[3.Stȕ ƪ?W/eg W<}v~OLShu0섎yxkW ^Zyޜ[^Íg//1[/;oίNC7^V,s&C"7~XzkNA>3Q\><'ya􄫝Ɍ6ɸ^" 7]Oh|F'w5%9@n:^^LKw.:@>xA:$@=24ޏ?Dmy]9NxA;0_c`2~AsfphLdPoYږ@$ EH' dNk'3<᠋g v7y{-` ^+k? _?p*í4xEcCfq }h'8!O#.wm-7ņR/#9_<8m_K=+ų'Gzǟ͜j?~d?0Rd8b/2'?7>&"D>+a#s=ً%`ѐߜ)[v|F=k T~)_?q79s7 }mN6ce^u)W3?Y[6SƷNҁaqF_c'W%N*߮_{͚_7)Cof-^_#_^??_{_k;IۄTLJrAc,JBX=<{ OAn4dxN^Wn < r0N>kuL6dϕ [͘x~<]N[&a8c]E\2'~6L&=G*>oah򤉞~]łɧ>0OnQlVjIg<ꋮvO;\anc) etϱ餿2 Ǹl9RHLRw;yW}cgW<~l`%ragO6pmnL _wuel]Ʒ6x Џ/ F#0R<-08Kl8I ]ԅ,Ʌn8хyn6Xeu$̟S_gFg\&3kоp$J?cI^ɂJ}3w}3JRz Qpk$<6/՗0-H$pِwx& pϿ.酪Ol94i尵6^eCvS;6 [‰&)Y0>2V2~.pm6-'^SFKFƦ3xgFs|,YCGW{]c% W^|ks)h~alam\6+^nqxbļG |8 kbsFU8r/5pV+}ߣSNbds/͠Or!Ժ<.}7%؁Ś6Oli ~pp%l%oWk2ċx([[ ֆ~[Y>`Ó)O GG;uu3qp uI&Z+Щo3KYp PY6V"(GrgQLl N/3NtQCE]mem~w}=J2IykW±`/C^K1dx' O[`ϕAne{K64֜;m_ۇ@pdclh@o}c 9RbSx9>˼fC -ק|\^XN鋦>4"9%2 E8>N>@\I2%q\-xDga>G+a{e'.91Yz~{E~s{󟌷-v#};(=ϔD~o!`ϼƮ+qndxl{b# yzg37;ۯe_ O }6ZI}$J?쫯o>:px:7v ׄ04ڴČX4J_L&+t*/OphQf*3>z٧`̷#`.-Cx{֐;l|;/MޙCe 8؏ O}%*Csc]O0N0qP9N2?.&=%e`α?C5`<4Z /Jb~絩d'Yg??\Cy5(bǬE^7]3V)z_yͦo& ?2;S6`'YX'g''=-:~3'Z##83? 6}wXfo^Yseu O@G"{v`r)9Atos ʑ)τxK=3_ؼjR.hv͏K;Ѧg"Nm~Aӣ$'/z m4 2/=8Wpc߂~NƤ9L2 $gNDKf"EvLR&rǙ2[]8h{2c N_%9[GS?If̸,=sK ^[Ѫǧ>S=XW_?C!~ x+(6Y8gf=B,b60GT;3 .pt&>pJOWj=im%r-߾}t~6޽+\' 9ߢ"$eѠ>67?]{6|Ћ6My;(pVY`4IoPOOd4Ž>՗)h~$7:JIN;l ]vOŢd1ތǧ !@7d/o߬Cc$+RHɉ6L3rEIJقƨ6D0b|o`n}&c}9Y[M o{&2lE_'L-+/ЍSd۝CD+؛,D 9R}ɐK&;Azʎ`/%Ke 2?{u唁,&M|ȟ~NO"bzm-~ʅ~ELd#\o'`oۿ,dYT(Vwgpɓ|d~me8 9#6NgKvlPƔȥ}w.xk[Xqus9[0xƣЙ J[fu0ĔoܲeF^p[Ϧ#fh&K:S6o2}}`W ^_@C۸he9KbMV"1Sʆg';s9516k\vz̿oܱ;Μ3ia_9[+Yi`$}CcOYF?>Y?H/~_s/'1}8m\p:'oR]'nL>6&O^&\)VrÍfY#RRNll&\}=N^h$<Y|vD9{E\D-Zyil7307YWF4-rbnrg;v%O~m ΄iWӋ|:97z2զ;mOo` l~x"|*1+\ȖU̒a9^#_IgS}*?|ၟqYK pݍ`o~\9Бo٭p:t0O؏(}JWWq֛qƛ)_M0#qY0MFq;q׷a.HqƑ#`|Edma,ƃqm҂[C|w'gY&EK6 |jI.xy?;B}!&-zo> ]m`-ف,ɓgwanz'VV'񃲶 |qğLЖM|xÃml(6;-GSY}?'$mO_I;>q%Ә]~ep{+f{1Z|h5f#sEOl/=؋[,|z8d0爵F Ot޼QwepK-V?ٯXYR_bgHgC)G}cӖ~F-\8 DW~w:kICjmNӎƏT;uƸ)4Aūqq388`ڜ1I_@VJnT` Fxc_Zٕ-&'È,C_rMЂerwr:`yG)d[.Z찓"8xW?bM˧,r-jp,Yg_֟g<=/M:ܗn#[X6iwPC+9؇x>cLwǖCf#MRȞ쪭g#[ƯMj@eXg?g{ןt[:;;u bWͣ)hI Ƴo%{EF}`ЀBgR: 18ƔbS)C)wַXj//]w Vɗ|Sx=rtW?W9\}m+Q?&Psׯ޼wq|빅?mAW`4hXp \xe}dl{x[19 ;oS3&@M_r}+R}1 ze0&DBxo냇Ot}.@IDATQ>zgF^g'&W>цZZ-Sl3#1SG)_| //F/"D'ʡѱw~?0l 13c]_! ߾~7߽`?ׁ^FPguޖYC+a.t~oEŸ@ESJ&e>3'r~bC?&Kw9ql<k"S63;U&8x6Af]IKOCTnA?{&-#ݷld-;Qk:]d|S2dU]0,w"NRB6X&_ҵsgF}6?r+7^`ҋEݟ|~S<n\aOR| _ܒ?.+;#u7+Ϋv]mhH^Ռ~9>ni7ܿqP7?O7sKo_f9N\| 9WJe4xy̵㶪i[IW0m&im%hKɛNɥȀ| '}ƾS|E.ec0Mwn=]?xetH`p!n{џ=2~_\y s`(eiO/b~{f+Ƅ2+mOғp':(>ɰX wSw+'8x2|eVCa$c|6UG}҆~E?}N_VG[^Z/ׇƳ2Wt[;*೓zP>sm;.Xj>&V6?91 vRJMƥ;|̡a"]^..S~o&3@??`H}`0/1U6az5?70 K)S98_m@ϩbW^>y|`Hھ< h6)q06{~VvϰJGlJ"'_Rc:\9-Hݨ^LBAǹ'i;dn._LS#*KT斲q-dV‹V|2/Ny껗HCH>vIleM#]K}}1P$/KTC[LdH'g][޼T_:tk/.]bpd!'X;>fq†$-㫼ÙL v]'O[694~hD <~[m dA BS`̋עߕ}|w\v7w#wӜqr\mVm$n?\2|YJl̉g/!Kk鐽bL;d/kPwS<yK;<ݢkMW}4!Ң/!_oȜ-ټz6:/'R'X| d.dG2d4N&)_mcRJN;05 7RֽƆ7 lW=؆]ٍm C>(=l02f?!a6vWlk}u2+I69J7+r6>|=66&i;->W~n=\F9EIes,;zP@Y.I']uJ+>Rnӟoo6+$qoËז択O\~5tՃ3K,h1٢kL@/-ld(6v6dI:&!m#%]QMɘLcdk~e%:ltiޗ &7|ѧ]; &:Z͘Gy7k>R}JYlL~ze6aqel[d&"w%3;UF?GWT,'wp$m,[ G=ѭ~]Y̐]Ch _e `d;pZh>fcɨLN'vi~u8!9  sA> \hlZ.6T/{k[o%KlʶxJIJrhG~s0.v:Ll Щw)QgQ~wCҒ9J&RS,,^+Fes L "?eAtߎA<anL_&(=6O@/ %YϬ/yQ;y&?6%3woow/Z[eJ0Mk~reӖ.頄MSziz__d*ݺ HLxG%%x`|&v@l>|vژC)U/(!iyݚ3̍wC'ח'} _p3Ә6_w^qqy弤&0NQE~ "Ɣpd0ĦQظldA Wr]sfe7G2I %^Aout >%|7?W6)U66Wf`B ]ʖ ^c g{: i 2[v&?[k1Yel㳴^|?4FH`̏7~?L=J3_}`'}`uwOg2. qxm?|3dPkD9^:ӏΜo8j ߅ML0:jo,~o=~:Xωf2GDhi,#OɫW%Њvv6W}F{{dšqWA;<|l\Ru&I}k+WԮ\ 2 dHl[`.[\ u`gŏh)W<>S?9;uV.Ͻ vd>m.^/K6`$)Z-9u8<RDT&_7)Q ysv5mC6o4 ;$YW6c3wS]ņϣ>5KN9={upͫ|>ÌR9twwCw35?O]X呂?q3Dd2޳Mzj_lA]E 6CkstM}U%Ad!,xI]9'JhHƥ1x?ã>rtV؀ks1rӦnWl6/C t맛03y=/xI_٘z9MXyx=rxhbl 4__퓏:>| \cm2ڿ|n\֦KOw.^AEWcX 7_v^P^2NRm0x38.l͉߾+$:CC!z7woT?M?OO@qnS}ycnWr 8fu՟D7ɇ~A& =, lIv2X4?O\W${GbINgަ=soGs'ln ?ꏞ. ~/%M*uթɆ%kjxC_>u` ;(Z`#YQG]\pljz?WNw?ȇl/߽`\4e+I֧\{<<#oʘ.e2g|;ŝ?$񅋟33ؓ}=ZlgH@X KN|ɀl< lQ+/w ( ?N+ &{5).o,̉Jd̲7OprƦNvyackષK\տ }9rD7 #y.xwcZ/oÀ[[q(’=382~ P`t~&K Ab䎹 X}MB#tҷ[~^ɗEàxYE=ӡ^NO:M`]آ8%ig|'xRFɈ 2zְ<:)<2Uo8h Q_s?~m"Bq2<{4Ϝ]uaQi[/1_dy=џ䡥YN9t5oxuLPbV:.XѹUS~uDaDmݴ ', G_įuN n|90ڕLcdtV =]>|xw&` BfƣG FTBeG7mgYYj`]<fy{)W |WC;_6,T=e~4շp~6I}@/6p^uﶙf {eو`ٱzT x|p6Yhy)m ҳ(ۄyxs&e4\ɇhNcmX }&wLCq:{u!'M׸&%P^+Nv//>+ ]U'N]5Z`dR}1*Y$0"I& DM/Xq9rR2gY) ʯ3^P s}hw8] ~Si#FJZ*Fh e7I!cKg0.dž&nllLtU8'GS vU' „a5P k 2ɫ7or@ x |y'@f<{6 Zil^[aršӡ+u&8 '-_SᤅkAWse?UH?Wm~H׆UoU_-ǣ:TҔjk|M>9Uy9V>E/%_~k]Ҷ+↽aSlOZjKkQ߯2WYxhkHW&Ń]/)m[YZ R\y_6 ld^Ж { r̟ ʹ~B+lS+FB,ka>$8#Wכt39t2>64XtVԷ/+|9#~Mu+Th}S=d=,0@ʗA 60 +NkQ @4lD  6:he58a,+ y;^;Dn&E|jt*8nW2^T] ۺ֣E}ȳ&^5+}~g7O`an7!Vu@xthvg_+OUi|_+lXcuoyvd)z)N\q܈\aEN8ի8֦l,w]~7n*O娼-7纸^}Η}ʟQAtG7F*uJgs-#'n+pB"Si˅x'~Iap)}ϥt^|Ey':Rp:sup:Ο\%OلOJhvgW>`ʯW֑dkSVvcye4[~7|++X#:91D=:-ZAȏx"mKM.I=:腷: ų[& ,~V.ֆ҆TY[Bu+٥}6BntP'_~׾cyߢ>W9pK۸V]7IsyѠt|W;[67Xx`l畵G=Cf̓Ym+4V0ԋXPK^Kc.KU&t/Jq/|]5}GO^ye>SloGC+ ᥝW8/ l i(E]4 1^۸7/ U_);?m5_8u̓k}yim_a+ᱟv#?q׳rO[*cn/ ].'oO5Ǐ}W|r/z e'C[RdN+=etأӃA:q,ҙ#9!uY|u ᚖNhc&/ <ڕi8#Q{߅I9>Gz ZPn(m2'Ke\6@<~+M407}9~@CSlKKjgf32CG@@sm?x 偞j:Wjkl}ᚖ>8/y kz+9v\_ K:io,)?OƳM;ZYm-?iy>NXq#~ 6&V|vJ:a2} ߯qrev9=u(W3fGv:L}~avoBL򇘲vt֖I(R' g'ۄ.?p20^:4FmCv?:D}CtG]N -LSKW{WFB`6G."e9WqGAo;T^R n k!?GRm Mm9r2-WkAnodrߋxm e' ez&ԧ_0ƪ@}ҝ2: Z6tUzRt`Q: gR{{aZ?tVzCh,By⨓/Lտ)+p+1]V¶̭;:)Z]:gJ/Y߰>4uO _?nx p>_;|7Sy=||y[h;pYW9ú)yyv-ʯj1FvWQ ~~:ӳ9MGf~I9FJQ@'8pp}p=:T8N?KpK戥KX헃^+U>֚2;ʗ4IE`-Q6A~>U&J ^ELh6MX;o΍lo]S,bv?Դx&g dZm3Sk5mT>OiKu/lxТ7<6_!ݝN NHl&}=ݍzx MzPWL0?nL邠.ExEykyUj3$sn_Xao}6m[SA7M⸍BeZIBU ʫoXнE=rf!,#lG@W:iuvVOrp6>=پ?zpಽ<* V8 xct@UNO)ҒA\],Le]Sm|H_:j?SRepGů6a}\͚|y`Λ ].$O8yN|^$z@Uޜe/E/_[+qn"05=_gx>@3d1eP3ZCwe'fS0Ҽq2v1 3zW%hq :|V^,|6FeS0ɭEKOZ+-4/.=!VʥC6:yYR7ooH_YvQٛjnU%BӶ +"Ǝd"ga2X # Zmht5Y&XQ0m\M 62<O?_0rWNiݦ[|mxE,z" >]=é+4XˢNE8YixMFuG6anڧ Ԝ2ZYYoq^ZLJ|UnisįFS~=rVw᫋nYNMSܢ8K>.|nϢǽJ_Bm!˵X8.i:,657{)XX>Lh>߮d8GM~-/J_ddÒe7htpIW5iw`Th ep^ n`S DvWyۆ| WmSrgQtR=ѤeHu al(*mM[_-ko:^fI?`V[$?'[Y'?o61/Z,heh/^z>)j{W;t 6J—zn=^诲/jN*{LVʛY`Pk4<6jo7=7{\EW6f:bYVN[\k O,Usś=xYߜ#}u{nl~0t-N7ar"\zNŏ~gty 3ݍ&}e"W^ .^zũ1OE?;:gȠ[q/gpu>g}d)yeAycDZ8YuXJS=vy8BFЃ~\V30hT6YmSXy.ʁ1ـu:VnW4;AG;vGWJ^ŧrm{iCqVmS'^xmlD6vi[>4 d&3l-JKtՒE_۷O8Jo'&.OplV_iB3ƘI}:vV'y/M˃kTP'|`]ZH˫[66iִ4ִW[whQu_m|}6}NFRݥ>?6ǖ nշ4?HFrˣ!T>>!I߉oJ(Ǖiԅ^\yi4q|mi 2y睛oۿn˟2סK|65o,wg#A&`:^vΗtn>s&qMM@̄{i{ۍenxO_$<hfDƐr7/5{o~ynx#q  ,:Xut8T#w =:tuZz5ZGëدGbw]sV[*kyW_AꀆWJoM|钉>՗F/tlo~|VjsydQk.yXݵɰKmӺ"qrhUǕnWZL/^'+}RڷvB_諯`(?6Tg/HzVW|L-ߛ]]}a-?E nħ'zuMk['k8]Zݠ,)T+ ſ4v'--4++6Iux;[Ȯ6l-g\zG^ģ|7T/oT(⢏^®4*SBh3,WuK8"_i% xGGy R&o:U*7Ɲ7]Agoy> 8G^ 1q꽳:?11W5[Ÿ׷.K 'mlM9B/mYT.bRoԗv<~mM`J-h嫬^2Wy$*dͷsh%華]>_'t/l嗘~|ŧN;s?8tl˜0_Oө-wfaK_p}Br:vqkx Jt'u "R[Ydʓo@xGcFff! :틗.mGVWRul|jd rI"q$ouW/ܱ.iqxE2=(O.rrl~bmª_ջǣXXmd*plFn`mE@IDATՍ pOY~yE[o57^ے<{W~^~|㳻yZ?>PYC' ,1Aڠ~O_.gԲڶu_ih%oeԞG幦)~iHE|XsG}%%3R86E?Xg`ΪO]LJ>W6i8Y\#6V? ,:kzx?,0|_e Wl lCв[G/'9GGo&`}E^ r$=ٟt#^M@:qt*gҡ"GqT;iꄻ#fAvetqxNd 4-{9+I# ]J&o^]gD2)Gg9+;z>٢Y =]0;DNmYaxt@l(-0v::)Ekw{Ȳ?(\>&.](J˄fa1]yk4#GS87<0ՇNk?#7=~3MS=kgUG)`.+o}ϖ'.8;6sNs<|\m>\e:IV[q'oaZH~6xBg|2 O̓UhϏD'!:'`uä@NG;x78u t8Ǹ5O L<:y\qơ;rNl0)s"yf܏ 96$!&WT'ty !J{h7⥭Aَ]yLy{Yy:մ͝Ϫ{}P? [=Yq˯.-z6Y]MnMVi E>U9+KA曂Փԑ:C|M{1C? O}sQ$ 320P:r\,gHe[:,y[?u?qW7Ӂ7MPKu>g9К Bdh>S?mũ:.}xlu0g,=,6sB >=g.ꔷM6xwEpJ uM+_nafX2ErW)r)D`ќ{~U.]݉:m:hZ 蕦MџEro\GhS N,;IZ,E[$m6wLʷK#ͪEdGHZ]>6 |8=0ɺJ]Cg 4lL؂\ƜXe~w>C[zӾDvnJW~[X]`_[^iy+LK W;CnIҷw~p~`3cB\7hw T5ײY -_8=O_v_j𡏍p0~&7^"m'jpdn$f mNײ7_\x7m-NC IvOaOґԷ?HU֩um8y @#|B s8$-3: j1g@xx*Geh`O[=nv_C\Ţ} E~tOfvmWw]u+YI?m ^c_eXۘuO_lc`;δ+=I)Ao&L*T&G[*K:N ˓}YiMՉd+hcLjW/?1.7ຸ:goo?|P/ʅȘM+.&l|RxFhK;[_u^?W_L#䞿hӤ N7􍋼~#^X1fc;pЍ?lbj?b+P.-0x4{+Oj3v~3i\_ xq8!1Iv1>Wvy2,9Cm-6ڜkUC&f+^vr dpJ*[m(oǽ{mM ReL6*OsT6'_Ջ].S.],l}6 ~l >_}+ T~+_qSXb ."]<>=;G<&yYt,8߫P.Zbn]hg*㠌o闙&ٛI~u:6y1?̉Kf7nIt\5KH9@`⪟>?˫7;*-͓I-.M=ŕD=m+G=96&fà^ }g8…+vW~|P5?|ce|}tL)P;4͆5V78yKmD\7cxc9*U՞䫿ˣ yWvCO/lTױ[6[O^nN b֘3>0a29E':mFm:`n ^^]쾎Iƛ:W0$N9r[G_ɯ]8I&GƯ liN0[77'և⽿io]8_` ]:B|6b:mp;O㜛O?9ϓ^u4 qlNB7l.xuRAGD ^Ʃٴ:vށgptp|Ve't0Aw.{ ~W :`+}]񩟔1]!|<¯^hpL`,$f5 x&cNOA^H($Դ顎- Hʸ ,JmuR#_ee;zt =[ Av 󂅮:<ʁ<tlSf-"9V}.([B(nt,ƩoƹpBSuʷ0iA:r6V^QZ_`=21"@n.f_J ^|y䷱gpyt}xٲB3"^^.M_Z5a<٤O2~+[otLL'^pp8L`yYC>rr5BCk 0 px'Z88uV@#Lt=78xl|wH`ώ_@cR{6`l +=votyRjp\OoF} y_pzGm.l!ʫ u( ?W27_ڳ( ێ >P9vևsWv ֤8P'z&^2 K.xuC#ܫFVN`gdE|{KCOd'ڬ{c,S٤hgw}u3?H^\gB5%(m"Ǯ=V9>"_V|zcy[v, ~YW9ʻzM Ypr0hL' >kW ޕ|Fsiԡ13'IKFu@*[ \Q.oOge]' Oiufa%rF@C,S?dwI'.bSVuފO?_]h*?fV{(O^Y&s75 Khg7r2'@}Lc}Ѯ..YRxgn5v<&]zK FK=Ջx7?G^M0fG&7UWi,/Š[k:+ʟ◧tԭ0|_{;}9I6sJd1_>I=s9%|oy\6D!YQ]ї_iI_gt0jl#b8ȷ,4:I5܃iN,42dT'g`h/͵yBDI O~$70l֕# ~%:37rUP1Ƣx/pWhz2 RQ~6峳Ї-]ߑ+:7o̤F-h#9? ^eܞivR,6 }A Fp\Dt7;ˁDgZFD>LO 芫/"y}&TBLw 2_'_:`Lyg ʫ](uD8uYOQ{y/]W\6ѽ<̙} cA__yWIˣu)z+K?o\Uk.ӟ/Ky{?΀q_BgO}gx}硶f(W~m6qnZxS?NK=Iyױ:\LxOv~A~»Iwt'>v Ѩ&~0d>?Y؁m_=}D=.t3Yj^/ |] Y E⫟n?ScK)v<$;ern&&Se1QMEx=&ΛiHgS}aL J80^64vS}lEN\ Y&[~kZ| ۞_:i^3g#>(FuGOL:rKk+zpэmm@Ξl !&A_@~ Ly& n4 N x#}ѮSe.&Ƀ&2p3d!0&=J[:4w[bI~tta#VRtE\L۞Ng?lؔ,B`+Ȅ%a0ɣPٳVXA̟؈ڊF࣎`M?yC`1̀4B[5Pmk G;9Ы-.K8ut!/~WDNڦ6mVԹZNT>_jcbmZrqԣ=rZCb6's+8 (ٮ {uDqr3:S;~y6Wmkqbi:t⿦y?Nވÿ:Ouޏ#xϲ{ggyPN辜8YtSoPDq̴Ҁp6![`WJ9&'Nvڶyh+q/&ka&p/9"WD%M[PMḼwUr7>N'(/8I4| w_ Ϳ0mYN{)~& on&_'_>@-F޾[`/d6;Ƴ3#DV>M=çW8E%{&}ФySF@3g ˀ("z_qg#gn:5W/'"/oI>YM,N1 br("ī}0'N|#7zcGP'/ʋ8l"㭇/> ,Rݾ!-\S}h doy /ӏĴq胢oKt/~6dX Vd/ Cj۶p +6-%?Ћ>/_KS}jkOF6;ȳsRxkC1@6rym[*;c2ɭoq񥠏ៅ 8,@~~44վ G '$l*&݊WW ]<ҡ?NDn^AgE{98ʕ}R">Z;̖ݜkV0IpgpqzkuKȄjg9|o1 ;9qrnxY ]F'z9w~@x 8!8p'Ky2GШ.M.Ա3MH넘ÜوXC'|23 W"}kb;|Ϸlxߕ 7'

l.Vfm]ա=',4ǫ|e B rCut`O:Sl|w| *r]ΉЦ]Y&!X_#,?˓]/X|Zև(ANE? {Ì.$Ojvd_d]˽7#q'0t0 ę_:, ;}uV8;gNV&8Ee6dc=O_㠛m !G[g4 :p@A`vAi8K-"6qwH; nYlrUO\dT.GU0tD}[gTDFwBBx,_Gq0 ymH׷mdm{>WGbo79v4qMC{ mrQ߹ãWvך~tx:AM]jKiM6yqt>c&'NCcѫ z-Km/Ly6m=xrEE6uBP}Gխ-pৎ݄[U=v?g`;4smIk+]R~ֹA=T;}m6|v* cp[-l\dtimu`i_aj#XݤՍ̚]@)>ln"OL}dɂ3n"O/}`{Xȭyᯇ{!j/26\k_3N>ev;Kp{Ngq|*6BO8~&oe 'q?@K%i>q Df32D _  *ITk&ǀQ fP{;uIMr/UnDBvζ&&ocaQucˆs[.?rCND KLRz§5NW"hMsLQRc,#gŗ ô}H?)k=Sv/.ۄliEӯW_\j? O77Ȃd+[ L U'-.&Mnni4G&Q؎ :ѧ&ud)W>gBOG]!Gl!ZFd/LxM:}@5GMT%O2[F?ȃ[Cje)vmQB茚9"d_խA5M *o~؀r1LF&/}R=m mKL<+/<XP^_4O[8x2nlŸ];C*W󵧲x2<ؔ`l%V)|m69xMENB>U{v/:gpٻiX>я~t1 So:w6騟"Zg6ݞ>J1gD_%42^qMY㤳) l΀ߟhhsnmpVtC0}5X:yg׀w3045L0iz)D"g7.7.pzV5!2C#ڀ=6<o.1a.6GxDr Weo֜>xpШMՑ1[ 9j9U [=2:NxʍY"{kJ7qzm!pH}|]E[6npsc3^OA8ґ'u˿hX{_ug6cџLn _#;gLW~N\ZUɆ h,W76p~,mp01E_$a|*xbv⧷0פ<{o߇F$Iï3&=?{Ԯ#`a\~-NrldžWX2[{S,4q/9# %j&i`tpp:P8 к|kFZtAk"b0Kcg>a0KNfeWyйnj6,8g $nh'ַ M<=$\N`-z) LL&=&rH,HW6p7pڿhnώI&0h٤y`0 .n=0# VO!Щ<rlHɭa(7Ym:2 `5Tx ) fhXtx` 'e jpԟybC -}ö[6]4j<K#qkWtuƶ-j,[&^z#c kubѡ>͏S7tv]c?r;#[3g1|}\\{tNLCR?g/Mtxv,t$"r^>B-lʴt.yY"~7#tPp]]G*Z9N n~q&2O|#yMp' K't>)d2&8 \ok3/NMB`0& 9CCL#.vy`7XC ,:=*@)O@+)_ml*j{'ZHMx&lrYJ&߈ouXaɳ}vﰸ'LU~6膞ڤ~vZ ]dj~ZoRm3ˌGGоF:0+7IC7FZ G[-چ|A~>]z@z5r|QM[쑼>|i*h~@󹴟,Iq#is+߾(WwW 9yx["k^@ ]-B`D!wboЉR]1CޤNFe|: 5\,`2V_m=h۸; LE ]ܢjn6y6;$?zɆ@]y -ˣ 9ő ={PIA6 h򱽠\ S۴i_B^dʫ9"x)QFi֖@,\]0xvKyKHwZ+z |YMO37=I4GiJ1lA'OOl:RmC?< Ѧ{giC8>oy7o%#Py- rmN8 z'?Of`q% ^ͤ|𥔽jRonyoˉ/u2IzK^e@xL̇A ÄN : L.WてYĉq>S&a^- &nRC:l&U>b&5)k,SY(}Z6rty:G+|- &J}кbf` x x5X;Y8b?~dWO.xw_"Xv_7r2i+~iT5?=;gpE6+]c oe *) r!>6Nԡ| z+tsTy +ox_,ltLs6վg|"kbf3Af&.]}cC 3>K!zr}Q>D,⾈3_sTpHR:s tI.8nM:utEg?wzۅSἐm3 )Zs7m2-!_Nf3> E[q7%}=0o^ӽ&M>7此m MK@^`|k$0)fίf6+`CuMv<~k,߽ntˠf ܄PϠ4՛d֏`DX"Du娛.NB33PsUe2%a|.Eik2^.[&j @sȯSB"cpsc8qhv} P?9|Myv~'XmP. ҅CwNxqa;0:iWךּ;._Ai?t;x?@|0f==2g01<OqߝE:hoޕ9en+? :/A&xH{Bz0|M].alm>)߆O]A$>'&/w ~Y=~P֟X>¬L](Qf[f;yeS ɻB^Ksu/f]=A^r]p}%,у@3k&08˄`I n exӐ,_~ir].c3͊UD%{kuÑvTa h2mVF𩣜@FЗx+:)lNNo`8!>8jGʵ>G ExWn`Lczr[n <3 d[@IDATsՇl!^s~ m6!NuyQ\>\ `m%]۫#3.~a?#[cNu ( \ݷ`ן~Vz>tt>itj#:cٿgj:i׮4_<6t`?#J) .qɡ8 ^mA2{uSdRyK)!DHJ]ϟ%Q$uh!ӳhPv~Ӣ{֩DhMמjV"w5gjiClZԝ|g 2ƫa@)g\g"g98=cxoS~N[[//+g^tGa>g?KuK_~dG rg~zYl_zY槲~CT/|zg&^-Qy,O 4z)r7eA}0J.yZKVB"uiN02/Q"p|T~x<I0!%f B#\H%,#ަ : /B o~x t}G'Ol`jv pʃ-^;Չ$V%zf/tP;w2|hwQ?gY}NkF#o5wݭ`PVKU'a\եy7PXxgsqmYo.U w?Q (FF0g|v,vURGypm1G;0n@S}*lW;oãG/I4܌Ǹ=wW^I J4{?;4yy){?Ɵ0eҟ|C#Ohwa{NJv( &H =@uٺ_2ŏFD ';|%Vy~eY_v T?fdN7@a^v PdROq DHX17D) 2v[Vn\)n=jptr2 AUTaB8Ou( +PC[h-^ͧ|t-k{fM8˧ѹwﭛh:I~,HK`Zvv[u(S^fY1Cpw})ʺo鋏e=t7}^XqvJKxs|{F6O-On>'ӻ4~Ø$C=9wnS?Ki8җz~dёO-\p o=`[cy>|mh<]i4>qFAqf߂FR~VAHO?wh͏|Ni%Gf3+W |}~拤ж|a L/28e \IJ^kI;+p.0B|\.`_0'E'!=. [A<)T}B #XZ0Eo:-D|beʺ~#m^-t18] BNiOWŽSv 6s]# V\xV&>)uZ m2*|E >Nw^|+G+|é^(]47r/|BW@)u-x p_Y~F_E8e }Op,u_9]2m& Yo5wͰy݇FZ/ƾ  :?1ReŷrO34?k27=xe~N?I_|>wȏwf'ѩ;!}2H/EtYNov~FymK,.%C3kyv ]ɀrtEN f_k`=2 fr3ش0h3MW>j otx/= 1 gC'ݴ~AKc\pg|t3y-ډsVb/*|n(YKC~O z)oUy 'JxۊEj FzƗ}?OhoV]a}URq(oDp^?{~ 2J f: >bu`U~$EZˀ nºC~ l h^8Fa6WqAAxiГVfRPxh(4՗tK@:DCM[k4@גk]]x/t =Γ=_!g.e/`K@p҄`J&8tKPNηI9ycǗQ `(ćx)duF.~sfdBg c8^P'=>khuؼu:3]>[~Xx0_kw(g8/\s¦+mɋMF> NI=j A`3#/oہ%,uHH$qSUֳ~On8Ӌn*ea ?LA'ɻs9 2븖zF;QNofyBFKXYٷ->JfᩕЩt Щ% :aRgA@ԫx3ko)/g{V L5"P)V4#X ,/R.{|f2‰_+% 'ƫOVG=8[x PVÕ5mGc?oQpxj_yt nsGnM2g+o4\<:Lv[4 JpO͢ XiryZ'w)~]8zp'MxzE{s7[Kh!HuAW3~IoB,}yshțy4N}Xb{t |`\K._bm'-y^yvz +z[xN )eW\Lyǒ&ߏ钤lKq+py⪕+nݿ]~Ru5O'ԆVƙ>:|<~n髂ǰ 0w0GGvz׸IV~3wo,00. $7\2Ɉ|PafK7m 0(e~k7iN9\^)W|zס~i/(+l?xQܶXY-x/</F d|Z 8K'5_nɧxf,LMoY8,ȼdNIrb PA: t !»gvM:7RG (x)4g.&SJD) yߴ-@[!!eD@lޮz+X'a< )Y8` "m^)}8mVmiz8+^<qXBk;ƻDo[wۘ^9zwq 3ZY'Wvxw xNFms{ȩn.kzp`/Cu3>xGdȬKeWS^S?ŗXukE dڤgec!77^s~|dӻ8xRNJغ~OߊML7)2{~߷Q5M^ȫz/kzepc/-?/vy (o6j* Xm7[D=p!rN_@J^FxMp5Q sgxߝ>B4E(i@~p!Dp$X\xYLBjB?}ǭ6 {ʧfW#᥷Ho/M5Xy"kfW[3ߚQ:(, CG 7^i:1 nmi9 OVB^0+f:hXuxᄣw}ĕ{̄K ~5_ͣPj x{hk׺o\`t;y<]>#n+N=ԣ}}s3RRi5pgi[-iގj 'Bh{)t:ӻW+Xf n[L>ͳV۷no`#۹~Rap9d]"2bf3x3l4S7!BRӆQf0$+[h%$KE@Oxg*NsAs8x |ڭXP>fRJp3uv@xo,|+| xlOV2U-ڝxP?08B^ihۭ>Oa;a+xv{y/O]!P$0N+k|xv px@<}< HH<ΏWu6tQp?F~{QNN{?S~e{暈Rz*̃龐Ż_y_. ooq[2>K<2ڋվOO މg߈P!3/ٳ}p.rp!Wd0?`'{gRtۜ#P9L\{ww:KSz 8 Zؤp5S #aC9&w*W&o݃Q|wCdziӶ&T+8Ʋ[7ӯe'y7~зO8@S:}>`rq>zM~$?(6e5zs^hVDr(giz g ?y~/E3fky +\?;/y F `C8x;Qg#n.泸ssYb%p)ܥC#dG1rUݻpR9\}h Soh+E+ܔ 0%BpIQ #(k[Ċ2 NCo}%-$mrH| b y+} jlG|h_q_pm68n}_z!+!|X;MQ_Fղsm3j(Ex͓Kvf G'54/=z=*M߻8jk"1Djw;7\G]FSw7}q+MpHvnψo|+ۃ[g }Eq~ċ ̽s?8w#3oZ:䭶5V3uC\F( Q4ݢASH3BUCxY>Ok m;vQ{y')uUpI;ION^r1:;*oU|q!_}~0~W[VM= ~AoMP >ͤG(i3~hGX|U ?rNޘ1TWI`-*WxjyH_nc}ahB?sͼ_g ۗw?}?nLJ2*{dEhi߽U4w]yKnF dK_a~෿-^s\^ .U_T[끥s:䧖| ՃDև5|"ճpI8?S6ilM)xRc`\ʬ|{E_V+𶺇 (e='G*/ ]JYPQU)М]F0#`m y ~KFȺh6M\uY%m3]X~TT#}qYiSCJ p)?f%de]Bi~%©%\駟n|gRQg6pl;_è:5,<݆vuY17ߖg؇#}Ln4 ۩o``&_$o?+,DŽA@[^}Sc:c\x M޷SNs(0L֙!Yp~f}wzۻ2wep9/ElѬw `a C-%Ll?L9*JٯDhm /%Ҥ]ס%tmK0(u)(Cs2\:moRtK!3^JRW>KѢd/]Mċ֜v oeaou؆SO[Gx74pݳ GG gc_3m}{!({ߧ{1/xx .otTO31*+FA>< oKsiжv&Os$1r~$axy 8YxQw_(kw3yMtgxd)σ5ygxMI֑ MF| g ~Ҿ&W `1^:U a\ ! 끸}˃C4 Vf67xD3|;TSF>.'F]LT.yW"^Kx5w൰(0{ d8N L'T͂0RS O}>-VN2Ń0VR".c5E CQQȄ;x݅_~xhh^3P`hB q4 |p@8!Npq e|=0Rwz+xe8-[EW~P_<t~-_˔J̓08'8b}!,ߙKڗDWlZfaW.E^2kAX †Cgvf#kT2Nvodg .vMLmeSަLYimUe.oy\PkK\'NSD]Y0G iV eQ< :MO/xSozMqw[X0c8u'!'DoV57x| U1Ks`y8'v}<<| |11+݀/=&ٔA/b0~z_3vmy#g^ü l9Azn}wb?0zƞu't=j<ňH{qԴJ{9=/Ű,qG`d} EOd.X߇QO"e!AߋneF03|WaQP+I[a؉/"j>>k |+ gR1W"\;/> A~8(`=V*:}pY ᥔ_ep9j `O|;BCaf_M) KQ 'h'}SV┏( '9될|gfhH8's%euWgF)_pvs.BQfFJ hCy;ݾzÔ3\[[F H[wͬ}:d\am+pͦct^`?nsQGQZG2\`_0g;`3#LHW/Ji7WJDW EL3.J[fgB'({!FT8Wy¹\]FS-eW{ڌT[ф_Wn+~GXu^=]_zp{,rvuoBgR9X?Tnc0wN OwÿN1o31.KxIs 1⹣$M$9w —2'JL]LsgzQ~ Ԭvbpv."J{@dbT8ĭ৔*Ax Q_"H3 |2(#~QzfH~"W:Bw`|߫p(*X[ ]ʈRo:U|:O~F^{yx Nmlty+fJR'/nV8ŹcxxHO]zp%O_f~]HXe'gB'+Hcz`>?5bܼʿ醓eOx,ϺOoa5t4؏ h;a z"uN?@ "FA+xY ?!NQxCgp Il?RJ^I|B;Jb'<8mK piqkVt2I>fJPHgeWt?%T=<%#_!e&%UR\F%vJmN\]<'e*|AShZB]e=w_*Gm/+` `Pa<8>yWhk+\<}`s~t*/l8͊cW~holȪhlO ޯ@NKN:wBtO|}%GQtW\' VP>Ia=Aquhyxޯ6sff2f;ɻ/E>9IÃ2p+g>݉?uQ 71ʧn6vY95ݾ_L OKaN)Ju6 <%IjߴOKr |]jN)G Qdd,u,dL&B|* +6)b$PWCuRߘSP[6G(ryxjʻQmDsMhi c䷍xdKG{OW\G>e׊R}y V^>Nm<.vuۄ<<1F _J:0+ x|hr7pt=FS>} lŽo7m$ ͠9zRamx3IìGL43Ga]ݮ3IDAT`Ͼg_n OE# Q'Sy|J*{ \W[k !yt<Ѻ .̮b|WrHϏ!Y 6I~%m[3Y%-˪_ȵ~ 2v5Jj7ogfiBfQ|%Y08"KE@-FEeG צO}؇(5u(dx =Ց7ߊ YMV^Ό|ek@ +LVۚ&`;荼;ITOƖ+ Z꣫NCHB.gܔ|;&) Uf_ ì]:v(y,+2% ' 'M;|.eҭŻq [Aw4oMؾj[~ `3KN#%Qu9>+[ع(k.2p/;}|˽~mZAQFy%D@<72GsR߹x(73Y9(eXoJPVQjG^9ytw)G9pGZy$tÂxvS9E,Oo>4l5/hvmlt ozxO5p˥l3R|8A^V$lK!9Da>竭{ ?O)vwW~I4ʏ#uwԀZPu8TT~vYGڵKp?9hx-ފbyC`}s܊w6H!ۿD+*e$sh&uG䛩RT`98)7ʙRb\p)Pyy'>·Rn߰`Цl;q+^샀 𓒤GQ u߼_rw\}i0.HaIh J=RCW ,KS2=ä}Un^&Px 7a+n SH礴<ǓFS>tM`u^P~~*fVlˁS}Pg~ \_|7+^\Cr{`1~`e jO57Ʈ|Vz~CYdhM+QToĿ%bFZ(L̈́|_)ۢh(e G,_ֽǏ j}n[R2Q<) npڷxޒ7%u@}Xi$RK^q7 Mt[A 7癞vd>/W^m+O ꛨH~̿#47RuCBw9/?X {%_ uL'k“Xq#̓ˏ<"˟؉3߈U<@1$pT(V6O|p P@A.xNSjPxzhIѴ4qN Ro8F^;`:NհUmSBv9RWmZ/ۡ2i+xM2nkhZc,Qb@$Y_o3lw9 ੼?gFƲzC.K<_N;%Fa^i'!?6[֯u&y|sa;os/l))}!n5Lx:B+ʫ0+R?E ;4Ji'=:ԓ/M2ѧyՓ+Z֘UO#M]wY/VnG! װ$W1W|מei${'ȅl;:pfg xX 蟱V"]SHc1Wc9)=a=η:ApK^}x+ }F7^RU( Rv> lKYdն@)3 MJ?o Yr=ۭk [Z u~)YiIi2 R}`?O獡wӡ_[,xr7bK< VNTѪ@e_34fD=uL{톙mƳul ; se[:~w.=7yz`1^4Lgz yMo,?3'uݡ.֪]Ht0((SE)N[; s+LfgMPz5o?`7GRa@sn:@n,%;)xRt +9]ʖ.@:=x;MRK[(!XF:-nh14:Q2³65a+5q.ӷ;>[o%B\WF|puǏwTr%brp|B_>3{?!HL]z给߉oSN۹Bٿ+x=⿉\|:ie%V_"[Ig B*稔_[ a:VeXAnJ_Z|FXJ?z@蔫NjqVG^T6u~?æ xyi<¡<ӡHqy.}u>Ә0.J}0!qtPz]z`t釥,~ɝkQhynj}We{drws~ߏҿV)s+RMV)س;W`k`7QXu3୬͹J#s G*w`nP`^2^y`s5]!n,Γzp/ N_ѰAVfNd'}#~l?.Z sue;=I1Ǐ7?M[SQ?'V1|#7,eZWgB磜gwe@Y?d(sma){NB,ۅn)8ixx,<)e)@uqyiŌ^>hr{< ll|y +;n,k#s (t &fS^s\¥FsWYi^M{u|4,g!NVGߌr,񏲧Zހ~e^k{(' M7{vo޼Y?*DG@AM+c ]"Gɢ%sSfgUGZw 6:^Gea;6< .ƷP9LYbH U;j-9;j{e{`ce4>z#yya'zBK`{ [IU٨h MlV]'}Zey#ckئ%5N\xnʰג~Tm|`w"Q([?RV]SzNw탍>+'g0n[]z;l i=J]l87݇OAx:[9JVգG6,:-5<<{{8y#]GtfI7? װ/+KGl):F,~`,ϾNR/Q&y>l`y¬&뙮ة(|/ʇayfoD_Rz-JyQ.2?eMy}(.-ud[yj^09y,+#:-2uwO׽VV.8!xG6_'z;W>d$3we;/e3zݖn.=Cz`1~H-u_ d F~F@٤MրVnd&.&(r>ߊz7I^wc\) ,uU&8'˷ipol)*P/ +neoVh7f`OeŁo忻=ݷn4-܆|7lu(hP>iѫd$N4 +v:KKzxZ=p&T-;ӬW>rҏ[կ\(עάοLar smEa氙3A_Chi53 }v'q/1,m(LF. o(/8(85y¦'V>/u\w2wuXta'LVKuh~^}댉نZ¥g,츥?R#B~ٟ~5m8Ūt k? hPkUV@{$0(Ѡ8' [V & `%`FpLBZ Fӓϩ~ `Mg n^~ ԉgP3LU{?~?m>Lek*;]KX gROZiJp:s1gcs(K7uzWѡK><')X؈B:BЁA>@ X 0;fbN(“[SJf&Ʃ.lz`11K?R/H%0דh 弟Y(ϢT>soR_okLENYwyPlQf8 0 6ܹSwΊAvQINʸnLSY^qn;@9ɧOW%|!%?dw_S<4a1?#_MaL֡_{R1ο/6] <\K<],=Gr"; uqL')Ol &nI3\}ʛ_DiߌMcl&b 3JZoX{V(l ԗ1z 8U~ q58_٬뇁*?2*lBqt|T?'a}p}Ye#;FlwwߍM֊woKbHo-K4z+4kU& LgQQފ2t%KIV_d0%XtR77(qyWH6_yvhЯ[x )}ax^3> e+l✰pt\5\KF*| wV]s)F`WDz%z`1;K?4q;OQ*ɸߔ$-?BvfEFd%V8J"=E_AZ.%hu* ׿V8SpA+2(\3R ;5xoZѽLl4Ȃt(c3ui`b_Apf~R҇c68F óك6r#߭KXv pIbz`1~1ziϤGJt曖2yssQG(/_ gj )LÀɧ(=Fi&; 4{AR ս):**ggTfYKKyK  )x ?!O}A*c6=ҳk1t!Es^rq?v:y3'}=I>ﻙ.G}7oAe({Q/F9?x&S̻s& y5qvaD[!"o"N3R~+6,f@2,Ggf$񧾨h%۩s3<{m?&c`?t j%\z{`1^@Z?O(9xZ}߮wW_GAe?^ ?LS~5qP&_Z54S^3 V[,__Ƴ鄿- eD̳R @ a<#`S<nQ8Ȍ}7?uF(ݷ%%,%jN:տ:$~"⌅RE8GƒxCa:' W[ U0>;-wQgɗǯ-Zq>h?R%xZx{`nǛH|R(Wq O>ߝYwNe(_Gގ܋#@ wRv[BwṚ3 bn*u 1< +Q=_@ڷ!||Ǔ>M[>(GaJo_o_wݟDxɳNdT]zg)6:lc ,K޷guΣЃ~/ηSQc 8H?̅QȵwE[fjUa.~qTS7k 7uʁ=;{L駟~XLU9K=?j.ȗ 0~o-s{_W223O5Z?L~c%`uJ^)|a|45]-2L򞃇uQlGHoo%&g_ \' Î?ʒx9`Yzϫp t/p.QTolڕofU _(f[.OQ'¥Vj2(zWq*?u`Pq3wÏO }oR5eq3nJ-~xk-'Gzy;j-x=/CtKb=ЊfaNowZyS߼dZey :!FҦy^y1d)Aemn 4ao#<'໛)>_z0kcGR/ޒX.>l[KpMRIn dXpK+uԫԥxcBAEО&-&EYph2@@Upr$v~}1 cׯ_#gu{=}ۓX-u_orG v ڪQ{i}Z=tA+^<ht2*C*O{u.hK_#{NPt4qF(X*Ջt9zw}]O LhLv;# -`UTvIuoUP-UNhVż:Cc"r>.Qy1 @ѝX  @;d坺ԣsUuE_zo:epIsڃÄr :XM~[(p.[խ{4..?=V> ڣ4]v4<"n]Q#BHV@% 0y;h0iw6F~;:u|`K ue,S.+[izhs}k/+?HY TAٳ̷ܻwy~0gcWǺ*G/ Qީ"ݼy߽W_[lʾ~A .u)|.jS{>*WV'}*9~w4ܶr|:{2y{߿~®YubL"p?VKm  57z}p˗i"8>} 죗)z;w:_р)ݛO+;ZBKwl-//o((7ěy֭\-Zkwm,کiY?'!Pf #e`:ޓk*=rgcbqqqJA}Jf:寥wlhzj{?n>y䌂}_+N on<Ew)۵M^~ڀT|S Um( z- ; 8]3==$}uD }4_,RYT/aov 0yuAtuZ;Cr~&8cu~5dmד&kR~tZڲkd g}4X VV^9oš{;ҡ{ϻvZGi i+TD(J+*F"#JX)@P0Uց{c вN<0TT}TZJAIk j@X#aW˺imNL,@ ~?~mB`Z<{["~2y^*uWeHHb: "0U$MT :ey`~s{SPCE{QlVS}a P%PtWeWꊂ5uFRZ u7# l]iy>PמyB@U@ dGﵘҺԕ9|Xk-BJ#.HlLi]QAAn x0t?-  H u$=t_)}9T v!P Uͧ3PBި pn@HxO`-B@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|?#VIIENDB`icnV Cconnectome-workbench-1.4.2/icons/mac/spec_file.icns000066400000000000000000003275751360521144700223400ustar00rootroot00000000000000icns}TOC His32s8mkil32 l8mkit32et8mk@ic08pic09@is32 '#@MHi~:' PZ4Y|}Xvj·`!ԃ]աR(\pﺐ柜5ok2y)d@SReh/*WwvyY|Y31!zzJ (!;`No{4( p\fmx\9tvrx!iitfgpoq}SjFk_Z|gNpzwmhxFoV{zy}}P6]yV)\}U/ ,- q~N ( 9|Uw}2' "SKk ^uxXdϜ2nǂeIhai#)y0lt|s;DqFbä85y:ZZhrm~XR4ty=}kѠdU+]qh* "?nxP s8mkSš͛0i*\J6!1dER Sil32  ˠŬh 61 I/ng l l/MNptcѡ-h #KxgʪȴHi4?}v>oe]j!e4q^U=̠tL'f~Ha^Y͋zn$rh jy]۝QqvĴ$eeR]tyyaFe޵TVRta^}iΓȱqT"i4Bj+עᢙO~U:_-zбⵈfA[YnxƯH701qԮ~i90ZD~.Q2aDΰpJTX/V2ilcMUT`8y}p7RYD tȀjeUTRTtϨc4 Jg/r6qIҖQe9GŬ\(h 5y18 մsya ˣe8yo/Is~dXI7EWrS =͎ĊILW6|x ˠĭh 'I( IAld l rkWtLvmo:h '6epRdwGi (M\sc5mJy?!fTzGveƷ 'g ecjNtdc|ƅ#k6t{r{z]Qjt#fk`eratBMgg1[V_yZY~Yps9pHdy7)pkiOW5tވKxiGOudXMz8(Rݢׅōcs8dmD[>OL:/0qa}mZR`|RMBG_ss,fʔh  dD C>{w(&{g!h #KK~?w/|ڑ 'g>ꋝHK5]e`sƒ !h'xŌ)B[efpTfPv#e0i͕^o7IX3o{'ScZ9i dSXJXOxl9]&T8./S[LCB-u$s:S?aĹ^1Ik&M=I|ib60MU0HI  &=-g|HI]U=LE2P?R{>?4RLsǿʳ4  &A ;]4OM?M#.z>WJVxmƵ`dt| &A 1;Qy8 GM4 |5/S^rͬsWp͖Ϻ &C(+8*:Kmq7ROIE"de>Ucp{l|ᶹp ֒&C4+1GEgG]cSIJD2ðtj}}΃rtpoY(e5s9&I67$ȥf&GE:FS7ΗnK[IJGF!Dplyo{ʰmwTW|̲*&Gje76 RL[ռ]WL=>BDE[m)Lqjz*slBI˭]_I/4U=&Nem+~\@ڱCPqjMQXm4^Xy%ֿ̯/%2&R d>?JSþĽƶOGS^wyKZb{)แw追ů~5X>&VY#FM=2QŻƱؠAOUj}\WZk8칀hp˞w!)׺;a& 򄧹+evtۍŞx\S>e&dtƴ*'bqоԛӿGV\lHiZl{BSmetײwdSd@Af&=ʷPS[ Wv}ξoLYd~|LmbpE[ckrkpyƲbMwϿ/&fһZ .}y›OZ`pZPqmzԂJc\adgnuyz}Ǻʭ|dٛd&3ۏ^ mlwsX[_nVMtv[O[Z`belqqryȴڣw&& LmWyr{sro剁<׸iTjk~JKtτBRX[_abhllrǼSp&2gyT3Lgq]D˙wwlMrr(Nu֘`FGWZ]\\chku섒äp&g}:K&$:t_Wc}CWntCovf1`rܤ`|]CMQWX[agnubop&uZ]>ÀxkDUrTJlHfxUd_dB?DR__eiryʉhֻ"p&HɺI~[Gt~xHErCpᆴųVZwxZOiwXZ0.8F\h}notϤZjp'ػ0> ruqxR6wry~ϕߢj_g~ӓozL~A;\nK3uvߴpNp' t"tn/ h_~xW5k3 mVm于uoԭML;YQ;tʵ΀LzFp& WztJPׯ?kzU6gЩ"NjUlױ~῝wekPTwܲ}gPDPrkؚNX^o$Ff$W`nwyxøL~R7d\}s~FS]ONuնƲl`{ޢ|zo񟐩]Pe>g2p%|opt~S 0qS4bʮG xBG[KCIlǡýiGǬpEl͑Cw^HPp)*}~z$bsR5YtzK6HC@-sR=D-EA>86Kqʸ\«Ͷych~uyKpClĵ&pQFCiQ6J<7*&FkȲYʽ|Ͱ¿u)p 1aȿKaXDIMn/-44+"&7eڼƳ`رǿwsv˛Tp,GW{µzY) OZfjWbc#/-))-RE¼f˵Ͼȩul{nоzp)j7d}Ơ "fVg͟[U>37DC62LuI}mɱλkmܳAJ`b*p,Ea\s \S +k[OqMUw+49GMMH:17F[wuϿכʯtfv+6|U_ȭAo>\w΂;`,h\Y[uk_`lew -0517;;9410&6ՓdῼþZRw߬X:ќ5p@pzʵzPss3jjmbMNUxaOG[Z: 3MH>63:@A=73/1-<٢ޖvY˾uK`dEܧ3pDTnͶI8hZm}wc\P=A?HuueD31AĴsHiTz̯@qt5Vtdt]#Dkajվx@Leb[UKEBI\w8=CHMOMIEFGKKByъ`F68B8z;PY݂\ôOAzBAJzg. [;]^UNJHCDL[zi ?KTVRPO,SPyĭgEACABF=Ơ`P}i^Y(t\Css= !ו AW[QKCGB53XqDk9EPZ_[WZYaU?NLMMLGHJJEB}ӫrKvr:}Ի(~Yopa^觀Jmĝ`ի(WETUKKLL ?W^n dYY[_cadkdbRRSUSQMKOPLKBb۴SiZ/m\Cq^KᚈP2"wI n;TOMNSH#0I^dktwўiZgiquztjdXSTVXUOOTWVNP:w་\gh"KEvޕ]%VrW g5RLRRXbglmmxw˴ƎVoq|sg^\\[WSU\^^VS )OLRU[_iTnR]Tuwsiec_\Z^eeaXZ9t߿j̎څ/FϺ̟pMRJ 2IRVW\]n%q' ^Zvskgb_bjmi^][<ߵqV{M+(BǦɫxi:lPkVBSYAcs {P@7ڋb~sjc`eone[fLaz j"&4etȧԸX TddW"KQORYo`9vgxld`cjh[\TxFt#'{Nb 4!%~;/˵N&g2<\q\'h=\G9EJ>/ *V9|Ķp֢  n"  Ơ0KҴZfo|bB|oCGdijcd[=&N#%Gæ#=eix{` 60Jia*рxǦS>ftwIKiEG*$'&'T&%%'*&%!P-^nQlZNrs_jj~ߋ[Ǚ{]FqwdWhY<" ')'&%(%L  Lnahowům@ADqnϹVs}̑lLIF& L3ESatZ 57wFg|{ !'<`|jSF?>;)  SioxucN;7<=,   CUfg]WUR;   QK< ۗ  G*$'&'&)'!-^P9$RklIYxY- &%+\um=8beM,,SUKVwlUðɲH &=*n[q:8__WA?NZhE8Q?S{gS?OSyWw~; &A 7ef2LYgH@KH_bFRLVwͷabxs|EvXTP9є\X*&A 5;X^݆4S`MFLCICe>GP_q˷ƮrUYCBTmf}a¬Og3 &A'3?G=:PLY?[WOHGACoo^ap{Y}{=CdWUgbTwLq\=֒&C38-3FSMJFo֦>]aTIIF9T~³sj}|qN^EUmRpOkwj8AKeg|t\jd9&G;KH0<\O;/\rDdULEHB6a{l~wuuJ^jYYePOtYeg`fȦg&G /?Q:V3D[K/]ӺYNZHHED:OmÑOtq|̼WFlYX/Dl[dx̮~)&L VA::1]K8l3UҟPTMADHDHZmoybnk}ĚBLeV;>\xh`~n^b;&N g>12D`&Ckv;J867BGN]sX[\dmTWI>1Pf`mqUHs}]vP{M &M muA:Vc-qpf_phKT:?IQbvysVXczMaMM~~NfIнva\wc_&OccCPd7EnBi~·ǘ@D=ÿ^Rgùj:OPcp`D\a^J[uݩhijq_o@&T,ugxv^I4-Hż`˘6DLZcsiSYXlipyYeq~ȤmNsӷ?&V qttv`71qűϝHIR[uyDbMZ[^yOʣfBYm~}Ѵ^F˜=&XSHe}TX˿eS[DDPUdLpq@bYh|eW~ǽV6jq}SEŝzYPXTƽ>&YPdoyĵxkfoѿ`q{dk^[ڌ8MUXy^k]Kh\hmMppCRipXPv}ײzhYjjab$d&!c]blY~v}پ|fyTdiMn>XUfgɷDYjcpnfElbE\cecjpyǰ|M|eceze&MM_>kcZUn~߾~shl:hݢ{K\[zqyzmSPrmweψAO`^bdgnuyz}ȗd}ӑe&4[pDw{wb^S|wvs~xdF=QG_]lTOuwھTBRY]`belqqryȦxʻjmYvp& PhR_kZs^xx~{tHoi{lsg޴^:`doyNFuq;TU\_abhllrD_zZgoDǾRp&4P;vRo[Zxe}hobctWa[{b|`]GTosOcx4Mupޗ5CNUY]\]cgkvyaճPh˿#f&nQcDeO`wP_WaҋupRqbl^hYoKLKXApuwȌi:\syaA>:GMQWX[`gkwo[ֆJg_աWp&;dFak_{kDSxϗvGbyhecڅDrP\7lsyՍHKh}jy2MI=;>DR__flowsSNĿQV`-p&.^`}X}h4kuxHDuÅ]rEmvkZҝPg{[folB_qyZ߫Tiwa/Gm^.+/6F[ekpx{^M{_jݟcEo`Vp'ԬL}THIuq~xR6wakrQbVŗ`M_Gu}Ek]jypcҐpz`R8ERG5<[uI:MYfizv[֙q۴oSn`o"p'PBzoSDw_}xW4ld_slDDă_RQL[Sf亏up|]ۚ]̮|kg/HA>@WwD):NW\`e\Е`|STvV0p&ş=e~zqYb٬MrxV4hϼqgs_JذiRٙ_ƙHs)DC>OsxQn@++BIEJ_f]kOUaoU p%*SЍ3X`oyvwĵ?bxU4fχeezhBlBWdPJFԹefū^gת̚SwR5EB:Cr8dVC@BpE`~ZN_Aj1p'L}d`|ooui@]nU3cȼ{`gUzCEXJDNl¯q`bŒھzBFTKDHnUlqloCPsx5Z͑@y[EQp*.Ox~{WS]kV3ZQQij\/LA@9MpYyRth|?G[ISSuĐhQRe.KwfbjZ&p*bkõsSqTZmU2*%%98G\wcUɲgħncرiQOrfwl[i^/9YbVPDo@XzmAI4c̘PXUe>n_KNc`V`jmmbL987;|VSl@C-1Yɼ~ndeS\waCO_`X\jttmcKEKAlf90,1@LJC=52574-('+J΀H݅^VfmH|ij}527;;9410&6ӘpnNLRVM9zWwʻt\QwkJ53;@A=73/1-<ԬYpHv^XEGn|ȪuK`oH8Nyۨ2oGFQFi\:xZcǽJILhnADH3K`O=A@Ew~LۆWucB+55mȳsHhboY}˯@qpK?Cnquy۽KaY;qihqeiտ}6=ha\UKEBI\x36:CHMOMIEFGKKD@H֙CmgE8X[PYw]aôOqyU6Jz[YKn6]w\]9^^UNJHCDKZzmX(=KTVRPONQPUSJM`a=DF@DABCE~Ơ`P{HY*wW,tLetU|=QvҩaAW[QKCIE>?Xqo9EPZ_[WY[\bTKRGDFKIMLGHJKCFӫqMrqepXTXor>BMen_HJpkƬƅүiSRETUKKML?;8HU_n]tbYX[^eafgnaXZYSRTUSQMKOPNIAbܴTfqhvkSX[Eo_/ZWdm[ODlpd\ldWjUFkNzSD;TPLOQPKKR^ckuОjXfjpvuvreYSUVXUOOTXVOP:wཊ]eRbo{D[N2oN-^{iatjZDkxxb\nttnXygYsbWHf6QMRSW`egloww˶œXnr|{rg_\][WSU\^^US=ckbV]WYdDUo;'{í~k@hU{hHotXjl|r[XWAi{WQ)OLRU\aidu[]ɇNJWuwsiec_\Z^eeaXZ9so?Qp[bmr>p5%sлnFVoWi`as}~mR[ehQ2IQVX[_jWT^drKIұu[vskgb_bjmi^][=ݶuJ^yYmp{g"p.#jȤ{tѨxiY{blNZsUBSZYXdthwkvZztZϊUމd}sjc`eoneZfL~ˏ{MRUX]@hup'$n}ɦѸ`Ikzv{k\de߀Q}POORYon]eEOyVђlfxld`cjhZ[TwòO:mzETZSϠ7RXp$qG8ʷaI\jlkthxX\mh?gvFNOOLH6BI^`L[]LgZsm{lc]_`ZPSmqbdkQj2Ev:p%`W=8˱zN_uddZthW]nRєWYhm^a}q8DXYLDGLNP}~xeq~ymb\ZWQJey]Hvȼd8=cp';7չYcgPU[u\Xeg^ckGgOʫx_MGPXp|oQQ|y~tl`[XORRTYböS@;>p&/o̹xpXE1_tfXhpw`VuX۶kuơz^^krwvTRM{kwd_ZSLWZiSHWºnL<1 p&IbdeglpzzeQD>DB0 *V9}·q׬k|auLBGPT\QOďpz_nѷA-OT,Okwb@HckceUOA&L%?cǥzȿSLGMfjw{nA8C?Wsȇ\d|3M{R+CL:!H_W,G*$'&'V&%%(*'#)T\fm]Xrjg}[McƞJMo^A89:Ob\;""&)'&'&%(%L29Zkbhpwȴilvqʽ\l[spdXWS]NDB!% L3ES^uֈlsmt]Pwg|&.CZSA1#!%$ 4 3PliMecXogwȼu;LPeio~ 7'(')+7:.8[NbŶ{lZShLz  *!;::AHfmJǻY>Kmw}ν. +5RH=EMPijOW|x||ʴ? *6icB.YͽyvK\v}S #VvE,jʶ?qY %)hr[;ST #UsJ5 !aw[Ƿ~[   0[Rqó|somkh\> !(;aG}{iTF?>;)   5RrvvbO<7<=,   9[gf_RRS;   *5+ ۗ G*$'&'%& )'/EZ][7%(&&(%!0HOQI3#&*)($%&'(&'#-& A~}WDX2 /UgjUX`N% ***lgFaR9$Sjm{|avT$ &%*bo}}>]aM+.RVIYricg9 '/(`' KhwSOF#,NoIMDbNHLpu[r{$Zw-K;&!{ǐ4֒& 2VGSSG=30\]VJFP~Ĺtj{|O)*4g}zt:&EJxEAXJ-FcVKHE^oúw{xxQq&-Jmpȧj&G %Ilx^0&SYIGCGmdg֓ntzA",  Em}̫w&&L %>AgyG*VMBGJIQYoxknzդog|8&P +2S]%#K#-CFM^pZfjD%#(]~Jøb|Q &N 7Pa, =jM!7'?JRbujUb~uLO|q(¶vӒ_&O'Vd:!&OeiսȌ$@IWe|˝RZkړp~6| ǿ⧙t &Q*uԻe@1H̴n`RӾ~&JK[mYdP^tȰRAB6̾+8ĸL,SNdmQOrlx:gS^_ccgnuyz}͇FҎe&53`ٟ|q{2 !@b^m\UOwwݹ1:UX]`belqqryʙVȺ}JEDS__flmur( N`;2p&y}ۯtxHCxg"oՕ/D\:aol jdyB!(06F[dft{}C  Df%"Rp& vsrxP9o{%" sǖZ!3k\kxL  ;˒oz6!#1;[vH;B-R~s/ +ٴpS$`+p&}w`{xV5l@ " ^~c*HE幏up{F&˰R&$>CVu@$# .DG1zVCY56p& {yyqzݧmuY1kmB04~ObAU8װTƘ95LsX+i3$211.]? IOUceTp& "MUboynuðm[0kֆg AXfQH6ԹP!ש ,+"/~GPC.s'uYN[Am2p' 7)W|nozpV1e堎d=DFWJDOlR 7ܽ¿T H;J. V_Zy4WΏ?zZDQ p*/N{ϧmV4YXs"[].M??9Mqņ5[3H# ^ 3Pc#@wf`k[+p+fuIij֩kV)ĸiD/b¼qZE"2"y]s48DB>B=CuNVرڃ'hnlˬc  @3o7`__ADG͔{b\U? *UL#/ }S0׫; )sfwןW)-GoBV{a!Qˏqy`bS`ghndF|Wfd6/=JQJB:4+*.:FSfj RHqXjaݘa,*sbPoLKO$GʺҜl_ra`XZkuulf=e’w_bP%4?LJC=52574-('+J́6}h ,rUgӁW'"8.<]{~Z: 3MI>33;?A=73/2-<ӯv#hN:4F&>ɪuK`PA+Xۨ2oH?'bG |C=ƿNtd(DaN<<"P_PE>Qo༡vD<@A;1;BEEA=9484HĬ@konI('ŲXN{ʧH8[ի7oWL$u>({joӇPnzH:9*ywD"?d\VH@EXwοiC,3;@HJIDA>=A@Dzm'ubA*1<$ɳsHi&1`{˯@omn40slq{߰4X]΅yfl18ia\UKEBI]xÄ06DGMOMIEFGLJE,biD9>>@IPYI>s´OHv{9H{dwmM͗]9^^UNKHDCJYz?:LSVRPONQOWJ#8F@D@CAGtƠ`Pyt UXqxc#tv{HAW[QKKILLTXXs;DP[^[WY\Ze?3HFIHMLGHJLCGӬoQe ǾXqt,7#$IETUKKMO^Q_p`ZV[_eaferQ>NUSQTUSQMKOONI@bܴ}X[- l߼JqbG6-PzٽHbmaeMKF &M+tͥqǿpfnuzxfcs溨љy'nS#3=" GOP$G*$'&'V&%%(*'%:`}ίogvy̙fb|Ц{Ġ+ [_?$Ka]:"#&)'&'&%(%L"3fvhegpw˼‡v}iY(>VPDA#% L3ER]uٶe}(LT@1"!%% 4 ,Jjo~ 7'(')3AHRdpĵxz  *5-6;bŲDz}zyʴ? ),hdH-EʽX%Ew|S (UBeƷqZY &%r`eT # On\5 !$dtZǶ~[   1[Rpų{somkh\> !(;a.t{iSF?>;)  "+JpuwbP<7==,   5gkd`POS:    */% ۗ t8mk@   U+k`% %o^l6 F  Fn` \q La0 >T& XJ5v) 5"1A Ts @ u 4<* aD^BN3# W{ (io9 y /Fg q r | v>D. U &L62  Q )]zF8!SpI7|@Et|sG  6r¿S Q  J|?  k[  dy =Ch"jYu!l!A-7]/5Gic08pPNG  IHDR\rf$iCCPICC Profile8UoT>oR? XGůUS[IJ*$:7鶪O{7@Hkk?<kktq݋m6nƶد-mR;`zv x#=\% oYRڱ#&?>ҹЪn_;j;$}*}+(}'}/LtY"$].9⦅%{_a݊]hk5'SN{<_ t jM{-4%TńtY۟R6#v\喊x:'HO3^&0::m,L%3:qVE t]~Iv6Wٯ) |ʸ2]G4(6w‹$"AEv m[D;Vh[}چN|3HS:KtxU'D;77;_"e?Yqxl+@IDATxWu&~ss,MPI#!$$]wm؋5xm^d, ! %$i&L]9530dltOuW{Ϲ'=))ꔀ:o[޵4rH Tŗ.% RU,ixK H @K@*^|yR= %P_޺4rH Tŗ.% RU,ixK H @K@*^|yR= %P_޺4rH Tŗ.% RU,ixK H @K@*^|yR= %P_޺4rH Tŗ.% RU,ixK H @K@*^|yR= %P_޺4rH Tŗ.% RU,ixK H @K@*^|yR= %P_޺4rH Tŗ.% RU,ixK H @K@*^|yR= %P_޺4rH Tŗ.% RU,ixK H @K@*^|yR= %P_޺4rH Tŗ.% RU,ixK H @K@*^|yR= %P_޺4rH Tŗ.% RU,ixK H @K@*^|yR= %P_޺4rH Tŗ.% RU,ixK H @K@*^|yR= %PUܺ*7_o~J@+ws E۫Oo .8PTUYrz^fZhEiԲZ %k߼XbkEQşW^%~UKē \o&Q|ǐ41>EE/ZJfղua (T~ϥ^.(SZPLqMo~Ƨ7\)i.Sdܵkaِ+s`+]˨\8+'򥿤T|NVvŠTBtqS곖_PKRX,d`0vzL6 GщBP2L0t¸KeP* Oh* qY-N{', ~?oG.h[#eu|rr333t-6ei|ҩ-NeN9@`hм}:E5gF`VsרjFFFB/zghhzz{4Z#z%fd2b RYi^b ]lb:I@pj Z 'D)罍kls=Xe{<4q^1t5_۹OZ uNze_#WXK(Z7y_̡ǟ?=%)`03(9޷*_?/׼!~O"'?xk!Y߅EM t[<.@<)(xO_Yc->m!]afP[6 AE)U* {JM}U&VKgK);N&\j!h ٠+V~Wګ G|詳,EcPw*wP0]1G׹6:/j/Oh4:Ot/v.h.SE]2 yS Z=u =nhľF.)WՑ}P՚3ʆZސD"z*ulḮi"\ÊG-KϦRbZCfMo~pzr'ۻo_AXJQu"Ԡb CP.\9 &(L HpK˿_k~x"|Ɔ߰5ż!Qԕ,IC;2+z`7qz:ڕ({PMaҶ隬j],ֲ^^4ƢupZu]h8q[?z%j(SlR,f3rTΩzWϓ3߉S'œLZ+B*\qWl;xdu-俿E]@h 7 57UOVNPE)j-m\'|2dJ"Tr"jV@g)5H4 zX,z شƀ3Y/"=% WkG`R$UN#!r:vZM8|:_q? k`t٦yqukTgC#º>,ba1X{#^ܾ:O 5֥Jǟ%Ow7q)x#x-i~*NbP7Ԙ"6Fmi.B2(G )/@q,23ȕ-pcPt4ՂN_vݨSOD8Tl\XKOuUܵ#vlZ¿>b,Z!4֠ۇ&l5JӹgAq9,++tYi.LBݰq5ۮЃ>G\:g1  BQ64>ً/2tռqoMfڍ^M[󊉖G0"( qEPyF/!7OoaJ܂}>)NCՋlt*s#pHk\Z@ZvZuߤHﻚOh+W }7-CId|%=oI9$#Z#ih>~iV`Q-xЩB0ıy ڦ$vbO!In',7ERCk|TP?q3 b YIaUOHzK5W*7kj1`^GnY@󮻾wEY xJ@ EjS$^AS HSQ?p Ln]Sm6Wg*-A_4L i.#aУU`7m>t#VA&^B]s3=,XCG,!!Єs5.l^xދHGsߨmpAjoVMz:=+8=Esa:kWTzmۛ=ZL&}OOw{~GsSAl9+"•PK]ߜKﳖ/gdw]f8s|=E͐,{07~Rm㖺r!0> C:ȓLZVR1xvl$e*O2ܚ%xuNxmYfᵰU} j6gۦQK .bAnԄh 3Ǒ..c-js,!&? nyb,:l4 SvҶs5b9p̸Jk47}=yIk?v/*0y P^e@ﳦ4|ht?SsFuΛ]?jQ*m"e؄:|2WSd`LgSbCn8Y_nHãF1_VC"W@FeN.\P  3n ވSa 4%#I KK!AO`!AR6oϣeSwՠ%{5c/Ar2IP%\BomصYyiR|?Pe5Jc'#SrCW۷nhE6 Ǜ,iTW6Md.uݳBd(%3Ih֣k4+p0[FkO-8}TyVK9=Yxj44Zl? O i52l<j d(Kyfg]d'V!Jo'x L`9C-ks6`Mpy ɂCp߯}^w(?#;Ckֽln'N@7^HxS態2O0nb(: x$U;"AB.E6méګW )4"sHt'@yt܏dĮf @(⪡$O0؈"rg3 $2Bhjn5zw-ce AyTW[J"KK})ur[wXr2;3ҴMg*yLBzN;GKYAnZ7B`ع烩׮kf⮅To=fzOCHt4j߽8c ph!/Zѣ+܎3%Y=pBs4d΁4Wd:42igb!Fd!1c:-Ύeڻ;X(ݚq}gjz~29X/|7 xi׭sGbMR_JKQmM}u·v7ce.33<.]nMGZ֣=BPui٬*GKq*_HiPxvfg Nl<%n6z/޳4c<s!4&RlhmGc_Edl30-0| Kz.k:͡7Z`b5u] ! |mp,GDaiTM:ZzJ5c/3#24o~97Xrӊ٬2_g37A QcN.aGqmȔo<Յh+Y X[arv`W_-X߄ŪKJoqKPl/}j[ώx6PcJ4T3"QtVYQ:܂,)z~:]do> .]c5BTH}Bwڌۋȧb$*/MMbqq 50?m(B;}wKA4ۗsXFW>Dw> ckn]>2D+ta"L..N0̮CGch@1ɯ|/PR{ݼ}z[\@} P<*Wsܯz{&+H`)ժK?m-n }㶂+?bLx 6g  Di;t*H n܎U}UiF*hQYhW fBX.?h8r< $0K_Z oSc^5)&6bO=N'J8kd/l!Bp` _XiuE dF%8 Ňb"$JH &\y-C E=}#Ε Tyce#cI4 G^k8H<^V'?-IVWt6|m}jljÇTCVObo*Fzto:46D#A,,cϞa". ZV'h}JJ--1ZfM/WlƻlbBIEᲧ#̲?kj)= |/PD8`/B~?{d߲9nC]| a/ٽ}F1Lb"8DYGpLXK/kkbc'hS7?bn'vkEVkh䂉\7lABA|i7괪VQ7 Meg6ޫwzܻYY53濡a m^jP9Tq3sOT [ 6 ?0:0JV?ԇ;xaۋ]$Aza^~2=q]o6~DwEh) BO"ü@i$Jiv$ (kJ!\9=?x?"wqڀP% b$=xH:*<x\𒝨p׷`ϡcO :Ma-[4Z퓟5 _"2GOB,J#n_\Q 6PR ;7C'oLl~97֓˯{_ߊ:nO͡2ʭ-hjjF'Tۑ # 9MXX^`*VmB}k<  g<ݴ 9=eg#<9G h.74nF0ueg΁)sPUf61gf^2+4z+Ƀ9@$T xĶ܈Ʒ!tZ)GaQ[+/._|/t*U Ԁ\0oN/ôaM =3);}L]+uM?rY *r# en/!׫|xq{cdepCQ~2Z3Ng2PocrބgDǸ9./c]wF|+&eB̸4XQk͍-h> 7;?Onw#8I\d@29Wg1muFt,e|IDY˷r4;p\`\u2i(mדVܝXD0aJ$8ė8_xI0F'&0=ډ#`+ro(ݏUcwg#1(ܠ}r)4RYtY L>~ HKeRSGǓ-k[ޣ>z3 &힯cT,i#rNX$J^ğ_> E?4icEF8&T}Y3{>,ԣ#2,˵gF`*H DQ'J-맲!Gġ'6 |Ɇi[=O} /~C|o'V9,z ZG͓F_H, 2@ <A%^(0bg!"!!a?r`񯢿m+60ϱ SRnjz-7#Lv ;my?JpzWV?&dMSs$X.ѡ2LTp@Aqqt|#r [+rl(l؉OlCvԫ` Z lfe,A 둀4GZ?ZT-,O5;7^w|J)rJ&{9JO4\3,X3 $FqE{fq}< A 7 Ksdxbyu"D`>X" G3F_n$t COL= v-(\ewjŽc6TF`q`~zcboM?Bmd/" 6H c8"X~r ҃ W(xǨhebNtD3p$NN>Q[|EצkPӷo 3& BF?G_^ƞՂ݃_ݙ+CqԬ#Lcsq- haL4А#R*r"yzn[ 4 xmLH,(ʰdÍ~σAhC;RXrJ`ҊHkQdai*3qS{o˧$8[-M.L?UL;ލ@gR H QpnAL~PcI*V8БBe0M'p \ :_4<EjN P)e|2iyamP}^՜9b^ZyMS@\xH/UB<04&h0[Uwźe6'Vpt_$c$$YvʥI?ڞuC +sTP.v-v.:I G-l) Z\F"ӽ0Z&q6Ha fT"JJڣO?,nW V+Y9Xf;Q(aCC\k oc"vGP{u#v'?B0lWu¼D={b49hdan?Z*izI&&43ϡy ?q+Ć8>"v J@X^uKW'F \>tK>o&ZWVŤ 1Н `o"v*qwOGe_c4|3831~XlBȮ!ǥ"OIYt&?aAA`Ίv&튈בhD_ށl** +c}[ϥǜUz!Ѯ(vn p͋&2jjeL +Y?O/bIEc-Z1MW]]I~ON11τ]a_YG7 ӰғPZ[j;naҒ.D" d.@\~EDUNߺ_,2\DY<ݹi)* sTk.\ & 누knE8,K>*^5m"sn@C %faDyR%~S͏pN_ЂeD:6"ÿm`!R`r(]ksZM(:QJ攂9SdMܚ,Ie[ݒ_@'|0a<=:_w&hc{%H;dl HNNn1ؓAI%^/aA>)e$I Z;3.$/N떦$d?>-g6o'[i3alq# TFې\@+ l+O4x:ԓЗ@Ó:ZC@6iDD,x?{0As{}H=ۚxt~vxk,7qEŘJ2unX_ ?:"pzӏ亻jآ^ ,S,1YƬ>q,/-,TвiMp_OLH2Xr4afO-lDIcyd{,= 䭘\\WR`_^޲HvaA߈.)!м P׿ \L Hsוu4MLy}7dַݎuX;(!&iɚdEGW"{E(Y~e-RJMMT.RBaR'W#}jo14HaQֳ/b`+j)d.NGŧ1NPOS/*fnRxv6=?#g IAIF rİ{k ޏcc{id؂Y*l g:r52}OrI`,?dC<+'f )'CmN>S&ʣ(nCm54E?@?E>`C;PY"mDyr\4Ш0.WɧׯCcbDV@,BAơKz^mW級b![\{m*USI/qi~p~Wrhh_m&>![uѢd:ԐU<xS@`sָȊRU+&ش`eY]G|!aЌo>pY^-~ʊ=awD5f&q1_)81[fĆP$~j*-?z˖d90d G)_ۘu[WAFL. j)J[&UF ?Gk5pD@u(u4׾5=h#:{6ȹNBF5462'I{(0b2НȜ*:d)m>;-W|X3 mo'F _?Y~d5ڹ6;8Yfr/+2D"̒&yq2BK/+w!NuI=68X3_Oȯr[Khily|e&1 q ;˰7s(=*˸9 ^79Tglf Nϓ)#+E#SlbJd T(>s}y,UIN"C.+n`@#-FgXN0|iJ2,m}.ō6/NzhY(3,!U i^{k4߿]]-<:JYg;Uo#F+ꗙOsZF;66#muz+tsEkF 6aK -#عK_f&!֐V\!-9xғTY,DYOF@$a.}酧p¥^"ܹs9 q0$g.CXLNZfr,A2q-'EY\;rC/.,k=1qg`rP-@&u}n4x5>8 2rmFx] %Cw~wYA5 ^C@~-J&A󹜒>ؾE0n:8/n1p gL\÷^Th,47!7Jl`a#q],~ ~ GNcܘFvz~0]) }5T87Y{u6Hȱ)nx=H5O4\ˤ$Ic֯[X蹎.zILOOرclݍŦ"3^V9@T%ۗEOd/xBŗ0FxZg'p z60u J1xLЈCފ9(I le' l&]"JdKK ۥg+m R +5w UF2Ábs׿}- e JE^=Qڦyνodly kK 7ab ,xIDATLyOfME#<Ś&ںls1ϱFVU9y3s8Q|nd,YB/v~A82G4zp" ژʾvs@V5ǩ - eH{.`V\O(5)eRDe'',-[ t=wH1=#6EJ c =?&k;k+!3ym ^\z+H]7g?G0ĸcb|`'`]&xS0>1A\ 74Oen~!|i7wcPw?ː 'u:f _D"M|Eqa芋x1.8FK60#xaK: = =!͖ɕX`3OI(.FǨ^bl]ỵ`:SHx?Ng?3IA%Zq3IWtpn zi-GmC?'Ɓ'6gf\.304X z^lsd&(bMTCQH892]0D+^k89,F Qr$5Cf!5Js}qْ,b:_2ūģNJғO=sgadw*93rThXɒ:Vh`F.!Tl׵IA,ep,V$jG=ڕ<4Ls*[u.s0a쇓6sal5p֘L٨ ;g j; {m%b@*16`O&(% i5^\7Q.S7p3=Ċl K4鿏=V/BV*0' 󵊨 P_JJ y/Ax0n !t10aH%*lǛ0Z ؂7CuB'bJJy n߳Fwȁ|(xHx)|/|xSԩȶeTl\c2z@gR Q.D6 L Co]\ K]h5?r>p݁wv (3gK#`cy-nl|g 5-? 5`⽈ENdL VX agyOĕx4:ߵTL ٫6lan^0\vC3>8N<;p}4r$lnjOIxTK&BB//[  huF F}n?03%,j*hӸ[!@kŽ\ixIdST1>+-mU?' k/@T\vɹR&W&KK怶Waלi+wBnlUڈu'6L{fMf;= ҀF̴m@ bThr4Q-gmXk`0mG dL`0<' NS erدPqgm)(tM z$b-Bx0t~p̈́dן? [v#G?0<:f eRIE~)'Z2@T.|煬Qk֛ =~O=Y&)7,cJh dr`&τ?>H?g!N*Dr,ZW_AK>.Gܸ%f"GutSHF"oF:J7}FFbI)I)IY` IFHnǖm)f4kqx33Fo{_kE /bF@Pᕹcw>v `lG@c2c t1X' =1BЮj 'lk)-_KaF* C 饁H L4,ں~H,$ td>X~:;$ t%4֢h ϑr--_x}q Ꭓ3O$qmMPad\Լlno9|ͅ`8.XqLcI߸b|,G@-(QF[ўAut|$6гr[*V†t]!8I%Aor AH77bQlA7݀Ⱥ$Jv'_@S*/g!y\t>BNDbxϪ>%"[V-.璟W 5s " #!+<P-"[>\S W7VGSV%otf҅ib+] _A@k9i2Gc*,*}?mGoۭI6pu*clg[Qq*;*ugV5+nE.vb;F)Puy4A 0)QTʩ_Gw'AS| uj aOa"ZQ j2RsrH3>&i\~ipC'N@L> #:w':8u#%3܀]w=\x @ rn?@JcTY fgMLA`/B9IvbEt 6EJbJ">:s7d?|"No˜YoD<;:Nq7]n4Ljl6G|8-#_D1z+dRheHEYl, P{Ԇ=]% maN)v080Z $=y)NViutE_QI Mg.CC4kaM"Pmk(% >K@ d_!:=8,@G^uh۶m@1fDy>"̙gn+T6Yabd68t\rWfPl[mIX09,)~Qp-"--Vm^-ΧozA~U}U SYKX˰ [$ԐXTt p(M=lṾzQA6PA?Ґ 1L|>@=ل G w J rΎ^E.^uʗ_mBaR!?ܯn{Qݗ d?1j|$XP9Ci^+޼7S \(Zim|c>#K̈́p+& e:l琋}B@k]H[A^>w._4򐚓6%lwZӾWTЍRb՘hS8< h F17\vxR! Ĩ~0L[#^MQ(; DY{AŤ:OhUmꑒ&m8с/^vwNz:\e1x+]{{{.e9@K H^y]G8_Gߨ\+w $LJrO |t ^U*J ŢLb@ t8u_`LpeO`!$! p:ů,x |z'r wlbKo665fnƦ]W?KE<5(4('حf&Ix,FtJݽ!0vF1 S>rX9IzZPf=Y̾;xNeYTHзBe;ZJv"Y*#9e;*^ͽ|ŷme0تiuӰ "sM5>12rݕTVSgZG8ڑyX˾N9ڄqv8;N~An˫)@; ܕ8xÛ,Goa؎eNݰbqp/}uyT[zhutaai q4tFLG=w+6[ ɋ # f;\n…5XYQi])T QkVVEZnL<'|Tw ,6+UVjAe+'ƃ=DkEXmU5#{eZC=)kS5ټ 9ZQ:5g uOhl8hLyXfT5&'f3c ]ry1:W M@GMa9f(G` O;DEMm҉TeVEW5Cj8QP(C;)ݞ]\W!P*NŒVȕޱI73 h&8؇JL"_-0h!A\ca;v\-*!e"  l`J.7Dbg&ǟȧjd-c|Njm Ӝ:㎏͛B`F`Êm G3` Z}S|y|b?oCePragLmR4Ir_77ݹ͜ 7146J`' td =8܆K. [~A#J&`MTrlpTfv?J8]%2vT\S-"%CY}= gՀ4R8Qs9 2WD;HBC@6"zrZg59?}5Whɲ<#ٽǞHYb^1wfž -DuTrNnbF=C 9'~3䠊ɀ4fGI3]Xmg;{= Bmpg#mW]{;*j"|2d%* F1- /Bgo&:3nslZZZ:QAAͷ;ҿ1gۋܤVa2u&{;|.^Ӌ~ڼdi&Ꚕ2j֨J۟W| )(pIrLzdy[!mN`Vq  +jI8 i^aǦ҇cdʡ}i窍*_:CAg7 (`PQ8N H&Cn\م9OvG~" "_N+>5[p:޳ fj7v_>\I' AO`'ҩPp <i8Q}-|=U>uc $ܳQm9~smM+Cyh={x0qÇfMlĵkJ\;Q8د˒=@ƓWBsLggV`Y`>OWrifVgm'0Z99Mh-s-WD4 3isp_rx;O^UxWSAs}apȻ;<5ijJ.{^KV«k*".UjfV ʰ> sZK2@IcMt^q Ϋ= #Dž c)Wq6fYsH_x 𑻸S'}.9.DpBD8=fM9 ! @i  tSC@*&h =TM0" 2MA@zH `Dd"P6A 0@K7=D"mA`n zCE  - A@AZ)! @i  tSC@*&h =TM0" 2MA@zH `Dd"P6A 0@K7=D"mA`n zCE  - A@AZ)! @i  tSC@*&h =TM0" 2MA@zH `Dd"P6A 0@K7=D"mA`n zCE  - A@AZ)! @i  tSC@*&h =TM0" 2MA@zH `Dd"P6A 0@K7=D"mA`n zCE  - A@AZ)! @i  tSC@*&h =TM0" 2MA@zH `Dd"P6A 0@K7=D"mA`n zCE _h8IENDB`ic09@PNG  IHDRx$iCCPICC Profile8UoT>oR? XGůUS[IJ*$:7鶪O{7@Hkk?<kktq݋m6nƶد-mR;`zv x#=\% oYRڱ#&?>ҹЪn_;j;$}*}+(}'}/LtY"$].9⦅%{_a݊]hk5'SN{<_ t jM{-4%TńtY۟R6#v\喊x:'HO3^&0::m,L%3:qVE t]~Iv6Wٯ) |ʸ2]G4(6w‹$"AEv m[D;Vh[}چN|3HS:KtxU'D;77;_"e?Yqxl+@IDATx\yo\9w&0gQH[lix[=4h %Rf&A htU]9ٷHxZLJdZѩ=90Mz؋^hE@D@D@,Z" " "`C6t YD@D@$D@D@D$l8Hh  Hp5dk" " " 5 " " 6$ `IאE@D@D@@k@D@D@lH@!րؐ ']C ! N," " Z" " "`C6t YD@D@$D@D@D$l8Hh  Hp5dk" " " 5 " " 6$ `IאE@D@D@@k@D@D@lH@!րؐ ']C ! N," " Z" " "`C6t YD@D@$D@D@D$l8Hh  Hp5dk" " " 5 " " 6$ `IאE@D@D@@k@D@D@lH@!րؐ ']C ! N," " Z" " "`C6t YD@D@$D@D@D$l8Hh  Hp5dk" " " 5 " " 6$ `IאE@D@D@@k@D@D@lH@!րؐ ']C ! N," " Z" " "`C6t YD@D@$D@D@D$l8Hh  Hp5dk" " " 5 " " 6$ `IאE@D@D@@k@D@D@lH@!րؐ ']C ! N," " Z" " "`C6t YD@D@$D@D@D$l8Hh  Hp5dk" " " 5 " " 6$ `IאE@D@D@@k@D@D@lH@!րؐ ']C ! N," " Z" " "`C6t YD@D@$D@D@D$l8Hh  Hp5dk" " " 5 " " 6$ `IאE@D@D@@k@D@D@lH@!րؐ ']C ! N," " Z" " "`C6t YD@D@$D@D@D$l8Hh  Hp5dk" " " 5 " " 6$ `IאE@D@D@@k@D@D@lH@!րؐ ']C ! N," " Z" " "`C6t YD@D@$D@D@D$l8Hh  Hp5dk" " " 5 " " 6$ `IאE@D@D@@k@D@D@lH@!րؐ ']C ! N," " Z" " "`C6t YD@D@$D@D@D$l8Hh  Hp5dk" " " 5 " " 6$ `IאE@D@D@@k@D@D@lH@!րؐ ']C ! N," " Z" " "`C6t YD@D@$D@D@D$l8Hh  Hp5dk" " " 5 " " 6$ `IאE@D@D@@k@D@D@lH@!րؐ ']C ! N," " Z" " "`C6t YD@D@$D@D@D$l8Hh  Hp5dk" " " 5 " " 6$ `IאE@D@D@@k@D@D@lH@!րؐ ']C ! N," " Z" " "`C6t YD@D@$D@D@D$l8Hh  Hp5dk" " " 5 " " 6$ `IאE@D@D@@k@D@D@lH@!րؐ ']C ! Ǭ!}c~[?a^._\$.Y=,C>}?ϸ.=Ո| wt?nZ4k0a8|ìUeYu^h4טϲ~U*SZo^$ OO~t"Wtk'7 fͲt.ׯs5[V5Qyw:aGͿ)XװxrWD'E@'E^{YvovO{AX[\Z}+Xq.w6x*K~inʭSkoK힞 ve^' 3gξ^KyC֭wx|ɉZq-QO8ysB3\zO^|?,%/{䏾ߏ|>|OE&$l2C2l1u ]{\U.} aJ5?m^L}0ԸJ!2]xڶ~eMg)V7|EWwmqۓ;/;ٕo.,,(F=ix~s||XWECD 󠻸LXla}e`nIXpMjiLpFV-WRw\/b|\>Z l\:X|y5իt8/+t{aIhhJ&~^r;{L?tGO<0$_uOPXq;Pփ17A@4&. w~3򪑑_+d`9X͟M͸ʵ')y<>Qv٣X;`VkxmΙ:_bW57{ܞҒ7B'ԁİKf]5 w!5PTrz*^MuFGS{gNBRҾvKԽ % ^v]FI@Q.K^zY< +uuܶ?֔)EӕW5!fCh}KacX.Ϝ; omy kn^wey\qv"O_Dy`2Fk:m&KtJJ,3 BXM5?cG1(9u ?xXWDG" #ӋEu#`YH d6߆Z[:1pZ0*΀ۙ2g-K:_j?%44Č2ۼ7%vh/ı B(6Z n9~_drKQcP˥jƌ7D{v_zZ?tߚŋie(Vg%&|FM HBx]Xzԃ,W:=]񳅬+XԜUG@xi<2h|-qϝڈ[G1Ԙ3iϙ"1|dڝ )@2=>x&_±r pv>dq畭hsJqƌ?^I͔gVk\yg7өz.eXc^\l|\:rx=kmF5ˍFf/-f1\a<gc?B?i1Q@K<9kD++$'Qta'ո6|Ha,4V|ܴ1-a*;$Hbfz t57a4vj2:O=B*/'`zwe^in߱k兯|OGrSP%#^mjm~,$,3q\vhHz͒ey =pm9̻aoсΫKeI,f+paTӌC=ӄ߿Ӆ[6˵n<75tlZHS-7!6bt?C'sYw_K^h(y棥jaR3r4$ T{^lz_V7 7tj0Mz͂a8^wc,^һeeҩ겧,j`ӻًYzht7W~YqT.v5x0MƧ? ?P^X*dpEFT7ڊ|7f.brbI4@+ |1q{jM 3պ +YP[̤W77Wd)w{]Wv,4]j9p͞nU$!\^hx}vZn b})_|DT:3<2+0 yU8:.ftPeRD++p 0ྈtxlpj =.\Hh, w:}y|jI݂WKgkW~3/@^ w/P"yx,ݢ[ 0`=D@@-ϬgwZ_#"r\;b;K5ۉVt&cxo11];s,؎m=8J ۅt.'`XHɩ$f1306M2p)\"^-|nObU^"McwzW t%cQ)X jhl!Ԉލe46>/ 2=6xMqݕi8h@f07=D@@o \]F*[;3W\YnU=L><[h4Mk5`*dz*fh M>E77KrqP 8q,7{~ S\@V"`i| LLZ}+n2湃_dҘOZD HOpbև`.+X=eke^GlFx͋-CyWчLcϣ3[qԪVc۵g 7^{|[epƷb$$t#ؔw4b0\Xn ]uK!ҰQ; 9W溮0ض {\p`5</ȣX2^`yڍgpln[wl[0|Ax&!T%چ +,@s~ H`fY4V1XJ$\b"C?Ʒ!ubЉ,:} c܆Z18+p/2#`{wp$&[=[؁ ?g D&rb/^(^}k1zٹ'gb$e>Ҿ'S(58Sjg}-ƭh ya44#22J6 3ֆ~?=.a~~N4Q;#hzo7sy&H-0J\eT5WFq&3q`b9^V,Qc Ҡa .?nĉs /=sUp3x *ޕog?wx'>:Ƴ&g茍 hȈ=]mߠf0D1-p0n]B|f܎:YxGe/r/}ftưkMj/ǿ?//^Kim)" (/EVVw%4iSUgȱc:ۢW#xv y`0CTsiz73dg&rMH,f>GC>ȍ|85a/.fj@{i 0YW wNpNYppݝH9٭B`aGN0Bowc?مv|cӈyf]nmo{[9 2})" H@<6z 5C׶ͅ؛2+[n@w]7ob ~D,dsٹ)ԂQttu@cc>.WA!AL KM8q]J3|X`.SB)J<L7O⧺XE0au3s მ&">,#.\Eber KI,׋ hd%NO=j\8 C ?fƍ3fP5{Ͽ{׆֯LYѳE@G>sLD;0(^Ix3ߙvvmz˪uw\Sxe|9vchZDٙ:iBw% N,"lvnlܺkbee^.˪ˋXucb:$]7~Y "wv 0J: ^̞:)Ǧ@(`[>٧LWq˶%&{Yε@On] f]<0wz=q ZPI/!CQQa l{syپ Tōʳpń2rŚngq3gbfeN|XshjjWY؜<6_Ge?M^hJފDG1~ o7z{B|V4utGg^j `KLyoCs455hYC w]Q6 b@ -}ni ,^58*|/\Ari|K(f>ͻY7D_GׄOcEXJ8ǣ%^3~bV=Y,\K;(W]$ò?Ow@b.p4@OBqOo-p5}Yu>x ?"c cȱ m,DIxA8R'хoc54IeUvWej Tjv*@E^u HW{rfr1wTͿMtS [U:؁Nmv+ -gyr%\6 /'bMЂ΢%5{;܋> Ui a֎[?{W;Eu[-Y|  f?g,DV<}旧`\9e;(ī8̪>_m$F|xSxnUpp]r VcGxgj! *c<<ھP#7܆ނ/)_K#ÀbW:0k7P Ϋѳ0Se}WDDGN\~ ':vaA{E{qKSS g3~FAVƁe|[_gi-@1 g/bzlEkF(|g,<ݏ?@bp><o?s#]-" kw0jֻ-C]v|}g> h]g1 4xsįlwe  W*02Y$=?ucùy}1[<<&V!oJ_oazEV r^eD~|!}y >6q~M ]toӛZY}\y1pך~z< ߹OQ$|"ֶp"ʼnGN#<{ BW2R{V̌[Q;J ~ ߂S [Aٽ0[0e^k%_?Al/_ Ozqq dYfuf'@Ex^{ 0`Sa2,` ,P@UVKP!sm};؍7x[h3{ǟyt\^Q+s߻\~(; zZ'elL1=!zvBQF[ދSF>g<f缮\՘7yoy,0=ăv 4g˸o~y0ޅ g"I jC"?AQ. ?\L$jX$e ؛;ا8E,N8 4ko=EˋAQPF>Y@P(f@?\ArK689z~j-~j3`WFGr;$~ R/ٵ]ssnX=)Ui)C?<~iw &<]oV!+_rswPi9< X!=oq"^!Ȃ>l~+, ̎(M|0劉6WhYw*S{?T!H>C\oẮ"?U/K~>c )Ll ?K +&G'џ,,hdǪcbq")>fPDa,T,0@)vQzXDc5Ƴ{2ǟwό p CX凼w"/ HKN^ G,ZL8&ߴ\YlapWyX{Ye+.g_*ơqu{ +-ʝr8;t/3wꔗ̰P'@+?U|XF],`ö8ZE8NmZM,8|ai k5! "ø@*АCtl&3 iZLJqW_Nt#P{І-77߳gPzdb*+4/0pr^~ݿq9z2 4L;8cTx|sW"z'ܻD'"pokqcuaլ`=GH@@@^n^s)~:*wiFW ob&d@@Ģx^O'UC;kemxįrpB1O@e Q̂?1'yz w>ҝN7uLX b*Hz9. ܽZlaS2xr)lZ}-W]!Bu &b}s2nf/s|ox9܅c,(2(fsnxlh'G/2>&~'O}$C oی*DϧQeR= F17KU7bbͭl0l4w VJWG6Ati'>x kZO/ νF#`ſNgn[KFkf+r$4Qܹy,M`rrmՃd2/o`t雵 ks`s9A9ւH''OW1OP2]H/GhTHL{>QRz7ӋUVł|4%BdSD,0gpӃv<[ ZteWb3ENy\ ``#zX` صqzn|5˘Ggg5~z:6\ܷ e`{ g) !ut f ef\>0Kr9s["XYZ~eڌ" e-/]:J,:Tqz-Bb[zfҹ a=?EWyF_~,PQOgg{e_;76a0~ER I8 R?W`}j0z &qmV 13v#sۏu/`]vVL+?EcBsK,Ȳ ,7LU^ECtבo#fcp G3\xi6i@&D^0C!dGP0 kjc8xHzVYN}i-1t!kߋ4x~jAx{g12ZFճ lJf<أ>kG k֬l}ˣw?e"`+n G$oxGәI*z\k6)lD1zC4鋬{v4fKab܀/SUܻ|oTF1_yUDxLCw&z'Xbq,N>?Xu;; a4>$Xb?\ȻZ^=ƌ(j|~) q} 7p3aMZ{=?Q]nLG,|!\shۏ;9 a#ጹ\yB mσK㈻V`LFBzY`x+_5V[c䞾_>qǙn89v>S=Go\$ӫ,o'nV\3z"MwEB+ /HԄ(kmHnùxN,?kG (g6!k`glx|9ޅ7cVw(S4,T7e1s@%c(Ow܎3F=9c`"ë27mnݲ8sa3sgWVfP8O9{׀.%o*o`8/wWm=и}Ʀo=n!6a$?װE k32nvCLKSa*X6= I(:ܷ4> ssLLc$">R&P ;;ބM?+̫ySrY1XQc~nrZ. #؉X,ʠ@h`=jr?Y)fyR# {ٓFVݜUڗ^2smث1l Ѐ0+<˻Al?øiN5J 'KөP?V߀({Na%= >H Q1b陯c$qb}{ 'd?0:z/B` /ؼqBW˚e=}zZhWP.G|ȨfynnKkikn[i,ǯr цf]9Ÿ<6ba,S,8+OWMcW ;P$Jh_M?ۆډ=X!^<ׁ)?= UX[`|%N*M[ݛ+{Z+EYN `ʠkJlm~=cWB56)ZQe`OqQ>f} ΢s XA*Ҍ#H!,AaQ@m䇢D4ccZ;kV, 0kXiT)e"(h8(e#2IR.T8p;yP=5\H6 ot?2jJiBbY4:FBXi:V"6nCCЍ+G1 : ˵c< siۻ0yd>w֙ 6qlc s~=5"2/|/"} ~ஃDe@$ fTXЖAÓfKbՏs }?ue=f"q ejk }x.lΝG@gbfxTXJ`GkF+ÍdpG@X,ҽnD]L yx&YXclp{A}lSv"Yjc_ ̡@IDATsN/Ƴ~ҧY`'@;jweᘤ*ᖮ4p* G[?%.(HRt??fKpn$?6| V-0Ujr<`8`Z s.昻n!?kmpetGoFzn:yc W`A*Ī7^{;S7EK8%f]8܃+жƖ++J&ȃ wເ[hF (U@$ڲnm|]V! "]63rլ4ar&f4Gs ,CxE=h@gͳ^,cMԃ[81L-u#WqX[CP1TŸ ť q^9~8Ņmy߈y?Ǡ$м81 ̱|U*xX#7ps͌8w/4= s3= U'zgx%OVHM@^c.NoB>9Zwȏrd8h8Q:(5o`]eoUg(śQ mk TXo07jYO /4m1 0%8s<? quNs}\ss( w qאK(< 9Е3ϳt {l9 ~qtuvL(S8 hE7EqEcȇ7“E{5xvۑhAQ^Z4DsXN2+ (1pHHH ^=M21``~$\Ɔ`kk0ΡJ[zz 4t줟}v[h@82Q҇bSw4ϠHpsv ' ,(`q!0u.9h#xh܅mc@ w ߆I};0>%ncO3]O֛It2?]4s''q*k^lٲLыc>`VD/MZ9g~!.ojr2k>eFlH@!&Ҩ ~ʷ ./@&l[c$Le"_(c}<#sK H0/]hqgۮ,\ cajFXx٤(Z @ Hpcj>߻NG}#JAnjls5yX9V b+fJ3-`{K\p[W :u1n0!BS,$|Q8ٮPh"Sx?#2j[a$`})z>l]݀_8r5"Iav!>y^8=|iv##͸C ޣ*F&]<ۯb& ,cKTC'̓D]w VS,-iܫhl>"[NOOt0e_;-o-P@0>Aq?0<|;x(hΆFOPgmtS> <ֽKtӐtX4(ǣj~d ݿeK(xYǪOppUנ/yTbxa[1#L}l|N)d~!8;fae,dnKINRhaQezVXppmʬ#N&˪yrcZ"Lk>Yk![Bv0b ssgCQ[{Xߖz ˃P{7l@[s+xq#+~'yI?} "ܟ%Y! k^b<`jj/bڵذ~=3`|^l޺?>Zv1hK^+0WelLH@s&'Vh+gPbzދ\8; [ЙBȸfKP0"z ,:py,,+)Yh^EzB̓X6&G1ل#n*/rht59LX'8z|~}+ENs0R=_HH5ڻ踏N $;E -*V;'|i󒻔%K=;vΎH-5˔e lA^%#ʲ~@` v377ZfyjT`ʿ gd9qorh{:Ɲqr Ԧ<. J{{tv-0 i;[뮔wxXN,{AQZW{ ؜J%dG1>66.4.QǕ\@ݎ2]#ڗÅD8CuWڍ`p&oQ$جy{!G"Ndn4,TfD(ߏ >(nEK$ ՍjA5P'X֨E%MXTؓBlDC҄z;Ϊ"6 :e@}Oߓ\+6'_#PhL sV'ߊe\NNsr gF_Z[I8܈KweIGZ$_8Y#+XKO~FǠ2.6߯Rۘs'_o4I n5,W$a%@DC2⨒lF@_`35bv *}~$=In?sH]併巏kw54YL١Yl.\ x0YPC]X,SwzY-pUc#[šl6[k]8B^trZv$ D'%Rndy2=S%at7 Q/zi F*]t-)y_>*g.yȩl[nAӕizγn;Ȥw"s/B-f&x&%k|> ;؅>){i/ka6"PfŇDG*b4Wȸ~oGKn_},,YS3&?ZI4сWAG4F@dGt$VZ/e!\4ʝvwYds27F>jV׷noM؞\gq**>@>"P?^@"X| \am3fcz| m$A0+%s>WK^\CZf&ĕɷdwODPjponMȋ^S_ pzAi 1PO}݇xu lL#X_w\ ף%DB8'G|&ֆeEwX.TVni4WRiw?[9:8!a5R _8cerZp01+LT:|5+'T j~5LTn&YvmeoZfa YP>݃m"Y9]%g%~VRk|HUde 6w{-(r ^NS`^`~ _KR7qlSS+@,}tBҸM/Z!l8kBW)Lx`FI1uXYZ K!: EKp 5Y]ur|';GG_ERR/Z׌v:^ns%S qoE㴔s2;Kpak[/lĥ<ȶUq:Pݻ;Pw/]s"pa:>,S'FBLs 0s*3'NY8<nb?GfRRՅa)GaV[{QwAd߅ )kO P% ^B'(RUeչEbո ձ;,$@'wz;#էH~UP܃S\VF\V6izWXA\72HWU^-/,,An Kٸr՚Yta\{:{_ڽR}nw%k`1ӎ|A>vDa9ImISO])G/D~457_8V#V%dS+K:q_@ #|bNU¦Dya Ty 5QW)19,A`IE@vBrkii #`Z);|RMǢ,_MA h 4)p9 bj}._re+;Lc[g#9-9 A.^ƻ% [ƯK7Y[+lǍ<(c=;d;GFrk r)cm8V~uKSKp՚ڬvЅBGl6\d>K%GfVB/Sg?囻7+V˯1'=,)w祐ƦӸ5pQ^5|j6BON^CWUnP#Pji%ĴhZ86,W9**DwrZNoS"HӉA`;꺩νz9OYT^E@ o^(pA%P wXV@.;ySL.I&+,ܚgG]N+B ػEJCCG௒TpJtK8_9I1-3}r)yh:jtm|I>;|^T}tLMpY;Ђ$?-E)rr<$ŀ7J*6{a4ゞaCbF%9 ͸7{P~_o?Jf@':i^O|S 0G?X!M;w~|uxo8ptlڼuV GF _={KU86[Z̓M򾿨/>/| 6b!oq 8=Sь=o;?*g3.kdj<35=6<O䟭`QG'^" D*s\՛}.77wlaYxw-2fmہk^*'g@tfd9DfSv,ʁj9JK9ˎ7Idz1rOJNJ5:t@~ί$bSgD]1m<k۱9q 7N,[{7I+" 7pnFE{RB,0S,M"v92P.'r*|)<2t7kj/}+/^w̃㨛mcs[ on#6|b۔ܺU c HvEbwJ qՇE&< JKjY)|xKV=3'oOô,µĭf&"7@͏U66@g;+WKӳcrs $0jiDo^ž#gl .,rw܉#|Ͳk׮_X8Tǯ>qD0}, \v907@4'x'); Kω&)3?m{2V.+b97p,S ^jg( ʣD8bO܂|w3Ƚ}\oK{o.w+ѿ cQWgm^>-k/!K2,F;&p_N6Kٍ+K.LA$JJ9CyyB rqyb`ΗξC~+mM;+oV~YcV~a<&e0^+|fGc2c>R@Ngz4%SJ8!ٶm>Ca5:|jc I-]"睵"}8+DddM[(~o%Ct*b,B~I;25+s#ORB)x'"/fȫx0R .')pytfز/lYFqO}b.;7 *~s EǮ) vIdt,z"|t8 ݵI"!/v\-XF @^R Hu>zt!O[s|d㻲(z%|h!@}M6 A1Zz+I'$ٺ\%Ab @(b_]?_|<*A[:"r%}#fFA9^Zj\wjd!@"$Jedg䱃b{5c?#R1K'^<7-jNPBR`p>EVʖ&7dcǎ؁nZcϠG+mnO;$ðԊF$OaG q/Fe\|Lz.#*_RwI3n t(FXW|Y2,BiE }.l!qPQ_+)0p#^K6u'H:ٸjgg>Lg {8w~tEOц%SQ\C;A*y{#O=T*_u:> PIjHb|B2w˃/(:j%t N%O(#oVo9|&nL-r<8?)زP^ߡTVhn~~oF+bz6|tcr2n7vTW*CKr:{u!]2J_DӃ2Iʶ ~XLv@>xXBת~Zb~%sq`AFj[/.ӋZz9Ӗ|q)K.t,Ux'-G/!\㫒 ᒞBm0 pC" u{_ 1D"$?&32 UW"UYC#'R6,p ` nȴ2鏦dddv)lܢ 6ZbE%PԞ>(@ X+ %BoE['*'kwÚ5k5o[[mbI܅.j h}Շ%_Ekq;nK[Ce. {YgM=- ixYZٹ⼬'S pt7#{J\&?[ekV\UN8.'M',_Nyiܙ:}X'(WO媎tJuR" ߰A1Ǧƒȓk/(};2Oˎ=X~>-:$wP /]eWᶿIC4lS&VaGD$"'1}mѹl57s˚de+8w"G 8Oya_u=T( ^و?A g*P:} ]Դ={h={=~ki꥿ֿjyvUm!zEi3Xbnn[L|yfvS m–9-Dgщp-GJ_^v|dg'e}p䑊-\+q<0.]W >/꒎%Ke ۧ/e >jJb=Tmh ˊkwHˣ@v\{l-ÉՃ=3>ؾ ;nNwr=ylW=}z?=] Qj>(@W`F \XdIewVKf~ـOWCT8.%tK\&񷞑owMϮyp~C'7n^-X[esŚ 8;L:y46-Y{FېdABˤC#֔2 Dܲ$ȸhIi^V"}_*$)?8q`CZYc21yR" 5Q'!w?\fE0(Һtx[v9KPzoLs:Ӷ;f}u܉;l{|h띞-U?1(@/M?އߥk%,VTΠ|6|s{hs{ҍ3kmWyܸ$diݜȔ,a{}-~oSc܈[qr|~Lk#۞%Ml;gA7Fd{MK=ܭmջUYy},uMAïA ЈS 2Y[/tI wS:[ Py.C\|^[`wa9?}Iu{adO߿<1KRybj՚jJ+.. .'^y0YW!*:@jVT%d~PKS;' T;^=v]}} 褯-a.)>FǝoYO?YHP.q`r9_`wmETWcZ^U#h\z$d I9;RiL%>D#yy-S~Cc -pjǿ'Qz,w}e/nR:uJ33|>PXryV JK 3pf$e5_I 0? ArZpN]\S.ՂË L<7/輵fn|Ou<#\6v:v֧B$͞vȲZUĥA{ĥ^fcMjBo~iVGK/T" uMɖiɞ,_)o/IQ%A`#.I8I3ȇ?T Ψq C-+ʲ 49ş$gb_k"Й- __尒t&3GƧ﩯 [OS5|Onv͊_cbH ބ22?\$~_:;:'=,by^ZifN%^ ;w@A*YBU7YSFepŎ#_\}~M J|wCa;Fʘ!U UKmS+EC4<rwK׵ͅt{zPozкUvWGH8ϒTc|^鍲s[PC찷3I-RDZ~ޛʯX^*gըCc\,TWYyψg<._oO P`F(5(ЗHY<+ j+fz0'yzh_NNߖ-muW\ws&_F]=_;{>ap8E>ܱ&)mMin⌴<$` Xl]B+oAGaI#J@:Vظz}ѿz H* P `Q( \q.䗣/ W. q붭qG?Sw5kE~UH]5#3V2>yV+永2n!6Qůr#-pⲣy,Po7 (. _|ʒTgy1.ONMjnUa'};'k5r`7N)3fi/%pK"Sٌ5C_D|Po%o{k+`@%FX9U`Y'N}vx֛>aӶ;僧{`-ks)A?zv?fk!MsC ߤϋʱAuO*oBj桒T|ajxmF $ ~% wDĞD}'?U+{O-;ۼy˒:gF>iD 61c :~֯R";|K=^c~v޽gϜ95E~jzMwOI:(T.#g"ٯ}K^ao[94k7l̷܁nk1l;q aX85q?+Z:<>ߝL&CCC!ƛTi>(@@#-P@ }(@b=)fѺ[U^d7]tj˾w5Wl/o ]. Xx/H3f6k0(-Xxsv Do[A 58h P*l3~C(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@!&IDAT*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@*Rt(@Ȭ"(@ P@`L P0@~h׽IENDB`icnV Cconnectome-workbench-1.4.2/icons/mac/wb_view.icns000066400000000000000000001311551360521144700220340ustar00rootroot00000000000000icnsmTOC (il32 l8mkit32et8mk@il32  ˠŬh 61 I/ng l l/MNptcѡ-h #KxgʪȴHi4?}v>oe]j!e4q^U=̠tL'f~Ha^Y͋zn$rh jy]۝QqvĴ$eeR]tyyaFe޵TVRta^}iΓȱqT"i4Bj+עᢙO~U:_-zбⵈfA[YnxƯH701qԮ~i90ZD~.Q2aDΰpJTX/V2ilcMUT`8y}p7RYD tȀjeUTRTtϨc4 Jg/r6qIҖQe9GŬ\(h 5y18 մsya ˣe8yo/Is~dXI7EWrS =͎ĊILW6|x ˠĭh 'I( IAld l rkWtLvmo:h '6epRdwGi (M\sc5mJy?!fTzGveƷ 'g ecjNtdc|ƅ#k6t{r{z]Qjt#fk`eratBMgg1[V_yZY~Yps9pHdy7)pkiOW5tވKxiGOudXMz8(Rݢׅōcs8dmD[>OL:/0qa}mZR`|RMBG_ss,fʔh  dD C>{w(&{g!h #KK~?w/|ڑ 'g>ꋝHK5]e`sƒ !h'xŌ)B[efpTfPv#e0i͕^o7IX3o{'ScZ9i dSXJXOxl9]&T8./S[LCB-u$s:S?aĹ^1Ik&M=I|ib60MU0HI  &=-g|HI]U=LE2P?R{>?4RLsǿʳ4  &A ;]4OM?M#.z>WJVxmƵ`dt| &A 1;Qy8 GM4 |5/S^rͬsWp͖Ϻ &C(+8*:Kmq7ROIE"de>Ucp{l|ᶹp ֒&C4+1GEgG]cSIJD2ðtj}}΃rtpoY(e5s9&I67$ȥf&GE:FS7ΗnK[IJGF!Dplyo{ʰmwTW|̲*&Gje76 RL[ռ]WL=>BDE[m)Lqjz*slBI˭]_I/4U=&Nem+~\@ڱCPqjMQXm4^Xy%ֿ̯/%2&R d>?JSþĽƶOGS^wyKZb{)แw追ů~5X>&VY#FM=2QŻƱؠAOUj}\WZk8칀hp˞w!)׺;a& 򄧹+evtۍŞx\S>e&dtƴ*'bqоԛӿGV\lHiZl{BSmetײwdSd@Af&=ʷPS[ Wv}ξoLYd~|LmbpE[ckrkpyƲbMwϿ/&fһZ .}y›OZ`pZPqmzԂJc\adgnuyz}Ǻʭ|dٛd&3ۏ^ mlwsX[_nVMtv[O[Z`belqqryȴڣw&& LmWyr{sro剁<׸iTjk~JKtτBRX[_abhllrǼSp&2gyT3Lgq]D˙wwlMrr(Nu֘`FGWZ]\\chku섒äp&g}:K&$:t_Wc}CWntCovf1`rܤ`|]CMQWX[agnubop&uZ]>ÀxkDUrTJlHfxUd_dB?DR__eiryʉhֻ"p&HɺI~[Gt~xHErCpᆴųVZwxZOiwXZ0.8F\h}notϤZjp'ػ0> ruqxR6wry~ϕߢj_g~ӓozL~A;\nK3uvߴpNp' t"tn/ h_~xW5k3 mVm于uoԭML;YQ;tʵ΀LzFp& WztJPׯ?kzU6gЩ"NjUlױ~῝wekPTwܲ}gPDPrkؚNX^o$Ff$W`nwyxøL~R7d\}s~FS]ONuնƲl`{ޢ|zo񟐩]Pe>g2p%|opt~S 0qS4bʮG xBG[KCIlǡýiGǬpEl͑Cw^HPp)*}~z$bsR5YtzK6HC@-sR=D-EA>86Kqʸ\«Ͷych~uyKpClĵ&pQFCiQ6J<7*&FkȲYʽ|Ͱ¿u)p 1aȿKaXDIMn/-44+"&7eڼƳ`رǿwsv˛Tp,GW{µzY) OZfjWbc#/-))-RE¼f˵Ͼȩul{nоzp)j7d}Ơ "fVg͟[U>37DC62LuI}mɱλkmܳAJ`b*p,Ea\s \S +k[OqMUw+49GMMH:17F[wuϿכʯtfv+6|U_ȭAo>\w΂;`,h\Y[uk_`lew -0517;;9410&6ՓdῼþZRw߬X:ќ5p@pzʵzPss3jjmbMNUxaOG[Z: 3MH>63:@A=73/1-<٢ޖvY˾uK`dEܧ3pDTnͶI8hZm}wc\P=A?HuueD31AĴsHiTz̯@qt5Vtdt]#Dkajվx@Leb[UKEBI\w8=CHMOMIEFGKKByъ`F68B8z;PY݂\ôOAzBAJzg. [;]^UNJHCDL[zi ?KTVRPO,SPyĭgEACABF=Ơ`P}i^Y(t\Css= !ו AW[QKCGB53XqDk9EPZ_[WZYaU?NLMMLGHJJEB}ӫrKvr:}Ի(~Yopa^觀Jmĝ`ի(WETUKKLL ?W^n dYY[_cadkdbRRSUSQMKOPLKBb۴SiZ/m\Cq^KᚈP2"wI n;TOMNSH#0I^dktwўiZgiquztjdXSTVXUOOTWVNP:w་\gh"KEvޕ]%VrW g5RLRRXbglmmxw˴ƎVoq|sg^\\[WSU\^^VS )OLRU[_iTnR]Tuwsiec_\Z^eeaXZ9t߿j̎څ/FϺ̟pMRJ 2IRVW\]n%q' ^Zvskgb_bjmi^][<ߵqV{M+(BǦɫxi:lPkVBSYAcs {P@7ڋb~sjc`eone[fLaz j"&4etȧԸX TddW"KQORYo`9vgxld`cjh[\TxFt#'{Nb 4!%~;/˵N&g2<\q\'h=\G9EJ>/ *V9|Ķp֢  n"  Ơ0KҴZfo|bB|oCGdijcd[=&N#%Gæ#=eix{` 60Jia*рxǦS>ftwIKiEG*$'&'T&%%'*&%!P-^nQlZNrs_jj~ߋ[Ǚ{]FqwdWhY<" ')'&%(%L  Lnahowům@ADqnϹVs}̑lLIF& L3ESatZ 57wFg|{ !'<`|jSF?>;)  SioxucN;7<=,   CUfg]WUR;   QK< ۗ  G*$'&'&)'!-^P9$RklIYxY- &%+\um=8beM,,SUKVwlUðɲH &=*n[q:8__WA?NZhE8Q?S{gS?OSyWw~; &A 7ef2LYgH@KH_bFRLVwͷabxs|EvXTP9є\X*&A 5;X^݆4S`MFLCICe>GP_q˷ƮrUYCBTmf}a¬Og3 &A'3?G=:PLY?[WOHGACoo^ap{Y}{=CdWUgbTwLq\=֒&C38-3FSMJFo֦>]aTIIF9T~³sj}|qN^EUmRpOkwj8AKeg|t\jd9&G;KH0<\O;/\rDdULEHB6a{l~wuuJ^jYYePOtYeg`fȦg&G /?Q:V3D[K/]ӺYNZHHED:OmÑOtq|̼WFlYX/Dl[dx̮~)&L VA::1]K8l3UҟPTMADHDHZmoybnk}ĚBLeV;>\xh`~n^b;&N g>12D`&Ckv;J867BGN]sX[\dmTWI>1Pf`mqUHs}]vP{M &M muA:Vc-qpf_phKT:?IQbvysVXczMaMM~~NfIнva\wc_&OccCPd7EnBi~·ǘ@D=ÿ^Rgùj:OPcp`D\a^J[uݩhijq_o@&T,ugxv^I4-Hż`˘6DLZcsiSYXlipyYeq~ȤmNsӷ?&V qttv`71qűϝHIR[uyDbMZ[^yOʣfBYm~}Ѵ^F˜=&XSHe}TX˿eS[DDPUdLpq@bYh|eW~ǽV6jq}SEŝzYPXTƽ>&YPdoyĵxkfoѿ`q{dk^[ڌ8MUXy^k]Kh\hmMppCRipXPv}ײzhYjjab$d&!c]blY~v}پ|fyTdiMn>XUfgɷDYjcpnfElbE\cecjpyǰ|M|eceze&MM_>kcZUn~߾~shl:hݢ{K\[zqyzmSPrmweψAO`^bdgnuyz}ȗd}ӑe&4[pDw{wb^S|wvs~xdF=QG_]lTOuwھTBRY]`belqqryȦxʻjmYvp& PhR_kZs^xx~{tHoi{lsg޴^:`doyNFuq;TU\_abhllrD_zZgoDǾRp&4P;vRo[Zxe}hobctWa[{b|`]GTosOcx4Mupޗ5CNUY]\]cgkvyaճPh˿#f&nQcDeO`wP_WaҋupRqbl^hYoKLKXApuwȌi:\syaA>:GMQWX[`gkwo[ֆJg_աWp&;dFak_{kDSxϗvGbyhecڅDrP\7lsyՍHKh}jy2MI=;>DR__flowsSNĿQV`-p&.^`}X}h4kuxHDuÅ]rEmvkZҝPg{[folB_qyZ߫Tiwa/Gm^.+/6F[ekpx{^M{_jݟcEo`Vp'ԬL}THIuq~xR6wakrQbVŗ`M_Gu}Ek]jypcҐpz`R8ERG5<[uI:MYfizv[֙q۴oSn`o"p'PBzoSDw_}xW4ld_slDDă_RQL[Sf亏up|]ۚ]̮|kg/HA>@WwD):NW\`e\Е`|STvV0p&ş=e~zqYb٬MrxV4hϼqgs_JذiRٙ_ƙHs)DC>OsxQn@++BIEJ_f]kOUaoU p%*SЍ3X`oyvwĵ?bxU4fχeezhBlBWdPJFԹefū^gת̚SwR5EB:Cr8dVC@BpE`~ZN_Aj1p'L}d`|ooui@]nU3cȼ{`gUzCEXJDNl¯q`bŒھzBFTKDHnUlqloCPsx5Z͑@y[EQp*.Ox~{WS]kV3ZQQij\/LA@9MpYyRth|?G[ISSuĐhQRe.KwfbjZ&p*bkõsSqTZmU2*%%98G\wcUɲgħncرiQOrfwl[i^/9YbVPDo@XzmAI4c̘PXUe>n_KNc`V`jmmbL987;|VSl@C-1Yɼ~ndeS\waCO_`X\jttmcKEKAlf90,1@LJC=52574-('+J΀H݅^VfmH|ij}527;;9410&6ӘpnNLRVM9zWwʻt\QwkJ53;@A=73/1-<ԬYpHv^XEGn|ȪuK`oH8Nyۨ2oGFQFi\:xZcǽJILhnADH3K`O=A@Ew~LۆWucB+55mȳsHhboY}˯@qpK?Cnquy۽KaY;qihqeiտ}6=ha\UKEBI\x36:CHMOMIEFGKKD@H֙CmgE8X[PYw]aôOqyU6Jz[YKn6]w\]9^^UNJHCDKZzmX(=KTVRPONQPUSJM`a=DF@DABCE~Ơ`P{HY*wW,tLetU|=QvҩaAW[QKCIE>?Xqo9EPZ_[WY[\bTKRGDFKIMLGHJKCFӫqMrqepXTXor>BMen_HJpkƬƅүiSRETUKKML?;8HU_n]tbYX[^eafgnaXZYSRTUSQMKOPNIAbܴTfqhvkSX[Eo_/ZWdm[ODlpd\ldWjUFkNzSD;TPLOQPKKR^ckuОjXfjpvuvreYSUVXUOOTXVOP:wཊ]eRbo{D[N2oN-^{iatjZDkxxb\nttnXygYsbWHf6QMRSW`egloww˶œXnr|{rg_\][WSU\^^US=ckbV]WYdDUo;'{í~k@hU{hHotXjl|r[XWAi{WQ)OLRU\aidu[]ɇNJWuwsiec_\Z^eeaXZ9so?Qp[bmr>p5%sлnFVoWi`as}~mR[ehQ2IQVX[_jWT^drKIұu[vskgb_bjmi^][=ݶuJ^yYmp{g"p.#jȤ{tѨxiY{blNZsUBSZYXdthwkvZztZϊUމd}sjc`eoneZfL~ˏ{MRUX]@hup'$n}ɦѸ`Ikzv{k\de߀Q}POORYon]eEOyVђlfxld`cjhZ[TwòO:mzETZSϠ7RXp$qG8ʷaI\jlkthxX\mh?gvFNOOLH6BI^`L[]LgZsm{lc]_`ZPSmqbdkQj2Ev:p%`W=8˱zN_uddZthW]nRєWYhm^a}q8DXYLDGLNP}~xeq~ymb\ZWQJey]Hvȼd8=cp';7չYcgPU[u\Xeg^ckGgOʫx_MGPXp|oQQ|y~tl`[XORRTYböS@;>p&/o̹xpXE1_tfXhpw`VuX۶kuơz^^krwvTRM{kwd_ZSLWZiSHWºnL<1 p&IbdeglpzzeQD>DB0 *V9}·q׬k|auLBGPT\QOďpz_nѷA-OT,Okwb@HckceUOA&L%?cǥzȿSLGMfjw{nA8C?Wsȇ\d|3M{R+CL:!H_W,G*$'&'V&%%(*'#)T\fm]Xrjg}[McƞJMo^A89:Ob\;""&)'&'&%(%L29Zkbhpwȴilvqʽ\l[spdXWS]NDB!% L3ES^uֈlsmt]Pwg|&.CZSA1#!%$ 4 3PliMecXogwȼu;LPeio~ 7'(')+7:.8[NbŶ{lZShLz  *!;::AHfmJǻY>Kmw}ν. +5RH=EMPijOW|x||ʴ? *6icB.YͽyvK\v}S #VvE,jʶ?qY %)hr[;ST #UsJ5 !aw[Ƿ~[   0[Rqó|somkh\> !(;aG}{iTF?>;)   5RrvvbO<7<=,   9[gf_RRS;   *5+ ۗ G*$'&'%& )'/EZ][7%(&&(%!0HOQI3#&*)($%&'(&'#-& A~}WDX2 /UgjUX`N% ***lgFaR9$Sjm{|avT$ &%*bo}}>]aM+.RVIYricg9 '/(`' KhwSOF#,NoIMDbNHLpu[r{$Zw-K;&!{ǐ4֒& 2VGSSG=30\]VJFP~Ĺtj{|O)*4g}zt:&EJxEAXJ-FcVKHE^oúw{xxQq&-Jmpȧj&G %Ilx^0&SYIGCGmdg֓ntzA",  Em}̫w&&L %>AgyG*VMBGJIQYoxknzդog|8&P +2S]%#K#-CFM^pZfjD%#(]~Jøb|Q &N 7Pa, =jM!7'?JRbujUb~uLO|q(¶vӒ_&O'Vd:!&OeiսȌ$@IWe|˝RZkړp~6| ǿ⧙t &Q*uԻe@1H̴n`RӾ~&JK[mYdP^tȰRAB6̾+8ĸL,SNdmQOrlx:gS^_ccgnuyz}͇FҎe&53`ٟ|q{2 !@b^m\UOwwݹ1:UX]`belqqryʙVȺ}JEDS__flmur( N`;2p&y}ۯtxHCxg"oՕ/D\:aol jdyB!(06F[dft{}C  Df%"Rp& vsrxP9o{%" sǖZ!3k\kxL  ;˒oz6!#1;[vH;B-R~s/ +ٴpS$`+p&}w`{xV5l@ " ^~c*HE幏up{F&˰R&$>CVu@$# .DG1zVCY56p& {yyqzݧmuY1kmB04~ObAU8װTƘ95LsX+i3$211.]? IOUceTp& "MUboynuðm[0kֆg AXfQH6ԹP!ש ,+"/~GPC.s'uYN[Am2p' 7)W|nozpV1e堎d=DFWJDOlR 7ܽ¿T H;J. V_Zy4WΏ?zZDQ p*/N{ϧmV4YXs"[].M??9Mqņ5[3H# ^ 3Pc#@wf`k[+p+fuIij֩kV)ĸiD/b¼qZE"2"y]s48DB>B=CuNVرڃ'hnlˬc  @3o7`__ADG͔{b\U? *UL#/ }S0׫; )sfwןW)-GoBV{a!Qˏqy`bS`ghndF|Wfd6/=JQJB:4+*.:FSfj RHqXjaݘa,*sbPoLKO$GʺҜl_ra`XZkuulf=e’w_bP%4?LJC=52574-('+J́6}h ,rUgӁW'"8.<]{~Z: 3MI>33;?A=73/2-<ӯv#hN:4F&>ɪuK`PA+Xۨ2oH?'bG |C=ƿNtd(DaN<<"P_PE>Qo༡vD<@A;1;BEEA=9484HĬ@konI('ŲXN{ʧH8[ի7oWL$u>({joӇPnzH:9*ywD"?d\VH@EXwοiC,3;@HJIDA>=A@Dzm'ubA*1<$ɳsHi&1`{˯@omn40slq{߰4X]΅yfl18ia\UKEBI]xÄ06DGMOMIEFGLJE,biD9>>@IPYI>s´OHv{9H{dwmM͗]9^^UNKHDCJYz?:LSVRPONQOWJ#8F@D@CAGtƠ`Pyt UXqxc#tv{HAW[QKKILLTXXs;DP[^[WY\Ze?3HFIHMLGHJLCGӬoQe ǾXqt,7#$IETUKKMO^Q_p`ZV[_eaferQ>NUSQTUSQMKOONI@bܴ}X[- l߼JqbG6-PzٽHbmaeMKF &M+tͥqǿpfnuzxfcs溨љy'nS#3=" GOP$G*$'&'V&%%(*'%:`}ίogvy̙fb|Ц{Ġ+ [_?$Ka]:"#&)'&'&%(%L"3fvhegpw˼‡v}iY(>VPDA#% L3ER]uٶe}(LT@1"!%% 4 ,Jjo~ 7'(')3AHRdpĵxz  *5-6;bŲDz}zyʴ? ),hdH-EʽX%Ew|S (UBeƷqZY &%r`eT # On\5 !$dtZǶ~[   1[Rpų{somkh\> !(;a.t{iSF?>;)  "+JpuwbP<7==,   5gkd`POS:    */% ۗ t8mk@   U+k`% %o^l6 F  Fn` \q La0 >T& XJ5v) 5"1A Ts @ u 4<* aD^BN3# W{ (io9 y /Fg q r | v>D. U &L62  Q )]zF8!SpI7|@Et|sG  6r¿S Q  J|?  k[  dy =Ch"jYu!l!A-7]/5GicnV Cconnectome-workbench-1.4.2/icons/mac/workbench.icns000066400000000000000000001311551360521144700223540ustar00rootroot00000000000000icnsmTOC (il32 l8mkit32et8mk@il32  ˠŬh 61 I/ng l l/MNptcѡ-h #KxgʪȴHi4?}v>oe]j!e4q^U=̠tL'f~Ha^Y͋zn$rh jy]۝QqvĴ$eeR]tyyaFe޵TVRta^}iΓȱqT"i4Bj+עᢙO~U:_-zбⵈfA[YnxƯH701qԮ~i90ZD~.Q2aDΰpJTX/V2ilcMUT`8y}p7RYD tȀjeUTRTtϨc4 Jg/r6qIҖQe9GŬ\(h 5y18 մsya ˣe8yo/Is~dXI7EWrS =͎ĊILW6|x ˠĭh 'I( IAld l rkWtLvmo:h '6epRdwGi (M\sc5mJy?!fTzGveƷ 'g ecjNtdc|ƅ#k6t{r{z]Qjt#fk`eratBMgg1[V_yZY~Yps9pHdy7)pkiOW5tވKxiGOudXMz8(Rݢׅōcs8dmD[>OL:/0qa}mZR`|RMBG_ss,fʔh  dD C>{w(&{g!h #KK~?w/|ڑ 'g>ꋝHK5]e`sƒ !h'xŌ)B[efpTfPv#e0i͕^o7IX3o{'ScZ9i dSXJXOxl9]&T8./S[LCB-u$s:S?aĹ^1Ik&M=I|ib60MU0HI  &=-g|HI]U=LE2P?R{>?4RLsǿʳ4  &A ;]4OM?M#.z>WJVxmƵ`dt| &A 1;Qy8 GM4 |5/S^rͬsWp͖Ϻ &C(+8*:Kmq7ROIE"de>Ucp{l|ᶹp ֒&C4+1GEgG]cSIJD2ðtj}}΃rtpoY(e5s9&I67$ȥf&GE:FS7ΗnK[IJGF!Dplyo{ʰmwTW|̲*&Gje76 RL[ռ]WL=>BDE[m)Lqjz*slBI˭]_I/4U=&Nem+~\@ڱCPqjMQXm4^Xy%ֿ̯/%2&R d>?JSþĽƶOGS^wyKZb{)แw追ů~5X>&VY#FM=2QŻƱؠAOUj}\WZk8칀hp˞w!)׺;a& 򄧹+evtۍŞx\S>e&dtƴ*'bqоԛӿGV\lHiZl{BSmetײwdSd@Af&=ʷPS[ Wv}ξoLYd~|LmbpE[ckrkpyƲbMwϿ/&fһZ .}y›OZ`pZPqmzԂJc\adgnuyz}Ǻʭ|dٛd&3ۏ^ mlwsX[_nVMtv[O[Z`belqqryȴڣw&& LmWyr{sro剁<׸iTjk~JKtτBRX[_abhllrǼSp&2gyT3Lgq]D˙wwlMrr(Nu֘`FGWZ]\\chku섒äp&g}:K&$:t_Wc}CWntCovf1`rܤ`|]CMQWX[agnubop&uZ]>ÀxkDUrTJlHfxUd_dB?DR__eiryʉhֻ"p&HɺI~[Gt~xHErCpᆴųVZwxZOiwXZ0.8F\h}notϤZjp'ػ0> ruqxR6wry~ϕߢj_g~ӓozL~A;\nK3uvߴpNp' t"tn/ h_~xW5k3 mVm于uoԭML;YQ;tʵ΀LzFp& WztJPׯ?kzU6gЩ"NjUlױ~῝wekPTwܲ}gPDPrkؚNX^o$Ff$W`nwyxøL~R7d\}s~FS]ONuնƲl`{ޢ|zo񟐩]Pe>g2p%|opt~S 0qS4bʮG xBG[KCIlǡýiGǬpEl͑Cw^HPp)*}~z$bsR5YtzK6HC@-sR=D-EA>86Kqʸ\«Ͷych~uyKpClĵ&pQFCiQ6J<7*&FkȲYʽ|Ͱ¿u)p 1aȿKaXDIMn/-44+"&7eڼƳ`رǿwsv˛Tp,GW{µzY) OZfjWbc#/-))-RE¼f˵Ͼȩul{nоzp)j7d}Ơ "fVg͟[U>37DC62LuI}mɱλkmܳAJ`b*p,Ea\s \S +k[OqMUw+49GMMH:17F[wuϿכʯtfv+6|U_ȭAo>\w΂;`,h\Y[uk_`lew -0517;;9410&6ՓdῼþZRw߬X:ќ5p@pzʵzPss3jjmbMNUxaOG[Z: 3MH>63:@A=73/1-<٢ޖvY˾uK`dEܧ3pDTnͶI8hZm}wc\P=A?HuueD31AĴsHiTz̯@qt5Vtdt]#Dkajվx@Leb[UKEBI\w8=CHMOMIEFGKKByъ`F68B8z;PY݂\ôOAzBAJzg. [;]^UNJHCDL[zi ?KTVRPO,SPyĭgEACABF=Ơ`P}i^Y(t\Css= !ו AW[QKCGB53XqDk9EPZ_[WZYaU?NLMMLGHJJEB}ӫrKvr:}Ի(~Yopa^觀Jmĝ`ի(WETUKKLL ?W^n dYY[_cadkdbRRSUSQMKOPLKBb۴SiZ/m\Cq^KᚈP2"wI n;TOMNSH#0I^dktwўiZgiquztjdXSTVXUOOTWVNP:w་\gh"KEvޕ]%VrW g5RLRRXbglmmxw˴ƎVoq|sg^\\[WSU\^^VS )OLRU[_iTnR]Tuwsiec_\Z^eeaXZ9t߿j̎څ/FϺ̟pMRJ 2IRVW\]n%q' ^Zvskgb_bjmi^][<ߵqV{M+(BǦɫxi:lPkVBSYAcs {P@7ڋb~sjc`eone[fLaz j"&4etȧԸX TddW"KQORYo`9vgxld`cjh[\TxFt#'{Nb 4!%~;/˵N&g2<\q\'h=\G9EJ>/ *V9|Ķp֢  n"  Ơ0KҴZfo|bB|oCGdijcd[=&N#%Gæ#=eix{` 60Jia*рxǦS>ftwIKiEG*$'&'T&%%'*&%!P-^nQlZNrs_jj~ߋ[Ǚ{]FqwdWhY<" ')'&%(%L  Lnahowům@ADqnϹVs}̑lLIF& L3ESatZ 57wFg|{ !'<`|jSF?>;)  SioxucN;7<=,   CUfg]WUR;   QK< ۗ  G*$'&'&)'!-^P9$RklIYxY- &%+\um=8beM,,SUKVwlUðɲH &=*n[q:8__WA?NZhE8Q?S{gS?OSyWw~; &A 7ef2LYgH@KH_bFRLVwͷabxs|EvXTP9є\X*&A 5;X^݆4S`MFLCICe>GP_q˷ƮrUYCBTmf}a¬Og3 &A'3?G=:PLY?[WOHGACoo^ap{Y}{=CdWUgbTwLq\=֒&C38-3FSMJFo֦>]aTIIF9T~³sj}|qN^EUmRpOkwj8AKeg|t\jd9&G;KH0<\O;/\rDdULEHB6a{l~wuuJ^jYYePOtYeg`fȦg&G /?Q:V3D[K/]ӺYNZHHED:OmÑOtq|̼WFlYX/Dl[dx̮~)&L VA::1]K8l3UҟPTMADHDHZmoybnk}ĚBLeV;>\xh`~n^b;&N g>12D`&Ckv;J867BGN]sX[\dmTWI>1Pf`mqUHs}]vP{M &M muA:Vc-qpf_phKT:?IQbvysVXczMaMM~~NfIнva\wc_&OccCPd7EnBi~·ǘ@D=ÿ^Rgùj:OPcp`D\a^J[uݩhijq_o@&T,ugxv^I4-Hż`˘6DLZcsiSYXlipyYeq~ȤmNsӷ?&V qttv`71qűϝHIR[uyDbMZ[^yOʣfBYm~}Ѵ^F˜=&XSHe}TX˿eS[DDPUdLpq@bYh|eW~ǽV6jq}SEŝzYPXTƽ>&YPdoyĵxkfoѿ`q{dk^[ڌ8MUXy^k]Kh\hmMppCRipXPv}ײzhYjjab$d&!c]blY~v}پ|fyTdiMn>XUfgɷDYjcpnfElbE\cecjpyǰ|M|eceze&MM_>kcZUn~߾~shl:hݢ{K\[zqyzmSPrmweψAO`^bdgnuyz}ȗd}ӑe&4[pDw{wb^S|wvs~xdF=QG_]lTOuwھTBRY]`belqqryȦxʻjmYvp& PhR_kZs^xx~{tHoi{lsg޴^:`doyNFuq;TU\_abhllrD_zZgoDǾRp&4P;vRo[Zxe}hobctWa[{b|`]GTosOcx4Mupޗ5CNUY]\]cgkvyaճPh˿#f&nQcDeO`wP_WaҋupRqbl^hYoKLKXApuwȌi:\syaA>:GMQWX[`gkwo[ֆJg_աWp&;dFak_{kDSxϗvGbyhecڅDrP\7lsyՍHKh}jy2MI=;>DR__flowsSNĿQV`-p&.^`}X}h4kuxHDuÅ]rEmvkZҝPg{[folB_qyZ߫Tiwa/Gm^.+/6F[ekpx{^M{_jݟcEo`Vp'ԬL}THIuq~xR6wakrQbVŗ`M_Gu}Ek]jypcҐpz`R8ERG5<[uI:MYfizv[֙q۴oSn`o"p'PBzoSDw_}xW4ld_slDDă_RQL[Sf亏up|]ۚ]̮|kg/HA>@WwD):NW\`e\Е`|STvV0p&ş=e~zqYb٬MrxV4hϼqgs_JذiRٙ_ƙHs)DC>OsxQn@++BIEJ_f]kOUaoU p%*SЍ3X`oyvwĵ?bxU4fχeezhBlBWdPJFԹefū^gת̚SwR5EB:Cr8dVC@BpE`~ZN_Aj1p'L}d`|ooui@]nU3cȼ{`gUzCEXJDNl¯q`bŒھzBFTKDHnUlqloCPsx5Z͑@y[EQp*.Ox~{WS]kV3ZQQij\/LA@9MpYyRth|?G[ISSuĐhQRe.KwfbjZ&p*bkõsSqTZmU2*%%98G\wcUɲgħncرiQOrfwl[i^/9YbVPDo@XzmAI4c̘PXUe>n_KNc`V`jmmbL987;|VSl@C-1Yɼ~ndeS\waCO_`X\jttmcKEKAlf90,1@LJC=52574-('+J΀H݅^VfmH|ij}527;;9410&6ӘpnNLRVM9zWwʻt\QwkJ53;@A=73/1-<ԬYpHv^XEGn|ȪuK`oH8Nyۨ2oGFQFi\:xZcǽJILhnADH3K`O=A@Ew~LۆWucB+55mȳsHhboY}˯@qpK?Cnquy۽KaY;qihqeiտ}6=ha\UKEBI\x36:CHMOMIEFGKKD@H֙CmgE8X[PYw]aôOqyU6Jz[YKn6]w\]9^^UNJHCDKZzmX(=KTVRPONQPUSJM`a=DF@DABCE~Ơ`P{HY*wW,tLetU|=QvҩaAW[QKCIE>?Xqo9EPZ_[WY[\bTKRGDFKIMLGHJKCFӫqMrqepXTXor>BMen_HJpkƬƅүiSRETUKKML?;8HU_n]tbYX[^eafgnaXZYSRTUSQMKOPNIAbܴTfqhvkSX[Eo_/ZWdm[ODlpd\ldWjUFkNzSD;TPLOQPKKR^ckuОjXfjpvuvreYSUVXUOOTXVOP:wཊ]eRbo{D[N2oN-^{iatjZDkxxb\nttnXygYsbWHf6QMRSW`egloww˶œXnr|{rg_\][WSU\^^US=ckbV]WYdDUo;'{í~k@hU{hHotXjl|r[XWAi{WQ)OLRU\aidu[]ɇNJWuwsiec_\Z^eeaXZ9so?Qp[bmr>p5%sлnFVoWi`as}~mR[ehQ2IQVX[_jWT^drKIұu[vskgb_bjmi^][=ݶuJ^yYmp{g"p.#jȤ{tѨxiY{blNZsUBSZYXdthwkvZztZϊUމd}sjc`eoneZfL~ˏ{MRUX]@hup'$n}ɦѸ`Ikzv{k\de߀Q}POORYon]eEOyVђlfxld`cjhZ[TwòO:mzETZSϠ7RXp$qG8ʷaI\jlkthxX\mh?gvFNOOLH6BI^`L[]LgZsm{lc]_`ZPSmqbdkQj2Ev:p%`W=8˱zN_uddZthW]nRєWYhm^a}q8DXYLDGLNP}~xeq~ymb\ZWQJey]Hvȼd8=cp';7չYcgPU[u\Xeg^ckGgOʫx_MGPXp|oQQ|y~tl`[XORRTYböS@;>p&/o̹xpXE1_tfXhpw`VuX۶kuơz^^krwvTRM{kwd_ZSLWZiSHWºnL<1 p&IbdeglpzzeQD>DB0 *V9}·q׬k|auLBGPT\QOďpz_nѷA-OT,Okwb@HckceUOA&L%?cǥzȿSLGMfjw{nA8C?Wsȇ\d|3M{R+CL:!H_W,G*$'&'V&%%(*'#)T\fm]Xrjg}[McƞJMo^A89:Ob\;""&)'&'&%(%L29Zkbhpwȴilvqʽ\l[spdXWS]NDB!% L3ES^uֈlsmt]Pwg|&.CZSA1#!%$ 4 3PliMecXogwȼu;LPeio~ 7'(')+7:.8[NbŶ{lZShLz  *!;::AHfmJǻY>Kmw}ν. +5RH=EMPijOW|x||ʴ? *6icB.YͽyvK\v}S #VvE,jʶ?qY %)hr[;ST #UsJ5 !aw[Ƿ~[   0[Rqó|somkh\> !(;aG}{iTF?>;)   5RrvvbO<7<=,   9[gf_RRS;   *5+ ۗ G*$'&'%& )'/EZ][7%(&&(%!0HOQI3#&*)($%&'(&'#-& A~}WDX2 /UgjUX`N% ***lgFaR9$Sjm{|avT$ &%*bo}}>]aM+.RVIYricg9 '/(`' KhwSOF#,NoIMDbNHLpu[r{$Zw-K;&!{ǐ4֒& 2VGSSG=30\]VJFP~Ĺtj{|O)*4g}zt:&EJxEAXJ-FcVKHE^oúw{xxQq&-Jmpȧj&G %Ilx^0&SYIGCGmdg֓ntzA",  Em}̫w&&L %>AgyG*VMBGJIQYoxknzդog|8&P +2S]%#K#-CFM^pZfjD%#(]~Jøb|Q &N 7Pa, =jM!7'?JRbujUb~uLO|q(¶vӒ_&O'Vd:!&OeiսȌ$@IWe|˝RZkړp~6| ǿ⧙t &Q*uԻe@1H̴n`RӾ~&JK[mYdP^tȰRAB6̾+8ĸL,SNdmQOrlx:gS^_ccgnuyz}͇FҎe&53`ٟ|q{2 !@b^m\UOwwݹ1:UX]`belqqryʙVȺ}JEDS__flmur( N`;2p&y}ۯtxHCxg"oՕ/D\:aol jdyB!(06F[dft{}C  Df%"Rp& vsrxP9o{%" sǖZ!3k\kxL  ;˒oz6!#1;[vH;B-R~s/ +ٴpS$`+p&}w`{xV5l@ " ^~c*HE幏up{F&˰R&$>CVu@$# .DG1zVCY56p& {yyqzݧmuY1kmB04~ObAU8װTƘ95LsX+i3$211.]? IOUceTp& "MUboynuðm[0kֆg AXfQH6ԹP!ש ,+"/~GPC.s'uYN[Am2p' 7)W|nozpV1e堎d=DFWJDOlR 7ܽ¿T H;J. V_Zy4WΏ?zZDQ p*/N{ϧmV4YXs"[].M??9Mqņ5[3H# ^ 3Pc#@wf`k[+p+fuIij֩kV)ĸiD/b¼qZE"2"y]s48DB>B=CuNVرڃ'hnlˬc  @3o7`__ADG͔{b\U? *UL#/ }S0׫; )sfwןW)-GoBV{a!Qˏqy`bS`ghndF|Wfd6/=JQJB:4+*.:FSfj RHqXjaݘa,*sbPoLKO$GʺҜl_ra`XZkuulf=e’w_bP%4?LJC=52574-('+J́6}h ,rUgӁW'"8.<]{~Z: 3MI>33;?A=73/2-<ӯv#hN:4F&>ɪuK`PA+Xۨ2oH?'bG |C=ƿNtd(DaN<<"P_PE>Qo༡vD<@A;1;BEEA=9484HĬ@konI('ŲXN{ʧH8[ի7oWL$u>({joӇPnzH:9*ywD"?d\VH@EXwοiC,3;@HJIDA>=A@Dzm'ubA*1<$ɳsHi&1`{˯@omn40slq{߰4X]΅yfl18ia\UKEBI]xÄ06DGMOMIEFGLJE,biD9>>@IPYI>s´OHv{9H{dwmM͗]9^^UNKHDCJYz?:LSVRPONQOWJ#8F@D@CAGtƠ`Pyt UXqxc#tv{HAW[QKKILLTXXs;DP[^[WY\Ze?3HFIHMLGHJLCGӬoQe ǾXqt,7#$IETUKKMO^Q_p`ZV[_eaferQ>NUSQTUSQMKOONI@bܴ}X[- l߼JqbG6-PzٽHbmaeMKF &M+tͥqǿpfnuzxfcs溨љy'nS#3=" GOP$G*$'&'V&%%(*'%:`}ίogvy̙fb|Ц{Ġ+ [_?$Ka]:"#&)'&'&%(%L"3fvhegpw˼‡v}iY(>VPDA#% L3ER]uٶe}(LT@1"!%% 4 ,Jjo~ 7'(')3AHRdpĵxz  *5-6;bŲDz}zyʴ? ),hdH-EʽX%Ew|S (UBeƷqZY &%r`eT # On\5 !$dtZǶ~[   1[Rpų{somkh\> !(;a.t{iSF?>;)  "+JpuwbP<7==,   5gkd`POS:    */% ۗ t8mk@   U+k`% %o^l6 F  Fn` \q La0 >T& XJ5v) 5"1A Ts @ u 4<* aD^BN3# W{ (io9 y /Fg q r | v>D. U &L62  Q )]zF8!SpI7|@Et|sG  6r¿S Q  J|?  k[  dy =Ch"jYu!l!A-7]/5GicnV Cconnectome-workbench-1.4.2/icons/windows/000077500000000000000000000000001360521144700204405ustar00rootroot00000000000000connectome-workbench-1.4.2/icons/windows/workbench.ico000066400000000000000000002143661360521144700231320ustar00rootroot00000000000000  & (( @   ggg777BBB<<;===<=>=?@??@<<<333LNVUMNQK=<<//0: OLI B<<< hVM\oJIE@@AIIJ 6N / P@ev95dgglkk.-+DCC ]]] hhg``_URR2'!b -38?61`dlzG)&UC9VTTw||DW7,emkAHg5 vZ[`5aeh_\Zsts###J ,01\B=sg@6 gF>RXtG-9k[M%%,1!9BBE .--h>;7џodW0 z$ 3P#O#(c>+7 C*L&#N@@DN !4 <wpi 03>\TQROTdOgO9)(9.I dUs%\-z@XNE76:=(&%!4"cGR*/4|u ?DQWXU>D[;(,E:3oc[##$Q:mJCCG2+&&; W3z# /vJ-1 IHP$MPg IB <#3_`\Z?GiC?>w|kH5  ;.Plo-+)8O&8Vp[ JQax R/>|sWFN '  ( 0mtyrm ***pv|L4lLy$'5OHA]PWMW[lUB5Zvz}ZM- | G>z2<%  2BDOC\p>BO1 ]$? ?1-_NCL45$)[06JR&Pvlp , *)WH O 1>N}_[W !"!+;z$%!7MQV@-!o)O +=IFJ1)-1IA=3H #!#Wi PJLvx#%+ #0-B39%C?9pk+p9O[:312T!:w"Nh)7V"%*<7.ep-t.LzQOV ##" !m9Xl5B VVX_c%w}}Ta - !;; ,3UUUR:ZZZggg``accc`aaacc_]Z[VR}pd*|yv;ZZZmlkBkkiQPQVW\`ckolkVWWg%o P  /3H;(   OOO\\\VVVXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXZZZZZZXXXXXXZ[[XXZTVWZZZghp5opwGccaUUTUTU[[[\\\XXXXXXXXXZZZXXXWWW\\\OOOXXX]  /XXX]]]- #%#" "# 7]]]XXX $)+)-.0/.-  AXXXZZZl L-4Vd`V_`dkigOOO333$$% !ZZZXXXu)*+XXVHR|vzsssUUUBBB333,,,)))'''%%%### !XXXXXXY -/0::9stswyy]]]EEE888555;;;EEELLLIIIGGGJJJXXXXXX"=<=(,.A;8vwyvvwgggPPP>>>777>>>HHHWWWcccddd```VVVLLL j]]]XXXh+#!G+! e}|||FW`cl]\XLMOBAA999;;;III[[[lllmmmiiihhhZZZ[[[]]]XXXC6.+8!%-sA.toywworphmvvo`*< *FC:9:>>=;@@@JJJ\\\sss}}}sss```dddVVVXXX]]]XXX= #$' GwyzgddV\]1dE3.zd/.-345?>=JLL\\\tttcccVVV___XXX\\\]]]XXX  d   \yrstZWVEDEr73340-231135898GHHZZ[ttttttFFFZZZ]]]______ y]]] XXXk     "#N'FdegIFE08:P ]<'!9/->40EIJWVUsss>>>III___ccceddQRR[\\\XXX J|   )TwZQR5vwwa``NNN<;<0338&#TgV#m[E>_]\wvt222???[[[aaakiihhhFEE?XZ\  XXX Q %&'@BCMMMHHHGFFEEEL$U[!a r)#/<N2}cehONNJJJGGF=??9646@EI-#v w!$ )))555[[[___llkoooprp?@A\ZU  [[[ 6r---JIHkhhzww?&E ,>A'- wkgeGHI>>>EEEMMMHHHCDDECCMPQdG?wB/N>/}!##433XXXZZZeedpppttt;83 211 SRQQE"A .#%(!###)))///799MNOeikopp}yytmhep<'|$ & .A*>FL.*(467GFFVVVUUULLLPPP[[[hiiy||&y,$),>;:WZZQQQ]]]gghvvtvto 4} H& t|sG 7|489L>97m:(F"JJJZ[\ikipstprmdmmC,6Q[`7CH"%%#%345LJJ___ddcXXX\\\lll}}¼]Ba3 HLMQOOMMNXXX___oop}|zZWQZ)kC>3  * / OMJNNO?>=# @p- V k_[``a*26dpwrvw`[Z_N9) ""!(%$-/023307 QJJEFEHHIVVV`__kkk|||1370(3a@@= " - /?@Ba`X>EaF$I! 343rlk}ywi]+*)|wi\%A3\X_OVWBCC>-(MMC>PdvkdBFZ|)2(:3@BJ 8 %9-/3)  '%$ %!!   SF()(CCC``_eggehkiggokhhca%sQUX__]iggwwwRTT--1!P 81=m|hotzs]Wp`[||}tvv`a`CCI!'6%-   z Q !!"##"'&')))222221 !!   , kUmO%h0,/2=EI3hI %#)< haooo* 'WBW887*))023E?0  JTw|zr@@@ %%#(*3mki}vv6"yvoRUUM#P 5 $%)    ,)'BBBQRQZ[Ztstv|}TNMH0(?BC())3eD:gM-"*# $)/z/΅lȅpO6;%-tL?my|wN%;-O(V[]/23$%&++*.//686#.c@P333%%%/// =A@ze]$ka|r}r=,UCBGF>)} 6ir333111555---&&&3>AA%<8zro|||zwv[__IEF 8   &". HGGNOOHHGPPQttthprN2+t[O- -:9L#P  <("X*L59$O#%') 445P*O /errzC40?B@859OM?26d@0!vvv***555CCC@@@111'''!#18N9.dloga`hiiosv|}}ki_ H  L %*5  LNOyww___IJJOONoop}yvLUZDr%D#&%-#0>L[7L &'*:#E# # v./  3}t}g#aC9\deZW\NXN<>v,lLVXZZ''':::EEELLLIII333&&& 0'%*  %%R[_LHFDIJTA9XTTdehvmIL] /./  16<:(!L4-aacJIIGHLgegyzzedd=BB0|%2.3@PPQX[T%/ "! T[caD7w)4:$))O(<!18eOImlmrmI.|gc7&-EĪNMI!"#999AAALLLOOOBBB000&&&  %%%###./0rO 'ZekCAA>2-|}miNZ 3@@A %H\TItty\_aNME-3F-rcdhZZX/00%$$3Zc[B8;RWO8\ #&&_3;CE>,% 4-,#/%F3.E92 wo- !Am}@@B 445<<-(1=BA:7@@?T>8=e<>PA;---0//>??BBA@@?667,,,$$$!!! !!!!!! *,-¼IJL1)%M B)E6UW'EoI+ <vFwsm}}|acdHHD137B>.$w- %URMBBC.r%|00(-}-v(mE1+L#v,eZ "# !##&%&',)'-/00//9AE]WVdTwwth]MJE'(),+*333997778236++,### GFG#%%(GA ;V9 >7spoz||}}gggJLI=<=>>@  'UTR>>?2g&) & %D/%2C(opp X?% %%%/--CDEtB/mVWWWDCDC?=;;:%%$!"#%%$))*..---2..--+%!!  ///@AB!#:9-)}3`#*I$@ -+)  lllrpoTUUFFFGJP!(FMc;:78v)7%J'iV<iQmh$9vvtF R @  )((@@VQPkw|ZH)ACm6% ! ZD 874kllihh)*+!+.i:+* !_)48UN5ϭ.123 322NMMLLI=<>GFFUZe 9/;v'(# X?/\FOUX979667IGHieezw 222]\\Ծ]$'  1kX8\a A #    -5QlzZZZ134]UOZNPaA-=H7$}:rc`}}쵳')-( -,( &*8*-;31-ABCrpgo PNI v*>P$#PBNDDD(#\Cp-!2<:4 - # 2113MMMJLJ//-  g t  ///QRROPP$#"    2/-'5pM=?AE--- !   B'sst]]],,,$#$LLLNNNlmi)|342ypmmmm  | Tp$<E Z30(d ľwkha:::- :#;@V# (' Q_4/  8 )(%GGGrrr[ZZMMM...     ??>ipz $a%2d<92))((% O.ҺrstIII334MMJMNOc|B ']wzyhhi   r)p z eH Q#&24ywv[]`112/,,yL,%/Q7%% ' : 0 @   338ZZ`pml566     ?@Ami\.8`@)#.NJ r .(N 3gge---@AAGGGadc·)   1ddc q3dsa MF N_rvvVVV*('2/-B*1w#7J% ! !%%%)('!#) l 7 +,IIHwtsr!%'    ;;;¾QPJ )P(tX %2i/cw|CQ-=?E///JIIOQQ}|%i  UUU g&PMF#ac ORMVv}5UD=&() !=!/_+D %%$--*---&')"  2. 8!&:WVRIa/J"$     MOO87?mi< "'`431rs|#4 l+*)##"A@@TVWh`]֜lX8F[ Q[`k}}sRRO  F32/'F oc T WvP9F *!d (IUB18 ##%-#'7('%  & ! P t3>i3e}"&/ [     """<<:84PQRyyycZiF;GJOp:*?EI*#"#  X  QPrvB=*1:v mw,      --3AQQUhhi8[4'OD3pppidXZ[[U]|:M#)A('%&&'EDCgik}Ȋs5 )iso %C ;wVB Wy }(.4://3;:;QRRtttmtv[VTrB25"Zp#FsJ " 8 % wi W m!    G)0 %tw4mNy ",NH &zzv\aso$<0ؼ e>:-##&543\\]}dPi_imlEFL(,FP`'%%29o$B<=$#?BCRQOrrs}vyze& W o3# (31&ZW V 3    ! s# Gr-G}Īlms R>Qpy|*&%4|%.M43/)*,JIHtttytpr|twycch\[T#. yF-$-T(`#_Q#H5*&NTZihd|zzzzzyvODA#iO&&) $mw &&3h#hMTy0    ('%IN\2# [_rX} Z,agl-/BO_\heeeFED543:9:```mmoXWTIIHDEGPNM`\[iko]ZO 8 [84-i" O3-6%9DJ?:ckrtyzz||svv_[[:EIQ,XB* eM%', he_7"#t #; p$:  ***__`AQ+ )ļALz Qh[/BļQkcHgohhhEEH<==MMNwwwtvw431  #765JLMddassv@@= -zX-/1 WQ[zt0LL<4i]\|ywpooPPP755332CBC=c_lJc'%,  z||>-d,>m=72Z@$%}   *))``a|=N;1- #3 ")MZ9BR-G#FUydEFGJIEZZZ !# !//0MMMggezzyprp""!#CCG%%%{ C4 BD79=EIIABB333()))))2--865V$ye\mdcC \)(* ! l3Z=0EH? #=Pcz 27:I&&&TTTsm[*iG CVr2$ Tp>z(&*&)d|,hkiIMXVX\iii10) &997LLIkllFHH 21/]JDM))(11/(.1-/0;ADovz8 H'05 %" >!!=24=@6##,A@>EA5 "  -;=E||wQRXQOB!}"hT#:Oegrih`adm6R/& vc 3@53GB2GC8ABC,))[-5XPNG_`e! '%#3BXk6 3!158122**-2>OMMcim' 8+%-02 %##րe*#',GN ; %pt557!% N & RV[ooopLLI89=A>5$ikQN}PQVOOJPRX}mBXc,/!z % ,,/p0r$(4 #+>U% "iG%d_RmotWWW !)A)#-|hA<2-478/)(AUM/#rz}HHH345000 &&%7 H9' ,&_89t5:B 'Hd"|}}FFE---)))336@A8WRolk==?>>>NMM]_a3%#Fh J  ONHU\w-/9   -}v!dM6F}t2372.  BFgii;=<=.46C Z_d9+,--+**756000 )//_V%3++V=T1,F}NOP5M-_4vʼRU\%%%%%#015GC9)I] IGJ)))222DDBPRXv\o ] T`5 .-( -"$y52.,.:JQ*`hwttt)))()\N4k]}1?@B445;#_ m%mll---6656660000-+<#+9'.X%))>MVl#3@s")̾&V )*/=:0&1hQhBcA% $$1//BBAJLQk=T`zgG'D8  !#"%4-)(30)43-yw3%ĸVX_" U)% - hdFT+D><7DJF%l wU7iMQ]d530>AB;;;%%%50+O=#.<h1g#&! %<D_7+C\C (&"-,0==8:;R1D`<`]&# 346CBBRRTehv%h}#1g<@  ""!&&$')+-/1+,7EO>VQa?@@#]g: ^D%(#4 ew% R!EAAa/ G-CORGA>LLM876 @:4Bz-):?*Fy(&e#)CUƼ- ))).-.:<=;ABJvlR1 ķAH_  3 ###%%(0/-666EB;)oZ=#EJ_O[) # `.1Q)]z0!>wihMQTWXZNRU346%##%)*(V D-Q 6#/;h/3J=W|34F@G> 0ti /--=>=FEDVTR_ai)gtĺNOP  ###%%%..-=<;FHMa]U196w}s#;PNIid_a*#V)%'lw,8J0pd\iXR\;1>0+1584330-,_rgt}$)++$)3p&@,8#BX_t9PzJg $! %*)%015QPC-E#J_yy.--987AAAILPdc_ah}4L%*; ###&&&&&&+++567FECORWwk$> 2#R)WQE> DHQ8V)FC/3G/?X3'FLND><3:>O/&sky*./3,,5v0_ <P[eg B]hr '&(=<8DGl9/--//.67=JIFddc}z| !!!&&&******+++111:::RQOstyQa0}t4A%' ]M@:-./4VAQ-M %D `D(dio`ggGHI554?CCtwy3512,:7h#&T G#Vos<\@aļ(3Z22)$*\12 '++*&''0/2JG;JOe !=Zı#? 9   ###(((---111222444:::FFF}>O okkomaWae<93P4 EHT<  cly<_&yaZC;TBpd5LLL/..544hhh@?:23J"1 $mm([vsgֺ!: ) " =:5#y 3$%' *))<<:("&_ =P  !% +%%%)))111778>>>AAAEEEDDDppomorXXT+3U\.38+!4 !W/2u   8I)21-ty||vt|`U0%EOV%"&)*WVWGGLONL*-3T % VVU`dl(C d01&m%r #$##&>;3'w))>XD`!$',)! cp..-346?>=FEENMNTTT\\\ZZZrrrIJL62/%# .% % kOhiz z+LVc!_QIByy|z}||zeE4 16?DB@ZZZ`ad>IyRRWWUJOQQ! FIZda[tts " 366)* ##!336NNH !5\v #%!)*.74-?@DGHHLMMVVVa``lklvvvVVW320FFHzyw @*5D7R(-;ehcst|-Iz. " **.opptttrmgaac[\c_`gdgmhhdDLhGLZ[[WlloFV '/-()1UT31/CCFl_QN\L]"F '''357HE<'4o,:yke\acica]kkivvwttyEC@ 8gRHt||yvU0lP|  -6 #}GA7egl|zw0.L  tst||zwwrrtr(@R`}piiimlhrsy:P Z  %GC4, $ap)&%DLOTDC$ }v )1mI| 7#!#)*)556CDCPQVec\trhgishoe_W'/N,ghlwtrmy} sC);RQHkmtrh,#  OOR[e #z|}%w  ')/e`N TscM1::;_>3yyEE|+-888/99?GFFIMLJLNU5emz)@y}|mevy|wsm3> =th : elrzehk 3a($W5B!BP$JW6@FZRO|sloyCP 2 !!"333X\]V!%! >IMy7%J)56:|iGRO) ONUURJ3@s?UdQ;)hki9@GQ$ WO)cZ_QTQDBC---T1'@rk- ) M p=+VW[  *N)"|W}Hdyl8_ &%)-TRQ# s - -..GDCtvw1, % 521O]cG1-358*5h]o"GGa\[M7Bp:Qw. .>E=/[R I?A98]psJ6a" %')HDApy|aQ3" G"vA]'skdO5Am*zvNAF,34I.c336")% ! #1 Z&LMQaNwX  )''::;WXWzkk)10%(*(%%247WQNzR2_G!,&  8E\ms)0kccTOP[dadzywz}}popoig_TN9##|zz5(s 3 5 &0  9O:FD\R}('  #'):::UWZwtpH&J(-1-*)233ADGpoko kB&'7/&I} lZURPONWZZ_ltiehmihiedXVV9DI'034@Ehlr/58v X 0 9 "# !2F[ic+G  : )789VOLvwv}D3-/&%3530/3JG=0 2-!!l# 3-% @,687   )B  '7_*A \ ) C>) QakJ8E!) - +))333C?=QPPeeht|4w/38 &3 Np># /w|37Z]\Uc|G)6}I*G  ILM&>  1Fo=; a4 B[`<3s! )**+=>?P\`gllhymli++,)a'XWN\[h"4BR}i[Ivw##TXXX "!"@:v6; 2r#% /`zsii}e?2 //0IFE}:'meyvIDB /0-#,L)3g.3E #:L3\WWW)(#;*[83  8  E#XImvyCAA  333QNL# M8izd`_MMP:  !?1,_``ypZ-@R[ 7/5,HityysD><  XXXa%% 01 #&$A(#  #g&|8)?JM  433dilzr[WU2$%    +@EIUTVooi}Zozsrla]M:960XXX+,3;,37/94,3>GI607  , Ug I  321_gkg:)O   11/===AEF79:21/0/-003;=?HE<332)),$%'LXXX\7 V#I =024A;9=CF-  JPA!    #!AGL:  /& ')+><;UVVdaamlmikl__a\[XPOM?@D557q XXXn'F)#$"/347)#>%P8  %%%))''>1#243POOgegvvs|psvGIN###` ZZZF )-/4'#4  !!# +/0?&C $ "%653OPRvtry|}_dr#'5 FXXX^&J-d#  l%%%'&&369=863.00JIHZ[_OOI#6 [[[ 54 %#%oXXX U   + k `% lll   ?g3@3Ȁ"? /@@~P^wpq"0Ӏ/P@ PPPPPPPPPPPPPPP ++W@?PP +W_@ PKO(L3O@1 ;connectome-workbench-1.4.2/icons/windows/workbench.rc000066400000000000000000000000601360521144700227440ustar00rootroot00000000000000IDI_ICON1 ICON DISCARDABLE "workbench.ico" connectome-workbench-1.4.2/mac_plist/000077500000000000000000000000001360521144700176065ustar00rootroot00000000000000connectome-workbench-1.4.2/mac_plist/MacOSXBundleInfo.plist.in000066400000000000000000000041571360521144700243370ustar00rootroot00000000000000 CFBundleDocumentTypes CFBundleTypeExtensions scene spec CFBundleTypeIconFile spec_file.icns CFBundleTypeName Workbench Spec File CFBundleTypeRole Viewer CFBundleTypeRole Viewer CFBundleTypeExtensions border foci gii nii palette CFBundleTypeIconFile data_file.icns CFBundleTypeName Workbench Data File CFBundleTypeRole Viewer CFBundleTypeRole Viewer CFBundleDevelopmentRegion English CFBundleExecutable ${MACOSX_BUNDLE_EXECUTABLE_NAME} CFBundleGetInfoString ${MACOSX_BUNDLE_INFO_STRING} CFBundleIconFile ${MACOSX_BUNDLE_ICON_FILE} CFBundleIdentifier ${MACOSX_BUNDLE_GUI_IDENTIFIER} CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString ${MACOSX_BUNDLE_LONG_VERSION_STRING} CFBundleName ${MACOSX_BUNDLE_BUNDLE_NAME} CFBundlePackageType APPL CFBundleShortVersionString ${MACOSX_BUNDLE_SHORT_VERSION_STRING} CFBundleSignature ???? CFBundleVersion ${MACOSX_BUNDLE_BUNDLE_VERSION} CSResourcesFileMapped LSRequiresCarbon NSHumanReadableCopyright ${MACOSX_BUNDLE_COPYRIGHT} connectome-workbench-1.4.2/notes/000077500000000000000000000000001360521144700167635ustar00rootroot00000000000000connectome-workbench-1.4.2/notes/images.txt000066400000000000000000000007551360521144700210000ustar00rootroot00000000000000 Use a PNG image and place the image in the directory src/Desktop/images directory. In the same directory, edit the file resources.qrc and add the image. In the code, to load the image, use one of the "load" methods in WuQtUtilities. In the load methods, prefix the file name with ":/" which tells Qt that the image should be loaded from resources. Delete Desktop from your build directory, rerun cmake, and then build. This step must be done after images.qrc has been edited or touched. connectome-workbench-1.4.2/notes/mac_app_icon.txt000066400000000000000000000004151360521144700221340ustar00rootroot00000000000000 * Create an image file in photoshop or other program with a transparent background that is 128x128. * Save as TIFF. * Start Icon Composer (/Developer/Utilities/Icon Composer). * Using Finder, drag the TIFF image and drop it into the 128x128 box. * Save the ICNS file. connectome-workbench-1.4.2/notes/qwt_notes.txt000066400000000000000000000027701360521144700215550ustar00rootroot00000000000000 Setting up QWT for use with workbench In QWT's 'src' directory: Examine src.pro A configuration item (QWT_CONFIG) allow selective building of items. There are some HEADERS and SOURCES that we need. These are the HEADERS and SOURCES not controlled with QWT_CONFIG, and QwtPlot. QwtSvg and QwtWidgets are NOT needed to copy part of the src.pro file to create a command for deleting these unneeded files. Something like this: #!/bin/sh rm \ qwt_plot_svgitem.h \ qwt_plot_svgitem.cpp rm \ qwt_abstract_slider.h \ qwt_abstract_scale.h \ qwt_arrow_button.h \ qwt_analog_clock.h \ qwt_compass.h \ qwt_compass_rose.h \ qwt_counter.h \ qwt_dial.h \ qwt_dial_needle.h \ qwt_double_range.h \ qwt_knob.h \ qwt_slider.h \ qwt_thermo.h \ qwt_wheel.h rm \ qwt_abstract_slider.cpp \ qwt_abstract_scale.cpp \ qwt_arrow_button.cpp \ qwt_analog_clock.cpp \ qwt_compass.cpp \ qwt_compass_rose.cpp \ qwt_counter.cpp \ qwt_dial.cpp \ qwt_dial_needle.cpp \ qwt_double_range.cpp \ qwt_knob.cpp \ qwt_slider.cpp \ qwt_thermo.cpp \ qwt_wheel.cpp Next, copy the src.pro to CMakeLists.txt. Run "grep --files-with-matches Q_OBJECT *.h" to find the files that need to go in the MOC_INPUT_HEADER_FILES section of the CMakeLists.txt file. Next place all headers and CPP files into the SOURCE_FILES section. connectome-workbench-1.4.2/src/000077500000000000000000000000001360521144700164225ustar00rootroot00000000000000connectome-workbench-1.4.2/src/Algorithms/000077500000000000000000000000001360521144700205335ustar00rootroot00000000000000connectome-workbench-1.4.2/src/Algorithms/AbstractAlgorithm.cxx000066400000000000000000000033041360521144700246710ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" using namespace std; using namespace caret; AbstractAlgorithm::AbstractAlgorithm(ProgressObject* myProgressObject) { m_progObj = myProgressObject; m_finish = true; if (m_progObj == NULL) { m_finish = false; return; } myProgressObject->algorithmStartSentinel(); if (myProgressObject->isDisabled()) { m_finish = false;//don't let a subalgorithm finish the progress bar if the main algorithm ignores it } } float AbstractAlgorithm::getAlgorithmInternalWeight() { return 1.0f; } float AbstractAlgorithm::getSubAlgorithmWeight() { return 0.0f; } float AbstractAlgorithm::getAlgorithmWeight() { return getAlgorithmInternalWeight() + getSubAlgorithmWeight(); } AbstractAlgorithm::~AbstractAlgorithm() { if ((m_progObj != NULL) && m_finish) { m_progObj->forceFinish(); } } connectome-workbench-1.4.2/src/Algorithms/AbstractAlgorithm.h000066400000000000000000000041701360521144700243200ustar00rootroot00000000000000#ifndef __ABSTRACT_ALGORITHM_H__ #define __ABSTRACT_ALGORITHM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ //make it easy to use these in an algorithm class, don't just forward declare them #include "ProgressObject.h" #include "CaretAssert.h" #include "OperationParameters.h" #include "AbstractOperation.h" namespace caret { ///the constructor for algorithms does the processing, because constructor/execute cycles don't make sense for something this simple class AbstractAlgorithm : public AbstractOperation { ProgressObject* m_progObj;//so that the destructor can make sure the bar finishes bool m_finish; AbstractAlgorithm();//prevent default construction protected: ///override this with the weights of the algorithms this algorithm will call static float getSubAlgorithmWeight();//protected so that people don't try to use them to set algorithm weights in progress objects ///override this with the amount of work the algorithm does internally, outside of calls to other algorithms static float getAlgorithmInternalWeight(); AbstractAlgorithm(ProgressObject* myProgressObject); virtual ~AbstractAlgorithm(); public: ///use this to set the weight parameter of a ProgressObject static float getAlgorithmWeight(); }; } #endif //__ABSTRACT_ALGORITHM_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmAnnotationResample.cxx000066400000000000000000000332611360521144700267360ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "CaretLogger.h" #include "AlgorithmAnnotationResample.h" #include "AlgorithmException.h" #include "Annotation.h" #include "AnnotationCoordinate.h" #include "AnnotationFile.h" #include "AnnotationGroup.h" #include "AnnotationOneDimensionalShape.h" #include "AnnotationTwoDimensionalShape.h" #include "DataFileException.h" #include "SurfaceFile.h" using namespace caret; /** * \class caret::AlgorithmAnnotationResample * \brief RESAMPLE AN ANNOTATION FILE TO DIFFERENT MESHES */ /** * @return Command line switch */ AString AlgorithmAnnotationResample::getCommandSwitch() { return "-annotation-resample"; } /** * @return Short description of algorithm */ AString AlgorithmAnnotationResample::getShortDescription() { return "RESAMPLE AN ANNOTATION FILE TO DIFFERENT MESHES"; } /** * @return Parameters for algorithm */ OperationParameters* AlgorithmAnnotationResample::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addAnnotationParameter(1, "annotation-in", "the annotation file to resample"); /* * We need to preserve 'annotation groups' that may be created by the user. * By modifying the annotation file that was read, any user created * groups are preserved. In addition, we are only modifying annotations * in 'surface space'; all others are preserved without modification. * So, we get a string for the output filename instead of an output annotation file */ ret->addStringParameter(2, "annotation-out", "name of resampled annotation file"); ParameterComponent* surfacePairOpt = ret->createRepeatableParameter(3, "-surface-pair", "pair of surfaces for resampling surface annotations for one structure"); surfacePairOpt->addSurfaceParameter(1, "source-surface", "the midthickness surface of the current mesh the annotations use"); surfacePairOpt->addSurfaceParameter(2, "target-surface", "the midthickness surface of the mesh the annotations should be transferred to"); AString helpText = ("Resample an annotation file from the source mesh to the target mesh.\n\n" "Only annotations in surface space are modified, no changes are made to " "annotations in other spaces. " "The -surface-pair option may be repeated for additional " "structures used by surface space annotations."); ret->setHelpText(helpText); return ret; } /** * Use Parameters and perform algorithm * @param myParams * Parameters for algorithm * @param myProgObj * The progress object * @throws * AlgorithmException if errors */ void AlgorithmAnnotationResample::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { AnnotationFile* annotIn = myParams->getAnnotation(1); AString outputFileName = myParams->getString(2); std::vector sourceSurfaces; std::vector targetSurfaces; for (auto instance : *(myParams->getRepeatableParameterInstances(3))) { sourceSurfaces.push_back(instance->getSurface(1)); targetSurfaces.push_back(instance->getSurface(2)); } /* * Constructs and executes the algorithm */ AlgorithmAnnotationResample(myProgObj, annotIn, outputFileName, sourceSurfaces, targetSurfaces); } /** * Constructor * * Calling the constructor will execute the algorithm * * @param myProgObj * Parameters for algorithm */ AlgorithmAnnotationResample::AlgorithmAnnotationResample(ProgressObject* myProgObj, AnnotationFile* annotationFile, const AString& annotationFileName, const std::vector& sourceSurfaces, const std::vector& targetSurfaces) : AbstractAlgorithm(myProgObj) { /* * Sets the algorithm up to use the progress object, and will * finish the progress object automatically when the algorithm terminates */ LevelProgress myProgress(myProgObj); if (annotationFileName.isEmpty()) { throw AlgorithmException("Output annotation file name is empty."); } setupSurfaces(sourceSurfaces, targetSurfaces); std::vector allAnnotations; annotationFile->getAllAnnotations(allAnnotations); for (auto ann : allAnnotations) { CaretAssert(ann); if (ann->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::SURFACE) { resampleAnnotation(ann); } } try { const AString outputFileName(DataFileTypeEnum::addFileExtensionIfMissing(annotationFileName, DataFileTypeEnum::ANNOTATION)); annotationFile->writeFile(outputFileName); } catch (const DataFileException& dfe) { throw AlgorithmException(dfe); } } /** * Resample the given annotation * * @param ann * The annotation */ void AlgorithmAnnotationResample::resampleAnnotation(Annotation* ann) { CaretAssert(ann); CaretAssert(ann->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::SURFACE); AnnotationOneDimensionalShape* oneDimAnn = ann->castToOneDimensionalShape(); AnnotationTwoDimensionalShape* twoDimAnn = ann->castToTwoDimensionalShape(); std::vector coordinates; if (oneDimAnn != NULL) { coordinates.push_back(oneDimAnn->getStartCoordinate()); coordinates.push_back(oneDimAnn->getEndCoordinate()); } else if (twoDimAnn != NULL) { coordinates.push_back(twoDimAnn->getCoordinate()); } else { const AString msg("Annotation is neither one- nor two-dimensional " + ann->toString()); CaretAssertMessage(0, msg); CaretLogSevere(msg); return; } for (auto coord : coordinates) { StructureEnum::Enum structure = StructureEnum::INVALID; int32_t numberOfVertices(-1); int32_t vertexIndex(-1); coord->getSurfaceSpace(structure, numberOfVertices, vertexIndex); if (numberOfVertices < 0) { throw AlgorithmException("Annotation in surface space has invalid number of vertices=" + AString::number(numberOfVertices) + " for " + ann->toString()); } if (vertexIndex < 0) { throw AlgorithmException("Annotation in surface space has invalid vertex index=" + AString::number(vertexIndex) + " for " + ann->toString()); } if (vertexIndex > numberOfVertices) { throw AlgorithmException("Annotation has invalid vertex index=" + AString::number(vertexIndex) + " but number of vertices=" + AString::number(numberOfVertices) + " for " + ann->toString()); } const auto stsIter = m_surfaces.find(structure); if (stsIter != m_surfaces.end()) { SourceTargetSurface* sts = stsIter->second; CaretAssert(sts); CaretAssert(sts->m_source); CaretAssert(sts->m_target); if (numberOfVertices != sts->m_source->getNumberOfNodes()) { throw AlgorithmException("Source surface with structure " + StructureEnum::toName(structure) + " contains " + AString::number(sts->m_source->getNumberOfNodes()) + " vertices but annotation requires surface with " + AString::number(numberOfVertices) + " for " + ann->toString()); } float xyz[3]; sts->m_source->getCoordinate(vertexIndex, xyz); const int32_t targetVertexIndex = sts->m_target->closestNode(xyz); if (targetVertexIndex >= 0) { coord->setSurfaceSpace(structure, sts->m_target->getNumberOfNodes(), targetVertexIndex); } else { throw AlgorithmException("Unable to find closest vertex in target surface for " + ann->toString()); } } else { throw AlgorithmException("There are no surfaces for annotation with structure " + StructureEnum::toName(structure) + " for " + ann->toString()); } } } /** * Setup the surfaces and validate them * * @param sourceSurfaces * The source surfaces * @param targetSurfaces * The target surfaces */ void AlgorithmAnnotationResample::setupSurfaces(const std::vector& sourceSurfaces, const std::vector& targetSurfaces) { if (sourceSurfaces.empty()) { throw AlgorithmException("There are no source surfaces"); } if (targetSurfaces.empty()) { throw AlgorithmException("There are no target surfaces"); } /* * Verify each source surface uses a unique structure */ for (const auto surf : sourceSurfaces) { const StructureEnum::Enum structure = surf->getStructure(); const auto iter = m_surfaces.find(structure); if (iter == m_surfaces.end()) { m_surfaces.insert(std::make_pair(structure, new SourceTargetSurface(surf))); } else { throw AlgorithmException("Source surfaces have same structure: " + iter->second->m_source->getFileName() + " and " + surf->getFileName()); } } /* * Verify target surfaces use unique structure and * there is a source surface using the same structure */ for (const auto surf : targetSurfaces) { const StructureEnum::Enum structure = surf->getStructure(); auto iter = m_surfaces.find(structure); if (iter == m_surfaces.end()) { throw AlgorithmException("Target surface " + surf->getFileName() + " uses structure " + StructureEnum::toName(structure) + " but there is no source surface with the structure."); } else { SourceTargetSurface* sts = iter->second; CaretAssert(sts); if (sts->m_target == NULL) { sts->m_target = surf; } else { throw AlgorithmException("Target surfaces have same structure: " + sts->m_target->getFileName() + " and " + surf->getFileName()); } } } /* * Verify no missing target surfaces */ for (auto iter : m_surfaces) { SourceTargetSurface* sts = iter.second; CaretAssert(sts); CaretAssert(sts->m_source); if (sts->m_target == NULL) { throw AlgorithmException("There is no target surface with structure " + StructureEnum::toName(iter.first) + " for source surface " + sts->m_source->getFileName()); } } } /** * @return Algorithm internal weight */ float AlgorithmAnnotationResample::getAlgorithmInternalWeight() { /* * override this if needed, if the progress bar isn't smooth */ return 1.0f; } /** * @return Algorithm sub-algorithm weight */ float AlgorithmAnnotationResample::getSubAlgorithmWeight() { /* * If you use a subalgorithm */ //return AlgorithmInsertNameHere::getAlgorithmWeight() return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmAnnotationResample.h000066400000000000000000000052171360521144700263630ustar00rootroot00000000000000#ifndef __ALGORITHM_ANNOTATION_RESAMPLE_H__ #define __ALGORITHM_ANNOTATION_RESAMPLE_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AbstractAlgorithm.h" namespace caret { class Annotation; class AlgorithmAnnotationResample : public AbstractAlgorithm { private: AlgorithmAnnotationResample(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmAnnotationResample(ProgressObject* myProgObj, AnnotationFile* annotationFile, const AString& annotationFileName, const std::vector& sourceSurfaces, const std::vector& targetSurfaces); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); private: class SourceTargetSurface { public: SourceTargetSurface(const SurfaceFile* source) : m_source(source), m_target(NULL) { } const SurfaceFile* m_source; const SurfaceFile* m_target; }; std::map m_surfaces; void setupSurfaces(const std::vector& sourceSurfaces, const std::vector& targetSurfaces); void resampleAnnotation(Annotation* ann); }; typedef TemplateAutoOperation AutoAlgorithmAnnotationResample; } // namespace #endif //__ALGORITHM_ANNOTATION_RESAMPLE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmBorderResample.cxx000066400000000000000000000171001360521144700260330ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmBorderResample.h" #include "AlgorithmException.h" #include "Border.h" #include "BorderFile.h" #include "GiftiLabelTable.h" #include "GiftiMetaData.h" #include "SurfaceFile.h" #include "SurfaceProjectedItem.h" #include "SurfaceProjectionBarycentric.h" #include "SignedDistanceHelper.h" using namespace caret; using namespace std; AString AlgorithmBorderResample::getCommandSwitch() { return "-border-resample"; } AString AlgorithmBorderResample::getShortDescription() { return "RESAMPLE A BORDER FILE TO A DIFFERENT MESH"; } OperationParameters* AlgorithmBorderResample::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addBorderParameter(1, "border-in", "the border file to resample"); ret->addSurfaceParameter(2, "current-sphere", "a sphere surface with the mesh that the metric is currently on"); ret->addSurfaceParameter(3, "new-sphere", "a sphere surface that is in register with and has the desired output mesh"); ret->addBorderOutputParameter(4, "border-out", "the output border file"); ret->setHelpText( AString("Resamples a border file, given two spherical surfaces that are in register. ") + "Only borders that have the same structure as current-sphere will be resampled." ); return ret; } void AlgorithmBorderResample::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { BorderFile* borderIn = myParams->getBorder(1); SurfaceFile* curSphere = myParams->getSurface(2); SurfaceFile* newSphere = myParams->getSurface(3); BorderFile* borderOut = myParams->getOutputBorder(4); AlgorithmBorderResample(myProgObj, borderIn, curSphere, newSphere, borderOut); } AlgorithmBorderResample::AlgorithmBorderResample(ProgressObject* myProgObj, const BorderFile* borderIn, const SurfaceFile* curSphere, const SurfaceFile* newSphere, BorderFile* borderOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); SurfaceFile curAdjust, newAdjust; adjustRadius(curSphere, curAdjust); adjustRadius(newSphere, newAdjust); borderOut->clear(); *(borderOut->getClassColorTable()) = *(borderIn->getClassColorTable()); *(borderOut->getNameColorTable()) = *(borderIn->getNameColorTable()); *(borderOut->getFileMetaData()) = *(borderIn->getFileMetaData()); borderOut->setStructure(curSphere->getStructure()); borderOut->setNumberOfNodes(newSphere->getNumberOfNodes()); int numBorderMDKeys = borderIn->getNumberOfBorderMetadataKeys(); for (int m = 0; m < numBorderMDKeys; ++m) { borderOut->addBorderMetadataKey(borderIn->getBorderMetadataKey(m));//rely on the keys being in order added } int numBorders = borderIn->getNumberOfBorders(); CaretPointer myHelp = newAdjust.getSignedDistanceHelper(); for (int i = 0; i < numBorders; ++i) { const Border* inputBorder = borderIn->getBorder(i); if (inputBorder->getStructure() != curSphere->getStructure()) continue; CaretPointer outputBorder(new Border());//in case something throws outputBorder->setName(inputBorder->getName()); outputBorder->setClassName(inputBorder->getClassName()); outputBorder->setClosed(inputBorder->isClosed()); int numPoints = inputBorder->getNumberOfPoints(); for (int j = 0; j < numPoints; ++j) { CaretPointer outPoint(new SurfaceProjectedItem());//ditto float coord[3]; const SurfaceProjectedItem* myItem = inputBorder->getPoint(j); if (!myItem->getBarycentricProjection()->isValid()) throw AlgorithmException("input file has a border point without barycentric projection");//because we never want to use van essen projection or straight coords bool valid = myItem->getBarycentricProjection()->unprojectToSurface(curAdjust, coord, 0.0f, true);//should really be "from" surface - "true" makes it not use the signed distance above surface, if present if (!valid) throw AlgorithmException("input file has a border point that is invalid for the current sphere"); BarycentricInfo myBaryInfo; myHelp->barycentricWeights(coord, myBaryInfo); outPoint->setStructure(inputBorder->getStructure()); outPoint->getBarycentricProjection()->setTriangleNodes(myBaryInfo.nodes); outPoint->getBarycentricProjection()->setTriangleAreas(myBaryInfo.baryWeights); outPoint->getBarycentricProjection()->setProjectionSurfaceNumberOfNodes(newSphere->getNumberOfNodes()); outPoint->getBarycentricProjection()->setValid(true); outputBorder->addPoint(outPoint.releasePointer());//NOTE: addPoint currently takes ownership of a RAW POINTER - shared_ptr won't release the pointer, so this function would need to be deprecated } borderOut->addBorder(outputBorder.releasePointer());//NOTE: again, ownership of RAW POINTER for (int m = 0; m < numBorderMDKeys; ++m)//HACK: will do this repeatedly for multi-part borders, but oh well { AString value = borderIn->getBorderMetadataValue(inputBorder->getName(), inputBorder->getClassName(), m); if (value != "") borderOut->setBorderMetadataValue(inputBorder->getName(), inputBorder->getClassName(), m, value); } } } void AlgorithmBorderResample::adjustRadius(const SurfaceFile* in, SurfaceFile& out) { int numNodes = in->getNumberOfNodes(); out = *in;//easiest way to set topology, etc CaretAssert(numNodes > 1); int numNodes3 = numNodes * 3; const float* coordData = in->getCoordinateData(); Vector3D tempData = coordData;//gets the first 3 floats float mindist = tempData.length(); if (mindist != mindist) throw CaretException("found NaN coordinate in an input sphere"); float maxdist = mindist; out.setCoordinate(0, tempData / mindist * 100.0f); const float TOLERANCE = 1.001f; for (int i = 3; i < numNodes3; i += 3) { tempData = coordData + i; float tempf = tempData.length(); if (tempf != tempf) throw CaretException("found NaN coordinate in an input sphere"); if (tempf < mindist) { mindist = tempf; } if (tempf > maxdist) { maxdist = tempf; } out.setCoordinate(i / 3, tempData / tempf * 100.0f); } if (mindist * TOLERANCE <= maxdist) { throw AlgorithmException("input surfaces must be spheres"); } } float AlgorithmBorderResample::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmBorderResample::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmBorderResample.h000066400000000000000000000034271360521144700254670ustar00rootroot00000000000000#ifndef __ALGORITHM_BORDER_RESAMPLE_H__ #define __ALGORITHM_BORDER_RESAMPLE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmBorderResample : public AbstractAlgorithm { AlgorithmBorderResample(); void adjustRadius(const SurfaceFile* in, SurfaceFile& out); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmBorderResample(ProgressObject* myProgObj, const BorderFile* borderIn, const SurfaceFile* curSphere, const SurfaceFile* newSphere, BorderFile* borderOut); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmBorderResample; } #endif //__ALGORITHM_BORDER_RESAMPLE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmBorderToVertices.cxx000066400000000000000000000320031360521144700263510ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmBorderToVertices.h" #include "AlgorithmException.h" #include "Border.h" #include "BorderFile.h" #include "CaretAssert.h" #include "GeodesicHelper.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "SurfaceProjectedItem.h" #include "SurfaceProjectionBarycentric.h" #include "Vector3D.h" #include #include using namespace caret; using namespace std; AString AlgorithmBorderToVertices::getCommandSwitch() { return "-border-to-vertices"; } AString AlgorithmBorderToVertices::getShortDescription() { return "DRAW BORDERS AS VERTICES IN A METRIC FILE"; } OperationParameters* AlgorithmBorderToVertices::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface the borders are drawn on"); ret->addBorderParameter(2, "border-file", "the border file"); ret->addMetricOutputParameter(3, "metric-out", "the output metric file"); OptionalParameter* borderOpt = ret->createOptionalParameter(4, "-border", "create ROI for only one border"); borderOpt->addStringParameter(1, "name", "the name of the border"); ret->setHelpText( AString("Outputs a metric with 1s on vertices that follow a border, and 0s elsewhere. ") + "By default, a separate metric column is created for each border." ); return ret; } void AlgorithmBorderToVertices::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* mySurf = myParams->getSurface(1); BorderFile* myBorderFile = myParams->getBorder(2); MetricFile* myMetricOut = myParams->getOutputMetric(3); bool borderSelectMode = false; AString borderName; OptionalParameter* borderOpt = myParams->getOptionalParameter(4); if (borderOpt->m_present) { borderName = borderOpt->getString(1); borderSelectMode = true; } if (borderSelectMode) { AlgorithmBorderToVertices(myProgObj, mySurf, myBorderFile, myMetricOut, borderName); } else { AlgorithmBorderToVertices(myProgObj, mySurf, myBorderFile, myMetricOut); } } AlgorithmBorderToVertices::AlgorithmBorderToVertices(ProgressObject* myProgObj, const SurfaceFile* mySurf, const BorderFile* myBorderFile, MetricFile* myMetricOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); //TODO: check structure against surface set > borderCounter;//"multi-part border" behavior int numBorderParts = myBorderFile->getNumberOfBorders();//total number of parts for (int i = 0; i < numBorderParts; ++i) { const Border* thisBorderPart = myBorderFile->getBorder(i); borderCounter.insert(make_pair(thisBorderPart->getName(), thisBorderPart->getClassName())); } int numBorders = (int)borderCounter.size(); myMetricOut->setNumberOfNodesAndColumns(mySurf->getNumberOfNodes(), numBorders); myMetricOut->setStructure(mySurf->getStructure()); CaretPointer myGeoHelp = mySurf->getGeodesicHelper(); vector used(numBorderParts, false);//tracking for "multi-part border" behavior int curBorder = 0; for (int i = 0; i < numBorderParts; ++i)//visit borders in file order (of first piece), not set sorted order { if (used[i]) continue;//skip previously used parts vector colScratch(mySurf->getNumberOfNodes(), 0.0f); const Border* refBorderPart = myBorderFile->getBorder(i); AString borderName = refBorderPart->getName(), className = refBorderPart->getClassName(); myMetricOut->setColumnName(curBorder, borderName); for (int j = i; j < numBorderParts; ++j)//we could store the matching info in the counting set instead { const Border* thisBorderPart = myBorderFile->getBorder(j); if (thisBorderPart->getName() == borderName && thisBorderPart->getClassName() == className) { used[j] = true;//now we can actually do stuff with the border part int numBorderPoints = thisBorderPart->getNumberOfPoints(); if (numBorderPoints < 1) continue; const SurfaceProjectionBarycentric* thisBary = thisBorderPart->getPoint(0)->getBarycentricProjection(); CaretAssert(thisBary->isValid()); const float* thisWeights = thisBary->getTriangleAreas(); const int32_t* thisNodes = thisBary->getTriangleNodes(); int useNode = 0; Vector3D curPos;//initializes to 0 float weightSum = 0.0f; for (int n = 0; n < 3; ++n) { if (thisWeights[n] > 0.0f) { curPos += thisWeights[n] * Vector3D(mySurf->getCoordinate(thisNodes[n])); weightSum += thisWeights[n]; } if (thisWeights[n] > thisWeights[useNode]) useNode = n;//get closest node to point } curPos /= weightSum; int curNode = thisBary->getTriangleNodes()[useNode]; colScratch[curNode] = 1.0f;//if there is only one border point, make sure it leaves a mark for (int k = 1; k < numBorderPoints; ++k) { thisBary = thisBorderPart->getPoint(k)->getBarycentricProjection(); CaretAssert(thisBary->isValid()); thisWeights = thisBary->getTriangleAreas(); thisNodes = thisBary->getTriangleNodes(); useNode = 0; weightSum = 0.0f; Vector3D nextPos;//initializes to 0 for (int n = 0; n < 3; ++n) { if (thisWeights[n] > 0.0f) { nextPos += thisWeights[n] * Vector3D(mySurf->getCoordinate(thisNodes[n])); weightSum += thisWeights[n]; } if (thisWeights[n] > thisWeights[useNode]) useNode = n;//get closest node to point } nextPos /= weightSum; int nextNode = thisBary->getTriangleNodes()[useNode]; vector pathNodes; vector pathDists;//not used, but mandatory output myGeoHelp->getPathAlongLineSegment(curNode, nextNode, curPos, nextPos, pathNodes, pathDists); int pathLength = (int)pathNodes.size(); for (int m = 0; m < pathLength; ++m) { colScratch[pathNodes[m]] = 1.0f; } curNode = nextNode; curPos = nextPos; } if (thisBorderPart->isClosed()) { thisBary = thisBorderPart->getPoint(0)->getBarycentricProjection(); CaretAssert(thisBary->isValid()); thisWeights = thisBary->getTriangleAreas(); thisNodes = thisBary->getTriangleNodes(); useNode = 0; weightSum = 0.0f; Vector3D nextPos;//initializes to 0 for (int n = 0; n < 3; ++n) { if (thisWeights[n] > 0.0f) { nextPos += thisWeights[n] * Vector3D(mySurf->getCoordinate(thisNodes[n])); weightSum += thisWeights[n]; } if (thisWeights[n] > thisWeights[useNode]) useNode = n;//get closest node to point } nextPos /= weightSum; int nextNode = thisBary->getTriangleNodes()[useNode]; vector pathNodes; vector pathDists;//not used, but mandatory output myGeoHelp->getPathAlongLineSegment(curNode, nextNode, curPos, nextPos, pathNodes, pathDists); int pathLength = (int)pathNodes.size(); for (int m = 0; m < pathLength; ++m) { colScratch[pathNodes[m]] = 1.0f; } } } } myMetricOut->setValuesForColumn(curBorder, colScratch.data()); ++curBorder; } } AlgorithmBorderToVertices::AlgorithmBorderToVertices(ProgressObject* myProgObj, const SurfaceFile* mySurf, const BorderFile* myBorderFile, MetricFile* myMetricOut, const AString& borderName) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); //TODO: check structure against surface bool first = true; AString className; int numBorderParts = myBorderFile->getNumberOfBorders();//total number of parts myMetricOut->setNumberOfNodesAndColumns(mySurf->getNumberOfNodes(), 1); myMetricOut->setStructure(mySurf->getStructure()); myMetricOut->setColumnName(0, borderName); CaretPointer myGeoHelp = mySurf->getGeodesicHelper(); vector colScratch(mySurf->getNumberOfNodes(), 0.0f); for (int i = 0; i < numBorderParts; ++i) { const Border* thisBorderPart = myBorderFile->getBorder(i); if (thisBorderPart->getName() == borderName) { if (first) { className = thisBorderPart->getClassName(); } else { if (thisBorderPart->getClassName() != className) throw AlgorithmException("border name matches borders with different classes"); } } int numBorderPoints = thisBorderPart->getNumberOfPoints(); if (numBorderPoints < 1) continue; const SurfaceProjectionBarycentric* thisBary = thisBorderPart->getPoint(0)->getBarycentricProjection(); CaretAssert(thisBary->isValid()); const float* thisWeights = thisBary->getTriangleAreas(); const int32_t* thisNodes = thisBary->getTriangleNodes(); int useNode = 0; Vector3D curPos;//initializes to 0 float weightSum = 0.0f; for (int n = 0; n < 3; ++n) { if (thisWeights[n] > 0.0f) { curPos += thisWeights[n] * Vector3D(mySurf->getCoordinate(thisNodes[n])); weightSum += thisWeights[n]; } if (thisWeights[n] > thisWeights[useNode]) useNode = n;//get closest node to point } curPos /= weightSum; int curNode = thisBary->getTriangleNodes()[useNode]; colScratch[curNode] = 1.0f;//if there is only one border point, make sure it leaves a mark for (int k = 1; k < numBorderPoints; ++k) { thisBary = thisBorderPart->getPoint(k)->getBarycentricProjection(); CaretAssert(thisBary->isValid()); thisWeights = thisBary->getTriangleAreas(); thisNodes = thisBary->getTriangleNodes(); useNode = 0; weightSum = 0.0f; Vector3D nextPos;//initializes to 0 for (int n = 0; n < 3; ++n) { if (thisWeights[n] > 0.0f) { nextPos += thisWeights[n] * Vector3D(mySurf->getCoordinate(thisNodes[n])); weightSum += thisWeights[n]; } if (thisWeights[n] > thisWeights[useNode]) useNode = n;//get closest node to point } nextPos /= weightSum; int nextNode = thisBary->getTriangleNodes()[useNode]; vector pathNodes; vector pathDists;//not used, but mandatory output myGeoHelp->getPathAlongLineSegment(curNode, nextNode, curPos, nextPos, pathNodes, pathDists); int pathLength = (int)pathNodes.size(); for (int m = 0; m < pathLength; ++m) { colScratch[pathNodes[m]] = 1.0f; } curNode = nextNode; curPos = nextPos; } } myMetricOut->setValuesForColumn(0, colScratch.data()); } float AlgorithmBorderToVertices::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmBorderToVertices::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmBorderToVertices.h000066400000000000000000000036011360521144700260000ustar00rootroot00000000000000#ifndef __ALGORITHM_BORDER_TO_VERTEX_PATH_H__ #define __ALGORITHM_BORDER_TO_VERTEX_PATH_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmBorderToVertices : public AbstractAlgorithm { AlgorithmBorderToVertices(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmBorderToVertices(ProgressObject* myProgObj, const SurfaceFile* mySurf, const BorderFile* myBorderFile, MetricFile* myMetricOut); AlgorithmBorderToVertices(ProgressObject* myProgObj, const SurfaceFile* mySurf, const BorderFile* myBorderFile, MetricFile* myMetricOut, const AString& borderName); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmBorderToVertices; } #endif //__ALGORITHM_BORDER_TO_VERTEX_PATH_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiAllLabelsToROIs.cxx000066400000000000000000000125701360521144700270050ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiAllLabelsToROIs.h" #include "AlgorithmException.h" #include "CiftiFile.h" #include "GiftiLabelTable.h" #include #include #include using namespace caret; using namespace std; AString AlgorithmCiftiAllLabelsToROIs::getCommandSwitch() { return "-cifti-all-labels-to-rois"; } AString AlgorithmCiftiAllLabelsToROIs::getShortDescription() { return "MAKE ROIS FROM ALL LABELS IN A CIFTI LABEL MAP"; } OperationParameters* AlgorithmCiftiAllLabelsToROIs::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "label-in", "the input cifti label file"); ret->addStringParameter(2, "map", "the number or name of the label map to use"); ret->addCiftiOutputParameter(3, "cifti-out", "the output cifti file"); ret->setHelpText( AString("The output cifti file is a dscalar file with a column (map) for each label in the specified input map, other than the ??? label, ") + "each of which contains a binary ROI of all brainordinates that are set to the corresponding label.\n\n" + "Most of the time, specifying '1' for the argument will do what is desired." ); return ret; } void AlgorithmCiftiAllLabelsToROIs::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* myLabel = myParams->getCifti(1); AString mapID = myParams->getString(2); if (myLabel->getCiftiXMLOld().getMappingType(CiftiXMLOld::ALONG_ROW) != CIFTI_INDEX_TYPE_LABELS) { throw AlgorithmException("mapping type along row must be labels");//because we need to translate map ID to index before algorithm, but want a more useful error if the reason it fails is mapping type } int whichMap = myLabel->getCiftiXMLOld().getMapIndexFromNameOrNumber(CiftiXMLOld::ALONG_ROW, mapID); if (whichMap == -1) { throw AlgorithmException("invalid map number or name specified"); } CiftiFile* myCiftiOut = myParams->getOutputCifti(3); AlgorithmCiftiAllLabelsToROIs(myProgObj, myLabel, whichMap, myCiftiOut); } AlgorithmCiftiAllLabelsToROIs::AlgorithmCiftiAllLabelsToROIs(ProgressObject* myProgObj, const CiftiFile* myLabel, const int& whichMap, CiftiFile* myCiftiOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const CiftiXMLOld& myXML = myLabel->getCiftiXMLOld(); if (myXML.getMappingType(CiftiXMLOld::ALONG_ROW) != CIFTI_INDEX_TYPE_LABELS) { throw AlgorithmException("mapping type along row must be labels");//check again, in case it is used from somewhere other than useParameters() } const GiftiLabelTable* myTable = myXML.getLabelTableForRowIndex(whichMap); int32_t unusedKey = myTable->getUnassignedLabelKey();//WARNING: this actually MODIFIES the label table if the ??? key doesn't exist set myKeys = myTable->getKeys(); int numKeys = (int)myKeys.size(); if (numKeys < 2) { throw AlgorithmException("label table doesn't contain any keys besides the ??? key"); } map keyToMap;//lookup from keys to column CiftiXMLOld outXML = myXML; outXML.resetDirectionToScalars(CiftiXMLOld::ALONG_ROW, numKeys - 1); int counter = 0; for (set::iterator iter = myKeys.begin(); iter != myKeys.end(); ++iter) { if (*iter == unusedKey) continue;//skip the ??? key keyToMap[*iter] = counter; outXML.setMapNameForIndex(CiftiXMLOld::ALONG_ROW, counter, myTable->getLabelName(*iter)); ++counter; } myCiftiOut->setCiftiXML(outXML); vector outRowScratch(numKeys - 1, 0.0f), inRowScratch(myXML.getNumberOfColumns()); int64_t numRows = myXML.getNumberOfRows(); for (int64_t i = 0; i < numRows; ++i) { myLabel->getRow(inRowScratch.data(), i); int32_t thisKey = (int32_t)floor(inRowScratch[whichMap] + 0.5f); map::iterator iter = keyToMap.find(thisKey); if (iter != keyToMap.end()) { outRowScratch[iter->second] = 1.0f;//set the single element for the correct map } myCiftiOut->setRow(outRowScratch.data(), i); if (iter != keyToMap.end()) { outRowScratch[iter->second] = 0.0f;//and rezero it to get ready for the next row } } } float AlgorithmCiftiAllLabelsToROIs::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiAllLabelsToROIs::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiAllLabelsToROIs.h000066400000000000000000000033431360521144700264300ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_ALL_LABELS_TO_ROIS_H__ #define __ALGORITHM_CIFTI_ALL_LABELS_TO_ROIS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmCiftiAllLabelsToROIs : public AbstractAlgorithm { AlgorithmCiftiAllLabelsToROIs(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiAllLabelsToROIs(ProgressObject* myProgObj, const CiftiFile* myLabel, const int& whichMap, CiftiFile* myCiftiOut); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiAllLabelsToROIs; } #endif //__ALGORITHM_CIFTI_ALL_LABELS_TO_ROIS_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiAverage.cxx000066400000000000000000000247121360521144700254650ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiAverage.h" #include "AlgorithmException.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPointer.h" #include "CiftiFile.h" #include "MathFunctions.h" #include using namespace caret; using namespace std; AString AlgorithmCiftiAverage::getCommandSwitch() { return "-cifti-average"; } AString AlgorithmCiftiAverage::getShortDescription() { return "AVERAGE CIFTI FILES"; } OperationParameters* AlgorithmCiftiAverage::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiOutputParameter(1, "cifti-out", "output cifti file"); OptionalParameter* excludeOpt = ret->createOptionalParameter(2, "-exclude-outliers", "exclude outliers by standard deviation of each element across files"); excludeOpt->addDoubleParameter(1, "sigma-below", "number of standard deviations below the mean to include"); excludeOpt->addDoubleParameter(2, "sigma-above", "number of standard deviations above the mean to include"); ParameterComponent* ciftiOpt = ret->createRepeatableParameter(3, "-cifti", "specify an input file"); ciftiOpt->addCiftiParameter(1, "cifti-in", "the input cifti file"); OptionalParameter* weightOpt = ciftiOpt->createOptionalParameter(1, "-weight", "give a weight for this file"); weightOpt->addDoubleParameter(1, "weight", "the weight to use"); ret->setHelpText( AString("Averages cifti files together. ") + "Files without -weight specified are given a weight of 1. " + "If -exclude-outliers is specified, at each element, the data across all files is taken as a set, its unweighted mean and sample standard deviation are found, " + "and values outside the specified number of standard deviations are excluded from the (potentially weighted) average at that element." ); return ret; } void AlgorithmCiftiAverage::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* ciftiOut = myParams->getOutputCifti(1); vector ciftiList;//this is just so that it can pass them to the algorithm vector weights; const vector& myInstances = *(myParams->getRepeatableParameterInstances(3)); for (int i = 0; i < (int)myInstances.size(); ++i) { ciftiList.push_back(myInstances[i]->getCifti(1)); OptionalParameter* weightOpt = myInstances[i]->getOptionalParameter(1); if (weightOpt->m_present) { weights.push_back((float)weightOpt->getDouble(1)); } else { weights.push_back(1.0f); } } OptionalParameter* excludeOpt = myParams->getOptionalParameter(2); if (excludeOpt->m_present) { AlgorithmCiftiAverage(myProgObj, ciftiList, excludeOpt->getDouble(1), excludeOpt->getDouble(2), ciftiOut, &weights); } else { AlgorithmCiftiAverage(myProgObj, ciftiList, ciftiOut, &weights); } } AlgorithmCiftiAverage::AlgorithmCiftiAverage(ProgressObject* myProgObj, const vector& ciftiList, CiftiFile* ciftiOut, const vector* weightsPtr) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (ciftiList.size() == 0) { throw AlgorithmException("no files specified"); } if (weightsPtr != NULL && ciftiList.size() != weightsPtr->size()) { throw AlgorithmException("number of weights doesn't match number of input cifti files"); } CaretAssert(ciftiList[0] != NULL); CiftiXML baseXML = ciftiList[0]->getCiftiXML(); if (baseXML.getNumberOfDimensions() != 2) throw AlgorithmException("cifti average currently only supports 2D files"); int numRows = baseXML.getDimensionLength(CiftiXML::ALONG_COLUMN), rowSize = baseXML.getDimensionLength(CiftiXML::ALONG_ROW), numFiles = (int)ciftiList.size(); for (int i = 1; i < numFiles; ++i) { CaretAssert(ciftiList[i] != NULL); if (!baseXML.approximateMatch(ciftiList[i]->getCiftiXML()))//requires at least length to match, often more restrictive { throw AlgorithmException("cifti file '" + ciftiList[i]->getFileName() + "' does not match earlier inputs"); } } ciftiOut->setCiftiXML(baseXML); vector accum(rowSize); vector myrow(rowSize); for (int i = 0; i < numRows; ++i) { vector weightaccum(rowSize, 0.0); for (int j = 0; j < rowSize; ++j) { accum[j] = 0.0; } for (int j = 0; j < numFiles; ++j) { ciftiList[j]->getRow(myrow.data(), i); if (weightsPtr == NULL) { for (int k = 0; k < rowSize; ++k) { if (MathFunctions::isNumeric(myrow[k])) { weightaccum[k] += 1.0; accum[k] += myrow[k]; } } } else { float weight = (*weightsPtr)[j]; for (int k = 0; k < rowSize; ++k) { if (MathFunctions::isNumeric(myrow[k])) { weightaccum[k] += weight; accum[k] += myrow[k] * weight; } } } } for (int k = 0; k < rowSize; ++k) { if (weightaccum[k] != 0.0) { myrow[k] = accum[k] / weightaccum[k]; } else { myrow[k] = 0.0f; } } ciftiOut->setRow(myrow.data(), i); } } AlgorithmCiftiAverage::AlgorithmCiftiAverage(ProgressObject* myProgObj, const vector& ciftiList, const float& sigmaBelow, const float& sigmaAbove, CiftiFile* ciftiOut, const std::vector* weightsPtr): AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (ciftiList.size() < 2) { throw AlgorithmException("fewer than 2 files specified with outlier exclusion"); } if (weightsPtr != NULL && ciftiList.size() != weightsPtr->size()) { throw AlgorithmException("number of weights doesn't match number of input cifti files"); } CaretAssert(ciftiList[0] != NULL); CiftiXML baseXML = ciftiList[0]->getCiftiXML(); if (baseXML.getNumberOfDimensions() != 2) throw AlgorithmException("cifti average currently only supports 2D files"); int numRows = baseXML.getDimensionLength(CiftiXML::ALONG_COLUMN), rowSize = baseXML.getDimensionLength(CiftiXML::ALONG_ROW), numFiles = (int)ciftiList.size(); for (int i = 1; i < numFiles; ++i) { CaretAssert(ciftiList[i] != NULL); if (!baseXML.approximateMatch(ciftiList[i]->getCiftiXML())) { throw AlgorithmException("cifti files do not match"); } } bool haveWarned = false; ciftiOut->setCiftiXML(baseXML); vector > myrows(numFiles, vector(rowSize)); for (int i = 0; i < numRows; ++i) { for (int j = 0; j < numFiles; ++j) { ciftiList[j]->getRow(myrows[j].data(), i); } vector outrow(rowSize); for (int k = 0; k < rowSize; ++k) { double accum = 0.0; double weightaccum = 0.0; int nonnumeric = 0; for (int j = 0; j < numFiles; ++j) { if (MathFunctions::isNumeric(myrows[j][k])) { accum += myrows[j][k]; } else { ++nonnumeric; } } if (nonnumeric >= numFiles - 1) { if (!haveWarned) { CaretLogWarning("found element where less than 2 files have numeric values"); haveWarned = true; } outrow[k] = 0.0f; } else { float mean = accum / (numFiles - nonnumeric); accum = 0.0; for (int j = 0; j < numFiles; ++j) { if (MathFunctions::isNumeric(myrows[j][k])) { float temp = myrows[j][k] - mean; accum += temp * temp; } } float stdev = sqrt(accum / (numFiles - 1 - nonnumeric)); float cutoffLow = mean - sigmaBelow * stdev; float cutoffHigh = mean + sigmaAbove * stdev; accum = 0.0; for (int j = 0; j < numFiles; ++j) { if (myrows[j][k] > cutoffLow && myrows[j][k] < cutoffHigh)//implicitly excludes NaN and inf { if (weightsPtr != NULL) { float weight = (*weightsPtr)[j]; accum += myrows[j][k] * weight; weightaccum += weight; } else { accum += myrows[j][k]; weightaccum += 1.0; } } } if (weightaccum != 0.0) { outrow[k] = accum / weightaccum; } else { outrow[k] = 0.0f; } } } ciftiOut->setRow(outrow.data(), i); } } float AlgorithmCiftiAverage::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiAverage::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiAverage.h000066400000000000000000000036661360521144700251170ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_AVERAGE_H__ #define __ALGORITHM_CIFTI_AVERAGE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include namespace caret { class AlgorithmCiftiAverage : public AbstractAlgorithm { AlgorithmCiftiAverage(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiAverage(ProgressObject* myProgObj, const std::vector& ciftiList, CiftiFile* ciftiOut, const std::vector* weightsPtr = NULL); AlgorithmCiftiAverage(ProgressObject* myProgObj, const std::vector& ciftiList, const float& sigmaBelow, const float& sigmaAbove, CiftiFile* ciftiOut, const std::vector* weightsPtr = NULL); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiAverage; } #endif //__ALGORITHM_CIFTI_AVERAGE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiAverageDenseROI.cxx000066400000000000000000000662731360521144700270260ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiAverageDenseROI.h" #include "AlgorithmException.h" #include "CaretLogger.h" #include "CiftiFile.h" #include "FileInformation.h" #include "SurfaceFile.h" #include "MetricFile.h" #include "VolumeFile.h" #include #include #include using namespace caret; using namespace std; AString AlgorithmCiftiAverageDenseROI::getCommandSwitch() { return "-cifti-average-dense-roi"; } AString AlgorithmCiftiAverageDenseROI::getShortDescription() { return "AVERAGE CIFTI ROWS ACROSS SUBJECTS BY ROI"; } OperationParameters* AlgorithmCiftiAverageDenseROI::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiOutputParameter(1, "cifti-out", "output cifti dscalar file"); OptionalParameter* ciftiRoiOpt = ret->createOptionalParameter(2, "-cifti-roi", "cifti file containing combined weights"); ciftiRoiOpt->addCiftiParameter(1, "roi-cifti", "the roi cifti file"); ciftiRoiOpt->createOptionalParameter(2, "-in-memory", "cache the roi in memory so that it isn't re-read for each input cifti"); OptionalParameter* leftRoiOpt = ret->createOptionalParameter(3, "-left-roi", "weights to use for left hempsphere"); leftRoiOpt->addMetricParameter(1, "roi-metric", "the left roi as a metric file"); OptionalParameter* rightRoiOpt = ret->createOptionalParameter(4, "-right-roi", "weights to use for right hempsphere"); rightRoiOpt->addMetricParameter(1, "roi-metric", "the right roi as a metric file"); OptionalParameter* cerebRoiOpt = ret->createOptionalParameter(5, "-cerebellum-roi", "weights to use for cerebellum surface"); cerebRoiOpt->addMetricParameter(1, "roi-metric", "the cerebellum roi as a metric file"); OptionalParameter* volRoiOpt = ret->createOptionalParameter(6, "-vol-roi", "voxel weights to use"); volRoiOpt->addVolumeParameter(1, "roi-vol", "the roi volume file"); OptionalParameter* leftAreaSurfOpt = ret->createOptionalParameter(7, "-left-area-surf", "specify the left surface for vertex area correction"); leftAreaSurfOpt->addSurfaceParameter(1, "left-surf", "the left surface file"); OptionalParameter* rightAreaSurfOpt = ret->createOptionalParameter(8, "-right-area-surf", "specify the right surface for vertex area correction"); rightAreaSurfOpt->addSurfaceParameter(1, "right-surf", "the right surface file"); OptionalParameter* cerebAreaSurfOpt = ret->createOptionalParameter(9, "-cerebellum-area-surf", "specify the cerebellum surface for vertex area correction"); cerebAreaSurfOpt->addSurfaceParameter(1, "cerebellum-surf", "the cerebellum surface file"); ParameterComponent* ciftiOpt = ret->createRepeatableParameter(10, "-cifti", "specify an input cifti file"); ciftiOpt->addCiftiParameter(1, "cifti-in", "a cifti file to average across"); ret->setHelpText( AString("Averages rows for each map of the ROI(s), across all files. ") + "ROI maps are treated as weighting functions, including negative values. " + "For efficiency, ensure that everything that is not intended to be used is zero in the ROI map. " + "If -cifti-roi is specified, -left-roi, -right-roi, -cerebellum-roi, and -vol-roi must not be specified. " + "If multiple non-cifti ROI files are specified, they must have the same number of columns." ); return ret; } void AlgorithmCiftiAverageDenseROI::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* ciftiOut = myParams->getOutputCifti(1); CiftiFile* ciftiROI = NULL; OptionalParameter* ciftiRoiOpt = myParams->getOptionalParameter(2); if (ciftiRoiOpt->m_present) { ciftiROI = ciftiRoiOpt->getCifti(1); if (ciftiRoiOpt->getOptionalParameter(2)->m_present) ciftiROI->convertToInMemory(); } MetricFile* leftROI = NULL; OptionalParameter* leftRoiOpt = myParams->getOptionalParameter(3); if (leftRoiOpt->m_present) { if (ciftiROI != NULL) throw AlgorithmException("-cifti-roi cannot be used with any other ROI option"); leftROI = leftRoiOpt->getMetric(1); } MetricFile* rightROI = NULL; OptionalParameter* rightRoiOpt = myParams->getOptionalParameter(4); if (rightRoiOpt->m_present) { if (ciftiROI != NULL) throw AlgorithmException("-cifti-roi cannot be used with any other ROI option"); rightROI = rightRoiOpt->getMetric(1); } MetricFile* cerebROI = NULL; OptionalParameter* cerebRoiOpt = myParams->getOptionalParameter(5); if (cerebRoiOpt->m_present) { if (ciftiROI != NULL) throw AlgorithmException("-cifti-roi cannot be used with any other ROI option"); cerebROI = cerebRoiOpt->getMetric(1); } VolumeFile* volROI = NULL; OptionalParameter* volRoiOpt = myParams->getOptionalParameter(6); if (volRoiOpt->m_present) { if (ciftiROI != NULL) throw AlgorithmException("-cifti-roi cannot be used with any other ROI option"); volROI = volRoiOpt->getVolume(1); } SurfaceFile* leftAreaSurf = NULL; OptionalParameter* leftAreaSurfOpt = myParams->getOptionalParameter(7); if (leftAreaSurfOpt->m_present) { leftAreaSurf = leftAreaSurfOpt->getSurface(1); } SurfaceFile* rightAreaSurf = NULL; OptionalParameter* rightAreaSurfOpt = myParams->getOptionalParameter(8); if (rightAreaSurfOpt->m_present) { rightAreaSurf = rightAreaSurfOpt->getSurface(1); } SurfaceFile* cerebAreaSurf = NULL; OptionalParameter* cerebAreaSurfOpt = myParams->getOptionalParameter(9); if (cerebAreaSurfOpt->m_present) { cerebAreaSurf = cerebAreaSurfOpt->getSurface(1); } vector ciftiList; const vector& ciftiInstances = *(myParams->getRepeatableParameterInstances(10)); for (int i = 0; i < (int)ciftiInstances.size(); ++i) { ciftiList.push_back(ciftiInstances[i]->getCifti(1)); } if (ciftiROI != NULL) { AlgorithmCiftiAverageDenseROI(myProgObj, ciftiList, ciftiOut, ciftiROI, leftAreaSurf, rightAreaSurf, cerebAreaSurf); } else { AlgorithmCiftiAverageDenseROI(myProgObj, ciftiList, ciftiOut, leftROI, rightROI, cerebROI, volROI, leftAreaSurf, rightAreaSurf, cerebAreaSurf); } } AlgorithmCiftiAverageDenseROI::AlgorithmCiftiAverageDenseROI(ProgressObject* myProgObj, const vector& ciftiList, CiftiFile* ciftiOut, const MetricFile* leftROI, const MetricFile* rightROI, const MetricFile* cerebROI, const VolumeFile* volROI, const SurfaceFile* leftAreaSurf, const SurfaceFile* rightAreaSurf, const SurfaceFile* cerebAreaSurf) : AbstractAlgorithm(myProgObj) { CaretAssert(ciftiOut != NULL); LevelProgress myProgress(myProgObj); int numCifti = (int)ciftiList.size(); if (numCifti < 1) throw AlgorithmException("no cifti files specified to average"); const CiftiXML& baseXML = ciftiList[0]->getCiftiXML(); if (baseXML.getNumberOfDimensions() != 2) throw AlgorithmException("this operation currently only supports 2D cifti"); if (baseXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) throw AlgorithmException("inputs must have brain models along columns"); int rowSize = baseXML.getDimensionLength(CiftiXML::ALONG_ROW); bool first = true; const CaretMappableDataFile* nameFile = NULL; int numMaps = -1; vector leftAreaData, rightAreaData, cerebAreaData; float* leftAreaPointer = NULL, *rightAreaPointer = NULL, *cerebAreaPointer = NULL; if (leftROI != NULL) { if (leftAreaSurf != NULL) { if (leftROI->getNumberOfNodes() != leftAreaSurf->getNumberOfNodes()) throw AlgorithmException("left area surface and left roi have different number of nodes"); leftAreaSurf->computeNodeAreas(leftAreaData); leftAreaPointer = leftAreaData.data(); } first = false; numMaps = leftROI->getNumberOfMaps(); nameFile = leftROI; } if (rightROI != NULL) { if (rightAreaSurf != NULL) { if (rightROI->getNumberOfNodes() != rightAreaSurf->getNumberOfNodes()) throw AlgorithmException("right area surface and right roi have different number of nodes"); rightAreaSurf->computeNodeAreas(rightAreaData); rightAreaPointer = rightAreaData.data(); } if (first) { first = false; numMaps = rightROI->getNumberOfMaps(); nameFile = rightROI; } else { if (rightROI->getNumberOfMaps() != numMaps) throw AlgorithmException("right roi has a different number of maps"); } } if (cerebROI != NULL) { if (cerebAreaSurf != NULL) { if (cerebROI->getNumberOfNodes() != cerebAreaSurf->getNumberOfNodes()) throw AlgorithmException("cerebellum area surface and cerebellum roi have different number of nodes"); cerebAreaSurf->computeNodeAreas(cerebAreaData); cerebAreaPointer = cerebAreaData.data(); } if (first) { first = false; numMaps = cerebROI->getNumberOfMaps(); nameFile = cerebROI; } else { if (cerebROI->getNumberOfMaps() != numMaps) throw AlgorithmException("cerebellum roi has a different number of maps"); } } if (volROI != NULL) { if (first) { first = false; numMaps = volROI->getNumberOfMaps(); nameFile = volROI; } else { if (volROI->getNumberOfMaps() != numMaps) throw AlgorithmException("volume roi has a different number of maps"); } } if (first) throw AlgorithmException("no roi files provided"); for (int i = 0; i < numCifti; ++i) { const CiftiXML& thisXML = ciftiList[i]->getCiftiXML(); if (!thisXML.approximateMatch(baseXML)) throw AlgorithmException("cifti files do not match between #1 and #" + AString::number(i + 1)); } if (leftROI != NULL) { verifySurfaceComponent(ciftiList[0], StructureEnum::CORTEX_LEFT, leftROI); } if (rightROI != NULL) { verifySurfaceComponent(ciftiList[0], StructureEnum::CORTEX_RIGHT, rightROI); } if (cerebROI != NULL) { verifySurfaceComponent(ciftiList[0], StructureEnum::CEREBELLUM, cerebROI); } if (volROI != NULL) { verifyVolumeComponent(ciftiList[0], volROI); } vector > accum(numMaps, vector(rowSize, 0.0)); vector denom(numMaps, 0.0); for (int i = 0; i < numCifti; ++i) { if (leftROI != NULL) { processSurfaceComponent(accum, denom, ciftiList[i], StructureEnum::CORTEX_LEFT, leftROI, leftAreaPointer); } if (rightROI != NULL) { processSurfaceComponent(accum, denom, ciftiList[i], StructureEnum::CORTEX_RIGHT, rightROI, rightAreaPointer); } if (cerebROI != NULL) { processSurfaceComponent(accum, denom, ciftiList[i], StructureEnum::CEREBELLUM, cerebROI, cerebAreaPointer); } if (volROI != NULL) { processVolumeComponent(accum, denom, ciftiList[i], volROI); } } CiftiXML newXml; newXml.setNumberOfDimensions(2); newXml.setMap(CiftiXML::ALONG_COLUMN, *(baseXML.getMap(CiftiXML::ALONG_ROW))); CiftiScalarsMap rowMap; rowMap.setLength(numMaps); for (int i = 0; i < numMaps; ++i) { rowMap.setMapName(i, nameFile->getMapName(i)); } newXml.setMap(CiftiXML::ALONG_ROW, rowMap); ciftiOut->setCiftiXML(newXml); vector outRow(numMaps); for (int j = 0; j < numMaps; ++j) { if (denom[j] == 0.0) throw AlgorithmException("no data matched one of the ROI(s)"); } for (int i = 0; i < rowSize; ++i) { for (int j = 0; j < numMaps; ++j) { outRow[j] = accum[j][i] / denom[j]; } ciftiOut->setRow(outRow.data(), i); } } AlgorithmCiftiAverageDenseROI::AlgorithmCiftiAverageDenseROI(ProgressObject* myProgObj, const vector& ciftiList, CiftiFile* ciftiOut, const CiftiFile* ciftiROI, const SurfaceFile* leftAreaSurf, const SurfaceFile* rightAreaSurf, const SurfaceFile* cerebAreaSurf): AbstractAlgorithm(myProgObj) { CaretAssert(ciftiOut != NULL); LevelProgress myProgress(myProgObj); int numCifti = (int)ciftiList.size(); if (numCifti < 1) throw AlgorithmException("no cifti files specified to average"); const CiftiXML& baseXML = ciftiList[0]->getCiftiXML(), &roiXML = ciftiROI->getCiftiXML(); if (baseXML.getNumberOfDimensions() != 2 || roiXML.getNumberOfDimensions() != 2) throw AlgorithmException("this operation currently only supports 2D cifti"); if (baseXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) throw AlgorithmException("inputs must have brain models along columns"); const CiftiBrainModelsMap& baseBrainModels = baseXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); if (baseBrainModels != *(roiXML.getMap(CiftiXML::ALONG_COLUMN))) throw AlgorithmException("cifti roi mapping along columns doesn't match input cifti"); int rowSize = baseXML.getDimensionLength(CiftiXML::ALONG_ROW); vector leftAreaData, rightAreaData, cerebAreaData; float* leftAreaPointer = NULL, *rightAreaPointer = NULL, *cerebAreaPointer = NULL; if (leftAreaSurf != NULL) { if (baseBrainModels.getSurfaceNumberOfNodes(StructureEnum::CORTEX_LEFT) != leftAreaSurf->getNumberOfNodes()) { throw AlgorithmException("left area surface and left cortex cifti structure have different number of nodes"); } leftAreaSurf->computeNodeAreas(leftAreaData); leftAreaPointer = leftAreaData.data(); } if (rightAreaSurf != NULL) { if (baseBrainModels.getSurfaceNumberOfNodes(StructureEnum::CORTEX_RIGHT) != rightAreaSurf->getNumberOfNodes()) { throw AlgorithmException("right area surface and right cortex cifti structure have different number of nodes"); } rightAreaSurf->computeNodeAreas(rightAreaData); rightAreaPointer = rightAreaData.data(); } if (cerebAreaSurf != NULL) { if (baseBrainModels.getSurfaceNumberOfNodes(StructureEnum::CEREBELLUM) != cerebAreaSurf->getNumberOfNodes()) { throw AlgorithmException("cerebellum area surface and cerebellum cortex cifti structure have different number of nodes"); } cerebAreaSurf->computeNodeAreas(cerebAreaData); cerebAreaPointer = cerebAreaData.data(); } for (int i = 1; i < numCifti; ++i) { const CiftiXML& thisXML = ciftiList[i]->getCiftiXML(); if (!thisXML.approximateMatch(baseXML)) throw AlgorithmException("cifti files do not match between #1 and #" + AString::number(i + 1)); } int numMaps = roiXML.getDimensionLength(CiftiXML::ALONG_ROW); vector > accum(numMaps, vector(rowSize, 0.0)); vector denom(numMaps, 0.0); for (int i = 0; i < numCifti; ++i) { processCifti(accum, denom, ciftiList[i], ciftiROI, leftAreaPointer, rightAreaPointer, cerebAreaPointer); } CiftiXML newXml; newXml.setNumberOfDimensions(2); newXml.setMap(CiftiXML::ALONG_COLUMN, *(baseXML.getMap(CiftiXML::ALONG_ROW))); CiftiScalarsMap rowMap; rowMap.setLength(numMaps); const CiftiMappingType& nameMap = *(roiXML.getMap(CiftiXML::ALONG_ROW)); for (int i = 0; i < numMaps; ++i) { rowMap.setMapName(i, nameMap.getIndexName(i)); } newXml.setMap(CiftiXML::ALONG_ROW, rowMap); ciftiOut->setCiftiXML(newXml); vector outRow(numMaps); for (int j = 0; j < numMaps; ++j) { if (denom[j] == 0.0) throw AlgorithmException("no data matched one of the ROI(s)"); } for (int i = 0; i < rowSize; ++i) { for (int j = 0; j < numMaps; ++j) { outRow[j] = accum[j][i] / denom[j]; } ciftiOut->setRow(outRow.data(), i); } } void AlgorithmCiftiAverageDenseROI::verifySurfaceComponent(const CiftiFile* myCifti, const StructureEnum::Enum& myStruct, const MetricFile* myRoi) { const CiftiXML& myXml = myCifti->getCiftiXML(); CaretAssert(myXml.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::BRAIN_MODELS);//should be checked in the algorithm constructor const CiftiBrainModelsMap& brainModelsMap = myXml.getBrainModelsMap(CiftiXML::ALONG_COLUMN); if (!brainModelsMap.hasSurfaceData(myStruct)) { CaretLogWarning("cifti files are missing structure " + StructureEnum::toName(myStruct)); return; } if (myRoi->getNumberOfNodes() != brainModelsMap.getSurfaceNumberOfNodes(myStruct)) { throw AlgorithmException("cifti number of vertices does not match roi for structure " + StructureEnum::toName(myStruct)); } } void AlgorithmCiftiAverageDenseROI::processSurfaceComponent(vector >& accum, vector& denom, const CiftiFile* myCifti, const StructureEnum::Enum& myStruct, const MetricFile* myRoi, const float* myAreas) { const CiftiXML& myXml = myCifti->getCiftiXML(); CaretAssert(myXml.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::BRAIN_MODELS);//should be checked in the algorithm constructor const CiftiBrainModelsMap& brainModelsMap = myXml.getBrainModelsMap(CiftiXML::ALONG_COLUMN); if (!brainModelsMap.hasSurfaceData(myStruct)) { return; } if (myRoi->getNumberOfNodes() != brainModelsMap.getSurfaceNumberOfNodes(myStruct)) throw AlgorithmException("cifti number of vertices does not match roi"); int rowSize = myXml.getDimensionLength(CiftiXML::ALONG_ROW); vector rowScratch(rowSize); CaretAssert(rowScratch.size() == accum[0].size()); vector myMap = brainModelsMap.getSurfaceMap(myStruct); int mapSize = (int)myMap.size(); int numMaps = myRoi->getNumberOfMaps(); if (myAreas == NULL) { for (int i = 0; i < mapSize; ++i) { const int& myNode = myMap[i].m_surfaceNode; bool dataLoaded = false; for (int m = 0; m < numMaps; ++m) { const float roiVal = myRoi->getValue(myNode, m); if (roiVal != 0.0f) { if (!dataLoaded) { myCifti->getRow(rowScratch.data(), myMap[i].m_ciftiIndex); dataLoaded = true; } for (int j = 0; j < rowSize; ++j) { accum[m][j] += rowScratch[j] * roiVal; } denom[m] += roiVal; } } } } else { for (int i = 0; i < mapSize; ++i) { const int& myNode = myMap[i].m_surfaceNode; bool dataLoaded = false; for (int m = 0; m < numMaps; ++m) { const float& roiVal = myRoi->getValue(myNode, m); if (roiVal != 0.0f) { const float weight = roiVal * myAreas[myMap[i].m_surfaceNode]; if (!dataLoaded) { myCifti->getRow(rowScratch.data(), myMap[i].m_ciftiIndex); dataLoaded = true; } for (int j = 0; j < rowSize; ++j) { accum[m][j] += rowScratch[j] * weight; } denom[m] += weight; } } } } } void AlgorithmCiftiAverageDenseROI::verifyVolumeComponent(const CiftiFile* myCifti, const VolumeFile* volROI) { const CiftiXML& myXml = myCifti->getCiftiXML(); CaretAssert(myXml.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::BRAIN_MODELS);//should be checked in the algorithm constructor const CiftiBrainModelsMap& brainModelsMap = myXml.getBrainModelsMap(CiftiXML::ALONG_COLUMN); if (!volROI->matchesVolumeSpace(brainModelsMap.getVolumeSpace())) throw AlgorithmException("cifti files don't match the ROI volume's space"); } void AlgorithmCiftiAverageDenseROI::processVolumeComponent(vector >& accum, vector& denom, const CiftiFile* myCifti, const VolumeFile* volROI) { const CiftiXML& myXml = myCifti->getCiftiXML(); CaretAssert(myXml.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::BRAIN_MODELS);//should be checked in the algorithm constructor const CiftiBrainModelsMap& brainModelsMap = myXml.getBrainModelsMap(CiftiXML::ALONG_COLUMN); if (!volROI->matchesVolumeSpace(brainModelsMap.getVolumeSpace())) throw AlgorithmException("cifti files don't match the ROI volume's space"); int rowSize = myXml.getDimensionLength(CiftiXML::ALONG_ROW); vector rowScratch(rowSize); CaretAssert(rowScratch.size() == accum[0].size()); vector myMap = brainModelsMap.getFullVolumeMap(); int mapSize = (int)myMap.size(); int numMaps = volROI->getNumberOfMaps(); for (int i = 0; i < mapSize; ++i) { bool dataLoaded = false; if (!volROI->indexValid(myMap[i].m_ijk)) throw AlgorithmException("cifti file lists invalid voxels"); for (int m = 0; m < numMaps; ++m) { const float& roiVal = volROI->getValue(myMap[i].m_ijk, m); if (roiVal != 0.0f) { if (!dataLoaded) { myCifti->getRow(rowScratch.data(), myMap[i].m_ciftiIndex); dataLoaded = true; } for (int j = 0; j < rowSize; ++j) { accum[m][j] += rowScratch[j] * roiVal; } denom[m] += roiVal; } } } } void AlgorithmCiftiAverageDenseROI::processCifti(vector >& accum, vector& denom, const CiftiFile* myCifti, const CiftiFile* ciftiROI, const float* leftAreas, const float* rightAreas, const float* cerebAreas) { const CiftiXML& myXml = myCifti->getCiftiXML();//same along columns for data and roi, we already checked CaretAssert(myXml.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::BRAIN_MODELS);//should be checked in the algorithm constructor const CiftiBrainModelsMap& brainModelsMap = myXml.getBrainModelsMap(CiftiXML::ALONG_COLUMN); int rowSize = myXml.getDimensionLength(CiftiXML::ALONG_ROW); vector surfList = brainModelsMap.getSurfaceStructureList(); int numMaps = ciftiROI->getNumberOfColumns(); vector dataScratch(rowSize), roiScratch(numMaps); for (int s = 0; s < (int)surfList.size(); ++s) { const float* myAreas = NULL; switch (surfList[s]) { case StructureEnum::CORTEX_LEFT: myAreas = leftAreas; break; case StructureEnum::CORTEX_RIGHT: myAreas = rightAreas; break; case StructureEnum::CEREBELLUM: myAreas = cerebAreas; break; default: throw AlgorithmException("found unexpected surface structure in cifti files: " + StructureEnum::toName(surfList[s])); } vector myMap = brainModelsMap.getSurfaceMap(surfList[s]); int mapSize = (int)myMap.size(); if (myAreas != NULL) { for (int i = 0; i < mapSize; ++i) { ciftiROI->getRow(roiScratch.data(), myMap[i].m_ciftiIndex); const float& thisArea = myAreas[myMap[i].m_surfaceNode]; bool dataLoaded = false; for (int m = 0; m < numMaps; ++m)//ROI maps, not cifti mapping { const float& roiValue = roiScratch[m]; if (roiValue != 0.0f) { if (!dataLoaded) { myCifti->getRow(dataScratch.data(), i); dataLoaded = true; } const float weight = roiValue * thisArea; for (int j = 0; j < rowSize; ++j) { accum[m][j] += dataScratch[j] * weight; } denom[m] += weight; } } } } else { for (int i = 0; i < mapSize; ++i) { ciftiROI->getRow(roiScratch.data(), myMap[i].m_ciftiIndex); bool dataLoaded = false; for (int m = 0; m < numMaps; ++m)//ROI maps, not cifti mapping { const float& roiValue = roiScratch[m]; if (roiValue != 0.0f) { if (!dataLoaded) { myCifti->getRow(dataScratch.data(), i); dataLoaded = true; } for (int j = 0; j < rowSize; ++j) { accum[m][j] += dataScratch[j] * roiValue; } denom[m] += roiValue; } } } } } vector myMap = brainModelsMap.getFullVolumeMap();//again, we know columns match between ROI and data int mapSize = (int)myMap.size(); for (int i = 0; i < mapSize; ++i) { ciftiROI->getRow(roiScratch.data(), myMap[i].m_ciftiIndex); bool dataLoaded = false; for (int m = 0; m < numMaps; ++m)//ROI maps, not cifti mapping { const float& roiValue = roiScratch[m]; if (roiValue != 0.0f) { if (!dataLoaded) { myCifti->getRow(dataScratch.data(), i); dataLoaded = true; } for (int j = 0; j < rowSize; ++j) { accum[m][j] += dataScratch[j] * roiValue; } denom[m] += roiValue; } } } } float AlgorithmCiftiAverageDenseROI::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiAverageDenseROI::getSubAlgorithmWeight() { return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiAverageDenseROI.h000066400000000000000000000064251360521144700264440ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_AVERAGE_DENSE_ROI_H__ #define __ALGORITHM_CIFTI_AVERAGE_DENSE_ROI_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "StructureEnum.h" #include namespace caret { class AlgorithmCiftiAverageDenseROI : public AbstractAlgorithm { AlgorithmCiftiAverageDenseROI(); void verifySurfaceComponent(const CiftiFile* myCifti, const StructureEnum::Enum& myStruct, const MetricFile* myRoi); void processSurfaceComponent(std::vector >& accum, std::vector& denom, const CiftiFile* myCifti, const StructureEnum::Enum& myStruct, const MetricFile* myRoi, const float* myAreas); void verifyVolumeComponent(const CiftiFile* myCifti, const VolumeFile* volROI); void processVolumeComponent(std::vector >& accum, std::vector& denom, const CiftiFile* myCifti, const VolumeFile* volROI); void processCifti(std::vector >& accum, std::vector& denom, const CiftiFile* myCifti, const CiftiFile* ciftiROI, const float* leftAreas, const float* rightAreas, const float* cerebAreas); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiAverageDenseROI(ProgressObject* myProgObj, const std::vector& ciftiList, CiftiFile* ciftiOut, const CiftiFile* ciftiROI, const SurfaceFile* leftAreaSurf = NULL, const SurfaceFile* rightAreaSurf = NULL, const SurfaceFile* cerebAreaSurf = NULL); AlgorithmCiftiAverageDenseROI(ProgressObject* myProgObj, const std::vector& ciftiList, CiftiFile* ciftiOut, const MetricFile* leftROI = NULL, const MetricFile* rightROI = NULL, const MetricFile* cerebROI = NULL, const VolumeFile* volROI = NULL, const SurfaceFile* leftAreaSurf = NULL, const SurfaceFile* rightAreaSurf = NULL, const SurfaceFile* cerebAreaSurf = NULL); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiAverageDenseROI; } #endif //__ALGORITHM_CIFTI_AVERAGE_DENSE_ROI_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiAverageROICorrelation.cxx000066400000000000000000000740571360521144700302500ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiAverageROICorrelation.h" #include "AlgorithmException.h" #include "CaretLogger.h" #include "CaretOMP.h" #include "CiftiFile.h" #include "FileInformation.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "VolumeFile.h" #include #include #include #include using namespace caret; using namespace std; AString AlgorithmCiftiAverageROICorrelation::getCommandSwitch() { return "-cifti-average-roi-correlation"; } AString AlgorithmCiftiAverageROICorrelation::getShortDescription() { return "CORRELATE ROI AVERAGE WITH ALL ROWS THEN AVERAGE ACROSS SUBJECTS"; } OperationParameters* AlgorithmCiftiAverageROICorrelation::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiOutputParameter(1, "cifti-out", "output cifti file"); OptionalParameter* ciftiRoiOpt = ret->createOptionalParameter(2, "-cifti-roi", "cifti file containing combined weights"); ciftiRoiOpt->addCiftiParameter(1, "roi-cifti", "the roi cifti file"); ciftiRoiOpt->createOptionalParameter(2, "-in-memory", "cache the roi in memory so that it isn't re-read for each input cifti"); OptionalParameter* leftRoiOpt = ret->createOptionalParameter(3, "-left-roi", "weights to use for left hempsphere"); leftRoiOpt->addMetricParameter(1, "roi-metric", "the left roi as a metric file"); OptionalParameter* rightRoiOpt = ret->createOptionalParameter(4, "-right-roi", "weights to use for right hempsphere"); rightRoiOpt->addMetricParameter(1, "roi-metric", "the right roi as a metric file"); OptionalParameter* cerebRoiOpt = ret->createOptionalParameter(5, "-cerebellum-roi", "weights to use for cerebellum surface"); cerebRoiOpt->addMetricParameter(1, "roi-metric", "the cerebellum roi as a metric file"); OptionalParameter* volRoiOpt = ret->createOptionalParameter(6, "-vol-roi", "voxel weights to use"); volRoiOpt->addVolumeParameter(1, "roi-vol", "the roi volume file"); OptionalParameter* leftAreaSurfOpt = ret->createOptionalParameter(7, "-left-area-surf", "specify the left surface for vertex area correction"); leftAreaSurfOpt->addSurfaceParameter(1, "left-surf", "the left surface file"); OptionalParameter* rightAreaSurfOpt = ret->createOptionalParameter(8, "-right-area-surf", "specify the right surface for vertex area correction"); rightAreaSurfOpt->addSurfaceParameter(1, "right-surf", "the right surface file"); OptionalParameter* cerebAreaSurfOpt = ret->createOptionalParameter(9, "-cerebellum-area-surf", "specify the cerebellum surface for vertex area correction"); cerebAreaSurfOpt->addSurfaceParameter(1, "cerebellum-surf", "the cerebellum surface file"); ParameterComponent* ciftiOpt = ret->createRepeatableParameter(10, "-cifti", "specify an input cifti file"); ciftiOpt->addCiftiParameter(1, "cifti-in", "a cifti file to average across"); ret->setHelpText( AString("Averages rows for each map of the ROI(s), takes the correlation of each ROI average to the rest of the rows in the same file, applies the fisher small z transform, then averages the results across all files. ") + "ROIs are always treated as weighting functions, including negative values. " + "For efficiency, ensure that everything that is not intended to be used is zero in the ROI map. " + "If -cifti-roi is specified, -left-roi, -right-roi, -cerebellum-roi, and -vol-roi must not be specified. " + "If multiple non-cifti ROI files are specified, they must have the same number of columns." ); return ret; } void AlgorithmCiftiAverageROICorrelation::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* ciftiOut = myParams->getOutputCifti(1); CiftiFile* ciftiROI = NULL; OptionalParameter* ciftiRoiOpt = myParams->getOptionalParameter(2); if (ciftiRoiOpt->m_present) { ciftiROI = ciftiRoiOpt->getCifti(1); if (ciftiRoiOpt->getOptionalParameter(2)->m_present) ciftiROI->convertToInMemory(); } MetricFile* leftROI = NULL; OptionalParameter* leftRoiOpt = myParams->getOptionalParameter(3); if (leftRoiOpt->m_present) { if (ciftiROI != NULL) throw AlgorithmException("-cifti-roi cannot be used with any other ROI option"); leftROI = leftRoiOpt->getMetric(1); } MetricFile* rightROI = NULL; OptionalParameter* rightRoiOpt = myParams->getOptionalParameter(4); if (rightRoiOpt->m_present) { if (ciftiROI != NULL) throw AlgorithmException("-cifti-roi cannot be used with any other ROI option"); rightROI = rightRoiOpt->getMetric(1); } MetricFile* cerebROI = NULL; OptionalParameter* cerebRoiOpt = myParams->getOptionalParameter(5); if (cerebRoiOpt->m_present) { if (ciftiROI != NULL) throw AlgorithmException("-cifti-roi cannot be used with any other ROI option"); cerebROI = cerebRoiOpt->getMetric(1); } VolumeFile* volROI = NULL; OptionalParameter* volRoiOpt = myParams->getOptionalParameter(6); if (volRoiOpt->m_present) { if (ciftiROI != NULL) throw AlgorithmException("-cifti-roi cannot be used with any other ROI option"); volROI = volRoiOpt->getVolume(1); } SurfaceFile* leftAreaSurf = NULL; OptionalParameter* leftAreaSurfOpt = myParams->getOptionalParameter(7); if (leftAreaSurfOpt->m_present) { leftAreaSurf = leftAreaSurfOpt->getSurface(1); } SurfaceFile* rightAreaSurf = NULL; OptionalParameter* rightAreaSurfOpt = myParams->getOptionalParameter(8); if (rightAreaSurfOpt->m_present) { rightAreaSurf = rightAreaSurfOpt->getSurface(1); } SurfaceFile* cerebAreaSurf = NULL; OptionalParameter* cerebAreaSurfOpt = myParams->getOptionalParameter(9); if (cerebAreaSurfOpt->m_present) { cerebAreaSurf = cerebAreaSurfOpt->getSurface(1); } vector ciftiList; const vector& ciftiInputs = *(myParams->getRepeatableParameterInstances(10)); if (ciftiInputs.size() == 0) throw AlgorithmException("at least one -cifti input is required"); for (int i = 0; i < (int)ciftiInputs.size(); ++i) { ciftiList.push_back(ciftiInputs[i]->getCifti(1)); } if (ciftiROI != NULL) { AlgorithmCiftiAverageROICorrelation(myProgObj, ciftiList, ciftiOut, ciftiROI, leftAreaSurf, rightAreaSurf, cerebAreaSurf); } else { AlgorithmCiftiAverageROICorrelation(myProgObj, ciftiList, ciftiOut, leftROI, rightROI, cerebROI, volROI, leftAreaSurf, rightAreaSurf, cerebAreaSurf); } } AlgorithmCiftiAverageROICorrelation::AlgorithmCiftiAverageROICorrelation(ProgressObject* myProgObj, const vector& ciftiList, CiftiFile* ciftiOut, const MetricFile* leftROI, const MetricFile* rightROI, const MetricFile* cerebROI, const VolumeFile* volROI, const SurfaceFile* leftAreaSurf, const SurfaceFile* rightAreaSurf, const SurfaceFile* cerebAreaSurf) : AbstractAlgorithm(myProgObj) { CaretAssert(ciftiOut != NULL); LevelProgress myProgress(myProgObj); int numCifti = (int)ciftiList.size(); if (numCifti < 1) throw AlgorithmException("no cifti files specified to average"); const CiftiXMLOld& baseXML = ciftiList[0]->getCiftiXMLOld(); int rowSize = baseXML.getNumberOfColumns(); int colSize = baseXML.getNumberOfRows(); bool first = true; const CaretMappableDataFile* nameFile = NULL; int numMaps = -1; vector leftAreaData, rightAreaData, cerebAreaData; float* leftAreaPointer = NULL, *rightAreaPointer = NULL, *cerebAreaPointer = NULL; if (leftROI != NULL) { if (leftAreaSurf != NULL) { if (leftROI->getNumberOfNodes() != leftAreaSurf->getNumberOfNodes()) throw AlgorithmException("left area surface and left roi have different number of nodes"); leftAreaSurf->computeNodeAreas(leftAreaData); leftAreaPointer = leftAreaData.data(); } first = false; numMaps = leftROI->getNumberOfMaps(); nameFile = leftROI; } if (rightROI != NULL) { if (rightAreaSurf != NULL) { if (rightROI->getNumberOfNodes() != rightAreaSurf->getNumberOfNodes()) throw AlgorithmException("right area surface and right roi have different number of nodes"); rightAreaSurf->computeNodeAreas(rightAreaData); rightAreaPointer = rightAreaData.data(); } if (first) { first = false; numMaps = rightROI->getNumberOfMaps(); nameFile = rightROI; } else { if (rightROI->getNumberOfMaps() != numMaps) throw AlgorithmException("right roi has a different number of maps"); } } if (cerebROI != NULL) { if (cerebAreaSurf != NULL) { if (cerebROI->getNumberOfNodes() != cerebAreaSurf->getNumberOfNodes()) throw AlgorithmException("cerebellum area surface and cerebellum roi have different number of nodes"); cerebAreaSurf->computeNodeAreas(cerebAreaData); cerebAreaPointer = cerebAreaData.data(); } if (first) { first = false; numMaps = cerebROI->getNumberOfMaps(); nameFile = cerebROI; } else { if (cerebROI->getNumberOfMaps() != numMaps) throw AlgorithmException("cerebellum roi has a different number of maps"); } } if (volROI != NULL) { if (first) { first = false; numMaps = volROI->getNumberOfMaps(); nameFile = volROI; } else { if (volROI->getNumberOfMaps() != numMaps) throw AlgorithmException("volume roi has a different number of maps"); } } if (first) throw AlgorithmException("no roi files provided"); for (int i = 0; i < numCifti; ++i) { const CiftiXMLOld& thisXML = ciftiList[i]->getCiftiXMLOld(); if (!thisXML.mappingMatches(CiftiXMLOld::ALONG_COLUMN, baseXML, CiftiXMLOld::ALONG_COLUMN)) throw AlgorithmException("cifti space does not match between cifti #1 and #" + AString::number(i + 1)); if (thisXML.getNumberOfColumns() != rowSize) throw AlgorithmException("row length doesn't match between cifti #1 and #" + AString::number(i + 1)); if (leftROI != NULL) { verifySurfaceComponent(i, ciftiList[i], StructureEnum::CORTEX_LEFT, leftROI); } if (rightROI != NULL) { verifySurfaceComponent(i, ciftiList[i], StructureEnum::CORTEX_RIGHT, rightROI); } if (cerebROI != NULL) { verifySurfaceComponent(i, ciftiList[i], StructureEnum::CEREBELLUM, cerebROI); } if (volROI != NULL) { verifyVolumeComponent(i, ciftiList[i], volROI); } } vector > tempresult(colSize, vector(numMaps)); CiftiXMLOld newXml = baseXML; newXml.resetRowsToScalars(numMaps); for (int i = 0; i < numMaps; ++i) { newXml.setMapNameForIndex(CiftiXMLOld::ALONG_ROW, i, nameFile->getMapName(i)); } ciftiOut->setCiftiXML(newXml); if (numCifti > 1)//skip averaging in single subject case { vector > accum(colSize, vector(numMaps, 0.0)); for (int i = 0; i < numCifti; ++i) { processCifti(ciftiList[i], tempresult, leftROI, rightROI, cerebROI, volROI, numMaps, leftAreaPointer, rightAreaPointer, cerebAreaPointer); for (int j = 0; j < colSize; ++j) { for (int myMap = 0; myMap < numMaps; ++myMap) { accum[j][myMap] += tempresult[j][myMap]; } } } for (int i = 0; i < colSize; ++i) { for (int myMap = 0; myMap < numMaps; ++myMap) { tempresult[i][myMap] = accum[i][myMap] / numCifti; } ciftiOut->setRow(tempresult[i].data(), i); } } else { processCifti(ciftiList[0], tempresult, leftROI, rightROI, cerebROI, volROI, numMaps, leftAreaPointer, rightAreaPointer, cerebAreaPointer); for (int i = 0; i < colSize; ++i) { ciftiOut->setRow(tempresult[i].data(), i); } } } AlgorithmCiftiAverageROICorrelation::AlgorithmCiftiAverageROICorrelation(ProgressObject* myProgObj, const vector& ciftiList, CiftiFile* ciftiOut, const CiftiFile* ciftiROI, const SurfaceFile* leftAreaSurf, const SurfaceFile* rightAreaSurf, const SurfaceFile* cerebAreaSurf): AbstractAlgorithm(myProgObj) { CaretAssert(ciftiOut != NULL); LevelProgress myProgress(myProgObj); int numCifti = (int)ciftiList.size(); if (numCifti < 1) throw AlgorithmException("no cifti files specified to average"); const CiftiXMLOld baseXML = ciftiList[0]->getCiftiXMLOld(), roiXML = ciftiROI->getCiftiXMLOld(); int rowSize = baseXML.getNumberOfColumns(); int colSize = baseXML.getNumberOfRows(); int numMaps = ciftiROI->getNumberOfColumns(); if (!baseXML.mappingMatches(CiftiXMLOld::ALONG_COLUMN, roiXML, CiftiXMLOld::ALONG_COLUMN)) throw AlgorithmException("cifti roi doesn't match cifti space of data"); for (int i = 1; i < numCifti; ++i) { if (!baseXML.mappingMatches(CiftiXMLOld::ALONG_COLUMN, ciftiList[i]->getCiftiXMLOld(), CiftiXMLOld::ALONG_COLUMN)) throw AlgorithmException("cifti space does not match between cifti #1 and #" + AString::number(i + 1)); if (ciftiList[i]->getNumberOfColumns() != rowSize) throw AlgorithmException("row length doesn't match between cifti #1 and #" + AString::number(i + 1)); } vector leftAreaData, rightAreaData, cerebAreaData; float* leftAreaPointer = NULL, *rightAreaPointer = NULL, *cerebAreaPointer = NULL; if (leftAreaSurf != NULL) { if (baseXML.getSurfaceNumberOfNodes(CiftiXMLOld::ALONG_COLUMN, StructureEnum::CORTEX_LEFT) != leftAreaSurf->getNumberOfNodes()) { throw AlgorithmException("left area surface and left cortex cifti structure have different number of nodes"); } leftAreaSurf->computeNodeAreas(leftAreaData); leftAreaPointer = leftAreaData.data(); } if (rightAreaSurf != NULL) { if (baseXML.getSurfaceNumberOfNodes(CiftiXMLOld::ALONG_COLUMN, StructureEnum::CORTEX_RIGHT) != rightAreaSurf->getNumberOfNodes()) { throw AlgorithmException("right area surface and right cortex cifti structure have different number of nodes"); } rightAreaSurf->computeNodeAreas(rightAreaData); rightAreaPointer = rightAreaData.data(); } if (cerebAreaSurf != NULL) { if (baseXML.getSurfaceNumberOfNodes(CiftiXMLOld::ALONG_COLUMN, StructureEnum::CEREBELLUM) != cerebAreaSurf->getNumberOfNodes()) { throw AlgorithmException("cerebellum area surface and cerebellum cortex cifti structure have different number of nodes"); } cerebAreaSurf->computeNodeAreas(cerebAreaData); cerebAreaPointer = cerebAreaData.data(); } vector > tempresult(colSize, vector(numMaps)); CiftiXMLOld newXml = baseXML; newXml.resetRowsToScalars(numMaps); for (int i = 0; i < numMaps; ++i) { newXml.setMapNameForIndex(CiftiXMLOld::ALONG_ROW, i, roiXML.getMapNameForRowIndex(i)); } ciftiOut->setCiftiXML(newXml); if (numCifti > 1)//skip averaging in single subject case { vector > accum(colSize, vector(numMaps, 0.0)); for (int i = 0; i < numCifti; ++i) { processCifti(ciftiList[i], tempresult, ciftiROI, numMaps, leftAreaPointer, rightAreaPointer, cerebAreaPointer); for (int j = 0; j < colSize; ++j) { for (int myMap = 0; myMap < numMaps; ++myMap) { accum[j][myMap] += tempresult[j][myMap]; } } } for (int i = 0; i < colSize; ++i) { for (int myMap = 0; myMap < numMaps; ++myMap) { tempresult[i][myMap] = accum[i][myMap] / numCifti; } ciftiOut->setRow(tempresult[i].data(), i); } } else { processCifti(ciftiList[0], tempresult, ciftiROI, numMaps, leftAreaPointer, rightAreaPointer, cerebAreaPointer); for (int i = 0; i < colSize; ++i) { ciftiOut->setRow(tempresult[i].data(), i); } } } void AlgorithmCiftiAverageROICorrelation::verifySurfaceComponent(const int& index, const CiftiFile* myCifti, const StructureEnum::Enum& myStruct, const MetricFile* myRoi) { const CiftiXMLOld& myXml = myCifti->getCiftiXMLOld(); if (!myXml.hasColumnSurfaceData(myStruct)) { CaretLogWarning("cifti file #" + AString::number(index + 1) + " missing structure " + StructureEnum::toName(myStruct)); return; } if (myRoi->getNumberOfNodes() != myXml.getColumnSurfaceNumberOfNodes(myStruct)) throw AlgorithmException("cifti #" + AString::number(index + 1) + " number of vertices does not match roi"); } void AlgorithmCiftiAverageROICorrelation::verifyVolumeComponent(const int& index, const CiftiFile* myCifti, const VolumeFile* volROI) { const CiftiXMLOld& myXml = myCifti->getCiftiXMLOld(); int64_t dims[3]; vector > sform; myXml.getVolumeDimsAndSForm(dims, sform); if (!volROI->matchesVolumeSpace(dims, sform)) throw AlgorithmException("cifti file #" + AString::number(index + 1) + " doesn't match the ROI volume's space"); vector myMap; myXml.getVolumeMapForColumns(myMap); int mapSize = (int)myMap.size(); for (int i = 0; i < mapSize; ++i) { if (!volROI->indexValid(myMap[i].m_ijk)) throw AlgorithmException("cifti file #" + AString::number(index + 1) + " lists invalid voxels"); } } void AlgorithmCiftiAverageROICorrelation::processCifti(const CiftiFile* myCifti, vector >& output, const MetricFile* leftROI, const MetricFile* rightROI,const MetricFile* cerebROI, const VolumeFile* volROI, const int& numMaps, const float* leftAreas, const float* rightAreas, const float* cerebAreas) { int rowSize = myCifti->getNumberOfColumns(); int colSize = myCifti->getNumberOfRows(); vector > average(numMaps, vector(rowSize)); vector rrs(numMaps); for (int myMap = 0; myMap < numMaps; ++myMap) { vector accumarray(rowSize, 0.0); addSurface(myCifti, StructureEnum::CORTEX_LEFT, accumarray, leftROI, myMap, leftAreas);//we don't need to keep track of the kernel sums because we are correlating addSurface(myCifti, StructureEnum::CORTEX_RIGHT, accumarray, rightROI, myMap, rightAreas); addSurface(myCifti, StructureEnum::CEREBELLUM, accumarray, cerebROI, myMap, cerebAreas); addVolume(myCifti, accumarray, volROI, myMap); double accum = 0.0; for (int i = 0; i < rowSize; ++i) { accum += accumarray[i]; } double mean = accum / rowSize; accum = 0.0; for (int i = 0; i < rowSize; ++i) { average[myMap][i] = accumarray[i] - mean;//remove the mean from the average timeseries to optimize the correlation, and change back to float for possible speed improvement accum += average[myMap][i] * average[myMap][i]; } rrs[myMap] = sqrt(accum);//compute this only once } int curRow = 0; #pragma omp CARET_PAR { vector rowscratch(rowSize); #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < colSize; ++i) { int myRow; #pragma omp critical { myRow = curRow;//force sequential reading ++curRow; myCifti->getRow(rowscratch.data(), myRow);//and never read multiple rows at once from the same file } double tempaccum = 0.0;//compute mean of new row for (int j = 0; j < rowSize; ++j) { tempaccum += rowscratch[j]; } float thismean = tempaccum / rowSize; tempaccum = 0.0; for (int j = 0; j < rowSize; ++j) { rowscratch[j] -= thismean;//demean tempaccum += rowscratch[j] * rowscratch[j];//precompute rrs } float thisrrs = sqrt(tempaccum); for (int myMap = 0; myMap < numMaps; ++myMap) { double corraccum = 0.0;//correlate for (int j = 0; j < rowSize; ++j) { corraccum += rowscratch[j] * average[myMap][j];//gather the correlation } corraccum /= rrs[myMap] * thisrrs; if (corraccum > 0.999999) corraccum = 0.999999; if (corraccum < -0.999999) corraccum = -0.999999; output[myRow][myMap] = 0.5 * log((1 + corraccum) / (1 - corraccum));//fisher z transform, needed for averaging } } } } void AlgorithmCiftiAverageROICorrelation::processCifti(const CiftiFile* myCifti, vector >& output, const CiftiFile* ciftiROI, const int& numMaps, const float* leftAreas, const float* rightAreas, const float* cerebAreas) { int rowSize = myCifti->getNumberOfColumns(); int colSize = myCifti->getNumberOfRows(); vector > average(numMaps, vector(rowSize)); vector rrs(numMaps); const CiftiXMLOld& roiXML = ciftiROI->getCiftiXMLOld(); vector surfStructures, ignored; roiXML.getStructureLists(CiftiXMLOld::ALONG_COLUMN, surfStructures, ignored); vector roiScratch(numMaps), dataScratch(rowSize); { vector > accumarray(numMaps, vector(rowSize, 0.0)); for (int whichStruct = 0; whichStruct < (int)surfStructures.size(); ++whichStruct) { const float* areaPtr = NULL; switch (surfStructures[whichStruct]) { case StructureEnum::CORTEX_LEFT: areaPtr = leftAreas; break; case StructureEnum::CORTEX_RIGHT: areaPtr = rightAreas; break; case StructureEnum::CEREBELLUM: areaPtr = cerebAreas; break; default: break; } vector myMap; roiXML.getSurfaceMap(CiftiXMLOld::ALONG_COLUMN, myMap, surfStructures[whichStruct]); for (int i = 0; i < (int)myMap.size(); ++i) { bool dataLoaded = false; ciftiROI->getRow(roiScratch.data(), myMap[i].m_ciftiIndex); for (int j = 0; j < numMaps; ++j) { if (roiScratch[j] != 0.0f) { if (!dataLoaded) { myCifti->getRow(dataScratch.data(), myMap[i].m_ciftiIndex); dataLoaded = true; } if (areaPtr != NULL) { for (int k = 0; k < rowSize; ++k) { accumarray[j][k] += dataScratch[k] * roiScratch[j] * areaPtr[myMap[i].m_surfaceNode]; } } else { for (int k = 0; k < rowSize; ++k) { accumarray[j][k] += dataScratch[k] * roiScratch[j]; } } } } } } vector myMap; roiXML.getVolumeMap(CiftiXMLOld::ALONG_COLUMN, myMap); for (int i = 0; i < (int)myMap.size(); ++i) { bool dataLoaded = false; ciftiROI->getRow(roiScratch.data(), myMap[i].m_ciftiIndex); for (int j = 0; j < numMaps; ++j) { if (roiScratch[j] != 0.0f) { if (!dataLoaded) { myCifti->getRow(dataScratch.data(), myMap[i].m_ciftiIndex); dataLoaded = true; } for (int k = 0; k < rowSize; ++k) { accumarray[j][k] += dataScratch[k] * roiScratch[j]; } } } } for (int i = 0; i < numMaps; ++i) { double accum = 0.0; for (int j = 0; j < rowSize; ++j) { accum += accumarray[i][j]; } float mean = accum / rowSize; accum = 0.0; for (int j = 0; j < rowSize; ++j) { average[i][j] = accumarray[i][j] - mean; accum += average[i][j] * average[i][j]; } vector().swap(accumarray[i]);//hack to free memory before it goes out of scope rrs[i] = sqrt(accum); } } int curRow = 0; #pragma omp CARET_PAR { vector rowscratch(rowSize); #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < colSize; ++i) { int myRow; #pragma omp critical { myRow = curRow;//force sequential reading ++curRow; myCifti->getRow(rowscratch.data(), myRow);//and never read multiple rows at once from the same file } double tempaccum = 0.0;//compute mean of new row for (int j = 0; j < rowSize; ++j) { tempaccum += rowscratch[j]; } float thismean = tempaccum / rowSize; tempaccum = 0.0; for (int j = 0; j < rowSize; ++j) { rowscratch[j] -= thismean;//demean tempaccum += rowscratch[j] * rowscratch[j];//precompute rrs } float thisrrs = sqrt(tempaccum); for (int myMap = 0; myMap < numMaps; ++myMap) { double corraccum = 0.0;//correlate for (int j = 0; j < rowSize; ++j) { corraccum += rowscratch[j] * average[myMap][j];//gather the correlation } corraccum /= rrs[myMap] * thisrrs; if (corraccum > 0.999999) corraccum = 0.999999; if (corraccum < -0.999999) corraccum = -0.999999; output[myRow][myMap] = 0.5 * log((1 + corraccum) / (1 - corraccum));//fisher z transform, needed for averaging } } } } void AlgorithmCiftiAverageROICorrelation::addSurface(const CiftiFile* myCifti, StructureEnum::Enum myStruct, vector& accum, const MetricFile* myRoi, const int& myMap, const float* myAreas) { if (myRoi == NULL) return; vector surfaceMap = myCifti->getCiftiXML().getBrainModelsMap(CiftiXML::ALONG_COLUMN).getSurfaceMap(myStruct); int mapSize = (int)surfaceMap.size(); int rowSize = myCifti->getNumberOfColumns(); vector rowscratch(rowSize); if (myAreas != NULL) { for (int i = 0; i < mapSize; ++i) { float value = myRoi->getValue(surfaceMap[i].m_surfaceNode, myMap); if (value != 0.0f) { float thisArea = myAreas[surfaceMap[i].m_surfaceNode]; myCifti->getRow(rowscratch.data(), surfaceMap[i].m_ciftiIndex); for (int j = 0; j < rowSize; ++j) { accum[j] += rowscratch[j] * value * thisArea; } } } } else { for (int i = 0; i < mapSize; ++i) { float value = myRoi->getValue(surfaceMap[i].m_surfaceNode, myMap); if (value != 0.0f) { myCifti->getRow(rowscratch.data(), surfaceMap[i].m_ciftiIndex); for (int j = 0; j < rowSize; ++j) { accum[j] += rowscratch[j] * value; } } } } } void AlgorithmCiftiAverageROICorrelation::addVolume(const CiftiFile* myCifti, vector& accum, const VolumeFile* myRoi, const int& myMap) { if (myRoi == NULL) return; vector volMap = myCifti->getCiftiXML().getBrainModelsMap(CiftiXML::ALONG_COLUMN).getFullVolumeMap(); int mapSize = (int)volMap.size(); int rowSize = myCifti->getNumberOfColumns(); vector rowscratch(rowSize); for (int i = 0; i < mapSize; ++i) { if (myRoi->getValue(volMap[i].m_ijk, myMap) > 0.0f) { myCifti->getRow(rowscratch.data(), volMap[i].m_ciftiIndex); for (int j = 0; j < rowSize; ++j) { accum[j] += rowscratch[j]; } } } } float AlgorithmCiftiAverageROICorrelation::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiAverageROICorrelation::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiAverageROICorrelation.h000066400000000000000000000070631360521144700276660ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_AVERAGE_ROI_CORRELATION_H__ #define __ALGORITHM_CIFTI_AVERAGE_ROI_CORRELATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "StructureEnum.h" #include namespace caret { class AlgorithmCiftiAverageROICorrelation : public AbstractAlgorithm { AlgorithmCiftiAverageROICorrelation(); void verifySurfaceComponent(const int& index, const CiftiFile* myCifti, const StructureEnum::Enum& myStruct, const MetricFile* myRoi); void verifyVolumeComponent(const int& index, const CiftiFile* myCifti, const VolumeFile* volROI); void processCifti(const CiftiFile* myCifti, std::vector >& output, const MetricFile* leftROI, const MetricFile* rightROI, const MetricFile* cerebROI, const VolumeFile* volROI, const int& numMaps, const float* leftAreas, const float* rightAreas, const float* cerebAreas); void processCifti(const CiftiFile* myCifti, std::vector >& output, const CiftiFile* ciftiROI, const int& numMaps, const float* leftAreas, const float* rightAreas, const float* cerebAreas); void addSurface(const CiftiFile* myCifti, StructureEnum::Enum myStruct, std::vector& accum, const MetricFile* myRoi, const int& myMap, const float* myAreas); void addVolume(const CiftiFile* myCifti, std::vector& accum, const VolumeFile* myRoi, const int& myMap); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiAverageROICorrelation(ProgressObject* myProgObj, const std::vector& ciftiList, CiftiFile* ciftiOut, const MetricFile* leftROI = NULL, const MetricFile* rightROI = NULL, const MetricFile* cerebROI = NULL, const VolumeFile* volROI = NULL, const SurfaceFile* leftAreaSurf = NULL, const SurfaceFile* rightAreaSurf = NULL, const SurfaceFile* cerebAreaSurf = NULL); AlgorithmCiftiAverageROICorrelation(ProgressObject* myProgObj, const std::vector& ciftiList, CiftiFile* ciftiOut, const CiftiFile* ciftiROI, const SurfaceFile* leftAreaSurf = NULL, const SurfaceFile* rightAreaSurf = NULL, const SurfaceFile* cerebAreaSurf = NULL); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiAverageROICorrelation; } #endif //__ALGORITHM_CIFTI_AVERAGE_ROI_CORRELATION_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiCorrelation.cxx000066400000000000000000001024571360521144700263770ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiCorrelation.h" #include "AlgorithmException.h" #include "AlgorithmCiftiSeparate.h" #include "CiftiFile.h" #include "MetricFile.h" #include "VolumeFile.h" #include "CaretLogger.h" #include "MathFunctions.h" #include "CaretOMP.h" #include "FileInformation.h" #include "CaretPointer.h" #include "dot_wrapper.h" #include #include #include using namespace caret; using namespace std; AString AlgorithmCiftiCorrelation::getCommandSwitch() { return "-cifti-correlation"; } AString AlgorithmCiftiCorrelation::getShortDescription() { return "GENERATE CORRELATION OF ROWS IN A CIFTI FILE"; } OperationParameters* AlgorithmCiftiCorrelation::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti", "input cifti file"); ret->addCiftiOutputParameter(2, "cifti-out", "output cifti file"); OptionalParameter* roiOverrideOpt = ret->createOptionalParameter(3, "-roi-override", "perform correlation from a subset of rows to all rows"); OptionalParameter* leftRoiOpt = roiOverrideOpt->createOptionalParameter(1, "-left-roi", "use an roi for left hempsphere"); leftRoiOpt->addMetricParameter(1, "roi-metric", "the left roi as a metric file"); OptionalParameter* rightRoiOpt = roiOverrideOpt->createOptionalParameter(2, "-right-roi", "use an roi for right hempsphere"); rightRoiOpt->addMetricParameter(1, "roi-metric", "the right roi as a metric file"); OptionalParameter* cerebRoiOpt = roiOverrideOpt->createOptionalParameter(3, "-cerebellum-roi", "use an roi for cerebellum"); cerebRoiOpt->addMetricParameter(1, "roi-metric", "the cerebellum roi as a metric file"); OptionalParameter* volRoiOpt = roiOverrideOpt->createOptionalParameter(4, "-vol-roi", "use an roi for volume"); volRoiOpt->addVolumeParameter(1, "roi-vol", "the volume roi file"); OptionalParameter* ciftiRoiOpt = roiOverrideOpt->createOptionalParameter(5, "-cifti-roi", "use a cifti file for combined rois"); ciftiRoiOpt->addCiftiParameter(1, "roi-cifti", "the cifti roi file"); OptionalParameter* weightsOpt = ret->createOptionalParameter(4, "-weights", "specify column weights"); weightsOpt->addStringParameter(1, "weight-file", "text file containing one weight per column"); ret->createOptionalParameter(5, "-fisher-z", "apply fisher small z transform (ie, artanh) to correlation"); ret->createOptionalParameter(7, "-no-demean", "instead of correlation, do dot product of rows, then normalize by diagonal"); ret->createOptionalParameter(8, "-covariance", "compute covariance instead of correlation"); OptionalParameter* memLimitOpt = ret->createOptionalParameter(6, "-mem-limit", "restrict memory usage"); memLimitOpt->addDoubleParameter(1, "limit-GB", "memory limit in gigabytes"); ret->setHelpText( AString("For each row (or each row inside an roi if -roi-override is specified), correlate to all other rows. ") + "The -cifti-roi suboption to -roi-override may not be specified with any other -*-roi suboption, but you may specify the other -*-roi suboptions together.\n\n" + "When using the -fisher-z option, the output is NOT a Z-score, it is artanh(r), to do further math on this output, consider using -cifti-math.\n\n" + "Restricting the memory usage will make it calculate the output in chunks, and if the input file size is more than 70% of the memory limit, " + "it will also read through the input file as rows are required, resulting in several passes through the input file (once per chunk). " + "Memory limit does not need to be an integer, you may also specify 0 to calculate a single output row at a time (this may be very slow)." ); return ret; } void AlgorithmCiftiCorrelation::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* myCifti = myParams->getCifti(1); CiftiFile* myCiftiOut = myParams->getOutputCifti(2); OptionalParameter* roiOverrideOpt = myParams->getOptionalParameter(3); bool roiOverrideMode = roiOverrideOpt->m_present; MetricFile* leftRoi = NULL, *rightRoi = NULL, *cerebRoi = NULL; VolumeFile* volRoi = NULL; CiftiFile* ciftiRoi = NULL; bool ciftiRoiMode = true; if (roiOverrideMode) { OptionalParameter* leftRoiOpt = roiOverrideOpt->getOptionalParameter(1); if (leftRoiOpt->m_present) { leftRoi = leftRoiOpt->getMetric(1); ciftiRoiMode = false; } OptionalParameter* rightRoiOpt = roiOverrideOpt->getOptionalParameter(2); if (rightRoiOpt->m_present) { rightRoi = rightRoiOpt->getMetric(1); ciftiRoiMode = false; } OptionalParameter* cerebRoiOpt = roiOverrideOpt->getOptionalParameter(3); if (cerebRoiOpt->m_present) { cerebRoi = cerebRoiOpt->getMetric(1); ciftiRoiMode = false; } OptionalParameter* volRoiOpt = roiOverrideOpt->getOptionalParameter(4); if (volRoiOpt->m_present) { volRoi = volRoiOpt->getVolume(1); ciftiRoiMode = false; } OptionalParameter* ciftiRoiOpt = roiOverrideOpt->getOptionalParameter(5); if (ciftiRoiOpt->m_present) { if (!ciftiRoiMode) throw AlgorithmException("-cifti-roi cannot be specified with any other -*-roi option"); ciftiRoi = ciftiRoiOpt->getCifti(1); } else { if (ciftiRoiMode) throw AlgorithmException("-roi-override requires a -*-roi suboption"); } } OptionalParameter* weightsOpt = myParams->getOptionalParameter(4); vector* weights = NULL, realweights;//NOTE: realweights is NOT a pointer if (weightsOpt->m_present) { weights = &realweights;//point it to the actual vector to signify the option is present AString weightFileName = weightsOpt->getString(1); FileInformation textFileInfo(weightFileName); if (!textFileInfo.exists()) { throw AlgorithmException("weight list file doesn't exist"); } fstream weightListFile(weightFileName.toLocal8Bit().constData(), fstream::in); if (!weightListFile.good()) { throw AlgorithmException("error reading weight list file"); } while (weightListFile.good()) { float weight; if (!(weightListFile >> weight))//yes, this is how you check fstream for successfully extracted output. seriously. { break; } realweights.push_back(weight); } } bool fisherZ = myParams->getOptionalParameter(5)->m_present; float memLimitGB = -1.0f; OptionalParameter* memLimitOpt = myParams->getOptionalParameter(6); if (memLimitOpt->m_present) { memLimitGB = (float)memLimitOpt->getDouble(1); if (memLimitGB < 0.0f) { throw AlgorithmException("memory limit cannot be negative"); } } bool noDemean = myParams->getOptionalParameter(7)->m_present; bool covariance = myParams->getOptionalParameter(8)->m_present; if (roiOverrideMode) { if (ciftiRoiMode) { AlgorithmCiftiCorrelation(myProgObj, myCifti, myCiftiOut, ciftiRoi, weights, fisherZ, memLimitGB, noDemean); } else { AlgorithmCiftiCorrelation(myProgObj, myCifti, myCiftiOut, leftRoi, rightRoi, cerebRoi, volRoi, weights, fisherZ, memLimitGB, noDemean); } } else { AlgorithmCiftiCorrelation(myProgObj, myCifti, myCiftiOut, weights, fisherZ, memLimitGB, noDemean, covariance); } } AlgorithmCiftiCorrelation::AlgorithmCiftiCorrelation(ProgressObject* myProgObj, const CiftiFile* myCifti, CiftiFile* myCiftiOut, const vector* weights, const bool& fisherZ, const float& memLimitGB, const bool& noDemean, const bool& covariance) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (covariance) { if (fisherZ) throw AlgorithmException("cannot apply fisher z transformation to covariance"); } init(myCifti, weights, noDemean, covariance); int numRows = myCifti->getNumberOfRows(); CiftiXMLOld newXML = myCifti->getCiftiXMLOld(); newXML.applyColumnMapToRows(); myCiftiOut->setCiftiXML(newXML); int numCacheRows; bool cacheFullInput = true; if (memLimitGB >= 0.0f) { numCacheRows = numRowsForMem(memLimitGB, cacheFullInput); } else { numCacheRows = numRows; } if (numCacheRows > numRows) numCacheRows = numRows; if (cacheFullInput) { if (numCacheRows != numRows) CaretLogInfo("computing " + AString::number(numCacheRows) + " rows at a time"); } else { CaretLogInfo("computing " + AString::number(numCacheRows) + " rows at a time, reading rows as needed during processing"); } vector > outRows; if (cacheFullInput) { for (int i = 0; i < numRows; ++i) { cacheRow(i); } } for (int startrow = 0; startrow < numRows; startrow += numCacheRows) { int endrow = startrow + numCacheRows; if (endrow > numRows) endrow = numRows; outRows.resize(endrow - startrow); for (int i = startrow; i < endrow; ++i) { if (!cacheFullInput) { cacheRow(i);//preload the rows in a range which we will reuse as much as possible during one row by row scan } if (outRows[i - startrow].size() != numRows) { outRows[i - startrow] = CaretArray(numRows); } } int curRow = 0;//because we can't trust the order threads hit the critical section #pragma omp CARET_PARFOR schedule(dynamic) for (int i = 0; i < numRows; ++i) { float movingRrs; int myrow; const float* movingRow; #pragma omp critical {//CiftiFile may explode if we request multiple rows concurrently (needs mutexes), but we should force sequential requests anyway myrow = curRow;//so, manually force it to read sequentially ++curRow; movingRow = getRow(myrow, movingRrs); } for (int j = startrow; j < endrow; ++j) { if (myrow >= startrow && myrow < endrow)//check whether we are in the output memory area { if (j >= myrow)//if so, only compute one half, and store both places { float cacheRrs; const float* cacheRow = getRow(j, cacheRrs, true); outRows[j - startrow][myrow] = correlate(movingRow, movingRrs, cacheRow, cacheRrs, fisherZ); outRows[myrow - startrow][j] = outRows[j - startrow][myrow]; } } else { float cacheRrs; const float* cacheRow = getRow(j, cacheRrs, true); outRows[j - startrow][myrow] = correlate(movingRow, movingRrs, cacheRow, cacheRrs, fisherZ); } } } for (int i = startrow; i < endrow; ++i) { myCiftiOut->setRow(outRows[i - startrow], i); } if (!cacheFullInput) { clearCache();//tell the cache we are going to preload a different set of rows now } } if (cacheFullInput) { clearCache();//don't currently need to do this, its just for completeness } } AlgorithmCiftiCorrelation::AlgorithmCiftiCorrelation(ProgressObject* myProgObj, const CiftiFile* myCifti, CiftiFile* myCiftiOut, const MetricFile* leftRoi, const MetricFile* rightRoi, const MetricFile* cerebRoi, const VolumeFile* volRoi, const vector* weights, const bool& fisherZ, const float& memLimitGB, const bool& noDemean, const bool& covariance) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (covariance) { if (fisherZ) throw AlgorithmException("cannot apply fisher z transformation to covariance"); } init(myCifti, weights, noDemean, covariance); const CiftiXMLOld& origXML = myCifti->getCiftiXMLOld(); if (origXML.getColumnMappingType() != CIFTI_INDEX_TYPE_BRAIN_MODELS) { throw AlgorithmException("cannot use ROIs on this cifti, columns are not brain models"); } CiftiXMLOld newXML = origXML; vector surfList, volList; origXML.getStructureListsForColumns(surfList, volList); newXML.applyColumnMapToRows(); newXML.resetColumnsToBrainModels(); vector > ciftiIndexList; int newCiftiIndex = 0; for (int i = 0; i < (int)surfList.size(); ++i) { const MetricFile* myRoi = NULL; switch (surfList[i]) { case StructureEnum::CORTEX_LEFT: myRoi = leftRoi; break; case StructureEnum::CORTEX_RIGHT: myRoi = rightRoi; break; case StructureEnum::CEREBELLUM: myRoi = cerebRoi; break; default: break; } if (myRoi != NULL) { if (myRoi->getNumberOfNodes() != origXML.getColumnSurfaceNumberOfNodes(surfList[i])) { throw AlgorithmException("surface roi has the wrong number of vertices for structure " + StructureEnum::toName(surfList[i])); } const CiftiBrainModelsMap& myDenseMap = myCifti->getCiftiXML().getBrainModelsMap(CiftiXML::ALONG_COLUMN); vector myMap = myDenseMap.getSurfaceMap(surfList[i]); int numNodes = myDenseMap.getSurfaceNumberOfNodes(surfList[i]); int mapsize = (int)myMap.size(); vector tempNodeList; for (int j = 0; j < mapsize; ++j) { int myNode = myMap[j].m_surfaceNode; if (myRoi->getValue(myNode, 0) > 0.0f) { tempNodeList.push_back(myNode); ciftiIndexList.push_back(std::pair(myMap[j].m_ciftiIndex, newCiftiIndex)); ++newCiftiIndex; } } if (tempNodeList.size() > 0)//don't add it if it is empty { newXML.addSurfaceModelToColumns(numNodes, surfList[i], tempNodeList); } } } if (volRoi != NULL) { int64_t origDims[3]; vector > origSForm; origXML.getVolumeDimsAndSForm(origDims, origSForm); if (!volRoi->matchesVolumeSpace(origDims, origSForm)) { throw AlgorithmException("roi volume space doesn't match cifti volume space"); } for (int i = 0; i < (int)volList.size(); ++i) { vector myMap; origXML.getVolumeStructureMapForColumns(myMap, volList[i]); vector tempVoxList; int64_t numVoxels = (int64_t)myMap.size(); for (int64_t j = 0; j < numVoxels; ++j) { if (volRoi->getValue(myMap[j].m_ijk) > 0.0f) { tempVoxList.push_back(myMap[j].m_ijk[0]); tempVoxList.push_back(myMap[j].m_ijk[1]); tempVoxList.push_back(myMap[j].m_ijk[2]); ciftiIndexList.push_back(std::pair(myMap[j].m_ciftiIndex, newCiftiIndex)); ++newCiftiIndex; } } if (tempVoxList.size() > 0) { newXML.addVolumeModelToColumns(tempVoxList, volList[i]); } } } myCiftiOut->setCiftiXML(newXML); int numSelected = (int)ciftiIndexList.size(), numRows = myCifti->getNumberOfRows(); int numCacheRows; bool cacheFullInput = true; if (memLimitGB >= 0.0f) { numCacheRows = numRowsForMem(memLimitGB, cacheFullInput); } else { numCacheRows = numSelected; } if (numCacheRows > numSelected) numCacheRows = numSelected; if (cacheFullInput) { if (numCacheRows != numSelected) CaretLogInfo("computing " + AString::number(numCacheRows) + " rows at a time"); } else { CaretLogInfo("computing " + AString::number(numCacheRows) + " rows at a time, reading rows as needed during processing"); } vector > outRows; if (cacheFullInput) { for (int i = 0; i < numRows; ++i) { cacheRow(i); } } CaretArray indexReverse(numRows, -1); for (int startrow = 0; startrow < numSelected; startrow += numCacheRows) { int endrow = startrow + numCacheRows; if (endrow > numSelected) endrow = numSelected; outRows.resize(endrow - startrow); int curRow = 0;//because we can't trust the order threads hit the critical section for (int i = startrow; i < endrow; ++i) { if (!cacheFullInput) { cacheRow(ciftiIndexList[i].first);//preload the rows in a range which we will reuse as much as possible during one row by row scan } if (outRows[i - startrow].size() != numRows) { outRows[i - startrow] = CaretArray(numRows); } indexReverse[ciftiIndexList[i].first] = i; } #pragma omp CARET_PARFOR schedule(dynamic) for (int i = 0; i < numRows; ++i) { float movingRrs; int myrow; const float* movingRow; #pragma omp critical {//CiftiFile may explode if we request multiple rows concurrently (needs mutexes), but we should force sequential requests anyway myrow = curRow;//so, manually force it to read sequentially ++curRow; movingRow = getRow(myrow, movingRrs); } for (int j = startrow; j < endrow; ++j) { if (indexReverse[myrow] != -1)//check if we are on a row that is in the output memory range { if (indexReverse[myrow] <= j)//if so, only compute one of the elements, then store it both places { float cacheRrs; const float* cacheRow = getRow(ciftiIndexList[j].first, cacheRrs, true); outRows[j - startrow][myrow] = correlate(movingRow, movingRrs, cacheRow, cacheRrs, fisherZ); outRows[indexReverse[myrow] - startrow][ciftiIndexList[j].first] = outRows[j - startrow][myrow]; } } else { float cacheRrs; const float* cacheRow = getRow(ciftiIndexList[j].first, cacheRrs, true); outRows[j - startrow][myrow] = correlate(movingRow, movingRrs, cacheRow, cacheRrs, fisherZ); } } } for (int i = startrow; i < endrow; ++i) { myCiftiOut->setRow(outRows[i - startrow], ciftiIndexList[i].second); indexReverse[ciftiIndexList[i].first] = -1; } if (!cacheFullInput) { clearCache();//tell the cache we are going to preload a different set of rows now } } if (cacheFullInput) { clearCache();//don't currently need to do this, its just for completeness } } AlgorithmCiftiCorrelation::AlgorithmCiftiCorrelation(ProgressObject* myProgObj, const CiftiFile* myCifti, CiftiFile* myCiftiOut, const CiftiFile* ciftiRoi, const vector* weights, const bool& fisherZ, const float& memLimitGB, const bool& noDemean, const bool& covariance): AbstractAlgorithm(NULL)//HACK: get around the sentinel by passing a null, because this implementation calls another { const CiftiXML& roiXML = ciftiRoi->getCiftiXML();//roi is not optional in this variant if (roiXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) throw AlgorithmException("cifti roi does not have brain models mapping along column"); const CiftiBrainModelsMap myDenseMap = roiXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); MetricFile leftRoi, rightRoi, cerebRoi; MetricFile* leftRoiPtr = NULL, *rightRoiPtr = NULL, *cerebRoiPtr = NULL; VolumeFile volRoi; VolumeFile* volRoiPtr = NULL; vector surfStructs = myDenseMap.getSurfaceStructureList(); for (int i = 0; i < (int)surfStructs.size(); ++i) { MetricFile* thisRoi = NULL; switch (surfStructs[i]) { case StructureEnum::CORTEX_LEFT: thisRoi = &leftRoi; leftRoiPtr = thisRoi; break; case StructureEnum::CORTEX_RIGHT: thisRoi = &rightRoi; rightRoiPtr = thisRoi; break; case StructureEnum::CEREBELLUM: thisRoi = &cerebRoi; cerebRoiPtr = thisRoi; break; default: throw AlgorithmException("structure not supported for surface type: " + StructureEnum::toName(surfStructs[i])); } AlgorithmCiftiSeparate(NULL, ciftiRoi, CiftiXML::ALONG_COLUMN, surfStructs[i], thisRoi); } if (myDenseMap.hasVolumeData()) { int64_t offsetOut[3]; AlgorithmCiftiSeparate(NULL, ciftiRoi, CiftiXML::ALONG_COLUMN, &volRoi, offsetOut, NULL, false);//don't crop, because it needs to match the original volume space in the input volRoiPtr = &volRoi; } AlgorithmCiftiCorrelation(myProgObj, myCifti, myCiftiOut, leftRoiPtr, rightRoiPtr, cerebRoiPtr, volRoiPtr, weights, fisherZ, memLimitGB, noDemean, covariance);//HACK: pass through our progress object } float AlgorithmCiftiCorrelation::correlate(const float* row1, const float& rrs1, const float* row2, const float& rrs2, const bool& fisherZ) { double r; if (row1 == row2 && !m_covariance) { r = 1.0;//short circuit for same row } else { if (m_weightedMode) { int numWeights = (int)m_weightIndexes.size();//because we compacted the data in the row to not include any zero weights double accum = dsdot(row1, row2, numWeights);//these have already had the weighted row means subtracted out, and weights applied if (m_covariance) { if (m_binaryWeights) { r = accum / numWeights; } else { r = accum / rrs1;//NOTE: will equal rrs2 as it only depends on weights, and is not square root } } else { r = accum / (rrs1 * rrs2);//as do these } } else { double accum = dsdot(row1, row2, m_numCols);//these have already had the row means subtracted out if (m_covariance) { r = accum / m_numCols; } else { r = accum / (rrs1 * rrs2); } } } if (!m_covariance) { if (fisherZ) { if (r > 0.999999) r = 0.999999;//prevent inf if (r < -0.999999) r = -0.999999;//prevent -inf r = 0.5 * log((1 + r) / (1 - r)); } else { if (r > 1.0) r = 1.0;//don't output anything silly if (r < -1.0) r = -1.0; } } return r; } void AlgorithmCiftiCorrelation::init(const CiftiFile* input, const vector* weights, const bool& noDemean, const bool& covariance) { m_noDemean = noDemean; m_covariance = covariance; m_inputCifti = input; m_rowInfo.resize(m_inputCifti->getNumberOfRows()); m_cacheUsed = 0; m_numCols = m_inputCifti->getNumberOfColumns(); if (weights != NULL) { m_weightedMode = true; int numWeights = (int)weights->size(); if (numWeights != m_numCols) { throw AlgorithmException("number of weights doesn't match length of a row, number of weights given: " + AString::number(weights->size())); } m_binaryWeights = true; for (int i = 0; i < numWeights; ++i) { float val = (*weights)[i]; if (val != 0.0f) { if (val < 0.0f) { throw AlgorithmException("weights cannot be negative"); } m_weights.push_back(val); m_weightIndexes.push_back(i); if (val != 1.0f) { m_binaryWeights = false; } } } if (m_binaryWeights && m_weights.size() == weights->size()) { m_weightedMode = false;//all weights were 1, so switch back to normal mode } } else { m_weightedMode = false; } } void AlgorithmCiftiCorrelation::cacheRow(const int& ciftiIndex) { CaretAssertVectorIndex(m_rowInfo, ciftiIndex); if (m_rowInfo[ciftiIndex].m_cacheIndex != -1) return;//shouldn't happen, but hey if (m_cacheUsed >= (int)m_rowCache.size()) { m_rowCache.push_back(CacheRow()); m_rowCache[m_cacheUsed].m_row.resize(m_numCols); } m_rowCache[m_cacheUsed].m_ciftiIndex = ciftiIndex; float* myPtr = m_rowCache[m_cacheUsed].m_row.data(); m_inputCifti->getRow(myPtr, ciftiIndex); if (!m_rowInfo[ciftiIndex].m_haveCalculated) { computeRowStats(myPtr, m_rowInfo[ciftiIndex].m_mean, m_rowInfo[ciftiIndex].m_rootResidSqr); m_rowInfo[ciftiIndex].m_haveCalculated = true; } doSubtract(myPtr, m_rowInfo[ciftiIndex].m_mean); m_rowInfo[ciftiIndex].m_cacheIndex = m_cacheUsed; ++m_cacheUsed; } void AlgorithmCiftiCorrelation::clearCache() { for (int i = 0; i < m_cacheUsed; ++i) { m_rowInfo[m_rowCache[i].m_ciftiIndex].m_cacheIndex = -1; } m_cacheUsed = 0; } const float* AlgorithmCiftiCorrelation::getRow(const int& ciftiIndex, float& rootResidSqr, const bool& mustBeCached) { float* ret; CaretAssertVectorIndex(m_rowInfo, ciftiIndex); if (m_rowInfo[ciftiIndex].m_cacheIndex != -1) { ret = m_rowCache[m_rowInfo[ciftiIndex].m_cacheIndex].m_row.data(); } else { CaretAssert(!mustBeCached); if (mustBeCached)//largely so it doesn't give warning about unused when compiled in release { throw AlgorithmException("something very bad happened, notify the developers"); } ret = getTempRow(); m_inputCifti->getRow(ret, ciftiIndex); if (!m_rowInfo[ciftiIndex].m_haveCalculated) { computeRowStats(ret, m_rowInfo[ciftiIndex].m_mean, m_rowInfo[ciftiIndex].m_rootResidSqr); m_rowInfo[ciftiIndex].m_haveCalculated = true; } doSubtract(ret, m_rowInfo[ciftiIndex].m_mean); } rootResidSqr = m_rowInfo[ciftiIndex].m_rootResidSqr; return ret; } void AlgorithmCiftiCorrelation::computeRowStats(const float* row, float& mean, float& rootResidSqr) { double accum = 0.0;//double, for numerical stability if (m_noDemean) { mean = 0.0f; } else { if (m_weightedMode) { int weightsize = (int)m_weightIndexes.size(); if (m_binaryWeights)//because should be a little faster without multiplies or a second sum { for (int i = 0; i < weightsize; ++i) { accum += row[m_weightIndexes[i]]; } mean = accum / weightsize; } else { double accum2 = 0.0; for (int i = 0; i < weightsize; ++i) { float weight = m_weights[i]; accum += row[m_weightIndexes[i]] * weight; accum2 += weight; } mean = accum / accum2; } } else { for (int i = 0; i < m_numCols; ++i)//two pass, for numerical stability { accum += row[i]; } mean = accum / m_numCols; } } accum = 0.0; if (m_covariance) { int weightsize = (int)m_weightIndexes.size(); rootResidSqr = 0.0f; if (m_weightedMode && !m_binaryWeights) { for (int i = 0; i < weightsize; ++i) { accum += m_weights[i]; } rootResidSqr = accum;//repurpose this variable to store the weight sum - NOTE: don't take sqrt in case negative sum (whatever that means), so must not divide by both in correlate() in covariance mode } } else { if (m_weightedMode) { int weightsize = (int)m_weightIndexes.size(); if (m_binaryWeights) { for (int i = 0; i < weightsize; ++i) { float tempf = row[m_weightIndexes[i]] - mean; accum += tempf * tempf; } rootResidSqr = sqrt(accum); } else { for (int i = 0; i < weightsize; ++i) { float tempf = row[m_weightIndexes[i]] - mean; accum += tempf * tempf * m_weights[i]; } rootResidSqr = sqrt(accum); } } else { for (int i = 0; i < m_numCols; ++i) { float tempf = row[i] - mean; accum += tempf * tempf; } rootResidSqr = sqrt(accum); } } } void AlgorithmCiftiCorrelation::doSubtract(float* row, const float& mean) { if (m_noDemean) return;//skip subtracting zero from everything if (m_weightedMode) { int weightsize = (int)m_weightIndexes.size(); if (m_binaryWeights) { for (int i = 0; i < weightsize; ++i) { row[i] = row[m_weightIndexes[i]] - mean; } } else { for (int i = 0; i < weightsize; ++i) { row[i] = sqrt(m_weights[i]) * (row[m_weightIndexes[i]] - mean);//multiply by square root of weight, so that the numerator of correlation doesn't get the square of the weight } } } else { for (int i = 0; i < m_numCols; ++i) { row[i] -= mean; } } } float* AlgorithmCiftiCorrelation::getTempRow() { #ifdef CARET_OMP int oldsize = (int)m_tempRows.size(); int threadNum = omp_get_thread_num(); if (threadNum >= oldsize) { m_tempRows.resize(threadNum + 1); for (int i = oldsize; i <= threadNum; ++i) { m_tempRows[i] = CaretArray(m_numCols); } } return m_tempRows[threadNum].getArray(); #else if (m_tempRows.size() == 0) { m_tempRows.resize(1); m_tempRows[0] = CaretArray(m_numCols); } return m_tempRows[0].getArray(); #endif } int AlgorithmCiftiCorrelation::numRowsForMem(const float& memLimitGB, bool& cacheFullInput) { int numRows = m_inputCifti->getNumberOfRows(); int inrowBytes = m_numCols * sizeof(float), outrowBytes = numRows * sizeof(float); int64_t targetBytes = (int64_t)(memLimitGB * 1024 * 1024 * 1024); if (m_inputCifti->isInMemory()) targetBytes -= numRows * m_numCols * 4;//count in-memory input against the total too #ifdef CARET_OMP targetBytes -= inrowBytes * omp_get_max_threads(); #else targetBytes -= inrowBytes;//1 row in memory that isn't a reference to cache #endif targetBytes -= numRows * sizeof(RowInfo);//storage for mean, stdev, and info about caching int64_t perRowBytes = inrowBytes + outrowBytes;//cache and memory collation for output rows if (numRows * m_numCols * 4 < targetBytes * 0.7f)//if caching the entire input file would take less than 70% of remaining allotted memory, do it to reduce IO { cacheFullInput = true;//precache the entire input file, rather than caching it synchronously with the in-memory output rows targetBytes -= numRows * m_numCols * 4;//reduce the remaining total by the memory used perRowBytes = outrowBytes;//don't need to count input rows against the remaining memory total } else { cacheFullInput = false; } if (perRowBytes == 0) return 1;//protect against integer div by zero int ret = targetBytes / perRowBytes;//integer divide rounds down if (ret < 1) return 1;//always return at least one return ret; } float AlgorithmCiftiCorrelation::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiCorrelation::getSubAlgorithmWeight() { return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiCorrelation.h000066400000000000000000000104751360521144700260220ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_CORRELATION_H__ #define __ALGORITHM_CIFTI_CORRELATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AbstractAlgorithm.h" #include "CaretPointer.h" namespace caret { class AlgorithmCiftiCorrelation : public AbstractAlgorithm { AlgorithmCiftiCorrelation(); struct CacheRow { int m_ciftiIndex; std::vector m_row; }; struct RowInfo { bool m_haveCalculated; float m_mean, m_rootResidSqr; int m_cacheIndex; RowInfo() { m_haveCalculated = false; m_cacheIndex = -1; } }; std::vector m_rowCache; std::vector m_rowInfo; std::vector > m_tempRows;//reuse return values in getRow instead of reallocating std::vector m_weights; std::vector m_weightIndexes; bool m_binaryWeights, m_weightedMode, m_noDemean, m_covariance; int m_cacheUsed;//reuse cache entries instead of reallocating them int m_numCols; const CiftiFile* m_inputCifti;//so that accesses work through the cache functions void cacheRow(const int& ciftiIndex); void computeRowStats(const float* row, float& mean, float& rootResidSqr); void doSubtract(float* row, const float& mean); void clearCache(); const float* getRow(const int& ciftiIndex, float& rootResidSqr, const bool& mustBeCached = false); float* getTempRow(); float correlate(const float* row1, const float& rrs1, const float* row2, const float& rrs2, const bool& fisherZ); void init(const CiftiFile* input, const std::vector* weights, const bool& noDemean, const bool& covariance); int numRowsForMem(const float& memLimitGB, bool& cacheFullInput); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiCorrelation(ProgressObject* myProgObj, const CiftiFile* myCifti, CiftiFile* myCiftiOut, const std::vector* weights = NULL, const bool& fisherZ = false, const float& memLimitGB = -1.0f, const bool& noDemean = false, const bool& covariance = false); AlgorithmCiftiCorrelation(ProgressObject* myProgObj, const CiftiFile* myCifti, CiftiFile* myCiftiOut, const MetricFile* leftRoi, const MetricFile* rightRoi = NULL, const MetricFile* cerebRoi = NULL, const VolumeFile* volRoi = NULL, const std::vector* weights = NULL, const bool& fisherZ = false, const float& memLimitGB = -1.0f, const bool& noDemean = false, const bool& covariance = false); AlgorithmCiftiCorrelation(ProgressObject* myProgObj, const CiftiFile* myCifti, CiftiFile* myCiftiOut, const CiftiFile* ciftiRoi, const std::vector* weights = NULL, const bool& fisherZ = false, const float& memLimitGB = -1.0f, const bool& noDemean = false, const bool& covariance = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiCorrelation; } #endif //__ALGORITHM_CIFTI_CORRELATION_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiCorrelationGradient.cxx000066400000000000000000001767211360521144700300620ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiCorrelationGradient.h" #include "AlgorithmException.h" #include "AlgorithmMetricGradient.h" #include "MetricSmoothingObject.h" #include "AlgorithmVolumeGradient.h" #include "CaretLogger.h" #include "CaretOMP.h" #include "CiftiFile.h" #include "GeodesicHelper.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "Vector3D.h" #include "VolumeFile.h" #include "dot_wrapper.h" #include #include using namespace caret; using namespace std; AString AlgorithmCiftiCorrelationGradient::getCommandSwitch() { return "-cifti-correlation-gradient"; } AString AlgorithmCiftiCorrelationGradient::getShortDescription() { return "CORRELATE CIFTI ROWS AND TAKE GRADIENT"; } OperationParameters* AlgorithmCiftiCorrelationGradient::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti", "the input cifti"); ret->addCiftiOutputParameter(2, "cifti-out", "the output cifti"); OptionalParameter* leftSurfOpt = ret->createOptionalParameter(3, "-left-surface", "specify the left surface to use"); leftSurfOpt->addSurfaceParameter(1, "surface", "the left surface file"); OptionalParameter* leftCorrAreasOpt = leftSurfOpt->createOptionalParameter(2, "-left-corrected-areas", "vertex areas to use instead of computing them from the left surface"); leftCorrAreasOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); OptionalParameter* rightSurfOpt = ret->createOptionalParameter(4, "-right-surface", "specify the right surface to use"); rightSurfOpt->addSurfaceParameter(1, "surface", "the right surface file"); OptionalParameter* rightCorrAreasOpt = rightSurfOpt->createOptionalParameter(2, "-right-corrected-areas", "vertex areas to use instead of computing them from the right surface"); rightCorrAreasOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); OptionalParameter* cerebSurfaceOpt = ret->createOptionalParameter(5, "-cerebellum-surface", "specify the cerebellum surface to use"); cerebSurfaceOpt->addSurfaceParameter(1, "surface", "the cerebellum surface file"); OptionalParameter* cerebCorrAreasOpt = cerebSurfaceOpt->createOptionalParameter(2, "-cerebellum-corrected-areas", "vertex areas to use instead of computing them from the cerebellum surface"); cerebCorrAreasOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); OptionalParameter* presmoothSurfOpt = ret->createOptionalParameter(6, "-surface-presmooth", "smooth on the surface before computing the gradient"); presmoothSurfOpt->addDoubleParameter(1, "surface-kernel", "the sigma for the gaussian surface smoothing kernel, in mm"); OptionalParameter* presmoothVolOpt = ret->createOptionalParameter(7, "-volume-presmooth", "smooth the volume before computing the gradient"); presmoothVolOpt->addDoubleParameter(1, "volume-kernel", "the sigma for the gaussian volume smoothing kernel, in mm"); ret->createOptionalParameter(8, "-undo-fisher-z", "apply the inverse fisher small z transform to the input"); ret->createOptionalParameter(12, "-fisher-z", "apply the fisher small z transform to the correlations before taking the gradient"); OptionalParameter* surfaceExcludeOpt = ret->createOptionalParameter(9, "-surface-exclude", "exclude vertices near each seed vertex from computation"); surfaceExcludeOpt->addDoubleParameter(1, "distance", "geodesic distance from seed vertex for the exclusion zone, in mm"); OptionalParameter* volumeExcludeOpt = ret->createOptionalParameter(10, "-volume-exclude", "exclude voxels near each seed voxel from computation"); volumeExcludeOpt->addDoubleParameter(1, "distance", "distance from seed voxel for the exclusion zone, in mm"); ret->createOptionalParameter(13, "-covariance", "compute covariance instead of correlation"); OptionalParameter* memLimitOpt = ret->createOptionalParameter(11, "-mem-limit", "restrict memory usage"); memLimitOpt->addDoubleParameter(1, "limit-GB", "memory limit in gigabytes"); OptionalParameter* secondCorrOpt = ret->createOptionalParameter(14, "-double-correlation", "do two correlations before taking the gradient"); secondCorrOpt->createOptionalParameter(1, "-fisher-z-first", "after the FIRST correlation, apply fisher small z transform (ie, artanh)"); secondCorrOpt->createOptionalParameter(2, "-no-demean-first", "instead of correlation for the FIRST operation, do dot product of rows, then normalize by diagonal"); secondCorrOpt->createOptionalParameter(3, "-covariance-first", "instead of correlation for the FIRST operation, compute covariance"); ret->setHelpText( AString("For each structure, compute the correlation of the rows in the structure, and take the gradients of ") + "the resulting rows, then average them. " + "Memory limit does not need to be an integer, you may also specify 0 to use as little memory as possible (this may be very slow)." ); return ret; } void AlgorithmCiftiCorrelationGradient::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* myCifti = myParams->getCifti(1); CiftiFile* myCiftiOut = myParams->getOutputCifti(2); SurfaceFile* myLeftSurf = NULL, *myRightSurf = NULL, *myCerebSurf = NULL; MetricFile* myLeftAreas = NULL, *myRightAreas = NULL, *myCerebAreas = NULL; OptionalParameter* leftSurfOpt = myParams->getOptionalParameter(3); if (leftSurfOpt->m_present) { myLeftSurf = leftSurfOpt->getSurface(1); OptionalParameter* leftCorrAreasOpt = leftSurfOpt->getOptionalParameter(2); if (leftCorrAreasOpt->m_present) { myLeftAreas = leftCorrAreasOpt->getMetric(1); } } OptionalParameter* rightSurfOpt = myParams->getOptionalParameter(4); if (rightSurfOpt->m_present) { myRightSurf = rightSurfOpt->getSurface(1); OptionalParameter* rightCorrAreasOpt = rightSurfOpt->getOptionalParameter(2); if (rightCorrAreasOpt->m_present) { myRightAreas = rightCorrAreasOpt->getMetric(1); } } OptionalParameter* cerebSurfOpt = myParams->getOptionalParameter(5); if (cerebSurfOpt->m_present) { myCerebSurf = cerebSurfOpt->getSurface(1); OptionalParameter* cerebCorrAreasOpt = cerebSurfOpt->getOptionalParameter(2); if (cerebCorrAreasOpt->m_present) { myCerebAreas = cerebCorrAreasOpt->getMetric(1); } } float surfKern = -1.0f; OptionalParameter* presmoothSurfOpt = myParams->getOptionalParameter(6); if (presmoothSurfOpt->m_present) { surfKern = (float)presmoothSurfOpt->getDouble(1); } float volKern = -1.0f; OptionalParameter* presmoothVolOpt = myParams->getOptionalParameter(7); if (presmoothVolOpt->m_present) { volKern = (float)presmoothVolOpt->getDouble(1); } bool undoFisherInput = myParams->getOptionalParameter(8)->m_present; bool applyFisher = myParams->getOptionalParameter(12)->m_present; float surfaceExclude = -1.0f; OptionalParameter* surfaceExcludeOpt = myParams->getOptionalParameter(9); if (surfaceExcludeOpt->m_present) { surfaceExclude = (float)surfaceExcludeOpt->getDouble(1); if (surfaceExclude < 0.0f) { throw AlgorithmException("surface exclude distance cannot be negative"); } } float volumeExclude = -1.0f; OptionalParameter* volumeExcludeOpt = myParams->getOptionalParameter(10); if (volumeExcludeOpt->m_present) { volumeExclude = (float)volumeExcludeOpt->getDouble(1); if (volumeExclude < 0.0f) { throw AlgorithmException("volume exclude distance cannot be negative"); } } float memLimitGB = -1.0f; OptionalParameter* memLimitOpt = myParams->getOptionalParameter(11); if (memLimitOpt->m_present) { memLimitGB = (float)memLimitOpt->getDouble(1); if (memLimitGB < 0.0f) { throw AlgorithmException("memory limit cannot be negative"); } } bool covariance = myParams->getOptionalParameter(13)->m_present; bool doubleCorr = false, firstFisher = false, firstNoDemean = false, firstCovar = false; OptionalParameter* doubleCorrOpt = myParams->getOptionalParameter(14); if (doubleCorrOpt->m_present) { doubleCorr = true; firstFisher = doubleCorrOpt->getOptionalParameter(1)->m_present; firstNoDemean = doubleCorrOpt->getOptionalParameter(2)->m_present; firstCovar = doubleCorrOpt->getOptionalParameter(3)->m_present; } AlgorithmCiftiCorrelationGradient(myProgObj, myCifti, myCiftiOut, myLeftSurf, myRightSurf, myCerebSurf, myLeftAreas, myRightAreas, myCerebAreas, surfKern, volKern, undoFisherInput, applyFisher, surfaceExclude, volumeExclude, covariance, memLimitGB, doubleCorr, firstFisher, firstNoDemean, firstCovar); } AlgorithmCiftiCorrelationGradient::AlgorithmCiftiCorrelationGradient(ProgressObject* myProgObj, CiftiFile* myCifti, CiftiFile* myCiftiOut, SurfaceFile* myLeftSurf, SurfaceFile* myRightSurf, SurfaceFile* myCerebSurf, const MetricFile* myLeftAreas, const MetricFile* myRightAreas, const MetricFile* myCerebAreas, const float& surfKern, const float& volKern, const bool& undoFisherInput, const bool& applyFisher, const float& surfaceExclude, const float& volumeExclude, const bool& covariance, const float& memLimitGB, const bool doubleCorr, const bool firstFisher, const bool firstNoDemean, const bool firstCovar) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); init(myCifti, memLimitGB, undoFisherInput, applyFisher, covariance, doubleCorr, firstFisher, firstNoDemean, firstCovar); const CiftiXML& myXML = myCifti->getCiftiXML(); CiftiXML myNewXML = myXML; CiftiScalarsMap newMap(1); newMap.setMapName(0, "gradient"); myNewXML.setMap(CiftiXML::ALONG_ROW, newMap); myCiftiOut->setCiftiXML(myNewXML); const CiftiBrainModelsMap& spaceMap = myXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); vector surfaceList = spaceMap.getSurfaceStructureList(), volumeList = spaceMap.getVolumeStructureList(); for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) {//sanity check surfaces SurfaceFile* mySurf = NULL; const MetricFile* myAreas = NULL; AString surfType; switch (surfaceList[whichStruct]) { case StructureEnum::CORTEX_LEFT: mySurf = myLeftSurf; myAreas = myLeftAreas; surfType = "left"; break; case StructureEnum::CORTEX_RIGHT: mySurf = myRightSurf; myAreas = myRightAreas; surfType = "right"; break; case StructureEnum::CEREBELLUM: mySurf = myCerebSurf; myAreas = myCerebAreas; surfType = "cerebellum"; break; default: throw AlgorithmException("found surface model with incorrect type: " + StructureEnum::toName(surfaceList[whichStruct])); break; } if (mySurf == NULL) { throw AlgorithmException(surfType + " surface required but not provided"); } if (mySurf->getNumberOfNodes() != myCifti->getCiftiXML().getBrainModelsMap(CiftiXML::ALONG_COLUMN).getSurfaceNumberOfNodes(surfaceList[whichStruct])) { throw AlgorithmException(surfType + " surface has the wrong number of vertices"); } if (myAreas != NULL && myAreas->getNumberOfNodes() != mySurf->getNumberOfNodes()) { throw AlgorithmException(surfType + " corrected vertex areas metric has the wrong number of vertices"); } } for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) { SurfaceFile* mySurf = NULL; const MetricFile* myAreas = NULL; switch (surfaceList[whichStruct]) { case StructureEnum::CORTEX_LEFT: mySurf = myLeftSurf; myAreas = myLeftAreas; break; case StructureEnum::CORTEX_RIGHT: mySurf = myRightSurf; myAreas = myRightAreas; break; case StructureEnum::CEREBELLUM: mySurf = myCerebSurf; myAreas = myCerebAreas; break; default: break; } if (surfaceExclude > 0.0f) { processSurfaceComponent(surfaceList[whichStruct], surfKern, surfaceExclude, memLimitGB, mySurf, myAreas); } else { processSurfaceComponent(surfaceList[whichStruct], surfKern, memLimitGB, mySurf, myAreas); } } for (int whichStruct = 0; whichStruct < (int)volumeList.size(); ++whichStruct) { if (volumeExclude > 0.0f) { processVolumeComponent(volumeList[whichStruct], volKern, volumeExclude, memLimitGB); } else { processVolumeComponent(volumeList[whichStruct], volKern, memLimitGB); } } myCiftiOut->setColumn(m_outColumn.data(), 0); } namespace { //expects rows to already be demeaned, if demeaning is to be done float correlate(const float* row1, const float& rrs1, const float* row2, const float& rrs2, const int64_t length, const bool covariance, const bool fisherz) { double r; if (row1 == row2 && !covariance) { r = 1.0;//short circuit for same row - works because one row is always in the cache range } else { double accum = dsdot(row1, row2, length);//these have already had the row means subtracted out if (covariance) { r = accum / length; } else { r = accum / (rrs1 * rrs2); } } if (!covariance) { if (fisherz) { if (r > 0.999999) r = 0.999999;//prevent inf if (r < -0.999999) r = -0.999999;//prevent -inf r = 0.5 * log((1 + r) / (1 - r)); } else { if (r > 1.0) r = 1.0;//don't output anything silly if (r < -1.0) r = -1.0; } } return r; } void adjustRow(float* rowOut, int64_t length, AlgorithmCiftiCorrelationGradient::RowInfo& rowInfo, const bool undoFisher, const bool covariance, const bool noDemean) { if (undoFisher) { for (int64_t i = 0; i < length; ++i) { double temp = exp(2 * rowOut[i]); rowOut[i] = (float)((temp - 1)/(temp + 1)); } } if (!rowInfo.m_haveCalculated) { double accum = 0.0; float mean = 0.0f; if (!noDemean) { for (int64_t i = 0; i < length; ++i) { accum += rowOut[i]; } mean = accum / length; } rowInfo.m_mean = mean;//note: mean is intentionally 0 when noDemean is true if (!covariance)//rrs not used in covariance { accum = 0.0; for (int i = 0; i < length; ++i) { float tempf = rowOut[i] - mean; accum += tempf * tempf; if (!noDemean)//do one less pass over the data the first time the mean is computed { rowOut[i] = tempf; } } rowInfo.m_rootResidSqr = sqrt(accum); } else { rowInfo.m_rootResidSqr = 0.0f; } rowInfo.m_haveCalculated = true; } else { if (!noDemean) { float mean = rowInfo.m_mean; for (int64_t i = 0; i < length; ++i) { rowOut[i] -= mean; } } } } struct FirstCorrPlan { bool m_cacheFullInput; int64_t m_chunkSize; }; bool firstCorrWarned = false; FirstCorrPlan firstCorrMemoryPlan(const int64_t totalRows, const int64_t cacheRowLength, const float memLimitGB, const bool inputIsMemory, const int64_t inputRowLength, const int64_t /*mapSize*/) { FirstCorrPlan ret; ret.m_cacheFullInput = true; ret.m_chunkSize = totalRows; if (memLimitGB < 0.0f) { return ret; } int64_t inputRowBytes = sizeof(float) * inputRowLength; int64_t mem_limit_bytes = int64_t(memLimitGB * 1024 * 1024 * 1024); int64_t full_input_cache_bytes = inputRowBytes * cacheRowLength;//cache is a part of a square dconn, sized by the column length of the input int64_t cache_bytes = sizeof(float) * totalRows * cacheRowLength; int64_t input_memory_bytes = 0; if (inputIsMemory) { input_memory_bytes = full_input_cache_bytes; } int64_t in_use_bytes = cache_bytes + input_memory_bytes;//the metric/volume file used to store the second correlation before gradient isn't allocated until after cacheRows() int64_t available_bytes = mem_limit_bytes - in_use_bytes; if (available_bytes <= 0) { //the user may have specified 0, just use minimum memory... if (!inputIsMemory && !firstCorrWarned) { CaretLogWarning("double correlation specified with extremely low memory limit, this may take a long time and do a lot of IO"); firstCorrWarned = true; } ret.m_chunkSize = 1; ret.m_cacheFullInput = false; return ret; } if (full_input_cache_bytes > available_bytes) { ret.m_cacheFullInput = false; int64_t maxChunkSize = available_bytes / inputRowBytes; if (maxChunkSize < 1) maxChunkSize = 1; int64_t numPasses = (totalRows - 1) / maxChunkSize + 1;//compute number of passes to find the minimum chunk size to do that number of passes ret.m_chunkSize = (totalRows - 1) / numPasses + 1;//technically, unequal chunks is slightly less computation and same total IO, but equal chunks makes IO more consistent if (ret.m_chunkSize < 1) { if (!inputIsMemory && !firstCorrWarned) { CaretLogWarning("double correlation specified with extremely low memory limit, this may take a long time and do a lot of IO"); firstCorrWarned = true; } ret.m_chunkSize = 1; return ret; } } //default is to cache full input //unlike ordinary correlation, the memory for storing the in-progress output has already been dictated to us, so there is no advantage to chunking any smaller than the input cache return ret; } } void AlgorithmCiftiCorrelationGradient::processSurfaceComponent(StructureEnum::Enum& myStructure, const float& surfKern, const float& memLimitGB, SurfaceFile* mySurf, const MetricFile* myAreas) { const CiftiXMLOld& myXML = m_inputCifti->getCiftiXMLOld(); vector myMap; myXML.getSurfaceMapForColumns(myMap, myStructure); int mapSize = (int)myMap.size(); vector accum(mapSize, 0.0); int numCacheRows = mapSize; bool cacheFullInput = true;//numRowsForMem() sets this if (memLimitGB >= 0.0f) { numCacheRows = numRowsForMem(m_numCols * sizeof(float), (mySurf->getNumberOfNodes() * (sizeof(float) * 8 + 1)) / 8, mapSize, cacheFullInput); } if (numCacheRows > mapSize) { cacheFullInput = true; numCacheRows = mapSize; } if (cacheFullInput) { if (numCacheRows != mapSize) CaretLogInfo("computing " + AString::number(numCacheRows) + " rows at a time"); } else { CaretLogInfo("computing " + AString::number(numCacheRows) + " rows at a time, reading rows as needed during processing"); } const float* areaData = NULL; if (myAreas != NULL) { areaData = myAreas->getValuePointerForColumn(0); } MetricFile myRoi; myRoi.setNumberOfNodesAndColumns(mySurf->getNumberOfNodes(), 1); myRoi.initializeColumn(0); vector rowsToCache; for (int i = 0; i < mapSize; ++i) { myRoi.setValue(myMap[i].m_surfaceNode, 0, 1.0f); if (cacheFullInput) { rowsToCache.push_back(myMap[i].m_ciftiIndex); } } if (cacheFullInput) { cacheRows(rowsToCache, mapSize); } CaretPointer mySmooth; if (surfKern > 0.0f) { mySmooth.grabNew(new MetricSmoothingObject(mySurf, surfKern, &myRoi, MetricSmoothingObject::GEO_GAUSS_AREA, areaData));//computes the smoothing weights only once per surface } for (int startpos = 0; startpos < mapSize; startpos += numCacheRows) { int endpos = startpos + numCacheRows; if (endpos > mapSize) endpos = mapSize; if (!cacheFullInput) { rowsToCache.clear(); for (int i = startpos; i < endpos; ++i) { rowsToCache.push_back(myMap[i].m_ciftiIndex); } cacheRows(rowsToCache, mapSize); } int curRow = 0;//because we can't trust the order threads hit the critical section MetricFile computeMetric; computeMetric.setNumberOfNodesAndColumns(mySurf->getNumberOfNodes(), endpos - startpos); #pragma omp CARET_PAR { vector scratchRow1(m_numCols), scratchRow2(m_numCols); #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < mapSize; ++i) { float movingRrs; const float* movingRow = NULL; int myrow; #pragma omp critical {//CiftiFile may explode if we request multiple rows concurrently (needs mutexes), but we should force sequential requests anyway myrow = curRow;//so, manually force it to read sequentially ++curRow; if (!m_doubleCorr) {//when not doing double corr, we want to read single rows in order on disk movingRow = getRow(myMap[myrow].m_ciftiIndex, movingRrs, scratchRow1.data()); } } if (m_doubleCorr) {//when doing double corr, let the threads compute correlations in parallel movingRow = getRow(myMap[myrow].m_ciftiIndex, movingRrs, scratchRow1.data()); } for (int j = startpos; j < endpos; ++j) { if (myrow >= startpos && myrow < endpos) { if (j >= myrow) { float cacheRrs; const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, scratchRow2.data()); float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs, m_numCols, m_covariance, m_applyFisher); computeMetric.setValue(myMap[myrow].m_surfaceNode, j - startpos, result); computeMetric.setValue(myMap[j].m_surfaceNode, myrow - startpos, result); } } else { float cacheRrs; const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, scratchRow2.data()); float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs, m_numCols, m_covariance, m_applyFisher); computeMetric.setValue(myMap[myrow].m_surfaceNode, j - startpos, result); } } } } int numMetricCols = endpos - startpos; MetricFile outputMetric, outputMetric2; for (int j = 0; j < numMetricCols; ++j) { const float* myCol; if (surfKern > 0.0f) { mySmooth->smoothColumn(&computeMetric, j, &outputMetric); AlgorithmMetricGradient(NULL, mySurf, &outputMetric, &outputMetric2, NULL, -1.0f, &myRoi, false, -1, myAreas); myCol = outputMetric2.getValuePointerForColumn(0); } else { AlgorithmMetricGradient(NULL, mySurf, &computeMetric, &outputMetric, NULL, -1.0f, &myRoi, false, j, myAreas); myCol = outputMetric.getValuePointerForColumn(0); } for (int i = 0; i < mapSize; ++i) { const float* roiColumn = myRoi.getValuePointerForColumn(0); if (roiColumn[myMap[i].m_surfaceNode] > 0.0f) { accum[i] += myCol[myMap[i].m_surfaceNode]; } } } } for (int i = 0; i < mapSize; ++i) { m_outColumn[myMap[i].m_ciftiIndex] = accum[i] / mapSize; } } void AlgorithmCiftiCorrelationGradient::processSurfaceComponent(StructureEnum::Enum& myStructure, const float& surfKern, const float& surfExclude, const float& memLimitGB, SurfaceFile* mySurf, const MetricFile* myAreas) { const CiftiXMLOld& myXML = m_inputCifti->getCiftiXMLOld(); vector myMap; myXML.getSurfaceMapForColumns(myMap, myStructure); int mapSize = (int)myMap.size(); vector accum(mapSize, 0.0); vector accumCount(mapSize, 0); int numCacheRows = mapSize; bool cacheFullInput = true; if (memLimitGB >= 0.0f) { numCacheRows = numRowsForMem(m_numCols * sizeof(float), (mySurf->getNumberOfNodes() * (sizeof(float) * 8 + 1)) / 8, mapSize, cacheFullInput); } if (numCacheRows > mapSize) { cacheFullInput = true; numCacheRows = mapSize; } if (cacheFullInput) { if (numCacheRows != mapSize) CaretLogInfo("computing " + AString::number(numCacheRows) + " rows at a time"); } else { CaretLogInfo("computing " + AString::number(numCacheRows) + " rows at a time, reading rows as needed during processing"); } const float* areaData = NULL; if (myAreas != NULL) { areaData = myAreas->getValuePointerForColumn(0); } CaretPointer myGeoBase(new GeodesicHelperBase(mySurf, areaData));//can't really have SurfaceFile cache ones with corrected areas MetricFile myRoi; myRoi.setNumberOfNodesAndColumns(mySurf->getNumberOfNodes(), 1); myRoi.initializeColumn(0); vector > roiLookup(numCacheRows);//this gets bit compressed vector origRoi(mySurf->getNumberOfNodes()); vector > excludeNodes(numCacheRows); vector rowsToCache; for (int i = 0; i < mapSize; ++i) { myRoi.setValue(myMap[i].m_surfaceNode, 0, 1.0f); if (cacheFullInput) { rowsToCache.push_back(myMap[i].m_ciftiIndex); } } if (cacheFullInput) { cacheRows(rowsToCache, mapSize); } CaretPointer mySmooth; if (surfKern > 0.0f) { mySmooth.grabNew(new MetricSmoothingObject(mySurf, surfKern, &myRoi, MetricSmoothingObject::GEO_GAUSS_AREA, areaData));//computes the smoothing weights only once per surface } for (int startpos = 0; startpos < mapSize; startpos += numCacheRows) { int endpos = startpos + numCacheRows; if (endpos > mapSize) endpos = mapSize; if (!cacheFullInput) { rowsToCache.clear(); for (int i = startpos; i < endpos; ++i) { rowsToCache.push_back(myMap[i].m_ciftiIndex); } cacheRows(rowsToCache, mapSize); } int numSurfNodes = mySurf->getNumberOfNodes(); #pragma omp CARET_PAR { vector distances; CaretPointer myGeoHelp(new GeodesicHelper(myGeoBase)); #pragma omp CARET_FOR for (int i = startpos; i < endpos; ++i) { vector& excludeRef = excludeNodes[i - startpos]; myGeoHelp->getNodesToGeoDist(myMap[i].m_surfaceNode, surfExclude, excludeRef, distances); vector& lookupRef = roiLookup[i - startpos]; lookupRef.resize(numSurfNodes); for (int j = 0; j < numSurfNodes; ++j) { lookupRef[j] = (myRoi.getValue(j, 0) > 0.0f); } int numExclude = excludeRef.size(); for (int j = 0; j < numExclude; ++j) { lookupRef[excludeRef[j]] = false; } } } int curRow = 0;//because we can't trust the order threads hit the critical section MetricFile computeMetric; computeMetric.setNumberOfNodesAndColumns(mySurf->getNumberOfNodes(), endpos - startpos); #pragma omp CARET_PAR { vector scratchRow1(m_numCols), scratchRow2(m_numCols); #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < mapSize; ++i) { float movingRrs; const float* movingRow = NULL; int myrow; #pragma omp critical {//CiftiFile may explode if we request multiple rows concurrently (needs mutexes), but we should force sequential requests anyway myrow = curRow;//so, manually force it to read sequentially ++curRow; if (!m_doubleCorr) {//when not doing double corr, we want to read single rows in order on disk movingRow = getRow(myMap[myrow].m_ciftiIndex, movingRrs, scratchRow1.data()); } } if (m_doubleCorr) {//when doing double corr, let the threads compute correlations in parallel movingRow = getRow(myMap[myrow].m_ciftiIndex, movingRrs, scratchRow1.data()); } for (int j = startpos; j < endpos; ++j) { if (roiLookup[j - startpos][myMap[myrow].m_surfaceNode]) { if (myrow >= startpos && myrow < endpos) { if (j >= myrow) { float cacheRrs; const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, scratchRow2.data()); float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs, m_numCols, m_covariance, m_applyFisher); computeMetric.setValue(myMap[myrow].m_surfaceNode, j - startpos, result); computeMetric.setValue(myMap[j].m_surfaceNode, myrow - startpos, result); } } else { float cacheRrs; const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, scratchRow2.data()); float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs, m_numCols, m_covariance, m_applyFisher); computeMetric.setValue(myMap[myrow].m_surfaceNode, j - startpos, result); } } } } } int numMetricCols = endpos - startpos; MetricFile outputMetric, outputMetric2; MetricFile excludeRoi = myRoi; for (int j = 0; j < numMetricCols; ++j) { int numExclude = (int)excludeNodes[j].size(); const float* myCol; for (int k = 0; k < numExclude; ++k) { excludeRoi.setValue(excludeNodes[j][k], 0, 0.0f);//exclude the nodes near the seed node } if (surfKern > 0.0f) { mySmooth->smoothColumn(&computeMetric, j, &outputMetric, &excludeRoi); AlgorithmMetricGradient(NULL, mySurf, &outputMetric, &outputMetric2, NULL, -1.0f, &excludeRoi, false, -1, myAreas); myCol = outputMetric2.getValuePointerForColumn(0); } else { AlgorithmMetricGradient(NULL, mySurf, &computeMetric, &outputMetric, NULL, -1.0f, &excludeRoi, false, j, myAreas); myCol = outputMetric.getValuePointerForColumn(0); } for (int i = 0; i < mapSize; ++i) { const float* roiColumn = excludeRoi.getValuePointerForColumn(0); if (roiColumn[myMap[i].m_surfaceNode] > 0.0f) { accum[i] += myCol[myMap[i].m_surfaceNode]; accumCount[i] += 1;//less dubious looking than ++accumCount[i] } } for (int k = 0; k < numExclude; ++k) { excludeRoi.setValue(excludeNodes[j][k], 0, myRoi.getValue(excludeNodes[j][k], 0));//and set them back to original roi afterwards, instead of a full reinitialize } } } for (int i = 0; i < mapSize; ++i) { if (accumCount[i] != 0) { m_outColumn[myMap[i].m_ciftiIndex] = accum[i] / accumCount[i]; } else { m_outColumn[myMap[i].m_ciftiIndex] = 0.0f; } } } void AlgorithmCiftiCorrelationGradient::processVolumeComponent(StructureEnum::Enum& myStructure, const float& volKern, const float& memLimitGB) { const CiftiXMLOld& myXML = m_inputCifti->getCiftiXMLOld(); vector myMap; myXML.getVolumeStructureMapForColumns(myMap, myStructure); int mapSize = (int)myMap.size(); vector accum(mapSize, 0.0); int numCacheRows = mapSize; bool cacheFullInput = true; vector newdims; int64_t offset[3]; if (mapSize > 0) {//make a voxel bounding box to minimize memory usage int extrema[6] = { myMap[0].m_ijk[0], myMap[0].m_ijk[0], myMap[0].m_ijk[1], myMap[0].m_ijk[1], myMap[0].m_ijk[2], myMap[0].m_ijk[2] }; for (int64_t i = 1; i < mapSize; ++i) { if (myMap[i].m_ijk[0] < extrema[0]) extrema[0] = myMap[i].m_ijk[0]; if (myMap[i].m_ijk[0] > extrema[1]) extrema[1] = myMap[i].m_ijk[0]; if (myMap[i].m_ijk[1] < extrema[2]) extrema[2] = myMap[i].m_ijk[1]; if (myMap[i].m_ijk[1] > extrema[3]) extrema[3] = myMap[i].m_ijk[1]; if (myMap[i].m_ijk[2] < extrema[4]) extrema[4] = myMap[i].m_ijk[2]; if (myMap[i].m_ijk[2] > extrema[5]) extrema[5] = myMap[i].m_ijk[2]; } newdims.push_back(extrema[1] - extrema[0] + 1); newdims.push_back(extrema[3] - extrema[2] + 1); newdims.push_back(extrema[5] - extrema[4] + 1); offset[0] = extrema[0]; offset[1] = extrema[2]; offset[2] = extrema[4]; } else { return; } if (memLimitGB >= 0.0f) { numCacheRows = numRowsForMem(m_numCols * sizeof(float), newdims[0] * newdims[1] * newdims[2] * sizeof(float), mapSize, cacheFullInput); } if (numCacheRows > mapSize) { cacheFullInput = true; numCacheRows = mapSize; } if (cacheFullInput) { if (numCacheRows != mapSize) CaretLogInfo("computing " + AString::number(numCacheRows) + " rows at a time"); } else { CaretLogInfo("computing " + AString::number(numCacheRows) + " rows at a time, reading rows as needed during processing"); } int64_t ciftiDims[3]; vector > ciftiSform; myXML.getVolumeDimsAndSForm(ciftiDims, ciftiSform); VolumeFile volRoi(newdims, ciftiSform); volRoi.setValueAllVoxels(0.0f); vector rowsToCache; for (int i = 0; i < mapSize; ++i) { volRoi.setValue(1.0f, myMap[i].m_ijk[0] - offset[0], myMap[i].m_ijk[1] - offset[1], myMap[i].m_ijk[2] - offset[2]); if (cacheFullInput) { rowsToCache.push_back(myMap[i].m_ciftiIndex); } } if (cacheFullInput) { cacheRows(rowsToCache, mapSize); } for (int startpos = 0; startpos < mapSize; startpos += numCacheRows) { int endpos = startpos + numCacheRows; if (endpos > mapSize) endpos = mapSize; if (!cacheFullInput) { rowsToCache.clear(); for (int i = startpos; i < endpos; ++i) { rowsToCache.push_back(myMap[i].m_ciftiIndex); } cacheRows(rowsToCache, mapSize); } int curRow = 0;//because we can't trust the order threads hit the critical section vector computeDims = newdims; computeDims.push_back(endpos - startpos); VolumeFile computeVol(computeDims, ciftiSform); #pragma omp CARET_PAR { vector scratchRow1(m_numCols), scratchRow2(m_numCols); #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < mapSize; ++i) { float movingRrs; const float* movingRow = NULL; int myrow; #pragma omp critical {//CiftiFile may explode if we request multiple rows concurrently (needs mutexes), but we should force sequential requests anyway myrow = curRow;//so, manually force it to read sequentially ++curRow; if (!m_doubleCorr) {//when not doing double corr, we want to read single rows in order on disk movingRow = getRow(myMap[myrow].m_ciftiIndex, movingRrs, scratchRow1.data()); } } if (m_doubleCorr) {//when doing double corr, let the threads compute correlations in parallel movingRow = getRow(myMap[myrow].m_ciftiIndex, movingRrs, scratchRow1.data()); } for (int j = startpos; j < endpos; ++j) { if (myrow >= startpos && myrow < endpos) { if (j >= myrow) { float cacheRrs; const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, scratchRow2.data()); float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs, m_numCols, m_covariance, m_applyFisher); computeVol.setValue(result, myMap[myrow].m_ijk[0] - offset[0], myMap[myrow].m_ijk[1] - offset[1], myMap[myrow].m_ijk[2] - offset[2], j - startpos); computeVol.setValue(result, myMap[j].m_ijk[0] - offset[0], myMap[j].m_ijk[1] - offset[1], myMap[j].m_ijk[2] - offset[2], myrow - startpos); } } else { float cacheRrs; const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, scratchRow2.data()); float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs, m_numCols, m_covariance, m_applyFisher); computeVol.setValue(result, myMap[myrow].m_ijk[0] - offset[0], myMap[myrow].m_ijk[1] - offset[1], myMap[myrow].m_ijk[2] - offset[2], j - startpos); } } } } VolumeFile outputVol; int numSubvols = endpos - startpos; for (int j = 0; j < numSubvols; ++j) { AlgorithmVolumeGradient(NULL, &computeVol, &outputVol, volKern, &volRoi, NULL, j); for (int i = 0; i < mapSize; ++i) { accum[i] += outputVol.getValue(myMap[i].m_ijk[0] - offset[0], myMap[i].m_ijk[1] - offset[1], myMap[i].m_ijk[2] - offset[2]); } } } for (int i = 0; i < mapSize; ++i) { m_outColumn[myMap[i].m_ciftiIndex] = accum[i] / mapSize; } } void AlgorithmCiftiCorrelationGradient::processVolumeComponent(StructureEnum::Enum& myStructure, const float& volKern, const float& volExclude, const float& memLimitGB) { const CiftiXMLOld& myXML = m_inputCifti->getCiftiXMLOld(); vector myMap; myXML.getVolumeStructureMapForColumns(myMap, myStructure); int mapSize = (int)myMap.size(); vector accum(mapSize, 0.0); vector accumCount(mapSize, 0); int numCacheRows = mapSize; bool cacheFullInput = true; vector newdims; int64_t offset[3]; if (mapSize > 0) {//make a voxel bounding box to minimize memory usage int extrema[6] = { myMap[0].m_ijk[0], myMap[0].m_ijk[0], myMap[0].m_ijk[1], myMap[0].m_ijk[1], myMap[0].m_ijk[2], myMap[0].m_ijk[2] }; for (int64_t i = 1; i < mapSize; ++i) { if (myMap[i].m_ijk[0] < extrema[0]) extrema[0] = myMap[i].m_ijk[0]; if (myMap[i].m_ijk[0] > extrema[1]) extrema[1] = myMap[i].m_ijk[0]; if (myMap[i].m_ijk[1] < extrema[2]) extrema[2] = myMap[i].m_ijk[1]; if (myMap[i].m_ijk[1] > extrema[3]) extrema[3] = myMap[i].m_ijk[1]; if (myMap[i].m_ijk[2] < extrema[4]) extrema[4] = myMap[i].m_ijk[2]; if (myMap[i].m_ijk[2] > extrema[5]) extrema[5] = myMap[i].m_ijk[2]; } newdims.push_back(extrema[1] - extrema[0] + 1); newdims.push_back(extrema[3] - extrema[2] + 1); newdims.push_back(extrema[5] - extrema[4] + 1); offset[0] = extrema[0]; offset[1] = extrema[2]; offset[2] = extrema[4]; } else { return; } if (memLimitGB >= 0.0f) { numCacheRows = numRowsForMem(m_numCols * sizeof(float), newdims[0] * newdims[1] * newdims[2] * sizeof(float), mapSize, cacheFullInput); } if (numCacheRows > mapSize) { cacheFullInput = true; numCacheRows = mapSize; } if (cacheFullInput) { if (numCacheRows != mapSize) CaretLogInfo("computing " + AString::number(numCacheRows) + " rows at a time"); } else { CaretLogInfo("computing " + AString::number(numCacheRows) + " rows at a time, reading rows as needed during processing"); } int64_t ciftiDims[3]; vector > ciftiSform; myXML.getVolumeDimsAndSForm(ciftiDims, ciftiSform); VolumeFile volRoi(newdims, ciftiSform); volRoi.setValueAllVoxels(0.0f); vector rowsToCache; for (int i = 0; i < mapSize; ++i) { volRoi.setValue(1.0f, myMap[i].m_ijk[0] - offset[0], myMap[i].m_ijk[1] - offset[1], myMap[i].m_ijk[2] - offset[2]); if (cacheFullInput) { rowsToCache.push_back(myMap[i].m_ciftiIndex); } } if (cacheFullInput) { cacheRows(rowsToCache, mapSize); } for (int startpos = 0; startpos < mapSize; startpos += numCacheRows) { int endpos = startpos + numCacheRows; if (endpos > mapSize) endpos = mapSize; if (!cacheFullInput) { rowsToCache.clear(); for (int i = startpos; i < endpos; ++i) { rowsToCache.push_back(myMap[i].m_ciftiIndex); } cacheRows(rowsToCache, mapSize); } int curRow = 0;//because we can't trust the order threads hit the critical section vector computeDims = newdims; computeDims.push_back(endpos - startpos); VolumeFile computeVol(computeDims, ciftiSform); #pragma omp CARET_PAR { vector scratchRow1(m_numCols), scratchRow2(m_numCols); #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < mapSize; ++i) { float movingRrs; const float* movingRow = NULL; int myrow; #pragma omp critical {//CiftiFile does use mutexes now (in NiftiIO), but sequential IO is better myrow = curRow;//so, manually force it to read sequentially ++curRow; if (!m_doubleCorr) {//when not doing double corr, we want to read single rows in order on disk movingRow = getRow(myMap[myrow].m_ciftiIndex, movingRrs, scratchRow1.data()); } } if (m_doubleCorr) {//when doing double corr, let the threads compute correlations in parallel movingRow = getRow(myMap[myrow].m_ciftiIndex, movingRrs, scratchRow1.data()); } Vector3D movingLoc; volRoi.indexToSpace(myMap[myrow].m_ijk, movingLoc);//NOTE: this is outside the cropped volume, but matches the real location in the full volume, because we didn't fix the center for (int j = startpos; j < endpos; ++j) { Vector3D seedLoc; volRoi.indexToSpace(myMap[j].m_ijk, seedLoc);//ditto if ((movingLoc - seedLoc).length() > volExclude)//don't correlate if closer than the exclude range { if (myrow >= startpos && myrow < endpos) { if (j >= myrow) { float cacheRrs; const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, scratchRow2.data()); float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs, m_numCols, m_covariance, m_applyFisher); computeVol.setValue(result, myMap[myrow].m_ijk[0] - offset[0], myMap[myrow].m_ijk[1] - offset[1], myMap[myrow].m_ijk[2] - offset[2], j - startpos); computeVol.setValue(result, myMap[j].m_ijk[0] - offset[0], myMap[j].m_ijk[1] - offset[1], myMap[j].m_ijk[2] - offset[2], myrow - startpos); } } else { float cacheRrs; const float* cacheRow = getRow(myMap[j].m_ciftiIndex, cacheRrs, scratchRow2.data()); float result = correlate(movingRow, movingRrs, cacheRow, cacheRrs, m_numCols, m_covariance, m_applyFisher); computeVol.setValue(result, myMap[myrow].m_ijk[0] - offset[0], myMap[myrow].m_ijk[1] - offset[1], myMap[myrow].m_ijk[2] - offset[2], j - startpos); } } } } } VolumeFile outputVol, excludeRoi(newdims, ciftiSform); excludeRoi.setFrame(volRoi.getFrame()); int numSubvols = endpos - startpos; for (int j = 0; j < numSubvols; ++j) { Vector3D seedLoc; volRoi.indexToSpace(myMap[j + startpos].m_ijk, seedLoc); for (int i = 0; i < mapSize; ++i) { Vector3D otherLoc; volRoi.indexToSpace(myMap[i].m_ijk, otherLoc); if ((otherLoc - seedLoc).length() <= volExclude) { excludeRoi.setValue(0.0f, myMap[i].m_ijk[0] - offset[0], myMap[i].m_ijk[1] - offset[1], myMap[i].m_ijk[2] - offset[2]); } } AlgorithmVolumeGradient(NULL, &computeVol, &outputVol, volKern, &excludeRoi, NULL, j); for (int i = 0; i < mapSize; ++i) { if (excludeRoi.getValue(myMap[i].m_ijk[0] - offset[0], myMap[i].m_ijk[1] - offset[1], myMap[i].m_ijk[2] - offset[2]) > 0.0f) { float val = outputVol.getValue(myMap[i].m_ijk[0] - offset[0], myMap[i].m_ijk[1] - offset[1], myMap[i].m_ijk[2] - offset[2]); accum[i] += val; accumCount[i] += 1; } else { excludeRoi.setValue(1.0f, myMap[i].m_ijk[0] - offset[0], myMap[i].m_ijk[1] - offset[1], myMap[i].m_ijk[2] - offset[2]);//reset the ROI } } } } for (int i = 0; i < mapSize; ++i) { if (accumCount[i] != 0) { m_outColumn[myMap[i].m_ciftiIndex] = accum[i] / accumCount[i]; } else { m_outColumn[myMap[i].m_ciftiIndex] = 0.0f; } } } void AlgorithmCiftiCorrelationGradient::init(CiftiFile* input, const float& memLimitGB, const bool& undoFisherInput, const bool& applyFisher, const bool& covariance, const bool doubleCorr, const bool firstFisher, const bool firstNoDemean, const bool firstCovar) { if (input->getCiftiXML().getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) throw AlgorithmException("input cifti file must have brain models mapping along column"); if (covariance) { if (applyFisher) throw AlgorithmException("cannot apply fisher z transformation to covariance"); } m_undoFisherInput = undoFisherInput; m_applyFisher = applyFisher; m_covariance = covariance; m_inputCifti = input; int64_t colLength = m_inputCifti->getNumberOfRows();//this is correct even for double correlation m_doubleCorr = doubleCorr; if (doubleCorr) { if (firstCovar && firstFisher) throw AlgorithmException("cannot apply fisher z transformation to first covariance"); m_numCols = colLength;//virtual intermediate file is square and symmetric, because there is no -roi-override option m_rowLengthFirst = m_inputCifti->getNumberOfColumns(); m_firstFisher = firstFisher; m_firstNoDemean = firstNoDemean; m_firstCovar = firstCovar; m_firstCorrInfo.resize(colLength); } else { m_numCols = m_inputCifti->getNumberOfColumns(); m_rowLengthFirst = 0;//trick to get the memory computations to work out } m_memLimitGB = memLimitGB; m_rowInfo.resize(colLength); m_outColumn.resize(colLength); } void AlgorithmCiftiCorrelationGradient::cacheRows(const vector& ciftiIndices, const int64_t mapSize) { clearCache();//clear first, to be sure we never keep a cache around too long int64_t numIndices = (int64_t)ciftiIndices.size(); m_rowCache.resize(numIndices, CacheRow(m_numCols)); if (m_doubleCorr) { for (int64_t i = 0; i < numIndices; ++i)//prepopulate intermediate output lookups, they will be useful to reuse symmetric correlations { m_rowCache[i].m_ciftiIndex = ciftiIndices[i]; m_rowInfo[ciftiIndices[i]].m_cacheIndex = i; } vector > preparedInput; FirstCorrPlan plan = firstCorrMemoryPlan(numIndices, m_numCols, m_memLimitGB, m_inputCifti->isInMemory(), m_rowLengthFirst, mapSize); if (plan.m_cacheFullInput)//we could cache full input while still chunking computation, but there is no reason to for first corr... { preparedInput.resize(m_numCols, vector(m_rowLengthFirst)); for (int64_t i = 0; i < m_numCols; ++i) { m_inputCifti->getRow(preparedInput[i].data(), i); adjustRow(preparedInput[i].data(), m_rowLengthFirst, m_firstCorrInfo[i], false, m_firstCovar, m_firstNoDemean);//also calculates rrs, needed for -no-demean-first in correlation mode m_firstCorrInfo[i].m_cacheIndex = i; } } else { preparedInput.resize(plan.m_chunkSize, vector(m_rowLengthFirst)); } vector scratchRow(m_rowLengthFirst); for (int64_t chunkStart = 0; chunkStart < m_numCols; chunkStart += plan.m_chunkSize)//cache chunks are along the complete dimension { int64_t chunkEnd = min(m_numCols, chunkStart + plan.m_chunkSize); if (!(plan.m_cacheFullInput)) { for (int64_t i = chunkStart; i < chunkEnd; ++i) { m_inputCifti->getRow(preparedInput[i - chunkStart].data(), i); adjustRow(preparedInput[i - chunkStart].data(), m_rowLengthFirst, m_firstCorrInfo[i], false, m_firstCovar, m_firstNoDemean); m_firstCorrInfo[i].m_cacheIndex = i - chunkStart; } } int64_t curIndex = 0;//force manual in-order #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t i = 0; i < numIndices; ++i)//myIndex loops through the ciftiIndices array { float* movingData = NULL; int64_t movingRow = -1, myIndex = -1; bool doAdjust = false; #pragma omp critical { myIndex = curIndex; ++curIndex; movingRow = ciftiIndices[myIndex]; if (m_firstCorrInfo[movingRow].m_cacheIndex != -1) { movingData = preparedInput[m_firstCorrInfo[movingRow].m_cacheIndex].data(); } else { doAdjust = true; movingData = scratchRow.data(); m_inputCifti->getRow(movingData, movingRow); } } if (doAdjust) { adjustRow(movingData, m_rowLengthFirst, m_firstCorrInfo[movingRow], false, m_firstCovar, m_firstNoDemean); } float movingRrs = m_firstCorrInfo[movingRow].m_rootResidSqr;//do not move this up, for some rows it is not computed until adjustRow for (int64_t j = chunkStart; j < chunkEnd; ++j)//j loops through the complete dimension, in chunks { float* cacheData = preparedInput[j - chunkStart].data(); float cacheRrs = m_firstCorrInfo[j].m_rootResidSqr; if (m_rowInfo[j].m_cacheIndex == -1 || ciftiIndices[m_rowInfo[j].m_cacheIndex] >= movingRow)//if a symmetric output element exists in the rows to cache, don't do the correlation of the lower one { float corrval = correlate(movingData, movingRrs, cacheData, cacheRrs, m_rowLengthFirst, m_firstCovar, m_firstFisher); m_rowCache[myIndex].m_row[j] = corrval; if (m_rowInfo[j].m_cacheIndex != -1)//fill the symmetric part if it exists { m_rowCache[m_rowInfo[j].m_cacheIndex].m_row[movingRow] = corrval; } } } } if (!(plan.m_cacheFullInput)) { for (int64_t i = chunkStart; i < chunkEnd; ++i) { m_firstCorrInfo[i].m_cacheIndex = -1; } } } #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t i = 0; i < numIndices; ++i) { adjustRow(m_rowCache[i].m_row.data(), m_numCols, m_rowInfo[ciftiIndices[i]], m_undoFisherInput, m_covariance, false); } } else { int64_t curIndex = 0; #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t i = 0; i < numIndices; ++i) { float* myPtr = NULL; int64_t myIndex = -1; #pragma omp critical {//manually in-order reading myIndex = curIndex; ++curIndex; CaretAssertVectorIndex(m_rowInfo, ciftiIndices[myIndex]); myPtr = m_rowCache[myIndex].m_row.data(); m_inputCifti->getRow(myPtr, ciftiIndices[myIndex]); m_rowCache[myIndex].m_ciftiIndex = ciftiIndices[myIndex]; m_rowInfo[ciftiIndices[myIndex]].m_cacheIndex = myIndex; }//end critical, now demean while the next thread reads adjustRow(myPtr, m_numCols, m_rowInfo[ciftiIndices[myIndex]], m_undoFisherInput, m_covariance, false); } } } void AlgorithmCiftiCorrelationGradient::clearCache() { for (int64_t i = 0; i < int64_t(m_rowCache.size()); ++i) { m_rowInfo[m_rowCache[i].m_ciftiIndex].m_cacheIndex = -1; } m_rowCache.clear(); } const float* AlgorithmCiftiCorrelationGradient::getRow(const int& ciftiIndex, float& rootResidSqr, float* scratchStorage) { float* ret; CaretAssertVectorIndex(m_rowInfo, ciftiIndex); if (m_rowInfo[ciftiIndex].m_cacheIndex != -1) { ret = m_rowCache[m_rowInfo[ciftiIndex].m_cacheIndex].m_row.data(); } else { ret = scratchStorage; if (m_doubleCorr) {//will only happen with a memory limit that prevents caching entire row range - may need a closer look vector fixedRow(m_rowLengthFirst), movingRow(m_rowLengthFirst); m_inputCifti->getRow(fixedRow.data(), ciftiIndex); adjustRow(fixedRow.data(), m_rowLengthFirst, m_firstCorrInfo[ciftiIndex], false, m_firstCovar, m_firstNoDemean); for (int64_t i = 0; i < m_numCols; ++i)//TODO: convert input to in-memory when possible { float* movingData = movingRow.data(); if (i == ciftiIndex) {//correlate has logic to give the right answer without doing the corr when the pointers are the same movingData = fixedRow.data(); } else { m_inputCifti->getRow(movingRow.data(), i); adjustRow(movingRow.data(), m_rowLengthFirst, m_firstCorrInfo[i], false, m_firstCovar, m_firstNoDemean); } ret[i] = correlate(fixedRow.data(), m_firstCorrInfo[ciftiIndex].m_rootResidSqr, movingData, m_firstCorrInfo[i].m_rootResidSqr, m_rowLengthFirst, m_firstCovar, m_firstFisher); } } else { m_inputCifti->getRow(ret, ciftiIndex); } adjustRow(ret, m_numCols, m_rowInfo[ciftiIndex], m_undoFisherInput, m_covariance, false); } rootResidSqr = m_rowInfo[ciftiIndex].m_rootResidSqr; return ret; } int AlgorithmCiftiCorrelationGradient::numRowsForMem(const int64_t& inrowBytes, const int64_t& outrowBytes, const int& numRows, bool& cacheFullInputOut) {//double corr might benefit from some reworking if (m_memLimitGB < 0.0f) { cacheFullInputOut = true; return numRows; } int64_t targetBytes = (int64_t)(m_memLimitGB * 1024 * 1024 * 1024); int64_t inputFileSize = sizeof(float) * m_inputCifti->getNumberOfColumns() * m_inputCifti->getNumberOfRows(); bool inputIsMemory = m_inputCifti->isInMemory();//TODO: if in memory, we don't really need to cache input rows as much... if (inputIsMemory) { targetBytes -= inputFileSize;//count in-memory input against the total too } targetBytes -= numRows * sizeof(RowInfo) + 2 * outrowBytes;//storage for mean, stdev, and info about caching, output structures if (targetBytes < 1) { if (!inputIsMemory) CaretLogWarning("extremely low memory limit used, this may take a long time and do a lot of IO"); cacheFullInputOut = false;//the most memory conservation possible return 1; } if (inrowBytes * numRows < targetBytes)//if we can cache the full input, compute the number of passes needed and compare { int64_t div = max(outrowBytes, (int64_t)1);//make sure it is never zero or negative int64_t numRowsFull = (targetBytes - inrowBytes * numRows) / div; if (numRowsFull < 1) numRowsFull = 1; int64_t fullPasses = numRows / numRowsFull; int64_t fullCorrSkip = (fullPasses * numRowsFull * (numRowsFull - 1) + (numRows - fullPasses * numRowsFull) * (numRows - fullPasses * numRowsFull - 1)) / 2; #ifdef CARET_OMP targetBytes -= inrowBytes * omp_get_max_threads(); #else targetBytes -= inrowBytes;//1 row in memory that isn't a reference to cache #endif int64_t numPassesPartial = ((outrowBytes + inrowBytes) * numRows + targetBytes - 1) / targetBytes;//break the partial cached passes up equally, to use less memory, and so we don't get an anemic pass at the end if (numPassesPartial < 1) { numPassesPartial = 1; CaretLogWarning("memory usage calculation found zero/negative pass solution, report to developers (it may use a lot of memory this run)"); } int64_t numRowsPartial = (numRows + numPassesPartial - 1) / numPassesPartial; fullPasses = numPassesPartial - 1; int64_t partialCorrSkip = (fullPasses * numRowsPartial * (numRowsPartial - 1) + (numRows - fullPasses * numRowsPartial) * (numRows - fullPasses * numRowsPartial - 1)) / 2; int ret; if (!m_doubleCorr && partialCorrSkip > fullCorrSkip * 1.05f)//prefer full caching slightly - always cache full if possible when doing double corr, recomputation is much more expensive than rereading {//assume IO and row adjustment (unfisher, subtract mean) won't be the limiting factor, since IO should be balanced during correlation due to evenly sized passes when not fully cached cacheFullInputOut = false; ret = numRowsPartial; } else { cacheFullInputOut = true; ret = numRowsFull; } if (ret < 1) ret = 1;//sanitize, just in case if (ret > numRows) ret = numRows; return ret; } else {//if we can't cache the whole thing, split passes evenly if (m_doubleCorr) { if (!inputIsMemory) {//getting a correlation row outside of the cached range will cause a huge IO increase, so convert input to memory if at all possible if (inputFileSize < targetBytes - (inrowBytes + outrowBytes) * sqrt(numRows))//TODO: consider edge cases { m_inputCifti->convertToInMemory(); inputIsMemory = true; } else { if (!firstCorrWarned) { CaretLogWarning("double correlation specified with low memory limit, this may take an extremely long time and do a lot of IO"); firstCorrWarned = true; } } } } cacheFullInputOut = false; int64_t div = max((int64_t)1, (outrowBytes + inrowBytes) * numRows); #ifdef CARET_OMP targetBytes -= inrowBytes * omp_get_max_threads(); #else targetBytes -= inrowBytes;//1 row in memory that isn't a reference to cache #endif int64_t numPassesPartial = (targetBytes + div - 1) / targetBytes; int ret = (numRows + numPassesPartial - 1) / numPassesPartial; if (ret < 1) ret = 1;//sanitize, just in case if (ret > numRows) ret = numRows; return ret; } } float AlgorithmCiftiCorrelationGradient::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiCorrelationGradient::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiCorrelationGradient.h000066400000000000000000000122301360521144700274670ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_CORRELATION_GRADIENT_H__ #define __ALGORITHM_CIFTI_CORRELATION_GRADIENT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "StructureEnum.h" namespace caret { class AlgorithmCiftiCorrelationGradient : public AbstractAlgorithm { AlgorithmCiftiCorrelationGradient(); public: struct RowInfo { bool m_haveCalculated; float m_mean, m_rootResidSqr; int m_cacheIndex; RowInfo() { m_haveCalculated = false; m_cacheIndex = -1; } }; private: struct CacheRow { int m_ciftiIndex; std::vector m_row; CacheRow(int64_t rowLength) { m_ciftiIndex = -1; m_row.resize(rowLength); } }; std::vector m_rowCache; std::vector m_rowInfo, m_firstCorrInfo; std::vector m_outColumn; int64_t m_numCols; bool m_undoFisherInput, m_applyFisher, m_covariance; CiftiFile* m_inputCifti; int64_t m_rowLengthFirst;//for -double-correlation bool m_doubleCorr, m_firstCovar, m_firstNoDemean, m_firstFisher; float m_memLimitGB; void cacheRows(const std::vector& ciftiIndices, const int64_t mapSize);//grabs the rows and does whatever it needs to, using as much IO bandwidth and CPU resources as available/needed void clearCache(); const float* getRow(const int& ciftiIndex, float& rootResidSqr, float* scratchStorage); void init(CiftiFile* input, const float& memLimitGB, const bool& undoFisherInput, const bool& applyFisher, const bool& covariance, const bool doubleCorr, const bool firstFisher, const bool firstNoDemean, const bool firstCovar); int numRowsForMem(const int64_t& inrowBytes, const int64_t& outrowBytes, const int& numRows, bool& cacheFullInput); //void processSurfaceComponentLocal(StructureEnum::Enum& myStructure, const float& surfKern, const float& memLimitGB, SurfaceFile* mySurf); void processSurfaceComponent(StructureEnum::Enum& myStructure, const float& surfKern, const float& memLimitGB, SurfaceFile* mySurf, const MetricFile* myAreas); void processSurfaceComponent(StructureEnum::Enum& myStructure, const float& surfKern, const float& surfExclude, const float& memLimitGB, SurfaceFile* mySurf, const MetricFile* myAreas); //void processVolumeComponentLocal(StructureEnum::Enum& myStructure, const float& volKern, const float& memLimitGB); void processVolumeComponent(StructureEnum::Enum& myStructure, const float& volKern, const float& memLimitGB); void processVolumeComponent(StructureEnum::Enum& myStructure, const float& volKern, const float& volExclude, const float& memLimitGB); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiCorrelationGradient(ProgressObject* myProgObj, CiftiFile* myCifti, CiftiFile* myCiftiOut, SurfaceFile* myLeftSurf = NULL, SurfaceFile* myRightSurf = NULL, SurfaceFile* myCerebSurf = NULL, const MetricFile* myLeftAreas = NULL, const MetricFile* myRightAreas = NULL, const MetricFile* myCerebAreas = NULL, const float& surfKern = -1.0f, const float& volKern = -1.0f, const bool& undoFisherInput = false, const bool& applyFisher = false, const float& surfaceExclude = -1.0f, const float& volumeExclude = -1.0f, const bool& covariance = false, const float& memLimitGB = -1.0f, const bool doubleCorr = false, const bool firstFisher = false, const bool firstNoDemean = false, const bool firstCovar = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiCorrelationGradient; } #endif //__ALGORITHM_CIFTI_CORRELATION_GRADIENT_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiCreateDenseScalar.cxx000066400000000000000000000301461360521144700274210ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiCreateDenseScalar.h" #include "AlgorithmException.h" #include "AlgorithmCiftiCreateDenseTimeseries.h" //for making the dense mapping from metric files #include "CaretAssert.h" #include "CaretLogger.h" #include "CiftiFile.h" #include "CaretAssert.h" #include "GiftiLabelTable.h" #include "MetricFile.h" #include "StructureEnum.h" #include "VolumeFile.h" #include #include #include #include using namespace caret; using namespace std; AString AlgorithmCiftiCreateDenseScalar::getCommandSwitch() { return "-cifti-create-dense-scalar"; } AString AlgorithmCiftiCreateDenseScalar::getShortDescription() { return "CREATE A CIFTI DENSE SCALAR FILE"; } OperationParameters* AlgorithmCiftiCreateDenseScalar::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiOutputParameter(1, "cifti-out", "the output cifti file"); OptionalParameter* volumeOpt = ret->createOptionalParameter(2, "-volume", "volume component"); volumeOpt->addVolumeParameter(1, "volume-data", "volume file containing all voxel data for all volume structures"); volumeOpt->addVolumeParameter(2, "structure-label-volume", "label volume file containing labels for cifti structures"); OptionalParameter* leftMetricOpt = ret->createOptionalParameter(3, "-left-metric", "metric for left surface"); leftMetricOpt->addMetricParameter(1, "metric", "the metric file"); OptionalParameter* leftRoiOpt = leftMetricOpt->createOptionalParameter(2, "-roi-left", "roi of vertices to use from left surface"); leftRoiOpt->addMetricParameter(1, "roi-metric", "the ROI as a metric file"); OptionalParameter* rightMetricOpt = ret->createOptionalParameter(4, "-right-metric", "metric for right surface"); rightMetricOpt->addMetricParameter(1, "metric", "the metric file"); OptionalParameter* rightRoiOpt = rightMetricOpt->createOptionalParameter(2, "-roi-right", "roi of vertices to use from right surface"); rightRoiOpt->addMetricParameter(1, "roi-metric", "the ROI as a metric file"); OptionalParameter* cerebMetricOpt = ret->createOptionalParameter(5, "-cerebellum-metric", "metric for the cerebellum"); cerebMetricOpt->addMetricParameter(1, "metric", "the metric file"); OptionalParameter* cerebRoiOpt = cerebMetricOpt->createOptionalParameter(2, "-roi-cerebellum", "roi of vertices to use from right surface"); cerebRoiOpt->addMetricParameter(1, "roi-metric", "the ROI as a metric file"); OptionalParameter* nameFileOpt = ret->createOptionalParameter(6, "-name-file", "use a text file to set all map names"); nameFileOpt->addStringParameter(1, "file", "text file containing map names, one per line"); AString myText = AString("All input files must have the same number of columns/subvolumes. ") + "Only the specified components will be in the output cifti file. " + "Map names will be taken from one of the input files. " + "At least one component must be specified.\n\n" + "See -volume-label-import and -volume-help for format details of label volume files. " + "The structure-label-volume should have some of the label names from this list, all other label names will be ignored:\n"; vector myStructureEnums; StructureEnum::getAllEnums(myStructureEnums); for (int i = 0; i < (int)myStructureEnums.size(); ++i) { myText += "\n" + StructureEnum::toName(myStructureEnums[i]); } ret->setHelpText(myText); return ret; } void AlgorithmCiftiCreateDenseScalar::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* myVol = NULL, *myVolLabel = NULL; CiftiFile* myCiftiOut = myParams->getOutputCifti(1); OptionalParameter* volumeOpt = myParams->getOptionalParameter(2); if (volumeOpt->m_present) { myVol = volumeOpt->getVolume(1); myVolLabel = volumeOpt->getVolume(2); } MetricFile* leftData = NULL, *leftRoi = NULL, *rightData = NULL, *rightRoi = NULL, *cerebData = NULL, *cerebRoi = NULL; OptionalParameter* leftMetricOpt = myParams->getOptionalParameter(3); if (leftMetricOpt->m_present) { leftData = leftMetricOpt->getMetric(1); OptionalParameter* leftRoiOpt = leftMetricOpt->getOptionalParameter(2); if (leftRoiOpt->m_present) { leftRoi = leftRoiOpt->getMetric(1); } } OptionalParameter* rightMetricOpt = myParams->getOptionalParameter(4); if (rightMetricOpt->m_present) { rightData = rightMetricOpt->getMetric(1); OptionalParameter* rightRoiOpt = rightMetricOpt->getOptionalParameter(2); if (rightRoiOpt->m_present) { rightRoi = rightRoiOpt->getMetric(1); } } OptionalParameter* cerebMetricOpt = myParams->getOptionalParameter(5); if (cerebMetricOpt->m_present) { cerebData = cerebMetricOpt->getMetric(1); OptionalParameter* cerebRoiOpt = cerebMetricOpt->getOptionalParameter(2); if (cerebRoiOpt->m_present) { cerebRoi = cerebRoiOpt->getMetric(1); } } vector nameStore; vector* namePtr = NULL; OptionalParameter* nameFileOpt = myParams->getOptionalParameter(6); if (nameFileOpt->m_present) { AString listfileName = nameFileOpt->getString(1); ifstream nameListFile(listfileName.toLocal8Bit().constData()); if (!nameListFile.good()) { throw AlgorithmException("error reading name list file"); } string mapName; while (getline(nameListFile, mapName)) { nameStore.push_back(mapName.c_str()); } namePtr = &nameStore; } AlgorithmCiftiCreateDenseScalar(myProgObj, myCiftiOut, myVol, myVolLabel, leftData, leftRoi, rightData, rightRoi, cerebData, cerebRoi, namePtr); } AlgorithmCiftiCreateDenseScalar::AlgorithmCiftiCreateDenseScalar(ProgressObject* myProgObj, CiftiFile* myCiftiOut, const VolumeFile* myVol, const VolumeFile* myVolLabel, const MetricFile* leftData, const MetricFile* leftRoi, const MetricFile* rightData, const MetricFile* rightRoi, const MetricFile* cerebData, const MetricFile* cerebRoi, const vector* namePtr) : AbstractAlgorithm(myProgObj) { CaretAssert(myCiftiOut != NULL); LevelProgress myProgress(myProgObj); CiftiBrainModelsMap denseMap = AlgorithmCiftiCreateDenseTimeseries::makeDenseMapping(myVol, myVolLabel, leftData, leftRoi, rightData, rightRoi, cerebData, cerebRoi); CiftiXML myXML; myXML.setNumberOfDimensions(2); myXML.setMap(CiftiXML::ALONG_COLUMN, denseMap); int numMaps = -1; const CaretMappableDataFile* nameFile = NULL; if (leftData != NULL) { numMaps = leftData->getNumberOfMaps(); nameFile = leftData; } if (rightData != NULL) { if (numMaps == -1) { numMaps = rightData->getNumberOfMaps(); if (nameFile == NULL) nameFile = rightData; } else { if (numMaps != rightData->getNumberOfMaps()) { throw AlgorithmException("right and left surface data have a different number of maps"); } } } if (cerebData != NULL) { if (numMaps == -1) { numMaps = cerebData->getNumberOfMaps(); if (nameFile == NULL) nameFile = cerebData; } else { if (numMaps != cerebData->getNumberOfMaps()) { throw AlgorithmException("cerebellum surface data has a different number of maps"); } } } if (myVol != NULL) { if (numMaps == -1) { numMaps = myVol->getNumberOfMaps(); if (nameFile == NULL) nameFile = myVol; } else { if (numMaps != myVol->getNumberOfMaps()) { throw AlgorithmException("volume data has a different number of maps"); } } } if (numMaps == -1)//doubles as checking nameFile for being NULL { throw AlgorithmException("no models specified"); } if (namePtr != NULL) { if ((int)(namePtr->size()) != numMaps) { if ((int)(namePtr->size()) < numMaps) { throw AlgorithmException("not enough map names provided"); } else { if ((int)(namePtr->size()) > numMaps + 1 || namePtr->back() != "") {//allow an extra newline on the end of the input file - could do strict checking here and fix things up in useParameters, but then it would also need to figure out number of output maps throw AlgorithmException("more map names were provided than output file would use"); } } CaretLogFine("provided map names list has an extra empty string on the end"); } } CiftiScalarsMap scalarMap; scalarMap.setLength(numMaps); for (int i = 0; i < numMaps; ++i) { if (namePtr != NULL) { scalarMap.setMapName(i, namePtr->at(i)); } else { scalarMap.setMapName(i, nameFile->getMapName(i));//copy map names } } myXML.setMap(CiftiXML::ALONG_ROW, scalarMap); myCiftiOut->setCiftiXML(myXML); CaretArray temprow(numMaps); const CiftiBrainModelsMap& myDenseMap = myXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); vector surfStructs = myDenseMap.getSurfaceStructureList(); for (int whichStruct = 0; whichStruct < (int)surfStructs.size(); ++whichStruct) { vector surfMap = myDenseMap.getSurfaceMap(surfStructs[whichStruct]); const MetricFile* dataMetric = NULL; switch (surfStructs[whichStruct]) { case StructureEnum::CORTEX_LEFT: dataMetric = leftData; break; case StructureEnum::CORTEX_RIGHT: dataMetric = rightData; break; case StructureEnum::CEREBELLUM: dataMetric = cerebData; break; default: CaretAssert(false); } for (int64_t i = 0; i < (int)surfMap.size(); ++i) { for (int t = 0; t < numMaps; ++t) { temprow[t] = dataMetric->getValue(surfMap[i].m_surfaceNode, t); } myCiftiOut->setRow(temprow, surfMap[i].m_ciftiIndex); } } vector volMap = myDenseMap.getFullVolumeMap();//we don't need to know which voxel is from which structure for (int64_t i = 0; i < (int)volMap.size(); ++i) { for (int t = 0; t < numMaps; ++t) { temprow[t] = myVol->getValue(volMap[i].m_ijk, t); } myCiftiOut->setRow(temprow, volMap[i].m_ciftiIndex); } } float AlgorithmCiftiCreateDenseScalar::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiCreateDenseScalar::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiCreateDenseScalar.h000066400000000000000000000041751360521144700270510ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_CREATE_DENSE_SCALAR_H__ #define __ALGORITHM_CIFTI_CREATE_DENSE_SCALAR_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmCiftiCreateDenseScalar : public AbstractAlgorithm { AlgorithmCiftiCreateDenseScalar(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiCreateDenseScalar(ProgressObject* myProgObj, CiftiFile* myCiftiOut, const VolumeFile* myVol = NULL, const VolumeFile* myVolLabel = NULL, const MetricFile* leftData = NULL, const MetricFile* leftRoi = NULL, const MetricFile* rightData = NULL, const MetricFile* rightRoi = NULL, const MetricFile* cerebData = NULL, const MetricFile* cerebRoi = NULL, const std::vector* namePtr = NULL); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiCreateDenseScalar; } #endif //__ALGORITHM_CIFTI_CREATE_DENSE_SCALAR_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiCreateDenseTimeseries.cxx000066400000000000000000000416601360521144700303300ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiCreateDenseTimeseries.h" #include "AlgorithmException.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPointer.h" #include "CiftiFile.h" #include "GiftiLabelTable.h" #include "MetricFile.h" #include "StructureEnum.h" #include "VolumeFile.h" #include #include #include using namespace caret; using namespace std; AString AlgorithmCiftiCreateDenseTimeseries::getCommandSwitch() { return "-cifti-create-dense-timeseries"; } AString AlgorithmCiftiCreateDenseTimeseries::getShortDescription() { return "CREATE A CIFTI DENSE TIMESERIES"; } OperationParameters* AlgorithmCiftiCreateDenseTimeseries::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiOutputParameter(1, "cifti-out", "the output cifti file"); OptionalParameter* volumeOpt = ret->createOptionalParameter(2, "-volume", "volume component"); volumeOpt->addVolumeParameter(1, "volume-data", "volume file containing all voxel data for all volume structures"); volumeOpt->addVolumeParameter(2, "structure-label-volume", "label volume file containing labels for cifti structures"); OptionalParameter* leftMetricOpt = ret->createOptionalParameter(3, "-left-metric", "metric for left surface"); leftMetricOpt->addMetricParameter(1, "metric", "the metric file"); OptionalParameter* leftRoiOpt = leftMetricOpt->createOptionalParameter(2, "-roi-left", "roi of vertices to use from left surface"); leftRoiOpt->addMetricParameter(1, "roi-metric", "the ROI as a metric file"); OptionalParameter* rightMetricOpt = ret->createOptionalParameter(4, "-right-metric", "metric for left surface"); rightMetricOpt->addMetricParameter(1, "metric", "the metric file"); OptionalParameter* rightRoiOpt = rightMetricOpt->createOptionalParameter(2, "-roi-right", "roi of vertices to use from right surface"); rightRoiOpt->addMetricParameter(1, "roi-metric", "the ROI as a metric file"); OptionalParameter* cerebMetricOpt = ret->createOptionalParameter(5, "-cerebellum-metric", "metric for the cerebellum"); cerebMetricOpt->addMetricParameter(1, "metric", "the metric file"); OptionalParameter* cerebRoiOpt = cerebMetricOpt->createOptionalParameter(2, "-roi-cerebellum", "roi of vertices to use from right surface"); cerebRoiOpt->addMetricParameter(1, "roi-metric", "the ROI as a metric file"); OptionalParameter* timestepOpt = ret->createOptionalParameter(6, "-timestep", "set the timestep"); timestepOpt->addDoubleParameter(1, "interval", "the timestep, in seconds (default 1.0)"); OptionalParameter* timestartOpt = ret->createOptionalParameter(7, "-timestart", "set the start time"); timestartOpt->addDoubleParameter(1, "start", "the time at the first frame, in seconds (default 0.0)"); OptionalParameter* unitOpt = ret->createOptionalParameter(8, "-unit", "use a unit other than time"); unitOpt->addStringParameter(1, "unit", "unit identifier (default SECOND)"); AString myText = AString("All input files must have the same number of columns/subvolumes. ") + "Only the specified components will be in the output cifti. " + "At least one component must be specified.\n\n" + "See -volume-label-import and -volume-help for format details of label volume files. " + "The structure-label-volume should have some of the label names from this list, all other label names will be ignored:\n"; vector myStructureEnums; StructureEnum::getAllEnums(myStructureEnums); for (int i = 0; i < (int)myStructureEnums.size(); ++i) { myText += "\n" + StructureEnum::toName(myStructureEnums[i]); } myText += "\n\nThe -unit option accepts these values:\n"; vector units = CiftiSeriesMap::getAllUnits(); for (int i = 0; i < (int)units.size(); ++i) { myText += "\n" + CiftiSeriesMap::unitToString(units[i]); } ret->setHelpText(myText); return ret; } void AlgorithmCiftiCreateDenseTimeseries::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* myVol = NULL, *myVolLabel = NULL; CiftiFile* myCiftiOut = myParams->getOutputCifti(1); OptionalParameter* volumeOpt = myParams->getOptionalParameter(2); if (volumeOpt->m_present) { myVol = volumeOpt->getVolume(1); myVolLabel = volumeOpt->getVolume(2); } MetricFile* leftData = NULL, *leftRoi = NULL, *rightData = NULL, *rightRoi = NULL, *cerebData = NULL, *cerebRoi = NULL; OptionalParameter* leftMetricOpt = myParams->getOptionalParameter(3); if (leftMetricOpt->m_present) { leftData = leftMetricOpt->getMetric(1); OptionalParameter* leftRoiOpt = leftMetricOpt->getOptionalParameter(2); if (leftRoiOpt->m_present) { leftRoi = leftRoiOpt->getMetric(1); } } OptionalParameter* rightMetricOpt = myParams->getOptionalParameter(4); if (rightMetricOpt->m_present) { rightData = rightMetricOpt->getMetric(1); OptionalParameter* rightRoiOpt = rightMetricOpt->getOptionalParameter(2); if (rightRoiOpt->m_present) { rightRoi = rightRoiOpt->getMetric(1); } } OptionalParameter* cerebMetricOpt = myParams->getOptionalParameter(5); if (cerebMetricOpt->m_present) { cerebData = cerebMetricOpt->getMetric(1); OptionalParameter* cerebRoiOpt = cerebMetricOpt->getOptionalParameter(2); if (cerebRoiOpt->m_present) { cerebRoi = cerebRoiOpt->getMetric(1); } } float timestep = 1.0f; OptionalParameter* timestepOpt = myParams->getOptionalParameter(6); if (timestepOpt->m_present) { timestep = (float)timestepOpt->getDouble(1); } float timestart = 0.0f; OptionalParameter* timestartOpt = myParams->getOptionalParameter(7); if (timestartOpt->m_present) { timestart = (float)timestartOpt->getDouble(1); } CiftiSeriesMap::Unit myUnit = CiftiSeriesMap::SECOND; OptionalParameter* unitOpt = myParams->getOptionalParameter(8); if (unitOpt->m_present) { AString unitName = unitOpt->getString(1); bool ok = false; myUnit = CiftiSeriesMap::stringToUnit(unitName, ok); if (!ok) { throw AlgorithmException("unrecognized unit name: '" + unitName + "'"); } } AlgorithmCiftiCreateDenseTimeseries(myProgObj, myCiftiOut, myVol, myVolLabel, leftData, leftRoi, rightData, rightRoi, cerebData, cerebRoi, timestep, timestart, myUnit); } AlgorithmCiftiCreateDenseTimeseries::AlgorithmCiftiCreateDenseTimeseries(ProgressObject* myProgObj, CiftiFile* myCiftiOut, const VolumeFile* myVol, const VolumeFile* myVolLabel, const MetricFile* leftData, const MetricFile* leftRoi, const MetricFile* rightData, const MetricFile* rightRoi, const MetricFile* cerebData, const MetricFile* cerebRoi, const float& timestep, const float& timestart, const CiftiSeriesMap::Unit& myUnit) : AbstractAlgorithm(myProgObj) { CaretAssert(myCiftiOut != NULL); LevelProgress myProgress(myProgObj); CiftiBrainModelsMap denseMap = makeDenseMapping(myVol, myVolLabel, leftData, leftRoi, rightData, rightRoi, cerebData, cerebRoi); CiftiXML myXML; myXML.setNumberOfDimensions(2); myXML.setMap(CiftiXML::ALONG_COLUMN, denseMap); int numMaps = -1; if (leftData != NULL) { numMaps = leftData->getNumberOfMaps(); } if (rightData != NULL) { if (numMaps == -1) { numMaps = rightData->getNumberOfMaps(); } else { if (numMaps != rightData->getNumberOfMaps()) { throw AlgorithmException("right and left surface data have a different number of maps"); } } } if (cerebData != NULL) { if (numMaps == -1) { numMaps = cerebData->getNumberOfMaps(); } else { if (numMaps != cerebData->getNumberOfMaps()) { throw AlgorithmException("cerebellum surface data has a different number of maps"); } } } if (myVol != NULL) { if (numMaps == -1) { numMaps = myVol->getNumberOfMaps(); } else { if (numMaps != myVol->getNumberOfMaps()) { throw AlgorithmException("volume data has a different number of maps"); } } } if (numMaps == -1) { throw AlgorithmException("no models specified"); } CiftiSeriesMap seriesMap; seriesMap.setUnit(myUnit); seriesMap.setStart(timestart); seriesMap.setStep(timestep); seriesMap.setLength(numMaps); myXML.setMap(CiftiXML::ALONG_ROW, seriesMap); myCiftiOut->setCiftiXML(myXML); CaretArray temprow(numMaps); const CiftiBrainModelsMap& myDenseMap = myXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); vector surfStructs = myDenseMap.getSurfaceStructureList(); for (int whichStruct = 0; whichStruct < (int)surfStructs.size(); ++whichStruct) { vector surfMap = myDenseMap.getSurfaceMap(surfStructs[whichStruct]); const MetricFile* dataMetric = NULL; switch (surfStructs[whichStruct]) { case StructureEnum::CORTEX_LEFT: dataMetric = leftData; break; case StructureEnum::CORTEX_RIGHT: dataMetric = rightData; break; case StructureEnum::CEREBELLUM: dataMetric = cerebData; break; default: CaretAssert(false); } for (int64_t i = 0; i < (int)surfMap.size(); ++i) { for (int t = 0; t < numMaps; ++t) { temprow[t] = dataMetric->getValue(surfMap[i].m_surfaceNode, t); } myCiftiOut->setRow(temprow, surfMap[i].m_ciftiIndex); } } vector volMap = myDenseMap.getFullVolumeMap();//we don't need to know which voxel is from which structure for (int64_t i = 0; i < (int)volMap.size(); ++i) { for (int t = 0; t < numMaps; ++t) { temprow[t] = myVol->getValue(volMap[i].m_ijk, t); } myCiftiOut->setRow(temprow, volMap[i].m_ciftiIndex); } } CiftiBrainModelsMap AlgorithmCiftiCreateDenseTimeseries::makeDenseMapping(const VolumeFile* myVol, const VolumeFile* myVolLabel, const MetricFile* leftData, const MetricFile* leftRoi, const MetricFile* rightData, const MetricFile* rightRoi, const MetricFile* cerebData, const MetricFile* cerebRoi) { bool noData = true; CiftiBrainModelsMap denseMap; if (leftData != NULL) { noData = false; if (leftRoi == NULL) { denseMap.addSurfaceModel(leftData->getNumberOfNodes(), StructureEnum::CORTEX_LEFT); } else { if (leftRoi->getNumberOfNodes() != leftData->getNumberOfNodes()) { throw AlgorithmException("left surface ROI and data have different vertex counts"); } denseMap.addSurfaceModel(leftData->getNumberOfNodes(), StructureEnum::CORTEX_LEFT, leftRoi->getValuePointerForColumn(0)); } } if (rightData != NULL) { noData = false; if (rightRoi == NULL) { denseMap.addSurfaceModel(rightData->getNumberOfNodes(), StructureEnum::CORTEX_RIGHT); } else { if (rightRoi->getNumberOfNodes() != rightData->getNumberOfNodes()) { throw AlgorithmException("right surface ROI and data have different vertex counts"); } denseMap.addSurfaceModel(rightRoi->getNumberOfNodes(), StructureEnum::CORTEX_RIGHT, rightRoi->getValuePointerForColumn(0)); } } if (cerebData != NULL) { noData = false; if (cerebRoi == NULL) { denseMap.addSurfaceModel(cerebData->getNumberOfNodes(), StructureEnum::CEREBELLUM); } else { if (cerebRoi->getNumberOfNodes() != cerebData->getNumberOfNodes()) { throw AlgorithmException("cerebellum surface ROI and data have different vertex counts"); } denseMap.addSurfaceModel(cerebRoi->getNumberOfNodes(), StructureEnum::CEREBELLUM, cerebRoi->getValuePointerForColumn(0)); } } if (myVol != NULL) { CaretAssert(myVolLabel != NULL); if (myVolLabel == NULL) { throw AlgorithmException("making a dense mapping with voxels requires a label volume"); } if (!myVol->matchesVolumeSpace(myVolLabel)) { throw AlgorithmException("label volume has a different volume space than data volume"); } if (myVolLabel->getType() != SubvolumeAttributes::LABEL) { throw AlgorithmException("parcel volume is not of type label"); } noData = false; map labelMap;//maps label values to structures vector > voxelLists;//voxel lists for each volume component map componentMap;//maps structures to indexes in voxelLists const GiftiLabelTable* myLabelTable = myVolLabel->getMapLabelTable(0); vector labelKeys; myLabelTable->getKeys(labelKeys); int count = 0; for (int i = 0; i < (int)labelKeys.size(); ++i) { bool ok = false; StructureEnum::Enum thisStructure = StructureEnum::fromName(myLabelTable->getLabelName(labelKeys[i]), &ok); if (ok) { labelMap[labelKeys[i]] = thisStructure; if (componentMap.find(thisStructure) == componentMap.end())//make sure we don't already have this structure from another label { componentMap[thisStructure] = count; ++count; } } } voxelLists.resize(count); vector mydims; myVolLabel->getDimensions(mydims); for (int64_t k = 0; k < mydims[2]; ++k) { for (int64_t j = 0; j < mydims[1]; ++j) { for (int64_t i = 0; i < mydims[0]; ++i) { int myval = (int)floor(myVolLabel->getValue(i, j, k) + 0.5f); map::iterator myiter = labelMap.find(myval); if (myiter != labelMap.end()) { int whichList = componentMap.find(myiter->second)->second;//this should always find one, so we don't need to check for being end voxelLists[whichList].push_back(i); voxelLists[whichList].push_back(j); voxelLists[whichList].push_back(k); } } } } denseMap.setVolumeSpace(VolumeSpace(mydims.data(), myVol->getSform())); for (map::iterator myiter = componentMap.begin(); myiter != componentMap.end(); ++myiter) { if (voxelLists[myiter->second].empty()) { CaretLogWarning("volume label file has empty definition of '" + StructureEnum::toName(myiter->first) + "', skipping"); } else { denseMap.addVolumeModel(myiter->first, voxelLists[myiter->second]); } } } if (noData) { throw AlgorithmException("no models specified"); } return denseMap; } float AlgorithmCiftiCreateDenseTimeseries::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiCreateDenseTimeseries::getSubAlgorithmWeight() { return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiCreateDenseTimeseries.h000066400000000000000000000055451360521144700277570ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_CREATE_DENSE_TIMESERIES_H__ #define __ALGORITHM_CIFTI_CREATE_DENSE_TIMESERIES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "CiftiBrainModelsMap.h" #include "CiftiSeriesMap.h" namespace caret { class AlgorithmCiftiCreateDenseTimeseries : public AbstractAlgorithm { AlgorithmCiftiCreateDenseTimeseries(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiCreateDenseTimeseries(ProgressObject* myProgObj, CiftiFile* myCiftiOut, const VolumeFile* myVol = NULL, const VolumeFile* myVolLabel = NULL, const MetricFile* leftData = NULL, const MetricFile* leftRoi = NULL, const MetricFile* rightData = NULL, const MetricFile* rightRoi = NULL, const MetricFile* cerebData = NULL, const MetricFile* cerebRoi = NULL, const float& timestep = 1.0f, const float& timestart = 0.0f, const CiftiSeriesMap::Unit& myUnit = CiftiSeriesMap::SECOND); static CiftiBrainModelsMap makeDenseMapping(const VolumeFile* myVol = NULL, const VolumeFile* myVolLabel = NULL, const MetricFile* leftData = NULL, const MetricFile* leftRoi = NULL, const MetricFile* rightData = NULL, const MetricFile* rightRoi = NULL, const MetricFile* cerebData = NULL, const MetricFile* cerebRoi = NULL);//where should this go? should also have version that accepts LabelFile static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiCreateDenseTimeseries; } #endif //__ALGORITHM_CIFTI_CREATE_DENSE_TIMESERIES_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiCreateLabel.cxx000066400000000000000000000425041360521144700262550ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiCreateLabel.h" #include "AlgorithmException.h" #include "CaretAssert.h" #include "CaretPointer.h" #include "CiftiFile.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "LabelFile.h" #include "MetricFile.h" #include "StructureEnum.h" #include "VolumeFile.h" #include #include #include using namespace caret; using namespace std; AString AlgorithmCiftiCreateLabel::getCommandSwitch() { return "-cifti-create-label"; } AString AlgorithmCiftiCreateLabel::getShortDescription() { return "CREATE A CIFTI LABEL FILE"; } OperationParameters* AlgorithmCiftiCreateLabel::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiOutputParameter(1, "cifti-out", "the output cifti file"); OptionalParameter* volumeOpt = ret->createOptionalParameter(2, "-volume", "volume component"); volumeOpt->addVolumeParameter(1, "label-volume", "label volume file containing the data to be copied"); volumeOpt->addVolumeParameter(2, "structure-label-volume", "label volume file that defines which voxels to use"); OptionalParameter* leftLabelOpt = ret->createOptionalParameter(3, "-left-label", "label file for left surface"); leftLabelOpt->addLabelParameter(1, "label", "the label file"); OptionalParameter* leftRoiOpt = leftLabelOpt->createOptionalParameter(2, "-roi-left", "roi of vertices to use from left surface"); leftRoiOpt->addMetricParameter(1, "roi-metric", "the ROI as a metric file"); OptionalParameter* rightLabelOpt = ret->createOptionalParameter(4, "-right-label", "label for left surface"); rightLabelOpt->addLabelParameter(1, "label", "the label file"); OptionalParameter* rightRoiOpt = rightLabelOpt->createOptionalParameter(2, "-roi-right", "roi of vertices to use from right surface"); rightRoiOpt->addMetricParameter(1, "roi-metric", "the ROI as a metric file"); OptionalParameter* cerebLabelOpt = ret->createOptionalParameter(5, "-cerebellum-label", "label for the cerebellum"); cerebLabelOpt->addLabelParameter(1, "label", "the label file"); OptionalParameter* cerebRoiOpt = cerebLabelOpt->createOptionalParameter(2, "-roi-cerebellum", "roi of vertices to use from right surface"); cerebRoiOpt->addMetricParameter(1, "roi-metric", "the ROI as a metric file"); AString myText = AString("All input files must have the same number of columns/subvolumes. Only the specified components will be in the output cifti. ") + "At least one component must be specified.\n\n" + "The -volume option requires two volume arguments, " + "the label-volume argument contains all labels you want to display (e.g. nuclei of the thalamus), " + "whereas the structure-label-volume argument contains all CIFTI voxel-based structures you want to include data within (e.g. THALAMUS_LEFT, THALAMUS_RIGHT, etc). " + "See -volume-label-import and -volume-help for format details of label volume files. " + "If you just want the labels in voxels to be the structure names, you may use the same file for both arguments. " + "The structure-label-volume must use some of the label names from this list, all other label names in the structure-label-volume will be ignored:\n"; vector myStructureEnums; StructureEnum::getAllEnums(myStructureEnums); for (int i = 0; i < (int)myStructureEnums.size(); ++i) { myText += "\n" + StructureEnum::toName(myStructureEnums[i]); } ret->setHelpText(myText); return ret; } void AlgorithmCiftiCreateLabel::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* myVol = NULL, *myVolLabel = NULL; CiftiFile* myCiftiOut = myParams->getOutputCifti(1); OptionalParameter* volumeOpt = myParams->getOptionalParameter(2); if (volumeOpt->m_present) { myVol = volumeOpt->getVolume(1); myVolLabel = volumeOpt->getVolume(2); } LabelFile* leftData = NULL, *rightData = NULL, *cerebData = NULL; MetricFile* leftRoi = NULL, *rightRoi = NULL, *cerebRoi = NULL; OptionalParameter* leftLabelOpt = myParams->getOptionalParameter(3); if (leftLabelOpt->m_present) { leftData = leftLabelOpt->getLabel(1); OptionalParameter* leftRoiOpt = leftLabelOpt->getOptionalParameter(2); if (leftRoiOpt->m_present) { leftRoi = leftRoiOpt->getMetric(1); } } OptionalParameter* rightLabelOpt = myParams->getOptionalParameter(4); if (rightLabelOpt->m_present) { rightData = rightLabelOpt->getLabel(1); OptionalParameter* rightRoiOpt = rightLabelOpt->getOptionalParameter(2); if (rightRoiOpt->m_present) { rightRoi = rightRoiOpt->getMetric(1); } } OptionalParameter* cerebLabelOpt = myParams->getOptionalParameter(5); if (cerebLabelOpt->m_present) { cerebData = cerebLabelOpt->getLabel(1); OptionalParameter* cerebRoiOpt = cerebLabelOpt->getOptionalParameter(2); if (cerebRoiOpt->m_present) { cerebRoi = cerebRoiOpt->getMetric(1); } } AlgorithmCiftiCreateLabel(myProgObj, myCiftiOut, myVol, myVolLabel, leftData, leftRoi, rightData, rightRoi, cerebData, cerebRoi); } AlgorithmCiftiCreateLabel::AlgorithmCiftiCreateLabel(ProgressObject* myProgObj, CiftiFile* myCiftiOut, const VolumeFile* myVol, const VolumeFile* myVolLabel, const LabelFile* leftData, const MetricFile* leftRoi, const LabelFile* rightData, const MetricFile* rightRoi, const LabelFile* cerebData, const MetricFile* cerebRoi) : AbstractAlgorithm(myProgObj) { CaretAssert(myCiftiOut != NULL); LevelProgress myProgress(myProgObj); CiftiXMLOld myXML; myXML.resetColumnsToBrainModels(); int numMaps = -1; if (leftData != NULL) { numMaps = leftData->getNumberOfMaps(); if (leftRoi == NULL) { myXML.addSurfaceModelToColumns(leftData->getNumberOfNodes(), StructureEnum::CORTEX_LEFT); } else { if (leftRoi->getNumberOfNodes() != leftData->getNumberOfNodes()) { throw AlgorithmException("left surface ROI and data have different vertex counts"); } myXML.addSurfaceModelToColumns(leftData->getNumberOfNodes(), StructureEnum::CORTEX_LEFT, leftRoi->getValuePointerForColumn(0)); } } if (rightData != NULL) { if (numMaps == -1) { numMaps = rightData->getNumberOfMaps(); } else { if (numMaps != rightData->getNumberOfMaps()) { throw AlgorithmException("right and left surface data have a different number of maps"); } } if (rightRoi == NULL) { myXML.addSurfaceModelToColumns(rightData->getNumberOfNodes(), StructureEnum::CORTEX_RIGHT); } else { if (rightRoi->getNumberOfNodes() != rightData->getNumberOfNodes()) { throw AlgorithmException("right surface ROI and data have different vertex counts"); } myXML.addSurfaceModelToColumns(rightRoi->getNumberOfNodes(), StructureEnum::CORTEX_RIGHT, rightRoi->getValuePointerForColumn(0)); } } if (cerebData != NULL) { if (numMaps == -1) { numMaps = cerebData->getNumberOfMaps(); } else { if (numMaps != cerebData->getNumberOfMaps()) { throw AlgorithmException("cerebellum surface data has a different number of maps"); } } if (cerebRoi == NULL) { myXML.addSurfaceModelToColumns(cerebData->getNumberOfNodes(), StructureEnum::CEREBELLUM); } else { if (cerebRoi->getNumberOfNodes() != cerebData->getNumberOfNodes()) { throw AlgorithmException("cerebellum surface ROI and data have different vertex counts"); } myXML.addSurfaceModelToColumns(cerebRoi->getNumberOfNodes(), StructureEnum::CEREBELLUM, cerebRoi->getValuePointerForColumn(0)); } } if (myVol != NULL) { CaretAssert(myVolLabel != NULL); if (myVol->getType() != SubvolumeAttributes::LABEL) { throw AlgorithmException("input volume is not a label volume"); } if (!myVol->matchesVolumeSpace(myVolLabel)) { throw AlgorithmException("label volume has a different volume space than data volume"); } if (myVolLabel->getType() != SubvolumeAttributes::LABEL) { throw AlgorithmException("parcel volume is not a label volume"); } if (numMaps == -1) { numMaps = myVol->getNumberOfMaps(); } else { if (numMaps != myVol->getNumberOfMaps()) { throw AlgorithmException("volume data has a different number of maps"); } } map labelMap;//maps label values to structures vector > voxelLists;//voxel lists for each volume component map componentMap;//maps structures to indexes in voxelLists const GiftiLabelTable* myLabelTable = myVolLabel->getMapLabelTable(0); vector labelKeys; myLabelTable->getKeys(labelKeys); int count = 0; for (int i = 0; i < (int)labelKeys.size(); ++i) { bool ok = false; StructureEnum::Enum thisStructure = StructureEnum::fromName(myLabelTable->getLabelName(labelKeys[i]), &ok); if (ok) { if (componentMap.find(thisStructure) == componentMap.end())//make sure we don't already have this structure from another label { labelMap[labelKeys[i]] = thisStructure; componentMap[thisStructure] = count; ++count; } } } if (count == 0) { throw AlgorithmException("volume label file does not contain any structure names"); } voxelLists.resize(count); vector mydims; myVolLabel->getDimensions(mydims); for (int64_t k = 0; k < mydims[2]; ++k) { for (int64_t j = 0; j < mydims[1]; ++j) { for (int64_t i = 0; i < mydims[0]; ++i) { int myval = (int)floor(myVolLabel->getValue(i, j, k) + 0.5f); map::iterator myiter = labelMap.find(myval); if (myiter != labelMap.end()) { int whichList = componentMap.find(myiter->second)->second;//this should always find one, so we don't need to check for being end voxelLists[whichList].push_back(i); voxelLists[whichList].push_back(j); voxelLists[whichList].push_back(k); } } } } int64_t ciftiVolDims[3]; ciftiVolDims[0] = mydims[0]; ciftiVolDims[1] = mydims[1]; ciftiVolDims[2] = mydims[2]; myXML.setVolumeDimsAndSForm(ciftiVolDims, myVol->getSform()); for (map::iterator myiter = componentMap.begin(); myiter != componentMap.end(); ++myiter) { if (!voxelLists[myiter->second].empty()) { myXML.addVolumeModelToColumns(voxelLists[myiter->second], myiter->first); } } if (myXML.getNumberOfRows() == 0) { throw AlgorithmException("volume label file does not label any voxels as any structure"); } } if (numMaps == -1) { throw AlgorithmException("no models specified"); } myXML.resetRowsToLabels(numMaps); vector > surfLeftConvert(numMaps), surfRightConvert(numMaps), surfCerebConvert(numMaps), volConvert(numMaps);//surfLeftConvert could just be a set, but for consistency... for (int i = 0; i < numMaps; ++i) { GiftiLabelTable mapTable;//NOTE: this relies on GiftiLabelTable::append doing the right thing bool first = true; if (leftData != NULL) { surfLeftConvert[i] = mapTable.append(*(leftData->getMapLabelTable(i)));//in case label files ever move to one table per map if (first) { first = false; myXML.setMapNameForRowIndex(i, leftData->getColumnName(i)); } } if (rightData != NULL) { surfRightConvert[i] = mapTable.append(*(rightData->getMapLabelTable(i))); if (first) { first = false; myXML.setMapNameForRowIndex(i, rightData->getColumnName(i)); } } if (cerebData != NULL) { surfCerebConvert[i] = mapTable.append(*(cerebData->getMapLabelTable(i))); if (first) { first = false; myXML.setMapNameForRowIndex(i, cerebData->getColumnName(i)); } } if (myVol != NULL) { volConvert[i] = mapTable.append(*(myVol->getMapLabelTable(i))); if (first) { first = false; myXML.setMapNameForRowIndex(i, myVol->getMapName(i)); } } myXML.setLabelTableForRowIndex(i, mapTable); } myCiftiOut->setCiftiXML(myXML); CaretArray temprow(numMaps); vector surfMap; if (myXML.getSurfaceMapForColumns(surfMap, StructureEnum::CORTEX_LEFT)) { for (int64_t i = 0; i < (int)surfMap.size(); ++i) { for (int t = 0; t < numMaps; ++t) { map::iterator iter = surfLeftConvert[t].find(leftData->getLabelKey(surfMap[i].m_surfaceNode, t)); if (iter == surfLeftConvert[t].end()) { temprow[t] = 0;//NOTE: this relies on 0 being the unused label, from the default constructor of the label table, and not being overwritten by append } else { temprow[t] = iter->second; } } myCiftiOut->setRow(temprow, surfMap[i].m_ciftiIndex); } } if (myXML.getSurfaceMapForColumns(surfMap, StructureEnum::CORTEX_RIGHT)) { for (int64_t i = 0; i < (int)surfMap.size(); ++i) { for (int t = 0; t < numMaps; ++t) { map::iterator iter = surfRightConvert[t].find(rightData->getLabelKey(surfMap[i].m_surfaceNode, t)); if (iter == surfRightConvert[t].end()) { temprow[t] = 0; } else { temprow[t] = iter->second; } } myCiftiOut->setRow(temprow, surfMap[i].m_ciftiIndex); } } if (myXML.getSurfaceMapForColumns(surfMap, StructureEnum::CEREBELLUM)) { for (int64_t i = 0; i < (int)surfMap.size(); ++i) { for (int t = 0; t < numMaps; ++t) { map::iterator iter = surfCerebConvert[t].find(cerebData->getLabelKey(surfMap[i].m_surfaceNode, t)); if (iter == surfCerebConvert[t].end()) { temprow[t] = 0; } else { temprow[t] = iter->second; } } myCiftiOut->setRow(temprow, surfMap[i].m_ciftiIndex); } } vector volMap; if (myXML.getVolumeMapForColumns(volMap))//we don't need to know which voxel is from which parcel { for (int64_t i = 0; i < (int)volMap.size(); ++i) { for (int t = 0; t < numMaps; ++t) { map::iterator iter = volConvert[t].find(myVol->getValue(volMap[i].m_ijk, t)); if (iter == volConvert[t].end()) { temprow[t] = 0; } else { temprow[t] = iter->second; } } myCiftiOut->setRow(temprow, volMap[i].m_ciftiIndex); } } } float AlgorithmCiftiCreateLabel::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiCreateLabel::getSubAlgorithmWeight() { return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiCreateLabel.h000066400000000000000000000037211360521144700257000ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_CREATE_LABEL_H__ #define __ALGORITHM_CIFTI_CREATE_LABEL_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmCiftiCreateLabel : public AbstractAlgorithm { AlgorithmCiftiCreateLabel(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiCreateLabel(ProgressObject* myProgObj, CiftiFile* myCiftiOut, const VolumeFile* myVol, const VolumeFile* myVolLabel, const LabelFile* leftData, const MetricFile* leftRoi, const LabelFile* rightData, const MetricFile* rightRoi, const LabelFile* cerebData, const MetricFile* cerebRoi); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiCreateLabel; } #endif //__ALGORITHM_CIFTI_CREATE_LABEL_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiCrossCorrelation.cxx000066400000000000000000000404511360521144700274040ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiCrossCorrelation.h" #include "AlgorithmException.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretOMP.h" #include "CiftiFile.h" #include "dot_wrapper.h" #include "FileInformation.h" #include #include using namespace caret; using namespace std; AString AlgorithmCiftiCrossCorrelation::getCommandSwitch() { return "-cifti-cross-correlation"; } AString AlgorithmCiftiCrossCorrelation::getShortDescription() { return "CORRELATE A CIFTI FILE WITH ANOTHER CIFTI FILE"; } OperationParameters* AlgorithmCiftiCrossCorrelation::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-a", "first input cifti file"); ret->addCiftiParameter(2, "cifti-b", "second input cifti file"); ret->addCiftiOutputParameter(3, "cifti-out", "output cifti file"); OptionalParameter* weightsOpt = ret->createOptionalParameter(4, "-weights", "specify column weights"); weightsOpt->addStringParameter(1, "weight-file", "text file containing one weight per column"); ret->createOptionalParameter(5, "-fisher-z", "apply fisher small z transform (ie, artanh) to correlation"); OptionalParameter* memLimitOpt = ret->createOptionalParameter(6, "-mem-limit", "restrict memory usage"); memLimitOpt->addDoubleParameter(1, "limit-GB", "memory limit in gigabytes"); ret->setHelpText( AString("Correlates every row in with every row in . ") + "The mapping along columns in becomes the mapping along rows in the output.\n\n" + "When using the -fisher-z option, the output is NOT a Z-score, it is artanh(r), to do further math on this output, consider using -cifti-math.\n\n" + "Restricting the memory usage will make it calculate the output in chunks, by reading through multiple times." ); return ret; } void AlgorithmCiftiCrossCorrelation::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* myCiftiA = myParams->getCifti(1); CiftiFile* myCiftiB = myParams->getCifti(2); CiftiFile* myCiftiOut = myParams->getOutputCifti(3); OptionalParameter* weightsOpt = myParams->getOptionalParameter(4); vector* weights = NULL, realweights;//NOTE: realweights is not a pointer if (weightsOpt->m_present) { weights = &realweights;//point it to the actual vector to signify the option is present AString weightFileName = weightsOpt->getString(1); FileInformation textFileInfo(weightFileName); if (!textFileInfo.exists()) { throw AlgorithmException("weight list file doesn't exist"); } fstream weightListFile(weightFileName.toLocal8Bit().constData(), fstream::in); if (!weightListFile.good()) { throw AlgorithmException("error reading weight list file"); } while (weightListFile.good()) { float weight; if (!(weightListFile >> weight))//yes, this is how you check fstream for successfully extracted output. seriously. { break; } realweights.push_back(weight); } } bool fisherZ = myParams->getOptionalParameter(5)->m_present; float memLimitGB = -1.0f; OptionalParameter* memLimitOpt = myParams->getOptionalParameter(6); if (memLimitOpt->m_present) { memLimitGB = (float)memLimitOpt->getDouble(1); if (memLimitGB < 0.0f) { throw AlgorithmException("memory limit cannot be negative"); } } AlgorithmCiftiCrossCorrelation(myProgObj, myCiftiA, myCiftiB, myCiftiOut, weights, fisherZ, memLimitGB); } AlgorithmCiftiCrossCorrelation::AlgorithmCiftiCrossCorrelation(ProgressObject* myProgObj, const CiftiFile* myCiftiA, const CiftiFile* myCiftiB, CiftiFile* myCiftiOut, const vector* weights, const bool& fisherZ, const float& memLimitGB) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); init(myCiftiA, myCiftiB, myCiftiOut, weights); CiftiXMLOld outXML = myCiftiA->getCiftiXMLOld(); outXML.copyMapping(CiftiXMLOld::ALONG_ROW, myCiftiB->getCiftiXMLOld(), CiftiXMLOld::ALONG_COLUMN);//(try to) copy B's along column mapping to output's along row mapping myCiftiOut->setCiftiXML(outXML); int64_t chunkSize = m_numRowsA; if (memLimitGB >= 0.0f) { chunkSize = numRowsForMem(memLimitGB); } vector > outscratch(chunkSize, vector(m_numRowsB));//allocate output rows for (int64_t chunkStart = 0; chunkStart < m_numRowsA; chunkStart += chunkSize) { int64_t chunkEnd = chunkStart + chunkSize; if (chunkEnd > m_numRowsA) chunkEnd = m_numRowsA; cacheRowsA(chunkStart, chunkEnd); int64_t counter = 0; #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t i = 0; i < m_numRowsB; ++i) { float rrsB; int64_t indB; const float* rowB; #pragma omp critical { indB = counter;//manually in-order rows because we need to read them from disk, and can't request more than one at a time ++counter; rowB = getRowB(indB, rrsB); } for (int indA = chunkStart; indA < chunkEnd; ++indA) { float rrsA; const float* rowA = getCachedRowA(indA, rrsA); outscratch[indA - chunkStart][indB] = correlate(rowA, rrsA, rowB, rrsB, fisherZ); } } for (int64_t indA = chunkStart; indA < chunkEnd; ++indA) { myCiftiOut->setRow(outscratch[indA - chunkStart].data(), indA); } } } void AlgorithmCiftiCrossCorrelation::init(const CiftiFile* myCiftiA, const CiftiFile* myCiftiB, const CiftiFile* myCiftiOut, const vector* weights) { m_numCols = myCiftiA->getNumberOfColumns(); if (myCiftiB->getNumberOfColumns() != m_numCols) throw AlgorithmException("input cifti files have different row lengths"); m_numRowsA = myCiftiA->getNumberOfRows(); m_numRowsB = myCiftiB->getNumberOfRows(); m_ciftiA = myCiftiA; m_ciftiB = myCiftiB; m_ciftiOut = myCiftiOut; m_rowInfoA.resize(m_numRowsA);//calls default constructors, setting m_haveCalculated and m_cacheIndex m_rowInfoB.resize(m_numRowsB); if (weights != NULL) { m_weightSum = 0.0; m_weightedMode = true; int64_t numWeights = (int64_t)weights->size(); if (numWeights != m_numCols) throw AlgorithmException("input weights do not match row length"); m_binaryWeights = true; for (int i = 0; i < numWeights; ++i) { float val = (*weights)[i]; if (val != 0.0f) { if (val < 0.0f) { throw AlgorithmException("weights cannot be negative"); } m_weightSum += val; m_weights.push_back(val); m_weightIndexes.push_back(i); if (val != 1.0f) { m_binaryWeights = false; } } } if (m_binaryWeights && m_weights.size() == weights->size()) { m_weightedMode = false;//all weights were 1, so switch back to normal mode } } else { m_weightedMode = false; } } int64_t AlgorithmCiftiCrossCorrelation::numRowsForMem(const float& memLimitGB) { int64_t targetBytes = (int64_t)(memLimitGB * 1024 * 1024 * 1024); if (m_ciftiOut->isInMemory()) targetBytes -= sizeof(float) * m_numRowsA * m_numRowsB;//count only in-memory output against total, the only time inputs might be in memory is in the GUI int64_t bytesPerInputRow = sizeof(float) * m_numCols;//this means we expect the user to give "current free memory" as the limit int64_t bytesPerOutputRow = sizeof(float) * m_numRowsB; #ifdef CARET_OMP targetBytes -= bytesPerInputRow * omp_get_max_threads();//subtract the temporary row memory #else targetBytes -= bytesPerInputRow; #endif int64_t ret = 1; if (targetBytes < 1) { ret = 1;//assume the user knows what they are doing when they request minimum memory usage, even if we do yell at them } else { int64_t numRowsMax = targetBytes / (bytesPerInputRow + bytesPerOutputRow);//calculate max that can fit in given memory if (numRowsMax < 1) numRowsMax = 1; int64_t numPasses = (m_numRowsA - 1) / numRowsMax + 1;//figure the number of passes that makes if (numPasses < 1) { CaretLogWarning("memory usage calculation found zero/negative pass solution, report to developers (it may use a lot of memory this run)"); numPasses = 1; } ret = (m_numRowsA - 1) / numPasses + 1;//and then figure the most even distribution for that number of passes } if (ret == 1) { if (!m_ciftiA->isInMemory() || !m_ciftiB->isInMemory()) { CaretLogWarning("requested memory usage is too low, and at least one input is not in memory, using only 1 row at a time - this may be extremely slow"); } } return ret; } float AlgorithmCiftiCrossCorrelation::correlate(const float* row1, const float& rrs1, const float* row2, const float& rrs2, const bool& fisherZ) { double r; if (m_weightedMode) { int numWeights = (int)m_weightIndexes.size();//because we compacted the data in the row to not include any zero weights double accum = dsdot(row1, row2, numWeights);//these have already had the weighted row means subtracted out, and weights applied r = accum / (rrs1 * rrs2);//as do these } else { double accum = dsdot(row1, row2, m_numCols);//these have already had the row means subtracted out r = accum / (rrs1 * rrs2); } if (fisherZ) { if (r > 0.999999) r = 0.999999;//prevent inf if (r < -0.999999) r = -0.999999;//prevent -inf return 0.5 * log((1 + r) / (1 - r)); } else { if (r > 1.0) r = 1.0;//don't output anything silly if (r < -1.0) r = -1.0; return r; } } const float* AlgorithmCiftiCrossCorrelation::getCachedRowA(const int64_t& ciftiIndex, float& rootResidSqr) { CaretAssertVectorIndex(m_rowInfoA, ciftiIndex); CaretAssert(m_rowInfoA[ciftiIndex].m_cacheIndex != -1); rootResidSqr = m_rowInfoA[ciftiIndex].m_rootResidSqr; return m_rowCacheA[m_rowInfoA[ciftiIndex].m_cacheIndex].m_row.data(); } const float* AlgorithmCiftiCrossCorrelation::getRowB(const int64_t& ciftiIndex, float& rootResidSqr) { CaretAssertVectorIndex(m_rowInfoB, ciftiIndex); float* ret = getTempRowB();//purely allocation, one array per thread m_ciftiB->getRow(ret, ciftiIndex); adjustRow(ret, m_rowInfoB[ciftiIndex]); rootResidSqr = m_rowInfoB[ciftiIndex].m_rootResidSqr;//NOTE: must do this AFTER adjustRow, because it is not computed before it on the first chunk return ret; } float* AlgorithmCiftiCrossCorrelation::getTempRowB() { #ifdef CARET_OMP int oldsize = (int)m_tempRowsB.size(); int threadNum = omp_get_thread_num(); if (threadNum >= oldsize) { m_tempRowsB.resize(threadNum + 1); for (int i = oldsize; i <= threadNum; ++i) { m_tempRowsB[i] = CaretArray(m_numCols); } } return m_tempRowsB[threadNum].getArray(); #else if (m_tempRowsB.size() == 0) { m_tempRowsB.resize(1); m_tempRowsB[0] = CaretArray(m_numCols); } return m_tempRowsB[0].getArray(); #endif } void AlgorithmCiftiCrossCorrelation::cacheRowsA(const int64_t& begin, const int64_t& end) { CaretAssert(begin > -1); CaretAssert(end <= m_numRowsA); CaretAssert(begin < end);//takes care of end <= 0 and being >= numrows int64_t cacheSize = (int64_t)m_rowCacheA.size();//clear the existing cache references for (int64_t i = 0; i < cacheSize; ++i) { m_rowInfoA[m_rowCacheA[i].m_ciftiIndex].m_cacheIndex = -1; } m_rowCacheA.resize(end - begin);//set to exactly the size needed int64_t counter = begin;//force in-order row reading via critical and counter #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t i = begin; i < end; ++i) { int64_t myindex; #pragma omp critical { myindex = counter; ++counter; m_rowCacheA[myindex - begin].m_row.resize(m_numCols); m_ciftiA->getRow(m_rowCacheA[myindex - begin].m_row.data(), myindex); } CacheRow& myRow = m_rowCacheA[myindex - begin]; myRow.m_ciftiIndex = myindex; m_rowInfoA[myindex].m_cacheIndex = myindex - begin; adjustRow(myRow.m_row.data(), m_rowInfoA[myindex]); } } void AlgorithmCiftiCrossCorrelation::adjustRow(float* row, RowInfo& info) { if (!info.m_haveCalculated)//ensure statistics are calculated { info.m_haveCalculated = true; double accum = 0.0; if (m_weightedMode) { int64_t mycount = (int64_t)m_weightIndexes.size(); if (m_binaryWeights) { for (int64_t i = 0; i < mycount; ++i) { accum += row[m_weightIndexes[i]]; } info.m_mean = accum / mycount; accum = 0.0; for (int64_t i = 0; i < mycount; ++i) { float tempf = row[m_weightIndexes[i]] - info.m_mean; accum += tempf * tempf; } info.m_rootResidSqr = sqrt(accum); } else { for (int64_t i = 0; i < mycount; ++i) { accum += m_weights[i] * row[m_weightIndexes[i]]; } info.m_mean = accum / m_weightSum; accum = 0.0; for (int64_t i = 0; i < mycount; ++i) { float tempf = row[m_weightIndexes[i]] - info.m_mean; accum += m_weights[i] * tempf * tempf; } info.m_rootResidSqr = sqrt(accum); } } else { for (int64_t i = 0; i < m_numCols; ++i) { accum += row[i]; } info.m_mean = accum / m_numCols; accum = 0.0; for (int64_t i = 0; i < m_numCols; ++i) { float tempf = row[i] - info.m_mean; accum += tempf * tempf; } info.m_rootResidSqr = sqrt(accum); } } if (m_weightedMode)//COMPACT data, subtract mean, multiply by square root of weights if applicable { int64_t mycount = (int64_t)m_weightIndexes.size(); if (m_binaryWeights) { for (int64_t i = 0; i < mycount; ++i) { row[i] = row[m_weightIndexes[i]] - info.m_mean; } } else { for (int64_t i = 0; i < mycount; ++i) { row[i] = sqrt(m_weights[i]) * (row[m_weightIndexes[i]] - info.m_mean);//this is so the numerator doesn't get squared weights applied, since this happens to both rows } } } else { for (int64_t i = 0; i < m_numCols; ++i) { row[i] -= info.m_mean; } } } float AlgorithmCiftiCrossCorrelation::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiCrossCorrelation::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiCrossCorrelation.h000066400000000000000000000072261360521144700270340ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_CROSS_CORRELATION_H__ #define __ALGORITHM_CIFTI_CROSS_CORRELATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "CaretPointer.h" #include namespace caret { class AlgorithmCiftiCrossCorrelation : public AbstractAlgorithm { struct CacheRow { int m_ciftiIndex; std::vector m_row; }; struct RowInfo { bool m_haveCalculated; float m_mean, m_rootResidSqr; int m_cacheIndex; RowInfo() { m_haveCalculated = false; m_cacheIndex = -1; } }; int64_t m_numCols, m_numRowsA, m_numRowsB; const CiftiFile* m_ciftiA, *m_ciftiB, *m_ciftiOut;//output is really only to check if it is in-memory for numRowsForMem std::vector m_rowCacheA;//we only cache from cifti A std::vector m_rowInfoA, m_rowInfoB; std::vector > m_tempRowsB;//reuse return values in getRowB instead of reallocating std::vector m_weights; std::vector m_weightIndexes; bool m_binaryWeights, m_weightedMode; double m_weightSum; AlgorithmCiftiCrossCorrelation(); void init(const CiftiFile* myCiftiA, const CiftiFile* myCiftiB, const CiftiFile* myCiftiOut, const std::vector* weights); int64_t numRowsForMem(const float& memLimitGB);//call after init() float* getTempRowB();//only used for getRowB, A rows are pulled from cache const float* getCachedRowA(const int64_t& ciftiIndex, float& rootResidSqr);//retrieve already cached rows const float* getRowB(const int64_t& ciftiIndex, float& rootResidSqr); void adjustRow(float* row, RowInfo& info); float correlate(const float* row1, const float& rrs1, const float* row2, const float& rrs2, const bool& fisherZ); void cacheRowsA(const int64_t& begin, const int64_t& end);//grabs the rows and does whatever it needs to, using as much IO bandwidth and CPU resources as available/needed protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiCrossCorrelation(ProgressObject* myProgObj, const CiftiFile* myCiftiA, const CiftiFile* myCiftiB, CiftiFile* myCiftiOut, const std::vector* weights, const bool& fisherZ, const float& memLimitGB); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiCrossCorrelation; } #endif //__ALGORITHM_CIFTI_CROSS_CORRELATION_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiDilate.cxx000066400000000000000000000355651360521144700253250ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiDilate.h" #include "AlgorithmException.h" #include "AlgorithmCiftiReplaceStructure.h" #include "AlgorithmCiftiSeparate.h" #include "AlgorithmLabelDilate.h" #include "AlgorithmMetricDilate.h" #include "AlgorithmVolumeDilate.h" #include "CiftiFile.h" #include "LabelFile.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "VolumeFile.h" using namespace caret; using namespace std; AString AlgorithmCiftiDilate::getCommandSwitch() { return "-cifti-dilate"; } AString AlgorithmCiftiDilate::getShortDescription() { return "DILATE A CIFTI FILE"; } OperationParameters* AlgorithmCiftiDilate::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-in", "the input cifti file"); ret->addStringParameter(2, "direction", "which dimension to dilate along, ROW or COLUMN"); ret->addDoubleParameter(3, "surface-distance", "the distance to dilate on surfaces, in mm"); ret->addDoubleParameter(4, "volume-distance", "the distance to dilate in the volume, in mm"); ret->addCiftiOutputParameter(5, "cifti-out", "the output cifti file"); OptionalParameter* leftSurfOpt = ret->createOptionalParameter(6, "-left-surface", "specify the left surface to use"); leftSurfOpt->addSurfaceParameter(1, "surface", "the left surface file"); OptionalParameter* leftCorrAreasOpt = leftSurfOpt->createOptionalParameter(2, "-left-corrected-areas", "vertex areas to use instead of computing them from the left surface"); leftCorrAreasOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); OptionalParameter* rightSurfOpt = ret->createOptionalParameter(7, "-right-surface", "specify the right surface to use"); rightSurfOpt->addSurfaceParameter(1, "surface", "the right surface file"); OptionalParameter* rightCorrAreasOpt = rightSurfOpt->createOptionalParameter(2, "-right-corrected-areas", "vertex areas to use instead of computing them from the right surface"); rightCorrAreasOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); OptionalParameter* cerebSurfOpt = ret->createOptionalParameter(8, "-cerebellum-surface", "specify the cerebellum surface to use"); cerebSurfOpt->addSurfaceParameter(1, "surface", "the cerebellum surface file"); OptionalParameter* cerebCorrAreasOpt = cerebSurfOpt->createOptionalParameter(2, "-cerebellum-corrected-areas", "vertex areas to use instead of computing them from the cerebellum surface"); cerebCorrAreasOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); OptionalParameter* roiOpt = ret->createOptionalParameter(9, "-bad-brainordinate-roi", "specify an roi of brainordinates to overwrite, rather than zeros"); roiOpt->addCiftiParameter(1, "roi-cifti", "cifti dscalar or dtseries file, positive values denote brainordinates to have their values replaced"); ret->createOptionalParameter(10, "-nearest", "use nearest value"); ret->createOptionalParameter(11, "-merged-volume", "treat volume components as if they were a single component"); ret->createOptionalParameter(12, "-legacy-mode", "use the math from v1.3.2 and earlier for weighted dilation"); ret->setHelpText( AString("For all data values designated as bad, if they neighbor a good value or are within the specified distance of a good value in the same kind of model, ") + "replace the value with a distance weighted average of nearby good values, otherwise set the value to zero. " + "If -nearest is specified, it will use the value from the closest good value within range instead of a weighted average. " + "When the input file contains label data, nearest dilation is used on the surface, and weighted popularity is used in the volume.\n\n" + "The -*-corrected-areas options are intended for dilating on group average surfaces, but it is only an approximate correction " + "for the reduction of structure in a group average surface.\n\n" + "If -bad-brainordinate-roi is specified, all values, including those with value zero, are good, except for locations with a positive value in the ROI. " + "If it is not specified, only values equal to zero are bad." ); return ret; } void AlgorithmCiftiDilate::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* myCifti = myParams->getCifti(1); AString directionName = myParams->getString(2); int myDir; if (directionName == "ROW") { myDir = CiftiXMLOld::ALONG_ROW; } else if (directionName == "COLUMN") { myDir = CiftiXMLOld::ALONG_COLUMN; } else { throw AlgorithmException("incorrect string for direction, use ROW or COLUMN"); } float surfDist = (float)myParams->getDouble(3); float volDist = (float)myParams->getDouble(4); CiftiFile* myCiftiOut = myParams->getOutputCifti(5); SurfaceFile* myLeftSurf = NULL, *myRightSurf = NULL, *myCerebSurf = NULL; MetricFile* myLeftAreas = NULL, *myRightAreas = NULL, *myCerebAreas = NULL; OptionalParameter* leftSurfOpt = myParams->getOptionalParameter(6); if (leftSurfOpt->m_present) { myLeftSurf = leftSurfOpt->getSurface(1); OptionalParameter* leftCorrAreasOpt = leftSurfOpt->getOptionalParameter(2); if (leftCorrAreasOpt->m_present) { myLeftAreas = leftCorrAreasOpt->getMetric(1); } } OptionalParameter* rightSurfOpt = myParams->getOptionalParameter(7); if (rightSurfOpt->m_present) { myRightSurf = rightSurfOpt->getSurface(1); OptionalParameter* rightCorrAreasOpt = rightSurfOpt->getOptionalParameter(2); if (rightCorrAreasOpt->m_present) { myRightAreas = rightCorrAreasOpt->getMetric(1); } } OptionalParameter* cerebSurfOpt = myParams->getOptionalParameter(8); if (cerebSurfOpt->m_present) { myCerebSurf = cerebSurfOpt->getSurface(1); OptionalParameter* cerebCorrAreasOpt = cerebSurfOpt->getOptionalParameter(2); if (cerebCorrAreasOpt->m_present) { myCerebAreas = cerebCorrAreasOpt->getMetric(1); } } CiftiFile* myRoi = NULL; OptionalParameter* roiOpt = myParams->getOptionalParameter(9); if (roiOpt->m_present) { myRoi = roiOpt->getCifti(1); } bool nearest = myParams->getOptionalParameter(10)->m_present; bool mergedVolume = myParams->getOptionalParameter(11)->m_present; bool legacyMode = myParams->getOptionalParameter(12)->m_present; AlgorithmCiftiDilate(myProgObj, myCifti, myDir, surfDist, volDist, myCiftiOut, myLeftSurf, myRightSurf, myCerebSurf, myLeftAreas, myRightAreas, myCerebAreas, myRoi, nearest, mergedVolume, legacyMode); } AlgorithmCiftiDilate::AlgorithmCiftiDilate(ProgressObject* myProgObj, const CiftiFile* myCifti, const int& myDir, const float& surfDist, const float& volDist, CiftiFile* myCiftiOut, const SurfaceFile* myLeftSurf, const SurfaceFile* myRightSurf, const SurfaceFile* myCerebSurf, const MetricFile* myLeftAreas, const MetricFile* myRightAreas, const MetricFile* myCerebAreas, const CiftiFile* myBadRoi, const bool& nearest, const bool& mergedVolume, const bool legacyMode) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CiftiXMLOld myXML = myCifti->getCiftiXMLOld(); vector surfaceList, volumeList; if (myDir != CiftiXMLOld::ALONG_ROW && myDir != CiftiXMLOld::ALONG_COLUMN) throw AlgorithmException("direction not supported by cifti dilate"); if (myBadRoi != NULL && !myXML.mappingMatches(myDir, myBadRoi->getCiftiXMLOld(), CiftiXMLOld::ALONG_COLUMN)) throw AlgorithmException("bad brainordinate roi has different brainordinate space than input"); if (!myXML.getStructureLists(myDir, surfaceList, volumeList)) { throw AlgorithmException("specified direction does not contain brainordinates"); } float volExponent = 7.0f, surfExponent = 6.0f; if (legacyMode) { volExponent = 2.0f; surfExponent = 2.0f; } for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) {//sanity check surfaces const SurfaceFile* mySurf = NULL; const MetricFile* myCorrAreas = NULL; AString surfType; switch (surfaceList[whichStruct]) { case StructureEnum::CORTEX_LEFT: mySurf = myLeftSurf; myCorrAreas = myLeftAreas; surfType = "left"; break; case StructureEnum::CORTEX_RIGHT: mySurf = myRightSurf; myCorrAreas = myRightAreas; surfType = "right"; break; case StructureEnum::CEREBELLUM: mySurf = myCerebSurf; myCorrAreas = myCerebAreas; surfType = "cerebellum"; break; default: throw AlgorithmException("found surface model with incorrect type: " + StructureEnum::toName(surfaceList[whichStruct])); break; } if (mySurf == NULL) { throw AlgorithmException(surfType + " surface required but not provided"); } if (mySurf->getNumberOfNodes() != myXML.getSurfaceNumberOfNodes(myDir, surfaceList[whichStruct])) { throw AlgorithmException(surfType + " surface has the wrong number of vertices"); } if (myCorrAreas != NULL && myCorrAreas->getNumberOfNodes() != mySurf->getNumberOfNodes()) { throw AlgorithmException(surfType + " surface and corrected areas metric have different numbers of vertices"); } } myCiftiOut->setCiftiXML(myXML); for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) { const SurfaceFile* mySurf = NULL; const MetricFile* myCorrAreas = NULL; switch (surfaceList[whichStruct]) { case StructureEnum::CORTEX_LEFT: mySurf = myLeftSurf; myCorrAreas = myLeftAreas; break; case StructureEnum::CORTEX_RIGHT: mySurf = myRightSurf; myCorrAreas = myRightAreas; break; case StructureEnum::CEREBELLUM: mySurf = myCerebSurf; myCorrAreas = myCerebAreas; break; default: break; } MetricFile badRoiMetric, dataRoiMetric; MetricFile* badRoiPtr = NULL; if (myBadRoi != NULL) { AlgorithmCiftiSeparate(NULL, myBadRoi, CiftiXMLOld::ALONG_COLUMN, surfaceList[whichStruct], &badRoiMetric); badRoiPtr = &badRoiMetric; } if (myXML.getMappingType(1 - myDir) == CIFTI_INDEX_TYPE_LABELS) { LabelFile myLabel, myLabelOut; AlgorithmCiftiSeparate(NULL, myCifti, myDir, surfaceList[whichStruct], &myLabel); AlgorithmLabelDilate(NULL, &myLabel, mySurf, surfDist, &myLabelOut, badRoiPtr, -1, myCorrAreas); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, surfaceList[whichStruct], &myLabelOut); } else { MetricFile myMetric, myMetricOut; AlgorithmMetricDilate::Method myMethod = AlgorithmMetricDilate::WEIGHTED; if (nearest) myMethod = AlgorithmMetricDilate::NEAREST; AlgorithmCiftiSeparate(NULL, myCifti, myDir, surfaceList[whichStruct], &myMetric, &dataRoiMetric); AlgorithmMetricDilate(NULL, &myMetric, mySurf, surfDist, &myMetricOut, badRoiPtr, &dataRoiMetric, -1, myMethod, surfExponent, myCorrAreas, legacyMode); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, surfaceList[whichStruct], &myMetricOut); } } if (mergedVolume) { if (myXML.hasVolumeData(myDir)) { VolumeFile myVol, roiVol, myVolOut, dataRoi, junkVol; VolumeFile* roiPtr = NULL, *dataRoiPtr = &dataRoi; if (legacyMode) dataRoiPtr = NULL; int64_t offset[3]; AlgorithmVolumeDilate::Method myMethod = AlgorithmVolumeDilate::WEIGHTED; if (nearest) { myMethod = AlgorithmVolumeDilate::NEAREST; } if (myBadRoi != NULL) { AlgorithmCiftiSeparate(NULL, myBadRoi, CiftiXMLOld::ALONG_COLUMN, &roiVol, offset, NULL, true); roiPtr = &roiVol; } AlgorithmCiftiSeparate(NULL, myCifti, myDir, &myVol, offset, &dataRoi, true); AlgorithmVolumeDilate(NULL, &myVol, volDist, myMethod, &myVolOut, roiPtr, dataRoiPtr, -1, volExponent, legacyMode); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, &myVolOut, true); } } else { AlgorithmVolumeDilate::Method myMethod = AlgorithmVolumeDilate::WEIGHTED; if (nearest) { myMethod = AlgorithmVolumeDilate::NEAREST; } for (int whichStruct = 0; whichStruct < (int)volumeList.size(); ++whichStruct) { VolumeFile myVol, badRoiVol, myVolOut, dataRoiVol; VolumeFile* roiPtr = NULL; int64_t offset[3]; if (myBadRoi != NULL) { AlgorithmCiftiSeparate(NULL, myBadRoi, CiftiXMLOld::ALONG_COLUMN, volumeList[whichStruct], &badRoiVol, offset, NULL, true); roiPtr = &badRoiVol; } AlgorithmCiftiSeparate(NULL, myCifti, myDir, volumeList[whichStruct], &myVol, offset, &dataRoiVol, true); AlgorithmVolumeDilate(NULL, &myVol, volDist, myMethod, &myVolOut, roiPtr, &dataRoiVol); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, volumeList[whichStruct], &myVolOut, true); } } } float AlgorithmCiftiDilate::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiDilate::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiDilate.h000066400000000000000000000041701360521144700247360ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_DILATE_H__ #define __ALGORITHM_CIFTI_DILATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmCiftiDilate : public AbstractAlgorithm { AlgorithmCiftiDilate(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiDilate(ProgressObject* myProgObj, const CiftiFile* myCifti, const int& myDir, const float& surfDist, const float& volDist, CiftiFile* myCiftiOut, const SurfaceFile* myLeftSurf = NULL, const SurfaceFile* myRightSurf = NULL, const SurfaceFile* myCerebSurf = NULL, const MetricFile* myLeftAreas = NULL, const MetricFile* myRightAreas = NULL, const MetricFile* myCerebAreas = NULL, const CiftiFile* myRoi = NULL, const bool& nearest = false, const bool& mergedVolume = false, const bool legacyMode = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiDilate; } #endif //__ALGORITHM_CIFTI_DILATE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiErode.cxx000066400000000000000000000273641360521144700251570ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiErode.h" #include "AlgorithmException.h" #include "AlgorithmCiftiSeparate.h" #include "AlgorithmCiftiReplaceStructure.h" #include "AlgorithmLabelErode.h" #include "AlgorithmMetricErode.h" #include "AlgorithmVolumeErode.h" #include "CiftiFile.h" #include "LabelFile.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "VolumeFile.h" using namespace caret; using namespace std; AString AlgorithmCiftiErode::getCommandSwitch() { return "-cifti-erode"; } AString AlgorithmCiftiErode::getShortDescription() { return "ERODE A CIFTI FILE"; } OperationParameters* AlgorithmCiftiErode::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-in", "the input cifti file"); ret->addStringParameter(2, "direction", "which dimension to dilate along, ROW or COLUMN"); ret->addDoubleParameter(3, "surface-distance", "the distance to dilate on surfaces, in mm"); ret->addDoubleParameter(4, "volume-distance", "the distance to dilate in the volume, in mm"); ret->addCiftiOutputParameter(5, "cifti-out", "the output cifti file"); OptionalParameter* leftSurfOpt = ret->createOptionalParameter(6, "-left-surface", "specify the left surface to use"); leftSurfOpt->addSurfaceParameter(1, "surface", "the left surface file"); OptionalParameter* leftCorrAreasOpt = leftSurfOpt->createOptionalParameter(2, "-left-corrected-areas", "vertex areas to use instead of computing them from the left surface"); leftCorrAreasOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); OptionalParameter* rightSurfOpt = ret->createOptionalParameter(7, "-right-surface", "specify the right surface to use"); rightSurfOpt->addSurfaceParameter(1, "surface", "the right surface file"); OptionalParameter* rightCorrAreasOpt = rightSurfOpt->createOptionalParameter(2, "-right-corrected-areas", "vertex areas to use instead of computing them from the right surface"); rightCorrAreasOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); OptionalParameter* cerebSurfOpt = ret->createOptionalParameter(8, "-cerebellum-surface", "specify the cerebellum surface to use"); cerebSurfOpt->addSurfaceParameter(1, "surface", "the cerebellum surface file"); OptionalParameter* cerebCorrAreasOpt = cerebSurfOpt->createOptionalParameter(2, "-cerebellum-corrected-areas", "vertex areas to use instead of computing them from the cerebellum surface"); cerebCorrAreasOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); ret->createOptionalParameter(9, "-merged-volume", "treat volume components as if they were a single component"); ret->setHelpText( AString("For all data values that are empty (for label data, unlabeled, for other data, zero), set the surrounding values to empty. ") + "The surrounding values are defined as the immediate neighbors and all values in the same structure within the specified distance " + "(-merged-volume treats all voxels as one structure).\n\n" + "The -*-corrected-areas options are intended for eroding on group average surfaces, but it is only an approximate correction." ); return ret; } void AlgorithmCiftiErode::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* myCifti = myParams->getCifti(1); AString directionName = myParams->getString(2); int myDir; if (directionName == "ROW") { myDir = CiftiXML::ALONG_ROW; } else if (directionName == "COLUMN") { myDir = CiftiXML::ALONG_COLUMN; } else { throw AlgorithmException("incorrect string for direction, use ROW or COLUMN"); } float surfDist = (float)myParams->getDouble(3); float volDist = (float)myParams->getDouble(4); CiftiFile* myCiftiOut = myParams->getOutputCifti(5); SurfaceFile* myLeftSurf = NULL, *myRightSurf = NULL, *myCerebSurf = NULL; MetricFile* myLeftAreas = NULL, *myRightAreas = NULL, *myCerebAreas = NULL; OptionalParameter* leftSurfOpt = myParams->getOptionalParameter(6); if (leftSurfOpt->m_present) { myLeftSurf = leftSurfOpt->getSurface(1); OptionalParameter* leftCorrAreasOpt = leftSurfOpt->getOptionalParameter(2); if (leftCorrAreasOpt->m_present) { myLeftAreas = leftCorrAreasOpt->getMetric(1); } } OptionalParameter* rightSurfOpt = myParams->getOptionalParameter(7); if (rightSurfOpt->m_present) { myRightSurf = rightSurfOpt->getSurface(1); OptionalParameter* rightCorrAreasOpt = rightSurfOpt->getOptionalParameter(2); if (rightCorrAreasOpt->m_present) { myRightAreas = rightCorrAreasOpt->getMetric(1); } } OptionalParameter* cerebSurfOpt = myParams->getOptionalParameter(8); if (cerebSurfOpt->m_present) { myCerebSurf = cerebSurfOpt->getSurface(1); OptionalParameter* cerebCorrAreasOpt = cerebSurfOpt->getOptionalParameter(2); if (cerebCorrAreasOpt->m_present) { myCerebAreas = cerebCorrAreasOpt->getMetric(1); } } bool mergedVolume = myParams->getOptionalParameter(9)->m_present; AlgorithmCiftiErode(myProgObj, myCifti, myDir, surfDist, volDist, myCiftiOut, myLeftSurf, myRightSurf, myCerebSurf, myLeftAreas, myRightAreas, myCerebAreas, mergedVolume); } AlgorithmCiftiErode::AlgorithmCiftiErode(ProgressObject* myProgObj, const CiftiFile* myCifti, const int& myDir, const float& surfDist, const float& volDist, CiftiFile* myCiftiOut, const SurfaceFile* myLeftSurf, const SurfaceFile* myRightSurf, const SurfaceFile* myCerebSurf, const MetricFile* myLeftAreas, const MetricFile* myRightAreas, const MetricFile* myCerebAreas, const bool& mergedVolume) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const CiftiXML& myXML = myCifti->getCiftiXML(); if (myXML.getNumberOfDimensions() != 2) { throw AlgorithmException("cifti erode only supports 2D cifti"); } if (myXML.getMappingType(myDir) != CiftiMappingType::BRAIN_MODELS) { throw AlgorithmException("specified direction does not contain brainordinates"); } const CiftiBrainModelsMap& myDenseMap = myXML.getBrainModelsMap(myDir); vector surfaceList = myDenseMap.getSurfaceStructureList(); for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) {//sanity check surfaces const SurfaceFile* mySurf = NULL; const MetricFile* myCorrAreas = NULL; AString surfType; switch (surfaceList[whichStruct]) { case StructureEnum::CORTEX_LEFT: mySurf = myLeftSurf; myCorrAreas = myLeftAreas; surfType = "left"; break; case StructureEnum::CORTEX_RIGHT: mySurf = myRightSurf; myCorrAreas = myRightAreas; surfType = "right"; break; case StructureEnum::CEREBELLUM: mySurf = myCerebSurf; myCorrAreas = myCerebAreas; surfType = "cerebellum"; break; default: throw AlgorithmException("found surface model with incorrect type: " + StructureEnum::toName(surfaceList[whichStruct])); break; } if (mySurf == NULL) { throw AlgorithmException(surfType + " surface required but not provided"); } if (mySurf->getNumberOfNodes() != myDenseMap.getSurfaceNumberOfNodes(surfaceList[whichStruct])) { throw AlgorithmException(surfType + " surface has the wrong number of vertices"); } if (myCorrAreas != NULL && myCorrAreas->getNumberOfNodes() != mySurf->getNumberOfNodes()) { throw AlgorithmException(surfType + " surface and corrected areas metric have different numbers of vertices"); } } myCiftiOut->setCiftiXML(myXML); for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) { const SurfaceFile* mySurf = NULL; const MetricFile* myCorrAreas = NULL; switch (surfaceList[whichStruct]) { case StructureEnum::CORTEX_LEFT: mySurf = myLeftSurf; myCorrAreas = myLeftAreas; break; case StructureEnum::CORTEX_RIGHT: mySurf = myRightSurf; myCorrAreas = myRightAreas; break; case StructureEnum::CEREBELLUM: mySurf = myCerebSurf; myCorrAreas = myCerebAreas; break; default: break; } MetricFile dataRoiMetric; if (myXML.getMappingType(1 - myDir) == CiftiMappingType::LABELS) { LabelFile myLabel, myLabelOut; AlgorithmCiftiSeparate(NULL, myCifti, myDir, surfaceList[whichStruct], &myLabel, &dataRoiMetric); AlgorithmLabelErode(NULL, &myLabel, mySurf, surfDist, &myLabelOut, &dataRoiMetric, -1, myCorrAreas); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, surfaceList[whichStruct], &myLabelOut); } else { MetricFile myMetric, myMetricOut; AlgorithmCiftiSeparate(NULL, myCifti, myDir, surfaceList[whichStruct], &myMetric, &dataRoiMetric); AlgorithmMetricErode(NULL, &myMetric, mySurf, surfDist, &myMetricOut, &dataRoiMetric, -1, myCorrAreas); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, surfaceList[whichStruct], &myMetricOut); } } if (mergedVolume) { if (myDenseMap.hasVolumeData()) { VolumeFile myVol, roiVol, myVolOut; int64_t offset[3]; AlgorithmCiftiSeparate(NULL, myCifti, myDir, &myVol, offset, &roiVol, true); AlgorithmVolumeErode(NULL, &myVol, volDist, &myVolOut, &roiVol); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, &myVolOut, true); } } else { vector volumeList = myDenseMap.getVolumeStructureList(); for (int whichStruct = 0; whichStruct < (int)volumeList.size(); ++whichStruct) { VolumeFile myVol, myVolOut, dataRoiVol; int64_t offset[3]; AlgorithmCiftiSeparate(NULL, myCifti, myDir, volumeList[whichStruct], &myVol, offset, &dataRoiVol, true); AlgorithmVolumeErode(NULL, &myVol, volDist, &myVolOut, &dataRoiVol); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, volumeList[whichStruct], &myVolOut, true); } } } float AlgorithmCiftiErode::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiErode::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiErode.h000066400000000000000000000037661360521144700246040ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_ERODE_H__ #define __ALGORITHM_CIFTI_ERODE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmCiftiErode : public AbstractAlgorithm { AlgorithmCiftiErode(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiErode(ProgressObject* myProgObj, const CiftiFile* myCifti, const int& myDir, const float& surfDist, const float& volDist, CiftiFile* myCiftiOut, const SurfaceFile* myLeftSurf = NULL, const SurfaceFile* myRightSurf = NULL, const SurfaceFile* myCerebSurf = NULL, const MetricFile* myLeftAreas = NULL, const MetricFile* myRightAreas = NULL, const MetricFile* myCerebAreas = NULL, const bool& mergedVolume = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiErode; } #endif //__ALGORITHM_CIFTI_ERODE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiExtrema.cxx000066400000000000000000000332411360521144700255150ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiExtrema.h" #include "AlgorithmException.h" #include "AlgorithmCiftiSeparate.h" #include "AlgorithmCiftiReplaceStructure.h" #include "AlgorithmMetricExtrema.h" #include "AlgorithmVolumeExtrema.h" #include "CiftiFile.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "VolumeFile.h" using namespace caret; using namespace std; AString AlgorithmCiftiExtrema::getCommandSwitch() { return "-cifti-extrema"; } AString AlgorithmCiftiExtrema::getShortDescription() { return "FIND EXTREMA IN A CIFTI FILE"; } OperationParameters* AlgorithmCiftiExtrema::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti", "the input cifti"); ret->addDoubleParameter(2, "surface-distance", "the minimum distance between extrema of the same type, for surface components"); ret->addDoubleParameter(3, "volume-distance", "the minimum distance between extrema of the same type, for volume components"); ret->addStringParameter(4, "direction", "which dimension to find extrema along, ROW or COLUMN"); ret->addCiftiOutputParameter(5, "cifti-out", "the output cifti"); OptionalParameter* leftSurfOpt = ret->createOptionalParameter(6, "-left-surface", "specify the left surface to use"); leftSurfOpt->addSurfaceParameter(1, "surface", "the left surface file"); OptionalParameter* rightSurfOpt = ret->createOptionalParameter(7, "-right-surface", "specify the right surface to use"); rightSurfOpt->addSurfaceParameter(1, "surface", "the right surface file"); OptionalParameter* cerebSurfaceOpt = ret->createOptionalParameter(8, "-cerebellum-surface", "specify the cerebellum surface to use"); cerebSurfaceOpt->addSurfaceParameter(1, "surface", "the cerebellum surface file"); OptionalParameter* presmoothSurfOpt = ret->createOptionalParameter(9, "-surface-presmooth", "smooth on the surface before finding extrema"); presmoothSurfOpt->addDoubleParameter(1, "surface-kernel", "the sigma for the gaussian surface smoothing kernel, in mm"); OptionalParameter* presmoothVolOpt = ret->createOptionalParameter(10, "-volume-presmooth", "smooth volume components before finding extrema"); presmoothVolOpt->addDoubleParameter(1, "volume-kernel", "the sigma for the gaussian volume smoothing kernel, in mm"); OptionalParameter* thresholdOpt = ret->createOptionalParameter(11, "-threshold", "ignore small extrema"); thresholdOpt->addDoubleParameter(1, "low", "the largest value to consider for being a minimum"); thresholdOpt->addDoubleParameter(2, "high", "the smallest value to consider for being a maximum"); ret->createOptionalParameter(12, "-merged-volume", "treat volume components as if they were a single component"); ret->createOptionalParameter(13, "-sum-maps", "output the sum of the extrema maps instead of each map separately"); ret->createOptionalParameter(14, "-consolidate-mode", "use consolidation of local minima instead of a large neighborhood"); ret->createOptionalParameter(15, "-only-maxima", "only find the maxima"); ret->createOptionalParameter(16, "-only-minima", "only find the minima"); ret->setHelpText( AString("Finds spatial locations in a cifti file that have more extreme values than all nearby locations in the same component (surface or volume structure). ") + "The input cifti file must have a brain models mapping along the specified direction. " + "COLUMN is the direction that works on dtseries and dscalar. For dconn, if it is symmetric use COLUMN, otherwise use ROW." ); return ret; } void AlgorithmCiftiExtrema::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* myCifti = myParams->getCifti(1); float surfDist = (float)myParams->getDouble(2); float volDist = (float)myParams->getDouble(3); AString directionName = myParams->getString(4); int myDir; if (directionName == "ROW") { myDir = CiftiXMLOld::ALONG_ROW; } else if (directionName == "COLUMN") { myDir = CiftiXMLOld::ALONG_COLUMN; } else { throw AlgorithmException("incorrect string for direction, use ROW or COLUMN"); } CiftiFile* myCiftiOut = myParams->getOutputCifti(5); SurfaceFile* myLeftSurf = NULL, *myRightSurf = NULL, *myCerebSurf = NULL; OptionalParameter* leftSurfOpt = myParams->getOptionalParameter(6); if (leftSurfOpt->m_present) { myLeftSurf = leftSurfOpt->getSurface(1); } OptionalParameter* rightSurfOpt = myParams->getOptionalParameter(7); if (rightSurfOpt->m_present) { myRightSurf = rightSurfOpt->getSurface(1); } OptionalParameter* cerebSurfOpt = myParams->getOptionalParameter(8); if (cerebSurfOpt->m_present) { myCerebSurf = cerebSurfOpt->getSurface(1); } float surfPresmooth = -1.0f; OptionalParameter* presmoothSurfOpt = myParams->getOptionalParameter(9); if (presmoothSurfOpt->m_present) { surfPresmooth = (float)presmoothSurfOpt->getDouble(1); } float volPresmooth = -1.0f; OptionalParameter* presmoothVolOpt = myParams->getOptionalParameter(10); if (presmoothVolOpt->m_present) { volPresmooth = (float)presmoothVolOpt->getDouble(1); } OptionalParameter* thresholdOpt = myParams->getOptionalParameter(11); bool thresholdMode = false; float lowThresh = 0.0f, highThresh = 0.0f; if (thresholdOpt->m_present) { thresholdMode = true; lowThresh = (float)thresholdOpt->getDouble(1); highThresh = (float)thresholdOpt->getDouble(2); } bool mergedVolume = myParams->getOptionalParameter(12)->m_present; bool sumMaps = myParams->getOptionalParameter(13)->m_present; bool consolidateMode = myParams->getOptionalParameter(14)->m_present; bool ignoreMinima = myParams->getOptionalParameter(15)->m_present; bool ignoreMaxima = myParams->getOptionalParameter(16)->m_present; if (ignoreMinima && ignoreMaxima) throw AlgorithmException("you may not specify both -only-maxima and -only-minima"); AlgorithmCiftiExtrema(myProgObj, myCifti, surfDist, volDist, myDir, myCiftiOut, myLeftSurf, myRightSurf, myCerebSurf, surfPresmooth, volPresmooth, thresholdMode, lowThresh, highThresh, mergedVolume, sumMaps, consolidateMode, ignoreMinima, ignoreMaxima); } AlgorithmCiftiExtrema::AlgorithmCiftiExtrema(ProgressObject* myProgObj, const CiftiFile* myCifti, const float& surfDist, const float& volDist, const int& myDir, CiftiFile* myCiftiOut, const SurfaceFile* myLeftSurf, const SurfaceFile* myRightSurf, const SurfaceFile* myCerebSurf, const float& surfPresmooth, const float& volPresmooth, const bool& thresholdMode, const float& lowThresh, const float& highThresh, const bool& mergedVolume, const bool& sumMaps, const bool& consolidateMode, const bool& ignoreMinima, const bool& ignoreMaxima) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CiftiXMLOld myXML = myCifti->getCiftiXMLOld(), myOutXML; myOutXML = myXML; vector surfaceList, volumeList; if (myDir == CiftiXMLOld::ALONG_COLUMN) { if (!myXML.getStructureListsForColumns(surfaceList, volumeList)) { throw AlgorithmException("specified direction does not contain brainordinates"); } } else { if (!myXML.getStructureListsForRows(surfaceList, volumeList)) { throw AlgorithmException("specified direction does not contain brainordinates"); } } for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) {//sanity check surfaces const SurfaceFile* mySurf = NULL; AString surfType; switch (surfaceList[whichStruct]) { case StructureEnum::CORTEX_LEFT: mySurf = myLeftSurf; surfType = "left"; break; case StructureEnum::CORTEX_RIGHT: mySurf = myRightSurf; surfType = "right"; break; case StructureEnum::CEREBELLUM: mySurf = myCerebSurf; surfType = "cerebellum"; break; default: throw AlgorithmException("found surface model with incorrect type: " + StructureEnum::toName(surfaceList[whichStruct])); break; } if (mySurf == NULL) { throw AlgorithmException(surfType + " surface required but not provided"); } if (myDir == CiftiXMLOld::ALONG_COLUMN) { if (mySurf->getNumberOfNodes() != myXML.getColumnSurfaceNumberOfNodes(surfaceList[whichStruct])) { throw AlgorithmException(surfType + " surface has the wrong number of vertices"); } } else { if (mySurf->getNumberOfNodes() != myXML.getRowSurfaceNumberOfNodes(surfaceList[whichStruct])) { throw AlgorithmException(surfType + " surface has the wrong number of vertices"); } } } int outDir = myDir; if (sumMaps) { if (myDir == CiftiXMLOld::ALONG_ROW)//NOTE: when using along row and -sum-maps, make a dscalar, not a scalard { myOutXML.copyMapping(CiftiXMLOld::ALONG_COLUMN, myXML, CiftiXMLOld::ALONG_ROW);//so, transpose the maps if we are using dense along row myOutXML.copyMapping(CiftiXMLOld::ALONG_ROW, myXML, CiftiXMLOld::ALONG_COLUMN); } outDir = CiftiXMLOld::ALONG_COLUMN; myOutXML.resetDirectionToScalars(CiftiXMLOld::ALONG_ROW, 1); myOutXML.setMapNameForIndex(CiftiXMLOld::ALONG_ROW, 0, "sum of extrema"); } myCiftiOut->setCiftiXML(myOutXML); for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) { const SurfaceFile* mySurf = NULL; switch (surfaceList[whichStruct]) { case StructureEnum::CORTEX_LEFT: mySurf = myLeftSurf; break; case StructureEnum::CORTEX_RIGHT: mySurf = myRightSurf; break; case StructureEnum::CEREBELLUM: mySurf = myCerebSurf; break; default: break; } MetricFile myMetric, myRoi, myMetricOut; AlgorithmCiftiSeparate(NULL, myCifti, myDir, surfaceList[whichStruct], &myMetric, &myRoi); if (thresholdMode) { AlgorithmMetricExtrema(NULL, mySurf, &myMetric, surfDist, &myMetricOut, lowThresh, highThresh, &myRoi, surfPresmooth, sumMaps, consolidateMode, ignoreMinima, ignoreMaxima); } else { AlgorithmMetricExtrema(NULL, mySurf, &myMetric, surfDist, &myMetricOut, &myRoi, surfPresmooth, sumMaps, consolidateMode, ignoreMinima, ignoreMaxima); } AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, outDir, surfaceList[whichStruct], &myMetricOut); } if (mergedVolume) { if (myCifti->getCiftiXMLOld().hasVolumeData(myDir)) { VolumeFile myVol, myRoi, myVolOut; int64_t offset[3]; AlgorithmCiftiSeparate(NULL, myCifti, myDir, &myVol, offset, &myRoi, true); if (thresholdMode) { AlgorithmVolumeExtrema(NULL, &myVol, volDist, &myVolOut, lowThresh, highThresh, &myRoi, volPresmooth, sumMaps, consolidateMode, ignoreMinima, ignoreMaxima); } else { AlgorithmVolumeExtrema(NULL, &myVol, volDist, &myVolOut, &myRoi, volPresmooth, sumMaps, consolidateMode, ignoreMinima, ignoreMaxima); } AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, outDir, &myVolOut, true); } } else { for (int whichStruct = 0; whichStruct < (int)volumeList.size(); ++whichStruct) { VolumeFile myVol, myRoi, myVolOut; int64_t offset[3]; AlgorithmCiftiSeparate(NULL, myCifti, myDir, volumeList[whichStruct], &myVol, offset, &myRoi, true); if (thresholdMode) { AlgorithmVolumeExtrema(NULL, &myVol, volDist, &myVolOut, lowThresh, highThresh, &myRoi, volPresmooth, sumMaps, consolidateMode, ignoreMinima, ignoreMaxima); } else { AlgorithmVolumeExtrema(NULL, &myVol, volDist, &myVolOut, &myRoi, volPresmooth, sumMaps, consolidateMode, ignoreMinima, ignoreMaxima); } AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, outDir, volumeList[whichStruct], &myVolOut, true); } } } float AlgorithmCiftiExtrema::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiExtrema::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiExtrema.h000066400000000000000000000044371360521144700251470ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_EXTREMA_H__ #define __ALGORITHM_CIFTI_EXTREMA_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmCiftiExtrema : public AbstractAlgorithm { AlgorithmCiftiExtrema(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiExtrema(ProgressObject* myProgObj, const CiftiFile* myCifti, const float& surfDist, const float& volDist, const int& myDir, CiftiFile* myCiftiOut, const SurfaceFile* myLeftSurf = NULL, const SurfaceFile* myRightSurf = NULL, const SurfaceFile* myCerebSurf = NULL, const float& surfPresmooth = -1.0f, const float& volPresmooth = -1.0f, const bool& thresholdMode = false, const float& lowThresh = 0.0f, const float& highThresh = 0.0f, const bool& mergedVolume = false, const bool& sumMaps = false, const bool& consolidateMode = false, const bool& ignoreMinima = false, const bool& ignoreMaxima = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiExtrema; } #endif //__ALGORITHM_CIFTI_EXTREMA_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiFalseCorrelation.cxx000066400000000000000000000236411360521144700273470ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiFalseCorrelation.h" #include "AlgorithmException.h" #include "AlgorithmCiftiReplaceStructure.h" #include "AlgorithmCiftiSeparate.h" #include "AlgorithmMetricFalseCorrelation.h" #include "CiftiFile.h" #include "SurfaceFile.h" #include "MetricFile.h" #include "VolumeFile.h" using namespace caret; using namespace std; AString AlgorithmCiftiFalseCorrelation::getCommandSwitch() { return "-cifti-false-correlation"; } AString AlgorithmCiftiFalseCorrelation::getShortDescription() { return "COMPARE CORRELATION LOCALLY AND ACROSS/THROUGH SULCI/GYRI"; } OperationParameters* AlgorithmCiftiFalseCorrelation::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-in", "the cifti file to use for correlation"); ret->addDoubleParameter(2, "3D-dist", "maximum 3D distance to check around each vertex"); ret->addDoubleParameter(3, "geo-outer", "maximum geodesic distance to use for neighboring correlation"); ret->addDoubleParameter(4, "geo-inner", "minimum geodesic distance to use for neighboring correlation"); ret->addCiftiOutputParameter(5, "cifti-out", "the output cifti dscalar file"); OptionalParameter* leftSurfOpt = ret->createOptionalParameter(6, "-left-surface", "specify the left surface to use"); leftSurfOpt->addSurfaceParameter(1, "surface", "the left surface file"); OptionalParameter* dumpLeftOpt = leftSurfOpt->createOptionalParameter(2, "-dump-text", "dump the raw measures used to a text file"); dumpLeftOpt->addStringParameter(1, "text-out", "the output text file"); OptionalParameter* rightSurfOpt = ret->createOptionalParameter(7, "-right-surface", "specify the right surface to use"); rightSurfOpt->addSurfaceParameter(1, "surface", "the right surface file"); OptionalParameter* dumpRightOpt = rightSurfOpt->createOptionalParameter(2, "-dump-text", "dump the raw measures used to a text file"); dumpRightOpt->addStringParameter(1, "text-out", "the output text file"); OptionalParameter* cerebSurfOpt = ret->createOptionalParameter(8, "-cerebellum-surface", "specify the cerebellum surface to use"); cerebSurfOpt->addSurfaceParameter(1, "surface", "the cerebellum surface file"); OptionalParameter* dumpCerebOpt = cerebSurfOpt->createOptionalParameter(2, "-dump-text", "dump the raw measures used to a text file"); dumpCerebOpt->addStringParameter(1, "text-out", "the output text file"); ret->setHelpText( AString("For each vertex, compute the average correlation within a range of geodesic distances that don't cross a sulcus/gyrus, and the correlation to the closest vertex crossing a sulcus/gyrus. ") + "A vertex is considered to cross a sulcus/gyrus if the 3D distance is less than a third of the geodesic distance. " + "The output file contains the ratio between these correlations, and some additional maps to help explain the ratio." ); return ret; } void AlgorithmCiftiFalseCorrelation::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* myCiftiIn = myParams->getCifti(1); float max3D = (float)myParams->getDouble(2); float maxgeo = (float)myParams->getDouble(3); float mingeo = (float)myParams->getDouble(4); CiftiFile* myCiftiOut = myParams->getOutputCifti(5); SurfaceFile* myLeftSurf = NULL, *myRightSurf = NULL, *myCerebSurf = NULL; AString leftDumpName, rightDumpName, cerebDumpName; OptionalParameter* leftSurfOpt = myParams->getOptionalParameter(6); if (leftSurfOpt->m_present) { myLeftSurf = leftSurfOpt->getSurface(1); OptionalParameter* dumpLeftOpt = leftSurfOpt->getOptionalParameter(2); if (dumpLeftOpt->m_present) { leftDumpName = dumpLeftOpt->getString(1); } } OptionalParameter* rightSurfOpt = myParams->getOptionalParameter(7); if (rightSurfOpt->m_present) { myRightSurf = rightSurfOpt->getSurface(1); OptionalParameter* dumpRightOpt = rightSurfOpt->getOptionalParameter(2); if (dumpRightOpt->m_present) { rightDumpName = dumpRightOpt->getString(1); } } OptionalParameter* cerebSurfOpt = myParams->getOptionalParameter(8); if (cerebSurfOpt->m_present) { myCerebSurf = cerebSurfOpt->getSurface(1); OptionalParameter* dumpCerebOpt = cerebSurfOpt->getOptionalParameter(2); if (dumpCerebOpt->m_present) { cerebDumpName = dumpCerebOpt->getString(1); } } AlgorithmCiftiFalseCorrelation(myProgObj, myCiftiIn, max3D, maxgeo, mingeo, myCiftiOut, myLeftSurf, leftDumpName, myRightSurf, rightDumpName, myCerebSurf, cerebDumpName); } AlgorithmCiftiFalseCorrelation::AlgorithmCiftiFalseCorrelation(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const float& max3D, const float& maxgeo, const float& mingeo, CiftiFile* myCiftiOut, const SurfaceFile* myLeftSurf, const AString& leftDumpName, const SurfaceFile* myRightSurf, const AString& rightDumpName, const SurfaceFile* myCerebSurf, const AString& cerebDumpName) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const CiftiXMLOld& myXML = myCiftiIn->getCiftiXMLOld(); CiftiXMLOld myNewXML = myXML; vector surfaceList, volumeList; if (!myXML.getStructureLists(CiftiXMLOld::ALONG_COLUMN, surfaceList, volumeList)) { throw AlgorithmException("input cifti does not contain brainordinates along columns"); } for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) {//sanity check surfaces const SurfaceFile* mySurf = NULL; AString surfType; switch (surfaceList[whichStruct]) { case StructureEnum::CORTEX_LEFT: mySurf = myLeftSurf; surfType = "left"; break; case StructureEnum::CORTEX_RIGHT: mySurf = myRightSurf; surfType = "right"; break; case StructureEnum::CEREBELLUM: mySurf = myCerebSurf; surfType = "cerebellum"; break; default: throw AlgorithmException("found surface model with incorrect type: " + StructureEnum::toName(surfaceList[whichStruct])); break; } if (mySurf == NULL) { throw AlgorithmException(surfType + " surface required but not provided"); } if (mySurf->getNumberOfNodes() != myXML.getSurfaceNumberOfNodes(CiftiXMLOld::ALONG_COLUMN, surfaceList[whichStruct])) { throw AlgorithmException(surfType + " surface has the wrong number of vertices"); } } myNewXML.resetRowsToScalars(5); myNewXML.setMapNameForIndex(CiftiXMLOld::ALONG_ROW, 0, "correlation ratio"); myNewXML.setMapNameForIndex(CiftiXMLOld::ALONG_ROW, 1, "non-neighborhood correlation"); myNewXML.setMapNameForIndex(CiftiXMLOld::ALONG_ROW, 2, "average neighborhood correlation"); myNewXML.setMapNameForIndex(CiftiXMLOld::ALONG_ROW, 3, "3D distance to non-neighborhood vertex"); myNewXML.setMapNameForIndex(CiftiXMLOld::ALONG_ROW, 4, "non-neighborhood vertex number"); myCiftiOut->setCiftiXML(myNewXML); for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) { const SurfaceFile* mySurf = NULL; AString dumpName; switch (surfaceList[whichStruct]) { case StructureEnum::CORTEX_LEFT: mySurf = myLeftSurf; dumpName = leftDumpName; break; case StructureEnum::CORTEX_RIGHT: mySurf = myRightSurf; dumpName = rightDumpName; break; case StructureEnum::CEREBELLUM: mySurf = myCerebSurf; dumpName = cerebDumpName; break; default: break; } MetricFile myMetric, myRoi, myMetricOut; AlgorithmCiftiSeparate(NULL, myCiftiIn, CiftiXML::ALONG_COLUMN, surfaceList[whichStruct], &myMetric, &myRoi); AlgorithmMetricFalseCorrelation(NULL, mySurf, &myMetric, &myMetricOut, max3D, maxgeo, mingeo, &myRoi, dumpName); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, CiftiXML::ALONG_COLUMN, surfaceList[whichStruct], &myMetricOut); } int64_t offset[3]; vector dims(3); vector > sform; AlgorithmCiftiSeparate::getCroppedVolSpaceAll(myCiftiIn, CiftiXML::ALONG_COLUMN, dims.data(), sform, offset); dims.push_back(5); VolumeFile zeros(dims, sform); zeros.setValueAllVoxels(0.0f); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, CiftiXML::ALONG_COLUMN, &zeros, true); } float AlgorithmCiftiFalseCorrelation::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiFalseCorrelation::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiFalseCorrelation.h000066400000000000000000000040261360521144700267700ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_FALSE_CORRELATION_H__ #define __ALGORITHM_CIFTI_FALSE_CORRELATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmCiftiFalseCorrelation : public AbstractAlgorithm { AlgorithmCiftiFalseCorrelation(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiFalseCorrelation(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const float& max3D, const float& maxgeo, const float& mingeo, CiftiFile* myCiftiOut, const SurfaceFile* myLeftSurf, const AString& leftDumpName, const SurfaceFile* myRightSurf, const AString& rightDumpName, const SurfaceFile* myCerebSurf, const AString& cerebDumpName); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiFalseCorrelation; } #endif //__ALGORITHM_CIFTI_FALSE_CORRELATION_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiFindClusters.cxx000066400000000000000000000411211360521144700265110ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiFindClusters.h" #include "AlgorithmException.h" #include "AlgorithmCiftiSeparate.h" #include "AlgorithmCiftiReplaceStructure.h" #include "AlgorithmMetricFindClusters.h" #include "AlgorithmVolumeFindClusters.h" #include "CiftiFile.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "VolumeFile.h" using namespace caret; using namespace std; AString AlgorithmCiftiFindClusters::getCommandSwitch() { return "-cifti-find-clusters"; } AString AlgorithmCiftiFindClusters::getShortDescription() { return "FILTER CLUSTERS BY AREA/VOLUME"; } OperationParameters* AlgorithmCiftiFindClusters::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti", "the input cifti"); ret->addDoubleParameter(2, "surface-value-threshold", "threshold for surface data values"); ret->addDoubleParameter(3, "surface-minimum-area", "threshold for surface cluster area, in mm^2"); ret->addDoubleParameter(4, "volume-value-threshold", "threshold for volume data values"); ret->addDoubleParameter(5, "volume-minimum-size", "threshold for volume cluster size, in mm^3"); ret->addStringParameter(6, "direction", "which dimension to use for spatial information, ROW or COLUMN"); ret->addCiftiOutputParameter(7, "cifti-out", "the output cifti"); ret->createOptionalParameter(8, "-less-than", "find values less than , rather than greater"); OptionalParameter* leftSurfOpt = ret->createOptionalParameter(9, "-left-surface", "specify the left surface to use"); leftSurfOpt->addSurfaceParameter(1, "surface", "the left surface file"); OptionalParameter* leftCorrAreasOpt = leftSurfOpt->createOptionalParameter(2, "-corrected-areas", "vertex areas to use instead of computing them from the surface"); leftCorrAreasOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); OptionalParameter* rightSurfOpt = ret->createOptionalParameter(10, "-right-surface", "specify the right surface to use"); rightSurfOpt->addSurfaceParameter(1, "surface", "the right surface file"); OptionalParameter* rightCorrAreasOpt = rightSurfOpt->createOptionalParameter(2, "-corrected-areas", "vertex areas to use instead of computing them from the surface"); rightCorrAreasOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); OptionalParameter* cerebSurfaceOpt = ret->createOptionalParameter(11, "-cerebellum-surface", "specify the cerebellum surface to use"); cerebSurfaceOpt->addSurfaceParameter(1, "surface", "the cerebellum surface file"); OptionalParameter* cerebCorrAreasOpt = cerebSurfaceOpt->createOptionalParameter(2, "-corrected-areas", "vertex areas to use instead of computing them from the surface"); cerebCorrAreasOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); OptionalParameter* roiOpt = ret->createOptionalParameter(12, "-cifti-roi", "search only within regions of interest"); roiOpt->addCiftiParameter(1, "roi-cifti", "the regions to search within, as a cifti file"); ret->createOptionalParameter(13, "-merged-volume", "treat volume components as if they were a single component"); OptionalParameter* sizeRatioOpt = ret->createOptionalParameter(15, "-size-ratio", "ignore clusters smaller than a given fraction of the largest cluster in the structure"); sizeRatioOpt->addDoubleParameter(1, "surface-ratio", "fraction of the structure's largest cluster area"); sizeRatioOpt->addDoubleParameter(2, "volume-ratio", "fraction of the structure's largest cluster volume"); OptionalParameter* distanceOpt = ret->createOptionalParameter(16, "-distance", "ignore clusters further than a given distance from the largest cluster in the structure"); distanceOpt->addDoubleParameter(1, "surface-distance", "how far from the largest cluster a cluster can be, edge to edge, in mm"); distanceOpt->addDoubleParameter(2, "volume-distance", "how far from the largest cluster a cluster can be, edge to edge, in mm"); OptionalParameter* startOpt = ret->createOptionalParameter(14, "-start", "start labeling clusters from a value other than 1"); startOpt->addIntegerParameter(1, "startval", "the value to give the first cluster found"); ret->setHelpText( AString("Outputs a cifti file with nonzero integers for all brainordinates within a large enough cluster, and zeros elsewhere. ") + "The integers denote cluster membership (by default, first cluster found will use value 1, second cluster 2, etc). " + "Cluster values are not reused across maps of the output, but instead keep counting up. " + "The input cifti file must have a brain models mapping on the chosen dimension, columns for .dtseries, and either for .dconn. " + "The ROI should have a brain models mapping along columns, exactly matching the mapping of the chosen direction in the input file. " + "Data outside the ROI is ignored." ); return ret; } void AlgorithmCiftiFindClusters::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* myCifti = myParams->getCifti(1); float surfThresh = (float)myParams->getDouble(2); float surfSize = (float)myParams->getDouble(3); float volThresh = (float)myParams->getDouble(4); float volSize = (float)myParams->getDouble(5); AString directionName = myParams->getString(6); int myDir; if (directionName == "ROW") { myDir = CiftiXML::ALONG_ROW; } else if (directionName == "COLUMN") { myDir = CiftiXML::ALONG_COLUMN; } else { throw AlgorithmException("incorrect string for direction, use ROW or COLUMN"); } CiftiFile* myCiftiOut = myParams->getOutputCifti(7); bool lessThan = myParams->getOptionalParameter(8)->m_present; SurfaceFile* myLeftSurf = NULL, *myRightSurf = NULL, *myCerebSurf = NULL; MetricFile* myLeftAreas = NULL, *myRightAreas = NULL, *myCerebAreas = NULL; OptionalParameter* leftSurfOpt = myParams->getOptionalParameter(9); if (leftSurfOpt->m_present) { myLeftSurf = leftSurfOpt->getSurface(1); OptionalParameter* leftCorrAreasOpt = leftSurfOpt->getOptionalParameter(2); if (leftCorrAreasOpt->m_present) { myLeftAreas = leftCorrAreasOpt->getMetric(1); } } OptionalParameter* rightSurfOpt = myParams->getOptionalParameter(10); if (rightSurfOpt->m_present) { myRightSurf = rightSurfOpt->getSurface(1); OptionalParameter* rightCorrAreasOpt = rightSurfOpt->getOptionalParameter(2); if (rightCorrAreasOpt->m_present) { myRightAreas = rightCorrAreasOpt->getMetric(1); } } OptionalParameter* cerebSurfOpt = myParams->getOptionalParameter(11); if (cerebSurfOpt->m_present) { myCerebSurf = cerebSurfOpt->getSurface(1); OptionalParameter* cerebCorrAreasOpt = cerebSurfOpt->getOptionalParameter(2); if (cerebCorrAreasOpt->m_present) { myCerebAreas = cerebCorrAreasOpt->getMetric(1); } } CiftiFile* roiCifti = NULL; OptionalParameter* roiOpt = myParams->getOptionalParameter(12); if (roiOpt->m_present) { roiCifti = roiOpt->getCifti(1); } bool mergedVol = myParams->getOptionalParameter(13)->m_present; OptionalParameter* startOpt = myParams->getOptionalParameter(14); int startVal = 1; if (startOpt->m_present) { startVal = (int)startOpt->getInteger(1); } OptionalParameter* sizeRatioOpt = myParams->getOptionalParameter(15); float surfSizeRatio = -1.0f, volSizeRatio = -1.0f; if (sizeRatioOpt->m_present) { surfSizeRatio = sizeRatioOpt->getDouble(1); volSizeRatio = sizeRatioOpt->getDouble(2); if (surfSizeRatio <= 0.0f && volSizeRatio <= 0.0f) { throw AlgorithmException("at least one size ratio must be positive"); } } OptionalParameter* distanceOpt = myParams->getOptionalParameter(16); float surfDistCutoff = -1.0f, volDistCutoff = -1.0f; if (distanceOpt->m_present) { surfDistCutoff = distanceOpt->getDouble(1); volDistCutoff = distanceOpt->getDouble(2); if (surfDistCutoff <= 0.0f && volDistCutoff <= 0.0f) { throw AlgorithmException("at least one distance cutoff must be positive"); } } AlgorithmCiftiFindClusters(myProgObj, myCifti, surfThresh, surfSize, volThresh, volSize, myDir, myCiftiOut, lessThan, myLeftSurf, myLeftAreas, myRightSurf, myRightAreas, myCerebSurf, myCerebAreas, roiCifti, mergedVol, startVal, NULL, surfSizeRatio, volSizeRatio, surfDistCutoff, volDistCutoff); } AlgorithmCiftiFindClusters::AlgorithmCiftiFindClusters(ProgressObject* myProgObj, const CiftiFile* myCifti, const float& surfThresh, const float& surfSize, const float& volThresh, const float& volSize, const int& myDir, CiftiFile* myCiftiOut, const bool& lessThan, const SurfaceFile* myLeftSurf, const MetricFile* myLeftAreas, const SurfaceFile* myRightSurf, const MetricFile* myRightAreas, const SurfaceFile* myCerebSurf, const MetricFile* myCerebAreas, const CiftiFile* roiCifti, const bool& mergedVol, const int& startVal, int* endVal, const float& surfSizeRatio, const float& volSizeRatio, const float& surfDistCutoff, const float& volDistCutoff) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (startVal == 0) { throw AlgorithmException("0 is not a valid cluster marking start value"); } const CiftiXML& myXML = myCifti->getCiftiXML(); if (myXML.getNumberOfDimensions() != 2) throw AlgorithmException("cifti separate only supported on 2D cifti"); if (myDir >= myXML.getNumberOfDimensions() || myDir < 0) throw AlgorithmException("direction invalid for input cifti"); if (myXML.getMappingType(myDir) != CiftiMappingType::BRAIN_MODELS) { throw AlgorithmException("specified direction does not contain brainordinates"); } const CiftiBrainModelsMap& myBrainMap = myXML.getBrainModelsMap(myDir); if (roiCifti != NULL && myBrainMap != *(roiCifti->getCiftiXML().getMap(CiftiXML::ALONG_COLUMN))) { throw AlgorithmException("along-column mapping of roi cifti does not match the smoothing direction of the input cifti"); } vector surfaceList = myBrainMap.getSurfaceStructureList(); int markVal = startVal; for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) {//sanity check surfaces const SurfaceFile* mySurf = NULL; const MetricFile* myAreas = NULL; AString surfType; switch (surfaceList[whichStruct]) { case StructureEnum::CORTEX_LEFT: mySurf = myLeftSurf; myAreas = myLeftAreas; surfType = "left"; break; case StructureEnum::CORTEX_RIGHT: mySurf = myRightSurf; myAreas = myRightAreas; surfType = "right"; break; case StructureEnum::CEREBELLUM: mySurf = myCerebSurf; myAreas = myCerebAreas; surfType = "cerebellum"; break; default: throw AlgorithmException("found surface model with incorrect type: " + StructureEnum::toName(surfaceList[whichStruct])); break; } if (mySurf == NULL) { throw AlgorithmException(surfType + " surface required but not provided"); } if (mySurf->getNumberOfNodes() != myBrainMap.getSurfaceNumberOfNodes(surfaceList[whichStruct])) { throw AlgorithmException(surfType + " surface has the wrong number of vertices"); } if (myAreas != NULL && myAreas->getNumberOfNodes() != mySurf->getNumberOfNodes()) { throw AlgorithmException(surfType + " corrected areas metric has the wrong number of vertices"); } } myCiftiOut->setCiftiXML(myXML); for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) { const SurfaceFile* mySurf = NULL; const MetricFile* myAreas = NULL; switch (surfaceList[whichStruct]) { case StructureEnum::CORTEX_LEFT: mySurf = myLeftSurf; myAreas = myLeftAreas; break; case StructureEnum::CORTEX_RIGHT: mySurf = myRightSurf; myAreas = myRightAreas; break; case StructureEnum::CEREBELLUM: mySurf = myCerebSurf; myAreas = myCerebAreas; break; default: break; } MetricFile myMetric, myRoi, myMetricOut; AlgorithmCiftiSeparate(NULL, myCifti, myDir, surfaceList[whichStruct], &myMetric, &myRoi); if (roiCifti != NULL) {//due to above testing, we know the structure mask is the same, so just overwrite the ROI from the mask AlgorithmCiftiSeparate(NULL, roiCifti, CiftiXML::ALONG_COLUMN, surfaceList[whichStruct], &myRoi); } AlgorithmMetricFindClusters(NULL, mySurf, &myMetric, surfThresh, surfSize, &myMetricOut, lessThan, &myRoi, myAreas, -1, markVal, &markVal, surfSizeRatio, surfDistCutoff); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, surfaceList[whichStruct], &myMetricOut); } if (mergedVol) { if (myBrainMap.hasVolumeData()) { VolumeFile myVol, myRoi, myVolOut; int64_t offset[3]; AlgorithmCiftiSeparate(NULL, myCifti, myDir, &myVol, offset, &myRoi, true); if (roiCifti != NULL) {//due to above testing, we know the structure mask is the same, so just overwrite the ROI from the mask AlgorithmCiftiSeparate(NULL, roiCifti, CiftiXMLOld::ALONG_COLUMN, &myRoi, offset, NULL, true); } AlgorithmVolumeFindClusters(NULL, &myVol, volThresh, volSize, &myVolOut, lessThan, &myRoi, -1, markVal, &markVal, volSizeRatio, volDistCutoff); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, &myVolOut, true); } } else { vector volumeList = myBrainMap.getVolumeStructureList(); for (int whichStruct = 0; whichStruct < (int)volumeList.size(); ++whichStruct) { VolumeFile myVol, myRoi, myVolOut; int64_t offset[3]; AlgorithmCiftiSeparate(NULL, myCifti, myDir, volumeList[whichStruct], &myVol, offset, &myRoi, true); if (roiCifti != NULL) {//due to above testing, we know the structure mask is the same, so just overwrite the ROI from the mask AlgorithmCiftiSeparate(NULL, roiCifti, CiftiXML::ALONG_COLUMN, volumeList[whichStruct], &myRoi, offset, NULL, true); } AlgorithmVolumeFindClusters(NULL, &myVol, volThresh, volSize, &myVolOut, lessThan, &myRoi, -1, markVal, &markVal, volSizeRatio, volDistCutoff); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, volumeList[whichStruct], &myVolOut, true); } } if (endVal != NULL) *endVal = markVal; } float AlgorithmCiftiFindClusters::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiFindClusters::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiFindClusters.h000066400000000000000000000050311360521144700261360ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_FIND_CLUSTERS_H__ #define __ALGORITHM_CIFTI_FIND_CLUSTERS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmCiftiFindClusters : public AbstractAlgorithm { AlgorithmCiftiFindClusters(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiFindClusters(ProgressObject* myProgObj, const CiftiFile* myCifti, const float& surfThresh, const float& surfSize, const float& volThresh, const float& volSize, const int& myDir, CiftiFile* myCiftiOut, const bool& lessThan = false, const SurfaceFile* myLeftSurf = NULL, const MetricFile* myLeftAreas = NULL, const SurfaceFile* myRightSurf = NULL, const MetricFile* myRightAreas = NULL, const SurfaceFile* myCerebSurf = NULL, const MetricFile* myCerebAreas = NULL, const CiftiFile* roiCifti = NULL, const bool& mergedVol = false, const int& startVal = 1, int* endVal = NULL, const float& surfSizeRatio = -1.0f, const float& volSizeRatio = -1.0f, const float& surfDistCutoff = -1.0f, const float& volDistCutoff = -1.0f); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiFindClusters; } #endif //__ALGORITHM_CIFTI_FIND_CLUSTERS_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiGradient.cxx000066400000000000000000000401541360521144700256460ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiGradient.h" #include "AlgorithmException.h" #include "AlgorithmMetricGradient.h" #include "AlgorithmVolumeGradient.h" #include "CiftiFile.h" #include "MetricFile.h" #include "VolumeFile.h" #include "SurfaceFile.h" #include "AlgorithmCiftiSeparate.h" #include "AlgorithmCiftiReplaceStructure.h" #include using namespace caret; using namespace std; AString AlgorithmCiftiGradient::getCommandSwitch() { return "-cifti-gradient"; } AString AlgorithmCiftiGradient::getShortDescription() { return "TAKE GRADIENT OF A CIFTI FILE"; } OperationParameters* AlgorithmCiftiGradient::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti", "the input cifti"); ret->addStringParameter(2, "direction", "which dimension to take the gradient along, ROW or COLUMN"); ret->addCiftiOutputParameter(3, "cifti-out", "the output cifti"); OptionalParameter* leftSurfOpt = ret->createOptionalParameter(4, "-left-surface", "specify the left surface to use"); leftSurfOpt->addSurfaceParameter(1, "surface", "the left surface file"); OptionalParameter* leftCorrAreasOpt = leftSurfOpt->createOptionalParameter(2, "-left-corrected-areas", "vertex areas to use instead of computing them from the left surface"); leftCorrAreasOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); OptionalParameter* rightSurfOpt = ret->createOptionalParameter(5, "-right-surface", "specify the right surface to use"); rightSurfOpt->addSurfaceParameter(1, "surface", "the right surface file"); OptionalParameter* rightCorrAreasOpt = rightSurfOpt->createOptionalParameter(2, "-right-corrected-areas", "vertex areas to use instead of computing them from the right surface"); rightCorrAreasOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); OptionalParameter* cerebSurfOpt = ret->createOptionalParameter(6, "-cerebellum-surface", "specify the cerebellum surface to use"); cerebSurfOpt->addSurfaceParameter(1, "surface", "the cerebellum surface file"); OptionalParameter* cerebCorrAreasOpt = cerebSurfOpt->createOptionalParameter(2, "-cerebellum-corrected-areas", "vertex areas to use instead of computing them from the cerebellum surface"); cerebCorrAreasOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); OptionalParameter* presmoothSurfOpt = ret->createOptionalParameter(7, "-surface-presmooth", "smooth on the surface before computing the gradient"); presmoothSurfOpt->addDoubleParameter(1, "surface-kernel", "the sigma for the gaussian surface smoothing kernel, in mm"); OptionalParameter* presmoothVolOpt = ret->createOptionalParameter(8, "-volume-presmooth", "smooth on the surface before computing the gradient"); presmoothVolOpt->addDoubleParameter(1, "volume-kernel", "the sigma for the gaussian volume smoothing kernel, in mm"); ret->createOptionalParameter(9, "-average-output", "output the average of the gradient magnitude maps instead of each gradient map separately"); OptionalParameter* vectorOpt = ret->createOptionalParameter(10, "-vectors", "output gradient vectors"); vectorOpt->addCiftiOutputParameter(1, "vectors-out", "the vectors, as a dscalar file"); ret->setHelpText( AString("Performs gradient calculation on each component of the cifti file, and optionally averages the resulting gradients. ") + "The -vectors and -average-output options may not be used together. " + "You must specify a surface for each surface structure in the cifti file. The COLUMN direction should be faster, and is the " + "direction that works on dtseries. For dconn, you probably want ROW, unless you are using -average-output." ); return ret; } void AlgorithmCiftiGradient::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* myCifti = myParams->getCifti(1); AString directionName = myParams->getString(2); int myDir; if (directionName == "ROW") { myDir = CiftiXMLOld::ALONG_ROW; } else if (directionName == "COLUMN") { myDir = CiftiXMLOld::ALONG_COLUMN; } else { throw AlgorithmException("incorrect string for direction, use ROW or COLUMN"); } CiftiFile* myCiftiOut = myParams->getOutputCifti(3); SurfaceFile* myLeftSurf = NULL, *myRightSurf = NULL, *myCerebSurf = NULL; MetricFile* myLeftAreas = NULL, *myRightAreas = NULL, *myCerebAreas = NULL; OptionalParameter* leftSurfOpt = myParams->getOptionalParameter(4); if (leftSurfOpt->m_present) { myLeftSurf = leftSurfOpt->getSurface(1); OptionalParameter* leftCorrAreasOpt = leftSurfOpt->getOptionalParameter(2); if (leftCorrAreasOpt->m_present) { myLeftAreas = leftCorrAreasOpt->getMetric(1); } } OptionalParameter* rightSurfOpt = myParams->getOptionalParameter(5); if (rightSurfOpt->m_present) { myRightSurf = rightSurfOpt->getSurface(1); OptionalParameter* rightCorrAreasOpt = rightSurfOpt->getOptionalParameter(2); if (rightCorrAreasOpt->m_present) { myRightAreas = rightCorrAreasOpt->getMetric(1); } } OptionalParameter* cerebSurfOpt = myParams->getOptionalParameter(6); if (cerebSurfOpt->m_present) { myCerebSurf = cerebSurfOpt->getSurface(1); OptionalParameter* cerebCorrAreasOpt = cerebSurfOpt->getOptionalParameter(2); if (cerebCorrAreasOpt->m_present) { myCerebAreas = cerebCorrAreasOpt->getMetric(1); } } float surfKern = -1.0f; OptionalParameter* presmoothSurfOpt = myParams->getOptionalParameter(7); if (presmoothSurfOpt->m_present) { surfKern = (float)presmoothSurfOpt->getDouble(1); } float volKern = -1.0f; OptionalParameter* presmoothVolOpt = myParams->getOptionalParameter(8); if (presmoothVolOpt->m_present) { volKern = (float)presmoothVolOpt->getDouble(1); } bool outputAverage = myParams->getOptionalParameter(9)->m_present; CiftiFile* ciftiVectorsOut = NULL; OptionalParameter* vectorOpt = myParams->getOptionalParameter(10); if (vectorOpt->m_present) { ciftiVectorsOut = vectorOpt->getOutputCifti(1); } AlgorithmCiftiGradient(myProgObj, myCifti, myDir, myCiftiOut, surfKern, volKern, myLeftSurf, myRightSurf, myCerebSurf, outputAverage, myLeftAreas, myRightAreas, myCerebAreas, ciftiVectorsOut); } AlgorithmCiftiGradient::AlgorithmCiftiGradient(ProgressObject* myProgObj, const CiftiFile* myCifti, const int& myDir, CiftiFile* myCiftiOut, const float& surfKern, const float& volKern, SurfaceFile* myLeftSurf, SurfaceFile* myRightSurf, SurfaceFile* myCerebSurf, bool outputAverage, const MetricFile* myLeftAreas, const MetricFile* myRightAreas, const MetricFile* myCerebAreas, CiftiFile* ciftiVectorsOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const CiftiXML& myXML = myCifti->getCiftiXML(); CiftiXML myNewXML = myXML, myVecXML = myXML; if (myXML.getNumberOfDimensions() != 2) { throw AlgorithmException("cifti gradient only supports 2D cifti"); } if (myXML.getMappingType(myDir) != CiftiMappingType::BRAIN_MODELS) { throw AlgorithmException("specified direction does not contain brainordinates"); } if (outputAverage && ciftiVectorsOut != NULL) { throw AlgorithmException("outputting gradient vectors while averaging gradient magnitude is not supported"); } const CiftiBrainModelsMap& myDenseMap = myXML.getBrainModelsMap(myDir); vector surfaceList = myDenseMap.getSurfaceStructureList(), volumeList = myDenseMap.getVolumeStructureList(); if (outputAverage) { if (myDir == CiftiXML::ALONG_ROW) {//dscalar always has brainordinates on columns, so flip the mappings myNewXML.setMap(CiftiXML::ALONG_COLUMN, *(myNewXML.getMap(CiftiXML::ALONG_ROW))); } CiftiScalarsMap magMap; magMap.setLength(1); magMap.setMapName(0, "gradient average"); myNewXML.setMap(CiftiXML::ALONG_ROW, magMap); } else { if (myDir == CiftiXML::ALONG_ROW) {//dscalar always has brainordinates on columns, so flip the mappings myVecXML.setMap(CiftiXML::ALONG_COLUMN, *(myVecXML.getMap(CiftiXML::ALONG_ROW))); } CiftiScalarsMap vecMap; vecMap.setLength(3 * myXML.getDimensionLength(1 - myDir)); myVecXML.setMap(CiftiXML::ALONG_ROW, vecMap); } for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) {//sanity check surfaces SurfaceFile* mySurf = NULL; const MetricFile* myAreas = NULL; AString surfType; switch (surfaceList[whichStruct]) { case StructureEnum::CORTEX_LEFT: mySurf = myLeftSurf; myAreas = myLeftAreas; surfType = "left"; break; case StructureEnum::CORTEX_RIGHT: mySurf = myRightSurf; myAreas = myRightAreas; surfType = "right"; break; case StructureEnum::CEREBELLUM: mySurf = myCerebSurf; myAreas = myCerebAreas; surfType = "cerebellum"; break; default: throw AlgorithmException("found surface model with incorrect type: " + StructureEnum::toName(surfaceList[whichStruct])); break; } if (mySurf == NULL) { throw AlgorithmException(surfType + " surface required but not provided"); } if (mySurf->getNumberOfNodes() != myDenseMap.getSurfaceNumberOfNodes(surfaceList[whichStruct])) { throw AlgorithmException(surfType + " surface has the wrong number of vertices"); } checkStructureMatch(mySurf, surfaceList[whichStruct], "surface file", "the argument expects"); if (myAreas != NULL) { if (myAreas->getNumberOfNodes() != mySurf->getNumberOfNodes()) { throw AlgorithmException(surfType + " surface and vertex area metric have different number of vertices"); } checkStructureMatch(myAreas, surfaceList[whichStruct], "vertex area metric", "the argument expects"); } } myCiftiOut->setCiftiXML(myNewXML); if (ciftiVectorsOut != NULL) { ciftiVectorsOut->setCiftiXML(myVecXML); } for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) { SurfaceFile* mySurf = NULL; const MetricFile* myAreas = NULL; switch (surfaceList[whichStruct]) { case StructureEnum::CORTEX_LEFT: mySurf = myLeftSurf; myAreas = myLeftAreas; break; case StructureEnum::CORTEX_RIGHT: mySurf = myRightSurf; myAreas = myRightAreas; break; case StructureEnum::CEREBELLUM: mySurf = myCerebSurf; myAreas = myCerebAreas; break; default: break; } MetricFile myMetric, myRoi, myMetricOut, vectorsOut, *vectorPtr = NULL; if (ciftiVectorsOut != NULL) vectorPtr = &vectorsOut; AlgorithmCiftiSeparate(NULL, myCifti, myDir, surfaceList[whichStruct], &myMetric, &myRoi); AlgorithmMetricGradient(NULL, mySurf, &myMetric, &myMetricOut, vectorPtr, surfKern, &myRoi, false, -1, myAreas); if (outputAverage) { int numNodes = myMetricOut.getNumberOfNodes(), numCols = myMetricOut.getNumberOfColumns(); vector accum(numNodes, 0.0);//use double for numerical stability for (int i = 0; i < numCols; ++i) { const float* column = myMetricOut.getValuePointerForColumn(i); for (int j = 0; j < numNodes; ++j) { accum[j] += column[j]; } } vector temparray(numNodes);//copy result into float array so it can be put into a metric, and then into cifti (yes, really) for (int i = 0; i < numNodes; ++i) { temparray[i] = (float)(accum[i] / numCols); } myMetricOut.setNumberOfNodesAndColumns(numNodes, 1); myMetricOut.setValuesForColumn(0, temparray.data()); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, CiftiXML::ALONG_COLUMN, surfaceList[whichStruct], &myMetricOut);//average always outputs a dscalar, so always along column } else { AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, surfaceList[whichStruct], &myMetricOut); if (ciftiVectorsOut != NULL) {//is always a dscalar, so always use column AlgorithmCiftiReplaceStructure(NULL, ciftiVectorsOut, CiftiXML::ALONG_COLUMN, surfaceList[whichStruct], &vectorsOut); } } } for (int whichStruct = 0; whichStruct < (int)volumeList.size(); ++whichStruct) { VolumeFile myVol, myRoi, myVolOut, vecVolOut, *vecVolPtr = NULL; if (ciftiVectorsOut != NULL) vecVolPtr = &vecVolOut; int64_t offset[3]; AlgorithmCiftiSeparate(NULL, myCifti, myDir, volumeList[whichStruct], &myVol, offset, &myRoi, true); AlgorithmVolumeGradient(NULL, &myVol, &myVolOut, volKern, &myRoi, vecVolPtr); if (outputAverage) { vector myDims; myVolOut.getDimensions(myDims); int64_t frameSize = myDims[0] * myDims[1] * myDims[2]; vector accum(frameSize, 0.0); for (int64_t i = 0; i < myDims[3]; ++i) { const float* myFrame = myVolOut.getFrame(i); for (int64_t j = 0; j < frameSize; ++j) { accum[j] += myFrame[j]; } } vector temparray(frameSize); for (int64_t i = 0; i < frameSize; ++i) { temparray[i] = (float)(accum[i] / myDims[3]); } vector newDims = myDims; newDims.resize(3); myVolOut.reinitialize(newDims, myVol.getSform()); myVolOut.setFrame(temparray.data()); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, CiftiXML::ALONG_COLUMN, volumeList[whichStruct], &myVolOut, true); } else { AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, volumeList[whichStruct], &myVolOut, true); if (ciftiVectorsOut != NULL) { AlgorithmCiftiReplaceStructure(NULL, ciftiVectorsOut, CiftiXML::ALONG_COLUMN, volumeList[whichStruct], &vecVolOut, true); } } } } float AlgorithmCiftiGradient::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiGradient::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiGradient.h000066400000000000000000000042141360521144700252700ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_GRADIENT_H__ #define __ALGORITHM_CIFTI_GRADIENT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmCiftiGradient : public AbstractAlgorithm { AlgorithmCiftiGradient(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiGradient(ProgressObject* myProgObj, const CiftiFile* myCifti, const int& myDir, CiftiFile* myCiftiOut, const float& surfKern = -1.0f, const float& volKern = -1.0f, SurfaceFile* myLeftSurf = NULL, SurfaceFile* myRightSurf = NULL, SurfaceFile* myCerebSurf = NULL, bool outputAverage = false, const MetricFile* myLeftAreas = NULL, const MetricFile* myRightAreas = NULL, const MetricFile* myCerebAreas = NULL, CiftiFile* ciftiVectorsOut = NULL); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiGradient; } #endif //__ALGORITHM_CIFTI_GRADIENT_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiLabelAdjacency.cxx000066400000000000000000000251041360521144700267300ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiLabelAdjacency.h" #include "AlgorithmException.h" #include "AlgorithmCiftiParcellate.h" #include "AlgorithmCiftiSeparate.h" //for cropped volume space #include "CiftiFile.h" #include "SurfaceFile.h" #include "TopologyHelper.h" using namespace caret; using namespace std; AString AlgorithmCiftiLabelAdjacency::getCommandSwitch() { return "-cifti-label-adjacency"; } AString AlgorithmCiftiLabelAdjacency::getShortDescription() { return "MAKE ADJACENCY MATRIX OF A CIFTI LABEL FILE"; } OperationParameters* AlgorithmCiftiLabelAdjacency::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "label-in", "the input cifti label file"); ret->addCiftiOutputParameter(2, "adjacency-out", "the output cifti pconn adjacency matrix"); OptionalParameter* leftSurfOpt = ret->createOptionalParameter(3, "-left-surface", "specify the left surface to use"); leftSurfOpt->addSurfaceParameter(1, "surface", "the left surface file"); OptionalParameter* rightSurfOpt = ret->createOptionalParameter(4, "-right-surface", "specify the right surface to use"); rightSurfOpt->addSurfaceParameter(1, "surface", "the right surface file"); OptionalParameter* cerebSurfaceOpt = ret->createOptionalParameter(5, "-cerebellum-surface", "specify the cerebellum surface to use"); cerebSurfaceOpt->addSurfaceParameter(1, "surface", "the cerebellum surface file"); ret->setHelpText( AString("Find face-adjacent voxels and connected vertices that have different label values, and count them for each pair. ") + "Put the resulting counts into a parcellated connectivity file, with the diagonal being zero. " + "This gives a rough estimate of how long or expansive the border between two labels is." ); return ret; } void AlgorithmCiftiLabelAdjacency::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* myLabelIn = myParams->getCifti(1); CiftiFile* myAdjOut = myParams->getOutputCifti(2); SurfaceFile* myLeftSurf = NULL; OptionalParameter* leftSurfOpt = myParams->getOptionalParameter(3); if (leftSurfOpt->m_present) { myLeftSurf = leftSurfOpt->getSurface(1); } SurfaceFile* myRightSurf = NULL; OptionalParameter* rightSurfOpt = myParams->getOptionalParameter(4); if (rightSurfOpt->m_present) { myRightSurf = rightSurfOpt->getSurface(1); } SurfaceFile* myCerebSurf = NULL; OptionalParameter* cerebSurfOpt = myParams->getOptionalParameter(5); if (cerebSurfOpt->m_present) { myCerebSurf = cerebSurfOpt->getSurface(1); } AlgorithmCiftiLabelAdjacency(myProgObj, myLabelIn, myAdjOut, myLeftSurf, myRightSurf, myCerebSurf); } AlgorithmCiftiLabelAdjacency::AlgorithmCiftiLabelAdjacency(ProgressObject* myProgObj, const CiftiFile* myLabelIn, CiftiFile* myAdjOut, const SurfaceFile* myLeftSurf, const SurfaceFile* myRightSurf, const SurfaceFile* myCerebSurf) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const CiftiXML& myLabelXML = myLabelIn->getCiftiXML(); if (myLabelXML.getNumberOfDimensions() != 2 || myLabelXML.getMappingType(CiftiXML::ALONG_ROW) != CiftiMappingType::LABELS || myLabelXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) { throw AlgorithmException("input cifti label file has the wrong mapping types"); } const CiftiBrainModelsMap& myDenseMap = myLabelXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); vector surfaceList = myDenseMap.getSurfaceStructureList(); for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) {//sanity check surfaces const SurfaceFile* mySurf = NULL; AString surfType; switch (surfaceList[whichStruct]) { case StructureEnum::CORTEX_LEFT: mySurf = myLeftSurf; surfType = "left"; break; case StructureEnum::CORTEX_RIGHT: mySurf = myRightSurf; surfType = "right"; break; case StructureEnum::CEREBELLUM: mySurf = myCerebSurf; surfType = "cerebellum"; break; default: throw AlgorithmException("found surface model with unexpected type: " + StructureEnum::toName(surfaceList[whichStruct])); break; } if (mySurf == NULL) { throw AlgorithmException(surfType + " surface required but not provided"); } if (mySurf->getNumberOfNodes() != myDenseMap.getSurfaceNumberOfNodes(surfaceList[whichStruct])) { throw AlgorithmException(surfType + " surface has the wrong number of vertices"); } } vector indexToParcel; CiftiParcelsMap myParcelMap = AlgorithmCiftiParcellate::parcellateMapping(myLabelIn, myDenseMap, indexToParcel); int numParcels = myParcelMap.getLength(); if (numParcels == 0) throw AlgorithmException("no labels found, output would be empty"); CiftiXML outXML; outXML.setNumberOfDimensions(2); outXML.setMap(CiftiXML::ALONG_ROW, myParcelMap); outXML.setMap(CiftiXML::ALONG_COLUMN, myParcelMap); myAdjOut->setCiftiXML(outXML); vector > adjCount(numParcels, vector(numParcels, 0));//count as int, translate back to float when writing for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) { const SurfaceFile* mySurf = NULL; switch (surfaceList[whichStruct]) { case StructureEnum::CORTEX_LEFT: mySurf = myLeftSurf; break; case StructureEnum::CORTEX_RIGHT: mySurf = myRightSurf; break; case StructureEnum::CEREBELLUM: mySurf = myCerebSurf; break; default: throw AlgorithmException("found surface model with unexpected type: " + StructureEnum::toName(surfaceList[whichStruct])); break; } CaretPointer myHelp = mySurf->getTopologyHelper(); int numNodes = mySurf->getNumberOfNodes(); for (int i = 0; i < numNodes - 1; ++i)//to avoid double counting, only count pairs that are in ascending order - this means the last node won't have any valid edges { int64_t baseIndex = myDenseMap.getIndexForNode(i, surfaceList[whichStruct]); if (baseIndex < 0) continue; int baseLabel = indexToParcel[baseIndex];//translate on the fly, to do separate we would need to put indexToParcel into a temporary CiftiFile if (baseLabel < 0) continue; const vector& neighbors = myHelp->getNodeNeighbors(i); int numNeighbors = (int)neighbors.size(); for (int j = 0; j < numNeighbors; ++j) { if (neighbors[j] > i) { int64_t neighIndex = myDenseMap.getIndexForNode(neighbors[j], surfaceList[whichStruct]); if (neighIndex < 0) continue; int neighLabel = indexToParcel[neighIndex]; if (neighLabel < 0) continue; if (baseLabel != neighLabel) { ++adjCount[baseLabel][neighLabel]; ++adjCount[neighLabel][baseLabel]; } } } } } if (myDenseMap.hasVolumeData()) { int64_t dims[3], offset[3];//all we really want is offset and dims, to avoid scanning the original FOV vector > sform; AlgorithmCiftiSeparate::getCroppedVolSpaceAll(myLabelIn, CiftiXML::ALONG_COLUMN, dims, sform, offset); int64_t stencil[9] = {1, 0, 0, 0, 1, 0, 0, 0, 1};//only forward differences, to avoid double counting int64_t ijk[3]; for (ijk[2] = offset[2]; ijk[2] < offset[2] + dims[2]; ++ijk[2]) { for (ijk[1] = offset[1]; ijk[1] < offset[1] + dims[1]; ++ijk[1]) { for (ijk[0] = offset[0]; ijk[0] < offset[0] + dims[0]; ++ijk[0]) { int64_t baseIndex = myDenseMap.getIndexForVoxel(ijk); if (baseIndex < 0) continue; int baseLabel = indexToParcel[baseIndex]; if (baseLabel < 0) continue; for (int neighbor = 0; neighbor < 9; neighbor += 3) { int64_t neighIndex = myDenseMap.getIndexForVoxel(ijk[0] + stencil[neighbor], ijk[1] + stencil[neighbor + 1], ijk[2] + stencil[neighbor + 2]); if (neighIndex < 0) continue; int neighLabel = indexToParcel[neighIndex]; if (neighLabel < 0) continue; if (baseLabel != neighLabel) { ++adjCount[baseLabel][neighLabel]; ++adjCount[neighLabel][baseLabel]; } } } } } } vector tempRow(numParcels); for (int i = 0; i < numParcels; ++i) { for (int j = 0; j < numParcels; ++j) { tempRow[j] = adjCount[i][j]; } myAdjOut->setRow(tempRow.data(), i); } } float AlgorithmCiftiLabelAdjacency::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiLabelAdjacency::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiLabelAdjacency.h000066400000000000000000000035311360521144700263550ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_LABEL_ADJACENCY_H__ #define __ALGORITHM_CIFTI_LABEL_ADJACENCY_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmCiftiLabelAdjacency : public AbstractAlgorithm { AlgorithmCiftiLabelAdjacency(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiLabelAdjacency(ProgressObject* myProgObj, const CiftiFile* myLabelIn, CiftiFile* myAdjOut, const SurfaceFile* myLeftSurf = NULL, const SurfaceFile* myRightSurf = NULL, const SurfaceFile* myCerebSurf = NULL); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiLabelAdjacency; } #endif //__ALGORITHM_CIFTI_LABEL_ADJACENCY_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiLabelModifyKeys.cxx000066400000000000000000000250061360521144700271330ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiLabelModifyKeys.h" #include "AlgorithmException.h" #include "CiftiFile.h" #include "FileInformation.h" #include "GiftiLabel.h" #include #include #include using namespace caret; using namespace std; AString AlgorithmCiftiLabelModifyKeys::getCommandSwitch() { return "-cifti-label-modify-keys"; } AString AlgorithmCiftiLabelModifyKeys::getShortDescription() { return "CHANGE KEY VALUES IN A DLABEL FILE"; } OperationParameters* AlgorithmCiftiLabelModifyKeys::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-in", "the input dlabel file"); ret->addStringParameter(2, "remap-file", "text file with old and new key values"); ret->addCiftiOutputParameter(3, "cifti-out", "the output dlabel file"); OptionalParameter* columnOpt = ret->createOptionalParameter(4, "-column", "select a single column to use"); columnOpt->addStringParameter(1, "column", "the column number or name"); ret->setHelpText( AString(" should have lines of the form 'oldkey newkey', like so:\n\n") + "3 5\n5 8\n8 2\n\n" + "This would change the current label with key '3' to use the key '5' instead, 5 would use 8, and 8 would use 2. " + "Any collision in key values results in the label that was not specified in the remap file getting remapped to an otherwise unused key. " + "Remapping more than one key to the same new key, or the same key to more than one new key, results in an error. " + "This will not change the appearance of the file when displayed, as it will change the key values in the data at the same time." ); return ret; } void AlgorithmCiftiLabelModifyKeys::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* ciftiIn = myParams->getCifti(1); AString remapName = myParams->getString(2); CiftiFile* ciftiOut = myParams->getOutputCifti(3); int column = -1; OptionalParameter* columnOpt = myParams->getOptionalParameter(4); if (columnOpt->m_present) { column = ciftiIn->getCiftiXML().getMap(CiftiXML::ALONG_ROW)->getIndexFromNumberOrName(columnOpt->getString(1)); if (column < 0) throw AlgorithmException("invalid column specified"); } FileInformation textFileInfo(remapName); if (!textFileInfo.exists()) { throw AlgorithmException("label list file doesn't exist"); } fstream remapFile(remapName.toLocal8Bit().constData(), fstream::in); if (!remapFile.good()) { throw AlgorithmException("error reading label list file"); } map remap; int32_t oldkey, newkey; while (remapFile >> oldkey >> newkey) { if (remap.find(oldkey) != remap.end()) throw AlgorithmException("remapping tried to duplicate label " + AString::number(oldkey)); remap[oldkey] = newkey; } AlgorithmCiftiLabelModifyKeys(myProgObj, ciftiIn, remap, ciftiOut, column); } AlgorithmCiftiLabelModifyKeys::AlgorithmCiftiLabelModifyKeys(ProgressObject* myProgObj, const CiftiFile* ciftiIn, const map remap, CiftiFile* ciftiOut, const int column) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const CiftiXML& xmlIn = ciftiIn->getCiftiXML(); if (xmlIn.getNumberOfDimensions() != 2) throw AlgorithmException("cifti label modify keys only supports 2D cifti"); if (xmlIn.getMappingType(CiftiXML::ALONG_ROW) != CiftiMappingType::LABELS) throw AlgorithmException("input cifti file does not have labels mapping along row"); const CiftiLabelsMap& oldmap = xmlIn.getLabelsMap(CiftiXML::ALONG_ROW); int64_t numRows = ciftiIn->getNumberOfRows(); int64_t startCol = 0, endCol = ciftiIn->getNumberOfColumns(); if (column > -1) { startCol = column; endCol = column + 1; } CiftiLabelsMap newmap; newmap.setLength(endCol - startCol); vector> valChanges(endCol - startCol); for (int64_t i = startCol; i < endCol; ++i) { newmap.setMapName(i - startCol, oldmap.getMapName(i)); const GiftiLabelTable* oldTable = oldmap.getMapLabelTable(i); int32_t oldUnlabeled = oldTable->getUnassignedLabelKey();//because GiftiLabelTable is quirky, we need to check if the unlabeled value ends up as something other than 0 GiftiLabelTable newTable;//careful, label 0 is created by the constructor bool setZero = false;//because of this, we need to track if we overwrote it, so that we can pretend it isn't there for (map::const_iterator iter = remap.begin(); iter != remap.end(); ++iter) { const GiftiLabel* oldLabel = oldTable->getLabel(iter->first); if (oldLabel == NULL) throw AlgorithmException("label key " + AString::number(iter->first) + " does not exist in the input file"); GiftiLabel newLabel(*oldLabel); newLabel.setKey(iter->second); if (iter->first == oldUnlabeled) { if (iter->second != 0)//if it isn't the default unlabeled value, then we have to do something { if (newTable.getLabel(iter->second) != NULL) throw AlgorithmException("remapping tried to set label " + AString::number(iter->second) + " more than once"); newTable.deleteLabel(0);//delete the default, since we don't know what overwrites it, if anything newTable.insertLabel(&newLabel);//insert forces it to use the key in the label, even if it causes a duplicate name (which the original might theoretically have) } else {//otherwise, just error checking if (setZero) throw AlgorithmException("remapping tried to set label " + AString::number(iter->second) + " more than once"); setZero = true;//we do have to track that zero now contains something that can't be overwritten } } else { if (iter->second == 0)//if it remaps to the default unlabeled key, we have to check it differently { if (setZero) throw AlgorithmException("remapping tried to set label " + AString::number(iter->second) + " more than once"); setZero = true; newTable.insertLabel(&newLabel);//insert forces it to use the key in the label, so it will overwrite the existing default 0 key } else {//finally, the simple case if (newTable.getLabel(iter->second) != NULL) throw AlgorithmException("remapping tried to set label " + AString::number(iter->second) + " more than once"); newTable.insertLabel(&newLabel);//insert forces it to use the key in the label, even if it causes a duplicate name (which the original might theoretically have) } } } set keys = oldTable->getKeys(), collisions; for (set::const_iterator iter = keys.begin(); iter != keys.end(); ++iter) { if (remap.find(*iter) == remap.end())//skip if it was remapped { if (*iter == 0)//again with the special default 0 key { if (setZero)//check for collision { collisions.insert(*iter); } else { setZero = true; if (*iter != oldUnlabeled)//if its merely the unassigned label already, we can just keep the existing default { newTable.insertLabel(oldTable->getLabel(*iter)); } } } else { if (newTable.getLabel(*iter) == NULL) { newTable.insertLabel(oldTable->getLabel(*iter)); } else {//collision collisions.insert(*iter); } } } } map& valueChanges = valChanges[i - startCol]; valueChanges = remap;//start with the specified changes, then add the collision changes for (set::const_iterator iter = collisions.begin(); iter != collisions.end(); ++iter) {//now deal with collisions int32_t newKey = newTable.generateUnusedKey(); GiftiLabel newLabel(*(oldTable->getLabel(*iter))); newLabel.setKey(newKey); newTable.insertLabel(&newLabel);//insert forces it to use the key in the label, even if it causes a duplicate name (which the original might theoretically have) valueChanges[*iter] = newKey; } *(newmap.getMapLabelTable(i - startCol)) = newTable; } CiftiXML xmlOut = xmlIn; xmlOut.setMap(CiftiXML::ALONG_ROW, newmap); ciftiOut->setCiftiXML(xmlOut); vector scratchRow(ciftiIn->getNumberOfColumns()), outRow(endCol - startCol); for (int i = 0; i < numRows; ++i) { ciftiIn->getRow(scratchRow.data(), i); for (int j = startCol; j < endCol; ++j) { int32_t oldkey = floor(scratchRow[j] + 0.5f); auto iter = valChanges[j - startCol].find(oldkey); if (iter == valChanges[j - startCol].end()) { outRow[j - startCol] = oldkey; } else { outRow[j - startCol] = iter->second; } } ciftiOut->setRow(outRow.data(), i); } } float AlgorithmCiftiLabelModifyKeys::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiLabelModifyKeys::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiLabelModifyKeys.h000066400000000000000000000034301360521144700265550ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_LABEL_MODIFY_KEYS_H__ #define __ALGORITHM_CIFTI_LABEL_MODIFY_KEYS_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include namespace caret { class AlgorithmCiftiLabelModifyKeys : public AbstractAlgorithm { AlgorithmCiftiLabelModifyKeys(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiLabelModifyKeys(ProgressObject* myProgObj, const CiftiFile* ciftiIn, const std::map remap, CiftiFile* ciftiOut, const int column = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiLabelModifyKeys; } #endif //__ALGORITHM_CIFTI_LABEL_MODIFY_KEYS_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiLabelProbability.cxx000066400000000000000000000143771360521144700273410ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiLabelProbability.h" #include "AlgorithmException.h" #include "CiftiFile.h" #include #include #include using namespace caret; using namespace std; AString AlgorithmCiftiLabelProbability::getCommandSwitch() { return "-cifti-label-probability"; } AString AlgorithmCiftiLabelProbability::getShortDescription() { return "FIND FREQUENCY OF CIFTI LABELS"; } OperationParameters* AlgorithmCiftiLabelProbability::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "label-maps", "cifti dlabel file containing individual label maps from many subjects"); ret->addCiftiOutputParameter(2, "probability-dscalar-out", "the relative frequencies of each label at each vertex/voxel"); ret->createOptionalParameter(3, "-exclude-unlabeled", "don't make a probability map of the unlabeled key"); ret->setHelpText( AString("This command outputs a set of soft ROIs, one for each label in the input, ") + "where the value is how many of the input maps had that label at that vertex/voxel, divided by the number of input maps." ); return ret; } void AlgorithmCiftiLabelProbability::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { const CiftiFile* inputLabel = myParams->getCifti(1); CiftiFile* outputCifti = myParams->getOutputCifti(2); bool excludeUnlabeled = myParams->getOptionalParameter(3)->m_present; AlgorithmCiftiLabelProbability(myProgObj, inputLabel, outputCifti, excludeUnlabeled); } AlgorithmCiftiLabelProbability::AlgorithmCiftiLabelProbability(ProgressObject* myProgObj, const CiftiFile* inputLabel, CiftiFile* outputCifti, const bool& excludeUnlabeled) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const CiftiXML& inputXML = inputLabel->getCiftiXML(); if (inputXML.getNumberOfDimensions() != 2 || inputXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS || inputXML.getMappingType(CiftiXML::ALONG_ROW) != CiftiMappingType::LABELS) { throw AlgorithmException("input cifti file does not have the mapping types of a dlabel file"); } const CiftiLabelsMap& inputLabelMap = inputXML.getLabelsMap(CiftiXML::ALONG_ROW); int64_t numInMaps = inputLabelMap.getLength(); vector > keyToOutMapLookup(numInMaps);//we match labels by name, not by key - since cifti files are more memory efficient than volume files, do it the fast way map nameToOutMap; for (int64_t m = 0; m < numInMaps; ++m) { const GiftiLabelTable* mapTable = inputLabelMap.getMapLabelTable(m); set mapKeys = mapTable->getKeys(); int32_t unlabeledKey = -1;//don't request it from the table if we aren't going to skip it, because requesting it can add it to the table if (excludeUnlabeled) { unlabeledKey = mapTable->getUnassignedLabelKey(); } for (set::iterator iter = mapKeys.begin(); iter != mapKeys.end(); ++iter)//order by key value { if (excludeUnlabeled && *iter == unlabeledKey) continue;//skip to next key const AString thisName = mapTable->getLabelName(*iter); map::iterator search = nameToOutMap.find(thisName); int outMap = -1; if (search == nameToOutMap.end()) { outMap = nameToOutMap.size();//sequential integers starting from 0 nameToOutMap[thisName] = outMap; } else { outMap = search->second; } keyToOutMapLookup[m][*iter] = outMap; } }//for simplicity, do the actual processing in a second loop int64_t numOutMaps = nameToOutMap.size(), colSize = inputXML.getDimensionLength(CiftiXML::ALONG_COLUMN); vector > counts(numOutMaps, vector(colSize, 0)); for (int64_t row = 0; row < colSize; ++row) { vector scratchRow(numInMaps); inputLabel->getRow(scratchRow.data(), row); for (int64_t m = 0; m < numInMaps; ++m) { int thiskey = (int)floor(scratchRow[m] + 0.5f); map::iterator search = keyToOutMapLookup[m].find(thiskey); if (search != keyToOutMapLookup[m].end()) { ++counts[search->second][row]; } } } CiftiXML outXML; outXML.setNumberOfDimensions(2); outXML.setMap(CiftiXML::ALONG_COLUMN, inputXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN)); CiftiScalarsMap outRowMap; outRowMap.setLength(numOutMaps); for (map::iterator iter = nameToOutMap.begin(); iter != nameToOutMap.end(); ++iter) { outRowMap.setMapName(iter->second, iter->first); } outXML.setMap(CiftiXML::ALONG_ROW, outRowMap); outputCifti->setCiftiXML(outXML); for (int64_t row = 0; row < colSize; ++row) { vector scratchRow(numOutMaps); for (int64_t m = 0; m < numOutMaps; ++m) { scratchRow[m] = ((float)counts[m][row]) / numInMaps; } outputCifti->setRow(scratchRow.data(), row); } } float AlgorithmCiftiLabelProbability::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiLabelProbability::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiLabelProbability.h000066400000000000000000000033721360521144700267570ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_LABEL_PROBABILITY_H__ #define __ALGORITHM_CIFTI_LABEL_PROBABILITY_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmCiftiLabelProbability : public AbstractAlgorithm { AlgorithmCiftiLabelProbability(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiLabelProbability(ProgressObject* myProgObj, const CiftiFile* inputLabel, CiftiFile* outputCifti, const bool& excludeUnlabeled = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiLabelProbability; } #endif //__ALGORITHM_CIFTI_LABEL_PROBABILITY_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiLabelToBorder.cxx000066400000000000000000000123351360521144700265710ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiLabelToBorder.h" #include "AlgorithmException.h" #include "AlgorithmCiftiSeparate.h" #include "AlgorithmLabelToBorder.h" #include "CaretLogger.h" #include "BorderFile.h" #include "CiftiFile.h" #include "LabelFile.h" #include "SurfaceFile.h" using namespace caret; using namespace std; AString AlgorithmCiftiLabelToBorder::getCommandSwitch() { return "-cifti-label-to-border"; } AString AlgorithmCiftiLabelToBorder::getShortDescription() { return "DRAW BORDERS AROUND CIFTI LABELS"; } OperationParameters* AlgorithmCiftiLabelToBorder::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-in", "the input cifti dlabel file"); OptionalParameter* placeOpt = ret->createOptionalParameter(2, "-placement", "set how far along the edge border points are drawn"); placeOpt->addDoubleParameter(1, "fraction", "fraction along edge from inside vertex (default 0.33)"); OptionalParameter* columnOpt = ret->createOptionalParameter(3, "-column", "select a single column"); columnOpt->addStringParameter(1, "column", "the column number or name"); ParameterComponent* borderOpt = ret->createRepeatableParameter(4, "-border", "specify output file for a surface structure"); borderOpt->addSurfaceParameter(1, "surface", "the surface to use for neighbor and structure information"); borderOpt->addBorderOutputParameter(2, "border-out", "the output border file"); ret->setHelpText( AString("For each surface, takes the labels on the matching structure and draws borders around the labels. ") + "Use -column to only draw borders around one label map." ); return ret; } void AlgorithmCiftiLabelToBorder::useParameters(OperationParameters* myParams, ProgressObject* /*myProgObj*/) { CiftiFile* myCifti = myParams->getCifti(1); float placement = 0.33f; OptionalParameter* placeOpt = myParams->getOptionalParameter(2); if (placeOpt->m_present) { placement = (float)placeOpt->getDouble(1); } int64_t column = -1; OptionalParameter* columnOpt = myParams->getOptionalParameter(3); if (columnOpt->m_present) { //row is first dimension, 0D cifti won't load, so don't need a test column = myCifti->getCiftiXML().getMap(CiftiXML::ALONG_ROW)->getIndexFromNumberOrName(columnOpt->getString(2)); if (column < 0) { throw AlgorithmException("invalid column specified"); } } const vector& borderOpts = *(myParams->getRepeatableParameterInstances(4)); if (borderOpts.empty()) CaretLogWarning("no output requested from -cifti-label-to-border, command will do nothing"); for (int i = 0; i < (int)borderOpts.size(); ++i) { ParameterComponent& thisBorderOpt = *(borderOpts[i]); AlgorithmCiftiLabelToBorder(NULL, myCifti, thisBorderOpt.getSurface(1), thisBorderOpt.getOutputBorder(2), placement, column); } } AlgorithmCiftiLabelToBorder::AlgorithmCiftiLabelToBorder(ProgressObject* myProgObj, const CiftiFile* myCifti, const SurfaceFile* mySurf, BorderFile* borderOut, const float& placement, const int& column) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const CiftiXML& myXML = myCifti->getCiftiXML(); if (myXML.getNumberOfDimensions() != 2) throw AlgorithmException("input cifti file should have 2 dimensions, has " + AString::number(myXML.getNumberOfDimensions())); if (myXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) throw AlgorithmException("input cifti file does not have brain models mapping along column"); if (myXML.getMappingType(CiftiXML::ALONG_ROW) != CiftiMappingType::LABELS) throw AlgorithmException("input cifti file does not have labels mapping along row"); LabelFile tempLabel; AlgorithmCiftiSeparate(NULL, myCifti, CiftiXML::ALONG_COLUMN, mySurf->getStructure(), &tempLabel);//NOTE: bad surface structure errors are printed from this algorithm AlgorithmLabelToBorder(NULL, mySurf, &tempLabel, borderOut, placement, column); } float AlgorithmCiftiLabelToBorder::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiLabelToBorder::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiLabelToBorder.h000066400000000000000000000035071360521144700262170ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_LABEL_TO_BORDER_H__ #define __ALGORITHM_CIFTI_LABEL_TO_BORDER_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmCiftiLabelToBorder : public AbstractAlgorithm { AlgorithmCiftiLabelToBorder(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiLabelToBorder(ProgressObject* myProgObj, const CiftiFile* myCifti, const SurfaceFile* mySurf, BorderFile* borderOut, const float& placement = 0.33f, const int& column = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiLabelToBorder; } #endif //__ALGORITHM_CIFTI_LABEL_TO_BORDER_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiLabelToROI.cxx000066400000000000000000000265451360521144700260150ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiLabelToROI.h" #include "AlgorithmException.h" #include "CaretLogger.h" #include "CiftiFile.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include using namespace caret; using namespace std; AString AlgorithmCiftiLabelToROI::getCommandSwitch() { return "-cifti-label-to-roi"; } AString AlgorithmCiftiLabelToROI::getShortDescription() { return "MAKE A CIFTI LABEL INTO AN ROI"; } OperationParameters* AlgorithmCiftiLabelToROI::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "label-in", "the input cifti label file"); ret->addCiftiOutputParameter(2, "scalar-out", "the output cifti scalar file"); OptionalParameter* nameOpt = ret->createOptionalParameter(3, "-name", "select label by name"); nameOpt->addStringParameter(1, "label-name", "the label name that you want an roi of"); OptionalParameter* keyOpt = ret->createOptionalParameter(4, "-key", "select label by key"); keyOpt->addIntegerParameter(1, "label-key", "the label key that you want an roi of"); OptionalParameter* mapOpt = ret->createOptionalParameter(5, "-map", "select a single label map to use"); mapOpt->addStringParameter(1, "map", "the map number or name"); ret->setHelpText( AString("For each map in , a map is created in where all locations labeled with or with a key of are given a value of 1, and all other locations are given 0. ") + "Exactly one of -name and -key must be specified. " + "Specify -map to use only one map from ." ); return ret; } void AlgorithmCiftiLabelToROI::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* myCifti = myParams->getCifti(1); CiftiFile* myCiftiOut = myParams->getOutputCifti(2); bool nameMode = false; AString labelName; OptionalParameter* nameOpt = myParams->getOptionalParameter(3); if (nameOpt->m_present) { nameMode = true; labelName = nameOpt->getString(1); } int32_t labelKey; OptionalParameter* keyOpt = myParams->getOptionalParameter(4); if (keyOpt->m_present) { if (nameMode) throw AlgorithmException("-name and -key cannot be specified together"); labelKey = (int32_t)keyOpt->getInteger(1); } else { if (!nameMode) throw AlgorithmException("you must specify one of -name or -key"); } int64_t whichMap = -1; OptionalParameter* mapOpt = myParams->getOptionalParameter(5); if (mapOpt->m_present) { AString mapID = mapOpt->getString(1); whichMap = myCifti->getCiftiXMLOld().getMapIndexFromNameOrNumber(CiftiXMLOld::ALONG_ROW, mapID); if (whichMap == -1) { throw AlgorithmException("invalid map number or name specified"); } } if (nameMode) { AlgorithmCiftiLabelToROI(myProgObj, myCifti, labelName, myCiftiOut, whichMap); } else { AlgorithmCiftiLabelToROI(myProgObj, myCifti, labelKey, myCiftiOut, whichMap); } } AlgorithmCiftiLabelToROI::AlgorithmCiftiLabelToROI(ProgressObject* myProgObj, const CiftiFile* myCifti, const AString& labelName, CiftiFile* myCiftiOut, const int64_t& whichMap) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const CiftiXMLOld& myXml = myCifti->getCiftiXMLOld(); CiftiXMLOld outXml = myXml; int64_t numRows = myXml.getNumberOfRows(); int64_t numMaps = myXml.getDimensionLength(CiftiXMLOld::ALONG_ROW); if (whichMap < -1 || whichMap >= numMaps) { throw AlgorithmException("invalid map index specified"); } if (myXml.getMappingType(CiftiXMLOld::ALONG_ROW) != CIFTI_INDEX_TYPE_LABELS) { throw AlgorithmException("input cifti must have labels along rows"); } if (whichMap == -1) { outXml.resetDirectionToScalars(CiftiXMLOld::ALONG_ROW, numMaps); vector matchKey(numMaps, -1); vector haveKey(numMaps, false);//-1 is actually a valid key, track with a second variable bool shouldThrow = true; for (int64_t i = 0; i < numMaps; ++i) { outXml.setMapNameForIndex(CiftiXMLOld::ALONG_ROW, i, myXml.getMapName(CiftiXMLOld::ALONG_ROW, i)); const GiftiLabelTable* myTable = myXml.getLabelTableForRowIndex(i); int thisKey = myTable->getLabelKeyFromName(labelName); if (thisKey != GiftiLabel::getInvalidLabelKey()) { matchKey[i] = thisKey; haveKey[i] = true; shouldThrow = false; } else { CaretLogWarning("label name '" + labelName + "' not found in map #" + AString::number(i + 1)); } } if (shouldThrow) { throw AlgorithmException("label name was not found in any map"); } shouldThrow = true; myCiftiOut->setCiftiXML(outXml); vector rowScratch(numMaps); for (int64_t row = 0; row < numRows; ++row) { myCifti->getRow(rowScratch.data(), row); for (int64_t i = 0; i < numMaps; ++i) { if (haveKey[i]) { int input = (int)floor(rowScratch[i] + 0.5f); if (input == matchKey[i]) { rowScratch[i] = 1.0f; shouldThrow = false; } else { rowScratch[i] = 0.0f; } } else { rowScratch[i] = 0.0f; } } myCiftiOut->setRow(rowScratch.data(), row); } if (shouldThrow) { throw AlgorithmException("no data matched the specified label name"); } } else { float outScratch; outXml.resetDirectionToScalars(CiftiXMLOld::ALONG_ROW, 1); outXml.setMapNameForIndex(CiftiXMLOld::ALONG_ROW, 0, myXml.getMapName(CiftiXMLOld::ALONG_ROW, whichMap)); myCiftiOut->setCiftiXML(outXml); const GiftiLabelTable* myTable = myXml.getLabelTableForRowIndex(whichMap); int matchKey = myTable->getLabelKeyFromName(labelName); if (matchKey == GiftiLabel::getInvalidLabelKey()) { throw AlgorithmException("label name '" + labelName + "' not found in specified map"); } bool shouldThrow = true; vector rowScratch(numMaps); for (int64_t row = 0; row < numRows; ++row) { myCifti->getRow(rowScratch.data(), row); int input = (int)floor(rowScratch[whichMap] + 0.5f); if (input == matchKey) { outScratch = 1.0f; shouldThrow = false; } else { outScratch = 0.0f; } myCiftiOut->setRow(&outScratch, row); } if (shouldThrow) { throw AlgorithmException("no data matched the specified label name in the specified map"); } } } AlgorithmCiftiLabelToROI::AlgorithmCiftiLabelToROI(ProgressObject* myProgObj, const CiftiFile* myCifti, const int32_t& labelKey, CiftiFile* myCiftiOut, const int64_t& whichMap) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const CiftiXMLOld& myXml = myCifti->getCiftiXMLOld(); CiftiXMLOld outXml = myXml; int64_t numRows = myXml.getNumberOfRows(); int64_t numMaps = myXml.getDimensionLength(CiftiXMLOld::ALONG_ROW); if (whichMap < -1 || whichMap >= numMaps) { throw AlgorithmException("invalid map index specified"); } if (myXml.getMappingType(CiftiXMLOld::ALONG_ROW) != CIFTI_INDEX_TYPE_LABELS) { throw AlgorithmException("input cifti must have labels along rows"); } if (whichMap == -1) { outXml.resetDirectionToScalars(CiftiXMLOld::ALONG_ROW, numMaps); for (int64_t i = 0; i < numMaps; ++i) { outXml.setMapNameForIndex(CiftiXMLOld::ALONG_ROW, i, myXml.getMapName(CiftiXMLOld::ALONG_ROW, i)); const GiftiLabelTable* myTable = myXml.getLabelTableForRowIndex(i); if (myTable->getLabel(labelKey) == NULL) { CaretLogWarning("label key " + AString::number(labelKey) + " not found in map #" + AString::number(i + 1)); } } bool shouldThrow = true; myCiftiOut->setCiftiXML(outXml); vector rowScratch(numMaps); for (int64_t row = 0; row < numRows; ++row) { myCifti->getRow(rowScratch.data(), row); for (int64_t i = 0; i < numMaps; ++i) { int input = (int)floor(rowScratch[i] + 0.5f); if (input == labelKey) { rowScratch[i] = 1.0f; shouldThrow = false; } else { rowScratch[i] = 0.0f; } } myCiftiOut->setRow(rowScratch.data(), row); } if (shouldThrow) { throw AlgorithmException("no data matched the specified label key"); } } else { float outScratch; outXml.resetDirectionToScalars(CiftiXMLOld::ALONG_ROW, 1); outXml.setMapNameForIndex(CiftiXMLOld::ALONG_ROW, 0, myXml.getMapName(CiftiXMLOld::ALONG_ROW, whichMap)); myCiftiOut->setCiftiXML(outXml); const GiftiLabelTable* myTable = myXml.getLabelTableForRowIndex(whichMap); if (myTable->getLabel(labelKey) == NULL) { CaretLogWarning("label key " + AString::number(labelKey) + " not found in specified map"); } bool shouldThrow = true; vector rowScratch(numMaps); for (int64_t row = 0; row < numRows; ++row)//try anyway, in case label table is incomplete { myCifti->getRow(rowScratch.data(), row); int input = (int)floor(rowScratch[whichMap] + 0.5f); if (input == labelKey) { outScratch = 1.0f; shouldThrow = false; } else { outScratch = 0.0f; } myCiftiOut->setRow(&outScratch, row); } if (shouldThrow) { throw AlgorithmException("no data matched the specified label key in the specified map"); } } } float AlgorithmCiftiLabelToROI::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiLabelToROI::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiLabelToROI.h000066400000000000000000000036001360521144700254250ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_LABEL_TO_ROI_H__ #define __ALGORITHM_CIFTI_LABEL_TO_ROI_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmCiftiLabelToROI : public AbstractAlgorithm { AlgorithmCiftiLabelToROI(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiLabelToROI(ProgressObject* myProgObj, const CiftiFile* myCifti, const AString& labelName, CiftiFile* myCiftiOut, const int64_t& whichMap = -1); AlgorithmCiftiLabelToROI(ProgressObject* myProgObj, const CiftiFile* myCifti, const int32_t& labelKey, CiftiFile* myCiftiOut, const int64_t& whichMap = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiLabelToROI; } #endif //__ALGORITHM_CIFTI_LABEL_TO_ROI_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiMergeDense.cxx000066400000000000000000000322161360521144700261270ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiMergeDense.h" #include "AlgorithmException.h" #include "AlgorithmCiftiReplaceStructure.h" #include "AlgorithmCiftiSeparate.h" #include "CiftiFile.h" #include "LabelFile.h" #include "MetricFile.h" #include "VolumeFile.h" using namespace caret; using namespace std; AString AlgorithmCiftiMergeDense::getCommandSwitch() { return "-cifti-merge-dense"; } AString AlgorithmCiftiMergeDense::getShortDescription() { return "MERGE CIFTI FILES ALONG DENSE DIMENSION"; } OperationParameters* AlgorithmCiftiMergeDense::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "direction", "which dimension to merge along, ROW or COLUMN"); ret->addCiftiOutputParameter(2, "cifti-out", "the output cifti file"); ParameterComponent* ciftiOpt = ret->createRepeatableParameter(3, "-cifti", "specify an input cifti file"); ciftiOpt->addCiftiParameter(1, "cifti-in", "a cifti file to merge"); ret->setHelpText( AString("The input cifti files must have matching mappings along the direction not specified, and the mapping along the specified direction must be brain models.") ); return ret; } void AlgorithmCiftiMergeDense::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { AString directionName = myParams->getString(1); int myDir; if (directionName == "ROW") { myDir = CiftiXMLOld::ALONG_ROW; } else if (directionName == "COLUMN") { myDir = CiftiXMLOld::ALONG_COLUMN; } else { throw AlgorithmException("incorrect string for direction, use ROW or COLUMN"); } CiftiFile* myCiftiOut = myParams->getOutputCifti(2); const vector& myInstances = *(myParams->getRepeatableParameterInstances(3)); vector ciftiList; int numCifti = (int)myInstances.size(); for (int i = 0; i < numCifti; ++i) { ciftiList.push_back(myInstances[i]->getCifti(1)); } AlgorithmCiftiMergeDense(myProgObj, myDir, ciftiList, myCiftiOut); } AlgorithmCiftiMergeDense::AlgorithmCiftiMergeDense(ProgressObject* myProgObj, const int& myDir, const vector& ciftiList, CiftiFile* myCiftiOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (ciftiList.size() == 0) throw AlgorithmException("no input files specified"); CaretAssert(ciftiList[0] != NULL); if (myDir != CiftiXMLOld::ALONG_ROW && myDir != CiftiXMLOld::ALONG_COLUMN) throw AlgorithmException("direction not supported by cifti merge dense"); int otherDir = 1 - myDir;//find the other direction const CiftiXMLOld& baseXML = ciftiList[0]->getCiftiXMLOld(); if (baseXML.getMappingType(myDir) != CIFTI_INDEX_TYPE_BRAIN_MODELS) throw AlgorithmException("mapping type along specified dimension is not brain models"); bool isLabel = (baseXML.getMappingType(otherDir) == CIFTI_INDEX_TYPE_LABELS); CiftiXMLOld outXML = baseXML; VolumeSpace baseSpace; bool haveVolSpace = false; if (baseXML.hasVolumeData(myDir)) { haveVolSpace = true; baseXML.getVolumeSpace(baseSpace); } vector sourceCifti(baseXML.getNumberOfBrainModels(myDir), 0); for (int i = 1; i < (int)ciftiList.size(); ++i) { CaretAssert(ciftiList[i] != NULL); const CiftiXMLOld& otherXML = ciftiList[i]->getCiftiXMLOld(); if (!ciftiList[0]->getCiftiXML().getMap(otherDir)->approximateMatch(*(ciftiList[i]->getCiftiXML().getMap(otherDir)))) { throw AlgorithmException("mappings along other dimension do not match"); } if (otherXML.hasVolumeData(myDir)) { if (haveVolSpace) { VolumeSpace otherSpace; otherXML.getVolumeSpace(otherSpace); if (!baseSpace.matches(otherSpace)) throw AlgorithmException("input cifti files have non-matching volume spaces"); } else { haveVolSpace = true; otherXML.getVolumeSpace(baseSpace); outXML.setVolumeDimsAndSForm(baseSpace.getDims(), baseSpace.getSform());//need to set the output vol space if the first input didn't have volume data } } if (otherXML.getMappingType(myDir) != CIFTI_INDEX_TYPE_BRAIN_MODELS) throw AlgorithmException("mapping type along specified dimension is not brain models"); if ((otherXML.getMappingType(otherDir) == CIFTI_INDEX_TYPE_LABELS) != isLabel) throw AlgorithmException("input files to cifti merge dense mix label and non-label data"); int numModels = otherXML.getNumberOfBrainModels(myDir); for (int j = 0; j < numModels; ++j) { sourceCifti.push_back(i); CiftiBrainModelInfo myInfo = otherXML.getBrainModelInfo(myDir, j); switch (myInfo.m_type) { case CIFTI_MODEL_TYPE_SURFACE: { vector myMap; otherXML.getSurfaceMap(myDir, myMap, myInfo.m_structure); vector nodeList(myMap.size()); for (int64_t k = 0; k < (int64_t)myMap.size(); ++k) { nodeList[k] = myMap[k].m_surfaceNode; } if (!outXML.addSurfaceModel(myDir, otherXML.getSurfaceNumberOfNodes(myDir, myInfo.m_structure), myInfo.m_structure, nodeList)) { throw AlgorithmException("duplicate surface structure " + StructureEnum::toName(myInfo.m_structure) + " found in input to cifti merge dense"); } break; } case CIFTI_MODEL_TYPE_VOXELS: { vector myMap; otherXML.getVolumeStructureMap(myDir, myMap, myInfo.m_structure); vector voxelList(myMap.size() * 3); for (int64_t k = 0; k < (int64_t)myMap.size(); ++k) { int64_t k3 = k * 3; voxelList[k3] = myMap[k].m_ijk[0]; voxelList[k3 + 1] = myMap[k].m_ijk[1]; voxelList[k3 + 2] = myMap[k].m_ijk[2]; } if (!outXML.addVolumeModel(myDir, voxelList, myInfo.m_structure)) { throw AlgorithmException("duplicate volume structure " + StructureEnum::toName(myInfo.m_structure) + " found in input to cifti merge dense"); } break; } default: throw AlgorithmException("encountered unknown model type in cifti merge dense"); } } } CaretAssert((int)sourceCifti.size() == outXML.getNumberOfBrainModels(myDir)); myCiftiOut->setCiftiXML(outXML); for (int i = 0; i < (int)sourceCifti.size(); ++i) { CiftiBrainModelInfo myInfo = outXML.getBrainModelInfo(myDir, i); switch (myInfo.m_type) { case CIFTI_MODEL_TYPE_SURFACE: { if (isLabel) { LabelFile tempFile; AlgorithmCiftiSeparate(NULL, ciftiList[sourceCifti[i]], myDir, myInfo.m_structure, &tempFile);//using this because dealing with label tables is nasty, but doesn't happen on large files AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, myInfo.m_structure, &tempFile); } else {//for everything else, just use rows directly, because making large metric files in-memory is problematic vector inMap, outMap; const CiftiXMLOld& otherXML = ciftiList[sourceCifti[i]]->getCiftiXMLOld(); outXML.getSurfaceMap(myDir, outMap, myInfo.m_structure); otherXML.getSurfaceMap(myDir, inMap, myInfo.m_structure); CaretAssert(inMap.size() == outMap.size()); vector rowscratch(outXML.getNumberOfColumns()), otherscratch(otherXML.getNumberOfColumns()); if (myDir == CiftiXMLOld::ALONG_ROW) { for (int j = 0; j < outXML.getNumberOfRows(); ++j) { myCiftiOut->getRow(rowscratch.data(), j, true); ciftiList[sourceCifti[i]]->getRow(otherscratch.data(), j); for (int k = 0; k < (int)inMap.size(); ++k) { CaretAssert(inMap[k].m_surfaceNode == outMap[k].m_surfaceNode); rowscratch[outMap[k].m_ciftiIndex] = otherscratch[inMap[k].m_ciftiIndex]; } myCiftiOut->setRow(rowscratch.data(), j); } } else { for (int k = 0; k < (int)inMap.size(); ++k) { CaretAssert(inMap[k].m_surfaceNode == outMap[k].m_surfaceNode); ciftiList[sourceCifti[i]]->getRow(otherscratch.data(), inMap[k].m_ciftiIndex); myCiftiOut->setRow(otherscratch.data(), outMap[k].m_ciftiIndex); } } } break; } case CIFTI_MODEL_TYPE_VOXELS: { if (isLabel) {//cropped volume should be okay on memory for label files - let replace structure handle the label table VolumeFile tempFile; int64_t junk[3]; AlgorithmCiftiSeparate(NULL, ciftiList[sourceCifti[i]], myDir, myInfo.m_structure, &tempFile, junk, NULL, true); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, myInfo.m_structure, &tempFile, true); } else { vector inMap, outMap; const CiftiXMLOld& otherXML = ciftiList[sourceCifti[i]]->getCiftiXMLOld(); outXML.getVolumeStructureMap(myDir, outMap, myInfo.m_structure); otherXML.getVolumeStructureMap(myDir, inMap, myInfo.m_structure); CaretAssert(inMap.size() == outMap.size()); vector rowscratch(outXML.getNumberOfColumns()), otherscratch(otherXML.getNumberOfColumns()); if (myDir == CiftiXMLOld::ALONG_ROW) { for (int j = 0; j < outXML.getNumberOfRows(); ++j) { myCiftiOut->getRow(rowscratch.data(), j, true); ciftiList[sourceCifti[i]]->getRow(otherscratch.data(), j); for (int k = 0; k < (int)inMap.size(); ++k) { CaretAssert(inMap[k].m_ijk[0] == outMap[k].m_ijk[0]); CaretAssert(inMap[k].m_ijk[1] == outMap[k].m_ijk[1]); CaretAssert(inMap[k].m_ijk[2] == outMap[k].m_ijk[2]); rowscratch[outMap[k].m_ciftiIndex] = otherscratch[inMap[k].m_ciftiIndex]; } myCiftiOut->setRow(rowscratch.data(), j); } } else { for (int k = 0; k < (int)inMap.size(); ++k) { CaretAssert(inMap[k].m_ijk[0] == outMap[k].m_ijk[0]); CaretAssert(inMap[k].m_ijk[1] == outMap[k].m_ijk[1]); CaretAssert(inMap[k].m_ijk[2] == outMap[k].m_ijk[2]); ciftiList[sourceCifti[i]]->getRow(otherscratch.data(), inMap[k].m_ciftiIndex); myCiftiOut->setRow(otherscratch.data(), outMap[k].m_ciftiIndex); } } } break; } default: throw AlgorithmException("encountered unknown model type in cifti merge dense"); } } } float AlgorithmCiftiMergeDense::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiMergeDense::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiMergeDense.h000066400000000000000000000033561360521144700255570ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_MERGE_DENSE_H__ #define __ALGORITHM_CIFTI_MERGE_DENSE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include #include namespace caret { class AlgorithmCiftiMergeDense : public AbstractAlgorithm { AlgorithmCiftiMergeDense(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiMergeDense(ProgressObject* myProgObj, const int& myDir, const std::vector& ciftiList, CiftiFile* myCiftiOut); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiMergeDense; } #endif //__ALGORITHM_CIFTI_MERGE_DENSE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiMergeParcels.cxx000066400000000000000000000365221360521144700264660ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiMergeParcels.h" #include "AlgorithmException.h" #include "CiftiFile.h" #include "GiftiLabelTable.h" #include "MultiDimIterator.h" #include using namespace caret; using namespace std; AString AlgorithmCiftiMergeParcels::getCommandSwitch() { return "-cifti-merge-parcels"; } AString AlgorithmCiftiMergeParcels::getShortDescription() { return "MERGE CIFTI FILES ALONG PARCELS DIMENSION"; } OperationParameters* AlgorithmCiftiMergeParcels::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "direction", "which dimension to merge along (integer, 'ROW', or 'COLUMN')"); ret->addCiftiOutputParameter(2, "cifti-out", "the output cifti file"); ParameterComponent* ciftiOpt = ret->createRepeatableParameter(3, "-cifti", "specify an input cifti file"); ciftiOpt->addCiftiParameter(1, "cifti-in", "a cifti file to merge"); ret->setHelpText( AString("The input cifti files must have matching mappings along the direction not specified, and the mapping along the specified direction must be parcels. ") + CiftiXML::directionFromStringExplanation() ); return ret; } void AlgorithmCiftiMergeParcels::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { AString directionName = myParams->getString(1); int myDir = CiftiXML::directionFromString(directionName); CiftiFile* myCiftiOut = myParams->getOutputCifti(2); const vector& myInstances = *(myParams->getRepeatableParameterInstances(3)); vector ciftiList; int numCifti = (int)myInstances.size(); for (int i = 0; i < numCifti; ++i) { ciftiList.push_back(myInstances[i]->getCifti(1)); } AlgorithmCiftiMergeParcels(myProgObj, myDir, ciftiList, myCiftiOut); } AlgorithmCiftiMergeParcels::AlgorithmCiftiMergeParcels(ProgressObject* myProgObj, const int& myDir, const vector& ciftiList, CiftiFile* myCiftiOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CaretAssert(myDir >= 0); int listSize = (int)ciftiList.size(); if (listSize < 1) throw AlgorithmException("no input files specified"); CaretAssert(ciftiList[0] != NULL); const CiftiXML& firstXML = ciftiList[0]->getCiftiXML(); CiftiXML outXML = firstXML; int numDims = -1; int labelDim = -1; vector > > remaps(listSize); for (int i = 0; i < listSize; ++i) { CaretAssert(ciftiList[i] != NULL); const CiftiXML& thisXML = ciftiList[i]->getCiftiXML(); if (myDir >= thisXML.getNumberOfDimensions()) { throw AlgorithmException("input cifti file '" + ciftiList[i]->getFileName() + "' does not have the specified dimension"); } if (thisXML.getMappingType(myDir) != CiftiMappingType::PARCELS) { throw AlgorithmException("input cifti file '" + ciftiList[i]->getFileName() + "' does not have a parcels mapping on the specified dimension"); } if (i != 0) { CiftiParcelsMap& outParcelMap = outXML.getParcelsMap(myDir); const CiftiParcelsMap& thisParcelMap = thisXML.getParcelsMap(myDir); if (thisParcelMap.hasVolumeData()) { if (outParcelMap.hasVolumeData())//if there is no volume data yet, we don't care about the volume space, if it exists { if (!outParcelMap.getVolumeSpace().matches(thisParcelMap.getVolumeSpace())) { throw AlgorithmException("input cifti file '" + ciftiList[i]->getFileName() + "' does not match the volume space of earlier input files"); } } else { outParcelMap.setVolumeSpace(thisParcelMap.getVolumeSpace()); } } vector thisSurfs = thisParcelMap.getParcelSurfaceStructures(); for (int i = 0; i < (int)thisSurfs.size(); ++i) { if (outParcelMap.hasSurface(thisSurfs[i])) { if (thisParcelMap.getSurfaceNumberOfNodes(thisSurfs[i]) != outParcelMap.getSurfaceNumberOfNodes(thisSurfs[i])) { throw AlgorithmException("input cifti file '" + ciftiList[i]->getFileName() + "' has different number of vertices than earlier input files for surface " + StructureEnum::toName(thisSurfs[i])); } } else { outParcelMap.addSurface(thisParcelMap.getSurfaceNumberOfNodes(thisSurfs[i]), thisSurfs[i]); } } const vector& thisParcels = thisParcelMap.getParcels(); for (int64_t p = 0; p < (int64_t)thisParcels.size(); ++p) { outParcelMap.addParcel(thisParcels[p]);//does the error checking for overlap, unique name } } int thisNumDims = thisXML.getNumberOfDimensions(); if (i == 0) { numDims = thisNumDims; } else { if (thisNumDims != numDims) { throw AlgorithmException("input cifti file '" + ciftiList[i]->getFileName() + "' has " + AString::number(thisNumDims) + " dimensions, while file '" + ciftiList[0]->getFileName() + "' has " + AString::number(numDims) + " dimensions"); } AString explanation; for (int d = 0; d < thisNumDims; ++d) { if (d != myDir) { if (!(firstXML.getMap(d)->approximateMatch(*(thisXML.getMap(d)), &explanation)))//expect transitive property in approximateMatch, so only check against first file { throw AlgorithmException("input cifti file '" + ciftiList[i]->getFileName() + "' is incompatible with file '" + ciftiList[0]->getFileName() + "' on dimension " + AString::number(d + 1) + ": " + explanation); } if (thisXML.getMappingType(d) == CiftiMappingType::LABELS || firstXML.getMappingType(d) == CiftiMappingType::LABELS) {//NOTE: relies on CiftiXML not allowing more than one label dimension if (firstXML.getMappingType(d) != CiftiMappingType::LABELS) { throw AlgorithmException("input cifti file '" + ciftiList[i]->getFileName() + "' has a labels mapping on dimension " + AString::number(d + 1) + ", but file '" + ciftiList[0]->getFileName() + "' does not"); } if (thisXML.getMappingType(d) != CiftiMappingType::LABELS) { throw AlgorithmException("input cifti file '" + ciftiList[0]->getFileName() + "' has a labels mapping on dimension " + AString::number(d + 1) + ", but file '" + ciftiList[i]->getFileName() + "' does not"); } labelDim = d; if (i != 0)//because we used the first file's XML as a template { CiftiLabelsMap& outLabelsMap = outXML.getLabelsMap(d); int64_t numMaps = outLabelsMap.getLength(); remaps[d].resize(numMaps); for (int64_t m = 0; m < numMaps; ++m) { remaps[d][m] = outLabelsMap.getMapLabelTable(m)->append(*(thisXML.getLabelsMap(d).getMapLabelTable(m))); } } } } } } } myCiftiOut->setCiftiXML(outXML); vector outDims = outXML.getDimensions(); vector unlabeledKeys; if (labelDim != -1) { unlabeledKeys.resize(outDims[labelDim]); const CiftiLabelsMap& outLabelsMap = outXML.getLabelsMap(labelDim); for (int64_t i = 0; i < (int64_t)unlabeledKeys.size(); ++i) { unlabeledKeys[i] = outLabelsMap.getMapLabelTable(i)->getUnassignedLabelKey(); } } if (myDir == CiftiXML::ALONG_ROW) {//because unit of input/output is a row vector rowOut(outXML.getDimensionLength(CiftiXML::ALONG_ROW)), rowIn;//adapt input row size on use, in case we add options to select parcels from files for (MultiDimIterator iter(vector(outDims.begin() + 1, outDims.end())); !iter.atEnd(); ++iter) {//the + 1 is to exclude the row dimension int64_t startIndex = 0; for (int i = 0; i < listSize; ++i) { int64_t inRowLength = ciftiList[i]->getCiftiXML().getDimensionLength(CiftiXML::ALONG_ROW); if (inRowLength > (int64_t)rowIn.size()) { rowIn.resize(inRowLength); } ciftiList[i]->getRow(rowIn.data(), *iter); if (labelDim != -1) { int64_t labelMap = (*iter)[labelDim - 1]; for (int64_t j = 0; j < inRowLength; ++j) { int32_t key = (int32_t)floor(0.5f + rowIn[j]); if (i == 0)//because we used the first XML as a template { rowOut[startIndex + j] = key; } else { map::iterator iter = remaps[i][labelMap].find(key); if (iter == remaps[i][labelMap].end())//NOTE: GiftiLabelTable::append creates an entry for every key in the original table, even if it maps to the same value { rowOut[startIndex + j] = unlabeledKeys[labelMap]; } else { rowOut[startIndex + j] = iter->second; } } } } else { for (int64_t j = 0; j < inRowLength; ++j) { rowOut[startIndex + j] = rowIn[j]; } } startIndex += inRowLength; } myCiftiOut->setRow(rowOut.data(), *iter); } } else {//now the fun begins... int64_t rowLength = outXML.getDimensionLength(CiftiXML::ALONG_ROW); vector rowOut(rowLength), rowIn(rowLength);//input rows must be the same length if not row merging vector indexvec(outDims.size() - 1, -1); for (MultiDimIterator outeriter(vector(outDims.begin() + myDir + 1, outDims.end())); !outeriter.atEnd(); ++outeriter) {//split matching cifti dimensions by greater or less than myDir, aim for sequential output vector outerindexvec = *outeriter; for (int i = myDir + 1; i < (int)outDims.size(); ++i) { indexvec[i - 1] = outerindexvec[i - myDir - 1];//indexvec is missing the row dimension, outerindexvec starts one after myDir } int64_t startIndex = 0; for (int i = 0; i < listSize; ++i) {//for mydir, loop over files, and then parcels within file int64_t thisNumParcels = ciftiList[i]->getCiftiXML().getDimensionLength(myDir); for (int64_t j = 0; j < thisNumParcels; ++j) { for (MultiDimIterator inneriter(vector(outDims.begin() + 1, outDims.begin() + myDir)); !inneriter.atEnd(); ++inneriter) {//then loop over dimensions less than mydir, excluding row vector innerindices = *inneriter; for (int k = 1; k < myDir; ++k) { indexvec[k - 1] = innerindices[k - 1]; } indexvec[myDir - 1] = j;//for input ciftiList[i]->getRow(rowIn.data(), indexvec); if (labelDim != -1) {//we COULD check if labelDim is before or after myDim, and move some of the following to an outer loop, but it really doesn't seem worth it for (int k = 0; k < rowLength; ++k) { int32_t key = (int32_t)floor(0.5f + rowIn[k]); if (i == 0)//we used the first XML as a template, there is no remap { rowOut[k] = key; } else { int64_t labelMap = -1; if (labelDim == 0)//note that labelDim will never be myDir, so indexvec doesn't need to be adjusted { labelMap = k; } else { labelMap = indexvec[labelDim - 1]; } map::iterator iter = remaps[i][labelMap].find(key); if (iter == remaps[i][labelMap].end())//NOTE: GiftiLabelTable::append creates an entry for every key in the original table, even if it maps to the same value { rowOut[k] = unlabeledKeys[labelMap]; } else { rowOut[k] = iter->second; } } } indexvec[myDir - 1] = startIndex + j;//for output myCiftiOut->setRow(rowOut.data(), indexvec); } else { indexvec[myDir - 1] = startIndex + j;//for output myCiftiOut->setRow(rowIn.data(), indexvec); } } } startIndex += thisNumParcels; } } } } float AlgorithmCiftiMergeParcels::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiMergeParcels::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiMergeParcels.h000066400000000000000000000033301360521144700261020ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_MERGE_PARCELS_H__ #define __ALGORITHM_CIFTI_MERGE_PARCELS_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmCiftiMergeParcels : public AbstractAlgorithm { AlgorithmCiftiMergeParcels(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiMergeParcels(ProgressObject* myProgObj, const int& myDir, const std::vector& ciftiList, CiftiFile* myCiftiOut); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiMergeParcels; } #endif //__ALGORITHM_CIFTI_MERGE_PARCELS_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiPairwiseCorrelation.cxx000066400000000000000000000127621360521144700301020ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiPairwiseCorrelation.h" #include "AlgorithmException.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretOMP.h" #include "CiftiFile.h" #include "FileInformation.h" #include using namespace caret; using namespace std; AString AlgorithmCiftiPairwiseCorrelation::getCommandSwitch() { return "-cifti-pairwise-correlation"; } AString AlgorithmCiftiPairwiseCorrelation::getShortDescription() { return "CORRELATE PAIRED ROWS BETWEEN TWO CIFTI FILES"; } OperationParameters* AlgorithmCiftiPairwiseCorrelation::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-a", "first input cifti file"); ret->addCiftiParameter(2, "cifti-b", "second input cifti file"); ret->addCiftiOutputParameter(3, "cifti-out", "output cifti file"); ret->createOptionalParameter(4, "-fisher-z", "apply fisher small z transform (ie, artanh) to correlation"); ret->createOptionalParameter(5, "-override-mapping-check", "don't check the mappings for compatibility, only check length"); ret->setHelpText( AString("For each row in , correlate it with the same row in , and put the result in the same row of , which has only one column.") ); return ret; } void AlgorithmCiftiPairwiseCorrelation::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* myCiftiA = myParams->getCifti(1); CiftiFile* myCiftiB = myParams->getCifti(2); CiftiFile* myCiftiOut = myParams->getOutputCifti(3); bool fisherZ = myParams->getOptionalParameter(4)->m_present; bool overrideMappingCheck = myParams->getOptionalParameter(5)->m_present; AlgorithmCiftiPairwiseCorrelation(myProgObj, myCiftiA, myCiftiB, myCiftiOut, fisherZ, overrideMappingCheck); } AlgorithmCiftiPairwiseCorrelation::AlgorithmCiftiPairwiseCorrelation(ProgressObject* myProgObj, const CiftiFile* myCiftiA, const CiftiFile* myCiftiB, CiftiFile* myCiftiOut, const bool& fisherZ, const bool& overrideMappingCheck) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CiftiXMLOld outXML = myCiftiA->getCiftiXMLOld(); int64_t numRows = myCiftiA->getNumberOfRows(), rowLength = myCiftiA->getNumberOfColumns(); if (overrideMappingCheck) { if (numRows != myCiftiB->getNumberOfRows()) throw AlgorithmException("column length must match between the input files"); } else { if (!outXML.matchesForColumns(myCiftiB->getCiftiXMLOld())) throw AlgorithmException("mapping along columns must match between the input files"); } if (rowLength != myCiftiB->getNumberOfColumns()) throw AlgorithmException("row length must match between the input files"); outXML.resetRowsToScalars(1); outXML.setMapNameForRowIndex(0, "pairwise correlation"); myCiftiOut->setCiftiXML(outXML); vector rowA(rowLength), rowB(rowLength), columnOut(numRows); for (int64_t i = 0; i < numRows; ++i) { float rrsA, rrsB; myCiftiA->getRow(rowA.data(), i); myCiftiB->getRow(rowB.data(), i); preprocess(rowA.data(), rowLength, rrsA); preprocess(rowB.data(), rowLength, rrsB); columnOut[i] = correlate(rowA.data(), rrsA, rowB.data(), rrsB, rowLength, fisherZ); } myCiftiOut->setColumn(columnOut.data(), 0); } void AlgorithmCiftiPairwiseCorrelation::preprocess(float* row, const int64_t length, float& rrsOut) { double accum = 0.0; for (int64_t i = 0; i < length; ++i) { accum += row[i]; } float mean = accum / length; accum = 0.0; for (int64_t i = 0; i < length; ++i) { row[i] -= mean; accum += row[i] * row[i]; } rrsOut = sqrt(accum); } float AlgorithmCiftiPairwiseCorrelation::correlate(const float* rowA, const float& rrsA, const float* rowB, const float& rrsB, const int64_t& length, const bool& fisherZ) { double r = 0.0; for (int64_t i = 0; i < length; ++i) { r += rowA[i] * rowB[i]; } r /= rrsA * rrsB; if (fisherZ) { if (r > 0.999999) r = 0.999999;//prevent inf if (r < -0.999999) r = -0.999999;//prevent -inf return 0.5 * log((1 + r) / (1 - r)); } else { if (r > 1.0) r = 1.0;//don't output anything silly if (r < -1.0) r = -1.0; return r; } } float AlgorithmCiftiPairwiseCorrelation::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiPairwiseCorrelation::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiPairwiseCorrelation.h000066400000000000000000000041201360521144700275140ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_PAIRWISE_CORRELATION_H__ #define __ALGORITHM_CIFTI_PAIRWISE_CORRELATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmCiftiPairwiseCorrelation : public AbstractAlgorithm { AlgorithmCiftiPairwiseCorrelation(); void preprocess(float* row, const int64_t length, float& rrsOut); float correlate(const float* rowA, const float& rrsA, const float* rowB, const float& rrsB, const int64_t& length, const bool& fisherZ); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiPairwiseCorrelation(ProgressObject* myProgObj, const CiftiFile* myCiftiA, const CiftiFile* myCiftiB, CiftiFile* myCiftiOut, const bool& fisherZ = false, const bool& overrideMappingCheck = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiPairwiseCorrelation; } #endif //__ALGORITHM_CIFTI_PAIRWISE_CORRELATION_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiParcelMappingToLabel.cxx000066400000000000000000000135201360521144700300730ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiParcelMappingToLabel.h" #include "AlgorithmException.h" #include "CiftiFile.h" #include using namespace caret; using namespace std; AString AlgorithmCiftiParcelMappingToLabel::getCommandSwitch() { return "-cifti-parcel-mapping-to-label"; } AString AlgorithmCiftiParcelMappingToLabel::getShortDescription() { return "CREATE DLABEL FROM PARCELLATED FILE"; } OperationParameters* AlgorithmCiftiParcelMappingToLabel::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-in", "the input parcellated file"); ret->addStringParameter(2, "direction", "which dimension to take the parcel map from, ROW or COLUMN"); ret->addCiftiParameter(3, "template-cifti", "a cifti file with the desired dense mapping along column"); ret->addCiftiOutputParameter(4, "dlabel-out", "the output dense label file"); ret->setHelpText( AString("This command will output a dlabel file, useful for doing the same parcellation to another dense file.\n\n") + "For ptseries, pscalar, plabel, pconn, and pdconn, using COLUMN for will work." ); return ret; } void AlgorithmCiftiParcelMappingToLabel::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* ciftiIn = myParams->getCifti(1); AString dirString = myParams->getString(2); int direction = -1; if (dirString == "ROW") { direction = CiftiXML::ALONG_ROW; } else if (dirString == "COLUMN") { direction = CiftiXML::ALONG_COLUMN; } else { throw AlgorithmException("unrecognized direction string, use ROW or COLUMN"); } CiftiFile* templateCifti = myParams->getCifti(3); CiftiFile* ciftiOut = myParams->getOutputCifti(4); const CiftiXML& parcelXML = ciftiIn->getCiftiXML(); if (direction >= parcelXML.getNumberOfDimensions()) { throw AlgorithmException("specified direction does not exist in input cifti file"); } if (parcelXML.getMappingType(direction) != CiftiMappingType::PARCELS) { throw AlgorithmException("input cifti file does not have parcels mapping on specified direction"); } const CiftiXML& denseXML = templateCifti->getCiftiXML(); if (denseXML.getNumberOfDimensions() < 2) { throw AlgorithmException("template cifti file does not have an along column dimension"); } if (denseXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) { throw AlgorithmException("template cifti file does not have a dense mapping along column, try using a dscalar, dtseries, dlabel, or dconn"); } AlgorithmCiftiParcelMappingToLabel(myProgObj, parcelXML.getParcelsMap(direction), denseXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN), ciftiOut); } AlgorithmCiftiParcelMappingToLabel::AlgorithmCiftiParcelMappingToLabel(ProgressObject* myProgObj, const CiftiParcelsMap& parcelMap, const CiftiBrainModelsMap& denseMap, CiftiFile* ciftiOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CiftiXML outXML; outXML.setNumberOfDimensions(2); outXML.setMap(CiftiXML::ALONG_COLUMN, denseMap); vector surfStructures = parcelMap.getParcelSurfaceStructures(); CiftiLabelsMap outLabelMap; outLabelMap.setLength(1); GiftiLabelTable* outTable = outLabelMap.getMapLabelTable(0); vector parcelToKey(parcelMap.getLength()); for (int i = 0; i < (int)parcelMap.getLength(); ++i) { parcelToKey[i] = outTable->addLabel(parcelMap.getIndexName(i), rand() & 255, rand() & 255, rand() & 255, 255); } outXML.setMap(CiftiXML::ALONG_ROW, outLabelMap); vector scratchCol(denseMap.getLength(), outTable->getUnassignedLabelKey()); vector surfStructs = denseMap.getSurfaceStructureList(); for (int i = 0; i < (int)surfStructs.size(); ++i) { vector surfMap = denseMap.getSurfaceMap(surfStructs[i]); for (int j = 0; j < (int)surfMap.size(); ++j) { int whichParcel = parcelMap.getIndexForNode(surfMap[j].m_surfaceNode, surfStructs[i]); if (whichParcel >= 0) { scratchCol[surfMap[j].m_ciftiIndex] = parcelToKey[whichParcel]; } } } vector volMap = denseMap.getFullVolumeMap(); for (int i = 0; i < (int)volMap.size(); ++i) { int whichParcel = parcelMap.getIndexForVoxel(volMap[i].m_ijk); if (whichParcel >= 0) { scratchCol[volMap[i].m_ciftiIndex] = parcelToKey[whichParcel]; } } ciftiOut->setCiftiXML(outXML); ciftiOut->setColumn(scratchCol.data(), 0); } float AlgorithmCiftiParcelMappingToLabel::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiParcelMappingToLabel::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiParcelMappingToLabel.h000066400000000000000000000035401360521144700275210ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_PARCEL_MAPPING_TO_LABEL_H__ #define __ALGORITHM_CIFTI_PARCEL_MAPPING_TO_LABEL_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class CiftiParcelsMap; class CiftiBrainModelsMap; class AlgorithmCiftiParcelMappingToLabel : public AbstractAlgorithm { AlgorithmCiftiParcelMappingToLabel(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiParcelMappingToLabel(ProgressObject* myProgObj, const CiftiParcelsMap& parcelMap, const CiftiBrainModelsMap& denseMap, CiftiFile* ciftiOut); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiParcelMappingToLabel; } #endif //__ALGORITHM_CIFTI_PARCEL_MAPPING_TO_LABEL_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiParcellate.cxx000066400000000000000000001553421360521144700261730ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiParcellate.h" #include "AlgorithmException.h" #include "CaretLogger.h" #include "CiftiFile.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "MetricFile.h" #include "MultiDimIterator.h" #include "ReductionOperation.h" #include "SurfaceFile.h" #include #include using namespace caret; using namespace std; AString AlgorithmCiftiParcellate::getCommandSwitch() { return "-cifti-parcellate"; } AString AlgorithmCiftiParcellate::getShortDescription() { return "PARCELLATE A CIFTI FILE"; } OperationParameters* AlgorithmCiftiParcellate::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-in", "the cifti file to parcellate"); ret->addCiftiParameter(2, "cifti-label", "a cifti label file to use for the parcellation"); ret->addStringParameter(3, "direction", "which mapping to parcellate (integer, ROW, or COLUMN)"); ret->addCiftiOutputParameter(4, "cifti-out", "output cifti file"); OptionalParameter* spatialWeightOpt = ret->createOptionalParameter(5, "-spatial-weights", "use voxel volume and either vertex areas or metric files as weights"); OptionalParameter* leftAreaSurfOpt = spatialWeightOpt->createOptionalParameter(1, "-left-area-surf", "use a surface for left vertex areas"); leftAreaSurfOpt->addSurfaceParameter(1, "left-surf", "the left surface to use, areas are in mm^2"); OptionalParameter* rightAreaSurfOpt = spatialWeightOpt->createOptionalParameter(2, "-right-area-surf", "use a surface for right vertex areas"); rightAreaSurfOpt->addSurfaceParameter(1, "right-surf", "the right surface to use, areas are in mm^2"); OptionalParameter* cerebAreaSurfOpt = spatialWeightOpt->createOptionalParameter(3, "-cerebellum-area-surf", "use a surface for cerebellum vertex areas"); cerebAreaSurfOpt->addSurfaceParameter(1, "cerebellum-surf", "the cerebellum surface to use, areas are in mm^2"); OptionalParameter* leftAreaMetricOpt = spatialWeightOpt->createOptionalParameter(4, "-left-area-metric", "use a metric file for left vertex weights"); leftAreaMetricOpt->addMetricParameter(1, "left-metric", "metric file containing left vertex weights"); OptionalParameter* rightAreaMetricOpt = spatialWeightOpt->createOptionalParameter(5, "-right-area-metric", "use a metric file for right vertex weights"); rightAreaMetricOpt->addMetricParameter(1, "right-metric", "metric file containing right vertex weights"); OptionalParameter* cerebAreaMetricOpt = spatialWeightOpt->createOptionalParameter(6, "-cerebellum-area-metric", "use a metric file for cerebellum vertex weights"); cerebAreaMetricOpt->addMetricParameter(1, "cerebellum-metric", "metric file containing cerebellum vertex weights"); OptionalParameter* ciftiWeightOpt = ret->createOptionalParameter(6, "-cifti-weights", "use a cifti file containing weights"); ciftiWeightOpt->addCiftiParameter(1, "weight-cifti", "the weights to use, as a cifti file"); OptionalParameter* methodOpt = ret->createOptionalParameter(7, "-method", "specify method of parcellation (default MEAN, or MODE if label data)"); methodOpt->addStringParameter(1, "method", "the method to use to assign parcel values from the values of member brainordinates"); OptionalParameter* excludeOpt = ret->createOptionalParameter(8, "-exclude-outliers", "exclude non-numeric values and outliers from each parcel by standard deviation"); excludeOpt->addDoubleParameter(1, "sigma-below", "number of standard deviations below the mean to include"); excludeOpt->addDoubleParameter(2, "sigma-above", "number of standard deviations above the mean to include"); ret->createOptionalParameter(9, "-only-numeric", "exclude non-numeric values"); OptionalParameter* emptyValOpt = ret->createOptionalParameter(11, "-fill-value", "specify value to use in empty parcels (default 0)"); emptyValOpt->addDoubleParameter(1, "value", "the value to fill empty parcels with"); OptionalParameter* emptyRoiOpt = ret->createOptionalParameter(12, "-nonempty-mask-out", "output a matching pscalar file that has 0s in empty parcels, and 1s elsewhere"); emptyRoiOpt->addCiftiOutputParameter(1, "mask-out", "the output mask file"); ret->createOptionalParameter(13, "-legacy-mode", "use the old behavior, parcels are defined by the intersection between labels and valid data, and empty parcels are discarded"); ret->createOptionalParameter(10, "-include-empty", "deprecated: now the default behavior"); ret->setHelpText( AString("Each label (other than the unlabeled key) in the cifti label file will be treated as a parcel, and all rows or columns of data within the parcel ") + "are averaged together to form the parcel's output row or column. " + "If -legacy-mode is specified, parcels will be defined as the overlap between a label and the data, with no errors for missing data vertices or voxels, and empty parcels discarded. " + CiftiXML::directionFromStringExplanation() + " " + "For dtseries or dscalar, use COLUMN. " + "If you are parcellating a dconn in both directions, parcellating by ROW first will use much less memory.\n\n" + "The parameter to the -method option must be one of the following:\n\n" + ReductionOperation::getHelpInfo() + "\nThe -*-weights options are mutually exclusive and may only be used with MEAN (default), SUM, STDEV, SAMPSTDEV, VARIANCE, MEDIAN, or MODE (default for label data)." ); return ret; } void AlgorithmCiftiParcellate::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* myCiftiIn = myParams->getCifti(1); CiftiFile* myCiftiLabel = myParams->getCifti(2); int direction = CiftiXML::directionFromString(myParams->getString(3)); CiftiFile* myCiftiOut = myParams->getOutputCifti(4); const CiftiXML& myXML = myCiftiIn->getCiftiXML(); vector dims = myXML.getDimensions(); ReductionEnum::Enum method = ReductionEnum::MEAN; for (int i = 0; i < (int)dims.size(); ++i) { if (myXML.getMappingType(i) == CiftiMappingType::LABELS) { method = ReductionEnum::MODE; break; } } OptionalParameter* methodOpt = myParams->getOptionalParameter(7); if (methodOpt->m_present) { bool ok = false; method = ReductionEnum::fromName(methodOpt->getString(1), &ok); if (!ok) { throw AlgorithmException("unrecognized method string '" + methodOpt->getString(1) + "'"); } } bool onlyNumeric = myParams->getOptionalParameter(9)->m_present; float excludeLow = -1.0f, excludeHigh = -1.0f; OptionalParameter* excludeOpt = myParams->getOptionalParameter(8); if (excludeOpt->m_present) { if (onlyNumeric) CaretLogWarning("-only-numeric is redundant when -exclude-outliers is specified"); excludeLow = (float)excludeOpt->getDouble(1); excludeHigh = (float)excludeOpt->getDouble(2); if (!(excludeLow > 0.0f && excludeHigh > 0.0f)) throw AlgorithmException("exclusion sigmas must be positive"); } /*OptionalParameter* emptyOpt = */myParams->getOptionalParameter(10);//deprecated, but we need to "get" it to avoid a debug warning of an ignored option float emptyFillValue = 0.0f; OptionalParameter* emptyValOpt = myParams->getOptionalParameter(11); if (emptyValOpt->m_present) { emptyFillValue = emptyValOpt->getDouble(1); } CiftiFile* emptyMaskOut = NULL; OptionalParameter* emptyRoiOpt = myParams->getOptionalParameter(12); if (emptyRoiOpt->m_present) { emptyMaskOut = emptyRoiOpt->getOutputCifti(1); } bool legacyMode = myParams->getOptionalParameter(13)->m_present; OptionalParameter* spatialWeightOpt = myParams->getOptionalParameter(5); OptionalParameter* ciftiWeightOpt = myParams->getOptionalParameter(6); if (spatialWeightOpt->m_present && ciftiWeightOpt->m_present) { throw AlgorithmException("only one of -spatial-weights and -cifti-weights may be specified"); } if (spatialWeightOpt->m_present) { if (direction >= myXML.getNumberOfDimensions()) throw AlgorithmException("input cifti file does not have the specified dimension"); if (myXML.getMappingType(direction) != CiftiMappingType::BRAIN_MODELS) throw AlgorithmException("input cifti file does not have brain models mapping type in specified direction"); CiftiBrainModelsMap myDenseMap = myXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); OptionalParameter* leftSurfOpt = spatialWeightOpt->getOptionalParameter(1); OptionalParameter* rightSurfOpt = spatialWeightOpt->getOptionalParameter(2); OptionalParameter* cerebSurfOpt = spatialWeightOpt->getOptionalParameter(3); OptionalParameter* leftMetricOpt = spatialWeightOpt->getOptionalParameter(4); OptionalParameter* rightMetricOpt = spatialWeightOpt->getOptionalParameter(5); OptionalParameter* cerebMetricOpt = spatialWeightOpt->getOptionalParameter(6); if (leftSurfOpt->m_present && leftMetricOpt->m_present) throw AlgorithmException("only one of -left-area-surf and -left-area-metric may be specified"); if (rightSurfOpt->m_present && rightMetricOpt->m_present) throw AlgorithmException("only one of -right-area-surf and -right-area-metric may be specified"); if (cerebSurfOpt->m_present && cerebMetricOpt->m_present) throw AlgorithmException("only one of -cerebellum-area-surf and -cerebellum-area-metric may be specified"); MetricFile leftStore, rightStore, cerebStore; const MetricFile* leftWeights = NULL, *rightWeights = NULL, *cerebWeights = NULL; for (int i = 0; i < 3; ++i) { MetricFile* thisStore = NULL; const MetricFile** thisWeights = NULL; OptionalParameter* thisSurfOpt = NULL, *thisMetricOpt = NULL; switch (i) { case 0: thisStore = &leftStore; thisWeights = &leftWeights; thisSurfOpt = leftSurfOpt; thisMetricOpt = leftMetricOpt; break; case 1: thisStore = &rightStore; thisWeights = &rightWeights; thisSurfOpt = rightSurfOpt; thisMetricOpt = rightMetricOpt; break; case 2: thisStore = &cerebStore; thisWeights = &cerebWeights; thisSurfOpt = cerebSurfOpt; thisMetricOpt = cerebMetricOpt; break; } if (thisMetricOpt->m_present) { *thisWeights = thisMetricOpt->getMetric(1); } if (thisSurfOpt->m_present) { SurfaceFile* thisSurf = thisSurfOpt->getSurface(1); thisStore->setNumberOfNodesAndColumns(thisSurf->getNumberOfNodes(), 1); thisStore->setStructure(thisSurf->getStructure()); vector vertAreas; thisSurf->computeNodeAreas(vertAreas); thisStore->setValuesForColumn(0, vertAreas.data()); *thisWeights = thisStore; } } AlgorithmCiftiParcellate(myProgObj, myCiftiIn, myCiftiLabel, direction, myCiftiOut, leftWeights, rightWeights, cerebWeights, method, excludeLow, excludeHigh, onlyNumeric, legacyMode, emptyFillValue, emptyMaskOut); return; } if (ciftiWeightOpt->m_present) { AlgorithmCiftiParcellate(myProgObj, myCiftiIn, myCiftiLabel, direction, myCiftiOut, ciftiWeightOpt->getCifti(1), method, excludeLow, excludeHigh, onlyNumeric, legacyMode, emptyFillValue, emptyMaskOut); return; } AlgorithmCiftiParcellate(myProgObj, myCiftiIn, myCiftiLabel, direction, myCiftiOut, method, excludeLow, excludeHigh, onlyNumeric, legacyMode, emptyFillValue, emptyMaskOut); } AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const CiftiFile* myCiftiLabel, const int& direction, CiftiFile* myCiftiOut, const ReductionEnum::Enum& method, const float& excludeLow, const float& excludeHigh, const bool& onlyNumeric, const bool& legacyMode, const float& emptyFillVal, CiftiFile* emptyMaskOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CaretAssert(direction >= 0); const CiftiXML& myInputXML = myCiftiIn->getCiftiXML(); const CiftiXML& myLabelXML = myCiftiLabel->getCiftiXML(); vector dims = myInputXML.getDimensions(); if (direction >= (int)dims.size()) throw AlgorithmException("specified direction doesn't exist in input file"); if (myInputXML.getMappingType(direction) != CiftiMappingType::BRAIN_MODELS) { throw AlgorithmException("input cifti file does not have brain models mapping type in specified direction"); } if (myLabelXML.getNumberOfDimensions() != 2 || myLabelXML.getMappingType(CiftiXML::ALONG_ROW) != CiftiMappingType::LABELS || myLabelXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) { throw AlgorithmException("input cifti label file has the wrong mapping types"); } const CiftiBrainModelsMap& inputDense = myInputXML.getBrainModelsMap(direction); const CiftiBrainModelsMap& labelDense = myLabelXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); if (inputDense.hasVolumeData()) {//don't check volume space if direction doesn't have volume data if (labelDense.hasVolumeData() && !inputDense.getVolumeSpace().matches(labelDense.getVolumeSpace())) { throw AlgorithmException("input cifti files must have the same volume space"); } } vector indexToParcel; CiftiXML myOutXML = myInputXML; CiftiParcelsMap outParcelMap = parcellateMapping(myCiftiLabel, inputDense, indexToParcel, legacyMode); int numParcels = outParcelMap.getLength(); if (numParcels < 1) { throw AlgorithmException("no parcels found, output file would be empty, aborting"); } myOutXML.setMap(direction, outParcelMap); myCiftiOut->setCiftiXML(myOutXML); int64_t numCols = myInputXML.getDimensionLength(CiftiXML::ALONG_ROW); vector scratchRow(numCols); vector parcelCounts(numParcels, 0); for (int64_t j = 0; j < (int64_t)indexToParcel.size(); ++j) { int parcel = indexToParcel[j]; CaretAssert(parcel > -2 && parcel < numParcels); if (parcel != -1) { ++parcelCounts[parcel]; } } if (emptyMaskOut != NULL) { CiftiXML maskOutXML; maskOutXML.setNumberOfDimensions(2); maskOutXML.setMap(CiftiXML::ALONG_COLUMN, outParcelMap); CiftiScalarsMap maskNameMap; maskNameMap.setLength(1); maskNameMap.setMapName(0, "parcel not empty"); maskOutXML.setMap(CiftiXML::ALONG_ROW, maskNameMap); emptyMaskOut->setCiftiXML(maskOutXML); vector emptyMaskData(numParcels, 1.0f); for (int i = 0; i < numParcels; ++i) { if (parcelCounts[i] == 0) { emptyMaskData[i] = 0.0f; } } emptyMaskOut->setColumn(emptyMaskData.data(), 0); } bool isLabel = false; int labelDir = -1; for (int i = 0; i < (int)dims.size(); ++i) { if (myInputXML.getMappingType(i) == CiftiMappingType::LABELS) { isLabel = true; labelDir = i; break;//there should never be more than one dimension with LABEL type, and if there is, just use the first one, i guess... } } if (isLabel && method != ReductionEnum::MODE) { CaretLogWarning(ReductionEnum::toName(method) + " reduction requested while parcellating label data"); } if (direction == CiftiXML::ALONG_ROW) { vector scratchOutRow(numParcels); vector > parcelData(numParcels);//float so we can use ReductionOperation for (int j = 0; j < numParcels; ++j) { parcelData[j].reserve(parcelCounts[j]); } for (MultiDimIterator iter(vector(dims.begin() + 1, dims.end())); !iter.atEnd(); ++iter) { for (int j = 0; j < numParcels; ++j) { parcelData[j].clear();//doesn't change allocation } myCiftiIn->getRow(scratchRow.data(), *iter); for (int64_t j = 0; j < numCols; ++j) { int parcel = indexToParcel[j]; if (parcel != -1) { if (isLabel) { parcelData[parcel].push_back(floor(scratchRow[j] + 0.5f));//round to nearest integer to be safe } else { parcelData[parcel].push_back(scratchRow[j]); } } } for (int j = 0; j < numParcels; ++j) { CaretAssert(parcelCounts[j] == (int64_t)parcelData[j].size()); if (parcelCounts[j] > 0 && (method != ReductionEnum::SAMPSTDEV || parcelCounts[j] > 1)) { if (excludeLow > 0.0f && excludeHigh > 0.0f) { scratchOutRow[j] = ReductionOperation::reduceExcludeDev(parcelData[j].data(), parcelData[j].size(), method, excludeLow, excludeHigh); } else { if (onlyNumeric) { scratchOutRow[j] = ReductionOperation::reduceOnlyNumeric(parcelData[j].data(), parcelData[j].size(), method); } else { scratchOutRow[j] = ReductionOperation::reduce(parcelData[j].data(), parcelData[j].size(), method); } } } else {//labelDir can't be 0 (row) because we are parcellating along row, so row must be dense if (isLabel) { scratchOutRow[j] = myOutXML.getLabelsMap(labelDir).getMapLabelTable((*iter)[labelDir - 1])->getUnassignedLabelKey(); } else { scratchOutRow[j] = emptyFillVal;//odd corner case, but probably fine: with nonzero empty fill value and SAMPSTDEV, parcels with only one element get the fill value, but aren't technically empty } } } myCiftiOut->setRow(scratchOutRow.data(), *iter); } } else { vector scratchOutRow(numCols); vector otherDims = dims; otherDims.erase(otherDims.begin() + direction);//direction being parcellated otherDims.erase(otherDims.begin());//row vector > > parcelData(numParcels, vector >(numCols));//float so we can use ReductionOperation for (int i = 0; i < numParcels; ++i) { for (int j = 0; j < numCols; ++j) { parcelData[i][j].reserve(parcelCounts[i]); } } for (MultiDimIterator iter(otherDims); !iter.atEnd(); ++iter) { vector indices(dims.size() - 1);//we need to add the parcellated direction index back into the index list to use it in getRow/setRow for (int i = 0; i < (int)otherDims.size(); ++i) { if (i < direction - 1) { indices[i] = (*iter)[i]; } else { indices[i + 1] = (*iter)[i]; } }//indices[direction - 1] is uninitialized, as it is the dimension to be parcellated for (int i = 0; i < numParcels; ++i) { for (int j = 0; j < numCols; ++j) { parcelData[i][j].clear();//doesn't change allocation } } for (int64_t i = 0; i < dims[direction]; ++i) { int parcel = indexToParcel[i]; if (parcel != -1) { indices[direction - 1] = i; myCiftiIn->getRow(scratchRow.data(), indices); vector >& parcelRef = parcelData[parcel]; for (int j = 0; j < numCols; ++j) { if (isLabel) { parcelRef[j].push_back(floor(scratchRow[j] + 0.5f)); } else { parcelRef[j].push_back(scratchRow[j]); } } } } for (int i = 0; i < numParcels; ++i) { indices[direction - 1] = i; int64_t count = parcelCounts[i]; vector >& parcelRef = parcelData[i]; if (count > 0 && (method != ReductionEnum::SAMPSTDEV || count > 1)) { for (int j = 0; j < numCols; ++j) { CaretAssert((int64_t)parcelRef[j].size() == count); if (excludeLow > 0.0f && excludeHigh > 0.0f) { scratchOutRow[j] = ReductionOperation::reduceExcludeDev(parcelRef[j].data(), parcelRef[j].size(), method, excludeLow, excludeHigh); } else { if (onlyNumeric) { scratchOutRow[j] = ReductionOperation::reduceOnlyNumeric(parcelRef[j].data(), parcelRef[j].size(), method); } else { scratchOutRow[j] = ReductionOperation::reduce(parcelRef[j].data(), parcelRef[j].size(), method); } } } } else { for (int j = 0; j < numCols; ++j) { CaretAssert((int64_t)parcelRef[j].size() == count); if (isLabel) { if (labelDir == CiftiXML::ALONG_ROW) { scratchOutRow[j] = myOutXML.getLabelsMap(CiftiXML::ALONG_ROW).getMapLabelTable(j)->getUnassignedLabelKey(); } else { scratchOutRow[j] = myOutXML.getLabelsMap(labelDir).getMapLabelTable(indices[labelDir - 1])->getUnassignedLabelKey(); } } else { scratchOutRow[j] = emptyFillVal; } } } myCiftiOut->setRow(scratchOutRow.data(), indices); } } } } namespace { void doWeightedParcellation(const CiftiFile* myCiftiIn, const int& direction, CiftiFile* myCiftiOut, const vector& indexToParcel, const vector >& parcelWeights, const ReductionEnum::Enum& method, const float& excludeLow, const float& excludeHigh, const bool& onlyNumeric, const float& emptyFillVal, CiftiFile* emptyMaskOut) { const CiftiXML& myInputXML = myCiftiIn->getCiftiXML(); const CiftiXML& myOutXML = myCiftiOut->getCiftiXML(); vector dims = myInputXML.getDimensions(); CaretAssert(direction < (int)dims.size()); bool isLabel = false; int labelDir = -1; for (int i = 0; i < (int)dims.size(); ++i) { if (myInputXML.getMappingType(i) == CiftiMappingType::LABELS) { isLabel = true; labelDir = i; break;//there should never be more than one dimension with LABEL type, and if there is, just use the first one, i guess... } } if (isLabel && method != ReductionEnum::MODE) { CaretLogWarning(ReductionEnum::toName(method) + " reduction requested while parcellating label data"); } int numParcels = myOutXML.getDimensionLength(direction); if (emptyMaskOut != NULL) { CiftiXML maskOutXML; maskOutXML.setNumberOfDimensions(2); maskOutXML.setMap(CiftiXML::ALONG_COLUMN, myOutXML.getParcelsMap(direction)); CiftiScalarsMap maskNameMap; maskNameMap.setLength(1); maskNameMap.setMapName(0, "parcel not empty"); maskOutXML.setMap(CiftiXML::ALONG_ROW, maskNameMap); emptyMaskOut->setCiftiXML(maskOutXML); vector emptyMaskData(numParcels, 1.0f); for (int i = 0; i < numParcels; ++i) { if (parcelWeights[i].size() == 0) { emptyMaskData[i] = 0.0f; } } emptyMaskOut->setColumn(emptyMaskData.data(), 0); } int64_t numCols = myInputXML.getDimensionLength(CiftiXML::ALONG_ROW); vector scratchRow(numCols); if (direction == CiftiXML::ALONG_ROW) { vector scratchOutRow(numParcels); vector > parcelData(numParcels);//float so we can use ReductionOperation for (int j = 0; j < numParcels; ++j) { parcelData[j].reserve(parcelWeights[j].size()); } for (MultiDimIterator iter(vector(dims.begin() + 1, dims.end())); !iter.atEnd(); ++iter) { for (int j = 0; j < numParcels; ++j) { parcelData[j].clear();//doesn't change allocation } myCiftiIn->getRow(scratchRow.data(), *iter); for (int64_t j = 0; j < numCols; ++j) { int parcel = indexToParcel[j]; if (parcel != -1) { if (isLabel) { parcelData[parcel].push_back(floor(scratchRow[j] + 0.5f));//round to nearest integer to be safe } else { parcelData[parcel].push_back(scratchRow[j]); } } } for (int j = 0; j < numParcels; ++j) { CaretAssert(parcelWeights[j].size() == parcelData[j].size()); if (parcelData[j].size() > 0 && (method != ReductionEnum::SAMPSTDEV || parcelData[j].size() > 1)) { if (excludeLow > 0.0f && excludeHigh > 0.0f) { scratchOutRow[j] = ReductionOperation::reduceWeightedExcludeDev(parcelData[j].data(), parcelWeights[j].data(), parcelData[j].size(), method, excludeLow, excludeHigh); } else { if (onlyNumeric) { scratchOutRow[j] = ReductionOperation::reduceWeightedOnlyNumeric(parcelData[j].data(), parcelWeights[j].data(), parcelData[j].size(), method); } else { scratchOutRow[j] = ReductionOperation::reduceWeighted(parcelData[j].data(), parcelWeights[j].data(), parcelData[j].size(), method); } } } else {//labelDir can't be 0 (row) because we are parcellating along row, so row must be dense if (isLabel) { scratchOutRow[j] = myOutXML.getLabelsMap(labelDir).getMapLabelTable((*iter)[labelDir - 1])->getUnassignedLabelKey(); } else { scratchOutRow[j] = emptyFillVal; } } } myCiftiOut->setRow(scratchOutRow.data(), *iter); } } else { vector scratchOutRow(numCols); vector otherDims = dims; otherDims.erase(otherDims.begin() + direction);//direction being parcellated otherDims.erase(otherDims.begin());//row vector > > parcelData(numParcels, vector >(numCols));//float so we can use ReductionOperation for (int i = 0; i < numParcels; ++i) { for (int j = 0; j < numCols; ++j) { parcelData[i][j].reserve(parcelWeights[i].size()); } } for (MultiDimIterator iter(otherDims); !iter.atEnd(); ++iter) { vector indices(dims.size() - 1);//we need to add the parcellated direction index back into the index list to use it in getRow/setRow for (int i = 0; i < (int)otherDims.size(); ++i) { if (i < direction - 1) { indices[i] = (*iter)[i]; } else { indices[i + 1] = (*iter)[i]; } }//indices[direction - 1] is uninitialized, as it is the dimension to be parcellated for (int i = 0; i < numParcels; ++i) { for (int j = 0; j < numCols; ++j) { parcelData[i][j].clear();//doesn't change allocation } } for (int64_t i = 0; i < dims[direction]; ++i) { int parcel = indexToParcel[i]; if (parcel != -1) { indices[direction - 1] = i; myCiftiIn->getRow(scratchRow.data(), indices); vector >& parcelRef = parcelData[parcel]; for (int j = 0; j < numCols; ++j) { if (isLabel) { parcelRef[j].push_back(floor(scratchRow[j] + 0.5f)); } else { parcelRef[j].push_back(scratchRow[j]); } } } } for (int i = 0; i < numParcels; ++i) { indices[direction - 1] = i; int64_t count = (int64_t)parcelWeights[i].size(); vector >& parcelRef = parcelData[i]; if (count > 0 && (method != ReductionEnum::SAMPSTDEV || count > 1)) { for (int j = 0; j < numCols; ++j) { CaretAssert((int64_t)parcelRef[j].size() == count); if (excludeLow > 0.0f && excludeHigh > 0.0f) { scratchOutRow[j] = ReductionOperation::reduceWeightedExcludeDev(parcelRef[j].data(), parcelWeights[i].data(), parcelRef[j].size(), method, excludeLow, excludeHigh); } else { if (onlyNumeric) { scratchOutRow[j] = ReductionOperation::reduceWeightedOnlyNumeric(parcelRef[j].data(), parcelWeights[i].data(), parcelRef[j].size(), method); } else { scratchOutRow[j] = ReductionOperation::reduceWeighted(parcelRef[j].data(), parcelWeights[i].data(), parcelRef[j].size(), method); } } } } else { for (int j = 0; j < numCols; ++j) { CaretAssert((int64_t)parcelRef[j].size() == count); if (isLabel) { if (labelDir == CiftiXML::ALONG_ROW) { scratchOutRow[j] = myOutXML.getLabelsMap(CiftiXML::ALONG_ROW).getMapLabelTable(j)->getUnassignedLabelKey(); } else { scratchOutRow[j] = myOutXML.getLabelsMap(labelDir).getMapLabelTable(indices[labelDir - 1])->getUnassignedLabelKey(); } } else { scratchOutRow[j] = emptyFillVal; } } } myCiftiOut->setRow(scratchOutRow.data(), indices); } } } } } AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const CiftiFile* myCiftiLabel, const int& direction, CiftiFile* myCiftiOut, const MetricFile* leftWeights, const MetricFile* rightWeights, const MetricFile* cerebWeights, const ReductionEnum::Enum& method, const float& excludeLow, const float& excludeHigh, const bool& onlyNumeric, const bool& legacyMode, const float& emptyFillVal, CiftiFile* emptyMaskOut): AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CaretAssert(direction >= 0); const CiftiXML& myInputXML = myCiftiIn->getCiftiXML(); const CiftiXML& myLabelXML = myCiftiLabel->getCiftiXML(); vector dims = myInputXML.getDimensions(); if (direction >= (int)dims.size()) throw AlgorithmException("specified direction doesn't exist in input file"); if (myInputXML.getMappingType(direction) != CiftiMappingType::BRAIN_MODELS) { throw AlgorithmException("input cifti file does not have brain models mapping type in specified direction"); } if (myLabelXML.getNumberOfDimensions() != 2 || myLabelXML.getMappingType(CiftiXML::ALONG_ROW) != CiftiMappingType::LABELS || myLabelXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) { throw AlgorithmException("input cifti label file has the wrong mapping types"); } const CiftiBrainModelsMap& inputDense = myInputXML.getBrainModelsMap(direction); const CiftiBrainModelsMap& labelDense = myLabelXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); float voxelVolume = 1.0f; if (inputDense.hasVolumeData()) {//don't check volume space if direction doesn't have volume data if (labelDense.hasVolumeData() && !inputDense.getVolumeSpace().matches(labelDense.getVolumeSpace())) { throw AlgorithmException("input cifti files must have the same volume space"); } Vector3D ivec, jvec, kvec, origin;//compute the volume of a voxel in case a parcel spans both surface and volume inputDense.getVolumeSpace().getSpacingVectors(ivec, jvec, kvec, origin); voxelVolume = abs(ivec.dot(jvec.cross(kvec))); } vector surfStructs = inputDense.getSurfaceStructureList(); for (int i = 0; i < (int)surfStructs.size(); ++i) { const MetricFile* toCheck = NULL; switch (surfStructs[i]) { case StructureEnum::CORTEX_LEFT: toCheck = leftWeights; break; case StructureEnum::CORTEX_RIGHT: toCheck = rightWeights; break; case StructureEnum::CEREBELLUM: toCheck = cerebWeights; break; default: throw AlgorithmException("unsupported surface structure: " + StructureEnum::toName(surfStructs[i])); } if (toCheck == NULL) throw AlgorithmException("weight metric required but not provided for structure " + StructureEnum::toName(surfStructs[i])); if (toCheck->getNumberOfNodes() != inputDense.getSurfaceNumberOfNodes(surfStructs[i])) { throw AlgorithmException("weight metric has incorrect number of vertices for structure " + StructureEnum::toName(surfStructs[i])); } checkStructureMatch(toCheck, surfStructs[i], "weight metric", "it is provided as the argument for"); } vector indexToParcel; CiftiXML myOutXML = myInputXML; CiftiParcelsMap outParcelMap = parcellateMapping(myCiftiLabel, inputDense, indexToParcel, legacyMode); int numParcels = outParcelMap.getLength(); if (numParcels < 1) { throw AlgorithmException("no parcels found, output file would be empty, aborting"); } myOutXML.setMap(direction, outParcelMap); myCiftiOut->setCiftiXML(myOutXML); vector > parcelWeights(numParcels); for (int64_t j = 0; j < (int64_t)indexToParcel.size(); ++j) { int parcel = indexToParcel[j]; if (parcel != -1) { const CiftiBrainModelsMap::IndexInfo myDenseInfo = inputDense.getInfoForIndex(j); if (myDenseInfo.m_type == CiftiBrainModelsMap::VOXELS) { parcelWeights[parcel].push_back(voxelVolume); } else { const MetricFile* toUse = NULL; switch (myDenseInfo.m_structure) { case StructureEnum::CORTEX_LEFT: toUse = leftWeights; break; case StructureEnum::CORTEX_RIGHT: toUse = rightWeights; break; case StructureEnum::CEREBELLUM: toUse = cerebWeights; break; default: CaretAssert(0); } parcelWeights[parcel].push_back(toUse->getValue(myDenseInfo.m_surfaceNode, 0)); } } } doWeightedParcellation(myCiftiIn, direction, myCiftiOut, indexToParcel, parcelWeights, method, excludeLow, excludeHigh, onlyNumeric, emptyFillVal, emptyMaskOut); } AlgorithmCiftiParcellate::AlgorithmCiftiParcellate(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const CiftiFile* myCiftiLabel, const int& direction, CiftiFile* myCiftiOut, const CiftiFile* ciftiWeights, const ReductionEnum::Enum& method, const float& excludeLow, const float& excludeHigh, const bool& onlyNumeric, const bool& legacyMode, const float& emptyFillVal, CiftiFile* emptyMaskOut): AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CaretAssert(direction >= 0); const CiftiXML& myInputXML = myCiftiIn->getCiftiXML(); const CiftiXML& myLabelXML = myCiftiLabel->getCiftiXML(); const CiftiXML& weightsXML = ciftiWeights->getCiftiXML(); vector dims = myInputXML.getDimensions(); if (direction >= (int)dims.size()) throw AlgorithmException("specified direction doesn't exist in input file"); if (myInputXML.getMappingType(direction) != CiftiMappingType::BRAIN_MODELS) { throw AlgorithmException("input cifti file does not have brain models mapping type in specified direction"); } if (weightsXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) { throw AlgorithmException("cifti weight file does not have brain models along column"); } if (myLabelXML.getNumberOfDimensions() != 2 || myLabelXML.getMappingType(CiftiXML::ALONG_ROW) != CiftiMappingType::LABELS || myLabelXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) { throw AlgorithmException("input cifti label file has the wrong mapping types"); } const CiftiBrainModelsMap& inputDense = myInputXML.getBrainModelsMap(direction); const CiftiBrainModelsMap& labelDense = myLabelXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); const CiftiBrainModelsMap& weightsDense = weightsXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); vector surfModels = labelDense.getSurfaceStructureList(); for (int i = 0; i < int(surfModels.size()); ++i) { if (weightsDense.hasSurfaceData(surfModels[i])) { if (labelDense.getSurfaceNumberOfNodes(surfModels[i]) != weightsDense.getSurfaceNumberOfNodes(surfModels[i])) { throw AlgorithmException("cifti weight file has wrong number of vertices for surface structure " + StructureEnum::toName(surfModels[i])); } } } if (labelDense.hasVolumeData()) {//don't check volume space if direction doesn't have volume data if (inputDense.hasVolumeData() && !labelDense.getVolumeSpace().matches(inputDense.getVolumeSpace())) { throw AlgorithmException("input cifti file has a different volume space"); } if (weightsDense.hasVolumeData() && !labelDense.getVolumeSpace().matches(weightsDense.getVolumeSpace())) { throw AlgorithmException("cifti weight file has a different volume space"); } } vector indexToParcel; CiftiXML myOutXML = myInputXML; CiftiParcelsMap outParcelMap = parcellateMapping(myCiftiLabel, inputDense, indexToParcel, legacyMode); int numParcels = outParcelMap.getLength(); if (numParcels < 1) { throw AlgorithmException("no parcels found, output file would be empty, aborting"); } myOutXML.setMap(direction, outParcelMap); myCiftiOut->setCiftiXML(myOutXML); vector weightCol(weightsXML.getDimensionLength(CiftiXML::ALONG_COLUMN)); ciftiWeights->getColumn(weightCol.data(), 0); vector > parcelWeights(numParcels); for (int64_t j = 0; j < (int64_t)indexToParcel.size(); ++j) { int parcel = indexToParcel[j]; if (parcel != -1) { int weightIndex = -1; CiftiBrainModelsMap::IndexInfo myInfo = inputDense.getInfoForIndex(j); switch (myInfo.m_type) { case CiftiBrainModelsMap::SURFACE: weightIndex = weightsDense.getIndexForNode(myInfo.m_surfaceNode, myInfo.m_structure); break; case CiftiBrainModelsMap::VOXELS: weightIndex = weightsDense.getIndexForVoxel(myInfo.m_ijk); break; } if (weightIndex < 0) { throw AlgorithmException("cifti weights file does not contain all necessary vertices and voxels"); } parcelWeights[parcel].push_back(weightCol[weightIndex]); } } doWeightedParcellation(myCiftiIn, direction, myCiftiOut, indexToParcel, parcelWeights, method, excludeLow, excludeHigh, onlyNumeric, emptyFillVal, emptyMaskOut); } CiftiParcelsMap AlgorithmCiftiParcellate::parcellateMapping(const CiftiFile* myCiftiLabel, const CiftiBrainModelsMap& toParcellate, vector& indexToParcelOut, const bool& legacyMode) { const CiftiXML& myLabelXML = myCiftiLabel->getCiftiXML(); if (myLabelXML.getNumberOfDimensions() != 2 || myLabelXML.getMappingType(CiftiXML::ALONG_ROW) != CiftiMappingType::LABELS || myLabelXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) { throw AlgorithmException("AlgorithmCiftiParcellate::parcellateMapping requires a cifti dlabel file as input"); } const CiftiLabelsMap& myLabelsMap = myLabelXML.getLabelsMap(CiftiXML::ALONG_ROW); const CiftiBrainModelsMap& labelDenseMap = myLabelXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); CiftiParcelsMap ret; if (labelDenseMap.hasVolumeData() && toParcellate.hasVolumeData()) {//if only one has voxel data, don't error until we know it is used if(!toParcellate.getVolumeSpace().matches(labelDenseMap.getVolumeSpace())) { throw AlgorithmException("data file to parcellate has a different voxel space than the dlabel file"); } ret.setVolumeSpace(toParcellate.getVolumeSpace()); } const GiftiLabelTable* myLabelTable = myLabelsMap.getMapLabelTable(0); vector labelData(myLabelXML.getDimensionLength(CiftiXML::ALONG_COLUMN)); int unusedKey = myLabelTable->getUnassignedLabelKey(); myCiftiLabel->getColumn(labelData.data(), 0); indexToParcelOut.clear(); indexToParcelOut.resize(toParcellate.getLength(), -1); if (!legacyMode) {//by default, the parcel definitions are based only on the dlabel file const vector labelSurfList = labelDenseMap.getSurfaceStructureList(); const set allLabelKeys = myLabelTable->getKeys(); map keyToParcel; int32_t count = 0; vector parcelList; for (set::const_iterator iter = allLabelKeys.begin(); iter != allLabelKeys.end(); ++iter) { if (*iter != unusedKey) { keyToParcel[*iter] = count; parcelList.push_back(CiftiParcelsMap::Parcel()); parcelList.back().m_name = myLabelTable->getLabelName(*iter); ++count; } } for (int i = 0; i < (int)labelSurfList.size(); ++i) { StructureEnum::Enum myStruct = labelSurfList[i]; if (toParcellate.hasSurfaceData(myStruct)) {//if a surface is missing from the data, don't error until we know it is used by the parcellation if (labelDenseMap.getSurfaceNumberOfNodes(myStruct) != toParcellate.getSurfaceNumberOfNodes(myStruct)) {//if both have a surface, it must match throw AlgorithmException("mismatch in number of surface vertices between data and dlabel for structure " + StructureEnum::toName(myStruct)); } } ret.addSurface(labelDenseMap.getSurfaceNumberOfNodes(myStruct), myStruct); vector labelSurfMap = labelDenseMap.getSurfaceMap(myStruct); for (int64_t j = 0; j < (int64_t)labelSurfMap.size(); ++j) { int labelKey = (int)floor(labelData[labelSurfMap[j].m_ciftiIndex] + 0.5f); map::iterator found = keyToParcel.find(labelKey);//could be unlabeled, or wild key value if (found != keyToParcel.end()) { int32_t whichParcel = found->second; parcelList[whichParcel].m_surfaceNodes[myStruct].insert(labelSurfMap[j].m_surfaceNode); int64_t dataIndex = toParcellate.getIndexForNode(labelSurfMap[j].m_surfaceNode, myStruct); if (dataIndex < 0) { throw AlgorithmException("data file is missing vertex " + AString::number(labelSurfMap[j].m_surfaceNode) + " in structure " + StructureEnum::toName(myStruct) + ", which is used by label '" + parcelList[whichParcel].m_name + "'"); } indexToParcelOut[dataIndex] = whichParcel; } } } const vector labelVolMap = labelDenseMap.getFullVolumeMap(); for (int64_t i = 0; i < (int64_t)labelVolMap.size(); ++i) { int labelKey = (int)floor(labelData[labelVolMap[i].m_ciftiIndex] + 0.5f); map::iterator found = keyToParcel.find(labelKey);//could be unlabeled, or wild key value if (found != keyToParcel.end()) { int32_t whichParcel = found->second; parcelList[whichParcel].m_voxelIndices.insert(labelVolMap[i].m_ijk); int64_t dataIndex = toParcellate.getIndexForVoxel(labelVolMap[i].m_ijk); if (dataIndex < 0) { throw AlgorithmException("data file is missing voxel (" + AString::fromNumbers(labelVolMap[i].m_ijk, 3, ", ") + "), which is used by label '" + parcelList[whichParcel].m_name + "'"); } indexToParcelOut[dataIndex] = whichParcel; } } for (int i = 0; i < (int)parcelList.size(); ++i) { ret.addParcel(parcelList[i]); } } else {//legacy mode: parcels are defined by overlap between labels and the data ROI, any parcels that don't overlap any data are discarded vector surfList = toParcellate.getSurfaceStructureList(); map > usedKeys;//the keys from the label table that actually overlap with data in the input file for (int i = 0; i < (int)surfList.size(); ++i) { StructureEnum::Enum myStruct = surfList[i]; if (labelDenseMap.hasSurfaceData(myStruct)) {//if a surface is missing from the label file, don't error if (labelDenseMap.getSurfaceNumberOfNodes(myStruct) != toParcellate.getSurfaceNumberOfNodes(myStruct)) { throw AlgorithmException("mismatch in number of surface vertices between input and dlabel for structure " + StructureEnum::toName(myStruct)); } ret.addSurface(toParcellate.getSurfaceNumberOfNodes(myStruct), myStruct); vector surfMap = toParcellate.getSurfaceMap(myStruct); int64_t mapSize = (int64_t)surfMap.size(); for (int64_t j = 0; j < mapSize; ++j) { int64_t labelIndex = labelDenseMap.getIndexForNode(surfMap[j].m_surfaceNode, myStruct); if (labelIndex != -1) { int labelKey = (int)floor(labelData[labelIndex] + 0.5f); if (labelKey != unusedKey) { int tempVal = -1; map >::iterator iter = usedKeys.find(labelKey); if (iter == usedKeys.end()) { const GiftiLabel* myLabel = myLabelTable->getLabel(labelKey); if (myLabel != NULL)//ignore values that aren't in the label table { tempVal = usedKeys.size(); CiftiParcelsMap::Parcel tempParcel; tempParcel.m_name = myLabel->getName(); tempParcel.m_surfaceNodes[myStruct].insert(surfMap[j].m_surfaceNode); usedKeys[labelKey] = pair(tempParcel, tempVal); } } else { tempVal = iter->second.second; CiftiParcelsMap::Parcel& tempParcel = iter->second.first; tempParcel.m_surfaceNodes[myStruct].insert(surfMap[j].m_surfaceNode); } indexToParcelOut[surfMap[j].m_ciftiIndex] = tempVal;//we will remap these to be in order of label keys later } } } } } vector volMap = toParcellate.getFullVolumeMap(); for (int64_t i = 0; i < (int64_t)volMap.size(); ++i) { int64_t labelIndex = labelDenseMap.getIndexForVoxel(volMap[i].m_ijk); if (labelIndex != -1) { int labelKey = (int)floor(labelData[labelIndex] + 0.5f); if (labelKey != unusedKey) { int tempVal = -1; map >::iterator iter = usedKeys.find(labelKey); if (iter == usedKeys.end()) { const GiftiLabel* myLabel = myLabelTable->getLabel(labelKey); if (myLabel != NULL)//ignore values that aren't in the label table { tempVal = usedKeys.size(); CiftiParcelsMap::Parcel tempParcel; tempParcel.m_name = myLabel->getName(); tempParcel.m_voxelIndices.insert(VoxelIJK(volMap[i].m_ijk)); usedKeys[labelKey] = pair(tempParcel, tempVal); } } else { tempVal = iter->second.second; CiftiParcelsMap::Parcel& tempParcel = iter->second.first; tempParcel.m_voxelIndices.insert(VoxelIJK(volMap[i].m_ijk)); } indexToParcelOut[volMap[i].m_ciftiIndex] = tempVal;//we will remap these to be in order of label keys later } } } int numParcels = (int)usedKeys.size(); vector valRemap(numParcels, -1); int count = 0; for (map >::const_iterator iter = usedKeys.begin(); iter != usedKeys.end(); ++iter) { valRemap[iter->second.second] = count;//build a lookup from temp values to label key rank ret.addParcel(iter->second.first); ++count; } int64_t lookupSize = (int64_t)indexToParcelOut.size(); for (int64_t i = 0; i < lookupSize; ++i)//finally, remap the temporary values to the key order of the labels { if (indexToParcelOut[i] != -1) { indexToParcelOut[i] = valRemap[indexToParcelOut[i]]; } } } return ret; } float AlgorithmCiftiParcellate::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiParcellate::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiParcellate.h000066400000000000000000000070321360521144700256100ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_PARCELLATE_H__ #define __ALGORITHM_CIFTI_PARCELLATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "CiftiBrainModelsMap.h" #include "CiftiParcelsMap.h" #include "ReductionEnum.h" #include namespace caret { class AlgorithmCiftiParcellate : public AbstractAlgorithm { AlgorithmCiftiParcellate(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiParcellate(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const CiftiFile* myCiftiLabel, const int& direction, CiftiFile* myCiftiOut, const ReductionEnum::Enum& method = ReductionEnum::MEAN, const float& excludeLow = -1.0f, const float& excludeHigh = -1.0f, const bool& onlyNumeric = false, const bool& legacyMode = false, const float& emptyFillVal = 0.0f, CiftiFile* emptyMaskOut = NULL); AlgorithmCiftiParcellate(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const CiftiFile* myCiftiLabel, const int& direction, CiftiFile* myCiftiOut, const MetricFile* leftWeights, const MetricFile* rightWeights = NULL, const MetricFile* cerebWeights = NULL, const ReductionEnum::Enum& method = ReductionEnum::MEAN, const float& excludeLow = -1.0f, const float& excludeHigh = -1.0f, const bool& onlyNumeric = false, const bool& legacyMode = false, const float& emptyFillVal = 0.0f, CiftiFile* emptyMaskOut = NULL); AlgorithmCiftiParcellate(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const CiftiFile* myCiftiLabel, const int& direction, CiftiFile* myCiftiOut, const CiftiFile* ciftiWeights, const ReductionEnum::Enum& method = ReductionEnum::MEAN, const float& excludeLow = -1.0f, const float& excludeHigh = -1.0f, const bool& onlyNumeric = false, const bool& legacyMode = false, const float& emptyFillVal = 0.0f, CiftiFile* emptyMaskOut = NULL); static CiftiParcelsMap parcellateMapping(const CiftiFile* myCiftiLabel, const CiftiBrainModelsMap& toParcellate, std::vector& indexToParcelOut, const bool& legacyMode = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiParcellate; } #endif //__ALGORITHM_CIFTI_PARCELLATE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiROIsFromExtrema.cxx000066400000000000000000000466771360521144700271170ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiROIsFromExtrema.h" #include "AlgorithmException.h" #include "AlgorithmCiftiSeparate.h" #include "AlgorithmMetricROIsFromExtrema.h" #include "AlgorithmVolumeROIsFromExtrema.h" #include "CaretAssert.h" #include "CaretPointer.h" #include "CiftiFile.h" #include "MetricFile.h" #include "VolumeFile.h" #include "OverlapLogicEnum.h" #include "SurfaceFile.h" #include #include using namespace caret; using namespace std; AString AlgorithmCiftiROIsFromExtrema::getCommandSwitch() { return "-cifti-rois-from-extrema"; } AString AlgorithmCiftiROIsFromExtrema::getShortDescription() { return "CREATE CIFTI ROI MAPS FROM EXTREMA MAPS"; } OperationParameters* AlgorithmCiftiROIsFromExtrema::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti", "the input cifti"); ret->addDoubleParameter(2, "surf-limit", "geodesic distance limit from vertex, in mm"); ret->addDoubleParameter(3, "vol-limit", "euclidean distance limit from voxel center, in mm"); ret->addStringParameter(4, "direction", "which dimension an extrema map is along, ROW or COLUMN"); ret->addCiftiOutputParameter(5, "cifti-out", "the output cifti"); OptionalParameter* leftSurfOpt = ret->createOptionalParameter(6, "-left-surface", "specify the left surface to use"); leftSurfOpt->addSurfaceParameter(1, "surface", "the left surface file"); OptionalParameter* rightSurfOpt = ret->createOptionalParameter(7, "-right-surface", "specify the right surface to use"); rightSurfOpt->addSurfaceParameter(1, "surface", "the right surface file"); OptionalParameter* cerebSurfaceOpt = ret->createOptionalParameter(8, "-cerebellum-surface", "specify the cerebellum surface to use"); cerebSurfaceOpt->addSurfaceParameter(1, "surface", "the cerebellum surface file"); OptionalParameter* gaussOpt = ret->createOptionalParameter(9, "-gaussian", "generate gaussian kernels instead of flat ROIs"); gaussOpt->addDoubleParameter(1, "surf-sigma", "the sigma for the surface gaussian kernel, in mm"); gaussOpt->addDoubleParameter(2, "vol-sigma", "the sigma for the volume gaussian kernel, in mm"); OptionalParameter* overlapOpt = ret->createOptionalParameter(10, "-overlap-logic", "how to handle overlapping ROIs, default ALLOW"); overlapOpt->addStringParameter(1, "method", "the method of resolving overlaps"); ret->createOptionalParameter(11, "-merged-volume", "treat volume components as if they were a single component"); ret->setHelpText( AString("For each nonzero value in each map, make a map with an ROI around that location. ") + "If the -gaussian option is specified, then normalized gaussian kernels are output instead of ROIs. " + "The argument to -overlap-logic must be one of ALLOW, CLOSEST, or EXCLUDE. " + "ALLOW is the default, and means that ROIs are treated independently and may overlap. " + "CLOSEST means that ROIs may not overlap, and that no ROI contains vertices that are closer to a different seed vertex. " + "EXCLUDE means that ROIs may not overlap, and that any vertex within range of more than one ROI does not belong to any ROI." ); return ret; } void AlgorithmCiftiROIsFromExtrema::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* myCifti = myParams->getCifti(1); float surfLimit = (float)myParams->getDouble(2); float volLimit = (float)myParams->getDouble(3); AString directionName = myParams->getString(4); int myDir; if (directionName == "ROW") { myDir = CiftiXMLOld::ALONG_ROW; } else if (directionName == "COLUMN") { myDir = CiftiXMLOld::ALONG_COLUMN; } else { throw AlgorithmException("incorrect string for direction, use ROW or COLUMN"); } CiftiFile* myCiftiOut = myParams->getOutputCifti(5); SurfaceFile* myLeftSurf = NULL, *myRightSurf = NULL, *myCerebSurf = NULL; OptionalParameter* leftSurfOpt = myParams->getOptionalParameter(6); if (leftSurfOpt->m_present) { myLeftSurf = leftSurfOpt->getSurface(1); } OptionalParameter* rightSurfOpt = myParams->getOptionalParameter(7); if (rightSurfOpt->m_present) { myRightSurf = rightSurfOpt->getSurface(1); } OptionalParameter* cerebSurfOpt = myParams->getOptionalParameter(8); if (cerebSurfOpt->m_present) { myCerebSurf = cerebSurfOpt->getSurface(1); } float surfSigma = -1.0f, volSigma = -1.0f; OptionalParameter* gaussOpt = myParams->getOptionalParameter(9); if (gaussOpt->m_present) { surfSigma = (float)gaussOpt->getDouble(1); volSigma = (float)gaussOpt->getDouble(2); if (surfSigma <= 0.0f || volSigma <= 0.0f) { throw AlgorithmException("sigma values must be positive"); } } OverlapLogicEnum::Enum myLogic = OverlapLogicEnum::ALLOW; OptionalParameter* overlapOpt = myParams->getOptionalParameter(10); if (overlapOpt->m_present) { bool ok = false; myLogic = OverlapLogicEnum::fromName(overlapOpt->getString(1), &ok); if (!ok) { throw AlgorithmException("unrecognized overlap method"); } } bool mergedVolume = myParams->getOptionalParameter(11)->m_present; AlgorithmCiftiROIsFromExtrema(myProgObj, myCifti, surfLimit, volLimit, myDir, myCiftiOut, myLeftSurf, myRightSurf, myCerebSurf, surfSigma, volSigma, myLogic, mergedVolume); } AlgorithmCiftiROIsFromExtrema::AlgorithmCiftiROIsFromExtrema(ProgressObject* myProgObj, const CiftiFile* myCifti, const float& surfLimit, const float& volLimit, const int& myDir, CiftiFile* myCiftiOut, const SurfaceFile* myLeftSurf, const SurfaceFile* myRightSurf, const SurfaceFile* myCerebSurf, const float& surfSigma, const float& volSigma, const OverlapLogicEnum::Enum& myLogic, const bool& mergedVolume) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CiftiXMLOld myXML = myCifti->getCiftiXMLOld(); vector surfaceList, volumeList; if (myDir != CiftiXMLOld::ALONG_ROW && myDir != CiftiXMLOld::ALONG_COLUMN) throw AlgorithmException("direction not supported by cifti rois from extrema"); if (!myXML.getStructureLists(myDir, surfaceList, volumeList)) { throw AlgorithmException("columns do not contain brainordinates"); } for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) {//sanity check surfaces const SurfaceFile* mySurf = NULL; AString surfType; switch (surfaceList[whichStruct]) { case StructureEnum::CORTEX_LEFT: mySurf = myLeftSurf; surfType = "left"; break; case StructureEnum::CORTEX_RIGHT: mySurf = myRightSurf; surfType = "right"; break; case StructureEnum::CEREBELLUM: mySurf = myCerebSurf; surfType = "cerebellum"; break; default: throw AlgorithmException("found surface model with incorrect type: " + StructureEnum::toName(surfaceList[whichStruct])); break; } if (mySurf == NULL) { throw AlgorithmException(surfType + " surface required but not provided"); } if (mySurf->getNumberOfNodes() != myXML.getColumnSurfaceNumberOfNodes(surfaceList[whichStruct])) { throw AlgorithmException(surfType + " surface has the wrong number of vertices"); } } vector > surfROIs; vector > volROIs; vector volOffsets; int64_t mapCount = 0; for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) { const SurfaceFile* mySurf = NULL; switch (surfaceList[whichStruct]) { case StructureEnum::CORTEX_LEFT: mySurf = myLeftSurf; break; case StructureEnum::CORTEX_RIGHT: mySurf = myRightSurf; break; case StructureEnum::CEREBELLUM: mySurf = myCerebSurf; break; default: break; } MetricFile myMetric, myRoi, myMetricOut; AlgorithmCiftiSeparate(NULL, myCifti, myDir, surfaceList[whichStruct], &myMetric, &myRoi); surfROIs.push_back(CaretPointer(new MetricFile())); AlgorithmMetricROIsFromExtrema(NULL, mySurf, &myMetric, surfLimit, surfROIs.back(), surfSigma, &myRoi, myLogic); mapCount += surfROIs.back()->getNumberOfMaps(); } if (mergedVolume) { if (myCifti->getCiftiXMLOld().hasVolumeData(myDir)) { VolumeFile myVol, myRoi, myVolOut; volOffsets.resize(3); AlgorithmCiftiSeparate(NULL, myCifti, myDir, &myVol, volOffsets.data(), &myRoi, true);//without structure, it returns a combined volume volROIs.push_back(CaretPointer(new VolumeFile())); AlgorithmVolumeROIsFromExtrema(NULL, &myVol, volLimit, volROIs.back(), volSigma, &myRoi, myLogic); vector tempDims; volROIs.back()->getDimensions(tempDims); mapCount += tempDims[3];//because getNumberOfMaps only returns int32 } } else { volOffsets.resize(volumeList.size() * 3); for (int whichStruct = 0; whichStruct < (int)volumeList.size(); ++whichStruct) { VolumeFile myVol, myRoi, myVolOut; AlgorithmCiftiSeparate(NULL, myCifti, myDir, volumeList[whichStruct], &myVol, volOffsets.data() + 3 * whichStruct, &myRoi, true); volROIs.push_back(CaretPointer(new VolumeFile())); AlgorithmVolumeROIsFromExtrema(NULL, &myVol, volLimit, volROIs.back(), volSigma, &myRoi, myLogic); vector tempDims; volROIs.back()->getDimensions(tempDims); mapCount += tempDims[3];//because getNumberOfMaps only returns int32 } } if (mapCount == 0) throw AlgorithmException("no nonzero values in input cifti file"); if (mapCount > numeric_limits::max()) throw AlgorithmException("result has too many ROIs"); myXML.resetDirectionToScalars(1 - myDir, mapCount); myCiftiOut->setCiftiXML(myXML); if (myDir == CiftiXMLOld::ALONG_ROW) { int64_t curRow = 0; for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) { vector scratchrow(myXML.getNumberOfColumns(), 0.0f);//so that it is initially zeroed for each structure vector myMap; myXML.getSurfaceMap(myDir, myMap, surfaceList[whichStruct]); for (int i = 0; i < surfROIs[whichStruct]->getNumberOfColumns(); ++i) { const float* data = surfROIs[whichStruct]->getValuePointerForColumn(i); for (int j = 0; j < (int)myMap.size(); ++j) { scratchrow[myMap[j].m_ciftiIndex] = data[myMap[j].m_surfaceNode]; } myCiftiOut->setRow(scratchrow.data(), curRow); ++curRow; } } if (mergedVolume) { if (myXML.hasVolumeData(myDir)) { vector scratchrow(myXML.getNumberOfColumns(), 0.0f); vector myMap; myXML.getVolumeMap(myDir, myMap); vector tempDims; volROIs[0]->getDimensions(tempDims); for (int64_t b = 0; b < tempDims[3]; ++b) { for (int64_t j = 0; j < (int64_t)myMap.size(); ++j) { int64_t myijk[3] = { myMap[j].m_ijk[0] - volOffsets[0], myMap[j].m_ijk[1] - volOffsets[1], myMap[j].m_ijk[2] - volOffsets[2] }; scratchrow[myMap[j].m_ciftiIndex] = volROIs[0]->getValue(myijk, b); } myCiftiOut->setRow(scratchrow.data(), curRow); ++curRow; } } } else { for (int whichStruct = 0; whichStruct < (int)volumeList.size(); ++whichStruct) { vector scratchrow(myXML.getNumberOfColumns(), 0.0f); vector myMap; myXML.getVolumeStructureMapForRows(myMap, volumeList[whichStruct]); vector tempDims; volROIs[whichStruct]->getDimensions(tempDims); for (int64_t b = 0; b < tempDims[3]; ++b) { for (int64_t j = 0; j < (int64_t)myMap.size(); ++j) { int64_t myijk[3] = { myMap[j].m_ijk[0] - volOffsets[whichStruct * 3], myMap[j].m_ijk[1] - volOffsets[whichStruct * 3 + 1], myMap[j].m_ijk[2] - volOffsets[whichStruct * 3 + 2] }; scratchrow[myMap[j].m_ciftiIndex] = volROIs[whichStruct]->getValue(myijk, b); } myCiftiOut->setRow(scratchrow.data(), curRow); ++curRow; } } } } else { vector surfaceStart, volumeStart; int64_t mystart = 0; for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) { surfaceStart.push_back(mystart); mystart += surfROIs[whichStruct]->getNumberOfMaps(); } if (mergedVolume) { volumeStart.push_back(mystart); } else { for (int whichStruct = 0; whichStruct < (int)volumeList.size(); ++whichStruct) { volumeStart.push_back(mystart); vector tempDims; volROIs[whichStruct]->getDimensions(tempDims); mystart += tempDims[3]; } } int64_t curRow = 0; while (curRow < myXML.getNumberOfRows()) { bool found = false; for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) { vector myMap; myXML.getSurfaceMap(myDir, myMap, surfaceList[whichStruct]); if (myMap.size() > 0 && myMap[0].m_ciftiIndex == curRow)//NOTE: cifti indexes in structure maps are always linear ascending { vector scratchrow(myXML.getNumberOfColumns(), 0.0f); for (int64_t j = 0; j < (int64_t)myMap.size(); ++j) { CaretAssert(curRow == myMap[j].m_ciftiIndex); for (int k = 0; k < surfROIs[whichStruct]->getNumberOfColumns(); ++k) { scratchrow[surfaceStart[whichStruct] + k] = surfROIs[whichStruct]->getValue(myMap[j].m_surfaceNode, k); } myCiftiOut->setRow(scratchrow.data(), curRow); ++curRow; } found = true; break; } } if (!found) { if (mergedVolume) { for (int whichStruct = 0; whichStruct < (int)volumeList.size(); ++whichStruct)//NOTE: merged map may not be in ascending order, or contiguous, so don't use it { vector myMap; myXML.getVolumeStructureMapForColumns(myMap, volumeList[whichStruct]); if (myMap.size() > 0 && myMap[0].m_ciftiIndex == curRow) { vector tempDims; volROIs[0]->getDimensions(tempDims); vector scratchrow(myXML.getNumberOfColumns(), 0.0f); for (int64_t j = 0; j < (int64_t)myMap.size(); ++j) { CaretAssert(curRow == myMap[j].m_ciftiIndex); int64_t myijk[3] = { myMap[j].m_ijk[0] - volOffsets[0], myMap[j].m_ijk[1] - volOffsets[1], myMap[j].m_ijk[2] - volOffsets[2] }; for (int64_t b = 0; b < tempDims[3]; ++b) { scratchrow[volumeStart[0] + b] = volROIs[0]->getValue(myijk, b); } myCiftiOut->setRow(scratchrow.data(), curRow); ++curRow; } found = true; break; } } } else { for (int whichStruct = 0; whichStruct < (int)volumeList.size(); ++whichStruct) { vector myMap; myXML.getVolumeStructureMapForColumns(myMap, volumeList[whichStruct]); vector tempDims; volROIs[whichStruct]->getDimensions(tempDims); if (myMap.size() > 0 && myMap[0].m_ciftiIndex == curRow) { vector scratchrow(myXML.getNumberOfColumns(), 0.0f); for (int64_t j = 0; j < (int64_t)myMap.size(); ++j) { CaretAssert(curRow == myMap[j].m_ciftiIndex); int64_t myijk[3] = { myMap[j].m_ijk[0] - volOffsets[whichStruct * 3], myMap[j].m_ijk[1] - volOffsets[whichStruct * 3 + 1], myMap[j].m_ijk[2] - volOffsets[whichStruct * 3 + 2] }; for (int64_t b = 0; b < tempDims[3]; ++b) { scratchrow[volumeStart[whichStruct] + b] = volROIs[whichStruct]->getValue(myijk, b); } myCiftiOut->setRow(scratchrow.data(), curRow); ++curRow; } found = true; break; } } } } CaretAssert(found); } } } float AlgorithmCiftiROIsFromExtrema::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiROIsFromExtrema::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiROIsFromExtrema.h000066400000000000000000000042151360521144700265220ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_ROIS_FROM_EXTREMA_H__ #define __ALGORITHM_CIFTI_ROIS_FROM_EXTREMA_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "OverlapLogicEnum.h" namespace caret { class AlgorithmCiftiROIsFromExtrema : public AbstractAlgorithm { AlgorithmCiftiROIsFromExtrema(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiROIsFromExtrema(ProgressObject* myProgObj, const CiftiFile* myCifti, const float& surfLimit, const float& volLimit, const int& myDir, CiftiFile* myCiftiOut, const SurfaceFile* myLeftSurf = NULL, const SurfaceFile* myRightSurf = NULL, const SurfaceFile* myCerebSurf = NULL, const float& surfSigma = -1.0f, const float& volSigma = -1.0f, const OverlapLogicEnum::Enum& myLogic = OverlapLogicEnum::ALLOW, const bool& mergedVolume = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiROIsFromExtrema; } #endif //__ALGORITHM_CIFTI_ROIS_FROM_EXTREMA_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiReduce.cxx000066400000000000000000000250041360521144700253150ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiReduce.h" #include "AlgorithmException.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CiftiFile.h" #include "MultiDimIterator.h" #include "ReductionOperation.h" #include using namespace caret; using namespace std; AString AlgorithmCiftiReduce::getCommandSwitch() { return "-cifti-reduce"; } AString AlgorithmCiftiReduce::getShortDescription() { return "PERFORM REDUCTION OPERATION ON A CIFTI FILE"; } OperationParameters* AlgorithmCiftiReduce::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-in", "the cifti file to reduce"); ret->addStringParameter(2, "operation", "the reduction operator to use"); ret->addCiftiOutputParameter(3, "cifti-out", "the output cifti file"); OptionalParameter* directionOpt = ret->createOptionalParameter(6, "-direction", "specify what direction to reduce along"); directionOpt->addStringParameter(1, "direction", "the direction (default ROW)"); OptionalParameter* excludeOpt = ret->createOptionalParameter(4, "-exclude-outliers", "exclude non-numeric values and outliers by standard deviation"); excludeOpt->addDoubleParameter(1, "sigma-below", "number of standard deviations below the mean to include"); excludeOpt->addDoubleParameter(2, "sigma-above", "number of standard deviations above the mean to include"); ret->createOptionalParameter(5, "-only-numeric", "exclude non-numeric values"); ret->setHelpText( AString("For the specified direction (default ROW), perform a reduction operation along that direction. ") + CiftiXML::directionFromStringExplanation() + " " + "The reduction operators are as follows:\n\n" + ReductionOperation::getHelpInfo() ); return ret; } void AlgorithmCiftiReduce::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* ciftiIn = myParams->getCifti(1); AString opString = myParams->getString(2); CiftiFile* ciftiOut = myParams->getOutputCifti(3); int direction = CiftiXML::ALONG_ROW; OptionalParameter* directionOpt = myParams->getOptionalParameter(6); if (directionOpt->m_present) { direction = CiftiXML::directionFromString(directionOpt->getString(1));//does error checking, throws with message on error } OptionalParameter* excludeOpt = myParams->getOptionalParameter(4); bool onlyNumeric = myParams->getOptionalParameter(5)->m_present; bool ok = false; ReductionEnum::Enum myReduce = ReductionEnum::fromName(opString, &ok); if (!ok) throw AlgorithmException("unrecognized operation string '" + opString + "'"); if (excludeOpt->m_present) { if (onlyNumeric) CaretLogWarning("-only-numeric is redundant when -exclude-outliers is specified"); AlgorithmCiftiReduce(myProgObj, ciftiIn, myReduce, ciftiOut, excludeOpt->getDouble(1), excludeOpt->getDouble(2), direction); } else { AlgorithmCiftiReduce(myProgObj, ciftiIn, myReduce, ciftiOut, onlyNumeric, direction); } } AlgorithmCiftiReduce::AlgorithmCiftiReduce(ProgressObject* myProgObj, const CiftiFile* ciftiIn, const ReductionEnum::Enum& myReduce, CiftiFile* ciftiOut, const bool& onlyNumeric, const int& direction) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CaretAssert(direction >= 0); const CiftiXML& inputXML = ciftiIn->getCiftiXML(); CiftiXML myOutXML = inputXML; if (direction >= myOutXML.getNumberOfDimensions()) throw AlgorithmException("specified reduction direction doesn't exist in input cifti file"); CiftiScalarsMap newMap; newMap.setLength(1); newMap.setMapName(0, ReductionEnum::toName(myReduce)); myOutXML.setMap(direction, newMap); ciftiOut->setCiftiXML(myOutXML); vector inDims = inputXML.getDimensions(); if (direction == CiftiXML::ALONG_ROW) { if (inDims[0] == 1) { CaretLogWarning("-cifti-reduce is being used for a length=1 reduction on file '" + ciftiIn->getFileName() + "'"); } vector scratchInRow(inDims[0]); for (MultiDimIterator iter(vector(inDims.begin() + 1, inDims.end())); !iter.atEnd(); ++iter) {// + 1 to exclude row dimension, because getRow/setRow ciftiIn->getRow(scratchInRow.data(), *iter); float result = -1; if (onlyNumeric) { result = ReductionOperation::reduceOnlyNumeric(scratchInRow.data(), inDims[0], myReduce); } else { result = ReductionOperation::reduce(scratchInRow.data(), inDims[0], myReduce); } ciftiOut->setRow(&result, *iter);//if reducing along row, length of output row is 1 } } else { if (inDims[direction] == 1) { CaretLogWarning("-cifti-reduce is being used for a length=1 reduction on file '" + ciftiIn->getFileName() + "'"); } vector > scratchInRows(inDims[direction], vector(inDims[0])); vector outRow(inDims[0]), reduceScratch(inDims[direction]);//reduction isn't along row, so out rows will be same length as in rows vector otherDims = inDims; otherDims.erase(otherDims.begin() + direction);//direction isn't 0 otherDims.erase(otherDims.begin());//remove row direction because getRow/setRow for (MultiDimIterator iter(otherDims); !iter.atEnd(); ++iter) { vector indexvec = *iter; indexvec.insert(indexvec.begin() + direction - 1, -1);//dummy value in place of reduce direction for (int64_t i = 0; i < inDims[direction]; ++i) { indexvec[direction - 1] = i; ciftiIn->getRow(scratchInRows[i].data(), indexvec); } for (int64_t i = 0; i < inDims[0]; ++i) { for (int64_t j = 0; j < inDims[direction]; ++j) {//need reduction input in contiguous array reduceScratch[j] = scratchInRows[j][i]; } if (onlyNumeric) { outRow[i] = ReductionOperation::reduceOnlyNumeric(reduceScratch.data(), inDims[direction], myReduce); } else { outRow[i] = ReductionOperation::reduce(reduceScratch.data(), inDims[direction], myReduce); } } indexvec[direction - 1] = 0;//only one element along reduce output direction ciftiOut->setRow(outRow.data(), indexvec); } } } AlgorithmCiftiReduce::AlgorithmCiftiReduce(ProgressObject* myProgObj, const CiftiFile* ciftiIn, const ReductionEnum::Enum& myReduce, CiftiFile* ciftiOut, const float& sigmaBelow, const float& sigmaAbove, const int& direction) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CaretAssert(direction >= 0); const CiftiXML& inputXML = ciftiIn->getCiftiXML(); CiftiXML myOutXML = inputXML; if (direction >= myOutXML.getNumberOfDimensions()) throw AlgorithmException("specified reduction direction doesn't exist in input cifti file"); CiftiScalarsMap newMap; newMap.setLength(1); newMap.setMapName(0, ReductionEnum::toName(myReduce)); myOutXML.setMap(direction, newMap); ciftiOut->setCiftiXML(myOutXML); vector inDims = inputXML.getDimensions(); if (direction == CiftiXML::ALONG_ROW) { vector scratchInRow(inDims[0]); for (MultiDimIterator iter(vector(inDims.begin() + 1, inDims.end())); !iter.atEnd(); ++iter) {// + 1 to exclude row dimension, because getRow/setRow ciftiIn->getRow(scratchInRow.data(), *iter); float result = ReductionOperation::reduceExcludeDev(scratchInRow.data(), inDims[0], myReduce, sigmaBelow, sigmaAbove); ciftiOut->setRow(&result, *iter);//if reducing along row, length of output row is 1 } } else { vector > scratchInRows(inDims[direction], vector(inDims[0])); vector outRow(inDims[0]), reduceScratch(inDims[direction]);//reduction isn't along row, so out rows will be same length as in rows vector otherDims = inDims; otherDims.erase(otherDims.begin() + direction);//direction isn't 0 otherDims.erase(otherDims.begin());//remove row direction because getRow/setRow for (MultiDimIterator iter(otherDims); !iter.atEnd(); ++iter) { vector indexvec = *iter; indexvec.insert(indexvec.begin() + direction - 1, -1);//dummy value in place of reduce direction for (int64_t i = 0; i < inDims[direction]; ++i) { indexvec[direction - 1] = i; ciftiIn->getRow(scratchInRows[i].data(), indexvec); } for (int64_t i = 0; i < inDims[0]; ++i) { for (int64_t j = 0; j < inDims[direction]; ++j) {//need reduction input in contiguous array reduceScratch[j] = scratchInRows[j][i]; } outRow[i] = ReductionOperation::reduceExcludeDev(reduceScratch.data(), inDims[direction], myReduce, sigmaBelow, sigmaAbove); } indexvec[direction - 1] = 0;//only one element along reduce output direction ciftiOut->setRow(outRow.data(), indexvec); } } } float AlgorithmCiftiReduce::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiReduce::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiReduce.h000066400000000000000000000041031360521144700247370ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_REDUCE_H__ #define __ALGORITHM_CIFTI_REDUCE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "CiftiXML.h" #include "ReductionEnum.h" namespace caret { class AlgorithmCiftiReduce : public AbstractAlgorithm { AlgorithmCiftiReduce(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiReduce(ProgressObject* myProgObj, const CiftiFile* ciftiIn, const ReductionEnum::Enum& myReduce, CiftiFile* ciftiOut, const bool& onlyNumeric = false, const int& direction = CiftiXML::ALONG_ROW); AlgorithmCiftiReduce(ProgressObject* myProgObj, const CiftiFile* ciftiIn, const ReductionEnum::Enum& myReduce, CiftiFile* ciftiOut, const float& sigmaBelow, const float& sigmaAbove, const int& direction = CiftiXML::ALONG_ROW); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiReduce; } #endif //__ALGORITHM_CIFTI_REDUCE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiReorder.cxx000066400000000000000000000172451360521144700255200ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiReorder.h" #include "AlgorithmException.h" #include "CiftiFile.h" #include "FileInformation.h" #include "GiftiLabelTable.h" #include "PaletteColorMapping.h" #include using namespace caret; using namespace std; AString AlgorithmCiftiReorder::getCommandSwitch() { return "-cifti-reorder"; } AString AlgorithmCiftiReorder::getShortDescription() { return "REORDER THE PARCELS OR SCALAR/LABEL MAPS IN A CIFTI FILE"; } OperationParameters* AlgorithmCiftiReorder::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-in", "input cifti file"); ret->addStringParameter(2, "direction", "which dimension to reorder along, ROW or COLUMN"); ret->addStringParameter(3, "reorder-list", "a text file containing the desired order transformation"); ret->addCiftiOutputParameter(4, "cifti-out", "the reordered cifti file"); ret->setHelpText( AString("The mapping along the specified direction must be parcels, scalars, or labels. ") + "For pscalar or ptseries, use COLUMN to reorder the parcels. " + "For dlabel, use ROW. " + "The file must contain 1-based indices separated by whitespace (spaces, newlines, tabs, etc), with as many indices as has along the specified dimension. " + "These indices specify which current index should end up in that position, for instance, if the current order is 'A B C D', and the desired order is 'D A B C', the text file " + "should contain '4 1 2 3'." ); return ret; } void AlgorithmCiftiReorder::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* myCifti = myParams->getCifti(1); AString directionName = myParams->getString(2); int myDir; if (directionName == "ROW") { myDir = CiftiXMLOld::ALONG_ROW; } else if (directionName == "COLUMN") { myDir = CiftiXMLOld::ALONG_COLUMN; } else { throw AlgorithmException("incorrect string for direction, use ROW or COLUMN"); } AString listFileName = myParams->getString(3); CiftiFile* myCiftiOut = myParams->getOutputCifti(4); FileInformation textFileInfo(listFileName); if (!textFileInfo.exists()) { throw AlgorithmException("name list file doesn't exist"); } fstream listFile(listFileName.toLocal8Bit().constData(), fstream::in); if (!listFile.good()) { throw AlgorithmException("error reading name list file"); } vector reorder; int64_t temp; while (listFile >> temp) { reorder.push_back(temp - 1); } AlgorithmCiftiReorder(myProgObj, myCifti, myDir, reorder, myCiftiOut); } AlgorithmCiftiReorder::AlgorithmCiftiReorder(ProgressObject* myProgObj, const CiftiFile* myCifti, const int& myDir, const vector& reorder, CiftiFile* myCiftiOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const CiftiXMLOld& myXML = myCifti->getCiftiXMLOld(); CiftiXMLOld myOutXML = myXML; int64_t rowSize = myXML.getNumberOfColumns(), colSize = myXML.getNumberOfRows(), myDirSize; if (myDir == CiftiXMLOld::ALONG_ROW) { myDirSize = rowSize; } else if (myDir == CiftiXMLOld::ALONG_COLUMN) { myDirSize = colSize; } else { throw AlgorithmException("direction not supported by cifti reorder"); } if ((int64_t)reorder.size() != myDirSize) throw AlgorithmException("reorder list has incorrect size, expected " + AString::number(myDirSize) + ", got " + AString::number(reorder.size())); vector used(myDirSize, false); for (int64_t i = 0; i < myDirSize; ++i) { int64_t val = reorder[i]; if (val < 0 || val >= myDirSize) throw AlgorithmException("invalid index in reorder list"); if (used[val]) throw AlgorithmException("index specified more than once in reorder list"); used[val] = true; } IndicesMapToDataType myType = myXML.getMappingType(myDir); switch (myType) { case CIFTI_INDEX_TYPE_SCALARS: { for (int64_t i = 0; i < myDirSize; ++i) { myOutXML.setMapNameForIndex(myDir, i, myXML.getMapName(myDir, reorder[i])); *(myOutXML.getMapPalette(myDir, i)) = *(myXML.getMapPalette(myDir, reorder[i])); *(myOutXML.getMapMetadata(myDir, i)) = *(myXML.getMapMetadata(myDir, reorder[i])); } break; } case CIFTI_INDEX_TYPE_LABELS: { for (int64_t i = 0; i < myDirSize; ++i) { myOutXML.setMapNameForIndex(myDir, i, myXML.getMapName(myDir, reorder[i])); *(myOutXML.getMapLabelTable(myDir, i)) = *(myXML.getMapLabelTable(myDir, reorder[i])); *(myOutXML.getMapMetadata(myDir, i)) = *(myXML.getMapMetadata(myDir, reorder[i])); } break; } case CIFTI_INDEX_TYPE_PARCELS: { myOutXML.resetDirectionToParcels(myDir); vector mySurfs; myXML.getParcelSurfaceStructures(myDir, mySurfs); for (int i = 0; i < (int)mySurfs.size(); ++i) { myOutXML.addParcelSurface(myDir, myXML.getSurfaceNumberOfNodes(myDir, mySurfs[i]), mySurfs[i]); } vector origParcels; myXML.getParcels(myDir, origParcels); for (int64_t i = 0; i < myDirSize; ++i) { myOutXML.addParcel(myDir, origParcels[reorder[i]]); } break; } default: throw AlgorithmException("mapping along specified direction must be scalars, labels, or parcels"); } myCiftiOut->setCiftiXML(myOutXML); vector scratchrow(rowSize); switch (myDir) { case CiftiXMLOld::ALONG_ROW: { vector scratchrow2(rowSize); for (int64_t i = 0; i < colSize; ++i) { myCifti->getRow(scratchrow.data(), i); for (int64_t j = 0; j < rowSize; ++j) { scratchrow2[j] = scratchrow[reorder[j]]; } myCiftiOut->setRow(scratchrow2.data(), i); } break; } case CiftiXMLOld::ALONG_COLUMN: { for (int64_t i = 0; i < colSize; ++i) { myCifti->getRow(scratchrow.data(), reorder[i]); myCiftiOut->setRow(scratchrow.data(), i); } break; } default: CaretAssert(false); } } float AlgorithmCiftiReorder::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiReorder::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiReorder.h000066400000000000000000000033171360521144700251400ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_REORDER_H__ #define __ALGORITHM_CIFTI_REORDER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include namespace caret { class AlgorithmCiftiReorder : public AbstractAlgorithm { AlgorithmCiftiReorder(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiReorder(ProgressObject* myProgObj, const CiftiFile* myCifti, const int& myDir, const std::vector& reorder, CiftiFile* myCiftiOut); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiReorder; } #endif //__ALGORITHM_CIFTI_REORDER_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiReplaceStructure.cxx000066400000000000000000001066221360521144700274100ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiReplaceStructure.h" //for computing the cropped volume space #include "AlgorithmCiftiSeparate.h" #include "AlgorithmException.h" #include "CaretPointer.h" #include "CiftiFile.h" #include "GiftiLabelTable.h" #include "LabelFile.h" #include "MetricFile.h" #include "Vector3D.h" #include "VolumeFile.h" #include #include using namespace caret; using namespace std; AString AlgorithmCiftiReplaceStructure::getCommandSwitch() { return "-cifti-replace-structure"; } AString AlgorithmCiftiReplaceStructure::getShortDescription() { return "REPLACE DATA IN A STRUCTURE IN A CIFTI FILE"; } OperationParameters* AlgorithmCiftiReplaceStructure::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "cifti", "the cifti to modify");//see useParameters for why this is a string ret->addStringParameter(2, "direction", "which dimension to interpret as a single map, ROW or COLUMN"); ParameterComponent* labelOpt = ret->createRepeatableParameter(3, "-label", "replace the data in a surface label component"); labelOpt->addStringParameter(1, "structure", "the structure to replace the data of"); labelOpt->addLabelParameter(2, "label", "the input label file"); ParameterComponent* metricOpt = ret->createRepeatableParameter(4, "-metric", "replace the data in a surface component"); metricOpt->addStringParameter(1, "structure", "the structure to replace the data of"); metricOpt->addMetricParameter(2, "metric", "the input metric"); ParameterComponent* volumeOpt = ret->createRepeatableParameter(5, "-volume", "replace the data in a volume component"); volumeOpt->addStringParameter(1, "structure", "the structure to replace the data of"); volumeOpt->addVolumeParameter(2, "volume", "the input volume"); volumeOpt->createOptionalParameter(3, "-from-cropped", "the input is cropped to the size of the component"); OptionalParameter* volumeAllOpt = ret->createOptionalParameter(6, "-volume-all", "replace the data in all volume components"); volumeAllOpt->addVolumeParameter(1, "volume", "the input volume"); volumeAllOpt->createOptionalParameter(2, "-from-cropped", "the input is cropped to the size of the data"); ret->createOptionalParameter(7, "-discard-unused-labels", "when operating on a dlabel file, drop any unused label keys from the label table"); AString helpText = AString("You must specify at least one of -metric, -label, -volume, or -volume-all for this command to do anything. ") + "Input volumes must line up with the output of -cifti-separate. " + "For dtseries/dscalar, use COLUMN, and if your matrix will be fully symmetric, COLUMN is more efficient. " + "The structure argument must be one of the following:\n"; vector myStructureEnums; StructureEnum::getAllEnums(myStructureEnums); for (int i = 0; i < (int)myStructureEnums.size(); ++i) { helpText += "\n" + StructureEnum::toName(myStructureEnums[i]); } ret->setHelpText(helpText); return ret; } void AlgorithmCiftiReplaceStructure::useParameters(OperationParameters* myParams, ProgressObject* /*myProgObj*/) { AString ciftiName = myParams->getString(1); CiftiFile myCifti(ciftiName);//CiftiFile currently doesn't expose the filename it is using, and we need to call writeFile manually (since the parsing framework doesn't expect an input to be modified) AString dirName = myParams->getString(2);//as for why it needs to modify an input, that is the only way it is useful for things like -cifti-smoothing int myDir; if (dirName == "ROW") { myDir = CiftiXML::ALONG_ROW; } else if (dirName == "COLUMN") { myDir = CiftiXML::ALONG_COLUMN; } else { throw AlgorithmException("incorrect string for direction, use ROW or COLUMN"); } bool discardUnusedLabels = myParams->getOptionalParameter(7)->m_present; const vector& labelInst = *(myParams->getRepeatableParameterInstances(3)); for (int i = 0; i < (int)labelInst.size(); ++i) { AString structName = labelInst[i]->getString(1); bool ok = false; StructureEnum::Enum myStruct = StructureEnum::fromName(structName, &ok); if (!ok) { throw AlgorithmException("unrecognized structure name"); } LabelFile* labelIn = labelInst[i]->getLabel(2); AlgorithmCiftiReplaceStructure(NULL, &myCifti, myDir, myStruct, labelIn, discardUnusedLabels); } const vector& metricInst = *(myParams->getRepeatableParameterInstances(4)); for (int i = 0; i < (int)metricInst.size(); ++i) { AString structName = metricInst[i]->getString(1); bool ok = false; StructureEnum::Enum myStruct = StructureEnum::fromName(structName, &ok); if (!ok) { throw AlgorithmException("unrecognized structure name"); } MetricFile* metricIn = metricInst[i]->getMetric(2); AlgorithmCiftiReplaceStructure(NULL, &myCifti, myDir, myStruct, metricIn); } const vector& volumeInst = *(myParams->getRepeatableParameterInstances(5)); for (int i = 0; i < (int)volumeInst.size(); ++i) { AString structName = volumeInst[i]->getString(1); bool ok = false; StructureEnum::Enum myStruct = StructureEnum::fromName(structName, &ok); if (!ok) { throw AlgorithmException("unrecognized structure name"); } VolumeFile* volIn = volumeInst[i]->getVolume(2); bool fromCropVol = volumeInst[i]->getOptionalParameter(3)->m_present; AlgorithmCiftiReplaceStructure(NULL, &myCifti, myDir, myStruct, volIn, fromCropVol, discardUnusedLabels); } OptionalParameter* volumeAllOpt = myParams->getOptionalParameter(6); if (volumeAllOpt->m_present) { VolumeFile* volIn = volumeAllOpt->getVolume(1); bool fromCropVol = volumeAllOpt->getOptionalParameter(2)->m_present; AlgorithmCiftiReplaceStructure(NULL, &myCifti, myDir, volIn, fromCropVol, discardUnusedLabels); } myCifti.writeFile(ciftiName);//and write the modified file } AlgorithmCiftiReplaceStructure::AlgorithmCiftiReplaceStructure(ProgressObject* myProgObj, CiftiFile* ciftiInOut, const int& myDir, const StructureEnum::Enum& myStruct, const MetricFile* metricIn) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const CiftiXML& myXML = ciftiInOut->getCiftiXML(); if (myXML.getNumberOfDimensions() != 2) throw AlgorithmException("replace structure only supported on 2D cifti"); if (myXML.getMappingType(myDir) != CiftiMappingType::BRAIN_MODELS) throw AlgorithmException("specified dimension must contain brain models"); const CiftiBrainModelsMap& myDenseMap = myXML.getBrainModelsMap(myDir); vector myMap; int rowSize = ciftiInOut->getNumberOfColumns(), colSize = ciftiInOut->getNumberOfRows(); if (myDir == CiftiXML::ALONG_COLUMN) { myMap = myDenseMap.getSurfaceMap(myStruct); int64_t numNodes = myDenseMap.getSurfaceNumberOfNodes(myStruct); if (metricIn->getNumberOfNodes() != numNodes) { throw AlgorithmException("input metric has the wrong number of vertices"); } if (metricIn->getNumberOfColumns() != rowSize) { throw AlgorithmException("input metric has the wrong number of columns"); } int mapSize = (int)myMap.size(); CaretArray rowScratch(rowSize); for (int i = 0; i < mapSize; ++i) { for (int j = 0; j < rowSize; ++j) { rowScratch[j] = metricIn->getValue(myMap[i].m_surfaceNode, j); } ciftiInOut->setRow(rowScratch, myMap[i].m_ciftiIndex); } } else { if (myDir != CiftiXML::ALONG_ROW) throw AlgorithmException("unsupported cifti direction"); myMap = myDenseMap.getSurfaceMap(myStruct); int64_t numNodes = myDenseMap.getSurfaceNumberOfNodes(myStruct); if (metricIn->getNumberOfNodes() != numNodes) { throw AlgorithmException("input metric has the wrong number of vertices"); } if (metricIn->getNumberOfColumns() != colSize) { throw AlgorithmException("input metric has the wrong number of columns"); } int mapSize = (int)myMap.size(); CaretArray rowScratch(rowSize); for (int i = 0; i < colSize; ++i) { ciftiInOut->getRow(rowScratch, i, true); for (int j = 0; j < mapSize; ++j) { rowScratch[myMap[j].m_ciftiIndex] = metricIn->getValue(myMap[j].m_surfaceNode, i); } ciftiInOut->setRow(rowScratch, i); } } } AlgorithmCiftiReplaceStructure::AlgorithmCiftiReplaceStructure(ProgressObject* myProgObj, CiftiFile* ciftiInOut, const int& myDir, const StructureEnum::Enum& myStruct, const LabelFile* labelIn, const bool& discardUnusedLabels) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const CiftiXML& myXML = ciftiInOut->getCiftiXML(); if (myXML.getNumberOfDimensions() != 2) throw AlgorithmException("replace structure only supported on 2D cifti"); if (myXML.getMappingType(myDir) != CiftiMappingType::BRAIN_MODELS) throw AlgorithmException("specified dimension must contain brain models"); const CiftiBrainModelsMap& myDenseMap = myXML.getBrainModelsMap(myDir); ciftiInOut->convertToInMemory();//so that writing it can change the header vector myMap; int64_t rowSize = ciftiInOut->getNumberOfColumns(), colSize = ciftiInOut->getNumberOfRows(); if (myDir == CiftiXML::ALONG_COLUMN) { if (myXML.getMappingType(CiftiXML::ALONG_ROW) != CiftiMappingType::LABELS) throw AlgorithmException("label separate requested on non-label cifti"); const CiftiLabelsMap& myLabelsMap = myXML.getLabelsMap(CiftiXML::ALONG_ROW); myMap = myDenseMap.getSurfaceMap(myStruct); int64_t numNodes = myDenseMap.getSurfaceNumberOfNodes(myStruct); if (labelIn->getNumberOfNodes() != numNodes) { throw AlgorithmException("input label file has the wrong number of vertices"); } if (labelIn->getNumberOfColumns() != rowSize) { throw AlgorithmException("input label file has the wrong number of columns"); } int64_t mapSize = (int64_t)myMap.size(); CaretArray rowScratch(rowSize, 0.0f);//initialize to the default "unused" value in case we get short reads due to unallocated on-disk cifti vector > usedArray(rowSize); vector > remapArray(rowSize); for (int64_t j = 0; j < rowSize; ++j) { GiftiLabelTable myTable = *(labelIn->getLabelTable());//we remap the old label table values so that the new label table keys are unmolested remapArray[j] = myTable.append(*(myLabelsMap.getMapLabelTable(j))); *(myLabelsMap.getMapLabelTable(j)) = myTable; } set writeRows; for (int64_t i = 0; i < mapSize; ++i) { writeRows.insert(myMap[i].m_ciftiIndex); } for (int64_t i = 0; i < colSize; ++i)//we have to remap all old data since we are changing he keys of the old label table { if (writeRows.find(i) == writeRows.end()) { ciftiInOut->getRow(rowScratch, i, true); bool rowChanged = false; for (int64_t j = 0; j < rowSize; ++j) { int32_t tempKey = (int32_t)floor(rowScratch[j] + 0.5f); map::iterator iter = remapArray[j].find(tempKey); if (iter != remapArray[j].end()) { if (iter->first != iter->second) { rowChanged = true; rowScratch[j] = iter->second;//remap the key if its value changes usedArray[j].insert(iter->second); } else { usedArray[j].insert(tempKey); } } else { rowChanged = true; int32_t unusedLabel = myLabelsMap.getMapLabelTable(j)->getUnassignedLabelKey(); rowScratch[j] = unusedLabel; usedArray[j].insert(unusedLabel); } } if (rowChanged) ciftiInOut->setRow(rowScratch, i); } } for (int64_t i = 0; i < mapSize; ++i)//set the new rows { for (int64_t j = 0; j < rowSize; ++j) { int32_t tempKey = labelIn->getLabelKey(myMap[i].m_surfaceNode, j); usedArray[j].insert(tempKey); rowScratch[j] = tempKey; } ciftiInOut->setRow(rowScratch, myMap[i].m_ciftiIndex); } if (discardUnusedLabels) { for (int64_t i = 0; i < rowSize; ++i)//delete unused labels { myLabelsMap.getMapLabelTable(i)->deleteUnusedLabels(usedArray[i]); } } } else { if (myDir != CiftiXML::ALONG_ROW) throw AlgorithmException("unsupported cifti direction"); if (myXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::LABELS) throw AlgorithmException("label separate requested on non-label cifti"); const CiftiLabelsMap& myLabelsMap = myXML.getLabelsMap(CiftiXML::ALONG_COLUMN); myMap = myDenseMap.getSurfaceMap(myStruct); { throw AlgorithmException("structure not found in specified dimension"); } int64_t numNodes = myDenseMap.getSurfaceNumberOfNodes(myStruct); if (labelIn->getNumberOfNodes() != numNodes) { throw AlgorithmException("input label file has the wrong number of vertices"); } if (labelIn->getNumberOfColumns() != colSize) { throw AlgorithmException("input label file has the wrong number of columns"); } int64_t mapSize = (int64_t)myMap.size(); CaretArray rowScratch(rowSize, 0.0f); set writeCols; for (int64_t i = 0; i < mapSize; ++i) { writeCols.insert(myMap[i].m_ciftiIndex); } for (int64_t i = 0; i < colSize; ++i) { GiftiLabelTable myTable = *(labelIn->getLabelTable());//we remap the old label table values so that the new label table keys are unmolested map remap = myTable.append(*(myLabelsMap.getMapLabelTable(i))); *(myLabelsMap.getMapLabelTable(i)) = myTable; ciftiInOut->getRow(rowScratch, i, true); set used; int32_t unusedKey = myTable.getUnassignedLabelKey(); for(int64_t j = 0; j < rowSize; ++j) { if (writeCols.find(j) == writeCols.end()) { int32_t tempKey = (int32_t)floor(rowScratch[j] + 0.5f); map::iterator iter = remap.find(tempKey); if (iter != remap.end()) { rowScratch[j] = iter->second; used.insert(iter->second); } else { rowScratch[j] = unusedKey; used.insert(unusedKey); } } } for (int64_t j = 0; j < mapSize; ++j) { int32_t tempKey = labelIn->getLabelKey(myMap[j].m_surfaceNode, i); rowScratch[myMap[j].m_ciftiIndex] = tempKey; used.insert(tempKey); } if (discardUnusedLabels) { myLabelsMap.getMapLabelTable(i)->deleteUnusedLabels(used); } ciftiInOut->setRow(rowScratch, i); } } } AlgorithmCiftiReplaceStructure::AlgorithmCiftiReplaceStructure(ProgressObject* myProgObj, CiftiFile* ciftiInOut, const int& myDir, const StructureEnum::Enum& myStruct, const VolumeFile* volIn, const bool& fromCropped, const bool& discardUnusedLabels) : AbstractAlgorithm(myProgObj) { const CiftiXML& myXML = ciftiInOut->getCiftiXML(); if (myDir != CiftiXML::ALONG_ROW && myDir != CiftiXML::ALONG_COLUMN) throw AlgorithmException("direction not supported in cifti replace structure"); if (myXML.getNumberOfDimensions() != 2) throw AlgorithmException("replace structure only supported on 2D cifti"); LevelProgress myProgress(myProgObj); int64_t rowSize = ciftiInOut->getNumberOfColumns(), colSize = ciftiInOut->getNumberOfRows(); if (myXML.getMappingType(myDir) != CiftiMappingType::BRAIN_MODELS) throw AlgorithmException("specified direction does not contain brain models"); const CiftiBrainModelsMap& myBrainMap = myXML.getBrainModelsMap(myDir); const int64_t* myDims = myBrainMap.getVolumeSpace().getDims(); vector > mySform = myBrainMap.getVolumeSpace().getSform(); vector myMap = myBrainMap.getVolumeStructureMap(myStruct); int64_t numVoxels = (int64_t)myMap.size(); int64_t offset[3]; vector newdims; if (fromCropped) { newdims.resize(3); AlgorithmCiftiSeparate::getCroppedVolSpace(ciftiInOut, myDir, myStruct, newdims.data(), mySform, offset); } else { newdims.push_back(myDims[0]); newdims.push_back(myDims[1]); newdims.push_back(myDims[2]); offset[0] = 0; offset[1] = 0; offset[2] = 0; } if (!volIn->matchesVolumeSpace(newdims.data(), mySform)) { throw AlgorithmException("input volume doesn't match volume space and dimensions in CIFTI"); } CaretArray rowScratch(rowSize, 0.0f);//initialize with default unused label in case dlabel and short reads due to uninitialized on-disk cifti vector volDims; volIn->getDimensions(volDims); if (myDir == CiftiXML::ALONG_COLUMN) { if (volDims[3] != rowSize) { throw AlgorithmException("volume has the wrong number of subvolumes"); } if (myXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::LABELS) { if (volIn->getType() != SubvolumeAttributes::LABEL) throw AlgorithmException("replace structure called on cifti label file with non-label volume"); ciftiInOut->convertToInMemory();//so that writing can change the XML const CiftiLabelsMap& myLabelsMap = myXML.getLabelsMap(CiftiXML::ALONG_ROW); vector > remapArray(rowSize); vector > usedArray(rowSize); for (int64_t i = 0; i < rowSize; ++i) { GiftiLabelTable myTable = *(volIn->getMapLabelTable(i));//we remap the old label table values so that the new label table keys are unmolested remapArray[i] = myTable.append(*(myLabelsMap.getMapLabelTable(i))); *(myLabelsMap.getMapLabelTable(i)) = myTable; } set writeRows; for (int64_t i = 0; i < numVoxels; ++i) { writeRows.insert(myMap[i].m_ciftiIndex); } for (int64_t i = 0; i < colSize; ++i) { if (writeRows.find(i) == writeRows.end()) { ciftiInOut->getRow(rowScratch, i, true); bool rowChanged = false; for (int64_t j = 0; j < rowSize; ++j) { int32_t tempKey = (int32_t)floor(rowScratch[j] + 0.5f); map::iterator iter = remapArray[j].find(tempKey); if (iter != remapArray[j].end()) { if (iter->first != iter->second) { rowChanged = true; rowScratch[j] = iter->second;//remap the key if its value changes usedArray[j].insert(iter->second); } else { usedArray[j].insert(tempKey); } } else { rowChanged = true; int32_t unusedLabel = myLabelsMap.getMapLabelTable(j)->getUnassignedLabelKey(); rowScratch[j] = unusedLabel; usedArray[j].insert(unusedLabel); } } if (rowChanged) ciftiInOut->setRow(rowScratch, i); } } for (int64_t i = 0; i < numVoxels; ++i) { int64_t thisvoxel[3] = { myMap[i].m_ijk[0] - offset[0], myMap[i].m_ijk[1] - offset[1], myMap[i].m_ijk[2] - offset[2] }; for (int j = 0; j < rowSize; ++j) { int32_t tempKey = (int32_t)floor(volIn->getValue(thisvoxel, j) + 0.5f); usedArray[j].insert(tempKey); rowScratch[j] = tempKey; } ciftiInOut->setRow(rowScratch, myMap[i].m_ciftiIndex); } if (discardUnusedLabels) { for (int64_t i = 0; i < rowSize; ++i)//delete unused labels { myLabelsMap.getMapLabelTable(i)->deleteUnusedLabels(usedArray[i]); } } } else { for (int64_t i = 0; i < numVoxels; ++i) { int64_t thisvoxel[3] = { myMap[i].m_ijk[0] - offset[0], myMap[i].m_ijk[1] - offset[1], myMap[i].m_ijk[2] - offset[2] }; for (int j = 0; j < rowSize; ++j) { rowScratch[j] = volIn->getValue(thisvoxel, j); } ciftiInOut->setRow(rowScratch, myMap[i].m_ciftiIndex); } } } else { if (volDims[3] != colSize) { throw AlgorithmException("volume has the wrong number of subvolumes"); } if (myXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::LABELS) { if (volIn->getType() != SubvolumeAttributes::LABEL) throw AlgorithmException("replace structure called on cifti label file with non-label volume"); ciftiInOut->convertToInMemory(); const CiftiLabelsMap& myLabelsMap = myXML.getLabelsMap(CiftiXML::ALONG_COLUMN); set writeCols; for (int64_t i = 0; i < numVoxels; ++i) { writeCols.insert(myMap[i].m_ciftiIndex); } for (int64_t i = 0; i < colSize; ++i) { GiftiLabelTable myTable = *(volIn->getMapLabelTable(i));//we remap the old label table values so that the new label table keys are unmolested map remap = myTable.append(*(myLabelsMap.getMapLabelTable(i))); *(myLabelsMap.getMapLabelTable(i)) = myTable; ciftiInOut->getRow(rowScratch, i, true); set used; int32_t unusedKey = myTable.getUnassignedLabelKey(); for(int64_t j = 0; j < rowSize; ++j) { if (writeCols.find(j) == writeCols.end()) { int32_t tempKey = (int32_t)floor(rowScratch[j] + 0.5f); map::iterator iter = remap.find(tempKey); if (iter != remap.end()) { rowScratch[j] = iter->second; used.insert(iter->second); } else { rowScratch[j] = unusedKey; used.insert(unusedKey); } } } for (int64_t j = 0; j < numVoxels; ++j) { int64_t thisvoxel[3] = { myMap[j].m_ijk[0] - offset[0], myMap[j].m_ijk[1] - offset[1], myMap[j].m_ijk[2] - offset[2] }; int32_t tempKey = (int32_t)floor(volIn->getValue(thisvoxel, i) + 0.5f); rowScratch[myMap[j].m_ciftiIndex] = tempKey; used.insert(tempKey); } if (discardUnusedLabels) { myLabelsMap.getMapLabelTable(i)->deleteUnusedLabels(used); } ciftiInOut->setRow(rowScratch, i); } } else { for (int64_t i = 0; i < colSize; ++i) { ciftiInOut->getRow(rowScratch, i, true);//the on-disk cifti file may not have been allocated yet, so short reads are okay for (int64_t j = 0; j < numVoxels; ++j) { int64_t thisvoxel[3] = { myMap[j].m_ijk[0] - offset[0], myMap[j].m_ijk[1] - offset[1], myMap[j].m_ijk[2] - offset[2] }; rowScratch[myMap[j].m_ciftiIndex] = volIn->getValue(thisvoxel, i); } ciftiInOut->setRow(rowScratch, i); } } } } AlgorithmCiftiReplaceStructure::AlgorithmCiftiReplaceStructure(ProgressObject* myProgObj, CiftiFile* ciftiInOut, const int& myDir, const VolumeFile* volIn, const bool& fromCropped, const bool& discardUnusedLabels): AbstractAlgorithm(myProgObj) { const CiftiXML& myXML = ciftiInOut->getCiftiXML(); if (myXML.getNumberOfDimensions() != 2) throw AlgorithmException("replace structure only supported on 2D cifti"); LevelProgress myProgress(myProgObj); if (myDir != CiftiXML::ALONG_ROW && myDir != CiftiXML::ALONG_COLUMN) throw AlgorithmException("direction not supported in cifti replace structure"); if (myXML.getMappingType(myDir) != CiftiMappingType::BRAIN_MODELS) throw AlgorithmException("specified direction does not contain brain models"); const CiftiBrainModelsMap& myBrainMap = myXML.getBrainModelsMap(myDir); const int64_t* myDims = myBrainMap.getVolumeSpace().getDims(); vector > mySform = myBrainMap.getVolumeSpace().getSform(); vector myMap = myBrainMap.getFullVolumeMap(); int64_t numVoxels = (int64_t)myMap.size(); int64_t rowSize = ciftiInOut->getNumberOfColumns(), colSize = ciftiInOut->getNumberOfRows(); vector newdims; int64_t offset[3]; if (fromCropped) { newdims.resize(3); AlgorithmCiftiSeparate::getCroppedVolSpaceAll(ciftiInOut, myDir, newdims.data(), mySform, offset); } else { newdims.push_back(myDims[0]); newdims.push_back(myDims[1]); newdims.push_back(myDims[2]); offset[0] = 0; offset[1] = 0; offset[2] = 0; } if (!volIn->matchesVolumeSpace(newdims.data(), mySform)) { throw AlgorithmException("input volume doesn't match volume space and dimensions in CIFTI"); } CaretArray rowScratch(rowSize, 0.0f);//initialize with default unused label in case dlabel and short reads due to uninitialized on-disk cifti vector volDims; volIn->getDimensions(volDims); if (myDir == CiftiXML::ALONG_COLUMN) { if (volDims[3] != rowSize) { throw AlgorithmException("volume has the wrong number of subvolumes"); } if (myXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::LABELS) { const CiftiLabelsMap& myLabelsMap = myXML.getLabelsMap(CiftiXML::ALONG_ROW); if (volIn->getType() != SubvolumeAttributes::LABEL) throw AlgorithmException("replace structure called on cifti label file with non-label volume"); ciftiInOut->convertToInMemory(); vector > remapArray(rowSize); vector > usedArray(rowSize); for (int64_t i = 0; i < rowSize; ++i) { GiftiLabelTable myTable = *(volIn->getMapLabelTable(i));//we remap the old label table values so that the new label table keys are unmolested remapArray[i] = myTable.append(*(myLabelsMap.getMapLabelTable(i))); *(myLabelsMap.getMapLabelTable(i)) = myTable; } set writeRows; for (int64_t i = 0; i < numVoxels; ++i) { writeRows.insert(myMap[i].m_ciftiIndex); } for (int64_t i = 0; i < colSize; ++i) { if (writeRows.find(i) == writeRows.end()) { ciftiInOut->getRow(rowScratch, i, true); bool rowChanged = false; for (int64_t j = 0; j < rowSize; ++j) { int32_t tempKey = (int32_t)floor(rowScratch[j] + 0.5f); map::iterator iter = remapArray[j].find(tempKey); if (iter != remapArray[j].end()) { if (iter->first != iter->second) { rowChanged = true; rowScratch[j] = iter->second;//remap the key if its value changes usedArray[j].insert(iter->second); } else { usedArray[j].insert(tempKey); } } else { rowChanged = true; int32_t unusedLabel = myLabelsMap.getMapLabelTable(j)->getUnassignedLabelKey(); rowScratch[j] = unusedLabel; usedArray[j].insert(unusedLabel); } } if (rowChanged) ciftiInOut->setRow(rowScratch, i); } } for (int64_t i = 0; i < numVoxels; ++i) { int64_t thisvoxel[3] = { myMap[i].m_ijk[0] - offset[0], myMap[i].m_ijk[1] - offset[1], myMap[i].m_ijk[2] - offset[2] }; for (int j = 0; j < rowSize; ++j) { int32_t tempKey = (int32_t)floor(volIn->getValue(thisvoxel, j) + 0.5f); usedArray[j].insert(tempKey); rowScratch[j] = tempKey; } ciftiInOut->setRow(rowScratch, myMap[i].m_ciftiIndex); } if (discardUnusedLabels) { for (int64_t i = 0; i < rowSize; ++i)//delete unused labels { myLabelsMap.getMapLabelTable(i)->deleteUnusedLabels(usedArray[i]); } } } else { for (int64_t i = 0; i < numVoxels; ++i) { int64_t thisvoxel[3] = { myMap[i].m_ijk[0] - offset[0], myMap[i].m_ijk[1] - offset[1], myMap[i].m_ijk[2] - offset[2] }; for (int j = 0; j < rowSize; ++j) { rowScratch[j] = volIn->getValue(thisvoxel, j); } ciftiInOut->setRow(rowScratch, myMap[i].m_ciftiIndex); } } } else { if (volDims[3] != colSize) { throw AlgorithmException("volume has the wrong number of subvolumes"); } if (myXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::LABELS) { const CiftiLabelsMap& myLabelsMap = myXML.getLabelsMap(CiftiXML::ALONG_COLUMN); if (volIn->getType() != SubvolumeAttributes::LABEL) throw AlgorithmException("replace structure called on cifti label file with non-label volume"); ciftiInOut->convertToInMemory(); set writeCols; for (int64_t i = 0; i < numVoxels; ++i) { writeCols.insert(myMap[i].m_ciftiIndex); } for (int64_t i = 0; i < colSize; ++i) { GiftiLabelTable myTable = *(volIn->getMapLabelTable(i));//we remap the old label table values so that the new label table keys are unmolested map remap = myTable.append(*(myLabelsMap.getMapLabelTable(i))); *(myLabelsMap.getMapLabelTable(i)) = myTable; ciftiInOut->getRow(rowScratch, i, true); set used; int32_t unusedKey = myTable.getUnassignedLabelKey(); for(int64_t j = 0; j < rowSize; ++j) { if (writeCols.find(j) == writeCols.end()) { int32_t tempKey = (int32_t)floor(rowScratch[j] + 0.5f); map::iterator iter = remap.find(tempKey); if (iter != remap.end()) { rowScratch[j] = iter->second; used.insert(iter->second); } else { rowScratch[j] = unusedKey; used.insert(unusedKey); } } } for (int64_t j = 0; j < numVoxels; ++j) { int64_t thisvoxel[3] = { myMap[j].m_ijk[0] - offset[0], myMap[j].m_ijk[1] - offset[1], myMap[j].m_ijk[2] - offset[2] }; int32_t tempKey = (int32_t)floor(volIn->getValue(thisvoxel, i) + 0.5f); rowScratch[myMap[j].m_ciftiIndex] = tempKey; used.insert(tempKey); } if (discardUnusedLabels) { myLabelsMap.getMapLabelTable(i)->deleteUnusedLabels(used); } ciftiInOut->setRow(rowScratch, i); } } else { for (int64_t i = 0; i < colSize; ++i) { ciftiInOut->getRow(rowScratch, i, true);//the on-disk cifti file may not have been allocated yet, so short reads are okay for (int64_t j = 0; j < numVoxels; ++j) { int64_t thisvoxel[3] = { myMap[j].m_ijk[0] - offset[0], myMap[j].m_ijk[1] - offset[1], myMap[j].m_ijk[2] - offset[2] }; rowScratch[myMap[j].m_ciftiIndex] = volIn->getValue(thisvoxel, i); } ciftiInOut->setRow(rowScratch, i); } } } } float AlgorithmCiftiReplaceStructure::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiReplaceStructure::getSubAlgorithmWeight() { return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiReplaceStructure.h000066400000000000000000000051071360521144700270310ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_REPLACE_STRUCTURE_H__ #define __ALGORITHM_CIFTI_REPLACE_STRUCTURE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "StructureEnum.h" namespace caret { class AlgorithmCiftiReplaceStructure : public AbstractAlgorithm { AlgorithmCiftiReplaceStructure(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiReplaceStructure(ProgressObject* myProgObj, CiftiFile* ciftiInOut, const int& myDir, const StructureEnum::Enum& myStruct, const MetricFile* metricIn); AlgorithmCiftiReplaceStructure(ProgressObject* myProgObj, CiftiFile* ciftiInOut, const int& myDir, const StructureEnum::Enum& myStruct, const LabelFile* labelIn, const bool& discardUnusedLabels = false); AlgorithmCiftiReplaceStructure(ProgressObject* myProgObj, CiftiFile* ciftiInOut, const int& myDir, const StructureEnum::Enum& myStruct, const VolumeFile* volIn, const bool& fromCropped, const bool& discardUnusedLabels = false); AlgorithmCiftiReplaceStructure(ProgressObject* myProgObj, CiftiFile* ciftiInOut, const int& myDir, const VolumeFile* volIn, const bool& fromCropped, const bool& discardUnusedLabels = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiReplaceStructure; } #endif //__ALGORITHM_CIFTI_REPLACE_STRUCTURE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiResample.cxx000066400000000000000000002303501360521144700256600ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiResample.h" #include "AlgorithmException.h" #include "AffineFile.h" #include "AlgorithmCiftiSeparate.h" #include "AlgorithmCiftiReplaceStructure.h" #include "AlgorithmLabelDilate.h" #include "AlgorithmLabelResample.h" #include "AlgorithmMetricResample.h" #include "AlgorithmVolumeAffineResample.h" #include "AlgorithmVolumeWarpfieldResample.h" #include "CiftiFile.h" #include "LabelFile.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "SurfaceResamplingHelper.h" #include "VolumeFile.h" #include "VolumePaddingHelper.h" #include "WarpfieldFile.h" #include #include using namespace caret; using namespace std; AString AlgorithmCiftiResample::getCommandSwitch() { return "-cifti-resample"; } AString AlgorithmCiftiResample::getShortDescription() { return "RESAMPLE A CIFTI FILE TO A NEW CIFTI SPACE"; } OperationParameters* AlgorithmCiftiResample::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-in", "the cifti file to resample"); ret->addStringParameter(2, "direction", "the direction of the input that should be resampled, ROW or COLUMN"); ret->addCiftiParameter(3, "cifti-template", "a cifti file containing the cifti space to resample to"); ret->addStringParameter(4, "template-direction", "the direction of the template to use as the resampling space, ROW or COLUMN"); ret->addStringParameter(5, "surface-method", "specify a surface resampling method"); ret->addStringParameter(6, "volume-method", "specify a volume interpolation method"); ret->addCiftiOutputParameter(7, "cifti-out", "the output cifti file"); ret->createOptionalParameter(8, "-surface-largest", "use largest weight instead of weighted average or popularity when doing surface resampling"); OptionalParameter* volDilateOpt = ret->createOptionalParameter(9, "-volume-predilate", "dilate the volume components before resampling"); volDilateOpt->addDoubleParameter(1, "dilate-mm", "distance, in mm, to dilate"); volDilateOpt->createOptionalParameter(2, "-nearest", "use nearest value dilation"); OptionalParameter* volDilateWeightedOpt = volDilateOpt->createOptionalParameter(3, "-weighted", "use weighted dilation (default)"); OptionalParameter* volDilateExpOpt = volDilateWeightedOpt->createOptionalParameter(1, "-exponent", "specify exponent in weighting function"); volDilateExpOpt->addDoubleParameter(1, "exponent", "exponent 'n' to use in (1 / (distance ^ n)) as the weighting function (default 7)"); volDilateWeightedOpt->createOptionalParameter(2, "-legacy-cutoff", "use v1.3.2 logic for the kernel cutoff"); OptionalParameter* surfDilateOpt = ret->createOptionalParameter(10, "-surface-postdilate", "dilate the surface components after resampling"); surfDilateOpt->addDoubleParameter(1, "dilate-mm", "distance, in mm, to dilate"); surfDilateOpt->createOptionalParameter(2, "-nearest", "use nearest value dilation"); surfDilateOpt->createOptionalParameter(3, "-linear", "use linear dilation"); OptionalParameter* surfDilateWeightedOpt = surfDilateOpt->createOptionalParameter(4, "-weighted", "use weighted dilation (default for non-label data)"); OptionalParameter* surfDilateExpOpt = surfDilateWeightedOpt->createOptionalParameter(1, "-exponent", "specify exponent in weighting function"); surfDilateExpOpt->addDoubleParameter(1, "exponent", "exponent 'n' to use in (area / (distance ^ n)) as the weighting function (default 6)"); surfDilateWeightedOpt->createOptionalParameter(2, "-legacy-cutoff", "use v1.3.2 logic for the kernel cutoff"); OptionalParameter* affineOpt = ret->createOptionalParameter(11, "-affine", "use an affine transformation on the volume components"); affineOpt->addStringParameter(1, "affine-file", "the affine file to use"); OptionalParameter* flirtOpt = affineOpt->createOptionalParameter(2, "-flirt", "MUST be used if affine is a flirt affine"); flirtOpt->addStringParameter(1, "source-volume", "the source volume used when generating the affine"); flirtOpt->addStringParameter(2, "target-volume", "the target volume used when generating the affine"); OptionalParameter* warpfieldOpt = ret->createOptionalParameter(12, "-warpfield", "use a warpfield on the volume components"); warpfieldOpt->addStringParameter(1, "warpfield", "the warpfield to use"); OptionalParameter* fnirtOpt = warpfieldOpt->createOptionalParameter(2, "-fnirt", "MUST be used if using a fnirt warpfield"); fnirtOpt->addStringParameter(1, "source-volume", "the source volume used when generating the warpfield"); OptionalParameter* leftSpheresOpt = ret->createOptionalParameter(13, "-left-spheres", "specify spheres for left surface resampling"); leftSpheresOpt->addSurfaceParameter(1, "current-sphere", "a sphere with the same mesh as the current left surface"); leftSpheresOpt->addSurfaceParameter(2, "new-sphere", "a sphere with the new left mesh that is in register with the current sphere"); OptionalParameter* leftAreaSurfsOpt = leftSpheresOpt->createOptionalParameter(3, "-left-area-surfs", "specify left surfaces to do vertex area correction based on"); leftAreaSurfsOpt->addSurfaceParameter(1, "current-area", "a relevant left anatomical surface with current mesh"); leftAreaSurfsOpt->addSurfaceParameter(2, "new-area", "a relevant left anatomical surface with new mesh"); OptionalParameter* leftAreaMetricsOpt = leftSpheresOpt->createOptionalParameter(4, "-left-area-metrics", "specify left vertex area metrics to do area correction based on"); leftAreaMetricsOpt->addMetricParameter(1, "current-area", "a metric file with vertex areas for the current mesh"); leftAreaMetricsOpt->addMetricParameter(2, "new-area", "a metric file with vertex areas for the new mesh"); OptionalParameter* rightSpheresOpt = ret->createOptionalParameter(14, "-right-spheres", "specify spheres for right surface resampling"); rightSpheresOpt->addSurfaceParameter(1, "current-sphere", "a sphere with the same mesh as the current right surface"); rightSpheresOpt->addSurfaceParameter(2, "new-sphere", "a sphere with the new right mesh that is in register with the current sphere"); OptionalParameter* rightAreaSurfsOpt = rightSpheresOpt->createOptionalParameter(3, "-right-area-surfs", "specify right surfaces to do vertex area correction based on"); rightAreaSurfsOpt->addSurfaceParameter(1, "current-area", "a relevant right anatomical surface with current mesh"); rightAreaSurfsOpt->addSurfaceParameter(2, "new-area", "a relevant right anatomical surface with new mesh"); OptionalParameter* rightAreaMetricsOpt = rightSpheresOpt->createOptionalParameter(4, "-right-area-metrics", "specify right vertex area metrics to do area correction based on"); rightAreaMetricsOpt->addMetricParameter(1, "current-area", "a metric file with vertex areas for the current mesh"); rightAreaMetricsOpt->addMetricParameter(2, "new-area", "a metric file with vertex areas for the new mesh"); OptionalParameter* cerebSpheresOpt = ret->createOptionalParameter(15, "-cerebellum-spheres", "specify spheres for cerebellum surface resampling"); cerebSpheresOpt->addSurfaceParameter(1, "current-sphere", "a sphere with the same mesh as the current cerebellum surface"); cerebSpheresOpt->addSurfaceParameter(2, "new-sphere", "a sphere with the new cerebellum mesh that is in register with the current sphere"); OptionalParameter* cerebAreaSurfsOpt = cerebSpheresOpt->createOptionalParameter(3, "-cerebellum-area-surfs", "specify cerebellum surfaces to do vertex area correction based on"); cerebAreaSurfsOpt->addSurfaceParameter(1, "current-area", "a relevant cerebellum anatomical surface with current mesh"); cerebAreaSurfsOpt->addSurfaceParameter(2, "new-area", "a relevant cerebellum anatomical surface with new mesh"); OptionalParameter* cerebAreaMetricsOpt = cerebSpheresOpt->createOptionalParameter(4, "-cerebellum-area-metrics", "specify cerebellum vertex area metrics to do area correction based on"); cerebAreaMetricsOpt->addMetricParameter(1, "current-area", "a metric file with vertex areas for the current mesh"); cerebAreaMetricsOpt->addMetricParameter(2, "new-area", "a metric file with vertex areas for the new mesh"); AString myHelpText = AString("Resample cifti data to a different brainordinate space. Use COLUMN for the direction to resample dscalar, dlabel, or dtseries. ") + "Resampling both dimensions of a dconn requires running this command twice, once with COLUMN and once with ROW. " + "If you are resampling a dconn and your machine has a large amount of memory, you might consider using -cifti-resample-dconn-memory to avoid writing and rereading an intermediate file. " + "The argument should usually be COLUMN, as dtseries, dscalar, and dlabel all have brainordinates on that direction. " + "If spheres are not specified for a surface structure which exists in the cifti files, its data is copied without resampling or dilation. " + "Dilation is done with the 'nearest' method, and is done on for surface data. " + "Volume components are padded before dilation so that dilation doesn't run into the edge of the component bounding box. " + "If neither -affine nor -warpfield are specified, the identity transform is assumed for the volume data.\n\n" + "The recommended resampling methods are ADAP_BARY_AREA and CUBIC (cubic spline), except for label data which should use ADAP_BARY_AREA and ENCLOSING_VOXEL. " + "Using ADAP_BARY_AREA requires specifying an area option to each used -*-spheres option.\n\n" + "The argument must be one of the following:\n\n" + "CUBIC\nENCLOSING_VOXEL\nTRILINEAR\n\n" + "The argument must be one of the following:\n\n"; vector allEnums; SurfaceResamplingMethodEnum::getAllEnums(allEnums); for (int i = 0; i < (int)allEnums.size(); ++i) { myHelpText += SurfaceResamplingMethodEnum::toName(allEnums[i]) + "\n"; } ret->setHelpText(myHelpText); return ret; } void AlgorithmCiftiResample::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* myCiftiIn = myParams->getCifti(1); AString myDirString = myParams->getString(2); int direction = -1; if (myDirString == "ROW") { direction = CiftiXML::ALONG_ROW; } else { if (myDirString == "COLUMN") { direction = CiftiXML::ALONG_COLUMN; } else { throw AlgorithmException("unrecognized direction string, use ROW or COLUMN"); } } CiftiFile* myTemplate = myParams->getCifti(3); AString myTemplDirString = myParams->getString(4); int templateDir = -1; if (myTemplDirString == "ROW") { templateDir = CiftiXML::ALONG_ROW; } else { if (myTemplDirString == "COLUMN") { templateDir = CiftiXML::ALONG_COLUMN; } else { throw AlgorithmException("unrecognized template direction string, use ROW or COLUMN"); } } bool ok = false; SurfaceResamplingMethodEnum::Enum mySurfMethod = SurfaceResamplingMethodEnum::fromName(myParams->getString(5), &ok); if (!ok) { throw AlgorithmException("invalid surface resampling method name"); } AString myVolMethodString = myParams->getString(6); VolumeFile::InterpType myVolMethod = VolumeFile::CUBIC; if (myVolMethodString == "CUBIC") { myVolMethod = VolumeFile::CUBIC; } else if (myVolMethodString == "TRILINEAR") { myVolMethod = VolumeFile::TRILINEAR; } else if (myVolMethodString == "ENCLOSING_VOXEL") { myVolMethod = VolumeFile::ENCLOSING_VOXEL; } else { throw AlgorithmException("unrecognized volume interpolation method"); } CiftiFile* myCiftiOut = myParams->getOutputCifti(7); bool surfLargest = myParams->getOptionalParameter(8)->m_present; float voldilatemm = -1.0f, surfdilatemm = -1.0f; bool isLabelData = false;//dilation method arguments checking needs to know if it is label data const CiftiXML& inputXML = myCiftiIn->getCiftiXML(); for (int i = 0; i < inputXML.getNumberOfDimensions(); ++i) { if (inputXML.getMappingType(i) == CiftiMappingType::LABELS) { isLabelData = true; break; } } AlgorithmVolumeDilate::Method volDilateMethod = AlgorithmVolumeDilate::WEIGHTED; float volDilateExponent = 7.0f; AlgorithmMetricDilate::Method surfDilateMethod = AlgorithmMetricDilate::WEIGHTED;//label dilate doesn't support multiple methods float surfDilateExponent = 6.0f;//label dilate currently only supports nearest, so in order to accept a default in the algorithm, it currently ignores this on label data, no warning bool surfLegacyCutoff = false, volLegacyCutoff = false; OptionalParameter* volDilateOpt = myParams->getOptionalParameter(9);//but it does check the options on the command line for sanity if (volDilateOpt->m_present) { bool methodSpecified = false; voldilatemm = (float)volDilateOpt->getDouble(1); if (voldilatemm <= 0.0f) throw AlgorithmException("dilation amount must be positive"); if (volDilateOpt->getOptionalParameter(2)->m_present) { methodSpecified = true; volDilateMethod = AlgorithmVolumeDilate::NEAREST; } OptionalParameter* volDilateWeightedOpt = volDilateOpt->getOptionalParameter(3); if (volDilateWeightedOpt->m_present) { if (methodSpecified) throw AlgorithmException("cannot specify multiple volume dilation methods"); methodSpecified = true; volDilateMethod = AlgorithmVolumeDilate::WEIGHTED; OptionalParameter* volDilateExpOpt = volDilateWeightedOpt->getOptionalParameter(1); if (volDilateExpOpt->m_present) { volDilateExponent = (float)volDilateExpOpt->getDouble(1); } volLegacyCutoff = volDilateWeightedOpt->getOptionalParameter(2)->m_present; } } OptionalParameter* surfDilateOpt = myParams->getOptionalParameter(10); if (surfDilateOpt->m_present) { bool methodSpecified = false; surfdilatemm = (float)surfDilateOpt->getDouble(1); if (surfdilatemm <= 0.0f) throw AlgorithmException("dilation amount must be positive"); if (surfDilateOpt->getOptionalParameter(2)->m_present) { methodSpecified = true; surfDilateMethod = AlgorithmMetricDilate::NEAREST; } if (surfDilateOpt->getOptionalParameter(3)->m_present) { if (methodSpecified) throw AlgorithmException("cannot specify multiple surface dilation methods"); methodSpecified = true; if (isLabelData) throw AlgorithmException("cannot do linear surface dilation on label data"); surfDilateMethod = AlgorithmMetricDilate::LINEAR; } OptionalParameter* surfDilateWeightedOpt = surfDilateOpt->getOptionalParameter(4); if (surfDilateWeightedOpt->m_present) { if (methodSpecified) throw AlgorithmException("cannot specify multiple surface dilation methods"); methodSpecified = true; if (isLabelData) throw AlgorithmException("cannot do weighted surface dilation on label data"); surfDilateMethod = AlgorithmMetricDilate::WEIGHTED; OptionalParameter* surfDilateExpOpt = surfDilateWeightedOpt->getOptionalParameter(1); if (surfDilateExpOpt->m_present) { surfDilateExponent = (float)surfDilateExpOpt->getDouble(1); } } surfLegacyCutoff = surfDilateWeightedOpt->getOptionalParameter(2)->m_present; } OptionalParameter* affineOpt = myParams->getOptionalParameter(11); OptionalParameter* warpfieldOpt = myParams->getOptionalParameter(12); if (affineOpt->m_present && warpfieldOpt->m_present) throw AlgorithmException("you cannot specify both -affine and -warpfield"); AffineFile myAffine; WarpfieldFile myWarpfield; if (affineOpt->m_present) { OptionalParameter* flirtOpt = affineOpt->getOptionalParameter(2); if (flirtOpt->m_present) { myAffine.readFlirt(affineOpt->getString(1), flirtOpt->getString(1), flirtOpt->getString(2)); } else { myAffine.readWorld(affineOpt->getString(1)); } } if (warpfieldOpt->m_present) { OptionalParameter* fnirtOpt = warpfieldOpt->getOptionalParameter(2); if (fnirtOpt->m_present) { myWarpfield.readFnirt(warpfieldOpt->getString(1), fnirtOpt->getString(1)); } else { myWarpfield.readWorld(warpfieldOpt->getString(1)); } } SurfaceFile* curLeftSphere = NULL, *newLeftSphere = NULL; MetricFile* curLeftAreas = NULL, *newLeftAreas = NULL; MetricFile curLeftAreasTemp, newLeftAreasTemp; OptionalParameter* leftSpheresOpt = myParams->getOptionalParameter(13); if (leftSpheresOpt->m_present) { curLeftSphere = leftSpheresOpt->getSurface(1); newLeftSphere = leftSpheresOpt->getSurface(2); OptionalParameter* leftAreaSurfsOpt = leftSpheresOpt->getOptionalParameter(3); if (leftAreaSurfsOpt->m_present) { SurfaceFile* curAreaSurf = leftAreaSurfsOpt->getSurface(1); SurfaceFile* newAreaSurf = leftAreaSurfsOpt->getSurface(2); vector nodeAreasTemp; curAreaSurf->computeNodeAreas(nodeAreasTemp); curLeftAreasTemp.setNumberOfNodesAndColumns(curAreaSurf->getNumberOfNodes(), 1); curLeftAreasTemp.setValuesForColumn(0, nodeAreasTemp.data()); curLeftAreas = &curLeftAreasTemp; newAreaSurf->computeNodeAreas(nodeAreasTemp); newLeftAreasTemp.setNumberOfNodesAndColumns(newAreaSurf->getNumberOfNodes(), 1); newLeftAreasTemp.setValuesForColumn(0, nodeAreasTemp.data()); newLeftAreas = &newLeftAreasTemp; } OptionalParameter* leftAreaMetricsOpt = leftSpheresOpt->getOptionalParameter(4); if (leftAreaMetricsOpt->m_present) { if (leftAreaSurfsOpt->m_present) { throw AlgorithmException("only one of -left-area-surfs and -left-area-metrics can be specified"); } curLeftAreas = leftAreaMetricsOpt->getMetric(1); newLeftAreas = leftAreaMetricsOpt->getMetric(2); } } SurfaceFile* curRightSphere = NULL, *newRightSphere = NULL; MetricFile* curRightAreas = NULL, *newRightAreas = NULL; MetricFile curRightAreasTemp, newRightAreasTemp; OptionalParameter* rightSpheresOpt = myParams->getOptionalParameter(14); if (rightSpheresOpt->m_present) { curRightSphere = rightSpheresOpt->getSurface(1); newRightSphere = rightSpheresOpt->getSurface(2); OptionalParameter* rightAreaSurfsOpt = rightSpheresOpt->getOptionalParameter(3); if (rightAreaSurfsOpt->m_present) { SurfaceFile* curAreaSurf = rightAreaSurfsOpt->getSurface(1); SurfaceFile* newAreaSurf = rightAreaSurfsOpt->getSurface(2); vector nodeAreasTemp; curAreaSurf->computeNodeAreas(nodeAreasTemp); curRightAreasTemp.setNumberOfNodesAndColumns(curAreaSurf->getNumberOfNodes(), 1); curRightAreasTemp.setValuesForColumn(0, nodeAreasTemp.data()); curRightAreas = &curRightAreasTemp; newAreaSurf->computeNodeAreas(nodeAreasTemp); newRightAreasTemp.setNumberOfNodesAndColumns(newAreaSurf->getNumberOfNodes(), 1); newRightAreasTemp.setValuesForColumn(0, nodeAreasTemp.data()); newRightAreas = &newRightAreasTemp; } OptionalParameter* rightAreaMetricsOpt = rightSpheresOpt->getOptionalParameter(4); if (rightAreaMetricsOpt->m_present) { if (rightAreaSurfsOpt->m_present) { throw AlgorithmException("only one of -right-area-surfs and -right-area-metrics can be specified"); } curRightAreas = rightAreaMetricsOpt->getMetric(1); newRightAreas = rightAreaMetricsOpt->getMetric(2); } } SurfaceFile* curCerebSphere = NULL, *newCerebSphere = NULL; MetricFile* curCerebAreas = NULL, *newCerebAreas = NULL; MetricFile curCerebAreasTemp, newCerebAreasTemp; OptionalParameter* cerebSpheresOpt = myParams->getOptionalParameter(15); if (cerebSpheresOpt->m_present) { curCerebSphere = cerebSpheresOpt->getSurface(1); newCerebSphere = cerebSpheresOpt->getSurface(2); OptionalParameter* cerebAreaSurfsOpt = cerebSpheresOpt->getOptionalParameter(3); if (cerebAreaSurfsOpt->m_present) { SurfaceFile* curAreaSurf = cerebAreaSurfsOpt->getSurface(1); SurfaceFile* newAreaSurf = cerebAreaSurfsOpt->getSurface(2); vector nodeAreasTemp; curAreaSurf->computeNodeAreas(nodeAreasTemp); curCerebAreasTemp.setNumberOfNodesAndColumns(curAreaSurf->getNumberOfNodes(), 1); curCerebAreasTemp.setValuesForColumn(0, nodeAreasTemp.data()); curCerebAreas = &curCerebAreasTemp; newAreaSurf->computeNodeAreas(nodeAreasTemp); newCerebAreasTemp.setNumberOfNodesAndColumns(newAreaSurf->getNumberOfNodes(), 1); newCerebAreasTemp.setValuesForColumn(0, nodeAreasTemp.data()); newCerebAreas = &newCerebAreasTemp; } OptionalParameter* cerebAreaMetricsOpt = cerebSpheresOpt->getOptionalParameter(4); if (cerebAreaMetricsOpt->m_present) { if (cerebAreaSurfsOpt->m_present) { throw AlgorithmException("only one of -cerebellum-area-surfs and -cerebellum-area-metrics can be specified"); } curCerebAreas = cerebAreaMetricsOpt->getMetric(1); newCerebAreas = cerebAreaMetricsOpt->getMetric(2); } } if (warpfieldOpt->m_present) { AlgorithmCiftiResample(myProgObj, myCiftiIn, direction, myTemplate, templateDir, mySurfMethod, myVolMethod, myCiftiOut, surfLargest, voldilatemm, surfdilatemm, myWarpfield.getWarpfield(), curLeftSphere, newLeftSphere, curLeftAreas, newLeftAreas, curRightSphere, newRightSphere, curRightAreas, newRightAreas, curCerebSphere, newCerebSphere, curCerebAreas, newCerebAreas, volDilateMethod, volDilateExponent, surfDilateMethod, surfDilateExponent, volLegacyCutoff, surfLegacyCutoff); } else {//rely on AffineFile() being the identity transform for if neither option is specified AlgorithmCiftiResample(myProgObj, myCiftiIn, direction, myTemplate, templateDir, mySurfMethod, myVolMethod, myCiftiOut, surfLargest, voldilatemm, surfdilatemm, myAffine.getMatrix(), curLeftSphere, newLeftSphere, curLeftAreas, newLeftAreas, curRightSphere, newRightSphere, curRightAreas, newRightAreas, curCerebSphere, newCerebSphere, curCerebAreas, newCerebAreas, volDilateMethod, volDilateExponent, surfDilateMethod, surfDilateExponent, volLegacyCutoff, surfLegacyCutoff); } } pair AlgorithmCiftiResample::checkForErrors(const CiftiFile* myCiftiIn, const int& direction, const CiftiFile* myTemplate, const int& templateDir, const SurfaceResamplingMethodEnum::Enum& mySurfMethod, const SurfaceFile* curLeftSphere, const SurfaceFile* newLeftSphere, const MetricFile* curLeftAreas, const MetricFile* newLeftAreas, const SurfaceFile* curRightSphere, const SurfaceFile* newRightSphere, const MetricFile* curRightAreas, const MetricFile* newRightAreas, const SurfaceFile* curCerebSphere, const SurfaceFile* newCerebSphere, const MetricFile* curCerebAreas, const MetricFile* newCerebAreas) { if (direction > 1) return make_pair(true, AString("unsupported mapping direction for cifti resample")); const CiftiXML& myInputXML = myCiftiIn->getCiftiXML(); if (myInputXML.getNumberOfDimensions() != 2) return make_pair(true, AString("cifti resample only supports 2D cifti")); if (myInputXML.getMappingType(direction) != CiftiMappingType::BRAIN_MODELS) return make_pair(true, AString("direction for input must contain brain models")); const CiftiBrainModelsMap& inModels = myInputXML.getBrainModelsMap(direction); const CiftiXML& myTemplateXML = myTemplate->getCiftiXML(); if (templateDir < 0 || templateDir >= myTemplateXML.getNumberOfDimensions()) return make_pair(true, AString("specified template direction does not exist in template file")); if (myTemplateXML.getMappingType(templateDir) != CiftiMappingType::BRAIN_MODELS) return make_pair(true, AString("direction for template must contain brain models")); const CiftiBrainModelsMap& outModels = myTemplate->getCiftiXML().getBrainModelsMap(templateDir); vector surfList = outModels.getSurfaceStructureList(), volList = outModels.getVolumeStructureList(); for (int i = 0; i < (int)surfList.size(); ++i)//ensure existence of resampling spheres before doing any computation { if (!inModels.hasSurfaceData(surfList[i])) return make_pair(true, AString("input cifti missing surface information for structure: " + StructureEnum::toGuiName(surfList[i]))); const SurfaceFile* curSphere = NULL, *newSphere = NULL; const MetricFile* curAreas = NULL, *newAreas = NULL; AString structName; switch (surfList[i]) { case StructureEnum::CORTEX_LEFT: curSphere = curLeftSphere; newSphere = newLeftSphere; curAreas = curLeftAreas; newAreas = newLeftAreas; structName = "left"; break; case StructureEnum::CORTEX_RIGHT: curSphere = curRightSphere; newSphere = newRightSphere; curAreas = curRightAreas; newAreas = newRightAreas; structName = "right"; break; case StructureEnum::CEREBELLUM: curSphere = curCerebSphere; newSphere = newCerebSphere; curAreas = curCerebAreas; newAreas = newCerebAreas; structName = "cerebellum"; break; default: return make_pair(true, AString("unsupported surface structure: " + StructureEnum::toGuiName(surfList[i]))); break; } if (curSphere != NULL)//resampling { if (newSphere == NULL) return make_pair(true, AString("missing " + structName + " new sphere")); if (curSphere->getNumberOfNodes() != inModels.getSurfaceNumberOfNodes(surfList[i])) return make_pair(true, AString(structName + " current sphere doesn't match input cifti")); if (newSphere->getNumberOfNodes() != outModels.getSurfaceNumberOfNodes(surfList[i])) return make_pair(true, AString(structName + " new sphere doesn't match input cifti")); switch (mySurfMethod) { case SurfaceResamplingMethodEnum::ADAP_BARY_AREA: if (curAreas == NULL || newAreas == NULL) return make_pair(true, AString(structName + " area data is missing")); if (curAreas->getNumberOfNodes() != curSphere->getNumberOfNodes()) return make_pair(true, AString(structName + " current area data has the wrong number of vertices")); if (newAreas->getNumberOfNodes() != newSphere->getNumberOfNodes()) return make_pair(true, AString(structName + " new area data has the wrong number of vertices")); break; default: break; } } else {//copying if (inModels.getSurfaceNumberOfNodes(surfList[i]) != outModels.getSurfaceNumberOfNodes(surfList[i])) return make_pair(true, AString(structName + " structure requires resampling spheres, does not match template")); } } for (int i = 0; i < (int)volList.size(); ++i) { if (!inModels.hasVolumeData(volList[i])) { return make_pair(true, AString(StructureEnum::toGuiName(volList[i]) + " volume model missing from input cifti")); } } return make_pair(false, AString()); } namespace {//so that we don't need these in the header file struct ResampleCache {//a place to stuff anything that can be precomputed or reused for applying to the same structure in multiple maps SurfaceResamplingHelper surfResamp; VolumePaddingHelper volPadding; const SurfaceFile* curSphere, *newSphere; MetricFile tempMetric1, tempMetric2, surfDilateRoi; LabelFile tempLabel1, tempLabel2; CaretPointer inputVol, tempVol2, tempVol3, volDilateRoi; vector inSurfMap, outSurfMap; vector inVolMap, outVolMap; vector floatScratch1, floatScratch2; vector intScratch1, intScratch2; int64_t refDims[3], refOffset[3], inOffset[3]; vector > refSform; bool copyMode; vector edgeVoxelList, outsideRoiVoxels, insideResampledRoiVoxels; }; void setupRowResampling(map& surfCache, map& volCache, const CiftiFile* myCiftiIn, CiftiFile* myCiftiOut, const SurfaceResamplingMethodEnum::Enum& mySurfMethod, const float& voldilatemm, const FloatMatrix* affine, const VolumeFile* warpfield, const SurfaceFile* curLeftSphere, const SurfaceFile* newLeftSphere, const MetricFile* curLeftAreas, const MetricFile* newLeftAreas, const SurfaceFile* curRightSphere, const SurfaceFile* newRightSphere, const MetricFile* curRightAreas, const MetricFile* newRightAreas, const SurfaceFile* curCerebSphere, const SurfaceFile* newCerebSphere, const MetricFile* curCerebAreas, const MetricFile* newCerebAreas) { const CiftiXML& myInputXML = myCiftiIn->getCiftiXML(), &myOutXML = myCiftiOut->getCiftiXML(); bool labelMode = (myInputXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::LABELS); const CiftiBrainModelsMap& inModels = myInputXML.getBrainModelsMap(CiftiXML::ALONG_ROW), &outModels = myOutXML.getBrainModelsMap(CiftiXML::ALONG_ROW); vector surfList = outModels.getSurfaceStructureList(), volList = outModels.getVolumeStructureList(); int numSurfStructs = (int)surfList.size(), numVolStructs = (int)volList.size(); for (int i = 0; i < numSurfStructs; ++i)//initialize reusables { const SurfaceFile* curSphere = NULL, *newSphere = NULL; const MetricFile* curAreas = NULL, *newAreas = NULL; switch (surfList[i]) { case StructureEnum::CORTEX_LEFT: curSphere = curLeftSphere; newSphere = newLeftSphere; curAreas = curLeftAreas; newAreas = newLeftAreas; break; case StructureEnum::CORTEX_RIGHT: curSphere = curRightSphere; newSphere = newRightSphere; curAreas = curRightAreas; newAreas = newRightAreas; break; case StructureEnum::CEREBELLUM: curSphere = curCerebSphere; newSphere = newCerebSphere; curAreas = curCerebAreas; newAreas = newCerebAreas; break; default: throw AlgorithmException("unsupported surface structure: " + StructureEnum::toGuiName(surfList[i])); break; } ResampleCache& myCache = surfCache[surfList[i]]; myCache.inSurfMap = inModels.getSurfaceMap(surfList[i]); myCache.outSurfMap = outModels.getSurfaceMap(surfList[i]); if (curSphere == NULL) { myCache.copyMode = true; myCache.floatScratch1.resize(inModels.getSurfaceNumberOfNodes(surfList[i]), 0.0f); continue; } myCache.copyMode = false; myCache.curSphere = curSphere; myCache.newSphere = newSphere; const float* curAreasPtr = NULL, *newAreasPtr = NULL; if (curAreas != NULL && newAreas != NULL) { curAreasPtr = curAreas->getValuePointerForColumn(0); newAreasPtr = newAreas->getValuePointerForColumn(0); } vector tempRoi(curSphere->getNumberOfNodes(), 0.0f); for (int j = 0; j < (int)myCache.inSurfMap.size(); ++j) { tempRoi[myCache.inSurfMap[j].m_surfaceNode] = 1.0f; } myCache.surfResamp = SurfaceResamplingHelper(mySurfMethod, curSphere, newSphere, curAreasPtr, newAreasPtr, tempRoi.data());//resampling is already a helper, so use it as such tempRoi.resize(newSphere->getNumberOfNodes()); myCache.surfResamp.getResampleValidROI(tempRoi.data()); myCache.surfDilateRoi.setNumberOfNodesAndColumns(newSphere->getNumberOfNodes(), 1); for (int j = 0; j < (int)tempRoi.size(); ++j) { myCache.surfDilateRoi.setValue(j, 0, (tempRoi[j] > 0.0f ? 0.0f : 1.0f)); } if (labelMode) { myCache.intScratch1.resize(curSphere->getNumberOfNodes(), 0); myCache.intScratch2.resize(newSphere->getNumberOfNodes(), 0); myCache.tempLabel1.setNumberOfNodesAndColumns(newSphere->getNumberOfNodes(), 1); } else { myCache.floatScratch1.resize(curSphere->getNumberOfNodes(), 0.0f); myCache.floatScratch2.resize(newSphere->getNumberOfNodes(), 0.0f); myCache.tempMetric1.setNumberOfNodesAndColumns(newSphere->getNumberOfNodes(), 1); } } for (int i = 0; i < numVolStructs; ++i) { ResampleCache& myCache = volCache[volList[i]]; myCache.inVolMap = inModels.getVolumeStructureMap(volList[i]); myCache.outVolMap = outModels.getVolumeStructureMap(volList[i]); vector > sform; vector inDims(3); myCache.floatScratch1.resize(inDims[0] * inDims[1] * inDims[2]); AlgorithmCiftiSeparate::getCroppedVolSpace(myCiftiIn, CiftiXML::ALONG_ROW, volList[i], inDims.data(), sform, myCache.inOffset); AlgorithmCiftiSeparate::getCroppedVolSpace(myCiftiOut, CiftiXML::ALONG_ROW, volList[i], myCache.refDims, myCache.refSform, myCache.refOffset); if (labelMode) { myCache.inputVol.grabNew(new VolumeFile(inDims, sform, 1, SubvolumeAttributes::LABEL)); } else { myCache.inputVol.grabNew(new VolumeFile(inDims, sform)); myCache.inputVol->setValueAllVoxels(0.0f); } myCache.tempVol2.grabNew(new VolumeFile(inDims, sform));//make the dilation roi, to figure out edge voxels and in case we do dilation myCache.tempVol2->setValueAllVoxels(0.0f); for (int64_t j = 0; j < (int64_t)myCache.inVolMap.size(); ++j) { myCache.tempVol2->setValue(1.0f, myCache.inVolMap[j].m_ijk[0] - myCache.inOffset[0], myCache.inVolMap[j].m_ijk[1] - myCache.inOffset[1], myCache.inVolMap[j].m_ijk[2] - myCache.inOffset[2]); } int neighbors[] = { 0, 0, -1, 0, -1, 0, -1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 }; VolumeFile resampledRoi; if (voldilatemm > 0.0f) { VolumeFile ROIinvTemp(inDims, sform); ROIinvTemp.setValueAllVoxels(1.0f);//make the ordinary ROI so that we can dilate it for (int64_t j = 0; j < (int64_t)myCache.inVolMap.size(); ++j) { ROIinvTemp.setValue(0.0f, myCache.inVolMap[j].m_ijk[0] - myCache.inOffset[0], myCache.inVolMap[j].m_ijk[1] - myCache.inOffset[1], myCache.inVolMap[j].m_ijk[2] - myCache.inOffset[2]); } myCache.volPadding = VolumePaddingHelper::padMM(myCache.inputVol, voldilatemm); myCache.volDilateRoi.grabNew(new VolumeFile()); myCache.volPadding.doPadding(&ROIinvTemp, myCache.volDilateRoi, 1.0f);//this is the correct final volDilateRoi, we don't need the unpadded form anymore ROIinvTemp.clear(); myCache.tempVol3.grabNew(new VolumeFile());//this is only used in processing when dilating myCache.volPadding.doPadding(myCache.tempVol2, myCache.tempVol3); AlgorithmVolumeDilate(NULL, myCache.tempVol3, voldilatemm, AlgorithmVolumeDilate::NEAREST, myCache.tempVol2, myCache.volDilateRoi); vector paddedDims = myCache.tempVol2->getDimensions(); for (int64_t k = 0; k < paddedDims[2]; ++k) { for (int64_t j = 0; j < paddedDims[1]; ++j) { for (int64_t i = 0; i < paddedDims[0]; ++i) { if (myCache.tempVol2->getValue(i, j, k) > 0.0f) { for (int n = 0; n < 6; ++n) { VoxelIJK thisVoxel = VoxelIJK(i + neighbors[j * 3 + 0], j + neighbors[j * 3 + 1], k + neighbors[j * 3 + 2]); if (myCache.tempVol2->indexValid(thisVoxel.m_ijk) && myCache.tempVol2->getValue(thisVoxel.m_ijk) == 0.0f)//trick: if it is merely touching an FOV edge, cubic won't cause ringing there, so ignore that voxel { myCache.edgeVoxelList.push_back(VoxelIJK(i, j, k)); break; } } } else { myCache.outsideRoiVoxels.push_back(VoxelIJK(i, j, k)); } } } } if (warpfield != NULL) { AlgorithmVolumeWarpfieldResample(NULL, myCache.tempVol2, warpfield, myCache.refDims, myCache.refSform, VolumeFile::TRILINEAR, &resampledRoi); } else { AlgorithmVolumeAffineResample(NULL, myCache.tempVol2, *affine, myCache.refDims, myCache.refSform, VolumeFile::TRILINEAR, &resampledRoi); } } else { for (int64_t k = 0; k < inDims[2]; ++k)//we have to loop through all voxels anyway to find the ones outside the ROI { for (int64_t j = 0; j < inDims[1]; ++j) { for (int64_t i = 0; i < inDims[0]; ++i) { if (myCache.tempVol2->getValue(i, j, k) > 0.0f) { for (int k = 0; k < 6; ++k) { VoxelIJK thisVoxel = VoxelIJK(myCache.inVolMap[j].m_ijk[0] - myCache.inOffset[0] + neighbors[k * 3 + 0], myCache.inVolMap[j].m_ijk[1] - myCache.inOffset[1] + neighbors[k * 3 + 1], myCache.inVolMap[j].m_ijk[2] - myCache.inOffset[2] + neighbors[k * 3 + 2]); if (myCache.tempVol2->indexValid(thisVoxel.m_ijk) && myCache.tempVol2->getValue(thisVoxel.m_ijk) == 0.0f) { myCache.edgeVoxelList.push_back(VoxelIJK(myCache.inVolMap[j].m_ijk[0] - myCache.inOffset[0], myCache.inVolMap[j].m_ijk[1] - myCache.inOffset[1], myCache.inVolMap[j].m_ijk[2] - myCache.inOffset[2])); break; } } } else { myCache.outsideRoiVoxels.push_back(VoxelIJK(i, j, k)); } } } } if (warpfield != NULL) { AlgorithmVolumeWarpfieldResample(NULL, myCache.tempVol2, warpfield, myCache.refDims, myCache.refSform, VolumeFile::TRILINEAR, &resampledRoi); } else { AlgorithmVolumeAffineResample(NULL, myCache.tempVol2, *affine, myCache.refDims, myCache.refSform, VolumeFile::TRILINEAR, &resampledRoi); } } for (int64_t k = 0; k < myCache.refDims[2]; ++k) { for (int64_t j = 0; j < myCache.refDims[1]; ++j) { for (int64_t i = 0; i < myCache.refDims[0]; ++i) { if (resampledRoi.getValue(i, j, k) > 0.5f) { myCache.insideResampledRoiVoxels.push_back(VoxelIJK(i, j, k)); } } } } } } void processRowSurface(ResampleCache& myCache, const vector& inRow, vector& outRow, const CiftiXML& myInputXML, const float& surfdilatemm, const bool& surfLargest, const int& unassignedLabelKey, const int64_t& row, const AlgorithmMetricDilate::Method& surfDilateMethod, const float& surfDilateExponent, const bool surfLegacyCutoff) { bool labelMode = (myInputXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::LABELS); int inMapSize = (int)myCache.inSurfMap.size(), outMapSize = (int)myCache.outSurfMap.size(); if (myCache.copyMode)//copy { for (int j = 0; j < inMapSize; ++j) { myCache.floatScratch1[myCache.inSurfMap[j].m_surfaceNode] = inRow[myCache.inSurfMap[j].m_ciftiIndex]; } for (int j = 0; j < outMapSize; ++j) { outRow[myCache.outSurfMap[j].m_ciftiIndex] = myCache.floatScratch1[myCache.outSurfMap[j].m_surfaceNode]; } } else { if (labelMode) { const CiftiLabelsMap& myLabelMap = myInputXML.getLabelsMap(CiftiXML::ALONG_COLUMN); for (int j = 0; j < inMapSize; ++j) { myCache.intScratch1[myCache.inSurfMap[j].m_surfaceNode] = (int)floor(inRow[myCache.inSurfMap[j].m_ciftiIndex] + 0.5f); } if (surfLargest) { myCache.surfResamp.resampleLargest(myCache.intScratch1.data(), myCache.intScratch2.data(), unassignedLabelKey); } else { myCache.surfResamp.resamplePopular(myCache.intScratch1.data(), myCache.intScratch2.data(), unassignedLabelKey); } *(myCache.tempLabel1.getLabelTable()) = *(myLabelMap.getMapLabelTable(row)); myCache.tempLabel1.setLabelKeysForColumn(0, myCache.intScratch2.data()); LabelFile* toUse = &(myCache.tempLabel1); if (surfdilatemm > 0.0f) { AlgorithmLabelDilate(NULL, toUse, myCache.newSphere, surfdilatemm, &(myCache.tempLabel2), &(myCache.surfDilateRoi), 0); toUse = &(myCache.tempLabel2); } const int32_t* outData = toUse->getLabelKeyPointerForColumn(0); for (int j = 0; j < outMapSize; ++j) { outRow[myCache.outSurfMap[j].m_ciftiIndex] = outData[myCache.outSurfMap[j].m_surfaceNode]; } } else { for (int j = 0; j < inMapSize; ++j) { myCache.floatScratch1[myCache.inSurfMap[j].m_surfaceNode] = inRow[myCache.inSurfMap[j].m_ciftiIndex]; } if (surfLargest) { myCache.surfResamp.resampleLargest(myCache.floatScratch1.data(), myCache.floatScratch2.data()); } else { myCache.surfResamp.resampleNormal(myCache.floatScratch1.data(), myCache.floatScratch2.data()); } myCache.tempMetric1.setValuesForColumn(0, myCache.floatScratch2.data()); MetricFile* toUse = &(myCache.tempMetric1); if (surfdilatemm > 0.0f) { AlgorithmMetricDilate(NULL, toUse, myCache.newSphere, surfdilatemm, &(myCache.tempMetric2), &(myCache.surfDilateRoi), NULL, 0, surfDilateMethod, surfDilateExponent, NULL, surfLegacyCutoff); toUse = &(myCache.tempMetric2); } const float* outData = toUse->getValuePointerForColumn(0); for (int j = 0; j < outMapSize; ++j) { outRow[myCache.outSurfMap[j].m_ciftiIndex] = outData[myCache.outSurfMap[j].m_surfaceNode]; } } } } void processRowVolume(ResampleCache& myCache, const vector& inRow, vector& outRow, const CiftiXML& myInputXML, const float& voldilatemm, const AlgorithmVolumeDilate::Method& volDilateMethod, const float& volDilateExponent, const int& unassignedLabelKey, const VolumeFile* warpfield, const FloatMatrix* affine, const VolumeFile::InterpType& myVolMethod, const bool volLegacyCutoff) { bool labelMode = (myInputXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::LABELS); bool doEdgeAdjust = (myVolMethod == VolumeFile::VolumeFile::CUBIC);//if they ask for cubic on label data, let strange things happen (there will be warnings from resample) if (labelMode)//gets initialized to 0 when not using labels { myCache.inputVol->setValueAllVoxels(unassignedLabelKey); } int inMapSize = (int)myCache.inVolMap.size(), outMapSize = (int)myCache.outVolMap.size(); for (int j = 0; j < inMapSize; ++j) { myCache.inputVol->setValue(inRow[myCache.inVolMap[j].m_ciftiIndex], myCache.inVolMap[j].m_ijk[0] - myCache.inOffset[0], myCache.inVolMap[j].m_ijk[1] - myCache.inOffset[1], myCache.inVolMap[j].m_ijk[2] - myCache.inOffset[2]); } VolumeFile* toResample = myCache.inputVol; if (voldilatemm > 0.0f) {//inputVol is kept at original dimensions, don't overwrite it myCache.volPadding.doPadding(myCache.inputVol, myCache.tempVol2); AlgorithmVolumeDilate(NULL, myCache.tempVol2, voldilatemm, volDilateMethod, myCache.tempVol3, myCache.volDilateRoi, NULL, -1, volDilateExponent, volLegacyCutoff); toResample = myCache.tempVol3; } if (doEdgeAdjust) { double edgeSum = 0.0;//calculate the average edge value so we can use it to reduce interpolation edge effects (particularly cubic) for (int64_t j = 0; j < (int64_t)myCache.edgeVoxelList.size(); ++j) { edgeSum += toResample->getValue(myCache.edgeVoxelList[j]); } float edgeAverage = 0.0f; if (!myCache.edgeVoxelList.empty()) { edgeAverage = edgeSum / myCache.edgeVoxelList.size(); } for (int j = 0; j < int(myCache.outsideRoiVoxels.size()); ++j) { toResample->setValue(edgeAverage, myCache.outsideRoiVoxels[j]); } }//toResample is never 2, so we can use 2 if (warpfield != NULL) { AlgorithmVolumeWarpfieldResample(NULL, toResample, warpfield, myCache.refDims, myCache.refSform, myVolMethod, myCache.tempVol2); } else { AlgorithmVolumeAffineResample(NULL, toResample, *affine, myCache.refDims, myCache.refSform, myVolMethod, myCache.tempVol2); } if (doEdgeAdjust) { vector tempFrame(myCache.refDims[0] * myCache.refDims[1] * myCache.refDims[2], 0.0f);//for consistency with COLUMN, copy out only the selected voxels for (int j = 0; j < int(myCache.insideResampledRoiVoxels.size()); ++j) { tempFrame[myCache.tempVol2->getIndex(myCache.insideResampledRoiVoxels[j])] = myCache.tempVol2->getValue(myCache.insideResampledRoiVoxels[j]); } myCache.tempVol2->setFrame(tempFrame.data()); } for (int j = 0; j < outMapSize; ++j) { outRow[myCache.outVolMap[j].m_ciftiIndex] = myCache.tempVol2->getValue(myCache.outVolMap[j].m_ijk[0] - myCache.refOffset[0], myCache.outVolMap[j].m_ijk[1] - myCache.refOffset[1], myCache.outVolMap[j].m_ijk[2] - myCache.refOffset[2]); } } } AlgorithmCiftiResample::AlgorithmCiftiResample(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const int& direction, const CiftiFile* myTemplate, const int& templateDir, const SurfaceResamplingMethodEnum::Enum& mySurfMethod, const VolumeFile::InterpType& myVolMethod, CiftiFile* myCiftiOut, const bool& surfLargest, const float& voldilatemm, const float& surfdilatemm, const VolumeFile* warpfield, const SurfaceFile* curLeftSphere, const SurfaceFile* newLeftSphere, const MetricFile* curLeftAreas, const MetricFile* newLeftAreas, const SurfaceFile* curRightSphere, const SurfaceFile* newRightSphere, const MetricFile* curRightAreas, const MetricFile* newRightAreas, const SurfaceFile* curCerebSphere, const SurfaceFile* newCerebSphere, const MetricFile* curCerebAreas, const MetricFile* newCerebAreas, const AlgorithmVolumeDilate::Method& volDilateMethod, const float& volDilateExponent, const AlgorithmMetricDilate::Method& surfDilateMethod, const float& surfDilateExponent, const bool volLegacyCutoff, const bool surfLegacyCutoff) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); pair myError = checkForErrors(myCiftiIn, direction, myTemplate, templateDir, mySurfMethod, curLeftSphere, newLeftSphere, curLeftAreas, newLeftAreas, curRightSphere, newRightSphere, curRightAreas, newRightAreas, curCerebSphere, newCerebSphere, curCerebAreas, newCerebAreas); if (myError.first) throw AlgorithmException(myError.second); const CiftiXML& myInputXML = myCiftiIn->getCiftiXML(); CiftiXML myOutXML = myInputXML; myOutXML.setMap(direction, *(myTemplate->getCiftiXML().getMap(templateDir))); const CiftiBrainModelsMap& outModels = myOutXML.getBrainModelsMap(direction); vector surfList = outModels.getSurfaceStructureList(), volList = outModels.getVolumeStructureList(); myCiftiOut->setCiftiXML(myOutXML); if (direction == CiftiXML::ALONG_COLUMN) { for (int i = 0; i < (int)surfList.size(); ++i)//and now, resampling { const SurfaceFile* curSphere = NULL, *newSphere = NULL; const MetricFile* curAreas = NULL, *newAreas = NULL; switch (surfList[i]) { case StructureEnum::CORTEX_LEFT: curSphere = curLeftSphere; newSphere = newLeftSphere; curAreas = curLeftAreas; newAreas = newLeftAreas; break; case StructureEnum::CORTEX_RIGHT: curSphere = curRightSphere; newSphere = newRightSphere; curAreas = curRightAreas; newAreas = newRightAreas; break; case StructureEnum::CEREBELLUM: curSphere = curCerebSphere; newSphere = newCerebSphere; curAreas = curCerebAreas; newAreas = newCerebAreas; break; default: throw AlgorithmException("unsupported surface structure: " + StructureEnum::toGuiName(surfList[i])); break; } processSurfaceComponent(myCiftiIn, direction, surfList[i], mySurfMethod, myCiftiOut, surfLargest, surfdilatemm, curSphere, newSphere, curAreas, newAreas, surfDilateMethod, surfDilateExponent, surfLegacyCutoff); } for (int i = 0; i < (int)volList.size(); ++i) { processVolume(myCiftiIn, direction, volList[i], myVolMethod, myCiftiOut, voldilatemm, warpfield, NULL, volDilateMethod, volDilateExponent, volLegacyCutoff); } } else {//avoid cifti separate/replace with ALONG_ROW bool labelMode = (myInputXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::LABELS); vector surfList = outModels.getSurfaceStructureList(), volList = outModels.getVolumeStructureList(); int numSurfStructs = (int)surfList.size(), numVolStructs = (int)volList.size(); vector unassignedLabelKey; if (labelMode) { const CiftiLabelsMap& myLabelMap = myInputXML.getLabelsMap(CiftiXML::ALONG_COLUMN); unassignedLabelKey.resize(myLabelMap.getLength()); for (int i = 0; i < myLabelMap.getLength(); ++i) { unassignedLabelKey[i] = myLabelMap.getMapLabelTable(i)->getUnassignedLabelKey(); } } map surfCache, volCache;//could make them different types, but whatever - two variables in case of structure overlap in surface and volume, as some members may get used by both setupRowResampling(surfCache, volCache, myCiftiIn, myCiftiOut, mySurfMethod, voldilatemm, NULL, warpfield, curLeftSphere, newLeftSphere, curLeftAreas, newLeftAreas, curRightSphere, newRightSphere, curRightAreas, newRightAreas, curCerebSphere, newCerebSphere, curCerebAreas, newCerebAreas); int64_t numRows = myInputXML.getDimensionLength(CiftiXML::ALONG_COLUMN); vector inRow(myInputXML.getDimensionLength(CiftiXML::ALONG_ROW)), outRow(myOutXML.getDimensionLength(CiftiXML::ALONG_ROW)); for (int64_t row = 0; row < numRows; ++row) { myCiftiIn->getRow(inRow.data(), row); for (int i = 0; i < numSurfStructs; ++i) { map::iterator iter = surfCache.find(surfList[i]); CaretAssert(iter != surfCache.end()); processRowSurface(iter->second, inRow, outRow, myInputXML, surfdilatemm, surfLargest, unassignedLabelKey[row], row, surfDilateMethod, surfDilateExponent, surfLegacyCutoff); } for (int i = 0; i < numVolStructs; ++i) { map::iterator iter = volCache.find(volList[i]); CaretAssert(iter != volCache.end()); processRowVolume(iter->second, inRow, outRow, myInputXML, voldilatemm, volDilateMethod, volDilateExponent, unassignedLabelKey[row], warpfield, NULL, myVolMethod, volLegacyCutoff); } myCiftiOut->setRow(outRow.data(), row); } } } AlgorithmCiftiResample::AlgorithmCiftiResample(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const int& direction, const CiftiFile* myTemplate, const int& templateDir, const SurfaceResamplingMethodEnum::Enum& mySurfMethod, const VolumeFile::InterpType& myVolMethod, CiftiFile* myCiftiOut, const bool& surfLargest, const float& voldilatemm, const float& surfdilatemm, const FloatMatrix& affine, const SurfaceFile* curLeftSphere, const SurfaceFile* newLeftSphere, const MetricFile* curLeftAreas, const MetricFile* newLeftAreas, const SurfaceFile* curRightSphere, const SurfaceFile* newRightSphere, const MetricFile* curRightAreas, const MetricFile* newRightAreas, const SurfaceFile* curCerebSphere, const SurfaceFile* newCerebSphere, const MetricFile* curCerebAreas, const MetricFile* newCerebAreas, const AlgorithmVolumeDilate::Method& volDilateMethod, const float& volDilateExponent, const AlgorithmMetricDilate::Method& surfDilateMethod, const float& surfDilateExponent, const bool volLegacyCutoff, const bool surfLegacyCutoff) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); pair myError = checkForErrors(myCiftiIn, direction, myTemplate, templateDir, mySurfMethod, curLeftSphere, newLeftSphere, curLeftAreas, newLeftAreas, curRightSphere, newRightSphere, curRightAreas, newRightAreas, curCerebSphere, newCerebSphere, curCerebAreas, newCerebAreas); if (myError.first) throw AlgorithmException(myError.second); const CiftiXML& myInputXML = myCiftiIn->getCiftiXML(); CiftiXML myOutXML = myInputXML; myOutXML.setMap(direction, *(myTemplate->getCiftiXML().getMap(templateDir))); const CiftiBrainModelsMap& outModels = myOutXML.getBrainModelsMap(direction); vector surfList = outModels.getSurfaceStructureList(), volList = outModels.getVolumeStructureList(); myCiftiOut->setCiftiXML(myOutXML); if (direction == CiftiXML::ALONG_COLUMN) { for (int i = 0; i < (int)surfList.size(); ++i)//and now, resampling { const SurfaceFile* curSphere = NULL, *newSphere = NULL; const MetricFile* curAreas = NULL, *newAreas = NULL; switch (surfList[i]) { case StructureEnum::CORTEX_LEFT: curSphere = curLeftSphere; newSphere = newLeftSphere; curAreas = curLeftAreas; newAreas = newLeftAreas; break; case StructureEnum::CORTEX_RIGHT: curSphere = curRightSphere; newSphere = newRightSphere; curAreas = curRightAreas; newAreas = newRightAreas; break; case StructureEnum::CEREBELLUM: curSphere = curCerebSphere; newSphere = newCerebSphere; curAreas = curCerebAreas; newAreas = newCerebAreas; break; default: throw AlgorithmException("unsupported surface structure: " + StructureEnum::toGuiName(surfList[i])); break; } processSurfaceComponent(myCiftiIn, direction, surfList[i], mySurfMethod, myCiftiOut, surfLargest, surfdilatemm, curSphere, newSphere, curAreas, newAreas, surfDilateMethod, surfDilateExponent, surfLegacyCutoff); } for (int i = 0; i < (int)volList.size(); ++i) { processVolume(myCiftiIn, direction, volList[i], myVolMethod, myCiftiOut, voldilatemm, NULL, &affine, volDilateMethod, volDilateExponent, volLegacyCutoff); } } else {//avoid cifti separate/replace with ALONG_ROW bool labelMode = (myInputXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::LABELS); vector surfList = outModels.getSurfaceStructureList(), volList = outModels.getVolumeStructureList(); int numSurfStructs = (int)surfList.size(), numVolStructs = (int)volList.size(); vector unassignedLabelKey; if (labelMode) { const CiftiLabelsMap& myLabelMap = myInputXML.getLabelsMap(CiftiXML::ALONG_COLUMN); unassignedLabelKey.resize(myLabelMap.getLength()); for (int i = 0; i < myLabelMap.getLength(); ++i) { unassignedLabelKey[i] = myLabelMap.getMapLabelTable(i)->getUnassignedLabelKey(); } } map surfCache, volCache;//could make them different types, but whatever - two variables in case of structure overlap in surface and volume, as some members may get used by both setupRowResampling(surfCache, volCache, myCiftiIn, myCiftiOut, mySurfMethod, voldilatemm, &affine, NULL, curLeftSphere, newLeftSphere, curLeftAreas, newLeftAreas, curRightSphere, newRightSphere, curRightAreas, newRightAreas, curCerebSphere, newCerebSphere, curCerebAreas, newCerebAreas); int64_t numRows = myInputXML.getDimensionLength(CiftiXML::ALONG_COLUMN); vector inRow(myInputXML.getDimensionLength(CiftiXML::ALONG_ROW)), outRow(myOutXML.getDimensionLength(CiftiXML::ALONG_ROW)); for (int64_t row = 0; row < numRows; ++row) { myCiftiIn->getRow(inRow.data(), row); for (int i = 0; i < numSurfStructs; ++i) { map::iterator iter = surfCache.find(surfList[i]); CaretAssert(iter != surfCache.end()); processRowSurface(iter->second, inRow, outRow, myInputXML, surfdilatemm, surfLargest, unassignedLabelKey[row], row, surfDilateMethod, surfDilateExponent, surfLegacyCutoff); } for (int i = 0; i < numVolStructs; ++i) { map::iterator iter = volCache.find(volList[i]); CaretAssert(iter != volCache.end()); processRowVolume(iter->second, inRow, outRow, myInputXML, voldilatemm, volDilateMethod, volDilateExponent, unassignedLabelKey[row], NULL, &affine, myVolMethod, volLegacyCutoff); } myCiftiOut->setRow(outRow.data(), row); } } } void AlgorithmCiftiResample::processSurfaceComponent(const CiftiFile* myCiftiIn, const int& direction, const StructureEnum::Enum& myStruct, const SurfaceResamplingMethodEnum::Enum& mySurfMethod, CiftiFile* myCiftiOut, const bool& surfLargest, const float& surfdilatemm, const SurfaceFile* curSphere, const SurfaceFile* newSphere, const MetricFile* curAreas, const MetricFile* newAreas, const AlgorithmMetricDilate::Method& surfDilateMethod, const float& surfDilateExponent, const bool surfLegacyCutoff) { const CiftiXML& myInputXML = myCiftiIn->getCiftiXML(); if (myInputXML.getMappingType(1 - direction) == CiftiMappingType::LABELS) { LabelFile origLabel; MetricFile origRoi, resampleROI; AlgorithmCiftiSeparate(NULL, myCiftiIn, direction, myStruct, &origLabel, &origRoi); LabelFile newLabel, newDilate, *newUse = &newLabel; if (curSphere != NULL) { AlgorithmLabelResample(NULL, &origLabel, curSphere, newSphere, mySurfMethod, &newLabel, curAreas, newAreas, &origRoi, &resampleROI, surfLargest); origLabel.clear();//delete the data we no longer need to keep memory use down if (surfdilatemm > 0.0f) { MetricFile invertResampleROI; invertResampleROI.setNumberOfNodesAndColumns(resampleROI.getNumberOfNodes(), 1); for (int j = 0; j < resampleROI.getNumberOfNodes(); ++j) { float tempf = (resampleROI.getValue(j, 0) > 0.0f) ? 0.0f : 1.0f;//make an inverse ROI invertResampleROI.setValue(j, 0, tempf); } AlgorithmLabelDilate(NULL, &newLabel, newSphere, surfdilatemm, &newDilate, &invertResampleROI); newLabel.clear();//ditto newUse = &newDilate; } } else { newUse = &origLabel; } AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, direction, myStruct, newUse); } else { MetricFile origMetric, origROI; AlgorithmCiftiSeparate(NULL, myCiftiIn, direction, myStruct, &origMetric, &origROI); MetricFile newMetric, newDilate, resampleROI, *newUse = &newMetric; if (curSphere != NULL) { AlgorithmMetricResample(NULL, &origMetric, curSphere, newSphere, mySurfMethod, &newMetric, curAreas, newAreas, &origROI, &resampleROI, surfLargest); origMetric.clear();//ditto if (surfdilatemm > 0.0f) { MetricFile invertResampleROI; invertResampleROI.setNumberOfNodesAndColumns(resampleROI.getNumberOfNodes(), 1); for (int j = 0; j < resampleROI.getNumberOfNodes(); ++j) { float tempf = (resampleROI.getValue(j, 0) > 0.0f) ? 0.0f : 1.0f;//make an inverse ROI invertResampleROI.setValue(j, 0, tempf); } AlgorithmMetricDilate(NULL, &newMetric, newSphere, surfdilatemm, &newDilate, &invertResampleROI, NULL, -1, surfDilateMethod, surfDilateExponent, NULL, surfLegacyCutoff);//we could get the data roi from the template cifti and use it here newMetric.clear(); newUse = &newDilate; } } else { newUse = &origMetric; } AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, direction, myStruct, newUse); } } void AlgorithmCiftiResample::processVolume(const CiftiFile* myCiftiIn, const int& direction, const StructureEnum::Enum& myStruct, const VolumeFile::InterpType& myVolMethod, CiftiFile* myCiftiOut, const float& voldilatemm, const VolumeFile* warpfield, const FloatMatrix* affine, const AlgorithmVolumeDilate::Method& volDilateMethod, const float& volDilateExponent, const bool volLegacyCutoff) { VolumeFile origData, origDilate, origROI, ROIDilate, *origProcess, *ROIProcess; origProcess = &origData; ROIProcess = &origROI; int64_t offset[3]; const int neighbors[] = { 0, 0, -1, 0, -1, 0, -1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 }; const bool doEdgeAdjust = (myVolMethod == VolumeFile::CUBIC);//if someone asks for cubic resampling of label data, allow strange things to happen (there will be a warning from resample) vector edgeVoxelList; AlgorithmCiftiSeparate(NULL, myCiftiIn, direction, myStruct, &origData, offset, &origROI, true); vector origDims = origData.getDimensions(); if (voldilatemm > 0.0f) { vector spatialDims = origDims;//make the bad voxel roi by inverting spatialDims.resize(3); int64_t framesize = origDims[0] * origDims[1] * origDims[2]; vector scratchframe(framesize); const float* roiframe = origROI.getFrame(); for (int64_t i = 0; i < framesize; ++i) { scratchframe[i] = (roiframe[i] > 0.0f ? 0.0f : 1.0f); } VolumeFile origPad, invertROI, invertROIPad; invertROI.reinitialize(spatialDims, origData.getSform()); invertROI.setFrame(scratchframe.data()); VolumePaddingHelper mypadding = VolumePaddingHelper::padMM(&origData, voldilatemm); mypadding.doPadding(&origData, &origPad); origData.clear();//free data copies we no longer need mypadding.doPadding(&invertROI, &invertROIPad, 1.0f);//pad with ones since this is an inverted ROI AlgorithmVolumeDilate(NULL, &origPad, voldilatemm, volDilateMethod, &origDilate, &invertROIPad, NULL, -1, volDilateExponent, volLegacyCutoff); origPad.clear();//ditto origProcess = &origDilate; if (doEdgeAdjust) {//we need to use the dilated ROI VolumeFile ROIPad; mypadding.doPadding(&origROI, &ROIPad); AlgorithmVolumeDilate(NULL, &ROIPad, voldilatemm, AlgorithmVolumeDilate::NEAREST, &ROIDilate, &invertROIPad); ROIProcess = &ROIDilate; vector paddedDims = ROIPad.getDimensions(); for (int64_t k = 0; k < paddedDims[2]; ++k) { for (int64_t j = 0; j < paddedDims[1]; ++j) { for (int64_t i = 0; i < paddedDims[0]; ++i) { if (ROIDilate.getValue(i, j, k) > 0.0f) { for (int n = 0; n < 6; ++n) { VoxelIJK thisVoxel = VoxelIJK(i + neighbors[j * 3 + 0], j + neighbors[j * 3 + 1], k + neighbors[j * 3 + 2]); if (ROIDilate.indexValid(thisVoxel.m_ijk) && ROIDilate.getValue(thisVoxel.m_ijk) == 0.0f)//trick: if it is merely touching an FOV edge, cubic won't cause ringing there, so ignore that voxel { edgeVoxelList.push_back(VoxelIJK(i, j, k)); break; } } } } } } } } else {//if we don't dilate, we can use cifti to find the used voxels if (doEdgeAdjust) { vector myMap = myCiftiIn->getCiftiXML().getBrainModelsMap(direction).getVolumeStructureMap(myStruct); for (int64_t i = 0; i < (int64_t)myMap.size(); ++i) { for (int j = 0; j < 6; ++j) { VoxelIJK thisVoxel = VoxelIJK(myMap[i].m_ijk[0] - offset[0] + neighbors[j * 3 + 0], myMap[i].m_ijk[1] - offset[1] + neighbors[j * 3 + 1], myMap[i].m_ijk[2] - offset[2] + neighbors[j * 3 + 2]); if (origROI.indexValid(thisVoxel.m_ijk) && origROI.getValue(thisVoxel.m_ijk) == 0.0f)//trick: if it is merely touching an FOV edge, cubic won't cause ringing there, so ignore that voxel { edgeVoxelList.push_back(VoxelIJK(myMap[i].m_ijk[0] - offset[0], myMap[i].m_ijk[1] - offset[1], myMap[i].m_ijk[2] - offset[2])); break; } } } } } if (doEdgeAdjust) { vector currentDims = origProcess->getDimensions(); int64_t framesize = currentDims[0] * currentDims[1] * currentDims[2]; vector scratchframe(framesize); const float* ROIFrame = ROIProcess->getFrame(); for (int64_t b = 0; b < origDims[3]; ++b) {//input is cifti, no RGB or complex types double edgesum = 0.0; for (int64_t i = 0; i < (int64_t)edgeVoxelList.size(); ++i) { edgesum += origProcess->getValue(edgeVoxelList[i].m_ijk, b); } float edgeMean = edgesum / edgeVoxelList.size(); const float* dataFrame = origProcess->getFrame(b); for (int64_t i = 0; i < framesize; ++i) { scratchframe[i] = (ROIFrame[i] > 0.0f ? dataFrame[i] : edgeMean);//trick: set the background to the edge mean so we don't need to readjust data values after resampling } origProcess->setFrame(scratchframe.data(), b); } } VolumeFile newVolume; int64_t refdims[3], refoffset[3]; vector > refsform; AlgorithmCiftiSeparate::getCroppedVolSpace(myCiftiOut, direction, myStruct, refdims, refsform, refoffset); if (warpfield != NULL) { AlgorithmVolumeWarpfieldResample(NULL, origProcess, warpfield, refdims, refsform, myVolMethod, &newVolume); } else { AlgorithmVolumeAffineResample(NULL, origProcess, *affine, refdims, refsform, myVolMethod, &newVolume); } origProcess->clear(); if (doEdgeAdjust) {//to make it obvious when the dilation didn't cover the output ROI, mask the result with the (dilated) input ROI VolumeFile newROI;//trilinear masked at 0.5 should give somewhat better downsampling behavior than enclosing if (warpfield != NULL) { AlgorithmVolumeWarpfieldResample(NULL, ROIProcess, warpfield, refdims, refsform, VolumeFile::TRILINEAR, &newROI); } else { AlgorithmVolumeAffineResample(NULL, ROIProcess, *affine, refdims, refsform, VolumeFile::TRILINEAR, &newROI); } const float* roiFrame = newROI.getFrame(); int64_t framesize = refdims[0] * refdims[1] * refdims[2]; vector scratchframe(framesize, 0.0f); for (int64_t b = 0; b < origDims[3]; ++b) { const float* dataFrame = newVolume.getFrame(b); for (int64_t i = 0; i < framesize; ++i) { if (roiFrame[i] > 0.5f) { scratchframe[i] = dataFrame[i]; } } newVolume.setFrame(scratchframe.data(), b); } } AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, direction, myStruct, &newVolume, true); } float AlgorithmCiftiResample::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiResample::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiResample.h000066400000000000000000000147601360521144700253120ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_RESAMPLE_H__ #define __ALGORITHM_CIFTI_RESAMPLE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "AlgorithmMetricDilate.h" //for dilate method enums #include "AlgorithmVolumeDilate.h" #include "FloatMatrix.h" #include "StructureEnum.h" #include "SurfaceResamplingMethodEnum.h" #include "VolumeFile.h" #include //for pair namespace caret { class AlgorithmCiftiResample : public AbstractAlgorithm { AlgorithmCiftiResample(); void processSurfaceComponent(const CiftiFile* myCiftiIn, const int& direction, const StructureEnum::Enum& myStruct, const SurfaceResamplingMethodEnum::Enum& mySurfMethod, CiftiFile* myCiftiOut, const bool& surfLargest, const float& surfdilatemm, const SurfaceFile* curSphere, const SurfaceFile* newSphere, const MetricFile* curAreas, const MetricFile* newAreas, const AlgorithmMetricDilate::Method& surfDilateMethod, const float& surfDilateExponent, const bool surfLegacyCutoff); void processVolume(const CiftiFile* myCiftiIn, const int& direction, const StructureEnum::Enum& myStruct, const VolumeFile::InterpType& myVolMethod, CiftiFile* myCiftiOut, const float& voldilatemm, const VolumeFile* warpfield, const FloatMatrix* affine, const AlgorithmVolumeDilate::Method& volDilateMethod, const float& volDilateExponent, const bool volLegacyCutoff); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: //so that other code that uses it more than once can pre-check things - returns true for error present! static std::pair checkForErrors(const CiftiFile* myCiftiIn, const int& direction, const CiftiFile* myTemplate, const int& templateDir, const SurfaceResamplingMethodEnum::Enum& mySurfMethod, const SurfaceFile* curLeftSphere, const SurfaceFile* newLeftSphere, const MetricFile* curLeftAreas, const MetricFile* newLeftAreas, const SurfaceFile* curRightSphere, const SurfaceFile* newRightSphere, const MetricFile* curRightAreas, const MetricFile* newRightAreas, const SurfaceFile* curCerebSphere, const SurfaceFile* newCerebSphere, const MetricFile* curCerebAreas, const MetricFile* newCerebAreas); AlgorithmCiftiResample(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const int& direction, const CiftiFile* myTemplate, const int& templateDir, const SurfaceResamplingMethodEnum::Enum& mySurfMethod, const VolumeFile::InterpType& myVolMethod, CiftiFile* myCiftiOut, const bool& surfLargest, const float& voldilatemm, const float& surfdilatemm, const VolumeFile* warpfield, const SurfaceFile* curLeftSphere, const SurfaceFile* newLeftSphere, const MetricFile* curLeftAreas, const MetricFile* newLeftAreas, const SurfaceFile* curRightSphere, const SurfaceFile* newRightSphere, const MetricFile* curRightAreas, const MetricFile* newRightAreas, const SurfaceFile* curCerebSphere, const SurfaceFile* newCerebSphere, const MetricFile* curCerebAreas, const MetricFile* newCerebAreas, const AlgorithmVolumeDilate::Method& volDilateMethod = AlgorithmVolumeDilate::WEIGHTED, const float& volDilateExponent = 7.0f, const AlgorithmMetricDilate::Method& surfDilateMethod = AlgorithmMetricDilate::WEIGHTED, const float& surfDilateExponent = 6.0f, const bool volLegacyCutoff = false, const bool surfLegacyCutoff = false); AlgorithmCiftiResample(ProgressObject* myProgObj, const CiftiFile* myCiftiIn, const int& direction, const CiftiFile* myTemplate, const int& templateDir, const SurfaceResamplingMethodEnum::Enum& mySurfMethod, const VolumeFile::InterpType& myVolMethod, CiftiFile* myCiftiOut, const bool& surfLargest, const float& voldilatemm, const float& surfdilatemm, const FloatMatrix& affine, const SurfaceFile* curLeftSphere, const SurfaceFile* newLeftSphere, const MetricFile* curLeftAreas, const MetricFile* newLeftAreas, const SurfaceFile* curRightSphere, const SurfaceFile* newRightSphere, const MetricFile* curRightAreas, const MetricFile* newRightAreas, const SurfaceFile* curCerebSphere, const SurfaceFile* newCerebSphere, const MetricFile* curCerebAreas, const MetricFile* newCerebAreas, const AlgorithmVolumeDilate::Method& volDilateMethod = AlgorithmVolumeDilate::WEIGHTED, const float& volDilateExponent = 7.0f, const AlgorithmMetricDilate::Method& surfDilateMethod = AlgorithmMetricDilate::WEIGHTED, const float& surfDilateExponent = 6.0f, const bool volLegacyCutoff = false, const bool surfLegacyCutoff = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiResample; } #endif //__ALGORITHM_CIFTI_RESAMPLE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiRestrictDenseMap.cxx000066400000000000000000000416071360521144700273310ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiRestrictDenseMap.h" #include "AlgorithmException.h" #include "CaretLogger.h" #include "CiftiFile.h" #include "MetricFile.h" #include "MultiDimIterator.h" #include "VolumeFile.h" #include using namespace caret; using namespace std; AString AlgorithmCiftiRestrictDenseMap::getCommandSwitch() { return "-cifti-restrict-dense-map"; } AString AlgorithmCiftiRestrictDenseMap::getShortDescription() { return "EXCLUDE BRAINORDINATES FROM A CIFTI FILE"; } OperationParameters* AlgorithmCiftiRestrictDenseMap::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-in", "the input cifti"); ret->addStringParameter(2, "direction", "which dimension to change the mapping on (integer, 'ROW', or 'COLUMN')"); ret->addCiftiOutputParameter(3, "cifti-out", "the output cifti"); OptionalParameter* ciftiRoiOpt = ret->createOptionalParameter(4, "-cifti-roi", "cifti file containing combined rois"); ciftiRoiOpt->addCiftiParameter(1, "roi-cifti", "the rois as a cifti file"); OptionalParameter* leftRoiOpt = ret->createOptionalParameter(5, "-left-roi", "vertices to use from left hemisphere"); leftRoiOpt->addMetricParameter(1, "roi-metric", "the left roi as a metric file"); OptionalParameter* rightRoiOpt = ret->createOptionalParameter(6, "-right-roi", "vertices to use from right hemisphere"); rightRoiOpt->addMetricParameter(1, "roi-metric", "the right roi as a metric file"); OptionalParameter* cerebRoiOpt = ret->createOptionalParameter(7, "-cerebellum-roi", "vertices to use from cerebellum"); cerebRoiOpt->addMetricParameter(1, "roi-metric", "the cerebellum roi as a metric file"); OptionalParameter* volRoiOpt = ret->createOptionalParameter(8, "-vol-roi", "voxels to use"); volRoiOpt->addVolumeParameter(1, "roi-vol", "the roi volume file"); ret->setHelpText( AString("Writes a modified version of , where all brainordinates outside the specified roi(s) are removed from the file. ") + CiftiXML::directionFromStringExplanation() + " " + "If -cifti-roi is specified, no other -*-roi option may be specified. " + "If not using -cifti-roi, any -*-roi options not present will discard the relevant structure, if present in the input file." ); return ret; } void AlgorithmCiftiRestrictDenseMap::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { const CiftiFile* ciftiIn = myParams->getCifti(1); int direction = CiftiXML::directionFromString(myParams->getString(2)); CiftiFile* ciftiOut = myParams->getOutputCifti(3); OptionalParameter* ciftiRoiOpt = myParams->getOptionalParameter(4); OptionalParameter* leftRoiOpt = myParams->getOptionalParameter(5); OptionalParameter* rightRoiOpt = myParams->getOptionalParameter(6); OptionalParameter* cerebRoiOpt = myParams->getOptionalParameter(7); OptionalParameter* volRoiOpt = myParams->getOptionalParameter(8); if (ciftiRoiOpt->m_present) { if (leftRoiOpt->m_present || rightRoiOpt->m_present || cerebRoiOpt->m_present || volRoiOpt->m_present) { throw AlgorithmException("-cifti-roi cannot be specified with any other roi option"); } const CiftiFile* ciftiRoi = ciftiRoiOpt->getCifti(1); AlgorithmCiftiRestrictDenseMap(myProgObj, ciftiIn, direction, ciftiOut, ciftiRoi); } else { if (!(leftRoiOpt->m_present || rightRoiOpt->m_present || cerebRoiOpt->m_present || volRoiOpt->m_present)) { throw AlgorithmException("you must specify at least one roi option"); } const MetricFile* leftRoi = NULL, *rightRoi = NULL, *cerebRoi = NULL; const VolumeFile* volRoi = NULL; if (leftRoiOpt->m_present) leftRoi = leftRoiOpt->getMetric(1); if (rightRoiOpt->m_present) rightRoi = rightRoiOpt->getMetric(1); if (cerebRoiOpt->m_present) cerebRoi = cerebRoiOpt->getMetric(1); if (volRoiOpt->m_present) volRoi = volRoiOpt->getVolume(1); AlgorithmCiftiRestrictDenseMap(myProgObj, ciftiIn, direction, ciftiOut, leftRoi, rightRoi, cerebRoi, volRoi); } } AlgorithmCiftiRestrictDenseMap::AlgorithmCiftiRestrictDenseMap(ProgressObject* myProgObj, const CiftiFile* ciftiIn, const int& direction, CiftiFile* ciftiOut, const CiftiFile* ciftiRoi) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CaretAssert(direction >= 0); const CiftiXML& inXML = ciftiIn->getCiftiXML(), &roiXML = ciftiRoi->getCiftiXML(); if (direction >= inXML.getNumberOfDimensions()) { throw AlgorithmException("invalid direction for input file"); } if (inXML.getMappingType(direction) != CiftiMappingType::BRAIN_MODELS) { throw AlgorithmException("input does not have a brain models mapping along specified direction"); } if (roiXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) { throw AlgorithmException("roi does not have a brain models mapping along column"); } const CiftiBrainModelsMap& inMap = inXML.getBrainModelsMap(direction); if (!inMap.approximateMatch(roiXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN))) {//for now, require that the brain models mappings use the same vertices/voxels, but allow for unusual surface structures not available in the metric/volume version throw AlgorithmException("roi cifti brain models mapping doesn't match the input cifti"); }//alternatively, could separate and call the other version if they don't match, but could be more confusing vector roiData(roiXML.getDimensionLength(CiftiXML::ALONG_COLUMN)); ciftiRoi->getColumn(roiData.data(), 0);//we only need 1 column from the roi CiftiBrainModelsMap outMap; if (inMap.hasVolumeData()) { outMap.setVolumeSpace(inMap.getVolumeSpace()); } vector translate; vector modelInfo = inMap.getModelInfo(); for (int i = 0; i < (int)modelInfo.size(); ++i) { switch (modelInfo[i].m_type) { case CiftiBrainModelsMap::SURFACE: { vector surfMap = inMap.getSurfaceMap(modelInfo[i].m_structure); vector usedNodes; for (size_t j = 0; j < surfMap.size(); ++j) { if (roiData[surfMap[j].m_ciftiIndex] > 0.0f) { usedNodes.push_back(surfMap[j].m_surfaceNode); translate.push_back(surfMap[j].m_ciftiIndex); } } if (!usedNodes.empty()) { outMap.addSurfaceModel(inMap.getSurfaceNumberOfNodes(modelInfo[i].m_structure), modelInfo[i].m_structure, usedNodes); } break; } case CiftiBrainModelsMap::VOXELS: { vector volMap = inMap.getVolumeStructureMap(modelInfo[i].m_structure); vector usedVoxels; for (size_t j = 0; j < volMap.size(); ++j) { if (roiData[volMap[j].m_ciftiIndex] > 0.0f) { usedVoxels.push_back(volMap[j].m_ijk[0]); usedVoxels.push_back(volMap[j].m_ijk[1]); usedVoxels.push_back(volMap[j].m_ijk[2]); translate.push_back(volMap[j].m_ciftiIndex); } } if (!usedVoxels.empty()) { outMap.addVolumeModel(modelInfo[i].m_structure, usedVoxels); } break; } } } if (outMap.getLength() == 0) { throw AlgorithmException("output mapping would contain no brainordinates"); } CiftiXML outXML = inXML; outXML.setMap(direction, outMap); ciftiOut->setCiftiXML(outXML); vector outDims = outXML.getDimensions(); vector scratchRow(inXML.getDimensionLength(CiftiXML::ALONG_ROW)); if (direction == CiftiXML::ALONG_ROW) { vector outRow(outMap.getLength()); for (MultiDimIterator iter(vector(outDims.begin() + 1, outDims.end())); !iter.atEnd(); ++iter) { ciftiIn->getRow(scratchRow.data(), *iter); for (size_t i = 0; i < translate.size(); ++i) { outRow[i] = scratchRow[translate[i]]; } ciftiOut->setRow(outRow.data(), *iter); } } else { for (MultiDimIterator iter(vector(outDims.begin() + 1, outDims.end())); !iter.atEnd(); ++iter) { vector indices = *iter; indices[direction - 1] = translate[(*iter)[direction - 1]]; ciftiIn->getRow(scratchRow.data(), indices); ciftiOut->setRow(scratchRow.data(), *iter); } } } AlgorithmCiftiRestrictDenseMap::AlgorithmCiftiRestrictDenseMap(ProgressObject* myProgObj, const CiftiFile* ciftiIn, const int& direction, CiftiFile* ciftiOut, const MetricFile* leftRoi, const MetricFile* rightRoi, const MetricFile* cerebRoi, const VolumeFile* volRoi) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CaretAssert(direction >= 0); const CiftiXML& inXML = ciftiIn->getCiftiXML(); if (direction >= inXML.getNumberOfDimensions()) { throw AlgorithmException("invalid direction for input file"); } if (inXML.getMappingType(direction) != CiftiMappingType::BRAIN_MODELS) { throw AlgorithmException("input does not have a brain models mapping along specified direction"); } const CiftiBrainModelsMap& inMap = inXML.getBrainModelsMap(direction); if (leftRoi != NULL) { if (!inMap.hasSurfaceData(StructureEnum::CORTEX_LEFT)) { throw AlgorithmException("left surface roi provided, but input has no left surface data"); } if (leftRoi->getNumberOfNodes() != inMap.getSurfaceNumberOfNodes(StructureEnum::CORTEX_LEFT)) { throw AlgorithmException("left surface roi has different number of vertices than input cifti"); } } if (rightRoi != NULL) { if (!inMap.hasSurfaceData(StructureEnum::CORTEX_RIGHT)) { throw AlgorithmException("right surface roi provided, but input has no left surface data"); } if (rightRoi->getNumberOfNodes() != inMap.getSurfaceNumberOfNodes(StructureEnum::CORTEX_RIGHT)) { throw AlgorithmException("right surface roi has different number of vertices than input cifti"); } } if (cerebRoi != NULL) { if (!inMap.hasSurfaceData(StructureEnum::CEREBELLUM)) { throw AlgorithmException("cerebellum surface roi provided, but input has no left surface data"); } if (cerebRoi->getNumberOfNodes() != inMap.getSurfaceNumberOfNodes(StructureEnum::CEREBELLUM)) { throw AlgorithmException("cerebellum surface roi has different number of vertices than input cifti"); } } if (volRoi != NULL) { if (!inMap.hasVolumeData()) throw AlgorithmException("volume roi provided, but input has no volume data"); if (!inMap.getVolumeSpace().matches(volRoi->getVolumeSpace())) throw AlgorithmException("roi volume has different volume space than input cifti"); } CiftiBrainModelsMap outMap; if (inMap.hasVolumeData() && volRoi != NULL) { outMap.setVolumeSpace(inMap.getVolumeSpace()); } vector translate; vector modelInfo = inMap.getModelInfo(); for (int i = 0; i < (int)modelInfo.size(); ++i) { switch (modelInfo[i].m_type) { case CiftiBrainModelsMap::SURFACE: { const MetricFile* useRoi = NULL; switch (modelInfo[i].m_structure) { case StructureEnum::CORTEX_LEFT: useRoi = leftRoi; break; case StructureEnum::CORTEX_RIGHT: useRoi = rightRoi; break; case StructureEnum::CEREBELLUM: useRoi = cerebRoi; break; default: CaretLogWarning("removing unsupported surface structure: '" + StructureEnum::toName(modelInfo[i].m_structure) + "'"); break;//remove other surface structures, but warn } if (useRoi != NULL) { const float* roiData = useRoi->getValuePointerForColumn(0); vector surfMap = inMap.getSurfaceMap(modelInfo[i].m_structure); vector usedNodes; for (size_t j = 0; j < surfMap.size(); ++j) { if (roiData[surfMap[j].m_surfaceNode] > 0.0f) { usedNodes.push_back(surfMap[j].m_surfaceNode); translate.push_back(surfMap[j].m_ciftiIndex); } } if (!usedNodes.empty()) { outMap.addSurfaceModel(inMap.getSurfaceNumberOfNodes(modelInfo[i].m_structure), modelInfo[i].m_structure, usedNodes); } } break; } case CiftiBrainModelsMap::VOXELS: { if (volRoi != NULL) { vector volMap = inMap.getVolumeStructureMap(modelInfo[i].m_structure); vector usedVoxels; for (size_t j = 0; j < volMap.size(); ++j) { if (volRoi->getValue(volMap[j].m_ijk) > 0.0f) { usedVoxels.push_back(volMap[j].m_ijk[0]); usedVoxels.push_back(volMap[j].m_ijk[1]); usedVoxels.push_back(volMap[j].m_ijk[2]); translate.push_back(volMap[j].m_ciftiIndex); } } if (!usedVoxels.empty()) { outMap.addVolumeModel(modelInfo[i].m_structure, usedVoxels); } } break; } } } if (outMap.getLength() == 0) { throw AlgorithmException("output mapping would contain no brainordinates"); } CiftiXML outXML = inXML; outXML.setMap(direction, outMap); ciftiOut->setCiftiXML(outXML); vector outDims = outXML.getDimensions(); vector scratchRow(inXML.getDimensionLength(CiftiXML::ALONG_ROW)); if (direction == CiftiXML::ALONG_ROW) { vector outRow(outMap.getLength()); for (MultiDimIterator iter(vector(outDims.begin() + 1, outDims.end())); !iter.atEnd(); ++iter) { ciftiIn->getRow(scratchRow.data(), *iter); for (size_t i = 0; i < translate.size(); ++i) { outRow[i] = scratchRow[translate[i]]; } ciftiOut->setRow(outRow.data(), *iter); } } else { for (MultiDimIterator iter(vector(outDims.begin() + 1, outDims.end())); !iter.atEnd(); ++iter) { vector indices = *iter; indices[direction - 1] = translate[(*iter)[direction - 1]]; ciftiIn->getRow(scratchRow.data(), indices); ciftiOut->setRow(scratchRow.data(), *iter); } } } float AlgorithmCiftiRestrictDenseMap::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiRestrictDenseMap::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiRestrictDenseMap.h000066400000000000000000000041131360521144700267450ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_RESTRICT_DENSE_MAP_H__ #define __ALGORITHM_CIFTI_RESTRICT_DENSE_MAP_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmCiftiRestrictDenseMap : public AbstractAlgorithm { AlgorithmCiftiRestrictDenseMap(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiRestrictDenseMap(ProgressObject* myProgObj, const CiftiFile* ciftiIn, const int& direction, CiftiFile* ciftiOut, const CiftiFile* ciftiRoi); AlgorithmCiftiRestrictDenseMap(ProgressObject* myProgObj, const CiftiFile* ciftiIn, const int& direction, CiftiFile* ciftiOut, const MetricFile* leftRoi, const MetricFile* rightRoi = NULL, const MetricFile* cerebRoi = NULL, const VolumeFile* volRoi = NULL); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiRestrictDenseMap; } #endif //__ALGORITHM_CIFTI_RESTRICT_DENSE_MAP_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiSeparate.cxx000066400000000000000000001044401360521144700256540ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiSeparate.h" #include "AlgorithmException.h" #include "CaretLogger.h" #include "CaretPointer.h" #include "CiftiFile.h" #include "GiftiLabelTable.h" #include "LabelFile.h" #include "MetricFile.h" #include "Vector3D.h" #include "VolumeFile.h" #include #include using namespace caret; using namespace std; AString AlgorithmCiftiSeparate::getCommandSwitch() { return "-cifti-separate"; } AString AlgorithmCiftiSeparate::getShortDescription() { return "WRITE A CIFTI STRUCTURE AS METRIC, LABEL OR VOLUME"; } OperationParameters* AlgorithmCiftiSeparate::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-in", "the cifti to separate a component of"); ret->addStringParameter(2, "direction", "which direction to separate into components, ROW or COLUMN"); ParameterComponent* labelOpt = ret->createRepeatableParameter(3, "-label", "separate a surface model into a surface label file"); labelOpt->addStringParameter(1, "structure", "the structure to output"); labelOpt->addLabelOutputParameter(2, "label-out", "the output label file"); OptionalParameter* labelRoiOpt = labelOpt->createOptionalParameter(3, "-roi", "also output the roi of which vertices have data"); labelRoiOpt->addMetricOutputParameter(1, "roi-out", "the roi output metric"); ParameterComponent* metricOpt = ret->createRepeatableParameter(4, "-metric", "separate a surface model into a metric file"); metricOpt->addStringParameter(1, "structure", "the structure to output"); metricOpt->addMetricOutputParameter(2, "metric-out", "the output metric"); OptionalParameter* metricRoiOpt = metricOpt->createOptionalParameter(3, "-roi", "also output the roi of which vertices have data"); metricRoiOpt->addMetricOutputParameter(1, "roi-out", "the roi output metric"); ParameterComponent* volumeOpt = ret->createRepeatableParameter(5, "-volume", "separate a volume structure into a volume file"); volumeOpt->addStringParameter(1, "structure", "the structure to output"); volumeOpt->addVolumeOutputParameter(2, "volume-out", "the output volume"); OptionalParameter* volumeRoiOpt = volumeOpt->createOptionalParameter(3, "-roi", "also output the roi of which voxels have data"); volumeRoiOpt->addVolumeOutputParameter(1, "roi-out", "the roi output volume"); volumeOpt->createOptionalParameter(4, "-crop", "crop volume to the size of the component rather than using the original volume size"); OptionalParameter* volumeAllOpt = ret->createOptionalParameter(6, "-volume-all", "separate all volume structures into a volume file"); volumeAllOpt->addVolumeOutputParameter(1, "volume-out", "the output volume"); OptionalParameter* volumeAllRoiOpt = volumeAllOpt->createOptionalParameter(2, "-roi", "also output the roi of which voxels have data"); volumeAllRoiOpt->addVolumeOutputParameter(1, "roi-out", "the roi output volume"); OptionalParameter* volumeAllLabelOpt = volumeAllOpt->createOptionalParameter(4, "-label", "output a volume label file indicating the location of structures"); volumeAllLabelOpt->addVolumeOutputParameter(1, "label-out", "the label output volume"); volumeAllOpt->createOptionalParameter(3, "-crop", "crop volume to the size of the data rather than using the original volume size"); AString helpText = AString("For dtseries, dscalar, and dlabel, use COLUMN for , and if you have a symmetric dconn, COLUMN is more efficient.\n\n") + "You must specify at least one of -metric, -volume-all, -volume, or -label for this command to do anything. " + "Output volumes will spatially line up with their original positions, whether or not they are cropped. " + "Volume files produced by separating a dlabel file, or from the -label suboption of -volume-all, will be label volumes, see -volume-help.\n\n" + "For each argument, use one of the following strings:\n"; vector myStructureEnums; StructureEnum::getAllEnums(myStructureEnums); for (int i = 0; i < (int)myStructureEnums.size(); ++i) { helpText += "\n" + StructureEnum::toName(myStructureEnums[i]); } ret->setHelpText(helpText); return ret; } void AlgorithmCiftiSeparate::useParameters(OperationParameters* myParams, ProgressObject* /*myProgObj*/) {//ignore the progress object for now, and allow specifying multiple options at once CiftiFile* ciftiIn = myParams->getCifti(1); AString dirName = myParams->getString(2); int myDir; if (dirName == "ROW") { myDir = CiftiXML::ALONG_ROW; } else if (dirName == "COLUMN") { myDir = CiftiXML::ALONG_COLUMN; } else { throw AlgorithmException("incorrect string for direction, use ROW or COLUMN"); } bool outputRequested = false; const vector& labelInstances = *(myParams->getRepeatableParameterInstances(3)); for (int i = 0; i < (int)labelInstances.size(); ++i) { outputRequested = true; AString structName = labelInstances[i]->getString(1); bool ok = false; StructureEnum::Enum myStruct = StructureEnum::fromName(structName, &ok); if (!ok) { throw AlgorithmException("unrecognized structure type: '" + structName + "'"); } LabelFile* labelOut = labelInstances[i]->getOutputLabel(2); MetricFile* roiOut = NULL; OptionalParameter* labelRoiOpt = labelInstances[i]->getOptionalParameter(3); if (labelRoiOpt->m_present) { roiOut = labelRoiOpt->getOutputMetric(1); } AlgorithmCiftiSeparate(NULL, ciftiIn, myDir, myStruct, labelOut, roiOut); } const vector& metricInstances = *(myParams->getRepeatableParameterInstances(4)); for (int i = 0; i < (int)metricInstances.size(); ++i) { outputRequested = true; AString structName = metricInstances[i]->getString(1); bool ok = false; StructureEnum::Enum myStruct = StructureEnum::fromName(structName, &ok); if (!ok) { throw AlgorithmException("unrecognized structure type: '" + structName + "'"); } MetricFile* metricOut = metricInstances[i]->getOutputMetric(2); MetricFile* roiOut = NULL; OptionalParameter* metricRoiOpt = metricInstances[i]->getOptionalParameter(3); if (metricRoiOpt->m_present) { roiOut = metricRoiOpt->getOutputMetric(1); } AlgorithmCiftiSeparate(NULL, ciftiIn, myDir, myStruct, metricOut, roiOut); } const vector& volumeInstances = *(myParams->getRepeatableParameterInstances(5)); for (int i = 0; i < (int)volumeInstances.size(); ++i) { outputRequested = true; AString structName = volumeInstances[i]->getString(1); bool ok = false; StructureEnum::Enum myStruct = StructureEnum::fromName(structName, &ok); if (!ok) { throw AlgorithmException("unrecognized structure type: '" + structName + "'"); } VolumeFile* volOut = volumeInstances[i]->getOutputVolume(2); VolumeFile* roiOut = NULL; OptionalParameter* volumeRoiOpt = volumeInstances[i]->getOptionalParameter(3); if (volumeRoiOpt->m_present) { roiOut = volumeRoiOpt->getOutputVolume(1); } bool cropVol = volumeInstances[i]->getOptionalParameter(4)->m_present; int64_t offset[3]; AlgorithmCiftiSeparate(NULL, ciftiIn, myDir, myStruct, volOut, offset, roiOut, cropVol); } OptionalParameter* volumeAllOpt = myParams->getOptionalParameter(6); if (volumeAllOpt->m_present) { outputRequested = true; VolumeFile* volOut = volumeAllOpt->getOutputVolume(1); VolumeFile* roiOut = NULL; OptionalParameter* volumeAllRoiOpt = volumeAllOpt->getOptionalParameter(2); if (volumeAllRoiOpt->m_present) { roiOut = volumeAllRoiOpt->getOutputVolume(1); } bool cropVol = volumeAllOpt->getOptionalParameter(3)->m_present; VolumeFile* labelOut = NULL; OptionalParameter* volumeAllLabelOpt = volumeAllOpt->getOptionalParameter(4); if (volumeAllLabelOpt->m_present) { labelOut = volumeAllLabelOpt->getOutputVolume(1); } int64_t offset[3]; AlgorithmCiftiSeparate(NULL, ciftiIn, myDir, volOut, offset, roiOut, cropVol, labelOut); } if (!outputRequested) { CaretLogWarning("no output requested from -cifti-separate, command will do nothing"); } } AlgorithmCiftiSeparate::AlgorithmCiftiSeparate(ProgressObject* myProgObj, const CiftiFile* ciftiIn, const int& myDir, const StructureEnum::Enum& myStruct, MetricFile* metricOut, MetricFile* roiOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const CiftiXML& myXML = ciftiIn->getCiftiXML(); if (myXML.getNumberOfDimensions() != 2) throw AlgorithmException("cifti separate only supported on 2D cifti"); if (myDir >= myXML.getNumberOfDimensions() || myDir < 0) throw AlgorithmException("direction invalid for input cifti"); if (myXML.getMappingType(myDir) != CiftiMappingType::BRAIN_MODELS) throw AlgorithmException("specified direction does not contain brain models"); if (myXML.getMappingType(1 - myDir) == CiftiMappingType::LABELS) CaretLogWarning("creating a metric file from cifti label data"); const CiftiBrainModelsMap& myBrainModelsMap = myXML.getBrainModelsMap(myDir); if (!myBrainModelsMap.hasSurfaceData(myStruct)) throw AlgorithmException("specified file and direction does not contain the requested surface structure '" + StructureEnum::toName(myStruct) + "'"); vector myMap = myBrainModelsMap.getSurfaceMap(myStruct); int rowSize = ciftiIn->getNumberOfColumns(), colSize = ciftiIn->getNumberOfRows(); if (myDir == CiftiXML::ALONG_COLUMN) { int64_t numNodes = myBrainModelsMap.getSurfaceNumberOfNodes(myStruct); metricOut->setNumberOfNodesAndColumns(numNodes, rowSize); metricOut->setStructure(myStruct); const CiftiMappingType& myNamesMap = *(myXML.getMap(1 - myDir)); for (int j = 0; j < rowSize; ++j) { metricOut->setMapName(j, myNamesMap.getIndexName(j)); } if (roiOut != NULL) { roiOut->setNumberOfNodesAndColumns(numNodes, 1); roiOut->setStructure(myStruct); } int mapSize = (int)myMap.size(); CaretArray rowScratch(rowSize); CaretArray nodeUsed(numNodes, 0.0f); for (int i = 0; i < mapSize; ++i) { ciftiIn->getRow(rowScratch, myMap[i].m_ciftiIndex); nodeUsed[myMap[i].m_surfaceNode] = 1.0f; for (int j = 0; j < rowSize; ++j) { metricOut->setValue(myMap[i].m_surfaceNode, j, rowScratch[j]); } } if (roiOut != NULL) { roiOut->setValuesForColumn(0, nodeUsed); } for (int i = 0; i < numNodes; ++i)//zero unused columns { if (nodeUsed[i] == 0.0f) { for (int j = 0; j < rowSize; ++j) { metricOut->setValue(i, j, 0.0f); } } } } else { int64_t numNodes = myBrainModelsMap.getSurfaceNumberOfNodes(myStruct); metricOut->setNumberOfNodesAndColumns(numNodes, colSize); metricOut->setStructure(myStruct); const CiftiMappingType& myNamesMap = *(myXML.getMap(1 - myDir)); for (int j = 0; j < colSize; ++j) { metricOut->setMapName(j, myNamesMap.getIndexName(j)); } if (roiOut != NULL) { roiOut->setNumberOfNodesAndColumns(numNodes, 1); roiOut->setStructure(myStruct); } int mapSize = (int)myMap.size(); CaretArray rowScratch(rowSize), metricScratch(numNodes, 0.0f); if (roiOut != NULL) { CaretArray nodeUsed(numNodes, 0.0f); for (int i = 0; i < mapSize; ++i) { nodeUsed[myMap[i].m_surfaceNode] = 1.0f; } roiOut->setValuesForColumn(0, nodeUsed); } for (int i = 0; i < colSize; ++i) { ciftiIn->getRow(rowScratch, i); for (int j = 0; j < mapSize; ++j) { metricScratch[myMap[j].m_surfaceNode] = rowScratch[myMap[j].m_ciftiIndex]; } metricOut->setValuesForColumn(i, metricScratch); } } } AlgorithmCiftiSeparate::AlgorithmCiftiSeparate(ProgressObject* myProgObj, const CiftiFile* ciftiIn, const int& myDir, const StructureEnum::Enum& myStruct, LabelFile* labelOut, MetricFile* roiOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const CiftiXML& myXML = ciftiIn->getCiftiXML(); if (myXML.getNumberOfDimensions() != 2) throw AlgorithmException("cifti separate only supported on 2D cifti"); if (myDir >= myXML.getNumberOfDimensions() || myDir < 0) throw AlgorithmException("direction invalid for input cifti"); if (myXML.getMappingType(myDir) != CiftiMappingType::BRAIN_MODELS) throw AlgorithmException("specified direction does not contain brain models"); if (myXML.getMappingType(1 - myDir) != CiftiMappingType::LABELS) throw AlgorithmException("label separate requested on non-label cifti"); const CiftiBrainModelsMap& myBrainModelsMap = myXML.getBrainModelsMap(myDir); const CiftiLabelsMap& myLabelsMap = myXML.getLabelsMap(1 - myDir); if (!myBrainModelsMap.hasSurfaceData(myStruct)) throw AlgorithmException("specified file and direction does not contain the requested surface structure '" + StructureEnum::toName(myStruct) + "'"); vector myMap = myBrainModelsMap.getSurfaceMap(myStruct); int64_t rowSize = ciftiIn->getNumberOfColumns(), colSize = ciftiIn->getNumberOfRows(); if (myDir == CiftiXML::ALONG_COLUMN) { int64_t numNodes = myBrainModelsMap.getSurfaceNumberOfNodes(myStruct); labelOut->setNumberOfNodesAndColumns(numNodes, rowSize); labelOut->setStructure(myStruct); const CiftiMappingType& myNamesMap = *(myXML.getMap(1 - myDir)); for (int j = 0; j < rowSize; ++j) { labelOut->setMapName(j, myNamesMap.getIndexName(j)); } if (roiOut != NULL) { roiOut->setNumberOfNodesAndColumns(numNodes, 1); roiOut->setStructure(myStruct); } int64_t mapSize = (int64_t)myMap.size(); CaretArray rowScratch(rowSize); CaretArray nodeUsed(numNodes, 0.0f); GiftiLabelTable myTable; map cumulativeRemap; for (int64_t i = 0; i < rowSize; ++i) { map thisRemap = myTable.append(*(myLabelsMap.getMapLabelTable(i))); cumulativeRemap.insert(thisRemap.begin(), thisRemap.end()); } for (int64_t i = 0; i < mapSize; ++i) { ciftiIn->getRow(rowScratch, myMap[i].m_ciftiIndex); nodeUsed[myMap[i].m_surfaceNode] = 1.0f; for (int j = 0; j < rowSize; ++j) { int32_t inVal = (int32_t)floor(rowScratch[j] + 0.5f); map::const_iterator iter = cumulativeRemap.find(inVal); if (iter == cumulativeRemap.end()) { labelOut->setLabelKey(myMap[i].m_surfaceNode, j, inVal); } else { labelOut->setLabelKey(myMap[i].m_surfaceNode, j, iter->second); } } } *(labelOut->getLabelTable()) = myTable; int32_t unusedLabel = myTable.getUnassignedLabelKey(); if (roiOut != NULL) { roiOut->setValuesForColumn(0, nodeUsed); } for (int i = 0; i < numNodes; ++i)//set unused columns to unassigned { if (nodeUsed[i] == 0.0f) { for (int j = 0; j < rowSize; ++j) { labelOut->setLabelKey(i, j, unusedLabel); } } } } else { int64_t numNodes = myBrainModelsMap.getSurfaceNumberOfNodes(myStruct); labelOut->setNumberOfNodesAndColumns(numNodes, colSize); labelOut->setStructure(myStruct); const CiftiMappingType& myNamesMap = *(myXML.getMap(1 - myDir)); for (int j = 0; j < colSize; ++j) { labelOut->setMapName(j, myNamesMap.getIndexName(j)); } if (roiOut != NULL) { roiOut->setNumberOfNodesAndColumns(numNodes, 1); roiOut->setStructure(myStruct); } int64_t mapSize = (int)myMap.size(); if (roiOut != NULL) { CaretArray nodeUsed(numNodes, 0.0f); for (int i = 0; i < mapSize; ++i) { nodeUsed[myMap[i].m_surfaceNode] = 1.0f; } roiOut->setValuesForColumn(0, nodeUsed); } CaretArray rowScratch(rowSize); CaretArray nodeUsed(numNodes, 0); for (int64_t j = 0; j < mapSize; ++j) { nodeUsed[myMap[j].m_surfaceNode] = 1; } GiftiLabelTable myTable; map cumulativeRemap; for (int64_t i = 0; i < colSize; ++i) { map thisRemap = myTable.append(*(myLabelsMap.getMapLabelTable(i))); cumulativeRemap.insert(thisRemap.begin(), thisRemap.end()); } *(labelOut->getLabelTable()) = myTable; int32_t unusedLabel = myTable.getUnassignedLabelKey(); for (int64_t i = 0; i < colSize; ++i) { ciftiIn->getRow(rowScratch, i); for (int64_t j = 0; j < mapSize; ++j) { int32_t inVal = (int32_t)floor(rowScratch[j] + 0.5f); map::const_iterator iter = cumulativeRemap.find(inVal); if (iter == cumulativeRemap.end()) { labelOut->setLabelKey(myMap[j].m_surfaceNode, i, inVal); } else { labelOut->setLabelKey(myMap[j].m_surfaceNode, i, iter->second); } } for (int64_t j = 0; j < numNodes; ++j)//set unused columns to unassigned { if (nodeUsed[j] == 0) { labelOut->setLabelKey(j, i, unusedLabel); } } } } } AlgorithmCiftiSeparate::AlgorithmCiftiSeparate(ProgressObject* myProgObj, const CiftiFile* ciftiIn, const int& myDir, const StructureEnum::Enum& myStruct, VolumeFile* volOut, int64_t offsetOut[3], VolumeFile* roiOut, const bool& cropVol) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const CiftiXML& myXML = ciftiIn->getCiftiXML(); if (myXML.getNumberOfDimensions() != 2) throw AlgorithmException("cifti separate only supported on 2D cifti"); if (myDir >= ciftiIn->getCiftiXML().getNumberOfDimensions() || myDir < 0) throw AlgorithmException("direction invalid for input cifti"); if (myXML.getMappingType(myDir) != CiftiMappingType::BRAIN_MODELS) throw AlgorithmException("specified direction does not contain brain models"); int rowSize = ciftiIn->getNumberOfColumns(), colSize = ciftiIn->getNumberOfRows(); const CiftiBrainModelsMap& myBrainMap = myXML.getBrainModelsMap(myDir); const int64_t* myDims = myBrainMap.getVolumeSpace().getDims(); vector > mySform = myBrainMap.getVolumeSpace().getSform(); if (!myBrainMap.hasVolumeData(myStruct)) throw AlgorithmException("specified file and direction does not contain the requested volume structure"); vector myMap = myBrainMap.getVolumeStructureMap(myStruct); vector newdims; int64_t numVoxels = (int64_t)myMap.size(); if (cropVol) { newdims.resize(3); getCroppedVolSpace(ciftiIn, myDir, myStruct, newdims.data(), mySform, offsetOut); } else { newdims.push_back(myDims[0]); newdims.push_back(myDims[1]); newdims.push_back(myDims[2]); offsetOut[0] = 0; offsetOut[1] = 0; offsetOut[2] = 0; } if (roiOut != NULL) { roiOut->reinitialize(newdims, mySform); roiOut->setValueAllVoxels(0.0f); } CaretArray rowScratch(rowSize); if (myDir == CiftiXML::ALONG_COLUMN) { if (rowSize > 1) newdims.push_back(rowSize); volOut->reinitialize(newdims, mySform); volOut->setValueAllVoxels(0.0f); const CiftiMappingType& myNamesMap = *(myXML.getMap(1 - myDir)); for (int j = 0; j < rowSize; ++j) { volOut->setMapName(j, myNamesMap.getIndexName(j)); } if (myXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::LABELS) { const CiftiLabelsMap& myLabelsMap = myXML.getLabelsMap(CiftiXML::ALONG_ROW); volOut->setType(SubvolumeAttributes::LABEL); for (int j = 0; j < rowSize; ++j) { *(volOut->getMapLabelTable(j)) = *(myLabelsMap.getMapLabelTable(j)); } } for (int64_t i = 0; i < numVoxels; ++i) { int64_t thisvoxel[3] = { myMap[i].m_ijk[0] - offsetOut[0], myMap[i].m_ijk[1] - offsetOut[1], myMap[i].m_ijk[2] - offsetOut[2] }; if (roiOut != NULL) { roiOut->setValue(1.0f, thisvoxel); } ciftiIn->getRow(rowScratch, myMap[i].m_ciftiIndex); for (int j = 0; j < rowSize; ++j) { volOut->setValue(rowScratch[j], thisvoxel, j); } } } else { if (colSize > 1) newdims.push_back(colSize); volOut->reinitialize(newdims, mySform); volOut->setValueAllVoxels(0.0f); const CiftiMappingType& myNamesMap = *(myXML.getMap(1 - myDir)); for (int j = 0; j < colSize; ++j) { volOut->setMapName(j, myNamesMap.getIndexName(j)); } if (myXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::LABELS) { const CiftiLabelsMap& myLabelsMap = myXML.getLabelsMap(CiftiXML::ALONG_COLUMN); volOut->setType(SubvolumeAttributes::LABEL); for (int j = 0; j < colSize; ++j) { *(volOut->getMapLabelTable(j)) = *(myLabelsMap.getMapLabelTable(j)); } } for (int64_t i = 0; i < colSize; ++i) { ciftiIn->getRow(rowScratch, i); for (int64_t j = 0; j < numVoxels; ++j) { int64_t thisvoxel[3] = { myMap[j].m_ijk[0] - offsetOut[0], myMap[j].m_ijk[1] - offsetOut[1], myMap[j].m_ijk[2] - offsetOut[2] }; if (i == 0 && roiOut != NULL) { roiOut->setValue(1.0f, thisvoxel); } volOut->setValue(rowScratch[myMap[j].m_ciftiIndex], thisvoxel, i); } } } } AlgorithmCiftiSeparate::AlgorithmCiftiSeparate(ProgressObject* myProgObj, const CiftiFile* ciftiIn, const int& myDir, VolumeFile* volOut, int64_t offsetOut[3], VolumeFile* roiOut, const bool& cropVol, VolumeFile* labelOut): AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const CiftiXML& myXML = ciftiIn->getCiftiXML(); if (myXML.getNumberOfDimensions() != 2) throw AlgorithmException("cifti separate only supported on 2D cifti"); if (myDir >= ciftiIn->getCiftiXML().getNumberOfDimensions() || myDir < 0) throw AlgorithmException("direction invalid for input cifti"); if (myXML.getMappingType(myDir) != CiftiMappingType::BRAIN_MODELS) throw AlgorithmException("specified direction does not contain brain models"); int rowSize = ciftiIn->getNumberOfColumns(), colSize = ciftiIn->getNumberOfRows(); const CiftiBrainModelsMap& myBrainMap = myXML.getBrainModelsMap(myDir); if (!myBrainMap.hasVolumeData()) throw AlgorithmException("specified file and direction does not contain any volume data"); const int64_t* myDims = myBrainMap.getVolumeSpace().getDims(); vector > mySform = myBrainMap.getVolumeSpace().getSform(); vector newdims; if (cropVol) { newdims.resize(3); getCroppedVolSpaceAll(ciftiIn, myDir, newdims.data(), mySform, offsetOut); } else { newdims.push_back(myDims[0]); newdims.push_back(myDims[1]); newdims.push_back(myDims[2]); offsetOut[0] = 0; offsetOut[1] = 0; offsetOut[2] = 0; } if (labelOut != NULL) { labelOut->reinitialize(newdims, mySform, 1, SubvolumeAttributes::LABEL); labelOut->setValueAllVoxels(0.0f);//unlabeled key defaults to 0 vector volStructs = myBrainMap.getVolumeStructureList(); GiftiLabelTable structureTable; for (int i = 0; i < (int)volStructs.size(); ++i) { const int32_t structKey = structureTable.addLabel(StructureEnum::toName(volStructs[i]), rand() & 255, rand() & 255, rand() & 255, 255); const vector& voxelList = myBrainMap.getVoxelList(volStructs[i]); int64_t structVoxels = (int64_t)voxelList.size(); for (int64_t j = 0; j < structVoxels; j += 3) { labelOut->setValue(structKey, voxelList[j] - offsetOut[0], voxelList[j + 1] - offsetOut[1], voxelList[j + 2] - offsetOut[2]); } } *(labelOut->getMapLabelTable(0)) = structureTable; } if (roiOut != NULL) { roiOut->reinitialize(newdims, mySform); roiOut->setValueAllVoxels(0.0f); } vector myMap = myBrainMap.getFullVolumeMap(); int64_t numVoxels = (int64_t)myMap.size(); CaretArray rowScratch(rowSize); if (myDir == CiftiXML::ALONG_COLUMN) { if (rowSize > 1) newdims.push_back(rowSize); volOut->reinitialize(newdims, mySform); volOut->setValueAllVoxels(0.0f); const CiftiMappingType& myNamesMap = *(myXML.getMap(1 - myDir)); for (int j = 0; j < rowSize; ++j) { volOut->setMapName(j, myNamesMap.getIndexName(j)); } if (myXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::LABELS) { const CiftiLabelsMap& myLabelsMap = myXML.getLabelsMap(CiftiXML::ALONG_ROW); volOut->setType(SubvolumeAttributes::LABEL); for (int j = 0; j < rowSize; ++j) { *(volOut->getMapLabelTable(j)) = *(myLabelsMap.getMapLabelTable(j)); } } for (int64_t i = 0; i < numVoxels; ++i) { int64_t thisvoxel[3] = { myMap[i].m_ijk[0] - offsetOut[0], myMap[i].m_ijk[1] - offsetOut[1], myMap[i].m_ijk[2] - offsetOut[2] }; if (roiOut != NULL) { roiOut->setValue(1.0f, thisvoxel); } ciftiIn->getRow(rowScratch, myMap[i].m_ciftiIndex); for (int j = 0; j < rowSize; ++j) { volOut->setValue(rowScratch[j], thisvoxel, j); } } } else { if (colSize > 1) newdims.push_back(colSize); volOut->reinitialize(newdims, mySform); volOut->setValueAllVoxels(0.0f); const CiftiMappingType& myNamesMap = *(myXML.getMap(1 - myDir)); for (int j = 0; j < colSize; ++j) { volOut->setMapName(j, myNamesMap.getIndexName(j)); } if (myXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::LABELS) { const CiftiLabelsMap& myLabelsMap = myXML.getLabelsMap(CiftiXML::ALONG_COLUMN); volOut->setType(SubvolumeAttributes::LABEL); for (int j = 0; j < colSize; ++j) { *(volOut->getMapLabelTable(j)) = *(myLabelsMap.getMapLabelTable(j)); } } for (int64_t i = 0; i < colSize; ++i) { ciftiIn->getRow(rowScratch, i); for (int64_t j = 0; j < numVoxels; ++j) { int64_t thisvoxel[3] = { myMap[j].m_ijk[0] - offsetOut[0], myMap[j].m_ijk[1] - offsetOut[1], myMap[j].m_ijk[2] - offsetOut[2] }; if (i == 0 && roiOut != NULL) { roiOut->setValue(1.0f, thisvoxel); } volOut->setValue(rowScratch[myMap[j].m_ciftiIndex], thisvoxel, i); } } } } void AlgorithmCiftiSeparate::getCroppedVolSpace(const CiftiFile* ciftiIn, const int& myDir, const StructureEnum::Enum& myStruct, int64_t dimsOut[3], vector >& sformOut, int64_t offsetOut[3]) { const CiftiXML& myXML = ciftiIn->getCiftiXML(); if (myXML.getMappingType(myDir) != CiftiMappingType::BRAIN_MODELS) throw AlgorithmException("specified direction does not contain brain models"); const CiftiBrainModelsMap& myBrainMap = myXML.getBrainModelsMap(myDir); sformOut = myBrainMap.getVolumeSpace().getSform(); vector myMap = myBrainMap.getVolumeStructureMap(myStruct); int64_t numVoxels = (int64_t)myMap.size(); if (numVoxels > 0) {//make a voxel bounding box to minimize memory usage int extrema[6] = { myMap[0].m_ijk[0], myMap[0].m_ijk[0], myMap[0].m_ijk[1], myMap[0].m_ijk[1], myMap[0].m_ijk[2], myMap[0].m_ijk[2] }; for (int64_t i = 1; i < numVoxels; ++i) { if (myMap[i].m_ijk[0] < extrema[0]) extrema[0] = myMap[i].m_ijk[0]; if (myMap[i].m_ijk[0] > extrema[1]) extrema[1] = myMap[i].m_ijk[0]; if (myMap[i].m_ijk[1] < extrema[2]) extrema[2] = myMap[i].m_ijk[1]; if (myMap[i].m_ijk[1] > extrema[3]) extrema[3] = myMap[i].m_ijk[1]; if (myMap[i].m_ijk[2] < extrema[4]) extrema[4] = myMap[i].m_ijk[2]; if (myMap[i].m_ijk[2] > extrema[5]) extrema[5] = myMap[i].m_ijk[2]; } dimsOut[0] = extrema[1] - extrema[0] + 1; dimsOut[1] = extrema[3] - extrema[2] + 1; dimsOut[2] = extrema[5] - extrema[4] + 1; offsetOut[0] = extrema[0]; offsetOut[1] = extrema[2]; offsetOut[2] = extrema[4]; Vector3D ivec, jvec, kvec, shift; ivec[0] = sformOut[0][0]; ivec[1] = sformOut[1][0]; ivec[2] = sformOut[2][0]; jvec[0] = sformOut[0][1]; jvec[1] = sformOut[1][1]; jvec[2] = sformOut[2][1]; kvec[0] = sformOut[0][2]; kvec[1] = sformOut[1][2]; kvec[2] = sformOut[2][2]; shift = offsetOut[0] * ivec + offsetOut[1] * jvec + offsetOut[2] * kvec; sformOut[0][3] += shift[0];//fix the sform to align to the old position with the new dimensions sformOut[1][3] += shift[1]; sformOut[2][3] += shift[2]; } else { throw AlgorithmException("cropped volume requested, but no voxels exist in this structure"); } } void AlgorithmCiftiSeparate::getCroppedVolSpaceAll(const CiftiFile* ciftiIn, const int& myDir, int64_t dimsOut[3], vector >& sformOut, int64_t offsetOut[3]) { const CiftiXML& myXML = ciftiIn->getCiftiXML(); if (myXML.getMappingType(myDir) != CiftiMappingType::BRAIN_MODELS) throw AlgorithmException("specified direction does not contain brain models"); const CiftiBrainModelsMap& myBrainMap = myXML.getBrainModelsMap(myDir); sformOut = myBrainMap.getVolumeSpace().getSform(); vector myMap = myBrainMap.getFullVolumeMap(); int64_t numVoxels = (int64_t)myMap.size(); if (numVoxels > 0) {//make a voxel bounding box to minimize memory usage int extrema[6] = { myMap[0].m_ijk[0], myMap[0].m_ijk[0], myMap[0].m_ijk[1], myMap[0].m_ijk[1], myMap[0].m_ijk[2], myMap[0].m_ijk[2] }; for (int64_t i = 1; i < numVoxels; ++i) { if (myMap[i].m_ijk[0] < extrema[0]) extrema[0] = myMap[i].m_ijk[0]; if (myMap[i].m_ijk[0] > extrema[1]) extrema[1] = myMap[i].m_ijk[0]; if (myMap[i].m_ijk[1] < extrema[2]) extrema[2] = myMap[i].m_ijk[1]; if (myMap[i].m_ijk[1] > extrema[3]) extrema[3] = myMap[i].m_ijk[1]; if (myMap[i].m_ijk[2] < extrema[4]) extrema[4] = myMap[i].m_ijk[2]; if (myMap[i].m_ijk[2] > extrema[5]) extrema[5] = myMap[i].m_ijk[2]; } dimsOut[0] = extrema[1] - extrema[0] + 1; dimsOut[1] = extrema[3] - extrema[2] + 1; dimsOut[2] = extrema[5] - extrema[4] + 1; offsetOut[0] = extrema[0]; offsetOut[1] = extrema[2]; offsetOut[2] = extrema[4]; Vector3D ivec, jvec, kvec, shift; ivec[0] = sformOut[0][0]; ivec[1] = sformOut[1][0]; ivec[2] = sformOut[2][0]; jvec[0] = sformOut[0][1]; jvec[1] = sformOut[1][1]; jvec[2] = sformOut[2][1]; kvec[0] = sformOut[0][2]; kvec[1] = sformOut[1][2]; kvec[2] = sformOut[2][2]; shift = offsetOut[0] * ivec + offsetOut[1] * jvec + offsetOut[2] * kvec; sformOut[0][3] += shift[0];//fix the sform to align to the old position with the new dimensions sformOut[1][3] += shift[1]; sformOut[2][3] += shift[2]; } else { throw AlgorithmException("cropped volume requested, but no voxels exist in the specified direction"); } } float AlgorithmCiftiSeparate::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiSeparate::getSubAlgorithmWeight() { return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiSeparate.h000066400000000000000000000060421360521144700253000ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_SEPARATE_H__ #define __ALGORITHM_CIFTI_SEPARATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "StructureEnum.h" #include namespace caret { class AlgorithmCiftiSeparate : public AbstractAlgorithm { AlgorithmCiftiSeparate(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiSeparate(ProgressObject* myProgObj, const CiftiFile* ciftiIn, const int& myDir, const StructureEnum::Enum& myStruct, MetricFile* metricOut, MetricFile* roiOut = NULL); AlgorithmCiftiSeparate(ProgressObject* myProgObj, const CiftiFile* ciftiIn, const int& myDir, const StructureEnum::Enum& myStruct, LabelFile* labelOut, MetricFile* roiOut = NULL); AlgorithmCiftiSeparate(ProgressObject* myProgObj, const CiftiFile* ciftiIn, const int& myDir, const StructureEnum::Enum& myStruct, VolumeFile* volOut, int64_t offsetOut[3], VolumeFile* roiOut = NULL, const bool& cropVol = true); AlgorithmCiftiSeparate(ProgressObject* myProgObj, const CiftiFile* ciftiIn, const int& myDir, VolumeFile* volOut, int64_t offsetOut[3], VolumeFile* roiOut = NULL, const bool& cropVol = true, VolumeFile* labelOut = NULL); static void getCroppedVolSpace(const CiftiFile* ciftiIn, const int& myDir, const StructureEnum::Enum& myStruct, int64_t dimsOut[3], std::vector >& sformOut, int64_t offsetOut[3]); static void getCroppedVolSpaceAll(const CiftiFile* ciftiIn, const int& myDir, int64_t dimsOut[3], std::vector >& sformOut, int64_t offsetOut[3]); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiSeparate; } #endif //__ALGORITHM_CIFTI_SEPARATE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiSmoothing.cxx000066400000000000000000000356071360521144700260670ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiSmoothing.h" #include "AlgorithmException.h" #include "AlgorithmMetricSmoothing.h" #include "AlgorithmVolumeSmoothing.h" #include "CiftiFile.h" #include "MetricFile.h" #include "VolumeFile.h" #include "SurfaceFile.h" #include "AlgorithmCiftiSeparate.h" #include "AlgorithmCiftiReplaceStructure.h" using namespace caret; using namespace std; AString AlgorithmCiftiSmoothing::getCommandSwitch() { return "-cifti-smoothing"; } AString AlgorithmCiftiSmoothing::getShortDescription() { return "SMOOTH A CIFTI FILE"; } OperationParameters* AlgorithmCiftiSmoothing::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti", "the input cifti"); ret->addDoubleParameter(2, "surface-kernel", "the sigma for the gaussian surface smoothing kernel, in mm"); ret->addDoubleParameter(3, "volume-kernel", "the sigma for the gaussian volume smoothing kernel, in mm"); ret->addStringParameter(4, "direction", "which dimension to smooth along, ROW or COLUMN"); ret->addCiftiOutputParameter(5, "cifti-out", "the output cifti"); OptionalParameter* leftSurfOpt = ret->createOptionalParameter(6, "-left-surface", "specify the left surface to use"); leftSurfOpt->addSurfaceParameter(1, "surface", "the left surface file"); OptionalParameter* leftCorrAreasOpt = leftSurfOpt->createOptionalParameter(2, "-left-corrected-areas", "vertex areas to use instead of computing them from the left surface"); leftCorrAreasOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); OptionalParameter* rightSurfOpt = ret->createOptionalParameter(7, "-right-surface", "specify the right surface to use"); rightSurfOpt->addSurfaceParameter(1, "surface", "the right surface file"); OptionalParameter* rightCorrAreasOpt = rightSurfOpt->createOptionalParameter(2, "-right-corrected-areas", "vertex areas to use instead of computing them from the right surface"); rightCorrAreasOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); OptionalParameter* cerebSurfOpt = ret->createOptionalParameter(8, "-cerebellum-surface", "specify the cerebellum surface to use"); cerebSurfOpt->addSurfaceParameter(1, "surface", "the cerebellum surface file"); OptionalParameter* cerebCorrAreasOpt = cerebSurfOpt->createOptionalParameter(2, "-cerebellum-corrected-areas", "vertex areas to use instead of computing them from the cerebellum surface"); cerebCorrAreasOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); OptionalParameter* roiOpt = ret->createOptionalParameter(9, "-cifti-roi", "smooth only within regions of interest"); roiOpt->addCiftiParameter(1, "roi-cifti", "the regions to smooth within, as a cifti file"); ret->createOptionalParameter(10, "-fix-zeros-volume", "treat values of zero in the volume as missing data"); ret->createOptionalParameter(11, "-fix-zeros-surface", "treat values of zero on the surface as missing data"); ret->createOptionalParameter(12, "-merged-volume", "smooth across subcortical structure boundaries"); ret->setHelpText( AString("The input cifti file must have a brain models mapping on the chosen dimension, columns for .dtseries, and either for .dconn. ") + "By default, data in different structures is smoothed independently (i.e., \"parcel constrained\" smoothing), so volume structures that touch do not smooth across this boundary. " + "Specify -merged-volume to ignore these boundaries. " + "Surface smoothing uses the GEO_GAUSS_AREA smoothing method.\n\n" + "The -*-corrected-areas options are intended for when it is unavoidable to smooth on group average surfaces, it is only an approximate correction " + "for the reduction of structure in a group average surface. It is better to smooth the data on individuals before averaging, when feasible.\n\n" + "The -fix-zeros-* options will treat values of zero as lack of data, and not use that value when generating the smoothed values, but will fill zeros with extrapolated values. " + "The ROI should have a brain models mapping along columns, exactly matching the mapping of the chosen direction in the input file. " + "Data outside the ROI is ignored." ); return ret; } void AlgorithmCiftiSmoothing::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* myCifti = myParams->getCifti(1); float surfKern = (float)myParams->getDouble(2); float volKern = (float)myParams->getDouble(3); AString directionName = myParams->getString(4); int myDir; if (directionName == "ROW") { myDir = CiftiXMLOld::ALONG_ROW; } else if (directionName == "COLUMN") { myDir = CiftiXMLOld::ALONG_COLUMN; } else { throw AlgorithmException("incorrect string for direction, use ROW or COLUMN"); } CiftiFile* myCiftiOut = myParams->getOutputCifti(5); SurfaceFile* myLeftSurf = NULL, *myRightSurf = NULL, *myCerebSurf = NULL; MetricFile* myLeftAreas = NULL, *myRightAreas = NULL, *myCerebAreas = NULL; OptionalParameter* leftSurfOpt = myParams->getOptionalParameter(6); if (leftSurfOpt->m_present) { myLeftSurf = leftSurfOpt->getSurface(1); OptionalParameter* leftCorrAreasOpt = leftSurfOpt->getOptionalParameter(2); if (leftCorrAreasOpt->m_present) { myLeftAreas = leftCorrAreasOpt->getMetric(1); } } OptionalParameter* rightSurfOpt = myParams->getOptionalParameter(7); if (rightSurfOpt->m_present) { myRightSurf = rightSurfOpt->getSurface(1); OptionalParameter* rightCorrAreasOpt = rightSurfOpt->getOptionalParameter(2); if (rightCorrAreasOpt->m_present) { myRightAreas = rightCorrAreasOpt->getMetric(1); } } OptionalParameter* cerebSurfOpt = myParams->getOptionalParameter(8); if (cerebSurfOpt->m_present) { myCerebSurf = cerebSurfOpt->getSurface(1); OptionalParameter* cerebCorrAreasOpt = cerebSurfOpt->getOptionalParameter(2); if (cerebCorrAreasOpt->m_present) { myCerebAreas = cerebCorrAreasOpt->getMetric(1); } } CiftiFile* roiCifti = NULL; OptionalParameter* roiOpt = myParams->getOptionalParameter(9); if (roiOpt->m_present) { roiCifti = roiOpt->getCifti(1); } bool fixZerosVol = myParams->getOptionalParameter(10)->m_present; bool fixZerosSurf = myParams->getOptionalParameter(11)->m_present; bool mergedVolume = myParams->getOptionalParameter(12)->m_present; AlgorithmCiftiSmoothing(myProgObj, myCifti, surfKern, volKern, myDir, myCiftiOut, myLeftSurf, myRightSurf, myCerebSurf, roiCifti, fixZerosVol, fixZerosSurf, myLeftAreas, myRightAreas, myCerebAreas, mergedVolume); } AlgorithmCiftiSmoothing::AlgorithmCiftiSmoothing(ProgressObject* myProgObj, const CiftiFile* myCifti, const float& surfKern, const float& volKern, const int& myDir, CiftiFile* myCiftiOut, const SurfaceFile* myLeftSurf, const SurfaceFile* myRightSurf, const SurfaceFile* myCerebSurf, const CiftiFile* roiCifti, bool fixZerosVol, bool fixZerosSurf, const MetricFile* myLeftAreas, const MetricFile* myRightAreas, const MetricFile* myCerebAreas, const bool& mergedVolume) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (!(surfKern > 0.0f) && !(volKern > 0.0f)) throw AlgorithmException("zero smoothing kernels requested for both volume and surface"); const CiftiXMLOld& myXML = myCifti->getCiftiXMLOld(); vector surfaceList, volumeList; if (myDir == CiftiXMLOld::ALONG_COLUMN) { if (!myXML.getStructureListsForColumns(surfaceList, volumeList)) { throw AlgorithmException("specified direction does not contain brainordinates"); } } else { if (myDir != CiftiXMLOld::ALONG_ROW) throw AlgorithmException("direction not supported in AlgorithmCiftiSmoothing"); if (!myXML.getStructureListsForRows(surfaceList, volumeList)) { throw AlgorithmException("specified direction does not contain brainordinates"); } } if (roiCifti != NULL && !myXML.mappingMatches(myDir, roiCifti->getCiftiXMLOld(), CiftiXMLOld::ALONG_COLUMN)) { throw AlgorithmException("along-column mapping of roi cifti does not match the smoothing direction of the input cifti"); } for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) {//sanity check surfaces const SurfaceFile* mySurf = NULL; const MetricFile* myAreas = NULL; AString surfType; switch (surfaceList[whichStruct]) { case StructureEnum::CORTEX_LEFT: mySurf = myLeftSurf; myAreas = myLeftAreas; surfType = "left"; break; case StructureEnum::CORTEX_RIGHT: mySurf = myRightSurf; myAreas = myRightAreas; surfType = "right"; break; case StructureEnum::CEREBELLUM: mySurf = myCerebSurf; myAreas = myCerebAreas; surfType = "cerebellum"; break; default: throw AlgorithmException("found surface model with incorrect type: " + StructureEnum::toName(surfaceList[whichStruct])); break; } if (mySurf == NULL) { throw AlgorithmException(surfType + " surface required but not provided"); } if (myDir == CiftiXMLOld::ALONG_COLUMN) { if (mySurf->getNumberOfNodes() != myXML.getColumnSurfaceNumberOfNodes(surfaceList[whichStruct])) { throw AlgorithmException(surfType + " surface has the wrong number of vertices"); } } else { if (mySurf->getNumberOfNodes() != myXML.getRowSurfaceNumberOfNodes(surfaceList[whichStruct])) { throw AlgorithmException(surfType + " surface has the wrong number of vertices"); } } if (myAreas != NULL && myAreas->getNumberOfNodes() != mySurf->getNumberOfNodes()) { throw AlgorithmException(surfType + " surface and vertex area metric have different number of vertices"); } } myCiftiOut->setCiftiXML(myXML); for (int whichStruct = 0; whichStruct < (int)surfaceList.size(); ++whichStruct) { const SurfaceFile* mySurf = NULL; const MetricFile* myAreas = NULL; switch (surfaceList[whichStruct]) { case StructureEnum::CORTEX_LEFT: mySurf = myLeftSurf; myAreas = myLeftAreas; break; case StructureEnum::CORTEX_RIGHT: mySurf = myRightSurf; myAreas = myRightAreas; break; case StructureEnum::CEREBELLUM: mySurf = myCerebSurf; myAreas = myCerebAreas; break; default: break; } MetricFile myMetric, myRoi, myMetricOut; AlgorithmCiftiSeparate(NULL, myCifti, myDir, surfaceList[whichStruct], &myMetric, &myRoi); if (surfKern > 0.0f) { if (roiCifti != NULL) {//due to above testing, we know the structure mask is the same, so just overwrite the ROI from the mask AlgorithmCiftiSeparate(NULL, roiCifti, CiftiXMLOld::ALONG_COLUMN, surfaceList[whichStruct], &myRoi); } AlgorithmMetricSmoothing(NULL, mySurf, &myMetric, surfKern, &myMetricOut, &myRoi, false, fixZerosSurf, -1, myAreas); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, surfaceList[whichStruct], &myMetricOut); } else { AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, surfaceList[whichStruct], &myMetric); } } if (mergedVolume) { VolumeFile myVol, myRoi, myVolOut; int64_t offset[3]; AlgorithmCiftiSeparate(NULL, myCifti, myDir, &myVol, offset, &myRoi, true); if (volKern > 0.0f) { if (roiCifti != NULL) {//due to above testing, we know the structure mask is the same, so just overwrite the ROI from the mask AlgorithmCiftiSeparate(NULL, roiCifti, CiftiXMLOld::ALONG_COLUMN, &myRoi, offset, NULL, true); } AlgorithmVolumeSmoothing(NULL, &myVol, volKern, &myVolOut, &myRoi, fixZerosVol); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, &myVolOut, true); } else { AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, &myVol, true); } } else { for (int whichStruct = 0; whichStruct < (int)volumeList.size(); ++whichStruct) { VolumeFile myVol, myRoi, myVolOut; int64_t offset[3]; AlgorithmCiftiSeparate(NULL, myCifti, myDir, volumeList[whichStruct], &myVol, offset, &myRoi, true); if (volKern > 0.0f) { if (roiCifti != NULL) {//due to above testing, we know the structure mask is the same, so just overwrite the ROI from the mask AlgorithmCiftiSeparate(NULL, roiCifti, CiftiXMLOld::ALONG_COLUMN, volumeList[whichStruct], &myRoi, offset, NULL, true); } AlgorithmVolumeSmoothing(NULL, &myVol, volKern, &myVolOut, &myRoi, fixZerosVol); AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, volumeList[whichStruct], &myVolOut, true); } else { AlgorithmCiftiReplaceStructure(NULL, myCiftiOut, myDir, volumeList[whichStruct], &myVol, true); } } } } float AlgorithmCiftiSmoothing::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiSmoothing::getSubAlgorithmWeight() { return 0.0f;//if you use a subalgorithm } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiSmoothing.h000066400000000000000000000042211360521144700255000ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_SMOOTHING_H__ #define __ALGORITHM_CIFTI_SMOOTHING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmCiftiSmoothing : public AbstractAlgorithm { AlgorithmCiftiSmoothing(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiSmoothing(ProgressObject* myProgObj, const CiftiFile* myCifti, const float& surfKern, const float& volKern, const int& myDir, CiftiFile* myCiftiOut, const SurfaceFile* myLeftSurf = NULL, const SurfaceFile* myRightSurf = NULL, const SurfaceFile* myCerebSurf = NULL, const CiftiFile* roiCifti = NULL, bool fixZerosVol = false, bool fixZerosSurf = false, const MetricFile* myLeftAreas = NULL, const MetricFile* myRightAreas = NULL, const MetricFile* myCerebAreas = NULL, const bool& mergedVolume = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiSmoothing; } #endif //__ALGORITHM_CIFTI_SMOOTHING_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiTranspose.cxx000066400000000000000000000105231360521144700260640ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiTranspose.h" #include "AlgorithmException.h" #include "CiftiFile.h" using namespace caret; using namespace std; AString AlgorithmCiftiTranspose::getCommandSwitch() { return "-cifti-transpose"; } AString AlgorithmCiftiTranspose::getShortDescription() { return "TRANSPOSE A CIFTI FILE"; } OperationParameters* AlgorithmCiftiTranspose::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-in", "the input cifti file"); ret->addCiftiOutputParameter(2, "cifti-out", "the output cifti file"); OptionalParameter* memLimitOpt = ret->createOptionalParameter(3, "-mem-limit", "restrict memory usage"); memLimitOpt->addDoubleParameter(1, "limit-GB", "memory limit in gigabytes"); ret->setHelpText( AString("The input must be a 2-dimensional cifti file. ") + "The output is a cifti file where every row in the input is a column in the output." ); return ret; } void AlgorithmCiftiTranspose::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* ciftiIn = myParams->getCifti(1); CiftiFile* ciftiOut = myParams->getOutputCifti(2); OptionalParameter* memLimitOpt = myParams->getOptionalParameter(3); float memLimitGB = -1.0f; if (memLimitOpt->m_present) { memLimitGB = (float)memLimitOpt->getDouble(1); if (memLimitGB < 0.0f) { throw AlgorithmException("memory limit cannot be negative"); } } AlgorithmCiftiTranspose(myProgObj, ciftiIn, ciftiOut, memLimitGB); } AlgorithmCiftiTranspose::AlgorithmCiftiTranspose(ProgressObject* myProgObj, const CiftiFile* ciftiIn, CiftiFile* ciftiOut, const float& memLimitGB) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const CiftiXML& inXML = ciftiIn->getCiftiXML(); if (inXML.getNumberOfDimensions() != 2) { throw AlgorithmException("cifti transpose only supports 2D cifti"); } CiftiXML outXML; outXML.setNumberOfDimensions(2); outXML.setMap(0, *(inXML.getMap(1))); outXML.setMap(1, *(inXML.getMap(0))); ciftiOut->setCiftiXML(outXML); int rowSize = outXML.getDimensionLength(CiftiXML::ALONG_ROW), colSize = outXML.getDimensionLength(CiftiXML::ALONG_COLUMN); int64_t outRowBytes = rowSize * sizeof(float); int numCacheRows = colSize; if (memLimitGB >= 0.0f) { numCacheRows = memLimitGB * 1024 * 1024 * 1024 / outRowBytes; if (numCacheRows < 1) numCacheRows = 1; if (numCacheRows > colSize) numCacheRows = colSize; } vector > cacheRows(numCacheRows, vector(rowSize)); vector scratchInRow(colSize); for (int i = 0; i < colSize; i += numCacheRows)//loop through cache chunks { int end = i + numCacheRows; if (end > colSize) end = colSize; for (int j = 0; j < rowSize; ++j)//loop through all input rows { ciftiIn->getRow(scratchInRow.data(), j); for (int k = i; k < end; ++k) { cacheRows[k - i][j] = scratchInRow[k]; } } for (int k = i; k < end; ++k) { ciftiOut->setRow(cacheRows[k - i].data(), k); } } } float AlgorithmCiftiTranspose::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiTranspose::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiTranspose.h000066400000000000000000000032641360521144700255150ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_TRANSPOSE_H__ #define __ALGORITHM_CIFTI_TRANSPOSE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmCiftiTranspose : public AbstractAlgorithm { AlgorithmCiftiTranspose(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiTranspose(ProgressObject* myProgObj, const CiftiFile* ciftiIn, CiftiFile* ciftiOut, const float& memLimitGB = -1.0f); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiTranspose; } #endif //__ALGORITHM_CIFTI_TRANSPOSE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiVectorOperation.cxx000066400000000000000000000172171360521144700272400ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiVectorOperation.h" #include "AlgorithmException.h" #include "CiftiFile.h" using namespace caret; using namespace std; AString AlgorithmCiftiVectorOperation::getCommandSwitch() { return "-cifti-vector-operation"; } AString AlgorithmCiftiVectorOperation::getShortDescription() { return "DO A VECTOR OPERATION ON CIFTI FILES"; } OperationParameters* AlgorithmCiftiVectorOperation::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "vectors-a", "first vector input file"); ret->addCiftiParameter(2, "vectors-b", "second vector input file"); ret->addStringParameter(3, "operation", "what vector operation to do"); ret->addCiftiOutputParameter(4, "cifti-out", "the output file"); ret->createOptionalParameter(5, "-normalize-a", "normalize vectors of first input"); ret->createOptionalParameter(6, "-normalize-b", "normalize vectors of second input"); ret->createOptionalParameter(7, "-normalize-output", "normalize output vectors (not valid for dot product)"); ret->createOptionalParameter(8, "-magnitude", "output the magnitude of the result (not valid for dot product)"); AString myText = AString("Does a vector operation on two cifti files (that must have a multiple of 3 columns). ") + "Either of the inputs may have multiple vectors (more than 3 columns), but not both (at least one must have exactly 3 columns). " + "The -magnitude and -normalize-output options may not be specified together, or with an operation that returns a scalar (dot product). " + "The parameter must be one of the following:\n"; vector opList = VectorOperation::getAllOperations(); for (int i = 0; i < (int)opList.size(); ++i) { myText += "\n" + VectorOperation::operationToString(opList[i]); } ret->setHelpText(myText); return ret; } void AlgorithmCiftiVectorOperation::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { CiftiFile* ciftiA = myParams->getCifti(1); CiftiFile* ciftiB = myParams->getCifti(2); AString operString = myParams->getString(3); bool ok = false; VectorOperation::Operation myOper = VectorOperation::stringToOperation(operString, ok); if (!ok) throw AlgorithmException("unrecognized operation string: " + operString); CiftiFile* myCiftiOut = myParams->getOutputCifti(4); bool normA = myParams->getOptionalParameter(5)->m_present; bool normB = myParams->getOptionalParameter(6)->m_present; bool normOut = myParams->getOptionalParameter(7)->m_present; bool magOut = myParams->getOptionalParameter(8)->m_present; AlgorithmCiftiVectorOperation(myProgObj, ciftiA, ciftiB, myOper, myCiftiOut, normA, normB, normOut, magOut); } AlgorithmCiftiVectorOperation::AlgorithmCiftiVectorOperation(ProgressObject* myProgObj, const CiftiFile* ciftiA, const CiftiFile* ciftiB, const VectorOperation::Operation& myOper, CiftiFile* myCiftiOut, const bool& normA, const bool& normB, const bool& normOut, const bool& magOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const CiftiXML& xmlA = ciftiA->getCiftiXML(), &xmlB = ciftiB->getCiftiXML(); if (xmlA.getNumberOfDimensions() != 2 || xmlB.getNumberOfDimensions() != 2) { throw AlgorithmException("cifti vector operation only supports 2D cifti"); } if (!xmlA.getMap(CiftiXML::ALONG_COLUMN)->approximateMatch(*xmlB.getMap(CiftiXML::ALONG_COLUMN))) { throw AlgorithmException("input cifti files have non-matching mappings along column"); } int64_t numColA = xmlA.getDimensionLength(CiftiXML::ALONG_ROW), numColB = xmlB.getDimensionLength(CiftiXML::ALONG_ROW); if (numColA % 3 != 0) throw AlgorithmException("number of columns of first input is not a multiple of 3"); if (numColB % 3 != 0) throw AlgorithmException("number of columns of second input is not a multiple of 3"); int numVecA = numColA / 3, numVecB = numColB / 3; if (numVecA > 1 && numVecB > 1) throw AlgorithmException("both inputs have more than 3 columns (more than 1 vector)"); if (normOut && magOut) throw AlgorithmException("normalizing the output and taking the magnitude is meaningless"); bool opScalarResult = VectorOperation::operationReturnsScalar(myOper); if (opScalarResult && (normOut || magOut)) throw AlgorithmException("cannot normalize or take magnitude of a scalar result (such as a dot product)"); bool swapped = false; const CiftiFile* multiVec = ciftiA, *singleVec = ciftiB; int numOutVecs = numVecA; if (numVecB > 1) { multiVec = ciftiB; singleVec = ciftiA; numOutVecs = numVecB; swapped = true; } CiftiXML outXML = multiVec->getCiftiXML(); int numColsOut = numOutVecs * 3; if (opScalarResult || magOut) { numColsOut = numOutVecs; CiftiScalarsMap outRowMap; outRowMap.setLength(numColsOut); outXML.setMap(CiftiXML::ALONG_ROW, outRowMap); } myCiftiOut->setCiftiXML(outXML); vector outRow(numColsOut), multiRow(numOutVecs * 3); int64_t numRows = xmlA.getDimensionLength(CiftiXML::ALONG_COLUMN); for (int64_t row = 0; row < numRows; ++row) { multiVec->getRow(multiRow.data(), row); Vector3D vecSingle; singleVec->getRow(vecSingle, row); for (int64_t v = 0; v < numOutVecs; ++v) { Vector3D vecA, vecB; if (swapped) { vecA = multiRow.data() + v * 3; vecB = vecSingle; } else { vecA = vecSingle; vecB = multiRow.data() + v * 3; } if (normA) vecA = vecA.normal(); if (normB) vecB = vecB.normal(); if (opScalarResult) { outRow[v] = VectorOperation::doScalarOperation(vecA, vecB, myOper); } else { Vector3D tempVec = VectorOperation::doVectorOperation(vecA, vecB, myOper); if (normOut) tempVec = tempVec.normal(); if (magOut) { outRow[v] = tempVec.length(); } else { outRow[v * 3] = tempVec[0]; outRow[v * 3 + 1] = tempVec[1]; outRow[v * 3 + 2] = tempVec[2]; } } } myCiftiOut->setRow(outRow.data(), row); } } float AlgorithmCiftiVectorOperation::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCiftiVectorOperation::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCiftiVectorOperation.h000066400000000000000000000037431360521144700266640ustar00rootroot00000000000000#ifndef __ALGORITHM_CIFTI_VECTOR_OPERATION_H__ #define __ALGORITHM_CIFTI_VECTOR_OPERATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "VectorOperation.h" namespace caret { class AlgorithmCiftiVectorOperation : public AbstractAlgorithm { AlgorithmCiftiVectorOperation(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCiftiVectorOperation(ProgressObject* myProgObj, const CiftiFile* ciftiA, const CiftiFile* ciftiB, const VectorOperation::Operation& myOper, CiftiFile* myCiftiOut, const bool& normA = false, const bool& normB = false, const bool& normOut = false, const bool& magOut = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCiftiVectorOperation; } #endif //__ALGORITHM_CIFTI_VECTOR_OPERATION_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmCreateSignedDistanceVolume.cxx000066400000000000000000000637521360521144700303430ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCreateSignedDistanceVolume.h" #include "AlgorithmException.h" #include "VolumeFile.h" #include "CaretOMP.h" #include "CaretHeap.h" #include "MathFunctions.h" #include "NiftiIO.h" #include "SurfaceFile.h" #include #include #include using namespace caret; using namespace std; AString AlgorithmCreateSignedDistanceVolume::getCommandSwitch() { return "-create-signed-distance-volume"; } AString AlgorithmCreateSignedDistanceVolume::getShortDescription() { return "CREATE SIGNED DISTANCE VOLUME FROM SURFACE"; } OperationParameters* AlgorithmCreateSignedDistanceVolume::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the input surface"); ret->addStringParameter(2, "refspace", "a volume in the desired output space (dims, spacing, origin)"); ret->addVolumeOutputParameter(3, "outvol", "the output volume"); OptionalParameter* roiOutOpt = ret->createOptionalParameter(9, "-roi-out", "output an roi volume of where the output has a computed value"); roiOutOpt->addVolumeOutputParameter(1, "roi-vol", "the output roi volume"); OptionalParameter* fillValOpt = ret->createOptionalParameter(4, "-fill-value", "specify a value to put in all voxels that don't get assigned a distance"); fillValOpt->addDoubleParameter(1, "value", "value to fill with (default 0)"); OptionalParameter* exactDistOpt = ret->createOptionalParameter(5, "-exact-limit", "specify distance for exact output"); exactDistOpt->addDoubleParameter(1, "dist", "distance in mm (default 5)"); OptionalParameter* approxDistOpt = ret->createOptionalParameter(6, "-approx-limit", "specify distance for approximate output"); approxDistOpt->addDoubleParameter(1, "dist", "distance in mm (default 20)"); OptionalParameter* approxNeighborhoodOpt = ret->createOptionalParameter(7, "-approx-neighborhood", "voxel neighborhood for approximate calculation"); approxNeighborhoodOpt->addIntegerParameter(1, "num", "size of neighborhood cube measured from center to face, in voxels (default 2 = 5x5x5)"); OptionalParameter* windingMethodOpt = ret->createOptionalParameter(8, "-winding", "winding method for point inside surface test"); windingMethodOpt->addStringParameter(1, "method", "name of the method (default EVEN_ODD)"); ret->setHelpText( AString("Computes the signed distance function of the surface. Exact distance is calculated by finding the closest point on any surface triangle ") + "to the center of the voxel. Approximate distance is calculated starting with these distances, using dijkstra's method with a neighborhood of voxels. " + "Specifying too small of an exact distance may produce unexpected results. Valid specifiers for winding methods are as follows:\n\n" + "EVEN_ODD (default)\nNEGATIVE\nNONZERO\nNORMALS\n\nThe NORMALS method uses the normals of triangles and edges, or the closest triangle hit by a ray from the point. " + "This method may be slightly faster, but is only reliable for a closed surface that does not cross through itself. All other methods count entry (positive) and " + "exit (negative) crossings of a vertical ray from the point, then counts as inside if the total is odd, negative, or nonzero, respectively." ); return ret; } void AlgorithmCreateSignedDistanceVolume::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* mySurf = myParams->getSurface(1); AString myRefName = myParams->getString(2); vector > volSpace; vector volDims; { NiftiIO refSpaceIO; refSpaceIO.openRead(myRefName); volDims = refSpaceIO.getDimensions(); if (volDims.size() < 3) volDims.resize(3, 1); volSpace = refSpaceIO.getHeader().getSForm(); } volDims.resize(3); VolumeFile* myVolOut = myParams->getOutputVolume(3); myVolOut->reinitialize(volDims, volSpace); float fillValue = 0.0f; OptionalParameter* fillValOpt = myParams->getOptionalParameter(4); if (fillValOpt->m_present) { fillValue = (float)fillValOpt->getDouble(1); } float exactLim = 5.0f; OptionalParameter* exactDistOpt = myParams->getOptionalParameter(5); if (exactDistOpt->m_present) { exactLim = (float)exactDistOpt->getDouble(1); } float approxLim = 20.0f; OptionalParameter* approxDistOpt = myParams->getOptionalParameter(6); if (approxDistOpt->m_present) { approxLim = (float)approxDistOpt->getDouble(1);//don't sanity check it, less than exact limit simply turns it off, specify extremely large to do entire volume } int approxNeighborhood = 2; OptionalParameter* approxNeighborhoodOpt = myParams->getOptionalParameter(7); if (approxNeighborhoodOpt->m_present) { approxNeighborhood = (int)approxNeighborhoodOpt->getInteger(1); } SignedDistanceHelper::WindingLogic myWinding = SignedDistanceHelper::EVEN_ODD; OptionalParameter* windingMethodOpt = myParams->getOptionalParameter(8); if (windingMethodOpt->m_present) { AString methodName = windingMethodOpt->getString(1); if (methodName == "EVEN_ODD") { myWinding = SignedDistanceHelper::EVEN_ODD; } else if (methodName == "NEGATIVE") { myWinding = SignedDistanceHelper::NEGATIVE; } else if (methodName == "NONZERO") { myWinding = SignedDistanceHelper::NONZERO; } else if (methodName == "NORMALS") { myWinding = SignedDistanceHelper::NORMALS; } else { throw AlgorithmException("unrecognized winding method"); } } VolumeFile* myRoiOut = NULL; OptionalParameter* roiOutOpt = myParams->getOptionalParameter(9); if (roiOutOpt->m_present) { myRoiOut = roiOutOpt->getOutputVolume(1); } AlgorithmCreateSignedDistanceVolume(myProgObj, mySurf, myVolOut, myRoiOut, fillValue, exactLim, approxLim, approxNeighborhood, myWinding); } AlgorithmCreateSignedDistanceVolume::AlgorithmCreateSignedDistanceVolume(ProgressObject* myProgObj, const SurfaceFile* mySurf, VolumeFile* myVolOut, VolumeFile* myRoiOut, const float& fillValue, const float& exactLim, const float& approxLim, const int& approxNeighborhood, const SignedDistanceHelper::WindingLogic& myWinding) : AbstractAlgorithm(myProgObj) { if (exactLim <= 0.0f) { throw AlgorithmException("exact limit must be positive"); } if (approxNeighborhood < 1) { throw AlgorithmException("approximate neighborhood must be at least 1"); } int32_t numNodes = mySurf->getNumberOfNodes(); float markweight = 0.1f, exactweight = 5.0f * exactLim, approxweight = 0.2f * (approxLim - exactLim); if (approxweight < 0.0f) approxweight = 0.0f; LevelProgress myProgress(myProgObj, markweight + exactweight + approxweight); vector > myVolSpace; myVolSpace = myVolOut->getSform(); Vector3D ivec, jvec, kvec; ivec[0] = myVolSpace[0][0]; ivec[1] = myVolSpace[1][0]; ivec[2] = myVolSpace[2][0]; jvec[0] = myVolSpace[0][1]; jvec[1] = myVolSpace[1][1]; jvec[2] = myVolSpace[2][1]; kvec[0] = myVolSpace[0][2]; kvec[1] = myVolSpace[1][2]; kvec[2] = myVolSpace[2][2]; Vector3D iOrthHat = jvec.cross(kvec);//these "orth" vectors are used to find the index extremes of a sphere, adding any amount of the other index vectors increases their length iOrthHat = iOrthHat.normal(); if (iOrthHat.dot(ivec) < 0) iOrthHat = -iOrthHat;//make sure it lies with rather than against the i vector Vector3D jOrthHat = ivec.cross(kvec); jOrthHat = jOrthHat.normal(); if (jOrthHat.dot(jvec) < 0) jOrthHat = -jOrthHat; Vector3D kOrthHat = ivec.cross(jvec); kOrthHat = kOrthHat.normal(); if (kOrthHat.dot(kvec) < 0) kOrthHat = -kOrthHat; vector myDims; myVolOut->getDimensions(myDims); myVolOut->setValueAllVoxels(fillValue); //list all voxels to be exactly computed int64_t frameSize = myDims[0] * myDims[1] * myDims[2]; CaretArray volMarked(frameSize, 0); myProgress.setTask("marking voxel to be calculated exactly"); //compare expected runtimes of kernel based and locator based marking methods if (2.9 * myDims[0] * myDims[1] * myDims[2] < (numNodes * exactLim * exactLim * exactLim / iOrthHat.dot(ivec) / jOrthHat.dot(jvec) / kOrthHat.dot(kvec))) { #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t k = 0; k < myDims[2]; ++k) { for (int64_t j = 0; j < myDims[1]; ++j) { for (int64_t i = 0; i < myDims[0]; ++i) { Vector3D voxCoord; myVolOut->indexToSpace(i, j, k, voxCoord); int32_t ret = mySurf->closestNode(voxCoord, exactLim); if (ret != -1) { volMarked[myVolOut->getIndex(i, j, k)] = 1; } } } } } else { #pragma omp CARET_PARFOR schedule(dynamic) for (int node = 0; node < numNodes; ++node) { int64_t ijk[3]; Vector3D nodeCoord = mySurf->getCoordinate(node), tempvec; float tempf, tempf2, tempf3; tempvec = nodeCoord - iOrthHat * exactLim; myVolOut->spaceToIndex(tempvec, tempf, tempf2, tempf3);//compute bounding box once rather than doing a convoluted sphere loop construct int64_t imin = (int64_t)ceil(tempf); if (imin < 0) imin = 0; tempvec = nodeCoord + iOrthHat * exactLim; myVolOut->spaceToIndex(tempvec, tempf, tempf2, tempf3); int64_t imax = (int64_t)floor(tempf) + 1; if (imax > myDims[0]) imax = myDims[0]; tempvec = nodeCoord - jOrthHat * exactLim; myVolOut->spaceToIndex(tempvec, tempf, tempf2, tempf3); int64_t jmin = (int64_t)ceil(tempf2); if (jmin < 0) jmin = 0; tempvec = nodeCoord + jOrthHat * exactLim; myVolOut->spaceToIndex(tempvec, tempf, tempf2, tempf3); int64_t jmax = (int64_t)floor(tempf2) + 1; if (jmax > myDims[1]) jmax = myDims[1]; tempvec = nodeCoord - kOrthHat * exactLim; myVolOut->spaceToIndex(tempvec, tempf, tempf2, tempf3); int64_t kmin = (int64_t)ceil(tempf3); if (kmin < 0) kmin = 0; tempvec = nodeCoord + kOrthHat * exactLim; myVolOut->spaceToIndex(tempvec, tempf, tempf2, tempf3); int64_t kmax = (int64_t)floor(tempf3) + 1; if (kmax > myDims[2]) kmax = myDims[2]; for (ijk[2] = kmin; ijk[2] < kmax; ++ijk[2]) { for (ijk[1] = jmin; ijk[1] < jmax; ++ijk[1]) { for (ijk[0] = imin; ijk[0] < imax; ++ijk[0]) { myVolOut->indexToSpace(ijk, tempvec); tempvec -= nodeCoord; if (tempvec.length() <= exactLim) { volMarked[myVolOut->getIndex(ijk)] = 1; } } } } } } vector exactVoxelList; int64_t ijk[3]; for (ijk[2] = 0; ijk[2] < myDims[2]; ++ijk[2]) { for (ijk[1] = 0; ijk[1] < myDims[1]; ++ijk[1]) { for (ijk[0] = 0; ijk[0] < myDims[0]; ++ijk[0]) { if (volMarked[myVolOut->getIndex(ijk)] == 1) { exactVoxelList.push_back(ijk[0]); exactVoxelList.push_back(ijk[1]); exactVoxelList.push_back(ijk[2]); } } } } myProgress.reportProgress(markweight); myProgress.setTask("computing exact distances"); #pragma omp CARET_PAR { CaretPointer myDist = mySurf->getSignedDistanceHelper(); int numExact = (int)exactVoxelList.size(); Vector3D thisCoord; #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < numExact; i += 3) { myVolOut->indexToSpace(exactVoxelList.data() + i, thisCoord); myVolOut->setValue(myDist->dist(thisCoord, myWinding), exactVoxelList.data() + i); volMarked[myVolOut->getIndex(exactVoxelList.data() + i)] |= 22;//set marked to have valid value (positive and negative), and frozen } } myProgress.reportProgress(markweight + exactweight); if (approxLim > exactLim) { myProgress.setTask("approximating distances in extended region"); int faceNeigh[] = { 1, 0, 0, -1, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 1, 0, 0, -1 }; vector neighborhood;//this will contain ONLY the shortest voxel offsets with unique 3d slopes within the neighborhood DistVoxOffset tempIndex; Vector3D tempvec; for (int i = -approxNeighborhood; i <= approxNeighborhood; ++i) { tempIndex.m_offset[0] = i; for (int j = -approxNeighborhood; j <= approxNeighborhood; ++j) { tempIndex.m_offset[1] = j; for (int k = -approxNeighborhood; k <= approxNeighborhood; ++k) { tempIndex.m_offset[2] = k; tempvec = ivec * i + jvec * j + kvec * k; tempIndex.m_dist = tempvec.length(); int low, med, high; low = min(min(abs(i), abs(j)), abs(k));//stupid sort high = max(max(abs(i), abs(j)), abs(k)); if (abs(i) != low && abs(i) != high) { med = abs(i); } else if (abs(j) != low && abs(j) != high) { med = abs(j); } else { med = abs(k); } if (low == 0) { if (med == 0) { if (high == 1) { neighborhood.push_back(tempIndex);//face neighbors } } else { if (MathFunctions::gcd(med, high) == 1) { neighborhood.push_back(tempIndex);//unique in-plane } } } else { if (MathFunctions::gcd(MathFunctions::gcd(low, med), high) == 1) { neighborhood.push_back(tempIndex);//unique out of plane } } } } }//positives float maxFaceDist = max(max(ivec.length(), jvec.length()), kvec.length()) * 1.01f;//add a fudge factor to make sure rounding error doesn't remove a cardinal direction int neighSize = neighborhood.size();//this is provably correct for volumes where there is no diagonal shorter than the longest index vector, so we test this explicitly just in case CaretMinHeap posHeap; CaretArray heapIndexes(frameSize); int numExact = (int)exactVoxelList.size(); for (int i = 0; i < numExact; i += 3) { int64_t* thisVoxel = exactVoxelList.data() + i; float tempf = myVolOut->getValue(thisVoxel); for (int neigh = 0; neigh < neighSize; ++neigh) { int64_t tempijk[3]; tempijk[0] = thisVoxel[0] + neighborhood[neigh].m_offset[0]; tempijk[1] = thisVoxel[1] + neighborhood[neigh].m_offset[1]; tempijk[2] = thisVoxel[2] + neighborhood[neigh].m_offset[2]; if (myVolOut->indexValid(tempijk)) { int64_t tempindex = myVolOut->getIndex(tempijk); float tempf2 = tempf + neighborhood[neigh].m_dist; if (abs(tempf2) <= approxLim && (volMarked[tempindex] & 4) == 0 && ((volMarked[tempindex] & 2) == 0 || tempf2 < myVolOut->getValue(tempijk))) {//within approxlim (so no stragglers outside limit), not frozen, and either no value or worse value volMarked[tempindex] |= 2; myVolOut->setValue(tempf2, tempijk); } } } if (tempf > 0.0f) {//start only from positive values //check face neighbors for being unmarked for (int neigh = 0; neigh < 18; neigh += 3) { int64_t tempijk[3]; tempijk[0] = thisVoxel[0] + faceNeigh[neigh]; tempijk[1] = thisVoxel[1] + faceNeigh[neigh + 1]; tempijk[2] = thisVoxel[2] + faceNeigh[neigh + 2]; if (myVolOut->indexValid(tempijk)) { int64_t tempIndex = myVolOut->getIndex(tempijk); if ((volMarked[tempIndex] & 1) == 0) {//only add this to the heap if it has unmarked face neighbors posHeap.push(VoxelIndex(thisVoxel), tempf);//don't need to store the index to change the key, value is frozen break; } } } } }//initialization done, now (sort of) dijkstras - in order to not go to the "inside" (and to run faster), it only adds things that are FACE neighbors to the heap for cubic voxels while (!posHeap.isEmpty()) { float curDist; VoxelIndex curVoxel = posHeap.pop(&curDist); int64_t curIndex = myVolOut->getIndex(curVoxel.m_ijk); volMarked[curIndex] |= 4;//frozen volMarked[curIndex] &= ~8;//no longer in the heap, don't try to modify by the index it used to have for (int neigh = 0; neigh < neighSize; ++neigh) { int64_t tempijk[3]; tempijk[0] = curVoxel.m_ijk[0] + neighborhood[neigh].m_offset[0]; tempijk[1] = curVoxel.m_ijk[1] + neighborhood[neigh].m_offset[1]; tempijk[2] = curVoxel.m_ijk[2] + neighborhood[neigh].m_offset[2]; if (myVolOut->indexValid(tempijk)) { float tempf = curDist + neighborhood[neigh].m_dist; int tempindex = myVolOut->getIndex(tempijk); int& tempmark = volMarked[tempindex]; if (abs(tempf) <= approxLim && (tempmark & 4) == 0 && ((tempmark & 2) == 0 || myVolOut->getValue(tempijk) > tempf)) {//within range, not frozen, no value or current value is worse tempmark |= 2;//valid value myVolOut->setValue(tempf, tempijk); if ((tempmark & 8) != 0)//if it is already in the heap, we must update its key (log time worst case, but changes should generally be small) { posHeap.changekey(heapIndexes[tempindex], tempf); } } if ((tempmark & 12) == 0 && (tempmark & 2) != 0 && neighborhood[neigh].m_dist <= maxFaceDist) {//this neatly handles both face neighbors and any other needed neighbors to maintain dijkstra correctness under extreme scenarios heapIndexes[tempindex] = posHeap.push(VoxelIndex(tempijk), myVolOut->getValue(tempijk)); tempmark |= 8;//has a heap index } } } }//negatives myProgress.reportProgress(markweight + exactweight + approxweight * 0.5f); CaretMaxHeap negHeap; for (int i = 0; i < numExact; i += 3) { int64_t* thisVoxel = exactVoxelList.data() + i; float tempf = myVolOut->getValue(thisVoxel); for (int neigh = 0; neigh < neighSize; ++neigh) { int64_t tempijk[3]; tempijk[0] = thisVoxel[0] + neighborhood[neigh].m_offset[0]; tempijk[1] = thisVoxel[1] + neighborhood[neigh].m_offset[1]; tempijk[2] = thisVoxel[2] + neighborhood[neigh].m_offset[2]; if (myVolOut->indexValid(tempijk)) { int64_t tempindex = myVolOut->getIndex(tempijk); float tempf2 = tempf - neighborhood[neigh].m_dist; if (abs(tempf2) <= approxLim && (volMarked[tempindex] & 4) == 0 && ((volMarked[tempindex] & 16) == 0 || tempf2 > myVolOut->getValue(tempijk))) {//within approxlim (so no stragglers outside limit), not frozen, and either no value or worse value volMarked[tempindex] |= 16; myVolOut->setValue(tempf2, tempijk); } } } if (tempf < 0.0f) {//start only from negative values //check face neighbors for being unmarked for (int neigh = 0; neigh < 18; neigh += 3) { int64_t tempijk[3]; tempijk[0] = thisVoxel[0] + faceNeigh[neigh]; tempijk[1] = thisVoxel[1] + faceNeigh[neigh + 1]; tempijk[2] = thisVoxel[2] + faceNeigh[neigh + 2]; if (myVolOut->indexValid(tempijk)) { int64_t tempIndex = myVolOut->getIndex(tempijk); if ((volMarked[tempIndex] & 1) == 0) {//only add this to the heap if it has unmarked face neighbors negHeap.push(VoxelIndex(thisVoxel), tempf);//don't need to store the index to change the key, value is frozen break; } } } } } while (!negHeap.isEmpty()) { float curDist; VoxelIndex curVoxel = negHeap.pop(&curDist); int64_t curIndex = myVolOut->getIndex(curVoxel.m_ijk); volMarked[curIndex] |= 4;//frozen volMarked[curIndex] &= ~8;//no longer in the heap, don't try to modify by the index it used to have for (int neigh = 0; neigh < neighSize; ++neigh) { int64_t tempijk[3]; tempijk[0] = curVoxel.m_ijk[0] + neighborhood[neigh].m_offset[0]; tempijk[1] = curVoxel.m_ijk[1] + neighborhood[neigh].m_offset[1]; tempijk[2] = curVoxel.m_ijk[2] + neighborhood[neigh].m_offset[2]; if (myVolOut->indexValid(tempijk)) { float tempf = curDist - neighborhood[neigh].m_dist; int tempindex = myVolOut->getIndex(tempijk); int& tempmark = volMarked[tempindex]; if (abs(tempf) <= approxLim && (tempmark & 4) == 0 && ((tempmark & 16) == 0 || myVolOut->getValue(tempijk) < tempf)) {//within range, not frozen, no value or current value is worse tempmark |= 16;//valid value myVolOut->setValue(tempf, tempijk); if ((tempmark & 8) != 0)//if it is already in the heap, we must update its key (log time worst case, but changes should generally be small) { negHeap.changekey(heapIndexes[tempindex], tempf); } } if ((tempmark & 12) == 0 && (tempmark & 16) != 0 && neighborhood[neigh].m_dist <= maxFaceDist) {//this neatly handles both face neighbors and any other needed neighbors to maintain dijkstra correctness under extreme scenarios heapIndexes[tempindex] = negHeap.push(VoxelIndex(tempijk), myVolOut->getValue(tempijk)); tempmark |= 8;//has a heap index } } } } }//now make the roi volume if (myRoiOut != NULL) { myDims.resize(3); myRoiOut->reinitialize(myDims, myVolOut->getSform()); for (ijk[2] = 0; ijk[2] < myDims[2]; ++ijk[2]) { for (ijk[1] = 0; ijk[1] < myDims[1]; ++ijk[1]) { for (ijk[0] = 0; ijk[0] < myDims[0]; ++ijk[0]) { if ((volMarked[myVolOut->getIndex(ijk)] & 4) == 0)//only mark "frozen" (4) as valid, though "have value" (2) should now be the same { myRoiOut->setValue(0.0f, ijk); } else { myRoiOut->setValue(1.0f, ijk); } } } } } } float AlgorithmCreateSignedDistanceVolume::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmCreateSignedDistanceVolume::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmCreateSignedDistanceVolume.h000066400000000000000000000050331360521144700277540ustar00rootroot00000000000000#ifndef __ALGORITHM_CREATE_SIGNED_DISTANCE_VOLUME_H__ #define __ALGORITHM_CREATE_SIGNED_DISTANCE_VOLUME_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "Vector3D.h" #include "CaretMutex.h" #include "OctTree.h" #include "SignedDistanceHelper.h" #include namespace caret { struct DistVoxOffset { float m_dist; int m_offset[3]; }; struct VoxelIndex {//needed in order to contain the data in a heap, operator= doesn't work on a static array VoxelIndex(int64_t ijk[3]) { m_ijk[0] = ijk[0]; m_ijk[1] = ijk[1]; m_ijk[2] = ijk[2]; } int64_t m_ijk[3]; }; class AlgorithmCreateSignedDistanceVolume : public AbstractAlgorithm { AlgorithmCreateSignedDistanceVolume(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmCreateSignedDistanceVolume(ProgressObject* myProgObj, const SurfaceFile* mySurf, VolumeFile* myVolOut, VolumeFile* myRoiOut = NULL, const float& fillValue = 0.0f, const float& exactLim = 5.0f, const float& approxLim = 20.0f, const int& approxNeighborhood = 2, const SignedDistanceHelper::WindingLogic& myWinding = SignedDistanceHelper::EVEN_ODD); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmCreateSignedDistanceVolume; } #endif //__ALGORITHM_CREATE_SIGNED_DISTANCE_VOLUME_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmException.cxx000066400000000000000000000042431360521144700250670ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmException.h" #include using namespace caret; /** * Constructor. * */ AlgorithmException::AlgorithmException() : CaretException() { this->initializeMembersAlgorithmException(); } /** * Constructor that uses stack trace from the exception * passed in as a parameter. * * @param e Any exception whose stack trace becomes * this exception's stack trace. * */ AlgorithmException::AlgorithmException( const CaretException& e) : CaretException(e) { this->initializeMembersAlgorithmException(); } /** * Constructor. * * @param s Description of the exception. * */ AlgorithmException::AlgorithmException(const AString& s) : CaretException(s) { this->initializeMembersAlgorithmException(); } /** * Copy Constructor. * @param e * Exception that is copied. */ AlgorithmException::AlgorithmException(const AlgorithmException& e) : CaretException(e) { } /** * Assignment operator. * @param e * Exception that is copied. * @return * Copy of the exception. */ AlgorithmException& AlgorithmException::operator=(const AlgorithmException& e) { if (this != &e) { CaretException::operator=(e); } return *this; } /** * Destructor */ AlgorithmException::~AlgorithmException() throw() { } void AlgorithmException::initializeMembersAlgorithmException() { } connectome-workbench-1.4.2/src/Algorithms/AlgorithmException.h000066400000000000000000000027421360521144700245160ustar00rootroot00000000000000#ifndef __ALGORITHM_EXCEPTION_H__ #define __ALGORITHM_EXCEPTION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretException.h" namespace caret { /// An exception thrown during command processing. class AlgorithmException : public CaretException { public: AlgorithmException(); AlgorithmException(const CaretException& e); AlgorithmException(const AString& s); AlgorithmException(const AlgorithmException& e); AlgorithmException& operator=(const AlgorithmException& e); virtual ~AlgorithmException() throw(); private: void initializeMembersAlgorithmException(); }; } // namespace #endif // __ALGORITHM_EXCEPTION_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmFiberDotProducts.cxx000066400000000000000000000171431360521144700263560ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmFiberDotProducts.h" #include "AlgorithmException.h" #include "CiftiFile.h" #include "CaretPointLocator.h" #include "MetricFile.h" #include "SignedDistanceHelper.h" #include "SurfaceFile.h" #include #include using namespace caret; using namespace std; AString AlgorithmFiberDotProducts::getCommandSwitch() { return "-fiber-dot-products"; } AString AlgorithmFiberDotProducts::getShortDescription() { return "COMPUTE DOT PRODUCTS OF FIBER ORIENTATIONS WITH SURFACE NORMALS"; } OperationParameters* AlgorithmFiberDotProducts::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "white-surf", "the white/gray boundary surface"); ret->addCiftiParameter(2, "fiber-file", "the fiber orientation file"); ret->addDoubleParameter(3, "max-dist", "the maximum distance from any surface vertex a fiber population may be, in mm"); ret->addStringParameter(6, "direction", "test against surface for whether a fiber population should be used"); ret->addMetricOutputParameter(4, "dot-metric", "the metric of dot products"); ret->addMetricOutputParameter(5, "f-metric", "a metric of the f values of the fiber distributions"); ret->setHelpText( AString("For each vertex, this command finds the closest fiber population that satisfies the test, ") + "and computes the absolute value of the dot product of the surface normal and the normalized mean direction of each fiber. " + "The test must be one of INSIDE, OUTSIDE, or ANY, which causes the command to only use fiber populations " + "that are inside the surface, outside the surface, or to not care which direction it is from the surface. " + "Each fiber population is output in a separate metric column." ); return ret; } void AlgorithmFiberDotProducts::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* mySurf = myParams->getSurface(1); CiftiFile* myFibers = myParams->getCifti(2); float maxDist = (float)myParams->getDouble(3); MetricFile* myDotProdOut = myParams->getOutputMetric(4); MetricFile* myFSampOut = myParams->getOutputMetric(5); AString direction = myParams->getString(6); Direction myTest = INSIDE; if (direction == "INSIDE") { myTest = INSIDE; } else if (direction == "OUTSIDE") { myTest = OUTSIDE; } else if (direction == "ANY") { myTest = ANY; } else { throw AlgorithmException("unrecognized direction test"); } AlgorithmFiberDotProducts(myProgObj, mySurf, myFibers, maxDist, myTest, myDotProdOut, myFSampOut); } AlgorithmFiberDotProducts::AlgorithmFiberDotProducts(ProgressObject* myProgObj, const SurfaceFile* mySurf, const CiftiFile* myFibers, const float& maxDist, const Direction& myTest, MetricFile* myDotProdOut, MetricFile* myFSampOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); CaretPointer mySignedHelp = mySurf->getSignedDistanceHelper(); int rowSize = myFibers->getNumberOfColumns(); if ((rowSize - 3) % 7 != 0) throw AlgorithmException("input is not a fiber orientation file"); int numFibers = (rowSize - 3) / 7; int64_t numRows = myFibers->getNumberOfRows(); vector coordsInside; vector coordIndices; vector rowScratch(rowSize); for (int64_t i = 0; i < numRows; ++i) { myFibers->getRow(rowScratch.data(), i); int closeNode = mySurf->closestNode(rowScratch.data(), maxDist); if (closeNode == -1) continue;//skip samples that aren't close to a surface node, for speed (signed distance is kinda slow) if (myTest == ANY) { coordsInside.push_back(rowScratch[0]);//add point to vector for locator coordsInside.push_back(rowScratch[1]); coordsInside.push_back(rowScratch[2]); coordIndices.push_back(i);//and save its cifti index } else { float signedDist = mySignedHelp->dist(rowScratch.data(), SignedDistanceHelper::EVEN_ODD);//the first 3 floats are xyz coords if ((myTest == INSIDE) == (signedDist <= 0.0f))//test for inside/outside surface { coordsInside.push_back(rowScratch[0]);//add point to vector for locator coordsInside.push_back(rowScratch[1]); coordsInside.push_back(rowScratch[2]); coordIndices.push_back(i);//and save its cifti index } } } if (coordIndices.size() == 0) throw AlgorithmException("no fiber samples passed the and tests"); CaretPointLocator myLocator(coordsInside.data(), coordIndices.size());//build the locator int numNodes = mySurf->getNumberOfNodes(); myDotProdOut->setNumberOfNodesAndColumns(numNodes, numFibers); myFSampOut->setNumberOfNodesAndColumns(numNodes, numFibers); myDotProdOut->setStructure(mySurf->getStructure()); myFSampOut->setStructure(mySurf->getStructure()); for (int i = 0; i < numFibers; ++i) { myDotProdOut->setColumnName(i, "Fiber " + AString::number(i + 1) + " dot products"); myFSampOut->setColumnName(i, "Fiber " + AString::number(i + 1) + " population mean f"); } const float* coordData = mySurf->getCoordinateData(); for (int i = 0; i < numNodes; ++i) { int closest = myLocator.closestPoint(coordData + i * 3); if (closest != -1) { myFibers->getRow(rowScratch.data(), coordIndices[closest]); Vector3D myNormal = mySurf->getNormalVector(i); for (int j = 0; j < numFibers; ++j) { int base = 3 + j * 7; float fmean = rowScratch[base]; float theta = rowScratch[base + 2]; float phi = rowScratch[base + 3]; Vector3D direction; direction[0] = -sin(theta) * cos(phi);//NOTE: theta, phi are polar coordinates for a RADIOLOGICAL coordinate system, so flip x so that +x = right direction[1] = sin(theta) * sin(phi); direction[2] = cos(theta); float dotProd = abs(myNormal.dot(direction)); myDotProdOut->setValue(i, j, dotProd); myFSampOut->setValue(i, j, fmean); } } else { for (int j = 0; j < numFibers; ++j) { myDotProdOut->setValue(i, j, 0.0f); myFSampOut->setValue(i, j, 0.0f); } } } } float AlgorithmFiberDotProducts::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmFiberDotProducts::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmFiberDotProducts.h000066400000000000000000000035631360521144700260040ustar00rootroot00000000000000#ifndef __ALGORITHM_FIBER_DOT_PRODUCTS_H__ #define __ALGORITHM_FIBER_DOT_PRODUCTS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmFiberDotProducts : public AbstractAlgorithm { AlgorithmFiberDotProducts(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: enum Direction { INSIDE, OUTSIDE, ANY }; AlgorithmFiberDotProducts(ProgressObject* myProgObj, const SurfaceFile* mySurf, const CiftiFile* myFibers, const float& maxDist, const Direction& myTest, MetricFile* myDotProdOut, MetricFile* myFSampOut); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmFiberDotProducts; } #endif //__ALGORITHM_FIBER_DOT_PRODUCTS_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmFociResample.cxx000066400000000000000000000213001360521144700254730ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmFociResample.h" #include "AlgorithmException.h" #include "FociFile.h" #include "Focus.h" #include "GiftiLabelTable.h" #include "GiftiMetaData.h" #include "SurfaceFile.h" #include "SurfaceProjector.h" using namespace caret; using namespace std; AString AlgorithmFociResample::getCommandSwitch() { return "-foci-resample"; } AString AlgorithmFociResample::getShortDescription() { return "PROJECT FOCI TO A DIFFERENT SURFACE"; } OperationParameters* AlgorithmFociResample::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addFociParameter(1, "foci-in", "the input foci file"); ret->addFociOutputParameter(2, "foci-out", "the output foci file"); OptionalParameter* leftSurfaceOpt = ret->createOptionalParameter(3, "-left-surfaces", "the left surfaces for resampling"); leftSurfaceOpt->addSurfaceParameter(1, "current-surf", "the surface the foci are currently projected on"); leftSurfaceOpt->addSurfaceParameter(2, "new-surf", "the surface to project the foci onto"); OptionalParameter* rightSurfaceOpt = ret->createOptionalParameter(4, "-right-surfaces", "the right surfaces for resampling"); rightSurfaceOpt->addSurfaceParameter(1, "current-surf", "the surface the foci are currently projected on"); rightSurfaceOpt->addSurfaceParameter(2, "new-surf", "the surface to project the foci onto"); OptionalParameter* cerebSurfaceOpt = ret->createOptionalParameter(5, "-cerebellum-surfaces", "the cerebellum surfaces for resampling"); cerebSurfaceOpt->addSurfaceParameter(1, "current-surf", "the surface the foci are currently projected on"); cerebSurfaceOpt->addSurfaceParameter(2, "new-surf", "the surface to project the foci onto"); ret->createOptionalParameter(6, "-discard-distance-from-surface", "ignore the distance the foci are above or below the current surface"); ret->createOptionalParameter(7, "-restore-xyz", "put the original xyz coordinates into the foci, rather than the coordinates obtained from unprojection"); ret->setHelpText(AString("Unprojects foci from the for the structure, then projects them to . ") + "If the foci have meaningful distances above or below the surface, use anatomical surfaces. " + "If the foci should be on the surface, use registered spheres and the options -discard-distance-from-surface and -restore-xyz."); return ret; } void AlgorithmFociResample::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { FociFile* fociIn = myParams->getFoci(1); FociFile* fociOut = myParams->getOutputFoci(2); SurfaceFile* leftCurSurf = NULL, *leftNewSurf = NULL; OptionalParameter* leftSurfaceOpt = myParams->getOptionalParameter(3); if (leftSurfaceOpt->m_present) { leftCurSurf = leftSurfaceOpt->getSurface(1); leftNewSurf = leftSurfaceOpt->getSurface(2); } SurfaceFile* rightCurSurf = NULL, *rightNewSurf = NULL; OptionalParameter* rightSurfaceOpt = myParams->getOptionalParameter(4); if (rightSurfaceOpt->m_present) { rightCurSurf = rightSurfaceOpt->getSurface(1); rightNewSurf = rightSurfaceOpt->getSurface(2); } SurfaceFile* cerebCurSurf = NULL, *cerebNewSurf = NULL; OptionalParameter* cerebSurfaceOpt = myParams->getOptionalParameter(5); if (cerebSurfaceOpt->m_present) { cerebCurSurf = cerebSurfaceOpt->getSurface(1); cerebNewSurf = cerebSurfaceOpt->getSurface(2); } bool discardNormDist = myParams->getOptionalParameter(6)->m_present; bool restoryXyz = myParams->getOptionalParameter(7)->m_present; AlgorithmFociResample(myProgObj, fociIn, fociOut, leftCurSurf, leftNewSurf, rightCurSurf, rightNewSurf, cerebCurSurf, cerebNewSurf, discardNormDist, restoryXyz); } AlgorithmFociResample::AlgorithmFociResample(ProgressObject* myProgObj, const FociFile* fociIn, FociFile* fociOut, const SurfaceFile* leftCurSurf, const SurfaceFile* leftNewSurf, const SurfaceFile* rightCurSurf, const SurfaceFile* rightNewSurf, const SurfaceFile* cerebCurSurf, const SurfaceFile* cerebNewSurf, const bool& discardNormDist, const bool& restoryXyz) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); checkStructureMatch(leftCurSurf, StructureEnum::CORTEX_LEFT, "current left surface", "-left-surfaces option expects"); checkStructureMatch(leftNewSurf, StructureEnum::CORTEX_LEFT, "new left surface", "-left-surfaces option expects"); checkStructureMatch(rightCurSurf, StructureEnum::CORTEX_RIGHT, "current right surface", "-right-surfaces option expects"); checkStructureMatch(rightNewSurf, StructureEnum::CORTEX_RIGHT, "new right surface", "-right-surfaces option expects"); checkStructureMatch(cerebCurSurf, StructureEnum::CEREBELLUM, "current cerebellum surface", "-cerebellum-surfaces option expects"); checkStructureMatch(cerebNewSurf, StructureEnum::CEREBELLUM, "new cerebellum surface", "-cerebellum-surfaces option expects"); CaretPointer leftProj, rightProj, cerebProj; if (leftNewSurf != NULL) leftProj.grabNew(new SurfaceProjector(leftNewSurf)); if (rightNewSurf != NULL) rightProj.grabNew(new SurfaceProjector(rightNewSurf)); if (cerebNewSurf != NULL) cerebProj.grabNew(new SurfaceProjector(cerebNewSurf)); *(fociOut->getClassColorTable()) = *(fociIn->getClassColorTable()); *(fociOut->getNameColorTable()) = *(fociIn->getNameColorTable()); *(fociOut->getFileMetaData()) = *(fociIn->getFileMetaData()); for (int i = 0; i < fociIn->getNumberOfFoci(); ++i) { const Focus* thisFocus = fociIn->getFocus(i); if (thisFocus->getNumberOfProjections() < 1) { throw AlgorithmException("focus '" + thisFocus->getName() + "' has no surface projection"); } SurfaceProjector* myProj = NULL; const SurfaceFile* unprojFrom = NULL; switch (thisFocus->getProjection(0)->getStructure()) { case StructureEnum::CORTEX_LEFT: myProj = leftProj; unprojFrom = leftCurSurf; break; case StructureEnum::CORTEX_RIGHT: myProj = rightProj; unprojFrom = rightCurSurf; break; case StructureEnum::CEREBELLUM: myProj = cerebProj; unprojFrom = cerebCurSurf; break; default: throw AlgorithmException("focus '" + thisFocus->getName() + "' has unsupported structure " + StructureEnum::toName(thisFocus->getProjection(0)->getStructure())); } if (unprojFrom == NULL || myProj == NULL) throw AlgorithmException("focus '" + thisFocus->getName() + "' has structure " + StructureEnum::toName(thisFocus->getProjection(0)->getStructure()) + ", but surfaces for that structure were not specified"); CaretPointer newFocus(new Focus(*thisFocus));//start with a copy float xyz[3]; bool result = thisFocus->getProjection(0)->getProjectedPosition(*unprojFrom, xyz, discardNormDist); if (!result) throw AlgorithmException("failed to unproject focus '" + thisFocus->getName() + "'"); newFocus->getProjection(0)->setStereotaxicXYZ(xyz); myProj->projectFocus(i, newFocus); if (restoryXyz) { newFocus->getProjection(0)->setStereotaxicXYZ(thisFocus->getProjection(0)->getStereotaxicXYZ()); } fociOut->addFocus(newFocus.releasePointer()); } } float AlgorithmFociResample::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmFociResample::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmFociResample.h000066400000000000000000000040341360521144700251250ustar00rootroot00000000000000#ifndef __ALGORITHM_FOCI_RESAMPLE_H__ #define __ALGORITHM_FOCI_RESAMPLE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmFociResample : public AbstractAlgorithm { AlgorithmFociResample(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmFociResample(ProgressObject* myProgObj, const FociFile* fociIn, FociFile* fociOut, const SurfaceFile* leftCurSurf, const SurfaceFile* leftNewSurf, const SurfaceFile* rightCurSurf = NULL, const SurfaceFile* rightNewSurf = NULL, const SurfaceFile* cerebCurSurf = NULL, const SurfaceFile* cerebNewSurf = NULL, const bool& discardNormDist = false, const bool& restoryXyz = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmFociResample; } #endif //__ALGORITHM_FOCI_RESAMPLE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmGiftiAllLabelsToROIs.cxx000066400000000000000000000106721360521144700270120ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmGiftiAllLabelsToROIs.h" #include "AlgorithmException.h" #include "GiftiLabelTable.h" #include "LabelFile.h" #include "MetricFile.h" #include using namespace caret; using namespace std; AString AlgorithmGiftiAllLabelsToROIs::getCommandSwitch() { return "-gifti-all-labels-to-rois"; } AString AlgorithmGiftiAllLabelsToROIs::getShortDescription() { return "MAKE ROIS FROM ALL LABELS IN A GIFTI COLUMN"; } OperationParameters* AlgorithmGiftiAllLabelsToROIs::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addLabelParameter(1, "label-in", "the input gifti label file"); ret->addStringParameter(2, "map", "the number or name of the label map to use"); ret->addMetricOutputParameter(3, "metric-out", "the output metric file"); ret->setHelpText( AString("The output metric file has a column for each label in the specified input map, other than the ??? label, ") + "each of which contains an ROI of all vertices that are set to the corresponding label." ); return ret; } void AlgorithmGiftiAllLabelsToROIs::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LabelFile* myLabel = myParams->getLabel(1); AString mapID = myParams->getString(2); int whichMap = myLabel->getMapIndexFromNameOrNumber(mapID); if (whichMap == -1) { throw AlgorithmException("invalid map number or name specified"); } MetricFile* myMetricOut = myParams->getOutputMetric(3); AlgorithmGiftiAllLabelsToROIs(myProgObj, myLabel, whichMap, myMetricOut); } AlgorithmGiftiAllLabelsToROIs::AlgorithmGiftiAllLabelsToROIs(ProgressObject* myProgObj, const LabelFile* myLabel, const int& whichMap, MetricFile* myMetricOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (whichMap < 0 || whichMap >= myLabel->getNumberOfMaps()) { throw AlgorithmException("invalid map index specified"); } const GiftiLabelTable* myTable = myLabel->getMapLabelTable(whichMap); int32_t unusedKey = myTable->getUnassignedLabelKey();//WARNING: this actually MODIFIES the label table if the ??? key doesn't exist set myKeys = myTable->getKeys(); int numKeys = (int)myKeys.size(); if (numKeys < 2) { throw AlgorithmException("label table doesn't contain any keys besides the ??? key"); } int numNodes = myLabel->getNumberOfNodes(); map keyToMap;//lookup from keys to column myMetricOut->setNumberOfNodesAndColumns(numNodes, numKeys - 1);//skip the ??? label myMetricOut->setStructure(myLabel->getStructure()); for (int i = 0; i < numKeys - 1; ++i) { myMetricOut->initializeColumn(i, 0.0f); } int counter = 0; for (set::iterator iter = myKeys.begin(); iter != myKeys.end(); ++iter) { if (*iter == unusedKey) continue;//skip the ??? key keyToMap[*iter] = counter; myMetricOut->setMapName(counter, myTable->getLabelName(*iter)); ++counter; } const int32_t* myColumn = myLabel->getLabelKeyPointerForColumn(whichMap); for (int i = 0; i < numNodes; ++i) { map::iterator iter = keyToMap.find(myColumn[i]); if (iter != keyToMap.end()) { myMetricOut->setValue(i, iter->second, 1.0f); } } } float AlgorithmGiftiAllLabelsToROIs::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmGiftiAllLabelsToROIs::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmGiftiAllLabelsToROIs.h000066400000000000000000000033451360521144700264360ustar00rootroot00000000000000#ifndef __ALGORITHM_GIFTI_ALL_LABELS_TO_ROIS_H__ #define __ALGORITHM_GIFTI_ALL_LABELS_TO_ROIS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmGiftiAllLabelsToROIs : public AbstractAlgorithm { AlgorithmGiftiAllLabelsToROIs(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmGiftiAllLabelsToROIs(ProgressObject* myProgObj, const LabelFile* myLabel, const int& whichMap, MetricFile* myMetricOut); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmGiftiAllLabelsToROIs; } #endif //__ALGORITHM_GIFTI_ALL_LABELS_TO_ROIS_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmGiftiLabelAddPrefix.cxx000066400000000000000000000067311360521144700267260ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmGiftiLabelAddPrefix.h" #include "AlgorithmException.h" #include "GiftiLabelTable.h" #include "LabelFile.h" using namespace caret; using namespace std; AString AlgorithmGiftiLabelAddPrefix::getCommandSwitch() { return "-gifti-label-add-prefix"; } AString AlgorithmGiftiLabelAddPrefix::getShortDescription() { return "ADD PREFIX TO ALL LABEL NAMES IN A GIFTI LABEL FILE"; } OperationParameters* AlgorithmGiftiLabelAddPrefix::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addLabelParameter(1, "label-in", "the input label file"); ret->addStringParameter(2, "prefix", "the prefix string to add"); ret->addLabelOutputParameter(3, "label-out", "the output label file"); ret->setHelpText( AString("For each label other than '?\?\?', prepend to the label name."));//bleh, trigraphs return ret; } void AlgorithmGiftiLabelAddPrefix::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LabelFile* labelIn = myParams->getLabel(1); AString prefix = myParams->getString(2); LabelFile* labelOut = myParams->getOutputLabel(3); AlgorithmGiftiLabelAddPrefix(myProgObj, labelIn, prefix, labelOut); } AlgorithmGiftiLabelAddPrefix::AlgorithmGiftiLabelAddPrefix(ProgressObject* myProgObj, const LabelFile* labelIn, const AString& prefix, LabelFile* labelOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int numColumns = labelIn->getNumberOfColumns(); GiftiLabelTable outTable = *(labelIn->getLabelTable()); vector keys; outTable.getKeys(keys); int numKeys = (int)keys.size(); int32_t unassigned = GiftiLabelTable(outTable).getUnassignedLabelKey();//make a copy so getUnassignedLabelKey() doesn't modify the one we are using for (int i = 0; i < numKeys; ++i) { if (keys[i] != unassigned) { outTable.setLabelName(keys[i], prefix + outTable.getLabelName(keys[i])); } } labelOut->setNumberOfNodesAndColumns(labelIn->getNumberOfNodes(), numColumns); labelOut->setStructure(labelIn->getStructure()); *(labelOut->getLabelTable()) = outTable; for (int i = 0; i < numColumns; ++i) { labelOut->setMapName(i, labelIn->getMapName(i)); labelOut->setLabelKeysForColumn(i, labelIn->getLabelKeyPointerForColumn(i)); } } float AlgorithmGiftiLabelAddPrefix::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmGiftiLabelAddPrefix::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmGiftiLabelAddPrefix.h000066400000000000000000000033301360521144700263430ustar00rootroot00000000000000#ifndef __ALGORITHM_GIFTI_LABEL_ADD_PREFIX_H__ #define __ALGORITHM_GIFTI_LABEL_ADD_PREFIX_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmGiftiLabelAddPrefix : public AbstractAlgorithm { AlgorithmGiftiLabelAddPrefix(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmGiftiLabelAddPrefix(ProgressObject* myProgObj, const LabelFile* labelIn, const AString& prefix, LabelFile* labelOut); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmGiftiLabelAddPrefix; } #endif //__ALGORITHM_GIFTI_LABEL_ADD_PREFIX_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmGiftiLabelToROI.cxx000066400000000000000000000221231360521144700260050ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmGiftiLabelToROI.h" #include "AlgorithmException.h" #include "CaretLogger.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "LabelFile.h" #include "MetricFile.h" #include #include using namespace caret; using namespace std; AString AlgorithmGiftiLabelToROI::getCommandSwitch() { return "-gifti-label-to-roi"; } AString AlgorithmGiftiLabelToROI::getShortDescription() { return "MAKE A GIFTI LABEL INTO AN ROI METRIC"; } OperationParameters* AlgorithmGiftiLabelToROI::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addLabelParameter(1, "label-in", "the input gifti label file"); ret->addMetricOutputParameter(2, "metric-out", "the output metric file"); OptionalParameter* nameOpt = ret->createOptionalParameter(3, "-name", "select label by name"); nameOpt->addStringParameter(1, "label-name", "the label name that you want an roi of"); OptionalParameter* keyOpt = ret->createOptionalParameter(4, "-key", "select label by key"); keyOpt->addIntegerParameter(1, "label-key", "the label key that you want an roi of"); OptionalParameter* mapOpt = ret->createOptionalParameter(5, "-map", "select a single label map to use"); mapOpt->addStringParameter(1, "map", "the map number or name"); ret->setHelpText( AString("For each map in , a map is created in where all locations labeled with or with a key of are given a value of 1, and all other locations are given 0. ") + "Exactly one of -name and -key must be specified. " + "Specify -map to use only one map from ." ); return ret; } void AlgorithmGiftiLabelToROI::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LabelFile* myLabel = myParams->getLabel(1); MetricFile* myMetricOut = myParams->getOutputMetric(2); bool nameMode = false; AString labelName; OptionalParameter* nameOpt = myParams->getOptionalParameter(3); if (nameOpt->m_present) { nameMode = true; labelName = nameOpt->getString(1); } int32_t labelKey; OptionalParameter* keyOpt = myParams->getOptionalParameter(4); if (keyOpt->m_present) { if (nameMode) throw AlgorithmException("-name and -key cannot be specified together"); labelKey = (int32_t)keyOpt->getInteger(1); } else { if (!nameMode) throw AlgorithmException("you must specify one of -name or -key"); } int whichMap = -1; OptionalParameter* mapOpt = myParams->getOptionalParameter(5); if (mapOpt->m_present) { AString mapID = mapOpt->getString(1); whichMap = myLabel->getMapIndexFromNameOrNumber(mapID); if (whichMap == -1) { throw AlgorithmException("invalid map number or name specified"); } } if (nameMode) { AlgorithmGiftiLabelToROI(myProgObj, myLabel, labelName, myMetricOut, whichMap); } else { AlgorithmGiftiLabelToROI(myProgObj, myLabel, labelKey, myMetricOut, whichMap); } } AlgorithmGiftiLabelToROI::AlgorithmGiftiLabelToROI(ProgressObject* myProgObj, const LabelFile* myLabel, const AString& labelName, MetricFile* myMetricOut, const int& whichMap) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int64_t numNodes = myLabel->getNumberOfNodes(); int64_t numMaps = myLabel->getNumberOfMaps(); if (whichMap < -1 || whichMap >= numMaps) { throw AlgorithmException("invalid map index specified"); } const GiftiLabelTable* myTable = myLabel->getLabelTable(); int32_t matchKey = myTable->getLabelKeyFromName(labelName); if (matchKey == GiftiLabel::getInvalidLabelKey()) { throw AlgorithmException("label name '" + labelName + "' not found in label file"); } vector scratchCol(numNodes); if (whichMap == -1) { myMetricOut->setNumberOfNodesAndColumns(numNodes, numMaps); myMetricOut->setStructure(myLabel->getStructure()); bool shouldThrow = true; for (int thisMap = 0; thisMap < numMaps; ++thisMap) { myMetricOut->setColumnName(thisMap, myLabel->getColumnName(thisMap)); const int32_t* labelColumn = myLabel->getLabelKeyPointerForColumn(thisMap); for (int i = 0; i < numNodes; ++i) { if (labelColumn[i] == matchKey) { scratchCol[i] = 1.0f; shouldThrow = false; } else { scratchCol[i] = 0.0f; } } myMetricOut->setValuesForColumn(thisMap, scratchCol.data()); } if (shouldThrow) { throw AlgorithmException("no data matched the specified label name"); } } else { myMetricOut->setNumberOfNodesAndColumns(numNodes, 1); myMetricOut->setStructure(myLabel->getStructure()); myMetricOut->setColumnName(0, myLabel->getColumnName(whichMap)); const int32_t* labelColumn = myLabel->getLabelKeyPointerForColumn(whichMap); bool shouldThrow = true; for (int i = 0; i < numNodes; ++i) { if (labelColumn[i] == matchKey) { scratchCol[i] = 1.0f; shouldThrow = false; } else { scratchCol[i] = 0.0f; } } if (shouldThrow) { throw AlgorithmException("no data matched the specified label name in the specified map"); } myMetricOut->setValuesForColumn(0, scratchCol.data()); } } AlgorithmGiftiLabelToROI::AlgorithmGiftiLabelToROI(ProgressObject* myProgObj, const LabelFile* myLabel, const int32_t& labelKey, MetricFile* myMetricOut, const int& whichMap) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int64_t numNodes = myLabel->getNumberOfNodes(); int64_t numMaps = myLabel->getNumberOfMaps(); if (whichMap < -1 || whichMap >= numMaps) { throw AlgorithmException("invalid map index specified"); } const GiftiLabelTable* myTable = myLabel->getLabelTable(); if (myTable->getLabel(labelKey) == NULL) { CaretLogWarning("label key " + AString::number(labelKey) + " not found in label file"); } vector scratchCol(numNodes); if (whichMap == -1) { myMetricOut->setNumberOfNodesAndColumns(numNodes, numMaps); myMetricOut->setStructure(myLabel->getStructure()); bool shouldThrow = true; for (int thisMap = 0; thisMap < numMaps; ++thisMap) { myMetricOut->setColumnName(thisMap, myLabel->getColumnName(thisMap)); const int32_t* labelColumn = myLabel->getLabelKeyPointerForColumn(thisMap); for (int i = 0; i < numNodes; ++i) { if (labelColumn[i] == labelKey) { scratchCol[i] = 1.0f; shouldThrow = false; } else { scratchCol[i] = 0.0f; } } myMetricOut->setValuesForColumn(thisMap, scratchCol.data()); } if (shouldThrow) { throw AlgorithmException("no data matched the specified label key"); } } else { myMetricOut->setNumberOfNodesAndColumns(numNodes, 1); myMetricOut->setStructure(myLabel->getStructure()); myMetricOut->setColumnName(0, myLabel->getColumnName(whichMap)); const int32_t* labelColumn = myLabel->getLabelKeyPointerForColumn(whichMap); bool shouldThrow = true; for (int i = 0; i < numNodes; ++i) { if (labelColumn[i] == labelKey) { scratchCol[i] = 1.0f; } else { scratchCol[i] = 0.0f; } } if (shouldThrow) { throw AlgorithmException("no data matched the specified label key in the specified map"); } myMetricOut->setValuesForColumn(0, scratchCol.data()); } } float AlgorithmGiftiLabelToROI::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmGiftiLabelToROI::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmGiftiLabelToROI.h000066400000000000000000000035741360521144700254430ustar00rootroot00000000000000#ifndef __ALGORITHM_GIFTI_LABEL_TO_ROI_H__ #define __ALGORITHM_GIFTI_LABEL_TO_ROI_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmGiftiLabelToROI : public AbstractAlgorithm { AlgorithmGiftiLabelToROI(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmGiftiLabelToROI(ProgressObject* myProgObj, const LabelFile* myLabel, const AString& labelName, MetricFile* myMetricOut, const int& whichMap = -1); AlgorithmGiftiLabelToROI(ProgressObject* myProgObj, const LabelFile* myLabel, const int32_t& labelKey, MetricFile* myMetricOut, const int& whichMap = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmGiftiLabelToROI; } #endif //__ALGORITHM_GIFTI_LABEL_TO_ROI_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmLabelDilate.cxx000066400000000000000000000324571360521144700253030ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmLabelDilate.h" #include "AlgorithmException.h" #include "CaretOMP.h" #include "GeodesicHelper.h" #include "LabelFile.h" #include "MetricFile.h" #include "GiftiLabelTable.h" #include "SurfaceFile.h" #include "TopologyHelper.h" using namespace caret; using namespace std; AString AlgorithmLabelDilate::getCommandSwitch() { return "-label-dilate"; } AString AlgorithmLabelDilate::getShortDescription() { return "DILATE A LABEL FILE"; } OperationParameters* AlgorithmLabelDilate::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addLabelParameter(1, "label", "the input label"); ret->addSurfaceParameter(2, "surface", "the surface to dilate on"); ret->addDoubleParameter(3, "dilate-dist", "distance in mm to dilate the labels"); ret->addLabelOutputParameter(4, "label-out", "the output label file"); OptionalParameter* roiOpt = ret->createOptionalParameter(5, "-bad-vertex-roi", "specify an roi of vertices to overwrite, rather than vertices with the unlabeled key"); roiOpt->addMetricParameter(1, "roi-metric", "metric file, positive values denote vertices to have their values replaced"); OptionalParameter* columnSelect = ret->createOptionalParameter(6, "-column", "select a single column to dilate"); columnSelect->addStringParameter(1, "column", "the column number or name"); OptionalParameter* corrAreaOpt = ret->createOptionalParameter(7, "-corrected-areas", "vertex areas to use instead of computing them from the surface"); corrAreaOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); ret->setHelpText( AString("Fills in label information for all vertices designated as bad, up to the specified distance away from other labels. ") + "If -bad-vertex-roi is specified, all vertices, including those with the unlabeled key, are good, except for vertices with a positive value in the ROI. " + "If it is not specified, only vertices with the unlabeled key are bad." ); return ret; } void AlgorithmLabelDilate::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LabelFile* myLabel = myParams->getLabel(1); SurfaceFile* mySurf = myParams->getSurface(2); float myDist = (float)myParams->getDouble(3); LabelFile* myLabelOut = myParams->getOutputLabel(4); OptionalParameter* roiOpt = myParams->getOptionalParameter(5); MetricFile* badNodeRoi = NULL; if (roiOpt->m_present) { badNodeRoi = roiOpt->getMetric(1); } OptionalParameter* columnSelect = myParams->getOptionalParameter(6); int columnNum = -1; if (columnSelect->m_present) {//set up to use the single column columnNum = (int)myLabel->getMapIndexFromNameOrNumber(columnSelect->getString(1)); if (columnNum < 0) { throw AlgorithmException("invalid column specified"); } } OptionalParameter* corrAreaOpt = myParams->getOptionalParameter(7); MetricFile* corrAreas = NULL; if (corrAreaOpt->m_present) { corrAreas = corrAreaOpt->getMetric(1); } AlgorithmLabelDilate(myProgObj, myLabel, mySurf, myDist, myLabelOut, badNodeRoi, columnNum, corrAreas); } AlgorithmLabelDilate::AlgorithmLabelDilate(ProgressObject* myProgObj, const LabelFile* myLabel, const SurfaceFile* mySurf, float myDist, LabelFile* myLabelOut, const MetricFile* badNodeRoi, int columnNum, const MetricFile* corrAreas) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int32_t unusedLabel = myLabel->getLabelTable()->getUnassignedLabelKey(); int numColumns = myLabel->getNumberOfColumns(); if (myDist < 0.0f) { throw AlgorithmException("invalid distance specified"); } if (columnNum < -1 || columnNum >= numColumns) { throw AlgorithmException("invalid column specified"); } int numNodes = myLabel->getNumberOfNodes(); if (mySurf->getNumberOfNodes() != numNodes) { throw AlgorithmException("surface has wrong number of vertices for this label file"); } if (corrAreas != NULL && corrAreas->getNumberOfNodes() != numNodes) { throw AlgorithmException("corrected areas metric number of vertices does not match"); } CaretArray colScratch(numNodes); CaretArray markArray(numNodes); if (badNodeRoi != NULL) { const float* myRoiData = badNodeRoi->getValuePointerForColumn(0); for (int i = 0; i < numNodes; ++i) { if (myRoiData[i] > 0.0f) { markArray[i] = 0; } else { markArray[i] = 1; } } } CaretPointer myCorrBase; if (corrAreas != NULL) { myCorrBase.grabNew(new GeodesicHelperBase(mySurf, corrAreas->getValuePointerForColumn(0))); } if (columnNum == -1) { myLabelOut->setNumberOfNodesAndColumns(numNodes, myLabel->getNumberOfColumns()); *(myLabelOut->getLabelTable()) = *(myLabel->getLabelTable()); myLabelOut->setStructure(mySurf->getStructure()); for (int thisCol = 0; thisCol < myLabel->getNumberOfColumns(); ++thisCol) { const int32_t* myInputData = myLabel->getLabelKeyPointerForColumn(thisCol); myLabelOut->setColumnName(thisCol, myLabel->getColumnName(thisCol) + " dilated"); if (badNodeRoi == NULL) { for (int i = 0; i < numNodes; ++i) { if (myInputData[i] == unusedLabel) { markArray[i] = 0; } else { markArray[i] = 1; } } } #pragma omp CARET_PAR { CaretPointer myTopoHelp = mySurf->getTopologyHelper(); CaretPointer myGeoHelp; if (corrAreas == NULL) { myGeoHelp = mySurf->getGeodesicHelper(); } else { myGeoHelp.grabNew(new GeodesicHelper(myCorrBase)); } #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < numNodes; ++i) { if (markArray[i] == 0) { vector nodeList; vector distList; myGeoHelp->getNodesToGeoDist(i, myDist, nodeList, distList); int numInRange = (int)nodeList.size(); bool first = true; float bestDist = -1.0f; int32_t bestLabel = unusedLabel; for (int j = 0; j < numInRange; ++j) { if (markArray[nodeList[j]] == 1) { if (first || distList[j] < bestDist) { first = false; bestDist = distList[j]; bestLabel = myInputData[nodeList[j]]; } } } if (!first) { colScratch[i] = bestLabel; } else { nodeList = myTopoHelp->getNodeNeighbors(i); nodeList.push_back(i); myGeoHelp->getGeoToTheseNodes(i, nodeList, distList);//ok, its a little silly to do this numInRange = (int)nodeList.size(); for (int j = 0; j < numInRange; ++j) { if (markArray[nodeList[j]] == 1) { if (first || distList[j] < bestDist) { first = false; bestDist = distList[j]; bestLabel = myInputData[nodeList[j]]; } } } if (!first) { colScratch[i] = bestLabel; } else { colScratch[i] = unusedLabel; } } } else { colScratch[i] = myInputData[i]; } } } myLabelOut->setLabelKeysForColumn(thisCol, colScratch.getArray()); } } else { myLabelOut->setNumberOfNodesAndColumns(numNodes, 1); *(myLabelOut->getLabelTable()) = *(myLabel->getLabelTable()); myLabelOut->setStructure(mySurf->getStructure()); const int32_t* myInputData = myLabel->getLabelKeyPointerForColumn(columnNum); myLabelOut->setColumnName(0, myLabel->getColumnName(columnNum) + " dilated"); if (badNodeRoi == NULL) { for (int i = 0; i < numNodes; ++i) { if (myInputData[i] == unusedLabel) { markArray[i] = 0; } else { markArray[i] = 1; } } } #pragma omp CARET_PAR { CaretPointer myTopoHelp = mySurf->getTopologyHelper(); CaretPointer myGeoHelp; if (corrAreas == NULL) { myGeoHelp = mySurf->getGeodesicHelper(); } else { myGeoHelp.grabNew(new GeodesicHelper(myCorrBase)); } #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < numNodes; ++i) { if (markArray[i] == 0) { vector nodeList; vector distList; myGeoHelp->getNodesToGeoDist(i, myDist, nodeList, distList); int numInRange = (int)nodeList.size(); bool first = true; float bestDist = -1.0f; int32_t bestLabel = unusedLabel; for (int j = 0; j < numInRange; ++j) { if (markArray[nodeList[j]] == 1) { if (first || distList[j] < bestDist) { first = false; bestDist = distList[j]; bestLabel = myInputData[nodeList[j]]; } } } if (!first) { colScratch[i] = bestLabel; } else { nodeList = myTopoHelp->getNodeNeighbors(i); nodeList.push_back(i); myGeoHelp->getGeoToTheseNodes(i, nodeList, distList);//ok, its a little silly to do this numInRange = (int)nodeList.size(); for (int j = 0; j < numInRange; ++j) { if (markArray[nodeList[j]] == 1) { if (first || distList[j] < bestDist) { first = false; bestDist = distList[j]; bestLabel = myInputData[nodeList[j]]; } } } if (!first) { colScratch[i] = bestLabel; } else { colScratch[i] = unusedLabel; } } } else { colScratch[i] = myInputData[i]; } } } myLabelOut->setLabelKeysForColumn(0, colScratch.getArray()); } } float AlgorithmLabelDilate::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmLabelDilate::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmLabelDilate.h000066400000000000000000000034401360521144700247160ustar00rootroot00000000000000#ifndef __ALGORITHM_LABEL_DILATE_H__ #define __ALGORITHM_LABEL_DILATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmLabelDilate : public AbstractAlgorithm { AlgorithmLabelDilate(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmLabelDilate(ProgressObject* myProgObj, const LabelFile* myLabel, const SurfaceFile* mySurf, float myDist, LabelFile* myLabelOut, const MetricFile* badNodeRoi = NULL, int columnNum = -1, const MetricFile* corrAreas = NULL); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmLabelDilate; } #endif //__ALGORITHM_LABEL_DILATE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmLabelErode.cxx000066400000000000000000000226641360521144700251360ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmLabelErode.h" #include "AlgorithmException.h" #include "GeodesicHelper.h" #include "LabelFile.h" #include "GiftiLabelTable.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "TopologyHelper.h" using namespace caret; using namespace std; AString AlgorithmLabelErode::getCommandSwitch() { return "-label-erode"; } AString AlgorithmLabelErode::getShortDescription() { return "ERODE A LABEL FILE"; } OperationParameters* AlgorithmLabelErode::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addLabelParameter(1, "label", "the input label"); ret->addSurfaceParameter(2, "surface", "the surface to erode on"); ret->addDoubleParameter(3, "erode-dist", "distance in mm to erode the labels"); ret->addLabelOutputParameter(4, "label-out", "the output label file"); OptionalParameter* dataRoiOpt = ret->createOptionalParameter(5, "-roi", "assume values outside this roi are labeled"); dataRoiOpt->addMetricParameter(1, "roi-metric", "metric file, positive values denote vertices that have data"); OptionalParameter* columnSelect = ret->createOptionalParameter(6, "-column", "select a single column to erode"); columnSelect->addStringParameter(1, "column", "the column number or name"); OptionalParameter* corrAreaOpt = ret->createOptionalParameter(7, "-corrected-areas", "vertex areas to use instead of computing them from the surface"); corrAreaOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); ret->setHelpText( AString("Around each vertex that is unlabeled, set surrounding vertices to unlabeled. ") + "The surrounding vertices are all immediate neighbors and all vertices within the specified distance." + "\n\nNote that the -corrected-areas option uses an approximate correction for distance along the surface." ); return ret; } void AlgorithmLabelErode::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LabelFile* myLabel = myParams->getLabel(1); SurfaceFile* mySurf = myParams->getSurface(2); float myDist = (float)myParams->getDouble(3); LabelFile* myLabelOut = myParams->getOutputLabel(4); OptionalParameter* roiOpt = myParams->getOptionalParameter(5); MetricFile* myRoi = NULL; if (roiOpt->m_present) { myRoi = roiOpt->getMetric(1); } OptionalParameter* columnSelect = myParams->getOptionalParameter(6); int columnNum = -1; if (columnSelect->m_present) {//set up to use the single column columnNum = (int)myLabel->getMapIndexFromNameOrNumber(columnSelect->getString(1)); if (columnNum < 0) { throw AlgorithmException("invalid column specified"); } } OptionalParameter* corrAreaOpt = myParams->getOptionalParameter(7); MetricFile* corrAreas = NULL; if (corrAreaOpt->m_present) { corrAreas = corrAreaOpt->getMetric(1); } AlgorithmLabelErode(myProgObj, myLabel, mySurf, myDist, myLabelOut, myRoi, columnNum, corrAreas); } namespace { vector > precomputeStencils(const SurfaceFile* mySurf, const float& distance, const MetricFile* corrAreas, const float* roiCol) { int numNodes = mySurf->getNumberOfNodes(); vector > ret(numNodes); CaretPointer myGeoBase; if (corrAreas != NULL) { myGeoBase.grabNew(new GeodesicHelperBase(mySurf, corrAreas->getValuePointerForColumn(0))); } CaretPointer myTopoHelp = mySurf->getTopologyHelper();//we aren't using to depth, so share the topology helper #pragma omp CARET_PAR {//use parallel here so each thread gets its own geodesic helper CaretPointer myGeoHelp; if (corrAreas == NULL) { myGeoHelp = mySurf->getGeodesicHelper(); } else { myGeoHelp.grabNew(new GeodesicHelper(myGeoBase)); } #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < numNodes; ++i) { if (roiCol == NULL || roiCol[i] > 0.0f) { vector geoNodes; vector geoDists; myGeoHelp->getNodesToGeoDist(i, distance, geoNodes, geoDists); const vector& topoNodes = myTopoHelp->getNodeNeighbors(i); set mergeSet(geoNodes.begin(), geoNodes.end()); mergeSet.insert(topoNodes.begin(), topoNodes.end()); mergeSet.erase(i);//center of stencil is already 0 if stencil is used, so don't set it again ret[i] = vector(mergeSet.begin(), mergeSet.end()); } } } return ret; } } AlgorithmLabelErode::AlgorithmLabelErode(ProgressObject* myProgObj, const LabelFile* myLabel, const SurfaceFile* mySurf, const float& myDist, LabelFile* myLabelOut, const MetricFile* myRoi, const int& columnNum, const MetricFile* corrAreas) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int numNodes = mySurf->getNumberOfNodes(); if (numNodes != myLabel->getNumberOfNodes()) { throw AlgorithmException("surface and metric number of vertices do not match"); } if (myRoi != NULL && myRoi->getNumberOfNodes() != numNodes) { throw AlgorithmException("roi number of vertices does not match"); } if (corrAreas != NULL && corrAreas->getNumberOfNodes() != numNodes) { throw AlgorithmException("corrected areas metric number of vertices does not match"); } int numInColumns = myLabel->getNumberOfColumns(); if (columnNum < -1 || columnNum >= numInColumns) { throw AlgorithmException("invalid column specified"); } if (myDist < 0.0f) { throw AlgorithmException("distance cannot be negative"); } if (columnNum == -1) { myLabelOut->setNumberOfNodesAndColumns(numNodes, numInColumns); } else { myLabelOut->setNumberOfNodesAndColumns(numNodes, 1); } myLabelOut->setStructure(mySurf->getStructure()); const int32_t unlabeledKey = myLabel->getLabelTable()->getUnassignedLabelKey();//will have same key for both *(myLabelOut->getLabelTable()) = *(myLabel->getLabelTable());//file type has only one label table for the whole file const float* roiCol = NULL; if (myRoi != NULL) { roiCol = myRoi->getValuePointerForColumn(0); } vector > stencils = precomputeStencils(mySurf, myDist, corrAreas, roiCol); if (columnNum == -1) { for (int c = 0; c < numInColumns; ++c) { const int32_t* inData = myLabel->getLabelKeyPointerForColumn(c); vector scratchCol(inData, inData + numNodes); for (int i = 0; i < numNodes; ++i) { if (roiCol == NULL || roiCol[i] > 0.0f) { if (inData[i] == unlabeledKey) { for (int n = 0; n < (int)stencils[i].size(); ++n) { scratchCol[stencils[i][n]] = unlabeledKey; } } } else { scratchCol[i] = unlabeledKey;//zero things outside the data roi } } myLabelOut->setMapName(c, myLabel->getMapName(c)); myLabelOut->setLabelKeysForColumn(c, scratchCol.data()); } } else { const int32_t* inData = myLabel->getLabelKeyPointerForColumn(columnNum); vector scratchCol(inData, inData + numNodes); for (int i = 0; i < numNodes; ++i) { if (roiCol == NULL || roiCol[i] > 0.0f) { if (inData[i] == unlabeledKey) { for (int n = 0; n < (int)stencils[i].size(); ++n) { scratchCol[stencils[i][n]] = unlabeledKey; } } } else { scratchCol[i] = unlabeledKey;//zero things outside the data roi } } myLabelOut->setMapName(0, myLabel->getMapName(columnNum)); myLabelOut->setLabelKeysForColumn(0, scratchCol.data()); } } float AlgorithmLabelErode::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmLabelErode::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmLabelErode.h000066400000000000000000000034401360521144700245520ustar00rootroot00000000000000#ifndef __ALGORITHM_LABEL_ERODE_H__ #define __ALGORITHM_LABEL_ERODE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmLabelErode : public AbstractAlgorithm { AlgorithmLabelErode(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmLabelErode(ProgressObject* myProgObj, const LabelFile* myLabel, const SurfaceFile* mySurf, const float& myDist, LabelFile* myLabelOut, const MetricFile* myRoi = NULL, const int& columnNum = -1, const MetricFile* corrAreas = NULL); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmLabelErode; } #endif //__ALGORITHM_LABEL_ERODE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmLabelModifyKeys.cxx000066400000000000000000000242141360521144700261540ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmLabelModifyKeys.h" #include "AlgorithmException.h" #include "FileInformation.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "LabelFile.h" #include #include using namespace caret; using namespace std; AString AlgorithmLabelModifyKeys::getCommandSwitch() { return "-label-modify-keys"; } AString AlgorithmLabelModifyKeys::getShortDescription() { return "CHANGE KEY VALUES IN A LABEL FILE"; } OperationParameters* AlgorithmLabelModifyKeys::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addLabelParameter(1, "label-in", "the input label file"); ret->addStringParameter(2, "remap-file", "text file with old and new key values"); ret->addLabelOutputParameter(3, "label-out", "output label file"); OptionalParameter* columnOpt = ret->createOptionalParameter(4, "-column", "select a single column to use"); columnOpt->addStringParameter(1, "column", "the column number or name"); ret->setHelpText( AString(" should have lines of the form 'oldkey newkey', like so:\n\n") + "3 5\n5 8\n8 2\n\n" + "This would change the current label with key '3' to use the key '5' instead, 5 would use 8, and 8 would use 2. " + "Any collision in key values results in the label that was not specified in the remap file getting remapped to an otherwise unused key. " + "Remapping more than one key to the same new key, or the same key to more than one new key, results in an error. " + "This will not change the appearance of the file when displayed, as it will change the key values in the data at the same time." ); return ret; } void AlgorithmLabelModifyKeys::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LabelFile* labelIn = myParams->getLabel(1); AString remapName = myParams->getString(2); LabelFile* labelOut = myParams->getOutputLabel(3); int column = -1; OptionalParameter* columnOpt = myParams->getOptionalParameter(4); if (columnOpt->m_present) { column = labelIn->getMapIndexFromNameOrNumber(columnOpt->getString(1)); if (column < 0) throw AlgorithmException("invalid column specified"); } FileInformation textFileInfo(remapName); if (!textFileInfo.exists()) { throw AlgorithmException("label list file doesn't exist"); } fstream remapFile(remapName.toLocal8Bit().constData(), fstream::in); if (!remapFile.good()) { throw AlgorithmException("error reading label list file"); } map remap; int32_t oldkey, newkey; while (remapFile >> oldkey >> newkey) { if (remap.find(oldkey) != remap.end()) throw AlgorithmException("remapping tried to duplicate label " + AString::number(oldkey)); remap[oldkey] = newkey; } AlgorithmLabelModifyKeys(myProgObj, labelIn, remap, labelOut, column); } AlgorithmLabelModifyKeys::AlgorithmLabelModifyKeys(ProgressObject* myProgObj, const LabelFile* labelIn, const map& remap, LabelFile* labelOut, const int& column) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const GiftiLabelTable* oldTable = labelIn->getLabelTable(); int32_t oldUnlabeled = oldTable->getUnassignedLabelKey();//because GiftiLabelTable is quirky, we need to check if the unlabeled value ends up as something other than 0 GiftiLabelTable newTable;//beware: key 0 already has the "???" label bool setZero = false;//because of this, we need to track if we overwrote it, so that we can pretend it isn't there for (map::const_iterator iter = remap.begin(); iter != remap.end(); ++iter) { const GiftiLabel* oldLabel = oldTable->getLabel(iter->first); if (oldLabel == NULL) throw AlgorithmException("label key " + AString::number(iter->first) + " does not exist in the input file"); GiftiLabel newLabel(*oldLabel); newLabel.setKey(iter->second); if (iter->first == oldUnlabeled) { if (iter->second != 0)//if it isn't the default unlabeled value, then we have to do something { if (newTable.getLabel(iter->second) != NULL) throw AlgorithmException("remapping tried to set label " + AString::number(iter->second) + " more than once"); newTable.deleteLabel(0);//delete the default, since we don't know what overwrites it, if anything newTable.insertLabel(&newLabel);//insert forces it to use the key in the label, even if it causes a duplicate name (which the original might theoretically have) } else {//otherwise, just error checking if (setZero) throw AlgorithmException("remapping tried to set label " + AString::number(iter->second) + " more than once"); setZero = true;//we do have to track that zero now contains something that can't be overwritten } } else { if (iter->second == 0)//if it remaps to the default unlabeled key, we have to check it differently { if (setZero) throw AlgorithmException("remapping tried to set label " + AString::number(iter->second) + " more than once"); setZero = true; newTable.insertLabel(&newLabel);//insert forces it to use the key in the label, so it will overwrite the existing default 0 key } else {//finally, the simple case if (newTable.getLabel(iter->second) != NULL) throw AlgorithmException("remapping tried to set label " + AString::number(iter->second) + " more than once"); newTable.insertLabel(&newLabel);//insert forces it to use the key in the label, even if it causes a duplicate name (which the original might theoretically have) } } } set keys = oldTable->getKeys(), collisions; for (set::const_iterator iter = keys.begin(); iter != keys.end(); ++iter) { if (remap.find(*iter) == remap.end())//skip if it was remapped { if (*iter == 0)//again with the special default 0 key { if (setZero)//check for collision { collisions.insert(*iter); } else { setZero = true; if (*iter != oldUnlabeled)//if its merely the unassigned label already, we can just keep the existing default { newTable.insertLabel(oldTable->getLabel(*iter)); } } } else { if (newTable.getLabel(*iter) == NULL) { newTable.insertLabel(oldTable->getLabel(*iter)); } else {//collision collisions.insert(*iter); } } } } map valueChanges = remap;//start with the specified changes, then add the collision changes for (set::const_iterator iter = collisions.begin(); iter != collisions.end(); ++iter) {//now deal with collisions int32_t newKey = newTable.generateUnusedKey(); GiftiLabel newLabel(*(oldTable->getLabel(*iter))); newLabel.setKey(newKey); newTable.insertLabel(&newLabel);//insert forces it to use the key in the label, even if it causes a duplicate name (which the original might theoretically have) valueChanges[*iter] = newKey; } int numNodes = labelIn->getNumberOfNodes(), numColumns = labelIn->getNumberOfColumns(); vector scratchCol(numNodes); if (column == -1) { labelOut->setNumberOfNodesAndColumns(numNodes, numColumns); labelOut->setStructure(labelIn->getStructure()); *(labelOut->getLabelTable()) = newTable; for (int i = 0; i < numColumns; ++i) { labelOut->setColumnName(i, labelIn->getColumnName(i)); const int32_t* inCol = labelIn->getLabelKeyPointerForColumn(i); for (int j = 0; j < numNodes; ++j) { map::const_iterator iter = valueChanges.find(inCol[j]); if (iter == valueChanges.end()) { scratchCol[j] = inCol[j]; } else { scratchCol[j] = iter->second; } } labelOut->setLabelKeysForColumn(i, scratchCol.data()); } } else { labelOut->setNumberOfNodesAndColumns(numNodes, 1); labelOut->setStructure(labelIn->getStructure()); *(labelOut->getLabelTable()) = newTable; labelOut->setColumnName(0, labelIn->getColumnName(column)); const int32_t* inCol = labelIn->getLabelKeyPointerForColumn(column); for (int j = 0; j < numNodes; ++j) { map::const_iterator iter = valueChanges.find(inCol[j]); if (iter == valueChanges.end()) { scratchCol[j] = inCol[j]; } else { scratchCol[j] = iter->second; } } labelOut->setLabelKeysForColumn(0, scratchCol.data()); } } float AlgorithmLabelModifyKeys::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmLabelModifyKeys::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmLabelModifyKeys.h000066400000000000000000000033571360521144700256060ustar00rootroot00000000000000#ifndef __ALGORITHM_LABEL_MODIFY_KEYS_H__ #define __ALGORITHM_LABEL_MODIFY_KEYS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include namespace caret { class AlgorithmLabelModifyKeys : public AbstractAlgorithm { AlgorithmLabelModifyKeys(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmLabelModifyKeys(ProgressObject* myProgObj, const LabelFile* labelIn, const std::map& remap, LabelFile* labelOut, const int& column = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmLabelModifyKeys; } #endif //__ALGORITHM_LABEL_MODIFY_KEYS_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmLabelProbability.cxx000066400000000000000000000115041360521144700263470ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmLabelProbability.h" #include "AlgorithmException.h" #include "GiftiLabelTable.h" #include "LabelFile.h" #include "MetricFile.h" #include #include using namespace caret; using namespace std; AString AlgorithmLabelProbability::getCommandSwitch() { return "-label-probability"; } AString AlgorithmLabelProbability::getShortDescription() { return "FIND FREQUENCY OF SURFACE LABELS"; } OperationParameters* AlgorithmLabelProbability::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addLabelParameter(1, "label-maps", "label file containing individual label maps from many subjects"); ret->addMetricOutputParameter(2, "probability-metric-out", "the relative frequencies of each label at each vertex"); ret->createOptionalParameter(3, "-exclude-unlabeled", "don't make a probability map of the unlabeled key"); ret->setHelpText( AString("This command outputs a set of soft ROIs, one for each label in the input, ") + "where the value is how many of the input maps had that label at that vertex, divided by the number of input maps." ); return ret; } void AlgorithmLabelProbability::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { const LabelFile* inputLabel = myParams->getLabel(1); MetricFile* outputMetric = myParams->getOutputMetric(2); bool excludeUnlabeled = myParams->getOptionalParameter(3)->m_present; AlgorithmLabelProbability(myProgObj, inputLabel, outputMetric, excludeUnlabeled); } AlgorithmLabelProbability::AlgorithmLabelProbability(ProgressObject* myProgObj, const LabelFile* inputLabel, MetricFile* outputMetric, const bool& excludeUnlabeled) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int numNodes = inputLabel->getNumberOfNodes(); int numInMaps = inputLabel->getNumberOfMaps();//note: label files have only one label table that covers the entire file, and should never have duplicate names map keyToOutMapLookup; vector outMapNames; const GiftiLabelTable* fileTable = inputLabel->getLabelTable(); set keys = fileTable->getKeys(); int32_t unlabeledKey = -1;//don't request it from label table if we aren't going to exclude it, as that could create the unassigned key if (excludeUnlabeled) { unlabeledKey = fileTable->getUnassignedLabelKey(); } for (set::iterator iter = keys.begin(); iter != keys.end(); ++iter) { if (excludeUnlabeled && *iter == unlabeledKey) continue; int newOutMap = (int)keyToOutMapLookup.size();//get size before [] allocates a new member keyToOutMapLookup[*iter] = newOutMap; outMapNames.push_back(fileTable->getLabelName(*iter)); } int numOutMaps = keyToOutMapLookup.size(); vector > counts(numOutMaps, vector(numNodes, 0)); for (int m = 0; m < numInMaps; ++m) { const int32_t* data = inputLabel->getLabelKeyPointerForColumn(m); for (int i = 0; i < numNodes; ++i) { map::iterator search = keyToOutMapLookup.find(data[i]); if (search != keyToOutMapLookup.end()) { ++counts[search->second][i]; } } } vector scratch(numNodes); outputMetric->setNumberOfNodesAndColumns(numNodes, numOutMaps); outputMetric->setStructure(inputLabel->getStructure()); for (int m = 0; m < numOutMaps; ++m) { outputMetric->setMapName(m, outMapNames[m]); for (int i = 0; i < numNodes; ++i) { scratch[i] = ((float)counts[m][i]) / numInMaps; } outputMetric->setValuesForColumn(m, scratch.data()); } } float AlgorithmLabelProbability::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmLabelProbability::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmLabelProbability.h000066400000000000000000000033211360521144700257720ustar00rootroot00000000000000#ifndef __ALGORITHM_LABEL_PROBABILITY_H__ #define __ALGORITHM_LABEL_PROBABILITY_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmLabelProbability : public AbstractAlgorithm { AlgorithmLabelProbability(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmLabelProbability(ProgressObject* myProgObj, const LabelFile* inputLabel, MetricFile* outputMetric, const bool& excludeUnlabeled = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmLabelProbability; } #endif //__ALGORITHM_LABEL_PROBABILITY_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmLabelResample.cxx000066400000000000000000000246561360521144700256530ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmLabelResample.h" #include "AlgorithmException.h" #include "CaretLogger.h" #include "GiftiLabelTable.h" #include "LabelFile.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "SurfaceResamplingHelper.h" using namespace caret; using namespace std; AString AlgorithmLabelResample::getCommandSwitch() { return "-label-resample"; } AString AlgorithmLabelResample::getShortDescription() { return "RESAMPLE A LABEL FILE TO A DIFFERENT MESH"; } OperationParameters* AlgorithmLabelResample::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addLabelParameter(1, "label-in", "the label file to resample"); ret->addSurfaceParameter(2, "current-sphere", "a sphere surface with the mesh that the label file is currently on"); ret->addSurfaceParameter(3, "new-sphere", "a sphere surface that is in register with and has the desired output mesh"); ret->addStringParameter(4, "method", "the method name"); ret->addLabelOutputParameter(5, "label-out", "the output label file"); OptionalParameter* areaSurfsOpt = ret->createOptionalParameter(6, "-area-surfs", "specify surfaces to do vertex area correction based on"); areaSurfsOpt->addSurfaceParameter(1, "current-area", "a relevant anatomical surface with mesh"); areaSurfsOpt->addSurfaceParameter(2, "new-area", "a relevant anatomical surface with mesh"); OptionalParameter* areaMetricsOpt = ret->createOptionalParameter(7, "-area-metrics", "specify vertex area metrics to do area correction based on"); areaMetricsOpt->addMetricParameter(1, "current-area", "a metric file with vertex areas for mesh"); areaMetricsOpt->addMetricParameter(2, "new-area", "a metric file with vertex areas for mesh"); OptionalParameter* roiOpt = ret->createOptionalParameter(8, "-current-roi", "use an input roi on the current mesh to exclude non-data vertices"); roiOpt->addMetricParameter(1, "roi-metric", "the roi, as a metric file"); OptionalParameter* validRoiOutOpt = ret->createOptionalParameter(9, "-valid-roi-out", "output the ROI of vertices that got data from valid source vertices"); validRoiOutOpt->addMetricOutputParameter(1, "roi-out", "the output roi as a metric"); ret->createOptionalParameter(10, "-largest", "use only the label of the vertex with the largest weight"); AString myHelpText = AString("Resamples a label file, given two spherical surfaces that are in register. ") + "If ADAP_BARY_AREA is used, exactly one of -area-surfs or -area-metrics must be specified.\n\n" + "The ADAP_BARY_AREA method is recommended for label data, because it should be better at resolving vertices that are near multiple labels, or in case of downsampling. " + "Midthickness surfaces are recommended for the vertex areas for most data.\n\n" + "The -largest option results in nearest vertex behavior when used with BARYCENTRIC, as it uses the value of the source vertex that has the largest weight.\n\n" + "When -largest is not specified, the vertex weights are summed according to which label they correspond to, and the label with the largest sum is used.\n\n" + "The argument must be one of the following:\n\n"; vector allEnums; SurfaceResamplingMethodEnum::getAllEnums(allEnums); for (int i = 0; i < (int)allEnums.size(); ++i) { myHelpText += SurfaceResamplingMethodEnum::toName(allEnums[i]) + "\n"; } ret->setHelpText(myHelpText); return ret; } void AlgorithmLabelResample::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LabelFile* labelIn = myParams->getLabel(1); SurfaceFile* curSphere = myParams->getSurface(2); SurfaceFile* newSphere = myParams->getSurface(3); bool ok = false; SurfaceResamplingMethodEnum::Enum myMethod = SurfaceResamplingMethodEnum::fromName(myParams->getString(4), &ok); if (!ok) { throw AlgorithmException("invalid method name"); } LabelFile* labelOut = myParams->getOutputLabel(5); MetricFile* curAreas = NULL, *newAreas = NULL; MetricFile curAreasTemp, newAreasTemp; OptionalParameter* areaSurfsOpt = myParams->getOptionalParameter(6); if (areaSurfsOpt->m_present) { switch(myMethod) { case SurfaceResamplingMethodEnum::BARYCENTRIC: CaretLogInfo("This method does not use area correction, -area-surfs is not needed"); break; default: break; } vector nodeAreasTemp; SurfaceFile* curAreaSurf = areaSurfsOpt->getSurface(1); SurfaceFile* newAreaSurf = areaSurfsOpt->getSurface(2); curAreaSurf->computeNodeAreas(nodeAreasTemp); curAreasTemp.setNumberOfNodesAndColumns(curAreaSurf->getNumberOfNodes(), 1); curAreasTemp.setValuesForColumn(0, nodeAreasTemp.data()); curAreas = &curAreasTemp; newAreaSurf->computeNodeAreas(nodeAreasTemp); newAreasTemp.setNumberOfNodesAndColumns(newAreaSurf->getNumberOfNodes(), 1); newAreasTemp.setValuesForColumn(0, nodeAreasTemp.data()); newAreas = &newAreasTemp; } OptionalParameter* areaMetricsOpt = myParams->getOptionalParameter(7); if (areaMetricsOpt->m_present) { if (areaSurfsOpt->m_present) { throw AlgorithmException("only one of -area-surfs and -area-metrics can be specified"); } switch(myMethod) { case SurfaceResamplingMethodEnum::BARYCENTRIC: CaretLogInfo("This method does not use area correction, -area-metrics is not needed"); break; default: break; } curAreas = areaMetricsOpt->getMetric(1); newAreas = areaMetricsOpt->getMetric(2); } OptionalParameter* roiOpt = myParams->getOptionalParameter(8); MetricFile* currentRoi = NULL; if (roiOpt->m_present) { currentRoi = roiOpt->getMetric(1); } MetricFile* validRoiOut = NULL; OptionalParameter* validRoiOutOpt = myParams->getOptionalParameter(9); if (validRoiOutOpt->m_present) { validRoiOut = validRoiOutOpt->getOutputMetric(1); } bool largest = myParams->getOptionalParameter(10)->m_present; AlgorithmLabelResample(myProgObj, labelIn, curSphere, newSphere, myMethod, labelOut, curAreas, newAreas, currentRoi, validRoiOut, largest); } AlgorithmLabelResample::AlgorithmLabelResample(ProgressObject* myProgObj, const LabelFile* labelIn, const SurfaceFile* curSphere, const SurfaceFile* newSphere, const SurfaceResamplingMethodEnum::Enum& myMethod, LabelFile* labelOut, const MetricFile* curAreas, const MetricFile* newAreas, const MetricFile* currentRoi, MetricFile* validRoiOut, const bool& largest) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (labelIn->getNumberOfNodes() != curSphere->getNumberOfNodes()) throw AlgorithmException("input label file has different number of nodes than input sphere"); const float* curAreaData = NULL, *newAreaData = NULL; switch (myMethod) { case SurfaceResamplingMethodEnum::BARYCENTRIC: break; default: if (curAreas == NULL || newAreas == NULL) throw AlgorithmException("specified method does area correction, but no vertex area data given"); if (curSphere->getNumberOfNodes() != curAreas->getNumberOfNodes()) throw AlgorithmException("current vertex area data has different number of nodes than current sphere"); if (newSphere->getNumberOfNodes() != newAreas->getNumberOfNodes()) throw AlgorithmException("new vertex area data has different number of nodes than new sphere"); curAreaData = curAreas->getValuePointerForColumn(0); newAreaData = newAreas->getValuePointerForColumn(0); } int numColumns = labelIn->getNumberOfColumns(), numNewNodes = newSphere->getNumberOfNodes(); labelOut->setNumberOfNodesAndColumns(numNewNodes, numColumns); labelOut->setStructure(labelIn->getStructure()); *labelOut->getLabelTable() = *labelIn->getLabelTable(); int32_t unusedLabel = labelIn->getLabelTable()->getUnassignedLabelKey(); vector colScratch(numNewNodes, unusedLabel); const float* roiCol = NULL; if (currentRoi != NULL) roiCol = currentRoi->getValuePointerForColumn(0); SurfaceResamplingHelper myHelp(myMethod, curSphere, newSphere, curAreaData, newAreaData, roiCol); if (validRoiOut != NULL) { validRoiOut->setNumberOfNodesAndColumns(numNewNodes, 1); validRoiOut->setStructure(labelIn->getStructure()); vector scratch(numNewNodes); myHelp.getResampleValidROI(scratch.data()); validRoiOut->setValuesForColumn(0, scratch.data()); } for (int i = 0; i < numColumns; ++i) { labelOut->setColumnName(i, labelIn->getColumnName(i)); if (largest) { myHelp.resampleLargest(labelIn->getLabelKeyPointerForColumn(i), colScratch.data(), unusedLabel); } else { myHelp.resamplePopular(labelIn->getLabelKeyPointerForColumn(i), colScratch.data(), unusedLabel); } labelOut->setLabelKeysForColumn(i, colScratch.data()); } } float AlgorithmLabelResample::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmLabelResample::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmLabelResample.h000066400000000000000000000040111360521144700252570ustar00rootroot00000000000000#ifndef __ALGORITHM_LABEL_RESAMPLE_H__ #define __ALGORITHM_LABEL_RESAMPLE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "SurfaceResamplingMethodEnum.h" namespace caret { class AlgorithmLabelResample : public AbstractAlgorithm { AlgorithmLabelResample(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmLabelResample(ProgressObject* myProgObj, const LabelFile* labelIn, const SurfaceFile* curSphere, const SurfaceFile* newSphere, const SurfaceResamplingMethodEnum::Enum& myMethod, LabelFile* labelOut, const MetricFile* curAreas = NULL, const MetricFile* newAreas = NULL, const MetricFile* currentRoi = NULL, MetricFile* validRoiOut = NULL, const bool& largest = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmLabelResample; } #endif //__ALGORITHM_LABEL_RESAMPLE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmLabelToBorder.cxx000066400000000000000000000150361360521144700256130ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmLabelToBorder.h" #include "AlgorithmException.h" #include "Border.h" #include "BorderFile.h" #include "BorderTracingHelper.h" #include "GiftiLabelTable.h" #include "LabelFile.h" #include "SurfaceFile.h" using namespace caret; using namespace std; AString AlgorithmLabelToBorder::getCommandSwitch() { return "-label-to-border"; } AString AlgorithmLabelToBorder::getShortDescription() { return "DRAW BORDERS AROUND LABELS"; } OperationParameters* AlgorithmLabelToBorder::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to use for neighbor information"); ret->addLabelParameter(2, "label-in", "the input label file"); ret->addBorderOutputParameter(3, "border-out", "the output border file"); OptionalParameter* placeOpt = ret->createOptionalParameter(4, "-placement", "set how far along the edge border points are drawn"); placeOpt->addDoubleParameter(1, "fraction", "fraction along edge from inside vertex (default 0.33)"); OptionalParameter* columnSelect = ret->createOptionalParameter(5, "-column", "select a single column"); columnSelect->addStringParameter(1, "column", "the column number or name"); ret->setHelpText( AString("For each label, finds all edges on the mesh that cross the boundary of the label, and draws borders through them. ") + "By default, this is done on all columns in the input file, using the map name as the class name for the border." ); return ret; } void AlgorithmLabelToBorder::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* mySurf = myParams->getSurface(1); LabelFile* myLabel = myParams->getLabel(2); BorderFile* myBorderOut = myParams->getOutputBorder(3); float placement = 0.33f; OptionalParameter* placeOpt = myParams->getOptionalParameter(4); if (placeOpt->m_present) { placement = (float)placeOpt->getDouble(1); } OptionalParameter* columnSelect = myParams->getOptionalParameter(5); int columnNum = -1; if (columnSelect->m_present) {//set up to use the single column columnNum = (int)myLabel->getMapIndexFromNameOrNumber(columnSelect->getString(1)); if (columnNum < 0) { throw AlgorithmException("invalid column specified"); } } AlgorithmLabelToBorder(myProgObj, mySurf, myLabel, myBorderOut, placement, columnNum); } AlgorithmLabelToBorder::AlgorithmLabelToBorder(ProgressObject* myProgObj, const SurfaceFile* mySurf, const LabelFile* myLabel, BorderFile* myBorderOut, const float& placement, const int& columnNum) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (mySurf->getNumberOfNodes() != myLabel->getNumberOfNodes()) throw AlgorithmException("label file does not match surface file number of vertices"); if (placement < 0.0f || placement > 1.0f || placement != placement) throw AlgorithmException("placement must be between 0 and 1"); if (columnNum < -1 || columnNum > myLabel->getNumberOfColumns()) throw AlgorithmException("invalid column specified"); myBorderOut->setStructure(mySurf->getStructure()); myBorderOut->setNumberOfNodes(mySurf->getNumberOfNodes()); BorderTracingHelper myHelper(mySurf); if (columnNum == -1) { for (int col = 0; col < myLabel->getNumberOfColumns(); ++col) { const GiftiLabelTable* myTable = myLabel->getLabelTable(); set myKeys = myTable->getKeys(); int32_t unassignedKey = myTable->getUnassignedLabelKey(); for (set::iterator iter = myKeys.begin(); iter != myKeys.end(); ++iter) { if (*iter == unassignedKey) continue; vector > result = myHelper.traceData(myLabel->getLabelKeyPointerForColumn(col), BorderTracingHelper::LabelSelect(*iter), placement); AString borderName = myTable->getLabelName(*iter); myBorderOut->getNameColorTable()->addLabel(myTable->getLabel(*iter)); for (int i = 0; i < (int)result.size(); ++i) { result[i]->setClassName(myLabel->getMapName(col)); result[i]->setName(borderName); myBorderOut->addBorder(result[i].releasePointer());//NOTE: addBorder takes ownership of a RAW POINTER, shared_ptr won't release the pointer } } } } else { const GiftiLabelTable* myTable = myLabel->getLabelTable(); set myKeys = myTable->getKeys(); int32_t unassignedKey = myTable->getUnassignedLabelKey(); for (set::iterator iter = myKeys.begin(); iter != myKeys.end(); ++iter) { if (*iter == unassignedKey) continue; vector > result = myHelper.traceData(myLabel->getLabelKeyPointerForColumn(columnNum), BorderTracingHelper::LabelSelect(*iter), placement); AString borderName = myTable->getLabelName(*iter); myBorderOut->getNameColorTable()->addLabel(myTable->getLabel(*iter)); for (int i = 0; i < (int)result.size(); ++i) { result[i]->setClassName(myLabel->getMapName(columnNum)); result[i]->setName(borderName); myBorderOut->addBorder(result[i].releasePointer());//ditto } } } } float AlgorithmLabelToBorder::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmLabelToBorder::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmLabelToBorder.h000066400000000000000000000034071360521144700252370ustar00rootroot00000000000000#ifndef __ALGORITHM_LABEL_TO_BORDER_H__ #define __ALGORITHM_LABEL_TO_BORDER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmLabelToBorder : public AbstractAlgorithm { AlgorithmLabelToBorder(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmLabelToBorder(ProgressObject* myProgObj, const SurfaceFile* mySurf, const LabelFile* myLabel, BorderFile* myBorderOut, const float& placement = 0.33f, const int& columnNum = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmLabelToBorder; } #endif //__ALGORITHM_LABEL_TO_BORDER_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmLabelToVolumeMapping.cxx000066400000000000000000000305361360521144700271630ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmLabelToVolumeMapping.h" #include "AlgorithmException.h" #include "CaretAssert.h" #include "CaretOMP.h" #include "CaretPointLocator.h" #include "LabelFile.h" #include "GiftiLabelTable.h" #include "RibbonMappingHelper.h" #include "SurfaceFile.h" #include "VolumeFile.h" using namespace caret; using namespace std; AString AlgorithmLabelToVolumeMapping::getCommandSwitch() { return "-label-to-volume-mapping"; } AString AlgorithmLabelToVolumeMapping::getShortDescription() { return "MAP LABEL FILE TO VOLUME"; } OperationParameters* AlgorithmLabelToVolumeMapping::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addLabelParameter(1, "label", "the input label file"); ret->addSurfaceParameter(2, "surface", "the surface to use coordinates from"); ret->addVolumeParameter(3, "volume-space", "a volume file in the desired output volume space"); ret->addVolumeOutputParameter(4, "volume-out", "the output volume file"); OptionalParameter* nearestVertOpt = ret->createOptionalParameter(5, "-nearest-vertex", "use the label from the vertex closest to the voxel center"); nearestVertOpt->addDoubleParameter(1, "distance", "how far from the surface to map labels to voxels, in mm"); OptionalParameter* ribbonOpt = ret->createOptionalParameter(6, "-ribbon-constrained", "use ribbon constrained mapping algorithm"); ribbonOpt->addSurfaceParameter(1, "inner-surf", "the inner surface of the ribbon"); ribbonOpt->addSurfaceParameter(2, "outer-surf", "the outer surface of the ribbon"); OptionalParameter* ribbonSubdivOpt = ribbonOpt->createOptionalParameter(3, "-voxel-subdiv", "voxel divisions while estimating voxel weights"); ribbonSubdivOpt->addIntegerParameter(1, "subdiv-num", "number of subdivisions, default 3"); ribbonOpt->createOptionalParameter(4, "-greedy", "also put labels in voxels with less than 50% partial volume (legacy behavior)"); ribbonOpt->createOptionalParameter(5, "-thick-columns", "use overlapping columns (legacy method)"); ret->setHelpText( AString("Maps labels from a gifti label file into a volume file. ") + "You must specify exactly one mapping method option. " + "The -nearest-vertex method uses the label from the vertex closest to the voxel center. " + "The -ribbon-constrained method uses the same method as in -volume-to-surface-mapping, then uses the weights in reverse, with popularity logic to decide on a label to use." ); return ret; } void AlgorithmLabelToVolumeMapping::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LabelFile* myLabel = myParams->getLabel(1); SurfaceFile* mySurf = myParams->getSurface(2); VolumeFile* myTemplateVol = myParams->getVolume(3); VolumeFile* myVolOut = myParams->getOutputVolume(4); enum Method { INVALID, NEAREST, RIBBON }; bool haveMethod = false; Method myMethod = INVALID; float nearDist = -1.0f; OptionalParameter* nearestVertOpt = myParams->getOptionalParameter(5); if (nearestVertOpt->m_present) { myMethod = NEAREST; haveMethod = true; nearDist = (float)nearestVertOpt->getDouble(1); if (nearDist < 0.0f) { throw AlgorithmException("invalid distance specified"); } } SurfaceFile* innerSurf = NULL, *outerSurf = NULL; int subDivs = 3; bool greedy = false, thick = false; OptionalParameter* ribbonOpt = myParams->getOptionalParameter(6); if (ribbonOpt->m_present) { if (haveMethod) { throw AlgorithmException("more than one mapping method specified"); } myMethod = RIBBON; haveMethod = true; innerSurf = ribbonOpt->getSurface(1); outerSurf = ribbonOpt->getSurface(2); OptionalParameter* ribbonSubdivOpt = ribbonOpt->getOptionalParameter(3); if (ribbonSubdivOpt->m_present) { subDivs = (int)ribbonSubdivOpt->getInteger(1); if (subDivs < 1) { throw AlgorithmException("invalid number of subdivisions specified"); } } greedy = ribbonOpt->getOptionalParameter(4)->m_present; thick = ribbonOpt->getOptionalParameter(5)->m_present; } if (!haveMethod) { throw AlgorithmException("no mapping method specified"); } switch (myMethod) { case NEAREST: AlgorithmLabelToVolumeMapping(myProgObj, myLabel, mySurf, myTemplateVol->getVolumeSpace(), myVolOut, nearDist); break; case RIBBON: AlgorithmLabelToVolumeMapping(myProgObj, myLabel, mySurf, myTemplateVol->getVolumeSpace(), myVolOut, innerSurf, outerSurf, subDivs, greedy, thick); break; case INVALID: CaretAssert(0); throw AlgorithmException("internal error, tell the developers what you just tried to do"); } } AlgorithmLabelToVolumeMapping::AlgorithmLabelToVolumeMapping(ProgressObject* myProgObj, const LabelFile* myLabel, const SurfaceFile* mySurf, const VolumeSpace& myVolSpace, VolumeFile* myVolOut, const float& nearDist) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (myLabel->getNumberOfNodes() != mySurf->getNumberOfNodes()) { throw AlgorithmException("input surface and label file have different number of vertices"); } if (nearDist < 0.0f) { throw AlgorithmException("invalid distance specified in surface to volume mapping"); } checkStructureMatch(myLabel, mySurf->getStructure(), "input label file", "the surface has"); int numCols = myLabel->getNumberOfColumns(); myVolOut->reinitialize(myVolSpace, numCols, 1, SubvolumeAttributes::LABEL); const int64_t* dims = myVolSpace.getDims(); const int64_t frameSize = dims[0] * dims[1] * dims[2]; vector voxelToVertex(frameSize); CaretPointer myLocator = mySurf->getPointLocator(); #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t k = 0; k < dims[2]; ++k) { for (int64_t j = 0; j < dims[1]; ++j) { for (int64_t i = 0; i < dims[0]; ++i) { float voxelCoord[3]; myVolSpace.indexToSpace(i, j, k, voxelCoord); voxelToVertex[myVolSpace.getIndex(i, j, k)] = myLocator->closestPointLimited(voxelCoord, nearDist); } } } vector scratchFrame(frameSize, 0.0f); for (int i = 0; i < numCols; ++i) { const int32_t* labelData = myLabel->getLabelKeyPointerForColumn(i); for (int64_t v = 0; v < frameSize; ++v) { if (voxelToVertex[v] >= 0) { scratchFrame[v] = labelData[voxelToVertex[v]]; } } myVolOut->setFrame(scratchFrame.data(), i); *(myVolOut->getMapLabelTable(i)) = *(myLabel->getLabelTable()); myVolOut->setMapName(i, myLabel->getMapName(i)); } } AlgorithmLabelToVolumeMapping::AlgorithmLabelToVolumeMapping(ProgressObject* myProgObj, const LabelFile* myLabel, const SurfaceFile* mySurf, const VolumeSpace& myVolSpace, VolumeFile* myVolOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const int& subDivs, const bool& greedy, const bool& thickColumn) : AbstractAlgorithm(myProgObj) { int numNodes = mySurf->getNumberOfNodes(); if (myLabel->getNumberOfNodes() != numNodes) { throw AlgorithmException("label file and input surfaces have different number of vertices"); } if (!mySurf->hasNodeCorrespondence(*outerSurf) || !mySurf->hasNodeCorrespondence(*innerSurf)) { throw AlgorithmException("all surfaces must have vertex correspondence"); } if (subDivs < 0.0f) { throw AlgorithmException("invalid number of subdivisions specified in surface to volume mapping"); } checkStructureMatch(myLabel, mySurf->getStructure(), "input label file", "the surface has"); checkStructureMatch(innerSurf, myLabel->getStructure(), "inner surface file", "the label file has"); checkStructureMatch(outerSurf, myLabel->getStructure(), "outer surface file", "the label file has"); int numCols = myLabel->getNumberOfColumns(); myVolOut->reinitialize(myVolSpace, numCols, 1, SubvolumeAttributes::LABEL); vector > forwardWeights; RibbonMappingHelper::computeWeightsRibbon(forwardWeights, myVolSpace, innerSurf, outerSurf, NULL, subDivs, !thickColumn); map > > reverseWeights; for (int i = 0; i < numNodes; ++i) { for (int v = 0; v < (int)forwardWeights[i].size(); ++v) {//vectors initialize to empty reverseWeights[VoxelIJK(forwardWeights[i][v].ijk)].push_back(pair(i, forwardWeights[i][v].weight)); } } const int64_t* dims = myVolSpace.getDims(); const int64_t frameSize = dims[0] * dims[1] * dims[2]; const int32_t unlabeledVal = myLabel->getLabelTable()->getUnassignedLabelKey(); vector scratchFrame(frameSize, unlabeledVal); for (int m = 0; m < numCols; ++m) { const int32_t* colData = myLabel->getLabelKeyPointerForColumn(m); for (map > >::const_iterator iter = reverseWeights.begin(); iter != reverseWeights.end(); ++iter) { double totalWeight = 0.0; map totals; const vector >& vertWeightsRef = iter->second; for (int i = 0; i < (int)vertWeightsRef.size(); ++i) { totalWeight += vertWeightsRef[i].second; map::iterator iter2 = totals.find(colData[vertWeightsRef[i].first]); if (iter2 == totals.end()) {//because floats don't initialize to 0 totals[colData[vertWeightsRef[i].first]] = vertWeightsRef[i].second; } else { iter2->second += vertWeightsRef[i].second; } } float bestWeight = -1.0f; int32_t bestLabel = unlabeledVal; bool skipLoop = false; if (!greedy) { if (thickColumn) { skipLoop = (totalWeight < 1.5);//slight hack: the thick column method basically counts every triangle three times } else { skipLoop = (totalWeight < 0.5); } } if (!skipLoop) { for (map::iterator iter2 = totals.begin(); iter2 != totals.end(); ++iter2) { if (iter2->second > bestWeight) { bestWeight = iter2->second; bestLabel = iter2->first; } } } scratchFrame[myVolSpace.getIndex(iter->first.m_ijk)] = bestLabel; } myVolOut->setFrame(scratchFrame.data(), m); *(myVolOut->getMapLabelTable(m)) = *(myLabel->getLabelTable()); myVolOut->setMapName(m, myLabel->getMapName(m)); } } float AlgorithmLabelToVolumeMapping::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmLabelToVolumeMapping::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmLabelToVolumeMapping.h000066400000000000000000000043401360521144700266020ustar00rootroot00000000000000#ifndef __ALGORITHM_LABEL_TO_VOLUME_MAPPING_H__ #define __ALGORITHM_LABEL_TO_VOLUME_MAPPING_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class VolumeSpace; class AlgorithmLabelToVolumeMapping : public AbstractAlgorithm { AlgorithmLabelToVolumeMapping(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmLabelToVolumeMapping(ProgressObject* myProgObj, const LabelFile* myLabel, const SurfaceFile* mySurf, const VolumeSpace& myVolSpace, VolumeFile* myVolOut, const float& nearDist); AlgorithmLabelToVolumeMapping(ProgressObject* myProgObj, const LabelFile* myLabel, const SurfaceFile* mySurf, const VolumeSpace& myVolSpace, VolumeFile* myVolOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const int& subDivs = 3, const bool& greedy = false, const bool& thick = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmLabelToVolumeMapping; } #endif //__ALGORITHM_LABEL_TO_VOLUME_MAPPING_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricDilate.cxx000066400000000000000000001060441360521144700255010ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmMetricDilate.h" #include "AlgorithmException.h" #include "CaretAssert.h" #include "CaretOMP.h" #include "FastStatistics.h" #include "GeodesicHelper.h" #include "MetricFile.h" #include "PaletteColorMapping.h" #include "SurfaceFile.h" #include "TopologyHelper.h" #include "Vector3D.h" #include #include using namespace caret; using namespace std; AString AlgorithmMetricDilate::getCommandSwitch() { return "-metric-dilate"; } AString AlgorithmMetricDilate::getShortDescription() { return "DILATE A METRIC FILE"; } OperationParameters* AlgorithmMetricDilate::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addMetricParameter(1, "metric", "the metric to dilate"); ret->addSurfaceParameter(2, "surface", "the surface to compute on"); ret->addDoubleParameter(3, "distance", "distance in mm to dilate"); ret->addMetricOutputParameter(4, "metric-out", "the output metric"); OptionalParameter* badRoiOpt = ret->createOptionalParameter(5, "-bad-vertex-roi", "specify an roi of vertices to overwrite, rather than vertices with value zero"); badRoiOpt->addMetricParameter(1, "roi-metric", "metric file, positive values denote vertices to have their values replaced"); OptionalParameter* dataRoiOpt = ret->createOptionalParameter(9, "-data-roi", "specify an roi of where there is data"); dataRoiOpt->addMetricParameter(1, "roi-metric", "metric file, positive values denote vertices that have data"); OptionalParameter* columnSelect = ret->createOptionalParameter(6, "-column", "select a single column to dilate"); columnSelect->addStringParameter(1, "column", "the column number or name"); ret->createOptionalParameter(7, "-nearest", "use the nearest good value instead of a weighted average"); ret->createOptionalParameter(10, "-linear", "fill in values with linear interpolation along strongest gradient"); OptionalParameter* exponentOpt = ret->createOptionalParameter(8, "-exponent", "use a different exponent in the weighting function"); exponentOpt->addDoubleParameter(1, "exponent", "exponent 'n' to use in (area / (distance ^ n)) as the weighting function (default 6)"); OptionalParameter* corrAreaOpt = ret->createOptionalParameter(11, "-corrected-areas", "vertex areas to use instead of computing them from the surface"); corrAreaOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); ret->createOptionalParameter(12, "-legacy-cutoff", "use the old method of choosing how many vertices to use when calulating the dilated value with weighted method"); ret->setHelpText( AString("For all metric vertices that are designated as bad, if they neighbor a non-bad vertex with data or are within the specified distance of such a vertex, ") + "replace the value with a distance-based weighted average of nearby non-bad vertices that have data, otherwise set the value to zero. " + "No matter how small is, dilation will always use at least the immediate neighbor vertices. " + "If -nearest is specified, it will use the value from the closest non-bad vertex with data within range instead of a weighted average.\n\n" + "If -bad-vertex-roi is specified, all vertices with a positive ROI value are bad. " + "If it is not specified, only vertices that have data, with a value of zero, are bad. " + "If -data-roi is not specified, all vertices are assumed to have data.\n\n" + "Note that the -corrected-areas option uses an approximate correction for the change in distances along a group average surface.\n\n" + "To get the behavior of version 1.3.2 or earlier, use '-legacy-cutoff -exponent 2'." ); return ret; } void AlgorithmMetricDilate::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { MetricFile* myMetric = myParams->getMetric(1); SurfaceFile* mySurf = myParams->getSurface(2); float distance = (float)myParams->getDouble(3); MetricFile* myMetricOut = myParams->getOutputMetric(4); OptionalParameter* badRoiOpt = myParams->getOptionalParameter(5); MetricFile* badNodeRoi = NULL; if (badRoiOpt->m_present) { badNodeRoi = badRoiOpt->getMetric(1); } OptionalParameter* dataRoiOpt = myParams->getOptionalParameter(9); MetricFile* dataRoi = NULL; if (dataRoiOpt->m_present) { dataRoi = dataRoiOpt->getMetric(1); } OptionalParameter* columnSelect = myParams->getOptionalParameter(6); int columnNum = -1; if (columnSelect->m_present) {//set up to use the single column columnNum = (int)myMetric->getMapIndexFromNameOrNumber(columnSelect->getString(1)); if (columnNum < 0) { throw AlgorithmException("invalid column specified"); } } Method myMethod = WEIGHTED; bool methodSpecified = false; if (myParams->getOptionalParameter(7)->m_present) { methodSpecified = true; myMethod = NEAREST; } if (myParams->getOptionalParameter(10)->m_present) { if (methodSpecified) throw AlgorithmException("-nearest and -linear may not be specified together"); methodSpecified = true; myMethod = LINEAR; } float exponent = 6.0f; OptionalParameter* exponentOpt = myParams->getOptionalParameter(8); if (exponentOpt->m_present) { exponent = (float)exponentOpt->getDouble(1); } OptionalParameter* corrAreaOpt = myParams->getOptionalParameter(11); MetricFile* corrAreas = NULL; if (corrAreaOpt->m_present) { corrAreas = corrAreaOpt->getMetric(1); } bool legacyCutoff = myParams->getOptionalParameter(12)->m_present; AlgorithmMetricDilate(myProgObj, myMetric, mySurf, distance, myMetricOut, badNodeRoi, dataRoi, columnNum, myMethod, exponent, corrAreas, legacyCutoff); } AlgorithmMetricDilate::AlgorithmMetricDilate(ProgressObject* myProgObj, const MetricFile* myMetric, const SurfaceFile* mySurf, const float& distance, MetricFile* myMetricOut, const MetricFile* badNodeRoi, const MetricFile* dataRoi, const int& columnNum, const Method& myMethod, const float& exponent, const MetricFile* corrAreas, const bool legacyCutoff) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int numNodes = mySurf->getNumberOfNodes(); if (numNodes != myMetric->getNumberOfNodes()) { throw AlgorithmException("surface and metric number of vertices do not match"); } if (badNodeRoi != NULL && badNodeRoi->getNumberOfNodes() != numNodes) { throw AlgorithmException("bad vertex roi number of vertices does not match"); } if (dataRoi != NULL && dataRoi->getNumberOfNodes() != numNodes) { throw AlgorithmException("data roi number of vertices does not match"); } if (corrAreas != NULL && corrAreas->getNumberOfNodes() != numNodes) { throw AlgorithmException("corrected areas metric number of vertices does not match"); } if (columnNum < -1 || columnNum >= myMetric->getNumberOfColumns()) { throw AlgorithmException("invalid column specified"); } if (distance < 0.0f) { throw AlgorithmException("distance cannot be negative"); } myMetricOut->setStructure(mySurf->getStructure()); vector > myStencils;//because we need to iterate over it in parallel vector > myNearest; vector colScratch(numNodes); vector myAreasData; const float* myAreas = NULL; if (corrAreas == NULL) { mySurf->computeNodeAreas(myAreasData); myAreas = myAreasData.data(); } else { myAreas = corrAreas->getValuePointerForColumn(0); } bool linear = (myMethod == LINEAR), nearest = (myMethod == NEAREST); FastStatistics spacingStats; if (!linear && badNodeRoi != NULL)//if we know which nodes need to have their values replaced, then we can do the same thing at each vertex for each column { if (nearest) { precomputeNearest(myNearest, mySurf, badNodeRoi, dataRoi, corrAreas, distance); } else { precomputeStencils(myStencils, mySurf, myAreas, badNodeRoi, dataRoi, corrAreas, distance, exponent, legacyCutoff); } } else { mySurf->getNodesSpacingStatistics(spacingStats);//use mean spacing to help set minimum stencil distance, since native surfaces might have a minimum of 0 } if (columnNum == -1) { myMetricOut->setNumberOfNodesAndColumns(numNodes, myMetric->getNumberOfColumns()); for (int thisCol = 0; thisCol < myMetric->getNumberOfColumns(); ++thisCol) { *(myMetricOut->getMapPaletteColorMapping(thisCol)) = *(myMetric->getMapPaletteColorMapping(thisCol)); const float* myInputData = myMetric->getValuePointerForColumn(thisCol); myMetricOut->setColumnName(thisCol, myMetric->getColumnName(thisCol)); if (badNodeRoi == NULL) { processColumn(colScratch.data(), myInputData, mySurf, myAreas, badNodeRoi, dataRoi, corrAreas, distance, nearest, linear, exponent, legacyCutoff, spacingStats.getMean()); } else { switch (myMethod) { case NEAREST: processColumn(colScratch.data(), numNodes, myInputData, myNearest); break; case WEIGHTED: processColumn(colScratch.data(), numNodes, myInputData, myStencils); break; case LINEAR: processColumn(colScratch.data(), myInputData, mySurf, myAreas, badNodeRoi, dataRoi, corrAreas, distance, nearest, linear, exponent, legacyCutoff, spacingStats.getMean()); break; } } myMetricOut->setValuesForColumn(thisCol, colScratch.data()); } } else { myMetricOut->setNumberOfNodesAndColumns(numNodes, 1); *(myMetricOut->getMapPaletteColorMapping(0)) = *(myMetric->getMapPaletteColorMapping(columnNum)); const float* myInputData = myMetric->getValuePointerForColumn(columnNum); myMetricOut->setColumnName(0, myMetric->getColumnName(columnNum)); if (badNodeRoi == NULL) { processColumn(colScratch.data(), myInputData, mySurf, myAreas, badNodeRoi, dataRoi, corrAreas, distance, nearest, linear, exponent, legacyCutoff, spacingStats.getMean()); } else { switch (myMethod) { case NEAREST: processColumn(colScratch.data(), numNodes, myInputData, myNearest); break; case WEIGHTED: processColumn(colScratch.data(), numNodes, myInputData, myStencils); break; case LINEAR: processColumn(colScratch.data(), myInputData, mySurf, myAreas, badNodeRoi, dataRoi, corrAreas, distance, nearest, linear, exponent, legacyCutoff, spacingStats.getMean()); break; } } myMetricOut->setValuesForColumn(0, colScratch.data()); } } void AlgorithmMetricDilate::processColumn(float* colScratch, const int& numNodes, const float* myInputData, vector > myNearest) { for (int i = 0; i < numNodes; ++i) { colScratch[i] = myInputData[i];//precopy so that the parallel part doesn't have to worry about vertices that don't get dilated to } int numStencils = (int)myNearest.size(); #pragma omp CARET_PARFOR schedule(dynamic) for (int i = 0; i < numStencils; ++i)//parallel may not matter here, but we do other stuff parallel, so... { const int& node = myNearest[i].first; const int& nearest = myNearest[i].second; if (nearest != -1) { colScratch[node] = myInputData[nearest]; } else { colScratch[node] = 0.0f; } } } void AlgorithmMetricDilate::processColumn(float* colScratch, const int& numNodes, const float* myInputData, vector > myStencils) { for (int i = 0; i < numNodes; ++i) { colScratch[i] = myInputData[i];//precopy so that the parallel part doesn't have to worry about vertices that don't get dilated to } int numStencils = (int)myStencils.size(); #pragma omp CARET_PARFOR schedule(dynamic) for (int i = 0; i < numStencils; ++i)//ditto { const int& node = myStencils[i].first; const StencilElem& stencil = myStencils[i].second; int numWeights = (int)stencil.m_weightlist.size(); if (numWeights > 0) { double accum = 0.0; for (int j = 0; j < numWeights; ++j) { accum += myInputData[stencil.m_weightlist[j].first] * stencil.m_weightlist[j].second; } colScratch[node] = accum / stencil.m_weightsum; } else { colScratch[node] = 0.0f; } } } void AlgorithmMetricDilate::processColumn(float* colScratch, const float* myInputData, const SurfaceFile* mySurf, const float* myAreas, const MetricFile* badNodeRoi, const MetricFile* dataRoi, const MetricFile* corrAreas, const float& distance, const bool& nearest, const bool& linear, const float& exponent, const bool legacyCutoff, const float meanSpacing) { float cutoffBase = max(2.0f * distance, 2.0f * meanSpacing), cutoffRatio = max(1.1f, pow(49.0f, 1.0f / (exponent - 2.0f)));//find what ratio from closest vertex corresponds to having 98% of total weight accounted for on a plane, assuming non-adverse ROI float minKernel = 1.5f * meanSpacing;//small kernels are cheap for weighted, use similar minimum distance as volume dilate float legacyCutoffRatio = 1.5f, test = pow(10.0f, 1.0f / exponent);//old logic: find what cutoff ratio corresponds to a tenth of weight, but don't use more than a 1.5 * nearest cutoff if (test > 1.0f && test < legacyCutoffRatio)//if it is less than 1, the exponent is weird, so simply ignore it and use default {//this generally cut off early, causing the result to behave like a higher exponent was used if (test > 1.1f) { legacyCutoffRatio = test; } else { legacyCutoffRatio = 1.1f; } } int numNodes = mySurf->getNumberOfNodes(); vector charRoi(numNodes, 0); const float* badRoiData = NULL; if (badNodeRoi != NULL) badRoiData = badNodeRoi->getValuePointerForColumn(0); const float* dataRoiVals = NULL; if (dataRoi != NULL) { dataRoiVals = dataRoi->getValuePointerForColumn(0); } for (int i = 0; i < numNodes; ++i) { if (badRoiData == NULL) { if ((dataRoiVals == NULL || dataRoiVals[i] > 0.0f) && myInputData[i] != 0.0f) { charRoi[i] = 1; } } else { if ((dataRoiVals == NULL || dataRoiVals[i] > 0.0f) && !(badRoiData[i] > 0.0f))//"not greater than" to trap NaNs { charRoi[i] = 1; } } } CaretPointer correctedBase; if (corrAreas != NULL) { correctedBase.grabNew(new GeodesicHelperBase(mySurf, corrAreas->getValuePointerForColumn(0)));//NOTE: myAreas also points to this when applicable } #pragma omp CARET_PAR { CaretPointer myTopoHelp = mySurf->getTopologyHelper(); CaretPointer myGeoHelp; if (corrAreas == NULL) { myGeoHelp = mySurf->getGeodesicHelper(); } else { myGeoHelp.grabNew(new GeodesicHelper(correctedBase)); } #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < numNodes; ++i) { bool badNode; if (badRoiData != NULL) { badNode = (badRoiData[i] > 0.0f); } else { badNode = (myInputData[i] == 0.0f); } if (badNode) { float closestDist;//NOTE: the only time this function is called with a badRoi is when using linear, which doesn't use the closest distance int closestNode = myGeoHelp->getClosestNodeInRoi(i, charRoi.data(), distance, closestDist); if (closestNode == -1)//check neighbors, to ensure we dilate by at least one node everywhere { const vector& nodeList = myTopoHelp->getNodeNeighbors(i); vector distList; myGeoHelp->getGeoToTheseNodes(i, nodeList, distList);//ok, its a little silly to do this const int numInRange = (int)nodeList.size(); for (int j = 0; j < numInRange; ++j) { if (charRoi[nodeList[j]] != 0 && (closestNode == -1 || distList[j] < closestDist)) { closestNode = nodeList[j]; closestDist = distList[j]; } } } if (closestNode == -1) { colScratch[i] = 0.0f; } else { if (nearest) { colScratch[i] = myInputData[closestNode]; } else { vector nodeList; vector distList; if (linear) { myGeoHelp->getNodesToGeoDist(i, distance, nodeList, distList); int numInRange = (int)nodeList.size(); Vector3D center = mySurf->getCoordinate(i); vector blockDists; vector blockPath; vector usableNodes; vector usableDists; for (int j = 0; j < numInRange; ++j)//prescan what is usable, and also exclude things that are through a valid node { if (badRoiData != NULL) { badNode = (badRoiData[nodeList[j]] > 0.0f); } else { badNode = (myInputData[nodeList[j]] == 0.0f); } if ((dataRoiVals == NULL || dataRoiVals[nodeList[j]] > 0.0f) && !badNode) { myGeoHelp->getPathAlongLineSegment(i, nodeList[j], center, mySurf->getCoordinate(nodeList[j]), blockPath, blockDists); CaretAssert(blockPath.size() > 0 && blockPath[0] == i);//we already know that i is "bad", skip it bool usable = true; for (int k = 1; k < (int)blockPath.size() - 1; ++k)//and don't test the endpoint { if (dataRoiVals == NULL || dataRoiVals[blockPath[k]] > 0.0f) { if (badRoiData != NULL) { if (!(badRoiData[blockPath[k]] > 0.0f))//"not greater than" to trap NaNs { usable = false; break; } } else { if (myInputData[blockPath[k]] != 0.0f) { usable = false; break; } } } } if (usable) { usableNodes.push_back(nodeList[j]); usableDists.push_back(distList[j]); } } } int numUsable = (int)usableNodes.size(); float bestGradient = -1.0f; int bestj = -1, bestk = -1; for (int j = 0; j < numUsable; ++j) { int node1 = usableNodes[j]; for (int k = j + 1; k < numUsable; ++k) { int node2 = usableNodes[k]; float grad = abs(myInputData[node1] - myInputData[node2]) / (usableDists[j] + usableDists[k]); if (grad > bestGradient) { bestGradient = grad; bestj = j; bestk = k; } } } if (bestj == -1) { colScratch[i] = myInputData[closestNode]; } else { int node1 = usableNodes[bestj], node2 = usableNodes[bestk]; colScratch[i] = myInputData[node1] + (myInputData[node2] - myInputData[node1]) * usableDists[bestj] / (usableDists[bestj] + usableDists[bestk]); } } else { float cutoffDist = cutoffBase; if (legacyCutoff) { cutoffDist = closestDist * legacyCutoffRatio; } else { if (exponent > 2.0f && cutoffRatio < 100.0f && cutoffRatio > 1.0f)//if the ratio is sane, use it, but never exceed cutoffBase { cutoffDist = max(min(cutoffRatio * closestDist, cutoffDist), minKernel);//but small kernels are rather cheap anyway, so have a minimum size just in case } } myGeoHelp->getNodesToGeoDist(i, cutoffDist, nodeList, distList); int numInRange = (int)nodeList.size(); float totalWeight = 0.0f, weightedSum = 0.0f; for (int j = 0; j < numInRange; ++j) { if (charRoi[nodeList[j]] != 0) { float weight; const float tolerance = 0.9f;//distances should NEVER be less than closestDist, for obvious reasons float divdist = distList[j] / closestDist; if (divdist > tolerance)//tricky: if closestDist is zero, this filters between NaN and inf, resulting in a straight average between nodes with 0 distance { weight = myAreas[nodeList[j]] / pow(divdist, exponent);//NOTE: myAreas has already been pointed to the right data with -corrected-areas } else { weight = myAreas[nodeList[j]] / pow(tolerance, exponent); } totalWeight += weight; weightedSum += myInputData[nodeList[j]] * weight; } } if (totalWeight != 0.0f) { colScratch[i] = weightedSum / totalWeight; } else { colScratch[i] = 0.0f; } } } } } else { colScratch[i] = myInputData[i]; } } } } void AlgorithmMetricDilate::precomputeStencils(vector >& myStencils, const SurfaceFile* mySurf, const float* myAreas, const MetricFile* badNodeRoi, const MetricFile* dataRoi, const MetricFile* corrAreas, const float& distance, const float& exponent, const bool legacyCutoff) { CaretAssert(badNodeRoi != NULL);//because it should never be called if we don't know exactly what nodes we are replacing const float* badNodeData = badNodeRoi->getValuePointerForColumn(0); FastStatistics spacingStats; mySurf->getNodesSpacingStatistics(spacingStats);//use mean spacing to help set minimum stencil distance, since native surfaces might have a minimum of 0 float cutoffBase = max(2.0f * distance, 2.0f * spacingStats.getMean()), cutoffRatio = max(1.1f, pow(49.0f, 1.0f / (exponent - 2.0f)));//find what ratio from closest vertex corresponds to having 98% of total weight accounted for on a plane, assuming non-adverse ROI float minKernel = 1.5f * spacingStats.getMean();//small kernels are cheap for weighted, use similar minimum distance as volume dilate float legacyCutoffRatio = 1.5f, test = pow(10.0f, 1.0f / exponent);//old logic: find what cutoff ratio corresponds to a tenth of weight, but don't use more than a 1.5 * nearest cutoff if (test > 1.0f && test < legacyCutoffRatio)//if it is less than 1, the exponent is weird, so simply ignore it and use default {//this generally cut off early, causing the result to behave like a higher exponent was used if (test > 1.1f) { legacyCutoffRatio = test; } else { legacyCutoffRatio = 1.1f; } } int numNodes = mySurf->getNumberOfNodes(); vector charRoi(numNodes, 0); const float* dataRoiVals = NULL; int badCount = 0; if (dataRoi != NULL) { dataRoiVals = dataRoi->getValuePointerForColumn(0); } for (int i = 0; i < numNodes; ++i) { if (badNodeData[i] > 0.0f) { ++badCount; } else { if (dataRoiVals == NULL || dataRoiVals[i] > 0.0f) { charRoi[i] = 1; } } } myStencils.resize(badCount);//initializes all stencils to have empty lists badCount = 0; CaretPointer correctedBase; if (corrAreas != NULL) { correctedBase.grabNew(new GeodesicHelperBase(mySurf, corrAreas->getValuePointerForColumn(0)));//NOTE: myAreas also points to this when applicable } #pragma omp CARET_PAR { CaretPointer myTopoHelp = mySurf->getTopologyHelper(); CaretPointer myGeoHelp; if (corrAreas == NULL) { myGeoHelp = mySurf->getGeodesicHelper(); } else { myGeoHelp.grabNew(new GeodesicHelper(correctedBase)); } #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < numNodes; ++i) { if (badNodeData[i] > 0.0f) { int myIndex; #pragma omp critical { myIndex = badCount; ++badCount; } myStencils[myIndex].first = i; StencilElem& myElem = myStencils[myIndex].second; float closestDist; int closestNode = myGeoHelp->getClosestNodeInRoi(i, charRoi.data(), distance, closestDist); if (closestNode == -1)//check neighbors, to ensure we dilate by at least one node everywhere { const vector& nodeList = myTopoHelp->getNodeNeighbors(i); vector distList; myGeoHelp->getGeoToTheseNodes(i, nodeList, distList);//ok, its a little silly to do this const int numInRange = (int)nodeList.size(); for (int j = 0; j < numInRange; ++j) { if (charRoi[nodeList[j]] != 0 && (closestNode == -1 || distList[j] < closestDist)) { closestNode = nodeList[j]; closestDist = distList[j]; } } } if (closestNode != -1) { vector nodeList; vector distList; float cutoffDist = cutoffBase; if (legacyCutoff) { cutoffDist = closestDist * legacyCutoffRatio; } else { if (exponent > 2.0f && cutoffRatio < 100.0f && cutoffRatio > 1.0f)//if the ratio is sane, use it, but never exceed cutoffBase { cutoffDist = max(min(cutoffRatio * closestDist, cutoffDist), minKernel);//but small kernels are rather cheap anyway, so have a minimum size just in case } } myGeoHelp->getNodesToGeoDist(i, cutoffDist, nodeList, distList); int numInRange = (int)nodeList.size(); myElem.m_weightsum = 0.0f; for (int j = 0; j < numInRange; ++j) { if (charRoi[nodeList[j]] != 0) { float weight; const float tolerance = 0.9f;//distances should NEVER be less than closestDist, for obvious reasons float divdist = distList[j] / closestDist; if (divdist > tolerance)//tricky: if closestDist is zero, this filters between NaN and inf, resulting in a straight average between nodes with 0 distance { weight = myAreas[nodeList[j]] / pow(divdist, exponent);//NOTE: myAreas has already been pointed to the right data with -corrected-areas } else { weight = myAreas[nodeList[j]] / pow(tolerance, exponent); } myElem.m_weightsum += weight; myElem.m_weightlist.push_back(pair(nodeList[j], weight)); } } if (myElem.m_weightsum == 0.0f)//set list to empty instead of making NaNs { myElem.m_weightlist.clear(); } } } } } } void AlgorithmMetricDilate::precomputeNearest(vector >& myNearest, const SurfaceFile* mySurf, const MetricFile* badNodeRoi, const MetricFile* dataRoi, const MetricFile* corrAreas, const float& distance) { CaretAssert(badNodeRoi != NULL);//because it should never be called if we don't know exactly what nodes we are replacing const float* badNodeData = badNodeRoi->getValuePointerForColumn(0); int numNodes = mySurf->getNumberOfNodes(); vector charRoi(numNodes, 0); const float* dataRoiVals = NULL; int badCount = 0; if (dataRoi != NULL) { dataRoiVals = dataRoi->getValuePointerForColumn(0); } for (int i = 0; i < numNodes; ++i) { if (badNodeData[i] > 0.0f) { ++badCount; } else { if (dataRoiVals == NULL || dataRoiVals[i] > 0.0f) { charRoi[i] = 1; } } } myNearest.resize(badCount); badCount = 0; CaretPointer correctedBase; if (corrAreas != NULL) { correctedBase.grabNew(new GeodesicHelperBase(mySurf, corrAreas->getValuePointerForColumn(0)));//NOTE: myAreas also points to this when applicable } #pragma omp CARET_PAR { CaretPointer myTopoHelp = mySurf->getTopologyHelper(); CaretPointer myGeoHelp; if (corrAreas == NULL) { myGeoHelp = mySurf->getGeodesicHelper(); } else { myGeoHelp.grabNew(new GeodesicHelper(correctedBase)); } #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < numNodes; ++i) { if (badNodeData[i] > 0.0f) { int myIndex; #pragma omp critical { myIndex = badCount; ++badCount; } myNearest[myIndex].first = i; float closestDist; int closestNode = myGeoHelp->getClosestNodeInRoi(i, charRoi.data(), distance, closestDist); if (closestNode == -1)//check neighbors, to ensure we dilate by at least one node everywhere { const vector& nodeList = myTopoHelp->getNodeNeighbors(i); vector distList; myGeoHelp->getGeoToTheseNodes(i, nodeList, distList);//ok, its a little silly to do this const int numInRange = (int)nodeList.size(); for (int j = 0; j < numInRange; ++j) { if (charRoi[nodeList[j]] != 0 && (closestNode == -1 || distList[j] < closestDist)) { closestNode = nodeList[j]; closestDist = distList[j]; } } } myNearest[myIndex].second = closestNode; } } } } float AlgorithmMetricDilate::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmMetricDilate::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricDilate.h000066400000000000000000000067341360521144700251330ustar00rootroot00000000000000#ifndef __ALGORITHM_METRIC_DILATE_H__ #define __ALGORITHM_METRIC_DILATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmMetricDilate : public AbstractAlgorithm { struct StencilElem { std::vector > m_weightlist; float m_weightsum; }; AlgorithmMetricDilate(); void precomputeStencils(std::vector >& myStencils, const SurfaceFile* mySurf, const float* myAreas, const MetricFile* badNodeRoi, const MetricFile* dataRoi, const MetricFile* corrAreas, const float& distance, const float& exponent, const bool legacyCutoff); void precomputeNearest(std::vector >& myNearest, const SurfaceFile* mySurf, const MetricFile* badNodeRoi, const MetricFile* dataRoi, const MetricFile* corrAreas, const float& distance); void processColumn(float* colScratch, const int& numNodes, const float* myInputData, std::vector > myNearest); void processColumn(float* colScratch, const int& numNodes, const float* myInputData, std::vector > myStencils); void processColumn(float* colScratch, const float* myInputData, const SurfaceFile* mySurf, const float* myAreas, const MetricFile* badNodeRoi, const MetricFile* dataRoi, const MetricFile* corrAreas, const float& distance, const bool& nearest, const bool& linear, const float& exponent, const bool legacyCutoff, const float meanSpacing); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: enum Method { NEAREST, WEIGHTED, LINEAR }; AlgorithmMetricDilate(ProgressObject* myProgObj, const MetricFile* myMetric, const SurfaceFile* mySurf, const float& distance, MetricFile* myMetricOut, const MetricFile* badNodeRoi = NULL, const MetricFile* dataRoi = NULL, const int& columnNum = -1, const Method& myMethod = WEIGHTED, const float& exponent = 6.0f, const MetricFile* corrAreas = NULL, const bool legacyCutoff = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmMetricDilate; } #endif //__ALGORITHM_METRIC_DILATE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricErode.cxx000066400000000000000000000225611360521144700253360ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmMetricErode.h" #include "AlgorithmException.h" #include "CaretOMP.h" #include "GeodesicHelper.h" #include "MetricFile.h" #include "PaletteColorMapping.h" #include "SurfaceFile.h" #include "TopologyHelper.h" #include #include using namespace caret; using namespace std; AString AlgorithmMetricErode::getCommandSwitch() { return "-metric-erode"; } AString AlgorithmMetricErode::getShortDescription() { return "ERODE A METRIC FILE"; } OperationParameters* AlgorithmMetricErode::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addMetricParameter(1, "metric", "the metric file to erode"); ret->addSurfaceParameter(2, "surface", "the surface to compute on"); ret->addDoubleParameter(3, "distance", "distance in mm to erode"); ret->addMetricOutputParameter(4, "metric-out", "the output metric"); OptionalParameter* dataRoiOpt = ret->createOptionalParameter(5, "-roi", "assume values outside this roi are nonzero"); dataRoiOpt->addMetricParameter(1, "roi-metric", "metric file, positive values denote vertices that have data"); OptionalParameter* columnSelect = ret->createOptionalParameter(6, "-column", "select a single column to erode"); columnSelect->addStringParameter(1, "column", "the column number or name"); OptionalParameter* corrAreaOpt = ret->createOptionalParameter(7, "-corrected-areas", "vertex areas to use instead of computing them from the surface"); corrAreaOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); ret->setHelpText( AString("Around each vertex with a value of zero, set surrounding vertices to zero. ") + "The surrounding vertices are all immediate neighbors and all vertices within the specified distance." + "\n\nNote that the -corrected-areas option uses an approximate correction for distance along the surface." ); return ret; } void AlgorithmMetricErode::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { MetricFile* myMetric = myParams->getMetric(1); SurfaceFile* mySurf = myParams->getSurface(2); float distance = (float)myParams->getDouble(3); MetricFile* myMetricOut = myParams->getOutputMetric(4); OptionalParameter* roiOpt = myParams->getOptionalParameter(5); MetricFile* myRoi = NULL; if (roiOpt->m_present) { myRoi = roiOpt->getMetric(1); } OptionalParameter* columnOpt = myParams->getOptionalParameter(6); int columnNum = -1; if (columnOpt->m_present) { columnNum = (int)myMetric->getMapIndexFromNameOrNumber(columnOpt->getString(1)); if (columnNum < 0) { throw AlgorithmException("invalid column specified"); } } OptionalParameter* corrAreasOpt = myParams->getOptionalParameter(7); MetricFile* corrAreas = NULL; if (corrAreasOpt->m_present) { corrAreas = corrAreasOpt->getMetric(1); } AlgorithmMetricErode(myProgObj, myMetric, mySurf, distance, myMetricOut, myRoi, columnNum, corrAreas); } namespace { vector > precomputeStencils(const SurfaceFile* mySurf, const float& distance, const MetricFile* corrAreas, const float* roiCol) { int numNodes = mySurf->getNumberOfNodes(); vector > ret(numNodes); CaretPointer myGeoBase; if (corrAreas != NULL) { myGeoBase.grabNew(new GeodesicHelperBase(mySurf, corrAreas->getValuePointerForColumn(0))); } CaretPointer myTopoHelp = mySurf->getTopologyHelper();//we aren't using to depth, so share the topology helper #pragma omp CARET_PAR {//use parallel here so each thread gets its own geodesic helper CaretPointer myGeoHelp; if (corrAreas == NULL) { myGeoHelp = mySurf->getGeodesicHelper(); } else { myGeoHelp.grabNew(new GeodesicHelper(myGeoBase)); } #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < numNodes; ++i) { if (roiCol == NULL || roiCol[i] > 0.0f) { vector geoNodes; vector geoDists; myGeoHelp->getNodesToGeoDist(i, distance, geoNodes, geoDists); const vector& topoNodes = myTopoHelp->getNodeNeighbors(i); set mergeSet(geoNodes.begin(), geoNodes.end()); mergeSet.insert(topoNodes.begin(), topoNodes.end()); mergeSet.erase(i);//center of stencil is already 0 if stencil is used, so don't set it again ret[i] = vector(mergeSet.begin(), mergeSet.end()); } } } return ret; } } AlgorithmMetricErode::AlgorithmMetricErode(ProgressObject* myProgObj, const MetricFile* myMetric, const SurfaceFile* mySurf, const float& distance, MetricFile* myMetricOut, const MetricFile* myRoi, const int& columnNum, const MetricFile* corrAreas) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int numNodes = mySurf->getNumberOfNodes(); if (numNodes != myMetric->getNumberOfNodes()) { throw AlgorithmException("surface and metric number of vertices do not match"); } if (myRoi != NULL && myRoi->getNumberOfNodes() != numNodes) { throw AlgorithmException("roi number of vertices does not match"); } if (corrAreas != NULL && corrAreas->getNumberOfNodes() != numNodes) { throw AlgorithmException("corrected areas metric number of vertices does not match"); } int numInColumns = myMetric->getNumberOfColumns(); if (columnNum < -1 || columnNum >= numInColumns) { throw AlgorithmException("invalid column specified"); } if (distance < 0.0f) { throw AlgorithmException("distance cannot be negative"); } if (columnNum == -1) { myMetricOut->setNumberOfNodesAndColumns(numNodes, numInColumns); } else { myMetricOut->setNumberOfNodesAndColumns(numNodes, 1); } myMetricOut->setStructure(mySurf->getStructure()); const float* roiCol = NULL; if (myRoi != NULL) { roiCol = myRoi->getValuePointerForColumn(0); } vector > stencils = precomputeStencils(mySurf, distance, corrAreas, roiCol); if (columnNum == -1) { for (int c = 0; c < numInColumns; ++c) { const float* inData = myMetric->getValuePointerForColumn(c); vector scratchCol(inData, inData + numNodes); for (int i = 0; i < numNodes; ++i) { if (roiCol == NULL || roiCol[i] > 0.0f) { if (inData[i] == 0.0f) { for (int n = 0; n < (int)stencils[i].size(); ++n) { scratchCol[stencils[i][n]] = 0.0f; } } } else { scratchCol[i] = 0.0f;//zero things outside the data roi } } *(myMetricOut->getPaletteColorMapping(c)) = *(myMetric->getPaletteColorMapping(c)); myMetricOut->setMapName(c, myMetric->getMapName(c)); myMetricOut->setValuesForColumn(c, scratchCol.data()); } } else { const float* inData = myMetric->getValuePointerForColumn(columnNum); vector scratchCol(inData, inData + numNodes); for (int i = 0; i < numNodes; ++i) { if (roiCol == NULL || roiCol[i] > 0.0f) { if (inData[i] == 0.0f) { for (int n = 0; n < (int)stencils[i].size(); ++n) { scratchCol[stencils[i][n]] = 0.0f; } } } else { scratchCol[i] = 0.0f;//zero things outside the data roi } } *(myMetricOut->getPaletteColorMapping(0)) = *(myMetric->getPaletteColorMapping(columnNum)); myMetricOut->setMapName(0, myMetric->getMapName(columnNum)); myMetricOut->setValuesForColumn(0, scratchCol.data()); } } float AlgorithmMetricErode::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmMetricErode::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricErode.h000066400000000000000000000034571360521144700247660ustar00rootroot00000000000000#ifndef __ALGORITHM_METRIC_ERODE_H__ #define __ALGORITHM_METRIC_ERODE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmMetricErode : public AbstractAlgorithm { AlgorithmMetricErode(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmMetricErode(ProgressObject* myProgObj, const MetricFile* myMetric, const SurfaceFile* mySurf, const float& distance, MetricFile* myMetricOut, const MetricFile* myRoi = NULL, const int& columnNum = -1, const MetricFile* corrAreas = NULL); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmMetricErode; } #endif //__ALGORITHM_METRIC_ERODE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricEstimateFWHM.cxx000066400000000000000000000261141360521144700265330ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmMetricEstimateFWHM.h" #include "AlgorithmException.h" #include "DescriptiveStatistics.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "TopologyHelper.h" #include using namespace caret; using namespace std; AString AlgorithmMetricEstimateFWHM::getCommandSwitch() { return "-metric-estimate-fwhm"; } AString AlgorithmMetricEstimateFWHM::getShortDescription() { return "ESTIMATE FWHM SMOOTHNESS OF A METRIC FILE"; } OperationParameters* AlgorithmMetricEstimateFWHM::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to use for distance and neighbor information"); ret->addMetricParameter(2, "metric-in", "the input metric"); OptionalParameter* roiOpt = ret->createOptionalParameter(3, "-roi", "use only data within an ROI"); roiOpt->addMetricParameter(1, "roi-metric", "the metric file to use as an ROI"); OptionalParameter* columnSelect = ret->createOptionalParameter(4, "-column", "select a single column to estimate smoothness of"); columnSelect->addStringParameter(1, "column", "the column number or name"); OptionalParameter* allColumnsOpt = ret->createOptionalParameter(5, "-whole-file", "estimate for the whole file at once, not each column separately"); allColumnsOpt->createOptionalParameter(1, "-demean", "subtract the mean image before estimating smoothness"); ret->setHelpText( AString("Estimates the smoothness of the metric columns, printing the estimates to standard output. ") + "These estimates ignore variation in vertex spacing." ); return ret; } void AlgorithmMetricEstimateFWHM::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); SurfaceFile* mySurf = myParams->getSurface(1); MetricFile* myMetric = myParams->getMetric(2); OptionalParameter* roiOpt = myParams->getOptionalParameter(3); MetricFile* roi = NULL; if (roiOpt->m_present) { roi = roiOpt->getMetric(1); } OptionalParameter* columnSelect = myParams->getOptionalParameter(4); int columnNum = -1; int numColumns = myMetric->getNumberOfMaps(); if (columnSelect->m_present) { columnNum = (int)myMetric->getMapIndexFromNameOrNumber(columnSelect->getString(1)); if (columnNum < 0 || columnNum >= numColumns) { throw AlgorithmException("invalid column specified"); } } bool allColumns = false, demean = false; OptionalParameter* allColumnsOpt = myParams->getOptionalParameter(5); if (allColumnsOpt->m_present) { if (columnSelect->m_present) throw AlgorithmException("specifying both -column and -whole-file is not allowed"); allColumns = true; demean = allColumnsOpt->getOptionalParameter(1)->m_present; } if (allColumns) { float result = estimateFWHMAllColumns(mySurf, myMetric, roi, demean); cout << "FWHM: " << result << endl; } else { if (columnNum == -1) { for (int i = 0; i < numColumns; ++i) { float result = estimateFWHM(mySurf, myMetric, roi, i); if (numColumns > 1) cout << "column " << i + 1 << " "; cout << "FWHM: " << result << endl; } } else { float result = estimateFWHM(mySurf, myMetric, roi, columnNum); if (numColumns > 1) cout << "column " << columnNum + 1 << " "; cout << "FWHM: " << result << endl; } } } float AlgorithmMetricEstimateFWHM::estimateFWHM(const SurfaceFile* mySurf, const MetricFile* input, const MetricFile* roi, const int64_t& column) { CaretAssert(column >= 0 && column < input->getNumberOfColumns()); int numNodes = input->getNumberOfNodes(); if (mySurf->getNumberOfNodes() != numNodes) { throw AlgorithmException("surface has different number of vertices than the input data"); } const float* inCol = input->getValuePointerForColumn(column); const float* roiCol = NULL; if (roi != NULL) { if (roi->getNumberOfNodes() != numNodes) { throw AlgorithmException("roi metric has a different number of vertices than the input metric"); } roiCol = roi->getValuePointerForColumn(0); } DescriptiveStatistics nodeSpacingStats; mySurf->getNodesSpacingStatistics(nodeSpacingStats);//this will be slow since it recomputes - should change it to returning a const reference, and make it a lazy member double globalAccum = 0.0, localAccum = 0.0; int64_t globalCount = 0, localCount = 0; CaretPointer myHelp = mySurf->getTopologyHelper(); for (int i = 0; i < numNodes; ++i)//the local difference mean will be zero, as we don't have directionality, so don't bother collecting it { if (roi == NULL || roiCol[i] > 0.0f) { float center = inCol[i]; globalAccum += center; ++globalCount; } } float globalMean = globalAccum / globalCount; globalAccum = 0.0; for (int i = 0; i < numNodes; ++i) { if (roi == NULL || roiCol[i] > 0.0f) { float center = inCol[i]; float tempf = center - globalMean; globalAccum += tempf * tempf;//don't need to recalculate count const vector& neighbors = myHelp->getNodeNeighbors(i); for (int j = 0; j < (int)neighbors.size(); ++j) { if (neighbors[j] > i && (roi == NULL || roiCol[neighbors[j]] > 0.0f))//collect lopsided to get correct degrees of freedom (if n-1 denom is desired), mean is assumed zero so it works out { tempf = center - inCol[neighbors[j]]; localAccum += tempf * tempf; ++localCount; } } } } float globalVariance = globalAccum / globalCount; float localVariance = localAccum / localCount; float ret = nodeSpacingStats.getMean() * sqrt(-2.0f * log(2.0f) / log(1.0f - localVariance / (2.0f * globalVariance))); return ret; } float AlgorithmMetricEstimateFWHM::estimateFWHMAllColumns(const SurfaceFile* mySurf, const MetricFile* input, const MetricFile* roi, const bool& demean) { int numNodes = input->getNumberOfNodes(); if (mySurf->getNumberOfNodes() != numNodes) { throw AlgorithmException("surface has different number of vertices than the input metric"); } const float* roiCol = NULL; if (roi != NULL) { if (roi->getNumberOfNodes() != numNodes) { throw AlgorithmException("roi metric has a different number of vertices than the input metric"); } roiCol = roi->getValuePointerForColumn(0); } DescriptiveStatistics nodeSpacingStats; mySurf->getNodesSpacingStatistics(nodeSpacingStats);//this will be slow since it recomputes - should change it to returning a const reference, and make it a lazy member int numCols = input->getNumberOfColumns(); vector meanImage; if (demean) { meanImage.resize(numNodes, 0.0); for (int j = 0; j < numCols; ++j) { const float* inCol = input->getValuePointerForColumn(j); for (int i = 0; i < numNodes; ++i) { if (roi == NULL || roiCol[i] > 0.0f)//not that it matters, but only computing the mean inside the ROI reduces the working set somewhat { meanImage[i] += inCol[i]; } } } for (int i = 0; i < numNodes; ++i) { if (roi == NULL || roiCol[i] > 0.0f) { meanImage[i] /= numCols; } } } double globalAccum = 0.0, localAccum = 0.0; int64_t globalCount = 0, localCount = 0; CaretPointer myHelp = mySurf->getTopologyHelper(); vector demeaned; if (demean) demeaned.resize(numNodes); for (int j = 0; j < numCols; ++j) { const float* inCol = input->getValuePointerForColumn(j); if (demean) { for (int i = 0; i < numNodes; ++i) { if (roi == NULL || roiCol[i] > 0.0f) { demeaned[i] = inCol[i] - meanImage[i]; } } inCol = demeaned.data(); } for (int i = 0; i < numNodes; ++i)//the local difference mean will be zero, as we don't have directionality, so don't bother collecting it { if (roi == NULL || roiCol[i] > 0.0f) { float center = inCol[i]; globalAccum += center; ++globalCount; } } } float globalMean = globalAccum / globalCount; globalAccum = 0.0; for (int j = 0; j < numCols; ++j) { const float* inCol = input->getValuePointerForColumn(j); if (demean) { for (int i = 0; i < numNodes; ++i) { if (roi == NULL || roiCol[i] > 0.0f) { demeaned[i] = inCol[i] - meanImage[i]; } } inCol = demeaned.data(); } for (int i = 0; i < numNodes; ++i) { if (roi == NULL || roiCol[i] > 0.0f) { float center = inCol[i]; float tempf = center - globalMean; globalAccum += tempf * tempf;//don't need to recalculate count const vector& neighbors = myHelp->getNodeNeighbors(i); for (int j = 0; j < (int)neighbors.size(); ++j) { if (neighbors[j] > i && (roi == NULL || roiCol[neighbors[j]] > 0.0f))//collect lopsided to get correct degrees of freedom (if n-1 denom is desired), mean is assumed zero so it works out { tempf = center - inCol[neighbors[j]]; localAccum += tempf * tempf; ++localCount; } } } } } float globalVariance = globalAccum / globalCount; float localVariance = localAccum / localCount; float ret = nodeSpacingStats.getMean() * sqrt(-2.0f * log(2.0f) / log(1.0f - localVariance / (2.0f * globalVariance))); return ret; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricEstimateFWHM.h000066400000000000000000000033341360521144700261570ustar00rootroot00000000000000#ifndef __ALGORITHM_METRIC_ESTIMATE_FWHM_H__ #define __ALGORITHM_METRIC_ESTIMATE_FWHM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmMetricEstimateFWHM : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); static float estimateFWHM(const SurfaceFile* mySurf, const MetricFile* input, const MetricFile* roi = NULL, const int64_t& column = 0); static float estimateFWHMAllColumns(const SurfaceFile* mySurf, const MetricFile* input, const MetricFile* roi = NULL, const bool& demean = false); }; typedef TemplateAutoOperation AutoAlgorithmMetricEstimateFWHM; } #endif //__ALGORITHM_METRIC_ESTIMATE_FWHM_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricExtrema.cxx000066400000000000000000001062561360521144700257110ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmMetricExtrema.h" #include "AlgorithmException.h" #include "AlgorithmMetricSmoothing.h" #include "CaretHeap.h" #include "CaretOMP.h" #include "GeodesicHelper.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "TopologyHelper.h" #include #include #include using namespace caret; using namespace std; AString AlgorithmMetricExtrema::getCommandSwitch() { return "-metric-extrema"; } AString AlgorithmMetricExtrema::getShortDescription() { return "FIND EXTREMA IN A METRIC FILE"; } OperationParameters* AlgorithmMetricExtrema::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to use for distance information"); ret->addMetricParameter(2, "metric-in", "the metric to find the extrema of"); ret->addDoubleParameter(3, "distance", "the minimum distance between identified extrema of the same type"); ret->addMetricOutputParameter(4, "metric-out", "the output extrema metric"); OptionalParameter* presmoothOpt = ret->createOptionalParameter(5, "-presmooth", "smooth the metric before finding extrema"); presmoothOpt->addDoubleParameter(1, "kernel", "the sigma for the gaussian smoothing kernel, in mm"); OptionalParameter* roiOpt = ret->createOptionalParameter(6, "-roi", "ignore values outside the selected area"); roiOpt->addMetricParameter(1, "roi-metric", "the area to find extrema in, as a metric"); OptionalParameter* thresholdOpt = ret->createOptionalParameter(7, "-threshold", "ignore small extrema"); thresholdOpt->addDoubleParameter(1, "low", "the largest value to consider for being a minimum"); thresholdOpt->addDoubleParameter(2, "high", "the smallest value to consider for being a maximum"); ret->createOptionalParameter(8, "-sum-columns", "output the sum of the extrema columns instead of each column separately"); ret->createOptionalParameter(9, "-consolidate-mode", "use consolidation of local minima instead of a large neighborhood"); ret->createOptionalParameter(11, "-only-maxima", "only find the maxima"); ret->createOptionalParameter(12, "-only-minima", "only find the minima"); OptionalParameter* columnSelect = ret->createOptionalParameter(10, "-column", "select a single column to find extrema in"); columnSelect->addStringParameter(1, "column", "the column number or name"); ret->setHelpText( AString("Finds extrema in a metric file, such that no two extrema of the same type are within of each other. ") + "The extrema are labeled as -1 for minima, 1 for maxima, 0 otherwise. " + "If -only-maxima or -only-minima is specified, then it will ignore extrema not of the specified type. These options are mutually exclusive.\n\n" + "If -roi is specified, not only is data outside the roi not used, but any vertex on the edge of the ROI will never be counted as an extrema, " + "in case the ROI cuts across a gradient, which would otherwise generate extrema where there should be none.\n\n" + "If -sum-columns is specified, these extrema columns are summed, and the output has a single column with this result.\n\n" + "By default, a datapoint is an extrema only if it is more extreme than every other datapoint that is within from it. " + "If -consolidate-mode is used, it instead starts by finding all datapoints that are more extreme than their immediate neighbors, " + "then while there are any extrema within of each other, take the two extrema closest to each other and merge them into one by a weighted average " + "based on how many original extrema have been merged into each.\n\n" + "By default, all input columns are used with no smoothing, use -column to specify a single column to use, and -presmooth to smooth the input before " + "finding the extrema." ); return ret; } void AlgorithmMetricExtrema::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* mySurf = myParams->getSurface(1); MetricFile* myMetric = myParams->getMetric(2); float distance = (float)myParams->getDouble(3); MetricFile* myMetricOut = myParams->getOutputMetric(4); OptionalParameter* presmoothOpt = myParams->getOptionalParameter(5); float presmooth = -1.0f; if (presmoothOpt->m_present) { presmooth = (float)presmoothOpt->getDouble(1); if (presmooth <= 0.0f) { throw AlgorithmException("smoothing kernel must be positive"); } } OptionalParameter* roiOpt = myParams->getOptionalParameter(6); MetricFile* myRoi = NULL; if (roiOpt->m_present) { myRoi = roiOpt->getMetric(1); } OptionalParameter* thresholdOpt = myParams->getOptionalParameter(7); bool thresholdMode = false; float lowThresh = 0.0f, highThresh = 0.0f; if (thresholdOpt->m_present) { thresholdMode = true; lowThresh = (float)thresholdOpt->getDouble(1); highThresh = (float)thresholdOpt->getDouble(2); } bool sumColumns = myParams->getOptionalParameter(8)->m_present; bool consolidateMode = myParams->getOptionalParameter(9)->m_present; OptionalParameter* columnSelect = myParams->getOptionalParameter(10); int columnNum = -1; if (columnSelect->m_present) {//set up to use the single column columnNum = (int)myMetric->getMapIndexFromNameOrNumber(columnSelect->getString(1)); if (columnNum < 0) { throw AlgorithmException("invalid column specified"); } } bool ignoreMinima = myParams->getOptionalParameter(11)->m_present; bool ignoreMaxima = myParams->getOptionalParameter(12)->m_present; if (ignoreMinima && ignoreMaxima) throw AlgorithmException("you may not specify both -only-maxima and -only-minima"); if (thresholdMode) { AlgorithmMetricExtrema(myProgObj, mySurf, myMetric, distance, myMetricOut, lowThresh, highThresh, myRoi, presmooth, sumColumns, consolidateMode, ignoreMinima, ignoreMaxima, columnNum); } else { AlgorithmMetricExtrema(myProgObj, mySurf, myMetric, distance, myMetricOut, myRoi, presmooth, sumColumns, consolidateMode, ignoreMinima, ignoreMaxima, columnNum); } } AlgorithmMetricExtrema::AlgorithmMetricExtrema(ProgressObject* myProgObj, const SurfaceFile* mySurf,const MetricFile* myMetric, const float& distance, MetricFile* myMetricOut, const MetricFile* myRoi, const float& presmooth, const bool& sumColumns, const bool& consolidateMode, const bool& ignoreMinima, const bool& ignoreMaxima, const int& columnNum) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (ignoreMinima && ignoreMaxima) throw AlgorithmException("AlgorithmMetricExtrema called with ignoreMinima and ignoreMaxima both true"); int numNodes = mySurf->getNumberOfNodes(); if (myMetric->getNumberOfNodes() != numNodes) { throw AlgorithmException("input metric has different number of vertices than input surface"); } const float* roiColumn = NULL; if (myRoi != NULL) { if (myRoi->getNumberOfNodes() != numNodes) { throw AlgorithmException("roi metric has a different number of nodes than input surface"); } roiColumn = myRoi->getValuePointerForColumn(0); } int numCols = myMetric->getNumberOfColumns(); if (columnNum < -1 || columnNum >= numCols) { throw AlgorithmException("invalid column number"); } int useCol = columnNum; const MetricFile* toProcess = myMetric; MetricFile tempMetric; if (presmooth > 0.0f) { AlgorithmMetricSmoothing(NULL, mySurf, myMetric, presmooth, &tempMetric, myRoi, false, false, columnNum); toProcess = &tempMetric; if (columnNum != -1) { useCol = 0; } } vector > neighborhoods; if (!consolidateMode) { precomputeNeighborhoods(mySurf, roiColumn, distance, neighborhoods); } if (columnNum == -1) { vector scratchcol(numNodes, 0.0f); vector minima, maxima; if (sumColumns) { myMetricOut->setNumberOfNodesAndColumns(numNodes, 1); myMetricOut->setColumnName(0, "sum of extrema"); } else { myMetricOut->setNumberOfNodesAndColumns(numNodes, numCols); } myMetricOut->setStructure(mySurf->getStructure()); for (int i = 0; i < numCols; ++i) { if (consolidateMode) { findExtremaConsolidate(mySurf, toProcess->getValuePointerForColumn(i), roiColumn, distance, false, 0.0f, 0.0f, ignoreMinima, ignoreMaxima, minima, maxima); } else { findExtremaNeighborhoods(toProcess->getValuePointerForColumn(i), neighborhoods, false, 0.0f, 0.0f, ignoreMinima, ignoreMaxima, minima, maxima); } if (sumColumns) { int numelems = (int)minima.size(); for (int j = 0; j < numelems; ++j) { scratchcol[minima[j]] -= 1.0f; } numelems = (int)maxima.size(); for (int j = 0; j < numelems; ++j) { scratchcol[maxima[j]] += 1.0f; } } else { int numelems = (int)minima.size(); for (int j = 0; j < numelems; ++j) { scratchcol[minima[j]] = -1.0f; } numelems = (int)maxima.size(); for (int j = 0; j < numelems; ++j) { scratchcol[maxima[j]] = 1.0f; } myMetricOut->setColumnName(i, "extrema of " + myMetric->getColumnName(i));//don't include the whatever smoothing adds to the names, i guess myMetricOut->setValuesForColumn(i, scratchcol.data()); numelems = (int)minima.size(); for (int j = 0; j < numelems; ++j) { scratchcol[minima[j]] = 0.0f; } numelems = (int)maxima.size(); for (int j = 0; j < numelems; ++j) { scratchcol[maxima[j]] = 0.0f; } } } if (sumColumns) { myMetricOut->setValuesForColumn(0, scratchcol.data()); } } else { vector scratchcol(numNodes, 0.0f); vector minima, maxima; myMetricOut->setNumberOfNodesAndColumns(numNodes, 1); myMetricOut->setStructure(mySurf->getStructure()); if (consolidateMode) { findExtremaConsolidate(mySurf, toProcess->getValuePointerForColumn(useCol), roiColumn, distance, false, 0.0f, 0.0f, ignoreMinima, ignoreMaxima, minima, maxima); } else { findExtremaNeighborhoods(toProcess->getValuePointerForColumn(useCol), neighborhoods, false, 0.0f, 0.0f, ignoreMinima, ignoreMaxima, minima, maxima); } int numelems = (int)minima.size(); for (int j = 0; j < numelems; ++j) { scratchcol[minima[j]] = -1.0f; } numelems = (int)maxima.size(); for (int j = 0; j < numelems; ++j) { scratchcol[maxima[j]] = 1.0f; } myMetricOut->setColumnName(0, "extrema of" + myMetric->getColumnName(columnNum));//ditto myMetricOut->setValuesForColumn(0, scratchcol.data()); } } AlgorithmMetricExtrema::AlgorithmMetricExtrema(ProgressObject* myProgObj, const SurfaceFile* mySurf,const MetricFile* myMetric, const float& distance, MetricFile* myMetricOut, const float& lowThresh, const float& highThresh, const MetricFile* myRoi, const float& presmooth, const bool& sumColumns, const bool& consolidateMode, const bool& ignoreMinima, const bool& ignoreMaxima, const int& columnNum) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (ignoreMinima && ignoreMaxima) throw AlgorithmException("AlgorithmMetricExtrema called with ignoreMinima and ignoreMaxima both true"); int numNodes = mySurf->getNumberOfNodes(); if (myMetric->getNumberOfNodes() != numNodes) { throw AlgorithmException("input metric has different number of vertices than input surface"); } const float* roiColumn = NULL; if (myRoi != NULL) { if (myRoi->getNumberOfNodes() != numNodes) { throw AlgorithmException("roi metric has a different number of nodes than input surface"); } roiColumn = myRoi->getValuePointerForColumn(0); } int numCols = myMetric->getNumberOfColumns(); if (columnNum < -1 || columnNum >= numCols) { throw AlgorithmException("invalid column number"); } int useCol = columnNum; const MetricFile* toProcess = myMetric; MetricFile tempMetric; if (presmooth > 0.0f) { AlgorithmMetricSmoothing(NULL, mySurf, myMetric, presmooth, &tempMetric, myRoi, false, false, columnNum); toProcess = &tempMetric; if (columnNum != -1) { useCol = 0; } } vector > neighborhoods; if (!consolidateMode) { precomputeNeighborhoods(mySurf, roiColumn, distance, neighborhoods); } if (columnNum == -1) { vector scratchcol(numNodes, 0.0f); vector minima, maxima; if (sumColumns) { myMetricOut->setNumberOfNodesAndColumns(numNodes, 1); } else { myMetricOut->setNumberOfNodesAndColumns(numNodes, numCols); } for (int i = 0; i < numCols; ++i) { if (consolidateMode) { findExtremaConsolidate(mySurf, toProcess->getValuePointerForColumn(i), roiColumn, distance, true, lowThresh, highThresh, ignoreMinima, ignoreMaxima, minima, maxima); } else { findExtremaNeighborhoods(toProcess->getValuePointerForColumn(i), neighborhoods, true, lowThresh, highThresh, ignoreMinima, ignoreMaxima, minima, maxima); } if (sumColumns) { int numelems = (int)minima.size(); for (int j = 0; j < numelems; ++j) { scratchcol[minima[j]] -= 1.0f; } numelems = (int)maxima.size(); for (int j = 0; j < numelems; ++j) { scratchcol[maxima[j]] += 1.0f; } } else { int numelems = (int)minima.size(); for (int j = 0; j < numelems; ++j) { scratchcol[minima[j]] = -1.0f; } numelems = (int)maxima.size(); for (int j = 0; j < numelems; ++j) { scratchcol[maxima[j]] = 1.0f; } myMetricOut->setValuesForColumn(i, scratchcol.data()); numelems = (int)minima.size(); for (int j = 0; j < numelems; ++j) { scratchcol[minima[j]] = 0.0f; } numelems = (int)maxima.size(); for (int j = 0; j < numelems; ++j) { scratchcol[maxima[j]] = 0.0f; } } } if (sumColumns) { myMetricOut->setValuesForColumn(0, scratchcol.data()); } } else { vector scratchcol(numNodes, 0.0f); vector minima, maxima; myMetricOut->setNumberOfNodesAndColumns(numNodes, 1); if (consolidateMode) { findExtremaConsolidate(mySurf, toProcess->getValuePointerForColumn(useCol), roiColumn, distance, true, lowThresh, highThresh, ignoreMinima, ignoreMaxima, minima, maxima); } else { findExtremaNeighborhoods(toProcess->getValuePointerForColumn(useCol), neighborhoods, true, lowThresh, highThresh, ignoreMinima, ignoreMaxima, minima, maxima); } int numelems = (int)minima.size(); for (int j = 0; j < numelems; ++j) { scratchcol[minima[j]] = -1.0f; } numelems = (int)maxima.size(); for (int j = 0; j < numelems; ++j) { scratchcol[maxima[j]] = 1.0f; } myMetricOut->setValuesForColumn(0, scratchcol.data()); } } void AlgorithmMetricExtrema::precomputeNeighborhoods(const SurfaceFile* mySurf, const float* roiColumn, const float& distance, vector >& neighborhoods) { int numNodes = mySurf->getNumberOfNodes(); neighborhoods.clear(); neighborhoods.resize(numNodes); CaretPointer myTopoHelp = mySurf->getTopologyHelper();//can share this, we will only use 1-hop neighbors CaretPointer myGeoHelp = mySurf->getGeodesicHelper();//must be thread-private vector junk;//also thread-private for (int i = 0; i < numNodes; ++i) { if (roiColumn == NULL || roiColumn[i] > 0.0f) { if (roiColumn != NULL) { const vector& neighbors = myTopoHelp->getNodeNeighbors(i); int numNeigh = (int)neighbors.size(); bool good = true; for (int j = 0; j < numNeigh; ++j) { if (roiColumn[neighbors[j]] <= 0.0f) { good = false; break; } } if (!good) { neighborhoods[i].push_back(-1);//use a single neighbor of -1 to denote "do not use due to being on the edge of the ROI" - a bit of a hack, but means we don't need a second array, and still separates it from "no neighbors" continue; } } myGeoHelp->getNodesToGeoDist(i, distance, neighborhoods[i], junk); int numelems = (int)neighborhoods[i].size(); if (numelems < 7) { neighborhoods[i] = myTopoHelp->getNodeNeighbors(i); if (roiColumn != NULL) { numelems = (int)neighborhoods[i].size(); for (int j = 0; j < numelems; ++j) { if (roiColumn[neighborhoods[i][j]] <= 0.0f) { neighborhoods[i].erase(neighborhoods[i].begin() + j);//erase it --j;//don't skip any or walk off the vector --numelems; } } } } else { if (roiColumn == NULL) { for (int j = 0; j < numelems; ++j) { if (neighborhoods[i][j] == i) { neighborhoods[i].erase(neighborhoods[i].begin() + j);//we don't want the node itself, so erase it break; } } } else { for (int j = 0; j < numelems; ++j) { if (neighborhoods[i][j] == i || roiColumn[neighborhoods[i][j]] <= 0.0f)//don't want the node itself, or anything outside the roi { neighborhoods[i].erase(neighborhoods[i].begin() + j);//erase it --j;//don't skip any or walk off the vector --numelems; } } } } } } } void AlgorithmMetricExtrema::findExtremaNeighborhoods(const float* data, const vector >& neighborhoods, const bool& threshMode, const float& lowThresh, const float& highThresh, const bool& ignoreMinima, const bool& ignoreMaxima, vector& minima, vector& maxima) { int numNodes = (int)neighborhoods.size(); minima.clear(); maxima.clear(); vector minPos(numNodes, 1), maxPos(numNodes, 1);//mark off things that fail a comparison to reduce the work - these are just used as booleans, but we don't want bitwise packing slowing us down or dropping parallel writes #pragma omp CARET_PARFOR schedule(dynamic) for (int i = 0; i < numNodes; ++i) { bool canBeMin = minPos[i] && !ignoreMinima, canBeMax = maxPos[i] && !ignoreMaxima; if (canBeMin || canBeMax) { const vector& myneighbors = neighborhoods[i]; int numNeigh = (int)myneighbors.size(); if (numNeigh == 0) continue;//don't count isolated nodes as minima or maxima if (numNeigh == 1 && myneighbors[0] == -1) continue;//ignore nodes on the edge of the ROI, because this often generates artificial extrema float myval = data[i]; if (threshMode) { if (myval > lowThresh) canBeMin = false;//check thresholds if (myval < highThresh) canBeMax = false; } int j = 0; if (canBeMin && canBeMax)//avoid the double-test unless both options are on the table {//should be fairly rare, and doesn't need to loop int32_t neighNode = myneighbors[0];//NOTE: the equals case should set one of these to false, so that only one of the two loops needs to execute float otherval = data[neighNode]; if (myval < otherval) { minPos[neighNode] = 0; } else { canBeMin = false;//center being equal or greater means it is not a minimum, so stop testing that } if (myval > otherval) { maxPos[neighNode] = 0; } else { canBeMax = false; } j = 1;//don't test 0 again if we did the double test } if (canBeMax) { for (; j < numNeigh; ++j) { int32_t neighNode = myneighbors[j]; float otherval = data[neighNode]; if (myval > otherval) { maxPos[neighNode] = 0;//TODO: test if performing an intelligent comparison here is faster than doing unneeded stores } else { canBeMax = false; break; } } } if (canBeMin) { for (; j < numNeigh; ++j) { int32_t neighNode = myneighbors[j]; float otherval = data[neighNode]; if (myval < otherval) { minPos[neighNode] = 0;//ditto } else { canBeMin = false; break; } } } if (canBeMax) { #pragma omp critical { maxima.push_back(i); } } if (canBeMin) { #pragma omp critical { minima.push_back(i); } } } } } void AlgorithmMetricExtrema::findExtremaConsolidate(const SurfaceFile* mySurf, const float* data, const float* roiColumn, const float& distance, const bool& threshMode, const float& lowThresh, const float& highThresh, const bool& ignoreMinima, const bool& ignoreMaxima, vector& minima, vector& maxima) { int numNodes = mySurf->getNumberOfNodes(); minima.clear(); maxima.clear(); vector > tempExtrema[2]; vector minPos(numNodes, 1), maxPos(numNodes, 1);//mark off things that fail a comparison to reduce the work - these are just used as booleans, but we don't want bitwise packing slowing us down or dropping writes CaretPointer myTopoHelp = mySurf->getTopologyHelper(); #pragma omp CARET_PARFOR schedule(dynamic) for (int i = 0; i < numNodes; ++i) { bool canBeMin = minPos[i] && !ignoreMinima, canBeMax = maxPos[i] && !ignoreMaxima; if (canBeMin || canBeMax) { const vector& myneighbors = myTopoHelp->getNodeNeighbors(i); int numNeigh = (int)myneighbors.size(); if (numNeigh == 0) continue;//don't count isolated nodes as minima or maxima float myval = data[i]; if (threshMode) { if (myval > lowThresh) canBeMin = false;//check thresholds if (myval < highThresh) canBeMax = false; } if (canBeMin && canBeMax)//avoid the double-test unless both options are on the table {//NOTE: the equals case should set one of these to false, so that only one of the two below loops needs to execute int32_t neighNode = myneighbors[0]; if (roiColumn == NULL || roiColumn[neighNode] > 0.0f) { float otherval = data[neighNode]; if (myval < otherval) { minPos[neighNode] = 0; } else { canBeMin = false;//center being equal or greater means it is not a minimum, so stop testing that } if (myval > otherval) { maxPos[neighNode] = 0; } else { canBeMax = false; } } else { canBeMin = false;//if we neighbor something outside the ROI, do not allow counting as max or min canBeMax = false; } } int j = 1;//don't retest the first neighbor if (canBeMax) { for (; j < numNeigh; ++j) { int32_t neighNode = myneighbors[j]; if (roiColumn == NULL || roiColumn[neighNode] > 0.0f) { float otherval = data[neighNode]; if (myval > otherval) { maxPos[neighNode] = 0;//TODO: test if performing an intelligent comparison here is faster than doing unneeded stores } else { canBeMax = false; break; } } else { canBeMax = false;//if we neighbor something outside the ROI, do not allow counting as max or min break; } } } if (canBeMin) { for (; j < numNeigh; ++j) { int32_t neighNode = myneighbors[j]; if (roiColumn == NULL || roiColumn[neighNode] > 0.0f) { float otherval = data[neighNode]; if (myval < otherval) { minPos[neighNode] = 0;//ditto } else { canBeMin = false; break; } } else { canBeMin = false;//if we neighbor something outside the ROI, do not allow counting as max or min break; } } } if (canBeMax) { #pragma omp critical { tempExtrema[0].push_back(pair(i, 1)); } } if (canBeMin) { #pragma omp critical { tempExtrema[1].push_back(pair(i, 1)); } } } } consolidateStep(mySurf, distance, tempExtrema, minima, maxima); } void AlgorithmMetricExtrema::consolidateStep(const SurfaceFile* mySurf, const float& distance, vector > initExtrema[2], vector& minima, vector& maxima) { int numNodes = mySurf->getNumberOfNodes(); vector scratchDist(numNodes, -1.0f); for (int sign = 0; sign < 2; ++sign) { int numInitExtrema = (int)initExtrema[sign].size(); vector removed(numInitExtrema, false);//track which extrema locations are dropped during consolidation - the one that isn't dropped in a merge has its node number changed vector > heapIDmatrix(numInitExtrema, vector(numInitExtrema, -1)); CaretMinHeap, float> myDistHeap; vector dists; vector neighbors; CaretPointer myGeoHelp = mySurf->getGeodesicHelper(); for (int i = 0; i < numInitExtrema - 1; ++i) { myGeoHelp->getNodesToGeoDist(initExtrema[sign][i].first, distance, neighbors, dists);//use smooth distance to get whether they are close enough int numInDist = (int)dists.size(); for (int j = 0; j < numInDist; ++j) { scratchDist[neighbors[j]] = dists[j]; } for (int j = i + 1; j < numInitExtrema; ++j) { float tempf = scratchDist[initExtrema[sign][j].first]; if (tempf > -0.5f) { int64_t tempID = myDistHeap.push(pair(i, j), tempf); heapIDmatrix[i][j] = tempID; heapIDmatrix[j][i] = tempID; } } for (int j = 0; j < numInDist; ++j) { scratchDist[neighbors[j]] = -1.0f; } }//initial distance matrix computed, now we iterate while (!myDistHeap.isEmpty()) { pair toMerge = myDistHeap.pop();//we don't need to know the key int extr1 = toMerge.first; int extr2 = toMerge.second; heapIDmatrix[extr1][extr2] = -1; heapIDmatrix[extr2][extr1] = -1; int weight1 = initExtrema[sign][extr1].second; int weight2 = initExtrema[sign][extr2].second; if (weight2 > weight1)//swap so weight1 is always bigger { int temp = weight2; weight2 = weight1; weight1 = temp; temp = extr2; extr2 = extr1; extr1 = temp; } int node1 = initExtrema[sign][extr1].first; int node2 = initExtrema[sign][extr2].first; removed[extr2] = true;//drop the one that has less weight, and modify the one that has more weight for (int j = 0; j < numInitExtrema; ++j) { if (!removed[j]) { int64_t tempID = heapIDmatrix[extr2][j]; if (tempID != -1) { myDistHeap.remove(tempID); heapIDmatrix[extr2][j] = -1; heapIDmatrix[j][extr2] = -1; } } } vector pathnodes; vector pathdists; myGeoHelp->getPathToNode(node1, node2, pathnodes, pathdists, false); if (pathdists.size() != 0) { float distToWalk = (pathdists.back() * weight2) / (weight1 + weight2); int walk = 1, maxSteps = (int)pathnodes.size(); float prevdiff = abs(distToWalk - pathdists[0]); while (walk < maxSteps) { float newdiff = abs(distToWalk - pathdists[walk]); if (newdiff > prevdiff) break; ++walk; } int newnode = pathnodes[walk - 1]; initExtrema[sign][extr1].first = newnode; initExtrema[sign][extr1].second += weight2;//add the weights together myGeoHelp->getNodesToGeoDist(newnode, distance, neighbors, dists); int numInDist = (int)dists.size(); for (int j = 0; j < numInDist; ++j) { scratchDist[neighbors[j]] = dists[j]; } for (int j = 0; j < numInitExtrema; ++j) { if (!removed[j]) { float tempf = scratchDist[initExtrema[sign][j].first]; int64_t tempID = heapIDmatrix[extr1][j]; if (tempf > -0.5f) { if (tempID != -1) { myDistHeap.changekey(tempID, tempf); } else { tempID = myDistHeap.push(pair(extr1, j), tempf); heapIDmatrix[extr1][j] = tempID; heapIDmatrix[j][extr1] = tempID; } } else { if (tempID != -1) { myDistHeap.remove(tempID); heapIDmatrix[extr1][j] = -1; heapIDmatrix[j][extr1] = -1; } } } } for (int j = 0; j < numInDist; ++j) { scratchDist[neighbors[j]] = -1.0f; } } } if (sign == 0) { for (int i = 0; i < numInitExtrema; ++i) { if (!removed[i]) { maxima.push_back(initExtrema[sign][i].first); } } } else { for (int i = 0; i < numInitExtrema; ++i) { if (!removed[i]) { minima.push_back(initExtrema[sign][i].first); } } } } } float AlgorithmMetricExtrema::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmMetricExtrema::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricExtrema.h000066400000000000000000000071461360521144700253340ustar00rootroot00000000000000#ifndef __ALGORITHM_METRIC_EXTREMA_H__ #define __ALGORITHM_METRIC_EXTREMA_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include #include namespace caret { class AlgorithmMetricExtrema : public AbstractAlgorithm { void precomputeNeighborhoods(const SurfaceFile* mySurf, const float* roiColumn, const float& distance, std::vector >& neighborhoods); void findExtremaConsolidate(const SurfaceFile* mySurf, const float* data, const float* roiColumn, const float& distance, const bool& threshMode, const float& lowThresh, const float& highThresh, const bool& ignoreMinima, const bool& ignoreMaxima, std::vector& minima, std::vector& maxima); void findExtremaNeighborhoods(const float* data, const std::vector >& neighborhoods, const bool& threshMode, const float& lowThresh, const float& highThresh, const bool& ignoreMinima, const bool& ignoreMaxima, std::vector& minima, std::vector& maxima); void consolidateStep(const SurfaceFile* mySurf, const float& distance, std::vector > initExtrema[2], std::vector& minima, std::vector& maxima); AlgorithmMetricExtrema(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmMetricExtrema(ProgressObject* myProgObj, const SurfaceFile* mySurf,const MetricFile* myMetric, const float& distance, MetricFile* myMetricOut, const MetricFile* myRoi = NULL, const float& presmooth = -1.0f, const bool& sumColumns = false, const bool& consolidateMode = false, const bool& ignoreMinima = false, const bool& ignoreMaxima = false, const int& columnNum = -1); AlgorithmMetricExtrema(ProgressObject* myProgObj, const SurfaceFile* mySurf,const MetricFile* myMetric, const float& distance, MetricFile* myMetricOut, const float& lowThresh, const float& highThresh, const MetricFile* myRoi = NULL, const float& presmooth = -1.0f, const bool& sumColumns = false, const bool& consolidateMode = false, const bool& ignoreMinima = false, const bool& ignoreMaxima = false, const int& columnNum = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmMetricExtrema; } #endif //__ALGORITHM_METRIC_EXTREMA_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricFalseCorrelation.cxx000066400000000000000000000340661360521144700275370ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmMetricFalseCorrelation.h" #include "AlgorithmException.h" #include "CaretOMP.h" #include "CaretPointLocator.h" #include "GeodesicHelper.h" #include "SurfaceFile.h" #include "MetricFile.h" #include #include using namespace caret; using namespace std; AString AlgorithmMetricFalseCorrelation::getCommandSwitch() { return "-metric-false-correlation"; } AString AlgorithmMetricFalseCorrelation::getShortDescription() { return "COMPARE CORRELATION LOCALLY AND ACROSS/THROUGH SULCI/GYRI"; } OperationParameters* AlgorithmMetricFalseCorrelation::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to compute geodesic and 3D distance with"); ret->addMetricParameter(2, "metric-in", "the metric to correlate"); ret->addDoubleParameter(3, "3D-dist", "maximum 3D distance to check around each vertex"); ret->addDoubleParameter(4, "geo-outer", "maximum geodesic distance to use for neighboring correlation"); ret->addDoubleParameter(5, "geo-inner", "minimum geodesic distance to use for neighboring correlation"); ret->addMetricOutputParameter(6, "metric-out", "the output metric"); OptionalParameter* roiOpt = ret->createOptionalParameter(7, "-roi", "select a region of interest that has data"); roiOpt->addMetricParameter(1, "roi-metric", "the region, as a metric file"); OptionalParameter* dumpTextOpt = ret->createOptionalParameter(8, "-dump-text", "dump the raw measures used to a text file"); dumpTextOpt->addStringParameter(1, "text-out", "the output text file"); ret->setHelpText( AString("For each vertex, compute the average correlation within a range of geodesic distances that don't cross a sulcus/gyrus, and the correlation to the closest vertex crossing a sulcus/gyrus. ") + "A vertex is considered to cross a sulcus/gyrus if the 3D distance is less than a third of the geodesic distance. " + "The output file contains the ratio between these correlations, and some additional maps to help explain the ratio." ); return ret; } void AlgorithmMetricFalseCorrelation::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* mySurf = myParams->getSurface(1); MetricFile* myMetric = myParams->getMetric(2); float max3D = (float)myParams->getDouble(3); float maxgeo = (float)myParams->getDouble(4); float mingeo = (float)myParams->getDouble(5); MetricFile* myMetricOut = myParams->getOutputMetric(6); MetricFile* myRoi = NULL; OptionalParameter* roiOpt = myParams->getOptionalParameter(7); if (roiOpt->m_present) { myRoi = roiOpt->getMetric(1); } AString textName = ""; OptionalParameter* dumpTextOpt = myParams->getOptionalParameter(8); if (dumpTextOpt->m_present) { textName = dumpTextOpt->getString(1); } AlgorithmMetricFalseCorrelation(myProgObj, mySurf, myMetric, myMetricOut, max3D, maxgeo, mingeo, myRoi, textName); } AlgorithmMetricFalseCorrelation::AlgorithmMetricFalseCorrelation(ProgressObject* myProgObj, const SurfaceFile* mySurf, const MetricFile* myMetric, MetricFile* myMetricOut, const float& max3D, const float& maxgeo, const float& mingeo, const MetricFile* myRoi, const AString& textName) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (max3D <= 0.0f || maxgeo <= 0.0f || mingeo < 0.0f) throw AlgorithmException("distance limits must not be negative, and maximums must be positive"); int numNodes = mySurf->getNumberOfNodes(); if (myMetric->getNumberOfNodes() != numNodes) throw AlgorithmException("surface and metric have different number of vertices"); const float* roiCol = NULL; if (myRoi != NULL) { if (myRoi->getNumberOfNodes() != numNodes) throw AlgorithmException("surface and roi metric have different number of vertices"); roiCol = myRoi->getValuePointerForColumn(0); } if (myMetric->getNumberOfColumns() < 3) throw AlgorithmException("input metric must have more than 2 columns for correlation to be meaningful"); bool dumpRaw = false; ofstream rawOut; if (textName != "") { dumpRaw = true; rawOut.open(textName.toLocal8Bit().constData()); if (!rawOut) throw AlgorithmException("failed to open text file for output"); } m_toCorr = myMetric;//so we can do fancy correlation caching without rewriting this part, if we want setupCorr(roiCol); myMetricOut->setNumberOfNodesAndColumns(numNodes, 5); myMetricOut->setStructure(mySurf->getStructure()); myMetricOut->setColumnName(0, "correlation ratio"); myMetricOut->setColumnName(1, "non-neighborhood correlation"); myMetricOut->setColumnName(2, "average neighborhood correlation"); myMetricOut->setColumnName(3, "3D distance to non-neighborhood vertex"); myMetricOut->setColumnName(4, "non-neighborhood vertex number"); const AString sep1 = ",", sep2 = ";\n"; float distRatioCutoff = 3.0f; CaretPointer myLocator = mySurf->getPointLocator(); #pragma omp CARET_PAR { CaretPointer myGeo = mySurf->getGeodesicHelper(); #pragma omp CARET_FOR schedule(dynamic) for (int n = 0; n < numNodes; ++n) { int crossingNode = -1, neighCount = 0; float crossingDist = -1.0f, neighAccum = 0.0f; if (roiCol == NULL || roiCol[n] > 0.0f) { AString rawDumpString;//build the entire string for a single node, then write it in one call within #pragma omp critical Vector3D myCoord = mySurf->getCoordinate(n); vector inRange = myLocator->pointsInRange(myCoord, max3D); int numInterested = (int)inRange.size(); vector interested(numInterested); int counter = 0; for (vector::iterator iter = inRange.begin(); iter != inRange.end(); ++iter) { interested[counter] = iter->index; ++counter; } vector geoDists; myGeo->getGeoToTheseNodes(n, interested, geoDists); counter = 0; for (vector::iterator iter = inRange.begin(); iter != inRange.end(); ++iter) { if (roiCol == NULL || (roiCol[iter->index] > 0.0f)) { float dist3D = (myCoord - iter->coords).length(); if (iter->index == n || geoDists[counter] / dist3D < distRatioCutoff) { if (maxgeo <= max3D)//otherwise, we can't trust the 3D test picking up all the points we want { if (dumpRaw) { float thiscorr = correlate(n, iter->index); rawDumpString += AString::number(n) + sep1 + AString::number(iter->index) + sep1 + AString::number(thiscorr) + sep1 + AString::number(geoDists[counter]) + sep1 + AString::number(dist3D) + sep2; if (geoDists[counter] <= maxgeo && geoDists[counter] >= mingeo) { neighAccum += thiscorr; ++neighCount; } } else { if (geoDists[counter] <= maxgeo && geoDists[counter] >= mingeo) { float thiscorr = correlate(n, iter->index); neighAccum += thiscorr; ++neighCount; } } } } else { if (dist3D < crossingDist || crossingNode == -1) { crossingDist = dist3D; crossingNode = iter->index; } if (dumpRaw) { float thiscorr = correlate(n, iter->index); rawDumpString += AString::number(n) + sep1 + AString::number(iter->index) + sep1 + AString::number(thiscorr) + sep1 + AString::number(geoDists[counter]) + sep1 + AString::number(dist3D) + sep2; } } } ++counter; } if (maxgeo > max3D)//so, we have to run geodesic separately { myGeo->getNodesToGeoDist(n, maxgeo, interested, geoDists);//reuse interested, we don't need its previous contents int numInRange = (int)interested.size(); for (int i = 0; i < numInRange; ++i) { if (roiCol != NULL && !(roiCol[interested[i]] > 0.0f)) continue; float dist3D = (myCoord - Vector3D(mySurf->getCoordinate(interested[i]))).length(); if ((interested[i] == n || geoDists[i] / dist3D < distRatioCutoff)) { if (dumpRaw) { float thiscorr = correlate(n, interested[i]); rawDumpString += AString::number(n) + sep1 + AString::number(interested[i]) + sep1 + AString::number(thiscorr) + sep1 + AString::number(geoDists[i]) + sep1 + AString::number(dist3D) + sep2; if (geoDists[i] >= mingeo)//we already know it is not greater than maxgeo { neighAccum += thiscorr; ++neighCount; } } else { if (geoDists[i] >= mingeo) { float thiscorr = correlate(n, interested[i]); neighAccum += thiscorr; ++neighCount; } } } } } if (dumpRaw) { #pragma omp critical { rawOut << rawDumpString; } } } if (crossingNode != -1 && neighCount != 0) { float longCorr = correlate(n, crossingNode); float closeAvg = neighAccum / neighCount; myMetricOut->setValue(n, 0, longCorr / closeAvg); myMetricOut->setValue(n, 1, longCorr); myMetricOut->setValue(n, 2, closeAvg); myMetricOut->setValue(n, 3, crossingDist); myMetricOut->setValue(n, 4, crossingNode); } else { myMetricOut->setValue(n, 0, 0.0f); myMetricOut->setValue(n, 1, 0.0f); myMetricOut->setValue(n, 2, 0.0f); myMetricOut->setValue(n, 3, 0.0f); myMetricOut->setValue(n, 4, -1); } } } } float AlgorithmMetricFalseCorrelation::correlate(int first, int second) { CaretAssert((int)m_demeanedRows[first].size() == m_rowSize); CaretAssert((int)m_demeanedRows[second].size() == m_rowSize); double accum = 0.0; for (int i = 0; i < m_rowSize; ++i) { accum += m_demeanedRows[first][i] * m_demeanedRows[second][i]; } return accum / (m_rrs[first] * m_rrs[second]); } void AlgorithmMetricFalseCorrelation::setupCorr(const float* roiCol) { m_rowSize = m_toCorr->getNumberOfColumns(); int numRows = m_toCorr->getNumberOfNodes(); m_demeanedRows.resize(numRows); m_rrs.resize(numRows); for (int i = 0; i < numRows; ++i) { if (roiCol != NULL && !(roiCol[i] > 0.0f)) continue; double accum = 0.0f; m_demeanedRows[i].resize(m_rowSize); for (int j = 0; j < m_rowSize; ++j) { float tempf = m_toCorr->getValue(i, j); m_demeanedRows[i][j] = tempf;//first, transpose the indexing - in MetricFile, a column is contiguous in memory accum += tempf; } float mean = accum / m_rowSize; accum = 0.0; for (int j = 0; j < m_rowSize; ++j) { float tempf = m_demeanedRows[i][j] - mean;//remove mean, calculate rrs for correlation m_demeanedRows[i][j] = tempf; accum += tempf * tempf; } m_rrs[i] = sqrt(accum); } } float AlgorithmMetricFalseCorrelation::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmMetricFalseCorrelation::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricFalseCorrelation.h000066400000000000000000000042411360521144700271540ustar00rootroot00000000000000#ifndef __ALGORITHM_METRIC_FALSE_CORRELATION_H__ #define __ALGORITHM_METRIC_FALSE_CORRELATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include namespace caret { class AlgorithmMetricFalseCorrelation : public AbstractAlgorithm { AlgorithmMetricFalseCorrelation(); float correlate(int first, int second); const MetricFile* m_toCorr; int m_rowSize; std::vector > m_demeanedRows; std::vector m_rrs; void setupCorr(const float* roiCol); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmMetricFalseCorrelation(ProgressObject* myProgObj, const SurfaceFile* mySurf, const MetricFile* myMetric, MetricFile* myMetricOut, const float& max3D, const float& maxgeo, const float& mingeo, const MetricFile* myRoi = NULL, const AString& textName = ""); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmMetricFalseCorrelation; } #endif //__ALGORITHM_METRIC_FALSE_CORRELATION_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricFillHoles.cxx000066400000000000000000000150071360521144700261560ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmMetricFillHoles.h" #include "AlgorithmException.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "TopologyHelper.h" #include #include using namespace caret; using namespace std; AString AlgorithmMetricFillHoles::getCommandSwitch() { return "-metric-fill-holes"; } AString AlgorithmMetricFillHoles::getShortDescription() { return "FILL HOLES IN AN ROI METRIC"; } OperationParameters* AlgorithmMetricFillHoles::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to use for neighbor information"); ret->addMetricParameter(2, "metric-in", "the input ROI metric"); ret->addMetricOutputParameter(3, "metric-out", "the output ROI metric"); OptionalParameter* corrAreaOpt = ret->createOptionalParameter(4, "-corrected-areas", "vertex areas to use instead of computing them from the surface"); corrAreaOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); ret->setHelpText( AString("Finds all connected areas that are not included in the ROI, and writes ones into all but the largest one, in terms of surface area.") ); return ret; } void AlgorithmMetricFillHoles::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* mySurf = myParams->getSurface(1); MetricFile* myMetric = myParams->getMetric(2); MetricFile* myMetricOut = myParams->getOutputMetric(3); MetricFile* corrAreaMetric = NULL; OptionalParameter* corrAreaOpt = myParams->getOptionalParameter(4); if (corrAreaOpt->m_present) { corrAreaMetric = corrAreaOpt->getMetric(1); } AlgorithmMetricFillHoles(myProgObj, mySurf, myMetric, myMetricOut, corrAreaMetric); } AlgorithmMetricFillHoles::AlgorithmMetricFillHoles(ProgressObject* myProgObj, const SurfaceFile* mySurf, const MetricFile* myMetric, MetricFile* myMetricOut, const MetricFile* corrAreaMetric) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int numNodes = mySurf->getNumberOfNodes(); if (myMetric->getNumberOfNodes() != numNodes) throw AlgorithmException("metric file has different number of nodes than the surface"); vector surfAreaData; const float* areaData = NULL; if (corrAreaMetric != NULL) { if (corrAreaMetric->getNumberOfNodes() != numNodes) throw AlgorithmException("corrected vertex area metric file has different number of nodes than the surface"); areaData = corrAreaMetric->getValuePointerForColumn(0); } else { mySurf->computeNodeAreas(surfAreaData); areaData = surfAreaData.data(); } int numCols = myMetric->getNumberOfColumns(); myMetricOut->setNumberOfNodesAndColumns(numNodes, numCols); myMetricOut->setStructure(myMetric->getStructure()); for (int col = 0; col < numCols; ++col) { vector > > areas; vector used(numNodes, 0); CaretPointer myHelp = mySurf->getTopologyHelper(); const float* roiData = myMetric->getValuePointerForColumn(col); myMetricOut->setColumnName(col, myMetric->getColumnName(col)); for (int i = 0; i < numNodes; ++i) { if (used[i] == 0 && !(roiData[i] > 0.0f))//use "not greater than" in case someone uses NaNs in their ROI { areas.push_back(make_pair(0.0f, vector())); vector& thisAreaMembers = areas.back().second; float& thisSurfArea = areas.back().first; thisAreaMembers.push_back(i); thisSurfArea += areaData[i]; used[i] = 1; vector mystack; mystack.push_back(i); while (!mystack.empty()) { int curnode = mystack.back(); mystack.pop_back(); const vector& neighbors = myHelp->getNodeNeighbors(curnode); int numNeigh = (int)neighbors.size(); for (int j = 0; j < numNeigh; ++j) { int thisneigh = neighbors[j]; if (used[thisneigh] == 0 && !(roiData[thisneigh] > 0.0f)) { used[thisneigh] = 1; thisAreaMembers.push_back(thisneigh); thisSurfArea += areaData[thisneigh]; mystack.push_back(thisneigh); } } } } } vector outscratch(numNodes, 1.0f); int numAreas = (int)areas.size(); if (numAreas > 0) { int bestIndex = 0; float bestArea = areas[0].first; for (int i = 1; i < numAreas; ++i) { float thisArea = (int)areas[i].first; if (thisArea > bestArea) { bestIndex = i; bestArea = thisArea; } } const vector& thisArea = areas[bestIndex].second; int numAreaNodes = (int)thisArea.size(); for (int i = 0; i < numAreaNodes; ++i) { outscratch[thisArea[i]] = 0.0f;//make it into a simple 0/1 metric, even if it wasn't before } } myMetricOut->setValuesForColumn(col, outscratch.data()); } } float AlgorithmMetricFillHoles::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmMetricFillHoles::getSubAlgorithmWeight() { return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricFillHoles.h000066400000000000000000000034111360521144700255770ustar00rootroot00000000000000#ifndef __ALGORITHM_METRIC_FILL_HOLES_H__ #define __ALGORITHM_METRIC_FILL_HOLES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmMetricFillHoles : public AbstractAlgorithm { AlgorithmMetricFillHoles(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmMetricFillHoles(ProgressObject* myProgObj, const SurfaceFile* mySurf, const MetricFile* myMetric, MetricFile* myMetricOut, const MetricFile* corrAreaMetric = NULL); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmMetricFillHoles; } #endif //__ALGORITHM_METRIC_FILL_HOLES_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricFindClusters.cxx000066400000000000000000000353471360521144700267130ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmMetricFindClusters.h" #include "AlgorithmException.h" #include "CaretLogger.h" #include "GeodesicHelper.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "TopologyHelper.h" #include using namespace caret; using namespace std; AString AlgorithmMetricFindClusters::getCommandSwitch() { return "-metric-find-clusters"; } AString AlgorithmMetricFindClusters::getShortDescription() { return "FILTER CLUSTERS BY SURFACE AREA"; } OperationParameters* AlgorithmMetricFindClusters::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to compute on"); ret->addMetricParameter(2, "metric-in", "the input metric"); ret->addDoubleParameter(3, "value-threshold", "threshold for data values"); ret->addDoubleParameter(4, "minimum-area", "threshold for cluster area, in mm^2"); ret->addMetricOutputParameter(5, "metric-out", "the output metric"); ret->createOptionalParameter(6, "-less-than", "find values less than , rather than greater"); OptionalParameter* roiOption = ret->createOptionalParameter(7, "-roi", "select a region of interest"); roiOption->addMetricParameter(1, "roi-metric", "the roi, as a metric"); OptionalParameter* corrAreasOpt = ret->createOptionalParameter(8, "-corrected-areas", "vertex areas to use instead of computing them from the surface"); corrAreasOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); OptionalParameter* columnSelect = ret->createOptionalParameter(9, "-column", "select a single column"); columnSelect->addStringParameter(1, "column", "the column number or name"); OptionalParameter* sizeRatioOpt = ret->createOptionalParameter(11, "-size-ratio", "ignore clusters smaller than a given fraction of the largest cluster in map"); sizeRatioOpt->addDoubleParameter(1, "ratio", "fraction of the largest cluster's area"); OptionalParameter* distanceOpt = ret->createOptionalParameter(12, "-distance", "ignore clusters further than a given distance from the largest cluster"); distanceOpt->addDoubleParameter(1, "distance", "how far from the largest cluster a cluster can be, edge to edge, in mm"); OptionalParameter* startOpt = ret->createOptionalParameter(10, "-start", "start labeling clusters from a value other than 1"); startOpt->addIntegerParameter(1, "startval", "the value to give the first cluster found"); ret->setHelpText( AString("Outputs a metric with nonzero integers for all vertices within a large enough cluster, and zeros elsewhere. ") + "The integers denote cluster membership (by default, first cluster found will use value 1, second cluster 2, etc). " + "Cluster values are not reused across maps of the output, but instead keep counting up. " + "By default, values greater than are considered to be in a cluster, use -less-than to test for values less than the threshold. " + "To apply this as a mask to the data, or to do more complicated thresholding, see -metric-math." ); return ret; } void AlgorithmMetricFindClusters::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* mySurf = myParams->getSurface(1); MetricFile* myMetric = myParams->getMetric(2); float threshVal = (float)myParams->getDouble(3); float minArea = (float)myParams->getDouble(4); MetricFile* myMetricOut = myParams->getOutputMetric(5); bool lessThan = myParams->getOptionalParameter(6)->m_present; MetricFile* myRoi = NULL; OptionalParameter* roiOption = myParams->getOptionalParameter(7); if (roiOption->m_present) { myRoi = roiOption->getMetric(1); } MetricFile* myAreas = NULL; OptionalParameter* corrAreasOpt = myParams->getOptionalParameter(8); if (corrAreasOpt->m_present) { myAreas = corrAreasOpt->getMetric(1); } OptionalParameter* columnSelect = myParams->getOptionalParameter(9); int columnNum = -1; if (columnSelect->m_present) {//set up to use the single column columnNum = (int)myMetric->getMapIndexFromNameOrNumber(columnSelect->getString(1)); if (columnNum < 0) { throw AlgorithmException("invalid column specified"); } } OptionalParameter* startOpt = myParams->getOptionalParameter(10); int startVal = 1; if (startOpt->m_present) { startVal = (int)startOpt->getInteger(1); } OptionalParameter* sizeRatioOpt = myParams->getOptionalParameter(11); float sizeRatio = -1.0f; if (sizeRatioOpt->m_present) { sizeRatio = sizeRatioOpt->getDouble(1); if (sizeRatio <= 0.0f) { throw AlgorithmException("area ratio must be positive"); } } OptionalParameter* distanceOpt = myParams->getOptionalParameter(12); float distanceCutoff = -1.0f; if (distanceOpt->m_present) { distanceCutoff = distanceOpt->getDouble(1); if (distanceCutoff <= 0.0f) { throw AlgorithmException("distance cutoff must be positive"); } } AlgorithmMetricFindClusters(myProgObj, mySurf, myMetric, threshVal, minArea, myMetricOut, lessThan, myRoi, myAreas, columnNum, startVal, NULL, sizeRatio, distanceCutoff); } namespace { struct Cluster { Cluster() { area = 0.0; } vector members; double area; }; void processColumn(const float* data, const float* roiData, const float* nodeAreas, TopologyHelper* myTopoHelp, GeodesicHelper* myGeoHelp, const float& threshVal, const float& minArea, const bool& lessThan, const float& areaRatio, const float& distanceCutoff, float* outData, int& markVal) { int numNodes = myTopoHelp->getNumberOfNodes(); vector marked(numNodes, 0); if (lessThan) { for (int i = 0; i < numNodes; ++i) { if ((roiData == NULL || roiData[i] > 0.0f) && data[i] < threshVal) { marked[i] = 1; } } } else { for (int i = 0; i < numNodes; ++i) { if ((roiData == NULL || roiData[i] > 0.0f) && data[i] > threshVal) { marked[i] = 1; } } } vector clusters; float biggestSize = 0.0f; int biggestCluster = -1; for (int i = 0; i < numNodes; ++i) { if (marked[i]) { Cluster newCluster; newCluster.members.push_back(i); marked[i] = 0;//unmark it when added to list to prevent multiples for (int index = 0; index < (int)newCluster.members.size(); ++index)//NOTE: vector grows inside loop { int node = newCluster.members[index];//keep list around so we can put it into the output immediately if it is large enough newCluster.area += nodeAreas[node]; const vector& neighbors = myTopoHelp->getNodeNeighbors(node); int numNeigh = (int)neighbors.size(); for (int n = 0; n < numNeigh; ++n) { const int32_t& neighbor = neighbors[n]; if (marked[neighbor]) { newCluster.members.push_back(neighbor); marked[neighbor] = 0; } } } if (newCluster.area > minArea) { if (newCluster.area > biggestSize) { biggestSize = newCluster.area; biggestCluster = (int)clusters.size(); } clusters.push_back(newCluster); } } } vector pathScratch; vector distScratch; if (!clusters.empty() && biggestCluster == -1) CaretLogWarning("clusters found, but none have positive area, check your vertex areas for negatives"); if (biggestCluster != -1 && (distanceCutoff > 0.0f || areaRatio > 0.0f)) { for (size_t i = 0; i < clusters.size(); ++i) { if ((int)i != biggestCluster) { bool erase = false; if (areaRatio > 0.0f) { if ((clusters[i].area / biggestSize) < areaRatio) { erase = true; } } if (!erase && distanceCutoff > 0.0f) { CaretAssert(myGeoHelp != NULL); myGeoHelp->getPathBetweenNodeLists(clusters[i].members, clusters[biggestCluster].members, distanceCutoff, pathScratch, distScratch, true); if (pathScratch.empty())//empty path means no path found { erase = true; } } if (erase) { clusters.erase(clusters.begin() + i);//remove it --i;//don't skip a cluster if (biggestCluster > (int)i) --biggestCluster;//don't lose track of the biggest cluster } } } } for (size_t i = 0; i < clusters.size(); ++i) { if (markVal == 0) { CaretLogInfo("skipping 0 for cluster marking"); ++markVal; } float tempVal = markVal; if ((int)tempVal != markVal) throw AlgorithmException("too many clusters, unable to mark them uniquely"); int numMembers = (int)clusters[i].members.size(); for (int index = 0; index < numMembers; ++index) { outData[clusters[i].members[index]] = tempVal; } ++markVal; } } } AlgorithmMetricFindClusters::AlgorithmMetricFindClusters(ProgressObject* myProgObj, const SurfaceFile* mySurf, const MetricFile* myMetric, const float& threshVal, const float& minArea, MetricFile* myMetricOut, const bool& lessThan, const MetricFile* myRoi, const MetricFile* myAreas, const int& columnNum, const int& startVal, int* endVal, const float& areaRatio, const float& distanceCutoff) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (startVal == 0) { throw AlgorithmException("0 is not a valid cluster marking start value"); } int numNodes = mySurf->getNumberOfNodes(); if (myMetric->getNumberOfNodes() != numNodes) throw AlgorithmException("metric does not match surface in number of vertices"); const float* roiData = NULL; if (myRoi != NULL) { if (myRoi->getNumberOfNodes() != numNodes) throw AlgorithmException("roi metric does not match surface in number of vertices"); roiData = myRoi->getValuePointerForColumn(0); } if (myAreas != NULL && myAreas->getNumberOfNodes() != mySurf->getNumberOfNodes()) { throw AlgorithmException("corrected area metric does not match surface in number of vertices"); } int numCols = myMetric->getNumberOfColumns(); if (columnNum < -1 || columnNum >= numCols) { throw AlgorithmException("invalid column number"); } vector nodeAreasVec; const float* nodeAreas = NULL; if (myAreas == NULL) { mySurf->computeNodeAreas(nodeAreasVec); nodeAreas = nodeAreasVec.data(); } else { nodeAreas = myAreas->getValuePointerForColumn(0); } CaretPointer myTopoHelp = mySurf->getTopologyHelper(); CaretPointer myGeoHelp; CaretPointer myGeoBase; if (distanceCutoff > 0.0f)//geodesic is only needed for distance cutoff { if (myAreas == NULL) { myGeoHelp = mySurf->getGeodesicHelper(); } else { myGeoBase.grabNew(new GeodesicHelperBase(mySurf, myAreas->getValuePointerForColumn(0))); myGeoHelp.grabNew(new GeodesicHelper(myGeoBase)); } } vector toSearch; int markVal = startVal;//give each cluster a different value, including across maps if (columnNum == -1) { myMetricOut->setNumberOfNodesAndColumns(numNodes, numCols); myMetricOut->setStructure(mySurf->getStructure()); for (int c = 0; c < numCols; ++c) { myMetricOut->setColumnName(c, myMetric->getColumnName(c)); vector outData(numNodes, 0.0f); const float* data = myMetric->getValuePointerForColumn(c); processColumn(data, roiData, nodeAreas, myTopoHelp, myGeoHelp, threshVal, minArea, lessThan, areaRatio, distanceCutoff, outData.data(), markVal); myMetricOut->setValuesForColumn(c, outData.data()); } } else { myMetricOut->setNumberOfNodesAndColumns(numNodes, 1); myMetricOut->setStructure(mySurf->getStructure()); myMetricOut->setColumnName(0, myMetric->getColumnName(columnNum)); vector outData(numNodes, 0.0f); const float* data = myMetric->getValuePointerForColumn(columnNum); processColumn(data, roiData, nodeAreas, myTopoHelp, myGeoHelp, threshVal, minArea, lessThan, areaRatio, distanceCutoff, outData.data(), markVal); myMetricOut->setValuesForColumn(0, outData.data()); } if (endVal != NULL) *endVal = markVal; } float AlgorithmMetricFindClusters::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmMetricFindClusters::getSubAlgorithmWeight() { return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricFindClusters.h000066400000000000000000000040671360521144700263330ustar00rootroot00000000000000#ifndef __ALGORITHM_METRIC_FIND_CLUSTERS_H__ #define __ALGORITHM_METRIC_FIND_CLUSTERS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmMetricFindClusters : public AbstractAlgorithm { AlgorithmMetricFindClusters(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmMetricFindClusters(ProgressObject* myProgObj, const SurfaceFile* mySurf, const MetricFile* myMetric, const float& minVal, const float& minArea, MetricFile* myMetricOut, const bool& lessThan = false, const MetricFile* myRoi = NULL, const MetricFile* myAreas = NULL, const int& columnNum = -1, const int& startVal = 1, int* endVal = NULL, const float& areaRatio = -1.0f, const float& distanceCutoff = -1.0f); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmMetricFindClusters; } #endif //__ALGORITHM_METRIC_FIND_CLUSTERS_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricGradient.cxx000066400000000000000000001036061360521144700260350ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AlgorithmMetricGradient.h" #include "AlgorithmMetricSmoothing.h" #include "AlgorithmException.h" #include "CaretOMP.h" #include "CaretLogger.h" #include "FloatMatrix.h" #include "MathFunctions.h" #include "MetricFile.h" #include "PaletteColorMapping.h" #include "SurfaceFile.h" #include "TopologyHelper.h" #include "Vector3D.h" #include using namespace caret; using namespace std; AString AlgorithmMetricGradient::getCommandSwitch() { return "-metric-gradient"; } AString AlgorithmMetricGradient::getShortDescription() { return "SURFACE GRADIENT OF A METRIC FILE"; } OperationParameters* AlgorithmMetricGradient::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to compute the gradient on"); ret->addMetricParameter(2, "metric-in", "the metric to compute the gradient of"); ret->addMetricOutputParameter(3, "metric-out", "the magnitude of the gradient"); OptionalParameter* presmooth = ret->createOptionalParameter(4, "-presmooth", "smooth the metric before computing the gradient"); presmooth->addDoubleParameter(1, "kernel", "the sigma for the gaussian smoothing kernel, in mm"); OptionalParameter* roiOption = ret->createOptionalParameter(5, "-roi", "select a region of interest to take the gradient of"); roiOption->addMetricParameter(1, "roi-metric", "the area to take the gradient within, as a metric"); roiOption->createOptionalParameter(2, "-match-columns", "for each input column, use the corresponding column from the roi"); OptionalParameter* vecOut = ret->createOptionalParameter(6, "-vectors", "output gradient vectors"); vecOut->addMetricOutputParameter(1, "vector-metric-out", "the vectors as a metric file"); OptionalParameter* columnSelect = ret->createOptionalParameter(7, "-column", "select a single column to compute the gradient of"); columnSelect->addStringParameter(1, "column", "the column number or name"); OptionalParameter* corrAreaOpt = ret->createOptionalParameter(8, "-corrected-areas", "vertex areas to use instead of computing them from the surface"); corrAreaOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); ret->createOptionalParameter(9, "-average-normals", "average the normals of each vertex with its neighbors before using them to compute the gradient"); //that option has no parameters to take, so don't store the return value ret->setHelpText( AString("At each vertex, the immediate neighbors are unfolded onto a plane tangent to the surface at the vertex (specifically, perpendicular to the normal). ") + "The gradient is computed using a regression between the unfolded positions of the vertices and their values. " + "The gradient is then given by the slopes of the regression, and reconstructed as a 3D gradient vector. " + "By default, takes the gradient of all columns, with no presmoothing, across the whole surface, without averaging the normals of the surface among neighbors.\n\n" + "When using -corrected-areas, note that it is an approximate correction. " + "Doing smoothing on individual surfaces before averaging/gradient is preferred, when possible, in order to make use of the original surface structure.\n\n" + "Specifying an ROI will restrict the gradient to only use data from where the ROI metric is positive, and output zeros anywhere the ROI metric is not positive.\n\n" + "By default, the first column of the roi metric is used for all input columns. " + "When -match-columns is specified to the -roi option, the input and roi metrics must have the same number of columns, " + "and for each input column's index, the same column index is used in the roi metric. " + "If the -match-columns option to -roi is used while the -column option is also used, the number of columns of the roi metric must match the input metric, " + "and it will use the roi column with the index of the selected input column.\n\n" + "The vector output metric is organized such that the X, Y, and Z components from a single input column are consecutive columns." ); return ret; } void AlgorithmMetricGradient::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* mySurf = myParams->getSurface(1); MetricFile* myMetricIn = myParams->getMetric(2); MetricFile* myMetricOut = myParams->getOutputMetric(3); float myPresmooth = -1.0f;//negative or zero means no smoothing OptionalParameter* presmooth = myParams->getOptionalParameter(4); if (presmooth->m_present) { myPresmooth = (float)presmooth->getDouble(1); if (myPresmooth <= 0.0f) throw AlgorithmException("presmooth kernel size must be positive"); } MetricFile* myRoi = NULL; bool matchRoiColumns = false; OptionalParameter* roiOption = myParams->getOptionalParameter(5); if (roiOption->m_present) { myRoi = roiOption->getMetric(1); matchRoiColumns = roiOption->getOptionalParameter(2)->m_present; } MetricFile* myVectorsOut = NULL; OptionalParameter* vecOut = myParams->getOptionalParameter(6); if (vecOut->m_present) { myVectorsOut = vecOut->getOutputMetric(1); } int32_t myColumn = -1; OptionalParameter* columnSelect = myParams->getOptionalParameter(7); if (columnSelect->m_present) { myColumn = (int)myMetricIn->getMapIndexFromNameOrNumber(columnSelect->getString(1)); if (myColumn < 0) { throw AlgorithmException("invalid column specified"); } } MetricFile* corrAreaMetric = NULL; OptionalParameter* corrAreaOpt = myParams->getOptionalParameter(8); if (corrAreaOpt->m_present) { corrAreaMetric = corrAreaOpt->getMetric(1); } OptionalParameter* avgNormals = myParams->getOptionalParameter(9); bool myAvgNormals = avgNormals->m_present; AlgorithmMetricGradient(myProgObj, mySurf, myMetricIn, myMetricOut, myVectorsOut, myPresmooth, myRoi, myAvgNormals, myColumn, corrAreaMetric, matchRoiColumns);//executes the algorithm } AlgorithmMetricGradient::AlgorithmMetricGradient(ProgressObject* myProgObj, SurfaceFile* mySurf, const MetricFile* myMetricIn, MetricFile* myMetricOut, MetricFile* myVectorsOut, const float myPresmooth, const MetricFile* myRoi, const bool myAvgNormals, const int32_t myColumn, const MetricFile* corrAreaMetric, const bool matchRoiColumns) : AbstractAlgorithm(myProgObj) { ProgressObject* smoothProgress = NULL; if (myProgObj != NULL && myPresmooth > 0.0f) { smoothProgress = myProgObj->addAlgorithm(AlgorithmMetricSmoothing::getAlgorithmWeight()); } LevelProgress myProgress(myProgObj); int32_t numNodes = mySurf->getNumberOfNodes(); if (myMetricIn->getNumberOfNodes() != numNodes) {//TODO: write these as static functions into an AlgorithmHelper class? throw AlgorithmException("metric does not match surface in number of vertices"); } if (myRoi != NULL && myRoi->getNumberOfNodes() != numNodes) { throw AlgorithmException("roi metric does not match surface in number of vertices"); } if (corrAreaMetric != NULL && corrAreaMetric->getNumberOfNodes() != numNodes) { throw AlgorithmException("corrected areas metric does not match surface in number of vertices"); } int32_t numColumns = myMetricIn->getNumberOfColumns(); if (myColumn < -1 || myColumn >= numColumns) { throw AlgorithmException("invalid column number"); } if (myRoi != NULL && matchRoiColumns && numColumns != myRoi->getNumberOfColumns()) { throw AlgorithmException("match roi columns specified, but roi metric has the wrong number of columns"); } const MetricFile* toProcess = myMetricIn; MetricFile processTemp; int32_t useColumn = myColumn; if (myPresmooth > 0.0f) { AlgorithmMetricSmoothing(smoothProgress, mySurf, myMetricIn, myPresmooth, &processTemp, myRoi, matchRoiColumns, false, myColumn, corrAreaMetric, MetricSmoothingObject::GEO_GAUSS_AREA); toProcess = &processTemp; if (myColumn != -1) { useColumn = 0; } } const float* myNormals = NULL; vector avgNormalStorage; if (myAvgNormals) { avgNormalStorage = mySurf->computeAverageNormals(); myNormals = avgNormalStorage.data(); } else { mySurf->computeNormals(); myNormals = mySurf->getNormalData(); } vector sqrtCorrAreas;//same logic as GeodesicHelper vector sqrtVertAreas; const float* vertAreas = NULL; vector areaData; if (corrAreaMetric != NULL) { sqrtCorrAreas.resize(numNodes); mySurf->computeNodeAreas(sqrtVertAreas); const float* corrAreaData = corrAreaMetric->getValuePointerForColumn(0); for (int i = 0; i < numNodes; ++i) { sqrtCorrAreas[i] = sqrt(corrAreaData[i]); sqrtVertAreas[i] = sqrt(sqrtVertAreas[i]); } vertAreas = corrAreaData; } else { mySurf->computeNodeAreas(areaData); vertAreas = areaData.data(); } const float* myCoords = mySurf->getCoordinateData(); bool haveWarned = false, haveFailed = false;//print warning or failure messages only once if (myColumn == -1) { myMetricOut->setNumberOfNodesAndColumns(numNodes, numColumns); myMetricOut->setStructure(mySurf->getStructure()); float* myVecScratch = NULL; if (myVectorsOut != NULL) { myVectorsOut->setNumberOfNodesAndColumns(numNodes, numColumns * 3); myVectorsOut->setStructure(mySurf->getStructure()); myVecScratch = new float[numNodes * 3]; } float* myScratch = new float[numNodes]; for (int32_t col = 0; col < numColumns; ++col) { const float* myRoiColumn = NULL; if (myRoi != NULL) { if (matchRoiColumns) { myRoiColumn = myRoi->getValuePointerForColumn(col); } else { myRoiColumn = myRoi->getValuePointerForColumn(0); } } const float* myMetricColumn = toProcess->getValuePointerForColumn(col); myMetricOut->setColumnName(col, toProcess->getColumnName(col) + ", gradient"); *(myMetricOut->getPaletteColorMapping(col)) = *(toProcess->getPaletteColorMapping(col));//copy the palette settings if (myVectorsOut != NULL) { myVectorsOut->setColumnName(col * 3, toProcess->getColumnName(col) + ", gradient vector X"); myVectorsOut->setColumnName(col * 3 + 1, toProcess->getColumnName(col) + ", gradient vector Y"); myVectorsOut->setColumnName(col * 3 + 2, toProcess->getColumnName(col) + ", gradient vector Z"); } #pragma omp CARET_PAR { Vector3D somevec, xhat, yhat; float sanity = 0.0f; CaretPointer myTopoHelp = mySurf->getTopologyHelper();//this stores and reuses helpers, so it isn't really a problem to call inside the loop #pragma omp CARET_FOR schedule(dynamic) for (int32_t i = 0; i < numNodes; ++i) { if (myRoiColumn != NULL && myRoiColumn[i] <= 0.0f) { myScratch[i] = 0.0f; if (myVecScratch != NULL) { myVecScratch[i] = 0.0f; myVecScratch[i + numNodes] = 0.0f; myVecScratch[i + numNodes * 2] = 0.0f; } continue; } int32_t numNeigh; int32_t i3 = i * 3; const int32_t* myNeighbors = myTopoHelp->getNodeNeighbors(i, numNeigh);//one function call isn't that bad, most time spent is floating point math anyway Vector3D myNormal = Vector3D(myNormals + i3).normal();//should already be normalized, but just in case Vector3D myCoord = myCoords + i3; float nodeValue = myMetricColumn[i]; somevec[2] = 0.0; if (abs(myNormal[0]) > abs(myNormal[1])) {//generate a vector not parallel to normal somevec[0] = 0.0; somevec[1] = 1.0; } else { somevec[0] = 1.0; somevec[1] = 0.0; } xhat = myNormal.cross(somevec).normal(); yhat = myNormal.cross(xhat).normal();//xhat, yhat are orthogonal unit vectors describing a coord system with k = surface normal int neighCount = 0;//count within-roi neighbors, not simply surface neighbors if (numNeigh >= 2) { FloatMatrix myRegress = FloatMatrix::zeros(3, 4); for (int32_t j = 0; j < numNeigh; ++j) { int32_t whichNode = myNeighbors[j]; int32_t whichNode3 = whichNode * 3; if (myRoiColumn == NULL || myRoiColumn[whichNode] > 0.0f) { ++neighCount; float tempf = myMetricColumn[whichNode] - nodeValue; Vector3D neighCoord = myCoords + whichNode3; somevec = neighCoord - myCoord; float origMag = somevec.length();//save the original length float unrollMag = origMag; float opposite = somevec.dot(myNormal);//check for division by close to zero if (abs(opposite) > 0.035f * origMag)//do not do unrolling on very small angles - this is ~2 degrees { unrollMag = origMag * asin(opposite / origMag) * origMag / opposite; } if (corrAreaMetric != NULL) { unrollMag *= (sqrtCorrAreas[i] + sqrtCorrAreas[whichNode]) / (sqrtVertAreas[i] + sqrtVertAreas[whichNode]); } float xmag = xhat.dot(somevec);//dot product to get the direction in 2d float ymag = yhat.dot(somevec); float mag2d = sqrt(xmag * xmag + ymag * ymag);//get the new magnitude, to divide out xmag *= unrollMag / mag2d;//normalize the 2d vector and multiply by unrolled length ymag *= unrollMag / mag2d; myRegress[0][0] += xmag * xmag * vertAreas[whichNode];//gather A'A and A'b sums for regression, weighted by vertex area myRegress[0][1] += xmag * ymag * vertAreas[whichNode]; myRegress[0][2] += xmag * vertAreas[whichNode]; myRegress[1][1] += ymag * ymag * vertAreas[whichNode]; myRegress[1][2] += ymag * vertAreas[whichNode]; myRegress[2][2] += vertAreas[whichNode]; myRegress[0][3] += xmag * tempf * vertAreas[whichNode]; myRegress[1][3] += ymag * tempf * vertAreas[whichNode]; myRegress[2][3] += tempf * vertAreas[whichNode]; } } if (neighCount >= 2) { myRegress[1][0] = myRegress[0][1];//complete the symmetric elements myRegress[2][0] = myRegress[0][2]; myRegress[2][1] = myRegress[1][2]; myRegress[2][2] += vertAreas[i];//include center (metric and coord differences will be zero, so this is all that is needed) FloatMatrix myRref = myRegress.reducedRowEchelon(); somevec = xhat * myRref[0][3] + yhat * myRref[1][3];//somevec is now our surface gradient sanity = somevec[0] + somevec[1] + somevec[2]; } } if (neighCount > 0 && (neighCount < 2 || sanity != sanity)) { if (!haveWarned && myRoi == NULL) {//don't issue this warning with an ROI, because it is somewhat expected haveWarned = true; CaretLogWarning("WARNING: gradient calculation found a NaN/inf with regression method for at least vertex " + AString::number(i)); } float xgrad = 0.0f, ygrad = 0.0f, totalWeight = 0.0f; for (int32_t j = 0; j < numNeigh; ++j) { int32_t whichNode = myNeighbors[j]; int32_t whichNode3 = whichNode * 3; if (myRoiColumn == NULL || myRoiColumn[whichNode] > 0.0f) { float tempf = myMetricColumn[whichNode] - nodeValue; Vector3D neighCoord = myCoords + whichNode3; somevec = neighCoord - myCoord; float origMag = somevec.length();//save the original length float unrollMag = origMag; float opposite = somevec.dot(myNormal);//check for division by close to zero if (abs(opposite) > 0.035f * origMag)//do not do unrolling on very small angles - this is ~2 degrees { unrollMag = origMag * asin(opposite / origMag) * origMag / opposite; } if (corrAreaMetric != NULL) { unrollMag *= (sqrtCorrAreas[i] + sqrtCorrAreas[whichNode]) / (sqrtVertAreas[i] + sqrtVertAreas[whichNode]); } float xmag = xhat.dot(somevec);//dot product to get the direction in 2d float ymag = yhat.dot(somevec); float mag2d = sqrt(xmag * xmag + ymag * ymag);//get the new magnitude, to divide out tempf /= unrollMag * mag2d;//difference divided by distance gives point estimate of gradient magnitude, also divide by magnitude of 2d vector to normalize the next step at the same time xgrad += xmag * tempf * vertAreas[whichNode];//point estimate of gradient magnitude times normalized projected direction gives 2d estimate of gradient ygrad += ymag * tempf * vertAreas[whichNode];//average point estimates for each neighbor to estimate local gradient totalWeight += vertAreas[whichNode]; } } xgrad /= totalWeight;//weighted average ygrad /= totalWeight; somevec = xhat * xgrad + yhat * ygrad;//unproject back into 3d sanity = somevec[0] + somevec[1] + somevec[2]; } if (neighCount <= 0 || sanity != sanity) { if (!haveFailed && myRoiColumn == NULL) {//don't warn with an roi, they can be strange haveFailed = true; CaretLogWarning("Failed to compute gradient for at least vertex " + AString::number(i) + " with standard and fallback methods, outputting ZERO, check your surface for disconnected vertices or other strangeness"); } somevec[0] = 0.0f; somevec[1] = 0.0f; somevec[2] = 0.0f; } if (myVecScratch != NULL) { myVecScratch[i] = somevec[0];//split them up far, so that they can be set to columns easily myVecScratch[numNodes + i] = somevec[1]; myVecScratch[numNodes * 2 + i] = somevec[2]; } myScratch[i] = MathFunctions::vectorLength(somevec); } } if (myVectorsOut != NULL) { myVectorsOut->setValuesForColumn(col * 3, myVecScratch); myVectorsOut->setValuesForColumn(col * 3 + 1, myVecScratch + numNodes); myVectorsOut->setValuesForColumn(col * 3 + 2, myVecScratch + (numNodes * 2)); } myMetricOut->setValuesForColumn(col, myScratch); myProgress.reportProgress(((float)col + 1) / numColumns); } delete[] myScratch; if (myVecScratch != NULL) { delete[] myVecScratch; } } else { myMetricOut->setNumberOfNodesAndColumns(numNodes, 1); myMetricOut->setStructure(mySurf->getStructure()); float* myVecScratch = NULL; if (myVectorsOut != NULL) { myVectorsOut->setNumberOfNodesAndColumns(numNodes, 3); myVectorsOut->setStructure(mySurf->getStructure()); myVectorsOut->setColumnName(0, toProcess->getColumnName(useColumn) + ", gradient vector X"); myVectorsOut->setColumnName(1, toProcess->getColumnName(useColumn) + ", gradient vector Y"); myVectorsOut->setColumnName(2, toProcess->getColumnName(useColumn) + ", gradient vector Z"); myVecScratch = new float[numNodes * 3]; } float* myScratch = new float[numNodes]; const float* myRoiColumn = NULL; if (myRoi != NULL) { if (matchRoiColumns) { myRoiColumn = myRoi->getValuePointerForColumn(myColumn);//use the ORIGINAL column number, not the one that has been modified due to a presmoothing step that generated a new single column metric } else { myRoiColumn = myRoi->getValuePointerForColumn(0); } } const float* myMetricColumn = toProcess->getValuePointerForColumn(useColumn); myMetricOut->setColumnName(0, toProcess->getColumnName(useColumn) + ", gradient"); *(myMetricOut->getPaletteColorMapping(0)) = *(toProcess->getPaletteColorMapping(useColumn));//copy the palette settings #pragma omp CARET_PAR { Vector3D somevec, xhat, yhat; float sanity = 0.0f; CaretPointer myTopoHelp = mySurf->getTopologyHelper(); #pragma omp CARET_FOR schedule(dynamic) for (int32_t i = 0; i < numNodes; ++i) { if (myRoiColumn != NULL && myRoiColumn[i] <= 0.0f) { myScratch[i] = 0.0f; if (myVecScratch != NULL) { myVecScratch[i] = 0.0f; myVecScratch[i + numNodes] = 0.0f; myVecScratch[i + numNodes * 2] = 0.0f; } continue; } int32_t numNeigh; int32_t i3 = i * 3; const int32_t* myNeighbors = myTopoHelp->getNodeNeighbors(i, numNeigh); Vector3D myNormal = Vector3D(myNormals + i3).normal();//should already be normalized, but just in case Vector3D myCoord = myCoords + i3; float nodeValue = myMetricColumn[i]; somevec[2] = 0.0; if (myNormal[0] > myNormal[1]) {//generate a vector not parallel to normal somevec[0] = 0.0; somevec[1] = 1.0; } else { somevec[0] = 1.0; somevec[1] = 0.0; } xhat = myNormal.cross(somevec).normal(); yhat = myNormal.cross(xhat).normal();//xhat, yhat are orthogonal unit vectors describing a coord system with k = surface normal int neighCount = 0;//count within-roi neighbors, not simply surface neighbors if (numNeigh >= 2) { FloatMatrix myRegress = FloatMatrix::zeros(3, 4); for (int32_t j = 0; j < numNeigh; ++j) { int32_t whichNode = myNeighbors[j]; int32_t whichNode3 = whichNode * 3; if (myRoiColumn == NULL || myRoiColumn[whichNode] > 0.0f) { ++neighCount; float tempf = myMetricColumn[whichNode] - nodeValue; Vector3D neighCoord = myCoords + whichNode3; somevec = neighCoord - myCoord; float origMag = somevec.length();//save the original length float unrollMag = origMag; float opposite = somevec.dot(myNormal);//check for division by close to zero if (abs(opposite) > 0.035f * origMag)//do not do unrolling on very small angles - this is ~2 degrees { unrollMag = origMag * asin(opposite / origMag) * origMag / opposite; } if (corrAreaMetric != NULL) { unrollMag *= (sqrtCorrAreas[i] + sqrtCorrAreas[whichNode]) / (sqrtVertAreas[i] + sqrtVertAreas[whichNode]); } float xmag = xhat.dot(somevec);//dot product to get the direction in 2d float ymag = yhat.dot(somevec); float mag2d = sqrt(xmag * xmag + ymag * ymag);//get the new magnitude, to divide out xmag *= unrollMag / mag2d;//normalize the 2d vector and multiply by unrolled length ymag *= unrollMag / mag2d; myRegress[0][0] += xmag * xmag * vertAreas[whichNode];//gather A'A and A'b sums for regression, weighted by vertex area myRegress[0][1] += xmag * ymag * vertAreas[whichNode]; myRegress[0][2] += xmag * vertAreas[whichNode]; myRegress[1][1] += ymag * ymag * vertAreas[whichNode]; myRegress[1][2] += ymag * vertAreas[whichNode]; myRegress[2][2] += vertAreas[whichNode]; myRegress[0][3] += xmag * tempf * vertAreas[whichNode]; myRegress[1][3] += ymag * tempf * vertAreas[whichNode]; myRegress[2][3] += tempf * vertAreas[whichNode]; } } if (neighCount >= 2) { myRegress[1][0] = myRegress[0][1];//complete the symmetric elements myRegress[2][0] = myRegress[0][2]; myRegress[2][1] = myRegress[1][2]; myRegress[2][2] += vertAreas[i];//include center (metric and coord differences will be zero, so this is all that is needed) FloatMatrix myRref = myRegress.reducedRowEchelon(); somevec = xhat * myRref[0][3] + yhat * myRref[1][3];//somevec is now our surface gradient sanity = somevec[0] + somevec[1] + somevec[2]; } } if (neighCount > 0 && (neighCount < 2 || sanity != sanity)) { if (!haveWarned && myRoi == NULL) {//don't issue this warning with an ROI, because it is somewhat expected haveWarned = true; CaretLogWarning("WARNING: gradient calculation found a NaN/inf with regression method for at least vertex " + AString::number(i)); } float xgrad = 0.0f, ygrad = 0.0f, totalWeight = 0.0f; for (int32_t j = 0; j < numNeigh; ++j) { int32_t whichNode = myNeighbors[j]; int32_t whichNode3 = whichNode * 3; if (myRoiColumn == NULL || myRoiColumn[whichNode] > 0.0f) { float tempf = myMetricColumn[whichNode] - nodeValue; Vector3D neighCoord = myCoords + whichNode3; somevec = neighCoord - myCoord; float origMag = somevec.length();//save the original length float unrollMag = origMag; float opposite = somevec.dot(myNormal);//check for division by close to zero if (abs(opposite) > 0.035f * origMag)//do not do unrolling on very small angles - this is ~2 degrees { unrollMag = origMag * asin(opposite / origMag) * origMag / opposite; } if (corrAreaMetric != NULL) { unrollMag *= (sqrtCorrAreas[i] + sqrtCorrAreas[whichNode]) / (sqrtVertAreas[i] + sqrtVertAreas[whichNode]); } float xmag = xhat.dot(somevec);//dot product to get the direction in 2d float ymag = yhat.dot(somevec); float mag2d = sqrt(xmag * xmag + ymag * ymag);//get the new magnitude, to divide out tempf /= unrollMag * mag2d;//difference divided by distance gives point estimate of gradient magnitude, also divide by magnitude of 2d vector to normalize the next step at the same time xgrad += xmag * tempf * vertAreas[whichNode];//point estimate of gradient magnitude times normalized projected direction gives 2d estimate of gradient ygrad += ymag * tempf * vertAreas[whichNode];//average point estimates for each neighbor to estimate local gradient totalWeight += vertAreas[whichNode]; } } xgrad /= totalWeight;//weighted average ygrad /= totalWeight; somevec = xhat * xgrad + yhat * ygrad;//unproject back into 3d sanity = somevec[0] + somevec[1] + somevec[2]; } if (neighCount <= 0 || sanity != sanity) { if (!haveFailed && myRoiColumn == NULL) {//don't warn with an roi, they can be strange haveFailed = true; CaretLogWarning("Failed to compute gradient for at least vertex " + AString::number(i) + " with standard and fallback methods, outputting ZERO, check your surface for disconnected vertices or other strangeness"); } somevec[0] = 0.0f; somevec[1] = 0.0f; somevec[2] = 0.0f; } if (myVecScratch != NULL) { myVecScratch[i] = somevec[0];//split them up far, so that they can be set to columns easily myVecScratch[numNodes + i] = somevec[1]; myVecScratch[numNodes * 2 + i] = somevec[2]; } myScratch[i] = MathFunctions::vectorLength(somevec); } } if (myVectorsOut != NULL) { myVectorsOut->setValuesForColumn(0, myVecScratch); myVectorsOut->setValuesForColumn(1, myVecScratch + numNodes); myVectorsOut->setValuesForColumn(2, myVecScratch + (numNodes * 2)); } myMetricOut->setValuesForColumn(0, myScratch); delete[] myScratch; if (myVecScratch != NULL) { delete[] myVecScratch; } } } float AlgorithmMetricGradient::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmMetricGradient::getSubAlgorithmWeight() { return AlgorithmMetricSmoothing::getAlgorithmWeight();//if you use a subalgorithm } connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricGradient.h000066400000000000000000000043271360521144700254620ustar00rootroot00000000000000#ifndef __ALGORITHM_METRIC_GRADIENT_H__ #define __ALGORITHM_METRIC_GRADIENT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmMetricGradient : public AbstractAlgorithm { AlgorithmMetricGradient(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmMetricGradient(ProgressObject* myProgObj, SurfaceFile* mySurf, const MetricFile* myMetricIn, MetricFile* myMetricOut, MetricFile* myVectorsOut = NULL, const float myPresmooth = -1.0f, const MetricFile* myRoi = NULL, const bool myAvgNormals = false, const int32_t myColumn = -1, const MetricFile* corrAreaMetric = NULL, bool matchRoiColumns = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmMetricGradient; } #endif //__ALGORITHM_METRIC_GRADIENT_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricROIsFromExtrema.cxx000066400000000000000000000344351360521144700272710ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmMetricROIsFromExtrema.h" #include "AlgorithmException.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "GeodesicHelper.h" #include "MetricFile.h" #include "SurfaceFile.h" #include using namespace caret; using namespace std; AString AlgorithmMetricROIsFromExtrema::getCommandSwitch() { return "-metric-rois-from-extrema"; } AString AlgorithmMetricROIsFromExtrema::getShortDescription() { return "CREATE METRIC ROI MAPS FROM EXTREMA MAPS"; } OperationParameters* AlgorithmMetricROIsFromExtrema::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to use for geodesic distance"); ret->addMetricParameter(2, "metric", "the input metric file"); ret->addDoubleParameter(3, "limit", "geodesic distance limit from vertex, in mm"); ret->addMetricOutputParameter(4, "metric-out", "the output metric file"); OptionalParameter* gaussOpt = ret->createOptionalParameter(5, "-gaussian", "generate a gaussian kernel instead of a flat ROI"); gaussOpt->addDoubleParameter(1, "sigma", "the sigma for the gaussian kernel, in mm"); OptionalParameter* roiOption = ret->createOptionalParameter(6, "-roi", "select a region of interest to use"); roiOption->addMetricParameter(1, "roi-metric", "the area to use, as a metric"); OptionalParameter* overlapOpt = ret->createOptionalParameter(7, "-overlap-logic", "how to handle overlapping ROIs, default ALLOW"); overlapOpt->addStringParameter(1, "method", "the method of resolving overlaps"); OptionalParameter* columnSelect = ret->createOptionalParameter(8, "-column", "select a single input column to use"); columnSelect->addStringParameter(1, "column", "the column number or name"); ret->setHelpText( AString("For each nonzero value in each map, make a map with an ROI around that location. ") + "If the -gaussian option is specified, then normalized gaussian kernels are output instead of ROIs. " + "The argument to -overlap-logic must be one of ALLOW, CLOSEST, or EXCLUDE. " + "ALLOW is the default, and means that ROIs are treated independently and may overlap. " + "CLOSEST means that ROIs may not overlap, and that no ROI contains vertices that are closer to a different seed vertex. " + "EXCLUDE means that ROIs may not overlap, and that any vertex within range of more than one ROI does not belong to any ROI." ); return ret; } void AlgorithmMetricROIsFromExtrema::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* mySurf = myParams->getSurface(1); MetricFile* myMetric = myParams->getMetric(2); float limit = (float)myParams->getDouble(3); MetricFile* myMetricOut = myParams->getOutputMetric(4); OptionalParameter* gaussOpt = myParams->getOptionalParameter(5); float sigma = -1.0f; if (gaussOpt->m_present) {//set up to use a gaussian function sigma = (float)gaussOpt->getDouble(1); if (sigma <= 0.0f) { throw AlgorithmException("invalid sigma specified"); } } MetricFile* myRoi = NULL; OptionalParameter* roiOption = myParams->getOptionalParameter(6); if (roiOption->m_present) { myRoi = roiOption->getMetric(1); } OverlapLogicEnum::Enum overlapType = OverlapLogicEnum::ALLOW; OptionalParameter* overlapOpt = myParams->getOptionalParameter(7); if (overlapOpt->m_present) { bool ok = false; overlapType = OverlapLogicEnum::fromName(overlapOpt->getString(1), &ok); if (!ok) throw AlgorithmException("unrecognized overlap method: " + overlapOpt->getString(1)); } int myColumn = -1; OptionalParameter* columnSelect = myParams->getOptionalParameter(8); if (columnSelect->m_present) { myColumn = (int)myMetric->getMapIndexFromNameOrNumber(columnSelect->getString(1)); if (myColumn < 0) { throw AlgorithmException("invalid column specified"); } } AlgorithmMetricROIsFromExtrema(myProgObj, mySurf, myMetric, limit, myMetricOut, sigma, myRoi, overlapType, myColumn); } AlgorithmMetricROIsFromExtrema::AlgorithmMetricROIsFromExtrema(ProgressObject* myProgObj, const SurfaceFile* mySurf, const MetricFile* myMetric, const float& limit, MetricFile* myMetricOut, const float& sigma, const MetricFile* myRoi, const OverlapLogicEnum::Enum& overlapType, const int& myColumn) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int numNodes = mySurf->getNumberOfNodes(); if (myMetric->getNumberOfNodes() != numNodes) throw AlgorithmException("surface and metric files have different number of nodes"); const float* roiData = NULL; if (myRoi != NULL) { if (myRoi->getNumberOfNodes() != numNodes) throw AlgorithmException("roi metric has a different number of nodes"); roiData = myRoi->getValuePointerForColumn(0); } int numCols = myMetric->getNumberOfColumns(); if (myColumn < -1 || myColumn >= numCols) { throw AlgorithmException("invalid column number"); } int64_t extremaCount = 0; if (myColumn == -1) { if (roiData == NULL) { for (int i = 0; i < numCols; ++i) { const float* data = myMetric->getValuePointerForColumn(i); for (int j = 0; j < numNodes; ++j) { if (data[j] != 0.0f) ++extremaCount; } } } else { for (int i = 0; i < numCols; ++i) { const float* data = myMetric->getValuePointerForColumn(i); for (int j = 0; j < numNodes; ++j) { if (roiData[j] > 0.0f && data[j] != 0.0f) ++extremaCount; } } } } else { if (roiData == NULL) { const float* data = myMetric->getValuePointerForColumn(0); for (int j = 0; j < numNodes; ++j) { if (data[j] != 0.0f) ++extremaCount; } } else { const float* data = myMetric->getValuePointerForColumn(0); for (int j = 0; j < numNodes; ++j) { if (roiData[j] > 0.0f && data[j] != 0.0f) ++extremaCount; } } } if (extremaCount == 0) CaretLogWarning("no nonzero values in input metric file, output file will be empty");//if this were an error, the cifti version will error when just one component is zeros if (extremaCount >= (1LL<<31)) throw AlgorithmException("too many output maps for a metric file");//hopefully this is never needed int32_t mapsOut = (int32_t)extremaCount; vector excludeDists(numNodes, -1.0f); vector excludeSources(numNodes, -1); vector > roiLists(mapsOut); CaretPointer myHelp = mySurf->getGeodesicHelper(); int64_t mapCounter = 0; if (myColumn == -1) { for (int i = 0; i < numCols; ++i) { const float* data = myMetric->getValuePointerForColumn(i); processMap(data, excludeDists, excludeSources, roiLists, mapCounter, myHelp, limit, roiData, overlapType, numNodes); } } else { const float* data = myMetric->getValuePointerForColumn(0); processMap(data, excludeDists, excludeSources, roiLists, mapCounter, myHelp, limit, roiData, overlapType, numNodes); } CaretAssert(mapCounter == extremaCount); myMetricOut->setNumberOfNodesAndColumns(numNodes, mapsOut); myMetricOut->setStructure(mySurf->getStructure()); vector tempCol(numNodes, 0.0f); if (sigma > 0.0f) { float gaussDenom = -0.5f / sigma / sigma; for (int32_t i = 0; i < mapsOut; ++i) { double accum = 0.0; map::iterator myEnd = roiLists[i].end(); for (map::iterator iter = roiLists[i].begin(); iter != myEnd; ++iter) { float gaussVal = exp(iter->second * iter->second * gaussDenom); accum += gaussVal; tempCol[iter->first] = gaussVal;//initial kernel value } for (map::iterator iter = roiLists[i].begin(); iter != myEnd; ++iter) { tempCol[iter->first] /= accum;//normalize } myMetricOut->setValuesForColumn(i, tempCol.data()); for (map::iterator iter = roiLists[i].begin(); iter != myEnd; ++iter) { tempCol[iter->first] = 0.0f;//rezero changed values for next map } } } else { for (int32_t i = 0; i < mapsOut; ++i) { map::iterator myEnd = roiLists[i].end(); for (map::iterator iter = roiLists[i].begin(); iter != myEnd; ++iter) { tempCol[iter->first] = 1.0f;//make roi } myMetricOut->setValuesForColumn(i, tempCol.data()); for (map::iterator iter = roiLists[i].begin(); iter != myEnd; ++iter) { tempCol[iter->first] = 0.0f;//rezero changed values for next map } } } } void AlgorithmMetricROIsFromExtrema::processMap(const float* data, vector& excludeDists, vector excludeSources, vector >& roiLists, int64_t& mapCounter, CaretPointer& myHelp, const float& limit, const float* roiData, const OverlapLogicEnum::Enum& overlapType, const int& numNodes) { for (int j = 0; j < numNodes; ++j) { if ((roiData == NULL || roiData[j] > 0.0f) && data[j] != 0.0f) { vector nodeList; vector distList; myHelp->getNodesToGeoDist(j, limit, nodeList, distList); int listNum = (int)nodeList.size(); switch (overlapType) { case OverlapLogicEnum::ALLOW: if (roiData == NULL) { for (int k = 0; k < listNum; ++k) { const int32_t& thisNode = nodeList[k]; roiLists[mapCounter][thisNode] = distList[k]; } } else { for (int k = 0; k < listNum; ++k) { const int32_t& thisNode = nodeList[k]; if (roiData[thisNode] > 0.0f) { roiLists[mapCounter][thisNode] = distList[k]; } } } break; case OverlapLogicEnum::CLOSEST: for (int k = 0; k < listNum; ++k) { const int32_t& thisNode = nodeList[k]; if (roiData == NULL || roiData[thisNode] > 0.0f) { const float& thisDist = distList[k]; if (excludeDists[thisNode] < 0.0f) { excludeDists[thisNode] = thisDist; excludeSources[thisNode] = mapCounter; roiLists[mapCounter][thisNode] = thisDist; } else { if (excludeDists[thisNode] > thisDist) { roiLists[excludeSources[thisNode]].erase(thisNode); } excludeDists[thisNode] = thisDist; excludeSources[thisNode] = mapCounter; roiLists[mapCounter][thisNode] = thisDist; } } } break; case OverlapLogicEnum::EXCLUDE: for (int k = 0; k < listNum; ++k) { const int32_t& thisNode = nodeList[k]; if (roiData == NULL || roiData[thisNode] > 0.0f) { const float& thisDist = distList[k]; if (excludeDists[thisNode] < 0.0f) { excludeDists[thisNode] = thisDist; excludeSources[thisNode] = mapCounter; roiLists[mapCounter][thisNode] = thisDist; } else { if (excludeSources[thisNode] != -1) { roiLists[excludeSources[thisNode]].erase(thisNode); excludeSources[thisNode] = -1; } } } } break; } ++mapCounter; } } } float AlgorithmMetricROIsFromExtrema::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmMetricROIsFromExtrema::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricROIsFromExtrema.h000066400000000000000000000046111360521144700267070ustar00rootroot00000000000000#ifndef __ALGORITHM_METRIC_ROIS_FROM_EXTREMA_H__ #define __ALGORITHM_METRIC_ROIS_FROM_EXTREMA_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "OverlapLogicEnum.h" #include #include namespace caret { class GeodesicHelper; class AlgorithmMetricROIsFromExtrema : public AbstractAlgorithm { AlgorithmMetricROIsFromExtrema(); void processMap(const float* data, std::vector& excludeDists, std::vector excludeSouces, std::vector >& roiLists, int64_t& mapCounter, CaretPointer& myHelp, const float& limit, const float* roiData, const OverlapLogicEnum::Enum& overlapType, const int& numNodes); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmMetricROIsFromExtrema(ProgressObject* myProgObj, const SurfaceFile* mySurf, const MetricFile* myMetric, const float& limit, MetricFile* myMetricOut, const float& sigma = -1.0f, const MetricFile* myRoi = NULL, const OverlapLogicEnum::Enum& overlapType = OverlapLogicEnum::ALLOW, const int& myColumn = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmMetricROIsFromExtrema; } #endif //__ALGORITHM_METRIC_ROIS_FROM_EXTREMA_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricROIsToBorder.cxx000066400000000000000000000141351360521144700265530ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmMetricROIsToBorder.h" #include "AlgorithmException.h" #include "Border.h" #include "BorderFile.h" #include "BorderTracingHelper.h" #include "GiftiLabelTable.h" #include "MetricFile.h" #include "SurfaceFile.h" #include using namespace caret; using namespace std; AString AlgorithmMetricROIsToBorder::getCommandSwitch() { return "-metric-rois-to-border"; } AString AlgorithmMetricROIsToBorder::getShortDescription() { return "DRAW BORDERS AROUND METRIC ROIS"; } OperationParameters* AlgorithmMetricROIsToBorder::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to use for neighbor information"); ret->addMetricParameter(2, "metric", "the input metric containing ROIs"); ret->addStringParameter(3, "class-name", "the name to use for the class of the output borders"); ret->addBorderOutputParameter(4, "border-out", "the output border file"); OptionalParameter* placeOpt = ret->createOptionalParameter(5, "-placement", "set how far along the edge border points are drawn"); placeOpt->addDoubleParameter(1, "fraction", "fraction along edge from inside vertex (default 0.33)"); OptionalParameter* columnSelect = ret->createOptionalParameter(6, "-column", "select a single column"); columnSelect->addStringParameter(1, "column", "the column number or name"); ret->setHelpText( AString("For each ROI column, finds all edges on the mesh that cross the boundary of the ROI, and draws borders through them. ") + "By default, this is done on all columns in the input file, using the map name as the name for the border." ); return ret; } void AlgorithmMetricROIsToBorder::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* mySurf = myParams->getSurface(1); MetricFile* myMetric = myParams->getMetric(2); AString className = myParams->getString(3); BorderFile* myBorderOut = myParams->getOutputBorder(4); float placement = 0.33f; OptionalParameter* placeOpt = myParams->getOptionalParameter(5); if (placeOpt->m_present) { placement = (float)placeOpt->getDouble(1); } OptionalParameter* columnSelect = myParams->getOptionalParameter(6); int columnNum = -1; if (columnSelect->m_present) {//set up to use the single column columnNum = (int)myMetric->getMapIndexFromNameOrNumber(columnSelect->getString(1)); if (columnNum < 0) { throw AlgorithmException("invalid column specified"); } } AlgorithmMetricROIsToBorder(myProgObj, mySurf, myMetric, className, myBorderOut, placement, columnNum); } AlgorithmMetricROIsToBorder::AlgorithmMetricROIsToBorder(ProgressObject* myProgObj, const SurfaceFile* mySurf, const MetricFile* myMetric, const AString& className, BorderFile* myBorderOut, const float& placement, const int& columnNum) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (mySurf->getNumberOfNodes() != myMetric->getNumberOfNodes()) throw AlgorithmException("label file does not match surface file number of vertices"); if (placement < 0.0f || placement > 1.0f || placement != placement) throw AlgorithmException("placement must be between 0 and 1"); if (columnNum < -1 || columnNum > myMetric->getNumberOfColumns()) throw AlgorithmException("invalid column specified"); myBorderOut->setStructure(mySurf->getStructure()); myBorderOut->setNumberOfNodes(mySurf->getNumberOfNodes()); BorderTracingHelper myHelper(mySurf); GiftiLabelTable myNameTable; if (columnNum == -1) { for (int col = 0; col < myMetric->getNumberOfColumns(); ++col) { vector > result = myHelper.traceData(myMetric->getValuePointerForColumn(col), BorderTracingHelper::GreaterThan(0.0f, false), placement); myNameTable.addLabel(myMetric->getMapName(col), rand() & 255, rand() & 255, rand() & 255); for (int i = 0; i < (int)result.size(); ++i) { result[i]->setClassName(className); result[i]->setName(myMetric->getMapName(col)); myBorderOut->addBorder(result[i].releasePointer());//NOTE: addBorder takes ownership of a RAW POINTER, shared_ptr won't release the pointer } } } else { myNameTable.addLabel(myMetric->getMapName(columnNum), rand() & 255, rand() & 255, rand() & 255); vector > result = myHelper.traceData(myMetric->getValuePointerForColumn(columnNum), BorderTracingHelper::GreaterThan(0.0f, false), placement); for (int i = 0; i < (int)result.size(); ++i) { result[i]->setClassName(className); result[i]->setName(myMetric->getMapName(columnNum)); myBorderOut->addBorder(result[i].releasePointer()); } } *(myBorderOut->getNameColorTable()) = myNameTable; } float AlgorithmMetricROIsToBorder::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmMetricROIsToBorder::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricROIsToBorder.h000066400000000000000000000035231360521144700261770ustar00rootroot00000000000000#ifndef __ALGORITHM_METRIC_ROIS_TO_BORDER_H__ #define __ALGORITHM_METRIC_ROIS_TO_BORDER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmMetricROIsToBorder : public AbstractAlgorithm { AlgorithmMetricROIsToBorder(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmMetricROIsToBorder(ProgressObject* myProgObj, const SurfaceFile* mySurf, const MetricFile* myMetric, const AString& className, BorderFile* myBorderOut, const float& placement = 0.33f, const int& columnNum = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmMetricROIsToBorder; } #endif //__ALGORITHM_METRIC_ROIS_TO_BORDER_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricReduce.cxx000066400000000000000000000136231360521144700255060ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmMetricReduce.h" #include "AlgorithmException.h" #include "CaretLogger.h" #include "MetricFile.h" #include "ReductionOperation.h" #include using namespace caret; using namespace std; AString AlgorithmMetricReduce::getCommandSwitch() { return "-metric-reduce"; } AString AlgorithmMetricReduce::getShortDescription() { return "PERFORM REDUCTION OPERATION ACROSS METRIC COLUMNS"; } OperationParameters* AlgorithmMetricReduce::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addMetricParameter(1, "metric-in", "the metric to reduce"); ret->addStringParameter(2, "operation", "the reduction operator to use"); ret->addMetricOutputParameter(3, "metric-out", "the output metric"); OptionalParameter* excludeOpt = ret->createOptionalParameter(4, "-exclude-outliers", "exclude non-numeric values and outliers by standard deviation"); excludeOpt->addDoubleParameter(1, "sigma-below", "number of standard deviations below the mean to include"); excludeOpt->addDoubleParameter(2, "sigma-above", "number of standard deviations above the mean to include"); ret->createOptionalParameter(5, "-only-numeric", "exclude non-numeric values"); ret->setHelpText( AString("For each surface vertex, takes the data across columns as a vector, and performs the specified reduction on it, putting the result ") + "into the single output column at that vertex. The reduction operators are as follows:\n\n" + ReductionOperation::getHelpInfo() ); return ret; } void AlgorithmMetricReduce::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { MetricFile* metricIn = myParams->getMetric(1); AString opString = myParams->getString(2); MetricFile* metricOut = myParams->getOutputMetric(3); OptionalParameter* excludeOpt = myParams->getOptionalParameter(4); bool onlyNumeric = myParams->getOptionalParameter(5)->m_present; bool ok = false; ReductionEnum::Enum myReduce = ReductionEnum::fromName(opString, &ok); if (!ok) throw AlgorithmException("unrecognized operation string '" + opString + "'"); if (excludeOpt->m_present) { if (onlyNumeric) CaretLogWarning("-only-numeric is redundant when -exclude-outliers is specified"); AlgorithmMetricReduce(myProgObj, metricIn, myReduce, metricOut, excludeOpt->getDouble(1), excludeOpt->getDouble(2)); } else { AlgorithmMetricReduce(myProgObj, metricIn, myReduce, metricOut, onlyNumeric); } } AlgorithmMetricReduce::AlgorithmMetricReduce(ProgressObject* myProgObj, const MetricFile* metricIn, const ReductionEnum::Enum& myReduce, MetricFile* metricOut, const bool& onlyNumeric) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int numNodes = metricIn->getNumberOfNodes(); int numCols = metricIn->getNumberOfColumns(); if (numCols < 1 || numNodes < 1) throw AlgorithmException("input must have at least 1 column and 1 vertex"); if (numCols == 1) { CaretLogWarning("-metric-reduce is being used for a length=1 reduction on file '" + metricIn->getFileName() + "'"); } metricOut->setNumberOfNodesAndColumns(numNodes, 1); metricOut->setStructure(metricIn->getStructure()); metricOut->setColumnName(0, ReductionEnum::toName(myReduce)); vector scratch(numCols); for (int node = 0; node < numNodes; ++node) { for (int col = 0; col < numCols; ++col) { scratch[col] = metricIn->getValue(node, col); } if (onlyNumeric) { metricOut->setValue(node, 0, ReductionOperation::reduceOnlyNumeric(scratch.data(), numCols, myReduce)); } else { metricOut->setValue(node, 0, ReductionOperation::reduce(scratch.data(), numCols, myReduce)); } } } AlgorithmMetricReduce::AlgorithmMetricReduce(ProgressObject* myProgObj, const MetricFile* metricIn, const ReductionEnum::Enum& myReduce, MetricFile* metricOut, const float& sigmaBelow, const float& sigmaAbove) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int numNodes = metricIn->getNumberOfNodes(); int numCols = metricIn->getNumberOfColumns(); if (numCols < 1 || numNodes < 1) throw AlgorithmException("input must have at least 1 column and 1 vertex"); metricOut->setNumberOfNodesAndColumns(numNodes, 1); metricOut->setStructure(metricIn->getStructure()); metricOut->setColumnName(0, ReductionEnum::toName(myReduce)); vector scratch(numCols); for (int node = 0; node < numNodes; ++node) { for (int col = 0; col < numCols; ++col) { scratch[col] = metricIn->getValue(node, col); } metricOut->setValue(node, 0, ReductionOperation::reduceExcludeDev(scratch.data(), numCols, myReduce, sigmaBelow, sigmaAbove)); } } float AlgorithmMetricReduce::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmMetricReduce::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricReduce.h000066400000000000000000000036541360521144700251360ustar00rootroot00000000000000#ifndef __ALGORITHM_METRIC_REDUCE_H__ #define __ALGORITHM_METRIC_REDUCE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "ReductionEnum.h" namespace caret { class AlgorithmMetricReduce : public AbstractAlgorithm { AlgorithmMetricReduce(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmMetricReduce(ProgressObject* myProgObj, const MetricFile* metricIn, const ReductionEnum::Enum& myReduce, MetricFile* metricOut, const bool& onlyNumeric = false); AlgorithmMetricReduce(ProgressObject* myProgObj, const MetricFile* metricIn, const ReductionEnum::Enum& myReduce, MetricFile* metricOut, const float& sigmaBelow, const float& sigmaAbove); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmMetricReduce; } #endif //__ALGORITHM_METRIC_REDUCE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricRegression.cxx000066400000000000000000000340571360521144700264230ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmMetricRegression.h" #include "AlgorithmException.h" #include "FloatMatrix.h" #include "MetricFile.h" #include "PaletteColorMapping.h" using namespace caret; using namespace std; AString AlgorithmMetricRegression::getCommandSwitch() { return "-metric-regression"; } AString AlgorithmMetricRegression::getShortDescription() { return "REGRESS METRICS OUT OF A METRIC FILE"; } OperationParameters* AlgorithmMetricRegression::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addMetricParameter(1, "metric-in", "the metric to regress from"); ret->addMetricOutputParameter(2, "metric-out", "the output metric"); OptionalParameter* roiOpt = ret->createOptionalParameter(3, "-roi", "only regress inside an roi"); roiOpt->addMetricParameter(1, "roi-metric", "the area to use for regression, as a metric"); OptionalParameter* columnOpt = ret->createOptionalParameter(4, "-column", "select a single column to regress from"); columnOpt->addStringParameter(1, "column", "the column number or name"); ParameterComponent* removeOpt = ret->createRepeatableParameter(5, "-remove", "specify a metric to regress out"); removeOpt->addMetricParameter(1, "metric", "the metric file to use"); OptionalParameter* removeColOpt = removeOpt->createOptionalParameter(2, "-remove-column", "select a column to use, rather than all"); removeColOpt->addStringParameter(1, "column", "the column number or name"); ParameterComponent* keepOpt = ret->createRepeatableParameter(6, "-keep", "specify a metric to include in regression, but not remove"); keepOpt->addMetricParameter(1, "metric", "the metric file to use"); OptionalParameter* keepColOpt = keepOpt->createOptionalParameter(2, "-keep-column", "select a column to use, rather than all"); keepColOpt->addStringParameter(1, "column", "the column number or name"); ret->setHelpText( AString("For each regressor, its mean across the surface is subtracted from its data. ") + "Each input map is then regressed against these, and a constant term. The resulting regressed slopes of all regressors specified with -remove " + "are multiplied with their respective regressor maps, and these are subtracted from the input map." ); return ret; } void AlgorithmMetricRegression::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { MetricFile* myMetricIn = myParams->getMetric(1); MetricFile* myMetricOut = myParams->getOutputMetric(2); MetricFile* myRoi = NULL; OptionalParameter* roiOpt = myParams->getOptionalParameter(3); if (roiOpt->m_present) { myRoi = roiOpt->getMetric(1); } int32_t myColumn = -1; OptionalParameter* columnOpt = myParams->getOptionalParameter(4); if (columnOpt->m_present) { myColumn = (int)myMetricIn->getMapIndexFromNameOrNumber(columnOpt->getString(1)); if (myColumn < 0) { throw AlgorithmException("invalid column specified"); } } vector > remove, keep; const vector& removeInstances = *(myParams->getRepeatableParameterInstances(5)); int numRemove = (int)removeInstances.size(); if (numRemove == 0) throw AlgorithmException("you must specify at least one 'remove' metric"); for (int i = 0; i < numRemove; ++i) { MetricFile* toRemove = removeInstances[i]->getMetric(1); int removeCol = -1; OptionalParameter* removeColOpt = removeInstances[i]->getOptionalParameter(2); if (removeColOpt->m_present) { removeCol = toRemove->getMapIndexFromNameOrNumber(removeColOpt->getString(1)); if (removeCol < 0) { throw AlgorithmException("invalid column specified for 'remove' metric '" + toRemove->getFileName() + "'"); } } remove.push_back(pair(toRemove, removeCol)); } const vector& keepInstances = *(myParams->getRepeatableParameterInstances(6)); int numKeep = (int)keepInstances.size(); for (int i = 0; i < numKeep; ++i) { MetricFile* toKeep = keepInstances[i]->getMetric(1); int keepCol = -1; OptionalParameter* keepColOpt = keepInstances[i]->getOptionalParameter(2); if (keepColOpt->m_present) { keepCol = toKeep->getMapIndexFromNameOrNumber(keepColOpt->getString(1)); if (keepCol < 0) { throw AlgorithmException("invalid column specified for 'keep' metric '" + toKeep->getFileName() + "'"); } } keep.push_back(pair(toKeep, keepCol)); } AlgorithmMetricRegression(myProgObj, myMetricIn, myMetricOut, remove, keep, myColumn, myRoi); } AlgorithmMetricRegression::AlgorithmMetricRegression(ProgressObject* myProgObj, const MetricFile* myMetricIn, MetricFile* myMetricOut, const vector >& remove, const vector >& keep, const int& myColumn, const MetricFile* myRoi) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); vector > regressCols;//because we are going to de-mean the input data int removeCount = 0; int numNodes = myMetricIn->getNumberOfNodes(); int numColumns = myMetricIn->getNumberOfColumns(); if (myColumn < -1 || myColumn >= numColumns) { throw AlgorithmException("invalid column number"); } int numRemove = (int)remove.size(); if (numRemove == 0) throw AlgorithmException("empty remove list in AlgorithmMetricRegression"); const float* roiData = NULL; int numUsedNodes = numNodes; if (myRoi != NULL) { if (myRoi->getNumberOfNodes() != numNodes) throw AlgorithmException("roi metric has different number of nodes"); roiData = myRoi->getValuePointerForColumn(0); numUsedNodes = 0; for (int i = 0; i < numNodes; ++i) { if (roiData[i] > 0.0f) ++numUsedNodes; } } for (int i = 0; i < numRemove; ++i) { const MetricFile* thisMetric = remove[i].first; if (thisMetric->getNumberOfNodes() != numNodes) { throw AlgorithmException("'remove' metric '" + thisMetric->getFileName() + "' has a different number of nodes than the input metric"); } int thisCol = remove[i].second; if (thisCol == -1) { int endCol = thisMetric->getNumberOfColumns(); removeCount += endCol; for (int j = 0; j < endCol; ++j) { regressCols.push_back(vector()); demeanCol(thisMetric->getValuePointerForColumn(j), numNodes, roiData, regressCols.back()); } } else { if (thisCol < 0 || thisCol >= thisMetric->getNumberOfColumns()) throw AlgorithmException("invalid column specified for metric '" + thisMetric->getFileName() + "'"); ++removeCount; regressCols.push_back(vector()); demeanCol(thisMetric->getValuePointerForColumn(thisCol), numNodes, roiData, regressCols.back()); } } int numKeep = (int)keep.size();//repeat, without increasing removeCount - this separates what gets removed after regression for (int i = 0; i < numKeep; ++i) { const MetricFile* thisMetric = keep[i].first; if (thisMetric->getNumberOfNodes() != numNodes) { throw AlgorithmException("'keep' metric '" + thisMetric->getFileName() + "' has a different number of nodes than the input metric"); } int thisCol = keep[i].second; if (thisCol == -1) { int endCol = thisMetric->getNumberOfColumns(); for (int j = 0; j < endCol; ++j) { regressCols.push_back(vector()); demeanCol(thisMetric->getValuePointerForColumn(j), numNodes, roiData, regressCols.back()); } } else { if (thisCol < 0 || thisCol >= thisMetric->getNumberOfColumns()) throw AlgorithmException("invalid column specified for metric '" + thisMetric->getFileName() + "'"); regressCols.push_back(vector()); demeanCol(thisMetric->getValuePointerForColumn(thisCol), numNodes, roiData, regressCols.back()); } } FloatMatrix xtrans(regressCols);//use naive matrix math - not particularly efficient, but it works regressCols.clear();//don't need this any more, should call destructor on each member vector and release the memory xtrans = xtrans.concatVert(FloatMatrix::ones(1, numUsedNodes));//add constant term FloatMatrix toInvert = xtrans * xtrans.transpose(); int invertSize = toInvert.getNumberOfRows(); //a bit of a hack, but it should work, though this causes the work of inversion to be done twice if (toInvert.reducedRowEchelon()[invertSize - 1][invertSize - 1] != 1.0f) throw AlgorithmException("regression encountered a non-invertible matrix, check your inputs for linear independence"); FloatMatrix solver = toInvert.inverse() * xtrans;//do most of the math in temporaries if (myColumn == -1) { myMetricOut->setNumberOfNodesAndColumns(numNodes, numColumns); myMetricOut->setStructure(myMetricIn->getStructure()); for (int i = 0; i < numColumns; ++i) { myMetricOut->setColumnName(i, myMetricIn->getColumnName(i) + " regressed"); *(myMetricOut->getPaletteColorMapping(i)) = *(myMetricIn->getPaletteColorMapping(i)); FloatMatrix y(numUsedNodes, 1);//create column vector for input - note that column vectors are extremely inefficient currently, as is copying the data... const float* data = myMetricIn->getValuePointerForColumn(i); int m = 0; for (int j = 0; j < numNodes; ++j) { if (roiData == NULL || roiData[j] > 0.0f) { y[m][0] = data[j]; ++m; } } FloatMatrix regressed = solver * y; vector outscratch(numNodes); m = 0; for (int j = 0; j < numNodes; ++j) { if (roiData == NULL || roiData[j] > 0.0f) { outscratch[j] = data[j]; for (int k = 0; k < removeCount; ++k) { outscratch[j] -= regressed[k][0] * xtrans[k][m]; } ++m; } else { outscratch[j] = 0.0f; } } myMetricOut->setValuesForColumn(i, outscratch.data()); } } else { myMetricOut->setNumberOfNodesAndColumns(numNodes, 1); myMetricOut->setStructure(myMetricIn->getStructure()); myMetricOut->setColumnName(0, myMetricIn->getColumnName(myColumn) + " regressed"); *(myMetricOut->getPaletteColorMapping(0)) = *(myMetricIn->getPaletteColorMapping(myColumn)); FloatMatrix y(numUsedNodes, 1);//create column vector for input - note that column vectors are extremely inefficient currently, as is copying the data... const float* data = myMetricIn->getValuePointerForColumn(myColumn); int m = 0; for (int j = 0; j < numNodes; ++j) { if (roiData == NULL || roiData[j] > 0.0f) { y[m][0] = data[j]; ++m; } } FloatMatrix regressed = solver * y; vector outscratch(numNodes); m = 0; for (int j = 0; j < numNodes; ++j) { if (roiData == NULL || roiData[j] > 0.0f) { outscratch[j] = data[j]; for (int k = 0; k < removeCount; ++k) { outscratch[j] -= regressed[k][0] * xtrans[k][m]; } ++m; } else { outscratch[j] = 0.0f; } } myMetricOut->setValuesForColumn(0, outscratch.data()); } } void AlgorithmMetricRegression::demeanCol(const float* data, const int& count, const float* roiData, std::vector< float >& out) { if (roiData == NULL) { double accum = 0.0; for (int i = 0; i < count; ++i) { accum += data[i]; } accum /= count; out.resize(count); for (int i = 0; i < count; ++i) { out[i] = data[i] - accum; } } else { int usedCount = 0; double accum = 0.0; for (int i = 0; i < count; ++i) { if (roiData[i] > 0.0f) { accum += data[i]; ++usedCount; } } accum /= usedCount; out.resize(usedCount); int m = 0; for (int i = 0; i < count; ++i) { if (roiData[i] > 0.0f) { out[m] = data[i] - accum; ++m; } } } } float AlgorithmMetricRegression::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmMetricRegression::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricRegression.h000066400000000000000000000040251360521144700260400ustar00rootroot00000000000000#ifndef __ALGORITHM_METRIC_REGRESSION_H__ #define __ALGORITHM_METRIC_REGRESSION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include #include namespace caret { class AlgorithmMetricRegression : public AbstractAlgorithm { AlgorithmMetricRegression(); void demeanCol(const float* data, const int& count, const float* roiData, std::vector& out); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmMetricRegression(ProgressObject* myProgObj, const MetricFile* myMetricIn, MetricFile* myMetricOut, const std::vector >& remove, const std::vector >& keep, const int& myColumn = -1, const MetricFile* myRoi = NULL); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmMetricRegression; } #endif //__ALGORITHM_METRIC_REGRESSION_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricRemoveIslands.cxx000066400000000000000000000147431360521144700270560ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmMetricRemoveIslands.h" #include "AlgorithmException.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "TopologyHelper.h" #include #include using namespace caret; using namespace std; AString AlgorithmMetricRemoveIslands::getCommandSwitch() { return "-metric-remove-islands"; } AString AlgorithmMetricRemoveIslands::getShortDescription() { return "REMOVE ISLANDS FROM AN ROI METRIC"; } OperationParameters* AlgorithmMetricRemoveIslands::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to use for neighbor information"); ret->addMetricParameter(2, "metric-in", "the input ROI metric"); ret->addMetricOutputParameter(3, "metric-out", "the output ROI metric"); OptionalParameter* corrAreaOpt = ret->createOptionalParameter(4, "-corrected-areas", "vertex areas to use instead of computing them from the surface"); corrAreaOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); ret->setHelpText( AString("Finds all connected areas in the ROI, and zeros out all but the largest one, in terms of surface area.") ); return ret; } void AlgorithmMetricRemoveIslands::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* mySurf = myParams->getSurface(1); MetricFile* myMetric = myParams->getMetric(2); MetricFile* myMetricOut = myParams->getOutputMetric(3); MetricFile* corrAreaMetric = NULL; OptionalParameter* corrAreaOpt = myParams->getOptionalParameter(4); if (corrAreaOpt->m_present) { corrAreaMetric = corrAreaOpt->getMetric(1); } AlgorithmMetricRemoveIslands(myProgObj, mySurf, myMetric, myMetricOut, corrAreaMetric); } AlgorithmMetricRemoveIslands::AlgorithmMetricRemoveIslands(ProgressObject* myProgObj, const SurfaceFile* mySurf, const MetricFile* myMetric, MetricFile* myMetricOut, const MetricFile* corrAreaMetric) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int numNodes = mySurf->getNumberOfNodes(); if (myMetric->getNumberOfNodes() != numNodes) throw AlgorithmException("metric file has different number of nodes than the surface"); vector surfAreaData; const float* areaData = NULL; if (corrAreaMetric != NULL) { if (corrAreaMetric->getNumberOfNodes() != numNodes) throw AlgorithmException("corrected vertex area metric file has different number of nodes than the surface"); areaData = corrAreaMetric->getValuePointerForColumn(0); } else { mySurf->computeNodeAreas(surfAreaData); areaData = surfAreaData.data(); } int numCols = myMetric->getNumberOfColumns(); myMetricOut->setNumberOfNodesAndColumns(numNodes, numCols); myMetricOut->setStructure(myMetric->getStructure()); for (int col = 0; col < numCols; ++col) { vector > > areas; vector used(numNodes, 0); CaretPointer myHelp = mySurf->getTopologyHelper(); const float* roiData = myMetric->getValuePointerForColumn(col); myMetricOut->setColumnName(col, myMetric->getColumnName(col)); for (int i = 0; i < numNodes; ++i) { if (used[i] == 0 && roiData[i] > 0.0f) { areas.push_back(make_pair(0.0f, vector())); vector& thisAreaMembers = areas.back().second; float& thisSurfArea = areas.back().first; thisAreaMembers.push_back(i); thisSurfArea += areaData[i]; used[i] = 1; vector mystack; mystack.push_back(i); while (!mystack.empty()) { int curnode = mystack.back(); mystack.pop_back(); const vector& neighbors = myHelp->getNodeNeighbors(curnode); int numNeigh = (int)neighbors.size(); for (int j = 0; j < numNeigh; ++j) { int thisneigh = neighbors[j]; if (used[thisneigh] == 0 && roiData[thisneigh] > 0.0f) { used[thisneigh] = 1; thisAreaMembers.push_back(thisneigh); thisSurfArea += areaData[thisneigh]; mystack.push_back(thisneigh); } } } } } vector outscratch(numNodes, 0.0f); int numAreas = (int)areas.size(); if (numAreas > 0) { int bestIndex = 0; float bestArea = areas[0].first; for (int i = 1; i < numAreas; ++i) { float thisArea = (int)areas[i].first; if (thisArea > bestArea) { bestIndex = i; bestArea = thisArea; } } const vector& thisArea = areas[bestIndex].second; int numAreaNodes = (int)thisArea.size(); for (int i = 0; i < numAreaNodes; ++i) { outscratch[thisArea[i]] = 1.0f;//make it into a simple 0/1 metric, even if it wasn't before } } myMetricOut->setValuesForColumn(col, outscratch.data()); } } float AlgorithmMetricRemoveIslands::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmMetricRemoveIslands::getSubAlgorithmWeight() { return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricRemoveIslands.h000066400000000000000000000034551360521144700265010ustar00rootroot00000000000000#ifndef __ALGORITHM_METRIC_REMOVE_ISLANDS_H__ #define __ALGORITHM_METRIC_REMOVE_ISLANDS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmMetricRemoveIslands : public AbstractAlgorithm { AlgorithmMetricRemoveIslands(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmMetricRemoveIslands(ProgressObject* myProgObj, const SurfaceFile* mySurf, const MetricFile* myMetric, MetricFile* myMetricOut, const MetricFile* corrAreaMetric = NULL); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmMetricRemoveIslands; } #endif //__ALGORITHM_METRIC_REMOVE_ISLANDS_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricResample.cxx000066400000000000000000000252601360521144700260470ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmMetricResample.h" #include "AlgorithmException.h" #include "CaretLogger.h" #include "MetricFile.h" #include "PaletteColorMapping.h" #include "SurfaceFile.h" #include "SurfaceResamplingHelper.h" using namespace caret; using namespace std; AString AlgorithmMetricResample::getCommandSwitch() { return "-metric-resample"; } AString AlgorithmMetricResample::getShortDescription() { return "RESAMPLE A METRIC FILE TO A DIFFERENT MESH"; } OperationParameters* AlgorithmMetricResample::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addMetricParameter(1, "metric-in", "the metric file to resample"); ret->addSurfaceParameter(2, "current-sphere", "a sphere surface with the mesh that the metric is currently on"); ret->addSurfaceParameter(3, "new-sphere", "a sphere surface that is in register with and has the desired output mesh"); ret->addStringParameter(4, "method", "the method name"); ret->addMetricOutputParameter(5, "metric-out", "the output metric"); OptionalParameter* areaSurfsOpt = ret->createOptionalParameter(6, "-area-surfs", "specify surfaces to do vertex area correction based on"); areaSurfsOpt->addSurfaceParameter(1, "current-area", "a relevant anatomical surface with mesh"); areaSurfsOpt->addSurfaceParameter(2, "new-area", "a relevant anatomical surface with mesh"); OptionalParameter* areaMetricsOpt = ret->createOptionalParameter(7, "-area-metrics", "specify vertex area metrics to do area correction based on"); areaMetricsOpt->addMetricParameter(1, "current-area", "a metric file with vertex areas for mesh"); areaMetricsOpt->addMetricParameter(2, "new-area", "a metric file with vertex areas for mesh"); OptionalParameter* roiOpt = ret->createOptionalParameter(8, "-current-roi", "use an input roi on the current mesh to exclude non-data vertices"); roiOpt->addMetricParameter(1, "roi-metric", "the roi, as a metric file"); OptionalParameter* validRoiOutOpt = ret->createOptionalParameter(9, "-valid-roi-out", "output the ROI of vertices that got data from valid source vertices"); validRoiOutOpt->addMetricOutputParameter(1, "roi-out", "the output roi as a metric"); ret->createOptionalParameter(10, "-largest", "use only the value of the vertex with the largest weight"); AString myHelpText = AString("Resamples a metric file, given two spherical surfaces that are in register. ") + "If ADAP_BARY_AREA is used, exactly one of -area-surfs or -area-metrics must be specified.\n\n" + "The ADAP_BARY_AREA method is recommended for ordinary metric data, because it should use all data while downsampling, unlike BARYCENTRIC. " + "The recommended areas option for most data is individual midthicknesses for individual data, and averaged vertex area metrics from individual midthicknesses for group average data.\n\n" "The -current-roi option only masks the input, the output may be slightly dilated in comparison, consider using -metric-mask on the output " + "when using -current-roi.\n\n" + "The -largest option results in nearest vertex behavior when used with BARYCENTRIC. " + "When resampling a binary metric, consider thresholding at 0.5 after resampling rather than using -largest.\n\n" + "The argument must be one of the following:\n\n"; vector allEnums; SurfaceResamplingMethodEnum::getAllEnums(allEnums); for (int i = 0; i < (int)allEnums.size(); ++i) { myHelpText += SurfaceResamplingMethodEnum::toName(allEnums[i]) + "\n"; } ret->setHelpText(myHelpText); return ret; } void AlgorithmMetricResample::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { MetricFile* metricIn = myParams->getMetric(1); SurfaceFile* curSphere = myParams->getSurface(2); SurfaceFile* newSphere = myParams->getSurface(3); bool ok = false; SurfaceResamplingMethodEnum::Enum myMethod = SurfaceResamplingMethodEnum::fromName(myParams->getString(4), &ok); if (!ok) { throw AlgorithmException("invalid method name"); } MetricFile* metricOut = myParams->getOutputMetric(5); MetricFile* curAreas = NULL, *newAreas = NULL; MetricFile curAreasTemp, newAreasTemp; OptionalParameter* areaSurfsOpt = myParams->getOptionalParameter(6); if (areaSurfsOpt->m_present) { switch(myMethod) { case SurfaceResamplingMethodEnum::BARYCENTRIC: CaretLogInfo("This method does not use area correction, -area-surfs is not needed"); break; default: break; } vector nodeAreasTemp; SurfaceFile* curAreaSurf = areaSurfsOpt->getSurface(1); SurfaceFile* newAreaSurf = areaSurfsOpt->getSurface(2); curAreaSurf->computeNodeAreas(nodeAreasTemp); curAreasTemp.setNumberOfNodesAndColumns(curAreaSurf->getNumberOfNodes(), 1); curAreasTemp.setValuesForColumn(0, nodeAreasTemp.data()); curAreas = &curAreasTemp; newAreaSurf->computeNodeAreas(nodeAreasTemp); newAreasTemp.setNumberOfNodesAndColumns(newAreaSurf->getNumberOfNodes(), 1); newAreasTemp.setValuesForColumn(0, nodeAreasTemp.data()); newAreas = &newAreasTemp; } OptionalParameter* areaMetricsOpt = myParams->getOptionalParameter(7); if (areaMetricsOpt->m_present) { if (areaSurfsOpt->m_present) { throw AlgorithmException("only one of -area-surfs and -area-metrics can be specified"); } switch(myMethod) { case SurfaceResamplingMethodEnum::BARYCENTRIC: CaretLogInfo("This method does not use area correction, -area-metrics is not needed"); break; default: break; } curAreas = areaMetricsOpt->getMetric(1); newAreas = areaMetricsOpt->getMetric(2); } OptionalParameter* roiOpt = myParams->getOptionalParameter(8); MetricFile* currentRoi = NULL; if (roiOpt->m_present) { currentRoi = roiOpt->getMetric(1); } MetricFile* validRoiOut = NULL; OptionalParameter* validRoiOutOpt = myParams->getOptionalParameter(9); if (validRoiOutOpt->m_present) { validRoiOut = validRoiOutOpt->getOutputMetric(1); } bool largest = myParams->getOptionalParameter(10)->m_present; AlgorithmMetricResample(myProgObj, metricIn, curSphere, newSphere, myMethod, metricOut, curAreas, newAreas, currentRoi, validRoiOut, largest); } AlgorithmMetricResample::AlgorithmMetricResample(ProgressObject* myProgObj, const MetricFile* metricIn, const SurfaceFile* curSphere, const SurfaceFile* newSphere, const SurfaceResamplingMethodEnum::Enum& myMethod, MetricFile* metricOut, const MetricFile* curAreas, const MetricFile* newAreas, const MetricFile* currentRoi, MetricFile* validRoiOut, const bool& largest) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (metricIn->getNumberOfNodes() != curSphere->getNumberOfNodes()) throw AlgorithmException("input metric has different number of nodes than input sphere"); if (currentRoi != NULL && currentRoi->getNumberOfNodes() != curSphere->getNumberOfNodes()) throw AlgorithmException("roi metric has different number of nodes than input sphere"); const float* curAreaData = NULL, *newAreaData = NULL; switch (myMethod) { case SurfaceResamplingMethodEnum::BARYCENTRIC: break; default: if (curAreas == NULL || newAreas == NULL) throw AlgorithmException("specified method does area correction, but no vertex area data given"); if (curSphere->getNumberOfNodes() != curAreas->getNumberOfNodes()) throw AlgorithmException("current vertex area data has different number of nodes than current sphere"); if (newSphere->getNumberOfNodes() != newAreas->getNumberOfNodes()) throw AlgorithmException("new vertex area data has different number of nodes than new sphere"); curAreaData = curAreas->getValuePointerForColumn(0); newAreaData = newAreas->getValuePointerForColumn(0); } int numColumns = metricIn->getNumberOfColumns(), numNewNodes = newSphere->getNumberOfNodes(); metricOut->setNumberOfNodesAndColumns(numNewNodes, numColumns); metricOut->setStructure(metricIn->getStructure()); vector colScratch(numNewNodes, 0.0f); const float* roiCol = NULL; if (currentRoi != NULL) roiCol = currentRoi->getValuePointerForColumn(0); SurfaceResamplingHelper myHelp(myMethod, curSphere, newSphere, curAreaData, newAreaData, roiCol); if (validRoiOut != NULL) { validRoiOut->setNumberOfNodesAndColumns(numNewNodes, 1); validRoiOut->setStructure(metricIn->getStructure()); vector scratch(numNewNodes); myHelp.getResampleValidROI(scratch.data()); validRoiOut->setValuesForColumn(0, scratch.data()); } for (int i = 0; i < numColumns; ++i) { metricOut->setColumnName(i, metricIn->getColumnName(i)); *metricOut->getPaletteColorMapping(i) = *metricIn->getPaletteColorMapping(i); if (largest) { myHelp.resampleLargest(metricIn->getValuePointerForColumn(i), colScratch.data()); } else { myHelp.resampleNormal(metricIn->getValuePointerForColumn(i), colScratch.data()); } metricOut->setValuesForColumn(i, colScratch.data()); } } float AlgorithmMetricResample::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmMetricResample::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricResample.h000066400000000000000000000040271360521144700254720ustar00rootroot00000000000000#ifndef __ALGORITHM_METRIC_RESAMPLE_H__ #define __ALGORITHM_METRIC_RESAMPLE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "SurfaceResamplingMethodEnum.h" namespace caret { class AlgorithmMetricResample : public AbstractAlgorithm { AlgorithmMetricResample(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmMetricResample(ProgressObject* myProgObj, const MetricFile* metricIn, const SurfaceFile* curSphere, const SurfaceFile* newSphere, const SurfaceResamplingMethodEnum::Enum& myMethod, MetricFile* metricOut, const MetricFile* curAreas = NULL, const MetricFile* newAreas = NULL, const MetricFile* currentRoi = NULL, MetricFile* validRoiOut = NULL, const bool& largest = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmMetricResample; } #endif //__ALGORITHM_METRIC_RESAMPLE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricSmoothing.cxx000066400000000000000000000273701360521144700262520ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmMetricSmoothing.h" #include "AlgorithmException.h" #include "CaretOMP.h" #include "CaretPointer.h" #include "GeodesicHelper.h" #include "MetricFile.h" #include "PaletteColorMapping.h" #include "SurfaceFile.h" #include "TopologyHelper.h" #include using namespace caret; using namespace std; AString AlgorithmMetricSmoothing::getCommandSwitch() { return "-metric-smoothing"; } AString AlgorithmMetricSmoothing::getShortDescription() { return "SMOOTH A METRIC FILE"; } OperationParameters* AlgorithmMetricSmoothing::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to smooth on"); ret->addMetricParameter(2, "metric-in", "the metric to smooth"); ret->addDoubleParameter(3, "smoothing-kernel", "the sigma for the gaussian kernel function, in mm"); ret->addMetricOutputParameter(4, "metric-out", "the output metric"); OptionalParameter* roiOption = ret->createOptionalParameter(5, "-roi", "select a region of interest to smooth"); roiOption->addMetricParameter(1, "roi-metric", "the roi to smooth within, as a metric"); roiOption->createOptionalParameter(2, "-match-columns", "for each input column, use the corresponding column from the roi"); ret->createOptionalParameter(6, "-fix-zeros", "treat zero values as not being data"); OptionalParameter* columnSelect = ret->createOptionalParameter(7, "-column", "select a single column to smooth"); columnSelect->addStringParameter(1, "column", "the column number or name"); OptionalParameter* corrAreaOpt = ret->createOptionalParameter(8, "-corrected-areas", "vertex areas to use instead of computing them from the surface"); corrAreaOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); OptionalParameter* methodSelect = ret->createOptionalParameter(9, "-method", "select smoothing method, default GEO_GAUSS_AREA"); methodSelect->addStringParameter(1, "method", "the name of the smoothing method"); ret->setHelpText( AString("Smooth a metric file on a surface. ") + "By default, smooths all input columns on the entire surface, specify -column to use only one input column, and -roi to smooth only where " + "the roi metric is greater than 0, outputting zeros elsewhere.\n\n" + "When using -roi, input data outside the ROI is not used to compute the smoothed values. " + "By default, the first column of the roi metric is used for all input columns. " + "When -match-columns is specified to the -roi option, the input and roi metrics must have the same number of columns, " + "and for each input column's index, the same column index is used in the roi metric. " + "If the -match-columns option to -roi is used while the -column option is also used, the number of columns must match between the roi and input metric, " + "and it will use the roi column with the index of the selected input column.\n\n" + "The -fix-zeros option causes the smoothing to not use an input value if it is zero, but still write a smoothed value to the vertex. " + "This is useful for zeros that indicate lack of information, preventing them from pulling down the intensity of nearby vertices, while " + "giving the zero an extrapolated value.\n\n" + "The -corrected-areas option is intended for when it is unavoidable to smooth on a group average surface, it is only an approximate correction " + "for the reduction of structure in a group average surface. It is better to smooth the data on individuals before averaging, when feasible.\n\n" + "Valid values for are:\n\n" + "GEO_GAUSS_AREA - uses a geodesic gaussian kernel, and normalizes based on vertex area in order to work more reliably on irregular surfaces\n\n" + "GEO_GAUSS_EQUAL - uses a geodesic gaussian kernel, and normalizes assuming each vertex has equal importance\n\n" + "GEO_GAUSS - matches geodesic gaussian smoothing from caret5, but does not check kernels for having unequal importance\n\n" + "The GEO_GAUSS_AREA method is the default because it is usually the correct choice. " + "GEO_GAUSS_EQUAL may be the correct choice when the sum of vertex values is more meaningful then the surface integral (sum of values .* areas), " + "for instance when smoothing vertex areas (the sum is the total surface area, while the surface integral is the sum of squares of the vertex areas). " + "The GEO_GAUSS method is not recommended, it exists mainly to replicate methods of studies done with caret5's geodesic smoothing." ); return ret; } void AlgorithmMetricSmoothing::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* mySurf = myParams->getSurface(1); MetricFile* myMetric = myParams->getMetric(2); double myKernel = myParams->getDouble(3); MetricFile* myMetricOut = myParams->getOutputMetric(4); MetricFile* myRoi = NULL; bool matchRoiColumns = false; OptionalParameter* roiOption = myParams->getOptionalParameter(5); if (roiOption->m_present) { myRoi = roiOption->getMetric(1); matchRoiColumns = roiOption->getOptionalParameter(2)->m_present; } OptionalParameter* fixZerosOpt = myParams->getOptionalParameter(6); bool fixZeros = fixZerosOpt->m_present; int64_t columnNum = -1; OptionalParameter* columnSelect = myParams->getOptionalParameter(7); if (columnSelect->m_present) { columnNum = (int)myMetric->getMapIndexFromNameOrNumber(columnSelect->getString(1)); if (columnNum < 0) { throw AlgorithmException("invalid column specified"); } } MetricFile* corrAreaMetric = NULL; OptionalParameter* corrAreaOpt = myParams->getOptionalParameter(8); if (corrAreaOpt->m_present) { corrAreaMetric = corrAreaOpt->getMetric(1); } MetricSmoothingObject::Method myMethod = MetricSmoothingObject::GEO_GAUSS_AREA; OptionalParameter* methodSelect = myParams->getOptionalParameter(9); if (methodSelect->m_present) { AString methodName = methodSelect->getString(1); if (methodName == "GEO_GAUSS_AREA") { myMethod = MetricSmoothingObject::GEO_GAUSS_AREA; } else if (methodName == "GEO_GAUSS_EQUAL") { myMethod = MetricSmoothingObject::GEO_GAUSS_EQUAL; } else if (methodName == "GEO_GAUSS") { myMethod = MetricSmoothingObject::GEO_GAUSS; } else { throw AlgorithmException("unknown smoothing method name"); } } AlgorithmMetricSmoothing(myProgObj, mySurf, myMetric, myKernel, myMetricOut, myRoi, matchRoiColumns, fixZeros, columnNum, corrAreaMetric, myMethod); } AlgorithmMetricSmoothing::AlgorithmMetricSmoothing(ProgressObject* myProgObj, const SurfaceFile* mySurf, const MetricFile* myMetric, const double myKernel, MetricFile* myMetricOut, const MetricFile* myRoi, const bool matchRoiColumns, const bool fixZeros, const int64_t columnNum, const MetricFile* corrAreaMetric, const MetricSmoothingObject::Method myMethod) : AbstractAlgorithm(myProgObj) { float precomputeWeightWork = 5.0f;//TODO: adjust this based on number of columns to smooth, if we ever end up using progress indicators LevelProgress myProgress(myProgObj, 1.0f + precomputeWeightWork); int32_t numNodes = mySurf->getNumberOfNodes(); if (numNodes != myMetric->getNumberOfNodes()) { throw AlgorithmException("metric does not match surface in number of vertices"); } if (myRoi != NULL && myRoi->getNumberOfNodes() != numNodes) { throw AlgorithmException("roi metric does not match surface in number of vertices"); } int32_t numCols = myMetric->getNumberOfColumns(); if (columnNum < -1 || columnNum >= numCols) { throw AlgorithmException("invalid column number"); } if (myKernel <= 0.0) { throw AlgorithmException("invalid kernel size"); } if (myRoi != NULL && matchRoiColumns && numCols != myRoi->getNumberOfColumns()) { throw AlgorithmException("match roi columns specified, but roi metric has the wrong number of columns"); } CaretPointer mySmoothObj; const float* areaData = NULL; if (corrAreaMetric != NULL) { if (corrAreaMetric->getNumberOfNodes() != numNodes) { throw AlgorithmException("corrected vertex areas metric does not match surface in number of vertices"); } areaData = corrAreaMetric->getValuePointerForColumn(0); } myProgress.setTask("Precomputing Smoothing Weights"); if (matchRoiColumns) { mySmoothObj.grabNew(new MetricSmoothingObject(mySurf, myKernel, NULL, myMethod, areaData));//don't use an ROI to build weights when the ROI changes each time } else { mySmoothObj.grabNew(new MetricSmoothingObject(mySurf, myKernel, myRoi, myMethod, areaData)); } myProgress.reportProgress(precomputeWeightWork); if (columnNum == -1) { myMetricOut->setNumberOfNodesAndColumns(numNodes, myMetric->getNumberOfColumns()); myMetricOut->setStructure(mySurf->getStructure()); for (int32_t col = 0; col < numCols; ++col) { myProgress.setTask("Smoothing Column " + AString::number(col)); myMetricOut->setColumnName(col, myMetric->getColumnName(col) + ", smooth " + AString::number(myKernel)); *(myMetricOut->getPaletteColorMapping(col)) = *(myMetric->getPaletteColorMapping(col));//copy the palette settings if (myRoi != NULL && matchRoiColumns) { mySmoothObj->smoothColumn(myMetric, col, myMetricOut, col, myRoi, col, fixZeros); } else { mySmoothObj->smoothColumn(myMetric, col, myMetricOut, col, myRoi, 0, fixZeros); } myProgress.reportProgress(precomputeWeightWork + ((float)col + 1) / numCols); } } else { myMetricOut->setNumberOfNodesAndColumns(numNodes, 1); myMetricOut->setStructure(mySurf->getStructure()); myMetricOut->setColumnName(0, myMetric->getColumnName(columnNum) + ", smooth " + AString::number(myKernel)); *(myMetricOut->getPaletteColorMapping(0)) = *(myMetric->getPaletteColorMapping(columnNum));//copy the palette settings myProgress.setTask("Smoothing Column " + AString::number(columnNum)); if (myRoi != NULL && matchRoiColumns) { mySmoothObj->smoothColumn(myMetric, columnNum, myMetricOut, 0, myRoi, columnNum, fixZeros); } else { mySmoothObj->smoothColumn(myMetric, columnNum, myMetricOut, 0, myRoi, 0, fixZeros); } } } float AlgorithmMetricSmoothing::getAlgorithmInternalWeight() { return 1.0f; } float AlgorithmMetricSmoothing::getSubAlgorithmWeight() { return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricSmoothing.h000066400000000000000000000041651360521144700256740ustar00rootroot00000000000000#ifndef __ALGORITHM_METRIC_SMOOTHING_H__ #define __ALGORITHM_METRIC_SMOOTHING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "MetricSmoothingObject.h" #include "stdint.h" #include namespace caret { class AlgorithmMetricSmoothing : public AbstractAlgorithm { public: private: AlgorithmMetricSmoothing(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmMetricSmoothing(ProgressObject* myProgObj, const SurfaceFile* mySurf, const MetricFile* myMetric, const double myKernel, MetricFile* myMetricOut, const MetricFile* myRoi = NULL, const bool matchRoiColumns = false, const bool fixZeros = false, const int64_t columnNum = -1, const MetricFile* corrAreaMetric = NULL, const MetricSmoothingObject::Method myMethod = MetricSmoothingObject::GEO_GAUSS_AREA); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmMetricSmoothing; } #endif //__ALGORITHM_METRIC_SMOOTHING_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricTFCE.cxx000066400000000000000000000441071360521144700250210ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmMetricTFCE.h" #include "AlgorithmException.h" #include "AlgorithmMetricSmoothing.h" #include "CaretAssert.h" #include "CaretHeap.h" #include "CaretOMP.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "TopologyHelper.h" #include #include #include using namespace caret; using namespace std; AString AlgorithmMetricTFCE::getCommandSwitch() { return "-metric-tfce"; } AString AlgorithmMetricTFCE::getShortDescription() { return "DO TFCE ON A METRIC FILE"; } OperationParameters* AlgorithmMetricTFCE::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to compute on"); ret->addMetricParameter(2, "metric-in", "the metric to run TFCE on"); ret->addMetricOutputParameter(3, "metric-out", "the output metric"); OptionalParameter* presmoothOpt = ret->createOptionalParameter(4, "-presmooth", "smooth the metric before running TFCE"); presmoothOpt->addDoubleParameter(1, "kernel", "the sigma for the gaussian smoothing kernel, in mm"); OptionalParameter* roiOpt = ret->createOptionalParameter(5, "-roi", "select a region of interest to run TFCE on"); roiOpt->addMetricParameter(1, "roi-metric", "the area to run TFCE on, as a metric"); OptionalParameter* paramsOpt = ret->createOptionalParameter(6, "-parameters", "set parameters for TFCE integral"); paramsOpt->addDoubleParameter(1, "E", "exponent for cluster area (default 1.0)"); paramsOpt->addDoubleParameter(2, "H", "exponent for threshold value (default 2.0)"); OptionalParameter* columnSelect = ret->createOptionalParameter(7, "-column", "select a single column"); columnSelect->addStringParameter(1, "column", "the column number or name"); OptionalParameter* corrAreaOpt = ret->createOptionalParameter(8, "-corrected-areas", "vertex areas to use instead of computing them from the surface"); corrAreaOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); ret->setHelpText( AString("Threshold-free cluster enhancement is a method to increase the relative value of regions that would form clusters in a standard thresholding test. ") + "This is accomplished by evaluating the integral of:\n\n" + "e(h, p)^E * h^H * dh\n\n" + "at each vertex p, where h ranges from 0 to the maximum value in the data, and e(h, p) is the extent of the cluster containing vertex p at threshold h. " + "Negative values are similarly enhanced by negating the data, running the same process, and negating the result.\n\n" + "When using -presmooth with -corrected-areas, note that it is an approximate correction within the smoothing algorithm (the TFCE correction is exact). " + "Doing smoothing on individual surfaces before averaging/TFCE is preferred, when possible, in order to better tie the smoothing kernel size to the original feature size.\n\n" + "The TFCE method is explained in: Smith SM, Nichols TE., \"Threshold-free cluster enhancement: addressing problems of smoothing, threshold dependence and localisation in cluster inference.\" Neuroimage. 2009 Jan 1;44(1):83-98. PMID: 18501637" ); return ret; } void AlgorithmMetricTFCE::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* mySurf = myParams->getSurface(1); MetricFile* myMetric = myParams->getMetric(2); MetricFile* myMetricOut = myParams->getOutputMetric(3); float presmooth = 0.0f; OptionalParameter* presmoothOpt = myParams->getOptionalParameter(4); if (presmoothOpt->m_present) { presmooth = (float)presmoothOpt->getDouble(1); if (presmooth <= 0.0f) throw AlgorithmException("presmooth kernel size must be positive"); } MetricFile* myRoi = NULL; OptionalParameter* roiOpt = myParams->getOptionalParameter(5); if (roiOpt->m_present) { myRoi = roiOpt->getMetric(1); } float param_e = 1.0f, param_h = 2.0; OptionalParameter* paramsOpt = myParams->getOptionalParameter(6); if (paramsOpt->m_present) { param_e = (float)paramsOpt->getDouble(1); param_h = (float)paramsOpt->getDouble(2); } OptionalParameter* columnSelect = myParams->getOptionalParameter(7); int columnNum = -1; if (columnSelect->m_present) {//set up to use the single column columnNum = (int)myMetric->getMapIndexFromNameOrNumber(columnSelect->getString(1)); if (columnNum < 0) { throw AlgorithmException("invalid column specified"); } } MetricFile* corrAreaMetric = NULL; OptionalParameter* corrAreaOpt = myParams->getOptionalParameter(8); if (corrAreaOpt->m_present) { corrAreaMetric = corrAreaOpt->getMetric(1); } AlgorithmMetricTFCE(myProgObj, mySurf, myMetric, myMetricOut, presmooth, myRoi, param_e, param_h, columnNum, corrAreaMetric); } AlgorithmMetricTFCE::AlgorithmMetricTFCE(ProgressObject* myProgObj, const SurfaceFile* mySurf, const MetricFile* myMetric, MetricFile* myMetricOut, const float& presmooth, const MetricFile* myRoi, const float& param_e, const float& param_h, const int& columnNum, const MetricFile* corrAreaMetric) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (mySurf->getNumberOfNodes() != myMetric->getNumberOfNodes()) throw AlgorithmException("metric and surface have different number of vertices"); if (myRoi != NULL && mySurf->getNumberOfNodes() != myRoi->getNumberOfNodes()) throw AlgorithmException("roi metric and surface have different number of vertices"); if (corrAreaMetric != NULL && mySurf->getNumberOfNodes() != corrAreaMetric->getNumberOfNodes()) throw AlgorithmException("corrected area metric and surface have different number of vertices"); if (columnNum < -1 || columnNum >= myMetric->getNumberOfColumns()) throw AlgorithmException("invalid column specified"); const float* roiData = NULL, *areaData = NULL; vector surfAreaData; if (corrAreaMetric == NULL) { mySurf->computeNodeAreas(surfAreaData); areaData = surfAreaData.data(); } else { areaData = corrAreaMetric->getValuePointerForColumn(0); } if (myRoi != NULL) roiData = myRoi->getValuePointerForColumn(0); if (columnNum == -1) { const MetricFile* toUse = myMetric; MetricFile postSmooth; if (presmooth > 0.0f) { AlgorithmMetricSmoothing(NULL, mySurf, myMetric, presmooth, &postSmooth, myRoi, false, false, -1, corrAreaMetric); toUse = &postSmooth; } int numCols = myMetric->getNumberOfColumns(); myMetricOut->setNumberOfNodesAndColumns(mySurf->getNumberOfNodes(), numCols); myMetricOut->setStructure(mySurf->getStructure()); #pragma omp CARET_PAR { vector outcol(mySurf->getNumberOfNodes(), 0.0f); #pragma omp CARET_FOR for (int col = 0; col < numCols; ++col) { processColumn(mySurf, toUse->getValuePointerForColumn(col), outcol.data(), roiData, param_e, param_h, areaData); myMetricOut->setValuesForColumn(col, outcol.data()); myMetricOut->setMapName(col, myMetric->getMapName(col)); } } } else { const MetricFile* toUse = myMetric; int useCol = columnNum; MetricFile postSmooth; if (presmooth > 0.0f) { AlgorithmMetricSmoothing(NULL, mySurf, myMetric, presmooth, &postSmooth, myRoi, false, false, columnNum, corrAreaMetric); toUse = &postSmooth; useCol = 0; } myMetricOut->setNumberOfNodesAndColumns(mySurf->getNumberOfNodes(), 1); myMetricOut->setStructure(mySurf->getStructure()); vector outcol(mySurf->getNumberOfNodes(), 0.0f); processColumn(mySurf, toUse->getValuePointerForColumn(useCol), outcol.data(), roiData, param_e, param_h, areaData); myMetricOut->setValuesForColumn(0, outcol.data()); myMetricOut->setMapName(0, myMetric->getMapName(columnNum)); } } void AlgorithmMetricTFCE::processColumn(const SurfaceFile* mySurf, const float* colData, float* outData, const float* roiData, const float& param_e, const float& param_h, const float* areaData) { int numNodes = mySurf->getNumberOfNodes(); vector accum(numNodes, 0.0); CaretPointer myHelper = mySurf->getTopologyHelper(); tfce_pos(myHelper, colData, accum.data(), roiData, param_e, param_h, areaData); vector negData(numNodes); for (int i = 0; i < numNodes; ++i) { negData[i] = -colData[i]; } tfce_pos(myHelper, negData.data(), accum.data(), roiData, param_e, param_h, areaData);//negatives and positives don't overlap, so reuse the accum array for (int i = 0; i < numNodes; ++i) { if (roiData == NULL || roiData[i] > 0.0f) { if (colData[i] < 0.0f) { outData[i] = (float)-accum[i]; } else { outData[i] = (float)accum[i]; } } else { outData[i] = 0.0f; } } } namespace {//hidden namespace just to make sure things don't collide struct Cluster { double accumVal, totalArea; vector members; float lastVal; bool first; Cluster() { first = true; accumVal = 0.0; totalArea = 0.0; lastVal = 0.0f; } void addMember(const int& node, const float& val, const float& area, const float& param_e, const float& param_h) { update(val, param_e, param_h); members.push_back(node); totalArea += area; } void update(const float& bottomVal, const float& param_e, const float& param_h) { if (first) { lastVal = bottomVal; first = false; } else { if (bottomVal != lastVal)//skip computing if there is no difference { CaretAssert(bottomVal < lastVal); double integrated_h = param_h + 1.0f;//integral(x^h) = (x^(h + 1))/(h + 1) + C double newSlice = pow(totalArea, (double)param_e) * (pow((double)lastVal, integrated_h) - pow((double)bottomVal, integrated_h)) / integrated_h; accumVal += newSlice; lastVal = bottomVal;//computing in double precision, with float for inputs, puts the smallest difference between values far greater than the instability of the computation } } } }; int allocCluster(vector& clusterList, set& deadClusters) { if (deadClusters.empty()) { clusterList.push_back(Cluster()); return (int)(clusterList.size() - 1); } else { set::iterator iter = deadClusters.begin(); int ret = *iter; deadClusters.erase(iter); clusterList[ret] = Cluster();//reinitialize return ret; } } } void AlgorithmMetricTFCE::tfce_pos(TopologyHelper* myHelper, const float* colData, double* accumData, const float* roiData, const float& param_e, const float& param_h, const float* areaData) { int numNodes = myHelper->getNumberOfNodes(); vector membership(numNodes, -1);//int is enough as long as numNodes is fine as an int, for obvious reasons vector clusterList; set deadClusters;//to allow reallocation without changing indices CaretSimpleMaxHeap nodeHeap; for (int i = 0; i < numNodes; ++i) { if ((roiData == NULL || roiData[i] > 0.0f) && colData[i] > 0.0f) { nodeHeap.push(i, colData[i]); } } while (!nodeHeap.isEmpty()) { float value; int node = nodeHeap.pop(&value); const vector& neighbors = myHelper->getNodeNeighbors(node); int numNeigh = (int)neighbors.size(); set touchingClusters; for (int i = 0; i < numNeigh; ++i) { if (membership[neighbors[i]] != -1) { touchingClusters.insert(membership[neighbors[i]]); } } int numTouching = (int)touchingClusters.size(); switch (numTouching) { case 0://make new cluster { int newCluster = allocCluster(clusterList, deadClusters); clusterList[newCluster].addMember(node, value, areaData[node], param_e, param_h); membership[node] = newCluster; break; } case 1://add to cluster { int whichCluster = *(touchingClusters.begin()); clusterList[whichCluster].addMember(node, value, areaData[node], param_e, param_h); membership[node] = whichCluster; accumData[node] -= clusterList[whichCluster].accumVal;//the accum value is the current amount less than the peak value that the edge of the cluster has (this node is on the edge) break;//so, when the cluster merges or reaches 0, we add the accum value to every member and zero the accum value of the merged cluster, and we get the correct value in the end (with far fewer flops than integrating everywhere) } default://merge all touching clusters { int mergedIndex = -1, biggestSize = 0;//find the biggest cluster (in number of members) and use as merged cluster, for optimization purposes for (set::iterator iter = touchingClusters.begin(); iter != touchingClusters.end(); ++iter) { if ((int)clusterList[*iter].members.size() > biggestSize) { mergedIndex = *iter; biggestSize = (int)clusterList[*iter].members.size(); } } CaretAssertVectorIndex(clusterList, mergedIndex); Cluster& mergedCluster = clusterList[mergedIndex]; mergedCluster.update(value, param_e, param_h);//recalculate to align cluster bottoms for (set::iterator iter = touchingClusters.begin(); iter != touchingClusters.end(); ++iter) { if (*iter != mergedIndex)//if we are the largest cluster, don't modify the per-vertex accum for members, so merges between small and large clusters are cheap { Cluster& thisCluster = clusterList[*iter]; thisCluster.update(value, param_e, param_h);//recalculate to align cluster bottoms int numMembers = (int)thisCluster.members.size(); double correctionVal = thisCluster.accumVal - mergedCluster.accumVal;//fix the accum values in the side cluster so we can add the merged cluster's accum to everything at the end for (int j = 0; j < numMembers; ++j)//add the correction value to every member so that we have the current integrated values correct { accumData[thisCluster.members[j]] += correctionVal;//apply the correction membership[thisCluster.members[j]] = mergedIndex;//change the membership lookup } mergedCluster.members.insert(mergedCluster.members.end(), thisCluster.members.begin(), thisCluster.members.end());//copy all members mergedCluster.totalArea += thisCluster.totalArea; deadClusters.insert(*iter);//kill it vector().swap(clusterList[*iter].members);//also try to deallocate member list } } mergedCluster.addMember(node, value, areaData[node], param_e, param_h);//will not trigger recomputation, we already recomputed at this value accumData[node] -= mergedCluster.accumVal;//the vertex they merge on must not get the peak value of the cluster, obviously, so again, record its difference from peak membership[node] = mergedIndex; break;//NOTE: do not reset the accum value of the merged cluster, we specifically avoided modifying the per-vertex accum for its members, so the cluster accum is still in play } } } int listSize = (int)clusterList.size();//final cleanup of accum values for (int i = 0; i < listSize; ++i) { if (deadClusters.find(i) != deadClusters.end()) continue;//ignore clusters that don't exist Cluster& thisCluster = clusterList[i]; thisCluster.update(0.0f, param_e, param_h);//update to include the to-zero slice int numMembers = (int)thisCluster.members.size(); for (int j = 0; j < numMembers; ++j) { accumData[thisCluster.members[j]] += thisCluster.accumVal;//add the resulting slice to all members - their stored data contains the offset between the cluster peak and their corect value } } } float AlgorithmMetricTFCE::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmMetricTFCE::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricTFCE.h000066400000000000000000000043651360521144700244500ustar00rootroot00000000000000#ifndef __ALGORITHM_METRIC_TFCE_H__ #define __ALGORITHM_METRIC_TFCE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class TopologyHelper; class AlgorithmMetricTFCE : public AbstractAlgorithm { AlgorithmMetricTFCE(); void processColumn(const SurfaceFile* mySurf, const float* colData, float* outData, const float* roiData, const float& param_e, const float& param_h, const float* areaData); void tfce_pos(TopologyHelper* myHelper, const float* colData, double* accumData, const float* roiData, const float& param_e, const float& param_h, const float* areaData); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmMetricTFCE(ProgressObject* myProgObj, const SurfaceFile* mySurf, const MetricFile* myMetric, MetricFile* myMetricOut, const float& presmooth = 0.0f, const MetricFile* myRoi = NULL, const float& param_e = 1.0f, const float& param_h = 2.0f, const int& columnNum = -1, const MetricFile* corrAreaMetric = NULL); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmMetricTFCE; } #endif //__ALGORITHM_METRIC_TFCE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricToVolumeMapping.cxx000066400000000000000000000274031360521144700273660ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmMetricToVolumeMapping.h" #include "AlgorithmException.h" #include "CaretAssert.h" #include "CaretOMP.h" #include "CaretPointLocator.h" #include "MetricFile.h" #include "RibbonMappingHelper.h" #include "SurfaceFile.h" #include "VolumeFile.h" #include "VoxelIJK.h" #include using namespace caret; using namespace std; AString AlgorithmMetricToVolumeMapping::getCommandSwitch() { return "-metric-to-volume-mapping"; } AString AlgorithmMetricToVolumeMapping::getShortDescription() { return "MAP METRIC FILE TO VOLUME"; } OperationParameters* AlgorithmMetricToVolumeMapping::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addMetricParameter(1, "metric", "the input metric file"); ret->addSurfaceParameter(2, "surface", "the surface to use coordinates from"); ret->addVolumeParameter(3, "volume-space", "a volume file in the desired output volume space"); ret->addVolumeOutputParameter(4, "volume-out", "the output volume file"); OptionalParameter* nearestVertOpt = ret->createOptionalParameter(5, "-nearest-vertex", "use the value from the vertex closest to the voxel center"); nearestVertOpt->addDoubleParameter(1, "distance", "how far from the surface to map values to voxels, in mm"); OptionalParameter* ribbonOpt = ret->createOptionalParameter(6, "-ribbon-constrained", "use ribbon constrained mapping algorithm"); ribbonOpt->addSurfaceParameter(1, "inner-surf", "the inner surface of the ribbon"); ribbonOpt->addSurfaceParameter(2, "outer-surf", "the outer surface of the ribbon"); OptionalParameter* ribbonSubdivOpt = ribbonOpt->createOptionalParameter(3, "-voxel-subdiv", "voxel divisions while estimating voxel weights"); ribbonSubdivOpt->addIntegerParameter(1, "subdiv-num", "number of subdivisions, default 3"); ribbonOpt->createOptionalParameter(4, "-greedy", "instead of antialiasing partial-volumed voxels, put full metric values (legacy behavior)"); ribbonOpt->createOptionalParameter(5, "-thick-columns", "use overlapping columns (legacy method)"); ret->setHelpText( AString("Maps values from a metric file into a volume file. ") + "You must specify exactly one mapping method option. " + "The -nearest-vertex method uses the value from the vertex closest to the voxel center (useful for integer values). " + "The -ribbon-constrained method uses the same method as in -volume-to-surface-mapping, then uses the weights in reverse. " + "Mapping to lower resolutions than the mesh may require a larger -voxel-subdiv value in order to have all of the surface data participate." ); return ret; } void AlgorithmMetricToVolumeMapping::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { MetricFile* myMetric = myParams->getMetric(1); SurfaceFile* mySurf = myParams->getSurface(2); VolumeFile* myTemplateVol = myParams->getVolume(3); VolumeFile* myVolOut = myParams->getOutputVolume(4); enum Method { INVALID, NEAREST, RIBBON }; bool haveMethod = false; Method myMethod = INVALID; float nearDist = -1.0f; OptionalParameter* nearestVertOpt = myParams->getOptionalParameter(5); if (nearestVertOpt->m_present) { myMethod = NEAREST; haveMethod = true; nearDist = (float)nearestVertOpt->getDouble(1); if (nearDist < 0.0f) { throw AlgorithmException("invalid distance specified"); } } SurfaceFile* innerSurf = NULL, *outerSurf = NULL; int subDivs = 3; bool greedy = false, thick = false; OptionalParameter* ribbonOpt = myParams->getOptionalParameter(6); if (ribbonOpt->m_present) { if (haveMethod) { throw AlgorithmException("more than one mapping method specified"); } myMethod = RIBBON; haveMethod = true; innerSurf = ribbonOpt->getSurface(1); outerSurf = ribbonOpt->getSurface(2); OptionalParameter* ribbonSubdivOpt = ribbonOpt->getOptionalParameter(3); if (ribbonSubdivOpt->m_present) { subDivs = (int)ribbonSubdivOpt->getInteger(1); if (subDivs < 1) { throw AlgorithmException("invalid number of subdivisions specified"); } } greedy = ribbonOpt->getOptionalParameter(4)->m_present; thick = ribbonOpt->getOptionalParameter(5)->m_present; } if (!haveMethod) { throw AlgorithmException("no mapping method specified"); } switch (myMethod) { case NEAREST: AlgorithmMetricToVolumeMapping(myProgObj, myMetric, mySurf, myTemplateVol->getVolumeSpace(), myVolOut, nearDist); break; case RIBBON: AlgorithmMetricToVolumeMapping(myProgObj, myMetric, mySurf, myTemplateVol->getVolumeSpace(), myVolOut, innerSurf, outerSurf, subDivs, greedy, thick); break; case INVALID: CaretAssert(0); throw AlgorithmException("internal error, tell the developers what you just tried to do"); } } AlgorithmMetricToVolumeMapping::AlgorithmMetricToVolumeMapping(ProgressObject* myProgObj, const MetricFile* myMetric, const SurfaceFile* mySurf, const VolumeSpace& myVolSpace, VolumeFile* myVolOut, const float& nearDist) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (myMetric->getNumberOfNodes() != mySurf->getNumberOfNodes()) { throw AlgorithmException("input surface and metric have different number of vertices"); } if (nearDist < 0.0f) { throw AlgorithmException("invalid distance specified in surface to volume mapping"); } checkStructureMatch(myMetric, mySurf->getStructure(), "input metric file", "the surface has"); int numCols = myMetric->getNumberOfColumns(); myVolOut->reinitialize(myVolSpace, numCols); const int64_t* dims = myVolSpace.getDims(); const int64_t frameSize = dims[0] * dims[1] * dims[2]; vector voxelToVertex(frameSize); CaretPointer myLocator = mySurf->getPointLocator(); #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t k = 0; k < dims[2]; ++k) { for (int64_t j = 0; j < dims[1]; ++j) { for (int64_t i = 0; i < dims[0]; ++i) { float voxelCoord[3]; myVolSpace.indexToSpace(i, j, k, voxelCoord); voxelToVertex[myVolSpace.getIndex(i, j, k)] = myLocator->closestPointLimited(voxelCoord, nearDist); } } } vector scratchFrame(frameSize, 0.0f); for (int i = 0; i < numCols; ++i) { const float* metricData = myMetric->getValuePointerForColumn(i); for (int64_t v = 0; v < frameSize; ++v) { if (voxelToVertex[v] >= 0) { scratchFrame[v] = metricData[voxelToVertex[v]]; } } myVolOut->setFrame(scratchFrame.data(), i); myVolOut->setMapName(i, myMetric->getMapName(i)); } } AlgorithmMetricToVolumeMapping::AlgorithmMetricToVolumeMapping(ProgressObject* myProgObj, const MetricFile* myMetric, const SurfaceFile* mySurf, const VolumeSpace& myVolSpace, VolumeFile* myVolOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const int& subDivs, const bool& greedy, const bool& thickColumn) : AbstractAlgorithm(myProgObj) { int numNodes = mySurf->getNumberOfNodes(); if (myMetric->getNumberOfNodes() != numNodes) { throw AlgorithmException("metric and input surfaces have different number of vertices"); } if (!mySurf->hasNodeCorrespondence(*outerSurf) || !mySurf->hasNodeCorrespondence(*innerSurf)) { throw AlgorithmException("all surfaces must have vertex correspondence"); } if (subDivs < 0.0f) { throw AlgorithmException("invalid number of subdivisions specified in surface to volume mapping"); } checkStructureMatch(myMetric, mySurf->getStructure(), "input metric file", "the surface has"); checkStructureMatch(innerSurf, myMetric->getStructure(), "inner surface file", "the metric file has"); checkStructureMatch(outerSurf, myMetric->getStructure(), "outer surface file", "the metric file has"); int numCols = myMetric->getNumberOfColumns(); myVolOut->reinitialize(myVolSpace, numCols); vector > forwardWeights; RibbonMappingHelper::computeWeightsRibbon(forwardWeights, myVolSpace, innerSurf, outerSurf, NULL, subDivs, !thickColumn); map > > reverseWeights; for (int i = 0; i < numNodes; ++i) { for (int v = 0; v < (int)forwardWeights[i].size(); ++v) {//vectors initialize to empty reverseWeights[VoxelIJK(forwardWeights[i][v].ijk)].push_back(pair(i, forwardWeights[i][v].weight)); } } const int64_t* dims = myVolSpace.getDims(); const int64_t frameSize = dims[0] * dims[1] * dims[2]; vector scratchFrame(frameSize, 0.0f); for (int m = 0; m < numCols; ++m) { const float* colData = myMetric->getValuePointerForColumn(m); for (map > >::const_iterator iter = reverseWeights.begin(); iter != reverseWeights.end(); ++iter) { double accum = 0.0, totalWeight = 0.0; for (int i = 0; i < (int)iter->second.size(); ++i) { totalWeight += iter->second[i].second; accum += colData[iter->second[i].first] * iter->second[i].second; } CaretAssert(totalWeight > 0.0);//ribbon mapping should never add weights of 0 to lists if (greedy) { scratchFrame[myVolSpace.getIndex(iter->first.m_ijk)] = accum / totalWeight; } else { float denom = 1.0f;//thin weights are intended to be space filling without overlapping if (thickColumn) denom = 3.0f;//a bit of a hack - ideally, in thick mode every fully covered voxel should have weights sum to 3 if (totalWeight > denom) { denom = totalWeight;//however, the surface contours occasionally occasionally turn the polyhedrons partly inside out, so voxels can sum to more than they theoretically should } scratchFrame[myVolSpace.getIndex(iter->first.m_ijk)] = accum / denom; } } myVolOut->setFrame(scratchFrame.data(), m); myVolOut->setMapName(m, myMetric->getMapName(m)); } } float AlgorithmMetricToVolumeMapping::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmMetricToVolumeMapping::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricToVolumeMapping.h000066400000000000000000000044501360521144700270100ustar00rootroot00000000000000#ifndef __ALGORITHM_METRIC_TO_VOLUME_MAPPING_H__ #define __ALGORITHM_METRIC_TO_VOLUME_MAPPING_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class VolumeSpace; class AlgorithmMetricToVolumeMapping : public AbstractAlgorithm { AlgorithmMetricToVolumeMapping(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: ///nearest vertex AlgorithmMetricToVolumeMapping(ProgressObject* myProgObj, const MetricFile* myMetric, const SurfaceFile* mySurf, const VolumeSpace& myVolSpace, VolumeFile* myVolOut, const float& nearDist); ///ribbon constrained AlgorithmMetricToVolumeMapping(ProgressObject* myProgObj, const MetricFile* myMetric, const SurfaceFile* mySurf, const VolumeSpace& myVolSpace, VolumeFile* myVolOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const int& subDivs = 3, const bool& greedy = false, const bool& thick = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmMetricToVolumeMapping; } #endif //__ALGORITHM_METRIC_TO_VOLUME_MAPPING_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricVectorOperation.cxx000066400000000000000000000203041360521144700274140ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmMetricVectorOperation.h" #include "AlgorithmException.h" #include "CaretLogger.h" #include "MetricFile.h" #include "Vector3D.h" using namespace caret; using namespace std; AString AlgorithmMetricVectorOperation::getCommandSwitch() { return "-metric-vector-operation"; } AString AlgorithmMetricVectorOperation::getShortDescription() { return "DO A VECTOR OPERATION ON METRIC FILES"; } OperationParameters* AlgorithmMetricVectorOperation::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addMetricParameter(1, "vectors-a", "first vector input file"); ret->addMetricParameter(2, "vectors-b", "second vector input file"); ret->addStringParameter(3, "operation", "what vector operation to do"); ret->addMetricOutputParameter(4, "metric-out", "the output file"); ret->createOptionalParameter(5, "-normalize-a", "normalize vectors of first input"); ret->createOptionalParameter(6, "-normalize-b", "normalize vectors of second input"); ret->createOptionalParameter(7, "-normalize-output", "normalize output vectors (not valid for dot product)"); ret->createOptionalParameter(8, "-magnitude", "output the magnitude of the result (not valid for dot product)"); AString myText = AString("Does a vector operation on two metric files (that must have a multiple of 3 columns). ") + "Either of the inputs may have multiple vectors (more than 3 columns), but not both (at least one must have exactly 3 columns). " + "The -magnitude and -normalize-output options may not be specified together, or with an operation that returns a scalar (dot product). " + "The parameter must be one of the following:\n"; vector opList = VectorOperation::getAllOperations(); for (int i = 0; i < (int)opList.size(); ++i) { myText += "\n" + VectorOperation::operationToString(opList[i]); } ret->setHelpText(myText); return ret; } void AlgorithmMetricVectorOperation::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { MetricFile* metricA = myParams->getMetric(1); MetricFile* metricB = myParams->getMetric(2); AString operString = myParams->getString(3); bool ok = false; VectorOperation::Operation myOper = VectorOperation::stringToOperation(operString, ok); if (!ok) throw AlgorithmException("unrecognized operation string: " + operString); MetricFile* myMetricOut = myParams->getOutputMetric(4); bool normA = myParams->getOptionalParameter(5)->m_present; bool normB = myParams->getOptionalParameter(6)->m_present; bool normOut = myParams->getOptionalParameter(7)->m_present; bool magOut = myParams->getOptionalParameter(8)->m_present; AlgorithmMetricVectorOperation(myProgObj, metricA, metricB, myOper, myMetricOut, normA, normB, normOut, magOut); } AlgorithmMetricVectorOperation::AlgorithmMetricVectorOperation(ProgressObject* myProgObj, const MetricFile* metricA, const MetricFile* metricB, const VectorOperation::Operation& myOper, MetricFile* myMetricOut, const bool& normA, const bool& normB, const bool& normOut, const bool& magOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); StructureEnum::Enum checkStruct = metricA->getStructure(); int numNodes = metricA->getNumberOfNodes(); if (numNodes != metricB->getNumberOfNodes()) throw AlgorithmException("inputs have different numbers of nodes"); int numColA = metricA->getNumberOfColumns(), numColB = metricB->getNumberOfColumns(); if (numColA % 3 != 0) throw AlgorithmException("number of columns of first input is not a multiple of 3"); if (numColB % 3 != 0) throw AlgorithmException("number of columns of second input is not a multiple of 3"); int numVecA = numColA / 3, numVecB = numColB / 3; if (numVecA > 1 && numVecB > 1) throw AlgorithmException("both inputs have more than 3 columns (more than 1 vector)"); if (normOut && magOut) throw AlgorithmException("normalizing the output and taking the magnitude is meaningless"); bool opScalarResult = VectorOperation::operationReturnsScalar(myOper); if (opScalarResult && (normOut || magOut)) throw AlgorithmException("cannot normalize or take magnitude of a scalar result (such as a dot product)"); if (checkStruct == StructureEnum::INVALID) { CaretLogWarning("first input vector file has INVALID structure"); } else { checkStructureMatch(metricB, checkStruct, "second input vector file", "the first has"); } bool swapped = false; const MetricFile* multiVec = metricA, *singleVec = metricB; int numOutVecs = numVecA; if (numVecB > 1) { multiVec = metricB; singleVec = metricA; numOutVecs = numVecB; swapped = true; } int numColsOut = numOutVecs * 3; if (opScalarResult || magOut) numColsOut = numOutVecs; myMetricOut->setNumberOfNodesAndColumns(numNodes, numColsOut); myMetricOut->setStructure(checkStruct); vector outCols[3];//let the scalar result case overallocate outCols[0].resize(numNodes); outCols[1].resize(numNodes); outCols[2].resize(numNodes); const float* xColSingle = singleVec->getValuePointerForColumn(0); const float* yColSingle = singleVec->getValuePointerForColumn(1); const float* zColSingle = singleVec->getValuePointerForColumn(2); for (int v = 0; v < numOutVecs; ++v) { const float* xColMulti = multiVec->getValuePointerForColumn(v * 3); const float* yColMulti = multiVec->getValuePointerForColumn(v * 3 + 1); const float* zColMulti = multiVec->getValuePointerForColumn(v * 3 + 2); for (int i = 0; i < numNodes; ++i) { Vector3D vecA(xColMulti[i], yColMulti[i], zColMulti[i]); Vector3D vecB(xColSingle[i], yColSingle[i], zColSingle[i]); if (swapped) { Vector3D tempVec = vecA; vecA = vecB; vecB = tempVec; } if (normA) vecA = vecA.normal(); if (normB) vecB = vecB.normal(); if (opScalarResult) { outCols[0][i] = VectorOperation::doScalarOperation(vecA, vecB, myOper); } else { Vector3D tempVec = VectorOperation::doVectorOperation(vecA, vecB, myOper); if (normOut) tempVec = tempVec.normal(); if (magOut) { outCols[0][i] = tempVec.length(); } else { outCols[0][i] = tempVec[0]; outCols[1][i] = tempVec[1]; outCols[2][i] = tempVec[2]; } } } if (opScalarResult || magOut) { myMetricOut->setValuesForColumn(v, outCols[0].data()); } else { myMetricOut->setValuesForColumn(v * 3, outCols[0].data()); myMetricOut->setValuesForColumn(v * 3 + 1, outCols[1].data()); myMetricOut->setValuesForColumn(v * 3 + 2, outCols[2].data()); } } } float AlgorithmMetricVectorOperation::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmMetricVectorOperation::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricVectorOperation.h000066400000000000000000000037141360521144700270470ustar00rootroot00000000000000#ifndef __ALGORITHM_METRIC_VECTOR_OPERATION_H__ #define __ALGORITHM_METRIC_VECTOR_OPERATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "VectorOperation.h" namespace caret { class AlgorithmMetricVectorOperation : public AbstractAlgorithm { AlgorithmMetricVectorOperation(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmMetricVectorOperation(ProgressObject* myProgObj, const MetricFile* metricA, const MetricFile* metricB, const VectorOperation::Operation& myOper, MetricFile* myMetricOut, const bool& normA = false, const bool& normB = false, const bool& normOut = false, const bool& magOut = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmMetricVectorOperation; } #endif //__ALGORITHM_METRIC_VECTOR_OPERATION_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricVectorTowardROI.cxx000066400000000000000000000133731360521144700272760ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmMetricVectorTowardROI.h" #include "AlgorithmException.h" #include "CaretOMP.h" #include "GeodesicHelper.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "Vector3D.h" #include using namespace caret; using namespace std; AString AlgorithmMetricVectorTowardROI::getCommandSwitch() { return "-metric-vector-toward-roi"; } AString AlgorithmMetricVectorTowardROI::getShortDescription() { return "FIND IF VECTORS POINT TOWARD AN ROI"; } OperationParameters* AlgorithmMetricVectorTowardROI::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to compute on"); ret->addMetricParameter(2, "target-roi", "the roi to find the shortest path to"); ret->addMetricOutputParameter(3, "metric-out", "the output metric"); OptionalParameter* roiOpt = ret->createOptionalParameter(4, "-roi", "don't compute for vertices outside an roi"); roiOpt->addMetricParameter(1, "roi-metric", "the region to compute inside, as a metric"); ret->setHelpText( AString("At each vertex, compute the vector along the start of the shortest path to the ROI.") ); return ret; } void AlgorithmMetricVectorTowardROI::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* mySurf = myParams->getSurface(1); MetricFile* targetRoi = myParams->getMetric(2); MetricFile* myMetricOut = myParams->getOutputMetric(3); MetricFile* computeRoi = NULL; OptionalParameter* roiOpt = myParams->getOptionalParameter(4); if (roiOpt->m_present) { computeRoi = roiOpt->getMetric(1); } AlgorithmMetricVectorTowardROI(myProgObj, mySurf, targetRoi, myMetricOut, computeRoi); } AlgorithmMetricVectorTowardROI::AlgorithmMetricVectorTowardROI(ProgressObject* myProgObj, SurfaceFile* mySurf, const MetricFile* targetRoi, MetricFile* myMetricOut, const MetricFile* computeRoi) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int numNodes = mySurf->getNumberOfNodes(); if (targetRoi->getNumberOfNodes() != numNodes) throw AlgorithmException("target roi and surface have different number of vertices"); const float* computeRoiCol = NULL; if (computeRoi != NULL) { if (computeRoi->getNumberOfNodes() != numNodes) throw AlgorithmException("compute roi and surface have different number of vertices"); computeRoiCol = computeRoi->getValuePointerForColumn(0); } mySurf->computeNormals(); const float* myNormals = mySurf->getNormalData(); myMetricOut->setNumberOfNodesAndColumns(numNodes, 3); myMetricOut->setStructure(mySurf->getStructure()); vector roiConvert(numNodes, 0); const float* coordData = mySurf->getCoordinateData(); const float* targetData = targetRoi->getValuePointerForColumn(0); bool haveTarget = false; vector outCol[3]; outCol[0].resize(numNodes, 0.0f); outCol[1].resize(numNodes, 0.0f); outCol[2].resize(numNodes, 0.0f); for (int i = 0; i < numNodes; ++i) { if (targetData[i] > 0.0f) { roiConvert[i] = 1; haveTarget = true; } } if (!haveTarget) throw AlgorithmException("target roi is empty"); #pragma omp CARET_PAR { CaretPointer myGeoHelp = mySurf->getGeodesicHelper(); #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < numNodes; ++i) { if (computeRoiCol == NULL || computeRoiCol[i] > 0.0f) { Vector3D normal = Vector3D(myNormals + i * 3).normal();//ensure unit length, just in case vector pathNodes; vector pathDists; myGeoHelp->getClosestNodeInRoi(i, roiConvert.data(), pathNodes, pathDists, true);//not using smooth will make noisier results, project via normal to avoid curvature problems if (pathNodes.size() < 2)//no path found, or node is inside the target roi { continue;//will already be zero } Vector3D pathVec = Vector3D(coordData + pathNodes[1] * 3) - Vector3D(coordData + i * 3); Vector3D pathProject = (pathVec - pathVec.dot(normal) * normal).normal();//the path vector is a direction only, just normalize after projection outCol[0][i] = pathProject[0]; outCol[1][i] = pathProject[1]; outCol[2][i] = pathProject[2]; } } } myMetricOut->setValuesForColumn(0, outCol[0].data()); myMetricOut->setValuesForColumn(1, outCol[1].data()); myMetricOut->setValuesForColumn(2, outCol[2].data()); } float AlgorithmMetricVectorTowardROI::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmMetricVectorTowardROI::getSubAlgorithmWeight() { return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmMetricVectorTowardROI.h000066400000000000000000000034711360521144700267210ustar00rootroot00000000000000#ifndef __ALGORITHM_METRIC_VECTOR_TOWARD_ROI_H__ #define __ALGORITHM_METRIC_VECTOR_TOWARD_ROI_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmMetricVectorTowardROI : public AbstractAlgorithm { AlgorithmMetricVectorTowardROI(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmMetricVectorTowardROI(ProgressObject* myProgObj, SurfaceFile* mySurf, const MetricFile* targetRoi, MetricFile* myMetricOut, const MetricFile* computeRoi = NULL); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmMetricVectorTowardROI; } #endif //__ALGORITHM_METRIC_VECTOR_TOWARD_ROI_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmNodesInsideBorder.cxx000066400000000000000000001033511360521144700264730ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "AlgorithmNodesInsideBorder.h" #include "AlgorithmException.h" #include "Border.h" #include "BorderFile.h" #include "CaretAssert.h" #include "CaretOMP.h" #include "CiftiBrainordinateLabelFile.h" #include "CiftiBrainordinateScalarFile.h" #include "CiftiFile.h" #include "GeodesicHelper.h" #include "LabelFile.h" #include "MathFunctions.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "SurfaceProjectedItem.h" #include "TopologyHelper.h" using namespace caret; using namespace std; AString AlgorithmNodesInsideBorder::getCommandSwitch() { return "-border-to-rois";//maybe the command should be in a separate file, and the nodes inside border code should be a helper class? } AString AlgorithmNodesInsideBorder::getShortDescription() { return "MAKE METRIC ROIS FROM BORDERS"; } OperationParameters* AlgorithmNodesInsideBorder::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface the borders are drawn on"); ret->addBorderParameter(2, "border-file", "the border file"); ret->addMetricOutputParameter(3, "metric-out", "the output metric file"); OptionalParameter* borderOpt = ret->createOptionalParameter(4, "-border", "create ROI for only one border"); borderOpt->addStringParameter(1, "name", "the name of the border"); ret->createOptionalParameter(5, "-inverse", "use inverse selection (outside border)"); ret->createOptionalParameter(6, "-include-border", "include vertices the border is closest to"); ret->setHelpText( AString("By default, draws ROIs inside all borders in the border file, as separate metric columns.") ); return ret; } void AlgorithmNodesInsideBorder::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); SurfaceFile* mySurf = myParams->getSurface(1); BorderFile* myBorderFile = myParams->getBorder(2); MetricFile* myMetricOut = myParams->getOutputMetric(3); OptionalParameter* borderOpt = myParams->getOptionalParameter(4); bool inverse = myParams->getOptionalParameter(5)->m_present; bool includeBorder = myParams->getOptionalParameter(6)->m_present; int numNodes = mySurf->getNumberOfNodes(); if (mySurf->getStructure() == StructureEnum::INVALID) throw AlgorithmException("surface file needs a valid structure to find the correct borders in the file"); if (myBorderFile->getNumberOfNodes() > 0)//-1 number of nodes is the signal that this is an old-format, potentially multistructure border file { if (myBorderFile->getStructure() != mySurf->getStructure()) throw AlgorithmException("border file and surface file have different structures"); if (myBorderFile->getNumberOfNodes() != numNodes) throw AlgorithmException("border file and surface file have different number of vertices"); } if (borderOpt->m_present) { AString findName = borderOpt->getString(1); int numBorders = myBorderFile->getNumberOfBorders(); vector scratchCol(numNodes, (inverse ? 1.0f : 0.0f)); bool found = false; for (int i = 0; i < numBorders; ++i) { const Border* thisBorder = myBorderFile->getBorder(i); if (thisBorder->getName() == findName && thisBorder->getStructure() == mySurf->getStructure()) { found = true;//don't use inverse in this call, because we need to merge results, and having them inverted first would just make things more confusing vector insideNodes = findNodesInsideBorder(mySurf, thisBorder, false, includeBorder); for (int index = 0; index < (int)insideNodes.size(); ++index) { scratchCol[insideNodes[index]] = (inverse ? 0.0f : 1.0f); } } } if (!found) throw AlgorithmException("border name not found for surface structure"); myMetricOut->setNumberOfNodesAndColumns(mySurf->getNumberOfNodes(), 1); myMetricOut->setStructure(mySurf->getStructure()); myMetricOut->setColumnName(0, findName); myMetricOut->setValuesForColumn(0, scratchCol.data()); } else { int numBorderParts = myBorderFile->getNumberOfBorders(); map, int> borderCounter;//for grouping border parts with this structure into borders, with indexes into borderPartGroups vector > borderPartGroups;//stores the border parts of borders, in order of first part encountered in file for (int i = 0; i < numBorderParts; ++i) { const Border* thisBorder = myBorderFile->getBorder(i); if (thisBorder->getStructure() == mySurf->getStructure()) { map, int>::iterator iter = borderCounter.find(make_pair(thisBorder->getName(), thisBorder->getClassName())); if (iter == borderCounter.end()) { borderCounter[make_pair(thisBorder->getName(), thisBorder->getClassName())] = (int)borderPartGroups.size(); borderPartGroups.push_back(vector(1, i)); } else { borderPartGroups[iter->second].push_back(i); } } } int numBorders = (int)borderPartGroups.size(); if (numBorders == 0) throw AlgorithmException("no borders match the structure of the surface"); myMetricOut->setNumberOfNodesAndColumns(numNodes, numBorders); myMetricOut->setStructure(mySurf->getStructure()); #pragma omp CARET_PARFOR schedule(dynamic) for (int i = 0; i < numBorders; ++i)//parallel mainly because the method used to be inefficient (repeatedly uses geodesic to full surface) { myMetricOut->setColumnName(i, myBorderFile->getBorder(borderPartGroups[i][0])->getName());//should be safe to do in parallel vector scratchCol(numNodes, (inverse ? 1.0f : 0.0f)); int numParts = (int)borderPartGroups[i].size(); for (int j = 0; j < numParts; ++j) { const Border* thisBorder = myBorderFile->getBorder(borderPartGroups[i][j]); vector insideNodes = findNodesInsideBorder(mySurf, thisBorder, false, includeBorder); for (int index = 0; index < (int)insideNodes.size(); ++index) { scratchCol[insideNodes[index]] = (inverse ? 0.0f : 1.0f); } } myMetricOut->setValuesForColumn(i, scratchCol.data());//ditto } } } /** * \class caret::AlgorithmNodesInsideBorder * \brief Assign attribute values to nodes within a closed border. * * Identify nodes within a closed border and assign scalar or * label values to those nodes. * * Identifying nodes within a border can be troublesome for several reasons. * (1) Some borders are very narrow and opposite sides of a border may * be adjacent (like a figure eight) such that there are multiple closed * regions. (2) Borders may self intersect. (3) One end of a border may * overlay the other end of the border. (4) Combinations of 1, 2, and/or 3. * * The original implementation of this algorithm assumed the border was * oriented in a counter-clockwise orientation: * (1) Identified a node to the left (inside) the border and filled * the region using the border as a boundary. * (2) If the number of selected nodes was greater than half then number * of nodes in the surface, it indicated that the border must have been * a clockwise orientation and the node selection was inverted. * * Corrections were made for a couple of the problems listed above but * when combinations of the problems were present the algorithm failed. * * Since finding nodes inside a border was too challenging, it was realized * that finding nodes outside a border was much easier. So, the algorithm * was re-written to identify nodes outside the border and then the selection * is inverted. * (1) Find the center of gravity (average coordinate) of the border. * (2) Find the surface node furthest from the border's center of gravity. * (3) Perform a connected fill operation but stopping anytime a border * node is encountered. * (4) Invert the selection (verifying that the selected number of nodes * is greater than half the number of nodes in the surface). */ /** * Constructor. * * @param myProgObj * * @param surfaceFile * Surface file for nodes inside border. * @param border * Border for which nodes inside are found. * @param isInverseSelection * Invert the selection. * @param assignToMetricMapIndex * Map index in metric file to which assigments are made for * nodes inside the border. * @param assignMetricValue * Metric value assigned to nodes within the border. * @param metricFileInOut * Metric file that has map set with nodes inside border. */ AlgorithmNodesInsideBorder::AlgorithmNodesInsideBorder(ProgressObject* myProgObj, const SurfaceFile* surfaceFile, const Border* border, const bool isInverseSelection, const int32_t assignToMetricMapIndex, const float assignMetricValue, MetricFile* metricFileInOut, const bool& includeBorder) : AbstractAlgorithm(myProgObj) { CaretAssert(surfaceFile); CaretAssert(border); CaretAssert(metricFileInOut); if (surfaceFile->getNumberOfNodes() != metricFileInOut->getNumberOfNodes()) throw AlgorithmException("metric file must be initialized to same number of nodes");//a method that requires this really shouldn't be public std::vector nodesInsideBorder = findNodesInsideBorder(surfaceFile, border, isInverseSelection, includeBorder); const int32_t numberOfNodesInsideBorder = static_cast(nodesInsideBorder.size()); for (int32_t i = 0; i < numberOfNodesInsideBorder; i++) { const int32_t nodeNumber = nodesInsideBorder[i]; metricFileInOut->setValue(nodeNumber, assignToMetricMapIndex, assignMetricValue); } } /** * Constructor. * * @param myProgObj * * @param surfaceFile * Surface file for nodes inside border. * @param border * Border for which nodes inside are found. * @param isInverseSelection * Invert the selection. * @param assignToLabelMapIndex * Map index in label file to which assigments are made for * nodes inside the border. * @param assignLabelKey * Label key assigned to nodes within the border. * @param labelFileInOut * Label file that has map set with nodes inside border. */ AlgorithmNodesInsideBorder::AlgorithmNodesInsideBorder(ProgressObject* myProgObj, const SurfaceFile* surfaceFile, const Border* border, const bool isInverseSelection, const int32_t assignToLabelMapIndex, const int32_t assignLabelKey, LabelFile* labelFileInOut, const bool& includeBorder) : AbstractAlgorithm(myProgObj) { CaretAssert(surfaceFile); CaretAssert(border); CaretAssert(labelFileInOut); if (surfaceFile->getNumberOfNodes() != labelFileInOut->getNumberOfNodes()) throw AlgorithmException("metric file must be initialized to same number of nodes");//a method that requires this really shouldn't be public std::vector nodesInsideBorder = findNodesInsideBorder(surfaceFile, border, isInverseSelection, includeBorder); const int32_t numberOfNodesInsideBorder = static_cast(nodesInsideBorder.size()); for (int32_t i = 0; i < numberOfNodesInsideBorder; i++) { const int32_t nodeNumber = nodesInsideBorder[i]; labelFileInOut->setLabelKey(nodeNumber, assignToLabelMapIndex, assignLabelKey); } } /** * Constructor. * * @param myProgObj * * @param surfaceFile * Surface file for nodes inside border. * @param border * Border for which nodes inside are found. * @param isInverseSelection * Invert the selection. * @param assignToCiftiScalarMapIndex * Map index in cifti scalar file to which assigments are made for * nodes inside the border. * @param assignScalarValue * Scalar value assigned to nodes within the border. * @param ciftiScalarFileInOut * CIFTI scalar file that has map set with nodes inside border. */ AlgorithmNodesInsideBorder::AlgorithmNodesInsideBorder(ProgressObject* myProgObj, const SurfaceFile* surfaceFile, const Border* border, const bool isInverseSelection, const int32_t assignToCiftiScalarMapIndex, const float assignScalarValue, CiftiBrainordinateScalarFile* ciftiScalarFileInOut, const bool& includeBorder) : AbstractAlgorithm(myProgObj) { CaretAssert(surfaceFile); CaretAssert(border); CaretAssert(ciftiScalarFileInOut); std::vector nodesInsideBorder = findNodesInsideBorder(surfaceFile, border, isInverseSelection, includeBorder); std::vector surfaceMapData(surfaceFile->getNumberOfNodes(), 0.0); const int32_t numberOfNodesInsideBorder = static_cast(nodesInsideBorder.size()); for (int32_t i = 0; i < numberOfNodesInsideBorder; i++) { const int32_t nodeIndex = nodesInsideBorder[i]; CaretAssertVectorIndex(surfaceMapData, nodeIndex); surfaceMapData[nodeIndex] = assignScalarValue; } ciftiScalarFileInOut->setMapDataForSurface(assignToCiftiScalarMapIndex, surfaceFile->getStructure(), surfaceMapData); } /** * Constructor. * * @param myProgObj * * @param surfaceFile * Surface file for nodes inside border. * @param border * Border for which nodes inside are found. * @param isInverseSelection * Invert the selection. * @param assignToCiftiScalarMapIndex * Map index in cifti scalar file to which assigments are made for * nodes inside the border. * @param assignLabelKey * Label key assigned to nodes within the border. * @param ciftiLabelFileInOut * CIFTI label file that has map set with nodes inside border. */ AlgorithmNodesInsideBorder::AlgorithmNodesInsideBorder(ProgressObject* myProgObj, const SurfaceFile* surfaceFile, const Border* border, const bool isInverseSelection, const int32_t assignToCiftiLabelMapIndex, const int32_t assignLabelKey, CiftiBrainordinateLabelFile* ciftiLabelFileInOut, const bool& includeBorder) : AbstractAlgorithm(myProgObj) { CaretAssert(surfaceFile); CaretAssert(border); CaretAssert(ciftiLabelFileInOut); std::vector nodesInsideBorder = this->findNodesInsideBorder(surfaceFile, border, isInverseSelection, includeBorder); std::vector surfaceMapData(surfaceFile->getNumberOfNodes(), 0.0); const int32_t numberOfNodesInsideBorder = static_cast(nodesInsideBorder.size()); for (int32_t i = 0; i < numberOfNodesInsideBorder; i++) { const int32_t nodeIndex = nodesInsideBorder[i]; CaretAssertVectorIndex(surfaceMapData, nodeIndex); surfaceMapData[nodeIndex] = assignLabelKey; } ciftiLabelFileInOut->setMapDataForSurface(assignToCiftiLabelMapIndex, surfaceFile->getStructure(), surfaceMapData); } /** * Constructor for getting a vector containing indices of nodes inside * the border. * * @param myProgObj * * @param surfaceFile * Surface file for nodes inside border. * @param border * Border for which nodes inside are found. * @param isInverseSelection * Invert the selection. * @param assignToCiftiScalarMapIndex * Map index in cifti scalar file to which assigments are made for * nodes inside the border. * @param assignLabelKey * Label key assigned to nodes within the border. * @param ciftiLabelFileInOut * CIFTI label file that has map set with nodes inside border. */ AlgorithmNodesInsideBorder::AlgorithmNodesInsideBorder(ProgressObject* myProgObj, const SurfaceFile* surfaceFile, const Border* border, const bool isInverseSelection, std::vector& nodesInsideBorderOut, const bool& includeBorder) : AbstractAlgorithm(myProgObj) { CaretAssert(surfaceFile); CaretAssert(border); nodesInsideBorderOut = this->findNodesInsideBorder(surfaceFile, border, isInverseSelection, includeBorder); } std::vector AlgorithmNodesInsideBorder::findNodesInsideBorder(const SurfaceFile* mySurf, const Border* myBorder, const bool& inverse, const bool& includeBorder) { std::vector nodesInsideBorderOut; if (myBorder->getNumberOfPoints() == 0) return nodesInsideBorderOut;//we could throw, but whatever /* * Move border points to the nearest nodes. */ std::vector unconnectedNodesPath = moveBorderPointsToNearestNodes(mySurf, myBorder); /* * Convert the unconnected nodes path into a connected nodes path */ std::vector connectedNodesPath = createConnectedNodesPath(mySurf, myBorder, unconnectedNodesPath); int32_t numberOfNodesInConnectedPath = static_cast(connectedNodesPath.size()); if (numberOfNodesInConnectedPath < 1) { throw AlgorithmException("Connected path contains no vertices."); } /* * Find nodes that are OUTSIDE the connected path */ std::vector nodesOutsidePath = findNodesOutsideOfConnectedPath(mySurf, connectedNodesPath); /* * Identify nodes INSIDE the connected path */ const int32_t numberOfSurfaceNodes = mySurf->getNumberOfNodes(); std::vector nodeInsideRegionFlags(numberOfSurfaceNodes, true); const int32_t numberOfNodesOutsidePath = static_cast(nodesOutsidePath.size()); for (int32_t i = 0; i < numberOfNodesOutsidePath; i++) { const int32_t nodeIndex = nodesOutsidePath[i]; CaretAssertVectorIndex(nodeInsideRegionFlags, nodeIndex); nodeInsideRegionFlags[nodeIndex] = false; } /* * Handle inverse selection or possibility outside selection was * accidentally inside selection */ bool doInverseFlag = inverse; const int32_t halfNumberOfSurfaceNodes = numberOfSurfaceNodes / 2; if (numberOfNodesOutsidePath < halfNumberOfSurfaceNodes) { doInverseFlag = ( ! doInverseFlag); } const CaretPointer th = mySurf->getTopologyHelper(); /* * Identify nodes */ for (int32_t i = 0; i < numberOfSurfaceNodes; i++) { bool insideFlag = nodeInsideRegionFlags[i]; if (doInverseFlag) { insideFlag = ( ! insideFlag); } if (th->getNodeHasNeighbors(i)) { if (std::find(connectedNodesPath.begin(), connectedNodesPath.end(), i) != connectedNodesPath.end()) { insideFlag = includeBorder; } } else { insideFlag = false; } if (insideFlag) { nodesInsideBorderOut.push_back(i); } } return nodesInsideBorderOut; } std::vector AlgorithmNodesInsideBorder::moveBorderPointsToNearestNodes(const SurfaceFile* mySurf, const Border* myBorder) { std::vector nodeIndicesFollowingBorder; /* * Move border points to the nearest nodes. */ const int32_t originalNumberOfBorderPoints = myBorder->getNumberOfPoints(); for (int32_t i = 0; i < originalNumberOfBorderPoints; i++) { const SurfaceProjectedItem* spi = myBorder->getPoint(i); float xyz[3]; if (spi->getProjectedPosition(*mySurf, xyz, true)) { const int32_t nearestNode = mySurf->closestNode(xyz); if (nearestNode >= 0) { nodeIndicesFollowingBorder.push_back(nearestNode); } } } CaretAssert(myBorder->getNumberOfPoints() == (int)nodeIndicesFollowingBorder.size());//required for the connecting code to use following line segment logic return nodeIndicesFollowingBorder; } std::vector AlgorithmNodesInsideBorder::createConnectedNodesPath(const SurfaceFile* mySurf, const Border* myBorder, const std::vector& unconnectedNodesPath) { std::vector connectedNodesPathOut; /* * Geodesic helper for surface */ CaretPointer geodesicHelper = mySurf->getGeodesicHelper(); /* * Get the topology helper for the surface */ CaretPointer th = mySurf->getTopologyHelper(); /* * Find connected path along node neighbors */ const int32_t numberOfNodesInUnconnectedPath = static_cast(unconnectedNodesPath.size()); for (int32_t i = 0; i < numberOfNodesInUnconnectedPath; i++) { const int node = unconnectedNodesPath[i]; connectedNodesPathOut.push_back(node); int nextIndex = -1; const bool lastNodeFlag = (i >= (numberOfNodesInUnconnectedPath - 1)); if (lastNodeFlag) { nextIndex = 0; } else { nextIndex = i + 1; } int nextNode = unconnectedNodesPath[nextIndex]; /*if (node != nextNode) { bool doGeodesicSearch = true; const std::vector neighbors = th->getNodeNeighbors(node); if (std::find(neighbors.begin(), neighbors.end(), nextNode) != neighbors.end()) { connectedNodesPathOut.push_back(nextNode); doGeodesicSearch = false; } if (doGeodesicSearch) { std::vector distances; std::vector parentNodes; geodesicHelper->getGeoFromNode(node, distances, parentNodes, false); bool doneFlag = false; std::vector pathFromNextNodeToNode; int32_t pathNode = nextNode; while (doneFlag == false) { int32_t nextPathNode = parentNodes[pathNode]; if (nextPathNode >= 0) { if (nextPathNode == node) { doneFlag = true; } else { pathFromNextNodeToNode.push_back(nextPathNode); } } else { doneFlag = true; } if (doneFlag == false) { pathNode = nextPathNode; } } const int32_t numberOfPathNodes = static_cast(pathFromNextNodeToNode.size()); for (int32_t i = (numberOfPathNodes - 1); i >= 0; i--) { connectedNodesPathOut.push_back(pathFromNextNodeToNode[i]); } } }//*/ vector path; vector dists; Vector3D nodePos, nextPos; myBorder->getPoint(i)->getProjectedPosition(*mySurf, nodePos, true);//really means unproject myBorder->getPoint(nextIndex)->getProjectedPosition(*mySurf, nextPos, true); geodesicHelper->getPathAlongLineSegment(node, nextNode, nodePos, nextPos, path, dists); connectedNodesPathOut.insert(connectedNodesPathOut.end(), path.begin(), path.end()); } /* * Remove duplicates. */ cleanNodePath(connectedNodesPathOut); /* * Valid that the path nodes are connected. */ validateConnectedNodesPath(mySurf, connectedNodesPathOut); return connectedNodesPathOut; } /** * Find the nodes OUTSIDE the given connected path. * * @param connectedNodesPath * Connected path for which nodes inside are found. * @param nodesOutsidePathOut * Vector into which nodes OUTSIDE connected path are loaded. */ std::vector AlgorithmNodesInsideBorder::findNodesOutsideOfConnectedPath(const SurfaceFile* mySurf, const std::vector& connectedNodesPath) { std::vector nodesOutsidePathOut; /* * Track nodes that are found inside and/or have been visited. */ const int32_t numberOfNodes = mySurf->getNumberOfNodes(); std::vector nodeSearchStatus(numberOfNodes, 0); std::vector insideBorderFlag(numberOfNodes, false); /* * Mark all nodes in connected path as visited. */ const int32_t numberOfNodesInConnectedPath = static_cast(connectedNodesPath.size()); for (int32_t i = 0; i < numberOfNodesInConnectedPath; i++) { CaretAssertVectorIndex(nodeSearchStatus, connectedNodesPath[i]); nodeSearchStatus[connectedNodesPath[i]] = 1; } /* * Get the topology helper for the surface with neighbors sorted. */ CaretPointer th = mySurf->getTopologyHelper(true); /* * Find the node that is furthest from the connected path's * center of gravity (average coordinate) */ int32_t startNode = findNodeFurthestFromConnectedPathCenterOfGravity(mySurf, connectedNodesPath, nodeSearchStatus); if (startNode < 0) { throw AlgorithmException("Failed to find vertex that is not inside of the connected path."); } /* * Mark the starting node as 'inside'. */ CaretAssertVectorIndex(insideBorderFlag, startNode); insideBorderFlag[startNode] = true; /* * Use a stack to help with search. */ std::stack stack; stack.push(startNode); /* * Search until no more to search. */ while (stack.empty() == false) { const int32_t nodeNumber = stack.top(); stack.pop(); /* * Has node been visited? */ CaretAssertVectorIndex(nodeSearchStatus, nodeNumber); if (nodeSearchStatus[nodeNumber] == 0) { nodeSearchStatus[nodeNumber] = 1; /* * Set node as inside */ CaretAssertVectorIndex(insideBorderFlag, nodeNumber); insideBorderFlag[nodeNumber] = true; /* * Get neighbors of this node */ int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(nodeNumber, numNeighbors); /* * add neighbors to search */ for (int i = 0; i < numNeighbors; i++) { const int neighborNode = neighbors[i]; CaretAssertVectorIndex(nodeSearchStatus, neighborNode); if (nodeSearchStatus[neighborNode] != 1) { stack.push(neighborNode); } } } } /* * Return nodes inside the path */ int32_t insideCount = 0; for (int32_t i = 0; i < numberOfNodes; i++) { CaretAssertVectorIndex(insideBorderFlag, i); if (insideBorderFlag[i]) { nodesOutsidePathOut.push_back(i); insideCount++; } } return nodesOutsidePathOut; } /** * Find an unvisited node that is FURTHEST from the center-of-gravity of * the the nodes in the connected path. * * @param connectedNodesPath * Path of connected nodes. * @param nodeSearchStatus * Search status of the nodes. */ int32_t AlgorithmNodesInsideBorder::findNodeFurthestFromConnectedPathCenterOfGravity(const SurfaceFile* mySurf, const std::vector& connectedNodesPath, std::vector& nodeSearchStatus) { double sumX = 0.0; double sumY = 0.0; double sumZ = 0.0; double sumCount = 0.0; const int32_t numberOfNodesInConnectedPath = static_cast(connectedNodesPath.size()); for (int32_t i = 1; i < (numberOfNodesInConnectedPath - 1); i++) { const float* xyz = mySurf->getCoordinate(connectedNodesPath[i]); sumX += xyz[0]; sumY += xyz[1]; sumZ += xyz[2]; sumCount++; } if (sumCount >= 1.0) { const float cog[3] = { (float)(sumX / sumCount), (float)(sumY / sumCount), (float)(sumZ / sumCount) }; /* * Get the topology helper for the surface with neighbors sorted. */ CaretPointer topologyHelper = mySurf->getTopologyHelper(true); float maxDist = -1.0; int32_t maxDistNodeIndex = -1; const int32_t numberOfNodes = mySurf->getNumberOfNodes(); for (int32_t i = 0; i < numberOfNodes; i++) { if (nodeSearchStatus[i] == 0) { if (topologyHelper->getNodeHasNeighbors(i)) { const float* coordXYZ = mySurf->getCoordinate(i); const float distSQ = MathFunctions::distanceSquared3D(cog, coordXYZ); if (distSQ > maxDist) { maxDist = distSQ; maxDistNodeIndex = i; } } } } return maxDistNodeIndex; } return -1; } /** * Clean the path by removing any consecutive nodes that are identical. * * @param nodePath * Path that is cleaned. */ void AlgorithmNodesInsideBorder::cleanNodePath(std::vector& nodePath) { std::vector path = nodePath; nodePath.clear(); /* * Unique copy will remove consecutive identical elements */ std::unique_copy(path.begin(), path.end(), back_inserter(nodePath)); } /** * Verify that the connect nodes path is fully connected. * * @param connectedNodesPath * Path that is validated. */ void AlgorithmNodesInsideBorder::validateConnectedNodesPath(const SurfaceFile* mySurf, const std::vector& connectedNodesPath) { /* * Get the topology helper for the surface with neighbors sorted. */ CaretPointer th = mySurf->getTopologyHelper(false); /* * Check the path to see that each pair of nodes are connected. */ const int32_t numberOfNodesInPath = static_cast(connectedNodesPath.size()); for (int32_t i = 0; i < numberOfNodesInPath; i++) { int numNeighbors; const int node = connectedNodesPath[i]; const int* neighbors = th->getNodeNeighbors(node, numNeighbors); int32_t nextNode = -1; if (i >= (numberOfNodesInPath - 1)) { nextNode = connectedNodesPath[0]; } else { nextNode = connectedNodesPath[i + 1]; } if (node != nextNode) { bool foundIt = false; for (int j = 0; j < numNeighbors; j++) { if (neighbors[j] == nextNode) { foundIt = true; break; } } if (foundIt == false) { throw AlgorithmException("Validation of vertex path along border failed. Vertex " + AString::number(node) + " should be connected to " + AString::number(nextNode) + " but it is not."); } } } } connectome-workbench-1.4.2/src/Algorithms/AlgorithmNodesInsideBorder.h000066400000000000000000000126221360521144700261200ustar00rootroot00000000000000#ifndef __ALGORITHM_NODES_INSIDE_BORDER__H_ #define __ALGORITHM_NODES_INSIDE_BORDER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AbstractAlgorithm.h" namespace caret { class Border; class BorderFile; class CiftiBrainordinateLabelFile; class CiftiBrainordinateScalarFile; class MetricFile; class LabelFile; class SurfaceFile; class TopologyHelper; class AlgorithmNodesInsideBorder : public AbstractAlgorithm { public: AlgorithmNodesInsideBorder(ProgressObject* myProgObj, const SurfaceFile* surfaceFile, const Border* border, const bool isInverseSelection, const int32_t assignToMetricMapIndex, const float assignMetricValue, MetricFile* metricFileInOut, const bool& includeBorder = false); AlgorithmNodesInsideBorder(ProgressObject* myProgObj, const SurfaceFile* surfaceFile, const Border* border, const bool isInverseSelection, const int32_t assignToCiftiScalarMapIndex, const float assignScalarValue, CiftiBrainordinateScalarFile* ciftiScalarFileInOut, const bool& includeBorder = false); AlgorithmNodesInsideBorder(ProgressObject* myProgObj, const SurfaceFile* surfaceFile, const Border* border, const bool isInverseSelection, const int32_t assignToCiftiLabelMapIndex, const int32_t assignLabelKey, CiftiBrainordinateLabelFile* ciftiLabelFileInOut, const bool& includeBorder = false); AlgorithmNodesInsideBorder(ProgressObject* myProgObj, const SurfaceFile* surfaceFile, const Border* border, const bool isInverseSelection, const int32_t assignToLabelMapIndex, const int32_t assignLabelKey, LabelFile* labelFileInOut, const bool& includeBorder = false); AlgorithmNodesInsideBorder(ProgressObject* myProgObj, const SurfaceFile* surfaceFile, const Border* border, const bool isInverseSelection, std::vector& nodesInsideBorderOut, const bool& includeBorder = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); static const BorderFile* getDebugBorderFile() { return NULL; } private: static std::vector findNodesInsideBorder(const SurfaceFile* mySurf, const Border* myBorder, const bool& inverse, const bool& includeBorder); static std::vector findNodesOutsideOfConnectedPath(const SurfaceFile* mySurf, const std::vector& connectedNodesPath); static int32_t findNodeFurthestFromConnectedPathCenterOfGravity(const SurfaceFile* mySurf, const std::vector& connectedNodesPath, std::vector& nodeSearchStatus); static std::vector createConnectedNodesPath(const SurfaceFile* mySurf, const Border* myBorder, const std::vector& unconnectedNodesPath); static void cleanNodePath(std::vector& nodePath); static std::vector moveBorderPointsToNearestNodes(const SurfaceFile* mySurf, const Border* myBorder); static void validateConnectedNodesPath(const SurfaceFile* mySurf, const std::vector& connectedNodesPath); }; typedef TemplateAutoOperation AutoAlgorithmNodesInsideBorder; } // namespace #endif //__ALGORITHM_NODES_INSIDE_BORDER__H_ connectome-workbench-1.4.2/src/Algorithms/AlgorithmSignedDistanceToSurface.cxx000066400000000000000000000121071360521144700276270ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmSignedDistanceToSurface.h" #include "AlgorithmException.h" #include "CaretOMP.h" #include "MetricFile.h" #include "SurfaceFile.h" using namespace caret; using namespace std; AString AlgorithmSignedDistanceToSurface::getCommandSwitch() { return "-signed-distance-to-surface"; } AString AlgorithmSignedDistanceToSurface::getShortDescription() { return "COMPUTE SIGNED DISTANCE FROM ONE SURFACE TO ANOTHER"; } OperationParameters* AlgorithmSignedDistanceToSurface::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface-comp", "the comparison surface to measure the signed distance on"); ret->addSurfaceParameter(2, "surface-ref", "the reference surface that defines the signed distance function"); ret->addMetricOutputParameter(3, "metric", "the output metric"); OptionalParameter* windingMethodOpt = ret->createOptionalParameter(4, "-winding", "winding method for point inside surface test"); windingMethodOpt->addStringParameter(1, "method", "name of the method (default EVEN_ODD)"); ret->setHelpText( AString("Compute the signed distance function of the reference surface at every vertex on the comparison surface. ") + "NOTE: this relation is NOT symmetric, the line from a vertex to the closest point on the 'ref' surface " + "(the one that defines the signed distance function) will only align with the normal of the 'ref' surface. Valid specifiers for winding methods are as follows:\n\n" + "EVEN_ODD (default)\nNEGATIVE\nNONZERO\nNORMALS\n\nThe NORMALS method uses the normals of triangles and edges, or the closest triangle hit by a ray from the point. " + "This method may be slightly faster, but is only reliable for a closed surface that does not cross through itself. All other methods count entry (positive) and " + "exit (negative) crossings of a vertical ray from the point, then counts as inside if the total is odd, negative, or nonzero, respectively." ); return ret; } void AlgorithmSignedDistanceToSurface::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* testSurf = myParams->getSurface(1); SurfaceFile* levelSetSurf = myParams->getSurface(2); MetricFile* myMetricOut = myParams->getOutputMetric(3); SignedDistanceHelper::WindingLogic myWinding = SignedDistanceHelper::EVEN_ODD; OptionalParameter* windingMethodOpt = myParams->getOptionalParameter(4); if (windingMethodOpt->m_present) { AString methodName = windingMethodOpt->getString(1); if (methodName == "EVEN_ODD") { myWinding = SignedDistanceHelper::EVEN_ODD; } else if (methodName == "NEGATIVE") { myWinding = SignedDistanceHelper::NEGATIVE; } else if (methodName == "NONZERO") { myWinding = SignedDistanceHelper::NONZERO; } else if (methodName == "NORMALS") { myWinding = SignedDistanceHelper::NORMALS; } else { throw AlgorithmException("unrecognized winding method"); } } AlgorithmSignedDistanceToSurface(myProgObj, testSurf, levelSetSurf, myMetricOut, myWinding); } AlgorithmSignedDistanceToSurface::AlgorithmSignedDistanceToSurface(ProgressObject* myProgObj, const SurfaceFile* testSurf, const SurfaceFile* levelSetSurf, MetricFile* myMetricOut, SignedDistanceHelper::WindingLogic myWinding) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int numNodes = testSurf->getNumberOfNodes(); myMetricOut->setNumberOfNodesAndColumns(numNodes, 1); myMetricOut->setStructure(testSurf->getStructure()); #pragma omp CARET_PAR { CaretPointer myHelp = levelSetSurf->getSignedDistanceHelper(); #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < numNodes; ++i) { myMetricOut->setValue(i, 0, myHelp->dist(testSurf->getCoordinate(i), myWinding)); } } } float AlgorithmSignedDistanceToSurface::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmSignedDistanceToSurface::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmSignedDistanceToSurface.h000066400000000000000000000035721360521144700272620ustar00rootroot00000000000000#ifndef __ALGORITHM_SIGNED_DISTANCE_TO_SURFACE_H__ #define __ALGORITHM_SIGNED_DISTANCE_TO_SURFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "SignedDistanceHelper.h" namespace caret { class AlgorithmSignedDistanceToSurface : public AbstractAlgorithm { AlgorithmSignedDistanceToSurface(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmSignedDistanceToSurface(ProgressObject* myProgObj, const SurfaceFile* testSurf, const SurfaceFile* levelSetSurf, MetricFile* myMetricOut, SignedDistanceHelper::WindingLogic myWinding = SignedDistanceHelper::EVEN_ODD); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmSignedDistanceToSurface; } #endif //__ALGORITHM_SIGNED_DISTANCE_TO_SURFACE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceAffineRegression.cxx000066400000000000000000000107411360521144700276730ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmSurfaceAffineRegression.h" #include "AlgorithmException.h" #include "AffineFile.h" #include "SurfaceFile.h" //in order to do rref on double #include "MatrixFunctions.h" using namespace caret; using namespace std; AString AlgorithmSurfaceAffineRegression::getCommandSwitch() { return "-surface-affine-regression"; } AString AlgorithmSurfaceAffineRegression::getShortDescription() { return "REGRESS THE AFFINE TRANSFORM BETWEEN SURFACES ON THE SAME MESH"; } OperationParameters* AlgorithmSurfaceAffineRegression::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "source", "the surface to warp"); ret->addSurfaceParameter(2, "target", "the surface to match the coordinates of"); ret->addStringParameter(3, "affine-out", "output - the output affine file"); ret->setHelpText( AString("Use linear regression to compute an affine that minimizes the sum of squares of the coordinate differences between the target surface and the warped source surface. ") + "Note that this has a bias to shrink the surface that is being warped. " + "The output is written as a NIFTI 'world' matrix, see -convert-affine to convert it for use in other software." ); return ret; } void AlgorithmSurfaceAffineRegression::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* sourceSurf = myParams->getSurface(1); SurfaceFile* targetSurf = myParams->getSurface(2); AString affineOutName = myParams->getString(3); FloatMatrix affineMatOut; AlgorithmSurfaceAffineRegression(myProgObj, sourceSurf, targetSurf, affineMatOut); AffineFile affineOut; affineOut.setMatrix(affineMatOut); affineOut.writeWorld(affineOutName); } AlgorithmSurfaceAffineRegression::AlgorithmSurfaceAffineRegression(ProgressObject* myProgObj, const SurfaceFile* sourceSurf, const SurfaceFile* targetSurf, FloatMatrix& affineMatOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (!targetSurf->hasNodeCorrespondence(*sourceSurf)) throw AlgorithmException("input surfaces must have vertex correspondence"); affineMatOut = FloatMatrix::identity(4); vector > indep(4, vector(4, 0.0)), dep(4, vector(3, 0.0)); int numNodes = targetSurf->getNumberOfNodes(); int coordSize = 3 * numNodes; const float* targetData = targetSurf->getCoordinateData(); const float* sourceData = sourceSurf->getCoordinateData(); for (int i = 0; i < coordSize; i += 3) { const float* targetCoord = targetData + i; const float* sourceCoord = sourceData + i; for (int j = 0; j < 3; ++j)//compute X' * X and X' * Y { for (int k = 0; k < 3; ++k) { indep[j][k] += sourceCoord[j] * sourceCoord[k]; dep[k][j] += targetCoord[j] * sourceCoord[k]; } indep[j][3] += sourceCoord[j]; indep[3][j] += sourceCoord[j]; dep[3][j] += targetCoord[j]; } indep[3][3] += 1.0; } vector > rrefMat; MatrixFunctions::horizCat(indep, dep, rrefMat); MatrixFunctions::rref(rrefMat); for (int i = 0; i < 3; ++i) { for (int j = 0; j < 4; ++j) { affineMatOut[i][j] = rrefMat[j][4 + i]; } } } float AlgorithmSurfaceAffineRegression::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmSurfaceAffineRegression::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceAffineRegression.h000066400000000000000000000034411360521144700273170ustar00rootroot00000000000000#ifndef __ALGORITHM_SURFACE_AFFINE_REGRESSION_H__ #define __ALGORITHM_SURFACE_AFFINE_REGRESSION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "FloatMatrix.h" namespace caret { class AlgorithmSurfaceAffineRegression : public AbstractAlgorithm { AlgorithmSurfaceAffineRegression(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmSurfaceAffineRegression(ProgressObject* myProgObj, const SurfaceFile* sourceSurf, const SurfaceFile* targetSurf, FloatMatrix& affineMatOut); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmSurfaceAffineRegression; } #endif //__ALGORITHM_SURFACE_AFFINE_REGRESSION_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceApplyAffine.cxx000066400000000000000000000102451360521144700266370ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmSurfaceApplyAffine.h" #include "AlgorithmException.h" #include "AffineFile.h" #include "SurfaceFile.h" #include "Vector3D.h" using namespace caret; using namespace std; AString AlgorithmSurfaceApplyAffine::getCommandSwitch() { return "-surface-apply-affine"; } AString AlgorithmSurfaceApplyAffine::getShortDescription() { return "APPLY AFFINE TRANSFORM TO SURFACE FILE"; } OperationParameters* AlgorithmSurfaceApplyAffine::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "in-surf", "the surface to transform"); ret->addStringParameter(2, "affine", "the affine file"); ret->addSurfaceOutputParameter(3, "out-surf", "the output transformed surface"); OptionalParameter* flirtOpt = ret->createOptionalParameter(4, "-flirt", "MUST be used if affine is a flirt affine"); flirtOpt->addStringParameter(1, "source-volume", "the source volume used when generating the affine"); flirtOpt->addStringParameter(2, "target-volume", "the target volume used when generating the affine"); ret->setHelpText( AString("For flirt matrices, you must use the -flirt option, because flirt matrices are not a complete description of the coordinate transform they represent. ") + "If the -flirt option is not present, the affine must be a nifti 'world' affine, which can be obtained with the -convert-affine command, or aff_conv from the 4dfp suite." ); return ret; } void AlgorithmSurfaceApplyAffine::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* mySurf = myParams->getSurface(1); AString affineName = myParams->getString(2); SurfaceFile* mySurfOut = myParams->getOutputSurface(3); OptionalParameter* flirtOpt = myParams->getOptionalParameter(4); AffineFile myAffine; if (flirtOpt->m_present) { myAffine.readFlirt(affineName, flirtOpt->getString(1), flirtOpt->getString(2)); } else { myAffine.readWorld(affineName); } AlgorithmSurfaceApplyAffine(myProgObj, mySurf, myAffine.getMatrix(), mySurfOut); } AlgorithmSurfaceApplyAffine::AlgorithmSurfaceApplyAffine(ProgressObject* myProgObj, const SurfaceFile* mySurf, const FloatMatrix& myMatrix, SurfaceFile* mySurfOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); *mySurfOut = *mySurf;//copy rather than initialize, don't currently have much in the way of modification functions Vector3D xvec, yvec, zvec, translate; myMatrix.getAffineVectors(xvec, yvec, zvec, translate); int numNodes = mySurf->getNumberOfNodes(); const float* coordData = mySurf->getCoordinateData(); vector coordsOut(numNodes * 3); for (int i = 0; i < numNodes; ++i) { int base = i * 3; Vector3D transformed = coordData[base] * xvec + coordData[base + 1] * yvec + coordData[base + 2] * zvec + translate; coordsOut[base] = transformed[0]; coordsOut[base + 1] = transformed[1]; coordsOut[base + 2] = transformed[2]; } mySurfOut->setCoordinates(coordsOut.data()); } float AlgorithmSurfaceApplyAffine::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmSurfaceApplyAffine::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceApplyAffine.h000066400000000000000000000033601360521144700262640ustar00rootroot00000000000000#ifndef __ALGORITHM_SURFACE_APPLY_AFFINE_H__ #define __ALGORITHM_SURFACE_APPLY_AFFINE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "FloatMatrix.h" namespace caret { class AlgorithmSurfaceApplyAffine : public AbstractAlgorithm { AlgorithmSurfaceApplyAffine(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmSurfaceApplyAffine(ProgressObject* myProgObj, const SurfaceFile* mySurf, const FloatMatrix& myMatrix, SurfaceFile* mySurfOut); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmSurfaceApplyAffine; } #endif //__ALGORITHM_SURFACE_APPLY_AFFINE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceApplyWarpfield.cxx000066400000000000000000000111741360521144700273660ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmSurfaceApplyWarpfield.h" #include "AlgorithmException.h" #include "SurfaceFile.h" #include "Vector3D.h" #include "WarpfieldFile.h" using namespace caret; using namespace std; AString AlgorithmSurfaceApplyWarpfield::getCommandSwitch() { return "-surface-apply-warpfield"; } AString AlgorithmSurfaceApplyWarpfield::getShortDescription() { return "APPLY WARPFIELD TO SURFACE FILE"; } OperationParameters* AlgorithmSurfaceApplyWarpfield::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "in-surf", "the surface to transform"); ret->addStringParameter(2, "warpfield", "the INVERSE warpfield"); ret->addSurfaceOutputParameter(3, "out-surf", "the output transformed surface"); OptionalParameter* fnirtOpt = ret->createOptionalParameter(4, "-fnirt", "MUST be used if using a fnirt warpfield"); fnirtOpt->addStringParameter(1, "forward-warp", "the forward warpfield"); ret->setHelpText( AString("NOTE: warping a surface requires the INVERSE of the warpfield used to warp the volume it lines up with. ") + "The header of the forward warp is needed by the -fnirt option in order to correctly interpret the displacements in the fnirt warpfield.\n\n" + "If the -fnirt option is not present, the warpfield must be a nifti 'world' warpfield, which can be obtained with the -convert-warpfield command." ); return ret; } void AlgorithmSurfaceApplyWarpfield::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* mySurf = myParams->getSurface(1); AString warpName = myParams->getString(2); SurfaceFile* mySurfOut = myParams->getOutputSurface(3); OptionalParameter* flirtOpt = myParams->getOptionalParameter(4); WarpfieldFile myWarp; if (flirtOpt->m_present) { myWarp.readFnirt(warpName, flirtOpt->getString(1)); } else { myWarp.readWorld(warpName); } AlgorithmSurfaceApplyWarpfield(myProgObj, mySurf, myWarp.getWarpfield(), mySurfOut); } AlgorithmSurfaceApplyWarpfield::AlgorithmSurfaceApplyWarpfield(ProgressObject* myProgObj, const SurfaceFile* mySurf, const VolumeFile* warpfield, SurfaceFile* mySurfOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); vector warpDims; warpfield->getDimensions(warpDims); if (warpDims[3] != 3 || warpDims[4] != 1) throw AlgorithmException("provided warpfield volume has wrong number of subvolumes or components"); *mySurfOut = *mySurf;//copy rather than initialize, don't currently have much in the way of modification functions int numNodes = mySurf->getNumberOfNodes(); const float* coordData = mySurf->getCoordinateData(); vector coordsOut(numNodes * 3); for (int i = 0; i < numNodes; ++i) { int base = i * 3; Vector3D sample = coordData + base; Vector3D displacement; bool valid = false; displacement[0] = warpfield->interpolateValue(sample, VolumeFile::TRILINEAR, &valid, 0); if (!valid) throw AlgorithmException("surface exceeds the bounding box of the warpfield"); displacement[1] = warpfield->interpolateValue(sample, VolumeFile::TRILINEAR, NULL, 1); displacement[2] = warpfield->interpolateValue(sample, VolumeFile::TRILINEAR, NULL, 2); Vector3D newCoord = sample + displacement; coordsOut[base] = newCoord[0]; coordsOut[base + 1] = newCoord[1]; coordsOut[base + 2] = newCoord[2]; } mySurfOut->setCoordinates(coordsOut.data()); } float AlgorithmSurfaceApplyWarpfield::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmSurfaceApplyWarpfield::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceApplyWarpfield.h000066400000000000000000000033571360521144700270170ustar00rootroot00000000000000#ifndef __ALGORITHM_SURFACE_APPLY_WARPFIELD_H__ #define __ALGORITHM_SURFACE_APPLY_WARPFIELD_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmSurfaceApplyWarpfield : public AbstractAlgorithm { AlgorithmSurfaceApplyWarpfield(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmSurfaceApplyWarpfield(ProgressObject* myProgObj, const SurfaceFile* mySurf, const VolumeFile* warpfield, SurfaceFile* mySurfOut); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmSurfaceApplyWarpfield; } #endif //__ALGORITHM_SURFACE_APPLY_WARPFIELD_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceAverage.cxx000066400000000000000000000231761360521144700260220ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmSurfaceAverage.h" #include "AlgorithmException.h" #include "CaretAssert.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "Vector3D.h" #include using namespace caret; using namespace std; AString AlgorithmSurfaceAverage::getCommandSwitch() { return "-surface-average"; } AString AlgorithmSurfaceAverage::getShortDescription() { return "AVERAGE SURFACE FILES TOGETHER"; } OperationParameters* AlgorithmSurfaceAverage::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceOutputParameter(1, "surface-out", "the output averaged surface"); ParameterComponent* surfOpt = ret->createRepeatableParameter(2, "-surf", "specify a surface to include in the average"); surfOpt->addSurfaceParameter(1, "surface", "a surface file to average"); OptionalParameter* surfWeightOpt = surfOpt->createOptionalParameter(2, "-weight", "specify a weighted average"); surfWeightOpt->addDoubleParameter(1, "weight", "the weight to use (default 1)"); OptionalParameter* stdevOpt = ret->createOptionalParameter(3, "-stddev", "compute 3D sample standard deviation"); stdevOpt->addMetricOutputParameter(1, "stddev-metric-out", "the output metric for 3D sample standard deviation"); OptionalParameter* uncertaintyOpt = ret->createOptionalParameter(4, "-uncertainty", "compute caret5 'uncertainty'"); uncertaintyOpt->addMetricOutputParameter(1, "uncert-metric-out", "the output metric for uncertainty"); ret->setHelpText( AString("The 3D sample standard deviation is computed as 'sqrt(sum(squaredlength(xyz - mean(xyz)))/(n - 1))'.\n\n") + "Uncertainty is a legacy measure used in caret5, and is computed as 'sum(length(xyz - mean(xyz)))/n'.\n\n" + "When weights are used, the 3D sample standard deviation treats them as reliability weights." ); return ret; } void AlgorithmSurfaceAverage::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* myAvgOut = myParams->getOutputSurface(1); vector inputSurfs; const vector& surfOpts = *(myParams->getRepeatableParameterInstances(2)); int numSurfs = (int)surfOpts.size(); vector surfWeights, *surfWeightPtr = NULL; for (int i = 0; i < numSurfs; ++i) { inputSurfs.push_back(surfOpts[i]->getSurface(1)); OptionalParameter* surfWeightOpt = surfOpts[i]->getOptionalParameter(2); if (surfWeightOpt->m_present) { if (surfWeightPtr == NULL) { surfWeights.resize(i, 1.0f); surfWeightPtr = &surfWeights; } surfWeights.push_back((float)surfWeightOpt->getDouble(1)); } else { if (surfWeightPtr != NULL) { surfWeights.push_back(1.0f); } } } MetricFile* stdevOut = NULL; OptionalParameter* stdevOpt = myParams->getOptionalParameter(3); if (stdevOpt->m_present) { stdevOut = stdevOpt->getOutputMetric(1); } MetricFile* uncertOut = NULL; OptionalParameter* uncertaintyOpt = myParams->getOptionalParameter(4); if (uncertaintyOpt->m_present) { uncertOut = uncertaintyOpt->getOutputMetric(1); } AlgorithmSurfaceAverage(myProgObj, myAvgOut, inputSurfs, stdevOut, uncertOut, surfWeightPtr); } AlgorithmSurfaceAverage::AlgorithmSurfaceAverage(ProgressObject* myProgObj, SurfaceFile* myAvgOut, const vector& inputSurfs, MetricFile* stdevOut, MetricFile* uncertOut, const vector* surfWeightPtr) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int numSurfs = (int)inputSurfs.size(); if (numSurfs == 0) throw AlgorithmException("no input surfaces specified in AlgorithmSurfaceAverage"); if (surfWeightPtr != NULL) { CaretAssert((int)surfWeightPtr->size() == numSurfs); } int numNodes = inputSurfs[0]->getNumberOfNodes(); for (int i = 1; i < numSurfs; ++i) { if (!inputSurfs[i]->hasNodeCorrespondence(*(inputSurfs[0]))) throw AlgorithmException("surface '" + inputSurfs[i]->getFileName() + "' does not have node correspondence to surface '" + inputSurfs[0]->getFileName() + "'"); inputSurfs[i]->clearCachedHelpers(); } *myAvgOut = *(inputSurfs[0]); if (uncertOut != NULL) { uncertOut->setNumberOfNodesAndColumns(numNodes, 1); uncertOut->setStructure(inputSurfs[0]->getStructure()); uncertOut->setColumnName(0, "SHAPE_STANDARD_UNCERTAINTY"); } if (stdevOut != NULL) { stdevOut->setNumberOfNodesAndColumns(numNodes, 1); stdevOut->setStructure(inputSurfs[0]->getStructure()); stdevOut->setColumnName(0, "3D sample standard deviation"); } //loop across nodes first so that we can use doubles for accumulation easily for (int i = 0; i < numNodes; ++i) { double accumpoint[3] = {0.0, 0.0, 0.0}; Vector3D avgpoint; if (surfWeightPtr == NULL) { for (int j = 0; j < numSurfs; ++j) { Vector3D inpoint = inputSurfs[j]->getCoordinate(i); accumpoint[0] += inpoint[0]; accumpoint[1] += inpoint[1]; accumpoint[2] += inpoint[2]; } avgpoint[0] = accumpoint[0] / numSurfs; avgpoint[1] = accumpoint[1] / numSurfs; avgpoint[2] = accumpoint[2] / numSurfs; } else { double weightsum = 0.0; for (int j = 0; j < numSurfs; ++j) { Vector3D inpoint = inputSurfs[j]->getCoordinate(i); float thisweight = (*surfWeightPtr)[j]; weightsum += thisweight; accumpoint[0] += inpoint[0] * thisweight; accumpoint[1] += inpoint[1] * thisweight; accumpoint[2] += inpoint[2] * thisweight; } avgpoint[0] = accumpoint[0] / weightsum; avgpoint[1] = accumpoint[1] / weightsum; avgpoint[2] = accumpoint[2] / weightsum; } myAvgOut->setCoordinate(i, avgpoint); if (uncertOut != NULL || stdevOut != NULL) { if (numSurfs == 1) { if (uncertOut != NULL) { uncertOut->setValue(i, 0, 0.0f); } if (stdevOut != NULL) { stdevOut->setValue(i, 0, 0.0f); } } else { double distAccum = 0.0;//for caret5 uncertainty double dist2Accum = 0.0;//for sample stdev if (surfWeightPtr == NULL) { for (int j = 0; j < numSurfs; ++j) { Vector3D inpoint = inputSurfs[j]->getCoordinate(i); float dist2 = (avgpoint - inpoint).lengthsquared(); dist2Accum += dist2; distAccum += sqrt(dist2); } if (uncertOut != NULL) { uncertOut->setValue(i, 0, distAccum / numSurfs); } if (stdevOut != NULL) { stdevOut->setValue(i, 0, sqrt(dist2Accum / (numSurfs - 1))); } } else { double weightsum = 0.0, weight2sum = 0.0; for (int j = 0; j < numSurfs; ++j) { Vector3D inpoint = inputSurfs[j]->getCoordinate(i); float thisweight = (*surfWeightPtr)[j]; weightsum += thisweight; weight2sum += thisweight * thisweight; float dist2 = (avgpoint - inpoint).lengthsquared(); dist2Accum += dist2 * thisweight; distAccum += sqrt(dist2) * thisweight; } if (uncertOut != NULL) { uncertOut->setValue(i, 0, distAccum / weightsum); } if (stdevOut != NULL) { stdevOut->setValue(i, 0, sqrt(dist2Accum / (weightsum - weight2sum / weightsum)));//https://en.wikipedia.org/wiki/Weighted_arithmetic_mean#Weighted_sample_variance } } } } } } float AlgorithmSurfaceAverage::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmSurfaceAverage::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceAverage.h000066400000000000000000000035141360521144700254410ustar00rootroot00000000000000#ifndef __ALGORITHM_SURFACE_AVERAGE_H__ #define __ALGORITHM_SURFACE_AVERAGE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include namespace caret { class AlgorithmSurfaceAverage : public AbstractAlgorithm { AlgorithmSurfaceAverage(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmSurfaceAverage(ProgressObject* myProgObj, SurfaceFile* myAvgOut, const std::vector& inputSurfs, MetricFile* stdevOut = NULL, MetricFile* uncertOut = NULL, const std::vector* surfWeightPtr = NULL); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmSurfaceAverage; } #endif //__ALGORITHM_SURFACE_AVERAGE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceCortexLayer.cxx000066400000000000000000000403501360521144700267020ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmSurfaceCortexLayer.h" #include "AlgorithmException.h" #include "MathFunctions.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "TopologyHelper.h" #include "Vector3D.h" #include using namespace caret; using namespace std; AString AlgorithmSurfaceCortexLayer::getCommandSwitch() { return "-surface-cortex-layer"; } AString AlgorithmSurfaceCortexLayer::getShortDescription() { return "CREATE SURFACE APPROXIMATING A CORTICAL LAYER"; } OperationParameters* AlgorithmSurfaceCortexLayer::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "white-surface", "the white matter surface"); ret->addSurfaceParameter(2, "pial-surface", "the pial surface"); ret->addDoubleParameter(3, "location", "what volume fraction to place the layer at"); ret->addSurfaceOutputParameter(4, "out-surface", "the output surface"); OptionalParameter* metricOpt = ret->createOptionalParameter(5, "-placement-out", "output the placement as a distance fraction from pial to white"); metricOpt->addMetricOutputParameter(1, "placement-metric", "output metric"); //ret->createOptionalParameter(6, "-untwist", "temporary option for comparing methods, specify to use old method"); ret->setHelpText( AString("The input surfaces must have vertex correspondence. ") + "The output surface is generated by placing vertices between the two surfaces such that the enclosed volume within any small patch of the new and white surfaces " + "is the given fraction of the volume of the same patch between the pial and white surfaces " + "(i.e., specifying 0 would give the white surface, 1 would give the pial surface). " ); return ret; } void AlgorithmSurfaceCortexLayer::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* myWhiteSurf = myParams->getSurface(1); SurfaceFile* myPialSurf = myParams->getSurface(2); float myVolFrac = myParams->getDouble(3); SurfaceFile* myOutSurf = myParams->getOutputSurface(4); MetricFile* myMetricOut = NULL; OptionalParameter* metricOpt = myParams->getOptionalParameter(5); if (metricOpt->m_present) { myMetricOut = metricOpt->getOutputMetric(1); } bool untwistMode = false;//myParams->getOptionalParameter(6)->m_present; AlgorithmSurfaceCortexLayer(myProgObj, myWhiteSurf, myPialSurf, myVolFrac, myOutSurf, myMetricOut, untwistMode); } AlgorithmSurfaceCortexLayer::AlgorithmSurfaceCortexLayer(ProgressObject* myProgObj, const SurfaceFile* myWhiteSurf, const SurfaceFile* myPialSurf, const float& myVolFrac, SurfaceFile* myOutSurf, MetricFile* myMetricOut, const bool& untwistMode) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int numNodes = myWhiteSurf->getNumberOfNodes(); if (!myWhiteSurf->hasNodeCorrespondence(*myPialSurf)) { throw AlgorithmException("input surfaces don't have node correspondence"); } *myOutSurf = *myWhiteSurf;//copy topology myOutSurf->setSecondaryType(SecondarySurfaceTypeEnum::MIDTHICKNESS);//??? if (myMetricOut != NULL) { myMetricOut->setNumberOfNodesAndColumns(numNodes, 1); myMetricOut->setStructure(myWhiteSurf->getStructure()); myMetricOut->setColumnName(0, "distance fraction"); } const float* whiteCoords = myWhiteSurf->getCoordinateData(); const float* pialCoords = myPialSurf->getCoordinateData(); bool outside = false; bool above = false; if (myVolFrac < 0 || myVolFrac > 1) { outside = true; if (myVolFrac > 1) above = true; } CaretPointer myTopoHelp = myWhiteSurf->getTopologyHelper();//we checked that the input surfaces have the same effective topology for (int i = 0; i < numNodes; ++i) { Vector3D whiteCenter = whiteCoords + i * 3; Vector3D pialCenter = pialCoords + i * 3; float distFrac = 0.0f; if (untwistMode) { float d1; Vector3D axisHat = (pialCenter - whiteCenter).normal(&d1); const vector& neighbors = myTopoHelp->getNodeNeighbors(i); int numNeigh = (int)neighbors.size(); for (int j = 0; j < numNeigh; ++j) { Vector3D whiteNeighbor = whiteCoords + neighbors[j] * 3; Vector3D pialNeighbor = pialCoords + neighbors[j] * 3; float R0 = axisHat.cross(whiteCenter - whiteNeighbor).length(); float RF = axisHat.cross(pialCenter - pialNeighbor).length(); float Rd = RF - R0; float h0 = axisHat.dot(whiteCenter - whiteNeighbor); float hF = axisHat.dot(pialCenter - pialNeighbor); float hd = hF - h0; float a = d1 * Rd * Rd;//coefficient for t^3 float b = Rd * (3 * d1 * R0 + h0 * Rd - hd * R0);//t^2 float c = R0 * (3 * d1 * R0 + 2 * h0 * Rd - 2 * hd * R0);//t float fullVol = c + b + a;//trivial to evaluate for t = 1, and t = 0 gives 0 float target = fullVol * myVolFrac; float lowt = 0, lowval = 0, hight = 1, highval = fullVol; if (outside) { if (above) { if (Rd / R0 < 0) { hight = min(-R0 / Rd, 1 + (myVolFrac - 1) * 3);//because conical volumes are 1/3 the equivalent cylinder } else { hight = myVolFrac;//because the longest result here is cylinder } highval = hight * (c + hight * (b + hight * a)); } else { if (Rd / R0 > 0) { lowt = max(-R0 / Rd, myVolFrac * 3);//ditto } else { lowt = myVolFrac; } lowval = lowt * (c + lowt * (b + lowt * a)); } }//these ranges SHOULD make the function monotonic const float TOLER = 0.0001f;//stop when high and low bounds are this close const int MAX_ITERS = 100;//but don't take too long trying to get there int iter = 0; while (abs(hight - lowt) > TOLER && iter < MAX_ITERS) { ++iter; float highdiff = (highval - target); float lowdiff = (target - lowval); float guess = (lowt * highdiff + hight * lowdiff) / (highdiff + lowdiff);//weighted average to get guess float highcap = (lowt + 9 * hight) / 10.0f;//make guess lie in the middle 80%, to make sure it always moves nontrivially float lowcap = (9 * lowt + hight) / 10.0f; if (guess < lowcap) guess = lowcap; if (guess > highcap) guess = highcap; float guessval = guess * (c + guess * (b + guess * a)); if ((guessval < target) == (lowval < highval))//in case positive t produces negative volume { lowt = guess; lowval = guessval; } else { hight = guess; highval = guessval; } } float highdiff = (highval - target);//one more iteration to get the value to add to accum float lowdiff = (target - lowval); float guess = (lowt * highdiff + hight * lowdiff) / (highdiff + lowdiff); float highcap = (lowt + 9 * hight) / 10.0f; float lowcap = (9 * lowt + hight) / 10.0f; if (guess < lowcap) guess = lowcap; if (guess > highcap) guess = highcap; distFrac += guess; } distFrac /= numNeigh; } else { float a = 0.0f, b = 0.0f, c = 0.0f;//constants for the cubic function that will give the volume const vector& myTiles = myTopoHelp->getNodeTiles(i); int numTiles = (int)myTiles.size(); for (int j = 0; j < numTiles; ++j) { const int32_t* whiteTile = myWhiteSurf->getTriangle(myTiles[j]); Vector3D whitePoints[3], pialPoints[3], layerDelta[3]; for (int k = 0; k < 3; ++k) { whitePoints[k] = whiteCoords + whiteTile[k] * 3; pialPoints[k] = pialCoords + whiteTile[k] * 3; layerDelta[k] = pialPoints[k] - whitePoints[k]; }//calculate volume with vector field trick: http://en.wikipedia.org/wiki/Polyhedron#Volume Vector3D refPoint = whitePoints[0];//use an "origin" for the vector field that is near the polyhedron for numerical stability - also, this makes several sides have zero contribution //NOTE: the white surface triangle has zero contribution due to choice of reference point, would otherwise contribute to both volumes //layerVol += (layerPoints[0] - refPoint).dot((layerPoints[1] - layerPoints[0]).cross(layerPoints[2] - layerPoints[1])); // (t * (pialPoints[0] - whitePoints[0])).dot((t * (pialPoints[1] - pialPoints[0] - (whitePoints[1] - whitePoints[0])) + whitePoints[1] - whitePoints[0]).cross(...) Vector3D edge10delta = pialPoints[1] - pialPoints[0] - whitePoints[1] + whitePoints[0]; Vector3D edge21delta = pialPoints[2] - pialPoints[1] - whitePoints[2] + whitePoints[1]; // (t * layerDelta[0]).dot((t * edge10delta + whitePoints[1] - whitePoints[0]).cross(t * edge21delta + whitePoints[2] - whitepoints[1])); a += layerDelta[0].dot(edge10delta.cross(edge21delta)); b += layerDelta[0].dot((whitePoints[1] - whitePoints[0]).cross(edge21delta) + edge10delta.cross(whitePoints[2] - whitePoints[1])); c += layerDelta[0].dot((whitePoints[1] - whitePoints[0]).cross(whitePoints[2] - whitePoints[1])); int m = 2; for (int k = 0; k < 3; ++k)//walk the side quadrilaterals as 2->0, 0->1, 1->2 {//add the average of the two triangulations of the quadrilateral Vector3D mref = whitePoints[m] - refPoint, kref = whitePoints[k] - refPoint;//precalculate reference points on the white surface for use in both volumes Vector3D whiteEdge = whitePoints[k] - whitePoints[m];//precalculate this frequently used edge also if (k != 0 && m != 0) //layerVol += 0.5f * mref.dot(whiteEdge.cross(layerPoints[k] - whitePoints[k])); { c += 0.5f * mref.dot(whiteEdge.cross(layerDelta[k])); } if (m != 0) //layerVol += 0.5f * mref.dot((layerPoints[m] - whitePoints[m]).cross(whitePoints[m] - layerPoints[k])); { // 0.5f * mref.dot((t * layerDelta[m]).cross(whitePoints[m] - (whitePoints[k] + t * layerDelta[k]))); b += 0.5f * mref.dot(layerDelta[m].cross(-layerDelta[k])); c += 0.5f * mref.dot(layerDelta[m].cross(-whiteEdge)); } if (k != 0 && m != 0) //layerVol += 0.5f * kref.dot(whiteEdge.cross(layerPoints[m] - whitePoints[k])); { // 0.5f * kref.dot(whiteEdge.cross(layerPoints[m] - whitePoints[m]));//use a formula where t = 0 gives a zero length edge c += 0.5f * kref.dot(whiteEdge.cross(layerDelta[m])); } if (k != 0) //layerVol += 0.5f * kref.dot((layerPoints[k] - whitePoints[k]).cross(layerPoints[m] - layerPoints[k])); { // 0.5f * kref.dot((t * layerDelta[k]).cross((whitePoints[m] + t * layerDelta[m]) - (whitePoints[k] + t * layerDelta[k]))); b += 0.5f * kref.dot(layerDelta[k].cross(layerDelta[m] - layerDelta[k])); c += 0.5f * kref.dot(layerDelta[k].cross(-whiteEdge)); } m = k; } } float fullVol = a + b + c;//trivial to evaluate for t = 1, and t = 0 gives 0 float target = fullVol * myVolFrac; float lowt = 0, lowval = 0, hight = 1, highval = fullVol; if (outside) { if (above) { hight = 1 + (myVolFrac - 1) * 3;//set a limit at 3 times further out than the requested fraction, and just hope that it is monotonic highval = hight * (c + hight * (b + hight * a)); } else { lowt = myVolFrac * 3;//ditto lowval = lowt * (c + lowt * (b + lowt * a)); } }//these ranges SHOULD make the function monotonic const float TOLER = 0.0001f;//stop when high and low bounds are this close const int MAX_ITERS = 100;//but don't take too long trying to get there int iter = 0; while (abs(hight - lowt) > TOLER && iter < MAX_ITERS) { ++iter; float highdiff = (highval - target); float lowdiff = (target - lowval); float guess = (lowt * highdiff + hight * lowdiff) / (highdiff + lowdiff);//weighted average to get guess float highcap = (lowt + 9 * hight) / 10.0f;//make guess lie in the middle 80%, to make sure it always moves nontrivially float lowcap = (9 * lowt + hight) / 10.0f; if (guess < lowcap) guess = lowcap; if (guess > highcap) guess = highcap; float guessval = guess * (c + guess * (b + guess * a)); if ((guessval < target) == (lowval < highval))//in case positive t produces negative volume { lowt = guess; lowval = guessval; } else { hight = guess; highval = guessval; } } float highdiff = (highval - target);//one more iteration to get the value to add to accum float lowdiff = (target - lowval); float guess = (lowt * highdiff + hight * lowdiff) / (highdiff + lowdiff); float highcap = (lowt + 9 * hight) / 10.0f; float lowcap = (9 * lowt + hight) / 10.0f; if (guess < lowcap) guess = lowcap; if (guess > highcap) guess = highcap; distFrac = guess; } if (!MathFunctions::isNumeric(distFrac)) { distFrac = 0.5f;//non-numeric should only happen when pial and white coords are identical, so average should be fine } myOutSurf->setCoordinate(i, distFrac * (pialCenter - whiteCenter) + whiteCenter); if (myMetricOut != NULL) { myMetricOut->setValue(i, 0, distFrac); } } } float AlgorithmSurfaceCortexLayer::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmSurfaceCortexLayer::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceCortexLayer.h000066400000000000000000000035331360521144700263310ustar00rootroot00000000000000#ifndef __ALGORITHM_SURFACE_CORTEX_LAYER_H__ #define __ALGORITHM_SURFACE_CORTEX_LAYER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmSurfaceCortexLayer : public AbstractAlgorithm { AlgorithmSurfaceCortexLayer(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmSurfaceCortexLayer(ProgressObject* myProgObj, const SurfaceFile* myWhiteSurf, const SurfaceFile* myPialSurf, const float& myVolFrac, SurfaceFile* myOutSurf, MetricFile* myMetricOut = NULL, const bool& untwistMode = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmSurfaceCortexLayer; } #endif //__ALGORITHM_SURFACE_CORTEX_LAYER_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceCreateSphere.cxx000066400000000000000000000301421360521144700270110ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmSurfaceCreateSphere.h" #include "AlgorithmException.h" #include "CaretLogger.h" #include "SurfaceFile.h" #include "Vector3D.h" #include using namespace caret; using namespace std; AString AlgorithmSurfaceCreateSphere::getCommandSwitch() { return "-surface-create-sphere"; } AString AlgorithmSurfaceCreateSphere::getShortDescription() { return "GENERATE A SPHERE WITH CONSISTENT VERTEX AREAS"; } OperationParameters* AlgorithmSurfaceCreateSphere::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addIntegerParameter(1, "num-vertices", "desired number of vertices"); ret->addSurfaceOutputParameter(2, "sphere-out", "the output sphere"); ret->setHelpText( AString("Generates a sphere by regularly dividing the triangles of an icosahedron, to come as close to the desired number of vertices as possible, ") + "and modifying it to have very similar vertex areas for all vertices. " + "To generate a pair of vertex-matched left and right spheres, use this command, then -surface-flip-lr to generate the other sphere, then -set-structure on each. " + "For example:\n\n" + "$ wb_command -surface-create-sphere 6000 Sphere.6k.R.surf.gii\n" + "$ wb_command -surface-flip-lr Sphere.6k.R.surf.gii Sphere.6k.L.surf.gii\n" + "$ wb_command -set-structure Sphere.6k.R.surf.gii CORTEX_RIGHT\n" + "$ wb_command -set-structure Sphere.6k.L.surf.gii CORTEX_LEFT" ); return ret; } void AlgorithmSurfaceCreateSphere::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { int numVertices = (int)myParams->getInteger(1); SurfaceFile* mySurfOut = myParams->getOutputSurface(2); AlgorithmSurfaceCreateSphere(myProgObj, numVertices, mySurfOut); } AlgorithmSurfaceCreateSphere::AlgorithmSurfaceCreateSphere(ProgressObject* myProgObj, const int& numVertices, SurfaceFile* mySurfOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (numVertices < 1) throw AlgorithmException("desired number of vertices must be positive"); int lastnodes, mynodes, mytris; m_numDivisions = -1; getNumberOfNodesAndTrianglesFromDivisions(0, lastnodes, mytris); for (int i = 1; i < 10000; ++i)//10363 divisions overflows an int32 in number of triangles, tighten this sanity check? { getNumberOfNodesAndTrianglesFromDivisions(i, mynodes, mytris); if (abs(numVertices - lastnodes) < abs(numVertices - mynodes)) { m_numDivisions = i - 1; CaretLogFine("Closest divided icosahedron has " + AString::number(lastnodes) + " nodes."); break; } lastnodes = mynodes; } if (m_numDivisions == -1) throw AlgorithmException("too many vertices specified"); m_surface = mySurfOut; getNumberOfNodesAndTrianglesFromDivisions(m_numDivisions, mynodes, mytris); m_surface->setNumberOfNodesAndTriangles(mynodes, mytris); m_surface->setSurfaceType(SurfaceTypeEnum::SPHERICAL); m_surface->setSecondaryType(SecondarySurfaceTypeEnum::INVALID); SurfaceFile initSurf; initSurf.setNumberOfNodesAndTriangles(12, 20); const double phi = (1.0 + sqrt(5.0)) / 2.0; initSurf.setCoordinate(0, -phi, 0.0, 1.0);//initial icosahedron initSurf.setCoordinate(1, 0, -1.0, phi); initSurf.setCoordinate(2, phi, 0.0, 1.0); initSurf.setCoordinate(3, 0, 1.0, phi); initSurf.setCoordinate(4, -1.0, -phi, 0.0); initSurf.setCoordinate(5, 1.0, -phi, 0.0); initSurf.setCoordinate(6, 1.0, phi, 0.0); initSurf.setCoordinate(7, -1.0, phi, 0.0); initSurf.setCoordinate(8, -phi, 0.0, -1.0); initSurf.setCoordinate(9, 0, -1.0, -phi); initSurf.setCoordinate(10, phi, 0.0, -1.0); initSurf.setCoordinate(11, 0, 1.0, -phi); initSurf.setTriangle(0, 0, 7, 8); initSurf.setTriangle(1, 0, 3, 7); initSurf.setTriangle(2, 0, 1, 3); initSurf.setTriangle(3, 1, 2, 3); initSurf.setTriangle(4, 1, 5, 2); initSurf.setTriangle(5, 5, 9, 10); initSurf.setTriangle(6, 10, 11, 6); initSurf.setTriangle(7, 4, 1, 0); initSurf.setTriangle(8, 4, 5, 1); initSurf.setTriangle(9, 4, 9, 5); initSurf.setTriangle(10, 5, 10, 2); initSurf.setTriangle(11, 10, 6, 2); initSurf.setTriangle(12, 6, 11, 7); initSurf.setTriangle(13, 11, 9, 8); initSurf.setTriangle(14, 9, 4, 8); initSurf.setTriangle(15, 8, 4, 0); initSurf.setTriangle(16, 11, 8, 7); initSurf.setTriangle(17, 6, 7, 3); initSurf.setTriangle(18, 6, 3, 2); initSurf.setTriangle(19, 11, 10, 9); Vector3D tempcoord; for (int i = 0; i < 12; ++i) { tempcoord = initSurf.getCoordinate(i); tempcoord *= 100.0f / tempcoord.length();//make it directly into a radius 100 sphere rather than taking a second pass m_surface->setCoordinate(i, tempcoord); } m_curTiles = 0; m_curNodes = 12; m_edgenodes.resize(11);//stores by low node # vector edge1(m_numDivisions + 1), edge2(m_numDivisions + 1), edge3(m_numDivisions + 1); vector > facenodes(m_numDivisions + 1); for (int i = 0; i <= m_numDivisions; ++i) {// first index is row from bottom, second index is column from left facenodes[i].resize(m_numDivisions - i + 1); } for (int i = 0; i < 20; ++i) { const int32_t* nodes = initSurf.getTriangle(i); //convention for visualization: nodes[0] is bottom left, nodes[1] is bottom right, nodes[2] is top //tile generation also follows this convention, with the consequence that tile orientation is preserved getEdge(nodes[0], nodes[1], edge1.data());//bottom edge, left to right getEdge(nodes[0], nodes[2], edge2.data());//left edge, bottom to top getEdge(nodes[1], nodes[2], edge3.data());//right edge, bottom to top const float* coord1 = initSurf.getCoordinate(nodes[0]); const float* coord2 = initSurf.getCoordinate(nodes[1]); const float* coord3 = initSurf.getCoordinate(nodes[2]); for (int j = 0; j <= m_numDivisions; ++j) {//copy edge nodes into the face array facenodes[0][j] = edge1[j]; facenodes[j][0] = edge2[j]; facenodes[j][m_numDivisions - j] = edge3[j]; } for (int j = 1; j < m_numDivisions - 1; ++j) {//generate interior coordinates int intCols = m_numDivisions - j; for (int k = 1; k < intCols; ++k) { interp3(coord1, coord2, coord3, j, k, tempcoord); tempcoord *= 100.0f / tempcoord.length();//make it directly into a radius 100 sphere rather than taking a second pass m_surface->setCoordinate(m_curNodes, tempcoord); facenodes[j][k] = m_curNodes; ++m_curNodes; } } for (int j = 0; j < m_numDivisions; ++j) {//generate tiles for (int k = 0; k < m_numDivisions - j - 1; ++k) {//pairs for trapezoidal pieces m_surface->setTriangle(m_curTiles, facenodes[j][k], facenodes[j][k + 1], facenodes[j + 1][k]); m_surface->setTriangle(m_curTiles + 1, facenodes[j + 1][k], facenodes[j][k + 1], facenodes[j + 1][k + 1]); m_curTiles += 2; }//and one more m_surface->setTriangle(m_curTiles, facenodes[j][m_numDivisions - j - 1], facenodes[j][m_numDivisions - j], facenodes[j + 1][m_numDivisions - j - 1]); ++m_curTiles; } } } void AlgorithmSurfaceCreateSphere::getNumberOfNodesAndTrianglesFromDivisions(const int& divisions, int& numNodesOut, int& numTrianglesOut) { int div2 = divisions * divisions; numNodesOut = 2 + 10 * div2; numTrianglesOut = 20 * div2;//yes, its really that simple, the sum of the two triangulars is square } void AlgorithmSurfaceCreateSphere::interp3(const float coord1[3], const float coord2[3], const float coord3[3], const int& row, const int& col, float out[3]) {//this is the function to change if you want different spacing float weight2 = ((float)col) / m_numDivisions;//start with flat interpolation weights float weight3 = ((float)row) / m_numDivisions; float weight1 = 1.0f - weight2 - weight3; //polynomial for each weight - should map 0 to 0 and 1 to 1 const float quintweight = 0.0537206f;//WEIGHTS TUNED FOR ICOSAHEDRON VIA GENETIC ALGORITHM, ADJUST FOR OTHER INITIAL POLYGONS const float quartweight = -0.174466f;//this polynomial should be highly dependent on size of the triangle being interpolated const float cubeweight = 0.292547f; const float quadweight = -0.456351f; const float linweight = 1.0f - quintweight - quartweight - cubeweight - quadweight;//make sure it maps 0 to 0 and 1 to 1 weight1 = ((((quintweight * weight1 + quartweight) * weight1 + cubeweight) * weight1 + quadweight) * weight1 + linweight) * weight1;//quintic approximation of great arc equal area weight transformation function weight2 = ((((quintweight * weight2 + quartweight) * weight2 + cubeweight) * weight2 + quadweight) * weight2 + linweight) * weight2; weight3 = ((((quintweight * weight3 + quartweight) * weight3 + cubeweight) * weight3 + quadweight) * weight3 + linweight) * weight3;//three weights no longer sum to 1, but thats ok out[0] = coord1[0] * weight1 + coord2[0] * weight2 + coord3[0] * weight3; out[1] = coord1[1] * weight1 + coord2[1] * weight2 + coord3[1] * weight3; out[2] = coord1[2] * weight1 + coord2[2] * weight2 + coord3[2] * weight3; } void AlgorithmSurfaceCreateSphere::getEdge(int node1, int node2, int* out) { bool reverse = false; int i, index, edgesize = m_numDivisions + 1; if (node1 > node2) { reverse = true; i = node1; node1 = node2; node2 = i; } bool found = false; for (i = 0; i < (int)m_edgenodes[node1].size(); ++i) { if (m_edgenodes[node1][i][m_numDivisions] == node2) { found = true; index = i; break; } } if (!found) { float coord3[3] = {0.0f, 0.0f, 0.0f}; Vector3D tempcoord; const float* coord1, *coord2; coord1 = m_surface->getCoordinate(node1); coord2 = m_surface->getCoordinate(node2); std::vector tempvec; tempvec.resize(edgesize); tempvec[0] = node1; tempvec[m_numDivisions] = node2; for (i = 1; i < m_numDivisions; ++i) { interp3(coord1, coord2, coord3, 0, i, tempcoord);//use 0 as dummy node, with row 0 it is unused tempvec[i] = m_curNodes; tempcoord *= 100.0f / tempcoord.length(); m_surface->setCoordinate(m_curNodes, tempcoord); ++m_curNodes; } index = m_edgenodes[node1].size(); m_edgenodes[node1].push_back(tempvec); } if (reverse) { for (i = 0; i < edgesize; ++i) { out[i] = m_edgenodes[node1][index][edgesize - i - 1]; } } else { for (i = 0; i < edgesize; ++i) { out[i] = m_edgenodes[node1][index][i]; } } } float AlgorithmSurfaceCreateSphere::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmSurfaceCreateSphere::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceCreateSphere.h000066400000000000000000000042441360521144700264420ustar00rootroot00000000000000#ifndef __ALGORITHM_SURFACE_CREATE_SPHERE_H__ #define __ALGORITHM_SURFACE_CREATE_SPHERE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include namespace caret { class AlgorithmSurfaceCreateSphere : public AbstractAlgorithm { AlgorithmSurfaceCreateSphere(); void interp3(const float coord1[3], const float coord2[3], const float coord3[3], const int& row, const int& col, float out[3]); void getEdge(int node1, int node2, int* out); int m_numDivisions, m_curNodes, m_curTiles; SurfaceFile* m_surface; std::vector > > m_edgenodes; static void getNumberOfNodesAndTrianglesFromDivisions(const int& divisions, int& numNodesOut, int& numTrianglesOut); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmSurfaceCreateSphere(ProgressObject* myProgObj, const int& numVertices, SurfaceFile* mySurfOut); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmSurfaceCreateSphere; } #endif //__ALGORITHM_SURFACE_CREATE_SPHERE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceCurvature.cxx000066400000000000000000000151641360521144700264260ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmSurfaceCurvature.h" #include "AlgorithmException.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "TopologyHelper.h" #include "Vector3D.h" #include using namespace caret; using namespace std; AString AlgorithmSurfaceCurvature::getCommandSwitch() { return "-surface-curvature"; } AString AlgorithmSurfaceCurvature::getShortDescription() { return "CALCULATE CURVATURE OF SURFACE"; } OperationParameters* AlgorithmSurfaceCurvature::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to compute the curvature of"); OptionalParameter* meanOpt = ret->createOptionalParameter(2, "-mean", "output mean curvature"); meanOpt->addMetricOutputParameter(1, "mean-out", "mean curvature metric"); OptionalParameter* gaussOpt = ret->createOptionalParameter(3, "-gauss", "output gaussian curvature"); gaussOpt->addMetricOutputParameter(1, "gauss-out", "gaussian curvature metric"); ret->setHelpText( AString("Compute the curvature of the surface, using the method from:\n") + "Interactive Texture Mapping by J. Maillot, Yahia, and Verroust, 1993.\n" + "ACM-0-98791-601-8/93/008" ); return ret; } void AlgorithmSurfaceCurvature::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* mySurf = myParams->getSurface(1); MetricFile* meanOut = NULL, *gaussOut = NULL; OptionalParameter* meanOpt = myParams->getOptionalParameter(2); if (meanOpt->m_present) { meanOut = meanOpt->getOutputMetric(1); } OptionalParameter* gaussOpt = myParams->getOptionalParameter(3); if (gaussOpt->m_present) { gaussOut = gaussOpt->getOutputMetric(1); } AlgorithmSurfaceCurvature(myProgObj, mySurf, meanOut, gaussOut); } AlgorithmSurfaceCurvature::AlgorithmSurfaceCurvature(ProgressObject* myProgObj, const SurfaceFile* mySurf, MetricFile* meanOut, MetricFile* gaussOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int numNodes = mySurf->getNumberOfNodes(); if (meanOut != NULL) { meanOut->setNumberOfNodesAndColumns(numNodes, 1); meanOut->setStructure(mySurf->getStructure()); meanOut->setColumnName(0, "mean curvature"); } if (gaussOut != NULL) { gaussOut->setNumberOfNodesAndColumns(numNodes, 1); gaussOut->setStructure(mySurf->getStructure()); gaussOut->setColumnName(0, "gaussian curvature"); } CaretPointer myTopoHelp = mySurf->getTopologyHelper(); const float* normalData = mySurf->getNormalData(); for (int i = 0; i < numNodes; ++i) { const vector& neighbors = myTopoHelp->getNodeNeighbors(i); int numNeigh = (int)neighbors.size(); float k1 = 0.0f, k2 = 0.0f; if (numNeigh > 0) { Vector3D center = mySurf->getCoordinate(i); Vector3D normal = normalData + i * 3; Vector3D basisStart;//default constructor is 0 vector if (abs(normal[0]) > abs(normal[1])) {//a vector not parallel to the normal basisStart[1] = 1.0f; } else { basisStart[0] = 1.0f; } Vector3D ihat = normal.cross(basisStart).normal(); Vector3D jhat = normal.cross(ihat); float sig_x = 0.0f, sig_xy = 0.0f, sig_y = 0.0f; float norm_x = 0.0f, norm_xy = 0.0f, norm_y = 0.0f; for (int j = 0; j < numNeigh; ++j) {//center node contributes 0 to each sum, so skip it Vector3D neighNormal = normalData + neighbors[j] * 3; Vector3D neighDiff = Vector3D(mySurf->getCoordinate(neighbors[j])) - center; float normProj[2] = { neighNormal.dot(ihat), neighNormal.dot(jhat) }; float diffProj[2] = { neighDiff.dot(ihat), neighDiff.dot(jhat) }; sig_x += diffProj[0] * diffProj[0]; sig_xy += diffProj[0] * diffProj[1]; sig_y += diffProj[1] * diffProj[1]; norm_x += normProj[0] * diffProj[0]; norm_xy += normProj[0] * diffProj[1] + normProj[1] * diffProj[0]; norm_y += normProj[1] * diffProj[1]; } float sig_xy2 = sig_xy * sig_xy; float denom = (sig_x + sig_y) * (-sig_xy2 + sig_x * sig_y); if (denom != 0.0f) { float a = (norm_x * (-sig_xy2 + sig_x * sig_y + sig_y * sig_y) - norm_xy * sig_xy * sig_y + norm_y * sig_xy2) / denom; float b = (-norm_x * sig_xy * sig_y + norm_xy * sig_x * sig_y - norm_y * sig_x * sig_xy) / denom; float c = (norm_x * sig_xy2 - norm_xy * sig_x * sig_xy + norm_y * (sig_x * sig_x - sig_xy2 + sig_x * sig_y)) / denom; float trC = a + c; float detC = a * c - b * b; float temp = trC * trC - 4 * detC; if (temp >= 0.0f) { float delta = sqrt(temp); k1 = (trC + delta) / 2; k2 = (trC - delta) / 2; } } } if (meanOut != NULL) { meanOut->setValue(i, 0, (k1 + k2) / 2); } if (gaussOut != NULL) { gaussOut->setValue(i, 0, k1 * k2); } } } float AlgorithmSurfaceCurvature::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmSurfaceCurvature::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceCurvature.h000066400000000000000000000033101360521144700260410ustar00rootroot00000000000000#ifndef __ALGORITHM_SURFACE_CURVATURE_H__ #define __ALGORITHM_SURFACE_CURVATURE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmSurfaceCurvature : public AbstractAlgorithm { AlgorithmSurfaceCurvature(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmSurfaceCurvature(ProgressObject* myProgObj, const SurfaceFile* mySurf, MetricFile* meanOut = NULL, MetricFile* gaussOut = NULL); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmSurfaceCurvature; } #endif //__ALGORITHM_SURFACE_CURVATURE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceDistortion.cxx000066400000000000000000000400601360521144700265750ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmSurfaceDistortion.h" #include "AlgorithmException.h" #include "AlgorithmMetricSmoothing.h" #include "FloatMatrix.h" #include "MathFunctions.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "TopologyHelper.h" #include "Vector3D.h" #include #include using namespace caret; using namespace std; AString AlgorithmSurfaceDistortion::getCommandSwitch() { return "-surface-distortion"; } AString AlgorithmSurfaceDistortion::getShortDescription() { return "MEASURE DISTORTION BETWEEN SURFACES"; } OperationParameters* AlgorithmSurfaceDistortion::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface-reference", "the reference surface"); ret->addSurfaceParameter(2, "surface-distorted", "the distorted surface"); ret->addMetricOutputParameter(3, "metric-out", "the output distortion metric"); OptionalParameter* smoothOpt = ret->createOptionalParameter(4, "-smooth", "smooth the area data"); smoothOpt->addDoubleParameter(1, "sigma", "the smoothing kernel sigma in mm"); ret->createOptionalParameter(5, "-caret5-method", "use the surface distortion method from caret5"); ret->createOptionalParameter(6, "-edge-method", "calculate distortion of edge lengths rather than areas"); OptionalParameter* strainOpt = ret->createOptionalParameter(7, "-local-affine-method", "calculate distortion by the local affines between triangles"); strainOpt->createOptionalParameter(1, "-log2", "apply base-2 log transform"); ret->setHelpText( AString("This command, when not using -caret5-method, -edge-method, or -local-affine-method, is equivalent to using -surface-vertex-areas on each surface, ") + "smoothing both output metrics with the GEO_GAUSS_EQUAL method on the surface they came from if -smooth is specified, and then using the formula " + "'ln(distorted/reference)/ln(2)' on the smoothed results.\n\n" + "When using -caret5-method, it uses the surface distortion method from caret5, which takes the base 2 log of the ratio of tile areas, " + "then averages those results at each vertex, and then smooths the result on the reference surface.\n\n" + "When using -edge-method, the -smooth option is ignored, and the output at each vertex is the average of 'abs(ln(refEdge/distortEdge)/ln(2))' over all edges " + "connected to the vertex.\n\n" + "When using -local-affine-method, the -smooth option is ignored. The output is two columns, the first is the area distortion ratio, and the second is anisotropic strain. " + "These are calculated by an affine transform between matching triangles, and then averaged across the triangles of a vertex." ); return ret; } void AlgorithmSurfaceDistortion::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* referenceSurf = myParams->getSurface(1); SurfaceFile* distortedSurf = myParams->getSurface(2); MetricFile* myMetricOut = myParams->getOutputMetric(3); float smooth = -1.0f; OptionalParameter* smoothOpt = myParams->getOptionalParameter(4); if (smoothOpt->m_present) { smooth = (float)smoothOpt->getDouble(1); if (smooth <= 0.0f) throw AlgorithmException("smoothing kernel must be positive if specified"); } int methodCount = 0; bool caret5method = myParams->getOptionalParameter(5)->m_present; if (caret5method) ++methodCount; bool edgeMethod = myParams->getOptionalParameter(6)->m_present; if (edgeMethod) ++methodCount; bool strainMethod = false; bool strainLog2 = false; OptionalParameter* strainOpt = myParams->getOptionalParameter(7); if (strainOpt->m_present) { strainMethod = true; ++methodCount; strainLog2 = strainOpt->getOptionalParameter(1)->m_present; } if (methodCount > 1) throw AlgorithmException("you may not specify more than one of -caret5-method, -edge-method, or -local-affine-method"); AlgorithmSurfaceDistortion(myProgObj, referenceSurf, distortedSurf, myMetricOut, smooth, caret5method, edgeMethod, strainMethod, strainLog2); } AlgorithmSurfaceDistortion::AlgorithmSurfaceDistortion(ProgressObject* myProgObj, const SurfaceFile* referenceSurf, const SurfaceFile* distortedSurf, MetricFile* myMetricOut, const float& smooth, const bool& caret5method, const bool& edgeMethod, const bool& strainMethod, const bool& strainLog2) : AbstractAlgorithm(myProgObj) { int methodCount = 0; if (caret5method) ++methodCount; if (edgeMethod) ++methodCount; if (strainMethod) ++methodCount; if (methodCount > 1) throw AlgorithmException("you may not use multiple method flags"); ProgressObject* smoothRef = NULL, *smoothDistort = NULL, *caret5Smooth = NULL; if (myProgObj != NULL) { if (smooth > 0.0f && !edgeMethod && !strainMethod) { if (caret5method) { caret5Smooth = myProgObj->addAlgorithm(AlgorithmMetricSmoothing::getAlgorithmWeight()); } else { smoothRef = myProgObj->addAlgorithm(AlgorithmMetricSmoothing::getAlgorithmWeight()); smoothDistort = myProgObj->addAlgorithm(AlgorithmMetricSmoothing::getAlgorithmWeight()); } } } LevelProgress myProgress(myProgObj); if (!referenceSurf->hasNodeCorrespondence(*distortedSurf)) throw AlgorithmException("input surfaces must have node correspondence"); int numNodes = referenceSurf->getNumberOfNodes(); int numOutCols = 1; if (strainMethod) numOutCols = 2; myMetricOut->setNumberOfNodesAndColumns(numNodes, numOutCols); myMetricOut->setStructure(referenceSurf->getStructure()); if (caret5method) { myMetricOut->setColumnName(0, "area distortion (caret5)"); int numTiles = referenceSurf->getNumberOfTriangles(); vector tilescratch(numTiles), nodescratch(numNodes); const float* refCoords = referenceSurf->getCoordinateData(), *distortCoords = distortedSurf->getCoordinateData(); for (int i = 0; i < numTiles; ++i) { const int32_t* myTile = referenceSurf->getTriangle(i); int32_t offset[3] = { myTile[0] * 3, myTile[1] * 3, myTile[2] * 3 }; float refarea = MathFunctions::triangleArea(refCoords + offset[0], refCoords + offset[1], refCoords + offset[2]); float distortarea = MathFunctions::triangleArea(distortCoords + offset[0], distortCoords + offset[1], distortCoords + offset[2]); if (refarea == 0.0f) { if (distortarea == 0.0f) { tilescratch[i] = 0.0f; } else { tilescratch[i] = log(10000.0) / log(2.0);//thats what it says } } else { if (distortarea / refarea < 0.00000001) { tilescratch[i] = log(0.00000001) / log(2.0); } else { tilescratch[i] = log(distortarea / refarea) / log(2.0); } } } CaretPointer myhelp = referenceSurf->getTopologyHelper(); for (int i = 0; i < numNodes; ++i) { const vector& myTiles = myhelp->getNodeTiles(i); int tileCount = (int)myTiles.size(); double accum = 0.0; for (int j = 0; j < tileCount; ++j) { accum += tilescratch[myTiles[j]]; } if (tileCount == 0) { nodescratch[i] = 0.0f;//actually, caret5 uses 1 here, but that is wrong, so fix it } else { nodescratch[i] = accum / tileCount; } } if (smooth > 0.0f) { MetricFile tempResult; tempResult.setNumberOfNodesAndColumns(numNodes, 1); tempResult.setValuesForColumn(0, nodescratch.data());//TSC: not sure what the "best" smoothing method here is, but there isn't a "correct" one because this method has flaws AlgorithmMetricSmoothing(caret5Smooth, referenceSurf, &tempResult, smooth, myMetricOut, NULL, false, false, -1, NULL, MetricSmoothingObject::GEO_GAUSS_AREA); myMetricOut->setStructure(referenceSurf->getStructure());//just in case we change where metric smoothing gets structure from myMetricOut->setColumnName(0, "area distortion (caret5)"); } else { myMetricOut->setValuesForColumn(0, nodescratch.data()); } } else if (edgeMethod) { myMetricOut->setColumnName(0, "edge distortion"); CaretPointer myhelp = referenceSurf->getTopologyHelper(); const float* refCoords = referenceSurf->getCoordinateData(), *distortCoords = distortedSurf->getCoordinateData(); for (int i = 0; i < numNodes; ++i) { Vector3D refCenter = refCoords + i * 3; Vector3D distortCenter = distortCoords + i * 3; const vector& neighbors = myhelp->getNodeNeighbors(i); int numNeigh = (int)neighbors.size(); float accum = 0.0f; for (int j = 0; j < numNeigh; ++j) { Vector3D refNeigh = refCoords + neighbors[j] * 3; Vector3D distortNeigh = distortCoords + neighbors[j] * 3; float refLength = (refNeigh - refCenter).length(); float distortLength = (distortNeigh - distortCenter).length(); float ratio; if (refLength < distortLength) { ratio = distortLength / refLength; } else { ratio = refLength / distortLength; } accum += log(ratio) / log(2.0f); } myMetricOut->setValue(i, 0, accum / numNeigh); } } else if (strainMethod) { myMetricOut->setColumnName(0, "area ratio (J)"); myMetricOut->setColumnName(1, "elongation ratio (R)"); int numTris = referenceSurf->getNumberOfTriangles(); vector affines(numTris); for (int i = 0; i < numTris; ++i) { const int32_t* thisTri = referenceSurf->getTriangle(i); Vector3D allCoords[2][3]; for (int j = 0; j < 3; ++j) { allCoords[0][j] = referenceSurf->getCoordinate(thisTri[j]); allCoords[1][j] = distortedSurf->getCoordinate(thisTri[j]); } float allCoords2D[2][3][2];//ref/dist, vert, x/y for (int k = 0; k < 2; ++k) { Vector3D iHat = (allCoords[k][1] - allCoords[k][0]).normal();//we don't need the triangle normal, so make the 2D basis without cross products Vector3D jHat = allCoords[k][2] - allCoords[k][0]; jHat = (jHat - iHat * iHat.dot(jHat)).normal(); for (int j = 0; j < 3; ++j) { Vector3D tempCoord = allCoords[k][j] - allCoords[k][0];//use a triangle vertex as the origin to make the numbers smaller, less rounding error allCoords2D[k][j][0] = iHat.dot(tempCoord); allCoords2D[k][j][1] = jHat.dot(tempCoord); } } affines[i].resize(2, 2, true); FloatMatrix solver(3, 4);//3 equations, 3 unknowns for (int k = 0; k < 2; ++k) { for (int j = 0; j < 3; ++j) { solver[j][0] = allCoords2D[0][j][0];//x solver[j][1] = allCoords2D[0][j][1];//y solver[j][2] = 1; solver[j][3] = allCoords2D[1][j][k];//x' or y' } FloatMatrix solved = solver.reducedRowEchelon(); affines[i][k][0] = solved[0][3];//x coef affines[i][k][1] = solved[1][3];//y coef } } int numNodes = referenceSurf->getNumberOfNodes(); CaretPointer myTopoHelp = referenceSurf->getTopologyHelper(); for (int i = 0; i < numNodes; ++i) { const vector& myTiles = myTopoHelp->getNodeTiles(i); double accumJ = 0.0, accumR = 0.0; for (int j = 0; j < (int)myTiles.size(); ++j) { FloatMatrix tempMat = affines[myTiles[j]] * affines[myTiles[j]].transpose(); float thisJ = sqrt(tempMat[0][0] * tempMat[1][1] - tempMat[0][1] * tempMat[1][0]);//written-out determinant for 2x2, because FloatMatrix doesn't currently have a generic determinant function float I1_st = (tempMat[0][0] + tempMat[1][1]) / thisJ;//2D formula float thisR; if (I1_st <= 2) { thisR = 1.0; } else { thisR = 0.5 * (I1_st + sqrt(I1_st * I1_st - 4));//convert I1* to (major strain) / (minor strain) } accumJ += thisJ;//not sure which areas to weight by, so for now do a straight average, relying on smoothness inherent in the measures accumR += thisR;//could maybe do some fancy interpolation of the affines in 3D sphere space } if (strainLog2) { myMetricOut->setValue(i, 0, log2(accumJ / myTiles.size())); myMetricOut->setValue(i, 1, log2(accumR / myTiles.size())); } else { myMetricOut->setValue(i, 0, accumJ / myTiles.size()); myMetricOut->setValue(i, 1, accumR / myTiles.size()); } } } else { myMetricOut->setColumnName(0, "area distortion"); MetricFile refAreas, distortAreas; refAreas.setNumberOfNodesAndColumns(numNodes, 1); distortAreas.setNumberOfNodesAndColumns(numNodes, 1); vector scratch; referenceSurf->computeNodeAreas(scratch); refAreas.setValuesForColumn(0, scratch.data()); distortedSurf->computeNodeAreas(scratch); distortAreas.setValuesForColumn(0, scratch.data()); MetricFile refSmoothed, distortSmoothed; const float* refData = refAreas.getValuePointerForColumn(0), *distortData = distortAreas.getValuePointerForColumn(0); if (smooth > 0.0f) { AlgorithmMetricSmoothing(smoothRef, referenceSurf, &refAreas, smooth, &refSmoothed, NULL, false, false, -1, NULL, MetricSmoothingObject::GEO_GAUSS_EQUAL); AlgorithmMetricSmoothing(smoothDistort, distortedSurf, &distortAreas, smooth, &distortSmoothed, NULL, false, false, -1, NULL, MetricSmoothingObject::GEO_GAUSS_EQUAL); refData = refSmoothed.getValuePointerForColumn(0); distortData = distortSmoothed.getValuePointerForColumn(0); } for (int i = 0; i < numNodes; ++i) { scratch[i] = log(distortData[i] / refData[i]) / log(2.0f);//should we sanity check these? } myMetricOut->setValuesForColumn(0, scratch.data()); } } float AlgorithmSurfaceDistortion::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmSurfaceDistortion::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceDistortion.h000066400000000000000000000037431360521144700262310ustar00rootroot00000000000000#ifndef __ALGORITHM_SURFACE_DISTORTION_H__ #define __ALGORITHM_SURFACE_DISTORTION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmSurfaceDistortion : public AbstractAlgorithm { AlgorithmSurfaceDistortion(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmSurfaceDistortion(ProgressObject* myProgObj, const SurfaceFile* referenceSurf, const SurfaceFile* distortedSurf, MetricFile* myMetricOut, const float& smooth = -1.0f, const bool& caret5method = false, const bool& edgeMethod = false, const bool& strainMethod = false, const bool& strainLog2 = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmSurfaceDistortion; } #endif //__ALGORITHM_SURFACE_DISTORTION_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceFlipLR.cxx000066400000000000000000000065011360521144700255710ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmSurfaceFlipLR.h" #include "AlgorithmException.h" #include "SurfaceFile.h" using namespace caret; using namespace std; AString AlgorithmSurfaceFlipLR::getCommandSwitch() { return "-surface-flip-lr"; } AString AlgorithmSurfaceFlipLR::getShortDescription() { return "MIRROR A SURFACE THROUGH THE YZ PLANE"; } OperationParameters* AlgorithmSurfaceFlipLR::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to flip"); ret->addSurfaceOutputParameter(2, "surface-out", "the output flipped surface"); ret->setHelpText( AString("This command negates the x coordinate of each vertex, and flips the surface normals, so that you have a surface of ") + "opposite handedness with the same features and vertex correspondence, with normals consistent with the original surface. " + "That is, if the input surface has normals facing outward, the output surface will also have normals facing outward." ); return ret; } void AlgorithmSurfaceFlipLR::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* mySurf = myParams->getSurface(1); SurfaceFile* mySurfOut = myParams->getOutputSurface(2); AlgorithmSurfaceFlipLR(myProgObj, mySurf, mySurfOut); } AlgorithmSurfaceFlipLR::AlgorithmSurfaceFlipLR(ProgressObject* myProgObj, const SurfaceFile* mySurf, SurfaceFile* mySurfOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); mySurfOut->setNumberOfNodesAndTriangles(mySurf->getNumberOfNodes(), mySurf->getNumberOfTriangles()); mySurfOut->setSurfaceType(mySurf->getSurfaceType()); mySurfOut->setSecondaryType(mySurf->getSecondaryType()); int numNodes = mySurf->getNumberOfNodes(); float tempcoord[3]; for (int i = 0; i < numNodes; ++i) { mySurf->getCoordinate(i, tempcoord); tempcoord[0] = -tempcoord[0]; mySurfOut->setCoordinate(i, tempcoord); } int numTiles = mySurf->getNumberOfTriangles(); for (int i = 0; i < numTiles; ++i) { const int32_t* temptile = mySurf->getTriangle(i); mySurfOut->setTriangle(i, temptile[1], temptile[0], temptile[2]); } } float AlgorithmSurfaceFlipLR::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmSurfaceFlipLR::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceFlipLR.h000066400000000000000000000032221360521144700252130ustar00rootroot00000000000000#ifndef __ALGORITHM_SURFACE_FLIP_LR_H__ #define __ALGORITHM_SURFACE_FLIP_LR_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmSurfaceFlipLR : public AbstractAlgorithm { AlgorithmSurfaceFlipLR(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmSurfaceFlipLR(ProgressObject* myProgObj, const SurfaceFile* mySurf, SurfaceFile* mySurfOut); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmSurfaceFlipLR; } #endif //__ALGORITHM_SURFACE_FLIP_LR_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceGenerateInflated.cxx000066400000000000000000000223251360521144700276440ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "CaretLogger.h" #include "AlgorithmSurfaceGenerateInflated.h" #include "AlgorithmSurfaceInflation.h" #include "AlgorithmException.h" #include "SurfaceFile.h" using namespace caret; /** * \class caret::AlgorithmSurfaceGenerateInflated * \brief SURFACE GENERATE INFLATED * * */ /** * @return Command line switch */ AString AlgorithmSurfaceGenerateInflated::getCommandSwitch() { return "-surface-generate-inflated"; } /** * @return Short description of algorithm */ AString AlgorithmSurfaceGenerateInflated::getShortDescription() { return "SURFACE GENERATE INFLATED"; } /** * @return Parameters for algorithm */ OperationParameters* AlgorithmSurfaceGenerateInflated::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "anatomical-surface-in", "the anatomical surface"); ret->addSurfaceOutputParameter(2, "inflated-surface-out", "the output inflated surface"); ret->addSurfaceOutputParameter(3, "very-inflated-surface-out", "the output very inflated surface"); OptionalParameter* weightOpt = ret->createOptionalParameter(4, "-iterations-scale", "optional iterations scaling"); weightOpt->addDoubleParameter(1, "iterations-scale-value", "iterations-scale value"); AString helpText = ("Generate inflated and very inflated surfaces. The output surfaces are " "\'matched\' (have same XYZ range) to the anatomical surface. " "In most cases, an iterations-scale of 1.0 (default) is sufficient. However, if " "the surface contains a large number of vertices (150,000), try an " "iterations-scale of 2.5."); ret->setHelpText(helpText); return ret; } /** * Use Parameters and perform algorithm * @param myParams * Parameters for algorithm * @param myProgObj * The progress object * @throws * AlgorithmException if errors */ void AlgorithmSurfaceGenerateInflated::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { const SurfaceFile* anatomicalSurfaceIn = myParams->getSurface(1); SurfaceFile* inflatedSurfaceFile = myParams->getOutputSurface(2); SurfaceFile* veryInflatedSurfaceFile = myParams->getOutputSurface(3); float iterationsScale = 1.0; OptionalParameter* iterationsScaleOpt = myParams->getOptionalParameter(4); if (iterationsScaleOpt->m_present) { iterationsScale = iterationsScaleOpt->getDouble(1); } /* * Constructs and executes the algorithm */ AlgorithmSurfaceGenerateInflated(myProgObj, anatomicalSurfaceIn, inflatedSurfaceFile, veryInflatedSurfaceFile, iterationsScale); } /** * Constructor * * Calling the constructor will execute the algorithm * * @param myProgObj * Parameters for algorithm * @param anatomicalSurfaceFile * The anatomical surface. * @param inflatedSurfaceFileOut * Inflated surface that is generated. * @param veryInflatedSurfaceFileOut * Very inflated surface that is generated. * @param iterationsScaleIn * Iterations scale used for surface with large numbers of nodes. */ AlgorithmSurfaceGenerateInflated::AlgorithmSurfaceGenerateInflated(ProgressObject* myProgObj, const SurfaceFile* anatomicalSurfaceFile, SurfaceFile* inflatedSurfaceFileOut, SurfaceFile* veryInflatedSurfaceFileOut, const float iterationsScaleIn) : AbstractAlgorithm(myProgObj) { ProgressObject* lowProgress = NULL, *inflatedProgress = NULL, *veryInfProgress = NULL; if (myProgObj != NULL) { lowProgress = myProgObj->addAlgorithm(AlgorithmSurfaceInflation::getAlgorithmWeight()); inflatedProgress = myProgObj->addAlgorithm(AlgorithmSurfaceInflation::getAlgorithmWeight() * 2); veryInfProgress = myProgObj->addAlgorithm(AlgorithmSurfaceInflation::getAlgorithmWeight() * 4); } /* * Sets the algorithm up to use the progress object, and will * finish the progress object automatically when the algorithm terminates */ LevelProgress myProgress(myProgObj, 1.0f, 0.1f);//low internal weight because this function doesn't do much non-subalgorithm stuff const float iterationsScale = ((iterationsScaleIn > 0.0) ? iterationsScaleIn : 1.0); /* * Generate low-smooth surface which is an intermediate surface * between anatomical and inflated. */ SurfaceFile lowSmoothSurface(*anatomicalSurfaceFile); const int32_t lowSmoothCycles = 1; const float lowSmoothStrength = 0.2; const int32_t lowSmoothIterations = static_cast(50 * iterationsScale); const float lowSmoothInflationFactor = 1.0; myProgress.setTask("Generating Low-smooth Surface"); AlgorithmSurfaceInflation(lowProgress, anatomicalSurfaceFile, &lowSmoothSurface, &lowSmoothSurface, lowSmoothCycles, lowSmoothStrength, lowSmoothIterations, lowSmoothInflationFactor); /* * Generation the inflated surface */ *inflatedSurfaceFileOut = lowSmoothSurface; const int32_t inflatedSmoothCycles = 2; const float inflatedSmoothStrength = 1.0; const int32_t inflatedSmoothIterations = static_cast(30 * iterationsScale); const float inflatedSmoothInflationFactor = 1.4; myProgress.setTask("Generating Inflated Surface"); AlgorithmSurfaceInflation(inflatedProgress, anatomicalSurfaceFile, inflatedSurfaceFileOut, inflatedSurfaceFileOut, inflatedSmoothCycles, inflatedSmoothStrength, inflatedSmoothIterations, inflatedSmoothInflationFactor); inflatedSurfaceFileOut->setSurfaceType(SurfaceTypeEnum::INFLATED); /* * Generation the inflated surface */ *veryInflatedSurfaceFileOut = *inflatedSurfaceFileOut; const int32_t veryInflatedSmoothCycles = 4; const float veryInflatedSmoothStrength = 1.0; const int32_t veryInflatedSmoothIterations = static_cast(30 * iterationsScale); const float veryInflatedSmoothInflationFactor = 1.1; myProgress.setTask("Generating Very Inflated Surface"); AlgorithmSurfaceInflation(veryInfProgress, anatomicalSurfaceFile, veryInflatedSurfaceFileOut, veryInflatedSurfaceFileOut, veryInflatedSmoothCycles, veryInflatedSmoothStrength, veryInflatedSmoothIterations, veryInflatedSmoothInflationFactor); veryInflatedSurfaceFileOut->setSurfaceType(SurfaceTypeEnum::VERY_INFLATED); myProgress.setTask("Matching Bounding Boxes"); inflatedSurfaceFileOut->matchSurfaceBoundingBox(anatomicalSurfaceFile); myProgress.reportProgress(0.5);//report progress of non-subalgorithm computation only veryInflatedSurfaceFileOut->matchSurfaceBoundingBox(anatomicalSurfaceFile); myProgress.reportProgress(1.0);//this isn't really needed, happens automatically when algorithm ends, but for clarity } /** * @return Algorithm internal weight */ float AlgorithmSurfaceGenerateInflated::getAlgorithmInternalWeight() { /* * override this if needed, if the progress bar isn't smooth */ return 0.1f;//we very little inside this algorithm except call other algorithms } /** * @return Algorithm sub-algorithm weight */ float AlgorithmSurfaceGenerateInflated::getSubAlgorithmWeight() { /* * If you use a subalgorithm */ return AlgorithmSurfaceInflation::getAlgorithmWeight() * 7;//7 cycles in total - may deserve factoring in default number of iterations } connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceGenerateInflated.h000066400000000000000000000041061360521144700272660ustar00rootroot00000000000000#ifndef __ALGORITHM_SURFACE_GENERATE_INFLATED_H__ #define __ALGORITHM_SURFACE_GENERATE_INFLATED_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class SurfaceFile; class AlgorithmSurfaceGenerateInflated : public AbstractAlgorithm { private: AlgorithmSurfaceGenerateInflated(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmSurfaceGenerateInflated(ProgressObject* myProgObj, const SurfaceFile* anatomicalSurfaceFile, SurfaceFile* inflatedSurfaceFileOut, SurfaceFile* veryInflatedSurfaceFileOut, const float iterationsScale); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmSurfaceGenerateInflated; } // namespace #endif //__ALGORITHM_SURFACE_GENERATE_INFLATED_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceInflation.cxx000066400000000000000000000166351360521144700263750ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AlgorithmSurfaceInflation.h" #include "AlgorithmSurfaceSmoothing.h" #include "AlgorithmException.h" #include "BoundingBox.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "SurfaceFile.h" using namespace caret; /** * \class caret::AlgorithmSurfaceInflation * \brief SURFACE INFLATION * * Perfom surface inflation. */ /** * @return Command line switch */ AString AlgorithmSurfaceInflation::getCommandSwitch() { return "-surface-inflation"; } /** * @return Short description of algorithm */ AString AlgorithmSurfaceInflation::getShortDescription() { return "SURFACE INFLATION"; } /** * @return Parameters for algorithm */ OperationParameters* AlgorithmSurfaceInflation::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "anatomical-surface-in", "the anatomical surface"); ret->addSurfaceParameter(2, "surface-in", "the surface file to inflate"); ret->addIntegerParameter(3, "number-of-smoothing-cycles", "number of smoothing cycles"); ret->addDoubleParameter(4, "smoothing-strength", "smoothing strength (ranges [0.0 - 1.0])"); ret->addIntegerParameter(5, "smoothing-iterations", "smoothing iterations"); ret->addDoubleParameter(6, "inflation-factor", "inflation factor"); ret->addSurfaceOutputParameter(7, "surface-out", "output surface file"); AString helpText = ("Inflate a surface by performing cycles that consist of smoothing " " followed by inflation (to correct shrinkage caused by smoothing)."); ret->setHelpText(helpText); return ret; } /** * Use Parameters and perform algorithm * @param myParams * Parameters for algorithm * @param myProgObj * The progress object * @throws * AlgorithmException if errors */ void AlgorithmSurfaceInflation::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* anatomicalSurfaceIn = myParams->getSurface(1); SurfaceFile* surfaceIn = myParams->getSurface(2); const int32_t cycles = myParams->getInteger(3); const float strength = myParams->getDouble(4); const int32_t iterations = myParams->getInteger(5); const float inflationFactor = myParams->getDouble(6); SurfaceFile* surfaceOut = myParams->getOutputSurface(7); /* * Constructs and executes the algorithm */ AlgorithmSurfaceInflation(myProgObj, anatomicalSurfaceIn, surfaceIn, surfaceOut, cycles, strength, iterations, inflationFactor); } /** * Constructor * * Calling the constructor will execute the algorithm * * @param myProgObj * Parameters for algorithm */ AlgorithmSurfaceInflation::AlgorithmSurfaceInflation(ProgressObject* myProgObj, const SurfaceFile* anatomicalSurfaceFile, const SurfaceFile* inputSurfaceFile, SurfaceFile* outputSurfaceFile, const int32_t cycles, const float strength, const int32_t iterations, const float inflationFactorIn) : AbstractAlgorithm(myProgObj) { std::vector subAlgProgress; if (myProgObj != NULL) { subAlgProgress.resize(cycles); for (int32_t i = 0; i < cycles; ++i) { subAlgProgress[i] = myProgObj->addAlgorithm(AlgorithmSurfaceSmoothing::getAlgorithmWeight()); } } /* * Sets the algorithm up to use the progress object, and will * finish the progress object automatically when the algorithm terminates */ LevelProgress myProgress(myProgObj, 1.0f, 0.1f);//lower the internal weight const float inflationFactor = inflationFactorIn - 1.0; *outputSurfaceFile = *inputSurfaceFile; outputSurfaceFile->translateToCenterOfMass(); const BoundingBox* anatomicalBoundingBox = anatomicalSurfaceFile->getBoundingBox(); const float anatomicalRangeX = anatomicalBoundingBox->getDifferenceX(); const float anatomicalRangeY = anatomicalBoundingBox->getDifferenceY(); const float anatomicalRangeZ = anatomicalBoundingBox->getDifferenceZ(); const int32_t numberOfNodes = outputSurfaceFile->getNumberOfNodes(); for (int iCycle = 0; iCycle < cycles; iCycle++) { /* * Smooth */ ProgressObject* subProgress = NULL; if (myProgObj != NULL) { subProgress = subAlgProgress[iCycle]; } AlgorithmSurfaceSmoothing(subProgress, outputSurfaceFile, outputSurfaceFile, strength, iterations); /* * Inflate */ float xyz[3]; for (int32_t iNode = 0; iNode < numberOfNodes; iNode++) { outputSurfaceFile->getCoordinate(iNode, xyz); const float x = xyz[0] / anatomicalRangeX; const float y = xyz[1] / anatomicalRangeY; const float z = xyz[2] / anatomicalRangeZ; const float radius = std::sqrt(x*x + y*y + z*z); const float scale = 1.0 + inflationFactor * (1.0 - radius); xyz[0] *= scale; xyz[1] *= scale; xyz[2] *= scale; outputSurfaceFile->setCoordinate(iNode, xyz); } myProgress.reportProgress(static_cast(iCycle +1) / static_cast(cycles)); } outputSurfaceFile->computeNormals(); } /** * @return Algorithm internal weight */ float AlgorithmSurfaceInflation::getAlgorithmInternalWeight() { /* * override this if needed, if the progress bar isn't smooth */ return 0.1f;//all this does internally is rescale the coordinates, lower the internal weight } /** * @return Algorithm sub-algorithm weight */ float AlgorithmSurfaceInflation::getSubAlgorithmWeight() { /* * If you use a subalgorithm */ return AlgorithmSurfaceSmoothing::getAlgorithmWeight(); } connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceInflation.h000066400000000000000000000041671360521144700260170ustar00rootroot00000000000000#ifndef __ALGORITHM_SURFACE_INFLATION_H__ #define __ALGORITHM_SURFACE_INFLATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmSurfaceInflation : public AbstractAlgorithm { private: AlgorithmSurfaceInflation(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmSurfaceInflation(ProgressObject* myProgObj, const SurfaceFile* anatomicalSurfaceFile, const SurfaceFile* inputSurfaceFile, SurfaceFile* outputSurfaceFile, const int32_t cycles, const float strength, const int32_t iterations, const float inflationFactorIn); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmSurfaceInflation; } // namespace #endif //__ALGORITHM_SURFACE_INFLATION_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceMatch.cxx000066400000000000000000000124731360521144700255020ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "CaretLogger.h" #include "AlgorithmSurfaceMatch.h" #include "AlgorithmException.h" #include "DataFileException.h" #include "SurfaceFile.h" using namespace caret; /** * \class caret::AlgorithmSurfaceMatch * \brief surface match * * */ /** * @return Command line switch */ AString AlgorithmSurfaceMatch::getCommandSwitch() { return "-surface-match"; } /** * @return Short description of algorithm */ AString AlgorithmSurfaceMatch::getShortDescription() { return "SURFACE MATCH"; } /** * @return Parameters for algorithm */ OperationParameters* AlgorithmSurfaceMatch::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "Match Surface File", "Match (Reference) Surface"); ret->addSurfaceParameter(2, "Input Surface File", "File containing surface that will be transformed"); ret->addStringParameter(3, "Output Surface Name", "Surface File after transformation"); AString helpText = ("The Input Surface File will be transformed so that its coordinate " "ranges (bounding box) match that of the Match Surface File"); ret->setHelpText(helpText); return ret; } /** * Use Parameters and perform algorithm * @param myParams * Parameters for algorithm * @param myProgObj * The progress object * @throws * AlgorithmException if errors */ void AlgorithmSurfaceMatch::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { try { SurfaceFile* matchSurfaceFile = myParams->getSurface(1); SurfaceFile* surfaceFile = myParams->getSurface(2); const AString outputSurfaceFileName = myParams->getString(3); /* * Example parameter processing: * * Gets the surface with key 1 * SurfaceFile* mySurf = myParams->getSurface(1); * * Gets the output metric with key 2 * MetricFile* myMetricOut = myParams->getOutputMetric(2); * * Gets optional parameter with key 3 * OptionalParameter* columnSelect = myParams->getOptionalParameter(3); * int columnNum = -1; * if (columnSelect->m_present) { * columnNum = (int)myMetric->getMapIndexFromNameOrNumber(columnSelect->getString(1)); * if (columnNum < 0) { * throw AlgorithmException("invalid column specified"); * } * } */ /* * Constructs and executes the algorithm */ AlgorithmSurfaceMatch(myProgObj, matchSurfaceFile, surfaceFile); surfaceFile->writeFile(outputSurfaceFileName); } catch (const DataFileException& dfe) { throw AlgorithmException(dfe); } } /** * Constructor * * Calling the constructor will execute the algorithm * * @param myProgObj * Parameters for algorithm */ AlgorithmSurfaceMatch::AlgorithmSurfaceMatch(ProgressObject* myProgObj, const SurfaceFile* matchSurfaceFile, SurfaceFile* surfaceFile) : AbstractAlgorithm(myProgObj) { /* * Uncomment these if you use another algorithm inside here * * ProgressObject* subAlgProgress1 = NULL; * if (myProgObj != NULL) { * subAlgProgress1 = myProgObj->addAlgorithm(AlgorithmInsertNameHere::getAlgorithmWeight()); * } */ /* * Sets the algorithm up to use the progress object, and will * finish the progress object automatically when the algorithm terminates */ LevelProgress myProgress(myProgObj); surfaceFile->matchSurfaceBoundingBox(matchSurfaceFile); /* * How you say you are halfway done with the INTERNAL work of the algorithm * will report finished automatically when this function ends (myProgress goes out of scope, destructor triggers finish */ //myProgress.reportProgress(0.5f); } /** * @return Algorithm internal weight */ float AlgorithmSurfaceMatch::getAlgorithmInternalWeight() { /* * override this if needed, if the progress bar isn't smooth */ return 1.0f; } /** * @return Algorithm sub-algorithm weight */ float AlgorithmSurfaceMatch::getSubAlgorithmWeight() { /* * If you use a subalgorithm */ //return AlgorithmInsertNameHere::getAlgorithmWeight() return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceMatch.h000066400000000000000000000034211360521144700251200ustar00rootroot00000000000000#ifndef __ALGORITHM_SURFACE_MATCH_H__ #define __ALGORITHM_SURFACE_MATCH_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmSurfaceMatch : public AbstractAlgorithm { private: AlgorithmSurfaceMatch(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmSurfaceMatch(ProgressObject* myProgObj, const SurfaceFile* matchSurfaceFile, SurfaceFile* surfaceFile); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmSurfaceMatch; } // namespace #endif //__ALGORITHM_SURFACE_MATCH_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceModifySphere.cxx000066400000000000000000000135541360521144700270450ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmSurfaceModifySphere.h" #include "AlgorithmException.h" #include "BoundingBox.h" #include "CaretLogger.h" #include "SurfaceFile.h" #include "Vector3D.h" using namespace caret; using namespace std; AString AlgorithmSurfaceModifySphere::getCommandSwitch() { return "-surface-modify-sphere"; } AString AlgorithmSurfaceModifySphere::getShortDescription() { return "CHANGE RADIUS AND OPTIONALLY RECENTER A SPHERE"; } OperationParameters* AlgorithmSurfaceModifySphere::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "sphere-in", "the sphere to modify"); ret->addDoubleParameter(2, "radius", "the radius the output sphere should have"); ret->addSurfaceOutputParameter(3, "sphere-out", "the output sphere"); ret->createOptionalParameter(4, "-recenter", "recenter the sphere by means of the bounding box"); //TODO: add option to supress warnings? ret->setHelpText( AString("This command may be useful if you have used -surface-resample to resample a sphere, which can suffer from problems generally not present in ") + "-surface-sphere-project-unproject. If the sphere should already be centered around the origin, using -recenter may still shift it slightly before changing the radius, " + "which is likely to be undesireable.\n\n" + "If is not close to spherical, or not centered around the origin and -recenter is not used, a warning is printed." ); return ret; } void AlgorithmSurfaceModifySphere::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* mySphere = myParams->getSurface(1); float newRadius = (float)myParams->getDouble(2); SurfaceFile* outSphere = myParams->getOutputSurface(3); bool recenter = myParams->getOptionalParameter(4)->m_present; AlgorithmSurfaceModifySphere(myProgObj, mySphere, newRadius, outSphere, recenter); } AlgorithmSurfaceModifySphere::AlgorithmSurfaceModifySphere(ProgressObject* myProgObj, const SurfaceFile* mySphere, const float& newRadius, SurfaceFile* outSphere, const bool& recenter) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); bool originVertexWarned = false, nanWarned = false; Vector3D center;//initializes to the origin if (recenter) { const BoundingBox* mybb = mySphere->getBoundingBox(); mybb->getCenter(center); } int numNodes = mySphere->getNumberOfNodes(); CaretAssert(numNodes > 1); int numNodes3 = numNodes * 3; const float* coordData = mySphere->getCoordinateData(); float mindist = 0.0f, maxdist = 0.0f; bool first = true; const float TOLERANCE = 1.05f;//5% is a very loose tolerance, we expect some odd spheres *outSphere = *mySphere; vector outCoords(numNodes3); for (int i = 0; i < numNodes3; i += 3) { Vector3D recenterCoord = Vector3D(coordData + i) - center; float tempf = recenterCoord.length(); if (tempf == 0.0f) { outCoords[i] = newRadius; outCoords[i + 1] = 0.0f; outCoords[i + 2] = 0.0f; if (!originVertexWarned) { CaretLogWarning("found at least one vertex at origin, moved to +x position"); originVertexWarned = true; } } else if (tempf != tempf) { outCoords[i] = newRadius; outCoords[i + 1] = 0.0f; outCoords[i + 2] = 0.0f; if (!nanWarned) { CaretLogWarning("found at least one NaN vertex, moved to +x position"); nanWarned = true; } } else { Vector3D outCoord = recenterCoord * (newRadius / tempf); outCoords[i] = outCoord[0]; outCoords[i + 1] = outCoord[1]; outCoords[i + 2] = outCoord[2]; if (first) { first = false; mindist = tempf; maxdist = tempf; } else { if (tempf < mindist) { mindist = tempf; } if (tempf > maxdist) { maxdist = tempf; } } } } if (first) { throw AlgorithmException("all vertices were located at the origin, aborting"); } else { if (mindist * TOLERANCE < maxdist) { if (recenter) { CaretLogWarning("input sphere is unusually irregular, inspect the input"); } else { CaretLogWarning("input sphere is either unusually irregular or not centered, inspect the input"); } } } outSphere->setCoordinates(outCoords.data()); } float AlgorithmSurfaceModifySphere::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmSurfaceModifySphere::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceModifySphere.h000066400000000000000000000033721360521144700264670ustar00rootroot00000000000000#ifndef __ALGORITHM_SURFACE_MODIFY_SPHERE_H__ #define __ALGORITHM_SURFACE_MODIFY_SPHERE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmSurfaceModifySphere : public AbstractAlgorithm { AlgorithmSurfaceModifySphere(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmSurfaceModifySphere(ProgressObject* myProgObj, const SurfaceFile* mySphere, const float& newRadius, SurfaceFile* outSphere, const bool& recenter = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmSurfaceModifySphere; } #endif //__ALGORITHM_SURFACE_MODIFY_SPHERE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceResample.cxx000066400000000000000000000214221360521144700262100ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmSurfaceResample.h" #include "AlgorithmException.h" #include "CaretLogger.h" #include "GiftiMetaData.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "SurfaceResamplingHelper.h" using namespace caret; using namespace std; AString AlgorithmSurfaceResample::getCommandSwitch() { return "-surface-resample"; } AString AlgorithmSurfaceResample::getShortDescription() { return "RESAMPLE A SURFACE TO A DIFFERENT MESH"; } OperationParameters* AlgorithmSurfaceResample::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface-in", "the surface file to resample"); ret->addSurfaceParameter(2, "current-sphere", "a sphere surface with the mesh that the input surface is currently on"); ret->addSurfaceParameter(3, "new-sphere", "a sphere surface that is in register with and has the desired output mesh"); ret->addStringParameter(4, "method", "the method name"); ret->addSurfaceOutputParameter(5, "surface-out", "the output surface file"); OptionalParameter* areaSurfsOpt = ret->createOptionalParameter(6, "-area-surfs", "specify surfaces to do vertex area correction based on"); areaSurfsOpt->addSurfaceParameter(1, "current-area", "a relevant surface with mesh"); areaSurfsOpt->addSurfaceParameter(2, "new-area", "a relevant surface with mesh"); OptionalParameter* areaMetricsOpt = ret->createOptionalParameter(7, "-area-metrics", "specify vertex area metrics to do area correction based on"); areaMetricsOpt->addMetricParameter(1, "current-area", "a metric file with vertex areas for mesh"); areaMetricsOpt->addMetricParameter(2, "new-area", "a metric file with vertex areas for mesh"); AString myHelpText = AString("Resamples a surface file, given two spherical surfaces that are in register. ") + "If ADAP_BARY_AREA is used, exactly one of -area-surfs or -area-metrics must be specified. " + "This method is not generally recommended for surface resampling, but is provided for completeness.\n\n" + "The BARYCENTRIC method is generally recommended for anatomical surfaces, in order to minimize smoothing.\n\n" + "For cut surfaces (including flatmaps), use -surface-cut-resample.\n\n" + "Instead of resampling a spherical surface, the -surface-sphere-project-unproject command is recommended.\n\n" + "The argument must be one of the following:\n\n"; vector allEnums; SurfaceResamplingMethodEnum::getAllEnums(allEnums); for (int i = 0; i < (int)allEnums.size(); ++i) { myHelpText += SurfaceResamplingMethodEnum::toName(allEnums[i]) + "\n"; } ret->setHelpText(myHelpText); return ret; } void AlgorithmSurfaceResample::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* surfaceIn = myParams->getSurface(1); SurfaceFile* curSphere = myParams->getSurface(2); SurfaceFile* newSphere = myParams->getSurface(3); bool ok = false; SurfaceResamplingMethodEnum::Enum myMethod = SurfaceResamplingMethodEnum::fromName(myParams->getString(4), &ok); if (!ok) { throw AlgorithmException("invalid method name"); } SurfaceFile* surfaceOut = myParams->getOutputSurface(5); MetricFile* curAreas = NULL, *newAreas = NULL; MetricFile curAreasTemp, newAreasTemp; OptionalParameter* areaSurfsOpt = myParams->getOptionalParameter(6); if (areaSurfsOpt->m_present) { switch(myMethod) { case SurfaceResamplingMethodEnum::BARYCENTRIC: CaretLogInfo("This method does not use area correction, -area-surfs is not needed"); break; default: break; } vector nodeAreasTemp; SurfaceFile* curAreaSurf = areaSurfsOpt->getSurface(1); SurfaceFile* newAreaSurf = areaSurfsOpt->getSurface(2); curAreaSurf->computeNodeAreas(nodeAreasTemp); curAreasTemp.setNumberOfNodesAndColumns(curAreaSurf->getNumberOfNodes(), 1); curAreasTemp.setValuesForColumn(0, nodeAreasTemp.data()); curAreas = &curAreasTemp; newAreaSurf->computeNodeAreas(nodeAreasTemp); newAreasTemp.setNumberOfNodesAndColumns(newAreaSurf->getNumberOfNodes(), 1); newAreasTemp.setValuesForColumn(0, nodeAreasTemp.data()); newAreas = &newAreasTemp; } OptionalParameter* areaMetricsOpt = myParams->getOptionalParameter(7); if (areaMetricsOpt->m_present) { if (areaSurfsOpt->m_present) { throw AlgorithmException("only one of -area-surfs and -area-metrics can be specified"); } switch(myMethod) { case SurfaceResamplingMethodEnum::BARYCENTRIC: CaretLogInfo("This method does not use area correction, -area-metrics is not needed"); break; default: break; } curAreas = areaMetricsOpt->getMetric(1); newAreas = areaMetricsOpt->getMetric(2); } AlgorithmSurfaceResample(myProgObj, surfaceIn, curSphere, newSphere, myMethod, surfaceOut, curAreas, newAreas); } AlgorithmSurfaceResample::AlgorithmSurfaceResample(ProgressObject* myProgObj, const SurfaceFile* surfaceIn, const SurfaceFile* curSphere, const SurfaceFile* newSphere, const SurfaceResamplingMethodEnum::Enum& myMethod, SurfaceFile* surfaceOut, const MetricFile* curAreas, const MetricFile* newAreas) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (surfaceIn->getNumberOfNodes() != curSphere->getNumberOfNodes()) throw AlgorithmException("input surface has different number of nodes than input sphere"); const float* curAreaData = NULL, *newAreaData = NULL; switch (myMethod) { case SurfaceResamplingMethodEnum::BARYCENTRIC: break; default: if (curAreas == NULL || newAreas == NULL) throw AlgorithmException("specified method does area correction, but no vertex area data given"); if (curSphere->getNumberOfNodes() != curAreas->getNumberOfNodes()) throw AlgorithmException("current vertex area data has different number of nodes than current sphere"); if (newSphere->getNumberOfNodes() != newAreas->getNumberOfNodes()) throw AlgorithmException("new vertex area data has different number of nodes than new sphere"); curAreaData = curAreas->getValuePointerForColumn(0); newAreaData = newAreas->getValuePointerForColumn(0); } int numNewNodes = newSphere->getNumberOfNodes(); GiftiMetaData savedMD; GiftiMetaData* provenanceMD = surfaceOut->getFileMetaData();//save provenance, since we are using operator= on surface as a hack around setting the topology if (provenanceMD != NULL) { savedMD = *provenanceMD;//put it into a local instance, because operator= will probably change the one the pointer refers to } *surfaceOut = *newSphere; provenanceMD = surfaceOut->getFileMetaData();//in case the pointer changes anyway if (provenanceMD != NULL) { *provenanceMD = savedMD;//put it back } surfaceOut->setStructure(surfaceIn->getStructure()); surfaceOut->setSecondaryType(surfaceIn->getSecondaryType()); surfaceOut->setSurfaceType(surfaceIn->getSurfaceType()); vector coordScratch(numNewNodes * 3, 0.0f); SurfaceResamplingHelper myHelp(myMethod, curSphere, newSphere, curAreaData, newAreaData); myHelp.resample3DCoord(surfaceIn->getCoordinateData(), coordScratch.data()); surfaceOut->setCoordinates(coordScratch.data()); } float AlgorithmSurfaceResample::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmSurfaceResample::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceResample.h000066400000000000000000000036501360521144700256400ustar00rootroot00000000000000#ifndef __ALGORITHM_SURFACE_RESAMPLE_H__ #define __ALGORITHM_SURFACE_RESAMPLE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "SurfaceResamplingMethodEnum.h" namespace caret { class AlgorithmSurfaceResample : public AbstractAlgorithm { AlgorithmSurfaceResample(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmSurfaceResample(ProgressObject* myProgObj, const SurfaceFile* surfaceIn, const SurfaceFile* curSphere, const SurfaceFile* newSphere, const SurfaceResamplingMethodEnum::Enum& myMethod, SurfaceFile* surfaceOut, const MetricFile* curAreaSurf = NULL, const MetricFile* newAreaSurf = NULL); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmSurfaceResample; } #endif //__ALGORITHM_SURFACE_RESAMPLE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceSmoothing.cxx000066400000000000000000000240051360521144700264070ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "CaretLogger.h" #include "AlgorithmSurfaceSmoothing.h" #include "AlgorithmException.h" #include "MathFunctions.h" #include "SurfaceFile.h" #include "TopologyHelper.h" using namespace caret; /** * \class caret::AlgorithmSurfaceSmoothing * \brief SURFACE SMOOTHING * * Smooths a surface. */ /** * @return Command line switch */ AString AlgorithmSurfaceSmoothing::getCommandSwitch() { return "-surface-smoothing"; } /** * @return Short description of algorithm */ AString AlgorithmSurfaceSmoothing::getShortDescription() { return "SURFACE SMOOTHING"; } /** * @return Parameters for algorithm */ OperationParameters* AlgorithmSurfaceSmoothing::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface-in", "the surface file to smooth"); ret->addDoubleParameter(2, "smoothing-strength", "smoothing strength (ranges [0.0 - 1.0])"); ret->addIntegerParameter(3, "smoothing-iterations", "smoothing iterations"); ret->addSurfaceOutputParameter(4, "surface-out", "output surface file"); AString helpText = ("Smooths a surface by averaging vertex coordinates with those of the neighboring vertices."); ret->setHelpText(helpText); return ret; } /** * Use Parameters and perform algorithm * @param myParams * Parameters for algorithm * @param myProgObj * The progress object * @throws * AlgorithmException if errors */ void AlgorithmSurfaceSmoothing::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* surfaceIn = myParams->getSurface(1); const float strength = myParams->getDouble(2); const int32_t iterations = myParams->getInteger(3); SurfaceFile* surfaceOut = myParams->getOutputSurface(4); /* * Constructs and executes the algorithm */ AlgorithmSurfaceSmoothing(myProgObj, surfaceIn, surfaceOut, strength, iterations); } /** * Constructor * * Calling the constructor will execute the algorithm * * @param myProgObj * Parameters for algorithm */ AlgorithmSurfaceSmoothing::AlgorithmSurfaceSmoothing(ProgressObject* myProgObj, const SurfaceFile* inputSurfaceFile, SurfaceFile* outputSurfaceFile, const float strength, const int32_t iterations) : AbstractAlgorithm(myProgObj) { if ((strength < 0.0) || (strength > 1.0)) { throw AlgorithmException("Invalid smoothing strength outside [0.0, 1.0]: " + QString::number(strength, 'f', 5)); } if (iterations <= 0) { throw AlgorithmException("Invalid iterations value [1, infinity]: " + QString::number(iterations)); } /* * Sets the algorithm up to use the progress object, and will * finish the progress object automatically when the algorithm terminates */ LevelProgress myProgress(myProgObj); *outputSurfaceFile = *inputSurfaceFile; CaretPointer myTopoHelp = outputSurfaceFile->getTopologyHelper(true); const int32_t numNodes = outputSurfaceFile->getNumberOfNodes(); if (numNodes <= 0) { return; } /* * Storage for coordinates, input and output of each iteration */ std::vector coordsIn(numNodes * 3); std::vector coordsOut(numNodes * 3); /* * Copy coordinates from surface */ for (int32_t i = 0; i < numNodes; i++) { const float* xyz = outputSurfaceFile->getCoordinate(i); const int32_t i3 = i * 3; coordsIn[i3] = xyz[0]; coordsIn[i3+1] = xyz[1]; coordsIn[i3+2] = xyz[2]; coordsOut[i3] = xyz[0]; coordsOut[i3+1] = xyz[1]; coordsOut[i3+2] = xyz[2]; } std::vector triangleAreas(100); std::vector triangleCenters(100*3); const float inverseStrength = 1.0 - strength; /* * Perform the requested number of iterations */ for (int32_t iter = 1; iter <= iterations; iter++) { /* * Copy coordinates from previous iteration */ if (iter > 1) { coordsIn = coordsOut; } /* * Process each node */ for (int32_t iNode = 0; iNode < numNodes; iNode++) { /* * Get node's neighbors */ int32_t numNeighbors = 0; const int32_t* neighbors = myTopoHelp->getNodeNeighbors(iNode, numNeighbors); if (numNeighbors < 2) { coordsOut[iNode*3] = coordsIn[iNode*3]; coordsOut[iNode*3+1] = coordsIn[iNode*3+1]; coordsOut[iNode*3+2] = coordsIn[iNode*3+2]; } else { /* * Ensure adequate space for triangle areas and center coordinate */ if (numNeighbors > static_cast(triangleAreas.size())) { triangleAreas.resize(numNeighbors); triangleCenters.resize(numNeighbors * 3); } double totalArea = 0.0; /* * Average node with its neighbors */ for (int jn = 0; jn < numNeighbors; jn++) { /* * Get two consecutive neighbors */ const int32_t n1 = neighbors[jn]; int nextNeighborIndex = jn + 1; if (nextNeighborIndex >= numNeighbors) { nextNeighborIndex = 0; } const int32_t n2 = neighbors[nextNeighborIndex]; /* * Coordinates of nodes and neighbors */ const float* c1 = &coordsIn[iNode*3]; const float* c2 = &coordsIn[n1*3]; const float* c3 = &coordsIn[n2*3]; const float area = MathFunctions::triangleArea(c1, c2, c3); /* * Area of triangle formed by node and neighbors */ triangleAreas[jn] = area; totalArea += area; /* * Average of nodes that form triangle */ for (int32_t k = 0; k < 3; k++) { triangleCenters[jn*3+k] = (c1[k] + c2[k] + c3[k]) / 3.0; } } /* * Influence of neighbors */ float neighborAverageX = 0.0; float neighborAverageY = 0.0; float neighborAverageZ = 0.0; for (int j = 0; j < numNeighbors; j++) { if (triangleAreas[j] > 0.0) { const float weight = triangleAreas[j] / totalArea; neighborAverageX += (weight * triangleCenters[j*3]); neighborAverageY += (weight * triangleCenters[j*3+1]); neighborAverageZ += (weight * triangleCenters[j*3+2]); } } /* * Update coordinates */ coordsOut[iNode*3] = ((coordsIn[iNode*3] * inverseStrength) + (neighborAverageX * strength)); coordsOut[iNode*3+1] = ((coordsIn[iNode*3+1] * inverseStrength) + (neighborAverageY * strength)); coordsOut[iNode*3+2] = ((coordsIn[iNode*3+2] * inverseStrength) + (neighborAverageZ * strength)); } } /* * Update progress */ const float percentDone = (static_cast(iter) / static_cast(iterations)); myProgress.reportProgress(percentDone);//give continuous updates, if it slows things down we can reduce the resolution in the progress framework } /* * Copy coordinates into surface */ outputSurfaceFile->setCoordinates(&coordsOut[0]); myProgress.reportProgress(1.0f); } /** * @return Algorithm internal weight */ float AlgorithmSurfaceSmoothing::getAlgorithmInternalWeight() { /* * override this if needed, if the progress bar isn't smooth */ return 1.0f; } /** * @return Algorithm sub-algorithm weight */ float AlgorithmSurfaceSmoothing::getSubAlgorithmWeight() { /* * If you use a subalgorithm */ //return AlgorithmInsertNameHere::getAlgorithmWeight() return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceSmoothing.h000066400000000000000000000036631360521144700260430ustar00rootroot00000000000000#ifndef __ALGORITHM_SURFACE_SMOOTHING_H__ #define __ALGORITHM_SURFACE_SMOOTHING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmSurfaceSmoothing : public AbstractAlgorithm { private: AlgorithmSurfaceSmoothing(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmSurfaceSmoothing(ProgressObject* myProgObj, const SurfaceFile* inputSurfaceFile, SurfaceFile* outputSurfaceFile, const float strength, const int32_t iterations); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmSurfaceSmoothing; } // namespace #endif //__ALGORITHM_SURFACE_SMOOTHING_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceSphereProjectUnproject.cxx000066400000000000000000000231621360521144700311120ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmSurfaceSphereProjectUnproject.h" #include "AlgorithmException.h" #include "CaretOMP.h" #include "SignedDistanceHelper.h" #include "SurfaceFile.h" #include "Vector3D.h" #include using namespace caret; using namespace std; AString AlgorithmSurfaceSphereProjectUnproject::getCommandSwitch() { return "-surface-sphere-project-unproject"; } AString AlgorithmSurfaceSphereProjectUnproject::getShortDescription() { return "COPY REGISTRATION DEFORMATIONS TO DIFFERENT SPHERE"; } OperationParameters* AlgorithmSurfaceSphereProjectUnproject::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "sphere-in", "a sphere with the desired output mesh"); ret->addSurfaceParameter(2, "sphere-project-to", "a sphere that aligns with sphere-in"); ret->addSurfaceParameter(3, "sphere-unproject-from", " deformed to the desired output space"); ret->addSurfaceOutputParameter(4, "sphere-out", "the output sphere"); ret->setHelpText( AString("Background: A surface registration starts with an input sphere, and moves its vertices around on the sphere until it matches the template data. ") + "This means that the registration deformation is actually represented as the difference between two separate files - the starting sphere, and the registered sphere. " + "Since the starting sphere of the registration may not have vertex correspondence to any other sphere (often, it is a native sphere), it can be inconvenient to manipulate or compare these deformations across subjects, etc.\n\n" + "The purpose of this command is to be able to apply these deformations onto a new sphere of the user's choice, to make it easier to compare or manipulate them. " + "Common uses are to concatenate two successive separate registrations (e.g. Human to Chimpanzee, and then Chimpanzee to Macaque) or inversion (for dedrifting or symmetric registration schemes).\n\n" + " must already be considered to be in alignment with one of the two ends of the registration (if your registration is Human to Chimpanzee, must be in register with either Human or Chimpanzee). " + "The 'project-to' sphere must be the side of the registration that is aligned with (if your registration is Human to Chimpanzee, and is aligned with Human, then 'project-to' should be the original Human sphere). " + "The 'unproject-from' sphere must be the remaining sphere of the registration (original vs deformed/registered). " + "The output is as if you had run the same registration with as the starting sphere, in the direction of deforming the 'project-to' sphere to create the 'unproject-from' sphere.\n\n" + "Note that this command cannot check for you what spheres are aligned with other spheres, and using the wrong spheres or in the incorrect order will not necessarily cause an error message. " + "In some cases, it may be useful to use a new, arbitrary sphere as the input, which can be created with the -surface-create-sphere command.\n\n" + "Example 1: You have a Human to Chimpanzee registration, and a Chimpanzee to Macaque registration, and want to combine them. " + "If you use the Human sphere registered to Chimpanzee as sphere-in, the Chimpanzee standard sphere as project-to, and " + "the Chimpanzee sphere registered to Macaque as unproject-from, the output will be the Human sphere in register with the Macaque.\n\n" + "Example 2: You have a Human to Chimpanzee registration, but what you really want is the inverse, that is, the sphere as if you had run the registration from Chimpanzee to Human. " + "If you use the Chimpanzee standard sphere as sphere-in, the Human sphere registered to Chimpanzee as project-to, and the standard Human sphere as unproject-from, " + "the output will be the Chimpanzee sphere in register with the Human.\n\n" + "Technical details: Each vertex of is projected to a triangle of , and its new position is determined by the position of the corresponding triangle in . " + "The output is a sphere with the topology of , but coordinates shifted by the deformation from to . " + " and must have the same topology as each other, but may have any topology." ); return ret; } void AlgorithmSurfaceSphereProjectUnproject::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* sphereIn = myParams->getSurface(1); SurfaceFile* projectSphere = myParams->getSurface(2); SurfaceFile* unprojectSphere = myParams->getSurface(3); SurfaceFile* sphereOut = myParams->getOutputSurface(4); AlgorithmSurfaceSphereProjectUnproject(myProgObj, sphereIn, projectSphere, unprojectSphere, sphereOut);//executes the algorithm } AlgorithmSurfaceSphereProjectUnproject::AlgorithmSurfaceSphereProjectUnproject(ProgressObject* myProgObj, const SurfaceFile* sphereIn, const SurfaceFile* projectSphere, const SurfaceFile* unprojectSphere, SurfaceFile* sphereOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (!projectSphere->hasNodeCorrespondence(*unprojectSphere)) throw AlgorithmException("projection sphere and unprojection sphere do not have vertex correspondence"); if (!checkSphere(sphereIn) || !checkSphere(projectSphere) || !checkSphere(unprojectSphere)) throw AlgorithmException("all inputs must be spheres centered around the origin"); SurfaceFile inMod = *sphereIn, projectMod = *projectSphere, unprojectMod = *unprojectSphere; changeRadius(100.0f, &inMod); changeRadius(100.0f, &projectMod); changeRadius(100.0f, &unprojectMod); const float* unprojectCoords = unprojectMod.getCoordinateData(); const float* inCoords = inMod.getCoordinateData(); int numNodes = sphereIn->getNumberOfNodes(); vector outCoords(numNodes * 3); *sphereOut = *sphereIn; sphereOut->setStructure(unprojectSphere->getStructure()); CaretPointer myHelper = projectMod.getSignedDistanceHelper(); for (int i = 0; i < numNodes; ++i) { int i3 = i * 3; BarycentricInfo myInfo; myHelper->barycentricWeights(inCoords + i3, myInfo); Vector3D outCoord = myInfo.baryWeights[0] * Vector3D(unprojectCoords + myInfo.nodes[0] * 3) + myInfo.baryWeights[1] * Vector3D(unprojectCoords + myInfo.nodes[1] * 3) + myInfo.baryWeights[2] * Vector3D(unprojectCoords + myInfo.nodes[2] * 3); outCoords[i3] = outCoord[0]; outCoords[i3 + 1] = outCoord[1]; outCoords[i3 + 2] = outCoord[2]; } sphereOut->setCoordinates(outCoords.data()); changeRadius(100.0f, sphereOut); } bool AlgorithmSurfaceSphereProjectUnproject::checkSphere(const SurfaceFile* surface) { int numNodes = surface->getNumberOfNodes(); CaretAssert(numNodes > 1); int numNodes3 = numNodes * 3; const float* coordData = surface->getCoordinateData(); float mindist = Vector3D(coordData).length(); if (mindist != mindist) throw CaretException("found NaN coordinate in an input sphere"); float maxdist = mindist; const float TOLERANCE = 1.001f; for (int i = 3; i < numNodes3; i += 3) { float tempf = Vector3D(coordData + i).length(); if (tempf != tempf) throw CaretException("found NaN coordinate in an input sphere"); if (tempf < mindist) { mindist = tempf; } if (tempf > maxdist) { maxdist = tempf; } } return (mindist * TOLERANCE > maxdist); } void AlgorithmSurfaceSphereProjectUnproject::changeRadius(const float& radius, SurfaceFile* inout) { int numNodes = inout->getNumberOfNodes(); int numNodes3 = numNodes * 3; vector newCoordData(numNodes3); const float* oldCoordData = inout->getCoordinateData(); #pragma omp CARET_PARFOR schedule(dynamic) for (int i = 0; i < numNodes3; i += 3) { Vector3D tempvec = Vector3D(oldCoordData + i).normal() * radius; newCoordData[i] = tempvec[0]; newCoordData[i + 1] = tempvec[1]; newCoordData[i + 2] = tempvec[2]; } inout->setCoordinates(newCoordData.data()); } float AlgorithmSurfaceSphereProjectUnproject::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmSurfaceSphereProjectUnproject::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceSphereProjectUnproject.h000066400000000000000000000040061360521144700305330ustar00rootroot00000000000000#ifndef __ALGORITHM_SURFACE_SPHERE_PROJECT_UNPROJECT_H__ #define __ALGORITHM_SURFACE_SPHERE_PROJECT_UNPROJECT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmSurfaceSphereProjectUnproject : public AbstractAlgorithm { AlgorithmSurfaceSphereProjectUnproject(); bool checkSphere(const SurfaceFile* surface); void changeRadius(const float& radius, SurfaceFile* inout); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmSurfaceSphereProjectUnproject(ProgressObject* myProgObj, const SurfaceFile* sphereIn, const SurfaceFile* projectSphere, const SurfaceFile* unprojectSphere, SurfaceFile* sphereOut); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmSurfaceSphereProjectUnproject; } #endif //__ALGORITHM_SURFACE_SPHERE_PROJECT_UNPROJECT_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceToSurface3dDistance.cxx000066400000000000000000000105451360521144700302410ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmSurfaceToSurface3dDistance.h" #include "AlgorithmException.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "Vector3D.h" using namespace caret; using namespace std; AString AlgorithmSurfaceToSurface3dDistance::getCommandSwitch() { return "-surface-to-surface-3d-distance"; } AString AlgorithmSurfaceToSurface3dDistance::getShortDescription() { return "COMPUTE DISTANCE BETWEEN CORRESPONDING VERTICES"; } OperationParameters* AlgorithmSurfaceToSurface3dDistance::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface-comp", "the surface to compare to the reference"); ret->addSurfaceParameter(2, "surface-ref", "the surface to use as the reference"); ret->addMetricOutputParameter(3, "dists-out", "the output distances"); OptionalParameter* vectorOpt = ret->createOptionalParameter(4, "-vectors", "output the displacement vectors"); vectorOpt->addMetricOutputParameter(1, "vectors-out", "the output vectors"); ret->setHelpText( AString("Computes the vector difference between the vertices of each surface with the same index, as (comp - ref), ") + "and output the magnitudes, and optionally the displacement vectors." ); return ret; } void AlgorithmSurfaceToSurface3dDistance::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* myCompSurf = myParams->getSurface(1); SurfaceFile* myRefSurf = myParams->getSurface(2); MetricFile* distsOut = myParams->getOutputMetric(3); MetricFile* vectorsOut = NULL; OptionalParameter* vectorOpt = myParams->getOptionalParameter(4); if (vectorOpt->m_present) { vectorsOut = vectorOpt->getOutputMetric(1); } AlgorithmSurfaceToSurface3dDistance(myProgObj, myCompSurf, myRefSurf, distsOut, vectorsOut); } AlgorithmSurfaceToSurface3dDistance::AlgorithmSurfaceToSurface3dDistance(ProgressObject* myProgObj, const SurfaceFile* myCompSurf, const SurfaceFile* myRefSurf, MetricFile* distsOut, MetricFile* vectorsOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (!myCompSurf->hasNodeCorrespondence(*myRefSurf)) { throw AlgorithmException("input surfaces must have node correspondence"); } int numNodes = myCompSurf->getNumberOfNodes(); distsOut->setNumberOfNodesAndColumns(numNodes, 1); distsOut->setStructure(myCompSurf->getStructure()); distsOut->setMapName(0, "distance"); if (vectorsOut != NULL) { vectorsOut->setNumberOfNodesAndColumns(numNodes, 3); vectorsOut->setStructure(myCompSurf->getStructure()); vectorsOut->setMapName(0, "x displacement"); vectorsOut->setMapName(1, "y displacement"); vectorsOut->setMapName(2, "z displacement"); } for (int i = 0; i < numNodes; ++i) { Vector3D ref = myRefSurf->getCoordinate(i); Vector3D comp = myCompSurf->getCoordinate(i); Vector3D diff = comp - ref; distsOut->setValue(i, 0, diff.length()); if (vectorsOut != NULL) { vectorsOut->setValue(i, 0, diff[0]); vectorsOut->setValue(i, 1, diff[1]); vectorsOut->setValue(i, 2, diff[2]); } } } float AlgorithmSurfaceToSurface3dDistance::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmSurfaceToSurface3dDistance::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceToSurface3dDistance.h000066400000000000000000000034771360521144700276740ustar00rootroot00000000000000#ifndef __ALGORITHM_SURFACE_TO_SURFACE_3D_DISTANCE_H__ #define __ALGORITHM_SURFACE_TO_SURFACE_3D_DISTANCE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmSurfaceToSurface3dDistance : public AbstractAlgorithm { AlgorithmSurfaceToSurface3dDistance(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmSurfaceToSurface3dDistance(ProgressObject* myProgObj, const SurfaceFile* myCompSurf, const SurfaceFile* myRefSurf, MetricFile* distsOut, MetricFile* vectorsOut = NULL); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmSurfaceToSurface3dDistance; } #endif //__ALGORITHM_SURFACE_TO_SURFACE_3D_DISTANCE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceWedgeVolume.cxx000066400000000000000000000130471360521144700266670ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmSurfaceWedgeVolume.h" #include "AlgorithmException.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "Vector3D.h" #include using namespace caret; using namespace std; AString AlgorithmSurfaceWedgeVolume::getCommandSwitch() { return "-surface-wedge-volume"; } AString AlgorithmSurfaceWedgeVolume::getShortDescription() { return "MEASURE PER-VERTEX VOLUME BETWEEN SURFACES"; } OperationParameters* AlgorithmSurfaceWedgeVolume::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "inner-surface", "the inner surface"); ret->addSurfaceParameter(2, "outer-surface", "the outer surface"); ret->addMetricOutputParameter(3, "metric", "the output metric"); ret->setHelpText( AString("Compute the volume of each vertex's area from one surface to another. ") + "The surfaces must have vertex correspondence, and have consistent triangle orientation." ); return ret; } void AlgorithmSurfaceWedgeVolume::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { SurfaceFile* innerSurf = myParams->getSurface(1); SurfaceFile* outerSurf = myParams->getSurface(2); MetricFile* myMetricOut = myParams->getOutputMetric(3); AlgorithmSurfaceWedgeVolume(myProgObj, innerSurf, outerSurf, myMetricOut); } AlgorithmSurfaceWedgeVolume::AlgorithmSurfaceWedgeVolume(ProgressObject* myProgObj, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, MetricFile* myMetricOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int numNodes = innerSurf->getNumberOfNodes(); if (numNodes != outerSurf->getNumberOfNodes()) { throw AlgorithmException("input surfaces have different number of nodes"); } myMetricOut->setNumberOfNodesAndColumns(numNodes, 1); myMetricOut->setStructure(innerSurf->getStructure()); myMetricOut->setColumnName(0, "per-vertex volume between surfaces"); vector tempCol(numNodes, 0.0f); const float* innerCoords = innerSurf->getCoordinateData(); const float* outerCoords = outerSurf->getCoordinateData(); int numTiles = innerSurf->getNumberOfTriangles(); for (int i = 0; i < numTiles; ++i) { const int32_t* innerTile = innerSurf->getTriangle(i); Vector3D innerPoints[3], outerPoints[3]; for (int j = 0; j < 3; ++j) { innerPoints[j] = innerCoords + innerTile[j] * 3; outerPoints[j] = outerCoords + innerTile[j] * 3; } Vector3D refPoint = innerPoints[0];//use an "origin" for the vector field that is near the polyhedron for numerical stability - also, this makes several sides have zero contribution float volume = 0.0f;//I am ignoring the 1/3 in the vector field and the 1/2 for area of triangle for now, because they apply to everything so we can multiple later //NOTE: the inner surface triangle has zero contribution due to choice of reference point volume += (outerPoints[0] - refPoint).dot((outerPoints[1] - outerPoints[0]).cross(outerPoints[2] - outerPoints[1]));//we must be VERY careful with orientations int m = 2; for (int k = 0; k < 3; ++k)//walk the side quadrilaterals as 2->0, 0->1, 1->2 {//add the average of the two triangulations of the quadrilateral Vector3D mref = innerPoints[m] - refPoint, kref = innerPoints[k] - refPoint;//precalculate reference points on the white surface for use in both volumes Vector3D whiteEdge = innerPoints[k] - innerPoints[m];//precalculate this frequently used edge also if (k != 0 && m != 0) volume += 0.5f * mref.dot(whiteEdge.cross(outerPoints[k] - innerPoints[k]));//don't calculate them when their contribution is 0, due to containing the reference point if (m != 0) volume += 0.5f * mref.dot((outerPoints[m] - innerPoints[m]).cross(innerPoints[m] - outerPoints[k])); if (k != 0 && m != 0) volume += 0.5f * kref.dot(whiteEdge.cross(outerPoints[m] - innerPoints[k])); if (k != 0) volume += 0.5f * kref.dot((outerPoints[k] - innerPoints[k]).cross(outerPoints[m] - outerPoints[k])); m = k; } volume /= 18.0f;//1/3 for vector field, 1/2 for triangle, and 1/3 to split the tile volume among its 3 vertices for (int j = 0; j < 3; ++j) { tempCol[innerTile[j]] += volume; } } myMetricOut->setValuesForColumn(0, tempCol.data()); } float AlgorithmSurfaceWedgeVolume::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmSurfaceWedgeVolume::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmSurfaceWedgeVolume.h000066400000000000000000000033341360521144700263120ustar00rootroot00000000000000#ifndef __ALGORITHM_SURFACE_WEDGE_VOLUME_H__ #define __ALGORITHM_SURFACE_WEDGE_VOLUME_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmSurfaceWedgeVolume : public AbstractAlgorithm { AlgorithmSurfaceWedgeVolume(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmSurfaceWedgeVolume(ProgressObject* myProgObj, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, MetricFile* myMetricOut); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmSurfaceWedgeVolume; } #endif //__ALGORITHM_SURFACE_WEDGE_VOLUME_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmTemplate.cxx.txt000066400000000000000000000073651360521144700255320ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmName.h" #include "AlgorithmException.h" using namespace caret; using namespace std; AString AlgorithmName::getCommandSwitch() { return "-command-switch"; } AString AlgorithmName::getShortDescription() { return "SHORT DESCRIPTION"; } OperationParameters* AlgorithmName::getParameters() { OperationParameters* ret = new OperationParameters(); //ret->addSurfaceParameter(1, "surface", "the surface to compute on"); //ret->addMetricOutputParameter(2, "metric-out", "the output metric"); //OptionalParameter* columnOpt = ret->createOptionalParameter(3, "-column", "select a single column"); //columnOpt->addStringParameter(1, "column", "the column number or name"); ret->setHelpText( AString("This is where you set the help text. ") + "DO NOT add the info about what the command line format is, and do not give the command switch, " + "short description, or the short descriptions of parameters. " + "Do not indent, manually break long lines, or format the text in any way " + "other than to separate paragraphs within the help text prose, usually with two newlines." ); return ret; } void AlgorithmName::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { //SurfaceFile* mySurf = myParams->getSurface(1);//gets the surface with key 1 //MetricFile* myMetricOut = myParams->getOutputMetric(2);//gets the output metric with key 2 /*OptionalParameter* columnOpt = myParams->getOptionalParameter(3);//gets option with key 3 int column = -1; if (columnOpt->m_present) {//set up to use a single column column = myMetric->getMapIndexFromNameOrNumber(columnOpt->getString(1)); if (column < 0) throw AlgorithmException("invalid column specified"); }//*/ AlgorithmName(myProgObj /*INSERT PARAMETERS HERE*/);//executes the algorithm } AlgorithmName::AlgorithmName(ProgressObject* myProgObj /*INSERT PARAMETERS HERE*/) : AbstractAlgorithm(myProgObj) { /*ProgressObject* subAlgProgress1 = NULL;//uncomment these if you use another algorithm inside here if (myProgObj != NULL) { subAlgProgress1 = myProgObj->addAlgorithm(AlgorithmInsertNameHere::getAlgorithmWeight()); }//*/ LevelProgress myProgress(myProgObj);//this line sets the algorithm up to use the progress object, and will finish the progress object automatically when the algorithm terminates //myProgress.reportProgress(0.5f);//this is how you say you are halfway done with the INTERNAL work of the algorithm //will report finished automatically when this function ends (myProgress goes out of scope, destructor triggers finish) } float AlgorithmName::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmName::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmTemplate.h.txt000066400000000000000000000054661360521144700251570ustar00rootroot00000000000000#ifndef __ALGORITHM_NAME_H__ #define __ALGORITHM_NAME_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /* INSTRUCTIONS: file->save as... and enter what you will name the class, plus .h find and replace these strings in plain text mode (not "whole word only"): AlgorithmName : algorithm name, in CamelCase, with initial capital, same as what you saved the header file to ALGORITHM_NAME : uppercase of algorithm name, with underscore between words, used in #ifdef guards next, make AlgorithmName.cxx from AlgorithmTemplate.cxx.txt via one of the following (depending on working directory): cat AlgorithmTemplate.cxx.txt | sed 's/[A]lgorithmName/AlgorithmName/g' > AlgorithmName.cxx cat Algorithms/AlgorithmTemplate.cxx.txt | sed 's/[A]lgorithmName/AlgorithmName/g' > Algorithms/AlgorithmName.cxx cat src/Algorithms/AlgorithmTemplate.cxx.txt | sed 's/[A]lgorithmName/AlgorithmName/g' > src/Algorithms/AlgorithmName.cxx or manually copy and replace next, implement its functions - the algorithm work goes in the CONSTRUCTOR add these into Algorithms/CMakeLists.txt: AlgorithmName.h AlgorithmName.cxx place the following lines into Commands/CommandOperationManager.cxx: #include "AlgorithmName.h" //near the top this->commandOperations.push_back(new CommandParser(new AutoAlgorithmName())); //in CommandOperationManager() finally, remove this block comment */ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmName : public AbstractAlgorithm { AlgorithmName(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmName(ProgressObject* myProgObj /*INSERT PARAMETERS HERE//*/); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmName; } #endif //__ALGORITHM_NAME_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeAffineResample.cxx000066400000000000000000000171701360521144700272050ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeAffineResample.h" #include "AffineFile.h" #include "AlgorithmException.h" #include "CaretLogger.h" #include "CaretOMP.h" #include "NiftiIO.h" #include "Vector3D.h" using namespace caret; using namespace std; AString AlgorithmVolumeAffineResample::getCommandSwitch() { return "-volume-affine-resample"; } AString AlgorithmVolumeAffineResample::getShortDescription() { return "RESAMPLE VOLUME USING AFFINE TRANSFORM"; } OperationParameters* AlgorithmVolumeAffineResample::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume-in", "volume to resample"); ret->addStringParameter(2, "affine", "the affine file to apply"); ret->addStringParameter(3, "volume-space", "a volume file in the volume space you want for the output"); ret->addStringParameter(4, "method", "the resampling method"); ret->addVolumeOutputParameter(5, "volume-out", "the output volume"); OptionalParameter* flirtOpt = ret->createOptionalParameter(6, "-flirt", "MUST be used if affine is a flirt affine"); flirtOpt->addStringParameter(1, "source-volume", "the source volume used when generating the affine"); flirtOpt->addStringParameter(2, "target-volume", "the target volume used when generating the affine"); ret->setHelpText( AString("Resample a volume file with an affine transformation. ") + "The recommended methods are CUBIC (cubic spline) for most data, and ENCLOSING_VOXEL for label data. " "The parameter must be one of:\n\n" + "CUBIC\nENCLOSING_VOXEL\nTRILINEAR" ); return ret; } void AlgorithmVolumeAffineResample::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* inVol = myParams->getVolume(1); AString affName = myParams->getString(2); AString refSpaceName = myParams->getString(3); AString method = myParams->getString(4); VolumeFile* outVol = myParams->getOutputVolume(5); OptionalParameter* flirtOpt = myParams->getOptionalParameter(6); AffineFile myAffine; if (flirtOpt->m_present) { myAffine.readFlirt(affName, flirtOpt->getString(1), flirtOpt->getString(2)); } else { myAffine.readWorld(affName); } VolumeFile::InterpType myMethod = VolumeFile::CUBIC; if (method == "CUBIC") { myMethod = VolumeFile::CUBIC; } else if (method == "TRILINEAR") { myMethod = VolumeFile::TRILINEAR; } else if (method == "ENCLOSING_VOXEL") { myMethod = VolumeFile::ENCLOSING_VOXEL; } else { throw AlgorithmException("unrecognized interpolation method"); } FloatMatrix affMat = FloatMatrix(myAffine.getMatrix()); NiftiIO refSpaceIO; refSpaceIO.openRead(refSpaceName); vector refDims = refSpaceIO.getDimensions(); if (refDims.size() < 3) refDims.resize(3, 1); AlgorithmVolumeAffineResample(myProgObj, inVol, affMat, refDims.data(), refSpaceIO.getHeader().getSForm(), myMethod, outVol); } AlgorithmVolumeAffineResample::AlgorithmVolumeAffineResample(ProgressObject* myProgObj, const VolumeFile* inVol, const FloatMatrix& myAffine, const int64_t refDims[3], const vector >& refSform, const VolumeFile::InterpType& myMethod, VolumeFile* outVol) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int64_t affRows, affColumns; myAffine.getDimensions(affRows, affColumns); if (affRows < 3 || affRows > 4 || affColumns != 4) throw AlgorithmException("input matrix is not an affine matrix"); vector outDims = inVol->getOriginalDimensions(); if (outDims.size() < 3) throw AlgorithmException("input must have 3 spatial dimensions"); outDims[0] = refDims[0]; outDims[1] = refDims[1]; outDims[2] = refDims[2]; int64_t numMaps = inVol->getNumberOfMaps(), numComponents = inVol->getNumberOfComponents(); outVol->reinitialize(outDims, refSform, numComponents, inVol->getType(), inVol->m_header); FloatMatrix targetToSource = myAffine; targetToSource.resize(4, 4); targetToSource[3][0] = 0.0f; targetToSource[3][1] = 0.0f; targetToSource[3][2] = 0.0f; targetToSource[3][3] = 1.0f; targetToSource = targetToSource.inverse(); Vector3D xvec, yvec, zvec, offset; xvec[0] = targetToSource[0][0]; xvec[1] = targetToSource[1][0]; xvec[2] = targetToSource[2][0]; yvec[0] = targetToSource[0][1]; yvec[1] = targetToSource[1][1]; yvec[2] = targetToSource[2][1]; zvec[0] = targetToSource[0][2]; zvec[1] = targetToSource[1][2]; zvec[2] = targetToSource[2][2]; offset[0] = targetToSource[0][3]; offset[1] = targetToSource[1][3]; offset[2] = targetToSource[2][3]; vector scratchFrame(outDims[0] * outDims[1] * outDims[2], 0.0f); if (inVol->isMappedWithLabelTable()) { if (myMethod != VolumeFile::ENCLOSING_VOXEL) { CaretLogWarning("using interpolation type other than ENCLOSING_VOXEL on a label volume"); } for (int64_t i = 0; i < numMaps; ++i) { *(outVol->getMapLabelTable(i)) = *(inVol->getMapLabelTable(i)); } } for (int64_t i = 0; i < numMaps; ++i) { outVol->setMapName(i, inVol->getMapName(i)); } for (int64_t c = 0; c < numComponents; ++c) { for (int64_t b = 0; b < numMaps; ++b) { if (myMethod == VolumeFile::CUBIC) { inVol->validateSpline(b, c);//because deconvolve is parallel, but won't execute parallel if we are already in a parallel section } #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t k = 0; k < outDims[2]; ++k) { for (int64_t j = 0; j < outDims[1]; ++j) { for (int64_t i = 0; i < outDims[0]; ++i) { Vector3D outCoord, inCoord; outVol->indexToSpace(i, j, k, outCoord); inCoord = xvec * outCoord[0] + yvec * outCoord[1] + zvec * outCoord[2] + offset; float interpVal = inVol->interpolateValue(inCoord, myMethod, NULL, b, c); scratchFrame[outVol->getIndex(i, j, k)] = interpVal; } } } outVol->setFrame(scratchFrame.data(), b, c); if (myMethod == VolumeFile::CUBIC) { inVol->freeSpline(b, c);//release memory we no longer need, if we allocated it } } } } float AlgorithmVolumeAffineResample::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeAffineResample::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeAffineResample.h000066400000000000000000000036541360521144700266340ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_AFFINE_RESAMPLE_H__ #define __ALGORITHM_VOLUME_AFFINE_RESAMPLE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "FloatMatrix.h" #include "VolumeFile.h" namespace caret { class AlgorithmVolumeAffineResample : public AbstractAlgorithm { AlgorithmVolumeAffineResample(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeAffineResample(ProgressObject* myProgObj, const VolumeFile* inVol, const FloatMatrix& myAffine, const int64_t refDims[3], const std::vector >& refSform, const VolumeFile::InterpType& myMethod, VolumeFile* outVol); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeAffineResample; } #endif //__ALGORITHM_VOLUME_AFFINE_RESAMPLE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeAllLabelsToROIs.cxx000066400000000000000000000115601360521144700272140ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeAllLabelsToROIs.h" #include "AlgorithmException.h" #include "GiftiLabelTable.h" #include "VolumeFile.h" #include #include #include using namespace caret; using namespace std; AString AlgorithmVolumeAllLabelsToROIs::getCommandSwitch() { return "-volume-all-labels-to-rois"; } AString AlgorithmVolumeAllLabelsToROIs::getShortDescription() { return "MAKE ROIS FROM ALL LABELS IN A VOLUME FRAME"; } OperationParameters* AlgorithmVolumeAllLabelsToROIs::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "label-in", "the input volume label file"); ret->addStringParameter(2, "map", "the number or name of the label map to use"); ret->addVolumeOutputParameter(3, "volume-out", "the output volume file"); ret->setHelpText( AString("The output volume has a frame for each label in the specified input frame, other than the ??? label, ") + "each of which contains an ROI of all voxels that are set to the corresponding label." ); return ret; } void AlgorithmVolumeAllLabelsToROIs::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* myLabel = myParams->getVolume(1); AString mapID = myParams->getString(2); int whichMap = myLabel->getMapIndexFromNameOrNumber(mapID); if (whichMap == -1) { throw AlgorithmException("invalid map number or name specified"); } VolumeFile* myVolOut = myParams->getOutputVolume(3); AlgorithmVolumeAllLabelsToROIs(myProgObj, myLabel, whichMap, myVolOut); } AlgorithmVolumeAllLabelsToROIs::AlgorithmVolumeAllLabelsToROIs(ProgressObject* myProgObj, const VolumeFile* myLabel, const int& whichMap, VolumeFile* myVolOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (myLabel->getType() != SubvolumeAttributes::LABEL) { throw AlgorithmException("input volume must be a label volume"); } if (whichMap < 0 || whichMap >= myLabel->getNumberOfMaps()) { throw AlgorithmException("invalid map index specified"); } const GiftiLabelTable* myTable = myLabel->getMapLabelTable(whichMap); int32_t unusedKey = myTable->getUnassignedLabelKey();//WARNING: this actually MODIFIES the label table if the ??? key doesn't exist set myKeys = myTable->getKeys(); int numKeys = (int)myKeys.size(); if (numKeys < 2) { throw AlgorithmException("label table doesn't contain any keys besides the ??? key"); } map keyToMap;//lookup from keys to subvolume vector outDims = myLabel->getOriginalDimensions(); outDims.resize(4); outDims[3] = numKeys - 1;//don't include the ??? key myVolOut->reinitialize(outDims, myLabel->getSform()); myVolOut->setValueAllVoxels(0.0f); int counter = 0; for (set::iterator iter = myKeys.begin(); iter != myKeys.end(); ++iter) { if (*iter == unusedKey) continue;//skip the ??? key keyToMap[*iter] = counter; myVolOut->setMapName(counter, myTable->getLabelName(*iter)); ++counter; } for (int64_t k = 0; k < outDims[2]; ++k)//because we need to set voxels in the output, rather than in a temporary frame, for single pass without duplicating the memory { for (int64_t j = 0; j < outDims[1]; ++j) { for (int64_t i = 0; i < outDims[0]; ++i) { int32_t thisKey = (int32_t)floor(myLabel->getValue(i, j, k, whichMap) + 0.5f); map::iterator iter = keyToMap.find(thisKey); if (iter != keyToMap.end()) { myVolOut->setValue(1.0f, i, j, k, iter->second); } } } } } float AlgorithmVolumeAllLabelsToROIs::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeAllLabelsToROIs::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeAllLabelsToROIs.h000066400000000000000000000033531360521144700266420ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_ALL_LABELS_TO_ROIS_H__ #define __ALGORITHM_VOLUME_ALL_LABELS_TO_ROIS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmVolumeAllLabelsToROIs : public AbstractAlgorithm { AlgorithmVolumeAllLabelsToROIs(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeAllLabelsToROIs(ProgressObject* myProgObj, const VolumeFile* myLabel, const int& whichMap, VolumeFile* myVolOut); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeAllLabelsToROIs; } #endif //__ALGORITHM_VOLUME_ALL_LABELS_TO_ROIS_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeDilate.cxx000066400000000000000000000601621360521144700255250ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeDilate.h" #include "AlgorithmException.h" #include "CaretHeap.h" #include "CaretLogger.h" #include "CaretOMP.h" #include "CaretPointLocator.h" #include "FloatMatrix.h" #include "Vector3D.h" #include "VolumeFile.h" #include "VoxelIJK.h" #include #include #include using namespace caret; using namespace std; AString AlgorithmVolumeDilate::getCommandSwitch() { return "-volume-dilate"; } AString AlgorithmVolumeDilate::getShortDescription() { return "DILATE A VOLUME FILE"; } OperationParameters* AlgorithmVolumeDilate::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume", "the volume to dilate"); ret->addDoubleParameter(2, "distance", "distance in mm to dilate"); ret->addStringParameter(3, "method", "dilation method to use"); ret->addVolumeOutputParameter(4, "volume-out", "the output volume"); OptionalParameter* exponentOpt = ret->createOptionalParameter(8, "-exponent", "use a different exponent in the weighting function"); exponentOpt->addDoubleParameter(1, "exponent", "exponent 'n' to use in (1 / (distance ^ n)) as the weighting function (default 7)"); OptionalParameter* badRoiOpt = ret->createOptionalParameter(5, "-bad-voxel-roi", "specify an roi of voxels to overwrite, rather than voxels with value zero"); badRoiOpt->addVolumeParameter(1, "roi-volume", "volume file, positive values denote voxels to have their values replaced"); OptionalParameter* dataRoiOpt = ret->createOptionalParameter(7, "-data-roi", "specify an roi of where there is data"); dataRoiOpt->addVolumeParameter(1, "roi-volume", "volume file, positive values denote voxels that have data"); OptionalParameter* subvolSelect = ret->createOptionalParameter(6, "-subvolume", "select a single subvolume to dilate"); subvolSelect->addStringParameter(1, "subvol", "the subvolume number or name"); ret->createOptionalParameter(9, "-legacy-cutoff", "use the old method of excluding voxels further than the dilation distance when calculating the dilated value"); ret->setHelpText( AString("For all voxels that are designated as bad, if they neighbor a non-bad voxel with data or are within the specified distance of such a voxel, ") + "replace the value in the bad voxel with a value calculated from nearby non-bad voxels that have data, otherwise set the value to zero. " + "No matter how small is, dilation will always use at least the face neighbor voxels.\n\n" + "By default, voxels that have data with the value 0 are bad, specify -bad-voxel-roi to only count voxels as bad if they are selected by the roi. " + "If -data-roi is not specified, all voxels are assumed to have data.\n\n" + "To get the behavior of version 1.3.2 or earlier, use '-legacy-cutoff -exponent 2'.\n\n" + "Valid values for are:\n\n" + "NEAREST - use the value from the nearest good voxel\n" + "WEIGHTED - use a weighted average based on distance" ); return ret; } void AlgorithmVolumeDilate::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* volIn = myParams->getVolume(1); float distance = (float)myParams->getDouble(2); AString methodName = myParams->getString(3); Method myMethod = NEAREST; if (methodName == "NEAREST") { myMethod = NEAREST; } else if (methodName == "WEIGHTED") { myMethod = WEIGHTED; } else { throw AlgorithmException("invalid method specified, use NEAREST or WEIGHTED"); } VolumeFile* volOut = myParams->getOutputVolume(4); OptionalParameter* exponentOpt = myParams->getOptionalParameter(8); float exponent = 7.0f; if (exponentOpt->m_present) { exponent = (float)exponentOpt->getDouble(1); } OptionalParameter* badRoiOpt = myParams->getOptionalParameter(5); VolumeFile* badRoi = NULL; if (badRoiOpt->m_present) { badRoi = badRoiOpt->getVolume(1); } OptionalParameter* dataRoiOpt = myParams->getOptionalParameter(7); VolumeFile* dataRoi = NULL; if (dataRoiOpt->m_present) { dataRoi = dataRoiOpt->getVolume(1); } OptionalParameter* subvolSelect = myParams->getOptionalParameter(6); int subvol = -1; if (subvolSelect->m_present) { subvol = volIn->getMapIndexFromNameOrNumber(subvolSelect->getString(1)); if (subvol < 0) throw AlgorithmException("invalid subvolume specified"); } bool legacyCutoff = myParams->getOptionalParameter(9)->m_present; AlgorithmVolumeDilate(myProgObj, volIn, distance, myMethod, volOut, badRoi, dataRoi, subvol, exponent, legacyCutoff); } namespace { inline bool badVoxel(const bool labelMode, const int32_t unlabeledKey, const int64_t i, const int64_t j, const int64_t k, const VolumeFile* volIn, const int& insubvol, const int& component, const VolumeFile* badRoi, const VolumeFile* dataRoi) { if (badRoi == NULL) { if (labelMode) { return (dataRoi == NULL || dataRoi->getValue(i, j, k) > 0.0f) && floor(0.5f + volIn->getValue(i, j, k, insubvol, component)) == unlabeledKey;//without bad roi, bad is implicitly "data and not 0/unlabeled" } else { return (dataRoi == NULL || dataRoi->getValue(i, j, k) > 0.0f) && volIn->getValue(i, j, k, insubvol, component) == 0.0f; } } else { return badRoi->getValue(i, j, k) > 0.0f; } } inline bool dataVoxel(const int64_t i, const int64_t j, const int64_t k, const VolumeFile* dataRoi) { return dataRoi == NULL || dataRoi->getValue(i, j, k) > 0.0f; } void dilateFrame(const bool labelMode, const VolumeFile* volIn, const int& insubvol, const int& component, VolumeFile* volOut, const int& outsubvol, const VolumeFile* badRoi, const VolumeFile* dataRoi, const float& distance, const AlgorithmVolumeDilate::Method& myMethod, const float& exponent, const bool& legacyCutoff) {//copy data that is outside the dataROI, replace values where badROI is > 0 (with zero if nothing else), if no badROI, pretend badROI is (data == 0 && dataROI > 0) int neighbors[18] = {0, 0, -1, 0, -1, 0, -1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1};//special behavior: when distance is 0, it still dilates by 1 voxel Vector3D voxStep[3], origin; const VolumeSpace& myVolSpace = volIn->getVolumeSpace(); myVolSpace.getSpacingVectors(voxStep[0], voxStep[1], voxStep[2], origin); //if the distance is within 1% of excluding a neighbor, we need to additionally check the neighbors bool checkNeighbors = distance <= voxStep[0].length() * 1.01f || distance <= voxStep[1].length() * 1.01f || distance <= voxStep[2].length() * 1.01f; //the single-voxel rule means we can't just base the maximum search distance on the dilation distance float cutoffBase = max(2.0f * distance, 2.0f * min(min(voxStep[0].length(), voxStep[1].length()), voxStep[2].length())); float minKernel = 1.5f * min(min(voxStep[0].length(), voxStep[1].length()), voxStep[2].length());//small kernels are cheap, so use a minimum of face+edge neighbors in isotropic volumes in weighted mode vector myDims = volIn->getDimensions(); //HACK: unlabeledKey is also used to fill bad voxels that the dilation doesn't reach in non-label mode int32_t unlabeledKey = 0; if (labelMode) unlabeledKey = volIn->getMapLabelTable(insubvol)->getUnassignedLabelKey(); vector validPoints; vector validIndices, toReplace; vector scratchFrame(myDims[0] * myDims[1] * myDims[2]);//uninitialized, we will copy every voxel we don't replace for (int64_t k = 0; k < myDims[2]; ++k) { for (int64_t j = 0; j < myDims[1]; ++j) { for (int64_t i = 0; i < myDims[0]; ++i) { if (badVoxel(labelMode, unlabeledKey, i, j, k, volIn, insubvol, component, badRoi, dataRoi)) { toReplace.push_back(VoxelIJK(i, j, k)); } else {//copy it, and if it is data, add to usable set if (labelMode) { scratchFrame[myVolSpace.getIndex(i, j, k)] = floor(0.5f + volIn->getValue(i, j, k, insubvol, component)); } else { scratchFrame[myVolSpace.getIndex(i, j, k)] = volIn->getValue(i, j, k, insubvol, component); } if (dataVoxel(i, j, k, dataRoi)) { VoxelIJK tempVoxel(i, j, k); Vector3D tempCoord = myVolSpace.indexToSpace(tempVoxel); validPoints.push_back(tempCoord[0]); validPoints.push_back(tempCoord[1]); validPoints.push_back(tempCoord[2]); validIndices.push_back(tempVoxel); } } } } } if (!toReplace.empty()) { CaretPointLocator locator(validPoints); #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t whichVoxel = 0; whichVoxel < (int64_t)toReplace.size(); ++whichVoxel) { const VoxelIJK& iter = toReplace[whichVoxel]; int64_t i = iter.m_ijk[0], j = iter.m_ijk[1], k = iter.m_ijk[2]; Vector3D voxcoord = myVolSpace.indexToSpace(i, j, k); switch (myMethod) { case AlgorithmVolumeDilate::NEAREST: { int64_t index = locator.closestPointLimited(voxcoord, distance); float bestVal = unlabeledKey;//HACK: unlabeledKey is 0 when we aren't in label mode, so can double as default value for bad voxel beyond dilate range if (index < 0) { float bestDist = -1.0f; if (checkNeighbors) { for (int n = 0; n < 6; ++n) { int neighbase = n * 3; int64_t neighVox[3] = {i + neighbors[neighbase], j + neighbors[neighbase + 1], k + neighbors[neighbase + 2]}; if (myVolSpace.indexValid(neighVox) && ! badVoxel(labelMode, unlabeledKey, neighVox[0], neighVox[1], neighVox[2], volIn, insubvol, component, badRoi, dataRoi)) { float tempdist = (myVolSpace.indexToSpace(neighbors + neighbase) - myVolSpace.indexToSpace(0, 0, 0)).length();//slightly hacky, but won't have inconsistencies from different rounding per bad voxel if (tempdist < bestDist || bestDist == -1.0f) { bestDist = tempdist; bestVal = volIn->getValue(neighVox, insubvol, component); } } } } } else { bestVal = volIn->getValue(validIndices[index], insubvol, component); } if (labelMode) { bestVal = floor(0.5f + bestVal); } scratchFrame[myVolSpace.getIndex(i, j, k)] = bestVal; break; } case AlgorithmVolumeDilate::WEIGHTED: { vector inRange; if (legacyCutoff) { inRange = locator.pointsInRange(voxcoord, distance);//immediate neighbor special case is handled below } else { float closeDist = -1.0f; LocatorInfo myInfo; int64_t index = locator.closestPointLimited(voxcoord, distance, &myInfo);//only need the distance bool found = false; if (index >= 0) { found = true; closeDist = (myInfo.coords - voxcoord).length(); } else { if (checkNeighbors) {//always dilate to neighbor voxels, regardless for (int n = 0; n < 6; ++n) { int neighbase = n * 3; int64_t neighVox[3] = {i + neighbors[neighbase], j + neighbors[neighbase + 1], k + neighbors[neighbase + 2]}; if (myVolSpace.indexValid(neighVox) && ! badVoxel(labelMode, unlabeledKey, neighVox[0], neighVox[1], neighVox[2], volIn, insubvol, component, badRoi, dataRoi)) { float tempdist = (myVolSpace.indexToSpace(neighbors + neighbase) - myVolSpace.indexToSpace(0, 0, 0)).length();//slightly hacky, but won't have inconsistencies from different rounding per voxel if (tempdist < closeDist || !found) { found = true; closeDist = tempdist; } } } } } if (found) { //find what cutoff corresponds to 98% of the total weight being found compared to an infinite kernel //to do this, assume a non-adversarial situation, where farther parts have at most equal angular area to closer ones //49 = 98/(100-98) float cutoffRatio = max(1.1f, pow(49.0f, 1.0f / (exponent - 3.0f))), cutoffDist = cutoffBase;//find what cutoff ratio corresponds to a hudredth of weight if (exponent > 3.0f && cutoffRatio < 100.0f && cutoffRatio > 1.0f)//if the ratio is sane, use it, but never exceed cutoffBase { cutoffDist = max(min(cutoffRatio * closeDist, cutoffDist), minKernel);//but small kernels are rather cheap anyway, so have a minimum size just in case } inRange = locator.pointsInRange(voxcoord, cutoffDist); } } map labelSums; double sum = 0.0, weightsum = 0.0; if (legacyCutoff && checkNeighbors) {//add valid neighbors only if they aren't already in the list, and the non-legacy mode is already handled above... set voxelsToUse;//but looking up the neighbors' indices in validIndices is work we don't need to do, so copy the list and add to it for (auto thisInfo : inRange) { voxelsToUse.insert(validIndices[thisInfo.index]); } for (int n = 0; n < 6; ++n) { int neighbase = n * 3; int64_t neighVox[3] = {i + neighbors[neighbase], j + neighbors[neighbase + 1], k + neighbors[neighbase + 2]}; if (myVolSpace.indexValid(neighVox) && ! badVoxel(labelMode, unlabeledKey, neighVox[0], neighVox[1], neighVox[2], volIn, insubvol, component, badRoi, dataRoi)) { voxelsToUse.insert(neighVox);//set eliminates duplicates } } for (auto thisVoxel : voxelsToUse)//unfortunately, this means we need to write a copy of the loop for the common case not to do unneeded work { float thisdist = (myVolSpace.indexToSpace(thisVoxel) - voxcoord).length(); float weight = 1.0f / pow(thisdist, exponent); if (labelMode) { int32_t thisKey = int32_t(floor(0.5f + volIn->getValue(thisVoxel, insubvol, component))); map::iterator iter = labelSums.find(thisKey); if (iter == labelSums.end()) { labelSums[thisKey] = weight; } else { iter->second += weight; } } else { sum += weight * volIn->getValue(thisVoxel, insubvol, component); weightsum += weight; } } } else { for (auto thisInfo : inRange) { float thisdist = (thisInfo.coords - voxcoord).length(); float weight = 1.0f / pow(thisdist, exponent); if (labelMode) { int32_t thisKey = int32_t(floor(0.5f + volIn->getValue(validIndices[thisInfo.index], insubvol, component))); map::iterator iter = labelSums.find(thisKey); if (iter == labelSums.end()) { labelSums[thisKey] = weight; } else { iter->second += weight; } } else { sum += weight * volIn->getValue(validIndices[thisInfo.index], insubvol, component); weightsum += weight; } } } if (labelMode) { float bestWeight = -1.0f;//all weights should be positive, so their sums should too int32_t bestKey = unlabeledKey; for (auto iter : labelSums) { if (iter.second > bestWeight) { bestWeight = iter.second; bestKey = iter.first; } } scratchFrame[myVolSpace.getIndex(i, j, k)] = bestKey; } else { if (weightsum > 0.0) { scratchFrame[myVolSpace.getIndex(i, j, k)] = sum / weightsum; } else { scratchFrame[myVolSpace.getIndex(i, j, k)] = 0.0f; } } break; } } } } volOut->setFrame(scratchFrame.data(), outsubvol, component); } } AlgorithmVolumeDilate::AlgorithmVolumeDilate(ProgressObject* myProgObj, const VolumeFile* volIn, const float& distance, const Method& myMethod, VolumeFile* volOut, const VolumeFile* badRoi, const VolumeFile* dataRoi, const int& subvol, const float& exponent, const bool legacyCutoff) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); vector myDims; volIn->getDimensions(myDims); if (subvol < -1 || subvol >= myDims[3]) { throw AlgorithmException("invalid subvolume specified"); } if (distance < 0.0f) { throw AlgorithmException("distance cannot be negative"); } if (badRoi != NULL && !volIn->matchesVolumeSpace(badRoi)) { throw AlgorithmException("bad voxel roi volume space does not match input volume"); } if (dataRoi != NULL && !volIn->matchesVolumeSpace(dataRoi)) { throw AlgorithmException("data roi volume space does not match input volume"); } bool isLabelData = false; if (volIn->getType() == SubvolumeAttributes::LABEL) { isLabelData = true; } if (subvol == -1) { volOut->reinitialize(volIn->getOriginalDimensions(), volIn->getSform(), volIn->getNumberOfComponents(), volIn->getType(), volIn->m_header); for (int i = 0; i < myDims[3]; ++i) { if (volIn->getType() == SubvolumeAttributes::LABEL) { *(volOut->getMapLabelTable(i)) = *(volIn->getMapLabelTable(i)); } else { *(volOut->getMapPaletteColorMapping(i)) = *(volIn->getMapPaletteColorMapping(i)); } volOut->setMapName(i, volIn->getMapName(i) + " dilate " + AString::number(distance)); } } else { vector outDims = myDims; outDims.resize(3); volOut->reinitialize(outDims, volIn->getSform(), volIn->getNumberOfComponents(), volIn->getType(), volIn->m_header); if (volIn->getType() == SubvolumeAttributes::LABEL) { *(volOut->getMapLabelTable(0)) = *(volIn->getMapLabelTable(subvol)); } else { *(volOut->getMapPaletteColorMapping(0)) = *(volIn->getMapPaletteColorMapping(subvol)); } volOut->setMapName(0, volIn->getMapName(subvol) + " dilate " + AString::number(distance)); } if (subvol == -1) { for (int s = 0; s < myDims[3]; ++s) { for (int c = 0; c < myDims[4]; ++c) { dilateFrame(isLabelData, volIn, s, c, volOut, s, badRoi, dataRoi, distance, myMethod, exponent, legacyCutoff); } } } else { for (int c = 0; c < myDims[4]; ++c) { dilateFrame(isLabelData, volIn, subvol, c, volOut, 0, badRoi, dataRoi, distance, myMethod, exponent, legacyCutoff); } } } float AlgorithmVolumeDilate::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeDilate::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeDilate.h000066400000000000000000000036731360521144700251560ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_DILATE_H__ #define __ALGORITHM_VOLUME_DILATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmVolumeDilate : public AbstractAlgorithm { AlgorithmVolumeDilate(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: enum Method { NEAREST, WEIGHTED }; AlgorithmVolumeDilate(ProgressObject* myProgObj, const VolumeFile* volIn, const float& distance, const Method& myMethod, VolumeFile* volOut, const VolumeFile* badRoi = NULL, const VolumeFile* dataRoi = NULL, const int& subvol = -1, const float& exponent = 7.0f, const bool legacyCutoff = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeDilate; } #endif //__ALGORITHM_VOLUME_DILATE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeDistortion.cxx000066400000000000000000000237541360521144700264670ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeDistortion.h" #include "AlgorithmException.h" #include "AlgorithmVolumeGradient.h" #include "CaretOMP.h" #include "FloatMatrix.h" #include "VolumeFile.h" #include "WarpfieldFile.h" #include #include using namespace caret; using namespace std; AString AlgorithmVolumeDistortion::getCommandSwitch() { return "-volume-distortion"; } AString AlgorithmVolumeDistortion::getShortDescription() { return "CALCULATE VOLUME WARPFIELD DISTORTION"; } OperationParameters* AlgorithmVolumeDistortion::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "warpfield", "the warpfield to compute the distortion of"); ret->addVolumeOutputParameter(2, "volume-out", "the output distortion measures"); OptionalParameter* fnirtOpt = ret->createOptionalParameter(3, "-fnirt", "MUST be used if using a fnirt warpfield"); fnirtOpt->addStringParameter(1, "source-volume", "the source volume used when generating the warpfield"); ret->createOptionalParameter(4, "-circular", "use the circle-based formula for the anisotropic measure"); ret->createOptionalParameter(5, "-log2", "apply base-2 log transform"); ret->setHelpText( AString("Calculates isotropic and anisotropic distortions in the volume warpfield. ") + "At each voxel, the gradient of the absolute warpfield is computed to obtain the local affine transforms for each voxel (jacobian matrices), and strain tensors are derived from them. " + "The isotropic component (volumetric expansion ratio) is the product of the three principal strains. " + "The default measure ('elongation') for the anisotropic component is the largest principal strain divided by the smallest.\n\n" + "The -circular option instead calculates the anisotropic component by transforming the principal strains into log space, " + "considering them as x-values of points on a circle 120 degrees apart, finds the circle's diameter, and transforms that back to a ratio." ); return ret; } void AlgorithmVolumeDistortion::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { AString warpName = myParams->getString(1); VolumeFile* distortionOut = myParams->getOutputVolume(2); OptionalParameter* fnirtOpt = myParams->getOptionalParameter(3); Method myMethod = ELONGATION; if (myParams->getOptionalParameter(4)->m_present) myMethod = CIRCULAR; bool dolog2 = myParams->getOptionalParameter(5)->m_present; WarpfieldFile myWarp; if (fnirtOpt->m_present) { myWarp.readFnirt(warpName, fnirtOpt->getString(1)); } else { myWarp.readWorld(warpName); } AlgorithmVolumeDistortion(myProgObj, myWarp, distortionOut, myMethod, dolog2); } AlgorithmVolumeDistortion::AlgorithmVolumeDistortion(ProgressObject* myProgObj, const WarpfieldFile& myWarp, VolumeFile* distortionOut, const Method myMethod, const bool dolog2) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); switch (myMethod) { case ELONGATION: case CIRCULAR: break; default: throw AlgorithmException("invalid method value passed to AlgorithmVolumeDistortion"); } CaretPointer absWarp = myWarp.generateAbsolute(); VolumeFile gradMag, gradVec;//don't need gradMag, but it is a mandatory argument to algorithm AlgorithmVolumeGradient(NULL, absWarp, &gradMag, -1, NULL, &gradVec);//vector order is dx'/dx, dx'/dy, dx'/dz, dy'/dx, etc - these are the local affines, we don't need the translation vector dims = gradVec.getDimensions(); CaretAssert(dims[3] == 9);//make sure it has the expected components for a 3D tranform dims.resize(4);//drop components so we can use it to initialize output dims[3] = 2;//set it to 2 maps distortionOut->reinitialize(dims, absWarp->getSform()); distortionOut->setMapName(0, "isotropic (expansion)"); switch (myMethod) { case ELONGATION: distortionOut->setMapName(1, "anisotropic (elongation)"); break; case CIRCULAR: distortionOut->setMapName(1, "anisotropic (circular)"); break; } #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t k = 0; k < dims[2]; ++k) { for (int64_t j = 0; j < dims[1]; ++j) { for (int64_t i = 0; i < dims[0]; ++i) { FloatMatrix localAff(3, 3); for (int dim1 = 0; dim1 < 3; ++dim1) { for (int dim2 = 0; dim2 < 3; ++dim2) { localAff[dim1][dim2] = gradVec.getValue(i, j, k, dim1 * 3 + dim2); } } FloatMatrix squaredtensor = localAff * localAff.transpose();//this cancels the inner rotations, aligning the principal strains resulting in squaring them, allowing us to use tensor simplifications float isotropic = sqrt(squaredtensor.determinant());//square root of i3 for squared tensor float i1 = (squaredtensor[0][0] + squaredtensor[1][1] + squaredtensor[2][2]);//sum of squares of principal strains float i2 = squaredtensor[0][0] * squaredtensor[1][1] + squaredtensor[0][0] * squaredtensor[2][2] + squaredtensor[1][1] * squaredtensor[2][2] - squaredtensor[0][1] * squaredtensor[0][1] - squaredtensor[0][2] * squaredtensor[0][2] - squaredtensor[1][2] * squaredtensor[1][2]; float q = (3 * i2 - i1 * i1) / 9.0f;//now we need to solve the cubic for the three principal strains, so we can make whatever formula we want if (q > 0) { q = 0.0f;//just in case, avoid pow/sqrt giving NaN for tiny positive q, we should always have 3 solutions } float r = (i1 * (2 * i1 * i1 - 9 * i2) + 27 * isotropic * isotropic) / 54.0f;//remember, the tensor is squared const float PI = 3.141592654f;//trivially avoid the _USE_MATH_DEFINES that isn't actually required by the standard - float has only ~7 decimal digits of precision float triratio = r / pow(-q, 3.0f / 2.0f);//actually part of the cubic root equation, but we need to sanity check it if (triratio > 1.0f) triratio = 1.0f;//because we don't want acos to give a nan if (triratio < -1.0f) triratio = -1.0f; float theta = acos(triratio); float shapes[3];//these will be ordinary, not squared, strains float isoroot3 = pow(isotropic, 1.0f / 3.0f); for (int a = 0; a < 3; ++a) { shapes[a] = sqrt(2 * sqrt(-q) * cos((theta + a * 2 * PI) / 3.0f) + i1 / 3.0f) / isoroot3;//square root because squared tensor, and also divide out isotropic component } sort(shapes, shapes + 3); float anisotropic = -1.0f;//initialize with obviously-wrong value to silence compiler and make bugs obvious switch (myMethod) { case ELONGATION: anisotropic = shapes[2] / shapes[0];//deceptively simple: largest strain divided by smallest strain break; case CIRCULAR: { //new solution found by coincidence: square and sum the x coordinates of the vertices an equilateral triangle centered on the origin, you get (3r^2)/2, where r is the distance from the origin to a vertex float logshapes[3]; for (int a = 0; a < 3; ++a) { logshapes[a] = log(shapes[a]); } anisotropic = exp(sqrt(8.0f / 3.0f * (logshapes[0] * logshapes[0] + logshapes[1] * logshapes[1] + logshapes[2] * logshapes[2]))); break;//explanation time: per the help info, put the shape ratios into log space, so that geometry can be useful //now consider an equilateral triangle centered at the origin, and these log-space shape values as the x coordinates of the vertices //now, find the distance from the origin to any vertex, and multiply by 2 to get the circumscribing circle's diameter //the old solution relied on the the most-horizontal edge of the triangle being split by the y-axis at the same ratio as the magnitudes of the two extreme log-shape values (don't forget the negative sign) } } if (dolog2) { isotropic = log2(isotropic); anisotropic = log2(anisotropic); } distortionOut->setValue(isotropic, i, j, k, 0); distortionOut->setValue(anisotropic, i, j, k, 1); } } } } float AlgorithmVolumeDistortion::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeDistortion::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeDistortion.h000066400000000000000000000035401360521144700261030ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_DISTORTION_H__ #define __ALGORITHM_VOLUME_DISTORTION_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class WarpfieldFile; class AlgorithmVolumeDistortion : public AbstractAlgorithm { AlgorithmVolumeDistortion(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: enum Method { ELONGATION, CIRCULAR }; AlgorithmVolumeDistortion(ProgressObject* myProgObj, const WarpfieldFile& myWarp, VolumeFile* distortionOut, const Method myMethod = ELONGATION, const bool dolog2 = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeDistortion; } #endif //__ALGORITHM_VOLUME_DISTORTION_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeErode.cxx000066400000000000000000000237501360521144700253630ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeErode.h" #include "AlgorithmException.h" #include "CaretPointLocator.h" #include "VolumeFile.h" #include #include using namespace caret; using namespace std; AString AlgorithmVolumeErode::getCommandSwitch() { return "-volume-erode"; } AString AlgorithmVolumeErode::getShortDescription() { return "ERODE A VOLUME FILE"; } OperationParameters* AlgorithmVolumeErode::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume", "the volume to erode"); ret->addDoubleParameter(2, "distance", "distance in mm to erode"); ret->addVolumeOutputParameter(3, "volume-out", "the output volume"); OptionalParameter* roiOpt = ret->createOptionalParameter(4, "-roi", "assume voxels outside this roi are nonzero"); roiOpt->addVolumeParameter(1, "roi-volume", "volume file, positive values denote voxels that have data"); OptionalParameter* subvolOpt = ret->createOptionalParameter(5, "-subvolume", "select a single subvolume to dilate"); subvolOpt->addStringParameter(1, "subvol", "the subvolume number or name"); ret->setHelpText( AString("Around each voxel with a value of zero, set surrounding voxels to zero. ") + "The surrounding voxels are all face neighbors and all voxels within the specified distance (center to center)." ); return ret; } void AlgorithmVolumeErode::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* volIn = myParams->getVolume(1); float distance = (float)myParams->getDouble(2); VolumeFile* volOut = myParams->getOutputVolume(3); VolumeFile* roiVol = NULL; OptionalParameter* roiOpt = myParams->getOptionalParameter(4); if (roiOpt->m_present) { roiVol = roiOpt->getVolume(1); } int subvol = -1; OptionalParameter* subvolOpt = myParams->getOptionalParameter(5); if (subvolOpt->m_present) { subvol = volIn->getMapIndexFromNameOrNumber(subvolOpt->getString(1)); if (subvol < 0) throw AlgorithmException("invalid subvolume specified"); } AlgorithmVolumeErode(myProgObj, volIn, distance, volOut, roiVol, subvol); } namespace { void erodeFrame(const VolumeFile* volIn, const int& inFrame, const int& component, const float& distance, VolumeFile* volOut, const int& outFrame, const VolumeFile* roiVol) { int neighbors[] = { 0, 0, -1, 0, -1, 0, -1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 }; Vector3D ivec, jvec, kvec, origin; volIn->getVolumeSpace().getSpacingVectors(ivec, jvec, kvec, origin); float minSpacing = min(min(ivec.length(), jvec.length()), kvec.length()); bool checkNeighbors = (minSpacing > distance); vector myDims; volIn->getDimensions(myDims); const float* inData = volIn->getFrame(inFrame, component), *roiData = NULL; float emptyVal = 0.0f; bool labelData = false; if (volIn->getType() == SubvolumeAttributes::LABEL) { emptyVal = volIn->getMapLabelTable(inFrame)->getUnassignedLabelKey(); labelData = true; } if (roiVol != NULL) roiData = roiVol->getFrame(); vector scratchFrame(inData, inData + myDims[0] * myDims[1] * myDims[2]);//start with a copy, then zero what we don't need vector coordList; for (int64_t k = 0; k < myDims[2]; ++k) { for (int64_t j = 0; j < myDims[1]; ++j) { for (int64_t i = 0; i < myDims[0]; ++i) { int64_t flatIndex = volIn->getIndex(i, j, k); if (roiData == NULL || roiData[flatIndex] > 0.0f) { if (labelData) { if (floor(inData[flatIndex] + 0.5f) == emptyVal) { float coord[3]; volIn->indexToSpace(i, j, k, coord); coordList.insert(coordList.end(), coord, coord + 3); } } else { if (inData[flatIndex] == 0.0f) { float coord[3]; volIn->indexToSpace(i, j, k, coord); coordList.insert(coordList.end(), coord, coord + 3); } } } } } } CaretPointLocator myLocator(coordList.data(), coordList.size() / 3); for (int64_t k = 0; k < myDims[2]; ++k) { for (int64_t j = 0; j < myDims[1]; ++j) { for (int64_t i = 0; i < myDims[0]; ++i) { float coord[3]; volIn->indexToSpace(i, j, k, coord); if (myLocator.anyInRange(coord, distance)) { scratchFrame[volIn->getIndex(i, j, k)] = emptyVal;//this is used for both label and normal data, use the variable } else if (checkNeighbors) { for (int neigh = 0; neigh < 18; neigh += 3) { if (volIn->indexValid(i + neighbors[neigh], j + neighbors[neigh + 1], k + neighbors[neigh + 2])) { int64_t flatIndex = volIn->getIndex(i + neighbors[neigh], j + neighbors[neigh + 1], k + neighbors[neigh + 2]); if (roiData == NULL || roiData[flatIndex] > 0.0f) { if (labelData) { if (floor(inData[flatIndex] + 0.5f) == emptyVal) { scratchFrame[volIn->getIndex(i, j, k)] = emptyVal; } } else { if (inData[flatIndex] == 0.0f) { scratchFrame[volIn->getIndex(i, j, k)] = 0.0f; } } } } } } } } } volOut->setFrame(scratchFrame.data(), outFrame, component); } } AlgorithmVolumeErode::AlgorithmVolumeErode(ProgressObject* myProgObj, const VolumeFile* volIn, const float& distance, VolumeFile* volOut, VolumeFile* roiVol, const int& subvol) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); vector myDims; volIn->getDimensions(myDims); if (subvol < -1 || subvol >= myDims[3]) { throw AlgorithmException("invalid subvolume specified"); } if (distance < 0.0f) { throw AlgorithmException("distance cannot be negative"); } if (roiVol != NULL && !volIn->matchesVolumeSpace(roiVol)) { throw AlgorithmException("roi volume space does not match input volume"); } if (subvol == -1) { volOut->reinitialize(volIn->getOriginalDimensions(), volIn->getSform(), volIn->getNumberOfComponents(), volIn->getType(), volIn->m_header); for (int i = 0; i < myDims[3]; ++i) { if (volIn->getType() == SubvolumeAttributes::LABEL) { *(volOut->getMapLabelTable(i)) = *(volIn->getMapLabelTable(i)); } else { *(volOut->getMapPaletteColorMapping(i)) = *(volIn->getMapPaletteColorMapping(i)); } volOut->setMapName(i, volIn->getMapName(i) + " dilate " + AString::number(distance)); } for (int s = 0; s < myDims[3]; ++s) { for (int c = 0; c < myDims[4]; ++c) { erodeFrame(volIn, s, c, distance, volOut, s, roiVol); } } } else { vector outDims = myDims; outDims.resize(3); volOut->reinitialize(outDims, volIn->getSform(), volIn->getNumberOfComponents(), volIn->getType(), volIn->m_header); if (volIn->getType() == SubvolumeAttributes::LABEL) { *(volOut->getMapLabelTable(0)) = *(volIn->getMapLabelTable(subvol)); } else { *(volOut->getMapPaletteColorMapping(0)) = *(volIn->getMapPaletteColorMapping(subvol)); } volOut->setMapName(0, volIn->getMapName(subvol) + " dilate " + AString::number(distance)); for (int c = 0; c < myDims[4]; ++c) { erodeFrame(volIn, subvol, c, distance, volOut, 0, roiVol); } } } float AlgorithmVolumeErode::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeErode::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeErode.h000066400000000000000000000033031360521144700250000ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_ERODE_H__ #define __ALGORITHM_VOLUME_ERODE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmVolumeErode : public AbstractAlgorithm { AlgorithmVolumeErode(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeErode(ProgressObject* myProgObj, const VolumeFile* volIn, const float& distance, VolumeFile* volOut, VolumeFile* roiVol = NULL, const int& subvol = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeErode; } #endif //__ALGORITHM_VOLUME_ERODE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeEstimateFWHM.cxx000066400000000000000000000453051360521144700265620ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeEstimateFWHM.h" #include "AlgorithmException.h" #include #include using namespace caret; using namespace std; AString AlgorithmVolumeEstimateFWHM::getCommandSwitch() { return "-volume-estimate-fwhm"; } AString AlgorithmVolumeEstimateFWHM::getShortDescription() { return "ESTIMATE FWHM SMOOTHNESS OF A VOLUME"; } OperationParameters* AlgorithmVolumeEstimateFWHM::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume", "the input volume"); OptionalParameter* roiVolOpt = ret->createOptionalParameter(2, "-roi", "use only data within an ROI"); roiVolOpt->addVolumeParameter(1, "roivol", "the volume to use as an ROI"); OptionalParameter* subvolSelect = ret->createOptionalParameter(3, "-subvolume", "select a single subvolume to estimate smoothness of"); subvolSelect->addStringParameter(1, "subvol", "the subvolume number or name"); OptionalParameter* allFramesOpt = ret->createOptionalParameter(4, "-whole-file", "estimate for the whole file at once, not each subvolume separately"); allFramesOpt->createOptionalParameter(1, "-demean", "subtract the mean image before estimating smoothness"); ret->setHelpText( AString("Estimates the smoothness of the input volume in X, Y, and Z directions separately, printing the estimates to standard output, in mm as FWHM. ") + "If -subvolume or -whole-file are not specified, each subvolume is estimated and displayed separately." ); return ret; } void AlgorithmVolumeEstimateFWHM::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); VolumeFile* myVol = myParams->getVolume(1); OptionalParameter* roiVolOpt = myParams->getOptionalParameter(2); VolumeFile* roiVol = NULL; if (roiVolOpt->m_present) { roiVol = roiVolOpt->getVolume(1); if (!roiVol->matchesVolumeSpace(myVol)) { throw AlgorithmException("roi volume does not match the space of the input volume"); } } OptionalParameter* subvolSelect = myParams->getOptionalParameter(3); int subvolNum = -1; if (subvolSelect->m_present) { subvolNum = (int)myVol->getMapIndexFromNameOrNumber(subvolSelect->getString(1)); if (subvolNum < 0) { throw AlgorithmException("invalid subvolume specified"); } } bool allFrames = false, demean = false; OptionalParameter* allFramesOpt = myParams->getOptionalParameter(4); if (allFramesOpt->m_present) { if (subvolSelect->m_present) throw AlgorithmException("specifying both -subvolume and -whole-file is not allowed"); allFrames = true; demean = allFramesOpt->getOptionalParameter(1)->m_present; } vector dims; myVol->getDimensions(dims); if (allFrames) { Vector3D result = estimateFWHMAllFrames(myVol, roiVol, demean); cout << "FWHM: " << result[0] << ", " << result[1] << ", " << result[2] << endl; } else { if (subvolNum == -1) { for (int64_t s = 0; s < dims[3]; ++s) { for (int64_t c = 0; c < dims[4]; ++c) { Vector3D result = estimateFWHM(myVol, roiVol, s, c); if (dims[3] != 1) cout << "subvol " << s + 1 << " "; if (dims[4] != 1) cout << "component " << c + 1 << " "; cout << "FWHM: " << result[0] << ", " << result[1] << ", " << result[2] << endl; } } } else { for (int64_t c = 0; c < dims[4]; ++c) { Vector3D result = estimateFWHM(myVol, roiVol, subvolNum, c); if (dims[3] != 1) cout << "subvol " << subvolNum + 1 << " "; if (dims[4] != 1) cout << "component " << c + 1 << " "; cout << "FWHM: " << result[0] << ", " << result[1] << ", " << result[2] << endl; } } } } Vector3D AlgorithmVolumeEstimateFWHM::estimateFWHM(const VolumeFile* input, const VolumeFile* roi, const int64_t& brickIndex, const int64_t& component) { if (roi != NULL && !roi->matchesVolumeSpace(input)) { throw AlgorithmException("roi volume does not match the space of the input volume"); } vector dims; input->getDimensions(dims); double globalaccum = 0.0; int64_t globalCount = 0; double diraccum[3] = {0.0, 0.0, 0.0}; int64_t dirCount[3] = {0, 0, 0}; for (int64_t k = 0; k < dims[2]; ++k)//2 pass method, first find means of values and of FORWARD differences only - this removes global gradient effects {//for derivation, see Forman, S.D., Cohen, J.D., Fitzgerald, M., Eddy, W.F., Mintun, M.A., Noll, D.C., 1995. for (int64_t j = 0; j < dims[1]; ++j)//Improved assessment of significant activation in functional magnetic resonance imaging (fMRI): use of a cluster-size threshold. {//Magn. Reson. Med. 33, 636–647. for (int64_t i = 0; i < dims[0]; ++i) { if (roi == NULL || roi->getValue(i, j, k) > 0.0f) { float center = input->getValue(i, j, k, brickIndex, component); globalaccum += center; ++globalCount; if (i + 1 < dims[0] && (roi == NULL || roi->getValue(i + 1, j, k) > 0.0f))//use ONLY forward differences, to avoid double counting { float diff = center - input->getValue(i + 1, j, k, brickIndex, component); diraccum[0] += diff; ++dirCount[0]; } if (j + 1 < dims[1] && (roi == NULL || roi->getValue(i, j + 1, k) > 0.0f))//use ONLY forward differences, to avoid double counting { float diff = center - input->getValue(i, j + 1, k, brickIndex, component); diraccum[1] += diff; ++dirCount[1]; } if (k + 1 < dims[2] && (roi == NULL || roi->getValue(i, j, k + 1) > 0.0f))//use ONLY forward differences, to avoid double counting { float diff = center - input->getValue(i, j, k + 1, brickIndex, component); diraccum[2] += diff; ++dirCount[2]; } } } } } if (globalCount == 0) throw AlgorithmException("ROI is empty or volume file has no voxels"); float dirmean[3]; for (int i = 0; i < 3; ++i) { dirmean[i] = diraccum[i] / dirCount[i];//we will fix NaNs later diraccum[i] = 0.0; } float globalmean = globalaccum / globalCount; globalaccum = 0; for (int64_t k = 0; k < dims[2]; ++k)//now, find the variances { for (int64_t j = 0; j < dims[1]; ++j) { for (int64_t i = 0; i < dims[0]; ++i) { if (roi == NULL || roi->getValue(i, j, k) > 0.0f) { float center = input->getValue(i, j, k, brickIndex, component); float tempf = center - globalmean; globalaccum += tempf * tempf; if (i + 1 < dims[0] && (roi == NULL || roi->getValue(i + 1, j, k) > 0.0f))//use ONLY forward differences, to avoid double counting { float diff = center - input->getValue(i + 1, j, k, brickIndex, component); tempf = diff - dirmean[0]; diraccum[0] += tempf * tempf; } if (j + 1 < dims[1] && (roi == NULL || roi->getValue(i, j + 1, k) > 0.0f))//use ONLY forward differences, to avoid double counting { float diff = center - input->getValue(i, j + 1, k, brickIndex, component); tempf = diff - dirmean[1]; diraccum[1] += tempf * tempf; } if (k + 1 < dims[2] && (roi == NULL || roi->getValue(i, j, k + 1) > 0.0f))//use ONLY forward differences, to avoid double counting { float diff = center - input->getValue(i, j, k + 1, brickIndex, component); tempf = diff - dirmean[2]; diraccum[2] += tempf * tempf; } } } } } float dirvariance[3]; float fwhms[3]; float globalvariance = globalaccum / globalCount; const VolumeSpace& volSpace = input->getVolumeSpace(); Vector3D spacingVecs[4]; volSpace.getSpacingVectors(spacingVecs[0], spacingVecs[1], spacingVecs[2], spacingVecs[3]); for (int i = 0; i < 3; ++i) { if (dirCount[i] > 0) { dirvariance[i] = diraccum[i] / dirCount[i]; } else { dirvariance[i] = 0.0;//avoid NaN for variance...however, 0 directional variance means the formula will become NaN... } fwhms[i] = spacingVecs[i].length() * sqrt(-2.0f * log(2.0f) / log(1.0f - dirvariance[i] / (2.0f * globalvariance))); } Vector3D ret; VolumeSpace::OrientTypes myorient[3]; volSpace.getOrientation(myorient); for (int i = 0; i < 3; ++i) { switch (myorient[i]) { case VolumeSpace::LEFT_TO_RIGHT: case VolumeSpace::RIGHT_TO_LEFT: ret[0] = fwhms[i]; break; case VolumeSpace::POSTERIOR_TO_ANTERIOR: case VolumeSpace::ANTERIOR_TO_POSTERIOR: ret[1] = fwhms[i]; break; case VolumeSpace::INFERIOR_TO_SUPERIOR: case VolumeSpace::SUPERIOR_TO_INFERIOR: ret[2] = fwhms[i]; break; } } return ret; } Vector3D AlgorithmVolumeEstimateFWHM::estimateFWHMAllFrames(const VolumeFile* input, const VolumeFile* roi, bool demean) { if (roi != NULL && !roi->matchesVolumeSpace(input)) { throw AlgorithmException("roi volume does not match the space of the input volume"); } const float* roiFrame = NULL; if (roi != NULL) roiFrame = roi->getFrame(); vector dims; input->getDimensions(dims); int64_t frameSize = dims[0] * dims[1] * dims[2]; vector > meanimage; if (demean) { meanimage.resize(dims[4], vector(frameSize, 0.0));//keep components separate, I guess for (int64_t component = 0; component < dims[4]; ++component) { for (int64_t brickIndex = 0; brickIndex < dims[3]; ++brickIndex) { const float* frame = input->getFrame(brickIndex, component); for (int64_t i = 0; i < frameSize; ++i) { if (roiFrame == NULL || roiFrame[i] > 0.0f) {//only computing the mean image inside the ROI reduces the working set meanimage[component][i] += frame[i]; } } } for (int64_t i = 0; i < frameSize; ++i) { if (roiFrame == NULL || roiFrame[i] > 0.0f) { meanimage[component][i] /= dims[3]; } } } } double globalaccum = 0.0; int64_t globalCount = 0; double diraccum[3] = {0.0, 0.0, 0.0}; int64_t dirCount[3] = {0, 0, 0}; vector demeaned;//less reallocation if (demean) demeaned.resize(frameSize); for (int64_t component = 0; component < dims[4]; ++component) { for (int64_t brickIndex = 0; brickIndex < dims[3]; ++brickIndex) { const float* frame = input->getFrame(brickIndex, component); if (demean) { for (int64_t i = 0; i < frameSize; ++i) { if (roiFrame == NULL || roiFrame[i] > 0.0f) {//again, to keep working set down demeaned[i] = frame[i] - meanimage[component][i]; } } frame = demeaned.data(); } for (int64_t k = 0; k < dims[2]; ++k) { for (int64_t j = 0; j < dims[1]; ++j) { for (int64_t i = 0; i < dims[0]; ++i) { if (roi == NULL || roi->getValue(i, j, k) > 0.0f) { float center = frame[input->getIndex(i, j, k)]; globalaccum += center; ++globalCount; if (i + 1 < dims[0] && (roi == NULL || roi->getValue(i + 1, j, k) > 0.0f))//use ONLY forward differences, to avoid double counting { float diff = center - frame[input->getIndex(i + 1, j, k)]; diraccum[0] += diff; ++dirCount[0]; } if (j + 1 < dims[1] && (roi == NULL || roi->getValue(i, j + 1, k) > 0.0f))//use ONLY forward differences, to avoid double counting { float diff = center - frame[input->getIndex(i, j + 1, k)]; diraccum[1] += diff; ++dirCount[1]; } if (k + 1 < dims[2] && (roi == NULL || roi->getValue(i, j, k + 1) > 0.0f))//use ONLY forward differences, to avoid double counting { float diff = center - frame[input->getIndex(i, j, k + 1)]; diraccum[2] += diff; ++dirCount[2]; } } } } } } } if (globalCount == 0) throw AlgorithmException("ROI is empty or volume file has no voxels"); float dirmean[3]; for (int i = 0; i < 3; ++i) { dirmean[i] = diraccum[i] / dirCount[i];//we will fix NaNs later diraccum[i] = 0.0; } float globalmean = globalaccum / globalCount; globalaccum = 0.0; for (int64_t component = 0; component < dims[4]; ++component) { for (int64_t brickIndex = 0; brickIndex < dims[3]; ++brickIndex) { const float* frame = input->getFrame(brickIndex, component); if (demean) { for (int64_t i = 0; i < frameSize; ++i) { if (roiFrame == NULL || roiFrame[i] > 0.0f) { demeaned[i] = frame[i] - meanimage[component][i]; } } frame = demeaned.data(); } for (int64_t k = 0; k < dims[2]; ++k)//now, find the variances { for (int64_t j = 0; j < dims[1]; ++j) { for (int64_t i = 0; i < dims[0]; ++i) { if (roi == NULL || roi->getValue(i, j, k) > 0.0f) { float center = frame[input->getIndex(i, j, k)]; float tempf = center - globalmean; globalaccum += tempf * tempf; if (i + 1 < dims[0] && (roi == NULL || roi->getValue(i + 1, j, k) > 0.0f))//use ONLY forward differences, to avoid double counting { float diff = center - frame[input->getIndex(i + 1, j, k)]; tempf = diff - dirmean[0]; diraccum[0] += tempf * tempf; } if (j + 1 < dims[1] && (roi == NULL || roi->getValue(i, j + 1, k) > 0.0f))//use ONLY forward differences, to avoid double counting { float diff = center - frame[input->getIndex(i, j + 1, k)]; tempf = diff - dirmean[1]; diraccum[1] += tempf * tempf; } if (k + 1 < dims[2] && (roi == NULL || roi->getValue(i, j, k + 1) > 0.0f))//use ONLY forward differences, to avoid double counting { float diff = center - frame[input->getIndex(i, j, k + 1)]; tempf = diff - dirmean[2]; diraccum[2] += tempf * tempf; } } } } } } } float dirvariance[3]; float fwhms[3]; float globalvariance = globalaccum / globalCount; const VolumeSpace& volSpace = input->getVolumeSpace(); Vector3D spacingVecs[4]; volSpace.getSpacingVectors(spacingVecs[0], spacingVecs[1], spacingVecs[2], spacingVecs[3]); for (int i = 0; i < 3; ++i) { if (dirCount[i] > 0) { dirvariance[i] = diraccum[i] / dirCount[i]; } else { dirvariance[i] = 0.0; } fwhms[i] = spacingVecs[i].length() * sqrt(-2.0f * log(2.0f) / log(1.0f - dirvariance[i] / (2.0f * globalvariance))); } Vector3D ret; VolumeSpace::OrientTypes myorient[3]; volSpace.getOrientation(myorient); for (int i = 0; i < 3; ++i) { switch (myorient[i]) { case VolumeSpace::LEFT_TO_RIGHT: case VolumeSpace::RIGHT_TO_LEFT: ret[0] = fwhms[i]; break; case VolumeSpace::POSTERIOR_TO_ANTERIOR: case VolumeSpace::ANTERIOR_TO_POSTERIOR: ret[1] = fwhms[i]; break; case VolumeSpace::INFERIOR_TO_SUPERIOR: case VolumeSpace::SUPERIOR_TO_INFERIOR: ret[2] = fwhms[i]; break; } } return ret; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeEstimateFWHM.h000066400000000000000000000033751360521144700262100ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_ESTIMATE_FWHM_H__ #define __ALGORITHM_VOLUME_ESTIMATE_FWHM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "Vector3D.h" #include "VolumeFile.h" namespace caret { class AlgorithmVolumeEstimateFWHM : public AbstractAlgorithm { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); static Vector3D estimateFWHM(const VolumeFile* input, const VolumeFile* roi = NULL, const int64_t& brickIndex = 0, const int64_t& component = 0); static Vector3D estimateFWHMAllFrames(const VolumeFile* input, const VolumeFile* roi = NULL, bool demean = false); }; typedef TemplateAutoOperation AutoAlgorithmVolumeEstimateFWHM; } #endif //__ALGORITHM_VOLUME_ESTIMATE_FWHM_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeExtrema.cxx000066400000000000000000001516061360521144700257340ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeExtrema.h" #include "AlgorithmException.h" #include "AlgorithmVolumeSmoothing.h" #include "CaretHeap.h" #include "CaretLogger.h" #include "CaretOMP.h" #include "VolumeFile.h" #include #include #include using namespace caret; using namespace std; AString AlgorithmVolumeExtrema::getCommandSwitch() { return "-volume-extrema"; } AString AlgorithmVolumeExtrema::getShortDescription() { return "FIND EXTREMA IN A VOLUME FILE"; } OperationParameters* AlgorithmVolumeExtrema::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume-in", "volume file to find the extrema of"); ret->addDoubleParameter(2, "distance", "the minimum distance between identified extrema of the same type"); ret->addVolumeOutputParameter(3, "volume-out", "the output extrema volume"); OptionalParameter* presmoothOpt = ret->createOptionalParameter(4, "-presmooth", "smooth the volume before finding extrema"); presmoothOpt->addDoubleParameter(1, "kernel", "the sigma for the gaussian smoothing kernel, in mm"); OptionalParameter* roiOpt = ret->createOptionalParameter(5, "-roi", "ignore values outside the selected area"); roiOpt->addVolumeParameter(1, "roi-volume", "the area to find extrema in"); OptionalParameter* thresholdOpt = ret->createOptionalParameter(6, "-threshold", "ignore small extrema"); thresholdOpt->addDoubleParameter(1, "low", "the largest value to consider for being a minimum"); thresholdOpt->addDoubleParameter(2, "high", "the smallest value to consider for being a maximum"); ret->createOptionalParameter(7, "-sum-subvols", "output the sum of the extrema subvolumes instead of each subvolume separately"); ret->createOptionalParameter(8, "-consolidate-mode", "use consolidation of local minima instead of a large neighborhood"); ret->createOptionalParameter(10, "-only-maxima", "only find the maxima"); ret->createOptionalParameter(11, "-only-minima", "only find the minima"); OptionalParameter* subvolOpt = ret->createOptionalParameter(9, "-subvolume", "select a single subvolume to find extrema in"); subvolOpt->addStringParameter(1, "subvolume", "the subvolume number or name"); ret->setHelpText( AString("Finds extrema in a volume file, such that no two extrema of the same type are within of each other. ") + "The extrema are labeled as -1 for minima, 1 for maxima, 0 otherwise. " + "If -only-maxima or -only-minima is specified, then it will ignore extrema not of the specified type. These options are mutually exclusive.\n\n" + "If -sum-subvols is specified, these extrema subvolumes are summed, and the output has a single subvolume with this result.\n\n" + "By default, a datapoint is an extrema only if it is more extreme than every other datapoint that is within from it. " + "If -consolidate-mode is used, it instead starts by finding all datapoints that are more extreme than their immediate neighbors, " + "then while there are any extrema within of each other, take the two extrema closest to each other and merge them into one by a weighted average " + "based on how many original extrema have been merged into each.\n\n" + "By default, all input subvolumes are used with no smoothing, use -subvolume to specify a single subvolume to use, and -presmooth to smooth the input before " + "finding the extrema." ); return ret; } void AlgorithmVolumeExtrema::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* myVolIn = myParams->getVolume(1); float distance = (float)myParams->getDouble(2); VolumeFile* myVolOut = myParams->getOutputVolume(3); OptionalParameter* presmoothOpt = myParams->getOptionalParameter(4); float presmooth = -1.0f; if (presmoothOpt->m_present) { presmooth = presmoothOpt->getDouble(1); if (presmooth <= 0.0f) { throw AlgorithmException("smoothing kernel must be positive"); } } OptionalParameter* roiOpt = myParams->getOptionalParameter(5); VolumeFile* myRoi = NULL; if (roiOpt->m_present) { myRoi = roiOpt->getVolume(1); } OptionalParameter* thresholdOpt = myParams->getOptionalParameter(6); bool thresholdMode = false; float lowThresh = 0.0f, highThresh = 0.0f; if (thresholdOpt->m_present) { thresholdMode = true; lowThresh = (float)thresholdOpt->getDouble(1); highThresh = (float)thresholdOpt->getDouble(2); } bool sumSubvols = myParams->getOptionalParameter(7)->m_present; bool consolidateMode = myParams->getOptionalParameter(8)->m_present; OptionalParameter* subvolOpt = myParams->getOptionalParameter(9); int subvol = -1; if (subvolOpt->m_present) {//set up to use the single column subvol = (int)myVolIn->getMapIndexFromNameOrNumber(subvolOpt->getString(1)); if (subvol < 0) { throw AlgorithmException("invalid subvolume specified"); } } bool ignoreMinima = myParams->getOptionalParameter(10)->m_present; bool ignoreMaxima = myParams->getOptionalParameter(11)->m_present; if (ignoreMinima && ignoreMaxima) throw AlgorithmException("you may not specify both -only-maxima and -only-minima"); if (thresholdMode) { AlgorithmVolumeExtrema(myProgObj, myVolIn, distance, myVolOut, lowThresh, highThresh, myRoi, presmooth, sumSubvols, consolidateMode, ignoreMinima, ignoreMaxima, subvol); } else { AlgorithmVolumeExtrema(myProgObj, myVolIn, distance, myVolOut, myRoi, presmooth, sumSubvols, consolidateMode, ignoreMinima, ignoreMaxima, subvol); } } AlgorithmVolumeExtrema::AlgorithmVolumeExtrema(ProgressObject* myProgObj, const VolumeFile* myVolIn, const float& distance, VolumeFile* myVolOut, const VolumeFile* myRoi, const float& presmooth, const bool& sumSubvols, const bool& consolidateMode, bool ignoreMinima, bool ignoreMaxima, const int& subvol) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (ignoreMinima && ignoreMaxima) throw AlgorithmException("AlgorithmVolumeExtrema called with ignoreMinima and ignoreMaxima both true"); if (myRoi != NULL && !myVolIn->matchesVolumeSpace(myRoi)) { throw AlgorithmException("roi doesn't match input volume space"); } vector myDims; myVolIn->getDimensions(myDims); if (subvol < -1 || subvol >= myDims[3]) { throw AlgorithmException("invalid subvolume specified"); } int useSubvol = subvol; const VolumeFile* toProcess = myVolIn; VolumeFile tempVol; if (presmooth > 0.0f) { AlgorithmVolumeSmoothing(NULL, myVolIn, presmooth, &tempVol, myRoi, false, subvol); toProcess = &tempVol; if (subvol != -1) { useSubvol = 0; } } if (!consolidateMode) { precomputeStencil(myVolIn, distance); } if (subvol == -1) { vector minima, maxima; vector outDims = myDims; outDims.resize(4); if (sumSubvols) { outDims[3] = 1; } myVolOut->reinitialize(outDims, myVolIn->getSform(), myDims[4], SubvolumeAttributes::ANATOMY, myVolIn->m_header); if (sumSubvols) { myVolOut->setMapName(0, "sum of extrema"); } myVolOut->setValueAllVoxels(0.0f); for (int s = 0; s < myDims[3]; ++s) { for (int c = 0; c < myDims[4]; ++c) { if (consolidateMode) { findExtremaConsolidate(toProcess, s, c, myRoi, distance, false, 0.0f, 0.0f, ignoreMinima, ignoreMaxima, minima, maxima); } else { findExtremaStencils(toProcess, s, c, myRoi, false, 0.0f, 0.0f, ignoreMinima, ignoreMaxima, minima, maxima); } if (sumSubvols) { int64_t numElems = (int64_t)minima.size(); for (int64_t i = 0; i < numElems; ++i) { myVolOut->setValue(myVolOut->getValue(minima[i].m_ijk, 0, c) - 1.0f, minima[i].m_ijk, 0, c); } numElems = (int64_t)maxima.size(); for (int64_t i = 0; i < numElems; ++i) { myVolOut->setValue(myVolOut->getValue(maxima[i].m_ijk, 0, c) + 1.0f, maxima[i].m_ijk, 0, c); } } else { if (c == 0) myVolOut->setMapName(s, "extrema of " + myVolIn->getMapName(s)); int64_t numElems = (int64_t)minima.size(); for (int64_t i = 0; i < numElems; ++i) { myVolOut->setValue(-1.0f, minima[i].m_ijk, s, c); } numElems = (int64_t)maxima.size(); for (int64_t i = 0; i < numElems; ++i) { myVolOut->setValue(1.0f, maxima[i].m_ijk, s, c); } } } } } else { vector minima, maxima; vector outDims = myDims; outDims.resize(3); myVolOut->reinitialize(outDims, myVolIn->getSform(), myDims[4], SubvolumeAttributes::ANATOMY, myVolIn->m_header); myVolOut->setMapName(0, "extrema of " + myVolIn->getMapName(subvol)); myVolOut->setValueAllVoxels(0.0f); for (int c = 0; c < myDims[4]; ++c) { if (consolidateMode) { findExtremaConsolidate(toProcess, useSubvol, c, myRoi, distance, false, 0.0f, 0.0f, ignoreMinima, ignoreMaxima, minima, maxima); } else { findExtremaStencils(toProcess, useSubvol, c, myRoi, false, 0.0f, 0.0f, ignoreMinima, ignoreMaxima, minima, maxima); } int64_t numElems = (int64_t)minima.size(); for (int64_t i = 0; i < numElems; ++i) { myVolOut->setValue(-1.0f, minima[i].m_ijk, 0, c); } numElems = (int64_t)maxima.size(); for (int64_t i = 0; i < numElems; ++i) { myVolOut->setValue(1.0f, maxima[i].m_ijk, 0, c); } } } } AlgorithmVolumeExtrema::AlgorithmVolumeExtrema(ProgressObject* myProgObj, const VolumeFile* myVolIn, const float& distance, VolumeFile* myVolOut, const float& lowThresh, const float& highThresh, const VolumeFile* myRoi, const float& presmooth, const bool& sumSubvols, const bool& consolidateMode, bool ignoreMinima, bool ignoreMaxima, const int& subvol) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (ignoreMinima && ignoreMaxima) throw AlgorithmException("AlgorithmVolumeExtrema called with ignoreMinima and ignoreMaxima both true"); if (myRoi != NULL && !myVolIn->matchesVolumeSpace(myRoi)) { throw AlgorithmException("roi doesn't match input volume space"); } vector myDims; myVolIn->getDimensions(myDims); if (subvol < -1 || subvol >= myDims[3]) { throw AlgorithmException("invalid subvolume specified"); } int useSubvol = subvol; const VolumeFile* toProcess = myVolIn; VolumeFile tempVol; if (presmooth > 0.0f) { AlgorithmVolumeSmoothing(NULL, myVolIn, presmooth, &tempVol, myRoi, false, subvol); toProcess = &tempVol; if (subvol != -1) { useSubvol = 0; } } if (!consolidateMode) { precomputeStencil(myVolIn, distance); } if (subvol == -1) { vector minima, maxima; vector outDims = myDims; outDims.resize(4); if (sumSubvols) { outDims[3] = 1; } myVolOut->reinitialize(outDims, myVolIn->getSform(), myDims[4]); if (sumSubvols) { myVolOut->setMapName(0, "sum of extrema"); } myVolOut->setValueAllVoxels(0.0f); for (int s = 0; s < myDims[3]; ++s) { for (int c = 0; c < myDims[4]; ++c) { if (consolidateMode) { findExtremaConsolidate(toProcess, s, c, myRoi, distance, true, lowThresh, highThresh, ignoreMinima, ignoreMaxima, minima, maxima); } else { findExtremaStencils(toProcess, s, c, myRoi, true, lowThresh, highThresh, ignoreMinima, ignoreMaxima, minima, maxima); } if (sumSubvols) { int64_t numElems = (int64_t)minima.size(); for (int64_t i = 0; i < numElems; ++i) { myVolOut->setValue(myVolOut->getValue(minima[i].m_ijk, 0, c) - 1.0f, minima[i].m_ijk, 0, c); } numElems = (int64_t)maxima.size(); for (int64_t i = 0; i < numElems; ++i) { myVolOut->setValue(myVolOut->getValue(maxima[i].m_ijk, 0, c) + 1.0f, maxima[i].m_ijk, 0, c); } } else { if (c == 0) myVolOut->setMapName(s, "extrema of " + myVolIn->getMapName(s)); int64_t numElems = (int64_t)minima.size(); for (int64_t i = 0; i < numElems; ++i) { myVolOut->setValue(-1.0f, minima[i].m_ijk, s, c); } numElems = (int64_t)maxima.size(); for (int64_t i = 0; i < numElems; ++i) { myVolOut->setValue(1.0f, maxima[i].m_ijk, s, c); } } } } } else { vector minima, maxima; vector outDims = myDims; outDims.resize(3); myVolOut->reinitialize(outDims, myVolIn->getSform(), myDims[4]); myVolOut->setMapName(0, "extrema of " + myVolIn->getMapName(subvol)); myVolOut->setValueAllVoxels(0.0f); for (int c = 0; c < myDims[4]; ++c) { if (consolidateMode) { findExtremaConsolidate(toProcess, useSubvol, c, myRoi, distance, true, lowThresh, highThresh, ignoreMinima, ignoreMaxima, minima, maxima); } else { findExtremaStencils(toProcess, useSubvol, c, myRoi, true, lowThresh, highThresh, ignoreMinima, ignoreMaxima, minima, maxima); } int64_t numElems = (int64_t)minima.size(); for (int64_t i = 0; i < numElems; ++i) { myVolOut->setValue(-1.0f, minima[i].m_ijk, 0, c); } numElems = (int64_t)maxima.size(); for (int64_t i = 0; i < numElems; ++i) { myVolOut->setValue(1.0f, maxima[i].m_ijk, 0, c); } } } } void AlgorithmVolumeExtrema::precomputeStencil(const VolumeFile* myVolIn, const float& distance) { m_stencil.clear(); const vector >& volSpace = myVolIn->getSform(); Vector3D ivec, jvec, kvec, origin; ivec[0] = volSpace[0][0]; jvec[0] = volSpace[0][1]; kvec[0] = volSpace[0][2]; origin[0] = volSpace[0][3]; ivec[1] = volSpace[1][0]; jvec[1] = volSpace[1][1]; kvec[1] = volSpace[1][2]; origin[1] = volSpace[1][3]; ivec[2] = volSpace[2][0]; jvec[2] = volSpace[2][1]; kvec[2] = volSpace[2][2]; origin[2] = volSpace[2][3]; Vector3D ijorth = ivec.cross(jvec).normal();//find the bounding box that encloses a sphere of radius kernBox Vector3D jkorth = jvec.cross(kvec).normal(); Vector3D kiorth = kvec.cross(ivec).normal(); m_irange = (int)floor(abs(distance / ivec.dot(jkorth)));//these are member variables so we can avoid testing for things outside the volume bounding box when the stencil is m_jrange = (int)floor(abs(distance / jvec.dot(kiorth)));// guaranteed within the bounding box m_krange = (int)floor(abs(distance / kvec.dot(ijorth))); if (m_irange < 1) m_irange = 1;//don't underflow if (m_jrange < 1) m_jrange = 1; if (m_krange < 1) m_krange = 1; float dist2 = distance * distance;//don't require square root calls VoxelIJK tempVox; bool ichange = false, jchange = false, kchange = false;//ensure that stencil is 3D, not degenerate for (int k = -m_krange; k <= m_krange; ++k)//generate the stencil list in the same index order as the volume file { Vector3D kpart = k * kvec; tempVox.m_ijk[2] = k; for (int j = -m_jrange; j <= m_jrange; ++j) { Vector3D jpart = (j * jvec) + kpart;//I could do an extra test here, or recompute the range, but we only do this once, so whatever tempVox.m_ijk[1] = j; for (int i = -m_irange; i <= m_irange; ++i) { if (k == 0 && j == 0 && i == 0) continue;//skip the center voxel if ((jpart + (i * ivec)).lengthsquared() <= dist2) { tempVox.m_ijk[0] = i; m_stencil.push_back(tempVox); if (k != 0) kchange = true; if (j != 0) jchange = true; if (i != 0) ichange = true; } } } } if (!ichange || !jchange || !kchange) { CaretLogWarning("distance too small, stencil did not use all 3 dimensions, substituting in 6-neighbor stencil"); m_irange = 1; m_jrange = 1; m_krange = 1; m_stencil.clear(); m_stencil.push_back(VoxelIJK(-1, 0, 0)); m_stencil.push_back(VoxelIJK(0, -1, 0)); m_stencil.push_back(VoxelIJK(0, 0, -1)); m_stencil.push_back(VoxelIJK(0, 0, 1)); m_stencil.push_back(VoxelIJK(0, 1, 0)); m_stencil.push_back(VoxelIJK(1, 0, 0)); } } void AlgorithmVolumeExtrema::findExtremaStencils(const VolumeFile* toProcess, const int& s, const int& c, const VolumeFile* myRoi, const bool& threshMode, const float& lowThresh, const float& highThresh, bool ignoreMinima, bool ignoreMaxima, vector& minima, vector& maxima) { minima.clear(); maxima.clear(); vector myDims; toProcess->getDimensions(myDims); int64_t frameSize = myDims[0] * myDims[1] * myDims[2]; int stencilSize = (int)m_stencil.size(); vector minPos(frameSize, 1), maxPos(frameSize, 1);//mark things off that fail a comparison, to reduce redundant comparisons const float* dataFrame = toProcess->getFrame(s, c); const float* roiFrame = NULL; if (myRoi != NULL) { roiFrame = myRoi->getFrame(); } #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t k = 0; k < myDims[2]; ++k) { bool ksafe = (k >= m_krange && k < myDims[2] - m_krange);//so we can avoid performing certain bounds checks in the inner loop for (int64_t j = 0; j < myDims[1]; ++j) { bool jsafe = (j >= m_jrange && j < myDims[1] - m_jrange); for (int64_t i = 0; i < myDims[0]; ++i) { int64_t myindex = toProcess->getIndex(i, j, k); if (roiFrame == NULL || roiFrame[myindex] > 0.0f) { bool canBeMin = minPos[myindex] && !ignoreMinima; bool canBeMax = maxPos[myindex] && !ignoreMaxima; float myval = dataFrame[myindex]; if (threshMode) { if (myval > lowThresh) canBeMin = false;//check thresholds if (myval < highThresh) canBeMax = false; } if (canBeMin || canBeMax) { bool isafe = (i >= m_jrange && i < myDims[0] - m_irange); if (isafe && jsafe && ksafe)//special case out the inner loops to avoid branching when possible { if (roiFrame == NULL) { int v = 0; if (canBeMin && canBeMax)//no ROI and safe means we can just use the first element in stencil to break the double test { VoxelIJK& offset = m_stencil[0]; int64_t testVox[3] = { i + offset.m_ijk[0], j + offset.m_ijk[1], k + offset.m_ijk[2] }; int64_t otherindex = toProcess->getIndex(testVox); float otherval = dataFrame[otherindex]; if (myval < otherval) { minPos[otherindex] = 0; } else { canBeMin = false; } if (myval > otherval) { maxPos[otherindex] = 0; } else { canBeMax = false; } v = 1; } if (canBeMin) { for (; v < stencilSize; ++v) { VoxelIJK& offset = m_stencil[v]; int64_t testVox[3] = { i + offset.m_ijk[0], j + offset.m_ijk[1], k + offset.m_ijk[2] }; int64_t otherindex = toProcess->getIndex(testVox); float otherval = dataFrame[otherindex]; if (myval < otherval) { minPos[otherindex] = 0; } else { canBeMin = false; break; } } } if (canBeMax) { for (; v < stencilSize; ++v) { VoxelIJK& offset = m_stencil[v]; int64_t testVox[3] = { i + offset.m_ijk[0], j + offset.m_ijk[1], k + offset.m_ijk[2] }; int64_t otherindex = toProcess->getIndex(testVox); float otherval = dataFrame[otherindex]; if (myval > otherval) { maxPos[otherindex] = 0; } else { canBeMax = false; break; } } } } else { int v = 0; if (canBeMin && canBeMax)//we have an roi, so we may need to loop before the double test hits a valid neighbor { for (; v < stencilSize; ++v) { VoxelIJK& offset = m_stencil[v]; int64_t testVox[3] = { i + offset.m_ijk[0], j + offset.m_ijk[1], k + offset.m_ijk[2] }; int64_t otherindex = toProcess->getIndex(testVox); if (roiFrame[otherindex] > 0.0f) { float otherval = dataFrame[otherindex]; if (myval < otherval) { minPos[otherindex] = 0; } else { canBeMin = false; } if (myval > otherval) { maxPos[otherindex] = 0; } else { canBeMax = false; } ++v;//don't test the same voxel again break;//we have eliminated one possibility, so we can move to a loop with fewer tests } else { if (abs(offset.m_ijk[0]) + abs(offset.m_ijk[1]) + abs(offset.m_ijk[2]) == 1) { canBeMax = false;//if we find a face neighbor outside the roi, don't count this as an extrema canBeMin = false; break; } } } } if (canBeMin) { for (; v < stencilSize; ++v) { VoxelIJK& offset = m_stencil[v]; int64_t testVox[3] = { i + offset.m_ijk[0], j + offset.m_ijk[1], k + offset.m_ijk[2] }; int64_t otherindex = toProcess->getIndex(testVox); if (roiFrame[otherindex] > 0.0f) { float otherval = dataFrame[otherindex]; if (myval < otherval) { minPos[otherindex] = 0; } else { canBeMin = false; break; } } else { if (abs(offset.m_ijk[0]) + abs(offset.m_ijk[1]) + abs(offset.m_ijk[2])) { canBeMin = false;//if we find a face neighbor outside the roi, don't count this as an extrema break; } } } } if (canBeMax) { for (; v < stencilSize; ++v) { VoxelIJK& offset = m_stencil[v]; int64_t testVox[3] = { i + offset.m_ijk[0], j + offset.m_ijk[1], k + offset.m_ijk[2] }; int64_t otherindex = toProcess->getIndex(testVox); if (roiFrame[otherindex] > 0.0f) { float otherval = dataFrame[otherindex]; if (myval > otherval) { maxPos[otherindex] = 0; } else { canBeMax = false; break; } } else { if (abs(offset.m_ijk[0]) + abs(offset.m_ijk[1]) + abs(offset.m_ijk[2]) == 1) { canBeMax = false;//if we find a face neighbor outside the roi, don't count this as an extrema break; } } } } if (canBeMin && canBeMax)//only way for this to happen is if there are no neighbors in the roi { canBeMax = false;//don't count isolated voxels as extrema canBeMin = false; } } } else {//if we are near an edge, we have to check all the neighbor indexes if (i < 1 || i >= myDims[0] - 1 || j < 1 || j >= myDims[1] - 1 || k < 1 || k >= myDims[2] - 1) { canBeMax = false;//but if we are on the edge of the volume, that is effectively the same as on the edge of the roi canBeMin = false;//so, don't count any extrema here } else { for (int v = 0; v < stencilSize; ++v) { VoxelIJK& offset = m_stencil[v]; int64_t testVox[3] = { i + offset.m_ijk[0], j + offset.m_ijk[1], k + offset.m_ijk[2] }; if (!ksafe && (testVox[2] < 0 || testVox[2] >= myDims[2])) continue; if (!jsafe && (testVox[1] < 0 || testVox[1] >= myDims[1])) continue; if (!isafe && (testVox[0] < 0 || testVox[0] >= myDims[0])) continue; int64_t otherindex = toProcess->getIndex(testVox); if (roiFrame != NULL && roiFrame[otherindex] <= 0.0f) { if (abs(offset.m_ijk[0]) + abs(offset.m_ijk[1]) + abs(offset.m_ijk[2]) == 1) { canBeMax = false; canBeMin = false; break; } else { continue; } } float otherval = dataFrame[otherindex]; if (myval < otherval)//since we are checking index bounds anyway, just do the double test to make the code simpler { minPos[otherindex] = 0; } else { canBeMin = false; if (!canBeMax) break; } if (myval > otherval) { maxPos[otherindex] = 0; } else { canBeMax = false; if (!canBeMin) break; } } } /*if (canBeMin && canBeMax)//this can't happen anymore { canBeMax = false;//don't count isolated voxels as extrema canBeMin = false; }//*/ } if (canBeMin) { #pragma omp critical { minima.push_back(VoxelIJK(i, j, k)); } } if (canBeMax) { #pragma omp critical { maxima.push_back(VoxelIJK(i, j, k)); } } } } } } } } void AlgorithmVolumeExtrema::findExtremaConsolidate(const VolumeFile* toProcess, const int& s, const int& c, const VolumeFile* myRoi, const float& distance, const bool& threshMode, const float& lowThresh, const float& highThresh, bool ignoreMinima, bool ignoreMaxima, vector& minima, vector& maxima) { const int stencil[18] = {-1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 1, 0, 1, 0, 1, 0, 0}; const int STENCIL_SIZE = 18; minima.clear(); maxima.clear(); vector myDims; toProcess->getDimensions(myDims); int64_t frameSize = myDims[0] * myDims[1] * myDims[2]; vector minPos(frameSize, 1), maxPos(frameSize, 1);//mark things off that fail a comparison, to reduce redundant comparisons const float* dataFrame = toProcess->getFrame(s, c); const float* roiFrame = NULL; vector > tempExtrema[2]; if (myRoi != NULL) { roiFrame = myRoi->getFrame(); } #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t k = 0; k < myDims[2]; ++k) { bool ksafe = (k > 0 && k < myDims[2] - 1);//so we can avoid performing certain bounds checks in the inner loop for (int64_t j = 0; j < myDims[1]; ++j) { bool jsafe = (j > 0 && j < myDims[1] - 1); for (int64_t i = 0; i < myDims[0]; ++i) { int64_t myindex = toProcess->getIndex(i, j, k); if (roiFrame == NULL || roiFrame[myindex] > 0.0f) { bool canBeMin = minPos[myindex] && !ignoreMinima; bool canBeMax = maxPos[myindex] && !ignoreMaxima; float myval = dataFrame[myindex]; if (threshMode) { if (myval > lowThresh) canBeMin = false;//check thresholds if (myval < highThresh) canBeMax = false; } if (canBeMin || canBeMax) { bool isafe = (i > 0 && i < myDims[0] - 1); if (isafe && jsafe && ksafe)//special case out the inner loops to avoid branching when possible { if (roiFrame == NULL) { int v = 0; if (canBeMin && canBeMax)//no ROI and safe means we can just use the first element in stencil to break the double test { int64_t testVox[3] = { i + stencil[0], j + stencil[1], k + stencil[2] }; int64_t otherindex = toProcess->getIndex(testVox); float otherval = dataFrame[otherindex]; if (myval < otherval) { minPos[otherindex] = 0; } else { canBeMin = false; } if (myval > otherval) { maxPos[otherindex] = 0; } else { canBeMax = false; } v = 3; } if (canBeMin) { for (; v < STENCIL_SIZE; v += 3) { int64_t testVox[3] = { i + stencil[v], j + stencil[v + 1], k + stencil[v + 2] }; int64_t otherindex = toProcess->getIndex(testVox); float otherval = dataFrame[otherindex]; if (myval < otherval) { minPos[otherindex] = 0; } else { canBeMin = false; break; } } } if (canBeMax) { for (; v < STENCIL_SIZE; v += 3) { int64_t testVox[3] = { i + stencil[v], j + stencil[v + 1], k + stencil[v + 2] }; int64_t otherindex = toProcess->getIndex(testVox); float otherval = dataFrame[otherindex]; if (myval > otherval) { maxPos[otherindex] = 0; } else { canBeMax = false; break; } } } } else { if (canBeMin && canBeMax)//we have an roi, but if a neighbor falls outside it, we are done anyway, we don't count extrema on the edge { int64_t testVox[3] = { i + stencil[0], j + stencil[1], k + stencil[2] }; int64_t otherindex = toProcess->getIndex(testVox); if (roiFrame[otherindex] > 0.0f) { float otherval = dataFrame[otherindex]; if (myval < otherval) { minPos[otherindex] = 0; } else { canBeMin = false; } if (myval > otherval) { maxPos[otherindex] = 0; } else { canBeMax = false; } } else { canBeMax = false;//we are next to an roi edge, do not count this as an extrema canBeMin = false; } } int v = 3; if (canBeMin) { for (; v < STENCIL_SIZE; v += 3) { int64_t testVox[3] = { i + stencil[v], j + stencil[v + 1], k + stencil[v + 2] }; int64_t otherindex = toProcess->getIndex(testVox); if (roiFrame[otherindex] > 0.0f) { float otherval = dataFrame[otherindex]; if (myval < otherval) { minPos[otherindex] = 0; } else { canBeMin = false; break; } } else { canBeMin = false;//we are next to an roi edge, do not count this as an extrema break; } } } if (canBeMax) { for (; v < STENCIL_SIZE; v += 3) { int64_t testVox[3] = { i + stencil[v], j + stencil[v + 1], k + stencil[v + 2] }; int64_t otherindex = toProcess->getIndex(testVox); if (roiFrame[otherindex] > 0.0f) { float otherval = dataFrame[otherindex]; if (myval > otherval) { maxPos[otherindex] = 0; } else { canBeMax = false; break; } } else { canBeMax = false;//we are next to an roi edge, do not count this as an extrema } } } /*if (canBeMin && canBeMax)//this can't happen anymore { canBeMax = false;//don't count isolated voxels as extrema canBeMin = false; }//*/ } } else {//if we are near an edge, we have to check all the neighbor indexes for (int v = 0; v < STENCIL_SIZE; v += 3) { int64_t testVox[3] = { i + stencil[v], j + stencil[v + 1], k + stencil[v + 2] }; if (!ksafe && (testVox[2] < 0 || testVox[2] >= myDims[2])) continue; if (!jsafe && (testVox[1] < 0 || testVox[1] >= myDims[1])) continue; if (!isafe && (testVox[0] < 0 || testVox[0] >= myDims[0])) continue; int64_t otherindex = toProcess->getIndex(testVox); if (roiFrame != NULL && roiFrame[otherindex] <= 0.0f) { canBeMax = false;//neighbor outside the roi means on the roi edge, don't count as extrema canBeMin = false; break; } float otherval = dataFrame[otherindex]; if (myval < otherval)//since we are checking index bounds anyway, just do the double test to make the code simpler { minPos[otherindex] = 0; } else { canBeMin = false; if (!canBeMax) break; } if (myval > otherval) { maxPos[otherindex] = 0; } else { canBeMax = false; if (!canBeMin) break; } } /*if (canBeMin && canBeMax)//this can't happen anymore { canBeMax = false;//don't count isolated voxels as extrema canBeMin = false; }//*/ } if (canBeMax) { Vector3D tempvec; toProcess->indexToSpace(i, j, k, tempvec); #pragma omp critical { tempExtrema[0].push_back(pair(tempvec, 1)); } } if (canBeMin) { Vector3D tempvec; toProcess->indexToSpace(i, j, k, tempvec); #pragma omp critical { tempExtrema[1].push_back(pair(tempvec, 1)); } } } } } } } consolidateStep(toProcess, distance, tempExtrema, minima, maxima); } void AlgorithmVolumeExtrema::consolidateStep(const VolumeFile* toProcess, const float& distance, vector > initExtrema[2], vector& minima, vector& maxima) { for (int sign = 0; sign < 2; ++sign) { int numInitExtrema = (int)initExtrema[sign].size(); vector removed(numInitExtrema, false);//track which extrema locations are dropped during consolidation - the one that isn't dropped in a merge has its node number changed vector > heapIDmatrix(numInitExtrema, vector(numInitExtrema, -1)); CaretMinHeap, float> myDistHeap; for (int i = 0; i < numInitExtrema - 1; ++i) { for (int j = i + 1; j < numInitExtrema; ++j) { float tempf = (initExtrema[sign][i].first - initExtrema[sign][j].first).length(); if (tempf < distance) { int64_t tempID = myDistHeap.push(pair(i, j), tempf); heapIDmatrix[i][j] = tempID; heapIDmatrix[j][i] = tempID; } } }//initial distance matrix computed, now we iterate while (!myDistHeap.isEmpty()) { pair toMerge = myDistHeap.pop();//we don't need to know the key int extr1 = toMerge.first; int extr2 = toMerge.second; heapIDmatrix[extr1][extr2] = -1; heapIDmatrix[extr2][extr1] = -1; int weight1 = initExtrema[sign][extr1].second; int weight2 = initExtrema[sign][extr2].second; if (weight2 > weight1)//swap so weight1 is always bigger { int temp = weight2; weight2 = weight1; weight1 = temp; temp = extr2; extr2 = extr1; extr1 = temp; } Vector3D point1 = initExtrema[sign][extr1].first; Vector3D point2 = initExtrema[sign][extr2].first; removed[extr2] = true;//drop the one that has less weight, and modify the one that has more weight for (int j = 0; j < numInitExtrema; ++j) { if (!removed[j]) { int64_t tempID = heapIDmatrix[extr2][j]; if (tempID != -1) { myDistHeap.remove(tempID); heapIDmatrix[extr2][j] = -1; heapIDmatrix[j][extr2] = -1; } } } Vector3D newPoint = (point1 * weight1 + point2 * weight2) / (weight1 + weight2); initExtrema[sign][extr1].first = newPoint; for (int j = 0; j < numInitExtrema; ++j) { if (!removed[j]) { float tempf = (newPoint - initExtrema[sign][j].first).length(); int64_t tempID = heapIDmatrix[extr1][j]; if (tempf < distance) { if (tempID != -1) { myDistHeap.changekey(tempID, tempf); } else { tempID = myDistHeap.push(pair(extr1, j), tempf); heapIDmatrix[extr1][j] = tempID; heapIDmatrix[j][extr1] = tempID; } } else { if (tempID != -1) { myDistHeap.remove(tempID); heapIDmatrix[extr1][j] = -1; heapIDmatrix[j][extr1] = -1; } } } } } if (sign == 0) { for (int i = 0; i < numInitExtrema; ++i) { if (!removed[i]) { VoxelIJK tempijk; toProcess->enclosingVoxel(initExtrema[sign][i].first, tempijk.m_ijk); maxima.push_back(tempijk); } } } else { for (int i = 0; i < numInitExtrema; ++i) { if (!removed[i]) { VoxelIJK tempijk; toProcess->enclosingVoxel(initExtrema[sign][i].first, tempijk.m_ijk); minima.push_back(tempijk); } } } } } float AlgorithmVolumeExtrema::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeExtrema::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeExtrema.h000066400000000000000000000066371360521144700253640ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_EXTREMA_H__ #define __ALGORITHM_VOLUME_EXTREMA_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "Vector3D.h" #include "VoxelIJK.h" #include namespace caret { class VolumeFile; class AlgorithmVolumeExtrema : public AbstractAlgorithm { std::vector m_stencil; int64_t m_irange, m_jrange, m_krange; AlgorithmVolumeExtrema(); void precomputeStencil(const VolumeFile* myVolIn, const float& distance); void findExtremaConsolidate(const VolumeFile* toProcess, const int& s, const int& c, const VolumeFile* myRoi, const float& distance, const bool& threshMode, const float& lowThresh, const float& highThresh, bool ignoreMinima, bool ignoreMaxima, std::vector& minima, std::vector& maxima); void findExtremaStencils(const VolumeFile* toProcess, const int& s, const int& c, const VolumeFile* myRoi, const bool& threshMode, const float& lowThresh, const float& highThresh, bool ignoreMinima, bool ignoreMaxima, std::vector& minima, std::vector& maxima); void consolidateStep(const VolumeFile* toProcess, const float& distance, std::vector > tempExtrema[2], std::vector& minima, std::vector& maxima); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeExtrema(ProgressObject* myProgObj, const VolumeFile* myVolIn, const float& distance, VolumeFile* myVolOut, const float& lowThresh, const float& highThresh, const VolumeFile* myRoi = NULL, const float& presmooth = -1.0f, const bool& sumSubvols = false, const bool& consolidateMode = false, bool ignoreMinima = false, bool ignoreMaxima = false, const int& subvol = -1); AlgorithmVolumeExtrema(ProgressObject* myProgObj, const VolumeFile* myVolIn, const float& distance, VolumeFile* myVolOut, const VolumeFile* myRoi = NULL, const float& presmooth = -1.0f, const bool& sumSubvols = false, const bool& consolidateMode = false, bool ignoreMinima = false, bool ignoreMaxima = false, const int& subvol = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeExtrema; } #endif //__ALGORITHM_VOLUME_EXTREMA_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeFillHoles.cxx000066400000000000000000000155401360521144700262040ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeFillHoles.h" #include "AlgorithmException.h" #include "VolumeFile.h" #include using namespace caret; using namespace std; AString AlgorithmVolumeFillHoles::getCommandSwitch() { return "-volume-fill-holes"; } AString AlgorithmVolumeFillHoles::getShortDescription() { return "FILL HOLES IN AN ROI VOLUME"; } OperationParameters* AlgorithmVolumeFillHoles::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume-in", "the input ROI volume"); ret->addVolumeOutputParameter(2, "volume-out", "the output ROI volume"); ret->setHelpText( AString("Finds all face-connected parts that are not included in the ROI, and fills all but the largest one with ones.") ); return ret; } void AlgorithmVolumeFillHoles::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* myVolIn = myParams->getVolume(1); VolumeFile* myVolOut = myParams->getOutputVolume(2); AlgorithmVolumeFillHoles(myProgObj, myVolIn, myVolOut); } AlgorithmVolumeFillHoles::AlgorithmVolumeFillHoles(ProgressObject* myProgObj, const VolumeFile* myVolIn, VolumeFile* myVolOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const int STENCIL_SIZE = 18;//the easy way, and prepare for different stencils if we ever need them const int stencil[STENCIL_SIZE] = { 0, 0, -1, 0, -1, 0, -1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 }; vector dims; myVolIn->getDimensions(dims); myVolOut->reinitialize(myVolIn->getOriginalDimensions(), myVolIn->getSform(), myVolIn->getNumberOfComponents(), myVolIn->getType(), myVolIn->m_header); for (int s = 0; s < dims[3]; ++s) { myVolOut->setMapName(s, myVolIn->getMapName(s)); for (int c = 0; c < dims[4]; ++c) { int64_t ijk[3]; vector > parts; vector used(dims[0] * dims[1] * dims[2], 0); const float* frame = myVolIn->getFrame(s, c); for (ijk[2] = 0; ijk[2] < dims[2]; ++ijk[2]) { for (ijk[1] = 0; ijk[1] < dims[1]; ++ijk[1]) { for (ijk[0] = 0; ijk[0] < dims[0]; ++ijk[0]) { int64_t index = myVolIn->getIndex(ijk); if (used[index] == 0 && !(frame[index] > 0.0f))//use "not greater than" in case someone uses NaNs in their ROI { parts.push_back(vector()); vector& thispart = parts.back(); thispart.push_back(ijk[0]); thispart.push_back(ijk[1]); thispart.push_back(ijk[2]); used[index] = 1; vector mystack; mystack.push_back(ijk[0]); mystack.push_back(ijk[1]); mystack.push_back(ijk[2]); while (!mystack.empty()) { int64_t curSize = (int64_t)mystack.size(); int64_t curvox[3] = { mystack[curSize - 3], mystack[curSize - 2], mystack[curSize - 1] }; mystack.resize(curSize - 3);//basically pop_back for (int i = 0; i < STENCIL_SIZE; i += 3) { int64_t neighbor[3] = { curvox[0] + stencil[i], curvox[1] + stencil[i + 1], curvox[2] + stencil[i + 2] }; if (myVolIn->indexValid(neighbor)) { int64_t neighindex = myVolIn->getIndex(neighbor); if (used[neighindex] == 0 && !(frame[neighindex] > 0.0f)) { thispart.push_back(neighbor[0]); thispart.push_back(neighbor[1]); thispart.push_back(neighbor[2]); used[neighindex] = 1; mystack.push_back(neighbor[0]); mystack.push_back(neighbor[1]); mystack.push_back(neighbor[2]); } } } } } } } } int64_t bestCount = -1, bestPart = -1, numParts = (int64_t)parts.size(); for (int64_t i = 0; i < numParts; ++i) { int64_t thisCount = (int64_t)parts[i].size(); if (thisCount > bestCount) { bestCount = thisCount; bestPart = i; } } vector outFrame(dims[0] * dims[1] * dims[2], 1.0f); if (bestPart != -1) { vector& myPart = parts[bestPart]; for (int64_t i = 0; i < bestCount; i += 3) { int64_t myIndex = myVolIn->getIndex(myPart.data() + i); outFrame[myIndex] = 0.0f;//make it a simple 0/1 volume, even if it wasn't before } } myVolOut->setFrame(outFrame.data(), s, c); } } } float AlgorithmVolumeFillHoles::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeFillHoles::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeFillHoles.h000066400000000000000000000032401360521144700256230ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_FILL_HOLES_H__ #define __ALGORITHM_VOLUME_FILL_HOLES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmVolumeFillHoles : public AbstractAlgorithm { AlgorithmVolumeFillHoles(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeFillHoles(ProgressObject* myProgObj, const VolumeFile* myVolIn, VolumeFile* myVolOut); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeFillHoles; } #endif //__ALGORITHM_VOLUME_FILL_HOLES_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeFindClusters.cxx000066400000000000000000000352421360521144700267310ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeFindClusters.h" #include "AlgorithmException.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPointer.h" #include "CaretPointLocator.h" #include "VolumeFile.h" #include "VoxelIJK.h" #include #include using namespace caret; using namespace std; AString AlgorithmVolumeFindClusters::getCommandSwitch() { return "-volume-find-clusters"; } AString AlgorithmVolumeFindClusters::getShortDescription() { return "FILTER CLUSTERS BY VOLUME"; } OperationParameters* AlgorithmVolumeFindClusters::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume-in", "the input volume"); ret->addDoubleParameter(2, "value-threshold", "threshold for data values"); ret->addDoubleParameter(3, "minimum-volume", "threshold for cluster volume, in mm^3"); ret->addVolumeOutputParameter(4, "volume-out", "the output volume"); ret->createOptionalParameter(5, "-less-than", "find values less than , rather than greater"); OptionalParameter* roiOption = ret->createOptionalParameter(6, "-roi", "select a region of interest"); roiOption->addMetricParameter(1, "roi-volume", "the roi, as a volume file"); OptionalParameter* subvolSelect = ret->createOptionalParameter(7, "-subvolume", "select a single subvolume"); subvolSelect->addStringParameter(1, "subvol", "the subvolume number or name"); OptionalParameter* sizeRatioOpt = ret->createOptionalParameter(9, "-size-ratio", "ignore clusters smaller than a given fraction of the largest cluster in map"); sizeRatioOpt->addDoubleParameter(1, "ratio", "fraction of the largest cluster's volume"); OptionalParameter* distanceOpt = ret->createOptionalParameter(10, "-distance", "ignore clusters further than a given distance from the largest cluster"); distanceOpt->addDoubleParameter(1, "distance", "how far from the largest cluster a cluster can be, edge to edge, in mm"); OptionalParameter* startOpt = ret->createOptionalParameter(8, "-start", "start labeling clusters from a value other than 1"); startOpt->addIntegerParameter(1, "startval", "the value to give the first cluster found"); ret->setHelpText( AString("Outputs a volume with nonzero integers for all voxels within a large enough cluster, and zeros elsewhere. ") + "The integers denote cluster membership (by default, first cluster found will use value 1, second cluster 2, etc). " + "Cluster values are not reused across frames of the output, but instead keep counting up. " + "By default, values greater than are considered to be in a cluster, use -less-than to test for values less than the threshold. " + "To apply this as a mask to the data, or to do more complicated thresholding, see -volume-math." ); return ret; } void AlgorithmVolumeFindClusters::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* volIn = myParams->getVolume(1); float threshValue = (float)myParams->getDouble(2); float minVolume = (float)myParams->getDouble(3); VolumeFile* volOut = myParams->getOutputVolume(4); bool lessThan = myParams->getOptionalParameter(5)->m_present; VolumeFile* myRoi = NULL; OptionalParameter* roiOption = myParams->getOptionalParameter(6); if (roiOption->m_present) { myRoi = roiOption->getVolume(1); } OptionalParameter* subvolSelect = myParams->getOptionalParameter(7); int subvolNum = -1; if (subvolSelect->m_present) { subvolNum = (int)volIn->getMapIndexFromNameOrNumber(subvolSelect->getString(1)); if (subvolNum < 0) { throw AlgorithmException("invalid subvolume specified"); } } OptionalParameter* startOpt = myParams->getOptionalParameter(8); int startVal = 1; if (startOpt->m_present) { startVal = (int)startOpt->getInteger(1); } OptionalParameter* sizeRatioOpt = myParams->getOptionalParameter(9); float sizeRatio = -1.0f; if (sizeRatioOpt->m_present) { sizeRatio = sizeRatioOpt->getDouble(1); if (sizeRatio <= 0.0f) { throw AlgorithmException("volume ratio must be positive"); } } OptionalParameter* distanceOpt = myParams->getOptionalParameter(10); float distaceCutoff = -1.0f; if (distanceOpt->m_present) { distaceCutoff = distanceOpt->getDouble(1); if (distaceCutoff <= 0.0f) { throw AlgorithmException("distance cutoff must be positive"); } } AlgorithmVolumeFindClusters(myProgObj, volIn, threshValue, minVolume, volOut, lessThan, myRoi, subvolNum, startVal, NULL, sizeRatio, distaceCutoff); } namespace { void processSubvol(const float* inFrame, VolumeFile* volOut, const int64_t& outSubvol, const int64_t& outComponent, const float& threshValue, const float& minVolume, const bool& lessThan, const float* roiFrame, const float& sizeRatio, const float& distanceCutoff, int& markVal) { vector dims = volOut->getDimensions(); int64_t frameSize = dims[0] * dims[1] * dims[2]; const VolumeSpace& mySpace = volOut->getVolumeSpace(); Vector3D ivec, jvec, kvec, origin; mySpace.getSpacingVectors(ivec, jvec, kvec, origin); float voxelVolume = abs(ivec.dot(jvec.cross(kvec))); int64_t minVoxels = (int64_t)ceil(minVolume / voxelVolume); vector neighbors; neighbors.push_back(VoxelIJK(1, 0, 0)); neighbors.push_back(VoxelIJK(-1, 0, 0)); neighbors.push_back(VoxelIJK(0, 1, 0)); neighbors.push_back(VoxelIJK(0, -1, 0)); neighbors.push_back(VoxelIJK(0, 0, 1)); neighbors.push_back(VoxelIJK(0, 0, -1)); vector marked(frameSize, 0); if (lessThan) { for (int64_t i = 0; i < frameSize; ++i) { if ((roiFrame == NULL || roiFrame[i] > 0.0f) && inFrame[i] < threshValue) { marked[i] = 1; } } } else { for (int64_t i = 0; i < frameSize; ++i) { if ((roiFrame == NULL || roiFrame[i] > 0.0f) && inFrame[i] > threshValue) { marked[i] = 1; } } } vector > clusters; size_t biggestCount = 0; int64_t biggestCluster = -1; for (int64_t k = 0; k < dims[2]; ++k) { for (int64_t j = 0; j < dims[1]; ++j) { for (int64_t i = 0; i < dims[0]; ++i) { int64_t myIndex = mySpace.getIndex(i, j, k); if (marked[myIndex]) { vector voxelList; voxelList.push_back(VoxelIJK(i, j, k)); marked[myIndex] = 0;//don't let voxels get duplicated in the list for (int64_t index = 0; index < (int64_t)voxelList.size(); ++index)//NOTE: vector grows inside loop { const VoxelIJK& thisVoxel = voxelList[index]; for (int n = 0; n < (int)neighbors.size(); ++n) { VoxelIJK neighVox(thisVoxel.m_ijk[0] + neighbors[n].m_ijk[0], thisVoxel.m_ijk[1] + neighbors[n].m_ijk[1], thisVoxel.m_ijk[2] + neighbors[n].m_ijk[2]); if (mySpace.indexValid(neighVox.m_ijk)) { int64_t neighIndex = mySpace.getIndex(neighVox.m_ijk); if (marked[neighIndex]) { voxelList.push_back(neighVox); marked[neighIndex] = 0; } } } } if ((int64_t)voxelList.size() >= minVoxels) { if (voxelList.size() > biggestCount) { biggestCount = voxelList.size(); biggestCluster = (int64_t)clusters.size(); } clusters.push_back(voxelList); } } } } } if (!clusters.empty()) CaretAssert(biggestCluster != -1); if (biggestCluster != -1 && (distanceCutoff > 0.0f || sizeRatio > 0.0f)) { CaretPointer myLocator; if (distanceCutoff > 0.0f) { vector biggestCoords;//gather coordinates of biggest cluster voxels biggestCoords.reserve(biggestCount * 3); for (size_t i = 0; i < clusters[biggestCluster].size(); ++i) { float thisCoord[3]; mySpace.indexToSpace(clusters[biggestCluster][i].m_ijk, thisCoord); biggestCoords.push_back(thisCoord[0]); biggestCoords.push_back(thisCoord[1]); biggestCoords.push_back(thisCoord[2]); } myLocator.grabNew(new CaretPointLocator(biggestCoords.data(), biggestCoords.size())); } for (size_t i = 0; i < clusters.size(); ++i) { if ((int64_t)i != biggestCluster) { bool erase = false; if (sizeRatio > 0.0f && ((float)clusters[i].size()) / biggestCount < sizeRatio) { erase = true; } if (!erase && distanceCutoff > 0.0f) { erase = true;//erase unless we find a point close enough to the biggest cluster for (size_t j = 0; j < clusters[i].size(); ++j) { float thisCoord[3]; mySpace.indexToSpace(clusters[i][j].m_ijk, thisCoord); int32_t ret = myLocator->closestPointLimited(thisCoord, distanceCutoff); if (ret == -1) { erase = false; break; } } } if (erase) { clusters.erase(clusters.begin() + i);//remove it --i;//don't skip a cluster if (biggestCluster > (int64_t)i) --biggestCluster;//don't lose track of the biggest cluster } } } } for (size_t i = 0; i < clusters.size(); ++i) { if (markVal == 0) { CaretLogInfo("skipping 0 for cluster marking"); ++markVal; } float tempVal = markVal; if ((int)tempVal != markVal) throw AlgorithmException("too many clusters, unable to mark them uniquely"); for (size_t index = 0; index < clusters[i].size(); ++index) { volOut->setValue(tempVal, clusters[i][index].m_ijk, outSubvol, outComponent); } ++markVal; } } } AlgorithmVolumeFindClusters::AlgorithmVolumeFindClusters(ProgressObject* myProgObj, const VolumeFile* volIn, const float& threshValue, const float& minVolume, VolumeFile* volOut, const bool& lessThan, const VolumeFile* myRoi, const int& subvolNum, const int& startVal, int* endVal, const float& sizeRatio, const float& distanceCutoff) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (startVal == 0) { throw AlgorithmException("0 is not a valid cluster marking start value"); } const VolumeSpace& mySpace = volIn->getVolumeSpace(); const float* roiFrame = NULL; if (myRoi != NULL) { if (!mySpace.matches(myRoi->getVolumeSpace())) throw AlgorithmException("roi volume space does not match input"); roiFrame = myRoi->getFrame(); } vector dims = volIn->getDimensions(); int markVal = startVal; if (subvolNum == -1) { volOut->reinitialize(volIn->getOriginalDimensions(), volIn->getSform(), dims[4], SubvolumeAttributes::ANATOMY, volIn->m_header); volOut->setValueAllVoxels(0.0f); for (int64_t c = 0; c < dims[4]; ++c) { for (int64_t s = 0; s < dims[3]; ++s) { const float* inFrame = volIn->getFrame(s, c); processSubvol(inFrame, volOut, s, c, threshValue, minVolume, lessThan, roiFrame, sizeRatio, distanceCutoff, markVal); } } } else { vector outDims = volIn->getOriginalDimensions(); outDims.resize(3); volOut->reinitialize(outDims, volIn->getSform(), dims[4], SubvolumeAttributes::ANATOMY, volIn->m_header); volOut->setValueAllVoxels(0.0f); for (int64_t c = 0; c < dims[4]; ++c) { const float* inFrame = volIn->getFrame(subvolNum, c); processSubvol(inFrame, volOut, 0, c, threshValue, minVolume, lessThan, roiFrame, sizeRatio, distanceCutoff, markVal); } } if (endVal != NULL) *endVal = markVal; } float AlgorithmVolumeFindClusters::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeFindClusters::getSubAlgorithmWeight() { return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeFindClusters.h000066400000000000000000000037711360521144700263600ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_FIND_CLUSTERS_H__ #define __ALGORITHM_VOLUME_FIND_CLUSTERS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmVolumeFindClusters : public AbstractAlgorithm { AlgorithmVolumeFindClusters(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeFindClusters(ProgressObject* myProgObj, const VolumeFile* volIn, const float& threshValue, const float& minVolume, VolumeFile* volOut, const bool& lessThan = false, const VolumeFile* myRoi = NULL, const int& subvolNum = -1, const int& startVal = 1, int* endVal = NULL, const float& sizeRatio = -1.0f, const float& distanceCutoff = -1.0f); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeFindClusters; } #endif //__ALGORITHM_VOLUME_FIND_CLUSTERS_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeGradient.cxx000066400000000000000000001166621360521144700260670ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmException.h" #include "AlgorithmVolumeGradient.h" #include "AlgorithmVolumeSmoothing.h" #include "CaretOMP.h" #include "FloatMatrix.h" #include "MathFunctions.h" #include "Vector3D.h" #include "VolumeFile.h" #include #include using namespace caret; using namespace std; AString AlgorithmVolumeGradient::getCommandSwitch() { return "-volume-gradient"; } AString AlgorithmVolumeGradient::getShortDescription() { return "GRADIENT OF A VOLUME FILE"; } OperationParameters* AlgorithmVolumeGradient::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume-in", "the input volume"); ret->addVolumeOutputParameter(2, "volume-out", "the output gradient magnitude volume"); OptionalParameter* presmoothOpt = ret->createOptionalParameter(3, "-presmooth", "smooth the volume before computing the gradient"); presmoothOpt->addDoubleParameter(1, "kernel", "sigma for gaussian weighting function, in mm"); OptionalParameter* roiOption = ret->createOptionalParameter(4, "-roi", "select a region of interest to take the gradient of"); roiOption->addVolumeParameter(1, "roi-volume", "the region to take the gradient within"); OptionalParameter* vecOption = ret->createOptionalParameter(5, "-vectors", "output vectors"); vecOption->addVolumeOutputParameter(1, "vector-volume-out", "the vectors as a volume file"); OptionalParameter* subvolSelect = ret->createOptionalParameter(6, "-subvolume", "select a single subvolume to take the gradient of"); subvolSelect->addStringParameter(1, "subvol", "the subvolume number or name"); ret->setHelpText( AString("Computes the gradient of the volume by doing linear regressions for each voxel, considering only its face neighbors unless too few face neighbors exist. ") + "The gradient vector is constructed from the partial derivatives of the resulting linear function, and the magnitude of this vector is the output. " + "If specified, the volume vector output is arranged with the x, y, and z components from a subvolume as consecutive subvolumes." ); return ret; } void AlgorithmVolumeGradient::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* volIn = myParams->getVolume(1); VolumeFile* volOut = myParams->getOutputVolume(2); float presmooth = -1.0f; OptionalParameter* presmoothOpt = myParams->getOptionalParameter(3); if (presmoothOpt->m_present) { presmooth = (float)presmoothOpt->getDouble(1); } VolumeFile* myRoi = NULL; OptionalParameter* roiOption = myParams->getOptionalParameter(4); if (roiOption->m_present) { myRoi = roiOption->getVolume(1); } VolumeFile* vectorsOut = NULL; OptionalParameter* vecOption = myParams->getOptionalParameter(5); if (vecOption->m_present) { vectorsOut = vecOption->getOutputVolume(1); } OptionalParameter* subvolSelect = myParams->getOptionalParameter(6); int subvolNum = -1; if (subvolSelect->m_present) { subvolNum = (int)volIn->getMapIndexFromNameOrNumber(subvolSelect->getString(1)); if (subvolNum < 0) { throw AlgorithmException("invalid subvolume specified"); } } AlgorithmVolumeGradient(myProgObj, volIn, volOut, presmooth, myRoi, vectorsOut, subvolNum); } AlgorithmVolumeGradient::AlgorithmVolumeGradient(ProgressObject* myProgObj, const VolumeFile* volIn, VolumeFile* volOut, const float& presmooth, const VolumeFile* myRoi, VolumeFile* vectorsOut, const int& subvolNum) : AbstractAlgorithm(myProgObj) { ProgressObject* smoothProgress = NULL; if (myProgObj != NULL && presmooth > 0.0f) { smoothProgress = myProgObj->addAlgorithm(AlgorithmVolumeSmoothing::getAlgorithmWeight()); } LevelProgress myProgress(myProgObj); if (myRoi != NULL && !volIn->matchesVolumeSpace(myRoi)) { throw AlgorithmException("roi volume space does not match input"); } if (subvolNum < -1 || subvolNum > volIn->getNumberOfMaps()) { throw AlgorithmException("invalid subvolume specified"); } VolumeFile smoothVol; const VolumeFile* processVol = volIn; int useSubvol = subvolNum; if (presmooth > 0.0f) { AlgorithmVolumeSmoothing(smoothProgress, volIn, presmooth, &smoothVol, myRoi, false, subvolNum); processVol = &smoothVol; if (subvolNum != -1) { useSubvol = 0; } } vector origDims = volIn->getOriginalDimensions(), myDims; volIn->getDimensions(myDims); int stencil[] = { 0, 0, 1, 0, 0, -1, 0, 1, 0, 0, -1, 0, 1, 0, 0, -1, 0, 0 }; vector > volSpace = volIn->getSform(); Vector3D ivec, jvec, kvec, origin; ivec[0] = volSpace[0][0]; jvec[0] = volSpace[0][1]; kvec[0] = volSpace[0][2]; origin[0] = volSpace[0][3]; ivec[1] = volSpace[1][0]; jvec[1] = volSpace[1][1]; kvec[1] = volSpace[1][2]; origin[1] = volSpace[1][3]; ivec[2] = volSpace[2][0]; jvec[2] = volSpace[2][1]; kvec[2] = volSpace[2][2]; origin[2] = volSpace[2][3];//TODO: special case orthogonal volumes (central difference)? const float* roiFrame = NULL; if (myRoi != NULL) { roiFrame = myRoi->getFrame(); } if (subvolNum == -1) { volOut->reinitialize(origDims, volIn->getSform(), myDims[4], volIn->getType(), volIn->m_header); if (vectorsOut != NULL) { while (origDims.size() < 4) { origDims.push_back(1); } origDims[3] *= 3; vectorsOut->reinitialize(origDims, volIn->getSform(), myDims[4], volIn->getType()); } for (int c = 0; c < myDims[4]; ++c) { for (int s = 0; s < myDims[3]; ++s) { const float* inFrame = processVol->getFrame(s, c); #pragma omp CARET_PARFOR schedule(dynamic) for (int k = 0; k < myDims[2]; ++k) { for (int j = 0; j < myDims[1]; ++j) { for (int i = 0; i < myDims[0]; ++i) { float magnitude; Vector3D gradient; if (myRoi == NULL || myRoi->getValue(i, j, k) > 0.0f) { float curval = processVol->getValue(i, j, k, s, c); FloatMatrix regress = FloatMatrix::zeros(4, 5); regress[3][3] = 1;//count the center voxel in case neighbors are missing (displacement and valdiff are zero, cancelling all other terms) int dircheck = 0; for (int neighbase = 0; neighbase < 18; neighbase += 3) { int ikern = i + stencil[neighbase]; int jkern = j + stencil[neighbase + 1]; int kkern = k + stencil[neighbase + 2]; if (volIn->indexValid(ikern, jkern, kkern)) { int64_t kernIndex = volIn->getIndex(ikern, jkern, kkern); if (roiFrame == NULL || roiFrame[kernIndex] > 0.0f) { dircheck |= 1<<(neighbase / 6);//uses the ordering of the neighbors to map neighbor to direction float valdiff = inFrame[kernIndex] - curval; Vector3D displacement = ivec * stencil[neighbase] + jvec * stencil[neighbase + 1] + kvec * stencil[neighbase + 2]; regress[0][0] += displacement[0] * displacement[0];//note: this is the generic code, built to handle strange volumes, to get more speed, test regress[0][1] += displacement[0] * displacement[1];// for orthogonal volume, and use central differences (if no ROI, could special case for even more speed) regress[0][2] += displacement[0] * displacement[2];//but, seems reasonably fast anyway regress[0][3] += displacement[0]; regress[0][4] += displacement[0] * valdiff; regress[1][1] += displacement[1] * displacement[1]; regress[1][2] += displacement[1] * displacement[2]; regress[1][3] += displacement[1]; regress[1][4] += displacement[1] * valdiff; regress[2][2] += displacement[2] * displacement[2]; regress[2][3] += displacement[2]; regress[2][4] += displacement[2] * valdiff; regress[3][3] += 1; regress[3][4] += valdiff; } } } if (dircheck == 7)//have at least one neighbor in every index axis, continue { regress[1][0] = regress[0][1];//finish the symmetric part of the matrix regress[2][0] = regress[0][2]; regress[2][1] = regress[1][2]; regress[3][0] = regress[0][3]; regress[3][1] = regress[1][3]; regress[3][2] = regress[2][3]; FloatMatrix result = regress.reducedRowEchelon(); gradient[0] = result[0][4]; gradient[1] = result[1][4]; gradient[2] = result[2][4];//[3][4] is the constant part of the regression magnitude = gradient.length(); if (!MathFunctions::isNumeric(magnitude)) { magnitude = 0.0f; gradient[0] = 0.0f; gradient[1] = 0.0f; gradient[2] = 0.0f; } } else {//fallback 1: regression with 26-neighbors Vector3D directions[3];//track the displacements in index space for simplicity int dirUsed = 0; if (dircheck & 1) { directions[dirUsed][0] = 1; ++dirUsed; } if (dircheck & 2) { directions[dirUsed][1] = 1; ++dirUsed; } if (dircheck & 4) { directions[dirUsed][2] = 1; ++dirUsed; } int imin = max(i - 1, 0), jmin = max(j - 1, 0), kmin = max(k - 1, 0); int imax = min(i + 2, (int)myDims[0]), jmax = min(j + 2, (int)myDims[1]), kmax = min(k + 2, (int)myDims[2]); Vector3D voxelDir; for (int kkern = kmin; kkern < kmax; ++kkern) { voxelDir[2] = kkern - k; int kabs = abs(kkern - k); int64_t kindpart = kkern * myDims[1]; for (int jkern = jmin; jkern < jmax; ++jkern) { int jabs = abs(jkern - j) + kabs; if (jabs > 0)//skip inner loop if it won't get any new neighbors { int64_t jindpart = (kindpart + jkern) * myDims[0]; voxelDir[1] = jkern - j; for (int ikern = imin; ikern < imax; ++ikern) { int64_t kernIndex = jindpart + ikern; if (jabs + abs(ikern - i) > 1 && (roiFrame == NULL || roiFrame[kernIndex] > 0.0f))//only add non-face neighbors { if (dirUsed < 3)//check for singularity via base vectors being dependent { bool newDir = true; switch (dirUsed) { case 0: default: break; case 1: if (voxelDir.cross(directions[0]).length() < 0.01f) newDir = false; break; case 2: if (voxelDir.cross(directions[0]).cross(voxelDir.cross(directions[1])).length() < 0.01f) newDir = false; break; } if (newDir) { directions[dirUsed] = voxelDir; ++dirUsed; } } voxelDir[0] = ikern - i; Vector3D displacement = ivec * voxelDir[0] + jvec * voxelDir[1] + kvec * voxelDir[2]; float valdiff = inFrame[kernIndex] - curval; regress[0][0] += displacement[0] * displacement[0]; regress[0][1] += displacement[0] * displacement[1]; regress[0][2] += displacement[0] * displacement[2]; regress[0][3] += displacement[0]; regress[0][4] += displacement[0] * valdiff; regress[1][1] += displacement[1] * displacement[1]; regress[1][2] += displacement[1] * displacement[2]; regress[1][3] += displacement[1]; regress[1][4] += displacement[1] * valdiff; regress[2][2] += displacement[2] * displacement[2]; regress[2][3] += displacement[2]; regress[2][4] += displacement[2] * valdiff; regress[3][3] += 1; regress[3][4] += valdiff; } } } } } if (dirUsed == 3) { regress[1][0] = regress[0][1];//finish the symmetric part of the matrix regress[2][0] = regress[0][2]; regress[2][1] = regress[1][2]; regress[3][0] = regress[0][3]; regress[3][1] = regress[1][3]; regress[3][2] = regress[2][3]; FloatMatrix result = regress.reducedRowEchelon(); gradient[0] = result[0][4]; gradient[1] = result[1][4]; gradient[2] = result[2][4];//[3][4] is the constant part of the regression magnitude = gradient.length(); if (!MathFunctions::isNumeric(magnitude)) { magnitude = 0.0f; gradient[0] = 0.0f; gradient[1] = 0.0f; gradient[2] = 0.0f; } } else {//fallback 2: average forward differences in 26-neighborhood Vector3D accum; int accumCount = 0; for (int kkern = kmin; kkern < kmax; ++kkern) { voxelDir[2] = kkern - k; int64_t kindpart = kkern * myDims[1]; for (int jkern = jmin; jkern < jmax; ++jkern) { int64_t jindpart = (kindpart + jkern) * myDims[0]; voxelDir[1] = jkern - j; for (int ikern = imin; ikern < imax; ++ikern) { int64_t kernIndex = jindpart + ikern; if (roiFrame == NULL || roiFrame[kernIndex] > 0.0f) { float valdiff = inFrame[kernIndex] - curval; voxelDir[0] = ikern - i; Vector3D displacement = ivec * voxelDir[0] + jvec * voxelDir[1] + kvec * voxelDir[2]; float length = displacement.length(); if (length > 0.0f) { accum += displacement * (valdiff / (length * length));//once to normalize vector, and once to find gradient magnitude ++accumCount; } } } } } if (accumCount > 0) { gradient = accum / accumCount; magnitude = gradient.length(); if (!MathFunctions::isNumeric(magnitude)) { magnitude = 0.0f; gradient[0] = 0.0f; gradient[1] = 0.0f; gradient[2] = 0.0f; } } else { magnitude = 0.0f; gradient[0] = 0.0f; gradient[1] = 0.0f; gradient[2] = 0.0f; } } } } else { magnitude = 0.0f; gradient[0] = 0.0f; gradient[1] = 0.0f; gradient[2] = 0.0f; } volOut->setValue(magnitude, i, j, k, s, c); if (vectorsOut != NULL) { int subvolbase = s * 3; vectorsOut->setValue(gradient[0], i, j, k, subvolbase, c); vectorsOut->setValue(gradient[1], i, j, k, subvolbase + 1, c); vectorsOut->setValue(gradient[2], i, j, k, subvolbase + 2, c); } } } } } } } else { origDims.resize(3); volOut->reinitialize(origDims, volIn->getSform(), myDims[4], volIn->getType(), volIn->m_header); if (vectorsOut != NULL) { origDims.push_back(3); vectorsOut->reinitialize(origDims, volIn->getSform(), myDims[4], volIn->getType()); } for (int c = 0; c < myDims[4]; ++c) { const float* inFrame = processVol->getFrame(useSubvol, c); #pragma omp CARET_PARFOR schedule(dynamic) for (int k = 0; k < myDims[2]; ++k) { for (int j = 0; j < myDims[1]; ++j) { for (int i = 0; i < myDims[0]; ++i) { float magnitude; Vector3D gradient; if (myRoi == NULL || myRoi->getValue(i, j, k) > 0.0f) { float curval = processVol->getValue(i, j, k, useSubvol, c); FloatMatrix regress = FloatMatrix::zeros(4, 5); regress[3][3] = 1;//count the center voxel in case neighbors are missing (displacement and valdiff are zero, cancelling all other terms) int dircheck = 0; for (int neighbase = 0; neighbase < 18; neighbase += 3) { int ikern = i + stencil[neighbase]; int jkern = j + stencil[neighbase + 1]; int kkern = k + stencil[neighbase + 2]; if (volIn->indexValid(ikern, jkern, kkern)) { int64_t kernIndex = volIn->getIndex(ikern, jkern, kkern); if (roiFrame == NULL || roiFrame[kernIndex] > 0.0f) { dircheck |= 1<<(neighbase / 6);//uses the ordering of the neighbors to map neighbor to direction float valdiff = inFrame[kernIndex] - curval; Vector3D displacement = ivec * stencil[neighbase] + jvec * stencil[neighbase + 1] + kvec * stencil[neighbase + 2]; regress[0][0] += displacement[0] * displacement[0];//note: this is the generic code, built to handle strange volumes, to get more speed, test regress[0][1] += displacement[0] * displacement[1];// for orthogonal volume, and use central differences (if no ROI, could special case for even more speed) regress[0][2] += displacement[0] * displacement[2]; regress[0][3] += displacement[0]; regress[0][4] += displacement[0] * valdiff; regress[1][1] += displacement[1] * displacement[1]; regress[1][2] += displacement[1] * displacement[2]; regress[1][3] += displacement[1]; regress[1][4] += displacement[1] * valdiff; regress[2][2] += displacement[2] * displacement[2]; regress[2][3] += displacement[2]; regress[2][4] += displacement[2] * valdiff; regress[3][3] += 1; regress[3][4] += valdiff; } } } if (dircheck == 7)//have at least one neighbor in every index axis, continue { regress[1][0] = regress[0][1];//finish the symmetric part of the matrix regress[2][0] = regress[0][2]; regress[2][1] = regress[1][2]; regress[3][0] = regress[0][3]; regress[3][1] = regress[1][3]; regress[3][2] = regress[2][3]; FloatMatrix result = regress.reducedRowEchelon(); gradient[0] = result[0][4]; gradient[1] = result[1][4]; gradient[2] = result[2][4];//[3][4] is the constant part of the regression magnitude = gradient.length(); if (!MathFunctions::isNumeric(magnitude)) { magnitude = 0.0f; gradient[0] = 0.0f; gradient[1] = 0.0f; gradient[2] = 0.0f; } } else {//fallback 1: regression with 26-neighbors Vector3D directions[3];//track the displacements in index space for simplicity int dirUsed = 0; if (dircheck & 1) { directions[dirUsed][0] = 1; ++dirUsed; } if (dircheck & 2) { directions[dirUsed][1] = 1; ++dirUsed; } if (dircheck & 4) { directions[dirUsed][2] = 1; ++dirUsed; } int imin = max(i - 1, 0), jmin = max(j - 1, 0), kmin = max(k - 1, 0); int imax = min(i + 2, (int)myDims[0]), jmax = min(j + 2, (int)myDims[1]), kmax = min(k + 2, (int)myDims[2]); Vector3D voxelDir; for (int kkern = kmin; kkern < kmax; ++kkern) { voxelDir[2] = kkern - k; int kabs = abs(kkern - k); int64_t kindpart = kkern * myDims[1]; for (int jkern = jmin; jkern < jmax; ++jkern) { int jabs = abs(jkern - j) + kabs; if (jabs > 0)//skip inner loop if it won't get any new neighbors { int64_t jindpart = (kindpart + jkern) * myDims[0]; voxelDir[1] = jkern - j; for (int ikern = imin; ikern < imax; ++ikern) { int64_t kernIndex = jindpart + ikern; if (jabs + abs(ikern - i) > 1 && (roiFrame == NULL || roiFrame[kernIndex] > 0.0f))//only add non-face neighbors { if (dirUsed < 3)//check for singularity via base vectors being dependent { bool newDir = true; switch (dirUsed) { case 0: default: break; case 1: if (voxelDir.cross(directions[0]).length() < 0.01f) newDir = false; break; case 2: if (voxelDir.cross(directions[0]).cross(voxelDir.cross(directions[1])).length() < 0.01f) newDir = false; break; } if (newDir) { directions[dirUsed] = voxelDir; ++dirUsed; } } voxelDir[0] = ikern - i; Vector3D displacement = ivec * voxelDir[0] + jvec * voxelDir[1] + kvec * voxelDir[2]; float valdiff = inFrame[kernIndex] - curval; regress[0][0] += displacement[0] * displacement[0]; regress[0][1] += displacement[0] * displacement[1]; regress[0][2] += displacement[0] * displacement[2]; regress[0][3] += displacement[0]; regress[0][4] += displacement[0] * valdiff; regress[1][1] += displacement[1] * displacement[1]; regress[1][2] += displacement[1] * displacement[2]; regress[1][3] += displacement[1]; regress[1][4] += displacement[1] * valdiff; regress[2][2] += displacement[2] * displacement[2]; regress[2][3] += displacement[2]; regress[2][4] += displacement[2] * valdiff; regress[3][3] += 1; regress[3][4] += valdiff; } } } } } if (dirUsed == 3) { regress[1][0] = regress[0][1];//finish the symmetric part of the matrix regress[2][0] = regress[0][2]; regress[2][1] = regress[1][2]; regress[3][0] = regress[0][3]; regress[3][1] = regress[1][3]; regress[3][2] = regress[2][3]; FloatMatrix result = regress.reducedRowEchelon(); gradient[0] = result[0][4]; gradient[1] = result[1][4]; gradient[2] = result[2][4];//[3][4] is the constant part of the regression magnitude = gradient.length(); if (!MathFunctions::isNumeric(magnitude)) { magnitude = 0.0f; gradient[0] = 0.0f; gradient[1] = 0.0f; gradient[2] = 0.0f; } } else {//fallback 2: average forward differences in 26-neighborhood Vector3D accum; int accumCount = 0; for (int kkern = kmin; kkern < kmax; ++kkern) { voxelDir[2] = kkern - k; int64_t kindpart = kkern * myDims[1]; for (int jkern = jmin; jkern < jmax; ++jkern) { int64_t jindpart = (kindpart + jkern) * myDims[0]; voxelDir[1] = jkern - j; for (int ikern = imin; ikern < imax; ++ikern) { int64_t kernIndex = jindpart + ikern; if (roiFrame == NULL || roiFrame[kernIndex] > 0.0f) { float valdiff = inFrame[kernIndex] - curval; voxelDir[0] = ikern - i; Vector3D displacement = ivec * voxelDir[0] + jvec * voxelDir[1] + kvec * voxelDir[2]; float length = displacement.length(); if (length > 0.0f) { accum += displacement * (valdiff / (length * length));//once to normalize vector, and once to find gradient magnitude ++accumCount; } } } } } if (accumCount > 0) { gradient = accum / accumCount; magnitude = gradient.length(); if (!MathFunctions::isNumeric(magnitude)) { magnitude = 0.0f; gradient[0] = 0.0f; gradient[1] = 0.0f; gradient[2] = 0.0f; } } else { magnitude = 0.0f; gradient[0] = 0.0f; gradient[1] = 0.0f; gradient[2] = 0.0f; } } } } else { magnitude = 0.0f; gradient[0] = 0.0f; gradient[1] = 0.0f; gradient[2] = 0.0f; } volOut->setValue(magnitude, i, j, k, 0, c); if (vectorsOut != NULL) { vectorsOut->setValue(gradient[0], i, j, k, 0, c); vectorsOut->setValue(gradient[1], i, j, k, 1, c); vectorsOut->setValue(gradient[2], i, j, k, 2, c); } } } } } } } float AlgorithmVolumeGradient::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeGradient::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeGradient.h000066400000000000000000000034571360521144700255110ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_GRADIENT_H__ #define __ALGORITHM_VOLUME_GRADIENT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmVolumeGradient : public AbstractAlgorithm { AlgorithmVolumeGradient(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeGradient(ProgressObject* myProgObj, const VolumeFile* volIn, VolumeFile* volOut, const float& presmooth = -1.0f, const VolumeFile* myRoi = NULL, VolumeFile* vectorsOut = NULL, const int& subvolNum = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeGradient; } #endif //__ALGORITHM_VOLUME_GRADIENT_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeLabelModifyKeys.cxx000066400000000000000000000250111360521144700273400ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeLabelModifyKeys.h" #include "AlgorithmException.h" #include "FileInformation.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "VolumeFile.h" #include #include #include using namespace caret; using namespace std; AString AlgorithmVolumeLabelModifyKeys::getCommandSwitch() { return "-volume-label-modify-keys"; } AString AlgorithmVolumeLabelModifyKeys::getShortDescription() { return "CHANGE KEY VALUES IN A VOLUME LABEL FILE"; } OperationParameters* AlgorithmVolumeLabelModifyKeys::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume-in", "the input volume label file"); ret->addStringParameter(2, "remap-file", "text file with old and new key values"); ret->addVolumeOutputParameter(3, "volume-out", "the output volume label file"); OptionalParameter* subvolOpt = ret->createOptionalParameter(4, "-subvolume", "select a single subvolume"); subvolOpt->addStringParameter(1, "subvolume", "the subvolume number or name"); ret->setHelpText( AString(" should have lines of the form 'oldkey newkey', like so:\n\n") + "3 5\n5 8\n8 2\n\n" + "This would change the current label with key '3' to use the key '5' instead, 5 would use 8, and 8 would use 2. " + "Any collision in key values results in the label that was not specified in the remap file getting remapped to an otherwise unused key. " + "Remapping more than one key to the same new key, or the same key to more than one new key, results in an error. " + "This will not change the appearance of the file when displayed, as it will change the key values in the data at the same time." ); return ret; } void AlgorithmVolumeLabelModifyKeys::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* volIn = myParams->getVolume(1); AString remapName = myParams->getString(2); VolumeFile* volOut = myParams->getOutputVolume(3); OptionalParameter* subvolOpt = myParams->getOptionalParameter(4); int subvol = -1; if (subvolOpt->m_present) {//set up to use a single column subvol = volIn->getMapIndexFromNameOrNumber(subvolOpt->getString(1)); if (subvol < 0) throw AlgorithmException("invalid column specified"); } FileInformation textFileInfo(remapName); if (!textFileInfo.exists()) { throw AlgorithmException("label list file doesn't exist"); } fstream remapFile(remapName.toLocal8Bit().constData(), fstream::in); if (!remapFile.good()) { throw AlgorithmException("error reading label list file"); } map remap; int32_t oldkey, newkey; while (remapFile >> oldkey >> newkey) { if (remap.find(oldkey) != remap.end()) throw AlgorithmException("remapping tried to duplicate label " + AString::number(oldkey)); remap[oldkey] = newkey; } AlgorithmVolumeLabelModifyKeys(myProgObj, volIn, remap, volOut, subvol); } AlgorithmVolumeLabelModifyKeys::AlgorithmVolumeLabelModifyKeys(ProgressObject* myProgObj, const VolumeFile* volIn, const map remap, VolumeFile* volOut, const int subvol) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (volIn->getType() != SubvolumeAttributes::LABEL) { throw AlgorithmException("input volume must be a label volume"); } vector indims = volIn->getDimensions(); vector outdims = volIn->getOriginalDimensions(); if (indims[4] != 1) { throw AlgorithmException("multiple components are not allowed in label volumes"); } int64_t startVol = 0, endVol = indims[3]; if (subvol > -1) { startVol = subvol; endVol = subvol + 1; indims.resize(3); } volOut->reinitialize(outdims, volIn->getSform(), 1, SubvolumeAttributes::LABEL); vector scratchFrame(outdims[0] * outdims[1] * outdims[2]); for (int64_t s = startVol; s < endVol; ++s) { volOut->setMapName(s - startVol, volIn->getMapName(s)); const GiftiLabelTable* oldTable = volIn->getMapLabelTable(s); int32_t oldUnlabeled = oldTable->getUnassignedLabelKey();//because GiftiLabelTable is quirky, we need to check if the unlabeled value ends up as something other than 0 GiftiLabelTable newTable;//careful, label 0 is created by the constructor bool setZero = false;//because of this, we need to track if we overwrote it, so that we can pretend it isn't there for (map::const_iterator iter = remap.begin(); iter != remap.end(); ++iter) { const GiftiLabel* oldLabel = oldTable->getLabel(iter->first); if (oldLabel == NULL) throw AlgorithmException("label key " + AString::number(iter->first) + " does not exist in the input file"); GiftiLabel newLabel(*oldLabel); newLabel.setKey(iter->second); if (iter->first == oldUnlabeled) { if (iter->second != 0)//if it isn't the default unlabeled value, then we have to do something { if (newTable.getLabel(iter->second) != NULL) throw AlgorithmException("remapping tried to set label " + AString::number(iter->second) + " more than once"); newTable.deleteLabel(0);//delete the default, since we don't know what overwrites it, if anything newTable.insertLabel(&newLabel);//insert forces it to use the key in the label, even if it causes a duplicate name (which the original might theoretically have) } else {//otherwise, just error checking if (setZero) throw AlgorithmException("remapping tried to set label " + AString::number(iter->second) + " more than once"); setZero = true;//we do have to track that zero now contains something that can't be overwritten } } else { if (iter->second == 0)//if it remaps to the default unlabeled key, we have to check it differently { if (setZero) throw AlgorithmException("remapping tried to set label " + AString::number(iter->second) + " more than once"); setZero = true; newTable.insertLabel(&newLabel);//insert forces it to use the key in the label, so it will overwrite the existing default 0 key } else {//finally, the simple case if (newTable.getLabel(iter->second) != NULL) throw AlgorithmException("remapping tried to set label " + AString::number(iter->second) + " more than once"); newTable.insertLabel(&newLabel);//insert forces it to use the key in the label, even if it causes a duplicate name (which the original might theoretically have) } } } set keys = oldTable->getKeys(), collisions; for (set::const_iterator iter = keys.begin(); iter != keys.end(); ++iter) { if (remap.find(*iter) == remap.end())//skip if it was remapped { if (*iter == 0)//again with the special default 0 key { if (setZero)//check for collision { collisions.insert(*iter); } else { setZero = true; if (*iter != oldUnlabeled)//if its merely the unassigned label already, we can just keep the existing default { newTable.insertLabel(oldTable->getLabel(*iter)); } } } else { if (newTable.getLabel(*iter) == NULL) { newTable.insertLabel(oldTable->getLabel(*iter)); } else {//collision collisions.insert(*iter); } } } } map valueChanges = remap;//start with the specified changes, then add the collision changes for (set::const_iterator iter = collisions.begin(); iter != collisions.end(); ++iter) {//now deal with collisions int32_t newKey = newTable.generateUnusedKey(); GiftiLabel newLabel(*(oldTable->getLabel(*iter))); newLabel.setKey(newKey); newTable.insertLabel(&newLabel);//insert forces it to use the key in the label, even if it causes a duplicate name (which the original might theoretically have) valueChanges[*iter] = newKey; } *(volOut->getMapLabelTable(s - startVol)) = newTable; const float* inframe = volIn->getFrame(s); for (int64_t k = 0; k < indims[2]; ++k) { for (int64_t j = 0; j < indims[1]; ++j) { for (int64_t i = 0; i < indims[0]; ++i) { int64_t index = volIn->getIndex(i, j, k); int32_t oldkey = int32_t(floor(inframe[index] + 0.5)); auto iter = valueChanges.find(oldkey); if (iter == valueChanges.end()) { scratchFrame[index] = oldkey; } else { scratchFrame[index] = iter->second; } } } } volOut->setFrame(scratchFrame.data(), s - startVol); } } float AlgorithmVolumeLabelModifyKeys::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeLabelModifyKeys::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeLabelModifyKeys.h000066400000000000000000000034361360521144700267740ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_LABEL_MODIFY_KEYS_H__ #define __ALGORITHM_VOLUME_LABEL_MODIFY_KEYS_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include namespace caret { class AlgorithmVolumeLabelModifyKeys : public AbstractAlgorithm { AlgorithmVolumeLabelModifyKeys(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeLabelModifyKeys(ProgressObject* myProgObj, const VolumeFile* volIn, const std::map remap, VolumeFile* volOut, const int subvol = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeLabelModifyKeys; } #endif //__ALGORITHM_VOLUME_LABEL_MODIFY_KEYS_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeLabelProbability.cxx000066400000000000000000000145141360521144700275430ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeLabelProbability.h" #include "AlgorithmException.h" #include "GiftiLabelTable.h" #include "VolumeFile.h" #include #include #include using namespace caret; using namespace std; AString AlgorithmVolumeLabelProbability::getCommandSwitch() { return "-volume-label-probability"; } AString AlgorithmVolumeLabelProbability::getShortDescription() { return "FIND FREQUENCY OF VOLUME LABELS"; } OperationParameters* AlgorithmVolumeLabelProbability::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "label-maps", "volume label file containing individual label maps from many subjects"); ret->addVolumeOutputParameter(2, "probability-out", "the relative frequencies of each label at each voxel"); ret->createOptionalParameter(3, "-exclude-unlabeled", "don't make a probability map of the unlabeled key"); ret->setHelpText( AString("This command outputs a set of soft ROIs, one for each label in the input, ") + "where the value is how many of the input maps had that label at that voxel, divided by the number of input maps." ); return ret; } void AlgorithmVolumeLabelProbability::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { const VolumeFile* inputVol = myParams->getVolume(1); VolumeFile* outputVol = myParams->getOutputVolume(2); bool excludeUnlabeled = myParams->getOptionalParameter(3)->m_present; AlgorithmVolumeLabelProbability(myProgObj, inputVol, outputVol, excludeUnlabeled); } AlgorithmVolumeLabelProbability::AlgorithmVolumeLabelProbability(ProgressObject* myProgObj, const VolumeFile* inputVol, VolumeFile* outputVol, const bool& excludeUnlabeled) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (inputVol->getType() != SubvolumeAttributes::LABEL) throw AlgorithmException("input volume must be a label volume"); if (inputVol->getNumberOfComponents() != 1) throw AlgorithmException("label volumes must not have multiple components per map"); int numInMaps = inputVol->getNumberOfMaps(); vector > outMapToKeyLookup(numInMaps);//we match labels by name, not by key - the lookup is this direction so we can compute one output frame at a time map nameToOutMap;//yes, that involves a lot of rescanning memory, but it takes half the additional memory as one pass (because VolumeFile has internal memory) for (int i = 0; i < numInMaps; ++i)//testing shows it doesn't take that much longer anyway, for smallish frame sizes at least { const GiftiLabelTable* thisTable = inputVol->getMapLabelTable(i); set thisKeys = thisTable->getKeys(); int32_t unlabeledKey = -1;//don't request it from the table if we aren't going to skip it, because requesting it can add it to the table if (excludeUnlabeled) { unlabeledKey = thisTable->getUnassignedLabelKey(); } for (set::iterator iter = thisKeys.begin(); iter != thisKeys.end(); ++iter)//order by key value { if (excludeUnlabeled && *iter == unlabeledKey) continue;//skip to next key const AString thisName = thisTable->getLabelName(*iter); map::iterator search = nameToOutMap.find(thisName); int outMap = -1; if (search == nameToOutMap.end()) { outMap = nameToOutMap.size();//sequential integers starting from 0 nameToOutMap[thisName] = outMap; } else { outMap = search->second; } outMapToKeyLookup[i][outMap] = *iter; } } const vector inDims = inputVol->getDimensions(); vector outDims = inDims; outDims.resize(4); int64_t numOutMaps = (int64_t)nameToOutMap.size(); outDims[3] = numOutMaps; outputVol->reinitialize(outDims, inputVol->getSform()); for (map::iterator iter = nameToOutMap.begin(); iter != nameToOutMap.end(); ++iter) { outputVol->setMapName(iter->second, iter->first); } int64_t frameSize = inDims[0] * inDims[1] * inDims[2]; for (int outMap = 0; outMap < numOutMaps; ++outMap) { vector scratchCount(frameSize, 0); for (int inMap = 0; inMap < numInMaps; ++inMap) { map::iterator search = outMapToKeyLookup[inMap].find(outMap); if (search == outMapToKeyLookup[inMap].end()) { continue;//this map doesn't contain a label name that matches, skip to next input map } int matchKey = search->second; const float* inFrame = inputVol->getFrame(inMap); for (int64_t i = 0; i < frameSize; ++i) { int thisKey = (int)floor(inFrame[i] + 0.5f); if (thisKey == matchKey) { ++scratchCount[i]; } } } vector scratchFrameOut(frameSize); for (int64_t i = 0; i < frameSize; ++i) { scratchFrameOut[i] = ((float)scratchCount[i]) / numInMaps; } outputVol->setFrame(scratchFrameOut.data(), outMap); } } float AlgorithmVolumeLabelProbability::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeLabelProbability::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeLabelProbability.h000066400000000000000000000034001360521144700271600ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_LABEL_PROBABILITY_H__ #define __ALGORITHM_VOLUME_LABEL_PROBABILITY_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmVolumeLabelProbability : public AbstractAlgorithm { AlgorithmVolumeLabelProbability(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeLabelProbability(ProgressObject* myProgObj, const VolumeFile* inputVol, VolumeFile* outputVol, const bool& excludeUnlabeled = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeLabelProbability; } #endif //__ALGORITHM_VOLUME_LABEL_PROBABILITY_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeLabelToROI.cxx000066400000000000000000000246601360521144700262220ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeLabelToROI.h" #include "AlgorithmException.h" #include "CaretLogger.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "VolumeFile.h" #include #include using namespace caret; using namespace std; AString AlgorithmVolumeLabelToROI::getCommandSwitch() { return "-volume-label-to-roi"; } AString AlgorithmVolumeLabelToROI::getShortDescription() { return "MAKE A VOLUME LABEL INTO AN ROI VOLUME"; } OperationParameters* AlgorithmVolumeLabelToROI::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "label-in", "the input volume label file"); ret->addVolumeOutputParameter(2, "volume-out", "the output volume file"); OptionalParameter* nameOpt = ret->createOptionalParameter(3, "-name", "select label by name"); nameOpt->addStringParameter(1, "label-name", "the label name that you want an roi of"); OptionalParameter* keyOpt = ret->createOptionalParameter(4, "-key", "select label by key"); keyOpt->addIntegerParameter(1, "label-key", "the label key that you want an roi of"); OptionalParameter* mapOpt = ret->createOptionalParameter(5, "-map", "select a single label map to use"); mapOpt->addStringParameter(1, "map", "the map number or name"); ret->setHelpText( AString("For each map in , a map is created in where all locations labeled with or with a key of are given a value of 1, and all other locations are given 0. ") + "Exactly one of -name and -key must be specified. " + "Specify -map to use only one map from ." ); return ret; } void AlgorithmVolumeLabelToROI::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* myLabel = myParams->getVolume(1); VolumeFile* myVolumeOut = myParams->getOutputVolume(2); bool nameMode = false; AString labelName; OptionalParameter* nameOpt = myParams->getOptionalParameter(3); if (nameOpt->m_present) { nameMode = true; labelName = nameOpt->getString(1); } int32_t labelKey; OptionalParameter* keyOpt = myParams->getOptionalParameter(4); if (keyOpt->m_present) { if (nameMode) throw AlgorithmException("-name and -key cannot be specified together"); labelKey = (int32_t)keyOpt->getInteger(1); } else { if (!nameMode) throw AlgorithmException("you must specify one of -name or -key"); } int whichMap = -1; OptionalParameter* mapOpt = myParams->getOptionalParameter(5); if (mapOpt->m_present) { AString mapID = mapOpt->getString(1); whichMap = myLabel->getMapIndexFromNameOrNumber(mapID); if (whichMap == -1) { throw AlgorithmException("invalid map number or name specified"); } } if (nameMode) { AlgorithmVolumeLabelToROI(myProgObj, myLabel, labelName, myVolumeOut, whichMap); } else { AlgorithmVolumeLabelToROI(myProgObj, myLabel, labelKey, myVolumeOut, whichMap); } } AlgorithmVolumeLabelToROI::AlgorithmVolumeLabelToROI(ProgressObject* myProgObj, const VolumeFile* myLabel, const AString& labelName, VolumeFile* myVolumeOut, const int& whichMap) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int numMaps = myLabel->getNumberOfMaps(); if (whichMap < -1 || whichMap >= numMaps) { throw AlgorithmException("invalid map index specified"); } if (myLabel->getType() != SubvolumeAttributes::LABEL) { throw AlgorithmException("input volume is not a label volume"); } vector dims, origDims = myLabel->getOriginalDimensions(); myLabel->getDimensions(dims); if (dims[4] != 1) { throw AlgorithmException("input label volume has multi-component type"); } int64_t frameSize = dims[0] * dims[1] * dims[2]; vector scratchFrame(frameSize); if (whichMap == -1) { myVolumeOut->reinitialize(origDims, myLabel->getSform()); bool shouldThrow = true; for (int thisMap = 0; thisMap < numMaps; ++thisMap) { const GiftiLabelTable* myTable = myLabel->getMapLabelTable(thisMap); int matchKey = myTable->getLabelKeyFromName(labelName); if (matchKey == GiftiLabel::getInvalidLabelKey()) { CaretLogWarning("label name '" + labelName + "' not found in map #" + AString::number(thisMap + 1)); for (int64_t i = 0; i < frameSize; ++i) { scratchFrame[i] = 0.0f; } } else { const float* labelFrame = myLabel->getFrame(thisMap); for (int64_t i = 0; i < frameSize; ++i) { int thisKey = (int)floor(labelFrame[i] + 0.5f); if (thisKey == matchKey) { scratchFrame[i] = 1.0f; shouldThrow = false; } else { scratchFrame[i] = 0.0f; } } } myVolumeOut->setFrame(scratchFrame.data(), thisMap); } if (shouldThrow) { throw AlgorithmException("no data matched the specified label name"); } } else { origDims.resize(3); myVolumeOut->reinitialize(origDims, myLabel->getSform()); const GiftiLabelTable* myTable = myLabel->getMapLabelTable(whichMap); int matchKey = myTable->getLabelKeyFromName(labelName); if (matchKey == GiftiLabel::getInvalidLabelKey()) { throw AlgorithmException("label name '" + labelName + "' not found in specified map"); } const float* labelFrame = myLabel->getFrame(whichMap); bool shouldThrow = true; for (int64_t i = 0; i < frameSize; ++i) { int thisKey = (int)floor(labelFrame[i] + 0.5f); if (thisKey == matchKey) { scratchFrame[i] = 1.0f; shouldThrow = false; } else { scratchFrame[i] = 0.0f; } } if (shouldThrow) { throw AlgorithmException("no data matched the specified label name in the specified map"); } myVolumeOut->setFrame(scratchFrame.data(), 0); } } AlgorithmVolumeLabelToROI::AlgorithmVolumeLabelToROI(ProgressObject* myProgObj, const VolumeFile* myLabel, const int32_t& labelKey, VolumeFile* myVolumeOut, const int& whichMap) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); int numMaps = myLabel->getNumberOfMaps(); if (whichMap < -1 || whichMap >= numMaps) { throw AlgorithmException("invalid map index specified"); } if (myLabel->getType() != SubvolumeAttributes::LABEL) { throw AlgorithmException("input volume is not a label volume"); } vector dims, origDims = myLabel->getOriginalDimensions(); myLabel->getDimensions(dims); if (dims[4] != 1) { throw AlgorithmException("input label volume has multi-component type"); } int64_t frameSize = dims[0] * dims[1] * dims[2]; vector scratchFrame(frameSize); if (whichMap == -1) { myVolumeOut->reinitialize(origDims, myLabel->getSform()); bool shouldThrow = true; for (int thisMap = 0; thisMap < numMaps; ++thisMap) { const GiftiLabelTable* myTable = myLabel->getMapLabelTable(thisMap); if (myTable->getLabel(labelKey) == NULL) { CaretLogWarning("label key " + AString::number(labelKey) + " not found in map #" + AString::number(thisMap + 1)); } const float* labelFrame = myLabel->getFrame(thisMap);//try anyway, in case label table is incomplete for (int64_t i = 0; i < frameSize; ++i) { int thisKey = (int)floor(labelFrame[i] + 0.5f); if (thisKey == labelKey) { scratchFrame[i] = 1.0f; shouldThrow = false; } else { scratchFrame[i] = 0.0f; } } myVolumeOut->setFrame(scratchFrame.data(), thisMap); } if (shouldThrow) { throw AlgorithmException("no data matched the specified label key"); } } else { origDims.resize(3); myVolumeOut->reinitialize(origDims, myLabel->getSform()); const GiftiLabelTable* myTable = myLabel->getMapLabelTable(whichMap); if (myTable->getLabel(labelKey) == NULL) { CaretLogWarning("label key " + AString::number(labelKey) + " not found in specified map"); } const float* labelFrame = myLabel->getFrame(whichMap); bool shouldThrow = true; for (int64_t i = 0; i < frameSize; ++i) { int thisKey = (int)floor(labelFrame[i] + 0.5f); if (thisKey == labelKey) { scratchFrame[i] = 1.0f; shouldThrow = false; } else { scratchFrame[i] = 0.0f; } } if (shouldThrow) { throw AlgorithmException("no data matched the specified label key in the specified map"); } myVolumeOut->setFrame(scratchFrame.data(), 0); } } float AlgorithmVolumeLabelToROI::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeLabelToROI::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeLabelToROI.h000066400000000000000000000036071360521144700256450ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_LABEL_TO_ROI_H__ #define __ALGORITHM_VOLUME_LABEL_TO_ROI_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmVolumeLabelToROI : public AbstractAlgorithm { AlgorithmVolumeLabelToROI(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeLabelToROI(ProgressObject* myProgObj, const VolumeFile* myLabel, const AString& labelName, VolumeFile* myVolumeOut, const int& whichMap = -1); AlgorithmVolumeLabelToROI(ProgressObject* myProgObj, const VolumeFile* myLabel, const int32_t& labelKey, VolumeFile* myVolumeOut, const int& whichMap = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeLabelToROI; } #endif //__ALGORITHM_VOLUME_LABEL_TO_ROI_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeLabelToSurfaceMapping.cxx000066400000000000000000000367711360521144700305030ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeLabelToSurfaceMapping.h" #include "AlgorithmException.h" #include "GiftiLabelTable.h" #include "LabelFile.h" #include "RibbonMappingHelper.h" #include "SurfaceFile.h" #include "VolumeFile.h" #include #include using namespace caret; using namespace std; AString AlgorithmVolumeLabelToSurfaceMapping::getCommandSwitch() { return "-volume-label-to-surface-mapping"; } AString AlgorithmVolumeLabelToSurfaceMapping::getShortDescription() { return "MAP A LABEL VOLUME TO A SURFACE LABEL FILE"; } OperationParameters* AlgorithmVolumeLabelToSurfaceMapping::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume", "the volume to map data from"); ret->addSurfaceParameter(2, "surface", "the surface to map the data onto"); ret->addLabelOutputParameter(3, "label-out", "the output gifti label file"); OptionalParameter* ribbonOpt = ret->createOptionalParameter(4, "-ribbon-constrained", "use ribbon constrained mapping algorithm"); ribbonOpt->addSurfaceParameter(1, "inner-surf", "the inner surface of the ribbon"); ribbonOpt->addSurfaceParameter(2, "outer-surf", "the outer surface of the ribbon"); OptionalParameter* roiVol = ribbonOpt->createOptionalParameter(3, "-volume-roi", "use a volume roi"); roiVol->addVolumeParameter(1, "roi-volume", "the volume file"); OptionalParameter* ribbonSubdiv = ribbonOpt->createOptionalParameter(4, "-voxel-subdiv", "voxel divisions while estimating voxel weights"); ribbonSubdiv->addIntegerParameter(1, "subdiv-num", "number of subdivisions, default 3"); ribbonOpt->createOptionalParameter(5, "-thin-columns", "use non-overlapping polyhedra"); OptionalParameter* subvolumeSelect = ret->createOptionalParameter(5, "-subvol-select", "select a single subvolume to map"); subvolumeSelect->addStringParameter(1, "subvol", "the subvolume number or name"); ret->setHelpText( AString("Map label volume data to a surface. If -ribbon-constrained is not specified, uses the enclosing voxel method. ") + "The ribbon mapping method constructs a polyhedron from the vertex's neighbors on each " + "surface, and estimates the amount of this polyhedron's volume that falls inside any nearby voxels, to use as the weights for a popularity comparison. " + "If -thin-columns is specified, the polyhedron uses the edge midpoints and triangle centroids, so that neighboring vertices do not have overlapping polyhedra. " + "This may require increasing -voxel-subdiv to get enough samples in each voxel to reliably land inside these smaller polyhedra. " "The volume ROI is useful to exclude partial volume effects of voxels the surfaces pass through, and will cause the mapping to ignore " + "voxels that don't have a positive value in the mask. The subdivision number specifies how it approximates the amount of the volume the polyhedron " + "intersects, by splitting each voxel into NxNxN pieces, and checking whether the center of each piece is inside the polyhedron. If you have very large " + "voxels, consider increasing this if you get unexpected unlabeled vertices in your output." ); return ret; } void AlgorithmVolumeLabelToSurfaceMapping::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* myVolume = myParams->getVolume(1); SurfaceFile* mySurface = myParams->getSurface(2); LabelFile* myLabelOut = myParams->getOutputLabel(3); int64_t mySubVol = -1; OptionalParameter* subvolumeSelect = myParams->getOptionalParameter(5); if (subvolumeSelect->m_present) { mySubVol = myVolume->getMapIndexFromNameOrNumber(subvolumeSelect->getString(1)); if (mySubVol < 0) { throw AlgorithmException("invalid column specified"); } } OptionalParameter* ribbonOpt = myParams->getOptionalParameter(4);//method options last for now, for simplicity if (ribbonOpt->m_present) { SurfaceFile* innerSurf = ribbonOpt->getSurface(1); SurfaceFile* outerSurf = ribbonOpt->getSurface(2); OptionalParameter* roiVol = ribbonOpt->getOptionalParameter(3); VolumeFile* myRoiVol = NULL; if (roiVol->m_present) { myRoiVol = roiVol->getVolume(1); } int32_t subdivisions = 3; OptionalParameter* ribbonSubdiv = ribbonOpt->getOptionalParameter(4); if (ribbonSubdiv->m_present) { subdivisions = ribbonSubdiv->getInteger(1); if (subdivisions < 1) { throw AlgorithmException("invalid number of subdivisions specified"); } } bool thinColumns = ribbonOpt->getOptionalParameter(5)->m_present; AlgorithmVolumeLabelToSurfaceMapping(myProgObj, myVolume, mySurface, myLabelOut, innerSurf, outerSurf, myRoiVol, subdivisions, thinColumns, mySubVol); } else { AlgorithmVolumeLabelToSurfaceMapping(myProgObj, myVolume, mySurface, myLabelOut, mySubVol); } } AlgorithmVolumeLabelToSurfaceMapping::AlgorithmVolumeLabelToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, LabelFile* myLabelOut, const int64_t& mySubVol) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (myVolume->getType() != SubvolumeAttributes::LABEL) { throw AlgorithmException("input volume must be a label volume"); } if (myVolume->getNumberOfComponents() != 1) throw AlgorithmException("label volumes must not have multiple components per map"); vector myVolDims; myVolume->getDimensions(myVolDims); if (mySubVol >= myVolDims[3] || mySubVol < -1) { throw AlgorithmException("invalid subvolume specified"); } int64_t numColumns; if (mySubVol == -1) { numColumns = myVolDims[3]; } else { numColumns = 1; } int64_t numNodes = mySurface->getNumberOfNodes(); myLabelOut->setNumberOfNodesAndColumns(numNodes, numColumns); myLabelOut->setStructure(mySurface->getStructure()); vector myArray(numNodes); if (mySubVol == -1) { GiftiLabelTable cumulativeTable = *(myVolume->getMapLabelTable(0));//so we don't run into append issues with the "???" label that gets made by GiftiLabelTable's constructor for (int64_t i = 0; i < myVolDims[3]; ++i) { map frameRemap; if (i > 0) { const GiftiLabelTable* tempTable = myVolume->getMapLabelTable(i); if (tempTable == NULL) { throw AlgorithmException("a subvolume is missing a label table"); } frameRemap = cumulativeTable.append(*tempTable); } AString mapName = myVolume->getMapName(i); myLabelOut->setColumnName(i, mapName); #pragma omp CARET_PARFOR for (int64_t node = 0; node < numNodes; ++node) { int32_t tempKey = (int32_t)floor(myVolume->interpolateValue(mySurface->getCoordinate(node), VolumeFile::ENCLOSING_VOXEL, NULL, i) + 0.5f); map::iterator iter = frameRemap.find(tempKey); if (iter != frameRemap.end()) { myArray[node] = iter->second; } else { myArray[node] = tempKey;//for simplicity, assume all values in the volume file are in the label table } } myLabelOut->setLabelKeysForColumn(i, myArray.data()); } *(myLabelOut->getLabelTable()) = cumulativeTable; } else { const GiftiLabelTable* tempTable = myVolume->getMapLabelTable(mySubVol); if (tempTable == NULL) { throw AlgorithmException("specified subvolume is missing a label table"); } *(myLabelOut->getLabelTable()) = *tempTable; myLabelOut->setColumnName(0, myVolume->getMapName(mySubVol)); #pragma omp CARET_PARFOR for (int64_t node = 0; node < numNodes; ++node) {//for simplicity, assume all values in the volume file are in the label table myArray[node] = (int32_t)floor(myVolume->interpolateValue(mySurface->getCoordinate(node), VolumeFile::ENCLOSING_VOXEL, NULL, mySubVol) + 0.5f); } myLabelOut->setLabelKeysForColumn(0, myArray.data()); } } AlgorithmVolumeLabelToSurfaceMapping::AlgorithmVolumeLabelToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, LabelFile* myLabelOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const VolumeFile* myRoiVol, const int32_t& subdivisions, const bool& thinColumns, const int64_t& mySubVol): AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (myVolume->getType() != SubvolumeAttributes::LABEL) { throw AlgorithmException("input volume must be a label volume"); } if (myVolume->getNumberOfComponents() != 1) throw AlgorithmException("label volumes must not have multiple components per map"); vector myVolDims; myVolume->getDimensions(myVolDims); if (mySubVol >= myVolDims[3] || mySubVol < -1) { throw AlgorithmException("invalid subvolume specified"); } int64_t numColumns; if (mySubVol == -1) { numColumns = myVolDims[3]; } else { numColumns = 1; } int64_t numNodes = mySurface->getNumberOfNodes(); myLabelOut->setNumberOfNodesAndColumns(numNodes, numColumns); myLabelOut->setStructure(mySurface->getStructure()); vector myArray(numNodes); vector > myWeights; const float* roiFrame = NULL; if (myRoiVol != NULL) roiFrame = myRoiVol->getFrame(); RibbonMappingHelper::computeWeightsRibbon(myWeights, myVolume->getVolumeSpace(), innerSurf, outerSurf, roiFrame, subdivisions, thinColumns); if (mySubVol == -1) { GiftiLabelTable cumulativeTable = *(myVolume->getMapLabelTable(0));//so we don't run into append issues with the "???" label that gets made by GiftiLabelTable's constructor int32_t unlabeledKey = cumulativeTable.getUnassignedLabelKey();//but, assume the first table has one, because we may need it for (int64_t i = 0; i < myVolDims[3]; ++i) { map frameRemap; if (i > 0) { const GiftiLabelTable* tempTable = myVolume->getMapLabelTable(i); if (tempTable == NULL) { throw AlgorithmException("a subvolume is missing a label table"); } frameRemap = cumulativeTable.append(*tempTable); } myLabelOut->setColumnName(i, myVolume->getMapName(i)); #pragma omp CARET_PARFOR for (int64_t node = 0; node < numNodes; ++node) { const vector& weightRef = myWeights[node]; map totals; for (int v = 0; v < (int)weightRef.size(); ++v) { int32_t voxKey = (int32_t)floor(myVolume->getValue(weightRef[v].ijk, i) + 0.5f); map::iterator iter = totals.find(voxKey); if (iter == totals.end()) {//floats don't initialize to 0 totals[voxKey] = weightRef[v].weight; } else { totals[voxKey] += weightRef[v].weight; } } int32_t tempKey = unlabeledKey; float bestSum = -1.0f; for (map::iterator iter = totals.begin(); iter != totals.end(); ++iter) { if (iter->second > bestSum) { tempKey = iter->first; bestSum = iter->second; } } map::iterator iter = frameRemap.find(tempKey); if (iter != frameRemap.end()) { myArray[node] = iter->second; } else { myArray[node] = tempKey;//for simplicity, assume all values in the frame are in the label table } } myLabelOut->setLabelKeysForColumn(i, myArray.data()); } *(myLabelOut->getLabelTable()) = cumulativeTable; } else { const GiftiLabelTable* tempTable = myVolume->getMapLabelTable(mySubVol); int unlabeledKey = tempTable->getUnassignedLabelKey(); if (tempTable == NULL) { throw AlgorithmException("specified subvolume is missing a label table"); } *(myLabelOut->getLabelTable()) = *tempTable; myLabelOut->setColumnName(0, myVolume->getMapName(mySubVol)); #pragma omp CARET_PARFOR for (int64_t node = 0; node < numNodes; ++node) {//for simplicity, assume all values in the volume file are in the label table const vector& weightRef = myWeights[node]; map totals; for (int v = 0; v < (int)weightRef.size(); ++v) { int32_t voxKey = (int32_t)floor(myVolume->getValue(weightRef[v].ijk, mySubVol) + 0.5f); map::iterator iter = totals.find(voxKey); if (iter == totals.end()) {//floats don't initialize to 0 totals[voxKey] = weightRef[v].weight; } else { totals[voxKey] += weightRef[v].weight; } } int32_t tempKey = unlabeledKey; float bestSum = -1.0f; for (map::iterator iter = totals.begin(); iter != totals.end(); ++iter) { if (iter->second > bestSum) { tempKey = iter->first; bestSum = iter->second; } } myArray[node] = tempKey;//for simplicity, assume all values in the frame are in the label table } myLabelOut->setLabelKeysForColumn(0, myArray.data()); } } float AlgorithmVolumeLabelToSurfaceMapping::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeLabelToSurfaceMapping::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeLabelToSurfaceMapping.h000066400000000000000000000045211360521144700301140ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_LABEL_TO_SURFACE_MAPPING_H__ #define __ALGORITHM_VOLUME_LABEL_TO_SURFACE_MAPPING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmVolumeLabelToSurfaceMapping : public AbstractAlgorithm { AlgorithmVolumeLabelToSurfaceMapping(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeLabelToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, LabelFile* myLabelOut, const int64_t& mySubVol = -1); AlgorithmVolumeLabelToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, LabelFile* myLabelOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const VolumeFile* myRoiVol = NULL, const int32_t& subdivisions = 3, const bool& thinColumns = false, const int64_t& mySubVol = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeLabelToSurfaceMapping; } #endif //__ALGORITHM_VOLUME_LABEL_TO_SURFACE_MAPPING_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeParcelResampling.cxx000066400000000000000000001300021360521144700275420ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeParcelResampling.h" #include "AlgorithmException.h" #include "VolumeFile.h" #include "AlgorithmVolumeSmoothing.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "Vector3D.h" #include #include #include #include using namespace caret; using namespace std; const int FIX_ZEROS_POST_ITERATIONS = 10;//number of times to do the "find remaining zeros and try to fill" code before giving up when -fix-zeros is specified AString AlgorithmVolumeParcelResampling::getCommandSwitch() { return "-volume-parcel-resampling"; } AString AlgorithmVolumeParcelResampling::getShortDescription() { return "SMOOTH AND RESAMPLE VOLUME PARCELS"; } OperationParameters* AlgorithmVolumeParcelResampling::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume-in", "the input data volume"); ret->addVolumeParameter(2, "cur-parcels", "label volume of where the parcels currently are"); ret->addVolumeParameter(3, "new-parcels", "label volume of where the parcels should be"); ret->addDoubleParameter(4, "kernel", "gaussian kernel sigma to smooth by during resampling"); ret->addVolumeOutputParameter(5, "volume-out", "output volume"); ret->createOptionalParameter(6, "-fix-zeros", "treat zero values as not being data"); OptionalParameter* subvolSelect = ret->createOptionalParameter(7, "-subvolume", "select a single subvolume as input"); subvolSelect->addStringParameter(1, "subvol", "the subvolume number or name"); ret->setHelpText( AString("Smooths and resamples the region inside each label in cur-parcels to the region of the same label name in new-parcels. ") + "Any voxels in the output label region but outside the input label region will be extrapolated from nearby data. " + "The -fix-zeros option causes the smoothing to not use an input value if it is zero, but still write a smoothed value to the voxel, and after smoothing " + "is complete, it will check for any remaining values of zero, and fill them in with extrapolated values.\n\nNote: all volumes must have " + "the same dimensions and spacing. To use a different output space, see -volume-parcel-resampling-generic." ); return ret; } void AlgorithmVolumeParcelResampling::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* inVol = myParams->getVolume(1); VolumeFile* curLabel = myParams->getVolume(2); VolumeFile* newLabel = myParams->getVolume(3); float kernel = (float)myParams->getDouble(4); VolumeFile* outVol = myParams->getOutputVolume(5); bool fixZeros = false; if (myParams->getOptionalParameter(6)->m_present) { fixZeros = true; } OptionalParameter* subvolSelect = myParams->getOptionalParameter(7); int subvolNum = -1; if (subvolSelect->m_present) { subvolNum = (int)inVol->getMapIndexFromNameOrNumber(subvolSelect->getString(1)); if (subvolNum < 0) { throw AlgorithmException("invalid subvolume specified"); } } AlgorithmVolumeParcelResampling(myProgObj, inVol, curLabel, newLabel, kernel, outVol, fixZeros, subvolNum); } AlgorithmVolumeParcelResampling::AlgorithmVolumeParcelResampling(ProgressObject* myProgObj, const VolumeFile* inVol, const VolumeFile* curLabel, const VolumeFile* newLabel, const float& kernel, VolumeFile* outVol, const bool& fixZeros, const int& subvolNum) : AbstractAlgorithm(myProgObj) { CaretAssert(inVol != NULL); CaretAssert(curLabel != NULL); CaretAssert(newLabel != NULL); CaretAssert(outVol != NULL); if (!inVol->matchesVolumeSpace(curLabel) || !inVol->matchesVolumeSpace(newLabel)) { throw AlgorithmException("volume spacing or dimension mismatch"); } if (curLabel->getType() != SubvolumeAttributes::LABEL || newLabel->getType() != SubvolumeAttributes::LABEL) { throw AlgorithmException("parcel volumes are not of type label"); } if (subvolNum < -1 || subvolNum >= inVol->getNumberOfMaps()) { throw AlgorithmException("invalid subvolume specified"); } vector > matchedLabels; matchLabels(curLabel, newLabel, matchedLabels); if (matchedLabels.size() == 0) { throw AlgorithmException("no matching labels"); } vector > voxelLists; generateVoxelLists(matchedLabels, curLabel, newLabel, voxelLists); /*ProgressObject* subAlgProgress = NULL; if (myProgObj != NULL)//TODO: create a vector of progress objects based on number of matched labels, and possibly counts of voxels { subAlgProgress = myProgObj->addAlgorithm(AlgorithmVolumeParcelSmoothing::getAlgorithmWeight()); }//*/ LevelProgress myProgress(myProgObj); if (fixZeros) { resampleFixZeros(myProgress, matchedLabels, voxelLists, inVol, curLabel, newLabel, kernel, outVol, subvolNum); } else { resample(myProgress, matchedLabels, voxelLists, inVol, curLabel, newLabel, kernel, outVol, subvolNum); } } void AlgorithmVolumeParcelResampling::matchLabels(const VolumeFile* curLabel, const VolumeFile* newLabel, vector >& matchedLabels) { const GiftiLabelTable* curTable = curLabel->getMapLabelTable(0), *newTable = newLabel->getMapLabelTable(0); vector curKeys; curTable->getKeys(curKeys); int32_t curUnused = curTable->getUnassignedLabelKey(); for (int i = 0; i < (int)curKeys.size(); ++i) { if (curKeys[i] == curUnused) continue;//always skip the unassigned label if (newTable->getLabel(curKeys[i]) != NULL && newTable->getLabelName(curKeys[i]) == curTable->getLabelName(curKeys[i])) {//do the obvious check first matchedLabels.push_back(make_pair(curKeys[i], curKeys[i])); } else { int32_t newKey = newTable->getLabelKeyFromName(curTable->getLabelName(curKeys[i])); if (newKey != -1) { matchedLabels.push_back(make_pair(curKeys[i], newKey)); } } } } void AlgorithmVolumeParcelResampling::generateVoxelLists(const vector >& matchedLabels, const VolumeFile* curLabel, const VolumeFile* newLabel, vector >& voxelLists) { map curLabelReverse, newLabelReverse; for (int i = 0; i < (int)matchedLabels.size(); ++i) { curLabelReverse[matchedLabels[i].first] = i; newLabelReverse[matchedLabels[i].second] = i; } voxelLists.resize(matchedLabels.size()); vector myDims; curLabel->getDimensions(myDims); for (int64_t k = 0; k < myDims[2]; ++k) { for (int64_t j = 0; j < myDims[1]; ++j) { for (int64_t i = 0; i < myDims[0]; ++i) { int curValue = (int)floor(curLabel->getValue(i, j, k) + 0.5f); int newValue = (int)floor(newLabel->getValue(i, j, k) + 0.5f); map::iterator curiter = curLabelReverse.find(curValue), newiter = newLabelReverse.find(newValue); if (curiter != curLabelReverse.end()) { voxelLists[curiter->second].push_back(i); voxelLists[curiter->second].push_back(j); voxelLists[curiter->second].push_back(k); } if (newiter != newLabelReverse.end() && (curiter == curLabelReverse.end() || newiter->second != curiter->second)) { voxelLists[newiter->second].push_back(i); voxelLists[newiter->second].push_back(j); voxelLists[newiter->second].push_back(k); } } } } } void AlgorithmVolumeParcelResampling::resample(LevelProgress& myProgress, const vector >& matchedLabels, const vector >& voxelLists, const VolumeFile* inVol, const VolumeFile* curLabel, const VolumeFile* newLabel, const float& kernel, VolumeFile* outVol, const int& subvolNum) { float kernBox = kernel * 3.0f; vector > volSpace = inVol->getSform();//copied from volume smoothing, perhaps this should be in a convenience method in VolumeFile Vector3D ivec, jvec, kvec, origin, ijorth, jkorth, kiorth; ivec[0] = volSpace[0][0]; jvec[0] = volSpace[0][1]; kvec[0] = volSpace[0][2]; origin[0] = volSpace[0][3];//needs to be this verbose because the axis and origin vectors are column vectors ivec[1] = volSpace[1][0]; jvec[1] = volSpace[1][1]; kvec[1] = volSpace[1][2]; origin[1] = volSpace[1][3];//while vector > is a column of row vectors ivec[2] = volSpace[2][0]; jvec[2] = volSpace[2][1]; kvec[2] = volSpace[2][2]; origin[2] = volSpace[2][3]; ijorth = ivec.cross(jvec).normal();//find the bounding box that encloses a sphere of radius kernBox jkorth = jvec.cross(kvec).normal(); kiorth = kvec.cross(ivec).normal(); int irange = (int)floor(abs(kernBox / ivec.dot(jkorth))); int jrange = (int)floor(abs(kernBox / jvec.dot(kiorth))); int krange = (int)floor(abs(kernBox / kvec.dot(ijorth))); if (irange < 1) irange = 1;//don't underflow if (jrange < 1) jrange = 1; if (krange < 1) krange = 1; map curLabelReverse, newLabelReverse; int numLabels = (int)matchedLabels.size(); for (int i = 0; i < numLabels; ++i) { curLabelReverse[matchedLabels[i].first] = i; newLabelReverse[matchedLabels[i].second] = i; } vector myDims; inVol->getDimensions(myDims); if (subvolNum == -1) { outVol->reinitialize(inVol->getOriginalDimensions(), inVol->getSform(), myDims[4], inVol->getType(), inVol->m_header); } else { vector newDims = inVol->getOriginalDimensions(); newDims.resize(3);//discard nonspatial dimentions outVol->reinitialize(newDims, inVol->getSform(), myDims[4], inVol->getType(), inVol->m_header); } outVol->setValueAllVoxels(0.0f); const GiftiLabelTable* curTable = curLabel->getMapLabelTable(0); for (int whichList = 0; whichList < numLabels; ++whichList) { int curLabelValue = matchedLabels[whichList].first; int newLabelValue = matchedLabels[whichList].second; myProgress.reportProgress(((float)whichList) / numLabels); myProgress.setTask("Processing parcel " + curTable->getLabelName(curLabelValue)); const vector& thisList = voxelLists[whichList]; int64_t listSize = (int64_t)thisList.size(); if (listSize > 2)//NOTE: this should NEVER be something other than a multiple of 3, but check against what we will actually access anyway { int extrema[6] = { thisList[0], thisList[0], thisList[1], thisList[1], thisList[2], thisList[2] }; for (int64_t base = 3; base < listSize; base += 3) { if (thisList[base] < extrema[0]) extrema[0] = thisList[base]; if (thisList[base] > extrema[1]) extrema[1] = thisList[base]; if (thisList[base + 1] < extrema[2]) extrema[2] = thisList[base + 1]; if (thisList[base + 1] > extrema[3]) extrema[3] = thisList[base + 1]; if (thisList[base + 2] < extrema[4]) extrema[4] = thisList[base + 2]; if (thisList[base + 2] > extrema[5]) extrema[5] = thisList[base + 2]; } vector boxdims; boxdims.push_back(extrema[1] - extrema[0] + 1); boxdims.push_back(extrema[3] - extrema[2] + 1); boxdims.push_back(extrema[5] - extrema[4] + 1); VolumeFile roibox(boxdims, inVol->getSform()); roibox.setValueAllVoxels(0.0f); vector curList, newList;//make the 2 separate lists, so we don't need to test the label volume for (int64_t base = 0; base < listSize; base += 3)//could do this when we make the merged list...maybe use member variables to cut the argument clutter { int curvalue = (int)floor(curLabel->getValue(thisList[base], thisList[base + 1], thisList[base + 2]) + 0.5f); int newvalue = (int)floor(newLabel->getValue(thisList[base], thisList[base + 1], thisList[base + 2]) + 0.5f); if (curvalue == curLabelValue) { curList.push_back(thisList[base]); curList.push_back(thisList[base + 1]); curList.push_back(thisList[base + 2]); } if (newvalue == newLabelValue) { newList.push_back(thisList[base]); newList.push_back(thisList[base + 1]); newList.push_back(thisList[base + 2]); } } int64_t curListSize = (int64_t)curList.size(); int64_t newListSize = (int64_t)newList.size(); if (subvolNum == -1) { boxdims.push_back(myDims[3]); VolumeFile inbox(boxdims, inVol->getSform(), myDims[4]), outbox; for (int c = 0; c < myDims[4]; ++c) { for (int s = 0; s < myDims[3]; ++s) { for (int64_t base = 0; base < curListSize; base += 3) { if (s == 0 && c == 0)//first, smooth within only the current label { roibox.setValue(1.0f, curList[base] - extrema[0], curList[base + 1] - extrema[2], curList[base + 2] - extrema[4]); } inbox.setValue(inVol->getValue(curList[base], curList[base + 1], curList[base + 2], s, c), curList[base] - extrema[0], curList[base + 1] - extrema[2], curList[base + 2] - extrema[4], s, c); } } } AlgorithmVolumeSmoothing(NULL, &inbox, kernel, &outbox, &roibox, false); float kernelMult = -1.0f / kernel / kernel / 2.0f;//precompute the part of the kernel function that doesn't change for (int c = 0; c < myDims[4]; ++c) { for (int s = 0; s < myDims[3]; ++s) { const float* inFrame = inVol->getFrame(s, c); const float* labelFrame = curLabel->getFrame(); for (int64_t base = 0; base < newListSize; base += 3) { int myCurVal = (int)floor(curLabel->getValue(newList[base], newList[base + 1], newList[base + 2]) + 0.5f); if (myCurVal == curLabelValue) { outVol->setValue(outbox.getValue(newList[base] - extrema[0], newList[base + 1] - extrema[2], newList[base + 2] - extrema[4], s, c), newList[base], newList[base + 1], newList[base + 2], s, c); } else { float sum = 0.0f, weightsum = 0.0f;//coded in-place for now, its a special restricted case of volume dilate, copied out of nonorth volume smoothing int i = newList[base], j = newList[base + 1], k = newList[base + 2];//special casing orthogonal would be faster, but harder to follow/debug, and more code int imin = i - irange, imax = i + irange + 1;//one-after array size convention if (imin < 0) imin = 0; if (imax > myDims[0]) imax = myDims[0]; int jmin = j - jrange, jmax = j + jrange + 1; if (jmin < 0) jmin = 0; if (jmax > myDims[1]) jmax = myDims[1]; int kmin = k - krange, kmax = k + krange + 1; if (kmin < 0) kmin = 0; if (kmax > myDims[2]) kmax = myDims[2]; Vector3D kscratch, jscratch, iscratch; for (int kkern = kmin; kkern < kmax; ++kkern) { kscratch = kvec * (kkern - k); int64_t kindpart = kkern * myDims[1]; for (int jkern = jmin; jkern < jmax; ++jkern) { jscratch = kscratch + jvec * (jkern - j); int64_t jindpart = (kindpart + jkern) * myDims[0]; for (int ikern = imin; ikern < imax; ++ikern) { int64_t thisIndex = jindpart + ikern;//somewhat optimized index computation, could remove some integer multiplies, but there aren't that many int curVal = (int)floor(labelFrame[thisIndex] + 0.5f); if (curVal == curLabelValue) { iscratch = jscratch + ivec * (ikern - i); float tempf = iscratch.length(); float weight = exp(tempf * tempf * kernelMult); sum += weight * inFrame[thisIndex]; weightsum += weight; } } } } if (weightsum != 0.0f) { outVol->setValue(sum / weightsum, newList[base], newList[base + 1], newList[base + 2], s, c); }//should already be 0, so don't need to handle the else } } } } } else { VolumeFile inbox(boxdims, inVol->getSform(), myDims[4]), outbox; for (int c = 0; c < myDims[4]; ++c) { for (int64_t base = 0; base < curListSize; base += 3) { int myvalue = (int)floor(curLabel->getValue(curList[base], curList[base + 1], curList[base + 2]) + 0.5f); if (myvalue == matchedLabels[whichList].first) {//first, only smooth within the ROI of the current label, otherwise we would smooth in some zeros that aren't data if (c == 0) { roibox.setValue(1.0f, curList[base] - extrema[0], curList[base + 1] - extrema[2], curList[base + 2] - extrema[4]); } inbox.setValue(inVol->getValue(curList[base], curList[base + 1], curList[base + 2], subvolNum, c), curList[base] - extrema[0], curList[base + 1] - extrema[2], curList[base + 2] - extrema[4], 0, c); } } } AlgorithmVolumeSmoothing(NULL, &inbox, kernel, &outbox, &roibox, false); float kernelMult = -1.0f / kernel / kernel / 2.0f;//precompute the part of the kernel function that doesn't change for (int c = 0; c < myDims[4]; ++c) { const float* inFrame = inVol->getFrame(subvolNum, c); const float* labelFrame = curLabel->getFrame(); for (int64_t base = 0; base < newListSize; base += 3) { int myCurVal = (int)floor(curLabel->getValue(newList[base], newList[base + 1], newList[base + 2]) + 0.5f); if (myCurVal == curLabelValue) { outVol->setValue(outbox.getValue(newList[base] - extrema[0], newList[base + 1] - extrema[2], newList[base + 2] - extrema[4], 0, c), newList[base], newList[base + 1], newList[base + 2], 0, c); } else { float sum = 0.0f, weightsum = 0.0f;//coded in-place for now, its a special restricted case of volume dilate, copied out of nonorth volume smoothing int i = newList[base], j = newList[base + 1], k = newList[base + 2];//special casing orthogonal would be faster, but harder to follow/debug, and more code int imin = i - irange, imax = i + irange + 1;//one-after array size convention if (imin < 0) imin = 0; if (imax > myDims[0]) imax = myDims[0]; int jmin = j - jrange, jmax = j + jrange + 1; if (jmin < 0) jmin = 0; if (jmax > myDims[1]) jmax = myDims[1]; int kmin = k - krange, kmax = k + krange + 1; if (kmin < 0) kmin = 0; if (kmax > myDims[2]) kmax = myDims[2]; Vector3D kscratch, jscratch, iscratch; for (int kkern = kmin; kkern < kmax; ++kkern) { kscratch = kvec * (kkern - k); int64_t kindpart = kkern * myDims[1]; for (int jkern = jmin; jkern < jmax; ++jkern) { jscratch = kscratch + jvec * (jkern - j); int64_t jindpart = (kindpart + jkern) * myDims[0]; for (int ikern = imin; ikern < imax; ++ikern) { int64_t thisIndex = jindpart + ikern;//somewhat optimized index computation, could remove some integer multiplies, but there aren't that many int curVal = (int)floor(labelFrame[thisIndex] + 0.5f); if (curVal == curLabelValue) { iscratch = jscratch + ivec * (ikern - i); float tempf = iscratch.length(); float weight = exp(tempf * tempf * kernelMult); sum += weight * inFrame[thisIndex]; weightsum += weight; } } } } if (weightsum != 0.0f) { outVol->setValue(sum / weightsum, newList[base], newList[base + 1], newList[base + 2], 0, c); }//should already be 0, so don't need to handle the else } } } } } } } void AlgorithmVolumeParcelResampling::resampleFixZeros(LevelProgress& myProgress, const vector >& matchedLabels, const vector >& voxelLists, const VolumeFile* inVol, const VolumeFile* curLabel, const VolumeFile* newLabel, const float& kernel, VolumeFile* outVol, const int& subvolNum) { float kernBox = kernel * 3.0f; vector > volSpace = inVol->getSform();//copied from volume smoothing, perhaps this should be in a convenience method in VolumeFile Vector3D ivec, jvec, kvec, origin, ijorth, jkorth, kiorth; ivec[0] = volSpace[0][0]; jvec[0] = volSpace[0][1]; kvec[0] = volSpace[0][2]; origin[0] = volSpace[0][3];//needs to be this verbose because the axis and origin vectors are column vectors ivec[1] = volSpace[1][0]; jvec[1] = volSpace[1][1]; kvec[1] = volSpace[1][2]; origin[1] = volSpace[1][3];//while vector > is a column of row vectors ivec[2] = volSpace[2][0]; jvec[2] = volSpace[2][1]; kvec[2] = volSpace[2][2]; origin[2] = volSpace[2][3]; ijorth = ivec.cross(jvec).normal();//find the bounding box that encloses a sphere of radius kernBox jkorth = jvec.cross(kvec).normal(); kiorth = kvec.cross(ivec).normal(); int irange = (int)floor(abs(kernBox / ivec.dot(jkorth))); int jrange = (int)floor(abs(kernBox / jvec.dot(kiorth))); int krange = (int)floor(abs(kernBox / kvec.dot(ijorth))); if (irange < 1) irange = 1;//don't underflow if (jrange < 1) jrange = 1; if (krange < 1) krange = 1; map curLabelReverse, newLabelReverse; int numLabels = (int)matchedLabels.size(); for (int i = 0; i < numLabels; ++i) { curLabelReverse[matchedLabels[i].first] = i; newLabelReverse[matchedLabels[i].second] = i; } vector myDims; inVol->getDimensions(myDims); if (subvolNum == -1) { outVol->reinitialize(inVol->getOriginalDimensions(), inVol->getSform(), myDims[4], inVol->getType(), inVol->m_header); } else { vector newDims = inVol->getOriginalDimensions(); newDims.resize(3);//discard nonspatial dimentions outVol->reinitialize(newDims, inVol->getSform(), myDims[4], inVol->getType(), inVol->m_header); } outVol->setValueAllVoxels(0.0f); const GiftiLabelTable* curTable = curLabel->getMapLabelTable(0); for (int whichList = 0; whichList < numLabels; ++whichList) { int curLabelValue = matchedLabels[whichList].first; int newLabelValue = matchedLabels[whichList].second; myProgress.reportProgress(((float)whichList) / numLabels); myProgress.setTask("Processing parcel " + curTable->getLabelName(curLabelValue)); const vector& thisList = voxelLists[whichList]; int64_t listSize = (int64_t)thisList.size(); if (listSize > 2)//NOTE: this should NEVER be something other than a multiple of 3, but check against what we will actually access anyway { int extrema[6] = { thisList[0], thisList[0], thisList[1], thisList[1], thisList[2], thisList[2] }; for (int64_t base = 3; base < listSize; base += 3) { if (thisList[base] < extrema[0]) extrema[0] = thisList[base]; if (thisList[base] > extrema[1]) extrema[1] = thisList[base]; if (thisList[base + 1] < extrema[2]) extrema[2] = thisList[base + 1]; if (thisList[base + 1] > extrema[3]) extrema[3] = thisList[base + 1]; if (thisList[base + 2] < extrema[4]) extrema[4] = thisList[base + 2]; if (thisList[base + 2] > extrema[5]) extrema[5] = thisList[base + 2]; } vector boxdims; boxdims.push_back(extrema[1] - extrema[0] + 1); boxdims.push_back(extrema[3] - extrema[2] + 1); boxdims.push_back(extrema[5] - extrema[4] + 1); VolumeFile roibox(boxdims, inVol->getSform()); roibox.setValueAllVoxels(0.0f); vector newList;//make the separate new list, so we don't need to test the label volume for (int64_t base = 0; base < listSize; base += 3)//could do this when we make the merged list...maybe use member variables to cut the argument clutter { int newvalue = (int)floor(newLabel->getValue(thisList[base], thisList[base + 1], thisList[base + 2]) + 0.5f); if (newvalue == newLabelValue) { newList.push_back(thisList[base]); newList.push_back(thisList[base + 1]); newList.push_back(thisList[base + 2]); } } int64_t newListSize = (int64_t)newList.size(); if (subvolNum == -1) { boxdims.push_back(myDims[3]); VolumeFile inbox(boxdims, inVol->getSform(), myDims[4]), outbox; for (int c = 0; c < myDims[4]; ++c) { for (int s = 0; s < myDims[3]; ++s) { for (int64_t base = 0; base < listSize; base += 3) { if (s == 0 && c == 0)//smooth within BOTH labels, but only copy in from current label { roibox.setValue(1.0f, thisList[base] - extrema[0], thisList[base + 1] - extrema[2], thisList[base + 2] - extrema[4]); } int curValue = (int)floor(curLabel->getValue(thisList[base], thisList[base + 1], thisList[base + 2]) + 0.5f); if (curValue == curLabelValue) { inbox.setValue(inVol->getValue(thisList[base], thisList[base + 1], thisList[base + 2], s, c), thisList[base] - extrema[0], thisList[base + 1] - extrema[2], thisList[base + 2] - extrema[4], s, c); } else { inbox.setValue(0.0f, thisList[base] - extrema[0], thisList[base + 1] - extrema[2], thisList[base + 2] - extrema[4], s, c); } } } } AlgorithmVolumeSmoothing(NULL, &inbox, kernel, &outbox, &roibox, true); float kernelMult = -1.0f / kernel / kernel / 2.0f;//precompute the part of the kernel function that doesn't change VolumeFile* current = &outbox, *next = &inbox, *tempvol;//reuse inbox as scratch space for iterated dilation const float* labelFrame = newLabel->getFrame(); int fixIter; for (fixIter = 0; fixIter < FIX_ZEROS_POST_ITERATIONS; ++fixIter) { bool again = false; for (int c = 0; c < myDims[4]; ++c)//since fix zeros smoothing doesn't consider components as multidimensional datatypes, neither should this { for (int s = 0; s < myDims[3]; ++s) { for (int64_t base = 0; base < newListSize; base += 3) { float curVal = current->getValue(newList[base] - extrema[0], newList[base + 1] - extrema[2], newList[base + 2] - extrema[4], s, c); if (curVal == 0.0f) { float sum = 0.0f, weightsum = 0.0f;//coded in-place for now, its a special restricted case of volume dilate, copied out of nonorth volume smoothing int i = newList[base], j = newList[base + 1], k = newList[base + 2];//special casing orthogonal would be faster, but harder to follow/debug, and more code int imin = i - irange, imax = i + irange + 1;//one-after array size convention if (imin < 0) imin = 0; if (imax > myDims[0]) imax = myDims[0]; int jmin = j - jrange, jmax = j + jrange + 1; if (jmin < 0) jmin = 0; if (jmax > myDims[1]) jmax = myDims[1]; int kmin = k - krange, kmax = k + krange + 1; if (kmin < 0) kmin = 0; if (kmax > myDims[2]) kmax = myDims[2]; Vector3D kscratch, jscratch, iscratch; for (int kkern = kmin; kkern < kmax; ++kkern) { kscratch = kvec * (kkern - k); int64_t kindpart = kkern * myDims[1]; for (int jkern = jmin; jkern < jmax; ++jkern) { jscratch = kscratch + jvec * (jkern - j); int64_t jindpart = (kindpart + jkern) * myDims[0]; for (int ikern = imin; ikern < imax; ++ikern) { int64_t thisIndex = jindpart + ikern;//somewhat optimized index computation, could remove some integer multiplies, but there aren't that many int tempi = (int)floor(labelFrame[thisIndex] + 0.5f); if (tempi == curLabelValue) { float dataVal = current->getValue(ikern - extrema[0], jkern - extrema[2], kkern - extrema[4], s, c); if (dataVal != 0.0f) { iscratch = jscratch + ivec * (ikern - i); float tempf = iscratch.length(); float weight = exp(tempf * tempf * kernelMult); sum += weight * dataVal; weightsum += weight; } } } } } if (weightsum != 0.0f) { next->setValue(sum / weightsum, newList[base] - extrema[0], newList[base + 1] - extrema[2], newList[base + 2] - extrema[4], s, c); } else { again = true; next->setValue(0.0f, newList[base] - extrema[0], newList[base + 1] - extrema[2], newList[base + 2] - extrema[4], s, c); } } else { next->setValue(curVal, newList[base] - extrema[0], newList[base + 1] - extrema[2], newList[base + 2] - extrema[4], s, c); } } } } tempvol = current; current = next; next = tempvol; if (!again) break; } if (fixIter == FIX_ZEROS_POST_ITERATIONS) { const GiftiLabelTable* curLabelTable = curLabel->getMapLabelTable(0); CaretLogWarning("unable to fix all zeros in parcel " + curLabelTable->getLabelName(curLabelValue)); } for (int c = 0; c < myDims[4]; ++c)//copy the final result into the output valume { for (int s = 0; s < myDims[3]; ++s) { for (int64_t base = 0; base < newListSize; base += 3) { outVol->setValue(current->getValue(newList[base] - extrema[0], newList[base + 1] - extrema[2], newList[base + 2] - extrema[4], s, c), newList[base], newList[base + 1], newList[base + 2], s, c); } } } } else { VolumeFile inbox(boxdims, inVol->getSform(), myDims[4]), outbox; for (int c = 0; c < myDims[4]; ++c) { for (int64_t base = 0; base < listSize; base += 3) { if (c == 0)//smooth within BOTH labels, but only copy in from current label { roibox.setValue(1.0f, thisList[base] - extrema[0], thisList[base + 1] - extrema[2], thisList[base + 2] - extrema[4]); } int curValue = (int)floor(curLabel->getValue(thisList[base], thisList[base + 1], thisList[base + 2]) + 0.5f); if (curValue == curLabelValue) { inbox.setValue(inVol->getValue(thisList[base], thisList[base + 1], thisList[base + 2], subvolNum, c), thisList[base] - extrema[0], thisList[base + 1] - extrema[2], thisList[base + 2] - extrema[4], 0, c); } } } AlgorithmVolumeSmoothing(NULL, &inbox, kernel, &outbox, &roibox, true); float kernelMult = -1.0f / kernel / kernel / 2.0f;//precompute the part of the kernel function that doesn't change int fixIter; VolumeFile* current = &outbox, *next = &inbox, *tempvol;//reuse inbox as scratch space for iterated dilation const float* labelFrame = newLabel->getFrame(); for (fixIter = 0; fixIter < FIX_ZEROS_POST_ITERATIONS; ++fixIter) { bool again = false; for (int c = 0; c < myDims[4]; ++c)//since fix zeros smoothing doesn't consider components as multidimensional datatypes, neither should this { for (int64_t base = 0; base < newListSize; base += 3) { float curVal = current->getValue(newList[base] - extrema[0], newList[base + 1] - extrema[2], newList[base + 2] - extrema[4], 0, c); if (curVal == 0.0f) { float sum = 0.0f, weightsum = 0.0f;//coded in-place for now, its a special restricted case of volume dilate, copied out of nonorth volume smoothing int i = newList[base], j = newList[base + 1], k = newList[base + 2];//special casing orthogonal would be faster, but harder to follow/debug, and more code int imin = i - irange, imax = i + irange + 1;//one-after array size convention if (imin < 0) imin = 0; if (imax > myDims[0]) imax = myDims[0]; int jmin = j - jrange, jmax = j + jrange + 1; if (jmin < 0) jmin = 0; if (jmax > myDims[1]) jmax = myDims[1]; int kmin = k - krange, kmax = k + krange + 1; if (kmin < 0) kmin = 0; if (kmax > myDims[2]) kmax = myDims[2]; Vector3D kscratch, jscratch, iscratch; for (int kkern = kmin; kkern < kmax; ++kkern) { kscratch = kvec * (kkern - k); int64_t kindpart = kkern * myDims[1]; for (int jkern = jmin; jkern < jmax; ++jkern) { jscratch = kscratch + jvec * (jkern - j); int64_t jindpart = (kindpart + jkern) * myDims[0]; for (int ikern = imin; ikern < imax; ++ikern) { int64_t thisIndex = jindpart + ikern;//somewhat optimized index computation, could remove some integer multiplies, but there aren't that many int tempi = (int)floor(labelFrame[thisIndex] + 0.5f); if (tempi == curLabelValue) { float dataVal = current->getValue(ikern - extrema[0], jkern - extrema[2], kkern - extrema[4], 0, c); if (dataVal != 0.0f) { iscratch = jscratch + ivec * (ikern - i); float tempf = iscratch.length(); float weight = exp(tempf * tempf * kernelMult); sum += weight * dataVal; weightsum += weight; } } } } } if (weightsum != 0.0f) { next->setValue(sum / weightsum, newList[base] - extrema[0], newList[base + 1] - extrema[2], newList[base + 2] - extrema[4], 0, c); } else { again = true; next->setValue(0.0f, newList[base] - extrema[0], newList[base + 1] - extrema[2], newList[base + 2] - extrema[4], 0, c); } } else { next->setValue(curVal, newList[base] - extrema[0], newList[base + 1] - extrema[2], newList[base + 2] - extrema[4], 0, c); } } } tempvol = current; current = next; next = tempvol; if (!again) break; } if (fixIter == FIX_ZEROS_POST_ITERATIONS) { const GiftiLabelTable* curLabelTable = curLabel->getMapLabelTable(0); CaretLogWarning("unable to fix all zeros in parcel " + curLabelTable->getLabelName(curLabelValue)); } for (int c = 0; c < myDims[4]; ++c)//copy the final result into the output valume { for (int64_t base = 0; base < newListSize; base += 3) { outVol->setValue(current->getValue(newList[base] - extrema[0], newList[base + 1] - extrema[2], newList[base + 2] - extrema[4], 0, c), newList[base], newList[base + 1], newList[base + 2], 0, c); } } } } } } float AlgorithmVolumeParcelResampling::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeParcelResampling::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeParcelResampling.h000066400000000000000000000054431360521144700272010ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_PARCEL_RESAMPLING_H__ #define __ALGORITHM_VOLUME_PARCEL_RESAMPLING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmVolumeParcelResampling : public AbstractAlgorithm { AlgorithmVolumeParcelResampling(); void matchLabels(const caret::VolumeFile* curLabel, const caret::VolumeFile* newLabel, std::vector >& matchedLabels); void generateVoxelLists(const std::vector >& matchedLabels, const VolumeFile* curLabel, const VolumeFile* newLabel, std::vector >& voxelLists); void resampleFixZeros(LevelProgress& myProgress, const std::vector >& matchedLabels, const std::vector >& voxelLists, const VolumeFile* inVol, const VolumeFile* curLabel, const caret::VolumeFile* newLabel, const float& kernel, VolumeFile* outVol, const int& subvolNum); void resample(LevelProgress& myProgress, const std::vector >& matchedLabels, const std::vector >& voxelLists, const VolumeFile* inVol, const VolumeFile* curLabel, const caret::VolumeFile* newLabel, const float& kernel, VolumeFile* outVol, const int& subvolNum); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeParcelResampling(ProgressObject* myProgObj, const VolumeFile* inVol, const VolumeFile* curLabel, const VolumeFile* newLabel, const float& kernel, VolumeFile* outVol, const bool& fixZeros = false, const int& subvolNum = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeParcelResampling; } #endif //__ALGORITHM_VOLUME_PARCEL_RESAMPLING_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeParcelResamplingGeneric.cxx000066400000000000000000000665141360521144700310570ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeParcelResamplingGeneric.h" #include "AlgorithmException.h" #include "VolumeFile.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "Vector3D.h" #include "CaretOMP.h" #include #include #include #include using namespace caret; using namespace std; const int FIX_ZEROS_POST_ITERATIONS = 10;//number of times to do the "find remaining zeros and try to fill" code before giving up when -fix-zeros is specified AString AlgorithmVolumeParcelResamplingGeneric::getCommandSwitch() { return "-volume-parcel-resampling-generic"; } AString AlgorithmVolumeParcelResamplingGeneric::getShortDescription() { return "SMOOTH AND RESAMPLE VOLUME PARCELS FROM DIFFERENT VOLUME SPACE"; } OperationParameters* AlgorithmVolumeParcelResamplingGeneric::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume-in", "the input data volume"); ret->addVolumeParameter(2, "cur-parcels", "label volume of where the parcels currently are"); ret->addVolumeParameter(3, "new-parcels", "label volume of where the parcels should be"); ret->addDoubleParameter(4, "kernel", "gaussian kernel sigma to smooth by during resampling"); ret->addVolumeOutputParameter(5, "volume-out", "output volume"); ret->createOptionalParameter(6, "-fix-zeros", "treat zero values as not being data"); OptionalParameter* subvolSelect = ret->createOptionalParameter(7, "-subvolume", "select a single subvolume as input"); subvolSelect->addStringParameter(1, "subvol", "the subvolume number or name"); ret->setHelpText( AString("Smooths and resamples the region inside each label in cur-parcels to the region of the same label name in new-parcels. ") + "Any voxels in the output label region but outside the input label region will be extrapolated from nearby data. " + "The -fix-zeros option causes the smoothing to not use an input value if it is zero, but still write a smoothed value to the voxel, and after smoothing " + "is complete, it will check for any remaining values of zero, and fill them in with extrapolated values. " + "The output volume will use the volume space of new-parcels, which does not need to be in the same volume space as the input." ); return ret; } void AlgorithmVolumeParcelResamplingGeneric::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* inVol = myParams->getVolume(1); VolumeFile* curLabel = myParams->getVolume(2); VolumeFile* newLabel = myParams->getVolume(3); float kernel = (float)myParams->getDouble(4); VolumeFile* outVol = myParams->getOutputVolume(5); bool fixZeros = false; if (myParams->getOptionalParameter(6)->m_present) { fixZeros = true; } OptionalParameter* subvolSelect = myParams->getOptionalParameter(7); int subvolNum = -1; if (subvolSelect->m_present) { subvolNum = (int)inVol->getMapIndexFromNameOrNumber(subvolSelect->getString(1)); if (subvolNum < 0) { throw AlgorithmException("invalid subvolume specified"); } } AlgorithmVolumeParcelResamplingGeneric(myProgObj, inVol, curLabel, newLabel, kernel, outVol, fixZeros, subvolNum); } AlgorithmVolumeParcelResamplingGeneric::AlgorithmVolumeParcelResamplingGeneric(ProgressObject* myProgObj, const VolumeFile* inVol, const VolumeFile* curLabel, const VolumeFile* newLabel, const float& kernel, VolumeFile* outVol, const bool& fixZeros, const int& subvolNum) : AbstractAlgorithm(myProgObj) { CaretAssert(inVol != NULL); CaretAssert(curLabel != NULL); CaretAssert(newLabel != NULL); CaretAssert(outVol != NULL); if (!inVol->matchesVolumeSpace(curLabel)) { throw AlgorithmException("input label volume must be in the same space as input data volume"); } if (curLabel->getType() != SubvolumeAttributes::LABEL || newLabel->getType() != SubvolumeAttributes::LABEL) { throw AlgorithmException("parcel volumes are not of type label"); } if (subvolNum < -1 || subvolNum >= inVol->getNumberOfMaps()) { throw AlgorithmException("invalid subvolume specified"); } vector > matchedLabels; matchLabels(curLabel, newLabel, matchedLabels); if (matchedLabels.size() == 0) { throw AlgorithmException("no matching labels"); } vector > voxelLists; generateVoxelLists(matchedLabels, newLabel, voxelLists); int voxelListsSize = (int)voxelLists.size(); LevelProgress myProgress(myProgObj); float kernBox = kernel * 3.0f; float kernelMult = -1.0f / kernel / kernel / 2.0f;//precompute the part of the kernel function that doesn't change vector > newVolSpace = newLabel->getSform();//copied from volume smoothing, perhaps this should be in a convenience method in VolumeFile Vector3D ivecnew, jvecnew, kvecnew, ijorthnew, jkorthnew, kiorthnew; ivecnew[0] = newVolSpace[0][0]; jvecnew[0] = newVolSpace[0][1]; kvecnew[0] = newVolSpace[0][2]; ivecnew[1] = newVolSpace[1][0]; jvecnew[1] = newVolSpace[1][1]; kvecnew[1] = newVolSpace[1][2]; ivecnew[2] = newVolSpace[2][0]; jvecnew[2] = newVolSpace[2][1]; kvecnew[2] = newVolSpace[2][2]; ijorthnew = ivecnew.cross(jvecnew).normal();//find the bounding box that encloses a sphere of radius kernBox jkorthnew = jvecnew.cross(kvecnew).normal(); kiorthnew = kvecnew.cross(ivecnew).normal(); float irangenew = abs(kernBox / ivecnew.dot(jkorthnew));//note, these are in index space float jrangenew = abs(kernBox / jvecnew.dot(kiorthnew)); float krangenew = abs(kernBox / kvecnew.dot(ijorthnew)); if (irangenew < 1.0f) irangenew = 1.0f;//don't underflow, always use at least a 3x3x3 box if (jrangenew < 1.0f) jrangenew = 1.0f; if (krangenew < 1.0f) krangenew = 1.0f; vector > volSpace = inVol->getSform();//copied from volume smoothing, perhaps this should be in a convenience method in VolumeFile Vector3D ivec, jvec, kvec, ijorth, jkorth, kiorth; ivec[0] = volSpace[0][0]; jvec[0] = volSpace[0][1]; kvec[0] = volSpace[0][2];//needs to be this verbose because the axis and origin vectors are column vectors ivec[1] = volSpace[1][0]; jvec[1] = volSpace[1][1]; kvec[1] = volSpace[1][2];//while vector > is a column of row vectors ivec[2] = volSpace[2][0]; jvec[2] = volSpace[2][1]; kvec[2] = volSpace[2][2]; ijorth = ivec.cross(jvec).normal();//find the bounding box that encloses a sphere of radius kernBox jkorth = jvec.cross(kvec).normal(); kiorth = kvec.cross(ivec).normal(); float irange = abs(kernBox / ivec.dot(jkorth));//note, these are in index space float jrange = abs(kernBox / jvec.dot(kiorth)); float krange = abs(kernBox / kvec.dot(ijorth)); if (irange < 1.0f) irange = 1.0f;//don't underflow, always use at least a 3x3x3 box if (jrange < 1.0f) jrange = 1.0f; if (krange < 1.0f) krange = 1.0f; vector myDims; inVol->getDimensions(myDims); vector newDims; newLabel->getDimensions(newDims); if (subvolNum == -1) { vector outDims = newLabel->getOriginalDimensions(), inDims = inVol->getOriginalDimensions(); outDims.resize(3); for (int i = 3; i < (int)inDims.size(); ++i) { outDims.push_back(inDims[i]); } outVol->reinitialize(outDims, newLabel->getSform(), myDims[4], inVol->getType(), inVol->m_header); } else { vector outDims = newLabel->getOriginalDimensions(); outDims.resize(3);//discard nonspatial dimentions outVol->reinitialize(outDims, newLabel->getSform(), myDims[4], inVol->getType(), inVol->m_header); } outVol->setValueAllVoxels(0.0f); const float* labelFrame = curLabel->getFrame(); const float* newLabelFrame = newLabel->getFrame(); CaretArray scratchFrame(newDims[0] * newDims[1] * newDims[2]), scratchFrame2(newDims[0] * newDims[1] * newDims[2]), tempFrame; for (int whichList = 0; whichList < voxelListsSize; ++whichList) { int curLabelValue = matchedLabels[whichList].first; int newLabelValue = matchedLabels[whichList].second; vector& thisList = voxelLists[whichList]; int64_t listSize = (int64_t)thisList.size(); if (subvolNum == -1) { for (int c = 0; c < myDims[4]; ++c) { for (int s = 0; s < myDims[3]; ++s) { const float* inFrame = inVol->getFrame(s, c); //#pragma omp CARET_PARFOR schedule(dynamic) for (int64_t base = 0; base < listSize; base += 3) { float sum = 0.0f, weightsum = 0.0f; int i = thisList[base], j = thisList[base + 1], k = thisList[base + 2]; float xyz[3], curijk[3]; newLabel->indexToSpace(i, j, k, xyz); inVol->spaceToIndex(xyz, curijk); int imin = (int)ceil(curijk[0] - irange), imax = (int)floor(curijk[0] + irange) + 1; if (imin < 0) imin = 0; if (imax > myDims[0]) imax = myDims[0]; int jmin = (int)ceil(curijk[1] - jrange), jmax = (int)floor(curijk[1] + jrange) + 1; if (jmin < 0) jmin = 0; if (jmax > myDims[1]) jmax = myDims[1]; int kmin = (int)ceil(curijk[2] - krange), kmax = (int)floor(curijk[2] + krange) + 1; if (kmin < 0) kmin = 0; if (kmax > myDims[2]) kmax = myDims[2]; for (int kkern = kmin; kkern < kmax; ++kkern) { Vector3D kscratch = kvec * (kkern - curijk[2]); int64_t kindpart = kkern * myDims[1]; for (int jkern = jmin; jkern < jmax; ++jkern) { Vector3D jscratch = kscratch + jvec * (jkern - curijk[1]); int64_t jindpart = (kindpart + jkern) * myDims[0]; for (int ikern = imin; ikern < imax; ++ikern) { int64_t thisIndex = jindpart + ikern;//somewhat optimized index computation, could remove some integer multiplies, but there aren't that many int curVal = (int)floor(labelFrame[thisIndex] + 0.5f); float dataVal = inFrame[thisIndex]; if (curVal == curLabelValue && (!fixZeros || dataVal != 0.0f)) { Vector3D iscratch = jscratch + ivec * (ikern - curijk[0]); float tempf = iscratch.length(); float weight = exp(tempf * tempf * kernelMult); sum += weight * dataVal; weightsum += weight; } } } } if (weightsum != 0.0f) { scratchFrame[outVol->getIndex(i, j, k)] = sum / weightsum; } else { scratchFrame[outVol->getIndex(i, j, k)] = 0.0f; } } if (fixZeros) { int fixIter; for (fixIter = 0; fixIter < FIX_ZEROS_POST_ITERATIONS; ++fixIter) { bool again = false; //#pragma omp CARET_PARFOR schedule(dynamic) for (int64_t base = 0; base < listSize; base += 3) { int i = thisList[base], j = thisList[base + 1], k = thisList[base + 2]; int64_t outIndex = outVol->getIndex(i, j, k); float dataVal = scratchFrame[outIndex]; if (dataVal == 0.0f) { float sum = 0.0f, weightsum = 0.0f; int imin = (int)ceil(i - irangenew), imax = (int)floor(i + irangenew) + 1; if (imin < 0) imin = 0; if (imax > newDims[0]) imax = newDims[0]; int jmin = (int)ceil(j - jrangenew), jmax = (int)floor(j + jrangenew) + 1; if (jmin < 0) jmin = 0; if (jmax > newDims[1]) jmax = newDims[1]; int kmin = (int)ceil(k - krangenew), kmax = (int)floor(k + krangenew) + 1; if (kmin < 0) kmin = 0; if (kmax > newDims[2]) kmax = newDims[2]; for (int kkern = kmin; kkern < kmax; ++kkern) { Vector3D kscratch = kvecnew * (kkern - k); int64_t kindpart = kkern * newDims[1]; for (int jkern = jmin; jkern < jmax; ++jkern) { Vector3D jscratch = kscratch + jvecnew * (jkern - j); int64_t jindpart = (kindpart + jkern) * newDims[0]; for (int ikern = imin; ikern < imax; ++ikern) { int64_t thisIndex = jindpart + ikern;//somewhat optimized index computation, could remove some integer multiplies, but there aren't that many int newVal = (int)floor(newLabelFrame[thisIndex] + 0.5f); float dataVal = scratchFrame[thisIndex]; if (newVal == newLabelValue && (!fixZeros || dataVal != 0.0f)) { Vector3D iscratch = jscratch + ivecnew * (ikern - i); float tempf = iscratch.length(); float weight = exp(tempf * tempf * kernelMult); sum += weight * dataVal; weightsum += weight; } } } } if (weightsum != 0.0f) { scratchFrame2[outIndex] = sum / weightsum; } else { again = true; scratchFrame2[outIndex] = 0.0f; } } else { scratchFrame2[outIndex] = scratchFrame[outIndex]; } } tempFrame = scratchFrame;//this is just pointer swapping, CaretArray is not like vector scratchFrame = scratchFrame2; scratchFrame2 = tempFrame; if (!again) break; } if (fixIter == FIX_ZEROS_POST_ITERATIONS) { const GiftiLabelTable* curLabelTable = curLabel->getMapLabelTable(0); CaretLogWarning("unable to fix all zeros in parcel " + curLabelTable->getLabelName(curLabelValue)); } } for (int64_t base = 0; base < listSize; base += 3) { int i = thisList[base], j = thisList[base + 1], k = thisList[base + 2]; int64_t outIndex = outVol->getIndex(i, j, k); outVol->setValue(scratchFrame[outIndex], i, j, k, s, c); } } } } else { for (int c = 0; c < myDims[4]; ++c) { const float* inFrame = inVol->getFrame(subvolNum, c); #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t base = 0; base < listSize; base += 3) { float sum = 0.0f, weightsum = 0.0f; int i = thisList[base], j = thisList[base + 1], k = thisList[base + 2]; float xyz[3], curijk[3]; newLabel->indexToSpace(i, j, k, xyz); inVol->spaceToIndex(xyz, curijk); int imin = (int)ceil(curijk[0] - irange), imax = (int)floor(curijk[0] + irange) + 1; if (imin < 0) imin = 0; if (imax > myDims[0]) imax = myDims[0]; int jmin = (int)ceil(curijk[1] - jrange), jmax = (int)floor(curijk[1] + jrange) + 1; if (jmin < 0) jmin = 0; if (jmax > myDims[1]) jmax = myDims[1]; int kmin = (int)ceil(curijk[2] - krange), kmax = (int)floor(curijk[2] + krange) + 1; if (kmin < 0) kmin = 0; if (kmax > myDims[2]) kmax = myDims[2]; for (int kkern = kmin; kkern < kmax; ++kkern) { Vector3D kscratch = kvec * (kkern - curijk[2]); int64_t kindpart = kkern * myDims[1]; for (int jkern = jmin; jkern < jmax; ++jkern) { Vector3D jscratch = kscratch + jvec * (jkern - curijk[1]); int64_t jindpart = (kindpart + jkern) * myDims[0]; for (int ikern = imin; ikern < imax; ++ikern) { int64_t thisIndex = jindpart + ikern;//somewhat optimized index computation, could remove some integer multiplies, but there aren't that many int newVal = (int)floor(newLabelFrame[thisIndex] + 0.5f); float dataVal = inFrame[thisIndex]; if (newVal == newLabelValue && (!fixZeros || dataVal != 0.0f)) { Vector3D iscratch = jscratch + ivec * (ikern - curijk[0]); float tempf = iscratch.length(); float weight = exp(tempf * tempf * kernelMult); sum += weight * dataVal; weightsum += weight; } } } } if (weightsum != 0.0f) { scratchFrame[outVol->getIndex(i, j, k)] = sum / weightsum; } else { scratchFrame[outVol->getIndex(i, j, k)] = 0.0f; } } if (fixZeros) { int fixIter; for (fixIter = 0; fixIter < FIX_ZEROS_POST_ITERATIONS; ++fixIter) { bool again = false; #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t base = 0; base < listSize; base += 3) { int i = thisList[base], j = thisList[base + 1], k = thisList[base + 2]; int64_t outIndex = outVol->getIndex(i, j, k); float dataVal = scratchFrame[outIndex]; if (dataVal == 0.0f) { float sum = 0.0f, weightsum = 0.0f; int imin = (int)ceil(i - irangenew), imax = (int)floor(i + irangenew) + 1; if (imin < 0) imin = 0; if (imax > newDims[0]) imax = newDims[0]; int jmin = (int)ceil(j - jrangenew), jmax = (int)floor(j + jrangenew) + 1; if (jmin < 0) jmin = 0; if (jmax > newDims[1]) jmax = newDims[1]; int kmin = (int)ceil(k - krangenew), kmax = (int)floor(k + krangenew) + 1; if (kmin < 0) kmin = 0; if (kmax > newDims[2]) kmax = newDims[2]; for (int kkern = kmin; kkern < kmax; ++kkern) { Vector3D kscratch = kvecnew * (kkern - k); int64_t kindpart = kkern * newDims[1]; for (int jkern = jmin; jkern < jmax; ++jkern) { Vector3D jscratch = kscratch + jvecnew * (jkern - j); int64_t jindpart = (kindpart + jkern) * newDims[0]; for (int ikern = imin; ikern < imax; ++ikern) { int64_t thisIndex = jindpart + ikern;//somewhat optimized index computation, could remove some integer multiplies, but there aren't that many int curVal = (int)floor(labelFrame[thisIndex] + 0.5f); float dataVal = scratchFrame[thisIndex]; if (curVal == curLabelValue && (!fixZeros || dataVal != 0.0f)) { Vector3D iscratch = jscratch + ivecnew * (ikern - i); float tempf = iscratch.length(); float weight = exp(tempf * tempf * kernelMult); sum += weight * dataVal; weightsum += weight; } } } } if (weightsum != 0.0f) { scratchFrame2[outIndex] = sum / weightsum; } else { again = true; scratchFrame2[outIndex] = 0.0f; } } else { scratchFrame2[outIndex] = scratchFrame[outIndex]; } } tempFrame = scratchFrame;//this is just pointer swapping, CaretArray is not like vector scratchFrame = scratchFrame2; scratchFrame2 = tempFrame; if (!again) break; } if (fixIter == FIX_ZEROS_POST_ITERATIONS) { const GiftiLabelTable* curLabelTable = curLabel->getMapLabelTable(0); CaretLogWarning("unable to fix all zeros in parcel " + curLabelTable->getLabelName(curLabelValue)); } } for (int64_t base = 0; base < listSize; base += 3) { int i = thisList[base], j = thisList[base + 1], k = thisList[base + 2]; int64_t outIndex = outVol->getIndex(i, j, k); outVol->setValue(scratchFrame[outIndex], i, j, k, 0, c); } } } } } void AlgorithmVolumeParcelResamplingGeneric::matchLabels(const VolumeFile* curLabel, const VolumeFile* newLabel, vector >& matchedLabels) { const GiftiLabelTable* curTable = curLabel->getMapLabelTable(0), *newTable = newLabel->getMapLabelTable(0); vector curKeys; curTable->getKeys(curKeys); int32_t curUnused = curTable->getUnassignedLabelKey(); for (int i = 0; i < (int)curKeys.size(); ++i) { if (curKeys[i] == curUnused) continue;//always skip the unassigned label if (newTable->getLabel(curKeys[i]) != NULL && newTable->getLabelName(curKeys[i]) == curTable->getLabelName(curKeys[i])) {//do the obvious check first matchedLabels.push_back(make_pair(curKeys[i], curKeys[i])); } else { int32_t newKey = newTable->getLabelKeyFromName(curTable->getLabelName(curKeys[i])); if (newKey != -1) { matchedLabels.push_back(make_pair(curKeys[i], newKey)); } } } } void AlgorithmVolumeParcelResamplingGeneric::generateVoxelLists(const vector >& matchedLabels, const VolumeFile* newLabel, vector >& voxelLists) { map newLabelReverse; for (int i = 0; i < (int)matchedLabels.size(); ++i) { newLabelReverse[matchedLabels[i].second] = i; } voxelLists.resize(matchedLabels.size()); vector myDims; newLabel->getDimensions(myDims); for (int64_t k = 0; k < myDims[2]; ++k) { for (int64_t j = 0; j < myDims[1]; ++j) { for (int64_t i = 0; i < myDims[0]; ++i) { int newValue = (int)floor(newLabel->getValue(i, j, k) + 0.5f); map::iterator newiter = newLabelReverse.find(newValue); if (newiter != newLabelReverse.end()) { voxelLists[newiter->second].push_back(i); voxelLists[newiter->second].push_back(j); voxelLists[newiter->second].push_back(k); } } } } } float AlgorithmVolumeParcelResamplingGeneric::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeParcelResamplingGeneric::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeParcelResamplingGeneric.h000066400000000000000000000043141360521144700304720ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_PARCEL_RESAMPLING_GENERIC_H__ #define __ALGORITHM_VOLUME_PARCEL_RESAMPLING_GENERIC_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmVolumeParcelResamplingGeneric : public AbstractAlgorithm { AlgorithmVolumeParcelResamplingGeneric(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); void matchLabels(const caret::VolumeFile* curLabel, const caret::VolumeFile* newLabel, std::vector >& matchedLabels); void generateVoxelLists(const std::vector >& matchedLabels, const VolumeFile* newLabel, std::vector >& voxelLists); public: AlgorithmVolumeParcelResamplingGeneric(ProgressObject* myProgObj, const VolumeFile* inVol, const VolumeFile* curLabel, const VolumeFile* newLabel, const float& kernel, VolumeFile* outVol, const bool& fixZeros = false, const int& subvolNum = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeParcelResamplingGeneric; } #endif //__ALGORITHM_VOLUME_PARCEL_RESAMPLING_GENERIC_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeParcelSmoothing.cxx000066400000000000000000000315771360521144700274310ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeParcelSmoothing.h" #include "AlgorithmException.h" #include "VolumeFile.h" #include "AlgorithmVolumeSmoothing.h" #include #include using namespace caret; using namespace std; AString AlgorithmVolumeParcelSmoothing::getCommandSwitch() { return "-volume-parcel-smoothing"; } AString AlgorithmVolumeParcelSmoothing::getShortDescription() { return "SMOOTH PARCELS IN A VOLUME SEPARATELY"; } OperationParameters* AlgorithmVolumeParcelSmoothing::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "data-volume", "the volume to smooth"); ret->addVolumeParameter(2, "label-volume", "a label volume containing the parcels to smooth"); ret->addDoubleParameter(3, "kernel", "the gaussian smoothing kernel sigma, in mm"); ret->addVolumeOutputParameter(4, "volume-out", "the output volume"); ret->createOptionalParameter(5, "-fix-zeros", "treat zero values as not being data"); OptionalParameter* subvolSelect = ret->createOptionalParameter(6, "-subvolume", "select a single subvolume to smooth"); subvolSelect->addStringParameter(1, "subvol", "the subvolume number or name"); ret->setHelpText( AString("The volume is smoothed within each label in the label volume using data only from within the label. Equivalent to ") + "running volume smoothing with ROIs matching each label separately, then adding the resulting volumes, but faster." ); return ret; } void AlgorithmVolumeParcelSmoothing::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* myVol = myParams->getVolume(1); VolumeFile* myLabelVol = myParams->getVolume(2); float myKernel = (float)myParams->getDouble(3); VolumeFile* myOutVol = myParams->getOutputVolume(4); OptionalParameter* fixZerosOpt = myParams->getOptionalParameter(5); bool fixZeros = fixZerosOpt->m_present; OptionalParameter* subvolSelect = myParams->getOptionalParameter(6); int subvolNum = -1; if (subvolSelect->m_present) { subvolNum = (int)myVol->getMapIndexFromNameOrNumber(subvolSelect->getString(1)); if (subvolNum < 0) { throw AlgorithmException("invalid subvolume specified"); } } AlgorithmVolumeParcelSmoothing(myProgObj, myVol, myLabelVol, myKernel, myOutVol, fixZeros, subvolNum); } AlgorithmVolumeParcelSmoothing::AlgorithmVolumeParcelSmoothing(ProgressObject* myProgObj, const VolumeFile* myVol, const VolumeFile* myLabelVol, const float& myKernel, VolumeFile* myOutVol, const bool& fixZeros, const int& subvolNum) : AbstractAlgorithm(myProgObj) { CaretAssert(myVol != NULL); CaretAssert(myOutVol != NULL); CaretAssert(myLabelVol != NULL); if (myLabelVol->getType() != SubvolumeAttributes::LABEL) { throw AlgorithmException("label volume doesn't contain label data"); } if (!myLabelVol->matchesVolumeSpace(myVol)) { throw AlgorithmException("input volume and label volume have different spacing"); } const GiftiLabelTable* myLabels = myLabelVol->getMapLabelTable(0); vector myKeys; myLabels->getKeys(myKeys); int numLabels = (int)myKeys.size(); map labelLookup;//reverse lookup, used to compact labels into the list of voxel lists for (int i = 0; i < numLabels; ++i) { labelLookup[myKeys[i]] = i; } int32_t unusedLabel = myLabels->getUnassignedLabelKey(); /*ProgressObject* subAlgProgress1 = NULL;//uncomment these if you use another algorithm inside here if (myProgObj != NULL) { subAlgProgress1 = myProgObj->addAlgorithm(AlgorithmInsertNameHere::getAlgorithmWeight());//TODO: set a vector of objects up via number of labels }//*/ LevelProgress myProgress(myProgObj);//this line sets the algorithm up to use the progress object, and will finish the progress object automatically when the algorithm terminates vector myDims; myVol->getDimensions(myDims); if (subvolNum < -1 || subvolNum >= myDims[3]) { throw AlgorithmException("invalid subvolume specified"); } vector > voxelLists;//build all lists in a single pass, allows some short circuits and less conversion to label integers voxelLists.resize(numLabels); for (int k = 0; k < myDims[2]; ++k) { for (int j = 0; j < myDims[1]; ++j) { for (int i = 0; i < myDims[0]; ++i) { int myValue = (int)floor(myLabelVol->getValue(i, j, k) + 0.5f); if (myValue == unusedLabel) continue;//skip the ??? label, whether it is included in the keys or not map::iterator search = labelLookup.find(myValue); if (search != labelLookup.end()) { int keyIndex = search->second; voxelLists[keyIndex].push_back(i); voxelLists[keyIndex].push_back(j); voxelLists[keyIndex].push_back(k); } } } } if (subvolNum == -1) { myOutVol->reinitialize(myVol->getOriginalDimensions(), myVol->getSform(), myDims[4], myVol->getType(), myVol->m_header); myOutVol->setValueAllVoxels(0.0f); for (int whichList = 0; whichList < numLabels; ++whichList) { const vector& thisList = voxelLists[whichList]; int64_t listSize = (int64_t)thisList.size(); if (listSize > 2)//NOTE: this should NEVER be something other than a multiple of 3, but check against what we will actually access anyway { int extrema[6] = { thisList[0], thisList[0], thisList[1], thisList[1], thisList[2], thisList[2] }; for (int64_t base = 3; base < listSize; base += 3) { if (thisList[base] < extrema[0]) extrema[0] = thisList[base]; if (thisList[base] > extrema[1]) extrema[1] = thisList[base]; if (thisList[base + 1] < extrema[2]) extrema[2] = thisList[base + 1]; if (thisList[base + 1] > extrema[3]) extrema[3] = thisList[base + 1]; if (thisList[base + 2] < extrema[4]) extrema[4] = thisList[base + 2]; if (thisList[base + 2] > extrema[5]) extrema[5] = thisList[base + 2]; } vector boxdims; boxdims.push_back(extrema[1] - extrema[0] + 1); boxdims.push_back(extrema[3] - extrema[2] + 1); boxdims.push_back(extrema[5] - extrema[4] + 1); VolumeFile roibox(boxdims, myVol->getSform()); boxdims.push_back(myDims[3]); VolumeFile inbox(boxdims, myVol->getSform(), myDims[4]), outbox; roibox.setValueAllVoxels(0.0f); for (int c = 0; c < myDims[4]; ++c) { for (int s = 0; s < myDims[3]; ++s) { for (int64_t base = 0; base < listSize; base += 3) { if (s == 0 && c == 0) roibox.setValue(1.0f, thisList[base] - extrema[0], thisList[base + 1] - extrema[2], thisList[base + 2] - extrema[4]); inbox.setValue(myVol->getValue(thisList[base], thisList[base + 1], thisList[base + 2], s, c), thisList[base] - extrema[0], thisList[base + 1] - extrema[2], thisList[base + 2] - extrema[4], s, c); } } } AlgorithmVolumeSmoothing(NULL, &inbox, myKernel, &outbox, &roibox, fixZeros); for (int c = 0; c < myDims[4]; ++c) { for (int s = 0; s < myDims[3]; ++s) { for (int64_t base = 0; base < listSize; base += 3) { myOutVol->setValue(outbox.getValue(thisList[base] - extrema[0], thisList[base + 1] - extrema[2], thisList[base + 2] - extrema[4], s, c), thisList[base], thisList[base + 1], thisList[base + 2], s, c); } } } } } for (int s = 0; s < myDims[3]; ++s) { myOutVol->setMapName(s, myVol->getMapName(s) + ", parcel smoothed " + AString::number(myKernel)); } } else { vector newDims = myVol->getOriginalDimensions(); newDims.resize(3);//discard non-spatial extra dimensions myOutVol->reinitialize(newDims, myVol->getSform(), myDims[4], myVol->getType(), myVol->m_header);//keep components myOutVol->setValueAllVoxels(0.0f); for (int whichList = 0; whichList < numLabels; ++whichList) { const vector& thisList = voxelLists[whichList]; int64_t listSize = (int64_t)thisList.size(); if (listSize > 2)//NOTE: this should NEVER be something other than a multiple of 3, but check against what we will actually access anyway { int extrema[6] = { thisList[0], thisList[0], thisList[1], thisList[1], thisList[2], thisList[2] }; for (int64_t base = 3; base < listSize; base += 3) { if (thisList[base] < extrema[0]) extrema[0] = thisList[base]; if (thisList[base] > extrema[1]) extrema[1] = thisList[base]; if (thisList[base + 1] < extrema[2]) extrema[2] = thisList[base + 1]; if (thisList[base + 1] > extrema[3]) extrema[3] = thisList[base + 1]; if (thisList[base + 2] < extrema[4]) extrema[4] = thisList[base + 2]; if (thisList[base + 2] > extrema[5]) extrema[5] = thisList[base + 2]; } vector boxdims; boxdims.push_back(extrema[1] - extrema[0] + 1); boxdims.push_back(extrema[3] - extrema[2] + 1); boxdims.push_back(extrema[5] - extrema[4] + 1); VolumeFile inbox(boxdims, myVol->getSform(), myDims[4]), roibox(boxdims, myVol->getSform()), outbox; roibox.setValueAllVoxels(0.0f); for (int c = 0; c < myDims[4]; ++c) { for (int64_t base = 0; base < listSize; base += 3) { if (c == 0) roibox.setValue(1.0f, thisList[base] - extrema[0], thisList[base + 1] - extrema[2], thisList[base + 2] - extrema[4]); inbox.setValue(myVol->getValue(thisList[base], thisList[base + 1], thisList[base + 2], subvolNum, c), thisList[base] - extrema[0], thisList[base + 1] - extrema[2], thisList[base + 2] - extrema[4], 0, c); } } AlgorithmVolumeSmoothing(NULL, &inbox, myKernel, &outbox, &roibox, fixZeros); for (int c = 0; c < myDims[4]; ++c) { for (int64_t base = 0; base < listSize; base += 3) { myOutVol->setValue(outbox.getValue(thisList[base] - extrema[0], thisList[base + 1] - extrema[2], thisList[base + 2] - extrema[4], 0, c), thisList[base], thisList[base + 1], thisList[base + 2], 0, c); } } } } myOutVol->setMapName(0, myVol->getMapName(subvolNum) + ", parcel smoothed " + AString::number(myKernel)); } } float AlgorithmVolumeParcelSmoothing::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeParcelSmoothing::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeParcelSmoothing.h000066400000000000000000000034741360521144700270510ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_PARCEL_SMOOTHING_H__ #define __ALGORITHM_VOLUME_PARCEL_SMOOTHING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmVolumeParcelSmoothing : public AbstractAlgorithm { AlgorithmVolumeParcelSmoothing(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeParcelSmoothing(ProgressObject* myProgObj, const VolumeFile* myVol, const VolumeFile* myLabelVol, const float& myKernel, VolumeFile* myOutVol, const bool& fixZeros = false, const int& subvolNum = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeParcelSmoothing; } #endif //__ALGORITHM_VOLUME_PARCEL_SMOOTHING_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeROIsFromExtrema.cxx000066400000000000000000000423511360521144700273110ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeROIsFromExtrema.h" #include "AlgorithmException.h" #include "CaretLogger.h" #include "FloatMatrix.h" #include "Vector3D.h" #include "VolumeFile.h" #include using namespace caret; using namespace std; AString AlgorithmVolumeROIsFromExtrema::getCommandSwitch() { return "-volume-rois-from-extrema"; } AString AlgorithmVolumeROIsFromExtrema::getShortDescription() { return "CREATE VOLUME ROI MAPS FROM EXTREMA MAPS"; } OperationParameters* AlgorithmVolumeROIsFromExtrema::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume-in", "the input volume"); ret->addDoubleParameter(2, "limit", "distance limit from voxel center, in mm"); ret->addVolumeOutputParameter(3, "volume-out", "the output volume"); OptionalParameter* gaussOpt = ret->createOptionalParameter(4, "-gaussian", "generate a gaussian kernel instead of a flat ROI"); gaussOpt->addDoubleParameter(1, "sigma", "the sigma for the gaussian kernel, in mm"); OptionalParameter* roiOption = ret->createOptionalParameter(5, "-roi", "select a region of interest to use"); roiOption->addVolumeParameter(1, "roi-volume", "the region to use"); OptionalParameter* overlapOpt = ret->createOptionalParameter(6, "-overlap-logic", "how to handle overlapping ROIs, default ALLOW"); overlapOpt->addStringParameter(1, "method", "the method of resolving overlaps"); OptionalParameter* subvolSelect = ret->createOptionalParameter(7, "-subvolume", "select a single subvolume to take the gradient of"); subvolSelect->addStringParameter(1, "subvol", "the subvolume number or name"); ret->setHelpText( AString("For each nonzero value in each map, make a map with an ROI around that location. ") + "If the -gaussian option is specified, then normalized gaussian kernels are output instead of ROIs. " + "The argument to -overlap-logic must be one of ALLOW, CLOSEST, or EXCLUDE. " + "ALLOW is the default, and means that ROIs are treated independently and may overlap. " + "CLOSEST means that ROIs may not overlap, and that no ROI contains vertices that are closer to a different seed vertex. " + "EXCLUDE means that ROIs may not overlap, and that any vertex within range of more than one ROI does not belong to any ROI." ); return ret; } void AlgorithmVolumeROIsFromExtrema::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* myVol = myParams->getVolume(1); float limit = (float)myParams->getDouble(2); VolumeFile* myVolOut = myParams->getOutputVolume(3); float sigma = -1.0f; OptionalParameter* gaussOpt = myParams->getOptionalParameter(4); if (gaussOpt->m_present) { sigma = (float)gaussOpt->getDouble(1); if (sigma <= 0.0f) { throw AlgorithmException("invalid sigma specified"); } } VolumeFile* myRoi = NULL; OptionalParameter* roiOption = myParams->getOptionalParameter(5); if (roiOption->m_present) { myRoi = roiOption->getVolume(1); } OverlapLogicEnum::Enum overlapType = OverlapLogicEnum::ALLOW; OptionalParameter* overlapOpt = myParams->getOptionalParameter(6); if (overlapOpt->m_present) { bool ok = false; overlapType = OverlapLogicEnum::fromName(overlapOpt->getString(1), &ok); if (!ok) throw AlgorithmException("unrecognized overlap method: " + overlapOpt->getString(1)); } OptionalParameter* subvolSelect = myParams->getOptionalParameter(7); int subvolNum = -1; if (subvolSelect->m_present) { subvolNum = (int)myVol->getMapIndexFromNameOrNumber(subvolSelect->getString(1)); if (subvolNum < 0) { throw AlgorithmException("invalid subvolume specified"); } } AlgorithmVolumeROIsFromExtrema(myProgObj, myVol, limit, myVolOut, sigma, myRoi, overlapType, subvolNum); } AlgorithmVolumeROIsFromExtrema::AlgorithmVolumeROIsFromExtrema(ProgressObject* myProgObj, const VolumeFile* myVol, const float& limit, VolumeFile* myVolOut, const float& sigma, const VolumeFile* myRoi, const OverlapLogicEnum::Enum& overlapType, const int& subvolNum) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const float* roiFrame = NULL; if (myRoi != NULL) { if (!myRoi->matchesVolumeSpace(myVol)) throw AlgorithmException("roi volume has a different volume space"); roiFrame = myRoi->getFrame(); } int64_t extremaCount = 0; vector myDims; myVol->getDimensions(myDims); int64_t frameSize = myDims[0] * myDims[1] * myDims[2]; if (subvolNum == -1) { if (roiFrame == NULL) { for (int c = 0; c < myDims[4]; ++c) { for (int b = 0; b < myDims[3]; ++b) { const float* frame = myVol->getFrame(b, c); for (int64_t index = 0; index < frameSize; ++index) { if (frame[index] != 0.0f) ++extremaCount; } } } } else { for (int c = 0; c < myDims[4]; ++c) { for (int b = 0; b < myDims[3]; ++b) { const float* frame = myVol->getFrame(b, c); for (int64_t index = 0; index < frameSize; ++index) { if (roiFrame[index] > 0.0f && frame[index] != 0.0f) ++extremaCount; } } } } } else { if (roiFrame == NULL) { for (int c = 0; c < myDims[4]; ++c) { const float* frame = myVol->getFrame(subvolNum, c); for (int64_t index = 0; index < frameSize; ++index) { if (frame[index] != 0.0f) ++extremaCount; } } } else { for (int c = 0; c < myDims[4]; ++c) { const float* frame = myVol->getFrame(subvolNum, c); for (int64_t index = 0; index < frameSize; ++index) { if (roiFrame[index] > 0.0f && frame[index] != 0.0f) ++extremaCount; } } } } if (extremaCount == 0) CaretLogWarning("no nonzero values in input volume file, output file will be empty"); Vector3D ivec, jvec, kvec, offset, ijorth, jkorth, kiorth; FloatMatrix(myVol->getVolumeSpace().getSform()).getAffineVectors(ivec, jvec, kvec, offset);//this should probably be made more accessible ijorth = ivec.cross(jvec).normal();//find the bounding box that encloses a sphere of radius limit jkorth = jvec.cross(kvec).normal(); kiorth = kvec.cross(ivec).normal(); int irange = (int)floor(abs(limit / ivec.dot(jkorth))); int jrange = (int)floor(abs(limit / jvec.dot(kiorth))); int krange = (int)floor(abs(limit / kvec.dot(ijorth))); Vector3D iscratch, jscratch, kscratch; vector stencil; vector stencildist; for (int k = -krange; k <= krange; ++k) { kscratch = kvec * k; for (int j = -jrange; j <= jrange; ++j) { jscratch = kscratch + jvec * j; for (int i = -irange; i <= irange; ++i) { iscratch = jscratch + ivec * i; float tempf = iscratch.length(); if (tempf <= limit) { stencil.push_back(i); stencil.push_back(j); stencil.push_back(k); stencildist.push_back(tempf); } } } } vector excludeDists(frameSize, -1.0f); vector excludeSources(frameSize, -1); vector > roiLists(extremaCount); int64_t mapCounter = 0; if (subvolNum == -1) { for (int c = 0; c < myDims[4]; ++c) { for (int b = 0; b < myDims[3]; ++b) { const float* data = myVol->getFrame(b, c); processFrame(data, excludeDists, excludeSources, roiLists, mapCounter, stencil, stencildist, roiFrame, overlapType, myVol->getVolumeSpace()); } } } else { for (int c = 0; c < myDims[4]; ++c) { const float* data = myVol->getFrame(subvolNum, c); processFrame(data, excludeDists, excludeSources, roiLists, mapCounter, stencil, stencildist, roiFrame, overlapType, myVol->getVolumeSpace()); } } CaretAssert(mapCounter == extremaCount); vector outDims = myDims; outDims.resize(4); outDims[3] = extremaCount; myVolOut->reinitialize(outDims, myVol->getSform(), 1, SubvolumeAttributes::ANATOMY, myVol->m_header); vector tempFrame(frameSize, 0.0f); if (sigma > 0.0f) { float gaussDenom = -0.5f / sigma / sigma; for (int64_t i = 0; i < mapCounter; ++i) { double accum = 0.0; map::iterator myEnd = roiLists[i].end(); for (map::iterator iter = roiLists[i].begin(); iter != myEnd; ++iter) { float gaussVal = exp(iter->second * iter->second * gaussDenom); accum += gaussVal; tempFrame[iter->first] = gaussVal;//initial kernel value } for (map::iterator iter = roiLists[i].begin(); iter != myEnd; ++iter) { tempFrame[iter->first] /= accum;//normalize } myVolOut->setFrame(tempFrame.data(), i); for (map::iterator iter = roiLists[i].begin(); iter != myEnd; ++iter) { tempFrame[iter->first] = 0.0f;//rezero changed values for next map } } } else { for (int64_t i = 0; i < mapCounter; ++i) { map::iterator myEnd = roiLists[i].end(); for (map::iterator iter = roiLists[i].begin(); iter != myEnd; ++iter) { tempFrame[iter->first] = 1.0f;//make roi } myVolOut->setFrame(tempFrame.data(), i); for (map::iterator iter = roiLists[i].begin(); iter != myEnd; ++iter) { tempFrame[iter->first] = 0.0f;//rezero changed values for next map } } } } void AlgorithmVolumeROIsFromExtrema::processFrame(const float* data, vector& excludeDists, vector& excludeSources, vector >& roiLists, int64_t& mapCounter, const vector& stencil, const vector& stencildist, const float* roiFrame, const OverlapLogicEnum::Enum& overlapType, const VolumeSpace& mySpace) { const int64_t* myDims = mySpace.getDims(); int stencilSize = (int)stencildist.size(); for (int k = 0; k < myDims[2]; ++k) { for (int j = 0; j < myDims[1]; ++j) { for (int i = 0; i < myDims[0]; ++i) { int64_t myIndex = mySpace.getIndex(i, j, k); if ((roiFrame == NULL || roiFrame[myIndex] > 0.0f) && data[myIndex] != 0.0f) { switch (overlapType) { case OverlapLogicEnum::ALLOW: if (roiFrame == NULL) { for (int s = 0; s < stencilSize; ++s) { int s3 = s * 3; const int thisVoxel[3] = { i + stencil[s3], j + stencil[s3 + 1], k + stencil[s3 + 2] }; if (mySpace.indexValid(thisVoxel)) { roiLists[mapCounter][mySpace.getIndex(thisVoxel)] = stencildist[s]; } } } else { for (int s = 0; s < stencilSize; ++s) { int s3 = s * 3; const int thisVoxel[3] = { i + stencil[s3], j + stencil[s3 + 1], k + stencil[s3 + 2] }; if (mySpace.indexValid(thisVoxel) && roiFrame[mySpace.getIndex(thisVoxel)] > 0.0f) { roiLists[mapCounter][mySpace.getIndex(thisVoxel)] = stencildist[s]; } } } break; case OverlapLogicEnum::CLOSEST: for (int s = 0; s < stencilSize; ++s) { int s3 = s * 3; const int thisVoxel[3] = { i + stencil[s3], j + stencil[s3 + 1], k + stencil[s3 + 2] }; if (mySpace.indexValid(thisVoxel) && (roiFrame == NULL || roiFrame[mySpace.getIndex(thisVoxel)] > 0.0f)) { int64_t thisIndex = mySpace.getIndex(thisVoxel); const float& thisDist = stencildist[s]; roiLists[mapCounter][thisIndex] = thisDist; if (excludeDists[thisIndex] < 0.0f) { excludeDists[thisIndex] = thisDist; excludeSources[thisIndex] = mapCounter; roiLists[mapCounter][thisIndex] = thisDist; } else { if (excludeDists[thisIndex] > thisDist) { roiLists[excludeSources[thisIndex]].erase(thisIndex); } excludeDists[thisIndex] = thisDist; excludeSources[thisIndex] = mapCounter; roiLists[mapCounter][thisIndex] = thisDist; } } } break; case OverlapLogicEnum::EXCLUDE: for (int s = 0; s < stencilSize; ++s) { int s3 = s * 3; const int thisVoxel[3] = { i + stencil[s3], j + stencil[s3 + 1], k + stencil[s3 + 2] }; if (mySpace.indexValid(thisVoxel) && (roiFrame == NULL || roiFrame[mySpace.getIndex(thisVoxel)] > 0.0f)) { int64_t thisIndex = mySpace.getIndex(thisVoxel); const float& thisDist = stencildist[s]; roiLists[mapCounter][thisIndex] = thisDist; if (excludeDists[thisIndex] < 0.0f) { excludeDists[thisIndex] = thisDist; excludeSources[thisIndex] = mapCounter; roiLists[mapCounter][thisIndex] = thisDist; } else { if (excludeSources[thisIndex] != -1) { roiLists[excludeSources[thisIndex]].erase(thisIndex); excludeSources[thisIndex] = -1; } } } } break; } ++mapCounter; } } } } } float AlgorithmVolumeROIsFromExtrema::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeROIsFromExtrema::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeROIsFromExtrema.h000066400000000000000000000046271360521144700267420ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_ROIS_FROM_EXTREMA_H__ #define __ALGORITHM_VOLUME_ROIS_FROM_EXTREMA_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "OverlapLogicEnum.h" #include "VolumeSpace.h" #include #include namespace caret { class AlgorithmVolumeROIsFromExtrema : public AbstractAlgorithm { AlgorithmVolumeROIsFromExtrema(); void processFrame(const float* data, std::vector& excludeDists, std::vector& excludeSouces, std::vector >& roiLists, int64_t& mapCounter, const std::vector& stencil, const std::vector& stencildist, const float* roiFrame, const OverlapLogicEnum::Enum& overlapType, const VolumeSpace& myDims); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeROIsFromExtrema(ProgressObject* myProgObj, const VolumeFile* myVol, const float& limit, VolumeFile* myVolOut, const float& sigma = -1.0f, const VolumeFile* myRoi = NULL, const OverlapLogicEnum::Enum& overlapType = OverlapLogicEnum::ALLOW, const int& subvolNum = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeROIsFromExtrema; } #endif //__ALGORITHM_VOLUME_ROIS_FROM_EXTREMA_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeReduce.cxx000066400000000000000000000151531360521144700255320ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeReduce.h" #include "AlgorithmException.h" #include "CaretLogger.h" #include "GiftiLabelTable.h" #include "ReductionOperation.h" #include "VolumeFile.h" #include using namespace caret; using namespace std; AString AlgorithmVolumeReduce::getCommandSwitch() { return "-volume-reduce"; } AString AlgorithmVolumeReduce::getShortDescription() { return "PERFORM REDUCTION OPERATION ACROSS SUBVOLUMES"; } OperationParameters* AlgorithmVolumeReduce::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume-in", "the volume file to reduce"); ret->addStringParameter(2, "operation", "the reduction operator to use"); ret->addVolumeOutputParameter(3, "volume-out", "the output volume"); OptionalParameter* excludeOpt = ret->createOptionalParameter(4, "-exclude-outliers", "exclude non-numeric values and outliers by standard deviation"); excludeOpt->addDoubleParameter(1, "sigma-below", "number of standard deviations below the mean to include"); excludeOpt->addDoubleParameter(2, "sigma-above", "number of standard deviations above the mean to include"); ret->createOptionalParameter(5, "-only-numeric", "exclude non-numeric values"); ret->setHelpText( AString("For each voxel, takes the data across subvolumes as a vector, and performs the specified reduction on it, putting the result ") + "into the single output volume at that voxel. The reduction operators are as follows:\n\n" + ReductionOperation::getHelpInfo() ); return ret; } void AlgorithmVolumeReduce::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* volumeIn = myParams->getVolume(1); AString opString = myParams->getString(2); VolumeFile* volumeOut = myParams->getOutputVolume(3); OptionalParameter* excludeOpt = myParams->getOptionalParameter(4); bool onlyNumeric = myParams->getOptionalParameter(5)->m_present; bool ok = false; ReductionEnum::Enum myReduce = ReductionEnum::fromName(opString, &ok); if (!ok) throw AlgorithmException("unrecognized operation string '" + opString + "'"); if (excludeOpt->m_present) { if (onlyNumeric) CaretLogWarning("-only-numeric is redundant when -exclude-outliers is specified"); AlgorithmVolumeReduce(myProgObj, volumeIn, myReduce, volumeOut, excludeOpt->getDouble(1), excludeOpt->getDouble(2)); } else { AlgorithmVolumeReduce(myProgObj, volumeIn, myReduce, volumeOut, onlyNumeric); } } AlgorithmVolumeReduce::AlgorithmVolumeReduce(ProgressObject* myProgObj, const VolumeFile* volumeIn, const ReductionEnum::Enum& myReduce, VolumeFile* volumeOut, const bool& onlyNumeric) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); vector myDims, newDims = volumeIn->getOriginalDimensions(); newDims.resize(3, 1);//have only one subvolume volumeIn->getDimensions(myDims); if (myDims[3] == 1) { CaretLogWarning("-volume-reduce is being used for a length=1 reduction on file '" + volumeIn->getFileName() + "'"); } volumeOut->reinitialize(newDims, volumeIn->getSform(), myDims[4], volumeIn->getType()); if (volumeIn->getType() == SubvolumeAttributes::LABEL) { CaretLogWarning("reduction operation performed on label volume"); *(volumeOut->getMapLabelTable(0)) = *(volumeIn->getMapLabelTable(0)); } int64_t frameSize = myDims[0] * myDims[1] * myDims[2]; vector scratchArray(myDims[3]), outFrame(frameSize); for (int c = 0; c < myDims[4]; ++c) { for (int64_t i = 0; i < frameSize; ++i) { for (int b = 0; b < myDims[3]; ++b) { const float* tempFrame = volumeIn->getFrame(b, c); scratchArray[b] = tempFrame[i]; } if (onlyNumeric) { outFrame[i] = ReductionOperation::reduceOnlyNumeric(scratchArray.data(), myDims[3], myReduce); } else { outFrame[i] = ReductionOperation::reduce(scratchArray.data(), myDims[3], myReduce); } } volumeOut->setFrame(outFrame.data(), 0, c); } } AlgorithmVolumeReduce::AlgorithmVolumeReduce(ProgressObject* myProgObj, const VolumeFile* volumeIn, const ReductionEnum::Enum& myReduce, VolumeFile* volumeOut, const float& sigmaBelow, const float& sigmaAbove) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); vector myDims, newDims = volumeIn->getOriginalDimensions(); newDims.resize(3, 1);//have only one subvolume volumeIn->getDimensions(myDims); volumeOut->reinitialize(newDims, volumeIn->getSform(), myDims[4], volumeIn->getType()); if (volumeIn->getType() == SubvolumeAttributes::LABEL) { CaretLogWarning("reduction operation performed on label volume"); *(volumeOut->getMapLabelTable(0)) = *(volumeIn->getMapLabelTable(0)); } int64_t frameSize = myDims[0] * myDims[1] * myDims[2]; vector scratchArray(myDims[3]), outFrame(frameSize); for (int c = 0; c < myDims[4]; ++c) { for (int64_t i = 0; i < frameSize; ++i) { for (int b = 0; b < myDims[3]; ++b) { const float* tempFrame = volumeIn->getFrame(b, c); scratchArray[b] = tempFrame[i]; } outFrame[i] = ReductionOperation::reduceExcludeDev(scratchArray.data(), myDims[3], myReduce, sigmaBelow, sigmaAbove); } volumeOut->setFrame(outFrame.data(), 0, c); } } float AlgorithmVolumeReduce::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeReduce::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeReduce.h000066400000000000000000000036541360521144700251620ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_REDUCE_H__ #define __ALGORITHM_VOLUME_REDUCE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "ReductionEnum.h" namespace caret { class AlgorithmVolumeReduce : public AbstractAlgorithm { AlgorithmVolumeReduce(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeReduce(ProgressObject* myProgObj, const VolumeFile* volumeIn, const ReductionEnum::Enum& myReduce, VolumeFile* volumeOut, const bool& onlyNumeric = false); AlgorithmVolumeReduce(ProgressObject* myProgObj, const VolumeFile* volumeIn, const ReductionEnum::Enum& myReduce, VolumeFile* volumeOut, const float& sigmaBelow, const float& sigmaAbove); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeReduce; } #endif //__ALGORITHM_VOLUME_REDUCE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeRemoveIslands.cxx000066400000000000000000000154611360521144700271000ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeRemoveIslands.h" #include "AlgorithmException.h" #include "VolumeFile.h" #include using namespace caret; using namespace std; AString AlgorithmVolumeRemoveIslands::getCommandSwitch() { return "-volume-remove-islands"; } AString AlgorithmVolumeRemoveIslands::getShortDescription() { return "REMOVE ISLANDS FROM AN ROI VOLUME"; } OperationParameters* AlgorithmVolumeRemoveIslands::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume-in", "the input ROI volume"); ret->addVolumeOutputParameter(2, "volume-out", "the output ROI volume"); ret->setHelpText( AString("Finds all face-connected parts of the ROI, and zeros out all but the largest one.") ); return ret; } void AlgorithmVolumeRemoveIslands::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* myVolIn = myParams->getVolume(1); VolumeFile* myVolOut = myParams->getOutputVolume(2); AlgorithmVolumeRemoveIslands(myProgObj, myVolIn, myVolOut); } AlgorithmVolumeRemoveIslands::AlgorithmVolumeRemoveIslands(ProgressObject* myProgObj, const VolumeFile* myVolIn, VolumeFile* myVolOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const int STENCIL_SIZE = 18;//the easy way, and prepare for different stencils if we ever need them const int stencil[STENCIL_SIZE] = { 0, 0, -1, 0, -1, 0, -1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 }; vector dims; myVolIn->getDimensions(dims); myVolOut->reinitialize(myVolIn->getOriginalDimensions(), myVolIn->getSform(), myVolIn->getNumberOfComponents(), myVolIn->getType(), myVolIn->m_header); for (int s = 0; s < dims[3]; ++s) { myVolOut->setMapName(s, myVolIn->getMapName(s)); for (int c = 0; c < dims[4]; ++c) { int64_t ijk[3]; vector > parts; vector used(dims[0] * dims[1] * dims[2], 0); const float* frame = myVolIn->getFrame(s, c); for (ijk[2] = 0; ijk[2] < dims[2]; ++ijk[2]) { for (ijk[1] = 0; ijk[1] < dims[1]; ++ijk[1]) { for (ijk[0] = 0; ijk[0] < dims[0]; ++ijk[0]) { int64_t index = myVolIn->getIndex(ijk); if (used[index] == 0 && frame[index] > 0.0f) { parts.push_back(vector()); vector& thispart = parts.back(); thispart.push_back(ijk[0]); thispart.push_back(ijk[1]); thispart.push_back(ijk[2]); used[index] = 1; vector mystack; mystack.push_back(ijk[0]); mystack.push_back(ijk[1]); mystack.push_back(ijk[2]); while (!mystack.empty()) { int64_t curSize = (int64_t)mystack.size(); int64_t curvox[3] = { mystack[curSize - 3], mystack[curSize - 2], mystack[curSize - 1] }; mystack.resize(curSize - 3);//basically pop_back for (int i = 0; i < STENCIL_SIZE; i += 3) { int64_t neighbor[3] = { curvox[0] + stencil[i], curvox[1] + stencil[i + 1], curvox[2] + stencil[i + 2] }; if (myVolIn->indexValid(neighbor)) { int64_t neighindex = myVolIn->getIndex(neighbor); if (used[neighindex] == 0 && frame[neighindex] > 0.0f) { thispart.push_back(neighbor[0]); thispart.push_back(neighbor[1]); thispart.push_back(neighbor[2]); used[neighindex] = 1; mystack.push_back(neighbor[0]); mystack.push_back(neighbor[1]); mystack.push_back(neighbor[2]); } } } } } } } } int64_t bestCount = -1, bestPart = -1, numParts = (int64_t)parts.size(); for (int64_t i = 0; i < numParts; ++i) { int64_t thisCount = (int64_t)parts[i].size(); if (thisCount > bestCount) { bestCount = thisCount; bestPart = i; } } vector outFrame(dims[0] * dims[1] * dims[2], 0.0f); if (bestPart != -1) { vector& myPart = parts[bestPart]; for (int64_t i = 0; i < bestCount; i += 3) { int64_t myIndex = myVolIn->getIndex(myPart.data() + i); outFrame[myIndex] = 1.0f;//make it a simple 0/1 volume, even if it wasn't before } } myVolOut->setFrame(outFrame.data(), s, c); } } } float AlgorithmVolumeRemoveIslands::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeRemoveIslands::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeRemoveIslands.h000066400000000000000000000033001360521144700265120ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_REMOVE_ISLANDS_H__ #define __ALGORITHM_VOLUME_REMOVE_ISLANDS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmVolumeRemoveIslands : public AbstractAlgorithm { AlgorithmVolumeRemoveIslands(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeRemoveIslands(ProgressObject* myProgObj, const VolumeFile* myVolIn, VolumeFile* myVolOut); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeRemoveIslands; } #endif //__ALGORITHM_VOLUME_REMOVE_ISLANDS_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeSmoothing.cxx000066400000000000000000000777221360521144700263040ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeSmoothing.h" #include "AlgorithmException.h" #include "VolumeFile.h" #include "Vector3D.h" #include "CaretLogger.h" #include "CaretOMP.h" #include "CaretAssert.h" #include using namespace caret; using namespace std; //makes the program issue warning only once per launch, prevents repeated calls by other algorithms from spamming bool AlgorithmVolumeSmoothing::haveWarned = false; AString AlgorithmVolumeSmoothing::getCommandSwitch() { return "-volume-smoothing"; } AString AlgorithmVolumeSmoothing::getShortDescription() { return "SMOOTH A VOLUME FILE"; } OperationParameters* AlgorithmVolumeSmoothing::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume-in", "the volume to smooth"); ret->addDoubleParameter(2, "kernel", "the gaussian smoothing kernel sigma, in mm"); ret->addVolumeOutputParameter(3, "volume-out", "the output volume"); OptionalParameter* roiVolOpt = ret->createOptionalParameter(4, "-roi", "smooth only from data within an ROI"); roiVolOpt->addVolumeParameter(1, "roivol", "the volume to use as an ROI"); ret->createOptionalParameter(5, "-fix-zeros", "treat zero values as not being data"); OptionalParameter* subvolSelect = ret->createOptionalParameter(6, "-subvolume", "select a single subvolume to smooth"); subvolSelect->addStringParameter(1, "subvol", "the subvolume number or name"); ret->setHelpText( AString("Gaussian smoothing for volumes. By default, smooths all subvolumes with no ROI, if ROI is given, only ") + "positive voxels in the ROI volume have their values used, and all other voxels are set to zero. Smoothing a non-orthogonal volume will " + "be significantly slower, because the operation cannot be separated into 1-dimensional smoothings without distorting the kernel shape.\n\n" + "The -fix-zeros option causes the smoothing to not use an input value if it is zero, but still write a smoothed value to the voxel. " + "This is useful for zeros that indicate lack of information, preventing them from pulling down the intensity of nearby voxels, while " + "giving the zero an extrapolated value." ); return ret; } void AlgorithmVolumeSmoothing::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* myVol = myParams->getVolume(1); float myKernel = (float)myParams->getDouble(2); VolumeFile* myOutVol = myParams->getOutputVolume(3); OptionalParameter* roiVolOpt = myParams->getOptionalParameter(4); VolumeFile* roiVol = NULL; if (roiVolOpt->m_present) { roiVol = roiVolOpt->getVolume(1); } OptionalParameter* fixZerosOpt = myParams->getOptionalParameter(5); bool fixZeros = fixZerosOpt->m_present; OptionalParameter* subvolSelect = myParams->getOptionalParameter(6); int subvolNum = -1; if (subvolSelect->m_present) { subvolNum = (int)myVol->getMapIndexFromNameOrNumber(subvolSelect->getString(1)); if (subvolNum < 0) { throw AlgorithmException("invalid subvolume specified"); } } AlgorithmVolumeSmoothing(myProgObj, myVol, myKernel, myOutVol, roiVol, fixZeros, subvolNum); } AlgorithmVolumeSmoothing::AlgorithmVolumeSmoothing(ProgressObject* myProgObj, const VolumeFile* inVol, const float& kernel, VolumeFile* outVol, const VolumeFile* roiVol, const bool& fixZeros, const int& subvol) : AbstractAlgorithm(myProgObj) { CaretAssert(inVol != NULL); CaretAssert(outVol != NULL); LevelProgress myProgress(myProgObj); if (roiVol != NULL && !inVol->matchesVolumeSpace(roiVol)) { throw AlgorithmException("volume roi space does not match input volume"); } vector myDims; inVol->getDimensions(myDims); if (subvol < -1 || subvol >= myDims[3]) { throw AlgorithmException("invalid subvolume specified"); } if (kernel <= 0.0f) { throw AlgorithmException("kernel too small"); } CaretArray scratchFrame(myDims[0] * myDims[1] * myDims[2]);//it could be faster to preinitialize with zeros, then generate a usable voxels list if there is a small ROI... float kernBox = kernel * 3.0f; vector > volSpace = inVol->getSform(); Vector3D ivec, jvec, kvec, origin, ijorth, jkorth, kiorth; ivec[0] = volSpace[0][0]; jvec[0] = volSpace[0][1]; kvec[0] = volSpace[0][2]; origin[0] = volSpace[0][3]; ivec[1] = volSpace[1][0]; jvec[1] = volSpace[1][1]; kvec[1] = volSpace[1][2]; origin[1] = volSpace[1][3]; ivec[2] = volSpace[2][0]; jvec[2] = volSpace[2][1]; kvec[2] = volSpace[2][2]; origin[2] = volSpace[2][3]; const float ORTH_TOLERANCE = 0.001f;//tolerate this much deviation from orthogonal (dot product divided by product of lengths) to use orthogonal assumptions to smooth if (abs(ivec.dot(jvec.normal())) / ivec.length() < ORTH_TOLERANCE && abs(jvec.dot(kvec.normal())) / jvec.length() < ORTH_TOLERANCE && abs(kvec.dot(ivec.normal())) / kvec.length() < ORTH_TOLERANCE) {//if our axes are orthogonal, optimize by doing three 1-dimensional smoothings for O(voxels * (ki + kj + kk)) instead of O(voxels * (ki * kj * kk)) CaretArray scratchFrame2(myDims[0] * myDims[1] * myDims[2]), scratchWeights(myDims[0] * myDims[1] * myDims[2]), scratchWeights2(myDims[0] * myDims[1] * myDims[2]), scratchFrame3; if (roiVol != NULL) { scratchFrame3 = CaretArray (myDims[0] * myDims[1] * myDims[2]); } float ispace = ivec.length(), jspace = jvec.length(), kspace = kvec.length(); int irange = (int)floor(kernBox / ispace); int jrange = (int)floor(kernBox / jspace); int krange = (int)floor(kernBox / kspace); if (irange < 1) irange = 1;//don't underflow if (jrange < 1) jrange = 1; if (krange < 1) krange = 1; int isize = irange * 2 + 1;//and construct a precomputed kernel in the box int jsize = jrange * 2 + 1; int ksize = krange * 2 + 1; CaretArray iweights(isize), jweights(jsize), kweights(ksize); for (int i = 0; i < isize; ++i) { float tempf = ispace * (i - irange) / kernel; iweights[i] = exp(-tempf * tempf / 2.0f); } for (int j = 0; j < jsize; ++j) { float tempf = jspace * (j - jrange) / kernel; jweights[j] = exp(-tempf * tempf / 2.0f); } for (int k = 0; k < ksize; ++k) { float tempf = kspace * (k - krange) / kernel; kweights[k] = exp(-tempf * tempf / 2.0f); } if (subvol == -1) { vector origDims = inVol->getOriginalDimensions(); outVol->reinitialize(origDims, volSpace, myDims[4], inVol->getType(), inVol->m_header); vector lists[3]; for (int s = 0; s < myDims[3]; ++s) { outVol->setMapName(s, inVol->getMapName(s) + ", smooth " + AString::number(kernel)); for (int c = 0; c < myDims[4]; ++c) { const float* inFrame = inVol->getFrame(s, c); if (roiVol == NULL) { smoothFrame(inFrame, myDims, scratchFrame, scratchFrame2, scratchWeights, scratchWeights2, inVol, iweights, jweights, kweights, irange, jrange, krange, fixZeros); } else { smoothFrameROI(inFrame, myDims, scratchFrame, scratchFrame2, scratchFrame3, scratchWeights, scratchWeights2, lists, inVol, roiVol, iweights, jweights, kweights, irange, jrange, krange, fixZeros); } outVol->setFrame(scratchFrame, s, c); } } } else { vector origDims = inVol->getOriginalDimensions(), newDims; newDims.resize(3); newDims[0] = origDims[0]; newDims[1] = origDims[1]; newDims[2] = origDims[2]; outVol->reinitialize(newDims, volSpace, myDims[4], inVol->getType(), inVol->m_header); vector lists[3]; outVol->setMapName(0, inVol->getMapName(subvol) + ", smooth " + AString::number(kernel)); for (int c = 0; c < myDims[4]; ++c) { const float* inFrame = inVol->getFrame(subvol, c); if (roiVol == NULL) { smoothFrame(inFrame, myDims, scratchFrame, scratchFrame2, scratchWeights, scratchWeights2, inVol, iweights, jweights, kweights, irange, jrange, krange, fixZeros); } else { smoothFrameROI(inFrame, myDims, scratchFrame, scratchFrame2, scratchFrame3, scratchWeights, scratchWeights2, lists, inVol, roiVol, iweights, jweights, kweights, irange, jrange, krange, fixZeros); } outVol->setFrame(scratchFrame, 0, c); } } } else { if (!haveWarned) { CaretLogWarning("input volume is not orthogonal, smoothing will take longer"); haveWarned = true; } ijorth = ivec.cross(jvec).normal();//find the bounding box that encloses a sphere of radius kernBox jkorth = jvec.cross(kvec).normal(); kiorth = kvec.cross(ivec).normal(); int irange = (int)floor(abs(kernBox / ivec.dot(jkorth))); int jrange = (int)floor(abs(kernBox / jvec.dot(kiorth))); int krange = (int)floor(abs(kernBox / kvec.dot(ijorth))); if (irange < 1) irange = 1;//don't underflow if (jrange < 1) jrange = 1; if (krange < 1) krange = 1; int isize = irange * 2 + 1;//and construct a precomputed kernel in the box int jsize = jrange * 2 + 1; int ksize = krange * 2 + 1; CaretArray weights(ksize);//so I don't need to explicitly delete[] if I throw CaretArray weights2(ksize * jsize);//construct flat arrays and index them into 3D CaretArray weights3(ksize * jsize * isize);//index i comes last because that is linear for volume frames Vector3D kscratch, jscratch, iscratch; for (int k = 0; k < ksize; ++k) { kscratch = kvec * (k - krange); weights[k] = weights2 + k * jsize; for (int j = 0; j < jsize; ++j) { jscratch = kscratch + jvec * (j - jrange); weights[k][j] = weights3 + ((k * jsize) + j) * isize; for (int i = 0; i < isize; ++i) { iscratch = jscratch + ivec * (i - irange); float tempf = iscratch.length(); if (tempf > kernBox) { weights[k][j][i] = 0.0f;//test for zero to avoid some multiplies/adds, cheaper or cleaner than checking bounds on indexes from an index list } else { weights[k][j][i] = exp(-tempf * tempf / kernel / kernel / 2.0f);//optimization here isn't critical } } } } if (subvol == -1) { vector origDims = inVol->getOriginalDimensions(); outVol->reinitialize(origDims, volSpace, myDims[4], inVol->getType(), inVol->m_header); for (int s = 0; s < myDims[3]; ++s) { outVol->setMapName(s, inVol->getMapName(s) + ", smooth " + AString::number(kernel)); for (int c = 0; c < myDims[4]; ++c) { const float* inFrame = inVol->getFrame(s, c); smoothFrameNonOrth(inFrame, myDims, scratchFrame, inVol, roiVol, weights, irange, jrange, krange, fixZeros); outVol->setFrame(scratchFrame, s, c); } } } else { vector origDims = inVol->getOriginalDimensions(), newDims; newDims.resize(3); newDims[0] = origDims[0]; newDims[1] = origDims[1]; newDims[2] = origDims[2]; outVol->reinitialize(newDims, volSpace, myDims[4], inVol->getType(), inVol->m_header); outVol->setMapName(0, inVol->getMapName(subvol) + ", smooth " + AString::number(kernel)); for (int c = 0; c < myDims[4]; ++c) { const float* inFrame = inVol->getFrame(subvol, c); smoothFrameNonOrth(inFrame, myDims, scratchFrame, inVol, roiVol, weights, irange, jrange, krange, fixZeros); outVol->setFrame(scratchFrame, 0, c); } } } } void AlgorithmVolumeSmoothing::smoothFrame(const float* inFrame, vector myDims, CaretArray scratchFrame, CaretArray scratchFrame2, CaretArray scratchWeights, CaretArray scratchWeights2, const VolumeFile* inVol, CaretArray iweights, CaretArray jweights, CaretArray kweights, int irange, int jrange, int krange, const bool& fixZeros) {//this function should ONLY get invoked when the volume is orthogonal (axes are perpendicular, not necessarily aligned with x, y, z, and not necessarily equal spacing) #pragma omp CARET_PARFOR schedule(dynamic) for (int k = 0; k < myDims[2]; ++k)//smooth along i axis { for (int j = 0; j < myDims[1]; ++j) { for (int i = 0; i < myDims[0]; ++i) { int imin = i - irange, imax = i + irange + 1;//one-after array size convention if (imin < 0) imin = 0; if (imax > myDims[0]) imax = myDims[0]; float sum = 0.0f, weightsum = 0.0f; int64_t baseInd = inVol->getIndex(0, j, k, 0);//extra 0 on a default parameter is to prevent int->pointer vs int->int64 conversion ambiguity int64_t curInd = baseInd + i; for (int ikern = imin; ikern < imax; ++ikern) { int64_t thisIndex = baseInd + ikern; if ((!fixZeros || inFrame[thisIndex] != 0.0f)) { float weight = iweights[ikern - i + irange]; weightsum += weight; sum += weight * inFrame[thisIndex]; } } scratchWeights[curInd] = weightsum; scratchFrame[curInd] = sum;//don't divide yet, we will divide later after we gather the weighted sums of the weighted sums of the weight sums (yes, that repetition is right) } } } #pragma omp CARET_PARFOR schedule(dynamic) for (int k = 0; k < myDims[2]; ++k)//now j { for (int i = 0; i < myDims[0]; ++i) { for (int j = 0; j < myDims[1]; ++j)//step along the dimension being smoothed last for best cache coherence { int jmin = j - jrange, jmax = j + jrange + 1;//one-after array size convention if (jmin < 0) jmin = 0; if (jmax > myDims[1]) jmax = myDims[1]; float sum = 0.0f, weightsum = 0.0f; int64_t baseInd = inVol->getIndex(i, 0, k); int64_t curInd = baseInd + j * myDims[0]; for (int jkern = jmin; jkern < jmax; ++jkern) { int64_t thisIndex = baseInd + jkern * myDims[0]; float weight = jweights[jkern - j + jrange]; weightsum += weight * scratchWeights[thisIndex]; sum += weight * scratchFrame[thisIndex]; } scratchWeights2[curInd] = weightsum; scratchFrame2[curInd] = sum;//we now have the weighted sum of the weight sums } } } //somehow this loop set is helped by collapsing the two outers, while the other two are not helped by it //however, we need to upgrade our windows compiler before we can use "collapse" #pragma omp CARET_PARFOR schedule(dynamic) for (int j = 0; j < myDims[1]; ++j)//and finally k { for (int i = 0; i < myDims[0]; ++i) { for (int k = 0; k < myDims[2]; ++k)//ditto { int64_t baseInd = inVol->getIndex(i, j, 0); int64_t curInd = baseInd + k * myDims[0] * myDims[1]; int kmin = k - krange, kmax = k + krange + 1;//one-after array size convention if (kmin < 0) kmin = 0; if (kmax > myDims[2]) kmax = myDims[2]; float sum = 0.0f, weightsum = 0.0f; for (int kkern = kmin; kkern < kmax; ++kkern) { int64_t thisIndex = baseInd + kkern * myDims[0] * myDims[1]; float weight = kweights[kkern - k + krange]; weightsum += weight * scratchWeights2[thisIndex]; sum += weight * scratchFrame2[thisIndex]; } if (weightsum != 0.0f) { scratchFrame[curInd] = sum / weightsum;//NOW we can divide } else { scratchFrame[curInd] = 0.0f; } } } } } void AlgorithmVolumeSmoothing::smoothFrameROI(const float* inFrame, vector myDims, CaretArray scratchFrame, CaretArray scratchFrame2, CaretArray scratchFrame3, CaretArray scratchWeights, CaretArray scratchWeights2, vector lists[3], const VolumeFile* inVol, const VolumeFile* roiVol, CaretArray iweights, CaretArray jweights, CaretArray kweights, int irange, int jrange, int krange, const bool& fixZeros) {//optimized for orthogonal, plus lists of voxels for ROI smoothing if (lists[0].size() == 0) {//this is our first time into this function, we must populate the lists const float* roiFrame = roiVol->getFrame(); CaretArray markROI(myDims[0] * myDims[1] * myDims[2], 0);//need a temporary array to sort out ROI zeros from -fix-zeros zeros #pragma omp CARET_PARFOR for (int k = 0; k < myDims[2]; ++k)//smooth along i axis { for (int j = 0; j < myDims[1]; ++j) { for (int i = 0; i < myDims[0]; ++i)//don't test whether intermediate voxel is insode ROI, or we lose some data { int imin = i - irange, imax = i + irange + 1;//one-after array size convention if (imin < 0) imin = 0; if (imax > myDims[0]) imax = myDims[0]; float sum = 0.0f, weightsum = 0.0f; int64_t baseInd = inVol->getIndex(0, j, k, 0); int64_t curInd = baseInd + i; bool used = false; for (int ikern = imin; ikern < imax; ++ikern) { int64_t thisIndex = baseInd + ikern; if (roiFrame[thisIndex] > 0.0f)//only test source and final voxels for being in ROI { if (!used)//keep a list of voxels whose i-kernel intersects the ROI { used = true; markROI[curInd] = 1; #pragma omp critical { lists[0].push_back(i); lists[0].push_back(j); lists[0].push_back(k); } } if (!fixZeros || inFrame[thisIndex] != 0.0f) { float weight = iweights[ikern - i + irange]; weightsum += weight; sum += weight * inFrame[thisIndex]; } } } scratchWeights[curInd] = weightsum; scratchFrame3[curInd] = sum;//don't divide yet, we will divide later after we gather the weighted sums of the weighted sums of the weight sums (yes, that repetition is right) } } } #pragma omp CARET_PARFOR for (int k = 0; k < myDims[2]; ++k)//now j { for (int i = 0; i < myDims[0]; ++i) { for (int j = 0; j < myDims[1]; ++j)//step along the dimension being smoothed last for best cache coherence { int jmin = j - jrange, jmax = j + jrange + 1;//one-after array size convention if (jmin < 0) jmin = 0; if (jmax > myDims[1]) jmax = myDims[1]; float sum = 0.0f, weightsum = 0.0f; int64_t baseInd = inVol->getIndex(i, 0, k); int64_t curInd = baseInd + j * myDims[0]; bool used = false; for (int jkern = jmin; jkern < jmax; ++jkern) { int64_t thisIndex = baseInd + jkern * myDims[0];//DO NOT test for this source voxel being outside ROI, or you will skip good data if ((markROI[thisIndex] & 1) == 1) {//skip voxels whose i-kernels don't touch the ROI, they will always have 0/0 if (!used) { used = true; markROI[curInd] |= 2;//bitwise so i can track all 3 lists separately in one array #pragma omp critical { lists[1].push_back(i); lists[1].push_back(j); lists[1].push_back(k); } } float weight = jweights[jkern - j + jrange]; weightsum += weight * scratchWeights[thisIndex]; sum += weight * scratchFrame3[thisIndex]; } } scratchWeights2[curInd] = weightsum; scratchFrame2[curInd] = sum;//we now have the weighted sum of the weight sums } } } #pragma omp CARET_PARFOR for (int j = 0; j < myDims[1]; ++j)//and finally k { for (int i = 0; i < myDims[0]; ++i) { for (int k = 0; k < myDims[2]; ++k)//ditto { int64_t baseInd = inVol->getIndex(i, j, 0); int64_t curInd = baseInd + k * myDims[0] * myDims[1]; if (roiFrame[curInd] > 0.0f) { #pragma omp critical { lists[2].push_back(i);//third list is a little different, since we don't output stuff outside the ROI, we can drop the voxels that "grew" from the ROI lists[2].push_back(j);//we do need to calculate those grown voxels, though, since we use some of them within the k-kernel lists[2].push_back(k); } int kmin = k - krange, kmax = k + krange + 1;//one-after array size convention if (kmin < 0) kmin = 0; if (kmax > myDims[2]) kmax = myDims[2]; float sum = 0.0f, weightsum = 0.0f; for (int kkern = kmin; kkern < kmax; ++kkern) { int64_t thisIndex = baseInd + kkern * myDims[0] * myDims[1];//ditto float weight = kweights[kkern - k + krange]; weightsum += weight * scratchWeights2[thisIndex]; sum += weight * scratchFrame2[thisIndex]; } if (weightsum != 0.0f) { scratchFrame[curInd] = sum / weightsum;//NOW we can divide } else { scratchFrame[curInd] = 0.0f; } } else { scratchFrame[curInd] = 0.0f; } } } } if (lists[0].size() == 0) { lists[0].push_back(-1);//to keep it from scanning the ROI again when the ROI has no voxels, slightly hacky } } else {//lists already made, use them const float* roiFrame = roiVol->getFrame(); int64_t ibasesize = (int64_t)lists[0].size(); if (ibasesize < 3) return;//handle the case of empty ROI here (ibasesize will be 1) int64_t jbasesize = (int64_t)lists[1].size(); int64_t kbasesize = (int64_t)lists[2].size(); #pragma omp CARET_PARFOR schedule(dynamic) for (int ibase = 0; ibase < ibasesize; ibase += 3) { int i = lists[0][ibase]; int j = lists[0][ibase + 1]; int k = lists[0][ibase + 2]; int imin = i - irange, imax = i + irange + 1;//one-after array size convention if (imin < 0) imin = 0; if (imax > myDims[0]) imax = myDims[0]; float sum = 0.0f, weightsum = 0.0f; int64_t baseInd = inVol->getIndex(0, j, k, 0); int64_t curInd = baseInd + i; for (int ikern = imin; ikern < imax; ++ikern) { int64_t thisIndex = baseInd + ikern; if (roiFrame[thisIndex] > 0.0f && (!fixZeros || inFrame[thisIndex] != 0.0f)) { float weight = iweights[ikern - i + irange]; weightsum += weight; sum += weight * inFrame[thisIndex]; } } scratchWeights[curInd] = weightsum; scratchFrame3[curInd] = sum;//don't divide yet, we will divide later after we gather the weighted sums of the weighted sums of the weight sums (yes, that repetition is right) } #pragma omp CARET_PARFOR schedule(dynamic) for (int jbase = 0; jbase < jbasesize; jbase += 3) { int i = lists[1][jbase]; int j = lists[1][jbase + 1]; int k = lists[1][jbase + 2]; int jmin = j - jrange, jmax = j + jrange + 1;//one-after array size convention if (jmin < 0) jmin = 0; if (jmax > myDims[1]) jmax = myDims[1]; float sum = 0.0f, weightsum = 0.0f; int64_t baseInd = inVol->getIndex(i, 0, k); int64_t curInd = baseInd + j * myDims[0]; for (int jkern = jmin; jkern < jmax; ++jkern) { int64_t thisIndex = baseInd + jkern * myDims[0];//DO NOT test for this source voxel having zero data, or it will skip good data float weight = jweights[jkern - j + jrange]; weightsum += weight * scratchWeights[thisIndex]; sum += weight * scratchFrame3[thisIndex]; } scratchWeights2[curInd] = weightsum; scratchFrame2[curInd] = sum;//we now have the weighted sum of the weight sums } #pragma omp CARET_PARFOR schedule(dynamic) for (int kbase = 0; kbase < kbasesize; kbase += 3) { int i = lists[2][kbase]; int j = lists[2][kbase + 1]; int k = lists[2][kbase + 2]; int64_t baseInd = inVol->getIndex(i, j, 0); int64_t curInd = baseInd + k * myDims[0] * myDims[1]; int kmin = k - krange, kmax = k + krange + 1;//one-after array size convention if (kmin < 0) kmin = 0; if (kmax > myDims[2]) kmax = myDims[2]; float sum = 0.0f, weightsum = 0.0f; for (int kkern = kmin; kkern < kmax; ++kkern) { int64_t thisIndex = baseInd + kkern * myDims[0] * myDims[1];//ditto float weight = kweights[kkern - k + krange]; weightsum += weight * scratchWeights2[thisIndex]; sum += weight * scratchFrame2[thisIndex]; } if (weightsum != 0.0f) { scratchFrame[curInd] = sum / weightsum;//NOW we can divide } else { scratchFrame[curInd] = 0.0f; } }//the frame should be zeroed outside the ROI already due to the first time through } } void AlgorithmVolumeSmoothing::smoothFrameNonOrth(const float* inFrame, const vector& myDims, CaretArray& scratchFrame, const VolumeFile* inVol, const VolumeFile* roiVol, const CaretArray& weights, const int& irange, const int& jrange, const int& krange, const bool& fixZeros) { const float* roiFrame = NULL; if (roiVol != NULL) { roiFrame = roiVol->getFrame(); } #pragma omp CARET_PARFOR schedule(dynamic) for (int k = 0; k < myDims[2]; ++k) { for (int j = 0; j < myDims[1]; ++j) { for (int i = 0; i < myDims[0]; ++i) { if (roiVol == NULL || roiVol->getValue(i, j, k) > 0.0f) { int imin = i - irange, imax = i + irange + 1;//one-after array size convention if (imin < 0) imin = 0; if (imax > myDims[0]) imax = myDims[0]; int jmin = j - jrange, jmax = j + jrange + 1; if (jmin < 0) jmin = 0; if (jmax > myDims[1]) jmax = myDims[1]; int kmin = k - krange, kmax = k + krange + 1; if (kmin < 0) kmin = 0; if (kmax > myDims[2]) kmax = myDims[2]; float sum = 0.0f, weightsum = 0.0f; for (int kkern = kmin; kkern < kmax; ++kkern) { int64_t kindpart = kkern * myDims[1]; int kkernpart = kkern - k + krange; for (int jkern = jmin; jkern < jmax; ++jkern) { int64_t jindpart = (kindpart + jkern) * myDims[0]; int jkernpart = jkern - j + jrange; for (int ikern = imin; ikern < imax; ++ikern) { int64_t thisIndex = jindpart + ikern;//somewhat optimized index computation, could remove some integer multiplies, but there aren't that many float weight = weights[kkernpart][jkernpart][ikern - i + irange]; if (weight != 0.0f && (roiVol == NULL || roiFrame[thisIndex] > 0.0f) && (!fixZeros || inFrame[thisIndex] != 0.0f)) { weightsum += weight; sum += weight * inFrame[thisIndex]; } } } } if (weightsum != 0.0f) { scratchFrame[inVol->getIndex(i, j, k)] = sum / weightsum; } else { scratchFrame[inVol->getIndex(i, j, k)] = 0.0f; } } else { scratchFrame[inVol->getIndex(i, j, k)] = 0.0f; } } } } } float AlgorithmVolumeSmoothing::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeSmoothing::getSubAlgorithmWeight() { return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeSmoothing.h000066400000000000000000000061611360521144700257160ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_SMOOTHING_H__ #define __ALGORITHM_VOLUME_SMOOTHING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmVolumeSmoothing : public AbstractAlgorithm { AlgorithmVolumeSmoothing(); static bool haveWarned; protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); void smoothFrame(const float* inFrame, std::vector myDims, CaretArray scratchFrame, CaretArray scratchFrame2, CaretArray scratchWeights, CaretArray scratchWeights2, const VolumeFile* inVol, CaretArray iweights, CaretArray jweights, CaretArray kweights, int irange, int jrange, int krange, const bool& fixZeros); void smoothFrameROI(const float* inFrame, std::vector myDims, CaretArray scratchFrame, CaretArray scratchFrame2, CaretArray scratchFrame3, CaretArray scratchWeights, CaretArray scratchWeights2, std::vector lists[3], const VolumeFile* inVol, const VolumeFile* roiVol, CaretArray iweights, CaretArray jweights, CaretArray kweights, int irange, int jrange, int krange, const bool& fixZeros); void smoothFrameNonOrth(const float* inFrame, const std::vector& myDims, CaretArray& scratchFrame, const VolumeFile* inVol, const VolumeFile* roiVol, const CaretArray& weights, const int& irange, const int& jrange, const int& krange, const bool& fixZeros); public: AlgorithmVolumeSmoothing(ProgressObject* myProgObj, const VolumeFile* inVol, const float& kernel, VolumeFile* outVol, const VolumeFile* roiVol = NULL, const bool& fixZeros = false, const int& subvol = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeSmoothing; } #endif //__ALGORITHM_VOLUME_SMOOTHING_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeTFCE.cxx000066400000000000000000000436771360521144700250600ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeTFCE.h" #include "AlgorithmException.h" #include "AlgorithmVolumeSmoothing.h" #include "CaretAssert.h" #include "CaretHeap.h" #include "CaretOMP.h" #include "VolumeFile.h" #include "VoxelIJK.h" #include #include #include using namespace caret; using namespace std; AString AlgorithmVolumeTFCE::getCommandSwitch() { return "-volume-tfce"; } AString AlgorithmVolumeTFCE::getShortDescription() { return "DO TFCE ON A VOLUME FILE"; } OperationParameters* AlgorithmVolumeTFCE::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume-in", "the volume to run TFCE on"); ret->addVolumeOutputParameter(2, "volume-out", "the output volume"); OptionalParameter* presmoothOpt = ret->createOptionalParameter(3, "-presmooth", "smooth the volume before running TFCE"); presmoothOpt->addDoubleParameter(1, "kernel", "the sigma for the gaussian smoothing kernel, in mm"); OptionalParameter* roiOpt = ret->createOptionalParameter(4, "-roi", "select a region of interest to run TFCE on"); roiOpt->addVolumeParameter(1, "roi-volume", "the area to run TFCE on, as a volume"); OptionalParameter* paramsOpt = ret->createOptionalParameter(5, "-parameters", "set parameters for TFCE integral"); paramsOpt->addDoubleParameter(1, "E", "exponent for cluster volume (default 0.5)"); paramsOpt->addDoubleParameter(2, "H", "exponent for threshold value (default 2.0)"); OptionalParameter* subvolSelect = ret->createOptionalParameter(6, "-subvolume", "select a single subvolume"); subvolSelect->addStringParameter(1, "subvolume", "the subvolume number or name"); ret->setHelpText( AString("Threshold-free cluster enhancement is a method to increase the relative value of regions that would form clusters in a standard thresholding test. ") + "This is accomplished by evaluating the integral of:\n\n" + "e(h, p)^E * h^H * dh\n\n" + "at each vertex p, where h ranges from 0 to the maximum value in the data, and e(h, p) is the extent of the cluster containing vertex p at threshold h. " + "Negative values are similarly enhanced by negating the data, running the same process, and negating the result.\n\n" + "This method is explained in: Smith SM, Nichols TE., \"Threshold-free cluster enhancement: addressing problems of smoothing, threshold dependence and localisation in cluster inference.\" Neuroimage. 2009 Jan 1;44(1):83-98. PMID: 18501637" ); return ret; } void AlgorithmVolumeTFCE::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* myVol = myParams->getVolume(1); VolumeFile* myVolOut = myParams->getOutputVolume(2); float presmooth = 0.0f; OptionalParameter* presmoothOpt = myParams->getOptionalParameter(3); if (presmoothOpt->m_present) { presmooth = (float)presmoothOpt->getDouble(1); if (presmooth <= 0.0f) throw AlgorithmException("presmooth kernel size must be positive"); } VolumeFile* myRoi = NULL; OptionalParameter* roiOpt = myParams->getOptionalParameter(4); if (roiOpt->m_present) { myRoi = roiOpt->getVolume(1); } float param_e = 0.5f, param_h = 2.0; OptionalParameter* paramsOpt = myParams->getOptionalParameter(5); if (paramsOpt->m_present) { param_e = (float)paramsOpt->getDouble(1); param_h = (float)paramsOpt->getDouble(2); } OptionalParameter* subvolSelect = myParams->getOptionalParameter(6); int64_t subvolNum = -1; if (subvolSelect->m_present) {//set up to use the single column subvolNum = myVol->getMapIndexFromNameOrNumber(subvolSelect->getString(1)); if (subvolNum < 0) { throw AlgorithmException("invalid subvolume specified"); } } AlgorithmVolumeTFCE(myProgObj, myVol, myVolOut, presmooth, myRoi, param_e, param_h, subvolNum); } AlgorithmVolumeTFCE::AlgorithmVolumeTFCE(ProgressObject* myProgObj, const VolumeFile* myVol, VolumeFile* myVolOut, const float& presmooth, const VolumeFile* myRoi, const float& param_e, const float& param_h, const int64_t& subvolNum) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (myRoi != NULL && !myVol->getVolumeSpace().matches(myRoi->getVolumeSpace())) throw AlgorithmException("roi volume has different volume space than input"); if (subvolNum < -1 || subvolNum >= myVol->getNumberOfMaps()) throw AlgorithmException("invalid subvolume specified"); vector dims = myVol->getDimensions(); const float* roiFrame = NULL; if (myRoi != NULL) roiFrame = myRoi->getFrame(); if (subvolNum == -1) { myVolOut->reinitialize(myVol->getOriginalDimensions(), myVol->getSform(), dims[4], myVol->getType(), myVol->m_header); const VolumeFile* toUse = myVol; VolumeFile smoothed; if (presmooth > 0.0f) { AlgorithmVolumeSmoothing(NULL, myVol, presmooth, &smoothed, myRoi); toUse = &smoothed; } #pragma omp CARET_PAR { vector outframe(dims[0] * dims[1] * dims[2]); #pragma omp CARET_FOR for (int64_t b = 0; b < dims[3]; ++b) { for (int64_t c = 0; c < dims[4]; ++c) { processFrame(toUse, b, c, outframe.data(), roiFrame, param_e, param_h); myVolOut->setFrame(outframe.data(), b, c); } } } } else { vector outDims = dims; outDims.resize(3); myVolOut->reinitialize(outDims, myVol->getSform(), dims[4], myVol->getType(), myVol->m_header); const VolumeFile* toUse = myVol; int useFrame = subvolNum; VolumeFile smoothed; if (presmooth > 0.0f) { AlgorithmVolumeSmoothing(NULL, myVol, presmooth, &smoothed, myRoi, false, subvolNum); toUse = &smoothed; useFrame = 0; } vector outframe(dims[0] * dims[1] * dims[2]); for (int64_t c = 0; c < dims[4]; ++c) { processFrame(toUse, useFrame, c, outframe.data(), roiFrame, param_e, param_h); myVolOut->setFrame(outframe.data(), 0, c); } } } void AlgorithmVolumeTFCE::processFrame(const VolumeFile* inVol, const int64_t& b, const int64_t& c, float* outData, const float* roiData, const float& param_e, const float& param_h) { vector dims = inVol->getDimensions(); int64_t frameSize = dims[0] * dims[1] * dims[2]; vector accum(frameSize, 0.0); tfce(inVol, b, c, accum.data(), roiData, param_e, param_h, false);//don't negate - positives tfce(inVol, b, c, accum.data(), roiData, param_e, param_h, true);//negate - negatives - NOTE: output is still positive!!! const float* inData = inVol->getFrame(b, c); for (int64_t i = 0; i < frameSize; ++i) { if (inData[i] > 0.0f)//negate the results from negative inputs { outData[i] = accum[i]; } else {//the areas outside the roi will have zeros, so we don't have to worry about them outData[i] = -accum[i]; } } } namespace {//hidden namespace just to make sure things don't collide struct Cluster { double accumVal, totalVolume; vector members; float lastVal; bool first; Cluster() { first = true; accumVal = 0.0; totalVolume = 0.0; lastVal = 0.0f; } void addMember(const VoxelIJK& voxel, const float& val, const float& voxel_volume, const float& param_e, const float& param_h) { update(val, param_e, param_h); members.push_back(voxel); totalVolume += voxel_volume; } void update(const float& bottomVal, const float& param_e, const float& param_h) { if (first) { lastVal = bottomVal; first = false; } else { if (bottomVal != lastVal)//skip computing if there is no difference { CaretAssert(bottomVal < lastVal); double integrated_h = param_h + 1.0f;//integral(x^h) = (x^(h + 1))/(h + 1) + C double newSlice = pow(totalVolume, (double)param_e) * (pow((double)lastVal, integrated_h) - pow((double)bottomVal, integrated_h)) / integrated_h; accumVal += newSlice; lastVal = bottomVal;//computing in double precision, with float for inputs, puts the smallest difference between values far greater than the instability of the computation } } } }; int64_t allocCluster(vector& clusterList, set& deadClusters) { if (deadClusters.empty()) { clusterList.push_back(Cluster()); return (int64_t)(clusterList.size() - 1); } else { set::iterator iter = deadClusters.begin(); int64_t ret = *iter; deadClusters.erase(iter); clusterList[ret] = Cluster();//reinitialize return ret; } } } void AlgorithmVolumeTFCE::tfce(const VolumeFile* inVol, const int64_t& b, const int64_t& c, double* accumData, const float* roiData, const float& param_e, const float& param_h, const bool& negate) { vector dims = inVol->getDimensions(); Vector3D ivec, jvec, kvec, origin;//compute the volume of a voxel so different resolutions have comparable values - as if it matters, but hey inVol->getVolumeSpace().getSpacingVectors(ivec, jvec, kvec, origin);//who knows, maybe we'll have distortion correction in volume someday float voxelVolume = abs(ivec.dot(jvec.cross(kvec))); const int64_t frameSize = dims[0] * dims[1] * dims[2]; const float* frameData = inVol->getFrame(b, c); vector membership(frameSize, -1);//use int64_t just in case we get an absurd number of clusters vector clusterList; set deadClusters;//to allow reallocation without changing indices CaretSimpleMaxHeap voxelHeap; for (int64_t i = 0; i < dims[0]; ++i) { for (int64_t j = 0; j < dims[1]; ++j) { for (int64_t k = 0; k < dims[2]; ++k) { int64_t index = inVol->getIndex(i, j, k); if ((roiData == NULL || roiData[index] > 0.0f)) { if (negate) { if (frameData[index] < 0.0f) { voxelHeap.push(VoxelIJK(i, j, k), -frameData[index]); } } else { if (frameData[index] > 0.0f) { voxelHeap.push(VoxelIJK(i, j, k), frameData[index]); } } } } } } const int STENCIL_SIZE = 18; int64_t stencil[STENCIL_SIZE] = { 0, 0, -1, 0, -1, 0, -1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 }; while (!voxelHeap.isEmpty()) { float value; VoxelIJK voxel = voxelHeap.pop(&value); int64_t voxelIndex = inVol->getIndex(voxel.m_ijk); set touchingClusters; for (int i = 0; i < STENCIL_SIZE; i += 3) { VoxelIJK neighVoxel(voxel.m_ijk[0] + stencil[i], voxel.m_ijk[1] + stencil[i + 1], voxel.m_ijk[2] + stencil[i + 2]); if (inVol->indexValid(neighVoxel.m_ijk)) { int64_t neighIndex = inVol->getIndex(neighVoxel.m_ijk); if (membership[neighIndex] != -1) { touchingClusters.insert(membership[neighIndex]); } } } int numTouching = (int)touchingClusters.size(); switch (numTouching) { case 0://make new cluster { int64_t newCluster = allocCluster(clusterList, deadClusters); clusterList[newCluster].addMember(voxel, value, voxelVolume, param_e, param_h); membership[voxelIndex] = newCluster; break; } case 1://add to cluster { int64_t whichCluster = *(touchingClusters.begin()); clusterList[whichCluster].addMember(voxel, value, voxelVolume, param_e, param_h); membership[voxelIndex] = whichCluster; accumData[voxelIndex] -= clusterList[whichCluster].accumVal;//the accum value is the current amount less than the peak value that the edge of the cluster has (this node is on the edge) break;//so, when the cluster merges or reaches 0, we add the accum value to every member and zero the accum value of the merged cluster, and we get the correct value in the end (with far fewer flops than integrating everywhere) } default://merge all touching clusters { int64_t mergedIndex = -1, biggestSize = 0;//find the biggest cluster (in number of members) and use as merged cluster, for optimization purposes for (set::iterator iter = touchingClusters.begin(); iter != touchingClusters.end(); ++iter) { if ((int64_t)clusterList[*iter].members.size() > biggestSize) { mergedIndex = *iter; biggestSize = (int64_t)clusterList[*iter].members.size(); } } CaretAssertVectorIndex(clusterList, mergedIndex); Cluster& mergedCluster = clusterList[mergedIndex]; mergedCluster.update(value, param_e, param_h);//recalculate to align cluster bottoms for (set::iterator iter = touchingClusters.begin(); iter != touchingClusters.end(); ++iter) { if (*iter != mergedIndex)//if we are the largest cluster, don't modify the per-voxel accum for members, so merges between small and large clusters are cheap { Cluster& thisCluster = clusterList[*iter]; thisCluster.update(value, param_e, param_h); int64_t numMembers = (int64_t)thisCluster.members.size(); double correctionVal = thisCluster.accumVal - mergedCluster.accumVal;//fix the accum values in the side cluster so we can add the merged cluster's accum to everything at the end for (int64_t j = 0; j < numMembers; ++j)//add the correction value to every member so that we have the current integrated values correct { int64_t memberIndex = inVol->getIndex(thisCluster.members[j].m_ijk); accumData[memberIndex] += correctionVal;//apply the correction membership[memberIndex] = mergedIndex;//and update membership } mergedCluster.members.insert(mergedCluster.members.end(), thisCluster.members.begin(), thisCluster.members.end());//copy all members mergedCluster.totalVolume += thisCluster.totalVolume; deadClusters.insert(*iter);//kill it vector().swap(clusterList[*iter].members);//also try to deallocate member list } } mergedCluster.addMember(voxel, value, voxelVolume, param_e, param_h);//will not trigger recomputation, we already recomputed at this value accumData[voxelIndex] -= mergedCluster.accumVal;//the voxel they merge on must not get the peak value of the cluster, obviously, so again, record its difference from peak membership[voxelIndex] = mergedIndex; break;//NOTE: do not reset the accum value of the merged cluster, we specifically avoided modifying the per-voxel accum for its members, so the cluster accum is still in play } } } int listSize = (int)clusterList.size();//final cleanup of accum values for (int i = 0; i < listSize; ++i) { if (deadClusters.find(i) != deadClusters.end()) continue;//ignore clusters that don't exist Cluster& thisCluster = clusterList[i]; thisCluster.update(0.0f, param_e, param_h);//update to include the to-zero slice int numMembers = (int)thisCluster.members.size(); for (int j = 0; j < numMembers; ++j) { accumData[inVol->getIndex(thisCluster.members[j].m_ijk)] += thisCluster.accumVal;//add the resulting slice to all members - their stored data contains the offset between the cluster peak and their corect value } } } float AlgorithmVolumeTFCE::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeTFCE::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeTFCE.h000066400000000000000000000042121360521144700244630ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_TFCE_H__ #define __ALGORITHM_VOLUME_TFCE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" namespace caret { class AlgorithmVolumeTFCE : public AbstractAlgorithm { AlgorithmVolumeTFCE(); void processFrame(const VolumeFile* inVol, const int64_t& b, const int64_t& c, float* outData, const float* roiData, const float& param_e, const float& param_h); void tfce(const VolumeFile* inVol, const int64_t& b, const int64_t& c, double* accumData, const float* roiData, const float& param_e, const float& param_h, const bool& negate); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeTFCE(ProgressObject* myProgObj, const VolumeFile* myVol, VolumeFile* myVolOut, const float& presmooth = 0.0f, const VolumeFile* myRoi = NULL, const float& param_e = 0.5f, const float& param_h = 2.0f, const int64_t& subvolNum = -1); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeTFCE; } #endif //__ALGORITHM_VOLUME_TFCE_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeToSurfaceMapping.cxx000066400000000000000000001011211360521144700275210ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeToSurfaceMapping.h" #include "AlgorithmException.h" #include "CaretOMP.h" #include "FloatMatrix.h" #include "MathFunctions.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "TopologyHelper.h" #include "Vector3D.h" #include "VolumeFile.h" #include "AlgorithmSurfaceToSurface3dDistance.h" #include "AlgorithmCreateSignedDistanceVolume.h" #include #include using namespace caret; using namespace std; AString AlgorithmVolumeToSurfaceMapping::getCommandSwitch() { return "-volume-to-surface-mapping"; } AString AlgorithmVolumeToSurfaceMapping::getShortDescription() { return "MAP VOLUME TO SURFACE"; } OperationParameters* AlgorithmVolumeToSurfaceMapping::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume", "the volume to map data from"); ret->addSurfaceParameter(2, "surface", "the surface to map the data onto"); ret->addMetricOutputParameter(3, "metric-out", "the output metric file"); ret->createOptionalParameter(4, "-trilinear", "use trilinear volume interpolation"); ret->createOptionalParameter(5, "-enclosing", "use value of the enclosing voxel"); ret->createOptionalParameter(8, "-cubic", "use cubic splines"); OptionalParameter* ribbonOpt = ret->createOptionalParameter(6, "-ribbon-constrained", "use ribbon constrained mapping algorithm"); ribbonOpt->addSurfaceParameter(1, "inner-surf", "the inner surface of the ribbon"); ribbonOpt->addSurfaceParameter(2, "outer-surf", "the outer surface of the ribbon"); OptionalParameter* roiVol = ribbonOpt->createOptionalParameter(3, "-volume-roi", "use a volume roi"); roiVol->addVolumeParameter(1, "roi-volume", "the volume file"); OptionalParameter* ribbonSubdiv = ribbonOpt->createOptionalParameter(4, "-voxel-subdiv", "voxel divisions while estimating voxel weights"); ribbonSubdiv->addIntegerParameter(1, "subdiv-num", "number of subdivisions, default 3"); ribbonOpt->createOptionalParameter(7, "-thin-columns", "use non-overlapping polyhedra"); OptionalParameter* gaussianOpt = ribbonOpt->createOptionalParameter(8, "-gaussian", "reduce weight to voxels that aren't near "); gaussianOpt->addDoubleParameter(1, "scale", "value to multiply the local thickness by, to get the gaussian sigma"); OptionalParameter* badVertOpt = ribbonOpt->createOptionalParameter(9, "-bad-vertices-out", "output an ROI of which vertices didn't intersect any valid voxels"); badVertOpt->addMetricOutputParameter(1, "roi-out", "the output metric file of vertices that have no data"); OptionalParameter* ribbonWeights = ribbonOpt->createOptionalParameter(5, "-output-weights", "write the voxel weights for a vertex to a volume file"); ribbonWeights->addIntegerParameter(1, "vertex", "the vertex number to get the voxel weights for, 0-based"); ribbonWeights->addVolumeOutputParameter(2, "weights-out", "volume to write the weights to"); OptionalParameter* ribbonWeightsText = ribbonOpt->createOptionalParameter(6, "-output-weights-text", "write the voxel weights for all vertices to a text file"); ribbonWeightsText->addStringParameter(1, "text-out", "output - the output text filename");//fake the output formatting OptionalParameter* myelinStyleOpt = ret->createOptionalParameter(9, "-myelin-style", "use the method from myelin mapping"); myelinStyleOpt->addVolumeParameter(1, "ribbon-roi", "an roi volume of the cortical ribbon for this hemisphere"); myelinStyleOpt->addMetricParameter(2, "thickness", "a metric file of cortical thickness"); myelinStyleOpt->addDoubleParameter(3, "sigma", "gaussian kernel in mm for weighting voxels within range"); myelinStyleOpt->createOptionalParameter(4, "-legacy-bug", "emulate old v1.2.3 and earlier code that didn't follow a cylinder cutoff"); OptionalParameter* subvolumeSelect = ret->createOptionalParameter(7, "-subvol-select", "select a single subvolume to map"); subvolumeSelect->addStringParameter(1, "subvol", "the subvolume number or name"); ret->setHelpText( AString("You must specify exactly one mapping method. Enclosing voxel uses the value from the voxel the vertex lies inside, while trilinear does a 3D ") + "linear interpolation based on the voxels immediately on each side of the vertex's position.\n\n" + "The ribbon mapping method constructs a polyhedron from the vertex's neighbors on each " + "surface, and estimates the amount of this polyhedron's volume that falls inside any nearby voxels, to use as the weights for sampling. " + "If -thin-columns is specified, the polyhedron uses the edge midpoints and triangle centroids, so that neighboring vertices do not have overlapping polyhedra. " + "This may require increasing -voxel-subdiv to get enough samples in each voxel to reliably land inside these smaller polyhedra. " + "The volume ROI is useful to exclude partial volume effects of voxels the surfaces pass through, and will cause the mapping to ignore " + "voxels that don't have a positive value in the mask. The subdivision number specifies how it approximates the amount of the volume the polyhedron " + "intersects, by splitting each voxel into NxNxN pieces, and checking whether the center of each piece is inside the polyhedron. If you have very large " + "voxels, consider increasing this if you get zeros in your output. " + "The -gaussian option makes it act more like the myelin method, where the distance of a voxel from is used to downweight the voxel.\n\n" + "The myelin style method uses part of the caret5 myelin mapping command to do the mapping: for each surface vertex, take all voxels that are in a cylinder " + "with radius and height equal to cortical thickness, centered on the vertex and aligned with the surface normal, and that are also within the ribbon ROI, " + "and apply a gaussian kernel with the specified sigma to them to get the weights to use. " + "The -legacy-bug flag reverts to the unintended behavior present from the initial implementation up to and including v1.2.3, which had only the tangential cutoff " + "and a bounding box intended to be larger than where the cylinder cutoff should have been." ); return ret; } void AlgorithmVolumeToSurfaceMapping::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* myVolume = myParams->getVolume(1); SurfaceFile* mySurface = myParams->getSurface(2); MetricFile* myMetricOut = myParams->getOutputMetric(3); OptionalParameter* trilinearOpt = myParams->getOptionalParameter(4); OptionalParameter* enclosingOpt = myParams->getOptionalParameter(5); OptionalParameter* cubicOpt = myParams->getOptionalParameter(8); OptionalParameter* ribbonOpt = myParams->getOptionalParameter(6); OptionalParameter* myelinStyleOpt = myParams->getOptionalParameter(9); int64_t mySubVol = -1; OptionalParameter* subvolumeSelect = myParams->getOptionalParameter(7); if (subvolumeSelect->m_present) { mySubVol = (int)myVolume->getMapIndexFromNameOrNumber(subvolumeSelect->getString(1)); if (mySubVol < 0) { throw AlgorithmException("invalid column specified"); } } bool haveMethod = false; Method myMethod = CUBIC;//this tracks which constructor to call VolumeFile::InterpType volInterpMethod = VolumeFile::CUBIC; if (trilinearOpt->m_present) { haveMethod = true; myMethod = TRILINEAR; volInterpMethod = VolumeFile::TRILINEAR; } if (enclosingOpt->m_present) { if (haveMethod) { throw AlgorithmException("more than one mapping method specified"); } haveMethod = true; myMethod = ENCLOSING_VOXEL; volInterpMethod = VolumeFile::ENCLOSING_VOXEL; } if (ribbonOpt->m_present) { if (haveMethod) { throw AlgorithmException("more than one mapping method specified"); } haveMethod = true; myMethod = RIBBON_CONSTRAINED; } if (cubicOpt->m_present) { if (haveMethod) { throw AlgorithmException("more than one mapping method specified"); } haveMethod = true; myMethod = CUBIC; volInterpMethod = VolumeFile::CUBIC; } if (myelinStyleOpt->m_present) { if (haveMethod) { throw AlgorithmException("more than one mapping method specified"); } haveMethod = true; myMethod = MYELIN_STYLE; } if (!haveMethod) { throw AlgorithmException("no mapping method specified"); } switch (myMethod) { case TRILINEAR: case ENCLOSING_VOXEL: case CUBIC: AlgorithmVolumeToSurfaceMapping(myProgObj, myVolume, mySurface, myMetricOut, volInterpMethod, mySubVol);//because we have separate constructors break; case RIBBON_CONSTRAINED: { SurfaceFile* innerSurf = ribbonOpt->getSurface(1); SurfaceFile* outerSurf = ribbonOpt->getSurface(2); OptionalParameter* roiVol = ribbonOpt->getOptionalParameter(3); VolumeFile* myRoiVol = NULL; if (roiVol->m_present) { myRoiVol = roiVol->getVolume(1); } int32_t subdivisions = 3; OptionalParameter* ribbonSubdiv = ribbonOpt->getOptionalParameter(4); if (ribbonSubdiv->m_present) { subdivisions = ribbonSubdiv->getInteger(1); if (subdivisions < 1) { throw AlgorithmException("invalid number of subdivisions specified"); } } bool thinColumns = ribbonOpt->getOptionalParameter(7)->m_present; float gaussScale = -1.0f; OptionalParameter* gaussianOpt = ribbonOpt->getOptionalParameter(8); if (gaussianOpt->m_present) { gaussScale = (float)gaussianOpt->getDouble(1); if (!(gaussScale > 0.0f)) throw AlgorithmException("gaussian scale must be positive"); } MetricFile* badVertices = NULL; OptionalParameter* badVertOpt = ribbonOpt->getOptionalParameter(9); if (badVertOpt->m_present) { badVertices = badVertOpt->getOutputMetric(1); } int weightsOutVertex = -1; VolumeFile* weightsOut = NULL; OptionalParameter* ribbonWeights = ribbonOpt->getOptionalParameter(5); if (ribbonWeights->m_present) { weightsOutVertex = (int)ribbonWeights->getInteger(1); weightsOut = ribbonWeights->getOutputVolume(2); } AlgorithmVolumeToSurfaceMapping(myProgObj, myVolume, mySurface, myMetricOut, innerSurf, outerSurf, myRoiVol, subdivisions, thinColumns, mySubVol, gaussScale, badVertices, weightsOutVertex, weightsOut); OptionalParameter* ribbonWeightsText = ribbonOpt->getOptionalParameter(6); if (ribbonWeightsText->m_present) {//do this after the algorithm, to let it do the error condition checking ofstream outFile(ribbonWeightsText->getString(1).toLocal8Bit().constData()); if (!outFile) throw AlgorithmException("failed to open output textfile '" + ribbonWeightsText->getString(1) + "'"); vector > myWeights; const float* roiFrame = NULL; if (myRoiVol != NULL) roiFrame = myRoiVol->getFrame(); AlgorithmVolumeToSurfaceMapping::precomputeWeightsRibbon(myWeights, myVolume->getVolumeSpace(), innerSurf, outerSurf, roiFrame, subdivisions, thinColumns, mySurface, gaussScale); for (int i = 0; i < (int)myWeights.size(); ++i) { outFile << i << ", " << myWeights[i].size(); for (int j = 0; j < (int)myWeights[i].size(); ++j) { for (int v = 0; v < 3; ++v) { outFile << ", " << myWeights[i][j].ijk[v]; } outFile << ", " << myWeights[i][j].weight; } outFile << endl; } } break; } case MYELIN_STYLE: { VolumeFile* roi = myelinStyleOpt->getVolume(1); MetricFile* thickness = myelinStyleOpt->getMetric(2); float sigma = (float)myelinStyleOpt->getDouble(3); bool oldCutoffBug = myelinStyleOpt->getOptionalParameter(4)->m_present; AlgorithmVolumeToSurfaceMapping(myProgObj, myVolume, mySurface, myMetricOut, roi, thickness, sigma, mySubVol, oldCutoffBug); break; } default: throw AlgorithmException("this method not yet implemented"); } } //interpolation mapping AlgorithmVolumeToSurfaceMapping::AlgorithmVolumeToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, MetricFile* myMetricOut, const VolumeFile::InterpType& myMethod, const int64_t& mySubVol) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); vector myVolDims; myVolume->getDimensions(myVolDims); if (mySubVol >= myVolDims[3] || mySubVol < -1) { throw AlgorithmException("invalid subvolume specified"); } int64_t numColumns; if (mySubVol == -1) { numColumns = myVolDims[3] * myVolDims[4]; } else { numColumns = myVolDims[4]; } int64_t numNodes = mySurface->getNumberOfNodes(); myMetricOut->setNumberOfNodesAndColumns(numNodes, numColumns); myMetricOut->setStructure(mySurface->getStructure()); vector myArray(numNodes); AString methodName; switch (myMethod) { case VolumeFile::CUBIC: methodName = " cubic"; break; case VolumeFile::TRILINEAR: methodName = " trilinear"; break; case VolumeFile::ENCLOSING_VOXEL: methodName = " enclosing voxel"; break; } if (mySubVol == -1) { for (int64_t i = 0; i < myVolDims[3]; ++i) { for (int64_t j = 0; j < myVolDims[4]; ++j) { if (myMethod == VolumeFile::CUBIC) { myVolume->validateSpline(i, j);//to do spline deconvolution in parallel } AString metricLabel = myVolume->getMapName(i); if (myVolDims[4] != 1) { metricLabel += " component " + AString::number(j); } metricLabel += methodName; int64_t thisCol = i * myVolDims[4] + j; myMetricOut->setColumnName(thisCol, metricLabel); #pragma omp CARET_PARFOR for (int64_t node = 0; node < numNodes; ++node) { myArray[node] = myVolume->interpolateValue(mySurface->getCoordinate(node), myMethod, NULL, i, j); } if (myMethod == VolumeFile::CUBIC) { myVolume->freeSpline(i, j);//release memory we no longer need, if we allocated it } myMetricOut->setValuesForColumn(thisCol, myArray.data()); } } } else { for (int64_t j = 0; j < myVolDims[4]; ++j) { if (myMethod == VolumeFile::CUBIC) { myVolume->validateSpline(mySubVol, j);//to do spline deconvolution in parallel } AString metricLabel = myVolume->getMapName(mySubVol); if (myVolDims[4] != 1) { metricLabel += " component " + AString::number(j); } metricLabel += methodName; int64_t thisCol = j; myMetricOut->setColumnName(thisCol, metricLabel); #pragma omp CARET_PARFOR for (int64_t node = 0; node < numNodes; ++node) { myArray[node] = myVolume->interpolateValue(mySurface->getCoordinate(node), myMethod, NULL, mySubVol, j); } if (myMethod == VolumeFile::CUBIC) { myVolume->freeSpline(mySubVol, j);//release memory we no longer need, if we allocated it } myMetricOut->setValuesForColumn(thisCol, myArray.data()); } } } //ribbon mapping AlgorithmVolumeToSurfaceMapping::AlgorithmVolumeToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, MetricFile* myMetricOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const VolumeFile* roiVol, const int32_t& subdivisions, const bool& thinColumns, const int64_t& mySubVol, const float& gaussScale, MetricFile* badVertices, const int& weightsOutVertex, VolumeFile* weightsOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); vector myVolDims; myVolume->getDimensions(myVolDims); if (mySubVol >= myVolDims[3] || mySubVol < -1) { throw AlgorithmException("invalid subvolume specified"); } int64_t numColumns; if (mySubVol == -1) { numColumns = myVolDims[3] * myVolDims[4]; } else { numColumns = myVolDims[4]; } int64_t numNodes = mySurface->getNumberOfNodes(); myMetricOut->setNumberOfNodesAndColumns(numNodes, numColumns); myMetricOut->setStructure(mySurface->getStructure()); vector badVertScratch; if (badVertices != NULL) { badVertices->setNumberOfNodesAndColumns(numNodes, 1); badVertices->setStructure(mySurface->getStructure()); badVertScratch.resize(numNodes, 0.0f); } if (!mySurface->hasNodeCorrespondence(*outerSurf) || !mySurface->hasNodeCorrespondence(*innerSurf)) { throw AlgorithmException("all surfaces must have vertex correspondence"); } if (roiVol != NULL && !roiVol->matchesVolumeSpace(myVolume)) { throw AlgorithmException("roi volume is not in the same volume space as input volume"); } if (weightsOut != NULL) { if (weightsOutVertex < 0 || weightsOutVertex >= numNodes) throw AlgorithmException("invalid vertex for voxel weights output"); vector weightDims = myVolDims; weightDims.resize(3); weightsOut->reinitialize(weightDims, myVolume->getSform()); } vector > myWeights; const float* roiFrame = NULL; if (roiVol != NULL) roiFrame = roiVol->getFrame(); precomputeWeightsRibbon(myWeights, myVolume->getVolumeSpace(), innerSurf, outerSurf, roiFrame, subdivisions, thinColumns, mySurface, gaussScale); if (weightsOut != NULL) { weightsOut->setValueAllVoxels(0.0f); const vector& vertexWeights = myWeights[weightsOutVertex]; int numWeights = (int)vertexWeights.size(); for (int i = 0; i < numWeights; ++i) { weightsOut->setValue(vertexWeights[i].weight, vertexWeights[i].ijk); } } CaretArray myScratchArray(numNodes); float* myScratch = myScratchArray.getArray(); if (mySubVol == -1) { for (int64_t i = 0; i < myVolDims[3]; ++i) { for (int64_t j = 0; j < myVolDims[4]; ++j) { int64_t thisCol = i * myVolDims[4] + j; AString metricLabel = myVolume->getMapName(i); if (myVolDims[4] != 1) { metricLabel += " component " + AString::number(j); } metricLabel += " ribbon constrained"; myMetricOut->setColumnName(thisCol, metricLabel); #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t node = 0; node < numNodes; ++node) { myScratch[node] = 0.0f; float totalWeight = 0.0f; int numVoxels = (int)myWeights[node].size(); for (int voxel = 0; voxel < numVoxels; ++voxel) { float thisWeight = myWeights[node][voxel].weight; totalWeight += thisWeight; myScratch[node] += thisWeight * myVolume->getValue(myWeights[node][voxel].ijk, i, j); } if (totalWeight != 0.0f) { myScratch[node] /= totalWeight; } else { myScratch[node] = 0.0f; if (thisCol == 0 && badVertices != NULL) { badVertScratch[node] = 1.0f; } } } myMetricOut->setValuesForColumn(thisCol, myScratch); } } } else { for (int64_t j = 0; j < myVolDims[4]; ++j) { AString metricLabel = myVolume->getMapName(mySubVol); if (myVolDims[4] != 1) { metricLabel += " component " + AString::number(j); } metricLabel += " ribbon constrained"; int64_t thisCol = j; myMetricOut->setColumnName(thisCol, metricLabel); #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t node = 0; node < numNodes; ++node) { myScratch[node] = 0.0f; float totalWeight = 0.0f; int numVoxels = (int)myWeights[node].size(); for (int voxel = 0; voxel < numVoxels; ++voxel) { float thisWeight = myWeights[node][voxel].weight; totalWeight += thisWeight; myScratch[node] += thisWeight * myVolume->getValue(myWeights[node][voxel].ijk, mySubVol, j); } if (totalWeight != 0.0f) { myScratch[node] /= totalWeight; } else { myScratch[node] = 0.0f; if (badVertices != NULL) { badVertScratch[node] = 1.0f; } } } myMetricOut->setValuesForColumn(thisCol, myScratch); } } if (badVertices != NULL) { badVertices->setValuesForColumn(0, badVertScratch.data()); } } void AlgorithmVolumeToSurfaceMapping::precomputeWeightsRibbon(vector >& myWeights, const VolumeSpace& volSpace, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const float* roiFrame, const int& subdivisions, const bool& thinColumns, const SurfaceFile* gaussSurf, const float& gaussScale) { RibbonMappingHelper::computeWeightsRibbon(myWeights, volSpace, innerSurf, outerSurf, roiFrame, subdivisions, thinColumns); if (gaussScale > 0.0f) { VolumeFile signedDistVol; MetricFile thickness; AlgorithmSurfaceToSurface3dDistance(NULL, innerSurf, outerSurf, &thickness); int numNodes = innerSurf->getNumberOfNodes(); float maxThick = thickness.getValue(0, 0); for (int i = 1; i < numNodes; ++i) { float thisThick = thickness.getValue(i, 0); if (thisThick > maxThick) maxThick = thisThick; } signedDistVol.reinitialize(volSpace); AlgorithmCreateSignedDistanceVolume(NULL, gaussSurf, &signedDistVol, NULL, maxThick * gaussScale * 3.0f, maxThick * gaussScale * 3.0f);//if we somehow have a voxel really far away compared to thickness, treat it as at least 3 sigma for (int i = 0; i < numNodes; ++i) {//modify the weights from the ribbon helper vector& nodeWeights = myWeights[i]; for (int j = 0; j < (int)nodeWeights.size(); ++j) { float toSquare = signedDistVol.getValue(nodeWeights[j].ijk) / (thickness.getValue(i, 0) * gaussScale);//negatives are fine, we are going to square it nodeWeights[j].weight *= exp(-toSquare * toSquare / 2); } } } } //myelin style mapping AlgorithmVolumeToSurfaceMapping::AlgorithmVolumeToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, MetricFile* myMetricOut, const VolumeFile* roiVol, const MetricFile* thickness, const float& sigma, const int64_t& mySubVol, const bool& oldCutoffBug): AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); vector myVolDims; myVolume->getDimensions(myVolDims); if (mySubVol >= myVolDims[3] || mySubVol < -1) { throw AlgorithmException("invalid subvolume specified"); } if (!roiVol->matchesVolumeSpace(myVolume)) { throw AlgorithmException("roi volume is not in the same volume space as input volume"); } int64_t numColumns; if (mySubVol == -1) { numColumns = myVolDims[3] * myVolDims[4]; } else { numColumns = myVolDims[4]; } int64_t numNodes = mySurface->getNumberOfNodes(); myMetricOut->setNumberOfNodesAndColumns(numNodes, numColumns); myMetricOut->setStructure(mySurface->getStructure()); vector > myWeights; precomputeWeightsMyelin(myWeights, mySurface, roiVol, thickness, sigma, oldCutoffBug); vector myScratch(numNodes); if (mySubVol == -1) { for (int64_t i = 0; i < myVolDims[3]; ++i) { for (int64_t j = 0; j < myVolDims[4]; ++j) { int64_t thisCol = i * myVolDims[4] + j; AString metricLabel = myVolume->getMapName(i); if (myVolDims[4] != 1) { metricLabel += " component " + AString::number(j); } metricLabel += " myelin style"; myMetricOut->setColumnName(thisCol, metricLabel); #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t node = 0; node < numNodes; ++node) { double accum = 0.0; int numVoxels = (int)myWeights[node].size(); for (int voxel = 0; voxel < numVoxels; ++voxel) { accum += myWeights[node][voxel].weight * myVolume->getValue(myWeights[node][voxel].ijk, i, j);//weights have already been normalized in precompute, for this method } myScratch[node] = accum; } myMetricOut->setValuesForColumn(thisCol, myScratch.data()); } } } else { for (int64_t j = 0; j < myVolDims[4]; ++j) { AString metricLabel = myVolume->getMapName(mySubVol); if (myVolDims[4] != 1) { metricLabel += " component " + AString::number(j); } metricLabel += " myelin style"; int64_t thisCol = j; myMetricOut->setColumnName(thisCol, metricLabel); #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t node = 0; node < numNodes; ++node) { double accum = 0.0; int numVoxels = (int)myWeights[node].size(); for (int voxel = 0; voxel < numVoxels; ++voxel) { accum += myWeights[node][voxel].weight * myVolume->getValue(myWeights[node][voxel].ijk, mySubVol, j);//weights have already been normalized in precompute, for this method } myScratch[node] = accum; } myMetricOut->setValuesForColumn(thisCol, myScratch.data()); } } } void AlgorithmVolumeToSurfaceMapping::precomputeWeightsMyelin(vector >& myWeights, const SurfaceFile* mySurface, const VolumeFile* roiVol, const MetricFile* thickness, const float& sigma, const bool& oldCutoffBug) { int64_t numNodes = mySurface->getNumberOfNodes(); myWeights.clear(); myWeights.resize(numNodes); vector myDims; roiVol->getDimensions(myDims); vector > volSpace = roiVol->getSform();//same as input volume Vector3D ivec, jvec, kvec, origin, ijorth, jkorth, kiorth; ivec[0] = volSpace[0][0]; jvec[0] = volSpace[0][1]; kvec[0] = volSpace[0][2]; origin[0] = volSpace[0][3]; ivec[1] = volSpace[1][0]; jvec[1] = volSpace[1][1]; kvec[1] = volSpace[1][2]; origin[1] = volSpace[1][3]; ivec[2] = volSpace[2][0]; jvec[2] = volSpace[2][1]; kvec[2] = volSpace[2][2]; origin[2] = volSpace[2][3]; ijorth = ivec.cross(jvec).normal();//find the box in index space that encloses a sphere of radius 1 jkorth = jvec.cross(kvec).normal(); kiorth = kvec.cross(ivec).normal(); float range[3]; range[0] = abs(1.0f / ivec.dot(jkorth));//we can multiply these by thickness to get the range of voxels to check range[1] = abs(1.0f / jvec.dot(kiorth)); range[2] = abs(1.0f / kvec.dot(ijorth)); const float* thicknessData = thickness->getValuePointerForColumn(0); const float* normals = mySurface->getNormalData(); float invnegsigmasquaredx2 = -1.0f / (2.0f * sigma * sigma); #pragma omp CARET_PARFOR schedule(dynamic) for (int node = 0; node < numNodes; ++node) { Vector3D nodeCoord = mySurface->getCoordinate(node), nodeIndices, nodenormal = normals + (node * 3); roiVol->spaceToIndex(nodeCoord, nodeIndices); float nodeThick = thicknessData[node]; float cylinderCorner = nodeThick * sqrt(5.0f) / 2.0f; if (oldCutoffBug) { cylinderCorner = nodeThick;//old code didn't use a large enough box to always cover the cylinder corner } int64_t min[3], max[3]; for (int i = 0; i < 3; ++i) { min[i] = (int)ceil(nodeIndices[i] - range[i] * cylinderCorner); if (min[i] < 0) min[i] = 0; max[i] = (int)floor(nodeIndices[i] + range[i] * cylinderCorner) + 1; if (max[i] > myDims[i]) max[i] = myDims[i]; } double weightTotal = 0.0; int64_t ijk[3]; for (ijk[2] = min[2]; ijk[2] < max[2]; ++ijk[2]) { for (ijk[1] = min[1]; ijk[1] < max[1]; ++ijk[1]) { for (ijk[0] = min[0]; ijk[0] < max[0]; ++ijk[0]) { Vector3D voxelCoord; roiVol->indexToSpace(ijk, voxelCoord); Vector3D delta = voxelCoord - nodeCoord; if (abs(nodenormal.dot(delta)) < 0.5f * nodeThick && (oldCutoffBug || nodenormal.cross(delta).length() < nodeThick) && roiVol->getValue(ijk) > 0.0f) {//old code ignored the tangential distance, only using the box edge float weight = exp(delta.lengthsquared() * invnegsigmasquaredx2); myWeights[node].push_back(VoxelWeight(weight, ijk)); weightTotal += weight; } } } } int numWeights = (int)myWeights[node].size(); for (int i = 0; i < numWeights; ++i) { myWeights[node][i].weight /= weightTotal;//normalize weights to eliminate the need to divide } } } float AlgorithmVolumeToSurfaceMapping::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeToSurfaceMapping::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeToSurfaceMapping.h000066400000000000000000000072531360521144700271610ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_TO_SURFACE_MAPPING_H__ #define __ALGORITHM_VOLUME_TO_SURFACE_MAPPING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "RibbonMappingHelper.h" #include "Vector3D.h" #include "VolumeFile.h" #include namespace caret { class AlgorithmVolumeToSurfaceMapping : public AbstractAlgorithm { AlgorithmVolumeToSurfaceMapping(); static void precomputeWeightsMyelin(std::vector >& myWeights, const SurfaceFile* mySurface, const VolumeFile* roiVol, const MetricFile* thickness, const float& sigma, const bool& oldCutoffBug); static void precomputeWeightsRibbon(std::vector >& myWeights, const VolumeSpace& volSpace, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const float* roiFrame, const int& subdivisions, const bool& thinColumns, const SurfaceFile* gaussSurf, const float& gaussScale); enum Method { TRILINEAR, ENCLOSING_VOXEL, RIBBON_CONSTRAINED, CUBIC, MYELIN_STYLE }; protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, MetricFile* myMetricOut, const VolumeFile::InterpType& myMethod, const int64_t& mySubVol = -1); AlgorithmVolumeToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, MetricFile* myMetricOut, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const VolumeFile* roiVol = NULL, const int32_t& subdivisions = 3, const bool& thinColumns = false, const int64_t& mySubVol = -1, const float& gaussScale = -1.0f, MetricFile* badVertices = NULL, const int& weightsOutVertex = -1, VolumeFile* weightsOut = NULL); AlgorithmVolumeToSurfaceMapping(ProgressObject* myProgObj, const VolumeFile* myVolume, const SurfaceFile* mySurface, MetricFile* myMetricOut, const VolumeFile* roiVol, const MetricFile* thickness, const float& sigma, const int64_t& mySubVol = -1, const bool& oldCutoffBug = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeToSurfaceMapping; } #endif //__ALGORITHM_VOLUME_TO_SURFACE_MAPPING_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeVectorOperation.cxx000066400000000000000000000202241360521144700274410ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeVectorOperation.h" #include "AlgorithmException.h" #include "VolumeFile.h" using namespace caret; using namespace std; AString AlgorithmVolumeVectorOperation::getCommandSwitch() { return "-volume-vector-operation"; } AString AlgorithmVolumeVectorOperation::getShortDescription() { return "DO A VECTOR OPERATION ON VOLUME FILES"; } OperationParameters* AlgorithmVolumeVectorOperation::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "vectors-a", "first vector input file"); ret->addVolumeParameter(2, "vectors-b", "second vector input file"); ret->addStringParameter(3, "operation", "what vector operation to do"); ret->addVolumeOutputParameter(4, "volume-out", "the output file"); ret->createOptionalParameter(5, "-normalize-a", "normalize vectors of first input"); ret->createOptionalParameter(6, "-normalize-b", "normalize vectors of second input"); ret->createOptionalParameter(7, "-normalize-output", "normalize output vectors (not valid for dot product)"); ret->createOptionalParameter(8, "-magnitude", "output the magnitude of the result (not valid for dot product)"); AString myText = AString("Does a vector operation on two volume files (that must have a multiple of 3 subvolumes). ") + "Either of the inputs may have multiple vectors (more than 3 subvolumes), but not both (at least one must have exactly 3 subvolumes). " + "The -magnitude and -normalize-output options may not be specified together, or with the DOT operation. " + "The parameter must be one of the following:\n"; vector opList = VectorOperation::getAllOperations(); for (int i = 0; i < (int)opList.size(); ++i) { myText += "\n" + VectorOperation::operationToString(opList[i]); } ret->setHelpText(myText); return ret; } void AlgorithmVolumeVectorOperation::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* volumeA = myParams->getVolume(1); VolumeFile* volumeB = myParams->getVolume(2); AString operString = myParams->getString(3); bool ok = false; VectorOperation::Operation myOper = VectorOperation::stringToOperation(operString, ok); if (!ok) throw AlgorithmException("unrecognized operation string: " + operString); VolumeFile* myVolumeOut = myParams->getOutputVolume(4); bool normA = myParams->getOptionalParameter(5)->m_present; bool normB = myParams->getOptionalParameter(6)->m_present; bool normOut = myParams->getOptionalParameter(7)->m_present; bool magOut = myParams->getOptionalParameter(8)->m_present; AlgorithmVolumeVectorOperation(myProgObj, volumeA, volumeB, myOper, myVolumeOut, normA, normB, normOut, magOut); } AlgorithmVolumeVectorOperation::AlgorithmVolumeVectorOperation(ProgressObject* myProgObj, const VolumeFile* volumeA, const VolumeFile* volumeB, const VectorOperation::Operation& myOper, VolumeFile* myVolumeOut, const bool& normA, const bool& normB, const bool& normOut, const bool& magOut) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); const VolumeSpace& checkSpace = volumeA->getVolumeSpace(); if (!volumeB->matchesVolumeSpace(checkSpace)) throw AlgorithmException("input files have different volume spaces"); const vector dimA = volumeA->getDimensions(), dimB = volumeB->getDimensions(); if (dimA[4] != 1 || dimB[4] != 1) throw AlgorithmException("volumes with multiple components (complex or rgb datatypes) are not supported in vector operations"); if (dimA[3] % 3 != 0) throw AlgorithmException("number of subvolumes in first input is not a multiple of 3"); if (dimB[3] % 3 != 0) throw AlgorithmException("number of subvolumes in first input is not a multiple of 3"); int64_t numVecA = dimA[3] / 3, numVecB = dimB[3] / 3; if (numVecA > 1 && numVecB > 1) throw AlgorithmException("both inputs have more than 3 subvolumes (more than 1 vector)"); if (normOut && magOut) throw AlgorithmException("normalizing the output and taking the magnitude is meaningless"); bool opScalarResult = VectorOperation::operationReturnsScalar(myOper); if (opScalarResult && (normOut || magOut)) throw AlgorithmException("cannot normalize or take magnitude of a scalar result (such as a dot product)"); bool swapped = false; const VolumeFile* multiVec = volumeA, *singleVec = volumeB; int64_t numOutVecs = numVecA; if (numVecB > 1) { multiVec = volumeB; singleVec = volumeA; numOutVecs = numVecB; swapped = true; } int64_t numSubvolsOut = numOutVecs * 3; if (opScalarResult || magOut) numSubvolsOut = numOutVecs; vector outDims = dimA; outDims.resize(3); if (numSubvolsOut > 1) outDims.push_back(numSubvolsOut); myVolumeOut->reinitialize(outDims, checkSpace.getSform()); int64_t frameSize = dimA[0] * dimA[1] * dimA[2]; vector outFrames[3];//let the scalar result case overallocate outFrames[0].resize(frameSize); outFrames[1].resize(frameSize); outFrames[2].resize(frameSize); const float* xFrameSingle = singleVec->getFrame(0); const float* yFrameSingle = singleVec->getFrame(1); const float* zFrameSingle = singleVec->getFrame(2); for (int64_t v = 0; v < numOutVecs; ++v) { const float* xFrameMulti = multiVec->getFrame(v * 3); const float* yFrameMulti = multiVec->getFrame(v * 3 + 1); const float* zFrameMulti = multiVec->getFrame(v * 3 + 2); for (int64_t i = 0; i < frameSize; ++i) { Vector3D vecA(xFrameMulti[i], yFrameMulti[i], zFrameMulti[i]); Vector3D vecB(xFrameSingle[i], yFrameSingle[i], zFrameSingle[i]); if (swapped) { Vector3D tempVec = vecA; vecA = vecB; vecB = tempVec; } if (normA) vecA = vecA.normal(); if (normB) vecB = vecB.normal(); if (opScalarResult) { outFrames[0][i] = VectorOperation::doScalarOperation(vecA, vecB, myOper); } else { Vector3D tempVec = VectorOperation::doVectorOperation(vecA, vecB, myOper); if (normOut) tempVec = tempVec.normal(); if (magOut) { outFrames[0][i] = tempVec.length(); } else { outFrames[0][i] = tempVec[0]; outFrames[1][i] = tempVec[1]; outFrames[2][i] = tempVec[2]; } } } if (opScalarResult || magOut) { myVolumeOut->setFrame(outFrames[0].data(), v); } else { myVolumeOut->setFrame(outFrames[0].data(), v * 3); myVolumeOut->setFrame(outFrames[1].data(), v * 3 + 1); myVolumeOut->setFrame(outFrames[2].data(), v * 3 + 2); } } } float AlgorithmVolumeVectorOperation::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeVectorOperation::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeVectorOperation.h000066400000000000000000000037631360521144700270770ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_VECTOR_OPERATION_H__ #define __ALGORITHM_VOLUME_VECTOR_OPERATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "VectorOperation.h" namespace caret { class AlgorithmVolumeVectorOperation : public AbstractAlgorithm { AlgorithmVolumeVectorOperation(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeVectorOperation(ProgressObject* myProgObj, const VolumeFile* volumeA, const VolumeFile* volumeB, const VectorOperation::Operation& myOper, VolumeFile* myVolumeOut, const bool& normA = false, const bool& normB = false, const bool& normOut = false, const bool& magOut = false); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeVectorOperation; } #endif //__ALGORITHM_VOLUME_VECTOR_OPERATION_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeWarpfieldAffineRegression.cxx000066400000000000000000000156461360521144700314210ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeWarpfieldAffineRegression.h" #include "AlgorithmException.h" #include "AffineFile.h" #include "MatrixFunctions.h" #include "Vector3D.h" #include "VolumeFile.h" #include "WarpfieldFile.h" using namespace caret; using namespace std; AString AlgorithmVolumeWarpfieldAffineRegression::getCommandSwitch() { return "-volume-warpfield-affine-regression"; } AString AlgorithmVolumeWarpfieldAffineRegression::getShortDescription() { return "REGRESS AFFINE FROM WARPFIELD"; } OperationParameters* AlgorithmVolumeWarpfieldAffineRegression::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "warpfield", "the input warpfield"); ret->addStringParameter(2, "affine-out", "output - the output affine file");//HACK: fake the output help formatting OptionalParameter* roiOpt = ret->createOptionalParameter(3, "-roi", "only consider voxels within a mask (e.g., a brain mask)"); roiOpt->addVolumeParameter(1, "roi-vol", "the mask volume"); OptionalParameter* fnirtInOpt = ret->createOptionalParameter(4, "-fnirt", "input is a fnirt warpfield"); fnirtInOpt->addStringParameter(1, "source-volume", "the source volume used when generating the fnirt warpfield"); OptionalParameter* flirtOutOpt = ret->createOptionalParameter(5, "-flirt-out", "write output as a flirt matrix rather than a world coordinate transform"); flirtOutOpt->addStringParameter(1, "source-volume", "the volume you want to apply the transform to"); flirtOutOpt->addStringParameter(2, "target-volume", "the target space you want the transformed volume to match"); ret->setHelpText( AString("For all voxels in the warpfield, do a regression that predicts the post-warp coordinate from the source coordinate. ") + "When -roi is specified, only consider voxels with a value greater than 0 in .\n\n" + "The default is to expect the warpfield to be in relative world coordinates (mm space), and to write the output as a world affine (mm space to mm space). " + "If you are using FSL-created files and utilities, specify -fnirt and -flirt as needed, as their coordinate conventions are different." ); return ret; } void AlgorithmVolumeWarpfieldAffineRegression::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { AString warpfieldName = myParams->getString(1); AString affineOutName = myParams->getString(2); VolumeFile* myRoi = NULL; OptionalParameter* roiOpt = myParams->getOptionalParameter(3); if (roiOpt->m_present) { myRoi = roiOpt->getVolume(1); } WarpfieldFile myWarpfield; OptionalParameter* fnirtInOpt = myParams->getOptionalParameter(4); if (fnirtInOpt->m_present) { myWarpfield.readFnirt(warpfieldName, fnirtInOpt->getString(1)); } else { myWarpfield.readWorld(warpfieldName); } FloatMatrix affineMatOut; AlgorithmVolumeWarpfieldAffineRegression(myProgObj, myWarpfield.getWarpfield(), affineMatOut, myRoi); AffineFile affineOut; affineOut.setMatrix(affineMatOut); OptionalParameter* flirtOutOpt = myParams->getOptionalParameter(5); if (flirtOutOpt->m_present) { affineOut.writeFlirt(affineOutName, flirtOutOpt->getString(1), flirtOutOpt->getString(2)); } else { affineOut.writeWorld(affineOutName); } } AlgorithmVolumeWarpfieldAffineRegression::AlgorithmVolumeWarpfieldAffineRegression(ProgressObject* myProgObj, const VolumeFile* warpVol, FloatMatrix& affineMatOut, const VolumeFile* myRoi) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); if (myRoi != NULL && !warpVol->matchesVolumeSpace(myRoi)) { throw AlgorithmException("roi volume does not match the volume space of the warpfield"); } vector voldims = warpVol->getDimensions(); if (voldims[3] != 3) { throw AlgorithmException("warpfield volume does not have 3 subvolumes"); } //three regressions with the same predictors and different target values vector > indep(4, vector(4, 0.0)), dep(4, vector(3, 0.0)); for (int64_t k = 0; k < voldims[2]; ++k) { for (int64_t j = 0; j < voldims[1]; ++j) { for (int64_t i = 0; i < voldims[0]; ++i) { if (myRoi == NULL || myRoi->getValue(i, j, k) > 0.0f) { Vector3D outCoord, displacement, inCoord;//outCoord is the post-warp coordinate warpVol->indexToSpace(i, j, k, outCoord); displacement[0] = warpVol->getValue(i, j, k, 0); displacement[1] = warpVol->getValue(i, j, k, 1); displacement[2] = warpVol->getValue(i, j, k, 2); inCoord = outCoord + displacement; for (int dim1 = 0; dim1 < 3; ++dim1)//compute X' * X and X' * Y { for (int dim2 = 0; dim2 < 3; ++dim2) { indep[dim1][dim2] += inCoord[dim1] * inCoord[dim2]; dep[dim2][dim1] += outCoord[dim1] * inCoord[dim2]; } indep[dim1][3] += inCoord[dim1]; indep[3][dim1] += inCoord[dim1]; dep[3][dim1] += outCoord[dim1]; } indep[3][3] += 1.0; } } } } vector > rrefMat; MatrixFunctions::horizCat(indep, dep, rrefMat); MatrixFunctions::rref(rrefMat); affineMatOut = FloatMatrix::identity(4); for (int dim1 = 0; dim1 < 3; ++dim1) { for (int dim2 = 0; dim2 < 4; ++dim2) { affineMatOut[dim1][dim2] = rrefMat[dim2][4 + dim1]; } } } float AlgorithmVolumeWarpfieldAffineRegression::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeWarpfieldAffineRegression::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeWarpfieldAffineRegression.h000066400000000000000000000035421360521144700310360ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_WARPFIELD_AFFINE_REGRESSION_H__ #define __ALGORITHM_VOLUME_WARPFIELD_AFFINE_REGRESSION_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "FloatMatrix.h" namespace caret { class AlgorithmVolumeWarpfieldAffineRegression : public AbstractAlgorithm { AlgorithmVolumeWarpfieldAffineRegression(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeWarpfieldAffineRegression(ProgressObject* myProgObj, const VolumeFile* warpVol, FloatMatrix& affineMatOut, const VolumeFile* myRoi = NULL); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeWarpfieldAffineRegression; } #endif //__ALGORITHM_VOLUME_WARPFIELD_AFFINE_REGRESSION_H__ connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeWarpfieldResample.cxx000066400000000000000000000166731360521144700277410ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmVolumeWarpfieldResample.h" #include "AlgorithmException.h" #include "CaretLogger.h" #include "CaretOMP.h" #include "NiftiIO.h" #include "Vector3D.h" #include "WarpfieldFile.h" using namespace caret; using namespace std; AString AlgorithmVolumeWarpfieldResample::getCommandSwitch() { return "-volume-warpfield-resample"; } AString AlgorithmVolumeWarpfieldResample::getShortDescription() { return "RESAMPLE VOLUME USING WARPFIELD"; } OperationParameters* AlgorithmVolumeWarpfieldResample::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume-in", "volume to resample"); ret->addStringParameter(2, "warpfield", "the warpfield to apply"); ret->addStringParameter(3, "volume-space", "a volume file in the volume space you want for the output"); ret->addStringParameter(4, "method", "the resampling method"); ret->addVolumeOutputParameter(5, "volume-out", "the output volume"); OptionalParameter* fnirtOpt = ret->createOptionalParameter(6, "-fnirt", "MUST be used if using a fnirt warpfield"); fnirtOpt->addStringParameter(1, "source-volume", "the source volume used when generating the warpfield"); ret->setHelpText( AString("Resample a volume file with a warpfield. ") + "The recommended methods are CUBIC (cubic spline) for most data, and ENCLOSING_VOXEL for label data. " "The parameter must be one of:\n\n" + "CUBIC\nENCLOSING_VOXEL\nTRILINEAR" ); return ret; } void AlgorithmVolumeWarpfieldResample::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { VolumeFile* inVol = myParams->getVolume(1); AString warpName = myParams->getString(2); AString refSpaceName = myParams->getString(3); AString method = myParams->getString(4); VolumeFile* outVol = myParams->getOutputVolume(5); OptionalParameter* fnirtOpt = myParams->getOptionalParameter(6); WarpfieldFile myWarpfield; if (fnirtOpt->m_present) { myWarpfield.readFnirt(warpName, fnirtOpt->getString(1)); } else { myWarpfield.readWorld(warpName); } VolumeFile::InterpType myMethod = VolumeFile::CUBIC; if (method == "CUBIC") { myMethod = VolumeFile::CUBIC; } else if (method == "TRILINEAR") { myMethod = VolumeFile::TRILINEAR; } else if (method == "ENCLOSING_VOXEL") { myMethod = VolumeFile::ENCLOSING_VOXEL; } else { throw AlgorithmException("unrecognized interpolation method"); } NiftiIO refSpaceIO; refSpaceIO.openRead(refSpaceName); vector refDims = refSpaceIO.getDimensions(); if (refDims.size() < 3) refDims.resize(3, 1); AlgorithmVolumeWarpfieldResample(myProgObj, inVol, myWarpfield.getWarpfield(), refDims.data(), refSpaceIO.getHeader().getSForm(), myMethod, outVol); } AlgorithmVolumeWarpfieldResample::AlgorithmVolumeWarpfieldResample(ProgressObject* myProgObj, const VolumeFile* inVol, const VolumeFile* warpfield, const int64_t refDims[3], const vector >& refSform, const VolumeFile::InterpType& myMethod, VolumeFile* outVol) : AbstractAlgorithm(myProgObj) { LevelProgress myProgress(myProgObj); vector warpDims; warpfield->getDimensions(warpDims); if (warpDims[3] != 3 || warpDims[4] != 1) throw AlgorithmException("provided warpfield volume has wrong number of subvolumes or components"); vector outDims = inVol->getOriginalDimensions(); if (outDims.size() < 3) throw AlgorithmException("input must have 3 spatial dimensions"); outDims[0] = refDims[0]; outDims[1] = refDims[1]; outDims[2] = refDims[2]; int64_t numMaps = inVol->getNumberOfMaps(), numComponents = inVol->getNumberOfComponents(); outVol->reinitialize(outDims, refSform, numComponents, inVol->getType(), inVol->m_header); vector scratchFrame(outDims[0] * outDims[1] * outDims[2], 0.0f); if (inVol->isMappedWithLabelTable()) { if (myMethod != VolumeFile::ENCLOSING_VOXEL) { CaretLogWarning("using interpolation type other than ENCLOSING_VOXEL on a label volume"); } for (int64_t i = 0; i < numMaps; ++i) { *(outVol->getMapLabelTable(i)) = *(inVol->getMapLabelTable(i)); } } for (int64_t i = 0; i < numMaps; ++i) { outVol->setMapName(i, inVol->getMapName(i)); } for (int64_t c = 0; c < numComponents; ++c) { for (int64_t b = 0; b < numMaps; ++b) { if (myMethod == VolumeFile::CUBIC) { inVol->validateSpline(b, c);//because deconvolve is parallel, but won't execute parallel if we are already in a parallel section } #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t k = 0; k < outDims[2]; ++k) { for (int64_t j = 0; j < outDims[1]; ++j) { for (int64_t i = 0; i < outDims[0]; ++i) { Vector3D outCoord, inCoord, displacement; outVol->indexToSpace(i, j, k, outCoord); bool validDisplacement = false; displacement[0] = warpfield->interpolateValue(outCoord, VolumeFile::TRILINEAR, &validDisplacement, 0); if (validDisplacement) { displacement[1] = warpfield->interpolateValue(outCoord, VolumeFile::TRILINEAR, NULL, 1); displacement[2] = warpfield->interpolateValue(outCoord, VolumeFile::TRILINEAR, NULL, 2); inCoord = outCoord + displacement; float interpVal = inVol->interpolateValue(inCoord, myMethod, NULL, b, c); scratchFrame[outVol->getIndex(i, j, k)] = interpVal; } else { scratchFrame[outVol->getIndex(i, j, k)] = VolumeFile::INVALID_INTERP_VALUE; } } } } outVol->setFrame(scratchFrame.data(), b, c); if (myMethod == VolumeFile::CUBIC) { inVol->freeSpline(b, c);//release memory we no longer need, if we allocated it } } } } float AlgorithmVolumeWarpfieldResample::getAlgorithmInternalWeight() { return 1.0f;//override this if needed, if the progress bar isn't smooth } float AlgorithmVolumeWarpfieldResample::getSubAlgorithmWeight() { //return AlgorithmInsertNameHere::getAlgorithmWeight();//if you use a subalgorithm return 0.0f; } connectome-workbench-1.4.2/src/Algorithms/AlgorithmVolumeWarpfieldResample.h000066400000000000000000000036561360521144700273630ustar00rootroot00000000000000#ifndef __ALGORITHM_VOLUME_WARPFIELD_RESAMPLE_H__ #define __ALGORITHM_VOLUME_WARPFIELD_RESAMPLE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractAlgorithm.h" #include "VolumeFile.h" namespace caret { class AlgorithmVolumeWarpfieldResample : public AbstractAlgorithm { AlgorithmVolumeWarpfieldResample(); protected: static float getSubAlgorithmWeight(); static float getAlgorithmInternalWeight(); public: AlgorithmVolumeWarpfieldResample(ProgressObject* myProgObj, const VolumeFile* inVol, const VolumeFile* warpfield, const int64_t refDims[3], const std::vector >& refSform, const VolumeFile::InterpType& myMethod, VolumeFile* outVol); static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoAlgorithmVolumeWarpfieldResample; } #endif //__ALGORITHM_VOLUME_WARPFIELD_RESAMPLE_H__ connectome-workbench-1.4.2/src/Algorithms/CMakeLists.txt000066400000000000000000000175701360521144700233050ustar00rootroot00000000000000# # Name of project # PROJECT (Algorithms) # # Need XML from Qt # SET(QT_DONT_USE_QTGUI) # # Add QT for includes # if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () # # Create the helper library # ADD_LIBRARY(Algorithms AbstractAlgorithm.h AlgorithmAnnotationResample.h AlgorithmBorderResample.h AlgorithmBorderToVertices.h AlgorithmCiftiAllLabelsToROIs.h AlgorithmCiftiAverage.h AlgorithmCiftiAverageDenseROI.h AlgorithmCiftiAverageROICorrelation.h AlgorithmCiftiCorrelation.h AlgorithmCiftiCorrelationGradient.h AlgorithmCiftiCreateDenseScalar.h AlgorithmCiftiCreateDenseTimeseries.h AlgorithmCiftiCreateLabel.h AlgorithmCiftiCrossCorrelation.h AlgorithmCiftiDilate.h AlgorithmCiftiErode.h AlgorithmCiftiExtrema.h AlgorithmCiftiFalseCorrelation.h AlgorithmCiftiFindClusters.h AlgorithmCiftiGradient.h AlgorithmCiftiLabelAdjacency.h AlgorithmCiftiLabelModifyKeys.h AlgorithmCiftiLabelProbability.h AlgorithmCiftiLabelToBorder.h AlgorithmCiftiLabelToROI.h AlgorithmCiftiMergeDense.h AlgorithmCiftiMergeParcels.h AlgorithmCiftiPairwiseCorrelation.h AlgorithmCiftiParcellate.h AlgorithmCiftiParcelMappingToLabel.h AlgorithmCiftiReduce.h AlgorithmCiftiReorder.h AlgorithmCiftiReplaceStructure.h AlgorithmCiftiResample.h AlgorithmCiftiRestrictDenseMap.h AlgorithmCiftiROIsFromExtrema.h AlgorithmCiftiSeparate.h AlgorithmCiftiSmoothing.h AlgorithmCiftiTranspose.h AlgorithmCiftiVectorOperation.h AlgorithmCreateSignedDistanceVolume.h AlgorithmException.h AlgorithmFiberDotProducts.h AlgorithmFociResample.h AlgorithmGiftiAllLabelsToROIs.h AlgorithmGiftiLabelAddPrefix.h AlgorithmGiftiLabelToROI.h AlgorithmLabelDilate.h AlgorithmLabelErode.h AlgorithmLabelModifyKeys.h AlgorithmLabelProbability.h AlgorithmLabelResample.h AlgorithmLabelToBorder.h AlgorithmLabelToVolumeMapping.h AlgorithmMetricDilate.h AlgorithmMetricErode.h AlgorithmMetricEstimateFWHM.h AlgorithmMetricExtrema.h AlgorithmMetricFalseCorrelation.h AlgorithmMetricFillHoles.h AlgorithmMetricFindClusters.h AlgorithmMetricGradient.h AlgorithmMetricReduce.h AlgorithmMetricRegression.h AlgorithmMetricRemoveIslands.h AlgorithmMetricResample.h AlgorithmMetricROIsFromExtrema.h AlgorithmMetricROIsToBorder.h AlgorithmMetricSmoothing.h AlgorithmMetricTFCE.h AlgorithmMetricToVolumeMapping.h AlgorithmMetricVectorOperation.h AlgorithmMetricVectorTowardROI.h AlgorithmNodesInsideBorder.h AlgorithmSignedDistanceToSurface.h AlgorithmSurfaceAffineRegression.h AlgorithmSurfaceApplyAffine.h AlgorithmSurfaceApplyWarpfield.h AlgorithmSurfaceAverage.h AlgorithmSurfaceCortexLayer.h AlgorithmSurfaceCreateSphere.h AlgorithmSurfaceCurvature.h AlgorithmSurfaceDistortion.h AlgorithmSurfaceFlipLR.h AlgorithmSurfaceGenerateInflated.h AlgorithmSurfaceInflation.h AlgorithmSurfaceMatch.h AlgorithmSurfaceModifySphere.h AlgorithmSurfaceResample.h AlgorithmSurfaceSmoothing.h AlgorithmSurfaceSphereProjectUnproject.h AlgorithmSurfaceToSurface3dDistance.h AlgorithmSurfaceWedgeVolume.h AlgorithmVolumeAffineResample.h AlgorithmVolumeAllLabelsToROIs.h AlgorithmVolumeDilate.h AlgorithmVolumeDistortion.h AlgorithmVolumeErode.h AlgorithmVolumeEstimateFWHM.h AlgorithmVolumeExtrema.h AlgorithmVolumeFillHoles.h AlgorithmVolumeFindClusters.h AlgorithmVolumeGradient.h AlgorithmVolumeLabelModifyKeys.h AlgorithmVolumeLabelProbability.h AlgorithmVolumeLabelToROI.h AlgorithmVolumeLabelToSurfaceMapping.h AlgorithmVolumeParcelResampling.h AlgorithmVolumeParcelResamplingGeneric.h AlgorithmVolumeParcelSmoothing.h AlgorithmVolumeReduce.h AlgorithmVolumeRemoveIslands.h AlgorithmVolumeROIsFromExtrema.h AlgorithmVolumeSmoothing.h AlgorithmVolumeTFCE.h AlgorithmVolumeToSurfaceMapping.h AlgorithmVolumeVectorOperation.h AlgorithmVolumeWarpfieldAffineRegression.h AlgorithmVolumeWarpfieldResample.h OverlapLogicEnum.h AbstractAlgorithm.cxx AlgorithmAnnotationResample.cxx AlgorithmBorderResample.cxx AlgorithmBorderToVertices.cxx AlgorithmCiftiAllLabelsToROIs.cxx AlgorithmCiftiAverage.cxx AlgorithmCiftiAverageDenseROI.cxx AlgorithmCiftiAverageROICorrelation.cxx AlgorithmCiftiCorrelation.cxx AlgorithmCiftiCorrelationGradient.cxx AlgorithmCiftiCreateDenseScalar.cxx AlgorithmCiftiCreateDenseTimeseries.cxx AlgorithmCiftiCreateLabel.cxx AlgorithmCiftiCrossCorrelation.cxx AlgorithmCiftiDilate.cxx AlgorithmCiftiErode.cxx AlgorithmCiftiExtrema.cxx AlgorithmCiftiFalseCorrelation.cxx AlgorithmCiftiFindClusters.cxx AlgorithmCiftiGradient.cxx AlgorithmCiftiLabelAdjacency.cxx AlgorithmCiftiLabelModifyKeys.cxx AlgorithmCiftiLabelProbability.cxx AlgorithmCiftiLabelToBorder.cxx AlgorithmCiftiLabelToROI.cxx AlgorithmCiftiMergeDense.cxx AlgorithmCiftiMergeParcels.cxx AlgorithmCiftiPairwiseCorrelation.cxx AlgorithmCiftiParcellate.cxx AlgorithmCiftiParcelMappingToLabel.cxx AlgorithmCiftiReduce.cxx AlgorithmCiftiReorder.cxx AlgorithmCiftiReplaceStructure.cxx AlgorithmCiftiResample.cxx AlgorithmCiftiRestrictDenseMap.cxx AlgorithmCiftiROIsFromExtrema.cxx AlgorithmCiftiSeparate.cxx AlgorithmCiftiSmoothing.cxx AlgorithmCiftiTranspose.cxx AlgorithmCiftiVectorOperation.cxx AlgorithmCreateSignedDistanceVolume.cxx AlgorithmException.cxx AlgorithmFiberDotProducts.cxx AlgorithmFociResample.cxx AlgorithmGiftiAllLabelsToROIs.cxx AlgorithmGiftiLabelAddPrefix.cxx AlgorithmGiftiLabelToROI.cxx AlgorithmLabelDilate.cxx AlgorithmLabelErode.cxx AlgorithmLabelModifyKeys.cxx AlgorithmLabelProbability.cxx AlgorithmLabelResample.cxx AlgorithmLabelToBorder.cxx AlgorithmLabelToVolumeMapping.cxx AlgorithmMetricDilate.cxx AlgorithmMetricErode.cxx AlgorithmMetricEstimateFWHM.cxx AlgorithmMetricExtrema.cxx AlgorithmMetricFalseCorrelation.cxx AlgorithmMetricFillHoles.cxx AlgorithmMetricFindClusters.cxx AlgorithmMetricGradient.cxx AlgorithmMetricReduce.cxx AlgorithmMetricRegression.cxx AlgorithmMetricRemoveIslands.cxx AlgorithmMetricResample.cxx AlgorithmMetricROIsFromExtrema.cxx AlgorithmMetricROIsToBorder.cxx AlgorithmMetricSmoothing.cxx AlgorithmMetricTFCE.cxx AlgorithmMetricToVolumeMapping.cxx AlgorithmMetricVectorOperation.cxx AlgorithmMetricVectorTowardROI.cxx AlgorithmNodesInsideBorder.cxx AlgorithmSignedDistanceToSurface.cxx AlgorithmSurfaceAffineRegression.cxx AlgorithmSurfaceApplyAffine.cxx AlgorithmSurfaceApplyWarpfield.cxx AlgorithmSurfaceAverage.cxx AlgorithmSurfaceCortexLayer.cxx AlgorithmSurfaceCreateSphere.cxx AlgorithmSurfaceCurvature.cxx AlgorithmSurfaceDistortion.cxx AlgorithmSurfaceFlipLR.cxx AlgorithmSurfaceGenerateInflated.cxx AlgorithmSurfaceInflation.cxx AlgorithmSurfaceMatch.cxx AlgorithmSurfaceModifySphere.cxx AlgorithmSurfaceResample.cxx AlgorithmSurfaceSmoothing.cxx AlgorithmSurfaceSphereProjectUnproject.cxx AlgorithmSurfaceToSurface3dDistance.cxx AlgorithmSurfaceWedgeVolume.cxx AlgorithmVolumeAffineResample.cxx AlgorithmVolumeAllLabelsToROIs.cxx AlgorithmVolumeDilate.cxx AlgorithmVolumeDistortion.cxx AlgorithmVolumeErode.cxx AlgorithmVolumeEstimateFWHM.cxx AlgorithmVolumeExtrema.cxx AlgorithmVolumeFillHoles.cxx AlgorithmVolumeFindClusters.cxx AlgorithmVolumeGradient.cxx AlgorithmVolumeLabelModifyKeys.cxx AlgorithmVolumeLabelProbability.cxx AlgorithmVolumeLabelToROI.cxx AlgorithmVolumeLabelToSurfaceMapping.cxx AlgorithmVolumeParcelResampling.cxx AlgorithmVolumeParcelResamplingGeneric.cxx AlgorithmVolumeParcelSmoothing.cxx AlgorithmVolumeReduce.cxx AlgorithmVolumeRemoveIslands.cxx AlgorithmVolumeROIsFromExtrema.cxx AlgorithmVolumeSmoothing.cxx AlgorithmVolumeTFCE.cxx AlgorithmVolumeToSurfaceMapping.cxx AlgorithmVolumeVectorOperation.cxx AlgorithmVolumeWarpfieldAffineRegression.cxx AlgorithmVolumeWarpfieldResample.cxx OverlapLogicEnum.cxx ) TARGET_LINK_LIBRARIES(Algorithms ${CARET_QT5_LINK}) # # Find Headers # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Algorithms ${CMAKE_SOURCE_DIR}/Annotations ${CMAKE_SOURCE_DIR}/OperationsBase ${CMAKE_SOURCE_DIR}/FilesBase ${CMAKE_SOURCE_DIR}/Files ${CMAKE_SOURCE_DIR}/Gifti ${CMAKE_SOURCE_DIR}/Cifti ${CMAKE_SOURCE_DIR}/Palette ${CMAKE_SOURCE_DIR}/Nifti ${CMAKE_SOURCE_DIR}/Scenes ${CMAKE_SOURCE_DIR}/Xml ${CMAKE_SOURCE_DIR}/Charting ${CMAKE_SOURCE_DIR}/Common ) connectome-workbench-1.4.2/src/Algorithms/OverlapLogicEnum.cxx000066400000000000000000000223161360521144700244760ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __OVERLAP_LOGIC_ENUM_DECLARE__ #include "OverlapLogicEnum.h" #undef __OVERLAP_LOGIC_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::OverlapLogicEnum * \brief Enumeration for how to handle overlapping areas * * Created to be used as a parameter to ROIsFromExtrema algorithms */ /** * Constructor. * * @param enumValue * An enumerated value. * @param integerCode * Integer code for this enumerated value. * * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ OverlapLogicEnum::OverlapLogicEnum(const Enum enumValue, const int32_t integerCode, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCode; this->name = name; this->guiName = guiName; } /** * Destructor. */ OverlapLogicEnum::~OverlapLogicEnum() { } /** * Initialize the enumerated metadata. */ void OverlapLogicEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(OverlapLogicEnum(ALLOW, 0, "ALLOW", "Allow")); enumData.push_back(OverlapLogicEnum(CLOSEST, 1, "CLOSEST", "Closest")); enumData.push_back(OverlapLogicEnum(EXCLUDE, 2, "EXCLUDE", "Exclude")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const OverlapLogicEnum* OverlapLogicEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const OverlapLogicEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString OverlapLogicEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const OverlapLogicEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ OverlapLogicEnum::Enum OverlapLogicEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ALLOW; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const OverlapLogicEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type OverlapLogicEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString OverlapLogicEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const OverlapLogicEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ OverlapLogicEnum::Enum OverlapLogicEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ALLOW; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const OverlapLogicEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type OverlapLogicEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t OverlapLogicEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const OverlapLogicEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ OverlapLogicEnum::Enum OverlapLogicEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ALLOW; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const OverlapLogicEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type OverlapLogicEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void OverlapLogicEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void OverlapLogicEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(OverlapLogicEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void OverlapLogicEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(OverlapLogicEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Algorithms/OverlapLogicEnum.h000066400000000000000000000057771360521144700241370ustar00rootroot00000000000000#ifndef __OVERLAP_LOGIC_ENUM_H__ #define __OVERLAP_LOGIC_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class OverlapLogicEnum { public: /** * Enumerated values. */ enum Enum { /** Allow overlap */ ALLOW, /** Use closer center to resolve overlaps */ CLOSEST, /** Contested areas are unused */ EXCLUDE }; ~OverlapLogicEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: OverlapLogicEnum(const Enum enumValue, const int32_t integerCode, const AString& name, const AString& guiName); static const OverlapLogicEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __OVERLAP_LOGIC_ENUM_DECLARE__ std::vector OverlapLogicEnum::enumData; bool OverlapLogicEnum::initializedFlag = false; #endif // __OVERLAP_LOGIC_ENUM_DECLARE__ } // namespace #endif //__OVERLAP_LOGIC_ENUM_H__ connectome-workbench-1.4.2/src/Annotations/000077500000000000000000000000001360521144700207175ustar00rootroot00000000000000connectome-workbench-1.4.2/src/Annotations/Annotation.cxx000066400000000000000000002377561360521144700236010ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_DECLARE__ #include "Annotation.h" #undef __ANNOTATION_DECLARE__ #include "AnnotationBox.h" #include "AnnotationColorBar.h" #include "AnnotationCoordinate.h" #include "AnnotationGroup.h" #include "AnnotationImage.h" #include "AnnotationLine.h" #include "AnnotationOval.h" #include "AnnotationPercentSizeText.h" #include "AnnotationPointSizeText.h" #include "AnnotationText.h" #include "BrainConstants.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "DisplayGroupAndTabItemHelper.h" #include "MathFunctions.h" #include "Matrix4x4.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::Annotation * \brief Abstract class for annotations. * \ingroup Annotations */ /** * Constructor for an annotation. * * @param drawingType * Type of annotation for drawing. * @param attributeDefaultType * Default type for annotation attributes. */ Annotation::Annotation(const AnnotationTypeEnum::Enum type, const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType) : CaretObjectTracksModification(), DisplayGroupAndTabItemInterface(), SceneableInterface(), m_type(type), m_attributeDefaultType(attributeDefaultType) { initializeAnnotationMembers(); } /** * Destructor. */ Annotation::~Annotation() { delete m_displayGroupAndTabItemHelper; delete m_sceneAssistant; } /** * Copy constructor. * @param obj * Object that is copied. */ Annotation::Annotation(const Annotation& obj) : CaretObjectTracksModification(obj), DisplayGroupAndTabItemInterface(obj), SceneableInterface(obj), m_type(obj.m_type), m_attributeDefaultType(obj.m_attributeDefaultType) { initializeAnnotationMembers(); this->copyHelperAnnotation(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ Annotation& Annotation::operator=(const Annotation& obj) { if (this != &obj) { CaretObjectTracksModification::operator=(obj); this->copyHelperAnnotation(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void Annotation::copyHelperAnnotation(const Annotation& obj) { m_annotationGroupKey.reset(); m_uniqueKey = -1; m_coordinateSpace = obj.m_coordinateSpace; m_tabIndex = obj.m_tabIndex; m_spacerTabIndex = obj.m_spacerTabIndex; m_windowIndex = obj.m_windowIndex; m_viewportCoordinateSpaceViewport[0] = obj.m_viewportCoordinateSpaceViewport[0]; m_viewportCoordinateSpaceViewport[1] = obj.m_viewportCoordinateSpaceViewport[1]; m_viewportCoordinateSpaceViewport[2] = obj.m_viewportCoordinateSpaceViewport[2]; m_viewportCoordinateSpaceViewport[3] = obj.m_viewportCoordinateSpaceViewport[3]; m_lineWidthPixels = obj.m_lineWidthPixels; m_lineWidthPercentage = obj.m_lineWidthPercentage; m_colorLine = obj.m_colorLine; m_colorBackground = obj.m_colorBackground; m_customColorBackground[0] = obj.m_customColorBackground[0]; m_customColorBackground[1] = obj.m_customColorBackground[1]; m_customColorBackground[2] = obj.m_customColorBackground[2]; m_customColorBackground[3] = obj.m_customColorBackground[3]; m_customColorLine[0] = obj.m_customColorLine[0]; m_customColorLine[1] = obj.m_customColorLine[1]; m_customColorLine[2] = obj.m_customColorLine[2]; m_customColorLine[3] = obj.m_customColorLine[3]; m_properties = obj.m_properties; *m_displayGroupAndTabItemHelper = *obj.m_displayGroupAndTabItemHelper; /* * Initializes unique name */ m_uniqueKey = -1; m_name = ""; //setUniqueKey(m_uniqueKey); calling this will cause a crash since we could be in copy constructor and subclass has not been constructed /* * Selected status is NOT copied. */ m_selectedForEditingInWindowFlag.reset(); } /** * @return An identical copy (clone) of "this" annotation. * The type of the annotation is used to ensure the * correct type of annotation is created and returned. */ Annotation* Annotation::clone() const { Annotation* myClone = NULL; switch (getType()) { case AnnotationTypeEnum::BOX: { const AnnotationBox* box = dynamic_cast(this); CaretAssert(box); myClone = new AnnotationBox(*box); } break; case AnnotationTypeEnum::COLOR_BAR: { const AnnotationColorBar* colorBar = dynamic_cast(this); CaretAssert(colorBar); myClone = new AnnotationColorBar(*colorBar); } break; case AnnotationTypeEnum::IMAGE: { const AnnotationImage* image = dynamic_cast(this); CaretAssert(image); myClone = new AnnotationImage(*image); } break; case AnnotationTypeEnum::LINE: { const AnnotationLine* line = dynamic_cast(this); CaretAssert(line); myClone = new AnnotationLine(*line); } break; case AnnotationTypeEnum::OVAL: { const AnnotationOval* oval = dynamic_cast(this); CaretAssert(oval); myClone = new AnnotationOval(*oval); } break; case AnnotationTypeEnum::TEXT: { const AnnotationText* text = dynamic_cast(this); CaretAssert(text); switch (text->getFontSizeType()) { case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT: { const AnnotationPercentSizeText* pctText = dynamic_cast(text); CaretAssert(pctText); myClone = new AnnotationPercentSizeText(*pctText); } break; case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH: { const AnnotationPercentSizeText* pctText = dynamic_cast(text); CaretAssert(pctText); myClone = new AnnotationPercentSizeText(*pctText); } break; case AnnotationTextFontSizeTypeEnum::POINTS: { const AnnotationPointSizeText* pointText = dynamic_cast(text); CaretAssert(pointText); myClone = new AnnotationPointSizeText(*pointText); } } } break; } CaretAssert(myClone); return myClone; } /** * Replace "this" annotation with content of the given annotation. * The annotation must by the same type and class. * * @param annotation * Annotation whose content is copied to "this" annotation. */ void Annotation::replaceWithCopyOfAnnotation(const Annotation* annotation) { CaretAssert(annotation); const AnnotationTypeEnum::Enum myType = getType(); if (myType != annotation->getType()) { CaretLogSevere("Attempting to replace " + AnnotationTypeEnum::toGuiName(myType) + " with annotation of different type: " + AnnotationTypeEnum::toGuiName(annotation->getType())); return; } *this = *annotation; } /** * Set this instance modified. */ void Annotation::setModified() { /* * While this method does not need to be overridden, * doing so enables debugging of invalid modification status. */ CaretObjectTracksModification::setModified(); } /** * @return Is this annotation requiring that it be kept in a fixed * aspect ratio? By default, this is false. This method may be * overridden by annotations that require a fixed aspect ratio * (such as an image annotaiton). */ bool Annotation::isFixedAspectRatio() const { return false; } /** * @return The aspect ratio for annotations that have a fixed aspect ratio. * This method may be overridden by annotations that require a fixed aspect ratio * (such as an image annotaiton). * * If the aspect ratio is unknown return 1. Never return zero. */ float Annotation::getFixedAspectRatio() const { return 1.0; } /** * Apply coloring including line width from annother annotation. * * @param otherAnnotation * Other annotation from which coloring is copied. */ void Annotation::applyColoringFromOther(const Annotation* otherAnnotation) { CaretAssert(otherAnnotation); m_colorBackground = otherAnnotation->m_colorBackground; m_colorLine = otherAnnotation->m_colorLine; m_lineWidthPixels = otherAnnotation->m_lineWidthPixels; m_lineWidthPercentage = otherAnnotation->m_lineWidthPercentage; for (int32_t i = 0; i < 4; i++) { m_customColorBackground[i] = otherAnnotation->m_customColorBackground[i]; m_customColorLine[i] = otherAnnotation->m_customColorLine[i]; } } /** * Factory method for creating an annotation of the given type. * * @param annotationType * Type of annotation that will be created. * @param attributeDefaultType * Default type for annotation attributes. * @return * New annotation of the given type. */ Annotation* Annotation::newAnnotationOfType(const AnnotationTypeEnum::Enum annotationType, const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType) { Annotation* annotation = NULL; switch (annotationType) { case AnnotationTypeEnum::BOX: annotation = new AnnotationBox(attributeDefaultType); break; case AnnotationTypeEnum::COLOR_BAR: annotation = new AnnotationColorBar(attributeDefaultType); break; case AnnotationTypeEnum::IMAGE: annotation = new AnnotationImage(attributeDefaultType); break; case AnnotationTypeEnum::LINE: annotation = new AnnotationLine(attributeDefaultType); break; case AnnotationTypeEnum::OVAL: annotation = new AnnotationOval(attributeDefaultType); break; case AnnotationTypeEnum::TEXT: annotation = new AnnotationPercentSizeText(attributeDefaultType); break; } return annotation; } /** * Initialize members of this class. */ void Annotation::initializeAnnotationMembers() { CaretAssertMessage((m_selectedForEditingInWindowFlag.size() == BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS), ("m_selectedInWindowFlag (size=" + QString::number(m_selectedForEditingInWindowFlag.size()) + ") must be the same size as BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS (size=" + QString::number(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS) + ")")); m_selectedForEditingInWindowFlag.reset(); m_coordinateSpace = AnnotationCoordinateSpaceEnum::TAB; m_tabIndex = -1; m_spacerTabIndex = SpacerTabIndex(); m_windowIndex = -1; m_viewportCoordinateSpaceViewport[0] = 0; m_viewportCoordinateSpaceViewport[1] = 0; m_viewportCoordinateSpaceViewport[2] = 0; m_viewportCoordinateSpaceViewport[3] = 0; m_displayGroupAndTabItemHelper = new DisplayGroupAndTabItemHelper(); /* * Default the unique identifier. * * NOTE: do not call 'setUniqueIdentifier()' * from here as the * type of annotation has not been set * and may cause a crash. */ m_uniqueKey = -1; m_annotationGroupKey.reset(); switch (m_attributeDefaultType) { case AnnotationAttributesDefaultTypeEnum::NORMAL: m_lineWidthPixels = 3.0; m_lineWidthPercentage = 1.0; m_colorBackground = CaretColorEnum::NONE; m_colorLine = CaretColorEnum::WHITE; switch (m_type) { case AnnotationTypeEnum::BOX: break; case AnnotationTypeEnum::COLOR_BAR: m_colorBackground = CaretColorEnum::BLACK; break; case AnnotationTypeEnum::IMAGE: break; case AnnotationTypeEnum::LINE: break; case AnnotationTypeEnum::OVAL: break; case AnnotationTypeEnum::TEXT: m_colorBackground = CaretColorEnum::NONE; m_colorLine = CaretColorEnum::NONE; break; } m_customColorBackground[0] = 0.0; m_customColorBackground[1] = 0.0; m_customColorBackground[2] = 0.0; m_customColorBackground[3] = 1.0; m_customColorLine[0] = 1.0; m_customColorLine[1] = 1.0; m_customColorLine[2] = 1.0; m_customColorLine[3] = 1.0; break; case AnnotationAttributesDefaultTypeEnum::USER: { m_lineWidthPixels = s_userDefaultLineWidthPixelsObsolete; m_lineWidthPercentage = s_userDefaultLineWidthPercentage; m_colorBackground = s_userDefaultColorBackground; m_colorLine = s_userDefaultColorLine; m_customColorBackground[0] = s_userDefaultCustomColorBackground[0]; m_customColorBackground[1] = s_userDefaultCustomColorBackground[1]; m_customColorBackground[2] = s_userDefaultCustomColorBackground[2]; m_customColorBackground[3] = s_userDefaultCustomColorBackground[3]; m_customColorLine[0] = s_userDefaultCustomColorLine[0]; m_customColorLine[1] = s_userDefaultCustomColorLine[1]; m_customColorLine[2] = s_userDefaultCustomColorLine[2]; m_customColorLine[3] = s_userDefaultCustomColorLine[3]; const bool lineBackNoneFlag = ((m_colorLine == CaretColorEnum::NONE) && (m_colorBackground == CaretColorEnum::NONE)); const CaretColorEnum::Enum defaultColor = CaretColorEnum::RED; switch (m_type) { case AnnotationTypeEnum::BOX: if (lineBackNoneFlag) { m_colorBackground = defaultColor; } break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: break; case AnnotationTypeEnum::LINE: if (m_colorLine == CaretColorEnum::NONE) { m_colorLine = defaultColor; } break; case AnnotationTypeEnum::OVAL: if (lineBackNoneFlag) { m_colorBackground = defaultColor; } break; case AnnotationTypeEnum::TEXT: m_colorLine = s_userDefaultForTextColorLine; m_customColorLine[0] = s_userDefaultForTextCustomColorLine[0]; m_customColorLine[1] = s_userDefaultForTextCustomColorLine[1]; m_customColorLine[2] = s_userDefaultForTextCustomColorLine[2]; m_customColorLine[3] = s_userDefaultForTextCustomColorLine[3]; break; } } break; } /* * May need to override colors if both are none BUT NOT for text */ if (m_type != AnnotationTypeEnum::TEXT) { if ((m_colorBackground == CaretColorEnum::NONE) && (m_colorLine == CaretColorEnum::NONE)) { m_colorLine = CaretColorEnum::WHITE; } } /* * Don't allow a line color of NONE for text or line */ bool disallowLineColorNoneFlag = false; switch (m_type) { case AnnotationTypeEnum::BOX: break; case AnnotationTypeEnum::COLOR_BAR: disallowLineColorNoneFlag = true; break; case AnnotationTypeEnum::IMAGE: break; case AnnotationTypeEnum::LINE: disallowLineColorNoneFlag = true; break; case AnnotationTypeEnum::OVAL: break; case AnnotationTypeEnum::TEXT: break; } if (disallowLineColorNoneFlag) { if (m_colorLine == CaretColorEnum::NONE) { m_colorLine = CaretColorEnum::WHITE; if (m_colorBackground == CaretColorEnum::WHITE) { m_colorBackground = CaretColorEnum::NONE; } } } initializeProperties(); switch (m_coordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: setPropertiesForSpecializedUsage(PropertiesSpecializedUsage::VIEWPORT_ANNOTATION); break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } /* * Note: The 'const' members are not saved to the scene as they * are set by constructor. * * The 'selected' status is not saved to the scene. * * Currently this is used for saving color bar attributes * to a scene. */ m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_displayGroupAndTabItemHelper", "DisplayGroupAndTabItemHelper", m_displayGroupAndTabItemHelper); if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { m_sceneAssistant->add("m_coordinateSpace", &m_coordinateSpace); m_sceneAssistant->add("m_colorBackground", &m_colorBackground); m_sceneAssistant->addArray("m_customColorBackground", m_customColorBackground, 4, 0.0); m_sceneAssistant->add("m_colorLine", &m_colorLine); m_sceneAssistant->addArray("m_customColorLine", m_customColorLine, 4, 0.0); } } /** * @return The annotation drawing type. */ AnnotationTypeEnum::Enum Annotation::getType() const { return m_type; } QString Annotation::getShortDescriptiveString() const { QString s = AnnotationTypeEnum::toGuiName(m_type); if (m_type == AnnotationTypeEnum::TEXT) { const AnnotationText* textAnn = dynamic_cast(this); s += (" \"" + textAnn->getText() + "\""); } return s; } /** * Get text displayed in the Paste Menu Items * * @param pasteMenuItemText * Text for paste menu item. * @param pasteSpecialMenuItemText * Text for paste special menu item. */ void Annotation::getTextForPasteMenuItems(AString& pasteMenuItemText, AString& pasteSpecialMenuItemText) const { AString typeName = AnnotationTypeEnum::toGuiName(m_type); switch (m_type) { case AnnotationTypeEnum::BOX: break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: break; case AnnotationTypeEnum::LINE: break; case AnnotationTypeEnum::OVAL: break; case AnnotationTypeEnum::TEXT: { const AnnotationText* textAnn = dynamic_cast(this); CaretAssertMessage(textAnn, "If this fails, it may be due to this method being called from a constructor " "and the subclass constructor has not yet executed."); typeName = ("\"" + textAnn->getText() + "\""); } break; } const AString spaceName = AnnotationCoordinateSpaceEnum::toGuiName(m_coordinateSpace); pasteMenuItemText = ("Paste " + typeName + " in " + spaceName + " Space"); pasteSpecialMenuItemText = ("Paste " + typeName + " and Change Space..."); } /** * @return The coordinate space. */ AnnotationCoordinateSpaceEnum::Enum Annotation::getCoordinateSpace() const { return m_coordinateSpace; } /** * Set the coordinate space. * * @param coordinateSpace * New value for coordinate space. */ void Annotation::setCoordinateSpace(const AnnotationCoordinateSpaceEnum::Enum coordinateSpace) { if (m_coordinateSpace != coordinateSpace) { m_coordinateSpace = coordinateSpace; CaretAssertMessage((m_coordinateSpace != AnnotationCoordinateSpaceEnum::VIEWPORT), "Annotation coordinate space should never change to VIEWPORT space."); setModified(); } } /** * @return Is this annotation in surface coordinate space * with tangent selected for the surface offset vector? */ bool Annotation::isInSurfaceSpaceWithTangentOffset() const { bool flag = false; switch (m_coordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: switch (getSurfaceOffsetVectorType()) { case AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX: break; case AnnotationSurfaceOffsetVectorTypeEnum::SURFACE_NORMAL: break; case AnnotationSurfaceOffsetVectorTypeEnum::TANGENT: flag = true; break; } break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } return flag; } /** * Change a surface space annotation to TANGENT offset and update offset length. * If the annotation is already TANGENT space, no changes are made. */ void Annotation::changeSurfaceSpaceToTangentOffset() { std::vector coords; if (getCoordinateSpace() == AnnotationCoordinateSpaceEnum::SURFACE) { AnnotationOneDimensionalShape* oneDimAnn = castToOneDimensionalShape(); if (oneDimAnn != NULL) { coords.push_back(oneDimAnn->getStartCoordinate()); coords.push_back(oneDimAnn->getEndCoordinate()); } else { AnnotationTwoDimensionalShape* twoDimAnn = castToTwoDimensionalShape(); if (twoDimAnn != NULL) { coords.push_back(twoDimAnn->getCoordinate()); } } for (auto c : coords) { StructureEnum::Enum structure; int32_t surfaceNumberOfNodes; int32_t surfaceNodeIndex; float surfaceOffsetLength; AnnotationSurfaceOffsetVectorTypeEnum::Enum surfaceOffsetVectorType; c->getSurfaceSpace(structure, surfaceNumberOfNodes, surfaceNodeIndex, surfaceOffsetLength, surfaceOffsetVectorType); if (surfaceOffsetVectorType != AnnotationSurfaceOffsetVectorTypeEnum::TANGENT) { surfaceOffsetVectorType = AnnotationSurfaceOffsetVectorTypeEnum::TANGENT; surfaceOffsetLength = 1.0; c->setSurfaceSpace(structure, surfaceNumberOfNodes, surfaceNodeIndex, surfaceOffsetLength, surfaceOffsetVectorType); } } } } /** * Get the rotation for an annotation in surface space with tangent * offset using the given normal vector from the vertex to which the * annotation is attached. * * @param structure * The surface structure. * @param vertexNormal * Normal vector of surface vertex. * @return * Rotation angle so text is oriented up with 'best axis' */ float Annotation::getSurfaceSpaceWithTangentOffsetRotation(const StructureEnum::Enum structure, const float vertexNormal[3]) const { float angleOut(0.0); const AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(this); if (twoDimAnn != NULL) { if (isInSurfaceSpaceWithTangentOffset()) { enum class OrientationType { LEFT_TO_RIGHT = 0, RIGHT_TO_LEFT = 1, POSTERIOR_TO_ANTERIOR = 2, ANTERIOR_TO_POSTERIOR = 3, INFERIOR_TO_SUPERIOR = 4, SUPERIOR_TO_INFERIOR = 5 }; const OrientationType orientations[6] = { OrientationType::LEFT_TO_RIGHT, OrientationType::RIGHT_TO_LEFT, OrientationType::POSTERIOR_TO_ANTERIOR, OrientationType::ANTERIOR_TO_POSTERIOR, OrientationType::INFERIOR_TO_SUPERIOR, OrientationType::SUPERIOR_TO_INFERIOR }; const float orientationVectors[6][3] { { 1.0, 0.0, 0.0 }, { -1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }, { 0.0, -1.0, 0.0 }, { 0.0, 0.0, 1.0 }, { 0.0, 0.0, -1.0 } }; /* * Find orientation that aligns with the vertex's normal vector */ OrientationType matchingOrientation = OrientationType::LEFT_TO_RIGHT; float matchingAngle = 10000.0f; for (int32_t i = 0; i < 6; i++) { const float angle = MathFunctions::angleInDegreesBetweenVectors(orientationVectors[i], vertexNormal); if (angle < matchingAngle) { matchingAngle = angle; matchingOrientation = orientations[i]; } } float surfaceUpAxisVector[3] = { 0.0f, 0.0f, 1.0f }; switch (matchingOrientation) { case OrientationType::LEFT_TO_RIGHT: break; case OrientationType::RIGHT_TO_LEFT: break; case OrientationType::POSTERIOR_TO_ANTERIOR: break; case OrientationType::ANTERIOR_TO_POSTERIOR: break; case OrientationType::INFERIOR_TO_SUPERIOR: surfaceUpAxisVector[0] = 1.0; surfaceUpAxisVector[0] = 0.0; surfaceUpAxisVector[0] = 0.0; break; case OrientationType::SUPERIOR_TO_INFERIOR: surfaceUpAxisVector[0] = -1.0; surfaceUpAxisVector[0] = 0.0; surfaceUpAxisVector[0] = 0.0; break; } /* * Vector for annotation's Y (vector from bottom to top of annotation) */ const float annotationUpYVector[3] { 0.0, 1.0, 0.0 }; /* * Initialize the rotation angle so that the annotation's vertical axis * is aligned with the screen vertical axis when the surface is in the * analogous surface view. For a text annotation, the text should be * flowing left to right across screen. */ Matrix4x4 rotationMatrix; rotationMatrix.setMatrixToOpenGLRotationFromVector(vertexNormal); Matrix4x4 inverseMatrix(rotationMatrix); inverseMatrix.invert(); inverseMatrix.multiplyPoint3(surfaceUpAxisVector); const float alignRotationAngle = MathFunctions::angleInDegreesBetweenVectors(annotationUpYVector, surfaceUpAxisVector); float rotationAngle = alignRotationAngle; switch (matchingOrientation) { case OrientationType::LEFT_TO_RIGHT: rotationAngle = 360.0 - rotationAngle; break; case OrientationType::RIGHT_TO_LEFT: break; case OrientationType::POSTERIOR_TO_ANTERIOR: if (StructureEnum::isRight(structure)) { rotationAngle = 360.0 - rotationAngle; } break; case OrientationType::ANTERIOR_TO_POSTERIOR: if (StructureEnum::isRight(structure)) { rotationAngle = 360.0 - rotationAngle; } break; case OrientationType::INFERIOR_TO_SUPERIOR: if (StructureEnum::isRight(structure)) { rotationAngle += 180.0; } break; case OrientationType::SUPERIOR_TO_INFERIOR: rotationAngle += 90.0; break; } angleOut = rotationAngle; } } return angleOut; } /** * Initialize the rotation for an annotation in surface space with tangent * offset using the given normal vector from the vertex to which the * annotation is attached. * * @param structure * The surface structure. * @param vertexNormal * Normal vector of surface vertex. */ void Annotation::initializeSurfaceSpaceWithTangentOffsetRotation(const StructureEnum::Enum structure, const float vertexNormal[3]) { return; AnnotationTwoDimensionalShape* twoDimAnn = castToTwoDimensionalShape(); if (twoDimAnn != NULL) { if (isInSurfaceSpaceWithTangentOffset()) { const float angle = getSurfaceSpaceWithTangentOffsetRotation(structure, vertexNormal); twoDimAnn->setRotationAngle(angle); } } return; // AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(this); // if (twoDimAnn != NULL) { // if (isInSurfaceSpaceWithTangentOffset()) { // enum class OrientationType { // LEFT_TO_RIGHT = 0, // RIGHT_TO_LEFT = 1, // POSTERIOR_TO_ANTERIOR = 2, // ANTERIOR_TO_POSTERIOR = 3, // INFERIOR_TO_SUPERIOR = 4, // SUPERIOR_TO_INFERIOR = 5 // }; // // const OrientationType orientations[6] = { // OrientationType::LEFT_TO_RIGHT, // OrientationType::RIGHT_TO_LEFT, // OrientationType::POSTERIOR_TO_ANTERIOR, // OrientationType::ANTERIOR_TO_POSTERIOR, // OrientationType::INFERIOR_TO_SUPERIOR, // OrientationType::SUPERIOR_TO_INFERIOR // }; // const float orientationVectors[6][3] { // { 1.0, 0.0, 0.0 }, // { -1.0, 0.0, 0.0 }, // { 0.0, 1.0, 0.0 }, // { 0.0, -1.0, 0.0 }, // { 0.0, 0.0, 1.0 }, // { 0.0, 0.0, -1.0 } // }; // // // /* // * Find orientation that aligns with the vertex's normal vector // */ // OrientationType matchingOrientation = OrientationType::LEFT_TO_RIGHT; // float matchingAngle = 10000.0f; // for (int32_t i = 0; i < 6; i++) { // const float angle = MathFunctions::angleInDegreesBetweenVectors(orientationVectors[i], // vertexNormal); // if (angle < matchingAngle) { // matchingAngle = angle; // matchingOrientation = orientations[i]; // } // } // // float surfaceUpAxisVector[3] = { 0.0f, 0.0f, 1.0f }; // switch (matchingOrientation) { // case OrientationType::LEFT_TO_RIGHT: // break; // case OrientationType::RIGHT_TO_LEFT: // break; // case OrientationType::POSTERIOR_TO_ANTERIOR: // break; // case OrientationType::ANTERIOR_TO_POSTERIOR: // break; // case OrientationType::INFERIOR_TO_SUPERIOR: // surfaceUpAxisVector[0] = 1.0; // surfaceUpAxisVector[0] = 0.0; // surfaceUpAxisVector[0] = 0.0; // break; // case OrientationType::SUPERIOR_TO_INFERIOR: // surfaceUpAxisVector[0] = -1.0; // surfaceUpAxisVector[0] = 0.0; // surfaceUpAxisVector[0] = 0.0; // break; // } // // /* // * Vector for annotation's Y (vector from bottom to top of annotation) // */ // const float annotationUpYVector[3] { // 0.0, // 1.0, // 0.0 // }; // // /* // * Initialize the rotation angle so that the annotation's vertical axis // * is aligned with the screen vertical axis when the surface is in the // * analogous surface view. For a text annotation, the text should be // * flowing left to right across screen. // */ // Matrix4x4 rotationMatrix; // rotationMatrix.setMatrixToOpenGLRotationFromVector(vertexNormal); // Matrix4x4 inverseMatrix(rotationMatrix); // inverseMatrix.invert(); // inverseMatrix.multiplyPoint3(surfaceUpAxisVector); // const float alignRotationAngle = MathFunctions::angleInDegreesBetweenVectors(annotationUpYVector, // surfaceUpAxisVector); // float rotationAngle = alignRotationAngle; // switch (matchingOrientation) { // case OrientationType::LEFT_TO_RIGHT: // rotationAngle = 360.0 - rotationAngle; // break; // case OrientationType::RIGHT_TO_LEFT: // break; // case OrientationType::POSTERIOR_TO_ANTERIOR: // if (StructureEnum::isRight(structure)) { // rotationAngle = 360.0 - rotationAngle; // } // break; // case OrientationType::ANTERIOR_TO_POSTERIOR: // if (StructureEnum::isRight(structure)) { // rotationAngle = 360.0 - rotationAngle; // } // break; // case OrientationType::INFERIOR_TO_SUPERIOR: // if (StructureEnum::isRight(structure)) { // rotationAngle += 180.0; // } // break; // case OrientationType::SUPERIOR_TO_INFERIOR: // rotationAngle += 90.0; // break; // } // // twoDimAnn->setRotationAngle(rotationAngle); // } // } } /** * @return The tab index. Valid only for tab coordinate space annotations. */ int32_t Annotation::getTabIndex() const { return m_tabIndex; } /** * Set tab index. Valid only for tab coordinate space annotations. * * @param tabIndex */ void Annotation::setTabIndex(const int32_t tabIndex) { if (tabIndex != m_tabIndex) { m_tabIndex = tabIndex; setModified(); } } /** * @return Index of the spacer tab. */ SpacerTabIndex Annotation::getSpacerTabIndex() const { return m_spacerTabIndex; } /** * Set index of the spacer tab. * * @param spacerTabIndex * Index of the spacer tab. */ void Annotation::setSpacerTabIndex(const SpacerTabIndex& spacerTabIndex) { if (spacerTabIndex != m_spacerTabIndex) { m_spacerTabIndex = spacerTabIndex; setModified(); } } /** * @return The window index. Valid only for window coordinate space annotations. */ int32_t Annotation::getWindowIndex() const { return m_windowIndex; } /** * Set window index. Valid only for window coordinate space annotations. * * @param tabIndex */ void Annotation::setWindowIndex(const int32_t windowIndex) { if (windowIndex != m_windowIndex) { m_windowIndex = windowIndex; setModified(); } } /** * Get the viewport used by an annotation in viewport coordinate space. * * @param viewportOut * Ouput with the viewport. */ void Annotation::getViewportCoordinateSpaceViewport(int viewportOut[4]) const { viewportOut[0] = m_viewportCoordinateSpaceViewport[0]; viewportOut[1] = m_viewportCoordinateSpaceViewport[1]; viewportOut[2] = m_viewportCoordinateSpaceViewport[2]; viewportOut[3] = m_viewportCoordinateSpaceViewport[3]; } /** * Set the viewport used by an annotation in viewport coordinate space. * * @param viewport * Input with the viewport. */ void Annotation::setViewportCoordinateSpaceViewport(const int viewport[4]) { if ((m_viewportCoordinateSpaceViewport[0] != viewport[0]) || (m_viewportCoordinateSpaceViewport[1] != viewport[1]) || (m_viewportCoordinateSpaceViewport[2] != viewport[2]) || (m_viewportCoordinateSpaceViewport[3] != viewport[3])) { m_viewportCoordinateSpaceViewport[0] = viewport[0]; m_viewportCoordinateSpaceViewport[1] = viewport[1]; m_viewportCoordinateSpaceViewport[2] = viewport[2]; m_viewportCoordinateSpaceViewport[3] = viewport[3]; } } /** * Get a description of this object's content. * @return String describing this object's content. */ AString Annotation::toString() const { AString msg("Annotation type=" + AnnotationTypeEnum::toName(m_type)); msg += (" space=" + AnnotationCoordinateSpaceEnum::toGuiName(getCoordinateSpace())); const AnnotationText* textAnn = dynamic_cast(this); if (textAnn != NULL) { msg += (" text=" + textAnn->getText()); } return msg; } /** * Convert the annotation's obsolete line width that was in pixels to a percentage of viewport height. * Prior to late July, 2017, a line was specified in pixels. * * First, the annotation's percentage width is examined. If it is valid (greater than zero), then * no conversion is needed. Otherwise, use the viewport height to convert the pixel width to a * percentage and set the annotation's percentage line width. * * Note that even though this method is 'const' it may cause the modification status to change * to modified. * * @param viewportHeight * The height of the viewport in pixels. */ void Annotation::convertObsoleteLineWidthPixelsToPercentageWidth(const float viewportHeight) const { if (m_lineWidthPercentage > 0.0f) { return; } float percentWidth = 1.0f; if (viewportHeight > 0.0f) { percentWidth = (m_lineWidthPixels / viewportHeight) * 100.0f; } const_cast(this)->setLineWidthPercentage(percentWidth); } /** * @return The line width in pixels. */ float Annotation::getLineWidthPixelsObsolete() const { return m_lineWidthPixels; } /** * Set the line width in pixels. * * @param lineWidth * New value for line width. */ void Annotation::setLineWidthPixelsObsolete(const float lineWidth) { if (lineWidth != m_lineWidthPixels) { m_lineWidthPixels = lineWidth; setModified(); } } /** * @return The line width percentage. */ float Annotation::getLineWidthPercentage() const { return m_lineWidthPercentage; } /** * Set the line width percentage. * * @param lineWidthPercentage * New value for line width percentage. */ void Annotation::setLineWidthPercentage(const float lineWidthPercentage) { if (lineWidthPercentage != m_lineWidthPercentage) { m_lineWidthPercentage = lineWidthPercentage; } } /** * @return The line color. */ CaretColorEnum::Enum Annotation::getLineColor() const { return m_colorLine; } /** * Set the line color. * * @param color * New value for line color. */ void Annotation::setLineColor(const CaretColorEnum::Enum color) { if (m_colorLine != color) { m_colorLine = color; setModified(); } } /** * Get the line color's RGBA components regardless of * coloring (custom color or a CaretColorEnum) selected by the user. * * @param rgbaOut * RGBA components ranging 0.0 to 1.0. */ void Annotation::getLineColorRGBA(float rgbaOut[4]) const { switch (m_colorLine) { case CaretColorEnum::NONE: rgbaOut[0] = 0.0; rgbaOut[1] = 0.0; rgbaOut[2] = 0.0; rgbaOut[3] = 0.0; break; case CaretColorEnum::CUSTOM: getCustomLineColor(rgbaOut); break; case CaretColorEnum::AQUA: case CaretColorEnum::BLACK: case CaretColorEnum::BLUE: case CaretColorEnum::FUCHSIA: case CaretColorEnum::GRAY: case CaretColorEnum::GREEN: case CaretColorEnum::LIME: case CaretColorEnum::MAROON: case CaretColorEnum::NAVY: case CaretColorEnum::OLIVE: case CaretColorEnum::PURPLE: case CaretColorEnum::RED: case CaretColorEnum::SILVER: case CaretColorEnum::TEAL: case CaretColorEnum::WHITE: case CaretColorEnum::YELLOW: CaretColorEnum::toRGBAFloat(m_colorLine, rgbaOut); rgbaOut[3] = 1.0; break; } } /** * Get the line color's RGBA components regardless of * coloring (custom color or a CaretColorEnum) selected by the user. * * @param rgbaOut * RGBA components ranging 0 to 255. */ void Annotation::getLineColorRGBA(uint8_t rgbaOut[4]) const { float rgbaFloat[4] = { 0.0, 0.0, 0.0, 0.0 }; getLineColorRGBA(rgbaFloat); rgbaOut[0] = static_cast(rgbaFloat[0] * 255.0); rgbaOut[1] = static_cast(rgbaFloat[1] * 255.0); rgbaOut[2] = static_cast(rgbaFloat[2] * 255.0); rgbaOut[3] = static_cast(rgbaFloat[3] * 255.0); } /** * @return The background color. */ CaretColorEnum::Enum Annotation::getBackgroundColor() const { return m_colorBackground; } /** * Set the background color. * * @param color * New value for background color. */ void Annotation::setBackgroundColor(const CaretColorEnum::Enum color) { if (m_colorBackground != color) { m_colorBackground = color; setModified(); } } /** * Get the background color's RGBA components regardless of * coloring (custom color or a CaretColorEnum) selected by the user. * * @param rgbaOut * RGBA components ranging 0.0 to 1.0. */ void Annotation::getBackgroundColorRGBA(float rgbaOut[4]) const { switch (m_colorBackground) { case CaretColorEnum::NONE: rgbaOut[0] = 0.0; rgbaOut[1] = 0.0; rgbaOut[2] = 0.0; rgbaOut[3] = 0.0; break; case CaretColorEnum::CUSTOM: getCustomBackgroundColor(rgbaOut); break; case CaretColorEnum::AQUA: case CaretColorEnum::BLACK: case CaretColorEnum::BLUE: case CaretColorEnum::FUCHSIA: case CaretColorEnum::GRAY: case CaretColorEnum::GREEN: case CaretColorEnum::LIME: case CaretColorEnum::MAROON: case CaretColorEnum::NAVY: case CaretColorEnum::OLIVE: case CaretColorEnum::PURPLE: case CaretColorEnum::RED: case CaretColorEnum::SILVER: case CaretColorEnum::TEAL: case CaretColorEnum::WHITE: case CaretColorEnum::YELLOW: CaretColorEnum::toRGBAFloat(m_colorBackground, rgbaOut); rgbaOut[3] = 1.0; break; } } /** * Get the background color's RGBA components regardless of * coloring (custom color or a CaretColorEnum) selected by the user. * * @param rgbaOut * RGBA components ranging 0 to 255. */ void Annotation::getBackgroundColorRGBA(uint8_t rgbaOut[4]) const { float rgbaFloat[4] = { 0.0, 0.0, 0.0, 0.0 }; getBackgroundColorRGBA(rgbaFloat); rgbaOut[0] = static_cast(rgbaFloat[0] * 255.0); rgbaOut[1] = static_cast(rgbaFloat[1] * 255.0); rgbaOut[2] = static_cast(rgbaFloat[2] * 255.0); rgbaOut[3] = static_cast(rgbaFloat[3] * 255.0); } /** * Get the custom line color. * * @param rgbaOut * RGBA components (red, green, blue, alpha) each of which ranges [0.0, 1.0]. */ void Annotation::getCustomLineColor(float rgbaOut[4]) const { rgbaOut[0] = m_customColorLine[0]; rgbaOut[1] = m_customColorLine[1]; rgbaOut[2] = m_customColorLine[2]; rgbaOut[3] = m_customColorLine[3]; } /** * Get the custom line color. * * @param rgbaOut * RGBA components (red, green, blue, alpha) each of which ranges [0, 255]. */ void Annotation::getCustomLineColor(uint8_t rgbaOut[4]) const { rgbaOut[0] = static_cast(m_customColorLine[0] * 255.0); rgbaOut[1] = static_cast(m_customColorLine[1] * 255.0); rgbaOut[2] = static_cast(m_customColorLine[2] * 255.0); rgbaOut[3] = static_cast(m_customColorLine[3] * 255.0); } /** * Set the custom line color with floats. * * @param rgba * RGBA components (red, green, blue, alpha) each of which ranges [0.0, 1.0]. */ void Annotation::setCustomLineColor(const float rgba[4]) { for (int32_t i = 0; i < 4; i++) { if (rgba[i] != m_customColorLine[i]) { m_customColorLine[i] = rgba[i]; setModified(); } } } /** * Set the custom line color with unsigned bytes. * * @param rgba * RGBA components (red, green, blue, alpha) each of which ranges [0, 255]. */ void Annotation::setCustomLineColor(const uint8_t rgba[4]) { for (int32_t i = 0; i < 4; i++) { const float component = rgba[i] / 255.0; if (component != m_customColorLine[i]) { m_customColorLine[i] = component; setModified(); } } } /** * Get the background color. * * @param rgbaOut * RGBA components (red, green, blue, alpha) each of which ranges [0.0, 1.0]. */ void Annotation::getCustomBackgroundColor(float rgbaOut[4]) const { rgbaOut[0] = m_customColorBackground[0]; rgbaOut[1] = m_customColorBackground[1]; rgbaOut[2] = m_customColorBackground[2]; rgbaOut[3] = m_customColorBackground[3]; } /** * Get the background color. * * @param rgbaOut * RGBA components (red, green, blue, alpha) each of which ranges [0, 255]. */ void Annotation::getCustomBackgroundColor(uint8_t rgbaOut[4]) const { rgbaOut[0] = static_cast(m_customColorBackground[0] * 255.0); rgbaOut[1] = static_cast(m_customColorBackground[1] * 255.0); rgbaOut[2] = static_cast(m_customColorBackground[2] * 255.0); rgbaOut[3] = static_cast(m_customColorBackground[3] * 255.0); } /** * Set the background color with floats. * The background color is applied only when its alpha component is greater than zero. * * @param rgba * RGBA components (red, green, blue, alpha) each of which ranges [0.0, 1.0]. */ void Annotation::setCustomBackgroundColor(const float rgba[4]) { for (int32_t i = 0; i < 4; i++) { if (rgba[i] != m_customColorBackground[i]) { m_customColorBackground[i] = rgba[i]; setModified(); } } } /** * Set the background color with bytes. * The background color is applied only when its alpha component is greater than zero. * * @param rgba * RGBA components (red, green, blue, alpha) each of which ranges [0, 255]. */ void Annotation::setCustomBackgroundColor(const uint8_t rgba[4]) { for (int32_t i = 0; i < 4; i++) { const float component = rgba[i] / 255.0; if (component != m_customColorBackground[i]) { m_customColorBackground[i] = component; setModified(); } } } /** * Initialize properties. */ void Annotation::initializeProperties() { /* * Initialize all properties on/supported */ CaretAssert(m_properties.size() >= static_cast::type>(Property::COUNT_FOR_BITSET)); m_properties.set(); bool colorBarFlag = false; bool fillColorFlag = true; bool lineArrowsFlag = false; bool textFlag = false; switch (m_type) { case AnnotationTypeEnum::BOX: break; case AnnotationTypeEnum::COLOR_BAR: colorBarFlag = true; break; case AnnotationTypeEnum::IMAGE: fillColorFlag = false; break; case AnnotationTypeEnum::LINE: fillColorFlag = false; lineArrowsFlag = true; break; case AnnotationTypeEnum::OVAL: break; case AnnotationTypeEnum::TEXT: textFlag = true; break; } setProperty(Property::FILL_COLOR, fillColorFlag); setProperty(Property::LINE_ARROWS, lineArrowsFlag); setProperty(Property::TEXT_ALIGNMENT, textFlag); setProperty(Property::TEXT_EDIT, textFlag); setProperty(Property::TEXT_COLOR, colorBarFlag | textFlag); setProperty(Property::TEXT_FONT_NAME, colorBarFlag | textFlag); setProperty(Property::TEXT_FONT_SIZE, colorBarFlag | textFlag); setProperty(Property::TEXT_FONT_STYLE, textFlag); setProperty(Property::TEXT_ORIENTATION, textFlag); resetProperty(Property::SCENE_CONTAINS_ATTRIBUTES); /* * These are not valid properties */ resetProperty(Property::INVALID); resetProperty(Property::COUNT_FOR_BITSET); if (colorBarFlag) { resetProperty(Property::ARRANGE); resetProperty(Property::COPY_CUT_PASTE); resetProperty(Property::DELETION); resetProperty(Property::DISPLAY_GROUP); resetProperty(Property::GROUP); resetProperty(Property::LINE_COLOR); resetProperty(Property::LINE_THICKNESS); resetProperty(Property::TEXT_EDIT); setProperty(Property::SCENE_CONTAINS_ATTRIBUTES); } } /** * Set the properties for specialized usage of annotations. This is typically used * for annotations that are not stored in an annotation file but instead are a * property of some entity (such as chart labels). * * @param specializedUsage * The specialized usage. */ void Annotation::setPropertiesForSpecializedUsage(const PropertiesSpecializedUsage specializedUsage) { initializeProperties(); bool chartLabelTitleFlag = false; bool viewportFlag = false; switch (specializedUsage) { case PropertiesSpecializedUsage::CHART_LABEL: chartLabelTitleFlag = true; break; case PropertiesSpecializedUsage::CHART_TITLE: chartLabelTitleFlag = true; break; case PropertiesSpecializedUsage::VIEWPORT_ANNOTATION: viewportFlag = true; break; } if (chartLabelTitleFlag) { resetProperty(Property::ARRANGE); resetProperty(Property::COORDINATE); resetProperty(Property::COPY_CUT_PASTE); resetProperty(Property::DELETION); resetProperty(Property::DISPLAY_GROUP); resetProperty(Property::GROUP); resetProperty(Property::LINE_COLOR); resetProperty(Property::LINE_THICKNESS); resetProperty(Property::ROTATION); resetProperty(Property::TEXT_ALIGNMENT); resetProperty(Property::TEXT_COLOR); resetProperty(Property::TEXT_ORIENTATION); setProperty(Property::SCENE_CONTAINS_ATTRIBUTES); } if (viewportFlag) { resetProperty(Property::ARRANGE); resetProperty(Property::COORDINATE); resetProperty(Property::COPY_CUT_PASTE); resetProperty(Property::DELETION); resetProperty(Property::DISPLAY_GROUP); resetProperty(Property::GROUP); resetProperty(Property::ROTATION); setProperty(Property::SCENE_CONTAINS_ATTRIBUTES); } } /** * Test a property. * * @param property * Property for testing. * @return * True if property is on, else false. */ bool Annotation::testProperty(const Property property) const { /* * Text connect to brainordiante property is valid only * for a a text annotation in surface space */ if (property == Property::TEXT_CONNECT_TO_BRAINORDINATE) { if (m_type == AnnotationTypeEnum::TEXT) { if (m_coordinateSpace == AnnotationCoordinateSpaceEnum::SURFACE) { return true; } } return false; } const int32_t propertyIndex = static_cast::type>(property); return m_properties.test(propertyIndex); } /** * Test for any of the properties are set. * * @param propertyOne * First property for testing. * @param propertyTwo * Two property for testing. * @param propertyThree * Three property for testing. * @param propertyFour * Four property for testing. * @param propertyFive * Five property for testing. * @return * True if property is on, else false. */ bool Annotation::testPropertiesAny(const Property propertyOne, const Property propertyTwo, const Property propertyThree, const Property propertyFour, const Property propertyFive) const { if (testProperty(propertyOne)) { return true; } if (testProperty(propertyTwo)) { return true; } if (propertyThree != Property::INVALID) { if (testProperty(propertyThree)) { return true; } } if (propertyFour != Property::INVALID) { if (testProperty(propertyFour)) { return true; } } if (propertyFive != Property::INVALID) { if (testProperty(propertyFive)) { return true; } } return false; } /** * Set a property. * * @param property * Property for testing. * @param value * New on/off status for property (optional argument defaults to true). */ void Annotation::setProperty(const Property property, const bool value) { const int32_t propertyIndex = static_cast::type>(property); m_properties.set(propertyIndex, value); } /** * Reset (turn off) a property. * * @param property * Property for testing. */ void Annotation::resetProperty(const Property property) { const int32_t propertyIndex = static_cast::type>(property); m_properties.reset(propertyIndex); } /** * @return The key to the annotation group that owns this annotation. */ AnnotationGroupKey Annotation::getAnnotationGroupKey() const { return m_annotationGroupKey; } /** * Set the annotation group key. * * @param annotationGroupKey * The key to the annotation group that contains this annotation. */ void Annotation::setAnnotationGroupKey(const AnnotationGroupKey& annotationGroupKey) { AnnotationGroupKey newGroupKeyForAnnotation = annotationGroupKey; switch (newGroupKeyForAnnotation.getGroupType()) { case AnnotationGroupTypeEnum::INVALID: CaretAssertMessage(0, "Do not call this method with invalid key. " "Instead call invalidateAnnotationGroupKey()."); break; case AnnotationGroupTypeEnum::SPACE: CaretAssert(newGroupKeyForAnnotation.getSpaceGroupUniqueKey() > 0); /* * When an annotation is moved to a space group (from a user group), * we want to preserve the user group unique key so that it can * be used to 'regroup' annotations */ if (m_annotationGroupKey.getGroupType() == AnnotationGroupTypeEnum::USER) { newGroupKeyForAnnotation.setUserGroupUniqueKey(m_annotationGroupKey.getUserGroupUniqueKey()); } break; case AnnotationGroupTypeEnum::USER: CaretAssert(newGroupKeyForAnnotation.getUserGroupUniqueKey() > 0); break; } m_annotationGroupKey = newGroupKeyForAnnotation; } /** * Set the annotation group key so that it is invalid. */ void Annotation::invalidateAnnotationGroupKey() { m_annotationGroupKey = AnnotationGroupKey(); } /** * Set the unique key for this annotation. This method is * called by the annotation file when the annotation * is added to the file. * * @param uniqueKey * Unique key displayed in an annotation name. */ void Annotation::setUniqueKey(const int32_t uniqueKey) { m_uniqueKey = uniqueKey; textAnnotationResetName(); } /** * @return Unique key displayed in annotation name. */ int32_t Annotation::getUniqueKey() const { return m_uniqueKey; } /** * Invalidate text substitutions. This method is * implemented as a virtual method to avoid * dyamic casts since they are slow. */ void Annotation::invalidateTextSubstitution() { /* Nothing, override by AnnotationText */ } /** * @return Name of annotation. */ AString Annotation::getName() const { return m_name; } /** * Called by text annotation to reset the name * displayed in the gui. DO NOT CALL FROM * A CONSTRUCTOR !!! */ void Annotation::textAnnotationResetName() { AString suffixName; switch (m_type) { case AnnotationTypeEnum::BOX: break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: break; case AnnotationTypeEnum::LINE: break; case AnnotationTypeEnum::OVAL: break; case AnnotationTypeEnum::TEXT: { const AnnotationText* textAnn = dynamic_cast(this); CaretAssertMessage(textAnn, "If this fails, it may be due to this method being called from a constructor " "and the subclass constructor has not yet executed."); suffixName = (": " + textAnn->getText()); } break; } m_name = (AnnotationTypeEnum::toGuiName(m_type) + " " + AString::number(m_uniqueKey) + suffixName); } /** * Set the drawn status to true for the given window. * * @param windowIndex * Index of the window. * * This method is called from the graphics * code when an annotation is drawn. * * NOTE: To find the annotations drawn in a window, * the drawn status is cleared, annotations are drawn * in one window, and the graphics system sets the * drawn status for annotations that are drawn. * A query is then made to find all annotations with * the drawn status set. */ void Annotation::setDrawnInWindowStatus(const int32_t windowIndex) { CaretAssertArrayIndex(m_drawnInWindowStatus, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, windowIndex); m_drawnInWindowStatus[windowIndex] = true; } /** * Is the drawn status set for the given window. * * @param windowIndex * Index of the window. * * NOTE: To find the annotations drawn in a window, * the drawn status is cleared, annotations are drawn * in one window, and the graphics system sets the * drawn status for annotations that are drawn. * A query is then made to find all annotations with * the drawn status set. */ bool Annotation::isDrawnInWindowStatus(const int32_t windowIndex) { CaretAssertArrayIndex(m_drawnInWindowStatus, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, windowIndex); return m_drawnInWindowStatus[windowIndex]; } /** * Clear the drawn status for all windows. * * This method is called by the Annotation File * containing this annotation to clear the drawn status. * * NOTE: To find the annotations drawn in a window, * the drawn status is cleared, annotations are drawn * in one window, and the graphics system sets the * drawn status for annotations that are drawn. * A query is then made to find all annotations with * the drawn status set. */ void Annotation::clearDrawnInWindowStatusForAllWindows() { for (int32_t iWindow = 0; iWindow < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS; iWindow++) { CaretAssertArrayIndex(m_drawnInWindowStatus, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, iWindow); m_drawnInWindowStatus[iWindow] = false; } } /** * @return The annotation's selected for editing status. * * Note: (1) The selection status is never saved to a scene * or file. (2) Changing the selection status DOES NOT * alter the annotation's modified status. * * @param windowIndex * Window for annotation selection status. */ bool Annotation::isSelectedForEditing(const int32_t windowIndex) const { CaretAssert((windowIndex >= 0) && (windowIndex < static_cast(m_selectedForEditingInWindowFlag.size()))); return m_selectedForEditingInWindowFlag.test(windowIndex); } /** * Set the annotation's selected for editing status. * * This method is private - AnnotationManager handles selection and allowing * public access to this method could cause improper selection status. * * Note: (1) The selection status is never saved to a scene * or file. (2) Changing the selection status DOES NOT * alter the annotation's modified status. * * @param windowIndex * Window for annotation selection. * @param selectedStatus * New selection status. */ void Annotation::setSelectedForEditing(const int32_t windowIndex, const bool selectedStatus) const { CaretAssert((windowIndex >= 0) && (windowIndex < static_cast(m_selectedForEditingInWindowFlag.size()))); if (selectedStatus) { m_selectedForEditingInWindowFlag.set(windowIndex); } else { m_selectedForEditingInWindowFlag.reset(windowIndex); } } /** * Set the annotation's selected for editing status to deselected. */ void Annotation::setDeselectedForEditing() { /* * Clear selected status in ALL windows */ m_selectedForEditingInWindowFlag.reset(); } /** * Convert a relative (zero to one) XYZ coordinate to * a viewport coordinate. * * @param relativeXYZ * The relative (zero to one) XYZ. * @param viewportWidth * Width of the viewport. * @param viewportHeight * Height of the viewport. * @param viewportXYZOut * Output viewport coordinate. */ void Annotation::relativeXYZToViewportXYZ(const float relativeXYZ[3], const float viewportWidth, const float viewportHeight, float viewportXYZOut[3]) { viewportXYZOut[0] = (relativeXYZ[0] / 100.0) * viewportWidth; viewportXYZOut[1] = (relativeXYZ[1] / 100.0) * viewportHeight; viewportXYZOut[2] = relativeXYZ[2]; } /** * Convert a viewport XYZ coordinate to * a relative coordinate. The output relative * coordinates are may be outside of the range * zero to one if viewport coordinate is outside * of the viewport bounds. * * @param viewportXYZ * The relative (zero to one) XYZ. * @param viewportWidth * Width of the viewport. * @param viewportHeight * Height of the viewport. * @param relativeXYZOut * Output relative coordinate. */ void Annotation::viewportXYZToRelativeXYZ(const float viewportXYZ[3], const float viewportWidth, const float viewportHeight, float relativeXYZOut[3]) { relativeXYZOut[0] = 100.0 * (viewportXYZ[0] / viewportWidth); relativeXYZOut[1] = 100.0 * (viewportXYZ[1] / viewportHeight); relativeXYZOut[2] = viewportXYZ[2]; } /** * Convert a viewport XYZ coordinate to * a relative coordinate. The output relative coordinate * will be limited to the range zero to one even if the * viewport coordinate is outside of the viewport bounds. * * @param viewportXYZ * The relative (zero to one) XYZ. * @param viewportWidth * Width of the viewport. * @param viewportHeight * Height of the viewport. * @param relativeXYZOut * Output relative coordinate. */ void Annotation::viewportXYZToLimitedRelativeXYZ(const float viewportXYZ[3], const float viewportWidth, const float viewportHeight, float relativeXYZOut[3]) { viewportXYZToRelativeXYZ(viewportXYZ, viewportWidth, viewportHeight, relativeXYZOut); relativeXYZOut[0] = MathFunctions::limitRange(relativeXYZOut[0], 0.0f, 1.0f); relativeXYZOut[1] = MathFunctions::limitRange(relativeXYZOut[1], 0.0f, 1.0f); relativeXYZOut[2] = MathFunctions::limitRange(relativeXYZOut[2], 0.0f, 1.0f); } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* Annotation::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "Annotation", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); saveSubClassDataToScene(sceneAttributes, sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void Annotation::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); restoreSubClassDataFromScene(sceneAttributes, sceneClass); } /** * @return Number of children. */ int32_t Annotation::getNumberOfItemChildren() const { /* * Annotation has no children. */ return 0; } /** * Get child at the given index. * * @param index * Index of the child. * @return * Child at the given index. */ DisplayGroupAndTabItemInterface* Annotation::getItemChild(const int32_t /* index */) const { /* * Annotation has no children. */ return NULL; } /** * @return Children of this item. */ std::vector Annotation::getItemChildren() const { /* * Annotation has no children. */ std::vector children; return children; } /** * @return Parent of this item. */ DisplayGroupAndTabItemInterface* Annotation::getItemParent() const { return m_displayGroupAndTabItemHelper->getParent(); } /** * Set the parent of this item. * * @param itemParent * Parent of this item. */ void Annotation::setItemParent(DisplayGroupAndTabItemInterface* itemParent) { m_displayGroupAndTabItemHelper->setParent(itemParent); } /** * @return Name of this item. */ AString Annotation::getItemName() const { return getName(); } /** * Get the icon color for this item. Icon is filled with background * color, outline color is drawn around edges, and text color is small * square in center. For any colors that do not apply, use an alpha * value (last element) of zero. * * @param backgroundRgbaOut * Red, green, blue, alpha components for background ranging [0, 1]. * @param outlineRgbaOut * Red, green, blue, alpha components for outline ranging [0, 1]. * @param textRgbaOut * Red, green, blue, alpha components for text ranging [0, 1]. */ void Annotation::getItemIconColorsRGBA(float backgroundRgbaOut[4], float outlineRgbaOut[4], float textRgbaOut[4]) const { for (int32_t i = 0; i < 4; i++) { backgroundRgbaOut[i] = 0.0; outlineRgbaOut[i] = 0.0; textRgbaOut[i] = 0.0; } getBackgroundColorRGBA(backgroundRgbaOut); getLineColorRGBA(outlineRgbaOut); /* * Note: AnnotationText overrides this method to set text color */ textRgbaOut[0] = 0.0; textRgbaOut[1] = 0.0; textRgbaOut[2] = 0.0; textRgbaOut[3] = 0.0; } /** * @return This item can be expanded. */ bool Annotation::isItemExpandable() const { return false; } /** * @return Is this item expanded in the given display group/tab? * * Note: If this annotation is in window space, the display group * and tab are ignored and window status is used with the window index * of the annotation. * * @param displayGroup * The display group. * @param tabIndex * Index of the tab. */ bool Annotation::isItemExpanded(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { switch (m_coordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: return m_displayGroupAndTabItemHelper->isExpandedInWindow(m_windowIndex); break; } const int32_t itemTabIndex = updateDisplayGroupTabIndex(displayGroup, tabIndex); return m_displayGroupAndTabItemHelper->isExpanded(displayGroup, itemTabIndex); } /** * Set this item's expanded status in the given display group/tab. * * Note: If this annotation is in window space, the display group * and tab are ignored and window status is used with the window index * of the annotation. * * @param displayGroup * The display group. * @param tabIndex * Index of the tab. * @param status * New expanded status. */ void Annotation::setItemExpanded(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool status) { switch (m_coordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: m_displayGroupAndTabItemHelper->setExpandedInWindow(m_windowIndex, status); return; break; } const int32_t itemTabIndex = updateDisplayGroupTabIndex(displayGroup, tabIndex); m_displayGroupAndTabItemHelper->setExpanded(displayGroup, itemTabIndex, status); } /** * Get display selection status in the given display group/tab? * * Note: If this annotation is in window space, the display group * and tab are ignored and window status is used with the window index * of the annotation. * * @param displayGroup * The display group. * @param tabIndex * Index of the tab. */ TriStateSelectionStatusEnum::Enum Annotation::getItemDisplaySelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { if (testProperty(Annotation::Property::DISPLAY_GROUP)) { switch (m_coordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: return m_displayGroupAndTabItemHelper->getSelectedInSpacerTab(); break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: return m_displayGroupAndTabItemHelper->getSelectedInWindow(m_windowIndex); break; } const int32_t itemTabIndex = updateDisplayGroupTabIndex(displayGroup, tabIndex); return m_displayGroupAndTabItemHelper->getSelected(displayGroup, itemTabIndex); } /* * Annotations that do not support a "display group" are always displayed */ return TriStateSelectionStatusEnum::SELECTED; } /** * Set display this item selected in the given display group/tab. * * Note: If this annotation is in window space, the display group * and tab are ignored and window status is used with the window index * of the annotation. * * @param displayGroup * The display group. * @param tabIndex * Index of the tab. * @param status * New selection status. */ void Annotation::setItemDisplaySelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const TriStateSelectionStatusEnum::Enum status) { switch (m_coordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: m_displayGroupAndTabItemHelper->setSelectedInSpacerTab(status); return; break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: m_displayGroupAndTabItemHelper->setSelectedInWindow(m_windowIndex, status); return; break; } const int32_t itemTabIndex = updateDisplayGroupTabIndex(displayGroup, tabIndex); m_displayGroupAndTabItemHelper->setSelected(displayGroup, itemTabIndex, status); } /** * Update the tab index to correspond to the tab index used for this * annotation if it is in tab annotation space. This functionality * was added to resolve WB-831. * * @param displayGroup * The display group. * @param tabIndex * Index of the tab. */ int32_t Annotation::updateDisplayGroupTabIndex(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { int32_t tabIndexOut(tabIndex); if (getCoordinateSpace() == AnnotationCoordinateSpaceEnum::TAB) { if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { tabIndexOut = getTabIndex(); } } return tabIndexOut; } /** * Is this item selected for editing in the given window? * * @param windowIndex * Index of the window. * @return * Selection status. */ bool Annotation::isItemSelectedForEditingInWindow(const int32_t windowIndex) { return isSelectedForEditing(windowIndex); } /** * Set the default value for line color * * @param color * Default for newly created annotations. */ void Annotation::setUserDefaultLineColor(const CaretColorEnum::Enum color) { s_userDefaultColorLine = color; } /** * Set the default value for custom line color * * @param rgba * Default for newly created annotations. */ void Annotation::setUserDefaultCustomLineColor(const float rgba[4]) { s_userDefaultCustomColorLine[0] = rgba[0]; s_userDefaultCustomColorLine[1] = rgba[1]; s_userDefaultCustomColorLine[2] = rgba[2]; s_userDefaultCustomColorLine[3] = rgba[3]; } /** * Set the default value for line color FOR USE BY TEXT ONLY * * @param color * Default for newly created annotations. */ void Annotation::setUserDefaultForTextLineColor(const CaretColorEnum::Enum color) { s_userDefaultForTextColorLine = color; } /** * Set the default value for custom line color FOR USE BY TEXT ONLY * * @param rgba * Default for newly created annotations. */ void Annotation::setUserDefaultForTextCustomLineColor(const float rgba[4]) { s_userDefaultForTextCustomColorLine[0] = rgba[0]; s_userDefaultForTextCustomColorLine[1] = rgba[1]; s_userDefaultForTextCustomColorLine[2] = rgba[2]; s_userDefaultForTextCustomColorLine[3] = rgba[3]; } /** * Set the default value for background color * * @param color * Default for newly created annotations. */ void Annotation::setUserDefaultBackgroundColor(const CaretColorEnum::Enum color) { s_userDefaultColorBackground = color; } /** * Set the default value for custom background color * * @param rgba * Default for newly created annotations. */ void Annotation::setUserDefaultCustomBackgroundColor(const float rgba[4]) { s_userDefaultCustomColorBackground[0] = rgba[0]; s_userDefaultCustomColorBackground[1] = rgba[1]; s_userDefaultCustomColorBackground[2] = rgba[2]; s_userDefaultCustomColorBackground[3] = rgba[3]; } /** * Set the default value for line width percentage * * @param lineWidthPercentage * Default for newly created annotations. */ void Annotation::setUserDefaultLineWidthPercentage(const float lineWidthPercentage) { s_userDefaultLineWidthPercentage = lineWidthPercentage; } connectome-workbench-1.4.2/src/Annotations/Annotation.h000066400000000000000000000442631360521144700232130ustar00rootroot00000000000000#ifndef __ANNOTATION_H__ #define __ANNOTATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AnnotationAttributesDefaultTypeEnum.h" #include "AnnotationCoordinateSpaceEnum.h" #include "AnnotationGroupKey.h" #include "AnnotationSizingHandleTypeEnum.h" #include "AnnotationSurfaceOffsetVectorTypeEnum.h" #include "AnnotationTypeEnum.h" #include "CaretColorEnum.h" #include "CaretObjectTracksModification.h" #include "DisplayGroupAndTabItemInterface.h" #include "SceneableInterface.h" #include "SpacerTabIndex.h" #include "StructureEnum.h" namespace caret { class AnnotationOneDimensionalShape; class AnnotationTwoDimensionalShape; class AnnotationSpatialModification; class DisplayGroupAndTabItemHelper; class SceneClassAssistant; class Annotation : public CaretObjectTracksModification, public DisplayGroupAndTabItemInterface, public SceneableInterface { public: /** * Properties supported by an annotation */ enum class Property : int32_t { /** Invalid (for internal use only) */ INVALID, /** Annotation can be arranged by user */ ARRANGE, /** Annotation can be moved by user */ COORDINATE, /** Annotation allows cut, copy, and paste by user*/ COPY_CUT_PASTE, /** Annotation may be deleted by user (note 'DELETE' will not compile on windows) */ DELETION, /** Annotation display controlled by Display Group and Tab */ DISPLAY_GROUP, /** Annotation has fill (background) color */ FILL_COLOR, /** Annotation can be grouped by user */ GROUP, /** Annotation has arrows at its line endpoints */ LINE_ARROWS, /** Annotation has a line color */ LINE_COLOR, /** Annotation has line thickness */ LINE_THICKNESS, /** Annotation can be rotated by user */ ROTATION, /** * Annotation's attributes are saved to and restored from scene. * Typically used for special annotation that are saved to a scene * and NOT saved in a file. */ SCENE_CONTAINS_ATTRIBUTES, /** Annotation is selectable */ SELECT, /** Annotation has alignment of text */ TEXT_ALIGNMENT, /** Annotation allows connection to brainordinate */ TEXT_CONNECT_TO_BRAINORDINATE, /** Annotation allows editing of its text by user */ TEXT_EDIT, /** Annotation has text color */ TEXT_COLOR, /** Annotation has font name */ TEXT_FONT_NAME, /** Annotation has font size*/ TEXT_FONT_SIZE, /** Annotation has font style */ TEXT_FONT_STYLE, /** Annotation has orientation of text */ TEXT_ORIENTATION, /** Count of properties MUST BE LAST */ COUNT_FOR_BITSET }; /** Identifies properities for specialized uses of annotations */ enum class PropertiesSpecializedUsage { CHART_LABEL, CHART_TITLE, VIEWPORT_ANNOTATION }; Annotation(const AnnotationTypeEnum::Enum type, const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType); virtual ~Annotation(); Annotation(const Annotation& obj); Annotation& operator=(const Annotation& obj); static Annotation* newAnnotationOfType(const AnnotationTypeEnum::Enum annotationType, const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType); Annotation* clone() const; virtual AnnotationOneDimensionalShape* castToOneDimensionalShape() = 0; virtual const AnnotationOneDimensionalShape* castToOneDimensionalShape() const = 0; virtual AnnotationTwoDimensionalShape* castToTwoDimensionalShape() = 0; virtual const AnnotationTwoDimensionalShape* castToTwoDimensionalShape() const = 0; bool testProperty(const Property property) const; bool testPropertiesAny(const Property propertyOne, const Property propertyTwo, const Property propertyThree = Property::INVALID, const Property propertyFour = Property::INVALID, const Property propertyFive = Property::INVALID) const; void setProperty(const Property property, const bool value = true); void resetProperty(const Property property); void setPropertiesForSpecializedUsage(const PropertiesSpecializedUsage specializedUsage); virtual void setModified(); AnnotationGroupKey getAnnotationGroupKey() const; int32_t getUniqueKey() const; AString getName() const; void replaceWithCopyOfAnnotation(const Annotation* annotation); QString getShortDescriptiveString() const; void getTextForPasteMenuItems(AString& pasteMenuItemText, AString& pasteSpecialMenuItemText) const; AnnotationTypeEnum::Enum getType() const ; AnnotationCoordinateSpaceEnum::Enum getCoordinateSpace() const; void setCoordinateSpace(const AnnotationCoordinateSpaceEnum::Enum coordinateSpace); virtual AnnotationSurfaceOffsetVectorTypeEnum::Enum getSurfaceOffsetVectorType() const = 0; bool isInSurfaceSpaceWithTangentOffset() const; void changeSurfaceSpaceToTangentOffset(); float getSurfaceSpaceWithTangentOffsetRotation(const StructureEnum::Enum structure, const float vertexNormal[3]) const; void initializeSurfaceSpaceWithTangentOffsetRotation(const StructureEnum::Enum structure, const float vertexNormal[3]); int32_t getTabIndex() const; void setTabIndex(const int32_t tabIndex); SpacerTabIndex getSpacerTabIndex() const; void setSpacerTabIndex(const SpacerTabIndex& spacerTabIndex); int32_t getWindowIndex() const; void setWindowIndex(const int32_t windowIndex); void getViewportCoordinateSpaceViewport(int viewportOut[4]) const; void setViewportCoordinateSpaceViewport(const int viewport[4]); CaretColorEnum::Enum getLineColor() const; void setLineColor(const CaretColorEnum::Enum color); void getLineColorRGBA(float rgbaOut[4]) const; void getLineColorRGBA(uint8_t rgbaOut[4]) const; CaretColorEnum::Enum getBackgroundColor() const; void setBackgroundColor(const CaretColorEnum::Enum color); void getBackgroundColorRGBA(float rgbaOut[4]) const; void getBackgroundColorRGBA(uint8_t rgbaOut[4]) const; void getCustomLineColor(float rgbaOut[4]) const; void getCustomLineColor(uint8_t rgbaOut[4]) const; void setCustomLineColor(const float rgba[4]); void setCustomLineColor(const uint8_t rgba[4]); void getCustomBackgroundColor(float rgbaOut[4]) const; void getCustomBackgroundColor(uint8_t rgbaOut[4]) const; void setCustomBackgroundColor(const float rgba[4]); void setCustomBackgroundColor(const uint8_t rgba[4]); void convertObsoleteLineWidthPixelsToPercentageWidth(const float viewportHeight) const; float getLineWidthPercentage() const; void setLineWidthPercentage(const float lineWidthPercentage); bool isSelectedForEditing(const int32_t windowIndex) const; static void setUserDefaultLineColor(const CaretColorEnum::Enum color); static void setUserDefaultCustomLineColor(const float rgba[4]); static void setUserDefaultForTextLineColor(const CaretColorEnum::Enum color); static void setUserDefaultForTextCustomLineColor(const float rgba[4]); static void setUserDefaultBackgroundColor(const CaretColorEnum::Enum color); static void setUserDefaultCustomBackgroundColor(const float rgba[4]); static void setUserDefaultLineWidthPercentage(const float lineWidthPercentage); virtual bool isFixedAspectRatio() const; virtual float getFixedAspectRatio() const; /** * Apply a spatial modification to an annotation. * * @param spatialModification * Contains information about the spatial modification. * @return * True if the annotation was modified, else false. */ virtual bool applySpatialModification(const AnnotationSpatialModification& spatialModification) = 0; /** * Is the given sizing handle valid for this annotation? * * @sizingHandle * The sizing handle. * @return * True if sizing handle valid, else false. */ virtual bool isSizeHandleValid(const AnnotationSizingHandleTypeEnum::Enum sizingHandle) const = 0; virtual void applyColoringFromOther(const Annotation* otherAnnotation); virtual void applyCoordinatesSizeAndRotationFromOther(const Annotation* otherAnnotation) = 0; static void relativeXYZToViewportXYZ(const float relativeXYZ[3], const float viewportWidth, const float viewportHeight, float viewportXYZOut[3]); static void viewportXYZToRelativeXYZ(const float viewportXYZ[3], const float viewportWidth, const float viewportHeight, float relativeXYZOut[3]); static void viewportXYZToLimitedRelativeXYZ(const float viewportXYZ[3], const float viewportWidth, const float viewportHeight, float relativeXYZOut[3]); // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); virtual int32_t getNumberOfItemChildren() const; virtual DisplayGroupAndTabItemInterface* getItemChild(const int32_t index) const; virtual std::vector getItemChildren() const; virtual DisplayGroupAndTabItemInterface* getItemParent() const; virtual void setItemParent(DisplayGroupAndTabItemInterface* itemParent); virtual AString getItemName() const; virtual void getItemIconColorsRGBA(float backgroundRgbaOut[4], float outlineRgbaOut[4], float textRgbaOut[4]) const; virtual bool isItemExpandable() const; virtual bool isItemExpanded(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; virtual void setItemExpanded(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool status); virtual TriStateSelectionStatusEnum::Enum getItemDisplaySelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; virtual void setItemDisplaySelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const TriStateSelectionStatusEnum::Enum status); virtual bool isItemSelectedForEditingInWindow(const int32_t windowIndex); void setDrawnInWindowStatus(const int32_t windowIndex); protected: virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) = 0; virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) = 0; private: void copyHelperAnnotation(const Annotation& obj); void initializeAnnotationMembers(); void initializeProperties(); // private - AnnotationManager handles selection and allowing // public access to this method could cause improper selection status void setSelectedForEditing(const int32_t windowIndex, const bool selectedStatus) const; const AnnotationTypeEnum::Enum m_type; protected: void setDeselectedForEditing(); const AnnotationAttributesDefaultTypeEnum::Enum m_attributeDefaultType; void textAnnotationResetName(); bool isDrawnInWindowStatus(const int32_t windowIndex); void clearDrawnInWindowStatusForAllWindows(); virtual void invalidateTextSubstitution(); private: float getLineWidthPixelsObsolete() const; void setLineWidthPixelsObsolete(const float lineWidthPixels); void setAnnotationGroupKey(const AnnotationGroupKey& annotationGroupKey); void invalidateAnnotationGroupKey(); void setUniqueKey(const int32_t uniqueKey); int32_t updateDisplayGroupTabIndex(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; SceneClassAssistant* m_sceneAssistant; DisplayGroupAndTabItemHelper* m_displayGroupAndTabItemHelper; AnnotationCoordinateSpaceEnum::Enum m_coordinateSpace; SpacerTabIndex m_spacerTabIndex; int32_t m_tabIndex; int32_t m_windowIndex; int32_t m_viewportCoordinateSpaceViewport[4]; CaretColorEnum::Enum m_colorLine; CaretColorEnum::Enum m_colorBackground; float m_customColorLine[4]; float m_customColorBackground[4]; float m_lineWidthPixels; float m_lineWidthPercentage = -1.0f; AString m_name; int32_t m_uniqueKey; AnnotationGroupKey m_annotationGroupKey; bool m_drawnInWindowStatus[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS]; /** * Selection (NOT DISPLAY) status in each window. * * Number of elements must be same as Constants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS * An assertion will fail in cxx file the if number of elements differs. */ mutable std::bitset<10> m_selectedForEditingInWindowFlag; /** * Contains annotation properties. In the cxx file, an assertion will fail * if the number of elements is insufficient. */ std::bitset<32> m_properties; static CaretColorEnum::Enum s_userDefaultColorLine; static float s_userDefaultCustomColorLine[4]; static CaretColorEnum::Enum s_userDefaultForTextColorLine; static float s_userDefaultForTextCustomColorLine[4]; static CaretColorEnum::Enum s_userDefaultColorBackground; static float s_userDefaultCustomColorBackground[4]; static float s_userDefaultLineWidthPixelsObsolete; static float s_userDefaultLineWidthPercentage; // ADD_NEW_MEMBERS_HERE friend class AnnotationFile; friend class AnnotationFileXmlReader; friend class AnnotationFileXmlWriter; friend class AnnotationGroup; friend class AnnotationManager; }; #ifdef __ANNOTATION_DECLARE__ CaretColorEnum::Enum Annotation::s_userDefaultColorLine = CaretColorEnum::NONE; float Annotation::s_userDefaultCustomColorLine[4] = { 1.0, 1.0, 1.0, 1.0 }; CaretColorEnum::Enum Annotation::s_userDefaultForTextColorLine = CaretColorEnum::NONE; float Annotation::s_userDefaultForTextCustomColorLine[4] = { 1.0, 1.0, 1.0, 1.0 }; CaretColorEnum::Enum Annotation::s_userDefaultColorBackground = CaretColorEnum::NONE; float Annotation::s_userDefaultCustomColorBackground[4] = { 0.0, 0.0, 0.0, 1.0 }; float Annotation::s_userDefaultLineWidthPixelsObsolete = 3.0f; float Annotation::s_userDefaultLineWidthPercentage = 1.0f; #endif // __ANNOTATION_DECLARE__ } // namespace #endif //__ANNOTATION_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationAlignmentEnum.cxx000066400000000000000000000264021360521144700262450ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_ALIGNMENT_ENUM_DECLARE__ #include "AnnotationAlignmentEnum.h" #undef __ANNOTATION_ALIGNMENT_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationAlignmentEnum * \brief Enumerated type for aligning multiple annotations. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_annotationAlignmentEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void annotationAlignmentEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "AnnotationAlignmentEnum.h" * * Instatiate: * m_annotationAlignmentEnumComboBox = new EnumComboBoxTemplate(this); * m_annotationAlignmentEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_annotationAlignmentEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(annotationAlignmentEnumComboBoxItemActivated())); * * Update the selection: * m_annotationAlignmentEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const AnnotationAlignmentEnum::Enum VARIABLE = m_annotationAlignmentEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ AnnotationAlignmentEnum::AnnotationAlignmentEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ AnnotationAlignmentEnum::~AnnotationAlignmentEnum() { } /** * Initialize the enumerated metadata. */ void AnnotationAlignmentEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(AnnotationAlignmentEnum(ALIGN_LEFT, "ALIGN_LEFT", "Align Left")); enumData.push_back(AnnotationAlignmentEnum(ALIGN_CENTER, "ALIGN_CENTER", "Align Center")); enumData.push_back(AnnotationAlignmentEnum(ALIGN_RIGHT, "ALIGN_RIGHT", "Align Right")); enumData.push_back(AnnotationAlignmentEnum(ALIGN_TOP, "ALIGN_TOP", "Align Top")); enumData.push_back(AnnotationAlignmentEnum(ALIGN_MIDDLE, "ALIGN_MIDDLE", "Align Middle")); enumData.push_back(AnnotationAlignmentEnum(ALIGN_BOTTOM, "ALIGN_BOTTOM", "Align Bottom")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const AnnotationAlignmentEnum* AnnotationAlignmentEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const AnnotationAlignmentEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationAlignmentEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationAlignmentEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationAlignmentEnum::Enum AnnotationAlignmentEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationAlignmentEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationAlignmentEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type AnnotationAlignmentEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationAlignmentEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationAlignmentEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationAlignmentEnum::Enum AnnotationAlignmentEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationAlignmentEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationAlignmentEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type AnnotationAlignmentEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t AnnotationAlignmentEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationAlignmentEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ AnnotationAlignmentEnum::Enum AnnotationAlignmentEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationAlignmentEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationAlignmentEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type AnnotationAlignmentEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void AnnotationAlignmentEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationAlignmentEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(AnnotationAlignmentEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationAlignmentEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(AnnotationAlignmentEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Annotations/AnnotationAlignmentEnum.h000066400000000000000000000064111360521144700256700ustar00rootroot00000000000000#ifndef __ANNOTATION_ALIGNMENT_ENUM_H__ #define __ANNOTATION_ALIGNMENT_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class AnnotationAlignmentEnum { public: /** * Enumerated values. */ enum Enum { /** Left */ ALIGN_LEFT, /** Center */ ALIGN_CENTER, /** Right */ ALIGN_RIGHT, /** Top */ ALIGN_TOP, /** Middle */ ALIGN_MIDDLE, /** Bottom */ ALIGN_BOTTOM }; ~AnnotationAlignmentEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: AnnotationAlignmentEnum(const Enum enumValue, const AString& name, const AString& guiName); static const AnnotationAlignmentEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __ANNOTATION_ALIGNMENT_ENUM_DECLARE__ std::vector AnnotationAlignmentEnum::enumData; bool AnnotationAlignmentEnum::initializedFlag = false; int32_t AnnotationAlignmentEnum::integerCodeCounter = 0; #endif // __ANNOTATION_ALIGNMENT_ENUM_DECLARE__ } // namespace #endif //__ANNOTATION_ALIGNMENT_ENUM_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationAttributesDefaultTypeEnum.cxx000066400000000000000000000264731360521144700306340ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_ATTRIBUTES_DEFAULT_TYPE_ENUM_DECLARE__ #include "AnnotationAttributesDefaultTypeEnum.h" #undef __ANNOTATION_ATTRIBUTES_DEFAULT_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationAttributesDefaultTypeEnum * \brief * * * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_annotationAttributesDefaultTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void annotationAttributesDefaultTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "AnnotationAttributesDefaultTypeEnum.h" * * Instatiate: * m_annotationAttributesDefaultTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_annotationAttributesDefaultTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_annotationAttributesDefaultTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(annotationAttributesDefaultTypeEnumComboBoxItemActivated())); * * Update the selection: * m_annotationAttributesDefaultTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const AnnotationAttributesDefaultTypeEnum::Enum VARIABLE = m_annotationAttributesDefaultTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ AnnotationAttributesDefaultTypeEnum::AnnotationAttributesDefaultTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ AnnotationAttributesDefaultTypeEnum::~AnnotationAttributesDefaultTypeEnum() { } /** * Initialize the enumerated metadata. */ void AnnotationAttributesDefaultTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(AnnotationAttributesDefaultTypeEnum(NORMAL, "NORMAL", "")); enumData.push_back(AnnotationAttributesDefaultTypeEnum(USER, "USER", "")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const AnnotationAttributesDefaultTypeEnum* AnnotationAttributesDefaultTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const AnnotationAttributesDefaultTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationAttributesDefaultTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationAttributesDefaultTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationAttributesDefaultTypeEnum::Enum AnnotationAttributesDefaultTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationAttributesDefaultTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationAttributesDefaultTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type AnnotationAttributesDefaultTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationAttributesDefaultTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationAttributesDefaultTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationAttributesDefaultTypeEnum::Enum AnnotationAttributesDefaultTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationAttributesDefaultTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationAttributesDefaultTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type AnnotationAttributesDefaultTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t AnnotationAttributesDefaultTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationAttributesDefaultTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ AnnotationAttributesDefaultTypeEnum::Enum AnnotationAttributesDefaultTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationAttributesDefaultTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationAttributesDefaultTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type AnnotationAttributesDefaultTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void AnnotationAttributesDefaultTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationAttributesDefaultTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(AnnotationAttributesDefaultTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationAttributesDefaultTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(AnnotationAttributesDefaultTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Annotations/AnnotationAttributesDefaultTypeEnum.h000066400000000000000000000063731360521144700302560ustar00rootroot00000000000000#ifndef __ANNOTATION_ATTRIBUTES_DEFAULT_TYPE_ENUM_H__ #define __ANNOTATION_ATTRIBUTES_DEFAULT_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class AnnotationAttributesDefaultTypeEnum { public: /** * Enumerated values. */ enum Enum { /** */ NORMAL, /** */ USER }; ~AnnotationAttributesDefaultTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: AnnotationAttributesDefaultTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const AnnotationAttributesDefaultTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __ANNOTATION_ATTRIBUTES_DEFAULT_TYPE_ENUM_DECLARE__ std::vector AnnotationAttributesDefaultTypeEnum::enumData; bool AnnotationAttributesDefaultTypeEnum::initializedFlag = false; int32_t AnnotationAttributesDefaultTypeEnum::integerCodeCounter = 0; #endif // __ANNOTATION_ATTRIBUTES_DEFAULT_TYPE_ENUM_DECLARE__ } // namespace #endif //__ANNOTATION_ATTRIBUTES_DEFAULT_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationBox.cxx000066400000000000000000000100771360521144700242330ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_BOX_DECLARE__ #include "AnnotationBox.h" #undef __ANNOTATION_BOX_DECLARE__ #include "CaretAssert.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::AnnotationBox * \brief An annotation box. * \ingroup Annotations */ /** * Constructor. * * @param attributeDefaultType * Type for attribute defaults */ AnnotationBox::AnnotationBox(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType) : AnnotationTwoDimensionalShape(AnnotationTypeEnum::BOX, attributeDefaultType) { initializeMembersAnnotationBox(); } /** * Destructor. */ AnnotationBox::~AnnotationBox() { } /** * Copy constructor. * @param obj * Object that is copied. */ AnnotationBox::AnnotationBox(const AnnotationBox& obj) : AnnotationTwoDimensionalShape(obj) { this->initializeMembersAnnotationBox(); this->copyHelperAnnotationBox(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ AnnotationBox& AnnotationBox::operator=(const AnnotationBox& obj) { if (this != &obj) { AnnotationTwoDimensionalShape::operator=(obj); this->copyHelperAnnotationBox(obj); } return *this; } /** * Initialize a new instance of this class. */ void AnnotationBox::initializeMembersAnnotationBox() { m_sceneAssistant.grabNew(new SceneClassAssistant()); if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { } } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void AnnotationBox::copyHelperAnnotationBox(const AnnotationBox& /*obj*/) { /* nothing to copy here */ } /** * Save subclass data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void AnnotationBox::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { AnnotationTwoDimensionalShape::saveSubClassDataToScene(sceneAttributes, sceneClass); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void AnnotationBox::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { AnnotationTwoDimensionalShape::restoreSubClassDataFromScene(sceneAttributes, sceneClass); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } connectome-workbench-1.4.2/src/Annotations/AnnotationBox.h000066400000000000000000000042231360521144700236540ustar00rootroot00000000000000#ifndef __ANNOTATION_BOX_H__ #define __ANNOTATION_BOX_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationTwoDimensionalShape.h" #include "CaretPointer.h" namespace caret { class AnnotationBox : public AnnotationTwoDimensionalShape { public: AnnotationBox(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType); virtual ~AnnotationBox(); AnnotationBox(const AnnotationBox& obj); AnnotationBox& operator=(const AnnotationBox& obj); // ADD_NEW_METHODS_HERE protected: virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: void copyHelperAnnotationBox(const AnnotationBox& obj); void initializeMembersAnnotationBox(); CaretPointer m_sceneAssistant; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_BOX_DECLARE__ // #endif // __ANNOTATION_BOX_DECLARE__ } // namespace #endif //__ANNOTATION_BOX_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationColorBar.cxx000066400000000000000000000475711360521144700252170ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_COLOR_BAR_DECLARE__ #include "AnnotationColorBar.h" #undef __ANNOTATION_COLOR_BAR_DECLARE__ #include "AnnotationColorBarNumericText.h" #include "AnnotationColorBarSection.h" #include "CaretAssert.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::AnnotationColorBar * \brief Annotation used for drawing a color bar. * \ingroup Annotations */ /** * Constructor. * * @param attributeDefaultType * Type for attribute defaults */ AnnotationColorBar::AnnotationColorBar(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType) : AnnotationTwoDimensionalShape(AnnotationTypeEnum::COLOR_BAR, attributeDefaultType), AnnotationFontAttributesInterface() { reset(); m_sceneAssistant.grabNew(new SceneClassAssistant()); if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { m_sceneAssistant->add("m_fontName", &m_fontName); m_sceneAssistant->add("m_fontPercentViewportHeight", &m_fontPercentViewportHeight); m_sceneAssistant->add("m_positionMode", &m_positionMode); m_sceneAssistant->add("m_displayedFlag", &m_displayedFlag); m_sceneAssistant->add("m_showTickMarksSelected", &m_showTickMarksSelected); m_sceneAssistant->add("m_colorText", &m_colorText); m_sceneAssistant->addArray("m_customColorText", m_customColorText, 4, 1.0); } } /** * Destructor. */ AnnotationColorBar::~AnnotationColorBar() { clearSections(); clearNumericText(); } /** * Copy constructor. * @param obj * Object that is copied. */ AnnotationColorBar::AnnotationColorBar(const AnnotationColorBar& obj) : AnnotationTwoDimensionalShape(obj), AnnotationFontAttributesInterface() { this->copyHelperAnnotationColorBar(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ AnnotationColorBar& AnnotationColorBar::operator=(const AnnotationColorBar& obj) { if (this != &obj) { AnnotationTwoDimensionalShape::operator=(obj); this->copyHelperAnnotationColorBar(obj); } return *this; } /** * Helps with copying an object of this type. * * @param obj * Object that is copied. */ void AnnotationColorBar::copyHelperAnnotationColorBar(const AnnotationColorBar& obj) { /* * NOTE: sections and numeric text are not copied */ clearSections(); clearNumericText(); m_positionMode = obj.m_positionMode; m_fontName = obj.m_fontName; m_fontPercentViewportHeight = obj.m_fontPercentViewportHeight; m_positionMode = obj.m_positionMode; m_displayedFlag = obj.m_displayedFlag; m_showTickMarksSelected = obj.m_showTickMarksSelected; m_colorText = obj.m_colorText; m_customColorText[0] = obj.m_customColorText[0]; m_customColorText[1] = obj.m_customColorText[1]; m_customColorText[2] = obj.m_customColorText[2]; m_customColorText[3] = obj.m_customColorText[3]; m_fontTooSmallWhenLastDrawnFlag = obj.m_fontTooSmallWhenLastDrawnFlag; } /** * Reset the annotation colorbar. * * DO NOT make this method virtual is it is called from constructor. */ void AnnotationColorBar::reset() { resetSizeAttributes(); m_fontName = AnnotationTextFontNameEnum::getDefaultFontName(); m_positionMode = AnnotationColorBarPositionModeEnum::AUTOMATIC; m_displayedFlag = false; m_showTickMarksSelected = false; m_colorText = CaretColorEnum::WHITE; m_customColorText[0] = 1.0; m_customColorText[1] = 1.0; m_customColorText[2] = 1.0; m_customColorText[3] = 1.0; setLineColor(CaretColorEnum::WHITE); setBackgroundColor(CaretColorEnum::BLACK); clearSections(); clearNumericText(); m_fontTooSmallWhenLastDrawnFlag = false; } /** * Reset the size attributes of the color bar. */ void AnnotationColorBar::resetSizeAttributes() { setWidth(25.0); setHeight(7.0); setRotationAngle(0.0); m_fontPercentViewportHeight = 3.33; } /** * @return The font. */ AnnotationTextFontNameEnum::Enum AnnotationColorBar::getFont() const { return m_fontName; } /** * Set the font. * * @param font * New value for font. */ void AnnotationColorBar::setFont(const AnnotationTextFontNameEnum::Enum font) { if (font != m_fontName) { m_fontName = font; setModified(); } } /** * @return THe percent viewport height for the font. */ float AnnotationColorBar::getFontPercentViewportSize() const { return m_fontPercentViewportHeight; } /** * Set the percent viewport size for the font. * * @param fontPercentViewportHeight * New value for percent viewport height. */ void AnnotationColorBar::setFontPercentViewportSize(const float fontPercentViewportHeight) { if (fontPercentViewportHeight != m_fontPercentViewportHeight) { m_fontPercentViewportHeight = fontPercentViewportHeight; setModified(); } } /** * @return The foreground color. */ CaretColorEnum::Enum AnnotationColorBar::getTextColor() const { return m_colorText; } /** * Set the foreground color. * * @param color * New value for foreground color. */ void AnnotationColorBar::setTextColor(const CaretColorEnum::Enum color) { if (m_colorText != color) { m_colorText = color; setModified(); } } /** * Get the foreground color's RGBA components regardless of * coloring (custom color or a CaretColorEnum) selected by the user. * * @param rgbaOut * RGBA components ranging 0.0 to 1.0. */ void AnnotationColorBar::getTextColorRGBA(float rgbaOut[4]) const { switch (m_colorText) { case CaretColorEnum::NONE: rgbaOut[0] = 0.0; rgbaOut[1] = 0.0; rgbaOut[2] = 0.0; rgbaOut[3] = 0.0; break; case CaretColorEnum::CUSTOM: getCustomTextColor(rgbaOut); break; case CaretColorEnum::AQUA: case CaretColorEnum::BLACK: case CaretColorEnum::BLUE: case CaretColorEnum::FUCHSIA: case CaretColorEnum::GRAY: case CaretColorEnum::GREEN: case CaretColorEnum::LIME: case CaretColorEnum::MAROON: case CaretColorEnum::NAVY: case CaretColorEnum::OLIVE: case CaretColorEnum::PURPLE: case CaretColorEnum::RED: case CaretColorEnum::SILVER: case CaretColorEnum::TEAL: case CaretColorEnum::WHITE: case CaretColorEnum::YELLOW: CaretColorEnum::toRGBAFloat(m_colorText, rgbaOut); rgbaOut[3] = 1.0; break; } } /** * Get the foreground color's RGBA components regardless of * coloring (custom color or a CaretColorEnum) selected by the user. * * @param rgbaOut * RGBA components ranging 0 to 255. */ void AnnotationColorBar::getTextColorRGBA(uint8_t rgbaOut[4]) const { float rgbaFloat[4] = { 0.0, 0.0, 0.0, 0.0 }; getTextColorRGBA(rgbaFloat); rgbaOut[0] = static_cast(rgbaFloat[0] * 255.0); rgbaOut[1] = static_cast(rgbaFloat[1] * 255.0); rgbaOut[2] = static_cast(rgbaFloat[2] * 255.0); rgbaOut[3] = static_cast(rgbaFloat[3] * 255.0); } /** * Get the foreground color. * * @param rgbaOut * RGBA components (red, green, blue, alpha) each of which ranges [0.0, 1.0]. */ void AnnotationColorBar::getCustomTextColor(float rgbaOut[4]) const { rgbaOut[0] = m_customColorText[0]; rgbaOut[1] = m_customColorText[1]; rgbaOut[2] = m_customColorText[2]; rgbaOut[3] = m_customColorText[3]; } /** * Get the foreground color. * * @param rgbaOut * RGBA components (red, green, blue, alpha) each of which ranges [0, 255]. */ void AnnotationColorBar::getCustomTextColor(uint8_t rgbaOut[4]) const { rgbaOut[0] = static_cast(m_customColorText[0] * 255.0); rgbaOut[1] = static_cast(m_customColorText[1] * 255.0); rgbaOut[2] = static_cast(m_customColorText[2] * 255.0); rgbaOut[3] = static_cast(m_customColorText[3] * 255.0); } /** * Set the foreground color with floats. * * @param rgba * RGBA components (red, green, blue, alpha) each of which ranges [0.0, 1.0]. */ void AnnotationColorBar::setCustomTextColor(const float rgba[4]) { for (int32_t i = 0; i < 4; i++) { if (rgba[i] != m_customColorText[i]) { m_customColorText[i] = rgba[i]; setModified(); } } } /** * Set the foreground color with unsigned bytes. * * @param rgba * RGBA components (red, green, blue, alpha) each of which ranges [0, 255]. */ void AnnotationColorBar::setCustomTextColor(const uint8_t rgba[4]) { for (int32_t i = 0; i < 4; i++) { const float component = rgba[i] / 255.0; if (component != m_customColorText[i]) { m_customColorText[i] = component; setModified(); } } } /** * @return * Is bold enabled ? */ bool AnnotationColorBar::isBoldStyleEnabled() const { return false; } /** * Set bold enabled. * * @param enabled * New status for bold enabled. */ void AnnotationColorBar::setBoldStyleEnabled(const bool /*enabled*/) { } /** * @return * Is italic enabled ? */ bool AnnotationColorBar::isItalicStyleEnabled() const { return false; } /** * Set italic enabled. * * @param enabled * New status for italic enabled. */ void AnnotationColorBar::setItalicStyleEnabled(const bool /*enabled*/) { } /** * @return * Is underline enabled ? */ bool AnnotationColorBar::isUnderlineStyleEnabled() const { return false; } /** * Set underline enabled. * * @param enabled * New status for underline enabled. */ void AnnotationColorBar::setUnderlineStyleEnabled(const bool /*enabled*/) { } /** * @return * Is outline enabled ? */ bool AnnotationColorBar::isOutlineStyleEnabled() const { return false; } /** * Set outline enabled. * * @param enabled * New status for outline enabled. */ void AnnotationColorBar::setOutlineStyleEnabled(const bool /*enabled*/) { } /** * @return The position mode for the colorbar annotation. */ AnnotationColorBarPositionModeEnum::Enum AnnotationColorBar::getPositionMode() const { return m_positionMode; } /** * Set the position mode for the colorbar. * * @param positionMode * New position mode for the colorbar. */ void AnnotationColorBar::setPositionMode(const AnnotationColorBarPositionModeEnum::Enum positionMode) { if (positionMode != m_positionMode) { m_positionMode = positionMode; setModified(); } } /** * @return Display status of colorbar. */ bool AnnotationColorBar::isDisplayed() const { return m_displayedFlag; } /** * Set the color bar annotation displayed. * * Note that this also sets the annotation's selection * status to off so that if the user turns off display * of the annotation while the annotation is selected * the annotation does not show up as selected when * the color bar is later displayed by the user. * * @param displayed * New status for display of colorbar. */ void AnnotationColorBar::setDisplayed(const bool displayed) { if (displayed != m_displayedFlag) { m_displayedFlag = displayed; setDeselectedForEditing(); setModified(); } } /** * Save subclass data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void AnnotationColorBar::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { AnnotationTwoDimensionalShape::saveSubClassDataToScene(sceneAttributes, sceneClass); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void AnnotationColorBar::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { AnnotationTwoDimensionalShape::restoreSubClassDataFromScene(sceneAttributes, sceneClass); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); /* * Prior to WB-617 (28 Apr 2016), scenes may * not have contained the color bar background * color so it may be necessary to ensure * the background is not the same as the text * color. */ if (getTextColor() == getBackgroundColor()) { if (getTextColor() == CaretColorEnum::BLACK) { setBackgroundColor(CaretColorEnum::WHITE); } else { setBackgroundColor(CaretColorEnum::BLACK); } } } /** * Add a section. * * Note: sections are not saved to scene so this method DOES NOT change the modified status. * * @param startScalar * Value of the starting scalar. * @param endScalar * Value of the ending scalar. * @param startRGBA * RGBA coloring at the starting scalar. * @param endRGBA * RGBA coloring at the ending scalar. */ void AnnotationColorBar::addSection(const float startScalar, const float endScalar, const float startRGBA[4], const float endRGBA[4]) { m_sections.push_back(new AnnotationColorBarSection(startScalar, endScalar, startRGBA, endRGBA)); } /** * Clear the sections. * * Note: sections are not saved to scene so this method DOES NOT change the modified status. */ void AnnotationColorBar::clearSections() { for (std::vector::iterator iter = m_sections.begin(); iter != m_sections.end(); iter++) { delete *iter; } m_sections.clear(); } /** * @return Number of sections. */ int32_t AnnotationColorBar::getNumberOfSections() const { return m_sections.size(); } /** * @return Section at the given index. * * @param index * Index of the section. */ const AnnotationColorBarSection* AnnotationColorBar::getSection(const int32_t index) const { CaretAssertVectorIndex(m_sections, index); return m_sections[index]; } /** * @param Is show tick marks selected? */ bool AnnotationColorBar::isShowTickMarksSelected() const { return m_showTickMarksSelected; } /** * Set show tick marks selected. * * @param selected * New selection status. */ void AnnotationColorBar::setShowTickMarksSelected(const bool selected) { m_showTickMarksSelected = selected; } /** * Add numeric text. * * Note: numeric text is not saved to scene so this method DOES NOT change the modified status. * * @param scalar * Scalar value for position of numeric text. * @param numericText * The numeric text. */ void AnnotationColorBar::addNumericText(const float scalar, const AString& numericText, const AnnotationTextAlignHorizontalEnum::Enum horizontalAlignment, const bool drawTickMarkAtScalar) { m_numericText.push_back(new AnnotationColorBarNumericText(scalar, numericText, horizontalAlignment, drawTickMarkAtScalar)); } /** * Clear the numeric text. * * Note: numeric text is not saved to scene so this method DOES NOT change the modified status. */ void AnnotationColorBar::clearNumericText() { for (std::vector::iterator iter = m_numericText.begin(); iter != m_numericText.end(); iter++) { delete *iter; } m_numericText.clear(); } /** * @return Number of numeric text. */ int32_t AnnotationColorBar::getNumberOfNumericText() const { return m_numericText.size(); } /** * @return Numeric text at the given index. * * @param index * Inext of the numeric text. */ const AnnotationColorBarNumericText* AnnotationColorBar::getNumericText(const int32_t index) const { CaretAssertVectorIndex(m_numericText, index); return m_numericText[index]; } /** * Get the minimum and maximum scalar values in the colorbar. * * @param minimumScalarOut * Minimum scalar value upon exit. * @param maximumScalarOut * Maximum scalar value upon exit. */ void AnnotationColorBar::getScalarMinimumAndMaximumValues(float& minimumScalarOut, float& maximumScalarOut) const { minimumScalarOut = std::numeric_limits::max(); maximumScalarOut = -std::numeric_limits::max(); const int32_t numSections = getNumberOfSections(); if (numSections <= 0) { minimumScalarOut = 0.0; maximumScalarOut = 0.0; return; } for (int32_t i = 0; i < numSections; i++) { const AnnotationColorBarSection* section = getSection(i); minimumScalarOut = std::min(minimumScalarOut, section->getStartScalar()); minimumScalarOut = std::min(minimumScalarOut, section->getEndScalar()); maximumScalarOut = std::max(maximumScalarOut, section->getStartScalar()); maximumScalarOut = std::max(maximumScalarOut, section->getEndScalar()); } } /** * @return Is the font too small when it is last drawn * that may cause an OpenGL error and, as a result, * the text is not seen by the user. */ bool AnnotationColorBar::isFontTooSmallWhenLastDrawn() const { return m_fontTooSmallWhenLastDrawnFlag; } void AnnotationColorBar::setFontTooSmallWhenLastDrawn(const bool tooSmallFontFlag) const { m_fontTooSmallWhenLastDrawnFlag = tooSmallFontFlag; } connectome-workbench-1.4.2/src/Annotations/AnnotationColorBar.h000066400000000000000000000140671360521144700246360ustar00rootroot00000000000000#ifndef __ANNOTATION_COLOR_BAR_H__ #define __ANNOTATION_COLOR_BAR_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationColorBarPositionModeEnum.h" #include "AnnotationFontAttributesInterface.h" #include "AnnotationTextAlignHorizontalEnum.h" #include "AnnotationTwoDimensionalShape.h" namespace caret { class AnnotationColorBarSection; class AnnotationColorBarNumericText; class AnnotationColorBar : public AnnotationTwoDimensionalShape, public AnnotationFontAttributesInterface { public: AnnotationColorBar(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType); virtual ~AnnotationColorBar(); AnnotationColorBar(const AnnotationColorBar& obj); AnnotationColorBar& operator=(const AnnotationColorBar& obj); void reset(); void resetSizeAttributes(); virtual AnnotationTextFontNameEnum::Enum getFont() const; virtual void setFont(const AnnotationTextFontNameEnum::Enum font); virtual float getFontPercentViewportSize() const; virtual void setFontPercentViewportSize(const float fontPercentViewportHeight); AnnotationColorBarPositionModeEnum::Enum getPositionMode() const; void setPositionMode(const AnnotationColorBarPositionModeEnum::Enum positionMode); virtual CaretColorEnum::Enum getTextColor() const; virtual void setTextColor(const CaretColorEnum::Enum color); virtual void getTextColorRGBA(float rgbaOut[4]) const; virtual void getTextColorRGBA(uint8_t rgbaOut[4]) const; virtual void getCustomTextColor(float rgbaOut[4]) const; virtual void getCustomTextColor(uint8_t rgbaOut[4]) const; virtual void setCustomTextColor(const float rgba[4]); virtual void setCustomTextColor(const uint8_t rgba[4]); virtual bool isBoldStyleEnabled() const; virtual void setBoldStyleEnabled(const bool enabled); virtual bool isItalicStyleEnabled() const; virtual void setItalicStyleEnabled(const bool enabled); virtual bool isUnderlineStyleEnabled() const; virtual void setUnderlineStyleEnabled(const bool enabled); virtual bool isOutlineStyleEnabled() const; virtual void setOutlineStyleEnabled(const bool enabled); bool isDisplayed() const; void setDisplayed(const bool displayed); void addSection(const float startScalar, const float endScalar, const float startRGBA[4], const float endRGBA[4]); void clearSections(); int32_t getNumberOfSections() const; const AnnotationColorBarSection* getSection(const int32_t index) const; void addNumericText(const float scalar, const AString& numericText, const AnnotationTextAlignHorizontalEnum::Enum horizontalAlignment, const bool drawTickMarkAtScalar); void clearNumericText(); int32_t getNumberOfNumericText() const; const AnnotationColorBarNumericText* getNumericText(const int32_t index) const; void getScalarMinimumAndMaximumValues(float& minimumScalarOut, float& maximumScalarOut) const; bool isShowTickMarksSelected() const; void setShowTickMarksSelected(const bool selected); bool isFontTooSmallWhenLastDrawn() const override; void setFontTooSmallWhenLastDrawn(const bool tooSmallFontFlag) const override; // ADD_NEW_METHODS_HERE protected: virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: void copyHelperAnnotationColorBar(const AnnotationColorBar& obj); CaretPointer m_sceneAssistant; AnnotationTextFontNameEnum::Enum m_fontName; float m_fontPercentViewportHeight; AnnotationColorBarPositionModeEnum::Enum m_positionMode; CaretColorEnum::Enum m_colorText; float m_customColorText[4]; bool m_displayedFlag; /** color bar sections NOT SAVED TO SCENE */ std::vector m_sections; /** color bar numeric text NOT SAVED TO SCENE */ std::vector m_numericText; bool m_showTickMarksSelected; mutable bool m_fontTooSmallWhenLastDrawnFlag = false; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_COLOR_BAR_DECLARE__ // #endif // __ANNOTATION_COLOR_BAR_DECLARE__ } // namespace #endif //__ANNOTATION_COLOR_BAR_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationColorBarNumericText.cxx000066400000000000000000000063141360521144700273750ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_COLOR_BAR_NUMERIC_TEXT_DECLARE__ #include "AnnotationColorBarNumericText.h" #undef __ANNOTATION_COLOR_BAR_NUMERIC_TEXT_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationColorBarNumericText * \brief Numeric text that is displayed above the color bar. * \ingroup Annotations */ /** * Constructor. * * @param scalar * Scalar for position of text. * @param numericText * Text that is displayed. * @param horizontalAlignment * Horizontal alignment for the text. * @param drawTickMarkAtScalar * If true, a tick mark is drawn at the scalar */ AnnotationColorBarNumericText::AnnotationColorBarNumericText(const float scalar, const AString& numericText, const AnnotationTextAlignHorizontalEnum::Enum horizontalAlignment, const bool drawTickMarkAtScalar) : CaretObject(), m_scalar(scalar), m_numericText(numericText), m_horizontalAlignment(horizontalAlignment), m_drawTickMarkAtScalar(drawTickMarkAtScalar) { } /** * Destructor. */ AnnotationColorBarNumericText::~AnnotationColorBarNumericText() { } /** * Copy constructor. * @param obj * Object that is copied. */ AnnotationColorBarNumericText::AnnotationColorBarNumericText(const AnnotationColorBarNumericText& obj) : CaretObject(obj) { this->copyHelperAnnotationColorBarNumericText(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ AnnotationColorBarNumericText& AnnotationColorBarNumericText::operator=(const AnnotationColorBarNumericText& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperAnnotationColorBarNumericText(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void AnnotationColorBarNumericText::copyHelperAnnotationColorBarNumericText(const AnnotationColorBarNumericText& obj) { m_scalar = obj.m_scalar; m_numericText = obj.m_numericText; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString AnnotationColorBarNumericText::toString() const { return "AnnotationColorBarNumericText"; } connectome-workbench-1.4.2/src/Annotations/AnnotationColorBarNumericText.h000066400000000000000000000061101360521144700270140ustar00rootroot00000000000000#ifndef __ANNOTATION_COLOR_BAR_NUMERIC_TEXT_H__ #define __ANNOTATION_COLOR_BAR_NUMERIC_TEXT_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationTextAlignHorizontalEnum.h" #include "CaretObject.h" namespace caret { class AnnotationColorBarNumericText : public CaretObject { public: AnnotationColorBarNumericText(const float scalar, const AString& numericText, const AnnotationTextAlignHorizontalEnum::Enum horizontalAlignment, const bool drawTickMarkAtScalar); virtual ~AnnotationColorBarNumericText(); AnnotationColorBarNumericText(const AnnotationColorBarNumericText& obj); AnnotationColorBarNumericText& operator=(const AnnotationColorBarNumericText& obj); /** * @return The scalar value. */ float getScalar() const { return m_scalar; } /** * @return The numeric text. */ AString getNumericText() const { return m_numericText; } /** * Set the numeric text * * @param text * New text. */ void setNumericText(const AString& text) { m_numericText = text; } /** * @return The horizontal alignment for the text */ AnnotationTextAlignHorizontalEnum::Enum getHorizontalAlignment() const { return m_horizontalAlignment; } /** * @return Is a tick mark drawn at the scalar value ? */ bool isDrawTickMarkAtScalar() const { return m_drawTickMarkAtScalar; } // ADD_NEW_METHODS_HERE virtual AString toString() const; private: void copyHelperAnnotationColorBarNumericText(const AnnotationColorBarNumericText& obj); float m_scalar; AString m_numericText; AnnotationTextAlignHorizontalEnum::Enum m_horizontalAlignment; bool m_drawTickMarkAtScalar; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_COLOR_BAR_NUMERIC_TEXT_DECLARE__ // #endif // __ANNOTATION_COLOR_BAR_NUMERIC_TEXT_DECLARE__ } // namespace #endif //__ANNOTATION_COLOR_BAR_NUMERIC_TEXT_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationColorBarPositionModeEnum.cxx000066400000000000000000000270061360521144700303650ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_COLOR_BAR_POSITION_MODE_ENUM_DECLARE__ #include "AnnotationColorBarPositionModeEnum.h" #undef __ANNOTATION_COLOR_BAR_POSITION_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationColorBarPositionModeEnum * \brief Enumerated type for positioning of color bar * * * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_annotationColorBarPositionModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void annotationColorBarPositionModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "AnnotationColorBarPositionModeEnum.h" * * Instatiate: * m_annotationColorBarPositionModeEnumComboBox = new EnumComboBoxTemplate(this); * m_annotationColorBarPositionModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_annotationColorBarPositionModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(annotationColorBarPositionModeEnumComboBoxItemActivated())); * * Update the selection: * m_annotationColorBarPositionModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const AnnotationColorBarPositionModeEnum::Enum VARIABLE = m_annotationColorBarPositionModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ AnnotationColorBarPositionModeEnum::AnnotationColorBarPositionModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ AnnotationColorBarPositionModeEnum::~AnnotationColorBarPositionModeEnum() { } /** * Initialize the enumerated metadata. */ void AnnotationColorBarPositionModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(AnnotationColorBarPositionModeEnum(AUTOMATIC, "AUTOMATIC", "Automatic")); enumData.push_back(AnnotationColorBarPositionModeEnum(MANUAL, "MANUAL", "Manual")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const AnnotationColorBarPositionModeEnum* AnnotationColorBarPositionModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const AnnotationColorBarPositionModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationColorBarPositionModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationColorBarPositionModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationColorBarPositionModeEnum::Enum AnnotationColorBarPositionModeEnum::fromName(const AString& nameIn, bool* isValidOut) { if (initializedFlag == false) initialize(); AString name(nameIn); if (name == "USER") { name = AnnotationColorBarPositionModeEnum::toName(MANUAL); } if (name == "AUTO") { name = AnnotationColorBarPositionModeEnum::toName(AUTOMATIC); } bool validFlag = false; Enum enumValue = AnnotationColorBarPositionModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationColorBarPositionModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type AnnotationColorBarPositionModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationColorBarPositionModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationColorBarPositionModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationColorBarPositionModeEnum::Enum AnnotationColorBarPositionModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationColorBarPositionModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationColorBarPositionModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type AnnotationColorBarPositionModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t AnnotationColorBarPositionModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationColorBarPositionModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ AnnotationColorBarPositionModeEnum::Enum AnnotationColorBarPositionModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationColorBarPositionModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationColorBarPositionModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type AnnotationColorBarPositionModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void AnnotationColorBarPositionModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationColorBarPositionModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(AnnotationColorBarPositionModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationColorBarPositionModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(AnnotationColorBarPositionModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Annotations/AnnotationColorBarPositionModeEnum.h000066400000000000000000000064031360521144700300100ustar00rootroot00000000000000#ifndef __ANNOTATION_COLOR_BAR_POSITION_MODE_ENUM_H__ #define __ANNOTATION_COLOR_BAR_POSITION_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class AnnotationColorBarPositionModeEnum { public: /** * Enumerated values. */ enum Enum { /** Auto */ AUTOMATIC, /** Manual */ MANUAL }; ~AnnotationColorBarPositionModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: AnnotationColorBarPositionModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const AnnotationColorBarPositionModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __ANNOTATION_COLOR_BAR_POSITION_MODE_ENUM_DECLARE__ std::vector AnnotationColorBarPositionModeEnum::enumData; bool AnnotationColorBarPositionModeEnum::initializedFlag = false; int32_t AnnotationColorBarPositionModeEnum::integerCodeCounter = 0; #endif // __ANNOTATION_COLOR_BAR_POSITION_MODE_ENUM_DECLARE__ } // namespace #endif //__ANNOTATION_COLOR_BAR_POSITION_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationColorBarSection.cxx000066400000000000000000000060021360521144700265240ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_COLOR_BAR_SECTION_DECLARE__ #include "AnnotationColorBarSection.h" #undef __ANNOTATION_COLOR_BAR_SECTION_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationColorBarSection * \brief Contains scalars and coloring for one section of the colorbar. * \ingroup Annotations */ /** * Constructor. * * @param startScalar * Value of the starting scalar. * @param endScalar * Value of the ending scalar. * @param startRGBA * RGBA coloring at the starting scalar. * @param endRGBA * RGBA coloring at the ending scalar. */ AnnotationColorBarSection::AnnotationColorBarSection(const float startScalar, const float endScalar, const float startRGBA[4], const float endRGBA[4]) : CaretObject(), m_startScalar(startScalar), m_endScalar(endScalar) { for (int32_t i = 0; i < 4; i++) { m_startRGBA[i] = startRGBA[i]; m_endRGBA[i] = endRGBA[i]; } } /** * Destructor. */ AnnotationColorBarSection::~AnnotationColorBarSection() { } /** * Copy constructor. * @param obj * Object that is copied. */ AnnotationColorBarSection::AnnotationColorBarSection(const AnnotationColorBarSection& obj) : CaretObject(obj) { this->copyHelperAnnotationColorBarSection(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ AnnotationColorBarSection& AnnotationColorBarSection::operator=(const AnnotationColorBarSection& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperAnnotationColorBarSection(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void AnnotationColorBarSection::copyHelperAnnotationColorBarSection(const AnnotationColorBarSection& obj) { m_startScalar = obj.m_startScalar; m_endScalar = obj.m_endScalar; for (int32_t i = 0; i < 4; i++) { m_startRGBA[i] = obj.m_startRGBA[i]; m_endRGBA[i] = obj.m_endRGBA[i]; } } connectome-workbench-1.4.2/src/Annotations/AnnotationColorBarSection.h000066400000000000000000000050111360521144700261500ustar00rootroot00000000000000#ifndef __ANNOTATION_COLOR_BAR_SECTION_H__ #define __ANNOTATION_COLOR_BAR_SECTION_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" namespace caret { class AnnotationColorBarSection : public CaretObject { public: AnnotationColorBarSection(const float startScalar, const float endScalar, const float startRGBA[4], const float endRGBA[4]); virtual ~AnnotationColorBarSection(); AnnotationColorBarSection(const AnnotationColorBarSection& obj); AnnotationColorBarSection& operator=(const AnnotationColorBarSection& obj); /** * @return The starting scalar */ float getStartScalar() const { return m_startScalar; } /** * @return The ending scalar */ float getEndScalar() const { return m_endScalar; } /** * @return Pointer to starting RGBA */ const float* getStartRGBA() const { return m_startRGBA; } /** * @return Pointer to ending RGBA */ const float* getEndRGBA() const { return m_endRGBA; } private: void copyHelperAnnotationColorBarSection(const AnnotationColorBarSection& obj); float m_startScalar; float m_endScalar; float m_startRGBA[4]; float m_endRGBA[4]; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_COLOR_BAR_SECTION_DECLARE__ // #endif // __ANNOTATION_COLOR_BAR_SECTION_DECLARE__ } // namespace #endif //__ANNOTATION_COLOR_BAR_SECTION_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationCoordinate.cxx000066400000000000000000000361361360521144700255760ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_COORDINATE_DECLARE__ #include "AnnotationCoordinate.h" #undef __ANNOTATION_COORDINATE_DECLARE__ #include "CaretAssert.h" #include "MathFunctions.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::AnnotationCoordinate * \brief Coordinate for an annotation. * \ingroup Annotations */ /** * Constructor. */ AnnotationCoordinate::AnnotationCoordinate(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType) : CaretObjectTracksModification(), SceneableInterface(), m_attributeDefaultType(attributeDefaultType) { initializeAnnotationCoordinateMembers(); } /** * Destructor. */ AnnotationCoordinate::~AnnotationCoordinate() { delete m_sceneAssistant; } /** * Copy constructor. * @param obj * Object that is copied. */ AnnotationCoordinate::AnnotationCoordinate(const AnnotationCoordinate& obj) : CaretObjectTracksModification(obj), SceneableInterface(obj), m_attributeDefaultType(obj.m_attributeDefaultType) { initializeAnnotationCoordinateMembers(); this->copyHelperAnnotationCoordinate(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ AnnotationCoordinate& AnnotationCoordinate::operator=(const AnnotationCoordinate& obj) { if (this != &obj) { CaretObjectTracksModification::operator=(obj); this->copyHelperAnnotationCoordinate(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void AnnotationCoordinate::copyHelperAnnotationCoordinate(const AnnotationCoordinate& obj) { m_xyz[0] = obj.m_xyz[0]; m_xyz[1] = obj.m_xyz[1]; m_xyz[2] = obj.m_xyz[2]; m_surfaceSpaceStructure = obj.m_surfaceSpaceStructure; m_surfaceSpaceNumberOfNodes = obj.m_surfaceSpaceNumberOfNodes; m_surfaceSpaceNodeIndex = obj.m_surfaceSpaceNodeIndex; m_surfaceOffsetLength = obj.m_surfaceOffsetLength; m_surfaceOffsetVectorType = obj.m_surfaceOffsetVectorType; } /** * Initialize members for an instance of this class. */ void AnnotationCoordinate::initializeAnnotationCoordinateMembers() { m_xyz[0] = 0.0; m_xyz[1] = 0.0; m_xyz[2] = 0.0; m_surfaceSpaceStructure = StructureEnum::INVALID; m_surfaceSpaceNumberOfNodes = -1; m_surfaceSpaceNodeIndex = -1; switch (m_attributeDefaultType) { case AnnotationAttributesDefaultTypeEnum::NORMAL: m_surfaceOffsetLength = getDefaultSurfaceOffsetLength(); m_surfaceOffsetVectorType = AnnotationSurfaceOffsetVectorTypeEnum::TANGENT; break; case AnnotationAttributesDefaultTypeEnum::USER: m_surfaceOffsetLength = s_userDefaultSurfaceOffsetLength; m_surfaceOffsetVectorType = s_userDefaultSurfaceOffsetVectorType; break; } m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->addArray("m_xyz", m_xyz, 3, 0.0); m_sceneAssistant->add("m_surfaceSpaceStructure", &m_surfaceSpaceStructure); m_sceneAssistant->add("m_surfaceSpaceNumberOfNodes", &m_surfaceSpaceNumberOfNodes); m_sceneAssistant->add("m_surfaceSpaceNodeIndex", &m_surfaceSpaceNodeIndex); m_sceneAssistant->add("m_surfaceOffsetLength", &m_surfaceOffsetLength); m_sceneAssistant->add("m_surfaceOffsetVectorType", &m_surfaceOffsetVectorType); } /** * @return The annotation's coordinate. * * For tab and window spaces, the Z value is a depth for ordering. */ const float* AnnotationCoordinate::getXYZ() const { return m_xyz; } /** * Get the annotation's coordinate. * * For tab and window spaces, the Z value is a depth for ordering. * * @param xyzOut */ void AnnotationCoordinate::getXYZ(float xyzOut[3]) const { xyzOut[0] = m_xyz[0]; xyzOut[1] = m_xyz[1]; xyzOut[2] = m_xyz[2]; } /** * Set the annotation's coordinate. * * For tab and window spaces, the Z value is a depth for ordering. * * @param xyz * New coordinate for the annotation. */ void AnnotationCoordinate::setXYZ(const float xyz[3]) { setXYZ(xyz[0], xyz[1], xyz[2]); } /** * Set the annotation's coordinate. * * For tab and window spaces, the Z value is a depth for ordering. * * @param xyz * New coordinate for the annotation. */ void AnnotationCoordinate::setXYZ(const double xyz[3]) { setXYZ(xyz[0], xyz[1], xyz[2]); } /** * Set the annotation's coordinate. * * For tab and window spaces, the Z value is a depth for ordering. * * @param x * New X-coordinate for the annotation. * @param y * New Y-coordinate for the annotation. * @param z * New Z-coordinate for the annotation. */ void AnnotationCoordinate::setXYZ(const float x, const float y, const float z) { if ((x != m_xyz[0]) || (y != m_xyz[1]) || (z != m_xyz[2])) { m_xyz[0] = x; m_xyz[1] = y; m_xyz[2] = z; setModified(); } } /** * Add to the annotation's XYZ coordinate. * * @param dx * Change in X-coordinate for the annotation. * @param dy * Change in Y-coordinate for the annotation. * @param dz * Change in Z-coordinate for the annotation. */ void AnnotationCoordinate::addToXYZ(const float dx, const float dy, const float dz) { setXYZ(m_xyz[0] + dx, m_xyz[1] + dy, m_xyz[2] + dz); } /** * Set the window or tab XYZ from viewport X, Y. * * @param viewportWidth * Width of viewport. * @param viewportHeight * Height of viewport. * @param viewportX * X viewport coordinate. * @param viewportY * Y viewport coordinate. */ void AnnotationCoordinate::setXYZFromViewportXYZ(const float viewportWidth, const float viewportHeight, const float viewportX, const float viewportY) { const float x = MathFunctions::limitRange(((viewportX / viewportWidth) * 100.0), 0.0, 100.0); const float y = MathFunctions::limitRange(((viewportY / viewportHeight) * 100.0), 0.0, 100.0); setXYZ(x, y, m_xyz[2]); } /** * Get the viewport X, Y from window or tab XYZ. * * @param viewportWidth * Width of viewport. * @param viewportHeight * Height of viewport. * @param viewportXOut * X viewport coordinate. * @param viewportYOut * Y viewport coordinate. */ void AnnotationCoordinate::getViewportXY(const float viewportWidth, const float viewportHeight, float& viewportXOut, float& viewportYOut) const { viewportXOut = (m_xyz[0] / 100.0) * viewportWidth; viewportYOut = (m_xyz[1] / 100.0) * viewportHeight; } /** * Get the surface space data. * * @param structureOut * The surface structure. * @param surfaceNumberOfNodesOut * Number of nodes in surface. * @param surfaceNodeIndexOut * Index of surface node. */ void AnnotationCoordinate::getSurfaceSpace(StructureEnum::Enum& structureOut, int32_t& surfaceNumberOfNodesOut, int32_t& surfaceNodeIndexOut) const { structureOut = m_surfaceSpaceStructure; surfaceNumberOfNodesOut = m_surfaceSpaceNumberOfNodes; surfaceNodeIndexOut = m_surfaceSpaceNodeIndex; } /** * Get the surface space data. * * @param structureOut * The surface structure. * @param surfaceNumberOfNodesOut * Number of nodes in surface. * @param surfaceNodeIndexOut * Index of surface node. * @param surfaceOffsetLengthOut * Offset of annotation from surface * @param surfaceOffsetVectorTypeOut * Offset from surface vector type. */ void AnnotationCoordinate::getSurfaceSpace(StructureEnum::Enum& structureOut, int32_t& surfaceNumberOfNodesOut, int32_t& surfaceNodeIndexOut, float& surfaceOffsetLengthOut, AnnotationSurfaceOffsetVectorTypeEnum::Enum& surfaceOffsetVectorTypeOut) const { structureOut = m_surfaceSpaceStructure; surfaceNumberOfNodesOut = m_surfaceSpaceNumberOfNodes; surfaceNodeIndexOut = m_surfaceSpaceNodeIndex; surfaceOffsetLengthOut = m_surfaceOffsetLength; surfaceOffsetVectorTypeOut = m_surfaceOffsetVectorType; } /** * Set the surface space data. * * @param structure * The surface structure. * @param surfaceNumberOfNodes * Number of nodes in surface. * @param surfaceNodeIndex * Index of surface node. */ void AnnotationCoordinate::setSurfaceSpace(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const int32_t surfaceNodeIndex) { if (structure != m_surfaceSpaceStructure) { m_surfaceSpaceStructure = structure; setModified(); } if (surfaceNumberOfNodes != m_surfaceSpaceNumberOfNodes) { m_surfaceSpaceNumberOfNodes = surfaceNumberOfNodes; setModified(); } if (surfaceNodeIndex != m_surfaceSpaceNodeIndex) { m_surfaceSpaceNodeIndex = surfaceNodeIndex; setModified(); } } /** * Set the surface space data. * * @param structure * The surface structure. * @param surfaceNumberOfNodes * Number of nodes in surface. * @param surfaceNodeIndex * Index of surface node. * @param surfaceOffsetLength * Offset of annotation from surface * @param surfaceOffsetVectorType * Offset from surface vector type. */ void AnnotationCoordinate::setSurfaceSpace(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const int32_t surfaceNodeIndex, const float surfaceOffsetLength, const AnnotationSurfaceOffsetVectorTypeEnum::Enum surfaceOffsetVectorType) { if (structure != m_surfaceSpaceStructure) { m_surfaceSpaceStructure = structure; setModified(); } if (surfaceNumberOfNodes != m_surfaceSpaceNumberOfNodes) { m_surfaceSpaceNumberOfNodes = surfaceNumberOfNodes; setModified(); } if (surfaceNodeIndex != m_surfaceSpaceNodeIndex) { m_surfaceSpaceNodeIndex = surfaceNodeIndex; setModified(); } if (surfaceOffsetLength != m_surfaceOffsetLength) { m_surfaceOffsetLength = surfaceOffsetLength; setModified(); } if (surfaceOffsetVectorType != m_surfaceOffsetVectorType) { m_surfaceOffsetVectorType = surfaceOffsetVectorType; setModified(); } } /** * @return The default surface offset length. */ float AnnotationCoordinate::getDefaultSurfaceOffsetLength() { return 5.0; } /** * @return The surface offset length. */ float AnnotationCoordinate::getSurfaceOffsetLength() const { return m_surfaceOffsetLength; } /** * @return The surface structure. */ StructureEnum::Enum AnnotationCoordinate::getSurfaceStructure() const { return m_surfaceSpaceStructure; } /** * @return Type of surface offset. */ AnnotationSurfaceOffsetVectorTypeEnum::Enum AnnotationCoordinate::getSurfaceOffsetVectorType() const { return m_surfaceOffsetVectorType; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString AnnotationCoordinate::toString() const { return "AnnotationCoordinate"; } /** * Set the user default for the surface offset vector type. * * @param surfaceOffsetVectorType * new default value. */ void AnnotationCoordinate::setUserDefautlSurfaceOffsetVectorType(const AnnotationSurfaceOffsetVectorTypeEnum::Enum surfaceOffsetVectorType) { s_userDefaultSurfaceOffsetVectorType = surfaceOffsetVectorType; } /** * Set the user default for the surface offset length. * * @param surfaceOffsetLength * New default value. */ void AnnotationCoordinate::setUserDefaultSurfaceOffsetLength(const float surfaceOffsetLength) { s_userDefaultSurfaceOffsetLength = surfaceOffsetLength; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* AnnotationCoordinate::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "AnnotationCoordinate", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void AnnotationCoordinate::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Annotations/AnnotationCoordinate.h000066400000000000000000000142621360521144700252170ustar00rootroot00000000000000#ifndef __ANNOTATION_COORDINATE_H__ #define __ANNOTATION_COORDINATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationAttributesDefaultTypeEnum.h" #include "AnnotationSurfaceOffsetVectorTypeEnum.h" #include "CaretObjectTracksModification.h" #include "SceneableInterface.h" #include "StructureEnum.h" namespace caret { class SceneClassAssistant; class AnnotationCoordinate : public CaretObjectTracksModification, public SceneableInterface { public: AnnotationCoordinate(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType); virtual ~AnnotationCoordinate(); AnnotationCoordinate(const AnnotationCoordinate& obj); AnnotationCoordinate& operator=(const AnnotationCoordinate& obj); const float* getXYZ() const; void getXYZ(float xyzOut[3]) const; void setXYZ(const float xyz[3]); void setXYZ(const double xyz[3]); void setXYZ(const float x, const float y, const float z); void addToXYZ(const float dx, const float dy, const float dz); void setXYZFromViewportXYZ(const float viewportWidth, const float viewportHeight, const float viewportX, const float viewportY); void getViewportXY(const float viewportWidth, const float viewportHeight, float& viewportXOut, float& viewportYOut) const; void getSurfaceSpace(StructureEnum::Enum& structureOut, int32_t& surfaceNumberOfNodesOut, int32_t& surfaceNodeIndexOut) const; void getSurfaceSpace(StructureEnum::Enum& structureOut, int32_t& surfaceNumberOfNodesOut, int32_t& surfaceNodeIndexOut, float& surfaceOffsetLengthOut, AnnotationSurfaceOffsetVectorTypeEnum::Enum& surfaceOffsetVectorTypeOut) const; void setSurfaceSpace(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const int32_t surfaceNodeIndex); void setSurfaceSpace(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const int32_t surfaceNodeIndex, const float surfaceOffsetLength, const AnnotationSurfaceOffsetVectorTypeEnum::Enum surfaceOffsetVectorType); float getSurfaceOffsetLength() const; StructureEnum::Enum getSurfaceStructure() const; AnnotationSurfaceOffsetVectorTypeEnum::Enum getSurfaceOffsetVectorType() const; // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); static float getDefaultSurfaceOffsetLength(); static void setUserDefautlSurfaceOffsetVectorType(const AnnotationSurfaceOffsetVectorTypeEnum::Enum surfaceOffsetVectorType); static void setUserDefaultSurfaceOffsetLength(const float surfaceOffsetLength); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implemetation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: void copyHelperAnnotationCoordinate(const AnnotationCoordinate& obj); void initializeAnnotationCoordinateMembers(); const AnnotationAttributesDefaultTypeEnum::Enum m_attributeDefaultType; SceneClassAssistant* m_sceneAssistant; float m_xyz[3]; int32_t m_surfaceSpaceNodeIndex; int32_t m_surfaceSpaceNumberOfNodes; StructureEnum::Enum m_surfaceSpaceStructure; float m_surfaceOffsetLength; AnnotationSurfaceOffsetVectorTypeEnum::Enum m_surfaceOffsetVectorType; static float s_userDefaultSurfaceOffsetLength; static AnnotationSurfaceOffsetVectorTypeEnum::Enum s_userDefaultSurfaceOffsetVectorType; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_COORDINATE_DECLARE__ float AnnotationCoordinate::s_userDefaultSurfaceOffsetLength = 1.0f; AnnotationSurfaceOffsetVectorTypeEnum::Enum AnnotationCoordinate::s_userDefaultSurfaceOffsetVectorType = AnnotationSurfaceOffsetVectorTypeEnum::TANGENT; #endif // __ANNOTATION_COORDINATE_DECLARE__ } // namespace #endif //__ANNOTATION_COORDINATE_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationCoordinateSpaceEnum.cxx000066400000000000000000000344411360521144700273740ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_COORDINATE_SPACE_ENUM_DECLARE__ #include "AnnotationCoordinateSpaceEnum.h" #undef __ANNOTATION_COORDINATE_SPACE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationCoordinateSpaceEnum * \brief Coordinate space of annotation. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_annotationCoordinateSpaceEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void annotationCoordinateSpaceEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "AnnotationCoordinateSpaceEnum.h" * * Instatiate: * m_annotationCoordinateSpaceEnumComboBox = new EnumComboBoxTemplate(this); * m_annotationCoordinateSpaceEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_annotationCoordinateSpaceEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(annotationCoordinateSpaceEnumComboBoxItemActivated())); * * Update the selection: * m_annotationCoordinateSpaceEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const AnnotationCoordinateSpaceEnum::Enum VARIABLE = m_annotationCoordinateSpaceEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. * @param guiAbbreviatedName * Abbreviated User-friendly name for use in user-interface. */ AnnotationCoordinateSpaceEnum::AnnotationCoordinateSpaceEnum(const Enum enumValue, const AString& name, const AString& guiName, const AString& guiAbbreviatedName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; this->guiAbbreviatedName = guiAbbreviatedName; } /** * Destructor. */ AnnotationCoordinateSpaceEnum::~AnnotationCoordinateSpaceEnum() { } /** * Initialize the enumerated metadata. */ void AnnotationCoordinateSpaceEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(AnnotationCoordinateSpaceEnum(CHART, "CHART", "Chart", "Ch")); enumData.push_back(AnnotationCoordinateSpaceEnum(SPACER, "SPACER", "Spacer", "Sp")); enumData.push_back(AnnotationCoordinateSpaceEnum(STEREOTAXIC, "STEREOTAXIC", "Stereotaxic", "St")); enumData.push_back(AnnotationCoordinateSpaceEnum(SURFACE, "SURFACE", "Surface", "Sf")); enumData.push_back(AnnotationCoordinateSpaceEnum(TAB, "TAB", "Tab", "T")); enumData.push_back(AnnotationCoordinateSpaceEnum(VIEWPORT, "VIEWPORT", "Viewport", "V")); enumData.push_back(AnnotationCoordinateSpaceEnum(WINDOW, "WINDOW", "Window", "W")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const AnnotationCoordinateSpaceEnum* AnnotationCoordinateSpaceEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const AnnotationCoordinateSpaceEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationCoordinateSpaceEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationCoordinateSpaceEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name In * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationCoordinateSpaceEnum::Enum AnnotationCoordinateSpaceEnum::fromName(const AString& nameIn, bool* isValidOut) { if (initializedFlag == false) initialize(); AString name = nameIn; if (name == "MODEL") { name = "STEREOTAXIC"; } bool validFlag = false; Enum enumValue = AnnotationCoordinateSpaceEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationCoordinateSpaceEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type AnnotationCoordinateSpaceEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationCoordinateSpaceEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationCoordinateSpaceEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param guiNameIn * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationCoordinateSpaceEnum::Enum AnnotationCoordinateSpaceEnum::fromGuiName(const AString& guiNameIn, bool* isValidOut) { if (initializedFlag == false) initialize(); AString guiName = guiNameIn; if (guiName == "Model") { guiName = "Stereotaxic"; } bool validFlag = false; Enum enumValue = AnnotationCoordinateSpaceEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationCoordinateSpaceEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type AnnotationCoordinateSpaceEnum")); } return enumValue; } /** * Get a GUI abbreviated string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationCoordinateSpaceEnum::toGuiAbbreviatedName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationCoordinateSpaceEnum* enumInstance = findData(enumValue); return enumInstance->guiAbbreviatedName; } /** * @return Text that is displayed for a space's tooltip in the GUI. */ AString AnnotationCoordinateSpaceEnum::toToolTip(Enum enumValue) { AString text; switch (enumValue) { case CHART: text = "New annotation is drawn at a chart data XYZ coordinate"; break; case SPACER: text = "New annotation is drawn at an XY coordinate in the spacer"; break; case STEREOTAXIC: text = "New annotation is drawn at a surface/volume XYZ coordinate"; break; case SURFACE: text = "New annotation is drawn at a surface vertex"; break; case TAB: text = "New annotation is drawn at an XY coordinate in the tab"; break; case VIEWPORT: text = "New annotation is drawn at an XY coordinate in the viewport"; break; case WINDOW: text = "New annotation is drawn at an XY coordinate in the window"; break; } return text; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t AnnotationCoordinateSpaceEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationCoordinateSpaceEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ AnnotationCoordinateSpaceEnum::Enum AnnotationCoordinateSpaceEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationCoordinateSpaceEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationCoordinateSpaceEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type AnnotationCoordinateSpaceEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void AnnotationCoordinateSpaceEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationCoordinateSpaceEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(AnnotationCoordinateSpaceEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationCoordinateSpaceEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(AnnotationCoordinateSpaceEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Annotations/AnnotationCoordinateSpaceEnum.h000066400000000000000000000074731360521144700270260ustar00rootroot00000000000000#ifndef __ANNOTATION_COORDINATE_SPACE_ENUM_H__ #define __ANNOTATION_COORDINATE_SPACE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class AnnotationCoordinateSpaceEnum { public: /** * Enumerated values. */ enum Enum { /** Chart space */ CHART, /** Annotation in spacer */ SPACER, /** Annotation in stereotaxic (3D) space */ STEREOTAXIC, /** Annotation on surface node */ SURFACE, /** Annotation in tab space */ TAB, /** Annotation in viewport space */ VIEWPORT, /** Annotation in window space */ WINDOW }; ~AnnotationCoordinateSpaceEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static AString toGuiAbbreviatedName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static AString toToolTip(Enum enumValue); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: AnnotationCoordinateSpaceEnum(const Enum enumValue, const AString& name, const AString& guiName, const AString& guiAbbreviatedName); static const AnnotationCoordinateSpaceEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** An abbreviated user-friendly name that is displayed in the GUI */ AString guiAbbreviatedName; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __ANNOTATION_COORDINATE_SPACE_ENUM_DECLARE__ std::vector AnnotationCoordinateSpaceEnum::enumData; bool AnnotationCoordinateSpaceEnum::initializedFlag = false; int32_t AnnotationCoordinateSpaceEnum::integerCodeCounter = 0; #endif // __ANNOTATION_COORDINATE_SPACE_ENUM_DECLARE__ } // namespace #endif //__ANNOTATION_COORDINATE_SPACE_ENUM_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationDistributeEnum.cxx000066400000000000000000000252461360521144700264520ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_DISTRIBUTE_ENUM_DECLARE__ #include "AnnotationDistributeEnum.h" #undef __ANNOTATION_DISTRIBUTE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationDistributeEnum * \brief Enumerated type for distributing annotations. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_annotationDistributeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void annotationDistributeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "AnnotationDistributeEnum.h" * * Instatiate: * m_annotationDistributeEnumComboBox = new EnumComboBoxTemplate(this); * m_annotationDistributeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_annotationDistributeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(annotationDistributeEnumComboBoxItemActivated())); * * Update the selection: * m_annotationDistributeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const AnnotationDistributeEnum::Enum VARIABLE = m_annotationDistributeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ AnnotationDistributeEnum::AnnotationDistributeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ AnnotationDistributeEnum::~AnnotationDistributeEnum() { } /** * Initialize the enumerated metadata. */ void AnnotationDistributeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(AnnotationDistributeEnum(HORIZONTALLY, "HORIZONTALLY", "Distribute Horizontally")); enumData.push_back(AnnotationDistributeEnum(VERTICALLY, "VERTICALLY", "Distribute Vertically")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const AnnotationDistributeEnum* AnnotationDistributeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const AnnotationDistributeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationDistributeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationDistributeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationDistributeEnum::Enum AnnotationDistributeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationDistributeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationDistributeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type AnnotationDistributeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationDistributeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationDistributeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationDistributeEnum::Enum AnnotationDistributeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationDistributeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationDistributeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type AnnotationDistributeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t AnnotationDistributeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationDistributeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ AnnotationDistributeEnum::Enum AnnotationDistributeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationDistributeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationDistributeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type AnnotationDistributeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void AnnotationDistributeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationDistributeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(AnnotationDistributeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationDistributeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(AnnotationDistributeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Annotations/AnnotationDistributeEnum.h000066400000000000000000000061431360521144700260720ustar00rootroot00000000000000#ifndef __ANNOTATION_DISTRIBUTE_ENUM_H__ #define __ANNOTATION_DISTRIBUTE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class AnnotationDistributeEnum { public: /** * Enumerated values. */ enum Enum { /** */ HORIZONTALLY, /** */ VERTICALLY }; ~AnnotationDistributeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: AnnotationDistributeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const AnnotationDistributeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __ANNOTATION_DISTRIBUTE_ENUM_DECLARE__ std::vector AnnotationDistributeEnum::enumData; bool AnnotationDistributeEnum::initializedFlag = false; int32_t AnnotationDistributeEnum::integerCodeCounter = 0; #endif // __ANNOTATION_DISTRIBUTE_ENUM_DECLARE__ } // namespace #endif //__ANNOTATION_DISTRIBUTE_ENUM_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationEditingSelectionInformation.cxx000066400000000000000000000215661360521144700311470ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_SELECTION_INFORMATION_DECLARE__ #include "AnnotationEditingSelectionInformation.h" #undef __ANNOTATION_SELECTION_INFORMATION_DECLARE__ #include "Annotation.h" #include "AnnotationGroup.h" #include "CaretAssert.h" #include "CaretLogger.h" using namespace caret; /** * \class caret::AnnotationEditingSelectionInformation * \brief Contains selected annotations and related information. * \ingroup Annotations */ /** * Constructor. * * @param windowIndex * Index of window in which annotations are selected. */ AnnotationEditingSelectionInformation::AnnotationEditingSelectionInformation(const int32_t windowIndex) : CaretObject(), m_windowIndex(windowIndex) { } /** * Destructor. */ AnnotationEditingSelectionInformation::~AnnotationEditingSelectionInformation() { } /** * Copy constructor. * @param obj * Object that is copied. */ AnnotationEditingSelectionInformation::AnnotationEditingSelectionInformation(const AnnotationEditingSelectionInformation& obj) : CaretObject(obj), m_windowIndex(obj.m_windowIndex) { this->copyHelperAnnotationSelectionInformation(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ AnnotationEditingSelectionInformation& AnnotationEditingSelectionInformation::operator=(const AnnotationEditingSelectionInformation& obj) { if (this != &obj) { if (m_windowIndex == obj.m_windowIndex) { CaretObject::operator=(obj); this->copyHelperAnnotationSelectionInformation(obj); } else { const QString msg("Cannot copy AnnotationEditingSelectionInformation to different window."); CaretAssertMessage(0, msg); CaretLogSevere(msg); m_annotations.clear(); } } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void AnnotationEditingSelectionInformation::copyHelperAnnotationSelectionInformation(const AnnotationEditingSelectionInformation& obj) { CaretAssertMessage(0, "Copying not allowed"); m_annotations = obj.m_annotations; } /** * */ void AnnotationEditingSelectionInformation::clear() { m_annotations.clear(); m_annotationGroupKeys.clear(); m_groupingValid = false; m_regroupValid = false; m_ungroupValid = false; } /** * @return Index of window in which annotations are selected. */ int32_t AnnotationEditingSelectionInformation::getWindowIndex() const { return m_windowIndex; } /** * Update the selected annotations. If any of the given annotations * are in a 'user' annotation group, all annotations in the 'user' * annotation group are selected. * * @param annotation. */ void AnnotationEditingSelectionInformation::update(const std::vector& selectedAnnotations) { clear(); m_annotations = selectedAnnotations; bool allAnnotationsGroupableFlag = false; std::set groupKeysSet; if ( ! m_annotations.empty()) { allAnnotationsGroupableFlag = true; for (auto ann : m_annotations) { if (ann->testProperty(Annotation::Property::GROUP)) { groupKeysSet.insert(ann->getAnnotationGroupKey()); } else { allAnnotationsGroupableFlag = false; } } } // std::set groupSet; // for (std::vector::iterator annIter = m_annotations.begin(); // annIter != m_annotations.end(); // annIter++) { // const AnnotationGroup* annGroup = (*annIter)->getAnnotationGroup(); // CaretAssert(annGroup); // groupSet.insert(annGroup); // } if (allAnnotationsGroupableFlag) { m_annotationGroupKeys.insert(m_annotationGroupKeys.end(), groupKeysSet.begin(), groupKeysSet.end()); } const int32_t numGroups = static_cast(m_annotationGroupKeys.size()); /* * Are TWO or more annotations selected */ if (m_annotations.size() > 1) { if (numGroups == 1) { CaretAssertVectorIndex(m_annotationGroupKeys, 0); const AnnotationGroupKey& groupKey = m_annotationGroupKeys[0]; switch (groupKey.getGroupType()) { case AnnotationGroupTypeEnum::INVALID: break; case AnnotationGroupTypeEnum::SPACE: /* * All annotations in a space group, allow creating a user group */ m_groupingValid = true; break; case AnnotationGroupTypeEnum::USER: /* * All annotations in a user group, allow ungrouping to a space group */ m_ungroupValid = true; break; } } } /* * Is ANY annotation selected */ if (m_annotations.size() > 0) { /* * If all annotations are in a space group and were * in the same previous user group, enable regroup. */ if (numGroups == 1) { CaretAssertVectorIndex(m_annotationGroupKeys, 0); const AnnotationGroupKey& groupKey = m_annotationGroupKeys[0]; switch (groupKey.getGroupType()) { case AnnotationGroupTypeEnum::INVALID: break; case AnnotationGroupTypeEnum::SPACE: /* * The current group type is a 'space' group but * the annotation(s) were previously in a 'user' * group so enable 'regroup'. */ if (groupKey.getUserGroupUniqueKey() > 0) { m_regroupValid = true; } break; case AnnotationGroupTypeEnum::USER: break; } } } } /** * @return Vector containing the selected annotation group keys. */ std::vector AnnotationEditingSelectionInformation::getSelectedAnnotationGroupKeys() const { return m_annotationGroupKeys; } /** * @return Number of annotations selected. */ int32_t AnnotationEditingSelectionInformation::getNumberOfSelectedAnnotations() const { return m_annotations.size(); } /** * @return True if any annotations are selected. */ bool AnnotationEditingSelectionInformation::isAnyAnnotationSelected() const { return ( ! m_annotations.empty()); } /** * @return Vector containing the selected annotations. */ std::vector AnnotationEditingSelectionInformation::getAnnotationsSelectedForEditing() const { return m_annotations; } /** * Get the selected annotations. * * @param annotationsOut * Output containing the selected anntotations. */ void AnnotationEditingSelectionInformation::getAnnotationsSelectedForEditing(std::vector& annotationsOut) const { annotationsOut = m_annotations; } /** * Is the given grouping mode valid? * * @param groupingMode * The grouping mode. * @return * True if the grouping mode is valid, else false. */ bool AnnotationEditingSelectionInformation::isGroupingModeValid(const AnnotationGroupingModeEnum::Enum groupingMode) const { bool valid = false; switch (groupingMode) { case AnnotationGroupingModeEnum::GROUP: valid = m_groupingValid; break; case AnnotationGroupingModeEnum::REGROUP: valid = m_regroupValid; break; case AnnotationGroupingModeEnum::UNGROUP: valid = m_ungroupValid; break; } return valid; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString AnnotationEditingSelectionInformation::toString() const { return "AnnotationEditingSelectionInformation"; } connectome-workbench-1.4.2/src/Annotations/AnnotationEditingSelectionInformation.h000066400000000000000000000056071360521144700305720ustar00rootroot00000000000000#ifndef __ANNOTATION_SELECTION_INFORMATION_H__ #define __ANNOTATION_SELECTION_INFORMATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationGroupKey.h" #include "AnnotationGroupingModeEnum.h" #include "CaretObject.h" namespace caret { class Annotation; class AnnotationEditingSelectionInformation : public CaretObject { public: AnnotationEditingSelectionInformation(const int32_t windowIndex); virtual ~AnnotationEditingSelectionInformation(); void clear(); void update(const std::vector& selectedAnnotations); int32_t getWindowIndex() const; std::vector getSelectedAnnotationGroupKeys() const; int32_t getNumberOfSelectedAnnotations() const; bool isAnyAnnotationSelected() const; std::vector getAnnotationsSelectedForEditing() const; void getAnnotationsSelectedForEditing(std::vector& annotationsOut) const; bool isGroupingModeValid(const AnnotationGroupingModeEnum::Enum groupingMode) const; // ADD_NEW_METHODS_HERE virtual AString toString() const; private: AnnotationEditingSelectionInformation(const AnnotationEditingSelectionInformation& obj); AnnotationEditingSelectionInformation& operator=(const AnnotationEditingSelectionInformation& obj); void copyHelperAnnotationSelectionInformation(const AnnotationEditingSelectionInformation& obj); const int32_t m_windowIndex; std::vector m_annotationGroupKeys; std::vector m_annotations; bool m_groupingValid; bool m_ungroupValid; bool m_regroupValid; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_SELECTION_INFORMATION_DECLARE__ // #endif // __ANNOTATION_SELECTION_INFORMATION_DECLARE__ } // namespace #endif //__ANNOTATION_SELECTION_INFORMATION_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationFontAttributesInterface.h000066400000000000000000000062711360521144700277270ustar00rootroot00000000000000#ifndef __ANNOTATION_FONT_STYLE_INTERFACE_H__ #define __ANNOTATION_FONT_STYLE_INTERFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationTextFontNameEnum.h" #include "CaretColorEnum.h" namespace caret { class AnnotationFontAttributesInterface { public: AnnotationFontAttributesInterface() { } virtual ~AnnotationFontAttributesInterface() { } virtual AnnotationTextFontNameEnum::Enum getFont() const = 0; virtual void setFont(const AnnotationTextFontNameEnum::Enum font) = 0; virtual float getFontPercentViewportSize() const = 0; virtual void setFontPercentViewportSize(const float fontPercentViewportHeight) = 0; virtual CaretColorEnum::Enum getTextColor() const = 0; virtual void setTextColor(const CaretColorEnum::Enum color) = 0; virtual void getTextColorRGBA(float rgbaOut[4]) const = 0; virtual void getTextColorRGBA(uint8_t rgbaOut[4]) const = 0; virtual void getCustomTextColor(float rgbaOut[4]) const = 0; virtual void getCustomTextColor(uint8_t rgbaOut[4]) const = 0; virtual void setCustomTextColor(const float rgba[4]) = 0; virtual void setCustomTextColor(const uint8_t rgba[4]) = 0; virtual bool isBoldStyleEnabled() const = 0; virtual void setBoldStyleEnabled(const bool enabled) = 0; virtual bool isItalicStyleEnabled() const = 0; virtual void setItalicStyleEnabled(const bool enabled) = 0; virtual bool isUnderlineStyleEnabled() const = 0; virtual void setUnderlineStyleEnabled(const bool enabled) = 0; virtual bool isFontTooSmallWhenLastDrawn() const = 0; virtual void setFontTooSmallWhenLastDrawn(const bool tooSmallFontFlag) const = 0; // ADD_NEW_METHODS_HERE private: AnnotationFontAttributesInterface(const AnnotationFontAttributesInterface&); AnnotationFontAttributesInterface& operator=(const AnnotationFontAttributesInterface&); // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_FONT_STYLE_INTERFACE_DECLARE__ // #endif // __ANNOTATION_FONT_STYLE_INTERFACE_DECLARE__ } // namespace #endif //__ANNOTATION_FONT_STYLE_INTERFACE_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationGroup.cxx000066400000000000000000000742441360521144700246050ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_GROUP_DECLARE__ #include "AnnotationGroup.h" #undef __ANNOTATION_GROUP_DECLARE__ #include "Annotation.h" #include "AnnotationPointSizeText.h" #include "BrainConstants.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "DisplayGroupAndTabItemHelper.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::AnnotationGroup * \brief Contains a group of annotations. * \ingroup Annotations */ /** * Constructor. * * @param annotationFile * File to which this group belongs. * @param groupType * Type of annotation group. * @param uniqueKey * Unique key for this group. * @param coordinateSpace * Annotation coordinate space for the group. * @param tabOrWindowIndex * Index of tab or window for tab or window space. * @param spacerTabIndex * Index of a spacer tab. */ AnnotationGroup::AnnotationGroup(AnnotationFile* annotationFile, const AnnotationGroupTypeEnum::Enum groupType, const int32_t uniqueKey, const AnnotationCoordinateSpaceEnum::Enum coordinateSpace, const int32_t tabOrWindowIndex, const SpacerTabIndex& spacerTabIndex) : CaretObjectTracksModification(), DisplayGroupAndTabItemInterface(), SceneableInterface() { CaretAssert(annotationFile); CaretAssert(groupType != AnnotationGroupTypeEnum::INVALID); CaretAssert(uniqueKey > 0); CaretAssert(coordinateSpace != AnnotationCoordinateSpaceEnum::VIEWPORT); initializeInstance(); m_groupKey.setAnnotationFile(annotationFile); m_groupKey.setGroupType(groupType); switch (groupType) { case AnnotationGroupTypeEnum::INVALID: CaretAssertMessage(0, "Should never get here"); break; case AnnotationGroupTypeEnum::SPACE: m_groupKey.setSpaceGroupUniqueKey(uniqueKey); break; case AnnotationGroupTypeEnum::USER: m_groupKey.setUserGroupUniqueKey(uniqueKey); break; } m_coordinateSpace = coordinateSpace; m_tabOrWindowIndex = tabOrWindowIndex; m_spacerTabIndex = spacerTabIndex; switch (m_coordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: CaretAssert(m_spacerTabIndex.isValid()); break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: CaretAssert((tabOrWindowIndex >= 0) && (tabOrWindowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)); break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: CaretAssert((tabOrWindowIndex >= 0) && (tabOrWindowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)); break; } setModified(); } /** * Destructor. */ AnnotationGroup::~AnnotationGroup() { m_annotations.clear(); delete m_displayGroupAndTabItemHelper; delete m_sceneAssistant; } /** * Copy constructor. * @param obj * Object that is copied. */ AnnotationGroup::AnnotationGroup(const AnnotationGroup& obj) : CaretObjectTracksModification(obj), DisplayGroupAndTabItemInterface(obj), SceneableInterface(obj) { initializeInstance(); this->copyHelperAnnotationGroup(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ AnnotationGroup& AnnotationGroup::operator=(const AnnotationGroup& obj) { if (this != &obj) { CaretObjectTracksModification::operator=(obj); this->copyHelperAnnotationGroup(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void AnnotationGroup::copyHelperAnnotationGroup(const AnnotationGroup& obj) { m_groupKey = obj.m_groupKey; m_coordinateSpace = obj.m_coordinateSpace; m_name = obj.m_name; m_tabOrWindowIndex = obj.m_tabOrWindowIndex; m_spacerTabIndex = obj.m_spacerTabIndex; *m_displayGroupAndTabItemHelper = *obj.m_displayGroupAndTabItemHelper; CaretAssertMessage(0, "What to do with annotations remove copy constructor/operator="); } /** * Initialize an instance. */ void AnnotationGroup::initializeInstance() { m_groupKey.reset(); m_coordinateSpace = AnnotationCoordinateSpaceEnum::VIEWPORT; m_name = ""; m_tabOrWindowIndex = -1; m_spacerTabIndex = SpacerTabIndex(); m_displayGroupAndTabItemHelper = new DisplayGroupAndTabItemHelper(); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_displayGroupAndTabItemHelper", "DisplayGroupAndTabItemHelper", m_displayGroupAndTabItemHelper); } /** * @return Is this group valid? */ bool AnnotationGroup::isEmpty() const { return (m_annotations.empty()); } /** * @return The annotation group key. */ AnnotationGroupKey AnnotationGroup::getAnnotationGroupKey() const { return m_groupKey; } /** * @return Annotation file that contains this group. */ AnnotationFile* AnnotationGroup::getAnnotationFile() const { return m_groupKey.getAnnotationFile(); } /** * @return The group type. */ AnnotationGroupTypeEnum::Enum AnnotationGroup::getGroupType() const { return m_groupKey.getGroupType(); } /** * @return Coordinate space of the annotations. */ AnnotationCoordinateSpaceEnum::Enum AnnotationGroup::getCoordinateSpace() const { return m_coordinateSpace; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString AnnotationGroup::toString() const { return "AnnotationGroup"; } /** * @return Name of the annotation group. */ AString AnnotationGroup::getName() const { if (m_name.isEmpty()) { AString spaceName = AnnotationCoordinateSpaceEnum::toGuiName(m_coordinateSpace); switch (m_coordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: spaceName.append(" " + m_spacerTabIndex.getWindowRowColumnGuiText()); break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: spaceName.append(" " + AString::number(getTabOrWindowIndex() + 1)); break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssertMessage(0, "Should never be viewport"); break; case AnnotationCoordinateSpaceEnum::WINDOW: spaceName.append(" " + AString::number(getTabOrWindowIndex() + 1)); break; } switch (m_groupKey.getGroupType()) { case AnnotationGroupTypeEnum::INVALID: CaretAssertMessage(0, "Should never get here"); break; case AnnotationGroupTypeEnum::SPACE: // m_name.append("Space Group: " // + spaceName); m_name.append(spaceName); break; case AnnotationGroupTypeEnum::USER: // m_name.append("User Group " // + AString::number(m_groupKey.getUserGroupUniqueKey()) // + ": " // + spaceName); m_name.append("Group " + AString::number(m_groupKey.getUserGroupUniqueKey()) + ": " + spaceName); break; } } return m_name; } /** * @return Index or tab or window for tab or window space. */ int32_t AnnotationGroup::getTabOrWindowIndex() const { return m_tabOrWindowIndex; } /** * Index of a spacer tab. */ SpacerTabIndex AnnotationGroup::getSpacerTabIndex() const { return m_spacerTabIndex; } /** * @return Unique key displayed in annotation group name. */ int32_t AnnotationGroup::getUniqueKey() const { int32_t uniqueKey = -1; switch (m_groupKey.getGroupType()) { case AnnotationGroupTypeEnum::INVALID: CaretAssertMessage(0, "Should never get here"); break; case AnnotationGroupTypeEnum::SPACE: uniqueKey = m_groupKey.getSpaceGroupUniqueKey(); break; case AnnotationGroupTypeEnum::USER: uniqueKey = m_groupKey.getUserGroupUniqueKey(); break; } return uniqueKey; } /** * Private method for adding annotations to this file. * * In the GUI, annotations are added using the AnnotationRedoUndoCommand * which allows undo/redo operations. * * @param annotation * Annotation that is added. */ void AnnotationGroup::addAnnotationPrivate(Annotation* annotation) { if ( ! validateAddedAnnotation(annotation)) { delete annotation; return; } assignGroupKeyToAnnotation(annotation); m_annotations.push_back(QSharedPointer(annotation)); setModified(); } /** * Private method for adding annotations to this file using shared pointer. * * In the GUI, annotations are added using the AnnotationRedoUndoCommand * which allows undo/redo operations. * * @param annotation * Annotation that is added. */ void AnnotationGroup::addAnnotationPrivateSharedPointer(QSharedPointer& annotation) { if ( ! validateAddedAnnotation(annotation.data())) { return; } assignGroupKeyToAnnotation(annotation.data()); m_annotations.push_back(annotation); setModified(); } /** * Assign group key for the given annotation. * * @param annotation * The annotation. */ void AnnotationGroup::assignGroupKeyToAnnotation(Annotation* annotation) { annotation->setAnnotationGroupKey(m_groupKey); annotation->setItemParent(this); } /** * Validate the annotation that is being added to this group. * * @param annotation * Pointer to annotation. * @return * True if the annotation is compatible with this group. */ bool AnnotationGroup::validateAddedAnnotation(const Annotation* annotation) { if (annotation->getType() == AnnotationTypeEnum::TEXT) { const AnnotationPointSizeText* pointSizeAnnotation = dynamic_cast(annotation); if (pointSizeAnnotation != NULL) { CaretLogWarning("Point size text annotations are not supported in AnnotationGroup. " "The annotation has been discarded."); return false; } } const AnnotationCoordinateSpaceEnum::Enum space = annotation->getCoordinateSpace(); if (space != m_coordinateSpace) { CaretLogSevere("Attempting to add annotation with non-matching coordinate space"); CaretAssert(0); return false; } switch (space) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: if (m_spacerTabIndex != annotation->getSpacerTabIndex()) { CaretLogSevere("Attempting to add anntation with non-matching spacer tab index"); CaretAssert(0); return false; } break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: if (m_tabOrWindowIndex != annotation->getTabIndex()) { CaretLogSevere("Attempting to add anntation with non-matching tab index: "); CaretAssert(0); return false; } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: if (m_tabOrWindowIndex != annotation->getWindowIndex()) { CaretLogSevere("Attempting to add anntation with non-matching tab index: "); CaretAssert(0); return false; } break; } return true; } /** * @return The maximum unique key found in this group and * its annotations. */ int32_t AnnotationGroup::getMaximumUniqueKey() const { int32_t maxUniqueKey = getUniqueKey(); for (AnnotationConstIterator iter = m_annotations.begin(); iter != m_annotations.end(); iter++) { maxUniqueKey = std::max(maxUniqueKey, (*iter)->getUniqueKey()); } return maxUniqueKey; } /** * Remove all annotations from this group. * * @param allRemovedAnnotationsOut * Output containing all annotations from this group. */ void AnnotationGroup::removeAllAnnotations(std::vector >& allRemovedAnnotationsOut) { allRemovedAnnotationsOut = m_annotations; m_annotations.clear(); setModified(); } /** * Remove the annotation. NOTE: The annotation is NOT deleted * but instead it is returned so that it can be 'undeleted' * or 're-pasted'. * * @param annotation * Annotation that is removed. * @param removedAnnotationOut * Shared pointer for annotation that was removed so * the file can later undelete the annotation. Only * valid when true is returned. * @return * True if the annotation was removed, otherwise false. */ bool AnnotationGroup::removeAnnotation(Annotation* annotation, QSharedPointer& removedAnnotationOut) { removedAnnotationOut.clear(); for (AnnotationIterator iter = m_annotations.begin(); iter != m_annotations.end(); iter++) { QSharedPointer& annotationPointer = *iter; if (annotationPointer == annotation) { annotation->setItemParent(NULL); removedAnnotationOut = annotationPointer; m_annotations.erase(iter); setModified(); /* * Successfully removed */ return true; } } /* * Annotation not in this file */ return false; } /** * @return Number of annotations in this group. */ int32_t AnnotationGroup::getNumberOfAnnotations() const { return m_annotations.size(); } /** * @param index * Get the annotation at the given index. * @return * Annotation at the given index. */ Annotation* AnnotationGroup::getAnnotation(const int32_t index) { CaretAssertVectorIndex(m_annotations, index); return m_annotations[index].data(); } /** * Are all of the given annotations in this group? * * @param annotations * Annotations tested for membership in this group. * @return * True if all of the annotations are in this group. * False if (a) not all annotations are in this group; * or if (b) the annotations are empty * or if (c) this group contains no annotations. */ bool AnnotationGroup::containsAllAnnotation(const std::vector annotations) const { if (annotations.empty()) { return false; } if (m_annotations.empty()) { return false; } for (std::vector::const_iterator annIter = annotations.begin(); annIter != annotations.end(); annIter++) { CaretAssert(*annIter); if ( ! containsAnnotation(*annIter)) { return false; } } return true; } /** * Is the given annotation in this group. * * @param annotation * Annotation tested for membership in this group. * @return * True if annotation is in this group, else false. */ bool AnnotationGroup::containsAnnotation(const Annotation* annotation) const { CaretAssert(annotation); for (AnnotationConstIterator annIter = m_annotations.begin(); annIter != m_annotations.end(); annIter++) { if (annotation == (*annIter).data()) { return true; } } return false; } /** * @param index * Get the annotation at the given index. * @return * Annotation at the given index. */ const Annotation* AnnotationGroup::getAnnotation(const int32_t index) const { CaretAssertVectorIndex(m_annotations, index); return m_annotations[index].data(); } /** * Get all annotations in this group. * * @param annotationsOut * Output containing all annotations. */ void AnnotationGroup::getAllAnnotations(std::vector& annotationsOut) const { annotationsOut.clear(); for (AnnotationConstIterator iter = m_annotations.begin(); iter != m_annotations.end(); iter++) { annotationsOut.push_back((*iter).data()); } } /** * Set the selection for editing status for all annotations in this group * in the given window. * * @param windowIndex * Index of window. * @param selectedStatus * The selection status. */ void AnnotationGroup::setAllAnnotationsSelectedForEditing(const int32_t windowIndex, const bool selectedStatus) { for (AnnotationIterator iter = m_annotations.begin(); iter != m_annotations.end(); iter++) { (*iter)->setSelectedForEditing(windowIndex, selectedStatus); } } /** * @return true if file is modified, else false. */ bool AnnotationGroup::isModified() const { for (AnnotationConstIterator iter = m_annotations.begin(); iter != m_annotations.end(); iter++) { const QSharedPointer& annotationPointer = *iter; if (annotationPointer->isModified()) { return true; } } return false; } /** * Clear the modified status of this file. */ void AnnotationGroup::clearModified() { for (AnnotationIterator iter = m_annotations.begin(); iter != m_annotations.end(); iter++) { (*iter)->clearModified(); } } /** * @return name for an annotation saved to scene. * * @param uniqueKey * Unique key of the annotation in the file. */ AString AnnotationGroup::getSceneClassNameForAnnotationUniqueKey(const int32_t uniqueKey) { return ("Ann-" + AString::number(uniqueKey)); } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* AnnotationGroup::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "AnnotationGroup", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); const int32_t annCount = getNumberOfAnnotations(); for (int32_t i = 0; i < annCount; i++) { const int32_t uniqueKey = getAnnotation(i)->getUniqueKey(); SceneClass* annClass = getAnnotation(i)->saveToScene(sceneAttributes, getSceneClassNameForAnnotationUniqueKey(uniqueKey)); sceneClass->addClass(annClass); } // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void AnnotationGroup::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); const int32_t annCount = getNumberOfAnnotations(); for (int32_t i = 0; i < annCount; i++) { const int32_t uniqueKey = getAnnotation(i)->getUniqueKey(); const SceneClass* annClass = sceneClass->getClass(getSceneClassNameForAnnotationUniqueKey(uniqueKey)); if (sceneClass != NULL) { getAnnotation(i)->restoreFromScene(sceneAttributes, annClass); } } //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } /** * @return Number of children. */ int32_t AnnotationGroup::getNumberOfItemChildren() const { return m_annotations.size(); } /** * Get child at the given index. * * @param index * Index of the child. * @return * Child at the given index. */ DisplayGroupAndTabItemInterface* AnnotationGroup::getItemChild(const int32_t index) const { CaretAssertVectorIndex(m_annotations, index); return m_annotations[index].data(); } /** * @return Children of this item. */ std::vector AnnotationGroup::getItemChildren() const { std::vector children; for (AnnotationConstIterator annIter = m_annotations.begin(); annIter != m_annotations.end(); annIter++) { children.push_back((*annIter).data()); } return children; } /** * @return Parent of this item. */ DisplayGroupAndTabItemInterface* AnnotationGroup::getItemParent() const { return m_displayGroupAndTabItemHelper->getParent(); } /** * Set the parent of this item. * * @param itemParent * Parent of this item. */ void AnnotationGroup::setItemParent(DisplayGroupAndTabItemInterface* itemParent) { m_displayGroupAndTabItemHelper->setParent(itemParent); } /** * @return Name of this item. */ AString AnnotationGroup::getItemName() const { return getName(); } /** * Get the icon color for this item. Icon is filled with background * color, outline color is drawn around edges, and text color is small * square in center. For any colors that do not apply, use an alpha * value (last element) of zero. * * @param backgroundRgbaOut * Red, green, blue, alpha components for background ranging [0, 1]. * @param outlineRgbaOut * Red, green, blue, alpha components for outline ranging [0, 1]. * @param textRgbaOut * Red, green, blue, alpha components for text ranging [0, 1]. */ void AnnotationGroup::getItemIconColorsRGBA(float backgroundRgbaOut[4], float outlineRgbaOut[4], float textRgbaOut[4]) const { backgroundRgbaOut[0] = 0.0; backgroundRgbaOut[1] = 0.0; backgroundRgbaOut[2] = 0.0; backgroundRgbaOut[3] = 0.0; outlineRgbaOut[0] = 0.0; outlineRgbaOut[1] = 0.0; outlineRgbaOut[2] = 0.0; outlineRgbaOut[3] = 0.0; textRgbaOut[0] = 0.0; textRgbaOut[1] = 0.0; textRgbaOut[2] = 0.0; textRgbaOut[3] = 0.0; } /** * @return This item can be expanded. */ bool AnnotationGroup::isItemExpandable() const { return true; } /** * @return Is this item expanded in the given display group/tab? * * @param displayGroup * The display group. * @param tabIndexIn * Index of the tab. */ bool AnnotationGroup::isItemExpanded(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndexIn) const { if (m_coordinateSpace == AnnotationCoordinateSpaceEnum::WINDOW) { return m_displayGroupAndTabItemHelper->isExpandedInWindow(m_tabOrWindowIndex); } const int32_t tabIndex = updateDisplayGroupTabIndex(displayGroup, tabIndexIn); return m_displayGroupAndTabItemHelper->isExpanded(displayGroup, tabIndex); } /** * Set this item's expanded status in the given display group/tab. * * @param displayGroup * The display group. * @param tabIndexIn * Index of the tab. * @param status * New expanded status. */ void AnnotationGroup::setItemExpanded(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndexIn, const bool status) { if (m_coordinateSpace == AnnotationCoordinateSpaceEnum::WINDOW) { m_displayGroupAndTabItemHelper->setExpandedInWindow(m_tabOrWindowIndex, status); } else { const int32_t tabIndex = updateDisplayGroupTabIndex(displayGroup, tabIndexIn); m_displayGroupAndTabItemHelper->setExpanded(displayGroup, tabIndex, status); } } /** * Get display selection status in the given display group/tab? * * @param displayGroup * The display group. * @param tabIndexIn * Index of the tab. */ TriStateSelectionStatusEnum::Enum AnnotationGroup::getItemDisplaySelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndexIn) const { const int32_t tabIndex = updateDisplayGroupTabIndex(displayGroup, tabIndexIn); TriStateSelectionStatusEnum::Enum status = TriStateSelectionStatusEnum::UNSELECTED; const int numChildren = getNumberOfAnnotations(); if (numChildren > 0) { int32_t selectedCount = 0; for (int32_t i = 0; i < numChildren; i++) { CaretAssertVectorIndex(m_annotations, i); switch (m_annotations[i]->getItemDisplaySelected(displayGroup, tabIndex)) { case TriStateSelectionStatusEnum::PARTIALLY_SELECTED: CaretAssertMessage(0, "Annotation should never be partially selected."); break; case TriStateSelectionStatusEnum::SELECTED: selectedCount++; break; case TriStateSelectionStatusEnum::UNSELECTED: break; } } if (selectedCount == numChildren) { status = TriStateSelectionStatusEnum::SELECTED; } else if (selectedCount > 0) { status = TriStateSelectionStatusEnum::PARTIALLY_SELECTED; } } return status; } /** * Set display this item selected in the given display group/tab. * * @param displayGroup * The display group. * @param tabIndexIn * Index of the tab. * @param status * New selection status. */ void AnnotationGroup::setItemDisplaySelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndexIn, const TriStateSelectionStatusEnum::Enum status) { switch (status) { case TriStateSelectionStatusEnum::PARTIALLY_SELECTED: CaretAssertMessage(0, "Annotation group should never be set to partially selected."); return; break; case TriStateSelectionStatusEnum::SELECTED: break; case TriStateSelectionStatusEnum::UNSELECTED: break; } const int32_t tabIndex = updateDisplayGroupTabIndex(displayGroup, tabIndexIn); /* * Note: An annotation group's selection status is based * of the the group's annotations so we do not need to set * an explicit selection status for the group. */ DisplayGroupAndTabItemInterface::setChildrenDisplaySelectedHelper(this, displayGroup, tabIndex, status); } /** * Update the tab index to correspond to the tab index used for this * annotation group if it is in tab annotation space. This functionality * was added to resolve WB-831. * * @param displayGroup * The display group. * @param tabIndex * Index of the tab. */ int32_t AnnotationGroup::updateDisplayGroupTabIndex(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { int32_t tabIndexOut(tabIndex); if (getCoordinateSpace() == AnnotationCoordinateSpaceEnum::TAB) { if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { tabIndexOut = getTabOrWindowIndex(); } } return tabIndexOut; } /** * Is this item selected for editing in the given window? * * @param windowIndex * Index of the window. * @return * Selection status. */ bool AnnotationGroup::isItemSelectedForEditingInWindow(const int32_t /*windowIndex*/) { return false; } connectome-workbench-1.4.2/src/Annotations/AnnotationGroup.h000066400000000000000000000172271360521144700242300ustar00rootroot00000000000000#ifndef __ANNOTATION_GROUP_H__ #define __ANNOTATION_GROUP_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AnnotationCoordinateSpaceEnum.h" #include "AnnotationGroupKey.h" #include "CaretObjectTracksModification.h" #include "DisplayGroupAndTabItemInterface.h" #include "SceneableInterface.h" #include "SpacerTabIndex.h" namespace caret { class Annotation; class DisplayGroupAndTabItemHelper; class SceneClassAssistant; class AnnotationGroup : public CaretObjectTracksModification, public DisplayGroupAndTabItemInterface, public SceneableInterface { public: AnnotationGroup(AnnotationFile* annotationFile, const AnnotationGroupTypeEnum::Enum groupType, const int32_t uniqueKey, const AnnotationCoordinateSpaceEnum::Enum coordinateSpace, const int32_t tabOrWindowIndex, const SpacerTabIndex& spacerTabIndex); virtual ~AnnotationGroup(); bool isEmpty() const; int32_t getUniqueKey() const; AString getName() const; AnnotationGroupKey getAnnotationGroupKey() const; AnnotationFile* getAnnotationFile() const; AnnotationGroupTypeEnum::Enum getGroupType() const; AnnotationCoordinateSpaceEnum::Enum getCoordinateSpace() const; int32_t getTabOrWindowIndex() const; SpacerTabIndex getSpacerTabIndex() const; int32_t getNumberOfAnnotations() const; Annotation* getAnnotation(const int32_t index); const Annotation* getAnnotation(const int32_t index) const; void getAllAnnotations(std::vector& annotationsOut) const; bool containsAnnotation(const Annotation* annotation) const; bool containsAllAnnotation(const std::vector annotations) const; void setAllAnnotationsSelectedForEditing(const int32_t windowIndex, const bool selectedStatus); bool isModified() const; void clearModified(); // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); virtual int32_t getNumberOfItemChildren() const; virtual DisplayGroupAndTabItemInterface* getItemChild(const int32_t index) const; virtual std::vector getItemChildren() const; virtual DisplayGroupAndTabItemInterface* getItemParent() const; virtual void setItemParent(DisplayGroupAndTabItemInterface* itemParent); virtual AString getItemName() const; virtual void getItemIconColorsRGBA(float backgroundRgbaOut[4], float outlineRgbaOut[4], float textRgbaOut[4]) const; virtual bool isItemExpandable() const; virtual bool isItemExpanded(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; virtual void setItemExpanded(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool status); virtual TriStateSelectionStatusEnum::Enum getItemDisplaySelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; virtual void setItemDisplaySelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const TriStateSelectionStatusEnum::Enum status); virtual bool isItemSelectedForEditingInWindow(const int32_t windowIndex); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implementation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: AnnotationGroup(const AnnotationGroup& obj); AnnotationGroup& operator=(const AnnotationGroup& obj); void copyHelperAnnotationGroup(const AnnotationGroup& obj); void addAnnotationPrivate(Annotation* annotation); void addAnnotationPrivateSharedPointer(QSharedPointer& annotation); void assignGroupKeyToAnnotation(Annotation* annotation); bool validateAddedAnnotation(const Annotation* annotation); bool removeAnnotation(Annotation* annotation, QSharedPointer& removedAnnotationOut); void removeAllAnnotations(std::vector >& allRemovedAnnotationsOut); int32_t getMaximumUniqueKey() const; void initializeInstance(); int32_t updateDisplayGroupTabIndex(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; SceneClassAssistant* m_sceneAssistant; DisplayGroupAndTabItemHelper* m_displayGroupAndTabItemHelper; AnnotationGroupKey m_groupKey; AnnotationCoordinateSpaceEnum::Enum m_coordinateSpace; SpacerTabIndex m_spacerTabIndex; int32_t m_tabOrWindowIndex; mutable AString m_name; std::vector > m_annotations; typedef std::vector >::iterator AnnotationIterator; typedef std::vector >::const_iterator AnnotationConstIterator; static AString getSceneClassNameForAnnotationUniqueKey(const int32_t uniqueKey); // ADD_NEW_MEMBERS_HERE friend class AnnotationFile; friend class AnnotationFileXmlReader; friend class AnnotationFileXmlWriter; }; #ifdef __ANNOTATION_GROUP_DECLARE__ // #endif // __ANNOTATION_GROUP_DECLARE__ } // namespace #endif //__ANNOTATION_GROUP_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationGroupKey.cxx000066400000000000000000000175361360521144700252570ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_GROUP_KEY_DECLARE__ #include "AnnotationGroupKey.h" #undef __ANNOTATION_GROUP_KEY_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationGroupKey * \brief This class is a "key" for an annotation group. * \ingroup Annotations * * This class is a member of each annotation and tracks the * group to which the annotation belongs. * * There are two types of annotation groups: 'Space' and 'User'. * By default, annotations are assigned to a 'Space' group when * added to an annotation file. In an annotation file, there * is one group for each space (stereotaxic, surface, each tab, * and each window). A user may create 'User' groups to group * annotation that are in the same space. * * Creating a user group: * - The group type is set to USER. * - The user group unique key is set to the key in the user group. * - The space key is invalidate. * * Ungrouping a user group: * - The group type is set to SPACE. * - The space group unique key is set to the key in the space group. * - The user group unique is not changed. It is used by a regroup operation. * * Regrouping a user group: * - The group type is changed to USER. * - A user group is created with the user group unique key and all annotations * that have the user group unique key are added to the user group. */ /** * Constructor. */ AnnotationGroupKey::AnnotationGroupKey() : CaretObject(), m_annotationFile(NULL), m_groupType(AnnotationGroupTypeEnum::INVALID), m_spaceGroupUniqueKey(-1), m_userGroupUniqueKey(-1) { reset(); } /** * Destructor. */ AnnotationGroupKey::~AnnotationGroupKey() { } /** * Copy constructor. * @param obj * Object that is copied. */ AnnotationGroupKey::AnnotationGroupKey(const AnnotationGroupKey& obj) : CaretObject(obj) { this->copyHelperAnnotationGroupKey(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ AnnotationGroupKey& AnnotationGroupKey::operator=(const AnnotationGroupKey& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperAnnotationGroupKey(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void AnnotationGroupKey::copyHelperAnnotationGroupKey(const AnnotationGroupKey& obj) { m_annotationFile = obj.m_annotationFile; m_groupType = obj.m_groupType; m_spaceGroupUniqueKey = obj.m_spaceGroupUniqueKey; m_userGroupUniqueKey = obj.m_userGroupUniqueKey; } /** * Reset an instance to invalid. */ void AnnotationGroupKey::reset() { m_annotationFile = NULL; m_groupType = AnnotationGroupTypeEnum::INVALID; m_spaceGroupUniqueKey = -1; m_userGroupUniqueKey = -1; } /** * Equality operator. Equal if annotation file is equal AND * either the group type is space and the space unique keys are * equal or the group type is user and the user unique keys are * equal. * * @param groupKey * The group key that is tested for equality. * @return * True if these group keys are equal, else false. */ bool AnnotationGroupKey::operator==(const AnnotationGroupKey& groupKey) const { if (this == &groupKey) { return true; } if (m_annotationFile == groupKey.m_annotationFile) { if (m_groupType == groupKey.m_groupType) { switch (m_groupType) { case AnnotationGroupTypeEnum::INVALID: CaretAssertMessage(0, "Should never get here."); break; case AnnotationGroupTypeEnum::SPACE: if (m_spaceGroupUniqueKey == groupKey.m_spaceGroupUniqueKey) { return true; } break; case AnnotationGroupTypeEnum::USER: if (m_userGroupUniqueKey == groupKey.m_userGroupUniqueKey) { return true; } break; } } } return false; } /** * Less than operator. * * @param groupKey * The group key that is tested for equality. * @return * True if these group keys are equal, else false. */ bool AnnotationGroupKey::operator<(const AnnotationGroupKey& groupKey) const { if (this == &groupKey) { return false; } bool lessThanFlag = false; if (m_annotationFile == groupKey.m_annotationFile) { if (m_groupType == groupKey.m_groupType) { switch (m_groupType) { case AnnotationGroupTypeEnum::INVALID: CaretAssertMessage(0, "Should never get here."); lessThanFlag = false; break; case AnnotationGroupTypeEnum::SPACE: lessThanFlag = (m_spaceGroupUniqueKey < groupKey.m_spaceGroupUniqueKey); break; case AnnotationGroupTypeEnum::USER: lessThanFlag = (m_userGroupUniqueKey < groupKey.m_userGroupUniqueKey); break; } } else { lessThanFlag = (AnnotationGroupTypeEnum::toIntegerCode(m_groupType) < AnnotationGroupTypeEnum::toIntegerCode(groupKey.m_groupType)); } } else { lessThanFlag = (m_annotationFile < groupKey.m_annotationFile); } return lessThanFlag; } /** * @return The annotation file. */ AnnotationFile* AnnotationGroupKey::getAnnotationFile() const { return m_annotationFile; } /** * Set the annotation file. * * @param annotationFile * The annotation file. */ void AnnotationGroupKey::setAnnotationFile(AnnotationFile* annotationFile) { m_annotationFile = annotationFile; } /** * @return The group type. */ AnnotationGroupTypeEnum::Enum AnnotationGroupKey::getGroupType() const { return m_groupType; } /** * Set the group type. * * @param groupType * The group type. */ void AnnotationGroupKey::setGroupType(const AnnotationGroupTypeEnum::Enum groupType) { m_groupType = groupType; } /** * @return The space group unique key. */ int32_t AnnotationGroupKey::getSpaceGroupUniqueKey() const { return m_spaceGroupUniqueKey; } /** * Set the space group unique key. * * @param spaceGroupUniqueKey * The space group unique key. */ void AnnotationGroupKey::setSpaceGroupUniqueKey(const int32_t spaceGroupUniqueKey) { m_spaceGroupUniqueKey = spaceGroupUniqueKey; } /** * @return The user group unique key. */ int32_t AnnotationGroupKey::getUserGroupUniqueKey() const { return m_userGroupUniqueKey; } /** * Set the user group unique key. * * @param userGroupUniqueKey * The user group unique key. */ void AnnotationGroupKey::setUserGroupUniqueKey(const int32_t userGroupUniqueKey) { m_userGroupUniqueKey = userGroupUniqueKey; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString AnnotationGroupKey::toString() const { return "AnnotationGroupKey"; } connectome-workbench-1.4.2/src/Annotations/AnnotationGroupKey.h000066400000000000000000000054721360521144700247000ustar00rootroot00000000000000#ifndef __ANNOTATION_GROUP_KEY_H__ #define __ANNOTATION_GROUP_KEY_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationGroupTypeEnum.h" #include "CaretObject.h" namespace caret { class AnnotationFile; class AnnotationGroupKey : public CaretObject { public: AnnotationGroupKey(); virtual ~AnnotationGroupKey(); AnnotationGroupKey(const AnnotationGroupKey& obj); AnnotationGroupKey& operator=(const AnnotationGroupKey& obj); bool operator==(const AnnotationGroupKey& groupKey) const; bool operator<(const AnnotationGroupKey& groupKey) const; void reset(); AnnotationFile* getAnnotationFile() const; AnnotationGroupTypeEnum::Enum getGroupType() const; int32_t getSpaceGroupUniqueKey() const; int32_t getUserGroupUniqueKey() const; // ADD_NEW_METHODS_HERE virtual AString toString() const; private: void copyHelperAnnotationGroupKey(const AnnotationGroupKey& obj); /* set method private so that only friend classes can access them */ void setAnnotationFile(AnnotationFile* annotationFile); void setGroupType(const AnnotationGroupTypeEnum::Enum groupType); void setSpaceGroupUniqueKey(const int32_t spaceGroupUniqueKey); void setUserGroupUniqueKey(const int32_t userGroupUniqueKey); AnnotationFile* m_annotationFile; AnnotationGroupTypeEnum::Enum m_groupType; int32_t m_spaceGroupUniqueKey; int32_t m_userGroupUniqueKey; friend class Annotation; friend class AnnotationFile; friend class AnnotationGroup; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_GROUP_KEY_DECLARE__ // #endif // __ANNOTATION_GROUP_KEY_DECLARE__ } // namespace #endif //__ANNOTATION_GROUP_KEY_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationGroupTypeEnum.cxx000066400000000000000000000257151360521144700262730ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_GROUP_TYPE_ENUM_DECLARE__ #include "AnnotationGroupTypeEnum.h" #undef __ANNOTATION_GROUP_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationGroupTypeEnum * \brief Type of annotation group * * In an annotation file, each annotation is assigned to a group. * These groups may be created by the user or be 'space' groups. * For annotations not assigned to a user created annotation group, * the annotation, the file contains one group for each annotation * space. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_annotationGroupTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void annotationGroupTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "AnnotationGroupTypeEnum.h" * * Instatiate: * m_annotationGroupTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_annotationGroupTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_annotationGroupTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(annotationGroupTypeEnumComboBoxItemActivated())); * * Update the selection: * m_annotationGroupTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const AnnotationGroupTypeEnum::Enum VARIABLE = m_annotationGroupTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ AnnotationGroupTypeEnum::AnnotationGroupTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ AnnotationGroupTypeEnum::~AnnotationGroupTypeEnum() { } /** * Initialize the enumerated metadata. */ void AnnotationGroupTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(AnnotationGroupTypeEnum(INVALID, "INVALID", "Invalid")); enumData.push_back(AnnotationGroupTypeEnum(SPACE, "SPACE", "Space")); enumData.push_back(AnnotationGroupTypeEnum(USER, "USER", "User")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const AnnotationGroupTypeEnum* AnnotationGroupTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const AnnotationGroupTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationGroupTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationGroupTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationGroupTypeEnum::Enum AnnotationGroupTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationGroupTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationGroupTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type AnnotationGroupTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationGroupTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationGroupTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationGroupTypeEnum::Enum AnnotationGroupTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationGroupTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationGroupTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type AnnotationGroupTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t AnnotationGroupTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationGroupTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ AnnotationGroupTypeEnum::Enum AnnotationGroupTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationGroupTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationGroupTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type AnnotationGroupTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void AnnotationGroupTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationGroupTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(AnnotationGroupTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationGroupTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(AnnotationGroupTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Annotations/AnnotationGroupTypeEnum.h000066400000000000000000000063741360521144700257200ustar00rootroot00000000000000#ifndef __ANNOTATION_GROUP_TYPE_ENUM_H__ #define __ANNOTATION_GROUP_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class AnnotationGroupTypeEnum { public: /** * Enumerated values for type of annotation group */ enum Enum { /** Invalid*/ INVALID, /** Annotations not in a user group are assigned to a file's space groups */ SPACE, /** Annotation groups created by the user */ USER }; ~AnnotationGroupTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: AnnotationGroupTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const AnnotationGroupTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __ANNOTATION_GROUP_TYPE_ENUM_DECLARE__ std::vector AnnotationGroupTypeEnum::enumData; bool AnnotationGroupTypeEnum::initializedFlag = false; int32_t AnnotationGroupTypeEnum::integerCodeCounter = 0; #endif // __ANNOTATION_GROUP_TYPE_ENUM_DECLARE__ } // namespace #endif //__ANNOTATION_GROUP_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationGroupingModeEnum.cxx000066400000000000000000000256411360521144700267320ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_GROUPING_MODE_ENUM_DECLARE__ #include "AnnotationGroupingModeEnum.h" #undef __ANNOTATION_GROUPING_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationGroupingModeEnum * \brief Mode for creating, regrouping, and ungrouping annotations. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_annotationGroupingModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void annotationGroupingModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "AnnotationGroupingModeEnum.h" * * Instatiate: * m_annotationGroupingModeEnumComboBox = new EnumComboBoxTemplate(this); * m_annotationGroupingModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_annotationGroupingModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(annotationGroupingModeEnumComboBoxItemActivated())); * * Update the selection: * m_annotationGroupingModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const AnnotationGroupingModeEnum::Enum VARIABLE = m_annotationGroupingModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ AnnotationGroupingModeEnum::AnnotationGroupingModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ AnnotationGroupingModeEnum::~AnnotationGroupingModeEnum() { } /** * Initialize the enumerated metadata. */ void AnnotationGroupingModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(AnnotationGroupingModeEnum(GROUP, "GROUP", "Group")); enumData.push_back(AnnotationGroupingModeEnum(REGROUP, "REGROUP", "Regroup")); enumData.push_back(AnnotationGroupingModeEnum(UNGROUP, "UNGROUP", "Ungroup")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const AnnotationGroupingModeEnum* AnnotationGroupingModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const AnnotationGroupingModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationGroupingModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationGroupingModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationGroupingModeEnum::Enum AnnotationGroupingModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationGroupingModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationGroupingModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type AnnotationGroupingModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationGroupingModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationGroupingModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationGroupingModeEnum::Enum AnnotationGroupingModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationGroupingModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationGroupingModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type AnnotationGroupingModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t AnnotationGroupingModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationGroupingModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ AnnotationGroupingModeEnum::Enum AnnotationGroupingModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationGroupingModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationGroupingModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type AnnotationGroupingModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void AnnotationGroupingModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationGroupingModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(AnnotationGroupingModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationGroupingModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(AnnotationGroupingModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Annotations/AnnotationGroupingModeEnum.h000066400000000000000000000063521360521144700263550ustar00rootroot00000000000000#ifndef __ANNOTATION_GROUPING_MODE_ENUM_H__ #define __ANNOTATION_GROUPING_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class AnnotationGroupingModeEnum { public: /** * Enumerated values. */ enum Enum { /** Create a group */ GROUP, /** Recreate a previously 'ungrouped' group */ REGROUP, /** Ungroup (remove) a group */ UNGROUP }; ~AnnotationGroupingModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: AnnotationGroupingModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const AnnotationGroupingModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __ANNOTATION_GROUPING_MODE_ENUM_DECLARE__ std::vector AnnotationGroupingModeEnum::enumData; bool AnnotationGroupingModeEnum::initializedFlag = false; int32_t AnnotationGroupingModeEnum::integerCodeCounter = 0; #endif // __ANNOTATION_GROUPING_MODE_ENUM_DECLARE__ } // namespace #endif //__ANNOTATION_GROUPING_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationImage.cxx000066400000000000000000000222471360521144700245270ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_IMAGE_DECLARE__ #include "AnnotationImage.h" #undef __ANNOTATION_IMAGE_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "GraphicsPrimitiveV3fT3f.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::AnnotationImage * \brief An annotation image. * \ingroup Annotations */ /** * Constructor. * * @param attributeDefaultType * Type for attribute defaults */ AnnotationImage::AnnotationImage(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType) : AnnotationTwoDimensionalShape(AnnotationTypeEnum::IMAGE, attributeDefaultType) { initializeMembersAnnotationImage(); } /** * Destructor. */ AnnotationImage::~AnnotationImage() { delete m_sceneAssistant; } /** * Copy constructor. * @param obj * Object that is copied. */ AnnotationImage::AnnotationImage(const AnnotationImage& obj) : AnnotationTwoDimensionalShape(obj) { initializeMembersAnnotationImage(); this->copyHelperAnnotationImage(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ AnnotationImage& AnnotationImage::operator=(const AnnotationImage& obj) { if (this != &obj) { AnnotationTwoDimensionalShape::operator=(obj); this->copyHelperAnnotationImage(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void AnnotationImage::copyHelperAnnotationImage(const AnnotationImage& obj) { m_imageBytesRGBA = obj.m_imageBytesRGBA; m_imageWidth = obj.m_imageWidth; m_imageHeight = obj.m_imageHeight; } /** * Set the image. * * @param imageBytesRGBA * Bytes containing the image. 4 bytes per pixel with values * ranging 0 to 255. Number of elements MUST BE * (width * height * 4) * @param imageWidth * Width of the image. * @param imageHeight * Height of the image. */ void AnnotationImage::setImageBytesRGBA(const uint8_t* imageBytesRGBA, const int32_t imageWidth, const int32_t imageHeight) { m_imageWidth = imageWidth; m_imageHeight = imageHeight; const int32_t numBytes = (imageWidth * imageHeight * 4); m_imageBytesRGBA.resize(numBytes); for (int32_t i = 0; i < numBytes; i++) { m_imageBytesRGBA[i] = imageBytesRGBA[i]; } setModified(); } /** * @return Width of the image. */ int32_t AnnotationImage::getImageWidth() const { return m_imageWidth; } /** * @return Height of the image. */ int32_t AnnotationImage::getImageHeight() const { return m_imageHeight; } /** * @return The RGBA bytes of the image. * NULL if image is invalid. */ const uint8_t* AnnotationImage::getImageBytesRGBA() const { if (m_imageBytesRGBA.empty()) { return NULL; } return &m_imageBytesRGBA[0]; } /** * Initialize members of a new instance. */ void AnnotationImage::initializeMembersAnnotationImage() { switch (m_attributeDefaultType) { case AnnotationAttributesDefaultTypeEnum::NORMAL: break; case AnnotationAttributesDefaultTypeEnum::USER: break; } m_imageBytesRGBA.clear(); m_imageWidth = 0; m_imageHeight = 0; m_sceneAssistant = new SceneClassAssistant(); if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { } } /** * @return Is this annotation requiring that it be kept in a fixed * aspect ratio? By default, this is false. This method may be * overridden by annotations that require a fixed aspect ratio * (such as an image annotaiton). */ bool AnnotationImage::isFixedAspectRatio() const { return true; } /** * @return The aspect ratio for annotations that have a fixed aspect ratio. * This method may be overridden by annotations that require a fixed aspect ratio * (such as an image annotaiton). * * If the aspect ratio is unknown return 1. Never return zero. */ float AnnotationImage::getFixedAspectRatio() const { float aspectRatio = 1.0; if ((m_imageWidth > 0.0) && (m_imageHeight > 0.0)) { aspectRatio = static_cast(m_imageHeight) / static_cast(m_imageWidth); CaretAssert(aspectRatio != 0.0); } return aspectRatio; } /** * @return The graphics primitive for drawing the image as a texture. */ GraphicsPrimitiveV3fT3f* AnnotationImage::getGraphicsPrimitive() const { if (m_graphicsPrimitive == NULL) { if ( ! m_imageBytesRGBA.empty()) { GraphicsPrimitiveV3fT3f* primitive = GraphicsPrimitive::newPrimitiveV3fT3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP, &m_imageBytesRGBA[0], m_imageWidth, m_imageHeight); /* * A Triangle Strip (consisting of two triangles) is used * for drawing the image. At this time, the XYZ coordinates * do not matter and they will be updated when the annotation * is drawn by a call to ::setVertexBounds(). * The order of the vertices in the triangle strip is * Top Left, Bottom Left, Top Right, Bottom Right. If this * order changes, ::setVertexBounds must be updated. * * Zeros are used for the X- and Y-coordinates. * The third and fourth parameters are the texture * S and T coordinates. */ primitive->addVertex(0, 0, 0, 1); /* Top Left */ primitive->addVertex(0, 0, 0, 0); /* Bottom Left */ primitive->addVertex(0, 0, 1, 1); /* Top Right */ primitive->addVertex(0, 0, 1, 0); /* Bottom Right */ m_graphicsPrimitive.reset(primitive); // create triangles above and add method to set the vertex coordintes (bottom left, bottom right, etc) } } return m_graphicsPrimitive.get(); } void AnnotationImage::setVertexBounds(const float bottomLeft[3], const float bottomRight[3], const float topRight[3], const float topLeft[3]) { GraphicsPrimitiveV3fT3f* primitive = getGraphicsPrimitive(); CaretAssert(primitive); CaretAssert(primitive->getNumberOfVertices() == 4); primitive->replaceVertexFloatXYZ(0, topLeft); primitive->replaceVertexFloatXYZ(1, bottomLeft); primitive->replaceVertexFloatXYZ(2, topRight); primitive->replaceVertexFloatXYZ(3, bottomRight); } /** * Save subclass data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void AnnotationImage::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { AnnotationTwoDimensionalShape::saveSubClassDataToScene(sceneAttributes, sceneClass); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void AnnotationImage::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { AnnotationTwoDimensionalShape::restoreSubClassDataFromScene(sceneAttributes, sceneClass); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } connectome-workbench-1.4.2/src/Annotations/AnnotationImage.h000066400000000000000000000062021360521144700241450ustar00rootroot00000000000000#ifndef __ANNOTATION_IMAGE_H__ #define __ANNOTATION_IMAGE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AnnotationTwoDimensionalShape.h" namespace caret { class GraphicsPrimitiveV3fT3f; class AnnotationImage : public AnnotationTwoDimensionalShape { public: AnnotationImage(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType); virtual ~AnnotationImage(); AnnotationImage(const AnnotationImage& obj); AnnotationImage& operator=(const AnnotationImage& obj); virtual bool isFixedAspectRatio() const; virtual float getFixedAspectRatio() const; void setImageBytesRGBA(const uint8_t* imageBytesRGBA, const int32_t imageWidth, const int32_t imageHeight); int32_t getImageWidth() const; int32_t getImageHeight() const; const uint8_t* getImageBytesRGBA() const; GraphicsPrimitiveV3fT3f* getGraphicsPrimitive() const; void setVertexBounds(const float bottomLeft[3], const float bottomRight[3], const float topRight[3], const float topLeft[3]); // ADD_NEW_METHODS_HERE protected: virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: void copyHelperAnnotationImage(const AnnotationImage& obj); void initializeMembersAnnotationImage(); SceneClassAssistant* m_sceneAssistant; std::vector m_imageBytesRGBA; int32_t m_imageWidth; int32_t m_imageHeight; mutable std::unique_ptr m_graphicsPrimitive; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_IMAGE_DECLARE__ // #endif // __ANNOTATION_IMAGE_DECLARE__ } // namespace #endif //__ANNOTATION_IMAGE_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationLine.cxx000066400000000000000000000135071360521144700243730ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_LINE_DECLARE__ #include "AnnotationLine.h" #undef __ANNOTATION_LINE_DECLARE__ #include "CaretAssert.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::AnnotationLine * \brief An annotation line. * \ingroup Annotations */ /** * Constructor. * * @param attributeDefaultType * Type for attribute defaults */ AnnotationLine::AnnotationLine(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType) : AnnotationOneDimensionalShape(AnnotationTypeEnum::LINE, attributeDefaultType) { initializeMembersAnnotationLine(); } /** * Destructor. */ AnnotationLine::~AnnotationLine() { } /** * Copy constructor. * @param obj * Object that is copied. */ AnnotationLine::AnnotationLine(const AnnotationLine& obj) : AnnotationOneDimensionalShape(obj) { this->initializeMembersAnnotationLine(); this->copyHelperAnnotationLine(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ AnnotationLine& AnnotationLine::operator=(const AnnotationLine& obj) { if (this != &obj) { AnnotationOneDimensionalShape::operator=(obj); this->copyHelperAnnotationLine(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void AnnotationLine::copyHelperAnnotationLine(const AnnotationLine& obj) { m_displayEndArrow = obj.m_displayEndArrow; m_displayStartArrow = obj.m_displayStartArrow; } /** * Initialize a new instance of this class. */ void AnnotationLine::initializeMembersAnnotationLine() { switch (m_attributeDefaultType) { case AnnotationAttributesDefaultTypeEnum::NORMAL: m_displayStartArrow = false; m_displayEndArrow = false; break; case AnnotationAttributesDefaultTypeEnum::USER: m_displayStartArrow = s_userDefaultDisplayStartArrow; m_displayEndArrow = s_userDefaultDisplayEndArrow; break; } m_sceneAssistant.grabNew(new SceneClassAssistant()); if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { } } /** * @return Is the arrow at the line's start coordinate displayed? */ bool AnnotationLine::isDisplayStartArrow() const { return m_displayStartArrow; } /** * Set the display status of the arrow at the line's start coordinate. * * @param displayArrow * New status. */ void AnnotationLine::setDisplayStartArrow(const bool displayArrow) { m_displayStartArrow = displayArrow; } /** * @return Is the arrow at the line's start coordinate displayed? */ bool AnnotationLine::isDisplayEndArrow() const { return m_displayEndArrow; } /** * Set the display status of the arrow at the line's start coordinate. * * @param displayArrow * New status. */ void AnnotationLine::setDisplayEndArrow(const bool displayArrow) { m_displayEndArrow = displayArrow; } /** * Save subclass data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void AnnotationLine::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { AnnotationOneDimensionalShape::saveSubClassDataToScene(sceneAttributes, sceneClass); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void AnnotationLine::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { AnnotationOneDimensionalShape::restoreSubClassDataFromScene(sceneAttributes, sceneClass); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } /** * Set the default value for start arrow enabled. * * @param displayArrow * Default for newly created line annotations. */ void AnnotationLine::setUserDefaultDisplayStartArrow(const bool displayArrow) { s_userDefaultDisplayStartArrow = displayArrow; } /** * Set the default value for end arrow enabled. * * @param displayArrow * Default for newly created line annotations. */ void AnnotationLine::setUserDefaultDisplayEndArrow(const bool displayArrow) { s_userDefaultDisplayEndArrow = displayArrow; } connectome-workbench-1.4.2/src/Annotations/AnnotationLine.h000066400000000000000000000055411360521144700240170ustar00rootroot00000000000000#ifndef __ANNOTATION_LINE_H__ #define __ANNOTATION_LINE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationOneDimensionalShape.h" #include "CaretPointer.h" namespace caret { class AnnotationLine : public AnnotationOneDimensionalShape { public: AnnotationLine(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType); virtual ~AnnotationLine(); AnnotationLine(const AnnotationLine& obj); AnnotationLine& operator=(const AnnotationLine& obj); bool isDisplayStartArrow() const; void setDisplayStartArrow(const bool displayArrow); bool isDisplayEndArrow() const; void setDisplayEndArrow(const bool displayArrow); static void setUserDefaultDisplayStartArrow(const bool displayArrow); static void setUserDefaultDisplayEndArrow(const bool displayArrow); // ADD_NEW_METHODS_HERE protected: virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: void copyHelperAnnotationLine(const AnnotationLine& obj); void initializeMembersAnnotationLine(); CaretPointer m_sceneAssistant; bool m_displayStartArrow; bool m_displayEndArrow; // defaults static bool s_userDefaultDisplayStartArrow; static bool s_userDefaultDisplayEndArrow; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_LINE_DECLARE__ bool AnnotationLine::s_userDefaultDisplayStartArrow = false; bool AnnotationLine::s_userDefaultDisplayEndArrow = false; #endif // __ANNOTATION_LINE_DECLARE__ } // namespace #endif //__ANNOTATION_LINE_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationOneDimensionalShape.cxx000066400000000000000000000737331360521144700274000ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_ONE_DIMENSIONAL_SHAPE_DECLARE__ #include "AnnotationOneDimensionalShape.h" #undef __ANNOTATION_ONE_DIMENSIONAL_SHAPE_DECLARE__ #include #include "AnnotationCoordinate.h" #include "AnnotationSpatialModification.h" #include "CaretAssert.h" #include "MathFunctions.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::AnnotationOneDimensionalShape * \brief Class for annotations that are one-dimensional (lines) * \ingroup Annotations */ /** * Constructor. * @param type * Type of annotation. * @param attributeDefaultType * Type for attribute defaults */ AnnotationOneDimensionalShape::AnnotationOneDimensionalShape(const AnnotationTypeEnum::Enum type, const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType) : Annotation(type, attributeDefaultType) { initializeMembersAnnotationOneDimensionalShape(); } /** * Destructor. */ AnnotationOneDimensionalShape::~AnnotationOneDimensionalShape() { } /** * Copy constructor. * @param obj * Object that is copied. */ AnnotationOneDimensionalShape::AnnotationOneDimensionalShape(const AnnotationOneDimensionalShape& obj) : Annotation(obj) { initializeMembersAnnotationOneDimensionalShape(); this->copyHelperAnnotationOneDimensionalShape(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ AnnotationOneDimensionalShape& AnnotationOneDimensionalShape::operator=(const AnnotationOneDimensionalShape& obj) { if (this != &obj) { Annotation::operator=(obj); this->copyHelperAnnotationOneDimensionalShape(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void AnnotationOneDimensionalShape::copyHelperAnnotationOneDimensionalShape(const AnnotationOneDimensionalShape& obj) { *m_startCoordinate = *obj.m_startCoordinate; *m_endCoordinate = *obj.m_endCoordinate; } /** * Initialize members of this class. */ void AnnotationOneDimensionalShape::initializeMembersAnnotationOneDimensionalShape() { m_startCoordinate.grabNew(new AnnotationCoordinate(m_attributeDefaultType)); m_endCoordinate.grabNew(new AnnotationCoordinate(m_attributeDefaultType)); m_sceneAssistant.grabNew(new SceneClassAssistant()); if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { m_sceneAssistant->add("m_startCoordinate", "AnnotationCoordinate", m_startCoordinate); m_sceneAssistant->add("m_endCoordinate", "AnnotationCoordinate", m_endCoordinate); } } /** * @return 'this' as a one-dimensional shape. NULL if this is not a one-dimensional shape. */ AnnotationOneDimensionalShape* AnnotationOneDimensionalShape::castToOneDimensionalShape() { return this; } /** * @return 'this' as a one-dimensional shape. NULL if this is not a one-dimensional shape. */ const AnnotationOneDimensionalShape* AnnotationOneDimensionalShape::castToOneDimensionalShape() const { return this; } /** * @return 'this' as a one-dimensional shape. NULL if this is not a two-dimensional shape. */ AnnotationTwoDimensionalShape* AnnotationOneDimensionalShape::castToTwoDimensionalShape() { return NULL; } /** * @return 'this' as a one-dimensional shape. NULL if this is not a two-dimensional shape. */ const AnnotationTwoDimensionalShape* AnnotationOneDimensionalShape::castToTwoDimensionalShape() const { return NULL; } /** * @return The start coordinate for the one dimensional shape. */ AnnotationCoordinate* AnnotationOneDimensionalShape::getStartCoordinate() { return m_startCoordinate; } /** * @return The start coordinate for the one dimensional shape. */ const AnnotationCoordinate* AnnotationOneDimensionalShape::getStartCoordinate() const { return m_startCoordinate; } /** * @return The end coordinate for the one dimensional shape. */ AnnotationCoordinate* AnnotationOneDimensionalShape::getEndCoordinate() { return m_endCoordinate; } /** * @return The end coordinate for the one dimensional shape. */ const AnnotationCoordinate* AnnotationOneDimensionalShape::getEndCoordinate() const { return m_endCoordinate; } /** * @return The surface offset vector type for this annotation. */ AnnotationSurfaceOffsetVectorTypeEnum::Enum AnnotationOneDimensionalShape::getSurfaceOffsetVectorType() const { CaretAssert(m_startCoordinate); return m_startCoordinate->getSurfaceOffsetVectorType(); } /** * Is the object modified? * @return true if modified, else false. */ bool AnnotationOneDimensionalShape::isModified() const { if (Annotation::isModified()) { return true; } if (m_startCoordinate->isModified()) { return true; } if (m_endCoordinate->isModified()) { return true; } return false; } /** * Set the status to unmodified. */ void AnnotationOneDimensionalShape::clearModified() { Annotation::clearModified(); m_startCoordinate->clearModified(); m_endCoordinate->clearModified(); } /** * Apply the coordinates, size, and rotation from the given annotation * to this annotation. * * @param otherAnnotation * The other annotation from which attributes are obtained. */ void AnnotationOneDimensionalShape::applyCoordinatesSizeAndRotationFromOther(const Annotation* otherAnnotation) { CaretAssert(otherAnnotation); const AnnotationOneDimensionalShape* otherOneDim = dynamic_cast(otherAnnotation); CaretAssert(otherOneDim); AnnotationCoordinate* startCoord = getStartCoordinate(); const AnnotationCoordinate* otherStartCoord = otherOneDim->getStartCoordinate(); *startCoord = *otherStartCoord; AnnotationCoordinate* endCoord = getEndCoordinate(); const AnnotationCoordinate* otherEndCoord = otherOneDim->getEndCoordinate(); *endCoord = *otherEndCoord; setCoordinateSpace(otherAnnotation->getCoordinateSpace()); setTabIndex(otherAnnotation->getTabIndex()); setWindowIndex(otherAnnotation->getWindowIndex()); } /** * Get the rotation angle from the one-dimensional annotation. * 0 is horizontal. * * @param viewportWidth * Width of viewport. * @param viewportHeight * Height of viewport. * @return * Rotation angle of the annotation. */ float AnnotationOneDimensionalShape::getRotationAngle(const float viewportWidth, const float viewportHeight) const { if ( ! isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION)) { return 0.0; } float vpOneX = 0.0; float vpOneY = 0.0; float vpTwoX = 0.0; float vpTwoY = 0.0; getStartCoordinate()->getViewportXY(viewportWidth, viewportHeight, vpOneX, vpOneY); getEndCoordinate()->getViewportXY(viewportWidth, viewportHeight, vpTwoX, vpTwoY); const float dx = vpTwoX - vpOneX; const float dy = vpTwoY - vpOneY; float angle = 180.0 - MathFunctions::toDegrees(std::atan2(dy, dx)); if (angle < 0.0) { angle = angle + 360.0; } else if (angle > 360.0) { angle = angle - 360.0; } return angle; } /** * Set the rotation angle from the one-dimensional annotation. * 0 is horizontal. * * @param viewportWidth * Width of viewport. * @param viewportHeight * Height of viewport. * @param rotationAngle * Rotation angle for the annotation. */ void AnnotationOneDimensionalShape::setRotationAngle(const float viewportWidth, const float viewportHeight, const float rotationAngle) { if ( ! isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION)) { return; } float annOneX = 0.0; float annOneY = 0.0; float annTwoX = 0.0; float annTwoY = 0.0; getStartCoordinate()->getViewportXY(viewportWidth, viewportHeight, annOneX, annOneY); getEndCoordinate()->getViewportXY(viewportWidth, viewportHeight, annTwoX, annTwoY); const float midPointXYZ[3] = { (annOneX + annTwoX) / 2.0f, (annOneY + annTwoY) / 2.0f, 0.0f }; const float vpOneXYZ[3] = { annOneX, annOneY, 0.0f }; const float lengthMidToOne = MathFunctions::distance3D(midPointXYZ, vpOneXYZ); const float newRotationAngle = 180.0f - rotationAngle; const float angleRadians = MathFunctions::toRadians(newRotationAngle); const float dy = lengthMidToOne * std::sin(angleRadians); const float dx = lengthMidToOne * std::cos(angleRadians); annOneX = midPointXYZ[0] - dx; annOneY = midPointXYZ[1] - dy; annTwoX = midPointXYZ[0] + dx; annTwoY = midPointXYZ[1] + dy; getStartCoordinate()->setXYZFromViewportXYZ(viewportWidth, viewportHeight, annOneX, annOneY); getEndCoordinate()->setXYZFromViewportXYZ(viewportWidth, viewportHeight, annTwoX, annTwoY); } /** * Is the given sizing handle valid for this annotation? * * @sizingHandle * The sizing handle. * @return * True if sizing handle valid, else false. */ bool AnnotationOneDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTypeEnum::Enum sizingHandle) const { bool xyPlaneFlag = false; switch (getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: xyPlaneFlag = true; break; case AnnotationCoordinateSpaceEnum::SPACER: xyPlaneFlag = true; break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: xyPlaneFlag = true; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: xyPlaneFlag = true; break; } bool validFlag = false; switch (sizingHandle) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: validFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: validFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: if (xyPlaneFlag) { validFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: if (xyPlaneFlag) { validFlag = true; } break; } return validFlag; } /** * Apply a spatial modification to an annotation in surface space. * * @param spatialModification * Contains information about the spatial modification. * @return * True if the annotation was modified, else false. */ bool AnnotationOneDimensionalShape::applySpatialModificationSurfaceSpace(const AnnotationSpatialModification& spatialModification) { bool validFlag = false; switch (spatialModification.m_sizingHandleType) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: { StructureEnum::Enum structure = StructureEnum::INVALID; int32_t surfaceNumberOfNodes = -1; int32_t surfaceNodeIndex = -1; m_endCoordinate->getSurfaceSpace(structure, surfaceNumberOfNodes, surfaceNodeIndex); if (spatialModification.m_surfaceCoordinateAtMouseXY.m_surfaceNodeValid) { if ((spatialModification.m_surfaceCoordinateAtMouseXY.m_surfaceStructure == structure) && (spatialModification.m_surfaceCoordinateAtMouseXY.m_surfaceNumberOfNodes == surfaceNumberOfNodes)) { m_endCoordinate->setSurfaceSpace(spatialModification.m_surfaceCoordinateAtMouseXY.m_surfaceStructure, spatialModification.m_surfaceCoordinateAtMouseXY.m_surfaceNumberOfNodes, spatialModification.m_surfaceCoordinateAtMouseXY.m_surfaceNodeIndex); validFlag = true; } } } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: { StructureEnum::Enum structure = StructureEnum::INVALID; int32_t surfaceNumberOfNodes = -1; int32_t surfaceNodeIndex = -1; m_startCoordinate->getSurfaceSpace(structure, surfaceNumberOfNodes, surfaceNodeIndex); if (spatialModification.m_surfaceCoordinateAtMouseXY.m_surfaceNodeValid) { if ((spatialModification.m_surfaceCoordinateAtMouseXY.m_surfaceStructure == structure) && (spatialModification.m_surfaceCoordinateAtMouseXY.m_surfaceNumberOfNodes == surfaceNumberOfNodes)) { m_startCoordinate->setSurfaceSpace(spatialModification.m_surfaceCoordinateAtMouseXY.m_surfaceStructure, spatialModification.m_surfaceCoordinateAtMouseXY.m_surfaceNumberOfNodes, spatialModification.m_surfaceCoordinateAtMouseXY.m_surfaceNodeIndex); validFlag = true; } } } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: break; } if (validFlag) { setModified(); } return validFlag; } /** * Apply a spatial modification to an annotation in spacer tab space. * * @param spatialModification * Contains information about the spatial modification. * @return * True if the annotation was modified, else false. */ bool AnnotationOneDimensionalShape::applySpatialModificationSpacerTabSpace(const AnnotationSpatialModification& spatialModification) { return applySpatialModificationTabOrWindowSpace(spatialModification); } /** * Apply a spatial modification to an annotation in tab or window space. * * @param spatialModification * Contains information about the spatial modification. * @return * True if the annotation was modified, else false. */ bool AnnotationOneDimensionalShape::applySpatialModificationTabOrWindowSpace(const AnnotationSpatialModification& spatialModification) { float xyz1[3]; float xyz2[3]; m_startCoordinate->getXYZ(xyz1); m_endCoordinate->getXYZ(xyz2); float newX1 = xyz1[0]; float newY1 = xyz1[1]; float newX2 = xyz2[0]; float newY2 = xyz2[1]; const float spaceDX = 100.0f * ((spatialModification.m_viewportWidth != 0.0f) ? (spatialModification.m_mouseDX / spatialModification.m_viewportWidth) : 0.0f); const float spaceDY = 100.0f * ((spatialModification.m_viewportHeight != 0.0f) ? (spatialModification.m_mouseDY / spatialModification.m_viewportHeight) : 0.0f); bool validFlag = false; switch (spatialModification.m_sizingHandleType) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: newX2 += spaceDX; newY2 += spaceDY; validFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: newX1 += spaceDX; newY1 += spaceDY; validFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: newX1 += spaceDX; newY1 += spaceDY; newX2 += spaceDX; newY2 += spaceDY; validFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: { float vpOneXYZ[3] = { 0.0, 0.0, 0.0 }; relativeXYZToViewportXYZ(xyz1, spatialModification.m_viewportWidth, spatialModification.m_viewportHeight, vpOneXYZ); float vpTwoXYZ[3] = { 0.0, 0.0, 0.0 }; relativeXYZToViewportXYZ(xyz2, spatialModification.m_viewportWidth, spatialModification.m_viewportHeight, vpTwoXYZ); float vpXYZ[3] = { (vpOneXYZ[0] + vpTwoXYZ[0]) / 2.0f, (vpOneXYZ[1] + vpTwoXYZ[1]) / 2.0f, (vpOneXYZ[2] + vpTwoXYZ[2]) / 2.0f }; /* * Rotation angle is a formed by the triangle * (Mouse XY, Annotation XY, Positive X-axis). */ const float dy = spatialModification.m_mouseY - vpXYZ[1]; const float dx = spatialModification.m_mouseX - vpXYZ[0]; const float angleRadians = std::atan2(dy, dx); const float angleDegrees = MathFunctions::toDegrees(angleRadians); float rotationAngle = -angleDegrees; if (rotationAngle > 360.0) { rotationAngle -= 360.0; } else if (rotationAngle < 0.0) { rotationAngle += 360.0; } CaretPointer shapeCopy(dynamic_cast(this->clone())); shapeCopy->setRotationAngle(spatialModification.m_viewportWidth, spatialModification.m_viewportHeight, rotationAngle); const float* xyzOne = shapeCopy->getStartCoordinate()->getXYZ(); const float* xyzTwo = shapeCopy->getEndCoordinate()->getXYZ(); newX1 = xyzOne[0]; newY1 = xyzOne[1]; newX2 = xyzTwo[0]; newY2 = xyzTwo[1]; validFlag = true; } break; } if (validFlag) { if ((newX1 >= 0.0) && (newX1 <= 100.0) && (newY1 >= 0.0) && (newY1 <= 100.0) && (newX2 >= 0.0) && (newX2 <= 100.0) && (newY2 >= 0.0) && (newY2 <= 100.0)) { xyz1[0] = newX1; xyz1[1] = newY1; m_startCoordinate->setXYZ(xyz1); xyz2[0] = newX2; xyz2[1] = newY2; m_endCoordinate->setXYZ(xyz2); } else { validFlag = false; } } return validFlag; } /** * Apply a spatial modification to an annotation in chart space. * * @param spatialModification * Contains information about the spatial modification. * @return * True if the annotation was modified, else false. */ bool AnnotationOneDimensionalShape::applySpatialModificationChartSpace(const AnnotationSpatialModification& spatialModification) { bool validFlag = false; switch (spatialModification.m_sizingHandleType) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: if (spatialModification.m_chartCoordAtMouseXY.m_chartXYZValid) { m_endCoordinate->setXYZ(spatialModification.m_chartCoordAtMouseXY.m_chartXYZ); validFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: if (spatialModification.m_chartCoordAtMouseXY.m_chartXYZValid) { m_startCoordinate->setXYZ(spatialModification.m_chartCoordAtMouseXY.m_chartXYZ); validFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: if (spatialModification.m_chartCoordAtMouseXY.m_chartXYZValid && spatialModification.m_chartCoordAtPreviousMouseXY.m_chartXYZValid) { const float dx = spatialModification.m_chartCoordAtMouseXY.m_chartXYZ[0] - spatialModification.m_chartCoordAtPreviousMouseXY.m_chartXYZ[0]; const float dy = spatialModification.m_chartCoordAtMouseXY.m_chartXYZ[1] - spatialModification.m_chartCoordAtPreviousMouseXY.m_chartXYZ[1]; const float dz = spatialModification.m_chartCoordAtMouseXY.m_chartXYZ[2] - spatialModification.m_chartCoordAtPreviousMouseXY.m_chartXYZ[2]; m_startCoordinate->addToXYZ(dx, dy, dz); m_endCoordinate->addToXYZ(dx, dy, dz); validFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: break; } if (validFlag) { setModified(); } return validFlag; } /** * Apply a spatial modification to an annotation in stereotaxic space. * * @param spatialModification * Contains information about the spatial modification. * @return * True if the annotation was modified, else false. */ bool AnnotationOneDimensionalShape::applySpatialModificationStereotaxicSpace(const AnnotationSpatialModification& spatialModification) { bool validFlag = false; switch (spatialModification.m_sizingHandleType) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: if (spatialModification.m_stereotaxicCoordinateAtMouseXY.m_stereotaxicValid) { m_endCoordinate->setXYZ(spatialModification.m_stereotaxicCoordinateAtMouseXY.m_stereotaxicXYZ); validFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: if (spatialModification.m_stereotaxicCoordinateAtMouseXY.m_stereotaxicValid) { m_startCoordinate->setXYZ(spatialModification.m_stereotaxicCoordinateAtMouseXY.m_stereotaxicXYZ); validFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: break; } if (validFlag) { setModified(); } return validFlag; } /** * Apply a spatial modification to an annotation. * * @param spatialModification * Contains information about the spatial modification. * @return * True if the annotation was modified, else false. */ bool AnnotationOneDimensionalShape::applySpatialModification(const AnnotationSpatialModification& spatialModification) { if ( ! isSizeHandleValid(spatialModification.m_sizingHandleType)) { return false; } switch (getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: return applySpatialModificationChartSpace(spatialModification); break; case AnnotationCoordinateSpaceEnum::SPACER: return applySpatialModificationSpacerTabSpace(spatialModification); break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: return applySpatialModificationStereotaxicSpace(spatialModification); break; case AnnotationCoordinateSpaceEnum::SURFACE: return applySpatialModificationSurfaceSpace(spatialModification); break; case AnnotationCoordinateSpaceEnum::TAB: return applySpatialModificationTabOrWindowSpace(spatialModification); break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: return applySpatialModificationTabOrWindowSpace(spatialModification); break; } return false; } /** * Save subclass data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void AnnotationOneDimensionalShape::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void AnnotationOneDimensionalShape::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } connectome-workbench-1.4.2/src/Annotations/AnnotationOneDimensionalShape.h000066400000000000000000000112471360521144700270150ustar00rootroot00000000000000#ifndef __ANNOTATION_ONE_DIMENSIONAL_SHAPE_H__ #define __ANNOTATION_ONE_DIMENSIONAL_SHAPE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Annotation.h" #include "CaretPointer.h" namespace caret { class AnnotationCoordinate; class AnnotationOneDimensionalShape : public Annotation { public: AnnotationOneDimensionalShape(const AnnotationTypeEnum::Enum type, const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType); virtual ~AnnotationOneDimensionalShape(); AnnotationOneDimensionalShape(const AnnotationOneDimensionalShape& obj); AnnotationOneDimensionalShape& operator=(const AnnotationOneDimensionalShape& obj); virtual AnnotationOneDimensionalShape* castToOneDimensionalShape() override; virtual const AnnotationOneDimensionalShape* castToOneDimensionalShape() const override; virtual AnnotationTwoDimensionalShape* castToTwoDimensionalShape() override; virtual const AnnotationTwoDimensionalShape* castToTwoDimensionalShape() const override; AnnotationCoordinate* getStartCoordinate(); const AnnotationCoordinate* getStartCoordinate() const; AnnotationCoordinate* getEndCoordinate(); const AnnotationCoordinate* getEndCoordinate() const; virtual AnnotationSurfaceOffsetVectorTypeEnum::Enum getSurfaceOffsetVectorType() const override; virtual bool isModified() const; virtual void clearModified(); virtual bool isSizeHandleValid(const AnnotationSizingHandleTypeEnum::Enum sizingHandle) const; virtual bool applySpatialModification(const AnnotationSpatialModification& spatialModification); virtual void applyCoordinatesSizeAndRotationFromOther(const Annotation* otherAnnotation); float getRotationAngle(const float viewportWidth, const float viewportHeight) const; void setRotationAngle(const float viewportWidth, const float viewportHeight, const float rotationAngle); // ADD_NEW_METHODS_HERE protected: virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: void copyHelperAnnotationOneDimensionalShape(const AnnotationOneDimensionalShape& obj); void initializeMembersAnnotationOneDimensionalShape(); bool applySpatialModificationChartSpace(const AnnotationSpatialModification& spatialModification); bool applySpatialModificationSurfaceSpace(const AnnotationSpatialModification& spatialModification); bool applySpatialModificationStereotaxicSpace(const AnnotationSpatialModification& spatialModification); bool applySpatialModificationTabOrWindowSpace(const AnnotationSpatialModification& spatialModification); bool applySpatialModificationSpacerTabSpace(const AnnotationSpatialModification& spatialModification); CaretPointer m_sceneAssistant; CaretPointer m_startCoordinate; CaretPointer m_endCoordinate; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_ONE_DIMENSIONAL_SHAPE_DECLARE__ // #endif // __ANNOTATION_ONE_DIMENSIONAL_SHAPE_DECLARE__ } // namespace #endif //__ANNOTATION_ONE_DIMENSIONAL_SHAPE_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationOval.cxx000066400000000000000000000101071360521144700243760ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_OVAL_DECLARE__ #include "AnnotationOval.h" #undef __ANNOTATION_OVAL_DECLARE__ #include "CaretAssert.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::AnnotationOval * \brief An annotation oval. * \ingroup Annotations */ /** * Constructor. * * @param attributeDefaultType * Type for attribute defaults */ AnnotationOval::AnnotationOval(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType) : AnnotationTwoDimensionalShape(AnnotationTypeEnum::OVAL, attributeDefaultType) { initializeMembersAnnotationOval(); } /** * Destructor. */ AnnotationOval::~AnnotationOval() { } /** * Copy constructor. * @param obj * Object that is copied. */ AnnotationOval::AnnotationOval(const AnnotationOval& obj) : AnnotationTwoDimensionalShape(obj) { this->initializeMembersAnnotationOval(); this->copyHelperAnnotationOval(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ AnnotationOval& AnnotationOval::operator=(const AnnotationOval& obj) { if (this != &obj) { AnnotationTwoDimensionalShape::operator=(obj); this->copyHelperAnnotationOval(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void AnnotationOval::copyHelperAnnotationOval(const AnnotationOval& /*obj*/) { /* nothing to copy */ } /** * Initialize a new instance of this class. */ void AnnotationOval::initializeMembersAnnotationOval() { m_sceneAssistant.grabNew(new SceneClassAssistant()); if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { } } /** * Save subclass data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void AnnotationOval::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { AnnotationTwoDimensionalShape::saveSubClassDataToScene(sceneAttributes, sceneClass); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void AnnotationOval::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { AnnotationTwoDimensionalShape::restoreSubClassDataFromScene(sceneAttributes, sceneClass); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } connectome-workbench-1.4.2/src/Annotations/AnnotationOval.h000066400000000000000000000042321360521144700240250ustar00rootroot00000000000000#ifndef __ANNOTATION_OVAL_H__ #define __ANNOTATION_OVAL_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationTwoDimensionalShape.h" #include "CaretPointer.h" namespace caret { class AnnotationOval : public AnnotationTwoDimensionalShape { public: AnnotationOval(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType); virtual ~AnnotationOval(); AnnotationOval(const AnnotationOval&); AnnotationOval& operator=(const AnnotationOval&); // ADD_NEW_METHODS_HERE protected: virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: void copyHelperAnnotationOval(const AnnotationOval& obj); void initializeMembersAnnotationOval(); CaretPointer m_sceneAssistant; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_OVAL_DECLARE__ // #endif // __ANNOTATION_OVAL_DECLARE__ } // namespace #endif //__ANNOTATION_OVAL_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationPercentSizeText.cxx000066400000000000000000000121551360521144700266020ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_PERCENT_SIZE_TEXT_DECLARE__ #include "AnnotationPercentSizeText.h" #undef __ANNOTATION_PERCENT_SIZE_TEXT_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" using namespace caret; /** * \class caret::AnnotationPercentSizeText * \brief Text annotation with font height a percentage of viewport height. * \ingroup Annotations */ /** * Constructor. * * @param attributeDefaultType * Type for attribute defaults * @param textFontSizeType * Type of font sizing must be percentage height/width */ AnnotationPercentSizeText::AnnotationPercentSizeText(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, const AnnotationTextFontSizeTypeEnum::Enum textFontSizeType) : AnnotationText(attributeDefaultType, textFontSizeType) { switch (textFontSizeType) { case AnnotationTextFontSizeTypeEnum::POINTS: CaretAssertMessage(0, "POINTS font size type not allowed for AnnotationPercentSizeText"); CaretLogSevere("POINTS font size type not allowed for AnnotationPercentSizeText"); break; case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH: break; case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT: break; } } /** * Constructor for subclass. * * @param type * Type of annotation. * @param attributeDefaultType * Type for attribute defaults * @param textFontSizeType * Type of font sizing must be percentage height/width */ AnnotationPercentSizeText::AnnotationPercentSizeText(const AnnotationTypeEnum::Enum type, const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, const AnnotationTextFontSizeTypeEnum::Enum textFontSizeType) : AnnotationText(type, attributeDefaultType, textFontSizeType) { switch (textFontSizeType) { case AnnotationTextFontSizeTypeEnum::POINTS: CaretAssertMessage(0, "POINTS font size type not allowed for AnnotationPercentSizeText"); CaretLogSevere("POINTS font size type not allowed for AnnotationPercentSizeText"); break; case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH: break; case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT: break; } } /** * Constructor. * * @param attributeDefaultType * Type for attribute defaults */ AnnotationPercentSizeText::AnnotationPercentSizeText(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType) : AnnotationText(attributeDefaultType, AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT) { } /** * Destructor. */ AnnotationPercentSizeText::~AnnotationPercentSizeText() { } /** * Copy constructor. * @param obj * Object that is copied. */ AnnotationPercentSizeText::AnnotationPercentSizeText(const AnnotationPercentSizeText& obj) : AnnotationText(obj) { this->copyHelperAnnotationPercentSizeText(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ AnnotationPercentSizeText& AnnotationPercentSizeText::operator=(const AnnotationPercentSizeText& obj) { if (this != &obj) { AnnotationText::operator=(obj); this->copyHelperAnnotationPercentSizeText(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void AnnotationPercentSizeText::copyHelperAnnotationPercentSizeText(const AnnotationPercentSizeText& /* obj */) { } /** * @return Size of font as a percentage of the viewport height. * * Range is zero to one hundred. */ float AnnotationPercentSizeText::getFontPercentViewportSize() const { return getFontPercentViewportSizeProtected(); } /** * Set the size of the font as a percentage of the viewport height. * * @param fontPercentViewportHeight * New value for percentage of viewport height. * Range is zero to one hundred. */ void AnnotationPercentSizeText::setFontPercentViewportSize(const float fontPercentViewportHeight) { setFontPercentViewportSizeProtected(fontPercentViewportHeight); } connectome-workbench-1.4.2/src/Annotations/AnnotationPercentSizeText.h000066400000000000000000000046241360521144700262310ustar00rootroot00000000000000#ifndef __ANNOTATION_PERCENT_SIZE_TEXT_H__ #define __ANNOTATION_PERCENT_SIZE_TEXT_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationText.h" namespace caret { class AnnotationPercentSizeText : public AnnotationText { public: AnnotationPercentSizeText(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType); AnnotationPercentSizeText(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, const AnnotationTextFontSizeTypeEnum::Enum textFontSizeType); virtual ~AnnotationPercentSizeText(); AnnotationPercentSizeText(const AnnotationPercentSizeText& obj); AnnotationPercentSizeText& operator=(const AnnotationPercentSizeText& obj); virtual float getFontPercentViewportSize() const; virtual void setFontPercentViewportSize(const float fontPercentViewportHeight); // ADD_NEW_METHODS_HERE protected: AnnotationPercentSizeText(const AnnotationTypeEnum::Enum type, const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, const AnnotationTextFontSizeTypeEnum::Enum textFontSizeType); private: void copyHelperAnnotationPercentSizeText(const AnnotationPercentSizeText& obj); // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_PERCENT_SIZE_TEXT_DECLARE__ // #endif // __ANNOTATION_PERCENT_SIZE_TEXT_DECLARE__ } // namespace #endif //__ANNOTATION_PERCENT_SIZE_TEXT_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationPointSizeText.cxx000066400000000000000000000066451360521144700263020ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_POINT_SIZE_TEXT_DECLARE__ #include "AnnotationPointSizeText.h" #undef __ANNOTATION_POINT_SIZE_TEXT_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationPointSizeText * \brief Text annotation with font height in points (one point is 1/72 of inch). * \ingroup Annotations */ /** * Constructor. * * @param attributeDefaultType * Type for attribute defaults */ AnnotationPointSizeText::AnnotationPointSizeText(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType) : AnnotationText(attributeDefaultType, AnnotationTextFontSizeTypeEnum::POINTS) { } /** * Destructor. */ AnnotationPointSizeText::~AnnotationPointSizeText() { } /** * Copy constructor. * @param obj * Object that is copied. */ AnnotationPointSizeText::AnnotationPointSizeText(const AnnotationPointSizeText& obj) : AnnotationText(obj) { this->copyHelperAnnotationPointSizeText(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ AnnotationPointSizeText& AnnotationPointSizeText::operator=(const AnnotationPointSizeText& obj) { if (this != &obj) { AnnotationText::operator=(obj); this->copyHelperAnnotationPointSizeText(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void AnnotationPointSizeText::copyHelperAnnotationPointSizeText(const AnnotationPointSizeText& /*obj*/) { } /** * @return The font point size. */ AnnotationTextFontPointSizeEnum::Enum AnnotationPointSizeText::getFontPointSize() const { return getFontPointSizeProtected(); } /** * Set the font point size. * * @param fontPointSize * New font point size. */ void AnnotationPointSizeText::setFontPointSize(const AnnotationTextFontPointSizeEnum::Enum fontPointSize) { setFontPointSizeProtected(fontPointSize); } /** * @return Size of font as a percentage of the viewport height. * * Range is zero to one hundred. */ float AnnotationPointSizeText::getFontPercentViewportSize() const { CaretAssertMessage(0, "This method should never be called for Point Size Text"); return 10.0; } /** * Set the size of the font as a percentage of the viewport height. * * @param fontPercentViewportHeight * New value for percentage of viewport height. * Range is zero to one hundred. */ void AnnotationPointSizeText::setFontPercentViewportSize(const float /*fontPercentViewportHeight*/) { CaretAssertMessage(0, "This method should never be called for Point Size Text"); } connectome-workbench-1.4.2/src/Annotations/AnnotationPointSizeText.h000066400000000000000000000040661360521144700257220ustar00rootroot00000000000000#ifndef __ANNOTATION_POINT_SIZE_TEXT_H__ #define __ANNOTATION_POINT_SIZE_TEXT_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationText.h" namespace caret { class AnnotationPointSizeText : public AnnotationText { public: AnnotationPointSizeText(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType); virtual ~AnnotationPointSizeText(); AnnotationPointSizeText(const AnnotationPointSizeText& obj); AnnotationPointSizeText& operator=(const AnnotationPointSizeText& obj); AnnotationTextFontPointSizeEnum::Enum getFontPointSize() const; void setFontPointSize(const AnnotationTextFontPointSizeEnum::Enum fontPointSize); virtual float getFontPercentViewportSize() const; virtual void setFontPercentViewportSize(const float fontPercentViewportHeight); // ADD_NEW_METHODS_HERE private: void copyHelperAnnotationPointSizeText(const AnnotationPointSizeText& obj); // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_POINT_SIZE_TEXT_DECLARE__ // #endif // __ANNOTATION_POINT_SIZE_TEXT_DECLARE__ } // namespace #endif //__ANNOTATION_POINT_SIZE_TEXT_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationRedoUndoCommand.cxx000066400000000000000000002457011360521144700265250ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_UNDO_COMMAND_DECLARE__ #include "AnnotationRedoUndoCommand.h" #undef __ANNOTATION_UNDO_COMMAND_DECLARE__ #include #include "AnnotationFontAttributesInterface.h" #include "AnnotationLine.h" #include "AnnotationPercentSizeText.h" #include "AnnotationPointSizeText.h" #include "AnnotationTwoDimensionalShape.h" #include "EventAnnotationAddToRemoveFromFile.h" #include "EventAnnotationGrouping.h" #include "EventGetViewportSize.h" #include "EventManager.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "MathFunctions.h" using namespace caret; /** * \class caret::AnnotationRedoUndoCommand * \brief Command pattern for annotation modifications that undo and redo. * \ingroup Annotations */ /** * Constructor. */ AnnotationRedoUndoCommand::AnnotationRedoUndoCommand() : CaretUndoCommand() { m_mode = AnnotationRedoUndoCommandModeEnum::INVALID; m_annotationGroupMemento = NULL; m_sortedFlag = false; } /** * Destructor. */ AnnotationRedoUndoCommand::~AnnotationRedoUndoCommand() { for (std::vector::iterator iter = m_annotationMementos.begin(); iter != m_annotationMementos.end(); iter++) { delete *iter; } if (m_annotationGroupMemento != NULL) { delete m_annotationGroupMemento; } } /** * Apply a redo or undo command. * * @param annotation * The annotation being redone or undone. * @param annotationValue * The redo or undo value for the annotation. */ void AnnotationRedoUndoCommand::applyRedoOrUndo(Annotation* annotation, const Annotation* annotationValue) const { CaretAssert(annotation); const AnnotationTypeEnum::Enum annType = annotation->getType(); switch (m_mode) { case AnnotationRedoUndoCommandModeEnum::INVALID: break; case AnnotationRedoUndoCommandModeEnum::COLOR_BACKGROUND: { CaretAssert(annotationValue); annotation->setBackgroundColor(annotationValue->getBackgroundColor()); float rgba[4]; annotationValue->getCustomBackgroundColor(rgba); annotation->setCustomBackgroundColor(rgba); } break; case AnnotationRedoUndoCommandModeEnum::COLOR_FOREGROUND: { CaretAssert(annotationValue); annotation->setLineColor(annotationValue->getLineColor()); float rgba[4]; annotationValue->getCustomLineColor(rgba); annotation->setCustomLineColor(rgba); } break; case AnnotationRedoUndoCommandModeEnum::COORDINATE_ONE: { AnnotationOneDimensionalShape* oneDimShape = dynamic_cast(annotation); AnnotationTwoDimensionalShape* twoDimShape = dynamic_cast(annotation); const AnnotationOneDimensionalShape* valueOneDimShape = dynamic_cast(annotationValue); const AnnotationTwoDimensionalShape* valueTwoDimShape = dynamic_cast(annotationValue); if ((oneDimShape != NULL) && (valueOneDimShape != NULL)) { AnnotationCoordinate* coordDest = oneDimShape->getStartCoordinate(); const AnnotationCoordinate* coordFrom = valueOneDimShape->getStartCoordinate(); *coordDest = *coordFrom; } else if ((twoDimShape != NULL) && (valueTwoDimShape != NULL)) { AnnotationCoordinate* coordDest = twoDimShape->getCoordinate(); const AnnotationCoordinate* coordFrom = valueTwoDimShape->getCoordinate(); *coordDest = *coordFrom; } else { CaretAssert(0); } } break; case AnnotationRedoUndoCommandModeEnum::COORDINATE_ONE_AND_TWO: { AnnotationOneDimensionalShape* oneDimShape = dynamic_cast(annotation); const AnnotationOneDimensionalShape* valueOneDimShape = dynamic_cast(annotationValue); if ((oneDimShape != NULL) && (valueOneDimShape != NULL)) { AnnotationCoordinate* coordDestStart = oneDimShape->getStartCoordinate(); const AnnotationCoordinate* coordFromStart = valueOneDimShape->getStartCoordinate(); *coordDestStart = *coordFromStart; AnnotationCoordinate* coordDestEnd = oneDimShape->getEndCoordinate(); const AnnotationCoordinate* coordFromEnd = valueOneDimShape->getEndCoordinate(); *coordDestEnd = *coordFromEnd; } else { CaretAssert(0); } } break; case AnnotationRedoUndoCommandModeEnum::COORDINATE_TWO: { AnnotationOneDimensionalShape* oneDimShape = dynamic_cast(annotation); const AnnotationOneDimensionalShape* valueOneDimShape = dynamic_cast(annotationValue); if ((oneDimShape != NULL) && (valueOneDimShape != NULL)) { AnnotationCoordinate* coordDest = oneDimShape->getEndCoordinate(); const AnnotationCoordinate* coordFrom = valueOneDimShape->getEndCoordinate(); *coordDest = *coordFrom; } else { CaretAssert(0); } } break; case AnnotationRedoUndoCommandModeEnum::CREATE_ANNOTATION: CaretAssertMessage(0, ("This mode " + AnnotationRedoUndoCommandModeEnum::toName(m_mode) + " is handle in the redo() and undo() functions.")); break; case AnnotationRedoUndoCommandModeEnum::CUT_ANNOTATION: CaretAssertMessage(0, ("This mode " + AnnotationRedoUndoCommandModeEnum::toName(m_mode) + " is handle in the redo() and undo() functions.")); break; case AnnotationRedoUndoCommandModeEnum::DELETE_ANNOTATIONS: CaretAssertMessage(0, ("This mode " + AnnotationRedoUndoCommandModeEnum::toName(m_mode) + " is handle in the redo() and undo() functions.")); break; case AnnotationRedoUndoCommandModeEnum::DUPLICATE_ANNOTATION: CaretAssertMessage(0, ("This mode " + AnnotationRedoUndoCommandModeEnum::toName(m_mode) + " is handle in the redo() and undo() functions.")); break; case AnnotationRedoUndoCommandModeEnum::GROUPING_GROUP: CaretAssert(0); break; case AnnotationRedoUndoCommandModeEnum::GROUPING_REGROUP: CaretAssert(0); break; case AnnotationRedoUndoCommandModeEnum::GROUPING_UNGROUP: CaretAssert(0); break; case AnnotationRedoUndoCommandModeEnum::LINE_ARROW_START: if ((annType == AnnotationTypeEnum::LINE) && (annotationValue->getType() == AnnotationTypeEnum::LINE)) { AnnotationLine* line = dynamic_cast(annotation); CaretAssert(line); const AnnotationLine* lineValue = dynamic_cast(annotationValue); line->setDisplayStartArrow(lineValue->isDisplayStartArrow()); } else { CaretAssert(0); } break; case AnnotationRedoUndoCommandModeEnum::LINE_ARROW_END: if ((annType == AnnotationTypeEnum::LINE) && (annotationValue->getType() == AnnotationTypeEnum::LINE)) { AnnotationLine* line = dynamic_cast(annotation); CaretAssert(line); const AnnotationLine* lineValue = dynamic_cast(annotationValue); line->setDisplayEndArrow(lineValue->isDisplayEndArrow()); } else { CaretAssert(0); } break; case AnnotationRedoUndoCommandModeEnum::LINE_WIDTH_FOREGROUND: if (annotation->testProperty(Annotation::Property::LINE_THICKNESS)) { annotation->setLineWidthPercentage(annotationValue->getLineWidthPercentage()); } break; case AnnotationRedoUndoCommandModeEnum::LOCATION_AND_SIZE: annotation->applyCoordinatesSizeAndRotationFromOther(annotationValue); break; case AnnotationRedoUndoCommandModeEnum::PASTE_ANNOTATION: CaretAssertMessage(0, ("This mode " + AnnotationRedoUndoCommandModeEnum::toName(m_mode) + " is handle in the redo() and undo() functions.")); break; case AnnotationRedoUndoCommandModeEnum::ROTATION_ANGLE: { AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(annotation); const AnnotationTwoDimensionalShape* twoDimValue = dynamic_cast(annotationValue); if ((twoDimAnn != NULL) && (twoDimValue != NULL)) { twoDimAnn->setRotationAngle(twoDimValue->getRotationAngle()); } else { AnnotationOneDimensionalShape* oneDimAnn = dynamic_cast(annotation); const AnnotationOneDimensionalShape* oneDimValue = dynamic_cast(annotationValue); if ((oneDimAnn != NULL) && (oneDimValue != NULL)) { oneDimAnn->getStartCoordinate()->setXYZ(oneDimValue->getStartCoordinate()->getXYZ()); oneDimAnn->getEndCoordinate()->setXYZ(oneDimValue->getEndCoordinate()->getXYZ()); } } } break; case AnnotationRedoUndoCommandModeEnum::TEXT_ALIGNMENT_HORIZONTAL: { AnnotationText* textAnn = dynamic_cast(annotation); const AnnotationText* textAnnValue = dynamic_cast(annotationValue); if ((textAnn != NULL) && (textAnnValue != NULL)) { textAnn->setHorizontalAlignment(textAnnValue->getHorizontalAlignment()); } else { CaretAssert(0); } } break; case AnnotationRedoUndoCommandModeEnum::TEXT_ALIGNMENT_VERTICAL: { AnnotationText* textAnn = dynamic_cast(annotation); const AnnotationText* textAnnValue = dynamic_cast(annotationValue); if ((textAnn != NULL) && (textAnnValue != NULL)) { textAnn->setVerticalAlignment(textAnnValue->getVerticalAlignment()); } else { CaretAssert(0); } } break; case AnnotationRedoUndoCommandModeEnum::TEXT_CHARACTERS: { AnnotationText* textAnn = dynamic_cast(annotation); const AnnotationText* textAnnValue = dynamic_cast(annotationValue); if ((textAnn != NULL) && (textAnnValue != NULL)) { textAnn->setText(textAnnValue->getText()); } else { CaretAssert(0); } } break; case AnnotationRedoUndoCommandModeEnum::TEXT_COLOR: { AnnotationFontAttributesInterface* textAnn = dynamic_cast(annotation); const AnnotationFontAttributesInterface* textAnnValue = dynamic_cast(annotationValue); if ((textAnn != NULL) && (textAnnValue != NULL)) { textAnn->setTextColor(textAnnValue->getTextColor()); float rgba[4]; textAnnValue->getCustomTextColor(rgba); textAnn->setCustomTextColor(rgba); } else { CaretAssert(0); } CaretAssert(annotationValue); annotation->setLineColor(annotationValue->getLineColor()); float rgba[4]; annotationValue->getCustomLineColor(rgba); annotation->setCustomLineColor(rgba); } break; case AnnotationRedoUndoCommandModeEnum::TEXT_CONNECT_TO_BRAINORDINATE: { AnnotationText* textAnn = dynamic_cast(annotation); const AnnotationText* textAnnValue = dynamic_cast(annotationValue); if ((textAnn != NULL) && (textAnnValue != NULL)) { textAnn->setConnectToBrainordinate(textAnnValue->getConnectToBrainordinate()); } else { CaretAssert(0); } } break; case AnnotationRedoUndoCommandModeEnum::TEXT_FONT_BOLD: { AnnotationFontAttributesInterface* textAnn = dynamic_cast(annotation); const AnnotationFontAttributesInterface* textAnnValue = dynamic_cast(annotationValue); if ((textAnn != NULL) && (textAnnValue != NULL)) { textAnn->setBoldStyleEnabled(textAnnValue->isBoldStyleEnabled()); } else { CaretAssert(0); } } break; case AnnotationRedoUndoCommandModeEnum::TEXT_FONT_ITALIC: { AnnotationFontAttributesInterface* textAnn = dynamic_cast(annotation); const AnnotationFontAttributesInterface* textAnnValue = dynamic_cast(annotationValue); if ((textAnn != NULL) && (textAnnValue != NULL)) { textAnn->setItalicStyleEnabled(textAnnValue->isItalicStyleEnabled()); } else { CaretAssert(0); } } break; case AnnotationRedoUndoCommandModeEnum::TEXT_FONT_NAME: { AnnotationFontAttributesInterface* textAnn = dynamic_cast(annotation); const AnnotationFontAttributesInterface* textAnnValue = dynamic_cast(annotationValue); if ((textAnn != NULL) && (textAnnValue != NULL)) { textAnn->setFont(textAnnValue->getFont()); } else { CaretAssert(0); } } break; case AnnotationRedoUndoCommandModeEnum::TEXT_FONT_PERCENT_SIZE: { AnnotationFontAttributesInterface* textAnn = dynamic_cast(annotation); const AnnotationFontAttributesInterface* textAnnValue = dynamic_cast(annotationValue); if ((textAnn != NULL) && (textAnnValue != NULL)) { textAnn->setFontPercentViewportSize(textAnnValue->getFontPercentViewportSize()); } else { CaretAssert(0); } } break; case AnnotationRedoUndoCommandModeEnum::TEXT_FONT_POINT_SIZE: { AnnotationPointSizeText* textAnn = dynamic_cast(annotation); const AnnotationPointSizeText* textAnnValue = dynamic_cast(annotationValue); if ((textAnn != NULL) && (textAnnValue != NULL)) { textAnn->setFontPointSize(textAnnValue->getFontPointSize()); } else { CaretAssert(0); } } break; case AnnotationRedoUndoCommandModeEnum::TEXT_FONT_UNDERLINE: { AnnotationFontAttributesInterface* textAnn = dynamic_cast(annotation); const AnnotationFontAttributesInterface* textAnnValue = dynamic_cast(annotationValue); if ((textAnn != NULL) && (textAnnValue != NULL)) { textAnn->setUnderlineStyleEnabled(textAnnValue->isUnderlineStyleEnabled()); } else { CaretAssert(0); } } break; case AnnotationRedoUndoCommandModeEnum::TEXT_ORIENTATION: { AnnotationText* textAnn = dynamic_cast(annotation); const AnnotationText* textAnnValue = dynamic_cast(annotationValue); if ((textAnn != NULL) && (textAnnValue != NULL)) { textAnn->setOrientation(textAnnValue->getOrientation()); } else { CaretAssert(0); } } break; case AnnotationRedoUndoCommandModeEnum::TWO_DIM_HEIGHT: { AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(annotation); const AnnotationTwoDimensionalShape* twoDimValue = dynamic_cast(annotationValue); if ((twoDimAnn != NULL) && (twoDimValue != NULL)) { twoDimAnn->setHeight(twoDimValue->getHeight()); } else { CaretAssert(0); } } break; case AnnotationRedoUndoCommandModeEnum::TWO_DIM_WIDTH: { AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(annotation); const AnnotationTwoDimensionalShape* twoDimValue = dynamic_cast(annotationValue); if ((twoDimAnn != NULL) && (twoDimValue != NULL)) { twoDimAnn->setWidth(twoDimValue->getWidth()); } else { CaretAssert(0); } } break; } } /** * Operation that "redoes" the command. * * @param errorMessageOut * Output containing error message. * @return * True if the command executed successfully, else false. */ bool AnnotationRedoUndoCommand::redo(AString& errorMessageOut) { errorMessageOut.clear(); if (m_mode == AnnotationRedoUndoCommandModeEnum::GROUPING_GROUP) { CaretAssert(m_annotationGroupMemento); EventAnnotationGrouping groupEvent; groupEvent.setModeGroupAnnotations(getWindowIndex(), m_annotationGroupMemento->m_annotationGroupKey, m_annotationGroupMemento->m_annotations); EventManager::get()->sendEvent(groupEvent.getPointer()); m_annotationGroupMemento->setUndoAnnotationGroupKey(groupEvent.getGroupKeyToWhichAnnotationsWereMoved()); if (groupEvent.isError()) { errorMessageOut = groupEvent.getErrorMessage(); return false; } return true; } else if (m_mode == AnnotationRedoUndoCommandModeEnum::GROUPING_UNGROUP) { CaretAssert(m_annotationGroupMemento); EventAnnotationGrouping groupEvent; groupEvent.setModeUngroupAnnotations(getWindowIndex(), m_annotationGroupMemento->m_annotationGroupKey); EventManager::get()->sendEvent(groupEvent.getPointer()); if (groupEvent.isError()) { errorMessageOut = groupEvent.getErrorMessage(); return false; } return true; } else if (m_mode == AnnotationRedoUndoCommandModeEnum::GROUPING_REGROUP) { CaretAssert(m_annotationGroupMemento); EventAnnotationGrouping groupEvent; groupEvent.setModeRegroupAnnotations(getWindowIndex(), m_annotationGroupMemento->m_annotationGroupKey); EventManager::get()->sendEvent(groupEvent.getPointer()); m_annotationGroupMemento->setUndoAnnotationGroupKey(groupEvent.getGroupKeyToWhichAnnotationsWereMoved()); if (groupEvent.isError()) { errorMessageOut = groupEvent.getErrorMessage(); return false; } return true; } bool validFlag = true; for (std::vector::iterator iter = m_annotationMementos.begin(); iter != m_annotationMementos.end(); iter++) { const AnnotationMemento* annMem = *iter; CaretAssert(annMem); if (m_mode == AnnotationRedoUndoCommandModeEnum::CREATE_ANNOTATION) { EventAnnotationAddToRemoveFromFile event(EventAnnotationAddToRemoveFromFile::MODE_CREATE, annMem->m_annotationFile, annMem->m_annotation); EventManager::get()->sendEvent(event.getPointer()); if (event.isError()) { errorMessageOut.appendWithNewLine(event.getErrorMessage()); validFlag = false; } } else if (m_mode == AnnotationRedoUndoCommandModeEnum::CUT_ANNOTATION) { EventAnnotationAddToRemoveFromFile event(EventAnnotationAddToRemoveFromFile::MODE_CUT, annMem->m_annotationFile, annMem->m_annotation); EventManager::get()->sendEvent(event.getPointer()); if (event.isError()) { errorMessageOut.appendWithNewLine(event.getErrorMessage()); validFlag = false; } } else if (m_mode == AnnotationRedoUndoCommandModeEnum::DELETE_ANNOTATIONS) { EventAnnotationAddToRemoveFromFile event(EventAnnotationAddToRemoveFromFile::MODE_DELETE, annMem->m_annotationFile, annMem->m_annotation); EventManager::get()->sendEvent(event.getPointer()); if (event.isError()) { errorMessageOut.appendWithNewLine(event.getErrorMessage()); validFlag = false; } } else if (m_mode == AnnotationRedoUndoCommandModeEnum::DUPLICATE_ANNOTATION) { EventAnnotationAddToRemoveFromFile duplicateEvent(EventAnnotationAddToRemoveFromFile::MODE_DUPLICATE, annMem->m_annotationFile, annMem->m_annotation); EventManager::get()->sendEvent(duplicateEvent.getPointer()); if (duplicateEvent.isError()) { errorMessageOut.appendWithNewLine(duplicateEvent.getErrorMessage()); validFlag = false; } } else if (m_mode == AnnotationRedoUndoCommandModeEnum::PASTE_ANNOTATION) { EventAnnotationAddToRemoveFromFile pasteEvent(EventAnnotationAddToRemoveFromFile::MODE_PASTE, annMem->m_annotationFile, annMem->m_annotation); EventManager::get()->sendEvent(pasteEvent.getPointer()); if (pasteEvent.isError()) { errorMessageOut.appendWithNewLine(pasteEvent.getErrorMessage()); validFlag = false; } } else { /* * Note: Does not report any errors */ applyRedoOrUndo(annMem->m_annotation, annMem->m_redoAnnotation); } } return validFlag; } /** * Operation that "undoes" the command. * * @param errorMessageOut * Output containing error message. * @return * True if the command executed successfully, else false. */ bool AnnotationRedoUndoCommand::undo(AString& errorMessageOut) { errorMessageOut.clear(); if (m_mode == AnnotationRedoUndoCommandModeEnum::GROUPING_GROUP) { CaretAssert(m_annotationGroupMemento); EventAnnotationGrouping groupEvent; groupEvent.setModeUngroupAnnotations(getWindowIndex(), m_annotationGroupMemento->m_undoAnnotationGroupKey); EventManager::get()->sendEvent(groupEvent.getPointer()); if (groupEvent.isError()) { errorMessageOut = groupEvent.getErrorMessage(); return false; } return true; } else if (m_mode == AnnotationRedoUndoCommandModeEnum::GROUPING_UNGROUP) { CaretAssert(m_annotationGroupMemento); EventAnnotationGrouping groupEvent; groupEvent.setModeRegroupAnnotations(getWindowIndex(), m_annotationGroupMemento->m_annotationGroupKey); EventManager::get()->sendEvent(groupEvent.getPointer()); if (groupEvent.isError()) { errorMessageOut = groupEvent.getErrorMessage(); return false; } return true; } else if (m_mode == AnnotationRedoUndoCommandModeEnum::GROUPING_REGROUP) { CaretAssert(m_annotationGroupMemento); EventAnnotationGrouping groupEvent; groupEvent.setModeUngroupAnnotations(getWindowIndex(), m_annotationGroupMemento->m_undoAnnotationGroupKey); EventManager::get()->sendEvent(groupEvent.getPointer()); m_annotationGroupMemento->setUndoAnnotationGroupKey(groupEvent.getGroupKeyToWhichAnnotationsWereMoved()); if (groupEvent.isError()) { errorMessageOut = groupEvent.getErrorMessage(); return false; } return true; } bool validFlag = true; for (std::vector::iterator iter = m_annotationMementos.begin(); iter != m_annotationMementos.end(); iter++) { const AnnotationMemento* annMem = *iter; CaretAssert(annMem); if (m_mode == AnnotationRedoUndoCommandModeEnum::CREATE_ANNOTATION) { EventAnnotationAddToRemoveFromFile event(EventAnnotationAddToRemoveFromFile::MODE_UNCREATE, annMem->m_annotationFile, annMem->m_annotation); EventManager::get()->sendEvent(event.getPointer()); if (event.isError()) { errorMessageOut.appendWithNewLine(event.getErrorMessage()); validFlag = false; } } else if (m_mode == AnnotationRedoUndoCommandModeEnum::CUT_ANNOTATION) { EventAnnotationAddToRemoveFromFile event(EventAnnotationAddToRemoveFromFile::MODE_UNCUT, annMem->m_annotationFile, annMem->m_annotation); EventManager::get()->sendEvent(event.getPointer()); if (event.isError()) { errorMessageOut.appendWithNewLine(event.getErrorMessage()); validFlag = false; } } else if (m_mode == AnnotationRedoUndoCommandModeEnum::DELETE_ANNOTATIONS) { EventAnnotationAddToRemoveFromFile event(EventAnnotationAddToRemoveFromFile::MODE_UNDELETE, annMem->m_annotationFile, annMem->m_annotation); EventManager::get()->sendEvent(event.getPointer()); if (event.isError()) { errorMessageOut.appendWithNewLine(event.getErrorMessage()); validFlag = false; } } else if (m_mode == AnnotationRedoUndoCommandModeEnum::DUPLICATE_ANNOTATION) { EventAnnotationAddToRemoveFromFile duplicateEvent(EventAnnotationAddToRemoveFromFile::MODE_UNDUPLICATE, annMem->m_annotationFile, annMem->m_annotation); EventManager::get()->sendEvent(duplicateEvent.getPointer()); if (duplicateEvent.isError()) { errorMessageOut.appendWithNewLine(duplicateEvent.getErrorMessage()); validFlag = false; } } else if (m_mode == AnnotationRedoUndoCommandModeEnum::PASTE_ANNOTATION) { EventAnnotationAddToRemoveFromFile pasteEvent(EventAnnotationAddToRemoveFromFile::MODE_UNPASTE, annMem->m_annotationFile, annMem->m_annotation); EventManager::get()->sendEvent(pasteEvent.getPointer()); if (pasteEvent.isError()) { errorMessageOut.appendWithNewLine(pasteEvent.getErrorMessage()); validFlag = false; } } else { applyRedoOrUndo(annMem->m_annotation, annMem->m_undoAnnotation); } } return validFlag; } /** * @return Is the command valid? */ bool AnnotationRedoUndoCommand::isValid() const { if (m_annotationMementos.size() > 0) { return true; } else if (m_annotationGroupMemento != NULL) { return true; } return false; } /** * Attempts to merge this command with command. Returns true on success; otherwise returns false. * * If this function returns true, calling this command's redo() must have the same effect as * redoing both this command and command. Similarly, calling this command's undo() must have * the same effect as undoing command and this command. * * @return True if the given command was merged with this command, else false. */ bool AnnotationRedoUndoCommand::mergeWith(const CaretUndoCommand* command) { const AnnotationRedoUndoCommand* otherCommand = dynamic_cast(command); CaretAssert(otherCommand); /* * Assume compatibility if same mode and applied to same number of annotations. */ if (m_mode != otherCommand->m_mode) { return false; } if (m_annotationMementos.size() != otherCommand->m_annotationMementos.size()) { return false; } /* * Sort mementos so that the standard library's equal() function * can compare the annotation pointers */ sortAnnotationMementos(); otherCommand->sortAnnotationMementos(); /* * Compare to verify that the corresponding annotation mementos * are the same. */ if ( ! std::equal(m_annotationMementos.begin(), m_annotationMementos.end(), otherCommand->m_annotationMementos.begin(), AnnotationRedoUndoCommand::equalAnnotationMemento)) { return false; } const int32_t numAnnMem = static_cast(m_annotationMementos.size()); for (int32_t i = 0; i < numAnnMem; i++) { CaretAssertVectorIndex(m_annotationMementos, i); CaretAssertVectorIndex(otherCommand->m_annotationMementos, i); delete m_annotationMementos[i]->m_redoAnnotation; m_annotationMementos[i]->m_redoAnnotation = otherCommand->m_annotationMementos[i]->m_redoAnnotation->clone(); } return true; } /** * Set them mode to first coordinate and create the redo/undo instances. * * @param coordinate * New value of the coordinate. * @param annotations * Annotations that receive this new coordinate. */ void AnnotationRedoUndoCommand::setModeCoordinateOne(const AnnotationCoordinate& coordinate, const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::COORDINATE_ONE; setDescription("Coordinate"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); Annotation* redoAnnotation = annotation->clone(); AnnotationOneDimensionalShape* oneDimShape = dynamic_cast(redoAnnotation); AnnotationTwoDimensionalShape* twoDimShape = dynamic_cast(redoAnnotation); AnnotationCoordinate* redoCoordinate = NULL; if (oneDimShape != NULL) { redoCoordinate = oneDimShape->getStartCoordinate(); } else if (twoDimShape != NULL) { redoCoordinate = twoDimShape->getCoordinate(); } if (redoCoordinate != NULL) { *redoCoordinate = coordinate; Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } else { delete redoAnnotation; } } } /** * Set them mode to second coordinate and create the redo/undo instances. * * @param coordinateOne * New value of the coordinate one. * @param coordinateTwo * New value of the coordinate two. * @param annotations * Annotations that receive this new coordinate. */ void AnnotationRedoUndoCommand::setModeCoordinateOneAndTwo(const AnnotationCoordinate& coordinateOne, const AnnotationCoordinate& coordinateTwo, const std::vector annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::COORDINATE_ONE_AND_TWO; setDescription("Coordinate"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); Annotation* redoAnnotation = annotation->clone(); AnnotationOneDimensionalShape* oneDimShape = dynamic_cast(redoAnnotation); if (oneDimShape != NULL) { AnnotationCoordinate* redoCoordinateOne = oneDimShape->getStartCoordinate(); CaretAssert(redoCoordinateOne); AnnotationCoordinate* redoCoordinateTwo = oneDimShape->getEndCoordinate(); CaretAssert(redoCoordinateTwo); *redoCoordinateOne = coordinateOne; *redoCoordinateTwo = coordinateTwo; Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } else { delete redoAnnotation; } } } /** * Set them mode to location and size of annotations (coords, size, space, window, tab) * * @param annotationsBeforeMoveAndResize * Annotations before move and resize has been applied. * @param annotationsAfterMoveAndResize * Corresponding annotations after move and resize has been applied. */ void AnnotationRedoUndoCommand::setModeLocationAndSize(const std::vector& annotationsBeforeMoveAndResize, const std::vector& annotationsAfterMoveAndResize) { const int32_t numAnnotations = static_cast(annotationsBeforeMoveAndResize.size()); if (numAnnotations != static_cast(annotationsAfterMoveAndResize.size())) { CaretAssertMessage(0, "Number of annotations must be the same"); CaretLogSevere("Number of annotations must be the same"); return; } m_mode = AnnotationRedoUndoCommandModeEnum::LOCATION_AND_SIZE; if (numAnnotations == 1) { setDescription("Reshape Annotation"); } else { setDescription("Reshape Annotations"); } for (int32_t i = 0; i < numAnnotations; i++) { CaretAssertVectorIndex(annotationsBeforeMoveAndResize, i); CaretAssertVectorIndex(annotationsAfterMoveAndResize, i); Annotation* annBefore = annotationsBeforeMoveAndResize[i]; const Annotation* annAfter = annotationsAfterMoveAndResize[i]; CaretAssert(annBefore); CaretAssert(annAfter); CaretAssert(annBefore->getType() == annAfter->getType()); Annotation* undoAnnotation = annBefore->clone(); Annotation* redoAnnotation = annAfter->clone(); AnnotationMemento* am = new AnnotationMemento(annBefore, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } /** * Set them mode to second coordinate and create the redo/undo instances. * * @param coordinate * New value of the coordinate. * @param annotations * Annotations that receive this new coordinate. */ void AnnotationRedoUndoCommand::setModeCoordinateTwo(const AnnotationCoordinate& coordinate, const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::COORDINATE_TWO; setDescription("Coordinate"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); Annotation* redoAnnotation = annotation->clone(); AnnotationOneDimensionalShape* oneDimShape = dynamic_cast(redoAnnotation); AnnotationCoordinate* redoCoordinate = NULL; if (oneDimShape != NULL) { redoCoordinate = oneDimShape->getEndCoordinate(); } if (redoCoordinate != NULL) { *redoCoordinate = coordinate; Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } else { delete redoAnnotation; } } } /** * Set them mode to line arrow start and create the redo/undo instances. * * @param newStatus * New status of line arrow at start of line. * @param annotations * Annotation that receive this new color. */ void AnnotationRedoUndoCommand::setModeLineArrowStart(const bool newStatus, const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::LINE_ARROW_START; setDescription("Line Arrow Start"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); if (annotation->getType() == AnnotationTypeEnum::LINE) { AnnotationLine* redoAnnotation = dynamic_cast(annotation->clone()); redoAnnotation->setDisplayStartArrow(newStatus); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } } /** * Set them mode to line arrow end and create the redo/undo instances. * * @param newStatus * New status of line arrow at end of line. * @param annotations * Annotation that receive this new color. */ void AnnotationRedoUndoCommand::setModeLineArrowEnd(const bool newStatus, const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::LINE_ARROW_END; setDescription("Line Arrow End"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); if (annotation->getType() == AnnotationTypeEnum::LINE) { AnnotationLine* redoAnnotation = dynamic_cast(annotation->clone()); redoAnnotation->setDisplayEndArrow(newStatus); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } } /** * Set them mode to line width and create the redo/undo instances. * * @param newLineWidth * New line width. * @param annotations * Annotation that receive this new line width. */ void AnnotationRedoUndoCommand::setModeLineWidth(const float newLineWidth, const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::LINE_WIDTH_FOREGROUND; setDescription("Line Width"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); Annotation* redoAnnotation = annotation->clone(); redoAnnotation->setLineWidthPercentage(newLineWidth); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } /** * Set the mode to color background and create the undo/redo instances. * * @param color * The new background color. * @param customColor * The new custom background color. * @param annotations * Annotation that receive this new color. */ void AnnotationRedoUndoCommand::setModeColorBackground(const CaretColorEnum::Enum color, const float customColor[4], const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::COLOR_BACKGROUND; setDescription("Background Color"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); Annotation* redoAnnotation = annotation->clone(); redoAnnotation->setBackgroundColor(color); redoAnnotation->setCustomBackgroundColor(customColor); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } /** * Set the mode to line color and create the undo/redo instances. * * @param color * The new line color. * @param customColor * The new custom line color. * @param annotations * Annotation that receive this new color. */ void AnnotationRedoUndoCommand::setModeColorLine(const CaretColorEnum::Enum color, const float customColor[4], const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::COLOR_FOREGROUND; setDescription("Line Color"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); Annotation* redoAnnotation = annotation->clone(); redoAnnotation->setLineColor(color); redoAnnotation->setCustomLineColor(customColor); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } /** * Set the mode to add new annotation and create the undo/redo instances. * * @param annotationFile * File to which annotation is pasted. * @param annotations * Annotation that are pasted. */ void AnnotationRedoUndoCommand::setModeCreateAnnotation(AnnotationFile* annotationFile, Annotation* annotation) { m_mode = AnnotationRedoUndoCommandModeEnum::CREATE_ANNOTATION; setDescription("Create Annotation"); CaretAssert(annotationFile); CaretAssert(annotation); /* * NOTE: We only need the pointer since the file containing * the annotation will handle delete/undelete of the * annotation. If we don't use NULL for the redo and * undo annotations, copies of the annotation would be * needed since the AnnotationMemento will delete * the redo and undo annotations when it is deleted. */ AnnotationMemento* am = new AnnotationMemento(annotationFile, annotation, NULL, NULL); m_annotationMementos.push_back(am); } /** * Set the mode to cut annotations and create the undo/redo instances. * * @param annotations * Annotation that are cut. */ void AnnotationRedoUndoCommand::setModeCutAnnotations(const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::CUT_ANNOTATION; setDescription("Cut Annotation"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); /* * NOTE: We only need the pointer since the file containing * the annotation will handle delete/undelete of the * annotation. If we don't use NULL for the redo and * undo annotations, copies of the annotation would be * needed since the AnnotationMemento will delete * the redo and undo annotations when it is deleted. */ AnnotationMemento* am = new AnnotationMemento(annotation, NULL, NULL); m_annotationMementos.push_back(am); } } /** * Set the mode to delete annotations and create the undo/redo instances. * * @param annotations * Annotation that are deleted. */ void AnnotationRedoUndoCommand::setModeDeleteAnnotations(const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::DELETE_ANNOTATIONS; if (annotations.size() > 1) { setDescription("Delete Annotations"); } else { setDescription("Delete Annotation"); } for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); /* * NOTE: We only need the pointer since the file containing * the annotation will handle delete/undelete of the * annotation. If we don't use NULL for the redo and * undo annotations, copies of the annotation would be * needed since the AnnotationMemento will delete * the redo and undo annotations when it is deleted. */ AnnotationMemento* am = new AnnotationMemento(annotation, NULL, NULL); m_annotationMementos.push_back(am); } } /** * Set the mode to move annotations into a user group. * * @param annotationGroupKey * Group key for source of annotations. * @param annotations * Annotations that will be moved to a user group. */ void AnnotationRedoUndoCommand::setModeGroupingGroupAnnotations(const AnnotationGroupKey& annotationGroupKey, const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::GROUPING_GROUP; setDescription("Group Annotations"); m_annotationGroupMemento = new AnnotationGroupMemento(annotationGroupKey, annotations); } /** * Set the mode to remove annotations from a user group. * * @param annotationGroupKey * Group key of user group containing annotations. */ void AnnotationRedoUndoCommand::setModeGroupingUngroupAnnotations(const AnnotationGroupKey& annotationGroupKey) { m_mode = AnnotationRedoUndoCommandModeEnum::GROUPING_UNGROUP; setDescription("Ungroup Annotations"); std::vector emptyAnnotations; m_annotationGroupMemento = new AnnotationGroupMemento(annotationGroupKey, emptyAnnotations); } /** * Set the mode to move annotations back to a previous user group. * * @param annotationGroupKey * Group key of previous user group. */ void AnnotationRedoUndoCommand::setModeGroupingRegroupAnnotations(const AnnotationGroupKey& annotationGroupKey) { m_mode = AnnotationRedoUndoCommandModeEnum::GROUPING_REGROUP; setDescription("Regroup Annotations"); std::vector emptyAnnotations; m_annotationGroupMemento = new AnnotationGroupMemento(annotationGroupKey, emptyAnnotations); } /** * Set the mode to paste annotations and create the undo/redo instances. * * @param annotationFile * File to which annotation is pasted. * @param annotations * Annotation that are pasted. */ void AnnotationRedoUndoCommand::setModePasteAnnotation(AnnotationFile* annotationFile, Annotation* annotation) { m_mode = AnnotationRedoUndoCommandModeEnum::PASTE_ANNOTATION; setDescription("Paste Annotation"); CaretAssert(annotationFile); CaretAssert(annotation); /* * NOTE: We only need the pointer since the file containing * the annotation will handle delete/undelete of the * annotation. If we don't use NULL for the redo and * undo annotations, copies of the annotation would be * needed since the AnnotationMemento will delete * the redo and undo annotations when it is deleted. */ AnnotationMemento* am = new AnnotationMemento(annotationFile, annotation, NULL, NULL); m_annotationMementos.push_back(am); } /** * Set the mode to duplicate annotations and create the undo/redo instances. * * @param annotationFile * File to which annotation is pasted. * @param annotations * The new anntotation duplicated from existing annotation. */ void AnnotationRedoUndoCommand::setModeDuplicateAnnotation(AnnotationFile* annotationFile, Annotation* annotation) { m_mode = AnnotationRedoUndoCommandModeEnum::DUPLICATE_ANNOTATION; setDescription("Duplicate Annotation"); CaretAssert(annotationFile); CaretAssert(annotation); /* * NOTE: We only need the pointer since the file containing * the annotation will handle delete/undelete of the * annotation. If we don't use NULL for the redo and * undo annotations, copies of the annotation would be * needed since the AnnotationMemento will delete * the redo and undo annotations when it is deleted. */ AnnotationMemento* am = new AnnotationMemento(annotationFile, annotation, NULL, NULL); m_annotationMementos.push_back(am); } /** * Set the mode to rotation angle and create the undo/redo instances * * @param newRotationAngle * The new rotation angle * @param annotations * Annotations that receive this new rotation angle */ void AnnotationRedoUndoCommand::setModeRotationAngle(const float newRotationAngle, const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::ROTATION_ANGLE; setDescription("Rotation Angle"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(annotation); AnnotationOneDimensionalShape* oneDimAnn = dynamic_cast(annotation); if (twoDimAnn != NULL) { AnnotationTwoDimensionalShape* redoAnnotation = dynamic_cast(annotation->clone()); CaretAssert(redoAnnotation); redoAnnotation->setRotationAngle(newRotationAngle); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } else if (oneDimAnn != NULL) { int32_t viewport[4] = { 0, 0, 0, 0 }; bool viewportValid = false; switch (oneDimAnn->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: { const int tabIndex = oneDimAnn->getTabIndex(); EventGetViewportSize vpSizeEvent(EventGetViewportSize::MODE_TAB_AFTER_MARGINS_INDEX, tabIndex); EventManager::get()->sendEvent(vpSizeEvent.getPointer()); if (vpSizeEvent.isViewportSizeValid()) { vpSizeEvent.getViewportSize(viewport); viewportValid = true; } } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: { const int windowIndex = oneDimAnn->getWindowIndex(); EventGetViewportSize vpSizeEvent(EventGetViewportSize::MODE_WINDOW_INDEX, windowIndex); EventManager::get()->sendEvent(vpSizeEvent.getPointer()); if (vpSizeEvent.isViewportSizeValid()) { vpSizeEvent.getViewportSize(viewport); viewportValid = true; } } break; } if (viewportValid) { const float vpWidth = viewport[2]; const float vpHeight = viewport[3]; float annOneX = 0.0; float annOneY = 0.0; float annTwoX = 0.0; float annTwoY = 0.0; oneDimAnn->getStartCoordinate()->getViewportXY(vpWidth, vpHeight, annOneX, annOneY); oneDimAnn->getEndCoordinate()->getViewportXY(vpWidth, vpHeight, annTwoX, annTwoY); const bool rotateAroundMiddleFlag = true; if (rotateAroundMiddleFlag) { AnnotationOneDimensionalShape* redoAnnotation = dynamic_cast(annotation->clone()); CaretAssert(redoAnnotation); redoAnnotation->setRotationAngle(vpWidth, vpHeight, newRotationAngle); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } else { const float vpOneXYZ[3] = { annOneX, annOneY, 0.0 }; const float vpTwoXYZ[3] = { annTwoX, annTwoY, 0.0 }; const float length = MathFunctions::distance3D(vpOneXYZ, vpTwoXYZ); const float angleRadians = MathFunctions::toRadians(-newRotationAngle); const float dy = length * std::sin(angleRadians); const float dx = length * std::cos(angleRadians); annTwoX = annOneX + dx; annTwoY = annOneY + dy; AnnotationOneDimensionalShape* redoAnnotation = dynamic_cast(annotation->clone()); CaretAssert(redoAnnotation); redoAnnotation->getEndCoordinate()->setXYZFromViewportXYZ(vpWidth, vpHeight, annTwoX, annTwoY); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } } } } /** * Set the mode to horizontal text alignment and create the undo/redo instances * * @param newHorizontalAlignment * The new horizontal alignment * @param annotations * Annotation that receive this new text. */ void AnnotationRedoUndoCommand::setModeTextAlignmentHorizontal(const AnnotationTextAlignHorizontalEnum::Enum newHorizontalAlignment, const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::TEXT_ALIGNMENT_HORIZONTAL; setDescription("Text Horizontal Alignment"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); if (annotation->getType() == AnnotationTypeEnum::TEXT) { AnnotationText* redoAnnotation = dynamic_cast(annotation->clone()); CaretAssert(redoAnnotation); redoAnnotation->setHorizontalAlignment(newHorizontalAlignment); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } } /** * Set the mode to vertical text alignment and create the undo/redo instances * * @param newVerticalAlignment * The new vertical alignment * @param annotations * Annotation that receive this new text. */ void AnnotationRedoUndoCommand::setModeTextAlignmentVertical(const AnnotationTextAlignVerticalEnum::Enum newVerticalAlignment, const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::TEXT_ALIGNMENT_VERTICAL; setDescription("Text Vertical Alignment"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); if (annotation->getType() == AnnotationTypeEnum::TEXT) { AnnotationText* redoAnnotation = dynamic_cast(annotation->clone()); CaretAssert(redoAnnotation); redoAnnotation->setVerticalAlignment(newVerticalAlignment); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } } /** * Set the mode to text characters and create the undo/redo instances. * * @param text * The text . * @param annotations * Annotation that receive this new text. */ void AnnotationRedoUndoCommand::setModeTextCharacters(const AString& text, const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::TEXT_CHARACTERS; setDescription("Text Characters"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); AnnotationText* redoAnnotation = NULL; switch (annotation->getType()) { case AnnotationTypeEnum::BOX: break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: break; case AnnotationTypeEnum::LINE: break; case AnnotationTypeEnum::OVAL: break; case AnnotationTypeEnum::TEXT: redoAnnotation = dynamic_cast(annotation->clone()); break; } /* * This method should only get call for text-type annotations. */ CaretAssert(redoAnnotation); if (redoAnnotation != NULL) { redoAnnotation->setText(text); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } } /** * Set the mode to text color and create the undo/redo instances. * * @param color * The color enum. * @param customColor * The custom color components. * @param annotations * Annotation that receive this new color. */ void AnnotationRedoUndoCommand::setModeTextColor(const CaretColorEnum::Enum color, const float customColor[4], const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::TEXT_COLOR; setDescription("Text Color"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); AnnotationFontAttributesInterface* fontStyleAnn = dynamic_cast(annotation); if (fontStyleAnn != NULL) { Annotation* redoAnnotation = annotation->clone(); AnnotationFontAttributesInterface* redoAnnotationFontStyle = dynamic_cast(redoAnnotation); CaretAssert(redoAnnotationFontStyle); redoAnnotationFontStyle->setTextColor(color); redoAnnotationFontStyle->setCustomTextColor(customColor); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } } /** * Set the mode to text connect to brainordinate and create the undo/redo instances. * * @param newConnectType * New value for connect to brainordinate. * @param annotations * Annotation that receive this new status. */ void AnnotationRedoUndoCommand::setModeTextConnectToBrainordinate(const AnnotationTextConnectTypeEnum::Enum newConnectType, const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::TEXT_CONNECT_TO_BRAINORDINATE; setDescription("Text Connect to Brainordinate"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); if (annotation->getType() == AnnotationTypeEnum::TEXT) { AnnotationText* redoAnnotation = dynamic_cast(annotation->clone()); CaretAssert(redoAnnotation); redoAnnotation->setConnectToBrainordinate(newConnectType); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } } /** * Set the mode to text font bold and create the undo/redo instances. * * @param newStatus * New status for font bold. * @param annotations * Annotation that receive this new status. */ void AnnotationRedoUndoCommand::setModeTextFontBold(const bool newStatus, const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::TEXT_FONT_BOLD; setDescription("Text Bold"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); AnnotationFontAttributesInterface* fontStyleAnn = dynamic_cast(annotation); if (fontStyleAnn != NULL) { Annotation* redoAnnotation = annotation->clone(); AnnotationFontAttributesInterface* redoAnnotationFontStyle = dynamic_cast(redoAnnotation); CaretAssert(redoAnnotationFontStyle); redoAnnotationFontStyle->setBoldStyleEnabled(newStatus); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } } /** * Set the mode to text font italic and create the undo/redo instances. * * @param newStatus * New status for font italic. * @param annotations * Annotation that receive this new status. */ void AnnotationRedoUndoCommand::setModeTextFontItalic(const bool newStatus, const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::TEXT_FONT_ITALIC; setDescription("Text Italic"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); AnnotationFontAttributesInterface* fontStyleAnn = dynamic_cast(annotation); if (fontStyleAnn != NULL) { Annotation* redoAnnotation = annotation->clone(); AnnotationFontAttributesInterface* redoAnnotationFontStyle = dynamic_cast(redoAnnotation); CaretAssert(redoAnnotationFontStyle); redoAnnotationFontStyle->setItalicStyleEnabled(newStatus); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } } /** * Set the mode to font name and create the undo/redo instances. * * @param newFontName * New font name * @param annotations * Annotation that receive this font name */ void AnnotationRedoUndoCommand::setModeTextFontName(const AnnotationTextFontNameEnum::Enum newFontName, const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::TEXT_FONT_NAME; setDescription("Text Font Name"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); AnnotationFontAttributesInterface* fontStyleAnn = dynamic_cast(annotation); if (fontStyleAnn != NULL) { Annotation* redoAnnotation = annotation->clone(); AnnotationFontAttributesInterface* redoAnnotationFontStyle = dynamic_cast(redoAnnotation); CaretAssert(redoAnnotationFontStyle); redoAnnotationFontStyle->setFont(newFontName); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } } /** * Set the mode to font size and create the undo/redo instances. * * @param newFontPointSize * New font point size * @param annotations * Annotation that receive this font size */ void AnnotationRedoUndoCommand::setModeTextFontPointSize(const AnnotationTextFontPointSizeEnum::Enum newFontPointSize, const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::TEXT_FONT_POINT_SIZE; setDescription("Text Font Point Size"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); if (annotation->getType() == AnnotationTypeEnum::TEXT) { AnnotationPointSizeText* redoAnnotation = dynamic_cast(annotation->clone()); CaretAssert(redoAnnotation); redoAnnotation->setFontPointSize(newFontPointSize); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } } /** * Set the mode to font percent size and create the undo/redo instances. * * @param newFontPercentSize * New font percentage size * @param annotations * Annotation that receive this font size */ void AnnotationRedoUndoCommand::setModeTextFontPercentSize(const float newFontPercentSize, const std::vector& annotations, const float surfaceSpaceRowCount) { m_mode = AnnotationRedoUndoCommandModeEnum::TEXT_FONT_PERCENT_SIZE; setDescription("Text Font Percent Size"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); AnnotationFontAttributesInterface* fontStyleAnn = dynamic_cast(annotation); if (fontStyleAnn != NULL) { Annotation* redoAnnotation = annotation->clone(); AnnotationFontAttributesInterface* redoAnnotationFontStyle = dynamic_cast(redoAnnotation); CaretAssert(redoAnnotationFontStyle); float percentSize = newFontPercentSize; switch (redoAnnotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: percentSize *= surfaceSpaceRowCount; break; case AnnotationCoordinateSpaceEnum::SURFACE: percentSize *= surfaceSpaceRowCount; break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } redoAnnotationFontStyle->setFontPercentViewportSize(percentSize); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } } /** * Set the mode to text font underline and create the undo/redo instances. * * @param newStatus * New status for font undeline. * @param annotations * Annotation that receive this new status. */ void AnnotationRedoUndoCommand::setModeTextFontUnderline(const bool newStatus, const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::TEXT_FONT_UNDERLINE; setDescription("Text Underline"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); AnnotationFontAttributesInterface* fontStyleAnn = dynamic_cast(annotation); if (fontStyleAnn != NULL) { Annotation* redoAnnotation = annotation->clone(); AnnotationFontAttributesInterface* redoAnnotationFontStyle = dynamic_cast(redoAnnotation); CaretAssert(redoAnnotationFontStyle); redoAnnotationFontStyle->setUnderlineStyleEnabled(newStatus); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } } /** * Set the mode to vertical text alignment and create the undo/redo instances * * @param newVerticalAlignment * The new vertical alignment * @param annotations * Annotation that receive this new text. */ void AnnotationRedoUndoCommand::setModeTextOrientation(const AnnotationTextOrientationEnum::Enum newTextOrientation, const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::TEXT_ORIENTATION; setDescription("Text Orientation"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); if (annotation->getType() == AnnotationTypeEnum::TEXT) { AnnotationText* redoAnnotation = dynamic_cast(annotation->clone()); CaretAssert(redoAnnotation); redoAnnotation->setOrientation(newTextOrientation); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } } /** * Set the mode to two dim height and create the undo/redo instances * * @param newHeight * The new height * @param annotations * Annotation that receive this new text. */ void AnnotationRedoUndoCommand::setModeTwoDimHeight(const float newHeight, const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::TWO_DIM_HEIGHT; setDescription("Height"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(annotation); if (twoDimAnn != NULL) { AnnotationTwoDimensionalShape* redoAnnotation = dynamic_cast(annotation->clone()); CaretAssert(redoAnnotation); redoAnnotation->setHeight(newHeight); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } } /** * Set the mode to two dim width and create the undo/redo instances * * @param newWidth * The new vertical alignment * @param annotations * Annotation that receive this new text. */ void AnnotationRedoUndoCommand::setModeTwoDimWidth(const float newWidth, const std::vector& annotations) { m_mode = AnnotationRedoUndoCommandModeEnum::TWO_DIM_WIDTH; setDescription("Width"); for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* annotation = *iter; CaretAssert(annotation); AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(annotation); if (twoDimAnn != NULL) { AnnotationTwoDimensionalShape* redoAnnotation = dynamic_cast(annotation->clone()); CaretAssert(redoAnnotation); redoAnnotation->setWidth(newWidth); Annotation* undoAnnotation = annotation->clone(); AnnotationMemento* am = new AnnotationMemento(annotation, redoAnnotation, undoAnnotation); m_annotationMementos.push_back(am); } } } /** * Compare the two annotation mementos using the annotation pointer. * * @param am1 * Left side for comparison. * @param am2 * Right side for comparison. * @return * True if left side's annotation pointer is equal to the right side's annotation pointer. */ bool AnnotationRedoUndoCommand::equalAnnotationMemento(const AnnotationMemento* am1, const AnnotationMemento* am2) { CaretAssert(am1); CaretAssert(am2); return (am1->m_annotation == am2->m_annotation); } /** * Compare the two annotation mementos using the annotation pointer. * * @param am1 * Left side for comparison. * @param am2 * Right side for comparison. * @return * True if left side's annotation pointer is less than right side's annotation pointer. */ bool AnnotationRedoUndoCommand::lessThanAnnotationMemento(const AnnotationMemento* am1, const AnnotationMemento* am2) { CaretAssert(am1); CaretAssert(am2); return (am1->m_annotation < am2->m_annotation); } /** * Sort the annotation mementos in this redo/undo command. * The mergeWith() method needs to compare the mementos * in two command and when the mementos are sorted, * it allows faster comparison. */ void AnnotationRedoUndoCommand::sortAnnotationMementos() const { if (m_sortedFlag) { return; } std::sort(m_annotationMementos.begin(), m_annotationMementos.end(), AnnotationRedoUndoCommand::lessThanAnnotationMemento); m_sortedFlag = true; } connectome-workbench-1.4.2/src/Annotations/AnnotationRedoUndoCommand.h000066400000000000000000000256321360521144700261510ustar00rootroot00000000000000#ifndef __ANNOTATION_UNDO_COMMAND_H__ #define __ANNOTATION_UNDO_COMMAND_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationCoordinate.h" #include "AnnotationRedoUndoCommandModeEnum.h" #include "AnnotationText.h" #include "CaretColorEnum.h" #include "CaretUndoCommand.h" namespace caret { class AnnotationFile; class Annotation; class AnnotationRedoUndoCommand : public CaretUndoCommand { public: AnnotationRedoUndoCommand(); virtual ~AnnotationRedoUndoCommand(); virtual bool redo(AString& errorMessageOut); virtual bool undo(AString& errorMessageOut); bool isValid() const; virtual bool mergeWith(const CaretUndoCommand* command); void setModeCoordinateOne(const AnnotationCoordinate& coordinate, const std::vector& annotations); void setModeCoordinateOneAndTwo(const AnnotationCoordinate& coordinateOne, const AnnotationCoordinate& coordinateTwo, const std::vector annotations); void setModeCoordinateTwo(const AnnotationCoordinate& coordinate, const std::vector& annotations); void setModeLineArrowStart(const bool newStatus, const std::vector& annotations); void setModeLineArrowEnd(const bool newStatus, const std::vector& annotations); void setModeLineWidth(const float newLineWidth, const std::vector& annotations); void setModeColorBackground(const CaretColorEnum::Enum color, const float customColor[4], const std::vector& annotations); void setModeColorLine(const CaretColorEnum::Enum color, const float customColor[4], const std::vector& annotations); void setModeCreateAnnotation(AnnotationFile* annotationFile, Annotation* annotation); void setModeCutAnnotations(const std::vector& annotations); void setModeDeleteAnnotations(const std::vector& annotations); void setModeGroupingGroupAnnotations(const AnnotationGroupKey& annotationGroupKey, const std::vector& annotations); void setModeGroupingUngroupAnnotations(const AnnotationGroupKey& annotationGroupKey); void setModeGroupingRegroupAnnotations(const AnnotationGroupKey& annotationGroupKey); void setModeLocationAndSize(const std::vector& annotationsBeforeMoveAndResize, const std::vector& annotationsAfterMoveAndResize); void setModePasteAnnotation(AnnotationFile* annotationFile, Annotation* annotation); void setModeDuplicateAnnotation(AnnotationFile* annotationFile, Annotation* annotation); void setModeRotationAngle(const float newRotationAngle, const std::vector& annotations); void setModeTextAlignmentHorizontal(const AnnotationTextAlignHorizontalEnum::Enum newHorizontalAlignment, const std::vector& annotations); void setModeTextAlignmentVertical(const AnnotationTextAlignVerticalEnum::Enum newVerticalAlignment, const std::vector& annotations); void setModeTextCharacters(const AString& text, const std::vector& annotations); void setModeTextColor(const CaretColorEnum::Enum color, const float customColor[4], const std::vector& annotations); void setModeTextConnectToBrainordinate(const AnnotationTextConnectTypeEnum::Enum newConnectType, const std::vector& annotations); void setModeTextFontBold(const bool newStatus, const std::vector& annotations); void setModeTextFontItalic(const bool newStatus, const std::vector& annotations); void setModeTextFontName(const AnnotationTextFontNameEnum::Enum newFontName, const std::vector& annotations); void setModeTextFontPointSize(const AnnotationTextFontPointSizeEnum::Enum newFontPointSize, const std::vector& annotations); void setModeTextFontPercentSize(const float newFontPercentSize, const std::vector& annotation, const float surfaceSpaceRowCount); void setModeTextFontUnderline(const bool newStatus, const std::vector& annotations); void setModeTextFontOutline(const bool newStatus, const std::vector& annotations); void setModeTextOrientation(const AnnotationTextOrientationEnum::Enum newTextOrientation, const std::vector& annotations); void setModeTwoDimHeight(const float newHeight, const std::vector& annotations); void setModeTwoDimWidth(const float newWidth, const std::vector& annotations); // ADD_NEW_METHODS_HERE private: /** * The annotation memento contains copies of the * annotation before and after its modification. */ class AnnotationMemento { public: AnnotationMemento(Annotation* annotation, Annotation* redoAnnotation, Annotation* undoAnnotation) { m_annotationFile = NULL; m_annotation = annotation; m_redoAnnotation = redoAnnotation; m_undoAnnotation = undoAnnotation; } AnnotationMemento(AnnotationFile* annotationFile, Annotation* annotation, Annotation* redoAnnotation, Annotation* undoAnnotation) { m_annotationFile = annotationFile; m_annotation = annotation; m_redoAnnotation = redoAnnotation; m_undoAnnotation = undoAnnotation; } ~AnnotationMemento() { if (m_redoAnnotation != NULL) { delete m_redoAnnotation; } if (m_undoAnnotation != NULL) { delete m_undoAnnotation; } } bool operator=(const AnnotationMemento& am) const { return (m_annotation < am.m_annotation); } AnnotationFile* m_annotationFile; Annotation* m_annotation; Annotation* m_undoAnnotation; Annotation* m_redoAnnotation; }; class AnnotationGroupMemento { public: AnnotationGroupMemento(const AnnotationGroupKey& annotationGroupKey) { m_windowIndex = -1; m_annotationGroupKey = annotationGroupKey; } AnnotationGroupMemento(const AnnotationGroupKey& annotationGroupKey, const std::vector& annotations) { m_windowIndex = -1; m_annotationGroupKey = annotationGroupKey; m_annotations = annotations; } void setUndoAnnotationGroupKey(const AnnotationGroupKey& undoAnnotationGroupKey) { m_undoAnnotationGroupKey = undoAnnotationGroupKey; } bool isValid() const { return (m_annotationGroupKey.getGroupType() != AnnotationGroupTypeEnum::INVALID); } AnnotationGroupKey m_annotationGroupKey; std::vector m_annotations; AnnotationGroupKey m_undoAnnotationGroupKey; int32_t m_windowIndex; }; AnnotationRedoUndoCommand(const AnnotationRedoUndoCommand&); AnnotationRedoUndoCommand& operator=(const AnnotationRedoUndoCommand&); void applyRedoOrUndo(Annotation* annotation, const Annotation* annotationValue) const; void sortAnnotationMementos() const; static bool equalAnnotationMemento(const AnnotationMemento* am1, const AnnotationMemento* am2); static bool lessThanAnnotationMemento(const AnnotationMemento* am1, const AnnotationMemento* am2); AnnotationRedoUndoCommandModeEnum::Enum m_mode; mutable std::vector m_annotationMementos; mutable AnnotationGroupMemento* m_annotationGroupMemento; mutable bool m_sortedFlag; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_UNDO_COMMAND_DECLARE__ // #endif // __ANNOTATION_UNDO_COMMAND_DECLARE__ } // namespace #endif //__ANNOTATION_UNDO_COMMAND_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationRedoUndoCommandModeEnum.cxx000066400000000000000000000434601360521144700301550ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_UNDO_COMMAND_MODE_ENUM_DECLARE__ #include "AnnotationRedoUndoCommandModeEnum.h" #undef __ANNOTATION_UNDO_COMMAND_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationRedoUndoCommandModeEnum * \brief Mode (type of modification) for the annotation undo command * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_AnnotationRedoUndoCommandModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void AnnotationRedoUndoCommandModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "AnnotationRedoUndoCommandModeEnum.h" * * Instatiate: * m_AnnotationRedoUndoCommandModeEnumComboBox = new EnumComboBoxTemplate(this); * m_AnnotationRedoUndoCommandModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_AnnotationRedoUndoCommandModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(AnnotationRedoUndoCommandModeEnumComboBoxItemActivated())); * * Update the selection: * m_AnnotationRedoUndoCommandModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const AnnotationRedoUndoCommandModeEnum::Enum VARIABLE = m_AnnotationRedoUndoCommandModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ AnnotationRedoUndoCommandModeEnum::AnnotationRedoUndoCommandModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ AnnotationRedoUndoCommandModeEnum::~AnnotationRedoUndoCommandModeEnum() { } /** * Initialize the enumerated metadata. */ void AnnotationRedoUndoCommandModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(AnnotationRedoUndoCommandModeEnum(INVALID, "INVALID", "Invalid")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(COLOR_BACKGROUND, "COLOR_BACKGROUND", "Color - Background")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(COLOR_FOREGROUND, "COLOR_FOREGROUND", "Color - Foreground")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(COORDINATE_ONE, "COORDINATE_ONE", "Coordinate One")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(COORDINATE_TWO, "COORDINATE_TWO", "Coordinate Two")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(CREATE_ANNOTATION, "CREATE_ANNOTATION", "Create Annotation")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(CUT_ANNOTATION, "CUT_ANNOTATION", "Cut Annotations")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(DELETE_ANNOTATIONS, "DELETE_ANNOTATIONS", "Delete Annotations")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(DUPLICATE_ANNOTATION, "DUPLICATE_ANNOTATION", "Duplicate Annotation")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(GROUPING_GROUP, "GROUPING_GROUP", "Group Annotations")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(GROUPING_REGROUP, "GROUPING_REGROUP", "Regroup Annotations")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(GROUPING_UNGROUP, "GROUPING_UNGROUP", "Ungroup Annotations")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(LINE_ARROW_START, "LINE_ARROW_START", "Line Arrow Start")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(LINE_ARROW_END, "LINE_ARROW_END", "Line Arrow End")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(LINE_WIDTH_FOREGROUND, "LINE_WIDTH_FOREGROUND", "Line Width - Foreground")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(LOCATION_AND_SIZE, "LOCATION_AND_SIZE", "location and size of annotations (coords, size, space, window, tab)")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(PASTE_ANNOTATION, "PASTE_ANNOTATION", "Paste Annotation")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(ROTATION_ANGLE, "ROTATION_ANGLE", "Rotation Angle")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(TEXT_ALIGNMENT_HORIZONTAL, "TEXT_ALIGNMENT_HORIZONTAL", "Text Alignment Horizontal")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(TEXT_ALIGNMENT_VERTICAL, "TEXT_ALIGNMENT_VERTICAL", "Text Alignment Vertical")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(TEXT_CHARACTERS, "TEXT_CHARACTERS", "Text Characters")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(TEXT_COLOR, "TEXT_COLOR", "Text Color")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(TEXT_CONNECT_TO_BRAINORDINATE, "TEXT_CONNECT_TO_BRAINORDINATE", "Text Connect to Brainordinate")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(TEXT_FONT_BOLD, "TEXT_FONT_BOLD", "Text Font Bold")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(TEXT_FONT_ITALIC, "TEXT_FONT_ITALIC", "Text Font Italic")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(TEXT_FONT_NAME, "TEXT_FONT_NAME", "Text Font Name")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(TEXT_FONT_PERCENT_SIZE, "TEXT_FONT_PERCENT_SIZE", "Text Font Percent Size")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(TEXT_FONT_POINT_SIZE, "TEXT_FONT_POINT_SIZE", "Text Font Point Size")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(TEXT_FONT_UNDERLINE, "TEXT_FONT_UNDERLINE", "Text Font Undeline")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(TEXT_ORIENTATION, "TEXT_ORIENTATION", "Text Orientation")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const AnnotationRedoUndoCommandModeEnum* AnnotationRedoUndoCommandModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const AnnotationRedoUndoCommandModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationRedoUndoCommandModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationRedoUndoCommandModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationRedoUndoCommandModeEnum::Enum AnnotationRedoUndoCommandModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationRedoUndoCommandModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationRedoUndoCommandModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type AnnotationRedoUndoCommandModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationRedoUndoCommandModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationRedoUndoCommandModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationRedoUndoCommandModeEnum::Enum AnnotationRedoUndoCommandModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationRedoUndoCommandModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationRedoUndoCommandModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type AnnotationRedoUndoCommandModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t AnnotationRedoUndoCommandModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationRedoUndoCommandModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ AnnotationRedoUndoCommandModeEnum::Enum AnnotationRedoUndoCommandModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationRedoUndoCommandModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationRedoUndoCommandModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type AnnotationRedoUndoCommandModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void AnnotationRedoUndoCommandModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationRedoUndoCommandModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(AnnotationRedoUndoCommandModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationRedoUndoCommandModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(AnnotationRedoUndoCommandModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Annotations/AnnotationRedoUndoCommandModeEnum.h000066400000000000000000000122531360521144700275760ustar00rootroot00000000000000#ifndef __ANNOTATION_UNDO_COMMAND_MODE_ENUM_H__ #define __ANNOTATION_UNDO_COMMAND_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class AnnotationRedoUndoCommandModeEnum { public: /** * Enumerated values. */ enum Enum { /** Invalid mode */ INVALID, /** Color - Background */ COLOR_BACKGROUND, /** Color - Foreground */ COLOR_FOREGROUND, /** Coordinate One */ COORDINATE_ONE, /** Coordinate One And Two */ COORDINATE_ONE_AND_TWO, /** Coordinate Two */ COORDINATE_TWO, /** Create an annotation */ CREATE_ANNOTATION, /** Cut Annotation */ CUT_ANNOTATION, /** Delete Annotations */ DELETE_ANNOTATIONS, /** Duplicate Annotation */ DUPLICATE_ANNOTATION, /** Group Annotations */ GROUPING_GROUP, /** Regroup Annotations */ GROUPING_REGROUP, /** Ungroup Annotations */ GROUPING_UNGROUP, /** Line Arrow Start */ LINE_ARROW_START, /** Line Arrow End */ LINE_ARROW_END, /** Line Width of Foreground */ LINE_WIDTH_FOREGROUND, /** Location and size of annotations (coords, size, space, window, tab) */ LOCATION_AND_SIZE, /** Paste Annotation */ PASTE_ANNOTATION, /** Rotation Angle */ ROTATION_ANGLE, /** Text Alignment Horizontal */ TEXT_ALIGNMENT_HORIZONTAL, /** Text Alignment Vertical */ TEXT_ALIGNMENT_VERTICAL, /** Text Characters */ TEXT_CHARACTERS, /** Text Color */ TEXT_COLOR, /** Text Connect to Brainordinate */ TEXT_CONNECT_TO_BRAINORDINATE, /** Text Font Bold */ TEXT_FONT_BOLD, /** Text Font Italic */ TEXT_FONT_ITALIC, /** Text Font Name */ TEXT_FONT_NAME, /** Text Font Percent Size */ TEXT_FONT_PERCENT_SIZE, /** Text Font Point Size */ TEXT_FONT_POINT_SIZE, /** Text Font Underline */ TEXT_FONT_UNDERLINE, /** Text Orientation */ TEXT_ORIENTATION, /** Two dimensional (box, oval) height */ TWO_DIM_HEIGHT, /** Two dimensional (box, oval) width */ TWO_DIM_WIDTH }; ~AnnotationRedoUndoCommandModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: AnnotationRedoUndoCommandModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const AnnotationRedoUndoCommandModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __ANNOTATION_UNDO_COMMAND_MODE_ENUM_DECLARE__ std::vector AnnotationRedoUndoCommandModeEnum::enumData; bool AnnotationRedoUndoCommandModeEnum::initializedFlag = false; int32_t AnnotationRedoUndoCommandModeEnum::integerCodeCounter = 0; #endif // __ANNOTATION_UNDO_COMMAND_MODE_ENUM_DECLARE__ } // namespace #endif //__ANNOTATION_UNDO_COMMAND_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationSizingHandleTypeEnum.cxx000066400000000000000000000333451360521144700275540ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_SIZING_HANDLE_TYPE_ENUM_DECLARE__ #include "AnnotationSizingHandleTypeEnum.h" #undef __ANNOTATION_SIZING_HANDLE_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationSizingHandleTypeEnum * \brief Enumerated type for annotation sizing handles * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_annotationSizingHandleTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void annotationSizingHandleTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "AnnotationSizingHandleTypeEnum.h" * * Instatiate: * m_annotationSizingHandleTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_annotationSizingHandleTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_annotationSizingHandleTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(annotationSizingHandleTypeEnumComboBoxItemActivated())); * * Update the selection: * m_annotationSizingHandleTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const AnnotationSizingHandleTypeEnum::Enum VARIABLE = m_annotationSizingHandleTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ AnnotationSizingHandleTypeEnum::AnnotationSizingHandleTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ AnnotationSizingHandleTypeEnum::~AnnotationSizingHandleTypeEnum() { } /** * Initialize the enumerated metadata. */ void AnnotationSizingHandleTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(AnnotationSizingHandleTypeEnum(ANNOTATION_SIZING_HANDLE_NONE, "ANNOTATION_SIZING_HANDLE_NONE", "None")); enumData.push_back(AnnotationSizingHandleTypeEnum(ANNOTATION_SIZING_HANDLE_BOX_BOTTOM, "ANNOTATION_SIZING_HANDLE_BOX_BOTTOM", "Bottom")); enumData.push_back(AnnotationSizingHandleTypeEnum(ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT, "ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT", "Bottom Left")); enumData.push_back(AnnotationSizingHandleTypeEnum(ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT, "ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT", "Bottom Right")); enumData.push_back(AnnotationSizingHandleTypeEnum(ANNOTATION_SIZING_HANDLE_BOX_LEFT, "ANNOTATION_SIZING_HANDLE_BOX_LEFT", "Left")); enumData.push_back(AnnotationSizingHandleTypeEnum(ANNOTATION_SIZING_HANDLE_BOX_RIGHT, "ANNOTATION_SIZING_HANDLE_BOX_RIGHT", "Right")); enumData.push_back(AnnotationSizingHandleTypeEnum(ANNOTATION_SIZING_HANDLE_BOX_TOP, "ANNOTATION_SIZING_HANDLE_BOX_TOP", "Top")); enumData.push_back(AnnotationSizingHandleTypeEnum(ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT, "ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT", "Top Left")); enumData.push_back(AnnotationSizingHandleTypeEnum(ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT, "ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT", "Top Right")); enumData.push_back(AnnotationSizingHandleTypeEnum(ANNOTATION_SIZING_HANDLE_ROTATION, "ANNOTATION_SIZING_HANDLE_ROTATION", "Rotation")); enumData.push_back(AnnotationSizingHandleTypeEnum(ANNOTATION_SIZING_HANDLE_LINE_END, "ANNOTATION_SIZING_HANDLE_LINE_END", "Line End")); enumData.push_back(AnnotationSizingHandleTypeEnum(ANNOTATION_SIZING_HANDLE_LINE_START, "ANNOTATION_SIZING_HANDLE_LINE_START", "Line Start")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const AnnotationSizingHandleTypeEnum* AnnotationSizingHandleTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const AnnotationSizingHandleTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationSizingHandleTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationSizingHandleTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationSizingHandleTypeEnum::Enum AnnotationSizingHandleTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationSizingHandleTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationSizingHandleTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type AnnotationSizingHandleTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationSizingHandleTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationSizingHandleTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationSizingHandleTypeEnum::Enum AnnotationSizingHandleTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationSizingHandleTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationSizingHandleTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type AnnotationSizingHandleTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t AnnotationSizingHandleTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationSizingHandleTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ AnnotationSizingHandleTypeEnum::Enum AnnotationSizingHandleTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationSizingHandleTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationSizingHandleTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type AnnotationSizingHandleTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void AnnotationSizingHandleTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationSizingHandleTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(AnnotationSizingHandleTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationSizingHandleTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(AnnotationSizingHandleTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Annotations/AnnotationSizingHandleTypeEnum.h000066400000000000000000000076711360521144700272040ustar00rootroot00000000000000#ifndef __ANNOTATION_SIZING_HANDLE_TYPE_ENUM_H__ #define __ANNOTATION_SIZING_HANDLE_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class AnnotationSizingHandleTypeEnum { public: /** * Enumerated values. */ enum Enum { /** No sizing handle */ ANNOTATION_SIZING_HANDLE_NONE, /** Bottom */ ANNOTATION_SIZING_HANDLE_BOX_BOTTOM, /** Bottom Left */ ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT, /** Bottom Right */ ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT, /** Left */ ANNOTATION_SIZING_HANDLE_BOX_LEFT, /** Right */ ANNOTATION_SIZING_HANDLE_BOX_RIGHT, /** Top */ ANNOTATION_SIZING_HANDLE_BOX_TOP, /** Top Left */ ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT, /** Top Right */ ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT, /** Rotation */ ANNOTATION_SIZING_HANDLE_ROTATION, /** Line End */ ANNOTATION_SIZING_HANDLE_LINE_END, /** Line Start */ ANNOTATION_SIZING_HANDLE_LINE_START }; ~AnnotationSizingHandleTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: AnnotationSizingHandleTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const AnnotationSizingHandleTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __ANNOTATION_SIZING_HANDLE_TYPE_ENUM_DECLARE__ std::vector AnnotationSizingHandleTypeEnum::enumData; bool AnnotationSizingHandleTypeEnum::initializedFlag = false; int32_t AnnotationSizingHandleTypeEnum::integerCodeCounter = 0; #endif // __ANNOTATION_SIZING_HANDLE_TYPE_ENUM_DECLARE__ } // namespace #endif //__ANNOTATION_SIZING_HANDLE_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationSpatialModification.cxx000066400000000000000000000154211360521144700274240ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_SPATIAL_MODIFICATION_DECLARE__ #include "AnnotationSpatialModification.h" #undef __ANNOTATION_SPATIAL_MODIFICATION_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationSpatialModification * \brief Contains information for spatially modifying an annotation. * \ingroup Annotations */ /** * Apply a move or resize operation received from the GUI. * * @param handleSelected * Annotatoion handle that is being processed by the user. * @param viewportWidth * Width of viewport * @param viewportHeight * Height of viewport * @param mousePressX * Mouse pressed X-coordinate. * @param mousePressY * Mouse pressed Y-coordinate. * @param mouseX * Mouse X-coordinate. * @param mouseY * Mouse Y-coordinate. * @param mouseDX * Change in mouse X-coordinate. * @param mouseDY * Change in mouse Y-coordinate. * @param startOfDraggingFlag * True when user starts to drag mouse. */ AnnotationSpatialModification::AnnotationSpatialModification(const AnnotationSizingHandleTypeEnum::Enum sizingHandleType, const float viewportWidth, const float viewportHeight, const float mousePressX, const float mousePressY, const float mouseX, const float mouseY, const float mouseDX, const float mouseDY, const bool startOfDraggingFlag) : CaretObject(), m_sizingHandleType(sizingHandleType), m_viewportWidth(viewportWidth), m_viewportHeight(viewportHeight), m_mousePressX(mousePressX), m_mousePressY(mousePressY), m_mouseX(mouseX), m_mouseY(mouseY), m_mouseDX(mouseDX), m_mouseDY(mouseDY), m_startOfDraggingFlag(startOfDraggingFlag) { m_chartCoordAtMouseXY.m_chartXYZValid = false; m_chartCoordAtPreviousMouseXY.m_chartXYZValid = false; m_stereotaxicCoordinateAtMouseXY.m_stereotaxicValid = false; m_surfaceCoordinateAtMouseXY.m_surfaceNodeValid = false; } /** * Destructor. */ AnnotationSpatialModification::~AnnotationSpatialModification() { } /** * Set the surface coordinate at mouse X/Y. * * @param structure * The surface structure. * @param surfaceNumberOfNodes * Number of nodes in the surface. * @param surfaceNodeIndex * Surface node index. */ void AnnotationSpatialModification::setSurfaceCoordinateAtMouseXY(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const int32_t surfaceNodeIndex) { m_surfaceCoordinateAtMouseXY.m_surfaceStructure = structure; m_surfaceCoordinateAtMouseXY.m_surfaceNumberOfNodes = surfaceNumberOfNodes; m_surfaceCoordinateAtMouseXY.m_surfaceNodeIndex = surfaceNodeIndex; m_surfaceCoordinateAtMouseXY.m_surfaceNodeValid = false; if ((m_surfaceCoordinateAtMouseXY.m_surfaceStructure != StructureEnum::INVALID) && (m_surfaceCoordinateAtMouseXY.m_surfaceNumberOfNodes > 0) && (m_surfaceCoordinateAtMouseXY.m_surfaceNodeIndex >= 0) && (m_surfaceCoordinateAtMouseXY.m_surfaceNodeIndex < m_surfaceCoordinateAtMouseXY.m_surfaceNumberOfNodes)) { m_surfaceCoordinateAtMouseXY.m_surfaceNodeValid = true; } } /** * Set the stereotaxic coordinate at mouse X/Y * * @param stereotaxicX * stereotaxic X-coordinate. * @param stereotaxicY * stereotaxic Y-coordinate. * @param stereotaxicZ * stereotaxic Z-coordinate. */ void AnnotationSpatialModification::setStereotaxicCoordinateAtMouseXY(const float stereotaxicX, const float stereotaxicY, const float stereotaxicZ) { m_stereotaxicCoordinateAtMouseXY.m_stereotaxicXYZ[0] = stereotaxicX; m_stereotaxicCoordinateAtMouseXY.m_stereotaxicXYZ[1] = stereotaxicY; m_stereotaxicCoordinateAtMouseXY.m_stereotaxicXYZ[2] = stereotaxicZ; m_stereotaxicCoordinateAtMouseXY.m_stereotaxicValid = true; } /** * Set the chart coordinate at mouse X/Y * * @param chartX * chart X-coordinate. * @param chartY * chart Y-coordinate. * @param chartZ * chart Z-coordinate. */ void AnnotationSpatialModification::setChartCoordinateAtMouseXY(const float chartX, const float chartY, const float chartZ) { m_chartCoordAtMouseXY.m_chartXYZ[0] = chartX; m_chartCoordAtMouseXY.m_chartXYZ[1] = chartY; m_chartCoordAtMouseXY.m_chartXYZ[2] = chartZ; m_chartCoordAtMouseXY.m_chartXYZValid = true; } /** * Set the chart coordinate at previous mouse X/Y * * @param chartX * chart X-coordinate. * @param chartY * chart Y-coordinate. * @param chartZ * chart Z-coordinate. */ void AnnotationSpatialModification::setChartCoordinateAtPreviousMouseXY(const float chartX, const float chartY, const float chartZ) { m_chartCoordAtPreviousMouseXY.m_chartXYZ[0] = chartX; m_chartCoordAtPreviousMouseXY.m_chartXYZ[1] = chartY; m_chartCoordAtPreviousMouseXY.m_chartXYZ[2] = chartZ; m_chartCoordAtPreviousMouseXY.m_chartXYZValid = true; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString AnnotationSpatialModification::toString() const { return "AnnotationSpatialModification"; } connectome-workbench-1.4.2/src/Annotations/AnnotationSpatialModification.h000066400000000000000000000124641360521144700270550ustar00rootroot00000000000000#ifndef __ANNOTATION_SPATIAL_MODIFICATION_H__ #define __ANNOTATION_SPATIAL_MODIFICATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationSizingHandleTypeEnum.h" #include "CaretObject.h" #include "StructureEnum.h" namespace caret { class AnnotationSpatialModification : public CaretObject { public: AnnotationSpatialModification(const AnnotationSizingHandleTypeEnum::Enum sizingHandleType, const float viewportWidth, const float viewportHeight, const float mousePressX, const float mousePressY, const float mouseX, const float mouseY, const float mouseDX, const float mouseDY, const bool startOfDraggingFlag); void setSurfaceCoordinateAtMouseXY(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const int32_t surfaceNodeIndex); void setStereotaxicCoordinateAtMouseXY(const float stereotaxicX, const float stereotaxicY, const float stereotaxicZ); void setChartCoordinateAtMouseXY(const float chartX, const float chartY, const float chartZ); void setChartCoordinateAtPreviousMouseXY(const float chartX, const float chartY, const float chartZ); virtual ~AnnotationSpatialModification(); // ADD_NEW_METHODS_HERE virtual AString toString() const; private: class SurfaceCoord { public: SurfaceCoord() { m_surfaceStructure = StructureEnum::INVALID; m_surfaceNumberOfNodes = -1; m_surfaceNodeIndex = -1; m_surfaceNodeValid = false; } StructureEnum::Enum m_surfaceStructure; int32_t m_surfaceNumberOfNodes; int32_t m_surfaceNodeIndex; bool m_surfaceNodeValid; }; class ChartCoord { public: ChartCoord() { m_chartXYZ[0] = 0.0; m_chartXYZ[1] = 0.0; m_chartXYZ[2] = 0.0; m_chartXYZValid = false; } float m_chartXYZ[3]; bool m_chartXYZValid; }; class StereotaxicCoord { public: StereotaxicCoord() { m_stereotaxicXYZ[0] = 0.0; m_stereotaxicXYZ[1] = 0.0; m_stereotaxicXYZ[2] = 0.0; m_stereotaxicValid = false; } float m_stereotaxicXYZ[3]; bool m_stereotaxicValid; }; AnnotationSpatialModification(const AnnotationSpatialModification&); AnnotationSpatialModification& operator=(const AnnotationSpatialModification&); const AnnotationSizingHandleTypeEnum::Enum m_sizingHandleType; const float m_viewportWidth; const float m_viewportHeight; const float m_mousePressX; const float m_mousePressY; const float m_mouseX; const float m_mouseY; const float m_mouseDX; const float m_mouseDY; const bool m_startOfDraggingFlag; ChartCoord m_chartCoordAtMouseXY; ChartCoord m_chartCoordAtPreviousMouseXY; SurfaceCoord m_surfaceCoordinateAtMouseXY; StereotaxicCoord m_stereotaxicCoordinateAtMouseXY; // ADD_NEW_MEMBERS_HERE friend class AnnotationOneDimensionalShape; friend class AnnotationText; friend class AnnotationTwoDimensionalShape; }; #ifdef __ANNOTATION_SPATIAL_MODIFICATION_DECLARE__ // #endif // __ANNOTATION_SPATIAL_MODIFICATION_DECLARE__ } // namespace #endif //__ANNOTATION_SPATIAL_MODIFICATION_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationSurfaceOffsetVectorTypeEnum.cxx000066400000000000000000000317051360521144700311150ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_SURFACE_OFFSET_VECTOR_TYPE_ENUM_DECLARE__ #include "AnnotationSurfaceOffsetVectorTypeEnum.h" #undef __ANNOTATION_SURFACE_OFFSET_VECTOR_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationSurfaceOffsetVectorTypeEnum * \brief Type of offset vector for surface annotations * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_annotationSurfaceOffsetVectorTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void annotationSurfaceOffsetVectorTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "AnnotationSurfaceOffsetVectorTypeEnum.h" * * Instatiate: * m_annotationSurfaceOffsetVectorTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_annotationSurfaceOffsetVectorTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_annotationSurfaceOffsetVectorTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(annotationSurfaceOffsetVectorTypeEnumComboBoxItemActivated())); * * Update the selection: * m_annotationSurfaceOffsetVectorTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const AnnotationSurfaceOffsetVectorTypeEnum::Enum VARIABLE = m_annotationSurfaceOffsetVectorTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * @param guiName * User-friendly name for use in user-interface. * @param longGuiName * Long User-friendly name for use in user-interface. */ AnnotationSurfaceOffsetVectorTypeEnum::AnnotationSurfaceOffsetVectorTypeEnum(const Enum enumValue, const AString& name, const AString& guiName, const AString& longGuiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; this->longGuiName = longGuiName; } /** * Destructor. */ AnnotationSurfaceOffsetVectorTypeEnum::~AnnotationSurfaceOffsetVectorTypeEnum() { } /** * Initialize the enumerated metadata. */ void AnnotationSurfaceOffsetVectorTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(AnnotationSurfaceOffsetVectorTypeEnum(CENTROID_THRU_VERTEX, "CENTROID_THRU_VERTEX", "C", "Centroid Thru Vertex")); enumData.push_back(AnnotationSurfaceOffsetVectorTypeEnum(SURFACE_NORMAL, "SURFACE_NORMAL", "N", "Surface Normal")); enumData.push_back(AnnotationSurfaceOffsetVectorTypeEnum(TANGENT, "TANGENT", "T", "Tangent")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const AnnotationSurfaceOffsetVectorTypeEnum* AnnotationSurfaceOffsetVectorTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const AnnotationSurfaceOffsetVectorTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationSurfaceOffsetVectorTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationSurfaceOffsetVectorTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param nameIn * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationSurfaceOffsetVectorTypeEnum::Enum AnnotationSurfaceOffsetVectorTypeEnum::fromName(const AString& nameIn, bool* isValidOut) { if (initializedFlag == false) initialize(); /* * SURFACE_NORMAL was spelled incorrectly prior to 24aug2018 * (was missing 'F'). */ AString name(nameIn); if (name == "SURACE_NORMAL") { name = "SURFACE_NORMAL"; } bool validFlag = false; Enum enumValue = AnnotationSurfaceOffsetVectorTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationSurfaceOffsetVectorTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type AnnotationSurfaceOffsetVectorTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationSurfaceOffsetVectorTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationSurfaceOffsetVectorTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get a long GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * long string representing enumerated value. */ AString AnnotationSurfaceOffsetVectorTypeEnum::toLongGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationSurfaceOffsetVectorTypeEnum* enumInstance = findData(enumValue); return enumInstance->longGuiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationSurfaceOffsetVectorTypeEnum::Enum AnnotationSurfaceOffsetVectorTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationSurfaceOffsetVectorTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationSurfaceOffsetVectorTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type AnnotationSurfaceOffsetVectorTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t AnnotationSurfaceOffsetVectorTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationSurfaceOffsetVectorTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ AnnotationSurfaceOffsetVectorTypeEnum::Enum AnnotationSurfaceOffsetVectorTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationSurfaceOffsetVectorTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationSurfaceOffsetVectorTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type AnnotationSurfaceOffsetVectorTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void AnnotationSurfaceOffsetVectorTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationSurfaceOffsetVectorTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(AnnotationSurfaceOffsetVectorTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationSurfaceOffsetVectorTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(AnnotationSurfaceOffsetVectorTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Annotations/AnnotationSurfaceOffsetVectorTypeEnum.h000066400000000000000000000072771360521144700305510ustar00rootroot00000000000000#ifndef __ANNOTATION_SURFACE_OFFSET_VECTOR_TYPE_ENUM_H__ #define __ANNOTATION_SURFACE_OFFSET_VECTOR_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class AnnotationSurfaceOffsetVectorTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Vector starts at centroid and extends through vertex */ CENTROID_THRU_VERTEX, /** Vector is surface normal */ SURFACE_NORMAL, /** Tangent to surface */ TANGENT }; ~AnnotationSurfaceOffsetVectorTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static AString toLongGuiName(Enum enumValue); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: AnnotationSurfaceOffsetVectorTypeEnum(const Enum enumValue, const AString& name, const AString& guiName, const AString& longGuiName); static const AnnotationSurfaceOffsetVectorTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; /** A user-friendly name that is displayed in the GUI */ AString longGuiName; }; #ifdef __ANNOTATION_SURFACE_OFFSET_VECTOR_TYPE_ENUM_DECLARE__ std::vector AnnotationSurfaceOffsetVectorTypeEnum::enumData; bool AnnotationSurfaceOffsetVectorTypeEnum::initializedFlag = false; int32_t AnnotationSurfaceOffsetVectorTypeEnum::integerCodeCounter = 0; #endif // __ANNOTATION_SURFACE_OFFSET_VECTOR_TYPE_ENUM_DECLARE__ } // namespace #endif //__ANNOTATION_SURFACE_OFFSET_VECTOR_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationText.cxx000066400000000000000000001126771360521144700244400ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_TEXT_DECLARE__ #include "AnnotationText.h" #undef __ANNOTATION_TEXT_DECLARE__ #include "AnnotationPercentSizeText.h" #include "AnnotationSpatialModification.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "EventAnnotationTextSubstitutionGet.h" #include "EventManager.h" #include "MathFunctions.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::AnnotationText * \brief Text annotation. * \ingroup Annotations */ /** * Constructor for subclass. * * @param attributeDefaultType * Type for attribute defaults * @param fontSizeType * Type of font sizing. */ AnnotationText::AnnotationText(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, const AnnotationTextFontSizeTypeEnum::Enum fontSizeType) : AnnotationTwoDimensionalShape(AnnotationTypeEnum::TEXT, attributeDefaultType), AnnotationFontAttributesInterface(), m_fontSizeType(fontSizeType) { initializeAnnotationTextMembers(); } /** * Constructor for subclass. * * @param type * Type of annotation. * @param attributeDefaultType * Type for attribute defaults * @param fontSizeType * Type of font sizing. */ AnnotationText::AnnotationText(const AnnotationTypeEnum::Enum type, const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, const AnnotationTextFontSizeTypeEnum::Enum fontSizeType) : AnnotationTwoDimensionalShape(type, attributeDefaultType), AnnotationFontAttributesInterface(), m_fontSizeType(fontSizeType) { initializeAnnotationTextMembers(); } /** * Destructor. */ AnnotationText::~AnnotationText() { } /** * Copy constructor. * @param obj * Object that is copied. */ AnnotationText::AnnotationText(const AnnotationText& obj) : AnnotationTwoDimensionalShape(obj), AnnotationFontAttributesInterface(), m_fontSizeType(obj.m_fontSizeType) { initializeAnnotationTextMembers(); this->copyHelperAnnotationText(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ AnnotationText& AnnotationText::operator=(const AnnotationText& obj) { if (this != &obj) { Annotation::operator=(obj); this->copyHelperAnnotationText(obj); } return *this; } /** * Initialize members of this class. */ void AnnotationText::initializeAnnotationTextMembers() { switch (m_attributeDefaultType) { case AnnotationAttributesDefaultTypeEnum::NORMAL: m_alignmentHorizontal = AnnotationTextAlignHorizontalEnum::LEFT; m_alignmentVertical = AnnotationTextAlignVerticalEnum::TOP; m_font = AnnotationTextFontNameEnum::VERA; m_fontPointSize = AnnotationTextFontPointSizeEnum::SIZE14; m_orientation = AnnotationTextOrientationEnum::HORIZONTAL; m_colorText = CaretColorEnum::WHITE; m_customColorText[0] = 1.0; m_customColorText[1] = 1.0; m_customColorText[2] = 1.0; m_customColorText[3] = 1.0; m_boldEnabled = false; m_italicEnabled = false; m_underlineEnabled = false; m_connectToBrainordinate = AnnotationTextConnectTypeEnum::ANNOTATION_TEXT_CONNECT_NONE; m_fontPercentViewportSize = 5.0; break; case AnnotationAttributesDefaultTypeEnum::USER: m_alignmentHorizontal = s_userDefaultAlignmentHorizontal; m_alignmentVertical = s_userDefaultAlignmentVertical; m_font = s_userDefaultFont; m_fontPointSize = s_userDefaultPointSize; m_orientation = s_userDefaultOrientation; m_colorText = s_userDefaultColorText; m_customColorText[0] = s_userDefaultCustomColorText[0]; m_customColorText[1] = s_userDefaultCustomColorText[1]; m_customColorText[2] = s_userDefaultCustomColorText[2]; m_customColorText[3] = s_userDefaultCustomColorText[3]; m_boldEnabled = s_userDefaultBoldEnabled; m_italicEnabled = s_userDefaultItalicEnabled; m_underlineEnabled = s_userDefaultUnderlineEnabled; m_connectToBrainordinate = s_userDefaultConnectToBrainordinate; m_fontPercentViewportSize = s_userDefaultFontPercentViewportSize; break; } m_text = ""; m_textWithSubstitutions = ""; /* * Assists with attributes that may be saved to scene (controlled by annotation property). */ m_attributesAssistant.grabNew(new SceneClassAssistant()); m_attributesAssistant->add("m_alignmentHorizontal", &m_alignmentHorizontal); m_attributesAssistant->add("m_alignmentVertical", &m_alignmentVertical); m_attributesAssistant->add("m_font", &m_font); m_attributesAssistant->add("m_fontPointSize", &m_fontPointSize); m_attributesAssistant->add("m_orientation", &m_orientation); m_attributesAssistant->add("m_colorText", &m_colorText); m_attributesAssistant->addArray("m_customColorText", m_customColorText, 4, 1.0); m_attributesAssistant->add("m_boldEnabled", &m_boldEnabled); m_attributesAssistant->add("m_italicEnabled", &m_italicEnabled); m_attributesAssistant->add("m_underlineEnabled", &m_underlineEnabled); m_attributesAssistant->add("m_connectToBrainordinate", &m_connectToBrainordinate); m_attributesAssistant->add("m_fontPercentViewportSize", &m_fontPercentViewportSize); m_attributesAssistant->add("m_text", &m_text); } /** * Get an encoded name that contains the * name of the font, the font height, and the * font style used by font rendering to provide * a name for cached fonts. * * The text annotation contains the height of the viewport * when the annotation was created. When it is valid ( * greater than zero), and the drawing viewport height * is also valid (greater than zero), a scaling value * (equal to drawing viewport height divided by creation * viewport height) is applied to the font size so that * the font can scale as the viewport change in size. * Thus, if the viewport becomes larger (smaller), the * text will become larger (smaller). While one could * scale while drawing the text (using glScale()), the * quality is poor. * * @param drawingViewportWidth * Width of the viewport that may be used to scale the font height. * @param drawingViewportHeight * Height of the viewport that may be used to scale the font height. * @return * Encoded name for font. */ AString AnnotationText::getFontRenderingEncodedName(const float drawingViewportWidth, const float drawingViewportHeight) const { AString fontSizeID = AnnotationTextFontPointSizeEnum::toName(m_fontPointSize); switch (m_fontSizeType) { case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT: if (m_fontPercentViewportSize > 0.0) { if (drawingViewportHeight > 0.0) { const int32_t fontSizeInt = getFontSizeForDrawing(drawingViewportWidth, drawingViewportHeight); if (fontSizeInt > 0) { fontSizeID = "SIZE" + AString::number(fontSizeInt); } } } break; case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH: if (m_fontPercentViewportSize > 0.0) { if (drawingViewportWidth > 0.0) { const int32_t fontSizeInt = getFontSizeForDrawing(drawingViewportWidth, drawingViewportHeight); if (fontSizeInt > 0) { fontSizeID = "SIZE" + AString::number(fontSizeInt); } } } break; case AnnotationTextFontSizeTypeEnum::POINTS: break; } AString encodedName; encodedName.reserve(50); encodedName.append(AnnotationTextFontNameEnum::toName(m_font)); encodedName.append("_" + fontSizeID); if (m_boldEnabled) { encodedName.append("_B"); } if (m_italicEnabled) { encodedName.append("_I"); } return encodedName; } /** * @return Text for the annotation. */ AString AnnotationText::getText() const { return m_text; } /** * Invalidate text substitutions. This method is * implemented as a virtual method to avoid * dyamic casts since they are slow. */ void AnnotationText::invalidateTextSubstitution() { m_textWithSubstitutions.clear(); } /** * @return Text with any substitutions applied to the text. */ AString AnnotationText::getTextWithSubstitutionsApplied() const { if (m_textWithSubstitutions.isEmpty()) { if ( ! m_text.isEmpty()) { std::vector indices; const QChar substituteChar('$'); int32_t index = m_text.indexOf(substituteChar); while (index >= 0) { indices.push_back(index); index = m_text.indexOf(substituteChar, index + 1); } if (indices.size() < 2) { if (indices.size() == 1) { CaretLogWarning("Text annotation \"" + m_text + "\" is missing substitution delimeters"); } m_textWithSubstitutions = m_text; } else { int32_t lastPos = 0; const int32_t numSubsitutions = static_cast(indices.size() / 2); for (int32_t i = 0; i < numSubsitutions; i++) { const int32_t i2 = i * 2; CaretAssertVectorIndex(indices, i2+1); const int32_t indexOne = indices[i2]; const int32_t indexTwo = indices[i2+1]; if (indexTwo > (indexOne + 1)) { const int32_t nameLen = indexTwo - indexOne - 1; AString name = m_text.mid(indexOne + 1, nameLen); EventAnnotationTextSubstitutionGet subEvent; subEvent.addSubstitutionName(name); EventManager::get()->sendEvent(subEvent.getPointer()); const AString subValue = subEvent.getSubstitutionValueForName(name); if (subValue.isEmpty()) { CaretLogWarning("Unable to find substitution value for name \"" + name + "\""); } const AString txt = m_text.mid(lastPos, indexOne - lastPos); m_textWithSubstitutions.append(txt); if (subValue.isEmpty()) { m_textWithSubstitutions.append("$" + name + "$"); } else { m_textWithSubstitutions.append(subValue); } } else { const AString txt = m_text.mid(lastPos, indexOne - lastPos); m_textWithSubstitutions.append(txt + "$$"); CaretLogWarning("Text annotation \"" + m_text + "\" contains empty text substitution delimeters (" + substituteChar + ")"); } lastPos = indexTwo + 1; } const AString lastTxt = m_text.mid(lastPos); m_textWithSubstitutions.append(lastTxt); } } } return m_textWithSubstitutions; } /** * Set the text for an annotation. * @param text * Text for the annotation. */ void AnnotationText::setText(const AString& text) { if (text != m_text) { m_text = text; m_textWithSubstitutions.clear(); textAnnotationResetName(); setModified(); } } /** * @return The horizontal alignment. */ AnnotationTextAlignHorizontalEnum::Enum AnnotationText::getHorizontalAlignment() const { return m_alignmentHorizontal; } /** * Set the horizontal alignment. * * @param alignment * New value for horizontal alignment. */ void AnnotationText::setHorizontalAlignment(const AnnotationTextAlignHorizontalEnum::Enum alignment) { if (m_alignmentHorizontal != alignment) { m_alignmentHorizontal = alignment; setModified(); } } /** * @return The vertical alignment. */ AnnotationTextAlignVerticalEnum::Enum AnnotationText::getVerticalAlignment() const { return m_alignmentVertical; } /** * Set the vertical alignment. * * @param alignment * New value for vertical alignment. */ void AnnotationText::setVerticalAlignment(const AnnotationTextAlignVerticalEnum::Enum alignment) { if (m_alignmentVertical != alignment) { m_alignmentVertical = alignment; setModified(); } } /** * @param connect to brainordinate status (none, line, arrow). */ AnnotationTextConnectTypeEnum::Enum AnnotationText::getConnectToBrainordinate() const { return m_connectToBrainordinate; } /** * Set the connect to brainordinate status. * * @param connectToBrainordinate * New value for connection to brainordinate (none, line, arrow) */ void AnnotationText::setConnectToBrainordinate(const AnnotationTextConnectTypeEnum::Enum connectToBrainordinate) { if (m_connectToBrainordinate != connectToBrainordinate) { m_connectToBrainordinate = connectToBrainordinate; setModified(); } } /** * @return Is connect to brainordinate valid for this text annotation. */ bool AnnotationText::isConnectToBrainordinateValid() const { if (getCoordinateSpace() == AnnotationCoordinateSpaceEnum::SURFACE) { return true; } return false; } /** * @return The font. */ AnnotationTextFontNameEnum::Enum AnnotationText::getFont() const { return m_font; } /** * Set the font for an annotation. * @param font * Font for the annotation. */ void AnnotationText::setFont(const AnnotationTextFontNameEnum::Enum font) { if (font != m_font) { m_font = font; setModified(); } } /** * Get the font size for drawing. The font size may * be scaled to "best fit" the viewport. * * For a Point Size Text Annotation, the size returned is the text annotation's * point size. * * For a Percentage Size Text Annotation, the size returned will be * "percent size" of the viewport height in a range from zero to * one where one equivalent to the viewport's height. * * @param drawingViewportWidth * Width of the viewport that may be used to scale the font height. * @param drawingViewportHeight * Height of the viewport that may be used to scale the font height. * @return * Size of the font. */ int32_t AnnotationText::getFontSizeForDrawing(const int32_t drawingViewportWidth, const int32_t drawingViewportHeight) const { float sizeForDrawing = AnnotationTextFontPointSizeEnum::toSizeNumeric(AnnotationTextFontPointSizeEnum::SIZE14); /* * Minimum pixel size for text that is sized as a percent of height (tab/window). * Note that some characters in a font may cause an OpenGL error and this * error may unique to the underlying OpenGL implementation. */ const float minimumPixelSizeForPercentageText = 1.0; switch (m_fontSizeType) { case AnnotationTextFontSizeTypeEnum::POINTS: sizeForDrawing = AnnotationTextFontPointSizeEnum::toSizeNumeric(m_fontPointSize); if (sizeForDrawing < AnnotationTextFontPointSizeEnum::getMinimumSizeNumeric()) { sizeForDrawing = AnnotationTextFontPointSizeEnum::getMinimumSizeNumeric(); } break; case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT: { /* * May need pixel to points conversion if not 72 DPI */ const float pixelSize = drawingViewportHeight * (m_fontPercentViewportSize / 100.0); sizeForDrawing = pixelSize; if (sizeForDrawing < minimumPixelSizeForPercentageText) { sizeForDrawing = minimumPixelSizeForPercentageText; } } break; case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH: { /* * May need pixel to points conversion if not 72 DPI */ const float pixelSize = drawingViewportWidth * (m_fontPercentViewportSize / 100.0); sizeForDrawing = pixelSize; if (sizeForDrawing < minimumPixelSizeForPercentageText) { sizeForDrawing = minimumPixelSizeForPercentageText; } } break; } const int32_t sizeInt = static_cast(MathFunctions::round(sizeForDrawing)); return sizeInt; } /** * @return The font point size. */ AnnotationTextFontPointSizeEnum::Enum AnnotationText::getFontPointSizeProtected() const { return m_fontPointSize; } /** * Set the font point size. * * @param fontPointSize * New font point size. */ void AnnotationText::setFontPointSizeProtected(const AnnotationTextFontPointSizeEnum::Enum fontPointSize) { if (fontPointSize != m_fontPointSize) { m_fontPointSize = fontPointSize; setModified(); } } /** * @param The font size type. */ AnnotationTextFontSizeTypeEnum::Enum AnnotationText::getFontSizeType() const { return m_fontSizeType; } /** * @return The text orientation. */ AnnotationTextOrientationEnum::Enum AnnotationText::getOrientation() const { return m_orientation; } /** * Set the text orientation. * * @param orientation * New value for orientation. */ void AnnotationText::setOrientation(const AnnotationTextOrientationEnum::Enum orientation) { if (orientation != m_orientation) { m_orientation = orientation; setModified(); } } /** * Get the icon color for this item. Icon is filled with background * color, outline color is drawn around edges, and text color is small * square in center. For any colors that do not apply, use an alpha * value (last element) of zero. * * @param backgroundRgbaOut * Red, green, blue, alpha components for background ranging [0, 1]. * @param outlineRgbaOut * Red, green, blue, alpha components for outline ranging [0, 1]. * @param textRgbaOut * Red, green, blue, alpha components for text ranging [0, 1]. */ void AnnotationText::getItemIconColorsRGBA(float backgroundRgbaOut[4], float outlineRgbaOut[4], float textRgbaOut[4]) const { /* * Sets the background and outline colors */ Annotation::getItemIconColorsRGBA(backgroundRgbaOut, outlineRgbaOut, textRgbaOut); getTextColorRGBA(textRgbaOut); } /** * @return The foreground color. */ CaretColorEnum::Enum AnnotationText::getTextColor() const { return m_colorText; } /** * Set the foreground color. * * @param color * New value for foreground color. */ void AnnotationText::setTextColor(const CaretColorEnum::Enum color) { if (m_colorText != color) { m_colorText = color; setModified(); } } /** * Get the foreground color's RGBA components regardless of * coloring (custom color or a CaretColorEnum) selected by the user. * * @param rgbaOut * RGBA components ranging 0.0 to 1.0. */ void AnnotationText::getTextColorRGBA(float rgbaOut[4]) const { switch (m_colorText) { case CaretColorEnum::NONE: rgbaOut[0] = 0.0; rgbaOut[1] = 0.0; rgbaOut[2] = 0.0; rgbaOut[3] = 0.0; break; case CaretColorEnum::CUSTOM: getCustomTextColor(rgbaOut); break; case CaretColorEnum::AQUA: case CaretColorEnum::BLACK: case CaretColorEnum::BLUE: case CaretColorEnum::FUCHSIA: case CaretColorEnum::GRAY: case CaretColorEnum::GREEN: case CaretColorEnum::LIME: case CaretColorEnum::MAROON: case CaretColorEnum::NAVY: case CaretColorEnum::OLIVE: case CaretColorEnum::PURPLE: case CaretColorEnum::RED: case CaretColorEnum::SILVER: case CaretColorEnum::TEAL: case CaretColorEnum::WHITE: case CaretColorEnum::YELLOW: CaretColorEnum::toRGBAFloat(m_colorText, rgbaOut); rgbaOut[3] = 1.0; break; } } /** * Get the foreground color's RGBA components regardless of * coloring (custom color or a CaretColorEnum) selected by the user. * * @param rgbaOut * RGBA components ranging 0 to 255. */ void AnnotationText::getTextColorRGBA(uint8_t rgbaOut[4]) const { float rgbaFloat[4] = { 0.0, 0.0, 0.0, 0.0 }; getTextColorRGBA(rgbaFloat); rgbaOut[0] = static_cast(rgbaFloat[0] * 255.0); rgbaOut[1] = static_cast(rgbaFloat[1] * 255.0); rgbaOut[2] = static_cast(rgbaFloat[2] * 255.0); rgbaOut[3] = static_cast(rgbaFloat[3] * 255.0); } /** * Get the foreground color. * * @param rgbaOut * RGBA components (red, green, blue, alpha) each of which ranges [0.0, 1.0]. */ void AnnotationText::getCustomTextColor(float rgbaOut[4]) const { rgbaOut[0] = m_customColorText[0]; rgbaOut[1] = m_customColorText[1]; rgbaOut[2] = m_customColorText[2]; rgbaOut[3] = m_customColorText[3]; } /** * Get the foreground color. * * @param rgbaOut * RGBA components (red, green, blue, alpha) each of which ranges [0, 255]. */ void AnnotationText::getCustomTextColor(uint8_t rgbaOut[4]) const { rgbaOut[0] = static_cast(m_customColorText[0] * 255.0); rgbaOut[1] = static_cast(m_customColorText[1] * 255.0); rgbaOut[2] = static_cast(m_customColorText[2] * 255.0); rgbaOut[3] = static_cast(m_customColorText[3] * 255.0); } /** * Set the foreground color with floats. * * @param rgba * RGBA components (red, green, blue, alpha) each of which ranges [0.0, 1.0]. */ void AnnotationText::setCustomTextColor(const float rgba[4]) { for (int32_t i = 0; i < 4; i++) { if (rgba[i] != m_customColorText[i]) { m_customColorText[i] = rgba[i]; setModified(); } } } /** * Set the foreground color with unsigned bytes. * * @param rgba * RGBA components (red, green, blue, alpha) each of which ranges [0, 255]. */ void AnnotationText::setCustomTextColor(const uint8_t rgba[4]) { for (int32_t i = 0; i < 4; i++) { const float component = rgba[i] / 255.0; if (component != m_customColorText[i]) { m_customColorText[i] = component; setModified(); } } } /** * @return * Is bold enabled ? */ bool AnnotationText::isBoldStyleEnabled() const { return m_boldEnabled; } /** * Set bold enabled. * * @param enabled * New status for bold enabled. */ void AnnotationText::setBoldStyleEnabled(const bool enabled) { if (enabled != m_boldEnabled) { m_boldEnabled = enabled; setModified(); } } /** * @return * Is italic enabled ? */ bool AnnotationText::isItalicStyleEnabled() const { return m_italicEnabled; } /** * Set italic enabled. * * @param enabled * New status for italic enabled. */ void AnnotationText::setItalicStyleEnabled(const bool enabled) { if (enabled != m_italicEnabled) { m_italicEnabled = enabled; setModified(); } } /** * @return * Is underline enabled ? */ bool AnnotationText::isUnderlineStyleEnabled() const { return m_underlineEnabled; } /** * Set underline enabled. * * @param enabled * New status for underline enabled. */ void AnnotationText::setUnderlineStyleEnabled(const bool enabled) { if (enabled != m_underlineEnabled) { m_underlineEnabled = enabled; setModified(); } } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void AnnotationText::copyHelperAnnotationText(const AnnotationText& obj) { m_text = obj.m_text; m_textWithSubstitutions.clear(); m_alignmentHorizontal = obj.m_alignmentHorizontal; m_alignmentVertical = obj.m_alignmentVertical; m_font = obj.m_font; m_fontPointSize = obj.m_fontPointSize; m_orientation = obj.m_orientation; m_colorText = obj.m_colorText; m_customColorText[0] = obj.m_customColorText[0]; m_customColorText[1] = obj.m_customColorText[1]; m_customColorText[2] = obj.m_customColorText[2]; m_customColorText[3] = obj.m_customColorText[3]; m_boldEnabled = obj.m_boldEnabled; m_italicEnabled = obj.m_italicEnabled; m_underlineEnabled = obj.m_underlineEnabled; m_connectToBrainordinate = obj.m_connectToBrainordinate; m_fontPercentViewportSize = obj.m_fontPercentViewportSize; m_fontTooSmallWhenLastDrawnFlag = obj.m_fontTooSmallWhenLastDrawnFlag; } /** * Apply the coordinates, size, and rotation from the given annotation * to this annotation. * * @param otherAnnotation * The other annotation from which attributes are obtained. */ void AnnotationText::applyCoordinatesSizeAndRotationFromOther(const Annotation* otherAnnotation) { AnnotationTwoDimensionalShape::applyCoordinatesSizeAndRotationFromOther(otherAnnotation); /* * Text size may change when an annotation is moved to a different * coordinate space (ie: Tab Space with Tile Tabs on to Window Space). */ const AnnotationPercentSizeText* otherTextAnn = dynamic_cast(otherAnnotation); AnnotationPercentSizeText* textAnn = dynamic_cast(this); if ((textAnn != NULL) && (otherTextAnn != NULL)) { textAnn->setFontPercentViewportSize(otherTextAnn->getFontPercentViewportSize()); } } /** * @return Size of font as a percentage of the viewport height. * * Range is zero to one-hundred. */ float AnnotationText::getFontPercentViewportSizeProtected() const { return m_fontPercentViewportSize; } /** * Set the size of the font as a percentage of the viewport height. * * @param fontPercentViewportHeight * New value for percentage of viewport height. * Range is zero to one-hundred. */ void AnnotationText::setFontPercentViewportSizeProtected(const float fontPercentViewportHeight) { bool validPercentSizeFlag = true; if (fontPercentViewportHeight < 0.0) { validPercentSizeFlag = false; } else if (fontPercentViewportHeight > 100.0) { /* * With surface montage tab sizing, percentage may exceed 100.0 * SO NOTHING TO DO */ } if ( ! validPercentSizeFlag) { const QString msg("Percent viewport height should range [0.0, 100.0] but value is " + QString::number(fontPercentViewportHeight)); CaretLogWarning(msg); CaretAssertMessage(0, msg); } if (fontPercentViewportHeight != m_fontPercentViewportSize) { m_fontPercentViewportSize = fontPercentViewportHeight; setModified(); } } /** * @return Is the font too small when it is last drawn * that may cause an OpenGL error and, as a result, * the text is not seen by the user. */ bool AnnotationText::isFontTooSmallWhenLastDrawn() const { return m_fontTooSmallWhenLastDrawnFlag; } void AnnotationText::setFontTooSmallWhenLastDrawn(const bool tooSmallFontFlag) const { m_fontTooSmallWhenLastDrawnFlag = tooSmallFontFlag; } /** * Apply a spatial modification to an annotation. * * @param spatialModification * Contains information about the spatial modification. * @return * True if the annotation was modified, else false. */ bool AnnotationText::applySpatialModification(const AnnotationSpatialModification& spatialModification) { /* * Text limits support of resize options */ bool operationSupportedFlag = false; switch (spatialModification.m_sizingHandleType) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: operationSupportedFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: operationSupportedFlag = true; break; } bool validFlag = false; if (operationSupportedFlag) { validFlag = AnnotationTwoDimensionalShape::applySpatialModification(spatialModification); } return validFlag; } /** * Save subclass data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void AnnotationText::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { AnnotationTwoDimensionalShape::saveSubClassDataToScene(sceneAttributes, sceneClass); if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { sceneClass->addBoolean("hasAttributesFlag", true); m_attributesAssistant->saveMembers(sceneAttributes, sceneClass); } } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void AnnotationText::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { AnnotationTwoDimensionalShape::restoreSubClassDataFromScene(sceneAttributes, sceneClass); if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { /* * This flag will tell us if the scene has attributes. * If this test was not performed and attributes were not in scene * members in the atttributes assistant would overwrite initialized * values with invalid values. */ if (sceneClass->getBooleanValue("hasAttributesFlag")) { m_attributesAssistant->restoreMembers(sceneAttributes, sceneClass); } } } /** * Set the default value for horizontal alignment. * * @param alignment * Default for newly created text annotations. */ void AnnotationText::setUserDefaultHorizontalAlignment(const AnnotationTextAlignHorizontalEnum::Enum alignment) { s_userDefaultAlignmentHorizontal = alignment; } /** * Set the default value for vertical alignment. * * @param alignment * Default for newly created text annotations. */ void AnnotationText::setUserDefaultVerticalAlignment(const AnnotationTextAlignVerticalEnum::Enum alignment) { s_userDefaultAlignmentVertical = alignment; } /** * Set the default value for the font name. * * @param font * Default for newly created text annotations. */ void AnnotationText::setUserDefaultFont(const AnnotationTextFontNameEnum::Enum font) { s_userDefaultFont = font; } /** * Set the default value for the text orientation. * * @param orientation * Default for newly created text annotations. */ void AnnotationText::setUserDefaultOrientation(const AnnotationTextOrientationEnum::Enum orientation) { s_userDefaultOrientation = orientation; } /** * Set the default value for font point size. * * @param fontPointSize * Default for newly created text annotations. */ void AnnotationText::setUserDefaultFontPointSize(const AnnotationTextFontPointSizeEnum::Enum fontPointSize) { s_userDefaultPointSize = fontPointSize; } /** * Set the default value for font percent viewport height. * * @param fontPercentViewportHeight * Default for newly created text annotations. */ void AnnotationText::setUserDefaultFontPercentViewportSize(const float fontPercentViewportHeight) { s_userDefaultFontPercentViewportSize = fontPercentViewportHeight; } /** * Set the default value for text color * * @param color * Default for newly created annotations. */ void AnnotationText::setUserDefaultTextColor(const CaretColorEnum::Enum color) { s_userDefaultColorText = color; } /** * Set the default value for custom text color * * @param rgba * Default for newly created annotations. */ void AnnotationText::setUserDefaultCustomTextColor(const float rgba[4]) { s_userDefaultCustomColorText[0] = rgba[0]; s_userDefaultCustomColorText[1] = rgba[1]; s_userDefaultCustomColorText[2] = rgba[2]; s_userDefaultCustomColorText[3] = rgba[3]; } /** * Set the default value for bold enabled. * * @param enabled * Default for newly created text annotations. */ void AnnotationText::setUserDefaultBoldEnabled(const bool enabled) { s_userDefaultBoldEnabled = enabled; } /** * Set the default value for italic enabled. * * @param enabled * Default for newly created text annotations. */ void AnnotationText::setUserDefaultItalicEnabled(const bool enabled) { s_userDefaultItalicEnabled = enabled; } /** * Set the default value for underline enabled. * * @param enabled * Default for newly created text annotations. */ void AnnotationText::setUserDefaultUnderlineEnabled(const bool enabled) { s_userDefaultUnderlineEnabled = enabled; } /** * Set the default value for connect to brainordinate. * * @param connectToBrainordinate * Default for newly created text annotations. */ void AnnotationText::setUserDefaultConnectToBrainordinate(const AnnotationTextConnectTypeEnum::Enum connectToBrainordinate) { s_userDefaultConnectToBrainordinate = connectToBrainordinate; } connectome-workbench-1.4.2/src/Annotations/AnnotationText.h000066400000000000000000000264031360521144700240540ustar00rootroot00000000000000#ifndef __ANNOTATION_TEXT_H__ #define __ANNOTATION_TEXT_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationFontAttributesInterface.h" #include "AnnotationTextFontPointSizeEnum.h" #include "AnnotationTextAlignHorizontalEnum.h" #include "AnnotationTextAlignVerticalEnum.h" #include "AnnotationTextFontSizeTypeEnum.h" #include "AnnotationTextConnectTypeEnum.h" #include "AnnotationTextOrientationEnum.h" #include "AnnotationTwoDimensionalShape.h" #include "CaretPointer.h" namespace caret { class AnnotationText : public AnnotationTwoDimensionalShape, public AnnotationFontAttributesInterface { public: /** * @return The "too small" text size. * * When the text is smaller than this font height, either all of the * text string may not be drawn or just particular characters */ static uint32_t getTooSmallTextHeight() { return 8; } virtual ~AnnotationText(); AnnotationText(const AnnotationText& obj); AnnotationText& operator=(const AnnotationText& obj); AString getFontRenderingEncodedName(const float drawingViewportWidth, const float drawingViewportHeight) const; AString getText() const; void setText(const AString& text); AString getTextWithSubstitutionsApplied() const; AnnotationTextAlignHorizontalEnum::Enum getHorizontalAlignment() const; void setHorizontalAlignment(const AnnotationTextAlignHorizontalEnum::Enum alignment); AnnotationTextAlignVerticalEnum::Enum getVerticalAlignment() const; void setVerticalAlignment(const AnnotationTextAlignVerticalEnum::Enum alignment); virtual AnnotationTextFontNameEnum::Enum getFont() const; virtual void setFont(const AnnotationTextFontNameEnum::Enum font); virtual float getFontPercentViewportSize() const = 0; virtual void setFontPercentViewportSize(const float fontPercentViewportHeight) = 0; AnnotationTextOrientationEnum::Enum getOrientation() const; void setOrientation(const AnnotationTextOrientationEnum::Enum orientation); int32_t getFontSizeForDrawing(const int32_t drawingViewportWidth, const int32_t drawingViewportHeight) const; bool isFontTooSmallWhenLastDrawn() const override; void setFontTooSmallWhenLastDrawn(const bool tooSmallFontFlag) const override; AnnotationTextFontSizeTypeEnum::Enum getFontSizeType() const; virtual CaretColorEnum::Enum getTextColor() const; virtual void setTextColor(const CaretColorEnum::Enum color); virtual void getTextColorRGBA(float rgbaOut[4]) const; virtual void getTextColorRGBA(uint8_t rgbaOut[4]) const; virtual void getCustomTextColor(float rgbaOut[4]) const; virtual void getCustomTextColor(uint8_t rgbaOut[4]) const; virtual void setCustomTextColor(const float rgba[4]); virtual void setCustomTextColor(const uint8_t rgba[4]); virtual bool isBoldStyleEnabled() const; virtual void setBoldStyleEnabled(const bool enabled); virtual bool isItalicStyleEnabled() const; virtual void setItalicStyleEnabled(const bool enabled); virtual bool isUnderlineStyleEnabled() const; virtual void setUnderlineStyleEnabled(const bool enabled); AnnotationTextConnectTypeEnum::Enum getConnectToBrainordinate() const; void setConnectToBrainordinate(const AnnotationTextConnectTypeEnum::Enum connectToBrainordinate); bool isConnectToBrainordinateValid() const; virtual bool applySpatialModification(const AnnotationSpatialModification& spatialModification); virtual void applyCoordinatesSizeAndRotationFromOther(const Annotation* otherAnnotation); virtual void getItemIconColorsRGBA(float backgroundRgbaOut[4], float outlineRgbaOut[4], float textRgbaOut[4]) const; static void setUserDefaultHorizontalAlignment(const AnnotationTextAlignHorizontalEnum::Enum alignment); static void setUserDefaultVerticalAlignment(const AnnotationTextAlignVerticalEnum::Enum alignment); static void setUserDefaultFont(const AnnotationTextFontNameEnum::Enum font); static void setUserDefaultOrientation(const AnnotationTextOrientationEnum::Enum orientation); static void setUserDefaultFontPointSize(const AnnotationTextFontPointSizeEnum::Enum fontPointSize); static void setUserDefaultFontPercentViewportSize(const float fontPercentViewportHeight); static void setUserDefaultTextColor(const CaretColorEnum::Enum color); static void setUserDefaultCustomTextColor(const float rgba[4]); static void setUserDefaultBoldEnabled(const bool enabled); static void setUserDefaultItalicEnabled(const bool enabled); static void setUserDefaultUnderlineEnabled(const bool enabled); static void setUserDefaultOutlineEnabled(const bool enabled); static void setUserDefaultConnectToBrainordinate(const AnnotationTextConnectTypeEnum::Enum connectToBrainordinate); // ADD_NEW_METHODS_HERE protected: AnnotationText(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, const AnnotationTextFontSizeTypeEnum::Enum fontSizeType); AnnotationText(const AnnotationTypeEnum::Enum type, const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType, const AnnotationTextFontSizeTypeEnum::Enum fontSizeType); virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); AnnotationTextFontPointSizeEnum::Enum getFontPointSizeProtected() const; void setFontPointSizeProtected(const AnnotationTextFontPointSizeEnum::Enum fontPointSize); float getFontPercentViewportSizeProtected() const; void setFontPercentViewportSizeProtected(const float fontPercentViewportHeight); virtual void invalidateTextSubstitution() override; private: /* Not implemented */ AnnotationText(); void copyHelperAnnotationText(const AnnotationText& obj); void initializeAnnotationTextMembers(); /* Not saved to scene since it is set by sub-class constructor. */ const AnnotationTextFontSizeTypeEnum::Enum m_fontSizeType; CaretPointer m_attributesAssistant; AString m_text; /* Not saved to scenes */ mutable AString m_textWithSubstitutions; AnnotationTextAlignHorizontalEnum::Enum m_alignmentHorizontal; AnnotationTextAlignVerticalEnum::Enum m_alignmentVertical; AnnotationTextFontNameEnum::Enum m_font; AnnotationTextOrientationEnum::Enum m_orientation; AnnotationTextFontPointSizeEnum::Enum m_fontPointSize; AnnotationTextConnectTypeEnum::Enum m_connectToBrainordinate; float m_fontPercentViewportSize; CaretColorEnum::Enum m_colorText; float m_customColorText[4]; bool m_boldEnabled; bool m_italicEnabled; bool m_underlineEnabled; mutable bool m_fontTooSmallWhenLastDrawnFlag = false; // Defaults static AnnotationTextAlignHorizontalEnum::Enum s_userDefaultAlignmentHorizontal; static AnnotationTextAlignVerticalEnum::Enum s_userDefaultAlignmentVertical; static AnnotationTextFontNameEnum::Enum s_userDefaultFont; static AnnotationTextOrientationEnum::Enum s_userDefaultOrientation; static AnnotationTextFontPointSizeEnum::Enum s_userDefaultPointSize; static AnnotationTextConnectTypeEnum::Enum s_userDefaultConnectToBrainordinate; static CaretColorEnum::Enum s_userDefaultColorText; static float s_userDefaultCustomColorText[4]; static float s_userDefaultFontPercentViewportSize; static bool s_userDefaultBoldEnabled; static bool s_userDefaultItalicEnabled; static bool s_userDefaultUnderlineEnabled; // ADD_NEW_MEMBERS_HERE friend class AnnotationFileXmlReader; friend class AnnotationFileXmlWriter; }; #ifdef __ANNOTATION_TEXT_DECLARE__ AnnotationTextAlignHorizontalEnum::Enum AnnotationText::s_userDefaultAlignmentHorizontal = AnnotationTextAlignHorizontalEnum::CENTER; AnnotationTextAlignVerticalEnum::Enum AnnotationText::s_userDefaultAlignmentVertical = AnnotationTextAlignVerticalEnum::MIDDLE; AnnotationTextFontNameEnum::Enum AnnotationText::s_userDefaultFont = AnnotationTextFontNameEnum::VERA; AnnotationTextOrientationEnum::Enum AnnotationText::s_userDefaultOrientation = AnnotationTextOrientationEnum::HORIZONTAL; AnnotationTextFontPointSizeEnum::Enum AnnotationText::s_userDefaultPointSize = AnnotationTextFontPointSizeEnum::SIZE14; AnnotationTextConnectTypeEnum::Enum AnnotationText::s_userDefaultConnectToBrainordinate = AnnotationTextConnectTypeEnum::ANNOTATION_TEXT_CONNECT_NONE; CaretColorEnum::Enum AnnotationText::s_userDefaultColorText = CaretColorEnum::WHITE; float AnnotationText::s_userDefaultCustomColorText[4] = { 1.0, 1.0, 1.0, 1.0 }; float AnnotationText::s_userDefaultFontPercentViewportSize = 5.0; bool AnnotationText::s_userDefaultBoldEnabled = false; bool AnnotationText::s_userDefaultItalicEnabled = false; bool AnnotationText::s_userDefaultUnderlineEnabled = false; #endif // __ANNOTATION_TEXT_DECLARE__ } // namespace #endif //__ANNOTATION_TEXT_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationTextAlignHorizontalEnum.cxx000066400000000000000000000264471360521144700303110ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_TEXT_ALIGN_HORIZONTAL_ENUM_DECLARE__ #include "AnnotationTextAlignHorizontalEnum.h" #undef __ANNOTATION_TEXT_ALIGN_HORIZONTAL_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationTextAlignHorizontalEnum * \brief Horizontal alignment for text annotations. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_annotationAlignHorizontalEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void annotationAlignHorizontalEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "AnnotationTextAlignHorizontalEnum.h" * * Instatiate: * m_annotationAlignHorizontalEnumComboBox = new EnumComboBoxTemplate(this); * m_annotationAlignHorizontalEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_annotationAlignHorizontalEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(annotationAlignHorizontalEnumComboBoxItemActivated())); * * Update the selection: * m_annotationAlignHorizontalEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const AnnotationTextAlignHorizontalEnum::Enum VARIABLE = m_annotationAlignHorizontalEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ AnnotationTextAlignHorizontalEnum::AnnotationTextAlignHorizontalEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ AnnotationTextAlignHorizontalEnum::~AnnotationTextAlignHorizontalEnum() { } /** * Initialize the enumerated metadata. */ void AnnotationTextAlignHorizontalEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(AnnotationTextAlignHorizontalEnum(LEFT, "LEFT", "Left")); enumData.push_back(AnnotationTextAlignHorizontalEnum(CENTER, "CENTER", "Center")); enumData.push_back(AnnotationTextAlignHorizontalEnum(RIGHT, "RIGHT", "Right")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const AnnotationTextAlignHorizontalEnum* AnnotationTextAlignHorizontalEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const AnnotationTextAlignHorizontalEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationTextAlignHorizontalEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextAlignHorizontalEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationTextAlignHorizontalEnum::Enum AnnotationTextAlignHorizontalEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTextAlignHorizontalEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextAlignHorizontalEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type AnnotationTextAlignHorizontalEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationTextAlignHorizontalEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextAlignHorizontalEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationTextAlignHorizontalEnum::Enum AnnotationTextAlignHorizontalEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTextAlignHorizontalEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextAlignHorizontalEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type AnnotationTextAlignHorizontalEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t AnnotationTextAlignHorizontalEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextAlignHorizontalEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ AnnotationTextAlignHorizontalEnum::Enum AnnotationTextAlignHorizontalEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTextAlignHorizontalEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextAlignHorizontalEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type AnnotationTextAlignHorizontalEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void AnnotationTextAlignHorizontalEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationTextAlignHorizontalEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(AnnotationTextAlignHorizontalEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationTextAlignHorizontalEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(AnnotationTextAlignHorizontalEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Annotations/AnnotationTextAlignHorizontalEnum.h000066400000000000000000000064411360521144700277260ustar00rootroot00000000000000#ifndef __ANNOTATION_TEXT_ALIGN_HORIZONTAL_ENUM_H__ #define __ANNOTATION_TEXT_ALIGN_HORIZONTAL_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class AnnotationTextAlignHorizontalEnum { public: /** * Enumerated values. */ enum Enum { /** Align Left */ LEFT, /** Align Center */ CENTER, /** Align Right */ RIGHT }; ~AnnotationTextAlignHorizontalEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: AnnotationTextAlignHorizontalEnum(const Enum enumValue, const AString& name, const AString& guiName); static const AnnotationTextAlignHorizontalEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __ANNOTATION_TEXT_ALIGN_HORIZONTAL_ENUM_DECLARE__ std::vector AnnotationTextAlignHorizontalEnum::enumData; bool AnnotationTextAlignHorizontalEnum::initializedFlag = false; int32_t AnnotationTextAlignHorizontalEnum::integerCodeCounter = 0; #endif // __ANNOTATION_TEXT_ALIGN_HORIZONTAL_ENUM_DECLARE__ } // namespace #endif //__ANNOTATION_TEXT_ALIGN_HORIZONTAL_ENUM_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationTextAlignVerticalEnum.cxx000066400000000000000000000262431360521144700277230ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_TEXT_ALIGN_VERTICAL_ENUM_DECLARE__ #include "AnnotationTextAlignVerticalEnum.h" #undef __ANNOTATION_TEXT_ALIGN_VERTICAL_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationTextAlignVerticalEnum * \brief Vertical alignment for text annotations. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_annotationAlignVerticalEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void annotationAlignVerticalEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "AnnotationTextAlignVerticalEnum.h" * * Instatiate: * m_annotationAlignVerticalEnumComboBox = new EnumComboBoxTemplate(this); * m_annotationAlignVerticalEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_annotationAlignVerticalEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(annotationAlignVerticalEnumComboBoxItemActivated())); * * Update the selection: * m_annotationAlignVerticalEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const AnnotationTextAlignVerticalEnum::Enum VARIABLE = m_annotationAlignVerticalEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ AnnotationTextAlignVerticalEnum::AnnotationTextAlignVerticalEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ AnnotationTextAlignVerticalEnum::~AnnotationTextAlignVerticalEnum() { } /** * Initialize the enumerated metadata. */ void AnnotationTextAlignVerticalEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(AnnotationTextAlignVerticalEnum(BOTTOM, "BOTTOM", "Bottom")); enumData.push_back(AnnotationTextAlignVerticalEnum(MIDDLE, "MIDDLE", "Middle")); enumData.push_back(AnnotationTextAlignVerticalEnum(TOP, "TOP", "Top")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const AnnotationTextAlignVerticalEnum* AnnotationTextAlignVerticalEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const AnnotationTextAlignVerticalEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationTextAlignVerticalEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextAlignVerticalEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationTextAlignVerticalEnum::Enum AnnotationTextAlignVerticalEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTextAlignVerticalEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextAlignVerticalEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type AnnotationTextAlignVerticalEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationTextAlignVerticalEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextAlignVerticalEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationTextAlignVerticalEnum::Enum AnnotationTextAlignVerticalEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTextAlignVerticalEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextAlignVerticalEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type AnnotationTextAlignVerticalEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t AnnotationTextAlignVerticalEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextAlignVerticalEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ AnnotationTextAlignVerticalEnum::Enum AnnotationTextAlignVerticalEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTextAlignVerticalEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextAlignVerticalEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type AnnotationTextAlignVerticalEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void AnnotationTextAlignVerticalEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationTextAlignVerticalEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(AnnotationTextAlignVerticalEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationTextAlignVerticalEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(AnnotationTextAlignVerticalEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Annotations/AnnotationTextAlignVerticalEnum.h000066400000000000000000000064051360521144700273460ustar00rootroot00000000000000#ifndef __ANNOTATION_TEXT_ALIGN_VERTICAL_ENUM_H__ #define __ANNOTATION_TEXT_ALIGN_VERTICAL_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class AnnotationTextAlignVerticalEnum { public: /** * Enumerated values. */ enum Enum { /** Align Bottom */ BOTTOM, /** Align Middle */ MIDDLE, /** Align Top */ TOP }; ~AnnotationTextAlignVerticalEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: AnnotationTextAlignVerticalEnum(const Enum enumValue, const AString& name, const AString& guiName); static const AnnotationTextAlignVerticalEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __ANNOTATION_TEXT_ALIGN_VERTICAL_ENUM_DECLARE__ std::vector AnnotationTextAlignVerticalEnum::enumData; bool AnnotationTextAlignVerticalEnum::initializedFlag = false; int32_t AnnotationTextAlignVerticalEnum::integerCodeCounter = 0; #endif // __ANNOTATION_TEXT_ALIGN_VERTICAL_ENUM_DECLARE__ } // namespace #endif //__ANNOTATION_TEXT_ALIGN_VERTICAL_ENUM_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationTextConnectTypeEnum.cxx000066400000000000000000000264051360521144700274320ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_TEXT_CONNECT_TYPE_ENUM_DECLARE__ #include "AnnotationTextConnectTypeEnum.h" #undef __ANNOTATION_TEXT_CONNECT_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationTextConnectTypeEnum * \brief Enumerated type for connecting a text annotation to a stereotaxic coordinate with arrow or line * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_annotationTextConnectTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void annotationTextConnectTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "AnnotationTextConnectTypeEnum.h" * * Instatiate: * m_annotationTextConnectTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_annotationTextConnectTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_annotationTextConnectTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(annotationTextConnectTypeEnumComboBoxItemActivated())); * * Update the selection: * m_annotationTextConnectTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const AnnotationTextConnectTypeEnum::Enum VARIABLE = m_annotationTextConnectTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ AnnotationTextConnectTypeEnum::AnnotationTextConnectTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ AnnotationTextConnectTypeEnum::~AnnotationTextConnectTypeEnum() { } /** * Initialize the enumerated metadata. */ void AnnotationTextConnectTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(AnnotationTextConnectTypeEnum(ANNOTATION_TEXT_CONNECT_NONE, "ANNOTATION_TEXT_CONNECT_NONE", "Off")); enumData.push_back(AnnotationTextConnectTypeEnum(ANNOTATION_TEXT_CONNECT_ARROW, "ANNOTATION_TEXT_CONNECT_ARROW", "Arrow")); enumData.push_back(AnnotationTextConnectTypeEnum(ANNOTATION_TEXT_CONNECT_LINE, "ANNOTATION_TEXT_CONNECT_LINE", "Line")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const AnnotationTextConnectTypeEnum* AnnotationTextConnectTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const AnnotationTextConnectTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationTextConnectTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextConnectTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationTextConnectTypeEnum::Enum AnnotationTextConnectTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTextConnectTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextConnectTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type AnnotationTextConnectTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationTextConnectTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextConnectTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationTextConnectTypeEnum::Enum AnnotationTextConnectTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTextConnectTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextConnectTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type AnnotationTextConnectTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t AnnotationTextConnectTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextConnectTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ AnnotationTextConnectTypeEnum::Enum AnnotationTextConnectTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTextConnectTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextConnectTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type AnnotationTextConnectTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void AnnotationTextConnectTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationTextConnectTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(AnnotationTextConnectTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationTextConnectTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(AnnotationTextConnectTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Annotations/AnnotationTextConnectTypeEnum.h000066400000000000000000000066251360521144700270610ustar00rootroot00000000000000#ifndef __ANNOTATION_TEXT_CONNECT_TYPE_ENUM_H__ #define __ANNOTATION_TEXT_CONNECT_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class AnnotationTextConnectTypeEnum { public: /** * Enumerated values. */ enum Enum { /** No connection of annotation to brainordinate */ ANNOTATION_TEXT_CONNECT_NONE, /** Connect annotation to brainordinate with arrow */ ANNOTATION_TEXT_CONNECT_ARROW, /** Connect annotation to brainordinate with line */ ANNOTATION_TEXT_CONNECT_LINE }; ~AnnotationTextConnectTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: AnnotationTextConnectTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const AnnotationTextConnectTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __ANNOTATION_TEXT_CONNECT_TYPE_ENUM_DECLARE__ std::vector AnnotationTextConnectTypeEnum::enumData; bool AnnotationTextConnectTypeEnum::initializedFlag = false; int32_t AnnotationTextConnectTypeEnum::integerCodeCounter = 0; #endif // __ANNOTATION_TEXT_CONNECT_TYPE_ENUM_DECLARE__ } // namespace #endif //__ANNOTATION_TEXT_CONNECT_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationTextFontNameEnum.cxx000066400000000000000000000347501360521144700267100ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_TEXT_FONT_NAME_ENUM_DECLARE__ #include "AnnotationTextFontNameEnum.h" #undef __ANNOTATION_TEXT_FONT_NAME_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationTextFontNameEnum * \brief Names of annotation fonts * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_annotationFontNameEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void annotationFontNameEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "AnnotationTextFontNameEnum.h" * * Instatiate: * m_annotationFontNameEnumComboBox = new EnumComboBoxTemplate(this); * m_annotationFontNameEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_annotationFontNameEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(annotationFontNameEnumComboBoxItemActivated())); * * Update the selection: * m_annotationFontNameEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const AnnotationTextFontNameEnum::Enum VARIABLE = m_annotationFontNameEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ AnnotationTextFontNameEnum::AnnotationTextFontNameEnum(const Enum enumValue, const AString& name, const AString& guiName, const AString& fontFileName, const AString& boldFontFileName, const AString& boldItalicFontFileName, const AString& italicFontFileName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; this->resourceFontFileName = fontFileName; this->resourceBoldFontFileName = boldFontFileName; this->resourceBoldItalicFontFileName = boldItalicFontFileName; this->resourceItalicFontFileName = italicFontFileName; } /** * Destructor. */ AnnotationTextFontNameEnum::~AnnotationTextFontNameEnum() { } /** * Initialize the enumerated metadata. */ void AnnotationTextFontNameEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(AnnotationTextFontNameEnum(LIBERTINE, "LIBERTINE", "Libertine", ":/Fonts/LinuxLibertine/LinLibertine_Rah.ttf", ":/Fonts/LinuxLibertine/LinLibertine_RBah.ttf", ":/Fonts/LinuxLibertine/LinLibertine_RBIah.ttf", ":/Fonts/LinuxLibertine/LinLibertine_RIah.ttf")); enumData.push_back(AnnotationTextFontNameEnum(VERA, "VERA", "Vera", ":/Fonts/VeraFonts/Vera.ttf", ":/Fonts/VeraFonts/VeraBd.ttf", ":/Fonts/VeraFonts/VeraBI.ttf", ":/Fonts/VeraFonts/VeraIt.ttf")); enumData.push_back(AnnotationTextFontNameEnum(VERA_MONOSPACE, "VERA_MONOSPACE", "Vera Mono", ":/Fonts/VeraFonts/VeraMono.ttf", ":/Fonts/VeraFonts/VeraMoBd.ttf", ":/Fonts/VeraFonts/VeraMoBI.ttf", ":/Fonts/VeraFonts/VeraMoIt.ttf")); } /** * @return The default font name. */ AnnotationTextFontNameEnum::Enum AnnotationTextFontNameEnum::getDefaultFontName() { if (initializedFlag == false) initialize(); CaretAssert( ! enumData.empty()); return AnnotationTextFontNameEnum::VERA; // return enumData[0].enumValue; } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const AnnotationTextFontNameEnum* AnnotationTextFontNameEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const AnnotationTextFontNameEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationTextFontNameEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextFontNameEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationTextFontNameEnum::Enum AnnotationTextFontNameEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = getDefaultFontName(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextFontNameEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type AnnotationTextFontNameEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationTextFontNameEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextFontNameEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationTextFontNameEnum::Enum AnnotationTextFontNameEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = getDefaultFontName(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextFontNameEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type AnnotationTextFontNameEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t AnnotationTextFontNameEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextFontNameEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ AnnotationTextFontNameEnum::Enum AnnotationTextFontNameEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = getDefaultFontName(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextFontNameEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type AnnotationTextFontNameEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void AnnotationTextFontNameEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationTextFontNameEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(AnnotationTextFontNameEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationTextFontNameEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(AnnotationTextFontNameEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } /** * Get the resource file name for the regular font file. * * @param enumValue * Enumerated value. * @return * String containing name of font file in resources. */ AString AnnotationTextFontNameEnum::getResourceFontFileName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextFontNameEnum* enumInstance = findData(enumValue); return enumInstance->resourceFontFileName; } /** * Get the resource file name for the bold font file. * * @param enumValue * Enumerated value. * @return * String containing name of font file in resources. */ AString AnnotationTextFontNameEnum::getResourceBoldFontFileName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextFontNameEnum* enumInstance = findData(enumValue); return enumInstance->resourceBoldFontFileName; } /** * Get the resource file name for the bold italic font file. * * @param enumValue * Enumerated value. * @return * String containing name of font file in resources. */ AString AnnotationTextFontNameEnum::getResourceBoldItalicFontFileName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextFontNameEnum* enumInstance = findData(enumValue); return enumInstance->resourceBoldItalicFontFileName; } /** * Get the resource file name for the italic font file. * * @param enumValue * Enumerated value. * @return * String containing name of font file in resources. */ AString AnnotationTextFontNameEnum::getResourceItalicFontFileName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextFontNameEnum* enumInstance = findData(enumValue); return enumInstance->resourceItalicFontFileName; } connectome-workbench-1.4.2/src/Annotations/AnnotationTextFontNameEnum.h000066400000000000000000000101111360521144700263160ustar00rootroot00000000000000#ifndef __ANNOTATION_TEXT_FONT_NAME_ENUM_H__ #define __ANNOTATION_TEXT_FONT_NAME_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class AnnotationTextFontNameEnum { public: /** * Enumerated values. */ enum Enum { /** Libertine */ LIBERTINE, /** Vera Fonts */ VERA, /** Vera Monospaced Fonts */ VERA_MONOSPACE }; ~AnnotationTextFontNameEnum(); static Enum getDefaultFontName(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); static AString getResourceFontFileName(Enum enumValue); static AString getResourceBoldFontFileName(Enum enumValue); static AString getResourceBoldItalicFontFileName(Enum enumValue); static AString getResourceItalicFontFileName(Enum enumValue); private: AnnotationTextFontNameEnum(const Enum enumValue, const AString& name, const AString& guiName, const AString& fontFileName, const AString& boldFontFileName, const AString& boldItalicFontFileName, const AString& italicFontFileName); static const AnnotationTextFontNameEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; /** Name of font file */ AString resourceFontFileName; /** Name of bold font file */ AString resourceBoldFontFileName; /** Name of bold italic font file */ AString resourceBoldItalicFontFileName; /** Name of italic font file */ AString resourceItalicFontFileName; }; #ifdef __ANNOTATION_TEXT_FONT_NAME_ENUM_DECLARE__ std::vector AnnotationTextFontNameEnum::enumData; bool AnnotationTextFontNameEnum::initializedFlag = false; int32_t AnnotationTextFontNameEnum::integerCodeCounter = 0; #endif // __ANNOTATION_TEXT_FONT_NAME_ENUM_DECLARE__ } // namespace #endif //__ANNOTATION_TEXT_FONT_NAME_ENUM_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationTextFontPointSizeEnum.cxx000066400000000000000000000370731360521144700277550ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_TEXT_FONT_POINT_SIZE_ENUM_DECLARE__ #include "AnnotationTextFontPointSizeEnum.h" #undef __ANNOTATION_TEXT_FONT_POINT_SIZE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationTextFontPointSizeEnum * \brief Enumerated type for font size. * * * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_annotationFontSizeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void annotationFontSizeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "AnnotationTextFontPointSizeEnum.h" * * Instatiate: * m_annotationFontSizeEnumComboBox = new EnumComboBoxTemplate(this); * m_annotationFontSizeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_annotationFontSizeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(annotationFontSizeEnumComboBoxItemActivated())); * * Update the selection: * m_annotationFontSizeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const AnnotationTextFontPointSizeEnum::Enum VARIABLE = m_annotationFontSizeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. * @param sizeNumeric * Numerical size of font. */ AnnotationTextFontPointSizeEnum::AnnotationTextFontPointSizeEnum(const Enum enumValue, const AString& name, const AString& guiName, const int32_t sizeNumeric) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; this->sizeNumeric = sizeNumeric; } /** * Destructor. */ AnnotationTextFontPointSizeEnum::~AnnotationTextFontPointSizeEnum() { } /** * Initialize the enumerated metadata. */ void AnnotationTextFontPointSizeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(AnnotationTextFontPointSizeEnum(SIZE10, "SIZE10", "10", 10)); enumData.push_back(AnnotationTextFontPointSizeEnum(SIZE12, "SIZE12", "12", 12)); enumData.push_back(AnnotationTextFontPointSizeEnum(SIZE14, "SIZE14", "14", 14)); enumData.push_back(AnnotationTextFontPointSizeEnum(SIZE16, "SIZE16", "16", 16)); enumData.push_back(AnnotationTextFontPointSizeEnum(SIZE18, "SIZE18", "18", 18)); enumData.push_back(AnnotationTextFontPointSizeEnum(SIZE20, "SIZE20", "20", 20)); enumData.push_back(AnnotationTextFontPointSizeEnum(SIZE24, "SIZE24", "24", 24)); enumData.push_back(AnnotationTextFontPointSizeEnum(SIZE28, "SIZE28", "28", 28)); enumData.push_back(AnnotationTextFontPointSizeEnum(SIZE32, "SIZE32", "32", 32)); enumData.push_back(AnnotationTextFontPointSizeEnum(SIZE36, "SIZE36", "36", 36)); enumData.push_back(AnnotationTextFontPointSizeEnum(SIZE40, "SIZE40", "40", 40)); enumData.push_back(AnnotationTextFontPointSizeEnum(SIZE44, "SIZE44", "44", 44)); enumData.push_back(AnnotationTextFontPointSizeEnum(SIZE48, "SIZE48", "48", 48)); enumData.push_back(AnnotationTextFontPointSizeEnum(SIZE54, "SIZE54", "54", 54)); enumData.push_back(AnnotationTextFontPointSizeEnum(SIZE60, "SIZE60", "60", 60)); enumData.push_back(AnnotationTextFontPointSizeEnum(SIZE66, "SIZE66", "66", 66)); enumData.push_back(AnnotationTextFontPointSizeEnum(SIZE72, "SIZE72", "72", 72)); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { if (minimumNumericSize < 0) { minimumNumericSize = iter->sizeNumeric; } else if (iter->sizeNumeric < minimumNumericSize) { minimumNumericSize = iter->sizeNumeric; } } } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const AnnotationTextFontPointSizeEnum* AnnotationTextFontPointSizeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const AnnotationTextFontPointSizeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationTextFontPointSizeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextFontPointSizeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationTextFontPointSizeEnum::Enum AnnotationTextFontPointSizeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTextFontPointSizeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextFontPointSizeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type AnnotationTextFontPointSizeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationTextFontPointSizeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextFontPointSizeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationTextFontPointSizeEnum::Enum AnnotationTextFontPointSizeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTextFontPointSizeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextFontPointSizeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type AnnotationTextFontPointSizeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t AnnotationTextFontPointSizeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextFontPointSizeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ AnnotationTextFontPointSizeEnum::Enum AnnotationTextFontPointSizeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTextFontPointSizeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextFontPointSizeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type AnnotationTextFontPointSizeEnum")); } return enumValue; } /** * Get the integer size for a data type. * * @return * Integer size for data type. */ int32_t AnnotationTextFontPointSizeEnum::toSizeNumeric(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextFontPointSizeEnum* enumInstance = findData(enumValue); return enumInstance->sizeNumeric; } /** * @return The minimum font size numeric value. */ int32_t AnnotationTextFontPointSizeEnum::getMinimumSizeNumeric() { if (initializedFlag == false) initialize(); return minimumNumericSize; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void AnnotationTextFontPointSizeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationTextFontPointSizeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(AnnotationTextFontPointSizeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationTextFontPointSizeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(AnnotationTextFontPointSizeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Annotations/AnnotationTextFontPointSizeEnum.h000066400000000000000000000100121360521144700273620ustar00rootroot00000000000000#ifndef __ANNOTATION_TEXT_FONT_POINT_SIZE_ENUM_H__ #define __ANNOTATION_TEXT_FONT_POINT_SIZE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class AnnotationTextFontPointSizeEnum { public: /** * Enumerated values. */ enum Enum { /** */ SIZE10, /** */ SIZE12, /** */ SIZE14, /** */ SIZE16, /** */ SIZE18, /** */ SIZE20, /** */ SIZE24, /** */ SIZE28, /** */ SIZE32, /** */ SIZE36, /** */ SIZE40, /** */ SIZE44, /** */ SIZE48, /** */ SIZE54, /** */ SIZE60, /** */ SIZE66, /** */ SIZE72 }; ~AnnotationTextFontPointSizeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); static int32_t toSizeNumeric(Enum enumValue); static int32_t getMinimumSizeNumeric(); private: AnnotationTextFontPointSizeEnum(const Enum enumValue, const AString& name, const AString& guiName, const int32_t sizeNumeric); static const AnnotationTextFontPointSizeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; static int32_t minimumNumericSize; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; /** Numerical size of font */ int32_t sizeNumeric; }; #ifdef __ANNOTATION_TEXT_FONT_POINT_SIZE_ENUM_DECLARE__ std::vector AnnotationTextFontPointSizeEnum::enumData; bool AnnotationTextFontPointSizeEnum::initializedFlag = false; int32_t AnnotationTextFontPointSizeEnum::integerCodeCounter = 0; int32_t AnnotationTextFontPointSizeEnum::minimumNumericSize = -1; #endif // __ANNOTATION_TEXT_FONT_POINT_SIZE_ENUM_DECLARE__ } // namespace #endif //__ANNOTATION_TEXT_FONT_POINT_SIZE_ENUM_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationTextFontSizeTypeEnum.cxx000066400000000000000000000264131360521144700276010ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_TEXT_FONT_SIZE_TYPE_ENUM_DECLARE__ #include "AnnotationTextFontSizeTypeEnum.h" #undef __ANNOTATION_TEXT_FONT_SIZE_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationTextFontSizeTypeEnum * \brief Enumerated type for font sizing * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_annotationFontSizeTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void annotationFontSizeTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "AnnotationTextFontSizeTypeEnum.h" * * Instatiate: * m_annotationFontSizeTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_annotationFontSizeTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_annotationFontSizeTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(annotationFontSizeTypeEnumComboBoxItemActivated())); * * Update the selection: * m_annotationFontSizeTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const AnnotationTextFontSizeTypeEnum::Enum VARIABLE = m_annotationFontSizeTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ AnnotationTextFontSizeTypeEnum::AnnotationTextFontSizeTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ AnnotationTextFontSizeTypeEnum::~AnnotationTextFontSizeTypeEnum() { } /** * Initialize the enumerated metadata. */ void AnnotationTextFontSizeTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(AnnotationTextFontSizeTypeEnum(POINTS, "POINTS", "Points")); enumData.push_back(AnnotationTextFontSizeTypeEnum(PERCENTAGE_OF_VIEWPORT_HEIGHT, "PERCENTAGE_OF_VIEWPORT_HEIGHT", "Percentage of Viewport Height")); enumData.push_back(AnnotationTextFontSizeTypeEnum(PERCENTAGE_OF_VIEWPORT_WIDTH, "PERCENTAGE_OF_VIEWPORT_WIDTH", "Percentage of Viewport Width")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const AnnotationTextFontSizeTypeEnum* AnnotationTextFontSizeTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const AnnotationTextFontSizeTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationTextFontSizeTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextFontSizeTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationTextFontSizeTypeEnum::Enum AnnotationTextFontSizeTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTextFontSizeTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextFontSizeTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type AnnotationTextFontSizeTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationTextFontSizeTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextFontSizeTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationTextFontSizeTypeEnum::Enum AnnotationTextFontSizeTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTextFontSizeTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextFontSizeTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type AnnotationTextFontSizeTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t AnnotationTextFontSizeTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextFontSizeTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ AnnotationTextFontSizeTypeEnum::Enum AnnotationTextFontSizeTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTextFontSizeTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextFontSizeTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type AnnotationTextFontSizeTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void AnnotationTextFontSizeTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationTextFontSizeTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(AnnotationTextFontSizeTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationTextFontSizeTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(AnnotationTextFontSizeTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Annotations/AnnotationTextFontSizeTypeEnum.h000066400000000000000000000065451360521144700272320ustar00rootroot00000000000000#ifndef __ANNOTATION_TEXT_FONT_SIZE_TYPE_ENUM_H__ #define __ANNOTATION_TEXT_FONT_SIZE_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class AnnotationTextFontSizeTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Sized in Points */ POINTS, /** Sized as percentage of viewport height */ PERCENTAGE_OF_VIEWPORT_HEIGHT, /** Sized as percentage of viewport width */ PERCENTAGE_OF_VIEWPORT_WIDTH }; ~AnnotationTextFontSizeTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: AnnotationTextFontSizeTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const AnnotationTextFontSizeTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __ANNOTATION_TEXT_FONT_SIZE_TYPE_ENUM_DECLARE__ std::vector AnnotationTextFontSizeTypeEnum::enumData; bool AnnotationTextFontSizeTypeEnum::initializedFlag = false; int32_t AnnotationTextFontSizeTypeEnum::integerCodeCounter = 0; #endif // __ANNOTATION_TEXT_FONT_SIZE_TYPE_ENUM_DECLARE__ } // namespace #endif //__ANNOTATION_TEXT_FONT_SIZE_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationTextOrientationEnum.cxx000066400000000000000000000257361360521144700275000ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_TEXT_ORIENTATION_ENUM_DECLARE__ #include "AnnotationTextOrientationEnum.h" #undef __ANNOTATION_TEXT_ORIENTATION_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationTextOrientationEnum * \brief * * * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_annotationTextOrientationEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void annotationTextOrientationEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "AnnotationTextOrientationEnum.h" * * Instatiate: * m_annotationTextOrientationEnumComboBox = new EnumComboBoxTemplate(this); * m_annotationTextOrientationEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_annotationTextOrientationEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(annotationTextOrientationEnumComboBoxItemActivated())); * * Update the selection: * m_annotationTextOrientationEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const AnnotationTextOrientationEnum::Enum VARIABLE = m_annotationTextOrientationEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ AnnotationTextOrientationEnum::AnnotationTextOrientationEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ AnnotationTextOrientationEnum::~AnnotationTextOrientationEnum() { } /** * Initialize the enumerated metadata. */ void AnnotationTextOrientationEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(AnnotationTextOrientationEnum(HORIZONTAL, "HORIZONTAL", "Horizontal")); enumData.push_back(AnnotationTextOrientationEnum(STACKED, "STACKED", "Stacked")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const AnnotationTextOrientationEnum* AnnotationTextOrientationEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const AnnotationTextOrientationEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationTextOrientationEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextOrientationEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationTextOrientationEnum::Enum AnnotationTextOrientationEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTextOrientationEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextOrientationEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type AnnotationTextOrientationEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationTextOrientationEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextOrientationEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationTextOrientationEnum::Enum AnnotationTextOrientationEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTextOrientationEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextOrientationEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type AnnotationTextOrientationEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t AnnotationTextOrientationEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTextOrientationEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ AnnotationTextOrientationEnum::Enum AnnotationTextOrientationEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTextOrientationEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTextOrientationEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type AnnotationTextOrientationEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void AnnotationTextOrientationEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationTextOrientationEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(AnnotationTextOrientationEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationTextOrientationEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(AnnotationTextOrientationEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Annotations/AnnotationTextOrientationEnum.h000066400000000000000000000062741360521144700271210ustar00rootroot00000000000000#ifndef __ANNOTATION_TEXT_ORIENTATION_ENUM_H__ #define __ANNOTATION_TEXT_ORIENTATION_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class AnnotationTextOrientationEnum { public: /** * Enumerated values. */ enum Enum { /** Horizontal */ HORIZONTAL, /** Stacked */ STACKED }; ~AnnotationTextOrientationEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: AnnotationTextOrientationEnum(const Enum enumValue, const AString& name, const AString& guiName); static const AnnotationTextOrientationEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __ANNOTATION_TEXT_ORIENTATION_ENUM_DECLARE__ std::vector AnnotationTextOrientationEnum::enumData; bool AnnotationTextOrientationEnum::initializedFlag = false; int32_t AnnotationTextOrientationEnum::integerCodeCounter = 0; #endif // __ANNOTATION_TEXT_ORIENTATION_ENUM_DECLARE__ } // namespace #endif //__ANNOTATION_TEXT_ORIENTATION_ENUM_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationTwoDimensionalShape.cxx000066400000000000000000001735061360521144700274270ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_TWO_DIMENSIONAL_SHAPE_DECLARE__ #include "AnnotationTwoDimensionalShape.h" #undef __ANNOTATION_TWO_DIMENSIONAL_SHAPE_DECLARE__ #include "AnnotationColorBar.h" #include "AnnotationCoordinate.h" #include "AnnotationSpatialModification.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "MathFunctions.h" #include "Matrix4x4.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::AnnotationTwoDimensionalShape * \brief Class for annotations that are two dimensional (width and height). * \ingroup Annotations */ /** * Constructor. * * @param type * Type of annotation * @param attributeDefaultType * Type for attribute defaults */ AnnotationTwoDimensionalShape::AnnotationTwoDimensionalShape(const AnnotationTypeEnum::Enum type, const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType) : Annotation(type, attributeDefaultType) { initializeMembersAnnotationTwoDimensionalShape(); } /** * Destructor. */ AnnotationTwoDimensionalShape::~AnnotationTwoDimensionalShape() { } /** * Copy constructor. * @param obj * Object that is copied. */ AnnotationTwoDimensionalShape::AnnotationTwoDimensionalShape(const AnnotationTwoDimensionalShape& obj) : Annotation(obj) { initializeMembersAnnotationTwoDimensionalShape(); this->copyHelperAnnotationTwoDimensionalShape(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ AnnotationTwoDimensionalShape& AnnotationTwoDimensionalShape::operator=(const AnnotationTwoDimensionalShape& obj) { if (this != &obj) { Annotation::operator=(obj); this->copyHelperAnnotationTwoDimensionalShape(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void AnnotationTwoDimensionalShape::copyHelperAnnotationTwoDimensionalShape(const AnnotationTwoDimensionalShape& obj) { *m_coordinate = *obj.m_coordinate; m_width = obj.m_width; m_height = obj.m_height; m_rotationAngle = obj.m_rotationAngle; } /** * Initialize members of this class. */ void AnnotationTwoDimensionalShape::initializeMembersAnnotationTwoDimensionalShape() { m_coordinate.grabNew(new AnnotationCoordinate(m_attributeDefaultType)); switch (m_attributeDefaultType) { case AnnotationAttributesDefaultTypeEnum::NORMAL: m_width = 25.0; m_height = 25.0; m_rotationAngle = 0.0; break; case AnnotationAttributesDefaultTypeEnum::USER: m_width = s_userDefaultWidth; m_height = s_userDefaultHeight; m_rotationAngle = 0.0; break; } m_sceneAssistant.grabNew(new SceneClassAssistant()); if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { /* * Saves/restores color bar manual position and size mode. */ m_sceneAssistant->add("m_coordinate", "AnnotationCoordinate", m_coordinate); m_sceneAssistant->add("m_width", &m_width); m_sceneAssistant->add("m_height", &m_height); m_sceneAssistant->add("m_rotationAngle", &m_rotationAngle); } } /** * @return 'this' as a one-dimensional shape. NULL if this is not a one-dimensional shape. */ AnnotationOneDimensionalShape* AnnotationTwoDimensionalShape::castToOneDimensionalShape() { return NULL; } /** * @return 'this' as a one-dimensional shape. NULL if this is not a one-dimensional shape. */ const AnnotationOneDimensionalShape* AnnotationTwoDimensionalShape::castToOneDimensionalShape() const { return NULL; } /** * @return 'this' as a one-dimensional shape. NULL if this is not a two-dimensional shape. */ AnnotationTwoDimensionalShape* AnnotationTwoDimensionalShape::castToTwoDimensionalShape() { return this; } /** * @return 'this' as a one-dimensional shape. NULL if this is not a two-dimensional shape. */ const AnnotationTwoDimensionalShape* AnnotationTwoDimensionalShape::castToTwoDimensionalShape() const { return this; } /** * @return The coordinate for the two dimensional shape. */ AnnotationCoordinate* AnnotationTwoDimensionalShape::getCoordinate() { return m_coordinate; } /** * @return The start coordinate for the two dimensional shape. */ const AnnotationCoordinate* AnnotationTwoDimensionalShape::getCoordinate() const { return m_coordinate; } /** * @return The surface offset vector type for this annotation. */ AnnotationSurfaceOffsetVectorTypeEnum::Enum AnnotationTwoDimensionalShape::getSurfaceOffsetVectorType() const { CaretAssert(m_coordinate); return m_coordinate->getSurfaceOffsetVectorType(); } /** * @return Height for "two-dimensional" annotations in percentage zero to one-hundred. */ float AnnotationTwoDimensionalShape::getHeight() const { return m_height; } /** * Set the height for "two-dimensional" annotations in percentage zero to one-hundred. * * @param height * New value for height of the annotation. */ void AnnotationTwoDimensionalShape::setHeight(const float height) { if (height != m_height) { if (isFixedAspectRatio()) { m_height = height; m_width = m_height / getFixedAspectRatio(); } else { m_height = height; } setModified(); } } /** * @return Width for "two-dimensional" annotations in percentage zero to one-hundred. */ float AnnotationTwoDimensionalShape::getWidth() const { return m_width; } /** * Set the width for "two-dimensional" annotations in percentage zero to one-hundred. * * @param width * New value for width of the annotation. */ void AnnotationTwoDimensionalShape::setWidth(const float width) { if (width != m_width) { if (isFixedAspectRatio()) { m_width = width; m_height = m_width * getFixedAspectRatio(); } else { m_width = width; } setModified(); } } /** * @return The rotation angle, in degrees, clockwise, from vertical at the top (12 o'clock). */ float AnnotationTwoDimensionalShape::getRotationAngle() const { return m_rotationAngle; } /** * The rotation angle, in degrees, clockwise, from vertical at the top (12 o'clock). * * @param rotationAngle * New value rotation angle. */ void AnnotationTwoDimensionalShape::setRotationAngle(const float rotationAngle) { if (rotationAngle != m_rotationAngle) { m_rotationAngle = rotationAngle; setModified(); } } /** * Is the object modified? * @return true if modified, else false. */ bool AnnotationTwoDimensionalShape::isModified() const { if (Annotation::isModified()) { return true; } if (m_coordinate->isModified()) { return true; } return false; } /** * Set the status to unmodified. */ void AnnotationTwoDimensionalShape::clearModified() { Annotation::clearModified(); m_coordinate->clearModified(); } /** * Apply the coordinates, size, and rotation from the given annotation * to this annotation. * * @param otherAnnotation * The other annotation from which attributes are obtained. */ void AnnotationTwoDimensionalShape::applyCoordinatesSizeAndRotationFromOther(const Annotation* otherAnnotation) { CaretAssert(otherAnnotation); const AnnotationTwoDimensionalShape* otherTwoDim = dynamic_cast(otherAnnotation); CaretAssert(otherTwoDim); AnnotationCoordinate* coord = getCoordinate(); const AnnotationCoordinate* otherCoord = otherTwoDim->getCoordinate(); *coord = *otherCoord; setWidth(otherTwoDim->getWidth()); setHeight(otherTwoDim->getHeight()); setRotationAngle(otherTwoDim->getRotationAngle()); setCoordinateSpace(otherAnnotation->getCoordinateSpace()); setTabIndex(otherAnnotation->getTabIndex()); setWindowIndex(otherAnnotation->getWindowIndex()); /* * Switch color bar to manual positioning */ AnnotationColorBar* colorBar = dynamic_cast(this); if (colorBar != NULL) { colorBar->setPositionMode(AnnotationColorBarPositionModeEnum::MANUAL); } } /** * Is the given sizing handle valid for this annotation? * * @sizingHandle * The sizing handle. * @return * True if sizing handle valid, else false. */ bool AnnotationTwoDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTypeEnum::Enum sizingHandle) const { const bool viewportFlag = (getCoordinateSpace() == AnnotationCoordinateSpaceEnum::VIEWPORT); const bool surfaceTangentOffsetFlag = isInSurfaceSpaceWithTangentOffset(); bool allowsMovingFlag = false; bool allowsCornerResizingFlag = false; bool allowsSideResizingFlag = false; bool allowsRotationFlag = false; switch (getType()) { case AnnotationTypeEnum::BOX: allowsMovingFlag = true; allowsCornerResizingFlag = true; allowsSideResizingFlag = true; allowsRotationFlag = true; break; case AnnotationTypeEnum::COLOR_BAR: allowsMovingFlag = true; allowsCornerResizingFlag = true; allowsSideResizingFlag = true; allowsRotationFlag = true; break; case AnnotationTypeEnum::IMAGE: allowsMovingFlag = true; allowsSideResizingFlag = true; allowsRotationFlag = true; break; case AnnotationTypeEnum::LINE: break; case AnnotationTypeEnum::OVAL: allowsMovingFlag = true; allowsCornerResizingFlag = true; allowsSideResizingFlag = true; allowsRotationFlag = true; break; case AnnotationTypeEnum::TEXT: allowsMovingFlag = true; allowsRotationFlag = true; break; } if (surfaceTangentOffsetFlag) { allowsCornerResizingFlag = false; allowsSideResizingFlag = false; } bool validFlag = false; if (! viewportFlag) { switch (sizingHandle) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: if (allowsSideResizingFlag) { validFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: if (allowsCornerResizingFlag) { validFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: if (allowsCornerResizingFlag) { validFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: if (allowsSideResizingFlag) { validFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: if (allowsSideResizingFlag) { validFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: if (allowsSideResizingFlag) { validFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: if (allowsCornerResizingFlag) { validFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: if (allowsCornerResizingFlag) { validFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: if (allowsMovingFlag) { validFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: if (allowsRotationFlag) { validFlag = true; } break; } } return validFlag; } /** * Apply a spatial modification to an annotation in chart space. * * @param spatialModification * Contains information about the spatial modification. * @return * True if the annotation was modified, else false. */ bool AnnotationTwoDimensionalShape::applySpatialModificationChartSpace(const AnnotationSpatialModification& spatialModification) { bool validFlag = false; const float rotationRadians = MathFunctions::toRadians(m_rotationAngle); float dx = (spatialModification.m_mouseDX * std::cos(rotationRadians) - spatialModification.m_mouseDY * std::sin(rotationRadians)); float dy = (spatialModification.m_mouseDX * std::sin(rotationRadians) + spatialModification.m_mouseDY * std::cos(rotationRadians)); if (spatialModification.m_viewportWidth > 0) { dx = (dx / spatialModification.m_viewportWidth) * 100.0; } else { dx = 0.0; } if (spatialModification.m_viewportHeight > 0) { dy = (dy / spatialModification.m_viewportHeight) * 100.0; } else { dy = 0.0; } bool validDxyFlag = false; switch (spatialModification.m_sizingHandleType) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: dx = 0.0; dy = -dy; validDxyFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: dx = -dx; dy = -dy; validDxyFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: dy = -dy; validDxyFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: dx = -dx; dy = 0.0; validDxyFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: dy = 0.0; validDxyFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: dx = 0.0; validDxyFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: dx = -dx; validDxyFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: validDxyFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: if (spatialModification.m_chartCoordAtMouseXY.m_chartXYZValid) { m_coordinate->setXYZ(spatialModification.m_chartCoordAtMouseXY.m_chartXYZ); validFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: { static float centerX = 0.0; static float centerY = 0.0; /* * Stereotaxic and surface rotations may be displayed in * multiple locations if more that one surface is dislayed * when surface montage is viewed and/or tile tabs is enabled. * * We don't have the window location of the annotation but * we can estimate it as it is in the center of the annotation. * Once we have approximated the center we can use the center * as the rotation point and so that the rotation handle points * to the mouse. During rotation, the center will not change * so set its position when the user starts to drag the mouse. */ if (spatialModification.m_startOfDraggingFlag) { const float height = ((m_height / 100.0) * spatialModification.m_viewportHeight); const float halfHeight = height / 2.0; const float handleOffsetHeight = 15.0; const float centerAngleRadians = MathFunctions::toRadians(m_rotationAngle - 90); const float centerOffsetY = (halfHeight + handleOffsetHeight) * std::sin(centerAngleRadians); const float centerOffsetX = -halfHeight * std::cos(centerAngleRadians); centerX = spatialModification.m_mousePressX + centerOffsetX; centerY = spatialModification.m_mousePressY + centerOffsetY; } /* * Rotation angle is a formed by the triangle * (Mouse XY, Annotation XY, Positive X-axis). */ const float dy = (spatialModification.m_mouseY - centerY); const float dx = (spatialModification.m_mouseX - centerX); const float angleRadians = std::atan2(dy, dx); const float angleDegrees = MathFunctions::toDegrees(angleRadians); m_rotationAngle = 90.0 - angleDegrees; if (m_rotationAngle > 360.0) { m_rotationAngle -= 360.0; } else if (m_rotationAngle < 0.0) { m_rotationAngle += 360.0; } validFlag = true; } break; } if (validDxyFlag) { if (isFixedAspectRatio()) { switch (spatialModification.m_sizingHandleType) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: if (std::fabs(dx) > std::fabs(dy)) { /* * For fixed aspect ratio, the width percentage is not a percentage * of window width but of the window's height since the annotation * is sized by its height (width = height / aspect). * * So when width is changed, need to set height. */ const float aspectRatio = getFixedAspectRatio(); const float newHeight = MathFunctions::limitRange(getHeight() + dx * aspectRatio, 0.0f, 100.0f); setHeight(newHeight); validFlag = true; } else if (std::fabs(dx) < std::fabs(dy)) { const float newHeight = MathFunctions::limitRange(getHeight() + dy, 0.0f, 100.0f); setHeight(newHeight); validFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: break; } } else { if (dx != 0.0) { m_width += dx; m_width = MathFunctions::limitRange(m_width, 1.0f, 100.0f); validFlag = true; } if (dy != 0.0) { m_height += dy; m_height = MathFunctions::limitRange(m_height, 1.0f, 100.0f); validFlag = true; } } } if (validFlag) { setModified(); } return validFlag; } /** * Apply a spatial modification to an annotation in surface * or stereotaxic space. * * @param spatialModification * Contains information about the spatial modification. * @param coordinateSpace * The coordinate space. * @return * True if the annotation was modified, else false. */ bool AnnotationTwoDimensionalShape::applySpatialModificationSurfaceOrStereotaxicSpace(const AnnotationSpatialModification& spatialModification, const AnnotationCoordinateSpaceEnum::Enum coordinateSpace) { bool badSpaceFlag = false; bool stereoSpaceFlag = false; bool surfaceSpaceFlag = false; switch (coordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: badSpaceFlag = true; break; case AnnotationCoordinateSpaceEnum::SPACER: badSpaceFlag = true; break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: stereoSpaceFlag = true; break; case AnnotationCoordinateSpaceEnum::SURFACE: surfaceSpaceFlag = true; break; case AnnotationCoordinateSpaceEnum::TAB: badSpaceFlag = true; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: badSpaceFlag = true; break; case AnnotationCoordinateSpaceEnum::WINDOW: badSpaceFlag = true; break; } if (badSpaceFlag) { CaretAssertMessage(0, ("This method should NEVER be called for " + AnnotationCoordinateSpaceEnum::toName(coordinateSpace) + " space annotations")); return false; } bool validFlag = false; const float rotationRadians = MathFunctions::toRadians(m_rotationAngle); float dx = (spatialModification.m_mouseDX * std::cos(rotationRadians) - spatialModification.m_mouseDY * std::sin(rotationRadians)); float dy = (spatialModification.m_mouseDX * std::sin(rotationRadians) + spatialModification.m_mouseDY * std::cos(rotationRadians)); if (spatialModification.m_viewportWidth > 0) { dx = (dx / spatialModification.m_viewportWidth) * 100.0; } else { dx = 0.0; } if (spatialModification.m_viewportHeight > 0) { dy = (dy / spatialModification.m_viewportHeight) * 100.0; } else { dy = 0.0; } bool validDxyFlag = false; switch (spatialModification.m_sizingHandleType) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: dx = 0.0; dy = -dy; validDxyFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: dx = -dx; dy = -dy; validDxyFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: dy = -dy; validDxyFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: dx = -dx; dy = 0.0; validDxyFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: dy = 0.0; validDxyFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: dx = 0.0; validDxyFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: dx = -dx; validDxyFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: validDxyFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: if (stereoSpaceFlag) { m_coordinate->setXYZ(spatialModification.m_stereotaxicCoordinateAtMouseXY.m_stereotaxicXYZ); validFlag = true; } else if (surfaceSpaceFlag) { StructureEnum::Enum structure = StructureEnum::INVALID; int32_t surfaceNumberOfNodes = -1; int32_t surfaceNodeIndex = -1; m_coordinate->getSurfaceSpace(structure, surfaceNumberOfNodes, surfaceNodeIndex); if (spatialModification.m_surfaceCoordinateAtMouseXY.m_surfaceNodeValid) { if ((spatialModification.m_surfaceCoordinateAtMouseXY.m_surfaceStructure == structure) && (spatialModification.m_surfaceCoordinateAtMouseXY.m_surfaceNumberOfNodes == surfaceNumberOfNodes)) { m_coordinate->setSurfaceSpace(spatialModification.m_surfaceCoordinateAtMouseXY.m_surfaceStructure, spatialModification.m_surfaceCoordinateAtMouseXY.m_surfaceNumberOfNodes, spatialModification.m_surfaceCoordinateAtMouseXY.m_surfaceNodeIndex); validFlag = true; } } } else { CaretAssertMessage(0, "New space???"); } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: { static float centerX = 0.0; static float centerY = 0.0; /* * Stereotaxic and surface rotations may be displayed in * multiple locations if more that one surface is dislayed * when surface montage is viewed and/or tile tabs is enabled. * * We don't have the window location of the annotation but * we can estimate it as it is in the center of the annotation. * Once we have approximated the center we can use the center * as the rotation point and so that the rotation handle points * to the mouse. During rotation, the center will not change * so set its position when the user starts to drag the mouse. */ if (spatialModification.m_startOfDraggingFlag) { const float height = ((m_height / 100.0) * spatialModification.m_viewportHeight); const float halfHeight = height / 2.0; const float handleOffsetHeight = 15.0; const float centerAngleRadians = MathFunctions::toRadians(m_rotationAngle - 90); const float centerOffsetY = (halfHeight + handleOffsetHeight) * std::sin(centerAngleRadians); const float centerOffsetX = -halfHeight * std::cos(centerAngleRadians); centerX = spatialModification.m_mousePressX + centerOffsetX; centerY = spatialModification.m_mousePressY + centerOffsetY; } /* * Rotation angle is a formed by the triangle * (Mouse XY, Annotation XY, Positive X-axis). */ const float dy = (spatialModification.m_mouseY - centerY); const float dx = (spatialModification.m_mouseX - centerX); const float angleRadians = std::atan2(dy, dx); const float angleDegrees = MathFunctions::toDegrees(angleRadians); m_rotationAngle = 90.0 - angleDegrees; if (m_rotationAngle > 360.0) { m_rotationAngle -= 360.0; } else if (m_rotationAngle < 0.0) { m_rotationAngle += 360.0; } validFlag = true; } break; } if (validDxyFlag) { if (isFixedAspectRatio()) { switch (spatialModification.m_sizingHandleType) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: if (std::fabs(dx) > std::fabs(dy)) { /* * For fixed aspect ratio, the width percentage is not a percentage * of window width but of the window's height since the annotation * is sized by its height (width = height / aspect). * * So when width is changed, need to set height. */ const float aspectRatio = getFixedAspectRatio(); const float newHeight = MathFunctions::limitRange(getHeight() + dx * aspectRatio, 0.0f, 100.0f); setHeight(newHeight); validFlag = true; } else if (std::fabs(dx) < std::fabs(dy)) { const float newHeight = MathFunctions::limitRange(getHeight() + dy, 0.0f, 100.0f); setHeight(newHeight); validFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: break; } } else { if (dx != 0.0) { m_width += dx; m_width = MathFunctions::limitRange(m_width, 1.0f, 100.0f); validFlag = true; } if (dy != 0.0) { m_height += dy; m_height = MathFunctions::limitRange(m_height, 1.0f, 100.0f); validFlag = true; } } } if (validFlag) { setModified(); } return validFlag; } /** * Apply a spatial modification to an annotation in spacer tab space. * * @param spatialModification * Contains information about the spatial modification. * @return * True if the annotation was modified, else false. */ bool AnnotationTwoDimensionalShape::applySpatialModificationSpacerTabSpace(const AnnotationSpatialModification& spatialModification) { return applySpatialModificationTabOrWindowSpace(spatialModification); } /** * Apply a spatial modification to an annotation in tab or window space. * * @param spatialModification * Contains information about the spatial modification. * @return * True if the annotation was modified, else false. */ bool AnnotationTwoDimensionalShape::applySpatialModificationTabOrWindowSpace(const AnnotationSpatialModification& spatialModification) { float xyz[3]; m_coordinate->getXYZ(xyz); float viewportXYZ[3] = { 0.0, 0.0, 0.0 }; relativeXYZToViewportXYZ(xyz, spatialModification.m_viewportWidth, spatialModification.m_viewportHeight, viewportXYZ); float bottomLeftXYZ[3]; float bottomRightXYZ[3]; float topLeftXYZ[3]; float topRightXYZ[3]; const bool validBounds = getShapeBounds(spatialModification.m_viewportWidth, spatialModification.m_viewportHeight, viewportXYZ, bottomLeftXYZ, bottomRightXYZ, topRightXYZ, topLeftXYZ); if ( ! validBounds) { return false; } float leftToRightUnitVector[3]; MathFunctions::createUnitVector(bottomLeftXYZ, bottomRightXYZ, leftToRightUnitVector); float bottomToTopUnitVector[3]; MathFunctions::createUnitVector(bottomLeftXYZ, topLeftXYZ, bottomToTopUnitVector); /* * Find size adjustment for side (not corner) sizing handles */ float sideHandleDX = 0.0; float sideHandleDY = 0.0; getSideHandleMouseDelta(spatialModification.m_sizingHandleType, leftToRightUnitVector, bottomToTopUnitVector, spatialModification.m_mouseDX, spatialModification.m_mouseDY, sideHandleDX, sideHandleDY); bool validCoordinatesFlag = false; bool validRotationFlag = false; /* * When a resize handle is moved, update the corners of the shape */ switch (spatialModification.m_sizingHandleType) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: addToXYZWithXY(bottomLeftXYZ, sideHandleDX, sideHandleDY); addToXYZWithXY(bottomRightXYZ, sideHandleDX, sideHandleDY); validCoordinatesFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: { /* * Bottom left is now at the mouse XY */ bottomLeftXYZ[0] = spatialModification.m_mouseX; bottomLeftXYZ[1] = spatialModification.m_mouseY; /* * Unit vector from bottom left to updated top right */ float bottomLeftToTopRightUnitVector[3]; MathFunctions::createUnitVector(bottomLeftXYZ, topRightXYZ, bottomLeftToTopRightUnitVector); /* * We have a right triangle where: * The hypotnuse is from bottom left corner to new top right corner * A right angle is at top left corner * Want angle at bottom left but vector angle is at top right (all * angles add up to PI=180). */ const float oppositeAngle = MathFunctions::angle(topLeftXYZ, topRightXYZ, bottomLeftXYZ); const float angle = (M_PI / 2.0) - oppositeAngle; const float hypotnuseLength = MathFunctions::distance3D(bottomLeftXYZ, topRightXYZ); const float newWidth = std::sin(angle) * hypotnuseLength; const float newHeight = std::cos(angle) * hypotnuseLength; topLeftXYZ[0] = bottomLeftXYZ[0] + bottomToTopUnitVector[0] * newHeight; topLeftXYZ[1] = bottomLeftXYZ[1] + bottomToTopUnitVector[1] * newHeight; bottomRightXYZ[0] = bottomLeftXYZ[0] + leftToRightUnitVector[0] * newWidth; bottomRightXYZ[1] = bottomLeftXYZ[1] + leftToRightUnitVector[1] * newWidth; validCoordinatesFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: { /* * Bottom right is now at the mouse XY */ bottomRightXYZ[0] = spatialModification.m_mouseX; bottomRightXYZ[1] = spatialModification.m_mouseY; /* * Unit vector from top left to updated bottom right */ float topLeftToBottomRightUnitVector[3]; MathFunctions::createUnitVector(topLeftXYZ, bottomRightXYZ, topLeftToBottomRightUnitVector); /* * We have a right triangle where: * The hypotnuse is from top left corner to new bottom right corner * A right angle is at top right corner */ const float angle = MathFunctions::angle(topRightXYZ, topLeftXYZ, bottomRightXYZ); const float hypotnuseLength = MathFunctions::distance3D(topLeftXYZ, bottomRightXYZ); const float newWidth = std::cos(angle) * hypotnuseLength; const float newHeight = std::sin(angle) * hypotnuseLength; topRightXYZ[0] = topLeftXYZ[0] + leftToRightUnitVector[0] * newWidth; topRightXYZ[1] = topLeftXYZ[1] + leftToRightUnitVector[1] * newWidth; bottomLeftXYZ[0] = topLeftXYZ[0] - bottomToTopUnitVector[0] * newHeight; bottomLeftXYZ[1] = topLeftXYZ[1] - bottomToTopUnitVector[1] * newHeight; validCoordinatesFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: addToXYZWithXY(topLeftXYZ, sideHandleDX, sideHandleDY); addToXYZWithXY(bottomLeftXYZ, sideHandleDX, sideHandleDY); validCoordinatesFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: addToXYZWithXY(topRightXYZ, sideHandleDX, sideHandleDY); addToXYZWithXY(bottomRightXYZ, sideHandleDX, sideHandleDY); validCoordinatesFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: addToXYZWithXY(topLeftXYZ, sideHandleDX, sideHandleDY); addToXYZWithXY(topRightXYZ, sideHandleDX, sideHandleDY); validCoordinatesFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: { /* * Top left is now at the mouse XY */ topLeftXYZ[0] = spatialModification.m_mouseX; topLeftXYZ[1] = spatialModification.m_mouseY; /* * Unit vector from top left to updated bottom right */ float topLeftToBottomRightUnitVector[3]; MathFunctions::createUnitVector(topLeftXYZ, bottomRightXYZ, topLeftToBottomRightUnitVector); /* * We have a right triangle where: * The hypotnuse is from top left corner to new bottom right corner * A right angle is at top right corner */ const float oppositeAngle = MathFunctions::angle(topLeftXYZ, bottomRightXYZ, bottomLeftXYZ); const float angle = (M_PI / 2.0) - oppositeAngle; const float hypotnuseLength = MathFunctions::distance3D(topLeftXYZ, bottomRightXYZ); const float newWidth = std::sin(angle) * hypotnuseLength; const float newHeight = std::cos(angle) * hypotnuseLength; topRightXYZ[0] = topLeftXYZ[0] + leftToRightUnitVector[0] * newWidth; topRightXYZ[1] = topLeftXYZ[1] + leftToRightUnitVector[1] * newWidth; bottomLeftXYZ[0] = topLeftXYZ[0] - bottomToTopUnitVector[0] * newHeight; bottomLeftXYZ[1] = topLeftXYZ[1] - bottomToTopUnitVector[1] * newHeight; validCoordinatesFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: { /* * Top right is now at the mouse XY */ topRightXYZ[0] = spatialModification.m_mouseX; topRightXYZ[1] = spatialModification.m_mouseY; /* * Unit vector from updated top right to bottom left */ float topRightToBottomLeftUnitVector[3]; MathFunctions::createUnitVector(topRightXYZ, bottomLeftXYZ, topRightToBottomLeftUnitVector); /* * We have a right triangle where: * The hypotnuse is from bottom left corner to new top right corner * A right angle is at top left corner */ const float oppositeAngle = MathFunctions::angle(topLeftXYZ, bottomLeftXYZ, topRightXYZ); const float angle = (M_PI / 2.0) - oppositeAngle; const float hypotnuseLength = MathFunctions::distance3D(topRightXYZ, bottomLeftXYZ); const float newWidth = std::cos(angle) * hypotnuseLength; const float newHeight = std::sin(angle) * hypotnuseLength; topLeftXYZ[0] = topRightXYZ[0] - leftToRightUnitVector[0] * newWidth; topLeftXYZ[1] = topRightXYZ[1] - leftToRightUnitVector[1] * newWidth; bottomRightXYZ[0] = topRightXYZ[0] - bottomToTopUnitVector[0] * newHeight; bottomRightXYZ[1] = topRightXYZ[1] - bottomToTopUnitVector[1] * newHeight; validCoordinatesFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: CaretAssert(0); break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: CaretAssert(0); break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: addToXYZWithXY(bottomLeftXYZ, spatialModification.m_mouseDX, spatialModification.m_mouseDY); addToXYZWithXY(bottomRightXYZ, spatialModification.m_mouseDX, spatialModification.m_mouseDY); addToXYZWithXY(topRightXYZ, spatialModification.m_mouseDX, spatialModification.m_mouseDY); addToXYZWithXY(topLeftXYZ, spatialModification.m_mouseDX, spatialModification.m_mouseDY); validCoordinatesFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: { /* * Rotation angle is a formed by the triangle * (Mouse XY, Annotation XY, Positive X-axis). */ const float dy = spatialModification.m_mouseY - viewportXYZ[1]; const float dx = spatialModification.m_mouseX - viewportXYZ[0]; const float angleRadians = std::atan2(dy, dx); const float angleDegrees = MathFunctions::toDegrees(angleRadians); m_rotationAngle = 90.0 - angleDegrees; if (m_rotationAngle > 360.0) { m_rotationAngle -= 360.0; } else if (m_rotationAngle < 0.0) { m_rotationAngle += 360.0; } validRotationFlag = true; } break; } if (validCoordinatesFlag) { /* * Using the updated corners of the annotation, convert back to normalized x, y, width, and aspect ratio */ float newViewportXYZ[3]; MathFunctions::averageOfFourCoordinates(bottomLeftXYZ, bottomRightXYZ, topRightXYZ, topLeftXYZ, newViewportXYZ); const float newX = 100.0 * (newViewportXYZ[0] / spatialModification.m_viewportWidth); const float newY = 100.0 * (newViewportXYZ[1] / spatialModification.m_viewportHeight); const float newShapeViewportWidth = MathFunctions::distance3D(bottomLeftXYZ, bottomRightXYZ); const float newWidth = 100.0 * (newShapeViewportWidth / spatialModification.m_viewportWidth); const float newShapeViewportHeight = MathFunctions::distance3D(bottomLeftXYZ, topLeftXYZ); const float newHeight = 100.0 * (newShapeViewportHeight / spatialModification.m_viewportHeight); /* * Note: * Coordinates are relative (range 0 to 100) * Width is relative (range 0 to 100) * Aspect ratio must only be greater than zero (when < 1, horizontal rectangle, when > 1 vertical rectangle) */ if ((newX >= 0.0) && (newX <= 100.0) && (newY >= 0.0) && (newY <= 100.0)) { if (isFixedAspectRatio()) { xyz[0] = newX; xyz[1] = newY; m_coordinate->setXYZ(xyz); switch (spatialModification.m_sizingHandleType) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: if (std::fabs(sideHandleDX) > std::fabs(sideHandleDY)) { /* * For fixed aspect ratio, the width percentage is not a percentage * of window width but of the window's height since the annotation * is sized by its height (width = height / aspect). * * So when width is changed, need to set height. */ const float aspectRatio = getFixedAspectRatio(); const float newViewportHeight = newShapeViewportWidth * aspectRatio; const float newShapeHeight = 100.0 * (newViewportHeight / spatialModification.m_viewportHeight); setHeight(newShapeHeight); } else if (std::fabs(sideHandleDX) < std::fabs(sideHandleDY)) { setHeight(newHeight); } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: break; } } else { xyz[0] = newX; xyz[1] = newY; m_coordinate->setXYZ(xyz); m_width = newWidth; m_height = newHeight; } } else { validCoordinatesFlag = false; } } if (validCoordinatesFlag || validRotationFlag) { setModified(); return true; } return false; } /** * Given the previous mouse location, current mouse location, and the shape * location, examine the angle formed to determine if rotation is allowed. * Note that if the mouse is moved purely horizontally or vertically from * the rotation point, the rotation angle may rapidly change causing weird * behavior. * * @param previousMouseXYZ * Previous location of mouse. * @param shapeXYZ * Location of shape. * @param currentMouseXYZ * Current location of mouse. * @return * True if rotation is valid, else false. */ bool AnnotationTwoDimensionalShape::rotationAngleTest(const float previousMouseXYZ[3], const float shapeXYZ[3], const float currentMouseXYZ[3]) const { const float angle = MathFunctions::angle(currentMouseXYZ, shapeXYZ, previousMouseXYZ); static const float MINIMUM_ANGLE = 0.025; //0.01; if (angle > MINIMUM_ANGLE) { return true; } return false; } /** * Apply a spatial modification to an annotation. * * @param spatialModification * Contains information about the spatial modification. * @return * True if the annotation was modified, else false. */ bool AnnotationTwoDimensionalShape::applySpatialModification(const AnnotationSpatialModification& spatialModification) { if ( ! isSizeHandleValid(spatialModification.m_sizingHandleType)) { return false; } const AnnotationCoordinateSpaceEnum::Enum space = getCoordinateSpace(); switch (space) { case AnnotationCoordinateSpaceEnum::CHART: return applySpatialModificationChartSpace(spatialModification); break; case AnnotationCoordinateSpaceEnum::SPACER: return applySpatialModificationSpacerTabSpace(spatialModification); break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: return applySpatialModificationSurfaceOrStereotaxicSpace(spatialModification, space); break; case AnnotationCoordinateSpaceEnum::SURFACE: return applySpatialModificationSurfaceOrStereotaxicSpace(spatialModification, space); break; case AnnotationCoordinateSpaceEnum::TAB: return applySpatialModificationTabOrWindowSpace(spatialModification); break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: return applySpatialModificationTabOrWindowSpace(spatialModification); break; } return false; } /** * When adjusting one of the "side handles" of a selected shape, set and adjust the change in the shape * so that the shape changes in the same direction as the mouse is moved. * * @param sizeHandle Size handle that is being adjusted. * @param leftToRightShapeVector * Vector running from left to right of shape accounting for any rotation. * @param bottomToTopShapeVector * Vector running from bottom to top of shape accounting for any rotation. * @param mouseDX * Mouse movement in X. * @param mouseDY * Mouse movement in Y. * @param shapeDxOut * Suggested change in shape (signed). * @param shapeDyOut * Suggested change in shape (signed). */ void AnnotationTwoDimensionalShape::getSideHandleMouseDelta(const AnnotationSizingHandleTypeEnum::Enum sizeHandle, const float leftToRightShapeVector[3], const float bottomToTopShapeVector[3], const float mouseDX, const float mouseDY, float& shapeDxOut, float& shapeDyOut) { shapeDxOut = 0.0; shapeDyOut = 0.0; bool useLeftRightFlag = false; bool useBottomTopFlag = false; bool posToNegFlag = false; switch (sizeHandle) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: useBottomTopFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: useLeftRightFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: useLeftRightFlag = true; posToNegFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: useBottomTopFlag = true; posToNegFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: break; } float shapeVector[3]; if (useLeftRightFlag) { shapeVector[0] = leftToRightShapeVector[0]; shapeVector[1] = leftToRightShapeVector[1]; shapeVector[2] = 0.0; } else if (useBottomTopFlag) { shapeVector[0] = bottomToTopShapeVector[0]; shapeVector[1] = bottomToTopShapeVector[1]; shapeVector[2] = 0.0; } else { return; } if (posToNegFlag) { shapeVector[0] = -shapeVector[0]; shapeVector[1] = -shapeVector[1]; } MathFunctions::normalizeVector(shapeVector); float mouseVector[3] = { mouseDX, mouseDY, 0.0 }; float mouseDelta = MathFunctions::normalizeVector(mouseVector); const float cosineAngle = MathFunctions::dotProduct(mouseVector, shapeVector); if (cosineAngle < 0.0) { mouseDelta = -mouseDelta; } shapeDxOut = (shapeVector[0] * mouseDelta); shapeDyOut = (shapeVector[1] * mouseDelta); } /** * Add the given X and Y values to the three-dimensional coordinate. * * @param xyz * Coordinate that has values added to it. * @param addX * Value that is added coordinate's X. * @param addY * Value that is added coordinate's Y. */ void AnnotationTwoDimensionalShape::addToXYZWithXY(float xyz[3], const float addX, const float addY) { xyz[0] += addX; xyz[1] += addY; } /** * Get the bounds for a two-dimensional shape annotation. * * @param viewportWidth * Width of the viewport. * @param viewportHeight * Height of the viewport. * @param viewportXYZ * Viewport coordinates of the annotation. * @param bottomLeftOut * The bottom left corner of the annotation absolute bounds. * @param bottomRightOut * The bottom right corner of the annotation absolute bounds. * @param topRightOut * The top right corner of the annotation absolute bounds. * @param topLeftOut * The top left corner of the annotation absolute bounds. */ bool AnnotationTwoDimensionalShape::getShapeBounds(const float viewportWidth, const float viewportHeight, const float viewportXYZ[3], float bottomLeftOut[3], float bottomRightOut[3], float topRightOut[3], float topLeftOut[3]) const { /* * NOTE: Annotation's height and width are 'relative' ([0.0, 100.0] percentage) of window size. * So want HALF of width/height */ const float width = getWidth(); float halfWidth = (width / 200.0) * viewportWidth; const float halfHeight = (getHeight() / 200.0) * viewportHeight; if (isFixedAspectRatio()) { halfWidth = halfHeight / getFixedAspectRatio(); } bottomLeftOut[0] = viewportXYZ[0] - halfWidth; bottomLeftOut[1] = viewportXYZ[1] - halfHeight; bottomLeftOut[2] = viewportXYZ[2]; bottomRightOut[0] = viewportXYZ[0] + halfWidth; bottomRightOut[1] = viewportXYZ[1] - halfHeight; bottomRightOut[2] = viewportXYZ[2]; topRightOut[0] = viewportXYZ[0] + halfWidth; topRightOut[1] = viewportXYZ[1] + halfHeight; topRightOut[2] = viewportXYZ[2]; topLeftOut[0] = viewportXYZ[0] - halfWidth; topLeftOut[1] = viewportXYZ[1] + halfHeight; topLeftOut[2] = viewportXYZ[2]; if (m_rotationAngle != 0) { Matrix4x4 matrix; matrix.translate(-viewportXYZ[0], -viewportXYZ[1], -viewportXYZ[2]); matrix.rotateZ(-m_rotationAngle); matrix.translate(viewportXYZ[0], viewportXYZ[1], viewportXYZ[2]); matrix.multiplyPoint3(bottomLeftOut); matrix.multiplyPoint3(bottomRightOut); matrix.multiplyPoint3(topRightOut); matrix.multiplyPoint3(topLeftOut); } return true; } /** * Set the width and height of the shape from bounding coordinates. * * @param xyzOne * First bounding coordinate in absolute tab coordinates * @param xyzTwo * Second bounding coordinate in absolute tab coordinates * @param spaceWidth * Width of space. * @param spaceHeight * Height of space. */ void AnnotationTwoDimensionalShape::setWidthAndHeightFromBounds(const float xyzOne[3], const float xyzTwo[3], const float spaceWidth, const float spaceHeight) { if ((spaceWidth > 0.0) && (spaceHeight > 0.0)) { const float minX = std::min(xyzOne[0], xyzTwo[0]); const float maxX = std::max(xyzOne[0], xyzTwo[0]); const float minY = std::min(xyzOne[1], xyzTwo[1]); const float maxY = std::max(xyzOne[1], xyzTwo[1]); const float width = ((maxX - minX) / spaceWidth) * 100.0; const float height = ((maxY - minY) / spaceHeight) * 100.0; setWidth(width); setHeight(height); } } /** * Save subclass data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void AnnotationTwoDimensionalShape::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void AnnotationTwoDimensionalShape::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } /** * Set the default value for height * * @param height * Default for newly created text annotations. */ void AnnotationTwoDimensionalShape::setUserDefaultHeight(const float height) { s_userDefaultHeight = height; } /** * Set the default value for width * * @param width * Default for newly created annotations. */ void AnnotationTwoDimensionalShape::setUserDefaultWidth(const float width) { s_userDefaultWidth = width; } connectome-workbench-1.4.2/src/Annotations/AnnotationTwoDimensionalShape.h000066400000000000000000000145401360521144700270440ustar00rootroot00000000000000#ifndef __ANNOTATION_TWO_DIMENSIONAL_SHAPE_H__ #define __ANNOTATION_TWO_DIMENSIONAL_SHAPE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Annotation.h" #include "CaretPointer.h" namespace caret { class AnnotationCoordinate; class AnnotationTwoDimensionalShape : public Annotation { public: AnnotationTwoDimensionalShape(const AnnotationTypeEnum::Enum type, const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType); virtual ~AnnotationTwoDimensionalShape(); AnnotationTwoDimensionalShape(const AnnotationTwoDimensionalShape& obj); AnnotationTwoDimensionalShape& operator=(const AnnotationTwoDimensionalShape& obj); virtual AnnotationOneDimensionalShape* castToOneDimensionalShape() override; virtual const AnnotationOneDimensionalShape* castToOneDimensionalShape() const override; virtual AnnotationTwoDimensionalShape* castToTwoDimensionalShape() override; virtual const AnnotationTwoDimensionalShape* castToTwoDimensionalShape() const override; AnnotationCoordinate* getCoordinate(); const AnnotationCoordinate* getCoordinate() const; virtual AnnotationSurfaceOffsetVectorTypeEnum::Enum getSurfaceOffsetVectorType() const override; float getHeight() const; void setHeight(const float height); float getWidth() const; void setWidth(const float width); float getRotationAngle() const; void setRotationAngle(const float rotationAngle); virtual bool isModified() const; virtual void clearModified(); virtual bool isSizeHandleValid(const AnnotationSizingHandleTypeEnum::Enum sizingHandle) const; virtual bool applySpatialModification(const AnnotationSpatialModification& spatialModification); virtual void applyCoordinatesSizeAndRotationFromOther(const Annotation* otherAnnotation); virtual bool getShapeBounds(const float viewportWidth, const float viewportHeight, const float viewportXYZ[3], float bottomLeftOut[3], float bottomRightOut[3], float topRightOut[3], float topLeftOut[3]) const; void getSideHandleMouseDelta(const AnnotationSizingHandleTypeEnum::Enum sizeHandle, const float leftToRightShapeVector[3], const float bottomToTopShapeVector[3], const float mouseDX, const float mouseDY, float& shapeDxOut, float& shapeDyOut); void setWidthAndHeightFromBounds(const float xyzOne[3], const float xyzTwo[3], const float spaceWidth, const float spaceHeight); static void setUserDefaultHeight(const float height); static void setUserDefaultWidth(const float width); // ADD_NEW_METHODS_HERE protected: virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: void copyHelperAnnotationTwoDimensionalShape(const AnnotationTwoDimensionalShape& obj); void initializeMembersAnnotationTwoDimensionalShape(); void addToXYZWithXY(float xyz[3], const float addX, const float addY); bool applySpatialModificationSpacerTabSpace(const AnnotationSpatialModification& spatialModification); bool applySpatialModificationSurfaceOrStereotaxicSpace(const AnnotationSpatialModification& spatialModification, const AnnotationCoordinateSpaceEnum::Enum coordinateSpace); bool applySpatialModificationTabOrWindowSpace(const AnnotationSpatialModification& spatialModification); bool applySpatialModificationChartSpace(const AnnotationSpatialModification& spatialModification); bool rotationAngleTest(const float previousMouseXYZ[3], const float shapeXYZ[3], const float currentMouseXYZ[3]) const; CaretPointer m_sceneAssistant; CaretPointer m_coordinate; float m_rotationAngle; float m_width; float m_height; static float s_userDefaultWidth; static float s_userDefaultHeight; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_TWO_DIMENSIONAL_SHAPE_DECLARE__ float AnnotationTwoDimensionalShape::s_userDefaultWidth = 25.0; float AnnotationTwoDimensionalShape::s_userDefaultHeight = 25.0; #endif // __ANNOTATION_TWO_DIMENSIONAL_SHAPE_DECLARE__ } // namespace #endif //__ANNOTATION_TWO_DIMENSIONAL_SHAPE_H__ connectome-workbench-1.4.2/src/Annotations/AnnotationTypeEnum.cxx000066400000000000000000000255361360521144700252570ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_TYPE_ENUM_DECLARE__ #include "AnnotationTypeEnum.h" #undef __ANNOTATION_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationTypeEnum * \brief Types of annotations. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_AnnotationTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void AnnotationTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "AnnotationTypeEnum.h" * * Instatiate: * m_AnnotationTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_AnnotationTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_AnnotationTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(AnnotationTypeEnumComboBoxItemActivated())); * * Update the selection: * m_AnnotationTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const AnnotationTypeEnum::Enum VARIABLE = m_AnnotationTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ AnnotationTypeEnum::AnnotationTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ AnnotationTypeEnum::~AnnotationTypeEnum() { } /** * Initialize the enumerated metadata. */ void AnnotationTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(AnnotationTypeEnum(BOX, "BOX", "Box")); enumData.push_back(AnnotationTypeEnum(COLOR_BAR, "COLOR_BAR", "Color Bar")); enumData.push_back(AnnotationTypeEnum(IMAGE, "IMAGE", "Image")); enumData.push_back(AnnotationTypeEnum(LINE, "LINE", "Line")); enumData.push_back(AnnotationTypeEnum(OVAL, "OVAL", "Oval")); enumData.push_back(AnnotationTypeEnum(TEXT, "TEXT", "Text")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const AnnotationTypeEnum* AnnotationTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const AnnotationTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationTypeEnum::Enum AnnotationTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type AnnotationTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationTypeEnum::Enum AnnotationTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type AnnotationTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t AnnotationTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ AnnotationTypeEnum::Enum AnnotationTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type AnnotationTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void AnnotationTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(AnnotationTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(AnnotationTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Annotations/AnnotationTypeEnum.h000066400000000000000000000062341360521144700246760ustar00rootroot00000000000000#ifndef __ANNOTATION_TYPE_ENUM_H__ #define __ANNOTATION_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class AnnotationTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Box */ BOX, /** Colorbar */ COLOR_BAR, /** Image */ IMAGE, /** Line */ LINE, /** Oval */ OVAL, /** Text */ TEXT }; ~AnnotationTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: AnnotationTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const AnnotationTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __ANNOTATION_TYPE_ENUM_DECLARE__ std::vector AnnotationTypeEnum::enumData; bool AnnotationTypeEnum::initializedFlag = false; int32_t AnnotationTypeEnum::integerCodeCounter = 0; #endif // __ANNOTATION_TYPE_ENUM_DECLARE__ } // namespace #endif //__ANNOTATION_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Annotations/CMakeLists.txt000066400000000000000000000061741360521144700234670ustar00rootroot00000000000000# # Name of Project # PROJECT (Annotations) # # Use XML from Qt but not GUI. # SET(QT_DONT_USE_QTGUI TRUE) # # QT include files # if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) #include_directories(${Qt5Network_INCLUDE_DIRS}) include_directories(${Qt5Xml_INCLUDE_DIRS}) endif() ###INCLUDE(${QT_USE_FILE}) # # Create a Library # ADD_LIBRARY(Annotations Annotation.h AnnotationAlignmentEnum.h AnnotationAttributesDefaultTypeEnum.h AnnotationBox.h AnnotationColorBar.h AnnotationColorBarNumericText.h AnnotationColorBarPositionModeEnum.h AnnotationColorBarSection.h AnnotationCoordinate.h AnnotationCoordinateSpaceEnum.h AnnotationDistributeEnum.h AnnotationFontAttributesInterface.h AnnotationGroup.h AnnotationGroupKey.h AnnotationGroupTypeEnum.h AnnotationGroupingModeEnum.h AnnotationImage.h AnnotationLine.h AnnotationOneDimensionalShape.h AnnotationOval.h AnnotationPercentSizeText.h AnnotationPointSizeText.h AnnotationRedoUndoCommand.h AnnotationRedoUndoCommandModeEnum.h AnnotationEditingSelectionInformation.h AnnotationSizingHandleTypeEnum.h AnnotationSpatialModification.h AnnotationSurfaceOffsetVectorTypeEnum.h AnnotationText.h AnnotationTextAlignHorizontalEnum.h AnnotationTextAlignVerticalEnum.h AnnotationTextConnectTypeEnum.h AnnotationTextFontNameEnum.h AnnotationTextFontPointSizeEnum.h AnnotationTextFontSizeTypeEnum.h AnnotationTextOrientationEnum.h AnnotationTwoDimensionalShape.h AnnotationTypeEnum.h EventAnnotationAddToRemoveFromFile.h EventAnnotationChartLabelGet.h EventAnnotationGroupGetWithKey.h EventAnnotationGrouping.h EventAnnotationTextSubstitutionGet.h EventAnnotationTextSubstitutionInvalidate.h Annotation.cxx AnnotationAlignmentEnum.cxx AnnotationAttributesDefaultTypeEnum.cxx AnnotationBox.cxx AnnotationColorBar.cxx AnnotationColorBarNumericText.cxx AnnotationColorBarPositionModeEnum.cxx AnnotationColorBarSection.cxx AnnotationCoordinate.cxx AnnotationCoordinateSpaceEnum.cxx AnnotationDistributeEnum.cxx AnnotationGroup.cxx AnnotationGroupKey.cxx AnnotationGroupTypeEnum.cxx AnnotationGroupingModeEnum.cxx AnnotationImage.cxx AnnotationLine.cxx AnnotationOneDimensionalShape.cxx AnnotationOval.cxx AnnotationPercentSizeText.cxx AnnotationPointSizeText.cxx AnnotationRedoUndoCommand.cxx AnnotationRedoUndoCommandModeEnum.cxx AnnotationEditingSelectionInformation.cxx AnnotationSizingHandleTypeEnum.cxx AnnotationSpatialModification.cxx AnnotationSurfaceOffsetVectorTypeEnum.cxx AnnotationText.cxx AnnotationTextAlignHorizontalEnum.cxx AnnotationTextAlignVerticalEnum.cxx AnnotationTextConnectTypeEnum.cxx AnnotationTextFontNameEnum.cxx AnnotationTextFontPointSizeEnum.cxx AnnotationTextFontSizeTypeEnum.cxx AnnotationTextOrientationEnum.cxx AnnotationTwoDimensionalShape.cxx AnnotationTypeEnum.cxx EventAnnotationAddToRemoveFromFile.cxx EventAnnotationChartLabelGet.cxx EventAnnotationGroupGetWithKey.cxx EventAnnotationGrouping.cxx EventAnnotationTextSubstitutionGet.cxx EventAnnotationTextSubstitutionInvalidate.cxx ) TARGET_LINK_LIBRARIES(Annotations ${CARET_QT5_LINK}) # # Find headers # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Common ${CMAKE_SOURCE_DIR}/Graphics ${CMAKE_SOURCE_DIR}/Scenes ${CMAKE_SOURCE_DIR}/Nifti ) connectome-workbench-1.4.2/src/Annotations/EventAnnotationAddToRemoveFromFile.cxx000066400000000000000000000067641360521144700303120ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_ANNOTATION_ADD_TO_REMOVE_FROM_FILE_H_DECLARE__ #include "EventAnnotationAddToRemoveFromFile.h" #undef __EVENT_ANNOTATION_ADD_TO_REMOVE_FROM_FILE_H_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventAnnotationAddToRemoveFromFile * \brief Request that an annotation be pasted from or unpasted from an annotation file * \ingroup Annotations * * Annotations may be deleted by the user but the user may request to undelete an * annotation. This event is received by an annotation file and the file will * then delete or undelete the annotation. When the file receives a request to * delete the annotation, the file will delete the annotation from its valid * annotations but it does NOT destroy the annotation. Instead, the file will * save the annotation so that the user can request undeletion of the annotation. * With this logic, the pointer can be used to request undeletion. */ /** * Constructor. * * @param mode * Mode (paste/unpaste) * @param annotationFile * AnnotationFile containing annontation that was pasted/unpasted * @param annotation * Annotation that is pasted or unpasted */ EventAnnotationAddToRemoveFromFile::EventAnnotationAddToRemoveFromFile(const Mode mode, AnnotationFile* annotationFile, Annotation* annotation) : Event(EventTypeEnum::EVENT_ANNOTATION_ADD_TO_REMOVE_FROM_FILE), m_mode(mode), m_annotationFile(annotationFile), m_annotation(annotation), m_successFlag(false) { CaretAssert(annotation); } /** * Destructor. */ EventAnnotationAddToRemoveFromFile::~EventAnnotationAddToRemoveFromFile() { } /** * @return the mode (paste/unpaste) */ EventAnnotationAddToRemoveFromFile::Mode EventAnnotationAddToRemoveFromFile::getMode() const { return m_mode; } /** * @return Pointer to annotation file of annotation that is pasted or unpasted. */ AnnotationFile* EventAnnotationAddToRemoveFromFile::getAnnotationFile() const { return m_annotationFile; } /** * @return Pointer to annotation that is pasted or unpasted. */ Annotation* EventAnnotationAddToRemoveFromFile::getAnnotation() const { return m_annotation; } /** * @return True if paste or unpaste of the annotation was successful. */ bool EventAnnotationAddToRemoveFromFile::isSuccessful() const { return m_successFlag; } /** * Set the success status for paste or unpaste of the annotation. * * @param status * New status indicating success. */ void EventAnnotationAddToRemoveFromFile::setSuccessful(const bool status) { m_successFlag = status; } connectome-workbench-1.4.2/src/Annotations/EventAnnotationAddToRemoveFromFile.h000066400000000000000000000051301360521144700277210ustar00rootroot00000000000000#ifndef __EVENT_ANNOTATION_ADD_TO_REMOVE_FROM_FILE_H__ #define __EVENT_ANNOTATION_ADD_TO_REMOVE_FROM_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class Annotation; class AnnotationFile; class EventAnnotationAddToRemoveFromFile : public Event { public: enum Mode { MODE_CREATE, MODE_CUT, MODE_DELETE, MODE_DUPLICATE, MODE_PASTE, MODE_UNCREATE, MODE_UNCUT, MODE_UNDELETE, MODE_UNDUPLICATE, MODE_UNPASTE }; EventAnnotationAddToRemoveFromFile(const Mode mode, AnnotationFile* annotationFile, Annotation* annotation); virtual ~EventAnnotationAddToRemoveFromFile(); Mode getMode() const; AnnotationFile* getAnnotationFile() const; Annotation* getAnnotation() const; bool isSuccessful() const; void setSuccessful(const bool status); // ADD_NEW_METHODS_HERE private: EventAnnotationAddToRemoveFromFile(const EventAnnotationAddToRemoveFromFile&); EventAnnotationAddToRemoveFromFile& operator=(const EventAnnotationAddToRemoveFromFile&); const Mode m_mode; AnnotationFile* m_annotationFile; Annotation* m_annotation; bool m_successFlag; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_ANNOTATION_ADD_TO_REMOVE_FROM_FILE_H_DECLARE__ // #endif // __EVENT_ANNOTATION_ADD_TO_REMOVE_FROM_FILE_H_DECLARE__ } // namespace #endif //__EVENT_ANNOTATION_ADD_TO_REMOVE_FROM_FILE_H__ connectome-workbench-1.4.2/src/Annotations/EventAnnotationChartLabelGet.cxx000066400000000000000000000034421360521144700271440ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_ANNOTATION_CHART_LABEL_GET_DECLARE__ #include "EventAnnotationChartLabelGet.h" #undef __EVENT_ANNOTATION_CHART_LABEL_GET_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventAnnotationChartLabelGet * \brief Event to get annotation chart labels * \ingroup Brain */ /** * Constructor. */ EventAnnotationChartLabelGet::EventAnnotationChartLabelGet() : Event(EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET) { } /** * Destructor. */ EventAnnotationChartLabelGet::~EventAnnotationChartLabelGet() { } /** * Add a chart label. * * @param annotationChartLabel */ void EventAnnotationChartLabelGet::addAnnotationChartLabel(Annotation* annotationChartLabel) { m_annotationChartLabels.push_back(annotationChartLabel); } /** * @return The annotation chart labels. */ std::vector EventAnnotationChartLabelGet::getAnnotationChartLabels() { return m_annotationChartLabels; } connectome-workbench-1.4.2/src/Annotations/EventAnnotationChartLabelGet.h000066400000000000000000000035441360521144700265740ustar00rootroot00000000000000#ifndef __EVENT_ANNOTATION_CHART_LABEL_GET_H__ #define __EVENT_ANNOTATION_CHART_LABEL_GET_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class Annotation; class EventAnnotationChartLabelGet : public Event { public: EventAnnotationChartLabelGet(); virtual ~EventAnnotationChartLabelGet(); void addAnnotationChartLabel(Annotation* annotationChartLabel); std::vector getAnnotationChartLabels(); // ADD_NEW_METHODS_HERE private: EventAnnotationChartLabelGet(const EventAnnotationChartLabelGet&); EventAnnotationChartLabelGet& operator=(const EventAnnotationChartLabelGet&); std::vector m_annotationChartLabels; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_ANNOTATION_CHART_LABEL_GET_DECLARE__ // #endif // __EVENT_ANNOTATION_CHART_LABEL_GET_DECLARE__ } // namespace #endif //__EVENT_ANNOTATION_CHART_LABEL_GET_H__ connectome-workbench-1.4.2/src/Annotations/EventAnnotationGroupGetWithKey.cxx000066400000000000000000000041611360521144700275430ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_ANNOTATION_GROUP_GET_WITH_KEY_DECLARE__ #include "EventAnnotationGroupGetWithKey.h" #undef __EVENT_ANNOTATION_GROUP_GET_WITH_KEY_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventAnnotationGroupGetWithKey * \brief Get an annotation group using its group key. * \ingroup Annotations */ /** * Constructor. * * @param groupKey * The annotation group's key. */ EventAnnotationGroupGetWithKey::EventAnnotationGroupGetWithKey(const AnnotationGroupKey& groupKey) : Event(EventTypeEnum::EVENT_ANNOTATION_GROUP_GET_WITH_KEY), m_groupKey(groupKey), m_annotationGroup(NULL) { } /** * Destructor. */ EventAnnotationGroupGetWithKey::~EventAnnotationGroupGetWithKey() { } /** * @return The annotation group's key. */ const AnnotationGroupKey EventAnnotationGroupGetWithKey::getGroupKey() const { return m_groupKey; } /** * @return The annotation group (my be NULL if not found). */ AnnotationGroup* EventAnnotationGroupGetWithKey::getAnnotationGroup() const { return m_annotationGroup; } /** * Set the annotation group. * * @param annotationGroup * The annotation group. */ void EventAnnotationGroupGetWithKey::setAnnotationGroup(AnnotationGroup* annotationGroup) { m_annotationGroup = annotationGroup; } connectome-workbench-1.4.2/src/Annotations/EventAnnotationGroupGetWithKey.h000066400000000000000000000040361360521144700271710ustar00rootroot00000000000000#ifndef __EVENT_ANNOTATION_GROUP_GET_WITH_KEY_H__ #define __EVENT_ANNOTATION_GROUP_GET_WITH_KEY_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationGroupKey.h" #include "Event.h" namespace caret { class Annotation; class AnnotationGroup; class EventAnnotationGroupGetWithKey : public Event { public: EventAnnotationGroupGetWithKey(const AnnotationGroupKey& groupKey); virtual ~EventAnnotationGroupGetWithKey(); const AnnotationGroupKey getGroupKey() const; AnnotationGroup* getAnnotationGroup() const; void setAnnotationGroup(AnnotationGroup* annotationGroup); // ADD_NEW_METHODS_HERE private: EventAnnotationGroupGetWithKey(const EventAnnotationGroupGetWithKey&); EventAnnotationGroupGetWithKey& operator=(const EventAnnotationGroupGetWithKey&); const AnnotationGroupKey m_groupKey; AnnotationGroup* m_annotationGroup; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_ANNOTATION_GROUP_GET_WITH_KEY_DECLARE__ // #endif // __EVENT_ANNOTATION_GROUP_GET_WITH_KEY_DECLARE__ } // namespace #endif //__EVENT_ANNOTATION_GROUP_GET_WITH_KEY_H__ connectome-workbench-1.4.2/src/Annotations/EventAnnotationGrouping.cxx000066400000000000000000000114571360521144700263020ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_ANNOTATION_GROUPING_DECLARE__ #include "EventAnnotationGrouping.h" #undef __EVENT_ANNOTATION_GROUPING_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventAnnotationGrouping * \brief Event for performing an annotation grouping operation. * \ingroup Annotations */ /** * Constructor. */ EventAnnotationGrouping::EventAnnotationGrouping() : Event(EventTypeEnum::EVENT_ANNOTATION_GROUPING), m_mode(MODE_INVALID) { m_annotationGroupKey.reset(); m_groupKeyToWhichAnnotationsWereMoved.reset(); } /** * Destructor. */ EventAnnotationGrouping::~EventAnnotationGrouping() { } /** * Set the mode to group annotations. * * @param windowIndex * Index of window in which operation was requested. * Will be negative if invalid. * @param spaceGroupKey * The annotation space group key whose annotations are moved into a user group. * @param annotations * Annotations move to user group. */ void EventAnnotationGrouping::setModeGroupAnnotations(const int32_t windowIndex, const AnnotationGroupKey spaceGroupKey, std::vector& annotations) { m_mode = MODE_GROUP; m_windowIndex = windowIndex; m_annotationGroupKey = spaceGroupKey; m_annotations = annotations; } /** * Set the mode to ungroup annotations. * * @param windowIndex * Index of window in which operation was requested. * Will be negative if invalid. * @param userGroupKey * The annotation user group key whose annotations are moved out of a user group. */ void EventAnnotationGrouping::setModeUngroupAnnotations(const int32_t windowIndex, const AnnotationGroupKey userGroupKey) { m_mode = MODE_UNGROUP; m_windowIndex = windowIndex; m_annotationGroupKey = userGroupKey; } /** * Set the mode to regroup annotations. * * @param windowIndex * Index of window in which operation was requested. * Will be negative if invalid. * @param userGroupKey * The annotation user group key whose annotations are moved back to a user group. */ void EventAnnotationGrouping::setModeRegroupAnnotations(const int32_t windowIndex, const AnnotationGroupKey userGroupKey) { m_mode = MODE_REGROUP; m_windowIndex = windowIndex; m_annotationGroupKey = userGroupKey; } /* * @return The mode. */ EventAnnotationGrouping::Mode EventAnnotationGrouping::getMode() const { return m_mode; } /* * @return The annotation group Key */ AnnotationGroupKey EventAnnotationGrouping::getAnnotationGroupKey() const { return m_annotationGroupKey; } /** * @return The annotation group key to which the annotations were * moved. This value is set by the receiver of the event and * can be used to assist with 'undo' of this event. This method * must be called after the event has successfully executed. */ AnnotationGroupKey EventAnnotationGrouping::getGroupKeyToWhichAnnotationsWereMoved() const { return m_groupKeyToWhichAnnotationsWereMoved; } /** * Set the annotation group key to which the anntotations were * moved. This method is called by the receiver of the event * so that the caller may be able to 'undo' this event. * * @param movedToKey * Key of group that now contains the annotations after * the event is executed. */ void EventAnnotationGrouping::setGroupKeyToWhichAnnotationsWereMoved(const AnnotationGroupKey& movedToKey) { m_groupKeyToWhichAnnotationsWereMoved = movedToKey; } /* * @return The annotations. */ std::vector EventAnnotationGrouping::getAnnotations() const { return m_annotations; } /** * @return Index of window in which operation was requested. * Will be negative if invalid. */ int32_t EventAnnotationGrouping::getWindowIndex() const { return m_windowIndex; } connectome-workbench-1.4.2/src/Annotations/EventAnnotationGrouping.h000066400000000000000000000056361360521144700257310ustar00rootroot00000000000000#ifndef __EVENT_ANNOTATION_GROUPING_H__ #define __EVENT_ANNOTATION_GROUPING_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationGroupKey.h" #include "Event.h" namespace caret { class Annotation; class EventAnnotationGrouping : public Event { public: enum Mode { MODE_INVALID, MODE_GROUP, MODE_REGROUP, MODE_UNGROUP }; EventAnnotationGrouping(); virtual ~EventAnnotationGrouping(); void setModeGroupAnnotations(const int32_t windowIndex, const AnnotationGroupKey spaceGroupKey, std::vector& annotations); void setModeUngroupAnnotations(const int32_t windowIndex, const AnnotationGroupKey userGroupKey); void setModeRegroupAnnotations(const int32_t windowIndex, const AnnotationGroupKey userGroupKey); Mode getMode() const; AnnotationGroupKey getAnnotationGroupKey() const; std::vector getAnnotations() const; AnnotationGroupKey getGroupKeyToWhichAnnotationsWereMoved() const; void setGroupKeyToWhichAnnotationsWereMoved(const AnnotationGroupKey& movedToKey); int32_t getWindowIndex() const; // ADD_NEW_METHODS_HERE private: EventAnnotationGrouping(const EventAnnotationGrouping&); EventAnnotationGrouping& operator=(const EventAnnotationGrouping&); Mode m_mode; int32_t m_windowIndex; AnnotationGroupKey m_annotationGroupKey; std::vector m_annotations; AnnotationGroupKey m_groupKeyToWhichAnnotationsWereMoved; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_ANNOTATION_GROUPING_DECLARE__ // #endif // __EVENT_ANNOTATION_GROUPING_DECLARE__ } // namespace #endif //__EVENT_ANNOTATION_GROUPING_H__ connectome-workbench-1.4.2/src/Annotations/EventAnnotationTextSubstitutionGet.cxx000066400000000000000000000067271360521144700305350ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_ANNOTATION_TEXT_SUBSTITUTION_GET_DECLARE__ #include "EventAnnotationTextSubstitutionGet.h" #undef __EVENT_ANNOTATION_TEXT_SUBSTITUTION_GET_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventAnnotationTextSubstitutionGet * \brief Get the substitution text for a text annotation. * \ingroup Annotations */ /** * Constructor. */ EventAnnotationTextSubstitutionGet::EventAnnotationTextSubstitutionGet() : Event(EventTypeEnum::EVENT_ANNOTATION_TEXT_SUBSTITUTION_GET) { } /** * Destructor. */ EventAnnotationTextSubstitutionGet::~EventAnnotationTextSubstitutionGet() { } /** * @return All substitution names for which values are requested. * This method is called by AnnotationTextSubstitutionFile's so * that the file may provide substitution values. */ const std::vector& EventAnnotationTextSubstitutionGet::getSubstitutionNames() const { return m_substitutionNames; } /** * Get the substitution value for the given substitution name. * This method is called by the annotation drawing code to get * annotation text substitution values. * * @param substitutionValue * The substitutionValue. */ AString EventAnnotationTextSubstitutionGet::getSubstitutionValueForName(const AString& substitutionName) const { AString value; const auto iter = m_substitutionNamesAndValues.find(substitutionName); if (iter != m_substitutionNamesAndValues.end()) { value = iter->second; } return value; } /** * Set the substitution value. * This method is called by AnnotationTextSubstitutionFile's so * that the file may provide substitution values. * * @param substitutionName * The substitution name. * @param substitutionValue * The substitution value. */ void EventAnnotationTextSubstitutionGet::setSubstitutionValueForName(const AString& substitutionName, const AString& substitutionValue) { auto iter = m_substitutionNamesAndValues.find(substitutionName); if (iter != m_substitutionNamesAndValues.end()) { iter->second = substitutionValue; } } /** * Add a substitution name for which a substitution value is sought. * This method is called by the annotation drawing code to get * annotation text substitution values. * * @param substitutionName * Name of the annotation substitution. */ void EventAnnotationTextSubstitutionGet::addSubstitutionName(const AString& substitutionName) { m_substitutionNames.push_back(substitutionName); m_substitutionNamesAndValues.insert(std::make_pair(substitutionName, "")); } connectome-workbench-1.4.2/src/Annotations/EventAnnotationTextSubstitutionGet.h000066400000000000000000000044001360521144700301440ustar00rootroot00000000000000#ifndef __EVENT_ANNOTATION_TEXT_SUBSTITUTION_GET_H__ #define __EVENT_ANNOTATION_TEXT_SUBSTITUTION_GET_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "Event.h" namespace caret { class EventAnnotationTextSubstitutionGet : public Event { public: EventAnnotationTextSubstitutionGet(); const std::vector& getSubstitutionNames() const; AString getSubstitutionValueForName(const AString& substitutionName) const; void addSubstitutionName(const AString& substitutionName); void setSubstitutionValueForName(const AString& substitutionName, const AString& substitutionValue); virtual ~EventAnnotationTextSubstitutionGet(); EventAnnotationTextSubstitutionGet(const EventAnnotationTextSubstitutionGet&) = delete; EventAnnotationTextSubstitutionGet& operator=(const EventAnnotationTextSubstitutionGet&) = delete; // ADD_NEW_METHODS_HERE private: std::vector m_substitutionNames; std::map m_substitutionNamesAndValues; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_ANNOTATION_TEXT_SUBSTITUTION_GET_DECLARE__ // #endif // __EVENT_ANNOTATION_TEXT_SUBSTITUTION_GET_DECLARE__ } // namespace #endif //__EVENT_ANNOTATION_TEXT_SUBSTITUTION_GET_H__ connectome-workbench-1.4.2/src/Annotations/EventAnnotationTextSubstitutionInvalidate.cxx000066400000000000000000000030741360521144700320660ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_ANNOTATION_TEXT_SUBSTITUTION_INVALIDATE_DECLARE__ #include "EventAnnotationTextSubstitutionInvalidate.h" #undef __EVENT_ANNOTATION_TEXT_SUBSTITUTION_INVALIDATE_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventAnnotationTextSubstitutionInvalidate * \brief * \ingroup Annotations * * */ /** * Constructor. */ EventAnnotationTextSubstitutionInvalidate::EventAnnotationTextSubstitutionInvalidate() : Event(EventTypeEnum::EVENT_ANNOTATION_TEXT_SUBSTITUTION_INVALIDATE) { } /** * Destructor. */ EventAnnotationTextSubstitutionInvalidate::~EventAnnotationTextSubstitutionInvalidate() { } connectome-workbench-1.4.2/src/Annotations/EventAnnotationTextSubstitutionInvalidate.h000066400000000000000000000034561360521144700315170ustar00rootroot00000000000000#ifndef __EVENT_ANNOTATION_TEXT_SUBSTITUTION_INVALIDATE_H__ #define __EVENT_ANNOTATION_TEXT_SUBSTITUTION_INVALIDATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class EventAnnotationTextSubstitutionInvalidate : public Event { public: EventAnnotationTextSubstitutionInvalidate(); virtual ~EventAnnotationTextSubstitutionInvalidate(); EventAnnotationTextSubstitutionInvalidate(const EventAnnotationTextSubstitutionInvalidate&) = delete; EventAnnotationTextSubstitutionInvalidate& operator=(const EventAnnotationTextSubstitutionInvalidate&) = delete; // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_ANNOTATION_TEXT_SUBSTITUTION_INVALIDATE_DECLARE__ // #endif // __EVENT_ANNOTATION_TEXT_SUBSTITUTION_INVALIDATE_DECLARE__ } // namespace #endif //__EVENT_ANNOTATION_TEXT_SUBSTITUTION_INVALIDATE_H__ connectome-workbench-1.4.2/src/Annotations/create_enum.sh000077500000000000000000000010511360521144700235420ustar00rootroot00000000000000#!/bin/tcsh wb_cmd_run -class-create-enum AnnotationSizingHandleTypeEnum 11 true \ ANNOTATION_SIZING_HANDLE_BOX_BOTTOM \ ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT \ ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT \ ANNOTATION_SIZING_HANDLE_BOX_LEFT \ ANNOTATION_SIZING_HANDLE_BOX_RIGHT \ ANNOTATION_SIZING_HANDLE_BOX_TOP \ ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT \ ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT \ ANNOTATION_SIZING_HANDLE_ROTATION \ ANNOTATION_SIZING_HANDLE_LINE_END \ ANNOTATION_SIZING_HANDLE_LINE_START connectome-workbench-1.4.2/src/Brain/000077500000000000000000000000001360521144700174555ustar00rootroot00000000000000connectome-workbench-1.4.2/src/Brain/AnnotationArrangerExecutor.cxx000066400000000000000000001163521360521144700255240ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #define __ANNOTATION_ARRANGER_EXECUTOR_DECLARE__ #include "AnnotationArrangerExecutor.h" #undef __ANNOTATION_ARRANGER_EXECUTOR_DECLARE__ #include "AnnotationArrangerInputs.h" #include "AnnotationCoordinate.h" #include "AnnotationManager.h" #include "AnnotationOneDimensionalShape.h" #include "AnnotationRedoUndoCommand.h" #include "AnnotationText.h" #include "BrainOpenGLTextRenderInterface.h" #include "CaretAssert.h" #include "CaretException.h" #include "DisplayPropertiesAnnotationTextSubstitution.h" #include "EventGetViewportSize.h" #include "EventManager.h" using namespace caret; /** * \class caret::AnnotationArrangerExecutor * \brief Performs alignment, distribution of annotations similar to PowerPoint. * \ingroup Brain */ /** * Constructor. */ AnnotationArrangerExecutor::AnnotationArrangerExecutor() : CaretObject(), m_mode(MODE_NONE), m_annotationManager(NULL), m_alignment(AnnotationAlignmentEnum::ALIGN_BOTTOM), m_distribute(AnnotationDistributeEnum::HORIZONTALLY), m_debugFlag(false) { } /** * Destructor. */ AnnotationArrangerExecutor::~AnnotationArrangerExecutor() { } /** * Apply alignment modification to selected annotations * * @param annotationManager * The annotation manager. * @param arrangerInputs * Contains information about the alignment. * @param alignment * The alignment selection. * @param errorMessageOut * Contains description of error. * @return * True if the alignment was successful, else false. */ bool AnnotationArrangerExecutor::alignAnnotations(AnnotationManager* annotationManager, const AnnotationArrangerInputs& arrangerInputs, const AnnotationAlignmentEnum::Enum alignment, AString& errorMessageOut) { m_mode = MODE_ALIGN; m_annotationManager = annotationManager; CaretAssert(m_annotationManager); m_alignment = alignment; errorMessageOut.clear(); try { alignAnnotationsPrivate(arrangerInputs); } catch (const CaretException& caretException) { errorMessageOut = caretException.whatString(); return false; } return true; } /** * Apply distribute modification to selected annotations * * @param annotationManager * The annotation manager. * @param arrangerInputs * Contains information about the alignment. * @param distribute * The distribute selection. * @param errorMessageOut * Contains description of error. * @return * True if the alignment was successful, else false. */ bool AnnotationArrangerExecutor::distributeAnnotations(AnnotationManager* annotationManager, const AnnotationArrangerInputs& arrangerInputs, const AnnotationDistributeEnum::Enum distribute, AString& errorMessageOut) { m_mode = MODE_DISTRIBUTE; m_annotationManager = annotationManager; CaretAssert(m_annotationManager); m_distribute = distribute; errorMessageOut.clear(); try { distributeAnnotationsPrivate(arrangerInputs); } catch (const CaretException& caretException) { errorMessageOut = caretException.whatString(); return false; } return true; } /** * \class caret::AnnotationArrangerExecutor::SortForDistributeFunctionObject * \brief Performs alignment, distribution of annotations similar to PowerPoint. * \ingroup Brain */ AnnotationArrangerExecutor::SortForDistributeFunctionObject::SortForDistributeFunctionObject(const AnnotationDistributeEnum::Enum distribute) : m_distribute(distribute) { } /** * Function for sorting by distribution value. * * @param ann1 * First annotation info. * @param ann2 * Second annotation info. * @return * True if ann1 less than ann2, else false. */ bool AnnotationArrangerExecutor::SortForDistributeFunctionObject::operator()(const AnnotationInfo& ann1, const AnnotationInfo& ann2) const { switch (m_distribute) { case AnnotationDistributeEnum::HORIZONTALLY: return (ann1.m_windowMidPointXY[0] < ann2.m_windowMidPointXY[0]); break; case AnnotationDistributeEnum::VERTICALLY: return (ann1.m_windowMidPointXY[1] < ann2.m_windowMidPointXY[1]); break; } return false; } /** * Apply distribute modification to selected annotations * * @param arrangerInputs * Contains information about the distribute. * @throw CaretException * If there is an error. */ void AnnotationArrangerExecutor::distributeAnnotationsPrivate(const AnnotationArrangerInputs& arrangerInputs) { initializeForArranging(arrangerInputs); printAnnotationInfo("BEFORE"); /* * Sort the annotation info by the window mid point value */ std::sort(m_annotationInfo.begin(), m_annotationInfo.end(), SortForDistributeFunctionObject(m_distribute)); printAnnotationInfo("AFTER SORT FOR DISTRIBUTE"); float distMinValue = 0.0; float distMaxValue = 0.0; float distributeSum = 0.0; const int32_t numAnn = static_cast(m_annotationInfo.size()); for (int32_t i = 0; i < numAnn; i++) { CaretAssertVectorIndex(m_annotationInfo, i); AnnotationInfo& annInfo = m_annotationInfo[i]; switch (m_distribute) { case AnnotationDistributeEnum::HORIZONTALLY: if (i == 0) { distMinValue = annInfo.m_windowBoundingBox.getMaxX(); } else if (i == (numAnn - 1)) { distMaxValue = annInfo.m_windowBoundingBox.getMinX(); } else { distributeSum += annInfo.m_windowBoundingBox.getDifferenceX(); } break; case AnnotationDistributeEnum::VERTICALLY: if (i == 0) { distMinValue = annInfo.m_windowBoundingBox.getMaxY(); } else if (i == (numAnn - 1)) { distMaxValue = annInfo.m_windowBoundingBox.getMinY(); } else { distributeSum += annInfo.m_windowBoundingBox.getDifferenceY(); } break; } } /* * Space between max edge of first and min edge of last */ const float availableSpace = distMaxValue - distMinValue; /* * Space to put between annotations. * Will be negative when the distance between the first and last annotations * is less than the total size of the annotations that are distributed. */ const float numberOfSpacesBetweenAnnotations = numAnn - 1; const float spaceBetweenAnnotations = ((availableSpace - distributeSum) / numberOfSpacesBetweenAnnotations); if (m_debugFlag) { std::cout << "Dist min max: (" << distMinValue << ", " << distMaxValue << ") availSpace=" << availableSpace << " delta-space=" << spaceBetweenAnnotations << std::endl; } std::vector beforeMoving; std::vector afterMoving; /* * Initialize to the right/top edge of the first annotation */ float newCoordinate = distMinValue; for (int32_t i = 0; i < numAnn; i++) { CaretAssertVectorIndex(m_annotationInfo, i); AnnotationInfo& annInfo = m_annotationInfo[i]; Annotation* annotationModified = annInfo.m_annotation->clone(); if (i == 0) { /* first annotation does not move */ } else if (i == (numAnn - 1)) { /* last annotation does not move */ } else { /* * newCoordinate is now at the location of the * left/bottom edge of the annotation to be moved. */ newCoordinate += spaceBetweenAnnotations; /* * For most annotations, the annotation's coordinate is at the * center of the annotation. However, an exception is text annotation * due to their alignment properties. So, we calculate how much the * left or bottom edge should move and apply that difference to the annotation's * coordinate. */ float dx = 0.0; float dy = 0.0; float annotationWidthHeight = 0.0; switch (m_distribute) { case AnnotationDistributeEnum::HORIZONTALLY: { dx = newCoordinate - annInfo.m_windowBoundingBox.getMinX(); annotationWidthHeight = annInfo.m_windowBoundingBox.getDifferenceX(); } break; case AnnotationDistributeEnum::VERTICALLY: { dy = newCoordinate - annInfo.m_windowBoundingBox.getMinY(); annotationWidthHeight = annInfo.m_windowBoundingBox.getDifferenceY(); } break; } annInfo.moveAnnotationByXY(annotationModified, dx, dy); newCoordinate += annotationWidthHeight; } beforeMoving.push_back(annInfo.m_annotation); afterMoving.push_back(annotationModified); } bool validFlag = true; AString errorMessage; /* * If any annotations were moved, use a redo command * so that the user may undo the alignment. */ if ( ! beforeMoving.empty()) { CaretAssert(beforeMoving.size() == afterMoving.size()); AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeLocationAndSize(beforeMoving, afterMoving); undoCommand->setDescription(AnnotationDistributeEnum::toGuiName(m_distribute)); validFlag = m_annotationManager->applyCommand(undoCommand, errorMessage); } /* * The undo command copies these annotations so we need * to delete them. */ for (std::vector::iterator annIter = afterMoving.begin(); annIter != afterMoving.end(); annIter++) { Annotation* ann = *annIter; CaretAssert(ann); delete ann; } if ( ! validFlag) { throw CaretException(errorMessage); } } /** * Apply alignment modification to selected annotations * * @param arrangerInputs * Contains information about the alignment. * @throw CaretException * If there is an error. */ void AnnotationArrangerExecutor::alignAnnotationsPrivate(const AnnotationArrangerInputs& arrangerInputs) { switch (m_mode) { case MODE_NONE: CaretAssertMessage(0, "Mode has not been set !!!"); throw CaretException("Mode has not been set !!!"); break; case MODE_ALIGN: break; case MODE_DISTRIBUTE: break; } initializeForArranging(arrangerInputs); printAnnotationInfo("BEFORE"); /* * Set the coordinate value to which annotations are aligned * based upon the selected alignment. */ float alignToCoordinateValue = 0.0; switch (m_alignment) { case AnnotationAlignmentEnum::ALIGN_BOTTOM: alignToCoordinateValue = m_allAnnotationsBoundingBox.getMinY(); break; case AnnotationAlignmentEnum::ALIGN_CENTER: alignToCoordinateValue = (m_allAnnotationsBoundingBox.getMinX() + m_allAnnotationsBoundingBox.getMaxX()) / 2.0; break; case AnnotationAlignmentEnum::ALIGN_LEFT: alignToCoordinateValue = m_allAnnotationsBoundingBox.getMinX(); break; case AnnotationAlignmentEnum::ALIGN_MIDDLE: alignToCoordinateValue = (m_allAnnotationsBoundingBox.getMinY() + m_allAnnotationsBoundingBox.getMaxY()) / 2.0; break; case AnnotationAlignmentEnum::ALIGN_RIGHT: alignToCoordinateValue = m_allAnnotationsBoundingBox.getMaxX(); break; case AnnotationAlignmentEnum::ALIGN_TOP: alignToCoordinateValue = m_allAnnotationsBoundingBox.getMaxY(); break; } if (m_debugFlag) { std::cout << "Bounding box for all: " << qPrintable(m_allAnnotationsBoundingBox.toString()) << std::endl; std::cout << "New Align to value: " << alignToCoordinateValue << std::endl; } /* * Move each of the annotations to align them. */ std::vector beforeMoving; std::vector afterMoving; for (std::vector::iterator annInfoIter = m_annotationInfo.begin(); annInfoIter != m_annotationInfo.end(); annInfoIter++) { AnnotationInfo& annInfo = *annInfoIter; alignAnnotationToValue(alignToCoordinateValue, annInfo, beforeMoving, afterMoving); } bool validFlag = true; AString errorMessage; /* * If any annotations were moved, use a redo command * so that the user may undo the alignment. */ if ( ! beforeMoving.empty()) { CaretAssert(beforeMoving.size() == afterMoving.size()); AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeLocationAndSize(beforeMoving, afterMoving); undoCommand->setDescription(AnnotationAlignmentEnum::toGuiName(m_alignment)); validFlag = m_annotationManager->applyCommand(undoCommand, errorMessage); } /* * The undo command copies these annotations so we need * to delete them. */ for (std::vector::iterator annIter = afterMoving.begin(); annIter != afterMoving.end(); annIter++) { Annotation* ann = *annIter; CaretAssert(ann); delete ann; } if ( ! validFlag) { throw CaretException(errorMessage); } } /** * Initialize members in preparation for arranging annotations. * * @param arrangerInputs * Inputs for arranging annotations. */ void AnnotationArrangerExecutor::initializeForArranging(const AnnotationArrangerInputs& arrangerInputs) { /* * Get the window's viewport. */ EventGetViewportSize vpEvent(EventGetViewportSize::MODE_WINDOW_INDEX, arrangerInputs.getWindowIndex()); EventManager::get()->sendEvent(vpEvent.getPointer()); if (vpEvent.isViewportSizeValid()) { vpEvent.getViewportSize(m_windowViewport); } else { throw CaretException("Failed to get viewport size for window index " + QString::number(arrangerInputs.getWindowIndex() + 1)); } /* * Verify that selected annotations can be arranged. */ std::vector annotations; getAnnotationsForArranging(arrangerInputs, annotations); /** * Setup information to assist with arranging each annotation. */ setupAnnotationInfo(arrangerInputs, annotations); /** * Setup a bounding box that contains the bounds * of all annotations. */ m_allAnnotationsBoundingBox.resetForUpdate(); for (std::vector::iterator annInfoIter = m_annotationInfo.begin(); annInfoIter != m_annotationInfo.end(); annInfoIter++) { const AnnotationInfo& annInfo = *annInfoIter; m_allAnnotationsBoundingBox.update(annInfo.m_windowBoundingBox.getMinXYZ()); m_allAnnotationsBoundingBox.update(annInfo.m_windowBoundingBox.getMaxXYZ()); } } /** * Get the annotations for arranging. Not all coordinate spaces are supported. * * @param arrangerInputs * Inputs for arranging annotations. * @param annotationsOut * On output contains annotations that will be arranged. * @throw CaretException * If there are input annotations that cannot be aligned. */ void AnnotationArrangerExecutor::getAnnotationsForArranging(const AnnotationArrangerInputs& arrangerInputs, std::vector& annotationsOut) const { annotationsOut.clear(); std::vector spaces; spaces.push_back(AnnotationCoordinateSpaceEnum::SPACER); spaces.push_back(AnnotationCoordinateSpaceEnum::TAB); spaces.push_back(AnnotationCoordinateSpaceEnum::WINDOW); const std::vector allSpaceAnnotations = m_annotationManager->getAnnotationsSelectedForEditing(arrangerInputs.getWindowIndex()); annotationsOut = m_annotationManager->getAnnotationsSelectedForEditingInSpaces(arrangerInputs.getWindowIndex(), spaces); if (allSpaceAnnotations.size() != annotationsOut.size()) { QString spaceString; for (std::vector::iterator spaceIter = spaces.begin(); spaceIter != spaces.end(); spaceIter++) { spaceString += ("\n " + AnnotationCoordinateSpaceEnum::toGuiName(*spaceIter) + " "); } throw CaretException("Annotations are selected that cannot be aligned due to their coordinate space. " "Annotations MUST BE in one of these spaces:" + spaceString); } const int32_t numAnnotations = static_cast(annotationsOut.size()); if (numAnnotations < 1) { throw CaretException("No annotations are selected."); } switch (m_mode) { case MODE_NONE: CaretAssert(0); break; case MODE_ALIGN: if (numAnnotations < 2) { throw CaretException("At least two annotations must be selected for alignment."); } break; case MODE_DISTRIBUTE: if (numAnnotations < 3) { throw CaretException("At least three annotations must be selected for distributing."); } break; } } /** * Setup the annotation information that contains the bounds of * the annotation in window coordinates and other information. * * @param arrangerInputs * Inputs for arranging annotations. * @param annotations * Contains annotations that will be arranged. * @throw CaretException * If there are input annotations that cannot be aligned. */ void AnnotationArrangerExecutor::setupAnnotationInfo(const AnnotationArrangerInputs& arrangerInputs, std::vector& annotations) { m_annotationInfo.clear(); for (std::vector::iterator annIter = annotations.begin(); annIter != annotations.end(); annIter++) { Annotation* annotation = *annIter; CaretAssert(annotation); /* * Viewport containing the annotation. */ int32_t annViewport[4] = { 0, 0, 0, 0 }; switch (annotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::SPACER: getSpacerTabViewport(annotation->getSpacerTabIndex(), annViewport); break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::SURFACE: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::TAB: getTabViewport(annotation->getTabIndex(), annViewport); break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: annViewport[0] = m_windowViewport[0]; annViewport[1] = m_windowViewport[1]; annViewport[2] = m_windowViewport[2]; annViewport[3] = m_windowViewport[3]; break; } const AnnotationOneDimensionalShape* oneDimAnn = dynamic_cast(annotation); const AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(annotation); float viewportPixelOneXYZ[3] = { 0.0, 0.0, 0.0 }; float viewportPixelTwoXYZ[3] = { 0.0, 0.0, 0.0 }; bool viewportPixelTwoXYZValidFlag = false; /* * Bounding box for the annotation. */ BoundingBox windowBoundingBox; windowBoundingBox.resetForUpdate(); if (oneDimAnn != NULL) { float xyzRel1[3]; oneDimAnn->getStartCoordinate()->getXYZ(xyzRel1); float xyzRel2[3]; oneDimAnn->getEndCoordinate()->getXYZ(xyzRel2); /* * Convert range [0.0, 100.0] to viewport XY. */ Annotation::relativeXYZToViewportXYZ(xyzRel1, annViewport[2], annViewport[3], viewportPixelOneXYZ); Annotation::relativeXYZToViewportXYZ(xyzRel2, annViewport[2], annViewport[3], viewportPixelTwoXYZ); windowBoundingBox.update(annViewport[0] + viewportPixelOneXYZ[0], annViewport[1] + viewportPixelOneXYZ[1], viewportPixelOneXYZ[2]); windowBoundingBox.update(annViewport[0] + viewportPixelTwoXYZ[0], annViewport[1] + viewportPixelTwoXYZ[1], viewportPixelTwoXYZ[2]); viewportPixelTwoXYZValidFlag = true; } else if (twoDimAnn != NULL) { float xyz[3]; twoDimAnn->getCoordinate()->getXYZ(xyz); /* * Convert range [0.0, 100.0] to viewport XY. */ Annotation::relativeXYZToViewportXYZ(xyz, annViewport[2], annViewport[3], viewportPixelOneXYZ); float bottomLeft[3]; float bottomRight[3]; float topRight[3]; float topLeft[3]; bool boundsValidFlag = false; if (twoDimAnn->getType() == AnnotationTypeEnum::TEXT) { const AnnotationText* textAnn = dynamic_cast(twoDimAnn); CaretAssert(textAnn); arrangerInputs.getTextRender()->getBoundsForTextAtViewportCoords(*textAnn, arrangerInputs.getDrawingFlags(), viewportPixelOneXYZ[0], viewportPixelOneXYZ[1], viewportPixelOneXYZ[2], annViewport[2], annViewport[3], bottomLeft, bottomRight, topRight, topLeft); boundsValidFlag = true; } else { boundsValidFlag = twoDimAnn->getShapeBounds(annViewport[2], annViewport[3], viewportPixelOneXYZ, bottomLeft, bottomRight, topRight, topLeft); } if (boundsValidFlag) { windowBoundingBox.update(annViewport[0] + bottomLeft[0], annViewport[1] + bottomLeft[1], bottomLeft[2]); windowBoundingBox.update(annViewport[0] + bottomRight[0], annViewport[1] + bottomRight[1], bottomRight[2]); windowBoundingBox.update(annViewport[0] + topRight[0], annViewport[1] + topRight[1], topRight[2]); windowBoundingBox.update(annViewport[0] + topLeft[0], annViewport[1] + topLeft[1], topLeft[2]); } else { throw CaretException("Failed to get bounds for an annotation: " + twoDimAnn->toString()); } } AnnotationInfo annInfo(annotation, annViewport, windowBoundingBox, viewportPixelOneXYZ, viewportPixelTwoXYZ, viewportPixelTwoXYZValidFlag); m_annotationInfo.push_back(annInfo); } CaretAssert(annotations.size() == m_annotationInfo.size()); } /** * Print the annotation info. * * @param title * Title that is printed before the annotation * information is printed. */ void AnnotationArrangerExecutor::printAnnotationInfo(const QString& title) { if ( ! m_debugFlag) { return; } std::cout << std::endl; std::cout << qPrintable(title) << std::endl; for (std::vector::iterator annInfoIter = m_annotationInfo.begin(); annInfoIter != m_annotationInfo.end(); annInfoIter++) { const AnnotationInfo& annInfo = *annInfoIter; annInfo.print(); } std::cout << std::endl; } /** * Align an annotation to the given window coordinate value. * * @param alignToWindowCoordinateValue * Align to window coordinate value. * @param annotationInfo * Information for annotation that is aligned. * @param annotationsBeforeMoving * If an annotation is moved, upon exit this will * contain the annotation before it is moved and * is used by the redo/undo command. * @param annotationsAfterMoving * If an annotation is moved, upon exit this will * contain the annotation after it is moved and * is used by the redo/undo command. * @throw CaretException * If there is an error. */ void AnnotationArrangerExecutor::alignAnnotationToValue(const float alignToWindowCoordinateValue, AnnotationInfo& annotationInfo, std::vector& annotationsBeforeMoving, std::vector& annotationsAfterMoving) { /* * Set amount of movement needed to align the annotation. */ float dx = 0.0; float dy = 0.0; switch (m_alignment) { case AnnotationAlignmentEnum::ALIGN_BOTTOM: dy = alignToWindowCoordinateValue - annotationInfo.m_windowBoundingBox.getMinY(); break; case AnnotationAlignmentEnum::ALIGN_CENTER: dx = alignToWindowCoordinateValue - (annotationInfo.m_windowBoundingBox.getMinX() + annotationInfo.m_windowBoundingBox.getMaxX()) / 2.0; break; case AnnotationAlignmentEnum::ALIGN_LEFT: dx = alignToWindowCoordinateValue - annotationInfo.m_windowBoundingBox.getMinX(); break; case AnnotationAlignmentEnum::ALIGN_MIDDLE: dy = alignToWindowCoordinateValue - (annotationInfo.m_windowBoundingBox.getMinY() + annotationInfo.m_windowBoundingBox.getMaxY()) / 2.0; break; case AnnotationAlignmentEnum::ALIGN_RIGHT: dx = alignToWindowCoordinateValue - annotationInfo.m_windowBoundingBox.getMaxX(); break; case AnnotationAlignmentEnum::ALIGN_TOP: dy = alignToWindowCoordinateValue - annotationInfo.m_windowBoundingBox.getMaxY(); break; } if (m_debugFlag) { std::cout << "Moving " << qPrintable(annotationInfo.m_annotation->toString()) << " by dx=" << dx << ", dy=" << dy << std::endl; } Annotation* annotationModified = annotationInfo.m_annotation->clone(); bool modifiedFlag = annotationInfo.moveAnnotationByXY(annotationModified, dx, dy); if (modifiedFlag) { annotationsBeforeMoving.push_back(annotationInfo.m_annotation); annotationsAfterMoving.push_back(annotationModified); } else { delete annotationModified; } } /** * Get the viewport for the given tab. Viewports are cached for efficiency. * * @param tabIndex * Index of the tab. * @param tabViewportOut * Viewport of the tab. * @throw CaretException * If there is an error. */ void AnnotationArrangerExecutor::getTabViewport(const int32_t tabIndex, int32_t tabViewportOut[4]) { /* * Check cached viewports to avoid retrieving it a second time */ std::map::iterator iter = m_tabViewports.find(tabIndex); if (iter != m_tabViewports.end()) { tabViewportOut[0] = iter->second.m_viewport[0]; tabViewportOut[1] = iter->second.m_viewport[1]; tabViewportOut[2] = iter->second.m_viewport[2]; tabViewportOut[3] = iter->second.m_viewport[3]; return; } EventGetViewportSize vpEvent(EventGetViewportSize::MODE_TAB_AFTER_MARGINS_INDEX, tabIndex); EventManager::get()->sendEvent(vpEvent.getPointer()); if (vpEvent.isViewportSizeValid()) { ViewportArray viewportArray; vpEvent.getViewportSize(tabViewportOut); viewportArray.m_viewport[0] = tabViewportOut[0]; viewportArray.m_viewport[1] = tabViewportOut[1]; viewportArray.m_viewport[2] = tabViewportOut[2]; viewportArray.m_viewport[3] = tabViewportOut[3]; m_tabViewports.insert(std::make_pair(tabIndex, viewportArray)); } else { throw CaretException("Failed to get viewport size for tab index " + QString::number(tabIndex + 1)); } } /** * Get the viewport for the given spacer tab. Viewports are cached for efficiency. * * @param spacerTabIndex * Index of the spacer tab. * @param tabViewportOut * Viewport of the tab. * @throw CaretException * If there is an error. */ void AnnotationArrangerExecutor::getSpacerTabViewport(const SpacerTabIndex& spacerTabIndex, int32_t tabViewportOut[4]) { EventGetViewportSize vpEvent(spacerTabIndex); EventManager::get()->sendEvent(vpEvent.getPointer()); if (vpEvent.isViewportSizeValid()) { vpEvent.getViewportSize(tabViewportOut); } else { throw CaretException("Failed to get viewport size for spacer tab index " + spacerTabIndex.toString()); } } /** * Get a description of this object's content. * @return String describing this object's content. */ AString AnnotationArrangerExecutor::toString() const { return "AnnotationArrangerExecutor"; } /** * \class caret::AnnotationInfo * \brief Contains information used to arrange annotations. * \ingroup Brain */ /** * Constructor. * * @param annotation * The annotation. * @param viewport * Viewport coordinates containing the annotation. * @param windowBoundingBox * Bounding box for the annotation in window coordinates. * @param viewportPixelOneXY * XY coordinate of the annotation in its viewport. * @param viewportPixelTwoXY * optional second XY coordinate of the annotation in its viewport. * @param viewportPixelTwoXYValidValid * True if optional second XY coordinate is valid. */ AnnotationArrangerExecutor::AnnotationInfo::AnnotationInfo(Annotation* annotation, const int32_t viewport[4], const BoundingBox windowBoundingBox, float viewportPixelOneXY[2], float viewportPixelTwoXY[2], const bool viewportPixelTwoXYValidValid) : m_annotation(annotation) { m_viewport[0] = viewport[0]; m_viewport[1] = viewport[1]; m_viewport[2] = viewport[2]; m_viewport[3] = viewport[3]; m_viewportPixelOneXY[0] = viewportPixelOneXY[0]; m_viewportPixelOneXY[1] = viewportPixelOneXY[1]; m_viewportPixelTwoXY[0] = viewportPixelTwoXY[0]; m_viewportPixelTwoXY[1] = viewportPixelTwoXY[1]; m_windowBoundingBox = windowBoundingBox; m_windowPixelOneXY[0] = m_viewport[0] + viewportPixelOneXY[0]; m_windowPixelOneXY[1] = m_viewport[1] + viewportPixelOneXY[1]; m_windowPixelTwoXY[0] = m_viewport[0] + viewportPixelTwoXY[0]; m_windowPixelTwoXY[1] = m_viewport[1] + viewportPixelTwoXY[1]; m_windowPixelTwoXYValidFlag = viewportPixelTwoXYValidValid; if (m_windowPixelTwoXYValidFlag) { m_windowMidPointXY[0] = (m_windowPixelOneXY[0] + m_windowPixelTwoXY[0]) / 2.0; m_windowMidPointXY[1] = (m_windowPixelOneXY[1] + m_windowPixelTwoXY[1]) / 2.0; } else { m_windowMidPointXY[0] = m_windowPixelOneXY[0]; m_windowMidPointXY[1] = m_windowPixelOneXY[1]; } } /** * Is this XY coordinate a valid relative coordinate, * in the range [0.0, 100.0]? * * @return x * The x-coordinate * @param y * The y-coordinate * @return * True if valid relative coordinate, else false. */ bool AnnotationArrangerExecutor::AnnotationInfo::isValidRelativeCoord(const float x, const float y) const { if ((x >= 0.0) && (x <= 100.0) && (y >= 0.0) && (y <= 100.0)) { return true; } return false; } /** * Move the given annotation by the given amounts. * The annotation is moved only if its new coordinates * remain in the viewport. * * @return x * The x-coordinate * @param y * The y-coordinate * @return * True if annotation was moved, else false. */bool AnnotationArrangerExecutor::AnnotationInfo::moveAnnotationByXY(Annotation* annotation, const float dx, const float dy) const { CaretAssert(m_annotation); AnnotationOneDimensionalShape* oneDimAnn = dynamic_cast(annotation); AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(annotation); const float newPixelOneX = m_viewportPixelOneXY[0] + dx; const float relativeOneX = (newPixelOneX / m_viewport[2]) * 100.0; const float newPixelOneY = m_viewportPixelOneXY[1] + dy; const float relativeOneY = (newPixelOneY / m_viewport[3]) * 100.0; if (isValidRelativeCoord(relativeOneX, relativeOneY)) { if (twoDimAnn != NULL) { float xyz[3]; twoDimAnn->getCoordinate()->getXYZ(xyz); xyz[0] = relativeOneX; xyz[1] = relativeOneY; twoDimAnn->getCoordinate()->setXYZ(xyz); return true; } else if (oneDimAnn) { const float newPixelTwoX = m_viewportPixelTwoXY[0] + dx; const float relativeTwoX = (newPixelTwoX / m_viewport[2]) * 100.0; const float newPixelTwoY = m_viewportPixelTwoXY[1] + dy; const float relativeTwoY = (newPixelTwoY / m_viewport[3]) * 100.0; if (isValidRelativeCoord(relativeTwoX, relativeTwoY)) { float xyz[3]; oneDimAnn->getStartCoordinate()->getXYZ(xyz); xyz[0] = relativeOneX; xyz[1] = relativeOneY; oneDimAnn->getStartCoordinate()->setXYZ(xyz); oneDimAnn->getEndCoordinate()->getXYZ(xyz); xyz[0] = relativeTwoX; xyz[1] = relativeTwoY; oneDimAnn->getEndCoordinate()->setXYZ(xyz); return true; } } } return false; } /** * Print information used to arrange an annotation. */ void AnnotationArrangerExecutor::AnnotationInfo::print() const { QString msg(m_annotation->toString() + "\n Window One XY: " + AString::fromNumbers(m_windowPixelOneXY, 2, ",") + "\n Window Two XY: " + AString::fromNumbers(m_windowPixelTwoXY, 2, ",") + "\n Window Mid Point XY: " + AString::fromNumbers(m_windowMidPointXY, 2, ",") + "\n Viewport XY: " + AString::fromNumbers(m_viewportPixelOneXY, 2, ",") + "\n Viewport: " + AString::fromNumbers(m_viewport, 4, ",") + "\n Bounds: " + m_windowBoundingBox.toString()); std::cout << qPrintable(msg) << std::endl; } connectome-workbench-1.4.2/src/Brain/AnnotationArrangerExecutor.h000066400000000000000000000136271360521144700251520ustar00rootroot00000000000000#ifndef __ANNOTATION_ARRANGER_EXECUTOR_H__ #define __ANNOTATION_ARRANGER_EXECUTOR_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AnnotationAlignmentEnum.h" #include "AnnotationDistributeEnum.h" #include "BoundingBox.h" #include "CaretObject.h" #include "SpacerTabIndex.h" namespace caret { class Annotation; class AnnotationArrangerInputs; class AnnotationManager; class AnnotationArrangerExecutor : public CaretObject { public: AnnotationArrangerExecutor(); virtual ~AnnotationArrangerExecutor(); bool alignAnnotations(AnnotationManager* annotationManager, const AnnotationArrangerInputs& arrangerInputs, const AnnotationAlignmentEnum::Enum alignment, AString& errorMessageOut); bool distributeAnnotations(AnnotationManager* annotationManager, const AnnotationArrangerInputs& arrangerInputs, const AnnotationDistributeEnum::Enum distribute, AString& errorMessageOut); // ADD_NEW_METHODS_HERE virtual AString toString() const; private: enum Mode { MODE_NONE, MODE_ALIGN, MODE_DISTRIBUTE }; class AnnotationInfo { public: AnnotationInfo(Annotation* annotation, const int32_t viewport[4], const BoundingBox windowBoundingBox, float viewportPixelOneXY[2], float viewportPixelTwoXY[2], const bool viewportPixelTwoXYValidValid); bool isValidRelativeCoord(const float x, const float y) const; bool moveAnnotationByXY(Annotation* annotation, const float dx, const float dy) const; void print() const; Annotation* m_annotation; int32_t m_viewport[4]; float m_viewportPixelOneXY[2]; float m_viewportPixelTwoXY[2]; BoundingBox m_windowBoundingBox; float m_windowPixelOneXY[2]; float m_windowPixelTwoXY[2]; bool m_windowPixelTwoXYValidFlag; float m_windowMidPointXY[2]; }; class SortForDistributeFunctionObject { public: SortForDistributeFunctionObject(const AnnotationDistributeEnum::Enum distribute); bool operator()(const AnnotationInfo& ann1, const AnnotationInfo& ann2) const; private: const AnnotationDistributeEnum::Enum m_distribute; }; AnnotationArrangerExecutor(const AnnotationArrangerExecutor&); AnnotationArrangerExecutor& operator=(const AnnotationArrangerExecutor&); void alignAnnotationsPrivate(const AnnotationArrangerInputs& arrangerInputs); void distributeAnnotationsPrivate(const AnnotationArrangerInputs& arrangerInputs); void alignAnnotationToValue(const float alignToWindowCoordinateValue, AnnotationInfo& annotationInfo, std::vector& annotationsBeforeMoving, std::vector& annotationsAfterMoving); void getAnnotationsForArranging(const AnnotationArrangerInputs& arrangerInputs, std::vector& annotationsOut) const; void getSpacerTabViewport(const SpacerTabIndex& spacerTabIndex, int32_t tabViewportOut[4]); void getTabViewport(const int32_t tabIndex, int32_t tabViewportOut[4]); void initializeForArranging(const AnnotationArrangerInputs& arrangerInputs); void setupAnnotationInfo(const AnnotationArrangerInputs& arrangerInputs, std::vector& annotations); void printAnnotationInfo(const QString& title); Mode m_mode; AnnotationManager* m_annotationManager; int32_t m_windowViewport[4]; struct ViewportArray { int32_t m_viewport[4]; }; std::map m_tabViewports; BoundingBox m_allAnnotationsBoundingBox; std::vector m_annotationInfo; AnnotationAlignmentEnum::Enum m_alignment; AnnotationDistributeEnum::Enum m_distribute; bool m_debugFlag; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_ARRANGER_EXECUTOR_DECLARE__ // #endif // __ANNOTATION_ARRANGER_EXECUTOR_DECLARE__ } // namespace #endif //__ANNOTATION_ARRANGER_EXECUTOR_H__ connectome-workbench-1.4.2/src/Brain/AnnotationArrangerInputs.cxx000066400000000000000000000051111360521144700251760ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define ____ANNOTATION_ARRANGER_INPUTS__DECLARE__ #include "AnnotationArrangerInputs.h" #undef ____ANNOTATION_ARRANGER_INPUTS__DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationArrangerInputs * \brief Contains information for aligning, distributing annotations * \ingroup Brain */ /** * Constructor. * * @param textRenderInterface * Text render interface needed for bounds of text annotations. * @param alignment * Alignment to direction. * @param windowIndex * Index of window in which annotations are aligned. */ AnnotationArrangerInputs::AnnotationArrangerInputs(BrainOpenGLTextRenderInterface* textRenderInterface, const BrainOpenGLTextRenderInterface::DrawingFlags& drawingFlags, const int32_t windowIndex) : CaretObject(), m_textRenderInterface(textRenderInterface), m_drawingFlags(drawingFlags), m_windowIndex(windowIndex) { } /** * Destructor. */ AnnotationArrangerInputs::~AnnotationArrangerInputs() { } /** * @return Text renderer needed for text annotation sizing. */ BrainOpenGLTextRenderInterface* AnnotationArrangerInputs::getTextRender() const { return m_textRenderInterface; } /** * @return Reference to the drawing flags. */ const BrainOpenGLTextRenderInterface::DrawingFlags& AnnotationArrangerInputs::getDrawingFlags() const { return m_drawingFlags; } /** * @return The window index. */ int32_t AnnotationArrangerInputs::getWindowIndex() const { return m_windowIndex; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString AnnotationArrangerInputs::toString() const { return "AnnotationArrangerInputs"; } connectome-workbench-1.4.2/src/Brain/AnnotationArrangerInputs.h000066400000000000000000000044021360521144700246250ustar00rootroot00000000000000#ifndef __ANNOTATION_ARRANGER_INPUTS_H__ #define __ANNOTATION_ARRANGER_INPUTS_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainOpenGLTextRenderInterface.h" #include "CaretObject.h" namespace caret { class AnnotationArrangerInputs : public CaretObject { public: AnnotationArrangerInputs(BrainOpenGLTextRenderInterface* textRenderInterface, const BrainOpenGLTextRenderInterface::DrawingFlags& drawingFlags, const int32_t windowIndex); virtual ~AnnotationArrangerInputs(); BrainOpenGLTextRenderInterface* getTextRender() const; const BrainOpenGLTextRenderInterface::DrawingFlags& getDrawingFlags() const; int32_t getWindowIndex() const; // ADD_NEW_METHODS_HERE virtual AString toString() const; private: AnnotationArrangerInputs(const AnnotationArrangerInputs&); AnnotationArrangerInputs& operator=(const AnnotationArrangerInputs&); BrainOpenGLTextRenderInterface* m_textRenderInterface; const BrainOpenGLTextRenderInterface::DrawingFlags& m_drawingFlags; const int32_t m_windowIndex; // ADD_NEW_MEMBERS_HERE }; #ifdef ____ANNOTATION_ARRANGER_INPUTS__DECLARE__ // #endif // ____ANNOTATION_ARRANGER_INPUTS__DECLARE__ } // namespace #endif //__ANNOTATION_ARRANGER_INPUTS_H__ connectome-workbench-1.4.2/src/Brain/AnnotationManager.cxx000066400000000000000000001032751360521144700236160ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_MANAGER_DECLARE__ #include "AnnotationManager.h" #undef __ANNOTATION_MANAGER_DECLARE__ #include "Annotation.h" #include "AnnotationArrangerExecutor.h" #include "AnnotationColorBar.h" #include "AnnotationFile.h" #include "AnnotationGroup.h" #include "AnnotationOneDimensionalShape.h" #include "AnnotationRedoUndoCommand.h" #include "AnnotationEditingSelectionInformation.h" #include "AnnotationTwoDimensionalShape.h" #include "Brain.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretUndoStack.h" #include "DisplayPropertiesAnnotation.h" #include "EventAnnotationChartLabelGet.h" #include "EventAnnotationColorBarGet.h" #include "EventAnnotationGroupGetWithKey.h" #include "EventGetDisplayedDataFiles.h" #include "EventManager.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::AnnotationManager * \brief Manager for annotations. * \ingroup Brain */ /** * Constructor. */ AnnotationManager::AnnotationManager(Brain* brain) : CaretObject(), m_brain(brain) { CaretAssert(m_brain); m_clipboardAnnotationFile = NULL; m_clipboardAnnotation.grabNew(NULL); m_annotationRedoUndoStack.grabNew(new CaretUndoStack()); m_annotationRedoUndoStack->setUndoLimit(500); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS; i++) { m_annotationBeingDrawnInWindow[i] = NULL; m_selectionInformation[i] = new AnnotationEditingSelectionInformation(i); } m_sceneAssistant = new SceneClassAssistant(); } /** * Destructor. */ AnnotationManager::~AnnotationManager() { EventManager::get()->removeAllEventsFromListener(this); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS; i++) { if (m_annotationBeingDrawnInWindow[i] != NULL) { delete m_annotationBeingDrawnInWindow[i]; } delete m_selectionInformation[i]; } m_annotationRedoUndoStack->clear(); delete m_sceneAssistant; } /** * Reset the annotation manager. */ void AnnotationManager::reset() { m_annotationRedoUndoStack->clear(); } /** * Apply a new command to the selected annotations. After execution of * the command, the command is placed on the undo stack so that the * user can undo or redo the command. * * @param command * Command that will be applied to the selected annotations. * Annotation manager will take ownership of the command and * destroy it at the appropriate time. */ bool AnnotationManager::applyCommand(AnnotationRedoUndoCommand* command, AString& errorMessageOut) { return applyCommandInWindow(command, -1, errorMessageOut); } /** * Apply a new command to the selected annotations. After execution of * the command, the command is placed on the undo stack so that the * user can undo or redo the command. * * @param command * Command that will be applied to the selected annotations. * Annotation manager will take ownership of the command and * destroy it at the appropriate time. * @param windowIndex * Index of window in which command was requested. */ bool AnnotationManager::applyCommandInWindow(AnnotationRedoUndoCommand* command, const int32_t windowIndex, AString& errorMessageOut) { errorMessageOut.clear(); CaretAssert(command); /* * Ignore command if it does not apply to any annotations */ if ( ! command->isValid()) { delete command; errorMessageOut = "Command was not valid."; return false; } /* * "Redo" the command and add it to the undo stack */ const bool result = m_annotationRedoUndoStack->pushAndRedo(command, windowIndex, errorMessageOut); return result; } /** * Deselect all annotations for editing in the given window. * * @param windowIndex * Index of window for deselection of window annotations. */ void AnnotationManager::deselectAllAnnotationsForEditing(const int32_t windowIndex) { std::vector annotationFiles; m_brain->getAllAnnotationFilesIncludingSceneAnnotationFile(annotationFiles); for (std::vector::iterator fileIter = annotationFiles.begin(); fileIter != annotationFiles.end(); fileIter++) { AnnotationFile* file = *fileIter; CaretAssert(file); file->setAllAnnotationsSelectedForEditing(windowIndex, false); } EventAnnotationColorBarGet colorBarEvent; EventManager::get()->sendEvent(colorBarEvent.getPointer()); std::vector colorBars = colorBarEvent.getAnnotationColorBars(); for (std::vector::iterator iter = colorBars.begin(); iter != colorBars.end(); iter++) { AnnotationColorBar* cb = *iter; cb->setSelectedForEditing(windowIndex, false); } EventAnnotationChartLabelGet chartLabelEvent; EventManager::get()->sendEvent(chartLabelEvent.getPointer()); std::vector chartLabels = chartLabelEvent.getAnnotationChartLabels(); for (auto label : chartLabels) { label->setSelectedForEditing(windowIndex, false); } } /** * Select the given annotation for editing using the given mode. * * @param windowIndex * Index of window for annotation selection. * @param selectionMode * The annotation selection mode. * @param shiftKeyDown * The shift key is down * @param selectedAnnotation * Annotation whose selection is updated. * May be NULL. */ void AnnotationManager::selectAnnotationForEditing(const int32_t windowIndex, const SelectionMode selectionMode, const bool shiftKeyDownFlag, Annotation* selectedAnnotation) { switch (selectionMode) { case SELECTION_MODE_EXTENDED: processExtendedModeSelectionForEditing(windowIndex, shiftKeyDownFlag, selectedAnnotation); break; case SELECTION_MODE_SINGLE: processSingleModeSelectionForEditing(windowIndex, selectedAnnotation); break; } /* * If the annotation is in a user group, select all * annotations in the group. */ if (selectedAnnotation != NULL) { const bool selectedStatus = selectedAnnotation->isSelectedForEditing(windowIndex); const AnnotationGroupKey groupKey = selectedAnnotation->getAnnotationGroupKey(); if (groupKey.getGroupType() == AnnotationGroupTypeEnum::USER) { EventAnnotationGroupGetWithKey getGroupEvent(groupKey); EventManager::get()->sendEvent(getGroupEvent.getPointer()); AnnotationGroup* annotationGroup = getGroupEvent.getAnnotationGroup(); if (annotationGroup != NULL) { annotationGroup->setAllAnnotationsSelectedForEditing(windowIndex, selectedStatus); } } } } /** * Set the annotations for editing to the given annotations in the given window. * * @param windowIndex * Index of window for annotation selection. * @param selectedAnnotations * Annotation that become the selected annotations. */ void AnnotationManager::setAnnotationsForEditing(const int32_t windowIndex, const std::vector& selectedAnnotations) { deselectAllAnnotationsForEditing(windowIndex); std::set uniqueAnnotationsSet; for (std::vector::const_iterator annIter = selectedAnnotations.begin(); annIter != selectedAnnotations.end(); annIter++) { Annotation* ann = *annIter; CaretAssert(ann); const AnnotationGroupKey groupKey = ann->getAnnotationGroupKey(); if (groupKey.getGroupType() == AnnotationGroupTypeEnum::USER) { EventAnnotationGroupGetWithKey getGroupEvent(groupKey); EventManager::get()->sendEvent(getGroupEvent.getPointer()); AnnotationGroup* annotationGroup = getGroupEvent.getAnnotationGroup(); if (annotationGroup != NULL) { std::vector groupAnns; annotationGroup->getAllAnnotations(groupAnns); uniqueAnnotationsSet.insert(groupAnns.begin(), groupAnns.end()); } } else { uniqueAnnotationsSet.insert(ann); } } for (std::set::iterator annIter = uniqueAnnotationsSet.begin(); annIter != uniqueAnnotationsSet.end(); annIter++) { Annotation* ann = *annIter; ann->setSelectedForEditing(windowIndex, true); } } /** * Process extended mode annotation selection for editing. * * @param windowIndex * Index of window for annotation selection. * @param shiftKeyDownFlag * True if the shift key is down. * @param selectedAnnotation * Annotation that was selected (NULL if no annotation selected). */ void AnnotationManager::processExtendedModeSelectionForEditing(const int32_t windowIndex, const bool shiftKeyDownFlag, Annotation* selectedAnnotation) { if (selectedAnnotation != NULL) { if (shiftKeyDownFlag) { /* * When shift key is down, the annotation's selection status * is toggled */ selectedAnnotation->setSelectedForEditing(windowIndex, ! selectedAnnotation->isSelectedForEditing(windowIndex)); } else { if (selectedAnnotation->isSelectedForEditing(windowIndex)) { /* cannot deselect an annotation WITHOUT shift key down */ } else { /* * Clicking an annotation without shift key selects the * annotation but deselects all other annotations. */ deselectAllAnnotationsForEditing(windowIndex); selectedAnnotation->setSelectedForEditing(windowIndex, true); } } } else { if (shiftKeyDownFlag) { /* do nothing with shift key down and no annotation clicked */ } else { deselectAllAnnotationsForEditing(windowIndex); } } } /** * Process single mode annotation selection for editing. * * @param windowIndex * Index of window for annotation selection. * @param selectedAnnotation * Annotation that was selected (NULL if no annotation selected). */ void AnnotationManager::processSingleModeSelectionForEditing(const int32_t windowIndex, Annotation* selectedAnnotation) { deselectAllAnnotationsForEditing(windowIndex); if (selectedAnnotation != NULL) { selectedAnnotation->setSelectedForEditing(windowIndex, true); } } /** * @return True if all of the selected annotations for editing are deletable. * * @param windowIndex * Index of window for annotation selection. */ bool AnnotationManager::isAnnotationSelectedForEditingDeletable(const int32_t windowIndex) const { bool selectedAnnotationsDeletableFlag = false; std::vector selectedAnnotations = getAnnotationsSelectedForEditing(windowIndex); if ( ! selectedAnnotations.empty()) { selectedAnnotationsDeletableFlag = true; for (std::vector::const_iterator iter = selectedAnnotations.begin(); iter != selectedAnnotations.end(); iter++) { const Annotation* ann = *iter; if ( ! ann->testProperty(Annotation::Property::DELETION)) { selectedAnnotationsDeletableFlag = false; break; } } } return selectedAnnotationsDeletableFlag; } /** * @return A vector containing all annotations. */ std::vector AnnotationManager::getAllAnnotations() const { std::vector annotationFiles; m_brain->getAllAnnotationFilesIncludingSceneAnnotationFile(annotationFiles); std::vector allAnnotations; for (std::vector::iterator fileIter = annotationFiles.begin(); fileIter != annotationFiles.end(); fileIter++) { AnnotationFile* file = *fileIter; CaretAssert(file); std::vector annotations; file->getAllAnnotations(annotations); if ( ! annotations.empty()) { allAnnotations.insert(allAnnotations.end(), annotations.begin(), annotations.end()); } } EventAnnotationColorBarGet colorBarEvent; EventManager::get()->sendEvent(colorBarEvent.getPointer()); std::vector colorBars = colorBarEvent.getAnnotationColorBars(); for (std::vector::iterator iter = colorBars.begin(); iter != colorBars.end(); iter++) { allAnnotations.push_back(*iter); } EventAnnotationChartLabelGet chartLabelEvent; EventManager::get()->sendEvent(chartLabelEvent.getPointer()); std::vector chartLabels = chartLabelEvent.getAnnotationChartLabels(); allAnnotations.insert(allAnnotations.end(), chartLabels.begin(), chartLabels.end()); return allAnnotations; } /** * Get the annotation editing selection information for the given window. * * @param windowIndex * Index of window. * @return * Annotation selection information. */ const AnnotationEditingSelectionInformation* AnnotationManager::getAnnotationEditingSelectionInformation(const int32_t windowIndex) const { CaretAssertArrayIndex(m_selectionInformation, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, windowIndex); AnnotationEditingSelectionInformation* asi = m_selectionInformation[windowIndex]; std::vector allAnnotations = getAllAnnotations(); std::vector selectedAnnotations; for (std::vector::iterator annIter = allAnnotations.begin(); annIter != allAnnotations.end(); annIter++) { Annotation* annotation = *annIter; if (annotation->isSelectedForEditing(windowIndex)) { selectedAnnotations.push_back(annotation); } } asi->update(selectedAnnotations); return asi; } /** * @return A vector containing all SELECTED annotations for editing * * @param windowIndex * Index of window for annotation selection. */ std::vector AnnotationManager::getAnnotationsSelectedForEditing(const int32_t windowIndex) const { std::vector selectedAnnotations; const AnnotationEditingSelectionInformation* asi = getAnnotationEditingSelectionInformation(windowIndex); asi->getAnnotationsSelectedForEditing(selectedAnnotations); return selectedAnnotations; } /** * @return A vector containing all SELECTED annotations for editing and in the * given spaces. * * @param windowIndex * Index of window for annotation selection. * @param spaces * Limit returned annotations to annotations in these spaces. */ std::vector AnnotationManager::getAnnotationsSelectedForEditingInSpaces(const int32_t windowIndex, const std::vector& spaces) const { std::vector annotations = getAnnotationsSelectedForEditing(windowIndex); std::vector annotationsOut; for (std::vector::iterator iter = annotations.begin(); iter != annotations.end(); iter++) { Annotation* ann = *iter; CaretAssert(ann); const AnnotationCoordinateSpaceEnum::Enum annSpace = ann->getCoordinateSpace(); if (std::find(spaces.begin(), spaces.end(), annSpace) != spaces.end()) { annotationsOut.push_back(ann); } } return annotationsOut; } /** * Get the selected annotations for editing and the files that contain them. * * @param windowIndex * Index of window for annotation selection. * @param annotationsAndFileOut * A 'pair' containing a selected annotation and the file that contains the annotation. */ void AnnotationManager::getAnnotationsSelectedForEditing(const int32_t windowIndex, std::vector >& annotationsAndFileOut) const { annotationsAndFileOut.clear(); std::vector annotationFiles; m_brain->getAllAnnotationFilesIncludingSceneAnnotationFile(annotationFiles); for (std::vector::iterator fileIter = annotationFiles.begin(); fileIter != annotationFiles.end(); fileIter++) { AnnotationFile* file = *fileIter; CaretAssert(file); std::vector annotations; file->getAllAnnotations(annotations); for (std::vector::iterator annIter = annotations.begin(); annIter != annotations.end(); annIter++) { Annotation* ann = *annIter; if (ann->isSelectedForEditing(windowIndex)) { annotationsAndFileOut.push_back(std::make_pair(ann, file)); } } } } /** * Get the selected annotations for editing and the files that contain them. * INCLUDES chart labels. * * @param windowIndex * Index of window for annotation selection. * @param annotationsAndFileOut * A 'pair' containing a selected annotation and the file that contains the annotation. */ void AnnotationManager::getAnnotationsSelectedForEditingIncludingLabels(const int32_t windowIndex, std::vector >& annotationsAndFileOut) const { getAnnotationsSelectedForEditing(windowIndex, annotationsAndFileOut); EventAnnotationChartLabelGet chartLabelEvent; EventManager::get()->sendEvent(chartLabelEvent.getPointer()); std::vector chartLabels = chartLabelEvent.getAnnotationChartLabels(); AnnotationFile* nullFile = NULL; for (auto cl : chartLabels) { if (cl->isSelectedForEditing(windowIndex)) { annotationsAndFileOut.push_back(std::make_pair(cl, nullFile)); } } } /** * Align annotations. * * @param arrangerInputs * Inputs to algorithm that aligns the annotations. * @param errorMessageOut * Contains error message upon exit. * @return * True if successful, false if error. */ bool AnnotationManager::alignAnnotations(const AnnotationArrangerInputs& arrangerInputs, const AnnotationAlignmentEnum::Enum alignment, AString& errorMessageOut) { AnnotationArrangerExecutor arranger; return arranger.alignAnnotations(this, arrangerInputs, alignment, errorMessageOut); } /** * Align annotations. * * @param arrangerInputs * Inputs to algorithm that aligns the annotations. * @param errorMessageOut * Contains error message upon exit. * @return * True if successful, false if error. */ bool AnnotationManager::distributeAnnotations(const AnnotationArrangerInputs& arrangerInputs, const AnnotationDistributeEnum::Enum distribute, AString& errorMessageOut) { AnnotationArrangerExecutor arranger; return arranger.distributeAnnotations(this, arrangerInputs, distribute, errorMessageOut); } /** * Apply given grouping mode valid in the given window. * * @param windowIndex * Index of the window. * @param groupingMode * The grouping mode. * @param errorMessageOut * Contains error message if grouping fails. * @return * True if successful, else false. */ bool AnnotationManager::applyGroupingMode(const int32_t windowIndex, const AnnotationGroupingModeEnum::Enum groupingMode, AString& errorMessageOut) { errorMessageOut.clear(); const AnnotationEditingSelectionInformation* selectionInfo = getAnnotationEditingSelectionInformation(windowIndex); CaretAssert(selectionInfo); if ( ! selectionInfo->isGroupingModeValid(groupingMode)) { const QString msg("PROGRAM ERROR: AnnotationMenuArrange::applyGrouping " "should not have been called. Grouping mode " + AnnotationGroupingModeEnum::toGuiName(groupingMode) + " is invalid for the selected annotations."); CaretAssertMessage(0, msg); errorMessageOut = msg; return false; } std::vector groupKeys = selectionInfo->getSelectedAnnotationGroupKeys(); std::vector annotations = selectionInfo->getAnnotationsSelectedForEditing(); bool validFlag = false; switch (groupingMode) { case AnnotationGroupingModeEnum::GROUP: { if (groupKeys.size() != 1) { const QString msg("PROGRAM ERROR: AnnotationMenuArrange::applyGrouping " "should not have been called. More than one selected group."); CaretAssertMessage(0, msg); errorMessageOut = msg; return false; } CaretAssertVectorIndex(groupKeys, 0); const AnnotationGroupKey annotationGroupKey = groupKeys[0]; AnnotationRedoUndoCommand* command = new AnnotationRedoUndoCommand(); command->setModeGroupingGroupAnnotations(annotationGroupKey, annotations); validFlag = applyCommandInWindow(command, windowIndex, errorMessageOut); } break; case AnnotationGroupingModeEnum::REGROUP: { if (groupKeys.size() != 1) { const QString msg("PROGRAM ERROR: AnnotationMenuArrange::applyGrouping " "should not have been called. More than one selected group."); CaretAssertMessage(0, msg); errorMessageOut = msg; return false; } CaretAssertVectorIndex(groupKeys, 0); const AnnotationGroupKey annotationGroupKey = groupKeys[0]; AnnotationRedoUndoCommand* command = new AnnotationRedoUndoCommand(); command->setModeGroupingRegroupAnnotations(annotationGroupKey); validFlag = applyCommandInWindow(command, windowIndex, errorMessageOut); } break; case AnnotationGroupingModeEnum::UNGROUP: { if (groupKeys.size() != 1) { const QString msg("PROGRAM ERROR: AnnotationMenuArrange::applyGrouping " "should not have been called. More than one selected group."); CaretAssertMessage(0, msg); errorMessageOut = msg; return false; } CaretAssertVectorIndex(groupKeys, 0); const AnnotationGroupKey annotationGroupKey = groupKeys[0]; AnnotationRedoUndoCommand* command = new AnnotationRedoUndoCommand(); command->setModeGroupingUngroupAnnotations(annotationGroupKey); validFlag = applyCommandInWindow(command, windowIndex, errorMessageOut); } break; } return validFlag; } /** * Is the given grouping mode valid in the given window. * * @param windowIndex * Index of the window. * @param groupingMode * The grouping mode. */ bool AnnotationManager::isGroupingModeValid(const int32_t windowIndex, const AnnotationGroupingModeEnum::Enum groupingMode) const { return getAnnotationEditingSelectionInformation(windowIndex)->isGroupingModeValid(groupingMode); } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void AnnotationManager::receiveEvent(Event* /*event*/) { } /** * Get a description of this object's content. * @return String describing this object's content. */ AString AnnotationManager::toString() const { return "AnnotationManager"; } /** * @return True if there is an annotation on the clipboard. */ bool AnnotationManager::isAnnotationOnClipboardValid() const { return (m_clipboardAnnotation != NULL); } /** * @return Pointer to annotation file on clipboard. * If there is not annotation file on the clipboard, * NULL is returned. */ AnnotationFile* AnnotationManager::getAnnotationFileOnClipboard() const { if (m_clipboardAnnotationFile != NULL) { /* * It is possible that the file has been destroyed. * If so, invalidate the file (set it to NULL). */ std::vector allAnnotationFiles; m_brain->getAllAnnotationFilesIncludingSceneAnnotationFile(allAnnotationFiles); if (std::find(allAnnotationFiles.begin(), allAnnotationFiles.end(), m_clipboardAnnotationFile) == allAnnotationFiles.end()) { m_clipboardAnnotationFile = NULL; } } return m_clipboardAnnotationFile; } /** * @return Pointer to annotation on clipboard. * If there is not annotation on the clipboard, * NULL is returned. */ const Annotation* AnnotationManager::getAnnotationOnClipboard() const { return m_clipboardAnnotation; } /** * @return A copy of the annotation on the clipboard. * If there is not annotation on the clipboard, * NULL is returned. */ Annotation* AnnotationManager::getCopyOfAnnotationOnClipboard() const { if (m_clipboardAnnotation != NULL) { return m_clipboardAnnotation->clone(); } return NULL; } void AnnotationManager::copyAnnotationToClipboard(const AnnotationFile* annotationFile, const Annotation* annotation) { m_clipboardAnnotationFile = const_cast(annotationFile); m_clipboardAnnotation.grabNew(annotation->clone()); } /** * Get the annotation being drawn in window with the given window index. * * @param windowIndex * Index of window. * @return * Pointer to the annotation (will be NULL if no annotation is being drawn). */ const Annotation* AnnotationManager::getAnnotationBeingDrawnInWindow(const int32_t windowIndex) const { CaretAssertArrayIndex(m_annotationBeingDrawnInWindow, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, windowIndex); return m_annotationBeingDrawnInWindow[windowIndex]; } /** * Set the annotation being drawn in window with the given window index. * * @param windowIndex * Index of window. * @param annotation * Pointer to the annotation (will be NULL if no annotation is being drawn). */ void AnnotationManager::setAnnotationBeingDrawnInWindow(const int32_t windowIndex, const Annotation* annotation) { CaretAssertArrayIndex(m_annotationBeingDrawnInWindow, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, windowIndex); if (m_annotationBeingDrawnInWindow[windowIndex] != NULL) { delete m_annotationBeingDrawnInWindow[windowIndex]; m_annotationBeingDrawnInWindow[windowIndex] = NULL; } if (annotation != NULL) { m_annotationBeingDrawnInWindow[windowIndex] = annotation->clone(); } } /** * Find annotation files that are displayed. * * @param displayedFilesEvent * Event that queries for displayed data files. * @param displayedAnnotationFilesOut * Output that contains annotation files that are displayed. */ void AnnotationManager::getDisplayedAnnotationFiles(EventGetDisplayedDataFiles* displayedFilesEvent, std::vector& displayedAnnotationFilesOut) const { displayedAnnotationFilesOut.clear(); const std::vector tabIndices = displayedFilesEvent->getTabIndices(); std::vector annotationFiles; m_brain->getAllAnnotationFilesIncludingSceneAnnotationFile(annotationFiles); const int32_t numAnnFiles = static_cast(annotationFiles.size()); for (int32_t iFile = 0; iFile < numAnnFiles; iFile++) { CaretAssertVectorIndex(annotationFiles, iFile); const AnnotationFile* annFile = annotationFiles[iFile]; std::vector annotations; annFile->getAllAnnotations(annotations); const int32_t numberOfAnnotations = static_cast(annotations.size()); for (int32_t i = 0; i < numberOfAnnotations; i++) { CaretAssertVectorIndex(annotations, i); const Annotation* ann = annotations[i]; CaretAssert(ann); bool displayedFlag = false; switch (ann->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: displayedFlag = true; break; case AnnotationCoordinateSpaceEnum::SPACER: displayedFlag = true; break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: displayedFlag = true; break; case AnnotationCoordinateSpaceEnum::SURFACE: displayedFlag = true; break; case AnnotationCoordinateSpaceEnum::TAB: displayedFlag = true; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: displayedFlag = true; break; } if (displayedFlag) { displayedFilesEvent->addDisplayedDataFile(annFile); break; } } } } /** * @return Pointer to the command redo undo stack */ CaretUndoStack* AnnotationManager::getCommandRedoUndoStack() { return m_annotationRedoUndoStack; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* AnnotationManager::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "AnnotationManager", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void AnnotationManager::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Brain/AnnotationManager.h000066400000000000000000000217311360521144700232370ustar00rootroot00000000000000#ifndef __ANNOTATION_MANAGER_H__ #define __ANNOTATION_MANAGER_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationAlignmentEnum.h" #include "AnnotationCoordinateSpaceEnum.h" #include "AnnotationDistributeEnum.h" #include "AnnotationGroupingModeEnum.h" #include "BrainConstants.h" #include "CaretObject.h" #include "CaretUndoCommand.h" #include "CaretPointer.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" namespace caret { class Annotation; class AnnotationArrangerInputs; class AnnotationFile; class AnnotationGroupKey; class AnnotationRedoUndoCommand; class AnnotationEditingSelectionInformation; class Brain; class CaretUndoStack; class EventGetDisplayedDataFiles; class SceneClassAssistant; class AnnotationManager : public CaretObject, public EventListenerInterface, public SceneableInterface { public: /** * Selection mode with the comments and functionality similar to QAbstractItemView::SelectionMode */ enum SelectionMode { /* * When the user selects an annotation, any already-selected annotation becomes unselected, * and the user cannot unselect the selected annotation by clicking on it. */ SELECTION_MODE_SINGLE, /** * When the user selects an annotation in the usual way, the selection is cleared * and the new annotation selected. However, if the user presses the Ctrl key when * clicking on an annotation, the clicked annotation gets toggled and all other annotation * are left untouched. */ SELECTION_MODE_EXTENDED }; AnnotationManager(Brain* brain); virtual ~AnnotationManager(); bool applyCommand(AnnotationRedoUndoCommand* command, AString& errorMessageOut); bool applyCommandInWindow(AnnotationRedoUndoCommand* command, const int32_t windowIndex, AString& errorMessageOut); void reset(); void deselectAllAnnotationsForEditing(const int32_t windowIndex); void selectAnnotationForEditing(const int32_t windowIndex, const SelectionMode selectionMode, const bool shiftKeyDownFlag, Annotation* selectedAnnotation); void setAnnotationsForEditing(const int32_t windowIndex, const std::vector& selectedAnnotations); bool isAnnotationSelectedForEditingDeletable(const int32_t windowIndex) const; std::vector getAllAnnotations() const; const AnnotationEditingSelectionInformation* getAnnotationEditingSelectionInformation(const int32_t windowIndex) const; std::vector getAnnotationsSelectedForEditing(const int32_t windowIndex) const; std::vector getAnnotationsSelectedForEditingInSpaces(const int32_t windowIndex, const std::vector& spaces) const; void getAnnotationsSelectedForEditing(const int32_t windowIndex, std::vector >& annotationsAndFileOut) const; void getAnnotationsSelectedForEditingIncludingLabels(const int32_t windowIndex, std::vector >& annotationsAndFileOut) const; bool isAnnotationOnClipboardValid() const; AnnotationFile* getAnnotationFileOnClipboard() const; const Annotation* getAnnotationOnClipboard() const; Annotation* getCopyOfAnnotationOnClipboard() const; void copyAnnotationToClipboard(const AnnotationFile* annotationFile, const Annotation* annotation); const Annotation* getAnnotationBeingDrawnInWindow(const int32_t windowIndex) const; void setAnnotationBeingDrawnInWindow(const int32_t windowIndex, const Annotation* annotation); CaretUndoStack* getCommandRedoUndoStack(); void getDisplayedAnnotationFiles(EventGetDisplayedDataFiles* displayedFilesEvent, std::vector& displayedAnnotationFilesOut) const; bool alignAnnotations(const AnnotationArrangerInputs& arrangerInputs, const AnnotationAlignmentEnum::Enum alignment, AString& errorMessageOut); bool distributeAnnotations(const AnnotationArrangerInputs& arrangerInputs, const AnnotationDistributeEnum::Enum distribute, AString& errorMessageOut); bool applyGroupingMode(const int32_t windowIndex, const AnnotationGroupingModeEnum::Enum groupingMode, AString& errorMessageOut); bool isGroupingModeValid(const int32_t windowIndex, const AnnotationGroupingModeEnum::Enum groupingMode) const; // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual void receiveEvent(Event* event); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implemetation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: AnnotationManager(const AnnotationManager&); AnnotationManager& operator=(const AnnotationManager&); void processExtendedModeSelectionForEditing(const int32_t windowIndex, const bool shiftKeyDownFlag, Annotation* selectedAnnotation); void processSingleModeSelectionForEditing(const int32_t windowIndex, Annotation* selectedAnnotation); SceneClassAssistant* m_sceneAssistant; /** Brain owning this manager */ Brain* m_brain; Annotation* m_annotationBeingDrawnInWindow[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS]; /* * DO NOT directly reference this. Instead, call this class' * getAnnotationEditingSelectionInformation() method so that the selection * information is updated. */ mutable AnnotationEditingSelectionInformation* m_selectionInformation[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS]; /** * Do not use a Caret Pointer for this as it points to a file in the brain. * If a pointer was used it may get deleted which will cause deletion of the * file that is owned by the Brain. */ mutable AnnotationFile* m_clipboardAnnotationFile; CaretPointer m_clipboardAnnotation; CaretPointer m_annotationRedoUndoStack; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_MANAGER_DECLARE__ // #endif // __ANNOTATION_MANAGER_DECLARE__ } // namespace #endif //__ANNOTATION_MANAGER_H__ connectome-workbench-1.4.2/src/Brain/BorderDrawingTypeEnum.cxx000066400000000000000000000231641360521144700244270ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __BORDER_DRAWING_TYPE_ENUM_DECLARE__ #include "BorderDrawingTypeEnum.h" #undef __BORDER_DRAWING_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::BorderDrawingTypeEnum * \brief Enumerated type for border drawing */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ BorderDrawingTypeEnum::BorderDrawingTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ BorderDrawingTypeEnum::~BorderDrawingTypeEnum() { } /** * Initialize the enumerated metadata. */ void BorderDrawingTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(BorderDrawingTypeEnum(DRAW_AS_LINES, "DRAW_AS_LINES", "Lines")); enumData.push_back(BorderDrawingTypeEnum(DRAW_AS_POLYLINES, "DRAW_AS_POLYLINES", "Polylines")); enumData.push_back(BorderDrawingTypeEnum(DRAW_AS_POINTS_SPHERES, "DRAW_AS_POINTS_SPHERES", "Spheres")); enumData.push_back(BorderDrawingTypeEnum(DRAW_AS_POINTS_SQUARES, "DRAW_AS_POINTS_SQUARES", "Squares")); enumData.push_back(BorderDrawingTypeEnum(DRAW_AS_POINTS_AND_LINES, "DRAW_AS_POINTS_AND_LINES", "Spheres and Lines")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const BorderDrawingTypeEnum* BorderDrawingTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const BorderDrawingTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString BorderDrawingTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const BorderDrawingTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ BorderDrawingTypeEnum::Enum BorderDrawingTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = DRAW_AS_LINES; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const BorderDrawingTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type BorderDrawingTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString BorderDrawingTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const BorderDrawingTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ BorderDrawingTypeEnum::Enum BorderDrawingTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = DRAW_AS_LINES; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const BorderDrawingTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type BorderDrawingTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t BorderDrawingTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const BorderDrawingTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ BorderDrawingTypeEnum::Enum BorderDrawingTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = DRAW_AS_LINES; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const BorderDrawingTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type BorderDrawingTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void BorderDrawingTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void BorderDrawingTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(BorderDrawingTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void BorderDrawingTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(BorderDrawingTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Brain/BorderDrawingTypeEnum.h000066400000000000000000000065521360521144700240560ustar00rootroot00000000000000#ifndef __BORDER_DRAWING_TYPE_ENUM__H_ #define __BORDER_DRAWING_TYPE_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class BorderDrawingTypeEnum { public: /** * Enumerated values for border drawing types. */ enum Enum { /** draw as lines */ DRAW_AS_LINES, /** draw as lines but thicker and slower */ DRAW_AS_POLYLINES, /** draw as spherical points */ DRAW_AS_POINTS_SPHERES, /** draw as square points */ DRAW_AS_POINTS_SQUARES, /** draw as points and lines */ DRAW_AS_POINTS_AND_LINES }; ~BorderDrawingTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: BorderDrawingTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const BorderDrawingTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __BORDER_DRAWING_TYPE_ENUM_DECLARE__ std::vector BorderDrawingTypeEnum::enumData; bool BorderDrawingTypeEnum::initializedFlag = false; int32_t BorderDrawingTypeEnum::integerCodeCounter = 0; #endif // __BORDER_DRAWING_TYPE_ENUM_DECLARE__ } // namespace #endif //__BORDER_DRAWING_TYPE_ENUM__H_ connectome-workbench-1.4.2/src/Brain/Brain.cxx000066400000000000000000010004701360521144700212360ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include "CaretAssert.h" #include "AnnotationFile.h" #include "AnnotationManager.h" #include "AnnotationTextSubstitutionFile.h" #include "Border.h" #include "BorderFile.h" #include "BorderPointFromSearch.h" #include "Brain.h" #include "BrainordinateRegionOfInterest.h" #include "BrainStructure.h" #include "BrowserTabContent.h" #include "CaretDataFileHelper.h" #include "CaretLogger.h" #include "CaretPreferences.h" #include "ChartingDataManager.h" #include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileMatrixChart.h" #include "ChartableLineSeriesBrainordinateInterface.h" #include "CiftiBrainordinateDataSeriesFile.h" #include "CiftiBrainordinateLabelFile.h" #include "CiftiBrainordinateScalarFile.h" #include "CiftiConnectivityMatrixDenseFile.h" #include "CiftiConnectivityMatrixDenseDynamicFile.h" #include "CiftiConnectivityMatrixDenseParcelFile.h" #include "CiftiFiberOrientationFile.h" #include "CiftiFiberTrajectoryFile.h" #include "CiftiConnectivityMatrixParcelFile.h" #include "CiftiConnectivityMatrixParcelDenseFile.h" #include "CiftiParcelLabelFile.h" #include "CiftiParcelSeriesFile.h" #include "CiftiParcelScalarFile.h" #include "CiftiScalarDataSeriesFile.h" #include "DisplayPropertiesAnnotation.h" #include "DisplayPropertiesAnnotationTextSubstitution.h" #include "DisplayPropertiesBorders.h" #include "DisplayPropertiesFiberOrientation.h" #include "DisplayPropertiesFoci.h" #include "DisplayPropertiesImages.h" #include "DisplayPropertiesLabels.h" #include "DisplayPropertiesSurface.h" #include "DisplayPropertiesVolume.h" #include "ElapsedTimer.h" #include "EventAnnotationTextSubstitutionInvalidate.h" #include "EventBrainReset.h" #include "EventBrowserTabGetAll.h" #include "EventCaretMappableDataFilesGet.h" #include "EventDataFileAdd.h" #include "EventDataFileDelete.h" #include "EventDataFileRead.h" #include "EventDataFileReload.h" #include "EventCaretDataFilesGet.h" #include "EventGetDisplayedDataFiles.h" #include "EventModelAdd.h" #include "EventModelDelete.h" #include "EventModelGetAll.h" #include "EventModelGetAllDisplayed.h" #include "EventPaletteGetByName.h" #include "EventProgressUpdate.h" #include "EventSceneActive.h" #include "EventSpecFileReadDataFiles.h" #include "EventManager.h" #include "FiberOrientationSamplesLoader.h" #include "FileInformation.h" #include "FociFile.h" #include "GapsAndMargins.h" #include "GroupAndNameHierarchyModel.h" #include "IdentificationManager.h" #include "ImageFile.h" #include "MathFunctions.h" #include "MetricDynamicConnectivityFile.h" #include "MetricFile.h" #include "ModelChart.h" #include "ModelChartTwo.h" #include "ModelSurface.h" #include "ModelSurfaceMontage.h" #include "ModelVolume.h" #include "ModelWholeBrain.h" #include "LabelFile.h" #include "Overlay.h" #include "OverlaySet.h" #include "PaletteFile.h" #include "RgbaFile.h" #include "Scene.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneClassAssistant.h" #include "SceneFile.h" #include "SelectionManager.h" #include "SessionManager.h" #include "SpecFile.h" #include "SpecFileDataFile.h" #include "SpecFileDataFileTypeGroup.h" #include "Surface.h" #include "SurfaceProjectedItem.h" #include "SystemUtilities.h" #include "VolumeDynamicConnectivityFile.h" #include "VolumeFile.h" #include "VolumeSurfaceOutlineSetModel.h" using namespace caret; /** * Constructor. * * @param caretPreferences * The caret preferencers used to initialize some components. */ Brain::Brain(const CaretPreferences* caretPreferences) { m_annotationManager = new AnnotationManager(this); m_chartingDataManager = new ChartingDataManager(this); m_fiberOrientationSamplesLoader = new FiberOrientationSamplesLoader(); m_paletteFile = new PaletteFile(); m_paletteFile->setFileName(convertFilePathNameToAbsolutePathName(m_paletteFile->getFileName())); m_paletteFile->clearModified(); m_specFile = new SpecFile(); m_specFile->setFileName(""); m_specFile->clearModified(); m_sceneAnnotationFile = new AnnotationFile(AnnotationFile::ANNOTATION_FILE_SAVE_TO_SCENE); m_sceneAnnotationFile->setFileName("Scene Annotations"); m_sceneAnnotationFile->clearModified(); m_modelChart = NULL; m_modelChartTwo = NULL; m_surfaceMontageModel = NULL; m_volumeSliceModel = NULL; m_wholeBrainModel = NULL; m_displayPropertiesAnnotation = new DisplayPropertiesAnnotation(this); m_displayProperties.push_back(m_displayPropertiesAnnotation); m_displayPropertiesAnnotationTextSubstitution = new DisplayPropertiesAnnotationTextSubstitution(this); m_displayProperties.push_back(m_displayPropertiesAnnotationTextSubstitution); m_displayPropertiesBorders = new DisplayPropertiesBorders(); m_displayProperties.push_back(m_displayPropertiesBorders); m_displayPropertiesFiberOrientation = new DisplayPropertiesFiberOrientation(); m_displayProperties.push_back(m_displayPropertiesFiberOrientation); m_displayPropertiesFoci = new DisplayPropertiesFoci(); m_displayProperties.push_back(m_displayPropertiesFoci); m_displayPropertiesImages = new DisplayPropertiesImages(this); m_displayProperties.push_back(m_displayPropertiesImages); m_displayPropertiesLabels = new DisplayPropertiesLabels(); m_displayProperties.push_back(m_displayPropertiesLabels); m_displayPropertiesSurface = new DisplayPropertiesSurface(); m_displayProperties.push_back(m_displayPropertiesSurface); m_displayPropertiesVolume = new DisplayPropertiesVolume(); m_displayProperties.push_back(m_displayPropertiesVolume); m_surfaceMatchingToAnatomicalFlag = false; EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CARET_DATA_FILES_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_DATA_FILE_ADD); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_DATA_FILE_DELETE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_DATA_FILE_READ); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_DATA_FILE_RELOAD); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILES_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GET_DISPLAYED_DATA_FILES); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_SPEC_FILE_READ_DATA_FILES); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_PALETTE_GET_BY_NAME); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_SCENE_ACTIVE); m_isSpecFileBeingRead = false; m_gapsAndMargins = new GapsAndMargins(); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_sceneAnnotationFile", "SceneAnnotationFile", m_sceneAnnotationFile); m_sceneAssistant->add("displayPropertiesAnnotation", "DisplayPropertiesAnnotation", m_displayPropertiesAnnotation); m_sceneAssistant->add("displayPropertiesAnnotationTextSubstitution", "DisplayPropertiesAnnotationTextSubstitution", m_displayPropertiesAnnotationTextSubstitution); m_sceneAssistant->add("displayPropertiesBorders", "DisplayPropertiesBorders", m_displayPropertiesBorders); m_sceneAssistant->add("displayPropertiesFiberOrientation", "DisplayPropertiesFiberOrientation", m_displayPropertiesFiberOrientation); m_sceneAssistant->add("displayPropertiesFoci", "DisplayPropertiesFoci", m_displayPropertiesFoci); m_sceneAssistant->add("m_displayPropertiesImages", "DisplayPropertiesImages", m_displayPropertiesImages); m_sceneAssistant->add("m_displayPropertiesLabels", "DisplayPropertiesLabels", m_displayPropertiesLabels); m_sceneAssistant->add("m_displayPropertiesSurface", "DisplayPropertiesSurface", m_displayPropertiesSurface); m_sceneAssistant->add("displayPropertiesVolume", "DisplayPropertiesVolume", m_displayPropertiesVolume); m_sceneAssistant->add("m_gapsAndMargins", "GapsAndMargins", m_gapsAndMargins); m_sceneAssistant->add("m_surfaceMatchingToAnatomicalFlag", &m_surfaceMatchingToAnatomicalFlag); m_selectionManager = new SelectionManager(); m_identificationManager = new IdentificationManager(caretPreferences); m_brainordinateHighlightRegionOfInterest = new BrainordinateRegionOfInterest(); updateChartModel(); } /** * Destructor. */ Brain::~Brain() { EventManager::get()->removeAllEventsFromListener(this); delete m_sceneAssistant; for (std::vector::iterator iter = m_displayProperties.begin(); iter != m_displayProperties.end(); iter++) { delete *iter; } m_displayProperties.clear(); resetBrain(); delete m_sceneAnnotationFile; delete m_specFile; delete m_annotationManager; delete m_chartingDataManager; delete m_fiberOrientationSamplesLoader; delete m_paletteFile; if (m_modelChart != NULL) { delete m_modelChart; } if (m_modelChartTwo != NULL) { delete m_modelChartTwo; } if (m_surfaceMontageModel != NULL) { delete m_surfaceMontageModel; } if (m_volumeSliceModel != NULL) { delete m_volumeSliceModel; } if (m_wholeBrainModel != NULL) { delete m_wholeBrainModel; } delete m_selectionManager; delete m_identificationManager; delete m_brainordinateHighlightRegionOfInterest; delete m_gapsAndMargins; } /** * Get number of brain structures. * * @return * Number of brain structure. */ int Brain::getNumberOfBrainStructures() const { return static_cast(m_brainStructures.size()); } /** * Add a brain structure. * * @param brainStructure * Brain structure to add. */ void Brain::addBrainStructure(BrainStructure* brainStructure) { m_brainStructures.push_back(brainStructure); } /** * Get a brain structure at specified index. * * @param indx * Index of brain structure. * @return * Pointer to brain structure at index. */ BrainStructure* Brain::getBrainStructure(const int32_t indx) { CaretAssertVectorIndex(m_brainStructures, indx); return m_brainStructures[indx]; } /** * Get a brain structure at specified index. * * @param indx * Index of brain structure. * @return * Pointer to brain structure at index. */ const BrainStructure* Brain::getBrainStructure(const int32_t indx) const { CaretAssertVectorIndex(m_brainStructures, indx); return m_brainStructures[indx]; } /** * Find, and possibly create, a brain structure that * models the specified structure. * * @param structure * The desired structure. * @param createIfNotFound * If there is not a matching brain structure, create one. * @return * Pointer to brain structure or NULL if no match. */ BrainStructure* Brain::getBrainStructure(StructureEnum::Enum structure, bool createIfNotFound) { for (std::vector::iterator iter = m_brainStructures.begin(); iter != m_brainStructures.end(); iter++) { BrainStructure* bs = *iter; if (bs->getStructure() == structure) { return bs; } } if (createIfNotFound) { BrainStructure* bs = new BrainStructure(this, structure); m_brainStructures.push_back(bs); return bs; } return NULL; } /** * Update brain structures by removing any that contain zero data files */ void Brain::updateBrainStructures() { std::vector validBrainStructures; for (auto bs : m_brainStructures) { CaretAssert(bs); if (bs->hasDataFiles()) { validBrainStructures.push_back(bs); } else { delete bs; } } if (m_brainStructures.size() != validBrainStructures.size()) { m_brainStructures = validBrainStructures; } } /** * Increment and return the duplicate counter for the given data file type. * * @param dataFileType * Type of data file. * @return * Next duplicate counter for the file type. */ int32_t Brain::getDuplicateFileNameCounterForFileType(const DataFileTypeEnum::Enum dataFileType) { int32_t counterValue = 0; std::map::iterator duplicateCounterIter = m_duplicateFileNameCounter.find(dataFileType); if (duplicateCounterIter != m_duplicateFileNameCounter.end()) { counterValue = duplicateCounterIter->second; } /* * Extremely unlikely that that this will happen */ if (counterValue == std::numeric_limits::max()) { counterValue = 0; } ++counterValue; m_duplicateFileNameCounter[dataFileType] = counterValue; // m_duplicateFileNameCounter.insert(std::make_pair(dataFileType, // counterValue)); return counterValue; } /** * Reset the duplicate file name counter for all data file types. In some * instances, the scene file counter is not altered and needs to be * preserved. * * @param preserveSceneFileCounter * If true, do not reset the scene file duplicate counter. */ void Brain::resetDuplicateFileNameCounter(const bool preserveSceneFileCounter) { int32_t sceneDuplicateCounter = -1; if (preserveSceneFileCounter) { std::map::iterator sceneDuplicateIter = m_duplicateFileNameCounter.find(DataFileTypeEnum::SCENE); if (sceneDuplicateIter != m_duplicateFileNameCounter.end()) { sceneDuplicateCounter = sceneDuplicateIter->second; } } m_duplicateFileNameCounter.clear(); if (sceneDuplicateCounter > 0) { m_duplicateFileNameCounter.insert(std::make_pair(DataFileTypeEnum::SCENE, sceneDuplicateCounter)); } } /** * Reset the brain structure. * @param keepSceneFiles * Status of keeping scene files. * @param keepSpecFile * Status of keeping spec file. */ void Brain::resetBrain(const ResetBrainKeepSceneFiles keepSceneFiles, const ResetBrainKeepSpecFile keepSpecFile) { m_isSpecFileBeingRead = false; m_activeScene = NULL; m_surfaceMatchingToAnatomicalFlag = false; /* * Clear the counters used to prevent duplicate file names. */ resetDuplicateFileNameCounter(keepSceneFiles); int num = getNumberOfBrainStructures(); for (int32_t i = 0; i < num; i++) { delete m_brainStructures[i]; } for (std::vector::iterator vfi = m_volumeFiles.begin(); vfi != m_volumeFiles.end(); vfi++) { VolumeFile* vf = *vfi; delete vf; } m_volumeFiles.clear(); m_brainStructures.clear(); for (std::vector::iterator afi = m_annotationFiles.begin(); afi != m_annotationFiles.end(); afi++) { AnnotationFile* af = *afi; delete af; } m_annotationFiles.clear(); for (auto asf : m_annotationSubstitutionFiles) { delete asf; } m_annotationSubstitutionFiles.clear(); m_sceneAnnotationFile->clear(); //m_sceneAnnotationFile->setFileName("Scene Annotations"); m_sceneAnnotationFile->clearModified(); for (std::vector::iterator bfi = m_borderFiles.begin(); bfi != m_borderFiles.end(); bfi++) { BorderFile* bf = *bfi; delete bf; } m_borderFiles.clear(); for (std::vector::iterator ffi = m_fociFiles.begin(); ffi != m_fociFiles.end(); ffi++) { FociFile* ff = *ffi; delete ff; } m_fociFiles.clear(); for (std::vector::iterator ifi = m_imageFiles.begin(); ifi != m_imageFiles.end(); ifi++) { ImageFile* img = *ifi; delete img; } m_imageFiles.clear(); for (std::vector::iterator cdsfi = m_connectivityDataSeriesFiles.begin(); cdsfi != m_connectivityDataSeriesFiles.end(); cdsfi++) { CiftiBrainordinateDataSeriesFile* cbdsf = *cdsfi; delete cbdsf; } m_connectivityDataSeriesFiles.clear(); for (std::vector::iterator clfi = m_connectivityDenseLabelFiles.begin(); clfi != m_connectivityDenseLabelFiles.end(); clfi++) { CiftiBrainordinateLabelFile* clf = *clfi; delete clf; } m_connectivityDenseLabelFiles.clear(); for (std::vector::iterator clfi = m_connectivityMatrixDenseFiles.begin(); clfi != m_connectivityMatrixDenseFiles.end(); clfi++) { CiftiConnectivityMatrixDenseFile* clf = *clfi; delete clf; } m_connectivityMatrixDenseFiles.clear(); for (std::vector::iterator clfi = m_connectivityMatrixDenseParcelFiles.begin(); clfi != m_connectivityMatrixDenseParcelFiles.end(); clfi++) { CiftiConnectivityMatrixDenseParcelFile* clf = *clfi; delete clf; } m_connectivityMatrixDenseParcelFiles.clear(); for (std::vector::iterator clfi = m_connectivityDenseScalarFiles.begin(); clfi != m_connectivityDenseScalarFiles.end(); clfi++) { CiftiBrainordinateScalarFile* clf = *clfi; delete clf; } m_connectivityDenseScalarFiles.clear(); for (std::vector::iterator clfi = m_connectivityParcelSeriesFiles.begin(); clfi != m_connectivityParcelSeriesFiles.end(); clfi++) { CiftiParcelSeriesFile* pdsf = *clfi; delete pdsf; } m_connectivityParcelSeriesFiles.clear(); for (std::vector::iterator cpfi = m_connectivityParcelLabelFiles.begin(); cpfi != m_connectivityParcelLabelFiles.end(); cpfi++) { CiftiParcelLabelFile* plf = *cpfi; delete plf; } m_connectivityParcelLabelFiles.clear(); for (std::vector::iterator clfi = m_connectivityParcelScalarFiles.begin(); clfi != m_connectivityParcelScalarFiles.end(); clfi++) { CiftiParcelScalarFile* psf = *clfi; delete psf; } m_connectivityParcelScalarFiles.clear(); for (std::vector::iterator clfi = m_connectivityScalarDataSeriesFiles.begin(); clfi != m_connectivityScalarDataSeriesFiles.end(); clfi++) { CiftiScalarDataSeriesFile* psf = *clfi; delete psf; } m_connectivityScalarDataSeriesFiles.clear(); for (std::vector::iterator clfi = m_connectivityFiberOrientationFiles.begin(); clfi != m_connectivityFiberOrientationFiles.end(); clfi++) { CiftiFiberOrientationFile* clf = *clfi; delete clf; } m_connectivityFiberOrientationFiles.clear(); for (std::vector::iterator clfi = m_connectivityFiberTrajectoryFiles.begin(); clfi != m_connectivityFiberTrajectoryFiles.end(); clfi++) { CiftiFiberTrajectoryFile* clf = *clfi; delete clf; } m_connectivityFiberTrajectoryFiles.clear(); for (std::vector::iterator clfi = m_connectivityMatrixParcelFiles.begin(); clfi != m_connectivityMatrixParcelFiles.end(); clfi++) { CiftiConnectivityMatrixParcelFile* clf = *clfi; delete clf; } m_connectivityMatrixParcelFiles.clear(); for (std::vector::iterator clfi = m_connectivityMatrixParcelDenseFiles.begin(); clfi != m_connectivityMatrixParcelDenseFiles.end(); clfi++) { CiftiConnectivityMatrixParcelDenseFile* clf = *clfi; delete clf; } m_connectivityMatrixParcelDenseFiles.clear(); if (m_paletteFile != NULL) { delete m_paletteFile; } m_paletteFile = new PaletteFile(); m_paletteFile->setFileName(convertFilePathNameToAbsolutePathName(m_paletteFile->getFileName())); m_paletteFile->clearModified(); m_fiberOrientationSamplesLoader->reset(); switch (keepSceneFiles) { case RESET_BRAIN_KEEP_SCENE_FILES_NO: for (std::vector::iterator sfi = m_sceneFiles.begin(); sfi != m_sceneFiles.end(); sfi++) { SceneFile* sf = *sfi; delete sf; } m_sceneFiles.clear(); break; case RESET_BRAIN_KEEP_SCENE_FILES_YES: break; } switch (keepSpecFile) { case RESET_BRAIN_KEEP_SPEC_FILE_NO: m_specFile->clear(); m_specFile->setFileName(""); m_specFile->clearModified(); break; case RESET_BRAIN_KEEP_SPEC_FILE_YES: break; } for (std::vector::iterator iter = m_displayProperties.begin(); iter != m_displayProperties.end(); iter++) { (*iter)->reset(); } m_identificationManager->removeAllIdentifiedItems(); m_selectionManager->reset(); m_selectionManager->setLastSelectedItem(NULL); m_annotationManager->reset(); m_brainordinateHighlightRegionOfInterest->clear(); if (m_modelChart != NULL) { m_modelChart->reset(); } if (m_modelChartTwo != NULL) { m_modelChartTwo->reset(); } m_gapsAndMargins->reset(); updateAfterFilesAddedOrRemoved(); EventManager::get()->sendEvent(EventBrainReset(this).getPointer()); } /** * Reset the brain structure. */ void Brain::resetBrain() { resetBrain(RESET_BRAIN_KEEP_SCENE_FILES_NO, RESET_BRAIN_KEEP_SPEC_FILE_NO); } /** * Reset the brain structure but keep spec and scene files. */ void Brain::resetBrainKeepSceneFiles() { /* * Save all of the non-modified files so that loading * of them can be avoided later */ std::vector allFiles; getAllDataFiles(allFiles); m_nonModifiedFilesForRestoringScene.clear(); for (std::vector::iterator iter = allFiles.begin(); iter != allFiles.end(); iter++) { CaretDataFile* caretDataFile = *iter; if (caretDataFile->isModified()) { continue; } else { /* * If a palette is modified by user or by showing a previous scene, * then the file MUST be reloaded because the palette may be different * in the new scene that is being loaded. */ CaretMappableDataFile* cmdf = dynamic_cast(caretDataFile); if (cmdf != NULL) { switch (cmdf->getPaletteColorMappingModifiedStatus()) { case PaletteModifiedStatusEnum::MODIFIED: continue; break; case PaletteModifiedStatusEnum::MODIFIED_BY_SHOW_SCENE: continue; break; case PaletteModifiedStatusEnum::UNMODIFIED: break; } } } if (caretDataFile->isModifiedSinceTimeOfLastReadOrWrite()) { continue; } const DataFileTypeEnum::Enum dataFileType = caretDataFile->getDataFileType(); bool keepFileFlag = true; switch (dataFileType) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: break; case DataFileTypeEnum::METRIC: break; case DataFileTypeEnum::METRIC_DYNAMIC: break; case DataFileTypeEnum::PALETTE: keepFileFlag = false; break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: keepFileFlag = false; break; case DataFileTypeEnum::SPECIFICATION: keepFileFlag = false; break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: keepFileFlag = false; break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: break; } if (keepFileFlag) { if (removeWithoutDeleteDataFile(caretDataFile)) { m_nonModifiedFilesForRestoringScene.push_back(caretDataFile); } } } resetBrain(RESET_BRAIN_KEEP_SCENE_FILES_YES, RESET_BRAIN_KEEP_SPEC_FILE_NO); } /** * Copy all display properties from the source tab to the target tab. * @param sourceTabIndex * Index of source tab. * @param targetTabIndex * Index of target tab. */ void Brain::copyDisplayProperties(const int32_t sourceTabIndex, const int32_t targetTabIndex) { for (std::vector::iterator iter = m_displayProperties.begin(); iter != m_displayProperties.end(); iter++) { (*iter)->copyDisplayProperties(sourceTabIndex, targetTabIndex); } } /** * Read a surface file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @param structureIn * Structure of label file. * @throws DataFileException * If reading failed. * @return Pointer to file that was read. */ Surface* Brain::addReadOrReloadSurfaceFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename, const StructureEnum::Enum structureIn, const bool markDataFileAsModified) { Surface* surface = NULL; StructureEnum::Enum structure = StructureEnum::INVALID; if (caretDataFile != NULL) { surface = dynamic_cast(caretDataFile); CaretAssert(surface); /* * Need structure in case file reloading fails */ structure = surface->getStructure(); } else { surface = new Surface(); } bool addFlag = false; bool readFlag = false; bool reloadFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; reloadFlag = true; break; } if (readFlag) { try { try { surface->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } } catch (const DataFileException& dfe) { if (reloadFlag) { BrainStructure* bs = getBrainStructure(structure, true); if (bs != NULL) { bs->removeWithoutDeleteDataFile(surface); } } delete surface; throw dfe; } } if (addFlag) { } bool fileIsModified = false; if (structureIn != StructureEnum::INVALID) { if (surface->getStructure() != structureIn) { surface->setStructure(structureIn); fileIsModified = markDataFileAsModified; } } structure = surface->getStructure(); if (structure == StructureEnum::INVALID) { if (caretDataFile == NULL) { delete surface; } DataFileException e(filename, "Structure is not valid."); e.setErrorInvalidStructure(true); CaretLogThrowing(e); throw e; } const bool brainStructureExists = (getBrainStructure(structure, false) != NULL); BrainStructure* bs = getBrainStructure(structure, true); if (bs != NULL) { /* * Initialize the overlays if the brain structure did NOT exist * AND a spec file is NOT being read */ bool initializeOverlaysFlag = false; if (brainStructureExists == false) { if (m_isSpecFileBeingRead == false) { initializeOverlaysFlag = true; } } if (addFlag) { std::vector allSurfaces; bs->getSurfaces(allSurfaces); updateDataFileNameIfDuplicate(allSurfaces, surface); } bs->addSurface(surface, addFlag, initializeOverlaysFlag); } else { if (caretDataFile == NULL) { delete surface; } AString message = "Failed to create a BrainStructure for surface with structure " + StructureEnum::toGuiName(structure) + "."; DataFileException e(filename, message); CaretLogThrowing(e); throw e; } surface->clearModified(); if (fileIsModified) { surface->setModified(); } return surface; } /** * Read a label file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @param structureIn * Structure of label file. * @throws DataFileException * If reading failed. * @return Pointer to file that was read. */ LabelFile* Brain::addReadOrReloadLabelFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename, const StructureEnum::Enum structureIn, const bool markDataFileAsModified) { LabelFile* labelFile = NULL; StructureEnum::Enum structure = StructureEnum::INVALID; if (caretDataFile != NULL) { labelFile = dynamic_cast(caretDataFile); CaretAssert(labelFile); /* * Need structure in case file reloading fails */ structure = labelFile->getStructure(); } else { labelFile = new LabelFile(); } bool addFlag = false; bool readFlag = false; bool reloadFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; reloadFlag = true; break; } if (readFlag) { try { try { labelFile->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } } catch (const DataFileException& dfe) { if (reloadFlag) { BrainStructure* bs = getBrainStructure(structure, true); if (bs != NULL) { bs->removeWithoutDeleteDataFile(labelFile); } } delete labelFile; throw dfe; } } if (addFlag) { } bool fileIsModified = false; if (structureIn != StructureEnum::INVALID) { if (labelFile->getStructure() != structureIn) { labelFile->setStructure(structureIn); fileIsModified = markDataFileAsModified; } } structure = labelFile->getStructure(); if (structure == StructureEnum::INVALID) { if (caretDataFile == NULL) { delete labelFile; } DataFileException e(filename, "Structure is not valid."); e.setErrorInvalidStructure(true); CaretLogThrowing(e); throw e; } BrainStructure* bs = getBrainStructure(structure, false); if (bs != NULL) { try { if (addFlag) { std::vector allLabelFiles; bs->getLabelFiles(allLabelFiles); updateDataFileNameIfDuplicate(allLabelFiles, labelFile); } bs->addLabelFile(labelFile, addFlag); } catch (const DataFileException& e) { if (caretDataFile == NULL) { delete labelFile; } throw e; } } else { if (caretDataFile == NULL) { delete labelFile; } AString message = "Must read a surface with structure " + StructureEnum::toGuiName(structure) + " before reading its label files."; DataFileException e(filename, message); CaretLogThrowing(e); throw e; } labelFile->clearModified(); if (fileIsModified) { labelFile->setModified(); } return labelFile; } /** * Read a metric file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @param structureIn * Structure of label file. * @throws DataFileException * If reading failed. * @return Pointer to file that was read. */ MetricFile* Brain::addReadOrReloadMetricFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename, const StructureEnum::Enum structureIn, const bool markDataFileAsModified) { MetricFile* metricFile = NULL; StructureEnum::Enum structure = StructureEnum::INVALID; if (caretDataFile != NULL) { metricFile = dynamic_cast(caretDataFile); CaretAssert(metricFile); /* * Need structure in case file reloading fails */ structure = metricFile->getStructure(); } else { metricFile = new MetricFile(); } bool addFlag = false; bool readFlag = false; bool reloadFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; reloadFlag = true; break; } if (readFlag) { try { try { metricFile->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } } catch (const DataFileException& dfe) { if (reloadFlag) { BrainStructure* bs = getBrainStructure(structure, true); if (bs != NULL) { bs->removeWithoutDeleteDataFile(metricFile); } } delete metricFile; throw dfe; } } if (addFlag) { } bool fileIsModified = false; if (structureIn != StructureEnum::INVALID) { if (metricFile->getStructure() != structureIn) { metricFile->setStructure(structureIn); fileIsModified = markDataFileAsModified; } } structure = metricFile->getStructure(); if (structure == StructureEnum::INVALID) { if (caretDataFile == NULL) { delete metricFile; } DataFileException e(filename, "Structure is not valid."); e.setErrorInvalidStructure(true); CaretLogThrowing(e); throw e; } BrainStructure* bs = getBrainStructure(structure, false); if (bs != NULL) { try { if (addFlag) { std::vector allMetricFiles; bs->getMetricFiles(allMetricFiles); updateDataFileNameIfDuplicate(allMetricFiles, metricFile); } bs->addMetricFile(metricFile, addFlag); } catch (const DataFileException& e) { if (caretDataFile == NULL) { delete metricFile; } throw e; } } else { if (caretDataFile == NULL) { delete metricFile; } AString message = "Must read a surface with structure " + StructureEnum::toGuiName(structure) + " before reading its metric files."; DataFileException e(filename, message); CaretLogThrowing(e); throw e; } metricFile->clearModified(); if (fileIsModified) { metricFile->setModified(); } return metricFile; } /** * Read an RGBA file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @param structureIn * Structure of label file. * @throws DataFileException * If reading failed. * @return Pointer to file that was read. */ RgbaFile* Brain::addReadOrReloadRgbaFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename, const StructureEnum::Enum structureIn, const bool markDataFileAsModified) { RgbaFile* rgbaFile = NULL; StructureEnum::Enum structure = StructureEnum::INVALID; if (caretDataFile != NULL) { rgbaFile = dynamic_cast(caretDataFile); CaretAssert(rgbaFile); /* * Need structure in case file reloading fails */ structure = rgbaFile->getStructure(); } else { rgbaFile = new RgbaFile(); } bool addFlag = false; bool readFlag = false; bool reloadFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; reloadFlag = true; break; } if (readFlag) { try { try { rgbaFile->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } } catch (const DataFileException& dfe) { if (reloadFlag) { BrainStructure* bs = getBrainStructure(structure, true); if (bs != NULL) { bs->removeWithoutDeleteDataFile(rgbaFile); } } delete rgbaFile; throw dfe; } } if (addFlag) { } bool fileIsModified = false; if (structureIn != StructureEnum::INVALID) { if (rgbaFile->getStructure() != structureIn) { rgbaFile->setStructure(structureIn); fileIsModified = markDataFileAsModified; } } structure = rgbaFile->getStructure(); if (structure == StructureEnum::INVALID) { if (caretDataFile == NULL) { delete rgbaFile; } DataFileException e(filename, "Structure is not valid."); e.setErrorInvalidStructure(true); CaretLogThrowing(e); throw e; } BrainStructure* bs = getBrainStructure(structure, false); if (bs != NULL) { try { if (addFlag) { std::vector allRgbaFiles; bs->getRgbaFiles(allRgbaFiles); updateDataFileNameIfDuplicate(allRgbaFiles, rgbaFile); } bs->addRgbaFile(rgbaFile, addFlag); } catch (const DataFileException& e) { if (caretDataFile == NULL) { delete rgbaFile; } throw e; } } else { if (caretDataFile == NULL) { delete rgbaFile; } AString message = "Must read a surface with structure " + StructureEnum::toGuiName(structure) + " before reading its RGBA files."; DataFileException e(filename, message); CaretLogThrowing(e); throw e; } rgbaFile->clearModified(); if (fileIsModified) { rgbaFile->setModified(); } return rgbaFile; } /** * Read a volume file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @return * File that was read. * @throws DataFileException * If reading failed. */ VolumeFile* Brain::addReadOrReloadVolumeFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename) { VolumeFile* vf = NULL; if (caretDataFile != NULL) { vf = dynamic_cast(caretDataFile); CaretAssert(vf); } else { vf = new VolumeFile(); } bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { try { try { vf->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } } catch (const DataFileException& e) { if (caretDataFile != NULL) { removeAndDeleteDataFile(caretDataFile); } else { delete vf; } throw e; } } vf->clearModified(); ElapsedTimer timer; timer.start(); vf->updateScalarColoringForAllMaps(); CaretLogInfo("Time to color volume data is " + AString::number(timer.getElapsedTimeSeconds(), 'f', 3) + " seconds."); if (addFlag) { updateDataFileNameIfDuplicate(m_volumeFiles, vf); m_volumeFiles.push_back(vf); } initializeVolumeFile(vf); return vf; } /** * @return Number of volume files. */ int32_t Brain::getNumberOfVolumeFiles() const { return m_volumeFiles.size(); } /** * Get the volume file at the given index. * @param volumeFileIndex * Index of the volume file. * @return * Volume file at the given index. */ VolumeFile* Brain::getVolumeFile(const int32_t volumeFileIndex) { CaretAssertVectorIndex(m_volumeFiles, volumeFileIndex); return m_volumeFiles[volumeFileIndex]; } /** * Get the volume dynamic connecivity files * * @param volumeDynamicConnectivityFilesOut * Output with volume dynamic connectivity files */ void Brain::getVolumeDynamicConnectivityFiles(std::vector& volumeDynamicConnectivityFilesOut) const { volumeDynamicConnectivityFilesOut.clear(); for (auto vf : m_volumeFiles) { CaretAssert(vf); VolumeDynamicConnectivityFile* volDynConn = vf->getVolumeDynamicConnectivityFile(); if (volDynConn != NULL) { if (volDynConn->isDataValid()) { volumeDynamicConnectivityFilesOut.push_back(volDynConn); } } } } /** * Get the metric dynamic connecivity files * * @param metricDynamicConnectivityFilesOut * Output with metric dynamic connectivity files */ void Brain::getMetricDynamicConnectivityFiles(std::vector& metricDynamicConnectivityFilesOut) const { metricDynamicConnectivityFilesOut.clear(); for (auto bs : m_brainStructures) { std::vector metricFiles; bs->getMetricFiles(metricFiles); for (auto mf : metricFiles) { MetricDynamicConnectivityFile* metricDynConn = mf->getMetricDynamicConnectivityFile(); if (metricDynConn != NULL) { if (metricDynConn->isDataValid()) { metricDynamicConnectivityFilesOut.push_back(metricDynConn); } } } } } /** * Initialize a volume file. If it is functional data and contains more than one timepoint * setup its volume dynamic connectivity file. */ void Brain::initializeVolumeFile(VolumeFile* volumeFile) { CaretAssert(volumeFile); /* * Enable dynamic connectivity using preferences */ CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); VolumeDynamicConnectivityFile* volDynConn = volumeFile->getVolumeDynamicConnectivityFile(); if (volDynConn != NULL) { volDynConn->setEnabledAsLayer(prefs->isDynamicConnectivityDefaultedOn()); } } /** * Get the volume file at the given index. * @param volumeFileIndex * Index of the volume file. * @return * Volume file at the given index. */ const VolumeFile* Brain::getVolumeFile(const int32_t volumeFileIndex) const { CaretAssertVectorIndex(m_volumeFiles, volumeFileIndex); return m_volumeFiles[volumeFileIndex]; } /** * Add, read, or reload an annotation file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @return * File that was read. * @throws DataFileException * If reading failed. */ AnnotationFile* Brain::addReadOrReloadAnnotationFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename) { AnnotationFile* af = NULL; if (caretDataFile != NULL) { af = dynamic_cast(caretDataFile); CaretAssert(af); } else { af = new AnnotationFile(); } bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { try { try { af->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } } catch (DataFileException& dfe) { if (caretDataFile != NULL) { removeAndDeleteDataFile(caretDataFile); } else { delete af; } throw dfe; } } if (addFlag) { updateDataFileNameIfDuplicate(m_annotationFiles, af); m_annotationFiles.push_back(af); } return af; } /** * Add, read, or reload an annotation substitution file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @return * File that was read. * @throws DataFileException * If reading failed. */ AnnotationTextSubstitutionFile* Brain::addReadOrReloadAnnotationTextSubstitutionFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename) { AnnotationTextSubstitutionFile* af = NULL; if (caretDataFile != NULL) { af = dynamic_cast(caretDataFile); CaretAssert(af); } else { af = new AnnotationTextSubstitutionFile(); } bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { try { try { af->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } } catch (DataFileException& dfe) { if (caretDataFile != NULL) { removeAndDeleteDataFile(caretDataFile); } else { delete af; } throw dfe; } } if (addFlag) { updateDataFileNameIfDuplicate(m_annotationSubstitutionFiles, af); m_annotationSubstitutionFiles.push_back(af); } if (fileMode == FILE_MODE_RELOAD) { EventManager::get()->sendEvent(EventAnnotationTextSubstitutionInvalidate().getPointer()); } return af; } /** * Read a border file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @return * File that was read. * @throws DataFileException * If reading failed. */ BorderFile* Brain::addReadOrReloadBorderFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename) { BorderFile* bf = NULL; if (caretDataFile != NULL) { bf = dynamic_cast(caretDataFile); CaretAssert(bf); } else { bf = new BorderFile(); } bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { try { try { bf->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } /* * Create a map of structure to number of nodes */ std::map structureToNodeCountMap; for (std::vector::iterator bsIter = m_brainStructures.begin(); bsIter != m_brainStructures.end(); bsIter++) { const BrainStructure* bs = *bsIter; CaretAssert(bs); structureToNodeCountMap.insert(std::make_pair(bs->getStructure(), bs->getNumberOfNodes())); } bf->updateNumberOfNodesIfSingleStructure(structureToNodeCountMap); } catch (DataFileException& dfe) { if (caretDataFile != NULL) { removeAndDeleteDataFile(caretDataFile); } else { delete bf; } throw dfe; } } if (addFlag) { updateDataFileNameIfDuplicate(m_borderFiles, bf); m_borderFiles.push_back(bf); } return bf; } /** * Read a foci file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @throws DataFileException * If reading failed. */ FociFile* Brain::addReadOrReloadFociFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename) { FociFile* ff = NULL; if (caretDataFile != NULL) { ff = dynamic_cast(caretDataFile); CaretAssert(ff); } else { ff = new FociFile(); } bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { try { try { ff->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } } catch (DataFileException& dfe) { if (caretDataFile != NULL) { removeAndDeleteDataFile(caretDataFile); } else { delete ff; } throw dfe; } } if (addFlag) { updateDataFileNameIfDuplicate(m_fociFiles, ff); m_fociFiles.push_back(ff); } return ff; } /** * Read a foci file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @throws DataFileException * If reading failed. */ ImageFile* Brain::addReadOrReloadImageFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename) { ImageFile* imageFile = NULL; if (caretDataFile != NULL) { imageFile = dynamic_cast(caretDataFile); CaretAssert(imageFile); } else { imageFile = new ImageFile(); } bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { try { try { imageFile->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } } catch (DataFileException& dfe) { if (caretDataFile != NULL) { removeAndDeleteDataFile(caretDataFile); } else { delete imageFile; } throw dfe; } } if (addFlag) { updateDataFileNameIfDuplicate(m_imageFiles, imageFile); m_imageFiles.push_back(imageFile); } return imageFile; } /** * Validate a CIFTI Mappable Data File. * A file is valid if its surface mappings match the loaded surfaces. * * @param ciftiMapFile * File examined for validity. * @throws DataFileException * If the file is found to be incompatible with the loaded surfaces. */ void Brain::validateCiftiMappableDataFile(const CiftiMappableDataFile* ciftiMapFile) const { const int32_t numBrainStructures = getNumberOfBrainStructures(); for (int32_t i = 0; i < numBrainStructures; i++) { const StructureEnum::Enum structure = getBrainStructure(i)->getStructure(); const int numNodes = getBrainStructure(i)->getNumberOfNodes(); const int numConnNodes = ciftiMapFile->getMappingSurfaceNumberOfNodes(structure); if (numConnNodes > 0) { if (numNodes != numConnNodes) { AString msg = ("The CIFTI file contains " + AString::number(numConnNodes) + " nodes for structure " + StructureEnum::toGuiName(structure) + " but the corresponding surface brain structure contains " + AString::number(numNodes) + " nodes."); throw DataFileException(ciftiMapFile->getFileName(), msg); } } } } /** * Read a connectivity matrix dense file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @return * File that was read. * @throws DataFileException * If reading failed. */ CiftiConnectivityMatrixDenseFile* Brain::addReadOrReloadConnectivityDenseFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename) { CiftiConnectivityMatrixDenseFile* cmdf = NULL; if (caretDataFile != NULL) { cmdf = dynamic_cast(caretDataFile); CaretAssert(cmdf); } else { cmdf = new CiftiConnectivityMatrixDenseFile(); } bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { try { try { cmdf->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } cmdf->clearModified(); validateCiftiMappableDataFile(cmdf); } catch (const DataFileException& dfe) { if (caretDataFile != NULL) { removeAndDeleteDataFile(caretDataFile); } else { delete cmdf; } throw dfe; } } if (addFlag) { updateDataFileNameIfDuplicate(m_connectivityMatrixDenseFiles, cmdf); m_connectivityMatrixDenseFiles.push_back(cmdf); } return cmdf; } /** * Read a connectivity dense label file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @return * File that was read. * @throws DataFileException * If reading failed. */ CiftiBrainordinateLabelFile* Brain::addReadOrReloadConnectivityDenseLabelFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename) { CiftiBrainordinateLabelFile* file = NULL; if (caretDataFile != NULL) { file = dynamic_cast(caretDataFile); CaretAssert(file); } else { file = new CiftiBrainordinateLabelFile(); } bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { try { try { file->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } validateCiftiMappableDataFile(file); } catch (const DataFileException& dfe) { if (caretDataFile != NULL) { removeAndDeleteDataFile(caretDataFile); } else { delete file; } throw dfe; } } if (addFlag) { updateDataFileNameIfDuplicate(m_connectivityDenseLabelFiles, file); m_connectivityDenseLabelFiles.push_back(file); } return file; } /** * Read a connectivity dense parcel file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @throws DataFileException * If reading failed. */ CiftiConnectivityMatrixDenseParcelFile* Brain::addReadOrReloadConnectivityMatrixDenseParcelFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename) { CiftiConnectivityMatrixDenseParcelFile* file = NULL; if (caretDataFile != NULL) { file = dynamic_cast(caretDataFile); CaretAssert(file); } else { file = new CiftiConnectivityMatrixDenseParcelFile(); } bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { try { try { file->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } validateCiftiMappableDataFile(file); } catch (const DataFileException& dfe) { if (caretDataFile != NULL) { removeAndDeleteDataFile(caretDataFile); } else { delete file; } throw dfe; } } if (addFlag) { updateDataFileNameIfDuplicate(m_connectivityMatrixDenseParcelFiles, file); m_connectivityMatrixDenseParcelFiles.push_back(file); } return file; } /** * Update the fiber orientation files assigned to matching * fiber trajectory files. This is typically called after * files are added or removed. */ void Brain::updateFiberTrajectoryMatchingFiberOrientationFiles() { for (std::vector::iterator iter = m_connectivityFiberTrajectoryFiles.begin(); iter != m_connectivityFiberTrajectoryFiles.end(); iter++) { CiftiFiberTrajectoryFile* trajFile = *iter; trajFile->updateMatchingFiberOrientationFileFromList(m_connectivityFiberOrientationFiles); } } /** * Read a connectivity dense scalar file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @throws DataFileException * If reading failed. */ CiftiBrainordinateScalarFile* Brain::addReadOrReloadConnectivityDenseScalarFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename) { CiftiBrainordinateScalarFile* clf = NULL; if (caretDataFile != NULL) { clf = dynamic_cast(caretDataFile); CaretAssert(clf); } else { clf = new CiftiBrainordinateScalarFile(); } bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { try { try { clf->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } validateCiftiMappableDataFile(clf); } catch (const DataFileException& dfe) { if (caretDataFile != NULL) { removeAndDeleteDataFile(caretDataFile); } else { delete clf; } throw dfe; } } if (addFlag) { updateDataFileNameIfDuplicate(m_connectivityDenseScalarFiles, clf); m_connectivityDenseScalarFiles.push_back(clf); } return clf; } /** * Read a connectivity parcel data series file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @throws DataFileException * If reading failed. */ CiftiParcelSeriesFile* Brain::addReadOrReloadConnectivityParcelSeriesFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename) { CiftiParcelSeriesFile* clf = NULL; if (caretDataFile != NULL) { clf = dynamic_cast(caretDataFile); CaretAssert(clf); } else { clf = new CiftiParcelSeriesFile(); } bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { try { try { clf->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } validateCiftiMappableDataFile(clf); } catch (const DataFileException& dfe) { if (caretDataFile != NULL) { removeAndDeleteDataFile(caretDataFile); } else { delete clf; } throw dfe; } } if (addFlag) { updateDataFileNameIfDuplicate(m_connectivityParcelSeriesFiles, clf); m_connectivityParcelSeriesFiles.push_back(clf); } return clf; } /** * Read a connectivity parcel label file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @throws DataFileException * If reading failed. */ CiftiParcelLabelFile* Brain::addReadOrReloadConnectivityParcelLabelFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename) { CiftiParcelLabelFile* clf = NULL; if (caretDataFile != NULL) { clf = dynamic_cast(caretDataFile); CaretAssert(clf); } else { clf = new CiftiParcelLabelFile(); } bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { try { try { clf->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } validateCiftiMappableDataFile(clf); } catch (const DataFileException& dfe) { if (caretDataFile != NULL) { removeAndDeleteDataFile(caretDataFile); } else { delete clf; } throw dfe; } } if (addFlag) { updateDataFileNameIfDuplicate(m_connectivityParcelLabelFiles, clf); m_connectivityParcelLabelFiles.push_back(clf); } return clf; } /** * Read a connectivity parcel scalar file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @throws DataFileException * If reading failed. */ CiftiParcelScalarFile* Brain::addReadOrReloadConnectivityParcelScalarFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename) { CiftiParcelScalarFile* clf = NULL; if (caretDataFile != NULL) { clf = dynamic_cast(caretDataFile); CaretAssert(clf); } else { clf = new CiftiParcelScalarFile(); } bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { try { try { clf->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } validateCiftiMappableDataFile(clf); } catch (const DataFileException& dfe) { if (caretDataFile != NULL) { removeAndDeleteDataFile(caretDataFile); } else { delete clf; } throw dfe; } } if (addFlag) { updateDataFileNameIfDuplicate(m_connectivityParcelScalarFiles, clf); m_connectivityParcelScalarFiles.push_back(clf); } return clf; } /** * Read a connectivity scalar data series file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @throws DataFileException * If reading failed. */ CiftiScalarDataSeriesFile* Brain::addReadOrReloadConnectivityScalarDataSeriesFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename) { CiftiScalarDataSeriesFile* clf = NULL; if (caretDataFile != NULL) { clf = dynamic_cast(caretDataFile); CaretAssert(clf); } else { clf = new CiftiScalarDataSeriesFile(); } bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { try { try { clf->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } validateCiftiMappableDataFile(clf); } catch (const DataFileException& dfe) { if (caretDataFile != NULL) { removeAndDeleteDataFile(caretDataFile); } else { delete clf; } throw dfe; } } if (addFlag) { updateDataFileNameIfDuplicate(m_connectivityScalarDataSeriesFiles, clf); m_connectivityScalarDataSeriesFiles.push_back(clf); } return clf; } /** * Find a cifti scalar file containing shape information. * * @param ciftiScalarShapeFileOut * Output CIFTI Scalar file that meets requirements (NULL if no matches. * @param shapeMapIndexOut * Output Index of map meeting requirements. */ void Brain::getCiftiShapeMap(CiftiBrainordinateScalarFile* &ciftiScalarShapeFileOut, int32_t& ciftiScalarhapeFileMapIndexOut, std::vector& ciftiScalarNotShapeFilesOut) const { ciftiScalarShapeFileOut = NULL; ciftiScalarhapeFileMapIndexOut = -1; ciftiScalarNotShapeFilesOut.clear(); CiftiBrainordinateScalarFile* depthMetricFile = NULL; int32_t depthMapIndex = -1; CiftiBrainordinateScalarFile* depthNamedMetricFile = NULL; CiftiBrainordinateScalarFile* curvatureMetricFile = NULL; int32_t curvatureMapIndex = -1; CiftiBrainordinateScalarFile* curvatureNamedMetricFile = NULL; CiftiBrainordinateScalarFile* shapeNamedMetricFile = NULL; CiftiBrainordinateScalarFile* sulcMetricFile = NULL; int32_t sulcMapIndex = -1; CiftiBrainordinateScalarFile* sulcNamedMetricFile = NULL; const int numFiles = static_cast(m_connectivityDenseScalarFiles.size()); for (int32_t i = 0; i < numFiles; i++) { CiftiBrainordinateScalarFile* cf = m_connectivityDenseScalarFiles[i]; const AString filename = cf->getFileNameNoPath().toLower(); const int32_t numMaps = cf->getNumberOfMaps(); for (int32_t j = 0; j < numMaps; j++) { const AString mapName = cf->getMapName(j).toLower(); if (mapName.contains("sulc")) { if (sulcMetricFile == NULL) { sulcMetricFile = cf; sulcMapIndex = j; } } else if (mapName.contains("depth")) { if (depthMetricFile == NULL) { depthMetricFile = cf; depthMapIndex = j; } } else if (mapName.contains("curv")) { if (curvatureMetricFile == NULL) { curvatureMetricFile = cf; curvatureMapIndex = j; } } } if (filename.contains("sulc")) { if (numMaps > 0) { sulcNamedMetricFile = cf; } } if (filename.contains("shape")) { if (numMaps > 0) { shapeNamedMetricFile = cf; } } if (filename.contains("curv")) { if (numMaps > 0) { curvatureNamedMetricFile = cf; } } if (filename.contains("depth")) { if (numMaps > 0) { depthNamedMetricFile = cf; } } } if (sulcMetricFile != NULL) { ciftiScalarShapeFileOut = sulcMetricFile; ciftiScalarhapeFileMapIndexOut = sulcMapIndex; } else if (depthMetricFile != NULL) { ciftiScalarShapeFileOut = depthMetricFile; ciftiScalarhapeFileMapIndexOut = depthMapIndex; } else if (curvatureMetricFile != NULL) { ciftiScalarShapeFileOut = curvatureMetricFile; ciftiScalarhapeFileMapIndexOut = curvatureMapIndex; } else if (sulcNamedMetricFile != NULL) { ciftiScalarShapeFileOut = sulcNamedMetricFile; ciftiScalarhapeFileMapIndexOut = 0; } else if (depthNamedMetricFile != NULL) { ciftiScalarShapeFileOut = depthNamedMetricFile; ciftiScalarhapeFileMapIndexOut = 0; } else if (curvatureNamedMetricFile != NULL) { ciftiScalarShapeFileOut = curvatureNamedMetricFile; ciftiScalarhapeFileMapIndexOut = 0; } else if (shapeNamedMetricFile != NULL) { ciftiScalarShapeFileOut = shapeNamedMetricFile; ciftiScalarhapeFileMapIndexOut = 0; } /* * Get all shape type files (NULLs okay) */ std::vector ciftiShapeFiles; ciftiShapeFiles.push_back(sulcMetricFile); ciftiShapeFiles.push_back(depthMetricFile); ciftiShapeFiles.push_back(curvatureMetricFile); ciftiShapeFiles.push_back(sulcNamedMetricFile); ciftiShapeFiles.push_back(depthNamedMetricFile); ciftiShapeFiles.push_back(curvatureNamedMetricFile); ciftiShapeFiles.push_back(shapeNamedMetricFile); /* * Find files that are NOT shape files */ for (int32_t i = 0; i < numFiles; i++) { CiftiBrainordinateScalarFile* cf = m_connectivityDenseScalarFiles[i]; if (std::find(ciftiShapeFiles.begin(), ciftiShapeFiles.end(), cf) == ciftiShapeFiles.end()) { ciftiScalarNotShapeFilesOut.push_back(cf); } } } /** * Read a connectivity fiber orientation file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @throws DataFileException * If reading failed. */ CiftiFiberOrientationFile* Brain::addReadOrReloadConnectivityFiberOrientationFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename) { CiftiFiberOrientationFile* cfof = NULL; if (caretDataFile != NULL) { cfof = dynamic_cast(caretDataFile); CaretAssert(cfof); } else { cfof = new CiftiFiberOrientationFile(); } bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { try { try { cfof->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } } catch (const DataFileException& dfe) { if (caretDataFile != NULL) { removeAndDeleteDataFile(caretDataFile); } else { delete cfof; } throw dfe; } } /* * If first fiber orientation file, default the above and below limits * to +/- one-half voxel size. */ if (m_connectivityFiberOrientationFiles.empty()) { float voxelSizes[3]; cfof->getVolumeSpacing(voxelSizes); float maxVoxelSize = std::max(std::fabs(voxelSizes[0]), std::max(std::fabs(voxelSizes[1]), std::fabs(voxelSizes[2]))); if (maxVoxelSize <= 0.0) { maxVoxelSize = 1.0; } const float aboveLimit = maxVoxelSize; const float belowLimit = -maxVoxelSize; m_displayPropertiesFiberOrientation->setAboveAndBelowLimitsForAll(aboveLimit, belowLimit); } if (addFlag) { updateDataFileNameIfDuplicate(m_connectivityFiberOrientationFiles, cfof); m_connectivityFiberOrientationFiles.push_back(cfof); } return cfof; } /** * Read a connectivity fiber trajectory file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @throws DataFileException * If reading failed. */ CiftiFiberTrajectoryFile* Brain::addReadOrReloadConnectivityFiberTrajectoryFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename) { CiftiFiberTrajectoryFile* cftf = NULL; if (caretDataFile != NULL) { cftf = dynamic_cast(caretDataFile); CaretAssert(cftf); } else { cftf = new CiftiFiberTrajectoryFile(); } bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { try { try { cftf->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } } catch (const DataFileException& dfe) { if (caretDataFile != NULL) { removeAndDeleteDataFile(caretDataFile); } else { delete cftf; } throw dfe; } } if (addFlag) { updateDataFileNameIfDuplicate(m_connectivityFiberTrajectoryFiles, cftf); m_connectivityFiberTrajectoryFiles.push_back(cftf); } return cftf; } /** * Read a connectivity parcel file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @throws DataFileException * If reading failed. */ CiftiConnectivityMatrixParcelFile* Brain::addReadOrReloadConnectivityMatrixParcelFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename) { CiftiConnectivityMatrixParcelFile* file = NULL; if (caretDataFile != NULL) { file = dynamic_cast(caretDataFile); CaretAssert(file); } else { file = new CiftiConnectivityMatrixParcelFile(); } bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { try { try { file->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } validateCiftiMappableDataFile(file); } catch (const DataFileException& dfe) { if (caretDataFile != NULL) { removeAndDeleteDataFile(caretDataFile); } else { delete file; } throw dfe; } } if (addFlag) { updateDataFileNameIfDuplicate(m_connectivityMatrixParcelFiles, file); m_connectivityMatrixParcelFiles.push_back(file); } return file; } /** * Read a connectivity parcel dense file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @throws DataFileException * If reading failed. */ CiftiConnectivityMatrixParcelDenseFile* Brain::addReadOrReloadConnectivityMatrixParcelDenseFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename) { CiftiConnectivityMatrixParcelDenseFile* file = NULL; if (caretDataFile != NULL) { file = dynamic_cast(caretDataFile); CaretAssert(file); } else { file = new CiftiConnectivityMatrixParcelDenseFile(); } bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { try { try { file->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } validateCiftiMappableDataFile(file); } catch (const DataFileException& dfe) { if (caretDataFile != NULL) { removeAndDeleteDataFile(caretDataFile); } else { delete file; } throw dfe; } } if (addFlag) { updateDataFileNameIfDuplicate(m_connectivityMatrixParcelDenseFiles, file); m_connectivityMatrixParcelDenseFiles.push_back(file); } return file; } /** * Initialize a data series file's dense connectivity */ void Brain::initializeDenseDataSeriesFile(CiftiBrainordinateDataSeriesFile* dataSeriesFile) { /* * Enable dynamic connectivity using preferences */ CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); CiftiConnectivityMatrixDenseDynamicFile* denseDynFile = dataSeriesFile->getConnectivityMatrixDenseDynamicFile(); denseDynFile->setEnabledAsLayer(prefs->isDynamicConnectivityDefaultedOn()); } /** * Read a connectivity data series file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @throws DataFileException * If reading failed. */ CiftiBrainordinateDataSeriesFile* Brain::addReadOrReloadConnectivityDataSeriesFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename) { CiftiBrainordinateDataSeriesFile* file = NULL; if (caretDataFile != NULL) { file = dynamic_cast(caretDataFile); CaretAssert(file); } else { file = new CiftiBrainordinateDataSeriesFile(); } bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { try { try { file->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } validateCiftiMappableDataFile(file); } catch (const DataFileException& dfe) { if (caretDataFile != NULL) { removeAndDeleteDataFile(caretDataFile); } else { delete file; } throw dfe; } } if (addFlag) { updateDataFileNameIfDuplicate(m_connectivityDataSeriesFiles, file); m_connectivityDataSeriesFiles.push_back(file); } initializeDenseDataSeriesFile(file); return file; } /** * Read a palette file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @throws DataFileException * If reading failed. */ PaletteFile* Brain::addReadOrReloadPaletteFile(const FileModeAddReadReload fileMode, CaretDataFile* /*caretDataFile*/, const AString& filename) { bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { } if (addFlag) { } throw DataFileException(filename, "Reading not implemented for: palette"); return NULL; } /** * Read a scene file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param filename * Name of the file. * @throws DataFileException * If reading failed. */ SceneFile* Brain::addReadOrReloadSceneFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename) { SceneFile* sf = NULL; if (caretDataFile != NULL) { sf = dynamic_cast(caretDataFile); CaretAssert(sf); } else { sf = new SceneFile(); } bool addFlag = false; bool readFlag = false; switch (fileMode) { case FILE_MODE_ADD: addFlag = true; break; case FILE_MODE_READ: addFlag = true; readFlag = true; break; case FILE_MODE_RELOAD: readFlag = true; break; } if (readFlag) { try { try { /* * Add to recent scene files */ if (FileInformation(filename).exists()) { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->addToPreviousSceneFiles(filename); } sf->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, CaretDataFileHelper::createBadAllocExceptionMessage(filename)); } } catch (DataFileException& dfe) { if (caretDataFile != NULL) { removeAndDeleteDataFile(caretDataFile); } else { delete sf; } throw dfe; } } if (addFlag) { updateDataFileNameIfDuplicate(m_sceneFiles, sf); m_sceneFiles.push_back(sf); } return sf; } /** * @return Number of connectivity matrix dense files. */ int32_t Brain::getNumberOfConnectivityMatrixDenseFiles() const { return m_connectivityMatrixDenseFiles.size(); } /** * Get the connectivity dense file at the given index. * @param indx * Index of file. * @return Conectivity dense file at index. */ CiftiConnectivityMatrixDenseFile* Brain::getConnectivityMatrixDenseFile(int32_t indx) { CaretAssertVectorIndex(m_connectivityMatrixDenseFiles, indx); return m_connectivityMatrixDenseFiles[indx]; } /** * Get the connectivity dense file at the given index. * @param indx * Index of file. * @return Conectivity dense file at index. */ const CiftiConnectivityMatrixDenseFile* Brain::getConnectivityMatrixDenseFile(int32_t indx) const { CaretAssertVectorIndex(m_connectivityMatrixDenseFiles, indx); return m_connectivityMatrixDenseFiles[indx]; } /** * Get ALL connectivity matrix dense files. * @param connectivityFilesOut * Contains all connectivity dense files on exit. */ void Brain::getConnectivityMatrixDenseFiles(std::vector& connectivityDenseFilesOut) const { connectivityDenseFilesOut = m_connectivityMatrixDenseFiles; } /** * Get ALL connectivity matrix dense dynamic files. * @param connectivityDenseDynamicFilesOut * Contains all connectivity dense dynamic files on exit. */ void Brain::getConnectivityMatrixDenseDynamicFiles(std::vector& connectivityDenseDynamicFilesOut) const { connectivityDenseDynamicFilesOut.clear(); for (std::vector::const_iterator iter = m_connectivityDataSeriesFiles.begin(); iter != m_connectivityDataSeriesFiles.end(); iter++) { CiftiConnectivityMatrixDenseDynamicFile* denseDynFile = (*iter)->getConnectivityMatrixDenseDynamicFile(); CaretAssert(denseDynFile); if (denseDynFile->isDataValid()) { connectivityDenseDynamicFilesOut.push_back(denseDynFile); } } } /** * @return Number of connectivity dense label files. */ int32_t Brain::getNumberOfConnectivityDenseLabelFiles() const { return m_connectivityDenseLabelFiles.size(); } /** * Get the connectivity dense label file at the given index. * @param indx * Index of file. * @return Conectivity dense label file at index. */ CiftiBrainordinateLabelFile* Brain::getConnectivityDenseLabelFile(int32_t indx) { CaretAssertVectorIndex(m_connectivityDenseLabelFiles, indx); return m_connectivityDenseLabelFiles[indx]; } /** * Get the connectivity dense label file at the given index. * @param indx * Index of file. * @return Conectivity dense label file at index. */ const CiftiBrainordinateLabelFile* Brain::getConnectivityDenseLabelFile(int32_t indx) const { CaretAssertVectorIndex(m_connectivityDenseLabelFiles, indx); return m_connectivityDenseLabelFiles[indx]; } /** * Get ALL connectivity dense label files. * @param connectivityDenseLabelFilesOut * Contains all connectivity dense labelfiles on exit. */ void Brain::getConnectivityDenseLabelFiles(std::vector& connectivityDenseLabelFilesOut) const { connectivityDenseLabelFilesOut = m_connectivityDenseLabelFiles; } /** * Get all of the CIFTI Mappable Data Files * @param allCiftiMappableDataFilesOut * Contains all CIFTI Mappable Data files upon exit. */ void Brain::getAllCiftiMappableDataFiles(std::vector& allCiftiMappableDataFilesOut) const { allCiftiMappableDataFilesOut.clear(); std::vector allFiles; getAllDataFiles(allFiles); for (std::vector::iterator iter = allFiles.begin(); iter != allFiles.end(); iter++) { CiftiMappableDataFile* cmdf = dynamic_cast(*iter); if (cmdf != NULL) { allCiftiMappableDataFilesOut.push_back(cmdf); } } } /** * Get all of the Brainordinate Chartable Data Files. Only files that implement the * ChartableLineSeriesBrainordinateInterface AND return true for ChartableLineSeriesBrainordinateInterface::isLineSeriesChartDataTypeSupported() * are included in the returned files. * * @param chartableDataFilesOut * Contains all chartable data files upon exit. */ void Brain::getAllChartableBrainordinateDataFiles(std::vector& chartableDataFilesOut) const { chartableDataFilesOut.clear(); std::vector allFiles; getAllDataFiles(allFiles); for (std::vector::iterator iter = allFiles.begin(); iter != allFiles.end(); iter++) { ChartableLineSeriesBrainordinateInterface* chartFile = dynamic_cast(*iter); if (chartFile != NULL) { if (chartFile->isLineSeriesChartingSupported()) { chartableDataFilesOut.push_back(chartFile); } } } } /** * Get all of the Line Series Chartable Data Files. Only files that implement the * ChartableLineSeriesInterface AND return true for ChartableLineSeriesInterface::isLineSeriesChartDataTypeSupported() * are included in the returned files. * * @param chartableDataFilesOut * Contains all chartable data files upon exit. */ void Brain::getAllChartableLineSeriesDataFiles(std::vector& chartableDataFilesOut) const { chartableDataFilesOut.clear(); std::vector allFiles; getAllDataFiles(allFiles); for (std::vector::iterator iter = allFiles.begin(); iter != allFiles.end(); iter++) { ChartableLineSeriesInterface* chartFile = dynamic_cast(*iter); if (chartFile != NULL) { if (chartFile->isLineSeriesChartingSupported()) { chartableDataFilesOut.push_back(chartFile); } } } } /** * Get all of the Line Series Chartable Data Files. Only files that implement the * ChartableLineSeriesInterface AND return true for ChartableLineSeriesInterface::isLineSeriesChartDataTypeSupported() * and support a chart of the given data type are included in the returned files. * * @param chartDataType * Desired chart data type. * @param chartableDataFilesOut * Contains all chartable data files upon exit. */ void Brain::getAllChartableLineSeriesDataFilesForChartDataType(const ChartOneDataTypeEnum::Enum chartDataType, std::vector& chartableDataFilesOut) const { chartableDataFilesOut.clear(); std::vector chartFiles; getAllChartableLineSeriesDataFiles(chartFiles); for (std::vector::iterator iter = chartFiles.begin(); iter != chartFiles.end(); iter++) { ChartableLineSeriesInterface* chartFile = *iter; if (chartFile->isLineSeriesChartDataTypeSupported(chartDataType)) { chartableDataFilesOut.push_back(chartFile); } } } /** * Get all of the Brainordinate Chartable Data Files. Only files that implement the * ChartableLineSeriesBrainordinateInterface, return true for ChartableLineSeriesBrainordinateInterface::isChartingSupported(), * AND return true for ChartableLineSeriesBrainordinateInterface::isChartingEnabled() for any tab index * are included in the returned files. * * @param chartableDataFilesOut * Contains all chartable data files upon exit. */ void Brain::getAllChartableBrainordinateDataFilesWithChartingEnabled(std::vector& chartableDataFilesOut) const { chartableDataFilesOut.clear(); std::vector allFiles; getAllDataFiles(allFiles); EventBrowserTabGetAll allTabsEvent; EventManager::get()->sendEvent(allTabsEvent.getPointer()); const std::vector tabIndices = allTabsEvent.getBrowserTabIndices(); const int32_t numTabs = static_cast(tabIndices.size()); for (std::vector::iterator iter = allFiles.begin(); iter != allFiles.end(); iter++) { ChartableLineSeriesBrainordinateInterface* chartFile = dynamic_cast(*iter); if (chartFile != NULL) { if (chartFile->isLineSeriesChartingSupported()) { for (int32_t iTab = 0; iTab < numTabs; iTab++) { const int32_t tabIndex = tabIndices[iTab]; if (chartFile->isLineSeriesChartingEnabled(tabIndex)) { chartableDataFilesOut.push_back(chartFile); break; } } } } } } /** * Get all of the Chartable Matrix Data Files. Only files that implement the * ChartableMatrixInterface AND return true for ChartableMatrixInterface::isChartingSupported() * are included in the returned files. * * @param chartableDataFilesOut * Contains all chartable data files upon exit. */ void Brain::getAllChartableMatrixDataFiles(std::vector& chartableDataFilesOut) const { chartableDataFilesOut.clear(); std::vector allFiles; getAllDataFiles(allFiles); for (std::vector::iterator iter = allFiles.begin(); iter != allFiles.end(); iter++) { ChartableMatrixInterface* chartFile = dynamic_cast(*iter); if (chartFile != NULL) { if (chartFile->isMatrixChartingSupported()) { chartableDataFilesOut.push_back(chartFile); } } } } /** * Get all of the Chartable Matrix Data Files. Only files that implement the * ChartableMatrixInterface AND return true for ChartableMatrixInterface::isChartingSupported() * and support a chart of the given data type are included in the returned files. * * @param chartDataType * Desired chart data type. * @param chartableDataFilesOut * Contains all chartable data files upon exit. */ void Brain::getAllChartableMatrixDataFilesForChartDataType(const ChartOneDataTypeEnum::Enum chartDataType, std::vector& chartableDataFilesOut) const { chartableDataFilesOut.clear(); std::vector chartFiles; getAllChartableMatrixDataFiles(chartFiles); for (std::vector::iterator iter = chartFiles.begin(); iter != chartFiles.end(); iter++) { ChartableMatrixInterface* chartFile = *iter; if (chartFile->isMatrixChartDataTypeSupported(chartDataType)) { chartableDataFilesOut.push_back(chartFile); } } } /** * @return Number of cifti dense parcel files. */ int32_t Brain::getNumberOfConnectivityMatrixDenseParcelFiles() const { return m_connectivityMatrixDenseParcelFiles.size(); } /** * Get the cifti dense parcel file at the given index. * @param indx * Index of file. * @return cifti dense parcel file at index. */ CiftiConnectivityMatrixDenseParcelFile* Brain::getConnectivityMatrixDenseParcelFile(int32_t indx) { CaretAssertVectorIndex(m_connectivityMatrixDenseParcelFiles, indx); return m_connectivityMatrixDenseParcelFiles[indx]; } /** * Get the connectivity dense parcel file at the given index. * @param indx * Index of file. * @return cifti dense parcel file at index. */ const CiftiConnectivityMatrixDenseParcelFile* Brain::getConnectivityMatrixDenseParcelFile(int32_t indx) const { CaretAssertVectorIndex(m_connectivityMatrixDenseParcelFiles, indx); return m_connectivityMatrixDenseParcelFiles[indx]; } /** * Get ALL cifti dense parcel files. * @param connectivityFilesOut * Contains all cifti dense parcel files on exit. */ void Brain::getConnectivityMatrixDenseParcelFiles(std::vector& connectivityDenseParcelFilesOut) const { connectivityDenseParcelFilesOut = m_connectivityMatrixDenseParcelFiles; } /** * @return Number of connectivity dense scalar files. */ int32_t Brain::getNumberOfConnectivityDenseScalarFiles() const { return m_connectivityDenseScalarFiles.size(); } /** * Get the connectivity dense scalar file at the given index. * @param indx * Index of file. * @return Conectivity dense scalar file at index. */ CiftiBrainordinateScalarFile* Brain::getConnectivityDenseScalarFile(int32_t indx) { CaretAssertVectorIndex(m_connectivityDenseScalarFiles, indx); return m_connectivityDenseScalarFiles[indx]; } /** * Get the connectivity dense scalar file at the given index. * @param indx * Index of file. * @return Conectivity dense scalar file at index. */ const CiftiBrainordinateScalarFile* Brain::getConnectivityDenseScalarFile(int32_t indx) const { CaretAssertVectorIndex(m_connectivityDenseScalarFiles, indx); return m_connectivityDenseScalarFiles[indx]; } /** * Get ALL connectivity dense scalr files. * @param connectivityDenseScalarFilesOut * Contains all connectivity dense files on exit. */ void Brain::getConnectivityDenseScalarFiles(std::vector& connectivityDenseScalarFilesOut) const { connectivityDenseScalarFilesOut = m_connectivityDenseScalarFiles; } /** * @return Number of connectivity parcel label files. */ int32_t Brain::getNumberOfConnectivityParcelLabelFiles() const { return m_connectivityParcelLabelFiles.size(); } /** * Get the connectivity parcel label file at the given index. * @param indx * Index of file. * @return Connectivity parcel label file at index. */ CiftiParcelLabelFile* Brain::getConnectivityParcelLabelFile(int32_t indx) { CaretAssertVectorIndex(m_connectivityParcelLabelFiles, indx); return m_connectivityParcelLabelFiles[indx]; } /** * Get the connectivity parcel label file at the given index. * @param indx * Index of file. * @return Connectivity parcel label file at index. */ const CiftiParcelLabelFile* Brain::getConnectivityParcelLabelFile(int32_t indx) const { CaretAssertVectorIndex(m_connectivityParcelLabelFiles, indx); return m_connectivityParcelLabelFiles[indx]; } /** * Get ALL connectivity parcel label files. * @param connectivityParcelLabelFilesOut * Contains all connectivity parcel label files on exit. */ void Brain::getConnectivityParcelLabelFiles(std::vector& connectivityParcelLabelFilesOut) const { connectivityParcelLabelFilesOut = m_connectivityParcelLabelFiles; } /** * @return Number of connectivity parcel scalar files. */ int32_t Brain::getNumberOfConnectivityParcelScalarFiles() const { return m_connectivityParcelScalarFiles.size(); } /** * Get the connectivity parcel scalar file at the given index. * @param indx * Index of file. * @return Connectivity parcel scalar file at index. */ CiftiParcelScalarFile* Brain::getConnectivityParcelScalarFile(int32_t indx) { CaretAssertVectorIndex(m_connectivityParcelScalarFiles, indx); return m_connectivityParcelScalarFiles[indx]; } /** * Get the connectivity parcel scalar file at the given index. * @param indx * Index of file. * @return Connectivity parcel scalar file at index. */ const CiftiParcelScalarFile* Brain::getConnectivityParcelScalarFile(int32_t indx) const { CaretAssertVectorIndex(m_connectivityParcelScalarFiles, indx); return m_connectivityParcelScalarFiles[indx]; } /** * Get ALL connectivity parcel scalar files. * @param connectivityParcelScalarFilesOut * Contains all connectivity parcel files on exit. */ void Brain::getConnectivityParcelScalarFiles(std::vector& connectivityParcelScalarFilesOut) const { connectivityParcelScalarFilesOut = m_connectivityParcelScalarFiles; } /** * @return Number of connectivity parcel scalar files. */ int32_t Brain::getNumberOfConnectivityScalarDataSeriesFiles() const { return m_connectivityScalarDataSeriesFiles.size(); } /** * Get the connectivity parcel scalar file at the given index. * @param indx * Index of file. * @return Connectivity parcel scalar file at index. */ CiftiScalarDataSeriesFile* Brain::getConnectivityScalarDataSeriesFile(int32_t indx) { CaretAssertVectorIndex(m_connectivityScalarDataSeriesFiles, indx); return m_connectivityScalarDataSeriesFiles[indx]; } /** * Get the connectivity parcel scalar file at the given index. * @param indx * Index of file. * @return Connectivity parcel scalar file at index. */ const CiftiScalarDataSeriesFile* Brain::getConnectivityScalarDataSeriesFile(int32_t indx) const { CaretAssertVectorIndex(m_connectivityScalarDataSeriesFiles, indx); return m_connectivityScalarDataSeriesFiles[indx]; } /** * Get ALL connectivity parcel scalar files. * @param connectivityScalarDataSeriesFilesOut * Contains all connectivity parcel files on exit. */ void Brain::getConnectivityScalarDataSeriesFiles(std::vector& connectivityScalarDataSeriesFilesOut) const { connectivityScalarDataSeriesFilesOut = m_connectivityScalarDataSeriesFiles; } /** * @return Number of connectivity parcel data series files. */ int32_t Brain::getNumberOfConnectivityParcelSeriesFiles() const { return m_connectivityParcelSeriesFiles.size(); } /** * Get the connectivity parcel data series file at the given index. * @param indx * Index of file. * @return Connectivity parcel data series file at index. */ CiftiParcelSeriesFile* Brain::getConnectivityParcelSeriesFile(int32_t indx) { CaretAssertVectorIndex(m_connectivityParcelSeriesFiles, indx); return m_connectivityParcelSeriesFiles[indx]; } /** * Get the connectivity parcel data series file at the given index. * @param indx * Index of file. * @return Connectivity parcel data series file at index. */ const CiftiParcelSeriesFile* Brain::getConnectivityParcelSeriesFile(int32_t indx) const { CaretAssertVectorIndex(m_connectivityParcelSeriesFiles, indx); return m_connectivityParcelSeriesFiles[indx]; } /** * Get ALL connectivity parcel data series files. * @param connectivityParcelSeriesFilesOut * Contains all connectivity parcel files on exit. */ void Brain::getConnectivityParcelSeriesFiles(std::vector& connectivityParcelSeriesFilesOut) const { connectivityParcelSeriesFilesOut = m_connectivityParcelSeriesFiles; } /** * @return Number of connectivity fiber orientation files. */ int32_t Brain::getNumberOfConnectivityFiberOrientationFiles() const { return m_connectivityFiberOrientationFiles.size(); } /** * Get the connectivity fiber orientation file at the given index. * @param indx * Index of file. * @return Conectivity fiber orientation file at index. */ CiftiFiberOrientationFile* Brain::getConnectivityFiberOrientationFile(int32_t indx) { CaretAssertVectorIndex(m_connectivityFiberOrientationFiles, indx); return m_connectivityFiberOrientationFiles[indx]; } /** * Get the connectivity fiber orientation file at the given index. * @param indx * Index of file. * @return Conectivity fiber orientation file at index. */ const CiftiFiberOrientationFile* Brain::getConnectivityFiberOrientationFile(int32_t indx) const { CaretAssertVectorIndex(m_connectivityFiberOrientationFiles, indx); return m_connectivityFiberOrientationFiles[indx]; } /** * Get ALL connectivity fiber orientation files. * @param connectivityFiberOrientationFilesOut * Contains all connectivity fiber orientation files on exit. */ void Brain::getConnectivityFiberOrientationFiles(std::vector& connectivityFiberOrientationFilesOut) const { connectivityFiberOrientationFilesOut = m_connectivityFiberOrientationFiles; } /** * @return Number of connectivity fiber trajectory files. */ int32_t Brain::getNumberOfConnectivityFiberTrajectoryFiles() const { return m_connectivityFiberTrajectoryFiles.size(); } /** * Get the connectivity fiber trajectory file at the given index. * @param indx * Index of file. * @return Conectivity fiber trajectory file at index. */ CiftiFiberTrajectoryFile* Brain::getConnectivityFiberTrajectoryFile(int32_t indx) { CaretAssertVectorIndex(m_connectivityFiberTrajectoryFiles, indx); return m_connectivityFiberTrajectoryFiles[indx]; } /** * Get the connectivity fiber trajectory file at the given index. * @param indx * Index of file. * @return Conectivity fiber trajectory file at index. */ const CiftiFiberTrajectoryFile* Brain::getConnectivityFiberTrajectoryFile(int32_t indx) const { CaretAssertVectorIndex(m_connectivityFiberTrajectoryFiles, indx); return m_connectivityFiberTrajectoryFiles[indx]; } /** * Get ALL connectivity fiber trajectory files. * @param connectivityFiberTrajectoryFilesOut * Contains all connectivity fiber trajectory files on exit. */ void Brain::getConnectivityFiberTrajectoryFiles(std::vector& connectivityFiberTrajectoryFilesOut) const { connectivityFiberTrajectoryFilesOut = m_connectivityFiberTrajectoryFiles; } /** * @return Number of cifti parcel files. */ int32_t Brain::getNumberOfConnectivityMatrixParcelFiles() const { return m_connectivityMatrixParcelFiles.size(); } /** * Get the cifti parcel file at the given index. * @param indx * Index of file. * @return cifti parcel file at index. */ CiftiConnectivityMatrixParcelFile* Brain::getConnectivityMatrixParcelFile(int32_t indx) { CaretAssertVectorIndex(m_connectivityMatrixParcelFiles, indx); return m_connectivityMatrixParcelFiles[indx]; } /** * Get the connectivity parcel file at the given index. * @param indx * Index of file. * @return cifti parcel file at index. */ const CiftiConnectivityMatrixParcelFile* Brain::getConnectivityMatrixParcelFile(int32_t indx) const { CaretAssertVectorIndex(m_connectivityMatrixParcelFiles, indx); return m_connectivityMatrixParcelFiles[indx]; } /** * Get ALL cifti parcel files. * @param connectivityFilesOut * Contains all cifti parcel files on exit. */ void Brain::getConnectivityMatrixParcelFiles(std::vector& connectivityParcelFilesOut) const { connectivityParcelFilesOut = m_connectivityMatrixParcelFiles; } /** * @return Number of cifti parcel dense files. */ int32_t Brain::getNumberOfConnectivityMatrixParcelDenseFiles() const { return m_connectivityMatrixParcelDenseFiles.size(); } /** * Get the cifti parcel dense file at the given index. * @param indx * Index of file. * @return cifti parcel dense file at index. */ CiftiConnectivityMatrixParcelDenseFile* Brain::getConnectivityMatrixParcelDenseFile(int32_t indx) { CaretAssertVectorIndex(m_connectivityMatrixParcelDenseFiles, indx); return m_connectivityMatrixParcelDenseFiles[indx]; } /** * Get the connectivity parcel dense file at the given index. * @param indx * Index of file. * @return cifti parcel dense file at index. */ const CiftiConnectivityMatrixParcelDenseFile* Brain::getConnectivityMatrixParcelDenseFile(int32_t indx) const { CaretAssertVectorIndex(m_connectivityMatrixParcelDenseFiles, indx); return m_connectivityMatrixParcelDenseFiles[indx]; } /** * Get ALL cifti parcel dense files. * @param connectivityFilesOut * Contains all cifti parcel dense files on exit. */ void Brain::getConnectivityMatrixParcelDenseFiles(std::vector& connectivityParcelDenseFilesOut) const { connectivityParcelDenseFilesOut = m_connectivityMatrixParcelDenseFiles; } /** * @return Number of cifti data series files. */ int32_t Brain::getNumberOfConnectivityDataSeriesFiles() const { return m_connectivityDataSeriesFiles.size(); } /** * Get the cifti data series file at the given index. * @param indx * Index of file. * @return cifti data series file at index. */ CiftiBrainordinateDataSeriesFile* Brain::getConnectivityDataSeriesFile(int32_t indx) { CaretAssertVectorIndex(m_connectivityDataSeriesFiles, indx); return m_connectivityDataSeriesFiles[indx]; } /** * Get the connectivity data series file at the given index. * @param indx * Index of file. * @return cifti data series file at index. */ const CiftiBrainordinateDataSeriesFile* Brain::getConnectivityDataSeriesFile(int32_t indx) const { CaretAssertVectorIndex(m_connectivityDataSeriesFiles, indx); return m_connectivityDataSeriesFiles[indx]; } /** * Get ALL cifti data series files. * @param connectivityDataSeriesFilesOut * Contains all cifti data series files on exit. */ void Brain::getConnectivityDataSeriesFiles(std::vector& connectivityDataSeriesFilesOut) const { connectivityDataSeriesFilesOut = m_connectivityDataSeriesFiles; } /** * Get all of the cifti connectivity type data files. * * param allCiftiConnectivityMatrixFiles * Will contain the files upon exit. */ void Brain::getAllCiftiConnectivityMatrixFiles(std::vector& allCiftiConnectivityMatrixFiles) const { allCiftiConnectivityMatrixFiles.clear(); std::vector allFiles; getAllDataFiles(allFiles); for (std::vector::iterator iter = allFiles.begin(); iter != allFiles.end(); iter++) { CiftiMappableConnectivityMatrixDataFile* cmdf = dynamic_cast(*iter); if (cmdf != NULL) { allCiftiConnectivityMatrixFiles.push_back(cmdf); } } } /** * Add a data file to the brain. * * This will add the file to its corresponding data file type and add the * file into the spec file. * * @param caretDataFile * The caret data file. * @throw DataFileException * If there is an error. */ void Brain::addDataFile(CaretDataFile* caretDataFile) { CaretAssert(caretDataFile); caretDataFile->setFileName(convertFilePathNameToAbsolutePathName(caretDataFile->getFileName())); const StructureEnum::Enum structure = caretDataFile->getStructure(); BrainStructure* brainStructure = getBrainStructure(structure, false); const DataFileTypeEnum::Enum dataFileType = caretDataFile->getDataFileType(); switch (dataFileType) { case DataFileTypeEnum::ANNOTATION: { AnnotationFile* file = dynamic_cast(caretDataFile); CaretAssert(file); m_annotationFiles.push_back(file); } break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: { AnnotationTextSubstitutionFile* file = dynamic_cast(caretDataFile); CaretAssert(file); m_annotationSubstitutionFiles.push_back(file); } break; case DataFileTypeEnum::BORDER: { BorderFile* file = dynamic_cast(caretDataFile); CaretAssert(file); m_borderFiles.push_back(file); } break; case DataFileTypeEnum::CONNECTIVITY_DENSE: { CiftiConnectivityMatrixDenseFile* file = dynamic_cast(caretDataFile); CaretAssert(file); m_connectivityMatrixDenseFiles.push_back(file); } break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: CaretAssertMessage(0, "Dense Dynamic Files should never be added to Brain."); break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: { CiftiBrainordinateLabelFile* file = dynamic_cast(caretDataFile); CaretAssert(file); m_connectivityDenseLabelFiles.push_back(file); } break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: { CiftiConnectivityMatrixDenseParcelFile* file = dynamic_cast(caretDataFile); CaretAssert(file); m_connectivityMatrixDenseParcelFiles.push_back(file); } break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: { CiftiBrainordinateScalarFile* file = dynamic_cast(caretDataFile); CaretAssert(file); m_connectivityDenseScalarFiles.push_back(file); } break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: { CiftiBrainordinateDataSeriesFile* file = dynamic_cast(caretDataFile); CaretAssert(file); initializeDenseDataSeriesFile(file); m_connectivityDataSeriesFiles.push_back(file); } break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: { CiftiFiberOrientationFile* file = dynamic_cast(caretDataFile); CaretAssert(file); m_connectivityFiberOrientationFiles.push_back(file); } break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: { CiftiFiberTrajectoryFile* file = dynamic_cast(caretDataFile); CaretAssert(file); m_connectivityFiberTrajectoryFiles.push_back(file); } break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: { CiftiConnectivityMatrixParcelFile* file = dynamic_cast(caretDataFile); CaretAssert(file); m_connectivityMatrixParcelFiles.push_back(file); } break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: { CiftiConnectivityMatrixParcelDenseFile* file = dynamic_cast(caretDataFile); CaretAssert(file); m_connectivityMatrixParcelDenseFiles.push_back(file); } break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: { CiftiParcelLabelFile* file = dynamic_cast(caretDataFile); CaretAssert(file); m_connectivityParcelLabelFiles.push_back(file); } break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: { CiftiParcelScalarFile* file = dynamic_cast(caretDataFile); CaretAssert(file); m_connectivityParcelScalarFiles.push_back(file); } break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: { CiftiParcelSeriesFile* file = dynamic_cast(caretDataFile); CaretAssert(file); m_connectivityParcelSeriesFiles.push_back(file); } break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: { CiftiScalarDataSeriesFile* file = dynamic_cast(caretDataFile); CaretAssert(file); m_connectivityScalarDataSeriesFiles.push_back(file); } break; case DataFileTypeEnum::FOCI: { FociFile* file = dynamic_cast(caretDataFile); CaretAssert(file); m_fociFiles.push_back(file); } break; case DataFileTypeEnum::IMAGE: { ImageFile* file = dynamic_cast(caretDataFile); CaretAssert(file); m_imageFiles.push_back(file); } break; case DataFileTypeEnum::LABEL: { LabelFile* file = dynamic_cast(caretDataFile); CaretAssert(file); if (structure == StructureEnum::INVALID) { throw DataFileException(file->getFileName(), "Structure in label file is INVALID."); } if (brainStructure == NULL) { throw DataFileException(file->getFileName(), "Must load surface(s) with matching structure prior to label files"); } brainStructure->addLabelFile(file, true); } break; case DataFileTypeEnum::METRIC: { MetricFile* file = dynamic_cast(caretDataFile); CaretAssert(file); if (structure == StructureEnum::INVALID) { throw DataFileException(file->getFileName(), "Structure in metric file is INVALID."); } if (brainStructure == NULL) { throw DataFileException(file->getFileName(), "Must load surface(s) with matching structure prior to metric files"); } brainStructure->addMetricFile(file, true); } break; case DataFileTypeEnum::METRIC_DYNAMIC: CaretAssertMessage(0, "Metric dynamic files should never be added to brain"); break; case DataFileTypeEnum::PALETTE: { throw DataFileException(caretDataFile->getFileName(), "Adding palette files not supported at this time."); } break; case DataFileTypeEnum::RGBA: { RgbaFile* file = dynamic_cast(caretDataFile); CaretAssert(file); if (structure == StructureEnum::INVALID) { throw DataFileException(file->getFileName(), "Structure in rgba file is INVALID."); } if (brainStructure == NULL) { throw DataFileException(file->getFileName(), "Must load surface(s) with matching structure prior to label files"); } brainStructure->addRgbaFile(file, true); } break; case DataFileTypeEnum::SCENE: { SceneFile* file = dynamic_cast(caretDataFile); CaretAssert(file); m_sceneFiles.push_back(file); } break; case DataFileTypeEnum::SPECIFICATION: CaretLogSevere("PROGRAM ERROR: Reading spec file should never call Brain::addReadOrReloadDataFile()"); throw DataFileException(caretDataFile->getFileName(), "PROGRAM ERROR: Reading spec file should never call Brain::addReadOrReloadDataFile()"); break; case DataFileTypeEnum::SURFACE: { Surface* file = dynamic_cast(caretDataFile); if (structure == StructureEnum::INVALID) { throw DataFileException(file->getFileName(), "Structure in surface file is INVALID."); } if (file == NULL) { throw DataFileException(file->getFileName(), "Cannot add SurfaceFile but can add a Surface."); } if (brainStructure == NULL) { brainStructure = getBrainStructure(structure, true); } brainStructure->addSurface(file, true, true); } break; case DataFileTypeEnum::UNKNOWN: throw DataFileException(caretDataFile->getFileName(), "Unable to read files of type UNKNOWN. Filename extension may be invalid."); break; case DataFileTypeEnum::VOLUME: { VolumeFile* file = dynamic_cast(caretDataFile); CaretAssert(file); initializeVolumeFile(file); m_volumeFiles.push_back(file); } break; case DataFileTypeEnum::VOLUME_DYNAMIC: CaretAssertMessage(0, "Volume Dynamic files are never added to the brain"); break; } m_specFile->addCaretDataFile(caretDataFile); } /** * Get all annotation files INCLUDING the scene's annotation file. * * @param allAnnotationFilesOut * Will contain files on exit. */ void Brain::getAllAnnotationFilesIncludingSceneAnnotationFile(std::vector& annotationFilesOut) const { annotationFilesOut = m_annotationFiles; annotationFilesOut.push_back(m_sceneAnnotationFile); } /** * Get all annotation files EXCLUDING the scene's annotation file * * @param allAnnotationFilesOut * Will contain files on exit. */ void Brain::getAllAnnotationFilesExcludingSceneAnnotationFile(std::vector& annotationFilesOut) const { annotationFilesOut = m_annotationFiles; } /** * @return The annotation file associated with the current scene. */ AnnotationFile* Brain::getSceneAnnotationFile() { CaretAssert(m_sceneAnnotationFile); return m_sceneAnnotationFile; } /** * @return The annotation file associated with the current scene. */ const AnnotationFile* Brain::getSceneAnnotationFile() const { CaretAssert(m_sceneAnnotationFile); return m_sceneAnnotationFile; } /** * Get the annotation substitution files. * * @param annSubFileOut * Output containing annotation substitution files. */ void Brain::getAnnotationTextSubstitutionFiles(std::vector& annSubFilesOut) const { annSubFilesOut = m_annotationSubstitutionFiles; } /** * @return Number of border files. */ int32_t Brain::getNumberOfBorderFiles() const { return m_borderFiles.size(); } /** * @return The border file. * @param indx Index of the border file. */ BorderFile* Brain::getBorderFile(const int32_t indx) { CaretAssertVectorIndex(m_borderFiles, indx); return m_borderFiles[indx]; } /** * @return The border file. * @param indx Index of the border file. */ const BorderFile* Brain::getBorderFile(const int32_t indx) const { CaretAssertVectorIndex(m_borderFiles, indx); return m_borderFiles[indx]; } /** * @return Number of foci files. */ int32_t Brain::getNumberOfFociFiles() const { return m_fociFiles.size(); } /** * @return The foci file. * @param indx Index of the foci file. */ FociFile* Brain::getFociFile(const int32_t indx) { CaretAssertVectorIndex(m_fociFiles, indx); return m_fociFiles[indx]; } /** * @return The foci file. * @param indx Index of the foci file. */ const FociFile* Brain::getFociFile(const int32_t indx) const { CaretAssertVectorIndex(m_fociFiles, indx); return m_fociFiles[indx]; } /** * @return All image files. */ const std::vector Brain::getAllImagesFiles() const { return m_imageFiles; } /** * @return Number of image files. */ int32_t Brain::getNumberOfImageFiles() const { return m_imageFiles.size(); } /** * @return The image file. * @param indx Index of the image file. */ ImageFile* Brain::getImageFile(const int32_t indx) { CaretAssertVectorIndex(m_imageFiles, indx); return m_imageFiles[indx]; } /** * @return The image file. * @param indx Index of the image file. */ const ImageFile* Brain::getImageFile(const int32_t indx) const { CaretAssertVectorIndex(m_imageFiles, indx); return m_imageFiles[indx]; } /** * @return Number of scene files. */ int32_t Brain::getNumberOfSceneFiles() const { return m_sceneFiles.size(); } /** * @return The scene file. * @param indx Index of the scene file. */ SceneFile* Brain::getSceneFile(const int32_t indx) { CaretAssertVectorIndex(m_sceneFiles, indx); return m_sceneFiles[indx]; } /** * @return The scene file. * @param indx Index of the scene file. */ const SceneFile* Brain::getSceneFile(const int32_t indx) const { CaretAssertVectorIndex(m_sceneFiles, indx); return m_sceneFiles[indx]; } /** * @return The Spec File. */ const SpecFile* Brain::getSpecFile() const { return m_specFile; } /** * @return The Spec File. */ SpecFile* Brain::getSpecFile() { return m_specFile; } /* * @return The palette file. */ PaletteFile* Brain::getPaletteFile() { return m_paletteFile; } /* * @return The palette file. */ const PaletteFile* Brain::getPaletteFile() const { return m_paletteFile; } /** * Find the surface with the given name. * @param surfaceFileName * Name of surface. * @param useAbsolutePath * If true the given surfaceFileName is an absolute path. * If false, the given surfaceFileName is just the file * name without any path. */ Surface* Brain::getSurfaceWithName(const AString& surfaceFileName, const bool useAbsolutePath) { for (std::vector::iterator iter = m_brainStructures.begin(); iter != m_brainStructures.end(); iter++) { BrainStructure* bs = *iter; Surface* surface = bs->getSurfaceWithName(surfaceFileName, useAbsolutePath); if (surface != NULL) { return surface; } } return NULL; } /** * @return The primary anatomical surfaces from all brain structures. */ std::vector Brain::getPrimaryAnatomicalSurfaces() const { std::vector surfaces; const int32_t numBrainStructures = getNumberOfBrainStructures(); for (int32_t i = 0; i < numBrainStructures; i++) { surfaces.push_back(m_brainStructures[i]->getPrimaryAnatomicalSurface()); } return surfaces; } /** * @return The primary anatomical surfaces from all brain structures. */ std::vector Brain::getPrimaryAnatomicalSurfaceFiles() const { std::vector surfaces = getPrimaryAnatomicalSurfaces(); std::vector surfaceFiles; surfaceFiles.insert(surfaceFiles.end(), surfaces.begin(), surfaces.end()); return surfaceFiles; } /** * Get the primary anatomical surface for the given structure. * * @param structure * Structure for which a primary anatomical surface is requested. * @return * The primary anatomical surface corresonding to the given structure. * NULL may be returned if a surface is not available. */ const Surface* Brain::getPrimaryAnatomicalSurfaceForStructure(const StructureEnum::Enum structure) const { const int32_t numBrainStructures = getNumberOfBrainStructures(); for (int32_t i = 0; i < numBrainStructures; i++) { if (m_brainStructures[i]->getStructure() == structure) { return m_brainStructures[i]->getPrimaryAnatomicalSurface(); } } return NULL; } /** * Get the primary anatomical surface nearest the given coordinate and * within the given tolerance. * * @param xyz * The coordinate. * @param tolerance * The tolerance (if negative tolerance is ignored). * @return * Nearest surface or NULL if nearest surface not within tolerance. */ Surface* Brain::getPrimaryAnatomicalSurfaceNearestCoordinate(const float xyz[3], const float tolerance) { Surface* nearestSurface = NULL; float nearestDistance = ((tolerance > 0.0) ? tolerance : std::numeric_limits::max()); const int32_t numBrainStructures = getNumberOfBrainStructures(); for (int32_t i = 0; i < numBrainStructures; i++) { Surface* surface = m_brainStructures[i]->getPrimaryAnatomicalSurface(); const int32_t nodeIndex = surface->closestNode(xyz, tolerance); if (nodeIndex >= 0) { const float dist = MathFunctions::distanceSquared3D(xyz, surface->getCoordinate(nodeIndex)); if (dist < nearestDistance) { nearestDistance = dist; nearestSurface = surface; } } } return nearestSurface; } /** * Update the chart model. */ void Brain::updateChartModel() { std::vector chartableBrainordinateFiles; getAllChartableBrainordinateDataFiles(chartableBrainordinateFiles); std::vector chartableMatrixFiles; getAllChartableMatrixDataFiles(chartableMatrixFiles); const int32_t numberOfChartableFiles = (chartableBrainordinateFiles.size() + chartableMatrixFiles.size()); if (numberOfChartableFiles > 0) { if (m_modelChart == NULL) { m_modelChart = new ModelChart(this); EventModelAdd eventAddModel(m_modelChart); EventManager::get()->sendEvent(eventAddModel.getPointer()); if (m_isSpecFileBeingRead == false) { m_modelChart->initializeOverlays(); } } } else { if (m_modelChart != NULL) { EventModelDelete eventDeleteModel(m_modelChart); EventManager::get()->sendEvent(eventDeleteModel.getPointer()); delete m_modelChart; m_modelChart = NULL; } } /* * For Chart Two, test for any files that report a valid charting data type * and then update (add/remove charting two model) */ EventCaretMappableDataFilesGet allMapFilesEvent; EventManager::get()->sendEvent(allMapFilesEvent.getPointer()); std::vector allMapFiles; allMapFilesEvent.getAllFiles(allMapFiles); bool haveChartableFileFlag = false; for (auto mapFile : allMapFiles) { CaretAssert(mapFile); std::vector chartDataTypes; mapFile->getChartingDelegate()->getSupportedChartTwoDataTypes(chartDataTypes); if ( ! chartDataTypes.empty()) { haveChartableFileFlag = true; break; } } if (haveChartableFileFlag) { if (m_modelChartTwo == NULL) { createModelChartTwo(); } } else { if (m_modelChartTwo != NULL) { EventModelDelete eventDeleteModel(m_modelChartTwo); EventManager::get()->sendEvent(eventDeleteModel.getPointer()); delete m_modelChartTwo; m_modelChartTwo = NULL; } } } /** * Create the model chart two. */ void Brain::createModelChartTwo() { m_modelChartTwo = new ModelChartTwo(this); EventModelAdd eventAddModel(m_modelChartTwo); EventManager::get()->sendEvent(eventAddModel.getPointer()); if (m_isSpecFileBeingRead == false) { m_modelChartTwo->initializeOverlays(); } } /** * Update the volume slice model. */ void Brain::updateVolumeSliceModel() { bool isValid = false; std::vector allCaretMappableDataFiles; getAllMappableDataFiles(allCaretMappableDataFiles); for (std::vector::iterator iter = allCaretMappableDataFiles.begin(); iter != allCaretMappableDataFiles.end(); iter++) { CaretMappableDataFile* cmdf = *iter; if (cmdf->isVolumeMappable()) { if (cmdf->isEmpty() == false) { isValid = true; break; } } } if (isValid) { if (m_volumeSliceModel == NULL) { m_volumeSliceModel = new ModelVolume(this); EventModelAdd eventAddModel(m_volumeSliceModel); EventManager::get()->sendEvent(eventAddModel.getPointer()); if (m_isSpecFileBeingRead == false) { m_volumeSliceModel->initializeOverlays(); } } } else { if (m_volumeSliceModel != NULL) { EventModelDelete eventDeleteModel(m_volumeSliceModel); EventManager::get()->sendEvent(eventDeleteModel.getPointer()); delete m_volumeSliceModel; m_volumeSliceModel = NULL; } } } /** * Update the whole brain model. */ void Brain::updateWholeBrainModel() { bool isValid = false; if ((getNumberOfBrainStructures() > 0) || (getNumberOfVolumeFiles() > 0)) { isValid = true; } if (isValid) { if (m_wholeBrainModel == NULL) { m_wholeBrainModel = new ModelWholeBrain(this); EventModelAdd eventAddModel(m_wholeBrainModel); EventManager::get()->sendEvent(eventAddModel.getPointer()); if (m_isSpecFileBeingRead == false) { m_wholeBrainModel->initializeOverlays(); } } m_wholeBrainModel->updateModel(); } else { if (m_wholeBrainModel != NULL) { EventModelDelete eventDeleteModel(m_wholeBrainModel); EventManager::get()->sendEvent(eventDeleteModel.getPointer()); delete m_wholeBrainModel; m_wholeBrainModel = NULL; } } } /** * Update the surface montage model */ void Brain::updateSurfaceMontageModel() { bool isValid = false; if (getNumberOfBrainStructures() > 0) { isValid = true; } if (isValid) { if (m_surfaceMontageModel == NULL) { m_surfaceMontageModel = new ModelSurfaceMontage(this); EventModelAdd eventAddModel(m_surfaceMontageModel); EventManager::get()->sendEvent(eventAddModel.getPointer()); if (m_isSpecFileBeingRead == false) { m_surfaceMontageModel->initializeOverlays(); } } } else { if (m_surfaceMontageModel != NULL) { EventModelDelete eventDeleteModel(m_surfaceMontageModel); EventManager::get()->sendEvent(eventDeleteModel.getPointer()); delete m_surfaceMontageModel; m_surfaceMontageModel = NULL; } } } /** * Process a reload data file event. * @param reloadDataFileEvent * Event containing file for reloading and my be updated with error messages. */ void Brain::processReloadDataFileEvent(EventDataFileReload* reloadDataFileEvent) { /* * Verify that file is already in memory. */ std::vector allDataFiles; getAllDataFiles(allDataFiles); CaretDataFile* caretDataFile = reloadDataFileEvent->getCaretDataFile(); CaretAssert(caretDataFile); if (std::find(allDataFiles.begin(), allDataFiles.end(), caretDataFile) == allDataFiles.end()) { reloadDataFileEvent->setErrorMessage("ERROR: " + caretDataFile->getFileNameNoPath() + " was not found as a loaded file."); return; } CaretDataFile::setFileReadingUsernameAndPassword(reloadDataFileEvent->getUsername(), reloadDataFileEvent->getPassword()); try { addReadOrReloadDataFile(FILE_MODE_RELOAD, caretDataFile, caretDataFile->getDataFileType(), caretDataFile->getStructure(), caretDataFile->getFileName(), false); } catch (const DataFileException& dfe) { reloadDataFileEvent->setErrorMessage(dfe.whatString()); } updateAfterFilesAddedOrRemoved(); } #include "CaretHttpManager.h" /** * Process a read data file event. * @param readDataFileEvent * Event describing file for reading and may be updated with error messages. */ void Brain::processReadDataFileEvent(EventDataFileRead* readDataFileEvent) { const QString username = readDataFileEvent->getUsername(); const QString password = readDataFileEvent->getPassword(); CaretDataFile::setFileReadingUsernameAndPassword(username, password); const int32_t numberOfFilesToRead = readDataFileEvent->getNumberOfDataFilesToRead(); EventProgressUpdate progressEvent(0, numberOfFilesToRead, 0, "Starting to read data file(s)"); EventManager::get()->sendEvent(progressEvent.getPointer()); AString eventErrorMessage; for (int32_t i = 0; i < numberOfFilesToRead; i++) { const AString filename = readDataFileEvent->getDataFileName(i); const DataFileTypeEnum::Enum dataFileType = readDataFileEvent->getDataFileType(i); const StructureEnum::Enum structure = readDataFileEvent->getStructure(i); const bool setFileModifiedStatus = readDataFileEvent->isFileToBeMarkedModified(i); const AString shortName = FileInformation(filename).getFileName(); progressEvent.setProgress(i, ("Reading " + shortName)); EventManager::get()->sendEvent(progressEvent.getPointer()); if (progressEvent.isCancelled()) { eventErrorMessage.appendWithNewLine("File reading cancelled."); break; } try { if (DataFile::isFileOnNetwork(filename) && ( ! username.isEmpty()) && ( ! password.isEmpty())) { CaretHttpManager::setAuthentication(filename, username, password); } CaretDataFile* fileRead = readDataFile(dataFileType, structure, filename, setFileModifiedStatus); readDataFileEvent->setDataFileRead(i, fileRead); } catch (const DataFileException& e) { if (e.isErrorInvalidStructure()) { readDataFileEvent->setFileErrorInvalidStructure(i, e.isErrorInvalidStructure()); } else { eventErrorMessage.appendWithNewLine(e.whatString()); readDataFileEvent->setFileErrorMessage(i, e.whatString()); } } } readDataFileEvent->setErrorMessage(eventErrorMessage); CaretDataFile::setFileReadingUsernameAndPassword("", ""); } /** * Read, or reload a data file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param dataFileType * Type of data file to read. * @param structure * Struture of file (used if not invalid) * @param dataFileNameIn * Name of data file to read. * @param markDataFileAsModified * If file has invalid structure and settings structure, mark file modified * @return * In some cases this will return a pointer to the file that was read so * beware that this value may be NULL. * @throws DataFileException * If there is an error reading the file. */ CaretDataFile* Brain::addReadOrReloadDataFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const DataFileTypeEnum::Enum dataFileType, const StructureEnum::Enum structure, const AString& dataFileNameIn, const bool markDataFileAsModified) { /* * Need absolute path */ AString dataFileName = convertFilePathNameToAbsolutePathName(dataFileNameIn); CaretDataFile* caretDataFileRead = NULL; switch (fileMode) { case FILE_MODE_ADD: CaretAssert(caretDataFile != NULL); break; case FILE_MODE_READ: CaretAssert(caretDataFile == NULL); break; case FILE_MODE_RELOAD: CaretAssert(caretDataFile != NULL); break; } try { ElapsedTimer et; et.start(); switch (dataFileType) { case DataFileTypeEnum::ANNOTATION: caretDataFileRead = addReadOrReloadAnnotationFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: caretDataFileRead = addReadOrReloadAnnotationTextSubstitutionFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::BORDER: caretDataFileRead = addReadOrReloadBorderFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::CONNECTIVITY_DENSE: caretDataFileRead = addReadOrReloadConnectivityDenseFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: CaretAssertMessage(0, "Dense Dynamic files are never read by the Brain."); break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: caretDataFileRead = addReadOrReloadConnectivityDenseLabelFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: caretDataFileRead = addReadOrReloadConnectivityMatrixDenseParcelFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: caretDataFileRead = addReadOrReloadConnectivityDenseScalarFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: caretDataFileRead = addReadOrReloadConnectivityDataSeriesFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: caretDataFileRead = addReadOrReloadConnectivityFiberOrientationFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: caretDataFileRead = addReadOrReloadConnectivityFiberTrajectoryFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: caretDataFileRead = addReadOrReloadConnectivityMatrixParcelFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: caretDataFileRead = addReadOrReloadConnectivityMatrixParcelDenseFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: caretDataFileRead = addReadOrReloadConnectivityParcelLabelFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: caretDataFileRead = addReadOrReloadConnectivityParcelScalarFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: caretDataFileRead = addReadOrReloadConnectivityParcelSeriesFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: caretDataFileRead = addReadOrReloadConnectivityScalarDataSeriesFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::FOCI: caretDataFileRead = addReadOrReloadFociFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::IMAGE: caretDataFileRead = addReadOrReloadImageFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::LABEL: caretDataFileRead = addReadOrReloadLabelFile(fileMode, caretDataFile, dataFileName, structure, markDataFileAsModified); break; case DataFileTypeEnum::METRIC: caretDataFileRead = addReadOrReloadMetricFile(fileMode, caretDataFile, dataFileName, structure, markDataFileAsModified); break; case DataFileTypeEnum::METRIC_DYNAMIC: CaretAssertMessage(0, "Metric dynamic files are never read by Brain"); break; case DataFileTypeEnum::PALETTE: caretDataFileRead = addReadOrReloadPaletteFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::RGBA: caretDataFileRead = addReadOrReloadRgbaFile(fileMode, caretDataFile, dataFileName, structure, markDataFileAsModified); break; case DataFileTypeEnum::SCENE: caretDataFileRead = addReadOrReloadSceneFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::SPECIFICATION: CaretLogSevere("PROGRAM ERROR: Reading spec file should never call Brain::addReadOrReloadDataFile()"); throw DataFileException(dataFileName, "PROGRAM ERROR: Reading spec file should never call Brain::addReadOrReloadDataFile()"); break; case DataFileTypeEnum::SURFACE: caretDataFileRead = addReadOrReloadSurfaceFile(fileMode, caretDataFile, dataFileName, structure, markDataFileAsModified); break; case DataFileTypeEnum::UNKNOWN: throw DataFileException(dataFileName, "Unable to read files of type UNKNOWN. May have invalid filename extenson."); break; case DataFileTypeEnum::VOLUME: caretDataFileRead = addReadOrReloadVolumeFile(fileMode, caretDataFile, dataFileName); break; case DataFileTypeEnum::VOLUME_DYNAMIC: CaretAssertMessage(0, "Volume dynamic files are never read by the Brain"); break; } if (caretDataFileRead != NULL) { /* * NOTE: Name may have changed if it is a duplicate file name * for the data type. */ dataFileName = caretDataFileRead->getFileName(); m_specFile->addCaretDataFile(caretDataFileRead); } m_specFile->addDataFile(dataFileType, structure, dataFileName, true, false, false); AString msg = ("Time to read " + dataFileName + " was " + AString::number(et.getElapsedTimeSeconds()) + " seconds."); CaretLogInfo(msg); } catch (DataFileException& dfe) { /* * If "caretDataFile" is not NULL, then we were trying to * RELOAD a file so remove it from the "loaded files" */ if (caretDataFile != NULL) { m_specFile->removeCaretDataFile(caretDataFile); } else { if (caretDataFileRead != NULL) { delete caretDataFileRead; caretDataFileRead = NULL; } } throw dfe; } loadMatrixChartingFileDefaultRowOrColumn(caretDataFileRead); updateAfterFilesAddedOrRemoved(); return caretDataFileRead; } /** * Read a data file. * * @param fileMode * Mode for file adding, reading, or reloading. * @param caretDataFile * File that is added or reloaded (MUST NOT BE NULL). If NULL, * the mode must be READING. * @param dataFileType * Type of data file to read. * @param structure * Struture of file (used if not invalid) * @param dataFileNameIn * Name of data file to read. * @param markDataFileAsModified * If file has invalid structure and settings structure, mark file modified * @throws DataFileException * If there is an error reading the file. * @return * Pointer to file that was read, if no errors. */ CaretDataFile* Brain::readDataFile(const DataFileTypeEnum::Enum dataFileType, const StructureEnum::Enum structure, const AString& dataFileNameIn, const bool markDataFileAsModified) { AString dataFileName = dataFileNameIn; /* * If possible, update path so that is absolute */ dataFileName = convertFilePathNameToAbsolutePathName(dataFileName); /* * Since file is being read, it must exist */ if (DataFile::isFileOnNetwork(dataFileName) == false) { FileInformation fileInfoFullPath(dataFileName); if (fileInfoFullPath.exists() == false) { throw DataFileException(dataFileName, "File not found:"); } } CaretDataFile* caretDataFileRead = addReadOrReloadDataFile(FILE_MODE_READ, NULL, dataFileType, structure, dataFileName, markDataFileAsModified); return caretDataFileRead; } /** * Processing performed after adding or removing a data file. */ void Brain::updateAfterFilesAddedOrRemoved() { updateBrainStructures(); updateSurfaceMontageModel(); updateVolumeSliceModel(); updateWholeBrainModel(); updateChartModel(); updateFiberTrajectoryMatchingFiberOrientationFiles(); } /** * Load the data files selected in a spec file. * @param readSpecFileDataFilesEvent * Event containing the spec file. */ void Brain::loadFilesSelectedInSpecFile(EventSpecFileReadDataFiles* readSpecFileDataFilesEvent) { ElapsedTimer timer; timer.start(); AString errorMessage; const SpecFile* sf = readSpecFileDataFilesEvent->getSpecFile(); CaretAssert(sf); resetBrain(); CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->invalidateSceneDataValues(); prefs->setBackgroundAndForegroundColorsMode(BackgroundAndForegroundColorsModeEnum::USER_PREFERENCES); const AString specFileName = sf->getFileName(); if (DataFile::isFileOnNetwork(specFileName)) { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->addToPreviousSpecFiles(specFileName); } else { FileInformation specFileInfo(specFileName); if (specFileInfo.exists() && specFileInfo.isAbsolute()) { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->addToPreviousSpecFiles(specFileName); } } try { m_specFile->clear(); *m_specFile = *sf; } catch (const DataFileException& e) { CaretLogSevere("SPEC FILE TODO: " + e.whatString()); } m_isSpecFileBeingRead = true; CaretDataFile::setFileReadingUsernameAndPassword(readSpecFileDataFilesEvent->getUsername(), readSpecFileDataFilesEvent->getPassword()); FileInformation fileInfo(sf->getFileName()); setCurrentDirectory(fileInfo.getPathName()); const int32_t numberOfFilesToRead = sf->getNumberOfFilesSelectedForLoading(); int32_t fileReadCounter = 0; EventProgressUpdate progressUpdate(0, numberOfFilesToRead, fileReadCounter, "Starting to read selected files"); EventManager::get()->sendEvent(progressUpdate.getPointer()); /* * Note: Need to read palette first since some of the individual file * reading routines update palette coloring when file is read */ const int32_t numFileGroups = sf->getNumberOfDataFileTypeGroups(); for (int32_t ig = -1; ig < numFileGroups; ig++) { const SpecFileDataFileTypeGroup* group = ((ig == -1) ? sf->getDataFileTypeGroupByType(DataFileTypeEnum::PALETTE) : sf->getDataFileTypeGroupByIndex(ig)); const DataFileTypeEnum::Enum dataFileType = group->getDataFileType(); if (ig >= 0) { if (dataFileType == DataFileTypeEnum::PALETTE) { continue; } } const int32_t numFiles = group->getNumberOfFiles(); for (int32_t iFile = 0; iFile < numFiles; iFile++) { const SpecFileDataFile* dataFileInfo = group->getFileInformation(iFile); if (dataFileInfo->isLoadingSelected()) { const AString filename = dataFileInfo->getFileName(); const StructureEnum::Enum structure = dataFileInfo->getStructure(); /* * Send event indicating progress of file reading */ FileInformation fileInfo(dataFileInfo->getFileName()); progressUpdate.setProgress(fileReadCounter, ("Reading " + fileInfo.getFileName())); EventManager::get()->sendEvent(progressUpdate.getPointer()); /* * If user cancelled, reset brain and get out! */ if (progressUpdate.isCancelled()) { resetBrain(); return; } try { readDataFile(dataFileType, structure, filename, false); } catch (const DataFileException& e) { if (errorMessage.isEmpty() == false) { errorMessage += "\n"; } errorMessage += e.whatString(); } fileReadCounter++; } } } m_specFile->clearModified(); if (errorMessage.isEmpty() == false) { readSpecFileDataFilesEvent->setErrorMessage(errorMessage); } m_paletteFile->setFileName(convertFilePathNameToAbsolutePathName(m_paletteFile->getFileNameNoPath())); m_paletteFile->clearModified(); // CaretLogSevere("Adding an annotation file for testing to the Brain." // "NOTE: THIS WILL CAUSE A PRINTOUT OF UNDELETED OBJECTS since this file is " // "added inside of resetBrain() which does all file deletion."); // AnnotationFile* testingAnnFile = new AnnotationFile(); // testingAnnFile->setFileName("Testing." + DataFileTypeEnum::toFileExtension(DataFileTypeEnum::ANNOTATION)); // addDataFile(testingAnnFile); /* * Reset the primary anatomical surfaces since they can get set * incorrectly when loading files */ for (std::vector::iterator bsi = m_brainStructures.begin(); bsi != m_brainStructures.end(); bsi++) { BrainStructure* bs = *bsi; bs->setPrimaryAnatomicalSurface(NULL); } /* * Initialize the overlay for ALL models */ EventModelGetAll getAllModels; EventManager::get()->sendEvent(getAllModels.getPointer()); std::vector allModels = getAllModels.getModels(); for (std::vector::iterator iter = allModels.begin(); iter != allModels.end(); iter++) { Model* mdc = *iter; mdc->initializeSelectedSurfaces(); mdc->initializeOverlays(); } /* * Initialize overlays for brain structures */ for (std::vector::iterator iter = m_brainStructures.begin(); iter != m_brainStructures.end(); iter++) { BrainStructure* bs = *iter; bs->initializeOverlays(); } CaretLogInfo("Time to read files from spec file (in Brain) \"" + sf->getFileNameNoPath() + "\" was " + AString::number(timer.getElapsedTimeSeconds()) + " seconds."); m_isSpecFileBeingRead = false; CaretDataFile::setFileReadingUsernameAndPassword("", ""); } /** * Load files from the given spec file. * @param specFileToLoad * Spec file from which selected files are read. * @param keepSceneFiles * Controls clearing of scene files * @param keepSpecFile * Controls clearing of spec file */ void Brain::loadSpecFileFromScene(const SceneAttributes* sceneAttributes, SpecFile* specFileToLoad, const ResetBrainKeepSceneFiles keepSceneFiles, const ResetBrainKeepSpecFile keepSpecFile) { CaretAssert(specFileToLoad); EventProgressUpdate progressEvent(-1, -1, -1, "Resetting brain"); EventManager::get()->sendEvent(progressEvent.getPointer()); resetBrainKeepSceneFiles(); /* * Try to set to current directory */ const AString previousSpecFileName = m_specFile->getFileName(); delete m_specFile; m_specFile = new SpecFile(*specFileToLoad); FileInformation newSpecFileInfo(m_specFile->getFileName()); if (newSpecFileInfo.isAbsolute()) { setCurrentDirectory(newSpecFileInfo.getPathName()); } else { if (previousSpecFileName.endsWith(m_specFile->getFileName()) == false) { FileInformation oldSpecFileInfo(previousSpecFileName); setCurrentDirectory(oldSpecFileInfo.getPathName()); } } /* * Check to see if existing spec file exists */ FileInformation specFileInfo(specFileToLoad->getFileName()); const bool specFileValid = specFileInfo.exists(); /* * Apply spec file pulled from scene */ m_isSpecFileBeingRead = true; /* * Set current directory to directory containing scene file * but only if there is NOT a valid spec file */ const AString sceneFileName = sceneAttributes->getSceneFileName(); const bool sceneFileOnNetwork = DataFile::isFileOnNetwork(sceneFileName); if (specFileValid == false) { FileInformation sceneFileInfo(sceneFileName); if (sceneFileInfo.exists()) { setCurrentDirectory(sceneFileInfo.getPathName()); } } progressEvent.setProgressMessage("Loading data files"); EventManager::get()->sendEvent(progressEvent.getPointer()); if (progressEvent.isCancelled()) { resetBrain(keepSceneFiles, keepSpecFile); return; } /* * To speed file loading, non-modified files that were in memory * prior to restoring the scene are saved. This map matches * an entry of a selected file to one of the non-modified in * memory data files. */ std::map specFilesEntryToNonModifiedFile; /* * Find non-modified files that match, by name, files that are to be * loaded from the spec file and associate them for later use. */ if ( ! m_nonModifiedFilesForRestoringScene.empty()) { const int32_t numFileGroups = specFileToLoad->getNumberOfDataFileTypeGroups(); for (int32_t ig = 0; ig < numFileGroups; ig++) { const SpecFileDataFileTypeGroup* group = specFileToLoad->getDataFileTypeGroupByIndex(ig); const int32_t numFiles = group->getNumberOfFiles(); for (int32_t iFile = 0; iFile < numFiles; iFile++) { const SpecFileDataFile* fileInfo = group->getFileInformation(iFile); if (fileInfo->isLoadingSelected()) { AString filename = fileInfo->getFileName(); for (std::vector::iterator iter = m_nonModifiedFilesForRestoringScene.begin(); iter != m_nonModifiedFilesForRestoringScene.end(); iter++) { CaretDataFile* caretDataFile = *iter; if (caretDataFile != NULL) { const AString nonModifiedFileName = caretDataFile->getFileName(); if (nonModifiedFileName == filename) { specFilesEntryToNonModifiedFile.insert(std::make_pair(fileInfo, caretDataFile)); *iter = NULL; CaretLogFine("Scene loading matched previous file: " + filename); } } } } } } } /* * Delete any of the files that were in memory prior to loading the scene * that are not part of the scene being loaded. */ for (std::vector::iterator iter = m_nonModifiedFilesForRestoringScene.begin(); iter != m_nonModifiedFilesForRestoringScene.end(); iter++) { CaretDataFile* caretDataFile = *iter; if (caretDataFile != NULL) { CaretLogFine("Scene loading removing previous file not needed: " + caretDataFile->getFileName()); delete caretDataFile; } } m_nonModifiedFilesForRestoringScene.clear(); /* * Load new files and add existing files that were previously loaded. */ const int32_t numFileGroups = specFileToLoad->getNumberOfDataFileTypeGroups(); for (int32_t ig = 0; ig < numFileGroups; ig++) { const SpecFileDataFileTypeGroup* group = specFileToLoad->getDataFileTypeGroupByIndex(ig); const DataFileTypeEnum::Enum dataFileType = group->getDataFileType(); const int32_t numFiles = group->getNumberOfFiles(); for (int32_t iFile = 0; iFile < numFiles; iFile++) { const SpecFileDataFile* fileInfo = group->getFileInformation(iFile); if (fileInfo->isLoadingSelected()) { try { AString filename = fileInfo->getFileName(); std::map::iterator specToFileIter = specFilesEntryToNonModifiedFile.find(fileInfo); if (specToFileIter != specFilesEntryToNonModifiedFile.end()) { const QString msg = ("Adding previous file " + FileInformation(filename).getFileName()); progressEvent.setProgressMessage(msg); EventManager::get()->sendEvent(progressEvent.getPointer()); if (progressEvent.isCancelled()) { resetBrain(keepSceneFiles, keepSpecFile); return; } CaretDataFile* caretDataFile = specToFileIter->second; addReadOrReloadDataFile(FILE_MODE_ADD, caretDataFile, caretDataFile->getDataFileType(), caretDataFile->getStructure(), filename, false); } else { const StructureEnum::Enum structure = fileInfo->getStructure(); const QString msg = ("Loading " + FileInformation(filename).getFileName()); progressEvent.setProgressMessage(msg); EventManager::get()->sendEvent(progressEvent.getPointer()); if (progressEvent.isCancelled()) { resetBrain(keepSceneFiles, keepSpecFile); return; } if (sceneFileOnNetwork) { if (DataFile::isFileOnNetwork(filename) == false) { const int32_t lastSlashIndex = sceneFileName.lastIndexOf("/"); if (lastSlashIndex >= 0) { const AString newName = (sceneFileName.left(lastSlashIndex) + "/" + filename); filename = newName; } } } readDataFile(dataFileType, structure, filename, false); } } catch (const DataFileException& e) { sceneAttributes->addToErrorMessage(e.whatString()); } } } } m_isSpecFileBeingRead = false; if (m_paletteFile != NULL) { delete m_paletteFile; } m_paletteFile = new PaletteFile(); m_paletteFile->setFileName(convertFilePathNameToAbsolutePathName(m_paletteFile->getFileNameNoPath())); m_paletteFile->clearModified(); progressEvent.setProgressMessage("Initializing Overlays"); EventManager::get()->sendEvent(progressEvent.getPointer()); if (progressEvent.isCancelled()) { resetBrain(keepSceneFiles, keepSpecFile); return; } /* * Initialize the overlay for ALL models */ EventModelGetAll getAllModels; EventManager::get()->sendEvent(getAllModels.getPointer()); std::vector allModels = getAllModels.getModels(); for (std::vector::iterator iter = allModels.begin(); iter != allModels.end(); iter++) { Model* mdc = *iter; mdc->initializeOverlays(); } /* * Initialize overlays for brain structures */ for (std::vector::iterator iter = m_brainStructures.begin(); iter != m_brainStructures.end(); iter++) { BrainStructure* bs = *iter; bs->initializeOverlays(); } } /** * If the file is NOT an absolute path, the name of the file path is updated * to include the current directory. * * @param caretDataFile * File that may have its name updated. */ void Brain::convertDataFilePathNameToAbsolutePathName(CaretDataFile* caretDataFile) const { CaretAssert(caretDataFile); const AString newFileName = convertFilePathNameToAbsolutePathName(caretDataFile->getFileName()); caretDataFile->setFileName(newFileName); } /** * Exampine the file path name to determine if it is an * absolute or relative path. If it is a relative * path, convert it to an absolute path. * * If the file is on the network (starts with "http:"), that is considered * an absolute path and the file name is not changed. * * @param filename * Name of file. * @return * If input filename was absolute path, it is returned with * no changes. Otherwise, the name is returned after * updating it to an absolute path. */ AString Brain::convertFilePathNameToAbsolutePathName(const AString& filename) const { /* * If file is on network, is is considered an absolute path */ if (DataFile::isFileOnNetwork(filename)) { return filename; } FileInformation fileInfo(filename); if (fileInfo.isAbsolute()) { return filename; } if (m_currentDirectory.isEmpty()) { AString fullPathName = FileInformation(filename).getAbsoluteFilePath(); return fullPathName; } FileInformation pathFileInfo(m_currentDirectory, filename); AString fullPathName = pathFileInfo.getAbsoluteFilePath(); return fullPathName; } /** * Receive events from the event manager. * * @param event * The event. */ void Brain::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_DATA_FILE_ADD) { EventDataFileAdd* addDataFileEvent = dynamic_cast(event); CaretAssert(addDataFileEvent); try { addDataFile(addDataFileEvent->getCaretDataFile()); } catch (const DataFileException& dfe) { addDataFileEvent->setErrorMessage(dfe.whatString()); } addDataFileEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_DATA_FILE_DELETE) { EventDataFileDelete* deleteDataFileEvent = dynamic_cast(event); CaretAssert(deleteDataFileEvent); removeAndDeleteDataFile(deleteDataFileEvent->getCaretDataFile()); deleteDataFileEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_DATA_FILE_READ) { EventDataFileRead* readDataFileEvent = dynamic_cast(event); CaretAssert(readDataFileEvent); /* * Make sure event is for this brain */ if (readDataFileEvent->getLoadIntoBrain() == this) { readDataFileEvent->setEventProcessed(); processReadDataFileEvent(readDataFileEvent); } } else if (event->getEventType() == EventTypeEnum::EVENT_DATA_FILE_RELOAD) { EventDataFileReload* reloadDataFileEvent = dynamic_cast(event); CaretAssert(reloadDataFileEvent); if (reloadDataFileEvent->getBrain() == this) { reloadDataFileEvent->setEventProcessed(); processReloadDataFileEvent(reloadDataFileEvent); } } else if (event->getEventType() == EventTypeEnum::EVENT_CARET_DATA_FILES_GET) { EventCaretDataFilesGet* filesEvent = dynamic_cast(event); CaretAssert(filesEvent); std::vector caretDataFiles; getAllDataFiles(caretDataFiles); filesEvent->addAllCaretDataFiles(caretDataFiles); filesEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILES_GET) { EventCaretMappableDataFilesGet* dataFilesEvent = dynamic_cast(event); CaretAssert(dataFilesEvent); std::vector allCaretMappableFiles; getAllMappableDataFiles(allCaretMappableFiles); for (std::vector::iterator iter = allCaretMappableFiles.begin(); iter != allCaretMappableFiles.end(); iter++) { dataFilesEvent->addFile(*iter); } dataFilesEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_SPEC_FILE_READ_DATA_FILES) { EventSpecFileReadDataFiles* readSpecFileDataFilesEvent = dynamic_cast(event); CaretAssert(readSpecFileDataFilesEvent); /* * Make sure event is for this brain */ if (readSpecFileDataFilesEvent->getLoadIntoBrain() == this) { readSpecFileDataFilesEvent->setEventProcessed(); loadFilesSelectedInSpecFile(readSpecFileDataFilesEvent); } } else if (event->getEventType() == EventTypeEnum::EVENT_GET_DISPLAYED_DATA_FILES) { EventGetDisplayedDataFiles* displayedFilesEvent = dynamic_cast(event); CaretAssert(displayedFilesEvent); /* * Get all visible browser tabs. */ EventBrowserTabGetAll getAllTabsEvent; EventManager::get()->sendEvent(getAllTabsEvent.getPointer()); std::set dataFilesDisplayedInTabs; /* * Get files displayed in each tab. */ const int32_t numberOfTabs = getAllTabsEvent.getNumberOfBrowserTabs(); for (int32_t i = 0; i < numberOfTabs; i++) { BrowserTabContent* btc = getAllTabsEvent.getBrowserTab(i); const int32_t tabIndex = btc->getTabNumber(); if (displayedFilesEvent->isTestForDisplayedDataFileInTabIndex(tabIndex)) { std::vector tabDataFiles; btc->getFilesDisplayedInTab(tabDataFiles); dataFilesDisplayedInTabs.insert(tabDataFiles.begin(), tabDataFiles.end()); } } /* * See if any palette mappable files are displayed */ bool havePaletteMappableFiles = false; for (std::set::const_iterator iter = dataFilesDisplayedInTabs.begin(); iter != dataFilesDisplayedInTabs.end(); iter++) { const CaretMappableDataFile* mappableFile = dynamic_cast(*iter); if (mappableFile != NULL) { if (mappableFile->isMappedWithPalette()) { havePaletteMappableFiles = true; break; } } } /* * If there are ANY palette mappable data files, add the * palette file. */ if (havePaletteMappableFiles) { dataFilesDisplayedInTabs.insert(m_paletteFile); } for (std::set::const_iterator iter = dataFilesDisplayedInTabs.begin(); iter != dataFilesDisplayedInTabs.end(); iter++) { displayedFilesEvent->addDisplayedDataFile(*iter); } /* * Annotation files */ std::vector annotationFiles; m_annotationManager->getDisplayedAnnotationFiles(displayedFilesEvent, annotationFiles); if ( ! annotationFiles.empty()) { dataFilesDisplayedInTabs.insert(annotationFiles.begin(), annotationFiles.end()); } } else if (event->getEventType() == EventTypeEnum::EVENT_PALETTE_GET_BY_NAME) { EventPaletteGetByName* paletteGetByName = dynamic_cast(event); CaretAssert(paletteGetByName); if (m_paletteFile != NULL) { Palette* palette = m_paletteFile->getPaletteByName(paletteGetByName->getPaletteName()); if (palette != NULL) { paletteGetByName->setPalette(palette); paletteGetByName->setEventProcessed(); } } } else if (event->getEventType() == EventTypeEnum::EVENT_SCENE_ACTIVE) { EventSceneActive* sceneEvent = dynamic_cast(event); CaretAssert(sceneEvent); switch (sceneEvent->getMode()) { case EventSceneActive::MODE_GET: { if (m_activeScene != NULL) { bool sceneFoundFlag = false; for (auto sf : m_sceneFiles) { const int32_t numScenes = sf->getNumberOfScenes(); for (int32_t i = 0; i < numScenes; i++) { if (sf->getSceneAtIndex(i) == m_activeScene) { sceneFoundFlag = true; break; } } if (sceneFoundFlag) { break; } } if ( ! sceneFoundFlag) { m_activeScene = NULL; } } sceneEvent->setScene(m_activeScene); sceneEvent->setEventProcessed(); } break; case EventSceneActive::MODE_SET: m_activeScene = sceneEvent->getScene(); break; } } } /** * @return The chart model (warning may be NULL!) */ ModelChart* Brain::getChartModel() { return m_modelChart; } /** * @return The chart model (warning may be NULL!) */ const ModelChart* Brain::getChartModel() const { return m_modelChart; } /** * @return The chart two model (warning may be NULL!) */ ModelChartTwo* Brain::getChartTwoModel() { return m_modelChartTwo; } /** * @return The chart two model (warning may be NULL!) */ const ModelChartTwo* Brain::getChartTwoModel() const { return m_modelChartTwo; } /** * @return The annotation manager. */ AnnotationManager* Brain::getAnnotationManager() { return m_annotationManager; } /** * @return The annotation manager. */ const AnnotationManager* Brain::getAnnotationManager() const { return m_annotationManager; } /** * @return The charting data manager. */ ChartingDataManager* Brain::getChartingDataManager() { return m_chartingDataManager; } /** * @return The charting data manager. */ const ChartingDataManager* Brain::getChartingDataManager() const { return m_chartingDataManager; } /** * @return The current directory. */ AString Brain::getCurrentDirectory() const { if (m_currentDirectory.isEmpty()) { m_currentDirectory = SystemUtilities::systemCurrentDirectory(); } return m_currentDirectory; } /** * Set the current directory. * @param currentDirectory * New value for current directory. */ void Brain::setCurrentDirectory(const AString& currentDirectory) { m_currentDirectory = currentDirectory; } /** * Get All CaretMappableDataFiles. * * @param allCaretMappableDataFilesOut * Will contain instance of CaretMappableDataFiles upon exit. */ void Brain::getAllMappableDataFiles(std::vector& allCaretMappableDataFilesOut) const { allCaretMappableDataFilesOut.clear(); std::vector allDataFiles; getAllDataFiles(allDataFiles); for (std::vector::iterator iter = allDataFiles.begin(); iter != allDataFiles.end(); iter++) { CaretDataFile* cdf = *iter; CaretMappableDataFile* cmdf = dynamic_cast(cdf); if (cmdf != NULL) { allCaretMappableDataFilesOut.push_back(cmdf); } } } /** * Get All CaretMappableDataFiles of the given data file type. * * @param dataFileType * Type of data file. * @param caretMappableDataFilesOut * Contains CaretMappableDataFiles matching data file type upon exit. */ void Brain::getAllMappableDataFileWithDataFileType(const DataFileTypeEnum::Enum dataFileType, std::vector& caretMappableDataFilesOut) const { caretMappableDataFilesOut.clear(); std::vector allFiles; getAllMappableDataFiles(allFiles); for (std::vector::iterator iter = allFiles.begin(); iter != allFiles.end(); iter++) { CaretMappableDataFile* cmdf = *iter; if (cmdf->getDataFileType() == dataFileType) { caretMappableDataFilesOut.push_back(cmdf); } } } /** * Get All CaretMappableDataFiles of the given data file types. * * @param dataFileType * Type of data file. * @param caretMappableDataFilesOut * Contains CaretMappableDataFiles matching data file type upon exit. */ void Brain::getAllMappableDataFileWithDataFileTypes(const std::vector& dataFileTypes, std::vector& caretMappableDataFilesOut) const { caretMappableDataFilesOut.clear(); std::vector allFiles; getAllMappableDataFiles(allFiles); for (std::vector::iterator iter = allFiles.begin(); iter != allFiles.end(); iter++) { CaretMappableDataFile* cmdf = *iter; if (std::find(dataFileTypes.begin(), dataFileTypes.end(), cmdf->getDataFileType()) != dataFileTypes.end()) { caretMappableDataFilesOut.push_back(cmdf); } } } /** * Get all CaretDataFiles of the given data file types. * * @param dataFileTypes * Types of data files. * @param caretDataFilesOut * Data file of the given data file type that were found. */ void Brain::getAllDataFilesWithDataFileTypes(const std::vector& dataFileTypes, std::vector& caretDataFilesOut) const { caretDataFilesOut.clear(); std::vector allDataFiles; getAllDataFiles(allDataFiles, true); for (std::vector::iterator iter = allDataFiles.begin(); iter != allDataFiles.end(); iter++) { CaretDataFile* cdf = *iter; if (std::find(dataFileTypes.begin(), dataFileTypes.end(), cdf->getDataFileType()) != dataFileTypes.end()) { caretDataFilesOut.push_back(cdf); } } } /** * Get all CaretDataFiles of the given data file type. * * @param dataFileType * Type of data file. * @param caretDataFilesOut * Data file of the given data file type that were found. */ void Brain::getAllDataFilesWithDataFileType(const DataFileTypeEnum::Enum dataFileType, std::vector& caretDataFilesOut) const { std::vector dataFileTypes; dataFileTypes.push_back(dataFileType); getAllDataFilesWithDataFileTypes(dataFileTypes, caretDataFilesOut); // caretDataFilesOut.clear(); // // std::vector allDataFiles; // getAllDataFiles(allDataFiles, // true); // // for (std::vector::iterator iter = allDataFiles.begin(); // iter != allDataFiles.end(); // iter++) { // CaretDataFile* cdf = *iter; // if (cdf->getDataFileType() == dataFileType) { // caretDataFilesOut.push_back(cdf); // } // } } /** * Get all loaded data files. * @param allDataFilesOut * Data files are loaded into this parameter. * @param includeSpecFile * If true, the spec file is included as the first file. */ void Brain::getAllDataFiles(std::vector& allDataFilesOut, const bool includeSpecFile) const { allDataFilesOut.clear(); if (includeSpecFile) { if (m_specFile->isEmpty() == false) { allDataFilesOut.push_back(m_specFile); } } const int32_t numBrainStructures = getNumberOfBrainStructures(); for (int32_t i = 0; i < numBrainStructures; i++) { getBrainStructure(i)->getAllDataFiles(allDataFilesOut); } allDataFilesOut.insert(allDataFilesOut.end(), m_annotationFiles.begin(), m_annotationFiles.end()); allDataFilesOut.insert(allDataFilesOut.end(), m_annotationSubstitutionFiles.begin(), m_annotationSubstitutionFiles.end()); allDataFilesOut.insert(allDataFilesOut.end(), m_borderFiles.begin(), m_borderFiles.end()); allDataFilesOut.insert(allDataFilesOut.end(), m_fociFiles.begin(), m_fociFiles.end()); allDataFilesOut.insert(allDataFilesOut.end(), m_imageFiles.begin(), m_imageFiles.end()); allDataFilesOut.insert(allDataFilesOut.end(), m_connectivityDenseScalarFiles.begin(), m_connectivityDenseScalarFiles.end()); allDataFilesOut.insert(allDataFilesOut.end(), m_connectivityMatrixDenseFiles.begin(), m_connectivityMatrixDenseFiles.end()); // allDataFilesOut.insert(allDataFilesOut.end(), // m_connectivityDataSeriesFiles.begin(), // m_connectivityDataSeriesFiles.end()); /* * By placing the dynamic connectivity file immediately after * its parent data-series file, they will appear in this * order in the overlay file selectors. */ for (std::vector::const_iterator dsIter = m_connectivityDataSeriesFiles.begin(); dsIter != m_connectivityDataSeriesFiles.end(); dsIter++) { CiftiBrainordinateDataSeriesFile* seriesFile = *dsIter; CaretAssert(seriesFile); allDataFilesOut.push_back(seriesFile); CiftiConnectivityMatrixDenseDynamicFile* dynFile = seriesFile->getConnectivityMatrixDenseDynamicFile(); CaretAssert(dynFile); if (dynFile->isDataValid()) { allDataFilesOut.push_back(dynFile); } } // std::vector denseDynFiles; // getConnectivityMatrixDenseDynamicFiles(denseDynFiles); // allDataFilesOut.insert(allDataFilesOut.end(), // denseDynFiles.begin(), // denseDynFiles.end()); allDataFilesOut.insert(allDataFilesOut.end(), m_connectivityDenseLabelFiles.begin(), m_connectivityDenseLabelFiles.end()); allDataFilesOut.insert(allDataFilesOut.end(), m_connectivityMatrixDenseParcelFiles.begin(), m_connectivityMatrixDenseParcelFiles.end()); allDataFilesOut.insert(allDataFilesOut.end(), m_connectivityFiberOrientationFiles.begin(), m_connectivityFiberOrientationFiles.end()); allDataFilesOut.insert(allDataFilesOut.end(), m_connectivityFiberTrajectoryFiles.begin(), m_connectivityFiberTrajectoryFiles.end()); allDataFilesOut.insert(allDataFilesOut.end(), m_connectivityMatrixParcelFiles.begin(), m_connectivityMatrixParcelFiles.end()); allDataFilesOut.insert(allDataFilesOut.end(), m_connectivityMatrixParcelDenseFiles.begin(), m_connectivityMatrixParcelDenseFiles.end()); allDataFilesOut.insert(allDataFilesOut.end(), m_connectivityParcelLabelFiles.begin(), m_connectivityParcelLabelFiles.end()); allDataFilesOut.insert(allDataFilesOut.end(), m_connectivityParcelScalarFiles.begin(), m_connectivityParcelScalarFiles.end()); allDataFilesOut.insert(allDataFilesOut.end(), m_connectivityParcelSeriesFiles.begin(), m_connectivityParcelSeriesFiles.end()); allDataFilesOut.insert(allDataFilesOut.end(), m_connectivityScalarDataSeriesFiles.begin(), m_connectivityScalarDataSeriesFiles.end()); allDataFilesOut.push_back(m_paletteFile); allDataFilesOut.insert(allDataFilesOut.end(), m_sceneFiles.begin(), m_sceneFiles.end()); for (auto vf : m_volumeFiles) { allDataFilesOut.push_back(vf); VolumeDynamicConnectivityFile* volDynConnFile = vf->getVolumeDynamicConnectivityFile(); if (volDynConnFile != NULL) { allDataFilesOut.push_back(volDynConnFile); } } } /** * Determine if a file is still valid (pointer is for an existing data * of the same DataFileType. */ bool Brain::isFileValid(const CaretDataFile* caretDataFile) const { std::vector allDataFiles; getAllDataFiles(allDataFiles); for (std::vector::iterator iter = allDataFiles.begin(); iter != allDataFiles.end(); iter++) { const CaretDataFile* cdf = *iter; if (caretDataFile == cdf) { if (caretDataFile->getDataFileType() == cdf->getDataFileType()) { return true; } } } return false; } /** * Get all of the modified files excluding the given data file types. * * @param excludeTheseDataTypes * Data types of files that excluded. * @param modifiedDataFilesOut * Output containing the modified files. * */ void Brain::getAllModifiedFiles(const std::vector& excludeTheseDataTypes, std::vector& modifiedDataFilesOut) const { modifiedDataFilesOut.clear(); if (std::find(excludeTheseDataTypes.begin(), excludeTheseDataTypes.end(), DataFileTypeEnum::SPECIFICATION) == excludeTheseDataTypes.end()) { if (m_specFile->isModified()) { modifiedDataFilesOut.push_back(m_specFile); } } std::vector dataFiles; getAllDataFiles(dataFiles); for (std::vector::iterator iter = dataFiles.begin(); iter != dataFiles.end(); iter++) { CaretDataFile* cdf = *iter; /** * Ignore files whose data type is excluded. */ if (std::find(excludeTheseDataTypes.begin(), excludeTheseDataTypes.end(), cdf->getDataFileType()) == excludeTheseDataTypes.end()) { if (cdf->isModified()) { modifiedDataFilesOut.push_back(cdf); } } } } ///** // * Are any data files modified (including spec file)? // * @param excludeTheseDataTypes // * Do not check the modification status of any data files whose // * data type is contained in this parameter. // */ //bool //Brain::areFilesModified(const std::vector& excludeTheseDataTypes) //{ // if (std::find(excludeTheseDataTypes.begin(), // excludeTheseDataTypes.end(), // DataFileTypeEnum::SPECIFICATION) == excludeTheseDataTypes.end()) { // if (m_specFile->isModified()) { // return true; // } // } // // std::vector dataFiles; // getAllDataFiles(dataFiles); // // for (std::vector::iterator iter = dataFiles.begin(); // iter != dataFiles.end(); // iter++) { // CaretDataFile* cdf = *iter; // // /** // * Ignore files whose data type is excluded. // */ // if (std::find(excludeTheseDataTypes.begin(), // excludeTheseDataTypes.end(), // cdf->getDataFileType()) == excludeTheseDataTypes.end()) { // if (cdf->isModified()) { // return true; // } // } // } // // return false; //} /** * Write a data file. * @param caretDataFile * Data file to write. * @return * true if file was written, else false. * @throw * DataFileException if there was an error writing the file. */ void Brain::writeDataFile(CaretDataFile* caretDataFile) { AString dataFileName = caretDataFile->getFileName(); /* * If file is on network, it cannot be written ! */ if (DataFile::isFileOnNetwork(dataFileName)) { throw DataFileException(dataFileName, "Cannot write a file with a network path. " "To write the file, its name must be changed to " "a path on your computer. This can be done using " "the \"More\" icon on the Manage Files Dialog " "(File Menu->Save/Manage Files)."); } /* * If file is relative path, update path using current directory */ dataFileName = convertFilePathNameToAbsolutePathName(dataFileName); caretDataFile->setFileName(dataFileName); /* * Write the data file */ caretDataFile->writeFile(caretDataFile->getFileName()); caretDataFile->clearModified(); /* * File has been successfully written. * Perform any post-write actions. */ const DataFileTypeEnum::Enum dataFileType = caretDataFile->getDataFileType(); switch (dataFileType) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: break; case DataFileTypeEnum::METRIC: break; case DataFileTypeEnum::METRIC_DYNAMIC: break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: { /* * Add to recent scene files */ CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->addToPreviousSceneFiles(caretDataFile->getFileName()); } break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: break; } } /** * Remove the data file from memory but DO NOT delete it. * * @param caretDataFile * Caret file that is removed from the Brain. After calling this method * and the file was removed( true was returned), the caller is responsible * for deleting the file when it is no longer needed. * @return * True if the file was removed, else false. */ bool Brain::removeWithoutDeleteDataFile(const CaretDataFile* caretDataFile) { if (caretDataFile == NULL) { return false; } /* * dynamic files are not removable. */ bool canBeRemovedFlag(true); switch (caretDataFile->getDataFileType()) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: canBeRemovedFlag = false; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: break; case DataFileTypeEnum::METRIC: break; case DataFileTypeEnum::METRIC_DYNAMIC: canBeRemovedFlag = false; break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: canBeRemovedFlag = false; break; } if ( ! canBeRemovedFlag) { return false; } const bool wasRemoved = removeWithoutDeleteDataFilePrivate(caretDataFile); if (wasRemoved) { /* Scene annotation file is NOT in the spec file */ if (caretDataFile != m_sceneAnnotationFile) { m_specFile->removeCaretDataFile(caretDataFile); } updateAfterFilesAddedOrRemoved(); } else { CaretLogSevere("Software bug: failed to remove file type=" + DataFileTypeEnum::toName(caretDataFile->getDataFileType()) + " name=" + caretDataFile->getFileName()); } return wasRemoved; } /** * Remove the data file from memory but DO NOT delete it. * * @param caretDataFile * Caret file that is removed from the Brain. After calling this method * and the file was removed( true was returned), the caller is responsible * for deleting the file when it is no longer needed. * @return * True if the file was removed, else false. */ bool Brain::removeWithoutDeleteDataFilePrivate(const CaretDataFile* caretDataFile) { const int32_t numBrainStructures = getNumberOfBrainStructures(); for (int32_t i = 0; i < numBrainStructures; i++) { if (getBrainStructure(i)->removeWithoutDeleteDataFile(caretDataFile)) { return true; } } std::vector::iterator annotationIterator = std::find(m_annotationFiles.begin(), m_annotationFiles.end(), caretDataFile); if (annotationIterator != m_annotationFiles.end()) { m_annotationFiles.erase(annotationIterator); return true; } if (caretDataFile == m_sceneAnnotationFile) { m_sceneAnnotationFile->clear(); m_sceneAnnotationFile->clearModified(); return true; } auto annSubIter = std::find(m_annotationSubstitutionFiles.begin(), m_annotationSubstitutionFiles.end(), caretDataFile); if (annSubIter != m_annotationSubstitutionFiles.end()) { m_annotationSubstitutionFiles.erase(annSubIter); return true; } std::vector::iterator borderIterator = std::find(m_borderFiles.begin(), m_borderFiles.end(), caretDataFile); if (borderIterator != m_borderFiles.end()) { m_borderFiles.erase(borderIterator); return true; } std::vector::iterator dataSeriesIterator = std::find(m_connectivityDataSeriesFiles.begin(), m_connectivityDataSeriesFiles.end(), caretDataFile); if (dataSeriesIterator != m_connectivityDataSeriesFiles.end()) { m_connectivityDataSeriesFiles.erase(dataSeriesIterator); return true; } std::vector::iterator connLabelIterator = std::find(m_connectivityDenseLabelFiles.begin(), m_connectivityDenseLabelFiles.end(), caretDataFile); if (connLabelIterator != m_connectivityDenseLabelFiles.end()) { m_connectivityDenseLabelFiles.erase(connLabelIterator); return true; } std::vector::iterator connDenseIterator = std::find(m_connectivityMatrixDenseFiles.begin(), m_connectivityMatrixDenseFiles.end(), caretDataFile); if (connDenseIterator != m_connectivityMatrixDenseFiles.end()) { m_connectivityMatrixDenseFiles.erase(connDenseIterator); return true; } /* Note: There is no test for dense dynamic files as they are a child of data sereies file */ std::vector::iterator connDenseParcelIterator = std::find(m_connectivityMatrixDenseParcelFiles.begin(), m_connectivityMatrixDenseParcelFiles.end(), caretDataFile); if (connDenseParcelIterator != m_connectivityMatrixDenseParcelFiles.end()) { m_connectivityMatrixDenseParcelFiles.erase(connDenseParcelIterator); return true; } std::vector::iterator connScalarIterator = std::find(m_connectivityDenseScalarFiles.begin(), m_connectivityDenseScalarFiles.end(), caretDataFile); if (connScalarIterator != m_connectivityDenseScalarFiles.end()) { m_connectivityDenseScalarFiles.erase(connScalarIterator); return true; } std::vector::iterator connParcelSeriesIterator = std::find(m_connectivityParcelSeriesFiles.begin(), m_connectivityParcelSeriesFiles.end(), caretDataFile); if (connParcelSeriesIterator != m_connectivityParcelSeriesFiles.end()) { m_connectivityParcelSeriesFiles.erase(connParcelSeriesIterator); return true; } std::vector::iterator connParcelLabelIterator = std::find(m_connectivityParcelLabelFiles.begin(), m_connectivityParcelLabelFiles.end(), caretDataFile); if (connParcelLabelIterator != m_connectivityParcelLabelFiles.end()) { m_connectivityParcelLabelFiles.erase(connParcelLabelIterator); return true; } std::vector::iterator connParcelScalarIterator = std::find(m_connectivityParcelScalarFiles.begin(), m_connectivityParcelScalarFiles.end(), caretDataFile); if (connParcelScalarIterator != m_connectivityParcelScalarFiles.end()) { m_connectivityParcelScalarFiles.erase(connParcelScalarIterator); return true; } std::vector::iterator connScalarDataSeriesIterator = std::find(m_connectivityScalarDataSeriesFiles.begin(), m_connectivityScalarDataSeriesFiles.end(), caretDataFile); if (connScalarDataSeriesIterator != m_connectivityScalarDataSeriesFiles.end()) { m_connectivityScalarDataSeriesFiles.erase(connScalarDataSeriesIterator); return true; } std::vector::iterator connFiberOrientationIterator = std::find(m_connectivityFiberOrientationFiles.begin(), m_connectivityFiberOrientationFiles.end(), caretDataFile); if (connFiberOrientationIterator != m_connectivityFiberOrientationFiles.end()) { m_connectivityFiberOrientationFiles.erase(connFiberOrientationIterator); return true; } std::vector::iterator connFiberTrajectoryIterator = std::find(m_connectivityFiberTrajectoryFiles.begin(), m_connectivityFiberTrajectoryFiles.end(), caretDataFile); if (connFiberTrajectoryIterator != m_connectivityFiberTrajectoryFiles.end()) { m_connectivityFiberTrajectoryFiles.erase(connFiberTrajectoryIterator); return true; } std::vector::iterator connParcelIterator = std::find(m_connectivityMatrixParcelFiles.begin(), m_connectivityMatrixParcelFiles.end(), caretDataFile); if (connParcelIterator != m_connectivityMatrixParcelFiles.end()) { m_connectivityMatrixParcelFiles.erase(connParcelIterator); return true; } std::vector::iterator connParcelDenseIterator = std::find(m_connectivityMatrixParcelDenseFiles.begin(), m_connectivityMatrixParcelDenseFiles.end(), caretDataFile); if (connParcelDenseIterator != m_connectivityMatrixParcelDenseFiles.end()) { m_connectivityMatrixParcelDenseFiles.erase(connParcelDenseIterator); return true; } std::vector::iterator fociIterator = std::find(m_fociFiles.begin(), m_fociFiles.end(), caretDataFile); if (fociIterator != m_fociFiles.end()) { m_fociFiles.erase(fociIterator); return true; } std::vector::iterator imageIterator = std::find(m_imageFiles.begin(), m_imageFiles.end(), caretDataFile); if (imageIterator != m_imageFiles.end()) { m_imageFiles.erase(imageIterator); return true; } if (m_paletteFile == caretDataFile) { if (m_paletteFile != NULL) { CaretLogSevere("Cannot remove PaletteFile at this time."); } } std::vector::iterator sceneIterator = std::find(m_sceneFiles.begin(), m_sceneFiles.end(), caretDataFile); if (sceneIterator != m_sceneFiles.end()) { m_sceneFiles.erase(sceneIterator); return true; } std::vector::iterator volumeIterator = std::find(m_volumeFiles.begin(), m_volumeFiles.end(), caretDataFile); if (volumeIterator != m_volumeFiles.end()) { m_volumeFiles.erase(volumeIterator); return true; } return false; } /** * Remove AND DELETE a data file from memory (does NOT delete file on disk.) * Searches all of the loaded files for given file, and, when found * deletes the file. * * @param caretDataFile * Data file to remove. After calling this method and the file was * deleted (true was returned) this pointer is no longer valid. * @return * true if file was removed, else false. */ bool Brain::removeAndDeleteDataFile(CaretDataFile* caretDataFile) { if (removeWithoutDeleteDataFile(caretDataFile)) { /* NEVER delete scene annotation file */ if (caretDataFile == m_sceneAnnotationFile) { m_sceneAnnotationFile->clear(); m_sceneAnnotationFile->clearModified(); } else { delete caretDataFile; } return true; } return false; } /** * @return The annotation display properties. */ DisplayPropertiesAnnotation* Brain::getDisplayPropertiesAnnotation() { return m_displayPropertiesAnnotation; } /** * @return The annotation display properties. */ const DisplayPropertiesAnnotation* Brain::getDisplayPropertiesAnnotation() const { return m_displayPropertiesAnnotation; } /** * @return The annotation text substitution display properties. */ DisplayPropertiesAnnotationTextSubstitution* Brain::getDisplayPropertiesAnnotationTextSubstitution() { return m_displayPropertiesAnnotationTextSubstitution; } /** * @return The annotation text substitution display properties. */ const DisplayPropertiesAnnotationTextSubstitution* Brain::getDisplayPropertiesAnnotationTextSubstitution() const { return m_displayPropertiesAnnotationTextSubstitution; } /** * @return The border display properties. */ DisplayPropertiesBorders* Brain::getDisplayPropertiesBorders() { return m_displayPropertiesBorders; } /** * @return The border display properties. */ const DisplayPropertiesBorders* Brain::getDisplayPropertiesBorders() const { return m_displayPropertiesBorders; } /** * @return The fiber orientation display properties. */ DisplayPropertiesFiberOrientation* Brain::getDisplayPropertiesFiberOrientation() { return m_displayPropertiesFiberOrientation; } /** * @return The fiber orientation display properties. */ const DisplayPropertiesFiberOrientation* Brain::getDisplayPropertiesFiberOrientation() const { return m_displayPropertiesFiberOrientation; } /** * @return The foci display properties. */ DisplayPropertiesFoci* Brain::getDisplayPropertiesFoci() { return m_displayPropertiesFoci; } /** * @return The foci display properties. */ const DisplayPropertiesFoci* Brain::getDisplayPropertiesFoci() const { return m_displayPropertiesFoci; } /** * @return The label display properties. */ DisplayPropertiesImages* Brain::getDisplayPropertiesImages() { return m_displayPropertiesImages; } /** * @return The label display properties. */ const DisplayPropertiesImages* Brain::getDisplayPropertiesImages() const { return m_displayPropertiesImages; } /** * @return The label display properties. */ DisplayPropertiesLabels* Brain::getDisplayPropertiesLabels() { return m_displayPropertiesLabels; } /** * @return The label display properties. */ const DisplayPropertiesLabels* Brain::getDisplayPropertiesLabels() const { return m_displayPropertiesLabels; } /** * @return The volume display properties. */ DisplayPropertiesVolume* Brain::getDisplayPropertiesVolume() { return m_displayPropertiesVolume; } /** * @return The volume display properties. */ const DisplayPropertiesVolume* Brain::getDisplayPropertiesVolume() const { return m_displayPropertiesVolume; } /** * @return The surface display properties. */ DisplayPropertiesSurface* Brain::getDisplayPropertiesSurface() { return m_displayPropertiesSurface; } /** * @return The volume display properties. */ const DisplayPropertiesSurface* Brain::getDisplayPropertiesSurface() const { return m_displayPropertiesSurface; } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* Brain::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { bool isSaveSpecFile = false; switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: isSaveSpecFile = true; break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } SceneClass* sceneClass = new SceneClass(instanceName, "Brain", 1); /* * Get all data files */ std::vector allCaretDataFiles; getAllDataFiles(allCaretDataFiles); /* * Save data files into an array. * Note that data file's saveToScene returns NULL if no data for saving. */ std::vector allCaretDataFileScenes; for (std::vector::iterator iter = allCaretDataFiles.begin(); iter != allCaretDataFiles.end(); iter++) { CaretDataFile* cdf = *iter; const AString caretDataFileName = cdf->getFileNameNoPath(); SceneClass* caretDataFileSceneClass = cdf->saveToScene(sceneAttributes, caretDataFileName); if (caretDataFileSceneClass != NULL) { caretDataFileSceneClass->addPathName("dataFileName_V2", cdf->getFileName()); allCaretDataFileScenes.push_back(caretDataFileSceneClass); } } if (allCaretDataFileScenes.empty() == false) { SceneClassArray* caretDataFileSceneArray = new SceneClassArray("allCaretDataFiles_V2", allCaretDataFileScenes); sceneClass->addChild(caretDataFileSceneArray); } if (isSaveSpecFile) { SpecFile sf; sf.setFileName(m_specFile->getFileName()); for (std::vector::iterator iter = allCaretDataFiles.begin(); iter != allCaretDataFiles.end(); iter++) { CaretDataFile* cdf = *iter; sf.addCaretDataFile(cdf); } sceneClass->addClass(sf.saveToScene(sceneAttributes, "specFile")); } m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); /* * Clear modification status of scene annotations */ m_sceneAnnotationFile->clearModified(); /* * Save all DISPLAYED models */ std::vector modelClassVector; EventModelGetAllDisplayed getAllModels; EventManager::get()->sendEvent(getAllModels.getPointer()); std::set allModels = getAllModels.getModels(); for (auto mdc : allModels) { modelClassVector.push_back(mdc->saveToScene(sceneAttributes, "models")); } SceneClassArray* modelsClassArray = new SceneClassArray("models", modelClassVector); sceneClass->addChild(modelsClassArray); /* * Save all brain structures */ const int32_t numBrainStructures = getNumberOfBrainStructures(); SceneClassArray* brainStructureClassArray = new SceneClassArray("m_brainStructures", numBrainStructures); for (int32_t i = 0; i < numBrainStructures; i++) { const AString name = ("m_brainStructures[" + AString::number(i) + "]"); brainStructureClassArray->setClassAtIndex(i, m_brainStructures[i]->saveToScene(sceneAttributes, name)); } sceneClass->addChild(brainStructureClassArray); /* * Save Group/Name Selection Hierarchies */ for (std::vector::iterator borderIter = m_borderFiles.begin(); borderIter != m_borderFiles.end(); borderIter++) { BorderFile* bf = *borderIter; sceneClass->addClass(bf->getGroupAndNameHierarchyModel()->saveToScene(sceneAttributes, bf->getFileNameNoPath())); } for (std::vector::iterator fociIter = m_fociFiles.begin(); fociIter != m_fociFiles.end(); fociIter++) { FociFile* ff = *fociIter; sceneClass->addClass(ff->getGroupAndNameHierarchyModel()->saveToScene(sceneAttributes, ff->getFileNameNoPath())); } sceneClass->addClass(m_identificationManager->saveToScene(sceneAttributes, "m_identificationManager")); sceneClass->addClass(m_brainordinateHighlightRegionOfInterest->saveToScene(sceneAttributes, "m_brainordinateHighlightRegionOfInterest")); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. May be NULL for some types of scenes. */ void Brain::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } /* * Prior to restoring the scene, make a copy of the current spec file * so that the "in spec" status for data files within the spec file * can be preserved. */ const SpecFile preSceneLoadSpecFile(*m_specFile); bool isLoadFiles = false; switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: isLoadFiles = true; break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } if (isLoadFiles) { SpecFile specFile; specFile.restoreFromScene(sceneAttributes, sceneClass->getClass("specFile")); loadSpecFileFromScene(sceneAttributes, &specFile, RESET_BRAIN_KEEP_SCENE_FILES_YES, RESET_BRAIN_KEEP_SPEC_FILE_YES); } /* * Preserve "in spec" status prior to loading of scene. */ m_specFile->transferDataFilesInSpecStatus(preSceneLoadSpecFile); /* * Add all scene files to the spec file (but not a member of * the spec file) since a scene file may not be in the spec file. */ const bool specFileModStatus = m_specFile->isModified(); for (std::vector::iterator sceneIter = m_sceneFiles.begin(); sceneIter != m_sceneFiles.end(); sceneIter++) { m_specFile->addCaretDataFile(*sceneIter); } if (specFileModStatus == false) { m_specFile->clearModified(); } /* * Get all data files */ std::vector allCaretDataFiles; getAllDataFiles(allCaretDataFiles); /* * Restore data files. Try to restore "V2" and if not found, restore older version */ const SceneClassArray* caretDataFileSceneArrayV2 = sceneClass->getClassArray("allCaretDataFiles_V2"); const SceneClassArray* caretDataFileSceneArray = sceneClass->getClassArray("allCaretDataFiles"); if (caretDataFileSceneArrayV2 != NULL) { /* * Note: Name of element is name of file without path. * A child of the element contains a ScenePathName containing * name of file (full path in memory and relative to scene * file name when file is written. */ for (auto caretDataFile : allCaretDataFiles) { CaretAssert(caretDataFile); const AString caretDataFileNameFullPath = caretDataFile->getFileName(); const AString caretDataFileName = caretDataFile->getFileNameNoPath(); const int32_t numCaretDataFileScenes = caretDataFileSceneArrayV2->getNumberOfArrayElements(); for (int32_t i = 0; i < numCaretDataFileScenes; i++) { const SceneClass* fileSceneClass = caretDataFileSceneArrayV2->getClassAtIndex(i); const AString fileName = fileSceneClass->getName(); if (fileName == caretDataFileName) { const AString fullPathFileName = fileSceneClass->getPathNameValue("dataFileName_V2"); if (fullPathFileName == caretDataFileNameFullPath) { caretDataFile->restoreFromScene(sceneAttributes, fileSceneClass); loadMatrixChartingFileDefaultRowOrColumn(caretDataFile); break; // get out of inner file loop } } } } } else if (caretDataFileSceneArray != NULL) { /* * Restore old file data that used full pathss */ for (std::vector::iterator iter = allCaretDataFiles.begin(); iter != allCaretDataFiles.end(); iter++) { CaretDataFile* caretDataFile = *iter; CaretAssert(caretDataFile); const AString caretDataFileNameNoPath = caretDataFile->getFileNameNoPath(); const AString caretDataFileNameFullPath = caretDataFile->getFileName(); SceneClass* bestMatchingSceneClass = NULL; int64_t bestMatchingCount = 0; const int32_t numCaretDataFileScenes = caretDataFileSceneArray->getNumberOfArrayElements(); for (int32_t i = 0; i < numCaretDataFileScenes; i++) { const SceneClass* fileSceneClass = caretDataFileSceneArray->getClassAtIndex(i); const AString fileNameFullPath = fileSceneClass->getName(); const FileInformation fileInfo(fileNameFullPath); const AString fileNameNoPath = fileInfo.getFileName(); if (caretDataFileNameNoPath == fileNameNoPath) { const int64_t matchCount = caretDataFileNameFullPath.countMatchingCharactersFromEnd(fileNameFullPath); if (matchCount > bestMatchingCount) { bestMatchingSceneClass = const_cast(fileSceneClass); bestMatchingCount = matchCount; } // caretDataFile->restoreFromScene(sceneAttributes, // fileSceneClass); } } if (bestMatchingCount > 0) { CaretAssert(bestMatchingSceneClass); caretDataFile->restoreFromScene(sceneAttributes, bestMatchingSceneClass); } loadMatrixChartingFileDefaultRowOrColumn(caretDataFile); } } /* * Fiber trajectory files need special handling after restoring a scene. */ updateFiberTrajectoryMatchingFiberOrientationFiles(); for (std::vector::iterator iter = m_connectivityFiberTrajectoryFiles.begin(); iter != m_connectivityFiberTrajectoryFiles.end(); iter++) { CiftiFiberTrajectoryFile* trajFile = *iter; trajFile->finishRestorationOfScene(); } /* * Restore members */ m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); /* * Need to color all connectivity matrix files */ std::vector ciftiMatrixFiles; getAllCiftiConnectivityMatrixFiles(ciftiMatrixFiles); for (std::vector::iterator iter = ciftiMatrixFiles.begin(); iter != ciftiMatrixFiles.end(); iter++) { CiftiMappableConnectivityMatrixDataFile* cmf = *iter; if (cmf->isEmpty() == false) { const int32_t mapIndex = 0; cmf->updateScalarColoringForMap(mapIndex); } } /* * Need to color all volume files since a thresholded volume may * not get loaded until after its "thresholdee" */ for (auto vf : m_volumeFiles) { vf->updateScalarColoringForAllMaps(); } /* * Restore all models */ EventModelGetAll getAllModels; EventManager::get()->sendEvent(getAllModels.getPointer()); std::vector allModels = getAllModels.getModels(); for (auto model : allModels) { model->setRestoredFromScene(false); } const SceneClassArray* modelsClassArray = sceneClass->getClassArray("models"); const int32_t numModelClasses = modelsClassArray->getNumberOfArrayElements(); for (int32_t i = 0; i < numModelClasses; i++) { /* * Apply to all models. Each model will only use the saved * scene information that is applicable. */ for (std::vector::iterator iter = allModels.begin(); iter != allModels.end(); iter++) { Model* mdc = *iter; mdc->restoreFromScene(sceneAttributes, modelsClassArray->getClassAtIndex(i)); } } /* * Apply each of the saved brain structures to each of the loaded brain structures. * The loaded brain structure will examine the structure and number of nodes in each * saved brain structure to determine the proper one to use for restoration */ const SceneClassArray* brainStructureClassArray = sceneClass->getClassArray("m_brainStructures"); const int32_t numSavedBrainStructures = brainStructureClassArray->getNumberOfArrayElements(); const int32_t numValidBrainStructures = getNumberOfBrainStructures(); for (int32_t i = 0; i < numValidBrainStructures; i++) { BrainStructure* bs = m_brainStructures[i]; for (int32_t j = 0; j < numSavedBrainStructures; j++) { bs->restoreFromScene(sceneAttributes, brainStructureClassArray->getClassAtIndex(j)); } } switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } /* * Restore Group/Name Selection Hierarchies */ for (std::vector::iterator borderIter = m_borderFiles.begin(); borderIter != m_borderFiles.end(); borderIter++) { BorderFile* bf = *borderIter; const SceneClass* borderScene = sceneClass->getClass(bf->getFileNameNoPath()); if (borderScene != NULL) { /* * WB-533 Default State of Borders in Scenes * * When there is scene information for a border file, disable the display * of all classes and names prior to restoring the class/name hierarchy. * The purpose of this is to prevent the display of borders that have been * added to the border file AFTER the scene was created. */ GroupAndNameHierarchyModel* groupAndNameModel = bf->getGroupAndNameHierarchyModel(); groupAndNameModel->setAllSelected(false); bf->getGroupAndNameHierarchyModel()->restoreFromScene(sceneAttributes, borderScene); } } for (std::vector::iterator fociIter = m_fociFiles.begin(); fociIter != m_fociFiles.end(); fociIter++) { FociFile* ff = *fociIter; ff->getGroupAndNameHierarchyModel()->restoreFromScene(sceneAttributes, sceneClass->getClass(ff->getFileNameNoPath())); } m_identificationManager->restoreFromScene(sceneAttributes, sceneClass->getClass("m_identificationManager")); m_brainordinateHighlightRegionOfInterest->restoreFromScene(sceneAttributes, sceneClass->getClass("m_brainordinateHighlightRegionOfInterest")); m_sceneAnnotationFile->clearModified(); EventManager::get()->sendEvent(EventAnnotationTextSubstitutionInvalidate().getPointer()); setSurfaceMatchingToAnatomical(m_surfaceMatchingToAnatomicalFlag); } /** * Load the default row/column for a matrix charting file. * If the file is not matrix chartable, no action is taken. * * @param caretDataFile * The Caret Data File. */ void Brain::loadMatrixChartingFileDefaultRowOrColumn(CaretDataFile* caretDataFile) { if (caretDataFile == NULL) { return; } CaretMappableDataFile* cmdf = dynamic_cast(caretDataFile); if (cmdf != NULL) { cmdf->getChartingDelegate()->getMatrixCharting()->loadDefaultRowOrColumn(); } } /** * If model one charts are in scene but not * model two charts, attempt to restore model * one charts to model two charts. * * This must be performed AFTER browser tabs * have been restored by the SessionManager. */ void Brain::restoreModelChartOneToModelChartTwo() { if (m_modelChartTwo != NULL) { if (m_modelChartTwo->isRestoredFromScene()) { return; } } if (m_modelChart != NULL) { if (m_modelChart->isRestoredFromScene()) { if (m_modelChartTwo == NULL) { createModelChartTwo(); } m_modelChartTwo->restoreSceneFromChartOneModel(m_modelChart); } } } /** * @return The gaps and margins. */ GapsAndMargins* Brain::getGapsAndMargins() { return m_gapsAndMargins; } /** * @return the gaps and margins. */ const GapsAndMargins* Brain::getGapsAndMargins() const { return m_gapsAndMargins; } /** * @return The selection manager. */ SelectionManager* Brain::getSelectionManager() { return m_selectionManager; } /** * @return The identification manager. */ IdentificationManager* Brain::getIdentificationManager() { return m_identificationManager; } /** Region of interest for highlighting brainordinates */ BrainordinateRegionOfInterest* Brain::getBrainordinateHighlightRegionOfInterest() { return m_brainordinateHighlightRegionOfInterest; } const BrainordinateRegionOfInterest* Brain::getBrainordinateHighlightRegionOfInterest() const { return m_brainordinateHighlightRegionOfInterest; } /** * Get the fiber orientation sample vectors for display on a sphere. * * @param xVectors * Vectors for X-orientation. * @param yVectors * Vectors for Y-orientation. * @param zVectors * Vectors for Z-orientation. * @param fiberOrientation * The nearby fiber orientation * @param errorMessageOut * Will contain any error messages. * This error message will only be set in some cases when there is an * error. * @return * True if data is valid, else false. */ bool Brain::getFiberOrientationSphericalSamplesVectors(std::vector& xVectors, std::vector& yVectors, std::vector& zVectors, FiberOrientation* &fiberOrientationOut, AString& errorMessageOut) { CaretAssert(m_fiberOrientationSamplesLoader); return m_fiberOrientationSamplesLoader->getFiberOrientationSphericalSamplesVectors(this, xVectors, yVectors, zVectors, fiberOrientationOut, errorMessageOut); } /** * @return True if surface matching to anatomical is enabled */ bool Brain::isSurfaceMatchingToAnatomical() const { return m_surfaceMatchingToAnatomicalFlag; } /** * Set the surface matching to anatomical surface status */ void Brain::setSurfaceMatchingToAnatomical(const bool matchStatus) { m_surfaceMatchingToAnatomicalFlag = matchStatus; for (auto bs : m_brainStructures) { bs->matchSurfacesToPrimaryAnatomical(m_surfaceMatchingToAnatomicalFlag); } } connectome-workbench-1.4.2/src/Brain/Brain.h000066400000000000000000001166611360521144700206740ustar00rootroot00000000000000#ifndef __BRAIN_H__ #define __BRAIN_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretObject.h" #include "ChartOneDataTypeEnum.h" #include "DataFileTypeEnum.h" #include "DisplayGroupEnum.h" #include "EventListenerInterface.h" #include "FiberOrientationSamplesLoader.h" #include "FiberOrientationSamplesVector.h" #include "FileInformation.h" #include "SceneableInterface.h" #include "StructureEnum.h" #include "VolumeFile.h" namespace caret { class AnnotationFile; class AnnotationTextSubstitutionFile; class AnnotationManager; class Border; class BorderFile; class BorderPointFromSearch; class BrainordinateRegionOfInterest; class FociFile; class BrainStructure; class CaretDataFile; class CaretMappableDataFile; class CaretPreferences; class ChartingDataManager; class ChartableLineSeriesBrainordinateInterface; class ChartableMatrixInterface; class CiftiBrainordinateDataSeriesFile; class CiftiBrainordinateLabelFile; class CiftiBrainordinateScalarFile; class CiftiConnectivityMatrixDenseFile; class CiftiConnectivityMatrixDenseDynamicFile; class CiftiConnectivityMatrixDenseParcelFile; class CiftiConnectivityMatrixParcelFile; class CiftiConnectivityMatrixParcelDenseFile; class CiftiFiberOrientationFile; class CiftiFiberTrajectoryFile; class CiftiMappableDataFile; class CiftiMappableConnectivityMatrixDataFile; class CiftiParcelLabelFile; class CiftiParcelSeriesFile; class CiftiParcelScalarFile; class CiftiScalarDataSeriesFile; class DisplayProperties; class DisplayPropertiesAnnotation; class DisplayPropertiesAnnotationTextSubstitution; class DisplayPropertiesBorders; class DisplayPropertiesFiberOrientation; class DisplayPropertiesFoci; class DisplayPropertiesImages; class DisplayPropertiesLabels; class DisplayPropertiesSurface; class DisplayPropertiesVolume; class EventDataFileRead; class EventDataFileReload; class EventSpecFileReadDataFiles; class GapsAndMargins; class IdentificationManager; class ImageFile; class LabelFile; class MetricFile; class MetricDynamicConnectivityFile; class ModelChart; class ModelChartTwo; class ModelSurfaceMontage; class ModelVolume; class ModelWholeBrain; class PaletteFile; class RgbaFile; class SceneClassAssistant; class Scene; class SceneFile; class SelectionManager; class SpecFile; class Surface; class SurfaceFile; class SurfaceProjectedItem; class VolumeDynamicConnectivityFile; class VolumeFile; class Brain : public CaretObject, public EventListenerInterface, public SceneableInterface { public: Brain(const CaretPreferences* caretPreferences); ~Brain(); private: Brain(const Brain&); Brain& operator=(const Brain&); public: int getNumberOfBrainStructures() const; void addBrainStructure(BrainStructure* brainStructure); BrainStructure* getBrainStructure(const int32_t indx); const BrainStructure* getBrainStructure(const int32_t indx) const; BrainStructure* getBrainStructure(StructureEnum::Enum structure, bool createIfNotFound); int32_t getNumberOfBorderFiles() const; BorderFile* getBorderFile(const int32_t indx); const BorderFile* getBorderFile(const int32_t indx) const; void getAllAnnotationFilesIncludingSceneAnnotationFile(std::vector& annotationFilesOut) const; void getAllAnnotationFilesExcludingSceneAnnotationFile(std::vector& annotationFilesOut) const; AnnotationFile* getSceneAnnotationFile(); const AnnotationFile* getSceneAnnotationFile() const; void getAnnotationTextSubstitutionFiles(std::vector& annSubFilesOut) const; int32_t getNumberOfFociFiles() const; FociFile* getFociFile(const int32_t indx); const FociFile* getFociFile(const int32_t indx) const; const std::vector getAllImagesFiles() const; int32_t getNumberOfImageFiles() const; ImageFile* getImageFile(const int32_t indx); const ImageFile* getImageFile(const int32_t indx) const; PaletteFile* getPaletteFile(); const PaletteFile* getPaletteFile() const; int32_t getNumberOfSceneFiles() const; SceneFile* getSceneFile(const int32_t indx); const SceneFile* getSceneFile(const int32_t indx) const; const SpecFile* getSpecFile() const; SpecFile* getSpecFile(); Surface* getSurfaceWithName(const AString& surfaceFileName, const bool useAbsolutePath); const Surface* getPrimaryAnatomicalSurfaceForStructure(const StructureEnum::Enum structure) const; Surface* getPrimaryAnatomicalSurfaceNearestCoordinate(const float xyz[3], const float tolerance); std::vector getPrimaryAnatomicalSurfaces() const; std::vector getPrimaryAnatomicalSurfaceFiles() const; int32_t getNumberOfVolumeFiles() const; VolumeFile* getVolumeFile(const int32_t volumeFileIndex); const VolumeFile* getVolumeFile(const int32_t volumeFileIndex) const; void getVolumeDynamicConnectivityFiles(std::vector& volumeDynamicConnectivityFilesOut) const; void getMetricDynamicConnectivityFiles(std::vector& metricDynamicConnectivityFilesOut) const; void resetBrain(); void resetBrainKeepSceneFiles(); void receiveEvent(Event* event); AnnotationManager* getAnnotationManager(); const AnnotationManager* getAnnotationManager() const; ModelChart* getChartModel(); const ModelChart* getChartModel() const; ModelChartTwo* getChartTwoModel(); const ModelChartTwo* getChartTwoModel() const; ChartingDataManager* getChartingDataManager(); const ChartingDataManager* getChartingDataManager() const; void getAllCiftiMappableDataFiles(std::vector& allCiftiMappableDataFilesOut) const; int32_t getNumberOfConnectivityMatrixDenseFiles() const; CiftiConnectivityMatrixDenseFile* getConnectivityMatrixDenseFile(int32_t indx); const CiftiConnectivityMatrixDenseFile* getConnectivityMatrixDenseFile(int32_t indx) const; void getConnectivityMatrixDenseFiles(std::vector& connectivityDenseFilesOut) const; void getConnectivityMatrixDenseDynamicFiles(std::vector& connectivityDenseDynamicFilesOut) const; int32_t getNumberOfConnectivityDenseLabelFiles() const; CiftiBrainordinateLabelFile* getConnectivityDenseLabelFile(int32_t indx); const CiftiBrainordinateLabelFile* getConnectivityDenseLabelFile(int32_t indx) const; void getConnectivityDenseLabelFiles(std::vector& connectivityDenseLabelFilesOut) const; int32_t getNumberOfConnectivityMatrixDenseParcelFiles() const; CiftiConnectivityMatrixDenseParcelFile* getConnectivityMatrixDenseParcelFile(int32_t indx); const CiftiConnectivityMatrixDenseParcelFile* getConnectivityMatrixDenseParcelFile(int32_t indx) const; void getConnectivityMatrixDenseParcelFiles(std::vector& connectivityDenseParcelFilesOut) const; int32_t getNumberOfConnectivityDenseScalarFiles() const; CiftiBrainordinateScalarFile* getConnectivityDenseScalarFile(int32_t indx); const CiftiBrainordinateScalarFile* getConnectivityDenseScalarFile(int32_t indx) const; void getConnectivityDenseScalarFiles(std::vector& connectivityDenseScalarFilesOut) const; int32_t getNumberOfConnectivityParcelLabelFiles() const; CiftiParcelLabelFile* getConnectivityParcelLabelFile(int32_t indx); const CiftiParcelLabelFile* getConnectivityParcelLabelFile(int32_t indx) const; void getConnectivityParcelLabelFiles(std::vector& connectivityParcelLabelFilesOut) const; int32_t getNumberOfConnectivityParcelScalarFiles() const; CiftiParcelScalarFile* getConnectivityParcelScalarFile(int32_t indx); const CiftiParcelScalarFile* getConnectivityParcelScalarFile(int32_t indx) const; void getConnectivityParcelScalarFiles(std::vector& connectivityParcelScalarFilesOut) const; int32_t getNumberOfConnectivityScalarDataSeriesFiles() const; CiftiScalarDataSeriesFile* getConnectivityScalarDataSeriesFile(int32_t indx); const CiftiScalarDataSeriesFile* getConnectivityScalarDataSeriesFile(int32_t indx) const; void getConnectivityScalarDataSeriesFiles(std::vector& connectivityScalarDataSeriesFilesOut) const; int32_t getNumberOfConnectivityParcelSeriesFiles() const; CiftiParcelSeriesFile* getConnectivityParcelSeriesFile(int32_t indx); const CiftiParcelSeriesFile* getConnectivityParcelSeriesFile(int32_t indx) const; void getConnectivityParcelSeriesFiles(std::vector& connectivityParcelSeriesFilesOut) const; int32_t getNumberOfConnectivityFiberOrientationFiles() const; CiftiFiberOrientationFile* getConnectivityFiberOrientationFile(int32_t indx); const CiftiFiberOrientationFile* getConnectivityFiberOrientationFile(int32_t indx) const; void getConnectivityFiberOrientationFiles(std::vector& connectivityFiberOrientationFilesOut) const; bool getFiberOrientationSphericalSamplesVectors(std::vector& xVectors, std::vector& yVectors, std::vector& zVectors, FiberOrientation* &fiberOrientationOut, AString& errorMessageOut); int32_t getNumberOfConnectivityFiberTrajectoryFiles() const; CiftiFiberTrajectoryFile* getConnectivityFiberTrajectoryFile(int32_t indx); const CiftiFiberTrajectoryFile* getConnectivityFiberTrajectoryFile(int32_t indx) const; void getConnectivityFiberTrajectoryFiles(std::vector& ciftiFiberTrajectoryFilesOut) const; int32_t getNumberOfConnectivityMatrixParcelFiles() const; CiftiConnectivityMatrixParcelFile* getConnectivityMatrixParcelFile(int32_t indx); const CiftiConnectivityMatrixParcelFile* getConnectivityMatrixParcelFile(int32_t indx) const; void getConnectivityMatrixParcelFiles(std::vector& connectivityParcelFilesOut) const; int32_t getNumberOfConnectivityMatrixParcelDenseFiles() const; CiftiConnectivityMatrixParcelDenseFile* getConnectivityMatrixParcelDenseFile(int32_t indx); const CiftiConnectivityMatrixParcelDenseFile* getConnectivityMatrixParcelDenseFile(int32_t indx) const; void getConnectivityMatrixParcelDenseFiles(std::vector& connectivityParcelDenseFilesOut) const; int32_t getNumberOfConnectivityTimeSeriesFiles() const; void getAllCiftiConnectivityMatrixFiles(std::vector& allCiftiConnectivityMatrixFiles) const; int32_t getNumberOfConnectivityDataSeriesFiles() const; CiftiBrainordinateDataSeriesFile* getConnectivityDataSeriesFile(int32_t indx); const CiftiBrainordinateDataSeriesFile* getConnectivityDataSeriesFile(int32_t indx) const; void getConnectivityDataSeriesFiles(std::vector& connectivityDataSeriesFilesOut) const; void getAllChartableBrainordinateDataFiles(std::vector& chartableDataFilesOut) const; void getAllChartableLineSeriesDataFiles(std::vector& chartableDataFilesOut) const; void getAllChartableLineSeriesDataFilesForChartDataType(const ChartOneDataTypeEnum::Enum chartDataType, std::vector& chartableDataFilesOut) const; void getAllChartableBrainordinateDataFilesWithChartingEnabled(std::vector& chartableDataFilesOut) const; void getAllChartableMatrixDataFiles(std::vector& chartableDataFilesOut) const; void getAllChartableMatrixDataFilesForChartDataType(const ChartOneDataTypeEnum::Enum chartDataType, std::vector& chartableDataFilesOut) const; AString getCurrentDirectory() const; void setCurrentDirectory(const AString& currentDirectory); void convertDataFilePathNameToAbsolutePathName(CaretDataFile* caretDataFile) const; void getAllDataFiles(std::vector& allDataFilesOut, const bool includeSpecFile = false) const; void getAllDataFilesWithDataFileTypes(const std::vector& dataFileTypes, std::vector& caretDataFilesOut) const; void getAllDataFilesWithDataFileType(const DataFileTypeEnum::Enum dataFileType, std::vector& caretDataFilesOut) const; void getAllMappableDataFiles(std::vector& allCaretMappableDataFilesOut) const; void getAllMappableDataFileWithDataFileType(const DataFileTypeEnum::Enum dataFileType, std::vector& caretMappableDataFilesOut) const; void getAllMappableDataFileWithDataFileTypes(const std::vector& dataFileTypes, std::vector& caretMappableDataFilesOut) const; bool isFileValid(const CaretDataFile* caretDataFile) const; void getAllModifiedFiles(const std::vector& excludeTheseDataTypes, std::vector& modifiedDataFilesOut) const; void writeDataFile(CaretDataFile* caretDataFile); DisplayPropertiesAnnotation* getDisplayPropertiesAnnotation(); const DisplayPropertiesAnnotation* getDisplayPropertiesAnnotation() const; DisplayPropertiesAnnotationTextSubstitution* getDisplayPropertiesAnnotationTextSubstitution(); const DisplayPropertiesAnnotationTextSubstitution* getDisplayPropertiesAnnotationTextSubstitution() const; DisplayPropertiesBorders* getDisplayPropertiesBorders(); const DisplayPropertiesBorders* getDisplayPropertiesBorders() const; DisplayPropertiesFiberOrientation* getDisplayPropertiesFiberOrientation(); const DisplayPropertiesFiberOrientation* getDisplayPropertiesFiberOrientation() const; DisplayPropertiesFoci* getDisplayPropertiesFoci(); const DisplayPropertiesFoci* getDisplayPropertiesFoci() const; DisplayPropertiesVolume* getDisplayPropertiesVolume(); const DisplayPropertiesVolume* getDisplayPropertiesVolume() const; DisplayPropertiesSurface* getDisplayPropertiesSurface(); const DisplayPropertiesSurface* getDisplayPropertiesSurface() const; DisplayPropertiesImages* getDisplayPropertiesImages(); const DisplayPropertiesImages* getDisplayPropertiesImages() const; DisplayPropertiesLabels* getDisplayPropertiesLabels(); const DisplayPropertiesLabels* getDisplayPropertiesLabels() const; void copyDisplayProperties(const int32_t sourceTabIndex, const int32_t targetTabIndex); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); void restoreModelChartOneToModelChartTwo(); void loadMatrixChartingFileDefaultRowOrColumn(CaretDataFile* caretDataFile); IdentificationManager* getIdentificationManager(); SelectionManager* getSelectionManager(); BrainordinateRegionOfInterest* getBrainordinateHighlightRegionOfInterest(); const BrainordinateRegionOfInterest* getBrainordinateHighlightRegionOfInterest() const; void getCiftiShapeMap(CiftiBrainordinateScalarFile* &ciftiScalarShapeFileOut, int32_t& ciftiScalarhapeFileMapIndexOut, std::vector& ciftiScalarNotShapeFilesOut) const; GapsAndMargins* getGapsAndMargins(); const GapsAndMargins* getGapsAndMargins() const; bool isSurfaceMatchingToAnatomical() const; void setSurfaceMatchingToAnatomical(const bool matchStatus); private: /** * Reset the brain scene file mode */ enum ResetBrainKeepSceneFiles { /** Do NOT keep scene files when resetting the brain*/ RESET_BRAIN_KEEP_SCENE_FILES_NO, /** Do keep scene files when resetting the brain*/ RESET_BRAIN_KEEP_SCENE_FILES_YES }; /** * Reset the brain spec file mode */ enum ResetBrainKeepSpecFile { /** Do NOT keep spec files when resetting the brain*/ RESET_BRAIN_KEEP_SPEC_FILE_NO, /** Do keep spec files when resetting the brain*/ RESET_BRAIN_KEEP_SPEC_FILE_YES }; /** * Mode of file reading */ enum FileModeAddReadReload { /** Add the file */ FILE_MODE_ADD, /** Read the file */ FILE_MODE_READ, /** Reload the file */ FILE_MODE_RELOAD }; void addDataFile(CaretDataFile* caretDataFile); bool removeWithoutDeleteDataFile(const CaretDataFile* caretDataFile); bool removeWithoutDeleteDataFilePrivate(const CaretDataFile* caretDataFile); bool removeAndDeleteDataFile(CaretDataFile* caretDataFile); void loadFilesSelectedInSpecFile(EventSpecFileReadDataFiles* readSpecFileDataFilesEvent); void loadSpecFileFromScene(const SceneAttributes* sceneAttributes, SpecFile* specFile, const ResetBrainKeepSceneFiles keepSceneFile, const ResetBrainKeepSpecFile keepSpecFile); void resetBrain(const ResetBrainKeepSceneFiles keepSceneFiles, const ResetBrainKeepSpecFile keepSpecFile); void processReadDataFileEvent(EventDataFileRead* readDataFileEvent); void processReloadDataFileEvent(EventDataFileReload* reloadDataFileEvent); CaretDataFile* readDataFile(const DataFileTypeEnum::Enum dataFileType, const StructureEnum::Enum structure, const AString& dataFileName, const bool markDataFileAsModified); void createModelChartTwo(); /** * Is the data file with the given name already loaded? * * @param loadedDataFiles * All files of a particular data type that are loaded. * @param fileName * File name for matching. */ template static bool dataFileWithNameIsLoaded(const std::vector& loadedDataFiles, const AString& fileName) { typename std::vector::const_iterator iter; for (iter = loadedDataFiles.begin(); iter != loadedDataFiles.end(); iter++) { const DFT* file = *iter; if (file->getFileName() == fileName) { return true; } } return false; } /** * If needed, update the name of a data file so that there are no two files * of the same type with the same name. If a duplicate needs to be created, * an underscore followed by a number is placed in the file name just * before the extension. * * @param loadedDataFiles * All files of a particular data type that are loaded. * @param newDataFile * New data file whose name may get changed if it duplicates * a currently loaded file. */ template void updateDataFileNameIfDuplicate(const std::vector& loadedDataFiles, DFT* newDataFile) { AString newFileName = newDataFile->getFileName(); const DataFileTypeEnum::Enum dataFileType = newDataFile->getDataFileType(); /* * Is there a file of the same name? */ if (dataFileWithNameIsLoaded(loadedDataFiles, newFileName)) { FileInformation fileInfo(newFileName); AString path; AString name; AString extension; fileInfo.getFileComponents(path, name, extension); /* * Modify the filename with a number (duplicate counter) * at the end of the file's name but before the extension's * dot. */ bool done = false; while ( ! done) { const int32_t duplicateCounter = getDuplicateFileNameCounterForFileType(dataFileType); AString versionName = (name + "_" + AString::number(duplicateCounter)); const AString versionFullName = FileInformation::assembleFileComponents(path, versionName, extension); if ( ! dataFileWithNameIsLoaded(loadedDataFiles, versionFullName)) { /* * Update name of file with version number, * Set the file modified (name changed), * and exit loop */ newDataFile->setFileName(versionFullName); newDataFile->setModified(); done = true; } } } } CaretDataFile* addReadOrReloadDataFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const DataFileTypeEnum::Enum dataFileType, const StructureEnum::Enum structure, const AString& dataFileName, const bool markDataFileAsModified); void updateAfterFilesAddedOrRemoved(); LabelFile* addReadOrReloadLabelFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename, const StructureEnum::Enum structure, const bool markDataFileAsModified); MetricFile* addReadOrReloadMetricFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename, const StructureEnum::Enum structure, const bool markDataFileAsModified); RgbaFile* addReadOrReloadRgbaFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename, const StructureEnum::Enum structure, const bool markDataFileAsModified); Surface* addReadOrReloadSurfaceFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename, const StructureEnum::Enum structure, const bool markDataFileAsModified); VolumeFile* addReadOrReloadVolumeFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); AnnotationFile* addReadOrReloadAnnotationFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); AnnotationTextSubstitutionFile* addReadOrReloadAnnotationTextSubstitutionFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); BorderFile* addReadOrReloadBorderFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); CiftiConnectivityMatrixDenseFile* addReadOrReloadConnectivityDenseFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); CiftiBrainordinateLabelFile* addReadOrReloadConnectivityDenseLabelFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); CiftiConnectivityMatrixDenseParcelFile* addReadOrReloadConnectivityMatrixDenseParcelFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); CiftiBrainordinateScalarFile* addReadOrReloadConnectivityDenseScalarFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); CiftiParcelLabelFile* addReadOrReloadConnectivityParcelLabelFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); CiftiParcelScalarFile* addReadOrReloadConnectivityParcelScalarFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); CiftiParcelSeriesFile* addReadOrReloadConnectivityParcelSeriesFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); CiftiScalarDataSeriesFile* addReadOrReloadConnectivityScalarDataSeriesFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); CiftiFiberOrientationFile* addReadOrReloadConnectivityFiberOrientationFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); CiftiFiberTrajectoryFile* addReadOrReloadConnectivityFiberTrajectoryFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); CiftiConnectivityMatrixParcelFile* addReadOrReloadConnectivityMatrixParcelFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); CiftiConnectivityMatrixParcelDenseFile* addReadOrReloadConnectivityMatrixParcelDenseFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); CiftiBrainordinateDataSeriesFile* addReadOrReloadConnectivityDataSeriesFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); FociFile* addReadOrReloadFociFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); ImageFile* addReadOrReloadImageFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); PaletteFile* addReadOrReloadPaletteFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); SceneFile* addReadOrReloadSceneFile(const FileModeAddReadReload fileMode, CaretDataFile* caretDataFile, const AString& filename); AString convertFilePathNameToAbsolutePathName(const AString& filename) const; void initializeDenseDataSeriesFile(CiftiBrainordinateDataSeriesFile* dataSeriesFile); void initializeVolumeFile(VolumeFile* volumeFile); void updateChartModel(); void updateVolumeSliceModel(); void updateWholeBrainModel(); void updateSurfaceMontageModel(); void updateBrainStructures(); void updateFiberTrajectoryMatchingFiberOrientationFiles(); void validateCiftiMappableDataFile(const CiftiMappableDataFile* ciftiMapFile) const; int32_t getDuplicateFileNameCounterForFileType(const DataFileTypeEnum::Enum dataFileType); void resetDuplicateFileNameCounter(const bool preserveSceneFileCounter); std::vector m_brainStructures; std::vector m_annotationFiles; AnnotationFile* m_sceneAnnotationFile; std::vector m_annotationSubstitutionFiles; std::vector m_borderFiles; std::vector m_fociFiles; std::vector m_imageFiles; std::vector m_sceneFiles; PaletteFile* m_paletteFile; std::vector m_connectivityMatrixDenseFiles; std::vector m_connectivityDenseLabelFiles; std::vector m_connectivityMatrixDenseParcelFiles; std::vector m_connectivityDenseScalarFiles; std::vector m_connectivityParcelLabelFiles; std::vector m_connectivityParcelSeriesFiles; std::vector m_connectivityParcelScalarFiles; std::vector m_connectivityScalarDataSeriesFiles; std::vector m_connectivityFiberOrientationFiles; std::vector m_connectivityFiberTrajectoryFiles; std::vector m_connectivityMatrixParcelFiles; std::vector m_connectivityMatrixParcelDenseFiles; std::vector m_connectivityDataSeriesFiles; std::vector m_nonModifiedFilesForRestoringScene; mutable AString m_currentDirectory; SpecFile* m_specFile; std::vector m_volumeFiles; ModelChart* m_modelChart; ModelChartTwo* m_modelChartTwo; ModelVolume* m_volumeSliceModel; ModelWholeBrain* m_wholeBrainModel; ModelSurfaceMontage* m_surfaceMontageModel; ChartingDataManager* m_chartingDataManager; AnnotationManager* m_annotationManager; /** contains all display properties */ std::vector m_displayProperties; /** * Display properties for volume - DO NOT delete since this * is also in the displayProperties std::vector. */ DisplayPropertiesVolume* m_displayPropertiesVolume; /** * Display properties for surface - DO NOT delete since this * is also in the displayProperties std::vector. */ DisplayPropertiesSurface* m_displayPropertiesSurface; /** * Display properties for image - DO NOT delete since this * is also in the displayProperties std::vector. */ DisplayPropertiesImages* m_displayPropertiesImages; /** * Display properties for labels - DO NOT delete since this * is also in the displayProperties std::vector. */ DisplayPropertiesLabels* m_displayPropertiesLabels; /** * Display properties for annotations - DO NOT delete since this * is also in the displayProperties std::vector. */ DisplayPropertiesAnnotation* m_displayPropertiesAnnotation; /** * Display properties for annotation text substitutions - DO NOT delete since this * is also in the displayProperties std::vector. */ DisplayPropertiesAnnotationTextSubstitution* m_displayPropertiesAnnotationTextSubstitution; /** * Display properties for borders - DO NOT delete since this * is also in the displayProperties std::vector. */ DisplayPropertiesBorders* m_displayPropertiesBorders; /** * Display properties for fiber orientation - DO NOT delete since this * is also in the displayProperties std::vector. */ DisplayPropertiesFiberOrientation* m_displayPropertiesFiberOrientation; /** * Display properties for foci - DO NOT delete since this * is also in the displayProperties std::vector. */ DisplayPropertiesFoci* m_displayPropertiesFoci; /** true when a spec file is being read */ bool m_isSpecFileBeingRead; SceneClassAssistant* m_sceneAssistant; /** Selection manager */ SelectionManager* m_selectionManager; /** Identification Manager */ IdentificationManager* m_identificationManager; /** The loader of fiber orientation samples */ FiberOrientationSamplesLoader* m_fiberOrientationSamplesLoader; /** Region of interest for highlighting brainordinates */ BrainordinateRegionOfInterest* m_brainordinateHighlightRegionOfInterest; std::map m_duplicateFileNameCounter; GapsAndMargins* m_gapsAndMargins; Scene* m_activeScene = NULL; bool m_surfaceMatchingToAnatomicalFlag = false; }; } // namespace #endif // __BRAIN_H__ connectome-workbench-1.4.2/src/Brain/BrainOpenGL.cxx000066400000000000000000001235571360521144700223160ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __BRAIN_OPENGL_DEFINE_H #include "BrainOpenGL.h" #undef __BRAIN_OPENGL_DEFINE_H #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPreferences.h" #include "DummyFontTextRenderer.h" #include "EventGetBrainOpenGLTextRenderer.h" #include "EventGraphicsOpenGLCreateBufferObject.h" #include "EventGraphicsOpenGLCreateTextureName.h" #include "EventGraphicsOpenGLDeleteBufferObject.h" #include "EventGraphicsOpenGLDeleteTextureName.h" #include "EventOpenGLObjectToWindowTransform.h" #include "EventManager.h" #include "GraphicsOpenGLBufferObject.h" #include "GraphicsOpenGLError.h" #include "GraphicsOpenGLTextureName.h" #include "GraphicsUtilitiesOpenGL.h" #include "Model.h" #include "SessionManager.h" using namespace caret; /** * Constructor. * * @param textRenderer * The text renderer is used for text rendering. * This parameter MUST NOT be NULL. It must be * a pointer to a text renderer. This instance * will take ownership of the text renderer and * delete it at the appropriate time. */ BrainOpenGL::BrainOpenGL(BrainOpenGLTextRenderInterface* textRenderer) { m_textRenderer = textRenderer; this->borderBeingDrawn = NULL; m_drawHighlightedEndPoints = false; EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GET_TEXT_RENDERER_FOR_WINDOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_BUFFER_OBJECT); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_TEXTURE_NAME); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_TEXTURE_NAME); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_OPENGL_OBJECT_TO_WINDOW_TRANSFORM); } /** * Destructor. */ BrainOpenGL::~BrainOpenGL() { EventManager::get()->removeAllEventsFromListener(this); if (m_textRenderer != NULL) { delete m_textRenderer; m_textRenderer = NULL; } } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void BrainOpenGL::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_BUFFER_OBJECT) { EventGraphicsOpenGLCreateBufferObject* createBufferEvent = dynamic_cast(event); CaretAssert(createBufferEvent); if (m_contextSharingGroupPointer == NULL) { AString msg("PROGRAM ERROR: " "A request for a new OpenGL Buffer Object has been made. " "However, there is no OpenGL context currently active so " "a buffer cannot be created. This is an error in the " "code and it is likely that the software will crash."); createBufferEvent->setErrorMessage(msg); createBufferEvent->setOpenGLBufferObject(NULL); CaretAssertMessage(0, msg); CaretLogSevere(msg); return; } GLuint bufferName = 0; glGenBuffers(1, &bufferName); createBufferEvent->setOpenGLBufferObject(new GraphicsOpenGLBufferObject(m_contextSharingGroupPointer, bufferName)); createBufferEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_TEXTURE_NAME) { EventGraphicsOpenGLCreateTextureName* createTextureEvent = dynamic_cast(event); CaretAssert(createTextureEvent); if (m_contextSharingGroupPointer == NULL) { AString msg("PROGRAM ERROR: " "A request for a new OpenGL Texture Name has been made. " "However, there is no OpenGL context currently active so " "a texture cannot be created. This is an error in the " "code and it is likely that the software will crash."); createTextureEvent->setErrorMessage(msg); createTextureEvent->setOpenGLTextureName(NULL); CaretAssertMessage(0, msg); CaretLogSevere(msg); return; } GLuint textureName = 0; glGenTextures(1, &textureName); createTextureEvent->setOpenGLTextureName(new GraphicsOpenGLTextureName(m_contextSharingGroupPointer, textureName)); createTextureEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT) { QMutexLocker locker(&m_buffersForDeletionLaterMutex); EventGraphicsOpenGLDeleteBufferObject* deleteBufferEvent = dynamic_cast(event); CaretAssert(deleteBufferEvent); const GraphicsOpenGLBufferObject* bufferObject = deleteBufferEvent->getOpenGLBufferObject(); if (bufferObject != NULL) { /* * Buffers are created within an OpenGL context and must * be deleted within that OpenGL context. */ m_buffersForDeletionLater.emplace(m_buffersForDeletionLater.end(), bufferObject->getOpenGLContextPointer(), bufferObject->getBufferObjectName()); } deleteBufferEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_TEXTURE_NAME) { QMutexLocker locker(&m_texturesForDeletionLaterMutex); EventGraphicsOpenGLDeleteTextureName* deleteTextureEvent = dynamic_cast(event); CaretAssert(deleteTextureEvent); const GraphicsOpenGLTextureName* textureName = deleteTextureEvent->getOpenGLTextureName(); if (textureName != NULL) { /* * Textures names are created within an OpenGL context and must * be deleted within that OpenGL context. */ m_texturesForDeletionLater.emplace(m_texturesForDeletionLater.end(), textureName->getOpenGLContextPointer(), textureName->getTextureName()); } deleteTextureEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_GET_TEXT_RENDERER_FOR_WINDOW) { EventGetBrainOpenGLTextRenderer* textRenderEvent = dynamic_cast(event); CaretAssert(textRenderEvent); textRenderEvent->setTextRenderer(m_textRenderer); textRenderEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_OPENGL_OBJECT_TO_WINDOW_TRANSFORM) { EventOpenGLObjectToWindowTransform* transformEvent = dynamic_cast(event); loadObjectToWindowTransform(transformEvent); } } /** * Draw models in their respective viewports. * * @param windowIndex * Index of window for drawing. * @param windowsUserInputMode * User input mode for window * @param brain * The brain (must be valid!) * @param contextSharingGroupPointer * Pointer to the active OpenGL context. * @param viewportContents * Viewport info for drawing. */ void BrainOpenGL::drawModels(const int32_t windowIndex, const UserInputModeEnum::Enum windowsUserInputMode, Brain* brain, void* contextSharingGroupPointer, const std::vector& viewportContents) { m_contextSharingGroupPointer = contextSharingGroupPointer; const std::vector vpContents(viewportContents.begin(), viewportContents.end()); // for (const auto& vp : viewportContents) { // vpContents.push_back(vp); // } drawModelsImplementation(windowIndex, windowsUserInputMode, brain, vpContents); deleteUnusedOpenGLNames(); m_contextSharingGroupPointer = NULL; } /** * Selection on a model. * * @param windowIndex * Index of window for selection. * @param windowsUserInputMode * User input mode for window * @param brain * The brain (must be valid!) * @param contextSharingGroupPointer * Pointer to the active OpenGL context * @param viewportContent * Viewport content in which mouse was clicked * @param mouseX * X position of mouse click * @param mouseY * Y position of mouse click * @param applySelectionBackgroundFiltering * If true (which is in most cases), if there are multiple items * selected, those items "behind" other items are not reported. * For example, suppose a focus is selected and there is a node * the focus. If this parameter is true, the node will NOT be * selected. If this parameter is false, the node will be * selected. */ void BrainOpenGL::selectModel(const int32_t windowIndex, const UserInputModeEnum::Enum windowsUserInputMode, Brain* brain, void* contextSharingGroupPointer, const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, const bool applySelectionBackgroundFiltering) { m_contextSharingGroupPointer = contextSharingGroupPointer; selectModelImplementation(windowIndex, windowsUserInputMode, brain, viewportContent, mouseX, mouseY, applySelectionBackgroundFiltering); deleteUnusedOpenGLNames(); m_contextSharingGroupPointer = NULL; } /** * Project the given window coordinate to the active models. * If the projection is successful, The 'original' XYZ * coordinate in 'projectionOut' will be valid. In addition, * the barycentric coordinate may also be valid in 'projectionOut'. * * @param windowIndex * Index of window for projection * @param windowsUserInputMode * User input mode for window * @param brain * The brain (must be valid!) * @param contextSharingGroupPointer * Pointer to the active OpenGL context. * @param viewportContent * Viewport content in which mouse was clicked * @param mouseX * X position of mouse click * @param mouseY * Y position of mouse click * @param projectionOut * Output with projection result. */ void BrainOpenGL::projectToModel(const int32_t windowIndex, const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, void* contextSharingGroupPointer, const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, SurfaceProjectedItem& projectionOut) { m_contextSharingGroupPointer = contextSharingGroupPointer; projectToModelImplementation(windowIndex, windowUserInputMode, brain, viewportContent, mouseX, mouseY, projectionOut); deleteUnusedOpenGLNames(); m_contextSharingGroupPointer = NULL; } /** * This method must be called only when the OpenGL context * is current. */ void BrainOpenGL::deleteUnusedOpenGLNames() { if ( ! m_buffersForDeletionLater.empty()) { QMutexLocker locker(&m_buffersForDeletionLaterMutex); std::vector otherContextBufferIdentifiers; std::vector bufferNames; for (auto bufferInfo : m_buffersForDeletionLater) { if (bufferInfo.m_openglContextPointer == m_contextSharingGroupPointer) { if (glIsBuffer(bufferInfo.m_name)) { bufferNames.push_back(bufferInfo.m_name); } else { CaretLogWarning("Attempting to delete invalid OpenGL buffer ID: " + AString::number(bufferInfo.m_name)); } } else { otherContextBufferIdentifiers.push_back(bufferInfo); } } if ( ! bufferNames.empty()) { const GLuint* namesPointer = &bufferNames[0]; glDeleteBuffers(bufferNames.size(), namesPointer); m_buffersForDeletionLater.clear(); } m_buffersForDeletionLater = otherContextBufferIdentifiers; if ( ! m_buffersForDeletionLater.empty()) { CaretLogWarning("Not deleting " + AString::number(m_buffersForDeletionLater.size()) + " buffers in another OpenGL Context."); } } if ( ! m_texturesForDeletionLater.empty()) { QMutexLocker locker(&m_texturesForDeletionLaterMutex); std::vector otherContextTextureIdentifiers; std::vector textureNames; for (auto textureInfo : m_texturesForDeletionLater) { if (textureInfo.m_openglContextPointer == m_contextSharingGroupPointer) { if (glIsTexture(textureInfo.m_name)) { textureNames.push_back(textureInfo.m_name); } else { CaretLogWarning("Attempting to delete invalid OpenGL Texture Name: " + AString::number(textureInfo.m_name)); } } else { otherContextTextureIdentifiers.push_back(textureInfo); } } if ( ! textureNames.empty()) { const GLuint* namesPointer = &textureNames[0]; glDeleteTextures(textureNames.size(), namesPointer); m_texturesForDeletionLater.clear(); } m_texturesForDeletionLater = otherContextTextureIdentifiers; if ( ! m_texturesForDeletionLater.empty()) { CaretLogWarning("Not deleting " + AString::number(m_texturesForDeletionLater.size()) + " textures in another OpenGL Context."); } } } /** * @return The active text renderer. */ BrainOpenGLTextRenderInterface* BrainOpenGL::getTextRenderer() { return m_textRenderer; } /** * Set the OpenGL line width. Value is clamped * to minimum and maximum values to prevent * OpenGL error caused by invalid line width. */ void BrainOpenGL::setLineWidth(const float lineWidth) { if (lineWidth > s_maxLineWidth) { glLineWidth(s_maxLineWidth); } else if (lineWidth < s_minLineWidth) { glLineWidth(s_minLineWidth); } else { glLineWidth(lineWidth); } } /** * Set the OpenGL point size. Value is clamped * to minimum and maximum values to prevent * OpenGL error caused by invalid point size. */ void BrainOpenGL::setPointSize(const float pointSize) { if (pointSize > s_maxPointSize) { glPointSize(s_maxPointSize); } else if (pointSize < s_minPointSize) { glPointSize(s_minPointSize); } else { glPointSize(pointSize); } } /** * Get the minimum and maximum values for the size of a point. * @param minPointSizeOut * Gets minimum size of point. * @param maxPointSizeOut * Gets maximum size of point. */ void BrainOpenGL::getMinMaxPointSize(float& minPointSizeOut, float& maxPointSizeOut) { minPointSizeOut = BrainOpenGL::s_minPointSize; maxPointSizeOut = BrainOpenGL::s_maxPointSize; } /** * Get the minimum and maximum values for the width of a line. * @param minLineWidthOut * Gets minimum line width. * @param maxLineWidthOut * Gets maximum line width. */ void BrainOpenGL::getMinMaxLineWidth(float& minLineWidthOut, float& maxLineWidthOut) { minLineWidthOut = BrainOpenGL::s_minLineWidth; maxLineWidthOut = BrainOpenGL::s_maxLineWidth; } /** * Set the border being drawn by the user. If not NULL then * subclasses should draw the border. * * @param borderBeingDrawn * Pointer to border that is being drawn. */ void BrainOpenGL::setBorderBeingDrawn(Border* borderBeingDrawn) { this->borderBeingDrawn = borderBeingDrawn; } /** * @return Should border end points be highlighted? */ bool BrainOpenGL::isDrawHighlightedEndPoints() const { return m_drawHighlightedEndPoints; } /** * Set border end points should be highlighted. */ void BrainOpenGL::setDrawHighlightedEndPoints(const bool drawHighlightedEndPoints) { m_drawHighlightedEndPoints = drawHighlightedEndPoints; } /** * Determine if the given version of OpenGL is supported at runtime. * OpenGL is continually updated and this method is used to test for * support of a given runtime version of OpenGL so that OpenGL functions * in the given version may be used. For example, if a function in OpenGL * 2.1 is called on a system that it is OpenGL 1.1, a crash will likely occur. * * The OpenGL runtime version is two or three numbers separated by a period, * possibly followed by a space and then text. * The first number is the major version, the second number is the minor * version, and the optional third number is the release of the major/minor * version. * * A version of of OpenGL is supported when it is less than or equal to * the runtime version of the OpenGL library. However, there may be exceptions as * OpenGL is deprecating functionality from OpenGL 1.x and 2.x in versions * 3.1 and later. At this time, an extension is provided by all vendors so * that OpenGL 1.x and 2.x is available in 3.1 and later. THIS MAY CHANGE. * This method does not check for this potential missing, deprecated capability. * * @param versionOfOpenGL * Version of OpenGL in the form X.Y.Z (eg: 1.1, 2.1, 3.0, 3.0.0, 3.1, etc.) * for which support is tested. * * @return true if the given version of OpenGL is less than the runtime version. */ bool BrainOpenGL::testForVersionOfOpenGLSupported(const AString& versionOfOpenGL) { AString desiredMajorVersion; AString desiredMinorVersion; getOpenGLMajorMinorVersions(versionOfOpenGL, desiredMajorVersion, desiredMinorVersion); /* * If desired MAJOR version is LESS THAN the runtime MAJOR version * then is it supported. */ if (desiredMajorVersion.toInt() < s_runtimeLibraryMajorVersionOfOpenGL.toInt()) { return true; } /* * Is the desired MAJOR version THE SAME as the runtime MAJOR version */ if (s_runtimeLibraryMajorVersionOfOpenGL.toInt() == desiredMajorVersion.toInt()) { /* * If the desired MINOR version is LESS THAN OR EQUAL to the * runtime MINOR version, then it is supported. */ if (desiredMinorVersion.toInt() <= s_runtimeLibraryMinorVersionOfOpenGL.toInt()) { return true; } } return false; } /** * Test for the required version of OpenGL Workbench needs. * * @param errorMessageOut * Output with error message if required version is not available. * @return * True if required version available, else false. */ bool BrainOpenGL::testForRequiredOpenGLVersion(AString& errorMessageOut) { const AString minimumOpenGLVersion("1.5"); if ( ! BrainOpenGL::testForVersionOfOpenGLSupported(minimumOpenGLVersion)) { const AString msg("OpenGL Version " + minimumOpenGLVersion + " or later is required. This computer has version " + BrainOpenGL::getOpenGLVersion() + "\nYou may continue but the software may crash."); errorMessageOut = msg; return false; } return true; } /** * @return The OpenGL version. */ AString BrainOpenGL::getOpenGLVersion() { return QLatin1String(reinterpret_cast(glGetString(GL_VERSION))); } /** * Extract the major and minor versions from an OpenGL version string. * @param versionString * The OpenGL version string which is ".[.optionalVendorInfo]. * Usually strings such as 1.1, 1.2, 2.1, 3.0, etc. * @param majorVersionOut * Output containing the major version. * @param minorVersionOut * Output containing the minor version. */ void BrainOpenGL::getOpenGLMajorMinorVersions(const AString& versionString, AString& majorVersionOut, AString& minorVersionOut) { /* * Major and minor version are separated by a period. * Vendor information may follow and begin with whitespace. */ const QStringList sl = versionString.split(QRegExp("[\\s|\\.]")); if (sl.count() >= 2) { minorVersionOut = sl.at(1); } else { minorVersionOut = "1"; } if (sl.count() >= 1) { majorVersionOut = sl.at(0); } else { majorVersionOut = "1"; } } /** * Initialize the drawing mode using the most optimal drawing given * the compile time and run time constraints. */ void BrainOpenGL::initializeOpenGL() { s_runtimeLibraryVersionOfOpenGL = QLatin1String(reinterpret_cast(glGetString(GL_VERSION))); if (s_runtimeLibraryVersionOfOpenGL.isEmpty()) { s_runtimeLibraryVersionOfOpenGL = "1.1"; } getOpenGLMajorMinorVersions(s_runtimeLibraryVersionOfOpenGL, s_runtimeLibraryMajorVersionOfOpenGL, s_runtimeLibraryMinorVersionOfOpenGL); float sizes[2]; glGetFloatv(GL_POINT_SIZE_RANGE, sizes); s_minPointSize = sizes[0]; s_maxPointSize = sizes[1]; glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, sizes); s_minLineWidth = sizes[0]; s_maxLineWidth = sizes[1]; s_supportsDisplayLists = false; s_supportsImmediateMode = false; s_supportsVertexBuffers = false; /* * Get the OpenGL Extensions. */ bool haveARBCompatibility = false; const QString extensionsString((char*)glGetString(GL_EXTENSIONS)); const QStringList extensionsList = extensionsString.split(QChar(' ')); QStringListIterator extensionsIterator(extensionsList); m_openGLExtensionsInformation = ("\n\nOpenGL Extensions:"); while (extensionsIterator.hasNext()) { const QString ext = extensionsIterator.next(); m_openGLExtensionsInformation += ("\n " + ext); if (ext == "GL_ARB_compatibility") { haveARBCompatibility = true; } } if (testForVersionOfOpenGLSupported("3.1")) { if (haveARBCompatibility == false) { CaretLogSevere("OpenGL 3.1 or later and ARB compatibilty extensions not found.\n" "OpenGL may fail."); } } #if BRAIN_OPENGL_INFO_SUPPORTS_IMMEDIATE s_supportsImmediateMode = true; #endif // BRAIN_OPENGL_INFO_SUPPORTS_IMMEDIATE #if BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS s_supportsDisplayLists = true; #endif // BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS #ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS s_supportsVertexBuffers = true; #endif // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS /* * Call to validate the draw mode selection logic. */ getBestDrawingMode(); } /** * @return String containing information about OpenGL. */ AString BrainOpenGL::getOpenGLInformation() { AString compileVersions = "OpenGL Header File Versions Supported: "; #ifdef GL_VERSION_1_1 compileVersions += " 1.1"; #endif #ifdef GL_VERSION_1_2 compileVersions += " 1.2"; #endif #ifdef GL_VERSION_1_3 compileVersions += " 1.3"; #endif #ifdef GL_VERSION_1_4 compileVersions += " 1.4"; #endif #ifdef GL_VERSION_1_5 compileVersions += " 1.5"; #endif #ifdef GL_VERSION_2_0 compileVersions += " 2.0"; #endif #ifdef GL_VERSION_2_1 compileVersions += " 2.1"; #endif #ifdef GL_VERSION_3_0 compileVersions += " 3.0"; #endif #ifdef GL_VERSION_3_1 compileVersions += " 3.1"; #endif #ifdef GL_VERSION_3_2 compileVersions += " 3.2"; #endif #ifdef GL_VERSION_3_3 compileVersions += " 3.3"; #endif #ifdef GL_VERSION_4_0 compileVersions += " 4.0"; #endif #ifdef GL_VERSION_4_1 compileVersions += " 4.1"; #endif #ifdef GL_VERSION_4_2 compileVersions += " 4.2"; #endif #ifdef GL_VERSION_4_3 compileVersions += " 4.3"; #endif #ifdef GL_VERSION_4_4 compileVersions += " 4.4"; #endif #ifdef GL_VERSION_4_4 compileVersions += " 4.4"; #endif #ifdef GL_VERSION_4_5 compileVersions += " 4.5"; #endif #ifdef GL_VERSION_5_0 compileVersions += " 5.0"; #endif #ifdef GL_OES_VERSION_1_0 compileVersions += " ES_1.0"; #endif #ifdef GL_ES_VERSION_2_0 compileVersions += " ES_2.0"; #endif #ifdef GL_ES_VERSION_3_0 compileVersions += " ES_3.0"; #endif // // Note: The version string might be something like 1.2.4. std::atof() // will get just the 1.2 which is okay. // const char* vendorStr = (char*)(glGetString(GL_VENDOR)); const char* renderStr = (char*)(glGetString(GL_RENDERER)); AString lineInfo = (compileVersions + "\nOpenGL Runtime Version: " + s_runtimeLibraryVersionOfOpenGL + "\nMajor Runtime Version: " + BrainOpenGL::s_runtimeLibraryMajorVersionOfOpenGL + "\nMinor Runtime Version: " + BrainOpenGL::s_runtimeLibraryMinorVersionOfOpenGL + "\nOpenGL Vendor: " + AString(vendorStr) + "\nOpenGL Renderer: " + AString(renderStr)); AString glewVersionName("No GLEW in this version of Workbench"); #ifdef HAVE_GLEW glewVersionName = AString(reinterpret_cast(glewGetString(GLEW_VERSION))); #endif /* HAVE_GLEW */ lineInfo += "\n"; lineInfo += ("\nGLEW Version: " + glewVersionName); lineInfo += "\n"; lineInfo += ("\nFont Renderer: " + m_textRenderer->getName()); lineInfo += "\n"; #ifdef GL_VERSION_2_0 if (testForVersionOfOpenGLSupported("2.0")) { const char* glslVersionString = (char*)glGetString(GL_SHADING_LANGUAGE_VERSION); lineInfo += ("\nOpenGL Shading Language (GLSL) Version: " + AString(glslVersionString) + "\n"); GLfloat values[2]; glGetFloatv (GL_ALIASED_LINE_WIDTH_RANGE, values); const AString aliasedLineWidthRange = ("GL_ALIASED_LINE_WIDTH_RANGE value is " + AString::fromNumbers(values, 2, ", ")); glGetFloatv (GL_SMOOTH_LINE_WIDTH_RANGE, values); const AString smoothLineWidthRange = ("GL_SMOOTH_LINE_WIDTH_RANGE value is " + AString::fromNumbers(values, 2, ", ")); glGetFloatv (GL_SMOOTH_LINE_WIDTH_GRANULARITY, values); const AString smoothLineWidthGranularity = ("GL_SMOOTH_LINE_WIDTH_GRANULARITY value is " + AString::number(values[0])); glGetFloatv(GL_SMOOTH_POINT_SIZE_RANGE, values); const AString smoothPointSizeRange = ("GL_SMOOTH_POINT_SIZE_RANGE value is " + AString::fromNumbers(values, 2, ", ")); lineInfo += ("\n" + aliasedLineWidthRange + "\n" + smoothLineWidthRange + "\n" + smoothLineWidthGranularity + "\n" + smoothPointSizeRange); } #endif // GL_VERSION_2_0 //#else // GL_VERSION_2_0 GLfloat values[2]; glGetFloatv (GL_LINE_WIDTH_RANGE, values); const AString lineWidthRange = ("GL_LINE_WIDTH_RANGE value is " + AString::fromNumbers(values, 2, ", ")); glGetFloatv (GL_LINE_WIDTH_GRANULARITY, values); const AString lineWidthGranularity = ("GL_LINE_WIDTH_GRANULARITY value is " + AString::number(values[0])); lineInfo += ("\n" + lineWidthRange + "\n" + lineWidthGranularity); //#endif // GL_VERSION_2_0 GLint maximumNumberOfClipPlanes; glGetIntegerv(GL_MAX_CLIP_PLANES, & maximumNumberOfClipPlanes); lineInfo += ("\n\nMaximum number of clipping planes is " + AString::number(maximumNumberOfClipPlanes)); GLint maxNameStackDepth, maxModelStackDepth, maxProjStackDepth; glGetIntegerv(GL_MAX_PROJECTION_STACK_DEPTH, &maxProjStackDepth); glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, &maxModelStackDepth); glGetIntegerv(GL_MAX_NAME_STACK_DEPTH, &maxNameStackDepth); lineInfo += ("\n\nMaximum Modelview Matrix Stack Depth " + QString::number(maxModelStackDepth)); lineInfo += ("\nMaximum Name Matrix Stack Depth " + QString::number(maxNameStackDepth)); lineInfo += ("\nMaximum Projection Matrix Stack Depth " + QString::number(maxProjStackDepth)); GLint redBits, greenBits, blueBits, alphaBits; glGetIntegerv(GL_RED_BITS, &redBits); glGetIntegerv(GL_GREEN_BITS, &greenBits); glGetIntegerv(GL_BLUE_BITS, &blueBits); glGetIntegerv(GL_ALPHA_BITS, &alphaBits); lineInfo += ("\n\nBuffer bits red/green/blue/apha: (" + AString::number(redBits) + ", " + AString::number(greenBits) + ", " + AString::number(blueBits) + ", " + AString::number(alphaBits) + ")"); lineInfo += ("\n\nBest Drawing Mode: " + BrainOpenGL::getBestDrawingModeName()); lineInfo += ("\nDisplay Lists Supported: " + AString::fromBool(s_supportsDisplayLists)); lineInfo += ("\nImmediate Mode Supported: " + AString::fromBool(s_supportsImmediateMode)); lineInfo += ("\nVertex Buffers Supported: " + AString::fromBool(s_supportsVertexBuffers)); GLint sampleBuffersCount = 0; glGetIntegerv(GL_SAMPLE_BUFFERS, &sampleBuffersCount); GLint sampleCount = 0; glGetIntegerv(GL_SAMPLES, &sampleCount); lineInfo += "\n"; lineInfo += ("\nSample Buffer Count: " + AString::number(sampleBuffersCount)); lineInfo += ("\nSamples Count: " + AString::number(sampleCount)); lineInfo += ("\nMultisampling Enabled: " + AString::fromBool(glIsEnabled(GL_MULTISAMPLE))); GLint textureMax, texture3DMax; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &textureMax); glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &texture3DMax); lineInfo += "\n"; lineInfo += ("\nTexture Max: " + AString::number(textureMax)); lineInfo += ("\nTexture 3D Max: " + AString::number(texture3DMax)); lineInfo += "\n"; lineInfo += "\n"; lineInfo += "\n"; lineInfo += "Note that State of OpenGL may be different when drawing objects.\n"; lineInfo += getStateOfOpenGL(); lineInfo += "\n"; lineInfo += m_openGLExtensionsInformation; return lineInfo; } /** * @return The best drawing mode given the limitations of * the compile and run-time systems. */ BrainOpenGL::DrawMode BrainOpenGL::getBestDrawingMode() { BrainOpenGL::DrawMode drawMode = BrainOpenGL::DRAW_MODE_INVALID; const OpenGLDrawingMethodEnum::Enum userPrefDrawMode = SessionManager::get()->getCaretPreferences()->getOpenDrawingMethod(); bool useVertexBuffersFlag = false; switch (userPrefDrawMode) { case OpenGLDrawingMethodEnum::DRAW_WITH_VERTEX_BUFFERS_OFF: break; case OpenGLDrawingMethodEnum::DRAW_WITH_VERTEX_BUFFERS_ON: if (s_supportsVertexBuffers) { useVertexBuffersFlag = true; } break; } if (s_supportsVertexBuffers && useVertexBuffersFlag) { drawMode = DRAW_MODE_VERTEX_BUFFERS; } else if (s_supportsDisplayLists) { drawMode = DRAW_MODE_DISPLAY_LISTS; } else if (s_supportsImmediateMode) { drawMode = DRAW_MODE_IMMEDIATE; } else if (s_supportsVertexBuffers) { drawMode = DRAW_MODE_VERTEX_BUFFERS; } else { CaretAssertMessage(0, "OpenGL does not appear to support any valid drawing modes, should never occur." " Or, OpenGL was not initialized (failed to call BrainOpenGL::initializeOpenGL())."); } return drawMode; } /** * @return Text string describing the drawing mode for shapes. */ QString BrainOpenGL::getBestDrawingModeName() { QString modeName = "Invalid"; switch (getBestDrawingMode()) { case BrainOpenGL::DRAW_MODE_DISPLAY_LISTS: modeName = "Display Lists"; break; case BrainOpenGL::DRAW_MODE_IMMEDIATE: modeName = "Immediate"; break; case BrainOpenGL::DRAW_MODE_INVALID: modeName = "Invalid"; break; case BrainOpenGL::DRAW_MODE_VERTEX_BUFFERS: modeName = "Vertex Buffers"; break; } return modeName; } /** * @return A string containing the state of OpenGL (depth testing, lighting, etc.) */ AString BrainOpenGL::getStateOfOpenGL() const { AString s; return s; } /** * Get the status of an OpenGL enum (enabled/disabled) as text in form * "name=true/false". * * @param enumName * Text name of the enumerated value. * @param enumValue * The OpenGl enum value. * @return * String with "enumName=true/false". */ AString BrainOpenGL::getOpenGLEnabledEnumAsText(const AString& enumName, const GLenum enumValue) const { /* * Reset error status */ GraphicsUtilitiesOpenGL::resetOpenGLError(); GLboolean boolValue= glIsEnabled(enumValue); AString errorText; const GLenum errorCode = glGetError(); if (errorCode != GL_NO_ERROR) { const GLubyte* errorChars = gluErrorString(errorCode); if (errorChars != NULL) { errorText = ("ERROR failed to glIsEnabled() value. Reason: " + AString((char*)errorChars)); } } const AString s = (enumName + "=" + ((boolValue == GL_TRUE) ? "true" : "false") + " " + errorText); return s; } /** * Get the status of an OpenGL boolean as text in form * "name=true/false". * * @param enumName * Text name of the enumerated value. * @param enumValue * The OpenGl enum value. * @return * String with "enumName=true/false". */ AString BrainOpenGL::getOpenGLBooleanAsText(const AString& enumName, const GLenum enumValue) const { /* * Reset error status */ GraphicsUtilitiesOpenGL::resetOpenGLError(); GLboolean boolValue = GL_FALSE; glGetBooleanv(enumValue, &boolValue); AString errorText; const GLenum errorCode = glGetError(); if (errorCode != GL_NO_ERROR) { const GLubyte* errorChars = gluErrorString(errorCode); if (errorChars != NULL) { errorText = ("ERROR failed to glGetBooleanv() value. Reason: " + AString((char*)errorChars)); } } const AString s = (enumName + "=" + ((boolValue == GL_TRUE) ? "true" : "false") + " " + errorText); return s; } /** * Get the status of an OpenGL enum (enabled/disabled) as text in form * "name=true/false". * * @param enumName * Text name of the enumerated value. * @param enumValue * The OpenGl enum value. * @param numberOfValues * Number of floating pointer values associated with enumName. * @return * String with "enumName=(1, 2, 3,..)". */ AString BrainOpenGL::getOpenGLFloatAsText(const AString& enumName, const GLenum enumValue, const int32_t numberOfValues) const { /* * Reset error status */ GraphicsUtilitiesOpenGL::resetOpenGLError(); AString valuesString; if (numberOfValues > 0) { std::vector valuesVector(numberOfValues, 0.0); GLfloat* values = &valuesVector[0]; glGetFloatv(enumValue, values); const GLenum errorCode = glGetError(); if (errorCode != GL_NO_ERROR) { const GLubyte* errorChars = gluErrorString(errorCode); if (errorChars != NULL) { valuesString = ("ERROR failed to glGetFloatv() value. Reason: " + AString((char*)errorChars)); } } else { valuesString = ("(" + AString::fromNumbers(valuesVector, ",") + ")"); } } const AString s = (enumName + "=" + valuesString); return s; } /** * Get the status of an OpenGL enum (enabled/disabled) as text in form * "name=true/false". * * @param enumName * Text name of the enumerated value. * @param enumValue * The OpenGl enum value. * @param enumValue * The OpenGl enum value. * @param numberOfValues * Number of floating pointer values associated with enumName. * @return * String with "enumName=(1, 2, 3,..)". */ AString BrainOpenGL::getOpenGLLightAsText(const AString& enumName, const GLenum lightEnum, const GLenum enumValue, const int32_t numberOfValues) const { /* * Reset error status */ GraphicsUtilitiesOpenGL::resetOpenGLError(); AString valuesString; if (numberOfValues > 0) { std::vector valuesVector(numberOfValues, 0.0); GLfloat* values = &valuesVector[0]; glGetLightfv(lightEnum, enumValue, values); const GLenum errorCode = glGetError(); if (errorCode != GL_NO_ERROR) { const GLubyte* errorChars = gluErrorString(errorCode); if (errorChars != NULL) { valuesString = ("ERROR failed to get glGetLightfv() value. Reason " + AString((char*)errorChars)); } } else { valuesString = ("(" + AString::fromNumbers(valuesVector, ",") + ")"); } } const AString s = (enumName + "=" + valuesString); return s; } /** * Get the background color. * * @param backgroundColor * Output containing RGB components [0, 255]. */ void BrainOpenGL::getBackgroundColor(uint8_t backgroundColor[3]) const { backgroundColor[0] = m_backgroundColorByte[0]; backgroundColor[1] = m_backgroundColorByte[1]; backgroundColor[2] = m_backgroundColorByte[2]; } /** * Print information if there is an OpenGL error. */ void BrainOpenGL::testForOpenGLError(const AString& message) { testForOpenGLError(message, NULL, -1, -1); } /** * Print information if there is an OpenGL error. * * @param message * Message that is printed at beginning of text. * @param model * Model being drawn. * @param windowIndex * Index of the window. * @param tabIndex * Index of the tab. */ void BrainOpenGL::testForOpenGLError(const AString& message, const Model* model, const int32_t windowIndex, const int32_t tabIndex) { std::unique_ptr openglError = GraphicsUtilitiesOpenGL::getOpenGLError(); if (openglError) { AString msg; if ( ! message.isEmpty()) { msg.appendWithNewLine(message); } if (model != NULL) { msg.appendWithNewLine("While drawing brain model " + model->getNameForGUI(true)); } if (windowIndex >= 0) { msg.appendWithNewLine("In window number " + AString::number(windowIndex)); } if (tabIndex >= 0) { msg.appendWithNewLine("In tab number " + AString::number(tabIndex)); } msg.appendWithNewLine(openglError->getVerboseDescription()); CaretLogSevere(msg); } } /** * Allow tab highlighting (needs disabling when replacing scenes) * * @param flag * New status. */ void BrainOpenGL::setAllowTabHighlighting(const bool flag) { s_allowTabHighlightingFlag = flag; } connectome-workbench-1.4.2/src/Brain/BrainOpenGL.h000066400000000000000000000347471360521144700217450ustar00rootroot00000000000000 #ifndef __BRAIN_OPENGL_H__ #define __BRAIN_OPENGL_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include "CaretOpenGLInclude.h" #include "CaretObject.h" #include "UserInputModeEnum.h" #undef BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS #undef BRAIN_OPENGL_INFO_SUPPORTS_IMMEDIATE #undef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS #define BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS 1 #define BRAIN_OPENGL_INFO_SUPPORTS_IMMEDIATE 1 //#define BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS 1 //#ifdef GL_VERSION_1_1 //#define BRAIN_OPENGL_INFO_SUPPORTS_IMMEDIATE 1 //#define BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS 1 //#endif // GL_VERSION_1_1 // #ifdef GL_VERSION_2_1 #define BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS 1 #endif // GL_VERSION_2_1 #ifdef GL_VERSION_3_0 #define BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS 1 #endif // GL_VERSION_3_0 #ifdef GL_VERSION_4_0 #define BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS 1 #endif // GL_VERSION_4_0 #include "CaretObject.h" #include "EventListenerInterface.h" namespace caret { class Border; class Brain; class BrainOpenGLTextRenderInterface; class BrainOpenGLViewportContent; class EventOpenGLObjectToWindowTransform; class Model; class SurfaceProjectedItem; /** * Performs drawing of graphics using OpenGL. */ class BrainOpenGL : public CaretObject, public EventListenerInterface { protected: BrainOpenGL(BrainOpenGLTextRenderInterface* textRenderer); public: /** Mode for how the shape is drawn, set to most optimal for compilation and runtime systems */ enum DrawMode { /** Draw using display lists */ DRAW_MODE_DISPLAY_LISTS, /** Draw using immediate mode */ DRAW_MODE_IMMEDIATE, /** Invalid */ DRAW_MODE_INVALID, /** Draw using vertex buffers */ DRAW_MODE_VERTEX_BUFFERS }; virtual ~BrainOpenGL(); /** * Initialize the OpenGL system. */ virtual void initializeOpenGL(); BrainOpenGLTextRenderInterface* getTextRenderer(); void drawModels(const int32_t windowIndex, const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, void* contextSharingGroupPointer, const std::vector& viewportContents); void selectModel(const int32_t windowIndex, const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, void* contextSharingGroupPointer, const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, const bool applySelectionBackgroundFiltering); void projectToModel(const int32_t windowIndex, const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, void* contextSharingGroupPointer, const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, SurfaceProjectedItem& projectionOut); /** * @return Half-size of the model window height. */ static float getModelViewingHalfWindowHeight() { return 90.0f; } void setBorderBeingDrawn(Border* borderBeingDrawn); bool isDrawHighlightedEndPoints() const; void setDrawHighlightedEndPoints(const bool drawHighlightedEndPoints); void getBackgroundColor(uint8_t backgroundColor[3]) const; static void setLineWidth(const float lineWidth); static void setPointSize(const float pointSize); static void getMinMaxPointSize(float& minPointSizeOut, float& maxPointSizeOut); static void getMinMaxLineWidth(float& minLineWidthOut, float& maxLineWidthOut); static bool testForRequiredOpenGLVersion(AString& errorMessageOut); static bool testForVersionOfOpenGLSupported(const AString& versionOfOpenGL); static AString getOpenGLVersion(); static void testForOpenGLError(const AString& message); static void testForOpenGLError(const AString& message, const Model* model, const int32_t windowIndex, const int32_t tabIndex); static QString getBestDrawingModeName(); AString getOpenGLInformation(); static DrawMode getBestDrawingMode(); /** * @return True if display list drawing is supported. */ inline static bool isDisplayListsSupported() { return s_supportsDisplayLists; } /** * @return True if immediate mode drawing is supported. */ inline static bool isImmediateSupported() { return s_supportsImmediateMode; } /** * @return True if vertex buffer drawing is supported. */ inline static bool isVertexBuffersSupported() { return s_supportsVertexBuffers; } virtual AString getStateOfOpenGL() const; virtual void receiveEvent(Event* event); /** * @return Pointer to OpenGL context sharing group pointer. */ inline void* getContextSharingGroupPointer() { return m_contextSharingGroupPointer; } static void setAllowTabHighlighting(const bool flag); private: class OpenGLNameInfo { public: OpenGLNameInfo(void* openglContextPointer, const GLuint name) : m_openglContextPointer(openglContextPointer), m_name(name) { } void* m_openglContextPointer; GLuint m_name; }; void deleteUnusedOpenGLNames(); /** prevents concurrent access to m_buffersForDeletionLater */ QMutex m_buffersForDeletionLaterMutex; /** use a mutex whenever accessing this member */ std::vector m_buffersForDeletionLater; /** prevents concurrent access to m_texturesForDeletionLater */ QMutex m_texturesForDeletionLaterMutex; /** use a mutex whenever accessing this member */ std::vector m_texturesForDeletionLater; /** Pointer to the current OpenGL Context sharing group */ void* m_contextSharingGroupPointer = 0; BrainOpenGL(const BrainOpenGL&); BrainOpenGL& operator=(const BrainOpenGL&); protected: /** * Draw models in their respective viewports. * * @param windowIndex * Index of window for drawing * @param windowUserInputMode * Input mode for window * @param brain * The brain (must be valid!) * @param viewportContents * Viewport info for drawing. */ virtual void drawModelsImplementation(const int32_t windowIndex, const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, const std::vector& viewportContents) = 0; /** * Selection on a model. * * @param windowIndex * Index of window for selection * @param userInputMode * Input mode for window * @param brain * The brain (must be valid!) * @param viewportContent * Viewport content in which mouse was clicked * @param mouseX * X position of mouse click * @param mouseY * Y position of mouse click * @param applySelectionBackgroundFiltering * If true (which is in most cases), if there are multiple items * selected, those items "behind" other items are not reported. * For example, suppose a focus is selected and there is a node * the focus. If this parameter is true, the node will NOT be * selected. If this parameter is false, the node will be * selected. */ virtual void selectModelImplementation(const int32_t windowIndex, const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, const bool applySelectionBackgroundFiltering) = 0; /** * Project the given window coordinate to the active models. * If the projection is successful, The 'original' XYZ * coordinate in 'projectionOut' will be valid. In addition, * the barycentric coordinate may also be valid in 'projectionOut'. * * @param windowIndex * Index of window for projection * @param userInputMode * Input mode for window * @param brain * The brain (must be valid!) * @param viewportContent * Viewport content in which mouse was clicked * @param mouseX * X position of mouse click * @param mouseY * Y position of mouse click * @param projectionOut * Output with projection result. */ virtual void projectToModelImplementation(const int32_t windowIndex, const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, SurfaceProjectedItem& projectionOut) = 0; AString getOpenGLEnabledEnumAsText(const AString& enumName, const GLenum enumValue) const; AString getOpenGLBooleanAsText(const AString& enumName, const GLenum enumValue) const; AString getOpenGLFloatAsText(const AString& enumName, const GLenum enumValue, const int32_t numberOfValues) const; AString getOpenGLLightAsText(const AString& enumName, const GLenum lightEnum, const GLenum enumValue, const int32_t numberOfValues) const; virtual void loadObjectToWindowTransform(EventOpenGLObjectToWindowTransform* transformEvent) = 0; Border* borderBeingDrawn; bool m_drawHighlightedEndPoints; uint8_t m_foregroundColorByte[4]; float m_foregroundColorFloat[4]; uint8_t m_backgroundColorByte[4]; float m_backgroundColorFloat[4]; /** minimum point size */ static float s_minPointSize; /** maximum point size */ static float s_maxPointSize; /** minimum line width */ static float s_minLineWidth; /** maximum line width */ static float s_maxLineWidth; static bool s_allowTabHighlightingFlag; private: static void getOpenGLMajorMinorVersions(const AString& versionString, AString& majorVersionOut, AString& minorVersionOut); /** runtime library version of OpenGL */ static AString s_runtimeLibraryVersionOfOpenGL; /** runtime library major version number of OpenGL */ static AString s_runtimeLibraryMajorVersionOfOpenGL; /** runtime library minor version number of OpenGL */ static AString s_runtimeLibraryMinorVersionOfOpenGL; static bool s_supportsDisplayLists; static bool s_supportsImmediateMode; static bool s_supportsVertexBuffers; /** Optional text rendering (if not null) */ BrainOpenGLTextRenderInterface* m_textRenderer; AString m_openGLExtensionsInformation; }; #ifdef __BRAIN_OPENGL_DEFINE_H AString BrainOpenGL::s_runtimeLibraryVersionOfOpenGL = ""; AString BrainOpenGL::s_runtimeLibraryMajorVersionOfOpenGL = ""; AString BrainOpenGL::s_runtimeLibraryMinorVersionOfOpenGL = ""; float BrainOpenGL::s_minPointSize = 1.0f; float BrainOpenGL::s_maxPointSize = 10.0f; float BrainOpenGL::s_minLineWidth = 1.0f; float BrainOpenGL::s_maxLineWidth = 10.0f; bool BrainOpenGL::s_supportsDisplayLists = false; bool BrainOpenGL::s_supportsImmediateMode = false; bool BrainOpenGL::s_supportsVertexBuffers = false; bool BrainOpenGL::s_allowTabHighlightingFlag = true; #endif //__BRAIN_OPENGL_DEFINE_H } // namespace #endif // __BRAIN_OPENGL_H__ connectome-workbench-1.4.2/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx000066400000000000000000006154211360521144700303270ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #define __BRAIN_OPEN_G_L_ANNOTATION_DRAWING_FIXED_PIPELINE_DECLARE__ #include "BrainOpenGLAnnotationDrawingFixedPipeline.h" #undef __BRAIN_OPEN_G_L_ANNOTATION_DRAWING_FIXED_PIPELINE_DECLARE__ #include "AnnotationBox.h" #include "AnnotationColorBar.h" #include "AnnotationColorBarSection.h" #include "AnnotationColorBarNumericText.h" #include "AnnotationCoordinate.h" #include "AnnotationFile.h" #include "AnnotationImage.h" #include "AnnotationLine.h" #include "AnnotationManager.h" #include "AnnotationOval.h" #include "AnnotationPercentSizeText.h" #include "AnnotationText.h" #include "Brain.h" #include "BrainOpenGLFixedPipeline.h" #include "BrainOpenGLTextRenderInterface.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretColorEnum.h" #include "CaretLogger.h" #include "DeveloperFlagsEnum.h" #include "DisplayPropertiesAnnotation.h" #include "DisplayPropertiesAnnotationTextSubstitution.h" #include "EventBrowserTabGet.h" #include "EventManager.h" #include "EventOpenGLObjectToWindowTransform.h" #include "GraphicsEngineDataOpenGL.h" #include "GraphicsPrimitiveV3f.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GraphicsPrimitiveV3fN3f.h" #include "GraphicsPrimitiveV3fT3f.h" #include "GraphicsShape.h" #include "GraphicsUtilitiesOpenGL.h" #include "IdentificationWithColor.h" #include "MathFunctions.h" #include "Matrix4x4.h" #include "SelectionManager.h" #include "SelectionItemAnnotation.h" #include "Surface.h" #include "TopologyHelper.h" using namespace caret; static const bool debugFlag = false; /** * \class caret::BrainOpenGLAnnotationDrawingFixedPipeline * \brief OpenGL Fixed Pipeline drawing of Annotations. * \ingroup Brain */ /** * Constructor. * * @param brainOpenGLFixedPipeline * Fixed pipeline drawing. */ BrainOpenGLAnnotationDrawingFixedPipeline::BrainOpenGLAnnotationDrawingFixedPipeline(BrainOpenGLFixedPipeline* brainOpenGLFixedPipeline) : CaretObject(), m_brainOpenGLFixedPipeline(brainOpenGLFixedPipeline), m_inputs(NULL), m_volumeSpacePlaneValid(false), m_volumeSliceThickness(0.0) { CaretAssert(brainOpenGLFixedPipeline); m_dummyAnnotationFile = new AnnotationFile(); m_dummyAnnotationFile->setFileName("DummyFileForDrawing" + DataFileTypeEnum::toFileExtension(DataFileTypeEnum::ANNOTATION)); float unusedLineWidthMaximum(0); BrainOpenGL::getMinMaxLineWidth(m_lineWidthMinimum, unusedLineWidthMaximum); } /** * Destructor. */ BrainOpenGLAnnotationDrawingFixedPipeline::~BrainOpenGLAnnotationDrawingFixedPipeline() { delete m_dummyAnnotationFile; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString BrainOpenGLAnnotationDrawingFixedPipeline::toString() const { return "BrainOpenGLAnnotationDrawingFixedPipeline"; } /** * Convert a viewport coordinate to an OpenGL window coordinate. * * @param viewportXYZ * Viewport coordinate * @param openGLXYZOut * Output OpenGL coordinate. */ void BrainOpenGLAnnotationDrawingFixedPipeline::viewportToOpenGLWindowCoordinate(const float viewportXYZ[3], float openGLXYZOut[3]) const { GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); openGLXYZOut[0] = viewport[2] * (viewportXYZ[0] / 100.0); openGLXYZOut[1] = viewport[3] * (viewportXYZ[1] / 100.0); openGLXYZOut[2] = (-viewportXYZ[2] / 100.0); } /** * Get the drawing space coordinate for display of the annotation. * * @param annotation * The annotation. * @param coordinate * The annotation coordinate whose window coordinate is computed. * @param surfaceDisplayed * Surface that is displayed (may be NULL !) * @param xyzOut * Output containing the drawing space coordinate. * @return * True if the drawing space coordinate is valid, else false. */ bool BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationDrawingSpaceCoordinate(const Annotation* annotation, const AnnotationCoordinate* coordinate, const Surface* surfaceDisplayed, float xyzOut[3]) const { CaretAssert(annotation); const AnnotationCoordinateSpaceEnum::Enum annotationCoordSpace = annotation->getCoordinateSpace(); float modelXYZ[3] = { 0.0, 0.0, 0.0 }; bool modelXYZValid = false; float drawingSpaceXYZ[3] = { 0.0, 0.0, 0.0 }; bool drawingSpaceXYZValid = false; float annotationXYZ[3]; coordinate->getXYZ(annotationXYZ); switch (annotationCoordSpace) { case AnnotationCoordinateSpaceEnum::CHART: modelXYZ[0] = annotationXYZ[0]; modelXYZ[1] = annotationXYZ[1]; modelXYZ[2] = annotationXYZ[2]; modelXYZValid = true; break; case AnnotationCoordinateSpaceEnum::SPACER: viewportToOpenGLWindowCoordinate(annotationXYZ, drawingSpaceXYZ); drawingSpaceXYZValid = true; break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: modelXYZ[0] = annotationXYZ[0]; modelXYZ[1] = annotationXYZ[1]; modelXYZ[2] = annotationXYZ[2]; modelXYZValid = true; if (m_volumeSpacePlaneValid) { float xyzFloat[3] = { modelXYZ[0], modelXYZ[1], modelXYZ[2] }; const float distToPlaneAbs = std::fabs(m_volumeSpacePlane.signedDistanceToPlane(xyzFloat)); const float halfSliceThickness = ((m_volumeSliceThickness > 0.0) ? (m_volumeSliceThickness / 2.0) : 1.0); if (distToPlaneAbs < halfSliceThickness) { modelXYZValid = true; float projectedPoint[3]; m_volumeSpacePlane.projectPointToPlane(modelXYZ, projectedPoint); } else { modelXYZValid = false; } } break; case AnnotationCoordinateSpaceEnum::SURFACE: if (surfaceDisplayed != NULL) { StructureEnum::Enum annotationStructure = StructureEnum::INVALID; int32_t annotationNumberOfNodes = -1; int32_t annotationNodeIndex = -1; float annotationOffsetLength = AnnotationCoordinate::getDefaultSurfaceOffsetLength(); AnnotationSurfaceOffsetVectorTypeEnum::Enum annotationOffsetVector = AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX; coordinate->getSurfaceSpace(annotationStructure, annotationNumberOfNodes, annotationNodeIndex, annotationOffsetLength, annotationOffsetVector); /* * Always use surface offset vector reported by annotation since * annotations with multiple coordinates must use the same offset */ annotationOffsetVector = annotation->getSurfaceOffsetVectorType(); const StructureEnum::Enum surfaceStructure = surfaceDisplayed->getStructure(); const int32_t surfaceNumberOfNodes = surfaceDisplayed->getNumberOfNodes(); if ((surfaceStructure == annotationStructure) && (surfaceNumberOfNodes == annotationNumberOfNodes)) { if ((annotationNodeIndex >= 0) && (annotationNodeIndex < surfaceNumberOfNodes)) { float nodeXYZ[3]; surfaceDisplayed->getCoordinate(annotationNodeIndex, nodeXYZ); modelXYZ[0] = nodeXYZ[0]; modelXYZ[1] = nodeXYZ[1]; modelXYZ[2] = nodeXYZ[2]; float offsetUnitVector[3] = { 0.0, 0.0, 0.0 }; /* * For a flat surface, ALWAYS use the normal vector. * Using the centroid will not work as there is no * "z depth" so it will incorrectly offset in the XY-plane. * */ if (surfaceDisplayed->getSurfaceType() == SurfaceTypeEnum::FLAT) { annotationOffsetVector = AnnotationSurfaceOffsetVectorTypeEnum::SURFACE_NORMAL; } switch (annotationOffsetVector) { case AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX: { BoundingBox boundingBox; surfaceDisplayed->getBounds(boundingBox); float surfaceCenter[3] = { 0.0, 0.0, 0.0 }; boundingBox.getCenter(surfaceCenter); MathFunctions::subtractVectors(nodeXYZ, surfaceCenter, offsetUnitVector); MathFunctions::normalizeVector(offsetUnitVector); } break; case AnnotationSurfaceOffsetVectorTypeEnum::SURFACE_NORMAL: { const float* normalVector = surfaceDisplayed->getNormalVector(annotationNodeIndex); offsetUnitVector[0] = normalVector[0]; offsetUnitVector[1] = normalVector[1]; offsetUnitVector[2] = normalVector[2]; } break; case AnnotationSurfaceOffsetVectorTypeEnum::TANGENT: CaretAssert(0); break; } modelXYZ[0] += (offsetUnitVector[0] * annotationOffsetLength); modelXYZ[1] += (offsetUnitVector[1] * annotationOffsetLength); modelXYZ[2] += (offsetUnitVector[2] * annotationOffsetLength); modelXYZValid = true; } } } break; case AnnotationCoordinateSpaceEnum::TAB: viewportToOpenGLWindowCoordinate(annotationXYZ, drawingSpaceXYZ); drawingSpaceXYZValid = true; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: { drawingSpaceXYZ[0] = annotationXYZ[0]; drawingSpaceXYZ[1] = annotationXYZ[1]; drawingSpaceXYZ[2] = annotationXYZ[2]; drawingSpaceXYZValid = true; const bool drawCrossFlag = false; if (drawCrossFlag) { const float redRGBA[4] = { 1.0f, 0.0, 0.0, 1.0f }; std::unique_ptr crossShape = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_LINES, redRGBA)); crossShape->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); crossShape->addVertex(drawingSpaceXYZ[0], drawingSpaceXYZ[1] - 10); crossShape->addVertex(drawingSpaceXYZ[0], drawingSpaceXYZ[1] + 10); crossShape->addVertex(drawingSpaceXYZ[0] - 10, drawingSpaceXYZ[1]); crossShape->addVertex(drawingSpaceXYZ[0] + 10, drawingSpaceXYZ[1]); GraphicsEngineDataOpenGL::draw(crossShape.get()); } } break; case AnnotationCoordinateSpaceEnum::WINDOW: viewportToOpenGLWindowCoordinate(annotationXYZ, drawingSpaceXYZ); drawingSpaceXYZValid = true; break; } if (modelXYZValid) { /* * Convert model space coordinates to window coordinates * as all annotations are drawn in window coordinates. */ if (convertModelToWindowCoordinate(modelXYZ, drawingSpaceXYZ)) { modelXYZValid = false; drawingSpaceXYZValid = true; } else { CaretLogSevere("Failed to convert model coordinates to drawing space coordinates for annotation drawing."); } } if (drawingSpaceXYZValid) { xyzOut[0] = drawingSpaceXYZ[0]; xyzOut[1] = drawingSpaceXYZ[1]; xyzOut[2] = drawingSpaceXYZ[2]; } return drawingSpaceXYZValid; } /** * Convert the given model coordinate into a window coordinate. * * @param modelXYZ * The model coordinate. * @param windowXYZOut * The window coordinate * @return true if the conversion is valid, else false. */ bool BrainOpenGLAnnotationDrawingFixedPipeline::convertModelToWindowCoordinate(const float modelXYZ[3], float windowXYZOut[3]) const { CaretAssert(m_transformEvent); CaretAssert(m_transformEvent->isValid()); m_transformEvent->transformPoint(modelXYZ, windowXYZOut); windowXYZOut[0] -= m_modelSpaceViewport[0]; windowXYZOut[1] -= m_modelSpaceViewport[1]; return true; } /** * Get the bounds for a two-dimensional shape annotation. * * @param annotation * The annotation whose bounds is computed. * @param windowXYZ * Window coordinates of the annotation. * @param bottomLeftOut * The bottom left corner of the annotation bounds. * @param bottomRightOut * The bottom right corner of the annotation bounds. * @param topRightOut * The top right corner of the annotation bounds. * @param topLeftOut * The top left corner of the annotation bounds. */ bool BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationTwoDimShapeBounds(const AnnotationTwoDimensionalShape* annotation2D, const float windowXYZ[3], float bottomLeftOut[3], float bottomRightOut[3], float topRightOut[3], float topLeftOut[3]) const { float viewportWidth = m_modelSpaceViewport[2]; float viewportHeight = m_modelSpaceViewport[3]; /* * Only use text characters when the text is NOT empty */ const AnnotationText* textAnnotation = dynamic_cast(annotation2D); bool textFlag = false; if (textAnnotation != NULL) { if ( ! textAnnotation->getText().isEmpty()) { textFlag = true; } } bool boundsValid = false; if (textFlag) { m_brainOpenGLFixedPipeline->getTextRenderer()->getBoundsForTextAtViewportCoords(*textAnnotation, m_textDrawingFlags, windowXYZ[0], windowXYZ[1], windowXYZ[2], viewportWidth, viewportHeight, bottomLeftOut, bottomRightOut, topRightOut, topLeftOut); boundsValid = true; } else { boundsValid = annotation2D->getShapeBounds(viewportWidth, viewportHeight, windowXYZ, bottomLeftOut, bottomRightOut, topRightOut, topLeftOut); } return boundsValid; } /** * Apply rotation to the shape's bounding coordinates. * * @param rotationAngle * The rotation angle. * @param bottomLeftOut * The bottom left corner of the annotation bounds. * @param bottomRightOut * The bottom right corner of the annotation bounds. * @param topRightOut * The top right corner of the annotation bounds. * @param topLeftOut * The top left corner of the annotation bounds. */ void BrainOpenGLAnnotationDrawingFixedPipeline::applyRotationToShape(const float rotationAngle, const float rotationPoint[3], float bottomLeftOut[3], float bottomRightOut[3], float topRightOut[3], float topLeftOut[3]) const { if (rotationAngle != 0) { Matrix4x4 matrix; matrix.translate(-rotationPoint[0], -rotationPoint[1], -rotationPoint[2]); matrix.rotateZ(-rotationAngle); matrix.translate(rotationPoint[0], rotationPoint[1], rotationPoint[2]); matrix.multiplyPoint3(bottomLeftOut); matrix.multiplyPoint3(bottomRightOut); matrix.multiplyPoint3(topRightOut); matrix.multiplyPoint3(topLeftOut); } } /** * Draw model space annotations on the volume slice with the given plane. * * @param inputs * Inputs for drawing annotations. * @param plane * The volume slice's plane. * @param sliceThickness * Thickness of volume slice */ void BrainOpenGLAnnotationDrawingFixedPipeline::drawModelSpaceAnnotationsOnVolumeSlice(Inputs* inputs, const Plane& plane, const float sliceThickness) { CaretAssert(inputs); m_inputs = inputs; m_surfaceViewScaling = 1.0f; m_volumeSpacePlaneValid = false; if (plane.isValidPlane()) { m_volumeSpacePlane = plane; m_volumeSpacePlaneValid = true; std::vector emptyColorBars; std::vector emptyNotInFileAnnotations; drawAnnotationsInternal(AnnotationCoordinateSpaceEnum::STEREOTAXIC, emptyColorBars, emptyNotInFileAnnotations, NULL, sliceThickness); } m_volumeSpacePlaneValid = false; m_inputs = NULL; } /** * Draw the annotations in the given coordinate space. * * @param inputs * Inputs for drawing annotations. * @param drawingCoordinateSpace * Coordinate space of annotation that are drawn. * @param colorbars * Colorbars that will be drawn. * @param notInFileAnnotations * Annotations that are not in a file but need to be drawn. * @param surfaceDisplayed * In not NULL, surface no which annotations are drawn. * @param surfaceViewScaling * Scaling of the viewed surface. */ void BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotations(Inputs* inputs, const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, std::vector& notInFileAnnotations, const Surface* surfaceDisplayed, const float surfaceViewScaling) { CaretAssert(inputs); m_inputs = inputs; m_surfaceViewScaling = surfaceViewScaling; m_volumeSpacePlaneValid = false; const float sliceThickness = 0.0; drawAnnotationsInternal(drawingCoordinateSpace, colorBars, notInFileAnnotations, surfaceDisplayed, sliceThickness); m_inputs = NULL; } /** * Draw the annotations in the given coordinate space. * * @param drawingCoordinateSpace * Coordinate space of annotation that are drawn. * @param colorbars * Colorbars that will be drawn. * @param notInFileAnnotations * Annotations that are not in a file but need to be drawn. * @param surfaceDisplayed * Surface that is displayed. May be NULL in some instances. * @param surfaceDisplayed * In not NULL, surface no which annotations are drawn. * @param sliceThickness * Thickness of volume slice */ void BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, std::vector& notInFileAnnotations, const Surface* surfaceDisplayed, const float sliceThickness) { if (m_inputs->m_brain == NULL) { return; } EventOpenGLObjectToWindowTransform::SpaceType spaceType = EventOpenGLObjectToWindowTransform::SpaceType::MODEL; if (m_volumeSpacePlaneValid) { spaceType = EventOpenGLObjectToWindowTransform::SpaceType::VOLUME_SLICE_MODEL; } m_transformEvent.reset(new EventOpenGLObjectToWindowTransform(spaceType)); EventManager::get()->sendEvent(m_transformEvent.get()->getPointer()); CaretAssert(m_transformEvent->isValid()); m_volumeSliceThickness = sliceThickness; setSelectionBoxColor(); m_brainOpenGLFixedPipeline->checkForOpenGLError(NULL, ("At beginning of annotation drawing in space " + AnnotationCoordinateSpaceEnum::toName(drawingCoordinateSpace))); AnnotationManager* annotationManager = m_inputs->m_brain->getAnnotationManager(); /* * When user is drawing an annotation by dragging the mouse, it is always in window space. */ const Annotation* annotationBeingDrawn = ((drawingCoordinateSpace == AnnotationCoordinateSpaceEnum::WINDOW) ? annotationManager->getAnnotationBeingDrawnInWindow(m_inputs->m_windowIndex) : NULL); bool drawAnnotationsFromFilesFlag = true; const DisplayPropertiesAnnotationTextSubstitution* dpats = m_inputs->m_brain->getDisplayPropertiesAnnotationTextSubstitution(); m_textDrawingFlags.setDrawSubstitutedText(dpats->isEnableSubstitutions()); bool haveDisplayGroupFlag = true; switch (drawingCoordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: haveDisplayGroupFlag = false; break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: haveDisplayGroupFlag = false; switch (m_inputs->m_windowDrawingMode) { case Inputs::WINDOW_DRAWING_NO: drawAnnotationsFromFilesFlag = false; break; case Inputs::WINDOW_DRAWING_YES: break; } break; } /* * User may turn off display of all annotations. * Color bars and other annotations not in a file are always * drawn so continue processing. */ const DisplayPropertiesAnnotation* dpa = m_inputs->m_brain->getDisplayPropertiesAnnotation(); if ( ! dpa->isDisplayAnnotations()) { drawAnnotationsFromFilesFlag = false; } /* * Note: When window annotations are being drawn, the * tab index is invalid so it must be ignored. */ DisplayGroupEnum::Enum displayGroup = DisplayGroupEnum::DISPLAY_GROUP_A; if (haveDisplayGroupFlag) { displayGroup = dpa->getDisplayGroupForTab(m_inputs->m_tabIndex); } SelectionItemAnnotation* annotationID = m_inputs->m_brain->getSelectionManager()->getAnnotationIdentification(); GLint savedShadeModel = 0; GLboolean savedLightingEnabled = GL_FALSE; startOpenGLForDrawing(&savedShadeModel, &savedLightingEnabled); /* * Check for a 'selection' type mode */ bool idReturnFlag = false; m_selectionModeFlag = false; m_selectionInfo.clear(); switch (m_inputs->m_drawingMode) { case BrainOpenGLFixedPipeline::MODE_DRAWING: break; case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: if (annotationID->isEnabledForSelection()) { m_selectionModeFlag = true; } else { idReturnFlag = true; } /* * Need flag shading for identification */ glShadeModel(GL_FLAT); break; case BrainOpenGLFixedPipeline::MODE_PROJECTION: idReturnFlag = true; break; } if (idReturnFlag) { endOpenGLForDrawing(savedShadeModel, savedLightingEnabled); return; } /* * When selecting, clear out all previous drawing * since we identify via colors in each pixel. */ if (m_selectionModeFlag) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } std::vector allAnnotationFiles; if (drawAnnotationsFromFilesFlag) { m_inputs->m_brain->getAllAnnotationFilesIncludingSceneAnnotationFile(allAnnotationFiles); } m_brainOpenGLFixedPipeline->checkForOpenGLError(NULL, ("Before draw annotations loop in space: " + AnnotationCoordinateSpaceEnum::toName(drawingCoordinateSpace))); /* * Draw annotations from all files. * NOTE: iFile == numAnnFiles, the annotation colorbars * and annotation chart labels are drawn */ const int32_t numAnnFiles = static_cast(allAnnotationFiles.size()); for (int32_t iFile = 0; iFile <= numAnnFiles; iFile++) { AnnotationFile* annotationFile = NULL; std::vector annotationsFromFile; if (iFile == numAnnFiles) { /* * Use the dummy file when drawing annotation color * bars since they do not belong to a file. */ annotationFile = m_dummyAnnotationFile; switch (drawingCoordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::TAB: case AnnotationCoordinateSpaceEnum::WINDOW: { /* * Note: Positions are in percentages ranging [0.0, 100.0] */ const float yStart = 4.0; float x = 14.0; float y = yStart; int32_t lastTabIndex = -1; bool firstColorBarFlag = true; if ( ! colorBars.empty()) { for (std::vector::iterator cbIter = colorBars.begin(); cbIter != colorBars.end(); cbIter++) { AnnotationColorBar* cb = *cbIter; if (cb->getCoordinateSpace() == drawingCoordinateSpace) { switch (cb->getPositionMode()) { case AnnotationColorBarPositionModeEnum::AUTOMATIC: { /* * Note: Y is incremented twice. Once to move colorbar * so that the colorbars bottom is just above the previous * colorbar or bottom of screen. Second time to move the * Y to the top of this annotation. */ const float halfHeight = cb->getHeight() / 2.0; if (firstColorBarFlag) { firstColorBarFlag = false; y = 4; if (halfHeight > y) { y = halfHeight; } if (drawingCoordinateSpace == AnnotationCoordinateSpaceEnum::TAB) { lastTabIndex = cb->getTabIndex(); } } else { y += halfHeight; if (drawingCoordinateSpace == AnnotationCoordinateSpaceEnum::TAB) { if (cb->getTabIndex() != lastTabIndex) { /* * First color bar in tab is at bottom of tab */ y = yStart; } lastTabIndex = cb->getTabIndex(); } } float xyz[3]; cb->getCoordinate()->getXYZ(xyz); xyz[0] = x; xyz[1] = y; cb->getCoordinate()->setXYZ(xyz); y += halfHeight; } break; case AnnotationColorBarPositionModeEnum::MANUAL: break; } } } annotationsFromFile.insert(annotationsFromFile.end(), colorBars.begin(), colorBars.end()); } } break; } annotationsFromFile.insert(annotationsFromFile.end(), notInFileAnnotations.begin(), notInFileAnnotations.end()); } else { CaretAssertVectorIndex(allAnnotationFiles, iFile); annotationFile = allAnnotationFiles[iFile]; annotationFile->getAllAnnotations(annotationsFromFile); } const int32_t annotationCount = static_cast(annotationsFromFile.size()); for (int32_t iAnn = 0; iAnn < annotationCount; iAnn++) { CaretAssertVectorIndex(annotationsFromFile, iAnn); Annotation* annotation = annotationsFromFile[iAnn]; CaretAssert(annotation); bool drawItFlag = false; switch (annotation->getItemDisplaySelected(displayGroup, m_inputs->m_tabIndex)) { case TriStateSelectionStatusEnum::PARTIALLY_SELECTED: CaretAssertMessage(0, "An annotation should never be partially selected"); break; case TriStateSelectionStatusEnum::SELECTED: drawItFlag = true; break; case TriStateSelectionStatusEnum::UNSELECTED: break; } if ( ! drawItFlag) { continue; } AnnotationOneDimensionalShape* oneDimAnn = dynamic_cast(annotation); AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(annotation); /* * Limit drawing of annotations to those in the * selected coordinate space. */ const AnnotationCoordinateSpaceEnum::Enum annotationCoordinateSpace = annotation->getCoordinateSpace(); if (annotationCoordinateSpace != drawingCoordinateSpace) { continue; } if (oneDimAnn != NULL) { } else if (twoDimAnn != NULL) { } else { CaretAssertMessage(0, ("Annotation is not derived from One or Two Dim Annotation classes: " + annotation->toString())); continue; } switch (annotationCoordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: { const SpacerTabIndex spacerTabIndex = annotation->getSpacerTabIndex(); CaretAssert(spacerTabIndex.isValid()); if (m_inputs->m_spacerTabIndex != spacerTabIndex) { continue; } } break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: { const int32_t annotationTabIndex = annotation->getTabIndex(); if ((annotationTabIndex < 0) || (annotationTabIndex >= BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)) { CaretLogSevere("Annotation has invalid tab index=" + AString::number(annotationTabIndex) + " " + annotation->toString()); } if (m_inputs->m_tabIndex != annotationTabIndex) { continue; } } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: { const int32_t annotationWindowIndex = annotation->getWindowIndex(); if ((annotationWindowIndex < 0) || (annotationWindowIndex >= BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)) { CaretLogSevere("Annotation has invalid window index=" + AString::number(annotationWindowIndex) + " " + annotation->toString()); } if (m_inputs->m_windowIndex != annotationWindowIndex) { continue; } } break; } // /* // * Skip annotation in a different window // */ // if (annotationCoordinateSpace == AnnotationCoordinateSpaceEnum::WINDOW) { // const int32_t annotationWindowIndex = annotation->getWindowIndex(); // if ((annotationWindowIndex < 0) // || (annotationWindowIndex >= BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)) { // CaretLogSevere("Annotation has invalid window index=" // + AString::number(annotationWindowIndex) // + " " // + annotation->toString()); // } // if (m_inputs->m_windowIndex != annotationWindowIndex) { // continue; // } // } // // /* // * Skip annotations in a different tab // */ // if (annotationCoordinateSpace == AnnotationCoordinateSpaceEnum::TAB) { // const int32_t annotationTabIndex = annotation->getTabIndex(); // if ((annotationTabIndex < 0) // || (annotationTabIndex >= BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)) { // CaretLogSevere("Annotation has invalid tab index=" // + AString::number(annotationTabIndex) // + " " // + annotation->toString()); // } // if (m_inputs->m_tabIndex != annotationTabIndex) { // continue; // } // } drawAnnotation(annotationFile, annotation, surfaceDisplayed); } } m_brainOpenGLFixedPipeline->checkForOpenGLError(NULL, ("After draw annotations loop in space: " + AnnotationCoordinateSpaceEnum::toName(drawingCoordinateSpace))); if (m_selectionModeFlag) { CaretAssert(annotationID); int32_t annotationIndex = -1; float depth = -1.0; m_brainOpenGLFixedPipeline->getIndexFromColorSelection(SelectionItemDataTypeEnum::ANNOTATION, m_brainOpenGLFixedPipeline->mouseX, m_brainOpenGLFixedPipeline->mouseY, annotationIndex, depth); if (annotationIndex >= 0) { if (annotationID != NULL) { CaretAssertVectorIndex(m_selectionInfo, annotationIndex); const SelectionInfo& selectionInfo = m_selectionInfo[annotationIndex]; if (annotationID->isOtherScreenDepthCloserToViewer(depth)) { annotationID->setAnnotation(selectionInfo.m_annotationFile, selectionInfo.m_annotation, selectionInfo.m_sizingHandle); annotationID->setBrain(m_inputs->m_brain); annotationID->setScreenXYZ(selectionInfo.m_windowXYZ); annotationID->setScreenDepth(depth); CaretLogFine("Selected Annotation: " + annotationID->toString()); } } } } else { /* * Annotation being drawn by the user. */ m_brainOpenGLFixedPipeline->checkForOpenGLError(NULL, "Start of annotation drawn by user model space."); if (annotationBeingDrawn != NULL) { if (annotationBeingDrawn->getType() == AnnotationTypeEnum::TEXT) { const AnnotationText* textAnn = dynamic_cast(annotationBeingDrawn); CaretAssert(textAnn); AnnotationBox box(AnnotationAttributesDefaultTypeEnum::NORMAL); box.applyCoordinatesSizeAndRotationFromOther(textAnn); box.applyColoringFromOther(textAnn); drawAnnotation(m_dummyAnnotationFile, &box, surfaceDisplayed); } else { drawAnnotation(m_dummyAnnotationFile, const_cast(annotationBeingDrawn), surfaceDisplayed); } } m_brainOpenGLFixedPipeline->checkForOpenGLError(NULL, "End of annotation drawn by user model space."); } endOpenGLForDrawing(savedShadeModel, savedLightingEnabled); m_brainOpenGLFixedPipeline->checkForOpenGLError(NULL, ("At end of annotation drawing in space " + AnnotationCoordinateSpaceEnum::toName(drawingCoordinateSpace))); } /** * Sets OpenGL attributes before drawing annotations. * * @param savedShadeModelOut * Current shading model is saved to this. * @param savedLightingEnabledOut * Current lighting enabled status is saved to this. */ void BrainOpenGLAnnotationDrawingFixedPipeline::startOpenGLForDrawing(GLint* savedShadeModelOut, GLboolean* savedLightingEnabledOut) { glGetIntegerv(GL_SHADE_MODEL, savedShadeModelOut); glGetBooleanv(GL_LIGHTING, savedLightingEnabledOut); glDisable(GL_LIGHTING); /* * When selection is performed, annoations in model space need * to be converted to window coordinates. However, when * selecting, all annotations are drawn in WINDOW SPACE * as a rectangle in a solid color so that the color selector * can be used. * * So, when selecting: * (1) Save the matrices and viewewport if drawing in * model space. * (2) Setup matrices for pixel (window) coordinates. * Since we are changing the matrices, they must * be saved as is done in (1). */ glGetDoublev(GL_MODELVIEW_MATRIX, m_modelSpaceModelMatrix); glGetDoublev(GL_PROJECTION_MATRIX, m_modelSpaceProjectionMatrix); glGetIntegerv(GL_VIEWPORT, m_modelSpaceViewport); GLdouble depthRange[2]; glGetDoublev(GL_DEPTH_RANGE, depthRange); /* * All drawing is in window space */ glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0.0, m_modelSpaceViewport[2], 0.0, m_modelSpaceViewport[3], depthRange[0], depthRange[1]); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); m_brainOpenGLFixedPipeline->enableLineAntiAliasing(); } /** * Restores OpenGL attributes after drawing annotations. * * @param savedShadeModel * Saved shading model that is restored * @param savedLightingEnabled * Saved lighting enabled that is restored */ void BrainOpenGLAnnotationDrawingFixedPipeline::endOpenGLForDrawing(GLint savedShadeModel, GLboolean savedLightingEnabled) { /* * Disable anti-aliasing for lines */ m_brainOpenGLFixedPipeline->disableLineAntiAliasing(); if (savedLightingEnabled) { glEnable(GL_LIGHTING); } else { glDisable(GL_LIGHTING); } glShadeModel(savedShadeModel); /* * Restore the matrices since we were drawing in window space */ glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } /** * Get color used for identification when drawing an annotation. * * @param identificationColorOut * Color components encoding identification. */ void BrainOpenGLAnnotationDrawingFixedPipeline::getIdentificationColor(uint8_t identificationColorOut[4]) { const int32_t annotationDrawnIndex = static_cast(m_selectionInfo.size()); m_brainOpenGLFixedPipeline->colorIdentification->addItem(identificationColorOut, SelectionItemDataTypeEnum::ANNOTATION, annotationDrawnIndex); } /** * Draw an annotation. * * @param annotationFile * File containing the annotation. * @param annotation * Annotation to draw. * @param surfaceDisplayed * Surface that is displayed (may be NULL). */ void BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotation(AnnotationFile* annotationFile, Annotation* annotation, const Surface* surfaceDisplayed) { CaretAssert(annotation); bool drawnFlag = false; if (annotation->isInSurfaceSpaceWithTangentOffset()) { AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(annotation); if (twoDimAnn != NULL) { drawnFlag = drawTwoDimAnnotationSurfaceTextureOffset(annotationFile, twoDimAnn, surfaceDisplayed); } else { AnnotationOneDimensionalShape* oneDimAnn = dynamic_cast(annotation); drawnFlag = drawOneDimAnnotationSurfaceTextureOffset(annotationFile, oneDimAnn, surfaceDisplayed); } } else { switch (annotation->getType()) { case AnnotationTypeEnum::BOX: drawnFlag = drawBox(annotationFile, dynamic_cast(annotation), surfaceDisplayed); break; case AnnotationTypeEnum::COLOR_BAR: drawColorBar(annotationFile, dynamic_cast(annotation)); break; case AnnotationTypeEnum::IMAGE: drawnFlag = drawImage(annotationFile, dynamic_cast(annotation), surfaceDisplayed); break; case AnnotationTypeEnum::LINE: drawnFlag = drawLine(annotationFile, dynamic_cast(annotation), surfaceDisplayed); break; case AnnotationTypeEnum::OVAL: drawnFlag = drawOval(annotationFile, dynamic_cast(annotation), surfaceDisplayed); break; case AnnotationTypeEnum::TEXT: drawnFlag = drawText(annotationFile, dynamic_cast(annotation), surfaceDisplayed); break; } } if (drawnFlag) { annotation->setDrawnInWindowStatus(m_inputs->m_windowIndex); } } /** * Draw a two-dimensional annotation that is in surface space with a texture offset. * * @param annotationFile * File containing the annotation. * @param annotation * Annotation to draw. * @param surfaceDisplayed * Surface that is displayed (may be NULL). * @return * True if the anntotation was drawn, else false. */ bool BrainOpenGLAnnotationDrawingFixedPipeline::drawTwoDimAnnotationSurfaceTextureOffset(AnnotationFile* annotationFile, AnnotationTwoDimensionalShape* annotation, const Surface* surfaceDisplayed) { bool drawnFlag = false; CaretAssert(annotationFile); CaretAssert(annotation); CaretAssert(surfaceDisplayed); const AnnotationCoordinate* coord = annotation->getCoordinate(); CaretAssert(coord->getSurfaceOffsetVectorType() == AnnotationSurfaceOffsetVectorTypeEnum::TANGENT); StructureEnum::Enum structure; int32_t surfaceNumberOfNodes(0); int32_t vertexIndex(0); float offsetLength(0.0f); AnnotationSurfaceOffsetVectorTypeEnum::Enum offsetVectorType; coord->getSurfaceSpace(structure, surfaceNumberOfNodes, vertexIndex, offsetLength, offsetVectorType); if (structure != surfaceDisplayed->getStructure()) { return false; } if (surfaceDisplayed->getNumberOfNodes() != surfaceNumberOfNodes) { return false; } float vertexXYZ[3]; surfaceDisplayed->getCoordinate(vertexIndex, vertexXYZ); float normalXYZ[3]; getSurfaceNormalVector(surfaceDisplayed, vertexIndex, normalXYZ); const BoundingBox* boundingBox = surfaceDisplayed->getBoundingBox(); const float surfaceExtentZ = ((surfaceDisplayed->getSurfaceType() == SurfaceTypeEnum::FLAT) ? boundingBox->getDifferenceY() : boundingBox->getDifferenceZ()); /* * Need to restore model space * Recall that all other annotation spaces are drawn in window space */ glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadMatrixd(m_modelSpaceProjectionMatrix); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadMatrixd(m_modelSpaceModelMatrix); int32_t savedViewport[4]; glGetIntegerv(GL_VIEWPORT, savedViewport); glViewport(m_modelSpaceViewport[0], m_modelSpaceViewport[1], m_modelSpaceViewport[2], m_modelSpaceViewport[3]); glPushMatrix(); /* * Matrix that rotates annotation to plane of vertex's normal vector */ Matrix4x4 rotationMatrix; rotationMatrix.setMatrixToOpenGLRotationFromVector(normalXYZ); double rotationArray[16]; rotationMatrix.getMatrixForOpenGL(rotationArray); /* * Translate to the vertex and then translate using offset * vector of text. */ const float offsetVectorXYZ[3] { normalXYZ[0] * offsetLength, normalXYZ[1] * offsetLength, normalXYZ[2] * offsetLength }; glTranslatef(vertexXYZ[0], vertexXYZ[1], vertexXYZ[2]); glTranslatef(offsetVectorXYZ[0], offsetVectorXYZ[1], offsetVectorXYZ[2]); /* * Rotate into plane of surface normal vector */ glMultMatrixd(rotationArray); /* * Up vector in local coordinates (text drawing plane) * Z points out of text */ const float len(25.0f); const float localUpXYZ[3] { 0.0, len, 0.0 }; /* * Inverse matrix goes back to surface coordinate system */ Matrix4x4 inverseMatrix(rotationMatrix); inverseMatrix.invert(); /* * Create the plane in which text is drawn * (plane is not used for drawing text but is used * to orient the text). The plane is constructed * from the vertex's normal vector and the the * vertex's XYZ-coordinate. */ Plane textDrawingPlane(normalXYZ, vertexXYZ); /* * Project a point with a large Z-coordinate to the plane * and use it to creat the 'text up orientation vector'. */ const float zBig[3] { 0.0, 0.0, 10000.0 }; float textUpOrientationVectorXYZ[3]; textDrawingPlane.projectPointToPlane(zBig, textUpOrientationVectorXYZ); inverseMatrix.multiplyPoint3(textUpOrientationVectorXYZ); /* * Vector is parallel to surface Z-axis */ float vectorSurfaceAxisZ[3] = { 0.0f, 0.0f, 100.0f }; inverseMatrix.multiplyPoint3(vectorSurfaceAxisZ); if (debugFlag) { /* * Red line is normal vector * Green line is "text up" vector * Blue points to surface Z-vector * Yellow is parallel to surface Z-axis */ const float startXYZ[3] { 0.0, 0.0, 0.0 }; const float endXYZ[3] { 0.0, 0.0, len }; glBegin(GL_LINES); glColor3f(1.0, 0.0, 0.0); glVertex3fv(startXYZ); glVertex3fv(endXYZ); glColor3f(0.0, 1.0, 0.0); glVertex3fv(startXYZ); glVertex3fv(localUpXYZ); glColor3f(0.0, 0.0, 1.0); glVertex3fv(startXYZ); glVertex3fv(textUpOrientationVectorXYZ); glColor3f(1.0, 1.0, 0.0); glVertex3fv(startXYZ); glVertex3fv(vectorSurfaceAxisZ); glEnd(); } /* * Rotate the text so that the horzontal flow of the text * is orthogonal to the 'text up orientation vector'. */ const float orientationUpAngle = MathFunctions::angleInDegreesBetweenVectors(localUpXYZ, vectorSurfaceAxisZ); if (debugFlag) { std::cout << "Annotation: " << annotation->toString() << std::endl; std::cout << " Plane: " << textDrawingPlane.toString() << std::endl; std::cout << " Local Up Vector: " << AString::fromNumbers(localUpXYZ, 3, ", ") << std::endl; std::cout << " Angle: " << orientationUpAngle << std::endl; } /* * Do not adjust tangent text on flat surfaces */ if (surfaceDisplayed->getSurfaceType() != SurfaceTypeEnum::FLAT) { /* * Rotates annotation so that its horizontal axis is aligned with the * 'best matching' cartesian axis. */ const float angle = annotation->getSurfaceSpaceWithTangentOffsetRotation(structure, normalXYZ); glRotated(angle, 0.0, 0.0, -1.0); } /* * Note that text is rotated by the text renderer */ if (annotation->getType() != AnnotationTypeEnum::TEXT) { glRotated(annotation->getRotationAngle(), 0.0, 0.0, -1.0); } switch (annotation->getType()) { case AnnotationTypeEnum::BOX: drawnFlag = drawBoxSurfaceTangentOffset(annotationFile, dynamic_cast(annotation), surfaceExtentZ, vertexXYZ); break; case AnnotationTypeEnum::COLOR_BAR: CaretAssertMessage(0, "Color Bar is NEVER drawn in surface space"); break; case AnnotationTypeEnum::IMAGE: drawnFlag = drawImageSurfaceTangentOffset(annotationFile, dynamic_cast(annotation), surfaceExtentZ, vertexXYZ); break; case AnnotationTypeEnum::LINE: CaretAssert(0); break; case AnnotationTypeEnum::OVAL: drawnFlag = drawOvalSurfaceTangentOffset(annotationFile, dynamic_cast(annotation), surfaceExtentZ, vertexXYZ); break; case AnnotationTypeEnum::TEXT: drawnFlag = drawTextSurfaceTangentOffset(annotationFile, dynamic_cast(annotation), surfaceExtentZ, vertexXYZ, normalXYZ); break; } glPopMatrix(); /* restore MODELVIEW */ glViewport(savedViewport[0], savedViewport[1], savedViewport[2], savedViewport[3]); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); return drawnFlag; } /** * Draw a one-dimensional annotation that is in surface space with a texture offset. * * @param annotationFile * File containing the annotation. * @param annotation * Annotation to draw. * @param surfaceDisplayed * Surface that is displayed (may be NULL). * @return * True if the anntotation was drawn, else false. */ bool BrainOpenGLAnnotationDrawingFixedPipeline::drawOneDimAnnotationSurfaceTextureOffset(AnnotationFile* annotationFile, AnnotationOneDimensionalShape* annotation, const Surface* surfaceDisplayed) { CaretAssert(annotationFile); CaretAssert(annotation); CaretAssert(surfaceDisplayed); bool drawnFlag = false; const BoundingBox* boundingBox = surfaceDisplayed->getBoundingBox(); const float surfaceExtentZ = boundingBox->getDifferenceZ(); /* * Need to restore model space * Recall that all other annotation spaces are drawn in window space */ glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadMatrixd(m_modelSpaceProjectionMatrix); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadMatrixd(m_modelSpaceModelMatrix); int32_t savedViewport[4]; glGetIntegerv(GL_VIEWPORT, savedViewport); glViewport(m_modelSpaceViewport[0], m_modelSpaceViewport[1], m_modelSpaceViewport[2], m_modelSpaceViewport[3]); glPushMatrix(); switch (annotation->getType()) { case AnnotationTypeEnum::BOX: case AnnotationTypeEnum::COLOR_BAR: case AnnotationTypeEnum::IMAGE: case AnnotationTypeEnum::OVAL: case AnnotationTypeEnum::TEXT: CaretAssert(0); break; case AnnotationTypeEnum::LINE: drawnFlag = drawLineSurfaceTextureOffset(annotationFile, dynamic_cast(annotation), surfaceDisplayed, surfaceExtentZ); break; } glPopMatrix(); /* restore MODELVIEW */ glViewport(savedViewport[0], savedViewport[1], savedViewport[2], savedViewport[3]); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); return drawnFlag; } /** * Draw an annotation box. * * @param annotationFile * File containing the annotation. * @param box * box to draw. * @param surfaceDisplayed * Surface that is displayed (may be NULL). * @return * True if the annotation was drawn while NOT selecting annotations. */ bool BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFile, AnnotationBox* box, const Surface* surfaceDisplayed) { CaretAssert(box); CaretAssert(box->getType() == AnnotationTypeEnum::BOX); float annXYZ[3]; if ( ! getAnnotationDrawingSpaceCoordinate(box, box->getCoordinate(), surfaceDisplayed, annXYZ)) { return false; } float bottomLeft[3]; float bottomRight[3]; float topRight[3]; float topLeft[3]; if ( ! getAnnotationTwoDimShapeBounds(box, annXYZ, bottomLeft, bottomRight, topRight, topLeft)) { return false; } const float selectionCenterXYZ[3] = { (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0f, (bottomLeft[1] + bottomRight[1] + topRight[1] + topLeft[1]) / 4.0f, (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0f }; if (box->getLineWidthPercentage() <= 0.0f) { convertObsoleteLineWidthPixelsToPercentageWidth(box); } const bool depthTestFlag = isDrawnWithDepthTesting(box, surfaceDisplayed); const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); uint8_t backgroundRGBA[4]; box->getBackgroundColorRGBA(backgroundRGBA); uint8_t foregroundRGBA[4]; box->getLineColorRGBA(foregroundRGBA); const bool drawBackgroundFlag = (backgroundRGBA[3] > 0); const bool drawForegroundFlag = (foregroundRGBA[3] > 0); const bool drawAnnotationFlag = (drawBackgroundFlag || drawForegroundFlag); bool drawnFlag = false; if (drawAnnotationFlag) { if (m_selectionModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); if (drawBackgroundFlag) { /* * When selecting draw only background if it is enabled * since it is opaque and prevents "behind" annotations * from being selected */ GraphicsShape::drawBoxFilledByteColor(bottomLeft, bottomRight, topRight, topLeft, selectionColorRGBA); } else { /* * Drawing foreground as line will still allow user to * select annotation that are inside of the box */ const float percentHeight = getLineWidthPercentageInSelectionMode(box); GraphicsShape::drawBoxOutlineByteColor(bottomLeft, bottomRight, topRight, topLeft, selectionColorRGBA, GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, percentHeight); } m_selectionInfo.push_back(SelectionInfo(annotationFile, box, AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, selectionCenterXYZ)); } else { if (drawBackgroundFlag) { GraphicsShape::drawBoxFilledByteColor(bottomLeft, bottomRight, topRight, topLeft, backgroundRGBA); drawnFlag = true; } if (drawForegroundFlag) { GraphicsShape::drawBoxOutlineByteColor(bottomLeft, bottomRight, topRight, topLeft, foregroundRGBA, GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, box->getLineWidthPercentage()); drawnFlag = true; } } if (box->isSelectedForEditing(m_inputs->m_windowIndex)) { drawAnnotationTwoDimSizingHandles(annotationFile, box, bottomLeft, bottomRight, topRight, topLeft, s_sizingHandleLineWidthInPixels, box->getRotationAngle()); } } setDepthTestingStatus(savedDepthTestStatus); return drawnFlag; } /** * Draw an annotation box in surface tangent offset space * * @param annotationFile * File containing the annotation. * @param box * box to draw. * @param surfaceExtentZ * Z-extent of the surface. * @param vertexXYZ * Coordinate of the vertex. * @return * True if the annotation was drawn while NOT selecting annotations. */ bool BrainOpenGLAnnotationDrawingFixedPipeline::drawBoxSurfaceTangentOffset(AnnotationFile* annotationFile, AnnotationBox* box, const float surfaceExtentZ, const float vertexXYZ[3]) { CaretAssert(annotationFile); CaretAssert(box); CaretAssert(box->getType() == AnnotationTypeEnum::BOX); const float halfWidth = ((box->getWidth() / 100.0) * surfaceExtentZ) / 2.0; const float halfHeight = ((box->getHeight() / 100.0) * surfaceExtentZ) / 2.0; float bottomLeft[3] { -halfWidth, -halfHeight, 0.0f }; float bottomRight[3] { halfWidth, -halfHeight, 0.0f }; float topRight[3] { halfWidth, halfHeight, 0.0f }; float topLeft[3] { -halfWidth, halfHeight, 0.0f }; const float selectionCenterXYZ[3] = { vertexXYZ[0], vertexXYZ[1], vertexXYZ[2] }; float lineThickness = ((box->getLineWidthPercentage() / 100.0) * surfaceExtentZ); if (m_selectionModeFlag) { lineThickness = std::max(lineThickness, s_selectionLineMinimumPixelWidth); } uint8_t backgroundRGBA[4]; box->getBackgroundColorRGBA(backgroundRGBA); uint8_t foregroundRGBA[4]; box->getLineColorRGBA(foregroundRGBA); const bool drawBackgroundFlag = (backgroundRGBA[3] > 0); const bool drawForegroundFlag = (foregroundRGBA[3] > 0); const bool drawAnnotationFlag = (drawBackgroundFlag || drawForegroundFlag); bool drawnFlag = false; if (drawAnnotationFlag) { if (m_selectionModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); if (drawBackgroundFlag) { /* * When selecting draw only background if it is enabled * since it is opaque and prevents "behind" annotations * from being selected */ GraphicsShape::drawBoxFilledByteColor(bottomLeft, bottomRight, topRight, topLeft, selectionColorRGBA); } else { /* * Drawing foreground as line will still allow user to * select annotation that are inside of the box */ GraphicsShape::drawBoxOutlineByteColor(bottomLeft, bottomRight, topRight, topLeft, selectionColorRGBA, GraphicsPrimitive::LineWidthType::PIXELS, lineThickness); } m_selectionInfo.push_back(SelectionInfo(annotationFile, box, AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, selectionCenterXYZ)); } else { if (drawBackgroundFlag) { GraphicsShape::drawBoxFilledByteColor(bottomLeft, bottomRight, topRight, topLeft, backgroundRGBA); drawnFlag = true; } if (drawForegroundFlag) { glPolygonOffset(-1.0, -1.0); glEnable(GL_POLYGON_OFFSET_FILL); GraphicsShape::drawOutlineRectangleVerticesInMiddle(bottomLeft, bottomRight, topRight, topLeft, lineThickness, foregroundRGBA); drawnFlag = true; glDisable(GL_POLYGON_OFFSET_FILL); } } if (box->isSelectedForEditing(m_inputs->m_windowIndex)) { drawAnnotationTwoDimSizingHandles(annotationFile, box, bottomLeft, bottomRight, topRight, topLeft, s_sizingHandleLineWidthInPixels, box->getRotationAngle()); } } return drawnFlag; } /** * Draw an annotation color bar. * * @param annotationFile * File containing the annotation. * @param colorBar * Color bar to draw. */ void BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBar(AnnotationFile* annotationFile, AnnotationColorBar* colorBar) { CaretAssert(colorBar); CaretAssert(colorBar->getType() == AnnotationTypeEnum::COLOR_BAR); float annXYZ[3]; if ( ! getAnnotationDrawingSpaceCoordinate(colorBar, colorBar->getCoordinate(), NULL, annXYZ)) { return; } float bottomLeft[3]; float bottomRight[3]; float topRight[3]; float topLeft[3]; if ( ! getAnnotationTwoDimShapeBounds(colorBar, annXYZ, bottomLeft, bottomRight, topRight, topLeft)) { return; } const float viewportHeight = m_modelSpaceViewport[3]; const float viewportWidth = m_modelSpaceViewport[2]; /* * The user sets the total height of the colorbar and the * height of the text. * * There are three items in the colorbar from top to bottom: * (1) The numeric values * (2) The tick marks * (3) The palettes color sections */ float totalHeightPercent = colorBar->getHeight(); float textHeightPercent = colorBar->getFontPercentViewportSize(); float totalHeightPixels = (viewportHeight * (totalHeightPercent / 100.0f)); /* * Text is aligned at the top of the characters */ float textHeightPixels = (viewportHeight * (textHeightPercent / 100.0f)); if (debugFlag) { std::cout << "Color bar heights before corrections (pixels) " << std::endl; std::cout << " Text: " << textHeightPixels << std::endl; } switch (colorBar->getPositionMode()) { case AnnotationColorBarPositionModeEnum::AUTOMATIC: { const float startingX = (bottomLeft[0] + topLeft[0]) / 2.0f; float estimatedWidth = estimateColorBarWidth(colorBar, textHeightPixels); /* * Maximum width is set so that margins on left and right sides * of the color bar are identical. */ const float maximumWidth = viewportWidth - (startingX * 2.0f); if (estimatedWidth > maximumWidth) { /* * Since the width of the text is a function of the text height, * gradually reduce the height of the text until the color bar * width is less than the maximum allowable width. Note that * the font heights are not a continuous function so that a * range of "requested font heights" may correspond to one * font height. */ const float tooBigTextHeightPixels = textHeightPixels; const float onePercentPixelHeight = textHeightPixels * 0.01; for (int32_t pctSteps = 0; pctSteps < 100; pctSteps++) { textHeightPixels -= onePercentPixelHeight; estimatedWidth = estimateColorBarWidth(colorBar, textHeightPixels); if (estimatedWidth <= maximumWidth) { break; } } if (estimatedWidth > maximumWidth) { estimatedWidth = maximumWidth; } /* * Since the height of the text has been reduced, we must also reduce the * height of the color bar. Otherwise, the color swatches will become taller * (color swatches fill the region of color bar not used by the text). */ const float textHeightPixelChangePercent = ((tooBigTextHeightPixels - textHeightPixels) / tooBigTextHeightPixels); if (debugFlag) { std::cout << "Too big text height: " << tooBigTextHeightPixels << std::endl; std::cout << " Reduced to: " << textHeightPixels << std::endl; std::cout << "Text height percentage change: " << textHeightPixelChangePercent << std::endl; } const float tooBigTextHeightPercent = textHeightPercent; textHeightPercent = (textHeightPixels / viewportHeight) * 100.0; const float textPercentChange = tooBigTextHeightPercent - textHeightPercent; totalHeightPercent -= textPercentChange; totalHeightPixels = (viewportHeight * (totalHeightPercent / 100.0f)); } const float shapeWidth = MathFunctions::distance3D(bottomLeft, bottomRight); if (estimatedWidth > shapeWidth) { /* * The corners of the color bar must now be recomputed to account * for the reduced dimensions of the color bar. */ float bottomUnitVector[3]; MathFunctions::createUnitVector(bottomLeft, bottomRight, bottomUnitVector); float topUnitVector[3]; MathFunctions::createUnitVector(topLeft, topRight, topUnitVector); float leftUnitVector[3]; MathFunctions::createUnitVector(bottomLeft, topLeft, leftUnitVector); if (debugFlag) { std::cout << "Too short bottom right: " << AString::fromNumbers(bottomRight, 3, ", ") << std::endl; } for (int32_t i = 0; i < 3; i++) { topLeft[i] = bottomLeft[i] + leftUnitVector[i] * totalHeightPixels; topRight[i] = topLeft[i] + topUnitVector[i] * estimatedWidth; bottomRight[i] = bottomLeft[i] + bottomUnitVector[i] * estimatedWidth; } if (debugFlag) { std::cout << " Adjusted bottom right: " << AString::fromNumbers(bottomRight, 3, ", ") << std::endl; } } } break; case AnnotationColorBarPositionModeEnum::MANUAL: break; } float ticksMarksHeightPercent = totalHeightPercent * 0.10; float sectionsHeightPercent = totalHeightPercent - (ticksMarksHeightPercent - textHeightPercent); if (sectionsHeightPercent <= 0.0f) { sectionsHeightPercent = totalHeightPercent * 0.10f; textHeightPercent = totalHeightPercent - sectionsHeightPercent; } const float tickMarksHeightPixels = (viewportHeight * (ticksMarksHeightPercent / 100.0f)); const float textOffsetFromTopPixels = 2; const float sectionsHeightPixels = (totalHeightPixels - (textHeightPixels + textOffsetFromTopPixels + tickMarksHeightPixels)); if (debugFlag) { std::cout << "Color bar heights after any adjustments (pixels) " << std::endl; std::cout << " Total: " << totalHeightPixels << std::endl; std::cout << " Text: " << textHeightPixels << std::endl; std::cout << " Text Offset: " << textOffsetFromTopPixels << std::endl; std::cout << " Ticks: " << tickMarksHeightPixels << std::endl; } const float selectionCenterXYZ[3] = { (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0f, (bottomLeft[1] + bottomRight[1] + topRight[1] + topLeft[1]) / 4.0f, (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0f }; const bool depthTestFlag = isDrawnWithDepthTesting(colorBar, NULL); const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); float backgroundRGBA[4]; colorBar->getBackgroundColorRGBA(backgroundRGBA); float foregroundRGBA[4]; colorBar->getLineColorRGBA(foregroundRGBA); const bool drawBackgroundFlag = (backgroundRGBA[3] > 0.0f); if (m_selectionModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); GraphicsShape::drawBoxFilledByteColor(bottomLeft, bottomRight, topRight, topLeft, selectionColorRGBA); m_selectionInfo.push_back(SelectionInfo(annotationFile, colorBar, AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, selectionCenterXYZ)); } else { if (drawBackgroundFlag) { float bgBottomLeft[3]; float bgBottomRight[3]; float bgTopRight[3]; float bgTopLeft[3]; for (int32_t i = 0; i < 3; i++) { bgBottomLeft[i] = bottomLeft[i]; bgBottomRight[i] = bottomRight[i]; bgTopLeft[i] = topLeft[i]; bgTopRight[i] = topRight[i]; } MathFunctions::expandBox(bgBottomLeft, bgBottomRight, bgTopRight, bgTopLeft, 2, 0); std::vector bgCoords; bgCoords.insert(bgCoords.end(), bgBottomLeft, bgBottomLeft + 3); bgCoords.insert(bgCoords.end(), bgBottomRight, bgBottomRight + 3); bgCoords.insert(bgCoords.end(), bgTopRight, bgTopRight + 3); bgCoords.insert(bgCoords.end(), bgTopLeft, bgTopLeft + 3); GraphicsShape::drawBoxFilledFloatColor(bgBottomLeft, bgBottomRight, bgTopRight, bgTopLeft, backgroundRGBA); } drawColorBarSections(colorBar, bottomLeft, bottomRight, topRight, topLeft, sectionsHeightPixels); drawColorBarText(colorBar, bottomLeft, bottomRight, topRight, topLeft, textHeightPixels, textOffsetFromTopPixels); /* * If 'extendTickMarksIntoColorBarPixels' is greater than zero, * the tickmarks will extend down and into the colorbar */ const float extendTickMarksIntoColorBarPixels = tickMarksHeightPixels; const float tickMarksOffsetFromBotom = sectionsHeightPixels - extendTickMarksIntoColorBarPixels; const float totalTickMarksHeightPixels = tickMarksHeightPixels + extendTickMarksIntoColorBarPixels; drawColorBarTickMarks(colorBar, bottomLeft, bottomRight, topRight, topLeft, totalTickMarksHeightPixels, tickMarksOffsetFromBotom); } if (colorBar->isSelectedForEditing(m_inputs->m_windowIndex)) { drawAnnotationTwoDimSizingHandles(annotationFile, colorBar, bottomLeft, bottomRight, topRight, topLeft, s_sizingHandleLineWidthInPixels, colorBar->getRotationAngle()); } setDepthTestingStatus(savedDepthTestStatus); } /** * Draw the color bar's tick marks * * @param colorBar * Colorbar whose tick marks are drawn. * @param bottomLeft * Bottom left corner of annotation. * @param bottomRight * Bottom right corner of annotation. * @param topRight * Top right corner of annotation. * @param topLeft * Top left corner of annotation. * @param tickMarksHeightInPixels * Height of the tick marks in pixels. * @param offsetFromBottomInPixels * Offset of tick marks from the bottom */ void BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarTickMarks(const AnnotationColorBar* colorBar, const float bottomLeftIn[3], const float bottomRightIn[3], const float topRightIn[3], const float topLeftIn[3], const float tickMarksHeightInPixels, const float offsetFromBottomInPixels) { if ( ! colorBar->isShowTickMarksSelected()) { return; } if (tickMarksHeightInPixels < 1.0) { return; } float bottomLeft[3]; float bottomRight[3]; float topRight[3]; float topLeft[3]; for (int32_t i = 0; i < 3; i++) { bottomLeft[i] = bottomLeftIn[i]; bottomRight[i] = bottomRightIn[i]; topRight[i] = topRightIn[i]; topLeft[i] = topLeftIn[i]; } /* * Shrink the box that bounds the color bar in X so that start * and end ticks are at the ends of the color bar. */ const float tickThickness = 2.0; MathFunctions::expandBox(bottomLeft, bottomRight, topRight, topLeft, (-tickThickness / 2.0), 0); float bottomToTopUnitVector[3]; MathFunctions::createUnitVector(bottomLeft, topLeft, bottomToTopUnitVector); const float xBottomLeft = (bottomLeft[0] + (bottomToTopUnitVector[0] * offsetFromBottomInPixels)); const float yBottomLeft = (bottomLeft[1] + (bottomToTopUnitVector[1] * offsetFromBottomInPixels)); const float xTopLeft = (xBottomLeft + (bottomToTopUnitVector[0] * tickMarksHeightInPixels)); const float yTopLeft = (yBottomLeft + (bottomToTopUnitVector[1] * tickMarksHeightInPixels)); const float xBottomRight = (bottomRight[0] + (bottomToTopUnitVector[0] * offsetFromBottomInPixels)); const float yBottomRight = (bottomRight[1] + (bottomToTopUnitVector[1] * offsetFromBottomInPixels)); const float xTopRight = (xBottomRight + (bottomToTopUnitVector[0] * tickMarksHeightInPixels)); const float yTopRight = (yBottomRight + (bottomToTopUnitVector[1] * tickMarksHeightInPixels)); float rgba[4]; colorBar->getTextColorRGBA(rgba); const float z = 0.0; std::unique_ptr linesPrimitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES, rgba)); /* * Horizontal line at top of tick marks */ const bool showHorizontalLineFlag = false; if (showHorizontalLineFlag) { linesPrimitive->addVertex(xTopLeft, yTopLeft, z); linesPrimitive->addVertex(xTopRight, yTopRight, z); } float leftToRightVector[3]; MathFunctions::subtractVectors(topRight, topLeft, leftToRightVector); const float dx = leftToRightVector[0]; const float dy = leftToRightVector[1]; /* * Tickmarks for numeric text */ const int32_t numText = colorBar->getNumberOfNumericText(); for (int32_t i = 0; i < numText; i++) { const AnnotationColorBarNumericText* numericText = colorBar->getNumericText(i); const float scalar = numericText->getScalar(); const float tickTopX = xTopLeft + (dx * scalar); const float tickTopY = yTopLeft + (dy * scalar); const float tickBottomX = xBottomLeft + (dx * scalar); const float tickBottomY = yBottomLeft + (dy * scalar); linesPrimitive->addVertex(tickTopX, tickTopY, z); linesPrimitive->addVertex(tickBottomX, tickBottomY, z); } /* * Draw lines and use polygon offset to ensure above color bar */ glPolygonOffset(1.0, 1.0); glEnable(GL_POLYGON_OFFSET_LINE); linesPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, tickThickness); GraphicsEngineDataOpenGL::draw(linesPrimitive.get()); glDisable(GL_POLYGON_OFFSET_LINE); } /** * Draw the color bar's sections (the actual color bar) * * @param colorBar * Colorbar whose sections are drawn. * @param bottomLeft * Bottom left corner of annotation. * @param bottomRight * Bottom right corner of annotation. * @param topRight * Top right corner of annotation. * @param topLeft * Top left corner of annotation. * @param sectionsHeightInPixels * Height for drawing the sections in pixels. */ void BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarSections(const AnnotationColorBar* colorBar, const float bottomLeft[3], const float bottomRight[3], const float* /* const float topRight[3]*/, const float topLeft[3], const float sectionsHeightInPixels) { std::vector colorBarLines; float bottomToTopUnitVector[3]; MathFunctions::createUnitVector(bottomLeft, topLeft, bottomToTopUnitVector); const float xTopLeft = (bottomLeft[0] + (bottomToTopUnitVector[0] * sectionsHeightInPixels)); const float yTopLeft = (bottomLeft[1] + (bottomToTopUnitVector[1] * sectionsHeightInPixels)); const float xTopRight = (bottomRight[0] + (bottomToTopUnitVector[0] * sectionsHeightInPixels)); const float yTopRight = (bottomRight[1] + (bottomToTopUnitVector[1] * sectionsHeightInPixels)); const float dx = xTopRight - xTopLeft; const float dy = yTopRight - yTopLeft; const float xBottomLeft = bottomLeft[0]; const float yBottomLeft = bottomLeft[1]; float minScalar = 0.0f; float maxScalar = 0.0f; colorBar->getScalarMinimumAndMaximumValues(minScalar, maxScalar); const float dScalar = maxScalar - minScalar; const bool printDebugFlag = false; if (printDebugFlag) { std::cout << qPrintable(QString("minScalar %1, maxScalar %2, dScalar %3").arg(minScalar).arg(maxScalar).arg(dScalar)) << std::endl; } const float z = 0.0f; std::unique_ptr linesPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); linesPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, 1.0f); std::unique_ptr trianglesPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES)); const int32_t numSections = colorBar->getNumberOfSections(); for (int32_t iSect = 0; iSect < numSections; iSect++) { const AnnotationColorBarSection* section = colorBar->getSection(iSect); const float startScalar = section->getStartScalar(); const float endScalar = section->getEndScalar(); float startNormalizedScalar = startScalar; float endNormalizedScalar = endScalar; if (dScalar > 0.0) { startNormalizedScalar = (startScalar - minScalar) / dScalar; endNormalizedScalar = (endScalar - minScalar) / dScalar; } const float blX = xBottomLeft + (dx * startNormalizedScalar); const float blY = yBottomLeft + (dy * startNormalizedScalar); const float tlX = xTopLeft + (dx * startNormalizedScalar); const float tlY = yTopLeft + (dy * startNormalizedScalar); if (startScalar == endScalar) { const float* rgba = section->getStartRGBA(); linesPrimitive->addVertex(blX, blY, z, rgba); linesPrimitive->addVertex(tlX, tlY, z, rgba); } else { const float brX = xBottomLeft + (dx * endNormalizedScalar); const float brY = yBottomLeft + (dy * endNormalizedScalar); const float trX = xTopLeft + (dx * endNormalizedScalar); const float trY = yTopLeft + (dy * endNormalizedScalar); const float* rgbaLeft = section->getStartRGBA(); const float* rgbaRight = section->getEndRGBA(); trianglesPrimitive->addVertex(blX, blY, z, rgbaLeft); trianglesPrimitive->addVertex(brX, brY, z, rgbaRight); trianglesPrimitive->addVertex(tlX, tlY, z, rgbaLeft); trianglesPrimitive->addVertex(tlX, tlY, z, rgbaLeft); trianglesPrimitive->addVertex(brX, brY, z, rgbaRight); trianglesPrimitive->addVertex(trX, trY, z, rgbaRight); if (printDebugFlag) { const AString msg("Section (" + AString::number(startScalar) + ", " + AString::number(endScalar) + ") normalized (" + AString::number(startNormalizedScalar) + ", " + AString::number(endNormalizedScalar) + ") X-range (" + AString::number(blX) + ", " + AString::number(brX) + ") Y-range (" + AString::number(blY) + ", " + AString::number(tlY) + ")"); std::cout << qPrintable(msg) << std::endl; } } } /* * Lines need to be drawn OVER any quads (otherwise the quads * would obscure the lines */ /* * Lines need to be drawn OVER any quads (otherwise the quads * would obscure the lines */ GraphicsEngineDataOpenGL::draw(trianglesPrimitive.get()); glPolygonOffset(1.0, 1.0); glEnable(GL_POLYGON_OFFSET_LINE); GraphicsEngineDataOpenGL::draw(linesPrimitive.get()); glDisable(GL_POLYGON_OFFSET_LINE); } /** * Estimate the width of the color bar. * * @param colorbar * The color bar. * @param textHeightInPixels * Height of the text in pixels. * @return * Estimated width of the color bar. */ float BrainOpenGLAnnotationDrawingFixedPipeline::estimateColorBarWidth(const AnnotationColorBar* colorBar, const float textHeightInPixels) const { const int32_t numText = colorBar->getNumberOfNumericText(); if (numText <= 0) { return 0.0f; } const int32_t viewportWidth = m_modelSpaceViewport[2]; const int32_t viewportHeight = m_modelSpaceViewport[3]; const float textPercentageHeight = (textHeightInPixels / viewportHeight) * 100.0; AnnotationPercentSizeText annText(AnnotationAttributesDefaultTypeEnum::NORMAL); annText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); annText.setFont(colorBar->getFont()); annText.setFontPercentViewportSize(textPercentageHeight); annText.setTextColor(CaretColorEnum::CUSTOM); float rgba[4]; colorBar->getTextColorRGBA(rgba); annText.setCustomTextColor(rgba); annText.setRotationAngle(colorBar->getRotationAngle()); float windowX = 0.0f; float windowY = 0.0f; float windowZ = 0.0f; std::vector allTextWidths; if (debugFlag) { std::cout << "Estimating with pixel height: " << textHeightInPixels << std::endl; } /* * Get width of each numerical text value displayed above the color bar */ for (int32_t i = 0; i < numText; i++) { const AnnotationColorBarNumericText* numericText = colorBar->getNumericText(i); annText.setText(numericText->getNumericText()); { float textBottomLeft[3]; float textBottomRight[3]; float textTopRight[3]; float textTopLeft[3]; m_brainOpenGLFixedPipeline->getTextRenderer()->getBoundsWithoutMarginForTextAtViewportCoords(annText, m_textDrawingFlags, windowX, windowY, windowZ, viewportWidth, viewportHeight, textBottomLeft, textBottomRight, textTopRight, textTopLeft); float textWidth = MathFunctions::distance3D(textBottomLeft, textBottomRight); allTextWidths.push_back(textWidth); if (debugFlag) { std::cout << "Width of \"" << numericText->getNumericText() << "\" is " << textWidth << std::endl; } } } /* * A seaparator may be placed between numerical values */ float separatorWidth = 0.0; { const AString separatorCharacter("0"); annText.setText(separatorCharacter); float textBottomLeft[3]; float textBottomRight[3]; float textTopRight[3]; float textTopLeft[3]; m_brainOpenGLFixedPipeline->getTextRenderer()->getBoundsForTextAtViewportCoords(annText, m_textDrawingFlags, windowX, windowY, windowZ, viewportWidth, viewportHeight, textBottomLeft, textBottomRight, textTopRight, textTopLeft); separatorWidth = MathFunctions::distance3D(textBottomLeft, textBottomRight); if (debugFlag) { std::cout << "Separator \"" << separatorCharacter << "\" width: " << separatorWidth << std::endl; } } CaretAssert(numText == static_cast(allTextWidths.size())); CaretAssertVectorIndex(allTextWidths, 0); const float firstWidth = allTextWidths[0]; float estimatedWidth = 0.0f; if (numText == 1) { estimatedWidth = firstWidth; } else { const int32_t lastIndex = numText - 1; CaretAssertVectorIndex(allTextWidths, lastIndex); const float lastWidth = allTextWidths[lastIndex]; if (numText == 2) { estimatedWidth = firstWidth + separatorWidth + lastWidth; } else { /* * Each of the numerical values are equally spaced. The first value is aligned left, * the last value is aligned right, and the remaining values are center aligned. * Our strategy is examine the interval (width) between each consecutive pair of * numerical values and ensure the interval is large enough so that the two * numerical text values do not overlap. Since all intervals are equally spaced, * use the largest interval for all intervals and then set the width of the color bar * to the sum of these intervals. */ float largestInterval = 0.0f; for (int32_t i = 1; i < numText; i++) { CaretAssertVectorIndex(allTextWidths, i); const float halfWidth = allTextWidths[i] / 2.0f; float interval = 0.0f; if (i == 1) { interval = firstWidth + halfWidth; } else if (i == lastIndex) { interval = lastWidth + halfWidth; } else { CaretAssertVectorIndex(allTextWidths, i - 1); const float previousHalfWidth = allTextWidths[i - 1] / 2.0f; interval = previousHalfWidth + halfWidth; } /* space to separate adjacent text */ interval += separatorWidth; if (debugFlag) { std::cout << "Interval " << i << " width: " << interval << std::endl; } largestInterval = std::max(largestInterval, interval); } const float numberOfIntervals = numText - 1; estimatedWidth = largestInterval * numberOfIntervals; if (debugFlag) { std::cout << "Estimated Width: " << estimatedWidth << " Viewport Width: " << viewportWidth << std::endl; } } } return estimatedWidth; } /** * Draw the color bar's text * * @param colorBar * Colorbar whose text is drawn. * @param bottomLeft * Bottom left corner of annotation. * @param bottomRight * Bottom right corner of annotation. * @param topRight * Top right corner of annotation. * @param topLeft * Top left corner of annotation. * @param textHeightInPixels * Height of text in pixels. * @param offsetFromTopInPixels * Offset of text from the top of the colorbar viewport in pixels * @return * Estimated width when colorBarTextMode is estimating otherwise zero when drawing. */ void BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBarText(const AnnotationColorBar* colorBar, const float bottomLeft[3], const float bottomRight[3], const float topRight[3], const float topLeft[3], const float textHeightInPixels, const float offsetFromTopInPixels) { const float textPercentageHeight = (textHeightInPixels / m_modelSpaceViewport[3]) * 100.0; AnnotationPercentSizeText annText(AnnotationAttributesDefaultTypeEnum::NORMAL); annText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); annText.setFont(colorBar->getFont()); annText.setFontPercentViewportSize(textPercentageHeight); annText.setTextColor(CaretColorEnum::CUSTOM); float rgba[4]; colorBar->getTextColorRGBA(rgba); annText.setCustomTextColor(rgba); annText.setRotationAngle(colorBar->getRotationAngle()); float bottomToTopUnitVector[3]; MathFunctions::createUnitVector(bottomLeft, topLeft, bottomToTopUnitVector); const float distanceBottomToTop = MathFunctions::distance3D(topLeft, bottomLeft); const float distanceBottomToTopWithOffset = (distanceBottomToTop - offsetFromTopInPixels); const float xTopLeft = (bottomLeft[0] + (bottomToTopUnitVector[0] * distanceBottomToTopWithOffset)); const float yTopLeft = (bottomLeft[1] + (bottomToTopUnitVector[1] * distanceBottomToTopWithOffset)); float leftToRightVector[3]; MathFunctions::subtractVectors(topRight, topLeft, leftToRightVector); const float dx = leftToRightVector[0]; const float dy = leftToRightVector[1]; std::vector> textWidthInfo; const float windowZ = (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0; const int32_t numText = colorBar->getNumberOfNumericText(); bool fontTooSmallFlag = false; for (int32_t i = 0; i < numText; i++) { const AnnotationColorBarNumericText* numericText = colorBar->getNumericText(i); const float scalar = numericText->getScalar(); float scalarOffset = 0.0; annText.setHorizontalAlignment(numericText->getHorizontalAlignment()); const float windowX = xTopLeft + (dx * (scalar + scalarOffset)); const float windowY = yTopLeft + (dy * (scalar + scalarOffset)); annText.setText(numericText->getNumericText()); BrainOpenGLTextRenderInterface::DrawingFlags flags; flags.setDrawSubstitutedText(false); m_brainOpenGLFixedPipeline->getTextRenderer()->drawTextAtViewportCoords(windowX, windowY, windowZ, annText, flags); if (annText.isFontTooSmallWhenLastDrawn()) { fontTooSmallFlag = true; } } colorBar->setFontTooSmallWhenLastDrawn(fontTooSmallFlag); } /** * Draw an annotation oval. * * @param annotationFile * File containing the annotation. * @param oval * Annotation oval to draw. * @param surfaceDisplayed * Surface that is displayed (may be NULL). * @return * True if the annotation was drawn while NOT selecting annotations. */ bool BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFile, AnnotationOval* oval, const Surface* surfaceDisplayed) { CaretAssert(oval); CaretAssert(oval->getType() == AnnotationTypeEnum::OVAL); float annXYZ[3]; if ( ! getAnnotationDrawingSpaceCoordinate(oval, oval->getCoordinate(), surfaceDisplayed, annXYZ)) { return false; } float bottomLeft[3]; float bottomRight[3]; float topRight[3]; float topLeft[3]; if ( ! getAnnotationTwoDimShapeBounds(oval, annXYZ, bottomLeft, bottomRight, topRight, topLeft)) { return false; } const float majorAxis = ((oval->getWidth() / 100.0f) * (m_modelSpaceViewport[2] / 2.0f)); const float minorAxis = ((oval->getHeight() / 100.0f) * (m_modelSpaceViewport[3] / 2.0f)); const float rotationAngle = oval->getRotationAngle(); if (oval->getLineWidthPercentage() <= 0.0) { convertObsoleteLineWidthPixelsToPercentageWidth(oval); } const float selectionCenterXYZ[3] = { (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0f, (bottomLeft[1] + bottomRight[1] + topRight[1] + topLeft[1]) / 4.0f, (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0f }; const bool depthTestFlag = isDrawnWithDepthTesting(oval, surfaceDisplayed); const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); uint8_t backgroundRGBA[4]; oval->getBackgroundColorRGBA(backgroundRGBA); uint8_t foregroundRGBA[4]; oval->getLineColorRGBA(foregroundRGBA); const bool drawBackgroundFlag = (backgroundRGBA[3] > 0); const bool drawForegroundFlag = (foregroundRGBA[3] > 0); const bool drawAnnotationFlag = (drawBackgroundFlag || drawForegroundFlag); bool drawnFlag = false; if (drawAnnotationFlag) { glPushMatrix(); glTranslatef(annXYZ[0], annXYZ[1], annXYZ[2]); if (rotationAngle != 0.0) { glRotatef(-rotationAngle, 0.0f, 0.0f, 1.0f); } if (m_selectionModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); if (drawBackgroundFlag) { /* * When selecting draw only background if it is enabled * since it is opaque and prevents "behind" annotations * from being selected */ GraphicsShape::drawEllipseFilledByteColor(majorAxis * 2.0f, minorAxis * 2.0f, selectionColorRGBA); } else { /* * Drawing foreground as line will still allow user to * select annotation that are inside of the box */ const float percentHeight = getLineWidthPercentageInSelectionMode(oval); GraphicsShape::drawEllipseOutlineByteColor(majorAxis * 2.0f, minorAxis * 2.0f, selectionColorRGBA, GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, percentHeight); } m_selectionInfo.push_back(SelectionInfo(annotationFile, oval, AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, selectionCenterXYZ)); } else { if (drawBackgroundFlag) { GraphicsShape::drawEllipseFilledByteColor(majorAxis * 2.0f, minorAxis * 2.0f, backgroundRGBA); drawnFlag = true; } if (drawForegroundFlag) { GraphicsShape::drawEllipseOutlineByteColor(majorAxis * 2.0f, minorAxis * 2.0f, foregroundRGBA, GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, oval->getLineWidthPercentage()); drawnFlag = true; } } glPopMatrix(); if (oval->isSelectedForEditing(m_inputs->m_windowIndex)) { drawAnnotationTwoDimSizingHandles(annotationFile, oval, bottomLeft, bottomRight, topRight, topLeft, s_sizingHandleLineWidthInPixels, oval->getRotationAngle()); } } setDepthTestingStatus(savedDepthTestStatus); return drawnFlag; } /** * Draw an annotation oval in surface tangent offset space * * @param annotationFile * File containing the annotation. * @param oval * oval to draw. * @param surfaceExtentZ * Z-extent of the surface. * @param vertexXYZ * Coordinate of the vertex. * @return * True if the annotation was drawn while NOT selecting annotations. */ bool BrainOpenGLAnnotationDrawingFixedPipeline::drawOvalSurfaceTangentOffset(AnnotationFile* annotationFile, AnnotationOval* oval, const float surfaceExtentZ, const float vertexXYZ[3]) { CaretAssert(annotationFile); CaretAssert(oval); CaretAssert(oval->getType() == AnnotationTypeEnum::OVAL); const float halfWidth = ((oval->getWidth() / 100.0) * surfaceExtentZ) / 2.0; const float halfHeight = ((oval->getHeight() / 100.0) * surfaceExtentZ) / 2.0; float bottomLeft[3] { -halfWidth, -halfHeight, 0.0f }; float bottomRight[3] { halfWidth, -halfHeight, 0.0f }; float topRight[3] { halfWidth, halfHeight, 0.0f }; float topLeft[3] { -halfWidth, halfHeight, 0.0f }; const float selectionCenterXYZ[3] = { vertexXYZ[0], vertexXYZ[1], vertexXYZ[2] }; float lineThickness = ((oval->getLineWidthPercentage() / 100.0) * surfaceExtentZ); if (m_selectionModeFlag) { lineThickness = std::max(lineThickness, s_selectionLineMinimumPixelWidth); } uint8_t backgroundRGBA[4]; oval->getBackgroundColorRGBA(backgroundRGBA); uint8_t foregroundRGBA[4]; oval->getLineColorRGBA(foregroundRGBA); const bool drawBackgroundFlag = (backgroundRGBA[3] > 0); const bool drawForegroundFlag = (foregroundRGBA[3] > 0); const bool drawAnnotationFlag = (drawBackgroundFlag || drawForegroundFlag); bool drawnFlag = false; const float majorAxis = ((oval->getWidth() / 100.0f) * surfaceExtentZ); const float minorAxis = ((oval->getHeight() / 100.0f) * surfaceExtentZ); if (drawAnnotationFlag) { if (m_selectionModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); if (drawBackgroundFlag) { /* * When selecting draw only background if it is enabled * since it is opaque and prevents "behind" annotations * from being selected */ GraphicsShape::drawEllipseFilledByteColor(majorAxis, minorAxis, selectionColorRGBA); } else { /* * Drawing foreground as line will still allow user to * select annotation that are inside of the box */ GraphicsShape::drawEllipseOutlineByteColor(majorAxis, minorAxis, selectionColorRGBA, GraphicsPrimitive::LineWidthType::PIXELS, lineThickness); } m_selectionInfo.push_back(SelectionInfo(annotationFile, oval, AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, selectionCenterXYZ)); } else { if (drawBackgroundFlag) { GraphicsShape::drawEllipseFilledByteColor(majorAxis, minorAxis, backgroundRGBA); drawnFlag = true; } if (drawForegroundFlag) { glPolygonOffset(-1.0, 1.0); glEnable(GL_POLYGON_OFFSET_FILL); GraphicsShape::drawEllipseOutlineModelSpaceByteColor(majorAxis, minorAxis, foregroundRGBA, lineThickness); // GraphicsShape::drawEllipseOutlineByteColor(majorAxis, // minorAxis, // foregroundRGBA, // GraphicsPrimitive::LineWidthType::PIXELS, // lineThickness); glDisable(GL_POLYGON_OFFSET_FILL); drawnFlag = true; } } if (oval->isSelectedForEditing(m_inputs->m_windowIndex)) { drawAnnotationTwoDimSizingHandles(annotationFile, oval, bottomLeft, bottomRight, topRight, topLeft, s_sizingHandleLineWidthInPixels, oval->getRotationAngle()); } } return drawnFlag; } /** * Get coordinate for drawing a line that connects text to brainordinate. * * @param text * The text annotation. * @param surfaceDisplayed * Surface for text * @param lineCoordinatesOut * Output with coordinates for drawing line. Will be EMPTY if line is not drawn. */ void BrainOpenGLAnnotationDrawingFixedPipeline::getTextLineToBrainordinateLineCoordinates(const AnnotationText* text, const Surface* surfaceDisplayed, const float bottomLeft[3], const float bottomRight[3], const float topRight[3], const float topLeft[3], std::vector& lineCoordinatesOut, std::vector& arrowCoordinatesOut) const { lineCoordinatesOut.clear(); arrowCoordinatesOut.clear(); if (text->isConnectToBrainordinateValid()) { bool showLineFlag = false; bool showArrowFlag = false; if (text->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::SURFACE) { if (surfaceDisplayed != NULL) { switch (text->getConnectToBrainordinate()) { case AnnotationTextConnectTypeEnum::ANNOTATION_TEXT_CONNECT_NONE: break; case AnnotationTextConnectTypeEnum::ANNOTATION_TEXT_CONNECT_ARROW: showArrowFlag = true; break; case AnnotationTextConnectTypeEnum::ANNOTATION_TEXT_CONNECT_LINE: showLineFlag = true; break; } } } if (showLineFlag || showArrowFlag) { const AnnotationCoordinate* coord = text->getCoordinate(); StructureEnum::Enum structure = StructureEnum::INVALID; int32_t numNodes = 0; int32_t nodeIndex = 0; float offset = 0.0; AnnotationSurfaceOffsetVectorTypeEnum::Enum offsetVector = AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX; coord->getSurfaceSpace(structure, numNodes, nodeIndex, offset, offsetVector); if (offset > 0.0) { AnnotationCoordinate noOffsetCoord = *coord; noOffsetCoord.setSurfaceSpace(structure, numNodes, nodeIndex, 0.0, AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX); float brainordinateXYZ[3]; if (getAnnotationDrawingSpaceCoordinate(text, &noOffsetCoord, surfaceDisplayed, brainordinateXYZ)) { float annXYZ[3]; if (getAnnotationDrawingSpaceCoordinate(text, coord, surfaceDisplayed, annXYZ)) { const bool clipAtBoxFlag = true; if (clipAtBoxFlag) { clipLineAtTextBox(bottomLeft, bottomRight, topRight, topLeft, brainordinateXYZ, annXYZ); } if (text->getLineWidthPercentage() <= 0.0) { convertObsoleteLineWidthPixelsToPercentageWidth(text); } const float lineWidth = getLineWidthFromPercentageHeight(text->getLineWidthPercentage()); std::vector unusedArrowCoordinates; createLineCoordinates(annXYZ, brainordinateXYZ, lineWidth, false, showArrowFlag, lineCoordinatesOut, unusedArrowCoordinates, arrowCoordinatesOut); } } } } } } /* * Clip the line that connects the text to the surface so that the line * does not enter a 'box' that encloses the text. * * @param bottomLeft * Bottom left corner of annotation. * @param bottomRight * Bottom right corner of annotation. * @param topRight * Top right corner of annotation. * @param topLeft * Top left corner of annotation. * param startXYZ * XYZ of where line attaches to surface * @param endXYZ * XYZ of where line attaches to text and may be changed to avoid * overlapping the text. */ void BrainOpenGLAnnotationDrawingFixedPipeline::clipLineAtTextBox(const float bottomLeft[3], const float bottomRight[3], const float topRight[3], const float topLeft[3], const float startXYZ[3], float endXYZ[3]) const { const float tol = 0.01; float clippedXYZ[3] = { 0.0, 0.0, 0.0 }; float clippedDistance = std::numeric_limits::max(); bool clippedValid = false; for (int32_t i = 0; i < 4; i++) { float* p1 = NULL; float* p2 = NULL; switch (i) { case 0: p1 = const_cast(bottomLeft); p2 = const_cast(bottomRight); break; case 1: p1 = const_cast(bottomRight); p2 = const_cast(topRight); break; case 2: p1 = const_cast(topRight); p2 = const_cast(topLeft); break; case 3: p1 = const_cast(topLeft); p2 = const_cast(bottomLeft); break; } /* * perform a 2D intersection test */ float intersection[3] = { 0.0, 0.0, 0.0 }; const bool yesFlag = MathFunctions::lineIntersection2D(p1, p2, startXYZ, endXYZ, tol, intersection); if (yesFlag) { /* * Intersection is TWO-D so must set * the correct Z-coordinate */ const float averageZ = ((p1[2] + p2[2]) / 2.0f); intersection[2] = averageZ; const float dist = MathFunctions::distance3D(startXYZ, intersection); if ( ( ! clippedValid) || (dist < clippedDistance)) { clippedDistance = dist; clippedValid = true; clippedXYZ[0] = intersection[0]; clippedXYZ[1] = intersection[1]; clippedXYZ[2] = intersection[2]; } } } if (clippedValid) { endXYZ[0] = clippedXYZ[0]; endXYZ[1] = clippedXYZ[1]; endXYZ[2] = clippedXYZ[2]; } } /** * Get the normal vector for a surface vector. * * @param surface * The surface. * @param vertexIndex * Index of the vertex. * @param normalVectorOut * Output containing the normal vector. */ void BrainOpenGLAnnotationDrawingFixedPipeline::getSurfaceNormalVector(const Surface* surfaceDisplayed, const int32_t vertexIndex, float normalVectorOut[3]) const { const float* normalXYZ = surfaceDisplayed->getNormalVector(vertexIndex); normalVectorOut[0] = normalXYZ[0]; normalVectorOut[1] = normalXYZ[1]; normalVectorOut[2] = normalXYZ[2]; const bool useAverageFlag = false; if ( ! useAverageFlag) { return; } CaretPointer th = surfaceDisplayed->getTopologyHelper(); int32_t numNeighbors(0); const int32_t* neighbors = th->getNodeNeighbors(vertexIndex, numNeighbors); normalVectorOut[0] = 0.0; normalVectorOut[1] = 0.0; normalVectorOut[2] = 0.0; for (int32_t n = 0; n < numNeighbors; n++) { const float* normalXYZ = surfaceDisplayed->getNormalVector(neighbors[n]); normalVectorOut[0] += normalXYZ[0]; normalVectorOut[1] += normalXYZ[1]; normalVectorOut[2] += normalXYZ[2]; } if (numNeighbors > 0) { normalVectorOut[0] /= numNeighbors; normalVectorOut[1] /= numNeighbors; normalVectorOut[2] /= numNeighbors; } } /** * @return True If the coordinate/normal vector backfacing (facing away from viewer)? * * @param xyz * Coordinate. * @param normal * Normal vector. */ bool BrainOpenGLAnnotationDrawingFixedPipeline::isBackFacing(const float xyz[3], const float normal[3]) const { /* * We don't know where the viewer is located in relation to the view of the model. * But, we can transform the XYZ coordinate and another XYZ coordinate along the * normal vector from model space to window space. Then, we can compare the transformed * Z-coordinates and if the Window Z along the normal vector is greater than Window Z * of the coordinate, the normal vector is pointing to the viewer (if NOT then backfacing). */ CaretAssert(m_transformEvent.get()); CaretAssert(m_transformEvent->isValid()); float windowXYZ[3]; const float length(25); float offsetXYZ[3] { xyz[0] + (normal[0] * length), xyz[1] + (normal[1] * length), xyz[2] + (normal[2] * length) }; m_transformEvent->transformPoint(xyz, windowXYZ); float windowOffsetXYZ[3]; m_transformEvent->transformPoint(offsetXYZ, windowOffsetXYZ); const float diff = windowOffsetXYZ[2] - windowXYZ[2]; return (diff < 0.0f); } /** * Draw an annotation text with surface tangent offset * * @param annotationFile * File containing the annotation. * @param text * Annotation text to draw. * @param surfaceExtentZ * Z-extent of the surface. * @param vertexXYZ, * Coordinate of the vertex. * @param vertexNormalXYZ * Normal vector of vertex. * @return * True if the annotation was drawn while NOT selecting annotations. */ bool BrainOpenGLAnnotationDrawingFixedPipeline::drawTextSurfaceTangentOffset(AnnotationFile* annotationFile, AnnotationText* text, const float surfaceExtentZ, const float vertexXYZ[3], const float vertexNormalXYZ[3]) { CaretAssert(annotationFile); CaretAssert(text); /* * Annotations with "DISPLAY_GROUP" propery may be turned on/off by user. */ DisplayPropertiesAnnotation* dpa = m_inputs->m_brain->getDisplayPropertiesAnnotation(); if (text->testProperty(Annotation::Property::DISPLAY_GROUP)) { if ( ! dpa->isDisplayTextAnnotations()) { return false; } } if (isBackFacing(vertexXYZ, vertexNormalXYZ)) { return false; } double bottomLeft[3]; double bottomRight[3]; double topRight[3]; double topLeft[3]; double underlineStart[3]; double underlineEnd[3]; m_brainOpenGLFixedPipeline->getTextRenderer()->getBoundsForTextInModelSpace(*text, m_surfaceViewScaling, surfaceExtentZ, m_textDrawingFlags, bottomLeft, bottomRight, topRight, topLeft, underlineStart, underlineEnd); bool textDrawnFlag = false; if (m_selectionModeFlag) { uint8_t selectionColorRGBA[4] = { 0, 0, 0, 0 }; getIdentificationColor(selectionColorRGBA); GraphicsPrimitiveV3fN3f primitive(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP, selectionColorRGBA); const double doubleNormalXYZ[3] { vertexNormalXYZ[0], vertexNormalXYZ[1], vertexNormalXYZ[2] }; primitive.addVertex(topLeft, doubleNormalXYZ); primitive.addVertex(bottomLeft, doubleNormalXYZ); primitive.addVertex(topRight, doubleNormalXYZ); primitive.addVertex(bottomRight, doubleNormalXYZ); GraphicsEngineDataOpenGL::draw(&primitive); m_selectionInfo.push_back(SelectionInfo(annotationFile, text, AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, vertexXYZ)); } else { glPushMatrix(); m_brainOpenGLFixedPipeline->getTextRenderer()->drawTextInModelSpace(*text, m_surfaceViewScaling, surfaceExtentZ, vertexNormalXYZ, m_textDrawingFlags); glPopMatrix(); textDrawnFlag = true; } if (text->isSelectedForEditing(m_inputs->m_windowIndex)) { glPushAttrib(GL_POLYGON_BIT | GL_LIGHTING_BIT); /* * So that text and background do not mix together * in the Z-buffer */ glEnable(GL_POLYGON_OFFSET_FILL); glEnable(GL_POLYGON_OFFSET_LINE); glEnable(GL_POLYGON_OFFSET_POINT); glPolygonOffset(-1.0, 1.0); glDisable(GL_LIGHTING); float floatBottomLeft[3]; float floatBottomRight[3]; float floatTopRight[3]; float floatTopLeft[3]; for (int32_t i = 0; i < 3; i++) { floatBottomLeft[i] = bottomLeft[i]; floatBottomRight[i] = bottomRight[i]; floatTopLeft[i] = topLeft[i]; floatTopRight[i] = topRight[i]; } drawAnnotationTwoDimSizingHandles(annotationFile, text, floatBottomLeft, floatBottomRight, floatTopRight, floatTopLeft, s_sizingHandleLineWidthInPixels, text->getRotationAngle()); glPopAttrib(); } return textDrawnFlag; } /** * Draw an annotation text. * * @param annotationFile * File containing the annotation. * @param text * Annotation text to draw. * @param surfaceDisplayed * Surface that is displayed (may be NULL). * @return * True if the annotation was drawn while NOT selecting annotations. */ bool BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFile, AnnotationText* text, const Surface* surfaceDisplayed) { CaretAssert(text); CaretAssert(text->getType() == AnnotationTypeEnum::TEXT); /* * Annotations with "DISPLAY_GROUP" propery may be turned on/off by user. */ DisplayPropertiesAnnotation* dpa = m_inputs->m_brain->getDisplayPropertiesAnnotation(); if (text->testProperty(Annotation::Property::DISPLAY_GROUP)) { if ( ! dpa->isDisplayTextAnnotations()) { return false; } } float annXYZ[3]; if ( ! getAnnotationDrawingSpaceCoordinate(text, text->getCoordinate(), surfaceDisplayed, annXYZ)) { return false; } float bottomLeft[3]; float bottomRight[3]; float topRight[3]; float topLeft[3]; /* * The fonts are sized using either the height * of the OpenGL viewport or the height of the * TAB viewport. During a single surface view, * they will be the same but different in a * surface montage view if there are two or more * rows. */ AnnotationPercentSizeText* percentSizeText = NULL; float savedFontPercentViewportHeight = -1.0; const bool modifiedStatus = text->isModified(); m_brainOpenGLFixedPipeline->getTextRenderer()->getBoundsForTextAtViewportCoords(*text, m_textDrawingFlags, annXYZ[0], annXYZ[1], annXYZ[2], m_modelSpaceViewport[2], m_modelSpaceViewport[3], bottomLeft, bottomRight, topRight, topLeft); const float selectionCenterXYZ[3] = { (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0f, (bottomLeft[1] + bottomRight[1] + topRight[1] + topLeft[1]) / 4.0f, (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0f }; const bool depthTestFlag = isDrawnWithDepthTesting(text, surfaceDisplayed); const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); float backgroundRGBA[4]; text->getBackgroundColorRGBA(backgroundRGBA); uint8_t foregroundRGBA[4]; text->getLineColorRGBA(foregroundRGBA); uint8_t textColorRGBA[4]; text->getTextColorRGBA(textColorRGBA); const bool drawTextFlag = (textColorRGBA[3] > 0); const bool drawBackgroundFlag = (backgroundRGBA[3] > 0.0f); const bool drawAnnotationFlag = (drawBackgroundFlag || drawTextFlag); bool drawnFlag = false; if (drawAnnotationFlag) { if (m_selectionModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); GraphicsShape::drawBoxFilledByteColor(bottomLeft, bottomRight, topRight, topLeft, selectionColorRGBA); m_selectionInfo.push_back(SelectionInfo(annotationFile, text, AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, selectionCenterXYZ)); } else { std::vector connectLineCoordinates; std::vector arrowCoordinates; getTextLineToBrainordinateLineCoordinates(text, surfaceDisplayed, bottomLeft, bottomRight, topRight, topLeft, connectLineCoordinates, arrowCoordinates); if ( ! connectLineCoordinates.empty()) { if (text->getLineWidthPercentage() <= 0.0) { convertObsoleteLineWidthPixelsToPercentageWidth(text); } GraphicsShape::drawLinesByteColor(connectLineCoordinates, textColorRGBA, GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, text->getLineWidthPercentage()); if ( ! arrowCoordinates.empty()) { GraphicsShape::drawLineStripMiterJoinByteColor(arrowCoordinates, textColorRGBA, GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, text->getLineWidthPercentage()); } } if (drawTextFlag) { if (debugFlag) { if (text->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::STEREOTAXIC) { AString msg("Drawing Text: " + text->getText() + " DepthTest=" + AString::fromBool(depthTestFlag)); const float* xyz = text->getCoordinate()->getXYZ(); msg.appendWithNewLine(" Stereotaxic: " + AString::fromNumbers(xyz, 3, ",")); msg.appendWithNewLine(" Drawing Space: " + AString::fromNumbers(annXYZ, 3, ",")); std::cout << qPrintable(msg) << std::endl; } } if (depthTestFlag) { m_brainOpenGLFixedPipeline->getTextRenderer()->drawTextAtViewportCoords(annXYZ[0], annXYZ[1], annXYZ[2], *text, m_textDrawingFlags); drawnFlag = true; } else { if (text->getText().isEmpty()) { /* * Text is empty when user is dragging mouse to create a * text region. In this case, use the bounds of the * two-dim shape. */ float bl[3]; float br[3]; float tr[3]; float tl[3]; getAnnotationTwoDimShapeBounds(text, annXYZ, bl, br, tr, tl); GraphicsShape::drawBoxOutlineByteColor(bl, br, tr, tl, foregroundRGBA, GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); } else { m_brainOpenGLFixedPipeline->getTextRenderer()->drawTextAtViewportCoords(annXYZ[0], annXYZ[1], *text, m_textDrawingFlags); drawnFlag = true; } } setDepthTestingStatus(depthTestFlag); } } if (text->isSelectedForEditing(m_inputs->m_windowIndex)) { drawAnnotationTwoDimSizingHandles(annotationFile, text, bottomLeft, bottomRight, topRight, topLeft, s_sizingHandleLineWidthInPixels, text->getRotationAngle()); /* * Cross can be used to show the text annotation's coordinate * to assist with placement of the annotation */ const bool drawCrossFlag = false; if (drawCrossFlag) { const float redRGBA[4] = { 1.0f, 0.0f, 0.0f, 1.0f }; std::unique_ptr crossShape = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_LINES, redRGBA)); crossShape->addVertex(annXYZ[0], annXYZ[1] - 10); crossShape->addVertex(annXYZ[0], annXYZ[1] + 10); crossShape->addVertex(annXYZ[0] - 10, annXYZ[1]); crossShape->addVertex(annXYZ[0] + 10, annXYZ[1]); crossShape->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); GraphicsEngineDataOpenGL::draw(crossShape.get()); } } } if (percentSizeText != NULL) { if (savedFontPercentViewportHeight > 0.0f) { percentSizeText->setFontPercentViewportSize(savedFontPercentViewportHeight); if ( ! modifiedStatus) { percentSizeText->clearModified(); } } } setDepthTestingStatus(savedDepthTestStatus); return drawnFlag; } /** * Draw an annotation image. * * @param annotationFile * File containing the annotation. * @param image * Annotation image to draw. * @param surfaceDisplayed * Surface that is displayed (may be NULL). * @return * True if the annotation was drawn while NOT selecting annotations. */ bool BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationFile, AnnotationImage* image, const Surface* surfaceDisplayed) { const uint8_t* imageRgbaBytes = image->getImageBytesRGBA(); const int32_t imageWidth = image->getImageWidth(); const int32_t imageHeight = image->getImageHeight(); if ((imageWidth > 0) && (imageHeight > 0) && (imageRgbaBytes != NULL)) { } else { CaretLogWarning("Attempt to draw invalid image annotation."); } float annXYZ[3]; if ( ! getAnnotationDrawingSpaceCoordinate(image, image->getCoordinate(), surfaceDisplayed, annXYZ)) { return false; } float bottomLeft[3]; float bottomRight[3]; float topRight[3]; float topLeft[3]; if ( ! getAnnotationTwoDimShapeBounds(image, annXYZ, bottomLeft, bottomRight, topRight, topLeft)) { return false; } const float selectionCenterXYZ[3] = { (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0f, (bottomLeft[1] + bottomRight[1] + topRight[1] + topLeft[1]) / 4.0f, (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0f }; const bool depthTestFlag = isDrawnWithDepthTesting(image, surfaceDisplayed); const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); const bool drawAnnotationFlag = true; float foregroundRGBA[4]; image->getLineColorRGBA(foregroundRGBA); const bool drawForegroundFlag = (foregroundRGBA[3] > 0.0); bool drawnFlag = false; if (drawAnnotationFlag) { if (m_selectionModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); GraphicsShape::drawBoxFilledByteColor(bottomLeft, bottomRight, topRight, topLeft, selectionColorRGBA); m_selectionInfo.push_back(SelectionInfo(annotationFile, image, AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, selectionCenterXYZ)); } else { if (debugFlag) { if (image->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::STEREOTAXIC) { AString msg("Drawing Image: DepthTest=" + AString::fromBool(depthTestFlag)); const float* xyz = image->getCoordinate()->getXYZ(); msg.appendWithNewLine(" Stereotaxic: " + AString::fromNumbers(xyz, 3, ",")); msg.appendWithNewLine(" Drawing Space: " + AString::fromNumbers(annXYZ, 3, ",")); std::cout << qPrintable(msg) << std::endl; } } image->setVertexBounds(bottomLeft, bottomRight, topRight, topLeft); GraphicsPrimitiveV3fT3f* primitive = image->getGraphicsPrimitive(); if (primitive != NULL) { if (primitive->isValid()) { GraphicsEngineDataOpenGL::draw(primitive); } drawnFlag = true; } if (drawForegroundFlag) { if (image->getLineWidthPercentage() <= 0.0f) { convertObsoleteLineWidthPixelsToPercentageWidth(image); } GraphicsShape::drawBoxOutlineFloatColor(bottomLeft, bottomRight, topRight, topLeft, foregroundRGBA, GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, image->getLineWidthPercentage()); } setDepthTestingStatus(depthTestFlag); } if (image->isSelectedForEditing(m_inputs->m_windowIndex)) { drawAnnotationTwoDimSizingHandles(annotationFile, image, bottomLeft, bottomRight, topRight, topLeft, s_sizingHandleLineWidthInPixels, image->getRotationAngle()); } } setDepthTestingStatus(savedDepthTestStatus); return drawnFlag; } /** * Draw an annotation image in surface tangent offset space * * @param annotationFile * File containing the annotation. * @param image * Image to draw. * @param surfaceExtentZ * Z-extent of the surface. * @param vertexXYZ * Coordinate of the vertex. * @return * True if the annotation was drawn while NOT selecting annotations. */ bool BrainOpenGLAnnotationDrawingFixedPipeline::drawImageSurfaceTangentOffset(AnnotationFile* annotationFile, AnnotationImage* image, const float surfaceExtentZ, const float vertexXYZ[3]) { CaretAssert(annotationFile); CaretAssert(image); CaretAssert(image->getType() == AnnotationTypeEnum::IMAGE); const float halfWidth = ((image->getWidth() / 100.0) * surfaceExtentZ) / 2.0; const float halfHeight = ((image->getHeight() / 100.0) * surfaceExtentZ) / 2.0; float bottomLeft[3] { -halfWidth, -halfHeight, 0.0f }; float bottomRight[3] { halfWidth, -halfHeight, 0.0f }; float topRight[3] { halfWidth, halfHeight, 0.0f }; float topLeft[3] { -halfWidth, halfHeight, 0.0f }; const float selectionCenterXYZ[3] = { vertexXYZ[0], vertexXYZ[1], vertexXYZ[2] }; float lineThickness = ((image->getLineWidthPercentage() / 100.0) * surfaceExtentZ); if (m_selectionModeFlag) { lineThickness = std::max(lineThickness, s_selectionLineMinimumPixelWidth); } uint8_t backgroundRGBA[4]; image->getBackgroundColorRGBA(backgroundRGBA); uint8_t foregroundRGBA[4]; image->getLineColorRGBA(foregroundRGBA); const bool drawForegroundFlag = (foregroundRGBA[3] > 0); const bool drawAnnotationFlag = true; bool drawnFlag = false; if (drawAnnotationFlag) { if (m_selectionModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); /* * When selecting draw only background if it is enabled * since it is opaque and prevents "behind" annotations * from being selected */ GraphicsShape::drawBoxFilledByteColor(bottomLeft, bottomRight, topRight, topLeft, selectionColorRGBA); m_selectionInfo.push_back(SelectionInfo(annotationFile, image, AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, selectionCenterXYZ)); } else { image->setVertexBounds(bottomLeft, bottomRight, topRight, topLeft); GraphicsPrimitiveV3fT3f* primitive = image->getGraphicsPrimitive(); if (primitive != NULL) { if (primitive->isValid()) { GraphicsEngineDataOpenGL::draw(primitive); } drawnFlag = true; } if (drawForegroundFlag) { glPolygonOffset(-1.0, -1.0); glEnable(GL_POLYGON_OFFSET_FILL); GraphicsShape::drawOutlineRectangleVerticesInMiddle(bottomLeft, bottomRight, topRight, topLeft, lineThickness, foregroundRGBA); drawnFlag = true; glDisable(GL_POLYGON_OFFSET_FILL); } } if (image->isSelectedForEditing(m_inputs->m_windowIndex)) { drawAnnotationTwoDimSizingHandles(annotationFile, image, bottomLeft, bottomRight, topRight, topLeft, s_sizingHandleLineWidthInPixels, image->getRotationAngle()); } } return drawnFlag; } /** * Create the coordinates for drawing a line with optional arrows at the end points. * * @param lineHeadXYZ * Start of the line * @param lineTailXYZ * End of the line * @param lineThickness * Thickness of the line that affects size of the optional arrow heads. * @param validStartArrow * Add an arrow at the start of the line * @param validEndArrow * Add an arrow at the end of the line * @param lineCoordinatesOut * Output containing coordinates for drawing the line * @param startArrowCoordinatesOut * Output containing coordinates for drawing the line's start arrow * @param endArrowCoordinatesOut * Output containing coordinates for drawing the line's end arrow */ void BrainOpenGLAnnotationDrawingFixedPipeline::createLineCoordinates(const float lineHeadXYZ[3], const float lineTailXYZ[3], const float lineThicknessPixels, const bool validStartArrow, const bool validEndArrow, std::vector& lineCoordinatesOut, std::vector& startArrowCoordinatesOut, std::vector& endArrowCoordinatesOut) const { lineCoordinatesOut.clear(); startArrowCoordinatesOut.clear(); endArrowCoordinatesOut.clear(); /* * Length of arrow's tips is function of line thickness */ const float lineLength = MathFunctions::distance3D(lineHeadXYZ, lineTailXYZ); const float thirdLineLength = lineLength / 3.0f; /* * Vector from Tail to Head of line */ float tailToHeadUnitVector[3]; MathFunctions::createUnitVector(lineTailXYZ, lineHeadXYZ, tailToHeadUnitVector); /* * Create a perpendicular vector by swapping first two elements * and negating the second element. */ const float leftToRightUnitVector[3] = { tailToHeadUnitVector[1], -tailToHeadUnitVector[0], tailToHeadUnitVector[2] }; /* * Left to right vector moves the arrows tips away from the line * in a direction perpendicular to the line */ const float awayFromLineScale = 3.0f; const float awayFromLineDistance = lineThicknessPixels * awayFromLineScale; const float leftToRightVector[3] = { leftToRightUnitVector[0] * awayFromLineDistance, leftToRightUnitVector[1] * awayFromLineDistance, leftToRightUnitVector[2] }; /* * Away from tail vector moves the arrows tips away from the tail * of the line in a direction along the line */ const float awayFromTipScale = 3.0f; const float alongLineDistanceFromTip = std::min((lineThicknessPixels * awayFromTipScale), (thirdLineLength)); const float awayFromTailVector[3] = { (tailToHeadUnitVector[0] * alongLineDistanceFromTip), (tailToHeadUnitVector[1] * alongLineDistanceFromTip), (tailToHeadUnitVector[2]) }; if (validEndArrow) { const float tailTipRightXYZ[3] = { lineTailXYZ[0] + leftToRightVector[0] + awayFromTailVector[0], lineTailXYZ[1] + leftToRightVector[1] + awayFromTailVector[1], lineTailXYZ[2] + leftToRightVector[2] + awayFromTailVector[2] }; const float tailTipLeftXYZ[3] = { lineTailXYZ[0] - leftToRightVector[0] + awayFromTailVector[0], lineTailXYZ[1] - leftToRightVector[1] + awayFromTailVector[1], lineTailXYZ[2] + leftToRightVector[2] + awayFromTailVector[2] }; endArrowCoordinatesOut.insert(endArrowCoordinatesOut.end(), tailTipLeftXYZ, tailTipLeftXYZ + 3); endArrowCoordinatesOut.insert(endArrowCoordinatesOut.end(), lineTailXYZ, lineTailXYZ + 3); endArrowCoordinatesOut.insert(endArrowCoordinatesOut.end(), tailTipRightXYZ, tailTipRightXYZ + 3); } if (validStartArrow) { const float headTipRightXYZ[3] = { lineHeadXYZ[0] + leftToRightVector[0] - awayFromTailVector[0], lineHeadXYZ[1] + leftToRightVector[1] - awayFromTailVector[1], lineHeadXYZ[2] + leftToRightVector[2] - awayFromTailVector[2] }; const float headTipLeftXYZ[3] = { lineHeadXYZ[0] - leftToRightVector[0] - awayFromTailVector[0], lineHeadXYZ[1] - leftToRightVector[1] - awayFromTailVector[1], lineHeadXYZ[2] + leftToRightVector[2] - awayFromTailVector[2] }; startArrowCoordinatesOut.insert(startArrowCoordinatesOut.end(), headTipLeftXYZ, headTipLeftXYZ + 3); startArrowCoordinatesOut.insert(startArrowCoordinatesOut.end(), lineHeadXYZ, lineHeadXYZ + 3); startArrowCoordinatesOut.insert(startArrowCoordinatesOut.end(), headTipRightXYZ, headTipRightXYZ + 3); } lineCoordinatesOut.insert(lineCoordinatesOut.end(), lineHeadXYZ, lineHeadXYZ + 3); lineCoordinatesOut.insert(lineCoordinatesOut.end(), lineTailXYZ, lineTailXYZ + 3); } /** * Draw an annotation line. * * @param annotationFile * File containing the annotation. * @param line * Annotation line to draw. * @param surfaceDisplayed * Surface that is displayed (may be NULL). * @return * True if the annotation was drawn while NOT selecting annotations. */ bool BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFile, AnnotationLine* line, const Surface* surfaceDisplayed) { CaretAssert(line); CaretAssert(line->getType() == AnnotationTypeEnum::LINE); float lineHeadXYZ[3]; float lineTailXYZ[3]; if ( ! getAnnotationDrawingSpaceCoordinate(line, line->getStartCoordinate(), surfaceDisplayed, lineHeadXYZ)) { return false; } if ( ! getAnnotationDrawingSpaceCoordinate(line, line->getEndCoordinate(), surfaceDisplayed, lineTailXYZ)) { return false; } if (line->getLineWidthPercentage() <= 0.0) { convertObsoleteLineWidthPixelsToPercentageWidth(line); } const float lineWidth = getLineWidthFromPercentageHeight(line->getLineWidthPercentage()); const float selectionCenterXYZ[3] = { (lineHeadXYZ[0] + lineTailXYZ[0]) / 2.0f, (lineHeadXYZ[1] + lineTailXYZ[1]) / 2.0f, (lineHeadXYZ[2] + lineTailXYZ[2]) / 2.0f }; const bool depthTestFlag = isDrawnWithDepthTesting(line, surfaceDisplayed); const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); std::vector lineCoordinates; std::vector startArrowCoordinates; std::vector endArrowCoordinates; createLineCoordinates(lineHeadXYZ, lineTailXYZ, lineWidth, line->isDisplayStartArrow(), line->isDisplayEndArrow(), lineCoordinates, startArrowCoordinates, endArrowCoordinates); uint8_t foregroundRGBA[4]; line->getLineColorRGBA(foregroundRGBA); const bool drawForegroundFlag = (foregroundRGBA[3] > 0.0f); bool drawnFlag = false; if (drawForegroundFlag) { if (m_selectionModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); const float percentHeight = getLineWidthPercentageInSelectionMode(line); GraphicsShape::drawLinesByteColor(lineCoordinates, selectionColorRGBA, GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, percentHeight); if ( ! startArrowCoordinates.empty()) { GraphicsShape::drawLineStripMiterJoinByteColor(startArrowCoordinates, selectionColorRGBA, GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); } if ( ! endArrowCoordinates.empty()) { GraphicsShape::drawLineStripMiterJoinByteColor(endArrowCoordinates, selectionColorRGBA, GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); } m_selectionInfo.push_back(SelectionInfo(annotationFile, line, AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, selectionCenterXYZ)); } else { if (drawForegroundFlag) { GraphicsShape::drawLinesByteColor(lineCoordinates, foregroundRGBA, GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); if ( ! startArrowCoordinates.empty()) { GraphicsShape::drawLineStripMiterJoinByteColor(startArrowCoordinates, foregroundRGBA, GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); } if ( ! endArrowCoordinates.empty()) { GraphicsShape::drawLineStripMiterJoinByteColor(endArrowCoordinates, foregroundRGBA, GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, line->getLineWidthPercentage()); } drawnFlag = true; } } if (line->isSelectedForEditing(m_inputs->m_windowIndex)) { drawAnnotationOneDimSizingHandles(annotationFile, line, lineHeadXYZ, lineTailXYZ, s_sizingHandleLineWidthInPixels); } } setDepthTestingStatus(savedDepthTestStatus); return drawnFlag; } /** * Draw an annotation line that is in surface space with tangent offset. * * @param annotationFile * File containing the annotation. * @param line * Annotation line to draw. * @param surfaceDisplayed * Surface that is displayed (may be NULL). * @return * True if the annotation was drawn while NOT selecting annotations. */ bool BrainOpenGLAnnotationDrawingFixedPipeline::drawLineSurfaceTextureOffset(AnnotationFile* annotationFile, AnnotationLine* line, const Surface* surfaceDisplayed, const float surfaceExtentZ) { CaretAssert(line); CaretAssert(line->getType() == AnnotationTypeEnum::LINE); StructureEnum::Enum structureOne(StructureEnum::INVALID); StructureEnum::Enum structureTwo(StructureEnum::INVALID); int32_t numberOfVerticesOne(0); int32_t numberOfVerticesTwo(0); int32_t vertexIndexOne(-1); int32_t vertexIndexTwo(-1); float offsetLengthOne(0.0f); float offsetLengthTwo(0.0f); AnnotationSurfaceOffsetVectorTypeEnum::Enum surfaceOffsetVectorOne(AnnotationSurfaceOffsetVectorTypeEnum::TANGENT); AnnotationSurfaceOffsetVectorTypeEnum::Enum surfaceOffsetVectorTwo(AnnotationSurfaceOffsetVectorTypeEnum::TANGENT); line->getStartCoordinate()->getSurfaceSpace(structureOne, numberOfVerticesOne, vertexIndexOne, offsetLengthOne, surfaceOffsetVectorOne); line->getEndCoordinate()->getSurfaceSpace(structureTwo, numberOfVerticesTwo, vertexIndexTwo, offsetLengthTwo, surfaceOffsetVectorTwo); if ((surfaceDisplayed->getStructure() != structureOne) || (surfaceDisplayed->getStructure() != structureTwo) || (surfaceDisplayed->getNumberOfNodes() != numberOfVerticesOne) || (surfaceDisplayed->getNumberOfNodes() != numberOfVerticesTwo) || (vertexIndexOne < 0) || (vertexIndexTwo < 0)) { return false; } float lineHeadXYZ[3]; float lineTailXYZ[3]; surfaceDisplayed->getCoordinate(vertexIndexOne, lineHeadXYZ); surfaceDisplayed->getCoordinate(vertexIndexTwo, lineTailXYZ); float offsetVectorOne[3]; float offsetVectorTwo[3]; surfaceDisplayed->getNormalVector(vertexIndexOne, offsetVectorOne); surfaceDisplayed->getNormalVector(vertexIndexTwo, offsetVectorTwo); for (int32_t i = 0; i < 3; i++) { lineHeadXYZ[i] += (offsetVectorOne[i] * offsetLengthOne); lineTailXYZ[i] += (offsetVectorTwo[i] * offsetLengthTwo); } const float selectionCenterXYZ[3] = { (lineHeadXYZ[0] + lineTailXYZ[0]) / 2.0f, (lineHeadXYZ[1] + lineTailXYZ[1]) / 2.0f, (lineHeadXYZ[2] + lineTailXYZ[2]) / 2.0f }; if (line->getLineWidthPercentage() <= 0.0) { convertObsoleteLineWidthPixelsToPercentageWidth(line); } float lineThickness = ((line->getLineWidthPercentage() / 100.0) * surfaceExtentZ); lineThickness *= m_surfaceViewScaling; if (m_selectionModeFlag) { lineThickness = std::max(lineThickness, s_selectionLineMinimumPixelWidth); } lineThickness = GraphicsUtilitiesOpenGL::convertMillimetersToPixels(lineThickness); bool drawnFlag = false; std::vector lineCoordinates; std::vector startArrowCoordinates; std::vector endArrowCoordinates; createLineCoordinates(lineHeadXYZ, lineTailXYZ, lineThickness, line->isDisplayStartArrow(), line->isDisplayEndArrow(), lineCoordinates, startArrowCoordinates, endArrowCoordinates); uint8_t foregroundRGBA[4]; line->getLineColorRGBA(foregroundRGBA); const bool drawForegroundFlag = (foregroundRGBA[3] > 0.0f); if (drawForegroundFlag) { if (m_selectionModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); GraphicsShape::drawLinesByteColor(lineCoordinates, selectionColorRGBA, GraphicsPrimitive::LineWidthType::PIXELS, lineThickness); // if ( ! startArrowCoordinates.empty()) { // GraphicsShape::drawLineStripMiterJoinByteColor(startArrowCoordinates, // selectionColorRGBA, // GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, // lineThickness); // } // if ( ! endArrowCoordinates.empty()) { // GraphicsShape::drawLineStripMiterJoinByteColor(endArrowCoordinates, // selectionColorRGBA, // GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, // lineThickness); // } m_selectionInfo.push_back(SelectionInfo(annotationFile, line, AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, selectionCenterXYZ)); } else { if (drawForegroundFlag) { // float floatRGBA[4]; // line->getLineColorRGBA(floatRGBA); // m_brainOpenGLFixedPipeline->drawCylinder(floatRGBA, // lineHeadXYZ, // lineTailXYZ, // lineThickness / 2); GraphicsShape::drawLinesByteColor(lineCoordinates, foregroundRGBA, GraphicsPrimitive::LineWidthType::PIXELS, lineThickness); // if ( ! startArrowCoordinates.empty()) { // if (startArrowCoordinates.size() == 9) { // m_brainOpenGLFixedPipeline->drawCylinder(floatRGBA, // &startArrowCoordinates[0], // &startArrowCoordinates[3], // lineThickness / 2); // m_brainOpenGLFixedPipeline->drawCylinder(floatRGBA, // &startArrowCoordinates[3], // &startArrowCoordinates[6], // lineThickness / 2); // } // else { // GraphicsShape::drawLineStripMiterJoinByteColor(startArrowCoordinates, // foregroundRGBA, // GraphicsPrimitive::LineWidthType::PIXELS, // lineThickness); // } // } // if ( ! endArrowCoordinates.empty()) { // GraphicsShape::drawLineStripMiterJoinByteColor(endArrowCoordinates, // foregroundRGBA, // GraphicsPrimitive::LineWidthType::PIXELS, // lineThickness); // } drawnFlag = true; } } if (line->isSelectedForEditing(m_inputs->m_windowIndex)) { const float minPixelSize = 30.0; const float minSizeMM = (GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(minPixelSize) * m_surfaceViewScaling); const float handleThickness = std::max(minSizeMM, lineThickness * 2.0f); drawAnnotationOneDimSizingHandles(annotationFile, line, lineHeadXYZ, lineTailXYZ, handleThickness); //lineThickness * 2.0); //s_sizingHandleLineWidthInPixels); } } return drawnFlag; } /** * When lines are very thin, they can be difficult to select. This method will * return the line thickness percentage, adjusted so that is thick enough that * the user will be able to select the annotation. * * @param * Annotation drawn as line * @return * Percentage thickness for drawing that may be increased to ensure that the annotation is selectable. */ float BrainOpenGLAnnotationDrawingFixedPipeline::getLineWidthPercentageInSelectionMode(const Annotation* annotation) const { CaretAssert(annotation); const float minPercentHeight = GraphicsUtilitiesOpenGL::convertPixelsToPercentageOfViewportHeight(s_selectionLineMinimumPixelWidth); float percentHeight = annotation->getLineWidthPercentage(); if (percentHeight < minPercentHeight) { percentHeight = minPercentHeight; } return percentHeight; } /** * Draw a sizing handle at the given coordinate. * * @param handleType * Type of sizing handle. * @param annotationFile * File containing the annotation. * @param annotation * Annotation to draw. * @param xyz * Center of square. * @param halfWidthHeight * Half Width/height of square. * @param rotationAngle * Rotation angle for the sizing handle. */ void BrainOpenGLAnnotationDrawingFixedPipeline::drawSizingHandle(const AnnotationSizingHandleTypeEnum::Enum handleType, AnnotationFile* annotationFile, Annotation* annotation, const float xyz[3], const float halfWidthHeight, const float rotationAngle) { glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); if (rotationAngle != 0.0) { glRotatef(-rotationAngle, 0.0, 0.0, 1.0); } const float bottomLeft[3] = { -halfWidthHeight, -halfWidthHeight, 0.0f }; const float bottomRight[3] = { halfWidthHeight, -halfWidthHeight, 0.0f }; const float topRight[3] = { halfWidthHeight, halfWidthHeight, 0.0f }; const float topLeft[3] = { -halfWidthHeight, halfWidthHeight, 0.0f }; bool drawFilledCircleFlag = false; bool drawOutlineCircleFlag = false; bool drawSquareFlag = false; bool drawSphereFlag = false; switch (handleType) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: drawSquareFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: drawFilledCircleFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: drawFilledCircleFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: drawSquareFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: drawSquareFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: drawSquareFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: drawFilledCircleFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: drawFilledCircleFlag = true; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: if (annotation->isInSurfaceSpaceWithTangentOffset()) { drawSphereFlag = true; } else { drawFilledCircleFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: if (annotation->isInSurfaceSpaceWithTangentOffset()) { drawSphereFlag = true; } else { drawFilledCircleFlag = true; } break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: drawOutlineCircleFlag = true; break; } if (m_selectionModeFlag) { uint8_t identificationRGBA[4]; getIdentificationColor(identificationRGBA); GraphicsShape::drawBoxFilledByteColor(bottomLeft, bottomRight, topRight, topLeft, identificationRGBA); m_selectionInfo.push_back(SelectionInfo(annotationFile, annotation, handleType, xyz)); } else { if (drawFilledCircleFlag) { GraphicsShape::drawCircleFilled(NULL, m_selectionBoxRGBA, halfWidthHeight * 2); } else if (drawSquareFlag) { GraphicsShape::drawBoxFilledByteColor(bottomLeft, bottomRight, topRight, topLeft, m_selectionBoxRGBA); } else if (drawOutlineCircleFlag) { const float diameter = halfWidthHeight; glPushMatrix(); glScaled(diameter, diameter, 1.0f); GraphicsShape::drawRing(NULL, m_selectionBoxRGBA, 0.7f, 1.0f); glPopMatrix(); } else if (drawSphereFlag) { float zeros[3] { 0.0f, 0.0f, 0.0f }; GraphicsShape::drawSphereByteColor(zeros, m_selectionBoxRGBA, halfWidthHeight); } } glPopMatrix(); } /** * Draw sizing handles around a one-dimensional annotation. * * @param annotationFile * File containing the annotation. * @param annotation * Annotation to draw. * @param firstPoint * Top right corner of annotation. * @param secondPoint * Top left corner of annotation. * @param lineThickness * Thickness of line (when enabled). */ void BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationOneDimSizingHandles(AnnotationFile* annotationFile, Annotation* annotation, const float firstPoint[3], const float secondPoint[3], const float lineThickness) { if ( ! m_inputs->m_annotationUserInputModeFlag) { return; } CaretAssert(annotation); float lengthVector[3]; MathFunctions::subtractVectors(secondPoint, firstPoint, lengthVector); MathFunctions::normalizeVector(lengthVector); const float dx = secondPoint[0] - firstPoint[0]; const float dy = secondPoint[1] - firstPoint[1]; const bool tangentSurfaceOffsetFlag = annotation->isInSurfaceSpaceWithTangentOffset(); float cornerSquareSize = 3.0 + lineThickness; if (tangentSurfaceOffsetFlag) { cornerSquareSize = lineThickness;// * 4.0; cornerSquareSize = GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(cornerSquareSize); } float directionVector[3] { 0.0f, 0.0f, 0.0f }; if ( ! tangentSurfaceOffsetFlag) { directionVector[0] = lengthVector[0] * cornerSquareSize; directionVector[1] = lengthVector[1] * cornerSquareSize; directionVector[2] = 0.0; } const float firstPointSymbolXYZ[3] = { firstPoint[0] - directionVector[0], firstPoint[1] - directionVector[1], firstPoint[2] - directionVector[2] }; const float secondPointSymbolXYZ[3] = { secondPoint[0] + directionVector[0], secondPoint[1] + directionVector[1], secondPoint[2] + directionVector[2] }; float rotationAngle = 0.0; if ((dy != 0.0) && (dx != 0.0)) { const float angleRadians = std::atan2(dx, dy); rotationAngle = MathFunctions::toDegrees(angleRadians); } if (annotation->isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START)) { /* * Symbol for first coordinate is a little bigger */ float startSquareSize = cornerSquareSize + 2.0; if (tangentSurfaceOffsetFlag) { startSquareSize = cornerSquareSize;// * 1.5; } drawSizingHandle(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START, annotationFile, annotation, firstPointSymbolXYZ, startSquareSize, rotationAngle); } if (annotation->isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END)) { drawSizingHandle(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END, annotationFile, annotation, secondPointSymbolXYZ, cornerSquareSize, rotationAngle); } if (annotation->isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION)) { const float midPointXYZ[3] = { (firstPoint[0] + secondPoint[0]) / 2.0f, (firstPoint[1] + secondPoint[1]) / 2.0f, (firstPoint[2] + secondPoint[2]) / 2.0f }; drawSizingHandle(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION, annotationFile, annotation, midPointXYZ, cornerSquareSize, rotationAngle); } } /** * Draw sizing handles around a two-dimensional annotation. * * @param annotationFile * File containing the annotation. * @param annotation * Annotation to draw. * @param bottomLeft * Bottom left corner of annotation. * @param bottomRight * Bottom right corner of annotation. * @param topRight * Top right corner of annotation. * @param topLeft * Top left corner of annotation. * @param lineThickness * Thickness of line (when enabled). * @param rotationAngle * Rotation of the annotation. */ void BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationTwoDimSizingHandles(AnnotationFile* annotationFile, Annotation* annotation, const float bottomLeft[3], const float bottomRight[3], const float topRight[3], const float topLeft[3], const float lineThickness, const float rotationAngle) { if ( ! m_inputs->m_annotationUserInputModeFlag) { return; } CaretAssert(annotation); AnnotationText* textAnn = dynamic_cast(annotation); const bool modelSpaceTangentTextFlag = annotation->isInSurfaceSpaceWithTangentOffset(); float heightVector[3]; MathFunctions::subtractVectors(topLeft, bottomLeft, heightVector); MathFunctions::normalizeVector(heightVector); float innerSpacing = 2.0f + (lineThickness / 2.0f); if (modelSpaceTangentTextFlag) { innerSpacing = GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(innerSpacing); } float handleTopLeft[3]; float handleTopRight[3]; float handleBottomRight[3]; float handleBottomLeft[3]; for (int32_t i = 0; i < 3; i++) { handleTopLeft[i] = topLeft[i]; handleTopRight[i] = topRight[i]; handleBottomRight[i] = bottomRight[i]; handleBottomLeft[i] = bottomLeft[i]; } MathFunctions::expandBox(handleBottomLeft, handleBottomRight, handleTopRight, handleTopLeft, innerSpacing, innerSpacing); if (! m_selectionModeFlag) { GraphicsShape::drawBoxOutlineByteColor(handleBottomLeft, handleBottomRight, handleTopRight, handleTopLeft, m_selectionBoxRGBA, GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); } const float handleLeft[3] = { (handleBottomLeft[0] + handleTopLeft[0]) / 2.0f, (handleBottomLeft[1] + handleTopLeft[1]) / 2.0f, (handleBottomLeft[2] + handleTopLeft[2]) / 2.0f, }; const float handleRight[3] = { (handleBottomRight[0] + handleTopRight[0]) / 2.0f, (handleBottomRight[1] + handleTopRight[1]) / 2.0f, (handleBottomRight[2] + handleTopRight[2]) / 2.0f, }; const float handleBottom[3] = { (handleBottomLeft[0] + handleBottomRight[0]) / 2.0f, (handleBottomLeft[1] + handleBottomRight[1]) / 2.0f, (handleBottomLeft[2] + handleBottomRight[2]) / 2.0f, }; const float handleTop[3] = { (handleTopLeft[0] + handleTopRight[0]) / 2.0f, (handleTopLeft[1] + handleTopRight[1]) / 2.0f, (handleTopLeft[2] + handleTopRight[2]) / 2.0f, }; float sizeHandleSize = 5.0; if (modelSpaceTangentTextFlag) { sizeHandleSize = GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(sizeHandleSize); } if (annotation->isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT)) { drawSizingHandle(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT, annotationFile, annotation, handleBottomLeft, sizeHandleSize, rotationAngle); } if (annotation->isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT)) { drawSizingHandle(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT, annotationFile, annotation, handleBottomRight, sizeHandleSize, rotationAngle); } if (annotation->isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT)) { drawSizingHandle(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT, annotationFile, annotation, handleTopRight, sizeHandleSize, rotationAngle); } if (annotation->isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT)) { drawSizingHandle(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT, annotationFile, annotation, handleTopLeft, sizeHandleSize, rotationAngle); } if (annotation->isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP)) { drawSizingHandle(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP, annotationFile, annotation, handleTop, sizeHandleSize, rotationAngle); } if (annotation->isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM)) { drawSizingHandle(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM, annotationFile, annotation, handleBottom, sizeHandleSize, rotationAngle); } if (annotation->isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT)) { drawSizingHandle(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT, annotationFile, annotation, handleRight, sizeHandleSize, rotationAngle); } if (annotation->isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT)) { drawSizingHandle(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT, annotationFile, annotation, handleLeft, sizeHandleSize, rotationAngle); } if (annotation->isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION)) { float handleOffset[3] = { handleTop[0], handleTop[1], handleTop[2] }; if (textAnn != NULL) { /* * The rotation point of a text annotation * is adjusted for the horizontal alignment. */ switch (textAnn->getHorizontalAlignment()) { case AnnotationTextAlignHorizontalEnum::CENTER: break; case AnnotationTextAlignHorizontalEnum::LEFT: handleOffset[0] = handleTopLeft[0]; handleOffset[1] = handleTopLeft[1]; handleOffset[2] = handleTopLeft[2]; break; case AnnotationTextAlignHorizontalEnum::RIGHT: handleOffset[0] = handleTopRight[0]; handleOffset[1] = handleTopRight[1]; handleOffset[2] = handleTopRight[2]; break; } } const float rotationOffset = sizeHandleSize * 3.0; const float handleRotation[3] = { handleOffset[0] + (rotationOffset * heightVector[0]), handleOffset[1] + (rotationOffset * heightVector[1]), handleOffset[2] + (rotationOffset * heightVector[2]) }; const float handleRotationLineEnd[3] = { handleOffset[0] + (rotationOffset * 0.75f * heightVector[0] ), handleOffset[1] + (rotationOffset * 0.75f * heightVector[1]), handleOffset[2] + (rotationOffset * 0.75f * heightVector[2]) }; /* * Rotation handle and line connecting rotation handle to selection box */ std::vector coords; coords.insert(coords.end(), handleRotationLineEnd, handleRotationLineEnd + 3); coords.insert(coords.end(), handleOffset, handleOffset + 3); GraphicsShape::drawLinesByteColor(coords, m_selectionBoxRGBA, GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); drawSizingHandle(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION, annotationFile, annotation, handleRotation, sizeHandleSize, rotationAngle); } } /** * Set the color for drawing the selection box and handles. */ void BrainOpenGLAnnotationDrawingFixedPipeline::setSelectionBoxColor() { /* * Use the foreground color but reduce the intensity and saturation. */ m_selectionBoxRGBA[0] = m_brainOpenGLFixedPipeline->m_foregroundColorByte[0]; m_selectionBoxRGBA[1] = m_brainOpenGLFixedPipeline->m_foregroundColorByte[1]; m_selectionBoxRGBA[2] = m_brainOpenGLFixedPipeline->m_foregroundColorByte[2]; m_selectionBoxRGBA[3] = m_brainOpenGLFixedPipeline->m_foregroundColorByte[3]; QColor color(m_selectionBoxRGBA[0], m_selectionBoxRGBA[1], m_selectionBoxRGBA[2], m_selectionBoxRGBA[3]); qreal hue = 0.0; qreal saturation = 0.0; qreal value = 0.0; color.getHsvF(&hue, &saturation, &value); saturation *= 0.8; value *= 0.8; color.setHsvF(hue, saturation, value); m_selectionBoxRGBA[0] = static_cast(color.red()); m_selectionBoxRGBA[1] = static_cast(color.green()); m_selectionBoxRGBA[2] = static_cast(color.blue()); } /** * Is the annotation drawn with depth testing enabled (based upon coordinate space)? * * @param annotation * Annotation that will be drawn. * @param surface * Surface that is being drawn. * @return * True if the annotation is drawn with depth testing, else false. */ bool BrainOpenGLAnnotationDrawingFixedPipeline::isDrawnWithDepthTesting(const Annotation* annotation, const Surface* surface) { bool testFlatSurfaceFlag = false; switch (annotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: testFlatSurfaceFlag = true; break; case AnnotationCoordinateSpaceEnum::SURFACE: testFlatSurfaceFlag = true; break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } bool depthTestFlag = true; if (testFlatSurfaceFlag) { if (surface != NULL) { if (surface->getSurfaceType() == SurfaceTypeEnum::FLAT) { depthTestFlag = false; } } } return depthTestFlag; } /** * Set the depth testing to the given status. * * @param newDepthTestingStatus * New status for depth testing. * @return * Depth testing status PRIOR to applying the new depth testing status. */ bool BrainOpenGLAnnotationDrawingFixedPipeline::setDepthTestingStatus(const bool newDepthTestingStatus) { GLboolean savedStatus = GL_FALSE; glGetBooleanv(GL_DEPTH_TEST, &savedStatus); if (newDepthTestingStatus) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); return (savedStatus == GL_TRUE); } /** * Convert a percentage height to a line width in pixels * * @param percentageHeight * Percentage of viewport height. * @return * Line width in pixels clamped to valid range */ float BrainOpenGLAnnotationDrawingFixedPipeline::getLineWidthFromPercentageHeight(const float percentageHeight) const { float widthPixels = (percentageHeight / 100.0f) * m_modelSpaceViewport[3]; if (widthPixels < m_lineWidthMinimum) { widthPixels = m_lineWidthMinimum; } return widthPixels; } /** * Convert the annotation's obsolete line width that was in pixels to a percentage of viewport height. * Prior to late July, 2017, a line was specified in pixels. * * First, the annotation's percentage width is examined. If it is valid (greater than zero), then * no conversion is needed. Otherwise, use the viewport height to convert the pixel width to a * percentage and set the annotation's percentage line width. * * @param annotation * The annotation. */ void BrainOpenGLAnnotationDrawingFixedPipeline::convertObsoleteLineWidthPixelsToPercentageWidth(const Annotation* annotation) const { annotation->convertObsoleteLineWidthPixelsToPercentageWidth(m_modelSpaceViewport[3]); } connectome-workbench-1.4.2/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h000066400000000000000000000446531360521144700277570ustar00rootroot00000000000000#ifndef __BRAIN_OPEN_G_L_ANNOTATION_DRAWING_FIXED_PIPELINE_H__ #define __BRAIN_OPEN_G_L_ANNOTATION_DRAWING_FIXED_PIPELINE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AnnotationCoordinateSpaceEnum.h" #include "AnnotationSizingHandleTypeEnum.h" #include "AnnotationSurfaceOffsetVectorTypeEnum.h" #include "BrainOpenGLFixedPipeline.h" #include "BrainOpenGLTextRenderInterface.h" #include "CaretObject.h" #include "CaretOpenGLInclude.h" #include "Plane.h" #include "SpacerTabIndex.h" namespace caret { class Annotation; class AnnotationBox; class AnnotationColorBar; class AnnotationCoordinate; class AnnotationFile; class AnnotationImage; class AnnotationLine; class AnnotationOneDimensionalShape; class AnnotationOval; class AnnotationText; class AnnotationTwoDimensionalShape; class Brain; class BrainOpenGLFixedPipeline; class EventOpenGLObjectToWindowTransform; class Surface; class BrainOpenGLAnnotationDrawingFixedPipeline : public CaretObject { public: class Inputs { public: enum WindowDrawingMode { WINDOW_DRAWING_NO, WINDOW_DRAWING_YES }; Inputs(Brain* brain, const BrainOpenGLFixedPipeline::Mode drawingMode, const float centerToEyeDistance, const int32_t windowIndex, const int32_t tabIndex, const SpacerTabIndex &spacerTabIndex, const WindowDrawingMode windowDrawingMode, const bool annotationUserInputModeFlag) : m_brain(brain), m_drawingMode(drawingMode), m_centerToEyeDistance(centerToEyeDistance), m_windowIndex(windowIndex), m_tabIndex(tabIndex), m_spacerTabIndex(spacerTabIndex), m_windowDrawingMode(windowDrawingMode), m_annotationUserInputModeFlag(annotationUserInputModeFlag) { } Brain* m_brain; const BrainOpenGLFixedPipeline::Mode m_drawingMode; const float m_centerToEyeDistance; const int32_t m_windowIndex; const int32_t m_tabIndex; const SpacerTabIndex m_spacerTabIndex; const WindowDrawingMode m_windowDrawingMode; const bool m_annotationUserInputModeFlag; }; BrainOpenGLAnnotationDrawingFixedPipeline(BrainOpenGLFixedPipeline* brainOpenGLFixedPipeline); virtual ~BrainOpenGLAnnotationDrawingFixedPipeline(); void drawAnnotations(Inputs* inputs, const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, std::vector& notInFileAnnotations, const Surface* surfaceDisplayed, const float surfaceViewScaling); void drawModelSpaceAnnotationsOnVolumeSlice(Inputs* inputs, const Plane& plane, const float sliceThickness); // ADD_NEW_METHODS_HERE virtual AString toString() const; private: class SelectionInfo { public: SelectionInfo(AnnotationFile* annotationFile, Annotation* annotation, AnnotationSizingHandleTypeEnum::Enum sizingHandle, const float windowXYZ[3]) { m_annotationFile = annotationFile; m_annotation = annotation; m_sizingHandle = sizingHandle; m_windowXYZ[0] = windowXYZ[0]; m_windowXYZ[1] = windowXYZ[1]; m_windowXYZ[2] = windowXYZ[2]; } AnnotationFile* m_annotationFile; Annotation* m_annotation; AnnotationSizingHandleTypeEnum::Enum m_sizingHandle; double m_windowXYZ[3]; }; class ColorBarLine { public: ColorBarLine(const std::vector& lineCoords, const float rgba[4]) { m_lineCoords = lineCoords; m_rgba[0] = rgba[0]; m_rgba[1] = rgba[1]; m_rgba[2] = rgba[2]; m_rgba[3] = rgba[3]; } std::vector m_lineCoords; float m_rgba[4]; }; /** * Used to save viewport, model view, projection */ class TransformationInfo { public: void save(); void restore(); GLint m_viewport[4]; GLdouble m_modelViewMatrix[16]; GLdouble m_projectionMatrix[16]; bool m_valid = false; }; BrainOpenGLAnnotationDrawingFixedPipeline(const BrainOpenGLAnnotationDrawingFixedPipeline&); BrainOpenGLAnnotationDrawingFixedPipeline& operator=(const BrainOpenGLAnnotationDrawingFixedPipeline&); void drawAnnotationsInternal(const AnnotationCoordinateSpaceEnum::Enum drawingCoordinateSpace, std::vector& colorBars, std::vector& viewportAnnotations, const Surface* surfaceDisplayed, const float sliceThickness); bool getAnnotationDrawingSpaceCoordinate(const Annotation* annotation, const AnnotationCoordinate* coordinate, const Surface* surfaceDisplayed, float xyzOut[3]) const; bool getAnnotationTwoDimShapeBounds(const AnnotationTwoDimensionalShape* annotation2D, const float windowXYZ[3], float bottomLeftOut[3], float bottomRightOut[3], float topRightOut[3], float topLeftOut[3]) const; void applyRotationToShape(const float rotationAngle, const float rotationPoint[3], float bottomLeftOut[3], float bottomRightOut[3], float topRightOut[3], float topLeftOut[3]) const; void drawAnnotation(AnnotationFile* annotationFile, Annotation* annotation, const Surface* surfaceDisplayed); bool drawTwoDimAnnotationSurfaceTextureOffset(AnnotationFile* annotationFile, AnnotationTwoDimensionalShape* annotation, const Surface* surfaceDisplayed); bool drawOneDimAnnotationSurfaceTextureOffset(AnnotationFile* annotationFile, AnnotationOneDimensionalShape* annotation, const Surface* surfaceDisplayed); void drawColorBar(AnnotationFile* annotationFile, AnnotationColorBar* colorBar); bool drawBox(AnnotationFile* annotationFile, AnnotationBox* box, const Surface* surfaceDisplayed); bool drawBoxSurfaceTangentOffset(AnnotationFile* annotationFile, AnnotationBox* box, const float surfaceExtentZ, const float vertexXYZ[3]); bool drawImage(AnnotationFile* annotationFile, AnnotationImage* image, const Surface* surfaceDisplayed); bool drawImageSurfaceTangentOffset(AnnotationFile* annotationFile, AnnotationImage* image, const float surfaceExtentZ, const float vertexXYZ[3]); bool drawLine(AnnotationFile* annotationFile, AnnotationLine* line, const Surface* surfaceDisplayed); bool drawLineSurfaceTextureOffset(AnnotationFile* annotationFile, AnnotationLine* line, const Surface* surfaceDisplayed, const float surfaceExtentZ); bool drawOval(AnnotationFile* annotationFile, AnnotationOval* oval, const Surface* surfaceDisplayed); bool drawOvalSurfaceTangentOffset(AnnotationFile* annotationFile, AnnotationOval* oval, const float surfaceExtentZ, const float vertexXYZ[3]); bool drawText(AnnotationFile* annotationFile, AnnotationText* text, const Surface* surfaceDisplayed); bool drawTextSurfaceTangentOffset(AnnotationFile* annotationFile, AnnotationText* text, const float surfaceExtentZ, const float vertexXYZ[3], const float vertexNormalXYZ[3]); void drawColorBarSections(const AnnotationColorBar* colorBar, const float bottomLeft[3], const float bottomRight[3], const float topRight[3], const float topLeft[3], const float sectionsHeightInPixels); void drawColorBarText(const AnnotationColorBar* colorBar, const float bottomLeft[3], const float bottomRight[3], const float topRight[3], const float topLeft[3], const float textHeightInPixels, const float offsetFromTopInPixels); void drawColorBarTickMarks(const AnnotationColorBar* colorBar, const float bottomLeft[3], const float bottomRight[3], const float topRight[3], const float topLeft[3], const float tickMarksHeightInPixels, const float offsetFromBottomInPixels); void drawSizingHandle(const AnnotationSizingHandleTypeEnum::Enum handleType, AnnotationFile* annotationFile, Annotation* annotation, const float xyz[3], const float halfWidthHeight, const float rotationAngle); void drawAnnotationTwoDimSizingHandles(AnnotationFile* annotationFile, Annotation* annotation, const float bottomLeft[3], const float bottomRight[3], const float topRight[3], const float topLeft[3], const float lineThickness, const float rotationAngle); void drawAnnotationOneDimSizingHandles(AnnotationFile* annotationFile, Annotation* annotation, const float firstPoint[3], const float secondPoint[3], const float lineThickness); bool isDrawnWithDepthTesting(const Annotation* annotation, const Surface* surface); bool setDepthTestingStatus(const bool newDepthTestingStatus); void getIdentificationColor(uint8_t identificationColorOut[4]); bool convertModelToWindowCoordinate(const float modelXYZ[3], float windowXYZOut[3]) const; void viewportToOpenGLWindowCoordinate(const float viewportXYZ[3], float openGLXYZOut[3]) const; void createLineCoordinates(const float lineHeadXYZ[3], const float lineTailXYZ[3], const float lineThickness, const bool validStartArrow, const bool validEndArrow, std::vector& lineCoordinatesOut, std::vector& startArrowCoordinatesOut, std::vector& endArrowCoordinatesOut) const; void getTextLineToBrainordinateLineCoordinates(const AnnotationText* text, const Surface* surfaceDisplayed, const float bottomLeft[3], const float bottomRight[3], const float topRight[3], const float topLeft[3], std::vector& lineCoordinatesOut, std::vector& arrowCoordinatesOut) const; void setSelectionBoxColor(); void startOpenGLForDrawing(GLint* savedShadeModelOut, GLboolean* savedLightingEnabledOut); void endOpenGLForDrawing(GLint savedShadeModel, GLboolean savedLightingEnabled); void clipLineAtTextBox(const float bottomLeft[3], const float bottomRight[3], const float topRight[3], const float topLeft[3], const float startXYZ[3], float endXYZ[3]) const; void convertObsoleteLineWidthPixelsToPercentageWidth(const Annotation* annotation) const; float getLineWidthFromPercentageHeight(const float percentageHeight) const; float getLineWidthPercentageInSelectionMode(const Annotation* annotation) const; float estimateColorBarWidth(const AnnotationColorBar* colorBar, const float textHeightInPixels) const; void getSurfaceNormalVector(const Surface* surfaceDisplayed, const int32_t vertexIndex, float normalVectorOut[3]) const; bool isBackFacing(const float xyz[3], const float normal[3]) const; BrainOpenGLFixedPipeline* m_brainOpenGLFixedPipeline; Inputs* m_inputs; float m_surfaceViewScaling; /** * Dummy annotation file is used for annotations that * do not belong to a file. This includes the * "annotation being drawn" and AnnotationColorBar's. */ AnnotationFile* m_dummyAnnotationFile; /** Tracks items drawn for selection */ std::vector m_selectionInfo; /** In selection mode */ bool m_selectionModeFlag; /** OpenGL Model Matrix */ GLdouble m_modelSpaceModelMatrix[16]; /** OpenGL Projection Matrix */ GLdouble m_modelSpaceProjectionMatrix[16]; /** OpenGL Viewport */ GLint m_modelSpaceViewport[4]; /** volume space plane */ Plane m_volumeSpacePlane; /** Validity of volume space plane */ bool m_volumeSpacePlaneValid; /** Thickness of volume slice when drawing annotations on volume slices */ float m_volumeSliceThickness; /** Color for selection box and sizing handles */ uint8_t m_selectionBoxRGBA[4]; float m_lineWidthMinimum = 1.0f; BrainOpenGLTextRenderInterface::DrawingFlags m_textDrawingFlags; std::unique_ptr m_transformEvent; static const float s_sizingHandleLineWidthInPixels; static const float s_selectionLineMinimumPixelWidth; // ADD_NEW_MEMBERS_HERE }; #ifdef __BRAIN_OPEN_G_L_ANNOTATION_DRAWING_FIXED_PIPELINE_DECLARE__ const float BrainOpenGLAnnotationDrawingFixedPipeline::s_sizingHandleLineWidthInPixels = 2.0f; const float BrainOpenGLAnnotationDrawingFixedPipeline::s_selectionLineMinimumPixelWidth = 5.0f; #endif // __BRAIN_OPEN_G_L_ANNOTATION_DRAWING_FIXED_PIPELINE_DECLARE__ } // namespace #endif //__BRAIN_OPEN_G_L_ANNOTATION_DRAWING_FIXED_PIPELINE_H__ connectome-workbench-1.4.2/src/Brain/BrainOpenGLChartDrawingFixedPipeline.cxx000066400000000000000000002035301360521144700272500ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __BRAIN_OPEN_G_L_CHART_DRAWING_FIXED_PIPELINE_DECLARE__ #include "BrainOpenGLChartDrawingFixedPipeline.h" #undef __BRAIN_OPEN_G_L_CHART_DRAWING_FIXED_PIPELINE_DECLARE__ #include "AnnotationColorBar.h" #include "AnnotationPointSizeText.h" #include "CaretOpenGLInclude.h" #include "BrainOpenGLFixedPipeline.h" #include "BrainOpenGLTextRenderInterface.h" #include "CaretAssert.h" #include "ChartAxis.h" #include "ChartAxisCartesian.h" #include "ChartData.h" #include "ChartDataCartesian.h" #include "CaretLogger.h" #include "ChartMatrixDisplayProperties.h" #include "ChartModelDataSeries.h" #include "ChartModelFrequencySeries.h" #include "ChartModelTimeSeries.h" #include "ChartableMatrixInterface.h" #include "CaretPreferences.h" #include "ChartPoint.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "CiftiParcelLabelFile.h" #include "CiftiParcelScalarFile.h" #include "CiftiScalarDataSeriesFile.h" #include "Brain.h" #include "ConnectivityDataLoaded.h" #include "EventCaretMappableDataFileMapsViewedInOverlays.h" #include "EventManager.h" #include "IdentificationWithColor.h" #include "SelectionItemChartDataSeries.h" #include "SelectionItemChartFrequencySeries.h" #include "SelectionItemChartMatrix.h" #include "SelectionItemChartTimeSeries.h" #include "SelectionManager.h" #include "SessionManager.h" using namespace caret; /** * \class caret::BrainOpenGLChartDrawingFixedPipeline * \brief Chart drawing using OpenGL's fixed pipeline. * \ingroup Brain */ /** * Constructor. */ BrainOpenGLChartDrawingFixedPipeline::BrainOpenGLChartDrawingFixedPipeline() : BrainOpenGLChartDrawingInterface() { m_brain = NULL; m_fixedPipelineDrawing = NULL; m_identificationModeFlag = false; } /** * Destructor. */ BrainOpenGLChartDrawingFixedPipeline::~BrainOpenGLChartDrawingFixedPipeline() { } /** * Draw a cartesian chart in the given viewport. * * @param brain * Brain. * @param fixedPipelineDrawing * The fixed pipeline OpenGL drawing. * @param viewport * Viewport for the chart. * @param textRenderer * Text rendering. * @param cartesianChart * Cartesian Chart that is drawn. * @param selectionItemDataType * Selected data type. * @param tabIndex * Index of the tab. */ void BrainOpenGLChartDrawingFixedPipeline::drawCartesianChart(Brain* brain, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const int32_t viewport[4], BrainOpenGLTextRenderInterface* textRenderer, ChartModelCartesian* cartesianChart, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t tabIndex) { m_brain = brain; m_fixedPipelineDrawing = fixedPipelineDrawing; m_tabIndex = tabIndex; m_chartModelDataSeriesBeingDrawnForIdentification = dynamic_cast(cartesianChart); m_chartModelFrequencySeriesBeingDrawnForIdentification = dynamic_cast(cartesianChart); m_chartModelTimeSeriesBeingDrawnForIdentification = dynamic_cast(cartesianChart); m_chartCartesianSelectionTypeForIdentification = selectionItemDataType; m_chartableMatrixInterfaceBeingDrawnForIdentification = NULL; CaretAssert(cartesianChart); if (cartesianChart->isEmpty()) { return; } SelectionItemChartDataSeries* chartDataSeriesID = m_brain->getSelectionManager()->getChartDataSeriesIdentification(); SelectionItemChartFrequencySeries* chartFrequencySeriesID = m_brain->getSelectionManager()->getChartFrequencySeriesIdentification(); SelectionItemChartTimeSeries* chartTimeSeriesID = m_brain->getSelectionManager()->getChartTimeSeriesIdentification(); /* * Check for a 'selection' type mode */ m_identificationModeFlag = false; switch (m_fixedPipelineDrawing->mode) { case BrainOpenGLFixedPipeline::MODE_DRAWING: break; case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: if (chartDataSeriesID->isEnabledForSelection() || chartFrequencySeriesID->isEnabledForSelection() || chartTimeSeriesID->isEnabledForSelection()) { m_identificationModeFlag = true; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } else { return; } break; case BrainOpenGLFixedPipeline::MODE_PROJECTION: return; break; } saveStateOfOpenGL(); resetIdentification(); const int32_t vpX = viewport[0]; const int32_t vpY = viewport[1]; const int32_t vpWidth = viewport[2]; const int32_t vpHeight = viewport[3]; int32_t chartGraphicsDrawingViewport[4] = { vpX, vpY, vpWidth, vpHeight }; /* * Margin is region around the chart in which * the axes legends, values, and ticks are drawn. */ const double marginSize = 30; Margins margins(marginSize); double width, height; estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpWidth, vpHeight, cartesianChart->getLeftAxis(), width, height); margins.m_left = std::max(margins.m_left, width); estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpWidth, vpHeight, cartesianChart->getRightAxis(), width, height); margins.m_right = std::max(margins.m_right, width); estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpWidth, vpHeight, cartesianChart->getTopAxis(), width, height); margins.m_top = std::max(margins.m_top, height); estimateCartesianChartAxisLegendsWidthHeight(textRenderer, vpWidth, vpHeight, cartesianChart->getBottomAxis(), width, height); margins.m_bottom = std::max(margins.m_bottom, height); if (margins.m_left > marginSize) margins.m_left += 10; if (margins.m_right > marginSize) margins.m_right += 10; /* * Ensure that there is sufficient space for the axes data display. */ if ((vpWidth > (marginSize * 3)) && (vpHeight > (marginSize * 3))) { /* Draw legends and grids */ drawChartAxis(vpX, vpY, vpWidth, vpHeight, margins, textRenderer, cartesianChart->getLeftAxis()); drawChartAxis(vpX, vpY, vpWidth, vpHeight, margins, textRenderer, cartesianChart->getRightAxis()); drawChartAxis(vpX, vpY, vpWidth, vpHeight, margins, textRenderer, cartesianChart->getBottomAxis()); drawChartAxis(vpX, vpY, vpWidth, vpHeight, margins, textRenderer, cartesianChart->getTopAxis()); drawChartGraphicsBoxAndSetViewport(vpX, vpY, vpWidth, vpHeight, margins, chartGraphicsDrawingViewport); } glViewport(chartGraphicsDrawingViewport[0], chartGraphicsDrawingViewport[1], chartGraphicsDrawingViewport[2], chartGraphicsDrawingViewport[3]); drawChartGraphicsLineSeries(textRenderer, cartesianChart); /* * Process selection */ if (m_identificationModeFlag) { processIdentification(); } restoreStateOfOpenGL(); } /** * Draw a matrix chart in the given viewport. * * @param brain * Brain. * @param fixedPipelineDrawing * The fixed pipeline OpenGL drawing. * @param viewport * Viewport for the chart. * @param textRenderer * Text rendering. * @param chartMatrixInterface * Chart matrix interface containing matrix data. * @param scalarDataSeriesMapIndex * Selected map in scalar data series file. * @param selectionItemDataType * Selected data type. * @param tabIndex * Index of the tab. */ void BrainOpenGLChartDrawingFixedPipeline::drawMatrixChart(Brain* brain, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const int32_t viewport[4], BrainOpenGLTextRenderInterface* textRenderer, ChartableMatrixInterface* chartMatrixInterface, const int32_t scalarDataSeriesMapIndex, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t tabIndex) { m_brain = brain; m_fixedPipelineDrawing = fixedPipelineDrawing; m_tabIndex = tabIndex; m_chartModelDataSeriesBeingDrawnForIdentification = NULL; m_chartModelFrequencySeriesBeingDrawnForIdentification = NULL; m_chartModelTimeSeriesBeingDrawnForIdentification = NULL; m_chartableMatrixInterfaceBeingDrawnForIdentification = chartMatrixInterface; m_chartableMatrixSelectionTypeForIdentification = selectionItemDataType; CaretAssert(chartMatrixInterface); SelectionItemChartMatrix* chartMatrixID = m_brain->getSelectionManager()->getChartMatrixIdentification(); /* * Check for a 'selection' type mode */ m_identificationModeFlag = false; switch (m_fixedPipelineDrawing->mode) { case BrainOpenGLFixedPipeline::MODE_DRAWING: break; case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: if (chartMatrixID->isEnabledForSelection()) { m_identificationModeFlag = true; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } else { return; } break; case BrainOpenGLFixedPipeline::MODE_PROJECTION: return; break; } saveStateOfOpenGL(); resetIdentification(); ChartMatrixDisplayProperties* matrixProperties = chartMatrixInterface->getChartMatrixDisplayProperties(m_tabIndex); const int32_t paletteHeight = (matrixProperties->getColorBar()->isDisplayed() ? 40 : 0); /* * Viewport is X, Y, Width, Height */ const int32_t chartGraphicsDrawingViewport[4] = { viewport[0], viewport[1] + paletteHeight, viewport[2], viewport[3] - paletteHeight }; /* * Margin is region around the chart in which * the axes legends, values, and ticks are drawn. */ glViewport(chartGraphicsDrawingViewport[0], chartGraphicsDrawingViewport[1], chartGraphicsDrawingViewport[2], chartGraphicsDrawingViewport[3]); drawChartGraphicsMatrix(chartGraphicsDrawingViewport, textRenderer, chartMatrixInterface, scalarDataSeriesMapIndex); /* * Process selection */ if (m_identificationModeFlag) { processIdentification(); } restoreStateOfOpenGL(); } /** * Draw the chart axes grid/box * * @param vpX * Viewport X for all chart content * @param vpY * Viewport Y for all chart content * @param vpWidth * Viewport width for all chart content * @param vpHeight * Viewport height for all chart content * @param margins * Margin around graphics region. The margin corresponding to the * axis may be changed so that all text in the axis is visible * (and not cut off). * @param textRenderer * Text rendering. * @param axis * Axis that is drawn. */ void BrainOpenGLChartDrawingFixedPipeline::drawChartAxis(const float vpX, const float vpY, const float vpWidth, const float vpHeight, Margins& margins, BrainOpenGLTextRenderInterface* textRenderer, ChartAxis* axis) { if (axis == NULL) { return; } if ( ! axis->isVisible()) { return; } switch (axis->getAxisType()) { case ChartAxisTypeEnum::CHART_AXIS_TYPE_CARTESIAN: drawChartAxisCartesian(vpX, vpY, vpWidth, vpHeight, margins, textRenderer, dynamic_cast(axis)); break; case ChartAxisTypeEnum::CHART_AXIS_TYPE_NONE: break; } } /** * Draw the chart axes grid/box * * @param vpX * Viewport X for all chart content * @param vpY * Viewport Y for all chart content * @param vpWidth * Viewport width for all chart content * @param vpHeight * Viewport height for all chart content * @param margins * Margin around graphics region. The margin corresponding to the * axis may be changed so that all text in the axis is visible * (and not cut off). * @param textRenderer * Text rendering. * @param chartModelCartesian * The chart cartesian model. * @param axis * Axis that is drawn. */ void BrainOpenGLChartDrawingFixedPipeline::drawChartAxisCartesian(const float vpX, const float vpY, const float vpWidth, const float vpHeight, Margins& margins, BrainOpenGLTextRenderInterface* textRenderer, ChartAxisCartesian* axis) { CaretAssert(axis); const float fontSizeInPixels = 14; float axisLength = 0.0; switch (axis->getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: axisLength = vpWidth - (margins.m_left + margins.m_right); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: axisLength = vpHeight - (margins.m_top + margins.m_bottom); break; } std::vector labelOffsetInPixels; std::vector labelTexts; axis->getLabelsAndPositions(axisLength, fontSizeInPixels, labelOffsetInPixels, labelTexts); const int32_t numLabelsToDraw = static_cast(labelTexts.size()); AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); if (numLabelsToDraw > 0) { float labelX = 0.0; float labelY = 0.0; float labelOffsetMultiplierX = 0.0; float labelOffsetMultiplierY = 0.0; annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); /* * Viewport for axis name and numeric values */ int32_t axisVpX = vpX; int32_t axisVpY = vpY; int32_t axisVpWidth = vpWidth; int32_t axisVpHeight = vpHeight; float tickDeltaXY[2] = { 0.0, 0.0 }; const float tickLength = 5.0; switch (axis->getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: axisVpX = vpX; axisVpY = vpY; axisVpWidth = vpWidth; axisVpHeight = margins.m_bottom; labelX = margins.m_left; labelY = margins.m_bottom; labelOffsetMultiplierX = 1.0; labelOffsetMultiplierY = 0.0; annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); tickDeltaXY[0] = 0.0; tickDeltaXY[1] = -tickLength; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: axisVpX = vpX; axisVpY = vpY + vpHeight - margins.m_top; axisVpWidth = vpWidth; axisVpHeight = margins.m_top; labelX = margins.m_left; labelY = 0.0; labelOffsetMultiplierX = 1.0; labelOffsetMultiplierY = 0.0; annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); tickDeltaXY[0] = 0.0; tickDeltaXY[1] = tickLength; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: axisVpX = vpX; axisVpY = vpY; axisVpWidth = margins.m_left; axisVpHeight = vpHeight; labelX = margins.m_left; labelY = margins.m_bottom; labelOffsetMultiplierX = 0.0; labelOffsetMultiplierY = 1.0; annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); tickDeltaXY[0] = -tickLength; tickDeltaXY[1] = 0.0; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: axisVpX = vpX + vpWidth - margins.m_right; axisVpY = vpY; axisVpWidth = margins.m_right; axisVpHeight = vpHeight; labelX = 0.0; labelY = margins.m_bottom; labelOffsetMultiplierX = 0.0; labelOffsetMultiplierY = 1.0; annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); tickDeltaXY[0] = tickLength; tickDeltaXY[1] = 0.0; break; } /* * Viewport for axis text and numeric values */ const int viewport[4] = { axisVpX, axisVpY, axisVpWidth, axisVpHeight }; glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, axisVpWidth, 0, axisVpHeight, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glColor3fv(m_fixedPipelineDrawing->m_foregroundColorFloat); for (int32_t i = 0; i < numLabelsToDraw; i++) { const float tickStartX = labelX + labelOffsetInPixels[i] * labelOffsetMultiplierX; const float tickStartY = labelY + labelOffsetInPixels[i] * labelOffsetMultiplierY; const float tickEndX = tickStartX + tickDeltaXY[0]; const float tickEndY = tickStartY + tickDeltaXY[1]; glBegin(GL_LINES); glVertex2f(tickStartX, tickStartY); glVertex2f(tickEndX, tickEndY); glEnd(); const float textX = tickEndX; const float textY = tickEndY; annotationText.setText(labelTexts[i]); textRenderer->drawTextAtViewportCoords(textX, textY, 0.0, annotationText, BrainOpenGLTextRenderInterface::DrawingFlags()); } const AString axisText = axis->getText(); if ( ! axisText.isEmpty()) { AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); bool drawAxisTextVerticalFlag = false; float axisTextCenterX = axisVpWidth / 2.0; float axisTextCenterY = axisVpHeight / 2.0; const float textMarginOffset = 5.0; switch (axis->getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: axisTextCenterX = (vpWidth / 2.0); axisTextCenterY = textMarginOffset; annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: axisTextCenterX = (vpWidth / 2.0); axisTextCenterY = margins.m_top - textMarginOffset; annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: axisTextCenterX = textMarginOffset; axisTextCenterY = (vpHeight / 2.0); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); drawAxisTextVerticalFlag = true; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: axisTextCenterX = margins.m_right - textMarginOffset; axisTextCenterY = (vpHeight / 2.0); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); drawAxisTextVerticalFlag = true; break; } if (drawAxisTextVerticalFlag) { annotationText.setOrientation(AnnotationTextOrientationEnum::STACKED); annotationText.setText(axisText); textRenderer->drawTextAtViewportCoords(axisTextCenterX, axisTextCenterY, 0.0, annotationText, BrainOpenGLTextRenderInterface::DrawingFlags()); } else { annotationText.setOrientation(AnnotationTextOrientationEnum::HORIZONTAL); annotationText.setText(axisText); textRenderer->drawTextAtViewportCoords(axisTextCenterX, axisTextCenterY, 0.0, annotationText, BrainOpenGLTextRenderInterface::DrawingFlags()); } } } } /** * Estimate the size of the axis' text. * * @param textRenderer * Text rendering. * @param viewportHeight * Height of viewport. * @param viewportHeight * Height of viewport. * @param axis * The axis. * @param widthOut * Width of text out. * @param heightOut * Heigh of text out. */ void BrainOpenGLChartDrawingFixedPipeline::estimateCartesianChartAxisLegendsWidthHeight(BrainOpenGLTextRenderInterface* textRenderer, const float viewportWidth, const float viewportHeight, ChartAxis* axis, double& widthOut, double& heightOut) { widthOut = 0; heightOut = 0; if (axis == NULL) { return; } ChartAxisCartesian* cartesianAxis = dynamic_cast(axis); if ( ! cartesianAxis->isVisible()) { return; } const float fontSizeInPixels = 14; const float axisLength = 1000.0; std::vector labelOffsetInPixels; std::vector labelTexts; cartesianAxis->getLabelsAndPositions(axisLength, fontSizeInPixels, labelOffsetInPixels, labelTexts); for (std::vector::iterator iter = labelTexts.begin(); iter != labelTexts.end(); iter++) { const AString text = *iter; if ( ! text.isEmpty()) { AnnotationPointSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); annotationText.setText(text); double textWidth = 0.0; double textHeight = 0.0; textRenderer->getTextWidthHeightInPixels(annotationText, BrainOpenGLTextRenderInterface::DrawingFlags(), viewportWidth, viewportHeight, textWidth, textHeight); widthOut = std::max(widthOut, textWidth); heightOut = std::max(heightOut, textHeight); } } } /** * Draw the chart graphics surrounding box and set the graphics viewport. * drawChartGraphicsBoxAndSetViewport * @param vpX * Viewport X * @param vpY * Viewport Y * @param vpWidth * Viewport width * @param vpHeight * Viewport height * @param marginSize * Margin around grid/box * @param chartGraphicsDrawingViewportOut * Output containing viewport for drawing chart graphics within * the box/grid that is adjusted for the box's line thickness. */ void BrainOpenGLChartDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(const float vpX, const float vpY, const float vpWidth, const float vpHeight, const Margins& margins, int32_t chartGraphicsDrawingViewportOut[4]) { const float gridLineWidth = 2; const float halfGridLineWidth = gridLineWidth / 2.0; const float gridLeft = vpX + margins.m_left; const float gridRight = vpX + vpWidth - margins.m_right; const float gridBottom = vpY + margins.m_bottom; const float gridTop = vpY + vpHeight - margins.m_top; glViewport(vpX, vpY, vpWidth, vpHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(vpX, (vpX + vpWidth), vpY, (vpY + vpHeight), -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glLineWidth(gridLineWidth); glColor3fv(m_fixedPipelineDrawing->m_foregroundColorFloat); glBegin(GL_LINES); /* bottom line */ glVertex3f(gridLeft, gridBottom + halfGridLineWidth, 0.0); glVertex3f(gridRight, gridBottom + halfGridLineWidth, 0.0); /* right line */ glVertex3f(gridRight - halfGridLineWidth, gridBottom, 0.0); glVertex3f(gridRight - halfGridLineWidth, gridTop, 0.0); /* top line */ glVertex3f(gridRight, gridTop - halfGridLineWidth, 0.0); glVertex3f(gridLeft, gridTop - halfGridLineWidth, 0.0); /* left line */ glVertex3f(gridLeft + halfGridLineWidth, gridTop, 0.0); glVertex3f(gridLeft + halfGridLineWidth, gridBottom, 0.0); glEnd(); /* * Region inside the grid's box */ const int32_t graphicsLeft = static_cast(gridLeft + std::ceil(gridLineWidth + 1.0)); const int32_t graphicsRight = static_cast(gridRight - std::floor(gridLineWidth + 1.0)); const int32_t graphicsBottom = static_cast(gridBottom + std::ceil(gridLineWidth + 1.0)); const int32_t graphicsTop = static_cast(gridTop - std::floor(gridLineWidth + 1.0)); const int32_t graphicsWidth = graphicsRight - graphicsLeft; const int32_t graphicsHeight = graphicsTop - graphicsBottom; chartGraphicsDrawingViewportOut[0] = graphicsLeft; chartGraphicsDrawingViewportOut[1] = graphicsBottom; chartGraphicsDrawingViewportOut[2] = graphicsWidth; chartGraphicsDrawingViewportOut[3] = graphicsHeight; } /** * Draw graphics for the given line series chart. * * @param textRenderer * Text rendering. * @param chart * Chart that is drawn. */ void BrainOpenGLChartDrawingFixedPipeline::drawChartGraphicsLineSeries(BrainOpenGLTextRenderInterface* /*textRenderer*/, ChartModelCartesian* chart) { CaretAssert(chart); std::vector chartVector = chart->getAllChartDatas(); if (chartVector.empty()) { return; } m_fixedPipelineDrawing->enableLineAntiAliasing(); const ChartAxisCartesian* leftAxis = dynamic_cast(chart->getLeftAxis()); CaretAssert(leftAxis); const ChartAxisCartesian* bottomAxis = dynamic_cast(chart->getBottomAxis()); CaretAssert(bottomAxis); float xMin = bottomAxis->getMinimumValue(); float xMax = bottomAxis->getMaximumValue(); float yMin = leftAxis->getMinimumValue(); float yMax = leftAxis->getMaximumValue(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(xMin, xMax, yMin, yMax, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); const float lineWidth = chart->getLineWidth(); /* * Start at the oldest chart and end with the newest chart. */ const int32_t numChartData = static_cast(chartVector.size()); for (int32_t chartDataIndex = (numChartData - 1); chartDataIndex >= 0; chartDataIndex--) { const ChartData* chartData = chartVector[chartDataIndex]; if (chartData->isSelected(m_tabIndex)) { const ChartDataCartesian* chartDataCart = dynamic_cast(chartData); CaretAssert(chartDataCart); CaretColorEnum::Enum color = chartDataCart->getColor(); drawChartDataCartesian(chartDataIndex, chartDataCart, lineWidth, CaretColorEnum::toRGB(color)); } } if (chart->isAverageChartDisplaySelected()) { const ChartData* chartData = chart->getAverageChartDataForDisplay(m_tabIndex); if (chartData != NULL) { const ChartDataCartesian* chartDataCart = dynamic_cast(chartData); CaretAssert(chartDataCart); drawChartDataCartesian(-1, chartDataCart, lineWidth, m_fixedPipelineDrawing->m_foregroundColorFloat); } } m_fixedPipelineDrawing->disableLineAntiAliasing(); } /** * Draw the cartesian data with the given color. * * @param chartDataIndex * Index of chart data * @param chartDataCartesian * Cartesian data that is drawn. * @param lineWidth * Width of lines. * @param color * Color for the data. */ void BrainOpenGLChartDrawingFixedPipeline::drawChartDataCartesian(const int32_t chartDataIndex, const ChartDataCartesian* chartDataCartesian, const float lineWidth, const float rgb[3]) { if (lineWidth <= 0.0) { return; } glColor3fv(rgb); glLineWidth(lineWidth); if (m_identificationModeFlag) { glLineWidth(5.0); } glBegin(GL_LINE_STRIP); const int32_t numPoints = chartDataCartesian->getNumberOfPoints(); for (int32_t i = 0; i < numPoints; i++) { const ChartPoint* point = chartDataCartesian->getPointAtIndex(i); if (m_identificationModeFlag) { uint8_t rgbaForID[4]; addToChartLineIdentification(chartDataIndex, i, rgbaForID); glColor4ubv(rgbaForID); } glVertex2fv(point->getXY()); } glEnd(); } /** * Draw graphics for the matrix chart.. * * @param viewport * The viewport. * @param textRenderer * Text rendering. * @param chartMatrixInterface * Chart that is drawn. * @param scalarDataSeriesMapIndex * Selected map for scalar data series file. */ void BrainOpenGLChartDrawingFixedPipeline::drawChartGraphicsMatrix(const int32_t viewport[4], BrainOpenGLTextRenderInterface* /*textRenderer*/, ChartableMatrixInterface* chartMatrixInterface, const int32_t scalarDataSeriesMapIndex) { CaretAssert(chartMatrixInterface); CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); uint8_t highlightRGBByte[3]; prefs->getBackgroundAndForegroundColors()->getColorForegroundChartView(highlightRGBByte); const float highlightRGB[3] = { highlightRGBByte[0] / 255.0f, highlightRGBByte[1] / 255.0f, highlightRGBByte[2] / 255.0f }; int32_t numberOfRows = 0; int32_t numberOfColumns = 0; std::vector matrixRGBA; if (chartMatrixInterface->getMatrixDataRGBA(numberOfRows, numberOfColumns, matrixRGBA)) { std::set selectedColumnIndices; std::set selectedRowIndices; CiftiMappableConnectivityMatrixDataFile* connMapFile = dynamic_cast(chartMatrixInterface); if (connMapFile != NULL) { const ConnectivityDataLoaded* connDataLoaded = connMapFile->getConnectivityDataLoaded(); if (connDataLoaded != NULL) { int64_t loadedRowIndex = -1; int64_t loadedColumnIndex = -1; connDataLoaded->getRowColumnLoading(loadedRowIndex, loadedColumnIndex); if (loadedRowIndex >= 0) { selectedRowIndices.insert(loadedRowIndex); } else if (loadedColumnIndex >= 0) { selectedColumnIndices.insert(loadedColumnIndex); } } } CiftiParcelScalarFile* parcelScalarFile = dynamic_cast(chartMatrixInterface); if (parcelScalarFile != NULL) { EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(parcelScalarFile); EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); selectedColumnIndices = mapOverlayEvent.getSelectedMapIndices(); } CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(chartMatrixInterface); if (parcelLabelFile != NULL) { EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(parcelLabelFile); EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); selectedColumnIndices = mapOverlayEvent.getSelectedMapIndices(); } CiftiScalarDataSeriesFile* scalarDataSeriesFile = dynamic_cast(chartMatrixInterface); if (scalarDataSeriesFile != NULL) { if (scalarDataSeriesMapIndex >= 0) { selectedRowIndices.insert(scalarDataSeriesMapIndex); } } bool applyTransformationsFlag = false; float panningXY[2] = { 0.0, 0.0 }; float zooming = 1.0; float cellWidth = 1.0; float cellHeight = 1.0; /* * Setup width/height of area in which matrix is drawn with a * small margin along all of the edges */ float margin = 10.0; if ((viewport[2] < (margin * 3.0)) || (viewport[3] < (margin * 3.0))) { margin = 0.0; } const float graphicsWidth = viewport[2] - (margin * 2.0); const float graphicsHeight = viewport[3] - (margin * 2.0); /* * Set the width and neight of each matrix cell. */ ChartMatrixDisplayProperties* matrixProperties = chartMatrixInterface->getChartMatrixDisplayProperties(m_tabIndex); CaretAssert(matrixProperties); const ChartMatrixScaleModeEnum::Enum scaleMode = matrixProperties->getScaleMode(); switch (scaleMode) { case ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_AUTO: /* * Auto scale 'fills' the matrix region * and updates the width and height in the * matrix properties for use in manual mode. * There is NO zooming or panning for Auto scale. */ cellWidth = graphicsWidth / numberOfColumns; cellHeight = graphicsHeight / numberOfRows; matrixProperties->setCellWidth(cellWidth); matrixProperties->setCellHeight(cellHeight); break; case ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_MANUAL: /* * Use the cell width and height for manual mode * and allow both panning and zooming. */ cellWidth = matrixProperties->getCellWidth(); cellHeight = matrixProperties->getCellHeight(); matrixProperties->getViewPanning(panningXY); zooming = matrixProperties->getViewZooming(); applyTransformationsFlag = true; break; } const bool highlightSelectedRowColumnFlag = ( ( ! m_identificationModeFlag) && matrixProperties->isSelectedRowColumnHighlighted() ); const bool displayGridLinesFlag = ( ( ! m_identificationModeFlag) && matrixProperties->isGridLinesDisplayed() ); /* * Set the coordinates for the area in which the matrix is drawn. */ const float xMin = -margin; const float xMax = graphicsWidth + margin; const float yMin = -margin; const float yMax = graphicsHeight + margin; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(xMin, xMax, yMin, yMax, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); if (applyTransformationsFlag) { glTranslatef(panningXY[0], panningXY[1], 0.0); const float chartWidth = cellWidth * numberOfColumns; const float chartHeight = cellHeight * numberOfRows; const float halfWidth = chartWidth / 2.0; const float halfHeight = chartHeight / 2.0; glTranslatef(halfWidth, halfHeight, 0.0); glScalef(zooming, zooming, 1.0); glTranslatef(-halfWidth, -halfHeight, 0.0); } int32_t rgbaOffset = 0; std::vector quadVerticesXYZ; quadVerticesXYZ.reserve(numberOfRows * numberOfColumns * 3); std::vector quadVerticesFloatRGBA; quadVerticesFloatRGBA.reserve(numberOfRows * numberOfColumns * 4); std::vector quadVerticesByteRGBA; quadVerticesByteRGBA.reserve(numberOfRows * numberOfColumns * 4); float cellY = (numberOfRows - 1) * cellHeight; for (int32_t rowIndex = 0; rowIndex < numberOfRows; rowIndex++) { float cellX = 0; for (int32_t columnIndex = 0; columnIndex < numberOfColumns; columnIndex++) { CaretAssertVectorIndex(matrixRGBA, rgbaOffset+3); const float* rgba = &matrixRGBA[rgbaOffset]; rgbaOffset += 4; uint8_t idRGBA[4]; if (m_identificationModeFlag) { addToChartMatrixIdentification(rowIndex, columnIndex, idRGBA); } if (m_identificationModeFlag) { quadVerticesByteRGBA.push_back(idRGBA[0]); quadVerticesByteRGBA.push_back(idRGBA[1]); quadVerticesByteRGBA.push_back(idRGBA[2]); quadVerticesByteRGBA.push_back(idRGBA[3]); } else { quadVerticesFloatRGBA.push_back(rgba[0]); quadVerticesFloatRGBA.push_back(rgba[1]); quadVerticesFloatRGBA.push_back(rgba[2]); quadVerticesFloatRGBA.push_back(rgba[3]); } quadVerticesXYZ.push_back(cellX); quadVerticesXYZ.push_back(cellY); quadVerticesXYZ.push_back(0.0); if (m_identificationModeFlag) { quadVerticesByteRGBA.push_back(idRGBA[0]); quadVerticesByteRGBA.push_back(idRGBA[1]); quadVerticesByteRGBA.push_back(idRGBA[2]); quadVerticesByteRGBA.push_back(idRGBA[3]); } else { quadVerticesFloatRGBA.push_back(rgba[0]); quadVerticesFloatRGBA.push_back(rgba[1]); quadVerticesFloatRGBA.push_back(rgba[2]); quadVerticesFloatRGBA.push_back(rgba[3]); } quadVerticesXYZ.push_back(cellX + cellWidth); quadVerticesXYZ.push_back(cellY); quadVerticesXYZ.push_back(0.0); if (m_identificationModeFlag) { quadVerticesByteRGBA.push_back(idRGBA[0]); quadVerticesByteRGBA.push_back(idRGBA[1]); quadVerticesByteRGBA.push_back(idRGBA[2]); quadVerticesByteRGBA.push_back(idRGBA[3]); } else { quadVerticesFloatRGBA.push_back(rgba[0]); quadVerticesFloatRGBA.push_back(rgba[1]); quadVerticesFloatRGBA.push_back(rgba[2]); quadVerticesFloatRGBA.push_back(rgba[3]); } quadVerticesXYZ.push_back(cellX + cellWidth); quadVerticesXYZ.push_back(cellY + cellHeight); quadVerticesXYZ.push_back(0.0); if (m_identificationModeFlag) { quadVerticesByteRGBA.push_back(idRGBA[0]); quadVerticesByteRGBA.push_back(idRGBA[1]); quadVerticesByteRGBA.push_back(idRGBA[2]); quadVerticesByteRGBA.push_back(idRGBA[3]); } else { quadVerticesFloatRGBA.push_back(rgba[0]); quadVerticesFloatRGBA.push_back(rgba[1]); quadVerticesFloatRGBA.push_back(rgba[2]); quadVerticesFloatRGBA.push_back(rgba[3]); } quadVerticesXYZ.push_back(cellX); quadVerticesXYZ.push_back(cellY + cellHeight); quadVerticesXYZ.push_back(0.0); cellX += cellWidth; } cellY -= cellHeight; } /* * Draw the matrix elements. */ if (m_identificationModeFlag) { CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesByteRGBA.size() / 4)); const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); glBegin(GL_QUADS); for (int32_t i = 0; i < numberQuadVertices; i++) { CaretAssertVectorIndex(quadVerticesByteRGBA, i*4 + 3); glColor4ubv(&quadVerticesByteRGBA[i*4]); CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); glVertex3fv(&quadVerticesXYZ[i*3]); } glEnd(); } else { /* * Enable alpha blending so voxels that are not drawn from higher layers * allow voxels from lower layers to be seen. */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); CaretAssert((quadVerticesXYZ.size() / 3) == (quadVerticesFloatRGBA.size() / 4)); const int32_t numberQuadVertices = static_cast(quadVerticesXYZ.size() / 3); glBegin(GL_QUADS); for (int32_t i = 0; i < numberQuadVertices; i++) { CaretAssertVectorIndex(quadVerticesFloatRGBA, i*4 + 3); glColor4fv(&quadVerticesFloatRGBA[i*4]); CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); glVertex3fv(&quadVerticesXYZ[i*3]); } glEnd(); glDisable(GL_BLEND); /* * Drawn an outline around the matrix elements. */ if (displayGridLinesFlag) { uint8_t gridLineColorBytes[3]; prefs->getBackgroundAndForegroundColors()->getColorChartMatrixGridLines(gridLineColorBytes); float gridLineColorFloats[4]; CaretPreferences::byteRgbToFloatRgb(gridLineColorBytes, gridLineColorFloats); gridLineColorFloats[3] = 1.0; std::vector outlineRGBA; outlineRGBA.reserve(numberQuadVertices * 4); for (int32_t i = 0; i < numberQuadVertices; i++) { outlineRGBA.push_back(gridLineColorFloats[0]); outlineRGBA.push_back(gridLineColorFloats[1]); outlineRGBA.push_back(gridLineColorFloats[2]); outlineRGBA.push_back(gridLineColorFloats[3]); } glPolygonMode(GL_FRONT, GL_LINE); glLineWidth(1.0); glBegin(GL_QUADS); for (int32_t i = 0; i < numberQuadVertices; i++) { CaretAssertVectorIndex(outlineRGBA, i*4 + 3); glColor4fv(&outlineRGBA[i*4]); CaretAssertVectorIndex(quadVerticesXYZ, i*3 + 2); glVertex3fv(&quadVerticesXYZ[i*3]); } glEnd(); } if ( (! selectedRowIndices.empty()) && highlightSelectedRowColumnFlag) { std::vector rowXYZ; std::vector rowRGBA; for (std::set::iterator rowIter = selectedRowIndices.begin(); rowIter != selectedRowIndices.end(); rowIter ++) { const float rowIndex = * rowIter; const float rowY = (numberOfRows - rowIndex - 1) * cellHeight; rowXYZ.push_back(0.0); rowXYZ.push_back(rowY); rowXYZ.push_back(0.0); rowRGBA.push_back(highlightRGB[0]); rowRGBA.push_back(highlightRGB[1]); rowRGBA.push_back(highlightRGB[2]); rowRGBA.push_back(1.0); rowXYZ.push_back(0.0); rowXYZ.push_back(rowY + cellHeight); rowXYZ.push_back(0.0); rowRGBA.push_back(highlightRGB[0]); rowRGBA.push_back(highlightRGB[1]); rowRGBA.push_back(highlightRGB[2]); rowRGBA.push_back(1.0); rowXYZ.push_back(numberOfColumns * cellWidth); rowXYZ.push_back(rowY + cellHeight); rowXYZ.push_back(0.0); rowRGBA.push_back(highlightRGB[0]); rowRGBA.push_back(highlightRGB[1]); rowRGBA.push_back(highlightRGB[2]); rowRGBA.push_back(1.0); rowXYZ.push_back(numberOfColumns * cellWidth); rowXYZ.push_back(rowY); rowXYZ.push_back(0.0); rowRGBA.push_back(highlightRGB[0]); rowRGBA.push_back(highlightRGB[1]); rowRGBA.push_back(highlightRGB[2]); rowRGBA.push_back(1.0); } CaretAssert((rowXYZ.size() / 3) == (rowRGBA.size() / 4)); const int32_t numberOfVertices = static_cast(rowXYZ.size() / 3); const int32_t numberOfQuads = numberOfVertices / 4; CaretAssert((numberOfQuads * 4) == numberOfVertices); /* * As cells get larger, increase linewidth for selected row */ const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); glLineWidth(highlightLineWidth); for (int32_t iQuad = 0; iQuad < numberOfQuads; iQuad++) { glBegin(GL_LINE_LOOP); for (int32_t iVert = 0; iVert < 4; iVert++) { const int32_t rgbaOffset = (iQuad * 16) + (iVert * 4); CaretAssertVectorIndex(rowRGBA, rgbaOffset + 3); glColor4fv(&rowRGBA[rgbaOffset]); const int32_t xyzOffset = (iQuad * 12) + (iVert * 3); CaretAssertVectorIndex(rowXYZ, xyzOffset + 2); glVertex3fv(&rowXYZ[xyzOffset]); } glEnd(); } glLineWidth(1.0); } if ( (! selectedColumnIndices.empty()) && highlightSelectedRowColumnFlag) { std::vector columnXYZ; std::vector columnRGBA; for (std::set::iterator colIter = selectedColumnIndices.begin(); colIter != selectedColumnIndices.end(); colIter++) { const float columnIndex = *colIter; const float colX = columnIndex * cellWidth; columnXYZ.push_back(colX); columnXYZ.push_back(0.0); columnXYZ.push_back(0.0); columnRGBA.push_back(highlightRGB[0]); columnRGBA.push_back(highlightRGB[1]); columnRGBA.push_back(highlightRGB[2]); columnRGBA.push_back(1.0); columnXYZ.push_back(colX + cellWidth); columnXYZ.push_back(0.0); columnXYZ.push_back(0.0); columnRGBA.push_back(highlightRGB[0]); columnRGBA.push_back(highlightRGB[1]); columnRGBA.push_back(highlightRGB[2]); columnRGBA.push_back(1.0); columnXYZ.push_back(colX + cellWidth); columnXYZ.push_back(numberOfRows * cellHeight); columnXYZ.push_back(0.0); columnRGBA.push_back(highlightRGB[0]); columnRGBA.push_back(highlightRGB[1]); columnRGBA.push_back(highlightRGB[2]); columnRGBA.push_back(1.0); columnXYZ.push_back(colX); columnXYZ.push_back(numberOfRows * cellHeight); columnXYZ.push_back(0.0); columnRGBA.push_back(highlightRGB[0]); columnRGBA.push_back(highlightRGB[1]); columnRGBA.push_back(highlightRGB[2]); columnRGBA.push_back(1.0); } CaretAssert((columnXYZ.size() / 3) == (columnRGBA.size() / 4)); const int32_t numberOfVertices = static_cast(columnXYZ.size() / 3); const int32_t numberOfQuads = numberOfVertices / 4; CaretAssert((numberOfQuads * 4) == numberOfVertices); /* * As cells get larger, increase linewidth for selected row */ const float highlightLineWidth = std::max(((cellHeight * zooming) * 0.20), 3.0); glLineWidth(highlightLineWidth); for (int32_t iQuad = 0; iQuad < numberOfQuads; iQuad++) { glBegin(GL_LINE_LOOP); for (int32_t iVert = 0; iVert < 4; iVert++) { const int32_t rgbaOffset = (iQuad * 16) + (iVert * 4); CaretAssertVectorIndex(columnRGBA, rgbaOffset + 3); glColor4fv(&columnRGBA[rgbaOffset]); const int32_t xyzOffset = (iQuad * 12) + (iVert * 3); CaretAssertVectorIndex(columnXYZ, xyzOffset + 2); glVertex3fv(&columnXYZ[xyzOffset]); } glEnd(); } glLineWidth(1.0); } glPolygonMode(GL_FRONT, GL_FILL); } } } /** * Save the state of OpenGL. * Copied from Qt's qgl.cpp, qt_save_gl_state(). */ void BrainOpenGLChartDrawingFixedPipeline::saveStateOfOpenGL() { glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); glPushAttrib(GL_ALL_ATTRIB_BITS); glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glShadeModel(GL_FLAT); glDisable(GL_LIGHTING); glDisable(GL_STENCIL_TEST); glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); } /** * Restore the state of OpenGL. * Copied from Qt's qgl.cpp, qt_restore_gl_state(). */ void BrainOpenGLChartDrawingFixedPipeline::restoreStateOfOpenGL() { glMatrixMode(GL_TEXTURE); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glPopAttrib(); glPopClientAttrib(); } /** * Add an item for line identification. * * @param chartDataIndex * Index of the chart data. * @param lineIndex * Index of the line. * @param rgbaForColorIdentificationOut * Encoded identification in RGBA color OUTPUT */ void BrainOpenGLChartDrawingFixedPipeline::addToChartLineIdentification(const int32_t chartDataIndex, const int32_t chartLineIndex, uint8_t rgbaForColorIdentificationOut[4]) { const int32_t idIndex = m_identificationIndices.size() / IDENTIFICATION_INDICES_PER_CHART_LINE; m_fixedPipelineDrawing->colorIdentification->addItem(rgbaForColorIdentificationOut, m_chartCartesianSelectionTypeForIdentification, idIndex); rgbaForColorIdentificationOut[3] = 255; /* * If these items change, need to update reset and * processing of identification. */ m_identificationIndices.push_back(chartDataIndex); m_identificationIndices.push_back(chartLineIndex); } /** * Add an item for matrix identification. * * @param matrixRowIndex * Index of the row * @param matrixColumnIndex * Index of the column * @param rgbaForColorIdentificationOut * Encoded identification in RGBA color OUTPUT */ void BrainOpenGLChartDrawingFixedPipeline::addToChartMatrixIdentification(const int32_t matrixRowIndex, const int32_t matrixColumnIndex, uint8_t rgbaForColorIdentificationOut[4]) { const int32_t idIndex = m_identificationIndices.size() / IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT; m_fixedPipelineDrawing->colorIdentification->addItem(rgbaForColorIdentificationOut, m_chartableMatrixSelectionTypeForIdentification, idIndex); rgbaForColorIdentificationOut[3] = 255; /* * If these items change, need to update reset and * processing of identification. */ m_identificationIndices.push_back(matrixRowIndex); m_identificationIndices.push_back(matrixColumnIndex); } /** * Reset identification. */ void BrainOpenGLChartDrawingFixedPipeline::resetIdentification() { m_identificationIndices.clear(); if (m_identificationModeFlag) { const int32_t estimatedNumberOfItems = 1000; m_identificationIndices.reserve(estimatedNumberOfItems); } } /** * Process identification. */ void BrainOpenGLChartDrawingFixedPipeline::processIdentification() { int32_t identifiedItemIndex; float depth = -1.0; if (m_chartModelDataSeriesBeingDrawnForIdentification != NULL) { m_fixedPipelineDrawing->getIndexFromColorSelection(m_chartCartesianSelectionTypeForIdentification, m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, identifiedItemIndex, depth); if (identifiedItemIndex >= 0) { const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_CHART_LINE; const int32_t chartDataIndex = m_identificationIndices[idIndex]; const int32_t chartLineIndex = m_identificationIndices[idIndex + 1]; SelectionItemChartDataSeries* chartDataSeriesID = m_brain->getSelectionManager()->getChartDataSeriesIdentification(); if (chartDataSeriesID->isOtherScreenDepthCloserToViewer(depth)) { ChartDataCartesian* chartDataCartesian = dynamic_cast(m_chartModelDataSeriesBeingDrawnForIdentification->getChartDataAtIndex(chartDataIndex)); CaretAssert(chartDataCartesian); chartDataSeriesID->setChart(m_chartModelDataSeriesBeingDrawnForIdentification, chartDataCartesian, chartLineIndex); const ChartPoint* chartPoint = chartDataCartesian->getPointAtIndex(chartLineIndex); const float lineXYZ[3] = { chartPoint->getX(), chartPoint->getY(), 0.0 }; m_fixedPipelineDrawing->setSelectedItemScreenXYZ(chartDataSeriesID, lineXYZ); } } } else if (m_chartModelFrequencySeriesBeingDrawnForIdentification != NULL) { m_fixedPipelineDrawing->getIndexFromColorSelection(m_chartCartesianSelectionTypeForIdentification, m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, identifiedItemIndex, depth); if (identifiedItemIndex >= 0) { const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_CHART_LINE; const int32_t chartDataIndex = m_identificationIndices[idIndex]; const int32_t chartLineIndex = m_identificationIndices[idIndex + 1]; SelectionItemChartFrequencySeries* chartFrequencySeriesID = m_brain->getSelectionManager()->getChartFrequencySeriesIdentification(); if (chartFrequencySeriesID->isOtherScreenDepthCloserToViewer(depth)) { ChartDataCartesian* chartDataCartesian = dynamic_cast(m_chartModelFrequencySeriesBeingDrawnForIdentification->getChartDataAtIndex(chartDataIndex)); CaretAssert(chartDataCartesian); chartFrequencySeriesID->setChart(m_chartModelFrequencySeriesBeingDrawnForIdentification, chartDataCartesian, chartLineIndex); const ChartPoint* chartPoint = chartDataCartesian->getPointAtIndex(chartLineIndex); const float lineXYZ[3] = { chartPoint->getX(), chartPoint->getY(), 0.0 }; m_fixedPipelineDrawing->setSelectedItemScreenXYZ(chartFrequencySeriesID, lineXYZ); } } } else if (m_chartModelTimeSeriesBeingDrawnForIdentification != NULL) { m_fixedPipelineDrawing->getIndexFromColorSelection(m_chartCartesianSelectionTypeForIdentification, m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, identifiedItemIndex, depth); if (identifiedItemIndex >= 0) { const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_CHART_LINE; const int32_t chartDataIndex = m_identificationIndices[idIndex]; const int32_t chartLineIndex = m_identificationIndices[idIndex + 1]; SelectionItemChartTimeSeries* chartTimeSeriesID = m_brain->getSelectionManager()->getChartTimeSeriesIdentification(); if (chartTimeSeriesID->isOtherScreenDepthCloserToViewer(depth)) { ChartDataCartesian* chartDataCartesian = dynamic_cast(m_chartModelTimeSeriesBeingDrawnForIdentification->getChartDataAtIndex(chartDataIndex)); CaretAssert(chartDataCartesian); chartTimeSeriesID->setChart(m_chartModelTimeSeriesBeingDrawnForIdentification, chartDataCartesian, chartLineIndex); const ChartPoint* chartPoint = chartDataCartesian->getPointAtIndex(chartLineIndex); const float lineXYZ[3] = { chartPoint->getX(), chartPoint->getY(), 0.0 }; m_fixedPipelineDrawing->setSelectedItemScreenXYZ(chartTimeSeriesID, lineXYZ); } } } else if (m_chartableMatrixInterfaceBeingDrawnForIdentification != NULL) { m_fixedPipelineDrawing->getIndexFromColorSelection(m_chartableMatrixSelectionTypeForIdentification, m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, identifiedItemIndex, depth); if (identifiedItemIndex >= 0) { const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT; const int32_t rowIndex = m_identificationIndices[idIndex]; const int32_t columnIndex = m_identificationIndices[idIndex + 1]; SelectionItemChartMatrix* chartMatrixID = m_brain->getSelectionManager()->getChartMatrixIdentification(); if (chartMatrixID->isOtherScreenDepthCloserToViewer(depth)) { chartMatrixID->setChartMatrix(m_chartableMatrixInterfaceBeingDrawnForIdentification, rowIndex, columnIndex); } } } } connectome-workbench-1.4.2/src/Brain/BrainOpenGLChartDrawingFixedPipeline.h000066400000000000000000000173201360521144700266750ustar00rootroot00000000000000#ifndef __BRAIN_OPEN_G_L_CHART_DRAWING_FIXED_PIPELINE_H__ #define __BRAIN_OPEN_G_L_CHART_DRAWING_FIXED_PIPELINE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainOpenGLChartDrawingInterface.h" #include "CaretColorEnum.h" namespace caret { class Brain; class BrainOpenGLFixedPipeline; class ChartAxis; class ChartAxisCartesian; class ChartDataCartesian; class ChartModelCartesian; class ChartModelDataSeries; class ChartModelFrequencySeries; class ChartModelTimeSeries; class ChartableMatrixInterface; class BrainOpenGLChartDrawingFixedPipeline : public BrainOpenGLChartDrawingInterface { public: BrainOpenGLChartDrawingFixedPipeline(); virtual ~BrainOpenGLChartDrawingFixedPipeline(); virtual void drawCartesianChart(Brain* brain, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const int32_t viewport[4], BrainOpenGLTextRenderInterface* textRenderer, ChartModelCartesian* cartesianChart, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t tabIndex); virtual void drawMatrixChart(Brain* brain, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const int32_t viewport[4], BrainOpenGLTextRenderInterface* textRenderer, ChartableMatrixInterface* chartMatrixInterface, const int32_t scalarDataSeriesMapIndex, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t tabIndex); private: class Margins { public: Margins(const double defaultSize) { m_bottom = defaultSize; m_left = defaultSize; m_right = defaultSize; m_top = defaultSize; } double m_bottom; double m_left; double m_right; double m_top; }; BrainOpenGLChartDrawingFixedPipeline(const BrainOpenGLChartDrawingFixedPipeline&); BrainOpenGLChartDrawingFixedPipeline& operator=(const BrainOpenGLChartDrawingFixedPipeline&); void drawChartGraphicsLineSeries(BrainOpenGLTextRenderInterface* textRenderer, ChartModelCartesian* chart); void drawChartGraphicsMatrix(const int32_t viewport[4], BrainOpenGLTextRenderInterface* textRenderer, ChartableMatrixInterface* chartMatrixInterface, const int32_t scalarDataSeriesMapIndex); void drawChartGraphicsBoxAndSetViewport(const float vpX, const float vpY, const float vpWidth, const float vpHeight, const Margins& margins, int32_t chartGraphicsDrawingViewportOut[4]); void drawChartAxis(const float vpX, const float vpY, const float vpWidth, const float vpHeight, Margins& margins, BrainOpenGLTextRenderInterface* textRenderer, ChartAxis* axis); void drawChartAxisCartesian(const float vpX, const float vpY, const float vpWidth, const float vpHeight, Margins& margins, BrainOpenGLTextRenderInterface* textRenderer, ChartAxisCartesian* axis); void drawChartDataCartesian(const int32_t chartDataIndex, const ChartDataCartesian* chartDataCartesian, const float lineWidth, const float rgb[3]); void estimateCartesianChartAxisLegendsWidthHeight(BrainOpenGLTextRenderInterface* textRenderer, const float viewportWidth, const float viewportHeight, ChartAxis* axis, double& widthOut, double& heightOut); void restoreStateOfOpenGL(); void saveStateOfOpenGL(); void addToChartLineIdentification(const int32_t chartDataIndex, const int32_t lineIndex, uint8_t rgbaForColorIdentification[4]); void addToChartMatrixIdentification(const int32_t matrixRowIndex, const int32_t matrixColumnIndex, uint8_t rgbaForColorIdentification[4]); void resetIdentification(); void processIdentification(); public: // ADD_NEW_METHODS_HERE private: Brain* m_brain; BrainOpenGLFixedPipeline* m_fixedPipelineDrawing; ChartModelDataSeries* m_chartModelDataSeriesBeingDrawnForIdentification; ChartModelFrequencySeries* m_chartModelFrequencySeriesBeingDrawnForIdentification; ChartModelTimeSeries* m_chartModelTimeSeriesBeingDrawnForIdentification; SelectionItemDataTypeEnum::Enum m_chartCartesianSelectionTypeForIdentification; ChartableMatrixInterface* m_chartableMatrixInterfaceBeingDrawnForIdentification; SelectionItemDataTypeEnum::Enum m_chartableMatrixSelectionTypeForIdentification; int32_t m_tabIndex; std::vector m_identificationIndices; bool m_identificationModeFlag; // ADD_NEW_MEMBERS_HERE static const int32_t IDENTIFICATION_INDICES_PER_CHART_LINE; static const int32_t IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT; }; #ifdef __BRAIN_OPEN_G_L_CHART_DRAWING_FIXED_PIPELINE_DECLARE__ const int32_t BrainOpenGLChartDrawingFixedPipeline::IDENTIFICATION_INDICES_PER_CHART_LINE = 2; const int32_t BrainOpenGLChartDrawingFixedPipeline::IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT = 2; #endif // __BRAIN_OPEN_G_L_CHART_DRAWING_FIXED_PIPELINE_DECLARE__ } // namespace #endif //__BRAIN_OPEN_G_L_CHART_DRAWING_FIXED_PIPELINE_H__ connectome-workbench-1.4.2/src/Brain/BrainOpenGLChartDrawingInterface.h000066400000000000000000000105741360521144700260540ustar00rootroot00000000000000#ifndef __BRAIN_OPEN_G_L_CHART_DRAWING_INTERFACE_H__ #define __BRAIN_OPEN_G_L_CHART_DRAWING_INTERFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AString.h" #include "SelectionItemDataTypeEnum.h" /** * \class caret::BrainOpenGLTextRenderInterface * \brief Interface for drawing charts with OpenGL. * \ingroup Brain */ namespace caret { class Brain; class BrainOpenGLFixedPipeline; class BrainOpenGLTextRenderInterface; class ChartModelCartesian; class ChartableMatrixInterface; class BrainOpenGLChartDrawingInterface { public: BrainOpenGLChartDrawingInterface() { } virtual ~BrainOpenGLChartDrawingInterface() { } /** * Draw a cartesian chart in the given viewport. * * @param brain * Brain. * @param fixedPipelineDrawing * The fixed pipeline OpenGL drawing. * @param viewport * Viewport for the chart. * @param textRenderer * Text rendering. * @param cartesianChart * Cartesian Chart that is drawn. * @param selectionItemDataType * Selected data type. * @param tabIndex * Index of the tab. */ virtual void drawCartesianChart(Brain* brain, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const int32_t viewport[4], BrainOpenGLTextRenderInterface* textRenderer, ChartModelCartesian* cartesianChart, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t tabIndex) = 0; /** * Draw a matrix chart in the given viewport. * * @param brain * Brain. * @param fixedPipelineDrawing * The fixed pipeline OpenGL drawing. * @param viewport * Viewport for the chart. * @param textRenderer * Text rendering. * @param chartMatrixInterface * Chart matrix interface containing matrix data. * @param scalarDataSeriesMapIndex * Scalar data series selected map index. * @param selectionItemDataType * Selected data type. * @param tabIndex * Index of the tab. */ virtual void drawMatrixChart(Brain* brain, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const int32_t viewport[4], BrainOpenGLTextRenderInterface* textRenderer, ChartableMatrixInterface* chartMatrixInterface, const int32_t scalarDataSeriesMapIndex, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t tabIndex) = 0; private: BrainOpenGLChartDrawingInterface(const BrainOpenGLChartDrawingInterface&); BrainOpenGLChartDrawingInterface& operator=(const BrainOpenGLChartDrawingInterface&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE }; #ifdef __BRAIN_OPEN_G_L_CHART_DRAWING_INTERFACE_DECLARE__ // #endif // __BRAIN_OPEN_G_L_CHART_DRAWING_INTERFACE_DECLARE__ } // namespace #endif //__BRAIN_OPEN_G_L_CHART_DRAWING_INTERFACE_H__ connectome-workbench-1.4.2/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.cxx000066400000000000000000003517351360521144700277550ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_FIXED_PIPELINE_DECLARE__ #include "BrainOpenGLChartTwoDrawingFixedPipeline.h" #undef __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_FIXED_PIPELINE_DECLARE__ #include #include "AnnotationCoordinate.h" #include "AnnotationColorBar.h" #include "AnnotationPercentSizeText.h" #include "AnnotationPointSizeText.h" #include "Brain.h" #include "BrainOpenGLFixedPipeline.h" #include "BrainOpenGLTextRenderInterface.h" #include "BrainOpenGLViewportContent.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPreferences.h" #include "ChartTwoCartesianAxis.h" #include "ChartTwoDataCartesian.h" #include "ChartTwoLineSeriesHistory.h" #include "ChartTwoMatrixDisplayProperties.h" #include "ChartTwoOverlay.h" #include "ChartTwoOverlaySet.h" #include "ChartTwoTitle.h" #include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileHistogramChart.h" #include "ChartableTwoFileMatrixChart.h" #include "ChartableTwoFileLineSeriesChart.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "DeveloperFlagsEnum.h" #include "FastStatistics.h" #include "GraphicsEngineDataOpenGL.h" #include "GraphicsPrimitiveV3f.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GraphicsPrimitiveV3fC4ub.h" #include "GraphicsShape.h" #include "IdentificationWithColor.h" #include "MathFunctions.h" #include "ModelChartTwo.h" #include "NodeAndVoxelColoring.h" #include "PaletteColorMapping.h" #include "SessionManager.h" #include "SelectionItemAnnotation.h" #include "SelectionItemChartTwoHistogram.h" #include "SelectionItemChartTwoLabel.h" #include "SelectionItemChartTwoLineSeries.h" #include "SelectionItemChartTwoMatrix.h" #include "SelectionManager.h" using namespace caret; static bool debugFlag = false; /** * \class caret::BrainOpenGLChartTwoDrawingFixedPipeline * \brief Drawing of version two charts. * \ingroup Brain */ /** * Constructor. * * @param viewportContent * The content of the viewport. */ BrainOpenGLChartTwoDrawingFixedPipeline::BrainOpenGLChartTwoDrawingFixedPipeline(const BrainOpenGLViewportContent* viewportContent) : BrainOpenGLChartTwoDrawingInterface(), m_viewportContent(viewportContent) { m_preferences = SessionManager::get()->getCaretPreferences(); BrainOpenGL::getMinMaxLineWidth(s_minimumLineWidthOpenGL, s_maximumLineWidthOpenGL); } /** * Destructor. */ BrainOpenGLChartTwoDrawingFixedPipeline::~BrainOpenGLChartTwoDrawingFixedPipeline() { } /** * Draw charts from a chart overlay. * * @param brain * Brain. * @param chartTwoModel * The chart two model. * @param fixedPipelineDrawing * The fixed pipeline OpenGL drawing. * @param selectionItemDataType * Selected data type. * @param viewport * Viewport for the chart. * @param annotationsOut * Output containing annotations that will be drawing by annotation drawing code. */ void BrainOpenGLChartTwoDrawingFixedPipeline::drawChartOverlaySet(Brain* brain, ModelChartTwo* chartTwoModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t viewport[4], std::vector& annotationsOut) { annotationsOut.clear(); m_annotationsForDrawingOutput.clear(); CaretAssert(m_viewportContent); BrowserTabContent* browserTabContent = m_viewportContent->getBrowserTabContent(); CaretAssert(browserTabContent); CaretAssert(brain); CaretAssert(browserTabContent); CaretAssert(chartTwoModel); CaretAssert(fixedPipelineDrawing); m_brain = brain; m_chartTwoModel = chartTwoModel; m_fixedPipelineDrawing = fixedPipelineDrawing; m_textRenderer = fixedPipelineDrawing->getTextRenderer(); m_browserTabContent = browserTabContent; m_translation[0] = 0.0; m_translation[1] = 0.0; m_translation[2] = 0.0; m_browserTabContent->getTranslation(m_translation); m_tabIndex = m_browserTabContent->getTabNumber(); m_zooming = m_browserTabContent->getScaling(); m_chartOverlaySet = m_chartTwoModel->getChartTwoOverlaySet(m_tabIndex); m_selectionItemDataType = selectionItemDataType; m_viewport[0] = viewport[0]; m_viewport[1] = viewport[1]; m_viewport[2] = viewport[2]; m_viewport[3] = viewport[3]; m_selectionItemAnnotation = m_brain->getSelectionManager()->getAnnotationIdentification(); m_selectionItemHistogram = m_brain->getSelectionManager()->getChartTwoHistogramIdentification(); m_selectionItemLineSeries = m_brain->getSelectionManager()->getChartTwoLineSeriesIdentification(); m_selectionItemMatrix = m_brain->getSelectionManager()->getChartTwoMatrixIdentification(); m_selectionItemChartLabel = m_brain->getSelectionManager()->getChartTwoLabelIdentification(); m_fixedPipelineDrawing->disableLighting(); /* * Find color bars for this tab and decrease height of * viewport so chart is above color bars. */ std::vector colorBars; m_browserTabContent->getAnnotationColorBars(colorBars); if ( ! colorBars.empty()) { int heightOfAllColorBars = 0; for (auto cb : colorBars) { bool useItFlag = false; switch (cb->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: useItFlag = true; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } if (useItFlag) { float bottomLeft[3], bottomRight[3], topRight[3], topLeft[3]; float viewportXYZ[3] = { 5.0, 5.0, 0.0 }; const bool boundsValid = cb->getShapeBounds(m_viewport[2], m_viewport[3], viewportXYZ, bottomLeft, bottomRight, topRight, topLeft); if (boundsValid) { heightOfAllColorBars += (topRight[1] - bottomRight[1]); } } } if (heightOfAllColorBars > 0) { const int32_t extraSpace = 5; heightOfAllColorBars += extraSpace; if (heightOfAllColorBars < viewport[3]) { m_viewport[1] += heightOfAllColorBars; m_viewport[3] -= heightOfAllColorBars; } } } bool drawHistogramFlag = true; bool drawLineSeriesFlag = true; bool drawMatrixFlag = true; /* * Check for a 'selection' type mode */ m_identificationModeFlag = false; switch (m_fixedPipelineDrawing->mode) { case BrainOpenGLFixedPipeline::MODE_DRAWING: break; case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: if ( (! m_selectionItemHistogram->isEnabledForSelection()) && (! m_selectionItemAnnotation->isEnabledForSelection()) && (! m_selectionItemChartLabel->isEnabledForSelection()) ) { drawHistogramFlag = false; } if ( (! m_selectionItemLineSeries->isEnabledForSelection()) && (! m_selectionItemAnnotation->isEnabledForSelection()) && (! m_selectionItemChartLabel->isEnabledForSelection()) ) { drawLineSeriesFlag = false; } if ( (! m_selectionItemMatrix->isEnabledForSelection()) && (! m_selectionItemAnnotation->isEnabledForSelection()) ) { drawMatrixFlag = false; } if (drawHistogramFlag || drawLineSeriesFlag || drawMatrixFlag) { m_identificationModeFlag = true; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } else { return; } break; case BrainOpenGLFixedPipeline::MODE_PROJECTION: return; break; } saveStateOfOpenGL(); if (m_chartOverlaySet != NULL) { const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); if (numberOfOverlays > 0) { ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); CaretAssert(topOverlay); CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; topOverlay->getSelectionData(mapFile, selectedIndexType, selectedIndex); if (mapFile != NULL) { const ChartTwoDataTypeEnum::Enum chartDataType = topOverlay->getChartTwoDataType(); switch (chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: if (drawHistogramFlag) { drawHistogramOrLineSeriesChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: if (drawLineSeriesFlag) { drawHistogramOrLineSeriesChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES); } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: if (drawMatrixFlag) { drawMatrixChart(); } break; } } } } restoreStateOfOpenGL(); annotationsOut = m_annotationsForDrawingOutput; } /** * Draw a histogram or line series chart. * * @param chartDataType * Type of chart to draw. */ void BrainOpenGLChartTwoDrawingFixedPipeline::drawHistogramOrLineSeriesChart(const ChartTwoDataTypeEnum::Enum chartDataType) { bool drawHistogramFlag = false; bool drawLineSeriesFlag = false; switch (chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: CaretAssert(0); return; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: drawHistogramFlag = true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: drawLineSeriesFlag = true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: CaretAssert(0); return; break; } const int32_t tabViewportX = m_viewport[0]; const int32_t tabViewportY = m_viewport[1]; const int32_t tabViewportWidth = m_viewport[2]; const int32_t tabViewportHeight = m_viewport[3]; int32_t chartGraphicsDrawingViewport[4] = { tabViewportX, tabViewportY, tabViewportWidth, tabViewportHeight }; const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); CaretAssert(numberOfOverlays > 0); const ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); if (drawHistogramFlag) { CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM); } else if (drawLineSeriesFlag) { CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES); } else { CaretAssert(0); } std::vector> histogramDrawingInfo; std::deque lineSeriesChartsToDraw; /* * Get the histogram drawing information and overall extent */ float xMinBottom = std::numeric_limits::max(); float xMaxBottom = -std::numeric_limits::max(); float xMinTop = std::numeric_limits::max(); float xMaxTop = -std::numeric_limits::max(); float yMinLeft = std::numeric_limits::max(); float yMaxLeft = -std::numeric_limits::max(); float yMinRight = std::numeric_limits::max(); float yMaxRight = -std::numeric_limits::max(); /* * Find histograms or line-series charts for drawing * and also find min/max coordinates on axes */ for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); if ( ! chartOverlay->isEnabled()) { continue; } CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; chartOverlay->getSelectionData(mapFile, selectedIndexType, selectedIndex); if (mapFile == NULL) { continue; } ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); if (drawHistogramFlag) { ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); if (histogramChart->isValid()) { CaretAssert(selectedIndexType == ChartTwoOverlay::SelectedIndexType::MAP); AString errorMessage; histogramDrawingInfo.push_back(std::unique_ptr(new HistogramChartDrawingInfo(histogramChart, selectedIndex, chartOverlay->getCartesianVerticalAxisLocation(), (chartOverlay->isAllMapsSupported() && chartOverlay->isAllMapsSelected())))); const Histogram* histogram = histogramChart->getHistogramForChartDrawing(selectedIndex, (chartOverlay->isAllMapsSupported() && chartOverlay->isAllMapsSelected())); if (histogram == NULL) { histogramDrawingInfo.pop_back(); continue; } float histogramMinX = 0.0, histogramMaxX = 0.0, histogramMaxY = 0.0; histogram->getRangeAndMaxDisplayHeight(histogramMinX, histogramMaxX, histogramMaxY); if (histogramMaxX > histogramMinX) { xMinBottom = std::min(xMinBottom, histogramMinX); xMaxBottom = std::max(xMaxBottom, histogramMaxX); xMinTop = std::min(xMinTop, histogramMinX); xMaxTop = std::max(xMaxTop, histogramMaxX); switch (chartOverlay->getCartesianVerticalAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: CaretAssertMessage(0, "TOP axis not allowed for vertical axis"); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: yMinRight = std::min(yMinRight, 0.0f); yMaxRight = std::max(yMaxRight, histogramMaxY); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: yMinLeft = std::min(yMinLeft, 0.0f); yMaxLeft = std::max(yMaxLeft, histogramMaxY); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: CaretAssertMessage(0, "BOTTOM axis not allowed for vertical axis"); break; } } } } if (drawLineSeriesFlag) { const ChartableTwoFileLineSeriesChart* lineSeriesChart = chartDelegate->getLineSeriesCharting(); const ChartTwoLineSeriesHistory* lineSeriesHistory = lineSeriesChart->getHistory(); const int32_t numHistory = lineSeriesHistory->getHistoryCount(); for (int32_t iHistory = (numHistory - 1); iHistory >= 0; iHistory--) { const ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(iHistory); CaretAssert(data); if (data->isSelected()) { BoundingBox boundingBox; if (data->getBounds(boundingBox)) { xMinBottom = std::min(xMinBottom, boundingBox.getMinX()); xMaxBottom = std::max(xMaxBottom, boundingBox.getMaxX()); xMinTop = std::min(xMinTop, boundingBox.getMinX()); xMaxTop = std::max(xMaxTop, boundingBox.getMaxX()); switch (chartOverlay->getCartesianVerticalAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: CaretAssertMessage(0, "TOP axis not allowed for vertical axis"); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: yMinRight = std::min(yMinRight, boundingBox.getMinY()); yMaxRight = std::max(yMaxRight, boundingBox.getMaxY()); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: yMinLeft = std::min(yMinLeft, boundingBox.getMinY()); yMaxLeft = std::max(yMaxLeft, boundingBox.getMaxY()); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: CaretAssertMessage(0, "BOTTOM axis not allowed for vertical axis"); break; } lineSeriesChartsToDraw.push_back(LineSeriesChartDrawingInfo(lineSeriesChart, data, chartOverlay->getCartesianVerticalAxisLocation())); } } } } } /* * Bounds valid? * For X, maximum value must be greater than minimum value * For Y, maximum value must be greater than or equal to minimum value since * all data points may be zero. */ const bool xBottomValid = (xMinBottom < xMaxBottom); const bool xTopValid = (xMinTop < xMaxTop); const bool xValid = (xBottomValid || xTopValid); const bool yLeftValid = (yMinLeft <= yMaxLeft); const bool yRightValid = (yMinRight <= yMaxRight); const bool yValid = (yLeftValid || yRightValid); if (xValid && yValid) { /* * Make invalid ranges zero */ if ( ! yLeftValid) { yMinLeft = 0.0; yMaxLeft = 0.0; } if ( ! yRightValid) { yMinRight = 0.0; yMaxRight = 0.0; } if ( ! xTopValid) { xMinTop = 0.0; xMaxTop = 0.0; } if ( ! xBottomValid) { xMinBottom = 0.0; xMaxBottom = 0.0; } ChartTwoCartesianAxis* leftAxis = NULL; ChartTwoCartesianAxis* rightAxis = NULL; ChartTwoCartesianAxis* bottomAxis = NULL; ChartTwoCartesianAxis* topAxis = NULL; std::vector displayedAxes; m_chartOverlaySet->getDisplayedChartAxes(displayedAxes); for (auto axis : displayedAxes) { CaretAssert(axis); switch (axis->getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: bottomAxis = axis; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: leftAxis = axis; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: rightAxis = axis; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: topAxis = axis; break; } } ChartTwoTitle* chartTitle = m_chartOverlaySet->getChartTitle(); GLint vp[4]; glGetIntegerv(GL_VIEWPORT, vp); glViewport(tabViewportX, tabViewportY, tabViewportWidth, tabViewportHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, tabViewportWidth, 0, tabViewportHeight, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); const float lineWidthPercentage = m_chartOverlaySet->getAxisLineThickness(); /* * Estimate size of title */ TitleDrawingInfo titleInfo(m_textRenderer, m_viewport, chartTitle); /* * Estimate axes sizes but at this point we can only find the * size one dimension (x or y) */ AxisDrawingInfo leftAxisInfo(m_textRenderer, m_viewport, xMinBottom, xMaxBottom, yMinLeft, yMaxLeft, ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT, leftAxis, m_chartOverlaySet->getAxisLabel(leftAxis), lineWidthPercentage); AxisDrawingInfo rightAxisInfo(m_textRenderer, m_viewport, xMinTop, xMaxTop, yMinRight, yMaxRight, ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT, rightAxis, m_chartOverlaySet->getAxisLabel(rightAxis), lineWidthPercentage); AxisDrawingInfo bottomAxisInfo(m_textRenderer, m_viewport, xMinBottom, xMaxBottom, yMinLeft, yMaxLeft, ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM, bottomAxis, m_chartOverlaySet->getAxisLabel(bottomAxis), lineWidthPercentage); AxisDrawingInfo topAxisInfo(m_textRenderer, m_viewport, xMinTop, xMaxTop, yMinLeft, yMaxLeft, ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP, topAxis, m_chartOverlaySet->getAxisLabel(topAxis), lineWidthPercentage); float topTitleHeight = titleInfo.m_titleHeight; const float topAxisHeight = topAxisInfo.m_axisHeight; if (titleInfo.m_titleDisplayedFlag) { topAxisInfo.m_axisHeight = 0.0f; } else { topTitleHeight = 0.0f; } const float bottomAxisHeight = bottomAxisInfo.m_axisHeight; const float leftAxisWidth = leftAxisInfo.m_axisWidth; const float rightAxisWidth = rightAxisInfo.m_axisWidth; /* * The constructors were only able to find width or height but not both. * Now we can find the other value. */ titleInfo.setTitleViewport(leftAxisWidth, rightAxisWidth); leftAxisInfo.setAxisViewport(topTitleHeight, bottomAxisHeight, topAxisHeight, leftAxisWidth, rightAxisWidth); rightAxisInfo.setAxisViewport(topTitleHeight, bottomAxisHeight, topAxisHeight, leftAxisWidth, rightAxisWidth); bottomAxisInfo.setAxisViewport(topTitleHeight, bottomAxisHeight, topAxisHeight, leftAxisWidth, rightAxisWidth); topAxisInfo.setAxisViewport(topTitleHeight, bottomAxisHeight, topAxisHeight, leftAxisWidth, rightAxisWidth); const float foregroundRGBA[4] = { m_fixedPipelineDrawing->m_foregroundColorFloat[0], m_fixedPipelineDrawing->m_foregroundColorFloat[1], m_fixedPipelineDrawing->m_foregroundColorFloat[2], 1.0f }; const float graphicsBoxLineThickness = convertPercentageOfViewportToOpenGLLineWidth(m_chartOverlaySet->getAxisLineThickness(), tabViewportHeight); leftAxisInfo.setLabelAndNumericsCoordinates(foregroundRGBA, graphicsBoxLineThickness); rightAxisInfo.setLabelAndNumericsCoordinates(foregroundRGBA, graphicsBoxLineThickness); bottomAxisInfo.setLabelAndNumericsCoordinates(foregroundRGBA, graphicsBoxLineThickness); topAxisInfo.setLabelAndNumericsCoordinates(foregroundRGBA, graphicsBoxLineThickness); const bool drawAxesFlag = createChartDrawingViewport(tabViewportX, tabViewportY, tabViewportWidth, tabViewportHeight, m_chartOverlaySet->getAxisLineThickness(), topTitleHeight, bottomAxisHeight, topAxisHeight, leftAxisWidth, rightAxisWidth, chartGraphicsDrawingViewport); if (drawAxesFlag) { titleInfo.drawTitle(foregroundRGBA); leftAxisInfo.drawAxis(this, m_chartOverlaySet, m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, foregroundRGBA, yMinLeft, yMaxLeft); rightAxisInfo.drawAxis(this, m_chartOverlaySet, m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, foregroundRGBA, yMinRight, yMaxRight); topAxisInfo.drawAxis(this, m_chartOverlaySet, m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, foregroundRGBA, xMinTop, xMaxTop); bottomAxisInfo.drawAxis(this, m_chartOverlaySet, m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, foregroundRGBA, xMinBottom, xMaxBottom); drawChartGraphicsBoxAndSetViewport(tabViewportX, tabViewportY, tabViewportWidth, tabViewportHeight, m_chartOverlaySet->getAxisLineThickness(), topTitleHeight, bottomAxisHeight, topAxisHeight, leftAxisWidth, rightAxisWidth, true, /* draw the box */ chartGraphicsDrawingViewport); } else { drawChartGraphicsBoxAndSetViewport(tabViewportX, tabViewportY, tabViewportWidth, tabViewportHeight, m_chartOverlaySet->getAxisLineThickness(), topTitleHeight, 0.0f, // bottomAxisHeight, 0.0f, //topAxisHeight, 0.0f, //leftAxisWidth, 0.0f, //rightAxisWidth, true, /* draw the box */ chartGraphicsDrawingViewport); } /* * When the user is editing an axis minimum or maximum value, * their difference may become zero which will cause * a problem with the orthographic projection. So * in this rare instance, make the maximum value * slightly larger than the minimum value. */ const float smallRange = 0.01; if (xMinBottom >= xMaxBottom) { xMaxBottom = xMinBottom + smallRange; } if (xMinTop >= xMaxTop) { xMaxTop = xMinBottom + smallRange; } if (yMinLeft >= yMaxLeft) { yMaxLeft = yMinLeft + smallRange; } if (yMinRight >= yMaxRight) { yMaxRight = yMinRight + smallRange; } glViewport(chartGraphicsDrawingViewport[0], chartGraphicsDrawingViewport[1], chartGraphicsDrawingViewport[2], chartGraphicsDrawingViewport[3]); if (drawHistogramFlag) { /* * Draw the bars for all histogram and then draw the envelopes * so the envelopes are not obscured by the bars */ for (auto& drawInfo : histogramDrawingInfo) { if (drawInfo->m_histogramChart->isValid()) { const CaretMappableDataFile* cmdf = drawInfo->m_histogramChart->getCaretMappableDataFile(); CaretAssert(cmdf); const PaletteColorMapping* paletteColorMapping = cmdf->getMapPaletteColorMapping(drawInfo->m_mapIndex); const bool drawBarsFlag = paletteColorMapping->isHistogramBarsVisible(); const bool drawEnvelopeFlag = paletteColorMapping->isHistogramEnvelopeVisible(); if (drawBarsFlag || drawEnvelopeFlag) { bool leftVerticalAxisFlag = true; switch (drawInfo->m_verticalAxisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: leftVerticalAxisFlag = false; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: break; } glMatrixMode(GL_PROJECTION); glLoadIdentity(); CaretAssert(xMinBottom < xMaxBottom); if (leftVerticalAxisFlag) { glOrtho(xMinBottom, xMaxBottom, yMinLeft, yMaxLeft, -10.0, 10.0); } else { glOrtho(xMinBottom, xMaxBottom, yMinRight, yMaxRight, -10.0, 10.0); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); bool applyTransformationsFlag = false; if (applyTransformationsFlag) { glTranslatef(m_translation[0], m_translation[1], 0.0); const float chartWidth = chartGraphicsDrawingViewport[2]; const float chartHeight = chartGraphicsDrawingViewport[3]; const float halfWidth = chartWidth / 2.0; const float halfHeight = chartHeight / 2.0; glTranslatef(halfWidth, halfHeight, 0.0); glScalef(m_zooming, m_zooming, 1.0); glTranslatef(-halfWidth, -halfHeight, 0.0); } /* * Save the transformation matrices and the viewport * If there is more than one line chart, this code will be executed * several times but since the top overlay is drawn last, the contents * of the top overlay will be used. */ updateViewportContentForCharting(chartGraphicsDrawingViewport); ChartableTwoFileHistogramChart::HistogramPrimitives* histogramPrimitives = drawInfo->m_histogramChart->getMapHistogramDrawingPrimitives(drawInfo->m_mapIndex, drawInfo->m_allMapsSelected); if (histogramPrimitives != NULL) { const float lineWidthPercentage = histogramPrimitives->getEnvelopeLineWidthPercentage(); if (m_identificationModeFlag) { int32_t primitiveIndex = -1; float primitiveDepth = 0.0; if (drawBarsFlag) { /* * Scale histogram bars in Y-axis so that identification * will function when mouse is above a bar. This is helpful * for identification of bars with a very small height. */ glPushMatrix(); glScalef(1.0, 1000.0, 1.0); GraphicsEngineDataOpenGL::drawWithSelection(histogramPrimitives->getBarsPrimitive(), m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, primitiveIndex, primitiveDepth); /* * Each bar is drawn using two triangles */ CaretAssert(histogramPrimitives->getBarsPrimitive()->getPrimitiveType() == GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES); if (primitiveIndex > 0) { primitiveIndex /= 2; } glPopMatrix(); } else if (drawEnvelopeFlag) { /* * Increase line width for identification */ histogramPrimitives->getEnvelopePrimitive()->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, (lineWidthPercentage + 0.5)); GraphicsEngineDataOpenGL::drawWithSelection(histogramPrimitives->getEnvelopePrimitive(), m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, primitiveIndex, primitiveDepth); } if (primitiveIndex >= 0) { if (m_selectionItemHistogram->isOtherScreenDepthCloserToViewer(primitiveDepth)) { m_selectionItemHistogram->setHistogramChart(const_cast(drawInfo->m_histogramChart), drawInfo->m_mapIndex, primitiveIndex, drawInfo->m_allMapsSelected); } } } else { drawPrimitivePrivate(histogramPrimitives->getThresholdPrimitive()); if (drawBarsFlag) { drawPrimitivePrivate(histogramPrimitives->getBarsPrimitive()); } if (drawEnvelopeFlag) { histogramPrimitives->getEnvelopePrimitive()->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, lineWidthPercentage); drawPrimitivePrivate(histogramPrimitives->getEnvelopePrimitive()); } } } } } } } if (drawLineSeriesFlag) { for (const auto lineChart : lineSeriesChartsToDraw) { bool leftVerticalAxisFlag = true; switch (lineChart.m_verticalAxisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: leftVerticalAxisFlag = false; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: break; } glMatrixMode(GL_PROJECTION); glLoadIdentity(); CaretAssert(xMinBottom < xMaxBottom); if (leftVerticalAxisFlag) { CaretAssert(yMinLeft < yMaxLeft); glOrtho(xMinBottom, xMaxBottom, yMinLeft, yMaxLeft, -10.0, 10.0); } else { CaretAssert(yMinRight < yMaxRight); glOrtho(xMinBottom, xMaxBottom, yMinRight, yMaxRight, -10.0, 10.0); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); bool applyTransformationsFlag = false; if (applyTransformationsFlag) { glTranslatef(m_translation[0], m_translation[1], 0.0f); const float chartWidth = chartGraphicsDrawingViewport[2]; const float chartHeight = chartGraphicsDrawingViewport[3]; const float halfWidth = chartWidth / 2.0f; const float halfHeight = chartHeight / 2.0f; glTranslatef(halfWidth, halfHeight, 0.0f); glScalef(m_zooming, m_zooming, 1.0f); glTranslatef(-halfWidth, -halfHeight, 0.0f); } if (m_identificationModeFlag) { int32_t primitiveIndex = -1; float primitiveDepth = 0.0f; GraphicsEngineDataOpenGL::drawWithSelection(lineChart.m_chartTwoCartesianData->getGraphicsPrimitive(), m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, primitiveIndex, primitiveDepth); if (primitiveIndex >= 0) { if (m_selectionItemLineSeries->isOtherScreenDepthCloserToViewer(primitiveDepth)) { m_selectionItemLineSeries->setLineSeriesChart(const_cast(lineChart.m_lineSeriesChart), const_cast(lineChart.m_chartTwoCartesianData), primitiveIndex); } } } else { GraphicsEngineDataOpenGL::draw(lineChart.m_chartTwoCartesianData->getGraphicsPrimitive()); } /* * Save the transformation matrices and the viewport * If there is more than one line chart, this code will be executed * several times but since the top overlay is drawn last, the contents * of the top overlay will be used. */ updateViewportContentForCharting(chartGraphicsDrawingViewport); } } } } /** * Draw a matrix chart. */ void BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChart() { const int32_t tabViewportX = m_viewport[0]; const int32_t tabViewportY = m_viewport[1]; const int32_t tabViewportWidth = m_viewport[2]; const int32_t tabViewportHeight = m_viewport[3]; int32_t chartGraphicsDrawingViewport[4] = { tabViewportX, tabViewportY, tabViewportWidth, tabViewportHeight }; /* * Estimate size of title */ float titleHeight = 0.0f; ChartTwoTitle* chartTitle = m_chartOverlaySet->getChartTitle(); TitleDrawingInfo titleInfo(m_textRenderer, m_viewport, chartTitle); float bottomMargin = 3.0f; float topMargin = 3.0f; float leftMargin = 3.0f; float rightMargin = 3.0f; if (titleInfo.m_titleDisplayedFlag) { topMargin = 0.0f; titleHeight = titleInfo.m_titleHeight; } titleInfo.setTitleViewport(leftMargin, rightMargin); glViewport(tabViewportX, tabViewportY, tabViewportWidth, tabViewportHeight); const float foregroundRGBA[4] = { m_fixedPipelineDrawing->m_foregroundColorFloat[0], m_fixedPipelineDrawing->m_foregroundColorFloat[1], m_fixedPipelineDrawing->m_foregroundColorFloat[2], 1.0f }; titleInfo.drawTitle(foregroundRGBA); drawChartGraphicsBoxAndSetViewport(tabViewportX, tabViewportY, tabViewportWidth, tabViewportHeight, m_chartOverlaySet->getAxisLineThickness(), titleHeight, bottomMargin, topMargin, leftMargin, rightMargin, false, /* do not draw box */ chartGraphicsDrawingViewport); glViewport(chartGraphicsDrawingViewport[0], chartGraphicsDrawingViewport[1], chartGraphicsDrawingViewport[2], chartGraphicsDrawingViewport[3]); bool applyTransformationsFlag = true; float cellWidth = 1.0; float cellHeight = 1.0; /* * Setup width/height of area in which matrix is drawn with a * small margin along all of the edges */ float margin = 10.0; if ((m_viewport[2] < (margin * 3.0)) || (m_viewport[3] < (margin * 3.0))) { margin = 0.0; } const float graphicsWidth = chartGraphicsDrawingViewport[2]; const float graphicsHeight = chartGraphicsDrawingViewport[3]; /* * First overlay is ALWAYS ON and since all matrices must have * same number of rows/columns, use first matrix for rows/columns */ const int32_t numberOfOverlays = m_chartOverlaySet->getNumberOfDisplayedOverlays(); CaretAssert(numberOfOverlays > 0); const ChartTwoOverlay* topOverlay = m_chartOverlaySet->getOverlay(0); const ChartTwoCompoundDataType cdt = topOverlay->getChartTwoCompoundDataType(); CaretAssert(cdt.getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX); const int32_t numberOfRows = cdt.getMatrixNumberOfRows(); const int32_t numberOfCols = cdt.getMatrixNumberOfColumns(); if ((numberOfRows > 0) && (numberOfCols > 0)) { cellWidth = graphicsWidth / numberOfCols; cellHeight = graphicsHeight / numberOfRows; } else { return; } /* * Set the width and neight of each matrix cell. */ const ChartTwoMatrixDisplayProperties* matrixProperties = m_browserTabContent->getChartTwoMatrixDisplayProperties(); CaretAssert(matrixProperties); const float cellWidthZoom = matrixProperties->getCellPercentageZoomWidth() / 100.0; const float cellHeightZoom = matrixProperties->getCellPercentageZoomHeight() / 100.0; if ((cellWidthZoom > 0.0) && (cellHeightZoom > 0.0)) { cellWidth *= cellWidthZoom; cellHeight *= cellHeightZoom; } /* * Set the coordinates for the area in which the matrix is drawn. */ margin = 0.0; const float xMin = -margin; const float xMax = graphicsWidth + margin; const float yMin = -margin; const float yMax = graphicsHeight + margin; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(xMin, xMax, yMin, yMax, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); if (applyTransformationsFlag) { glTranslatef(m_translation[0], m_translation[1], 0.0); const float chartWidth = cellWidth * numberOfCols; const float chartHeight = cellHeight * numberOfRows; const float halfWidth = chartWidth / 2.0; const float halfHeight = chartHeight / 2.0; glTranslatef(halfWidth, halfHeight, 0.0); glScalef(m_zooming, m_zooming, 1.0); glTranslatef(-halfWidth, -halfHeight, 0.0); } /* * Save the transformation matrices and the viewport * If there is more than one line chart, this code will be executed * several times but since the top overlay is drawn last, the contents * of the top overlay will be used. */ updateViewportContentForCharting(chartGraphicsDrawingViewport); std::vector rowColumnHighlighting; for (int32_t iOverlay = (numberOfOverlays - 1); iOverlay >= 0; iOverlay--) { ChartTwoOverlay* chartOverlay = m_chartOverlaySet->getOverlay(iOverlay); if ( ! chartOverlay->isEnabled()) { continue; } CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; chartOverlay->getSelectionData(mapFile, selectedIndexType, selectedIndex); if (mapFile == NULL) { continue; } const ChartableTwoFileMatrixChart* matrixChart = mapFile->getChartingDelegate()->getMatrixCharting(); int32_t overlayRows = 0; int32_t overlayColumns = 0; matrixChart->getMatrixDimensions(overlayRows, overlayColumns); /* * All matrices must have same rows/columns */ if ((overlayRows == numberOfRows) && (overlayColumns == numberOfCols)) { drawMatrixChartContent(matrixChart, chartOverlay->getMatrixTriangularViewingMode(), cellWidth, cellHeight, m_zooming, rowColumnHighlighting); } } /* * Row/column highlighting must be drawn after matrices to that * the highlights are over any and all displayed matrices */ const int32_t numHighlights = static_cast(rowColumnHighlighting.size()); if (numHighlights > 0) { for (int32_t ctr = 0; ctr < numHighlights; ctr++) { MatrixRowColumnHighight* mrch = rowColumnHighlighting[ctr]; CaretAssert(mrch); glPushMatrix(); glLoadMatrixf(mrch->m_modelViewMatrix); drawPrimitivePrivate(mrch->m_graphicsPrimitive.get()); delete mrch; glPopMatrix(); } rowColumnHighlighting.clear(); } } /* * Draw a matrix chart content. * * @param matrixChart * Matrix chart that is drawn. * @param chartViewingType * Type of chart viewing. * @param cellWidth * Width of cell. * @param cellHeight * Height of cell. * @param zooming * Current zooming. */ void BrainOpenGLChartTwoDrawingFixedPipeline::drawMatrixChartContent(const ChartableTwoFileMatrixChart* matrixChart, const ChartTwoMatrixTriangularViewingModeEnum::Enum chartViewingType, const float cellWidth, const float cellHeight, const float /*zooming*/, std::vector& rowColumnHighlightingOut) { GraphicsPrimitiveV3fC4f* matrixPrimitive = matrixChart->getMatrixChartingGraphicsPrimitive(chartViewingType, CiftiMappableDataFile::MatrixGridMode::FILLED); if (matrixPrimitive == NULL) { return; } if (m_identificationModeFlag) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } glPushMatrix(); glScalef(cellWidth, cellHeight, 1.0); /* * Enable alpha blending so voxels that are not drawn from higher layers * allow voxels from lower layers to be seen. */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); if (m_identificationModeFlag) { int32_t primitiveIndex = -1; float primitiveDepth = 0.0; GraphicsEngineDataOpenGL::drawWithSelection(matrixPrimitive, m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, primitiveIndex, primitiveDepth); if (primitiveIndex >= 0) { /* * Two triangles per cell so divided the primitive index by two */ CaretAssert(matrixPrimitive->getPrimitiveType() == GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES); primitiveIndex /= 2; int32_t numberOfRows = 0; int32_t numberOfColumns = 0; matrixChart->getMatrixDimensions(numberOfRows, numberOfColumns); const int32_t rowIndex = primitiveIndex / numberOfColumns; const int32_t colIndex = primitiveIndex % numberOfColumns; if (m_selectionItemMatrix->isOtherScreenDepthCloserToViewer(primitiveDepth)) { m_selectionItemMatrix->setMatrixChart(const_cast(matrixChart), rowIndex, colIndex); } } } else { drawPrimitivePrivate(matrixPrimitive); const ChartTwoMatrixDisplayProperties* matrixProperties = m_browserTabContent->getChartTwoMatrixDisplayProperties(); CaretAssert(matrixProperties); if (matrixProperties->isGridLinesDisplayed()) { GraphicsPrimitiveV3fC4f* matrixGridPrimitive = matrixChart->getMatrixChartingGraphicsPrimitive(chartViewingType, CiftiMappableDataFile::MatrixGridMode::OUTLINE); drawPrimitivePrivate(matrixGridPrimitive); } int32_t numberOfRows = 0; int32_t numberOfColumns = 0; matrixChart->getMatrixDimensions(numberOfRows, numberOfColumns); if (matrixProperties->isSelectedRowColumnHighlighted()) { uint8_t highlightRGBByte[3]; m_preferences->getBackgroundAndForegroundColors()->getColorForegroundChartView(highlightRGBByte); const float highlightRGBA[4] = { highlightRGBByte[0] / 255.0f, highlightRGBByte[1] / 255.0f, highlightRGBByte[2] / 255.0f, 1.0f }; std::vector selectedColumnIndices; std::vector selectedRowIndices; ChartTwoMatrixLoadingDimensionEnum::Enum selectedRowColumnDimension; matrixChart->getSelectedRowColumnIndices(m_tabIndex, selectedRowColumnDimension, selectedRowIndices, selectedColumnIndices); /* * If true, selected row highlighting will be limited * to a upper or lower triangular cells when * triangular display is selected * Disabled by WB-741 */ const bool limitSelectionToTriangularFlag = false; const float lineWidthPercentageHeight = 1.0f; for (auto rowIndex : selectedRowIndices) { float minX = 0; float maxX = numberOfColumns; const float minY = numberOfRows - rowIndex - 1; const float maxY = minY + 1.0f; if (limitSelectionToTriangularFlag) { switch (chartViewingType) { case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: break; case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: break; case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: maxX = rowIndex; /* matrix is symmetric */ break; case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: minX = rowIndex + 1; /* matrix is symmetric */ break; } } GraphicsPrimitiveV3fC4f* rowOutlineData = GraphicsPrimitiveV3fC4f::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN); rowOutlineData->reserveForNumberOfVertices(4); rowOutlineData->addVertex(minX, minY, highlightRGBA); rowOutlineData->addVertex(maxX, minY, highlightRGBA); rowOutlineData->addVertex(maxX, maxY, highlightRGBA); rowOutlineData->addVertex(minX, maxY, highlightRGBA); rowOutlineData->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, lineWidthPercentageHeight); float modelViewMatrix[16]; glGetFloatv(GL_MODELVIEW_MATRIX, modelViewMatrix); rowColumnHighlightingOut.push_back(new MatrixRowColumnHighight(rowOutlineData, modelViewMatrix)); } for (auto columnIndex : selectedColumnIndices) { const float minX = columnIndex; const float maxX = columnIndex + 1; float minY = 0; float maxY = numberOfRows; if (limitSelectionToTriangularFlag) { switch (chartViewingType) { case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: break; case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: break; case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: maxY = columnIndex; /* matrix is symmetric */ break; case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: minY = columnIndex + 1; /* matrix is symmetric */ break; } } // const float highlightLineWidth = std::max(((zooming) * 0.20), 3.0); GraphicsPrimitiveV3fC4f* columnOutlineData = GraphicsPrimitiveV3fC4f::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN); columnOutlineData->reserveForNumberOfVertices(4); columnOutlineData->addVertex(minX, minY, highlightRGBA); columnOutlineData->addVertex(maxX, minY, highlightRGBA); columnOutlineData->addVertex(maxX, maxY, highlightRGBA); columnOutlineData->addVertex(minX, maxY, highlightRGBA); columnOutlineData->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, lineWidthPercentageHeight); float modelViewMatrix[16]; glGetFloatv(GL_MODELVIEW_MATRIX, modelViewMatrix); rowColumnHighlightingOut.push_back(new MatrixRowColumnHighight(columnOutlineData, modelViewMatrix)); } } } glDisable(GL_BLEND); glPopMatrix(); } /** * Save the state of OpenGL. * Copied from Qt's qgl.cpp, qt_save_gl_state(). */ void BrainOpenGLChartTwoDrawingFixedPipeline::saveStateOfOpenGL() { glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); glPushAttrib(GL_ALL_ATTRIB_BITS); glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glShadeModel(GL_FLAT); glDisable(GL_LIGHTING); glDisable(GL_STENCIL_TEST); glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); } /** * Restore the state of OpenGL. * Copied from Qt's qgl.cpp, qt_restore_gl_state(). */ void BrainOpenGLChartTwoDrawingFixedPipeline::restoreStateOfOpenGL() { glMatrixMode(GL_TEXTURE); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glPopAttrib(); glPopClientAttrib(); } /** * Convert a percentage of viewport width or height to an OpenGL Line Width. * When percentage width or height is zero, zero will be returned. * Otherwise the returned value will ALWAYS be at least one. * * * @param percentageWidthOrHeight * The percentage of width or height (ranges 0.0 to 100.0). * @param viewportWidthOrHeight * The viewport width or height. * @return * Pixels size value. */ float BrainOpenGLChartTwoDrawingFixedPipeline::convertPercentageOfViewportToOpenGLLineWidth(const float percentageWidthOrHeight, const float viewportWidthOrHeight) { if (percentageWidthOrHeight <= 0.0f) { return 0.0f; } float pixelsWidthOrHeight = ((percentageWidthOrHeight / 100.0f) * viewportWidthOrHeight); if (pixelsWidthOrHeight < s_minimumLineWidthOpenGL) { pixelsWidthOrHeight = s_minimumLineWidthOpenGL; } // if (pixelsWidthOrHeight > s_maximumLineWidthOpenGL) { // pixelsWidthOrHeight = s_maximumLineWidthOpenGL; // } return pixelsWidthOrHeight; } /** * Convert a percentage of viewport width or height to pixels. * When percentage width or height is zero, zero will be returned. * Otherwise the returned value will ALWAYS be at least one. * * @param percentageWidthOrHeight * The percentage of width or height (ranges 0.0 to 100.0). * @param viewportWidthOrHeight * The viewport width or height. * @return * Pixels size value. */ float BrainOpenGLChartTwoDrawingFixedPipeline::convertPercentageOfViewportToPixels(const float percentageWidthOrHeight, const float viewportWidthOrHeight) { if (percentageWidthOrHeight <= 0.0f) { return 0.0f; } float pixelsWidthOrHeight = ((percentageWidthOrHeight / 100.0f) * viewportWidthOrHeight); return pixelsWidthOrHeight; } /** * Draw the chart graphics surrounding box and set the graphics viewport. * * @param vpX * Viewport X * @param vpY * Viewport Y * @param vpWidth * Viewport width * @param vpHeight * Viewport height * @param lineThicknessPercentage * Thickness of lines in percentage of viewport height * @param titleHeight * Height of the title * @param bottomAxisHeight * Height of bottom axis * @param topAxisHeight * Height of top axis * @param leftAxisWidth * Width of left axis * @param rightAxisWidth * Width of right axis * @param drawBoxFlag * Controls drawing of box. * @param chartGraphicsDrawingViewportOut * Output containing viewport for drawing chart graphics within * the box/grid that is adjusted for the box's line thickness. */ void BrainOpenGLChartTwoDrawingFixedPipeline::drawChartGraphicsBoxAndSetViewport(const float vpX, const float vpY, const float vpWidth, const float vpHeight, const float lineThicknessPercentage, const float titleHeight, const float bottomAxisHeight, const float topAxisHeight, const float leftAxisWidth, const float rightAxisWidth, const bool drawBoxFlag, int32_t chartGraphicsDrawingViewportOut[4]) { const float lineThicknessPixels = convertPercentageOfViewportToOpenGLLineWidth(lineThicknessPercentage, vpHeight); const float halfGridLineWidth = lineThicknessPixels / 2.0; glViewport(vpX, vpY, vpWidth, vpHeight); if (drawBoxFlag) { /* * For box, set coordinates for the middle of the line */ const float boxLeft = leftAxisWidth + halfGridLineWidth; const float boxRight = vpWidth - rightAxisWidth - halfGridLineWidth; const float boxBottom = bottomAxisHeight + halfGridLineWidth; const float boxTop = vpHeight - topAxisHeight - titleHeight - halfGridLineWidth; /* * We adjust the horizontal lines by half the line width. * Otherwise, there will be 'corner gaps' where the horizontal * and vertical lines are joined */ std::unique_ptr boxData = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN, m_fixedPipelineDrawing->m_foregroundColorFloat)); boxData->reserveForNumberOfVertices(4); boxData->addVertex(boxLeft, boxBottom); boxData->addVertex(boxRight, boxBottom); boxData->addVertex(boxRight, boxTop); boxData->addVertex(boxLeft, boxTop); boxData->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, lineThicknessPercentage); drawPrimitivePrivate(boxData.get()); } /* * Region INSIDE the grid's box so that any data plots * are WITHIN the box */ const float graphicsLeft = vpX + leftAxisWidth + lineThicknessPixels; const float graphicsRight = vpX + vpWidth - rightAxisWidth - lineThicknessPixels; const float graphicsBottom = vpY + bottomAxisHeight + lineThicknessPixels; const float graphicsTop = vpY + vpHeight - topAxisHeight - titleHeight - lineThicknessPixels; const int32_t graphicsWidth = graphicsRight - graphicsLeft; const int32_t graphicsHeight = graphicsTop - graphicsBottom; chartGraphicsDrawingViewportOut[0] = graphicsLeft; chartGraphicsDrawingViewportOut[1] = graphicsBottom; chartGraphicsDrawingViewportOut[2] = graphicsWidth; chartGraphicsDrawingViewportOut[3] = graphicsHeight; CaretAssert(graphicsWidth > 0); CaretAssert(graphicsHeight > 0); } /** * Create the graphics viewport. * * @param vpX * Viewport X * @param vpY * Viewport Y * @param vpWidth * Viewport width * @param vpHeight * Viewport height * @param lineThicknessPercentage * Thickness of lines in percentage of viewport height * @param titleHeight * Height of the title * @param bottomAxisHeight * Height of bottom axis * @param topAxisHeight * Height of top axis * @param leftAxisWidth * Width of left axis * @param rightAxisWidth * Width of right axis * @param chartGraphicsDrawingViewportOut * Output containing viewport for drawing chart graphics within * the box/grid that is adjusted for the box's line thickness. * @return * True if axes should be drawn, otherwise false. When chart * gets too small, axes are not drawn. */ bool BrainOpenGLChartTwoDrawingFixedPipeline::createChartDrawingViewport(const float vpX, const float vpY, const float vpWidth, const float vpHeight, const float lineThicknessPercentage, const float titleHeight, const float bottomAxisHeight, const float topAxisHeight, const float leftAxisWidth, const float rightAxisWidth, int32_t chartGraphicsDrawingViewportOut[4]) { const float lineThicknessPixels = convertPercentageOfViewportToOpenGLLineWidth(lineThicknessPercentage, vpHeight); /* * Region INSIDE the grid's box so that any data plots * are WITHIN the box */ float graphicsLeft = vpX + leftAxisWidth + lineThicknessPixels; float graphicsRight = vpX + vpWidth - rightAxisWidth - lineThicknessPixels; float graphicsBottom = vpY + bottomAxisHeight + lineThicknessPixels; float graphicsTop = vpY + vpHeight - topAxisHeight - titleHeight - lineThicknessPixels; int32_t graphicsWidth = graphicsRight - graphicsLeft; int32_t graphicsHeight = graphicsTop - graphicsBottom; bool drawAxesFlag = true; const int32_t minViewportSize = 20; if ((graphicsWidth < minViewportSize) || (graphicsHeight < minViewportSize)) { graphicsLeft = vpX; graphicsRight = vpX + vpWidth; graphicsBottom = vpY; graphicsTop = vpY + vpHeight; graphicsWidth = graphicsRight - graphicsLeft; graphicsHeight = graphicsTop - graphicsBottom; drawAxesFlag = false; } chartGraphicsDrawingViewportOut[0] = graphicsLeft; chartGraphicsDrawingViewportOut[1] = graphicsBottom; chartGraphicsDrawingViewportOut[2] = graphicsWidth; chartGraphicsDrawingViewportOut[3] = graphicsHeight; CaretAssert(graphicsWidth > 0); CaretAssert(graphicsHeight > 0); return drawAxesFlag; } /** * Update the viewport content with charting viewport and matrices. * * @param viewport * The viewport. */ void BrainOpenGLChartTwoDrawingFixedPipeline::updateViewportContentForCharting(const int32_t viewport[4]) { CaretAssert(viewport[2] > 0); CaretAssert(viewport[3] > 0); GLfloat modelviewArray[16]; glGetFloatv(GL_MODELVIEW_MATRIX, modelviewArray); GLfloat projectionArray[16]; glGetFloatv(GL_PROJECTION_MATRIX, projectionArray); Matrix4x4 modelviewMatrix; modelviewMatrix.setMatrixFromOpenGL(modelviewArray); Matrix4x4 projectionMatrix; projectionMatrix.setMatrixFromOpenGL(projectionArray); m_viewportContent->setChartDataMatricesAndViewport(projectionMatrix, modelviewMatrix, viewport); } /** * Draw the graphics primitive. * * @param primitive * Primitive that will be drawn. */ void BrainOpenGLChartTwoDrawingFixedPipeline::drawPrimitivePrivate(GraphicsPrimitive* primitive) { if (primitive == NULL) { return; } GraphicsEngineDataOpenGL::draw(primitive); } /** * Constructor. * * @param histogramChart * The file's histogram charting * @param mapIndex * Index of the map for which histogram is displayed. * @param verticalAxisLocation * Location of vertical axis for the histogram * @param allMapsSelected * True if ALL MAPS selected for histogram, else false. */ BrainOpenGLChartTwoDrawingFixedPipeline::HistogramChartDrawingInfo::HistogramChartDrawingInfo(ChartableTwoFileHistogramChart* histogramChart, int32_t mapIndex, ChartAxisLocationEnum::Enum verticalAxisLocation, const bool allMapsSelected) : m_histogramChart(histogramChart), m_mapIndex(mapIndex), m_verticalAxisLocation(verticalAxisLocation), m_allMapsSelected(allMapsSelected) { } /** * Destructor. */ BrainOpenGLChartTwoDrawingFixedPipeline::HistogramChartDrawingInfo::~HistogramChartDrawingInfo() { } /** * Constructor. * * @param textRenderer * The text renderer. * @param tabViewport * Viewport of the tab containing the chart. * @param dataMinX * Minimum X-data value. * @param dataMaxX * Maximum X-data value. * @param dataMinY * Minimum Y-data value. * @param dataMaxX * Maximum Y-data value. * @param axisLocation * Location of axis as 'axis' may be NULL. * @param axis * Axis being setup. * @param labelText * Text for the label. * @param lineWidthPercentage * The line width percentage. */ BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::AxisDrawingInfo(BrainOpenGLTextRenderInterface* textRenderer, const int32_t tabViewport[4], const float dataMinX, const float dataMaxX, const float dataMinY, const float dataMaxY, const ChartAxisLocationEnum::Enum axisLocation, const ChartTwoCartesianAxis* axis, const AString& labelText, const float lineWidthPercentage) : m_axisLocation(axisLocation), m_axis(axis), m_textRenderer(textRenderer), m_tabViewportWidth(tabViewport[2]), m_tabViewportHeight(tabViewport[3]) { m_axisValid = false; m_axisWidth = 0.0f; m_axisHeight = 0.0f; switch (axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: m_axisMinimumValue = dataMinX; m_axisMaximumValue = dataMaxX; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: m_axisMinimumValue = dataMinY; m_axisMaximumValue = dataMaxY; break; } float dataMinimumValue = m_axisMinimumValue; float dataMaximumValue = m_axisMaximumValue; m_axisDisplayedFlag = false; if (m_axis != NULL) { CaretAssert(m_axis->getAxisLocation() == axisLocation); m_axisDisplayedFlag = (axis->isEnabledByChart() && axis->isDisplayedByUser()); } if ( ! m_axisDisplayedFlag) { /* * If axis is not displayed, use padding with a small percentage of space. */ const float emptyAxisPaddingPercentage = 1.0f; switch (axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: m_axisHeight = convertPercentageOfViewportToPixels(emptyAxisPaddingPercentage, m_tabViewportHeight); m_labelPaddingSizePixels = m_axisHeight; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: m_axisWidth = convertPercentageOfViewportToPixels(emptyAxisPaddingPercentage, m_tabViewportWidth); m_labelPaddingSizePixels = m_axisWidth; break; } /* * This is necessary so that the correct axis minimum and * maximum values (m_axisMinimumValue and m_axisMaximumValue). */ if (m_axis != NULL) { std::vector scaleValuePositions; std::vector scaleValuesText; m_axis->getScaleValuesAndOffsets(dataMinimumValue, dataMaximumValue, 1.0, m_axisMinimumValue, m_axisMaximumValue, scaleValuePositions, scaleValuesText); } return; } if (m_axis == NULL) { return; } m_axisValid = true; /* * Padding values are percentages so convert to pixels. */ const float numericsTicksPaddingPercentage = 1.0f; m_labelPaddingSizePixels = 0.0f; m_numericsTicksPaddingSizePixels = 0.0f; switch (axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: m_labelPaddingSizePixels = convertPercentageOfViewportToPixels(axis->getPaddingSize(), m_tabViewportHeight); m_numericsTicksPaddingSizePixels = convertPercentageOfViewportToPixels(numericsTicksPaddingPercentage, m_tabViewportHeight); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: m_labelPaddingSizePixels = convertPercentageOfViewportToPixels(axis->getPaddingSize(), m_tabViewportHeight); m_numericsTicksPaddingSizePixels = convertPercentageOfViewportToPixels(numericsTicksPaddingPercentage, m_tabViewportHeight); break; } m_lineDrawingWidth = convertPercentageOfViewportToOpenGLLineWidth(lineWidthPercentage, m_tabViewportHeight); m_tickLength = 0.0f; if (m_axis->isShowTickmarks()) { const float tickLengthPercentage = 1.0f; m_tickLength = convertPercentageOfViewportToOpenGLLineWidth(tickLengthPercentage, m_tabViewportHeight); //m_tickLength = m_lineDrawingWidth; // * 2.0f; } /* * Width/height of label */ initializeLabel(labelText, m_labelWidth, m_labelHeight); /* * Maximum width/height of numeric values */ float numericsWidth = 0.0f; float numericsHeight = 0.0f; initializeNumericText(dataMinimumValue, dataMaximumValue, m_axis->isNumericsTextDisplayed(), m_axis->isNumericsTextRotated(), numericsWidth, numericsHeight); /* * For the bottom and the top, we now have its height but we do not yet know its width * and likewise for left and right. */ switch (axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: m_axisHeight = std::ceil(m_labelPaddingSizePixels + m_labelHeight + numericsHeight + m_numericsTicksPaddingSizePixels + m_tickLength); CaretAssert(m_axisHeight >= 0.0f); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: /* Note: label is rotated on left/right so use it's height */ m_axisWidth = std::ceil(m_labelPaddingSizePixels + m_labelHeight + numericsWidth + m_numericsTicksPaddingSizePixels + m_tickLength); CaretAssert(m_axisWidth >= 0.0f); break; } } /** * Initialize the numeric label by creating an annotation for the label * and determining the width and height of the label. * * @param labelText * Text of the label. * @param widthOut * Output with width of label. * @param heightOut * Output with hight of label. */ void BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::initializeLabel(const AString& labelText, float& widthOut, float& heightOut) { widthOut = 0.0f; heightOut = 0.0f; if (m_axis == NULL) { return; } AnnotationPercentSizeText* text = new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); if (m_axis->isShowLabel()) { float xyz[3] = { 0.0f, 0.0f, 0.0f }; switch (m_axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: xyz[0] = 0.5f; text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: xyz[0] = 0.5f; text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: xyz[1] = 0.5f; text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); text->setRotationAngle(-90.0f); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: xyz[1] = 0.5f; text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); text->setRotationAngle(-90.0f); break; } text->setText(labelText); text->setFontPercentViewportSize(m_axis->getLabelTextSize()); text->getCoordinate()->setXYZ(xyz); double textWidth = 0.0; double textHeight = 0.0; m_textRenderer->getTextWidthHeightInPixels(*text, BrainOpenGLTextRenderInterface::DrawingFlags(), m_tabViewportWidth, m_tabViewportHeight, textWidth, textHeight); widthOut = textWidth; heightOut = textHeight; } m_labelText.reset(text); } /** * Initialize the numeric text by creating an annotation for each numeric value * and find the maximum width and height of the numeric values. * * @param dataMinimumDataValue * Minimum data value for axis * @param dataMaximumDataValue * Maximum data value for axis * @param showNumericFlag, * Show numerics * @param rotateNumericFlag * Rotate numerics. * @param maxWidthOut * Output with maximum width of numeric text. * @param maxHeightOut * Output with maximum height of numeric text. */ void BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::initializeNumericText(const float dataMinimumDataValue, const float dataMaximumDataValue, const bool showNumericFlag, const bool rotateNumericFlag, float& maxWidthOut, float& maxHeightOut) { maxWidthOut = 0.0f; maxHeightOut = 0.0f; if (m_axis == NULL) { return; } /* * Using an axis length of 1.0 will result in the * offsets ranging (0.0 to 1.0) */ const float axisLength = 1.0; std::vector scaleValuePositions; std::vector scaleValuesText; m_axis->getScaleValuesAndOffsets(dataMinimumDataValue, dataMaximumDataValue, axisLength, m_axisMinimumValue, m_axisMaximumValue, scaleValuePositions, scaleValuesText); /* * For each numeric value, create a text annotation and determine the * width and height of the text. Also, set either the X or Y-coordinate * with the normalized coordinate (zero to one) that will be used * later to position the numeric value. */ CaretAssert(scaleValuePositions.size() == scaleValuesText.size()); const int32_t numValues = static_cast(scaleValuesText.size()); const int32_t firstIndex = 0; const int32_t lastIndex = (numValues - 1); for (int32_t i = 0; i < numValues; i++) { AnnotationPercentSizeText* text = new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); text->setFontPercentViewportSize(m_axis->getNumericsTextSize()); if (rotateNumericFlag) { text->setRotationAngle(-90.0f); } float xyz[3] = { 0.0f, 0.0f, 0.0f }; AnnotationTextAlignVerticalEnum::Enum verticalAlignment = AnnotationTextAlignVerticalEnum::MIDDLE; AnnotationTextAlignHorizontalEnum::Enum horizontalAlignment = AnnotationTextAlignHorizontalEnum::CENTER; switch (m_axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: xyz[0] = scaleValuePositions[i]; if (rotateNumericFlag) { horizontalAlignment = AnnotationTextAlignHorizontalEnum::RIGHT; if (i == firstIndex) { verticalAlignment = AnnotationTextAlignVerticalEnum::TOP; } else if (i == lastIndex) { verticalAlignment = AnnotationTextAlignVerticalEnum::BOTTOM; } else { verticalAlignment = AnnotationTextAlignVerticalEnum::MIDDLE; } } else { verticalAlignment = AnnotationTextAlignVerticalEnum::TOP; if (i == firstIndex) { horizontalAlignment = AnnotationTextAlignHorizontalEnum::LEFT; } else if (i == lastIndex) { horizontalAlignment = AnnotationTextAlignHorizontalEnum::RIGHT; } else { horizontalAlignment = AnnotationTextAlignHorizontalEnum::CENTER; } } break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: xyz[0] = scaleValuePositions[i]; if (rotateNumericFlag) { horizontalAlignment = AnnotationTextAlignHorizontalEnum::LEFT; if (i == firstIndex) { verticalAlignment = AnnotationTextAlignVerticalEnum::TOP; } else if (i == lastIndex) { verticalAlignment = AnnotationTextAlignVerticalEnum::BOTTOM; } else { verticalAlignment = AnnotationTextAlignVerticalEnum::MIDDLE; } } else { verticalAlignment = AnnotationTextAlignVerticalEnum::BOTTOM; if (i == firstIndex) { horizontalAlignment = AnnotationTextAlignHorizontalEnum::LEFT; } else if (i == lastIndex) { horizontalAlignment = AnnotationTextAlignHorizontalEnum::RIGHT; } else { horizontalAlignment = AnnotationTextAlignHorizontalEnum::CENTER; } } break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: xyz[1] = scaleValuePositions[i]; if (rotateNumericFlag) { verticalAlignment = AnnotationTextAlignVerticalEnum::BOTTOM; if (i == firstIndex) { horizontalAlignment = AnnotationTextAlignHorizontalEnum::LEFT; } else if (i == lastIndex) { horizontalAlignment = AnnotationTextAlignHorizontalEnum::RIGHT; } else { horizontalAlignment = AnnotationTextAlignHorizontalEnum::CENTER; } } else { horizontalAlignment = AnnotationTextAlignHorizontalEnum::RIGHT; if (i == firstIndex) { verticalAlignment = AnnotationTextAlignVerticalEnum::BOTTOM; } else if (i == lastIndex) { verticalAlignment = AnnotationTextAlignVerticalEnum::TOP; } else { verticalAlignment = AnnotationTextAlignVerticalEnum::MIDDLE; } } break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: xyz[1] = scaleValuePositions[i]; if (rotateNumericFlag) { verticalAlignment = AnnotationTextAlignVerticalEnum::TOP; if (i == firstIndex) { horizontalAlignment = AnnotationTextAlignHorizontalEnum::LEFT; } else if (i == lastIndex) { horizontalAlignment = AnnotationTextAlignHorizontalEnum::RIGHT; } else { horizontalAlignment = AnnotationTextAlignHorizontalEnum::CENTER; } } else { horizontalAlignment = AnnotationTextAlignHorizontalEnum::LEFT; if (i == firstIndex) { verticalAlignment = AnnotationTextAlignVerticalEnum::BOTTOM; } else if (i == lastIndex) { verticalAlignment = AnnotationTextAlignVerticalEnum::TOP; } else { verticalAlignment = AnnotationTextAlignVerticalEnum::MIDDLE; } } break; } text->setHorizontalAlignment(horizontalAlignment); text->setVerticalAlignment(verticalAlignment); if (showNumericFlag) { text->setText(scaleValuesText[i]); } text->getCoordinate()->setXYZ(xyz); double textWidth = 0.0; double textHeight = 0.0; m_textRenderer->getTextWidthHeightInPixels(*text, BrainOpenGLTextRenderInterface::DrawingFlags(), m_tabViewportWidth, m_tabViewportHeight, textWidth, textHeight); if (rotateNumericFlag) { std::swap(textWidth, textHeight); } maxWidthOut = std::max(maxWidthOut, static_cast(textWidth)); maxHeightOut = std::max(maxHeightOut, static_cast(textHeight)); //text->setText(scaleValuesText[i]); m_numericsText.push_back(std::unique_ptr(text)); } } /** * Set the axis viewport. * * In the constructor, we were able to determine the width of the left and right * axes and the height of the bottom and top axes. Now we can determine * the size of the other dimension and computer a viewport for the axis. * * @param titleHeight * Height of the title. * @param bottomAxisHeight * Height of the bottom axis. * @param topAxisHeight * Height of the top axis. * @param leftAxisWidth * Width of the left axis. * @param rightAxisWidth * Width of the right axis. */ void BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setAxisViewport(const float titleHeight, const float bottomAxisHeight, const float topAxisHeight, const float leftAxisWidth, const float rightAxisWidth) { switch (m_axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: m_axisWidth = m_tabViewportWidth - (leftAxisWidth + rightAxisWidth); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: m_axisHeight = m_tabViewportHeight - (bottomAxisHeight + topAxisHeight + titleHeight); break; } if (m_axisWidth < 1.0f) { m_axisWidth = 1.0f; } if (m_axisHeight < 1.0f) { m_axisHeight = 1.0f; } switch (m_axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: m_axisViewport[0] = leftAxisWidth; m_axisViewport[1] = 0.0; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: m_axisViewport[0] = leftAxisWidth; m_axisViewport[1] = m_tabViewportHeight - topAxisHeight - titleHeight; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: m_axisViewport[0] = 0.0f; m_axisViewport[1] = bottomAxisHeight; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: m_axisViewport[0] = m_tabViewportWidth - rightAxisWidth; m_axisViewport[1] = bottomAxisHeight; break; } m_axisViewport[2] = m_axisWidth; m_axisViewport[3] = m_axisHeight; CaretAssert(m_axisViewport[0] >= 0.0f); CaretAssert(m_axisViewport[1] >= 0.0f); CaretAssert(m_axisViewport[2] >= 0.0f); CaretAssert(m_axisViewport[3] >= 0.0f); } /** * When this method is called, we have the viewport for the axis and we can now use the * viewport to position the numerical value and the label. * * @param foregroundFloatRGBA * Color of the foreground. * @param graphicsBoxLineThickness * Line thickness of the graphics box. */ void BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::setLabelAndNumericsCoordinates(const float foregroundFloatRGBA[4], const float graphicsBoxLineThickness) { if (m_axis == NULL) { return; } if ( ! m_axisValid) { return; } if ( ! m_axisDisplayedFlag) { return; } /* * Adjust the 'viewport' to account for the thickness of the lines * for the box that contains the plot of data */ float vpX = m_axisViewport[0]; float vpY = m_axisViewport[1]; float vpWidth = m_axisViewport[2]; float vpHeight = m_axisViewport[3]; switch (m_axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: vpX += graphicsBoxLineThickness; vpWidth -= (graphicsBoxLineThickness * 2.0); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: vpY += graphicsBoxLineThickness; vpHeight -= (graphicsBoxLineThickness * 2.0); break; } if (debugFlag) { glColor3f(1.0, 0.0, 0.0); const float v1[3] = { vpX, vpY, 0.0f }; const float v2[3] = { vpX + vpWidth, vpY, 0.0f }; const float v3[3] = { vpX + vpWidth, vpY + vpHeight, 0.0f }; const float v4[3] = { vpX, vpY + vpHeight, 0.0f }; const uint8_t rgba[4] { 255, 0, 0, 255}; GraphicsShape::drawBoxOutlineByteColor(v1, v2, v3, v4, rgba, GraphicsPrimitive::LineWidthType::PIXELS, 1.0f); } /* * 'Center' the label in the viewport */ if (m_axis->isShowLabel()) { float xyz[3] = { 0.0, 0.0, 0.0 }; switch (m_axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: xyz[0] = vpX + (vpWidth / 2.0f); xyz[1] = vpY + m_labelPaddingSizePixels; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: xyz[0] = vpX + m_labelPaddingSizePixels; xyz[1] = vpY + (vpHeight / 2.0f); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: xyz[0] = vpX + vpWidth - m_labelPaddingSizePixels; xyz[1] = vpY + (vpHeight / 2.0f); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: xyz[0] = vpX + (vpWidth / 2.0f); xyz[1] = vpY + vpHeight - m_labelPaddingSizePixels; break; } m_labelText->setTextColor(CaretColorEnum::CUSTOM); m_labelText->setCustomTextColor(foregroundFloatRGBA); m_labelText->getCoordinate()->setXYZ(xyz); } /* * Now convert the 'normalized' (zero to one) numeric value coordinate * to real coordinate. */ for (auto& text : m_numericsText) { float xyz[3] = { 0.0, 0.0, 0.0 }; text->getCoordinate()->getXYZ(xyz); switch (m_axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: xyz[0] = vpX + (vpWidth * xyz[0]); xyz[1] = vpY + vpHeight - m_tickLength - m_numericsTicksPaddingSizePixels; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: xyz[0] = vpX + vpWidth - m_tickLength - m_numericsTicksPaddingSizePixels; xyz[1] = vpY + (vpHeight * xyz[1]); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: xyz[0] = vpX + m_tickLength + m_numericsTicksPaddingSizePixels; xyz[1] = vpY + (vpHeight * xyz[1]); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: xyz[0] = vpX + (vpWidth * xyz[0]); xyz[1] = vpY + m_tickLength + m_numericsTicksPaddingSizePixels; break; } text->setTextColor(CaretColorEnum::CUSTOM); text->setCustomTextColor(foregroundFloatRGBA); text->getCoordinate()->setXYZ(xyz); } } /** * Draw the axis. * * @param chartDrawing * The chart drawing parent. * @param chartTwoOverlaySet * Chart overlay set containing the axis. * @param mouseX * X-coordinate of the mouse. * @param mouseY * Y-coordinate of the mouse. * @param foregroundFloatRGBA * Color of the foreground. * @param axisMinimumValueOut * Output containing the minimum value for the axis * @param axisMaximumValueOut * Output containing the maximum value for the axis */ void BrainOpenGLChartTwoDrawingFixedPipeline::AxisDrawingInfo::drawAxis(BrainOpenGLChartTwoDrawingFixedPipeline* chartDrawing, ChartTwoOverlaySet* chartTwoOverlaySet, const int32_t mouseX, const int32_t mouseY, const float foregroundFloatRGBA[4], float& axisMinimumValueOut, float& axisMaximumValueOut) { axisMinimumValueOut = m_axisMinimumValue; axisMaximumValueOut = m_axisMaximumValue; if (m_axis == NULL) { return; } if ( ! m_axisValid) { return; } if ( ! m_axisDisplayedFlag) { return; } const int32_t numScaleValuesToDraw = static_cast(m_numericsText.size()); if (numScaleValuesToDraw > 0) { const bool showTicksEnabledFlag = m_axis->isShowTickmarks(); GraphicsPrimitive::PrimitiveType primitiveType = GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES; std::unique_ptr ticksData = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(primitiveType, foregroundFloatRGBA)); ticksData->reserveForNumberOfVertices(numScaleValuesToDraw * 2); const int32_t firstTickIndex = 0; const int32_t lastTickIndex = numScaleValuesToDraw - 1; for (int32_t i = 0; i < numScaleValuesToDraw; i++) { /* * Coordinate of numeric value text */ CaretAssertVectorIndex(m_numericsText, i); AnnotationPercentSizeText* text = m_numericsText[i].get(); float xyz[3]; text->getCoordinate()->getXYZ(xyz); const float textX = xyz[0]; const float textY = xyz[1]; /* * Tick starts at an offset from its corresponding numerical value. * The length of the tick is increased by half the line width so * that the tick connects to the box around the data plot without * a gap. */ float tickStartX = textX; float tickStartY = textY; float tickEndX = 0.0; float tickEndY = 0.0; const float tickLength = m_tickLength + (m_lineDrawingWidth / 2.0f); switch (m_axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: tickStartY += m_numericsTicksPaddingSizePixels; tickEndX = tickStartX; tickEndY = tickStartY + tickLength; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: tickStartY -= m_numericsTicksPaddingSizePixels; tickEndX = tickStartX; tickEndY = tickStartY - tickLength; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: tickStartX += m_numericsTicksPaddingSizePixels; tickEndX = tickStartX + tickLength; tickEndY = tickStartY; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: tickStartX -= m_numericsTicksPaddingSizePixels; tickEndX = tickStartX - tickLength; tickEndY = tickStartY; break; } if (showTicksEnabledFlag) { if ((i != firstTickIndex) && (i != lastTickIndex)) { ticksData->addVertex(tickStartX, tickStartY); ticksData->addVertex(tickEndX, tickEndY); } } /* * Draw the numeric value. */ m_textRenderer->drawTextAtViewportCoords(textX, textY, 0.0, *text, BrainOpenGLTextRenderInterface::DrawingFlags()); } /* * Draw the ticks. * Note Line width is set in pixel and was converted from PERCENTAGE OF VIEWPORT HEIGHT */ if (ticksData->getNumberOfVertices() > 1) { ticksData->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, m_lineDrawingWidth); chartDrawing->drawPrimitivePrivate(ticksData.get()); } } /* * Draw the label */ if (m_axis->isShowLabel()) { float xyz[3]; m_labelText->getCoordinate()->getXYZ(xyz); if (chartDrawing->m_identificationModeFlag) { /* * For identification simply draw a box using a triangle strip */ int32_t primitiveIndex = -1; float primitiveDepth = 0.0; float bottomLeft[3], bottomRight[3], topLeft[3], topRight[3]; m_textRenderer->getBoundsForTextAtViewportCoords(*(m_labelText.get()), BrainOpenGLTextRenderInterface::DrawingFlags(), xyz[0], xyz[1], xyz[2], m_tabViewportWidth, m_tabViewportHeight, bottomLeft, bottomRight, topRight, topLeft); std::unique_ptr boxPrimitive = std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP, foregroundFloatRGBA)); boxPrimitive->reserveForNumberOfVertices(4); boxPrimitive->addVertex(topLeft); boxPrimitive->addVertex(bottomLeft); boxPrimitive->addVertex(topRight); boxPrimitive->addVertex(bottomRight); GraphicsEngineDataOpenGL::drawWithSelection(boxPrimitive.get(), mouseX, mouseY, primitiveIndex, primitiveDepth); if (primitiveIndex >= 0) { if (chartDrawing->m_selectionItemChartLabel->isOtherScreenDepthCloserToViewer(primitiveDepth)) { chartDrawing->m_selectionItemChartLabel->setChartTwoCartesianAxis(const_cast(m_axis), chartTwoOverlaySet); } } } else { m_textRenderer->drawTextAtViewportCoords(xyz[0], xyz[1], 0.0, *(m_labelText.get()), BrainOpenGLTextRenderInterface::DrawingFlags()); } } } /** * Constructor. * * @param textRenderer * The text renderer. * @param tabViewport * Viewport of the tab containing the chart. * @param title * The chart title. */ BrainOpenGLChartTwoDrawingFixedPipeline::TitleDrawingInfo::TitleDrawingInfo(BrainOpenGLTextRenderInterface* textRenderer, const int32_t tabViewport[4], const ChartTwoTitle* title) : m_textRenderer(textRenderer), m_tabViewportWidth(tabViewport[2]), m_tabViewportHeight(tabViewport[3]), m_title(title) { const AString titleText = m_title->getText().trimmed(); m_titleDisplayedFlag = (m_title->isDisplayed() && ( ! titleText.isEmpty())); if ( ! m_titleDisplayedFlag) { /* * If axis is not displayed, use padding with a small percentage of space. */ const float emptyAxisPaddingPercentage = 1.0f; m_paddingSizePixels = convertPercentageOfViewportToPixels(emptyAxisPaddingPercentage, m_tabViewportHeight); m_titleHeight = m_paddingSizePixels; return; } m_paddingSizePixels = convertPercentageOfViewportToPixels(m_title->getPaddingSize(), m_tabViewportHeight); /* * Create a text annotation for drawing the title */ AnnotationPercentSizeText* text = new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); float xyz[3] = { 0.0f, 0.0f, 0.0f }; xyz[0] = 0.5f; text->setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); text->setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); text->setText(titleText); text->setFontPercentViewportSize(m_title->getTextSize()); text->getCoordinate()->setXYZ(xyz); double m_textWidth = 0.0; double m_textHeight = 0.0; m_textRenderer->getTextWidthHeightInPixels(*text, BrainOpenGLTextRenderInterface::DrawingFlags(), m_tabViewportWidth, m_tabViewportHeight, m_textWidth, m_textHeight); m_text.reset(text); m_titleHeight = m_paddingSizePixels + m_textHeight; CaretAssert(m_titleHeight >= 0.0f); } /** * Set the title viewport. Once the width of the left and right and the height of the * bottom and top axes are known, we can determine the sizes for the title. * * @param leftAxisWidth * Width of the left axis. * @param rightAxisWidth * Width of the right axis. */ void BrainOpenGLChartTwoDrawingFixedPipeline::TitleDrawingInfo::setTitleViewport(const float leftAxisWidth, const float rightAxisWidth) { if ( ! m_titleDisplayedFlag) { return; } m_titleWidth = m_tabViewportWidth - (leftAxisWidth + rightAxisWidth); if (m_titleWidth < 1.0f) { m_titleWidth = 1.0f; } if (m_titleHeight < 1.0f) { m_titleHeight = 1.0f; } m_titleWidth = m_tabViewportWidth - (leftAxisWidth + rightAxisWidth); m_titleViewport[0] = leftAxisWidth; m_titleViewport[1] = m_tabViewportHeight - m_titleHeight; m_titleViewport[2] = m_titleWidth; m_titleViewport[3] = m_titleHeight; CaretAssert(m_titleViewport[0] >= 0.0f); CaretAssert(m_titleViewport[1] >= 0.0f); CaretAssert(m_titleViewport[2] >= 0.0f); CaretAssert(m_titleViewport[3] >= 0.0f); float xyz[3]; m_text->getCoordinate()->getXYZ(xyz); xyz[0] = m_titleViewport[0] + (m_titleWidth / 2.0f); xyz[1] = m_titleViewport[1] + m_titleHeight - m_paddingSizePixels; m_text->getCoordinate()->setXYZ(xyz); } /** * Draw the title. * * @param foregroundFloatRGBA * Color of the foreground. */ void BrainOpenGLChartTwoDrawingFixedPipeline::TitleDrawingInfo::drawTitle(const float foregroundFloatRGBA[4]) { if (m_title == NULL) { return; } if ( ! m_titleDisplayedFlag) { return; } if (debugFlag) { const float v1[3] = { m_titleViewport[0], m_titleViewport[1], 0.0f }; const float v2[3] = { m_titleViewport[0] + m_titleViewport[2], m_titleViewport[1], 0.0f }; const float v3[3] = { m_titleViewport[0] + m_titleViewport[2], m_titleViewport[1] + m_titleViewport[3], 0.0f }; const float v4[3] = { m_titleViewport[0], m_titleViewport[1] + m_titleViewport[3], 0.0f }; const uint8_t rgba[4] { 255, 0, 0, 255}; GraphicsShape::drawBoxOutlineByteColor(v1, v2, v3, v4, rgba, GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); } m_text->setTextColor(CaretColorEnum::CUSTOM); m_text->setCustomTextColor(foregroundFloatRGBA); float xyz[3]; m_text->getCoordinate()->getXYZ(xyz); m_textRenderer->drawTextAtViewportCoords(xyz[0], xyz[1], 0.0, *(m_text.get()), BrainOpenGLTextRenderInterface::DrawingFlags()); } connectome-workbench-1.4.2/src/Brain/BrainOpenGLChartTwoDrawingFixedPipeline.h000066400000000000000000000341051360521144700273670ustar00rootroot00000000000000#ifndef __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_FIXED_PIPELINE_H__ #define __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_FIXED_PIPELINE_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "BrainOpenGLChartTwoDrawingInterface.h" #include "CaretColorEnum.h" #include "ChartAxisLocationEnum.h" #include "ChartTwoDataTypeEnum.h" #include "ChartTwoMatrixTriangularViewingModeEnum.h" #include "GraphicsPrimitive.h" namespace caret { class Annotation; class AnnotationPercentSizeText; class BrainOpenGLViewportContent; class BrowserTabContent; class CaretPreferences; class ChartTwoCartesianAxis; class ChartTwoDataCartesian; class ChartTwoOverlaySet; class ChartTwoTitle; class ChartableTwoFileHistogramChart; class ChartableTwoFileLineSeriesChart; class ChartableTwoFileMatrixChart; class SelectionItemAnnotation; class SelectionItemChartTwoHistogram; class SelectionItemChartTwoLabel; class SelectionItemChartTwoLineSeries; class SelectionItemChartTwoMatrix; class BrainOpenGLChartTwoDrawingFixedPipeline : public BrainOpenGLChartTwoDrawingInterface { public: BrainOpenGLChartTwoDrawingFixedPipeline(const BrainOpenGLViewportContent* viewportContent); virtual ~BrainOpenGLChartTwoDrawingFixedPipeline(); virtual void drawChartOverlaySet(Brain* brain, ModelChartTwo* chartTwoModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t viewport[4], std::vector& annotationsOut) override; // ADD_NEW_METHODS_HERE private: /** * Contains histogram for drawing */ class HistogramChartDrawingInfo { public: HistogramChartDrawingInfo(ChartableTwoFileHistogramChart* histogramChart, int32_t mapIndex, ChartAxisLocationEnum::Enum verticalAxisLocation, const bool allMapsSelected); ChartableTwoFileHistogramChart* m_histogramChart; int32_t m_mapIndex; ChartAxisLocationEnum::Enum m_verticalAxisLocation; const bool m_allMapsSelected; ~HistogramChartDrawingInfo(); }; /** * Contains line chart for drawing */ class LineSeriesChartDrawingInfo { public: LineSeriesChartDrawingInfo(const ChartableTwoFileLineSeriesChart* lineSeriesChart, const ChartTwoDataCartesian* chartTwoCartesianData, const ChartAxisLocationEnum::Enum verticalAxisLocation) : m_lineSeriesChart(lineSeriesChart), m_chartTwoCartesianData(chartTwoCartesianData), m_verticalAxisLocation(verticalAxisLocation) { } const ChartableTwoFileLineSeriesChart* m_lineSeriesChart; const ChartTwoDataCartesian* m_chartTwoCartesianData; const ChartAxisLocationEnum::Enum m_verticalAxisLocation; }; /** * Determines size of title and draws the title */ class TitleDrawingInfo { public: TitleDrawingInfo(BrainOpenGLTextRenderInterface* textRenderer, const int32_t tabViewport[4], const ChartTwoTitle* title); void setTitleViewport(const float leftAxisWidth, const float rightAxisWidth); void drawTitle(const float foregroundFloatRGBA[4]); float m_titleHeight = 0.0f; float m_titleWidth = 0.0f; bool m_titleDisplayedFlag; private: BrainOpenGLTextRenderInterface* m_textRenderer; const float m_tabViewportWidth = 0.0f; const float m_tabViewportHeight = 0.0f; const ChartTwoTitle* m_title; std::unique_ptr m_text; float m_paddingSizePixels = 0.0f; float m_titleViewport[4]; }; /** * Determines size of an axis and draws the axis */ class AxisDrawingInfo { public: AxisDrawingInfo(BrainOpenGLTextRenderInterface* textRenderer, const int32_t tabViewport[4], const float dataMinX, const float dataMaxX, const float dataMinY, const float dataMaxY, const ChartAxisLocationEnum::Enum axisLocation, const ChartTwoCartesianAxis* axis, const AString& labelText, const float lineWidthPercentage); void setAxisViewport(const float titleHeight, const float bottomAxisHeight, const float topAxisHeight, const float leftAxisWidth, const float rightAxisWidth); void setLabelAndNumericsCoordinates(const float foregroundFloatRGBA[4], const float graphicsBoxLineThickness); void drawAxis(BrainOpenGLChartTwoDrawingFixedPipeline* chartDrawing, ChartTwoOverlaySet* chartTwoOverlaySet, const int32_t mouseX, const int32_t mouseY, const float foregroundFloatRGBA[4], float& axisMinimumValueOut, float& axisMaximumValueOut); std::unique_ptr m_labelText; std::vector> m_numericsText; float m_axisWidth = 0.0f; float m_axisHeight = 0.0f; /** Axis minimum value is produced by the axis scaling user/auto */ float m_axisMinimumValue = 0.0f; float m_axisMaximumValue = 0.0f; float m_labelPaddingSizePixels = 0.0f; float m_numericsTicksPaddingSizePixels = 1.0f; bool m_axisValid = false; bool m_axisDisplayedFlag = false; int32_t m_axisViewport[4]; private: const ChartAxisLocationEnum::Enum m_axisLocation; const ChartTwoCartesianAxis* m_axis; BrainOpenGLTextRenderInterface* m_textRenderer; const float m_tabViewportWidth = 0.0f; const float m_tabViewportHeight = 0.0f; float m_lineDrawingWidth = 1.0f; float m_tickLength = 0.0f; float m_labelWidth = 0.0f; float m_labelHeight = 0.0f; void initializeNumericText(const float dataMinimumDataValue, const float dataMaximumDataValue, const bool showNumericFlag, const bool rotateNumericFlag, float& maxWidthOut, float& maxHeightOut); void initializeLabel(const AString& labelText, float& widthOut, float& heightOut); }; class MatrixRowColumnHighight { public: MatrixRowColumnHighight(GraphicsPrimitive* graphicsPrimitive, const float modelViewMatrix[16]) : m_graphicsPrimitive(std::unique_ptr(graphicsPrimitive)) { for (int32_t i = 0; i < 16; i++) m_modelViewMatrix[i] = modelViewMatrix[i]; } std::unique_ptr m_graphicsPrimitive; float m_modelViewMatrix[16]; }; BrainOpenGLChartTwoDrawingFixedPipeline(const BrainOpenGLChartTwoDrawingFixedPipeline&); BrainOpenGLChartTwoDrawingFixedPipeline& operator=(const BrainOpenGLChartTwoDrawingFixedPipeline&); void restoreStateOfOpenGL(); void saveStateOfOpenGL(); void drawMatrixChart(); void drawMatrixChartContent(const ChartableTwoFileMatrixChart* matrixChart, const ChartTwoMatrixTriangularViewingModeEnum::Enum chartViewingType, const float cellWidth, const float cellHeight, const float zooming, std::vector& rowColumnHighlightingOut); void drawHistogramOrLineSeriesChart(const ChartTwoDataTypeEnum::Enum chartDataType); void drawChartGraphicsBoxAndSetViewport(const float vpX, const float vpY, const float vpWidth, const float vpHeight, const float lineThicknessPercentage, const float titleHeight, const float bottomAxisHeight, const float topAxisHeight, const float leftAxisWidth, const float rightAxisWidth, const bool drawBoxFlag, int32_t chartGraphicsDrawingViewportOut[4]); bool createChartDrawingViewport(const float vpX, const float vpY, const float vpWidth, const float vpHeight, const float lineThicknessPercentage, const float titleHeight, const float bottomAxisHeight, const float topAxisHeight, const float leftAxisWidth, const float rightAxisWidth, int32_t chartGraphicsDrawingViewportOut[4]); void drawPrimitivePrivate(GraphicsPrimitive* primitive); void updateViewportContentForCharting(const int32_t viewport[4]); static float convertPercentageOfViewportToPixels(const float percentageWidthOrHeight, const float viewportWidthOrHeight); static float convertPercentageOfViewportToOpenGLLineWidth(const float percentageWidthOrHeight, const float viewportWidthOrHeight); Brain* m_brain; const BrainOpenGLViewportContent* m_viewportContent; BrowserTabContent* m_browserTabContent; ModelChartTwo* m_chartTwoModel; BrainOpenGLFixedPipeline* m_fixedPipelineDrawing; BrainOpenGLTextRenderInterface* m_textRenderer; ChartTwoOverlaySet* m_chartOverlaySet; SelectionItemDataTypeEnum::Enum m_selectionItemDataType; int32_t m_viewport[4]; int32_t m_tabIndex; float m_translation[3]; float m_zooming; CaretPreferences* m_preferences; SelectionItemAnnotation* m_selectionItemAnnotation; SelectionItemChartTwoHistogram* m_selectionItemHistogram; SelectionItemChartTwoLineSeries* m_selectionItemLineSeries; SelectionItemChartTwoMatrix* m_selectionItemMatrix; SelectionItemChartTwoLabel* m_selectionItemChartLabel; bool m_identificationModeFlag; /** These annotations will be drawn by the annotation drawing code */ std::vector m_annotationsForDrawingOutput; static float s_minimumLineWidthOpenGL; static float s_maximumLineWidthOpenGL; static const int32_t IDENTIFICATION_INDICES_PER_HISTOGRAM = 2; static const int32_t IDENTIFICATION_INDICES_PER_CHART_LINE = 2; static const int32_t IDENTIFICATION_INDICES_PER_MATRIX_ELEMENT = 2; // ADD_NEW_MEMBERS_HERE friend class AxisDrawingInfo; }; #ifdef __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_FIXED_PIPELINE_DECLARE__ float BrainOpenGLChartTwoDrawingFixedPipeline::s_minimumLineWidthOpenGL = 1.0f; float BrainOpenGLChartTwoDrawingFixedPipeline::s_maximumLineWidthOpenGL = 1.0f; #endif // __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_FIXED_PIPELINE_DECLARE__ } // namespace #endif //__BRAIN_OPEN_G_L_CHART_TWO_DRAWING_FIXED_PIPELINE_H__ connectome-workbench-1.4.2/src/Brain/BrainOpenGLChartTwoDrawingInterface.h000066400000000000000000000054041360521144700265420ustar00rootroot00000000000000#ifndef __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_INTERFACE_H__ #define __BRAIN_OPEN_G_L_CHART_TWO_DRAWING_INTERFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SelectionItemDataTypeEnum.h" namespace caret { class Annotation; class Brain; class BrainOpenGLFixedPipeline; class BrainOpenGLTextRenderInterface; class ModelChartTwo; class BrainOpenGLChartTwoDrawingInterface { public: BrainOpenGLChartTwoDrawingInterface() { } virtual ~BrainOpenGLChartTwoDrawingInterface() { } /** * Draw charts from a chart overlay. * * @param brain * Brain. * @param chartTwoModel * The chart two model. * @param fixedPipelineDrawing * The fixed pipeline OpenGL drawing. * @param selectionItemDataType * Selected data type. * @param viewport * Viewport for the chart. * @param annotationChartGraphicsLabelsOut * Output containing annotation chart axis labels that will be drawn * by the Annotation OpenGL Drawing. */ virtual void drawChartOverlaySet(Brain* brain, ModelChartTwo* chartTwoModel, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const SelectionItemDataTypeEnum::Enum selectionItemDataType, const int32_t viewport[4], std::vector& annotationChartGraphicsLabelsOut) = 0; // ADD_NEW_METHODS_HERE private: BrainOpenGLChartTwoDrawingInterface(const BrainOpenGLChartTwoDrawingInterface&); BrainOpenGLChartTwoDrawingInterface& operator=(const BrainOpenGLChartTwoDrawingInterface&); // ADD_NEW_MEMBERS_HERE }; } // namespace #endif //__BRAIN_OPEN_G_L_CHART_TWO_DRAWING_INTERFACE_H__ connectome-workbench-1.4.2/src/Brain/BrainOpenGLFixedPipeline.cxx000066400000000000000000010326061360521144700247570ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretOpenGLInclude.h" #define __BRAIN_OPENGL_FIXED_PIPELINE_DEFINE_H #include "BrainOpenGLFixedPipeline.h" #undef __BRAIN_OPENGL_FIXED_PIPELINE_DEFINE_H #include #include #include #include #include #include "AnnotationColorBar.h" #include "AnnotationManager.h" #include "AnnotationPointSizeText.h" #include "Border.h" #include "BorderFile.h" #include "Brain.h" #include "BrainOpenGLAnnotationDrawingFixedPipeline.h" #include "BrainOpenGLChartDrawingFixedPipeline.h" #include "BrainOpenGLChartTwoDrawingFixedPipeline.h" #include "BrainOpenGLPrimitiveDrawing.h" #include "BrainOpenGLVolumeObliqueSliceDrawing.h" #include "BrainOpenGLVolumeSliceDrawing.h" #include "BrainOpenGLVolumeTextureSliceDrawing.h" #include "BrainOpenGLShapeCone.h" #include "BrainOpenGLShapeCube.h" #include "BrainOpenGLShapeCylinder.h" #include "BrainOpenGLShapeRing.h" #include "BrainOpenGLShapeSphere.h" #include "BrainOpenGLViewportContent.h" #include "BrainStructure.h" #include "BrowserTabContent.h" #include "BoundingBox.h" #include "CaretAssert.h" #include "CaretDataFileSelectionModel.h" #include "CaretLogger.h" #include "CaretMappableDataFile.h" #include "CaretPreferences.h" #include "ChartableMatrixInterface.h" #include "ChartableMatrixSeriesInterface.h" #include "ChartModelDataSeries.h" #include "ChartModelFrequencySeries.h" #include "ChartModelTimeSeries.h" #include "ChartTwoOverlaySet.h" #include "CiftiBrainordinateLabelFile.h" #include "CiftiFiberOrientationFile.h" #include "CiftiFiberTrajectoryFile.h" #include "ClippingPlaneGroup.h" #include "ControlPointFile.h" #include "ControlPoint3D.h" #include "DeveloperFlagsEnum.h" #include "DisplayGroupEnum.h" #include "DisplayPropertiesAnnotation.h" #include "DisplayPropertiesBorders.h" #include "DisplayPropertiesFiberOrientation.h" #include "DisplayPropertiesFoci.h" #include "DisplayPropertiesImages.h" #include "DisplayPropertiesLabels.h" #include "DisplayPropertiesSurface.h" #include "DisplayPropertiesVolume.h" #include "ElapsedTimer.h" #include "EventAnnotationColorBarGet.h" #include "EventManager.h" #include "EventModelSurfaceGet.h" #include "EventNodeIdentificationColorsGetFromCharts.h" #include "EventOpenGLObjectToWindowTransform.h" #include "FastStatistics.h" #include "Fiber.h" #include "FiberOrientation.h" #include "FiberOrientationTrajectory.h" #include "FiberTrajectoryMapProperties.h" #include "FociFile.h" #include "Focus.h" #include "GapsAndMargins.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "GraphicsEngineDataOpenGL.h" #include "GraphicsPrimitiveV3fC4ub.h" #include "GraphicsPrimitiveV3f.h" #include "GraphicsShape.h" #include "GroupAndNameHierarchyModel.h" #include "IdentifiedItemNode.h" #include "IdentificationManager.h" #include "ImageFile.h" #include "Matrix4x4.h" #include "SelectionItemBorderSurface.h" #include "SelectionItemFocusSurface.h" #include "SelectionItemFocusVolume.h" #include "SelectionItemImage.h" #include "SelectionItemImageControlPoint.h" #include "SelectionItemSurfaceNode.h" #include "SelectionItemSurfaceNodeIdentificationSymbol.h" #include "SelectionItemSurfaceTriangle.h" #include "SelectionItemVoxel.h" #include "SpacerTabContent.h" #include "SurfaceMontageConfigurationCerebellar.h" #include "SurfaceMontageConfigurationCerebral.h" #include "SurfaceMontageConfigurationFlatMaps.h" #include "IdentificationWithColor.h" #include "SelectionManager.h" #include "MathFunctions.h" #include "ModelChart.h" #include "ModelChartTwo.h" #include "ModelSurface.h" #include "ModelSurfaceMontage.h" #include "ModelVolume.h" #include "ModelWholeBrain.h" #include "NodeAndVoxelColoring.h" #include "Overlay.h" #include "OverlaySet.h" #include "Palette.h" #include "PaletteColorMapping.h" #include "PaletteScalarAndColor.h" #include "Plane.h" #include "SessionManager.h" #include "Surface.h" #include "SurfaceMontageViewport.h" #include "SurfaceNodeColoring.h" #include "SurfaceProjectedItem.h" #include "SurfaceProjectionBarycentric.h" #include "SurfaceProjectionVanEssen.h" #include "SurfaceSelectionModel.h" #include "TopologyHelper.h" #include "VolumeFile.h" #include "VolumeMappableInterface.h" #include "VolumeSurfaceOutlineColorOrTabModel.h" #include "VolumeSurfaceOutlineModel.h" #include "VolumeSurfaceOutlineSetModel.h" using namespace caret; static Surface* annotationDrawingNullSurface(NULL); static float annotationDrawingUnusedSurfaceScaling(1.0f); /** * Constructor. * * @param textRenderer * The optional text renderer is used for text rendering. * This parameter may be NULL in which case no text * rendering is performed. */ BrainOpenGLFixedPipeline::BrainOpenGLFixedPipeline(BrainOpenGLTextRenderInterface* textRenderer) : BrainOpenGL(textRenderer) { this->initializeMembersBrainOpenGL(); this->colorIdentification = new IdentificationWithColor(); m_annotationDrawing.grabNew(new BrainOpenGLAnnotationDrawingFixedPipeline(this)); m_shapeSphere = NULL; m_shapeCone = NULL; m_shapeCylinder = NULL; m_shapeCube = NULL; m_shapeCubeRounded = NULL; this->surfaceNodeColoring = new SurfaceNodeColoring(); m_brain = NULL; m_clippingPlaneGroup = NULL; m_tileTabsActiveFlag = false; setTabViewport(NULL); } /** * Destructor. */ BrainOpenGLFixedPipeline::~BrainOpenGLFixedPipeline() { if (m_shapeSphere != NULL) { delete m_shapeSphere; m_shapeSphere = NULL; } if (m_shapeCone != NULL) { delete m_shapeCone; m_shapeCone = NULL; } if (m_shapeCylinder != NULL) { delete m_shapeCylinder; m_shapeCylinder = NULL; } if (m_shapeCube != NULL) { delete m_shapeCube; m_shapeCube = NULL; } if (m_shapeCubeRounded != NULL) { delete m_shapeCubeRounded; m_shapeCubeRounded = NULL; } if (this->surfaceNodeColoring != NULL) { delete this->surfaceNodeColoring; this->surfaceNodeColoring = NULL; } delete this->colorIdentification; this->colorIdentification = NULL; GraphicsShape::deleteAllPrimitives(); } /** * Selection on a model. * * @param windowIndex * Index of window for selection * @param userInputMode * Input mode for window * @param brain * The brain (must be valid!) * @param viewportContent * Viewport content in which mouse was clicked * @param mouseX * X position of mouse click * @param mouseY * Y position of mouse click * @param applySelectionBackgroundFiltering * If true (which is in most cases), if there are multiple items * selected, those items "behind" other items are not reported. * For example, suppose a focus is selected and there is a node * the focus. If this parameter is true, the node will NOT be * selected. If this parameter is false, the node will be * selected. */ void BrainOpenGLFixedPipeline::selectModelImplementation(const int32_t windowIndex, const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, const bool applySelectionBackgroundFiltering) { m_brain = brain; m_windowIndex = windowIndex; m_windowUserInputMode = windowUserInputMode; CaretAssert(m_brain); CaretAssert((m_windowIndex >= 0) && (m_windowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)); setTabViewport(viewportContent); m_specialCaseGraphicsAnnotations.clear(); std::vector viewportContentsVector; viewportContentsVector.push_back(viewportContent); setAnnotationColorBarsForDrawing(viewportContentsVector); m_clippingPlaneGroup = NULL; this->inverseRotationMatrixValid = false; /* * For identification, set the background * to white. */ glClearColor(1.0, 1.0, 1.0, 0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); this->mouseX = mouseX; this->mouseY = mouseY; this->colorIdentification->reset(); this->drawModelInternal(MODE_IDENTIFICATION, viewportContent); /* * Clear depth buffer since tab and window * annotations ALWAYS are on top of * everything else. */ glClear(GL_DEPTH_BUFFER_BIT); if (viewportContent->getSpacerTabContent() != NULL) { drawSpacerAnnotations(viewportContent); } else { drawTabAnnotations(viewportContent); } int windowViewport[4]; viewportContent->getWindowViewport(windowViewport); drawWindowAnnotations(windowViewport); m_brain->getSelectionManager()->filterSelections(applySelectionBackgroundFiltering); m_brain = NULL; m_windowIndex = -1; m_windowUserInputMode = UserInputModeEnum::INVALID; } /** * Project the given window coordinate to the active models. * If the projection is successful, The 'original' XYZ * coordinate in 'projectionOut' will be valid. In addition, * the barycentric coordinate may also be valid in 'projectionOut'. * * @param windowIndex * Index of window for projection * @param userInputMode * Input mode for window * @param brain * The brain (must be valid!) * @param viewportContent * Viewport content in which mouse was clicked * @param mouseX * X position of mouse click * @param mouseY * Y position of mouse click * @param projectionOut * Contains projection result upon exit. */ void BrainOpenGLFixedPipeline::projectToModelImplementation(const int32_t windowIndex, const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, SurfaceProjectedItem& projectionOut) { m_brain = brain; m_windowIndex = windowIndex; m_windowUserInputMode = windowUserInputMode; CaretAssert(m_brain); CaretAssert((m_windowIndex >= 0) && (m_windowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)); setTabViewport(viewportContent); m_clippingPlaneGroup = NULL; m_specialCaseGraphicsAnnotations.clear(); m_brain->getSelectionManager()->reset(); this->modeProjectionData = &projectionOut; this->modeProjectionData->reset(); this->modeProjectionScreenDepth = std::numeric_limits::max(); /* * For projection which uses colors for finding triangles, * set the background to white. */ glClearColor(1.0, 1.0, 1.0, 0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); this->mouseX = mouseX; this->mouseY = mouseY; this->colorIdentification->reset(); this->drawModelInternal(MODE_PROJECTION, viewportContent); this->modeProjectionData = NULL; m_brain = NULL; m_windowIndex = -1; m_windowUserInputMode = UserInputModeEnum::INVALID; } /** * Setup the content of the transform event with current transformation data. * * @param transformEvent * The transform event. */ void BrainOpenGLFixedPipeline::loadObjectToWindowTransform(EventOpenGLObjectToWindowTransform* transformEvent) { if (getContextSharingGroupPointer() != NULL) { std::array modelviewArray; std::array projectionArray; std::array depthRange; std::array viewport; glGetDoublev(GL_MODELVIEW_MATRIX, modelviewArray.data()); glGetDoublev(GL_PROJECTION_MATRIX, projectionArray.data()); glGetDoublev(GL_DEPTH_RANGE, depthRange.data()); glGetIntegerv(GL_VIEWPORT, viewport.data()); transformEvent->setup(modelviewArray, projectionArray, viewport, depthRange, s_gluLookAtCenterFromEyeOffsetDistance); transformEvent->setEventProcessed(); } else { CaretAssertMessage(0, "Received EventOpenGLObjectToWindowTransform but current context is invalid."); } } /** * Update the foreground and background colors using the model in * the given viewport content. */ void BrainOpenGLFixedPipeline::updateForegroundAndBackgroundColors(const BrainOpenGLViewportContent* vpContent) { /* * Default to colors for window */ CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->getBackgroundAndForegroundColors()->getColorForegroundWindow(m_foregroundColorByte); m_foregroundColorByte[3] = 255; prefs->getBackgroundAndForegroundColors()->getColorBackgroundWindow(m_backgroundColorByte); m_backgroundColorByte[3] = 255; if (vpContent != NULL) { const BrowserTabContent* btc = vpContent->getBrowserTabContent(); if (btc != NULL) { const Model* model = btc->getModelForDisplay(); if (model != NULL) { switch (model->getModelType()) { case ModelTypeEnum::MODEL_TYPE_CHART: prefs->getBackgroundAndForegroundColors()->getColorForegroundChartView(m_foregroundColorByte); prefs->getBackgroundAndForegroundColors()->getColorBackgroundChartView(m_backgroundColorByte); break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: prefs->getBackgroundAndForegroundColors()->getColorForegroundChartView(m_foregroundColorByte); prefs->getBackgroundAndForegroundColors()->getColorBackgroundChartView(m_backgroundColorByte); break; case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: prefs->getBackgroundAndForegroundColors()->getColorForegroundSurfaceView(m_foregroundColorByte); prefs->getBackgroundAndForegroundColors()->getColorBackgroundSurfaceView(m_backgroundColorByte); break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: prefs->getBackgroundAndForegroundColors()->getColorForegroundSurfaceView(m_foregroundColorByte); prefs->getBackgroundAndForegroundColors()->getColorBackgroundSurfaceView(m_backgroundColorByte); break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: prefs->getBackgroundAndForegroundColors()->getColorForegroundVolumeView(m_foregroundColorByte); prefs->getBackgroundAndForegroundColors()->getColorBackgroundVolumeView(m_backgroundColorByte); break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: prefs->getBackgroundAndForegroundColors()->getColorForegroundAllView(m_foregroundColorByte); prefs->getBackgroundAndForegroundColors()->getColorBackgroundAllView(m_backgroundColorByte); break; } } } m_foregroundColorByte[3] = 255; m_backgroundColorByte[3] = 255; } CaretPreferences::byteRgbToFloatRgb(m_backgroundColorByte, m_backgroundColorFloat); m_backgroundColorFloat[3] = 1.0; CaretPreferences::byteRgbToFloatRgb(m_foregroundColorByte, m_foregroundColorFloat); m_foregroundColorFloat[3] = 1.0; } /** * Set the viewport for the tab content that is being drawn. * * @param vpContent * The viewport content (may be NULL). */ void BrainOpenGLFixedPipeline::setTabViewport(const BrainOpenGLViewportContent* vpContent) { m_tabViewport[0] = 0; m_tabViewport[1] = 0; m_tabViewport[2] = 0; m_tabViewport[3] = 0; if (vpContent != NULL) { vpContent->getTabViewportBeforeApplyingMargins(m_tabViewport); } } /** * Get colorbars in window space. * * @param viewportContents * Contents of the viewports. */ void BrainOpenGLFixedPipeline::setAnnotationColorBarsForDrawing(const std::vector& viewportContents) { m_annotationColorBarsForDrawing.clear(); /* * This event gets EVERY color bar, even those * in other windows */ EventAnnotationColorBarGet colorBarEvent; EventManager::get()->sendEvent(colorBarEvent.getPointer()); std::vector allColorBars = colorBarEvent.getAnnotationColorBars(); /* * Find the color bars contained in the viewports and * exclude color bars not in the viewports (color bars that * are in other windows or other tabs while in single * tab view). */ for (auto colorBar : allColorBars) { const int32_t tabIndex = colorBar->getTabIndex(); for (auto vc : viewportContents) { if (vc->getTabIndex() == tabIndex) { /* * While color bars are associated with tabs, the color bar * may be in window space so always update the window index * (users can move tabs to other windows). */ colorBar->setWindowIndex(vc->getWindowIndex()); m_annotationColorBarsForDrawing.push_back(colorBar); break; } } } } /** * Draw models in their respective viewports. * * @param windowIndex * Index of window for drawing * @param userInputMode * Input mode for window * @param brain * The brain (must be valid!) * @param viewportContents * Viewport info for drawing. */ void BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, const std::vector& viewportContents) { m_brain = brain; m_windowIndex = windowIndex; m_windowUserInputMode = windowUserInputMode; CaretAssert(m_brain); CaretAssert((m_windowIndex >= 0) && (m_windowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)); setTabViewport(NULL); m_specialCaseGraphicsAnnotations.clear(); setAnnotationColorBarsForDrawing(viewportContents); m_tileTabsActiveFlag = (viewportContents.size() > 1); this->inverseRotationMatrixValid = false; m_clippingPlaneGroup = NULL; this->checkForOpenGLError(NULL, "At beginning of drawModels()"); /* * NULL will retrieve Window colors (window colors added on 07jul2019) */ updateForegroundAndBackgroundColors(NULL); /* * Use the background color as the clear color. */ uint8_t clearColorByte[3] = { m_backgroundColorByte[0], m_backgroundColorByte[1], m_backgroundColorByte[2], }; float clearColorFloat[3]; CaretPreferences::byteRgbToFloatRgb(clearColorByte, clearColorFloat); glClearColor(clearColorFloat[0], clearColorFloat[1], clearColorFloat[2], 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); this->checkForOpenGLError(NULL, "At middle of drawModels()"); for (int32_t i = 0; i < static_cast(viewportContents.size()); i++) { const BrainOpenGLViewportContent* vpContent = viewportContents[i]; /* * Don't draw if off-screen */ { int32_t windowViewport[4]; vpContent->getWindowViewport(windowViewport); int32_t tabViewport[4]; vpContent->getTabViewportBeforeApplyingMargins(tabViewport); /* * Test for tab offscreen to right (tabs flow left-to-right) */ if (tabViewport[0] > (windowViewport[0] + windowViewport[2])) { continue; } /* * Test for tab offscreen to bottom (tabs flow top-to-bottom) */ const int32_t tabTop = tabViewport[1] + tabViewport[3]; if (tabTop < 0) { continue; } if (tabViewport[2] <= 0) { CaretLogSevere("Invalid TAB width=" + AString::number(tabViewport[2]) + " for index=" + AString::number(i)); continue; } if (tabViewport[3] <= 0) { CaretLogSevere("Invalid TAB height=" + AString::number(tabViewport[3]) + " for index=" + AString::number(i)); continue; } } /* * Viewport of window. */ setTabViewport(vpContent); glViewport(m_tabViewport[0], m_tabViewport[1], m_tabViewport[2], m_tabViewport[3]); /* * Update foreground and background colors for model */ updateForegroundAndBackgroundColors(vpContent); /* * If the background color for this viewport content is * different that the clear color, THEN * draw a rectangle with the background color. */ if ((m_backgroundColorByte[0] != clearColorByte[0]) || (m_backgroundColorByte[1] != clearColorByte[1]) || (m_backgroundColorByte[2] != clearColorByte[2])) { GLboolean depthEnabledFlag; glGetBooleanv(GL_DEPTH_TEST, &depthEnabledFlag); glDisable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glColor3ubv(m_backgroundColorByte); glBegin(GL_POLYGON); glVertex2f(0.0, 0.0); glVertex2f(1.0, 0.0); glVertex2f(1.0, 1.0); glVertex2f(0.0, 1.0); glEnd(); if (depthEnabledFlag) { glEnable(GL_DEPTH_TEST); } } this->drawModelInternal(MODE_DRAWING, vpContent); /* * Draw border in foreground color around tab that is highlighted * in Tile Tabs when user selects a tab. */ if (vpContent->isTabHighlighted()) { drawTabHighlighting(m_tabViewport[2], m_tabViewport[3], m_foregroundColorFloat); } } if ( ! viewportContents.empty()) { /* * Clear depth buffer since tab and window * annotations ALWAYS are on top of * everything else. */ glClear(GL_DEPTH_BUFFER_BIT); for (int32_t i = 0; i < static_cast(viewportContents.size()); i++) { /* * Viewport of window. */ const BrainOpenGLViewportContent* vpContent = viewportContents[i]; setTabViewport(vpContent); /* * Update foreground and background colors for model */ updateForegroundAndBackgroundColors(vpContent); if (vpContent->getSpacerTabContent() != NULL) { drawSpacerAnnotations(vpContent); } else { drawTabAnnotations(vpContent); } } /* * Draw window viewport annotations */ int windowViewport[4]; viewportContents[0]->getWindowViewport(windowViewport); CaretAssert(m_windowIndex == viewportContents[0]->getWindowIndex()); drawWindowAnnotations(windowViewport); } m_specialCaseGraphicsAnnotations.clear(); this->checkForOpenGLError(NULL, "At end of drawModels()"); m_brain = NULL; m_windowIndex = -1; m_windowUserInputMode = UserInputModeEnum::INVALID; } /** * Draw a box to highlight a selected tab. * * @param width * Width of tab. * @param height * Height of tab. * @param rgb * RGB color components for the 'frame' drawn around the tab. */ void BrainOpenGLFixedPipeline::drawTabHighlighting(const float width, const float height, const float rgb[3]) { if ( ! s_allowTabHighlightingFlag) { return; } const bool depthFlag = glIsEnabled(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0.0, width, 0.0, height, -100.0, 100.0); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glColor3fv(rgb); const float thickness = 10; /* * Left Side */ glBegin(GL_QUADS); glVertex3f(0.0, 0.0, 0.0); glVertex3f(thickness, 0.0, 0.0); glVertex3f(thickness, height, 0.0); glVertex3f(0.0, height, 0.0); glEnd(); /* * Right Side */ glBegin(GL_QUADS); glVertex3f(width - thickness, 0.0, 0.0); glVertex3f(width, 0.0, 0.0); glVertex3f(width, height, 0.0); glVertex3f(width - thickness, height, 0.0); glEnd(); /* * Bottom Side */ glBegin(GL_QUADS); glVertex3f(0.0, 0.0, 0.0); glVertex3f(width, 0.0, 0.0); glVertex3f(width, thickness, 0.0); glVertex3f(0.0, thickness, 0.0); glEnd(); /* * Top Side */ glBegin(GL_QUADS); glVertex3f(0.0, height - thickness, 0.0); glVertex3f(width, height - thickness, 0.0); glVertex3f(width, height, 0.0); glVertex3f(0.0, height, 0.0); glEnd(); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); if (depthFlag) { glEnable(GL_DEPTH_TEST); } } /** * Draw the chart coordinate space annotations. * * @param tabContent * Viewport content */ void BrainOpenGLFixedPipeline::drawChartCoordinateSpaceAnnotations(const BrainOpenGLViewportContent* viewportContent) { glPushAttrib(GL_VIEWPORT_BIT); Matrix4x4 projectionMatrix; Matrix4x4 modelviewMatrix; int viewport[4]; if (viewportContent->getChartDataMatricesAndViewport(projectionMatrix, modelviewMatrix, viewport)) { glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); glMatrixMode(GL_PROJECTION); glPushMatrix(); float projectionArray[16]; projectionMatrix.getMatrixForOpenGL(projectionArray); glLoadMatrixf(projectionArray); glMatrixMode(GL_MODELVIEW); glPushMatrix(); float modelviewArray[16]; modelviewMatrix.getMatrixForOpenGL(modelviewArray); glLoadMatrixf(modelviewArray); /* * Draw annotations for this surface and maybe draw * the model annotations. */ const bool annotationModeFlag = (m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_windowIndex, this->windowTabIndex, SpacerTabIndex(), BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, annotationModeFlag); std::vector emptyColorBars; std::vector emptyViewportAnnotations; m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::CHART, emptyColorBars, emptyViewportAnnotations, NULL, 1.0); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } glPopAttrib(); } /** * Draw the spacer tag annotations. * * @param tabContent * Viewport content */ void BrainOpenGLFixedPipeline::drawSpacerAnnotations(const BrainOpenGLViewportContent* tabContent) { if (tabContent->getSpacerTabContent() == NULL) { return; } int tabViewport[4]; tabContent->getModelViewport(tabViewport); CaretAssertMessage(m_brain, "m_brain must NOT be NULL for drawing spacer tab annotations."); glViewport(tabViewport[0], tabViewport[1], tabViewport[2], tabViewport[3]); glMatrixMode(GL_PROJECTION); glPushMatrix(); glOrtho(0.0, tabViewport[2], 0.0, tabViewport[3], -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); CaretAssert(m_windowIndex == tabContent->getWindowIndex()); this->browserTabContent = NULL; m_clippingPlaneGroup = NULL; //const_cast(tabContent->getBrowserTabContent()->getClippingPlaneGroup()); this->windowTabIndex = -1; SpacerTabIndex spacerTabIndex; SpacerTabContent* spacerTabContent = tabContent->getSpacerTabContent(); CaretAssert(spacerTabContent); spacerTabIndex = spacerTabContent->getSpacerTabIndex(); const bool annotationModeFlag = (m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_windowIndex, this->windowTabIndex, spacerTabIndex, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, annotationModeFlag); m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::SPACER, m_annotationColorBarsForDrawing, m_specialCaseGraphicsAnnotations, annotationDrawingNullSurface, annotationDrawingUnusedSurfaceScaling); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } /** * Draw the tab annotations. * * @param tabContent * Viewport content */ void BrainOpenGLFixedPipeline::drawTabAnnotations(const BrainOpenGLViewportContent* tabContent) { if (tabContent->getBrowserTabContent() == NULL) { return; } int tabViewport[4]; tabContent->getModelViewport(tabViewport); CaretAssertMessage(m_brain, "m_brain must NOT be NULL for drawing window annotations."); glViewport(tabViewport[0], tabViewport[1], tabViewport[2], tabViewport[3]); glMatrixMode(GL_PROJECTION); glPushMatrix(); glOrtho(0.0, tabViewport[2], 0.0, tabViewport[3], -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); CaretAssert(m_windowIndex == tabContent->getWindowIndex()); this->browserTabContent = tabContent->getBrowserTabContent(); m_clippingPlaneGroup = const_cast(tabContent->getBrowserTabContent()->getClippingPlaneGroup()); CaretAssert(m_clippingPlaneGroup); this->windowTabIndex = this->browserTabContent->getTabNumber(); const bool annotationModeFlag = (m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_windowIndex, this->windowTabIndex, SpacerTabIndex(), BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, annotationModeFlag); m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::TAB, m_annotationColorBarsForDrawing, m_specialCaseGraphicsAnnotations, annotationDrawingNullSurface, annotationDrawingUnusedSurfaceScaling); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } /** * Draw the window annotations. * * @param windowViewport * Viewport (x, y, w, h). */ void BrainOpenGLFixedPipeline::drawWindowAnnotations(const int windowViewport[4]) { CaretAssertMessage(m_brain, "m_brain must NOT be NULL for drawing window annotations."); /* * User may want window annotations only when in tile tabs view. */ BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WindowDrawingMode windowDrawingMode = BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO; if (m_tileTabsActiveFlag) { windowDrawingMode = BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_YES; } else { const DisplayPropertiesAnnotation* dpa = m_brain->getDisplayPropertiesAnnotation(); if (dpa->isDisplayWindowAnnotationsInSingleTabViews(m_windowIndex)) { windowDrawingMode = BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_YES; } } glViewport(windowViewport[0], windowViewport[1], windowViewport[2], windowViewport[3]); glMatrixMode(GL_PROJECTION); glPushMatrix(); glOrtho(0.0, windowViewport[2], 0.0, windowViewport[3], -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); /* * No valid tab */ this->windowTabIndex = -1; const bool annotationModeFlag = (m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_windowIndex, this->windowTabIndex, SpacerTabIndex(), windowDrawingMode, annotationModeFlag); m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::WINDOW, m_annotationColorBarsForDrawing, m_specialCaseGraphicsAnnotations, annotationDrawingNullSurface, annotationDrawingUnusedSurfaceScaling); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } /** * Draw a model. * * @param mode * The mode of operations (draw, select, etc). * @param viewportContent * Viewport contents for drawing. */ void BrainOpenGLFixedPipeline::drawModelInternal(Mode mode, const BrainOpenGLViewportContent* viewportContent) { ElapsedTimer et; et.start(); CaretAssert(m_windowIndex == viewportContent->getWindowIndex()); this->windowTabIndex = -1; this->browserTabContent = viewportContent->getBrowserTabContent(); m_mirroredClippingEnabled = false; Model* model = NULL; this->mode = mode; glPushAttrib(GL_MULTISAMPLE_BIT); switch (this->mode) { case MODE_DRAWING: break; case MODE_IDENTIFICATION: glDisable(GL_MULTISAMPLE); break; case MODE_PROJECTION: glDisable(GL_MULTISAMPLE); break; } if (this->browserTabContent != NULL) { m_clippingPlaneGroup = const_cast(this->browserTabContent->getClippingPlaneGroup()); CaretAssert(m_clippingPlaneGroup); Model* model = this->browserTabContent->getModelForDisplay(); this->windowTabIndex = this->browserTabContent->getTabNumber(); int viewport[4]; viewportContent->getModelViewport(viewport); this->mode = mode; this->checkForOpenGLError(model, "At beginning of drawModelInternal()"); if(model != NULL) { CaretAssert((this->windowTabIndex >= 0) && (this->windowTabIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)); ModelChart* modelChart = dynamic_cast(model); ModelChartTwo* modelTwoChart = dynamic_cast(model); ModelSurface* surfaceModel = dynamic_cast(model); ModelSurfaceMontage* surfaceMontageModel = dynamic_cast(model); ModelVolume* volumeModel = dynamic_cast(model); ModelWholeBrain* wholeBrainModel = dynamic_cast(model); if (modelChart != NULL) { drawChartOneData(browserTabContent, modelChart, viewport); } else if (modelTwoChart != NULL) { drawChartTwoData(viewportContent, modelTwoChart, viewport); } else if (surfaceModel != NULL) { m_mirroredClippingEnabled = true; this->drawSurfaceModel(browserTabContent, surfaceModel, viewport); } else if (surfaceMontageModel != NULL) { m_mirroredClippingEnabled = true; this->drawSurfaceMontageModel(browserTabContent, surfaceMontageModel, viewport); } else if (volumeModel != NULL) { this->drawVolumeModel(browserTabContent, volumeModel, viewport); } else if (wholeBrainModel != NULL) { this->drawWholeBrainModel(browserTabContent, wholeBrainModel, viewport); } else { CaretAssertMessage(0, "Unknown type of model for drawing"); } } } drawBackgroundImage(viewportContent); glPopAttrib(); glFlush(); this->checkForOpenGLError(model, "At end of drawModelInternal()"); if (model != NULL) { CaretLogFine("Time to draw " + model->getNameForGUI(false) + " was " + AString::number(et.getElapsedTimeSeconds()) + " seconds"); } } /** * Set the viewport. * * @param viewport * Values for viewport (x, y, x-size, y-size) * @param projectionType * Type of view projection. */ void BrainOpenGLFixedPipeline::setViewportAndOrthographicProjection(const int32_t viewport[4], const ProjectionViewTypeEnum::Enum projectionType) { glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); glMatrixMode(GL_PROJECTION); glLoadIdentity(); this->setOrthographicProjection(viewport, projectionType); glMatrixMode(GL_MODELVIEW); } /** * Set the viewport for a volume. * * @param viewport * Values for viewport (x, y, x-size, y-size) * @param projectionType * Type of view projection. * @param volume * Volume for use in setting orthographic projection. */ void BrainOpenGLFixedPipeline::setViewportAndOrthographicProjectionForWholeBrainVolume(const int32_t viewport[4], const ProjectionViewTypeEnum::Enum projectionType, const VolumeMappableInterface* volume) { CaretAssert(volume); glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); BoundingBox boundingBox; volume->getVoxelSpaceBoundingBox(boundingBox); glMatrixMode(GL_PROJECTION); glLoadIdentity(); setOrthographicProjectionForWithBoundingBox(viewport, projectionType, &boundingBox); glMatrixMode(GL_MODELVIEW); } /** * Set the viewport for a surface file. * * @param viewport * Values for viewport (x, y, x-size, y-size) * @param projectionType * Type of view projection. * @param surfaceFile * Surface file for use in setting orthographic projection. */ void BrainOpenGLFixedPipeline::setViewportAndOrthographicProjectionForSurfaceFile(const int32_t viewport[4], const ProjectionViewTypeEnum::Enum projectionType, const SurfaceFile* surfaceFile) { CaretAssert(surfaceFile); glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); glMatrixMode(GL_PROJECTION); glLoadIdentity(); setOrthographicProjectionForWithBoundingBox(viewport, projectionType, surfaceFile->getBoundingBox()); glMatrixMode(GL_MODELVIEW); } /** * Disable clipping planes. */ void BrainOpenGLFixedPipeline::disableClippingPlanes() { glDisable(GL_CLIP_PLANE0); glDisable(GL_CLIP_PLANE1); glDisable(GL_CLIP_PLANE2); glDisable(GL_CLIP_PLANE3); glDisable(GL_CLIP_PLANE4); glDisable(GL_CLIP_PLANE5); } /** * Apply the clipping planes for the given data type and structure. * * @param clippingDataType * Type of data that is being clipped. * @param structureIn * The structure. */ void BrainOpenGLFixedPipeline::applyClippingPlanes(const ClippingDataType clippingDataType, const StructureEnum::Enum structureIn) { disableClippingPlanes(); StructureEnum::Enum structure = StructureEnum::CORTEX_LEFT; if (m_mirroredClippingEnabled) { structure = structureIn; } if (browserTabContent == NULL) { return; } CaretAssert(m_clippingPlaneGroup); float rotation[3]; m_clippingPlaneGroup->getRotationAngles(rotation); float panning[3]; m_clippingPlaneGroup->getTranslationForStructure(structure, panning); float rotationAngles[3]; m_clippingPlaneGroup->getRotationAngles(rotationAngles); float thickness[3]; m_clippingPlaneGroup->getThickness(thickness); float minX = -thickness[0] / 2.0; float maxX = thickness[0] / 2.0; float minY = -thickness[1] / 2.0; float maxY = thickness[1] / 2.0; float minZ = -thickness[2] / 2.0; float maxZ = thickness[2] / 2.0; GLfloat rotMatrix[16]; m_clippingPlaneGroup->getRotationMatrixForStructure(structure).getMatrixForOpenGL(rotMatrix); if (m_clippingPlaneGroup->isDisplayClippingBoxSelected()) { glColor3f(1.0, 0.0, 0.0); setLineWidth(2.0); glPushMatrix(); glTranslatef(panning[0], panning[1], panning[2]); glMultMatrixf(rotMatrix); glBegin(GL_LINE_LOOP); glVertex3f(minX, minY, minZ); glVertex3f(maxX, minY, minZ); glVertex3f(maxX, maxY, minZ); glVertex3f(minX, maxY, minZ); glEnd(); glBegin(GL_LINE_LOOP); glVertex3f(minX, minY, maxZ); glVertex3f(maxX, minY, maxZ); glVertex3f(maxX, maxY, maxZ); glVertex3f(minX, maxY, maxZ); glEnd(); glBegin(GL_LINES); glVertex3f(minX, minY, minZ); glVertex3f(minX, minY, maxZ); glVertex3f(maxX, minY, minZ); glVertex3f(maxX, minY, maxZ); glVertex3f(maxX, maxY, minZ); glVertex3f(maxX, maxY, maxZ); glVertex3f(minX, maxY, minZ); glVertex3f(minX, maxY, maxZ); glEnd(); glPopMatrix(); } switch (clippingDataType) { case CLIPPING_DATA_TYPE_FEATURES: if (! m_clippingPlaneGroup->isFeaturesSelected()) { return; } break; case CLIPPING_DATA_TYPE_SURFACE: if (! m_clippingPlaneGroup->isSurfaceSelected()) { return; } break; case CLIPPING_DATA_TYPE_VOLUME: if (! m_clippingPlaneGroup->isVolumeSelected()) { return; } break; } std::vector planes = m_clippingPlaneGroup->getActiveClippingPlanesForStructure(structure); const int32_t numPlanes = static_cast(planes.size()); for (int32_t i = 0; i < numPlanes; i++) { const Plane* p = planes[i]; double a, b, c, d; p->getPlane(a, b, c, d); const GLdouble abcd[4] = { a, b, c, d }; glClipPlane(GL_CLIP_PLANE0 + i, abcd); glEnable(GL_CLIP_PLANE0 + i); } } /** * Is the coordinate inside the clipping planes? * * If a clipping plane for an axis is off, the coordinate is considered * to be inside the clipping plane. * * @param structureIn * The structure. Note that right and left hemispheres are mirror flipped. * @param xyz * The coordinate. * * @return * True if inside the clipping planes, else false. */ bool BrainOpenGLFixedPipeline::isCoordinateInsideClippingPlanesForStructure(const StructureEnum::Enum structureIn, const float xyz[3]) const { CaretAssert(m_clippingPlaneGroup); StructureEnum::Enum structure = StructureEnum::CORTEX_LEFT; if (m_mirroredClippingEnabled) { structure = structureIn; } return m_clippingPlaneGroup->isCoordinateInsideClippingPlanesForStructure(structure, xyz); } /** * @return Is clipping of features enabled? */ bool BrainOpenGLFixedPipeline::isFeatureClippingEnabled() const { CaretAssert(m_clippingPlaneGroup); return m_clippingPlaneGroup->isFeaturesAndAnyAxisSelected(); } /** * Apply the viewing transformations for the content of the browser tab. * * @param model * Model that is being drawn. * @param objectCenterXYZ * If not NULL, contains center of object about * which rotation should take place. * @param projectionViewType * Projection view type. */ void BrainOpenGLFixedPipeline::applyViewingTransformations(const Model* model, const float objectCenterXYZ[3], const ProjectionViewTypeEnum::Enum projectionViewType) { CaretAssert(model); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); float eyeX = 0.0; float eyeY = 0.0; float eyeZ = 0.0; float centerX = 0.0; float centerY = 0.0; float centerZ = 0.0; float upX = 0.0; float upY = 0.0; float upZ = 0.0; bool useGluLookAt = false; bool rightCortexFlatFlag = false; switch (projectionViewType) { case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_ANTERIOR: case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_DORSAL: case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_POSTERIOR: case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_VENTRAL: eyeZ = BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance; upY = 1.0; useGluLookAt = true; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_FLAT_SURFACE: eyeZ = BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance; upY = 1.0; useGluLookAt = true; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_LATERAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_MEDIAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_FLAT_SURFACE: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_LATERAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_MEDIAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_FLAT_SURFACE: if (model->getModelType() == ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE) { const ModelSurfaceMontage* surfaceMontageModel = dynamic_cast(model); CaretAssert(surfaceMontageModel); if (surfaceMontageModel != NULL) { if (surfaceMontageModel->getSelectedConfigurationType(this->windowTabIndex) == SurfaceMontageConfigurationTypeEnum::FLAT_CONFIGURATION) { rightCortexFlatFlag = true; } } } break; } if (useGluLookAt) { gluLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ); } float translation[3]; double rotationMatrixElements[16]; float scaling; browserTabContent->getTransformationsForOpenGLDrawing(projectionViewType, translation, rotationMatrixElements, scaling); glTranslatef(translation[0], translation[1], translation[2]); glMultMatrixd(rotationMatrixElements); /* * Save the inverse rotation matrix which may be used * later by some drawing functions. */ Matrix4x4 inverseMatrix; inverseMatrix.setMatrixFromOpenGL(rotationMatrixElements); this->inverseRotationMatrixValid = inverseMatrix.invert(); if (this->inverseRotationMatrixValid) { inverseMatrix.getMatrixForOpenGL(this->inverseRotationMatrix); } glScalef(scaling, scaling, scaling); if (rightCortexFlatFlag) { /* * When drawing right flat, the translation is "left translation" * so need to flip sign of X-offset. */ float rightFlatOffsetX, rightFlatOffsetY; browserTabContent->getRightCortexFlatMapOffset(rightFlatOffsetX, rightFlatOffsetY); glTranslatef(-rightFlatOffsetX, rightFlatOffsetY, 0.0); const float rightFlatMapZoomFactor = browserTabContent->getRightCortexFlatMapZoomFactor(); glScalef(rightFlatMapZoomFactor, rightFlatMapZoomFactor, rightFlatMapZoomFactor); } if (objectCenterXYZ != NULL) { /* * Place center of surface at origin. */ glTranslatef(-objectCenterXYZ[0], -objectCenterXYZ[1], -objectCenterXYZ[2]); } } /** * For a volume, get translation and scaling so that the volume 'fills' * the window. * * @param volume * The volume. * @param sliceViewPlane * The slice viewing plane. * @param orthographicExtent * The orthographic bounds * @param translationOut * Output of translation. * @param scalingOut * Output of scaling. * */ void BrainOpenGLFixedPipeline::getVolumeFitToWindowScalingAndTranslation(const VolumeMappableInterface* volume, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const double orthographicExtent[6], float translationOut[3], float& scalingOut) const { /* * Apply some scaling and translation so that the volume slice, by default * is not larger than the window in which it is being viewed. */ scalingOut = 1.0; translationOut[0] = 0.0; translationOut[1] = 0.0; translationOut[2] = 0.0; if (volume != NULL) { BoundingBox boundingBox; volume->getVoxelSpaceBoundingBox(boundingBox); int64_t dimI, dimJ, dimK, numMaps, numComponents; volume->getDimensions(dimI, dimJ, dimK, numMaps, numComponents); if ((dimI > 2) && (dimJ > 2) && (dimK > 2)) { float volumeCenter[3] = { (boundingBox.getMinX() + boundingBox.getMaxX()) / 2, (boundingBox.getMinY() + boundingBox.getMaxY()) / 2, (boundingBox.getMinZ() + boundingBox.getMaxZ()) / 2 }; /* * Translate so that the center voxel (by dimenisons) * is at the center of the screen. */ translationOut[0] = -volumeCenter[0]; translationOut[1] = -volumeCenter[1]; translationOut[2] = -volumeCenter[2]; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: break; case VolumeSliceViewPlaneEnum::AXIAL: translationOut[2] = 0.0; break; case VolumeSliceViewPlaneEnum::CORONAL: translationOut[1] = 0.0; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: translationOut[0] = 0.0; break; } /* * Scale so volume fills, but does not extend out of window. */ const float xExtent = (boundingBox.getMaxX() - boundingBox.getMinX()) / 2; const float yExtent = (boundingBox.getMaxY() - boundingBox.getMinY()) / 2; const float zExtent = (boundingBox.getMaxZ() - boundingBox.getMinZ()) / 2; const float orthoExtentX = std::min(std::fabs(orthographicExtent[0]), std::fabs(orthographicExtent[1])); const float orthoExtentY = std::min(std::fabs(orthographicExtent[2]), std::fabs(orthographicExtent[3])); float temp; float scaleWindowX = (orthoExtentX / xExtent); temp = (orthoExtentX / yExtent);/* parasaggital y is screen x */ if (temp < scaleWindowX) scaleWindowX = temp; float scaleWindowY = (orthoExtentY / zExtent); temp = (orthoExtentY / yExtent);/* axial y is screen y */ if (temp < scaleWindowY) scaleWindowY = temp; scalingOut = std::min(scaleWindowX, scaleWindowY); scalingOut *= 0.98; } } } void BrainOpenGLFixedPipeline::initializeMembersBrainOpenGL() { this->initializedOpenGLFlag = false; this->modeProjectionData = NULL; } /** * Initialize OpenGL. */ void BrainOpenGLFixedPipeline::initializeOpenGL() { if (s_staticInitialized == false) { s_staticInitialized = true; BrainOpenGL::initializeOpenGL(); } glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glClearDepth(1.0); glFrontFace(GL_CCW); /* * As normal vectors are multiplied by transformation matrices, their * lengths may no longer be one and cause drawing errors. * GL_NORMALIZE will rescale normal vectors to one to prevent this problem. * GL_RESCALE_NORMAL was added in later versions of OpenGL and * is reported to be more efficient. However, GL_RESCALE_NORMAL * does not seem to work with OpenGL 4.2 on Linux, whereas GL_NORMALIZE * seems to work on all operating systems and versions of OpenGL. */ glEnable(GL_NORMALIZE); /* * OpenGL RedBook status that multisampling is available if * GL_SAMPLE_BUFFES is 1 and GL_SAMPLES is greater than one. */ GLint sampleBuffersCount = 0; glGetIntegerv(GL_SAMPLE_BUFFERS, &sampleBuffersCount); GLint sampleCount = 0; glGetIntegerv(GL_SAMPLES, &sampleCount); const bool enableMultiSampleFlag = ((sampleBuffersCount >= 1) && (sampleCount > 1)); if (enableMultiSampleFlag) { glEnable(GL_MULTISAMPLE); } else { glDisable(GL_MULTISAMPLE); } /* * Avoid drawing backfacing polygons */ glCullFace(GL_BACK); glEnable(GL_CULL_FACE); glShadeModel(GL_SMOOTH); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE); float lightColor[] = { 0.9f, 0.9f, 0.9f, 1.0f }; glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor); glLightfv(GL_LIGHT1, GL_DIFFUSE, lightColor); glEnable(GL_LIGHT0); glDisable(GL_LIGHT1); float materialColor[] = { 0.8f, 0.8f, 0.8f, 1.0f }; glMaterialfv(GL_FRONT, GL_DIFFUSE, materialColor); glColorMaterial(GL_FRONT, GL_DIFFUSE); float ambient[] = { 0.8f, 0.8f, 0.8f, 1.0f }; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); if (m_shapeSphere == NULL) { m_shapeSphere = new BrainOpenGLShapeSphere(5, 0.5); } if (m_shapeCone == NULL) { m_shapeCone = new BrainOpenGLShapeCone(8); } if (m_shapeCylinder == NULL) { m_shapeCylinder = new BrainOpenGLShapeCylinder(8); } if (m_shapeCube == NULL) { m_shapeCube = new BrainOpenGLShapeCube(1.0, BrainOpenGLShapeCube::NORMAL); } if (m_shapeCubeRounded == NULL) { m_shapeCubeRounded = new BrainOpenGLShapeCube(1.0, BrainOpenGLShapeCube::ROUNDED); } if (this->initializedOpenGLFlag) { return; } this->initializedOpenGLFlag = true; /* * Remaining items need to executed only once. */ } /** * Enable lighting based upon the current mode. */ void BrainOpenGLFixedPipeline::enableLighting() { float lightPosition[] = { 0.0f, 0.0f, 1000.0f, 0.0f }; switch (this->mode) { case MODE_DRAWING: glPushMatrix(); glLoadIdentity(); glLightfv(GL_LIGHT0, GL_POSITION, lightPosition); glEnable(GL_LIGHT0); /* * Light 1 position is opposite of light 0 */ lightPosition[0] = -lightPosition[0]; lightPosition[1] = -lightPosition[1]; lightPosition[2] = -lightPosition[2]; glLightfv(GL_LIGHT1, GL_POSITION, lightPosition); glEnable(GL_LIGHT1); glPopMatrix(); glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); if (browserTabContent != NULL) { if ( ! browserTabContent->isLightingEnabled()) { this->disableLighting(); } } break; case MODE_IDENTIFICATION: case MODE_PROJECTION: this->disableLighting(); break; } } /** * Disable lighting. */ void BrainOpenGLFixedPipeline::disableLighting() { glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); } /** * Enable line anti-aliasing (line smoothing) which also required blending. */ void BrainOpenGLFixedPipeline::enableLineAntiAliasing() { glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT); /* * If multi-sampling is enabled, it handle anti-aliasing */ if (glIsEnabled(GL_MULTISAMPLE)) { return; } return ; glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); } /** * Disable line anti-aliasing (line smoothing) which also required blending. */ void BrainOpenGLFixedPipeline::disableLineAntiAliasing() { glPopAttrib(); /* * If multi-sampling is enabled, it handle anti-aliasing */ if (glIsEnabled(GL_MULTISAMPLE)) { return; } // glDisable(GL_LINE_SMOOTH); // glDisable(GL_BLEND); } /** * Draw contents of a surface model. * @param browserTabContent * Browser tab containing surface model. * @param surfaceModel * Model that is drawn. * @param viewport * Viewport for drawing region. */ void BrainOpenGLFixedPipeline::drawSurfaceModel(BrowserTabContent* browserTabContent, ModelSurface* surfaceModel, const int32_t viewport[4]) { Surface* surface = surfaceModel->getSurface(); float center[3]; surface->getBoundingBox()->getCenter(center); this->setViewportAndOrthographicProjectionForSurfaceFile(viewport, browserTabContent->getProjectionViewType(), surface); this->applyViewingTransformations(surfaceModel, center, browserTabContent->getProjectionViewType()); const float* nodeColoringRGBA = this->surfaceNodeColoring->colorSurfaceNodes(surfaceModel, surface, this->windowTabIndex); this->drawSurface(surface, browserTabContent->getScaling(), nodeColoringRGBA, true); } /** * Draw the surface axes. */ void BrainOpenGLFixedPipeline::drawSurfaceAxes() { const float bigNumber = 1000000.0; glPushMatrix(); glColor3f(1.0, 0.0, 0.0); glBegin(GL_LINES); glVertex3f(-bigNumber, 0.0, 0.0); glVertex3f( bigNumber, 0.0, 0.0); glVertex3f(0.0, -bigNumber, 0.0); glVertex3f(0.0, bigNumber, 0.0); glVertex3f(0.0, 0.0, -bigNumber); glVertex3f(0.0, 0.0, bigNumber); glEnd(); glPopMatrix(); } /** * Draw a surface. * * @param surface * Surface that is drawn. * @param surfaceScaling * User scaling of surface. * @param nodeColoringRGBA * RGBA coloring for the nodes. * @param drawAnnotationsInModelSpaceFlag * If true, draw annotations in model space. */ void BrainOpenGLFixedPipeline::drawSurface(Surface* surface, const float surfaceScaling, const float* nodeColoringRGBA, const bool drawAnnotationsInModelSpaceFlag) { glPushAttrib(GL_COLOR_BUFFER_BIT); const DisplayPropertiesSurface* dps = m_brain->getDisplayPropertiesSurface(); glMatrixMode(GL_MODELVIEW); glEnable(GL_DEPTH_TEST); applyClippingPlanes(BrainOpenGLFixedPipeline::CLIPPING_DATA_TYPE_SURFACE, surface->getStructure()); this->enableLighting(); const SurfaceDrawingTypeEnum::Enum drawingType = dps->getSurfaceDrawingType(); switch (this->mode) { case MODE_DRAWING: { switch (drawingType) { case SurfaceDrawingTypeEnum::DRAW_HIDE: break; case SurfaceDrawingTypeEnum::DRAW_AS_LINKS: /* * Draw first as triangles without coloring which uses * the background color. This prevents edges on back * from being seen. */ glPolygonOffset(1.0, 1.0); glEnable(GL_POLYGON_OFFSET_FILL); disableLighting(); this->drawSurfaceTrianglesWithVertexArrays(surface, NULL); glDisable(GL_POLYGON_OFFSET_FILL); /* * Now draw as polygon but outline only, do not fill. */ enableLighting(); setLineWidth(dps->getLinkSize()); glPolygonMode(GL_FRONT, GL_LINE); this->drawSurfaceTrianglesWithVertexArrays(surface, nodeColoringRGBA); glPolygonMode(GL_FRONT, GL_FILL); break; case SurfaceDrawingTypeEnum::DRAW_AS_NODES: this->drawSurfaceNodes(surface, nodeColoringRGBA); break; case SurfaceDrawingTypeEnum::DRAW_AS_TRIANGLES: /* * Enable alpha blending so that surface transparency * (using first overlay opacity) will function. */ GLboolean blendingEnabled = false; glGetBooleanv(GL_BLEND, &blendingEnabled); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); const DisplayPropertiesBorders* dpb = m_brain->getDisplayPropertiesBorders(); const float borderAboveSurfaceOffset = dpb->getAboveSurfaceOffset(); if (borderAboveSurfaceOffset != 0.0) { const float factor = borderAboveSurfaceOffset; const float units = 1.0; glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(factor, units); } glPushAttrib(GL_ENABLE_BIT); glDisable(GL_CULL_FACE); this->drawSurfaceTrianglesWithVertexArrays(surface, nodeColoringRGBA); glPopAttrib(); if (borderAboveSurfaceOffset != 0.0) { glDisable(GL_POLYGON_OFFSET_FILL); } if (blendingEnabled == false) { glDisable(GL_BLEND); } break; } this->disableClippingPlanes(); if (dps->isDisplayNormalVectors()) { drawSurfaceNormalVectors(surface); } this->drawSurfaceBorders(surface); this->drawSurfaceFoci(surface); this->drawSurfaceNodeAttributes(surface); this->drawSurfaceBorderBeingDrawn(surface); /* * Draw annotations for this surface and maybe draw * the model annotations. */ const bool annotationModeFlag = (m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_windowIndex, this->windowTabIndex, SpacerTabIndex(), BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, annotationModeFlag); std::vector emptyColorBars; std::vector emptyViewportAnnotations; m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::SURFACE, emptyColorBars, emptyViewportAnnotations, surface, surfaceScaling); if (drawAnnotationsInModelSpaceFlag) { m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::STEREOTAXIC, emptyColorBars, emptyViewportAnnotations, annotationDrawingNullSurface, annotationDrawingUnusedSurfaceScaling); } } break; case MODE_IDENTIFICATION: { /* * Disable shading since ID info is encoded in rgba coloring */ glShadeModel(GL_FLAT); if (drawingType != SurfaceDrawingTypeEnum::DRAW_HIDE) { this->drawSurfaceNodes(surface, nodeColoringRGBA); this->drawSurfaceTriangles(surface, nodeColoringRGBA); } this->disableClippingPlanes(); if (dps->isDisplayNormalVectors()) { drawSurfaceNormalVectors(surface); } this->drawSurfaceBorders(surface); this->drawSurfaceFoci(surface); this->drawSurfaceNodeAttributes(surface); /* * Draw annotations for this surface and maybe draw * the model annotations. */ const bool annotationModeFlag = (m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_windowIndex, this->windowTabIndex, SpacerTabIndex(), BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, annotationModeFlag); std::vector emptyColorBars; std::vector emptyViewportAnnotations; m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::SURFACE, emptyColorBars, emptyViewportAnnotations, surface, surfaceScaling); if (drawAnnotationsInModelSpaceFlag) { m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::STEREOTAXIC, emptyColorBars, emptyViewportAnnotations, annotationDrawingNullSurface, annotationDrawingUnusedSurfaceScaling); } /* * Re-enable shading since ID info is encoded in rgba coloring */ glShadeModel(GL_SMOOTH); } break; case MODE_PROJECTION: /* * Disable shading since ID info is encoded in rgba coloring */ glShadeModel(GL_FLAT); if (drawingType != SurfaceDrawingTypeEnum::DRAW_HIDE) { this->drawSurfaceTriangles(surface, nodeColoringRGBA); } /* * Re-enable shading since ID info is encoded in rgba coloring */ glShadeModel(GL_SMOOTH); break; } this->disableLighting(); this->disableClippingPlanes(); glPopAttrib(); } /** * Draw a surface as individual triangles. * @param surface * Surface that is drawn. * @param nodeColoringRGBA * RGBA coloring for the nodes. */ void BrainOpenGLFixedPipeline::drawSurfaceTriangles(Surface* surface, const float* nodeColoringRGBA) { const int numTriangles = surface->getNumberOfTriangles(); const int32_t* triangles = surface->getTriangle(0); const float* coordinates = surface->getCoordinate(0); const float* normals = surface->getNormalVector(0); SelectionItemSurfaceTriangle* triangleID = NULL; /* * Check for a 'selection' type mode */ bool isSelect = false; bool isProjection = false; switch (this->mode) { case MODE_DRAWING: break; case MODE_IDENTIFICATION: triangleID = m_brain->getSelectionManager()->getSurfaceTriangleIdentification(); if (triangleID->isEnabledForSelection()) { isSelect = true; } else { return; } break; case MODE_PROJECTION: isSelect = true; isProjection = true; break; } if (isSelect) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } uint8_t rgba[4]; glBegin(GL_TRIANGLES); for (int32_t i = 0; i < numTriangles; i++) { const int32_t i3 = i * 3; const int32_t n1 = triangles[i3]; const int32_t n2 = triangles[i3+1]; const int32_t n3 = triangles[i3+2]; if (isSelect) { this->colorIdentification->addItem(rgba, SelectionItemDataTypeEnum::SURFACE_TRIANGLE, i); glColor3ubv(rgba); glNormal3fv(&normals[n1*3]); glVertex3fv(&coordinates[n1*3]); glNormal3fv(&normals[n2*3]); glVertex3fv(&coordinates[n2*3]); glNormal3fv(&normals[n3*3]); glVertex3fv(&coordinates[n3*3]); } else { glColor4fv(&nodeColoringRGBA[n1*4]); glNormal3fv(&normals[n1*3]); glVertex3fv(&coordinates[n1*3]); glColor4fv(&nodeColoringRGBA[n2*4]); glNormal3fv(&normals[n2*3]); glVertex3fv(&coordinates[n2*3]); glColor4fv(&nodeColoringRGBA[n3*4]); glNormal3fv(&normals[n3*3]); glVertex3fv(&coordinates[n3*3]); } } glEnd(); if (isSelect) { int32_t triangleIndex = -1; float depth = -1.0; this->getIndexFromColorSelection(SelectionItemDataTypeEnum::SURFACE_TRIANGLE, this->mouseX, this->mouseY, triangleIndex, depth); if (triangleIndex >= 0) { bool isTriangleIdAccepted = false; if (triangleID != NULL) { if (triangleID->isOtherScreenDepthCloserToViewer(depth)) { triangleID->setBrain(surface->getBrainStructure()->getBrain()); triangleID->setSurface(surface); triangleID->setTriangleNumber(triangleIndex); const int32_t* triangleNodeIndices = surface->getTriangle(triangleIndex); triangleID->setNearestNode(triangleNodeIndices[0]); triangleID->setScreenDepth(depth); isTriangleIdAccepted = true; CaretLogFine("Selected Triangle: " + triangleID->toString()); } else { CaretLogFine("Rejecting Selected Triangle but still using: " + triangleID->toString()); } } /* * Node indices */ const int32_t n1 = triangles[triangleIndex*3]; const int32_t n2 = triangles[triangleIndex*3 + 1]; const int32_t n3 = triangles[triangleIndex*3 + 2]; /* * Node coordinates */ const float* c1 = &coordinates[n1*3]; const float* c2 = &coordinates[n2*3]; const float* c3 = &coordinates[n3*3]; const float average[3] = { c1[0] + c2[0] + c3[0], c1[1] + c2[1] + c3[1], c1[2] + c2[2] + c3[2] }; if (triangleID != NULL) { if (isTriangleIdAccepted) { this->setSelectedItemScreenXYZ(triangleID, average); } } GLdouble selectionModelviewMatrix[16]; glGetDoublev(GL_MODELVIEW_MATRIX, selectionModelviewMatrix); GLdouble selectionProjectionMatrix[16]; glGetDoublev(GL_PROJECTION_MATRIX, selectionProjectionMatrix); GLint selectionViewport[4]; glGetIntegerv(GL_VIEWPORT, selectionViewport); /* * Window positions of each coordinate */ double dc1[3] = { c1[0], c1[1], c1[2] }; double dc2[3] = { c2[0], c2[1], c2[2] }; double dc3[3] = { c3[0], c3[1], c3[2] }; double wc1[3], wc2[3], wc3[3]; if (gluProject(dc1[0], dc1[1], dc1[2], selectionModelviewMatrix, selectionProjectionMatrix, selectionViewport, &wc1[0], &wc1[1], &wc1[2]) && gluProject(dc2[0], dc2[1], dc2[2], selectionModelviewMatrix, selectionProjectionMatrix, selectionViewport, &wc2[0], &wc2[1], &wc2[2]) && gluProject(dc3[0], dc3[1], dc3[2], selectionModelviewMatrix, selectionProjectionMatrix, selectionViewport, &wc3[0], &wc3[1], &wc3[2])) { const double d1 = MathFunctions::distanceSquared2D(wc1[0], wc1[1], this->mouseX, this->mouseY); const double d2 = MathFunctions::distanceSquared2D(wc2[0], wc2[1], this->mouseX, this->mouseY); const double d3 = MathFunctions::distanceSquared2D(wc3[0], wc3[1], this->mouseX, this->mouseY); if (triangleID != NULL) { if (isTriangleIdAccepted) { triangleID->setNearestNode(n3); triangleID->setNearestNodeScreenXYZ(wc3); triangleID->setNearestNodeModelXYZ(dc3); if ((d1 < d2) && (d1 < d3)) { triangleID->setNearestNode(n1); triangleID->setNearestNodeScreenXYZ(wc1); triangleID->setNearestNodeModelXYZ(dc1); } else if ((d2 < d1) && (d2 < d3)) { triangleID->setNearestNode(n2); triangleID->setNearestNodeScreenXYZ(wc2); triangleID->setNearestNodeModelXYZ(dc2); } } } /* * Getting projected position? */ if (isProjection) { /* * Place window coordinates of triangle's nodes * onto the screen by setting Z-coordinate to zero */ wc1[2] = 0.0; wc2[2] = 0.0; wc3[2] = 0.0; /* * Area of triangle when projected to display */ const double triangleDisplayArea = MathFunctions::triangleArea(wc1, wc2, wc3); /* * If area of triangle on display is small, * use a coordinate from the triangle */ if (triangleDisplayArea < 0.001) { float barycentricAreas[3] = { 1.0, 0.0, 0.0 }; int barycentricNodes[3] = { n1, n1, n1 }; this->setProjectionModeData(depth, c1, surface->getStructure(), barycentricAreas, barycentricNodes, surface->getNumberOfNodes()); } else { /* * Determine position in triangle using barycentric coordinates */ double displayXYZ[3] = { (double)this->mouseX, (double)this->mouseY, 0.0 }; const double areaU = (MathFunctions::triangleArea(displayXYZ, wc2, wc3) / triangleDisplayArea); const double areaV = (MathFunctions::triangleArea(displayXYZ, wc3, wc1) / triangleDisplayArea); const double areaW = (MathFunctions::triangleArea(displayXYZ, wc1, wc2) / triangleDisplayArea); double totalArea = areaU + areaV + areaW; if (totalArea <= 0) { totalArea = 1.0; } if ((areaU < 0.0) || (areaV < 0.0) || (areaW < 0.0)) { CaretLogWarning("Invalid tile area: less than zero when projecting to surface."); } else { /* * Convert to surface coordinates */ const float projectedXYZ[3] = { (float)((dc1[0]*areaU + dc2[0]*areaV + dc3[0]*areaW) / totalArea), (float)((dc1[1]*areaU + dc2[1]*areaV + dc3[1]*areaW) / totalArea), (float)((dc1[2]*areaU + dc2[2]*areaV + dc3[2]*areaW) / totalArea) }; const float barycentricAreas[3] = { (float)areaU, (float)areaV, (float)areaW }; const int32_t barycentricNodes[3] = { n1, n2, n3 }; this->setProjectionModeData(depth, projectedXYZ, surface->getStructure(), barycentricAreas, barycentricNodes, surface->getNumberOfNodes()); } } } } CaretLogFine("Selected Triangle: " + QString::number(triangleIndex)); } } } /** * During projection mode, set the projected data. If the * projection data is already set, it will be overridden * if the new data is closer, in screen depth, to the user. * * @param screenDepth * Screen depth of data. * @param xyz * Stereotaxic coordinate of projected position. * @param structure * Structure to which data projects. * @param barycentricAreas * Barycentric areas of projection, if to surface with valid structure. * @param barycentricNodes * Barycentric nodes of projection, if to surface with valid structure * @param numberOfNodes * Number of nodes in surface, if to surface with valid structure. */ void BrainOpenGLFixedPipeline::setProjectionModeData(const float screenDepth, const float xyz[3], const StructureEnum::Enum structure, const float barycentricAreas[3], const int barycentricNodes[3], const int numberOfNodes) { CaretAssert(this->modeProjectionData); if (screenDepth < this->modeProjectionScreenDepth) { this->modeProjectionScreenDepth = screenDepth; this->modeProjectionData->setStructure(structure); this->modeProjectionData->setStereotaxicXYZ(xyz); SurfaceProjectionBarycentric* barycentric = this->modeProjectionData->getBarycentricProjection(); barycentric->setProjectionSurfaceNumberOfNodes(numberOfNodes); barycentric->setTriangleAreas(barycentricAreas); barycentric->setTriangleNodes(barycentricNodes); barycentric->setValid(true); CaretLogFiner("Projected to surface " + StructureEnum::toName(structure) + " with depth " + screenDepth); } } /** * Draw a surface as individual nodes. * @param surface * Surface that is drawn. * @param nodeColoringRGBA * RGBA coloring for the nodes. */ void BrainOpenGLFixedPipeline::drawSurfaceNodes(Surface* surface, const float* nodeColoringRGBA) { const DisplayPropertiesSurface* dps = m_brain->getDisplayPropertiesSurface(); const int numNodes = surface->getNumberOfNodes(); const float* coordinates = surface->getCoordinate(0); const float* normals = surface->getNormalVector(0); SelectionItemSurfaceNode* nodeID = m_brain->getSelectionManager()->getSurfaceNodeIdentification(); /* * Check for a 'selection' type mode */ bool isSelect = false; switch (this->mode) { case MODE_DRAWING: break; case MODE_IDENTIFICATION: if (nodeID->isEnabledForSelection()) { isSelect = true; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } else { return; } break; case MODE_PROJECTION: break; } uint8_t rgba[4]; float pointSize = dps->getNodeSize(); if (isSelect) { if (pointSize < 2.0) { pointSize = 2.0; } } setPointSize(pointSize); glBegin(GL_POINTS); for (int32_t i = 0; i < numNodes; i++) { const int32_t i3 = i * 3; if (isSelect) { this->colorIdentification->addItem(rgba, SelectionItemDataTypeEnum::SURFACE_NODE, i); glColor3ubv(rgba); glNormal3fv(&normals[i3]); glVertex3fv(&coordinates[i3]); } else { glColor4fv(&nodeColoringRGBA[i*4]); glNormal3fv(&normals[i3]); glVertex3fv(&coordinates[i3]); } } glEnd(); if (isSelect) { int nodeIndex = -1; float depth = -1.0; this->getIndexFromColorSelection(SelectionItemDataTypeEnum::SURFACE_NODE, this->mouseX, this->mouseY, nodeIndex, depth); if (nodeIndex >= 0) { if (nodeID->isOtherScreenDepthCloserToViewer(depth)) { nodeID->setBrain(surface->getBrainStructure()->getBrain()); nodeID->setSurface(surface); nodeID->setNodeNumber(nodeIndex); nodeID->setScreenDepth(depth); this->setSelectedItemScreenXYZ(nodeID, &coordinates[nodeIndex * 3]); CaretLogFine("Selected Vertex: " + nodeID->toString()); } else { CaretLogFine("Rejecting Selected Vertex: " + nodeID->toString()); } } } } /** * Draw a surface triangles with vertex arrays. * @param surface * Surface that is drawn. * @param nodeColoringRGBA * RGBA coloring for the nodes. */ void BrainOpenGLFixedPipeline::drawSurfaceTrianglesWithVertexArrays(const Surface* surface, const float* nodeColoringRGBA) { glEnableClientState(GL_VERTEX_ARRAY); if (nodeColoringRGBA != NULL) { glEnableClientState(GL_COLOR_ARRAY); } glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3, GL_FLOAT, 0, reinterpret_cast(surface->getCoordinate(0))); if (nodeColoringRGBA != NULL) { glColorPointer(4, GL_FLOAT, 0, reinterpret_cast(nodeColoringRGBA)); } else { glColor3fv(m_backgroundColorFloat); } glNormalPointer(GL_FLOAT, 0, reinterpret_cast(surface->getNormalVector(0))); const int numTriangles = surface->getNumberOfTriangles(); glDrawElements(GL_TRIANGLES, (3 * numTriangles), GL_UNSIGNED_INT, reinterpret_cast(surface->getTriangle(0))); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); } /** * Draw a surface's normal vectors. * @param surface * Surface on which normal vectors are drawn. */ void BrainOpenGLFixedPipeline::drawSurfaceNormalVectors(const Surface* surface) { disableLighting(); const StructureEnum::Enum structure = surface->getStructure(); const float length = 10.0; CaretPointer topoHelper = surface->getTopologyHelper(); setLineWidth(1.0); glColor3f(1.0, 0.0, 0.0); const int32_t numNodes = surface->getNumberOfNodes(); glBegin(GL_LINES); for (int32_t i = 0; i < numNodes; i++) { if (topoHelper->getNodeHasNeighbors(i)) { const float* xyz = surface->getCoordinate(i); if (m_clippingPlaneGroup->isSurfaceSelected()) { if ( ! isCoordinateInsideClippingPlanesForStructure(structure, xyz)) { continue; } } const float* normal = surface->getNormalVector(i); float vector[3] = { xyz[0] + length * normal[0], xyz[1] + length * normal[1], xyz[2] + length * normal[2] }; glVertex3fv(xyz); glVertex3fv(vector); } } glEnd(); enableLighting(); } /** * Draw attributes for the given surface. * @param surface * Surface for which attributes are drawn. */ void BrainOpenGLFixedPipeline::drawSurfaceNodeAttributes(Surface* surface) { BrainStructure* brainStructure = surface->getBrainStructure(); CaretAssert(brainStructure); Brain* brain = brainStructure->getBrain(); CaretAssert(brain); const StructureEnum::Enum structure = surface->getStructure(); const int numNodes = surface->getNumberOfNodes(); const float* coordinates = surface->getCoordinate(0); IdentificationManager* idManager = brain->getIdentificationManager(); SelectionItemSurfaceNodeIdentificationSymbol* symbolID = m_brain->getSelectionManager()->getSurfaceNodeIdentificationSymbol(); const std::vector identifiedNodes = idManager->getNodeIdentifiedItemsForSurface(structure, numNodes); std::vector identifiedNodeIndices; for (std::vector::const_iterator iter = identifiedNodes.begin(); iter != identifiedNodes.end(); iter++) { const IdentifiedItemNode& nodeID = *iter; identifiedNodeIndices.push_back(nodeID.getNodeIndex()); } EventNodeIdentificationColorsGetFromCharts colorsFromChartsEvent(structure, this->windowTabIndex, identifiedNodeIndices); /* * Check for a 'selection' type mode */ bool isSelect = false; switch (this->mode) { case MODE_DRAWING: EventManager::get()->sendEvent(colorsFromChartsEvent.getPointer()); break; case MODE_IDENTIFICATION: if (symbolID->isEnabledForSelection()) { isSelect = true; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } else { return; } break; case MODE_PROJECTION: return; break; } if (idManager->isShowSurfaceIdentificationSymbols()) { for (std::vector::const_iterator iter = identifiedNodes.begin(); iter != identifiedNodes.end(); iter++) { const IdentifiedItemNode& nodeID = *iter; const int32_t nodeIndex = nodeID.getNodeIndex(); const int32_t i3 = nodeIndex * 3; const float* xyz = &coordinates[i3]; if (m_clippingPlaneGroup->isSurfaceSelected()) { if ( ! isCoordinateInsideClippingPlanesForStructure(structure, xyz)) { continue; } } const float symbolDiameter = nodeID.getSymbolSize(); uint8_t symbolRGBA[4]; if (isSelect) { this->colorIdentification->addItem(symbolRGBA, SelectionItemDataTypeEnum::SURFACE_NODE_IDENTIFICATION_SYMBOL, nodeIndex); } else { if (structure == nodeID.getStructure()) { nodeID.getSymbolRGBA(symbolRGBA); colorsFromChartsEvent.applyChartColorToNode(nodeIndex, symbolRGBA); } else { nodeID.getContralateralSymbolRGB(symbolRGBA); } } symbolRGBA[3] = 255; /* * Need to draw each symbol independently since each symbol * contains a unique size (diameter) */ std::unique_ptr idPrimitive(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::SPHERES)); idPrimitive->setSphereDiameter(GraphicsPrimitive::SphereSizeType::MILLIMETERS, symbolDiameter); idPrimitive->addVertex(xyz, symbolRGBA); GraphicsEngineDataOpenGL::draw(idPrimitive.get()); } } if (isSelect) { int nodeIndex = -1; float depth = -1.0; this->getIndexFromColorSelection(SelectionItemDataTypeEnum::SURFACE_NODE_IDENTIFICATION_SYMBOL, this->mouseX, this->mouseY, nodeIndex, depth); if (nodeIndex >= 0) { if (symbolID->isOtherScreenDepthCloserToViewer(depth)) { symbolID->setBrain(surface->getBrainStructure()->getBrain()); symbolID->setSurface(surface); symbolID->setNodeNumber(nodeIndex); symbolID->setScreenDepth(depth); this->setSelectedItemScreenXYZ(symbolID, &coordinates[nodeIndex * 3]); CaretLogFine("Selected Vertex Identification Symbol: " + QString::number(nodeIndex)); } } } } /** * Draw a border on a surface. The color must be set prior * to calling this method. * * @param borderDrawInfo * Info about border being drawn. */ void BrainOpenGLFixedPipeline::drawBorder(const BorderDrawInfo& borderDrawInfo) { CaretAssert(borderDrawInfo.surface); CaretAssert(borderDrawInfo.topologyHelper); CaretAssert(borderDrawInfo.border); const StructureEnum::Enum surfaceStructure = borderDrawInfo.surface->getStructure(); const StructureEnum::Enum contralateralSurfaceStructure = StructureEnum::getContralateralStructure(surfaceStructure); const int32_t numBorderPoints = borderDrawInfo.border->getNumberOfPoints(); const bool isHighlightEndPoints = borderDrawInfo.isHighlightEndPoints; CaretAssert(m_brain); const DisplayPropertiesBorders* dpb = m_brain->getDisplayPropertiesBorders(); const DisplayGroupEnum::Enum displayGroup = dpb->getDisplayGroupForTab(this->windowTabIndex); const float pointDiameter = dpb->getPointSize(displayGroup, this->windowTabIndex); const float lineWidth = dpb->getLineWidth(displayGroup, this->windowTabIndex); BorderDrawingTypeEnum::Enum drawType = dpb->getDrawingType(displayGroup, this->windowTabIndex); /* * When a border is being drawn, always use spheres */ if (borderDrawInfo.border == this->borderBeingDrawn) { drawType = BorderDrawingTypeEnum::DRAW_AS_POINTS_SPHERES; } bool drawSphericalPoints = false; bool drawSquarePoints = false; bool drawLineSegments = false; bool drawPolylines = false; switch (drawType) { case BorderDrawingTypeEnum::DRAW_AS_LINES: drawLineSegments = true; break; case BorderDrawingTypeEnum::DRAW_AS_POLYLINES: drawPolylines = true; break; case BorderDrawingTypeEnum::DRAW_AS_POINTS_SPHERES: drawSphericalPoints = true; break; case BorderDrawingTypeEnum::DRAW_AS_POINTS_SQUARES: drawSquarePoints = true; break; case BorderDrawingTypeEnum::DRAW_AS_POINTS_AND_LINES: drawLineSegments = true; drawSphericalPoints = true; break; } const bool flatSurfaceFlag = (borderDrawInfo.surface->getSurfaceType() == SurfaceTypeEnum::FLAT); bool flatSurfaceDrawUnstretchedLinesFlag = false; float unstretchedLinesLength = -1.0; if (flatSurfaceFlag) { if ((borderDrawInfo.anatomicalSurface != NULL) && (borderDrawInfo.unstretchedLinesLength > 0.0)) { flatSurfaceDrawUnstretchedLinesFlag = true; unstretchedLinesLength = borderDrawInfo.unstretchedLinesLength; } } const float drawAtDistanceAboveSurface = 0.0; const std::vector& nodesBoundaryEdgeCount = borderDrawInfo.topologyHelper->getNumberOfBoundaryEdgesForAllNodes(); CaretAssert(static_cast(nodesBoundaryEdgeCount.size()) == borderDrawInfo.surface->getNumberOfNodes()); const uint8_t highlightFirstPointRGBA[4] = { 0, 255, 0, 1 }; const uint8_t highlightLastPointRGBA[4] = { 0, 192, 0, 1 }; const uint8_t solidColorRGBA[4] = { static_cast(borderDrawInfo.rgba[0] * 255.0f), static_cast(borderDrawInfo.rgba[1] * 255.0f), static_cast(borderDrawInfo.rgba[2] * 255.0f), static_cast(borderDrawInfo.rgba[3] * 255.0f) }; std::unique_ptr pointsPrimitive; std::unique_ptr pointsIdentificationPrimitive; std::unique_ptr firstPointPrimitive; std::unique_ptr lastPointPrimitive; if (drawSquarePoints) { if (borderDrawInfo.isSelect) { pointsIdentificationPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::OPENGL_POINTS)); } else { pointsPrimitive.reset(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_POINTS, solidColorRGBA)); firstPointPrimitive.reset(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_POINTS, highlightFirstPointRGBA)); lastPointPrimitive.reset(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_POINTS, highlightLastPointRGBA)); } } if (drawSphericalPoints) { if (borderDrawInfo.isSelect) { pointsIdentificationPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::SPHERES)); } else { pointsPrimitive.reset(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::SPHERES, solidColorRGBA)); firstPointPrimitive.reset(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::SPHERES, highlightFirstPointRGBA)); lastPointPrimitive.reset(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::SPHERES, highlightLastPointRGBA)); } } /* * Due to the possibility of 'unstretched lines' not being drawn * must OPENGL_LINES must be used since there is no way to skip * a line segment in a line strip */ GraphicsPrimitive::PrimitiveType lineType = GraphicsPrimitive::PrimitiveType::OPENGL_LINES; bool allowPrimitiveRestartFlag = false; if (drawPolylines) { lineType = GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN; allowPrimitiveRestartFlag = true; } std::unique_ptr linesPrimitive; std::unique_ptr linesIdentificationPrimitive; if (drawLineSegments || drawPolylines) { if (borderDrawInfo.isSelect) { linesIdentificationPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(lineType)); } else { linesPrimitive.reset(GraphicsPrimitive::newPrimitiveV3f(lineType, solidColorRGBA)); } } const bool featureClippingFlag = isFeatureClippingEnabled(); bool lastPointForLineValidFlag = false; float lastPointForLineXYZ[3] = { 0.0f, 0.0f, 0.0f }; /* * Find points valid for this surface */ for (int32_t i = 0; i < numBorderPoints; i++) { /* * If previous point was not valid, need to "restart" the border lines */ if (i > 0) { if ( ! lastPointForLineValidFlag) { if (allowPrimitiveRestartFlag) { if (linesPrimitive) { linesPrimitive->addPrimitiveRestart(); } if (linesIdentificationPrimitive) { linesIdentificationPrimitive->addPrimitiveRestart(); } } } } const SurfaceProjectedItem* p = borderDrawInfo.border->getPoint(i); /* * Test to match structure */ const StructureEnum::Enum pointStructure = p->getStructure(); bool structureMatches = true; if (surfaceStructure != pointStructure) { structureMatches = false; if (borderDrawInfo.isContralateralEnabled) { if (contralateralSurfaceStructure == pointStructure) { structureMatches = true; } } } if ( ! structureMatches) { lastPointForLineValidFlag = false; continue; } /* * Test if point projects to surface successfully */ float xyz[3]; bool projectionValidFlag = p->getProjectedPositionAboveSurface(*borderDrawInfo.surface, borderDrawInfo.topologyHelper, xyz, drawAtDistanceAboveSurface); if ( ! projectionValidFlag) { lastPointForLineValidFlag = false; continue; } /* * Test if point is inside clipping planes */ if (featureClippingFlag) { if ( ! isCoordinateInsideClippingPlanesForStructure(surfaceStructure, xyz)) { lastPointForLineValidFlag = false; continue; } } /* * If this is a flat surface and unstretched lines is enabled * Do not use point if it was projected to all nodes that are on edges * Typically these edges are where cuts were made for flattening */ if (flatSurfaceDrawUnstretchedLinesFlag){ if (p->getBarycentricProjection()->isValid()) { const int32_t* baryNodes = p->getBarycentricProjection()->getTriangleNodes(); if (baryNodes != NULL) { int32_t edgeNodeCount = 0; if (nodesBoundaryEdgeCount[baryNodes[0]] > 0) edgeNodeCount++; if (nodesBoundaryEdgeCount[baryNodes[1]] > 0) edgeNodeCount++; if (nodesBoundaryEdgeCount[baryNodes[2]] > 0) edgeNodeCount++; if (edgeNodeCount >= 3) { lastPointForLineValidFlag = false; continue; } } } } /* * For Lines ONLY: * If flat surface and unstretched lines is enabled * */ if (flatSurfaceDrawUnstretchedLinesFlag) { if (i > 0) { if (lastPointForLineValidFlag) { float anatXYZ[3]; const bool anatXyzValid = p->getProjectedPositionAboveSurface(*borderDrawInfo.anatomicalSurface, borderDrawInfo.topologyHelper, anatXYZ, drawAtDistanceAboveSurface); const SurfaceProjectedItem* lastP = borderDrawInfo.border->getPoint(i - 1); float lastAnatXYZ[3]; const bool lastAnatXyzValid = lastP->getProjectedPositionAboveSurface(*borderDrawInfo.anatomicalSurface, borderDrawInfo.topologyHelper, lastAnatXYZ, drawAtDistanceAboveSurface); if (anatXyzValid && lastAnatXyzValid) { if (unstretchedBorderLineTest(xyz, lastPointForLineXYZ, anatXYZ, lastAnatXYZ, unstretchedLinesLength)) { if (allowPrimitiveRestartFlag) { if (linesPrimitive) { linesPrimitive->addPrimitiveRestart(); } if (linesIdentificationPrimitive) { linesIdentificationPrimitive->addPrimitiveRestart(); } } } } } } } if (borderDrawInfo.isSelect) { uint8_t idRGBA[4]; this->colorIdentification->addItem(idRGBA, SelectionItemDataTypeEnum::BORDER_SURFACE, borderDrawInfo.borderFileIndex, borderDrawInfo.borderIndex, i); if (pointsIdentificationPrimitive) { pointsIdentificationPrimitive->addVertex(xyz, idRGBA); } if (linesIdentificationPrimitive) { if (drawLineSegments) { if (lastPointForLineValidFlag) { linesIdentificationPrimitive->addVertex(lastPointForLineXYZ, idRGBA); linesIdentificationPrimitive->addVertex(xyz, idRGBA); } } else { linesIdentificationPrimitive->addVertex(xyz, idRGBA); } } } else { if (pointsPrimitive) { if (isHighlightEndPoints) { if (i == 0) { firstPointPrimitive->addVertex(xyz); } else if (i == (numBorderPoints - 1)) { lastPointPrimitive->addVertex(xyz); } else { pointsPrimitive->addVertex(xyz); } } else { pointsPrimitive->addVertex(xyz); } } if (linesPrimitive) { if (drawLineSegments) { if (lastPointForLineValidFlag) { linesPrimitive->addVertex(lastPointForLineXYZ); linesPrimitive->addVertex(xyz); } } else { linesPrimitive->addVertex(xyz); } } } /* * May need point for next time */ lastPointForLineXYZ[0] = xyz[0]; lastPointForLineXYZ[1] = xyz[1]; lastPointForLineXYZ[2] = xyz[2]; lastPointForLineValidFlag = true; } glPushAttrib(GL_ENABLE_BIT); glDisable(GL_LIGHTING); if (pointsIdentificationPrimitive) { pointsIdentificationPrimitive->setPointDiameter(GraphicsPrimitive::PointSizeType::MILLIMETERS, pointDiameter); pointsIdentificationPrimitive->setSphereDiameter(GraphicsPrimitive::SphereSizeType::MILLIMETERS, pointDiameter); GraphicsEngineDataOpenGL::draw(pointsIdentificationPrimitive.get()); } else if (pointsPrimitive) { pointsPrimitive->setPointDiameter(GraphicsPrimitive::PointSizeType::MILLIMETERS, pointDiameter); pointsPrimitive->setSphereDiameter(GraphicsPrimitive::SphereSizeType::MILLIMETERS, pointDiameter); if (pointsPrimitive->getPrimitiveType() == GraphicsPrimitive::PrimitiveType::SPHERES) { glEnable(GL_LIGHTING); } GraphicsEngineDataOpenGL::draw(pointsPrimitive.get()); if (firstPointPrimitive->isValid()) { GraphicsEngineDataOpenGL::draw(firstPointPrimitive.get()); } if (lastPointPrimitive->isValid()) { GraphicsEngineDataOpenGL::draw(lastPointPrimitive.get()); } } if (linesIdentificationPrimitive) { glDisable(GL_LIGHTING); linesIdentificationPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, lineWidth); GraphicsEngineDataOpenGL::draw(linesIdentificationPrimitive.get()); } else if (linesPrimitive) { glDisable(GL_LIGHTING); linesPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, lineWidth); GraphicsEngineDataOpenGL::draw(linesPrimitive.get()); } glPopAttrib(); } /** * Determine if the ratio if border length over anatomical border length * is greater than the unstretched lines factor. * * @param p1 * Position of border point in surface. * @param p1 * Position of next border point in surface. * @param anat1 * Position of border point in anatomical surface. * @param anat2 * Position of next border point in anatomical surface. * @param unstretchedLinesFactor * The unstretched lines factor. * @return * True if the border is too long and should NOT be drawn, else false. */ bool BrainOpenGLFixedPipeline::unstretchedBorderLineTest(const float p1[3], const float p2[3], const float anat1[3], const float anat2[3], const float unstretchedLinesFactor) const { const float dist = MathFunctions::distance3D(p1, p2); const float anatDist = MathFunctions::distance3D(anat1, anat2); if (anatDist > 0.0) { const float ratio = dist / anatDist; if (ratio > unstretchedLinesFactor) { return true; } } return false; } /** * Draw foci on a surface. * @param surface * Surface on which foci are drawn. */ void BrainOpenGLFixedPipeline::drawSurfaceFoci(Surface* surface) { SelectionItemFocusSurface* idFocus = m_brain->getSelectionManager()->getSurfaceFocusIdentification(); /* * Check for a 'selection' type mode */ bool isSelect = false; switch (this->mode) { case MODE_DRAWING: break; case MODE_IDENTIFICATION: if (idFocus->isEnabledForSelection()) { isSelect = true; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } else { return; } break; case MODE_PROJECTION: return; break; } Brain* brain = surface->getBrainStructure()->getBrain(); const DisplayPropertiesFoci* fociDisplayProperties = brain->getDisplayPropertiesFoci(); const DisplayGroupEnum::Enum displayGroup = fociDisplayProperties->getDisplayGroupForTab(this->windowTabIndex); if (fociDisplayProperties->isDisplayed(displayGroup, this->windowTabIndex) == false) { return; } const float focusDiameter = fociDisplayProperties->getFociSize(displayGroup, this->windowTabIndex); const FeatureColoringTypeEnum::Enum fociColoringType = fociDisplayProperties->getColoringType(displayGroup, this->windowTabIndex); const StructureEnum::Enum surfaceStructure = surface->getStructure(); const StructureEnum::Enum surfaceContralateralStructure = StructureEnum::getContralateralStructure(surfaceStructure); const bool doClipping = isFeatureClippingEnabled(); bool lightingOnFlag = false; std::unique_ptr fociPrimitive; switch (fociDisplayProperties->getDrawingType(displayGroup, this->windowTabIndex)) { case FociDrawingTypeEnum::DRAW_AS_SPHERES: fociPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::SPHERES)); fociPrimitive->setSphereDiameter(GraphicsPrimitive::SphereSizeType::MILLIMETERS, focusDiameter); lightingOnFlag = true; break; case FociDrawingTypeEnum::DRAW_AS_SQUARES: fociPrimitive.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::OPENGL_POINTS)); fociPrimitive->setPointDiameter(GraphicsPrimitive::PointSizeType::MILLIMETERS, focusDiameter); lightingOnFlag = false; break; } if (isSelect) { lightingOnFlag = false; } const CaretColorEnum::Enum caretColor = fociDisplayProperties->getStandardColorType(displayGroup, this->windowTabIndex); float caretColorRGBA[4]; CaretColorEnum::toRGBAFloat(caretColor, caretColorRGBA); const bool isPasteOntoSurface = fociDisplayProperties->isPasteOntoSurface(displayGroup, this->windowTabIndex); const bool isContralateralEnabled = fociDisplayProperties->isContralateralDisplayed(displayGroup, this->windowTabIndex); const int32_t numFociFiles = brain->getNumberOfFociFiles(); for (int32_t i = 0; i < numFociFiles; i++) { FociFile* fociFile = brain->getFociFile(i); const GroupAndNameHierarchyModel* classAndNameSelection = fociFile->getGroupAndNameHierarchyModel(); if (classAndNameSelection->isSelected(displayGroup, this->windowTabIndex) == false) { continue; } const GiftiLabelTable* classColorTable = fociFile->getClassColorTable(); const GiftiLabelTable* nameColorTable = fociFile->getNameColorTable(); const int32_t numFoci = fociFile->getNumberOfFoci(); for (int32_t j = 0; j < numFoci; j++) { Focus* focus = fociFile->getFocus(j); float rgbaFloat[4] = { caretColorRGBA[0], caretColorRGBA[1], caretColorRGBA[2], caretColorRGBA[3] }; const GroupAndNameHierarchyItem* nameItem = focus->getGroupNameSelectionItem(); if (nameItem != NULL) { if (nameItem->isSelected(displayGroup, this->windowTabIndex) == false) { continue; } } switch (fociColoringType) { case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_CLASS: if ( ! focus->isClassRgbaValid()) { const GiftiLabel* colorLabel = classColorTable->getLabelBestMatching(focus->getClassName()); if (colorLabel != NULL) { colorLabel->getColor(rgbaFloat); focus->setClassRgba(rgbaFloat); } } focus->getClassRgba(rgbaFloat); break; case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_STANDARD_COLOR: rgbaFloat[0] = caretColorRGBA[0]; rgbaFloat[1] = caretColorRGBA[1]; rgbaFloat[2] = caretColorRGBA[2]; rgbaFloat[3] = caretColorRGBA[3]; break; case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_NAME: if (focus->isNameRgbaValid() == false) { const GiftiLabel* colorLabel = nameColorTable->getLabelBestMatching(focus->getName()); if (colorLabel != NULL) { colorLabel->getColor(rgbaFloat); focus->setNameRgba(rgbaFloat); } } focus->getNameRgba(rgbaFloat); break; } /* * Always have valid color for RGBA */ rgbaFloat[3] = 1.0f; const int32_t numProjections = focus->getNumberOfProjections(); for (int32_t k = 0; k < numProjections; k++) { const SurfaceProjectedItem* spi = focus->getProjection(k); float xyz[3]; if (spi->getProjectedPosition(*surface, xyz, isPasteOntoSurface)) { const StructureEnum::Enum focusStructure = spi->getStructure(); bool drawIt = false; if (focusStructure == surfaceStructure) { drawIt = true; } else if (focusStructure == StructureEnum::INVALID) { drawIt = true; } else if (isContralateralEnabled) { if (focusStructure == surfaceContralateralStructure) { drawIt = true; } } if (doClipping) { if ( ! isCoordinateInsideClippingPlanesForStructure(surfaceStructure, xyz)) { drawIt = false; } } if (drawIt) { if (isSelect) { uint8_t idRGBA[4]; this->colorIdentification->addItem(idRGBA, SelectionItemDataTypeEnum::FOCUS_SURFACE, i, /* file index */ j, /* focus index */ k);/* projection index */ idRGBA[3] = 255; fociPrimitive->addVertex(xyz, idRGBA); } else { const uint8_t rgbaByte[4] = { static_cast(rgbaFloat[0] * 255), static_cast(rgbaFloat[1] * 255), static_cast(rgbaFloat[2] * 255), static_cast(rgbaFloat[3] * 255) }; fociPrimitive->addVertex(xyz, rgbaByte); } } } } } } glPushAttrib(GL_ENABLE_BIT); if (lightingOnFlag) { enableLighting(); } else { disableLighting(); } GraphicsEngineDataOpenGL::draw(fociPrimitive.get()); if (isSelect) { int32_t fociFileIndex = -1; int32_t focusIndex = -1; int32_t focusProjectionIndex = -1; float depth = -1.0; this->getIndexFromColorSelection(SelectionItemDataTypeEnum::FOCUS_SURFACE, this->mouseX, this->mouseY, fociFileIndex, focusIndex, focusProjectionIndex, depth); if (fociFileIndex >= 0) { if (idFocus->isOtherScreenDepthCloserToViewer(depth)) { Focus* focus = brain->getFociFile(fociFileIndex)->getFocus(focusIndex); idFocus->setBrain(brain); idFocus->setFocus(focus); idFocus->setFociFile(brain->getFociFile(fociFileIndex)); idFocus->setFocusIndex(focusIndex); idFocus->setFocusProjectionIndex(focusProjectionIndex); idFocus->setSurface(surface); idFocus->setScreenDepth(depth); float xyz[3]; const SurfaceProjectedItem* spi = focus->getProjection(focusProjectionIndex); spi->getProjectedPosition(*surface, xyz, false); this->setSelectedItemScreenXYZ(idFocus, xyz); CaretLogFine("Selected Focus Identification Symbol: " + QString::number(focusIndex)); } } } glPopAttrib(); } /** * Draw borders on a surface. * @param surface * Surface on which borders are drawn. */ void BrainOpenGLFixedPipeline::drawSurfaceBorders(Surface* surface) { CaretAssert(surface); SelectionItemBorderSurface* idBorder = m_brain->getSelectionManager()->getSurfaceBorderIdentification(); /* * Check for a 'selection' type mode */ bool isSelect = false; switch (this->mode) { case MODE_DRAWING: break; case MODE_IDENTIFICATION: if (idBorder->isEnabledForSelection()) { isSelect = true; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } else { return; } break; case MODE_PROJECTION: return; break; } Brain* brain = surface->getBrainStructure()->getBrain(); const DisplayPropertiesBorders* borderDisplayProperties = brain->getDisplayPropertiesBorders(); const DisplayGroupEnum::Enum displayGroup = borderDisplayProperties->getDisplayGroupForTab(this->windowTabIndex); if (borderDisplayProperties->isDisplayed(displayGroup, this->windowTabIndex) == false) { return; } float unstretchedLinesLength = -1.0; if (borderDisplayProperties->isUnstretchedLinesEnabled(displayGroup, this->windowTabIndex)) { unstretchedLinesLength = borderDisplayProperties->getUnstretchedLinesLength(displayGroup, this->windowTabIndex); } const FeatureColoringTypeEnum::Enum borderColoringType = borderDisplayProperties->getColoringType(displayGroup, this->windowTabIndex); const CaretColorEnum::Enum caretColor = borderDisplayProperties->getStandardColorType(displayGroup, this->windowTabIndex); float caretColorRGBA[4]; CaretColorEnum::toRGBAFloat(caretColor, caretColorRGBA); const bool isContralateralEnabled = borderDisplayProperties->isContralateralDisplayed(displayGroup, this->windowTabIndex); BorderDrawInfo borderDrawInfo; borderDrawInfo.surface = surface; borderDrawInfo.topologyHelper = surface->getTopologyHelper().getPointer(); const int32_t numBorderFiles = brain->getNumberOfBorderFiles(); for (int32_t i = 0; i < numBorderFiles; i++) { BorderFile* borderFile = brain->getBorderFile(i); const GroupAndNameHierarchyModel* classAndNameSelection = borderFile->getGroupAndNameHierarchyModel(); if (classAndNameSelection->isSelected(displayGroup, this->windowTabIndex) == false) { continue; } const GiftiLabelTable* classColorTable = borderFile->getClassColorTable(); const GiftiLabelTable* nameColorTable = borderFile->getNameColorTable(); const int32_t numBorders = borderFile->getNumberOfBorders(); for (int32_t j = 0; j < numBorders; j++) { Border* border = borderFile->getBorder(j); if (borderFile->isBorderDisplayed(displayGroup, this->windowTabIndex, border) == false) { continue; } float rgba[4] = { 0.0, 0.0, 0.0, 1.0 }; switch (borderColoringType) { case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_CLASS: if (border->isClassRgbaValid() == false) { const GiftiLabel* colorLabel = classColorTable->getLabelBestMatching(border->getClassName()); if (colorLabel != NULL) { colorLabel->getColor(rgba); border->setClassRgba(rgba); } else { border->setClassRgba(rgba); } } border->getClassRgba(rgba); break; case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_STANDARD_COLOR: rgba[0] = caretColorRGBA[0]; rgba[1] = caretColorRGBA[1]; rgba[2] = caretColorRGBA[2]; rgba[3] = caretColorRGBA[3]; break; case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_NAME: if (border->isNameRgbaValid() == false) { const GiftiLabel* colorLabel = nameColorTable->getLabelBestMatching(border->getName()); if (colorLabel != NULL) { colorLabel->getColor(rgba); border->setNameRgba(rgba); } else { border->setNameRgba(rgba); } } border->getNameRgba(rgba); break; } glColor3fv(rgba); borderDrawInfo.border = border; borderDrawInfo.rgba[0] = rgba[0]; borderDrawInfo.rgba[1] = rgba[1]; borderDrawInfo.rgba[2] = rgba[2]; borderDrawInfo.rgba[3] = rgba[3]; borderDrawInfo.borderFileIndex = i; borderDrawInfo.borderIndex = j; borderDrawInfo.isSelect = isSelect; borderDrawInfo.isContralateralEnabled = isContralateralEnabled; borderDrawInfo.isHighlightEndPoints = m_drawHighlightedEndPoints; borderDrawInfo.anatomicalSurface = NULL; borderDrawInfo.unstretchedLinesLength = unstretchedLinesLength; BrainStructure* bs = brain->getBrainStructure(border->getStructure(), false); if (bs != NULL) { borderDrawInfo.anatomicalSurface = bs->getPrimaryAnatomicalSurface(); } this->drawBorder(borderDrawInfo); } } if (isSelect) { int32_t borderFileIndex = -1; int32_t borderIndex = -1; int32_t borderPointIndex; float depth = -1.0; this->getIndexFromColorSelection(SelectionItemDataTypeEnum::BORDER_SURFACE, this->mouseX, this->mouseY, borderFileIndex, borderIndex, borderPointIndex, depth); if (borderFileIndex >= 0) { if (idBorder->isOtherScreenDepthCloserToViewer(depth)) { Border* border = brain->getBorderFile(borderFileIndex)->getBorder(borderIndex); idBorder->setBrain(brain); idBorder->setBorder(border); idBorder->setBorderFile(brain->getBorderFile(borderFileIndex)); idBorder->setBorderIndex(borderIndex); idBorder->setBorderPointIndex(borderPointIndex); idBorder->setSurface(surface); idBorder->setScreenDepth(depth); float xyz[3]; border->getPoint(borderPointIndex)->getProjectedPosition(*surface, xyz, false); this->setSelectedItemScreenXYZ(idBorder, xyz); CaretLogFine("Selected Border Identification Symbol: " + QString::number(borderIndex)); } } } } /** * Draw the border that is begin drawn. * @param surface * Surface on which border is being drawn. */ void BrainOpenGLFixedPipeline::drawSurfaceBorderBeingDrawn(const Surface* surface) { glColor3f(1.0, 0.0, 0.0); if (this->borderBeingDrawn != NULL) { BorderDrawInfo borderDrawInfo; borderDrawInfo.surface = const_cast(surface); borderDrawInfo.topologyHelper = surface->getTopologyHelper().getPointer(); borderDrawInfo.border = this->borderBeingDrawn; borderDrawInfo.rgba[0] = 1.0; borderDrawInfo.rgba[1] = 0.0; borderDrawInfo.rgba[2] = 0.0; borderDrawInfo.rgba[3] = 1.0; borderDrawInfo.borderFileIndex = -1; borderDrawInfo.borderIndex = -1; borderDrawInfo.isSelect = false; borderDrawInfo.isContralateralEnabled = false; borderDrawInfo.isHighlightEndPoints = false; borderDrawInfo.anatomicalSurface = NULL; borderDrawInfo.unstretchedLinesLength = -1.0; this->drawBorder(borderDrawInfo); } } /** * Setup volume drawing information for an overlay set. * * @param browserTabContent * Content in the browser tab. * @param paletteFile * File from which palette is obtained. * @param volumeDrawInfoOut * Output containing information for volume drawing. */ void BrainOpenGLFixedPipeline::setupVolumeDrawInfo(BrowserTabContent* browserTabContent, Brain* brain, std::vector& volumeDrawInfoOut) { volumeDrawInfoOut.clear(); OverlaySet* overlaySet = browserTabContent->getOverlaySet(); const int32_t numberOfOverlays = overlaySet->getNumberOfDisplayedOverlays(); for (int32_t iOver = (numberOfOverlays - 1); iOver >= 0; iOver--) { Overlay* overlay = overlaySet->getOverlay(iOver); if (overlay->isEnabled()) { CaretMappableDataFile* mapFile; int32_t mapIndex; overlay->getSelectionData(mapFile, mapIndex); if (mapFile != NULL) { if (mapFile->isVolumeMappable()) { VolumeMappableInterface* vf = dynamic_cast(mapFile); if (vf != NULL) { float opacity = overlay->getOpacity(); WholeBrainVoxelDrawingMode::Enum wholeBrainVoxelDrawingMode = overlay->getWholeBrainVoxelDrawingMode(); if (mapFile->isMappedWithPalette()) { FastStatistics* statistics = NULL; switch (mapFile->getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: statistics = const_cast(mapFile->getFileFastStatistics()); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: statistics = const_cast(mapFile->getMapFastStatistics(mapIndex)); break; } PaletteColorMapping* paletteColorMapping = mapFile->getMapPaletteColorMapping(mapIndex); const Palette* palette = paletteColorMapping->getPalette(); if (palette != NULL) { /* * Statistics may be NULL for a dense connectome file * that does not have any data loaded by user * clicking on surface/volume. */ if (statistics != NULL) { bool useIt = true; if (volumeDrawInfoOut.empty() == false) { /* * If previous volume is the same as this * volume, there is no need to draw it twice. */ const VolumeDrawInfo& vdi = volumeDrawInfoOut[volumeDrawInfoOut.size() - 1]; if ((vdi.volumeFile == vf) && (opacity >= 1.0) && (mapIndex == vdi.mapIndex) && (*paletteColorMapping == *vdi.paletteColorMapping)) { useIt = false; } } if (useIt) { VolumeDrawInfo vdi(mapFile, vf, brain, paletteColorMapping, statistics, wholeBrainVoxelDrawingMode, mapIndex, opacity); volumeDrawInfoOut.push_back(vdi); } } } else { CaretLogWarning("No valid palette for drawing volume file: " + mapFile->getFileNameNoPath()); } } else { VolumeDrawInfo vdi(mapFile, vf, brain, NULL, NULL, wholeBrainVoxelDrawingMode, mapIndex, opacity); volumeDrawInfoOut.push_back(vdi); } } } } } } } /** * Draw the volume slices. * @param browserTabContent * Content of the window. * @param volumeModel * Model for slices. * @param viewport * Region of drawing. */ void BrainOpenGLFixedPipeline::drawVolumeModel(BrowserTabContent* browserTabContent, ModelVolume* volumeModel, const int32_t viewport[4]) { /* * Determine volumes that are to be drawn */ const int32_t tabNumber = browserTabContent->getTabNumber(); volumeModel->updateModel(tabNumber); Brain* brain = volumeModel->getBrain(); std::vector volumeDrawInfo; this->setupVolumeDrawInfo(browserTabContent, brain, volumeDrawInfo); VolumeSliceDrawingTypeEnum::Enum sliceDrawingType = browserTabContent->getSliceDrawingType(); VolumeSliceProjectionTypeEnum::Enum sliceProjectionType = browserTabContent->getSliceProjectionType(); VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum obliqueMaskType = browserTabContent->getVolumeSliceInterpolationEdgeEffectsMaskingType(); /* * There is/was a flaw in volume drawing in that it does not "center" * correctly when the voxel corresponding to the coordinate (0, 0, 0) * is not within the volume. It seems to be fixed for orthogonal * drawing but oblique drawing probably needs a new algorithm to * fix the problem. */ bool useNewDrawingFlag = false; switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: useNewDrawingFlag = true; break; } /* * Allow blending of volume slices and volume surface outline */ glPushAttrib(GL_COLOR_BUFFER_BIT); applyVolumePropertiesOpacity(); if (useNewDrawingFlag) { if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_TEXTURE_VOLUME)) { BrainOpenGLVolumeTextureSliceDrawing textureSliceDrawing; textureSliceDrawing.draw(this, browserTabContent, volumeDrawInfo, sliceDrawingType, sliceProjectionType, obliqueMaskType, viewport); } else { BrainOpenGLVolumeSliceDrawing volumeSliceDrawing; volumeSliceDrawing.draw(this, browserTabContent, volumeDrawInfo, sliceDrawingType, sliceProjectionType, viewport); } } else { if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_TEXTURE_VOLUME)) { BrainOpenGLVolumeTextureSliceDrawing textureSliceDrawing; textureSliceDrawing.draw(this, browserTabContent, volumeDrawInfo, sliceDrawingType, sliceProjectionType, obliqueMaskType, viewport); } else { BrainOpenGLVolumeObliqueSliceDrawing obliqueVolumeSliceDrawing; obliqueVolumeSliceDrawing.draw(this, browserTabContent, volumeDrawInfo, sliceDrawingType, sliceProjectionType, obliqueMaskType, viewport); } } glPopAttrib(); } /** * Draw volumes a voxel cubes for whole brain view. * * @param volumeDrawInfoIn * Describes volumes that are drawn. */ void BrainOpenGLFixedPipeline::drawVolumeVoxelsAsCubesWholeBrain(std::vector& volumeDrawInfoIn) { /* * Filter volumes for drawing and only draw those volumes that * are to be drawn as 3D Voxel Cubes. */ std::vector volumeDrawInfo; for (std::vector::iterator iter = volumeDrawInfoIn.begin(); iter != volumeDrawInfoIn.end(); iter++) { bool useIt = false; VolumeDrawInfo& vdi = *iter; switch (vdi.wholeBrainVoxelDrawingMode) { case WholeBrainVoxelDrawingMode::DRAW_VOXELS_AS_THREE_D_CUBES: case WholeBrainVoxelDrawingMode::DRAW_VOXELS_AS_ROUNDED_THREE_D_CUBES: useIt = true; break; case WholeBrainVoxelDrawingMode::DRAW_VOXELS_ON_TWO_D_SLICES: break; } if (useIt) { volumeDrawInfo.push_back(vdi); } } const int32_t numberOfVolumesToDraw = static_cast(volumeDrawInfo.size()); if (numberOfVolumesToDraw <= 0) { return; } SelectionItemVoxel* voxelID = m_brain->getSelectionManager()->getVoxelIdentification(); /* * Check for a 'selection' type mode */ bool isSelect = false; switch (this->mode) { case MODE_DRAWING: break; case MODE_IDENTIFICATION: if (voxelID->isEnabledForSelection()) { isSelect = true; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } else { return; } break; case MODE_PROJECTION: return; break; } /* * When selecting turn on lighting and shading since * colors are used for identification. */ if (isSelect) { this->disableLighting(); glShadeModel(GL_FLAT); } else { this->enableLighting(); glEnable(GL_CULL_FACE); glShadeModel(GL_SMOOTH); } glEnable(GL_CULL_FACE); const bool doClipping = isFeatureClippingEnabled(); const DisplayPropertiesLabels* dsl = m_brain->getDisplayPropertiesLabels(); const DisplayGroupEnum::Enum displayGroup = dsl->getDisplayGroupForTab(this->windowTabIndex); /* * For identification, five items per voxel * 1) volume index * 2) map index * 3) index I * 4) index J * 5) index K */ const int32_t idPerVoxelCount = 5; std::vector identificationIndices; if (isSelect) { identificationIndices.reserve(10000 * idPerVoxelCount); } for (int32_t iVol = 0; iVol < numberOfVolumesToDraw; iVol++) { VolumeDrawInfo& volInfo = volumeDrawInfo[iVol]; if (volInfo.opacity < 1.0) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { glDisable(GL_BLEND); } const VolumeMappableInterface* volumeFile = volInfo.volumeFile; int64_t dimI, dimJ, dimK, numMaps, numComponents; volumeFile->getDimensions(dimI, dimJ, dimK, numMaps, numComponents); float originX, originY, originZ; float x1, y1, z1; volumeFile->indexToSpace(0, 0, 0, originX, originY, originZ); volumeFile->indexToSpace(1, 1, 1, x1, y1, z1); const float dx = x1 - originX; const float dy = y1 - originY; const float dz = z1 - originZ; /* * Cube size for voxel drawing. Some volumes may have a right to left * orientation in which case dx may be negative. * * Scale the cube slightly larger to avoid cracks, particularly if * a single slice is drawn. */ const float cubeScale = 1.10; const float cubeSizeDX = std::fabs(dx) * cubeScale; const float cubeSizeDY = std::fabs(dy) * cubeScale; const float cubeSizeDZ = std::fabs(dz) * cubeScale; std::vector labelMapData; const CiftiBrainordinateLabelFile* ciftiLabelFile = dynamic_cast(volumeFile); if (ciftiLabelFile != NULL) { ciftiLabelFile->getMapData(volInfo.mapIndex, labelMapData); } if ((dimI == 1) || (dimJ == 1) || (dimK == 1)) { glDisable(GL_LIGHTING); } uint8_t rgba[4]; for (int64_t iVoxel = 0; iVoxel < dimI; iVoxel++) { for (int64_t jVoxel = 0; jVoxel < dimJ; jVoxel++) { for (int64_t kVoxel = 0; kVoxel < dimK; kVoxel++) { if (ciftiLabelFile != NULL) { ciftiLabelFile->getVoxelColorInMapForLabelData(labelMapData, iVoxel, jVoxel, kVoxel, volInfo.mapIndex, displayGroup, this->windowTabIndex, rgba); } else { volumeFile->getVoxelColorInMap(iVoxel, jVoxel, kVoxel, volInfo.mapIndex, displayGroup, this->windowTabIndex, rgba); } if (rgba[3] > 0) { if (volInfo.opacity < 1.0) { rgba[3] *= volInfo.opacity; } if (rgba[3] > 0) { if (isSelect) { const int32_t idIndex = identificationIndices.size() / idPerVoxelCount; this->colorIdentification->addItem(rgba, SelectionItemDataTypeEnum::VOXEL, idIndex); identificationIndices.push_back(iVol); identificationIndices.push_back(volInfo.mapIndex); identificationIndices.push_back(iVoxel); identificationIndices.push_back(jVoxel); identificationIndices.push_back(kVoxel); } float x = 0, y = 0.0, z = 0.0; volumeFile->indexToSpace(iVoxel, jVoxel, kVoxel, x, y, z); bool drawIt = true; if (doClipping) { const float xyz[3] = { x, y, z }; if ( ! isCoordinateInsideClippingPlanesForStructure(StructureEnum::ALL, xyz)) { drawIt = false; } } if (drawIt) { glPushMatrix(); glTranslatef(x, y, z); switch (volInfo.wholeBrainVoxelDrawingMode) { case WholeBrainVoxelDrawingMode::DRAW_VOXELS_AS_THREE_D_CUBES: drawCuboid(rgba, cubeSizeDX, cubeSizeDY, cubeSizeDZ); break; case WholeBrainVoxelDrawingMode::DRAW_VOXELS_AS_ROUNDED_THREE_D_CUBES: drawRoundedCuboid(rgba, cubeSizeDX, cubeSizeDY, cubeSizeDZ); break; case WholeBrainVoxelDrawingMode::DRAW_VOXELS_ON_TWO_D_SLICES: break; } glPopMatrix(); } } } } } } } if (isSelect) { int32_t identifiedItemIndex; float depth = -1.0; this->getIndexFromColorSelection(SelectionItemDataTypeEnum::VOXEL, this->mouseX, this->mouseY, identifiedItemIndex, depth); if (identifiedItemIndex >= 0) { const int32_t idIndex = identifiedItemIndex * idPerVoxelCount; const int32_t volDrawInfoIndex = identificationIndices[idIndex]; CaretAssertVectorIndex(volumeDrawInfo, volDrawInfoIndex); VolumeMappableInterface* vf = volumeDrawInfo[volDrawInfoIndex].volumeFile; const int64_t voxelIndices[3] = { identificationIndices[idIndex + 2], identificationIndices[idIndex + 3], identificationIndices[idIndex + 4] }; if (voxelID->isOtherScreenDepthCloserToViewer(depth)) { voxelID->setVoxelIdentification(m_brain, vf, voxelIndices, depth); float voxelCoordinates[3]; vf->indexToSpace(voxelIndices[0], voxelIndices[1], voxelIndices[2], voxelCoordinates[0], voxelCoordinates[1], voxelCoordinates[2]); this->setSelectedItemScreenXYZ(voxelID, voxelCoordinates); CaretLogFine("Selected Voxel (3D): " + AString::fromNumbers(voxelIndices, 3, ",")); } } } this->disableLighting(); glShadeModel(GL_SMOOTH); glDisable(GL_BLEND); } void BrainOpenGLFixedPipeline::setFiberOrientationDisplayInfo(const DisplayPropertiesFiberOrientation* dpfo, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, Plane* plane, const StructureEnum::Enum structure, FiberTrajectoryColorModel::Item* colorSource, FiberOrientationDisplayInfo& dispInfo) { dispInfo.aboveLimit = dpfo->getAboveLimit(displayGroup, tabIndex); dispInfo.belowLimit = dpfo->getBelowLimit(displayGroup, tabIndex); dispInfo.colorSource = colorSource; dispInfo.fiberOrientationColorType = dpfo->getColoringType(displayGroup, tabIndex); dispInfo.fanMultiplier = dpfo->getFanMultiplier(displayGroup, tabIndex); dispInfo.isDrawWithMagnitude = dpfo->isDrawWithMagnitude(displayGroup, tabIndex); dispInfo.minimumMagnitude = dpfo->getMinimumMagnitude(displayGroup, tabIndex); dispInfo.magnitudeMultiplier = dpfo->getLengthMultiplier(displayGroup, tabIndex); dispInfo.plane = plane; dispInfo.structure = structure; dispInfo.symbolType = dpfo->getSymbolType(displayGroup, tabIndex); } /** * Draw fibers for a surface or a volume. * * @param plane * If not NULL, it is the plane of the volume slice being drawn and * only fibers within the above and below limits from the plane will * be drawn. * @param structure * The structure. */ void BrainOpenGLFixedPipeline::drawFiberOrientations(const Plane* plane, const StructureEnum::Enum structure) { const DisplayPropertiesFiberOrientation* dpfo = m_brain->getDisplayPropertiesFiberOrientation(); const DisplayGroupEnum::Enum displayGroup = dpfo->getDisplayGroupForTab(this->windowTabIndex); if (dpfo->isDisplayed(displayGroup, this->windowTabIndex) == false) { return; } const FiberOrientationSymbolTypeEnum::Enum symbolType = dpfo->getSymbolType(displayGroup, this->windowTabIndex); /* * Save status of clipping and disable clipping. * For fibers, the entire fiber symbol is displayed if its * origin is within the clipping planes which is tested below. */ GLboolean clipPlanesEnabled[6] = { glIsEnabled(GL_CLIP_PLANE0), glIsEnabled(GL_CLIP_PLANE1), glIsEnabled(GL_CLIP_PLANE2), glIsEnabled(GL_CLIP_PLANE3), glIsEnabled(GL_CLIP_PLANE4), glIsEnabled(GL_CLIP_PLANE5) }; glDisable(GL_CLIP_PLANE0); glDisable(GL_CLIP_PLANE1); glDisable(GL_CLIP_PLANE2); glDisable(GL_CLIP_PLANE3); glDisable(GL_CLIP_PLANE4); glDisable(GL_CLIP_PLANE5); /* * Fans use lighting but NOT on a volume slice */ disableLighting(); switch (symbolType) { case FiberOrientationSymbolTypeEnum::FIBER_SYMBOL_FANS: if (plane == NULL) { enableLighting(); } break; case FiberOrientationSymbolTypeEnum::FIBER_SYMBOL_LINES: break; } /* * Default constructor is color by fiber orientation settings XYZ/123 as RGB */ FiberTrajectoryColorModel::Item colorUseFiber; FiberOrientationDisplayInfo fiberOrientDispInfo; setFiberOrientationDisplayInfo(dpfo, displayGroup, this->windowTabIndex, const_cast(plane), structure, &colorUseFiber, fiberOrientDispInfo); /* * Draw the vectors from each of the connectivity files */ const int32_t numFiberOrienationFiles = m_brain->getNumberOfConnectivityFiberOrientationFiles(); for (int32_t iFile = 0; iFile < numFiberOrienationFiles; iFile++) { CiftiFiberOrientationFile* cfof = m_brain->getConnectivityFiberOrientationFile(iFile); if (cfof->isDisplayed(displayGroup, this->windowTabIndex)) { /* * Draw each of the fiber orientations which may contain multiple fibers */ const int64_t numberOfFiberOrientations = cfof->getNumberOfFiberOrientations(); for (int64_t i = 0; i < numberOfFiberOrientations; i++) { const FiberOrientation* fiberOrientation = cfof->getFiberOrientations(i); if (fiberOrientation->m_valid == false) { continue; } for (int32_t ifi = 0; ifi < fiberOrientation->m_numberOfFibers; ifi++) { fiberOrientation->m_fibers[ifi]->m_opacityForDrawing = 1.0; } addFiberOrientationForDrawing(&fiberOrientDispInfo, fiberOrientation); } } } drawAllFiberOrientations(&fiberOrientDispInfo, false); /* * Restore status of clipping planes enabled */ if (clipPlanesEnabled[0]) glEnable(GL_CLIP_PLANE0); if (clipPlanesEnabled[1]) glEnable(GL_CLIP_PLANE1); if (clipPlanesEnabled[2]) glEnable(GL_CLIP_PLANE2); if (clipPlanesEnabled[3]) glEnable(GL_CLIP_PLANE3); if (clipPlanesEnabled[4]) glEnable(GL_CLIP_PLANE4); if (clipPlanesEnabled[5]) glEnable(GL_CLIP_PLANE5); } /** * Add fiber orientation for drawing. Note that for alpha blending to * work correctly, the fibers must be sorted by depth and drawn from * furthest to nearest. Some tests will be performed to determine if * the fiber should be drawn prior to adding the fiber to the list * of fibers that will be drawn. * * @param fodi * Parameters controlling the drawing of fiber orientations. * @param fiberOrientation * The fiber orientation that will be drawn. */ void BrainOpenGLFixedPipeline::addFiberOrientationForDrawing(const FiberOrientationDisplayInfo* fodi, const FiberOrientation* fiberOrientation) { /* * Test location of fiber orientation for drawing */ if (fodi->plane != NULL) { const float distToPlane = fodi->plane->signedDistanceToPlane(fiberOrientation->m_xyz); if (distToPlane > fodi->aboveLimit) { return; } if (distToPlane < fodi->belowLimit) { return; } } if (isFeatureClippingEnabled()) { if ( ! isCoordinateInsideClippingPlanesForStructure(fodi->structure, fiberOrientation->m_xyz)) { return; } } m_fiberOrientationsForDrawing.push_back(const_cast(fiberOrientation)); } /* * For comparison when sorting that results in furthest fibers drawn first. */ static bool fiberDepthCompare(FiberOrientation* &f1, FiberOrientation* &f2) { return (f1->m_drawingDepth > f2->m_drawingDepth); } /** * Sort the fiber orientations by depth. */ void BrainOpenGLFixedPipeline::sortFiberOrientationsByDepth() { ElapsedTimer timer; timer.start(); /* * Create transforms model coordinate to a screen coordinate. */ GLdouble modelMatrixOpenGL[16]; glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrixOpenGL); GLdouble projectionMatrixOpenGL[16]; glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrixOpenGL); Matrix4x4 modelMatrix; modelMatrix.setMatrixFromOpenGL(modelMatrixOpenGL); Matrix4x4 projectionMatrix; projectionMatrix.setMatrixFromOpenGL(projectionMatrixOpenGL); Matrix4x4 modelToScreenMatrix; modelToScreenMatrix.setMatrix(projectionMatrix); modelToScreenMatrix.premultiply(modelMatrix); const float m0 = modelToScreenMatrix.getMatrixElement(2, 0); const float m1 = modelToScreenMatrix.getMatrixElement(2, 1); const float m2 = modelToScreenMatrix.getMatrixElement(2, 2); const float m3 = modelToScreenMatrix.getMatrixElement(2, 3); for (std::list::const_iterator iter = m_fiberOrientationsForDrawing.begin(); iter != m_fiberOrientationsForDrawing.end(); iter++) { const FiberOrientation* fiberOrientation = *iter; const float rawDepth =(m0 * fiberOrientation->m_xyz[0] + m1 * fiberOrientation->m_xyz[1] + m2 * fiberOrientation->m_xyz[2] + m3); const float screenDepth = ((rawDepth + 1.0) / 2.0); fiberOrientation->m_drawingDepth = screenDepth; } m_fiberOrientationsForDrawing.sort(fiberDepthCompare); } /** * Draw all of the fiber orienations. * * @param fodi * Parameters controlling the drawing of fiber orientations. */ void BrainOpenGLFixedPipeline::drawAllFiberOrientations(const FiberOrientationDisplayInfo* fodi, const bool isSortFibers) { if (isSortFibers) { sortFiberOrientationsByDepth(); } for (std::list::const_iterator iter = m_fiberOrientationsForDrawing.begin(); iter != m_fiberOrientationsForDrawing.end(); iter++) { const FiberOrientation* fiberOrientation = *iter; /* * Draw each of the fibers */ const int64_t numberOfFibers = fiberOrientation->m_numberOfFibers; for (int64_t j = 0; j < numberOfFibers; j++) { const Fiber* fiber = fiberOrientation->m_fibers[j]; /* * Apply display properties */ bool drawIt = true; if (fiber->m_meanF < fodi->minimumMagnitude) { drawIt = false; } if (drawIt) { float alpha = 1.0; if (j < 3) { alpha = fiber->m_opacityForDrawing; CaretAssertMessage(((alpha >= 0.0) && (alpha <= 1.0)), ("Value=" + AString::number(alpha))); if (alpha <= 0.0) { continue; } } /* * Length of vector */ float vectorLength = fodi->magnitudeMultiplier; if (fodi->isDrawWithMagnitude) { vectorLength *= fiber->m_meanF; } /* * Vector with magnitude */ const float magnitudeVector[3] = { fiber->m_directionUnitVector[0] * vectorLength, fiber->m_directionUnitVector[1] * vectorLength, fiber->m_directionUnitVector[2] * vectorLength }; const float halfMagnitudeVector[3] = { magnitudeVector[0] * 0.5f, magnitudeVector[1] * 0.5f, magnitudeVector[2] * 0.5f, }; /* * Start of vector */ float startXYZ[3] = { fiberOrientation->m_xyz[0], fiberOrientation->m_xyz[1], fiberOrientation->m_xyz[2] }; /* * When drawing lines, start of vector is offset by * have of the vector length since the vector is * bi-directional. */ switch (fodi->symbolType) { case FiberOrientationSymbolTypeEnum::FIBER_SYMBOL_FANS: break; case FiberOrientationSymbolTypeEnum::FIBER_SYMBOL_LINES: startXYZ[0] -= halfMagnitudeVector[0]; startXYZ[1] -= halfMagnitudeVector[1]; startXYZ[2] -= halfMagnitudeVector[2]; break; } /* * End of vector */ float endXYZ[3] = { 0.0, 0.0, 0.0 }; /* * When drawing lines, end point is the start * plus the vector with magnitude. * * When drawing fans, there are two endpoints * with the fans starting in the middle. */ switch (fodi->symbolType) { case FiberOrientationSymbolTypeEnum::FIBER_SYMBOL_FANS: endXYZ[0] = startXYZ[0] + halfMagnitudeVector[0]; endXYZ[1] = startXYZ[1] + halfMagnitudeVector[1]; endXYZ[2] = startXYZ[2] + halfMagnitudeVector[2]; break; case FiberOrientationSymbolTypeEnum::FIBER_SYMBOL_LINES: endXYZ[0] = startXYZ[0] + magnitudeVector[0]; endXYZ[1] = startXYZ[1] + magnitudeVector[1]; endXYZ[2] = startXYZ[2] + magnitudeVector[2]; break; } float fiberRGBA[4] = { 0.0, 0.0, 0.0, 0.0 }; /* * Color of fiber */ switch (fodi->colorSource->getItemType()) { case FiberTrajectoryColorModel::Item::ITEM_TYPE_FIBER_ORIENTATION_COLORING_TYPE: switch (fodi->fiberOrientationColorType) { case FiberOrientationColoringTypeEnum::FIBER_COLORING_FIBER_INDEX_AS_RGB: { const int32_t indx = j % 3; switch (indx) { case 0: /* use RED */ glColor4f(BrainOpenGLFixedPipeline::COLOR_RED[0], BrainOpenGLFixedPipeline::COLOR_RED[1], BrainOpenGLFixedPipeline::COLOR_RED[2], alpha); fiberRGBA[0] = BrainOpenGLFixedPipeline::COLOR_RED[0]; fiberRGBA[1] = BrainOpenGLFixedPipeline::COLOR_RED[1]; fiberRGBA[2] = BrainOpenGLFixedPipeline::COLOR_RED[2]; fiberRGBA[3] = alpha; break; case 1: /* use BLUE */ glColor4f(BrainOpenGLFixedPipeline::COLOR_BLUE[0], BrainOpenGLFixedPipeline::COLOR_BLUE[1], BrainOpenGLFixedPipeline::COLOR_BLUE[2], alpha); fiberRGBA[0] = BrainOpenGLFixedPipeline::COLOR_BLUE[0]; fiberRGBA[1] = BrainOpenGLFixedPipeline::COLOR_BLUE[1]; fiberRGBA[2] = BrainOpenGLFixedPipeline::COLOR_BLUE[2]; fiberRGBA[3] = alpha; break; case 2: /* use GREEN */ glColor4f(BrainOpenGLFixedPipeline::COLOR_GREEN[0], BrainOpenGLFixedPipeline::COLOR_GREEN[1], BrainOpenGLFixedPipeline::COLOR_GREEN[2], alpha); fiberRGBA[0] = BrainOpenGLFixedPipeline::COLOR_GREEN[0]; fiberRGBA[1] = BrainOpenGLFixedPipeline::COLOR_GREEN[1]; fiberRGBA[2] = BrainOpenGLFixedPipeline::COLOR_GREEN[2]; fiberRGBA[3] = alpha; break; } } break; case FiberOrientationColoringTypeEnum::FIBER_COLORING_XYZ_AS_RGB: CaretAssert((fiber->m_directionUnitVectorRGB[0] >= 0.0) && (fiber->m_directionUnitVectorRGB[0] <= 1.0)); CaretAssert((fiber->m_directionUnitVectorRGB[1] >= 0.0) && (fiber->m_directionUnitVectorRGB[1] <= 1.0)); CaretAssert((fiber->m_directionUnitVectorRGB[2] >= 0.0) && (fiber->m_directionUnitVectorRGB[2] <= 1.0)); CaretAssert((alpha >= 0.0) && (alpha <= 1.0)); glColor4f(fiber->m_directionUnitVectorRGB[0], fiber->m_directionUnitVectorRGB[1], fiber->m_directionUnitVectorRGB[2], alpha); fiberRGBA[0] = fiber->m_directionUnitVectorRGB[0]; fiberRGBA[1] = fiber->m_directionUnitVectorRGB[1]; fiberRGBA[2] = fiber->m_directionUnitVectorRGB[2]; fiberRGBA[3] = alpha; break; } break; case FiberTrajectoryColorModel::Item::ITEM_TYPE_CARET_COLOR: { const CaretColorEnum::Enum caretColor = fodi->colorSource->getCaretColor(); const float* rgb = CaretColorEnum::toRGB(caretColor); glColor4f(rgb[0], rgb[1], rgb[2], alpha); fiberRGBA[0] = rgb[0]; fiberRGBA[1] = rgb[1]; fiberRGBA[2] = rgb[2]; fiberRGBA[3] = alpha; } break; } /* * Draw the fiber */ switch (fodi->symbolType) { case FiberOrientationSymbolTypeEnum::FIBER_SYMBOL_FANS: { /* * Draw the cones */ const float radiansToDegrees = 180.0 / M_PI; const float majorAxis = std::min((vectorLength * std::tan(fiber->m_fanningMajorAxisAngle) * fodi->fanMultiplier), vectorLength); const float minorAxis = std::min((vectorLength * std::tan(fiber->m_fanningMinorAxisAngle) * fodi->fanMultiplier), vectorLength); /* * First cone */ glPushMatrix(); glTranslatef(startXYZ[0], startXYZ[1], startXYZ[2]); glRotatef(-fiber->m_phi * radiansToDegrees, 0.0, 0.0, 1.0); glRotatef(-fiber->m_theta * radiansToDegrees, 0.0, 1.0, 0.0); glRotatef(-fiber->m_psi * radiansToDegrees, 0.0, 0.0, 1.0); glScalef(majorAxis * 2.0, minorAxis * 2.0, vectorLength); m_shapeCone->draw(fiberRGBA); glPopMatrix(); /* * Second cone but pointing in opposite direction */ glPushMatrix(); glTranslatef(startXYZ[0], startXYZ[1], startXYZ[2]); glRotatef(-fiber->m_phi * radiansToDegrees, 0.0, 0.0, 1.0); glRotatef(180.0 -fiber->m_theta * radiansToDegrees, 0.0, 1.0, 0.0); glRotatef(fiber->m_psi * radiansToDegrees, 0.0, 0.0, 1.0); glScalef(majorAxis * 2.0, minorAxis * 2.0, vectorLength); m_shapeCone->draw(fiberRGBA); glPopMatrix(); } break; case FiberOrientationSymbolTypeEnum::FIBER_SYMBOL_LINES: { const float radius = 2.0; setLineWidth(radius); glBegin(GL_LINES); glVertex3fv(startXYZ); glVertex3fv(endXYZ); glEnd(); } break; } } } } /* * Now clear the list of fiber orientations for drawing. */ m_fiberOrientationsForDrawing.clear(); } /** * Draw fiber trajectories on a surface. */ void BrainOpenGLFixedPipeline::drawSurfaceFiberTrajectories(const StructureEnum::Enum structure) { drawFiberTrajectories(NULL, structure); } /** * Draw the fiber trajectories. * @param plane * If a volume it is non-NULL and contains the plane of the slice. * @param structure * The structure. */ void BrainOpenGLFixedPipeline::drawFiberTrajectories(const Plane* plane, const StructureEnum::Enum structure) { /* * Save status of clipping and disable clipping. * For fibers, the entire fiber symbol is displayed if its * origin is within the clipping planes which is tested below. */ GLboolean clipPlanesEnabled[6] = { glIsEnabled(GL_CLIP_PLANE0), glIsEnabled(GL_CLIP_PLANE1), glIsEnabled(GL_CLIP_PLANE2), glIsEnabled(GL_CLIP_PLANE3), glIsEnabled(GL_CLIP_PLANE4), glIsEnabled(GL_CLIP_PLANE5) }; glDisable(GL_CLIP_PLANE0); glDisable(GL_CLIP_PLANE1); glDisable(GL_CLIP_PLANE2); glDisable(GL_CLIP_PLANE3); glDisable(GL_CLIP_PLANE4); glDisable(GL_CLIP_PLANE5); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); CaretAssert(this->browserTabContent); OverlaySet* overlaySet = this->browserTabContent->getOverlaySet(); const int32_t numberOfDisplayedOverlays = overlaySet->getNumberOfDisplayedOverlays(); for (int32_t iOver = 0; iOver < numberOfDisplayedOverlays; iOver++) { Overlay* overlay = overlaySet->getOverlay(iOver); if (overlay->isEnabled() == false) { continue; } CaretMappableDataFile* caretMappableDataFile = NULL; int32_t mapIndex = -1; overlay->getSelectionData(caretMappableDataFile, mapIndex); if (caretMappableDataFile == NULL) { continue; } CiftiFiberTrajectoryFile* trajFile = dynamic_cast(caretMappableDataFile); if (trajFile == NULL) { continue; } FiberTrajectoryMapProperties* ftmp = trajFile->getFiberTrajectoryMapProperties(); const float proportionMinimumOpacity = ftmp->getProportionMinimumOpacity(); const float proportionMaximumOpacity = ftmp->getProportionMaximumOpacity(); const float proportionRangeOpacity = proportionMaximumOpacity - proportionMinimumOpacity; const float countMinimumOpacity = ftmp->getCountMinimumOpacity(); const float countMaximumOpacity = ftmp->getCountMaximumOpacity(); const float countRangeOpacity = countMaximumOpacity - countMinimumOpacity; const float distanceMinimumOpacity = ftmp->getDistanceMinimumOpacity(); const float distanceMaximumOpacity = ftmp->getDistanceMaximumOpacity(); const float distanceRangeOpacity = distanceMaximumOpacity - distanceMinimumOpacity; const FiberTrajectoryDisplayModeEnum::Enum displayMode = ftmp->getDisplayMode(); float streamlineThreshold = std::numeric_limits::max(); switch (displayMode) { case FiberTrajectoryDisplayModeEnum::FIBER_TRAJECTORY_DISPLAY_ABSOLUTE: streamlineThreshold = ftmp->getCountStreamline(); if (countRangeOpacity <= 0.0) { continue; } break; case FiberTrajectoryDisplayModeEnum::FIBER_TRAJECTORY_DISPLAY_DISTANCE_WEIGHTED: case FiberTrajectoryDisplayModeEnum::FIBER_TRAJECTORY_DISPLAY_DISTANCE_WEIGHTED_LOG: streamlineThreshold = ftmp->getDistanceStreamline(); if (distanceRangeOpacity <= 0.0) { continue; } break; case FiberTrajectoryDisplayModeEnum::FIBER_TRAJECTORY_DISPLAY_PROPORTION: streamlineThreshold = ftmp->getProportionStreamline(); if (proportionRangeOpacity <= 0.0) { continue; } break; } DisplayPropertiesFiberOrientation* dpfo = m_brain->getDisplayPropertiesFiberOrientation(); const DisplayGroupEnum::Enum displayGroup = dpfo->getDisplayGroupForTab(this->windowTabIndex); const FiberOrientationSymbolTypeEnum::Enum symbolType = dpfo->getSymbolType(displayGroup, this->windowTabIndex); FiberOrientationDisplayInfo fiberOrientDispInfo; setFiberOrientationDisplayInfo(dpfo, displayGroup, this->windowTabIndex, const_cast(plane), structure, ftmp->getFiberTrajectoryColorModel()->getSelectedItem(), fiberOrientDispInfo); /* * Fans use lighting but NOT on a volume slice */ disableLighting(); switch (symbolType) { case FiberOrientationSymbolTypeEnum::FIBER_SYMBOL_FANS: if (plane == NULL) { enableLighting(); } break; case FiberOrientationSymbolTypeEnum::FIBER_SYMBOL_LINES: break; } const std::vector& trajectories = trajFile->getLoadedFiberOrientationTrajectories(); const int64_t numTraj = static_cast(trajectories.size()); for (int64_t iTraj = 0; iTraj < numTraj; iTraj++) { const FiberOrientationTrajectory* fiberTraj = trajectories[iTraj]; const FiberOrientation* orientation = fiberTraj->getFiberOrientation(); const float fiberFractionTotalCount = fiberTraj->getFiberFractionTotalCount(); const std::vector& fiberFractions = fiberTraj->getFiberFractions(); if (fiberFractions.size() != 3) { CaretLogFinest("Fiber Trajectory index=" + AString::number(iTraj) + " has " + AString::number(fiberFractions.size()) + " fibers != 3 from file " + trajFile->getFileNameNoPath()); continue; } else if (fiberFractionTotalCount < streamlineThreshold) { continue; } float fiberOpacities[3] = { 0.0, 0.0, 0.0 }; const float fiberCounts[3] = { fiberFractions[0] * fiberFractionTotalCount, fiberFractions[1] * fiberFractionTotalCount, fiberFractions[2] * fiberFractionTotalCount }; const float fiberFractionDistance = fiberTraj->getFiberFractionDistance(); /* * Set opacities for each fiber using mapping of minimum and * maximum opacities */ switch (displayMode) { case FiberTrajectoryDisplayModeEnum::FIBER_TRAJECTORY_DISPLAY_ABSOLUTE: fiberOpacities[0] = (fiberCounts[0] - countMinimumOpacity) / countRangeOpacity; fiberOpacities[1] = (fiberCounts[1] - countMinimumOpacity) / countRangeOpacity; fiberOpacities[2] = (fiberCounts[2] - countMinimumOpacity) / countRangeOpacity; break; case FiberTrajectoryDisplayModeEnum::FIBER_TRAJECTORY_DISPLAY_DISTANCE_WEIGHTED: fiberOpacities[0] = ((fiberCounts[0] * fiberFractionDistance) - distanceMinimumOpacity) / distanceRangeOpacity; fiberOpacities[1] = ((fiberCounts[1] * fiberFractionDistance) - distanceMinimumOpacity) / distanceRangeOpacity; fiberOpacities[2] = ((fiberCounts[2] * fiberFractionDistance) - distanceMinimumOpacity) / distanceRangeOpacity; break; case FiberTrajectoryDisplayModeEnum::FIBER_TRAJECTORY_DISPLAY_DISTANCE_WEIGHTED_LOG: { const float distanceLog = std::log(fiberFractionDistance); fiberOpacities[0] = ((fiberCounts[0] * distanceLog) - distanceMinimumOpacity) / distanceRangeOpacity; fiberOpacities[1] = ((fiberCounts[1] * distanceLog) - distanceMinimumOpacity) / distanceRangeOpacity; fiberOpacities[2] = ((fiberCounts[2] * distanceLog) - distanceMinimumOpacity) / distanceRangeOpacity; } break; case FiberTrajectoryDisplayModeEnum::FIBER_TRAJECTORY_DISPLAY_PROPORTION: fiberOpacities[0] = (fiberFractions[0] - proportionMinimumOpacity) /proportionRangeOpacity; fiberOpacities[1] = (fiberFractions[1] - proportionMinimumOpacity) /proportionRangeOpacity; fiberOpacities[2] = (fiberFractions[2] - proportionMinimumOpacity) /proportionRangeOpacity; break; } int32_t drawCount = 3; for (int32_t i = 0; i < 3; i++) { if (fiberOpacities[i] > 1.0) { fiberOpacities[i] = 1.0; } else if (fiberOpacities[i] <= 0.0) { fiberOpacities[i] = 0.0; drawCount--; } } if (drawCount > 0) { orientation->m_fibers[0]->m_opacityForDrawing = fiberOpacities[0]; orientation->m_fibers[1]->m_opacityForDrawing = fiberOpacities[1]; orientation->m_fibers[2]->m_opacityForDrawing = fiberOpacities[2]; addFiberOrientationForDrawing(&fiberOrientDispInfo, orientation); } } drawAllFiberOrientations(&fiberOrientDispInfo, true); } glDisable(GL_BLEND); /* * Restore status of clipping planes enabled */ if (clipPlanesEnabled[0]) glEnable(GL_CLIP_PLANE0); if (clipPlanesEnabled[1]) glEnable(GL_CLIP_PLANE1); if (clipPlanesEnabled[2]) glEnable(GL_CLIP_PLANE2); if (clipPlanesEnabled[3]) glEnable(GL_CLIP_PLANE3); if (clipPlanesEnabled[4]) glEnable(GL_CLIP_PLANE4); if (clipPlanesEnabled[5]) glEnable(GL_CLIP_PLANE5); } /** * Draw a cone with an elliptical shape. * @param rgba * Color of cone. * @param baseXYZ * Location of the base (flat wide) part of the cone * @param apexXYZ * Location of the pointed end of the cone * @param baseRadiusScaling * Scale the base radius by this amount * @param baseMajorAngle * Angle for the major axis of the ellipse (units = Radians) * Valid range is [0, Pi/2] * @param baseMinorAngle * Angle for the minor axis of the ellipse (units = Radians) * Valid range is [0, Pi/2] * @param baseRotationAngle (units = Radians) * Rotation of major axis from 'up' * @param backwardsFlag * If true, draw the cone backwards (rotated 180 degrees). */ void BrainOpenGLFixedPipeline::drawEllipticalCone(const float rgba[4], const float baseXYZ[3], const float apexXYZ[3], const float baseRadiusScaling, const float baseMajorAngleIn, const float baseMinorAngleIn, const float baseRotationAngle, const bool backwardsFlag) { float x1 = apexXYZ[0]; float y1 = apexXYZ[1]; float z1 = apexXYZ[2]; float vx = baseXYZ[0] - x1; float vy = baseXYZ[1] - y1; float vz = baseXYZ[2] - z1; float z = (float)std::sqrt( vx*vx + vy*vy + vz*vz ); double ax = 0.0f; const float maxAngle = M_PI_2 * 0.95; float baseMajorAngle = baseMajorAngleIn; if (baseMajorAngle > maxAngle) { baseMajorAngle = maxAngle; } float baseMinorAngle = baseMinorAngleIn; if (baseMinorAngle > maxAngle) { baseMinorAngle = maxAngle; } const float maxWidth = z; const float majorAxis = std::min(z * std::tan(baseMajorAngle) * baseRadiusScaling, maxWidth); const float minorAxis = std::min(z * std::tan(baseMinorAngle) * baseRadiusScaling, maxWidth); double zero = 1.0e-3; if (std::abs(vz) < zero) { ax = 57.2957795*std::acos( vx/z ); /* rotation angle in x-y plane */ if ( vx <= 0.0f ) ax = -ax; } else { ax = 57.2957795*std::acos( vz/z ); /* rotation angle */ if ( vz <= 0.0f ) ax = -ax; } glPushMatrix(); glTranslatef( x1, y1, z1 ); float rx = -vy*vz; float ry = vx*vz; if ((std::abs(vx) < zero) && (std::fabs(vz) < zero)) { if (vy > 0) { ax = 90; } } if (std::abs(vz) < zero) { glRotated(90.0, 0.0, 1.0, 0.0); /* Rotate & align with x axis */ glRotated(ax, -1.0, 0.0, 0.0); /* Rotate to point 2 in x-y plane */ } else { glRotated(ax, rx, ry, 0.0); /* Rotate about rotation vector */ } glPushMatrix(); if (backwardsFlag) { glRotatef(180.0, 0.0, 1.0, 0.0); glRotatef(MathFunctions::toDegrees(-baseRotationAngle), 0.0, 0.0, 1.0); } else { /* * Rotate around Z-axis using the base rotation angle */ glRotatef(MathFunctions::toDegrees(baseRotationAngle), 0.0, 0.0, 1.0); } /* * Draw the cone */ glScalef(majorAxis * 2.0, minorAxis * 2.0, z); m_shapeCone->draw(rgba); glPopMatrix(); glPopMatrix(); } /** * Draw a cone with an elliptical shape. * @param rgba * Color of cone. * @param bottomXYZ * Location of the bottom of the cylinder. * @param topXYZ * Location of the top of the cylinder. * @param radius * Radius of the cylinder. */ void BrainOpenGLFixedPipeline::drawCylinder(const float rgba[4], const float bottomXYZ[3], const float topXYZ[3], const float radius) { float x1 = topXYZ[0]; float y1 = topXYZ[1]; float z1 = topXYZ[2]; float vx = bottomXYZ[0] - x1; float vy = bottomXYZ[1] - y1; float vz = bottomXYZ[2] - z1; float z = (float)std::sqrt( vx*vx + vy*vy + vz*vz ); double ax = 0.0f; double zero = 1.0e-3; if (std::abs(vz) < zero) { ax = 57.2957795*std::acos( vx/z ); /* rotation angle in x-y plane */ if ( vx <= 0.0f ) ax = -ax; } else { ax = 57.2957795*std::acos( vz/z ); /* rotation angle */ if ( vz <= 0.0f ) ax = -ax; } glPushMatrix(); glTranslatef( x1, y1, z1 ); float rx = -vy*vz; float ry = vx*vz; if ((std::abs(vx) < zero) && (std::fabs(vz) < zero)) { if (vy > 0) { ax = 90; } } if (std::abs(vz) < zero) { glRotated(90.0, 0.0, 1.0, 0.0); /* Rotate & align with x axis */ glRotated(ax, -1.0, 0.0, 0.0); /* Rotate to point 2 in x-y plane */ } else { glRotated(ax, rx, ry, 0.0); /* Rotate about rotation vector */ } glPushMatrix(); /* * Draw the cone */ glScalef(radius * 2.0, radius * 2.0, z); m_shapeCylinder->draw(rgba); glPopMatrix(); glPopMatrix(); } /** * Given the full size of a viewport, the gap percentage, and the number * of subviewports, compute the subviewport size and gap in pixels. * * @param viewportSize * Full size of the viewport. * @param gapPercentage * Percentage of viewport used for gap between adjacent subviewports * @param gapOverride * If greater than zero, use this value as the gap and ignore the gap percentage. * @param numberOfSubViewports * Number of subviewports * @param subViewportSizeOut * Output containing the size for a subviewport * @param gapOut * Output for the size of the gap between adjacent subviewports. */ void BrainOpenGLFixedPipeline::createSubViewportSizeAndGaps(const int32_t viewportSize, const float gapPercentage, const int32_t gapOverride, const int32_t numberOfSubViewports, int32_t& subViewportSizeOut, int32_t& gapOut) { subViewportSizeOut = viewportSize; gapOut = 0; if (numberOfSubViewports > 1) { subViewportSizeOut = viewportSize / numberOfSubViewports; gapOut = static_cast(std::floor(static_cast(viewportSize * (gapPercentage / 100.0)))); if (gapOverride > 0) { gapOut = gapOverride; } const double gapSum = gapOut * (numberOfSubViewports - 1); const int32_t subtractFromViewport = std::ceil(gapSum / numberOfSubViewports); subViewportSizeOut -= subtractFromViewport; int32_t checkValue = (subViewportSizeOut * numberOfSubViewports) + (gapOut * (numberOfSubViewports - 1)); if (checkValue < viewportSize) { const bool makeViewportsLargerFlag = true; if (makeViewportsLargerFlag) { /* * Since viewports are integer values, may be able to add more to gaps */ const int32_t subViewportSizePlusOne = subViewportSizeOut + 1; const int32_t checkValueOne = (subViewportSizePlusOne * numberOfSubViewports) + (gapOut * (numberOfSubViewports - 1)); if (checkValueOne <= viewportSize) { subViewportSizeOut = subViewportSizePlusOne; checkValue = checkValueOne; const int32_t subViewportSizePlusTwo = subViewportSizeOut + 1; const int32_t checkValueTwo = (subViewportSizePlusTwo * numberOfSubViewports) + (gapOut * (numberOfSubViewports - 1)); if (checkValueTwo <= viewportSize) { subViewportSizeOut = subViewportSizePlusTwo; checkValue = checkValueTwo; } } } else { /* * Since viewports are integer values, may be able to add more to gaps */ const int32_t gapPlusOne = gapOut + 1; const int32_t checkValueOne = (subViewportSizeOut * numberOfSubViewports) + (gapPlusOne * (numberOfSubViewports - 1)); if (checkValueOne <= viewportSize) { gapOut = gapPlusOne; checkValue = checkValueOne; const int32_t gapPlusTwo = gapOut + 1; const int32_t checkValueTwo = (subViewportSizeOut * numberOfSubViewports) + (gapPlusTwo * (numberOfSubViewports - 1)); if (checkValueTwo <= viewportSize) { gapOut = gapPlusTwo; checkValue = checkValueTwo; } } } } CaretAssert(checkValue <= viewportSize); } } /** * Draw fiber orientations on surface models. * * @param structure * The structure. */ void BrainOpenGLFixedPipeline::drawSurfaceFiberOrientations(const StructureEnum::Enum structure) { drawFiberOrientations(NULL, structure); } /** * Draw the surface montage model. * @param browserTabContent * Content of the window. * @param surfaceMontageModel * The surface montage displayed in the window. * @param viewport * Region for drawing. */ void BrainOpenGLFixedPipeline::drawSurfaceMontageModel(BrowserTabContent* browserTabContent, ModelSurfaceMontage* surfaceMontageModel, const int32_t viewport[4]) { const int32_t tabIndex = browserTabContent->getTabNumber(); std::vector montageViewports; surfaceMontageModel->getSurfaceMontageViewportsForDrawing(tabIndex, montageViewports); if (montageViewports.empty()) { return; } GLint savedVP[4]; glGetIntegerv(GL_VIEWPORT, savedVP); int32_t numberOfRows = 0; int32_t numberOfColumns = 0; SurfaceMontageViewport::getNumberOfRowsAndColumns(montageViewports, numberOfRows, numberOfColumns); const GapsAndMargins* gapsAndMargins = m_brain->getGapsAndMargins(); int32_t subViewportHeight = 0; int32_t verticalGap = 0; createSubViewportSizeAndGaps(viewport[3], gapsAndMargins->getSurfaceMontageVerticalGapForWindow(m_windowIndex), -1, numberOfRows, subViewportHeight, verticalGap); int32_t subViewportWidth = 0; int32_t horizontalGap = 0; createSubViewportSizeAndGaps(viewport[2], gapsAndMargins->getSurfaceMontageHorizontalGapForWindow(m_windowIndex), -1, numberOfColumns, subViewportWidth, horizontalGap); const int32_t numberOfViewports = static_cast(montageViewports.size()); for (int32_t ivp = 0; ivp < numberOfViewports; ivp++) { SurfaceMontageViewport* mvp = montageViewports[ivp]; const float* nodeColoringRGBA = this->surfaceNodeColoring->colorSurfaceNodes(surfaceMontageModel, mvp->getSurface(), this->windowTabIndex); float center[3]; mvp->getSurface()->getBoundingBox()->getCenter(center); const int32_t rowFromTop = mvp->getRow(); const int32_t rowFromBottom = (numberOfRows - rowFromTop - 1); const int32_t column = mvp->getColumn(); const int32_t surfaceViewport[4] = { (viewport[0] + (column * (subViewportWidth + horizontalGap))), (viewport[1] + (rowFromBottom * (subViewportHeight + verticalGap))), subViewportWidth, subViewportHeight }; mvp->setViewport(surfaceViewport); this->setViewportAndOrthographicProjectionForSurfaceFile(surfaceViewport, mvp->getProjectionViewType(), mvp->getSurface()); this->applyViewingTransformations(surfaceMontageModel, center, mvp->getProjectionViewType()); this->drawSurface(mvp->getSurface(), browserTabContent->getScaling(), nodeColoringRGBA, true); } glViewport(savedVP[0], savedVP[1], savedVP[2], savedVP[3]); } /** * Draw the whole brain. * @param browserTabContent * Content of the window. * @param wholeBrainModel * Model for whole brain. * @param viewport * Region for drawing. */ void BrainOpenGLFixedPipeline::drawWholeBrainModel(BrowserTabContent* browserTabContent, ModelWholeBrain* wholeBrainModel, const int32_t viewport[4]) { const int32_t tabNumberIndex = browserTabContent->getTabNumber(); Surface* leftSurface = wholeBrainModel->getSelectedSurface(StructureEnum::CORTEX_LEFT, tabNumberIndex); Surface* rightSurface = wholeBrainModel->getSelectedSurface(StructureEnum::CORTEX_RIGHT, tabNumberIndex); if (m_brain->isSurfaceMatchingToAnatomical()) { /* * Use the primary anatomical surface for sizing any surface in the same * structure so that size of viewport is the same. Otherwise, the viewport * is scaled uniquely for each structure */ BrainStructure* leftStructure = m_brain->getBrainStructure(StructureEnum::CORTEX_LEFT, false); if (leftStructure != NULL) { Surface* leftPrimaryAnat = leftStructure->getPrimaryAnatomicalSurface(); if (leftPrimaryAnat != NULL) { leftSurface = leftPrimaryAnat; } } BrainStructure* rightStructure = m_brain->getBrainStructure(StructureEnum::CORTEX_RIGHT, false); if (rightStructure != NULL) { Surface* rightPrimaryAnat = rightStructure->getPrimaryAnatomicalSurface(); if (rightPrimaryAnat != NULL) { rightSurface = rightPrimaryAnat; } } /* 2/22/19 ALL SURFACES SAME VIEWPORT */ } /* * Center using volume, if it is available * Otherwise, see if surface is available, but a surface is offset * from center so override the X-coordinate to zero. */ float center[3] = { 0.0, 0.0, 0.0 }; VolumeMappableInterface* underlayVolumeFile = wholeBrainModel->getUnderlayVolumeFile(tabNumberIndex); if (underlayVolumeFile != NULL) { BoundingBox volumeBoundingBox; underlayVolumeFile->getVoxelSpaceBoundingBox(volumeBoundingBox); volumeBoundingBox.getCenter(center); } if (leftSurface != NULL) { leftSurface->getBoundingBox()->getCenter(center); center[0] = 0.0; } else { if (rightSurface != NULL) { rightSurface->getBoundingBox()->getCenter(center); center[0] = 0.0; } } /* * Use a surface (if available) to set the orthographic projection size */ Surface* anySurface = NULL; if (leftSurface != NULL) { anySurface = leftSurface; } else if (rightSurface != NULL) { anySurface = rightSurface; } if (anySurface != NULL) { this->setViewportAndOrthographicProjectionForSurfaceFile(viewport, ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_LATERAL, anySurface); } else if (underlayVolumeFile != NULL) { this->setViewportAndOrthographicProjectionForWholeBrainVolume(viewport, ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_LATERAL, underlayVolumeFile); } else { this->setViewportAndOrthographicProjection(viewport, ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_LATERAL); } this->applyViewingTransformations(wholeBrainModel, center, ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_LATERAL); const SurfaceTypeEnum::Enum surfaceType = wholeBrainModel->getSelectedSurfaceType(tabNumberIndex); /* * Need depth testing for drawing slices */ glEnable(GL_DEPTH_TEST); /* * Determine volumes that are to be drawn */ if (underlayVolumeFile != NULL) { std::vector volumeDrawInfo; this->setupVolumeDrawInfo(browserTabContent, m_brain, volumeDrawInfo); if (volumeDrawInfo.empty() == false) { /* * Voxels as 3D */ drawVolumeVoxelsAsCubesWholeBrain(volumeDrawInfo); /* * Filter volumes for drawing and only draw those volumes that * are to be drawn as 2D volume slices. */ std::vector twoDimSliceDrawVolumeDrawInfo; for (std::vector::iterator iter = volumeDrawInfo.begin(); iter != volumeDrawInfo.end(); iter++) { bool useIt = false; VolumeDrawInfo& vdi = *iter; switch (vdi.wholeBrainVoxelDrawingMode) { case WholeBrainVoxelDrawingMode::DRAW_VOXELS_AS_THREE_D_CUBES: case WholeBrainVoxelDrawingMode::DRAW_VOXELS_AS_ROUNDED_THREE_D_CUBES: break; case WholeBrainVoxelDrawingMode::DRAW_VOXELS_ON_TWO_D_SLICES: useIt = true; break; } if (useIt) { twoDimSliceDrawVolumeDrawInfo.push_back(vdi); } } if ( ! twoDimSliceDrawVolumeDrawInfo.empty()) { /* * Allow blending of volume slices and volume surface outline */ glPushAttrib(GL_COLOR_BUFFER_BIT); applyVolumePropertiesOpacity(); /* * Check for oblique slice drawing */ VolumeSliceDrawingTypeEnum::Enum sliceDrawingType = browserTabContent->getSliceDrawingType(); VolumeSliceProjectionTypeEnum::Enum sliceProjectionType = browserTabContent->getSliceProjectionType(); if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_TEXTURE_VOLUME)) { VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum obliqueMaskType = browserTabContent->getVolumeSliceInterpolationEdgeEffectsMaskingType(); BrainOpenGLVolumeTextureSliceDrawing textureSliceDrawing; textureSliceDrawing.draw(this, browserTabContent, twoDimSliceDrawVolumeDrawInfo, sliceDrawingType, sliceProjectionType, obliqueMaskType, viewport); } else { switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: { VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum obliqueMaskType = browserTabContent->getVolumeSliceInterpolationEdgeEffectsMaskingType(); BrainOpenGLVolumeObliqueSliceDrawing volumeSliceDrawing; volumeSliceDrawing.draw(this, browserTabContent, twoDimSliceDrawVolumeDrawInfo, sliceDrawingType, sliceProjectionType, obliqueMaskType, viewport); } break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: { BrainOpenGLVolumeSliceDrawing volumeSliceDrawing; volumeSliceDrawing.draw(this, browserTabContent, twoDimSliceDrawVolumeDrawInfo, sliceDrawingType, sliceProjectionType, viewport); } break; } } glPopAttrib(); } } } drawSurfaceFiberOrientations(StructureEnum::ALL); drawSurfaceFiberTrajectories(StructureEnum::ALL); /* * Draw surfaces last so that opacity works. */ std::set uniqueStructuresToDraw; std::vector surfacesToDraw; const int32_t numberOfBrainStructures = m_brain->getNumberOfBrainStructures(); for (int32_t i = 0; i < numberOfBrainStructures; i++) { BrainStructure* brainStructure = m_brain->getBrainStructure(i); const StructureEnum::Enum structure = brainStructure->getStructure(); Surface* surface = wholeBrainModel->getSelectedSurface(structure, tabNumberIndex); if (surface != NULL) { bool drawIt = false; switch (structure) { case StructureEnum::CORTEX_LEFT: drawIt = browserTabContent->isWholeBrainLeftEnabled(); break; case StructureEnum::CORTEX_RIGHT: drawIt = browserTabContent->isWholeBrainRightEnabled(); break; case StructureEnum::CEREBELLUM: drawIt = browserTabContent->isWholeBrainCerebellumEnabled(); break; default: CaretLogWarning("programmer-issure: Surface type not left/right/cerebellum"); break; } if (drawIt) { uniqueStructuresToDraw.insert(structure); surfacesToDraw.push_back(surface); } } } /* * When only one surface structure is displayed, disable offset of surfaces */ bool allowLeftRightSeparationFlag(true); if (m_brain->isSurfaceMatchingToAnatomical()) { if (uniqueStructuresToDraw.size() == 1) { allowLeftRightSeparationFlag = false; } } const int32_t numSurfaceToDraw = static_cast(surfacesToDraw.size()); for (int32_t i = 0; i < numSurfaceToDraw; i++) { CaretAssertVectorIndex(surfacesToDraw, i); Surface* surface = surfacesToDraw[i]; CaretAssert(surface); float dx = 0.0; float dy = 0.0; float dz = 0.0; if (allowLeftRightSeparationFlag) { switch (surface->getStructure()) { case StructureEnum::CORTEX_LEFT: dx = -browserTabContent->getWholeBrainLeftRightSeparation(); if ((surfaceType != SurfaceTypeEnum::ANATOMICAL) && (surfaceType != SurfaceTypeEnum::RECONSTRUCTION)) { dx -= surface->getBoundingBox()->getMaxX(); } break; case StructureEnum::CORTEX_RIGHT: dx = browserTabContent->getWholeBrainLeftRightSeparation(); if ((surfaceType != SurfaceTypeEnum::ANATOMICAL) && (surfaceType != SurfaceTypeEnum::RECONSTRUCTION)) { dx -= surface->getBoundingBox()->getMinX(); } break; case StructureEnum::CEREBELLUM: dz = browserTabContent->getWholeBrainCerebellumSeparation(); break; default: CaretLogWarning("programmer-issure: Surface type not left/right/cerebellum"); break; } } if (surface != NULL) { /* * Draw the model annotations when the last surface is drawn. */ const bool drawModelSpaceAnnotationsFlag = (i == (numSurfaceToDraw - 1)); const float* nodeColoringRGBA = this->surfaceNodeColoring->colorSurfaceNodes(wholeBrainModel, surface, this->windowTabIndex); glPushMatrix(); glTranslatef(dx, dy, dz); this->drawSurface(surface, browserTabContent->getScaling(), nodeColoringRGBA, drawModelSpaceAnnotationsFlag); glPopMatrix(); } } } /** * Apply opacity from the volume properties */ void BrainOpenGLFixedPipeline::applyVolumePropertiesOpacity() { const DisplayPropertiesVolume* dpv = m_brain->getDisplayPropertiesVolume(); const float opacity = dpv->getOpacity(); const bool useBlendingFlag(opacity < 1.0f); if (useBlendingFlag) { glEnable(GL_BLEND); glBlendColor(opacity, opacity, opacity, opacity); glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA); } } /** * Draw a chart model. * * @param browserTabContent * Content of browser tab. * @param chartModel * The chart model. * @param viewport * The viewport (x, y, width, height) */ void BrainOpenGLFixedPipeline::drawChartOneData(BrowserTabContent* browserTabContent, ModelChart* chartModel, const int32_t viewport[4]) { CaretAssert(browserTabContent); CaretAssert(chartModel); const int32_t tabIndex = browserTabContent->getTabNumber(); ChartModelCartesian* cartesianChart = NULL; ChartableMatrixInterface* matrixChartFile = NULL; const ChartOneDataTypeEnum::Enum chartDataType = chartModel->getSelectedChartOneDataType(tabIndex); SelectionItemDataTypeEnum::Enum selectionItemDataType = SelectionItemDataTypeEnum::INVALID; int32_t scalarDataSeriesMapIndex = -1; switch (chartDataType) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: cartesianChart = chartModel->getSelectedDataSeriesChartModel(tabIndex); selectionItemDataType = SelectionItemDataTypeEnum::CHART_DATA_SERIES; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: cartesianChart = chartModel->getSelectedFrequencySeriesChartModel(tabIndex); selectionItemDataType = SelectionItemDataTypeEnum::CHART_FREQUENCY_SERIES; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: cartesianChart = chartModel->getSelectedTimeSeriesChartModel(tabIndex); selectionItemDataType = SelectionItemDataTypeEnum::CHART_TIME_SERIES; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: { CaretDataFileSelectionModel* matrixFileSelector = chartModel->getChartableMatrixParcelFileSelectionModel(tabIndex); matrixChartFile = matrixFileSelector->getSelectedFileOfType(); selectionItemDataType = SelectionItemDataTypeEnum::CHART_MATRIX; } break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: { CaretDataFileSelectionModel* fileModel = chartModel->getChartableMatrixSeriesFileSelectionModel(tabIndex); CaretDataFile* caretFile = fileModel->getSelectedFile(); if (caretFile != NULL) { ChartableMatrixSeriesInterface* matrixSeriesFile = dynamic_cast(caretFile); if (matrixSeriesFile != NULL) { matrixChartFile = matrixSeriesFile; selectionItemDataType = SelectionItemDataTypeEnum::CHART_MATRIX; scalarDataSeriesMapIndex = matrixSeriesFile->getSelectedMapIndex(tabIndex); } } } break; } if (cartesianChart != NULL) { BrainOpenGLChartDrawingFixedPipeline chartDrawing; chartDrawing.drawCartesianChart(m_brain, this, viewport, getTextRenderer(), cartesianChart, selectionItemDataType, this->windowTabIndex); } else if (matrixChartFile != NULL) { BrainOpenGLChartDrawingFixedPipeline chartDrawing; chartDrawing.drawMatrixChart(m_brain, this, viewport, getTextRenderer(), matrixChartFile, scalarDataSeriesMapIndex, selectionItemDataType, this->windowTabIndex); } } /** * Draw a chart two model. * * @param viewportContent * Content of the viewport * @param chartModel * The chart model. * @param viewport * The viewport (x, y, width, height) */ void BrainOpenGLFixedPipeline::drawChartTwoData(const BrainOpenGLViewportContent* viewportContent, ModelChartTwo* chartModel, const int32_t viewport[4]) { CaretAssert(browserTabContent); CaretAssert(chartModel); std::vector annotationFromChartDrawing; BrainOpenGLChartTwoDrawingFixedPipeline chartDrawing(viewportContent); chartDrawing.drawChartOverlaySet(m_brain, chartModel, this, SelectionItemDataTypeEnum::CHART_DATA_SERIES, viewport, annotationFromChartDrawing); m_specialCaseGraphicsAnnotations.insert(m_specialCaseGraphicsAnnotations.end(), annotationFromChartDrawing.begin(), annotationFromChartDrawing.end()); drawChartCoordinateSpaceAnnotations(viewportContent); } /** * Setup the orthographic projection. * @param viewport * The viewport (x, y, width, height) * @param projectionType * Type of view projection. */ void BrainOpenGLFixedPipeline::setOrthographicProjection(const int32_t viewport[4], const ProjectionViewTypeEnum::Enum projectionType) { setOrthographicProjectionWithHeight(viewport, projectionType, getModelViewingHalfWindowHeight()); } /** * Setup the orthographic projection for the given surface file. * * @param viewport * The viewport (x, y, width, height) * @param projectionType * Type of view projection. * @param boundingBox * The bounding box used for maximum spatial extent. */ void BrainOpenGLFixedPipeline::setOrthographicProjectionForWithBoundingBox(const int32_t viewport[4], const ProjectionViewTypeEnum::Enum projectionType, const BoundingBox* boundingBox) { CaretAssert(boundingBox); /* * For a cortical surface, this largest dimension is the Y-Axis. * This worked correctly when the default view was dorsal with * the anterior pole at the top of the display and the posterior * pole at the bottom of the display. */ float modelHalfHeight = std::max(std::max(boundingBox->getDifferenceX(), boundingBox->getDifferenceY()), boundingBox->getDifferenceZ()) / 2.0; float modelHalfWidth = modelHalfHeight; float windowHorizontalSize = boundingBox->getDifferenceY(); float windowVerticalSize = boundingBox->getDifferenceZ(); switch (projectionType) { case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_ANTERIOR: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_DORSAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_POSTERIOR: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_VENTRAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_FLAT_SURFACE: case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_FLAT_SURFACE: case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_FLAT_SURFACE: windowHorizontalSize = boundingBox->getDifferenceX(); windowVerticalSize = boundingBox->getDifferenceY(); break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_LATERAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_MEDIAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_LATERAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_MEDIAL: break; } /* * The default view was changed to a lateral view and the above * code results in problems during some window resize operations. * But, the Z-difference of a flat surface is zero. * * See also BrowserTabContent::restoreFromScene() that tries to make * old scenes compatible with this new scaling. */ if (windowVerticalSize != 0.0) { modelHalfHeight = windowVerticalSize / 2.0; if ((windowHorizontalSize > 0.0) && (viewport[2] > 0.0)) { /* * Note Z is vertical, Y is horizontal when viewed */ const float surfaceAspectRatio = windowVerticalSize / windowHorizontalSize; const float viewportAspectRatio = (static_cast(viewport[3]) / static_cast(viewport[2])); if (viewportAspectRatio > surfaceAspectRatio) { modelHalfWidth = windowHorizontalSize / 2.0; modelHalfHeight = modelHalfWidth * viewportAspectRatio; } } } const float orthoHeight = modelHalfHeight * 1.02; const float orthoWidth = modelHalfWidth * 1.02; const bool setWidthFromHeightFlag = true; if (setWidthFromHeightFlag) { setOrthographicProjectionWithHeight(viewport, projectionType, orthoHeight); } else { setOrthographicProjectionWithWidth(viewport, projectionType, orthoWidth); } } /** * Setup the orthographic projection with the given window height. * * @param viewport * The viewport (x, y, width, height) * @param projectionType * Type of view projection. * @param halfWindowHeight * Half of window height for model. */ void BrainOpenGLFixedPipeline::setOrthographicProjectionWithHeight(const int32_t viewport[4], const ProjectionViewTypeEnum::Enum projectionType, const float halfWindowHeight) { double width = viewport[2]; double height = viewport[3]; double aspectRatio = (width / height); this->orthographicRight = halfWindowHeight * aspectRatio; this->orthographicLeft = -halfWindowHeight * aspectRatio; this->orthographicTop = halfWindowHeight; this->orthographicBottom = -halfWindowHeight; this->orthographicNear = -1000.0; this->orthographicFar = 1000.0; switch (projectionType) { case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_ANTERIOR: case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_DORSAL: case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_POSTERIOR: case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_VENTRAL: glOrtho(this->orthographicLeft, this->orthographicRight, this->orthographicBottom, this->orthographicTop, this->orthographicNear, this->orthographicFar); break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_FLAT_SURFACE: glOrtho(this->orthographicLeft, this->orthographicRight, this->orthographicBottom, this->orthographicTop, this->orthographicNear, this->orthographicFar); break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_LATERAL: case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_FLAT_SURFACE: case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_MEDIAL: glOrtho(this->orthographicLeft, this->orthographicRight, this->orthographicBottom, this->orthographicTop, this->orthographicNear, this->orthographicFar); break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_LATERAL: case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_MEDIAL: case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_FLAT_SURFACE: glOrtho(this->orthographicRight, this->orthographicLeft, this->orthographicBottom, this->orthographicTop, this->orthographicFar, this->orthographicNear); break; } // std::cout << "Viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; // std::cout << " Ortho Left/Bottom: " << this->orthographicLeft << ", " << this->orthographicBottom << std::endl; // std::cout << " Ortho Right/Top: " << this->orthographicRight << ", " << this->orthographicTop << std::endl; } /** * Setup the orthographic projection with the given window width. * * @param viewport * The viewport (x, y, width, height) * @param projectionType * Type of view projection. * @param halfWindowWidth * Half of window width for model. */ void BrainOpenGLFixedPipeline::setOrthographicProjectionWithWidth(const int32_t viewport[4], const ProjectionViewTypeEnum::Enum projectionType, const float halfWindowWidth) { double width = viewport[2]; double height = viewport[3]; double aspectRatio = (width / height); this->orthographicRight = halfWindowWidth; this->orthographicLeft = -halfWindowWidth; this->orthographicTop = halfWindowWidth / aspectRatio; this->orthographicBottom = -halfWindowWidth / aspectRatio; this->orthographicNear = -1000.0; this->orthographicFar = 1000.0; switch (projectionType) { case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_ANTERIOR: case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_DORSAL: case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_POSTERIOR: case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_VENTRAL: glOrtho(this->orthographicLeft, this->orthographicRight, this->orthographicBottom, this->orthographicTop, this->orthographicNear, this->orthographicFar); break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_FLAT_SURFACE: glOrtho(this->orthographicLeft, this->orthographicRight, this->orthographicBottom, this->orthographicTop, this->orthographicNear, this->orthographicFar); break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_LATERAL: case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_FLAT_SURFACE: case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_MEDIAL: glOrtho(this->orthographicLeft, this->orthographicRight, this->orthographicBottom, this->orthographicTop, this->orthographicNear, this->orthographicFar); break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_LATERAL: case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_MEDIAL: case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_FLAT_SURFACE: glOrtho(this->orthographicRight, this->orthographicLeft, this->orthographicBottom, this->orthographicTop, this->orthographicFar, this->orthographicNear); break; } } /** * check for an OpenGL Error. */ void BrainOpenGLFixedPipeline::checkForOpenGLError(const Model* model, const AString& msgIn) { BrainOpenGL::testForOpenGLError(msgIn, model, this->m_windowIndex, this->windowTabIndex); } /** * Get the depth and RGBA value at the given pixel position. * * @param pixelX * The pixel X-coordinate * @param pixelY * The pixel Y-coordinate * @param depthOut * Output containing depth at pixel. * @param rgbaOut * Output containing RGBA components at pixel. * @return * True if output is valid, else false. * Invalid could be due to an invalid pixel XY. * */ bool BrainOpenGLFixedPipeline::getPixelDepthAndRGBA(const int32_t pixelX, const int32_t pixelY, float& depthOut, float rgbaOut[4]) { depthOut = -1.0; rgbaOut[0] = 0.0; rgbaOut[1] = 0.0; rgbaOut[2] = 0.0; rgbaOut[3] = 0.0; GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); if ((pixelX >= viewport[0]) && (pixelX < viewport[2]) && (pixelY >= viewport[1]) && (pixelY < viewport[3])) { /* OK */ } else { /* * Invalid pixel XY */ return false; } /* * Saves glPixelStore parameters */ glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); /* * QOpenGLWidget Note: The QOpenGLWidget always renders in a * frame buffer object (see its documentation). This is * probably why calls to glReadBuffer() always cause an * OpenGL error. */ #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET /* do not call glReadBuffer() */ #else glReadBuffer(GL_BACK); #endif glPixelStorei(GL_PACK_SKIP_ROWS, 0); glPixelStorei(GL_PACK_SKIP_PIXELS, 0); glPixelStorei(GL_PACK_ALIGNMENT, 4); /* float is 4 bytes */ glReadPixels(pixelX, pixelY, 1, 1, GL_RGBA, GL_FLOAT, rgbaOut); /* * Get depth from depth buffer */ glReadPixels(pixelX, pixelY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depthOut); glPopClientAttrib(); return true; } /** * Analyze color information to extract identification data. * @param dataType * Type of data. * @param x * X-coordinate of identification. * @param y * X-coordinate of identification. * @param indexOut * Index of selected item. * @param depthOut * Depth of selected item. */ void BrainOpenGLFixedPipeline::getIndexFromColorSelection(SelectionItemDataTypeEnum::Enum dataType, const int32_t x, const int32_t y, int32_t& indexOut, float& depthOut) { /* * Saves glPixelStore parameters */ glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); /* * Determine item picked by examination of color in back buffer * * QOpenGLWidget Note: The QOpenGLWidget always renders in a * frame buffer object (see its documentation). This is * probably why calls to glReadBuffer() always cause an * OpenGL error. */ #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET /* do not call glReadBuffer() */ #else glReadBuffer(GL_BACK); #endif glPixelStorei(GL_PACK_SKIP_ROWS, 0); glPixelStorei(GL_PACK_SKIP_PIXELS, 0); glPixelStorei(GL_PACK_ALIGNMENT, 1); uint8_t pixels[3]; glReadPixels((int)x, (int)y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, pixels); indexOut = -1; depthOut = -1.0; CaretLogFine("ID color is " + QString::number(pixels[0]) + ", " + QString::number(pixels[1]) + ", " + QString::number(pixels[2])); this->colorIdentification->getItem(pixels, dataType, &indexOut); if (indexOut >= 0) { /* * Get depth from depth buffer */ glPixelStorei(GL_PACK_ALIGNMENT, 4); glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depthOut); } this->colorIdentification->reset(); glPopClientAttrib(); } /** * Analyze color information to extract identification data. * @param dataType * Type of data. * @param x * X-coordinate of identification. * @param y * X-coordinate of identification. * @param indexOut1 * First index of selected item. * @param indexOut2 * Second index of selected item. * @param depthOut * Depth of selected item. */ void BrainOpenGLFixedPipeline::getIndexFromColorSelection(SelectionItemDataTypeEnum::Enum dataType, const int32_t x, const int32_t y, int32_t& index1Out, int32_t& index2Out, float& depthOut) { /* * Saves glPixelStore parameters */ glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); /* * Determine item picked by examination of color in back buffer * * QOpenGLWidget Note: The QOpenGLWidget always renders in a * frame buffer object (see its documentation). This is * probably why calls to glReadBuffer() always cause an * OpenGL error. */ #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET /* do not call glReadBuffer() */ #else glReadBuffer(GL_BACK); #endif glPixelStorei(GL_PACK_SKIP_ROWS, 0); glPixelStorei(GL_PACK_SKIP_PIXELS, 0); glPixelStorei(GL_PACK_ALIGNMENT, 1); uint8_t pixels[3]; glReadPixels((int)x, (int)y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, pixels); index1Out = -1; index2Out = -1; depthOut = -1.0; CaretLogFine("ID color is " + QString::number(pixels[0]) + ", " + QString::number(pixels[1]) + ", " + QString::number(pixels[2])); this->colorIdentification->getItem(pixels, dataType, &index1Out, &index2Out); if (index1Out >= 0) { /* * Get depth from depth buffer */ glPixelStorei(GL_PACK_ALIGNMENT, 4); glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depthOut); } this->colorIdentification->reset(); glPopClientAttrib(); } /** * Analyze color information to extract identification data. * @param dataType * Type of data. * @param x * X-coordinate of identification. * @param y * X-coordinate of identification. * @param indexOut1 * First index of selected item. * @param indexOut2 * Second index of selected item. * @param indexOut3 * Third index of selected item. * @param depthOut * Depth of selected item. */ void BrainOpenGLFixedPipeline::getIndexFromColorSelection(SelectionItemDataTypeEnum::Enum dataType, const int32_t x, const int32_t y, int32_t& index1Out, int32_t& index2Out, int32_t& index3Out, float& depthOut) { /* * Saves glPixelStore parameters */ glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); /* * Determine item picked by examination of color in back buffer * * QOpenGLWidget Note: The QOpenGLWidget always renders in a * frame buffer object (see its documentation). This is * probably why calls to glReadBuffer() always cause an * OpenGL error. */ #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET /* do not call glReadBuffer() */ #else glReadBuffer(GL_BACK); #endif glPixelStorei(GL_PACK_SKIP_ROWS, 0); glPixelStorei(GL_PACK_SKIP_PIXELS, 0); glPixelStorei(GL_PACK_ALIGNMENT, 1); uint8_t pixels[3]; glReadPixels((int)x, (int)y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, pixels); index1Out = -1; index2Out = -1; index3Out = -1; depthOut = -1.0; CaretLogFine("ID color is " + QString::number(pixels[0]) + ", " + QString::number(pixels[1]) + ", " + QString::number(pixels[2])); this->colorIdentification->getItem(pixels, dataType, &index1Out, &index2Out, &index3Out); if (index1Out >= 0) { /* * Get depth from depth buffer */ glPixelStorei(GL_PACK_ALIGNMENT, 4); glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depthOut); } this->colorIdentification->reset(); glPopClientAttrib(); } /** * Set the selected item's screen coordinates. * @param item * Item that has screen coordinates set. * @param itemXYZ * Model's coordinate. */ void BrainOpenGLFixedPipeline::setSelectedItemScreenXYZ(SelectionItem* item, const float itemXYZ[3]) { GLdouble selectionModelviewMatrix[16]; glGetDoublev(GL_MODELVIEW_MATRIX, selectionModelviewMatrix); GLdouble selectionProjectionMatrix[16]; glGetDoublev(GL_PROJECTION_MATRIX, selectionProjectionMatrix); GLint selectionViewport[4]; glGetIntegerv(GL_VIEWPORT, selectionViewport); const double modelXYZ[3] = { itemXYZ[0], itemXYZ[1], itemXYZ[2] }; double windowPos[3]; if (gluProject(modelXYZ[0], modelXYZ[1], modelXYZ[2], selectionModelviewMatrix, selectionProjectionMatrix, selectionViewport, &windowPos[0], &windowPos[1], &windowPos[2])) { item->setScreenXYZ(windowPos); item->setModelXYZ(modelXYZ); } } /** * Draw sphere. * * @param rgba * Color for drawing. * @param diameter * Diameter of the sphere. */ void BrainOpenGLFixedPipeline::drawSphereWithDiameter(const float rgba[4], const double diameter) { glPushMatrix(); glScaled(diameter, diameter, diameter); m_shapeSphere->draw(rgba); glPopMatrix(); } /** * Draw sphere. * * @param rgba * Color for drawing. * @param diameter * Diameter of the sphere. */ void BrainOpenGLFixedPipeline::drawSphereWithDiameter(const uint8_t rgba[4], const double diameter) { glPushMatrix(); glScaled(diameter, diameter, diameter); m_shapeSphere->draw(rgba); glPopMatrix(); } /** * Draw cube. * * @param rgba * Color for drawing. * @param cubeSize * Size of the cube (distance from one face to its opposite face). */ void BrainOpenGLFixedPipeline::drawCube(const float rgba[4], const double cubeSize) { glPushMatrix(); glScaled(cubeSize, cubeSize, cubeSize); m_shapeCube->draw(rgba); glPopMatrix(); } /** * Draw a cuboid (3D Box) * * @param rgba * Color for drawing. * @param sizeX * X-Size of the cube (distance from -X face to its +X face). * @param sizeY * Y-Size of the cube (distance from -Y face to its +Y face). * @param sizeZ * Z-Size of the cube (distance from -Z face to its +X face). */ void BrainOpenGLFixedPipeline::drawCuboid(const uint8_t rgba[4], const double sizeX, const double sizeY, const double sizeZ) { glPushMatrix(); glScaled(sizeX, sizeY, sizeZ); m_shapeCube->draw(rgba); glPopMatrix(); } /** * Draw cube. * * @param rgba * Color for drawing. * @param cubeSize * Size of the cube (distance from one face to its opposite face). */ void BrainOpenGLFixedPipeline::drawRoundedCube(const float rgba[4], const double cubeSize) { glPushMatrix(); glScaled(cubeSize, cubeSize, cubeSize); m_shapeCubeRounded->draw(rgba); glPopMatrix(); } /** * Draw a cuboid (3D Box) * * @param rgba * Color for drawing. * @param sizeX * X-Size of the cube (distance from -X face to its +X face). * @param sizeY * Y-Size of the cube (distance from -Y face to its +Y face). * @param sizeZ * Z-Size of the cube (distance from -Z face to its +X face). */ void BrainOpenGLFixedPipeline::drawRoundedCuboid(const uint8_t rgba[4], const double sizeX, const double sizeY, const double sizeZ) { glPushMatrix(); glScaled(sizeX, sizeY, sizeZ); m_shapeCubeRounded->draw(rgba); glPopMatrix(); } /** * Draw a one millimeter square facing the user. * NOTE: This method will alter the current * modelviewing matrices so caller may need * to enclose the call to this method within * glPushMatrix() and glPopMatrix(). * * @param rgba * RGBA coloring ranging 0.0 to 1.0. * @param size * Size of square. */ void BrainOpenGLFixedPipeline::drawSquare(const float rgba[4], const float size) { if (this->inverseRotationMatrixValid) { glColor4fv(rgba); /* * Remove any rotation */ glMultMatrixd(this->inverseRotationMatrix); glScalef(size, size, size); /* * Draw both front and back side since in some instances, * such as surface montage, we are viweing from the far * side (from back of monitor) */ glBegin(GL_QUADS); glNormal3f(0.0, 0.0, 1.0); glVertex3f(-0.5, -0.5, 0.0); glVertex3f( 0.5, -0.5, 0.0); glVertex3f( 0.5, 0.5, 0.0); glVertex3f(-0.5, 0.5, 0.0); glNormal3f(0.0, 0.0, -1.0); glVertex3f(-0.5, -0.5, 0.0); glVertex3f(-0.5, 0.5, 0.0); glVertex3f( 0.5, 0.5, 0.0); glVertex3f( 0.5, -0.5, 0.0); glEnd(); } } /** * Draw a one millimeter square facing the user. * NOTE: This method will alter the current * modelviewing matrices so caller may need * to enclose the call to this method within * glPushMatrix() and glPopMatrix(). * * @param rgba * RGBA coloring ranging 0 to 255. * @param size * Size of square. */ void BrainOpenGLFixedPipeline::drawSquare(const uint8_t rgba[4], const float size) { if (this->inverseRotationMatrixValid) { glColor4ubv(rgba); /* * Remove any rotation */ glMultMatrixd(this->inverseRotationMatrix); glScalef(size, size, size); /* * Draw both front and back side since in some instances, * such as surface montage, we are viweing from the far * side (from back of monitor) */ glBegin(GL_QUADS); glNormal3f(0.0, 0.0, 1.0); glVertex3f(-0.5, -0.5, 0.0); glVertex3f( 0.5, -0.5, 0.0); glVertex3f( 0.5, 0.5, 0.0); glVertex3f(-0.5, 0.5, 0.0); glNormal3f(0.0, 0.0, -1.0); glVertex3f(-0.5, -0.5, 0.0); glVertex3f(-0.5, 0.5, 0.0); glVertex3f( 0.5, 0.5, 0.0); glVertex3f( 0.5, -0.5, 0.0); glEnd(); } } /** * Draw the user's selected image over the background * * vpContent * Viewport content which image is displayed. */ void BrainOpenGLFixedPipeline::drawBackgroundImage(const BrainOpenGLViewportContent* vpContent) { BrowserTabContent* btc = vpContent->getBrowserTabContent(); if (btc == NULL) { return; } const float backZ = -990.0; const float middleZ = 0.0; const float frontZ = 990.0; DisplayPropertiesImages* dpi = m_brain->getDisplayPropertiesImages(); const int32_t tabIndex = btc->getTabNumber(); const DisplayGroupEnum::Enum displayGroup = dpi->getDisplayGroupForTab(tabIndex); if (dpi->isDisplayed(displayGroup, tabIndex)) { ImageFile* imageFile = dpi->getSelectedImageFile(displayGroup, tabIndex); if (imageFile != NULL) { float windowZ = 990.0; const ImageDepthPositionEnum::Enum depthPos = dpi->getImagePosition(displayGroup, tabIndex); switch (depthPos) { case ImageDepthPositionEnum::BACK: windowZ = backZ; break; case ImageDepthPositionEnum::FRONT: windowZ = frontZ; break; case ImageDepthPositionEnum::MIDDLE: windowZ = middleZ; break; } drawImage(vpContent, imageFile, windowZ, frontZ, dpi->getThresholdMinimum(displayGroup, tabIndex), dpi->getThresholdMaximum(displayGroup, tabIndex), dpi->getOpacity(displayGroup, tabIndex), dpi->isControlPointsDisplayed(displayGroup, tabIndex)); } } } /** * Draw the given image in the given viewport. * * @param vpContent * The viewport content. * @param imageFile * The QImage that is drawn. * @param windowZ * Z-position for image. * @param frontZ * Z-position for front (used for control points) * @param minimumThreshold * Minimum threshold value. * @param maximumThreshold * Maximum threshold value. * @param opacity * Opacity. */ void BrainOpenGLFixedPipeline::drawImage(const BrainOpenGLViewportContent* vpContent, ImageFile* imageFile, const float windowZ, const float frontZ, const float minimumThreshold, const float maximumThreshold, const float opacity, const bool drawControlPointsFlag) { CaretAssert(vpContent); const int32_t originalImageWidth = imageFile->getWidth(); const int32_t originalImageHeight = imageFile->getHeight(); const int32_t originalNumberOfPixels = originalImageWidth * originalImageHeight; if (originalNumberOfPixels <= 0) { return; } int viewport[4]; vpContent->getModelViewport(viewport); SelectionItemImage* idImage = m_brain->getSelectionManager()->getImageIdentification(); SelectionItemImageControlPoint* idControlPoint = m_brain->getSelectionManager()->getImageControlPointIdentification(); /* * Check for a 'selection' type mode */ bool isSelectImage = false; bool isSelectImageControlPoint = false; switch (this->mode) { case BrainOpenGLFixedPipeline::MODE_DRAWING: break; case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: if (idImage->isEnabledForSelection()) { isSelectImage = true; } if (idControlPoint->isEnabledForSelection()) { isSelectImageControlPoint = true; } if (isSelectImage || isSelectImageControlPoint) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } else { return; } break; case BrainOpenGLFixedPipeline::MODE_PROJECTION: return; break; } /* * Normalized width/height * * > 1.0 ===> viewport dimension larger than image dimension * < 1.0 ===> viewport dimension smaller than image dimension */ const int32_t viewportWidth = viewport[2]; const int32_t viewportHeight = viewport[3]; const float widthNormalized = static_cast(viewportWidth) / static_cast(originalImageWidth); const float heightNormalized = static_cast(viewportHeight) / static_cast(originalImageHeight); /* * Scale image so that it fills window in one dimension and other * image dimension is less than or equal to the window dimension. */ float imageScale = 0.0; if (widthNormalized < heightNormalized) { imageScale = widthNormalized; } else { imageScale = heightNormalized; } std::vector imageBytesRGBA; int32_t imageWidth = originalImageWidth; int32_t imageHeight = originalImageHeight; if (imageScale > 0.0) { imageWidth = originalImageWidth * imageScale; imageHeight = originalImageHeight * imageScale; imageFile->getImageResizedBytes(ImageFile::IMAGE_DATA_ORIGIN_AT_BOTTOM, imageWidth, imageHeight, imageBytesRGBA); } else { int32_t dummyWidth = 0; int32_t dummyHeight = 0; imageFile->getImageBytesRGBA(ImageFile::IMAGE_DATA_ORIGIN_AT_BOTTOM, imageBytesRGBA, dummyWidth, dummyHeight); } const int32_t numberOfPixels = imageWidth * imageHeight; const int32_t bytesPerPixel = 4; const int32_t correctNumberOfBytes = numberOfPixels * bytesPerPixel; if (static_cast(imageBytesRGBA.size()) != correctNumberOfBytes) { CaretLogSevere("Image size is incorrect. Number of bytes is " + QString::number(imageBytesRGBA.size()) + " but should be " + QString::number(correctNumberOfBytes)); } const bool testThresholdFlag = ((minimumThreshold > 0.0) || (maximumThreshold < 255.0)); const bool testOpacityFlag = (opacity < 1.0); bool useBlendingFlag = false; if (testThresholdFlag || testOpacityFlag) { for (int32_t i = 0; i < numberOfPixels; i++) { const int32_t i4 = i * 4; CaretAssertVectorIndex(imageBytesRGBA, i4 + 3); uint8_t pixelAlpha = 255; if (testThresholdFlag) { if ((imageBytesRGBA[i4] < minimumThreshold) || (imageBytesRGBA[i4] > maximumThreshold) || (imageBytesRGBA[i4+1] < minimumThreshold) || (imageBytesRGBA[i4+1] > maximumThreshold) || (imageBytesRGBA[i4+2] < minimumThreshold) || (imageBytesRGBA[i4+2] > maximumThreshold)) { pixelAlpha = 0; } } if (testOpacityFlag) { pixelAlpha = static_cast(pixelAlpha * opacity); } if (pixelAlpha < 255) { useBlendingFlag = true; } imageBytesRGBA[i4 + 3] = pixelAlpha; } } if (isSelectImage || isSelectImageControlPoint) { useBlendingFlag = false; } /* * Center image in the window */ const int32_t xHalfMargin = (viewportWidth - imageWidth) / 2.0; const int32_t xPos = std::max(xHalfMargin, 0); const int32_t yHalfMargin = (viewportHeight - imageHeight) / 2.0; const int32_t yPos = std::max(yHalfMargin, 0); /* * Reset orthographic projection to viewport size */ glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); const double maxClip = 1000.0; const double nearClip = -maxClip; const double farClip = maxClip; glOrtho(0, viewportWidth, 0, viewportHeight, nearClip, farClip); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); /* * Saves glPixelStore parameters */ glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); GLboolean blendingEnabled = GL_FALSE; glGetBooleanv(GL_BLEND, &blendingEnabled); if (useBlendingFlag) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } /* * Set the image's Z coordinate where a depth percentage of 100.0 * is at the far clipping plane (away from viewer) and a percentage * of zero is at the near clipping plane (closest to viewer). * * Old way to set Z: const float imageZ = 10.0 - farClip; */ glRasterPos3f(xPos, yPos, windowZ); glDrawPixels(imageWidth, imageHeight, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)&imageBytesRGBA[0]); if (blendingEnabled == GL_FALSE) { glDisable(GL_BLEND); } glPopClientAttrib(); ControlPointFile* controlPointFile = imageFile->getControlPointFile(); if (drawControlPointsFlag) { const int32_t numControlPoints = controlPointFile->getNumberOfControlPoints(); if (numControlPoints > 0) { const uint8_t red[4] = { 255, 0, 0, 255 }; for (int32_t icp = 0; icp < numControlPoints; icp++) { const ControlPoint3D* cp = controlPointFile->getControlPointAtIndex(icp); const float pixelX = cp->getSourceX(); const float pixelY = cp->getSourceY(); const float percentX = pixelX / originalImageWidth; const float percentY = pixelY / originalImageHeight; const float x = xPos + (percentX * imageWidth); const float y = yPos + (percentY * imageHeight); glPushMatrix(); glTranslatef(x, y, frontZ); uint8_t rgba[4] = { red[0], red[1], red[2], red[3] }; if (isSelectImageControlPoint) { this->colorIdentification->addItem(rgba, SelectionItemDataTypeEnum::IMAGE_CONTROL_POINT, 0, /* file index */ icp); /* index in file */ rgba[3] = 255; } drawSphereWithDiameter(rgba, 10); glPopMatrix(); } } } glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); if (isSelectImage) { const float mx = this->mouseX - viewport[0]; const float my = this->mouseY - viewport[1]; const float imageX = mx - xPos; const float imageY = my - yPos; const float normalizedX = imageX / static_cast(imageWidth); const float normalizedY = imageY / static_cast(imageHeight); const int32_t pixelX = static_cast(normalizedX * static_cast(originalImageWidth)); const int32_t pixelY = static_cast(normalizedY * static_cast(originalImageHeight)); if ((pixelX >= 0) && (pixelX < originalImageWidth) && (pixelY >= 0) && (pixelY < originalImageHeight)) { idImage->setImageFile(imageFile); idImage->setPixelI(pixelX); idImage->setPixelJ(pixelY); uint8_t pixelByteRGBA[4]; if (imageFile->getImagePixelRGBA(ImageFile::IMAGE_DATA_ORIGIN_AT_BOTTOM, pixelX, pixelY, pixelByteRGBA)) { idImage->setPixelRGBA(pixelByteRGBA); } } } if (isSelectImageControlPoint) { int32_t fileIndex = -1; int32_t controlPointIndex = -1; float depth = -1.0; this->getIndexFromColorSelection(SelectionItemDataTypeEnum::IMAGE_CONTROL_POINT, this->mouseX, this->mouseY, fileIndex, controlPointIndex, depth); if ((fileIndex >= 0) && (controlPointIndex >= 0)) { if (idControlPoint->isOtherScreenDepthCloserToViewer(depth)) { ControlPoint3D* controlPoint = controlPointFile->getControlPointAtIndex(controlPointIndex); idControlPoint->setBrain(m_brain); idControlPoint->setImageFile(imageFile); idControlPoint->setControlPointFile(controlPointFile); idControlPoint->setControlPoint(controlPoint); idControlPoint->setControlPointIndexInFile(controlPointIndex); idControlPoint->setScreenDepth(depth); } } } } /** * Draw annnotation text at the given viewport coordinates using * the the annotations attributes for the style of text. * * Depth testing is ENABLED for this method * * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param annotationText * Annotation text and attributes. */ void BrainOpenGLFixedPipeline::drawTextAtViewportCoords(const double viewportX, const double viewportY, const AnnotationText& annotationText) { if (getTextRenderer() != NULL) { getTextRenderer()->drawTextAtViewportCoords(viewportX, viewportY, annotationText, BrainOpenGLTextRenderInterface::DrawingFlags()); } } /** * Draw annnotation text at the given model coordinates using * the the annotations attributes for the style of text. * * Depth testing is ENABLED for this method * * @param modelX * Model X-coordinate. * @param modelY * Model Y-coordinate. * @param modelZ * Model Z-coordinate. * @param annotationText * Annotation text and attributes. */ void BrainOpenGLFixedPipeline::drawTextAtModelCoords(const double modelX, const double modelY, const double modelZ, const AnnotationText& annotationText) { if (getTextRenderer() != NULL) { getTextRenderer()->drawTextAtModelCoordsFacingUser(modelX, modelY, modelZ, annotationText, BrainOpenGLTextRenderInterface::DrawingFlags()); } } /** * Draw annnotation text at the given model coordinates using * the the annotations attributes for the style of text. * * @param modelXYZ * Model XYZ coordinates. * @param annotationText * Annotation text and attributes. */ void BrainOpenGLFixedPipeline::drawTextAtModelCoords(const double modelXYZ[3], const AnnotationText& annotationText) { if (getTextRenderer() != NULL) { getTextRenderer()->drawTextAtModelCoordsFacingUser(modelXYZ, annotationText, BrainOpenGLTextRenderInterface::DrawingFlags()); } } /** * Draw annnotation text at the given model coordinates using * the the annotations attributes for the style of text. * * @param modelXYZ * Model XYZ coordinates. * @param annotationText * Annotation text and attributes. */ void BrainOpenGLFixedPipeline::drawTextAtModelCoords(const float modelXYZ[3], const AnnotationText& annotationText) { if (getTextRenderer() != NULL) { getTextRenderer()->drawTextAtModelCoordsFacingUser(modelXYZ, annotationText, BrainOpenGLTextRenderInterface::DrawingFlags()); } } /** * @return A string containing the state of OpenGL (depth testing, lighting, etc.) */ AString BrainOpenGLFixedPipeline::getStateOfOpenGL() const { AString s = BrainOpenGL::getStateOfOpenGL(); s.appendWithNewLine("Fixed Pipeline State:"); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_BLEND", GL_BLEND)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_CLIP_PLANE0", GL_CLIP_PLANE0)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_CLIP_PLANE1", GL_CLIP_PLANE1)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_CLIP_PLANE2", GL_CLIP_PLANE2)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_CLIP_PLANE3", GL_CLIP_PLANE3)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_CLIP_PLANE4", GL_CLIP_PLANE4)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_CLIP_PLANE5", GL_CLIP_PLANE5)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_COLOR_MATERIAL", GL_COLOR_MATERIAL)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_CULL_FACE", GL_CULL_FACE)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_DEPTH_TEST", GL_DEPTH_TEST)); s.appendWithNewLine(" " + getOpenGLBooleanAsText("GL_DOUBLEBUFFER", GL_DOUBLEBUFFER)); s.appendWithNewLine(" " + getOpenGLBooleanAsText("GL_LIGHT_MODEL_LOCAL_VIEWER", GL_LIGHT_MODEL_LOCAL_VIEWER)); s.appendWithNewLine(" " + getOpenGLBooleanAsText("GL_LIGHT_MODEL_TWO_SIDE", GL_LIGHT_MODEL_TWO_SIDE)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_LIGHTING", GL_LIGHTING)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_LIGHT0", GL_LIGHT0)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_LIGHT1", GL_LIGHT1)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_LIGHT2", GL_LIGHT2)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_LIGHT3", GL_LIGHT3)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_LIGHT4", GL_LIGHT4)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_LIGHT5", GL_LIGHT5)); s.appendWithNewLine(" " + getOpenGLLightAsText("GL_LIGHT0, GL_DIFFUSE", GL_LIGHT0, GL_DIFFUSE, 4)); s.appendWithNewLine(" " + getOpenGLLightAsText("GL_LIGHT0, GL_POSITION", GL_LIGHT0, GL_POSITION, 4)); s.appendWithNewLine(" " + getOpenGLLightAsText("GL_LIGHT1, GL_DIFFUSE", GL_LIGHT1, GL_DIFFUSE, 4)); s.appendWithNewLine(" " + getOpenGLLightAsText("GL_LIGHT1, GL_POSITION", GL_LIGHT1, GL_POSITION, 4)); s.appendWithNewLine(" " + getOpenGLFloatAsText("GL_LIGHT_MODEL_AMBIENT", GL_LIGHT_MODEL_AMBIENT, 4)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_LINE_SMOOTH", GL_LINE_SMOOTH)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_NORMALIZE", GL_NORMALIZE)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_POLYGON_OFFSET_FILL", GL_POLYGON_OFFSET_FILL)); s.appendWithNewLine(" " + getOpenGLEnabledEnumAsText("GL_POLYGON_SMOOTH", GL_POLYGON_SMOOTH)); GLint frontFace; glGetIntegerv(GL_FRONT_FACE, &frontFace); AString frontFaceValue; switch (frontFace) { case GL_CW: frontFaceValue = "GL_CW"; break; case GL_CCW: frontFaceValue = "GL_CCW"; break; default: frontFaceValue = "INVALID"; break; } s.appendWithNewLine(" Front Face " + frontFaceValue); GLint cullFace; glGetIntegerv(GL_FRONT_FACE, &cullFace); AString cullFaceValue; switch (cullFace) { case GL_FRONT: cullFaceValue = "GL_FRONT"; break; case GL_BACK: cullFaceValue = "GL_BACK"; break; case GL_FRONT_AND_BACK: cullFaceValue = "GL_FRONT_AND_BACK"; break; default: cullFaceValue = "INVALID"; break; } s.appendWithNewLine(" Cull Face " + cullFaceValue); return s; } /* ============================================================================ */ /** * Constructor. */ BrainOpenGLFixedPipeline::VolumeDrawInfo::VolumeDrawInfo(CaretMappableDataFile* mapFile, VolumeMappableInterface* volumeFile, Brain* brain, PaletteColorMapping* paletteColorMapping, const FastStatistics* statistics, const WholeBrainVoxelDrawingMode::Enum wholeBrainVoxelDrawingMode, const int32_t mapIndex, const float opacity) : statistics(statistics) { this->mapFile = mapFile; this->volumeFile = volumeFile; this->brain = brain; this->paletteColorMapping = paletteColorMapping; this->wholeBrainVoxelDrawingMode = wholeBrainVoxelDrawingMode; this->mapIndex = mapIndex; this->opacity = opacity; } connectome-workbench-1.4.2/src/Brain/BrainOpenGLFixedPipeline.h000066400000000000000000000663241360521144700244070ustar00rootroot00000000000000 #ifndef __BRAIN_OPENGL_FIXED_PIPELINE_H__ #define __BRAIN_OPENGL_FIXED_PIPELINE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "BrainConstants.h" #include "BrainOpenGL.h" #include "BrainOpenGLTextRenderInterface.h" #include "CaretPointer.h" #include "CaretVolumeExtension.h" #include "DisplayGroupEnum.h" #include "FiberOrientationColoringTypeEnum.h" #include "FiberOrientationSymbolTypeEnum.h" #include "FiberTrajectoryColorModel.h" #include "ProjectionViewTypeEnum.h" #include "SelectionItemDataTypeEnum.h" #include "StructureEnum.h" #include "SurfaceNodeColoring.h" #include "VolumeSliceViewPlaneEnum.h" #include "WholeBrainVoxelDrawingMode.h" namespace caret { class Annotation; class AnnotationText; class BoundingBox; class Brain; class BrainOpenGLAnnotationDrawingFixedPipeline; class BrainOpenGLShapeCone; class BrainOpenGLShapeCube; class BrainOpenGLShapeCylinder; class BrainOpenGLShapeRing; class BrainOpenGLShapeSphere; class BrainOpenGLViewportContent; class BrowserTabContent; class CaretMappableDataFile; class ClippingPlaneGroup; class FastStatistics; class DisplayPropertiesFiberOrientation; class FiberOrientation; class SelectionItem; class SelectionManager; class IdentificationWithColor; class ImageFile; class Plane; class Surface; class Model; class ModelChart; class ModelChartTwo; class ModelSurface; class ModelSurfaceMontage; class ModelVolume; class ModelWholeBrain; class Palette; class PaletteColorMapping; class SurfaceFile; class SurfaceMontageConfigurationCerebellar; class SurfaceMontageConfigurationCerebral; class SurfaceMontageConfigurationFlatMaps; class VolumeFile; class VolumeMappableInterface; /** * Performs drawing of graphics using OpenGL. */ class BrainOpenGLFixedPipeline : public BrainOpenGL { private: enum Mode { MODE_DRAWING, MODE_IDENTIFICATION, MODE_PROJECTION }; BrainOpenGLFixedPipeline(const BrainOpenGLFixedPipeline&); BrainOpenGLFixedPipeline& operator=(const BrainOpenGLFixedPipeline&); public: BrainOpenGLFixedPipeline(BrainOpenGLTextRenderInterface* textRenderer); ~BrainOpenGLFixedPipeline(); void initializeOpenGL(); virtual AString getStateOfOpenGL() const; static void createSubViewportSizeAndGaps(const int32_t viewportSize, const float gapPercentage, const int32_t gapOverride, const int32_t numberOfSubViewports, int32_t& subViewportSizeOut, int32_t& gapOut); protected: void drawModelsImplementation(const int32_t windowIndex, const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, const std::vector& viewportContents) override; void selectModelImplementation(const int32_t windowIndex, const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, const bool applySelectionBackgroundFiltering) override; void projectToModelImplementation(const int32_t windowIndex, const UserInputModeEnum::Enum windowUserInputMode, Brain* brain, const BrainOpenGLViewportContent* viewportContent, const int32_t mouseX, const int32_t mouseY, SurfaceProjectedItem& projectionOut) override; protected: virtual void loadObjectToWindowTransform(EventOpenGLObjectToWindowTransform* transformEvent) override; private: class VolumeDrawInfo { public: VolumeDrawInfo(CaretMappableDataFile* mapFile, VolumeMappableInterface* volumeFile, Brain* brain, PaletteColorMapping* paletteColorMapping, const FastStatistics* statistics, const WholeBrainVoxelDrawingMode::Enum wholeBrainVoxelDrawingMode, const int32_t mapIndex, const float opacity); Brain* brain; CaretMappableDataFile* mapFile; VolumeMappableInterface* volumeFile; SubvolumeAttributes::VolumeType volumeType; PaletteColorMapping* paletteColorMapping; WholeBrainVoxelDrawingMode::Enum wholeBrainVoxelDrawingMode; const FastStatistics* statistics; int32_t mapIndex; float opacity; }; struct FiberOrientationDisplayInfo { float aboveLimit; float belowLimit; FiberTrajectoryColorModel::Item* colorSource; FiberOrientationColoringTypeEnum::Enum fiberOrientationColorType; float fanMultiplier; bool isDrawWithMagnitude; float minimumMagnitude; float magnitudeMultiplier; Plane* plane; FiberOrientationSymbolTypeEnum::Enum symbolType; StructureEnum::Enum structure; }; void setFiberOrientationDisplayInfo(const DisplayPropertiesFiberOrientation* dpfo, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, Plane* plane, const StructureEnum::Enum structure, FiberTrajectoryColorModel::Item* colorSource, FiberOrientationDisplayInfo& dispInfo); void drawModelInternal(Mode mode, const BrainOpenGLViewportContent* viewportContent); void initializeMembersBrainOpenGL(); void drawChartOneData(BrowserTabContent* browserTabContent, ModelChart* chartData, const int32_t viewport[4]); void drawChartTwoData(const BrainOpenGLViewportContent* viewportContent, ModelChartTwo* chartData, const int32_t viewport[4]); void drawSurfaceModel(BrowserTabContent* browserTabContent, ModelSurface* surfaceModel, const int32_t viewport[4]); void drawSurface(Surface* surface, const float surfaceScaling, const float* nodeColoringRGBA, const bool drawAnnotationsInModelSpaceFlag); void drawSurfaceNodes(Surface* surface, const float* nodeColoringRGBA); void drawSurfaceTrianglesWithVertexArrays(const Surface* surface, const float* nodeColoringRGBA); void drawSurfaceTriangles(Surface* surface, const float* nodeColoringRGBA); void drawSurfaceNodeAttributes(Surface* surface); void drawSurfaceBorderBeingDrawn(const Surface* surface); void drawSurfaceBorders(Surface* surface); struct BorderDrawInfo { Surface* anatomicalSurface; Surface* surface; TopologyHelper* topologyHelper; Border* border; int32_t borderFileIndex; int32_t borderIndex; float rgba[4]; bool isSelect; bool isContralateralEnabled; bool isHighlightEndPoints; float unstretchedLinesLength; }; void drawBorder(const BorderDrawInfo& borderDrawInfo); bool unstretchedBorderLineTest(const float p1[3], const float p2[3], const float anat1[3], const float anat2[3], const float unstretchedLinesFactor) const; void drawSurfaceFoci(Surface* surface); void drawSurfaceNormalVectors(const Surface* surface); void drawSurfaceFiberOrientations(const StructureEnum::Enum structure); void drawFiberOrientations(const Plane* plane, const StructureEnum::Enum structure); void addFiberOrientationForDrawing(const FiberOrientationDisplayInfo* fodi, const FiberOrientation* fiberOrientation); void sortFiberOrientationsByDepth(); void drawAllFiberOrientations(const FiberOrientationDisplayInfo* fodi, const bool isSortFibers); void drawSurfaceFiberTrajectories(const StructureEnum::Enum structure); void drawFiberTrajectories(const Plane* plane, const StructureEnum::Enum structure); void drawVolumeModel(BrowserTabContent* browserTabContent, ModelVolume* volumeModel, const int32_t viewport[4]); void drawVolumeAxesCrosshairs( const VolumeSliceViewPlaneEnum::Enum slicePlane, const float voxelXYZ[3]); void drawVolumeAxesLabels(const VolumeSliceViewPlaneEnum::Enum slicePlane, const int32_t viewport[4]); void drawVolumeVoxelsAsCubesWholeBrain(std::vector& volumeDrawInfoIn); void drawVolumeOrthogonalSliceWholeBrain(const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, std::vector& volumeDrawInfoIn); void drawVolumeOrthogonalSliceVolumeViewer(const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, std::vector& volumeDrawInfo); void drawVolumeSurfaceOutlines(Brain* brain, Model* modelDisplayModel, BrowserTabContent* browserTabContent, const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, VolumeMappableInterface* underlayVolume); void drawVolumeFoci(Brain* brain, ModelVolume* modelVolume, BrowserTabContent* browserTabContent, const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, VolumeMappableInterface* underlayVolume); void drawVolumeFibers(Brain* brain, ModelVolume* modelVolume, BrowserTabContent* browserTabContent, const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, VolumeMappableInterface* underlayVolume); void setupVolumeDrawInfo(BrowserTabContent* browserTabContent, Brain* brain, std::vector& volumeDrawInfoOut); void drawWholeBrainModel(BrowserTabContent* browserTabContent, ModelWholeBrain* wholeBrainModel, const int32_t viewport[4]); void drawSurfaceMontageModel(BrowserTabContent* browserTabContent, ModelSurfaceMontage* surfaceMontageModel, const int32_t viewport[4]); void setOrthographicProjection(const int32_t viewport[4], const ProjectionViewTypeEnum::Enum projectionType); void setOrthographicProjectionForWithBoundingBox(const int32_t viewport[4], const ProjectionViewTypeEnum::Enum projectionType, const BoundingBox* boundingBox); void setOrthographicProjectionWithHeight(const int32_t viewport[4], const ProjectionViewTypeEnum::Enum projectionType, const float halfWindowHeight); void setOrthographicProjectionWithWidth(const int32_t viewport[4], const ProjectionViewTypeEnum::Enum projectionType, const float halfWindowWidgth); void checkForOpenGLError(const Model* modelModel, const AString& msg); void enableLighting(); void disableLighting(); void enableLineAntiAliasing(); void disableLineAntiAliasing(); bool getPixelDepthAndRGBA(const int32_t pixelX, const int32_t pixelY, float& depthOut, float rgbaOut[4]); void getIndexFromColorSelection(const SelectionItemDataTypeEnum::Enum dataType, const int32_t x, const int32_t y, int32_t& indexOut, float& depthOut); void getIndexFromColorSelection(const SelectionItemDataTypeEnum::Enum dataType, const int32_t x, const int32_t y, int32_t& index1Out, int32_t& index2Out, float& depthOut); void getIndexFromColorSelection(const SelectionItemDataTypeEnum::Enum dataType, const int32_t x, const int32_t y, int32_t& index1Out, int32_t& index2Out, int32_t& index3Out, float& depthOut); void setSelectedItemScreenXYZ(SelectionItem* item, const float itemXYZ[3]); void setViewportAndOrthographicProjection(const int32_t viewport[4], const ProjectionViewTypeEnum::Enum projectionType); void setViewportAndOrthographicProjectionForWholeBrainVolume(const int32_t viewport[4], const ProjectionViewTypeEnum::Enum projectionType, const VolumeMappableInterface* volume); void setViewportAndOrthographicProjectionForSurfaceFile(const int32_t viewport[4], const ProjectionViewTypeEnum::Enum projectionType, const SurfaceFile* surfaceFile); void applyViewingTransformations(const Model* model, const float objectCenterXYZ[3], const ProjectionViewTypeEnum::Enum projectionViewType); void applyViewingTransformationsVolumeSlice(const ModelVolume* modelVolume, const int32_t tabIndex, const VolumeSliceViewPlaneEnum::Enum viewPlane); void drawSurfaceAxes(); void drawSphereWithDiameter(const uint8_t rgba[4], const double diameter); void drawSphereWithDiameter(const float rgba[4], const double diameter); void drawSquare(const float rgba[4], const float size); void drawSquare(const uint8_t rgba[4], const float size); void drawCube(const float rgba[4], const double cubeSize); void drawCuboid(const uint8_t rgba[4], const double sizeX, const double sizeY, const double sizeZ); void drawRoundedCube(const float rgba[4], const double cubeSize); void drawRoundedCuboid(const uint8_t rgba[4], const double sizeX, const double sizeY, const double sizeZ); void drawCylinder(const float rgba[4], const float bottomXYZ[3], const float topXYZ[3], const float radius); void drawEllipticalCone(const float rgba[4], const float baseXYZ[3], const float apexXYZ[3], const float baseRadiusScaling, const float baseMajorAngle, const float baseMinorAngle, const float baseRotationAngle, const bool backwardsFlag); void drawTextAtViewportCoords(const double viewportX, const double viewportY, const AnnotationText& annotationText); void drawTextAtModelCoords(const double modelX, const double modelY, const double modelZ, const AnnotationText& annotationText); void drawTextAtModelCoords(const double modelXYZ[3], const AnnotationText& annotationText); void drawTextAtModelCoords(const float modelXYZ[3], const AnnotationText& annotationText); void drawWindowAnnotations(const int windowViewport[4]); void drawSpacerAnnotations(const BrainOpenGLViewportContent* tabContent); void drawTabAnnotations(const BrainOpenGLViewportContent* tabContent); void drawChartCoordinateSpaceAnnotations(const BrainOpenGLViewportContent* viewportContent); void drawBackgroundImage(const BrainOpenGLViewportContent* vpContent); void drawImage(const BrainOpenGLViewportContent* vpContent, ImageFile* imageFile, const float windowZ, const float frontZ, const float minimumThreshold, const float maximumThreshold, const float opacity, const bool drawControlPointsFlag); void setProjectionModeData(const float screenDepth, const float xyz[3], const StructureEnum::Enum structure, const float barycentricAreas[3], const int barycentricNodes[3], const int numberOfNodes); enum ClippingDataType { CLIPPING_DATA_TYPE_FEATURES, CLIPPING_DATA_TYPE_SURFACE, CLIPPING_DATA_TYPE_VOLUME }; void applyClippingPlanes(const ClippingDataType clippingDataType, const StructureEnum::Enum structureIn); void disableClippingPlanes(); bool isCoordinateInsideClippingPlanesForStructure(const StructureEnum::Enum structureIn, const float xyz[3]) const; bool isFeatureClippingEnabled() const; void getVolumeFitToWindowScalingAndTranslation(const VolumeMappableInterface* volume, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const double orthographicExtent[6], float translationOut[3], float& scalingOut) const; Plane getPlaneForVolumeSliceIndex(const VolumeMappableInterface* volumeMappable, const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex) const; void updateForegroundAndBackgroundColors(const BrainOpenGLViewportContent* vpContent); void setTabViewport(const BrainOpenGLViewportContent* vpContent); void setAnnotationColorBarsForDrawing(const std::vector& viewportContents); void drawTabHighlighting(const float width, const float height, const float rgb[3]); void applyVolumePropertiesOpacity(); /** Index of window */ int32_t m_windowIndex = -1; /** User input mode for window */ UserInputModeEnum::Enum m_windowUserInputMode; /** Indicates OpenGL has been initialized */ bool initializedOpenGLFlag; /** Content of browser tab being drawn */ BrowserTabContent* browserTabContent; /** Source brain of content being drawn DOES NOT get deleted! */ Brain* m_brain; /** Index of window tab */ int32_t windowTabIndex; /** mode of operation draw/select/etc*/ Mode mode; /** Identification manager */ SelectionManager* selectionManager; int32_t mouseX; int32_t mouseY; /** Viewport for tab content that is being drawn */ int m_tabViewport[4]; /** Clipping plane group active in browser tab */ ClippingPlaneGroup* m_clippingPlaneGroup; /** * When mirrored clipping is enabled, the clipping region is * 'mirror flipped' for right structures and clipping performed * separately for left and right structures. Otherwise, one * clipping is used for all data. * * Model Enabled * ----- ------- * All NO * Montage YES * Surface YES * Volume NO */ bool m_mirroredClippingEnabled; /** Identify using color */ IdentificationWithColor* colorIdentification; SurfaceProjectedItem* modeProjectionData; /** Screen depth when projecting to surface mode */ double modeProjectionScreenDepth; /** Performs node coloring */ SurfaceNodeColoring* surfaceNodeColoring; /** Tile tabs active */ bool m_tileTabsActiveFlag; /** Sphere symbol */ BrainOpenGLShapeSphere* m_shapeSphere; /** Cone symbol */ BrainOpenGLShapeCone* m_shapeCone; /** Cube symbol */ BrainOpenGLShapeCube* m_shapeCube; /** Rounded Cube symbol */ BrainOpenGLShapeCube* m_shapeCubeRounded; /** Cylinder symbol */ BrainOpenGLShapeCylinder* m_shapeCylinder; std::list m_fiberOrientationsForDrawing; double inverseRotationMatrix[16]; bool inverseRotationMatrixValid; double orthographicLeft; double orthographicRight; double orthographicBottom; double orthographicTop; double orthographicFar; double orthographicNear; CaretPointer m_annotationDrawing; std::vector m_annotationColorBarsForDrawing; /** Some graphics using annotations for some elements so user can select and edit them */ std::vector m_specialCaseGraphicsAnnotations; static bool s_staticInitialized; static const float s_gluLookAtCenterFromEyeOffsetDistance; static float COLOR_RED[3]; static float COLOR_GREEN[3]; static float COLOR_BLUE[3]; friend class BrainOpenGLAnnotationDrawingFixedPipeline; friend class BrainOpenGLChartDrawingFixedPipeline; friend class BrainOpenGLChartTwoDrawingFixedPipeline; friend class BrainOpenGLVolumeObliqueSliceDrawing; friend class BrainOpenGLVolumeSliceDrawing; friend class BrainOpenGLVolumeTextureSliceDrawing; }; #ifdef __BRAIN_OPENGL_FIXED_PIPELINE_DEFINE_H bool BrainOpenGLFixedPipeline::s_staticInitialized = false; float BrainOpenGLFixedPipeline::COLOR_RED[3] = { 1.0, 0.0, 0.0 }; float BrainOpenGLFixedPipeline::COLOR_GREEN[3] = { 0.0, 1.0, 0.0 }; float BrainOpenGLFixedPipeline::COLOR_BLUE[3] = { 0.0, 0.0, 1.0 }; const float BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance = 1.0; #endif //__BRAIN_OPENGL_FIXED_PIPELINE_DEFINE_H } // namespace #endif // __BRAIN_OPENGL_FIXED_PIPELINE_H__ connectome-workbench-1.4.2/src/Brain/BrainOpenGLPrimitiveDrawing.cxx000066400000000000000000000431001360521144700255040ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BRAIN_OPEN_G_L_PRIMITIVE_DRAWING_DECLARE__ #include "BrainOpenGLPrimitiveDrawing.h" #undef __BRAIN_OPEN_G_L_PRIMITIVE_DRAWING_DECLARE__ #include "AString.h" #include "BrainOpenGL.h" #include "CaretOpenGLInclude.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "MathFunctions.h" using namespace caret; /** * \class caret::BrainOpenGLPrimitiveDrawing * \brief Draws OpenGL Primitives (Triangles, Quads, etc.) * \ingroup Brain * * As OpenGL has evolved, functionality for drawing primitives (triangles, quads, * etc.) has been added. Users of this class only need to provide the * vertices, colors, normal vectors, and type of primitive for drawing. This * class will use the OpenGL primitive drawing most appropriate for the * OpenGL capabilities available at runtime. * * All public methods are static methods. */ /** * Constructor. */ BrainOpenGLPrimitiveDrawing::BrainOpenGLPrimitiveDrawing() { } /** * Destructor. */ BrainOpenGLPrimitiveDrawing::~BrainOpenGLPrimitiveDrawing() { } /** * Draw quads. * * @param coordinates * Coordinates of the quads. * @param normals * Normal vectors for the quads. * @param rgbaColors * RGBA colors for the quads. */ void BrainOpenGLPrimitiveDrawing::drawQuads(const std::vector& coordinates, const std::vector& normals, const std::vector& rgbaColors) { std::vector rgbaBytes; for (std::vector::const_iterator iter = rgbaColors.begin(); iter != rgbaColors.end(); iter++) { rgbaBytes.push_back(static_cast(*iter * 255.0)); } drawQuads(coordinates, normals, rgbaBytes); } /** * Draw quads. * * @param coordinates * Coordinates of the quads. * @param normals * Normal vectors for the quads. * @param rgbaColors * RGBA colors for the quads. */ void BrainOpenGLPrimitiveDrawing::drawQuads(const std::vector& coordinates, const std::vector& normals, const std::vector& rgbaColors) { const uint64_t numCoords = coordinates.size() / 3; const uint64_t numNormals = normals.size() / 3; const uint64_t numColors = rgbaColors.size() / 4; const uint64_t numQuads = numCoords / 4; // 4 three-d coords per quad if (numQuads <= 0) { return; } if (numNormals != numCoords) { const AString message = ("Size of normals must equal size of coordinates. " "Coordinate size: " + AString::number(coordinates.size()) + " Normals size: " + AString::number(normals.size())); CaretLogSevere(message); CaretAssertMessage(0, message); return; } if (numColors != numCoords) { const AString message = ("Size of RGBA colors must be 4/3 size of coordinates. " "Coordinate size: " + AString::number(coordinates.size()) + " RGBA size: " + AString::number(rgbaColors.size())); CaretLogSevere(message); CaretAssertMessage(0, message); return; } /* * Use the number of voxels in a 300 x 300 slice as * as the most maximum number of voxels to draw in * in one call to OpenGL drawing. */ const int64_t maximumCoordinatesToDraw = 300 * 300 * 4; CaretAssert(maximumCoordinatesToDraw == ((maximumCoordinatesToDraw / 4) * 4)); //std::cout << "Max vertices to draw: " << maximumCoordinatesToDraw << std::endl; int64_t coordinateOffset = 0; bool done = false; while ( ! done) { const int64_t coordinateToDrawCount = std::min(int64_t(numCoords - coordinateOffset), maximumCoordinatesToDraw); if (coordinateToDrawCount > 0) { //std::cout << "Drawing offset " << coordinateOffset << " count " << coordinateToDrawCount << std::endl; bool wasDrawnWithVertexBuffers = false; #ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS if (BrainOpenGL::getBestDrawingMode() == BrainOpenGL::DRAW_MODE_VERTEX_BUFFERS) { CaretAssertMessage(0, "See John Harwell"); drawQuadsVertexBuffers(coordinates, normals, rgbaColors, coordinateOffset, coordinateToDrawCount); wasDrawnWithVertexBuffers = true; } #endif // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS if ( ! wasDrawnWithVertexBuffers) { drawQuadsVertexArrays(coordinates, normals, rgbaColors, coordinateOffset, coordinateToDrawCount); } coordinateOffset += maximumCoordinatesToDraw; } else { done = true; } } } /** * Draw quads using vertex arrays. * * @param coordinates * Coordinates of the quads. * @param normals * Normal vectors for the quads. * @param rgbaColors * RGBA colors for the quads. */ void BrainOpenGLPrimitiveDrawing::drawQuadsVertexArrays(const std::vector& coordinates, const std::vector& normals, const std::vector& rgbaColors, const int64_t coordinateOffset, const int64_t coordinateCount) { glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3, GL_FLOAT, 0, reinterpret_cast(&coordinates[0])); glColorPointer(4, GL_UNSIGNED_BYTE, 0, reinterpret_cast(&rgbaColors[0])); glNormalPointer(GL_FLOAT, 0, reinterpret_cast(&normals[0])); // const int64_t maxVertices = 1000; // const int64_t numQuads = maxVertices / 4; // CaretAssert(maxVertices == (numQuads * 4)); // if (numCoords > maxVertices) { // std::cout << "Max vertices: " << maxVertices << std::endl; // int64_t offset = 0; // bool done = false; // while ( ! done) { // const int64_t count = std::min(int64_t(numCoords - offset), // maxVertices); // if (count > 0) { // std::cout << "Drawing offset " << offset << " count " << count << std::endl; // glDrawArrays(GL_QUADS, // offset, // count); // offset += maxVertices; // } // else { // done = true; // } // } // } // else { // glDrawArrays(GL_QUADS, // 0, // numCoords); // } glDrawArrays(GL_QUADS, coordinateOffset, coordinateCount); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); } /** * Draw quads using vertex buffers. * * @param coordinates * Coordinates of the quads. * @param normals * Normal vectors for the quads. * @param rgbaColors * RGBA colors for the quads. */ void BrainOpenGLPrimitiveDrawing::drawQuadsVertexBuffers(const std::vector& coordinates, const std::vector& normals, const std::vector& rgbaColors, const int64_t coordinateOffset, const int64_t coordinateCount) { #ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS /* * Put vertices (coordinates) into its buffer. */ GLuint vertexBufferID = -1; glGenBuffers(1, &vertexBufferID); glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); glBufferData(GL_ARRAY_BUFFER, coordinates.size() * sizeof(GLfloat), &coordinates[0], GL_STREAM_DRAW); /* * Put normals into its buffer. */ GLuint normalBufferID = -1; glGenBuffers(1, &normalBufferID); glBindBuffer(GL_ARRAY_BUFFER, normalBufferID); glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(GLfloat), &normals[0], GL_STREAM_DRAW); /* * Put colors into its buffer. */ GLuint colorBufferID = -1; glGenBuffers(1, &colorBufferID); glBindBuffer(GL_ARRAY_BUFFER, colorBufferID); glBufferData(GL_ARRAY_BUFFER, rgbaColors.size() * sizeof(uint8_t), &rgbaColors[0], GL_STREAM_DRAW); // /* // * Put triangle strips into its buffer. // */ // GLuint quadsBufferID = -1; // glGenBuffers(1, &quadsBufferID); // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, // quadsBufferID); // glBufferData(GL_ELEMENT_ARRAY_BUFFER, // quads.size() * sizeof(GLuint), // &quads[0], // GL_STREAM_DRAW); /* * Deselect active buffer. */ glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); /* * Set the vertices for drawing. */ glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)0); /* * Set the normal vectors for drawing. */ glBindBuffer(GL_ARRAY_BUFFER, normalBufferID); glNormalPointer(GL_FLOAT, 0, (GLvoid*)0); /* * Set the rgba colors for drawing */ glBindBuffer(GL_ARRAY_BUFFER, colorBufferID); glColorPointer(4, GL_UNSIGNED_BYTE, 0, (GLvoid*)0); /* * Draw the triangle strips. */ glDrawArrays(GL_QUADS, coordinateOffset, coordinateCount); // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, // quadsBufferID); // glDrawElements(GL_TRIANGLE_STRIP, // quads.size(), // GL_UNSIGNED_INT, // (GLvoid*)0); /* * Deselect active buffer. */ glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDeleteBuffers(1, &vertexBufferID); glDeleteBuffers(1, &normalBufferID); glDeleteBuffers(1, &colorBufferID); #endif // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS } /** * Draw quads strips * * @param coordinates * Coordinates of the quads. * @param normals * Normal vectors for the quads. * @param rgbaColors * RGBA colors for the quads. * @param quadStripIndices * Indices into the quad strip coordinates. */ void BrainOpenGLPrimitiveDrawing::drawQuadStrips(const std::vector& coordinates, const std::vector& normals, const std::vector& rgbaColors, const std::vector& quadStripIndices) { drawQuadStripsVertexArrays(coordinates, normals, rgbaColors, quadStripIndices); } /** * Draw quads strips * * @param coordinates * Coordinates of the quads. * @param normals * Normal vectors for the quads. * @param rgbaColors * RGBA colors for the quads. * @param quadStripIndices * Indices into the quad strip coordinates. */ void BrainOpenGLPrimitiveDrawing::drawQuadStripsVertexArrays(const std::vector& coordinates, const std::vector& normals, const std::vector& rgbaColors, const std::vector& quadStripIndices) { if (quadStripIndices.empty()) { return; } glVertexPointer(3, GL_FLOAT, 0, reinterpret_cast(&coordinates[0])); glColorPointer(4, GL_UNSIGNED_BYTE, 0, reinterpret_cast(&rgbaColors[0])); glNormalPointer(GL_FLOAT, 0, reinterpret_cast(&normals[0])); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glDrawElements(GL_QUAD_STRIP, quadStripIndices.size(), GL_UNSIGNED_INT, &quadStripIndices[0]); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); } /** * Draw quad with indices * * @param coordinates * Coordinates of the quads. * @param normals * Normal vectors for the quads. * @param rgbaColors * RGBA colors for the quads. * @param quadIndices * Indices of the quads (4 per quad). */ void BrainOpenGLPrimitiveDrawing::drawQuadIndices(const std::vector& coordinates, const std::vector& normals, const std::vector& rgbaColors, const std::vector& quadIndices) { drawQuadIndicesVertexArrays(coordinates, normals, rgbaColors, quadIndices); } /** * Draw quad with indices * * @param coordinates * Coordinates of the quads. * @param normals * Normal vectors for the quads. * @param rgbaColors * RGBA colors for the quads. * @param quadIndices * Indices of the quads (4 per quad). */ void BrainOpenGLPrimitiveDrawing::drawQuadIndicesVertexArrays(const std::vector& coordinates, const std::vector& normals, const std::vector& rgbaColors, const std::vector& quadIndices) { const int64_t numQuadIndices = static_cast(quadIndices.size()); if (numQuadIndices <= 0) { return; } glVertexPointer(3, GL_FLOAT, 0, reinterpret_cast(&coordinates[0])); glColorPointer(4, GL_UNSIGNED_BYTE, 0, reinterpret_cast(&rgbaColors[0])); glNormalPointer(GL_FLOAT, 0, reinterpret_cast(&normals[0])); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glDrawElements(GL_QUADS, quadIndices.size(), GL_UNSIGNED_INT, &quadIndices[0]); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); } connectome-workbench-1.4.2/src/Brain/BrainOpenGLPrimitiveDrawing.h000066400000000000000000000105511360521144700251350ustar00rootroot00000000000000#ifndef __BRAIN_OPEN_G_L_PRIMITIVE_DRAWING_H__ #define __BRAIN_OPEN_G_L_PRIMITIVE_DRAWING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "stdint.h" #include #include "BrainOpenGL.h" namespace caret { class BrainOpenGLPrimitiveDrawing { public: static void drawQuads(const std::vector& coordinates, const std::vector& normals, const std::vector& rgbaColors); static void drawQuads(const std::vector& coordinates, const std::vector& normals, const std::vector& rgbaColors); static void drawQuadIndices(const std::vector& coordinates, const std::vector& normals, const std::vector& rgbaColors, const std::vector& quadIndices); static void drawQuadStrips(const std::vector& coordinates, const std::vector& normals, const std::vector& rgbaColors, const std::vector& quadStripIndices); private: BrainOpenGLPrimitiveDrawing(); ~BrainOpenGLPrimitiveDrawing(); BrainOpenGLPrimitiveDrawing(const BrainOpenGLPrimitiveDrawing&); BrainOpenGLPrimitiveDrawing& operator=(const BrainOpenGLPrimitiveDrawing&); static void drawQuadsImmediateMode(const std::vector& coordinates, const std::vector& normals, const std::vector& rgbaColors, const int64_t coordinateOffset, const int64_t coordinateCount); static void drawQuadsVertexArrays(const std::vector& coordinates, const std::vector& normals, const std::vector& rgbaColors, const int64_t coordinateOffset, const int64_t coordinateCount); static void drawQuadStripsVertexArrays(const std::vector& coordinates, const std::vector& normals, const std::vector& rgbaColors, const std::vector& quadStripIndices); static void drawQuadsVertexBuffers(const std::vector& coordinates, const std::vector& normals, const std::vector& rgbaColors, const int64_t coordinateOffset, const int64_t coordinateCount); static void drawQuadIndicesVertexArrays(const std::vector& coordinates, const std::vector& normals, const std::vector& rgbaColors, const std::vector& quadIndices); }; #ifdef __BRAIN_OPEN_G_L_PRIMITIVE_DRAWING_DECLARE__ // #endif // __BRAIN_OPEN_G_L_PRIMITIVE_DRAWING_DECLARE__ } // namespace #endif //__BRAIN_OPEN_G_L_PRIMITIVE_DRAWING_H__ connectome-workbench-1.4.2/src/Brain/BrainOpenGLShape.cxx000066400000000000000000000416201360521144700232650ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BRAIN_OPEN_GL_SHAPE_DECLARE__ #include "BrainOpenGLShape.h" #undef __BRAIN_OPEN_GL_SHAPE_DECLARE__ #include "BrainOpenGL.h" #include "CaretAssert.h" #include "CaretLogger.h" using namespace caret; /** * \class caret::BrainOpenGLShape * \brief Abstract class for shapes drawn in OpenGL. * * Subclasses should allocate the */ /** * Constructor. */ BrainOpenGLShape::BrainOpenGLShape() : CaretObject() { m_drawMode = BrainOpenGL::DRAW_MODE_INVALID; m_shapeSetupComplete = false; } /** * Destructor. */ BrainOpenGLShape::~BrainOpenGLShape() { releaseOpenGLAllocations(); } void BrainOpenGLShape::releaseOpenGLAllocations() { /* * Since 'releaseBufferIDInternal()' will alter 'm_bufferIDs' * make a copy of the set. Otherwise, the iterator will get * corrupted and a crash will occur. */ std::set bufferIDCopy = m_bufferIDs; for (std::set::iterator iter = bufferIDCopy.begin(); iter != bufferIDCopy.end(); iter++) { releaseBufferIDInternal(*iter); } m_bufferIDs.clear(); /* * Since 'releaseDisplayListInternal()' will alter 'm_displayLists' * make a copy of the set. Otherwise, the iterator will get * corrupted and a crash will occur. */ std::set displayListsCopy = m_displayLists; for (std::set::iterator iter = displayListsCopy.begin(); iter != displayListsCopy.end(); iter++) { releaseDisplayListInternal(*iter); } m_displayLists.clear(); } /** * Force drawing mode to immediate mode since display lists * do not work during image capture. * @param override * If true, immediate mode is always used until reset by * calling this with false. */ void BrainOpenGLShape::setImmediateModeOverride(const bool override) { s_immediateModeOverride = override; } /** * Draw the shape. * * @param rgba * Color for shape. */ void BrainOpenGLShape::draw(const uint8_t rgba[4]) { createShapeIfNeeded(); if (s_immediateModeOverride) { drawShape(BrainOpenGL::DRAW_MODE_IMMEDIATE, rgba); } else { drawShape(m_drawMode, rgba); } } /** * Create the shape or recreate it if drawing mode changed. */ void BrainOpenGLShape::createShapeIfNeeded() { if (m_drawMode == BrainOpenGL::DRAW_MODE_INVALID) { m_shapeSetupComplete = false; } if (m_drawMode != BrainOpenGL::getBestDrawingMode()) { m_shapeSetupComplete = false; } if (m_shapeSetupComplete == false) { releaseOpenGLAllocations(); m_drawMode = BrainOpenGL::getBestDrawingMode(); setupOpenGLForShape(m_drawMode); m_shapeSetupComplete = true; } } /** * Draw the shape. * * @param rgba * Color for shape. */ void BrainOpenGLShape::draw(const float rgba[4]) { createShapeIfNeeded(); if (s_immediateModeOverride) { drawShape(BrainOpenGL::DRAW_MODE_IMMEDIATE, rgba); } else { drawShape(m_drawMode, rgba); } } /** * @return A new buffer ID for use with OpenGL. * A return value of zero indicates that creation of buffer ID failed. * Values greater than zero are valid buffer IDs. */ GLuint BrainOpenGLShape::createBufferID() { GLuint id = 0; #ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS glGenBuffers(1, &id); if (id > 0) { m_bufferIDs.insert(id); } else { CaretLogSevere("Failed to create a new OpenGL Vertex Buffer"); } #else // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS CaretLogSevere("PROGRAM ERROR: Creating OpenGL vertex buffer but vertex buffers not supported."); #endif // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS return id; } /** * Release an allocated buffer ID. * * @param bufferID * Buffer ID that was previously returned by createBufferID(). */ void BrainOpenGLShape::releaseBufferID(const GLuint bufferID) { releaseBufferIDInternal(bufferID); } /** * Release an allocated buffer ID. * * @param bufferID * Buffer ID that was previously returned by createBufferID(). */ void BrainOpenGLShape::releaseBufferIDInternal(const GLuint bufferID) { #ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS if (glIsBuffer(bufferID)) { glDeleteBuffers(1, &bufferID); m_bufferIDs.erase(bufferID); } else { CaretLogSevere("PROGRAM ERROR: Attempting to delete invalid OpenGL BufferID=" + AString::number(bufferID)); } #else // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS CaretLogSevere("PROGRAM ERROR: Releasing OpenGL vertex buffer #" + AString::number(bufferID) + " but vertex buffers not supported."); #endif // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS } /** * Release an allocated buffer ID. * * @param bufferID * Buffer ID that was previously returned by createBufferID(). * @param isRemoveFromTrackedIDs * If true, remove the ID from the bufferID that are tracked * by this object. */ void BrainOpenGLShape::releaseDisplayListInternal(const GLuint displayList) { #ifdef BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS if (BrainOpenGL::isDisplayListsSupported()) { if (glIsList(displayList)) { glDeleteLists(displayList, 1); m_displayLists.erase(displayList); } else { CaretLogSevere("PROGRAM ERROR: Attempting to delete invalid OpenGL DisplayList=" + AString::number(displayList)); } } #else // BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS CaretLogSevere("PROGRAM ERROR: Releasing OpenGL display list #" + AString::number(displayList) + " but display lists not supported."); #endif // BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS } /** * @return A new display list for use with OpenGL. * A return value of zero indicates that creation of display list failed. * Values greater than zero are valid display list. */ GLuint BrainOpenGLShape::createDisplayList() { GLuint displayList = 0; #ifdef BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS if (BrainOpenGL::isDisplayListsSupported()) { displayList = glGenLists(1); if (displayList > 0) { m_displayLists.insert(displayList); } else { CaretLogSevere("Failed to create a new OpenGL Display List"); } } #else // BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS CaretLogSevere("PROGRAM ERROR: Creating OpenGL display list but display lists not supported."); #endif // BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS return displayList; } /** * Release an allocated display list. * * @param displayList * Display list that was previously returned by createDisplayList(). */ void BrainOpenGLShape::releaseDisplayList(const GLuint displayList) { releaseDisplayListInternal(displayList); } /** * Convert a series of discontinuous triangle strips into one triangle strip. * Between each of the original triangle strips, additional vertices forming * degenerate (arealess) triangles are added. This triangles are not drawn * by OpenGl. * * @see http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/concatenating-triangle-strips-r1871 * @see http://en.wikipedia.org/wiki/Triangle_strip * * @param vertices * The indices to all of the vertices in the input triangle strips. * @param stripStartIndices * A vector containing the starting index of the strip in 'vertices'. * @param stripEndIndices * A vector containing the ending index of the strip in 'vertices'. * @param triangleStripVerticesOut * OUTPUT - A vector containing all of the vertex indices for drawing * all of the input triangles with one triangle strip. */ void BrainOpenGLShape::contatenateTriangleStrips(const std::vector& vertices, const std::vector& stripStartIndices, const std::vector& stripEndIndices, std::vector& triangleStripVerticesOut) const { triangleStripVerticesOut.clear(); CaretAssert(stripStartIndices.size() == stripEndIndices.size()); const int32_t numberOfStrips = static_cast(stripStartIndices.size()); for (int32_t i = 0; i < numberOfStrips; i++) { const int32_t numInStrip = (stripEndIndices[i] - stripStartIndices[i]); if (numInStrip < 2) { continue; } const int32_t startIndex = stripStartIndices[i]; CaretAssertVectorIndex(vertices, startIndex); //const int32_t endIndex = stripEndIndices[i]; //CaretAssertVectorIndex(vertices, endIndex); if (i > 0) { /* * N1 is index of first vertex in the strip * N2 is index of second vertex in the strip */ const GLuint n1 = vertices[startIndex]; CaretAssertVectorIndex(vertices, startIndex+1); const GLuint n2 = vertices[startIndex + 1]; const GLuint prevEndIndex = stripEndIndices[i-1]; const int32_t numInPrevStrip = (prevEndIndex - stripStartIndices[i-1]); if (numInPrevStrip >= 2) { /* * P1 is index of last vertex in previous strip * P2 is index of second to last vertex in previous strip */ CaretAssertVectorIndex(vertices, ((int32_t)prevEndIndex) - 1); const GLuint p1 = vertices[prevEndIndex - 1]; CaretAssertVectorIndex(vertices, ((int32_t)prevEndIndex) - 2); const GLuint p2 = vertices[prevEndIndex - 2]; /* * Add degenerate triangles so that strips can be concatenated. */ triangleStripVerticesOut.push_back(p2); triangleStripVerticesOut.push_back(p1); triangleStripVerticesOut.push_back(p1); triangleStripVerticesOut.push_back(p1); triangleStripVerticesOut.push_back(p1); triangleStripVerticesOut.push_back(n1); triangleStripVerticesOut.push_back(p1); triangleStripVerticesOut.push_back(n1); triangleStripVerticesOut.push_back(n1); triangleStripVerticesOut.push_back(n1); triangleStripVerticesOut.push_back(n1); triangleStripVerticesOut.push_back(n2); triangleStripVerticesOut.push_back(n1); triangleStripVerticesOut.push_back(n2); triangleStripVerticesOut.push_back(n1); triangleStripVerticesOut.push_back(n1); triangleStripVerticesOut.push_back(n1); triangleStripVerticesOut.push_back(n2); } } const int32_t vertexStart = stripStartIndices[i]; const int32_t vertexEnd = stripEndIndices[i]; for (int32_t iVertex = vertexStart; iVertex < vertexEnd; iVertex++) { CaretAssertVectorIndex(vertices, iVertex); const int32_t vertexIndex = vertices[iVertex]; triangleStripVerticesOut.push_back(vertexIndex); } } } /** * Convert a series of discontinuous triangle strips into one triangle strip. * Between each of the original triangle strips, additional vertices forming * degenerate (arealess) triangles are added. This triangles are not drawn * by OpenGl. * * @see http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/concatenating-triangle-strips-r1871 * @see http://en.wikipedia.org/wiki/Triangle_strip * * @param triangleStrips * The triangle strips. Each contains a sequence of vertex indices. * @param triangleStripOut * OUTPUT - A vector containing all of the vertex indices for drawing * all of the input triangles with one triangle strip. */ void BrainOpenGLShape::contatenateTriangleStrips(const std::vector >& triangleStrips, std::vector& triangleStripOut) const { triangleStripOut.clear(); const int32_t numberOfStrips = static_cast(triangleStrips.size()); for (int32_t i = 0; i < numberOfStrips; i++) { const std::vector& strip = triangleStrips[i]; const int32_t numInStrip = static_cast(strip.size()); if (numInStrip < 2) { continue; } if (i > 0) { /* * N1 is index of first vertex in the strip * N2 is index of second vertex in the strip */ CaretAssertVectorIndex(strip, 0); const GLuint n1 = strip[0]; CaretAssertVectorIndex(strip, 1); const GLuint n2 = strip[1]; const std::vector& prevStrip = triangleStrips[i - 1]; const int32_t numInPrevStrip = static_cast(prevStrip.size()); if (numInPrevStrip >= 2) { /* * P1 is index of last vertex in previous strip * P2 is index of second to last vertex in previous strip */ CaretAssertVectorIndex(prevStrip, numInPrevStrip - 1); const GLuint p1 = prevStrip[numInPrevStrip - 1]; CaretAssertVectorIndex(prevStrip, numInPrevStrip - 2); const GLuint p2 = prevStrip[numInPrevStrip - 2]; /* * Add degenerate triangles so that strips can be concatenated. */ triangleStripOut.push_back(p2); triangleStripOut.push_back(p1); triangleStripOut.push_back(p1); triangleStripOut.push_back(p1); triangleStripOut.push_back(p1); triangleStripOut.push_back(n1); triangleStripOut.push_back(p1); triangleStripOut.push_back(n1); triangleStripOut.push_back(n1); triangleStripOut.push_back(n1); triangleStripOut.push_back(n1); triangleStripOut.push_back(n2); triangleStripOut.push_back(n1); triangleStripOut.push_back(n2); triangleStripOut.push_back(n1); triangleStripOut.push_back(n1); triangleStripOut.push_back(n1); triangleStripOut.push_back(n2); } } for (int32_t j = 0; j < numInStrip; j++) { triangleStripOut.push_back(strip[j]); } } } /** * Print the vertices in a triangle strip. Each triplet is contained * within a set of parenthesis. * * @param triangleStrip * Triangle strip that is printed. */ void BrainOpenGLShape::printTriangleStrip(const std::vector& triangleStrip) const { int i3 = 0; for (std::vector::const_iterator iter = triangleStrip.begin(); iter != triangleStrip.end(); iter++) { if (i3 == 0) { std::cout << " ("; } else { std::cout << ","; } std::cout << *iter; if (i3 == 2) { std::cout << ")"; i3 = 0; } else { i3++; } } std::cout << std::endl << std::endl; } /** * Print the vertices in a triangle fan * * @param triangleFan * Triangle fan that is printed. */ void BrainOpenGLShape::printTriangleFan(const std::vector& triangleFan) const { const int32_t numVertices = static_cast(triangleFan.size()); for (int32_t i = 0; i < numVertices; i++) { const GLuint vertexIndex = triangleFan[i]; if (i == 0) { std::cout << "Center ("; } else if (i > 1) { std::cout << ", "; } std::cout << vertexIndex; if (i == 0) { std::cout << ") Perimeter ("; } } if (numVertices > 1) { std::cout << ")"; } std::cout << std::endl << std::endl; } connectome-workbench-1.4.2/src/Brain/BrainOpenGLShape.h000066400000000000000000000103701360521144700227100ustar00rootroot00000000000000#ifndef __BRAIN_OPEN_GL_SHAPE__H_ #define __BRAIN_OPEN_GL_SHAPE__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "BrainOpenGL.h" namespace caret { class BrainOpenGLShape : public CaretObject { public: BrainOpenGLShape(); virtual ~BrainOpenGLShape(); // ADD_NEW_METHODS_HERE void draw(const uint8_t rgba[4]); void draw(const float rgba[4]); static void setImmediateModeOverride(const bool override); private: BrainOpenGLShape(const BrainOpenGLShape&); BrainOpenGLShape& operator=(const BrainOpenGLShape&); void releaseBufferIDInternal(const GLuint bufferID); void releaseDisplayListInternal(const GLuint displayList); protected: /** * Setup for drawing the shape with OpenGL. This may include * creating display lists, allocating buffers, and other calls * to the OpenGL API. The base class handles alllocation and * deallocation of OpenGL display lists and buffers. * * @param drawMode * How the shape will be drawn. */ virtual void setupOpenGLForShape(const BrainOpenGL::DrawMode drawMode) = 0; /** * Draw the shape using the given drawing mode. * * @param drawMode * How the shape will be drawn. * @param rgba * RGBA coloring ranging 0 to 255. */ virtual void drawShape(const BrainOpenGL::DrawMode drawMode, const uint8_t rgba[4]) = 0; /** * Draw the shape using the given drawing mode. * * @param drawMode * How the shape will be drawn. * @param rgba * RGBA coloring ranging 0.0 to 1.0. */ virtual void drawShape(const BrainOpenGL::DrawMode drawMode, const float rgba[4]) = 0; GLuint createBufferID(); void releaseBufferID(const GLuint bufferID); GLuint createDisplayList(); void releaseDisplayList(const GLuint displayList); void contatenateTriangleStrips(const std::vector& vertices, const std::vector& stripStartIndices, const std::vector& stripEndIndices, std::vector& triangleStripVerticesOut) const; void printTriangleStrip(const std::vector& triangleStrip) const; void printTriangleFan(const std::vector& triangleFan) const; void contatenateTriangleStrips(const std::vector >& triangleStrips, std::vector& triangleStripOut) const; private: void createShapeIfNeeded(); void releaseOpenGLAllocations(); // ADD_NEW_MEMBERS_HERE std::set m_bufferIDs; std::set m_displayLists; bool m_shapeSetupComplete; BrainOpenGL::DrawMode m_drawMode; static bool s_immediateModeOverride; }; #ifdef __BRAIN_OPEN_GL_SHAPE_DECLARE__ bool BrainOpenGLShape::s_immediateModeOverride = false; #endif // __BRAIN_OPEN_GL_SHAPE_DECLARE__ } // namespace #endif //__BRAIN_OPEN_GL_SHAPE__H_ connectome-workbench-1.4.2/src/Brain/BrainOpenGLShapeCone.cxx000066400000000000000000000441261360521144700240760ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __BRAIN_OPEN_GL_SHAPE_CONE_DECLARE__ #include "BrainOpenGLShapeCone.h" #undef __BRAIN_OPEN_GL_SHAPE_CONE_DECLARE__ #include "CaretAssert.h" #include "MathFunctions.h" using namespace caret; /** * \class caret::BrainOpenGLShapeCone * \brief Create a conical shape for use with OpenGL. */ /** * Constructor. * @param numberOfSides * Number of sides in the cone. */ BrainOpenGLShapeCone::BrainOpenGLShapeCone(const int32_t numberOfSides) : BrainOpenGLShape(), m_numberOfSides(numberOfSides) { m_isApplyColoring = true; bool debugFlag = false; /* * Add origin (apex) to points */ const int32_t apexIndex = static_cast(m_coordinates.size() / 3); const float origin[3] = { 0.0, 0.0, 0.0 }; m_coordinates.push_back(origin[0]); m_coordinates.push_back(origin[1]); m_coordinates.push_back(origin[2]); m_sideNormals.push_back(0.0); m_sideNormals.push_back(0.0); m_sideNormals.push_back(-1.0); m_capNormals.push_back(0.0); m_capNormals.push_back(0.0); m_capNormals.push_back(1.0); /* * Setup step size based upon number of points around circle */ // const int32_t numberOfPoints = 8; const float step = (2.0 * M_PI) / m_numberOfSides; /* * Generate points around circle */ const float radius = 0.5; const float z = 1.0; for (int32_t i = 0; i < m_numberOfSides; i++) { const float t = step * i; // const float x = majorRadius * std::cos(t); // const float y = minorRadius * std::sin(t); const float x = radius * std::cos(t); const float y = radius * std::sin(t); m_coordinates.push_back(x); m_coordinates.push_back(y); m_coordinates.push_back(z); m_sideNormals.push_back(0.0); m_sideNormals.push_back(0.0); m_sideNormals.push_back(1.0); m_capNormals.push_back(0.0); m_capNormals.push_back(0.0); m_capNormals.push_back(1.0); } /* * Add cap center */ const int32_t capCenterIndex = static_cast(m_coordinates.size() / 3); m_coordinates.push_back(origin[0]); m_coordinates.push_back(origin[1]); m_coordinates.push_back(origin[2]); m_sideNormals.push_back(0.0); m_sideNormals.push_back(0.0); m_sideNormals.push_back(1.0); m_capNormals.push_back(0.0); m_capNormals.push_back(0.0); m_capNormals.push_back(1.0); /* * Add normal vectors of triangles into normal vector summations * NOTE: Vertex at index zero is the apex */ for (int32_t i = 1; i <= m_numberOfSides; i++) { int32_t nextIndex = i + 1; if (nextIndex > m_numberOfSides) { nextIndex = 1; } /* * Normal of triangle */ const int32_t i3 = i * 3; const int32_t next3 = nextIndex * 3; float triangleNormal[3]; MathFunctions::normalVector(origin, &m_coordinates[i3], &m_coordinates[next3], triangleNormal); CaretAssertVectorIndex(m_sideNormals, i3+2); m_sideNormals[i3] += triangleNormal[0]; m_sideNormals[i3+1] += triangleNormal[1]; m_sideNormals[i3+2] += triangleNormal[2]; CaretAssertVectorIndex(m_sideNormals, next3+2); m_sideNormals[next3] += triangleNormal[0]; m_sideNormals[next3+1] += triangleNormal[1]; m_sideNormals[next3+2] += triangleNormal[2]; } /* * Finish creation of the normal vectors */ for (int32_t i = 1; i <= m_numberOfSides; i++) { const int32_t i3 = i * 3; CaretAssertVectorIndex(m_sideNormals, i3+2); m_sideNormals[i3] /= 2.0; // vertices are shared by two triangles m_sideNormals[i3+1] /= 2.0; m_sideNormals[i3+2] /= 2.0; MathFunctions::normalizeVector(&m_sideNormals[i3]); } /* * Generate vector list for triangles */ m_sidesTriangleFan.push_back(apexIndex); for (int32_t i = m_numberOfSides; i > 0; i--) { m_sidesTriangleFan.push_back(i); } m_sidesTriangleFan.push_back(m_numberOfSides); // closes m_capTriangleFan.push_back(capCenterIndex); for (int32_t i = 1; i <= m_numberOfSides; i++) { m_capTriangleFan.push_back(i); } m_capTriangleFan.push_back(1); if (debugFlag) { CaretAssert(m_coordinates.size() == m_sideNormals.size()); CaretAssert(m_coordinates.size() == m_capNormals.size()); const int32_t numPoints = static_cast(m_coordinates.size() / 3); for (int32_t i = 0; i < numPoints; i++) { const int32_t i3 = i * 3; CaretAssertVectorIndex(m_coordinates, i3+2); std::cout << "points[" << i << "]=(" << AString::fromNumbers(&m_coordinates[i3], 3, ",") << ")" << std::endl; CaretAssertVectorIndex(m_sideNormals, i3+2); std::cout << "side normal[" << i << "]=(" << AString::fromNumbers(&m_sideNormals[i3], 3, ",") << ")" << std::endl; CaretAssertVectorIndex(m_capNormals, i3+2); std::cout << "cap normal[" << i << "]=(" << AString::fromNumbers(&m_capNormals[i3], 3, ",") << ")" << std::endl; } std::cout << "Sides: "; printTriangleFan(m_sidesTriangleFan); std::cout << std::endl; std::cout << "Cap: "; printTriangleFan(m_capTriangleFan); std::cout << std::endl; } // /* // * End Cap // */ // glBegin(GL_POLYGON); // glNormal3f(0.0, 0.0, 1.0); // for (int32_t i = 0; i < m_numberOfSides; i++) { // const int32_t i3 = i * 3; // glVertex3fv(&m_coordinates[i3]); // } // glEnd(); /* * Create storage for colors */ const int64_t numCoords = static_cast(m_coordinates.size()) / 3; const int64_t numRGBA = numCoords * 4; m_rgbaByte.resize(numRGBA * 4, 0); for (GLuint i = 0; i < numCoords; i++) { const int32_t i4 = i * 4; CaretAssertVectorIndex(m_rgbaByte, i4+3); m_rgbaByte[i4] = 0; m_rgbaByte[i4+1] = 0; m_rgbaByte[i4+2] = 0; m_rgbaByte[i4+3] = 255; } } /** * Destructor. */ BrainOpenGLShapeCone::~BrainOpenGLShapeCone() { } void BrainOpenGLShapeCone::setupOpenGLForShape(const BrainOpenGL::DrawMode drawMode) { m_displayList = 0; m_coordinatesBufferID = 0; m_coordinatesRgbaByteBufferID = 0; m_sidesNormalBufferID = 0; m_sidesTriangleFanBufferID = 0; m_capNormalBufferID = 0; m_capTriangleFanBufferID = 0; switch (drawMode) { case BrainOpenGL::DRAW_MODE_DISPLAY_LISTS: { m_displayList = createDisplayList(); if (m_displayList > 0) { glNewList(m_displayList, GL_COMPILE); uint8_t rgbaUnused[4] = { 0, 0, 0, 0 }; m_isApplyColoring = false; drawShape(BrainOpenGL::DRAW_MODE_IMMEDIATE, rgbaUnused); m_isApplyColoring = true; glEndList(); } } break; case BrainOpenGL::DRAW_MODE_IMMEDIATE: { /* nothing to do for this case */ } break; case BrainOpenGL::DRAW_MODE_INVALID: { CaretAssert(0); } break; case BrainOpenGL::DRAW_MODE_VERTEX_BUFFERS: #ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS /* * Put coordinates into its buffer. */ m_coordinatesBufferID = createBufferID(); glBindBuffer(GL_ARRAY_BUFFER, m_coordinatesBufferID); glBufferData(GL_ARRAY_BUFFER, m_coordinates.size() * sizeof(GLfloat), &m_coordinates[0], GL_STATIC_DRAW); /* * For RGBA coloring */ m_coordinatesRgbaByteBufferID = createBufferID(); glBindBuffer(GL_ARRAY_BUFFER, m_coordinatesRgbaByteBufferID); glBufferData(GL_ARRAY_BUFFER, m_rgbaByte.size() * sizeof(GLubyte), &m_rgbaByte[0], GL_DYNAMIC_DRAW); /* * Put side normals into its buffer. */ m_sidesNormalBufferID = createBufferID(); glBindBuffer(GL_ARRAY_BUFFER, m_sidesNormalBufferID); glBufferData(GL_ARRAY_BUFFER, m_sideNormals.size() * sizeof(GLfloat), &m_sideNormals[0], GL_STATIC_DRAW); /* * Put sides triangle fan for sides into its buffer. */ m_sidesTriangleFanBufferID = createBufferID(); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_sidesTriangleFanBufferID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_sidesTriangleFan.size() * sizeof(GLuint), &m_sidesTriangleFan[0], GL_STATIC_DRAW); /* * Put cap normals into its buffer. */ m_capNormalBufferID = createBufferID(); glBindBuffer(GL_ARRAY_BUFFER, m_capNormalBufferID); glBufferData(GL_ARRAY_BUFFER, m_capNormals.size() * sizeof(GLfloat), &m_capNormals[0], GL_STATIC_DRAW); /* * Put cap triangle fan for cap into its buffer. */ m_capTriangleFanBufferID = createBufferID(); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_capTriangleFanBufferID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_capTriangleFan.size() * sizeof(GLuint), &m_capTriangleFan[0], GL_STATIC_DRAW); /* * Deselect active buffer. */ glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); #endif // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS break; } } /** * Draw the shape. * * @param drawMode * How to draw the shape. * @param rgba * RGBA coloring ranging 0.0 to 1.0 */ void BrainOpenGLShapeCone::drawShape(const BrainOpenGL::DrawMode drawMode, const float rgba[4]) { const uint8_t rgbaByte[4] = { static_cast(rgba[0] * 255.0), static_cast(rgba[1] * 255.0), static_cast(rgba[2] * 255.0), static_cast(rgba[3] * 255.0) }; drawShape(drawMode, rgbaByte); } /** * Draw the shape. * * @param drawMode * How to draw the shape. * @param rgba * RGBA coloring ranging 0 to 255. */ void BrainOpenGLShapeCone::drawShape(const BrainOpenGL::DrawMode drawMode, const uint8_t rgba[4]) { switch (drawMode) { case BrainOpenGL::DRAW_MODE_DISPLAY_LISTS: { if (m_displayList > 0) { if (m_isApplyColoring) { glColor4ubv(rgba); } glCallList(m_displayList); } } break; case BrainOpenGL::DRAW_MODE_IMMEDIATE: { if (m_isApplyColoring) { glColor4ubv(rgba); } const int32_t numSideVertices = static_cast(m_sidesTriangleFan.size()); glBegin(GL_TRIANGLE_FAN); for (int32_t j = 0; j < numSideVertices; j++) { const int32_t vertexIndex = m_sidesTriangleFan[j] * 3; CaretAssertVectorIndex(m_sideNormals, vertexIndex+2); CaretAssertVectorIndex(m_coordinates, vertexIndex+2); glNormal3fv(&m_sideNormals[vertexIndex]); glVertex3fv(&m_coordinates[vertexIndex]); } glEnd(); const int32_t numCapVertices = static_cast(m_capTriangleFan.size()); glBegin(GL_TRIANGLE_FAN); for (int32_t j = 0; j < numCapVertices; j++) { const int32_t vertexIndex = m_capTriangleFan[j] * 3; CaretAssertVectorIndex(m_capNormals, vertexIndex+2); CaretAssertVectorIndex(m_coordinates, vertexIndex+2); glNormal3fv(&m_capNormals[vertexIndex]); glVertex3fv(&m_coordinates[vertexIndex]); } glEnd(); } break; case BrainOpenGL::DRAW_MODE_INVALID: { CaretAssert(0); } break; case BrainOpenGL::DRAW_MODE_VERTEX_BUFFERS: #ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS /* * Enable vertices and normals for buffers */ glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_COLOR_ARRAY); /* * Set the vertices for drawing. */ CaretAssert(glIsBuffer(m_coordinatesBufferID) == GL_TRUE); glBindBuffer(GL_ARRAY_BUFFER, m_coordinatesBufferID); glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)0); /* * Put BYTE colors into its buffer */ const int64_t numRGBA = static_cast(m_rgbaByte.size()) / 4; for (int64_t ir = 0; ir < numRGBA; ir++) { const int64_t ir4 = ir * 4; m_rgbaByte[ir4] = rgba[0]; m_rgbaByte[ir4+1] = rgba[1]; m_rgbaByte[ir4+2] = rgba[2]; m_rgbaByte[ir4+3] = rgba[3]; } CaretAssert(glIsBuffer(m_coordinatesRgbaByteBufferID) == GL_TRUE); glBindBuffer(GL_ARRAY_BUFFER, m_coordinatesRgbaByteBufferID); glBufferData(GL_ARRAY_BUFFER, m_rgbaByte.size() * sizeof(GLubyte), &m_rgbaByte[0], GL_DYNAMIC_DRAW); glColorPointer(4, GL_UNSIGNED_BYTE, 0, (GLvoid*)0); /* * Set the side normal vectors for drawing. */ CaretAssert(glIsBuffer(m_sidesNormalBufferID) == GL_TRUE); glBindBuffer(GL_ARRAY_BUFFER, m_sidesNormalBufferID); glNormalPointer(GL_FLOAT, 0, (GLvoid*)0); /* * Draw the side triangle fans. */ CaretAssert(glIsBuffer(m_sidesTriangleFanBufferID) == GL_TRUE); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_sidesTriangleFanBufferID); glDrawElements(GL_TRIANGLE_FAN, m_sidesTriangleFan.size(), GL_UNSIGNED_INT, (GLvoid*)0); /* * Set the cap normal vectors for drawing. */ glBindBuffer(GL_ARRAY_BUFFER, m_capNormalBufferID); glNormalPointer(GL_FLOAT, 0, (GLvoid*)0); /* * Draw the cap triangle fans. */ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_capTriangleFanBufferID); glDrawElements(GL_TRIANGLE_FAN, m_capTriangleFan.size(), GL_UNSIGNED_INT, (GLvoid*)0); /* * Deselect active buffer. */ glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); /* * Disable vertices and normals for buffers. * Otherwise, bad thing will happen. */ glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); #endif // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS break; } } connectome-workbench-1.4.2/src/Brain/BrainOpenGLShapeCone.h000066400000000000000000000051421360521144700235160ustar00rootroot00000000000000#ifndef __BRAIN_OPEN_GL_SHAPE_CONE_H_ #define __BRAIN_OPEN_GL_SHAPE_CONE_H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "BrainOpenGLShape.h" namespace caret { class BrainOpenGLShapeCone : public BrainOpenGLShape { public: BrainOpenGLShapeCone(const int32_t numberOfSides); virtual ~BrainOpenGLShapeCone(); private: BrainOpenGLShapeCone(const BrainOpenGLShapeCone&); BrainOpenGLShapeCone& operator=(const BrainOpenGLShapeCone&); public: // ADD_NEW_METHODS_HERE protected: void drawShape(const BrainOpenGL::DrawMode drawMode, const uint8_t rgba[4]); void drawShape(const BrainOpenGL::DrawMode drawMode, const float rgba[4]); void setupOpenGLForShape(const BrainOpenGL::DrawMode drawMode); private: // ADD_NEW_MEMBERS_HERE const int32_t m_numberOfSides; GLuint m_coordinatesBufferID; GLuint m_coordinatesRgbaByteBufferID; GLuint m_sidesNormalBufferID; GLuint m_sidesTriangleFanBufferID; GLuint m_capNormalBufferID; GLuint m_capTriangleFanBufferID; GLuint m_displayList; std::vector m_coordinates; std::vector m_rgbaByte; std::vector m_sideNormals; std::vector m_sidesTriangleFan; std::vector m_capTriangleFan; std::vector m_capNormals; bool m_isApplyColoring; }; #ifdef __BRAIN_OPEN_GL_SHAPE_CONE_DECLARE__ // #endif // __BRAIN_OPEN_GL_SHAPE_CONE_DECLARE__ } // namespace #endif //__BRAIN_OPEN_GL_SHAPE_CONE_H_ connectome-workbench-1.4.2/src/Brain/BrainOpenGLShapeCube.cxx000066400000000000000000000405021360521144700240620ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __BRAIN_OPEN_G_L_SHAPE_CUBE_DECLARE__ #include "BrainOpenGLShapeCube.h" #undef __BRAIN_OPEN_G_L_SHAPE_CUBE_DECLARE__ #include "AString.h" #include "CaretAssert.h" #include "MathFunctions.h" using namespace caret; /** * \class caret::BrainOpenGLShapeCube * \brief Create a cube shape for use with OpenGL. */ /** * Constructor. * * @param cubeSize * Size of cube from one face to the opposite face. * @param cubeType * Type of cube. */ BrainOpenGLShapeCube::BrainOpenGLShapeCube(const float cubeSize, const CUBE_TYPE cubeType) : BrainOpenGLShape(), m_cubeSize(cubeSize), m_cubeType(cubeType) { m_isApplyColoring = true; GLfloat cubeVertices[8][3] = { { -0.5, -0.5, 0.5 }, // 0: left, near, top { 0.5, -0.5, 0.5 }, // 1: right, near, top { -0.5, 0.5, 0.5 }, // 2: left, far, top { 0.5, 0.5, 0.5 }, // 3: right, far, top { -0.5, -0.5, -0.5 }, // 4: left, near, bottom { 0.5, -0.5, -0.5 }, // 5: right, near, bottom { -0.5, 0.5, -0.5 }, // 6: left, far, bottom { 0.5, 0.5, -0.5 } // 7: right, far, bottom }; const GLint lnt = 0; const GLint rnt = 1; const GLint lft = 2; const GLint rft = 3; const GLint lnb = 4; const GLint rnb = 5; const GLint lfb = 6; const GLint rfb = 7; const GLfloat cubeNormals[6][3] = { { -1.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 0.0, -1.0, 0.0 }, { 0.0, 1.0, 0.0 }, { 0.0, 0.0, 1.0 }, { 0.0, 0.0, -1.0 } }; const GLint normalIndexLeftFace = 0; const GLint normalIndexRightFace = 1; const GLint normalIndexNearFace = 2; const GLint normalIndexFarFace = 3; const GLint normalIndexTopFace = 4; const GLint normalIndexBottomFace = 5; /* * Near Face */ addFace(cubeVertices, lnt, lnb, rnb, rnt, cubeNormals[normalIndexNearFace]); /* * Far Face */ addFace(cubeVertices, rfb, lfb, lft, rft, cubeNormals[normalIndexFarFace]); /* * Left Face */ addFace(cubeVertices, lfb, lnb, lnt, lft, cubeNormals[normalIndexLeftFace]); /* * Right Face */ addFace(cubeVertices, rnb, rfb, rft, rnt, cubeNormals[normalIndexRightFace]); /* * Bottom Face */ addFace(cubeVertices, rnb, lnb, lfb, rfb, cubeNormals[normalIndexBottomFace]); /* * Top Face */ addFace(cubeVertices, lnt, rnt, rft, lft, cubeNormals[normalIndexTopFace]); // /* // * Near Face // */ // addFace(cubeVertices, // lnt, lnb, rnb, rnt, // cubeNormals[normalIndexNearFace]); // // /* // * Far Face // */ // addFace(cubeVertices, // rfb, lfb, lft, rft, // cubeNormals[normalIndexFarFace]); // // /* // * Left Face // */ // addFace(cubeVertices, // lfb, lnb, lnt, lft, // cubeNormals[normalIndexLeftFace]); // // /* // * Right Face // */ // addFace(cubeVertices, // rnb, rfb, rft, rnt, // cubeNormals[normalIndexRightFace]); // // /* // * Bottom Face // */ // addFace(cubeVertices, // rnb, lnb, lfb, rfb, // cubeNormals[normalIndexBottomFace]); // // /* // * Top Face // */ // addFace(cubeVertices, // lnt, rnt, rft, lft, // cubeNormals[normalIndexTopFace]); CaretAssert(m_coordinates.size() == m_normals.size()); /* * Create storage for colors */ const int64_t numCoords = static_cast(m_coordinates.size()) / 3; const int64_t numRGBA = numCoords * 4; m_rgbaByte.resize(numRGBA * 4, 0); for (GLuint i = 0; i < numCoords; i++) { const int32_t i4 = i * 4; CaretAssertVectorIndex(m_rgbaByte, i4+3); m_rgbaByte[i4] = 0; m_rgbaByte[i4+1] = 0; m_rgbaByte[i4+2] = 0; m_rgbaByte[i4+3] = 255; } switch (m_cubeType) { case NORMAL: break; case ROUNDED: { const unsigned int numPoints = m_coordinates.size() / 3; for (unsigned int i = 0; i < numPoints; i++) { const unsigned int i3 = i * 3; m_normals[i3] = m_coordinates[i3]; m_normals[i3+1] = m_coordinates[i3+1]; m_normals[i3+2] = m_coordinates[i3+2]; MathFunctions::normalizeVector(&m_normals[i3]); } } break; } } /** * Destructor. */ BrainOpenGLShapeCube::~BrainOpenGLShapeCube() { } /** * Setup the shape for drawing. * * @param drawMode * The drawing mode. */ void BrainOpenGLShapeCube::setupOpenGLForShape(const BrainOpenGL::DrawMode drawMode) { m_displayList = 0; m_vertexBufferID = 0; m_coordinatesRgbaByteBufferID = 0; m_normalBufferID = 0; m_trianglesBufferID = 0; switch (drawMode) { case BrainOpenGL::DRAW_MODE_DISPLAY_LISTS: { m_displayList = createDisplayList(); if (m_displayList > 0) { glNewList(m_displayList, GL_COMPILE); uint8_t rgbaUnused[4] = { 0, 0, 0, 0 }; m_isApplyColoring = false; drawShape(BrainOpenGL::DRAW_MODE_IMMEDIATE, rgbaUnused); m_isApplyColoring = true; glEndList(); } } break; case BrainOpenGL::DRAW_MODE_IMMEDIATE: { /* nothing to do for this case */ } break; case BrainOpenGL::DRAW_MODE_INVALID: { CaretAssert(0); } break; case BrainOpenGL::DRAW_MODE_VERTEX_BUFFERS: #ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS /* * Put vertices (coordinates) into its buffer. */ m_vertexBufferID = createBufferID(); glBindBuffer(GL_ARRAY_BUFFER, m_vertexBufferID); glBufferData(GL_ARRAY_BUFFER, m_coordinates.size() * sizeof(GLfloat), &m_coordinates[0], GL_STATIC_DRAW); /* * For RGBA coloring */ m_coordinatesRgbaByteBufferID = createBufferID(); glBindBuffer(GL_ARRAY_BUFFER, m_coordinatesRgbaByteBufferID); glBufferData(GL_ARRAY_BUFFER, m_rgbaByte.size() * sizeof(GLubyte), &m_rgbaByte[0], GL_DYNAMIC_DRAW); /* * Put normals into its buffer. */ m_normalBufferID = createBufferID(); glBindBuffer(GL_ARRAY_BUFFER, m_normalBufferID); glBufferData(GL_ARRAY_BUFFER, m_normals.size() * sizeof(GLfloat), &m_normals[0], GL_STATIC_DRAW); /* * Put triangle strips into its buffer. */ m_trianglesBufferID = createBufferID(); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_trianglesBufferID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_triangles.size() * sizeof(GLuint), &m_triangles[0], GL_STATIC_DRAW); /* * Deselect active buffer. */ glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); #endif // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS break; } } /** * Add a face (two triangles) to vertices and normals for drawing. * Vertex indices must be in counter-clockwise order. * * @param vertices * Array of vertices. * @param v1 * First face coordinate index. * @param v2 * Second face coordinate index. * @param v3 * Third face coordinate index. * @param v4 * Fourth face coordinate index. * @param normalVector * Normal vector for the face. */ void BrainOpenGLShapeCube::addFace(const GLfloat coordinates[][3], const GLint v1, const GLint v2, const GLint v3, const GLint v4, const GLfloat normalVector[3]) { m_coordinates.push_back(coordinates[v1][0]); m_coordinates.push_back(coordinates[v1][1]); m_coordinates.push_back(coordinates[v1][2]); m_normals.push_back(normalVector[0]); m_normals.push_back(normalVector[1]); m_normals.push_back(normalVector[2]); m_triangles.push_back(m_coordinates.size() / 3 - 1); m_coordinates.push_back(coordinates[v2][0]); m_coordinates.push_back(coordinates[v2][1]); m_coordinates.push_back(coordinates[v2][2]); m_normals.push_back(normalVector[0]); m_normals.push_back(normalVector[1]); m_normals.push_back(normalVector[2]); m_triangles.push_back(m_coordinates.size() / 3 - 1); m_coordinates.push_back(coordinates[v3][0]); m_coordinates.push_back(coordinates[v3][1]); m_coordinates.push_back(coordinates[v3][2]); m_normals.push_back(normalVector[0]); m_normals.push_back(normalVector[1]); m_normals.push_back(normalVector[2]); m_triangles.push_back(m_coordinates.size() / 3 - 1); m_coordinates.push_back(coordinates[v3][0]); m_coordinates.push_back(coordinates[v3][1]); m_coordinates.push_back(coordinates[v3][2]); m_normals.push_back(normalVector[0]); m_normals.push_back(normalVector[1]); m_normals.push_back(normalVector[2]); m_triangles.push_back(m_coordinates.size() / 3 - 1); m_coordinates.push_back(coordinates[v4][0]); m_coordinates.push_back(coordinates[v4][1]); m_coordinates.push_back(coordinates[v4][2]); m_normals.push_back(normalVector[0]); m_normals.push_back(normalVector[1]); m_normals.push_back(normalVector[2]); m_triangles.push_back(m_coordinates.size() / 3 - 1); m_coordinates.push_back(coordinates[v1][0]); m_coordinates.push_back(coordinates[v1][1]); m_coordinates.push_back(coordinates[v1][2]); m_normals.push_back(normalVector[0]); m_normals.push_back(normalVector[1]); m_normals.push_back(normalVector[2]); m_triangles.push_back(m_coordinates.size() / 3 - 1); } /** * Draw the shape. * * @param drawMode * How to draw the shape. * @param rgba * RGBA coloring ranging 0.0 to 1.0 */ void BrainOpenGLShapeCube::drawShape(const BrainOpenGL::DrawMode drawMode, const float rgba[4]) { const uint8_t rgbaByte[4] = { static_cast(rgba[0] * 255.0), static_cast(rgba[1] * 255.0), static_cast(rgba[2] * 255.0), static_cast(rgba[3] * 255.0) }; drawShape(drawMode, rgbaByte); } /** * Draw the shape. * * @param drawMode * How to draw the shape. * @param rgba * RGBA coloring ranging 0 to 255. */ void BrainOpenGLShapeCube::drawShape(const BrainOpenGL::DrawMode drawMode, const uint8_t rgba[4]) { switch (drawMode) { case BrainOpenGL::DRAW_MODE_DISPLAY_LISTS: { if (m_displayList > 0) { if (m_isApplyColoring) { glColor4ubv(rgba); } glCallList(m_displayList); } } break; case BrainOpenGL::DRAW_MODE_IMMEDIATE: { if (m_isApplyColoring) { glColor4ubv(rgba); } const int32_t numVertices = static_cast(m_coordinates.size() / 3); glBegin(GL_TRIANGLES); for (int32_t j = 0; j < numVertices; j++) { const int32_t vertexIndex = j * 3; CaretAssertVectorIndex(m_normals, vertexIndex); CaretAssertVectorIndex(m_coordinates, vertexIndex); glNormal3fv(&m_normals[vertexIndex]); glVertex3fv(&m_coordinates[vertexIndex]); } glEnd(); } break; case BrainOpenGL::DRAW_MODE_INVALID: { CaretAssert(0); } break; case BrainOpenGL::DRAW_MODE_VERTEX_BUFFERS: #ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_COLOR_ARRAY); /* * Set the vertices for drawing. */ glBindBuffer(GL_ARRAY_BUFFER, m_vertexBufferID); glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)0); /* * Put BYTE colors into its buffer */ const int64_t numRGBA = static_cast(m_rgbaByte.size()) / 4; for (int64_t ir = 0; ir < numRGBA; ir++) { const int64_t ir4 = ir * 4; m_rgbaByte[ir4] = rgba[0]; m_rgbaByte[ir4+1] = rgba[1]; m_rgbaByte[ir4+2] = rgba[2]; m_rgbaByte[ir4+3] = rgba[3]; } CaretAssert(glIsBuffer(m_coordinatesRgbaByteBufferID) == GL_TRUE); glBindBuffer(GL_ARRAY_BUFFER, m_coordinatesRgbaByteBufferID); glBufferData(GL_ARRAY_BUFFER, m_rgbaByte.size() * sizeof(GLubyte), &m_rgbaByte[0], GL_DYNAMIC_DRAW); glColorPointer(4, GL_UNSIGNED_BYTE, 0, (GLvoid*)0); /* * Set the normal vectors for drawing. */ glBindBuffer(GL_ARRAY_BUFFER, m_normalBufferID); glNormalPointer(GL_FLOAT, 0, (GLvoid*)0); /* * Draw the triangles. */ CaretAssert(m_triangles.size() == (m_coordinates.size() / 3)); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_trianglesBufferID); glDrawElements(GL_TRIANGLES, m_triangles.size(), GL_UNSIGNED_INT, (GLvoid*)0); /* * Deselect active buffer. */ glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); #endif // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS break; } } connectome-workbench-1.4.2/src/Brain/BrainOpenGLShapeCube.h000066400000000000000000000057361360521144700235210ustar00rootroot00000000000000#ifndef __BRAIN_OPEN_G_L_SHAPE_CUBE__H_ #define __BRAIN_OPEN_G_L_SHAPE_CUBE__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "BrainOpenGLShape.h" namespace caret { class BrainOpenGLShapeCube : public BrainOpenGLShape { public: /** * Type of cube */ enum CUBE_TYPE { /** Normal vectors orthogonal to faces */ NORMAL, /** Normal vectors run though vertices which smooths corners */ ROUNDED }; BrainOpenGLShapeCube(const float cubeSize, const CUBE_TYPE cubeType); virtual ~BrainOpenGLShapeCube(); private: BrainOpenGLShapeCube(const BrainOpenGLShapeCube&); BrainOpenGLShapeCube& operator=(const BrainOpenGLShapeCube&); public: // ADD_NEW_METHODS_HERE protected: void drawShape(const BrainOpenGL::DrawMode drawMode, const uint8_t rgba[4]); void drawShape(const BrainOpenGL::DrawMode drawMode, const float rgba[4]); void setupOpenGLForShape(const BrainOpenGL::DrawMode drawMode); private: void addFace(const GLfloat coordinates[][3], const GLint v1, const GLint v2, const GLint v3, const GLint v4, const GLfloat normalVector[3]); // ADD_NEW_MEMBERS_HERE const float m_cubeSize; const CUBE_TYPE m_cubeType; GLuint m_vertexBufferID; GLuint m_coordinatesRgbaByteBufferID; GLuint m_normalBufferID; GLuint m_trianglesBufferID; GLuint m_displayList; std::vector m_coordinates; std::vector m_rgbaByte; std::vector m_normals; std::vector m_triangles; bool m_isApplyColoring; }; #ifdef __BRAIN_OPEN_G_L_SHAPE_CUBE_DECLARE__ // #endif // __BRAIN_OPEN_G_L_SHAPE_CUBE_DECLARE__ } // namespace #endif //__BRAIN_OPEN_G_L_SHAPE_CUBE__H_ connectome-workbench-1.4.2/src/Brain/BrainOpenGLShapeCylinder.cxx000066400000000000000000000473441360521144700247700ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __BRAIN_OPEN_G_L_SHAPE_CYLINDER_DECLARE__ #include "BrainOpenGLShapeCylinder.h" #undef __BRAIN_OPEN_G_L_SHAPE_CYLINDER_DECLARE__ #include "CaretAssert.h" #include "MathFunctions.h" using namespace caret; /** * \class caret::BrainOpenGLShapeCylinder * \brief Creates a cylinder shape for use with OpenGL. * \ingroup Brain */ /** * Constructor. */ BrainOpenGLShapeCylinder::BrainOpenGLShapeCylinder(const int32_t numberOfSides) : BrainOpenGLShape(), m_numberOfSides(numberOfSides) { m_isApplyColoring = true; // bool debugFlag = false; /* * Setup step size based upon number of points around circle */ const float step = (2.0 * M_PI) / m_numberOfSides; /* * Z-coordinates at bottom and top of cylinder */ const float zTop = 1.0; const float zBottom = 0.0; std::vector topTriangleStripVertices; std::vector bottomTriangleStripVertices; std::vector sideTriangleStripVertices; /* * Counts vertices */ GLuint vertexCounter = 0; // const float topCenterNormalX = 0.0; // const float topCenterNormalY = 0.0; // const float topCenterNormalZ = 1.0; // // const float topCenterX = 0.0; // const float topCenterY = 0.0; // const float topCenterZ = 1.0; // // const float bottomCenterNormalX = 0.0; // const float bottomCenterNormalY = 0.0; // const float bottomCenterNormalZ = -1.0; // // const float bottomCenterX = 0.0; // const float bottomCenterY = 0.0; // const float bottomCenterZ = -1.0; // /* // * Center of top // */ // m_coordinates.push_back(0.0); // m_coordinates.push_back(0.0); // m_coordinates.push_back(1.0); // m_normals.push_back(topCenterNormalX); // m_normals.push_back(topCenterNormalY); // m_normals.push_back(topCenterNormalZ); // m_normals.push_back(vertexCounter); // vertexCounter++; // // /* // * Center of bottom // */ // m_coordinates.push_back(0.0); // m_coordinates.push_back(0.0); // m_coordinates.push_back(-1.0); // m_normals.push_back(bottomCenterNormalX); // m_normals.push_back(bottomCenterNormalY); // m_normals.push_back(bottomCenterNormalZ); // m_normals.push_back(vertexCounter); // vertexCounter++; const GLuint firstSideVertex = vertexCounter; /* * Generate points around cylinder */ const float radius = 0.5; for (int32_t i = 0; i < m_numberOfSides; i++) { const float t = step * i; const float x = radius * std::cos(t); const float y = radius * std::sin(t); /* * Top of slice */ m_coordinates.push_back(x); m_coordinates.push_back(y); m_coordinates.push_back(zTop); m_normals.push_back(x); m_normals.push_back(y); m_normals.push_back(0.0); sideTriangleStripVertices.push_back(vertexCounter); vertexCounter++; // m_normals.push_back(topCenterNormalX); // m_normals.push_back(topCenterNormalY); // m_normals.push_back(topCenterNormalZ); // m_topTriangleFan.push_back(vertexCounter); m_coordinates.push_back(x); m_coordinates.push_back(y); m_coordinates.push_back(zBottom); m_normals.push_back(x); m_normals.push_back(y); m_normals.push_back(0.0); sideTriangleStripVertices.push_back(vertexCounter); vertexCounter++; // m_bottomNormals.push_back(bottomCenterNormalX); // m_bottomNormals.push_back(bottomCenterNormalY); // m_bottomNormals.push_back(bottomCenterNormalZ); // m_bottomTriangleFan.push_back(vertexCounter); // vertexCounter++; } /* * Finish cylinder by specifying first two coordinates again */ const GLuint firstVertexIndex = firstSideVertex * 3; m_coordinates.push_back(m_coordinates[firstVertexIndex]); m_coordinates.push_back(m_coordinates[firstVertexIndex+1]); m_coordinates.push_back(m_coordinates[firstVertexIndex+2]); m_normals.push_back(m_normals[firstVertexIndex]); m_normals.push_back(m_normals[firstVertexIndex+1]); m_normals.push_back(m_normals[firstVertexIndex+2]); sideTriangleStripVertices.push_back(vertexCounter); vertexCounter++; m_coordinates.push_back(m_coordinates[firstVertexIndex+3]); m_coordinates.push_back(m_coordinates[firstVertexIndex+4]); m_coordinates.push_back(m_coordinates[firstVertexIndex+5]); m_normals.push_back(m_normals[firstVertexIndex+3]); m_normals.push_back(m_normals[firstVertexIndex+4]); m_normals.push_back(m_normals[firstVertexIndex+5]); sideTriangleStripVertices.push_back(vertexCounter); vertexCounter++; CaretAssert((vertexCounter * 3) == static_cast(m_coordinates.size())); CaretAssert((vertexCounter * 3) == static_cast(m_normals.size())); m_triangleStrip = sideTriangleStripVertices; // /* // * Finish top and bottom // * Note bottom vertices need to be reverse so that // * that the vertices are counter clockwise when pointing down. // */ // m_topNormals.push_back(m_topNormals[0]); // m_topNormals.push_back(m_topNormals[1]); // m_topNormals.push_back(m_topNormals[2]); // m_topTriangleFan.push_back(firstSideVertex); // // m_bottomNormals.push_back(m_bottomNormals[0]); // m_bottomNormals.push_back(m_bottomNormals[1]); // m_bottomNormals.push_back(m_bottomNormals[2]); // m_bottomTriangleFan.push_back(firstSideVertex + 1); // std::reverse(m_bottomTriangleFan.begin(), // m_bottomTriangleFan.end()); // // CaretAssert(m_topNormals.size() == (m_topTriangleFan.size() * 3)); // CaretAssert(m_sidesNormals.size() == ((m_sidesTriangleStrip.size() - 2) * 3)); // CaretAssert(m_topNormals.size() == (m_topTriangleFan.size() * 3)); /* * Create storage for colors */ m_rgbaByte.resize(vertexCounter * 4, 0); m_rgbaFloat.resize(vertexCounter * 4, 0.0); for (GLuint i = 0; i < vertexCounter; i++) { const int32_t i4 = i * 4; m_rgbaFloat[i4] = 0.0; m_rgbaFloat[i4+1] = 0.0; m_rgbaFloat[i4+2] = 0.0; m_rgbaFloat[i4+3] = 1.0; m_rgbaByte[i4] = 0; m_rgbaByte[i4+1] = 0; m_rgbaByte[i4+2] = 0; m_rgbaByte[i4+3] = 255; } } /** * Destructor. */ BrainOpenGLShapeCylinder::~BrainOpenGLShapeCylinder() { } void BrainOpenGLShapeCylinder::setupOpenGLForShape(const BrainOpenGL::DrawMode drawMode) { m_displayList = 0; m_coordinatesBufferID = 0; m_coordinatesRgbaByteBufferID = 0; m_coordinatesRgbaFloatBufferID = 0; m_normalsBufferID = 0; m_triangleStripBufferID = 0; switch (drawMode) { case BrainOpenGL::DRAW_MODE_DISPLAY_LISTS: { m_displayList = createDisplayList(); if (m_displayList > 0) { glNewList(m_displayList, GL_COMPILE); uint8_t rgbaUnused[4] = { 0, 0, 0, 0 }; m_isApplyColoring = false; drawShape(BrainOpenGL::DRAW_MODE_IMMEDIATE, rgbaUnused); m_isApplyColoring = true; glEndList(); } } break; case BrainOpenGL::DRAW_MODE_IMMEDIATE: { /* nothing to do for this case */ } break; case BrainOpenGL::DRAW_MODE_INVALID: { CaretAssert(0); } break; case BrainOpenGL::DRAW_MODE_VERTEX_BUFFERS: #ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS /* * Put coordinates into its buffer. */ m_coordinatesBufferID = createBufferID(); glBindBuffer(GL_ARRAY_BUFFER, m_coordinatesBufferID); glBufferData(GL_ARRAY_BUFFER, m_coordinates.size() * sizeof(GLfloat), &m_coordinates[0], GL_STATIC_DRAW); m_coordinatesRgbaByteBufferID = createBufferID(); glBindBuffer(GL_ARRAY_BUFFER, m_coordinatesRgbaByteBufferID); glBufferData(GL_ARRAY_BUFFER, m_rgbaByte.size() * sizeof(GLubyte), &m_rgbaByte[0], GL_DYNAMIC_DRAW); /* * Put FLOAT colors into its buffer */ m_coordinatesRgbaFloatBufferID = createBufferID(); glBindBuffer(GL_ARRAY_BUFFER, m_coordinatesRgbaFloatBufferID); glBufferData(GL_ARRAY_BUFFER, m_rgbaFloat.size() * sizeof(GLfloat), &m_rgbaFloat[0], GL_DYNAMIC_DRAW); /* * Put side normals into its buffer. */ m_normalsBufferID = createBufferID(); glBindBuffer(GL_ARRAY_BUFFER, m_normalsBufferID); glBufferData(GL_ARRAY_BUFFER, m_normals.size() * sizeof(GLfloat), &m_normals[0], GL_STATIC_DRAW); /* * Put sides triangle strip for sides into its buffer. */ m_triangleStripBufferID = createBufferID(); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_triangleStripBufferID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_triangleStrip.size() * sizeof(GLuint), &m_triangleStrip[0], GL_STATIC_DRAW); /* * Deselect active buffer. */ glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); #endif // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS break; } } /** * Draw the shape. * * @param drawMode * How to draw the shape. * @param rgba * RGBA coloring ranging 0.0 to 1.0 */ void BrainOpenGLShapeCylinder::drawShape(const BrainOpenGL::DrawMode drawMode, const float rgba[4]) { const uint8_t rgbaByte[4] = { static_cast(rgba[0] * 255.0), static_cast(rgba[1] * 255.0), static_cast(rgba[2] * 255.0), static_cast(rgba[3] * 255.0) }; drawShape(drawMode, rgbaByte); } /** * Draw the shape. * * @param drawMode * How to draw the shape. * @param rgba * RGBA coloring ranging 0 to 255. */ /** * Draw the cone. * @param drawMode * How to draw the shape. */ void BrainOpenGLShapeCylinder::drawShape(const BrainOpenGL::DrawMode drawMode, const uint8_t rgba[4]) { switch (drawMode) { case BrainOpenGL::DRAW_MODE_DISPLAY_LISTS: { if (m_displayList > 0) { if (m_isApplyColoring) { glColor4ubv(rgba); } glCallList(m_displayList); } } break; case BrainOpenGL::DRAW_MODE_IMMEDIATE: { if (m_isApplyColoring) { glColor4ubv(rgba); } // /* // * Draw the top // */ // const int32_t numTopVertices = static_cast (m_topTriangleFan.size()); // glBegin(GL_TRIANGLE_FAN); // for (int32_t i = 0; i < numTopVertices; i++) { // CaretAssertVectorIndex(m_topTriangleFan, i); // const int32_t fanIndex = m_topTriangleFan[i]; // const int32_t coordinateOffset = fanIndex * 3; // const int32_t colorOffset = fanIndex * 4; // const int32_t normalOffset = i * 3; // // CaretAssertVectorIndex(m_coordinates, coordinateOffset + 2); // CaretAssertVectorIndex(m_topNormals, normalOffset + 2); // CaretAssertVectorIndex(m_coordinatesRGBA, colorOffset + 3); // // glColor4fv(&m_coordinatesRGBA[colorOffset]); // glNormal3fv(&m_topNormals[normalOffset]); // glVertex3fv(&m_coordinates[coordinateOffset]); // } // glEnd(); // // /* // * Draw the bottom // */ // const int32_t numBottomVertices = static_cast (m_bottomTriangleFan.size()); // glBegin(GL_TRIANGLE_FAN); // for (int32_t i = 0; i < numBottomVertices; i++) { // CaretAssertVectorIndex(m_bottomTriangleFan, i); // const int32_t fanIndex = m_bottomTriangleFan[i]; // const int32_t coordinateOffset = fanIndex * 3; // const int32_t colorOffset = fanIndex * 4; // const int32_t normalOffset = i * 3; // // CaretAssertVectorIndex(m_coordinates, coordinateOffset + 2); // CaretAssertVectorIndex(m_bottomNormals, normalOffset + 2); // CaretAssertVectorIndex(m_coordinatesRGBA, colorOffset + 3); // // glColor4fv(&m_coordinatesRGBA[colorOffset]); // glNormal3fv(&m_bottomNormals[normalOffset]); // glVertex3fv(&m_coordinates[coordinateOffset]); // } // glEnd(); /* * Draw the sides */ const int32_t numSideVertices = static_cast(m_triangleStrip.size()); glBegin(GL_TRIANGLE_STRIP); for (int32_t i = 0; i < numSideVertices; i++) { CaretAssertVectorIndex(m_triangleStrip, i); const int32_t stripIndex = m_triangleStrip[i]; const int32_t coordinateOffset = stripIndex * 3; //const int32_t colorOffset = stripIndex * 4; const int32_t normalOffset = stripIndex * 3; CaretAssertVectorIndex(m_coordinates, coordinateOffset + 2); CaretAssertVectorIndex(m_normals, normalOffset + 2); //CaretAssertVectorIndex(m_rgba, colorOffset + 3); //glColor4ubv(&m_rgba[colorOffset]); glNormal3fv(&m_normals[normalOffset]); glVertex3fv(&m_coordinates[coordinateOffset]); } glEnd(); } break; case BrainOpenGL::DRAW_MODE_INVALID: { CaretAssert(0); } break; case BrainOpenGL::DRAW_MODE_VERTEX_BUFFERS: #ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS /* * Enable vertices and normals for buffers */ glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_COLOR_ARRAY); /* * Set the vertices for drawing. */ glBindBuffer(GL_ARRAY_BUFFER, m_coordinatesBufferID); glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)0); /* * Put BYTE colors into its buffer */ const int64_t numRGBA = static_cast(m_rgbaByte.size()) / 4; for (int64_t ir = 0; ir < numRGBA; ir++) { const int64_t ir4 = ir * 4; m_rgbaByte[ir4] = rgba[0]; m_rgbaByte[ir4+1] = rgba[1]; m_rgbaByte[ir4+2] = rgba[2]; m_rgbaByte[ir4+3] = rgba[3]; } glBindBuffer(GL_ARRAY_BUFFER, m_coordinatesRgbaByteBufferID); glBufferData(GL_ARRAY_BUFFER, m_rgbaByte.size() * sizeof(GLubyte), &m_rgbaByte[0], GL_DYNAMIC_DRAW); glColorPointer(4, GL_UNSIGNED_BYTE, 0, (GLvoid*)0); // /* // * Set FLOAT color components for drawing // */ // glBindBuffer(GL_ARRAY_BUFFER, // m_coordinatesRgbaFloatBufferID); // glColorPointer(4, // GL_FLOAT, // 0, // (GLvoid*)0); /* * Set the side normal vectors for drawing. */ glBindBuffer(GL_ARRAY_BUFFER, m_normalsBufferID); glNormalPointer(GL_FLOAT, 0, (GLvoid*)0); /* * Draw the side triangle strip. */ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_triangleStripBufferID); glDrawElements(GL_TRIANGLE_STRIP, m_triangleStrip.size(), GL_UNSIGNED_INT, (GLvoid*)0); /* * Draw the bottom cap triangle fans. */ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_triangleStripBufferID); glDrawElements(GL_TRIANGLE_STRIP, m_triangleStrip.size(), GL_UNSIGNED_INT, (GLvoid*)0); /* * Deselect active buffer. */ glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); /* * Disable vertices and normals for buffers. * Otherwise, bad thing will happen. */ glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); #endif // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS break; } } connectome-workbench-1.4.2/src/Brain/BrainOpenGLShapeCylinder.h000066400000000000000000000051111360521144700243770ustar00rootroot00000000000000#ifndef __BRAIN_OPEN_G_L_SHAPE_CYLINDER_H__ #define __BRAIN_OPEN_G_L_SHAPE_CYLINDER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainOpenGLShape.h" namespace caret { class BrainOpenGLShapeCylinder : public BrainOpenGLShape { public: BrainOpenGLShapeCylinder(const int32_t numberOfSides); virtual ~BrainOpenGLShapeCylinder(); private: BrainOpenGLShapeCylinder(const BrainOpenGLShapeCylinder&); BrainOpenGLShapeCylinder& operator=(const BrainOpenGLShapeCylinder&); protected: void drawShape(const BrainOpenGL::DrawMode drawMode, const uint8_t rgba[4]); void drawShape(const BrainOpenGL::DrawMode drawMode, const float rgba[4]); void setupOpenGLForShape(const BrainOpenGL::DrawMode drawMode); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE // ADD_NEW_MEMBERS_HERE const int32_t m_numberOfSides; GLuint m_coordinatesBufferID; GLuint m_coordinatesRgbaByteBufferID; GLuint m_coordinatesRgbaFloatBufferID; GLuint m_normalsBufferID; GLuint m_triangleStripBufferID; GLuint m_displayList; std::vector m_coordinates; std::vector m_rgbaByte; std::vector m_rgbaFloat; std::vector m_normals; std::vector m_triangleStrip; bool m_isApplyColoring; }; #ifdef __BRAIN_OPEN_G_L_SHAPE_CYLINDER_DECLARE__ // #endif // __BRAIN_OPEN_G_L_SHAPE_CYLINDER_DECLARE__ } // namespace #endif //__BRAIN_OPEN_G_L_SHAPE_CYLINDER_H__ connectome-workbench-1.4.2/src/Brain/BrainOpenGLShapeRing.cxx000066400000000000000000000313701360521144700241060ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __BRAIN_OPEN_GL_SHAPE_RING_DECLARE__ #include "BrainOpenGLShapeRing.h" #undef __BRAIN_OPEN_GL_SHAPE_RING_DECLARE__ #include "CaretAssert.h" #include "MathFunctions.h" using namespace caret; /** * \class caret::BrainOpenGLShapeRing * \brief Create a conical shape for use with OpenGL. */ /** * Constructor. * @param numberOfSides * Number of sides in the ring. */ BrainOpenGLShapeRing::BrainOpenGLShapeRing(const int32_t numberOfSides, const float innerRadius, const float outerRadius) : BrainOpenGLShape(), m_numberOfSides(numberOfSides), m_innerRadius(innerRadius), m_outerRadius(outerRadius) { m_isApplyColoring = true; bool debugFlag = false; /* * Setup step size based upon number of points around circle */ // const int32_t numberOfPoints = 8; const float step = (2.0 * M_PI) / m_numberOfSides; /* * Generate points around ring */ const float z = 0.0; for (int32_t i = 0; i < m_numberOfSides; i++) { const float t = step * i; // const float x = majorRadius * std::cos(t); // const float y = minorRadius * std::sin(t); const float xin = m_innerRadius * std::cos(t); const float yin = m_innerRadius * std::sin(t); const float xout = m_outerRadius * std::cos(t); const float yout = m_outerRadius * std::sin(t); m_triangleStrip.push_back(m_coordinates.size() / 3); m_coordinates.push_back(xin); m_coordinates.push_back(yin); m_coordinates.push_back(z); m_normals.push_back(0.0); m_normals.push_back(0.0); m_normals.push_back(1.0); m_triangleStrip.push_back(m_coordinates.size() / 3); m_coordinates.push_back(xout); m_coordinates.push_back(yout); m_coordinates.push_back(z); m_normals.push_back(0.0); m_normals.push_back(0.0); m_normals.push_back(1.0); } if (m_numberOfSides > 0) { m_triangleStrip.push_back(0); m_triangleStrip.push_back(1); } if (debugFlag) { CaretAssert(m_coordinates.size() == m_normals.size()); const int32_t numPoints = static_cast(m_coordinates.size() / 3); for (int32_t i = 0; i < numPoints; i++) { const int32_t i3 = i * 3; std::cout << "points[" << i << "]=(" << AString::fromNumbers(&m_coordinates[i3], 3, ",") << ")" << std::endl; std::cout << "side normal[" << i << "]=(" << AString::fromNumbers(&m_normals[i3], 3, ",") << ")" << std::endl; } std::cout << "Sides: "; printTriangleStrip(m_triangleStrip); std::cout << std::endl; } // /* // * End Cap // */ // glBegin(GL_POLYGON); // glNormal3f(0.0, 0.0, 1.0); // for (int32_t i = 0; i < m_numberOfSides; i++) { // const int32_t i3 = i * 3; // glVertex3fv(&m_coordinates[i3]); // } // glEnd(); /* * Create storage for colors */ const int64_t numCoords = static_cast(m_coordinates.size()) / 3; const int64_t numRGBA = numCoords * 4; m_rgbaByte.resize(numRGBA * 4, 0); for (GLuint i = 0; i < numCoords; i++) { const int32_t i4 = i * 4; CaretAssertVectorIndex(m_rgbaByte, i4+3); m_rgbaByte[i4] = 0; m_rgbaByte[i4+1] = 0; m_rgbaByte[i4+2] = 0; m_rgbaByte[i4+3] = 255; } } /** * Destructor. */ BrainOpenGLShapeRing::~BrainOpenGLShapeRing() { } void BrainOpenGLShapeRing::setupOpenGLForShape(const BrainOpenGL::DrawMode drawMode) { m_displayList = 0; m_coordinatesBufferID = 0; m_coordinatesRgbaByteBufferID = 0; m_normalBufferID = 0; m_triangleStripBufferID = 0; switch (drawMode) { case BrainOpenGL::DRAW_MODE_DISPLAY_LISTS: { m_displayList = createDisplayList(); if (m_displayList > 0) { glNewList(m_displayList, GL_COMPILE); uint8_t rgbaUnused[4] = { 0, 0, 0, 0 }; m_isApplyColoring = false; drawShape(BrainOpenGL::DRAW_MODE_IMMEDIATE, rgbaUnused); m_isApplyColoring = true; glEndList(); } } break; case BrainOpenGL::DRAW_MODE_IMMEDIATE: { /* nothing to do for this case */ } break; case BrainOpenGL::DRAW_MODE_INVALID: { CaretAssert(0); } break; case BrainOpenGL::DRAW_MODE_VERTEX_BUFFERS: #ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS /* * Put coordinates into its buffer. */ m_coordinatesBufferID = createBufferID(); glBindBuffer(GL_ARRAY_BUFFER, m_coordinatesBufferID); glBufferData(GL_ARRAY_BUFFER, m_coordinates.size() * sizeof(GLfloat), &m_coordinates[0], GL_STATIC_DRAW); /* * For RGBA coloring */ m_coordinatesRgbaByteBufferID = createBufferID(); glBindBuffer(GL_ARRAY_BUFFER, m_coordinatesRgbaByteBufferID); glBufferData(GL_ARRAY_BUFFER, m_rgbaByte.size() * sizeof(GLubyte), &m_rgbaByte[0], GL_DYNAMIC_DRAW); /* * Put side normals into its buffer. */ m_normalBufferID = createBufferID(); glBindBuffer(GL_ARRAY_BUFFER, m_normalBufferID); glBufferData(GL_ARRAY_BUFFER, m_normals.size() * sizeof(GLfloat), &m_normals[0], GL_STATIC_DRAW); /* * Put sides triangle strip into its buffer. */ m_triangleStripBufferID = createBufferID(); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_triangleStripBufferID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_triangleStrip.size() * sizeof(GLuint), &m_triangleStrip[0], GL_STATIC_DRAW); /* * Deselect active buffer. */ glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); #endif // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS break; } } /** * Draw the shape. * * @param drawMode * How to draw the shape. * @param rgba * RGBA coloring ranging 0.0 to 1.0 */ void BrainOpenGLShapeRing::drawShape(const BrainOpenGL::DrawMode drawMode, const float rgba[4]) { const uint8_t rgbaByte[4] = { static_cast(rgba[0] * 255.0), static_cast(rgba[1] * 255.0), static_cast(rgba[2] * 255.0), static_cast(rgba[3] * 255.0) }; drawShape(drawMode, rgbaByte); } /** * Draw the shape. * * @param drawMode * How to draw the shape. * @param rgba * RGBA coloring ranging 0 to 255. */ void BrainOpenGLShapeRing::drawShape(const BrainOpenGL::DrawMode drawMode, const uint8_t rgba[4]) { switch (drawMode) { case BrainOpenGL::DRAW_MODE_DISPLAY_LISTS: { if (m_displayList > 0) { if (m_isApplyColoring) { glColor4ubv(rgba); } glCallList(m_displayList); } } break; case BrainOpenGL::DRAW_MODE_IMMEDIATE: { if (m_isApplyColoring) { glColor4ubv(rgba); } const int32_t numVertices = static_cast(m_triangleStrip.size()); glBegin(GL_TRIANGLE_STRIP); for (int32_t j = 0; j < numVertices; j++) { const int32_t vertexIndex = m_triangleStrip[j] * 3; CaretAssertVectorIndex(m_normals, vertexIndex); CaretAssertVectorIndex(m_coordinates, vertexIndex); glNormal3fv(&m_normals[vertexIndex]); glVertex3fv(&m_coordinates[vertexIndex]); } glEnd(); } break; case BrainOpenGL::DRAW_MODE_INVALID: { CaretAssert(0); } break; case BrainOpenGL::DRAW_MODE_VERTEX_BUFFERS: #ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS /* * Enable vertices and normals for buffers */ glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_COLOR_ARRAY); /* * Set the vertices for drawing. */ glBindBuffer(GL_ARRAY_BUFFER, m_coordinatesBufferID); glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)0); /* * Put BYTE colors into its buffer */ const int64_t numRGBA = static_cast(m_rgbaByte.size()) / 4; for (int64_t ir = 0; ir < numRGBA; ir++) { const int64_t ir4 = ir * 4; CaretAssertVectorIndex(m_rgbaByte, ir4+3); m_rgbaByte[ir4] = rgba[0]; m_rgbaByte[ir4+1] = rgba[1]; m_rgbaByte[ir4+2] = rgba[2]; m_rgbaByte[ir4+3] = rgba[3]; } CaretAssert(glIsBuffer(m_coordinatesRgbaByteBufferID) == GL_TRUE); glBindBuffer(GL_ARRAY_BUFFER, m_coordinatesRgbaByteBufferID); glBufferData(GL_ARRAY_BUFFER, m_rgbaByte.size() * sizeof(GLubyte), &m_rgbaByte[0], GL_DYNAMIC_DRAW); glColorPointer(4, GL_UNSIGNED_BYTE, 0, (GLvoid*)0); /* * Set the side normal vectors for drawing. */ glBindBuffer(GL_ARRAY_BUFFER, m_normalBufferID); glNormalPointer(GL_FLOAT, 0, (GLvoid*)0); /* * Draw the side triangle fans. */ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_triangleStripBufferID); glDrawElements(GL_TRIANGLE_STRIP, m_triangleStrip.size(), GL_UNSIGNED_INT, (GLvoid*)0); /* * Deselect active buffer. */ glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); /* * Disable vertices and normals for buffers. * Otherwise, bad thing will happen. */ glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); #endif // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS break; } } connectome-workbench-1.4.2/src/Brain/BrainOpenGLShapeRing.h000066400000000000000000000051461360521144700235350ustar00rootroot00000000000000#ifndef __BRAIN_OPEN_GL_SHAPE_RING_H_ #define __BRAIN_OPEN_GL_SHAPE_RING_H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "BrainOpenGLShape.h" namespace caret { class BrainOpenGLShapeRing : public BrainOpenGLShape { public: BrainOpenGLShapeRing(const int32_t numberOfSides, const float innerRadius, const float outerRadius); virtual ~BrainOpenGLShapeRing(); private: BrainOpenGLShapeRing(const BrainOpenGLShapeRing&); BrainOpenGLShapeRing& operator=(const BrainOpenGLShapeRing&); public: // ADD_NEW_METHODS_HERE protected: void drawShape(const BrainOpenGL::DrawMode drawMode, const uint8_t rgba[4]); void drawShape(const BrainOpenGL::DrawMode drawMode, const float rgba[4]); void setupOpenGLForShape(const BrainOpenGL::DrawMode drawMode); private: // ADD_NEW_MEMBERS_HERE const int32_t m_numberOfSides; const float m_innerRadius; const float m_outerRadius; GLuint m_coordinatesBufferID; GLuint m_coordinatesRgbaByteBufferID; GLuint m_normalBufferID; GLuint m_triangleStripBufferID; GLuint m_displayList; std::vector m_coordinates; std::vector m_rgbaByte; std::vector m_normals; std::vector m_triangleStrip; bool m_isApplyColoring; }; #ifdef __BRAIN_OPEN_GL_SHAPE_RING_DECLARE__ // #endif // __BRAIN_OPEN_GL_SHAPE_RING_DECLARE__ } // namespace #endif //__BRAIN_OPEN_GL_SHAPE_RING_H_ connectome-workbench-1.4.2/src/Brain/BrainOpenGLShapeSphere.cxx000066400000000000000000000361661360521144700244450ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __BRAIN_OPEN_G_L_SHAPE_SPHERE_DECLARE__ #include "BrainOpenGLShapeSphere.h" #undef __BRAIN_OPEN_G_L_SHAPE_SPHERE_DECLARE__ #include "AString.h" #include "CaretAssert.h" #include "MathFunctions.h" using namespace caret; /** * \class caret::BrainOpenGLShapeSphere * \brief Create a spherical shape for use with OpenGL. */ /** * Constructor. */ BrainOpenGLShapeSphere::BrainOpenGLShapeSphere(const int32_t numberOfLatitudeAndLongitude, const float radius) : BrainOpenGLShape(), m_numberOfLatitudeAndLongitude(numberOfLatitudeAndLongitude), m_radius(radius) { m_isApplyColoring = true; bool debugFlag = false; const int numLat = m_numberOfLatitudeAndLongitude; const int numLon = m_numberOfLatitudeAndLongitude; const float degToRad = M_PI / 180.0; const float dLat = 180.0 / numLat; for (int iLat = 0; iLat < numLat; iLat++) { const float latDeg = -90.0 + (iLat * dLat); const float latRad = latDeg * degToRad; float z1 = m_radius * std::sin(latRad); const float latDeg2 = -90.0 + ((iLat + 1) * dLat); const float latRad2 = latDeg2 * degToRad; float z2 = m_radius * std::sin(latRad2); std::vector strip; if (debugFlag) std::cout << "Strip Start: " << std::endl; const float dLon = 360.0 / numLon; for (int iLon = 0; iLon <= numLon; iLon++) { const float lonDeg = iLon * dLon; const float lonRad = lonDeg * degToRad; float x1 = m_radius * std::cos(latRad) * std::cos(lonRad); float y1 = m_radius * std::cos(latRad) * std::sin(lonRad); if (iLat == 0) { x1 = 0.0; y1 = 0.0; z1 = -m_radius; } float x2 = m_radius * std::cos(latRad2) * std::cos(lonRad); float y2 = m_radius * std::cos(latRad2) * std::sin(lonRad); if (iLat == (numLat - 1)) { x2 = 0.0; y2 = 0.0; z2 = m_radius; } strip.push_back(static_cast(m_coordinates.size() / 3)); const int32_t indx1 = static_cast(m_coordinates.size() / 3); m_coordinates.push_back(x2); m_coordinates.push_back(y2); m_coordinates.push_back(z2); const float length2 = std::sqrt(x2*x2 + y2*y2 + z2*z2); m_normals.push_back(x2 / length2); m_normals.push_back(y2 / length2); m_normals.push_back(z2 / length2); strip.push_back(static_cast(m_coordinates.size() / 3)); const int32_t indx2 = static_cast(m_coordinates.size() / 3); m_coordinates.push_back(x1); m_coordinates.push_back(y1); m_coordinates.push_back(z1); const float length1 = std::sqrt(x1*x1 + y1*y1 + z1*z1); m_normals.push_back(x1 / length1); m_normals.push_back(y1 / length1); m_normals.push_back(z1 / length1); if (debugFlag) { std::cout << " " << iLat << ", " << iLon << std::endl; std::cout << " " << indx1 << ":" << latDeg << ", " << lonDeg << ", " << x1 << ", " << y1 << ", " << z1 << std::endl; std::cout << " " << indx2 << ":" << latDeg2 << ", " << lonDeg << ", " << x2 << ", " << y2 << ", " << z2 << std::endl; } } if (strip.empty() == false) { m_triangleStrips.push_back(strip); if (debugFlag) { const float* c1 = &m_coordinates[strip[0]* 3]; const float* c2 = &m_coordinates[strip[1]* 3]; const float* c3 = &m_coordinates[strip[2]* 3]; float normal[3]; MathFunctions::normalVector(c1, c2, c3, normal); std::cout << "Normal Vector" << qPrintable(AString::fromNumbers(normal, 3, ",")) << std::endl; } } if (debugFlag) std::cout << std::endl; } // if (debugFlag) { // const int32_t numTriangleStrips = m_triangleStrips.size(); // for (int32_t i = 0; i < numTriangleStrips; i++) { // std::cout << "Strip " << i << ":"; // printTriangleStrip(m_triangleStrips[i]); // } // } /* * Concatente into a single strip */ contatenateTriangleStrips(m_triangleStrips, m_singleTriangleStrip); if (debugFlag) { std::cout << "NEW STRIPS" << std::endl; const int32_t numTriangleStrips = m_triangleStrips.size(); for (int32_t i = 0; i < numTriangleStrips; i++) { std::cout << "Strip " << i << ":"; printTriangleStrip(m_triangleStrips[i]); } std::cout << "SINGLE STRIP: "; printTriangleStrip(m_singleTriangleStrip); } /* * Create storage for colors */ const int64_t numCoords = static_cast(m_coordinates.size()) / 3; const int64_t numRGBA = numCoords * 4; m_rgbaByte.resize(numRGBA * 4, 0); for (GLuint i = 0; i < numCoords; i++) { const int32_t i4 = i * 4; CaretAssertVectorIndex(m_rgbaByte, i4+3); m_rgbaByte[i4] = 0; m_rgbaByte[i4+1] = 0; m_rgbaByte[i4+2] = 0; m_rgbaByte[i4+3] = 255; } } /** * Destructor. */ BrainOpenGLShapeSphere::~BrainOpenGLShapeSphere() { } void BrainOpenGLShapeSphere::setupOpenGLForShape(const BrainOpenGL::DrawMode drawMode) { m_displayList = 0; m_vertexBufferID = 0; switch (drawMode) { case BrainOpenGL::DRAW_MODE_DISPLAY_LISTS: { m_displayList = createDisplayList(); if (m_displayList > 0) { glNewList(m_displayList, GL_COMPILE); uint8_t rgbaUnused[4] = { 0, 0, 0, 0 }; m_isApplyColoring = false; drawShape(BrainOpenGL::DRAW_MODE_IMMEDIATE, rgbaUnused); m_isApplyColoring = true; glEndList(); } } break; case BrainOpenGL::DRAW_MODE_IMMEDIATE: { /* nothing to do for this case */ } break; case BrainOpenGL::DRAW_MODE_INVALID: { CaretAssert(0); } break; case BrainOpenGL::DRAW_MODE_VERTEX_BUFFERS: #ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS /* * Put vertices (coordinates) into its buffer. */ m_vertexBufferID = createBufferID(); glBindBuffer(GL_ARRAY_BUFFER, m_vertexBufferID); glBufferData(GL_ARRAY_BUFFER, m_coordinates.size() * sizeof(GLfloat), &m_coordinates[0], GL_STATIC_DRAW); /* * For RGBA coloring */ m_vertexRgbaByteBufferID = createBufferID(); glBindBuffer(GL_ARRAY_BUFFER, m_vertexRgbaByteBufferID); glBufferData(GL_ARRAY_BUFFER, m_rgbaByte.size() * sizeof(GLubyte), &m_rgbaByte[0], GL_DYNAMIC_DRAW); /* * Put normals into its buffer. */ m_normalBufferID = createBufferID(); glBindBuffer(GL_ARRAY_BUFFER, m_normalBufferID); glBufferData(GL_ARRAY_BUFFER, m_normals.size() * sizeof(GLfloat), &m_normals[0], GL_STATIC_DRAW); /* * Put triangle strips into its buffer. */ m_triangleStripBufferID = createBufferID(); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_triangleStripBufferID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_singleTriangleStrip.size() * sizeof(GLuint), &m_singleTriangleStrip[0], GL_STATIC_DRAW); /* * Deselect active buffer. */ glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); #endif // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS break; } } /** * Draw the shape. * * @param drawMode * How to draw the shape. * @param rgba * RGBA coloring ranging 0.0 to 1.0 */ void BrainOpenGLShapeSphere::drawShape(const BrainOpenGL::DrawMode drawMode, const float rgba[4]) { const uint8_t rgbaByte[4] = { static_cast(rgba[0] * 255.0), static_cast(rgba[1] * 255.0), static_cast(rgba[2] * 255.0), static_cast(rgba[3] * 255.0) }; drawShape(drawMode, rgbaByte); } /** * Draw the shape. * * @param drawMode * How to draw the shape. * @param rgba * RGBA coloring ranging 0 to 255. */ void BrainOpenGLShapeSphere::drawShape(const BrainOpenGL::DrawMode drawMode, const uint8_t rgba[4]) { if (m_isApplyColoring) { glColor4ubv(rgba); } bool useOneTriangleStrip = true; switch (drawMode) { case BrainOpenGL::DRAW_MODE_DISPLAY_LISTS: { if (m_displayList > 0) { glCallList(m_displayList); } } break; case BrainOpenGL::DRAW_MODE_IMMEDIATE: if (useOneTriangleStrip) { const int32_t numVertices = static_cast(m_singleTriangleStrip.size()); glBegin(GL_TRIANGLE_STRIP); for (int32_t j = 0; j < numVertices; j++) { const int32_t vertexIndex = m_singleTriangleStrip[j] * 3; CaretAssertVectorIndex(m_normals, vertexIndex); CaretAssertVectorIndex(m_coordinates, vertexIndex); glNormal3fv(&m_normals[vertexIndex]); glVertex3fv(&m_coordinates[vertexIndex]); } glEnd(); } else { const int32_t numTriangleStrips = m_triangleStrips.size(); for (int32_t i = 0; i < numTriangleStrips; i++) { const std::vector& strip = m_triangleStrips[i]; const int32_t numVertices = static_cast(strip.size()); glBegin(GL_TRIANGLE_STRIP); for (int32_t j = 0; j < numVertices; j++) { const int32_t vertexIndex = strip[j] * 3; CaretAssertVectorIndex(m_normals, vertexIndex); CaretAssertVectorIndex(m_coordinates, vertexIndex); glNormal3fv(&m_normals[vertexIndex]); glVertex3fv(&m_coordinates[vertexIndex]); } glEnd(); } } break; case BrainOpenGL::DRAW_MODE_INVALID: { CaretAssert(0); } break; case BrainOpenGL::DRAW_MODE_VERTEX_BUFFERS: #ifdef BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_COLOR_ARRAY); /* * Set the vertices for drawing. */ glBindBuffer(GL_ARRAY_BUFFER, m_vertexBufferID); glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)0); /* * Put BYTE colors into its buffer */ const int64_t numRGBA = static_cast(m_rgbaByte.size()) / 4; for (int64_t ir = 0; ir < numRGBA; ir++) { const int64_t ir4 = ir * 4; m_rgbaByte[ir4] = rgba[0]; m_rgbaByte[ir4+1] = rgba[1]; m_rgbaByte[ir4+2] = rgba[2]; m_rgbaByte[ir4+3] = rgba[3]; } CaretAssert(glIsBuffer(m_vertexRgbaByteBufferID) == GL_TRUE); glBindBuffer(GL_ARRAY_BUFFER, m_vertexRgbaByteBufferID); glBufferData(GL_ARRAY_BUFFER, m_rgbaByte.size() * sizeof(GLubyte), &m_rgbaByte[0], GL_DYNAMIC_DRAW); glColorPointer(4, GL_UNSIGNED_BYTE, 0, (GLvoid*)0); /* * Set the normal vectors for drawing. */ glBindBuffer(GL_ARRAY_BUFFER, m_normalBufferID); glNormalPointer(GL_FLOAT, 0, (GLvoid*)0); /* * Draw the triangle strips. */ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_triangleStripBufferID); glDrawElements(GL_TRIANGLE_STRIP, m_singleTriangleStrip.size(), GL_UNSIGNED_INT, (GLvoid*)0); /* * Deselect active buffer. */ glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); #endif // BRAIN_OPENGL_INFO_SUPPORTS_VERTEX_BUFFERS break; } } connectome-workbench-1.4.2/src/Brain/BrainOpenGLShapeSphere.h000066400000000000000000000051331360521144700240600ustar00rootroot00000000000000#ifndef __BRAIN_OPEN_G_L_SHAPE_SPHERE__H_ #define __BRAIN_OPEN_G_L_SHAPE_SPHERE__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "BrainOpenGLShape.h" namespace caret { class BrainOpenGLShapeSphere : public BrainOpenGLShape { public: BrainOpenGLShapeSphere(const int32_t numberOfLatitudeAndLongitude, const float radius); virtual ~BrainOpenGLShapeSphere(); private: BrainOpenGLShapeSphere(const BrainOpenGLShapeSphere&); BrainOpenGLShapeSphere& operator=(const BrainOpenGLShapeSphere&); public: // ADD_NEW_METHODS_HERE protected: void drawShape(const BrainOpenGL::DrawMode drawMode, const uint8_t rgba[4]); void drawShape(const BrainOpenGL::DrawMode drawMode, const float rgba[4]); void setupOpenGLForShape(const BrainOpenGL::DrawMode drawMode); private: // ADD_NEW_MEMBERS_HERE const int32_t m_numberOfLatitudeAndLongitude; const float m_radius; GLuint m_vertexBufferID; GLuint m_vertexRgbaByteBufferID; GLuint m_normalBufferID; GLuint m_triangleStripBufferID; GLuint m_displayList; std::vector m_coordinates; std::vector m_normals; std::vector m_rgbaByte; std::vector > m_triangleStrips; std::vector m_singleTriangleStrip; bool m_isApplyColoring; }; #ifdef __BRAIN_OPEN_G_L_SHAPE_SPHERE_DECLARE__ // #endif // __BRAIN_OPEN_G_L_SHAPE_SPHERE_DECLARE__ } // namespace #endif //__BRAIN_OPEN_G_L_SHAPE_SPHERE__H_ connectome-workbench-1.4.2/src/Brain/BrainOpenGLTextRenderInterface.cxx000066400000000000000000000175101360521144700261330ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BRAIN_OPEN_G_L_TEXT_RENDER_INTERFACE_DECLARE__ #include "BrainOpenGLTextRenderInterface.h" #undef __BRAIN_OPEN_G_L_TEXT_RENDER_INTERFACE_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::BrainOpenGLTextRenderInterface * \brief Interface for rendering of text to OpenGL. * \ingroup test */ /** * Constructor. */ BrainOpenGLTextRenderInterface::BrainOpenGLTextRenderInterface() : CaretObject() { } /** * Destructor. */ BrainOpenGLTextRenderInterface::~BrainOpenGLTextRenderInterface() { } /** * Get the bounds of text (in pixels) using the given text * attributes. * * See http://ftgl.sourceforge.net/docs/html/metrics.png * * @param annotationText * Text that is to be drawn. * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. * @param viewportWidth * Widgth of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param bottomLeftOut * The bottom left corner of the text bounds. * @param bottomRightOut * The bottom right corner of the text bounds. * @param topRightOut * The top right corner of the text bounds. * @param topLeftOut * The top left corner of the text bounds. */ void BrainOpenGLTextRenderInterface::getBoundsForTextAtViewportCoords(const AnnotationText& annotationText, const DrawingFlags& flags, const float viewportX, const float viewportY, const float viewportZ, const float viewportWidth, const float viewportHeight, float bottomLeftOut[3], float bottomRightOut[3], float topRightOut[3], float topLeftOut[3]) { double bottomLeft[3]; double bottomRight[3]; double topRight[3]; double topLeft[3]; getBoundsForTextAtViewportCoords(annotationText, flags, viewportX, viewportY, viewportZ, viewportWidth, viewportHeight, bottomLeft, bottomRight, topRight, topLeft); for (int32_t i = 0; i < 3; i++) { bottomLeftOut[i] = bottomLeft[i]; bottomRightOut[i] = bottomRight[i]; topRightOut[i] = topRight[i]; topLeftOut[i] = topLeft[i]; } } /** * Get the bounds of text (in pixels) using the given text * attributes. NO MARGIN is placed around the text. * * See http://ftgl.sourceforge.net/docs/html/metrics.png * * @param annotationText * Text that is to be drawn. * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. * @param viewportWidth * Widgth of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param bottomLeftOut * The bottom left corner of the text bounds. * @param bottomRightOut * The bottom right corner of the text bounds. * @param topRightOut * The top right corner of the text bounds. * @param topLeftOut * The top left corner of the text bounds. */ void BrainOpenGLTextRenderInterface::getBoundsWithoutMarginForTextAtViewportCoords(const AnnotationText& annotationText, const DrawingFlags& flags, const float viewportX, const float viewportY, const float viewportZ, const float viewportWidth, const float viewportHeight, float bottomLeftOut[3], float bottomRightOut[3], float topRightOut[3], float topLeftOut[3]) { double bottomLeft[3]; double bottomRight[3]; double topRight[3]; double topLeft[3]; getBoundsWithoutMarginForTextAtViewportCoords(annotationText, flags, viewportX, viewportY, viewportZ, viewportWidth, viewportHeight, bottomLeft, bottomRight, topRight, topLeft); for (int32_t i = 0; i < 3; i++) { bottomLeftOut[i] = bottomLeft[i]; bottomRightOut[i] = bottomRight[i]; topRightOut[i] = topRight[i]; topLeftOut[i] = topLeft[i]; } } /** * Convert point size to pixels. * One point is 1/72 inch. * * @param pointSize * The point size. * @return * The size in pixels. */ float BrainOpenGLTextRenderInterface::pointSizeToPixels(const float pointSize) { const float inches = pointSize / 72.0; float pixels = inches * s_pixelsPerInch; return pixels; } /** * Convert pixels to point size. * One point is 1/72 inch. * * @param pixels * The pixel size. * @return * The point size. */ float BrainOpenGLTextRenderInterface::pixelsToPointSize(const float pixels) { const float inches = pixels / s_pixelsPerInch; const float pointSize = 72.0 * inches; return pointSize; } /** * @return The pixels per inch (PPI). */ float BrainOpenGLTextRenderInterface::getPixelsPerInch() { return s_pixelsPerInch; } /** * Set the pixels per inch. * * @param pixelsPerInch * The new value for pixels per inch. */ void BrainOpenGLTextRenderInterface::setPixelsPerInch(const float pixelsPerInch) { s_pixelsPerInch = pixelsPerInch; } connectome-workbench-1.4.2/src/Brain/BrainOpenGLTextRenderInterface.h000066400000000000000000000456471360521144700255740ustar00rootroot00000000000000#ifndef __BRAIN_OPEN_G_L_TEXT_RENDER_INTERFACE__H_ #define __BRAIN_OPEN_G_L_TEXT_RENDER_INTERFACE__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" namespace caret { class AnnotationText; class BrainOpenGLTextRenderInterface : public CaretObject { protected: BrainOpenGLTextRenderInterface(); public: /** * Flags for drawing text. */ class DrawingFlags { public: /** * Constructor with all flags off. */ DrawingFlags() { } /** * @return Is draw substituted text flag on? */ inline bool isDrawSubstitutedText() const { return m_drawSubstitutedText; } /** * Set flag for drawing substituted text. * * @param flag * New status. */ inline void setDrawSubstitutedText(const bool flag) { m_drawSubstitutedText = flag; } private: bool m_drawSubstitutedText = false; }; virtual ~BrainOpenGLTextRenderInterface(); /** * Draw annnotation text at the given viewport coordinates using * the the annotations attributes for the style of text. * * Depth testing is DISABLED when drawing text with this method. * * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param annotationText * Annotation text and attributes. * @param flags * Drawing flags. */ virtual void drawTextAtViewportCoords(const double viewportX, const double viewportY, const AnnotationText& annotationText, const DrawingFlags& flags) = 0; /** * Draw annnotation text at the given viewport coordinates using * the the annotations attributes for the style of text. * * Depth testing is ENABLED when drawing text with this method. * * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. * @param annotationText * Annotation text and attributes. * @param flags * Drawing flags. */ virtual void drawTextAtViewportCoords(const double viewportX, const double viewportY, const double viewportZ, const AnnotationText& annotationText, const DrawingFlags& flags) = 0; /** * Draw annnotation text at the given model coordinates using * the the annotations attributes for the style of text. * Text is drawn so that is in the plane of the screen (faces user) * * Depth testing is ENABLED when drawing text with this method. * * @param modelX * Model X-coordinate. * @param modelY * Model Y-coordinate. * @param modelZ * Model Z-coordinate. * @param annotationText * Annotation text and attributes. * @param flags * Drawing flags. */ virtual void drawTextAtModelCoordsFacingUser(const double modelX, const double modelY, const double modelZ, const AnnotationText& annotationText, const DrawingFlags& flags) = 0; /** * Draw annnotation text at the given model coordinates using * the the annotations attributes for the style of text. * Text is drawn so that is in the plane of the screen (faces user) * * Depth testing is ENABLED when drawing text with this method. * * @param modelXYZ * Model XYZ coordinate. * @param annotationText * Annotation text and attributes. * @param flags * Drawing flags. */ void drawTextAtModelCoordsFacingUser(const double modelXYZ[3], const AnnotationText& annotationText, const DrawingFlags& flags) { drawTextAtModelCoordsFacingUser(modelXYZ[0], modelXYZ[1], modelXYZ[2], annotationText, flags); } /** * Draw annnotation text at the given model coordinates using * the the annotations attributes for the style of text. * Text is drawn so that is in the plane of the screen (faces user) * * Depth testing is ENABLED when drawing text with this method. * * @param modelXYZ * Model XYZ coordinate. * @param annotationText * Annotation text and attributes. * @param flags * Drawing flags. */ void drawTextAtModelCoordsFacingUser(const float modelXYZ[3], const AnnotationText& annotationText, const DrawingFlags& flags) { drawTextAtModelCoordsFacingUser(modelXYZ[0], modelXYZ[1], modelXYZ[2], annotationText, flags); } /** * Get the bounds of text drawn in model space using the current model transformations. * * @param annotationText * Text that is to be drawn. * @param modelSpaceScaling * Scaling in the model space. * @param heightOrWidthForPercentageSizeText * Size of region used when converting percentage size to a fixed size * @param flags * Drawing flags. * @param bottomLeftOut * The bottom left corner of the text bounds. * @param bottomRightOut * The bottom right corner of the text bounds. * @param topRightOut * The top right corner of the text bounds. * @param topLeftOut * The top left corner of the text bounds. * @param underlineStartOut * Starting coordinate for drawing text underline. * @param underlineEndOut * Ending coordinate for drawing text underline. */ virtual void getBoundsForTextInModelSpace(const AnnotationText& annotationText, const float modelSpaceScaling, const float heightOrWidthForPercentageSizeText, const DrawingFlags& flags, double bottomLeftOut[3], double bottomRightOut[3], double topRightOut[3], double topLeftOut[3], double underlineStartOut[3], double underlineEndOut[3]) = 0; /** * Draw text in model space using the current model transformations. * * Depth testing is ENABLED when drawing text with this method. * * @param annotationText * Annotation text and attributes. * @param modelSpaceScaling * Scaling in the model space. * @param heightOrWidthForPercentageSizeText * If positive, use it to override width/height of viewport. * @param backgroundOverrideRGBA * If alpha is greater that zero, draw background with this color * @param flags * Drawing flags. */ virtual void drawTextInModelSpace(const AnnotationText& annotationText, const float modelSpaceScaling, const float heightOrWidthForPercentageSizeText, const float normalVector[3], const DrawingFlags& flags) = 0; /** * Get the estimated width and height of text (in pixels) using the given text * attributes. * * See http://ftgl.sourceforge.net/docs/html/metrics.png * * @param annotationText * Text for width and height estimation. * @param viewportWidth * Width of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param widthOut * Estimated width of text. * @param heightOut * Estimated height of text. */ virtual void getTextWidthHeightInPixels(const AnnotationText& annotationText, const DrawingFlags& flags, const double viewportWidth, const double viewportHeight, double& widthOut, double& heightOut) = 0; /** * Get the bounds of text (in pixels) using the given text * attributes. * * See http://ftgl.sourceforge.net/docs/html/metrics.png * * @param annotationText * Text that is to be drawn. * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. * @param viewportWidth * Width of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param bottomLeftOut * The bottom left corner of the text bounds. * @param bottomRightOut * The bottom right corner of the text bounds. * @param topRightOut * The top right corner of the text bounds. * @param topLeftOut * The top left corner of the text bounds. */ virtual void getBoundsForTextAtViewportCoords(const AnnotationText& annotationText, const DrawingFlags& flags, const double viewportX, const double viewportY, const double viewportZ, const double viewportWidth, const double viewportHeight, double bottomLeftOut[3], double bottomRightOut[3], double topRightOut[3], double topLeftOut[3]) = 0; /** * Get the bounds of text (in pixels) using the given text * attributes. NO MARGIN is placed around the text. * * See http://ftgl.sourceforge.net/docs/html/metrics.png * * @param annotationText * Text that is to be drawn. * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. * @param viewportWidth * Width of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param bottomLeftOut * The bottom left corner of the text bounds. * @param bottomRightOut * The bottom right corner of the text bounds. * @param topRightOut * The top right corner of the text bounds. * @param topLeftOut * The top left corner of the text bounds. */ virtual void getBoundsWithoutMarginForTextAtViewportCoords(const AnnotationText& annotationText, const DrawingFlags& flags, const double viewportX, const double viewportY, const double viewportZ, const double viewportWidth, const double viewportHeight, double bottomLeftOut[3], double bottomRightOut[3], double topRightOut[3], double topLeftOut[3]) = 0; /** * Get the bounds of text (in pixels) using the given text * attributes. * * See http://ftgl.sourceforge.net/docs/html/metrics.png * * @param annotationText * Text that is to be drawn. * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. * @param viewportWidth * Width of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param bottomLeftOut * The bottom left corner of the text bounds. * @param bottomRightOut * The bottom right corner of the text bounds. * @param topRightOut * The top right corner of the text bounds. * @param topLeftOut * The top left corner of the text bounds. */ void getBoundsForTextAtViewportCoords(const AnnotationText& annotationText, const DrawingFlags& flags, const float viewportX, const float viewportY, const float viewportZ, const float viewportWidth, const float viewportHeight, float bottomLeftOut[3], float bottomRightOut[3], float topRightOut[3], float topLeftOut[3]); /** * Get the bounds of text (in pixels) using the given text * attributes. NO MARGIN is placed around the text. * * See http://ftgl.sourceforge.net/docs/html/metrics.png * * @param annotationText * Text that is to be drawn. * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. * @param viewportWidth * Width of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param bottomLeftOut * The bottom left corner of the text bounds. * @param bottomRightOut * The bottom right corner of the text bounds. * @param topRightOut * The top right corner of the text bounds. * @param topLeftOut * The top left corner of the text bounds. */ void getBoundsWithoutMarginForTextAtViewportCoords(const AnnotationText& annotationText, const DrawingFlags& flags, const float viewportX, const float viewportY, const float viewportZ, const float viewportWidth, const float viewportHeight, float bottomLeftOut[3], float bottomRightOut[3], float topRightOut[3], float topLeftOut[3]); static float pointSizeToPixels(const float pointSize); static float pixelsToPointSize(const float pixels); static float getPixelsPerInch(); static void setPixelsPerInch(const float pixelsPerInch); /** * @return The font system is valid. */ virtual bool isValid() const = 0; /** * @return Name of the text renderer. */ virtual AString getName() const = 0; private: BrainOpenGLTextRenderInterface(const BrainOpenGLTextRenderInterface&); BrainOpenGLTextRenderInterface& operator=(const BrainOpenGLTextRenderInterface&); private: static float s_pixelsPerInch; }; #ifdef __BRAIN_OPEN_G_L_TEXT_RENDER_INTERFACE_DECLARE__ float BrainOpenGLTextRenderInterface::s_pixelsPerInch = 72.0; #endif // __BRAIN_OPEN_G_L_TEXT_RENDER_INTERFACE_DECLARE__ } // namespace #endif //__BRAIN_OPEN_G_L_TEXT_RENDER_INTERFACE__H_ connectome-workbench-1.4.2/src/Brain/BrainOpenGLViewportContent.cxx000066400000000000000000001421451360521144700254030ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BRAIN_OPEN_G_L_VIEWPORT_CONTENT_DECLARE__ #include "BrainOpenGLViewportContent.h" #undef __BRAIN_OPEN_G_L_VIEWPORT_CONTENT_DECLARE__ #include #include #include #include #include "BrowserTabContent.h" #include "BrowserWindowContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "EventBrowserWindowContent.h" #include "EventManager.h" #include "EventSpacerTabGet.h" #include "GapsAndMargins.h" #include "MathFunctions.h" #include "ModelSurfaceMontage.h" #include "SpacerTabContent.h" #include "SurfaceMontageConfigurationAbstract.h" #include "TileTabsConfiguration.h" using namespace caret; /** * \class BrainOpenGLViewportContent * \brief Dimensions and model for a viewport in the graphics window. * * Dimensions and model for a viewport in the graphics window. */ /** * Constructor. * * @param windowViewport * Viewport of WINDOW in which drawing takes place. * @param tabViewport * Viewport for TAB in which drawing takes place. * @param modelViewport * Viewport for MODEL in which drawing takes place. * @param windowIndex * Index of browser window. * @param highlightTabFlag * True indicates that the tab is highlighted (used in * Tile Tabs mode so user knows graphics region corresponding * to the tab that was recently selected). * @param browserTabContent * Browser Tab content that is being drawn (if not NULL) * @param spacerTabContent * Spacer Tab content that is being drawn (if not NULL) */ BrainOpenGLViewportContent::BrainOpenGLViewportContent(const int windowViewport[4], const int tabViewport[4], const int modelViewport[4], const int windowIndex, const bool highlightTabFlag, BrowserTabContent* browserTabContent, SpacerTabContent* spacerTabContent) : CaretObject(), m_windowIndex(windowIndex), m_highlightTab(highlightTabFlag), m_browserTabContent(browserTabContent), m_spacerTabContent(spacerTabContent) { m_windowX = windowViewport[0]; m_windowY = windowViewport[1]; m_windowWidth = windowViewport[2]; m_windowHeight = windowViewport[3]; m_tabX = tabViewport[0]; m_tabY = tabViewport[1]; m_tabWidth = tabViewport[2]; m_tabHeight = tabViewport[3]; m_modelX = modelViewport[0]; m_modelY = modelViewport[1]; m_modelWidth = modelViewport[2]; m_modelHeight = modelViewport[3]; m_chartDataProjectionMatrix.identity(); m_chartDataModelViewMatrix.identity(); m_chartDataX = 0; m_chartDataY = 0; m_chartDataWidth = 0; m_chartDataHeight = 0; m_chartDataViewportValidFlag = false; } /** * Destructor. */ BrainOpenGLViewportContent::~BrainOpenGLViewportContent() { } /** * Copy constructor. * @param obj * Object that is copied. */ BrainOpenGLViewportContent::BrainOpenGLViewportContent(const BrainOpenGLViewportContent& obj) : CaretObject(obj), m_windowIndex(obj.m_windowIndex), m_highlightTab(obj.m_highlightTab) { this->initializeMembersBrainOpenGLViewportContent(); this->copyHelperBrainOpenGLViewportContent(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ BrainOpenGLViewportContent& BrainOpenGLViewportContent::operator=(const BrainOpenGLViewportContent& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperBrainOpenGLViewportContent(obj); } return *this; } /** * Initialize members of a new instance. */ void BrainOpenGLViewportContent::initializeMembersBrainOpenGLViewportContent() { m_chartDataProjectionMatrix.identity(); m_chartDataModelViewMatrix.identity(); m_chartDataX = 0; m_chartDataY = 0; m_chartDataWidth = 0; m_chartDataHeight = 0; m_chartDataViewportValidFlag = false; m_modelX = 0; m_modelY = 0; m_modelWidth = 0; m_modelHeight = 0; m_tabX = 0; m_tabY = 0; m_tabWidth = 0; m_tabHeight = 0; m_windowX = 0; m_windowY = 0; m_windowWidth = 0; m_windowHeight = 0; m_browserTabContent = NULL; m_spacerTabContent = NULL; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void BrainOpenGLViewportContent::copyHelperBrainOpenGLViewportContent(const BrainOpenGLViewportContent& obj) { m_chartDataProjectionMatrix = obj.m_chartDataProjectionMatrix; m_chartDataModelViewMatrix = obj.m_chartDataModelViewMatrix; m_chartDataX = obj.m_chartDataX; m_chartDataY = obj.m_chartDataY; m_chartDataWidth = obj.m_chartDataWidth; m_chartDataHeight = obj.m_chartDataHeight; m_chartDataViewportValidFlag = obj.m_chartDataViewportValidFlag; m_modelX = obj.m_modelX; m_modelY = obj.m_modelY; m_modelWidth = obj.m_modelWidth; m_modelHeight = obj.m_modelHeight; m_tabX = obj.m_tabX; m_tabY = obj.m_tabY; m_tabWidth = obj.m_tabWidth; m_tabHeight = obj.m_tabHeight; m_windowX = obj.m_windowX; m_windowY = obj.m_windowY; m_windowWidth = obj.m_windowWidth; m_windowHeight = obj.m_windowHeight; m_browserTabContent = obj.m_browserTabContent; m_spacerTabContent = obj.m_spacerTabContent; } /** * Adjust the width/height using the aspect ratio */ void BrainOpenGLViewportContent::adjustWidthHeightForAspectRatio(const float aspectRatio, int32_t& width, int32_t& height) { if (aspectRatio > 0.0) { int32_t heightInt = height; float widthFloat = width; float heightFloat = height; float preferredHeightFloat = MathFunctions::round(widthFloat * aspectRatio); const int32_t preferredHeightInt = static_cast(preferredHeightFloat); if (heightInt == preferredHeightInt) { /* * Viewport matches aspect ratio so do not need to * adjust the width and height. * * Due to floating point error, when lock is enabled, * the preferred height may be a very small difference * from the current height. So rounding and then * converting to an int prevents the graphics region * from a small resizing. */ } else if (preferredHeightFloat > heightFloat) { /* * Shrink width */ const float percentage = heightFloat / preferredHeightFloat; width = static_cast(widthFloat * percentage); } else { /* * Shrink height */ height = preferredHeightInt; } } } /** * Adjust the given viewport by applying the given aspect ratio. * * Sets the new height to be width * aspect ratio. If this new height * is too tall, the viewport width and height is scaled down so that * the height fits the original viewport size and the viewport is * horizontally centered. If the new height is less than the original * height, the viewport is centered vertically. * * @param viewport * The viewport * @param aspectRatio * The aspect ratio (height ~= width * aspect ratio) */ void BrainOpenGLViewportContent::adjustViewportForAspectRatio(int viewport[4], const float aspectRatio) { int32_t heightInt = viewport[3]; float widthFloat = viewport[2]; float heightFloat = viewport[3]; float preferredHeightFloat = MathFunctions::round(widthFloat * aspectRatio); const int32_t preferredHeightInt = static_cast(preferredHeightFloat); if (heightInt == preferredHeightInt) { /* * Due to floating point error, when lock is enabled, * the preferred height may be a very small difference * from the current height. So rounding and then * converting to an int prevents the graphics region * from a small resizing. */ } else if (preferredHeightFloat > heightFloat) { const float percentage = heightFloat / preferredHeightFloat; widthFloat *= percentage; const float xOffset = (viewport[2] - widthFloat) / 2.0; viewport[0] += xOffset; viewport[2] = widthFloat; } else { const float yOffset = (viewport[3] - preferredHeightFloat) / 2.0; viewport[1] += yOffset; viewport[3] = preferredHeightFloat; } } /** * @return True indicates that the tab is highlighted (used in * Tile Tabs mode so user knows graphics region corresponding * to the tab that was recently selected). */ bool BrainOpenGLViewportContent::isTabHighlighted() const { return m_highlightTab; } /** * Get the data bounds and viewport for drawing the chart data. * * @param chartDataProjectionMatrixOut * Output into which projection matrix for drawing chart data loaded. * @param chartDataModelViewMatrixOut * Output into which model viewing matrix for drawing chart data loaded. * @param chartViewportOut * Output into which viewport is loaded. * (x, y, width, height) * @return * True if the chart data viewport is valid. */ bool BrainOpenGLViewportContent::getChartDataMatricesAndViewport(Matrix4x4& chartDataProjectionMatrixOut, Matrix4x4& chartDataModelViewMatrixOut, int chartViewportOut[4]) const { chartDataProjectionMatrixOut = m_chartDataProjectionMatrix; chartDataModelViewMatrixOut = m_chartDataModelViewMatrix; chartViewportOut[0] = m_chartDataX; chartViewportOut[1] = m_chartDataY; chartViewportOut[2] = m_chartDataWidth; chartViewportOut[3] = m_chartDataHeight; return m_chartDataViewportValidFlag; } /** * Set the viewport for drawing the chart data. * * @param chartDataProjectionMatrix * Pojection matrix for drawing chart data. * @param chartDataModelViewMatrix * Viewing matrix for drawing chart data. * @param chartDataViewport * Viewport (x, y, width, height). */ void BrainOpenGLViewportContent::setChartDataMatricesAndViewport(const Matrix4x4& chartDataProjectionMatrix, const Matrix4x4& chartDataModelViewMatrix, const int chartViewport[4]) const { m_chartDataProjectionMatrix = chartDataProjectionMatrix; m_chartDataModelViewMatrix = chartDataModelViewMatrix; m_chartDataX = chartViewport[0]; m_chartDataY = chartViewport[1]; m_chartDataWidth = chartViewport[2]; m_chartDataHeight = chartViewport[3]; m_chartDataViewportValidFlag = true; } /** * Get the viewport for drawing the model (has been reduced * from tab viewport by applying the margin). * * @param modelViewport * Output into which model viewport dimensions are loaded. * (x, y, width, height) */ void BrainOpenGLViewportContent::getModelViewport(int modelViewport[4]) const { modelViewport[0] = m_modelX; modelViewport[1] = m_modelY; modelViewport[2] = m_modelWidth; modelViewport[3] = m_modelHeight; } /** * Get the viewport for drawing the tab (includes margin). * * @param tabViewport * Output into which tab viewport dimensions are loaded. * (x, y, width, height) */ void BrainOpenGLViewportContent::getTabViewportBeforeApplyingMargins(int tabViewportOut[4]) const { tabViewportOut[0] = m_tabX; tabViewportOut[1] = m_tabY; tabViewportOut[2] = m_tabWidth; tabViewportOut[3] = m_tabHeight; } /** * @return Pointer to the viewport for the window. * * @param windowViewportOut * Output into which window viewport dimensions are loaded. * (x, y, width, height) */ void BrainOpenGLViewportContent::getWindowViewport(int windowViewportOut[4]) const { windowViewportOut[0] = m_windowX; windowViewportOut[1] = m_windowY; windowViewportOut[2] = m_windowWidth; windowViewportOut[3] = m_windowHeight; } /** * @return The window index. */ int BrainOpenGLViewportContent::getWindowIndex() const { return m_windowIndex; } /** * @return Pointer to browser tab content in viewport (NULL if no browser tab in viewport) */ BrowserTabContent* BrainOpenGLViewportContent::getBrowserTabContent() const { return m_browserTabContent; } /** * @return Pointer to spacer tab content in viewport (NULL if no spacer tab in viewport) */ SpacerTabContent* BrainOpenGLViewportContent::getSpacerTabContent() const { return m_spacerTabContent; } /** * @return Index of browser tab or -1 if there is not browser tab for this viewport. */ int32_t BrainOpenGLViewportContent::getTabIndex() const { if (m_browserTabContent != NULL) { return m_browserTabContent->getTabNumber(); } return -1; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString BrainOpenGLViewportContent::toString() const { const QString windowMsg = QString(" Window x=%1 y=%2 w=%3 h=%4").arg(m_windowX).arg(m_windowY).arg(m_windowWidth).arg(m_windowHeight); const QString tabMsg = QString(" Tab x=%1 y=%2 w=%3 h=%4").arg(m_tabX).arg(m_tabY).arg(m_tabWidth).arg(m_tabHeight); const QString modelMsg = QString(" Model x=%1 y=%2 w=%3 h=%4").arg(m_modelX).arg(m_modelY).arg(m_modelWidth).arg(m_modelHeight); AString msgOut; if (m_chartDataViewportValidFlag) { const QString chartProjectionMsg = QString(" Chart Projection=" + m_chartDataProjectionMatrix.toFormattedString(" ")); const QString chartModelMsg = QString(" Chart Model View=" + m_chartDataModelViewMatrix.toFormattedString(" ")); const QString chartViewportMsg = QString(" Chart x=%1 y=%2 w=%3 h=%4").arg(m_chartDataX).arg(m_chartDataY).arg(m_chartDataWidth).arg(m_chartDataHeight); msgOut.appendWithNewLine(chartProjectionMsg); msgOut.appendWithNewLine(chartModelMsg); msgOut.appendWithNewLine(chartViewportMsg); } else { msgOut.appendWithNewLine(" Chart Invalid."); } msgOut.appendWithNewLine(windowMsg); msgOut.appendWithNewLine(tabMsg); msgOut.appendWithNewLine(modelMsg); return msgOut; } /** * Create viewport contents for a single tab using the given window content and window sizes. * * @param browserTabContent * Tab's content that is being drawn. * @param gapsAndMargins * Gaps and margins * @param windowIndex * Index of browser window. * @param windowViewport * Viewport of WINDOW in which drawing takes place. * @return * Viewport content for the single tab. */ BrainOpenGLViewportContent* BrainOpenGLViewportContent::createViewportForSingleTab(std::vector& allTabContents, BrowserTabContent* selectedTabContent, const GapsAndMargins* gapsAndMargins, const int32_t windowIndex, const int32_t windowViewport[4]) { int tabViewport[4] = { windowViewport[0], windowViewport[1], windowViewport[2], windowViewport[3] }; int modelViewport[4] = { tabViewport[0], tabViewport[1], tabViewport[2], tabViewport[3] }; std::unique_ptr eventContent = EventBrowserWindowContent::getWindowContent(windowIndex); EventManager::get()->sendEvent(eventContent->getPointer()); const BrowserWindowContent* browserWindowContent = eventContent->getBrowserWindowContent(); CaretAssert(browserWindowContent); if (browserWindowContent->isAllTabsInWindowAspectRatioLocked()) { /** * Update aspect locking for any tabs that have not bee locked * Locking is done here so that it will work for new tabs and * for tabs from old scenes before "lock all". * Aspect locking is also performed here so that it works * with both GUI and Command Line Show Scene */ for (auto btc : allTabContents) { if ( ! btc->isAspectRatioLocked()) { if (tabViewport[2] > 0) { const float aspectRatio = (static_cast(tabViewport[3]) / static_cast(tabViewport[2])); btc->setAspectRatio(aspectRatio); btc->setAspectRatioLocked(true); } } } } if (selectedTabContent != NULL) { if (selectedTabContent->isAspectRatioLocked()) { const float aspectRatio = selectedTabContent->getAspectRatio(); BrainOpenGLViewportContent::adjustViewportForAspectRatio(tabViewport, aspectRatio); } const int32_t tabIndex = selectedTabContent->getTabNumber(); createModelViewport(tabViewport, tabIndex, gapsAndMargins, modelViewport); } BrainOpenGLViewportContent* vpContent = new BrainOpenGLViewportContent(windowViewport, tabViewport, modelViewport, windowIndex, false, selectedTabContent, NULL); /* no spacer tab */ return vpContent; } /** * Create Viewport Contents for the given tab contents, window sizes, and tile sizes. * * @param tabContents * Content of each tab. * @param browserWindowContent * Content of window. * @param gapsAndMargins * Contains margins around edges of tabs * @param windowViewport * The window's viewport. * @param windowIndex * Index of the window. * @param hightlightTabIndex * Index of tab that is highlighted when selected by user. * @return * Vector containing data for drawing each model. */ std::vector BrainOpenGLViewportContent::createViewportContentForTileTabs(std::vector& tabContents, BrowserWindowContent* browserWindowContent, const GapsAndMargins* gapsAndMargins, const int32_t windowViewport[4], const int32_t windowIndex, const int32_t highlightTabIndex) { CaretAssert(browserWindowContent); CaretAssert(gapsAndMargins); std::vector viewportContentsOut; const int32_t numberOfTabs = static_cast(tabContents.size()); if (numberOfTabs <= 0) { return viewportContentsOut; } int32_t windowX = windowViewport[0]; int32_t windowY = windowViewport[1]; const int32_t windowWidth = windowViewport[2]; const int32_t windowHeight = windowViewport[3]; /* * The tile tabs configuration provides the sizes of the * rows and columns. The user may "stretch" rows and/or * columns. Thus, the tabs viewports may not be uniformly sized. */ std::vector rowHeights; std::vector columnWidths; TileTabsConfiguration* tileTabsConfiguration = browserWindowContent->getSelectedTileTabsConfiguration(); tileTabsConfiguration->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, windowHeight, numberOfTabs, browserWindowContent->getTileTabsConfigurationMode(), rowHeights, columnWidths); const int32_t numRows = static_cast(rowHeights.size()); const int32_t numColumns = static_cast(columnWidths.size()); const int32_t numCells = numRows * numColumns; if (numCells <= 0) { return viewportContentsOut; } CaretAssert(numRows > 0); CaretAssert(numColumns > 0); const bool allTabsAspectLockedFlag = browserWindowContent->isAllTabsInWindowAspectRatioLocked(); /* * Create the sizes for the tabs before and after application * of aspect ratio. */ std::vector tabSizeInfoVector; int32_t iTab = 0; for (int32_t iRowFromTop = 0; iRowFromTop < numRows; iRowFromTop++) { CaretAssertVectorIndex(rowHeights, iRowFromTop); const int32_t vpHeight = rowHeights[iRowFromTop]; for (int32_t jCol = 0; jCol < numColumns; jCol++) { bool spacerTabFlag = false; const TileTabsGridRowColumnContentTypeEnum::Enum rowContentType = tileTabsConfiguration->getRow(iRowFromTop)->getContentType(); switch (rowContentType) { case TileTabsGridRowColumnContentTypeEnum::SPACE: spacerTabFlag = true; break; case TileTabsGridRowColumnContentTypeEnum::TAB: break; } const TileTabsGridRowColumnContentTypeEnum::Enum tabContentType = tileTabsConfiguration->getColumn(jCol)->getContentType(); switch (tabContentType) { case TileTabsGridRowColumnContentTypeEnum::SPACE: spacerTabFlag = true; break; case TileTabsGridRowColumnContentTypeEnum::TAB: break; } CaretAssertVectorIndex(columnWidths, jCol); const int32_t vpWidth = columnWidths[jCol]; if (spacerTabFlag) { EventSpacerTabGet spacerTabEvent(windowIndex, iRowFromTop, jCol); EventManager::get()->sendEvent(spacerTabEvent.getPointer()); SpacerTabContent* spacerTabContent = spacerTabEvent.getSpacerTabContent(); if (spacerTabContent != NULL) { BrowserTabContent* invalidBrowserTab(NULL); TileTabsViewportSizingInfo tsi(invalidBrowserTab, spacerTabContent, iRowFromTop, jCol, vpWidth, vpHeight); tabSizeInfoVector.push_back(tsi); } else { AString msg("Failed to get SpacerTabContent for windowIndex=%1, row=%2, column=%3"); msg = msg.arg(windowIndex).arg(iRowFromTop).arg(jCol); CaretLogSevere(msg); } } else if (iTab < numberOfTabs) { CaretAssertVectorIndex(tabContents, iTab); /* * Is aspect ratio locked for all tabs ? */ if (allTabsAspectLockedFlag) { /** * Update aspect locking for any tabs that have not been locked * Locking is done here so that it will work for new tabs and * for tabs from old scenes before "lock all" * Aspect locking is also performed here so that it works * with both GUI and Command Line Show Scene */ if ( ! tabContents[iTab]->isAspectRatioLocked()) { if (vpWidth > 0) { const float aspectRatio = (static_cast(vpHeight) / static_cast(vpWidth)); tabContents[iTab]->setAspectRatio(aspectRatio); tabContents[iTab]->setAspectRatioLocked(true); } } } /* * Note: the constructor will adjust the width and * height if lock aspect ratio is enabled. */ SpacerTabContent* invalidSpacerTab(NULL); TileTabsViewportSizingInfo tsi(tabContents[iTab], invalidSpacerTab, iRowFromTop, jCol, vpWidth, vpHeight); tabSizeInfoVector.push_back(tsi); iTab++; } } } if (tileTabsConfiguration->isCenteringCorrectionEnabled()) { /* * Kludge that fixes old scenes * NEED TO ADJUST FOR X too ? * THIS WILL NEED TO BE AN OPTION SOMEWHERE * TRY MORE THAN TWO ROWS */ std::vector tabRowHeights(numRows, 0); std::vector tabColumnWidths(numColumns, 0); { for (auto tsi : tabSizeInfoVector) { const int32_t rowIndex = tsi.m_rowIndexFromTop; tabRowHeights[rowIndex] = std::max(tabRowHeights[rowIndex], tsi.m_height); const int32_t columnIndex(tsi.m_columnIndex); tabColumnWidths[columnIndex] = std::max(tabColumnWidths[columnIndex], tsi.m_width); } for (int32_t i = 0; i < numRows; i++) { rowHeights[i] = tabRowHeights[i]; } for (int32_t i = 0; i < numColumns; i++) { columnWidths[i] = tabColumnWidths[i]; } } const int32_t allTabsHeight = std::accumulate(tabRowHeights.begin(), tabRowHeights.end(), 0); windowY -= ((windowHeight - allTabsHeight) / 2); const int32_t allTabsWidth = std::accumulate(tabColumnWidths.begin(), tabColumnWidths.end(), 0); const int32_t offset = (windowWidth - allTabsWidth) / 2; windowX += offset; } /* * Note: There may be more tabs than there are cells (rows * columns) * so some tabs may not be displayed. */ const int32_t numberOfDisplayedTabs = static_cast(tabSizeInfoVector.size()); /* * Set the X and Y-coordinates for the tab viewports * We start at the bottom row, left corner. */ int32_t vpY = windowHeight + windowY; for (int32_t iRow = 0; iRow < numRows; iRow++) { CaretAssertVectorIndex(rowHeights, iRow); vpY -= rowHeights[iRow]; int32_t vpX = windowX; for (int32_t jCol = 0; jCol < numColumns; jCol++) { TileTabsViewportSizingInfo* tabSizePtr = NULL; for (int32_t iTab = 0; iTab < numberOfDisplayedTabs; iTab++) { CaretAssertVectorIndex(tabSizeInfoVector, iTab); if ((tabSizeInfoVector[iTab].m_rowIndexFromTop == iRow) && (tabSizeInfoVector[iTab].m_columnIndex == jCol)) { tabSizePtr = &tabSizeInfoVector[iTab]; break; } } if (tabSizePtr != NULL) { CaretAssertVectorIndex(columnWidths, jCol); CaretAssertVectorIndex(rowHeights, iRow); int32_t tabX = vpX; int32_t tabY = vpY; /* * Adjust Tab's X-coord so centered in tab * when lock aspect causes tab's width to be smaller * than the column's width */ CaretAssertVectorIndex(columnWidths, jCol); const int32_t extraWidth = columnWidths[jCol] - tabSizePtr->m_width; if (extraWidth > 1) { const int32_t halfExtraWidth = extraWidth / 2; tabX += halfExtraWidth; } /* * Adjust Tab's Y-coord so centered in tab * when lock aspect causes tab's height to be smaller * than the row's height */ CaretAssertVectorIndex(rowHeights, iRow); const int32_t extraHeight = rowHeights[iRow] - tabSizePtr->m_height; if (extraHeight > 1) { const int32_t halfExtraHeight = extraHeight / 2; tabY += halfExtraHeight; } const int tabViewport[4] = { tabX, tabY, tabSizePtr->m_width, tabSizePtr->m_height }; /* * Model is drawn in the model viewport inside any margins. */ int32_t tabIndex = -1; bool highlightTabFlag = false; if (tabSizePtr->m_browserTabContent != NULL) { tabIndex = tabSizePtr->m_browserTabContent->getTabNumber(); highlightTabFlag = (highlightTabIndex == tabIndex); } int modelViewport[4] = { 0, 0, 0, 0 }; createModelViewport(tabViewport, tabIndex, gapsAndMargins, modelViewport); BrainOpenGLViewportContent* vpContent = new BrainOpenGLViewportContent(windowViewport, tabViewport, modelViewport, browserWindowContent->getWindowIndex(), highlightTabFlag, tabSizePtr->m_browserTabContent, tabSizePtr->m_spacerTabContent); viewportContentsOut.push_back(vpContent); } else { /* * If the number of tabs is less than the number of tiles, * empty viewport content is needed so that user can draw * annotations in these regions. */ const int tabViewport[4] = { vpX, vpY, columnWidths[jCol], rowHeights[iRow] }; BrainOpenGLViewportContent* vpContent = new BrainOpenGLViewportContent(windowViewport, tabViewport, tabViewport, browserWindowContent->getWindowIndex(), false, NULL, NULL); viewportContentsOut.push_back(vpContent); } CaretAssertVectorIndex(columnWidths, jCol); vpX += columnWidths[jCol]; } } // for (auto vpc : viewportContentsOut) { // if (vpc->getTabIndex() == 0) { // std::cout << "TAB 1: " << vpc->toString() << std::endl << std::endl; // } // } return viewportContentsOut; } /** * Create viewport from the model using the tab's viewport and the tabs margins. * * @paramj tabViewport * Viewport for the tab. * @param tabIndex * Index of the tab. * @param gapsAndMargins * Gaps and margins. * @param modelViewportOut * Output containing viewport for model. */ void BrainOpenGLViewportContent::createModelViewport(const int tabViewport[4], const int32_t tabIndex, const GapsAndMargins* gapsAndMargins, int modelViewportOut[4]) { int32_t leftMargin = 0; int32_t rightMargin = 0; int32_t bottomMargin = 0; int32_t topMargin = 0; modelViewportOut[0] = tabViewport[0]; modelViewportOut[1] = tabViewport[1]; modelViewportOut[2] = tabViewport[2]; modelViewportOut[3] = tabViewport[3]; if (tabIndex >= 0) { if (gapsAndMargins != NULL) { gapsAndMargins->getMarginsInPixelsForDrawing(tabIndex, tabViewport[2], tabViewport[3], leftMargin, rightMargin, bottomMargin, topMargin); const int32_t marginHorizSize = (leftMargin + rightMargin); const int32_t marginVertSize = (bottomMargin + topMargin); if ((marginHorizSize < modelViewportOut[2]) && (marginVertSize < modelViewportOut[3])) { modelViewportOut[0] += leftMargin; modelViewportOut[1] += bottomMargin; modelViewportOut[2] -= marginHorizSize; modelViewportOut[3] -= marginVertSize; } else { CaretLogSevere("Margins are too big for tab " + AString::number(tabIndex + 1) + " viewport. Viewport (x,y,w,h)=" + AString::fromNumbers(modelViewportOut, 4, ",") + " margin (l,r,b,t)=" + AString::number(leftMargin) + "," + AString::number(rightMargin) + "," + AString::number(bottomMargin) + "," + AString::number(topMargin)); } } } } /** * When viewing a surface montage, "getModelViewport()" returns the viewport * for the entire surface montage (viewport containing all of the surfaces). * However, the are instance where we need the viewport for one of surfaces * in a surface montage. This method will find the viewport for one of the * surfaces within the surface montage using the given X and Y coordinates. * * @param montageX * X-coordinate within the surface montage. * @param montageX * X-coordinate within the surface montage. * @param subViewportOut * Viewport for individual surface in the montage at the given X, Y * coordinates. Note: if a surface montage is not displayed, * this method returns the same viewport as getModelViewport(). */ void BrainOpenGLViewportContent::getSurfaceMontageModelViewport(const int32_t montageX, const int32_t montageY, int subViewportOut[4]) const { getModelViewport(subViewportOut); if (this->m_browserTabContent == NULL) { return; } ModelSurfaceMontage* msm = m_browserTabContent->getDisplayedSurfaceMontageModel(); if (msm != NULL) { std::vector montageViewports; msm->getSurfaceMontageViewportsForTransformation(m_browserTabContent->getTabNumber(), montageViewports); const int x = montageX; const int y = montageY; for (std::vector::const_iterator iter = montageViewports.begin(); iter != montageViewports.end(); iter++) { const SurfaceMontageViewport* smv = *iter; int vp[4]; smv->getViewport(vp); const int offsetX = x - vp[0]; if ((offsetX >= 0) && (offsetX < vp[2])) { const int offsetY = y - vp[1]; if ((offsetY >= 0) && (offsetY < vp[3])) { smv->getViewport(subViewportOut); return; } } } } } /* =================================================================================================== */ /** * Contructor for tile tabs viewport sizing. * * @param browserTabContent * Content of the browser tab. * @param rowIndexFromTop * Row index starting with top row * @param columnIndex * Column index starting on left. * @param initialWidth * Initial width of the tab prior to application of aspect ratio. * @param initialHeight * Initial height of the tab prior to application of aspect ratio. */ BrainOpenGLViewportContent::TileTabsViewportSizingInfo::TileTabsViewportSizingInfo(BrowserTabContent* browserTabContent, SpacerTabContent* spacerTabContent, const int32_t rowIndexFromTop, const int32_t columnIndex, const float initialWidth, const float initialHeight) : m_browserTabContent(browserTabContent), m_spacerTabContent(spacerTabContent), m_rowIndexFromTop(rowIndexFromTop), m_columnIndex(columnIndex), m_initialWidth(initialWidth), m_initialHeight(initialHeight), m_width(initialWidth), m_height(initialHeight) { if (m_browserTabContent != NULL) { if (m_browserTabContent->isAspectRatioLocked()) { const float aspectRatio = m_browserTabContent->getAspectRatio(); if (aspectRatio > 0.0) { BrainOpenGLViewportContent::adjustWidthHeightForAspectRatio(aspectRatio, m_width, m_height); } } } } /** * Copy constructor. * @param obj * Object that is copied. */ BrainOpenGLViewportContent::TileTabsViewportSizingInfo& BrainOpenGLViewportContent::TileTabsViewportSizingInfo::operator=(const TileTabsViewportSizingInfo& obj) { if (this != &obj) { m_browserTabContent = obj.m_browserTabContent; m_spacerTabContent = obj.m_spacerTabContent; m_rowIndexFromTop = obj.m_rowIndexFromTop; m_columnIndex = obj.m_columnIndex; m_initialWidth = obj.m_initialWidth; m_initialHeight = obj.m_initialHeight; m_width = obj.m_initialWidth; m_height = obj.m_initialHeight; } return *this; } /** * Print for debugging. * * @param x * X-coordinate of tab viewport. * @param y * Y-coordinate of tab viewport. */ void BrainOpenGLViewportContent::TileTabsViewportSizingInfo::print(const int32_t x, const int32_t y) { AString name; if (m_browserTabContent != NULL) { name = m_browserTabContent->getTabName(); } else if (m_spacerTabContent != NULL) { name = m_spacerTabContent->getTabName(); } const QString msg("Model: " + name + "\n row/col: " + QString::number(m_rowIndexFromTop) + ", " + QString::number(m_columnIndex) + "\n x/y: " + QString::number(x) + ", " + QString::number(y) + "\n width/height: " + QString::number(m_width) + ", " + QString::number(m_height)); std::cout << qPrintable(msg) << std::endl; } /** * Get the viewport for a slice in all slices view. * * @param tabViewport * The viewport for the tab containing all slices. * @param sliceViewPlane * The plane for slice drawing. Note: "ALL" is used for orientation axes in oblique view. * @param allPlanesLayout * The layout in ALL slices view. * @param viewportOut * Output viewport (region of graphics area) for drawing slices. */ void BrainOpenGLViewportContent::getSliceAllViewViewport(const int32_t tabViewport[4], const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, int32_t viewportOut[4]) { const int32_t gap = 2; const int32_t tabViewportX = tabViewport[0]; const int32_t tabViewportY = tabViewport[1]; const int32_t tabViewportWidth = tabViewport[2]; const int32_t tabViewportHeight = tabViewport[3]; switch (allPlanesLayout) { case VolumeSliceViewAllPlanesLayoutEnum::COLUMN_LAYOUT: { const int32_t vpHeight = (tabViewportHeight - (gap * 2)) / 3; const int32_t vpOffsetY = vpHeight + gap; const int32_t vpWidth = tabViewportWidth; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: viewportOut[0] = 0; viewportOut[1] = 0; viewportOut[2] = 0; viewportOut[3] = 0; break; case VolumeSliceViewPlaneEnum::AXIAL: viewportOut[0] = tabViewportX; viewportOut[1] = tabViewportY; viewportOut[2] = vpWidth; viewportOut[3] = vpHeight; break; case VolumeSliceViewPlaneEnum::CORONAL: viewportOut[0] = tabViewportX; viewportOut[1] = tabViewportY + vpOffsetY; viewportOut[2] = vpWidth; viewportOut[3] = vpHeight; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: viewportOut[0] = tabViewportX; viewportOut[1] = tabViewportY + (vpOffsetY * 2); viewportOut[2] = vpWidth; viewportOut[3] = vpHeight; break; } } break; case VolumeSliceViewAllPlanesLayoutEnum::GRID_LAYOUT: { const int32_t vpWidth = (tabViewportWidth - gap) / 2; const int32_t vpHeight = (tabViewportHeight - gap) / 2; const int32_t vpOffsetX = vpWidth + gap; const int32_t vpOffsetY = vpHeight + gap; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: viewportOut[0] = tabViewportX; viewportOut[1] = tabViewportY; viewportOut[2] = vpWidth; viewportOut[3] = vpHeight; break; case VolumeSliceViewPlaneEnum::AXIAL: viewportOut[0] = tabViewportX + vpOffsetX; viewportOut[1] = tabViewportY; viewportOut[2] = vpWidth; viewportOut[3] = vpHeight; break; case VolumeSliceViewPlaneEnum::CORONAL: viewportOut[0] = tabViewportX + vpOffsetX; viewportOut[1] = tabViewportY + vpOffsetY; viewportOut[2] = vpWidth; viewportOut[3] = vpHeight; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: viewportOut[0] = tabViewportX; viewportOut[1] = tabViewportY + vpOffsetY; viewportOut[2] = vpWidth; viewportOut[3] = vpHeight; break; } } break; case VolumeSliceViewAllPlanesLayoutEnum::ROW_LAYOUT: { const int32_t vpWidth = (tabViewportWidth - (gap * 2)) / 3; const int32_t vpOffsetX = vpWidth + gap; const int32_t vpHeight = tabViewportHeight; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: viewportOut[0] = 0; viewportOut[1] = 0; viewportOut[2] = 0; viewportOut[3] = 0; break; case VolumeSliceViewPlaneEnum::AXIAL: viewportOut[0] = tabViewportX + (vpOffsetX * 2); viewportOut[1] = tabViewportY; viewportOut[2] = vpWidth; viewportOut[3] = vpHeight; break; case VolumeSliceViewPlaneEnum::CORONAL: viewportOut[0] = tabViewportX + vpOffsetX; viewportOut[1] = tabViewportY; viewportOut[2] = vpWidth; viewportOut[3] = vpHeight; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: viewportOut[0] = tabViewportX; viewportOut[1] = tabViewportY; viewportOut[2] = vpWidth; viewportOut[3] = vpHeight; break; } } break; } } /* * @return The slice view plane for the given viewport coordinate. * If ALL is returned, is indicates that the given viewport coordinate * is in the bottom left region in which volume slices are not displayed. * * @param viewport * The viewport. * @param mousePressX * X Location of the mouse press. * @param mousePressY * Y Location of the mouse press. * @param allPlanesLayout * The layout in ALL slices view. * @param sliceViewportOut * Output viewport (region of graphics area) for drawing slices. */ VolumeSliceViewPlaneEnum::Enum BrainOpenGLViewportContent::getSliceViewPlaneForVolumeAllSliceView(const int32_t viewport[4], const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, const int32_t mousePressX, const int32_t mousePressY, int32_t sliceViewportOut[4]) { VolumeSliceViewPlaneEnum::Enum view = VolumeSliceViewPlaneEnum::ALL; std::vector allSlicePlanes; VolumeSliceViewPlaneEnum::getAllEnums(allSlicePlanes); for (auto slicePlane : allSlicePlanes) { BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, slicePlane, allPlanesLayout, sliceViewportOut); const int32_t vpX = mousePressX - sliceViewportOut[0]; const int32_t vpY = mousePressY - sliceViewportOut[1]; if ((vpX >= 0) && (vpY >= 0) && (vpX < sliceViewportOut[2]) && (vpY < sliceViewportOut[3])) { return slicePlane; } } CaretLogSevere("Failed to find slice plane in all sliced view"); return view; } connectome-workbench-1.4.2/src/Brain/BrainOpenGLViewportContent.h000066400000000000000000000226711360521144700250310ustar00rootroot00000000000000#ifndef __BRAIN_OPEN_G_L_VIEWPORT_CONTENT__H_ #define __BRAIN_OPEN_G_L_VIEWPORT_CONTENT__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "Matrix4x4.h" #include "VolumeSliceViewPlaneEnum.h" #include "VolumeSliceViewAllPlanesLayoutEnum.h" namespace caret { class BrowserTabContent; class BrowserWindowContent; class GapsAndMargins; class SpacerTabContent; class TileTabsConfiguration; class BrainOpenGLViewportContent : public CaretObject { public: ~BrainOpenGLViewportContent(); BrainOpenGLViewportContent(const BrainOpenGLViewportContent& obj); BrainOpenGLViewportContent& operator=(const BrainOpenGLViewportContent& obj); bool getChartDataMatricesAndViewport(Matrix4x4& chartDataProjectionMatrixOut, Matrix4x4& chartDataModelViewMatrixOut, int chartViewportOut[4]) const; void setChartDataMatricesAndViewport(const Matrix4x4& chartDataProjectionMatrix, const Matrix4x4& chartDataModelViewMatrix, const int chartViewport[4]) const; void getModelViewport(int modelViewportOut[4]) const; void getSurfaceMontageModelViewport(const int32_t montageX, const int32_t montageY, int subViewportOut[4]) const; void getTabViewportBeforeApplyingMargins(int tabViewportOut[4]) const; void getWindowViewport(int windowViewportOut[4]) const; int getWindowIndex() const; BrowserTabContent* getBrowserTabContent() const; SpacerTabContent* getSpacerTabContent() const; int32_t getTabIndex() const; bool isTabHighlighted() const; static void adjustViewportForAspectRatio(int viewport[4], const float aspectRatio); static void adjustWidthHeightForAspectRatio(const float aspectRatio, int32_t& width, int32_t& height); static std::vector createViewportContentForTileTabs(std::vector& tabContents, BrowserWindowContent* browserWindowContent, const GapsAndMargins* gapsAndMargins, const int32_t windowViewport[4], const int32_t windowIndex, const int32_t highlightTabIndex); static BrainOpenGLViewportContent* createViewportForSingleTab(std::vector& allTabContents, BrowserTabContent* selectedTabContent, const GapsAndMargins* gapsAndMargins, const int32_t windowIndex, const int32_t windowViewport[4]); static void getSliceAllViewViewport(const int32_t tabViewport[4], const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, int32_t viewportOut[4]); static VolumeSliceViewPlaneEnum::Enum getSliceViewPlaneForVolumeAllSliceView(const int viewport[4], const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, const int32_t mousePressX, const int32_t mousePressY, int sliceViewportOut[4]); private: /** * Assists with creation of the tile tab viewports */ class TileTabsViewportSizingInfo { public: TileTabsViewportSizingInfo(BrowserTabContent* browserTabContent, SpacerTabContent* spacerTabContent, const int32_t rowIndexFromTop, const int32_t columnIndex, const float initialWidth, const float initialHeight); TileTabsViewportSizingInfo& operator=(const TileTabsViewportSizingInfo& obj); void print(const int32_t x, const int32_t y); BrowserTabContent* m_browserTabContent; SpacerTabContent* m_spacerTabContent; int32_t m_rowIndexFromTop; int32_t m_columnIndex; /** size with application of tile tabs configuration */ float m_initialWidth; float m_initialHeight; /** size after application of lock aspect ratio */ int32_t m_width; int32_t m_height; }; BrainOpenGLViewportContent(const int windowViewport[4], const int tabViewport[4], const int modelViewport[4], const int windowIndex, const bool highlightTabFlag, BrowserTabContent* browserTabContent, SpacerTabContent* spacerTabContent); void initializeMembersBrainOpenGLViewportContent(); void copyHelperBrainOpenGLViewportContent(const BrainOpenGLViewportContent& obj); static void createModelViewport(const int tabViewport[4], const int32_t tabIndex, const GapsAndMargins* gapsAndMargins, int modelViewportOut[4]); void updateTabLockedAspectRatios(const int32_t windowIndex, const int32_t windowViewport[4]); const int m_windowIndex; const bool m_highlightTab; /** Tab viewport's X-coordinate */ int m_tabX; /** Tab viewport's Y-coordinate */ int m_tabY; /** Tab viewport's Width */ int m_tabWidth; /** Tab viewport's Height */ int m_tabHeight; /** Chart data viewport's X-coordinate */ mutable int m_chartDataX; /** Chart data viewport's Y-coordinate */ mutable int m_chartDataY; /** Chart data viewport's Width */ mutable int m_chartDataWidth; /** Chart data viewport's Height */ mutable int m_chartDataHeight; /** Chart data viewport's validity */ mutable bool m_chartDataViewportValidFlag = false; /** Chart data transformation matrix */ mutable Matrix4x4 m_chartDataModelViewMatrix; /** Chart data transformation matrix */ mutable Matrix4x4 m_chartDataProjectionMatrix; /** Model viewport's X-coordinate */ int m_modelX; /** Model viewport's Y-coordinate */ int m_modelY; /** Model viewport's Width */ int m_modelWidth; /** Model viewport's Height */ int m_modelHeight; /** Window viewport's X-coordinate */ int m_windowX; /** Window viewport's Y-coordinate */ int m_windowY; /** Window viewport's Width */ int m_windowWidth; /** Window viewport's Height */ int m_windowHeight; BrowserTabContent* m_browserTabContent; SpacerTabContent* m_spacerTabContent; public: virtual AString toString() const; }; #ifdef __BRAIN_OPEN_G_L_VIEWPORT_CONTENT_DECLARE__ // #endif // __BRAIN_OPEN_G_L_VIEWPORT_CONTENT_DECLARE__ } // namespace #endif //__BRAIN_OPEN_G_L_VIEWPORT_CONTENT__H_ connectome-workbench-1.4.2/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx000066400000000000000000005100231360521144700273070ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __BRAIN_OPEN_GL_VOLUME_OBLIQUE_SLICE_DRAWING_DECLARE__ #include "BrainOpenGLVolumeObliqueSliceDrawing.h" #undef __BRAIN_OPEN_GL_VOLUME_OBLIQUE_SLICE_DRAWING_DECLARE__ #include "AnnotationCoordinate.h" #include "AnnotationPercentSizeText.h" #include "BoundingBox.h" #include "Brain.h" #include "BrainOpenGLAnnotationDrawingFixedPipeline.h" #include "BrainOpenGLPrimitiveDrawing.h" #include "BrainOpenGLViewportContent.h" #include "BrainOpenGLVolumeSliceDrawing.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretOpenGLInclude.h" #include "CaretPreferenceDataValue.h" #include "CaretPreferences.h" #include "CiftiMappableDataFile.h" #include "DeveloperFlagsEnum.h" #include "DisplayPropertiesFoci.h" #include "DisplayPropertiesLabels.h" #include "DisplayPropertiesVolume.h" #include "ElapsedTimer.h" #include "FociFile.h" #include "Focus.h" #include "GapsAndMargins.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "GroupAndNameHierarchyModel.h" #include "GraphicsEngineDataOpenGL.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GraphicsPrimitiveV3fC4ub.h" #include "GraphicsUtilitiesOpenGL.h" #include "IdentificationWithColor.h" #include "LabelDrawingProperties.h" #include "MathFunctions.h" #include "Matrix4x4.h" #include "ModelVolume.h" #include "ModelWholeBrain.h" #include "NodeAndVoxelColoring.h" #include "SelectionItemFocusVolume.h" #include "SelectionItemVoxel.h" #include "SelectionItemVoxelEditing.h" #include "SelectionManager.h" #include "SessionManager.h" #include "SpacerTabIndex.h" #include "Surface.h" #include "SurfacePlaneIntersectionToContour.h" #include "VolumeFile.h" #include "VolumeSurfaceOutlineColorOrTabModel.h" #include "VolumeSurfaceOutlineModel.h" #include "VolumeSurfaceOutlineSetModel.h" using namespace caret; static const bool debugFlag = false; /** * \class caret::BrainOpenGLVolumeObliqueSliceDrawing * \brief Draws volume slices using OpenGL * \ingroup Brain */ /** * Constructor. */ BrainOpenGLVolumeObliqueSliceDrawing::BrainOpenGLVolumeObliqueSliceDrawing() : CaretObject() { } /** * Destructor. */ BrainOpenGLVolumeObliqueSliceDrawing::~BrainOpenGLVolumeObliqueSliceDrawing() { } /** * Draw Volume Slices or slices for ALL Stuctures View. * * @param fixedPipelineDrawing * The OpenGL drawing. * @param browserTabContent * Content of browser tab that is to be drawn. * @param volumeDrawInfo * Info on each volume layers for drawing. * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param obliqueSliceMaskingType * Masking for oblique slice drawing * @param viewport * The viewport (region of graphics area) for drawing slices. */ void BrainOpenGLVolumeObliqueSliceDrawing::draw(BrainOpenGLFixedPipeline* fixedPipelineDrawing, BrowserTabContent* browserTabContent, std::vector& volumeDrawInfo, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum obliqueSliceMaskingType, const int32_t viewport[4]) { CaretAssert(sliceProjectionType == VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE); if (volumeDrawInfo.empty()) { return; } CaretAssert(fixedPipelineDrawing); CaretAssert(browserTabContent); m_browserTabContent = browserTabContent; m_fixedPipelineDrawing = fixedPipelineDrawing; m_obliqueSliceMaskingType = obliqueSliceMaskingType; /* * No lighting for drawing slices */ m_fixedPipelineDrawing->disableLighting(); /* * Initialize class members which help reduce the number of * parameters that are passed to methods. */ m_brain = NULL; m_modelVolume = NULL; m_modelWholeBrain = NULL; m_modelType = ModelTypeEnum::MODEL_TYPE_INVALID; if (m_browserTabContent->getDisplayedVolumeModel() != NULL) { m_modelVolume = m_browserTabContent->getDisplayedVolumeModel(); m_brain = m_modelVolume->getBrain(); m_modelType = m_modelVolume->getModelType(); } else if (m_browserTabContent->getDisplayedWholeBrainModel() != NULL) { m_modelWholeBrain = m_browserTabContent->getDisplayedWholeBrainModel(); m_brain = m_modelWholeBrain->getBrain(); m_modelType = m_modelWholeBrain->getModelType(); } else { CaretAssertMessage(0, "Invalid model for volume slice drawing."); } CaretAssert(m_brain); CaretAssert(m_modelType != ModelTypeEnum::MODEL_TYPE_INVALID); m_volumeDrawInfo = volumeDrawInfo; if (m_volumeDrawInfo.empty()) { return; } m_underlayVolume = m_volumeDrawInfo[0].volumeFile; const DisplayPropertiesLabels* dsl = m_brain->getDisplayPropertiesLabels(); m_displayGroup = dsl->getDisplayGroupForTab(m_fixedPipelineDrawing->windowTabIndex); m_tabIndex = m_browserTabContent->getTabNumber(); /* * Cifti files are slow at getting individual voxels since they * provide no access to individual voxels. The reason is that * the data may be on a server (Dense data) and accessing a single * voxel would require requesting the entire map. So, for * each Cifti file, get the enter map. This also, eliminate multiple * requests for the same map when drawing an ALL view. */ const int32_t numVolumes = static_cast(m_volumeDrawInfo.size()); for (int32_t i = 0; i < numVolumes; i++) { std::vector ciftiMapData; m_ciftiMappableFileData.push_back(ciftiMapData); const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(m_volumeDrawInfo[i].volumeFile); if (ciftiMapFile != NULL) { ciftiMapFile->getMapData(m_volumeDrawInfo[i].mapIndex, m_ciftiMappableFileData[i]); } } if (browserTabContent->getDisplayedVolumeModel() != NULL) { drawVolumeSliceViewPlane(sliceDrawingType, sliceProjectionType, browserTabContent->getSliceViewPlane(), browserTabContent->getSlicePlanesAllViewLayout(), viewport); } else if (browserTabContent->getDisplayedWholeBrainModel() != NULL) { drawVolumeSlicesForAllStructuresView(sliceProjectionType, viewport); } } /** * Draw volume view slices for the given view plane. * * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * The plane for slice drawing. * @param allPlanesLayout * The layout in ALL slices view. * @param viewport * The viewport (region of graphics area) for drawing slices. */ void BrainOpenGLVolumeObliqueSliceDrawing::drawVolumeSliceViewPlane(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, const int32_t viewport[4]) { switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: { int32_t paraVP[4] = { 0, 0, 0, 0 }; int32_t coronalVP[4] = { 0, 0, 0, 0 }; int32_t axialVP[4] = { 0, 0, 0, 0 }; BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, VolumeSliceViewPlaneEnum::PARASAGITTAL, allPlanesLayout, paraVP); BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, VolumeSliceViewPlaneEnum::CORONAL, allPlanesLayout, coronalVP); BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, VolumeSliceViewPlaneEnum::AXIAL, allPlanesLayout, axialVP); /* * Draw parasagittal slice */ glPushMatrix(); drawVolumeSliceViewType(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_YES, sliceDrawingType, sliceProjectionType, VolumeSliceViewPlaneEnum::PARASAGITTAL, paraVP); glPopMatrix(); /* * Draw coronal slice */ glPushMatrix(); drawVolumeSliceViewType(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_YES, sliceDrawingType, sliceProjectionType, VolumeSliceViewPlaneEnum::CORONAL, coronalVP); glPopMatrix(); /* * Draw axial slice */ glPushMatrix(); drawVolumeSliceViewType(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_YES, sliceDrawingType, sliceProjectionType, VolumeSliceViewPlaneEnum::AXIAL, axialVP); glPopMatrix(); if (allPlanesLayout == VolumeSliceViewAllPlanesLayoutEnum::GRID_LAYOUT) { /* * 4th quadrant is used for axis showing orientation */ int32_t allVP[4] = { 0, 0, 0, 0 }; BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, VolumeSliceViewPlaneEnum::ALL, allPlanesLayout, allVP); switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: drawOrientationAxes(allVP); break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: CaretAssert(0); break; } } } break; case VolumeSliceViewPlaneEnum::AXIAL: case VolumeSliceViewPlaneEnum::CORONAL: case VolumeSliceViewPlaneEnum::PARASAGITTAL: drawVolumeSliceViewType(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_NO, sliceDrawingType, sliceProjectionType, sliceViewPlane, viewport); break; } } /** * Draw slices for the all structures view. * * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param viewport * The viewport. */ void BrainOpenGLVolumeObliqueSliceDrawing::drawVolumeSlicesForAllStructuresView(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const int32_t viewport[4]) { m_orthographicBounds[0] = m_fixedPipelineDrawing->orthographicLeft; m_orthographicBounds[1] = m_fixedPipelineDrawing->orthographicRight; m_orthographicBounds[2] = m_fixedPipelineDrawing->orthographicBottom; m_orthographicBounds[3] = m_fixedPipelineDrawing->orthographicTop; m_orthographicBounds[4] = m_fixedPipelineDrawing->orthographicNear; m_orthographicBounds[5] = m_fixedPipelineDrawing->orthographicFar; /* * Enlarge the region */ { const float left = m_fixedPipelineDrawing->orthographicLeft; const float right = m_fixedPipelineDrawing->orthographicRight; const float bottom = m_fixedPipelineDrawing->orthographicBottom; const float top = m_fixedPipelineDrawing->orthographicTop; const float scale = 2.0; const float centerX = (left + right) / 2.0; const float dx = (right - left) / 2.0; const float newLeft = centerX - (dx * scale); const float newRight = centerX + (dx * scale); const float centerY = (bottom + top) / 2.0; const float dy = (top - bottom) / 2.0; const float newBottom = centerY - (dy * scale); const float newTop = centerY + (dy * scale); m_orthographicBounds[0] = newLeft; m_orthographicBounds[1] = newRight; m_orthographicBounds[2] = newBottom; m_orthographicBounds[3] = newTop; } const float sliceCoordinates[3] = { m_browserTabContent->getSliceCoordinateParasagittal(), m_browserTabContent->getSliceCoordinateCoronal(), m_browserTabContent->getSliceCoordinateAxial() }; if (m_browserTabContent->isSliceAxialEnabled()) { glPushMatrix(); drawVolumeSliceViewProjection(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_NO, VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE, sliceProjectionType, VolumeSliceViewPlaneEnum::AXIAL, sliceCoordinates, viewport); glPopMatrix(); } if (m_browserTabContent->isSliceCoronalEnabled()) { glPushMatrix(); drawVolumeSliceViewProjection(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_NO, VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE, sliceProjectionType, VolumeSliceViewPlaneEnum::CORONAL, sliceCoordinates, viewport); glPopMatrix(); } if (m_browserTabContent->isSliceParasagittalEnabled()) { glPushMatrix(); drawVolumeSliceViewProjection(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_NO, VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE, sliceProjectionType, VolumeSliceViewPlaneEnum::PARASAGITTAL, sliceCoordinates, viewport); glPopMatrix(); } } /** * Draw single or montage volume view slices. * * @param allSliceViewMode * Indicates drawing of ALL slices volume view (axial, coronal, parasagittal in one view) * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * The plane for slice drawing. * @param viewport * The viewport (region of graphics area) for drawing slices. */ void BrainOpenGLVolumeObliqueSliceDrawing::drawVolumeSliceViewType(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const int32_t viewport[4]) { switch (sliceDrawingType) { case VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_MONTAGE: drawVolumeSliceViewTypeMontage(allSliceViewMode, sliceDrawingType, sliceProjectionType, sliceViewPlane, viewport); break; case VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE: { const float sliceCoordinates[3] = { m_browserTabContent->getSliceCoordinateParasagittal(), m_browserTabContent->getSliceCoordinateCoronal(), m_browserTabContent->getSliceCoordinateAxial() }; drawVolumeSliceViewProjection(allSliceViewMode, sliceDrawingType, sliceProjectionType, sliceViewPlane, sliceCoordinates, viewport); } break; } } /** * Draw montage slices. * * @param allSliceViewMode * Indicates drawing of ALL slices volume view (axial, coronal, parasagittal in one view) * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * The plane for slice drawing. * @param viewport * The viewport (region of graphics area) for drawing slices. */ void BrainOpenGLVolumeObliqueSliceDrawing::drawVolumeSliceViewTypeMontage(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const int32_t viewport[4]) { const int32_t numRows = m_browserTabContent->getMontageNumberOfRows(); CaretAssert(numRows > 0); const int32_t numCols = m_browserTabContent->getMontageNumberOfColumns(); CaretAssert(numCols > 0); const int32_t montageCoordPrecision = m_browserTabContent->getVolumeMontageCoordinatePrecision(); const GapsAndMargins* gapsAndMargins = m_brain->getGapsAndMargins(); const int32_t windowIndex = m_fixedPipelineDrawing->m_windowIndex; int32_t vpSizeY = 0; int32_t verticalMargin = 0; BrainOpenGLFixedPipeline::createSubViewportSizeAndGaps(viewport[3], gapsAndMargins->getVolumeMontageVerticalGapForWindow(windowIndex), -1, numRows, vpSizeY, verticalMargin); int32_t vpSizeX = 0; int32_t horizontalMargin = 0; BrainOpenGLFixedPipeline::createSubViewportSizeAndGaps(viewport[2], gapsAndMargins->getVolumeMontageHorizontalGapForWindow(windowIndex), -1, numCols, vpSizeX, horizontalMargin); /* * Voxel sizes for underlay volume */ float originX, originY, originZ; float x1, y1, z1; m_underlayVolume->indexToSpace(0, 0, 0, originX, originY, originZ); m_underlayVolume->indexToSpace(1, 1, 1, x1, y1, z1); float sliceThickness = 0.0; float sliceOrigin = 0.0; AString axisLetter = ""; float sliceCoordinates[3] = { m_browserTabContent->getSliceCoordinateParasagittal(), m_browserTabContent->getSliceCoordinateCoronal(), m_browserTabContent->getSliceCoordinateAxial() }; int32_t sliceIndex = -1; int32_t maximumSliceIndex = -1; int64_t dimI, dimJ, dimK, numMaps, numComponents; m_underlayVolume->getDimensions(dimI, dimJ, dimK, numMaps, numComponents); const int32_t sliceStep = m_browserTabContent->getMontageSliceSpacing(); switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: sliceIndex = -1; break; case VolumeSliceViewPlaneEnum::AXIAL: sliceIndex = m_browserTabContent->getSliceIndexAxial(m_underlayVolume); maximumSliceIndex = dimK; sliceThickness = z1 - originZ; sliceOrigin = originZ; axisLetter = "Z"; break; case VolumeSliceViewPlaneEnum::CORONAL: sliceIndex = m_browserTabContent->getSliceIndexCoronal(m_underlayVolume); maximumSliceIndex = dimJ; sliceThickness = y1 - originY; sliceOrigin = originY; axisLetter = "Y"; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: sliceIndex = m_browserTabContent->getSliceIndexParasagittal(m_underlayVolume); maximumSliceIndex = dimI; sliceThickness = x1 - originX; sliceOrigin = originX; axisLetter = "X"; break; } /* * Foreground color for slice coordinate text */ const CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); uint8_t foregroundRGBA[4]; prefs->getBackgroundAndForegroundColors()->getColorForegroundVolumeView(foregroundRGBA); foregroundRGBA[3] = 255; uint8_t backgroundRGBA[4]; prefs->getBackgroundAndForegroundColors()->getColorBackgroundVolumeView(backgroundRGBA); backgroundRGBA[3] = 255; const bool showCoordinates = m_browserTabContent->isVolumeMontageAxesCoordinatesDisplayed(); /* * Determine a slice offset to selected slices is in * the center of the montage */ const int32_t numSlicesViewed = (numCols * numRows); const int32_t sliceOffset = ((numSlicesViewed / 2) * sliceStep); sliceIndex += sliceOffset; /* * Find first valid slice for montage */ while (sliceIndex >= 0) { if (sliceIndex < maximumSliceIndex) { break; } sliceIndex -= sliceStep; } if (sliceIndex >= 0) { for (int32_t i = 0; i < numRows; i++) { for (int32_t j = 0; j < numCols; j++) { if ((sliceIndex >= 0) && (sliceIndex < maximumSliceIndex)) { const int32_t vpX = (j * (vpSizeX + horizontalMargin)); const int32_t vpY = ((numRows - i - 1) * (vpSizeY + verticalMargin)); int32_t vp[4] = { viewport[0] + vpX, viewport[1] + vpY, vpSizeX, vpSizeY }; if ((vp[2] <= 0) || (vp[3] <= 0)) { continue; } const float sliceCoord = (sliceOrigin + sliceThickness * sliceIndex); switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: break; case VolumeSliceViewPlaneEnum::AXIAL: sliceCoordinates[2] = sliceCoord; break; case VolumeSliceViewPlaneEnum::CORONAL: sliceCoordinates[1] = sliceCoord; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: sliceCoordinates[0] = sliceCoord; break; } drawVolumeSliceViewProjection(allSliceViewMode, sliceDrawingType, sliceProjectionType, sliceViewPlane, sliceCoordinates, vp); if (showCoordinates) { const AString coordText = (axisLetter + "=" + AString::number(sliceCoord, 'f', montageCoordPrecision)); AnnotationPercentSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); annotationText.setFontPercentViewportSize(10.0f); annotationText.setLineColor(CaretColorEnum::NONE); annotationText.setTextColor(CaretColorEnum::CUSTOM); annotationText.setBackgroundColor(CaretColorEnum::CUSTOM); annotationText.setCustomTextColor(foregroundRGBA); annotationText.setCustomBackgroundColor(backgroundRGBA); annotationText.setText(coordText); m_fixedPipelineDrawing->drawTextAtViewportCoords((vpSizeX - 5), 5.0, annotationText); } } sliceIndex -= sliceStep; } } } /* * Draw the axes labels for the montage view */ glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); if (m_browserTabContent->isVolumeAxesCrosshairLabelsDisplayed()) { drawAxesCrosshairsOblique(sliceViewPlane, sliceCoordinates, false, true); } } /** * Draw a slice for either projection mode (oblique, orthogonal) * * @param allSliceViewMode * Indicates drawing of ALL slices volume view (axial, coronal, parasagittal in one view) * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * The plane for slice drawing. * @param sliceCoordinates * Coordinates of the selected slice. * @param viewport * The viewport (region of graphics area) for drawing slices. */ void BrainOpenGLVolumeObliqueSliceDrawing::drawVolumeSliceViewProjection(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], const int32_t viewport[4]) { bool twoDimSliceViewFlag = false; if (m_modelVolume != NULL) { twoDimSliceViewFlag = true; } else if (m_modelWholeBrain != NULL) { /* nothing */ } else { CaretAssertMessage(0, "Invalid model type."); } if (twoDimSliceViewFlag) { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); /* * Set the orthographic projection to fit the slice axis */ setOrthographicProjection(allSliceViewMode, sliceViewPlane, viewport); } /* * Create the plane equation for the slice */ Plane slicePlane; createSlicePlaneEquation(sliceProjectionType, sliceViewPlane, sliceCoordinates, slicePlane); CaretAssert(slicePlane.isValidPlane()); if (slicePlane.isValidPlane() == false) { return; } if (twoDimSliceViewFlag) { /* * Set the viewing transformation (camera position) */ setVolumeSliceViewingAndModelingTransformations(sliceProjectionType, sliceViewPlane, slicePlane, sliceCoordinates); } SelectionItemVoxel* voxelID = m_brain->getSelectionManager()->getVoxelIdentification(); SelectionItemVoxelEditing* voxelEditingID = m_brain->getSelectionManager()->getVoxelEditingIdentification(); m_fixedPipelineDrawing->applyClippingPlanes(BrainOpenGLFixedPipeline::CLIPPING_DATA_TYPE_VOLUME, StructureEnum::ALL); /* * Check for a 'selection' type mode */ bool drawVolumeSlicesFlag = true; m_identificationModeFlag = false; switch (m_fixedPipelineDrawing->mode) { case BrainOpenGLFixedPipeline::MODE_DRAWING: break; case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: if (voxelID->isEnabledForSelection() || voxelEditingID->isEnabledForSelection()) { m_identificationModeFlag = true; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } else { /* * Don't return. Allow other items (such as annotations) to be drawn. */ drawVolumeSlicesFlag = false; } break; case BrainOpenGLFixedPipeline::MODE_PROJECTION: return; break; } resetIdentification(); GLboolean cullFaceOn = glIsEnabled(GL_CULL_FACE); if (drawVolumeSlicesFlag) { /* * Disable culling so that both sides of the triangles/quads are drawn. */ glDisable(GL_CULL_FACE); switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: CaretAssert(0); break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: { /* * Create the oblique slice transformation matrix */ Matrix4x4 obliqueTransformationMatrix; createObliqueTransformationMatrix(sliceCoordinates, obliqueTransformationMatrix); drawObliqueSliceWithOutlines(sliceViewPlane, obliqueTransformationMatrix); } break; } /* * Process selection */ if (m_identificationModeFlag) { processIdentification(); } } if ( ! m_identificationModeFlag) { if (slicePlane.isValidPlane()) { drawLayers(sliceDrawingType, sliceProjectionType, sliceViewPlane, slicePlane, sliceCoordinates); } } /* * Draw model space annotaitons on the volume slice */ float sliceThickness = 1.0; if ( ! m_volumeDrawInfo.empty()) { if (m_volumeDrawInfo[0].volumeFile != NULL) { float spaceX = 0.0, spaceY = 0.0, spaceZ = 0.0; m_volumeDrawInfo[0].volumeFile->getVoxelSpacing(spaceX, spaceY, spaceZ); switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: sliceThickness = spaceZ; break; case VolumeSliceViewPlaneEnum::CORONAL: sliceThickness = spaceY; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: sliceThickness = spaceX; break; } } } const bool annotationModeFlag = (m_fixedPipelineDrawing->m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, m_fixedPipelineDrawing->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_fixedPipelineDrawing->m_windowIndex, m_fixedPipelineDrawing->windowTabIndex, SpacerTabIndex(), BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, annotationModeFlag); m_fixedPipelineDrawing->m_annotationDrawing->drawModelSpaceAnnotationsOnVolumeSlice(&inputs, slicePlane, sliceThickness); m_fixedPipelineDrawing->disableClippingPlanes(); if (cullFaceOn) { glEnable(GL_CULL_FACE); } } /** * Create the equation for the slice plane * * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * View plane that is displayed. * @param montageSliceIndex * Selected montage slice index * @param planeOut * OUTPUT plane of slice after transforms. */ void BrainOpenGLVolumeObliqueSliceDrawing::createSlicePlaneEquation(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], Plane& planeOut) { /* * Default the slice normal vector to an orthogonal view */ float sliceNormalVector[3] = { 0.0, 0.0, 0.0 }; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: case VolumeSliceViewPlaneEnum::AXIAL: sliceNormalVector[2] = 1.0; break; case VolumeSliceViewPlaneEnum::CORONAL: sliceNormalVector[1] = -1.0; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: sliceNormalVector[0] = -1.0; break; } switch (sliceProjectionType) { break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: { /* * Transform the slice normal vector by the oblique rotation * matrix so that the normal vector points out of the slice */ const Matrix4x4 obliqueRotationMatrix = m_browserTabContent->getObliqueVolumeRotationMatrix(); obliqueRotationMatrix.multiplyPoint3(sliceNormalVector); MathFunctions::normalizeVector(sliceNormalVector); } break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: CaretAssert(0); break; } Plane plane(sliceNormalVector, sliceCoordinates); planeOut = plane; m_lookAtCenter[0] = sliceCoordinates[0]; m_lookAtCenter[1] = sliceCoordinates[1]; m_lookAtCenter[2] = sliceCoordinates[2]; } /** * Set the volume slice viewing transformation. This sets the position and * orientation of the camera. * * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * View plane that is displayed. * @param plane * Plane equation of selected slice. * @param sliceCoordinates * Coordinates of the selected slices. */ void BrainOpenGLVolumeObliqueSliceDrawing::setVolumeSliceViewingAndModelingTransformations(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const Plane& plane, const float sliceCoordinates[3]) { /* * Initialize the modelview matrix to the identity matrix * This places the camera at the origin, pointing down the * negative-Z axis with the up vector set to (0,1,0 => * positive-Y is up). */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); const float* userTranslation = m_browserTabContent->getTranslation(); /* * Move the camera with the user's translation */ float viewTranslationX = 0.0; float viewTranslationY = 0.0; float viewTranslationZ = 0.0; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: case VolumeSliceViewPlaneEnum::AXIAL: viewTranslationX = sliceCoordinates[0] + userTranslation[0]; viewTranslationY = sliceCoordinates[1] + userTranslation[1]; break; case VolumeSliceViewPlaneEnum::CORONAL: viewTranslationX = sliceCoordinates[0] + userTranslation[0]; viewTranslationY = sliceCoordinates[2] + userTranslation[2]; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: viewTranslationX = -(sliceCoordinates[1] + userTranslation[1]); viewTranslationY = sliceCoordinates[2] + userTranslation[2]; break; } glTranslatef(viewTranslationX, viewTranslationY, viewTranslationZ); glGetDoublev(GL_MODELVIEW_MATRIX, m_viewingMatrix); /* * Since an orthographic projection is used, the camera only needs * to be a little bit from the center along the plane's normal vector. */ double planeNormal[3]; plane.getNormalVector(planeNormal); double cameraXYZ[3] = { m_lookAtCenter[0] + planeNormal[0] * BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_lookAtCenter[1] + planeNormal[1] * BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_lookAtCenter[2] + planeNormal[2] * BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, }; /* * Set the up vector which indices which way is up (screen Y) */ float up[3] = { 0.0, 0.0, 0.0 }; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: case VolumeSliceViewPlaneEnum::AXIAL: up[1] = 1.0; break; case VolumeSliceViewPlaneEnum::CORONAL: up[2] = 1.0; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: up[2] = 1.0; break; } /* * For oblique viewing, the up vector needs to be rotated by the * oblique rotation matrix. */ switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: m_browserTabContent->getObliqueVolumeRotationMatrix().multiplyPoint3(up); break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: CaretAssert(0); break; } /* * Now set the camera to look at the selected coordinate (center) * with the camera offset a little bit from the center. * This allows the slice's voxels to be drawn in the actual coordinates. */ gluLookAt(cameraXYZ[0], cameraXYZ[1], cameraXYZ[2], m_lookAtCenter[0], m_lookAtCenter[1], m_lookAtCenter[2], up[0], up[1], up[2]); } /** * Draw the layers type data. * * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * View plane that is displayed. * @param slicePlane * Plane of the slice. * @param sliceCoordinates * Coordinates of the selected slices. */ void BrainOpenGLVolumeObliqueSliceDrawing::drawLayers(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const Plane& slicePlane, const float sliceCoordinates[3]) { bool drawCrosshairsFlag = true; bool drawFibersFlag = true; bool drawFociFlag = true; bool drawOutlineFlag = true; if (m_modelWholeBrain != NULL) { drawCrosshairsFlag = false; drawFibersFlag = false; drawFociFlag = false; } if ( ! m_identificationModeFlag) { if (slicePlane.isValidPlane()) { /* * Disable culling so that both sides of the triangles/quads are drawn. */ GLboolean cullFaceOn = glIsEnabled(GL_CULL_FACE); glDisable(GL_CULL_FACE); glPushMatrix(); GLboolean depthBufferEnabled = false; glGetBooleanv(GL_DEPTH_TEST, &depthBufferEnabled); /* * Use some polygon offset that will adjust the depth values of the * layers so that the layers depth values place the layers in front of * the volume slice. */ glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(0.0, 1.0); if (drawOutlineFlag) { BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(m_underlayVolume, m_modelType, sliceProjectionType, sliceViewPlane, sliceCoordinates, slicePlane, m_browserTabContent->getVolumeSurfaceOutlineSet(), m_fixedPipelineDrawing, true); } if (drawFibersFlag) { glDisable(GL_DEPTH_TEST); m_fixedPipelineDrawing->drawFiberOrientations(&slicePlane, StructureEnum::ALL); m_fixedPipelineDrawing->drawFiberTrajectories(&slicePlane, StructureEnum::ALL); if (depthBufferEnabled) { glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); } } if (drawFociFlag) { glDisable(GL_DEPTH_TEST); drawVolumeSliceFoci(slicePlane); if (depthBufferEnabled) { glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); } } glDisable(GL_POLYGON_OFFSET_FILL); if (drawCrosshairsFlag) { glPushMatrix(); drawAxesCrosshairs(sliceProjectionType, sliceDrawingType, sliceViewPlane, sliceCoordinates); glPopMatrix(); if (depthBufferEnabled) { glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); } } glPopMatrix(); if (cullFaceOn) { glEnable(GL_CULL_FACE); } } } } /** * Draw foci on volume slice. * * @param plane * Plane of the volume slice on which surface outlines are drawn. */ void BrainOpenGLVolumeObliqueSliceDrawing::drawVolumeSliceFoci(const Plane& plane) { SelectionItemFocusVolume* idFocus = m_brain->getSelectionManager()->getVolumeFocusIdentification(); /* * Check for a 'selection' type mode */ bool isSelect = false; switch (m_fixedPipelineDrawing->mode) { case BrainOpenGLFixedPipeline::MODE_DRAWING: break; case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: if (idFocus->isEnabledForSelection()) { isSelect = true; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } else { return; } break; case BrainOpenGLFixedPipeline::MODE_PROJECTION: return; break; } VolumeMappableInterface* underlayVolume = m_volumeDrawInfo[0].volumeFile; float minVoxelSpacing; float maxVoxelSpacing; if ( ! getMinMaxVoxelSpacing(underlayVolume, minVoxelSpacing, maxVoxelSpacing)) { return; } const float sliceThickness = maxVoxelSpacing; const float halfSliceThickness = sliceThickness * 0.5; const DisplayPropertiesFoci* fociDisplayProperties = m_brain->getDisplayPropertiesFoci(); const DisplayGroupEnum::Enum displayGroup = fociDisplayProperties->getDisplayGroupForTab(m_fixedPipelineDrawing->windowTabIndex); if (fociDisplayProperties->isDisplayed(displayGroup, m_fixedPipelineDrawing->windowTabIndex) == false) { return; } const float focusDiameter = fociDisplayProperties->getFociSize(displayGroup, m_fixedPipelineDrawing->windowTabIndex); const FeatureColoringTypeEnum::Enum fociColoringType = fociDisplayProperties->getColoringType(displayGroup, m_fixedPipelineDrawing->windowTabIndex); const CaretColorEnum::Enum caretColor = fociDisplayProperties->getStandardColorType(displayGroup, m_fixedPipelineDrawing->windowTabIndex); float caretColorRGBA[4]; CaretColorEnum::toRGBAFloat(caretColor, caretColorRGBA); bool drawAsSpheres = false; switch (fociDisplayProperties->getDrawingType(displayGroup, m_fixedPipelineDrawing->windowTabIndex)) { case FociDrawingTypeEnum::DRAW_AS_SPHERES: drawAsSpheres = true; break; case FociDrawingTypeEnum::DRAW_AS_SQUARES: break; } /* * Process each foci file */ const int32_t numberOfFociFiles = m_brain->getNumberOfFociFiles(); for (int32_t iFile = 0; iFile < numberOfFociFiles; iFile++) { FociFile* fociFile = m_brain->getFociFile(iFile); const GroupAndNameHierarchyModel* classAndNameSelection = fociFile->getGroupAndNameHierarchyModel(); if (classAndNameSelection->isSelected(displayGroup, m_fixedPipelineDrawing->windowTabIndex) == false) { continue; } const GiftiLabelTable* classColorTable = fociFile->getClassColorTable(); const GiftiLabelTable* nameColorTable = fociFile->getNameColorTable(); const int32_t numFoci = fociFile->getNumberOfFoci(); for (int32_t j = 0; j < numFoci; j++) { Focus* focus = fociFile->getFocus(j); const GroupAndNameHierarchyItem* groupNameItem = focus->getGroupNameSelectionItem(); if (groupNameItem != NULL) { if (groupNameItem->isSelected(displayGroup, m_fixedPipelineDrawing->windowTabIndex) == false) { continue; } } float rgba[4] = { 0.0, 0.0, 0.0, 1.0 }; switch (fociColoringType) { case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_CLASS: if (focus->isClassRgbaValid() == false) { const GiftiLabel* colorLabel = classColorTable->getLabelBestMatching(focus->getClassName()); if (colorLabel != NULL) { colorLabel->getColor(rgba); focus->setClassRgba(rgba); } else { focus->setClassRgba(rgba); } } focus->getClassRgba(rgba); break; case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_STANDARD_COLOR: rgba[0] = caretColorRGBA[0]; rgba[1] = caretColorRGBA[1]; rgba[2] = caretColorRGBA[2]; rgba[3] = caretColorRGBA[3]; break; case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_NAME: if (focus->isNameRgbaValid() == false) { const GiftiLabel* colorLabel = nameColorTable->getLabelBestMatching(focus->getName()); if (colorLabel != NULL) { colorLabel->getColor(rgba); focus->setNameRgba(rgba); } else { focus->setNameRgba(rgba); } } focus->getNameRgba(rgba); break; } const int32_t numProjections = focus->getNumberOfProjections(); for (int32_t k = 0; k < numProjections; k++) { const SurfaceProjectedItem* spi = focus->getProjection(k); if (spi->isVolumeXYZValid()) { float xyz[3]; spi->getVolumeXYZ(xyz); bool drawIt = false; if (plane.absoluteDistanceToPlane(xyz) < halfSliceThickness) { drawIt = true; } if (drawIt) { glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); if (isSelect) { uint8_t idRGBA[4]; m_fixedPipelineDrawing->colorIdentification->addItem(idRGBA, SelectionItemDataTypeEnum::FOCUS_VOLUME, iFile, // file index j, // focus index k);// projection index idRGBA[3] = 255; if (drawAsSpheres) { m_fixedPipelineDrawing->drawSphereWithDiameter(idRGBA, focusDiameter); } else { glColor4ubv(idRGBA); drawSquare(focusDiameter); } } else { if (drawAsSpheres) { m_fixedPipelineDrawing->drawSphereWithDiameter(rgba, focusDiameter); } else { glColor3fv(rgba); drawSquare(focusDiameter); } } glPopMatrix(); } } } } } if (isSelect) { int32_t fociFileIndex = -1; int32_t focusIndex = -1; int32_t focusProjectionIndex = -1; float depth = -1.0; m_fixedPipelineDrawing->getIndexFromColorSelection(SelectionItemDataTypeEnum::FOCUS_VOLUME, m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, fociFileIndex, focusIndex, focusProjectionIndex, depth); if (fociFileIndex >= 0) { if (idFocus->isOtherScreenDepthCloserToViewer(depth)) { Focus* focus = m_brain->getFociFile(fociFileIndex)->getFocus(focusIndex); idFocus->setBrain(m_brain); idFocus->setFocus(focus); idFocus->setFociFile(m_brain->getFociFile(fociFileIndex)); idFocus->setFocusIndex(focusIndex); idFocus->setFocusProjectionIndex(focusProjectionIndex); idFocus->setVolumeFile(underlayVolume); idFocus->setScreenDepth(depth); float xyz[3]; const SurfaceProjectedItem* spi = focus->getProjection(focusProjectionIndex); spi->getVolumeXYZ(xyz); m_fixedPipelineDrawing->setSelectedItemScreenXYZ(idFocus, xyz); CaretLogFine("Selected Volume Focus Identification Symbol: " + QString::number(focusIndex)); } } } } /** * Draw the axes crosshairs. * * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceViewPlane * View plane that is displayed. * @param sliceCoordinates * Coordinates of the selected slices. */ void BrainOpenGLVolumeObliqueSliceDrawing::drawAxesCrosshairs(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3]) { const bool drawCrosshairsFlag = m_browserTabContent->isVolumeAxesCrosshairsDisplayed(); bool drawCrosshairLabelsFlag = m_browserTabContent->isVolumeAxesCrosshairLabelsDisplayed(); switch (sliceDrawingType) { case VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_MONTAGE: drawCrosshairLabelsFlag = false; break; case VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE: break; } switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: CaretAssert(0); break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: { glPushMatrix(); glLoadIdentity(); drawAxesCrosshairsOblique(sliceViewPlane, sliceCoordinates, drawCrosshairsFlag, drawCrosshairLabelsFlag); glPopMatrix(); } break; } } /** * Draw the axes crosshairs for an orthogonal slice. * * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * The slice plane view. * @param sliceCoordinatesIn * Coordinates of the selected slices. * @param drawCrosshairsFlag * If true, draw the crosshairs. * @param drawCrosshairLabelsFlag * If true, draw the crosshair labels. */ void BrainOpenGLVolumeObliqueSliceDrawing::drawAxesCrosshairsOblique(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinatesIn[3], const bool drawCrosshairsFlag, const bool drawCrosshairLabelsFlag) { const float gapPercentViewportHeight = SessionManager::get()->getCaretPreferences()->getVolumeCrosshairGap(); const float gapMM = GraphicsUtilitiesOpenGL::convertPercentageOfViewportHeightToMillimeters(gapPercentViewportHeight); const std::array sliceCoordinates { sliceCoordinatesIn[0], sliceCoordinatesIn[1], sliceCoordinatesIn[2] }; GLboolean depthEnabled = GL_FALSE; glGetBooleanv(GL_DEPTH_TEST, &depthEnabled); glDisable(GL_DEPTH_TEST); const float bigValue = 10000.0 + gapMM; std::array horizontalAxisPosStartXYZ = sliceCoordinates; float trans[3]; m_browserTabContent->getTranslation(trans); std::array horizTrans { trans[0], trans[1], trans[2] }; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: break; case VolumeSliceViewPlaneEnum::AXIAL: break; case VolumeSliceViewPlaneEnum::CORONAL: horizontalAxisPosStartXYZ[0] = sliceCoordinates[0]; horizontalAxisPosStartXYZ[1] = sliceCoordinates[2]; horizontalAxisPosStartXYZ[2] = sliceCoordinates[1]; horizTrans[0] = trans[0]; horizTrans[1] = trans[2]; horizTrans[2] = trans[1]; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: horizontalAxisPosStartXYZ[0] = -sliceCoordinates[1]; horizontalAxisPosStartXYZ[1] = sliceCoordinates[2]; horizontalAxisPosStartXYZ[2] = sliceCoordinates[0]; horizTrans[0] = -trans[1]; horizTrans[1] = trans[2]; horizTrans[2] = trans[0]; break; } std::array horizontalAxisPosEndXYZ = horizontalAxisPosStartXYZ; std::array verticalAxisPosStartXYZ = horizontalAxisPosStartXYZ; std::array verticalAxisPosEndXYZ = horizontalAxisPosStartXYZ; std::array horizontalAxisNegStartXYZ = horizontalAxisPosStartXYZ; std::array horizontalAxisNegEndXYZ = horizontalAxisPosEndXYZ; std::array verticalAxisNegStartXYZ = verticalAxisPosStartXYZ; std::array verticalAxisNegEndXYZ = verticalAxisPosEndXYZ; std::array vertTrans = horizTrans; float axialRGBA[4]; getAxesColor(VolumeSliceViewPlaneEnum::AXIAL, axialRGBA); float coronalRGBA[4]; getAxesColor(VolumeSliceViewPlaneEnum::CORONAL, coronalRGBA); float paraRGBA[4]; getAxesColor(VolumeSliceViewPlaneEnum::PARASAGITTAL, paraRGBA); AString horizontalLeftText = ""; AString horizontalRightText = ""; AString verticalBottomText = ""; AString verticalTopText = ""; float* horizontalAxisRGBA = axialRGBA; float* verticalAxisRGBA = axialRGBA; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: break; case VolumeSliceViewPlaneEnum::AXIAL: horizontalLeftText = "L"; horizontalRightText = "R"; horizontalAxisRGBA = coronalRGBA; horizontalAxisPosStartXYZ[0] += gapMM; horizontalAxisPosEndXYZ[0] += bigValue; horizontalAxisNegStartXYZ[0] -= gapMM; horizontalAxisNegEndXYZ[0] -= bigValue; verticalBottomText = "P"; verticalTopText = "A"; verticalAxisRGBA = paraRGBA; verticalAxisPosStartXYZ[1] += gapMM; verticalAxisPosEndXYZ[1] += bigValue; verticalAxisNegStartXYZ[1] -= gapMM; verticalAxisNegEndXYZ[1] -= bigValue; break; case VolumeSliceViewPlaneEnum::CORONAL: horizontalLeftText = "L"; horizontalRightText = "R"; horizontalAxisRGBA = axialRGBA; horizontalAxisPosStartXYZ[0] += gapMM; horizontalAxisPosEndXYZ[0] += bigValue; horizontalAxisNegStartXYZ[0] -= gapMM; horizontalAxisNegEndXYZ[0] -= bigValue; verticalBottomText = "I"; verticalTopText = "S"; verticalAxisRGBA = paraRGBA; verticalAxisPosStartXYZ[1] += gapMM; verticalAxisPosEndXYZ[1] += bigValue; verticalAxisNegStartXYZ[1] -= gapMM; verticalAxisNegEndXYZ[1] -= bigValue; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: horizontalLeftText = "A"; horizontalRightText = "P"; horizontalAxisRGBA = axialRGBA; horizontalAxisPosStartXYZ[0] += gapMM; horizontalAxisPosEndXYZ[0] += bigValue; horizontalAxisNegStartXYZ[0] -= gapMM; horizontalAxisNegEndXYZ[0] -= bigValue; verticalBottomText = "I"; verticalTopText = "S"; verticalAxisRGBA = coronalRGBA; verticalAxisPosStartXYZ[1] += gapMM; verticalAxisPosEndXYZ[1] += bigValue; verticalAxisNegStartXYZ[1] -= gapMM; verticalAxisNegEndXYZ[1] -= bigValue; break; } /* * Offset text labels be a percentage of viewort width/height */ GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); const int textOffsetX = viewport[2] * 0.01f; const int textOffsetY = viewport[3] * 0.01f; const int textLeftWindowXY[2] = { textOffsetX, (viewport[3] / 2) }; const int textRightWindowXY[2] = { viewport[2] - textOffsetX, (viewport[3] / 2) }; const int textBottomWindowXY[2] = { viewport[2] / 2, textOffsetY }; const int textTopWindowXY[2] = { (viewport[2] / 2), viewport[3] - textOffsetY }; /* * Crosshairs */ if (drawCrosshairsFlag) { glPushMatrix(); glTranslatef(horizTrans[0], horizTrans[1], horizTrans[2]); std::unique_ptr horizHairPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); horizHairPrimitive->addVertex(&horizontalAxisPosStartXYZ[0], horizontalAxisRGBA); horizHairPrimitive->addVertex(&horizontalAxisPosEndXYZ[0], horizontalAxisRGBA); horizHairPrimitive->addVertex(&horizontalAxisNegStartXYZ[0], horizontalAxisRGBA); horizHairPrimitive->addVertex(&horizontalAxisNegEndXYZ[0], horizontalAxisRGBA); horizHairPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); GraphicsEngineDataOpenGL::draw(horizHairPrimitive.get()); glPopMatrix(); glPushMatrix(); glTranslatef(vertTrans[0], vertTrans[1], vertTrans[2]); std::unique_ptr vertHairPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); vertHairPrimitive->addVertex(&verticalAxisPosStartXYZ[0], verticalAxisRGBA); vertHairPrimitive->addVertex(&verticalAxisPosEndXYZ[0], verticalAxisRGBA); vertHairPrimitive->addVertex(&verticalAxisNegStartXYZ[0], verticalAxisRGBA); vertHairPrimitive->addVertex(&verticalAxisNegEndXYZ[0], verticalAxisRGBA); vertHairPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); GraphicsEngineDataOpenGL::draw(vertHairPrimitive.get()); glPopMatrix(); } if (drawCrosshairLabelsFlag) { const AnnotationTextFontPointSizeEnum::Enum fontSize = AnnotationTextFontPointSizeEnum::SIZE18; const int textCenter[2] = { textLeftWindowXY[0], textLeftWindowXY[1] }; const int halfFontSize = AnnotationTextFontPointSizeEnum::toSizeNumeric(fontSize) / 2; uint8_t backgroundRGBA[4] = { m_fixedPipelineDrawing->m_backgroundColorByte[0], m_fixedPipelineDrawing->m_backgroundColorByte[1], m_fixedPipelineDrawing->m_backgroundColorByte[2], m_fixedPipelineDrawing->m_backgroundColorByte[3] }; GLint savedViewport[4]; glGetIntegerv(GL_VIEWPORT, savedViewport); int vpLeftX = savedViewport[0] + textCenter[0] - halfFontSize; int vpRightX = savedViewport[0] + textCenter[0] + halfFontSize; int vpBottomY = savedViewport[1] + textCenter[1] - halfFontSize; int vpTopY = savedViewport[1] + textCenter[1] + halfFontSize; MathFunctions::limitRange(vpLeftX, savedViewport[0], savedViewport[0] + savedViewport[2]); MathFunctions::limitRange(vpRightX, savedViewport[0], savedViewport[0] + savedViewport[2]); MathFunctions::limitRange(vpBottomY, savedViewport[1], savedViewport[1] + savedViewport[3]); MathFunctions::limitRange(vpTopY, savedViewport[1], savedViewport[1] + savedViewport[3]); const int vpSizeX = vpRightX - vpLeftX; const int vpSizeY = vpTopY - vpBottomY; glViewport(vpLeftX, vpBottomY, vpSizeX, vpSizeY); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); std::vector rgba; std::vector coords, normals; coords.push_back(-1.0); coords.push_back(-1.0); coords.push_back( 0.0); normals.push_back(0.0); normals.push_back(0.0); normals.push_back(1.0); rgba.push_back(backgroundRGBA[0]); rgba.push_back(backgroundRGBA[1]); rgba.push_back(backgroundRGBA[2]); rgba.push_back(backgroundRGBA[3]); coords.push_back( 1.0); coords.push_back(-1.0); coords.push_back( 0.0); normals.push_back(0.0); normals.push_back(0.0); normals.push_back(1.0); rgba.push_back(backgroundRGBA[0]); rgba.push_back(backgroundRGBA[1]); rgba.push_back(backgroundRGBA[2]); rgba.push_back(backgroundRGBA[3]); coords.push_back( 1.0); coords.push_back( 1.0); coords.push_back( 0.0); normals.push_back(0.0); normals.push_back(0.0); normals.push_back(1.0); rgba.push_back(backgroundRGBA[0]); rgba.push_back(backgroundRGBA[1]); rgba.push_back(backgroundRGBA[2]); rgba.push_back(backgroundRGBA[3]); coords.push_back(-1.0); coords.push_back( 1.0); coords.push_back( 0.0); normals.push_back(0.0); normals.push_back(0.0); normals.push_back(1.0); rgba.push_back(backgroundRGBA[0]); rgba.push_back(backgroundRGBA[1]); rgba.push_back(backgroundRGBA[2]); rgba.push_back(backgroundRGBA[3]); BrainOpenGLPrimitiveDrawing::drawQuads(coords, normals, rgba); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glViewport(savedViewport[0], savedViewport[1], savedViewport[2], savedViewport[3]); AnnotationPercentSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); annotationText.setBoldStyleEnabled(true); annotationText.setFontPercentViewportSize(5.0f); annotationText.setTextColor(CaretColorEnum::CUSTOM); annotationText.setBackgroundColor(CaretColorEnum::CUSTOM); annotationText.setCustomTextColor(horizontalAxisRGBA); annotationText.setCustomBackgroundColor(backgroundRGBA); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); annotationText.setText(horizontalLeftText); m_fixedPipelineDrawing->drawTextAtViewportCoords(textLeftWindowXY[0], textLeftWindowXY[1], annotationText); annotationText.setText(horizontalRightText); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); m_fixedPipelineDrawing->drawTextAtViewportCoords(textRightWindowXY[0], textRightWindowXY[1], annotationText); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); annotationText.setCustomTextColor(verticalAxisRGBA); annotationText.setText(verticalBottomText); m_fixedPipelineDrawing->drawTextAtViewportCoords(textBottomWindowXY[0], textBottomWindowXY[1], annotationText); annotationText.setText(verticalTopText); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); annotationText.getCoordinate()->setXYZ(textTopWindowXY[0], textTopWindowXY[1], 0.0); m_fixedPipelineDrawing->drawTextAtViewportCoords(textTopWindowXY[0], textTopWindowXY[1], annotationText); } if (depthEnabled) { glEnable(GL_DEPTH_TEST); } } /** * Get the RGBA coloring for a slice view plane. * * @param sliceViewPlane * The slice view plane. * @param rgbaOut * Output colors ranging 0.0 to 1.0 */ void BrainOpenGLVolumeObliqueSliceDrawing::getAxesColor(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, float rgbaOut[4]) const { switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: rgbaOut[0] = 0.0; rgbaOut[1] = 0.0; rgbaOut[2] = 1.0; rgbaOut[3] = 1.0; break; case VolumeSliceViewPlaneEnum::CORONAL: rgbaOut[0] = 0.0; rgbaOut[1] = 1.0; rgbaOut[2] = 0.0; rgbaOut[3] = 1.0; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: rgbaOut[0] = 1.0; rgbaOut[1] = 0.0; rgbaOut[2] = 0.0; rgbaOut[3] = 1.0; break; } } /** * Draw a one millimeter square facing the user. * NOTE: This method will alter the current * modelviewing matrices so caller may need * to enclose the call to this method within * glPushMatrix() and glPopMatrix(). * * @param size * Size of square. */ void BrainOpenGLVolumeObliqueSliceDrawing::drawSquare(const float size) { const float length = size * 0.5; /* * Draw both front and back side since in some instances, * such as surface montage, we are viweing from the far * side (from back of monitor) */ glBegin(GL_QUADS); glNormal3f(0.0, 0.0, 1.0); glVertex3f(-length, -length, 0.0); glVertex3f( length, -length, 0.0); glVertex3f( length, length, 0.0); glVertex3f(-length, length, 0.0); glNormal3f(0.0, 0.0, -1.0); glVertex3f(-length, -length, 0.0); glVertex3f(-length, length, 0.0); glVertex3f( length, length, 0.0); glVertex3f( length, -length, 0.0); glEnd(); } /** * Get the minimum and maximum distance between adjacent voxels in all * slices planes. Output spacing value are always non-negative even if * a right-to-left orientation. * * @param volume * Volume for which min/max spacing is requested. * @param minSpacingOut * Output minimum spacing. * @param maxSpacingOut * Output maximum spacing. * @return * True if min and max spacing are greater than zero. */ bool BrainOpenGLVolumeObliqueSliceDrawing::getMinMaxVoxelSpacing(const VolumeMappableInterface* volume, float& minSpacingOut, float& maxSpacingOut) const { CaretAssert(volume); float originX, originY, originZ; float x1, y1, z1; volume->indexToSpace(0, 0, 0, originX, originY, originZ); volume->indexToSpace(1, 1, 1, x1, y1, z1); const float dx = std::fabs(x1 - originX); const float dy = std::fabs(y1 - originY); const float dz = std::fabs(z1 - originZ); minSpacingOut = std::min(std::min(dx, dy), dz); maxSpacingOut = std::max(std::max(dx, dy), dz); if ((minSpacingOut > 0.0) && (maxSpacingOut > 0.0)) { return true; } return false; } /** * Draw orientation axes * * @param viewport * The viewport region for the orientation axes. */ void BrainOpenGLVolumeObliqueSliceDrawing::drawOrientationAxes(const int viewport[4]) { const bool drawCylindersFlag = m_browserTabContent->isVolumeAxesCrosshairsDisplayed(); const bool drawLabelsFlag = m_browserTabContent->isVolumeAxesCrosshairLabelsDisplayed(); /* * Set the viewport */ glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); const double viewportWidth = viewport[2]; const double viewportHeight = viewport[3]; /* * Determine bounds for orthographic projection */ const double maxCoord = 100.0; const double minCoord = -maxCoord; double left = 0.0; double right = 0.0; double top = 0.0; double bottom = 0.0; const double nearDepth = -1000.0; const double farDepth = 1000.0; if (viewportHeight > viewportWidth) { left = minCoord; right = maxCoord; const double aspectRatio = (viewportHeight / viewportWidth); top = maxCoord * aspectRatio; bottom = minCoord * aspectRatio; } else { const double aspectRatio = (viewportWidth / viewportHeight); top = maxCoord; bottom = minCoord; left = minCoord * aspectRatio; right = maxCoord * aspectRatio; } /* * Set the orthographic projection */ glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(left, right, bottom, top, nearDepth, farDepth); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); { /* * Set the viewing transformation, places 'eye' so that it looks * at the 'model' which is, in this case, the axes */ double eyeX = 0.0; double eyeY = 0.0; double eyeZ = BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance; //100.0; const double centerX = 0; const double centerY = 0; const double centerZ = 0; const double upX = 0; const double upY = 1; const double upZ = 0; gluLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ); /* * Set the modeling transformation */ const Matrix4x4 obliqueRotationMatrix = m_browserTabContent->getObliqueVolumeRotationMatrix(); double rotationMatrix[16]; obliqueRotationMatrix.getMatrixForOpenGL(rotationMatrix); glMultMatrixd(rotationMatrix); /* * Disable depth buffer. Otherwise, when volume slices are drawn * black regions of the slices may set depth buffer and the occlude * the axes from display. */ GLboolean depthBufferEnabled = false; glGetBooleanv(GL_DEPTH_TEST, &depthBufferEnabled); glDisable(GL_DEPTH_TEST); const float red[4] = { 1.0, 0.0, 0.0, 1.0 }; const float green[4] = { 0.0, 1.0, 0.0, 1.0 }; const float blue[4] = { 0.0, 0.0, 1.0, 1.0 }; const double axisMaxCoord = maxCoord * 0.8; const double axisMinCoord = -axisMaxCoord; const double textMaxCoord = maxCoord * 0.9; const double textMinCoord = -textMaxCoord; const float axialPlaneMin[3] = { 0.0, 0.0, (float)axisMinCoord }; const float axialPlaneMax[3] = { 0.0, 0.0, (float)axisMaxCoord }; const double axialTextMin[3] = { 0.0, 0.0, (float)textMinCoord }; const double axialTextMax[3] = { 0.0, 0.0, (float)textMaxCoord }; const float coronalPlaneMin[3] = { (float)axisMinCoord, 0.0, 0.0 }; const float coronalPlaneMax[3] = { (float)axisMaxCoord, 0.0, 0.0 }; const double coronalTextMin[3] = { (float)textMinCoord, 0.0, 0.0 }; const double coronalTextMax[3] = { (float)textMaxCoord, 0.0, 0.0 }; const float paraPlaneMin[3] = { 0.0, (float)axisMinCoord, 0.0 }; const float paraPlaneMax[3] = { 0.0, (float)axisMaxCoord, 0.0 }; const double paraTextMin[3] = { 0.0, (float)textMinCoord, 0.0 }; const double paraTextMax[3] = { 0.0, (float)textMaxCoord, 0.0 }; /* * Set radius as percentage of viewport height */ float axesCrosshairRadius = 1.0; if (viewportHeight > 0) { const float percentageRadius = 0.005f; axesCrosshairRadius = percentageRadius * viewportHeight; } if (drawCylindersFlag) { m_fixedPipelineDrawing->drawCylinder(blue, axialPlaneMin, axialPlaneMax, axesCrosshairRadius * 0.5f); } AnnotationPercentSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); annotationText.setFontPercentViewportSize(5.0f); annotationText.setCoordinateSpace(AnnotationCoordinateSpaceEnum::STEREOTAXIC); annotationText.setTextColor(CaretColorEnum::CUSTOM); if (drawLabelsFlag) { annotationText.setCustomTextColor(blue); annotationText.setText("I"); m_fixedPipelineDrawing->drawTextAtModelCoords(axialTextMin, annotationText); annotationText.setText("S"); m_fixedPipelineDrawing->drawTextAtModelCoords(axialTextMax, annotationText); } if (drawCylindersFlag) { m_fixedPipelineDrawing->drawCylinder(green, coronalPlaneMin, coronalPlaneMax, axesCrosshairRadius * 0.5f); } if (drawLabelsFlag) { annotationText.setCustomTextColor(green); annotationText.setText("L"); m_fixedPipelineDrawing->drawTextAtModelCoords(coronalTextMin, annotationText); annotationText.setText("R"); m_fixedPipelineDrawing->drawTextAtModelCoords(coronalTextMax, annotationText); } if (drawCylindersFlag) { m_fixedPipelineDrawing->drawCylinder(red, paraPlaneMin, paraPlaneMax, axesCrosshairRadius * 0.5f); } if (drawLabelsFlag) { annotationText.setCustomTextColor(red); annotationText.setText("P"); m_fixedPipelineDrawing->drawTextAtModelCoords(paraTextMin, annotationText); annotationText.setText("A"); m_fixedPipelineDrawing->drawTextAtModelCoords(paraTextMax, annotationText); } } glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } /** * Set the orthographic projection. * * @param allSliceViewMode * Indicates drawing of ALL slices volume view (axial, coronal, parasagittal in one view) * @param sliceViewPlane * View plane that is displayed. * @param viewport * The viewport. */ void BrainOpenGLVolumeObliqueSliceDrawing::setOrthographicProjection(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const int viewport[4]) { const bool useOrthosDrawingProjectionFlag = false; /* does not work as expected when oblique */ if (useOrthosDrawingProjectionFlag) { /* * Determine model size in screen Y when viewed */ BoundingBox boundingBox; m_volumeDrawInfo[0].volumeFile->getVoxelSpaceBoundingBox(boundingBox); const double zoomFactor = m_browserTabContent->getScaling(); BrainOpenGLVolumeSliceDrawing::setOrthographicProjection(allSliceViewMode, sliceViewPlane, boundingBox, zoomFactor, viewport, m_orthographicBounds); return; } /* * Determine model size in screen Y when viewed */ BoundingBox boundingBox; m_volumeDrawInfo[0].volumeFile->getVoxelSpaceBoundingBox(boundingBox); /* * Set top and bottom to the min/max coordinate * that runs vertically on the screen */ double modelTop = 200.0; double modelBottom = -200.0; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssertMessage(0, "Should never get here"); break; case VolumeSliceViewPlaneEnum::AXIAL: modelTop = boundingBox.getMaxY(); modelBottom = boundingBox.getMinY(); break; case VolumeSliceViewPlaneEnum::CORONAL: modelTop = boundingBox.getMaxZ(); modelBottom = boundingBox.getMinZ(); break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: modelTop = boundingBox.getMaxZ(); modelBottom = boundingBox.getMinZ(); break; } switch (allSliceViewMode) { case BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_YES: { /* * Parasagittal and Coronal Views have Brain's Z-axis in Screen Y * Axial View has Brain's Y-axis in Screen Y * So, use maximum of Brain's Y- and Z-axes for sizing height of slice * so that voxels are same size for each slice in each axis view */ const float maxRangeYZ = std::max(boundingBox.getDifferenceY(), boundingBox.getDifferenceZ()); const float range = modelTop - modelBottom; if (maxRangeYZ > range) { const float diff = maxRangeYZ - range; const float halfDiff = diff / 2.0; modelTop += halfDiff; modelBottom -= halfDiff; } } break; case BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_NO: break; } /* * Scale ratio makes region slightly larger than model */ const double zoom = m_browserTabContent->getScaling(); double scaleRatio = (1.0 / 0.98); if (zoom > 0.0) { scaleRatio /= zoom; } modelTop *= scaleRatio; modelBottom *= scaleRatio; /* * Determine aspect ratio of viewport */ const double viewportWidth = viewport[2]; const double viewportHeight = viewport[3]; const double aspectRatio = (viewportWidth / viewportHeight); /* * Set bounds of orthographic projection */ const double halfModelY = ((modelTop - modelBottom) / 2.0); const double orthoBottom = modelBottom; const double orthoTop = modelTop; const double orthoRight = halfModelY * aspectRatio; const double orthoLeft = -halfModelY * aspectRatio; const double nearDepth = -1000.0; const double farDepth = 1000.0; m_orthographicBounds[0] = orthoLeft; m_orthographicBounds[1] = orthoRight; m_orthographicBounds[2] = orthoBottom; m_orthographicBounds[3] = orthoTop; m_orthographicBounds[4] = nearDepth; m_orthographicBounds[5] = farDepth; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(m_orthographicBounds[0], m_orthographicBounds[1], m_orthographicBounds[2], m_orthographicBounds[3], m_orthographicBounds[4], m_orthographicBounds[5]); glMatrixMode(GL_MODELVIEW); } /** * Reset for volume identification. * * Clear identification indices and if identification is enabled, * reserve a reasonable amount of space for the indices. */ void BrainOpenGLVolumeObliqueSliceDrawing::resetIdentification() { m_identificationIndices.clear(); if (m_identificationModeFlag) { int64_t estimatedNumberOfItems = 0; std::vector volumeDims; m_volumeDrawInfo[0].volumeFile->getDimensions(volumeDims); if (volumeDims.size() >= 3) { const int64_t maxDim = std::max(volumeDims[0], std::max(volumeDims[1], volumeDims[2])); estimatedNumberOfItems = maxDim * maxDim * IDENTIFICATION_INDICES_PER_VOXEL; } m_identificationIndices.reserve(estimatedNumberOfItems); } } /** * Add a voxel to the identification indices. * * @param volumeIndex * Index of the volume. * @param mapIndex * Index of the volume map. * @param voxelI * Voxel Index I * @param voxelJ * Voxel Index J * @param voxelK * Voxel Index K * @param voxelDiffXYZ * Change in XYZ from voxel bottom left to top right * @param rgbaForColorIdentificationOut * Encoded identification in RGBA color OUTPUT */ void BrainOpenGLVolumeObliqueSliceDrawing::addVoxelToIdentification(const int32_t volumeIndex, const int32_t mapIndex, const int32_t voxelI, const int32_t voxelJ, const int32_t voxelK, const float voxelDiffXYZ[3], uint8_t rgbaForColorIdentificationOut[4]) { const int32_t idIndex = m_identificationIndices.size() / IDENTIFICATION_INDICES_PER_VOXEL; m_fixedPipelineDrawing->colorIdentification->addItem(rgbaForColorIdentificationOut, SelectionItemDataTypeEnum::VOXEL, idIndex); rgbaForColorIdentificationOut[3] = 255; /* * ID stack requires integers to * use an integer pointer to the float values */ CaretAssert(sizeof(float) == sizeof(int32_t)); const int32_t* intPointerDiffXYZ = (int32_t*)voxelDiffXYZ; /* * If these items change, need to update reset and * processing of identification. */ m_identificationIndices.push_back(volumeIndex); m_identificationIndices.push_back(mapIndex); m_identificationIndices.push_back(voxelI); m_identificationIndices.push_back(voxelJ); m_identificationIndices.push_back(voxelK); m_identificationIndices.push_back(intPointerDiffXYZ[0]); m_identificationIndices.push_back(intPointerDiffXYZ[1]); m_identificationIndices.push_back(intPointerDiffXYZ[2]); } /** * Process voxel identification. */ void BrainOpenGLVolumeObliqueSliceDrawing::processIdentification() { int32_t identifiedItemIndex; float depth = -1.0; m_fixedPipelineDrawing->getIndexFromColorSelection(SelectionItemDataTypeEnum::VOXEL, m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, identifiedItemIndex, depth); if (identifiedItemIndex >= 0) { const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_VOXEL; const int32_t volDrawInfoIndex = m_identificationIndices[idIndex]; CaretAssertVectorIndex(m_volumeDrawInfo, volDrawInfoIndex); VolumeMappableInterface* vf = m_volumeDrawInfo[volDrawInfoIndex].volumeFile; const int64_t voxelIndices[3] = { m_identificationIndices[idIndex + 2], m_identificationIndices[idIndex + 3], m_identificationIndices[idIndex + 4] }; const float* floatDiffXYZ = (float*)&m_identificationIndices[idIndex + 5]; SelectionItemVoxel* voxelID = m_brain->getSelectionManager()->getVoxelIdentification(); if (voxelID->isEnabledForSelection()) { if (voxelID->isOtherScreenDepthCloserToViewer(depth)) { voxelID->setVoxelIdentification(m_brain, vf, voxelIndices, depth); float voxelCoordinates[3]; vf->indexToSpace(voxelIndices[0], voxelIndices[1], voxelIndices[2], voxelCoordinates[0], voxelCoordinates[1], voxelCoordinates[2]); m_fixedPipelineDrawing->setSelectedItemScreenXYZ(voxelID, voxelCoordinates); CaretLogFinest("Selected Voxel (3D): " + AString::fromNumbers(voxelIndices, 3, ",")); } } SelectionItemVoxelEditing* voxelEditID = m_brain->getSelectionManager()->getVoxelEditingIdentification(); if (voxelEditID->isEnabledForSelection()) { if (voxelEditID->getVolumeFileForEditing() == vf) { if (voxelEditID->isOtherScreenDepthCloserToViewer(depth)) { voxelEditID->setVoxelIdentification(m_brain, vf, voxelIndices, depth); voxelEditID->setVoxelDiffXYZ(floatDiffXYZ); float voxelCoordinates[3]; vf->indexToSpace(voxelIndices[0], voxelIndices[1], voxelIndices[2], voxelCoordinates[0], voxelCoordinates[1], voxelCoordinates[2]); m_fixedPipelineDrawing->setSelectedItemScreenXYZ(voxelEditID, voxelCoordinates); CaretLogFinest("Selected Voxel Editing (3D): Indices (" + AString::fromNumbers(voxelIndices, 3, ",") + ") Diff XYZ (" + AString::fromNumbers(floatDiffXYZ, 3, ",") + ")"); } } } } } /** * Get the maximum bounds that enclose the volumes and the minimum * voxel spacing from the volumes. * * @param boundsOut * Bounds of the volumes. * @param spacingOut * Minimum voxel spacing from the volumes. Always positive values (even if * volumes is oriented right to left). * */ bool BrainOpenGLVolumeObliqueSliceDrawing::getVoxelCoordinateBoundsAndSpacing(float boundsOut[6], float spacingOut[3]) { const int32_t numberOfVolumesToDraw = static_cast(m_volumeDrawInfo.size()); if (numberOfVolumesToDraw <= 0) { return false; } /* * Find maximum extent of all voxels and smallest voxel * size in each dimension. */ float minVoxelX = std::numeric_limits::max(); float maxVoxelX = -std::numeric_limits::max(); float minVoxelY = std::numeric_limits::max(); float maxVoxelY = -std::numeric_limits::max(); float minVoxelZ = std::numeric_limits::max(); float maxVoxelZ = -std::numeric_limits::max(); float voxelStepX = std::numeric_limits::max(); float voxelStepY = std::numeric_limits::max(); float voxelStepZ = std::numeric_limits::max(); for (int32_t i = 0; i < numberOfVolumesToDraw; i++) { const VolumeMappableInterface* volumeFile = m_volumeDrawInfo[i].volumeFile; int64_t dimI, dimJ, dimK, numMaps, numComponents; volumeFile->getDimensions(dimI, dimJ, dimK, numMaps, numComponents); float originX, originY, originZ; float x1, y1, z1; float lastX, lastY, lastZ; volumeFile->indexToSpace(0, 0, 0, originX, originY, originZ); volumeFile->indexToSpace(1, 1, 1, x1, y1, z1); volumeFile->indexToSpace(dimI - 1, dimJ - 1, dimK - 1, lastX, lastY, lastZ); const float dx = x1 - originX; const float dy = y1 - originY; const float dz = z1 - originZ; voxelStepX = std::min(voxelStepX, std::fabs(dx)); voxelStepY = std::min(voxelStepY, std::fabs(dy)); voxelStepZ = std::min(voxelStepZ, std::fabs(dz)); minVoxelX = std::min(minVoxelX, std::min(originX, lastX)); maxVoxelX = std::max(maxVoxelX, std::max(originX, lastX)); minVoxelY = std::min(minVoxelY, std::min(originY, lastY)); maxVoxelY = std::max(maxVoxelY, std::max(originY, lastY)); minVoxelZ = std::min(minVoxelZ, std::min(originZ, lastZ)); maxVoxelZ = std::max(maxVoxelZ, std::max(originZ, lastZ)); } boundsOut[0] = minVoxelX; boundsOut[1] = maxVoxelX; boundsOut[2] = minVoxelY; boundsOut[3] = maxVoxelY; boundsOut[4] = minVoxelZ; boundsOut[5] = maxVoxelZ; spacingOut[0] = voxelStepX; spacingOut[1] = voxelStepY; spacingOut[2] = voxelStepZ; /* * Two dimensions: single slice * Three dimensions: multiple slices */ int32_t validDimCount = 0; if (maxVoxelX > minVoxelX) validDimCount++; if (maxVoxelY > minVoxelY) validDimCount++; if (maxVoxelZ > minVoxelZ) validDimCount++; bool valid = false; if ((validDimCount >= 2) && (voxelStepX > 0.0) && (voxelStepY > 0.0) && (voxelStepZ > 0.0)) { valid = true; } return valid; } /** * Create the oblique transformation matrix. * * @param sliceCoordinates * Slice that is being drawn. * @param obliqueTransformationMatrixOut * OUTPUT transformation matrix for oblique viewing. */ void BrainOpenGLVolumeObliqueSliceDrawing::createObliqueTransformationMatrix(const float sliceCoordinates[3], Matrix4x4& obliqueTransformationMatrixOut) { /* * Initialize the oblique transformation matrix */ obliqueTransformationMatrixOut.identity(); /* * Get the oblique rotation matrix */ Matrix4x4 obliqueRotationMatrix = m_browserTabContent->getObliqueVolumeRotationMatrix(); /* * Create the transformation matrix */ obliqueTransformationMatrixOut.postmultiply(obliqueRotationMatrix); /* * Translate to selected coordinate */ obliqueTransformationMatrixOut.translate(sliceCoordinates[0], sliceCoordinates[1], sliceCoordinates[2]); } /* ======================================================================= */ /** * Draw an oblique slice with support for outlining labels and thresholded palette data. * * @param sliceViewPlane * The plane for slice drawing. * @param transformationMatrix * The for oblique viewing. */ void BrainOpenGLVolumeObliqueSliceDrawing::drawObliqueSliceWithOutlines(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, Matrix4x4& transformationMatrix) { /* * When performing voxel identification for editing voxels, * we need to draw EVERY voxel since the user may click * regions where the voxels are "off". */ float voxelEditingValue = 1.0; VolumeFile* voxelEditingVolumeFile = NULL; if (m_identificationModeFlag) { SelectionItemVoxelEditing* voxelEditID = m_brain->getSelectionManager()->getVoxelEditingIdentification(); if (voxelEditID->isEnabledForSelection()) { voxelEditingVolumeFile = voxelEditID->getVolumeFileForEditing(); if (voxelEditingVolumeFile != NULL) { if (voxelEditingVolumeFile->isMappedWithLabelTable()) { if (voxelEditingVolumeFile->getNumberOfMaps() > 0) { voxelEditingValue = voxelEditingVolumeFile->getMapLabelTable(0)->getUnassignedLabelKey(); } } } } } const bool obliqueSliceModeThreeDimFlag = false; float m[16]; glGetFloatv(GL_MODELVIEW_MATRIX, m); Matrix4x4 tm; tm.setMatrixFromOpenGL(m); const int32_t numVolumes = static_cast(m_volumeDrawInfo.size()); /* * Get the maximum bounds of the voxels from all slices * and the smallest voxel spacing */ float voxelBounds[6]; float voxelSpacing[3]; if ( ! getVoxelCoordinateBoundsAndSpacing(voxelBounds, voxelSpacing)) { return; } float voxelSize = std::min(voxelSpacing[0], std::min(voxelSpacing[1], voxelSpacing[2])); /* * Use a larger voxel size for the 3D view in volume slice viewing * since it draws all three slices and this takes time */ if (obliqueSliceModeThreeDimFlag) { voxelSize *= 3.0; } /* * Look at point is in center of volume */ float translation[3]; m_browserTabContent->getTranslation(translation); float viewOffsetX = 0.0; float viewOffsetY = 0.0; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: viewOffsetX = (m_lookAtCenter[0] + translation[0]); viewOffsetY = (m_lookAtCenter[1] + translation[1]); break; case VolumeSliceViewPlaneEnum::CORONAL: viewOffsetX = (m_lookAtCenter[0] + translation[0]); viewOffsetY = (m_lookAtCenter[2] + translation[2]); break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: viewOffsetX = (m_lookAtCenter[1] + translation[1]); viewOffsetY = (m_lookAtCenter[2] + translation[2]); break; } float minScreenX = m_orthographicBounds[0] - viewOffsetX; float maxScreenX = m_orthographicBounds[1] - viewOffsetX; float minScreenY = m_orthographicBounds[2] - viewOffsetY; float maxScreenY = m_orthographicBounds[3] - viewOffsetY; /* * Get origin voxel IJK */ const float zeroXYZ[3] = { 0.0, 0.0, 0.0 }; int64_t originIJK[3]; m_volumeDrawInfo[0].volumeFile->enclosingVoxel(zeroXYZ[0], zeroXYZ[1], zeroXYZ[2], originIJK[0], originIJK[1], originIJK[2]); /* * Get XYZ center of origin Voxel */ float originVoxelXYZ[3]; m_volumeDrawInfo[0].volumeFile->indexToSpace(originIJK, originVoxelXYZ); float actualOrigin[3]; m_volumeDrawInfo[0].volumeFile->indexToSpace(originIJK, actualOrigin); float screenOffsetX = 0.0; float screenOffsetY = 0.0; float originOffsetX = 0.0; float originOffsetY = 0.0; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: screenOffsetX = m_lookAtCenter[0]; screenOffsetY = m_lookAtCenter[1]; originOffsetX = actualOrigin[0]; originOffsetY = actualOrigin[1]; break; case VolumeSliceViewPlaneEnum::CORONAL: screenOffsetX = m_lookAtCenter[0]; screenOffsetY = m_lookAtCenter[2]; originOffsetX = actualOrigin[0]; originOffsetY = actualOrigin[2]; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: screenOffsetX = m_lookAtCenter[1]; screenOffsetY = m_lookAtCenter[2]; originOffsetX = actualOrigin[1]; originOffsetY = actualOrigin[2]; break; } const int32_t alignVoxelsFlag = 1; if (alignVoxelsFlag == 1) { /* * Adjust for when selected slices are not at the origin */ const float xOffset = MathFunctions::remainder(screenOffsetX, voxelSize); const float yOffset = MathFunctions::remainder(screenOffsetY, voxelSize); originOffsetX -= xOffset; originOffsetY -= yOffset; const int64_t numVoxelsToLeft = static_cast(MathFunctions::round(minScreenX + originOffsetX) / voxelSize); const int64_t numVoxelsToRight = static_cast(MathFunctions::round(maxScreenX + originOffsetX) / voxelSize); const int64_t numVoxelsToBottom = static_cast(MathFunctions::round(minScreenY + originOffsetY) / voxelSize); const int64_t numVoxelsToTop = static_cast(MathFunctions::round(maxScreenY + originOffsetY)/ voxelSize); const float halfVoxel = voxelSize / 2.0; const float firstVoxelCenterX = (numVoxelsToLeft * voxelSize) + originOffsetX; const float lastVoxelCenterX = (numVoxelsToRight * voxelSize) + originOffsetX; const float firstVoxelCenterY = (numVoxelsToBottom * voxelSize) + originOffsetY; const float lastVoxelCenterY = (numVoxelsToTop * voxelSize) + originOffsetY; float newMinScreenX = firstVoxelCenterX - halfVoxel; float newMaxScreenX = lastVoxelCenterX + halfVoxel; float newMinScreenY = firstVoxelCenterY - halfVoxel; float newMaxScreenY = lastVoxelCenterY + halfVoxel; if (debugFlag) { const AString msg2 = ("Origin Voxel Coordinate: (" + AString::fromNumbers(actualOrigin, 3, ",") + "\n Oblique Screen X: (" + AString::number(minScreenX) + "," + AString::number(maxScreenX) + ") Y: (" + AString::number(minScreenY) + "," + AString::number(maxScreenY) + ")\nNew X: (" + AString::number(newMinScreenX) + "," + AString::number(newMaxScreenX) + ") Y: (" + AString::number(newMinScreenY) + "," + AString::number(newMaxScreenY) + ") Diff: (" + AString::number((newMaxScreenX - newMinScreenX) / voxelSize) + "," + AString::number((newMaxScreenY - newMinScreenY) / voxelSize) + ")"); std::cout << qPrintable(msg2) << std::endl; } minScreenX = newMinScreenX; maxScreenX = newMaxScreenX; minScreenY = newMinScreenY; maxScreenY = newMaxScreenY; } /* * Set the corners of the screen for the respective view */ float bottomLeft[3]; float bottomRight[3]; float topRight[3]; float topLeft[3]; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: bottomLeft[0] = minScreenX; bottomLeft[1] = minScreenY; bottomLeft[2] = 0.0; bottomRight[0] = maxScreenX; bottomRight[1] = minScreenY; bottomRight[2] = 0.0; topRight[0] = maxScreenX; topRight[1] = maxScreenY; topRight[2] = 0.0; topLeft[0] = minScreenX; topLeft[1] = maxScreenY; topLeft[2] = 0.0; break; case VolumeSliceViewPlaneEnum::CORONAL: bottomLeft[0] = minScreenX; bottomLeft[1] = 0.0; bottomLeft[2] = minScreenY; bottomRight[0] = maxScreenX; bottomRight[1] = 0.0; bottomRight[2] = minScreenY; topRight[0] = maxScreenX; topRight[1] = 0.0; topRight[2] = maxScreenY; topLeft[0] = minScreenX; topLeft[1] = 0.0; topLeft[2] = maxScreenY; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: bottomLeft[0] = 0.0; bottomLeft[1] = minScreenX; bottomLeft[2] = minScreenY; bottomRight[0] = 0.0; bottomRight[1] = maxScreenX; bottomRight[2] = minScreenY; topRight[0] = 0.0; topRight[1] = maxScreenX; topRight[2] = maxScreenY; topLeft[0] = 0.0; topLeft[1] = minScreenX; topLeft[2] = maxScreenY; break; } /* * Transform the corners of the screen into model coordinates */ transformationMatrix.multiplyPoint3(bottomLeft); transformationMatrix.multiplyPoint3(bottomRight); transformationMatrix.multiplyPoint3(topRight); transformationMatrix.multiplyPoint3(topLeft); if (debugFlag) { const double bottomDist = MathFunctions::distance3D(bottomLeft, bottomRight); const double topDist = MathFunctions::distance3D(topLeft, topRight); const double bottomVoxels = bottomDist / voxelSize; const double topVoxels = topDist / voxelSize; const AString msg = ("Bottom Dist: " + AString::number(bottomDist) + " voxel size: " + AString::number(bottomVoxels) + " Top Dist: " + AString::number(bottomDist) + " voxel size: " + AString::number(topVoxels)); std::cout << qPrintable(msg) << std::endl; } if (debugFlag) { m_fixedPipelineDrawing->setLineWidth(3.0); glColor3f(1.0, 0.0, 0.0); glBegin(GL_LINE_LOOP); glVertex3fv(bottomLeft); glVertex3fv(bottomRight); glVertex3fv(topRight); glVertex3fv(topLeft); glEnd(); } /* * Unit vector and distance in model coords along left side of screen */ double bottomLeftToTopLeftUnitVector[3] = { topLeft[0] - bottomLeft[0], topLeft[1] - bottomLeft[1], topLeft[2] - bottomLeft[2], }; MathFunctions::normalizeVector(bottomLeftToTopLeftUnitVector); const double bottomLeftToTopLeftDistance = MathFunctions::distance3D(bottomLeft, topLeft); /* * Unit vector and distance in model coords along right side of screen */ double bottomRightToTopRightUnitVector[3] = { topRight[0] - bottomRight[0], topRight[1] - bottomRight[1], topRight[2] - bottomRight[2] }; MathFunctions::normalizeVector(bottomRightToTopRightUnitVector); const double bottomRightToTopRightDistance = MathFunctions::distance3D(bottomRight, topRight); if ((bottomLeftToTopLeftDistance > 0) && (bottomRightToTopRightDistance > 0)) { float leftToRightStepXYZ[3] = { bottomRight[0] - bottomLeft[0], bottomRight[1] - bottomLeft[1], bottomRight[2] - bottomLeft[2] }; const float bottomLeftToBottomRightDistance = MathFunctions::normalizeVector(leftToRightStepXYZ); leftToRightStepXYZ[0] *= voxelSize; leftToRightStepXYZ[1] *= voxelSize; leftToRightStepXYZ[2] *= voxelSize; const int32_t numberOfRows = std::round(bottomLeftToTopLeftDistance / voxelSize); const int32_t numberOfColumns = std::round(bottomLeftToBottomRightDistance / voxelSize); float bottomToTopStepXYZ[3] = { topLeft[0] - bottomLeft[0], topLeft[1] - bottomLeft[1], topLeft[2] - bottomLeft[2] }; MathFunctions::normalizeVector(bottomToTopStepXYZ); bottomToTopStepXYZ[0] *= voxelSize; bottomToTopStepXYZ[1] *= voxelSize; bottomToTopStepXYZ[2] *= voxelSize; const int32_t browserTabIndex = m_browserTabContent->getTabNumber(); const DisplayPropertiesLabels* displayPropertiesLabels = m_brain->getDisplayPropertiesLabels(); const DisplayGroupEnum::Enum displayGroup = displayPropertiesLabels->getDisplayGroupForTab(browserTabIndex); bool haveAlphaBlendingFlag(false); std::vector slices; for (int32_t iVol = 0; iVol < numVolumes; iVol++) { const BrainOpenGLFixedPipeline::VolumeDrawInfo& vdi = m_volumeDrawInfo[iVol]; VolumeMappableInterface* volInter = vdi.volumeFile; bool volumeEditDrawAllVoxelsFlag = false; if (voxelEditingVolumeFile != NULL) { if (voxelEditingVolumeFile == m_volumeDrawInfo[iVol].volumeFile) { volumeEditDrawAllVoxelsFlag = true; } } const bool bottomLayerFlag(iVol == 0); ObliqueSlice* slice = new ObliqueSlice(m_fixedPipelineDrawing, volInter, m_volumeDrawInfo[iVol].opacity, m_volumeDrawInfo[iVol].mapIndex, numberOfRows, numberOfColumns, browserTabIndex, displayPropertiesLabels, displayGroup, bottomLeft, leftToRightStepXYZ, bottomToTopStepXYZ, m_obliqueSliceMaskingType, voxelEditingValue, volumeEditDrawAllVoxelsFlag, m_identificationModeFlag, bottomLayerFlag); slices.push_back(slice); if (m_volumeDrawInfo[iVol].opacity < 1.0) { haveAlphaBlendingFlag = true; } } const int32_t numSlices = static_cast(slices.size()); if (numSlices > 0) { bool drawEachSliceFlag = true; bool compositeFlag = true; if (haveAlphaBlendingFlag || m_identificationModeFlag) { /* * Do not composite slices if blending is used * or if in identification mode */ compositeFlag = false; } if (compositeFlag) { CaretAssertVectorIndex(slices, 0); ObliqueSlice* underlaySlice = slices[0]; if (numSlices > 1) { std::vector overlaySlices; for (int32_t i = 1; i < numSlices; i++) { CaretAssertVectorIndex(slices, i); overlaySlices.push_back(slices[i]); } if (underlaySlice->compositeSlicesRGBA(overlaySlices)) { underlaySlice->draw(m_fixedPipelineDrawing); drawEachSliceFlag = false; } } } if (drawEachSliceFlag) { for (auto s : slices) { s->draw(m_fixedPipelineDrawing); } } } for (auto s : slices) { delete s; } slices.clear(); } } /** * Constructor for drawing an oblique slice. * * @param fixedPipelineDrawing * The fixed pipeline drawing. * @param volumeInterface * Interface for volume-type file being drawn. * @param opacity * Opacity for drawing the slice. * @param mapIndex * Index of map in file being drawn. * @param numberOfRows * Number of rows used when drawing slice. * @param numberOfColumns * Number of columns used when drawing slice. * @param browserTabIndex * Index of browser tab being drawn. * @param displayPropertiesLabels * Display properties for labels. * @param displayGroup * Selected display group for labels. * @param originXYZ * XYZ coordinate of first voxel in slice. * @param leftToRightStepXYZ * XYZ step for one voxel in screen left to right. * @param bottomToTopStepXYZ * XYZ step for one voxel in screen bottom to top. * @param maskingType * Masking type to eliminate interpolation artifacts * @param voxelEditingValue * Value used when editing voxels. * @param volumeEditingDrawAllVoxelsFlag * Draw all voxels when editing a volume. * @param identificationModeFlag * True if identification mode is active. * @param bottomLayerFlag * True if bottom layer. */ BrainOpenGLVolumeObliqueSliceDrawing::ObliqueSlice::ObliqueSlice(BrainOpenGLFixedPipeline* fixedPipelineDrawing, VolumeMappableInterface* volumeInterface, const float opacity, const int32_t mapIndex, const int32_t numberOfRows, const int32_t numberOfColumns, const int32_t browserTabIndex, const DisplayPropertiesLabels* displayPropertiesLabels, const DisplayGroupEnum::Enum displayGroup, const float originXYZ[3], const float leftToRightStepXYZ[3], const float bottomToTopStepXYZ[3], const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum maskingType, const float voxelEditingValue, const bool volumeEditingDrawAllVoxelsFlag, const bool identificationModeFlag, const bool bottomLayerFlag) : m_volumeInterface(volumeInterface), m_opacity(opacity), m_mapFile(dynamic_cast(volumeInterface)), m_mapIndex(mapIndex), m_numberOfRows(numberOfRows), m_numberOfColumns(numberOfColumns), m_browserTabIndex(browserTabIndex), m_displayPropertiesLabels(displayPropertiesLabels), m_displayGroup(displayGroup), m_identificationX(fixedPipelineDrawing->mouseX), m_identificationY(fixedPipelineDrawing->mouseY), m_identificationModeFlag(identificationModeFlag), m_bottomLayerFlag(bottomLayerFlag) { CaretAssert(volumeInterface); CaretAssert(m_mapFile); m_opacityByte = 255; if (m_opacity >= 1.0) { m_opacityByte = 255; } if (m_opacity <= 0.0) { m_opacityByte = 0; } else { m_opacityByte = static_cast(m_opacity * 255.0f); } for (int32_t i = 0; i < 3; i++) { m_selectionIJK[i] = -1; m_leftToRightStepXYZ[i] = leftToRightStepXYZ[i]; m_bottomToTopStepXYZ[i] = bottomToTopStepXYZ[i]; m_originXYZ[i] = originXYZ[i]; } const VolumeFile* volumeFileConst = dynamic_cast(volumeInterface); m_volumeFile = const_cast(volumeFileConst); const CiftiMappableDataFile* ciftiMappableFileConst = dynamic_cast(volumeInterface); m_ciftiMappableFile = const_cast(ciftiMappableFileConst); m_dataValueType = DataValueType::INVALID; if (m_mapFile->isMappedWithPalette()) { if (m_volumeFile != NULL) { m_dataValueType = DataValueType::VOLUME_PALETTE; } else if (m_ciftiMappableFile != NULL) { m_dataValueType = DataValueType::CIFTI_PALETTE; } else { CaretAssert(0); } } else if (m_mapFile->isMappedWithLabelTable()) { if (m_volumeFile != NULL) { m_dataValueType = DataValueType::VOLUME_LABEL; } else if (m_ciftiMappableFile != NULL) { m_dataValueType = DataValueType::CIFTI_LABEL; } else { CaretAssert(0); } } else if (m_mapFile->isMappedWithRGBA()) { if (m_volumeFile != NULL) { if (m_volumeFile->getNumberOfComponents() == 4) { m_dataValueType = DataValueType::VOLUME_RGBA; } else if (m_volumeFile->getNumberOfComponents() == 3) { m_dataValueType = DataValueType::VOLUME_RGB; } } else { CaretAssert(0); } } CaretAssert(m_dataValueType != DataValueType::INVALID); m_sliceNumberOfVoxels = m_numberOfRows * m_numberOfColumns; m_voxelNumberOfComponents = 1; switch (m_dataValueType) { case DataValueType::INVALID: CaretAssert(0); break; case DataValueType::CIFTI_LABEL: case DataValueType::CIFTI_PALETTE: case DataValueType::VOLUME_LABEL: case DataValueType::VOLUME_PALETTE: break; case DataValueType::VOLUME_RGB: case DataValueType::VOLUME_RGBA: m_voxelNumberOfComponents = 4; break; } m_data.reserve(m_sliceNumberOfVoxels * m_voxelNumberOfComponents); m_thresholdData.reserve(m_data.size()); m_rgba.reserve(m_sliceNumberOfVoxels * 4); if (m_identificationModeFlag) { m_identificationIJK.reserve(m_sliceNumberOfVoxels * 3); m_identificationHelper.reset(new IdentificationWithColor()); } setThresholdFileAndMap(); loadData(maskingType, voxelEditingValue, volumeEditingDrawAllVoxelsFlag); assignRgba(volumeEditingDrawAllVoxelsFlag); if ( ! m_identificationModeFlag) { addOutlines(); } CaretAssert((m_sliceNumberOfVoxels*4) == static_cast(m_rgba.size())); } /** * Set thresholding file and map, if applicable. */ bool BrainOpenGLVolumeObliqueSliceDrawing::ObliqueSlice::setThresholdFileAndMap() { switch (m_dataValueType) { case DataValueType::INVALID: CaretAssert(0); break; case DataValueType::CIFTI_LABEL: break; case DataValueType::CIFTI_PALETTE: { const PaletteColorMapping* pcm = m_ciftiMappableFile->getMapPaletteColorMapping(m_mapIndex); CaretAssert(pcm); switch (pcm->getThresholdType()) { case PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF: break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_NORMAL: m_thresholdCiftiMappableFile = m_ciftiMappableFile; m_thresholdMapIndex = m_mapIndex; break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_FILE: { CaretMappableDataFileAndMapSelectionModel* selector = m_ciftiMappableFile->getMapThresholdFileSelectionModel(m_mapIndex); m_thresholdCiftiMappableFile = dynamic_cast(selector->getSelectedFile()); if (m_thresholdCiftiMappableFile != NULL) { m_thresholdMapIndex = selector->getSelectedMapIndex(); } } break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED: case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED_AVERAGE_AREA: CaretAssert(0); break; } if (m_thresholdCiftiMappableFile != NULL) { if ((m_thresholdMapIndex >= 0) && (m_thresholdMapIndex < m_thresholdCiftiMappableFile->getNumberOfMaps())) { m_thresholdPaletteColorMapping = m_thresholdCiftiMappableFile->getMapPaletteColorMapping(m_thresholdMapIndex); } else { m_thresholdCiftiMappableFile = NULL; m_thresholdMapIndex = -1; } } } break; case DataValueType::VOLUME_LABEL: break; case DataValueType::VOLUME_PALETTE: { const PaletteColorMapping* pcm = m_volumeFile->getMapPaletteColorMapping(m_mapIndex); CaretAssert(pcm); switch (pcm->getThresholdType()) { case PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF: break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_NORMAL: m_thresholdVolumeFile = m_volumeFile; m_thresholdMapIndex = m_mapIndex; break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_FILE: { CaretMappableDataFileAndMapSelectionModel* selector = m_volumeFile->getMapThresholdFileSelectionModel(m_mapIndex); m_thresholdVolumeFile = dynamic_cast(selector->getSelectedFile()); if (m_thresholdVolumeFile != NULL) { m_thresholdMapIndex = selector->getSelectedMapIndex(); } } break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED: case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED_AVERAGE_AREA: CaretAssert(0); break; } if (m_thresholdVolumeFile != NULL) { if ((m_thresholdMapIndex >= 0) && (m_thresholdMapIndex < m_thresholdVolumeFile->getNumberOfMaps())) { m_thresholdPaletteColorMapping = m_thresholdVolumeFile->getMapPaletteColorMapping(m_thresholdMapIndex); } else { m_thresholdVolumeFile = NULL; m_thresholdMapIndex = -1; } } } break; case DataValueType::VOLUME_RGB: break; case DataValueType::VOLUME_RGBA: break; } if (m_thresholdMapIndex < 0) { m_thresholdCiftiMappableFile = NULL; m_thresholdVolumeFile = NULL; m_thresholdPaletteColorMapping = NULL; } return (m_thresholdMapIndex >= 0); } /** * Assign RGBA coloring for the voxels. * * @param volumeEditingDrawAllVoxelsFlag * True if editing and all voxels should be drawn for selection. */ void BrainOpenGLVolumeObliqueSliceDrawing::ObliqueSlice::assignRgba(const bool volumeEditingDrawAllVoxelsFlag) { if (m_data.empty()) { return; } switch (m_dataValueType) { case DataValueType::INVALID: CaretAssert(0); break; case DataValueType::CIFTI_LABEL: case DataValueType::CIFTI_PALETTE: case DataValueType::VOLUME_LABEL: case DataValueType::VOLUME_PALETTE: /* * One data value per voxel. */ m_rgba.resize(m_data.size() * 4); break; case DataValueType::VOLUME_RGB: case DataValueType::VOLUME_RGBA: /* * For RGBA, there are four data values per voxel */ m_rgba.resize(m_data.size()); break; } if (volumeEditingDrawAllVoxelsFlag) { const int32_t numVoxels = static_cast(m_rgba.size() / 4); for (int32_t i = 0; i < numVoxels; i++) { const int32_t i4 = i * 4; m_rgba[i4] = 255; m_rgba[i4+1] = 255; m_rgba[i4+2] = 255; m_rgba[i4+3] = 255; } return; } switch (m_dataValueType) { case DataValueType::INVALID: break; case DataValueType::CIFTI_LABEL: { CaretAssert(m_ciftiMappableFile); const GiftiLabelTable* labelTable = m_ciftiMappableFile->getMapLabelTable(m_mapIndex); CaretAssert(labelTable); NodeAndVoxelColoring::colorIndicesWithLabelTableForDisplayGroupTab(labelTable, &m_data[0], m_data.size(), m_displayGroup, m_browserTabIndex, &m_rgba[0]); } break; case DataValueType::CIFTI_PALETTE: { CaretAssert(m_ciftiMappableFile); PaletteColorMapping* pcm = m_ciftiMappableFile->getMapPaletteColorMapping(m_mapIndex); CaretAssert(pcm); const FastStatistics* stats = m_ciftiMappableFile->getMapFastStatistics(m_mapIndex); CaretAssert(stats); CaretAssert(m_data.size() == m_thresholdData.size()); PaletteColorMapping* threshPcm = ((m_thresholdPaletteColorMapping != NULL) ? m_thresholdPaletteColorMapping : pcm); NodeAndVoxelColoring::colorScalarsWithPalette(stats, pcm, &m_data[0], threshPcm, &m_thresholdData[0], m_data.size(), &m_rgba[0]); } break; case DataValueType::VOLUME_LABEL: { CaretAssert(m_volumeFile); const GiftiLabelTable* labelTable = m_volumeFile->getMapLabelTable(m_mapIndex); CaretAssert(labelTable); NodeAndVoxelColoring::colorIndicesWithLabelTableForDisplayGroupTab(labelTable, &m_data[0], m_data.size(), m_displayGroup, m_browserTabIndex, &m_rgba[0]); } break; case DataValueType::VOLUME_PALETTE: { CaretAssert(m_volumeFile); PaletteColorMapping* pcm = m_volumeFile->getMapPaletteColorMapping(m_mapIndex); CaretAssert(pcm); const FastStatistics* stats = m_volumeFile->getMapFastStatistics(m_mapIndex); CaretAssert(stats); CaretAssert(m_data.size() == m_thresholdData.size()); PaletteColorMapping* threshPcm = ((m_thresholdPaletteColorMapping != NULL) ? m_thresholdPaletteColorMapping : pcm); NodeAndVoxelColoring::colorScalarsWithPalette(stats, pcm, &m_data[0], threshPcm, &m_thresholdData[0], m_data.size(), &m_rgba[0]); } break; case DataValueType::VOLUME_RGB: case DataValueType::VOLUME_RGBA: { /* * Test RGB data to see if it ranges from [0, 1] or [0, 255]. * Assume if any component is greater than 1, then the data is [0, 255] */ bool range255Flag = std::any_of(m_data.begin(), m_data.end(), [](float f) { return f > 1.0f; }); CaretAssert(m_data.size() == m_rgba.size()); const int32_t numVoxels = static_cast(m_data.size() / 4); if (range255Flag) { for (int32_t i = 0; i < numVoxels; i++) { const int32_t i4 = i * 4; m_rgba[i4] = static_cast(m_data[i4]); m_rgba[i4+1] = static_cast(m_data[i4+1]); m_rgba[i4+2] = static_cast(m_data[i4+2]); if (m_dataValueType == DataValueType::VOLUME_RGB) { m_rgba[i4+3] = ((m_data[i4+3] > 0) ? 255 : 0); } } } else { for (int32_t i = 0; i < numVoxels; i++) { const int32_t i4 = i * 4; m_rgba[i4] = static_cast(m_data[i4] * 255.0); m_rgba[i4+1] = static_cast(m_data[i4+1] * 255.0); m_rgba[i4+2] = static_cast(m_data[i4+2] * 255.0); m_rgba[i4+3] = static_cast(m_data[i4+3] * 255.0); } } } break; } } /** * Add any outlines for labels or thresholded palette data. */ void BrainOpenGLVolumeObliqueSliceDrawing::ObliqueSlice::addOutlines() { LabelDrawingProperties* labelDrawingProperties = NULL; PaletteColorMapping* paletteColorMapping = NULL; switch (m_dataValueType) { case DataValueType::INVALID: break; case DataValueType::CIFTI_LABEL: CaretAssert(m_ciftiMappableFile); labelDrawingProperties = m_ciftiMappableFile->getLabelDrawingProperties(); break; case DataValueType::CIFTI_PALETTE: CaretAssert(m_ciftiMappableFile); paletteColorMapping = m_ciftiMappableFile->getMapPaletteColorMapping(m_mapIndex); break; case DataValueType::VOLUME_LABEL: CaretAssert(m_volumeFile); labelDrawingProperties = m_volumeFile->getLabelDrawingProperties(); break; case DataValueType::VOLUME_PALETTE: CaretAssert(m_volumeFile); paletteColorMapping = m_volumeFile->getMapPaletteColorMapping(m_mapIndex); break; case DataValueType::VOLUME_RGB: break; case DataValueType::VOLUME_RGBA: break; } if (labelDrawingProperties != NULL) { const LabelDrawingTypeEnum::Enum labelDrawingType = labelDrawingProperties->getDrawingType(); if (labelDrawingType != LabelDrawingTypeEnum::DRAW_FILLED) { const CaretColorEnum::Enum outlineColor = labelDrawingProperties->getOutlineColor(); NodeAndVoxelColoring::convertSliceColoringToOutlineMode(&m_rgba[0], labelDrawingType, outlineColor, m_numberOfColumns, m_numberOfRows); } } if (paletteColorMapping != NULL) { const PaletteThresholdOutlineDrawingModeEnum::Enum outlineMode = paletteColorMapping->getThresholdOutlineDrawingMode(); if (outlineMode != PaletteThresholdOutlineDrawingModeEnum::OFF) { const CaretColorEnum::Enum outlineColor = paletteColorMapping->getThresholdOutlineDrawingColor(); NodeAndVoxelColoring::convertPaletteSliceColoringToOutlineMode(&m_rgba[0], outlineMode, outlineColor, m_numberOfColumns, m_numberOfRows); } } } /** * Loads voxels data into the 'slice'. * * @param maskingType * Masking type to hide artifacts of interpolation * @param voxelEditingValue * Value for voxels when editing a volume * @param volumeEditingDrawAllVoxelsFlag * True if editing and all voxels should be drawn for selection. */ void BrainOpenGLVolumeObliqueSliceDrawing::ObliqueSlice::loadData(const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum maskingType, const float voxelEditingValue, const bool volumeEditingDrawAllVoxelsFlag) { m_validVoxelCount = 0; bool needCiftiMapDataFlag = false; switch (m_dataValueType) { case DataValueType::INVALID: break; case DataValueType::CIFTI_LABEL: case DataValueType::CIFTI_PALETTE: needCiftiMapDataFlag = true; break; case DataValueType::VOLUME_LABEL: case DataValueType::VOLUME_PALETTE: case DataValueType::VOLUME_RGB: case DataValueType::VOLUME_RGBA: break; } float voxelCenterOffset[3] = { ((m_leftToRightStepXYZ[0] / 2.0f) + (m_bottomToTopStepXYZ[0] / 2.0f)), ((m_leftToRightStepXYZ[1] / 2.0f) + (m_bottomToTopStepXYZ[1] / 2.0f)), ((m_leftToRightStepXYZ[2] / 2.0f) + (m_bottomToTopStepXYZ[2] / 2.0f)), }; std::vector ciftiFileMapData; std::vector thresholdCiftiFileMapData; if (needCiftiMapDataFlag) { /* * Cifti files are slow at getting individual voxels since they * provide no access to individual voxels. The reason is that * the data may be on a server (Dense data) and accessing a single * voxel would require requesting the entire map. So, for * each Cifti file, get the entire map. */ CaretAssert(m_ciftiMappableFile); m_ciftiMappableFile->getMapData(m_mapIndex, ciftiFileMapData); if (m_thresholdCiftiMappableFile != NULL) { m_thresholdCiftiMappableFile->getMapData(m_thresholdMapIndex, thresholdCiftiFileMapData); } } for (int32_t iRow = 0; iRow < m_numberOfRows; iRow++) { float rowStartXYZ[3] = { m_originXYZ[0] + (iRow * m_bottomToTopStepXYZ[0]), m_originXYZ[1] + (iRow * m_bottomToTopStepXYZ[1]), m_originXYZ[2] + (iRow * m_bottomToTopStepXYZ[2]) }; for (int32_t iCol = 0; iCol < m_numberOfColumns; iCol++) { const float voxelBottomLeft[3] = { rowStartXYZ[0] + (iCol * m_leftToRightStepXYZ[0]), rowStartXYZ[1] + (iCol * m_leftToRightStepXYZ[1]), rowStartXYZ[2] + (iCol * m_leftToRightStepXYZ[2]) }; const float voxelCenter[3] = { voxelBottomLeft[0] + voxelCenterOffset[0], voxelBottomLeft[1] + voxelCenterOffset[1], voxelBottomLeft[2] + voxelCenterOffset[2] }; float values[4] = { 0.0, 0.0, 0.0, 0.0 }; bool valueValidFlag = false; float thresholdValue = 0.0; bool thresholdValueValidFlag = false; switch (m_dataValueType) { case DataValueType::INVALID: CaretAssert(0); break; case DataValueType::CIFTI_LABEL: case DataValueType::CIFTI_PALETTE: { CaretAssert(m_ciftiMappableFile); const int64_t voxelOffset = m_ciftiMappableFile->getMapDataOffsetForVoxelAtCoordinate(voxelCenter, m_mapIndex); if (voxelOffset >= 0) { CaretAssertVectorIndex(ciftiFileMapData, voxelOffset); values[0] = ciftiFileMapData[voxelOffset]; valueValidFlag = true; } if (m_thresholdCiftiMappableFile != NULL) { const int64_t thresholdVoxelOffset = m_thresholdCiftiMappableFile->getMapDataOffsetForVoxelAtCoordinate(voxelCenter, m_thresholdMapIndex); if (thresholdVoxelOffset >= 0) { CaretAssertVectorIndex(thresholdCiftiFileMapData, thresholdVoxelOffset); thresholdValue = thresholdCiftiFileMapData[thresholdVoxelOffset]; thresholdValueValidFlag = true; } } } break; case DataValueType::VOLUME_LABEL: { CaretAssert(m_volumeFile); values[0] = m_volumeFile->getVoxelValue(voxelCenter, &valueValidFlag, m_mapIndex, 0); } break; case DataValueType::VOLUME_PALETTE: { CaretAssert(m_volumeFile); values[0] = m_volumeFile->interpolateValue(voxelCenter, VolumeFile::CUBIC, &valueValidFlag, m_mapIndex); if (valueValidFlag && (values[0] != 0.0f)) { /* * Apply masking to oblique voxels (WB-750). * In some instances, CUBIC interpolation may result in a voxel * receiving a very small value (0.000000000000000210882405) and * this will cause the slice drawing to look very unusual. Masking * is used to prevent this from occurring. * */ bool maskValidFlag = false; float maskValue = 0.0f; switch (maskingType) { case VolumeSliceInterpolationEdgeEffectsMaskingEnum::OFF: maskValidFlag = false; break; case VolumeSliceInterpolationEdgeEffectsMaskingEnum::LOOSE: maskValue = m_volumeFile->interpolateValue(voxelCenter, VolumeFile::TRILINEAR, &maskValidFlag, m_mapIndex); break; case VolumeSliceInterpolationEdgeEffectsMaskingEnum::TIGHT: maskValue = m_volumeFile->interpolateValue(voxelCenter, VolumeFile::ENCLOSING_VOXEL, &maskValidFlag, m_mapIndex); break; } if (maskValidFlag && (maskValue == 0.0f)) { values[0] = 0.0f; valueValidFlag = false; } } if (m_thresholdVolumeFile != NULL) { thresholdValue = m_thresholdVolumeFile->getVoxelValue(voxelCenter, &thresholdValueValidFlag, m_thresholdMapIndex, 0); } } break; case DataValueType::VOLUME_RGB: case DataValueType::VOLUME_RGBA: { values[0] = m_volumeFile->getVoxelValue(voxelCenter, &valueValidFlag, m_mapIndex, 0); if (valueValidFlag) { values[1] = m_volumeFile->getVoxelValue(voxelCenter, &valueValidFlag, m_mapIndex, 1); values[2] = m_volumeFile->getVoxelValue(voxelCenter, &valueValidFlag, m_mapIndex, 2); if (m_dataValueType == DataValueType::VOLUME_RGBA) { values[3] = m_volumeFile->getVoxelValue(voxelCenter, &valueValidFlag, m_mapIndex, 3); } else { values[3] = 1.0; } } } break; } if (m_thresholdMapIndex < 0) { thresholdValue = values[0]; } /* * Need to draw all voxels when editing */ if (volumeEditingDrawAllVoxelsFlag) { if (! valueValidFlag) { values[0] = voxelEditingValue; valueValidFlag = true; } } switch (m_dataValueType) { case DataValueType::INVALID: break; case DataValueType::CIFTI_LABEL: case DataValueType::CIFTI_PALETTE: case DataValueType::VOLUME_LABEL: case DataValueType::VOLUME_PALETTE: m_data.push_back(values[0]); m_thresholdData.push_back(thresholdValue); break; case DataValueType::VOLUME_RGB: case DataValueType::VOLUME_RGBA: m_data.push_back(values[0]); m_data.push_back(values[1]); m_data.push_back(values[2]); m_data.push_back(values[3]); break; } if (m_identificationModeFlag) { /* * When identifying, need an IJK triplet * for each voxel */ int64_t ijk[3] = { -1, -1, -1 }; if (valueValidFlag) { if (m_volumeFile != NULL) { m_volumeFile->enclosingVoxel(voxelCenter, ijk); if ( ! m_volumeFile->indexValid(ijk)) { ijk[0] = -1; ijk[1] = -1; ijk[2] = -1; valueValidFlag = false; } } else if (m_ciftiMappableFile != NULL) { int64_t i(-1), j(-1), k(-1); m_ciftiMappableFile->enclosingVoxel(voxelCenter[0], voxelCenter[1], voxelCenter[2], i, j, k); if (m_ciftiMappableFile->indexValid(i, j, k)) { ijk[0] = i; ijk[1] = j; ijk[2] = k; } else { valueValidFlag = false; } } } m_identificationIJK.insert(m_identificationIJK.end(), ijk, ijk + 3); } if (valueValidFlag) { m_validVoxelCount++; } } } CaretAssert((m_sliceNumberOfVoxels * m_voxelNumberOfComponents) == static_cast(m_data.size())); if (m_thresholdMapIndex >= 0) { CaretAssert(m_data.size() == m_thresholdData.size()); } if (m_identificationModeFlag) { CaretAssert((m_data.size() * 3) == m_identificationIJK.size()); } } /** * Draw the oblique slice with the graphics primitives. * * @param fixedPipelineDrawing * The fixed pipeline drawing. */ void BrainOpenGLVolumeObliqueSliceDrawing::ObliqueSlice::draw(BrainOpenGLFixedPipeline* fixedPipelineDrawing) { Brain* brain = fixedPipelineDrawing->m_brain; SelectionItemVoxel* selectionItemVoxel = brain->getSelectionManager()->getVoxelIdentification(); SelectionItemVoxelEditing* selectionItemVoxelEditing = brain->getSelectionManager()->getVoxelEditingIdentification(); const GraphicsPrimitive::PrimitiveType primitiveType = GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES; std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3fC4ub(primitiveType)); float rowXYZ[3] = { m_originXYZ[0], m_originXYZ[1], m_originXYZ[2] }; uint8_t sliceAlpha = 255; bool drawWithBlendingFlag(false); // if (m_bottomLayerFlag) { if (m_opacity < 1.0) { sliceAlpha = static_cast(m_opacity * 255.0); drawWithBlendingFlag = true; } // } std::vector selectionIJK; for (int32_t iRow = 0; iRow < m_numberOfRows; iRow++) { float voxelXYZ[3] = { rowXYZ[0], rowXYZ[1], rowXYZ[2] }; const int32_t rowRgbaOffset = (iRow * m_numberOfColumns * 4); for (int32_t iCol = 0; iCol < m_numberOfColumns; iCol++) { float nextXYZ[3] = { voxelXYZ[0] + m_leftToRightStepXYZ[0], voxelXYZ[1] + m_leftToRightStepXYZ[1], voxelXYZ[2] + m_leftToRightStepXYZ[2], }; const int32_t rgbaIndex = rowRgbaOffset + (iCol * 4); CaretAssertVectorIndex(m_rgba, rgbaIndex + 3); const uint8_t alpha = m_rgba[rgbaIndex +3]; if (alpha > 0) { const float upperLeftXYZ[3] = { voxelXYZ[0] + m_bottomToTopStepXYZ[0], voxelXYZ[1] + m_bottomToTopStepXYZ[1], voxelXYZ[2] + m_bottomToTopStepXYZ[2] }; const float upperRightXYZ[3] = { nextXYZ[0] + m_bottomToTopStepXYZ[0], nextXYZ[1] + m_bottomToTopStepXYZ[1], nextXYZ[2] + m_bottomToTopStepXYZ[2] }; uint8_t* rgba = &m_rgba[rgbaIndex]; if (drawWithBlendingFlag) { if ((rgba[0] > 0) || (rgba[1] > 0) || (rgba[2] > 0)) { rgba[3] = sliceAlpha; } } /* * Each voxel is drawn with two triangles because: * (1) Voxels may be sparse and triangles strips do not support 'restart' * until newer versions of OpenGL. * (2) Support for Quads is removed in newer versions of OpenGL. */ primitive->addVertex(voxelXYZ, rgba); primitive->addVertex(nextXYZ, rgba); primitive->addVertex(upperLeftXYZ, rgba); primitive->addVertex(upperLeftXYZ, rgba); primitive->addVertex(nextXYZ, rgba); primitive->addVertex(upperRightXYZ, rgba); if (m_identificationModeFlag) { /* * Each voxel is drawn with two triangles so need to put ID * in twice since so that number of selections equals number * of triangles */ const int32_t idIndex = ((iRow * m_numberOfColumns * 3) + (iCol * 3)); CaretAssertVectorIndex(m_identificationIJK, idIndex + 2); selectionIJK.push_back(m_identificationIJK[idIndex]); selectionIJK.push_back(m_identificationIJK[idIndex+1]); selectionIJK.push_back(m_identificationIJK[idIndex+2]); selectionIJK.push_back(m_identificationIJK[idIndex]); selectionIJK.push_back(m_identificationIJK[idIndex+1]); selectionIJK.push_back(m_identificationIJK[idIndex+2]); } } voxelXYZ[0] = nextXYZ[0]; voxelXYZ[1] = nextXYZ[1]; voxelXYZ[2] = nextXYZ[2]; } rowXYZ[0] += m_bottomToTopStepXYZ[0]; rowXYZ[1] += m_bottomToTopStepXYZ[1]; rowXYZ[2] += m_bottomToTopStepXYZ[2]; } if (primitive->isValid()) { if (m_identificationModeFlag) { int32_t selectedIndex = -1; float selectedDepth = -1.0; GraphicsEngineDataOpenGL::drawWithSelection(primitive.get(), fixedPipelineDrawing->mouseX, fixedPipelineDrawing->mouseY, selectedIndex, selectedDepth); if (selectedIndex >= 0) { const int32_t ijkIndex = selectedIndex * 3; CaretAssertVectorIndex(selectionIJK, ijkIndex + 2); m_selectionIJK[0] = selectionIJK[ijkIndex]; m_selectionIJK[1] = selectionIJK[ijkIndex+1]; m_selectionIJK[2] = selectionIJK[ijkIndex+2]; if ((m_selectionIJK[0] >= 0) && (m_selectionIJK[1] >= 0) && (m_selectionIJK[2])) { if (selectionItemVoxel->isEnabledForSelection()) { if (selectionItemVoxel->isOtherScreenDepthCloserToViewer(selectedDepth)) { selectionItemVoxel->setVoxelIdentification(brain, m_volumeInterface, m_selectionIJK, selectedDepth); float voxelCoordinates[3]; m_volumeInterface->indexToSpace(m_selectionIJK[0], m_selectionIJK[1], m_selectionIJK[2], voxelCoordinates[0], voxelCoordinates[1], voxelCoordinates[2]); fixedPipelineDrawing->setSelectedItemScreenXYZ(selectionItemVoxel, voxelCoordinates); CaretLogFinest("Selected Voxel (3D): " + AString::fromNumbers(m_selectionIJK, 3, ",")); } } if (selectionItemVoxelEditing->isEnabledForSelection()) { if (selectionItemVoxelEditing->getVolumeFileForEditing() == m_volumeFile) { if (selectionItemVoxelEditing->isOtherScreenDepthCloserToViewer(selectedDepth)) { selectionItemVoxelEditing->setVoxelIdentification(brain, m_volumeInterface, m_selectionIJK, selectedDepth); float floatDiffXYZ[3] = { m_leftToRightStepXYZ[0] + m_bottomToTopStepXYZ[0], m_leftToRightStepXYZ[1] + m_bottomToTopStepXYZ[1], m_leftToRightStepXYZ[2] + m_bottomToTopStepXYZ[2] }; selectionItemVoxelEditing->setVoxelDiffXYZ(floatDiffXYZ); float voxelCoordinates[3]; m_volumeInterface->indexToSpace(m_selectionIJK[0], m_selectionIJK[1], m_selectionIJK[2], voxelCoordinates[0], voxelCoordinates[1], voxelCoordinates[2]); fixedPipelineDrawing->setSelectedItemScreenXYZ(selectionItemVoxelEditing, voxelCoordinates); CaretLogFinest("Selected Voxel Editing (3D): Indices (" + AString::fromNumbers(m_selectionIJK, 3, ",") + ") Diff XYZ (" + AString::fromNumbers(floatDiffXYZ, 3, ",") + ")"); } } } } } } else { /* * Only allow layer blending when overall volume opacity is off (>= 1.0) */ //const DisplayPropertiesVolume* dpv = brain->getDisplayPropertiesVolume(); const bool allowBlendingFlag(true); //dpv->getOpacity() >= 1.0f); glPushAttrib(GL_COLOR_BUFFER_BIT); if (drawWithBlendingFlag && allowBlendingFlag) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } GraphicsEngineDataOpenGL::draw(primitive.get()); glPopAttrib(); } } } /** * @return True if the output slice indices are valid, else false. * * @param ijkOut * Output slice indices. */ bool BrainOpenGLVolumeObliqueSliceDrawing::ObliqueSlice::getSelectionIJK(int32_t ijkOut[3]) const { ijkOut[0] = m_selectionIJK[0]; ijkOut[1] = m_selectionIJK[1]; ijkOut[2] = m_selectionIJK[2]; return (m_selectionIJK[0] >= 0); } /** * @return True if the given slice spatially matches (voxel row/columns and coordinates). * * @param slice * Slice for comparison. */ bool BrainOpenGLVolumeObliqueSliceDrawing::ObliqueSlice::spatialMatch(const ObliqueSlice* slice) { CaretAssert(slice); const float diffMax = 0.001f; if ((m_numberOfRows == slice->m_numberOfRows) && (m_numberOfColumns == slice->m_numberOfColumns) && (MathFunctions::distanceSquared3D(m_originXYZ, slice->m_originXYZ) < diffMax) && (MathFunctions::distanceSquared3D(m_leftToRightStepXYZ, slice->m_leftToRightStepXYZ) < diffMax) && (MathFunctions::distanceSquared3D(m_bottomToTopStepXYZ, slice->m_bottomToTopStepXYZ) < diffMax)) { return true; } return false; } /** * Composite the given slices onto this slice * * @param slices * Slices that are composited. * @return * True if able to composite all slices, else false. */ bool BrainOpenGLVolumeObliqueSliceDrawing::ObliqueSlice::compositeSlicesRGBA(const std::vector& slices) { std::vector matchedSlices; for (auto s : slices) { if (s != this) { if (spatialMatch(s)) { if (m_rgba.size() == s->m_rgba.size()) { matchedSlices.push_back(s); } else { return false; } } } } if (matchedSlices.empty()) { return false; } const int32_t numSlices = static_cast(matchedSlices.size()); const int32_t rgbaLength = static_cast(m_rgba.size() / 4); for (int32_t i = 0; i < rgbaLength; i++) { const int32_t i4 = i * 4; for (int32_t iSlice = 0; iSlice < numSlices; iSlice++) { CaretAssertVectorIndex(matchedSlices, iSlice); const uint8_t* rgbaTop = &matchedSlices[iSlice]->m_rgba[i4]; uint8_t alphaTop = rgbaTop[3]; if (matchedSlices[iSlice]->m_opacity < 1.0f) { float sliceAlphaFloat = ((static_cast(alphaTop) / 255.0f) * matchedSlices[iSlice]->m_opacity); if (sliceAlphaFloat >= 1.0f) { alphaTop = 255; } else if (sliceAlphaFloat <= 0.0f) { alphaTop = 0; } else { alphaTop = static_cast(sliceAlphaFloat * 255); } } if (alphaTop > 0) { uint8_t* rgbaBottom = &m_rgba[i4]; if ((alphaTop == 255) || (rgbaBottom[3] == 0)) { rgbaBottom[0] = rgbaTop[0]; rgbaBottom[1] = rgbaTop[1]; rgbaBottom[2] = rgbaTop[2]; rgbaBottom[3] = 255; } else if (alphaTop > 0) { const float alpha = static_cast(alphaTop) / 255.0f; const float oneMinusAlpha = 1.0f - alpha; for (int32_t m = 0; m < 3; m++) { const int32_t top = static_cast(static_cast(rgbaTop[m]) * alpha); const int32_t bottom = static_cast(static_cast(rgbaBottom[m]) * oneMinusAlpha); int32_t blended = (top + bottom); if (blended > 255) blended = 255; else if (blended < 0) blended = 0; rgbaBottom[m] = static_cast(blended); } rgbaBottom[3] = 255; } } } } return true; } connectome-workbench-1.4.2/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.h000066400000000000000000000345701360521144700267440ustar00rootroot00000000000000#ifndef __BRAIN_OPEN_GL_VOLUME_OBLIQUE_SLICE_DRAWING_H__ #define __BRAIN_OPEN_GL_VOLUME_OBLIQUE_SLICE_DRAWING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "BrainOpenGLFixedPipeline.h" #include "BrainOpenGLVolumeSliceDrawing.h" #include "CaretObject.h" #include "DisplayGroupEnum.h" #include "ModelTypeEnum.h" #include "VolumeSliceInterpolationEdgeEffectsMaskingEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "VolumeSliceDrawingTypeEnum.h" #include "VolumeSliceViewAllPlanesLayoutEnum.h" #include "VolumeSliceViewPlaneEnum.h" namespace caret { class Brain; class BrowserTabContent; class CiftiMappableDataFile; class Matrix4x4; class ModelVolume; class ModelWholeBrain; class Plane; class VolumeMappableInterface; class BrainOpenGLVolumeObliqueSliceDrawing : public CaretObject { public: BrainOpenGLVolumeObliqueSliceDrawing(); virtual ~BrainOpenGLVolumeObliqueSliceDrawing(); void draw(BrainOpenGLFixedPipeline* fixedPipelineDrawing, BrowserTabContent* browserTabContent, std::vector& volumeDrawInfo, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum obliqueSliceMaskingType, const int32_t viewport[4]); // ADD_NEW_METHODS_HERE private: class ObliqueSlice { public: enum class DataValueType { INVALID, CIFTI_LABEL, CIFTI_PALETTE, VOLUME_LABEL, VOLUME_PALETTE, VOLUME_RGB, VOLUME_RGBA }; ObliqueSlice(BrainOpenGLFixedPipeline* fixedPipelineDrawing, VolumeMappableInterface* volumeInterface, const float opacity, const int32_t mapIndex, const int32_t numberOfRows, const int32_t numberOfColumns, const int32_t browserTabIndex, const DisplayPropertiesLabels* displayPropertiesLabels, const DisplayGroupEnum::Enum displayGroup, const float originXYZ[3], const float leftToRightStepXYZ[3], const float bottomToTopStepXYZ[3], const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum maskingType, const float voxelEditingValue, const bool volumeEditingDrawAllVoxelsFlag, const bool identificationModeFlag, const bool bottomLayerFlag); void assignRgba(const bool volumeEditingDrawAllVoxelsFlag); void addOutlines(); void loadData(const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum maskingType, const float voxelEditingValue, const bool volumeEditingDrawAllVoxelsFlag); bool setThresholdFileAndMap(); bool getSelectionIJK(int32_t ijkOut[3]) const; void draw(BrainOpenGLFixedPipeline* fixedPipelineDrawing); bool spatialMatch(const ObliqueSlice* slice); bool compositeSlicesRGBA(const std::vector& slices); VolumeMappableInterface* m_volumeInterface; const float m_opacity; const CaretMappableDataFile* m_mapFile = NULL; const int32_t m_mapIndex; const int32_t m_numberOfRows; const int32_t m_numberOfColumns; const int32_t m_browserTabIndex; const DisplayPropertiesLabels* m_displayPropertiesLabels; const DisplayGroupEnum::Enum m_displayGroup; const int32_t m_identificationX; const int32_t m_identificationY; const bool m_identificationModeFlag; const bool m_bottomLayerFlag; CiftiMappableDataFile* m_ciftiMappableFile = NULL; VolumeFile* m_volumeFile = NULL; uint8_t m_opacityByte = 255; CiftiMappableDataFile* m_thresholdCiftiMappableFile = NULL; VolumeFile* m_thresholdVolumeFile = NULL; PaletteColorMapping* m_thresholdPaletteColorMapping = NULL; int32_t m_thresholdMapIndex = -1; float m_originXYZ[3]; float m_leftToRightStepXYZ[3]; float m_bottomToTopStepXYZ[3]; DataValueType m_dataValueType = DataValueType::INVALID; std::vector m_data; std::vector m_thresholdData; std::vector m_rgba; std::vector m_identificationIJK; int32_t m_validVoxelCount = 0; int32_t m_sliceNumberOfVoxels = 0; int32_t m_voxelNumberOfComponents = 1; std::unique_ptr m_identificationHelper; int64_t m_selectionIJK[3]; }; BrainOpenGLVolumeObliqueSliceDrawing(const BrainOpenGLVolumeObliqueSliceDrawing&); BrainOpenGLVolumeObliqueSliceDrawing& operator=(const BrainOpenGLVolumeObliqueSliceDrawing&); void drawVolumeSlicesForAllStructuresView(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const int32_t viewport[4]); void drawVolumeSliceViewPlane(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, const int32_t viewport[4]); void drawVolumeSliceViewType(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const int32_t viewport[4]); void drawVolumeSliceViewTypeMontage(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const int32_t viewport[4]); void drawVolumeSliceViewProjection(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], const int32_t viewport[4]); void drawObliqueSlice(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, Matrix4x4& transformationMatrix, const Plane& plane); void drawObliqueSliceWithOutlines(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, Matrix4x4& transformationMatrix); void createSlicePlaneEquation(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], Plane& planeOut); void drawAxesCrosshairsOblique(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], const bool drawCrosshairsFlag, const bool drawCrosshairLabelsFlag); void setVolumeSliceViewingAndModelingTransformations(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const Plane& plane, const float sliceCoordinates[3]); void getAxesColor(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, float rgbaOut[4]) const; void drawLayers(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const Plane& slicePlane, const float sliceCoordinates[3]); void drawVolumeSliceFoci(const Plane& plane); void drawAxesCrosshairs(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3]); bool getMinMaxVoxelSpacing(const VolumeMappableInterface* volume, float& minSpacingOut, float& maxSpacingOut) const; void drawSquare(const float size); void drawOrientationAxes(const int viewport[4]); void setOrthographicProjection(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const int viewport[4]); bool getVoxelCoordinateBoundsAndSpacing(float boundsOut[6], float spacingOut[3]); void createObliqueTransformationMatrix(const float sliceCoordinates[3], Matrix4x4& obliqueTransformationMatrixOut); void addVoxelToIdentification(const int32_t volumeIndex, const int32_t mapIndex, const int32_t voxelI, const int32_t voxelJ, const int32_t voxelK, const float voxelDiffXYZ[3], uint8_t rgbaForColorIdentificationOut[4]); bool getVolumeDrawingViewDependentCulling(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float selectedSliceCoordinate, const VolumeMappableInterface* volumeFile, int64_t culledFirstVoxelIJKOut[3], int64_t culledLastVoxelIJKOut[3], float voxelDeltaXYZOut[3]); void processIdentification(); void resetIdentification(); ModelVolume* m_modelVolume; ModelWholeBrain* m_modelWholeBrain; ModelTypeEnum::Enum m_modelType; VolumeMappableInterface* m_underlayVolume; Brain* m_brain; std::vector > m_ciftiMappableFileData; BrainOpenGLFixedPipeline* m_fixedPipelineDrawing; std::vector m_volumeDrawInfo; BrowserTabContent* m_browserTabContent; DisplayGroupEnum::Enum m_displayGroup; int32_t m_tabIndex; double m_lookAtCenter[3]; double m_viewingMatrix[16]; double m_orthographicBounds[6]; VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum m_obliqueSliceMaskingType = VolumeSliceInterpolationEdgeEffectsMaskingEnum::OFF; std::vector m_identificationIndices; bool m_identificationModeFlag; static const int32_t IDENTIFICATION_INDICES_PER_VOXEL; // ADD_NEW_MEMBERS_HERE }; #ifdef __BRAIN_OPEN_GL_VOLUME_OBLIQUE_SLICE_DRAWING_DECLARE__ const int32_t BrainOpenGLVolumeObliqueSliceDrawing::IDENTIFICATION_INDICES_PER_VOXEL = 8; #endif // __BRAIN_OPEN_GL_VOLUME_OBLIQUE_SLICE_DRAWING_DECLARE__ } // namespace #endif //__BRAIN_OPEN_GL_VOLUME_OBLIQUE_SLICE_DRAWING_H__ connectome-workbench-1.4.2/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx000066400000000000000000007310111360521144700257700ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __BRAIN_OPEN_GL_VOLUME_SLICE_DRAWING_DECLARE__ #include "BrainOpenGLVolumeSliceDrawing.h" #undef __BRAIN_OPEN_GL_VOLUME_SLICE_DRAWING_DECLARE__ #include "AnnotationCoordinate.h" #include "AnnotationPercentSizeText.h" #include "AnnotationPointSizeText.h" #include "BoundingBox.h" #include "Brain.h" #include "BrainOpenGLAnnotationDrawingFixedPipeline.h" #include "BrainOpenGLPrimitiveDrawing.h" #include "BrainOpenGLViewportContent.h" #include "BrainordinateRegionOfInterest.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretOpenGLInclude.h" #include "CaretPreferenceDataValue.h" #include "CaretPreferences.h" #include "CiftiMappableDataFile.h" #include "DeveloperFlagsEnum.h" #include "DisplayPropertiesFoci.h" #include "DisplayPropertiesLabels.h" #include "DisplayPropertiesVolume.h" #include "ElapsedTimer.h" #include "FociFile.h" #include "Focus.h" #include "GapsAndMargins.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "GraphicsEngineDataOpenGL.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GraphicsUtilitiesOpenGL.h" #include "GroupAndNameHierarchyModel.h" #include "IdentificationManager.h" #include "IdentificationWithColor.h" #include "IdentifiedItemVoxel.h" #include "LabelDrawingProperties.h" #include "MathFunctions.h" #include "Matrix4x4.h" #include "ModelVolume.h" #include "ModelWholeBrain.h" #include "NodeAndVoxelColoring.h" #include "SelectionItemFocusVolume.h" #include "SelectionItemVoxel.h" #include "SelectionItemVoxelEditing.h" #include "SelectionItemVoxelIdentificationSymbol.h" #include "SelectionManager.h" #include "SessionManager.h" #include "SpacerTabIndex.h" #include "SurfacePlaneIntersectionToContour.h" #include "Surface.h" #include "VolumeFile.h" #include "VolumeSurfaceOutlineColorOrTabModel.h" #include "VolumeSurfaceOutlineModel.h" #include "VolumeSurfaceOutlineSetModel.h" using namespace caret; static const bool debugFlag = false; /** * \class caret::BrainOpenGLVolumeSliceDrawing * \brief Draws volume slices using OpenGL * \ingroup Brain */ /** * Constructor. */ BrainOpenGLVolumeSliceDrawing::BrainOpenGLVolumeSliceDrawing() : CaretObject() { } /** * Destructor. */ BrainOpenGLVolumeSliceDrawing::~BrainOpenGLVolumeSliceDrawing() { } /** * Draw Volume Slices or slices for ALL Stuctures View. * * @param fixedPipelineDrawing * The OpenGL drawing. * @param browserTabContent * Content of browser tab that is to be drawn. * @param volumeDrawInfo * Info on each volume layers for drawing. * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param viewport * The viewport (region of graphics area) for drawing slices. */ void BrainOpenGLVolumeSliceDrawing::draw(BrainOpenGLFixedPipeline* fixedPipelineDrawing, BrowserTabContent* browserTabContent, std::vector& volumeDrawInfo, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const int32_t viewport[4]) { if (volumeDrawInfo.empty()) { return; } CaretAssert(sliceProjectionType == VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL); CaretAssert(fixedPipelineDrawing); CaretAssert(browserTabContent); m_browserTabContent = browserTabContent; m_fixedPipelineDrawing = fixedPipelineDrawing; /* * No lighting for drawing slices */ m_fixedPipelineDrawing->disableLighting(); /* * Initialize class members which help reduce the number of * parameters that are passed to methods. */ m_brain = NULL; m_modelVolume = NULL; m_modelWholeBrain = NULL; m_modelType = ModelTypeEnum::MODEL_TYPE_INVALID; if (m_browserTabContent->getDisplayedVolumeModel() != NULL) { m_modelVolume = m_browserTabContent->getDisplayedVolumeModel(); m_brain = m_modelVolume->getBrain(); m_modelType = m_modelVolume->getModelType(); } else if (m_browserTabContent->getDisplayedWholeBrainModel() != NULL) { m_modelWholeBrain = m_browserTabContent->getDisplayedWholeBrainModel(); m_brain = m_modelWholeBrain->getBrain(); m_modelType = m_modelWholeBrain->getModelType(); } else { CaretAssertMessage(0, "Invalid model for volume slice drawing."); } CaretAssert(m_brain); CaretAssert(m_modelType != ModelTypeEnum::MODEL_TYPE_INVALID); m_volumeDrawInfo = volumeDrawInfo; if (m_volumeDrawInfo.empty()) { return; } m_underlayVolume = m_volumeDrawInfo[0].volumeFile; const DisplayPropertiesLabels* dsl = m_brain->getDisplayPropertiesLabels(); m_displayGroup = dsl->getDisplayGroupForTab(m_fixedPipelineDrawing->windowTabIndex); m_tabIndex = m_browserTabContent->getTabNumber(); /* * Cifti files are slow at getting individual voxels since they * provide no access to individual voxels. The reason is that * the data may be on a server (Dense data) and accessing a single * voxel would require requesting the entire map. So, for * each Cifti file, get the enter map. This also, eliminate multiple * requests for the same map when drawing an ALL view. */ const int32_t numVolumes = static_cast(m_volumeDrawInfo.size()); for (int32_t i = 0; i < numVolumes; i++) { std::vector ciftiMapData; m_ciftiMappableFileData.push_back(ciftiMapData); const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(m_volumeDrawInfo[i].volumeFile); if (ciftiMapFile != NULL) { ciftiMapFile->getMapData(m_volumeDrawInfo[i].mapIndex, m_ciftiMappableFileData[i]); } } /** END SETUP OF MEMBERS IN PARENT CLASS BrainOpenGLVolumeSliceDrawing */ if (browserTabContent->getDisplayedVolumeModel() != NULL) { drawVolumeSliceViewPlane(sliceDrawingType, sliceProjectionType, browserTabContent->getSliceViewPlane(), browserTabContent->getSlicePlanesAllViewLayout(), viewport); } else if (browserTabContent->getDisplayedWholeBrainModel() != NULL) { drawVolumeSlicesForAllStructuresView(sliceProjectionType, viewport); } } /** * Draw volume view slices for the given view plane. * * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * The plane for slice drawing. * @param allPlanesLayout * The layout in ALL slices view. * @param viewport * The viewport (region of graphics area) for drawing slices. */ void BrainOpenGLVolumeSliceDrawing::drawVolumeSliceViewPlane(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, const int32_t viewport[4]) { switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: { int32_t paraVP[4] = { 0, 0, 0, 0 }; int32_t coronalVP[4] = { 0, 0, 0, 0 }; int32_t axialVP[4] = { 0, 0, 0, 0 }; BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, VolumeSliceViewPlaneEnum::PARASAGITTAL, allPlanesLayout, paraVP); BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, VolumeSliceViewPlaneEnum::CORONAL, allPlanesLayout, coronalVP); BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, VolumeSliceViewPlaneEnum::AXIAL, allPlanesLayout, axialVP); /* * Draw parasagittal slice */ glPushMatrix(); drawVolumeSliceViewType(AllSliceViewMode::ALL_YES, sliceDrawingType, sliceProjectionType, VolumeSliceViewPlaneEnum::PARASAGITTAL, paraVP); glPopMatrix(); /* * Draw coronal slice */ glPushMatrix(); drawVolumeSliceViewType(AllSliceViewMode::ALL_YES, sliceDrawingType, sliceProjectionType, VolumeSliceViewPlaneEnum::CORONAL, coronalVP); glPopMatrix(); /* * Draw axial slice */ glPushMatrix(); drawVolumeSliceViewType(AllSliceViewMode::ALL_YES, sliceDrawingType, sliceProjectionType, VolumeSliceViewPlaneEnum::AXIAL, axialVP); glPopMatrix(); if (allPlanesLayout == VolumeSliceViewAllPlanesLayoutEnum::GRID_LAYOUT) { /* * 4th quadrant is used for axis showing orientation */ int32_t allVP[4] = { 0, 0, 0, 0 }; BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, VolumeSliceViewPlaneEnum::ALL, allPlanesLayout, allVP); switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: CaretAssert(0); break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: break; } } } break; case VolumeSliceViewPlaneEnum::AXIAL: case VolumeSliceViewPlaneEnum::CORONAL: case VolumeSliceViewPlaneEnum::PARASAGITTAL: drawVolumeSliceViewType(AllSliceViewMode::ALL_NO, sliceDrawingType, sliceProjectionType, sliceViewPlane, viewport); break; } } /** * Draw slices for the all structures view. * * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param viewport * The viewport. */ void BrainOpenGLVolumeSliceDrawing::drawVolumeSlicesForAllStructuresView(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const int32_t viewport[4]) { m_orthographicBounds[0] = m_fixedPipelineDrawing->orthographicLeft; m_orthographicBounds[1] = m_fixedPipelineDrawing->orthographicRight; m_orthographicBounds[2] = m_fixedPipelineDrawing->orthographicBottom; m_orthographicBounds[3] = m_fixedPipelineDrawing->orthographicTop; m_orthographicBounds[4] = m_fixedPipelineDrawing->orthographicNear; m_orthographicBounds[5] = m_fixedPipelineDrawing->orthographicFar; /* * Enlarge the region */ { const float left = m_fixedPipelineDrawing->orthographicLeft; const float right = m_fixedPipelineDrawing->orthographicRight; const float bottom = m_fixedPipelineDrawing->orthographicBottom; const float top = m_fixedPipelineDrawing->orthographicTop; const float scale = 2.0; const float centerX = (left + right) / 2.0; const float dx = (right - left) / 2.0; const float newLeft = centerX - (dx * scale); const float newRight = centerX + (dx * scale); const float centerY = (bottom + top) / 2.0; const float dy = (top - bottom) / 2.0; const float newBottom = centerY - (dy * scale); const float newTop = centerY + (dy * scale); m_orthographicBounds[0] = newLeft; m_orthographicBounds[1] = newRight; m_orthographicBounds[2] = newBottom; m_orthographicBounds[3] = newTop; } const float sliceCoordinates[3] = { m_browserTabContent->getSliceCoordinateParasagittal(), m_browserTabContent->getSliceCoordinateCoronal(), m_browserTabContent->getSliceCoordinateAxial() }; if (m_browserTabContent->isSliceAxialEnabled()) { glPushMatrix(); drawVolumeSliceViewProjection(AllSliceViewMode::ALL_NO, VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE, sliceProjectionType, VolumeSliceViewPlaneEnum::AXIAL, sliceCoordinates, viewport); glPopMatrix(); } if (m_browserTabContent->isSliceCoronalEnabled()) { glPushMatrix(); drawVolumeSliceViewProjection(AllSliceViewMode::ALL_NO, VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE, sliceProjectionType, VolumeSliceViewPlaneEnum::CORONAL, sliceCoordinates, viewport); glPopMatrix(); } if (m_browserTabContent->isSliceParasagittalEnabled()) { glPushMatrix(); drawVolumeSliceViewProjection(AllSliceViewMode::ALL_NO, VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE, sliceProjectionType, VolumeSliceViewPlaneEnum::PARASAGITTAL, sliceCoordinates, viewport); glPopMatrix(); } } /** * Draw single or montage volume view slices. * * @param allSliceViewMode * Indicates drawing of ALL slices volume view (axial, coronal, parasagittal in one view) * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * The plane for slice drawing. * @param viewport * The viewport (region of graphics area) for drawing slices. */ void BrainOpenGLVolumeSliceDrawing::drawVolumeSliceViewType(const AllSliceViewMode allSliceViewMode, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const int32_t viewport[4]) { switch (sliceDrawingType) { case VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_MONTAGE: drawVolumeSliceViewTypeMontage(allSliceViewMode, sliceDrawingType, sliceProjectionType, sliceViewPlane, viewport); break; case VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE: { const float sliceCoordinates[3] = { m_browserTabContent->getSliceCoordinateParasagittal(), m_browserTabContent->getSliceCoordinateCoronal(), m_browserTabContent->getSliceCoordinateAxial() }; drawVolumeSliceViewProjection(allSliceViewMode, sliceDrawingType, sliceProjectionType, sliceViewPlane, sliceCoordinates, viewport); } break; } } /** * Draw montage slices. * * @param allSliceViewMode * Indicates drawing of ALL slices volume view (axial, coronal, parasagittal in one view) * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * The plane for slice drawing. * @param viewport * The viewport (region of graphics area) for drawing slices. */ void BrainOpenGLVolumeSliceDrawing::drawVolumeSliceViewTypeMontage(const AllSliceViewMode allSliceViewMode, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const int32_t viewport[4]) { const int32_t numRows = m_browserTabContent->getMontageNumberOfRows(); CaretAssert(numRows > 0); const int32_t numCols = m_browserTabContent->getMontageNumberOfColumns(); CaretAssert(numCols > 0); const int32_t montageCoordPrecision = m_browserTabContent->getVolumeMontageCoordinatePrecision(); const GapsAndMargins* gapsAndMargins = m_brain->getGapsAndMargins(); const int32_t windowIndex = m_fixedPipelineDrawing->m_windowIndex; int32_t vpSizeY = 0; int32_t verticalMargin = 0; BrainOpenGLFixedPipeline::createSubViewportSizeAndGaps(viewport[3], gapsAndMargins->getVolumeMontageVerticalGapForWindow(windowIndex), -1, numRows, vpSizeY, verticalMargin); int32_t vpSizeX = 0; int32_t horizontalMargin = 0; BrainOpenGLFixedPipeline::createSubViewportSizeAndGaps(viewport[2], gapsAndMargins->getVolumeMontageHorizontalGapForWindow(windowIndex), -1, numCols, vpSizeX, horizontalMargin); /* * Voxel sizes for underlay volume */ float originX, originY, originZ; float x1, y1, z1; m_underlayVolume->indexToSpace(0, 0, 0, originX, originY, originZ); m_underlayVolume->indexToSpace(1, 1, 1, x1, y1, z1); float sliceThickness = 0.0; float sliceOrigin = 0.0; AString axisLetter = ""; float sliceCoordinates[3] = { m_browserTabContent->getSliceCoordinateParasagittal(), m_browserTabContent->getSliceCoordinateCoronal(), m_browserTabContent->getSliceCoordinateAxial() }; int32_t sliceIndex = -1; int32_t maximumSliceIndex = -1; int64_t dimI, dimJ, dimK, numMaps, numComponents; m_underlayVolume->getDimensions(dimI, dimJ, dimK, numMaps, numComponents); const int32_t sliceStep = m_browserTabContent->getMontageSliceSpacing(); switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: sliceIndex = -1; break; case VolumeSliceViewPlaneEnum::AXIAL: sliceIndex = m_browserTabContent->getSliceIndexAxial(m_underlayVolume); maximumSliceIndex = dimK; sliceThickness = z1 - originZ; sliceOrigin = originZ; axisLetter = "Z"; break; case VolumeSliceViewPlaneEnum::CORONAL: sliceIndex = m_browserTabContent->getSliceIndexCoronal(m_underlayVolume); maximumSliceIndex = dimJ; sliceThickness = y1 - originY; sliceOrigin = originY; axisLetter = "Y"; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: sliceIndex = m_browserTabContent->getSliceIndexParasagittal(m_underlayVolume); maximumSliceIndex = dimI; sliceThickness = x1 - originX; sliceOrigin = originX; axisLetter = "X"; break; } /* * Foreground color for slice coordinate text */ const CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); uint8_t foregroundRGBA[4]; prefs->getBackgroundAndForegroundColors()->getColorForegroundVolumeView(foregroundRGBA); foregroundRGBA[3] = 255; const bool showCoordinates = m_browserTabContent->isVolumeMontageAxesCoordinatesDisplayed(); uint8_t backgroundRGBA[4]; prefs->getBackgroundAndForegroundColors()->getColorBackgroundVolumeView(backgroundRGBA); backgroundRGBA[3] = 255; /* * Determine a slice offset to selected slices is in * the center of the montage */ const int32_t numSlicesViewed = (numCols * numRows); const int32_t sliceOffset = ((numSlicesViewed / 2) * sliceStep); sliceIndex += sliceOffset; /* * Find first valid slice for montage */ while (sliceIndex >= 0) { if (sliceIndex < maximumSliceIndex) { break; } sliceIndex -= sliceStep; } if (sliceIndex >= 0) { for (int32_t i = 0; i < numRows; i++) { for (int32_t j = 0; j < numCols; j++) { if ((sliceIndex >= 0) && (sliceIndex < maximumSliceIndex)) { const int32_t vpX = (j * (vpSizeX + horizontalMargin)); const int32_t vpY = ((numRows - i - 1) * (vpSizeY + verticalMargin)); int32_t vp[4] = { viewport[0] + vpX, viewport[1] + vpY, vpSizeX, vpSizeY }; if ((vp[2] <= 0) || (vp[3] <= 0)) { continue; } const float sliceCoord = (sliceOrigin + sliceThickness * sliceIndex); switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: break; case VolumeSliceViewPlaneEnum::AXIAL: sliceCoordinates[2] = sliceCoord; break; case VolumeSliceViewPlaneEnum::CORONAL: sliceCoordinates[1] = sliceCoord; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: sliceCoordinates[0] = sliceCoord; break; } drawVolumeSliceViewProjection(allSliceViewMode, sliceDrawingType, sliceProjectionType, sliceViewPlane, sliceCoordinates, vp); if (showCoordinates) { const AString coordText = (axisLetter + "=" + AString::number(sliceCoord, 'f', montageCoordPrecision)); AnnotationPercentSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); annotationText.setFontPercentViewportSize(10.0f); annotationText.setTextColor(CaretColorEnum::CUSTOM); annotationText.setCustomTextColor(foregroundRGBA); annotationText.setBackgroundColor(CaretColorEnum::CUSTOM); annotationText.setCustomBackgroundColor(backgroundRGBA); annotationText.setText(coordText); m_fixedPipelineDrawing->drawTextAtViewportCoords((vpSizeX - 5), 5, annotationText); } } sliceIndex -= sliceStep; } } } /* * Draw the axes labels for the montage view */ glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); if (m_browserTabContent->isVolumeAxesCrosshairLabelsDisplayed()) { drawAxesCrosshairsOrtho(sliceViewPlane, sliceCoordinates, false, true); } } /** * Draw a slice for either projection mode (oblique, orthogonal) * * @param allSliceViewMode * Indicates drawing of ALL slices volume view (axial, coronal, parasagittal in one view) * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * The plane for slice drawing. * @param sliceCoordinates * Coordinates of the selected slice. * @param viewport * The viewport (region of graphics area) for drawing slices. */ void BrainOpenGLVolumeSliceDrawing::drawVolumeSliceViewProjection(const AllSliceViewMode allSliceViewMode, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], const int32_t viewport[4]) { bool twoDimSliceViewFlag = false; if (m_modelVolume != NULL) { twoDimSliceViewFlag = true; } else if (m_modelWholeBrain != NULL) { /* nothing */ } else { CaretAssertMessage(0, "Invalid model type."); } if (twoDimSliceViewFlag) { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); /* * Set the orthographic projection to fit the slice axis */ setOrthographicProjection(allSliceViewMode, sliceViewPlane, viewport); } /* * Create the plane equation for the slice */ Plane slicePlane; createSlicePlaneEquation(sliceProjectionType, sliceViewPlane, sliceCoordinates, slicePlane); CaretAssert(slicePlane.isValidPlane()); if (slicePlane.isValidPlane() == false) { return; } if (twoDimSliceViewFlag) { /* * Set the viewing transformation (camera position) */ setVolumeSliceViewingAndModelingTransformations(sliceProjectionType, sliceViewPlane, slicePlane); } SelectionItemVoxel* voxelID = m_brain->getSelectionManager()->getVoxelIdentification(); SelectionItemVoxelEditing* voxelEditingID = m_brain->getSelectionManager()->getVoxelEditingIdentification(); m_fixedPipelineDrawing->applyClippingPlanes(BrainOpenGLFixedPipeline::CLIPPING_DATA_TYPE_VOLUME, StructureEnum::ALL); /* * Check for a 'selection' type mode */ bool drawVolumeSlicesFlag = true; m_identificationModeFlag = false; switch (m_fixedPipelineDrawing->mode) { case BrainOpenGLFixedPipeline::MODE_DRAWING: break; case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: if (voxelID->isEnabledForSelection() || voxelEditingID->isEnabledForSelection()) { m_identificationModeFlag = true; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } else { /* * Don't return. Allow other items (such as annotations) to be drawn. */ drawVolumeSlicesFlag = false; } break; case BrainOpenGLFixedPipeline::MODE_PROJECTION: return; break; } resetIdentification(); GLboolean cullFaceOn = glIsEnabled(GL_CULL_FACE); if (drawVolumeSlicesFlag) { /* * Disable culling so that both sides of the triangles/quads are drawn. */ glDisable(GL_CULL_FACE); const bool cullingSliceViewFlag = true; const bool nonCulledLpiSliceViewFlag = false; // culling only works in a view looking along an axis (any rotation and slices disappear) switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: if (m_modelVolume != NULL) { if (cullingSliceViewFlag) { drawOrthogonalSliceWithCulling(sliceViewPlane, sliceCoordinates, slicePlane); } else { if (nonCulledLpiSliceViewFlag) { drawOrthogonalSlice_LPI_ONLY(sliceViewPlane, sliceCoordinates, slicePlane); } else { drawOrthogonalSlice(sliceViewPlane, sliceCoordinates, slicePlane); } } } else if (m_modelWholeBrain != NULL) { if (nonCulledLpiSliceViewFlag) { drawOrthogonalSlice_LPI_ONLY(sliceViewPlane, sliceCoordinates, slicePlane); } else { const bool allOrientationsFlag = true; if (allOrientationsFlag) { drawOrthogonalSliceAllView(sliceViewPlane, sliceCoordinates, slicePlane); } else { drawOrthogonalSlice(sliceViewPlane, sliceCoordinates, slicePlane); } } } break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: CaretAssert(0); break; } /* * Process selection */ if (m_identificationModeFlag) { processIdentification(); } } drawIdentificationSymbols(slicePlane); if ( ! m_identificationModeFlag) { if (slicePlane.isValidPlane()) { drawLayers(sliceDrawingType, sliceProjectionType, sliceViewPlane, slicePlane, sliceCoordinates); } } /* * Draw model space annotaitons on the volume slice */ float sliceThickness = 1.0; if ( ! m_volumeDrawInfo.empty()) { if (m_volumeDrawInfo[0].volumeFile != NULL) { float spaceX = 0.0, spaceY = 0.0, spaceZ = 0.0; m_volumeDrawInfo[0].volumeFile->getVoxelSpacing(spaceX, spaceY, spaceZ); switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: sliceThickness = spaceZ; break; case VolumeSliceViewPlaneEnum::CORONAL: sliceThickness = spaceY; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: sliceThickness = spaceX; break; } } } const bool annotationModeFlag = (m_fixedPipelineDrawing->m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, m_fixedPipelineDrawing->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_fixedPipelineDrawing->m_windowIndex, m_fixedPipelineDrawing->windowTabIndex, SpacerTabIndex(), BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, annotationModeFlag); m_fixedPipelineDrawing->m_annotationDrawing->drawModelSpaceAnnotationsOnVolumeSlice(&inputs, slicePlane, sliceThickness); m_fixedPipelineDrawing->disableClippingPlanes(); if (cullFaceOn) { glEnable(GL_CULL_FACE); } } /** * Draw an orthogonal slice. * * NOTE: THIS METHOD ONLY DRAWS CORRECTLY IF THE VOLUME IS IN AN LPI OR RPI ORIENTATION. * * @param sliceViewPlane * The plane for slice drawing. * @param sliceCoordinates * Coordinates of the selected slice. * @param plane * Plane equation for the selected slice. */ void BrainOpenGLVolumeSliceDrawing::drawOrthogonalSlice_LPI_ONLY(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], const Plane& plane) { const int32_t browserTabIndex = m_browserTabContent->getTabNumber(); const DisplayPropertiesLabels* displayPropertiesLabels = m_brain->getDisplayPropertiesLabels(); const DisplayGroupEnum::Enum displayGroup = displayPropertiesLabels->getDisplayGroupForTab(browserTabIndex); /* * Enable alpha blending so voxels that are not drawn from higher layers * allow voxels from lower layers to be seen. */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* * Flat shading voxels not interpolated */ glShadeModel(GL_FLAT); CaretAssert(plane.isValidPlane()); if (plane.isValidPlane() == false) { return; } /* * Compute coordinate of point in center of first slice */ float selectedSliceCoordinate = 0.0; float sliceNormalVector[3] = { 0.0, 0.0, 0.0 }; plane.getNormalVector(sliceNormalVector); switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: selectedSliceCoordinate = sliceCoordinates[2]; break; case VolumeSliceViewPlaneEnum::CORONAL: selectedSliceCoordinate = sliceCoordinates[1]; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: selectedSliceCoordinate = sliceCoordinates[0]; break; } /* * Holds colors for voxels in the slice * Outside of loop to minimize allocations * It is faster to make one call to * NodeAndVoxelColoring::colorScalarsWithPalette() with * all voxels in the slice than it is to call it * separately for each voxel. */ std::vector sliceVoxelsRgbaVector; /* * Draw each of the volumes separately so that each * is drawn with the correct voxel slices. */ const int32_t numberOfVolumesToDraw = static_cast(m_volumeDrawInfo.size()); for (int32_t iVol = 0; iVol < numberOfVolumesToDraw; iVol++) { const BrainOpenGLFixedPipeline::VolumeDrawInfo& volInfo = m_volumeDrawInfo[iVol]; const VolumeMappableInterface* volumeFile = volInfo.volumeFile; int64_t dimI, dimJ, dimK, numMaps, numComponents; volumeFile->getDimensions(dimI, dimJ, dimK, numMaps, numComponents); const int64_t mapIndex = volInfo.mapIndex; float originX, originY, originZ; volumeFile->indexToSpace(0, 0, 0, originX, originY, originZ); float x1, y1, z1; volumeFile->indexToSpace(1, 1, 1, x1, y1, z1); const float voxelStepX = x1 - originX; const float voxelStepY = y1 - originY; const float voxelStepZ = z1 - originZ; /* * Determine index of slice being viewed for the volume */ float coordinateOnSlice[3] = { originX, originY, originZ }; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: coordinateOnSlice[2] = selectedSliceCoordinate; break; case VolumeSliceViewPlaneEnum::CORONAL: coordinateOnSlice[1] = selectedSliceCoordinate; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: coordinateOnSlice[0] = selectedSliceCoordinate; break; } int64_t sliceIndicesForCoordinateOnSlice[3]; volumeFile->enclosingVoxel(coordinateOnSlice[0], coordinateOnSlice[1], coordinateOnSlice[2], sliceIndicesForCoordinateOnSlice[0], sliceIndicesForCoordinateOnSlice[1], sliceIndicesForCoordinateOnSlice[2]); int64_t sliceIndexForDrawing = -1; int64_t numVoxelsInSlice = 0; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: sliceIndexForDrawing = sliceIndicesForCoordinateOnSlice[2]; if ((sliceIndexForDrawing < 0) || (sliceIndexForDrawing >= dimK)) { continue; } numVoxelsInSlice = dimI * dimJ; break; case VolumeSliceViewPlaneEnum::CORONAL: sliceIndexForDrawing = sliceIndicesForCoordinateOnSlice[1]; if ((sliceIndexForDrawing < 0) || (sliceIndexForDrawing >= dimJ)) { continue; } numVoxelsInSlice = dimI * dimK; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: sliceIndexForDrawing = sliceIndicesForCoordinateOnSlice[0]; if ((sliceIndexForDrawing < 0) || (sliceIndexForDrawing >= dimI)) { continue; } numVoxelsInSlice = dimJ * dimK; break; } /* * Stores RGBA values for each voxel. * Use a vector for voxel colors so no worries about memory being freed. */ const int64_t numVoxelsInSliceRGBA = numVoxelsInSlice * 4; if (numVoxelsInSliceRGBA > static_cast(sliceVoxelsRgbaVector.size())) { sliceVoxelsRgbaVector.resize(numVoxelsInSliceRGBA); } uint8_t* sliceVoxelsRGBA = &sliceVoxelsRgbaVector[0]; /* * Get colors for all voxels in the slice. */ const int64_t validVoxelCount = volumeFile->getVoxelColorsForSliceInMap(mapIndex, sliceViewPlane, sliceIndexForDrawing, displayGroup, browserTabIndex, sliceVoxelsRGBA); /* * Is label outline mode? */ if (m_volumeDrawInfo[iVol].mapFile->isMappedWithLabelTable()) { int64_t xdim = 0; int64_t ydim = 0; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: xdim = dimI; ydim = dimJ; break; case VolumeSliceViewPlaneEnum::CORONAL: xdim = dimI; ydim = dimK; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: xdim = dimJ; ydim = dimK; break; } LabelDrawingTypeEnum::Enum labelDrawingType = LabelDrawingTypeEnum::DRAW_FILLED; CaretColorEnum::Enum outlineColor = CaretColorEnum::BLACK; const CaretMappableDataFile* mapFile = dynamic_cast(volumeFile); if (mapFile != NULL) { if (mapFile->isMappedWithLabelTable()) { const LabelDrawingProperties* props = mapFile->getLabelDrawingProperties(); labelDrawingType = props->getDrawingType(); outlineColor = props->getOutlineColor(); } } NodeAndVoxelColoring::convertSliceColoringToOutlineMode(sliceVoxelsRGBA, labelDrawingType, outlineColor, xdim, ydim); } int64_t selectedSliceIndices[3]; volumeFile->enclosingVoxel(sliceCoordinates[0], sliceCoordinates[1], sliceCoordinates[2], selectedSliceIndices[0], selectedSliceIndices[1], selectedSliceIndices[2]); const uint8_t volumeDrawingOpacity = static_cast(volInfo.opacity * 255.0); /* * Setup for drawing the voxels in the slice. */ float startCoordinate[3] = { originX - (voxelStepX / 2.0f), originY - (voxelStepY / 2.0f), originZ - (voxelStepZ / 2.0f) }; float rowStep[3] = { 0.0f, 0.0f, 0.0f }; float columnStep[3] = { 0.0f, 0.0f, 0.0f }; int64_t numberOfRows = 0; int64_t numberOfColumns = 0; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: startCoordinate[2] = selectedSliceCoordinate; rowStep[1] = voxelStepY; columnStep[0] = voxelStepX; numberOfRows = dimJ; numberOfColumns = dimI; break; case VolumeSliceViewPlaneEnum::CORONAL: startCoordinate[1] = selectedSliceCoordinate; rowStep[2] = voxelStepZ; columnStep[0] = voxelStepX; numberOfRows = dimK; numberOfColumns = dimI; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: startCoordinate[0] = selectedSliceCoordinate; rowStep[2] = voxelStepZ; columnStep[1] = voxelStepY; numberOfRows = dimK; numberOfColumns = dimJ; break; } if (m_modelWholeBrain != NULL) { /* * After the a slice is drawn in ALL view, some layers * (volume surface outline) may be drawn in lines. As the * view is rotated, lines will partially appear and disappear * due to the lines having the same (extremely close) depth * values as the voxel polygons. OpenGL's Polygon Offset * only works with polygons and NOT with lines or points. * So, polygon offset cannot be used to move the depth * values for the lines and points "a little closer" to * the user. Instead, polygon offset is used to push * the underlaying slices "a little bit away" from the * user. * * Resolves WB-414 */ const float inverseSliceIndex = numberOfVolumesToDraw - iVol; const float factor = inverseSliceIndex * 1.0 + 1.0; const float units = inverseSliceIndex * 1.0 + 1.0; glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(factor, units); } /* * Draw the voxels in the slice. */ // const AString drawMsg("OLD LPI:" // "\n Axis: " + VolumeSliceViewPlaneEnum::toName(sliceViewPlane) // + "\n Start XYZ: " + AString::fromNumbers(startCoordinate, 3, ",") // + "\n Row Step: " + AString::fromNumbers(rowStep, 3, ",") // + "\n Column Step: " + AString::fromNumbers(columnStep, 3, ",") // + "\n Num Cols: " + AString::number(numberOfColumns) // + "\n Num Rows: " + AString::number(numberOfRows) // + "\n"); // std::cout << qPrintable(drawMsg) << std::endl; drawOrthogonalSliceVoxels(sliceNormalVector, startCoordinate, rowStep, columnStep, numberOfColumns, numberOfRows, sliceVoxelsRgbaVector, validVoxelCount, volumeFile, iVol, mapIndex, volumeDrawingOpacity); glDisable(GL_POLYGON_OFFSET_FILL); } showBrainordinateHighlightRegionOfInterest(sliceViewPlane, sliceCoordinates, sliceNormalVector); glDisable(GL_BLEND); glShadeModel(GL_SMOOTH); } /** * Find the given orientation in the given volume, find its corresponding * dimesion index. * * @param volume * The volume. * @param orientation * The requested orientation * @return * Index of dimension containing the orientation or * Negative if not found. */ static int32_t getDimensionContainingOrientation(const VolumeMappableInterface* volume, const VolumeSpace::OrientTypes orientation) { VolumeSpace::OrientTypes orients[3]; volume->getVolumeSpace().getOrientation(orients); for (int32_t i = 0; i < 3; i++) { if (orientation == orients[i]) { return i; } } return -1; } /** * Find the given orientation in the given volume, find its corresponding * dimesion index. * * @param volume * The volume. * @param orientation1 * First requested orientation * @param orientation2 * Second requested orientation * @return * Index of dimension containing the orientation or * Negative if not found. */ static int32_t getDimensionContainingSlicePlane(const VolumeMappableInterface* volume, const VolumeSliceViewPlaneEnum::Enum slicePlane) { int32_t indexOne = -1; int32_t indexTwo = -1; switch (slicePlane) { case caret::VolumeSliceViewPlaneEnum::ALL: break; case caret::VolumeSliceViewPlaneEnum::AXIAL: indexOne = getDimensionContainingOrientation(volume, VolumeSpace::INFERIOR_TO_SUPERIOR); indexTwo = getDimensionContainingOrientation(volume, VolumeSpace::SUPERIOR_TO_INFERIOR); break; case caret::VolumeSliceViewPlaneEnum::CORONAL: indexOne = getDimensionContainingOrientation(volume, VolumeSpace::ANTERIOR_TO_POSTERIOR); indexTwo = getDimensionContainingOrientation(volume, VolumeSpace::POSTERIOR_TO_ANTERIOR); break; case caret::VolumeSliceViewPlaneEnum::PARASAGITTAL: indexOne = getDimensionContainingOrientation(volume, VolumeSpace::LEFT_TO_RIGHT); indexTwo = getDimensionContainingOrientation(volume, VolumeSpace::RIGHT_TO_LEFT); break; } if ((indexOne >= 0) && (indexTwo >= 0)) { CaretLogSevere("Volume contains same axes orientations in more than one dimension"); } else if ((indexOne < 0) && (indexTwo < 0)) { /* probably occurs if volume is not plumb */ } else if (indexOne >= 0) { return indexOne; } else if (indexTwo >= 0) { return indexTwo; } return -1; } /** * Provides information on an axis in a volume. * Used for drawing volumes in any valid orientation. */ class AxisInfo { public: VolumeSliceViewPlaneEnum::Enum axis; /** Orientation in axis */ VolumeSpace::OrientTypes orientation; /** index for use with slice indices/dimensions and 'this->axis' */ int64_t indexIntoIJK; /** index for use with XYZ coordinates */ int64_t indexIntoXYZ; /** number of voxels in dimension */ int64_t numberOfVoxels; /** step to move to next voxel */ int64_t voxelIndexStep; /** index of first voxel (either 0 or (numberOfVoxels - 1)) */ int64_t firstVoxelIndex; /** absolute spatial size (mm) of voxel */ float absoluteVoxelSize; /** spatial step to next voxel (signed) */ float voxelStepSize; /** first voxel xyz */ float firstVoxelXYZ[3]; /** last voxel xyz */ float lastVoxelXYZ[3]; /** true if this axis info is valid */ bool valid; AxisInfo() { valid = false; } void print() { AString orientationName; switch (orientation) { case caret::VolumeSpace::INFERIOR_TO_SUPERIOR: orientationName = "INFERIOR_TO_SUPERIOR"; break; case caret::VolumeSpace::POSTERIOR_TO_ANTERIOR: orientationName = "POSTERIOR_TO_ANTERIOR"; break; case caret::VolumeSpace::LEFT_TO_RIGHT: orientationName = "LEFT_TO_RIGHT"; break; case caret::VolumeSpace::RIGHT_TO_LEFT: orientationName = "RIGHT_TO_LEFT"; break; case caret::VolumeSpace::ANTERIOR_TO_POSTERIOR: orientationName = "ANTERIOR_TO_POSTERIOR"; break; case caret::VolumeSpace::SUPERIOR_TO_INFERIOR: orientationName = "SUPERIOR_TO_INFERIOR"; break; } const AString s("Axis: " + VolumeSliceViewPlaneEnum::toName(axis) + "\n Orientation: " + orientationName + "\n IJK Index: " + AString::number(indexIntoIJK) + "\n XYZ Index: " + AString::number(indexIntoXYZ) + "\n Number of voxels: " + AString::number(numberOfVoxels) + "\n First Voxel Index: " + AString::number(firstVoxelIndex) + "\n Voxel Index Step: " + AString::number(voxelIndexStep) + "\n Abs Voxel Size: " + AString::number(absoluteVoxelSize) + "\n Voxel Step Size: " + AString::number(voxelStepSize) + "\n First voxel XYZ: " + AString::fromNumbers(firstVoxelXYZ, 3, ", ") + "\n Last voxel XYZ: " + AString::fromNumbers(lastVoxelXYZ, 3, ", ") + "\n"); std::cout << qPrintable(s) << std::endl; } }; /** * Get the info for the given axis in the given volume file * * @param volumeFile * The volume file. * @param axis * The axis * @param startWithMinimumCoordFlag * If true, voxel information will start with voxel that has minimum coordinate. * @param axisInfoOut * Output containing information for the given axis */ static void getAxisInfo(const VolumeMappableInterface* volumeFile, const VolumeSliceViewPlaneEnum::Enum axis, const bool startWithMinimumCoordFlag, AxisInfo& axisInfoOut) { /* * Data for axis may be in any dimension */ axisInfoOut.axis = axis; axisInfoOut.indexIntoIJK = getDimensionContainingSlicePlane(volumeFile, axis); if (axisInfoOut.indexIntoIJK < 0) { axisInfoOut.valid = false; return; } /* * X, Y, Z is always indices 0, 1, 2 */ switch (axis) { case VolumeSliceViewPlaneEnum::ALL: break; case VolumeSliceViewPlaneEnum::AXIAL: axisInfoOut.indexIntoXYZ = 2; break; case VolumeSliceViewPlaneEnum::CORONAL: axisInfoOut.indexIntoXYZ = 1; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: axisInfoOut.indexIntoXYZ = 0; break; } VolumeSpace::OrientTypes orientations[3]; volumeFile->getVolumeSpace().getOrientation(orientations); axisInfoOut.orientation = orientations[axisInfoOut.indexIntoXYZ]; std::vector dimArray; volumeFile->getDimensions(dimArray); CaretAssertVectorIndex(dimArray, axisInfoOut.indexIntoIJK); axisInfoOut.numberOfVoxels = dimArray[axisInfoOut.indexIntoIJK]; axisInfoOut.firstVoxelIndex = 0; int64_t zeroIndices[3] = { 0, 0, 0 }; volumeFile->indexToSpace(zeroIndices, axisInfoOut.firstVoxelXYZ); int64_t oneIndices[3] = { 1, 1, 1}; float xyzOne[3] = { 1.0, 1.0, 1.0 }; volumeFile->indexToSpace(oneIndices, xyzOne); int64_t lastIndices[3] = { dimArray[0] - 1, dimArray[1] - 1, dimArray[2] - 1 }; volumeFile->indexToSpace(lastIndices, axisInfoOut.lastVoxelXYZ); axisInfoOut.voxelStepSize = (xyzOne[axisInfoOut.indexIntoXYZ] - axisInfoOut.firstVoxelXYZ[axisInfoOut.indexIntoXYZ]); axisInfoOut.absoluteVoxelSize = std::fabs(axisInfoOut.voxelStepSize); axisInfoOut.voxelIndexStep = 1; if (startWithMinimumCoordFlag) { if (axisInfoOut.voxelStepSize < 0.0) { axisInfoOut.firstVoxelIndex = axisInfoOut.numberOfVoxels - 1; axisInfoOut.voxelStepSize = -axisInfoOut.voxelStepSize; axisInfoOut.voxelIndexStep = -1; } } else { if (axisInfoOut.voxelStepSize > 0.0) { axisInfoOut.firstVoxelIndex = axisInfoOut.numberOfVoxels - 1; axisInfoOut.voxelStepSize = -axisInfoOut.voxelStepSize; axisInfoOut.voxelIndexStep = -1; } } axisInfoOut.valid = true; //axisInfoOut.print(); } /** * Draw an orthogonal slice. * * @param sliceViewingPlane * The plane for slice drawing. * @param sliceCoordinates * Coordinates of the selected slice. * @param plane * Plane equation for the selected slice. */ void BrainOpenGLVolumeSliceDrawing::drawOrthogonalSlice(const VolumeSliceViewPlaneEnum::Enum sliceViewingPlane, const float sliceCoordinates[3], const Plane& plane) { CaretAssert(plane.isValidPlane()); if (plane.isValidPlane() == false) { return; } const int32_t browserTabIndex = m_browserTabContent->getTabNumber(); const DisplayPropertiesLabels* displayPropertiesLabels = m_brain->getDisplayPropertiesLabels(); const DisplayGroupEnum::Enum displayGroup = displayPropertiesLabels->getDisplayGroupForTab(browserTabIndex); /* * Enable alpha blending so voxels that are not drawn from higher layers * allow voxels from lower layers to be seen. * * Only allow layer blending when overall volume opacity is off (>= 1.0) */ const bool allowBlendingFlag(true); glPushAttrib(GL_COLOR_BUFFER_BIT); if (allowBlendingFlag) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } /* * Flat shading voxels not interpolated */ glShadeModel(GL_FLAT); /* * Compute coordinate of point in center of first slice */ float selectedSliceCoordinate = 0.0; float sliceNormalVector[3] = { 0.0, 0.0, 0.0 }; plane.getNormalVector(sliceNormalVector); switch (sliceViewingPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: selectedSliceCoordinate = sliceCoordinates[2]; break; case VolumeSliceViewPlaneEnum::CORONAL: selectedSliceCoordinate = sliceCoordinates[1]; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: selectedSliceCoordinate = sliceCoordinates[0]; break; } /* * Holds colors for voxels in the slice * Outside of loop to minimize allocations * It is faster to make one call to * NodeAndVoxelColoring::colorScalarsWithPalette() with * all voxels in the slice than it is to call it * separately for each voxel. */ std::vector sliceVoxelsRgbaVector; /* * Draw each of the volumes separately so that each * is drawn with the correct voxel slices. */ const int32_t numberOfVolumesToDraw = static_cast(m_volumeDrawInfo.size()); for (int32_t iVol = 0; iVol < numberOfVolumesToDraw; iVol++) { const BrainOpenGLFixedPipeline::VolumeDrawInfo& volInfo = m_volumeDrawInfo[iVol]; const VolumeMappableInterface* volumeFile = volInfo.volumeFile; /* * Find axis that correspond to the axis that are on * the screen horizontally and vertically. */ AxisInfo drawLeftToRightInfo; AxisInfo drawBottomToTopInfo; int64_t viewPlaneDimIndex = getDimensionContainingSlicePlane(volumeFile, sliceViewingPlane); int64_t sliceViewingPlaneIndexIntoXYZ = -1; switch (sliceViewingPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: getAxisInfo(volumeFile, VolumeSliceViewPlaneEnum::PARASAGITTAL, true, drawLeftToRightInfo); getAxisInfo(volumeFile, VolumeSliceViewPlaneEnum::CORONAL, true, drawBottomToTopInfo); sliceViewingPlaneIndexIntoXYZ = 2; break; case VolumeSliceViewPlaneEnum::CORONAL: getAxisInfo(volumeFile, VolumeSliceViewPlaneEnum::PARASAGITTAL, true, drawLeftToRightInfo); getAxisInfo(volumeFile, VolumeSliceViewPlaneEnum::AXIAL, true, drawBottomToTopInfo); sliceViewingPlaneIndexIntoXYZ = 1; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: getAxisInfo(volumeFile, VolumeSliceViewPlaneEnum::CORONAL, false, drawLeftToRightInfo); getAxisInfo(volumeFile, VolumeSliceViewPlaneEnum::AXIAL, true, drawBottomToTopInfo); sliceViewingPlaneIndexIntoXYZ = 0; break; } CaretAssert(drawLeftToRightInfo.valid); CaretAssert(drawBottomToTopInfo.valid); CaretAssert(viewPlaneDimIndex != drawLeftToRightInfo.indexIntoIJK); CaretAssert(viewPlaneDimIndex != drawBottomToTopInfo.indexIntoIJK); CaretAssert(drawLeftToRightInfo.indexIntoIJK != drawBottomToTopInfo.indexIntoIJK); CaretAssert(sliceViewingPlaneIndexIntoXYZ != drawLeftToRightInfo.indexIntoXYZ); CaretAssert(sliceViewingPlaneIndexIntoXYZ != drawBottomToTopInfo.indexIntoXYZ); CaretAssert(drawLeftToRightInfo.indexIntoXYZ != drawBottomToTopInfo.indexIntoXYZ); /* * There must be at least two voxels in both dimensions. * If a dimension consists of a single voxel, then it is * likely a single slice volume and our viewpoint is * "in" the slice. * * Without this check the user would see a strange looking * line that is one voxel in width */ if ((drawLeftToRightInfo.numberOfVoxels <= 1) || (drawBottomToTopInfo.numberOfVoxels <= 1)) { continue; } /* * Spatial amount to move up row. */ float rowStepXYZ[3] = { 0.0, 0.0, 0.0 }; rowStepXYZ[drawBottomToTopInfo.indexIntoXYZ] = drawBottomToTopInfo.voxelStepSize; /* * Spatial amount to move right one column. */ float columnStepXYZ[3] = { 0.0, 0.0, 0.0 }; columnStepXYZ[drawLeftToRightInfo.indexIntoXYZ] = drawLeftToRightInfo.voxelStepSize; /* * Step in voxel dimensions to move right one column */ int64_t columnStepIJK[3] = { 0, 0, 0 }; columnStepIJK[drawLeftToRightInfo.indexIntoIJK] = drawLeftToRightInfo.voxelIndexStep; /* * Step in voxel dimensions to move up one row */ int64_t rowStepIJK[3] = { 0, 0, 0 }; rowStepIJK[drawBottomToTopInfo.indexIntoIJK] = drawBottomToTopInfo.voxelIndexStep; /* * XYZ needs to use regular X=0, Y=1, Z=2 indices */ int64_t sliceVoxelIndices[3] = { 0, 0, 0 }; float sliceVoxelXYZ[3] = { 0.0, 0.0, 0.0 }; sliceVoxelXYZ[sliceViewingPlaneIndexIntoXYZ] = selectedSliceCoordinate; volumeFile->enclosingVoxel(sliceVoxelXYZ[0], sliceVoxelXYZ[1], sliceVoxelXYZ[2], sliceVoxelIndices[0], sliceVoxelIndices[1], sliceVoxelIndices[2]); /* * Find the index of the slice for drawing and verify that * it is a valid slice index. */ const int64_t sliceIndexForDrawing = sliceVoxelIndices[viewPlaneDimIndex]; std::vector volDim; volumeFile->getDimensions(volDim); const int64_t maximumAxisSliceIndex = volDim[viewPlaneDimIndex]; if ((sliceIndexForDrawing < 0) || (sliceIndexForDrawing >= maximumAxisSliceIndex)) { continue; } /* * Voxel indices for first voxel that is drawn at bottom left of screen */ int64_t firstVoxelIJK[3] = { -1, -1, -1 }; firstVoxelIJK[drawBottomToTopInfo.indexIntoIJK] = drawBottomToTopInfo.firstVoxelIndex; firstVoxelIJK[drawLeftToRightInfo.indexIntoIJK] = drawLeftToRightInfo.firstVoxelIndex; firstVoxelIJK[viewPlaneDimIndex] = sliceIndexForDrawing; /* * Coordinate of first voxel that is drawn at bottom left of screen */ float startCoordinateXYZ[3] = { 0.0, 0.0, 0.0 }; volumeFile->indexToSpace(firstVoxelIJK, startCoordinateXYZ); startCoordinateXYZ[drawLeftToRightInfo.indexIntoXYZ] -= (drawLeftToRightInfo.voxelStepSize / 2.0); startCoordinateXYZ[drawBottomToTopInfo.indexIntoXYZ] -= (drawBottomToTopInfo.voxelStepSize / 2.0); startCoordinateXYZ[viewPlaneDimIndex] = selectedSliceCoordinate; /* * Stores RGBA values for each voxel. * Use a vector for voxel colors so no worries about memory being freed. */ const int64_t numVoxelsInSlice = drawBottomToTopInfo.numberOfVoxels * drawLeftToRightInfo.numberOfVoxels; const int64_t numVoxelsInSliceRGBA = numVoxelsInSlice * 4; if (numVoxelsInSliceRGBA > static_cast(sliceVoxelsRgbaVector.size())) { sliceVoxelsRgbaVector.resize(numVoxelsInSliceRGBA); } uint8_t* sliceVoxelsRGBA = &sliceVoxelsRgbaVector[0]; /* * Get colors for all voxels in the slice. */ const int64_t validVoxelCount = volumeFile->getVoxelColorsForSliceInMap(volInfo.mapIndex, firstVoxelIJK, rowStepIJK, columnStepIJK, drawBottomToTopInfo.numberOfVoxels, drawLeftToRightInfo.numberOfVoxels, displayGroup, browserTabIndex, sliceVoxelsRGBA); /* * Is label outline mode? */ if (m_volumeDrawInfo[iVol].mapFile->isMappedWithLabelTable()) { int64_t xdim = drawLeftToRightInfo.numberOfVoxels; int64_t ydim = drawBottomToTopInfo.numberOfVoxels; LabelDrawingTypeEnum::Enum labelDrawingType = LabelDrawingTypeEnum::DRAW_FILLED; CaretColorEnum::Enum outlineColor = CaretColorEnum::BLACK; const CaretMappableDataFile* mapFile = dynamic_cast(volumeFile); if (mapFile != NULL) { if (mapFile->isMappedWithLabelTable()) { const LabelDrawingProperties* props = mapFile->getLabelDrawingProperties(); labelDrawingType = props->getDrawingType(); outlineColor = props->getOutlineColor(); } } NodeAndVoxelColoring::convertSliceColoringToOutlineMode(sliceVoxelsRGBA, labelDrawingType, outlineColor, xdim, ydim); } if (m_volumeDrawInfo[iVol].mapFile->isMappedWithPalette()) { const int32_t mapIndex = m_volumeDrawInfo[iVol].mapIndex; const PaletteColorMapping* pcm = m_volumeDrawInfo[iVol].mapFile->getMapPaletteColorMapping(mapIndex); int64_t xdim = drawLeftToRightInfo.numberOfVoxels; int64_t ydim = drawBottomToTopInfo.numberOfVoxels; NodeAndVoxelColoring::convertPaletteSliceColoringToOutlineMode(sliceVoxelsRGBA, pcm->getThresholdOutlineDrawingMode(), pcm->getThresholdOutlineDrawingColor(), xdim, ydim); } const uint8_t volumeDrawingOpacity = static_cast(volInfo.opacity * 255.0); if (m_modelWholeBrain != NULL) { /* * After the a slice is drawn in ALL view, some layers * (volume surface outline) may be drawn in lines. As the * view is rotated, lines will partially appear and disappear * due to the lines having the same (extremely close) depth * values as the voxel polygons. OpenGL's Polygon Offset * only works with polygons and NOT with lines or points. * So, polygon offset cannot be used to move the depth * values for the lines and points "a little closer" to * the user. Instead, polygon offset is used to push * the underlaying slices "a little bit away" from the * user. * * Resolves WB-414 */ const float inverseSliceIndex = numberOfVolumesToDraw - iVol; const float factor = inverseSliceIndex * 1.0 + 1.0; const float units = inverseSliceIndex * 1.0 + 1.0; glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(factor, units); } /* * Draw the voxels in the slice. */ // const AString drawMsg("NEW:" // "\n Axis: " + VolumeSliceViewPlaneEnum::toName(sliceViewingPlane) // + "\n Start XYZ: " + AString::fromNumbers(startCoordinateXYZ, 3, ",") // + "\n Row Step: " + AString::fromNumbers(rowStepXYZ, 3, ",") // + "\n Column Step: " + AString::fromNumbers(columnStepXYZ, 3, ",") // + "\n Num Cols: " + AString::number(drawLeftToRightInfo.numberOfVoxels) // + "\n Num Rows: " + AString::number(drawBottomToTopInfo.numberOfVoxels) // + "\n"); // std::cout << qPrintable(drawMsg) << std::endl; drawOrthogonalSliceVoxels(sliceNormalVector, startCoordinateXYZ, rowStepXYZ, columnStepXYZ, drawLeftToRightInfo.numberOfVoxels, drawBottomToTopInfo.numberOfVoxels, sliceVoxelsRgbaVector, validVoxelCount, volumeFile, iVol, volInfo.mapIndex, volumeDrawingOpacity); glDisable(GL_POLYGON_OFFSET_FILL); } showBrainordinateHighlightRegionOfInterest(sliceViewingPlane, sliceCoordinates, sliceNormalVector); glPopAttrib(); //glDisable(GL_BLEND); glShadeModel(GL_SMOOTH); } /** * Show brainordinate highlighting region of interest for the volume slice. * * @param sliceViewPlane * Slice plane viewed. * @param sliceCoordinates * Coordinates of the slice. * @param sliceNormalVector * Normal vector for the slice. */ void BrainOpenGLVolumeSliceDrawing::showBrainordinateHighlightRegionOfInterest(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], const float sliceNormalVector[3]) { const BrainordinateRegionOfInterest* roi = m_brain->getBrainordinateHighlightRegionOfInterest(); if ( ! roi->hasVolumeVoxels()) { return; } if ( ! roi->isBrainordinateHighlightingEnabled()) { return; } const std::vector& voxelXYZ = roi->getVolumeVoxelsXYZ(); const int64_t numVoxels = static_cast(voxelXYZ.size() / 3); if (numVoxels <= 0) { return; } float voxelSize[3]; roi->getVolumeVoxelSize(voxelSize); CaretAssert(voxelSize[0] >= 0.0); CaretAssert(voxelSize[1] >= 0.0); CaretAssert(voxelSize[2] >= 0.0); float halfX = voxelSize[0] / 2.0; float halfY = voxelSize[1] / 2.0; float halfZ = voxelSize[2] / 2.0; int64_t axisIndex = 0; float sliceMinCoord = 0.0; float sliceMaxCoord = 0.0; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: sliceMinCoord = sliceCoordinates[2] - halfZ; sliceMaxCoord = sliceCoordinates[2] + halfZ; axisIndex = 2; break; case VolumeSliceViewPlaneEnum::CORONAL: sliceMinCoord = sliceCoordinates[1] - halfY; sliceMaxCoord = sliceCoordinates[1] + halfZ; axisIndex = 1; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: sliceMinCoord = sliceCoordinates[0] - halfX; sliceMaxCoord = sliceCoordinates[0] + halfX; axisIndex = 0; break; } std::vector quadsXYZ; for (int64_t i = 0; i < numVoxels; i++) { const int64_t i3 = i * 3; if ((voxelXYZ[i3 + axisIndex] >= sliceMinCoord) && (voxelXYZ[i3 + axisIndex] <= sliceMaxCoord)) { CaretAssertVectorIndex(voxelXYZ, i3+2); const float x = voxelXYZ[i3]; const float y = voxelXYZ[i3+1]; const float z = voxelXYZ[i3+2]; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: quadsXYZ.push_back(x - halfX); quadsXYZ.push_back(y - halfY); quadsXYZ.push_back(sliceCoordinates[2]); quadsXYZ.push_back(x + halfX); quadsXYZ.push_back(y - halfY); quadsXYZ.push_back(sliceCoordinates[2]); quadsXYZ.push_back(x + halfX); quadsXYZ.push_back(y + halfY); quadsXYZ.push_back(sliceCoordinates[2]); quadsXYZ.push_back(x - halfX); quadsXYZ.push_back(y + halfY); quadsXYZ.push_back(sliceCoordinates[2]); break; case VolumeSliceViewPlaneEnum::CORONAL: quadsXYZ.push_back(x - halfX); quadsXYZ.push_back(sliceCoordinates[1]); quadsXYZ.push_back(z - halfZ); quadsXYZ.push_back(x + halfX); quadsXYZ.push_back(sliceCoordinates[1]); quadsXYZ.push_back(z - halfZ); quadsXYZ.push_back(x + halfX); quadsXYZ.push_back(sliceCoordinates[1]); quadsXYZ.push_back(z + halfZ); quadsXYZ.push_back(x - halfX); quadsXYZ.push_back(sliceCoordinates[1]); quadsXYZ.push_back(z + halfZ); break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: quadsXYZ.push_back(sliceCoordinates[0]); quadsXYZ.push_back(y + halfY); quadsXYZ.push_back(z - halfZ); quadsXYZ.push_back(sliceCoordinates[0]); quadsXYZ.push_back(y - halfY); quadsXYZ.push_back(z - halfZ); quadsXYZ.push_back(sliceCoordinates[0]); quadsXYZ.push_back(y - halfY); quadsXYZ.push_back(z + halfZ); quadsXYZ.push_back(sliceCoordinates[0]); quadsXYZ.push_back(y + halfY); quadsXYZ.push_back(z + halfZ); break; } } } const int64_t numVoxelsToDraw = (quadsXYZ.size() / 12); CaretAssert((numVoxelsToDraw * 12) == static_cast(quadsXYZ.size())); const int64_t numCoords = (quadsXYZ.size()) / 3; std::vector voxelQuadNormals; voxelQuadNormals.reserve(numVoxelsToDraw * 12); std::vector voxelQuadRgba; voxelQuadRgba.reserve(numVoxelsToDraw * 16); CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); uint8_t foregroundColor[4]; prefs->getBackgroundAndForegroundColors()->getColorForegroundVolumeView(foregroundColor); for (int32_t iNormalAndColor = 0; iNormalAndColor < numCoords; iNormalAndColor++) { voxelQuadRgba.push_back(foregroundColor[0]); voxelQuadRgba.push_back(foregroundColor[1]); voxelQuadRgba.push_back(foregroundColor[2]); voxelQuadRgba.push_back(255); voxelQuadNormals.push_back(sliceNormalVector[0]); voxelQuadNormals.push_back(sliceNormalVector[1]); voxelQuadNormals.push_back(sliceNormalVector[2]); } CaretAssert(quadsXYZ.size() == voxelQuadNormals.size()); CaretAssert((numVoxelsToDraw * 16) == static_cast(voxelQuadRgba.size())); BrainOpenGLPrimitiveDrawing::drawQuads(quadsXYZ, voxelQuadNormals, voxelQuadRgba); } /** * Draw identification symbols on volume slice with the given plane. * * @param plane * The plane equation. */ void BrainOpenGLVolumeSliceDrawing::drawIdentificationSymbols(const Plane& plane) { IdentificationManager* idManager = m_brain->getIdentificationManager(); SelectionItemVoxelIdentificationSymbol* symbolID = m_brain->getSelectionManager()->getVoxelIdentificationSymbol(); const std::vector voxelIDs = idManager->getIdentifiedItemsForVolume(); /* * Check for a 'selection' type mode */ bool isSelect = false; switch (m_fixedPipelineDrawing->mode) { case BrainOpenGLFixedPipeline::MODE_DRAWING: break; case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: if (symbolID->isEnabledForSelection()) { isSelect = true; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } else { return; } break; case BrainOpenGLFixedPipeline::MODE_PROJECTION: return; break; } if (idManager->isShowVolumeIdentificationSymbols()) { uint8_t rgba[4]; const int32_t numVoxelIdSymbols = static_cast(voxelIDs.size()); for (int32_t iVoxel = 0; iVoxel < numVoxelIdSymbols; iVoxel++) { CaretAssertVectorIndex(voxelIDs, iVoxel); const IdentifiedItemVoxel& voxel = voxelIDs[iVoxel]; float xyz[3]; voxel.getXYZ(xyz); const float symbolDiameter = voxel.getSymbolSize(); const float halfSymbolSize = symbolDiameter / 2.0; const float dist = plane.signedDistanceToPlane(xyz); if (dist < halfSymbolSize) { if (isSelect) { m_fixedPipelineDrawing->colorIdentification->addItem(rgba, SelectionItemDataTypeEnum::VOXEL_IDENTIFICATION_SYMBOL, iVoxel); rgba[3] = 255; } else { voxel.getSymbolRGBA(rgba); } glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); m_fixedPipelineDrawing->drawSphereWithDiameter(rgba, symbolDiameter); glPopMatrix(); } } } if (isSelect) { int voxelIdIndex = -1; float depth = -1.0; m_fixedPipelineDrawing->getIndexFromColorSelection(SelectionItemDataTypeEnum::VOXEL_IDENTIFICATION_SYMBOL, m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, voxelIdIndex, depth); if (voxelIdIndex >= 0) { if (symbolID->isOtherScreenDepthCloserToViewer(depth)) { CaretAssertVectorIndex(voxelIDs, voxelIdIndex); const IdentifiedItemVoxel& voxel = voxelIDs[voxelIdIndex]; float xyz[3]; voxel.getXYZ(xyz); symbolID->setVoxelXYZ(xyz); symbolID->setBrain(m_brain); symbolID->setScreenDepth(depth); m_fixedPipelineDrawing->setSelectedItemScreenXYZ(symbolID, xyz); CaretLogFine("Selected Vertex Identification Symbol: " + QString::number(voxelIdIndex)); } } } } /** * Draw an orthogonal slice with culling to avoid drawing * voxels not visible in the viewport and reduce drawing time. * * @param sliceViewPlane * The plane for slice drawing. * @param sliceCoordinates * Coordinates of the selected slice. * @param plane * Plane equation for the selected slice. */ void BrainOpenGLVolumeSliceDrawing::drawOrthogonalSliceWithCulling(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], const Plane& plane) { const int32_t browserTabIndex = m_browserTabContent->getTabNumber(); const DisplayPropertiesLabels* displayPropertiesLabels = m_brain->getDisplayPropertiesLabels(); const DisplayGroupEnum::Enum displayGroup = displayPropertiesLabels->getDisplayGroupForTab(browserTabIndex); /* * Flat shading voxels not interpolated */ glShadeModel(GL_FLAT); CaretAssert(plane.isValidPlane()); if (plane.isValidPlane() == false) { return; } /* * Enable alpha blending so voxels that are not drawn from higher layers * allow voxels from lower layers to be seen. * * Only allow layer blending when overall volume opacity is off (>= 1.0) */ const bool allowBlendingFlag(true); glPushAttrib(GL_COLOR_BUFFER_BIT); if (allowBlendingFlag) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } /* * Compute coordinate of point in center of first slice */ float selectedSliceCoordinate = 0.0; float sliceNormalVector[3] = { 0.0, 0.0, 0.0 }; plane.getNormalVector(sliceNormalVector); switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: selectedSliceCoordinate = sliceCoordinates[2]; break; case VolumeSliceViewPlaneEnum::CORONAL: selectedSliceCoordinate = sliceCoordinates[1]; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: selectedSliceCoordinate = sliceCoordinates[0]; break; } /* * Holds colors for voxels in the slice * Outside of loop to minimize allocations * It is faster to make one call to * NodeAndVoxelColoring::colorScalarsWithPalette() with * all voxels in the slice than it is to call it * separately for each voxel. */ std::vector sliceVoxelsRgbaVector; /* * Draw each of the volumes separately so that each * is drawn with the correct voxel slices. */ const int32_t numberOfVolumesToDraw = static_cast(m_volumeDrawInfo.size()); for (int32_t iVol = 0; iVol < numberOfVolumesToDraw; iVol++) { const BrainOpenGLFixedPipeline::VolumeDrawInfo& volInfo = m_volumeDrawInfo[iVol]; const VolumeMappableInterface* volumeFile = volInfo.volumeFile; int64_t culledFirstVoxelIJK[3]; int64_t culledLastVoxelIJK[3]; float voxelDeltaXYZ[3]; if ( ! getVolumeDrawingViewDependentCulling(sliceViewPlane, selectedSliceCoordinate, volumeFile, culledFirstVoxelIJK, culledLastVoxelIJK, voxelDeltaXYZ)) { /* volume does not have slice within the culled region */ continue; } /*const int64_t numVoxelsI = std::abs(culledLastVoxelIJK[0] - culledFirstVoxelIJK[0]) + 1; const int64_t numVoxelsJ = std::abs(culledLastVoxelIJK[1] - culledFirstVoxelIJK[1]) + 1; const int64_t numVoxelsK = std::abs(culledLastVoxelIJK[2] - culledFirstVoxelIJK[2]) + 1;//*/ int64_t numVoxelsX = -1, numVoxelsY = -1, numVoxelsZ = -1; int64_t sliceIndexForDrawing = -1; int64_t dimIJK[3], numMaps, numComponents; volumeFile->getDimensions(dimIJK[0], dimIJK[1], dimIJK[2], numMaps, numComponents); VolumeSpace::OrientTypes orient[3]; volumeFile->getVolumeSpace().getOrientation(orient);//use the volume's orientation to get the correct dimension for each axis bool skipDraw = false; for (int whichDim = 0; whichDim < 3; ++whichDim) { int64_t numVoxelsIndex = std::abs(culledLastVoxelIJK[whichDim] - culledFirstVoxelIJK[whichDim]) + 1; switch (orient[whichDim]) { case VolumeSpace::LEFT_TO_RIGHT: case VolumeSpace::RIGHT_TO_LEFT: numVoxelsX = numVoxelsIndex; if (sliceViewPlane == VolumeSliceViewPlaneEnum::PARASAGITTAL) { sliceIndexForDrawing = culledFirstVoxelIJK[whichDim]; if ((sliceIndexForDrawing < 0) || (sliceIndexForDrawing >= dimIJK[whichDim])) { skipDraw = true; } } break; case VolumeSpace::POSTERIOR_TO_ANTERIOR: case VolumeSpace::ANTERIOR_TO_POSTERIOR: numVoxelsY = numVoxelsIndex; if (sliceViewPlane == VolumeSliceViewPlaneEnum::CORONAL) { sliceIndexForDrawing = culledFirstVoxelIJK[whichDim]; if ((sliceIndexForDrawing < 0) || (sliceIndexForDrawing >= dimIJK[whichDim])) { skipDraw = true; } } break; case VolumeSpace::INFERIOR_TO_SUPERIOR: case VolumeSpace::SUPERIOR_TO_INFERIOR: numVoxelsZ = numVoxelsIndex; if (sliceViewPlane == VolumeSliceViewPlaneEnum::AXIAL) { sliceIndexForDrawing = culledFirstVoxelIJK[whichDim]; if ((sliceIndexForDrawing < 0) || (sliceIndexForDrawing >= dimIJK[whichDim])) { skipDraw = true; } } break; } } if (skipDraw) continue; const int64_t mapIndex = volInfo.mapIndex; float firstVoxelXYZ[3]; volumeFile->indexToSpace(culledFirstVoxelIJK[0], culledFirstVoxelIJK[1], culledFirstVoxelIJK[2], firstVoxelXYZ[0], firstVoxelXYZ[1], firstVoxelXYZ[2]); const float voxelStepX = voxelDeltaXYZ[0]; const float voxelStepY = voxelDeltaXYZ[1]; const float voxelStepZ = voxelDeltaXYZ[2]; int64_t numVoxelsInSlice = 0; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: numVoxelsInSlice = numVoxelsX * numVoxelsY; break; case VolumeSliceViewPlaneEnum::CORONAL: numVoxelsInSlice = numVoxelsX * numVoxelsZ; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: numVoxelsInSlice = numVoxelsY * numVoxelsZ; break; } /* * Stores RGBA values for each voxel. * Use a vector for voxel colors so no worries about memory being freed. */ const int64_t numVoxelsInSliceRGBA = numVoxelsInSlice * 4; if (numVoxelsInSliceRGBA != static_cast(sliceVoxelsRgbaVector.size())) { sliceVoxelsRgbaVector.resize(numVoxelsInSliceRGBA); } uint8_t* sliceVoxelsRGBA = &sliceVoxelsRgbaVector[0]; /* * Get colors for all voxels in the slice. */ const int64_t voxelCountXYZ[3] = { numVoxelsX, numVoxelsY, numVoxelsZ };//only used to multiply them all together to get an element count for the presumed array size, so just provide them as XYZ const int64_t validVoxelCount = volumeFile->getVoxelColorsForSubSliceInMap(mapIndex, sliceViewPlane, sliceIndexForDrawing, culledFirstVoxelIJK, culledLastVoxelIJK, voxelCountXYZ, displayGroup, browserTabIndex, sliceVoxelsRGBA); /* * Is label outline mode? */ if (m_volumeDrawInfo[iVol].mapFile->isMappedWithLabelTable()) { int64_t xdim = 0; int64_t ydim = 0; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: xdim = numVoxelsX; ydim = numVoxelsY; break; case VolumeSliceViewPlaneEnum::CORONAL: xdim = numVoxelsX; ydim = numVoxelsZ; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: xdim = numVoxelsY; ydim = numVoxelsZ; break; } LabelDrawingTypeEnum::Enum labelDrawingType = LabelDrawingTypeEnum::DRAW_FILLED; CaretColorEnum::Enum outlineColor = CaretColorEnum::BLACK; const CaretMappableDataFile* mapFile = dynamic_cast(volumeFile); if (mapFile != NULL) { if (mapFile->isMappedWithLabelTable()) { const LabelDrawingProperties* props = mapFile->getLabelDrawingProperties(); labelDrawingType = props->getDrawingType(); outlineColor = props->getOutlineColor(); } } NodeAndVoxelColoring::convertSliceColoringToOutlineMode(sliceVoxelsRGBA, labelDrawingType, outlineColor, xdim, ydim); } if (m_volumeDrawInfo[iVol].mapFile->isMappedWithPalette()) { const int32_t mapIndex = m_volumeDrawInfo[iVol].mapIndex; int64_t xdim = 0; int64_t ydim = 0; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: xdim = numVoxelsX; ydim = numVoxelsY; break; case VolumeSliceViewPlaneEnum::CORONAL: xdim = numVoxelsX; ydim = numVoxelsZ; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: xdim = numVoxelsY; ydim = numVoxelsZ; break; } const PaletteColorMapping* pcm = m_volumeDrawInfo[iVol].mapFile->getMapPaletteColorMapping(mapIndex); NodeAndVoxelColoring::convertPaletteSliceColoringToOutlineMode(sliceVoxelsRGBA, pcm->getThresholdOutlineDrawingMode(), pcm->getThresholdOutlineDrawingColor(), xdim, ydim); } const uint8_t volumeDrawingOpacity = static_cast(volInfo.opacity * 255.0); /* * Setup for drawing the voxels in the slice. */ float startCoordinate[3] = { firstVoxelXYZ[0] - (voxelStepX / 2.0f), firstVoxelXYZ[1] - (voxelStepY / 2.0f), firstVoxelXYZ[2] - (voxelStepZ / 2.0f) }; float rowStep[3] = { 0.0, 0.0, 0.0 }; float columnStep[3] = { 0.0, 0.0, 0.0 }; int64_t numberOfRows = 0; int64_t numberOfColumns = 0; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: rowStep[1] = voxelStepY; columnStep[0] = voxelStepX; numberOfRows = numVoxelsY;//WARNING: this is actually length of row, not number of rows, ditto for the rest numberOfColumns = numVoxelsX;//leaving it alone for now... break; case VolumeSliceViewPlaneEnum::CORONAL: rowStep[2] = voxelStepZ; columnStep[0] = voxelStepX; numberOfRows = numVoxelsZ; numberOfColumns = numVoxelsX; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: rowStep[2] = voxelStepZ; columnStep[1] = voxelStepY; numberOfRows = numVoxelsZ; numberOfColumns = numVoxelsY; break; } if (m_modelWholeBrain != NULL) { /* * After the a slice is drawn in ALL view, some layers * (volume surface outline) may be drawn in lines. As the * view is rotated, lines will partially appear and disappear * due to the lines having the same (extremely close) depth * values as the voxel polygons. OpenGL's Polygon Offset * only works with polygons and NOT with lines or points. * So, polygon offset cannot be used to move the depth * values for the lines and points "a little closer" to * the user. Instead, polygon offset is used to push * the underlaying slices "a little bit away" from the * user. * * Resolves WB-414 */ const float inverseSliceIndex = numberOfVolumesToDraw - iVol; const float factor = inverseSliceIndex * 1.0 + 1.0; const float units = inverseSliceIndex * 1.0 + 1.0; glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(factor, units); } else { /* * A layer may be "under" another layer and not be seen. * Draw all layers at the selected slice coordinate. */ switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: startCoordinate[2] = selectedSliceCoordinate; break; case VolumeSliceViewPlaneEnum::CORONAL: startCoordinate[1] = selectedSliceCoordinate; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: startCoordinate[0] = selectedSliceCoordinate; break; } } /* * Draw the voxels in the slice. */ drawOrthogonalSliceVoxels(sliceNormalVector, startCoordinate, rowStep, columnStep, numberOfColumns, numberOfRows, sliceVoxelsRgbaVector, validVoxelCount, volumeFile, iVol, mapIndex, volumeDrawingOpacity); glDisable(GL_POLYGON_OFFSET_FILL); } showBrainordinateHighlightRegionOfInterest(sliceViewPlane, sliceCoordinates, sliceNormalVector); glPopAttrib(); glShadeModel(GL_SMOOTH); } /** * Create the equation for the slice plane * * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * View plane that is displayed. * @param montageSliceIndex * Selected montage slice index * @param planeOut * OUTPUT plane of slice after transforms. */ void BrainOpenGLVolumeSliceDrawing::createSlicePlaneEquation(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], Plane& planeOut) { /* * Default the slice normal vector to an orthogonal view */ float sliceNormalVector[3] = { 0.0, 0.0, 0.0 }; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: case VolumeSliceViewPlaneEnum::AXIAL: sliceNormalVector[2] = 1.0; break; case VolumeSliceViewPlaneEnum::CORONAL: sliceNormalVector[1] = -1.0; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: sliceNormalVector[0] = -1.0; break; } switch (sliceProjectionType) { break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: CaretAssert(0); break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: break; } Plane plane(sliceNormalVector, sliceCoordinates); planeOut = plane; m_lookAtCenter[0] = sliceCoordinates[0]; m_lookAtCenter[1] = sliceCoordinates[1]; m_lookAtCenter[2] = sliceCoordinates[2]; } /** * Set the volume slice viewing transformation. This sets the position and * orientation of the camera. * * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * View plane that is displayed. * @param plane * Plane equation of selected slice. */ void BrainOpenGLVolumeSliceDrawing::setVolumeSliceViewingAndModelingTransformations(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const Plane& plane) { /* * Determine model size in screen Y when viewed */ BoundingBox boundingBox; m_volumeDrawInfo[0].volumeFile->getVoxelSpaceBoundingBox(boundingBox); const double centerX = boundingBox.getCenterX(); const double centerY = boundingBox.getCenterY(); const double centerZ = boundingBox.getCenterZ(); /* * Initialize the modelview matrix to the identity matrix * This places the camera at the origin, pointing down the * negative-Z axis with the up vector set to (0,1,0 => * positive-Y is up). */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); /* * Translate to place center of volume at origin */ double moveToCenterX = 0.0; double moveToCenterY = 0.0; double moveToCenterZ = 0.0; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssertMessage(0, "Should never get here"); break; case VolumeSliceViewPlaneEnum::AXIAL: moveToCenterX = -centerX; moveToCenterY = -centerY; break; case VolumeSliceViewPlaneEnum::CORONAL: moveToCenterX = -centerX; moveToCenterY = -centerZ; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: moveToCenterX = centerY; moveToCenterY = -centerZ; break; } glTranslated(moveToCenterX, moveToCenterY, moveToCenterZ); /* * Set "look at" to origin */ m_lookAtCenter[0] = 0.0; m_lookAtCenter[1] = 0.0; m_lookAtCenter[2] = 0.0; /* * Since an orthographic projection is used, the camera only needs * to be a little bit from the center along the plane's normal vector. */ double planeNormal[3]; plane.getNormalVector(planeNormal); double cameraXYZ[3] = { m_lookAtCenter[0] + planeNormal[0] * BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_lookAtCenter[1] + planeNormal[1] * BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_lookAtCenter[2] + planeNormal[2] * BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance }; /* * Set the up vector which indices which way is up (screen Y) */ float up[3] = { 0.0, 0.0, 0.0 }; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: case VolumeSliceViewPlaneEnum::AXIAL: up[1] = 1.0; break; case VolumeSliceViewPlaneEnum::CORONAL: up[2] = 1.0; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: up[2] = 1.0; break; } /* * Now set the camera to look at the selected coordinate (center) * with the camera offset a little bit from the center. * This allows the slice's voxels to be drawn in the actual coordinates. */ gluLookAt(cameraXYZ[0], cameraXYZ[1], cameraXYZ[2], m_lookAtCenter[0], m_lookAtCenter[1], m_lookAtCenter[2], up[0], up[1], up[2]); const float* userTranslation = m_browserTabContent->getTranslation(); /* * Apply user translation */ glTranslatef(userTranslation[0], userTranslation[1], userTranslation[2]); /* * For oblique viewing, the up vector needs to be rotated by the * oblique rotation matrix. */ switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: CaretAssert(0); break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: break; } /* * Apply user scaling */ const float userScaling = m_browserTabContent->getScaling(); glScalef(userScaling, userScaling, userScaling); glGetDoublev(GL_MODELVIEW_MATRIX, m_viewingMatrix); } /** * Draw the layers type data. * * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * View plane that is displayed. * @param slicePlane * Plane of the slice. * @param sliceCoordinates * Coordinates of the selected slices. */ void BrainOpenGLVolumeSliceDrawing::drawLayers(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const Plane& slicePlane, const float sliceCoordinates[3]) { bool drawCrosshairsFlag = true; bool drawFibersFlag = true; bool drawFociFlag = true; bool drawOutlineFlag = true; if (m_modelWholeBrain != NULL) { drawCrosshairsFlag = false; drawFibersFlag = false; drawFociFlag = false; } if ( ! m_identificationModeFlag) { if (slicePlane.isValidPlane()) { /* * Disable culling so that both sides of the triangles/quads are drawn. */ GLboolean cullFaceOn = glIsEnabled(GL_CULL_FACE); glDisable(GL_CULL_FACE); glPushMatrix(); GLboolean depthBufferEnabled = false; glGetBooleanv(GL_DEPTH_TEST, &depthBufferEnabled); /* * Use some polygon offset that will adjust the depth values of the * layers so that the layers depth values place the layers in front of * the volume slice. */ glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(0.0, 1.0); if (drawOutlineFlag) { drawSurfaceOutline(m_underlayVolume, m_modelType, sliceProjectionType, sliceViewPlane, sliceCoordinates, slicePlane, m_browserTabContent->getVolumeSurfaceOutlineSet(), m_fixedPipelineDrawing, false); } if (drawFibersFlag) { glDisable(GL_DEPTH_TEST); m_fixedPipelineDrawing->drawFiberOrientations(&slicePlane, StructureEnum::ALL); m_fixedPipelineDrawing->drawFiberTrajectories(&slicePlane, StructureEnum::ALL); if (depthBufferEnabled) { glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); } } if (drawFociFlag) { glDisable(GL_DEPTH_TEST); drawVolumeSliceFoci(slicePlane); if (depthBufferEnabled) { glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); } } glDisable(GL_POLYGON_OFFSET_FILL); if (drawCrosshairsFlag) { glPushMatrix(); drawAxesCrosshairs(sliceProjectionType, sliceDrawingType, sliceViewPlane, sliceCoordinates); glPopMatrix(); if (depthBufferEnabled) { glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); } } glPopMatrix(); if (cullFaceOn) { glEnable(GL_CULL_FACE); } } } } /** * Draw surface outlines on the volume slices * * @param underlayVolume * The underlay volume * @param modelType * Type of model being drawn. * @param sliceProjectionType * Projection type (oblique/orthogonal) * @param sliceViewPlane * Slice view plane (axial, coronal, parasagittal) * @param sliceXYZ * Coordinates of slices * @param plane * Plane of the volume slice on which surface outlines are drawn. * @param outlineSet * The surface outline set. * @param fixedPipelineDrawing * The fixed pipeline drawing. * @param useNegativePolygonOffsetFlag * If true, use a negative offset for polygon offset */ void BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(const VolumeMappableInterface* underlayVolume, const ModelTypeEnum::Enum modelType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceXYZ[3], const Plane& plane, VolumeSurfaceOutlineSetModel* outlineSet, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const bool useNegativePolygonOffsetFlag) { /* * Code still here to allow comparison with * previous algorithm */ bool drawCachedFlag(true); if (drawCachedFlag) { drawSurfaceOutlineCached(underlayVolume, modelType, sliceProjectionType, sliceViewPlane, sliceXYZ, plane, outlineSet, fixedPipelineDrawing, useNegativePolygonOffsetFlag); } else { drawSurfaceOutlineNotCached(modelType, plane, outlineSet, fixedPipelineDrawing, useNegativePolygonOffsetFlag); } } /** * Draw surface outlines on the volume slices * * @param underlayVolume * The underlay volume * @param modelType * Type of model being drawn. * @param sliceProjectionType Type of slice projection * @param sliceProjectionType * Type of slice projection * @param sliceViewPlane * Slice view plane (axial, coronal, parasagittal) * @param sliceXYZ * Coordinates of slices * @param plane * Plane of the volume slice on which surface outlines are drawn. * @param outlineSet * The surface outline set. * @param fixedPipelineDrawing * The fixed pipeline drawing. * @param useNegativePolygonOffsetFlag * If true, use a negative offset for polygon offset */ void BrainOpenGLVolumeSliceDrawing::drawSurfaceOutlineCached(const VolumeMappableInterface* underlayVolume, const ModelTypeEnum::Enum modelType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceXYZ[3], const Plane& plane, VolumeSurfaceOutlineSetModel* outlineSet, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const bool useNegativePolygonOffsetFlag) { glPushAttrib(GL_ENABLE_BIT); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); switch (modelType) { case ModelTypeEnum::MODEL_TYPE_CHART: break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: break; case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: /* * Enable depth so outlines in front or in back * of the slices. Without this the volume surface * outlines "behind" the slices are visible and * it looks weird */ glEnable(GL_DEPTH_TEST); break; } float sliceCoordinate(0.0); switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: break; case VolumeSliceViewPlaneEnum::AXIAL: sliceCoordinate = sliceXYZ[2]; break; case VolumeSliceViewPlaneEnum::CORONAL: sliceCoordinate = sliceXYZ[1]; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: sliceCoordinate = sliceXYZ[0]; break; } /* * Key for outline cache */ VolumeSurfaceOutlineModelCacheKey outlineCacheKey(underlayVolume, sliceViewPlane, sliceCoordinate); switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: outlineCacheKey = VolumeSurfaceOutlineModelCacheKey(underlayVolume, plane); break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: break; } /* * Process each surface outline * As of 24 May, "zero" is on top so draw in reverse order */ const int32_t numberOfOutlines = outlineSet->getNumberOfDislayedVolumeSurfaceOutlines(); for (int32_t io = (numberOfOutlines - 1); io >= 0; io--) { std::vector contourPrimitives; VolumeSurfaceOutlineModel* outline = outlineSet->getVolumeSurfaceOutlineModel(io); if (outline->isDisplayed()) { Surface* surface = outline->getSurface(); if (surface != NULL) { float thicknessPercentage = outline->getThicknessPercentageViewportHeight(); const float thicknessPixels = outline->getThicknessPixelsObsolete(); /* * Thickness was changed from pixels to percentage viewport height on Feb 02, 2018 * If thickness percentage is negative, it was not present in an old * scene so convert pixels to percentage using viewports dimensions */ if (thicknessPercentage < 0.0f) { thicknessPercentage = GraphicsUtilitiesOpenGL::convertPixelsToPercentageOfViewportHeight(thicknessPixels); if (thicknessPercentage > 0.0f) { outline->setThicknessPercentageViewportHeight(thicknessPercentage); } } if (outline->getOutlineCachePrimitives(underlayVolume, outlineCacheKey, contourPrimitives)) { /* OK, have cached primitives to draw */ } else { CaretColorEnum::Enum outlineColor = CaretColorEnum::BLACK; int32_t colorSourceBrowserTabIndex = -1; VolumeSurfaceOutlineColorOrTabModel* colorOrTabModel = outline->getColorOrTabModel(); VolumeSurfaceOutlineColorOrTabModel::Item* selectedColorOrTabItem = colorOrTabModel->getSelectedItem(); switch (selectedColorOrTabItem->getItemType()) { case VolumeSurfaceOutlineColorOrTabModel::Item::ITEM_TYPE_BROWSER_TAB: colorSourceBrowserTabIndex = selectedColorOrTabItem->getBrowserTabIndex(); outlineColor = CaretColorEnum::CUSTOM; break; case VolumeSurfaceOutlineColorOrTabModel::Item::ITEM_TYPE_COLOR: outlineColor = selectedColorOrTabItem->getColor(); break; } const bool surfaceColorFlag = (colorSourceBrowserTabIndex >= 0); float* nodeColoringRGBA = NULL; if (surfaceColorFlag) { nodeColoringRGBA = fixedPipelineDrawing->surfaceNodeColoring->colorSurfaceNodes(NULL, surface, colorSourceBrowserTabIndex); } SurfacePlaneIntersectionToContour contour(surface, plane, outlineColor, nodeColoringRGBA, thicknessPercentage); AString errorMessage; if ( ! contour.createContours(contourPrimitives, errorMessage)) { CaretLogSevere(errorMessage); } outline->setOutlineCachePrimitives(underlayVolume, outlineCacheKey, contourPrimitives); } } } /** * Draw the contours. * Note: The primitives are now cached so DO NOT delete them. */ for (auto primitive : contourPrimitives) { if (useNegativePolygonOffsetFlag) { glPolygonOffset(-1.0, -1.0); } else { glPolygonOffset(1.0, 1.0); } glEnable(GL_POLYGON_OFFSET_FILL); GraphicsEngineDataOpenGL::draw(primitive); glDisable(GL_POLYGON_OFFSET_FILL); } } glPopAttrib(); } /** * Draw surface outlines on the volume slices WITHOUT caching * * @param modelType * Type of model being drawn. * @param plane * Plane of the volume slice on which surface outlines are drawn. * @param outlineSet * The surface outline set. * @param fixedPipelineDrawing * The fixed pipeline drawing. * @param useNegativePolygonOffsetFlag * If true, use a negative offset for polygon offset */ void BrainOpenGLVolumeSliceDrawing::drawSurfaceOutlineNotCached(const ModelTypeEnum::Enum modelType, const Plane& plane, VolumeSurfaceOutlineSetModel* outlineSet, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const bool useNegativePolygonOffsetFlag) { glPushAttrib(GL_ENABLE_BIT); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); switch (modelType) { case ModelTypeEnum::MODEL_TYPE_CHART: break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: break; case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: /* * Enable depth so outlines in front or in back * of the slices. Without this the volume surface * outlines "behind" the slices are visible and * it looks weird */ glEnable(GL_DEPTH_TEST); break; } /* * Process each surface outline * As of 24 May, "zero" is on top so draw in reverse order */ const int32_t numberOfOutlines = outlineSet->getNumberOfDislayedVolumeSurfaceOutlines(); for (int32_t io = (numberOfOutlines - 1); io >= 0; io--) { std::vector contourPrimitives; VolumeSurfaceOutlineModel* outline = outlineSet->getVolumeSurfaceOutlineModel(io); if (outline->isDisplayed()) { Surface* surface = outline->getSurface(); if (surface != NULL) { float thicknessPercentage = outline->getThicknessPercentageViewportHeight(); const float thicknessPixels = outline->getThicknessPixelsObsolete(); /* * Thickness was changed from pixels to percentage viewport height on Feb 02, 2018 * If thickness percentage is negative, it was not present in an old * scene so convert pixels to percentage using viewports dimensions */ if (thicknessPercentage < 0.0f) { thicknessPercentage = GraphicsUtilitiesOpenGL::convertPixelsToPercentageOfViewportHeight(thicknessPixels); if (thicknessPercentage > 0.0f) { outline->setThicknessPercentageViewportHeight(thicknessPercentage); } } CaretColorEnum::Enum outlineColor = CaretColorEnum::BLACK; int32_t colorSourceBrowserTabIndex = -1; VolumeSurfaceOutlineColorOrTabModel* colorOrTabModel = outline->getColorOrTabModel(); VolumeSurfaceOutlineColorOrTabModel::Item* selectedColorOrTabItem = colorOrTabModel->getSelectedItem(); switch (selectedColorOrTabItem->getItemType()) { case VolumeSurfaceOutlineColorOrTabModel::Item::ITEM_TYPE_BROWSER_TAB: colorSourceBrowserTabIndex = selectedColorOrTabItem->getBrowserTabIndex(); outlineColor = CaretColorEnum::CUSTOM; break; case VolumeSurfaceOutlineColorOrTabModel::Item::ITEM_TYPE_COLOR: outlineColor = selectedColorOrTabItem->getColor(); break; } const bool surfaceColorFlag = (colorSourceBrowserTabIndex >= 0); float* nodeColoringRGBA = NULL; if (surfaceColorFlag) { nodeColoringRGBA = fixedPipelineDrawing->surfaceNodeColoring->colorSurfaceNodes(NULL, surface, colorSourceBrowserTabIndex); } //const float thicknessPercentage = GraphicsUtilitiesOpenGL::convertPixelsToPercentageOfViewportHeight(thicknessMillimeters); SurfacePlaneIntersectionToContour contour(surface, plane, outlineColor, nodeColoringRGBA, thicknessPercentage); AString errorMessage; if ( ! contour.createContours(contourPrimitives, errorMessage)) { CaretLogSevere(errorMessage); } } } /** * Draw the contours. */ for (auto primitive : contourPrimitives) { if (useNegativePolygonOffsetFlag) { glPolygonOffset(-1.0, -1.0); } else { glPolygonOffset(1.0, 1.0); } glEnable(GL_POLYGON_OFFSET_FILL); GraphicsEngineDataOpenGL::draw(primitive); delete primitive; glDisable(GL_POLYGON_OFFSET_FILL); } } glPopAttrib(); } /** * Draw foci on volume slice. * * @param plane * Plane of the volume slice on which surface outlines are drawn. */ void BrainOpenGLVolumeSliceDrawing::drawVolumeSliceFoci(const Plane& plane) { SelectionItemFocusVolume* idFocus = m_brain->getSelectionManager()->getVolumeFocusIdentification(); /* * Check for a 'selection' type mode */ bool isSelect = false; switch (m_fixedPipelineDrawing->mode) { case BrainOpenGLFixedPipeline::MODE_DRAWING: break; case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: if (idFocus->isEnabledForSelection()) { isSelect = true; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } else { return; } break; case BrainOpenGLFixedPipeline::MODE_PROJECTION: return; break; } VolumeMappableInterface* underlayVolume = m_volumeDrawInfo[0].volumeFile; float minVoxelSpacing; float maxVoxelSpacing; if ( ! getMinMaxVoxelSpacing(underlayVolume, minVoxelSpacing, maxVoxelSpacing)) { return; } const float sliceThickness = maxVoxelSpacing; const float halfSliceThickness = sliceThickness * 0.5; const DisplayPropertiesFoci* fociDisplayProperties = m_brain->getDisplayPropertiesFoci(); const DisplayGroupEnum::Enum displayGroup = fociDisplayProperties->getDisplayGroupForTab(m_fixedPipelineDrawing->windowTabIndex); const CaretColorEnum::Enum caretColor = fociDisplayProperties->getStandardColorType(displayGroup, m_fixedPipelineDrawing->windowTabIndex); float caretColorRGBA[4]; CaretColorEnum::toRGBAFloat(caretColor, caretColorRGBA); if (fociDisplayProperties->isDisplayed(displayGroup, m_fixedPipelineDrawing->windowTabIndex) == false) { return; } const float focusDiameter = fociDisplayProperties->getFociSize(displayGroup, m_fixedPipelineDrawing->windowTabIndex); const FeatureColoringTypeEnum::Enum fociColoringType = fociDisplayProperties->getColoringType(displayGroup, m_fixedPipelineDrawing->windowTabIndex); bool drawAsSpheres = false; switch (fociDisplayProperties->getDrawingType(displayGroup, m_fixedPipelineDrawing->windowTabIndex)) { case FociDrawingTypeEnum::DRAW_AS_SPHERES: drawAsSpheres = true; break; case FociDrawingTypeEnum::DRAW_AS_SQUARES: break; } /* * Process each foci file */ const int32_t numberOfFociFiles = m_brain->getNumberOfFociFiles(); for (int32_t iFile = 0; iFile < numberOfFociFiles; iFile++) { FociFile* fociFile = m_brain->getFociFile(iFile); const GroupAndNameHierarchyModel* classAndNameSelection = fociFile->getGroupAndNameHierarchyModel(); if (classAndNameSelection->isSelected(displayGroup, m_fixedPipelineDrawing->windowTabIndex) == false) { continue; } const GiftiLabelTable* classColorTable = fociFile->getClassColorTable(); const GiftiLabelTable* nameColorTable = fociFile->getNameColorTable(); const int32_t numFoci = fociFile->getNumberOfFoci(); for (int32_t j = 0; j < numFoci; j++) { Focus* focus = fociFile->getFocus(j); const GroupAndNameHierarchyItem* groupNameItem = focus->getGroupNameSelectionItem(); if (groupNameItem != NULL) { if (groupNameItem->isSelected(displayGroup, m_fixedPipelineDrawing->windowTabIndex) == false) { continue; } } float rgba[4] = { 0.0, 0.0, 0.0, 1.0 }; switch (fociColoringType) { case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_CLASS: if (focus->isClassRgbaValid() == false) { const GiftiLabel* colorLabel = classColorTable->getLabelBestMatching(focus->getClassName()); if (colorLabel != NULL) { colorLabel->getColor(rgba); focus->setClassRgba(rgba); } else { focus->setClassRgba(rgba); } } focus->getClassRgba(rgba); break; case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_STANDARD_COLOR: rgba[0] = caretColorRGBA[0]; rgba[1] = caretColorRGBA[1]; rgba[2] = caretColorRGBA[2]; rgba[3] = caretColorRGBA[3]; break; case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_NAME: if (focus->isNameRgbaValid() == false) { const GiftiLabel* colorLabel = nameColorTable->getLabelBestMatching(focus->getName()); if (colorLabel != NULL) { colorLabel->getColor(rgba); focus->setNameRgba(rgba); } else { focus->setNameRgba(rgba); } } focus->getNameRgba(rgba); break; } const int32_t numProjections = focus->getNumberOfProjections(); for (int32_t k = 0; k < numProjections; k++) { const SurfaceProjectedItem* spi = focus->getProjection(k); if (spi->isVolumeXYZValid()) { float xyz[3]; spi->getVolumeXYZ(xyz); bool drawIt = false; if (plane.absoluteDistanceToPlane(xyz) < halfSliceThickness) { drawIt = true; } if (drawIt) { glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); if (isSelect) { uint8_t idRGBA[4]; m_fixedPipelineDrawing->colorIdentification->addItem(idRGBA, SelectionItemDataTypeEnum::FOCUS_VOLUME, iFile, // file index j, // focus index k);// projection index idRGBA[3] = 255; if (drawAsSpheres) { m_fixedPipelineDrawing->drawSphereWithDiameter(idRGBA, focusDiameter); } else { glColor4ubv(idRGBA); drawSquare(focusDiameter); } } else { if (drawAsSpheres) { m_fixedPipelineDrawing->drawSphereWithDiameter(rgba, focusDiameter); } else { glColor3fv(rgba); drawSquare(focusDiameter); } } glPopMatrix(); } } } } } if (isSelect) { int32_t fociFileIndex = -1; int32_t focusIndex = -1; int32_t focusProjectionIndex = -1; float depth = -1.0; m_fixedPipelineDrawing->getIndexFromColorSelection(SelectionItemDataTypeEnum::FOCUS_VOLUME, m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, fociFileIndex, focusIndex, focusProjectionIndex, depth); if (fociFileIndex >= 0) { if (idFocus->isOtherScreenDepthCloserToViewer(depth)) { Focus* focus = m_brain->getFociFile(fociFileIndex)->getFocus(focusIndex); idFocus->setBrain(m_brain); idFocus->setFocus(focus); idFocus->setFociFile(m_brain->getFociFile(fociFileIndex)); idFocus->setFocusIndex(focusIndex); idFocus->setFocusProjectionIndex(focusProjectionIndex); idFocus->setVolumeFile(underlayVolume); idFocus->setScreenDepth(depth); float xyz[3]; const SurfaceProjectedItem* spi = focus->getProjection(focusProjectionIndex); spi->getVolumeXYZ(xyz); m_fixedPipelineDrawing->setSelectedItemScreenXYZ(idFocus, xyz); CaretLogFine("Selected Volume Focus Identification Symbol: " + QString::number(focusIndex)); } } } } /** * Draw the axes crosshairs. * * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceViewPlane * View plane that is displayed. * @param sliceCoordinates * Coordinates of the selected slices. */ void BrainOpenGLVolumeSliceDrawing::drawAxesCrosshairs(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3]) { const bool drawCrosshairsFlag = m_browserTabContent->isVolumeAxesCrosshairsDisplayed(); bool drawCrosshairLabelsFlag = m_browserTabContent->isVolumeAxesCrosshairLabelsDisplayed(); switch (sliceDrawingType) { case VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_MONTAGE: drawCrosshairLabelsFlag = false; break; case VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE: break; } switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: drawAxesCrosshairsOrtho(sliceViewPlane, sliceCoordinates, drawCrosshairsFlag, drawCrosshairLabelsFlag); break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: { glPushMatrix(); glLoadIdentity(); double mv[16]; glGetDoublev(GL_MODELVIEW_MATRIX, mv); Matrix4x4 mvm; mvm.setMatrixFromOpenGL(mv); float trans[3]; m_browserTabContent->getTranslation(trans); glTranslatef(trans[0], trans[1], trans[2]); drawAxesCrosshairsOrtho(sliceViewPlane, sliceCoordinates, drawCrosshairsFlag, drawCrosshairLabelsFlag); glPopMatrix(); } break; } } /** * Draw the axes crosshairs for an orthogonal slice. * * @param sliceViewPlane * The slice plane view. * @param sliceCoordinatesIn * Coordinates of the selected slices. * @param drawCrosshairsFlag * If true, draw the crosshairs. * @param drawCrosshairLabelsFlag * If true, draw the crosshair labels. */ void BrainOpenGLVolumeSliceDrawing::drawAxesCrosshairsOrtho(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinatesIn[3], const bool drawCrosshairsFlag, const bool drawCrosshairLabelsFlag) { const float gapPercentViewportHeight = SessionManager::get()->getCaretPreferences()->getVolumeCrosshairGap(); const float gapMM = GraphicsUtilitiesOpenGL::convertPercentageOfViewportHeightToMillimeters(gapPercentViewportHeight); std::array sliceCoordinates { sliceCoordinatesIn[0], sliceCoordinatesIn[1], sliceCoordinatesIn[2] }; GLboolean depthEnabled = GL_FALSE; glGetBooleanv(GL_DEPTH_TEST, &depthEnabled); glDisable(GL_DEPTH_TEST); const float bigValue = 10000.0 + gapMM; std::array horizontalAxisPosStartXYZ = sliceCoordinates; std::array horizontalAxisPosEndXYZ = sliceCoordinates; std::array verticalAxisPosStartXYZ = sliceCoordinates; std::array verticalAxisPosEndXYZ = sliceCoordinates; std::array horizontalAxisNegStartXYZ = horizontalAxisPosStartXYZ; std::array horizontalAxisNegEndXYZ = horizontalAxisPosEndXYZ; std::array verticalAxisNegStartXYZ = verticalAxisPosStartXYZ; std::array verticalAxisNegEndXYZ = verticalAxisPosEndXYZ; float axialRGBA[4]; getAxesColor(VolumeSliceViewPlaneEnum::AXIAL, axialRGBA); float coronalRGBA[4]; getAxesColor(VolumeSliceViewPlaneEnum::CORONAL, coronalRGBA); float paraRGBA[4]; getAxesColor(VolumeSliceViewPlaneEnum::PARASAGITTAL, paraRGBA); AString horizontalLeftText = ""; AString horizontalRightText = ""; AString verticalBottomText = ""; AString verticalTopText = ""; float* horizontalAxisRGBA = axialRGBA; float* verticalAxisRGBA = axialRGBA; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: break; case VolumeSliceViewPlaneEnum::AXIAL: horizontalLeftText = "L"; horizontalRightText = "R"; horizontalAxisRGBA = coronalRGBA; horizontalAxisPosStartXYZ[0] += gapMM; horizontalAxisPosEndXYZ[0] += bigValue; horizontalAxisNegStartXYZ[0] -= gapMM; horizontalAxisNegEndXYZ[0] -= bigValue; verticalBottomText = "P"; verticalTopText = "A"; verticalAxisRGBA = paraRGBA; verticalAxisPosStartXYZ[1] += gapMM; verticalAxisPosEndXYZ[1] += bigValue; verticalAxisNegStartXYZ[1] -= gapMM; verticalAxisNegEndXYZ[1] -= bigValue; break; case VolumeSliceViewPlaneEnum::CORONAL: horizontalLeftText = "L"; horizontalRightText = "R"; horizontalAxisRGBA = axialRGBA; horizontalAxisPosStartXYZ[0] += gapMM; horizontalAxisPosEndXYZ[0] += bigValue; horizontalAxisNegStartXYZ[0] -= gapMM; horizontalAxisNegEndXYZ[0] -= bigValue; verticalBottomText = "I"; verticalTopText = "S"; verticalAxisRGBA = paraRGBA; verticalAxisPosStartXYZ[2] += gapMM; verticalAxisPosEndXYZ[2] += bigValue; verticalAxisNegStartXYZ[2] -= gapMM; verticalAxisNegEndXYZ[2] -= bigValue; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: horizontalLeftText = "A"; horizontalRightText = "P"; horizontalAxisRGBA = axialRGBA; horizontalAxisPosStartXYZ[1] += gapMM; horizontalAxisPosEndXYZ[1] += bigValue; horizontalAxisNegStartXYZ[1] -= gapMM; horizontalAxisNegEndXYZ[1] -= bigValue; verticalBottomText = "I"; verticalTopText = "S"; verticalAxisRGBA = coronalRGBA; verticalAxisPosStartXYZ[2] += gapMM; verticalAxisPosEndXYZ[2] += bigValue; verticalAxisNegStartXYZ[2] -= gapMM; verticalAxisNegEndXYZ[2] -= bigValue; break; } /* * Offset text labels be a percentage of viewort width/height */ GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); const int textOffsetX = viewport[2] * 0.01f; const int textOffsetY = viewport[3] * 0.01f; const int textLeftWindowXY[2] = { textOffsetX, (viewport[3] / 2) }; const int textRightWindowXY[2] = { viewport[2] - textOffsetX, (viewport[3] / 2) }; const int textBottomWindowXY[2] = { viewport[2] / 2, textOffsetY }; const int textTopWindowXY[2] = { (viewport[2] / 2), viewport[3] - textOffsetY }; /* * Crosshairs */ if (drawCrosshairsFlag) { std::unique_ptr xhairPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); xhairPrimitive->addVertex(&horizontalAxisPosStartXYZ[0], horizontalAxisRGBA); xhairPrimitive->addVertex(&horizontalAxisPosEndXYZ[0], horizontalAxisRGBA); xhairPrimitive->addVertex(&horizontalAxisNegStartXYZ[0], horizontalAxisRGBA); xhairPrimitive->addVertex(&horizontalAxisNegEndXYZ[0], horizontalAxisRGBA); xhairPrimitive->addVertex(&verticalAxisPosStartXYZ[0], verticalAxisRGBA); xhairPrimitive->addVertex(&verticalAxisPosEndXYZ[0], verticalAxisRGBA); xhairPrimitive->addVertex(&verticalAxisNegStartXYZ[0], verticalAxisRGBA); xhairPrimitive->addVertex(&verticalAxisNegEndXYZ[0], verticalAxisRGBA); xhairPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); GraphicsEngineDataOpenGL::draw(xhairPrimitive.get()); } if (drawCrosshairLabelsFlag) { uint8_t backgroundRGBA[4] = { m_fixedPipelineDrawing->m_backgroundColorByte[0], m_fixedPipelineDrawing->m_backgroundColorByte[1], m_fixedPipelineDrawing->m_backgroundColorByte[2], m_fixedPipelineDrawing->m_backgroundColorByte[3] }; AnnotationPercentSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); annotationText.setBoldStyleEnabled(true); annotationText.setFontPercentViewportSize(5.0f); annotationText.setBackgroundColor(CaretColorEnum::CUSTOM); annotationText.setTextColor(CaretColorEnum::CUSTOM); annotationText.setCustomTextColor(horizontalAxisRGBA); annotationText.setCustomBackgroundColor(backgroundRGBA); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); annotationText.setText(horizontalLeftText); m_fixedPipelineDrawing->drawTextAtViewportCoords(textLeftWindowXY[0], textLeftWindowXY[1], annotationText); annotationText.setText(horizontalRightText); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); m_fixedPipelineDrawing->drawTextAtViewportCoords(textRightWindowXY[0], textRightWindowXY[1], annotationText); annotationText.setCustomTextColor(verticalAxisRGBA); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); annotationText.setText(verticalBottomText); m_fixedPipelineDrawing->drawTextAtViewportCoords(textBottomWindowXY[0], textBottomWindowXY[1], annotationText); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); annotationText.setText(verticalTopText); m_fixedPipelineDrawing->drawTextAtViewportCoords(textTopWindowXY[0], textTopWindowXY[1], annotationText); } if (depthEnabled) { glEnable(GL_DEPTH_TEST); } } /** * Get the RGBA coloring for a slice view plane. * * @param sliceViewPlane * The slice view plane. * @param rgbaOut * Output colors ranging 0.0 to 1.0 */ void BrainOpenGLVolumeSliceDrawing::getAxesColor(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, float rgbaOut[4]) const { switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: rgbaOut[0] = 0.0; rgbaOut[1] = 0.0; rgbaOut[2] = 1.0; rgbaOut[3] = 1.0; break; case VolumeSliceViewPlaneEnum::CORONAL: rgbaOut[0] = 0.0; rgbaOut[1] = 1.0; rgbaOut[2] = 0.0; rgbaOut[3] = 1.0; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: rgbaOut[0] = 1.0; rgbaOut[1] = 0.0; rgbaOut[2] = 0.0; rgbaOut[3] = 1.0; break; } } /** * Draw a one millimeter square facing the user. * NOTE: This method will alter the current * modelviewing matrices so caller may need * to enclose the call to this method within * glPushMatrix() and glPopMatrix(). * * @param size * Size of square. */ void BrainOpenGLVolumeSliceDrawing::drawSquare(const float size) { const float length = size * 0.5; /* * Draw both front and back side since in some instances, * such as surface montage, we are viweing from the far * side (from back of monitor) */ glBegin(GL_QUADS); glNormal3f(0.0, 0.0, 1.0); glVertex3f(-length, -length, 0.0); glVertex3f( length, -length, 0.0); glVertex3f( length, length, 0.0); glVertex3f(-length, length, 0.0); glNormal3f(0.0, 0.0, -1.0); glVertex3f(-length, -length, 0.0); glVertex3f(-length, length, 0.0); glVertex3f( length, length, 0.0); glVertex3f( length, -length, 0.0); glEnd(); } /** * Get the minimum and maximum distance between adjacent voxels in all * slices planes. Output spacing value are always non-negative even if * a right-to-left orientation. * * @param volume * Volume for which min/max spacing is requested. * @param minSpacingOut * Output minimum spacing. * @param maxSpacingOut * Output maximum spacing. * @return * True if min and max spacing are greater than zero. */ bool BrainOpenGLVolumeSliceDrawing::getMinMaxVoxelSpacing(const VolumeMappableInterface* volume, float& minSpacingOut, float& maxSpacingOut) const { CaretAssert(volume); float originX, originY, originZ; float x1, y1, z1; volume->indexToSpace(0, 0, 0, originX, originY, originZ); volume->indexToSpace(1, 1, 1, x1, y1, z1); const float dx = std::fabs(x1 - originX); const float dy = std::fabs(y1 - originY); const float dz = std::fabs(z1 - originZ); minSpacingOut = std::min(std::min(dx, dy), dz); maxSpacingOut = std::max(std::max(dx, dy), dz); if ((minSpacingOut > 0.0) && (maxSpacingOut > 0.0)) { return true; } return false; } /** * Set the orthographic projection. * * @param allSliceViewMode * Indicates drawing of ALL slices volume view (axial, coronal, parasagittal in one view) * @param sliceViewPlane * View plane that is displayed. * @param boundingBox * Bounding box for all volume. * @param viewport * The viewport. * @param orthographicBoundsOut * Output containing the orthographic bounds used for orthographic projection. */ void BrainOpenGLVolumeSliceDrawing::setOrthographicProjection(const AllSliceViewMode allSliceViewMode, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const BoundingBox& boundingBox, const float zoomFactor, const int viewport[4], double orthographicBoundsOut[6]) { /* * Set top and bottom to the min/max coordinate * that runs vertically on the screen */ double modelTop = 200.0; double modelBottom = -200.0; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssertMessage(0, "Should never get here"); break; case VolumeSliceViewPlaneEnum::AXIAL: modelTop = boundingBox.getMaxY(); modelBottom = boundingBox.getMinY(); break; case VolumeSliceViewPlaneEnum::CORONAL: modelTop = boundingBox.getMaxZ(); modelBottom = boundingBox.getMinZ(); break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: modelTop = boundingBox.getMaxZ(); modelBottom = boundingBox.getMinZ(); break; } /* * WB-677 The zoom of axial, coronal, and sagittal views is not the same */ switch (allSliceViewMode) { case AllSliceViewMode::ALL_YES: { /* * Parasagittal and Coronal Views have Brain's Z-axis in Screen Y * Axial View has Brain's Y-axis in Screen Y * So, use maximum of Brain's Y- and Z-axes for sizing height of slice * so that voxels are same size for each slice in each axis view */ const float maxRangeYZ = std::max(boundingBox.getDifferenceY(), boundingBox.getDifferenceZ()); const double halfHeight = maxRangeYZ / 2.0; const double middle = (modelBottom + modelTop) / 2.0; modelTop = middle + halfHeight; modelBottom = middle - halfHeight; } break; case AllSliceViewMode::ALL_NO: break; } /* * Scale ratio makes region slightly larger than model */ const double zoom = zoomFactor; double scaleRatio = (1.0 / 0.98); if (zoom > 0.0) { scaleRatio /= zoom; } modelTop *= scaleRatio; modelBottom *= scaleRatio; /* * Determine aspect ratio of viewport */ const double viewportWidth = viewport[2]; const double viewportHeight = viewport[3]; const double aspectRatio = (viewportWidth / viewportHeight); /* * Set bounds of orthographic projection */ const double halfModelY = ((modelTop - modelBottom) / 2.0); const double orthoBottom = -halfModelY; const double orthoTop = halfModelY; const double orthoLeft = -halfModelY * aspectRatio; const double orthoRight = halfModelY * aspectRatio; const double nearDepth = -1000.0; const double farDepth = 1000.0; orthographicBoundsOut[0] = orthoLeft; orthographicBoundsOut[1] = orthoRight; orthographicBoundsOut[2] = orthoBottom; orthographicBoundsOut[3] = orthoTop; orthographicBoundsOut[4] = nearDepth; orthographicBoundsOut[5] = farDepth; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(orthographicBoundsOut[0], orthographicBoundsOut[1], orthographicBoundsOut[2], orthographicBoundsOut[3], orthographicBoundsOut[4], orthographicBoundsOut[5]); glMatrixMode(GL_MODELVIEW); } /** * Set the orthographic projection. * * @param allSliceViewMode * Indicates drawing of ALL slices volume view (axial, coronal, parasagittal in one view) * @param sliceViewPlane * View plane that is displayed. * @param viewport * The viewport. */ void BrainOpenGLVolumeSliceDrawing::setOrthographicProjection(const AllSliceViewMode allSliceViewMode, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const int viewport[4]) { /* * Determine model size in screen Y when viewed */ BoundingBox boundingBox; m_volumeDrawInfo[0].volumeFile->getVoxelSpaceBoundingBox(boundingBox); const float zoomFactor = 1.0f; setOrthographicProjection(allSliceViewMode, sliceViewPlane, boundingBox, zoomFactor, viewport, m_orthographicBounds); } /** * Draw the voxels in an orthogonal slice. * * @param sliceNormalVector * Normal vector of the slice plane. * @param coordinate * Coordinate of first voxel in the slice (bottom left as begin viewed) * @param rowStep * Three-dimensional step to next row. * @param columnStep * Three-dimensional step to next column. * @param numberOfColumns * Number of columns in the slice. * @param numberOfRows * Number of rows in the slice. * @param sliceRGBA * RGBA coloring for voxels in the slice. * @param validVoxelCount * Number of voxels with valid coloring * @param volumeInterface * Index of the volume being drawn. * @param volumeIndex * Selected map in the volume being drawn. * @param mapIndex * Selected map in the volume being drawn. * @param sliceOpacity * Opacity from the overlay. */ void BrainOpenGLVolumeSliceDrawing::drawOrthogonalSliceVoxels(const float sliceNormalVector[3], const float coordinate[3], const float rowStep[3], const float columnStep[3], const int64_t numberOfColumns, const int64_t numberOfRows, const std::vector& sliceRGBA, const int64_t validVoxelCount, const VolumeMappableInterface* volumeInterface, const int32_t volumeIndex, const int32_t mapIndex, const uint8_t sliceOpacity) { if (validVoxelCount <= 0) { if (m_identificationModeFlag) { /* voxels are always drawn in identification mode */ } else { return; } } /* * There are two ways to draw the voxels. * * Quad Indices: This method submits each vertex (coordinate, normal, rgba) * one time BUT it submits EVERY vertex in the slice. Note that the vertex * is shared by four voxels (except along an edge). For each valid voxel, * it submits the indices of the voxel's four vertices. This method is * efficient when many voxels are drawn since each vertex is submitted to * OpenGL one time and is shared by up to four voxels. However, when * only a few voxels are drawn, many unused vertices are submitted. * * Single Quads: For each voxel, this method submits the four vertices * (coordinate, normal, rgba) for each voxel drawn. Even though adjacent * voxels share vertices, the vertices are submitted for each voxel. When * only a small number of voxels in the slice are drawn, this method is * efficient since only the needed vertex data is submitted. However, * when many voxels are drawn, many vertices are duplicated making the * drawing inefficient. * * So, estimate the bytes that are passed to OpenGL for each drawing * mode and choose the drawing mode that requires the smallest number * of bytes. */ /* * Each vertex requires 28 bytes * (3 float xyz, 3 float normal xyz + 4 bytes color). * * Single quads uses four vertices per quad. * * Index quads requires four 4-byte ints for the quad's indices. */ const int64_t bytesPerVertex = 28; const int64_t totalVertexBytes = ((numberOfColumns + 1) * (numberOfRows + 1) * bytesPerVertex); const int64_t numberOfVoxels = numberOfColumns * numberOfRows; const int64_t singleQuadBytes = (numberOfVoxels * bytesPerVertex * 4); const int64_t indexQuadBytes = (totalVertexBytes + (16 * numberOfVoxels)); bool drawWithQuadIndicesFlag = false; if (indexQuadBytes < singleQuadBytes) { drawWithQuadIndicesFlag = true; } GLboolean blendOn = GL_FALSE; glGetBooleanv(GL_BLEND, &blendOn); if (drawWithQuadIndicesFlag) { drawOrthogonalSliceVoxelsQuadIndicesAndStrips(sliceNormalVector, coordinate, rowStep, columnStep, numberOfColumns, numberOfRows, sliceRGBA, volumeInterface, volumeIndex, mapIndex, sliceOpacity); } else { drawOrthogonalSliceVoxelsSingleQuads(sliceNormalVector, coordinate, rowStep, columnStep, numberOfColumns, numberOfRows, sliceRGBA, volumeInterface, volumeIndex, mapIndex, sliceOpacity); } glGetBooleanv(GL_BLEND, &blendOn); } /** * Draw the voxels in an orthogonal slice with single quads. * * Four coordinates, normals, and colors are sent to OpenGL for each * quad that is drawn. This may be efficent when only a few voxels * are drawn but very inefficient when many voxels are drawn. * * @param sliceNormalVector * Normal vector of the slice plane. * @param coordinate * Coordinate of first voxel in the slice (bottom left as begin viewed) * @param rowStep * Three-dimensional step to next row. * @param columnStep * Three-dimensional step to next column. * @param numberOfColumns * Number of columns in the slice. * @param numberOfRows * Number of rows in the slice. * @param sliceRGBA * RGBA coloring for voxels in the slice. * @param volumeInterface * Index of the volume being drawn. * @param volumeIndex * Selected map in the volume being drawn. * @param mapIndex * Selected map in the volume being drawn. * @param sliceOpacity * Opacity from the overlay. */ void BrainOpenGLVolumeSliceDrawing::drawOrthogonalSliceVoxelsSingleQuads(const float sliceNormalVector[3], const float coordinate[3], const float rowStep[3], const float columnStep[3], const int64_t numberOfColumns, const int64_t numberOfRows, const std::vector& sliceRGBA, const VolumeMappableInterface* volumeInterface, const int32_t volumeIndex, const int32_t mapIndex, const uint8_t sliceOpacity) { /* * When performing voxel identification for editing voxels, * we need to draw EVERY voxel since the user may click * regions where the voxels are "off". */ bool volumeEditingDrawAllVoxelsFlag = false; if (m_identificationModeFlag) { SelectionItemVoxelEditing* voxelEditID = m_brain->getSelectionManager()->getVoxelEditingIdentification(); if (voxelEditID->isEnabledForSelection()) { const VolumeFile* vf = dynamic_cast(volumeInterface); if (vf == voxelEditID->getVolumeFileForEditing()) { volumeEditingDrawAllVoxelsFlag = true; } } } const int64_t numVoxelsInSlice = numberOfColumns * numberOfRows; /* * Allocate for quadrilateral drawing */ const int64_t numQuadCoords = numVoxelsInSlice * 12; const int64_t numQuadRgba = numVoxelsInSlice * 16; std::vector voxelQuadCoordinates; std::vector voxelQuadNormals; std::vector voxelQuadRgba; voxelQuadCoordinates.reserve(numQuadCoords); voxelQuadNormals.reserve(numQuadCoords); voxelQuadRgba.reserve(numQuadRgba); /* * Step to next row or column voxel */ const float rowStepX = rowStep[0]; const float rowStepY = rowStep[1]; const float rowStepZ = rowStep[2]; const float columnStepX = columnStep[0]; const float columnStepY = columnStep[1]; const float columnStepZ = columnStep[2]; /* * Draw each row */ for (int64_t jRow = 0; jRow < numberOfRows; jRow++) { /* * Coordinates on left side of row */ float rowBottomLeft[3] = { coordinate[0] + (jRow * rowStepX), coordinate[1] + (jRow * rowStepY), coordinate[2] + (jRow * rowStepZ) }; float rowTopLeft[3] = { rowBottomLeft[0] + rowStepX, rowBottomLeft[1] + rowStepY, rowBottomLeft[2] + rowStepZ }; /* * Draw each voxel in its column */ for (int64_t iCol = 0; iCol < numberOfColumns; iCol++) { /* * Offset of voxel in coloring. */ const int64_t sliceRgbaOffset = (4 * (iCol + (numberOfColumns * jRow))); const int64_t alphaOffset = sliceRgbaOffset + 3; uint8_t rgba[4] = { 0, 0, 0, 0 }; /* * Negative alpha means do not display */ CaretAssertVectorIndex(sliceRGBA, alphaOffset); if (sliceRGBA[alphaOffset] <= 0) { if (volumeIndex == 0) { /* * For first drawn volume, use an alpha of 255 so * so that black is drawn */ rgba[3] = 255; /* * OVERRIDES BLACK VOXEL ABOVE (255) * For first drawn volume, use an alpha of zero so * that the background shows through */ rgba[3] = 0; } } else { /* * Use overlay's opacity */ rgba[0] = sliceRGBA[sliceRgbaOffset]; rgba[1] = sliceRGBA[sliceRgbaOffset + 1]; rgba[2] = sliceRGBA[sliceRgbaOffset + 2]; rgba[3] = sliceOpacity; } /* * Set coordinates of voxel corners */ float voxelBottomLeft[3] = { rowBottomLeft[0] + (iCol * columnStepX), rowBottomLeft[1] + (iCol * columnStepY), rowBottomLeft[2] + (iCol * columnStepZ) }; float voxelBottomRight[3] = { voxelBottomLeft[0] + columnStepX, voxelBottomLeft[1] + columnStepY, voxelBottomLeft[2] + columnStepZ }; float voxelTopLeft[3] = { rowTopLeft[0] + (iCol * columnStepX), rowTopLeft[1] + (iCol * columnStepY), rowTopLeft[2] + (iCol * columnStepZ) }; float voxelTopRight[3] = { voxelTopLeft[0] + columnStepX, voxelTopLeft[1] + columnStepY, voxelTopLeft[2] + columnStepZ }; /* * Need to draw ALL voxels if performing * identificaiton for voxel editing. */ if (volumeEditingDrawAllVoxelsFlag) { rgba[3] = 255; } /* * Draw voxel based upon opacity */ if (rgba[3] > 0) { if (m_identificationModeFlag) { /* * Add info about voxel for identication. */ int64_t voxelI = 0; int64_t voxelJ = 0; int64_t voxelK = 0; const float voxelCenterX = (voxelBottomLeft[0] + voxelTopRight[0]) / 2.0; const float voxelCenterY = (voxelBottomLeft[1] + voxelTopRight[1]) / 2.0; const float voxelCenterZ = (voxelBottomLeft[2] + voxelTopRight[2]) / 2.0; volumeInterface->enclosingVoxel(voxelCenterX, voxelCenterY, voxelCenterZ, voxelI, voxelJ, voxelK); const float voxelDiffXYZ[3] = { voxelTopRight[0] - voxelBottomLeft[0], voxelTopRight[1] - voxelBottomLeft[1], voxelTopRight[2] - voxelBottomLeft[2], }; addVoxelToIdentification(volumeIndex, mapIndex, voxelI, voxelJ, voxelK, voxelDiffXYZ, rgba); } /* * Add voxel to quadrilaterals */ voxelQuadCoordinates.push_back(voxelBottomLeft[0]); voxelQuadCoordinates.push_back(voxelBottomLeft[1]); voxelQuadCoordinates.push_back(voxelBottomLeft[2]); voxelQuadCoordinates.push_back(voxelBottomRight[0]); voxelQuadCoordinates.push_back(voxelBottomRight[1]); voxelQuadCoordinates.push_back(voxelBottomRight[2]); voxelQuadCoordinates.push_back(voxelTopRight[0]); voxelQuadCoordinates.push_back(voxelTopRight[1]); voxelQuadCoordinates.push_back(voxelTopRight[2]); voxelQuadCoordinates.push_back(voxelTopLeft[0]); voxelQuadCoordinates.push_back(voxelTopLeft[1]); voxelQuadCoordinates.push_back(voxelTopLeft[2]); for (int32_t iNormalAndColor = 0; iNormalAndColor < 4; iNormalAndColor++) { voxelQuadRgba.push_back(rgba[0]); voxelQuadRgba.push_back(rgba[1]); voxelQuadRgba.push_back(rgba[2]); voxelQuadRgba.push_back(rgba[3]); voxelQuadNormals.push_back(sliceNormalVector[0]); voxelQuadNormals.push_back(sliceNormalVector[1]); voxelQuadNormals.push_back(sliceNormalVector[2]); } } } } /* * Draw the voxels. */ if (voxelQuadCoordinates.empty() == false) { BrainOpenGLPrimitiveDrawing::drawQuads(voxelQuadCoordinates, voxelQuadNormals, voxelQuadRgba); } } /** * Draw the voxels in an orthogonal slice using quad indices or strips. * * Each vertex (coordinate, its normal vector, and its color) is sent to OpenGL * one time. Index arrays are used to specify the vertices when drawing the * quads. * * This is efficient when many voxels are drawn but may be inefficent * when only a few voxels are drawn. * * @param sliceNormalVector * Normal vector of the slice plane. * @param firstVoxelCoordinate * Coordinate of first voxel in the slice (bottom left as begin viewed) * @param rowStep * Three-dimensional step to next row. * @param columnStep * Three-dimensional step to next column. * @param numberOfColumns * Number of columns in the slice. * @param numberOfRows * Number of rows in the slice. * @param sliceRGBA * RGBA coloring for voxels in the slice. * @param volumeInterface * Index of the volume being drawn. * @param volumeIndex * Selected map in the volume being drawn. * @param mapIndex * Selected map in the volume being drawn. * @param sliceOpacity * Opacity from the overlay. */ void BrainOpenGLVolumeSliceDrawing::drawOrthogonalSliceVoxelsQuadIndicesAndStrips(const float sliceNormalVector[3], const float firstVoxelCoordinate[3], const float rowStep[3], const float columnStep[3], const int64_t numberOfColumns, const int64_t numberOfRows, const std::vector& sliceRGBA, const VolumeMappableInterface* volumeInterface, const int32_t volumeIndex, const int32_t mapIndex, const uint8_t sliceOpacity) { const bool debugFlag = false; enum DrawType { DRAW_QUADS, DRAW_QUAD_STRIPS }; const DrawType drawType = DRAW_QUADS; /* * When performing voxel identification for editing voxels, * we need to draw EVERY voxel since the user may click * regions where the voxels are "off". */ bool volumeEditingDrawAllVoxelsFlag = false; if (m_identificationModeFlag) { SelectionItemVoxelEditing* voxelEditID = m_brain->getSelectionManager()->getVoxelEditingIdentification(); if (voxelEditID->isEnabledForSelection()) { const VolumeFile* vf = dynamic_cast(volumeInterface); if (vf == voxelEditID->getVolumeFileForEditing()) { volumeEditingDrawAllVoxelsFlag = true; } } } /* * Allocate vectors for quadrilateral drawing */ const int64_t totalCoordElements = (numberOfColumns + 1) * (numberOfRows + 1); const int64_t numQuadStripCoords = totalCoordElements * 3; const int64_t numQuadStripRGBA = totalCoordElements * 4; std::vector voxelQuadCoordinates; std::vector voxelQuadNormals; std::vector voxelQuadRgba; voxelQuadCoordinates.reserve(numQuadStripCoords); voxelQuadNormals.reserve(numQuadStripCoords); voxelQuadRgba.reserve(numQuadStripRGBA); /* * Step to next row or column voxel */ const float rowStepX = rowStep[0]; const float rowStepY = rowStep[1]; const float rowStepZ = rowStep[2]; const float columnStepX = columnStep[0]; const float columnStepY = columnStep[1]; const float columnStepZ = columnStep[2]; const float voxelStepX = rowStepX + columnStepX; const float voxelStepY = rowStepY + columnStepY; const float voxelStepZ = rowStepZ + columnStepZ; const float voxelStepXYZ[3] = { voxelStepX, voxelStepY, voxelStepZ }; const float halfVoxelStepX = (voxelStepX / 2.0); const float halfVoxelStepY = (voxelStepY / 2.0); const float halfVoxelStepZ = (voxelStepZ / 2.0); int64_t numberOfVoxelsToDraw = 0; int64_t voxelJMin = 10000000; int64_t voxelJMax = -10000000; /* * Loop through column COORDINATES */ float columnBottomCoord[3] = { firstVoxelCoordinate[0], firstVoxelCoordinate[1], firstVoxelCoordinate[2] }; for (int64_t iCol = 0; iCol <= numberOfColumns; iCol++) { if (iCol > 0) { columnBottomCoord[0] += columnStepX; columnBottomCoord[1] += columnStepY; columnBottomCoord[2] += columnStepZ; } /* * Loop through the row COORDINATES */ float rowCoord[3] = { columnBottomCoord[0], columnBottomCoord[1], columnBottomCoord[2] }; for (int64_t jRow = 0; jRow <= numberOfRows; jRow++) { if (jRow > 0) { rowCoord[0] += rowStepX; rowCoord[1] += rowStepY; rowCoord[2] += rowStepZ; } voxelQuadCoordinates.push_back(rowCoord[0]); voxelQuadCoordinates.push_back(rowCoord[1]); voxelQuadCoordinates.push_back(rowCoord[2]); voxelQuadNormals.push_back(sliceNormalVector[0]); voxelQuadNormals.push_back(sliceNormalVector[1]); voxelQuadNormals.push_back(sliceNormalVector[2]); uint8_t rgba[4] = { 0, 0, 0, 0 }; /* * With FLAT shading: * Quads: Uses top left coordinate for quad coloring * Quad Strip: Uses top right coordinate for quad coloring * So, the color is only set for this coordinate */ int64_t iColRGBA = iCol; int64_t jRowRGBA = jRow; switch (drawType) { case DRAW_QUADS: if (iColRGBA >= numberOfColumns) { iColRGBA = numberOfColumns - 1; } jRowRGBA = jRow - 1; break; case DRAW_QUAD_STRIPS: iColRGBA = iCol - 1; jRowRGBA = jRow - 1; break; } if ((iColRGBA >= 0) && (jRowRGBA >= 0)) { const int64_t voxelOffset = (iColRGBA + (numberOfColumns * jRowRGBA)); if (debugFlag) { std::cout << "col=" << iCol << " row=" << jRow << " voxel-offset=" << voxelOffset << std::endl; } /* * Offset of voxel in coloring. * Note that colors are stored in rows */ int64_t sliceRgbaOffset = (4 * voxelOffset); /* * An alpha greater than zero means the voxel is displayed */ const int64_t alphaOffset = sliceRgbaOffset + 3; CaretAssertVectorIndex(sliceRGBA, alphaOffset); if (sliceRGBA[alphaOffset] > 0) { /* * Use overlay's opacity for the voxel */ rgba[0] = sliceRGBA[sliceRgbaOffset]; rgba[1] = sliceRGBA[sliceRgbaOffset + 1]; rgba[2] = sliceRGBA[sliceRgbaOffset + 2]; rgba[3] = sliceOpacity; } } /* * Voxel editing requires drawing of all voxels so that * "off" voxels can be turned "on". */ if (volumeEditingDrawAllVoxelsFlag) { rgba[3] = 255; } /* * Draw voxel if non-zero opacity */ if (rgba[3] > 0) { ++numberOfVoxelsToDraw; if (m_identificationModeFlag) { /* * Identification information is encoded in the * RGBA coloring. */ const float voxelCenterX = rowCoord[0] -rowStep[0] + halfVoxelStepX; const float voxelCenterY = rowCoord[1] -rowStep[1] + halfVoxelStepY; const float voxelCenterZ = rowCoord[2] -rowStep[2] + halfVoxelStepZ; int64_t voxelI = 0; int64_t voxelJ = 0; int64_t voxelK = 0; volumeInterface->enclosingVoxel(voxelCenterX, voxelCenterY, voxelCenterZ, voxelI, voxelJ, voxelK); voxelJMin = std::min(voxelJMin, voxelJ); voxelJMax = std::max(voxelJMax, voxelJ); addVoxelToIdentification(volumeIndex, mapIndex, voxelI, voxelJ, voxelK, voxelStepXYZ, rgba); } } voxelQuadRgba.push_back(rgba[0]); voxelQuadRgba.push_back(rgba[1]); voxelQuadRgba.push_back(rgba[2]); voxelQuadRgba.push_back(rgba[3]); } } const int64_t numberOfCoordinates = voxelQuadCoordinates.size() / 3; if (debugFlag) { std::cout << "Num rows/cols: " << numberOfRows << ", " << numberOfColumns << std::endl; std::cout << "Total, 3, 4 " << totalCoordElements << ", " << numQuadStripCoords << ", " << numQuadStripRGBA << std::endl; std::cout << "Size coords: " << voxelQuadCoordinates.size() << std::endl; std::cout << "Size normals: " << voxelQuadNormals.size() << std::endl; std::cout << "Size rgba: " << voxelQuadRgba.size() << std::endl; std::cout << "Valid voxels: " << numberOfVoxelsToDraw << std::endl; for (int64_t i = 0; i < numberOfCoordinates; i++) { std::cout << i << ": "; CaretAssertVectorIndex(voxelQuadCoordinates, i*3 + 2); std::cout << qPrintable(AString::fromNumbers(&voxelQuadCoordinates[i*3], 3, ",")) << " "; CaretAssertVectorIndex(voxelQuadRgba, i*4 + 3); std::cout << qPrintable(AString::fromNumbers(&voxelQuadRgba[i*4], 4, ",")) << std::endl; } } /* * Setup indices into coordinates/normals/coloring to draw the quads */ switch (drawType) { case DRAW_QUADS: { std::vector quadIndices; quadIndices.reserve(numberOfVoxelsToDraw * 4); for (int64_t iCol = 0; iCol < numberOfColumns; iCol++) { const int64_t columnOffset = (iCol * (numberOfRows + 1)); for (int64_t jRow = 0; jRow < numberOfRows; jRow++) { const int64_t coordBottomLeftIndex = columnOffset + jRow; //(iCol * (numberOfRows + 1) + jRow); const int64_t coordTopLeftIndex = coordBottomLeftIndex + 1; const int64_t rgbaIndex = coordTopLeftIndex * 4; CaretAssert(coordBottomLeftIndex < numberOfCoordinates); CaretAssert(coordTopLeftIndex < numberOfCoordinates); CaretAssertVectorIndex(voxelQuadRgba, rgbaIndex + 3); if (voxelQuadRgba[rgbaIndex + 3] > 0) { /* * For quads: (bottom left, bottom right, top right, top left) * Color with flat shading comes from the top left coordinate */ const int32_t coordBottomRightIndex = coordBottomLeftIndex + (numberOfRows + 1); const int32_t coordTopRightIndex = coordBottomRightIndex + 1; CaretAssert(coordBottomRightIndex < numberOfCoordinates); CaretAssert(coordTopRightIndex < numberOfCoordinates); quadIndices.push_back(coordBottomLeftIndex); quadIndices.push_back(coordBottomRightIndex); quadIndices.push_back(coordTopRightIndex); quadIndices.push_back(coordTopLeftIndex); } } if (debugFlag) { std::cout << "Quad Indices: " << quadIndices.size() << std::endl; for (uint32_t i = 0; i < quadIndices.size(); i++) { std::cout << quadIndices[i] << " ("; const int32_t coordOffset = quadIndices[i] * 3; CaretAssertVectorIndex(voxelQuadCoordinates, coordOffset + 2); std::cout << qPrintable(AString::fromNumbers(&voxelQuadCoordinates[coordOffset], 3, ",")) << ") ("; const int32_t rgbaOffset = quadIndices[i] * 4; CaretAssertVectorIndex(voxelQuadRgba, rgbaOffset + 3); std::cout << qPrintable(AString::fromNumbers(&voxelQuadRgba[rgbaOffset], 4, ",")) << " " << std::endl; } std::cout << std::endl; } } if (debugFlag) { std::cout << "Drawing " << quadIndices.size() / 4 << " quads." << std::endl; } BrainOpenGLPrimitiveDrawing::drawQuadIndices(voxelQuadCoordinates, voxelQuadNormals, voxelQuadRgba, quadIndices); } break; case DRAW_QUAD_STRIPS: { int64_t stripCount = 0; const int64_t maxCoordsPerStrip = numberOfRows * 2 + 2; for (int64_t iCol = 0; iCol < numberOfColumns; iCol++) { std::vector quadIndices; quadIndices.reserve(maxCoordsPerStrip); for (int64_t jRow = 0; jRow < numberOfRows; jRow++) { const int32_t coordBottomLeftIndex = (iCol * (numberOfRows + 1) + jRow); const int32_t coordTopLeftIndex = coordBottomLeftIndex + 1; const int32_t coordBottomRightIndex = coordBottomLeftIndex + (numberOfRows + 1); const int32_t coordTopRightIndex = coordBottomRightIndex + 1; const int64_t rgbaIndex = coordTopRightIndex * 4; CaretAssert(coordBottomLeftIndex < numberOfCoordinates); CaretAssert(coordTopLeftIndex < numberOfCoordinates); CaretAssert(coordBottomRightIndex < numberOfCoordinates); CaretAssert(coordTopRightIndex < numberOfCoordinates); CaretAssertVectorIndex(voxelQuadRgba, rgbaIndex + 3); if (voxelQuadRgba[rgbaIndex + 3] > 0) { /* * For quad strips (bottom left, bottom right, top left, top right) */ if (quadIndices.empty()) { quadIndices.push_back(coordBottomLeftIndex); quadIndices.push_back(coordBottomRightIndex); } quadIndices.push_back(coordTopLeftIndex); quadIndices.push_back(coordTopRightIndex); } else { if ( ! quadIndices.empty()) { if (debugFlag) { std::cout << "Quad Indices: " << quadIndices.size() << std::endl; for (uint32_t i = 0; i < quadIndices.size(); i++) { std::cout << quadIndices[i] << " ("; const int32_t coordOffset = quadIndices[i] * 3; CaretAssertVectorIndex(voxelQuadCoordinates, coordOffset + 2); std::cout << qPrintable(AString::fromNumbers(&voxelQuadCoordinates[coordOffset], 3, ",")) << ") ("; const int32_t rgbaOffset = quadIndices[i] * 4; CaretAssertVectorIndex(voxelQuadRgba, rgbaOffset + 3); std::cout << qPrintable(AString::fromNumbers(&voxelQuadRgba[rgbaOffset], 4, ",")) << " " << std::endl; } std::cout << std::endl; } BrainOpenGLPrimitiveDrawing::drawQuadStrips(voxelQuadCoordinates, voxelQuadNormals, voxelQuadRgba, quadIndices); quadIndices.clear(); stripCount++; } } } if ( ! quadIndices.empty()) { if (debugFlag) { std::cout << "Quad Indices: " << quadIndices.size() << std::endl; for (uint32_t i = 0; i < quadIndices.size(); i++) { std::cout << quadIndices[i] << " ("; const int32_t coordOffset = quadIndices[i] * 3; CaretAssertVectorIndex(voxelQuadCoordinates, coordOffset + 2); std::cout << qPrintable(AString::fromNumbers(&voxelQuadCoordinates[coordOffset], 3, ",")) << ") ("; const int32_t rgbaOffset = quadIndices[i] * 4; CaretAssertVectorIndex(voxelQuadRgba, rgbaOffset + 3); std::cout << qPrintable(AString::fromNumbers(&voxelQuadRgba[rgbaOffset], 4, ",")) << " " << std::endl; } std::cout << std::endl; } BrainOpenGLPrimitiveDrawing::drawQuadStrips(voxelQuadCoordinates, voxelQuadNormals, voxelQuadRgba, quadIndices); quadIndices.clear(); stripCount++; } } if (debugFlag) { std::cout << "Strips drawn: " << stripCount << std::endl; } } break; } } /** * Reset for volume identification. * * Clear identification indices and if identification is enabled, * reserve a reasonable amount of space for the indices. */ void BrainOpenGLVolumeSliceDrawing::resetIdentification() { m_identificationIndices.clear(); if (m_identificationModeFlag) { int64_t estimatedNumberOfItems = 0; std::vector volumeDims; m_volumeDrawInfo[0].volumeFile->getDimensions(volumeDims); if (volumeDims.size() >= 3) { const int64_t maxDim = std::max(volumeDims[0], std::max(volumeDims[1], volumeDims[2])); estimatedNumberOfItems = maxDim * maxDim * IDENTIFICATION_INDICES_PER_VOXEL; } m_identificationIndices.reserve(estimatedNumberOfItems); } } /** * Add a voxel to the identification indices. * * @param volumeIndex * Index of the volume. * @param mapIndex * Index of the volume map. * @param voxelI * Voxel Index I * @param voxelJ * Voxel Index J * @param voxelK * Voxel Index K * @param voxelDiffXYZ * Change in XYZ from voxel bottom left to top right * @param rgbaForColorIdentificationOut * Encoded identification in RGBA color OUTPUT */ void BrainOpenGLVolumeSliceDrawing::addVoxelToIdentification(const int32_t volumeIndex, const int32_t mapIndex, const int32_t voxelI, const int32_t voxelJ, const int32_t voxelK, const float voxelDiffXYZ[3], uint8_t rgbaForColorIdentificationOut[4]) { const int32_t idIndex = m_identificationIndices.size() / IDENTIFICATION_INDICES_PER_VOXEL; m_fixedPipelineDrawing->colorIdentification->addItem(rgbaForColorIdentificationOut, SelectionItemDataTypeEnum::VOXEL, idIndex); rgbaForColorIdentificationOut[3] = 255; /* * ID stack requires integers to * use an integer pointer to the float values */ CaretAssert(sizeof(float) == sizeof(int32_t)); const int32_t* intPointerDiffXYZ = (int32_t*)voxelDiffXYZ; /* * If these items change, need to update reset and * processing of identification. */ m_identificationIndices.push_back(volumeIndex); m_identificationIndices.push_back(mapIndex); m_identificationIndices.push_back(voxelI); m_identificationIndices.push_back(voxelJ); m_identificationIndices.push_back(voxelK); m_identificationIndices.push_back(intPointerDiffXYZ[0]); m_identificationIndices.push_back(intPointerDiffXYZ[1]); m_identificationIndices.push_back(intPointerDiffXYZ[2]); } /** * Process voxel identification. */ void BrainOpenGLVolumeSliceDrawing::processIdentification() { int32_t identifiedItemIndex; float depth = -1.0; m_fixedPipelineDrawing->getIndexFromColorSelection(SelectionItemDataTypeEnum::VOXEL, m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, identifiedItemIndex, depth); if (identifiedItemIndex >= 0) { const int32_t idIndex = identifiedItemIndex * IDENTIFICATION_INDICES_PER_VOXEL; const int32_t volDrawInfoIndex = m_identificationIndices[idIndex]; CaretAssertVectorIndex(m_volumeDrawInfo, volDrawInfoIndex); VolumeMappableInterface* vf = m_volumeDrawInfo[volDrawInfoIndex].volumeFile; const int64_t voxelIndices[3] = { m_identificationIndices[idIndex + 2], m_identificationIndices[idIndex + 3], m_identificationIndices[idIndex + 4] }; const float* floatDiffXYZ = (float*)&m_identificationIndices[idIndex + 5]; SelectionItemVoxel* voxelID = m_brain->getSelectionManager()->getVoxelIdentification(); if (voxelID->isEnabledForSelection()) { if (voxelID->isOtherScreenDepthCloserToViewer(depth)) { voxelID->setVoxelIdentification(m_brain, vf, voxelIndices, depth); float voxelCoordinates[3]; vf->indexToSpace(voxelIndices[0], voxelIndices[1], voxelIndices[2], voxelCoordinates[0], voxelCoordinates[1], voxelCoordinates[2]); m_fixedPipelineDrawing->setSelectedItemScreenXYZ(voxelID, voxelCoordinates); CaretLogFinest("Selected Voxel (3D): " + AString::fromNumbers(voxelIndices, 3, ",")); } } SelectionItemVoxelEditing* voxelEditID = m_brain->getSelectionManager()->getVoxelEditingIdentification(); if (voxelEditID->isEnabledForSelection()) { if (voxelEditID->getVolumeFileForEditing() == vf) { if (voxelEditID->isOtherScreenDepthCloserToViewer(depth)) { voxelEditID->setVoxelIdentification(m_brain, vf, voxelIndices, depth); voxelEditID->setVoxelDiffXYZ(floatDiffXYZ); float voxelCoordinates[3]; vf->indexToSpace(voxelIndices[0], voxelIndices[1], voxelIndices[2], voxelCoordinates[0], voxelCoordinates[1], voxelCoordinates[2]); m_fixedPipelineDrawing->setSelectedItemScreenXYZ(voxelEditID, voxelCoordinates); CaretLogFinest("Selected Voxel Editing (3D): Indices (" + AString::fromNumbers(voxelIndices, 3, ",") + ") Diff XYZ (" + AString::fromNumbers(floatDiffXYZ, 3, ",") + ")"); } } } } } /** * Get the maximum bounds that enclose the volumes and the minimum * voxel spacing from the volumes. * * @param boundsOut * Bounds of the volumes. * @param spacingOut * Minimum voxel spacing from the volumes. Always positive values (even if * volumes is oriented right to left). * */ bool BrainOpenGLVolumeSliceDrawing::getVoxelCoordinateBoundsAndSpacing(float boundsOut[6], float spacingOut[3]) { const int32_t numberOfVolumesToDraw = static_cast(m_volumeDrawInfo.size()); if (numberOfVolumesToDraw <= 0) { return false; } /* * Find maximum extent of all voxels and smallest voxel * size in each dimension. */ float minVoxelX = std::numeric_limits::max(); float maxVoxelX = -std::numeric_limits::max(); float minVoxelY = std::numeric_limits::max(); float maxVoxelY = -std::numeric_limits::max(); float minVoxelZ = std::numeric_limits::max(); float maxVoxelZ = -std::numeric_limits::max(); float voxelStepX = std::numeric_limits::max(); float voxelStepY = std::numeric_limits::max(); float voxelStepZ = std::numeric_limits::max(); for (int32_t i = 0; i < numberOfVolumesToDraw; i++) { const VolumeMappableInterface* volumeFile = m_volumeDrawInfo[i].volumeFile; int64_t dimI, dimJ, dimK, numMaps, numComponents; volumeFile->getDimensions(dimI, dimJ, dimK, numMaps, numComponents); float originX, originY, originZ; float x1, y1, z1; float lastX, lastY, lastZ; volumeFile->indexToSpace(0, 0, 0, originX, originY, originZ); volumeFile->indexToSpace(1, 1, 1, x1, y1, z1); volumeFile->indexToSpace(dimI - 1, dimJ - 1, dimK - 1, lastX, lastY, lastZ); const float dx = x1 - originX; const float dy = y1 - originY; const float dz = z1 - originZ; voxelStepX = std::min(voxelStepX, std::fabs(dx)); voxelStepY = std::min(voxelStepY, std::fabs(dy)); voxelStepZ = std::min(voxelStepZ, std::fabs(dz)); minVoxelX = std::min(minVoxelX, std::min(originX, lastX)); maxVoxelX = std::max(maxVoxelX, std::max(originX, lastX)); minVoxelY = std::min(minVoxelY, std::min(originY, lastY)); maxVoxelY = std::max(maxVoxelY, std::max(originY, lastY)); minVoxelZ = std::min(minVoxelZ, std::min(originZ, lastZ)); maxVoxelZ = std::max(maxVoxelZ, std::max(originZ, lastZ)); } boundsOut[0] = minVoxelX; boundsOut[1] = maxVoxelX; boundsOut[2] = minVoxelY; boundsOut[3] = maxVoxelY; boundsOut[4] = minVoxelZ; boundsOut[5] = maxVoxelZ; spacingOut[0] = voxelStepX; spacingOut[1] = voxelStepY; spacingOut[2] = voxelStepZ; bool valid = false; if ((maxVoxelX > minVoxelX) && (maxVoxelY > minVoxelY) && (maxVoxelZ > minVoxelZ) && (voxelStepX > 0.0) && (voxelStepY > 0.0) && (voxelStepZ > 0.0)) { valid = true; } return valid; } /** * Find portion (or all) of slice that fits inside the graphics window. * * @param sliceViewPlane * The orthogonal plane being viewed. * @param selectedSliceCoordinate * Coordinate of the slice being drawn. * @param volumeFile * Volume file that is to be drawn. * @param culledFirstVoxelIJKOut * First (bottom left) voxel that will be drawn for the volume file. * @param culledLastVoxelIJKOut * Last (top right) voxel that will be drawn for the volume file. * @param voxelDeltaXYZOut * Voxel sizes for the volume file. The element corresponding to the * slice plane being drawn will be zero (axial => [2]=0) */ bool BrainOpenGLVolumeSliceDrawing::getVolumeDrawingViewDependentCulling(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float selectedSliceCoordinate, const VolumeMappableInterface* volumeFile, int64_t culledFirstVoxelIJKOut[3], int64_t culledLastVoxelIJKOut[3], float voxelDeltaXYZOut[3]) { GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); GLdouble projectionMatrix[16]; glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix); GLdouble modelMatrix[16]; glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix); const double vpMinX = viewport[0]; const double vpMaxX = viewport[0] + viewport[2]; const double vpMinY = viewport[1]; const double vpMaxY = viewport[1] + viewport[3]; GLdouble bottomLeftWin[3] = { vpMinX, vpMinY, 0.0 }; GLdouble bottomRightWin[3] = { vpMaxX, vpMinY, 0.0 }; GLdouble topRightWin[3] = { vpMaxX, vpMaxY, 0.0 }; GLdouble topLeftWin[3] = { vpMinX, vpMaxY, 0.0 }; GLdouble bottomLeftCoord[3]; int32_t cornersValidCount = 0; if (gluUnProject(bottomLeftWin[0], bottomLeftWin[1], bottomLeftWin[2], modelMatrix, projectionMatrix, viewport, &bottomLeftCoord[0], &bottomLeftCoord[1], &bottomLeftCoord[2])) { cornersValidCount++; } GLdouble bottomRightCoord[3]; if (gluUnProject(bottomRightWin[0], bottomRightWin[1], bottomRightWin[2], modelMatrix, projectionMatrix, viewport, &bottomRightCoord[0], &bottomRightCoord[1], &bottomRightCoord[2])) { cornersValidCount++; } GLdouble topRightCoord[3]; if (gluUnProject(topRightWin[0], topRightWin[1], topRightWin[2], modelMatrix, projectionMatrix, viewport, &topRightCoord[0], &topRightCoord[1], &topRightCoord[2])) { cornersValidCount++; } GLdouble topLeftCoord[3]; if (gluUnProject(topLeftWin[0], topLeftWin[1], topLeftWin[2], modelMatrix, projectionMatrix, viewport, &topLeftCoord[0], &topLeftCoord[1], &topLeftCoord[2])) { cornersValidCount++; } if (cornersValidCount != 4) { return false; } /* * Limit the corner coordinates to the volume's bounding box */ BoundingBox boundingBox; volumeFile->getVoxelSpaceBoundingBox(boundingBox); { float spaceX, spaceY, spaceZ; volumeFile->getVoxelSpacing(spaceX, spaceY, spaceZ); const float halfX = std::fabs(spaceX / 2.0); const float halfY = std::fabs(spaceY / 2.0); const float halfZ = std::fabs(spaceZ / 2.0); switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: { const float maxZ = boundingBox.getMaxZ() + halfZ; const float minZ = boundingBox.getMinZ() - halfZ; if ((selectedSliceCoordinate < minZ) || (selectedSliceCoordinate > maxZ)) { return false; } } break; case VolumeSliceViewPlaneEnum::CORONAL: { const float maxY = boundingBox.getMaxY() + halfY; const float minY = boundingBox.getMinY() - halfY; if ((selectedSliceCoordinate < minY) || (selectedSliceCoordinate > maxY)) { return false; } } break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: { const float maxX = boundingBox.getMaxX() + halfX; const float minX = boundingBox.getMinX() - halfX; if ((selectedSliceCoordinate < minX) || (selectedSliceCoordinate > maxX)) { return false; } } break; } } /* * Limit the corner coordinates to the volume's bounding box */ boundingBox.limitCoordinateToBoundingBox(bottomLeftCoord); boundingBox.limitCoordinateToBoundingBox(bottomRightCoord); boundingBox.limitCoordinateToBoundingBox(topRightCoord); boundingBox.limitCoordinateToBoundingBox(topLeftCoord); /* * The unproject functions will return the "in plane" coordinate (Z in axial view) * that is not correct for the slice being viewed. So, override the * Z-coordinate with the coordinate of the current slice plane. * * This must be done AFTER limiting coordinates to the volume's bounding box. * Otherwise, the culled voxels will always be the first or last slice when * the slice coordinate is NOT within the volume file. */ switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: bottomLeftCoord[2] = selectedSliceCoordinate; bottomRightCoord[2] = selectedSliceCoordinate; topRightCoord[2] = selectedSliceCoordinate; topLeftCoord[2] = selectedSliceCoordinate; break; case VolumeSliceViewPlaneEnum::CORONAL: bottomLeftCoord[1] = selectedSliceCoordinate; bottomRightCoord[1] = selectedSliceCoordinate; topRightCoord[1] = selectedSliceCoordinate; topLeftCoord[1] = selectedSliceCoordinate; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: bottomLeftCoord[0] = selectedSliceCoordinate; bottomRightCoord[0] = selectedSliceCoordinate; topRightCoord[0] = selectedSliceCoordinate; topLeftCoord[0] = selectedSliceCoordinate; break; } /* * Note: Spacing may be negative for some orientations * and positive may be on left or bottom */ float voxelDeltaX, voxelDeltaY, voxelDeltaZ; volumeFile->getVoxelSpacing(voxelDeltaX, voxelDeltaY, voxelDeltaZ); voxelDeltaX = std::fabs(voxelDeltaX); voxelDeltaY = std::fabs(voxelDeltaY); voxelDeltaZ = std::fabs(voxelDeltaZ); if (bottomLeftCoord[0] > topRightCoord[0]) { voxelDeltaX = -voxelDeltaX; } if (bottomLeftCoord[1] > topRightCoord[1]) { voxelDeltaY = -voxelDeltaY; } if (bottomLeftCoord[2] > topRightCoord[2]) { voxelDeltaZ = -voxelDeltaZ; } bool adjustX = false; bool adjustY = false; bool adjustZ = false; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: adjustX = true; adjustY = true; voxelDeltaZ = 0.0; break; case VolumeSliceViewPlaneEnum::CORONAL: adjustX = true; adjustZ = true; voxelDeltaY = 0.0; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: adjustY = true; adjustZ = true; voxelDeltaX = 0.0; break; } /* * Adjust by one voxel to ensure full coverage */ if (adjustX) { bottomLeftCoord[0] -= voxelDeltaX; topRightCoord[0] += voxelDeltaX; } if (adjustY) { bottomLeftCoord[1] -= voxelDeltaY; topRightCoord[1] += voxelDeltaY; } if (adjustZ) { bottomLeftCoord[2] -= voxelDeltaZ; topRightCoord[2] += voxelDeltaZ; } int64_t bottomLeftIJK[3]; volumeFile->enclosingVoxel(bottomLeftCoord[0], bottomLeftCoord[1], bottomLeftCoord[2], bottomLeftIJK[0], bottomLeftIJK[1], bottomLeftIJK[2]); int64_t topRightIJK[3]; volumeFile->enclosingVoxel(topRightCoord[0], topRightCoord[1], topRightCoord[2], topRightIJK[0], topRightIJK[1], topRightIJK[2]); volumeFile->limitIndicesToValidIndices(bottomLeftIJK[0], bottomLeftIJK[1], bottomLeftIJK[2]); volumeFile->limitIndicesToValidIndices(topRightIJK[0], topRightIJK[1], topRightIJK[2]); culledFirstVoxelIJKOut[0] = bottomLeftIJK[0]; culledFirstVoxelIJKOut[1] = bottomLeftIJK[1]; culledFirstVoxelIJKOut[2] = bottomLeftIJK[2]; culledLastVoxelIJKOut[0] = topRightIJK[0]; culledLastVoxelIJKOut[1] = topRightIJK[1]; culledLastVoxelIJKOut[2] = topRightIJK[2]; voxelDeltaXYZOut[0] = voxelDeltaX; voxelDeltaXYZOut[1] = voxelDeltaY; voxelDeltaXYZOut[2] = voxelDeltaZ; return true; } /* ======================================================================= */ /** * Constructor * * @param volumeMappableInterface * Volume that contains the data values. * @param mapIndex * Index of selected map. */ BrainOpenGLVolumeSliceDrawing::VolumeSlice::VolumeSlice(VolumeMappableInterface* volumeMappableInterface, const int32_t mapIndex) { m_volumeMappableInterface = volumeMappableInterface; m_volumeFile = dynamic_cast(m_volumeMappableInterface); m_ciftiMappableDataFile = dynamic_cast(m_volumeMappableInterface); CaretAssert(m_volumeMappableInterface); m_mapIndex = mapIndex; CaretAssert(m_mapIndex >= 0); const int64_t sliceDim = 300; const int64_t numVoxels = sliceDim * sliceDim; m_values.reserve(numVoxels); } /** * Add a value and return its index. * * @param value * Value that is added. * @return * The index for the value. */ int64_t BrainOpenGLVolumeSliceDrawing::VolumeSlice::addValue(const float value) { const int64_t indx = static_cast(m_values.size()); m_values.push_back(value); return indx; } /** * Return RGBA colors for value using the value's index * returned by addValue(). * * @param indx * Index of the value. * @return * RGBA coloring for value. */ uint8_t* BrainOpenGLVolumeSliceDrawing::VolumeSlice::getRgbaForValueByIndex(const int64_t indx) { CaretAssertVectorIndex(m_rgba, indx * 4); return &m_rgba[indx*4]; } /** * Allocate colors for the voxel values */ void BrainOpenGLVolumeSliceDrawing::VolumeSlice::allocateColors() { m_rgba.resize(m_values.size() * 4); } /* ======================================================================= */ /** * Create a voxel for drawing. * * @param center * Center of voxel. * @param leftBottom * Left bottom coordinate of voxel. * @param rightBottom * Right bottom coordinate of voxel. * @param rightTop * Right top coordinate of voxel. * @param leftTop * Left top coordinate of voxel. */ BrainOpenGLVolumeSliceDrawing::VoxelToDraw::VoxelToDraw(const float center[3], const double leftBottom[3], const double rightBottom[3], const double rightTop[3], const double leftTop[3]) { m_center[0] = center[0]; m_center[1] = center[1]; m_center[2] = center[2]; m_coordinates[0] = leftBottom[0]; m_coordinates[1] = leftBottom[1]; m_coordinates[2] = leftBottom[2]; m_coordinates[3] = rightBottom[0]; m_coordinates[4] = rightBottom[1]; m_coordinates[5] = rightBottom[2]; m_coordinates[6] = rightTop[0]; m_coordinates[7] = rightTop[1]; m_coordinates[8] = rightTop[2]; m_coordinates[9] = leftTop[0]; m_coordinates[10] = leftTop[1]; m_coordinates[11] = leftTop[2]; const int64_t numSlices = 5; m_sliceIndices.reserve(numSlices); m_sliceOffsets.reserve(numSlices); } /** * Get the change in XYZ for the voxel ([top right] minus [bottom left]) * * @param dxyzOut * Change in XYZ from bottom left to top right */ void BrainOpenGLVolumeSliceDrawing::VoxelToDraw::getDiffXYZ(float dxyzOut[3]) const { dxyzOut[0] = m_coordinates[6] - m_coordinates[0]; dxyzOut[1] = m_coordinates[7] - m_coordinates[1]; dxyzOut[2] = m_coordinates[8] - m_coordinates[2]; } /** * Add a value from a volume slice. * * @param sliceIndex * Index of the slice. * @param sliceOffset * Offset of value in the slice. */ void BrainOpenGLVolumeSliceDrawing::VoxelToDraw::addVolumeValue(const int64_t sliceIndex, const int64_t sliceOffset) { CaretAssert(sliceIndex >= 0); CaretAssert(sliceOffset >= 0); m_sliceIndices.push_back(sliceIndex); m_sliceOffsets.push_back(sliceOffset); } /** * Get axis information for the given viewing plane and volume. * * @param volumeInterface * The volume interface. * @param sliceViewingPlane * The slice viewing plane. * @param axisIndexOut * Output with index into voxel IJK for axis. * @param orientationOut * Orientation of the axis. */ static void getAxisInfoForOrthogonalPlane(const VolumeMappableInterface* volumeInterface, const VolumeSliceViewPlaneEnum::Enum sliceViewingPlane, int32_t& axisIndexOut, VolumeSpace::OrientTypes& orientationOut) { CaretAssert(volumeInterface); axisIndexOut = -1; orientationOut = VolumeSpace::OrientTypes::LEFT_TO_RIGHT; const VolumeSpace volumeSpace = volumeInterface->getVolumeSpace(); VolumeSpace::OrientTypes volumeOrientations[3]; volumeSpace.getOrientation(volumeOrientations); for (int32_t i = 0; i < 3; i++) { CaretAssertArrayIndex(orientations, 3, i); const VolumeSpace::OrientTypes& ot = volumeOrientations[i]; bool matchFlag = false; switch (sliceViewingPlane) { case caret::VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case caret::VolumeSliceViewPlaneEnum::PARASAGITTAL: if ((ot == VolumeSpace::OrientTypes::LEFT_TO_RIGHT) || (ot == VolumeSpace::OrientTypes::RIGHT_TO_LEFT)) { matchFlag = true; } break; case caret::VolumeSliceViewPlaneEnum::CORONAL: if ((ot == VolumeSpace::OrientTypes::ANTERIOR_TO_POSTERIOR) || (ot == VolumeSpace::OrientTypes::POSTERIOR_TO_ANTERIOR)) { matchFlag = true; } break; case caret::VolumeSliceViewPlaneEnum::AXIAL: if ((ot == VolumeSpace::OrientTypes::INFERIOR_TO_SUPERIOR) || (ot == VolumeSpace::OrientTypes::SUPERIOR_TO_INFERIOR)) { matchFlag = true; } break; } if (matchFlag) { axisIndexOut = i; orientationOut = ot; break; } } CaretAssert((axisIndexOut >= 0) && (axisIndexOut < 3)); } /** * Get the info for the given axis in the given volume file * * @param volumeInterface * The volume interface. * @param axis * The axis * @param startWithMinimumCoordFlag * If true, voxel information will start with voxel that has minimum coordinate. * @param axisInfoOut * Output containing information for the given axis */ static void getAxisInfoAllView(const VolumeMappableInterface* volumeInterface, const VolumeSliceViewPlaneEnum::Enum axis, const bool startWithMinimumCoordFlag, AxisInfo& axisInfoOut) { /* * Data for axis may be in any dimension */ int32_t axisIndex = -1; VolumeSpace::OrientTypes axisOrientation = VolumeSpace::OrientTypes::LEFT_TO_RIGHT; getAxisInfoForOrthogonalPlane(volumeInterface, axis, axisIndex, axisOrientation); axisInfoOut.axis = axis; axisInfoOut.indexIntoIJK = axisIndex; if (axisInfoOut.indexIntoIJK < 0) { axisInfoOut.valid = false; return; } std::vector dimArray; volumeInterface->getDimensions(dimArray); CaretAssertVectorIndex(dimArray, axisInfoOut.indexIntoIJK); axisInfoOut.numberOfVoxels = dimArray[axisInfoOut.indexIntoIJK]; axisInfoOut.firstVoxelIndex = 0; int64_t zeroIndices[3] = { 0, 0, 0 }; volumeInterface->indexToSpace(zeroIndices, axisInfoOut.firstVoxelXYZ); int64_t oneIndices[3] = { 1, 1, 1}; float xyzOne[3] = { 1.0, 1.0, 1.0 }; volumeInterface->indexToSpace(oneIndices, xyzOne); int64_t lastIndices[3] = { dimArray[0] - 1, dimArray[1] - 1, dimArray[2] - 1 }; volumeInterface->indexToSpace(lastIndices, axisInfoOut.lastVoxelXYZ); axisInfoOut.indexIntoXYZ = axisInfoOut.indexIntoIJK; switch (axisOrientation) { case caret::VolumeSpace::LEFT_TO_RIGHT: case caret::VolumeSpace::RIGHT_TO_LEFT: axisInfoOut.indexIntoXYZ = 0; // X-axis break; case caret::VolumeSpace::POSTERIOR_TO_ANTERIOR: case caret::VolumeSpace::ANTERIOR_TO_POSTERIOR: axisInfoOut.indexIntoXYZ = 1; // Y-axis break; case caret::VolumeSpace::INFERIOR_TO_SUPERIOR: case caret::VolumeSpace::SUPERIOR_TO_INFERIOR: axisInfoOut.indexIntoXYZ = 2; // Z-axis break; } const float voxelStepSize = (xyzOne[axisInfoOut.indexIntoXYZ] - axisInfoOut.firstVoxelXYZ[axisInfoOut.indexIntoXYZ]); axisInfoOut.firstVoxelIndex = 0; axisInfoOut.voxelIndexStep = 1; axisInfoOut.voxelStepSize = voxelStepSize; axisInfoOut.orientation = axisOrientation; axisInfoOut.absoluteVoxelSize = std::fabs(axisInfoOut.voxelStepSize); bool flipFlag = false; if (startWithMinimumCoordFlag) { if (axisInfoOut.voxelStepSize < 0.0) { flipFlag = true; } } else { if (axisInfoOut.voxelStepSize > 0.0) { flipFlag = true; } } if (flipFlag) { axisInfoOut.firstVoxelIndex = axisInfoOut.numberOfVoxels - 1; axisInfoOut.voxelStepSize = -axisInfoOut.voxelStepSize; axisInfoOut.voxelIndexStep = -1; } axisInfoOut.valid = true; } /** * Draw an orthogonal slice for all view that works for any volume orientation. * * @param sliceViewingPlane * The plane for slice drawing. * @param sliceCoordinates * Coordinates of the selected slice. * @param plane * Plane equation for the selected slice. */ void BrainOpenGLVolumeSliceDrawing::drawOrthogonalSliceAllView(const VolumeSliceViewPlaneEnum::Enum sliceViewingPlane, const float sliceCoordinates[3], const Plane& plane) { CaretAssert(plane.isValidPlane()); if (plane.isValidPlane() == false) { return; } const int32_t browserTabIndex = m_browserTabContent->getTabNumber(); const DisplayPropertiesLabels* displayPropertiesLabels = m_brain->getDisplayPropertiesLabels(); const DisplayGroupEnum::Enum displayGroup = displayPropertiesLabels->getDisplayGroupForTab(browserTabIndex); /* * Enable alpha blending so voxels that are not drawn from higher layers * allow voxels from lower layers to be seen. * * Only allow layer blending when overall volume opacity is off (>= 1.0) */ const bool allowBlendingFlag(true); glPushAttrib(GL_COLOR_BUFFER_BIT); if (allowBlendingFlag) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } /* * Flat shading voxels not interpolated */ glShadeModel(GL_FLAT); /* * Compute coordinate of point in center of first slice */ float selectedSliceCoordinate = 0.0; float sliceNormalVector[3] = { 0.0, 0.0, 0.0 }; plane.getNormalVector(sliceNormalVector); switch (sliceViewingPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: selectedSliceCoordinate = sliceCoordinates[2]; break; case VolumeSliceViewPlaneEnum::CORONAL: selectedSliceCoordinate = sliceCoordinates[1]; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: selectedSliceCoordinate = sliceCoordinates[0]; break; } /* * Holds colors for voxels in the slice * Outside of loop to minimize allocations * It is faster to make one call to * NodeAndVoxelColoring::colorScalarsWithPalette() with * all voxels in the slice than it is to call it * separately for each voxel. */ std::vector sliceVoxelsRgbaVector; /* * Draw each of the volumes separately so that each * is drawn with the correct voxel slices. */ const int32_t numberOfVolumesToDraw = static_cast(m_volumeDrawInfo.size()); for (int32_t iVol = 0; iVol < numberOfVolumesToDraw; iVol++) { const BrainOpenGLFixedPipeline::VolumeDrawInfo& volInfo = m_volumeDrawInfo[iVol]; const VolumeMappableInterface* volumeInterface = volInfo.volumeFile; int32_t viewingAxisIndex = -1; VolumeSpace::OrientTypes orientation = VolumeSpace::OrientTypes::LEFT_TO_RIGHT; getAxisInfoForOrthogonalPlane(volumeInterface, sliceViewingPlane, viewingAxisIndex, orientation); /* * Coordinate of slice is ALWAYS from the bottom layer */ if (iVol == 0) { switch (sliceViewingPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: selectedSliceCoordinate = sliceCoordinates[2]; break; case VolumeSliceViewPlaneEnum::CORONAL: selectedSliceCoordinate = sliceCoordinates[1]; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: selectedSliceCoordinate = sliceCoordinates[0]; break; } } /* * Find axis that correspond to the axis that are on * the screen horizontally and vertically. */ AxisInfo drawLeftToRightInfo; AxisInfo drawBottomToTopInfo; int64_t viewPlaneDimIndex = viewingAxisIndex; int64_t sliceViewingPlaneIndexIntoXYZ = viewingAxisIndex; switch (sliceViewingPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: getAxisInfoAllView(volumeInterface, VolumeSliceViewPlaneEnum::PARASAGITTAL, true, drawLeftToRightInfo); getAxisInfoAllView(volumeInterface, VolumeSliceViewPlaneEnum::CORONAL, true, drawBottomToTopInfo); sliceViewingPlaneIndexIntoXYZ = 2; break; case VolumeSliceViewPlaneEnum::CORONAL: getAxisInfoAllView(volumeInterface, VolumeSliceViewPlaneEnum::PARASAGITTAL, true, drawLeftToRightInfo); getAxisInfoAllView(volumeInterface, VolumeSliceViewPlaneEnum::AXIAL, true, drawBottomToTopInfo); sliceViewingPlaneIndexIntoXYZ = 1; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: getAxisInfoAllView(volumeInterface, VolumeSliceViewPlaneEnum::CORONAL, false, drawLeftToRightInfo); getAxisInfoAllView(volumeInterface, VolumeSliceViewPlaneEnum::AXIAL, true, drawBottomToTopInfo); sliceViewingPlaneIndexIntoXYZ = 0; break; } CaretAssert(drawLeftToRightInfo.valid); CaretAssert(drawBottomToTopInfo.valid); CaretAssert(viewPlaneDimIndex != drawLeftToRightInfo.indexIntoIJK); CaretAssert(viewPlaneDimIndex != drawBottomToTopInfo.indexIntoIJK); CaretAssert(drawLeftToRightInfo.indexIntoIJK != drawBottomToTopInfo.indexIntoIJK); CaretAssert(sliceViewingPlaneIndexIntoXYZ != drawLeftToRightInfo.indexIntoXYZ); CaretAssert(sliceViewingPlaneIndexIntoXYZ != drawBottomToTopInfo.indexIntoXYZ); CaretAssert(drawLeftToRightInfo.indexIntoXYZ != drawBottomToTopInfo.indexIntoXYZ); if (debugFlag) { std::cout << "Viewing Axis Index: " << viewingAxisIndex << " for " << VolumeSliceViewPlaneEnum::toGuiName(sliceViewingPlane) << std::endl; std::cout << "Left to Right "; drawLeftToRightInfo.print(); std::cout << "Bottom to Top: "; drawBottomToTopInfo.print(); } /* * There must be at least two voxels in both dimensions. * If a dimension consists of a single voxel, then it is * likely a single slice volume and our viewpoint is * "in" the slice. * * Without this check the user would see a strange looking * line that is one voxel in width */ if ((drawLeftToRightInfo.numberOfVoxels <= 1) || (drawBottomToTopInfo.numberOfVoxels <= 1)) { continue; } /* * Spatial amount to move up row. */ float rowStepXYZ[3] = { 0.0, 0.0, 0.0 }; rowStepXYZ[drawBottomToTopInfo.indexIntoXYZ] = drawBottomToTopInfo.voxelStepSize; /* * Spatial amount to move right one column. */ float columnStepXYZ[3] = { 0.0, 0.0, 0.0 }; columnStepXYZ[drawLeftToRightInfo.indexIntoXYZ] = drawLeftToRightInfo.voxelStepSize; /* * Step in voxel dimensions to move right one column */ int64_t columnStepIJK[3] = { 0, 0, 0 }; columnStepIJK[drawLeftToRightInfo.indexIntoIJK] = drawLeftToRightInfo.voxelIndexStep; /* * Step in voxel dimensions to move up one row */ int64_t rowStepIJK[3] = { 0, 0, 0 }; rowStepIJK[drawBottomToTopInfo.indexIntoIJK] = drawBottomToTopInfo.voxelIndexStep; /* * XYZ needs to use regular X=0, Y=1, Z=2 indices */ int64_t sliceVoxelIndices[3] = { 0, 0, 0 }; float sliceVoxelXYZ[3] = { 0.0, 0.0, 0.0 }; sliceVoxelXYZ[sliceViewingPlaneIndexIntoXYZ] = selectedSliceCoordinate; volumeInterface->enclosingVoxel(sliceVoxelXYZ[0], sliceVoxelXYZ[1], sliceVoxelXYZ[2], sliceVoxelIndices[0], sliceVoxelIndices[1], sliceVoxelIndices[2]); /* * Find the index of the slice for drawing and verify that * it is a valid slice index. */ const int64_t sliceIndexForDrawing = sliceVoxelIndices[viewPlaneDimIndex]; std::vector volDim; volumeInterface->getDimensions(volDim); const int64_t maximumAxisSliceIndex = volDim[viewPlaneDimIndex]; if ((sliceIndexForDrawing < 0) || (sliceIndexForDrawing >= maximumAxisSliceIndex)) { continue; } /* * Voxel indices for first voxel that is drawn at bottom left of screen */ int64_t firstVoxelIJK[3] = { -1, -1, -1 }; firstVoxelIJK[drawBottomToTopInfo.indexIntoIJK] = drawBottomToTopInfo.firstVoxelIndex; // BACKWARDS ?????? firstVoxelIJK[drawLeftToRightInfo.indexIntoIJK] = drawLeftToRightInfo.firstVoxelIndex; firstVoxelIJK[viewPlaneDimIndex] = sliceIndexForDrawing; /* * Coordinate of first voxel that is drawn at bottom left of screen */ float startCoordinateXYZ[3] = { 0.0, 0.0, 0.0 }; volumeInterface->indexToSpace(firstVoxelIJK, startCoordinateXYZ); startCoordinateXYZ[sliceViewingPlaneIndexIntoXYZ] = selectedSliceCoordinate; startCoordinateXYZ[drawLeftToRightInfo.indexIntoXYZ] -= (drawLeftToRightInfo.voxelStepSize / 2.0); startCoordinateXYZ[drawBottomToTopInfo.indexIntoXYZ] -= (drawBottomToTopInfo.voxelStepSize / 2.0); /* * Stores RGBA values for each voxel. * Use a vector for voxel colors so no worries about memory being freed. */ const int64_t numVoxelsInSlice = drawBottomToTopInfo.numberOfVoxels * drawLeftToRightInfo.numberOfVoxels; const int64_t numVoxelsInSliceRGBA = numVoxelsInSlice * 4; if (numVoxelsInSliceRGBA > static_cast(sliceVoxelsRgbaVector.size())) { sliceVoxelsRgbaVector.resize(numVoxelsInSliceRGBA); } uint8_t* sliceVoxelsRGBA = &sliceVoxelsRgbaVector[0]; /* * Get colors for all voxels in the slice. */ if (debugFlag) { std::cout << "Slice Axis " << VolumeSliceViewPlaneEnum::toGuiName(sliceViewingPlane) << " start IJK: " << AString::fromNumbers(firstVoxelIJK, 3, ",") << " rowstep IJK: " << AString::fromNumbers(rowStepIJK, 3, ",") << " colstep IJK: " << AString::fromNumbers(columnStepIJK, 3, ",") << std::endl; } const int64_t validVoxelCount = volumeInterface->getVoxelColorsForSliceInMap(volInfo.mapIndex, firstVoxelIJK, rowStepIJK, columnStepIJK, drawBottomToTopInfo.numberOfVoxels, drawLeftToRightInfo.numberOfVoxels, displayGroup, browserTabIndex, sliceVoxelsRGBA); /* * Is label outline mode? */ if (m_volumeDrawInfo[iVol].mapFile->isMappedWithLabelTable()) { int64_t xdim = drawLeftToRightInfo.numberOfVoxels; int64_t ydim = drawBottomToTopInfo.numberOfVoxels; LabelDrawingTypeEnum::Enum labelDrawingType = LabelDrawingTypeEnum::DRAW_FILLED; CaretColorEnum::Enum outlineColor = CaretColorEnum::BLACK; const CaretMappableDataFile* mapFile = dynamic_cast(volumeInterface); if (mapFile != NULL) { if (mapFile->isMappedWithLabelTable()) { const LabelDrawingProperties* props = mapFile->getLabelDrawingProperties(); labelDrawingType = props->getDrawingType(); outlineColor = props->getOutlineColor(); } } NodeAndVoxelColoring::convertSliceColoringToOutlineMode(sliceVoxelsRGBA, labelDrawingType, outlineColor, xdim, ydim); } if (m_volumeDrawInfo[iVol].mapFile->isMappedWithPalette()) { const int32_t mapIndex = m_volumeDrawInfo[iVol].mapIndex; int64_t xdim = drawLeftToRightInfo.numberOfVoxels; int64_t ydim = drawBottomToTopInfo.numberOfVoxels; const PaletteColorMapping* pcm = m_volumeDrawInfo[iVol].mapFile->getMapPaletteColorMapping(mapIndex); NodeAndVoxelColoring::convertPaletteSliceColoringToOutlineMode(sliceVoxelsRGBA, pcm->getThresholdOutlineDrawingMode(), pcm->getThresholdOutlineDrawingColor(), xdim, ydim); } const uint8_t volumeDrawingOpacity = static_cast(volInfo.opacity * 255.0); if (m_modelWholeBrain != NULL) { /* * After the a slice is drawn in ALL view, some layers * (volume surface outline) may be drawn in lines. As the * view is rotated, lines will partially appear and disappear * due to the lines having the same (extremely close) depth * values as the voxel polygons. OpenGL's Polygon Offset * only works with polygons and NOT with lines or points. * So, polygon offset cannot be used to move the depth * values for the lines and points "a little closer" to * the user. Instead, polygon offset is used to push * the underlaying slices "a little bit away" from the * user. * * Resolves WB-414 */ const float inverseSliceIndex = numberOfVolumesToDraw - iVol; const float factor = inverseSliceIndex * 1.0 + 1.0; const float units = inverseSliceIndex * 1.0 + 1.0; glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(factor, units); } /* * Draw the voxels in the slice. */ // const AString drawMsg("NEW:" // "\n Axis: " + VolumeSliceViewPlaneEnum::toName(sliceViewingPlane) // + "\n Start XYZ: " + AString::fromNumbers(startCoordinateXYZ, 3, ",") // + "\n Row Step: " + AString::fromNumbers(rowStepXYZ, 3, ",") // + "\n Column Step: " + AString::fromNumbers(columnStepXYZ, 3, ",") // + "\n Num Cols: " + AString::number(drawLeftToRightInfo.numberOfVoxels) // + "\n Num Rows: " + AString::number(drawBottomToTopInfo.numberOfVoxels) // + "\n"); // std::cout << qPrintable(drawMsg) << std::endl; if (debugFlag) { std::cout << "Slice Axis " << VolumeSliceViewPlaneEnum::toGuiName(sliceViewingPlane) << " start XYZ: " << AString::fromNumbers(startCoordinateXYZ, 3, ",") << " rowstep XYZ: " << AString::fromNumbers(rowStepXYZ, 3, ",") << " colstep XYZ: " << AString::fromNumbers(columnStepXYZ, 3, ",") << std::endl; } drawOrthogonalSliceVoxels(sliceNormalVector, startCoordinateXYZ, rowStepXYZ, columnStepXYZ, drawLeftToRightInfo.numberOfVoxels, drawBottomToTopInfo.numberOfVoxels, sliceVoxelsRgbaVector, validVoxelCount, volumeInterface, iVol, volInfo.mapIndex, volumeDrawingOpacity); glDisable(GL_POLYGON_OFFSET_FILL); } showBrainordinateHighlightRegionOfInterest(sliceViewingPlane, sliceCoordinates, sliceNormalVector); // glDisable(GL_BLEND); glPopAttrib(); glShadeModel(GL_SMOOTH); } connectome-workbench-1.4.2/src/Brain/BrainOpenGLVolumeSliceDrawing.h000066400000000000000000000456271360521144700254300ustar00rootroot00000000000000#ifndef __BRAIN_OPEN_GL_VOLUME_SLICE_DRAWING_H__ #define __BRAIN_OPEN_GL_VOLUME_SLICE_DRAWING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainOpenGLFixedPipeline.h" #include "CaretObject.h" #include "DisplayGroupEnum.h" #include "ModelTypeEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "VolumeSliceDrawingTypeEnum.h" #include "VolumeSliceViewAllPlanesLayoutEnum.h" #include "VolumeSliceViewPlaneEnum.h" namespace caret { class Brain; class BrowserTabContent; class CiftiMappableDataFile; class Matrix4x4; class ModelVolume; class ModelWholeBrain; class Plane; class VolumeMappableInterface; class VolumeSurfaceOutlineSetModel; class BrainOpenGLVolumeSliceDrawing : public CaretObject { public: /** * Indicates drawing volume sclice "ALL that shows * axial, coronal, and parasagittal at same time */ enum class AllSliceViewMode { ALL_YES, ALL_NO }; BrainOpenGLVolumeSliceDrawing(); virtual ~BrainOpenGLVolumeSliceDrawing(); void draw(BrainOpenGLFixedPipeline* fixedPipelineDrawing, BrowserTabContent* browserTabContent, std::vector& volumeDrawInfo, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const int32_t viewport[4]); static void setOrthographicProjection(const AllSliceViewMode allSliceViewMode, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const BoundingBox& boundingBox, const float zoomFactor, const int viewport[4], double orthographicBoundsOut[6]); static void drawSurfaceOutline(const VolumeMappableInterface* underlayVolume, const ModelTypeEnum::Enum modelType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceXYZ[3], const Plane& plane, VolumeSurfaceOutlineSetModel* outlineSet, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const bool useNegativePolygonOffsetFlag); // ADD_NEW_METHODS_HERE private: /** * Holds values in the slice for a volume so that they * can be colored all at once which is more efficient than * colors singles voxels many times */ class VolumeSlice{ public: /** * Constructor * * @param volumeMappableInterface * Volume that contains the data values. */ VolumeSlice(VolumeMappableInterface* volumeMappableInterface, const int32_t mapIndex); /** * Add a value and return its index. * * @param value * Value that is added. * @return * The index for the value. */ int64_t addValue(const float value); /** * Return RGBA colors for value using the value's index * returned by addValue(). * * @param indx * Index of the value. * @return * RGBA coloring for value. */ uint8_t* getRgbaForValueByIndex(const int64_t indx); /** * Allocate colors for the voxel values */ void allocateColors(); /** * Volume containing the values */ VolumeMappableInterface* m_volumeMappableInterface; /** * If not NULL, it is a VolumeFile */ VolumeFile* m_volumeFile; /** * If not NULL, it is a Cifti Mappable Data File */ CiftiMappableDataFile* m_ciftiMappableDataFile; /** * Map index */ int32_t m_mapIndex; /** * The voxel values */ std::vector m_values; /** * Coloring corresponding to the values (4 components per voxel) */ std::vector m_rgba; }; /** * For each voxel, contains offsets to each layer */ class VoxelToDraw { public: VoxelToDraw(const float center[3], const double leftBottom[3], const double rightBottom[3], const double rightTop[3], const double leftTop[3]); void getDiffXYZ(float dxyzOut[3]) const; void addVolumeValue(const int64_t sliceIndex, const int64_t sliceOffset); /** * Center of voxel. */ float m_center[3]; /** * Corners of voxel */ float m_coordinates[12]; /* * Index of volume in VoxelsInSliceForVolume */ std::vector m_sliceIndices; /** * Offset in values in VoxelsInSliceForVolume */ std::vector m_sliceOffsets; }; BrainOpenGLVolumeSliceDrawing(const BrainOpenGLVolumeSliceDrawing&); BrainOpenGLVolumeSliceDrawing& operator=(const BrainOpenGLVolumeSliceDrawing&); void drawVolumeSlicesForAllStructuresView(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const int32_t viewport[4]); void drawVolumeSliceViewPlane(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, const int32_t viewport[4]); void drawVolumeSliceViewType(const AllSliceViewMode allSliceViewMode, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const int32_t viewport[4]); void drawVolumeSliceViewTypeMontage(const AllSliceViewMode allSliceViewMode, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const int32_t viewport[4]); void drawVolumeSliceViewProjection(const AllSliceViewMode allSliceViewMode, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], const int32_t viewport[4]); void drawOrthogonalSlice_LPI_ONLY(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], const Plane& plane); void drawOrthogonalSlice(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], const Plane& plane); void drawOrthogonalSliceAllView(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], const Plane& plane); void drawOrthogonalSliceWithCulling(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], const Plane& plane); void createSlicePlaneEquation(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], Plane& planeOut); void drawAxesCrosshairsOrtho(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], const bool drawCrosshairsFlag, const bool drawCrosshairLabelsFlag); void setVolumeSliceViewingAndModelingTransformations(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const Plane& plane); void getAxesColor(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, float rgbaOut[4]) const; void drawLayers(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const Plane& slicePlane, const float sliceCoordinates[3]); static void drawSurfaceOutlineCached(const VolumeMappableInterface* underlayVolume, const ModelTypeEnum::Enum modelType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceXYZ[3], const Plane& plane, VolumeSurfaceOutlineSetModel* outlineSet, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const bool useNegativePolygonOffsetFlag); static void drawSurfaceOutlineNotCached(const ModelTypeEnum::Enum modelType, const Plane& plane, VolumeSurfaceOutlineSetModel* outlineSet, BrainOpenGLFixedPipeline* fixedPipelineDrawing, const bool useNegativePolygonOffsetFlag); void drawVolumeSliceFoci(const Plane& plane); void drawAxesCrosshairs(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3]); bool getMinMaxVoxelSpacing(const VolumeMappableInterface* volume, float& minSpacingOut, float& maxSpacingOut) const; void drawSquare(const float size); void setOrthographicProjection(const AllSliceViewMode allSliceViewMode, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const int viewport[4]); void drawOrthogonalSliceVoxels(const float sliceNormalVector[3], const float coordinate[3], const float rowStep[3], const float columnStep[3], const int64_t numberOfColumns, const int64_t numberOfRows, const std::vector& sliceRGBA, const int64_t validVoxelCount, const VolumeMappableInterface* volumeInterface, const int32_t volumeIndex, const int32_t mapIndex, const uint8_t sliceOpacity); void drawOrthogonalSliceVoxelsSingleQuads(const float sliceNormalVector[3], const float coordinate[3], const float rowStep[3], const float columnStep[3], const int64_t numberOfColumns, const int64_t numberOfRows, const std::vector& sliceRGBA, const VolumeMappableInterface* volumeInterface, const int32_t volumeIndex, const int32_t mapIndex, const uint8_t sliceOpacity); void drawOrthogonalSliceVoxelsQuadIndicesAndStrips(const float sliceNormalVector[3], const float coordinate[3], const float rowStep[3], const float columnStep[3], const int64_t numberOfColumns, const int64_t numberOfRows, const std::vector& sliceRGBA, const VolumeMappableInterface* volumeInterface, const int32_t volumeIndex, const int32_t mapIndex, const uint8_t sliceOpacity); bool getVoxelCoordinateBoundsAndSpacing(float boundsOut[6], float spacingOut[3]); void drawIdentificationSymbols(const Plane& plane); void addVoxelToIdentification(const int32_t volumeIndex, const int32_t mapIndex, const int32_t voxelI, const int32_t voxelJ, const int32_t voxelK, const float voxelDiffXYZ[3], uint8_t rgbaForColorIdentificationOut[4]); bool getVolumeDrawingViewDependentCulling(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float selectedSliceCoordinate, const VolumeMappableInterface* volumeFile, int64_t culledFirstVoxelIJKOut[3], int64_t culledLastVoxelIJKOut[3], float voxelDeltaXYZOut[3]); void showBrainordinateHighlightRegionOfInterest(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], const float sliceNormalVector[3]); void processIdentification(); void resetIdentification(); ModelTypeEnum::Enum m_modelType; ModelVolume* m_modelVolume; ModelWholeBrain* m_modelWholeBrain; VolumeMappableInterface* m_underlayVolume; Brain* m_brain; std::vector > m_ciftiMappableFileData; BrainOpenGLFixedPipeline* m_fixedPipelineDrawing; std::vector m_volumeDrawInfo; BrowserTabContent* m_browserTabContent; DisplayGroupEnum::Enum m_displayGroup; int32_t m_tabIndex; double m_lookAtCenter[3]; double m_viewingMatrix[16]; double m_orthographicBounds[6]; std::vector m_identificationIndices; bool m_identificationModeFlag; static const int32_t IDENTIFICATION_INDICES_PER_VOXEL; // ADD_NEW_MEMBERS_HERE }; #ifdef __BRAIN_OPEN_GL_VOLUME_SLICE_DRAWING_DECLARE__ const int32_t BrainOpenGLVolumeSliceDrawing::IDENTIFICATION_INDICES_PER_VOXEL = 8; #endif // __BRAIN_OPEN_GL_VOLUME_SLICE_DRAWING_DECLARE__ } // namespace #endif //__BRAIN_OPEN_GL_VOLUME_SLICE_DRAWING_H__ connectome-workbench-1.4.2/src/Brain/BrainOpenGLVolumeTextureSliceDrawing.cxx000066400000000000000000004406221360521144700273560ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #define __BRAIN_OPEN_GL_VOLUME_TEXTURE_SLICE_DRAWING_DECLARE__ #include "BrainOpenGLVolumeTextureSliceDrawing.h" #undef __BRAIN_OPEN_GL_VOLUME_TEXTURE_SLICE_DRAWING_DECLARE__ #include "AnnotationCoordinate.h" #include "AnnotationPercentSizeText.h" #include "BoundingBox.h" #include "Brain.h" #include "BrainOpenGLAnnotationDrawingFixedPipeline.h" #include "BrainOpenGLPrimitiveDrawing.h" #include "BrainOpenGLViewportContent.h" #include "BrainOpenGLVolumeSliceDrawing.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretOpenGLInclude.h" #include "CaretPreferenceDataValue.h" #include "CaretPreferences.h" #include "CiftiMappableDataFile.h" #include "DeveloperFlagsEnum.h" #include "DisplayPropertiesFoci.h" #include "DisplayPropertiesLabels.h" #include "DisplayPropertiesVolume.h" #include "ElapsedTimer.h" #include "FociFile.h" #include "Focus.h" #include "GapsAndMargins.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "GroupAndNameHierarchyModel.h" #include "GraphicsEngineDataOpenGL.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GraphicsPrimitiveV3fC4ub.h" #include "GraphicsUtilitiesOpenGL.h" #include "IdentificationWithColor.h" #include "LabelDrawingProperties.h" #include "MathFunctions.h" #include "Matrix4x4.h" #include "ModelVolume.h" #include "ModelWholeBrain.h" #include "NodeAndVoxelColoring.h" #include "SelectionItemFocusVolume.h" #include "SelectionItemVoxel.h" #include "SelectionItemVoxelEditing.h" #include "SelectionManager.h" #include "SessionManager.h" #include "SpacerTabIndex.h" #include "Surface.h" #include "SurfacePlaneIntersectionToContour.h" #include "VolumeFile.h" #include "VolumeSurfaceOutlineColorOrTabModel.h" #include "VolumeSurfaceOutlineModel.h" #include "VolumeSurfaceOutlineSetModel.h" using namespace caret; static const bool debugFlag = false; /** * \class caret::BrainOpenGLVolumeTextureSliceDrawing * \brief Draws volume slices using OpenGL * \ingroup Brain */ /** * Constructor. */ BrainOpenGLVolumeTextureSliceDrawing::BrainOpenGLVolumeTextureSliceDrawing() : CaretObject() { } /** * Destructor. */ BrainOpenGLVolumeTextureSliceDrawing::~BrainOpenGLVolumeTextureSliceDrawing() { } /** * Draw Volume Slices or slices for ALL Stuctures View. * * @param fixedPipelineDrawing * The OpenGL drawing. * @param browserTabContent * Content of browser tab that is to be drawn. * @param volumeDrawInfo * Info on each volume layers for drawing. * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param obliqueSliceMaskingType * Masking for oblique slice drawing * @param viewport * The viewport (region of graphics area) for drawing slices. */ void BrainOpenGLVolumeTextureSliceDrawing::draw(BrainOpenGLFixedPipeline* fixedPipelineDrawing, BrowserTabContent* browserTabContent, std::vector& volumeDrawInfo, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum obliqueSliceMaskingType, const int32_t viewport[4]) { // CaretAssert(sliceProjectionType == VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE); if (volumeDrawInfo.empty()) { return; } glMatrixMode(GL_PROJECTION); glPushMatrix(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); drawPrivate(fixedPipelineDrawing, browserTabContent, volumeDrawInfo, sliceDrawingType, sliceProjectionType, obliqueSliceMaskingType, viewport); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } /** * Draw Volume Slices or slices for ALL Stuctures View. * * @param fixedPipelineDrawing * The OpenGL drawing. * @param browserTabContent * Content of browser tab that is to be drawn. * @param volumeDrawInfo * Info on each volume layers for drawing. * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param obliqueSliceMaskingType * Masking for oblique slice drawing * @param viewport * The viewport (region of graphics area) for drawing slices. */ void BrainOpenGLVolumeTextureSliceDrawing::drawPrivate(BrainOpenGLFixedPipeline* fixedPipelineDrawing, BrowserTabContent* browserTabContent, std::vector& volumeDrawInfo, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum obliqueSliceMaskingType, const int32_t viewport[4]) { // CaretAssert(sliceProjectionType == VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE); if (volumeDrawInfo.empty()) { return; } CaretAssert(fixedPipelineDrawing); CaretAssert(browserTabContent); m_browserTabContent = browserTabContent; m_fixedPipelineDrawing = fixedPipelineDrawing; m_obliqueSliceMaskingType = obliqueSliceMaskingType; /* * No lighting for drawing slices */ m_fixedPipelineDrawing->disableLighting(); /* * Initialize class members which help reduce the number of * parameters that are passed to methods. */ m_brain = NULL; m_modelVolume = NULL; m_modelWholeBrain = NULL; m_modelType = ModelTypeEnum::MODEL_TYPE_INVALID; if (m_browserTabContent->getDisplayedVolumeModel() != NULL) { m_modelVolume = m_browserTabContent->getDisplayedVolumeModel(); m_brain = m_modelVolume->getBrain(); m_modelType = m_modelVolume->getModelType(); } else if (m_browserTabContent->getDisplayedWholeBrainModel() != NULL) { m_modelWholeBrain = m_browserTabContent->getDisplayedWholeBrainModel(); m_brain = m_modelWholeBrain->getBrain(); m_modelType = m_modelWholeBrain->getModelType(); } else { CaretAssertMessage(0, "Invalid model for volume slice drawing."); } CaretAssert(m_brain); CaretAssert(m_modelType != ModelTypeEnum::MODEL_TYPE_INVALID); m_volumeDrawInfo = volumeDrawInfo; if (m_volumeDrawInfo.empty()) { return; } m_underlayVolume = m_volumeDrawInfo[0].volumeFile; const DisplayPropertiesLabels* dsl = m_brain->getDisplayPropertiesLabels(); m_displayGroup = dsl->getDisplayGroupForTab(m_fixedPipelineDrawing->windowTabIndex); m_tabIndex = m_browserTabContent->getTabNumber(); /* * Cifti files are slow at getting individual voxels since they * provide no access to individual voxels. The reason is that * the data may be on a server (Dense data) and accessing a single * voxel would require requesting the entire map. So, for * each Cifti file, get the enter map. This also, eliminate multiple * requests for the same map when drawing an ALL view. */ const int32_t numVolumes = static_cast(m_volumeDrawInfo.size()); for (int32_t i = 0; i < numVolumes; i++) { std::vector ciftiMapData; m_ciftiMappableFileData.push_back(ciftiMapData); const CiftiMappableDataFile* ciftiMapFile = dynamic_cast(m_volumeDrawInfo[i].volumeFile); if (ciftiMapFile != NULL) { ciftiMapFile->getMapData(m_volumeDrawInfo[i].mapIndex, m_ciftiMappableFileData[i]); } } if (browserTabContent->getDisplayedVolumeModel() != NULL) { drawVolumeSliceViewPlane(sliceDrawingType, sliceProjectionType, browserTabContent->getSliceViewPlane(), browserTabContent->getSlicePlanesAllViewLayout(), viewport); } else if (browserTabContent->getDisplayedWholeBrainModel() != NULL) { drawVolumeSlicesForAllStructuresView(sliceProjectionType, viewport); } } /** * Draw volume view slices for the given view plane. * * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * The plane for slice drawing. * @param allPlanesLayout * The layout in ALL slices view. * @param viewport * The viewport (region of graphics area) for drawing slices. */ void BrainOpenGLVolumeTextureSliceDrawing::drawVolumeSliceViewPlane(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, const int32_t viewport[4]) { switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: { int32_t paraVP[4] = { 0, 0, 0, 0 }; int32_t coronalVP[4] = { 0, 0, 0, 0 }; int32_t axialVP[4] = { 0, 0, 0, 0 }; BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, VolumeSliceViewPlaneEnum::PARASAGITTAL, allPlanesLayout, paraVP); BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, VolumeSliceViewPlaneEnum::CORONAL, allPlanesLayout, coronalVP); BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, VolumeSliceViewPlaneEnum::AXIAL, allPlanesLayout, axialVP); /* * Draw parasagittal slice */ glPushMatrix(); drawVolumeSliceViewType(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_YES, sliceDrawingType, sliceProjectionType, VolumeSliceViewPlaneEnum::PARASAGITTAL, paraVP); glPopMatrix(); /* * Draw coronal slice */ glPushMatrix(); drawVolumeSliceViewType(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_YES, sliceDrawingType, sliceProjectionType, VolumeSliceViewPlaneEnum::CORONAL, coronalVP); glPopMatrix(); /* * Draw axial slice */ glPushMatrix(); drawVolumeSliceViewType(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_YES, sliceDrawingType, sliceProjectionType, VolumeSliceViewPlaneEnum::AXIAL, axialVP); glPopMatrix(); if (allPlanesLayout == VolumeSliceViewAllPlanesLayoutEnum::GRID_LAYOUT) { /* * 4th quadrant is used for axis showing orientation */ int32_t allVP[4] = { 0, 0, 0, 0 }; BrainOpenGLViewportContent::getSliceAllViewViewport(viewport, VolumeSliceViewPlaneEnum::ALL, allPlanesLayout, allVP); switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: drawOrientationAxes(allVP); break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: break; } } } break; case VolumeSliceViewPlaneEnum::AXIAL: case VolumeSliceViewPlaneEnum::CORONAL: case VolumeSliceViewPlaneEnum::PARASAGITTAL: drawVolumeSliceViewType(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_NO, sliceDrawingType, sliceProjectionType, sliceViewPlane, viewport); break; } } /** * Draw slices for the all structures view. * * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param viewport * The viewport. */ void BrainOpenGLVolumeTextureSliceDrawing::drawVolumeSlicesForAllStructuresView(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const int32_t viewport[4]) { m_orthographicBounds[0] = m_fixedPipelineDrawing->orthographicLeft; m_orthographicBounds[1] = m_fixedPipelineDrawing->orthographicRight; m_orthographicBounds[2] = m_fixedPipelineDrawing->orthographicBottom; m_orthographicBounds[3] = m_fixedPipelineDrawing->orthographicTop; m_orthographicBounds[4] = m_fixedPipelineDrawing->orthographicNear; m_orthographicBounds[5] = m_fixedPipelineDrawing->orthographicFar; /* * Enlarge the region */ { const float left = m_fixedPipelineDrawing->orthographicLeft; const float right = m_fixedPipelineDrawing->orthographicRight; const float bottom = m_fixedPipelineDrawing->orthographicBottom; const float top = m_fixedPipelineDrawing->orthographicTop; const float scale = 2.0; const float centerX = (left + right) / 2.0; const float dx = (right - left) / 2.0; const float newLeft = centerX - (dx * scale); const float newRight = centerX + (dx * scale); const float centerY = (bottom + top) / 2.0; const float dy = (top - bottom) / 2.0; const float newBottom = centerY - (dy * scale); const float newTop = centerY + (dy * scale); m_orthographicBounds[0] = newLeft; m_orthographicBounds[1] = newRight; m_orthographicBounds[2] = newBottom; m_orthographicBounds[3] = newTop; } const float sliceCoordinates[3] = { m_browserTabContent->getSliceCoordinateParasagittal(), m_browserTabContent->getSliceCoordinateCoronal(), m_browserTabContent->getSliceCoordinateAxial() }; if (m_browserTabContent->isSliceAxialEnabled()) { glPushMatrix(); drawVolumeSliceViewProjection(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_NO, VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE, sliceProjectionType, VolumeSliceViewPlaneEnum::AXIAL, sliceCoordinates, viewport); glPopMatrix(); } if (m_browserTabContent->isSliceCoronalEnabled()) { glPushMatrix(); drawVolumeSliceViewProjection(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_NO, VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE, sliceProjectionType, VolumeSliceViewPlaneEnum::CORONAL, sliceCoordinates, viewport); glPopMatrix(); } if (m_browserTabContent->isSliceParasagittalEnabled()) { glPushMatrix(); drawVolumeSliceViewProjection(BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_NO, VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE, sliceProjectionType, VolumeSliceViewPlaneEnum::PARASAGITTAL, sliceCoordinates, viewport); glPopMatrix(); } } /** * Draw single or montage volume view slices. * * @param allSliceViewMode * Indicates drawing of ALL slices volume view (axial, coronal, parasagittal in one view) * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * The plane for slice drawing. * @param viewport * The viewport (region of graphics area) for drawing slices. */ void BrainOpenGLVolumeTextureSliceDrawing::drawVolumeSliceViewType(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const int32_t viewport[4]) { switch (sliceDrawingType) { case VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_MONTAGE: drawVolumeSliceViewTypeMontage(allSliceViewMode, sliceDrawingType, sliceProjectionType, sliceViewPlane, viewport); break; case VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE: { const float sliceCoordinates[3] = { m_browserTabContent->getSliceCoordinateParasagittal(), m_browserTabContent->getSliceCoordinateCoronal(), m_browserTabContent->getSliceCoordinateAxial() }; drawVolumeSliceViewProjection(allSliceViewMode, sliceDrawingType, sliceProjectionType, sliceViewPlane, sliceCoordinates, viewport); } break; } } /** * Draw montage slices. * * @param allSliceViewMode * Indicates drawing of ALL slices volume view (axial, coronal, parasagittal in one view) * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * The plane for slice drawing. * @param viewport * The viewport (region of graphics area) for drawing slices. */ void BrainOpenGLVolumeTextureSliceDrawing::drawVolumeSliceViewTypeMontage(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const int32_t viewport[4]) { const int32_t numRows = m_browserTabContent->getMontageNumberOfRows(); CaretAssert(numRows > 0); const int32_t numCols = m_browserTabContent->getMontageNumberOfColumns(); CaretAssert(numCols > 0); const int32_t montageCoordPrecision = m_browserTabContent->getVolumeMontageCoordinatePrecision(); const GapsAndMargins* gapsAndMargins = m_brain->getGapsAndMargins(); const int32_t windowIndex = m_fixedPipelineDrawing->m_windowIndex; int32_t vpSizeY = 0; int32_t verticalMargin = 0; BrainOpenGLFixedPipeline::createSubViewportSizeAndGaps(viewport[3], gapsAndMargins->getVolumeMontageVerticalGapForWindow(windowIndex), -1, numRows, vpSizeY, verticalMargin); int32_t vpSizeX = 0; int32_t horizontalMargin = 0; BrainOpenGLFixedPipeline::createSubViewportSizeAndGaps(viewport[2], gapsAndMargins->getVolumeMontageHorizontalGapForWindow(windowIndex), -1, numCols, vpSizeX, horizontalMargin); /* * Voxel sizes for underlay volume */ float originX, originY, originZ; float x1, y1, z1; m_underlayVolume->indexToSpace(0, 0, 0, originX, originY, originZ); m_underlayVolume->indexToSpace(1, 1, 1, x1, y1, z1); float sliceThickness = 0.0; float sliceOrigin = 0.0; AString axisLetter = ""; float sliceCoordinates[3] = { m_browserTabContent->getSliceCoordinateParasagittal(), m_browserTabContent->getSliceCoordinateCoronal(), m_browserTabContent->getSliceCoordinateAxial() }; int32_t sliceIndex = -1; int32_t maximumSliceIndex = -1; int64_t dimI, dimJ, dimK, numMaps, numComponents; m_underlayVolume->getDimensions(dimI, dimJ, dimK, numMaps, numComponents); const int32_t sliceStep = m_browserTabContent->getMontageSliceSpacing(); switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: sliceIndex = -1; break; case VolumeSliceViewPlaneEnum::AXIAL: sliceIndex = m_browserTabContent->getSliceIndexAxial(m_underlayVolume); maximumSliceIndex = dimK; sliceThickness = z1 - originZ; sliceOrigin = originZ; axisLetter = "Z"; break; case VolumeSliceViewPlaneEnum::CORONAL: sliceIndex = m_browserTabContent->getSliceIndexCoronal(m_underlayVolume); maximumSliceIndex = dimJ; sliceThickness = y1 - originY; sliceOrigin = originY; axisLetter = "Y"; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: sliceIndex = m_browserTabContent->getSliceIndexParasagittal(m_underlayVolume); maximumSliceIndex = dimI; sliceThickness = x1 - originX; sliceOrigin = originX; axisLetter = "X"; break; } /* * Foreground color for slice coordinate text */ const CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); uint8_t foregroundRGBA[4]; prefs->getBackgroundAndForegroundColors()->getColorForegroundVolumeView(foregroundRGBA); foregroundRGBA[3] = 255; uint8_t backgroundRGBA[4]; prefs->getBackgroundAndForegroundColors()->getColorBackgroundVolumeView(backgroundRGBA); backgroundRGBA[3] = 255; const bool showCoordinates = m_browserTabContent->isVolumeMontageAxesCoordinatesDisplayed(); /* * Determine a slice offset to selected slices is in * the center of the montage */ const int32_t numSlicesViewed = (numCols * numRows); const int32_t sliceOffset = ((numSlicesViewed / 2) * sliceStep); sliceIndex += sliceOffset; /* * Find first valid slice for montage */ while (sliceIndex >= 0) { if (sliceIndex < maximumSliceIndex) { break; } sliceIndex -= sliceStep; } if (sliceIndex >= 0) { for (int32_t i = 0; i < numRows; i++) { for (int32_t j = 0; j < numCols; j++) { if ((sliceIndex >= 0) && (sliceIndex < maximumSliceIndex)) { const int32_t vpX = (j * (vpSizeX + horizontalMargin)); const int32_t vpY = ((numRows - i - 1) * (vpSizeY + verticalMargin)); int32_t vp[4] = { viewport[0] + vpX, viewport[1] + vpY, vpSizeX, vpSizeY }; if ((vp[2] <= 0) || (vp[3] <= 0)) { continue; } const float sliceCoord = (sliceOrigin + sliceThickness * sliceIndex); switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: break; case VolumeSliceViewPlaneEnum::AXIAL: sliceCoordinates[2] = sliceCoord; break; case VolumeSliceViewPlaneEnum::CORONAL: sliceCoordinates[1] = sliceCoord; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: sliceCoordinates[0] = sliceCoord; break; } drawVolumeSliceViewProjection(allSliceViewMode, sliceDrawingType, sliceProjectionType, sliceViewPlane, sliceCoordinates, vp); if (showCoordinates) { const AString coordText = (axisLetter + "=" + AString::number(sliceCoord, 'f', montageCoordPrecision)); AnnotationPercentSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); annotationText.setFontPercentViewportSize(10.0f); annotationText.setLineColor(CaretColorEnum::NONE); annotationText.setTextColor(CaretColorEnum::CUSTOM); annotationText.setBackgroundColor(CaretColorEnum::CUSTOM); annotationText.setCustomTextColor(foregroundRGBA); annotationText.setCustomBackgroundColor(backgroundRGBA); annotationText.setText(coordText); m_fixedPipelineDrawing->drawTextAtViewportCoords((vpSizeX - 5), 5.0, annotationText); } } sliceIndex -= sliceStep; } } } /* * Draw the axes labels for the montage view */ glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); if (m_browserTabContent->isVolumeAxesCrosshairLabelsDisplayed()) { drawAxesCrosshairsOblique(sliceViewPlane, sliceCoordinates, false, true); } } /** * Draw a slice for either projection mode (oblique, orthogonal) * * @param allSliceViewMode * Indicates drawing of ALL slices volume view (axial, coronal, parasagittal in one view) * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * The plane for slice drawing. * @param sliceCoordinates * Coordinates of the selected slice. * @param viewport * The viewport (region of graphics area) for drawing slices. */ void BrainOpenGLVolumeTextureSliceDrawing::drawVolumeSliceViewProjection(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], const int32_t viewport[4]) { bool twoDimSliceViewFlag = false; if (m_modelVolume != NULL) { twoDimSliceViewFlag = true; } else if (m_modelWholeBrain != NULL) { /* nothing */ } else { CaretAssertMessage(0, "Invalid model type."); } if (twoDimSliceViewFlag) { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); /* * Set the orthographic projection to fit the slice axis */ setOrthographicProjection(allSliceViewMode, sliceViewPlane, viewport); } /* * Create the plane equation for the slice */ Plane slicePlane; createSlicePlaneEquation(sliceProjectionType, sliceViewPlane, sliceCoordinates, slicePlane); CaretAssert(slicePlane.isValidPlane()); if (slicePlane.isValidPlane() == false) { return; } if (twoDimSliceViewFlag) { /* * Set the viewing transformation (camera position) */ setVolumeSliceViewingAndModelingTransformations(sliceProjectionType, sliceViewPlane, slicePlane, sliceCoordinates); } SelectionItemVoxel* voxelID = m_brain->getSelectionManager()->getVoxelIdentification(); SelectionItemVoxelEditing* voxelEditingID = m_brain->getSelectionManager()->getVoxelEditingIdentification(); m_fixedPipelineDrawing->applyClippingPlanes(BrainOpenGLFixedPipeline::CLIPPING_DATA_TYPE_VOLUME, StructureEnum::ALL); /* * Check for a 'selection' type mode */ bool drawVolumeSlicesFlag = true; m_identificationModeFlag = false; switch (m_fixedPipelineDrawing->mode) { case BrainOpenGLFixedPipeline::MODE_DRAWING: break; case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: if (voxelID->isEnabledForSelection() || voxelEditingID->isEnabledForSelection()) { m_identificationModeFlag = true; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } else { /* * Don't return. Allow other items (such as annotations) to be drawn. */ drawVolumeSlicesFlag = false; } break; case BrainOpenGLFixedPipeline::MODE_PROJECTION: return; break; } GLboolean cullFaceOn = glIsEnabled(GL_CULL_FACE); if (drawVolumeSlicesFlag) { /* * Disable culling so that both sides of the triangles/quads are drawn. */ glDisable(GL_CULL_FACE); Matrix4x4 obliqueTransformationMatrix; switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: // break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: { /* * Create the oblique slice transformation matrix */ createObliqueTransformationMatrix(sliceProjectionType, sliceCoordinates, obliqueTransformationMatrix); } break; } drawObliqueSliceWithOutlines(sliceViewPlane, sliceProjectionType, obliqueTransformationMatrix); } if ( ! m_identificationModeFlag) { if (slicePlane.isValidPlane()) { drawLayers(sliceDrawingType, sliceProjectionType, sliceViewPlane, slicePlane, sliceCoordinates); } } /* * Draw model space annotaitons on the volume slice */ float sliceThickness = 1.0; if ( ! m_volumeDrawInfo.empty()) { if (m_volumeDrawInfo[0].volumeFile != NULL) { float spaceX = 0.0, spaceY = 0.0, spaceZ = 0.0; m_volumeDrawInfo[0].volumeFile->getVoxelSpacing(spaceX, spaceY, spaceZ); switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: sliceThickness = spaceZ; break; case VolumeSliceViewPlaneEnum::CORONAL: sliceThickness = spaceY; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: sliceThickness = spaceX; break; } } } const bool annotationModeFlag = (m_fixedPipelineDrawing->m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, m_fixedPipelineDrawing->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_fixedPipelineDrawing->m_windowIndex, m_fixedPipelineDrawing->windowTabIndex, SpacerTabIndex(), BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, annotationModeFlag); m_fixedPipelineDrawing->m_annotationDrawing->drawModelSpaceAnnotationsOnVolumeSlice(&inputs, slicePlane, sliceThickness); m_fixedPipelineDrawing->disableClippingPlanes(); if (cullFaceOn) { glEnable(GL_CULL_FACE); } } /** * Create the equation for the slice plane * * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * View plane that is displayed. * @param sliceCoordinates * Slice coordinates * @param planeOut * OUTPUT plane of slice after transforms. */ void BrainOpenGLVolumeTextureSliceDrawing::createSlicePlaneEquation(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], Plane& planeOut) { /* * Default the slice normal vector to an orthogonal view */ float sliceNormalVector[3] = { 0.0, 0.0, 0.0 }; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: case VolumeSliceViewPlaneEnum::AXIAL: sliceNormalVector[2] = 1.0; break; case VolumeSliceViewPlaneEnum::CORONAL: sliceNormalVector[1] = -1.0; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: sliceNormalVector[0] = -1.0; break; } switch (sliceProjectionType) { break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: { /* * Transform the slice normal vector by the oblique rotation * matrix so that the normal vector points out of the slice */ const Matrix4x4 obliqueRotationMatrix = m_browserTabContent->getObliqueVolumeRotationMatrix(); obliqueRotationMatrix.multiplyPoint3(sliceNormalVector); MathFunctions::normalizeVector(sliceNormalVector); } break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: break; } Plane plane(sliceNormalVector, sliceCoordinates); planeOut = plane; m_lookAtCenter[0] = sliceCoordinates[0]; m_lookAtCenter[1] = sliceCoordinates[1]; m_lookAtCenter[2] = sliceCoordinates[2]; } ///** // * Set the volume slice viewing transformation. This sets the position and // * orientation of the camera. // * // * @param sliceProjectionType // * Type of projection for the slice drawing (oblique, orthogonal) // * @param sliceViewPlane // * View plane that is displayed. // * @param plane // * Plane equation of selected slice. // * @param sliceCoordinates // * Coordinates of the selected slices. // */ //void //BrainOpenGLVolumeTextureSliceDrawing::setVolumeSliceViewingAndModelingTransformations(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, // const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, // const Plane& plane, // const float sliceCoordinates[3]) //{ // /* // * Initialize the modelview matrix to the identity matrix // * This places the camera at the origin, pointing down the // * negative-Z axis with the up vector set to (0,1,0 => // * positive-Y is up). // */ // glMatrixMode(GL_MODELVIEW); // glLoadIdentity(); // // const float* userTranslation = m_browserTabContent->getTranslation(); // // /* // * Move the camera with the user's translation // */ // float viewTranslationX = 0.0; // float viewTranslationY = 0.0; // float viewTranslationZ = 0.0; // // switch (sliceViewPlane) { // case VolumeSliceViewPlaneEnum::ALL: // case VolumeSliceViewPlaneEnum::AXIAL: // viewTranslationX = sliceCoordinates[0] + userTranslation[0]; // viewTranslationY = sliceCoordinates[1] + userTranslation[1]; // break; // case VolumeSliceViewPlaneEnum::CORONAL: // viewTranslationX = sliceCoordinates[0] + userTranslation[0]; // viewTranslationY = sliceCoordinates[2] + userTranslation[2]; // break; // case VolumeSliceViewPlaneEnum::PARASAGITTAL: // viewTranslationX = -(sliceCoordinates[1] + userTranslation[1]); // viewTranslationY = sliceCoordinates[2] + userTranslation[2]; // break; // } // // glTranslatef(viewTranslationX, // viewTranslationY, // viewTranslationZ); // // // // // glGetDoublev(GL_MODELVIEW_MATRIX, // m_viewingMatrix); // // /* // * Since an orthographic projection is used, the camera only needs // * to be a little bit from the center along the plane's normal vector. // */ // double planeNormal[3]; // plane.getNormalVector(planeNormal); // double cameraXYZ[3] = { // m_lookAtCenter[0] + planeNormal[0] * BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, // m_lookAtCenter[1] + planeNormal[1] * BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, // m_lookAtCenter[2] + planeNormal[2] * BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, // }; // // /* // * Set the up vector which indices which way is up (screen Y) // */ // float up[3] = { 0.0, 0.0, 0.0 }; // switch (sliceViewPlane) { // case VolumeSliceViewPlaneEnum::ALL: // case VolumeSliceViewPlaneEnum::AXIAL: // up[1] = 1.0; // break; // case VolumeSliceViewPlaneEnum::CORONAL: // up[2] = 1.0; // break; // case VolumeSliceViewPlaneEnum::PARASAGITTAL: // up[2] = 1.0; // break; // } // // /* // * For oblique viewing, the up vector needs to be rotated by the // * oblique rotation matrix. // */ // switch (sliceProjectionType) { // case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: // m_browserTabContent->getObliqueVolumeRotationMatrix().multiplyPoint3(up); // break; // case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: // break; // } // // /* // * Now set the camera to look at the selected coordinate (center) // * with the camera offset a little bit from the center. // * This allows the slice's voxels to be drawn in the actual coordinates. // */ // gluLookAt(cameraXYZ[0], cameraXYZ[1], cameraXYZ[2], // m_lookAtCenter[0], m_lookAtCenter[1], m_lookAtCenter[2], // up[0], up[1], up[2]); //} /** * Convert a Matrix4x4 to a glm::mat4 matrix */ glm::mat4 BrainOpenGLVolumeTextureSliceDrawing::convertMatrix4x4toGlmMat4(const Matrix4x4& matrix) const { float m[16]; matrix.getMatrixForOpenGL(m); glm::mat4 out(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13], m[14], m[15]); return out; } /** * Convert a glm::mat4 matrix to an OpenGL matrix */ void BrainOpenGLVolumeTextureSliceDrawing::mat4ToOpenGLMatrix(const glm::mat4& matrixIn, float matrixOut[16]) const { int32_t indx = 0; for (int32_t iRow = 0; iRow < 4; iRow++) { for (int jCol = 0; jCol < 4; jCol++) { matrixOut[indx] = matrixIn[iRow][jCol]; indx++; } } } /** * Set the volume slice viewing transformation. This sets the position and * orientation of the camera. * * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * View plane that is displayed. * @param plane * Plane equation of selected slice. * @param sliceCoordinates * Coordinates of the selected slices. */ void BrainOpenGLVolumeTextureSliceDrawing::setVolumeSliceViewingAndModelingTransformations(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const Plane& plane, const float sliceCoordinates[3]) { /* * Move the camera with the user's translation */ const float* userTranslation = m_browserTabContent->getTranslation(); glm::vec3 translation(0.0); switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: case VolumeSliceViewPlaneEnum::AXIAL: translation[0] = sliceCoordinates[0] + userTranslation[0]; translation[1] = sliceCoordinates[1] + userTranslation[1]; break; case VolumeSliceViewPlaneEnum::CORONAL: translation[0] = sliceCoordinates[0] + userTranslation[0]; translation[1] = sliceCoordinates[2] + userTranslation[2]; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: translation[0] = -(sliceCoordinates[1] + userTranslation[1]); translation[1] = sliceCoordinates[2] + userTranslation[2]; break; } /* * Since an orthographic projection is used, the eye only needs * to be a little bit from the center along the plane's normal vector. */ double planeNormal[3]; plane.getNormalVector(planeNormal); glm::vec3 eye(m_lookAtCenter[0] + planeNormal[0] * BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_lookAtCenter[1] + planeNormal[1] * BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, m_lookAtCenter[2] + planeNormal[2] * BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance); /* * Set the up vector which indices which way is up (screen Y) */ glm::vec4 up(0.0, 0.0, 0.0, 1.0); switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: case VolumeSliceViewPlaneEnum::AXIAL: up[1] = 1.0; break; case VolumeSliceViewPlaneEnum::CORONAL: up[2] = 1.0; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: up[2] = 1.0; break; } switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: { /* * For oblique viewing, the up vector needs to be rotated by the * oblique rotation matrix. */ const Matrix4x4 obMat = m_browserTabContent->getObliqueVolumeRotationMatrix(); const glm::mat4 matrix = convertMatrix4x4toGlmMat4(obMat); up = matrix * up; if (debugFlag) { float upTemp[3] = { up[0], up[1], up[2] }; m_browserTabContent->getObliqueVolumeRotationMatrix().multiplyPoint3(upTemp); float upCopy[3] = { up[0], up[1], up[2] }; const float dist = MathFunctions::distance3D(upTemp, upCopy); if (dist >= 0.01) { std::cout << "Up vectors different by distance: " << dist << std::endl; } } } break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: break; } /* * Now set the camera to look at the selected coordinate (center) * with the camera offset a little bit from the center. * This allows the slice's voxels to be drawn in the actual coordinates. */ // gluLookAt(eye[0], eye[1], eye[2], // m_lookAtCenter[0], m_lookAtCenter[1], m_lookAtCenter[2], // up[0], up[1], up[2]); glm::vec3 lookAt(m_lookAtCenter[0], m_lookAtCenter[1], m_lookAtCenter[2]); glm::mat4 lookAtMatrix = glm::lookAt(eye, lookAt, glm::vec3(up)); glm::mat4 translationMatrix = glm::translate(glm::mat4(1.0), translation); glm::mat4 projMatrix = translationMatrix * lookAtMatrix; glMatrixMode(GL_MODELVIEW); glLoadMatrixf(glm::value_ptr(projMatrix)); } /** * Draw the layers type data. * * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceViewPlane * View plane that is displayed. * @param slicePlane * Plane of the slice. * @param sliceCoordinates * Coordinates of the selected slices. */ void BrainOpenGLVolumeTextureSliceDrawing::drawLayers(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const Plane& slicePlane, const float sliceCoordinates[3]) { bool drawCrosshairsFlag = true; bool drawFibersFlag = true; bool drawFociFlag = true; bool drawOutlineFlag = true; if (m_modelWholeBrain != NULL) { drawCrosshairsFlag = false; drawFibersFlag = false; drawFociFlag = false; } if ( ! m_identificationModeFlag) { if (slicePlane.isValidPlane()) { /* * Disable culling so that both sides of the triangles/quads are drawn. */ GLboolean cullFaceOn = glIsEnabled(GL_CULL_FACE); glDisable(GL_CULL_FACE); glPushMatrix(); GLboolean depthBufferEnabled = false; glGetBooleanv(GL_DEPTH_TEST, &depthBufferEnabled); /* * Use some polygon offset that will adjust the depth values of the * layers so that the layers depth values place the layers in front of * the volume slice. */ glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(0.0, 1.0); if (drawOutlineFlag) { BrainOpenGLVolumeSliceDrawing::drawSurfaceOutline(m_underlayVolume, m_modelType, sliceProjectionType, sliceViewPlane, sliceCoordinates, slicePlane, m_browserTabContent->getVolumeSurfaceOutlineSet(), m_fixedPipelineDrawing, true); } if (drawFibersFlag) { glDisable(GL_DEPTH_TEST); m_fixedPipelineDrawing->drawFiberOrientations(&slicePlane, StructureEnum::ALL); m_fixedPipelineDrawing->drawFiberTrajectories(&slicePlane, StructureEnum::ALL); if (depthBufferEnabled) { glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); } } if (drawFociFlag) { glDisable(GL_DEPTH_TEST); drawVolumeSliceFoci(slicePlane); if (depthBufferEnabled) { glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); } } glDisable(GL_POLYGON_OFFSET_FILL); if (drawCrosshairsFlag) { glPushMatrix(); drawAxesCrosshairs(sliceProjectionType, sliceDrawingType, sliceViewPlane, sliceCoordinates); glPopMatrix(); if (depthBufferEnabled) { glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); } } glPopMatrix(); if (cullFaceOn) { glEnable(GL_CULL_FACE); } } } } /** * Draw foci on volume slice. * * @param plane * Plane of the volume slice on which surface outlines are drawn. */ void BrainOpenGLVolumeTextureSliceDrawing::drawVolumeSliceFoci(const Plane& plane) { SelectionItemFocusVolume* idFocus = m_brain->getSelectionManager()->getVolumeFocusIdentification(); /* * Check for a 'selection' type mode */ bool isSelect = false; switch (m_fixedPipelineDrawing->mode) { case BrainOpenGLFixedPipeline::MODE_DRAWING: break; case BrainOpenGLFixedPipeline::MODE_IDENTIFICATION: if (idFocus->isEnabledForSelection()) { isSelect = true; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } else { return; } break; case BrainOpenGLFixedPipeline::MODE_PROJECTION: return; break; } VolumeMappableInterface* underlayVolume = m_volumeDrawInfo[0].volumeFile; float minVoxelSpacing; float maxVoxelSpacing; if ( ! getMinMaxVoxelSpacing(underlayVolume, minVoxelSpacing, maxVoxelSpacing)) { return; } const float sliceThickness = maxVoxelSpacing; const float halfSliceThickness = sliceThickness * 0.5; const DisplayPropertiesFoci* fociDisplayProperties = m_brain->getDisplayPropertiesFoci(); const DisplayGroupEnum::Enum displayGroup = fociDisplayProperties->getDisplayGroupForTab(m_fixedPipelineDrawing->windowTabIndex); if (fociDisplayProperties->isDisplayed(displayGroup, m_fixedPipelineDrawing->windowTabIndex) == false) { return; } const float focusDiameter = fociDisplayProperties->getFociSize(displayGroup, m_fixedPipelineDrawing->windowTabIndex); const FeatureColoringTypeEnum::Enum fociColoringType = fociDisplayProperties->getColoringType(displayGroup, m_fixedPipelineDrawing->windowTabIndex); const CaretColorEnum::Enum caretColor = fociDisplayProperties->getStandardColorType(displayGroup, m_fixedPipelineDrawing->windowTabIndex); float caretColorRGBA[4]; CaretColorEnum::toRGBAFloat(caretColor, caretColorRGBA); bool drawAsSpheres = false; switch (fociDisplayProperties->getDrawingType(displayGroup, m_fixedPipelineDrawing->windowTabIndex)) { case FociDrawingTypeEnum::DRAW_AS_SPHERES: drawAsSpheres = true; break; case FociDrawingTypeEnum::DRAW_AS_SQUARES: break; } /* * Process each foci file */ const int32_t numberOfFociFiles = m_brain->getNumberOfFociFiles(); for (int32_t iFile = 0; iFile < numberOfFociFiles; iFile++) { FociFile* fociFile = m_brain->getFociFile(iFile); const GroupAndNameHierarchyModel* classAndNameSelection = fociFile->getGroupAndNameHierarchyModel(); if (classAndNameSelection->isSelected(displayGroup, m_fixedPipelineDrawing->windowTabIndex) == false) { continue; } const GiftiLabelTable* classColorTable = fociFile->getClassColorTable(); const GiftiLabelTable* nameColorTable = fociFile->getNameColorTable(); const int32_t numFoci = fociFile->getNumberOfFoci(); for (int32_t j = 0; j < numFoci; j++) { Focus* focus = fociFile->getFocus(j); const GroupAndNameHierarchyItem* groupNameItem = focus->getGroupNameSelectionItem(); if (groupNameItem != NULL) { if (groupNameItem->isSelected(displayGroup, m_fixedPipelineDrawing->windowTabIndex) == false) { continue; } } float rgba[4] = { 0.0, 0.0, 0.0, 1.0 }; switch (fociColoringType) { case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_CLASS: if (focus->isClassRgbaValid() == false) { const GiftiLabel* colorLabel = classColorTable->getLabelBestMatching(focus->getClassName()); if (colorLabel != NULL) { colorLabel->getColor(rgba); focus->setClassRgba(rgba); } else { focus->setClassRgba(rgba); } } focus->getClassRgba(rgba); break; case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_STANDARD_COLOR: rgba[0] = caretColorRGBA[0]; rgba[1] = caretColorRGBA[1]; rgba[2] = caretColorRGBA[2]; rgba[3] = caretColorRGBA[3]; break; case FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_NAME: if (focus->isNameRgbaValid() == false) { const GiftiLabel* colorLabel = nameColorTable->getLabelBestMatching(focus->getName()); if (colorLabel != NULL) { colorLabel->getColor(rgba); focus->setNameRgba(rgba); } else { focus->setNameRgba(rgba); } } focus->getNameRgba(rgba); break; } const int32_t numProjections = focus->getNumberOfProjections(); for (int32_t k = 0; k < numProjections; k++) { const SurfaceProjectedItem* spi = focus->getProjection(k); if (spi->isVolumeXYZValid()) { float xyz[3]; spi->getVolumeXYZ(xyz); bool drawIt = false; if (plane.absoluteDistanceToPlane(xyz) < halfSliceThickness) { drawIt = true; } if (drawIt) { glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); if (isSelect) { uint8_t idRGBA[4]; m_fixedPipelineDrawing->colorIdentification->addItem(idRGBA, SelectionItemDataTypeEnum::FOCUS_VOLUME, iFile, // file index j, // focus index k);// projection index idRGBA[3] = 255; if (drawAsSpheres) { m_fixedPipelineDrawing->drawSphereWithDiameter(idRGBA, focusDiameter); } else { glColor4ubv(idRGBA); drawSquare(focusDiameter); } } else { if (drawAsSpheres) { m_fixedPipelineDrawing->drawSphereWithDiameter(rgba, focusDiameter); } else { glColor3fv(rgba); drawSquare(focusDiameter); } } glPopMatrix(); } } } } } if (isSelect) { int32_t fociFileIndex = -1; int32_t focusIndex = -1; int32_t focusProjectionIndex = -1; float depth = -1.0; m_fixedPipelineDrawing->getIndexFromColorSelection(SelectionItemDataTypeEnum::FOCUS_VOLUME, m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, fociFileIndex, focusIndex, focusProjectionIndex, depth); if (fociFileIndex >= 0) { if (idFocus->isOtherScreenDepthCloserToViewer(depth)) { Focus* focus = m_brain->getFociFile(fociFileIndex)->getFocus(focusIndex); idFocus->setBrain(m_brain); idFocus->setFocus(focus); idFocus->setFociFile(m_brain->getFociFile(fociFileIndex)); idFocus->setFocusIndex(focusIndex); idFocus->setFocusProjectionIndex(focusProjectionIndex); idFocus->setVolumeFile(underlayVolume); idFocus->setScreenDepth(depth); float xyz[3]; const SurfaceProjectedItem* spi = focus->getProjection(focusProjectionIndex); spi->getVolumeXYZ(xyz); m_fixedPipelineDrawing->setSelectedItemScreenXYZ(idFocus, xyz); CaretLogFine("Selected Volume Focus Identification Symbol: " + QString::number(focusIndex)); } } } } /** * Draw the axes crosshairs. * * @param sliceProjectionType * Type of projection for the slice drawing (oblique, orthogonal) * @param sliceDrawingType * Type of slice drawing (montage, single) * @param sliceViewPlane * View plane that is displayed. * @param sliceCoordinates * Coordinates of the selected slices. */ void BrainOpenGLVolumeTextureSliceDrawing::drawAxesCrosshairs(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3]) { const bool drawCrosshairsFlag = m_browserTabContent->isVolumeAxesCrosshairsDisplayed(); bool drawCrosshairLabelsFlag = m_browserTabContent->isVolumeAxesCrosshairLabelsDisplayed(); switch (sliceDrawingType) { case VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_MONTAGE: drawCrosshairLabelsFlag = false; break; case VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE: break; } switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: // break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: { glPushMatrix(); glLoadIdentity(); drawAxesCrosshairsOblique(sliceViewPlane, sliceCoordinates, drawCrosshairsFlag, drawCrosshairLabelsFlag); glPopMatrix(); } break; } } /** * Draw the axes crosshairs for an orthogonal slice. * * @param sliceViewPlane * The slice plane view. * @param sliceCoordinatesIn * Coordinates of the selected slices. * @param drawCrosshairsFlag * If true, draw the crosshairs. * @param drawCrosshairLabelsFlag * If true, draw the crosshair labels. */ void BrainOpenGLVolumeTextureSliceDrawing::drawAxesCrosshairsOblique(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinatesIn[3], const bool drawCrosshairsFlag, const bool drawCrosshairLabelsFlag) { const float gapPercentViewportHeight = SessionManager::get()->getCaretPreferences()->getVolumeCrosshairGap(); const float gapMM = GraphicsUtilitiesOpenGL::convertPercentageOfViewportHeightToMillimeters(gapPercentViewportHeight); const std::array sliceCoordinates = { sliceCoordinatesIn[0], sliceCoordinatesIn[1], sliceCoordinatesIn[2] }; GLboolean depthEnabled = GL_FALSE; glGetBooleanv(GL_DEPTH_TEST, &depthEnabled); glDisable(GL_DEPTH_TEST); const float bigValue = 10000.0 + gapMM; std::array horizontalAxisPosStartXYZ = sliceCoordinates; float trans[3]; m_browserTabContent->getTranslation(trans); std::array horizTrans = { trans[0], trans[1], trans[2] }; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: break; case VolumeSliceViewPlaneEnum::AXIAL: break; case VolumeSliceViewPlaneEnum::CORONAL: horizontalAxisPosStartXYZ[0] = sliceCoordinates[0]; horizontalAxisPosStartXYZ[1] = sliceCoordinates[2]; horizontalAxisPosStartXYZ[2] = sliceCoordinates[1]; horizTrans[0] = trans[0]; horizTrans[1] = trans[2]; horizTrans[2] = trans[1]; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: horizontalAxisPosStartXYZ[0] = -sliceCoordinates[1]; horizontalAxisPosStartXYZ[1] = sliceCoordinates[2]; horizontalAxisPosStartXYZ[2] = sliceCoordinates[0]; horizTrans[0] = -trans[1]; horizTrans[1] = trans[2]; horizTrans[2] = trans[0]; break; } std::array horizontalAxisPosEndXYZ = horizontalAxisPosStartXYZ; std::array verticalAxisPosStartXYZ = horizontalAxisPosStartXYZ; std::array verticalAxisPosEndXYZ = horizontalAxisPosStartXYZ; std::array horizontalAxisNegStartXYZ = horizontalAxisPosStartXYZ; std::array horizontalAxisNegEndXYZ = horizontalAxisPosEndXYZ; std::array verticalAxisNegStartXYZ = verticalAxisPosStartXYZ; std::array verticalAxisNegEndXYZ = verticalAxisPosEndXYZ; std::array vertTrans = horizTrans; float axialRGBA[4]; getAxesColor(VolumeSliceViewPlaneEnum::AXIAL, axialRGBA); float coronalRGBA[4]; getAxesColor(VolumeSliceViewPlaneEnum::CORONAL, coronalRGBA); float paraRGBA[4]; getAxesColor(VolumeSliceViewPlaneEnum::PARASAGITTAL, paraRGBA); AString horizontalLeftText = ""; AString horizontalRightText = ""; AString verticalBottomText = ""; AString verticalTopText = ""; float* horizontalAxisRGBA = axialRGBA; float* verticalAxisRGBA = axialRGBA; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: break; case VolumeSliceViewPlaneEnum::AXIAL: horizontalLeftText = "L"; horizontalRightText = "R"; horizontalAxisRGBA = coronalRGBA; horizontalAxisPosStartXYZ[0] += gapMM; horizontalAxisPosEndXYZ[0] += bigValue; horizontalAxisNegStartXYZ[0] -= gapMM; horizontalAxisNegEndXYZ[0] -= bigValue; verticalBottomText = "P"; verticalTopText = "A"; verticalAxisRGBA = paraRGBA; verticalAxisPosStartXYZ[1] += gapMM; verticalAxisPosEndXYZ[1] += bigValue; verticalAxisNegStartXYZ[1] -= gapMM; verticalAxisNegEndXYZ[1] -= bigValue; break; case VolumeSliceViewPlaneEnum::CORONAL: horizontalLeftText = "L"; horizontalRightText = "R"; horizontalAxisRGBA = axialRGBA; horizontalAxisPosStartXYZ[0] += gapMM; horizontalAxisPosEndXYZ[0] += bigValue; horizontalAxisNegStartXYZ[0] -= gapMM; horizontalAxisNegEndXYZ[0] -= bigValue; verticalBottomText = "I"; verticalTopText = "S"; verticalAxisRGBA = paraRGBA; verticalAxisPosStartXYZ[1] += gapMM; verticalAxisPosEndXYZ[1] += bigValue; verticalAxisNegStartXYZ[1] -= gapMM; verticalAxisNegEndXYZ[1] -= bigValue; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: horizontalLeftText = "A"; horizontalRightText = "P"; horizontalAxisRGBA = axialRGBA; horizontalAxisPosStartXYZ[0] += gapMM; horizontalAxisPosEndXYZ[0] += bigValue; horizontalAxisNegStartXYZ[0] -= gapMM; horizontalAxisNegEndXYZ[0] -= bigValue; verticalBottomText = "I"; verticalTopText = "S"; verticalAxisRGBA = coronalRGBA; verticalAxisPosStartXYZ[1] += gapMM; verticalAxisPosEndXYZ[1] += bigValue; verticalAxisNegStartXYZ[1] -= gapMM; verticalAxisNegEndXYZ[1] -= bigValue; break; } /* * Offset text labels be a percentage of viewort width/height */ GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); const int textOffsetX = viewport[2] * 0.01f; const int textOffsetY = viewport[3] * 0.01f; const int textLeftWindowXY[2] = { textOffsetX, (viewport[3] / 2) }; const int textRightWindowXY[2] = { viewport[2] - textOffsetX, (viewport[3] / 2) }; const int textBottomWindowXY[2] = { viewport[2] / 2, textOffsetY }; const int textTopWindowXY[2] = { (viewport[2] / 2), viewport[3] - textOffsetY }; /* * Crosshairs */ if (drawCrosshairsFlag) { glPushMatrix(); glTranslatef(horizTrans[0], horizTrans[1], horizTrans[2]); std::unique_ptr horizHairPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); horizHairPrimitive->addVertex(&horizontalAxisPosStartXYZ[0], horizontalAxisRGBA); horizHairPrimitive->addVertex(&horizontalAxisPosEndXYZ[0], horizontalAxisRGBA); horizHairPrimitive->addVertex(&horizontalAxisNegStartXYZ[0], horizontalAxisRGBA); horizHairPrimitive->addVertex(&horizontalAxisNegEndXYZ[0], horizontalAxisRGBA); horizHairPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); GraphicsEngineDataOpenGL::draw(horizHairPrimitive.get()); glPopMatrix(); glPushMatrix(); glTranslatef(vertTrans[0], vertTrans[1], vertTrans[2]); std::unique_ptr vertHairPrimitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES)); vertHairPrimitive->addVertex(&verticalAxisPosStartXYZ[0], verticalAxisRGBA); vertHairPrimitive->addVertex(&verticalAxisPosEndXYZ[0], verticalAxisRGBA); vertHairPrimitive->addVertex(&verticalAxisNegStartXYZ[0], verticalAxisRGBA); vertHairPrimitive->addVertex(&verticalAxisNegEndXYZ[0], verticalAxisRGBA); vertHairPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); GraphicsEngineDataOpenGL::draw(vertHairPrimitive.get()); glPopMatrix(); } if (drawCrosshairLabelsFlag) { const AnnotationTextFontPointSizeEnum::Enum fontSize = AnnotationTextFontPointSizeEnum::SIZE18; const int textCenter[2] = { textLeftWindowXY[0], textLeftWindowXY[1] }; const int halfFontSize = AnnotationTextFontPointSizeEnum::toSizeNumeric(fontSize) / 2; uint8_t backgroundRGBA[4] = { m_fixedPipelineDrawing->m_backgroundColorByte[0], m_fixedPipelineDrawing->m_backgroundColorByte[1], m_fixedPipelineDrawing->m_backgroundColorByte[2], m_fixedPipelineDrawing->m_backgroundColorByte[3] }; GLint savedViewport[4]; glGetIntegerv(GL_VIEWPORT, savedViewport); int vpLeftX = savedViewport[0] + textCenter[0] - halfFontSize; int vpRightX = savedViewport[0] + textCenter[0] + halfFontSize; int vpBottomY = savedViewport[1] + textCenter[1] - halfFontSize; int vpTopY = savedViewport[1] + textCenter[1] + halfFontSize; MathFunctions::limitRange(vpLeftX, savedViewport[0], savedViewport[0] + savedViewport[2]); MathFunctions::limitRange(vpRightX, savedViewport[0], savedViewport[0] + savedViewport[2]); MathFunctions::limitRange(vpBottomY, savedViewport[1], savedViewport[1] + savedViewport[3]); MathFunctions::limitRange(vpTopY, savedViewport[1], savedViewport[1] + savedViewport[3]); const int vpSizeX = vpRightX - vpLeftX; const int vpSizeY = vpTopY - vpBottomY; glViewport(vpLeftX, vpBottomY, vpSizeX, vpSizeY); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); std::vector rgba; std::vector coords, normals; coords.push_back(-1.0); coords.push_back(-1.0); coords.push_back( 0.0); normals.push_back(0.0); normals.push_back(0.0); normals.push_back(1.0); rgba.push_back(backgroundRGBA[0]); rgba.push_back(backgroundRGBA[1]); rgba.push_back(backgroundRGBA[2]); rgba.push_back(backgroundRGBA[3]); coords.push_back( 1.0); coords.push_back(-1.0); coords.push_back( 0.0); normals.push_back(0.0); normals.push_back(0.0); normals.push_back(1.0); rgba.push_back(backgroundRGBA[0]); rgba.push_back(backgroundRGBA[1]); rgba.push_back(backgroundRGBA[2]); rgba.push_back(backgroundRGBA[3]); coords.push_back( 1.0); coords.push_back( 1.0); coords.push_back( 0.0); normals.push_back(0.0); normals.push_back(0.0); normals.push_back(1.0); rgba.push_back(backgroundRGBA[0]); rgba.push_back(backgroundRGBA[1]); rgba.push_back(backgroundRGBA[2]); rgba.push_back(backgroundRGBA[3]); coords.push_back(-1.0); coords.push_back( 1.0); coords.push_back( 0.0); normals.push_back(0.0); normals.push_back(0.0); normals.push_back(1.0); rgba.push_back(backgroundRGBA[0]); rgba.push_back(backgroundRGBA[1]); rgba.push_back(backgroundRGBA[2]); rgba.push_back(backgroundRGBA[3]); BrainOpenGLPrimitiveDrawing::drawQuads(coords, normals, rgba); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glViewport(savedViewport[0], savedViewport[1], savedViewport[2], savedViewport[3]); AnnotationPercentSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); annotationText.setBoldStyleEnabled(true); annotationText.setFontPercentViewportSize(5.0f); annotationText.setTextColor(CaretColorEnum::CUSTOM); annotationText.setBackgroundColor(CaretColorEnum::CUSTOM); annotationText.setCustomTextColor(horizontalAxisRGBA); annotationText.setCustomBackgroundColor(backgroundRGBA); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::LEFT); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); annotationText.setText(horizontalLeftText); m_fixedPipelineDrawing->drawTextAtViewportCoords(textLeftWindowXY[0], textLeftWindowXY[1], annotationText); annotationText.setText(horizontalRightText); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::RIGHT); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); m_fixedPipelineDrawing->drawTextAtViewportCoords(textRightWindowXY[0], textRightWindowXY[1], annotationText); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::BOTTOM); annotationText.setCustomTextColor(verticalAxisRGBA); annotationText.setText(verticalBottomText); m_fixedPipelineDrawing->drawTextAtViewportCoords(textBottomWindowXY[0], textBottomWindowXY[1], annotationText); annotationText.setText(verticalTopText); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::TOP); annotationText.getCoordinate()->setXYZ(textTopWindowXY[0], textTopWindowXY[1], 0.0); m_fixedPipelineDrawing->drawTextAtViewportCoords(textTopWindowXY[0], textTopWindowXY[1], annotationText); } if (depthEnabled) { glEnable(GL_DEPTH_TEST); } } /** * Get the RGBA coloring for a slice view plane. * * @param sliceViewPlane * The slice view plane. * @param rgbaOut * Output colors ranging 0.0 to 1.0 */ void BrainOpenGLVolumeTextureSliceDrawing::getAxesColor(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, float rgbaOut[4]) const { switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: rgbaOut[0] = 0.0; rgbaOut[1] = 0.0; rgbaOut[2] = 1.0; rgbaOut[3] = 1.0; break; case VolumeSliceViewPlaneEnum::CORONAL: rgbaOut[0] = 0.0; rgbaOut[1] = 1.0; rgbaOut[2] = 0.0; rgbaOut[3] = 1.0; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: rgbaOut[0] = 1.0; rgbaOut[1] = 0.0; rgbaOut[2] = 0.0; rgbaOut[3] = 1.0; break; } } /** * Draw a one millimeter square facing the user. * NOTE: This method will alter the current * modelviewing matrices so caller may need * to enclose the call to this method within * glPushMatrix() and glPopMatrix(). * * @param size * Size of square. */ void BrainOpenGLVolumeTextureSliceDrawing::drawSquare(const float size) { const float length = size * 0.5; /* * Draw both front and back side since in some instances, * such as surface montage, we are viweing from the far * side (from back of monitor) */ glBegin(GL_QUADS); glNormal3f(0.0, 0.0, 1.0); glVertex3f(-length, -length, 0.0); glVertex3f( length, -length, 0.0); glVertex3f( length, length, 0.0); glVertex3f(-length, length, 0.0); glNormal3f(0.0, 0.0, -1.0); glVertex3f(-length, -length, 0.0); glVertex3f(-length, length, 0.0); glVertex3f( length, length, 0.0); glVertex3f( length, -length, 0.0); glEnd(); } /** * Get the minimum and maximum distance between adjacent voxels in all * slices planes. Output spacing value are always non-negative even if * a right-to-left orientation. * * @param volume * Volume for which min/max spacing is requested. * @param minSpacingOut * Output minimum spacing. * @param maxSpacingOut * Output maximum spacing. * @return * True if min and max spacing are greater than zero. */ bool BrainOpenGLVolumeTextureSliceDrawing::getMinMaxVoxelSpacing(const VolumeMappableInterface* volume, float& minSpacingOut, float& maxSpacingOut) const { CaretAssert(volume); float originX, originY, originZ; float x1, y1, z1; volume->indexToSpace(0, 0, 0, originX, originY, originZ); volume->indexToSpace(1, 1, 1, x1, y1, z1); const float dx = std::fabs(x1 - originX); const float dy = std::fabs(y1 - originY); const float dz = std::fabs(z1 - originZ); minSpacingOut = std::min(std::min(dx, dy), dz); maxSpacingOut = std::max(std::max(dx, dy), dz); if ((minSpacingOut > 0.0) && (maxSpacingOut > 0.0)) { return true; } return false; } /** * Draw orientation axes * * @param viewport * The viewport region for the orientation axes. */ void BrainOpenGLVolumeTextureSliceDrawing::drawOrientationAxes(const int viewport[4]) { const bool drawCylindersFlag = m_browserTabContent->isVolumeAxesCrosshairsDisplayed(); const bool drawLabelsFlag = m_browserTabContent->isVolumeAxesCrosshairLabelsDisplayed(); /* * Set the viewport */ glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); const double viewportWidth = viewport[2]; const double viewportHeight = viewport[3]; /* * Determine bounds for orthographic projection */ const double maxCoord = 100.0; const double minCoord = -maxCoord; double left = 0.0; double right = 0.0; double top = 0.0; double bottom = 0.0; const double nearDepth = -1000.0; const double farDepth = 1000.0; if (viewportHeight > viewportWidth) { left = minCoord; right = maxCoord; const double aspectRatio = (viewportHeight / viewportWidth); top = maxCoord * aspectRatio; bottom = minCoord * aspectRatio; } else { const double aspectRatio = (viewportWidth / viewportHeight); top = maxCoord; bottom = minCoord; left = minCoord * aspectRatio; right = maxCoord * aspectRatio; } /* * Set the orthographic projection */ glMatrixMode(GL_PROJECTION); glPushMatrix(); // glLoadIdentity(); // glOrtho(left, right, // bottom, top, // nearDepth, farDepth); glm::mat4 orthoMatrix = glm::ortho(left, right, bottom, top, nearDepth, farDepth); glLoadMatrixf(glm::value_ptr(orthoMatrix)); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); { /* * Set the viewing transformation, places 'eye' so that it looks * at the 'model' which is, in this case, the axes */ const glm::vec3 eyeXYZ(0.0, 0.0, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance); const glm::vec3 lookAtXYZ(0.0, 0.0, 0.0); const glm::vec3 upVector(0.0, 1.0, 0.0); glm::mat4 lookAtMatrix = glm::lookAt(eyeXYZ, lookAtXYZ, upVector); /* * Set the modeling transformation */ const Matrix4x4 obliqueRotationMatrix = m_browserTabContent->getObliqueVolumeRotationMatrix(); const glm::mat4 obliqueMat4 = convertMatrix4x4toGlmMat4(obliqueRotationMatrix); const glm::mat4 modelMatrix = lookAtMatrix * obliqueMat4; glLoadMatrixf(glm::value_ptr(modelMatrix)); /* * Disable depth buffer. Otherwise, when volume slices are drawn * black regions of the slices may set depth buffer and the occlude * the axes from display. */ GLboolean depthBufferEnabled = false; glGetBooleanv(GL_DEPTH_TEST, &depthBufferEnabled); glDisable(GL_DEPTH_TEST); const float red[4] = { 1.0, 0.0, 0.0, 1.0 }; const float green[4] = { 0.0, 1.0, 0.0, 1.0 }; const float blue[4] = { 0.0, 0.0, 1.0, 1.0 }; const double axisMaxCoord = maxCoord * 0.8; const double axisMinCoord = -axisMaxCoord; const double textMaxCoord = maxCoord * 0.9; const double textMinCoord = -textMaxCoord; const float axialPlaneMin[3] = { 0.0, 0.0, (float)axisMinCoord }; const float axialPlaneMax[3] = { 0.0, 0.0, (float)axisMaxCoord }; const double axialTextMin[3] = { 0.0, 0.0, (float)textMinCoord }; const double axialTextMax[3] = { 0.0, 0.0, (float)textMaxCoord }; const float coronalPlaneMin[3] = { (float)axisMinCoord, 0.0, 0.0 }; const float coronalPlaneMax[3] = { (float)axisMaxCoord, 0.0, 0.0 }; const double coronalTextMin[3] = { (float)textMinCoord, 0.0, 0.0 }; const double coronalTextMax[3] = { (float)textMaxCoord, 0.0, 0.0 }; const float paraPlaneMin[3] = { 0.0, (float)axisMinCoord, 0.0 }; const float paraPlaneMax[3] = { 0.0, (float)axisMaxCoord, 0.0 }; const double paraTextMin[3] = { 0.0, (float)textMinCoord, 0.0 }; const double paraTextMax[3] = { 0.0, (float)textMaxCoord, 0.0 }; /* * Set radius as percentage of viewport height */ float axesCrosshairRadius = 1.0; if (viewportHeight > 0) { const float percentageRadius = 0.005f; axesCrosshairRadius = percentageRadius * viewportHeight; } if (drawCylindersFlag) { m_fixedPipelineDrawing->drawCylinder(blue, axialPlaneMin, axialPlaneMax, axesCrosshairRadius * 0.5f); } AnnotationPercentSizeText annotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); annotationText.setHorizontalAlignment(AnnotationTextAlignHorizontalEnum::CENTER); annotationText.setVerticalAlignment(AnnotationTextAlignVerticalEnum::MIDDLE); annotationText.setFontPercentViewportSize(5.0f); annotationText.setCoordinateSpace(AnnotationCoordinateSpaceEnum::STEREOTAXIC); annotationText.setTextColor(CaretColorEnum::CUSTOM); if (drawLabelsFlag) { annotationText.setCustomTextColor(blue); annotationText.setText("I"); m_fixedPipelineDrawing->drawTextAtModelCoords(axialTextMin, annotationText); annotationText.setText("S"); m_fixedPipelineDrawing->drawTextAtModelCoords(axialTextMax, annotationText); } if (drawCylindersFlag) { m_fixedPipelineDrawing->drawCylinder(green, coronalPlaneMin, coronalPlaneMax, axesCrosshairRadius * 0.5f); } if (drawLabelsFlag) { annotationText.setCustomTextColor(green); annotationText.setText("L"); m_fixedPipelineDrawing->drawTextAtModelCoords(coronalTextMin, annotationText); annotationText.setText("R"); m_fixedPipelineDrawing->drawTextAtModelCoords(coronalTextMax, annotationText); } if (drawCylindersFlag) { m_fixedPipelineDrawing->drawCylinder(red, paraPlaneMin, paraPlaneMax, axesCrosshairRadius * 0.5f); } if (drawLabelsFlag) { annotationText.setCustomTextColor(red); annotationText.setText("P"); m_fixedPipelineDrawing->drawTextAtModelCoords(paraTextMin, annotationText); annotationText.setText("A"); m_fixedPipelineDrawing->drawTextAtModelCoords(paraTextMax, annotationText); } } glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } /** * Set the orthographic projection. * * @param allSliceViewMode * Indicates drawing of ALL slices volume view (axial, coronal, parasagittal in one view) * @param sliceViewPlane * View plane that is displayed. * @param viewport * The viewport. */ void BrainOpenGLVolumeTextureSliceDrawing::setOrthographicProjection(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const int viewport[4]) { const bool useOrthosDrawingProjectionFlag = false; /* does not work as expected when oblique */ if (useOrthosDrawingProjectionFlag) { /* * Determine model size in screen Y when viewed */ BoundingBox boundingBox; m_volumeDrawInfo[0].volumeFile->getVoxelSpaceBoundingBox(boundingBox); const double zoomFactor = m_browserTabContent->getScaling(); BrainOpenGLVolumeSliceDrawing::setOrthographicProjection(allSliceViewMode, sliceViewPlane, boundingBox, zoomFactor, viewport, m_orthographicBounds); return; } /* * Determine model size in screen Y when viewed */ BoundingBox boundingBox; m_volumeDrawInfo[0].volumeFile->getVoxelSpaceBoundingBox(boundingBox); /* * Set top and bottom to the min/max coordinate * that runs vertically on the screen */ double modelTop = 200.0; double modelBottom = -200.0; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssertMessage(0, "Should never get here"); break; case VolumeSliceViewPlaneEnum::AXIAL: modelTop = boundingBox.getMaxY(); modelBottom = boundingBox.getMinY(); break; case VolumeSliceViewPlaneEnum::CORONAL: modelTop = boundingBox.getMaxZ(); modelBottom = boundingBox.getMinZ(); break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: modelTop = boundingBox.getMaxZ(); modelBottom = boundingBox.getMinZ(); break; } switch (allSliceViewMode) { case BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_YES: { /* * Parasagittal and Coronal Views have Brain's Z-axis in Screen Y * Axial View has Brain's Y-axis in Screen Y * So, use maximum of Brain's Y- and Z-axes for sizing height of slice * so that voxels are same size for each slice in each axis view */ const float maxRangeYZ = std::max(boundingBox.getDifferenceY(), boundingBox.getDifferenceZ()); const float range = modelTop - modelBottom; if (maxRangeYZ > range) { const float diff = maxRangeYZ - range; const float halfDiff = diff / 2.0; modelTop += halfDiff; modelBottom -= halfDiff; } } break; case BrainOpenGLVolumeSliceDrawing::AllSliceViewMode::ALL_NO: break; } /* * Scale ratio makes region slightly larger than model */ const double zoom = m_browserTabContent->getScaling(); double scaleRatio = (1.0 / 0.98); if (zoom > 0.0) { scaleRatio /= zoom; } modelTop *= scaleRatio; modelBottom *= scaleRatio; /* * Determine aspect ratio of viewport */ const double viewportWidth = viewport[2]; const double viewportHeight = viewport[3]; const double aspectRatio = (viewportWidth / viewportHeight); /* * Set bounds of orthographic projection */ const double halfModelY = ((modelTop - modelBottom) / 2.0); const double orthoBottom = modelBottom; const double orthoTop = modelTop; const double orthoRight = halfModelY * aspectRatio; const double orthoLeft = -halfModelY * aspectRatio; const double nearDepth = -1000.0; const double farDepth = 1000.0; m_orthographicBounds[0] = orthoLeft; m_orthographicBounds[1] = orthoRight; m_orthographicBounds[2] = orthoBottom; m_orthographicBounds[3] = orthoTop; m_orthographicBounds[4] = nearDepth; m_orthographicBounds[5] = farDepth; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(m_orthographicBounds[0], m_orthographicBounds[1], m_orthographicBounds[2], m_orthographicBounds[3], m_orthographicBounds[4], m_orthographicBounds[5]); glMatrixMode(GL_MODELVIEW); } /** * Get the maximum bounds that enclose the volumes and the minimum * voxel spacing from the volumes. * * @param boundsOut * Bounds of the volumes. * @param spacingOut * Minimum voxel spacing from the volumes. Always positive values (even if * volumes is oriented right to left). * */ bool BrainOpenGLVolumeTextureSliceDrawing::getVoxelCoordinateBoundsAndSpacing(float boundsOut[6], float spacingOut[3]) { const int32_t numberOfVolumesToDraw = static_cast(m_volumeDrawInfo.size()); if (numberOfVolumesToDraw <= 0) { return false; } /* * Find maximum extent of all voxels and smallest voxel * size in each dimension. */ float minVoxelX = std::numeric_limits::max(); float maxVoxelX = -std::numeric_limits::max(); float minVoxelY = std::numeric_limits::max(); float maxVoxelY = -std::numeric_limits::max(); float minVoxelZ = std::numeric_limits::max(); float maxVoxelZ = -std::numeric_limits::max(); float voxelStepX = std::numeric_limits::max(); float voxelStepY = std::numeric_limits::max(); float voxelStepZ = std::numeric_limits::max(); for (int32_t i = 0; i < numberOfVolumesToDraw; i++) { const VolumeMappableInterface* volumeFile = m_volumeDrawInfo[i].volumeFile; int64_t dimI, dimJ, dimK, numMaps, numComponents; volumeFile->getDimensions(dimI, dimJ, dimK, numMaps, numComponents); float originX, originY, originZ; float x1, y1, z1; float lastX, lastY, lastZ; volumeFile->indexToSpace(0, 0, 0, originX, originY, originZ); volumeFile->indexToSpace(1, 1, 1, x1, y1, z1); volumeFile->indexToSpace(dimI - 1, dimJ - 1, dimK - 1, lastX, lastY, lastZ); const float dx = x1 - originX; const float dy = y1 - originY; const float dz = z1 - originZ; voxelStepX = std::min(voxelStepX, std::fabs(dx)); voxelStepY = std::min(voxelStepY, std::fabs(dy)); voxelStepZ = std::min(voxelStepZ, std::fabs(dz)); minVoxelX = std::min(minVoxelX, std::min(originX, lastX)); maxVoxelX = std::max(maxVoxelX, std::max(originX, lastX)); minVoxelY = std::min(minVoxelY, std::min(originY, lastY)); maxVoxelY = std::max(maxVoxelY, std::max(originY, lastY)); minVoxelZ = std::min(minVoxelZ, std::min(originZ, lastZ)); maxVoxelZ = std::max(maxVoxelZ, std::max(originZ, lastZ)); } boundsOut[0] = minVoxelX; boundsOut[1] = maxVoxelX; boundsOut[2] = minVoxelY; boundsOut[3] = maxVoxelY; boundsOut[4] = minVoxelZ; boundsOut[5] = maxVoxelZ; spacingOut[0] = voxelStepX; spacingOut[1] = voxelStepY; spacingOut[2] = voxelStepZ; /* * Two dimensions: single slice * Three dimensions: multiple slices */ int32_t validDimCount = 0; if (maxVoxelX > minVoxelX) validDimCount++; if (maxVoxelY > minVoxelY) validDimCount++; if (maxVoxelZ > minVoxelZ) validDimCount++; bool valid = false; if ((validDimCount >= 2) && (voxelStepX > 0.0) && (voxelStepY > 0.0) && (voxelStepZ > 0.0)) { valid = true; } return valid; } /** * Create the oblique transformation matrix. * * @parm sliceProjectionType * The slice projection type * @param sliceCoordinates * Slice that is being drawn. * @param obliqueTransformationMatrixOut * OUTPUT transformation matrix for oblique viewing. */ void BrainOpenGLVolumeTextureSliceDrawing::createObliqueTransformationMatrix(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const float sliceCoordinates[3], Matrix4x4& obliqueTransformationMatrixOut) { /* * Initialize the oblique transformation matrix */ obliqueTransformationMatrixOut.identity(); switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: { /* * Get the oblique rotation matrix */ Matrix4x4 obliqueRotationMatrix = m_browserTabContent->getObliqueVolumeRotationMatrix(); /* * Create the transformation matrix */ obliqueTransformationMatrixOut.postmultiply(obliqueRotationMatrix); } break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: break; } /* * Translate to selected coordinate */ obliqueTransformationMatrixOut.translate(sliceCoordinates[0], sliceCoordinates[1], sliceCoordinates[2]); } /* ======================================================================= */ /** * Get the texture coordinates for an XYZ-coordinate * * @param volumeMappableInterface * The volume file * @param xyz * The XYZ coordinate * @param maxStr * The maximum texture str coordinate * @param strOut * Output texture str coordinate * @return * True if output coordinate is valid, else false. */ bool BrainOpenGLVolumeTextureSliceDrawing::getTextureCoordinates(const VolumeMappableInterface* volumeMappableInterface, const std::array& xyz, const std::array& maxStr, std::array& strOut) const { std::vector dims(5); volumeMappableInterface->getDimensions(dims); // int64_t smallCornerIJK[3] = { 0, 0, 0}; // float smallCornerXYZ[3] = { 0.0, 0.0, 0.0 }; // volumeMappableInterface->indexToSpace(smallCornerIJK, smallCornerXYZ); // // int64_t bigCornerIJK[3] = { dims[0] - 1, dims[1] - 1, dims[2] - 1 }; // float bigCornerXYZ[3] = { 0.0, 0.0, 0.0 }; // volumeMappableInterface->indexToSpace(bigCornerIJK, bigCornerXYZ); // // /* // * Coordinates from volume are at CENTER of the voxel // * so increase size of volume so that range is from // * outside edge to outside edge of the volume. // */ // float voxelOneXYZ[3]; // volumeMappableInterface->indexToSpace(0, 0, 0, voxelOneXYZ); // float voxelTwoXYZ[3]; // volumeMappableInterface->indexToSpace(1, 1, 1, voxelTwoXYZ); // const float halfVoxelSizeXYZ[3] { // (voxelTwoXYZ[0] - voxelOneXYZ[0]) / 2.0f, // (voxelTwoXYZ[1] - voxelOneXYZ[1]) / 2.0f, // (voxelTwoXYZ[2] - voxelOneXYZ[2]) / 2.0f, // }; // for (int32_t i = 0; i < 3; i++) { // smallCornerXYZ[i] -= halfVoxelSizeXYZ[i]; // bigCornerXYZ[i] += halfVoxelSizeXYZ[i]; // } // // const float rangeXYZ[3] = { // (bigCornerXYZ[0] - smallCornerXYZ[0]), // (bigCornerXYZ[1] - smallCornerXYZ[1]), // (bigCornerXYZ[2] - smallCornerXYZ[2]) // }; // // const float normalizedOffset[3] = { // (xyz[0] - smallCornerXYZ[0]) / rangeXYZ[0], // (xyz[1] - smallCornerXYZ[1]) / rangeXYZ[1], // (xyz[2] - smallCornerXYZ[2]) / rangeXYZ[2], // }; // // strOut[0] = normalizedOffset[0] * maxStr[0]; // strOut[1] = normalizedOffset[1] * maxStr[1]; // strOut[2] = normalizedOffset[2] * maxStr[2]; { const VolumeSpace& volumeSpace = volumeMappableInterface->getVolumeSpace(); std::array ijk; volumeSpace.spaceToIndex(xyz.data(), ijk.data()); const std::array normalizedIJK { (ijk[0] / dims[0]), (ijk[1] / dims[1]), (ijk[2] / dims[2]) }; std::array str { (normalizedIJK[0] * maxStr[0]), (normalizedIJK[1] * maxStr[1]), (normalizedIJK[2] * maxStr[2]) }; strOut = str; } return true; } /** * Create RGBA coloring for volume's texture * * @param volumeMappableInterface * The volume file * @param displayGroup * Display group for current tab * @param tabIndex * Index of tab * @param allowNonPowerOfTwoTextureFlag * Allow non power-of-two texture * @param identificationTextureFlag * True if creating texture for voxel identification * @param rgbaColorsOut * Output containing RGBA coloring * @param textureDimsOut * Output with dimensions for texture * @param maxStrOut * Output with maximum Texture str coordinates * @return * True if output rgba coloring is valid, else false. */ bool BrainOpenGLVolumeTextureSliceDrawing::createVolumeTexture(const VolumeMappableInterface* volumeMappableInterface, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool allowNonPowerOfTwoTextureFlag, const bool identificationTextureFlag, std::vector& rgbaColorsOut, std::array& textureDimsOut, std::array& maxStrOut) const { maxStrOut.fill(0.0); std::vector dims(5); volumeMappableInterface->getDimensions(dims); textureDimsOut.fill(256); const int64_t dimLargest = *std::max_element(dims.begin(), dims.begin() + 3); if (allowNonPowerOfTwoTextureFlag) { } else { if (dimLargest > 512) { const CaretMappableDataFile* mapFile = dynamic_cast(volumeMappableInterface); const QString filename((mapFile != NULL) ? mapFile->getFileNameNoPath() : "no file name available"); const QString msg("Dimensions too large for volume texture support. Dimensions=" + AString::fromNumbers(&dims[0], 3, ",") + " for volume " + filename); CaretLogSevere(msg); return false; } else if (dimLargest > 256) { textureDimsOut.fill(512); } } const int64_t mapIndex(0); const int64_t numberOfSlices = dims[2]; const int64_t numberOfRows = dims[1]; const int64_t numberOfColumns = dims[0]; const int64_t numSliceBytes = (numberOfRows * numberOfColumns * 4); if (allowNonPowerOfTwoTextureFlag) { textureDimsOut[0] = numberOfColumns; textureDimsOut[1] = numberOfRows; textureDimsOut[2] = numberOfSlices; } const int64_t textureBytes = (textureDimsOut[0] * textureDimsOut[1] * textureDimsOut[2] * 4); rgbaColorsOut.clear(); rgbaColorsOut.resize(textureBytes, 0); if (identificationTextureFlag) { uint32_t offsetID = 0; for (int64_t k = 0; k < numberOfSlices; k++) { for (int32_t j = 0; j < numberOfRows; j++) { for (int32_t i = 0; i < numberOfColumns; i++) { const int32_t textureOffset = ((k * textureDimsOut[0] * textureDimsOut[1]) + (j * textureDimsOut[0]) + i) * 4; CaretAssertVectorIndex(rgbaColorsOut, (textureOffset + 3)); /* * An offset is used and encoded into the R, G, and B bytes. * While we could use IJK, we cannot if a dimension is * greater than 255. With the offset, number of voxels * must only be less than 255**3. */ const uint8_t offsetRed = static_cast((offsetID >> 16) & 0xff); const uint8_t offsetGreen = static_cast((offsetID >> 8) & 0xff); const uint8_t offsetBlue = static_cast((offsetID) & 0xff); rgbaColorsOut[textureOffset] = offsetRed; rgbaColorsOut[textureOffset+1] = offsetGreen; rgbaColorsOut[textureOffset+2] = offsetBlue; rgbaColorsOut[textureOffset+3] = 255; offsetID++; } } } } else { /* * When non power-of-two textures are NOT allowed (OpenGL < 2.0) * To avoid resampling of the voxel data, the texture has larger dimensions * and the volume's voxels are placed in the bottom left corner of the texture * and extra texture texel's are zeros. */ std::vector rgbaSlice(numSliceBytes); for (int64_t k = 0; k < numberOfSlices; k++) { int64_t firstVoxelIJK[3] = { 0, 0, k }; int64_t rowStepIJK[3] = { 0, 1, 0 }; int64_t columnStepIJK[3] = { 1, 0, 0 }; std::fill(rgbaSlice.begin(), rgbaSlice.end(), 0); volumeMappableInterface->getVoxelColorsForSliceInMap(mapIndex, firstVoxelIJK, rowStepIJK, columnStepIJK, numberOfRows, numberOfColumns, displayGroup, tabIndex, &rgbaSlice[0]); for (int32_t j = 0; j < numberOfRows; j++) { for (int32_t i = 0; i < numberOfColumns; i++) { const int32_t sliceOffset = ((j * numberOfColumns) + i) * 4; const int32_t textureOffset = ((k * textureDimsOut[0] * textureDimsOut[1]) + (j * textureDimsOut[0]) + i) * 4; for (int32_t m = 0; m < 4; m++) { CaretAssertVectorIndex(rgbaColorsOut, (textureOffset + 3)); CaretAssertVectorIndex(rgbaSlice, sliceOffset + m); rgbaColorsOut[textureOffset + m] = rgbaSlice[sliceOffset + m]; } } } } } maxStrOut[0] = static_cast(dims[0]) / static_cast(textureDimsOut[0]); maxStrOut[1] = static_cast(dims[1]) / static_cast(textureDimsOut[1]); maxStrOut[2] = static_cast(dims[2]) / static_cast(textureDimsOut[2]); if (debugFlag) std::cout << "max STR: " << AString::fromNumbers(maxStrOut.data(), 3, ",") << std::endl; return true; } /** * Create a volume's texture * * @param volumeMappableInterface * The volume file * @param identificationTextureFlag * True if creating texture for voxel identification * @param displayGroup * Display group for current tab * @param maxStrOut * Output with maximum Texture str coordinates * @return * Valid texture ID (greater than zero) if texture was created, else 0. */ GLuint BrainOpenGLVolumeTextureSliceDrawing::createTextureName(const VolumeMappableInterface* volumeMappableInterface, const bool identificationTextureFlag, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, std::array& maxStrOut) const { const CaretMappableDataFile* mapFile = dynamic_cast(volumeMappableInterface); CaretAssert(mapFile); const VolumeFile* volumeFile = dynamic_cast(volumeMappableInterface); const CiftiMappableDataFile* ciftiFile = dynamic_cast(volumeMappableInterface); std::vector rgbaColors; std::array textureDims; /* * OpenGL 2.0 or later supports non-power-of-two texture dimensions */ const bool allowNonPowerOfTwoTextureFlag(true); if (volumeFile != NULL) { if ( ! createVolumeTexture(volumeFile, displayGroup, tabIndex, allowNonPowerOfTwoTextureFlag, identificationTextureFlag, rgbaColors, textureDims, maxStrOut)) { return 0; } } else if (ciftiFile != NULL) { if ( ! createVolumeTexture(ciftiFile, displayGroup, tabIndex, allowNonPowerOfTwoTextureFlag, identificationTextureFlag, rgbaColors, textureDims, maxStrOut)) { return 0; } } else { CaretAssert(0); } GLint64 maxTextureSize(0); glGetInteger64v(GL_MAX_3D_TEXTURE_SIZE, &maxTextureSize); if (maxTextureSize > 0) { for (int32_t i = 0; i < static_cast(textureDims.size()); i++) { if (textureDims[i] > maxTextureSize) { CaretLogSevere("Texture maximum dimension is " + AString::number(maxTextureSize) + ". Volume " + mapFile->getFileNameNoPath() + " dimensions = (" + AString::fromNumbers(textureDims.data(), 3, ", ") + ")"); return 0; } } } GLuint textureName(0); glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); glGenTextures(1, &textureName); glBindTexture(GL_TEXTURE_3D, textureName); glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); /* * Always clamp to border. If no texels (voxels) are available, pixel * maps to area outside of the volume, the border color is used. */ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER); const bool enableMipMapsFlag(false); if (enableMipMapsFlag) { /* * Generate mip-maps * However does not improve quality or remove aliasing in oblique views (rotation * around multiple axes) */ glTexParameteri(GL_TEXTURE_3D, GL_GENERATE_MIPMAP, GL_TRUE); } /* * Compression works but appears lossy for palette mapped data * but may be okay for label mapped data */ m_fixedPipelineDrawing->testForOpenGLError("Before glTexImage3D"); glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, //GL_COMPRESSED_RGBA, //GL_RGBA, textureDims[0], textureDims[1], textureDims[2], 0, GL_RGBA, GL_UNSIGNED_BYTE, &rgbaColors[0]); m_fixedPipelineDrawing->testForOpenGLError("After glTexImage3D"); glBindTexture(GL_TEXTURE_3D, 0); glPopClientAttrib(); return textureName; } /** * Draw an oblique slice with support for outlining labels and thresholded palette data. * * @param sliceViewPlane * The plane for slice drawing. * @param sliceProjectionType * The slice projection type * @param transformationMatrix * The for oblique viewing. */ void BrainOpenGLVolumeTextureSliceDrawing::drawObliqueSliceWithOutlines(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, Matrix4x4& transformationMatrix) { /* * When performing voxel identification for editing voxels, * we need to draw EVERY voxel since the user may click * regions where the voxels are "off". */ // value unused at this time but will likely be needed later if this volume rendering is fully implemented //float voxelEditingValue = 1.0; VolumeFile* voxelEditingVolumeFile = NULL; if (m_identificationModeFlag) { SelectionItemVoxelEditing* voxelEditID = m_brain->getSelectionManager()->getVoxelEditingIdentification(); if (voxelEditID->isEnabledForSelection()) { voxelEditingVolumeFile = voxelEditID->getVolumeFileForEditing(); if (voxelEditingVolumeFile != NULL) { if (voxelEditingVolumeFile->isMappedWithLabelTable()) { if (voxelEditingVolumeFile->getNumberOfMaps() > 0) { //voxelEditingValue = voxelEditingVolumeFile->getMapLabelTable(0)->getUnassignedLabelKey(); } } } } } const bool obliqueSliceModeThreeDimFlag = false; const int32_t numVolumes = static_cast(m_volumeDrawInfo.size()); /* * Get the maximum bounds of the voxels from all slices * and the smallest voxel spacing */ float voxelBounds[6]; float voxelSpacing[3]; if ( ! getVoxelCoordinateBoundsAndSpacing(voxelBounds, voxelSpacing)) { return; } float voxelSize = std::min(voxelSpacing[0], std::min(voxelSpacing[1], voxelSpacing[2])); /* * Use a larger voxel size for the 3D view in volume slice viewing * since it draws all three slices and this takes time */ if (obliqueSliceModeThreeDimFlag) { voxelSize *= 3.0; } /* * Look at point is in center of volume */ float translation[3]; m_browserTabContent->getTranslation(translation); float viewOffsetX = 0.0; float viewOffsetY = 0.0; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: viewOffsetX = (m_lookAtCenter[0] + translation[0]); viewOffsetY = (m_lookAtCenter[1] + translation[1]); break; case VolumeSliceViewPlaneEnum::CORONAL: viewOffsetX = (m_lookAtCenter[0] + translation[0]); viewOffsetY = (m_lookAtCenter[2] + translation[2]); break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: viewOffsetX = (m_lookAtCenter[1] + translation[1]); viewOffsetY = (m_lookAtCenter[2] + translation[2]); break; } float minScreenX = m_orthographicBounds[0] - viewOffsetX; float maxScreenX = m_orthographicBounds[1] - viewOffsetX; float minScreenY = m_orthographicBounds[2] - viewOffsetY; float maxScreenY = m_orthographicBounds[3] - viewOffsetY; /* * Get origin voxel IJK */ const float zeroXYZ[3] = { 0.0, 0.0, 0.0 }; int64_t originIJK[3]; m_volumeDrawInfo[0].volumeFile->enclosingVoxel(zeroXYZ[0], zeroXYZ[1], zeroXYZ[2], originIJK[0], originIJK[1], originIJK[2]); /* * Get XYZ center of origin Voxel */ float originVoxelXYZ[3]; m_volumeDrawInfo[0].volumeFile->indexToSpace(originIJK, originVoxelXYZ); float actualOrigin[3]; m_volumeDrawInfo[0].volumeFile->indexToSpace(originIJK, actualOrigin); /* * Set the corners of the screen for the respective view */ std::array bottomLeft; std::array bottomRight; std::array topRight; std::array topLeft; switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: bottomLeft[0] = minScreenX; bottomLeft[1] = minScreenY; bottomLeft[2] = 0.0; bottomRight[0] = maxScreenX; bottomRight[1] = minScreenY; bottomRight[2] = 0.0; topRight[0] = maxScreenX; topRight[1] = maxScreenY; topRight[2] = 0.0; topLeft[0] = minScreenX; topLeft[1] = maxScreenY; topLeft[2] = 0.0; break; case VolumeSliceViewPlaneEnum::CORONAL: bottomLeft[0] = minScreenX; bottomLeft[1] = 0.0; bottomLeft[2] = minScreenY; bottomRight[0] = maxScreenX; bottomRight[1] = 0.0; bottomRight[2] = minScreenY; topRight[0] = maxScreenX; topRight[1] = 0.0; topRight[2] = maxScreenY; topLeft[0] = minScreenX; topLeft[1] = 0.0; topLeft[2] = maxScreenY; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: bottomLeft[0] = 0.0; bottomLeft[1] = minScreenX; bottomLeft[2] = minScreenY; bottomRight[0] = 0.0; bottomRight[1] = maxScreenX; bottomRight[2] = minScreenY; topRight[0] = 0.0; topRight[1] = maxScreenX; topRight[2] = maxScreenY; topLeft[0] = 0.0; topLeft[1] = minScreenX; topLeft[2] = maxScreenY; break; } /* * Transform the corners of the screen into model coordinates */ transformationMatrix.multiplyPoint3(bottomLeft.data()); transformationMatrix.multiplyPoint3(bottomRight.data()); transformationMatrix.multiplyPoint3(topRight.data()); transformationMatrix.multiplyPoint3(topLeft.data()); if (debugFlag) { const double bottomDist = MathFunctions::distance3D(bottomLeft.data(), bottomRight.data()); const double topDist = MathFunctions::distance3D(topLeft.data(), topRight.data()); const double bottomVoxels = bottomDist / voxelSize; const double topVoxels = topDist / voxelSize; const AString msg = ("Bottom Dist: " + AString::number(bottomDist) + " voxel size: " + AString::number(bottomVoxels) + " Top Dist: " + AString::number(bottomDist) + " voxel size: " + AString::number(topVoxels)); std::cout << qPrintable(msg) << std::endl; } if (debugFlag) { m_fixedPipelineDrawing->setLineWidth(3.0); glColor3f(1.0, 0.0, 0.0); glBegin(GL_LINE_LOOP); glVertex3fv(bottomLeft.data()); glVertex3fv(bottomRight.data()); glVertex3fv(topRight.data()); glVertex3fv(topLeft.data()); glEnd(); } /* * Unit vector and distance in model coords along left side of screen */ double bottomLeftToTopLeftUnitVector[3] = { topLeft[0] - bottomLeft[0], topLeft[1] - bottomLeft[1], topLeft[2] - bottomLeft[2], }; MathFunctions::normalizeVector(bottomLeftToTopLeftUnitVector); const double bottomLeftToTopLeftDistance = MathFunctions::distance3D(bottomLeft.data(), topLeft.data()); /* * Unit vector and distance in model coords along right side of screen */ double bottomRightToTopRightUnitVector[3] = { topRight[0] - bottomRight[0], topRight[1] - bottomRight[1], topRight[2] - bottomRight[2] }; MathFunctions::normalizeVector(bottomRightToTopRightUnitVector); const double bottomRightToTopRightDistance = MathFunctions::distance3D(bottomRight.data(), topRight.data()); if ((bottomLeftToTopLeftDistance > 0) && (bottomRightToTopRightDistance > 0)) { glPushAttrib(GL_COLOR_BUFFER_BIT); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); if (m_modelWholeBrain != NULL) { glAlphaFunc(GL_GEQUAL, 0.95); glEnable(GL_ALPHA_TEST); glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); } bool firstFlag(true); for (int32_t iVol = 0; iVol < numVolumes; iVol++) { const BrainOpenGLFixedPipeline::VolumeDrawInfo& vdi = m_volumeDrawInfo[iVol]; VolumeMappableInterface* volumeInterface = vdi.volumeFile; if (volumeInterface != NULL) { if (debugFlag) { //std::cout << "Vol: " << iVol << ": " << vf->getFileNameNoPath() << std::endl; } if (firstFlag) { /* * Using GL_ONE prevents an edge artifact * (narrow line on texture edges). */ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); firstFlag = false; } else { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } std::array maxStr = { 1.0, 1.0, 1.0 }; GLuint textureID = 0; if (m_identificationModeFlag) { auto idIter = s_identificationTextureInfo.find(volumeInterface); if (idIter != s_identificationTextureInfo.end()) { TextureInfo textureInfo = idIter->second; textureID = textureInfo.m_textureID; maxStr = textureInfo.m_maxSTR; } } else { auto idIter = s_volumeTextureInfo.find(volumeInterface); if (idIter != s_volumeTextureInfo.end()) { TextureInfo textureInfo = idIter->second; textureID = textureInfo.m_textureID; maxStr = textureInfo.m_maxSTR; } } if (textureID == 0) { m_fixedPipelineDrawing->testForOpenGLError("Before creating texture"); textureID = createTextureName(volumeInterface, m_identificationModeFlag, m_displayGroup, m_tabIndex, maxStr); m_fixedPipelineDrawing->testForOpenGLError("After creating texture"); if (textureID != 0) { TextureInfo textureInfo; textureInfo.m_textureID = textureID; textureInfo.m_maxSTR = maxStr; if (m_identificationModeFlag) { s_identificationTextureInfo.insert(std::make_pair(volumeInterface, textureInfo)); } else { s_volumeTextureInfo.insert(std::make_pair(volumeInterface, textureInfo)); } /* 1.0 is highest priority texture so that texture is resident */ const GLclampf priority(1.0); glPrioritizeTextures(1, &textureID, &priority); if (debugFlag) std::cout << "Created texture: " << textureID << std::endl; if (debugFlag) { std::vector dims; volumeInterface->getDimensions(dims); if (dims.size() >= 3) { const int64_t maxI((dims[0] > 1) ? dims[0] - 1 : 0); const int64_t maxJ((dims[1] > 1) ? dims[1] - 1 : 0); const int64_t maxK((dims[2] > 1) ? dims[2] - 1 : 0); int64_t corners[8][3] = { { 0, 0, 0 }, { maxI, 0, 0 }, { maxI, maxJ, 0 }, { 0, maxJ, 0}, { 0, 0, maxK }, { maxI, 0, maxK }, { maxI, maxJ, maxK }, { 0, maxJ, maxK} }; for (int32_t m = 0; m < 8; m++) { const int64_t i(corners[m][0]); const int64_t j(corners[m][1]); const int64_t k(corners[m][2]); if (volumeInterface->indexValid(i, j, k)) { float x, y, z; volumeInterface->indexToSpace(i, j, k, x, y, z); std::cout << ("IJK = (" + AString::number(i) + "," + AString::number(j) + "," + AString::number(k) + ")") << std::endl; std::cout << (" XYZ = (" + AString::number(x) + ", " + AString::number(y) + ", " + AString::number(z) + ")") << std::endl; std::array str; std::array xyz { x, y, z }; getTextureCoordinates(volumeInterface, xyz, maxStr, str); std::cout << (" STR = (" + AString::number(str[0]) + ", " + AString::number(str[1]) + ", " + AString::number(str[2]) + ")") << std::endl; } } } } } else { if (debugFlag) std::cout << "Failed to create texture ID" << std::endl; } } if (textureID > 0) { std::array textureBottomLeft; getTextureCoordinates(volumeInterface, bottomLeft, maxStr, textureBottomLeft); std::array textureBottomRight; getTextureCoordinates(volumeInterface, bottomRight, maxStr, textureBottomRight); std::array textureTopLeft; getTextureCoordinates(volumeInterface, topLeft, maxStr, textureTopLeft); std::array textureTopRight; getTextureCoordinates(volumeInterface, topRight, maxStr, textureTopRight); if (debugFlag) { std::cout << "Bottom Left RST: " << AString::fromNumbers(textureBottomLeft.data(), 3, ", ") << std::endl; std::cout << "Bottom Right RST: " << AString::fromNumbers(textureBottomRight.data(), 3, ", ") << std::endl; std::cout << "Top Right RST: " << AString::fromNumbers(textureTopRight.data(), 3, ", ") << std::endl; std::cout << "Top Left RST: " << AString::fromNumbers(textureTopLeft.data(), 3, ", ") << std::endl; std::cout << std::endl; } glDisable(GL_CULL_FACE); m_fixedPipelineDrawing->testForOpenGLError("Before drawing with texture"); glEnable(GL_TEXTURE_3D); glBindTexture(GL_TEXTURE_3D, textureID); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); CaretMappableDataFile* mapFile = dynamic_cast(volumeInterface); CaretAssert(mapFile); /* * Setup pixel to texel filtering */ setupTextureFiltering(mapFile, sliceProjectionType); glBegin(GL_QUADS); glColor4f(0.0, 0.0, 1.0, 0.0); glTexCoord3fv(textureBottomLeft.data()); glVertex3fv(bottomLeft.data()); glTexCoord3fv(textureBottomRight.data()); glVertex3fv(bottomRight.data()); glTexCoord3fv(textureTopRight.data()); glVertex3fv(topRight.data()); glTexCoord3fv(textureTopLeft.data()); glVertex3fv(topLeft.data()); glEnd(); glBindTexture(GL_TEXTURE_3D, 0); glDisable(GL_TEXTURE_3D); m_fixedPipelineDrawing->testForOpenGLError("After drawing with texture"); if (m_identificationModeFlag) { processTextureVoxelIdentification(volumeInterface); /* * Exit loop so that only underlay volume is used for identification */ iVol = numVolumes; } } } } glPopAttrib(); } } /** * Process identification from the texture volume */ void BrainOpenGLVolumeTextureSliceDrawing::processTextureVoxelIdentification(VolumeMappableInterface* volumeMappableInterface) { /* * Saves glPixelStore parameters */ glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); /* * Determine item picked by examination of color in back buffer * * QOpenGLWidget Note: The QOpenGLWidget always renders in a * frame buffer object (see its documentation). This is * probably why calls to glReadBuffer() always cause an * OpenGL error. */ #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET /* do not call glReadBuffer() */ #else glReadBuffer(GL_BACK); #endif glPixelStorei(GL_PACK_SKIP_ROWS, 0); glPixelStorei(GL_PACK_SKIP_PIXELS, 0); glPixelStorei(GL_PACK_ALIGNMENT, 1); uint8_t pixels[4]; glReadPixels((int)m_fixedPipelineDrawing->mouseX, (int)m_fixedPipelineDrawing->mouseY, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels); CaretLogFine("ID color RGBA " + QString::number(pixels[0]) + ", " + QString::number(pixels[1]) + ", " + QString::number(pixels[2]) + ", " + QString::number(pixels[3])); if (debugFlag) std::cout << "Pixel ID: " << AString::fromNumbers(pixels, 4, ",") << std::endl; uint32_t alphaInt(pixels[3]); if (alphaInt == 255) { uint32_t redInt(pixels[0]); uint32_t greenInt(pixels[1]); uint32_t blueInt(pixels[2]); uint32_t offset = ((redInt << 16) + (greenInt << 8) + (blueInt)); if (debugFlag) std::cout << " Offset: " << offset << std::endl; std::vector dims; volumeMappableInterface->getDimensions(dims); const int64_t sliceSize = dims[0] * dims[1]; const int64_t sliceK = offset / sliceSize; const int64_t sliceOffset = offset % sliceSize; const int64_t sliceJ = sliceOffset / dims[0]; const int64_t sliceI = sliceOffset % dims[0]; if (debugFlag) std::cout << " Voxel IJK: " << sliceI << ", " << sliceJ << ", " << sliceK << std::endl; const int64_t voxelIndices[3] { sliceI, sliceJ, sliceK }; /* * Get depth from depth buffer */ glPixelStorei(GL_PACK_ALIGNMENT, 4); float depth(0.0); glReadPixels(m_fixedPipelineDrawing->mouseX, m_fixedPipelineDrawing->mouseY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth); SelectionItemVoxel* voxelID = m_brain->getSelectionManager()->getVoxelIdentification(); if (voxelID->isEnabledForSelection()) { if (voxelID->isOtherScreenDepthCloserToViewer(depth)) { voxelID->setVoxelIdentification(m_brain, volumeMappableInterface, voxelIndices, depth); float voxelCoordinates[3]; volumeMappableInterface->indexToSpace(voxelIndices[0], voxelIndices[1], voxelIndices[2], voxelCoordinates[0], voxelCoordinates[1], voxelCoordinates[2]); m_fixedPipelineDrawing->setSelectedItemScreenXYZ(voxelID, voxelCoordinates); CaretLogFinest("Selected Voxel (3D): " + AString::fromNumbers(voxelIndices, 3, ",")); } } SelectionItemVoxelEditing* voxelEditID = m_brain->getSelectionManager()->getVoxelEditingIdentification(); if (voxelEditID->isEnabledForSelection()) { if (voxelEditID->getVolumeFileForEditing() == volumeMappableInterface) { if (voxelEditID->isOtherScreenDepthCloserToViewer(depth)) { voxelEditID->setVoxelIdentification(m_brain, volumeMappableInterface, voxelIndices, depth); const float floatDiffXYZ[3] = { 1.0, 1.0, 1.0 }; voxelEditID->setVoxelDiffXYZ(floatDiffXYZ); float voxelCoordinates[3]; volumeMappableInterface->indexToSpace(voxelIndices[0], voxelIndices[1], voxelIndices[2], voxelCoordinates[0], voxelCoordinates[1], voxelCoordinates[2]); m_fixedPipelineDrawing->setSelectedItemScreenXYZ(voxelEditID, voxelCoordinates); CaretLogFinest("Selected Voxel Editing (3D): Indices (" + AString::fromNumbers(voxelIndices, 3, ",") + ") Diff XYZ (" + AString::fromNumbers(floatDiffXYZ, 3, ",") + ")"); } } } } glPopClientAttrib(); } /** * Set the texture filtering that controls mapping of texels to pixels * * @param mapFile * File is is being drawn * @param sliceProjectionType * Type of projection */ void BrainOpenGLVolumeTextureSliceDrawing::setupTextureFiltering(const CaretMappableDataFile* mapFile, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType) { if (mapFile->isMappedWithPalette()) { switch (sliceProjectionType) { case caret::VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: { /* * This combination MIN=Linear, MAG=Nearest * seems to produce voxel drawing that is * nearly identical to cubic interpolation when zoomed in so * that the voxels are large. The difference is when the slices * are rotated; In cubic interpolation, the "scan lines" are * horizontal (left to right on the screen) but with texture, * the "scan lines" follow the volume rotation. * * From the OpenGL documentation (man page) * * GL_TEXTURE_MIN_FILTER - The texture minifying function is used * whenever the pixel being textured maps to an area greater than one * texture element. * GL_NEAREST - Returns the value of the texture element that is * nearest (in Manhattan distance) to the center of * the pixel being textured. * GL_LINEAR - Returns the weighted average of the four texture * elements that are closest to the center of the * pixel being textured. * * Pixel area is GREATER THAN texel area so ZOOMED OUT * * Thus, Pixel contains more than one texel */ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); /* * GL_TEXTURE_MAG_FILTER - The texture magnification function * is used when the pixel being textured maps to an area less than or * equal to one texture element. * GL_NEAREST - Returns the value of the texture element that is * nearest (in Manhattan distance) to the center of * the pixel being textured. * GL_LINEAR Returns the weighted average of the four texture * elements that are closest to the center of the * pixel being textured. * * Pixel area is LESS THAN Texel area so ZOOMED IN * * Thus, pixel may be inside a texel * * If GL_LINEAR is used the voxel "blockiness" is smoothed out */ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } break; case caret::VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: { /* * No interpolation for orthogonal slice viewing */ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } break; } /* * Option to smooth voxels that removes all "blocki-ness" */ if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DELELOPER_FLAG_VOXEL_SMOOTH)) { glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } GLfloat borderColor[4] = { 0.0, 0.0, 0.0, 0.0 }; glTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, borderColor); } else { /* * No interpolation for Label or RGBA data */ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } } connectome-workbench-1.4.2/src/Brain/BrainOpenGLVolumeTextureSliceDrawing.h000066400000000000000000000313211360521144700267730ustar00rootroot00000000000000#ifndef __BRAIN_OPEN_GL_VOLUME_TEXTURE_SLICE_DRAWING_H__ #define __BRAIN_OPEN_GL_VOLUME_TEXTURE_SLICE_DRAWING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "BrainOpenGLFixedPipeline.h" #include "BrainOpenGLVolumeSliceDrawing.h" #include "CaretObject.h" #include "DisplayGroupEnum.h" #include "ModelTypeEnum.h" #include "VolumeSliceInterpolationEdgeEffectsMaskingEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "VolumeSliceDrawingTypeEnum.h" #include "VolumeSliceViewAllPlanesLayoutEnum.h" #include "VolumeSliceViewPlaneEnum.h" namespace caret { class Brain; class BrowserTabContent; class CiftiMappableDataFile; class Matrix4x4; class ModelVolume; class ModelWholeBrain; class Plane; class VolumeMappableInterface; class BrainOpenGLVolumeTextureSliceDrawing : public CaretObject { public: BrainOpenGLVolumeTextureSliceDrawing(); virtual ~BrainOpenGLVolumeTextureSliceDrawing(); void draw(BrainOpenGLFixedPipeline* fixedPipelineDrawing, BrowserTabContent* browserTabContent, std::vector& volumeDrawInfo, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum obliqueSliceMaskingType, const int32_t viewport[4]); // ADD_NEW_METHODS_HERE private: BrainOpenGLVolumeTextureSliceDrawing(const BrainOpenGLVolumeTextureSliceDrawing&); BrainOpenGLVolumeTextureSliceDrawing& operator=(const BrainOpenGLVolumeTextureSliceDrawing&); void drawPrivate(BrainOpenGLFixedPipeline* fixedPipelineDrawing, BrowserTabContent* browserTabContent, std::vector& volumeDrawInfo, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum obliqueSliceMaskingType, const int32_t viewport[4]); void drawVolumeSlicesForAllStructuresView(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const int32_t viewport[4]); void drawVolumeSliceViewPlane(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const VolumeSliceViewAllPlanesLayoutEnum::Enum allPlanesLayout, const int32_t viewport[4]); void drawVolumeSliceViewType(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const int32_t viewport[4]); void drawVolumeSliceViewTypeMontage(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const int32_t viewport[4]); void drawVolumeSliceViewProjection(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], const int32_t viewport[4]); void drawObliqueSlice(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, Matrix4x4& transformationMatrix, const Plane& plane); void drawObliqueSliceWithOutlines(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, Matrix4x4& transformationMatrix); void createSlicePlaneEquation(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], Plane& planeOut); void drawAxesCrosshairsOblique(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3], const bool drawCrosshairsFlag, const bool drawCrosshairLabelsFlag); void setVolumeSliceViewingAndModelingTransformations(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const Plane& plane, const float sliceCoordinates[3]); void getAxesColor(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, float rgbaOut[4]) const; void drawLayers(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const Plane& slicePlane, const float sliceCoordinates[3]); void drawVolumeSliceFoci(const Plane& plane); void drawAxesCrosshairs(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinates[3]); bool getMinMaxVoxelSpacing(const VolumeMappableInterface* volume, float& minSpacingOut, float& maxSpacingOut) const; void drawSquare(const float size); void drawOrientationAxes(const int viewport[4]); void setOrthographicProjection(const BrainOpenGLVolumeSliceDrawing::AllSliceViewMode allSliceViewMode, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const int viewport[4]); bool getVoxelCoordinateBoundsAndSpacing(float boundsOut[6], float spacingOut[3]); void createObliqueTransformationMatrix(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const float sliceCoordinates[3], Matrix4x4& obliqueTransformationMatrixOut); bool getVolumeDrawingViewDependentCulling(const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float selectedSliceCoordinate, const VolumeMappableInterface* volumeFile, int64_t culledFirstVoxelIJKOut[3], int64_t culledLastVoxelIJKOut[3], float voxelDeltaXYZOut[3]); glm::mat4 convertMatrix4x4toGlmMat4(const Matrix4x4& matrix) const; void mat4ToOpenGLMatrix(const glm::mat4& matrixIn, float matrixOut[16]) const; bool getTextureCoordinates(const VolumeMappableInterface* volumeMappableInterface, const std::array& xyz, const std::array& maxStr, std::array& strOut) const; bool createVolumeTexture(const VolumeMappableInterface* volumeFile, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool allowNonPowerOfTwoTextureFlag, const bool identificationTextureFlag, std::vector& rgbaColorsOut, std::array& textureDimsOut, std::array& maxStrOut) const; GLuint createTextureName(const VolumeMappableInterface* volumeMappableInterface, const bool identificationTextureFlag, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, std::array& maxStrOut) const; void setupTextureFiltering(const CaretMappableDataFile* mapFile, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType); void processTextureVoxelIdentification(VolumeMappableInterface* volumeMappableInterface); struct TextureInfo { GLuint m_textureID; std::array m_maxSTR; }; /* * These items will eventually be moved into the volume and cifti files */ static std::map s_volumeTextureInfo; static std::map s_identificationTextureInfo; ModelVolume* m_modelVolume; ModelWholeBrain* m_modelWholeBrain; ModelTypeEnum::Enum m_modelType; VolumeMappableInterface* m_underlayVolume; Brain* m_brain; std::vector> m_ciftiMappableFileData; BrainOpenGLFixedPipeline* m_fixedPipelineDrawing; std::vector m_volumeDrawInfo; BrowserTabContent* m_browserTabContent; DisplayGroupEnum::Enum m_displayGroup; int32_t m_tabIndex; double m_lookAtCenter[3]; // double m_viewingMatrix[16]; double m_orthographicBounds[6]; VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum m_obliqueSliceMaskingType = VolumeSliceInterpolationEdgeEffectsMaskingEnum::OFF; bool m_identificationModeFlag; // ADD_NEW_MEMBERS_HERE }; #ifdef __BRAIN_OPEN_GL_VOLUME_TEXTURE_SLICE_DRAWING_DECLARE__ std::map BrainOpenGLVolumeTextureSliceDrawing::s_volumeTextureInfo; std::map BrainOpenGLVolumeTextureSliceDrawing::s_identificationTextureInfo; #endif // __BRAIN_OPEN_GL_VOLUME_TEXTURE_SLICE_DRAWING_DECLARE__ } // namespace #endif //__BRAIN_OPEN_GL_VOLUME_TEXTURE_SLICE_DRAWING_H__ connectome-workbench-1.4.2/src/Brain/BrainOpenGLWindowContent.cxx000066400000000000000000000126041360521144700250270ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BRAIN_OPEN_G_L_WINDOW_CONTENT_DECLARE__ #include "BrainOpenGLWindowContent.h" #undef __BRAIN_OPEN_G_L_WINDOW_CONTENT_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::BrainOpenGLWindowContent * \brief Content of window and its tabs. * \ingroup Brain */ /** * Constructor. */ BrainOpenGLWindowContent::BrainOpenGLWindowContent() : CaretObject() { } /** * Destructor. */ BrainOpenGLWindowContent::~BrainOpenGLWindowContent() { } /** * Copy constructor. * @param obj * Object that is copied. */ BrainOpenGLWindowContent::BrainOpenGLWindowContent(const BrainOpenGLWindowContent& obj) : CaretObject(obj) { this->copyHelperBrainOpenGLWindowContent(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ BrainOpenGLWindowContent& BrainOpenGLWindowContent::operator=(const BrainOpenGLWindowContent& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperBrainOpenGLWindowContent(obj); } return *this; } /** * Clear the content of the window and tabs. */ void BrainOpenGLWindowContent::clear() { m_tabViewports.clear(); m_windowViewport.reset(); } /** * Add a tab viewport. * * @param tabViewport * Tab viewport to add. */ void BrainOpenGLWindowContent::addTabViewport(BrainOpenGLViewportContent* tabViewport) { std::unique_ptr ptr(tabViewport); m_tabViewports.push_back(std::move(ptr)); } /** * Set the window viewport. * * @param windowViewport * The new window viewport. */ void BrainOpenGLWindowContent::setWindowViewport(BrainOpenGLViewportContent* windowViewport) { m_windowViewport.reset(windowViewport); } /** * @return Number of tab viewports. */ int32_t BrainOpenGLWindowContent::getNumberOfTabViewports() const { return m_tabViewports.size(); } /** * Get the viewport content for the tab at the given index. * * @param index * Index of element in viewports BUT IS NOT the TAB INDEX * @return * Tab for the given index or NULL if not available. */ const BrainOpenGLViewportContent* BrainOpenGLWindowContent::getTabViewportAtIndex(const int32_t index) const { if ((index >= 0) && (index < static_cast(m_tabViewports.size()))) { CaretAssertVectorIndex(m_tabViewports, index); return m_tabViewports[index].get(); } return NULL; } /** * Get the tab viewport containing the given X/Y coordinates * after lock aspect ratio has been performed on the tab viewport. * * @param x * The X-coordinate * @param y * The Y-coordinate * @return * Tab viewport containing the coordinate or NULL if not found. */ const BrainOpenGLViewportContent* BrainOpenGLWindowContent::getTabViewportWithLockAspectXY(const int32_t x, const int32_t y) const { for (const auto& vp : m_tabViewports) { int32_t viewport[4]; vp->getTabViewportBeforeApplyingMargins(viewport); if ((x >= viewport[0]) && (x < (viewport[0] + viewport[2])) && (y >= viewport[1]) && (y < (viewport[1] + viewport[3]))) { return vp.get(); } } return NULL; } /** * All viewports for all tabs. */ std::vector BrainOpenGLWindowContent::getAllTabViewports() const { std::vector allTabs; for (auto& vp : m_tabViewports) { allTabs.push_back(vp.get()); } return allTabs; } /** * @return The viewport for the window (could be NULL). */ const BrainOpenGLViewportContent* BrainOpenGLWindowContent::getWindowViewport() const { return m_windowViewport.get(); } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void BrainOpenGLWindowContent::copyHelperBrainOpenGLWindowContent(const BrainOpenGLWindowContent& obj) { clear(); if (obj.m_windowViewport) { setWindowViewport(new BrainOpenGLViewportContent(*obj.m_windowViewport.get())); } for (const auto& tabvp : obj.m_tabViewports) { BrainOpenGLViewportContent* vp(NULL); const BrainOpenGLViewportContent* ptr = tabvp.get(); if (ptr != NULL) { vp = new BrainOpenGLViewportContent(*ptr); } addTabViewport(vp); } } /** * Get a description of this object's content. * @return String describing this object's content. */ AString BrainOpenGLWindowContent::toString() const { return "BrainOpenGLWindowContent"; } connectome-workbench-1.4.2/src/Brain/BrainOpenGLWindowContent.h000066400000000000000000000052461360521144700244600ustar00rootroot00000000000000#ifndef __BRAIN_OPEN_G_L_WINDOW_CONTENT_H__ #define __BRAIN_OPEN_G_L_WINDOW_CONTENT_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "BrainOpenGLViewportContent.h" #include "CaretObject.h" namespace caret { class BrainOpenGLWindowContent : public CaretObject { public: BrainOpenGLWindowContent(); virtual ~BrainOpenGLWindowContent(); BrainOpenGLWindowContent(const BrainOpenGLWindowContent& obj); BrainOpenGLWindowContent& operator=(const BrainOpenGLWindowContent& obj); void clear(); void addTabViewport(BrainOpenGLViewportContent* tabsViewportContent); void setWindowViewport(BrainOpenGLViewportContent* windowViewportContent); int32_t getNumberOfTabViewports() const; const BrainOpenGLViewportContent* getTabViewportAtIndex(const int32_t index) const; const BrainOpenGLViewportContent* getTabViewportWithLockAspectXY(const int32_t x, const int32_t y) const; const BrainOpenGLViewportContent* getWindowViewport() const; std::vector getAllTabViewports() const; // ADD_NEW_METHODS_HERE virtual AString toString() const; private: void copyHelperBrainOpenGLWindowContent(const BrainOpenGLWindowContent& obj); std::vector> m_tabViewports; std::unique_ptr m_windowViewport; // ADD_NEW_MEMBERS_HERE }; #ifdef __BRAIN_OPEN_G_L_WINDOW_CONTENT_DECLARE__ // #endif // __BRAIN_OPEN_G_L_WINDOW_CONTENT_DECLARE__ } // namespace #endif //__BRAIN_OPEN_G_L_WINDOW_CONTENT_H__ connectome-workbench-1.4.2/src/Brain/BrainStructure.cxx000066400000000000000000001346731360521144700231730ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __BRAIN_STRUCTURE_DEFINE__ #include "BrainStructure.h" #undef __BRAIN_STRUCTURE_DEFINE__ #include "Brain.h" #include "BrainStructureNodeAttributes.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPointLocator.h" #include "CaretPreferences.h" #include "DataFileException.h" #include "ElapsedTimer.h" #include "EventBrainStructureGetAll.h" #include "EventManager.h" #include "EventNodeDataFilesGet.h" #include "EventModelAdd.h" #include "EventModelDelete.h" #include "EventSurfacesGet.h" #include "EventSurfaceStructuresValidGet.h" #include "GroupAndNameHierarchyModel.h" #include "IdentificationManager.h" #include "SelectionManager.h" #include "LabelFile.h" #include "MathFunctions.h" #include "MetricDynamicConnectivityFile.h" #include "MetricFile.h" #include "ModelSurface.h" #include "OverlaySet.h" #include "OverlaySetArray.h" #include "RgbaFile.h" #include "SceneClass.h" #include "ScenePathName.h" #include "SessionManager.h" #include "Surface.h" using namespace caret; /** * Constructor. * */ BrainStructure::BrainStructure(Brain* brain, StructureEnum::Enum structure) { m_brainStructureIdentifier = BrainStructure::s_brainStructureIdentifierCounter++; m_brain = brain; m_structure = structure; m_nodeAttributes = new BrainStructureNodeAttributes(); m_primaryAnatomicalSurface = NULL; std::vector overlaySurfaceStructures; overlaySurfaceStructures.push_back(m_structure); m_overlaySetArray = new OverlaySetArray(overlaySurfaceStructures, Overlay::INCLUDE_VOLUME_FILES_NO, "Structure " + StructureEnum::toGuiName(m_structure)); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BRAIN_STRUCTURE_GET_ALL); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GET_NODE_DATA_FILES); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_IDENTIFICATION_HIGHLIGHT_LOCATION); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_IDENTIFICATION_SYMBOL_REMOVAL); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_SURFACES_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_SURFACE_STRUCTURES_VALID_GET); } /** * Destructor. */ BrainStructure::~BrainStructure() { EventManager::get()->removeAllEventsFromListener(this); delete m_overlaySetArray; /* * Make a copy of all surface pointers since * deleting surfaces will alter the actual * vector that stores the surfaces. */ std::vector allSurfaces(m_surfaces); for (uint64_t i = 0; i < allSurfaces.size(); i++) { removeAndMaybeDeleteSurface(allSurfaces[i], true); } m_surfaces.clear(); for (uint64_t i = 0; i < m_labelFiles.size(); i++) { delete m_labelFiles[i]; m_labelFiles[i] = NULL; } m_labelFiles.clear(); for (uint64_t i = 0; i < m_metricFiles.size(); i++) { delete m_metricFiles[i]; m_metricFiles[i] = NULL; } m_metricFiles.clear(); for (uint64_t i = 0; i < m_rgbaFiles.size(); i++) { delete m_rgbaFiles[i]; m_rgbaFiles[i] = NULL; } m_rgbaFiles.clear(); delete m_nodeAttributes; } /** * Get the structure for this BrainStructure. * * @return The structure. */ StructureEnum::Enum BrainStructure::getStructure() const { return m_structure; } /** * Add a label file. * * @param labelFile * Label file that is added. * @param addFileToBrainStructure * If true, add the file to the brain structure. This value is false * when a file is reloaded and already part of the brain structure. * @throw DataFileException * If the number of nodes in the label file does not match * the number of nodes in this brain structure. */ void BrainStructure::addLabelFile(LabelFile* labelFile, const bool addFileToBrainStructure) { CaretAssert(labelFile); int32_t numNodes = getNumberOfNodes(); if (numNodes > 0) { if (labelFile->getNumberOfNodes() != numNodes) { AString message = ("Label file contains " + AString::number(labelFile->getNumberOfNodes()) + " vertices but the " + StructureEnum::toGuiName(getStructure()) + " contains " + AString::number(numNodes) + " vertices."); DataFileException e(labelFile->getFileName(), message); CaretLogThrowing(e); throw e; } } if (labelFile->getStructure() != getStructure()) { AString message = ("Trying to add label file with structure \"" + StructureEnum::toGuiName(labelFile->getStructure()) + " to BrainStructure for \"" + StructureEnum::toGuiName(getStructure()) + "\n"); DataFileException e(labelFile->getFileName(), message); CaretLogThrowing(e); throw e; } if (addFileToBrainStructure) { m_labelFiles.push_back(labelFile); } } /** * Add a metric file. * * @param metricFile * Metric file that is added. * @param addFileToBrainStructure * If true, add the file to the brain structure. This value is false * when a file is reloaded and already part of the brain structure. * @throw DataFileException * If the number of nodes in the metric file does not match * the number of nodes in this brain structure. */ void BrainStructure::addMetricFile(MetricFile* metricFile, const bool addFileToBrainStructure) { CaretAssert(metricFile); int32_t numNodes = getNumberOfNodes(); if (numNodes > 0) { if (metricFile->getNumberOfNodes() != numNodes) { AString message = ("Metric file contains " + AString::number(metricFile->getNumberOfNodes()) + " vertices but the " + StructureEnum::toGuiName(getStructure()) + " contains " + AString::number(numNodes) + " vertices."); DataFileException e(metricFile->getFileName(), message); CaretLogThrowing(e); throw e; } } if (metricFile->getStructure() != getStructure()) { AString message = ("Trying to add metric file with structure \"" + StructureEnum::toGuiName(metricFile->getStructure()) + " to BrainStructure for \"" + StructureEnum::toGuiName(getStructure()) + "\n"); DataFileException e(metricFile->getFileName(), message); CaretLogThrowing(e); throw e; } if (addFileToBrainStructure) { m_metricFiles.push_back(metricFile); /* * Enable dynamic connectivity using preferences */ CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); MetricDynamicConnectivityFile* metricDynConn = metricFile->getMetricDynamicConnectivityFile(); if (metricDynConn != NULL) { metricDynConn->setEnabledAsLayer(prefs->isDynamicConnectivityDefaultedOn()); } } } /** * Add an RGBA file. * * @param rgbaFile * RGBA file that is added. * @param addFileToBrainStructure * If true, add the file to the brain structure. This value is false * when a file is reloaded and already part of the brain structure. * @throw DataFileException * If the number of nodes in the RGBA file does not match * the number of nodes in this brain structure. */ void BrainStructure::addRgbaFile(RgbaFile* rgbaFile, const bool addFileToBrainStructure) { CaretAssert(rgbaFile); int32_t numNodes = getNumberOfNodes(); if (numNodes > 0) { if (rgbaFile->getNumberOfNodes() != numNodes) { AString message = ("RGBA File contains " + AString::number(rgbaFile->getNumberOfNodes()) + " vertices but the " + StructureEnum::toGuiName(getStructure()) + " contains " + AString::number(numNodes) + " vertices."); DataFileException e(rgbaFile->getFileName(), message); CaretLogThrowing(e); throw e; } } if (rgbaFile->getStructure() != getStructure()) { AString message = ("Trying to add metric file with structure \"" + StructureEnum::toGuiName(rgbaFile->getStructure()) + " to BrainStructure for \"" + StructureEnum::toGuiName(getStructure()) + "\n"); DataFileException e(rgbaFile->getFileName(), message); CaretLogThrowing(e); throw e; } if (addFileToBrainStructure) { m_rgbaFiles.push_back(rgbaFile); } } /** * Add a surface. * * @param surface * Surface that is added. * @param addFileToBrainStructure * If true, add the file to the brain structure. This value is false * when a file is reloaded and already part of the brain structure. * @throw DataFileException * If the number of nodes in the surface does not match * the number of nodes in this brain structure. */ void BrainStructure::addSurface(Surface* surface, const bool addFileToBrainStructure, const bool initilizeOverlaysFlag) { CaretAssert(surface); int32_t numNodes = getNumberOfNodes(); if (numNodes > 0) { if (surface->getNumberOfNodes() != numNodes) { AString message = ("Surface file contains " + AString::number(surface->getNumberOfNodes()) + " vertices but the " + StructureEnum::toGuiName(getStructure()) + " contains " + AString::number(numNodes) + " vertices."); DataFileException e(surface->getFileName(), message); CaretLogThrowing(e); throw e; } } if (surface->getStructure() != getStructure()) { AString message = ("Trying to add metric file with structure \"" + StructureEnum::toGuiName(surface->getStructure()) + " to BrainStructure for \"" + StructureEnum::toGuiName(getStructure()) + "\n"); DataFileException e(surface->getFileName(), message); CaretLogThrowing(e); throw e; } if (numNodes == 0) { const int32_t numSurfaceNodes = surface->getNumberOfNodes(); m_nodeAttributes->update(numSurfaceNodes); } surface->setBrainStructure(this); if (addFileToBrainStructure) { m_surfaces.push_back(surface); /* * Create a model for the surface. */ ModelSurface* mdcs = new ModelSurface(m_brain, surface); m_surfaceModelMap.insert(std::make_pair(surface, mdcs)); if (initilizeOverlaysFlag) { initializeOverlays(); } /* * Send the model added event. */ EventModelAdd addEvent(mdcs); EventManager::get()->sendEvent(addEvent.getPointer()); } } /** * Remove a surface from this brain structure and the surface * model and maybe delete the surface. * * @param surface * Surface that is removed. * @param deleteSurfaceFile * If true, delete the surface file. If false, surface is removed * but not delete and caller is responsible for deleting the surface. * @return * True if the surface was removed, else false. */ bool BrainStructure::removeAndMaybeDeleteSurface(Surface* surface, const bool deleteSurfaceFile) { CaretAssert(surface); std::vector::iterator iter = std::find(m_surfaces.begin(), m_surfaces.end(), surface); CaretAssertMessage((iter != m_surfaces.end()), "Trying to delete surface not in brain structure."); if (iter == m_surfaces.end()) { CaretLogSevere("Trying to delete surface not in brain structure."); return false; } std::map::iterator modelIter = m_surfaceModelMap.find(surface); CaretAssertMessage((modelIter != m_surfaceModelMap.end()), "Surface does not map to a model"); if (modelIter == m_surfaceModelMap.end()) { CaretLogSevere("Surface does not map to a model"); return false; } ModelSurface* mdcs = modelIter->second; /* * Remove from surface to model map. */ m_surfaceModelMap.erase(modelIter); /* * Remove the surface. */ m_surfaces.erase(iter); /* * Send the model deleted event. */ EventModelDelete deleteEvent(mdcs); EventManager::get()->sendEvent(deleteEvent.getPointer()); /* * Delete the model and the surface. */ delete mdcs; if (deleteSurfaceFile) { delete surface; } return true; } /** * Get the number of surfaces. * * @return * Number of surfaces. */ int BrainStructure::getNumberOfSurfaces() const { return static_cast(m_surfaces.size()); } /** * Get a surface at the specified index. * * @param indx * Index of surface. * @return * Surface at the specified index. */ Surface* BrainStructure::getSurface(int indx) { CaretAssertVectorIndex(m_surfaces, indx); return m_surfaces[indx]; } /** * Get a surface at the specified index. * * @param indx * Index of surface. * @return * Surface at the specified index. */ const Surface* BrainStructure::getSurface(int indx) const { CaretAssertVectorIndex(m_surfaces, indx); return m_surfaces[indx]; } /** * Get all surfaces of the given type in this brain structure. * @param surfaceType * Type of surface * @param surfacesOut * Output that will contain the surfaces. */ void BrainStructure::getSurfacesOfType(const SurfaceTypeEnum::Enum surfaceType, std::vector& surfacesOut) const { surfacesOut.clear(); const int32_t numSurfaces = getNumberOfSurfaces(); for (int32_t i = 0; i < numSurfaces; i++) { if (m_surfaces[i]->getSurfaceType() == surfaceType) { surfacesOut.push_back(m_surfaces[i]); } } } /** * Get all surfaces. * * @param surfaceOut * Output containing all surfaces. */ void BrainStructure::getSurfaces(std::vector& surfacesOut) const { surfacesOut = m_surfaces; } /** * @return The surface used for primary anatomical. * Returns NULL if no anatomical surfaces. */ const Surface* BrainStructure::getPrimaryAnatomicalSurfacePrivate() const { bool valid = false; if (m_primaryAnatomicalSurface != NULL) { const int32_t numSurfaces = getNumberOfSurfaces(); for (int32_t i = 0; i < numSurfaces; i++) { if (m_surfaces[i] == m_primaryAnatomicalSurface) { valid = true; break; } } } if (valid) { return m_primaryAnatomicalSurface; } m_primaryAnatomicalSurface = NULL; /* * Give preference to anatomical surfaces but if there are none * (perhaps the surface types are missing), use all surfaces. */ std::vector primaryAnatomicalSurfaces; getSurfacesOfType(SurfaceTypeEnum::ANATOMICAL, primaryAnatomicalSurfaces); if (primaryAnatomicalSurfaces.empty()) { primaryAnatomicalSurfaces = m_surfaces; } if (primaryAnatomicalSurfaces.empty() == false) { /* * Default to first surface */ m_primaryAnatomicalSurface = primaryAnatomicalSurfaces[0]; /* * Now look for a surface with certain strings in their name */ Surface* midThicknessSurface = NULL; Surface* whiteMatterSurface = NULL; Surface* pialSurface = NULL; Surface* anatomicalSurface = NULL; Surface* fiducialSurface = NULL; const int32_t numSurfaces = static_cast(primaryAnatomicalSurfaces.size()); for (int32_t i = 0; i < numSurfaces; i++) { /* * First, look for anatomical surfaces that are midthickness, * gray/white, and pial. */ if (primaryAnatomicalSurfaces[i]->getSurfaceType() == SurfaceTypeEnum::ANATOMICAL) { const SecondarySurfaceTypeEnum::Enum secondType = primaryAnatomicalSurfaces[i]->getSecondaryType(); const AString name = primaryAnatomicalSurfaces[i]->getFileNameNoPath().toLower(); if (secondType == SecondarySurfaceTypeEnum::MIDTHICKNESS) { if (midThicknessSurface == NULL) { midThicknessSurface = primaryAnatomicalSurfaces[i]; } } if (secondType == SecondarySurfaceTypeEnum::GRAY_WHITE) { if (whiteMatterSurface == NULL) { whiteMatterSurface = primaryAnatomicalSurfaces[i]; } } if (secondType == SecondarySurfaceTypeEnum::PIAL) { if (pialSurface == NULL) { pialSurface = primaryAnatomicalSurfaces[i]; } } } } /* * Since it is possible surfaces may not have valid types, * perform an additional search using name substrings. */ for (int32_t i = 0; i < numSurfaces; i++) { const AString name = primaryAnatomicalSurfaces[i]->getFileNameNoPath().toLower(); if (name.indexOf("midthick") >= 0) { if (midThicknessSurface == NULL) { midThicknessSurface = primaryAnatomicalSurfaces[i]; } } if (name.indexOf("white") >= 0) { if (whiteMatterSurface == NULL) { whiteMatterSurface = primaryAnatomicalSurfaces[i]; } } if (name.indexOf("pial") >= 0) { if (pialSurface == NULL) { pialSurface = primaryAnatomicalSurfaces[i]; } } if (name.indexOf("anatomical") >= 0) { if (anatomicalSurface == NULL) { anatomicalSurface = primaryAnatomicalSurfaces[i]; } } if (name.indexOf("fiducial") >= 0) { if (fiducialSurface == NULL) { fiducialSurface = primaryAnatomicalSurfaces[i]; } } } if (midThicknessSurface != NULL) { m_primaryAnatomicalSurface = midThicknessSurface; } else if (whiteMatterSurface != NULL) { m_primaryAnatomicalSurface = whiteMatterSurface; } else if (pialSurface != NULL) { m_primaryAnatomicalSurface = pialSurface; } else if (anatomicalSurface != NULL) { m_primaryAnatomicalSurface = anatomicalSurface; } else if (fiducialSurface != NULL) { m_primaryAnatomicalSurface = fiducialSurface; } } if (m_primaryAnatomicalSurface != NULL) { CaretLogFiner("Primary Anatomical Surface for " + StructureEnum::toGuiName(m_structure) + ": " + m_primaryAnatomicalSurface->getFileNameNoPath()); } else { CaretLogFiner("Primary Anatomical Surface for " + StructureEnum::toGuiName(m_structure) + " is invalid."); } return m_primaryAnatomicalSurface; } /** * @return The surface used for primary anatomical. * Returns NULL if no anatomical surfaces. */ const Surface* BrainStructure::getPrimaryAnatomicalSurface() const { return getPrimaryAnatomicalSurfacePrivate(); } /** * @return The surface used for primary anatomical. * Returns NULL if no anatomical surfaces. */ Surface* BrainStructure::getPrimaryAnatomicalSurface() { /* * Kludge to avoid duplicated code and ease maintenance */ const Surface* constSurface = getPrimaryAnatomicalSurfacePrivate(); Surface* s = (Surface*)constSurface; return s; } /** * Set the primary anatomical surface. * @param primaryAnatomicalSurface * New primary anatomical surface. */ void BrainStructure::setPrimaryAnatomicalSurface(Surface* primaryAnatomicalSurface) { m_primaryAnatomicalSurface = primaryAnatomicalSurface; } /** * Find and return the first surface encountered that contains the * given text in the name of the surface's filename. Text is searched * in an case-insensitive mode. * * @param text * Text that is to bound in the surface's filenname. * @return * Surface that contains the given text in its filename or * NULL if no surface matches. */ Surface* BrainStructure::getSurfaceContainingTextInName(const AString& text) { /* * Kludge to avoid duplicated code and ease maintenance */ const Surface* constSurface = getSurfaceContainingTextInNamePrivate(text); Surface* s = (Surface*)constSurface; return s; } /** * Find and return the first surface encountered that contains the * given text in the name of the surface's filename. Text is searched * in an case-insensitive mode. * * @param text * Text that is to bound in the surface's filenname. * @return * Surface that contains the given text in its filename or * NULL if no surface matches. */ const Surface* BrainStructure::getSurfaceContainingTextInName(const AString& text) const { return getSurfaceContainingTextInNamePrivate(text); } /** * Find and return the first surface encountered that contains the * given text in the name of the surface's filename. Text is searched * in an case-insensitive mode. * * @param text * Text that is to bound in the surface's filenname. * @return * Surface that contains the given text in its filename or * NULL if no surface matches. */ const Surface* BrainStructure::getSurfaceContainingTextInNamePrivate(const AString& text) const { for (std::vector::const_iterator iter = m_surfaces.begin(); iter != m_surfaces.end(); iter++) { const Surface* surface = *iter; const AString name = surface->getFileNameNoPath(); if (name.indexOf(text, 0, Qt::CaseInsensitive) >= 0) { return surface; } } return NULL; } /** * Is the surface in this brain structure? * @param surface * Surface that is tested for being in this brain structure. * @return Returns true if surface in brain structure, else false. */ bool BrainStructure::containsSurface(const Surface* surface) { CaretAssert(surface); if (std::find(m_surfaces.begin(), m_surfaces.end(), surface) != m_surfaces.end()) { return true; } return false; } /** * Find the surface with the given name. * @param surfaceFileName * Name of surface. * @param useAbsolutePath * If true the given surfaceFileName is an absolute path. * If false, the given surfaceFileName is just the file * name without any path. */ Surface* BrainStructure::getSurfaceWithName(const AString& surfaceFileName, const bool useAbsolutePath) { for (std::vector::iterator iter = m_surfaces.begin(); iter != m_surfaces.end(); iter++) { Surface* surface = *iter; const AString name = (useAbsolutePath ? surface->getFileName() : surface->getFileNameNoPath()); if (surfaceFileName == name) { return surface; } } return NULL; } /** * Get the brain that this brain structure is in. */ Brain* BrainStructure::getBrain() { return m_brain; } /** * Get the brain that this brain structure is in. */ const Brain* BrainStructure::getBrain() const { return m_brain; } /** * Get the number of nodes used by this brain structure. * * @return Number of nodes. */ int32_t BrainStructure::getNumberOfNodes() const { if (m_surfaces.empty() == false) { return m_surfaces[0]->getNumberOfNodes(); } return 0; } /** * Get all of the label files. * @param labelFilesOut * Will contain all label files after this method exits. */ void BrainStructure::getLabelFiles(std::vector& labelFilesOut) const { labelFilesOut.clear(); labelFilesOut.insert(labelFilesOut.end(), m_labelFiles.begin(), m_labelFiles.end()); } /** * Get the number of label files. * @return Number of label files. */ int32_t BrainStructure::getNumberOfLabelFiles() const { return m_labelFiles.size(); } /** * Get a label file at the specified index. * @param fileIndex * Index of the label file. * @return * Metric file at the index. */ LabelFile* BrainStructure::getLabelFile(const int32_t fileIndex) { CaretAssertVectorIndex(m_labelFiles, fileIndex); return m_labelFiles[fileIndex]; } /** * Get a label file at the specified index. * @param fileIndex * Index of the label file. * @return * Metric file at the index. */ const LabelFile* BrainStructure::getLabelFile(const int32_t fileIndex) const { CaretAssertVectorIndex(m_labelFiles, fileIndex); return m_labelFiles[fileIndex]; } /** * Get all of the metric files. * @param metricFilesOut * Will contain all metric files after this method exits. */ void BrainStructure::getMetricFiles(std::vector& metricFilesOut) const { metricFilesOut.clear(); metricFilesOut.insert(metricFilesOut.end(), m_metricFiles.begin(), m_metricFiles.end()); } /** * Get the number of metric files. * @return Number of metric files. */ int32_t BrainStructure::getNumberOfMetricFiles() const { return m_metricFiles.size(); } /** * Get a metric file at the specified index. * @param fileIndex * Index of the metric file. * @return * Metric file at the index. */ MetricFile* BrainStructure::getMetricFile(const int32_t fileIndex) { CaretAssertVectorIndex(m_metricFiles, fileIndex); return m_metricFiles[fileIndex]; } /** * Get a metric file at the specified index. * @param fileIndex * Index of the metric file. * @return * Metric file at the index. */ const MetricFile* BrainStructure::getMetricFile(const int32_t fileIndex) const { CaretAssertVectorIndex(m_metricFiles, fileIndex); return m_metricFiles[fileIndex]; } /** * Get the number of rgba files. * @return Number of rgba files. */ int32_t BrainStructure::getNumberOfRgbaFiles() const { return m_rgbaFiles.size(); } /** * Get a rgba file at the specified index. * @param fileIndex * Index of the rgba file. * @return * Metric file at the index. */ RgbaFile* BrainStructure::getRgbaFile(const int32_t fileIndex) { CaretAssertVectorIndex(m_rgbaFiles, fileIndex); return m_rgbaFiles[fileIndex]; } /** * Get a rgba file at the specified index. * @param fileIndex * Index of the rgba file. * @return * Metric file at the index. */ const RgbaFile* BrainStructure::getRgbaFile(const int32_t fileIndex) const { CaretAssertVectorIndex(m_rgbaFiles, fileIndex); return m_rgbaFiles[fileIndex]; } /** * Get all of the rgba files. * @param rgbaFilesOut * Will contain all rgba files after this method exits. */ void BrainStructure::getRgbaFiles(std::vector& rgbaFilesOut) const { rgbaFilesOut.clear(); rgbaFilesOut.insert(rgbaFilesOut.end(), m_rgbaFiles.begin(), m_rgbaFiles.end()); } /** * Receive events from the event manager. * * @param event * The event. */ void BrainStructure::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_BRAIN_STRUCTURE_GET_ALL) { EventBrainStructureGetAll* brainStructureEvent = dynamic_cast(event); CaretAssert(brainStructureEvent); brainStructureEvent->addBrainStructure(this); brainStructureEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_GET_NODE_DATA_FILES) { EventNodeDataFilesGet* dataFilesEvent = dynamic_cast(event); CaretAssert(dataFilesEvent); const Surface* associatedSurface = dataFilesEvent->getSurface(); if (associatedSurface != NULL) { if (containsSurface(associatedSurface) == false) { return; } } for (std::vector::iterator labelIter = m_labelFiles.begin(); labelIter != m_labelFiles.end(); labelIter++) { dataFilesEvent->addFile(*labelIter); } for (std::vector::iterator metricIter = m_metricFiles.begin(); metricIter != m_metricFiles.end(); metricIter++) { dataFilesEvent->addFile(*metricIter); } for (std::vector::iterator rgbaIter = m_rgbaFiles.begin(); rgbaIter != m_rgbaFiles.end(); rgbaIter++) { dataFilesEvent->addFile(*rgbaIter); } dataFilesEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_SURFACES_GET) { EventSurfacesGet* getSurfacesEvent = dynamic_cast(event); CaretAssert(getSurfacesEvent); const int32_t numSurfaces = getNumberOfSurfaces(); for (int32_t i = 0; i < numSurfaces; i++) { getSurfacesEvent->addSurface(getSurface(i)); } getSurfacesEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_SURFACE_STRUCTURES_VALID_GET) { EventSurfaceStructuresValidGet* structEvent = dynamic_cast(event); CaretAssert(structEvent); structEvent->addStructure(m_structure, getNumberOfNodes()); } } /** * @return Return the unique identifier for this brain structure. */ int64_t BrainStructure::getBrainStructureIdentifier() const { return m_brainStructureIdentifier; } /** * Get the attributes for this brain structure. * @return * Attributes for this brain structure. */ BrainStructureNodeAttributes* BrainStructure::getNodeAttributes() { return m_nodeAttributes; } /** * Get the attributes for this brain structure. * @return * Attributes for this brain structure. */ const BrainStructureNodeAttributes* BrainStructure::getNodeAttributes() const { return m_nodeAttributes; } /** * @return True if this brain structure contains any data files, else false. */ bool BrainStructure::hasDataFiles() const { std::vector allDataFiles; getAllDataFiles(allDataFiles); return ( ! allDataFiles.empty()); } /** * Get all loaded data files. * @param allDataFilesOut * Data files are loaded into this parameter. */ void BrainStructure::getAllDataFiles(std::vector& allDataFilesOut) const { allDataFilesOut.insert(allDataFilesOut.end(), m_surfaces.begin(), m_surfaces.end()); allDataFilesOut.insert(allDataFilesOut.end(), m_labelFiles.begin(), m_labelFiles.end()); for (auto mf : m_metricFiles) { allDataFilesOut.push_back(mf); MetricDynamicConnectivityFile* dynFile = mf->getMetricDynamicConnectivityFile(); if (dynFile != NULL) { if (dynFile->isDataValid()) { allDataFilesOut.push_back(dynFile); } } } allDataFilesOut.insert(allDataFilesOut.end(), m_rgbaFiles.begin(), m_rgbaFiles.end()); } /** * Remove the data file from memory but DO NOT delete it. * * @param caretDataFile * Caret file that is removed from the Brain. After calling this method * and the file was removed( true was returned), the caller is responsible * for deleting the file when it is no longer needed. * @return * True if the file was removed, else false. */ bool BrainStructure::removeWithoutDeleteDataFile(const CaretDataFile* caretDataFile) { std::vector::iterator surfaceIterator = std::find(m_surfaces.begin(), m_surfaces.end(), caretDataFile); if (surfaceIterator != m_surfaces.end()) { Surface* s = *surfaceIterator; removeAndMaybeDeleteSurface(s, false); return true; } std::vector::iterator labelIterator = std::find(m_labelFiles.begin(), m_labelFiles.end(), caretDataFile); if (labelIterator != m_labelFiles.end()) { m_labelFiles.erase(labelIterator); return true; } std::vector::iterator metricIterator = std::find(m_metricFiles.begin(), m_metricFiles.end(), caretDataFile); if (metricIterator != m_metricFiles.end()) { m_metricFiles.erase(metricIterator); return true; } std::vector::iterator rgbaIterator = std::find(m_rgbaFiles.begin(), m_rgbaFiles.end(), caretDataFile); if (rgbaIterator != m_rgbaFiles.end()) { m_rgbaFiles.erase(rgbaIterator); return true; } return false; } ///** // * Remove AND DELETE a data file from memory (does NOT delete file on disk.) // * Searches all of the loaded files for given file, and, when found // * deletes the file. // * // * @param caretDataFile // * Data file to remove. After calling this method and the file was // * deleted (true was returned) this pointer is no longer valid. // * @return // * true if file was removed, else false. // */ //bool //BrainStructure::removeAndDeleteDataFile(CaretDataFile* caretDataFile) //{ // if (removeWithoutDeleteDataFile(caretDataFile)) { // delete caretDataFile; // return true; // } // // return false; // std::vector::iterator surfaceIterator = // std::find(m_surfaces.begin(), // m_surfaces.end(), // caretDataFile); // if (surfaceIterator != m_surfaces.end()) { // Surface* s = *surfaceIterator; // removeSurface(s); // return true; // } // // std::vector::iterator labelIterator = // std::find(m_labelFiles.begin(), // m_labelFiles.end(), // caretDataFile); // if (labelIterator != m_labelFiles.end()) { // delete caretDataFile; // m_labelFiles.erase(labelIterator); // return true; // } // // std::vector::iterator metricIterator = // std::find(m_metricFiles.begin(), // m_metricFiles.end(), // caretDataFile); // if (metricIterator != m_metricFiles.end()) { // delete caretDataFile; // m_metricFiles.erase(metricIterator); // return true; // } // // std::vector::iterator rgbaIterator = // std::find(m_rgbaFiles.begin(), // m_rgbaFiles.end(), // caretDataFile); // if (rgbaIterator != m_rgbaFiles.end()) { // delete caretDataFile; // m_rgbaFiles.erase(rgbaIterator); // return true; // } // // return false; //} /** * Find a map in a metric file that contains shape data. * It first looks for a shape NIFTI intent code. If that * is not found it looks for curvature, shape, depth, etc. * @param metricFileOut * Output metric file that contains the shape map. * @param shapeMapIndexOut * Output containing index of shape map. * @return * True if a shape map was found, else false. */ bool BrainStructure::getMetricShapeMap(MetricFile* &shapeMetricFileOut, int32_t& shapeMapIndexOut) const { shapeMetricFileOut = NULL; shapeMapIndexOut = -1; MetricFile* depthMetricFile = NULL; int32_t depthMapIndex = -1; MetricFile* depthNamedMetricFile = NULL; MetricFile* curvatureMetricFile = NULL; int32_t curvatureMapIndex = -1; MetricFile* curvatureNamedMetricFile = NULL; MetricFile* shapeNamedMetricFile = NULL; MetricFile* sulcMetricFile = NULL; int32_t sulcMapIndex = -1; MetricFile* sulcNamedMetricFile = NULL; const int numFiles = m_metricFiles.size(); for (int32_t i = 0; i < numFiles; i++) { MetricFile* mf = m_metricFiles[i]; const AString filename = mf->getFileNameNoPath().toLower(); const int32_t numMaps = mf->getNumberOfMaps(); for (int32_t j = 0; j < numMaps; j++) { const AString mapName = mf->getMapName(j).toLower(); if (mapName.contains("sulc")) { if (sulcMetricFile == NULL) { sulcMetricFile = mf; sulcMapIndex = j; } } else if (mapName.contains("depth")) { if (depthMetricFile == NULL) { depthMetricFile = mf; depthMapIndex = j; } } else if (mapName.contains("curv")) { if (curvatureMetricFile == NULL) { curvatureMetricFile = mf; curvatureMapIndex = j; } } } if (filename.contains("sulc")) { if (numMaps > 0) { sulcNamedMetricFile = mf; } } if (filename.contains("shape")) { if (numMaps > 0) { shapeNamedMetricFile = mf; } } if (filename.contains("curv")) { if (numMaps > 0) { curvatureNamedMetricFile = mf; } } if (filename.contains("depth")) { if (numMaps > 0) { depthNamedMetricFile = mf; } } } if (sulcMetricFile != NULL) { shapeMetricFileOut = sulcMetricFile; shapeMapIndexOut = sulcMapIndex; } else if (depthMetricFile != NULL) { shapeMetricFileOut = depthMetricFile; shapeMapIndexOut = depthMapIndex; } else if (curvatureMetricFile != NULL) { shapeMetricFileOut = curvatureMetricFile; shapeMapIndexOut = curvatureMapIndex; } else if (sulcNamedMetricFile != NULL) { shapeMetricFileOut = sulcNamedMetricFile; shapeMapIndexOut = 0; } else if (depthNamedMetricFile != NULL) { shapeMetricFileOut = depthNamedMetricFile; shapeMapIndexOut = 0; } else if (curvatureNamedMetricFile != NULL) { shapeMetricFileOut = curvatureNamedMetricFile; shapeMapIndexOut = 0; } else if (shapeNamedMetricFile != NULL) { shapeMetricFileOut = shapeNamedMetricFile; shapeMapIndexOut = 0; } if ((shapeMetricFileOut != NULL) && (shapeMapIndexOut >= 0)) { return true; } return false; } /** * Get the overlay set for the given tab. * @param tabIndex * Index of tab. * @return * Overlay set at the given tab index. */ OverlaySet* BrainStructure::getOverlaySet(const int tabIndex) { return m_overlaySetArray->getOverlaySet(tabIndex); } /** * Get the overlay set for the given tab. * @param tabIndex * Index of tab. * @return * Overlay set at the given tab index. */ const OverlaySet* BrainStructure::getOverlaySet(const int tabIndex) const { return m_overlaySetArray->getOverlaySet(tabIndex); } /** * Initilize the overlays for this model. */ void BrainStructure::initializeOverlays() { m_overlaySetArray->initializeOverlaySelections(); } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* BrainStructure::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "BrainStructure", 1); sceneClass->addInteger("numberOfNodes", getNumberOfNodes()); sceneClass->addEnumeratedType("m_structure", m_structure); sceneClass->addClass(m_nodeAttributes->saveToScene(sceneAttributes, "m_nodeAttributes")); /* * Save Group/Name Selection Hierarchies */ for (std::vector::iterator labelIter = m_labelFiles.begin(); labelIter != m_labelFiles.end(); labelIter++) { LabelFile* lf = *labelIter; sceneClass->addClass(lf->getGroupAndNameHierarchyModel()->saveToScene(sceneAttributes, lf->getFileNameNoPath())); } const Surface* primAnatSurface = getPrimaryAnatomicalSurface(); if (primAnatSurface != NULL) { sceneClass->addPathName("primaryAnatomicalSurface", primAnatSurface->getFileName()); } return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void BrainStructure::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } const int32_t numNodes = sceneClass->getIntegerValue("numberOfNodes", 0); const StructureEnum::Enum structure = sceneClass->getEnumeratedTypeValue("m_structure", StructureEnum::INVALID); /* * Since there may be multiple brain structures in scene, * match by structure-type and number of nodes */ if ((numNodes == getNumberOfNodes()) && (structure == m_structure)) { m_nodeAttributes->restoreFromScene(sceneAttributes, sceneClass->getClass("m_nodeAttributes")); /* * Save Group/Name Selection Hierarchies */ for (std::vector::iterator labelIter = m_labelFiles.begin(); labelIter != m_labelFiles.end(); labelIter++) { LabelFile* lf = *labelIter; const SceneClass* labelClass = sceneClass->getClass(lf->getFileNameNoPath()); lf->getGroupAndNameHierarchyModel()->restoreFromScene(sceneAttributes, labelClass); } } const ScenePathName* primAnatScenePathName = sceneClass->getPathName("primaryAnatomicalSurface"); if (primAnatScenePathName != NULL) { const AString surfaceFileName = primAnatScenePathName->stringValue(); if ( ! surfaceFileName.isEmpty()) { for (std::vector::iterator iter = m_surfaces.begin(); iter != m_surfaces.end(); iter++) { Surface* surface = *iter; CaretAssert(surface); if (surface->getFileName() == surfaceFileName) { setPrimaryAnatomicalSurface(surface); break; } } } } } /** * Match surface sizes to the primary anatomical surface * * @param matchStatus * The match status */ void BrainStructure::matchSurfacesToPrimaryAnatomical(const bool matchStatus) { const Surface* primaryAnatomical = getPrimaryAnatomicalSurface(); if (primaryAnatomical == NULL) { return; } for (auto s : m_surfaces) { if (s != primaryAnatomical) { s->matchToAnatomicalSurface(primaryAnatomical, matchStatus); } } } connectome-workbench-1.4.2/src/Brain/BrainStructure.h000066400000000000000000000160261360521144700226070ustar00rootroot00000000000000 #ifndef __BRAIN_STRUCTURE_H__ #define __BRAIN_STRUCTURE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "BrainConstants.h" #include "CaretObject.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" #include "StructureEnum.h" #include "SurfaceTypeEnum.h" namespace caret { class Brain; class BrainStructureNodeAttributes; class CaretDataFile; class LabelFile; class MetricFile; class ModelSurface; class OverlaySet; class OverlaySetArray; class RgbaFile; class Surface; /** * Maintains view of some type of object. */ class BrainStructure : public CaretObject, public EventListenerInterface, public SceneableInterface { public: BrainStructure(Brain* brain, StructureEnum::Enum structure); ~BrainStructure(); void receiveEvent(Event* event); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: BrainStructure(const BrainStructure& s); BrainStructure& operator=(const BrainStructure& s); public: void addLabelFile(LabelFile* labelFile, const bool addFileToBrainStructure); void addMetricFile(MetricFile* metricFile, const bool addFileToBrainStructure); void addRgbaFile(RgbaFile* rgbaFile, const bool addFileToBrainStructure); void addSurface(Surface* surface, const bool addFileToBrainStructure, const bool initilizeOverlaysFlag); int getNumberOfSurfaces() const; Surface* getSurface(const int32_t indx); const Surface* getSurface(const int32_t indx) const; void getSurfacesOfType(const SurfaceTypeEnum::Enum surfaceType, std::vector& surfacesOut) const; bool containsSurface(const Surface* surface); const Surface* getPrimaryAnatomicalSurface() const; Surface* getPrimaryAnatomicalSurface(); const Surface* getSurfaceContainingTextInName(const AString& text) const; Surface* getSurfaceContainingTextInName(const AString& text); Surface* getSurfaceWithName(const AString& surfaceFileName, const bool useAbsolutePath); void getSurfaces(std::vector& surfacesOut) const; void setPrimaryAnatomicalSurface(Surface* surface); Brain* getBrain(); const Brain* getBrain() const; int32_t getNumberOfNodes() const; StructureEnum::Enum getStructure() const; int32_t getNumberOfLabelFiles() const; LabelFile* getLabelFile(const int32_t fileIndex); const LabelFile* getLabelFile(const int32_t fileIndex) const; void getLabelFiles(std::vector& labelFilesOut) const; int32_t getNumberOfMetricFiles() const; MetricFile* getMetricFile(const int32_t fileIndex); const MetricFile* getMetricFile(const int32_t fileIndex) const; void getMetricFiles(std::vector& metricFilesOut) const; int32_t getNumberOfRgbaFiles() const; RgbaFile* getRgbaFile(const int32_t fileIndex); const RgbaFile* getRgbaFile(const int32_t fileIndex) const; void getRgbaFiles(std::vector& labelFilesOut) const; int64_t getBrainStructureIdentifier() const; BrainStructureNodeAttributes* getNodeAttributes(); const BrainStructureNodeAttributes* getNodeAttributes() const; bool hasDataFiles() const; void getAllDataFiles(std::vector& allDataFilesOut) const; bool removeWithoutDeleteDataFile(const CaretDataFile* caretDataFile); //bool removeAndDeleteDataFile(CaretDataFile* caretDataFile); bool getMetricShapeMap(MetricFile* &metricFileOut, int32_t& shapeMapIndexOut) const; OverlaySet* getOverlaySet(const int tabIndex); const OverlaySet* getOverlaySet(const int tabIndex) const; void initializeOverlays(); void matchSurfacesToPrimaryAnatomical(const bool matchStatus); private: const Surface* getPrimaryAnatomicalSurfacePrivate() const; const Surface* getSurfaceContainingTextInNamePrivate(const AString& text) const; bool removeAndMaybeDeleteSurface(Surface* surface, const bool deleteSurfaceFile); Brain* m_brain; StructureEnum::Enum m_structure; /** Overlays sets for this model and for each tab */ //OverlaySet* m_overlaySet[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; OverlaySetArray* m_overlaySetArray; std::vector m_surfaces; std::vector m_labelFiles; std::vector m_metricFiles; std::vector m_rgbaFiles; /** Maps a surface to its model */ std::map m_surfaceModelMap; /** Unique number assigned to each brain structure. */ int64_t m_brainStructureIdentifier; /** Generates unique number assigned to each brain structure */ static int64_t s_brainStructureIdentifierCounter; BrainStructureNodeAttributes* m_nodeAttributes; mutable Surface* m_primaryAnatomicalSurface; }; #ifdef __BRAIN_STRUCTURE_DEFINE__ int64_t BrainStructure::s_brainStructureIdentifierCounter = 1; #endif // __BRAIN_STRUCTURE_DEFINE__ } // namespace #endif // __BRAIN_STRUCTURE_H__ connectome-workbench-1.4.2/src/Brain/BrainStructureNodeAttributes.cxx000066400000000000000000000066721360521144700260450ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __BRAIN_STRUCTURE_NODE_ATTRIBUTE_DECLARE__ #include "BrainStructureNodeAttributes.h" #undef __BRAIN_STRUCTURE_NODE_ATTRIBUTE_DECLARE__ #include "CaretAssert.h" #include "SceneClass.h" using namespace caret; /** * \class caret::BrainStructureNodeAttributes * \brief Contains attributes for all node in a brain structure. * * Contains attributes for all nodes in a brain structure. * If the number of nodes in the brain structure changes, * this class' update() method must be called. */ /** * Constructor. */ BrainStructureNodeAttributes::BrainStructureNodeAttributes() : CaretObject() { this->update(0); } /** * Destructor. */ BrainStructureNodeAttributes::~BrainStructureNodeAttributes() { } /** * Get a description of this object's content. * @return String describing this object's content. */ AString BrainStructureNodeAttributes::toString() const { return ("BrainStructureNodeAttributes"); } void BrainStructureNodeAttributes::update(const int32_t /*numberOfNodes*/) { // if (numberOfNodes > 0) { // m_identificationType.resize(numberOfNodes); // this->setAllIdentificationNone(); // } // else { // m_identificationType.clear(); // } } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* BrainStructureNodeAttributes::saveToScene(const SceneAttributes* /*sceneAttributes*/, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "BrainStructureNodeAttributes", 1); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void BrainStructureNodeAttributes::restoreFromScene(const SceneAttributes* /*sceneAttributes*/, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } } connectome-workbench-1.4.2/src/Brain/BrainStructureNodeAttributes.h000066400000000000000000000040471360521144700254640ustar00rootroot00000000000000#ifndef __BRAIN_STRUCTURE_NODE_ATTRIBUTE__H_ #define __BRAIN_STRUCTURE_NODE_ATTRIBUTE__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "SceneableInterface.h" namespace caret { class BrainStructureNodeAttributes : public CaretObject, public SceneableInterface { public: BrainStructureNodeAttributes(); virtual ~BrainStructureNodeAttributes(); void update(const int32_t numberOfNodes); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: BrainStructureNodeAttributes(const BrainStructureNodeAttributes&); BrainStructureNodeAttributes& operator=(const BrainStructureNodeAttributes&); public: virtual AString toString() const; private: }; #ifdef __BRAIN_STRUCTURE_NODE_ATTRIBUTE_DECLARE__ // #endif // __BRAIN_STRUCTURE_NODE_ATTRIBUTE_DECLARE__ } // namespace #endif //__BRAIN_STRUCTURE_NODE_ATTRIBUTE__H_ connectome-workbench-1.4.2/src/Brain/BrowserTabContent.cxx000066400000000000000000005304611360521144700236170ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __BROWSER_TAB_CONTENT_DECLARE__ #include "BrowserTabContent.h" #undef __BROWSER_TAB_CONTENT_DECLARE__ #include "AnnotationColorBar.h" #include "BorderFile.h" #include "Brain.h" #include "BrainOpenGLViewportContent.h" #include "BrainStructure.h" #include "CaretAssert.h" #include "CaretDataFileSelectionModel.h" #include "CaretLogger.h" #include "CaretMappableDataFileAndMapSelectionModel.h" #include "ChartData.h" #include "ChartMatrixDisplayProperties.h" #include "CaretPreferences.h" #include "ChartableMatrixInterface.h" #include "ChartModelDataSeries.h" #include "ChartTwoMatrixDisplayProperties.h" #include "ChartTwoOverlay.h" #include "ChartTwoOverlaySet.h" #include "CiftiBrainordinateDataSeriesFile.h" #include "CiftiConnectivityMatrixDenseDynamicFile.h" #include "ClippingPlaneGroup.h" #include "GroupAndNameHierarchyGroup.h" #include "GroupAndNameHierarchyModel.h" #include "GroupAndNameHierarchyName.h" #include "DeveloperFlagsEnum.h" #include "DisplayPropertiesBorders.h" #include "DisplayPropertiesFoci.h" #include "EventAnnotationColorBarGet.h" #include "EventCaretMappableDataFilesAndMapsInDisplayedOverlays.h" #include "EventCaretMappableDataFileMapsViewedInOverlays.h" #include "EventIdentificationHighlightLocation.h" #include "EventModelGetAll.h" #include "EventManager.h" #include "FociFile.h" #include "IdentificationManager.h" #include "LabelFile.h" #include "MathFunctions.h" #include "Matrix4x4.h" #include "MetricDynamicConnectivityFile.h" #include "ModelChart.h" #include "ModelChartTwo.h" #include "ModelSurface.h" #include "ModelSurfaceMontage.h" #include "ModelSurfaceSelector.h" #include "ModelTransform.h" #include "ModelVolume.h" #include "ModelWholeBrain.h" #include "Overlay.h" #include "OverlaySet.h" #include "PaletteColorMapping.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "SessionManager.h" #include "Surface.h" #include "SurfaceMontageConfigurationCerebellar.h" #include "SurfaceMontageConfigurationCerebral.h" #include "SurfaceMontageConfigurationFlatMaps.h" #include "SurfaceSelectionModel.h" #include "StructureEnum.h" #include "VolumeFile.h" #include "ViewingTransformations.h" #include "ViewingTransformationsCerebellum.h" #include "ViewingTransformationsVolume.h" #include "VolumeDynamicConnectivityFile.h" #include "VolumeSliceSettings.h" #include "VolumeSurfaceOutlineModel.h" #include "VolumeSurfaceOutlineSetModel.h" #include "WholeBrainSurfaceSettings.h" using namespace caret; /** * Constructor. * @param tabNumber * Number for this tab. */ BrowserTabContent::BrowserTabContent(const int32_t tabNumber) : TabContentBase() { isExecutingConstructor = true; s_allBrowserTabContent.insert(this); const CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); m_tabNumber = tabNumber; m_surfaceModelSelector = new ModelSurfaceSelector(); m_selectedModelType = ModelTypeEnum::MODEL_TYPE_INVALID; m_volumeModel = NULL; m_wholeBrainModel = NULL; m_surfaceMontageModel = NULL; m_chartModel = NULL; m_chartTwoModel = NULL; m_guiName = ""; m_userName = ""; m_volumeSurfaceOutlineSetModel = new VolumeSurfaceOutlineSetModel(); m_brainModelYokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; m_chartModelYokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; m_identificationUpdatesVolumeSlices = prefs->isVolumeIdentificationDefaultedOn(); m_displayVolumeAxesCrosshairs = prefs->isVolumeAxesCrosshairsDisplayed(); m_displayVolumeAxesCrosshairLabels = prefs->isVolumeAxesLabelsDisplayed(); m_displayVolumeMontageAxesCoordinates = prefs->isVolumeMontageAxesCoordinatesDisplayed(); m_volumeMontageCoordinatePrecision = prefs->getVolumeMontageCoordinatePrecision(); m_lightingEnabled = true; m_aspectRatio = 1.0; m_aspectRatioLocked = false; m_cerebellumViewingTransformation = new ViewingTransformationsCerebellum(); m_flatSurfaceViewingTransformation = new ViewingTransformations(); m_viewingTransformation = new ViewingTransformations(); m_volumeSliceViewingTransformation = new ViewingTransformationsVolume(); m_chartTwoMatrixViewingTranformation = new ViewingTransformations(); m_chartTwoMatrixDisplayProperties = new ChartTwoMatrixDisplayProperties(); m_wholeBrainSurfaceSettings = new WholeBrainSurfaceSettings(); m_obliqueVolumeRotationMatrix = new Matrix4x4(); leftView(); m_volumeSliceSettings = new VolumeSliceSettings(); m_clippingPlaneGroup = new ClippingPlaneGroup(); m_sceneClassAssistant = new SceneClassAssistant(); m_sceneClassAssistant->add("m_tabNumber", &m_tabNumber); m_sceneClassAssistant->add("m_userName", &m_userName); m_sceneClassAssistant->add("m_selectedModelType", &m_selectedModelType); m_sceneClassAssistant->add("m_surfaceModelSelector", "ModelSurfaceSelector", m_surfaceModelSelector); m_sceneClassAssistant->add("m_volumeSurfaceOutlineSetModel", "VolumeSurfaceOutlineSetModel", m_volumeSurfaceOutlineSetModel); m_sceneClassAssistant->add("m_clippingPlaneGroup", "ClippingPlaneGroup", m_clippingPlaneGroup); m_sceneClassAssistant->add("m_cerebellumViewingTransformation", "ViewingTransformations", m_cerebellumViewingTransformation); m_sceneClassAssistant->add("m_flatSurfaceViewingTransformation", "ViewingTransformations", m_flatSurfaceViewingTransformation); m_sceneClassAssistant->add("m_viewingTransformation", "ViewingTransformations", m_viewingTransformation); m_sceneClassAssistant->add("m_volumeSliceViewingTransformation", "ViewingTransformations", m_volumeSliceViewingTransformation); m_sceneClassAssistant->add("m_chartTwoMatrixViewingTranformation", "ViewingTransformations", m_chartTwoMatrixViewingTranformation); m_sceneClassAssistant->add("m_chartTwoMatrixDisplayProperties", "ChartTwoMatrixDisplayProperties", m_chartTwoMatrixDisplayProperties); m_sceneClassAssistant->add("m_volumeSliceSettings", "VolumeSliceSettings", m_volumeSliceSettings); m_sceneClassAssistant->add("m_wholeBrainSurfaceSettings", "WholeBrainSurfaceSettings", m_wholeBrainSurfaceSettings); m_sceneClassAssistant->add("m_identificationUpdatesVolumeSlices", &m_identificationUpdatesVolumeSlices); m_sceneClassAssistant->add("m_displayVolumeAxesCrosshairs", &m_displayVolumeAxesCrosshairs); m_sceneClassAssistant->add("m_displayVolumeAxesCrosshairLabels", &m_displayVolumeAxesCrosshairLabels); m_sceneClassAssistant->add("m_displayVolumeMontageAxesCoordinates", &m_displayVolumeMontageAxesCoordinates); m_sceneClassAssistant->add("m_volumeMontageCoordinatePrecision", &m_volumeMontageCoordinatePrecision); m_sceneClassAssistant->add("m_lightingEnabled", &m_lightingEnabled); m_sceneClassAssistant->add("m_aspectRatio", &m_aspectRatio); m_sceneClassAssistant->add("m_aspectRatioLocked", &m_aspectRatioLocked); m_sceneClassAssistant->add("m_brainModelYokingGroup", &m_brainModelYokingGroup); m_sceneClassAssistant->add("m_chartModelYokingGroup", &m_chartModelYokingGroup); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_COLOR_BAR_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_IDENTIFICATION_HIGHLIGHT_LOCATION); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS); isExecutingConstructor = false; /* * Need to be done from here */ if (prefs->isYokingDefaultedOn()) { setBrainModelYokingGroup(YokingGroupEnum::YOKING_GROUP_A); setChartModelYokingGroup(YokingGroupEnum::YOKING_GROUP_OFF); } } /** * Destructor. */ BrowserTabContent::~BrowserTabContent() { EventManager::get()->removeAllEventsFromListener(this); s_allBrowserTabContent.erase(this); delete m_clippingPlaneGroup; delete m_flatSurfaceViewingTransformation; delete m_cerebellumViewingTransformation; delete m_viewingTransformation; delete m_volumeSliceViewingTransformation; delete m_chartTwoMatrixViewingTranformation; delete m_chartTwoMatrixDisplayProperties; delete m_obliqueVolumeRotationMatrix; delete m_surfaceModelSelector; m_surfaceModelSelector = NULL; delete m_volumeSurfaceOutlineSetModel; m_volumeSurfaceOutlineSetModel = NULL; delete m_volumeSliceSettings; delete m_wholeBrainSurfaceSettings; delete m_sceneClassAssistant; m_sceneClassAssistant = NULL; } /** * Clone the contents of the given browser tab. * @param tabToClone * Tab whose contents is cloned. */ void BrowserTabContent::cloneBrowserTabContent(BrowserTabContent* tabToClone) { CaretAssert(tabToClone); m_surfaceModelSelector->setSelectedStructure(tabToClone->m_surfaceModelSelector->getSelectedStructure()); m_surfaceModelSelector->setSelectedSurfaceModel(tabToClone->m_surfaceModelSelector->getSelectedSurfaceModel()); m_selectedModelType = tabToClone->m_selectedModelType; /* * */ EventModelGetAll allModelsEvent; EventManager::get()->sendEvent(allModelsEvent.getPointer()); std::vector allModels = allModelsEvent.getModels(); for (std::vector::iterator modelIter = allModels.begin(); modelIter != allModels.end(); modelIter++) { Model* model = *modelIter; model->copyTabContent(tabToClone->m_tabNumber, m_tabNumber); } *m_clippingPlaneGroup = *tabToClone->m_clippingPlaneGroup; m_brainModelYokingGroup = tabToClone->m_brainModelYokingGroup; m_chartModelYokingGroup = tabToClone->m_chartModelYokingGroup; m_aspectRatio = tabToClone->m_aspectRatio; m_aspectRatioLocked = tabToClone->m_aspectRatioLocked; *m_cerebellumViewingTransformation = *tabToClone->m_cerebellumViewingTransformation; *m_flatSurfaceViewingTransformation = *tabToClone->m_flatSurfaceViewingTransformation; *m_viewingTransformation = *tabToClone->m_viewingTransformation; *m_volumeSliceViewingTransformation = *tabToClone->m_volumeSliceViewingTransformation; *m_chartTwoMatrixViewingTranformation = *tabToClone->m_chartTwoMatrixViewingTranformation; *m_chartTwoMatrixDisplayProperties = *tabToClone->m_chartTwoMatrixDisplayProperties; *m_volumeSliceSettings = *tabToClone->m_volumeSliceSettings; *m_wholeBrainSurfaceSettings = *tabToClone->m_wholeBrainSurfaceSettings; *m_obliqueVolumeRotationMatrix = *tabToClone->m_obliqueVolumeRotationMatrix; m_identificationUpdatesVolumeSlices = tabToClone->m_identificationUpdatesVolumeSlices; m_displayVolumeAxesCrosshairs = tabToClone->m_displayVolumeAxesCrosshairs; m_displayVolumeAxesCrosshairLabels = tabToClone->m_displayVolumeAxesCrosshairLabels; m_displayVolumeMontageAxesCoordinates = tabToClone->m_displayVolumeMontageAxesCoordinates; m_volumeMontageCoordinatePrecision = tabToClone->m_volumeMontageCoordinatePrecision; m_lightingEnabled = tabToClone->m_lightingEnabled; Model* model = getModelForDisplay(); if (model != NULL) { Brain* brain = model->getBrain(); brain->copyDisplayProperties(tabToClone->getTabNumber(), getTabNumber()); const int32_t numberOfBrainStructures = brain->getNumberOfBrainStructures(); for (int32_t i = 0; i < numberOfBrainStructures; i++) { BrainStructure* bs = brain->getBrainStructure(i); const int32_t numLabelFiles = bs->getNumberOfLabelFiles(); for (int32_t j = 0; j < numLabelFiles; j++) { LabelFile* labelFile = bs->getLabelFile(j); labelFile->getGroupAndNameHierarchyModel()->copySelections(tabToClone->getTabNumber(), getTabNumber()); } } const int32_t numBorderFiles = brain->getNumberOfBorderFiles(); for (int32_t i = 0; i < numBorderFiles; i++) { BorderFile* bf = brain->getBorderFile(i); bf->getGroupAndNameHierarchyModel()->copySelections(tabToClone->getTabNumber(), getTabNumber()); } const int32_t numFociFiles = brain->getNumberOfFociFiles(); for (int32_t i = 0; i < numFociFiles; i++) { FociFile* ff = brain->getFociFile(i); ff->getGroupAndNameHierarchyModel()->copySelections(tabToClone->getTabNumber(), getTabNumber()); } } m_volumeSurfaceOutlineSetModel->copyVolumeSurfaceOutlineSetModel(tabToClone->getVolumeSurfaceOutlineSet()); } /** * @return Default name for this tab. */ AString BrowserTabContent::getDefaultName() const { AString s = getTabNamePrefix(); const Model* displayedModel = getModelForDisplay(); if (displayedModel != NULL) { const AString name = displayedModel->getNameForBrowserTab(); s += name; } return s; } /** * @return Prefix for the tab name that consists of the * tab number inside parenthesis. */ AString BrowserTabContent::getTabNamePrefix() const { const AString namePrefix = ("(" + AString::number(m_tabNumber + 1) + ") "); return namePrefix; } /** * Get the name of this browser tab. * * @return Name of this tab. */ AString BrowserTabContent::getTabName() const { if (m_userName.isEmpty()) { return getDefaultName(); } const AString nameOut = (getTabNamePrefix() + m_userName); return nameOut; } /** * Set the user name of this tab. The user name * overrides the default naming. * * @param userName * User name for tab. */ void BrowserTabContent::setUserTabName(const AString& userName) { m_userName = userName.trimmed(); } /** * @return The user name. */ AString BrowserTabContent::getUserTabName() const { return m_userName; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString BrowserTabContent::toString() const { PlainTextStringBuilder tb; getDescriptionOfContent(tb); return tb.getText(); } /** * Get a text description of the window's content. * * @param descriptionOut * Description of the window's content. */ void BrowserTabContent::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const { const int32_t tabIndex = getTabNumber(); descriptionOut.addLine("Browser Tab " + AString::number(tabIndex + 1) + ": "); descriptionOut.pushIndentation(); const Model* model = getModelForDisplay(); if (model != NULL) { bool chartOneFlag = false; bool chartTwoFlag = false; bool surfaceFlag = false; bool surfaceMontageFlag = false; bool wholeBrainFlag = false; bool volumeFlag = false; switch (model->getModelType()) { case ModelTypeEnum::MODEL_TYPE_CHART: chartOneFlag = true; break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: chartTwoFlag = true; break; case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: surfaceFlag = true; break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: surfaceMontageFlag = true; break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: volumeFlag = true; break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: wholeBrainFlag = true; break; } if (chartOneFlag) { model->getDescriptionOfContent(tabIndex, descriptionOut); } else if (volumeFlag) { descriptionOut.addLine("Volume Slice View"); } else if (wholeBrainFlag) { descriptionOut.addLine("All View"); descriptionOut.pushIndentation(); if (isWholeBrainCerebellumEnabled()) { const Surface* cerebellumSurface = m_wholeBrainModel->getSelectedSurface(StructureEnum::CEREBELLUM, tabIndex); if (cerebellumSurface != NULL) { cerebellumSurface->getDescriptionOfContent(descriptionOut); } } if (isWholeBrainLeftEnabled()) { const Surface* leftSurface = m_wholeBrainModel->getSelectedSurface(StructureEnum::CORTEX_LEFT, tabIndex); if (leftSurface != NULL) { leftSurface->getDescriptionOfContent(descriptionOut); } } if (isWholeBrainRightEnabled()) { const Surface* rightSurface = m_wholeBrainModel->getSelectedSurface(StructureEnum::CORTEX_RIGHT, tabIndex); if (rightSurface != NULL) { rightSurface->getDescriptionOfContent(descriptionOut); } } descriptionOut.popIndentation(); } else if (surfaceFlag) { model->getDescriptionOfContent(tabIndex, descriptionOut); } else if (surfaceMontageFlag) { model->getDescriptionOfContent(tabIndex, descriptionOut); } if (wholeBrainFlag || volumeFlag) { descriptionOut.pushIndentation(); m_volumeSliceSettings->getDescriptionOfContent(model->getModelType(), descriptionOut); descriptionOut.popIndentation(); } if (chartOneFlag) { /* nothing */ } else if (chartTwoFlag) { getChartTwoOverlaySet()->getDescriptionOfContent(descriptionOut); } else { getOverlaySet()->getDescriptionOfContent(descriptionOut); } } descriptionOut.popIndentation(); } /** * Get the selected model type. * * @return The selected model type. */ ModelTypeEnum::Enum BrowserTabContent::getSelectedModelType() const { return m_selectedModelType; } /** * Set the selected model type. * * @param selectedModelType * New selected model type. */ void BrowserTabContent::setSelectedModelType(ModelTypeEnum::Enum selectedModelType) { m_selectedModelType = selectedModelType; } /** * Get the model for DISPLAY. * * @return Pointer to displayed model or NULL * if none are available. */ Model* BrowserTabContent::getModelForDisplay() { Model* mdc = NULL; switch (m_selectedModelType) { case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: mdc = m_surfaceModelSelector->getSelectedSurfaceModel(); break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: mdc = m_surfaceMontageModel; break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: mdc = m_volumeModel; break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: mdc = m_wholeBrainModel; break; case ModelTypeEnum::MODEL_TYPE_CHART: mdc = m_chartModel; break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: mdc = m_chartTwoModel; break; } return mdc; } /** * Get the model model for DISPLAY. * * @return Pointer to displayed model or NULL * if none are available. */ const Model* BrowserTabContent::getModelForDisplay() const { Model* mdc = NULL; switch (m_selectedModelType) { case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: mdc = m_surfaceModelSelector->getSelectedSurfaceModel(); break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: mdc = m_surfaceMontageModel; break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: mdc = m_volumeModel; break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: mdc = m_wholeBrainModel; break; case ModelTypeEnum::MODEL_TYPE_CHART: mdc = m_chartModel; break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: mdc = m_chartTwoModel; break; } return mdc; } /** * Get the displayed chart model. * * @return Pointer to displayed chart model or * NULL if the displayed model is NOT a * chart. */ ModelChart* BrowserTabContent::getDisplayedChartOneModel() { ModelChart* mc = dynamic_cast(getModelForDisplay()); return mc; } /** * Get the displayed chart model. * * @return Pointer to displayed chart model or * NULL if the displayed model is NOT a * chart. */ const ModelChart* BrowserTabContent::getDisplayedChartOneModel() const { const ModelChart* mc = dynamic_cast(getModelForDisplay()); return mc; } /** * Get the displayed chart model two. * * @return Pointer to displayed chart model or * NULL if the displayed model is NOT a * chart. */ ModelChartTwo* BrowserTabContent::getDisplayedChartTwoModel() { ModelChartTwo* mc = dynamic_cast(getModelForDisplay()); return mc; } /** * Get the displayed chart model two. * * @return Pointer to displayed chart model or * NULL if the displayed model is NOT a * chart. */ const ModelChartTwo* BrowserTabContent::getDisplayedChartTwoModel() const { const ModelChartTwo* mc = dynamic_cast(getModelForDisplay()); return mc; } /** * Get the displayed surface model. * * @return Pointer to displayed surface model or * NULL if the displayed model is NOT a * surface. */ ModelSurface* BrowserTabContent::getDisplayedSurfaceModel() { ModelSurface* mdcs = dynamic_cast(getModelForDisplay()); return mdcs; } /** * Get the displayed surface model. * * @return Pointer to displayed surface model or * NULL if the displayed model is NOT a * surface. */ const ModelSurface* BrowserTabContent::getDisplayedSurfaceModel() const { const ModelSurface* mdcs = dynamic_cast(getModelForDisplay()); return mdcs; } /** * Get the displayed volume model. * * @return Pointer to displayed volume model or * NULL if the displayed model is NOT a * volume. */ ModelVolume* BrowserTabContent::getDisplayedVolumeModel() { ModelVolume* mdcv = dynamic_cast(getModelForDisplay()); return mdcv; } /** * Get the displayed volume model. * * @return Pointer to displayed volume model or * NULL if the displayed model is NOT a * volume. */ const ModelVolume* BrowserTabContent::getDisplayedVolumeModel() const { const ModelVolume* mdcv = dynamic_cast(getModelForDisplay()); return mdcv; } /** * @return True if the displayed model is a cerebellum surface. */ bool BrowserTabContent::isCerebellumDisplayed() const { const ModelSurface* surfaceModel = getDisplayedSurfaceModel(); if (surfaceModel != NULL) { if (surfaceModel->getSurface()->getStructure() == StructureEnum::CEREBELLUM) { return true; } } const ModelSurfaceMontage* montageModel = getDisplayedSurfaceMontageModel(); if (montageModel != NULL) { if (montageModel->getSelectedConfigurationType(getTabNumber()) == SurfaceMontageConfigurationTypeEnum::CEREBELLAR_CORTEX_CONFIGURATION) { return true; } } return false; } /** * @return True if the displayed model is a flat surface. */ bool BrowserTabContent::isFlatSurfaceDisplayed() const { const ModelSurface* surfaceModel = getDisplayedSurfaceModel(); if (surfaceModel != NULL) { if (surfaceModel->getSurface()->getSurfaceType() == SurfaceTypeEnum::FLAT) { return true; } } const ModelSurfaceMontage* montageModel = getDisplayedSurfaceMontageModel(); if (montageModel != NULL) { if (montageModel->getSelectedConfigurationType(getTabNumber()) == SurfaceMontageConfigurationTypeEnum::FLAT_CONFIGURATION) { return true; } } return false; } /** * @return True if the displayed model is a chart one */ bool BrowserTabContent::isChartOneDisplayed() const { const ModelChart* chartModel = getDisplayedChartOneModel(); if (chartModel != NULL) { return true; } return false; } /** * @return True if the displayed model is a chart two */ bool BrowserTabContent::isChartTwoDisplayed() const { const ModelChartTwo* chartModel = getDisplayedChartTwoModel(); if (chartModel != NULL) { return true; } return false; } /** * @return Is the displayed model a volume slice model? */ bool BrowserTabContent::isVolumeSlicesDisplayed() const { const ModelVolume* mdcv = dynamic_cast(getModelForDisplay()); const bool volumeFlag = (mdcv != NULL); return volumeFlag; } /** * @return Is the displayed model the whole brain model (ALL)? */ bool BrowserTabContent::isWholeBrainDisplayed() const { const ModelWholeBrain* mwb = dynamic_cast(getModelForDisplay()); const bool wholeBrainFlag = (mwb != NULL); return wholeBrainFlag; } /** * Get the displayed whole brain model. * * @return Pointer to displayed whole brain model or * NULL if the displayed model is NOT a * whole brain. */ ModelWholeBrain* BrowserTabContent::getDisplayedWholeBrainModel() { ModelWholeBrain* mdcwb = dynamic_cast(getModelForDisplay()); return mdcwb; } /** * @return Pointer to displayed surface montage model * or NULL if the displayed model is not a surface * montage model. */ ModelSurfaceMontage* BrowserTabContent::getDisplayedSurfaceMontageModel() { ModelSurfaceMontage* mdcsm = dynamic_cast(getModelForDisplay()); return mdcsm; } /** * @return Pointer to displayed surface montage model * or NULL if the displayed model is not a surface * montage model. */ const ModelSurfaceMontage* BrowserTabContent::getDisplayedSurfaceMontageModel() const { const ModelSurfaceMontage* mdcsm = dynamic_cast(getModelForDisplay()); return mdcsm; } /** * Get all of the available surface models. * * @return Vector containing all surface models. */ const std::vector BrowserTabContent::getAllSurfaceModels() const { return m_allSurfaceModels; } /** * @return The surface model selector used to * select a surface and structure. */ ModelSurfaceSelector* BrowserTabContent::getSurfaceModelSelector() { return m_surfaceModelSelector; } /** * Get the overlay assignments for this tab. * * @return Overlay assignments for this tab or NULL if no valid model. */ OverlaySet* BrowserTabContent::getOverlaySet() { Model* model = getModelForDisplay(); if (model != NULL) { return model->getOverlaySet(m_tabNumber); } return NULL; } /** * Get the overlay assignments for this tab. * * @return Overlay assignments for this tab or NULL if no valid model. */ const OverlaySet* BrowserTabContent::getOverlaySet() const { const Model* model = getModelForDisplay(); if (model != NULL) { return model->getOverlaySet(m_tabNumber); } return NULL; } /** * @return Chart overlay set for this tab. */ ChartTwoOverlaySet* BrowserTabContent::getChartTwoOverlaySet() { if (m_chartTwoModel == NULL) { return NULL; } CaretAssert(m_chartTwoModel); return m_chartTwoModel->getChartTwoOverlaySet(m_tabNumber); } /** * @return Chart overlay set for this tab. */ const ChartTwoOverlaySet* BrowserTabContent::getChartTwoOverlaySet() const { if (m_chartTwoModel == NULL) { return NULL; } CaretAssert(m_chartTwoModel); return m_chartTwoModel->getChartTwoOverlaySet(m_tabNumber); } /** * @return Chart two matrix display properties. */ ChartTwoMatrixDisplayProperties* BrowserTabContent::getChartTwoMatrixDisplayProperties() { return m_chartTwoMatrixDisplayProperties; } /** * @return Chart two matrix display properties (const method) */ const ChartTwoMatrixDisplayProperties* BrowserTabContent::getChartTwoMatrixDisplayProperties() const { return m_chartTwoMatrixDisplayProperties; } /** * Get the tab number for this content. * * @return Tab number. */ int32_t BrowserTabContent::getTabNumber() const { return m_tabNumber; } /** * Update the selected models. */ void BrowserTabContent::update(const std::vector models) { m_surfaceModelSelector->updateSelector(models); const int32_t numModels = static_cast(models.size()); ModelVolume* previousVolumeModel = m_volumeModel; m_allSurfaceModels.clear(); m_surfaceModelSelector->getSelectableSurfaceModels(m_allSurfaceModels); m_volumeModel = NULL; m_wholeBrainModel = NULL; m_surfaceMontageModel = NULL; m_chartModel = NULL; m_chartTwoModel = NULL; for (int i = 0; i < numModels; i++) { Model* mdc = models[i]; ModelSurface* mdcs = dynamic_cast(mdc); ModelVolume* mdcv = dynamic_cast(mdc); ModelWholeBrain* mdcwb = dynamic_cast(mdc); ModelSurfaceMontage* mdcsm = dynamic_cast(mdc); ModelChart* mdch = dynamic_cast(mdc); ModelChartTwo* mdchTwo = dynamic_cast(mdc); if (mdcs != NULL) { /* nothing to do since the surface model selector handles surfaces */ } else if (mdcv != NULL) { CaretAssertMessage((m_volumeModel == NULL), "There is more than one volume model."); m_volumeModel = mdcv; } else if (mdcwb != NULL) { CaretAssertMessage((m_wholeBrainModel == NULL), "There is more than one whole brain model."); m_wholeBrainModel = mdcwb; } else if (mdcsm != NULL) { CaretAssertMessage((m_surfaceMontageModel == NULL), "There is more than one surface montage model."); m_surfaceMontageModel = mdcsm; } else if (mdch != NULL) { CaretAssertMessage((m_chartModel == NULL), "There is more than one chart model."); m_chartModel = mdch; } else if (mdchTwo != NULL) { CaretAssertMessage((m_chartTwoModel == NULL), "There is more than one chart two model."); m_chartTwoModel = mdchTwo; } else { CaretAssertMessage(0, (AString("Unknown type of brain model.") + mdc->getNameForGUI(true))); } } switch (m_selectedModelType) { case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: if (m_surfaceModelSelector->getSelectedSurfaceModel() == NULL) { m_selectedModelType = ModelTypeEnum::MODEL_TYPE_INVALID; } break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: if (m_surfaceMontageModel == NULL) { m_selectedModelType = ModelTypeEnum::MODEL_TYPE_INVALID; } break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: if (m_volumeModel == NULL) { m_selectedModelType = ModelTypeEnum::MODEL_TYPE_INVALID; } break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: if (m_wholeBrainModel == NULL) { m_selectedModelType = ModelTypeEnum::MODEL_TYPE_INVALID; } break; case ModelTypeEnum::MODEL_TYPE_CHART: if (m_chartModel == NULL) { m_selectedModelType = ModelTypeEnum::MODEL_TYPE_INVALID; } break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: if (m_chartTwoModel == NULL) { m_selectedModelType = ModelTypeEnum::MODEL_TYPE_INVALID; } break; } if (m_selectedModelType == ModelTypeEnum::MODEL_TYPE_INVALID) { if (m_surfaceMontageModel != NULL) { m_selectedModelType = ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE; } else if (m_volumeModel != NULL) { m_selectedModelType = ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES; } else if (m_wholeBrainModel != NULL) { m_selectedModelType = ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN; } else if (m_chartTwoModel != NULL) { m_selectedModelType = ModelTypeEnum::MODEL_TYPE_CHART_TWO; } else if (m_surfaceModelSelector->getSelectedSurfaceModel() != NULL) { m_selectedModelType = ModelTypeEnum::MODEL_TYPE_SURFACE; } else if (m_chartModel != NULL) { m_selectedModelType = ModelTypeEnum::MODEL_TYPE_CHART; } } if (m_volumeModel != NULL) { if (m_volumeModel != previousVolumeModel) { VolumeMappableInterface* underlayVolume = m_volumeModel->getOverlaySet(m_tabNumber)->getUnderlayVolume(); if (underlayVolume != NULL) { /* * Set montage slice spacing based upon slices * in the Z-axis. */ std::vector dimensions; underlayVolume->getDimensions(dimensions); if (dimensions.size() >= 3) { const int32_t dimZ = dimensions[2]; if (dimZ > 0) { const int32_t maxZ = static_cast(dimZ * 0.90); const int32_t minZ = static_cast(dimZ * 0.10); const int32_t sliceRange = (maxZ - minZ); int32_t sliceSpacing = 1; if (sliceRange > 0) { const int32_t numSlicesViewed = (m_volumeSliceSettings->getMontageNumberOfRows() * m_volumeSliceSettings->getMontageNumberOfColumns()); sliceSpacing = (sliceRange / numSlicesViewed); } m_volumeSliceSettings->setMontageSliceSpacing(sliceSpacing); } } } } } } /** * Is the chart one model selection valid? * * @return bool indicating validity. */ bool BrowserTabContent::isChartOneModelValid() const { bool valid = (m_chartModel != NULL); return valid; } /** * Is the chart two model selection valid? * * @return bool indicating validity. */ bool BrowserTabContent::isChartTwoModelValid() const { bool valid = (m_chartTwoModel != NULL); return valid; } /** * Is the surface model selection valid? * * @return bool indicating validity. */ bool BrowserTabContent::isSurfaceModelValid() const { bool valid = (m_allSurfaceModels.empty() == false); return valid; } /** * Is the volume model selection valid? * * @return bool indicating validity. */ bool BrowserTabContent::isVolumeSliceModelValid() const { bool valid = (m_volumeModel != NULL); return valid; } /** * Is the whole brain model selection valid? * * @return bool indicating validity. */ bool BrowserTabContent::isWholeBrainModelValid() const { bool valid = (m_wholeBrainModel != NULL); return valid; } /** * Is the surface montage model selection valid? * * @return bool indicating validity. */ bool BrowserTabContent::isSurfaceMontageModelValid() const { bool valid = (m_surfaceMontageModel != NULL); return valid; } /** * @return Is the aspect ratio locked? */ bool BrowserTabContent::isAspectRatioLocked() const { return m_aspectRatioLocked; } /** * Set the aspect ratio locked status. * * @param locked * New status. */ void BrowserTabContent::setAspectRatioLocked(const bool locked) { m_aspectRatioLocked = locked; } /** * @return The aspect ratio. */ float BrowserTabContent::getAspectRatio() const { return m_aspectRatio; } /** * Set the aspect ratio. * * @param aspectRatio * New value for aspect ratio. */ void BrowserTabContent::setAspectRatio(const float aspectRatio) { m_aspectRatio = aspectRatio; } /** * Receive an event. * * @param event * The event that the receive can respond to. */ void BrowserTabContent::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_COLOR_BAR_GET) { EventAnnotationColorBarGet* colorBarEvent = dynamic_cast(event); CaretAssert(colorBarEvent); if (colorBarEvent->isGetAnnotationColorBarsForTabIndex(m_tabNumber)) { std::vector colorBars; getAnnotationColorBars(colorBars); colorBarEvent->addAnnotationColorBars(colorBars); } } else if (event->getEventType() == EventTypeEnum::EVENT_IDENTIFICATION_HIGHLIGHT_LOCATION) { EventIdentificationHighlightLocation* idLocationEvent = dynamic_cast(event); CaretAssert(idLocationEvent); Model* model = getModelForDisplay(); if (model == NULL) { return; } if (idLocationEvent->isTabSelected(getTabNumber())) { if (isIdentificationUpdatesVolumeSlices()) { const float* highlighXYZ = idLocationEvent->getXYZ(); for (int32_t windowTabNumber = 0; windowTabNumber < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; windowTabNumber++) { float volumeSliceXYZ[3] = { highlighXYZ[0], highlighXYZ[1], highlighXYZ[2] }; /* * If othogonal/montage viewing, do not alter the slice * coordinate in the axis being viewed */ if (getDisplayedVolumeModel() != NULL) { bool keepSliceCoordinateForSelectedAxis = false; switch (m_volumeSliceSettings->getSliceProjectionType()) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: if (getSliceViewPlane() != VolumeSliceViewPlaneEnum::ALL) { keepSliceCoordinateForSelectedAxis = true; } break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: //keepSliceCoordinateForSelectedAxis = true; break; } switch (m_volumeSliceSettings->getSliceDrawingType()) { case VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_MONTAGE: keepSliceCoordinateForSelectedAxis = true; break; case VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE: break; } if (keepSliceCoordinateForSelectedAxis) { switch (getSliceViewPlane()) { case VolumeSliceViewPlaneEnum::ALL: volumeSliceXYZ[0] = getSliceCoordinateParasagittal(); volumeSliceXYZ[1] = getSliceCoordinateCoronal(); volumeSliceXYZ[2] = getSliceCoordinateAxial(); break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: volumeSliceXYZ[0] = getSliceCoordinateParasagittal(); break; case VolumeSliceViewPlaneEnum::CORONAL: volumeSliceXYZ[1] = getSliceCoordinateCoronal(); break; case VolumeSliceViewPlaneEnum::AXIAL: volumeSliceXYZ[2] = getSliceCoordinateAxial(); break; } } } selectSlicesAtCoordinate(volumeSliceXYZ); //m_volumeSliceSettings->selectSlicesAtCoordinate(volumeSliceXYZ); } } } idLocationEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS) { EventCaretMappableDataFileMapsViewedInOverlays* mapOverlayEvent = dynamic_cast(event); CaretAssert(mapOverlayEvent); OverlaySet* overlaySet = getOverlaySet(); const int32_t numOverlays = overlaySet->getNumberOfDisplayedOverlays(); for (int32_t i = (numOverlays - 1); i >= 0; i--) { Overlay* overlay = overlaySet->getOverlay(i); if (overlay->isEnabled()) { CaretMappableDataFile* mapFile; int32_t mapFileIndex; overlay->getSelectionData(mapFile, mapFileIndex); if (mapFile != NULL) { if (mapFile == mapOverlayEvent->getCaretMappableDataFile()) { if ((mapFileIndex >= 0) && (mapFileIndex < mapFile->getNumberOfMaps())) { mapOverlayEvent->addMapIndex(mapFileIndex); } } } } } } } /** * Get annotation color bars that should be drawn for this tab. * * @param colorBarsOut * Colorbars that should be drawn. */ void BrowserTabContent::getAnnotationColorBars(std::vector& colorBarsOut) { colorBarsOut.clear(); if (getModelForDisplay() == NULL) { return; } bool useOverlayFlag = false; bool useChartOneFlag = false; bool useChartTwoFlag = false; switch (getSelectedModelType()) { case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_CHART: useChartOneFlag = true; break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: useChartTwoFlag = true; break; case ModelTypeEnum::MODEL_TYPE_SURFACE: useOverlayFlag = true; break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: useOverlayFlag = true; break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: useOverlayFlag = true; break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: useOverlayFlag = true; break; } std::vector colorBarMapFileInfo; if (useOverlayFlag) { OverlaySet* overlaySet = getOverlaySet(); const int32_t numOverlays = overlaySet->getNumberOfDisplayedOverlays(); for (int32_t i = (numOverlays - 1); i >= 0; i--) { Overlay* overlay = overlaySet->getOverlay(i); if (overlay->isEnabled()) { AnnotationColorBar* colorBar = overlay->getColorBar(); CaretMappableDataFile* mapFile; int32_t mapIndex; overlay->getSelectionData(mapFile, mapIndex); colorBarMapFileInfo.push_back(ColorBarFileMap(colorBar, mapFile, mapIndex)); } } } if (useChartOneFlag) { ModelChart* modelChart = getDisplayedChartOneModel(); if (modelChart != NULL) { CaretDataFileSelectionModel* fileModel = NULL; switch (modelChart->getSelectedChartOneDataType(m_tabNumber)) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { fileModel = modelChart->getChartableMatrixParcelFileSelectionModel(m_tabNumber); } break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { fileModel = modelChart->getChartableMatrixSeriesFileSelectionModel(m_tabNumber); } } if (fileModel != NULL) { CaretDataFile* caretFile = fileModel->getSelectedFile(); if (caretFile != NULL) { CaretMappableDataFile* mapFile = dynamic_cast(caretFile); if (mapFile != NULL) { ChartableMatrixInterface* matrixFile = dynamic_cast(mapFile); if (matrixFile != NULL) { ChartMatrixDisplayProperties* props = matrixFile->getChartMatrixDisplayProperties(m_tabNumber); AnnotationColorBar* colorBar = props->getColorBar(); const int32_t mapIndex = 0; colorBarMapFileInfo.push_back(ColorBarFileMap(colorBar, mapFile, mapIndex)); } } } } } } if (useChartTwoFlag) { ModelChartTwo* modelChartTwo = getDisplayedChartTwoModel(); if (modelChartTwo != NULL) { ChartTwoOverlaySet* overlaySet = m_chartTwoModel->getChartTwoOverlaySet(m_tabNumber); if (overlaySet != NULL) { const int32_t numOverlays = overlaySet->getNumberOfDisplayedOverlays(); for (int32_t i = 0; i < numOverlays; i++) { ChartTwoOverlay* chartOverlay = overlaySet->getOverlay(i); if (chartOverlay->isEnabled()) { switch (chartOverlay->getChartTwoDataType()) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: { CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; chartOverlay->getSelectionData(mapFile, selectedIndexType, selectedIndex); if (mapFile != NULL) { if (mapFile->isMappedWithPalette()) { AnnotationColorBar* colorBar = chartOverlay->getColorBar(); colorBarMapFileInfo.push_back(ColorBarFileMap(colorBar, mapFile, selectedIndex)); } } } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: { CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; chartOverlay->getSelectionData(mapFile, selectedIndexType, selectedIndex); if (mapFile != NULL) { if (mapFile->isMappedWithPalette()) { AnnotationColorBar* colorBar = chartOverlay->getColorBar(); /* * Matrix is all maps and uses map index 0 */ selectedIndex = 0; colorBarMapFileInfo.push_back(ColorBarFileMap(colorBar, mapFile, selectedIndex)); } } } break; } } } } } } const int32_t numColorBarMapInfo = static_cast(colorBarMapFileInfo.size()); for (int32_t i = 0; i < numColorBarMapInfo; i++) { CaretAssertVectorIndex(colorBarMapFileInfo, i); const ColorBarFileMap& info = colorBarMapFileInfo[i]; if (info.m_colorBar->isDisplayed()) { if (info.m_mapFile != NULL) { if (info.m_mapFile->isMappedWithPalette()) { if ((info.m_mapIndex >= 0) && (info.m_mapIndex < info.m_mapFile->getNumberOfMaps())) { PaletteColorMapping* paletteColorMapping = info.m_mapFile->getMapPaletteColorMapping(info.m_mapIndex); if (paletteColorMapping != NULL) { FastStatistics* statistics = NULL; switch (info.m_mapFile->getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: statistics = const_cast(info.m_mapFile->getFileFastStatistics()); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: statistics = const_cast(info.m_mapFile->getMapFastStatistics(info.m_mapIndex)); break; } /* * Statistics may be NULL for some instances of histograms * from dynamically loaded files (dynconn) */ if (statistics != NULL) { paletteColorMapping->setupAnnotationColorBar(statistics, info.m_colorBar); info.m_colorBar->setTabIndex(m_tabNumber); colorBarsOut.push_back(info.m_colorBar); } } } } } } } } /** * Get the map files for which a palette should be displayed in the * graphcis window. Note that the order of map files and indices starts * with the bottom most layer and ends with the top most overlay. * * @param mapFiles * Outut Map files that should have a palette displayed in the graphics window. * @param mapIndices * Output Indices of the maps in the mapFiles. */ void BrowserTabContent::getDisplayedPaletteMapFiles(std::vector& mapFiles, std::vector& mapIndices) { mapFiles.clear(); mapIndices.clear(); if (getModelForDisplay() == NULL) { return; } bool useOverlayFlag = false; bool useChartOneFlag = false; bool useChartTwoFlag = false; switch (getSelectedModelType()) { case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_CHART: useChartOneFlag = true; break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: useChartTwoFlag = true; break; case ModelTypeEnum::MODEL_TYPE_SURFACE: useOverlayFlag = true; break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: useOverlayFlag = true; break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: useOverlayFlag = true; break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: useOverlayFlag = true; break; } if (useOverlayFlag) { OverlaySet* overlaySet = getOverlaySet(); const int32_t numOverlays = overlaySet->getNumberOfDisplayedOverlays(); for (int32_t i = (numOverlays - 1); i >= 0; i--) { Overlay* overlay = overlaySet->getOverlay(i); if (overlay->isEnabled()) { AnnotationColorBar* colorBar = overlay->getColorBar(); if (colorBar->isDisplayed()) { CaretMappableDataFile* mapFile; int32_t mapFileIndex; overlay->getSelectionData(mapFile, mapFileIndex); if (mapFile != NULL) { if (mapFile->isMappedWithPalette()) { if ((mapFileIndex >= 0) && (mapFileIndex < mapFile->getNumberOfMaps())) { mapFiles.push_back(mapFile); mapIndices.push_back(mapFileIndex); } } } } } } } if (useChartOneFlag) { ModelChart* modelChart = getDisplayedChartOneModel(); if (modelChart != NULL) { CaretDataFileSelectionModel* fileModel = NULL; switch (modelChart->getSelectedChartOneDataType(m_tabNumber)) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { fileModel = modelChart->getChartableMatrixParcelFileSelectionModel(m_tabNumber); } break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { fileModel = modelChart->getChartableMatrixSeriesFileSelectionModel(m_tabNumber); } } if (fileModel != NULL) { CaretDataFile* caretFile = fileModel->getSelectedFile(); if (caretFile != NULL) { CaretMappableDataFile* mapFile = dynamic_cast(caretFile); if (mapFile != NULL) { ChartableMatrixInterface* matrixFile = dynamic_cast(mapFile); if (matrixFile != NULL) { ChartMatrixDisplayProperties* props = matrixFile->getChartMatrixDisplayProperties(m_tabNumber); if (props->getColorBar()->isDisplayed()) { /* * Matrix contains all file data and always * uses a map index of zero. */ mapFiles.push_back(mapFile); mapIndices.push_back(0); } } } } } } } if (useChartTwoFlag) { ModelChartTwo* modelChartTwo = getDisplayedChartTwoModel(); if (modelChartTwo != NULL) { ChartTwoOverlaySet* overlaySet = m_chartTwoModel->getChartTwoOverlaySet(m_tabNumber); const int32_t numOverlays = overlaySet->getNumberOfDisplayedOverlays(); for (int32_t i = (numOverlays - 1); i >= 0; i--) { ChartTwoOverlay* chartOverlay = overlaySet->getOverlay(i); if (chartOverlay->isEnabled()) { switch (chartOverlay->getChartTwoDataType()) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: { CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; chartOverlay->getSelectionData(mapFile, selectedIndexType, selectedIndex); if (mapFile != NULL) { if (mapFile->isMappedWithPalette()) { AnnotationColorBar* colorBar = chartOverlay->getColorBar(); if (colorBar->isDisplayed()) { mapFiles.push_back(mapFile); mapIndices.push_back(selectedIndex); } } } } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: { CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; chartOverlay->getSelectionData(mapFile, selectedIndexType, selectedIndex); if (mapFile != NULL) { if (mapFile->isMappedWithPalette()) { AnnotationColorBar* colorBar = chartOverlay->getColorBar(); if (colorBar->isDisplayed()) { mapFiles.push_back(mapFile); mapIndices.push_back(0); } } } } break; } } } } } CaretAssert(mapFiles.size() == mapIndices.size()); } /** * @return The volume surface outline model for this tab. */ VolumeSurfaceOutlineSetModel* BrowserTabContent::getVolumeSurfaceOutlineSet() { return m_volumeSurfaceOutlineSetModel; } /** * @return The volume surface outline model for this tab. */ const VolumeSurfaceOutlineSetModel* BrowserTabContent::getVolumeSurfaceOutlineSet() const { return m_volumeSurfaceOutlineSetModel; } /** * @return Structures from surface(s) displayed in this tab. */ std::vector BrowserTabContent::getSurfaceStructuresDisplayed() { std::vector allDisplayedFiles; getFilesDisplayedInTab(allDisplayedFiles); std::set structures; for (std::vector::iterator fileIter = allDisplayedFiles.begin(); fileIter != allDisplayedFiles.end(); fileIter++) { CaretDataFile* file = *fileIter; CaretAssert(file); if (file->getDataFileType() == DataFileTypeEnum::SURFACE) { SurfaceFile* surfaceFile = dynamic_cast(file); CaretAssert(surfaceFile); structures.insert(surfaceFile->getStructure()); } } std::vector structuresOut(structures.begin(), structures.end()); return structuresOut; } /** * Get data files and their map indices in all displayed overlays. * * @param fileAndMapsEvent * File and maps event to which files and maps are added. */ void BrowserTabContent::getFilesAndMapIndicesInOverlays(EventCaretMappableDataFilesAndMapsInDisplayedOverlays* fileAndMapsEvent) { Model* model = getModelForDisplay(); if (model == NULL) { return; } const int32_t tabIndex = getTabNumber(); switch (model->getModelType()) { case ModelTypeEnum::MODEL_TYPE_INVALID: case ModelTypeEnum::MODEL_TYPE_CHART: break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: { ModelChartTwo* chartTwoModel = getDisplayedChartTwoModel(); CaretAssert(chartTwoModel); ChartTwoOverlaySet* chartOverlaySet = chartTwoModel->getChartTwoOverlaySet(tabIndex); const int32_t numOverlays = chartOverlaySet->getNumberOfDisplayedOverlays(); for (int32_t i = 0; i < numOverlays; i++) { ChartTwoOverlay* overlay = chartOverlaySet->getOverlay(i); if (overlay->isEnabled()) { CaretMappableDataFile* overlayDataFile = NULL; ChartTwoOverlay::SelectedIndexType indexType; int32_t mapIndex(0); overlay->getSelectionData(overlayDataFile, indexType, mapIndex); if (overlayDataFile != NULL) { if (mapIndex >= 0) { fileAndMapsEvent->addChartFileAndMap(overlayDataFile, mapIndex); } } } } } break; case ModelTypeEnum::MODEL_TYPE_SURFACE: case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: { OverlaySet* overlaySet = model->getOverlaySet(tabIndex); const int32_t numOverlays = overlaySet->getNumberOfDisplayedOverlays(); for (int32_t i = 0; i < numOverlays; i++) { Overlay* overlay = overlaySet->getOverlay(i); if (overlay->isEnabled()) { CaretMappableDataFile* overlayDataFile = NULL; int32_t mapIndex; overlay->getSelectionData(overlayDataFile, mapIndex); if (overlayDataFile != NULL) { if (mapIndex >= 0) { fileAndMapsEvent->addBrainordinateFileAndMap(overlayDataFile, mapIndex); } } } } } break; } } /** * Get the data files displayed in this tab. * @param displayedDataFilesOut * Displayed data file are loaded into this parameter. */ void BrowserTabContent::getFilesDisplayedInTab(std::vector& displayedDataFilesOut) { displayedDataFilesOut.clear(); Model* model = getModelForDisplay(); if (model == NULL) { return; } std::set displayedDataFiles; const int32_t tabIndex = getTabNumber(); switch (getSelectedModelType()) { case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: { ModelSurface* ms = getDisplayedSurfaceModel(); displayedDataFiles.insert(ms->getSurface()); } break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: { ModelSurfaceMontage* msm = getDisplayedSurfaceMontageModel(); switch (msm->getSelectedConfigurationType(tabIndex)) { case SurfaceMontageConfigurationTypeEnum::CEREBELLAR_CORTEX_CONFIGURATION: { SurfaceMontageConfigurationCerebellar* smcc = msm->getCerebellarConfiguration(tabIndex); if (smcc->isFirstSurfaceEnabled()) { displayedDataFiles.insert(smcc->getFirstSurfaceSelectionModel()->getSurface()); } if (smcc->isSecondSurfaceEnabled()) { displayedDataFiles.insert(smcc->getSecondSurfaceSelectionModel()->getSurface()); } } break; case SurfaceMontageConfigurationTypeEnum::CEREBRAL_CORTEX_CONFIGURATION: { SurfaceMontageConfigurationCerebral* smcc = msm->getCerebralConfiguration(tabIndex); if (smcc->isFirstSurfaceEnabled()) { if (smcc->isLeftEnabled()) { displayedDataFiles.insert(smcc->getLeftFirstSurfaceSelectionModel()->getSurface()); } if (smcc->isRightEnabled()) { displayedDataFiles.insert(smcc->getRightFirstSurfaceSelectionModel()->getSurface()); } } if (smcc->isSecondSurfaceEnabled()) { if (smcc->isLeftEnabled()) { displayedDataFiles.insert(smcc->getLeftSecondSurfaceSelectionModel()->getSurface()); } if (smcc->isRightEnabled()) { displayedDataFiles.insert(smcc->getRightSecondSurfaceSelectionModel()->getSurface()); } } } break; case SurfaceMontageConfigurationTypeEnum::FLAT_CONFIGURATION: { SurfaceMontageConfigurationFlatMaps* smcfm = msm->getFlatMapsConfiguration(tabIndex); if (smcfm->isLeftEnabled()) { displayedDataFiles.insert(smcfm->getLeftSurfaceSelectionModel()->getSurface()); } if (smcfm->isRightEnabled()) { displayedDataFiles.insert(smcfm->getRightSurfaceSelectionModel()->getSurface()); } if (smcfm->isCerebellumEnabled()) { displayedDataFiles.insert(smcfm->getCerebellumSurfaceSelectionModel()->getSurface()); } } break; } } break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: { const int32_t numOutlines = m_volumeSurfaceOutlineSetModel->getNumberOfDislayedVolumeSurfaceOutlines(); for (int32_t i = 0; i < numOutlines; i++) { VolumeSurfaceOutlineModel* model = m_volumeSurfaceOutlineSetModel->getVolumeSurfaceOutlineModel(i); if (model->isDisplayed()) { displayedDataFiles.insert(model->getSurface()); } } } break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: { ModelWholeBrain* wbm = getDisplayedWholeBrainModel(); if (isWholeBrainLeftEnabled()) { displayedDataFiles.insert(wbm->getSelectedSurface(StructureEnum::CORTEX_LEFT, tabIndex)); } if (isWholeBrainRightEnabled()) { displayedDataFiles.insert(wbm->getSelectedSurface(StructureEnum::CORTEX_RIGHT, tabIndex)); } if (isWholeBrainCerebellumEnabled()) { displayedDataFiles.insert(wbm->getSelectedSurface(StructureEnum::CEREBELLUM, tabIndex)); } } break; case ModelTypeEnum::MODEL_TYPE_CHART: break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: { const ChartTwoOverlaySet* overlaySet = m_chartTwoModel->getChartTwoOverlaySet(tabIndex); if (overlaySet != NULL) { const int32_t numOverlays = overlaySet->getNumberOfDisplayedOverlays(); for (int32_t i = 0; i < numOverlays; i++) { const ChartTwoOverlay* chartOverlay = overlaySet->getOverlay(i); if (chartOverlay->isEnabled()) { CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; chartOverlay->getSelectionData(mapFile, selectedIndexType, selectedIndex); if (mapFile != NULL) { displayedDataFiles.insert(mapFile); } } } } } break; } /* * Check overlay files */ OverlaySet* overlaySet = model->getOverlaySet(tabIndex); const int32_t numOverlays = overlaySet->getNumberOfDisplayedOverlays(); for (int32_t i = 0; i < numOverlays; i++) { Overlay* overlay = overlaySet->getOverlay(i); if (overlay->isEnabled()) { CaretMappableDataFile* overlayDataFile = NULL; int32_t mapIndex; overlay->getSelectionData(overlayDataFile, mapIndex); if (overlayDataFile != NULL) { switch (overlayDataFile->getDataFileType()) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: { CiftiConnectivityMatrixDenseDynamicFile* dynFile = dynamic_cast(overlayDataFile); CaretAssert(dynFile); displayedDataFiles.insert(dynFile->getParentBrainordinateDataSeriesFile()); } break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: break; case DataFileTypeEnum::METRIC: break; case DataFileTypeEnum::METRIC_DYNAMIC: { MetricDynamicConnectivityFile* metricDynFile = dynamic_cast(overlayDataFile); CaretAssert(metricDynFile); displayedDataFiles.insert(metricDynFile); } break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: { VolumeDynamicConnectivityFile* volDynFile = dynamic_cast(overlayDataFile); CaretAssert(volDynFile); displayedDataFiles.insert(volDynFile->getParentVolumeFile()); } break; } displayedDataFiles.insert(overlayDataFile); if (overlayDataFile->isMappedWithPalette()) { /* * If mapped with palette, there may be thresholding with another file * so need to include that file */ if (overlayDataFile->getMapPaletteColorMapping(mapIndex)->getThresholdType() == PaletteThresholdTypeEnum::THRESHOLD_TYPE_FILE) { CaretMappableDataFileAndMapSelectionModel* mapFileSelector = overlayDataFile->getMapThresholdFileSelectionModel(mapIndex); CaretAssert(mapFileSelector); CaretMappableDataFile* thresholdFile = mapFileSelector->getSelectedFile(); if (thresholdFile != NULL) { displayedDataFiles.insert(thresholdFile); } } } } } } /* * Check border files */ Brain* brain = model->getBrain(); const DisplayPropertiesBorders* borderDisplayProperties = brain->getDisplayPropertiesBorders(); const DisplayGroupEnum::Enum borderDisplayGroup = borderDisplayProperties->getDisplayGroupForTab(tabIndex); if (borderDisplayProperties->isDisplayed(borderDisplayGroup, tabIndex)) { const int32_t numBorderFiles = brain->getNumberOfBorderFiles(); for (int32_t i = 0; i < numBorderFiles; i++) { BorderFile* borderFile = brain->getBorderFile(i); const GroupAndNameHierarchyModel* classAndNameSelection = borderFile->getGroupAndNameHierarchyModel(); if (classAndNameSelection->isSelected(borderDisplayGroup, tabIndex)) { displayedDataFilesOut.push_back(borderFile); } } } /* * Check foci files */ const DisplayPropertiesFoci* fociDisplayProperties = brain->getDisplayPropertiesFoci(); const DisplayGroupEnum::Enum fociDisplayGroup = fociDisplayProperties->getDisplayGroupForTab(tabIndex); if (fociDisplayProperties->isDisplayed(fociDisplayGroup, tabIndex)) { const int32_t numFociFiles = brain->getNumberOfFociFiles(); for (int32_t i = 0; i < numFociFiles; i++) { FociFile* fociFile = brain->getFociFile(i); const GroupAndNameHierarchyModel* classAndNameSelection = fociFile->getGroupAndNameHierarchyModel(); if (classAndNameSelection->isSelected(fociDisplayGroup, tabIndex)) { displayedDataFilesOut.push_back(fociFile); } } } /* * Might be NULLs so filter them out and return the results */ for (std::set::iterator iter = displayedDataFiles.begin(); iter != displayedDataFiles.end(); iter++) { CaretDataFile* cdf = *iter; if (cdf != NULL) { displayedDataFilesOut.push_back(cdf); } } } ViewingTransformations* BrowserTabContent::getViewingTransformation() { if (isVolumeSlicesDisplayed()) { return m_volumeSliceViewingTransformation; } else if (isFlatSurfaceDisplayed()) { return m_flatSurfaceViewingTransformation; } else if (isCerebellumDisplayed()) { return m_cerebellumViewingTransformation; } else if (isChartTwoDisplayed()) { return m_chartTwoMatrixViewingTranformation; } return m_viewingTransformation; } const ViewingTransformations* BrowserTabContent::getViewingTransformation() const { if (isVolumeSlicesDisplayed()) { return m_volumeSliceViewingTransformation; } else if (isFlatSurfaceDisplayed()) { return m_flatSurfaceViewingTransformation; } else if (isCerebellumDisplayed()) { return m_cerebellumViewingTransformation; } else if (isChartTwoDisplayed()) { return m_chartTwoMatrixViewingTranformation; } return m_viewingTransformation; } /** * @return The viewing translation. */ const float* BrowserTabContent::getTranslation() const { return getViewingTransformation()->getTranslation(); } /** * Get the viewing translation. * * @param translationOut * Translation values output. */ void BrowserTabContent::getTranslation(float translationOut[3]) const { return getViewingTransformation()->getTranslation(translationOut); } /** * Set the viewing translation. * * @param translation * New translation values. */ void BrowserTabContent::setTranslation( const float translation[3]) { getViewingTransformation()->setTranslation(translation); updateBrainModelYokedBrowserTabs(); } /** * Set the viewing translation. * * @param translationX * New translation X-value. * @param translationY * New translation Y-value. * @param translationZ * New translation Z-value. */ void BrowserTabContent::setTranslation(const float translationX, const float translationY, const float translationZ) { getViewingTransformation()->setTranslation(translationX, translationY, translationZ); updateYokedModelBrowserTabs(); } /** * @return The viewing scaling. */ float BrowserTabContent::getScaling() const { return getViewingTransformation()->getScaling(); } /** * Set the viewing scaling. * @param scaling * New value for scaling. */ void BrowserTabContent::setScaling(const float scaling) { return getViewingTransformation()->setScaling(scaling); updateYokedModelBrowserTabs(); } /** * @return The rotation matrix. */ Matrix4x4 BrowserTabContent::getRotationMatrix() const { return getViewingTransformation()->getRotationMatrix(); } /** * Set the rotation matrix. * * @param rotationMatrix * The new rotation matrix. */ void BrowserTabContent::setRotationMatrix(const Matrix4x4& rotationMatrix) { getViewingTransformation()->setRotationMatrix(rotationMatrix); updateYokedModelBrowserTabs(); } /** * @return The oblique volume rotation matrix. */ Matrix4x4 BrowserTabContent::getObliqueVolumeRotationMatrix() const { return *m_obliqueVolumeRotationMatrix; } /** * Set the oblique rotation matrix. * * @param obliqueRotationMatrix * The new oblique rotation matrix. */ void BrowserTabContent::setObliqueVolumeRotationMatrix(const Matrix4x4& obliqueRotationMatrix) { *m_obliqueVolumeRotationMatrix = obliqueRotationMatrix; updateBrainModelYokedBrowserTabs(); } /** * Get the offset for the right flat map offset. * * @param offsetX * Output with X-offset. * @param offsetY * Output with Y-offset. */ void BrowserTabContent::getRightCortexFlatMapOffset(float& offsetX, float& offsetY) const { getViewingTransformation()->getRightCortexFlatMapOffset(offsetX, offsetY); } /** * Set the offset for the right flat map offset. * * @param offsetX * X-offset. * @param offsetY * Y-offset. */ void BrowserTabContent::setRightCortexFlatMapOffset(const float offsetX, const float offsetY) { getViewingTransformation()->setRightCortexFlatMapOffset(offsetX, offsetY); updateBrainModelYokedBrowserTabs(); } /** * @return The right cortex flat map zoom factor. */ float BrowserTabContent::getRightCortexFlatMapZoomFactor() const { return getViewingTransformation()->getRightCortexFlatMapZoomFactor(); } /** * Set the right cortex flat map zoom factor. * * @param zoomFactor * The zoom factor. */ void BrowserTabContent::setRightCortexFlatMapZoomFactor(const float zoomFactor) { getViewingTransformation()->setRightCortexFlatMapZoomFactor(zoomFactor); } /** * Reset the view to the default view. */ void BrowserTabContent::resetView() { getViewingTransformation()->resetView(); if (isVolumeSlicesDisplayed()) { m_obliqueVolumeRotationMatrix->identity(); } updateYokedModelBrowserTabs(); } /** * Set to a right side view. */ void BrowserTabContent::rightView() { if (isVolumeSlicesDisplayed()) { return; } getViewingTransformation()->rightView(); updateYokedModelBrowserTabs(); } /** * set to a left side view. */ void BrowserTabContent::leftView() { if (isVolumeSlicesDisplayed()) { return; } getViewingTransformation()->leftView(); updateYokedModelBrowserTabs(); } /** * set to a anterior view. */ void BrowserTabContent::anteriorView() { if (isVolumeSlicesDisplayed()) { return; } getViewingTransformation()->anteriorView(); updateYokedModelBrowserTabs(); } /** * set to a posterior view. */ void BrowserTabContent::posteriorView() { if (isVolumeSlicesDisplayed()) { return; } getViewingTransformation()->posteriorView(); updateYokedModelBrowserTabs(); } /** * set to a dorsal view. */ void BrowserTabContent::dorsalView() { if (isVolumeSlicesDisplayed()) { return; } getViewingTransformation()->dorsalView(); updateYokedModelBrowserTabs(); } /** * set to a ventral view. */ void BrowserTabContent::ventralView() { if (isVolumeSlicesDisplayed()) { return; } getViewingTransformation()->ventralView(); updateYokedModelBrowserTabs(); } /** * Apply volume slice increment while dragging mouse * * @param viewportContent * Content of viewport * @param mousePressX * X coordinate of where mouse was pressed. * @param mousePressY * Y coordinate of where mouse was pressed. * @param mouseDY * Change in mouse Y coordinate. */ void BrowserTabContent::applyMouseVolumeSliceIncrement(BrainOpenGLViewportContent* viewportContent, const int32_t mousePressX, const int32_t mousePressY, const int32_t mouseDY) { bool incrementFlag(false); if (isVolumeSlicesDisplayed()) { switch (getSliceProjectionType()) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: incrementFlag = true; break; } } if ( ! incrementFlag) { return; } if (mouseDY == 0) { return; } /* * Prevents "too fast" scrolling. * If set to a very large number, it will result in the * slice increment becoming one */ int32_t slowDownIncrementer = 3; int32_t sliceDelta = mouseDY; if (sliceDelta > 1) { sliceDelta /= slowDownIncrementer; if (sliceDelta == 0) { sliceDelta = 1; } } else if (sliceDelta < -1) { sliceDelta /= slowDownIncrementer; if (sliceDelta == 0) { sliceDelta = -1; } } const int32_t tabIndex = viewportContent->getTabIndex(); VolumeMappableInterface* underlayVolume(NULL); ModelVolume* volumeModel = getDisplayedVolumeModel(); if (volumeModel != NULL) { underlayVolume = volumeModel->getUnderlayVolumeFile(tabIndex); } VolumeSliceViewPlaneEnum::Enum sliceViewPlane = getSliceViewPlane(); if (sliceViewPlane == VolumeSliceViewPlaneEnum::ALL) { int viewport[4]; viewportContent->getModelViewport(viewport); int sliceViewport[4] = { viewport[0], viewport[1], viewport[2], viewport[3] }; sliceViewPlane = BrainOpenGLViewportContent::getSliceViewPlaneForVolumeAllSliceView(viewport, getSlicePlanesAllViewLayout(), mousePressX, mousePressY, sliceViewport); } /* * Note: Functions that set slice indices will prevent * invalid slice indices */ switch (sliceViewPlane) { case VolumeSliceViewPlaneEnum::ALL: break; case VolumeSliceViewPlaneEnum::AXIAL: setSliceIndexAxial(underlayVolume, (getSliceIndexAxial(underlayVolume) + sliceDelta)); break; case VolumeSliceViewPlaneEnum::CORONAL: setSliceIndexCoronal(underlayVolume, (getSliceIndexCoronal(underlayVolume) + sliceDelta)); break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: setSliceIndexParasagittal(underlayVolume, (getSliceIndexParasagittal(underlayVolume) + sliceDelta)); break; } updateYokedModelBrowserTabs(); } /** * Apply mouse rotation to the displayed model. * * @param viewportContent * Content of viewport * @param mousePressX * X coordinate of where mouse was pressed. * @param mousePressY * Y coordinate of where mouse was pressed. * @param mouseX * X coordinate of mouse. * @param mouseY * Y coordinate of mouse. * @param mouseDeltaX * Change in mouse X coordinate. * @param mouseDeltaY * Change in mouse Y coordinate. */ void BrowserTabContent::applyMouseRotation(BrainOpenGLViewportContent* viewportContent, const int32_t mousePressX, const int32_t mousePressY, const int32_t mouseX, const int32_t mouseY, const int32_t mouseDeltaX, const int32_t mouseDeltaY) { if (isVolumeSlicesDisplayed()) { switch (getSliceProjectionType()) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: if (viewportContent == NULL) { /* * When no viewport content is available, apply 'ALL' rotation */ Matrix4x4 rotationMatrix = getObliqueVolumeRotationMatrix(); rotationMatrix.rotateX(-mouseDeltaY); rotationMatrix.rotateY(mouseDeltaX); setObliqueVolumeRotationMatrix(rotationMatrix); } else { int viewport[4]; viewportContent->getModelViewport(viewport); VolumeSliceViewPlaneEnum::Enum slicePlane = this->getSliceViewPlane(); int sliceViewport[4] = { viewport[0], viewport[1], viewport[2], viewport[3] }; if (slicePlane == VolumeSliceViewPlaneEnum::ALL) { slicePlane = BrainOpenGLViewportContent::getSliceViewPlaneForVolumeAllSliceView(viewport, getSlicePlanesAllViewLayout(), mousePressX, mousePressY, sliceViewport); } Matrix4x4 rotationMatrix = getObliqueVolumeRotationMatrix(); if (slicePlane == VolumeSliceViewPlaneEnum::ALL) { rotationMatrix.rotateX(-mouseDeltaY); rotationMatrix.rotateY(mouseDeltaX); } else { if ((mouseDeltaX != 0) || (mouseDeltaY != 0)) { const int previousMouseX = mouseX - mouseDeltaX; const int previousMouseY = mouseY - mouseDeltaY; /* * Need to account for the quadrants!!!! */ const float viewportCenter[3] = { (float)(sliceViewport[0] + sliceViewport[2] / 2), ((float)sliceViewport[1] + sliceViewport[3] / 2), 0.0 }; const float oldPos[3] = { (float)previousMouseX, (float)previousMouseY, 0.0 }; const float newPos[3] = { (float)mouseX, (float)mouseY, 0.0 }; /* * Compute normal vector from viewport center to * old mouse position to new mouse position. * If normal-Z is positive, mouse has been moved * in a counter clockwise motion relative to center. * If normal-Z is negative, mouse has moved clockwise. */ float normalDirection[3]; MathFunctions::normalVectorDirection(viewportCenter, oldPos, newPos, normalDirection); bool isClockwise = false; bool isCounterClockwise = false; if (normalDirection[2] > 0.0) { isCounterClockwise = true; } else if (normalDirection[2] < 0.0) { isClockwise = true; } if (isClockwise || isCounterClockwise) { float mouseDelta = std::sqrt(static_cast((mouseDeltaX * mouseDeltaX) + (mouseDeltaY * mouseDeltaY))); // /* // * Rotation needs to be oppposite for newer // * oblique slice drawing for volumes that // * do not have a voxel corresponding to // * the origin. // */ // mouseDelta = -mouseDelta; switch (slicePlane) { case VolumeSliceViewPlaneEnum::ALL: { CaretAssert(0); } break; case VolumeSliceViewPlaneEnum::AXIAL: { Matrix4x4 rotation; if (isClockwise) { rotation.rotateZ(mouseDelta); } else if (isCounterClockwise) { rotation.rotateZ(-mouseDelta); } rotationMatrix.premultiply(rotation); } break; case VolumeSliceViewPlaneEnum::CORONAL: { Matrix4x4 rotation; if (isClockwise) { rotation.rotateY(-mouseDelta); } else if (isCounterClockwise) { rotation.rotateY(mouseDelta); } rotationMatrix.premultiply(rotation); } break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: { Matrix4x4 rotation; if (isClockwise) { rotation.rotateX(-mouseDelta); } else if (isCounterClockwise) { rotation.rotateX(mouseDelta); } rotationMatrix.premultiply(rotation); } break; } } } } setObliqueVolumeRotationMatrix(rotationMatrix); } break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: break; } } else if (isChartOneDisplayed() || isChartTwoDisplayed()) { /* no rotation for chart */ } else if (isCerebellumDisplayed()) { const float screenDX = mouseDeltaX; const float screenDY = mouseDeltaY; float rotateDX = 0.0; float rotateDY = 0.0; float rotateDZ = 0.0; ModelSurfaceMontage* montageModel = getDisplayedSurfaceMontageModel(); if (montageModel != NULL) { std::vector montageViewports; montageModel->getSurfaceMontageViewportsForTransformation(getTabNumber(), montageViewports); bool foundMontageViewportFlag = false; const int32_t numViewports = static_cast(montageViewports.size()); for (int32_t ivp = 0; ivp < numViewports; ivp++) { const SurfaceMontageViewport* smv = montageViewports[ivp]; if (smv->isInside(mousePressX, mousePressY)) { switch (smv->getProjectionViewType()) { case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_ANTERIOR: rotateDX = screenDY; rotateDZ = screenDX; foundMontageViewportFlag = true; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_DORSAL: rotateDX = -screenDY; rotateDY = screenDX; foundMontageViewportFlag = true; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_POSTERIOR: rotateDX = -screenDY; rotateDZ = screenDX; foundMontageViewportFlag = true; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_VENTRAL: rotateDX = -screenDY; rotateDY = -screenDX; foundMontageViewportFlag = true; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_FLAT_SURFACE: foundMontageViewportFlag = true; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_LATERAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_MEDIAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_FLAT_SURFACE: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_LATERAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_MEDIAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_FLAT_SURFACE: break; } } if (foundMontageViewportFlag) { break; } } } else { rotateDX = -screenDY; rotateDY = screenDX; } Matrix4x4 rotationMatrix = m_cerebellumViewingTransformation->getRotationMatrix(); rotationMatrix.rotateX(rotateDX); rotationMatrix.rotateY(rotateDY); rotationMatrix.rotateZ(rotateDZ); m_cerebellumViewingTransformation->setRotationMatrix(rotationMatrix); } else { ViewingTransformations* viewingTransform = getViewingTransformation(); if (getProjectionViewType() == ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_LATERAL) { Matrix4x4 rotationMatrix = viewingTransform->getRotationMatrix(); rotationMatrix.rotateX(-mouseDeltaY); rotationMatrix.rotateY(-mouseDeltaX); viewingTransform->setRotationMatrix(rotationMatrix); } else { float dx = mouseDeltaX; float dy = mouseDeltaY; ModelSurfaceMontage* montageModel = getDisplayedSurfaceMontageModel(); if (montageModel != NULL) { std::vector montageViewports; montageModel->getSurfaceMontageViewportsForTransformation(getTabNumber(), montageViewports); bool isValid = false; bool isFlat = false; bool isLeft = false; bool isLateral = true; const int32_t numViewports = static_cast(montageViewports.size()); for (int32_t ivp = 0; ivp < numViewports; ivp++) { const SurfaceMontageViewport* smv = montageViewports[ivp]; if (smv->isInside(mousePressX, mousePressY)) { switch (smv->getProjectionViewType()) { case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_ANTERIOR: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_DORSAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_POSTERIOR: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_VENTRAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_FLAT_SURFACE: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_LATERAL: isLeft = true; isLateral = true; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_MEDIAL: isLeft = true; isLateral = false; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_FLAT_SURFACE: isLeft = true; isFlat = true; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_LATERAL: isLeft = false; isLateral = true; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_MEDIAL: isLeft = false; isLateral = false; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_FLAT_SURFACE: isLeft = false; isFlat = true; break; } isValid = true; } if (isValid) { break; } } if (isFlat) { /* * No rotation. */ dx = 0.0; dy = 0.0; } else if (isValid) { if (isLeft == false) { dx = -dx; } if (isLateral == false) { dy = -dy; } } } Matrix4x4 rotationMatrix = viewingTransform->getRotationMatrix(); rotationMatrix.rotateX(-dy); rotationMatrix.rotateY(dx); viewingTransform->setRotationMatrix(rotationMatrix); } } updateYokedModelBrowserTabs(); } /** * Apply mouse scaling to the displayed model. * * @param mouseDX * Change in mouse X coordinate. * @param mouseDY * Change in mouse Y coordinate. */ void BrowserTabContent::applyMouseScaling(const int32_t /*mouseDX*/, const int32_t mouseDY) { if (isChartOneDisplayed()) { ModelChart* modelChart = getDisplayedChartOneModel(); CaretAssert(modelChart); CaretDataFileSelectionModel* matrixSelectionModel = NULL; if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { matrixSelectionModel = modelChart->getChartableMatrixParcelFileSelectionModel(m_tabNumber); } if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { matrixSelectionModel = modelChart->getChartableMatrixSeriesFileSelectionModel(m_tabNumber); } if (matrixSelectionModel != NULL) { ChartableMatrixInterface* chartableInterface = matrixSelectionModel->getSelectedFileOfType(); if (chartableInterface != NULL) { ChartMatrixDisplayProperties* matrixProperties = chartableInterface->getChartMatrixDisplayProperties(m_tabNumber); matrixProperties->setScaleMode(ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_MANUAL); float scaling = matrixProperties->getViewZooming(); if (mouseDY != 0.0) { scaling *= (1.0f + (mouseDY * 0.01)); } if (scaling < 0.01) { scaling = 0.01; } matrixProperties->setViewZooming(scaling); } } } else if (isChartTwoDisplayed()) { float scaling = getViewingTransformation()->getScaling(); if (mouseDY != 0.0) { scaling *= (1.0f + (mouseDY * 0.01)); } if (scaling < 0.01) { scaling = 0.01; } getViewingTransformation()->setScaling(scaling); } else { float scaling = getViewingTransformation()->getScaling(); if (mouseDY != 0.0) { scaling *= (1.0f + (mouseDY * 0.01)); } if (scaling < 0.01) { scaling = 0.01; } getViewingTransformation()->setScaling(scaling); } updateYokedModelBrowserTabs(); } /** * Apply mouse translation to the displayed model. * * @param viewportContent * Content of the viewport. * @param mousePressX * X coordinate of where mouse was pressed. * @param mousePressY * X coordinate of where mouse was pressed. * @param mouseDX * Change in mouse X coordinate. * @param mouseDY * Change in mouse Y coordinate. */ void BrowserTabContent::applyMouseTranslation(BrainOpenGLViewportContent* viewportContent, const int32_t mousePressX, const int32_t mousePressY, const int32_t mouseDX, const int32_t mouseDY) { const int tabIndex = getTabNumber(); if (isVolumeSlicesDisplayed()) { const float volumeSliceScaling = m_volumeSliceViewingTransformation->getScaling(); ModelVolume* modelVolume = getDisplayedVolumeModel(); VolumeMappableInterface* vf = modelVolume->getUnderlayVolumeFile(tabIndex); BoundingBox mybox; vf->getVoxelSpaceBoundingBox(mybox); float cubesize = std::max(std::max(mybox.getDifferenceX(), mybox.getDifferenceY()), mybox.getDifferenceZ());//factor volume bounding box into slowdown for zoomed in float slowdown = 0.005f * cubesize / volumeSliceScaling;//when zoomed in, make the movements slower to match - still changes based on viewport currently slowdown = 1.0; float dx = 0.0; float dy = 0.0; float dz = 0.0; int viewport[4]; viewportContent->getModelViewport(viewport); int sliceViewport[4]; viewportContent->getModelViewport(sliceViewport); VolumeSliceViewPlaneEnum::Enum slicePlane = getSliceViewPlane(); if (slicePlane == VolumeSliceViewPlaneEnum::ALL) { slicePlane = BrainOpenGLViewportContent::getSliceViewPlaneForVolumeAllSliceView(viewport, getSlicePlanesAllViewLayout(), mousePressX, mousePressY, sliceViewport); } switch (slicePlane) { case VolumeSliceViewPlaneEnum::ALL: break; case VolumeSliceViewPlaneEnum::AXIAL: dx = mouseDX * slowdown; dy = mouseDY * slowdown; break; case VolumeSliceViewPlaneEnum::CORONAL: dx = mouseDX * slowdown; dz = mouseDY * slowdown; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: dy = -mouseDX * slowdown; dz = mouseDY * slowdown; break; } float translation[3]; m_volumeSliceViewingTransformation->getTranslation(translation); translation[0] += dx; translation[1] += dy; translation[2] += dz; m_volumeSliceViewingTransformation->setTranslation(translation); } else if (isChartOneDisplayed()) { ModelChart* modelChart = getDisplayedChartOneModel(); CaretAssert(modelChart); CaretDataFileSelectionModel* matrixSelectionModel = NULL; if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { matrixSelectionModel = modelChart->getChartableMatrixParcelFileSelectionModel(m_tabNumber); } if (modelChart->getSelectedChartOneDataType(m_tabNumber) == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { matrixSelectionModel = modelChart->getChartableMatrixSeriesFileSelectionModel(m_tabNumber); } if (matrixSelectionModel != NULL) { ChartableMatrixInterface* chartableInterface = matrixSelectionModel->getSelectedFileOfType(); if (chartableInterface != NULL) { ChartMatrixDisplayProperties* matrixProperties = chartableInterface->getChartMatrixDisplayProperties(m_tabNumber); matrixProperties->setScaleMode(ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_MANUAL); float translation[2]; matrixProperties->getViewPanning(translation); translation[0] += mouseDX; translation[1] += mouseDY; matrixProperties->setViewPanning(translation); } } } else if (isChartTwoDisplayed()) { float translation[3]; m_chartTwoMatrixViewingTranformation->getTranslation(translation); translation[0] += mouseDX; translation[1] += mouseDY; translation[2] = 0; // NO Z-translation m_chartTwoMatrixViewingTranformation->setTranslation(translation); } else if (isCerebellumDisplayed()) { const float screenDX = mouseDX; const float screenDY = mouseDY; float translateDX = 0.0; float translateDY = 0.0; float translateDZ = 0.0; ModelSurfaceMontage* montageModel = getDisplayedSurfaceMontageModel(); if (montageModel != NULL) { std::vector montageViewports; montageModel->getSurfaceMontageViewportsForTransformation(getTabNumber(), montageViewports); bool foundMontageViewportFlag = false; const int32_t numViewports = static_cast(montageViewports.size()); for (int32_t ivp = 0; ivp < numViewports; ivp++) { const SurfaceMontageViewport* smv = montageViewports[ivp]; if (smv->isInside(mousePressX, mousePressY)) { switch (smv->getProjectionViewType()) { case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_ANTERIOR: translateDX = screenDX; translateDY = screenDY; foundMontageViewportFlag = true; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_DORSAL: translateDX = screenDX; translateDY = screenDY; foundMontageViewportFlag = true; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_POSTERIOR: translateDX = screenDX; translateDY = screenDY; foundMontageViewportFlag = true; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_VENTRAL: translateDX = screenDX; translateDY = screenDY; foundMontageViewportFlag = true; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_FLAT_SURFACE: translateDX = screenDX; translateDY = screenDY; foundMontageViewportFlag = true; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_LATERAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_MEDIAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_FLAT_SURFACE: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_LATERAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_MEDIAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_FLAT_SURFACE: break; } } if (foundMontageViewportFlag) { break; } } } else { translateDX = screenDX; translateDY = screenDY; } float translation[3]; m_cerebellumViewingTransformation->getTranslation(translation); translation[0] += translateDX; translation[1] += translateDY; translation[2] += translateDZ; m_cerebellumViewingTransformation->setTranslation(translation); } else { float dx = mouseDX; float dy = mouseDY; ModelSurfaceMontage* montageModel = getDisplayedSurfaceMontageModel(); if (montageModel != NULL) { std::vector montageViewports; montageModel->getSurfaceMontageViewportsForTransformation(getTabNumber(), montageViewports); bool isValid = false; bool isLeft = true; bool isLateral = false; const int32_t numViewports = static_cast(montageViewports.size()); for (int32_t ivp = 0; ivp < numViewports; ivp++) { const SurfaceMontageViewport* smv = montageViewports[ivp]; if (smv->isInside(mousePressX, mousePressY)) { switch (smv->getProjectionViewType()) { case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_ANTERIOR: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_DORSAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_POSTERIOR: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_VENTRAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_FLAT_SURFACE: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_LATERAL: isLeft = true; isLateral = true; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_MEDIAL: isLeft = true; isLateral = false; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_FLAT_SURFACE: isLeft = true; isLateral = true; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_LATERAL: isLeft = false; isLateral = true; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_MEDIAL: isLeft = false; isLateral = false; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_FLAT_SURFACE: isLeft = false; isLateral = true; break; } isValid = true; } if (isValid) { break; } } if (isValid) { if (isLeft == false) { dx = -dx; } if (isLateral == false) { dx = -dx; } float translation[3]; getViewingTransformation()->getTranslation(translation); translation[0] += dx; translation[1] += dy; getViewingTransformation()->setTranslation(translation); } } else { if (getProjectionViewType() == ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_LATERAL) { dx = -dx; } else if (getProjectionViewType() == ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_FLAT_SURFACE) { dx = -dx; } float translation[3]; getViewingTransformation()->getTranslation(translation); translation[0] += dx; translation[1] += dy; getViewingTransformation()->setTranslation(translation); } } updateYokedModelBrowserTabs(); } /** * Get the transformations for drawing a model. * * @param projectionViewType * Type of projection view * @param translationOut * Translation * @param rotationMatrixOut * OpenGL rotation matrix. * @param scalingOut * Scaling. */ void BrowserTabContent::getTransformationsForOpenGLDrawing(const ProjectionViewTypeEnum::Enum projectionViewType, float translationOut[3], double rotationMatrixOut[16], float& scalingOut) const { /* * Check for volume slice viewing */ if (isVolumeSlicesDisplayed()) { m_volumeSliceViewingTransformation->getTranslation(translationOut); Matrix4x4 rotationMatrix = m_volumeSliceViewingTransformation->getRotationMatrix(); rotationMatrix.getMatrixForOpenGL(rotationMatrixOut); scalingOut = m_volumeSliceViewingTransformation->getScaling(); return; } if (isChartTwoDisplayed()) { m_chartTwoMatrixViewingTranformation->getTranslation(translationOut); Matrix4x4 matrix; matrix.identity(); matrix.getMatrixForOpenGL(rotationMatrixOut); scalingOut = m_chartTwoMatrixViewingTranformation->getScaling(); return; } /* * Surfaces may need a modification to the rotation matrix * dependent upon the projection view type. */ Matrix4x4 rotationMatrix = getViewingTransformation()->getRotationMatrix(); getViewingTransformation()->getTranslation(translationOut); scalingOut = getViewingTransformation()->getScaling(); double rotationX, rotationY, rotationZ; rotationMatrix.getRotation(rotationX, rotationY, rotationZ); const double rotationFlippedX = -rotationX; const double rotationFlippedY = 180.0 - rotationY; switch (projectionViewType) { case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_ANTERIOR: { Matrix4x4 matrixOut = rotationMatrix; Matrix4x4 anteriorMatrix; anteriorMatrix.setRotation(90.0, 0.0, -180.0); matrixOut.postmultiply(anteriorMatrix); matrixOut.getMatrixForOpenGL(rotationMatrixOut); return; } break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_DORSAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_POSTERIOR: { Matrix4x4 matrixOut = rotationMatrix; Matrix4x4 posteriorMatrix; posteriorMatrix.setRotation(-90.0, 0.0, 0.0); matrixOut.postmultiply(posteriorMatrix); matrixOut.getMatrixForOpenGL(rotationMatrixOut); return; } break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_VENTRAL: { Matrix4x4 matrixOut = rotationMatrix; Matrix4x4 ventralMatrix; ventralMatrix.setRotation(0.0, 180.0, 180.0); matrixOut.postmultiply(ventralMatrix); matrixOut.getMatrixForOpenGL(rotationMatrixOut); return; } break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_FLAT_SURFACE: rotationX = 0.0; rotationY = 0.0; rotationZ = 0.0; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_LATERAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_MEDIAL: break; case ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_FLAT_SURFACE: rotationX = 0.0; rotationY = 0.0; rotationZ = 0.0; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_LATERAL: rotationX = rotationFlippedX; rotationY = rotationFlippedY; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_MEDIAL: rotationX = rotationFlippedX; rotationY = rotationFlippedY; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_FLAT_SURFACE: rotationX = 0.0; rotationY = 180.0; rotationZ = 0.0; break; } Matrix4x4 matrix; matrix.setRotation(rotationX, rotationY, rotationZ); matrix.getMatrixForOpenGL(rotationMatrixOut); } /** * Place the transformations for the given window tab into * the model transform. * @param windowTabNumber * Tab number for transformations. * @param modelTransform * Model transform into which transformations are loaded. */ void BrowserTabContent::getTransformationsInModelTransform(ModelTransform& modelTransform) const { modelTransform.setTranslation(getTranslation()); const Matrix4x4 rotMatrix = getRotationMatrix(); float m[4][4]; rotMatrix.getMatrix(m); modelTransform.setRotation(m); const Matrix4x4 obliqueRotationMatrix = getObliqueVolumeRotationMatrix(); float mob[4][4]; obliqueRotationMatrix.getMatrix(mob); modelTransform.setObliqueRotation(mob); float rightFlatX, rightFlatY; getRightCortexFlatMapOffset(rightFlatX, rightFlatY); modelTransform.setRightCortexFlatMapOffset(rightFlatX, rightFlatY); modelTransform.setRightCortexFlatMapZoomFactor(getRightCortexFlatMapZoomFactor()); modelTransform.setScaling(getScaling()); } /** * Apply the transformations to the browser tab. * @param modelTransform * Model transform into which transformations are retrieved. */ void BrowserTabContent::setTransformationsFromModelTransform(const ModelTransform& modelTransform) { float translation[3]; modelTransform.getTranslation(translation); const float tx = translation[0]; const float ty = translation[1]; const float tz = translation[2]; setTranslation(tx, ty, tz); float m[4][4]; modelTransform.getRotation(m); Matrix4x4 rotationMatrix; rotationMatrix.setMatrix(m); setRotationMatrix(rotationMatrix); float mob[4][4]; modelTransform.getObliqueRotation(mob); Matrix4x4 obliqueRotationMatrix; obliqueRotationMatrix.setMatrix(mob); setObliqueVolumeRotationMatrix(obliqueRotationMatrix); const float scale = modelTransform.getScaling(); setScaling(scale); float rightFlatX, rightFlatY; modelTransform.getRightCortexFlatMapOffset(rightFlatX, rightFlatY); setRightCortexFlatMapOffset(rightFlatX, rightFlatY); const float rightFlatZoom = modelTransform.getRightCortexFlatMapZoomFactor(); setRightCortexFlatMapZoomFactor(rightFlatZoom); updateYokedModelBrowserTabs(); } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of the class' instance. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* BrowserTabContent::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "BrowserTabContent", 6); // WB-491 Flat Fixes //5); // WB-576 //4); // WB-491, 1/28/2015 //3); // version 3 as of 4/22/2014 float obliqueMatrix[16]; m_obliqueVolumeRotationMatrix->getMatrixForOpenGL(obliqueMatrix); sceneClass->addFloatArray("m_obliqueVolumeRotationMatrix", obliqueMatrix, 16); m_sceneClassAssistant->saveMembers(sceneAttributes, sceneClass); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. May be NULL for some types of scenes. */ void BrowserTabContent::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_brainModelYokingGroup = YokingGroupEnum::YOKING_GROUP_A; m_chartModelYokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; m_sceneClassAssistant->restoreMembers(sceneAttributes, sceneClass); /* * With charting version two, yoking was split into chart and non-chart yoking * If old yoking group is found, apply it to the brain model yoking group */ const AString oldYokingGroupName = sceneClass->getEnumeratedTypeValueAsString("m_yokingGroup", "XXXXXX"); if ( ! oldYokingGroupName.isEmpty()) { bool validFlag = false; const YokingGroupEnum::Enum oldYokeGroup = YokingGroupEnum::fromName(oldYokingGroupName, &validFlag); if (validFlag) { m_brainModelYokingGroup = oldYokeGroup; m_chartModelYokingGroup = oldYokeGroup; } } m_obliqueVolumeRotationMatrix->identity(); float obliqueMatrix[16]; const int32_t numInObliqueArray = sceneClass->getFloatArrayValue("m_obliqueVolumeRotationMatrix", obliqueMatrix, 16); if (numInObliqueArray == 16) { m_obliqueVolumeRotationMatrix->setMatrixFromOpenGL(obliqueMatrix); } /* * In older version of workbench, transformation were stored in the * model for each tab, so try to restore them. */ if (sceneClass->getVersionNumber() < 2) { float translation[3]; float scaling; float rotationMatrix[4][4]; const Model* model = getModelForDisplay(); if (model != NULL) { const bool valid = model->getOldSceneTransformation(m_tabNumber, translation, scaling, rotationMatrix); if (valid) { setTranslation(translation); setScaling(scaling); Matrix4x4 m; m.setMatrix(rotationMatrix); ModelSurface* ms = getDisplayedSurfaceModel(); if (ms != NULL) { /* * Right hemispheres need rotations changed for * proper viewing. */ const StructureEnum::Enum structure = ms->getSurface()->getStructure(); if (StructureEnum::isRight(structure)) { double rotationX, rotationY, rotationZ; m.getRotation(rotationX, rotationY, rotationZ); //rotationX = -rotationX; //rotationY = 180.0 - rotationY; rotationY = 90 + rotationY; rotationZ = -rotationZ; m.identity(); m.setRotation(rotationX, rotationY, rotationZ); } } setRotationMatrix(m); } } } if (getDisplayedWholeBrainModel() != NULL) { /* * As of 19sep2013 whole brain and volume slice settings were merged * (whole brain slice settings removed). For compatibility, if a * whole brain model is being viewed and whole brain slice settings * are found, allow them to override volume slice settings. */ const SceneClass* wholeBrainVolumeSettings = sceneClass->getClass("m_wholeBrainSliceSettings"); if (wholeBrainVolumeSettings != NULL) { VolumeSliceSettings settings; settings.restoreFromScene(sceneAttributes, wholeBrainVolumeSettings); *m_volumeSliceSettings = settings; } } /** * Check for now obsolete clipping coordinate array. If found it is an * old scene so update the clipping planes. */ const SceneClassArray* oldClippingCoordinateClassArray = sceneClass->getClassArray("m_clippingCoordinate"); if (oldClippingCoordinateClassArray != NULL) { float clipCoords[3]; if (sceneClass->getFloatArrayValue("m_clippingCoordinate", clipCoords, 3) != 3) { clipCoords[0] = 0.0; clipCoords[1] = 0.0; clipCoords[2] = 0.0; } float clipThick[3]; if (sceneClass->getFloatArrayValue("m_clippingThickness", clipThick, 3) != 3) { clipThick[0] = 0.0; clipThick[1] = 0.0; clipThick[2] = 0.0; } bool clipEnabled[3]; if (sceneClass->getBooleanArrayValue("m_clippingEnabled", clipEnabled, 3) != 3) { clipEnabled[0] = false; clipEnabled[1] = false; clipEnabled[2] = false; } m_clippingPlaneGroup->resetToDefaultValues(); m_clippingPlaneGroup->setXAxisSelected(clipEnabled[0]); m_clippingPlaneGroup->setYAxisSelected(clipEnabled[1]); m_clippingPlaneGroup->setZAxisSelected(clipEnabled[2]); m_clippingPlaneGroup->setTranslation(clipCoords); m_clippingPlaneGroup->setThickness(clipThick); } /* * In older version of workbench, there was no flat surface * viewing transformation as it used the same transformations * as other surfaces. */ if (sceneClass->getVersionNumber() < 3) { *m_flatSurfaceViewingTransformation = *m_viewingTransformation; } /* * Prior to WB-491 surface drawing used the maximum dimension for * scaling to fit the window height and this was almost * always the Y-axis. This worked well when the default view was * a dorsal view with the anterior pole was at the top of the display * and the posterior pole at the bottom of the display. However * the default view was changed to be a lateral view so the surface * did not scale to fit the window and there were problems with the * surfaces scaling improperly when the overlay toolbox was changed * in height. * * This code adjusts the surface scaling for older scenes so that * older scenes are restored properly with the newer default scaling * for a lateral view. * * See also: BrainOpenGLFixedPipeline::setOrthographicProjectionForWithBoundingBox() */ if (sceneClass->getVersionNumber() < 4) { Surface* surface = NULL; switch (getSelectedModelType()) { case ModelTypeEnum::MODEL_TYPE_CHART: break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: break; case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: { ModelSurface* modelSurface = getDisplayedSurfaceModel(); if (modelSurface != NULL) { surface = modelSurface->getSurface(); } } break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: { ModelSurfaceMontage* modelMontage = getDisplayedSurfaceMontageModel(); if (modelMontage != NULL) { std::vector surfaceMontageViewports; modelMontage->getSurfaceMontageViewportsForDrawing(getTabNumber(), surfaceMontageViewports); for (std::vector::iterator iter = surfaceMontageViewports.begin(); iter != surfaceMontageViewports.end(); iter++) { SurfaceMontageViewport* smv = *iter; if (smv->getSurface() != NULL) { surface = smv->getSurface(); break; } } } } break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: { ModelWholeBrain* modelWholeBrain = getDisplayedWholeBrainModel(); if (modelWholeBrain != NULL) { std::vector allSurfaces = modelWholeBrain->getSelectedSurfaces(getTabNumber()); if ( ! allSurfaces.empty()) { surface = allSurfaces[0]; } } } break; } if (surface != NULL) { if (surface->getSurfaceType() != SurfaceTypeEnum::FLAT) { const BoundingBox* boundingBox = surface->getBoundingBox(); const float zDiff = boundingBox->getDifferenceZ(); const float maxDim = std::max(std::max(boundingBox->getDifferenceX(), boundingBox->getDifferenceY()), zDiff); if (zDiff > 0.0) { const float scaleAdjustment = zDiff / maxDim; //maxDim / zDiff; float scaling = getScaling(); scaling *= scaleAdjustment; setScaling(scaling); } } } } if (sceneClass->getVersionNumber() < 5) { if ( ! m_userName.isEmpty()) { /* * Prior to version 5 and WB-576, * the tab number was ALWAYS displayed. */ m_userName.insert(0, "(" + AString::number(m_tabNumber + 1) + ") "); } } if (sceneClass->getVersionNumber() < 6) { /* * WB-491 sets the viewport for flat surfaces to fit the * flat surface when viewing a flat montage */ const ModelSurfaceMontage* msm = getDisplayedSurfaceMontageModel(); if (msm != NULL) { const SurfaceMontageConfigurationAbstract* smc = msm->getSelectedConfiguration(m_tabNumber); if (smc != NULL) { if (smc->getConfigurationType() == SurfaceMontageConfigurationTypeEnum::FLAT_CONFIGURATION) { setScaling(1.0); } } } } } /** * Get the clipping planes enabled attributes * * @param xEnabled * X clipping plane enabled. * @param yEnabled * Y clipping plane enabled. * @param zEnabled * Z clipping plane enabled. * @param surfaceEnabled * Surface clipping enabled. * @param volumeEnabled * Volume clipping enabled. * @param featuresEnabled * Features enabled. * @param displayClippingBox * Display the clipping box. */ void BrowserTabContent::getClippingPlaneEnabled(bool& xEnabled, bool& yEnabled, bool& zEnabled, bool& surfaceEnabled, bool& volumeEnabled, bool& featuresEnabled) const { xEnabled = m_clippingPlaneGroup->isXAxisSelected(); yEnabled = m_clippingPlaneGroup->isYAxisSelected(); zEnabled = m_clippingPlaneGroup->isZAxisSelected(); surfaceEnabled = m_clippingPlaneGroup->isSurfaceSelected(); volumeEnabled = m_clippingPlaneGroup->isVolumeSelected(); featuresEnabled = m_clippingPlaneGroup->isFeaturesSelected(); } /** * Set the clipping planes enabled attributes * * @param xEnabled * X clipping plane enabled. * @param yEnabled * Y clipping plane enabled. * @param zEnabled * Z clipping plane enabled. * @param surfaceEnabled * Surface clipping enabled. * @param volumeEnabled * Volume clipping enabled. * @param featuresEnabled * Features enabled. * @param displayClippingBox * Display the clipping box. */ void BrowserTabContent::setClippingPlaneEnabled(const bool xEnabled, const bool yEnabled, const bool zEnabled, const bool surfaceEnabled, const bool volumeEnabled, const bool featuresEnabled) { m_clippingPlaneGroup->setXAxisSelected(xEnabled); m_clippingPlaneGroup->setYAxisSelected(yEnabled); m_clippingPlaneGroup->setZAxisSelected(zEnabled); m_clippingPlaneGroup->setSurfaceSelected(surfaceEnabled); m_clippingPlaneGroup->setVolumeSelected(volumeEnabled); m_clippingPlaneGroup->setFeaturesSelected(featuresEnabled); updateYokedModelBrowserTabs(); } /** * Get the clipping planes transformations. * * @param panning * Panning (translation) of the clipping planes. * @param rotation * Rotation of clipping planes. * @param thickness * Thickness of the clipping planes. */ void BrowserTabContent::getClippingPlaneTransformation(float panning[3], float rotation[3], float thickness[3], bool& displayClippingBox) const { m_clippingPlaneGroup->getTranslation(panning); m_clippingPlaneGroup->getRotationAngles(rotation); m_clippingPlaneGroup->getThickness(thickness); displayClippingBox = m_clippingPlaneGroup->isDisplayClippingBoxSelected(); } /** * Set the clipping planes transformations. * * @param panning * Panning (translation) of the clipping planes. * @param rotation * Rotation of clipping planes. * @param thickness * Thickness of the clipping planes. */ void BrowserTabContent::setClippingPlaneTransformation(const float panning[3], const float rotation[3], const float thickness[3], const bool displayClippingBox) { m_clippingPlaneGroup->setTranslation(panning); m_clippingPlaneGroup->setRotationAngles(rotation); m_clippingPlaneGroup->setThickness(thickness); m_clippingPlaneGroup->setDisplayClippingBoxSelected(displayClippingBox); updateYokedModelBrowserTabs(); } /** * Get the clipping plane group (const method). * * NOTE: Because of yoking, only a const instance of the clipping plane * group is available. To adjust the clipping planes use the methods * in this class so that yoking is properly updated. */ const ClippingPlaneGroup* BrowserTabContent::getClippingPlaneGroup() const { return m_clippingPlaneGroup; } /** * Reset the clipping plane transformations. */ void BrowserTabContent::resetClippingPlaneTransformation() { m_clippingPlaneGroup->resetTransformation(); updateYokedModelBrowserTabs(); } /** * @return the projection view type (view from left/right) */ ProjectionViewTypeEnum::Enum BrowserTabContent::getProjectionViewType() const { ProjectionViewTypeEnum::Enum projectionViewType = ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_LATERAL; const ModelSurface* modelSurface = getDisplayedSurfaceModel(); if (modelSurface != NULL) { const SurfaceFile* surfaceFile = modelSurface->getSurface(); if (surfaceFile != NULL) { const StructureEnum::Enum structure = surfaceFile->getStructure(); const SurfaceTypeEnum::Enum surfaceType = surfaceFile->getSurfaceType(); if (StructureEnum::isRight(structure)) { projectionViewType = ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_LATERAL; if (surfaceType == SurfaceTypeEnum::FLAT) { projectionViewType = ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_FLAT_SURFACE; } } else { projectionViewType = ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_LATERAL; if (surfaceType == SurfaceTypeEnum::FLAT) { projectionViewType = ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_FLAT_SURFACE; } } } } return projectionViewType; } /** * @return The slice view plane. * */ VolumeSliceViewPlaneEnum::Enum BrowserTabContent::getSliceViewPlane() const { return m_volumeSliceSettings->getSliceViewPlane(); } /** * Set the slice view plane. * @param windowTabNumber * New value for slice plane. */ void BrowserTabContent::setSliceViewPlane(const VolumeSliceViewPlaneEnum::Enum slicePlane) { m_volumeSliceSettings->setSliceViewPlane(slicePlane); updateBrainModelYokedBrowserTabs(); } /** * @return The layout for all slices view (grid, row, column) */ VolumeSliceViewAllPlanesLayoutEnum::Enum BrowserTabContent::getSlicePlanesAllViewLayout() const { return m_volumeSliceSettings->getSlicePlanesAllViewLayout(); } /** * Set the layout for all slices view (grid, row, column) * * @param slicePlanesAllViewLayout * New value for layout. */ void BrowserTabContent::setSlicePlanesAllViewLayout(const VolumeSliceViewAllPlanesLayoutEnum::Enum slicePlanesAllViewLayout) { m_volumeSliceSettings->setSlicePlanesAllViewLayout(slicePlanesAllViewLayout); updateBrainModelYokedBrowserTabs(); } /** * @return Type of slice drawing (single/montage) */ VolumeSliceDrawingTypeEnum::Enum BrowserTabContent::getSliceDrawingType() const { return m_volumeSliceSettings->getSliceDrawingType(); } /** * Set type of slice drawing (single/montage) * * @param sliceDrawingType * New value for slice drawing type. */ void BrowserTabContent::setSliceDrawingType(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType) { m_volumeSliceSettings->setSliceDrawingType(sliceDrawingType); updateBrainModelYokedBrowserTabs(); } /** * @return Type of slice projection (oblique/orthogonal) */ VolumeSliceProjectionTypeEnum::Enum BrowserTabContent::getSliceProjectionType() const { return m_volumeSliceSettings->getSliceProjectionType(); } /** * Set type of slice projection (oblique/orthogonal) * * @param sliceProjectionType * New value for slice projection type. */ void BrowserTabContent::setSliceProjectionType(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType) { m_volumeSliceSettings->setSliceProjectionType(sliceProjectionType); updateBrainModelYokedBrowserTabs(); } /** * @return The masking used when drawing an oblique volume slice */ VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum BrowserTabContent::getVolumeSliceInterpolationEdgeEffectsMaskingType() const { return m_volumeSliceSettings->getVolumeSliceInterpolationEdgeEffectsMaskingType(); } /** * Set the masking used when drawing an oblique volume slice. * * @param maskingType * Type of masking. */ void BrowserTabContent::setVolumeSliceInterpolationEdgeEffectsMaskingType(const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum maskingType) { m_volumeSliceSettings->setVolumeSliceInterpolationEdgeEffectsMaskingType(maskingType); updateBrainModelYokedBrowserTabs(); } /** * @return the montage number of columns for the given window tab. */ int32_t BrowserTabContent::getMontageNumberOfColumns() const { return m_volumeSliceSettings->getMontageNumberOfColumns(); } /** * Set the montage number of columns in the given window tab. * @param montageNumberOfColumns * New value for montage number of columns */ void BrowserTabContent::setMontageNumberOfColumns(const int32_t montageNumberOfColumns) { m_volumeSliceSettings->setMontageNumberOfColumns(montageNumberOfColumns); updateBrainModelYokedBrowserTabs(); } /** * @return the montage number of rows for the given window tab. */ int32_t BrowserTabContent::getMontageNumberOfRows() const { return m_volumeSliceSettings->getMontageNumberOfRows(); } /** * Set the montage number of rows. * @param montageNumberOfRows * New value for montage number of rows */ void BrowserTabContent::setMontageNumberOfRows(const int32_t montageNumberOfRows) { m_volumeSliceSettings->setMontageNumberOfRows(montageNumberOfRows); updateBrainModelYokedBrowserTabs(); } /** * @return the montage slice spacing. */ int32_t BrowserTabContent::getMontageSliceSpacing() const { return m_volumeSliceSettings->getMontageSliceSpacing(); } /** * Set the montage slice spacing. * @param montageSliceSpacing * New value for montage slice spacing */ void BrowserTabContent::setMontageSliceSpacing(const int32_t montageSliceSpacing) { m_volumeSliceSettings->setMontageSliceSpacing(montageSliceSpacing); updateBrainModelYokedBrowserTabs(); } /** * Set the selected slices to the origin. */ void BrowserTabContent::setSlicesToOrigin() { selectSlicesAtOrigin(); updateBrainModelYokedBrowserTabs(); } /** * Reset the slices. */ void BrowserTabContent::reset() { if (isVolumeSlicesDisplayed() || isWholeBrainDisplayed()) { m_volumeSliceSettings->reset(); m_obliqueVolumeRotationMatrix->identity(); } updateBrainModelYokedBrowserTabs(); } /** * Update the slices coordinates so that they are valid for * the given VolumeFile. * @param volumeFile * File for which slice coordinates are made valid. */ void BrowserTabContent::updateForVolumeFile(const VolumeMappableInterface* volumeFile) { m_volumeSliceSettings->updateForVolumeFile(volumeFile); } /** * Set the slice indices so that they are at the origin. */ void BrowserTabContent::selectSlicesAtOrigin() { m_volumeSliceSettings->selectSlicesAtOrigin(); updateBrainModelYokedBrowserTabs(); } /** * Set the selected slices to the given coordinate. * @param xyz * Coordinate for selected slices. */ void BrowserTabContent::selectSlicesAtCoordinate(const float xyz[3]) { m_volumeSliceSettings->selectSlicesAtCoordinate(xyz); updateBrainModelYokedBrowserTabs(); } /** * If true, selected volume slices in tab move to location * of the identification operation. */ bool BrowserTabContent::isIdentificationUpdatesVolumeSlices() const { return m_identificationUpdatesVolumeSlices; } /** * Update selected volume slices in tab move to location * of the identification operation. * * @param status * New status. */ void BrowserTabContent::setIdentificationUpdatesVolumeSlices(const bool status) { m_identificationUpdatesVolumeSlices = status; updateBrainModelYokedBrowserTabs(); } /** * @return Is volume axis crosshairs displayed */ bool BrowserTabContent::isVolumeAxesCrosshairsDisplayed() const { return m_displayVolumeAxesCrosshairs; } /** * Set volume axis crosshairs displayed * * @param displayed * New status */ void BrowserTabContent::setVolumeAxesCrosshairsDisplayed(const bool displayed) { m_displayVolumeAxesCrosshairs = displayed; updateBrainModelYokedBrowserTabs(); } /** * @return Is volume axis crosshairs labels displayed */ bool BrowserTabContent::isVolumeAxesCrosshairLabelsDisplayed() const { return m_displayVolumeAxesCrosshairLabels; } /** * Set volume axis crosshairs labels displayed * * @param displayed * New status */ void BrowserTabContent::setVolumeAxesCrosshairLabelsDisplayed(const bool displayed) { m_displayVolumeAxesCrosshairLabels = displayed; updateBrainModelYokedBrowserTabs(); } /** * @return Is volume montage axes coordinates displayed */ bool BrowserTabContent::isVolumeMontageAxesCoordinatesDisplayed() const { return m_displayVolumeMontageAxesCoordinates; } /** * Set volume montage axes coordinates displayed * * @param displayed * New status */ void BrowserTabContent::setVolumeMontageAxesCoordinatesDisplayed(const bool displayed) { m_displayVolumeMontageAxesCoordinates = displayed; updateBrainModelYokedBrowserTabs(); } /** * @return Digits right of decimal for montage coordinates */ int32_t BrowserTabContent::getVolumeMontageCoordinatePrecision() const { return m_volumeMontageCoordinatePrecision; } /** * Set digits right of decimal for montage coordinates * * @param volumeMontageCoordinatePrecision * New precision */ void BrowserTabContent::setVolumeMontageCoordinatePrecision(const int32_t volumeMontageCoordinatePrecision) { m_volumeMontageCoordinatePrecision = volumeMontageCoordinatePrecision; updateBrainModelYokedBrowserTabs(); } /** * @return Is lighting enabled ? */ bool BrowserTabContent::isLightingEnabled() const { return m_lightingEnabled; } /** * Set lighting enabled. * * @param lightingEnabled * New status for lighting. */ void BrowserTabContent::setLightingEnabled(const bool lightingEnabled) { m_lightingEnabled = lightingEnabled; } /** * Return the axial slice index. * @return * Axial slice index or negative if invalid */ int64_t BrowserTabContent::getSliceIndexAxial(const VolumeMappableInterface* volumeFile) const { return m_volumeSliceSettings->getSliceIndexAxial(volumeFile); } /** * Set the axial slice index. * @param * New value for axial slice index. */ void BrowserTabContent::setSliceIndexAxial(const VolumeMappableInterface* volumeFile, const int64_t sliceIndexAxial) { m_volumeSliceSettings->setSliceIndexAxial(volumeFile, sliceIndexAxial); updateBrainModelYokedBrowserTabs(); } /** * Return the coronal slice index. * @return * Coronal slice index. */ int64_t BrowserTabContent::getSliceIndexCoronal(const VolumeMappableInterface* volumeFile) const { return m_volumeSliceSettings->getSliceIndexCoronal(volumeFile); } /** * Set the coronal slice index. * @param sliceIndexCoronal * New value for coronal slice index. */ void BrowserTabContent::setSliceIndexCoronal(const VolumeMappableInterface* volumeFile, const int64_t sliceIndexCoronal) { m_volumeSliceSettings->setSliceIndexCoronal(volumeFile, sliceIndexCoronal); updateBrainModelYokedBrowserTabs(); } /** * Return the parasagittal slice index. * @return * Parasagittal slice index. */ int64_t BrowserTabContent::getSliceIndexParasagittal(const VolumeMappableInterface* volumeFile) const { return m_volumeSliceSettings->getSliceIndexParasagittal(volumeFile); } /** * Set the parasagittal slice index. * @param sliceIndexParasagittal * New value for parasagittal slice index. */ void BrowserTabContent::setSliceIndexParasagittal(const VolumeMappableInterface* volumeFile, const int64_t sliceIndexParasagittal) { m_volumeSliceSettings->setSliceIndexParasagittal(volumeFile, sliceIndexParasagittal); updateBrainModelYokedBrowserTabs(); } /** * @return Coordinate of axial slice. */ float BrowserTabContent::getSliceCoordinateAxial() const { return m_volumeSliceSettings->getSliceCoordinateAxial(); } /** * Set the coordinate for the axial slice. * @param z * Z-coordinate for axial slice. */ void BrowserTabContent::setSliceCoordinateAxial(const float z) { m_volumeSliceSettings->setSliceCoordinateAxial(z); updateBrainModelYokedBrowserTabs(); } /** * @return Coordinate of coronal slice. */ float BrowserTabContent::getSliceCoordinateCoronal() const { return m_volumeSliceSettings->getSliceCoordinateCoronal(); } /** * Set the coordinate for the coronal slice. * @param y * Y-coordinate for coronal slice. */ void BrowserTabContent::setSliceCoordinateCoronal(const float y) { m_volumeSliceSettings->setSliceCoordinateCoronal(y); updateBrainModelYokedBrowserTabs(); } /** * @return Coordinate of parasagittal slice. */ float BrowserTabContent::getSliceCoordinateParasagittal() const { return m_volumeSliceSettings->getSliceCoordinateParasagittal(); } /** * Set the coordinate for the parasagittal slice. * @param x * X-coordinate for parasagittal slice. */ void BrowserTabContent::setSliceCoordinateParasagittal(const float x) { m_volumeSliceSettings->setSliceCoordinateParasagittal(x); updateBrainModelYokedBrowserTabs(); } /** * Is the parasagittal slice enabled? * @return * Enabled status of parasagittal slice. */ bool BrowserTabContent::isSliceParasagittalEnabled() const { return m_volumeSliceSettings->isSliceParasagittalEnabled(); } /** * Set the enabled status of the parasagittal slice. * @param sliceEnabledParasagittal * New enabled status. */ void BrowserTabContent::setSliceParasagittalEnabled(const bool sliceEnabledParasagittal) { m_volumeSliceSettings->setSliceParasagittalEnabled(sliceEnabledParasagittal); updateBrainModelYokedBrowserTabs(); } /** * Is the coronal slice enabled? * @return * Enabled status of coronal slice. */ bool BrowserTabContent::isSliceCoronalEnabled() const { return m_volumeSliceSettings->isSliceCoronalEnabled(); } /** * Set the enabled status of the coronal slice. * @param sliceEnabledCoronal * New enabled status. */ void BrowserTabContent::setSliceCoronalEnabled(const bool sliceEnabledCoronal) { m_volumeSliceSettings->setSliceCoronalEnabled(sliceEnabledCoronal); updateBrainModelYokedBrowserTabs(); } /** * Is the axial slice enabled? * @return * Enabled status of axial slice. */ bool BrowserTabContent::isSliceAxialEnabled() const { return m_volumeSliceSettings->isSliceAxialEnabled(); } /** * Set the enabled status of the axial slice. * @param sliceEnabledAxial * New enabled status. */ void BrowserTabContent::setSliceAxialEnabled(const bool sliceEnabledAxial) { m_volumeSliceSettings->setSliceAxialEnabled(sliceEnabledAxial); updateBrainModelYokedBrowserTabs(); } /** * @return Enabled status for left cerebral cortex. */ bool BrowserTabContent::isWholeBrainLeftEnabled() const { return m_wholeBrainSurfaceSettings->isLeftEnabled(); } /** * Set the enabled status for the left hemisphere. * @param windowTabNumber * Index of window tab. * @param enabled * New enabled status. */ void BrowserTabContent::setWholeBrainLeftEnabled(const bool enabled) { m_wholeBrainSurfaceSettings->setLeftEnabled(enabled); updateBrainModelYokedBrowserTabs(); } /** * @return Enabled status for right cerebral cortex. */ bool BrowserTabContent::isWholeBrainRightEnabled() const { return m_wholeBrainSurfaceSettings->isRightEnabled(); } /** * Set the enabled status for the right hemisphere. * @param enabled * New enabled status. */ void BrowserTabContent::setWholeBrainRightEnabled(const bool enabled) { m_wholeBrainSurfaceSettings->setRightEnabled(enabled); updateBrainModelYokedBrowserTabs(); } /** * @return Enabled status for cerebellum. */ bool BrowserTabContent::isWholeBrainCerebellumEnabled() const { return m_wholeBrainSurfaceSettings->isCerebellumEnabled(); } /** * Set the enabled status for the cerebellum. * @param enabled * New enabled status. */ void BrowserTabContent::setWholeBrainCerebellumEnabled(const bool enabled) { m_wholeBrainSurfaceSettings->setCerebellumEnabled(enabled); updateBrainModelYokedBrowserTabs(); } /** * @return The separation between the left and right surfaces. */ float BrowserTabContent::getWholeBrainLeftRightSeparation() const { return m_wholeBrainSurfaceSettings->getLeftRightSeparation(); } /** * Set the separation between the cerebellum and the left/right surfaces. * @param separation * New value for separation. */ void BrowserTabContent::setWholeBrainLeftRightSeparation(const float separation) { m_wholeBrainSurfaceSettings->setLeftRightSeparation(separation); updateBrainModelYokedBrowserTabs(); } /** * @return The separation between the left/right surfaces. */ float BrowserTabContent::getWholeBrainCerebellumSeparation() const { return m_wholeBrainSurfaceSettings->getCerebellumSeparation(); } /** * Set the separation between the cerebellum and the left and right surfaces. * @param separation * New value for separation. */ void BrowserTabContent::setWholeBrainCerebellumSeparation(const float separation) { m_wholeBrainSurfaceSettings->setCerebellumSeparation(separation); updateBrainModelYokedBrowserTabs(); } /** * @return Selected yoking group for charts */ YokingGroupEnum::Enum BrowserTabContent::getChartModelYokingGroup() const { return m_chartModelYokingGroup; } /** * Set the selected yoking group for charts. * * @param chartModelYokingType * New value for yoking group. */ void BrowserTabContent::setChartModelYokingGroup(const YokingGroupEnum::Enum chartModelYokingType) { m_chartModelYokingGroup = chartModelYokingType; if (m_chartModelYokingGroup == YokingGroupEnum::YOKING_GROUP_OFF) { return; } int32_t copyFromTabIndex = -1; /* * Find another browser tab using the same yoking as 'me' and copy * yoked data from the other browser tab. */ for (std::set::iterator iter = s_allBrowserTabContent.begin(); iter != s_allBrowserTabContent.end(); iter++) { BrowserTabContent* btc = *iter; if (btc != this) { if (btc->getChartModelYokingGroup() == m_chartModelYokingGroup) { copyFromTabIndex = btc->getTabNumber(); /* * If anything is added, also need to update updateYokedBrowserTabs() */ *m_chartTwoMatrixViewingTranformation = *btc->m_chartTwoMatrixViewingTranformation; *m_chartTwoMatrixDisplayProperties = *btc->m_chartTwoMatrixDisplayProperties; break; } } } if (copyFromTabIndex >= 0) { /* * Maybe NULL when restoring scenes */ if (m_chartTwoModel != NULL) { m_chartTwoModel->copyChartTwoCartesianAxes(copyFromTabIndex, m_tabNumber); } } } /** * @return Selected yoking group for brain models (surface or volumes) */ YokingGroupEnum::Enum BrowserTabContent::getBrainModelYokingGroup() const { return m_brainModelYokingGroup; } /** * Set the selected yoking group for brain models (surface or volumes) * * @param brainModelYokingType * New value for yoking group. */ void BrowserTabContent::setBrainModelYokingGroup(const YokingGroupEnum::Enum brainModelYokingType) { m_brainModelYokingGroup = brainModelYokingType; if (m_brainModelYokingGroup == YokingGroupEnum::YOKING_GROUP_OFF) { return; } /* * Find another browser tab using the same yoking as 'me' and copy * yoked data from the other browser tab. */ for (std::set::iterator iter = s_allBrowserTabContent.begin(); iter != s_allBrowserTabContent.end(); iter++) { BrowserTabContent* btc = *iter; if (btc != this) { if (btc->getBrainModelYokingGroup() == m_brainModelYokingGroup) { /* * If anything is added, also need to update updateYokedBrowserTabs() */ *m_viewingTransformation = *btc->m_viewingTransformation; *m_flatSurfaceViewingTransformation = *btc->m_flatSurfaceViewingTransformation; *m_cerebellumViewingTransformation = *btc->m_cerebellumViewingTransformation; *m_volumeSliceViewingTransformation = *btc->m_volumeSliceViewingTransformation; const VolumeSliceViewPlaneEnum::Enum slicePlane = m_volumeSliceSettings->getSliceViewPlane(); *m_volumeSliceSettings = *btc->m_volumeSliceSettings; m_volumeSliceSettings->setSliceViewPlane(slicePlane); // do not yoke the slice plane *m_obliqueVolumeRotationMatrix = *btc->m_obliqueVolumeRotationMatrix; *m_clippingPlaneGroup = *btc->m_clippingPlaneGroup; m_identificationUpdatesVolumeSlices = btc->m_identificationUpdatesVolumeSlices; m_displayVolumeAxesCrosshairs = btc->m_displayVolumeAxesCrosshairs; m_displayVolumeAxesCrosshairLabels = btc->m_displayVolumeAxesCrosshairLabels; m_displayVolumeMontageAxesCoordinates = btc->m_displayVolumeMontageAxesCoordinates; m_volumeMontageCoordinatePrecision = btc->m_volumeMontageCoordinatePrecision; /** * lighting enabled NOT yoked * m_lightingEnabled = btc->m_lightingEnabled; */ break; } } } } /** * @return Is this browser tab brain model yoked? */ bool BrowserTabContent::isBrainModelYoked() const { const bool yoked = (m_brainModelYokingGroup != YokingGroupEnum::YOKING_GROUP_OFF); return yoked; } /** * @return Is this browser tab chart model yoked? */ bool BrowserTabContent::isChartModelYoked() const { const bool yoked = (m_chartModelYokingGroup != YokingGroupEnum::YOKING_GROUP_OFF); return yoked; } /** * Update other browser tabs with brain or chart yoked data dependent upon active model */ void BrowserTabContent::updateYokedModelBrowserTabs() { bool chartFlag = false; switch (getSelectedModelType()) { case ModelTypeEnum::MODEL_TYPE_CHART: chartFlag = true; break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: chartFlag = true; break; case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: break; } if (chartFlag) { updateChartModelYokedBrowserTabs(); } else { updateBrainModelYokedBrowserTabs(); } } /** * Update other browser tabs with brain model yoked data. */ void BrowserTabContent::updateBrainModelYokedBrowserTabs() { if (isExecutingConstructor) { return; } if (m_brainModelYokingGroup == YokingGroupEnum::YOKING_GROUP_OFF) { return; } /* * Copy yoked data from 'me' to all other yoked browser tabs */ for (std::set::iterator iter = s_allBrowserTabContent.begin(); iter != s_allBrowserTabContent.end(); iter++) { BrowserTabContent* btc = *iter; if (btc != this) { /* * If anything is added, also need to update setYokingGroup() */ if (btc->getBrainModelYokingGroup() == m_brainModelYokingGroup) { *btc->m_viewingTransformation = *m_viewingTransformation; *btc->m_flatSurfaceViewingTransformation = *m_flatSurfaceViewingTransformation; *btc->m_cerebellumViewingTransformation = *m_cerebellumViewingTransformation; *btc->m_volumeSliceViewingTransformation = *m_volumeSliceViewingTransformation; const VolumeSliceViewPlaneEnum::Enum slicePlane = btc->m_volumeSliceSettings->getSliceViewPlane(); *btc->m_volumeSliceSettings = *m_volumeSliceSettings; btc->m_volumeSliceSettings->setSliceViewPlane(slicePlane); // do not yoke the slice plane *btc->m_obliqueVolumeRotationMatrix = *m_obliqueVolumeRotationMatrix; *btc->m_clippingPlaneGroup = *m_clippingPlaneGroup; btc->m_identificationUpdatesVolumeSlices = m_identificationUpdatesVolumeSlices; btc->m_displayVolumeAxesCrosshairs = m_displayVolumeAxesCrosshairs; btc->m_displayVolumeAxesCrosshairLabels = m_displayVolumeAxesCrosshairLabels; btc->m_displayVolumeMontageAxesCoordinates = m_displayVolumeMontageAxesCoordinates; btc->m_volumeMontageCoordinatePrecision = m_volumeMontageCoordinatePrecision; /** * lighting enabled NOT yoked * btc->m_lightingEnabled = m_lightingEnabled; */ } } } } /** * Update other browser tabs with brain model yoked data. */ void BrowserTabContent::updateChartModelYokedBrowserTabs() { if (isExecutingConstructor) { return; } if (m_chartModelYokingGroup == YokingGroupEnum::YOKING_GROUP_OFF) { return; } /* * Copy yoked data from 'me' to all other yoked browser tabs */ for (std::set::iterator iter = s_allBrowserTabContent.begin(); iter != s_allBrowserTabContent.end(); iter++) { BrowserTabContent* btc = *iter; if (btc != this) { /* * If anything is added, also need to update setYokingGroup() */ if (btc->getChartModelYokingGroup() == m_chartModelYokingGroup) { *btc->m_chartTwoMatrixViewingTranformation = *m_chartTwoMatrixViewingTranformation; *btc->m_chartTwoMatrixDisplayProperties = *m_chartTwoMatrixDisplayProperties; } } } } connectome-workbench-1.4.2/src/Brain/BrowserTabContent.h000066400000000000000000000532311360521144700232370ustar00rootroot00000000000000#ifndef __BROWSER_TAB_CONTENT__H_ #define __BROWSER_TAB_CONTENT__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "EventListenerInterface.h" #include "Model.h" #include "ModelTypeEnum.h" #include "Plane.h" #include "ProjectionViewTypeEnum.h" #include "SceneableInterface.h" #include "StructureEnum.h" #include "TabContentBase.h" #include "VolumeSliceDrawingTypeEnum.h" #include "VolumeSliceInterpolationEdgeEffectsMaskingEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "VolumeSliceViewPlaneEnum.h" #include "VolumeSliceViewAllPlanesLayoutEnum.h" #include "YokingGroupEnum.h" namespace caret { class AnnotationColorBar; class BrainOpenGLViewportContent; class CaretDataFile; class CaretMappableDataFile; class ChartTwoMatrixDisplayProperties; class ChartTwoOverlaySet; class ClippingPlaneGroup; class EventCaretMappableDataFilesAndMapsInDisplayedOverlays; class Matrix4x4; class ModelChart; class ModelChartTwo; class ModelSurface; class ModelSurfaceMontage; class ModelSurfaceSelector; class ModelTransform; class ModelVolume; class ModelWholeBrain; class OverlaySet; class Palette; class PlainTextStringBuilder; class SceneClassAssistant; class Surface; class ViewingTransformations; class ViewingTransformationsCerebellum; class ViewingTransformationsVolume; class VolumeMappableInterface; class VolumeSliceSettings; class VolumeSurfaceOutlineSetModel; class WholeBrainSurfaceSettings; /// Maintains content in a brower's tab class BrowserTabContent : public TabContentBase, public EventListenerInterface, public SceneableInterface { public: BrowserTabContent(const int32_t tabNumber); virtual ~BrowserTabContent(); void cloneBrowserTabContent(BrowserTabContent* tabToClone); virtual void receiveEvent(Event* event); virtual void getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const; virtual AString toString() const; AString getTabName() const override; AString getUserTabName() const; void setUserTabName(const AString& userName); OverlaySet* getOverlaySet(); const OverlaySet* getOverlaySet() const; ChartTwoOverlaySet* getChartTwoOverlaySet(); const ChartTwoOverlaySet* getChartTwoOverlaySet() const; int32_t getTabNumber() const; ModelTypeEnum::Enum getSelectedModelType() const; void setSelectedModelType(ModelTypeEnum::Enum selectedModelType); const Model* getModelForDisplay() const; Model* getModelForDisplay(); ModelChart* getDisplayedChartOneModel(); const ModelChart* getDisplayedChartOneModel() const; ModelChartTwo* getDisplayedChartTwoModel(); const ModelChartTwo* getDisplayedChartTwoModel() const; ModelSurface* getDisplayedSurfaceModel(); const ModelSurface* getDisplayedSurfaceModel() const; ModelVolume* getDisplayedVolumeModel(); const ModelVolume* getDisplayedVolumeModel() const; ModelWholeBrain* getDisplayedWholeBrainModel(); ModelSurfaceMontage* getDisplayedSurfaceMontageModel(); const ModelSurfaceMontage* getDisplayedSurfaceMontageModel() const; const std::vector getAllSurfaceModels() const; ModelSurfaceSelector* getSurfaceModelSelector(); std::vector getSurfaceStructuresDisplayed(); bool isCerebellumDisplayed() const; bool isChartOneDisplayed() const; bool isChartTwoDisplayed() const; bool isFlatSurfaceDisplayed() const; bool isVolumeSlicesDisplayed() const; bool isWholeBrainDisplayed() const; void getFilesDisplayedInTab(std::vector& displayedDataFilesOut); void getFilesAndMapIndicesInOverlays(EventCaretMappableDataFilesAndMapsInDisplayedOverlays* fileAndMapsEvent); void update(const std::vector models); bool isChartOneModelValid() const; bool isChartTwoModelValid() const; bool isSurfaceModelValid() const; bool isVolumeSliceModelValid() const; bool isWholeBrainModelValid() const; bool isSurfaceMontageModelValid() const; void getAnnotationColorBars(std::vector& colorBarsOut); void getDisplayedPaletteMapFiles(std::vector& mapFiles, std::vector& mapIndices); VolumeSurfaceOutlineSetModel* getVolumeSurfaceOutlineSet(); const VolumeSurfaceOutlineSetModel* getVolumeSurfaceOutlineSet() const; bool isAspectRatioLocked() const; void setAspectRatioLocked(const bool locked); float getAspectRatio() const; void setAspectRatio(const float aspectRatio); void getClippingPlaneEnabled(bool& xEnabled, bool& yEnabled, bool& zEnabled, bool& surfaceEnabled, bool& volumeEnabled, bool& featuresEnabled) const; void setClippingPlaneEnabled(const bool xEnabled, const bool yEnabled, const bool zEnabled, const bool surfaceEnabled, const bool volumeEnabled, const bool featuresEnabled); void getClippingPlaneTransformation(float panning[3], float rotation[3], float thickness[3], bool& displayClippingBox) const; void setClippingPlaneTransformation(const float panning[3], const float rotation[3], const float thickness[3], const bool displayClippingBox); const ClippingPlaneGroup* getClippingPlaneGroup() const; void resetClippingPlaneTransformation(); const float* getTranslation() const; void getTranslation(float translationOut[3]) const; void setTranslation( const float translation[3]); void setTranslation(const float translationX, const float translationY, const float translationZ); float getScaling() const; void setScaling(const float scaling); Matrix4x4 getRotationMatrix() const; void setRotationMatrix(const Matrix4x4& rotationMatrix); Matrix4x4 getObliqueVolumeRotationMatrix() const; void setObliqueVolumeRotationMatrix(const Matrix4x4& obliqueRotationMatrix); void getRightCortexFlatMapOffset(float& offsetX, float& offsetY) const; void setRightCortexFlatMapOffset(const float offsetX, const float offsetY); float getRightCortexFlatMapZoomFactor() const; void setRightCortexFlatMapZoomFactor(const float zoomFactor); ProjectionViewTypeEnum::Enum getProjectionViewType() const; void resetView(); void rightView(); void leftView(); void anteriorView(); void posteriorView(); void dorsalView(); void ventralView(); void applyMouseVolumeSliceIncrement(BrainOpenGLViewportContent* viewportContent, const int32_t mousePressX, const int32_t mousePressY, const int32_t mouseDY); void applyMouseRotation(BrainOpenGLViewportContent* viewportContent, const int32_t mousePressX, const int32_t mousePressY, const int32_t mouseX, const int32_t mouseY, const int32_t mouseDeltaX, const int32_t mouseDeltaY); void applyMouseScaling(const int32_t mouseDX, const int32_t mouseDY); void applyMouseTranslation(BrainOpenGLViewportContent* viewportContent, const int32_t mousePressX, const int32_t mousePressY, const int32_t mouseDX, const int32_t mouseDY); void getTransformationsForOpenGLDrawing(const ProjectionViewTypeEnum::Enum projectionViewType, float translationOut[3], double rotationMatrixOut[16], float& scalingOut) const; void getTransformationsInModelTransform(ModelTransform& modelTransform) const; void setTransformationsFromModelTransform(const ModelTransform& modelTransform); ChartTwoMatrixDisplayProperties* getChartTwoMatrixDisplayProperties(); const ChartTwoMatrixDisplayProperties* getChartTwoMatrixDisplayProperties() const; VolumeSliceViewPlaneEnum::Enum getSliceViewPlane() const; void setSliceViewPlane(VolumeSliceViewPlaneEnum::Enum sliceAxisMode); VolumeSliceViewAllPlanesLayoutEnum::Enum getSlicePlanesAllViewLayout() const; void setSlicePlanesAllViewLayout(const VolumeSliceViewAllPlanesLayoutEnum::Enum slicePlanesAllViewLayout); VolumeSliceDrawingTypeEnum::Enum getSliceDrawingType() const; void setSliceDrawingType(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType); VolumeSliceProjectionTypeEnum::Enum getSliceProjectionType() const; void setSliceProjectionType(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType); VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum getVolumeSliceInterpolationEdgeEffectsMaskingType() const; void setVolumeSliceInterpolationEdgeEffectsMaskingType(const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum maskingType); int32_t getMontageNumberOfColumns() const; void setMontageNumberOfColumns(const int32_t montageNumberOfColumns); int32_t getMontageNumberOfRows() const; void setMontageNumberOfRows(const int32_t montageNumberOfRows); int32_t getMontageSliceSpacing() const; void setMontageSliceSpacing(const int32_t montageSliceSpacing); void setSlicesToOrigin(); float getSliceCoordinateAxial() const; void setSliceCoordinateAxial(const float x); float getSliceCoordinateCoronal() const; void setSliceCoordinateCoronal(const float y); float getSliceCoordinateParasagittal() const; void setSliceCoordinateParasagittal(const float z); int64_t getSliceIndexAxial(const VolumeMappableInterface* volumeFile) const; void setSliceIndexAxial(const VolumeMappableInterface* volumeFile, const int64_t sliceIndexAxial); int64_t getSliceIndexCoronal(const VolumeMappableInterface* volumeFile) const; void setSliceIndexCoronal(const VolumeMappableInterface* volumeFile, const int64_t sliceIndexCoronal); int64_t getSliceIndexParasagittal(const VolumeMappableInterface* volumeFile) const; void setSliceIndexParasagittal(const VolumeMappableInterface* volumeFile, const int64_t sliceIndexParasagittal); bool isSliceParasagittalEnabled() const; void setSliceParasagittalEnabled(const bool sliceEnabledParasagittal); bool isSliceCoronalEnabled() const; void setSliceCoronalEnabled(const bool sliceEnabledCoronal); bool isSliceAxialEnabled() const; void setSliceAxialEnabled(const bool sliceEnabledAxial); void updateForVolumeFile(const VolumeMappableInterface* volumeFile); void selectSlicesAtOrigin(); void selectSlicesAtCoordinate(const float xyz[3]); bool isIdentificationUpdatesVolumeSlices() const; void setIdentificationUpdatesVolumeSlices(const bool status); bool isVolumeAxesCrosshairsDisplayed() const; void setVolumeAxesCrosshairsDisplayed(const bool displayed); bool isVolumeAxesCrosshairLabelsDisplayed() const; void setVolumeAxesCrosshairLabelsDisplayed(const bool displayed); bool isVolumeMontageAxesCoordinatesDisplayed() const; void setVolumeMontageAxesCoordinatesDisplayed(const bool displayed); int32_t getVolumeMontageCoordinatePrecision() const; void setVolumeMontageCoordinatePrecision(const int32_t volumeMontageCoordinatePrecision); bool isLightingEnabled() const; void setLightingEnabled(const bool lightingEnabled); void reset(); void updateChartModelYokedBrowserTabs(); bool isBrainModelYoked() const; bool isChartModelYoked() const; YokingGroupEnum::Enum getBrainModelYokingGroup() const; void setBrainModelYokingGroup(const YokingGroupEnum::Enum brainModelYokingType); YokingGroupEnum::Enum getChartModelYokingGroup() const; void setChartModelYokingGroup(const YokingGroupEnum::Enum chartModelYokingType); bool isWholeBrainLeftEnabled() const; void setWholeBrainLeftEnabled(const bool enabled); bool isWholeBrainRightEnabled() const; void setWholeBrainRightEnabled(const bool enabled); bool isWholeBrainCerebellumEnabled() const; void setWholeBrainCerebellumEnabled(const bool enabled); float getWholeBrainLeftRightSeparation() const; void setWholeBrainLeftRightSeparation(const float separation); float getWholeBrainCerebellumSeparation() const; void setWholeBrainCerebellumSeparation(const float separation); ViewingTransformations* getViewingTransformation(); const ViewingTransformations* getViewingTransformation() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: class ColorBarFileMap { public: ColorBarFileMap(AnnotationColorBar* colorBar, CaretMappableDataFile* mapFile, const int32_t mapIndex) : m_colorBar(colorBar), m_mapFile(mapFile), m_mapIndex(mapIndex) { } AnnotationColorBar* m_colorBar; CaretMappableDataFile* m_mapFile; int32_t m_mapIndex; }; BrowserTabContent(const BrowserTabContent&); BrowserTabContent& operator=(const BrowserTabContent&); // VolumeSliceViewPlaneEnum::Enum getSliceViewPlaneForVolumeAllSliceView(const int viewport[4], // const int32_t mousePressX, // const int32_t mousePressY, // int sliceViewportOut[4]) const; void updateBrainModelYokedBrowserTabs(); void updateYokedModelBrowserTabs(); AString getDefaultName() const; AString getTabNamePrefix() const override; /** Number of this tab */ int32_t m_tabNumber; /** Selected surface model */ ModelSurfaceSelector* m_surfaceModelSelector; /** Selected model type */ ModelTypeEnum::Enum m_selectedModelType; /** All surface models */ std::vector m_allSurfaceModels; /** The volume model */ ModelVolume* m_volumeModel; /** The whole brain model */ ModelWholeBrain* m_wholeBrainModel; /** The surface montage model */ ModelSurfaceMontage* m_surfaceMontageModel; /** The chart model */ ModelChart* m_chartModel; /** The chart two model */ ModelChartTwo* m_chartTwoModel; /** * Name requested by user interface - reflects contents * such as Surface, Volume Slices, etc */ AString m_guiName; /** * User can set the name of the tab. */ AString m_userName; /** * Clipping planes */ ClippingPlaneGroup* m_clippingPlaneGroup; /** * Rotation matrix for oblique volume viewing */ Matrix4x4* m_obliqueVolumeRotationMatrix; /** Brain Model Yoking group */ YokingGroupEnum::Enum m_brainModelYokingGroup; /** Chart Model Yoking group */ YokingGroupEnum::Enum m_chartModelYokingGroup; /** Volume Surface Outlines */ VolumeSurfaceOutlineSetModel* m_volumeSurfaceOutlineSetModel; /** Assists with creating/restoring scenes */ SceneClassAssistant* m_sceneClassAssistant; /** Transformation for cerebellum viewing */ ViewingTransformationsCerebellum* m_cerebellumViewingTransformation; /** Transformation for surface/all viewing */ ViewingTransformations* m_viewingTransformation; /** Transformation for surface/all viewing */ ViewingTransformations* m_flatSurfaceViewingTransformation; /** Transformation for volume slices viewing */ ViewingTransformationsVolume* m_volumeSliceViewingTransformation; /** Transformation for matrix chart two viewing */ ViewingTransformations* m_chartTwoMatrixViewingTranformation; /** Display properties for chart two matrix */ ChartTwoMatrixDisplayProperties* m_chartTwoMatrixDisplayProperties; /** Volume slice settings for volume slices */ VolumeSliceSettings* m_volumeSliceSettings; /** Whole brain surface settings. */ WholeBrainSurfaceSettings* m_wholeBrainSurfaceSettings; /** aspect ratio */ float m_aspectRatio; /** aspect ratio locked */ bool m_aspectRatioLocked; /** * If true, selected volume slices in tab move to location * of the identification operation. */ bool m_identificationUpdatesVolumeSlices; /** display crosshairs on volume slices */ bool m_displayVolumeAxesCrosshairs; /** display crosshair labels on volume slices */ bool m_displayVolumeAxesCrosshairLabels; /** display coordinates on montage */ bool m_displayVolumeMontageAxesCoordinates; /** precision for coordinate on montage */ int32_t m_volumeMontageCoordinatePrecision; /** enable lighting (shading) added 29 March 2018 */ bool m_lightingEnabled; /* * True if constructing an instance */ bool isExecutingConstructor; /** Contains all active browser tab content instances */ static std::set s_allBrowserTabContent; }; #ifdef __BROWSER_TAB_CONTENT_DECLARE__ std::set BrowserTabContent::s_allBrowserTabContent; #endif // __BROWSER_TAB_CONTENT_DECLARE__ } // namespace #endif //__BROWSER_TAB_CONTENT__H_ connectome-workbench-1.4.2/src/Brain/BrowserWindowContent.cxx000066400000000000000000000475051360521144700243620ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BROWSER_WINDOW_CONTENT_DECLARE__ #include "BrowserWindowContent.h" #undef __BROWSER_WINDOW_CONTENT_DECLARE__ #include "CaretAssert.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "SceneIntegerArray.h" #include "ScenePrimitive.h" #include "TileTabsConfiguration.h" using namespace caret; /** * \class caret::BrowserWindowContent * \brief Information about content of a browser window. * \ingroup Brain */ /** * Constructor. */ BrowserWindowContent::BrowserWindowContent(const int32_t windowIndex) : CaretObject(), m_windowIndex(windowIndex) { m_automaticTileTabsConfiguration.reset(new TileTabsConfiguration()); m_customTileTabsConfiguration.reset(new TileTabsConfiguration()); m_validFlag = false; reset(); m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); m_sceneAssistant->add("m_validFlag", &m_validFlag); m_sceneAssistant->add("m_windowAspectRatioLocked", &m_windowAspectRatioLocked); m_sceneAssistant->add("m_windowAspectLockedRatio", &m_windowAspectLockedRatio); m_sceneAssistant->add("m_allTabsInWindowAspectRatioLocked", &m_allTabsInWindowAspectRatioLocked); m_sceneAssistant->add("m_tileTabsEnabled", &m_tileTabsEnabled); m_sceneAssistant->add("m_tileTabsConfigurationMode", &m_tileTabsConfigurationMode); m_sceneAssistant->add("m_sceneGraphicsWidth", &m_sceneGraphicsWidth); m_sceneAssistant->add("m_sceneGraphicsHeight", &m_sceneGraphicsHeight); m_sceneAssistant->add("m_sceneSelectedTabIndex", &m_sceneSelectedTabIndex); } /** * Destructor. */ BrowserWindowContent::~BrowserWindowContent() { } /** * @return True if this browser window content is valid. */ bool BrowserWindowContent::isValid() const { return m_validFlag; } /** * Set validity for this browser window content. * * @param valid * New validity status. */ void BrowserWindowContent::setValid(const bool valid) { m_validFlag = valid; } /** * Reset the number of elements in this instance. */ void BrowserWindowContent::reset() { /* Note: do not change m_validFlag */ m_windowAspectRatioLocked = false; m_windowAspectLockedRatio = 1.0f; m_allTabsInWindowAspectRatioLocked = false; m_tileTabsEnabled = false; m_sceneGraphicsHeight = 0; m_sceneGraphicsWidth = 0; m_tileTabsConfigurationMode = TileTabsGridModeEnum::AUTOMATIC; m_automaticTileTabsConfiguration->updateAutomaticConfigurationRowsAndColumns(1); /* sets rows/columns/factors to defaults */ m_customTileTabsConfiguration->updateAutomaticConfigurationRowsAndColumns(1); m_sceneSelectedTabIndex = 0; m_sceneTabIndices.clear(); } /** * Get a description of this object's content. * @return String describing this object's content. */ int32_t BrowserWindowContent::getWindowIndex() const { return m_windowIndex; } /** * @return Window aspect locked status */ bool BrowserWindowContent::isWindowAspectLocked() const { return m_windowAspectRatioLocked; } /** * Set the window's aspect ratio locked status * * @param lockedStatus * The new locked status. */ void BrowserWindowContent::setWindowAspectLocked(const bool lockedStatus) { m_windowAspectRatioLocked = lockedStatus; } /** * @return The window's locked aspect ratio */ float BrowserWindowContent::getWindowAspectLockedRatio() const { return m_windowAspectLockedRatio; } /** * Set the window's locked aspect ratio * * @param aspectRatio * The aspect ratio. */ void BrowserWindowContent::setWindowAspectLockedRatio(const float aspectRatio) { m_windowAspectLockedRatio = aspectRatio; } /** * @return Is the aspect ratio locked for ALL TABS in the window */ bool BrowserWindowContent::isAllTabsInWindowAspectRatioLocked() const { return m_allTabsInWindowAspectRatioLocked; } /** * Set the aspect ratio locked for ALL TABS in the window * * @param lockedStatus * The new locked status. */ void BrowserWindowContent::setAllTabsInWindowAspectRatioLocked(const bool lockedStatus) { m_allTabsInWindowAspectRatioLocked = lockedStatus; } /** * @return Is tile tabs enabled ? */ bool BrowserWindowContent::isTileTabsEnabled() const { return m_tileTabsEnabled; } /** * Set tile tabs enabled * * @param tileTabsEnabled * Enabled status for tile tabs. */ void BrowserWindowContent::setTileTabsEnabled(const bool tileTabsEnabled) { m_tileTabsEnabled = tileTabsEnabled; } /** * @return The selected tile tabs configuration. * This will be the automatic configuration when automatic is selected, * otherwise it is the custom configuration. */ TileTabsConfiguration* BrowserWindowContent::getSelectedTileTabsConfiguration() { TileTabsConfiguration* configMode = NULL; switch (m_tileTabsConfigurationMode) { case TileTabsGridModeEnum::AUTOMATIC: configMode = m_automaticTileTabsConfiguration.get(); break; case TileTabsGridModeEnum::CUSTOM: configMode = m_customTileTabsConfiguration.get(); break; } CaretAssert(configMode); return configMode; } /** * @return The selected tile tabs configuration (const method) * This will be the automatic configuration when automatic is selected, * otherwise it is the custom configuration. */ const TileTabsConfiguration* BrowserWindowContent::getSelectedTileTabsConfiguration() const { TileTabsConfiguration* configMode = NULL; switch (m_tileTabsConfigurationMode) { case TileTabsGridModeEnum::AUTOMATIC: configMode = m_automaticTileTabsConfiguration.get(); break; case TileTabsGridModeEnum::CUSTOM: configMode = m_customTileTabsConfiguration.get(); break; } CaretAssert(configMode); return configMode; } /** * @return The automatic tile tabs configuration. */ TileTabsConfiguration* BrowserWindowContent::getAutomaticTileTabsConfiguration() { return m_automaticTileTabsConfiguration.get(); } /** * @return The automatic tile tabs configuration (const method) */ const TileTabsConfiguration* BrowserWindowContent::getAutomaticTileTabsConfiguration() const { return m_automaticTileTabsConfiguration.get(); } /** * @return The custom tile tabs configuration */ TileTabsConfiguration* BrowserWindowContent::getCustomTileTabsConfiguration() { return m_customTileTabsConfiguration.get(); } /** * @return The custom tile tabs configuration (const method) */ const TileTabsConfiguration* BrowserWindowContent::getCustomTileTabsConfiguration() const { return m_customTileTabsConfiguration.get(); } /** * @return The tile tabs configuration mode. */ TileTabsGridModeEnum::Enum BrowserWindowContent::getTileTabsConfigurationMode() const { return m_tileTabsConfigurationMode; } /** * Set the tile tabs configuration mode. * * @param configMode * New value for configuration mode. */ void BrowserWindowContent::setTileTabsConfigurationMode(const TileTabsGridModeEnum::Enum configMode) { m_tileTabsConfigurationMode = configMode; } /** * @return Width of the graphics region from scene. */ int32_t BrowserWindowContent::getSceneGraphicsWidth() const { return m_sceneGraphicsWidth; } /** * Set the width of the graphics region for scene. * * @param width * New value for width. */ void BrowserWindowContent::setSceneGraphicsWidth(const int32_t width) { m_sceneGraphicsWidth = width; } /** * @return Height of the graphics region from scene. */ int32_t BrowserWindowContent::getSceneGraphicsHeight() const { return m_sceneGraphicsHeight; } /** * Set the height of the graphics region for scene. * * @param height * New value for height. */ void BrowserWindowContent::setSceneGraphicsHeight(const int32_t height) { m_sceneGraphicsHeight = height; } /** * @return Index of the selected tab in the scene. */ int32_t BrowserWindowContent::getSceneSelectedTabIndex() const { return m_sceneSelectedTabIndex; } /** * Set index of the selected tab in the scene. * * @param selectedTabIndex * Index of selected tab. */ void BrowserWindowContent::setSceneSelectedTabIndex(const int32_t selectedTabIndex) { m_sceneSelectedTabIndex = selectedTabIndex; } /** * @return Indices of the tabs in the scene. * In single tab view, this returns one index that is the same as getSceneSelectedTabIndex(). * In tile tabs view, this contains all tabs in the window. */ std::vector BrowserWindowContent::getSceneTabIndices() const { return m_sceneTabIndices; } /** * Set indices of the tabs in the scene. * In single tab view, this contains one index that the displayed tab. * In tile tabs view, this contains all tabs in the window. * * @param sceneTabIndices * Indices of the tabs. */ void BrowserWindowContent::setSceneWindowTabIndices(const std::vector& sceneTabIndices) { m_sceneTabIndices = sceneTabIndices; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* BrowserWindowContent::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { /* * Version 2 added by WB-735 in May 2018 */ SceneClass* sceneClass = new SceneClass(instanceName, "BrowserWindowContent", 2); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); sceneClass->addString("m_customTileTabsConfigurationLatest", m_customTileTabsConfiguration->encodeInXML()); /* * Add a tile tabs version one so older versions of wb_view * may still load the scene correctly */ sceneClass->addString("m_customTileTabsConfiguration", m_customTileTabsConfiguration->encodeVersionInXML(1)); /* * Write the tile tabs configuration a second time using * the old name 'm_sceneTileTabsConfiguration'. This will * allow the previous version of Workbench to display * tile tabs correctly. */ sceneClass->addString("m_sceneTileTabsConfiguration", m_customTileTabsConfiguration->encodeVersionInXML(1)); sceneClass->addChild(new SceneIntegerArray("m_sceneTabIndices", m_sceneTabIndices)); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void BrowserWindowContent::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { reset(); if (sceneClass == NULL) { return; } const int32_t sceneVersion = sceneClass->getVersionNumber(); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); const ScenePrimitiveArray* sceneTabIndicesArray = sceneClass->getPrimitiveArray("m_sceneTabIndices"); if (sceneTabIndicesArray != NULL) { sceneTabIndicesArray->integerVectorValues(m_sceneTabIndices); } /* * Try restoring newest tile tabs configuration */ AString tileTabsConfig = sceneClass->getStringValue("m_customTileTabsConfigurationLatest"); if ( ! tileTabsConfig.isEmpty()) { /* Since latest was found, restore, but do not use, older configuration to prevent 'not found' warning */ sceneClass->getStringValue("m_customTileTabsConfiguration"); } if (tileTabsConfig.isEmpty()) { /* Try version one */ tileTabsConfig = sceneClass->getStringValue("m_customTileTabsConfiguration"); } if (tileTabsConfig.isEmpty()) { /* Restore an old name for custom configuration */ tileTabsConfig = sceneClass->getStringValue("m_tileTabsConfiguration"); } if ( ! tileTabsConfig.isEmpty()) { AString errorMessage; const bool valid = m_customTileTabsConfiguration->decodeFromXML(tileTabsConfig, errorMessage); if ( ! valid) { sceneAttributes->addToErrorMessage("Failed to decode custom tile tabs configuration with error \"" + errorMessage + "\" from BrowserWindowContent: \"" + tileTabsConfig + "\""); m_customTileTabsConfiguration.reset(new TileTabsConfiguration()); } /* * This statement is here to prevent a warning about an unrestored element. * When the scene is written after WB-735, 'm_sceneTileTabsConfiguration' is written in * addition to 'm_tileTabsConfiguration' to be compatible with wb_view * versions before before WB-735. */ (void)sceneClass->getStringValue("m_sceneTileTabsConfiguration"); } else { /* * "m_sceneTileTabsConfiguration" is from scenes before "m_customTileTabsConfiguration" was added */ const AString stringTileTabsConfig = sceneClass->getStringValue("m_sceneTileTabsConfiguration"); if ( ! stringTileTabsConfig.isEmpty()) { AString errorMessage; const bool valid = m_customTileTabsConfiguration->decodeFromXML(stringTileTabsConfig, errorMessage); if ( ! valid) { sceneAttributes->addToErrorMessage("Failed to decode custom tile tabs configuration with error \"" + errorMessage + "\" from BrowserWindowContent: \"" + stringTileTabsConfig + "\""); m_customTileTabsConfiguration.reset(new TileTabsConfiguration()); } } } const ScenePrimitive* oldTileTabsAutoPrimitive = sceneClass->getPrimitive("m_tileTabsAutomaticConfigurationEnabled"); if (oldTileTabsAutoPrimitive != NULL) { const bool autoModeSelected = oldTileTabsAutoPrimitive->booleanValue(); if (autoModeSelected) { m_tileTabsConfigurationMode = TileTabsGridModeEnum::AUTOMATIC; } else { m_tileTabsConfigurationMode = TileTabsGridModeEnum::CUSTOM; } } if (sceneVersion < 2) { /* * Automatic configuration added by WB-735 in May 2018 * If tile tabs was enabled, use CUSTOM, otherwise AUTOMATIC */ if (m_tileTabsEnabled) { m_tileTabsConfigurationMode = TileTabsGridModeEnum::CUSTOM; } else { m_tileTabsConfigurationMode = TileTabsGridModeEnum::AUTOMATIC; } } //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } /** * Restore from BrainBrowserWindow scene from before this class was created. * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param browserClass * A BrainBrowserWindow scene. */ void BrowserWindowContent::restoreFromOldBrainBrowserWindowScene(const SceneAttributes* sceneAttributes, const SceneClass* browserClass) { CaretAssert(browserClass); reset(); if (browserClass->getName() != "m_brainBrowserWindows") { sceneAttributes->addToErrorMessage("When restoring BrowserWindowContent::restoreFromOldBrainBrowserWindowScene " "name of scene class is not m_brainBrowserWindows"); return; } m_windowAspectRatioLocked = browserClass->getBooleanValue("m_windowAspectRatioLockedAction", false); m_windowAspectLockedRatio = browserClass->getFloatValue("m_aspectRatio", 1.0f); /* not in old scene */ m_allTabsInWindowAspectRatioLocked = false; m_tileTabsEnabled = browserClass->getBooleanValue("m_viewTileTabsAction", false); const SceneClass* graphicsGeometry = browserClass->getClass("openGLWidgetGeometry"); if (graphicsGeometry != NULL) { m_sceneGraphicsWidth = graphicsGeometry->getIntegerValue("geometryWidth", -1); m_sceneGraphicsHeight = graphicsGeometry->getIntegerValue("geometryHeight", -1); } const AString tileTabsConfigString = browserClass->getStringValue("m_sceneTileTabsConfiguration"); if ( ! tileTabsConfigString.isEmpty()) { AString errorMessage; const bool valid = m_customTileTabsConfiguration->decodeFromXML(tileTabsConfigString, errorMessage); if ( ! valid) { sceneAttributes->addToErrorMessage("Failed to decode custom tile tabs configuration with error \"" + errorMessage + "\" from OLD BrowserWindowContent: \"" + tileTabsConfigString + "\""); m_customTileTabsConfiguration.reset(new TileTabsConfiguration()); } } const SceneClass* toolbarClass = browserClass->getClass("m_toolbar"); if (toolbarClass != NULL) { m_sceneSelectedTabIndex = toolbarClass->getIntegerValue("selectedTabIndex", -1); const ScenePrimitiveArray* tabIndexArray = toolbarClass->getPrimitiveArray("tabIndices"); if (tabIndexArray != NULL) { const int32_t numTabs = tabIndexArray->getNumberOfArrayElements(); for (auto iTab = 0; iTab < numTabs; iTab++) { m_sceneTabIndices.push_back(tabIndexArray->integerValue(iTab)); } } } /* * Automatic configuration added by WB-735 in May 2018 * If tile tabs was enabled, use CUSTOM, otherwise AUTOMATIC */ if (m_tileTabsEnabled) { m_tileTabsConfigurationMode = TileTabsGridModeEnum::CUSTOM; } else { m_tileTabsConfigurationMode = TileTabsGridModeEnum::AUTOMATIC; } } connectome-workbench-1.4.2/src/Brain/BrowserWindowContent.h000066400000000000000000000127401360521144700240000ustar00rootroot00000000000000#ifndef __BROWSER_WINDOW_CONTENT_H__ #define __BROWSER_WINDOW_CONTENT_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "SceneableInterface.h" #include "TileTabsGridModeEnum.h" namespace caret { class SceneClassAssistant; class TileTabsConfiguration; class BrowserWindowContent : public CaretObject, public SceneableInterface { public: BrowserWindowContent(const int32_t windowIndex); virtual ~BrowserWindowContent(); int32_t getWindowIndex() const; bool isValid() const; void setValid(const bool valid); void reset(); bool isWindowAspectLocked() const; void setWindowAspectLocked(const bool lockedStatus); float getWindowAspectLockedRatio() const; void setWindowAspectLockedRatio(const float aspectRatio); bool isAllTabsInWindowAspectRatioLocked() const; void setAllTabsInWindowAspectRatioLocked(const bool lockedStatus); bool isTileTabsEnabled() const; void setTileTabsEnabled(const bool tileTabsEnabled); TileTabsConfiguration* getSelectedTileTabsConfiguration(); const TileTabsConfiguration* getSelectedTileTabsConfiguration() const; TileTabsConfiguration* getAutomaticTileTabsConfiguration(); const TileTabsConfiguration* getAutomaticTileTabsConfiguration() const; TileTabsConfiguration* getCustomTileTabsConfiguration(); const TileTabsConfiguration* getCustomTileTabsConfiguration() const; TileTabsGridModeEnum::Enum getTileTabsConfigurationMode() const; void setTileTabsConfigurationMode(const TileTabsGridModeEnum::Enum configMode); int32_t getSceneGraphicsWidth() const; void setSceneGraphicsWidth(const int32_t width); int32_t getSceneGraphicsHeight() const; void setSceneGraphicsHeight(const int32_t width); int32_t getSceneSelectedTabIndex() const; void setSceneSelectedTabIndex(const int32_t selectedTabIndex); std::vector getSceneTabIndices() const; void setSceneWindowTabIndices(const std::vector& sceneTabIndices); // ADD_NEW_METHODS_HERE virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); void restoreFromOldBrainBrowserWindowScene(const SceneAttributes* sceneAttributes, const SceneClass* browserClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implementation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: BrowserWindowContent(const BrowserWindowContent&); BrowserWindowContent& operator=(const BrowserWindowContent&); std::unique_ptr m_sceneAssistant; bool m_validFlag; const int32_t m_windowIndex; bool m_windowAspectRatioLocked = false; float m_windowAspectLockedRatio = 1.0f; bool m_allTabsInWindowAspectRatioLocked = false; bool m_tileTabsEnabled = false; TileTabsGridModeEnum::Enum m_tileTabsConfigurationMode = TileTabsGridModeEnum::AUTOMATIC; int32_t m_sceneGraphicsWidth = 0; int32_t m_sceneGraphicsHeight = 0; std::unique_ptr m_automaticTileTabsConfiguration; std::unique_ptr m_customTileTabsConfiguration; int32_t m_sceneSelectedTabIndex = 0; std::vector m_sceneTabIndices; friend class BrainBrowserWindow; // ADD_NEW_MEMBERS_HERE }; #ifdef __BROWSER_WINDOW_CONTENT_DECLARE__ #endif // __BROWSER_WINDOW_CONTENT_DECLARE__ } // namespace #endif //__BROWSER_WINDOW_CONTENT_H__ connectome-workbench-1.4.2/src/Brain/CMakeLists.txt000066400000000000000000000234641360521144700222260ustar00rootroot00000000000000# # Name of project # PROJECT (Brain) # # Need XML from Qt # SET(QT_DONT_USE_QTGUI) # # Add QT for includes # if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) include_directories(${Qt5Network_INCLUDE_DIRS}) include_directories(${Qt5Gui_INCLUDE_DIRS}) endif() IF (QT4_FOUND) SET(QT_USE_QTNETWORK TRUE) INCLUDE(${QT_USE_FILE}) ENDIF () # # Create the brain library # ADD_LIBRARY(Brain AnnotationArrangerExecutor.h AnnotationArrangerInputs.h AnnotationManager.h BorderDrawingTypeEnum.h Brain.h BrainOpenGL.h BrainOpenGLAnnotationDrawingFixedPipeline.h BrainOpenGLChartDrawingInterface.h BrainOpenGLChartDrawingFixedPipeline.h BrainOpenGLChartTwoDrawingFixedPipeline.h BrainOpenGLChartTwoDrawingInterface.h BrainOpenGLFixedPipeline.h BrainOpenGLPrimitiveDrawing.h BrainOpenGLShape.h BrainOpenGLShapeCone.h BrainOpenGLShapeCube.h BrainOpenGLShapeCylinder.h BrainOpenGLShapeRing.h BrainOpenGLShapeSphere.h BrainOpenGLTextRenderInterface.h BrainOpenGLViewportContent.h BrainOpenGLVolumeObliqueSliceDrawing.h BrainOpenGLVolumeSliceDrawing.h BrainOpenGLVolumeTextureSliceDrawing.h BrainOpenGLWindowContent.h BrainStructure.h BrainStructureNodeAttributes.h BrowserTabContent.h BrowserWindowContent.h ChartTwoOverlay.h ChartTwoOverlaySet.h ChartTwoOverlaySetArray.h ChartingDataManager.h CiftiConnectivityMatrixDataFileManager.h CiftiFiberTrajectoryManager.h ClippingPlaneGroup.h DataToolTipsManager.h DisplayProperties.h DisplayPropertiesAnnotation.h DisplayPropertiesAnnotationTextSubstitution.h DisplayPropertiesBorders.h DisplayPropertiesFiberOrientation.h DisplayPropertiesFoci.h DisplayPropertiesImages.h DisplayPropertiesLabels.h DisplayPropertiesSurface.h DisplayPropertiesVolume.h DisplayPropertyDataBoolean.h DisplayPropertyDataEnum.h DisplayPropertyDataFloat.h DummyFontTextRenderer.h EventAnnotationColorBarGet.h EventBrainReset.h EventBrainStructureGetAll.h EventBrowserTabGet.h EventBrowserTabGetAll.h EventBrowserTabGetAllViewed.h EventBrowserWindowContent.h EventCaretMappableDataFilesAndMapsInDisplayedOverlays.h EventChartOverlayValidate.h EventDataFileAdd.h EventDataFileDelete.h EventDataFileRead.h EventDataFileReload.h EventGetBrainOpenGLTextRenderer.h EventIdentificationHighlightLocation.h EventModelAdd.h EventModelDelete.h EventModelGetAll.h EventModelGetAllDisplayed.h EventModelSurfaceGet.h EventNodeDataFilesGet.h EventNodeIdentificationColorsGetFromCharts.h EventOverlayValidate.h EventSceneActive.h EventSpacerTabGet.h EventSpecFileReadDataFiles.h EventSurfacesGet.h FeatureColoringTypeEnum.h FiberOrientationSamplesLoader.h FiberOrientationSamplesVector.h FiberOrientationSymbolTypeEnum.h FociDrawingTypeEnum.h FtglFontTextRenderer.h GapsAndMargins.h IdentificationManager.h IdentificationStringBuilder.h IdentificationTextGenerator.h IdentificationWithColor.h IdentifiedItem.h IdentifiedItemNode.h IdentifiedItemVoxel.h ImageDepthPositionEnum.h Model.h ModelChart.h ModelChartTwo.h ModelSurface.h ModelSurfaceMontage.h ModelSurfaceSelector.h ModelTypeEnum.h ModelVolume.h ModelWholeBrain.h MovieRecorder.h MovieRecorderCaptureRegionTypeEnum.h MovieRecorderModeEnum.h MovieRecorderVideoFormatTypeEnum.h MovieRecorderVideoResolutionTypeEnum.h Overlay.h OverlaySet.h OverlaySetArray.h ProjectionViewTypeEnum.h SelectionItemDataTypeEnum.h SelectionItem.h SelectionItemAnnotation.h SelectionItemBorderSurface.h SelectionItemChartDataSeries.h SelectionItemChartFrequencySeries.h SelectionItemChartMatrix.h SelectionItemChartTimeSeries.h SelectionItemChartTwoHistogram.h SelectionItemChartTwoLabel.h SelectionItemChartTwoLineSeries.h SelectionItemChartTwoMatrix.h SelectionItemCiftiConnectivityMatrixRowColumn.h SelectionItemFocusSurface.h SelectionItemFocusVolume.h SelectionItemImage.h SelectionItemImageControlPoint.h SelectionItemSurfaceNode.h SelectionItemSurfaceNodeIdentificationSymbol.h SelectionItemSurfaceTriangle.h SelectionItemVoxel.h SelectionItemVoxelEditing.h SelectionItemVoxelIdentificationSymbol.h SelectionManager.h SessionManager.h SpacerTabContent.h Surface.h SurfaceDrawingTypeEnum.h SurfaceMontageConfigurationAbstract.h SurfaceMontageConfigurationCerebellar.h SurfaceMontageConfigurationCerebral.h SurfaceMontageConfigurationTypeEnum.h SurfaceMontageConfigurationFlatMaps.h SurfaceMontageLayoutOrientationEnum.h SurfaceMontageViewport.h SurfaceNodeColoring.h SurfaceSelectionModel.h TabContentBase.h UserInputModeEnum.h ViewingTransformations.h ViewingTransformationsCerebellum.h ViewingTransformationsVolume.h VolumeSliceDrawingTypeEnum.h VolumeSliceInterpolationEdgeEffectsMaskingEnum.h VolumeSliceSettings.h VolumeSurfaceOutlineColorOrTabModel.h VolumeSurfaceOutlineModel.h VolumeSurfaceOutlineModelCacheKey.h VolumeSurfaceOutlineModelCacheValue.h VolumeSurfaceOutlineSetModel.h WholeBrainSurfaceSettings.h WholeBrainVoxelDrawingMode.h AnnotationArrangerExecutor.cxx AnnotationArrangerInputs.cxx AnnotationManager.cxx BorderDrawingTypeEnum.cxx Brain.cxx BrainOpenGL.cxx BrainOpenGLAnnotationDrawingFixedPipeline.cxx BrainOpenGLChartDrawingFixedPipeline.cxx BrainOpenGLChartTwoDrawingFixedPipeline.cxx BrainOpenGLFixedPipeline.cxx BrainOpenGLPrimitiveDrawing.cxx BrainOpenGLShape.cxx BrainOpenGLShapeCone.cxx BrainOpenGLShapeCube.cxx BrainOpenGLShapeCylinder.cxx BrainOpenGLShapeRing.cxx BrainOpenGLShapeSphere.cxx BrainOpenGLTextRenderInterface.cxx BrainOpenGLViewportContent.cxx BrainOpenGLVolumeObliqueSliceDrawing.cxx BrainOpenGLVolumeSliceDrawing.cxx BrainOpenGLVolumeTextureSliceDrawing.cxx BrainOpenGLWindowContent.cxx BrainStructure.cxx BrainStructureNodeAttributes.cxx BrowserTabContent.cxx BrowserWindowContent.cxx ChartTwoOverlay.cxx ChartTwoOverlaySet.cxx ChartTwoOverlaySetArray.cxx ChartingDataManager.cxx CiftiConnectivityMatrixDataFileManager.cxx CiftiFiberTrajectoryManager.cxx ClippingPlaneGroup.cxx DataToolTipsManager.cxx DisplayProperties.cxx DisplayPropertiesAnnotation.cxx DisplayPropertiesAnnotationTextSubstitution.cxx DisplayPropertiesBorders.cxx DisplayPropertiesFiberOrientation.cxx DisplayPropertiesFoci.cxx DisplayPropertiesImages.cxx DisplayPropertiesLabels.cxx DisplayPropertiesSurface.cxx DisplayPropertiesVolume.cxx DisplayPropertyDataBoolean.cxx DisplayPropertyDataFloat.cxx DummyFontTextRenderer.cxx EventAnnotationColorBarGet.cxx EventBrainReset.cxx EventBrainStructureGetAll.cxx EventBrowserTabGet.cxx EventBrowserTabGetAll.cxx EventBrowserTabGetAllViewed.cxx EventBrowserWindowContent.cxx EventCaretMappableDataFilesAndMapsInDisplayedOverlays.cxx EventChartOverlayValidate.cxx EventDataFileAdd.cxx EventDataFileDelete.cxx EventDataFileRead.cxx EventDataFileReload.cxx EventGetBrainOpenGLTextRenderer.cxx EventIdentificationHighlightLocation.cxx EventModelAdd.cxx EventModelDelete.cxx EventModelGetAll.cxx EventModelGetAllDisplayed.cxx EventModelSurfaceGet.cxx EventNodeDataFilesGet.cxx EventNodeIdentificationColorsGetFromCharts.cxx EventOverlayValidate.cxx EventSceneActive.cxx EventSpacerTabGet.cxx EventSpecFileReadDataFiles.cxx EventSurfacesGet.cxx FeatureColoringTypeEnum.cxx FiberOrientationSamplesLoader.cxx FiberOrientationSymbolTypeEnum.cxx FociDrawingTypeEnum.cxx FtglFontTextRenderer.cxx GapsAndMargins.cxx IdentificationManager.cxx IdentificationStringBuilder.cxx IdentificationTextGenerator.cxx IdentificationWithColor.cxx IdentifiedItem.cxx IdentifiedItemNode.cxx IdentifiedItemVoxel.cxx ImageDepthPositionEnum.cxx Model.cxx ModelChart.cxx ModelChartTwo.cxx ModelSurface.cxx ModelSurfaceMontage.cxx ModelSurfaceSelector.cxx ModelTypeEnum.cxx ModelVolume.cxx ModelWholeBrain.cxx MovieRecorder.cxx MovieRecorderCaptureRegionTypeEnum.cxx MovieRecorderModeEnum.cxx MovieRecorderVideoFormatTypeEnum.cxx MovieRecorderVideoResolutionTypeEnum.cxx Overlay.cxx OverlaySet.cxx OverlaySetArray.cxx ProjectionViewTypeEnum.cxx SelectionItemDataTypeEnum.cxx SelectionItem.cxx SelectionItemAnnotation.cxx SelectionItemBorderSurface.cxx SelectionItemChartDataSeries.cxx SelectionItemChartFrequencySeries.cxx SelectionItemChartMatrix.cxx SelectionItemChartTimeSeries.cxx SelectionItemChartTwoHistogram.cxx SelectionItemChartTwoLabel.cxx SelectionItemChartTwoLineSeries.cxx SelectionItemChartTwoMatrix.cxx SelectionItemCiftiConnectivityMatrixRowColumn.cxx SelectionItemFocusSurface.cxx SelectionItemFocusVolume.cxx SelectionItemImage.cxx SelectionItemImageControlPoint.cxx SelectionItemSurfaceNode.cxx SelectionItemSurfaceNodeIdentificationSymbol.cxx SelectionItemSurfaceTriangle.cxx SelectionItemVoxel.cxx SelectionItemVoxelIdentificationSymbol.cxx SelectionItemVoxelEditing.cxx SelectionManager.cxx SessionManager.cxx SpacerTabContent.cxx Surface.cxx SurfaceDrawingTypeEnum.cxx SurfaceMontageConfigurationAbstract.cxx SurfaceMontageConfigurationCerebellar.cxx SurfaceMontageConfigurationCerebral.cxx SurfaceMontageConfigurationTypeEnum.cxx SurfaceMontageConfigurationFlatMaps.cxx SurfaceMontageLayoutOrientationEnum.cxx SurfaceMontageViewport.cxx SurfaceNodeColoring.cxx SurfaceSelectionModel.cxx TabContentBase.cxx UserInputModeEnum.cxx ViewingTransformations.cxx ViewingTransformationsCerebellum.cxx ViewingTransformationsVolume.cxx VolumeSliceDrawingTypeEnum.cxx VolumeSliceInterpolationEdgeEffectsMaskingEnum.cxx VolumeSliceSettings.cxx VolumeSurfaceOutlineColorOrTabModel.cxx VolumeSurfaceOutlineModel.cxx VolumeSurfaceOutlineModelCacheKey.cxx VolumeSurfaceOutlineModelCacheValue.cxx VolumeSurfaceOutlineSetModel.cxx WholeBrainSurfaceSettings.cxx WholeBrainVoxelDrawingMode.cxx ) TARGET_LINK_LIBRARIES(Brain ${CARET_QT5_LINK}) # # Find Headers # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Annotations ${CMAKE_SOURCE_DIR}/Brain ${CMAKE_SOURCE_DIR}/Charting ${CMAKE_SOURCE_DIR}/Cifti ${CMAKE_SOURCE_DIR}/FilesBase ${CMAKE_SOURCE_DIR}/Files ${CMAKE_SOURCE_DIR}/Graphics ${CMAKE_SOURCE_DIR}/Palette ${CMAKE_SOURCE_DIR}/Gifti ${CMAKE_SOURCE_DIR}/Nifti ${CMAKE_SOURCE_DIR}/QxtCore ${CMAKE_SOURCE_DIR}/Scenes ${CMAKE_SOURCE_DIR}/Xml ${CMAKE_SOURCE_DIR}/Common ) IF (FREETYPE_FOUND) INCLUDE_DIRECTORIES( ${FTGL_INCLUDE_DIRS} ${FREETYPE_INCLUDE_DIR_ft2build} ${FREETYPE_INCLUDE_DIR_freetype2} ) ENDIF (FREETYPE_FOUND) connectome-workbench-1.4.2/src/Brain/ChartTwoOverlay.cxx000066400000000000000000001625661360521144700233160ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_TWO_OVERLAY_DECLARE__ #include "ChartTwoOverlay.h" #undef __CHART_TWO_OVERLAY_DECLARE__ #include "AnnotationColorBar.h" #include "BoundingBox.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretMappableDataFile.h" #include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileHistogramChart.h" #include "ChartableTwoFileLineSeriesChart.h" #include "ChartableTwoFileMatrixChart.h" #include "ChartTwoLineSeriesHistory.h" #include "ChartTwoOverlaySet.h" #include "EventCaretMappableDataFilesGet.h" #include "EventChartOverlayValidate.h" #include "EventManager.h" #include "Histogram.h" #include "PlainTextStringBuilder.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ChartTwoOverlay * \brief Overlay for charts. * \ingroup Brain */ /** * Constructor. * * @param parentChartTwoOverlaySet * Parent of this chart overlay set. * @param chartDataType * Type of charts allowed in this overlay * @param overlayIndex * Index of this overlay. */ ChartTwoOverlay::ChartTwoOverlay(ChartTwoOverlaySet* parentChartTwoOverlaySet, const ChartTwoDataTypeEnum::Enum chartDataType, const int32_t tabIndex, const int32_t overlayIndex) : CaretObject(), m_parentChartTwoOverlaySet(parentChartTwoOverlaySet), m_chartDataType(chartDataType), m_tabIndex(tabIndex), m_overlayIndex(overlayIndex) { CaretAssert(m_parentChartTwoOverlaySet); m_name = "Overlay " + AString::number(overlayIndex + 1); m_enabled = (m_overlayIndex == 0); m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; m_colorBar = std::unique_ptr(new AnnotationColorBar(AnnotationAttributesDefaultTypeEnum::NORMAL)); m_colorBar->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); m_matrixTriangularViewingMode = ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL; m_cartesianVerticalAxisLocation = ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT; m_selectedMapFile = NULL; m_selectedHistogramMapIndex = -1; m_allHistogramMapsSelectedFlag = false; m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); m_sceneAssistant->add("m_enabled", &m_enabled); m_sceneAssistant->add("m_mapYokingGroup", &m_mapYokingGroup); m_sceneAssistant->add("m_colorBar", "AnnotationColorBar", m_colorBar.get()); m_sceneAssistant->add("m_matrixTriangularViewingMode", &m_matrixTriangularViewingMode); m_sceneAssistant->add("m_cartesianVerticalAxisLocation", &m_cartesianVerticalAxisLocation); m_sceneAssistant->add("m_selectedHistogramMapIndex", &m_selectedHistogramMapIndex); m_sceneAssistant->add("m_allHistogramMapsSelectedFlag", &m_allHistogramMapsSelectedFlag); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CHART_OVERLAY_VALIDATE); } /** * Destructor. */ ChartTwoOverlay::~ChartTwoOverlay() { EventManager::get()->removeAllEventsFromListener(this); } /** * @return Weak pointer to instance. * This weak pointer stored by classes (such as those in the GUI) * safely test if an instance is still valid and can be safely accessed. */ std::weak_ptr ChartTwoOverlay::getWeakPointerToSelf() { return m_weakPointerToSelf; } /** * Set the weak pointer for this instance. * This is called by the parent ChartTwoOverlaySet. * * @param weakPointerToSelf * Weak pointer to this instance. */ void ChartTwoOverlay::setWeakPointerToSelf(std::weak_ptr weakPointerToSelf) { m_weakPointerToSelf = weakPointerToSelf; CaretAssert( ! m_weakPointerToSelf.expired()); CaretAssert(m_weakPointerToSelf.lock().get() == this); } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void ChartTwoOverlay::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_CHART_OVERLAY_VALIDATE) { EventChartOverlayValidate* eov = dynamic_cast(event); CaretAssert(eov); eov->testValidChartOverlay(this); eov->setEventProcessed(); } } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ChartTwoOverlay::toString() const { PlainTextStringBuilder tb; getDescriptionOfContent(tb); return tb.getText(); } /** * Get a text description of the window's content. * * @param descriptionOut * Description of the window's content. */ void ChartTwoOverlay::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const { ChartTwoOverlay* me = const_cast(this); if (me != NULL) { if (me->isEnabled()) { CaretMappableDataFile* mapFile = NULL; SelectedIndexType indexType = SelectedIndexType::INVALID; int32_t index = 0; me->getSelectionData(mapFile, indexType, index); if (mapFile != NULL) { descriptionOut.addLine("Overlay Index: " + AString::number(m_overlayIndex)); descriptionOut.addLine("File: "+ mapFile->getFileNameNoPath()); if (mapFile->hasMapAttributes()) { switch (indexType) { case SelectedIndexType::INVALID: break; case SelectedIndexType::COLUMN: descriptionOut.addLine("Column " + AString::number(index)); break; case SelectedIndexType::MAP: if ((index >= 0) && (index < mapFile->getNumberOfMaps())) { descriptionOut.addLine("Map Index: " + AString::number(index + 1)); descriptionOut.addLine("Map Name: " + mapFile->getMapName(index)); } break; case SelectedIndexType::ROW: descriptionOut.addLine("Row " + AString::number(index)); break; } } const ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); ChartTwoCompoundDataType cdt; chartDelegate->getChartTwoCompoundDataTypeForChartTwoDataType(getChartTwoDataType(), cdt); descriptionOut.addLine(cdt.toString()); } } } } /** * @return The chart data type for this chart overlay. */ ChartTwoDataTypeEnum::Enum ChartTwoOverlay::getChartTwoDataType() const { return m_chartDataType; } /** * Get the chart compound data type */ ChartTwoCompoundDataType ChartTwoOverlay::getChartTwoCompoundDataType() const { return m_chartCompoundDataType; } /** * Set the compound chart type for charts displayed in this overlay. * MUST match simplae data type for this chart unless invalid. * Note that overlay index zero, allows any chart type. * * @param chartCompoundDataType * Type of charts for display in this overlay. */ void ChartTwoOverlay::setChartTwoCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) { if (m_overlayIndex == 0) { CaretAssertMessage(0, "ChartTwoOverlay::setChartTwoCompoundDataType() should not be called " " for first overlay"); return; } // do for overlay zero ?? if (chartCompoundDataType.getChartTwoDataType() != ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID) { CaretAssert(m_chartDataType == chartCompoundDataType.getChartTwoDataType()); } m_chartCompoundDataType = chartCompoundDataType; } /** * @return The tab index. */ int32_t ChartTwoOverlay::getTabIndex() const { return m_tabIndex; } /** * @return Enabled status for this surface overlay. */ bool ChartTwoOverlay::isEnabled() const { return m_enabled; } /** * Set the enabled status for this surface overlay. * @param enabled * New status. */ void ChartTwoOverlay::setEnabled(const bool enabled) { m_enabled = enabled; } /** * @return line-series loading enabled */ bool ChartTwoOverlay::isLineSeriesLoadingEnabled() const { CaretMappableDataFile* mapFile = NULL; SelectedIndexType indexType = SelectedIndexType::INVALID; int32_t mapIndex = -1; getSelectionData(mapFile, indexType, mapIndex); const ChartableTwoFileLineSeriesChart* lineSeriesChart = mapFile->getChartingDelegate()->getLineSeriesCharting(); const ChartTwoLineSeriesHistory* lineSeriesHistory = lineSeriesChart->getHistory(); return lineSeriesHistory->isLoadingEnabled(); } /** * Set line-series loading enabled * * @param lineSeriesLoadingEnabled * New value for line-series loading enabled */ void ChartTwoOverlay::setLineSeriesLoadingEnabled(const bool lineSeriesLoadingEnabled) { CaretMappableDataFile* mapFile = NULL; SelectedIndexType indexType = SelectedIndexType::INVALID; int32_t mapIndex = -1; getSelectionData(mapFile, indexType, mapIndex); ChartableTwoFileLineSeriesChart* lineSeriesChart = mapFile->getChartingDelegate()->getLineSeriesCharting(); ChartTwoLineSeriesHistory* lineSeriesHistory = lineSeriesChart->getHistory(); lineSeriesHistory->setLoadingEnabled(lineSeriesLoadingEnabled); } /** * Copy the data from the given overlay to this overlay. * @param overlay * Overlay from which data is transferred. */ void ChartTwoOverlay::copyData(const ChartTwoOverlay* overlay) { CaretAssert(overlay); /* * These members are not copied since they * identify the overlay: * m_parentChartTwoOverlaySet * m_name * m_overlayIndex * */ m_enabled = overlay->m_enabled; m_mapYokingGroup = overlay->m_mapYokingGroup; *m_colorBar = *overlay->m_colorBar; m_matrixTriangularViewingMode = overlay->m_matrixTriangularViewingMode; m_cartesianVerticalAxisLocation = overlay->m_cartesianVerticalAxisLocation; m_selectedMapFile = overlay->m_selectedMapFile; m_selectedHistogramMapIndex = overlay->m_selectedHistogramMapIndex; m_allHistogramMapsSelectedFlag = overlay->m_allHistogramMapsSelectedFlag; } /** * Swap my data with data from the given overlay. * @param overlay * Overlay from which data is swapped. */ void ChartTwoOverlay::swapData(ChartTwoOverlay* overlay) { std::unique_ptr swapOverlay = std::unique_ptr(new ChartTwoOverlay(m_parentChartTwoOverlaySet, overlay->m_chartDataType, overlay->m_tabIndex, overlay->m_overlayIndex)); swapOverlay->copyData(overlay); overlay->copyData(this); copyData(swapOverlay.get()); } /** * Is history supported ? */ bool ChartTwoOverlay::isHistorySupported() const { bool supportedFlag = false; switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: supportedFlag = true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; } return supportedFlag; } /** * @return Is map yoking supported ? * * NOTE: Within this class, do not use this method. * Instead, use isMapYokingSupportedPrivate(). */ bool ChartTwoOverlay::isMapYokingSupported() const { CaretMappableDataFile* mapFile = NULL; SelectedIndexType indexType = SelectedIndexType::INVALID; int32_t mapIndex = -1; getSelectionData(mapFile, indexType, mapIndex); return isMapYokingSupportedPrivate(mapFile); } /** * Is map yoking supported for the given map file? * This is a private method and used within this class. * as use of the public method could cause stack * overlow by use of isMapYokingSupported() and * getSelectionData(). * * @param mapFile * The map file. A NULL value is allowed. * @return * True if map yoking is supported, else false. */ bool ChartTwoOverlay::isMapYokingSupportedPrivate(const CaretMappableDataFile* mapFile) const { if (mapFile == NULL) { return false; } if (mapFile->getNumberOfMaps() < 2) { return false; } bool supportedFlag = false; switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: if (mapFile->isSurfaceMappable() || mapFile->isVolumeMappable()) { supportedFlag = true; } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: if (mapFile->getDataFileType() == DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES) { supportedFlag = true; } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: if (mapFile->getDataFileType() == DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES) { supportedFlag = true; } break; } return supportedFlag; } /** * @return Selected map yoking group. */ MapYokingGroupEnum::Enum ChartTwoOverlay::getMapYokingGroup() const { return m_mapYokingGroup; } /** * Set the map yoking group. * * @param mapYokingGroup * New value for map yoking group. */ void ChartTwoOverlay::setMapYokingGroup(const MapYokingGroupEnum::Enum mapYokingGroup) { m_mapYokingGroup = mapYokingGroup; } /** * @return The color bar displayed in graphics window. */ AnnotationColorBar* ChartTwoOverlay::getColorBar() { return m_colorBar.get(); } /** * @return The color bar displayed in graphics window (const method). */ const AnnotationColorBar* ChartTwoOverlay::getColorBar() const { return m_colorBar.get(); } /** * Get a bounding box for data displayed within this overlay. * Bounds are provided for histogram and line-series charts only. * * @param boundingBox * Upon exit contains bounds for data within this overlay * @return * True if the bounds are valid, else false. */ bool ChartTwoOverlay::getBounds(BoundingBox& boundingBoxOut) const { boundingBoxOut.resetForUpdate(); if ( ! isEnabled()) { return false; } CaretMappableDataFile* mapFile = NULL; SelectedIndexType selectedIndexType = SelectedIndexType::INVALID; int32_t selectedIndex = -1; getSelectionData(mapFile, selectedIndexType, selectedIndex); if (mapFile == NULL) { return false; } ChartableTwoFileDelegate* chartDelegate = mapFile->getChartingDelegate(); bool validFlag = false; switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: { ChartableTwoFileHistogramChart* histogramChart = chartDelegate->getHistogramCharting(); const Histogram* histogram = histogramChart->getHistogramForChartDrawing(selectedIndex, (isAllMapsSupported() && isAllMapsSelected())); //CaretAssert(histogram); if (histogram != NULL) { float histogramMinX = 0.0, histogramMaxX = 0.0, histogramMaxY = 0.0; histogram->getRangeAndMaxDisplayHeight(histogramMinX, histogramMaxX, histogramMaxY); if (histogramMaxX > histogramMinX) { boundingBoxOut.set(histogramMinX, histogramMaxX, 0.0f, histogramMaxY, 0.0f, 0.0f); validFlag = true; } } } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: { const ChartableTwoFileLineSeriesChart* lineSeriesChart = chartDelegate->getLineSeriesCharting(); const ChartTwoLineSeriesHistory* lineSeriesHistory = lineSeriesChart->getHistory(); validFlag = lineSeriesHistory->getBounds(boundingBoxOut); } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; } return validFlag; } /** * @return The selected map file (NULL if not map file available) */ CaretMappableDataFile* ChartTwoOverlay::getSelectedMapFile() const { std::vector mapFiles; CaretMappableDataFile* selectedMapFile = NULL; SelectedIndexType selectedIndexType = SelectedIndexType::INVALID; int32_t selectedIndex = -1; getSelectionData(mapFiles, selectedMapFile, selectedIndexType, selectedIndex); return selectedMapFile; } /** * Return the selection information. This method is typically * called to update the user-interface. * * @param selectedMapFileOut * The selected map file. May be NULL. * @param selectedIndexTypeOut * Type of index selection * @param selectedIndexOut * Selected index in the selected file. */ void ChartTwoOverlay::getSelectionData(CaretMappableDataFile* &selectedMapFileOut, SelectedIndexType& selectedIndexTypeOut, int32_t& selectedIndexOut) const { std::vector mapFiles; getSelectionData(mapFiles, selectedMapFileOut, selectedIndexTypeOut, selectedIndexOut); } /** * Return the selection information. This method is typically * called to update the user-interface. * * @param mapFilesOut * Contains all map files that can be selected. * @param selectedMapFileOut * The selected map file. May be NULL. * @param selectedFileMapNamesOut * Map names from selected file. * @param selectedIndexTypeOut * Type of index selection * @param selectedIndexOut * Selected index in the selected file. */ void ChartTwoOverlay::getSelectionData(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, std::vector& selectedFileMapNamesOut, SelectedIndexType& selectedIndexTypeOut, int32_t& selectedIndexOut) const { getSelectionDataPrivate(mapFilesOut, selectedMapFileOut, &selectedFileMapNamesOut, selectedIndexTypeOut, selectedIndexOut); } /** * Return the selection information. This method is typically * called to update the user-interface. * * @param mapFilesOut * Contains all map files that can be selected. * @param selectedMapFileOut * The selected map file. May be NULL. * @param selectedIndexTypeOut * Type of index selection * @param selectedIndexOut * Selected index in the selected file. */ void ChartTwoOverlay::getSelectionData(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, SelectedIndexType& selectedIndexTypeOut, int32_t& selectedIndexOut) const { getSelectionDataPrivate(mapFilesOut, selectedMapFileOut, NULL, selectedIndexTypeOut, selectedIndexOut); } /** * Return the selection information. This method is typically * called to update the user-interface. * * @param mapFilesOut * Contains all map files that can be selected. * @param selectedMapFileOut * The selected map file. May be NULL. * @param selectedFileMapNamesOut * Optional output, if not NULL, with map names * @param selectedMapIndexOut * Index of selected map in the selected file. */ void ChartTwoOverlay::getSelectionDataPrivate(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, std::vector* selectedFileMapNamesOut, SelectedIndexType& selectedIndexTypeOut, int32_t& selectedIndexOut) const { mapFilesOut.clear(); selectedMapFileOut = NULL; selectedIndexTypeOut = SelectedIndexType::INVALID; selectedIndexOut = -1; if (selectedFileMapNamesOut != NULL) { selectedFileMapNamesOut->clear(); } /** * Get the data files. */ std::vector allDataFiles; EventCaretMappableDataFilesGet eventGetMapDataFiles; EventManager::get()->sendEvent(eventGetMapDataFiles.getPointer()); eventGetMapDataFiles.getAllFiles(allDataFiles); /* * Use only those data files that meet criteria. */ for (auto mapFile : allDataFiles) { CaretAssert(mapFile); ChartableTwoFileDelegate* chartingFile = mapFile->getChartingDelegate(); if (chartingFile->isChartingTwoSupported()) { bool useIt = false; std::vector chartCompoundDataTypes; chartingFile->getSupportedChartTwoCompoundDataTypes(chartCompoundDataTypes); for (auto& compoundType : chartCompoundDataTypes) { if (m_chartDataType == compoundType.getChartTwoDataType()) { if (m_overlayIndex == 0) { /* * The first overlay displays ALL files that match the * enumerated chart type */ useIt = true; } else { if (m_chartCompoundDataType == compoundType) { /* * If not the first overlay, the enumerated type * and dimensions must also match */ useIt = true; /* * If file is a scalar data series, and the same scalar data series file * is enabled in a "higher" chart overlay, do not show the file in this * overlay. Updated to only hide this file in disabled overlays. */ const bool enableSdsFilterFlag(false); if (enableSdsFilterFlag) { if (mapFile->getDataFileType() == DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES) { if ( ! isEnabled()) { for (int32_t io = 0; io < m_overlayIndex; io++) { const ChartTwoOverlay* otherOverlay = m_parentChartTwoOverlaySet->getOverlay(io); CaretAssert(otherOverlay); if (otherOverlay->isEnabled()) { if (otherOverlay->getSelectedMapFile() == mapFile) { useIt = false; } } } } } } } } } } if (useIt) { mapFilesOut.push_back(mapFile); } } } /* * Does selected data file still no longer exist? */ if (std::find(mapFilesOut.begin(), mapFilesOut.end(), m_selectedMapFile) == mapFilesOut.end()) { /* * Invalidate seleted file and disable yoking since * the selected file will change. */ m_selectedMapFile = NULL; m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; } /* * If no file selected, select the first valid file */ if (m_selectedMapFile == NULL) { if ( ! mapFilesOut.empty()) { for (std::vector::iterator iter = mapFilesOut.begin(); iter != mapFilesOut.end(); iter++) { CaretMappableDataFile* mapTypeFile = *iter; m_selectedMapFile = mapTypeFile; switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: m_selectedHistogramMapIndex = 0; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; } break; } } } if (m_selectedMapFile != NULL) { int32_t numMaps = 0; ChartableTwoFileMatrixChart* matrixChart = NULL; switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: { numMaps = m_selectedMapFile->getNumberOfMaps(); if (selectedFileMapNamesOut != NULL) { for (int32_t i = 0; i < numMaps; i++) { selectedFileMapNamesOut->push_back(m_selectedMapFile->getMapName(i)); } } if (m_selectedHistogramMapIndex >= numMaps) { m_selectedHistogramMapIndex = numMaps - 1; } if (m_selectedHistogramMapIndex < 0) { m_selectedHistogramMapIndex = 0; } selectedIndexTypeOut = SelectedIndexType::MAP; selectedIndexOut = m_selectedHistogramMapIndex; } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: { /* * Row/Column Scalar files use the matrix for line chart tracking */ ChartableTwoFileDelegate* chartDelegate = m_selectedMapFile->getChartingDelegate(); ChartableTwoFileLineSeriesChart* lineChart = chartDelegate->getLineSeriesCharting(); CaretAssert(lineChart); switch (lineChart->getLineSeriesContentType()) { case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED: break; case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA: break; case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_ROW_SCALAR_DATA: matrixChart = chartDelegate->getMatrixCharting(); break; } } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: { ChartableTwoFileDelegate* chartDelegate = m_selectedMapFile->getChartingDelegate(); matrixChart = chartDelegate->getMatrixCharting(); // const ChartableTwoFileMatrixChart* matrixChart = chartDelegate->getMatrixCharting(); // CaretAssert(matrixChart); // int32_t numRows = 0; // int32_t numCols = 0; // matrixChart->getMatrixDimensions(numRows, numCols); // // ChartTwoMatrixLoadingDimensionEnum::Enum rowColumnDimension; // std::vector columnIndices; // std::vector rowIndices; // matrixChart->getSelectedRowColumnIndices(m_parentChartTwoOverlaySet->m_tabIndex, // rowColumnDimension, // rowIndices, // columnIndices); // // switch (rowColumnDimension) { // case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: // numMaps = numCols; // if ( ! columnIndices.empty()) { // selectedIndexTypeOut = SelectedIndexType::COLUMN; // selectedIndexOut = columnIndices[0]; // } // if (matrixChart->hasColumnSelection()) { // if (selectedFileMapNamesOut != NULL) { // for (int32_t i = 0; i < numMaps; i++) { // selectedFileMapNamesOut->push_back(matrixChart->getColumnName(i)); // } // } // } // break; // case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: // numMaps = numRows; // if ( ! rowIndices.empty()) { // selectedIndexTypeOut = SelectedIndexType::ROW; // selectedIndexOut = rowIndices[0]; // } // if (matrixChart->hasRowSelection()) { // if (selectedFileMapNamesOut != NULL) { // for (int32_t i = 0; i < numMaps; i++) { // selectedFileMapNamesOut->push_back(matrixChart->getRowName(i)); // } // } // } // break; // } } break; } if (matrixChart != NULL) { CaretAssert(matrixChart); int32_t numRows = 0; int32_t numCols = 0; matrixChart->getMatrixDimensions(numRows, numCols); ChartTwoMatrixLoadingDimensionEnum::Enum rowColumnDimension; std::vector columnIndices; std::vector rowIndices; matrixChart->getSelectedRowColumnIndices(m_parentChartTwoOverlaySet->m_tabIndex, rowColumnDimension, rowIndices, columnIndices); switch (rowColumnDimension) { case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: numMaps = numCols; if ( ! columnIndices.empty()) { selectedIndexTypeOut = SelectedIndexType::COLUMN; selectedIndexOut = columnIndices[0]; } if (matrixChart->hasColumnSelection()) { if (selectedFileMapNamesOut != NULL) { for (int32_t i = 0; i < numMaps; i++) { selectedFileMapNamesOut->push_back(matrixChart->getColumnName(i)); } } } break; case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: numMaps = numRows; if ( ! rowIndices.empty()) { selectedIndexTypeOut = SelectedIndexType::ROW; selectedIndexOut = rowIndices[0]; } if (matrixChart->hasRowSelection()) { if (selectedFileMapNamesOut != NULL) { for (int32_t i = 0; i < numMaps; i++) { selectedFileMapNamesOut->push_back(matrixChart->getRowName(i)); } } } break; } } } selectedMapFileOut = m_selectedMapFile; /* * Update the compound data type if this is the FIRST OVERLAY */ if (m_overlayIndex == 0) { if (m_selectedMapFile != NULL) { const ChartableTwoFileDelegate* chartFile = m_selectedMapFile->getChartingDelegate(); CaretAssert(chartFile); chartFile->getChartTwoCompoundDataTypeForChartTwoDataType(m_chartDataType, m_chartCompoundDataType); } CaretAssert(m_parentChartTwoOverlaySet); m_parentChartTwoOverlaySet->firstOverlaySelectionChanged(); } if (m_mapYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { if ( ! isMapYokingSupportedPrivate(m_selectedMapFile)) { m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; } } } /** * Set the selected map file and map. * @param selectedMapFile * File that is selected. * @param selectedMapIndex * Index of map for selection. If invalid, try the current map * index if it is valid. Otherwise, use the first map index. */ void ChartTwoOverlay::setSelectionData(CaretMappableDataFile* selectedMapFile, const int32_t selectedMapIndex) { m_selectedMapFile = selectedMapFile; if (m_selectedMapFile != NULL) { ChartableTwoFileLineSeriesChart* lineSeriesChart = NULL; ChartableTwoFileMatrixChart* matrixChart = NULL; switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: if (selectedMapIndex >= 0) { m_selectedHistogramMapIndex = selectedMapIndex; } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: { /* * Row/Column Scalar files use the matrix for line chart tracking */ ChartableTwoFileDelegate* chartDelegate = m_selectedMapFile->getChartingDelegate(); ChartableTwoFileLineSeriesChart* lineChart = chartDelegate->getLineSeriesCharting(); CaretAssert(lineChart); switch (lineChart->getLineSeriesContentType()) { case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED: break; case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA: break; case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_ROW_SCALAR_DATA: lineSeriesChart = lineChart; matrixChart = chartDelegate->getMatrixCharting(); break; } } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: { ChartableTwoFileDelegate* chartDelegate = m_selectedMapFile->getChartingDelegate(); CaretAssert(chartDelegate); matrixChart = chartDelegate->getMatrixCharting(); if (m_selectedMapFile->getDataFileType() == DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES) { ChartableTwoFileLineSeriesChart* lineChart = chartDelegate->getLineSeriesCharting(); if (lineChart != NULL) { switch (lineChart->getLineSeriesContentType()) { case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED: break; case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA: break; case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_ROW_SCALAR_DATA: lineSeriesChart = lineChart; break; } } } } break; } if (matrixChart != NULL) { matrixChart->setSelectedRowColumnIndex(m_parentChartTwoOverlaySet->m_tabIndex, selectedMapIndex); if (lineSeriesChart) { lineSeriesChart->loadDataForRowOrColumn(m_tabIndex, selectedMapIndex); } } if (m_mapYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { if (m_selectedMapFile == NULL) { m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; } } } /* * By calling getSelectionData(), it will validate the * selected file and map index and update if needed * (such as a valid map index). */ CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; getSelectionData(mapFile, selectedIndexType, selectedIndex); } /** * @return Is the all maps supported? */ bool ChartTwoOverlay::isAllMapsSupported() const { bool supportedFlag = false; switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: { CaretMappableDataFile* cmdf = NULL; SelectedIndexType indexType = SelectedIndexType::INVALID; int32_t mapIndex = 0; getSelectionData(cmdf, indexType, mapIndex); if (cmdf != NULL) { if (cmdf->getNumberOfMaps() > 1) { supportedFlag = true; } else { /* * Parcel type files (dpconn, pconn, and pdconn) are a matrix * type file in which one row is loaded as the current map. * Allow "all maps" so that the histogram of all data can * be viewed as a chart histogram overlay. */ switch (cmdf->getDataFileType()) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: supportedFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: supportedFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: supportedFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: break; case DataFileTypeEnum::METRIC: break; case DataFileTypeEnum::METRIC_DYNAMIC: break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: break; } } } } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; } return supportedFlag; } /** * @return All maps selected. */ bool ChartTwoOverlay::isAllMapsSelected() const { return m_allHistogramMapsSelectedFlag; } /** * Set all maps selected. * * @param status * New status. */ void ChartTwoOverlay::setAllMapsSelected(const bool status) { m_allHistogramMapsSelectedFlag = status; } /** * @return The matrix triangular viewing mode. */ ChartTwoMatrixTriangularViewingModeEnum::Enum ChartTwoOverlay::getMatrixTriangularViewingMode() const { if ( ! isMatrixTriangularViewingModeSupported()) { if (m_matrixTriangularViewingMode != ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL) { m_matrixTriangularViewingMode = ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL; } } return m_matrixTriangularViewingMode; } /** * Set the matrix triangular viewing mode. * * @param mode * New triangular viewing mode. */ void ChartTwoOverlay::setMatrixTriangularViewingMode(const ChartTwoMatrixTriangularViewingModeEnum::Enum mode) { m_matrixTriangularViewingMode = mode; } /** * @return Is the matrix triangular view mode supported? */ bool ChartTwoOverlay::isMatrixTriangularViewingModeSupported() const { switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: { ChartableTwoFileDelegate* chartDelegate = m_selectedMapFile->getChartingDelegate(); const ChartableTwoFileMatrixChart* matrixChart = chartDelegate->getMatrixCharting(); return matrixChart->isMatrixTriangularViewingModeSupported(); } } return false; } /** * @return Location of vertical cartesian axis */ ChartAxisLocationEnum::Enum ChartTwoOverlay::getCartesianVerticalAxisLocation() const { validateCartesianVerticalAxisLocation(); return m_cartesianVerticalAxisLocation; } /** * Set Location of vertical cartesian axis * * @param cartesianVerticalAxisLocation * New value for Location of vertical cartesian axis */ void ChartTwoOverlay::setCartesianVerticalAxisLocation(const ChartAxisLocationEnum::Enum cartesianVerticalAxisLocation) { m_cartesianVerticalAxisLocation = cartesianVerticalAxisLocation; validateCartesianVerticalAxisLocation(); } /** * Validate cartesian vertical axis to valid locations (left and right) */ void ChartTwoOverlay::validateCartesianVerticalAxisLocation() const { switch (m_cartesianVerticalAxisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: m_cartesianVerticalAxisLocation = ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: m_cartesianVerticalAxisLocation = ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT; break; } } /** * @return Is the cartesian vertical axis location supported? */ bool ChartTwoOverlay::isCartesianVerticalAxisLocationSupported() const { switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: return true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: return true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; } return false; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* ChartTwoOverlay::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ChartTwoOverlay", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); std::vector mapFiles; CaretMappableDataFile* selectedMapFile = NULL; //AString selectedMapUniqueID; SelectedIndexType selectedIndexType = SelectedIndexType::INVALID; int32_t selectedMapIndex; getSelectionData(mapFiles, selectedMapFile, selectedIndexType, selectedMapIndex); AString sceneSelectedMapFileNameWithPath; AString sceneSelectedMapFileNameNoPath; AString sceneSelectedMapName; int32_t sceneSelectedMapIndex = selectedMapIndex; /* * NOTE:Some of the connectivity matrix files may not have a valid * selection index (-1) until the user identifies a brainordinate */ if (selectedMapFile != NULL) { sceneSelectedMapFileNameWithPath = selectedMapFile->getFileName(); sceneSelectedMapFileNameNoPath = selectedMapFile->getFileNameNoPath(); if ((selectedMapIndex >= 0) && (selectedMapIndex < selectedMapFile->getNumberOfMaps())) { sceneSelectedMapName = selectedMapFile->getMapName(selectedMapIndex); } } sceneClass->addPathName("sceneSelectedMapFileNameWithPath", sceneSelectedMapFileNameWithPath); sceneClass->addString("sceneSelectedMapFileNameNoPath", sceneSelectedMapFileNameNoPath); sceneClass->addString("sceneSelectedMapName", sceneSelectedMapName); sceneClass->addInteger("sceneSelectedMapIndex", sceneSelectedMapIndex); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ChartTwoOverlay::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); const MapYokingGroupEnum::Enum mapYokingGroupFromScene = m_mapYokingGroup; /* * Making a call to getSelectionData() to get the availble * map files */ std::vector mapFiles; CaretMappableDataFile* unusedSelectedMapFile = NULL; SelectedIndexType unusedSelectedIndexType = SelectedIndexType::INVALID; int32_t unusedSelectedMapIndex; getSelectionData(mapFiles, unusedSelectedMapFile, unusedSelectedIndexType, unusedSelectedMapIndex); const AString selectedMapFileNameWithPath = sceneClass->getPathNameValue("sceneSelectedMapFileNameWithPath"); const AString selectedMapFileName = sceneClass->getStringValue("sceneSelectedMapFileNameNoPath", ""); const AString selectedMapName = sceneClass->getStringValue("sceneSelectedMapName", ""); const int32_t selectedMapIndex = sceneClass->getIntegerValue("sceneSelectedMapIndex", -1); bool found = false; /* * Is used when the file is found but a map is not matched */ CaretMappableDataFile* matchedMapFile = NULL; /* * First try to find file by filename INCLUDING path and map by unique ID */ /* * Find map by unique ID, map index, and map file */ CaretMappableDataFile* foundMapNameFile = NULL; int32_t foundMapNameIndex = -1; CaretMappableDataFile* foundMapIndexFile = NULL; int32_t foundMapIndex = -1; /* * Try to match files twice. First time by name with path, then * by name without path. */ for (int iTries = 0; iTries < 2; iTries++) { for (std::vector::iterator iter = mapFiles.begin(); iter != mapFiles.end(); iter++) { CaretMappableDataFile* mapFile = *iter; bool testIt = false; switch (iTries) { case 0: { const AString fileName = mapFile->getFileName(); if (fileName == selectedMapFileNameWithPath) { testIt = true; } } break; case 1: { const AString fileName = mapFile->getFileNameNoPath(); if (fileName == selectedMapFileName) { testIt = true; } } break; } if (testIt) { CaretMappableDataFile* mapFile = *iter; matchedMapFile = mapFile; if (foundMapNameIndex < 0) { if ( ! selectedMapName.isEmpty()) { const int mapNameIndex = mapFile->getMapIndexFromName(selectedMapName); if (mapNameIndex >= 0) { foundMapNameFile = mapFile; foundMapNameIndex = mapNameIndex; } } } if (foundMapIndex < 0) { if (selectedMapIndex >= 0) { if (selectedMapIndex < mapFile->getNumberOfMaps()) { foundMapIndexFile = mapFile; foundMapIndex = selectedMapIndex; } } } } } } if (! found) { if (foundMapIndex >= 0) { if (foundMapIndexFile != NULL) { setSelectionData(foundMapIndexFile, foundMapIndex); found = true; } } } if (! found) { if (foundMapNameIndex >= 0) { if (foundMapNameFile != NULL) { setSelectionData(foundMapNameFile, foundMapNameIndex); found = true; } } } if ( ! found) { /* * If not found by unique ID, try to find map by name */ if ( ! selectedMapName.isEmpty()) { for (std::vector::iterator iter = mapFiles.begin(); iter != mapFiles.end(); iter++) { CaretMappableDataFile* mapFile = *iter; const AString fileName = mapFile->getFileNameNoPath(); if (fileName == selectedMapFileName) { CaretMappableDataFile* mapFile = *iter; matchedMapFile = mapFile; const int32_t mapIndex = mapFile->getMapIndexFromName(selectedMapName); if (mapIndex >= 0) { setSelectionData(mapFile, mapIndex); found = true; break; } } } } } /* * NOTE:Some of the connectivity matrix files may not have a valid * selection index (-1) until the user identifies a brainordinate */ if ( ! found) { if (matchedMapFile != NULL) { if (matchedMapFile->getNumberOfMaps() > 0) { int32_t defaultMapIndex = -1; switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: defaultMapIndex = 0; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: defaultMapIndex = 0; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; } setSelectionData(matchedMapFile, defaultMapIndex); } } } if (mapYokingGroupFromScene != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { /* * Need to update selections and then apply yoking as * yoking is cleared when the the previous file * was not found. */ CaretMappableDataFile* mapFile = NULL; SelectedIndexType indexType = SelectedIndexType::INVALID; int32_t mapIndex = -1; getSelectionData(mapFile, indexType, mapIndex); setMapYokingGroup(mapYokingGroupFromScene); } //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Brain/ChartTwoOverlay.h000066400000000000000000000211711360521144700227250ustar00rootroot00000000000000#ifndef __CHART_TWO_OVERLAY_H__ #define __CHART_TWO_OVERLAY_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "ChartAxisLocationEnum.h" #include "ChartTwoCompoundDataType.h" #include "ChartTwoMatrixTriangularViewingModeEnum.h" #include "EventListenerInterface.h" #include "MapYokingGroupEnum.h" #include "SceneableInterface.h" namespace caret { class AnnotationColorBar; class BoundingBox; class CaretMappableDataFile; class ChartTwoOverlaySet; class PlainTextStringBuilder; class SceneClassAssistant; class ChartTwoOverlay : public CaretObject, public EventListenerInterface, public SceneableInterface { public: enum class SelectedIndexType { INVALID, MAP, ROW, COLUMN }; ChartTwoOverlay(ChartTwoOverlaySet* parentChartTwoOverlaySet, const ChartTwoDataTypeEnum::Enum chartDataType, const int32_t tabIndex, const int32_t overlayIndex); virtual ~ChartTwoOverlay(); std::weak_ptr getWeakPointerToSelf(); ChartTwoDataTypeEnum::Enum getChartTwoDataType() const; ChartTwoCompoundDataType getChartTwoCompoundDataType() const; void setChartTwoCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType); int32_t getTabIndex() const; virtual AString toString() const; virtual void getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const; bool isEnabled() const; void setEnabled(const bool enabled); bool isLineSeriesLoadingEnabled() const; void setLineSeriesLoadingEnabled(const bool lineSeriesLoadingEnabled); void copyData(const ChartTwoOverlay* overlay); void swapData(ChartTwoOverlay* overlay); bool isHistorySupported() const; bool isMapYokingSupported() const; MapYokingGroupEnum::Enum getMapYokingGroup() const; void setMapYokingGroup(const MapYokingGroupEnum::Enum mapYokingGroup); AnnotationColorBar* getColorBar(); const AnnotationColorBar* getColorBar() const; ChartTwoMatrixTriangularViewingModeEnum::Enum getMatrixTriangularViewingMode() const; void setMatrixTriangularViewingMode(const ChartTwoMatrixTriangularViewingModeEnum::Enum mode); bool isMatrixTriangularViewingModeSupported() const; ChartAxisLocationEnum::Enum getCartesianVerticalAxisLocation() const; void setCartesianVerticalAxisLocation(const ChartAxisLocationEnum::Enum cartesianVerticalAxisLocation); bool isCartesianVerticalAxisLocationSupported() const; CaretMappableDataFile* getSelectedMapFile() const; void getSelectionData(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, std::vector& selectedFileMapNamesOut, SelectedIndexType& selectedIndexTypeOut, int32_t& selectedIndexOut) const; void getSelectionData(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, SelectedIndexType& selectedIndexTypeOut, int32_t& selectedIndexOut) const; void getSelectionData(CaretMappableDataFile* &selectedMapFileOut, SelectedIndexType& selectedIndexTypeOut, int32_t& selectedIndexOut) const; void setSelectionData(CaretMappableDataFile* selectedMapFile, const int32_t selectedMapIndex); bool isAllMapsSupported() const; bool isAllMapsSelected() const; void setAllMapsSelected(const bool status); bool getBounds(BoundingBox& boundingBoxOut) const; virtual void receiveEvent(Event* event); // ADD_NEW_METHODS_HERE virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implementation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: ChartTwoOverlay(const ChartTwoOverlay&); ChartTwoOverlay& operator=(const ChartTwoOverlay&); void setWeakPointerToSelf(std::weak_ptr weakPointerToSelf); void getSelectionDataPrivate(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, std::vector* selectedFileMapNamesOut, SelectedIndexType& selectedIndexTypeOut, int32_t& selectedIndexOut) const; bool isMapYokingSupportedPrivate(const CaretMappableDataFile* mapFile) const; void validateCartesianVerticalAxisLocation() const; /** Parent chart overlay set (only used by first overlay in the set */ ChartTwoOverlaySet* m_parentChartTwoOverlaySet; /** Enumerated Type of charts allowed in this overlay */ const ChartTwoDataTypeEnum::Enum m_chartDataType; const int32_t m_tabIndex; /** Index of this overlay (DO NOT COPY)*/ const int32_t m_overlayIndex; std::unique_ptr m_sceneAssistant; /** Current 'compound chart type' of charts allowed in this overlay */ mutable ChartTwoCompoundDataType m_chartCompoundDataType; /** Name of overlay (DO NOT COPY)*/ AString m_name; /** enabled status */ mutable bool m_enabled = true; /** map yoking group */ mutable MapYokingGroupEnum::Enum m_mapYokingGroup; /** The color bar displayed in the graphics window */ std::unique_ptr m_colorBar; /** selected mappable file */ mutable CaretMappableDataFile* m_selectedMapFile = NULL; /** histogram selected map index */ mutable int32_t m_selectedHistogramMapIndex = -1; bool m_allHistogramMapsSelectedFlag = false; mutable ChartTwoMatrixTriangularViewingModeEnum::Enum m_matrixTriangularViewingMode; /** Location of vertical cartesian axis*/ mutable ChartAxisLocationEnum::Enum m_cartesianVerticalAxisLocation; /** A weak pointer to 'self' so that can be stored to safely test instance is valid and can be accessed */ std::weak_ptr m_weakPointerToSelf; // ADD_NEW_MEMBERS_HERE friend class ChartTwoOverlaySet; }; #ifdef __CHART_TWO_OVERLAY_DECLARE__ // #endif // __CHART_TWO_OVERLAY_DECLARE__ } // namespace #endif //__CHART_TWO_OVERLAY_H__ connectome-workbench-1.4.2/src/Brain/ChartTwoOverlaySet.cxx000066400000000000000000001300571360521144700237600ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_TWO_OVERLAY_SET_DECLARE__ #include "ChartTwoOverlaySet.h" #undef __CHART_TWO_OVERLAY_SET_DECLARE__ #include "AnnotationPercentSizeText.h" #include "BoundingBox.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretMappableDataFile.h" #include "ChartTwoCartesianAxis.h" #include "ChartTwoOverlay.h" #include "ChartTwoTitle.h" #include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileHistogramChart.h" #include "ChartableTwoFileLineSeriesChart.h" #include "EventAnnotationChartLabelGet.h" #include "EventBrowserTabGet.h" #include "EventChartTwoAttributesChanged.h" #include "EventChartTwoAxisGetDataRange.h" #include "EventManager.h" #include "EventMapYokingSelectMap.h" #include "EventMapYokingValidation.h" #include "PlainTextStringBuilder.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneClassAssistant.h" #include "SceneObjectMapIntegerKey.h" using namespace caret; /** * \class caret::ChartTwoOverlaySet * \brief A set of chart overlays. * \ingroup Brain */ /** * Constructor. * * @param chartDataType * Type of charts allowed in this overlay * @param name * Name of the overlay set. * @param tabIndex * Index of tab in which this overlay set is used. */ ChartTwoOverlaySet::ChartTwoOverlaySet(const ChartTwoDataTypeEnum::Enum chartDataType, const AString& name, const int32_t tabIndex) : CaretObject(), m_chartDataType(chartDataType), m_name(name), m_tabIndex(tabIndex) { m_numberOfDisplayedOverlays = BrainConstants::MINIMUM_NUMBER_OF_OVERLAYS; m_chartAxisLeft = std::unique_ptr(new ChartTwoCartesianAxis(this, ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT)); m_chartAxisRight = std::unique_ptr(new ChartTwoCartesianAxis(this, ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT)); m_chartAxisBottom = std::unique_ptr(new ChartTwoCartesianAxis(this, ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM)); m_chartAxisLeft->setEnabledByChart(false); m_chartAxisRight->setEnabledByChart(false); m_chartAxisBottom->setEnabledByChart(false); switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: { m_chartAxisLeft->setEnabledByChart(true); m_chartAxisLeft->setUnits(CaretUnitsTypeEnum::NONE); m_chartAxisRight->setEnabledByChart(false); m_chartAxisRight->setUnits(CaretUnitsTypeEnum::NONE); m_chartAxisBottom->setEnabledByChart(true); m_chartAxisBottom->setUnits(CaretUnitsTypeEnum::NONE); } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: { m_chartAxisLeft->setEnabledByChart(true); m_chartAxisLeft->setUnits(CaretUnitsTypeEnum::NONE); m_chartAxisRight->setEnabledByChart(false); m_chartAxisRight->setUnits(CaretUnitsTypeEnum::NONE); /* * X-axis for line series shows full extent of data */ m_chartAxisBottom->setScaleRangeMode(ChartTwoAxisScaleRangeModeEnum::DATA); m_chartAxisBottom->setEnabledByChart(true); m_chartAxisBottom->setUnits(CaretUnitsTypeEnum::NONE); } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; } m_title = std::unique_ptr(new ChartTwoTitle()); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_chartAxisLeft", "ChartTwoCartesianAxis", m_chartAxisLeft.get()); m_sceneAssistant->add("m_chartAxisRight", "ChartTwoCartesianAxis", m_chartAxisRight.get()); m_sceneAssistant->add("m_chartAxisBottom", "ChartTwoCartesianAxis", m_chartAxisBottom.get()); m_sceneAssistant->add("m_title", "ChartTwoTitle", m_title.get()); m_sceneAssistant->add("m_numberOfDisplayedOverlays", &m_numberOfDisplayedOverlays); m_sceneAssistant->add("m_axisLineThickness", &m_axisLineThickness); for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { m_overlays.push_back(std::make_shared(this, m_chartDataType, m_tabIndex, i)); CaretAssertVectorIndex(m_overlays, i); m_overlays[i]->setWeakPointerToSelf(m_overlays[i]); } EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CHART_TWO_ATTRIBUTES_CHANGED); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CHART_TWO_AXIS_GET_DATA_RANGE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_VALIDATION); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP); } /** * Destructor. */ ChartTwoOverlaySet::~ChartTwoOverlaySet() { EventManager::get()->removeAllEventsFromListener(this); m_overlays.clear(); delete m_sceneAssistant; } /** * Copy the given overlay set to this overlay set. * @param overlaySet * Overlay set that is copied. */ void ChartTwoOverlaySet::copyOverlaySet(const ChartTwoOverlaySet* overlaySet) { for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, i); m_overlays[i]->copyData(overlaySet->getOverlay(i)); } *m_chartAxisLeft = *overlaySet->m_chartAxisLeft; *m_chartAxisRight = *overlaySet->m_chartAxisRight; *m_chartAxisBottom = *overlaySet->m_chartAxisBottom; *m_title = *overlaySet->m_title; m_axisLineThickness = overlaySet->m_axisLineThickness; m_numberOfDisplayedOverlays = overlaySet->m_numberOfDisplayedOverlays; } /** * Copy the cartesian axes from the given overlay set to this overlay set. * * @param overlaySet * Overlay from which axes are copied. */ void ChartTwoOverlaySet::copyCartesianAxes(const ChartTwoOverlaySet* overlaySet) { CaretAssert(m_chartDataType == overlaySet->m_chartDataType); *m_chartAxisLeft = *overlaySet->m_chartAxisLeft; *m_chartAxisRight = *overlaySet->m_chartAxisRight; *m_chartAxisBottom = *overlaySet->m_chartAxisBottom; m_axisLineThickness = overlaySet->m_axisLineThickness; } /** * @return Returns the top-most overlay regardless of its enabled status. */ ChartTwoOverlay* ChartTwoOverlaySet::getPrimaryOverlay() { return m_overlays[0].get(); } /** * @return Returns the top-most overlay regardless of its enabled status. */ const ChartTwoOverlay* ChartTwoOverlaySet::getPrimaryOverlay() const { return m_overlays[0].get(); } /** * Get the overlay at the specified index. If caller needs * to store the pointer there is a risk that the overlay * may be destroyed. Consider using getOverlayWeakPointer() * instead. * * @param overlayNumber * Index of the overlay. * @return Overlay at the given index. */ const ChartTwoOverlay* ChartTwoOverlaySet::getOverlay(const int32_t overlayNumber) const { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, overlayNumber); return m_overlays[overlayNumber].get(); } /** * Get the overlay at the specified index. If caller needs * to store the pointer there is a risk that the overlay * may be destroyed. Consider using getOverlayWeakPointer() * instead. * * @param overlayNumber * Index of the overlay. * @return Overlay at the given index. */ ChartTwoOverlay* ChartTwoOverlaySet::getOverlay(const int32_t overlayNumber) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, overlayNumber); return m_overlays[overlayNumber].get(); } /** * Get the a "weak pointer" to the chart overlay at the given * index. Caller can store this pointer and test to see * if the chart overlay is still valid. * * @param overlayNumber * Index of the overlay. * @return Weak pointer to chart verlay at the given index. */ std::weak_ptr ChartTwoOverlaySet::getOverlayWeakPointer(const int32_t overlayNumber) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, overlayNumber); return m_overlays[overlayNumber]; } /** * @return The displayed overlays which are the overlays * shown in the Overlay Toolbox and this includes * overlays that the user may have set to disabled. */ std::vector ChartTwoOverlaySet::getDisplayedOverlays() const { std::vector displayedOverlays; const int numOverlays = getNumberOfDisplayedOverlays(); for (int32_t i = 0; i < numOverlays; i++) { CaretAssertVectorIndex(m_overlays, i); displayedOverlays.push_back(m_overlays[i].get()); } return displayedOverlays; } /** * @return The displayed overlays but only those * that are enabled by the user. */ std::vector ChartTwoOverlaySet::getEnabledOverlays() const { std::vector enabledOverlays; const int numOverlays = getNumberOfDisplayedOverlays(); for (int32_t i = 0; i < numOverlays; i++) { CaretAssertVectorIndex(m_overlays, i); if (m_overlays[i]->isEnabled()) { enabledOverlays.push_back(m_overlays[i].get()); } } return enabledOverlays; } /** * Get a text description of the window's content. * * @param descriptionOut * Description of the window's content. */ void ChartTwoOverlaySet::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const { descriptionOut.addLine("Overlay Set"); descriptionOut.pushIndentation(); descriptionOut.addLine(" Title: " + (m_title->isDisplayed() ? m_title->getText() : "Disabled by user")); descriptionOut.popIndentation(); const int numOverlays = getNumberOfDisplayedOverlays(); for (int32_t i = 0; i < numOverlays; i++) { if (getOverlay(i)->isEnabled()) { descriptionOut.pushIndentation(); descriptionOut.pushIndentation(); getOverlay(i)->getDescriptionOfContent(descriptionOut); descriptionOut.popIndentation(); descriptionOut.popIndentation(); } } } /** * Find the top-most displayed and enabled overlay containing the given data file. * * @param mapFile * File for which overlay is requested. */ ChartTwoOverlay* ChartTwoOverlaySet::getDisplayedOverlayContainingDataFile(const CaretMappableDataFile* mapFile) { if (mapFile == NULL) { return NULL; } ChartTwoOverlay* overlayOut = NULL; const int numOverlays = getNumberOfDisplayedOverlays(); for (int32_t i = 0; i < numOverlays; i++) { ChartTwoOverlay* overlay = getOverlay(i); if (overlay->isEnabled()) { CaretMappableDataFile* overlayMapFile = NULL; ChartTwoOverlay::SelectedIndexType selectionType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t dataFileIndex = -1; overlay->getSelectionData(overlayMapFile, selectionType, dataFileIndex); if (mapFile == overlayMapFile) { overlayOut = overlay; } } } return overlayOut; } /** * Add a displayed overlay. If the maximum * number of surface overlays is reached, * this method has no effect. */ void ChartTwoOverlaySet::addDisplayedOverlay() { m_numberOfDisplayedOverlays++; if (m_numberOfDisplayedOverlays > BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS) { m_numberOfDisplayedOverlays = BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; } } /** * @return Returns the number of displayed overlays. */ int32_t ChartTwoOverlaySet::getNumberOfDisplayedOverlays() const { return m_numberOfDisplayedOverlays; } /** * Insert an overlay below this overlay * @param overlayIndex * Index of overlay for which an overlay is added below */ void ChartTwoOverlaySet::insertOverlayAbove(const int32_t overlayIndex) { if (m_numberOfDisplayedOverlays < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS) { m_numberOfDisplayedOverlays++; for (int32_t i = (m_numberOfDisplayedOverlays - 2); i >= overlayIndex; i--) { moveDisplayedOverlayDown(i); } } } /** * Insert an overlay above this overlay * @param overlayIndex * Index of overlay for which an overlay is added above */ void ChartTwoOverlaySet::insertOverlayBelow(const int32_t overlayIndex) { if (m_numberOfDisplayedOverlays < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS) { m_numberOfDisplayedOverlays++; for (int32_t i = (m_numberOfDisplayedOverlays - 2); i > overlayIndex; i--) { moveDisplayedOverlayDown(i); } } } /** * Remove a displayed overlay. This method will have * no effect if the minimum number of overlays are * displayed * * @param overlayIndex * Index of overlay for removal from display. */ void ChartTwoOverlaySet::removeDisplayedOverlay(const int32_t overlayIndex) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, overlayIndex); m_overlays[overlayIndex]->setMapYokingGroup(MapYokingGroupEnum::MAP_YOKING_GROUP_OFF); if (m_numberOfDisplayedOverlays > BrainConstants::MINIMUM_NUMBER_OF_OVERLAYS) { m_numberOfDisplayedOverlays--; for (int32_t i = overlayIndex; i < m_numberOfDisplayedOverlays; i++) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, i+1); m_overlays[i]->copyData(m_overlays[i+1].get()); } } } /** * Move the overlay at the given index up one level * (swap it with overlayIndex - 1). This method will * have no effect if the overlay is the top-most overlay. * * @param overlayIndex * Index of overlay that is to be moved up. */ void ChartTwoOverlaySet::moveDisplayedOverlayUp(const int32_t overlayIndex) { if (overlayIndex > 0) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, overlayIndex); m_overlays[overlayIndex]->swapData(m_overlays[overlayIndex - 1].get()); } } /** * Move the overlay at the given index down one level * (swap it with overlayIndex + 1). This method will * have no effect if the overlay is the bottom-most overlay. * * @param overlayIndex * Index of overlay that is to be moved down. */ void ChartTwoOverlaySet::moveDisplayedOverlayDown(const int32_t overlayIndex) { const int32_t nextOverlayIndex = overlayIndex + 1; if (nextOverlayIndex < m_numberOfDisplayedOverlays) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, nextOverlayIndex); m_overlays[overlayIndex]->swapData(m_overlays[nextOverlayIndex].get()); } } /** * Initialize the overlays. */ void ChartTwoOverlaySet::initializeOverlays() { /* * This method could be used to choose specific file types * for the default overlays similar to that in OverlaySet.cxx. */ } /** * Called by first overlay when the first overlay's selection changes. * All other overlays are set to use the same chart compound data type * so that the charts in the tab are compatible */ void ChartTwoOverlaySet::firstOverlaySelectionChanged() { if (m_inFirstOverlayChangedMethodFlag) { return; } m_inFirstOverlayChangedMethodFlag = true; ChartTwoCompoundDataType cdt = m_overlays[0]->getChartTwoCompoundDataType(); for (int32_t i = 1; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, i); m_overlays[i]->setChartTwoCompoundDataType(cdt); } PlainTextStringBuilder description; getDescriptionOfContent(description); m_inFirstOverlayChangedMethodFlag = false; } /** * Reset the yoking status of all overlays to off. */ void ChartTwoOverlaySet::resetOverlayYokingToOff() { for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, i); m_overlays[i]->setMapYokingGroup(MapYokingGroupEnum::MAP_YOKING_GROUP_OFF); } } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ChartTwoOverlaySet::toString() const { return "ChartTwoOverlaySet"; } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void ChartTwoOverlaySet::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_CHART_TWO_ATTRIBUTES_CHANGED) { EventChartTwoAttributesChanged* attributeEvent = dynamic_cast(event); CaretAssert(attributeEvent); switch (attributeEvent->getMode()) { case EventChartTwoAttributesChanged::Mode::INVALID: break; case EventChartTwoAttributesChanged::Mode::CARTESIAN_AXIS: { YokingGroupEnum::Enum yokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; ChartTwoDataTypeEnum::Enum chartTwoDataType = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; ChartTwoCartesianAxis* cartesianAxis = NULL; attributeEvent->getCartesianAxisChanged(yokingGroup, chartTwoDataType, cartesianAxis); /* * Only tabs in the windows are valid */ EventBrowserTabGet tabEvent(m_tabIndex); EventManager::get()->sendEvent(tabEvent.getPointer()); const BrowserTabContent* btc = tabEvent.getBrowserTab(); if (btc != NULL) { const YokingGroupEnum::Enum tabYoking = btc->getChartModelYokingGroup(); if ((yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) && (yokingGroup == tabYoking) && (m_chartDataType == chartTwoDataType)) { switch (cartesianAxis->getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: *m_chartAxisBottom = *cartesianAxis; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: *m_chartAxisLeft = *cartesianAxis; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: *m_chartAxisRight = *cartesianAxis; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: CaretAssert(0); break; } } } } break; case EventChartTwoAttributesChanged::Mode::LINE_THICKESS: { YokingGroupEnum::Enum yokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; ChartTwoDataTypeEnum::Enum chartTwoDataType = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; float lineThickness = 0.0f; attributeEvent->getLineThicknessChanged(yokingGroup, chartTwoDataType, lineThickness); /* * Only tabs in the windows are valid */ EventBrowserTabGet tabEvent(m_tabIndex); EventManager::get()->sendEvent(tabEvent.getPointer()); const BrowserTabContent* btc = tabEvent.getBrowserTab(); if (btc != NULL) { const YokingGroupEnum::Enum tabYoking = btc->getChartModelYokingGroup(); if ((yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) && (yokingGroup == tabYoking) && (m_chartDataType == chartTwoDataType)) { m_axisLineThickness = lineThickness; } } } break; case EventChartTwoAttributesChanged::Mode::TITLE: { YokingGroupEnum::Enum yokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; ChartTwoDataTypeEnum::Enum chartTwoDataType = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; ChartTwoTitle* chartTitle = NULL; attributeEvent->getTitleChanged(yokingGroup, chartTwoDataType, chartTitle); /* * Only tabs in the windows are valid */ EventBrowserTabGet tabEvent(m_tabIndex); EventManager::get()->sendEvent(tabEvent.getPointer()); const BrowserTabContent* btc = tabEvent.getBrowserTab(); if (btc != NULL) { const YokingGroupEnum::Enum tabYoking = btc->getChartModelYokingGroup(); if ((yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) && (yokingGroup == tabYoking) && (m_chartDataType == chartTwoDataType)) { *m_title = *chartTitle; } } } break; } attributeEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_CHART_TWO_AXIS_GET_DATA_RANGE) { EventChartTwoAxisGetDataRange* rangeEvent = dynamic_cast(event); CaretAssert(rangeEvent); if (rangeEvent->getChartOverlaySet() == this) { float minimumValue = 0.0f; float maximumValue = 0.0f; if (getDataRangeForAxis(rangeEvent->getChartAxisLocation(), minimumValue, maximumValue)) { rangeEvent->setMinimumAndMaximumValues(minimumValue, maximumValue); rangeEvent->setEventProcessed(); } } } else if (event->getEventType() == EventTypeEnum::EVENT_MAP_YOKING_VALIDATION) { /* * The events intended for overlays are received here so that * only DISPLAYED overlays are updated. */ EventMapYokingValidation* mapYokeEvent = dynamic_cast(event); CaretAssert(mapYokeEvent); const MapYokingGroupEnum::Enum requestedYokingGroup = mapYokeEvent->getMapYokingGroup(); if (requestedYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { /* * Find all overlays with the requested yoking */ const int32_t overlayCount = getNumberOfDisplayedOverlays(); for (int32_t j = 0; j < overlayCount; j++) { ChartTwoOverlay* overlay = getOverlay(j); if (overlay->isMapYokingSupported()) { CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType indexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t mapIndex = -1; overlay->getSelectionData(mapFile, indexType, mapIndex); if (mapFile != NULL) { if (overlay->isMapYokingSupported()) { mapYokeEvent->addMapYokedFile(mapFile, overlay->getMapYokingGroup(), m_tabIndex); } } } } } mapYokeEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP) { /* * The events intended for overlays are received here so that * only DISPLAYED overlays are updated. */ EventMapYokingSelectMap* selectMapEvent = dynamic_cast(event); CaretAssert(selectMapEvent); const MapYokingGroupEnum::Enum eventYokingGroup = selectMapEvent->getMapYokingGroup(); if (eventYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { const int32_t yokingGroupMapIndex = MapYokingGroupEnum::getSelectedMapIndex(eventYokingGroup); const bool yokingGroupSelectedStatus = MapYokingGroupEnum::isEnabled(eventYokingGroup); const CaretMappableDataFile* eventMapFile = selectMapEvent->getCaretMappableDataFile(); /* * Find all overlays with the requested yoking */ const int32_t overlayCount = getNumberOfDisplayedOverlays(); for (int32_t j = 0; j < overlayCount; j++) { ChartTwoOverlay* overlay = getOverlay(j); if (overlay->isMapYokingSupported()) { if (overlay->getMapYokingGroup() == selectMapEvent->getMapYokingGroup()) { CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType indexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t mapIndex = -1; overlay->getSelectionData(mapFile, indexType, mapIndex); if (mapFile != NULL) { if (overlay->isMapYokingSupported()) { switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: if (yokingGroupMapIndex < mapFile->getNumberOfMaps()) { overlay->setSelectionData(mapFile, yokingGroupMapIndex); } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; } if (mapFile == eventMapFile) { overlay->setEnabled(yokingGroupSelectedStatus); } } } } } } selectMapEvent->setEventProcessed(); } } else if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET) { /* * The events intended for overlays are received here so that * only DISPLAYED overlays are updated. */ //EventAnnotationChartLabelGet* chartLabelEvent = dynamic_cast(event); //CaretAssert(chartLabelEvent); //chartLabelEvent->addAnnotationChartLabel(m_chartTitle.get()); } } /** * Get the minimum and maximum values for the given chart axis * from the ENABLED overlays in this chart overlay set. * * @param chartAxisLocation * Location of axis. * @param minimumValueOut * Output with minimum value for axis. * @param maximumValueOut * Output with maximum value for axis. * @return * True if output values are valid, else false. */ bool ChartTwoOverlaySet::getDataRangeForAxis(const ChartAxisLocationEnum::Enum chartAxisLocation, float& minimumValueOut, float& maximumValueOut) const { minimumValueOut = 0.0f; maximumValueOut = 0.0f; if ( ! isAxesSupportedByChartDataType()) { return false; } minimumValueOut = std::numeric_limits::max(); maximumValueOut = -std::numeric_limits::max(); std::vector enabledOverlays = getEnabledOverlays(); for (auto overlay : enabledOverlays) { if (overlay->isEnabled()) { CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; overlay->getSelectionData(mapFile, selectedIndexType, selectedIndex); if (mapFile != NULL) { BoundingBox boundingBox; if (overlay->getBounds(boundingBox)) { switch (chartAxisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: minimumValueOut = std::min(minimumValueOut, boundingBox.getMinX()); maximumValueOut = std::max(maximumValueOut, boundingBox.getMaxX()); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: if (overlay->getCartesianVerticalAxisLocation() == ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT) { minimumValueOut = std::min(minimumValueOut, boundingBox.getMinY()); maximumValueOut = std::max(maximumValueOut, boundingBox.getMaxY()); } break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: if (overlay->getCartesianVerticalAxisLocation() == ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT) { minimumValueOut = std::min(minimumValueOut, boundingBox.getMinY()); maximumValueOut = std::max(maximumValueOut, boundingBox.getMaxY()); } break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: minimumValueOut = std::min(minimumValueOut, boundingBox.getMinX()); maximumValueOut = std::max(maximumValueOut, boundingBox.getMaxX()); break; } } } } } if (minimumValueOut < maximumValueOut) { return true; } minimumValueOut = 0.0f; maximumValueOut = 0.0f; return false; } /** * @return Are axes supported by the chart data type for this overlay set? */ bool ChartTwoOverlaySet::isAxesSupportedByChartDataType() const { bool axisSupportedFlag = false; switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: axisSupportedFlag = true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: axisSupportedFlag = true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; } return axisSupportedFlag; } /** * Get the displayed chart axes. * * @param axesOut * Output containing the displayed axes. */ void ChartTwoOverlaySet::getDisplayedChartAxes(std::vector& axesOut) const { axesOut.clear(); AString lineSeriesDataTypeName; float xMin = 0.0f; float xMax = 0.0f; float yMinLeft = 0.0f; float yMaxLeft = 0.0f; float yMinRight = 0.0f; float yMaxRight = 0.0f; bool showBottomFlag = getDataRangeForAxis(ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM, xMin, xMax); bool showLeftFlag = getDataRangeForAxis(ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT, yMinLeft, yMaxLeft); bool showRightFlag = getDataRangeForAxis(ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT, yMinRight, yMaxRight); m_chartAxisBottom->setEnabledByChart(showBottomFlag); m_chartAxisLeft->setEnabledByChart(showLeftFlag); m_chartAxisRight->setEnabledByChart(showRightFlag); if (m_chartAxisBottom->isEnabledByChart()) { axesOut.push_back(m_chartAxisBottom.get()); } if (m_chartAxisLeft->isEnabledByChart()) { axesOut.push_back(m_chartAxisLeft.get()); } if (m_chartAxisRight->isEnabledByChart()) { axesOut.push_back(m_chartAxisRight.get()); } } /** * Get the text for the axis label. * * @param axis * The cartesian axis. * @return * Text for the axis label. */ AString ChartTwoOverlaySet::getAxisLabel(const ChartTwoCartesianAxis* axis) const { if (axis == NULL) { return ""; } AString label; const int32_t overlayTitleIndex = axis->getLabelOverlayIndex(m_numberOfDisplayedOverlays); const ChartTwoOverlay* chartOverlay = getOverlay(overlayTitleIndex); CaretMappableDataFile* mapFile = chartOverlay->getSelectedMapFile(); if (mapFile != NULL) { switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: switch (axis->getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: label = mapFile->getChartingDelegate()->getHistogramCharting()->getBottomAxisTitle(); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: label = mapFile->getChartingDelegate()->getHistogramCharting()->getLeftRightAxisTitle(); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: label = mapFile->getChartingDelegate()->getHistogramCharting()->getLeftRightAxisTitle(); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: CaretAssert(0); break; } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: switch (axis->getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: label = mapFile->getChartingDelegate()->getLineSeriesCharting()->getBottomAxisTitle(); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: label = mapFile->getChartingDelegate()->getLineSeriesCharting()->getLeftRightAxisTitle(); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: label = mapFile->getChartingDelegate()->getLineSeriesCharting()->getLeftRightAxisTitle(); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: CaretAssert(0); break; } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; } } return label; } /** * Set the text for the axis label. * * @param axis * The cartesian axis. * @param label * New text for the axis label. */ void ChartTwoOverlaySet::setAxisLabel(const ChartTwoCartesianAxis* axis, const AString& label) { const int32_t overlayTitleIndex = axis->getLabelOverlayIndex(m_numberOfDisplayedOverlays); const ChartTwoOverlay* chartOverlay = getOverlay(overlayTitleIndex); CaretMappableDataFile* mapFile = chartOverlay->getSelectedMapFile(); if (mapFile != NULL) { switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: switch (axis->getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: mapFile->getChartingDelegate()->getHistogramCharting()->setBottomAxisTitle(label); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: mapFile->getChartingDelegate()->getHistogramCharting()->setLeftRightAxisTitle(label); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: mapFile->getChartingDelegate()->getHistogramCharting()->setLeftRightAxisTitle(label); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: CaretAssert(0); break; } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: switch (axis->getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: mapFile->getChartingDelegate()->getLineSeriesCharting()->setBottomAxisTitle(label); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: mapFile->getChartingDelegate()->getLineSeriesCharting()->setLeftRightAxisTitle(label); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: mapFile->getChartingDelegate()->getLineSeriesCharting()->setLeftRightAxisTitle(label); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: CaretAssert(0); break; } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; } } } /** * @return The chart title. */ ChartTwoTitle* ChartTwoOverlaySet::getChartTitle() { return m_title.get(); } /** * @return The chart title. */ const ChartTwoTitle* ChartTwoOverlaySet::getChartTitle() const { return m_title.get(); } /** * @return Thickness of box around chart and tick marks on axes */ float ChartTwoOverlaySet::getAxisLineThickness() const { return m_axisLineThickness; } /** * Set Thickness of box around chart and tick marks on axes * * @param axisLineThickness * New value for Thickness of box around chart and tick marks on axes */ void ChartTwoOverlaySet::setAxisLineThickness(const float axisLineThickness) { m_axisLineThickness = axisLineThickness; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* ChartTwoOverlaySet::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ChartTwoOverlaySet", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); const int32_t numOverlaysToSave = getNumberOfDisplayedOverlays(); std::vector overlayClassVector; for (int i = 0; i < numOverlaysToSave; i++) { overlayClassVector.push_back(m_overlays[i]->saveToScene(sceneAttributes, "m_overlays")); } SceneClassArray* overlayClassArray = new SceneClassArray("m_overlays", overlayClassVector); sceneClass->addChild(overlayClassArray); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ChartTwoOverlaySet::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_title->reset(); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); /* * Title was originally saved as text and boolean */ const SceneClass* oldChartTitleClass = sceneClass->getClass("m_chartTitle"); if (oldChartTitleClass != NULL) { if (oldChartTitleClass->getClassName() == "AnnotationPercentSizeText") { std::unique_ptr title = std::unique_ptr(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT)); title->setText(""); title->restoreFromScene(sceneAttributes, oldChartTitleClass); m_title->setText(title->getText()); m_title->setDisplayed(sceneClass->getBooleanValue("m_chartTitleDisplayedFlag", false)); } } const SceneClassArray* overlayClassArray = sceneClass->getClassArray("m_overlays"); if (overlayClassArray != NULL) { const int32_t numOverlays = std::min(overlayClassArray->getNumberOfArrayElements(), (int32_t)BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS); for (int32_t i = 0; i < numOverlays; i++) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, i); m_overlays[i]->restoreFromScene(sceneAttributes, overlayClassArray->getClassAtIndex(i)); } } //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Brain/ChartTwoOverlaySet.h000066400000000000000000000142331360521144700234020ustar00rootroot00000000000000#ifndef __CHART_TWO_OVERLAY_SET_H__ #define __CHART_TWO_OVERLAY_SET_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "BrainConstants.h" #include "CaretObject.h" #include "ChartAxisLocationEnum.h" #include "ChartTwoDataTypeEnum.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" namespace caret { class AnnotationPercentSizeText; class CaretMappableDataFile; class ChartTwoCartesianAxis; class ChartTwoOverlay; class ChartTwoTitle; class PlainTextStringBuilder; class SceneClassAssistant; class ChartTwoOverlaySet : public CaretObject, public EventListenerInterface, public SceneableInterface { public: ChartTwoOverlaySet(const ChartTwoDataTypeEnum::Enum chartDataType, const AString& name, const int32_t tabIndex); virtual ~ChartTwoOverlaySet(); void copyOverlaySet(const ChartTwoOverlaySet* overlaySet); void copyCartesianAxes(const ChartTwoOverlaySet* overlaySet); ChartTwoOverlay* getPrimaryOverlay(); const ChartTwoOverlay* getPrimaryOverlay() const; ChartTwoOverlay* getOverlay(const int32_t overlayNumber); const ChartTwoOverlay* getOverlay(const int32_t overlayNumber) const; std::weak_ptr getOverlayWeakPointer(const int32_t overlayNumber); std::vector getDisplayedOverlays() const; std::vector getEnabledOverlays() const; void addDisplayedOverlay(); int32_t getNumberOfDisplayedOverlays() const; ChartTwoOverlay* getDisplayedOverlayContainingDataFile(const CaretMappableDataFile* mapFile); void getDisplayedChartAxes(std::vector& axesOut) const; AString getAxisLabel(const ChartTwoCartesianAxis* axis) const; void setAxisLabel(const ChartTwoCartesianAxis* axis, const AString& label); bool isAxesSupportedByChartDataType() const; bool getDataRangeForAxis(const ChartAxisLocationEnum::Enum chartAxisLocation, float& minimumValueOut, float& maximumValueOut) const; ChartTwoTitle* getChartTitle(); const ChartTwoTitle* getChartTitle() const; void insertOverlayAbove(const int32_t overlayIndex); void insertOverlayBelow(const int32_t overlayIndex); void removeDisplayedOverlay(const int32_t overlayIndex); void moveDisplayedOverlayUp(const int32_t overlayIndex); void moveDisplayedOverlayDown(const int32_t overlayIndex); void initializeOverlays(); void resetOverlayYokingToOff(); float getAxisLineThickness() const; void setAxisLineThickness(const float axisLineThickness); // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual void getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const; virtual void receiveEvent(Event* event); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implementation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: ChartTwoOverlaySet(const ChartTwoOverlaySet&); ChartTwoOverlaySet& operator=(const ChartTwoOverlaySet&); void firstOverlaySelectionChanged(); SceneClassAssistant* m_sceneAssistant; std::vector> m_overlays; const ChartTwoDataTypeEnum::Enum m_chartDataType; std::unique_ptr m_chartAxisLeft; std::unique_ptr m_chartAxisRight; std::unique_ptr m_chartAxisBottom; const AString m_name; const int32_t m_tabIndex; std::unique_ptr m_title; int32_t m_numberOfDisplayedOverlays; bool m_inFirstOverlayChangedMethodFlag = false; /** Thickness of box around chart and tick marks on axes*/ float m_axisLineThickness = 0.5; // ADD_NEW_MEMBERS_HERE friend class ChartTwoOverlay; }; #ifdef __CHART_TWO_OVERLAY_SET_DECLARE__ // #endif // __CHART_TWO_OVERLAY_SET_DECLARE__ } // namespace #endif //__CHART_TWO_OVERLAY_SET_H__ connectome-workbench-1.4.2/src/Brain/ChartTwoOverlaySetArray.cxx000066400000000000000000000237671360521144700247700ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_TWO_OVERLAY_SET_ARRAY_DECLARE__ #include "ChartTwoOverlaySetArray.h" #undef __CHART_TWO_OVERLAY_SET_ARRAY_DECLARE__ #include "BrainConstants.h" #include "CaretAssert.h" #include "ChartTwoOverlaySet.h" #include "EventBrowserTabDelete.h" #include "EventManager.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" using namespace caret; /** * \class caret::ChartTwoOverlaySetArray * \brief Maintains an array of chart overlay sets for use with a model * \ingroup Brain */ /** * Constructor. * * @param chartDataType * Type of charts allowed in this overlay * @param name * Name of model using this chart overlay set. This name is displayed * if there is an attempt to yoke models with incompatible chart overlays. */ ChartTwoOverlaySetArray::ChartTwoOverlaySetArray(const ChartTwoDataTypeEnum::Enum chartDataType, const AString& name) : CaretObject(), EventListenerInterface(), m_name(name) { m_chartOverlaySets.resize(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); for (int32_t tabIndex = 0; tabIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; tabIndex++) { m_chartOverlaySets[tabIndex] = new ChartTwoOverlaySet(chartDataType, name, tabIndex); } EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_DELETE); } /** * Destructor. */ ChartTwoOverlaySetArray::~ChartTwoOverlaySetArray() { EventManager::get()->removeAllEventsFromListener(this); for (std::vector::iterator iter =m_chartOverlaySets.begin(); iter !=m_chartOverlaySets.end(); iter++) { delete *iter; } m_chartOverlaySets.clear(); } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ChartTwoOverlaySetArray::toString() const { return "ChartTwoOverlaySetArray"; } /** * @return The number of chart overlay sets. */ int32_t ChartTwoOverlaySetArray::getNumberOfChartOverlaySets() { return m_chartOverlaySets.size(); } /** * Get the chart overlay set at the given index. * * @param tabIndex * Index of chart overlay tab. * @return * Overlay set at given index. */ ChartTwoOverlaySet* ChartTwoOverlaySetArray::getChartTwoOverlaySet(const int32_t tabIndex) { CaretAssertVectorIndex(m_chartOverlaySets, tabIndex); return m_chartOverlaySets[tabIndex]; } /** * Initialize the chart overlay selections. */ void ChartTwoOverlaySetArray::initializeOverlaySelections() { for (int32_t iTab = 0; iTab < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; iTab++) { CaretAssertVectorIndex(m_chartOverlaySets, iTab); m_chartOverlaySets[iTab]->initializeOverlays(); } } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void ChartTwoOverlaySetArray::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_DELETE) { EventBrowserTabDelete* deleteTabEvent = dynamic_cast(event); CaretAssert(deleteTabEvent); /* * Since tab is being deleted, reset any chart overlay yoking for the tab. */ const int32_t tabIndex = deleteTabEvent->getBrowserTabIndex(); if ((tabIndex > 0) && (tabIndex < getNumberOfChartOverlaySets())) { m_chartOverlaySets[tabIndex]->resetOverlayYokingToOff(); } deleteTabEvent->setEventProcessed(); } } /** * Copy the chart overlay set from the source tab index to the * destination tab index. * * @param sourceTabIndex * Source from which tab content is copied. * @param destinationTabIndex * Destination to which tab content is copied. */ void ChartTwoOverlaySetArray::copyChartOverlaySet(const int32_t sourceTabIndex, const int32_t destinationTabIndex) { CaretAssertVectorIndex(m_chartOverlaySets, sourceTabIndex); CaretAssertVectorIndex(m_chartOverlaySets, destinationTabIndex); const ChartTwoOverlaySet* sourceChartOverlaySet =m_chartOverlaySets[sourceTabIndex]; ChartTwoOverlaySet* destinationChartOverlaySet =m_chartOverlaySets[destinationTabIndex]; destinationChartOverlaySet->copyOverlaySet(sourceChartOverlaySet); } /** * Copy the chart overlay set cartesian axes from the source tab index to the * destination tab index. * * @param sourceTabIndex * Source from which tab content is copied. * @param destinationTabIndex * Destination to which tab content is copied. */ void ChartTwoOverlaySetArray::copyChartOverlaySetCartesianAxes(const int32_t sourceTabIndex, const int32_t destinationTabIndex) { CaretAssertVectorIndex(m_chartOverlaySets, sourceTabIndex); CaretAssertVectorIndex(m_chartOverlaySets, destinationTabIndex); const ChartTwoOverlaySet* sourceChartOverlaySet =m_chartOverlaySets[sourceTabIndex]; ChartTwoOverlaySet* destinationChartOverlaySet =m_chartOverlaySets[destinationTabIndex]; destinationChartOverlaySet->copyCartesianAxes(sourceChartOverlaySet); } /** * Save information specific to this type of model to the scene. * * @param tabIndices * Tab indices that are valid. * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* ChartTwoOverlaySetArray::saveTabIndicesToScene(const std::vector& tabIndices, const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ChartTwoOverlaySetArray", 1); /* * Save overlay sets for tabs */ SceneObjectMapIntegerKey* overlaySetMap = new SceneObjectMapIntegerKey("m_chartOverlaySetMAP", SceneObjectDataTypeEnum::SCENE_CLASS); for (const auto tabIndex : tabIndices) { overlaySetMap->addClass(tabIndex, m_chartOverlaySets[tabIndex]->saveToScene(sceneAttributes, "m_chartOverlaySet")); } sceneClass->addChild(overlaySetMap); // const int32_t numOverlaySetsToSave = getNumberOfChartOverlaySets(); // // std::vector overlaySetVector; // for (int i = 0; i < numOverlaySetsToSave; i++) { // overlaySetVector.push_back(m_chartOverlaySets[i]->saveToScene(sceneAttributes, // "m_chartOverlaySet")); // } // // SceneClassArray* overlaySetArray = new SceneClassArray("m_chartOverlaySets", // overlaySetVector); // sceneClass->addChild(overlaySetArray); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ChartTwoOverlaySetArray::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } const SceneObjectMapIntegerKey* overlaySetMap = sceneClass->getMapIntegerKey("m_chartOverlaySetMAP"); if (overlaySetMap != NULL) { const std::vector tabIndices = overlaySetMap->getKeys(); for (const auto tabIndex : tabIndices) { const SceneClass* sceneClass = overlaySetMap->classValue(tabIndex); CaretAssertVectorIndex(m_chartOverlaySets, tabIndex); m_chartOverlaySets[tabIndex]->restoreFromScene(sceneAttributes, sceneClass); } } // const SceneClassArray* overlaySetArray = sceneClass->getClassArray("m_chartOverlaySets"); // if (overlaySetArray != NULL) { // const int32_t numOverlaySets = std::min(overlaySetArray->getNumberOfArrayElements(), // (int32_t)BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); // for (int32_t i = 0; i < numOverlaySets; i++) { // m_chartOverlaySets[i]->restoreFromScene(sceneAttributes, // overlaySetArray->getClassAtIndex(i)); // } // } //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Brain/ChartTwoOverlaySetArray.h000066400000000000000000000060661360521144700244060ustar00rootroot00000000000000#ifndef __CHART_TWO_OVERLAY_SET_ARRAY_H__ #define __CHART_TWO_OVERLAY_SET_ARRAY_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "ChartTwoDataTypeEnum.h" #include "EventListenerInterface.h" namespace caret { class ChartTwoOverlaySet; class SceneAttributes; class SceneClass; class ChartTwoOverlaySetArray : public CaretObject, public EventListenerInterface { public: ChartTwoOverlaySetArray(const ChartTwoDataTypeEnum::Enum chartDataType, const AString& name); virtual ~ChartTwoOverlaySetArray(); int32_t getNumberOfChartOverlaySets(); ChartTwoOverlaySet* getChartTwoOverlaySet(const int32_t indx); void initializeOverlaySelections(); void copyChartOverlaySet(const int32_t sourceTabIndex, const int32_t destinationTabIndex); void copyChartOverlaySetCartesianAxes(const int32_t sourceTabIndex, const int32_t destinationTabIndex); virtual SceneClass* saveTabIndicesToScene(const std::vector& tabIndices, const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: ChartTwoOverlaySetArray(const ChartTwoOverlaySetArray&); ChartTwoOverlaySetArray& operator=(const ChartTwoOverlaySetArray&); public: // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual void receiveEvent(Event* event); private: // ADD_NEW_MEMBERS_HERE void initialize(); /** Name for this chart overlay set array */ AString m_name; /** The chart overlay sets */ std::vectorm_chartOverlaySets; }; #ifdef __CHART_TWO_OVERLAY_SET_ARRAY_DECLARE__ // #endif // __CHART_TWO_OVERLAY_SET_ARRAY_DECLARE__ } // namespace #endif //__CHART_TWO_OVERLAY_SET_ARRAY_H__ connectome-workbench-1.4.2/src/Brain/ChartingDataManager.cxx000066400000000000000000000167201360521144700240330ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHARTING_DATA_MANAGER_DECLARE__ #include "ChartingDataManager.h" #undef __CHARTING_DATA_MANAGER_DECLARE__ #include "Brain.h" #include "CaretAssert.h" #include "EventManager.h" #include "EventMapYokingSelectMap.h" #include "ModelChart.h" #include "ModelChartTwo.h" #include "SurfaceFile.h" using namespace caret; /** * \class caret::ChartingDataManager * \brief Manages charting data. * \ingroup Brain */ /** * Constructor. */ ChartingDataManager::ChartingDataManager(Brain* brain) : CaretObject(), m_brain(brain) { CaretAssert(brain); /* * Need PROCESSED event (after others have handled the event) */ EventManager::get()->addProcessedEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP); } /** * Destructor. */ ChartingDataManager::~ChartingDataManager() { EventManager::get()->removeAllEventsFromListener(this); } /** * Receive an event. * * @param event * The event that the receive can respond to. */ void ChartingDataManager::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP) { EventMapYokingSelectMap* yokeMapEvent = dynamic_cast(event); CaretAssert(yokeMapEvent); ModelChart* modelChart = m_brain->getChartModel(); if (modelChart != NULL) { modelChart->loadChartDataForYokedCiftiMappableFiles(yokeMapEvent->getMapYokingGroup(), yokeMapEvent->getMapIndex()); } ModelChartTwo* modelChartTwo = m_brain->getChartTwoModel(); if (modelChartTwo != NULL) { modelChartTwo->loadChartDataForYokedScalarDataSeriesFiles(yokeMapEvent->getMapYokingGroup(), yokeMapEvent->getMapIndex()); modelChartTwo->selectRowColumnInYokedScalarDataSeriesFileOverlay(yokeMapEvent->getMapYokingGroup(), yokeMapEvent->getMapIndex()); } } } /** * Load the average of chart data for a group of surface nodes. * * @param surfaceFile * The surface file * @param nodeIndices * Indices of nodes whose chart data is averaged */ void ChartingDataManager::loadAverageChartForSurfaceNodes(const SurfaceFile* surfaceFile, const std::vector& nodeIndices) const { CaretAssert(surfaceFile); ModelChart* modelChart = m_brain->getChartModel(); if (modelChart != NULL) { modelChart->loadAverageChartDataForSurfaceNodes(surfaceFile->getStructure(), surfaceFile->getNumberOfNodes(), nodeIndices); } ModelChartTwo* modelChartTwo = m_brain->getChartTwoModel(); if (modelChartTwo != NULL) { modelChartTwo->loadAverageChartDataForSurfaceNodes(surfaceFile->getStructure(), surfaceFile->getNumberOfNodes(), nodeIndices); } } /** * Load chart data for a surface node. * * @param surfaceFile * The surface file * @param nodeIndex * Index of node. */ void ChartingDataManager::loadChartForSurfaceNode(const SurfaceFile* surfaceFile, const int32_t nodeIndex) const { CaretAssert(surfaceFile); ModelChart* modelChart = m_brain->getChartModel(); if (modelChart != NULL) { modelChart->loadChartDataForSurfaceNode(surfaceFile->getStructure(), surfaceFile->getNumberOfNodes(), nodeIndex); } ModelChartTwo* modelChartTwo = m_brain->getChartTwoModel(); if (modelChartTwo != NULL) { modelChartTwo->loadChartDataForSurfaceNode(surfaceFile->getStructure(), surfaceFile->getNumberOfNodes(), nodeIndex); } } /** * Load chart data from given file at the given row. * * @param ciftiMapFile * The CIFTI file. * @param rowIndex * Index of row in the file. */ void ChartingDataManager::loadChartForCiftiMappableFileRow(CiftiMappableDataFile* ciftiMapFile, const int32_t rowIndex) const { CaretAssert(ciftiMapFile); ModelChart* modelChart = m_brain->getChartModel(); if (modelChart != NULL) { modelChart->loadChartDataForCiftiMappableFileRow(ciftiMapFile, rowIndex); } ModelChartTwo* modelChartTwo = m_brain->getChartTwoModel(); if (modelChartTwo != NULL) { modelChartTwo->loadChartDataForCiftiMappableFileRow(ciftiMapFile, rowIndex); } } /** * Load chart data for a voxel. * * @param xyz * Coordinate of voxel. */ void ChartingDataManager::loadChartForVoxelAtCoordinate(const float xyz[3]) const { ModelChart* modelChart = m_brain->getChartModel(); if (modelChart != NULL) { modelChart->loadChartDataForVoxelAtCoordinate(xyz); } ModelChartTwo* modelChartTwo = m_brain->getChartTwoModel(); if (modelChartTwo != NULL) { modelChartTwo->loadChartDataForVoxelAtCoordinate(xyz); } } /** * @return True if there are charting that retrieve data from the network. */ bool ChartingDataManager::hasNetworkFiles() const { /* * At this time, all 'chartable' files are read in their entirety * so all data is local once the file is read. */ return false; // std::vector chartFiles; // if (requireChartingEnableInFiles) { // m_brain->getAllChartableDataFilesWithChartingEnabled(chartFiles); // } // else { // m_brain->getAllChartableDataFiles(chartFiles); // } // // for (std::vector::iterator fileIter = chartFiles.begin(); // fileIter != chartFiles.end(); // fileIter++) { // ChartableLineSeriesBrainordinateInterface* chartFile = *fileIter; // // CaretDataFile* caretDataFile = dynamic_cast(chartFile); // CaretAssert(caretDataFile); // if (caretDataFile->isEmpty() == false) { // const AString filename = caretDataFile->getFileName(); // if (CaretDataFile::isFileOnNetwork(filename)) { // return true; // } // } // } // // return false; } connectome-workbench-1.4.2/src/Brain/ChartingDataManager.h000066400000000000000000000045041360521144700234550ustar00rootroot00000000000000#ifndef __CHARTING_DATA_MANAGER_H__ #define __CHARTING_DATA_MANAGER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "EventListenerInterface.h" namespace caret { class Brain; class CiftiMappableDataFile; class SurfaceFile; class ChartingDataManager : public CaretObject, public EventListenerInterface { public: ChartingDataManager(Brain* brain); virtual ~ChartingDataManager(); void loadAverageChartForSurfaceNodes(const SurfaceFile* surfaceFile, const std::vector& nodeIndices) const; void loadChartForSurfaceNode(const SurfaceFile* surfaceFile, const int32_t nodeIndex) const; void loadChartForVoxelAtCoordinate(const float xyz[3]) const; void loadChartForCiftiMappableFileRow(CiftiMappableDataFile* ciftiMapFile, const int32_t rowIndex) const; bool hasNetworkFiles() const; virtual void receiveEvent(Event* event); private: ChartingDataManager(const ChartingDataManager&); ChartingDataManager& operator=(const ChartingDataManager&); Brain* m_brain; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHARTING_DATA_MANAGER_DECLARE__ // #endif // __CHARTING_DATA_MANAGER_DECLARE__ } // namespace #endif //__CHARTING_DATA_MANAGER_H__ connectome-workbench-1.4.2/src/Brain/CiftiConnectivityMatrixDataFileManager.cxx000066400000000000000000000461271360521144700277220ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CIFTI_CONNECTIVITY_MATRIX_DATA_FILE_MANAGER_DECLARE__ #include "CiftiConnectivityMatrixDataFileManager.h" #undef __CIFTI_CONNECTIVITY_MATRIX_DATA_FILE_MANAGER_DECLARE__ #include "Brain.h" #include "CaretAssert.h" #include "CiftiConnectivityMatrixParcelFile.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "EventBrowserTabGetAllViewed.h" #include "EventGetDisplayedDataFiles.h" #include "EventManager.h" #include "EventSurfaceColoringInvalidate.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "ScenePrimitiveArray.h" #include "Surface.h" #include "SurfaceFile.h" using namespace caret; /** * \class caret::CiftiConnectivityMatrixDataFileManager * \brief Manages loading data from cifti connectivity files * \ingroup Brain */ /** * Constructor. * * @param brain * Brain that uses this instance. */ CiftiConnectivityMatrixDataFileManager::CiftiConnectivityMatrixDataFileManager() : CaretObject() { } /** * Destructor. */ CiftiConnectivityMatrixDataFileManager::~CiftiConnectivityMatrixDataFileManager() { } /** * Get the connectivity files that are displayed. * * @param brain * Brain for which data is loaded. * @param ciftiMatrixFilesOut * Output with displayed files. */ void CiftiConnectivityMatrixDataFileManager::getDisplayedConnectivityMatrixFiles(Brain* brain, std::vector& ciftiMatrixFilesOut) const { ciftiMatrixFilesOut.clear(); /* * WB-633 New requirements for updating of connectivity data * Implementation on hold and explained in Jira. * * 7/15/2016 - USE ALL FILES, DO NOT TEST FOR DISPLAYED VS NOT-DISPLAYED FILES */ const bool allFilesFlag = true; if (allFilesFlag) { /* * All cifti matrix files, even if not displayed? */ brain->getAllCiftiConnectivityMatrixFiles(ciftiMatrixFilesOut); return; } std::vector ciftiMatrixFiles; brain->getAllCiftiConnectivityMatrixFiles(ciftiMatrixFiles); /* * Get all browser tabs and only save transformations for tabs * that are valid. */ EventBrowserTabGetAllViewed getViewedTabs; EventManager::get()->sendEvent(getViewedTabs.getPointer()); std::vector tabIndices = getViewedTabs.getViewdedBrowserTabIndices(); std::vector windowIndices; // empty is all windows EventGetDisplayedDataFiles displayedFilesEvent(windowIndices, tabIndices); EventManager::get()->sendEvent(displayedFilesEvent.getPointer()); std::set displayedDataFiles = displayedFilesEvent.getDisplayedDataFiles(); /* * Find CIFTI matrix files that are displayed in an overlay */ for (std::vector::iterator iter = ciftiMatrixFiles.begin(); iter != ciftiMatrixFiles.end(); iter++) { if (std::find(displayedDataFiles.begin(), displayedDataFiles.end(), *iter) != displayedDataFiles.end()) { ciftiMatrixFilesOut.push_back(*iter); } } } /** * Load row from the given parcel file. * * @param brain * Brain for which data is loaded. * @param parcelFile * The parcel file. * @param rowIndex * Index of the row. * @param columnIndex * Index of the column. * @param rowColumnInformationOut * Appends one string for each row/column loaded * @return * true if success, else false. */ bool CiftiConnectivityMatrixDataFileManager::loadRowOrColumnFromParcelFile(Brain* brain, CiftiConnectivityMatrixParcelFile* parcelFile, const int32_t rowIndex, const int32_t columnIndex, std::vector& rowColumnInformationOut) { CaretAssert(parcelFile); int32_t rowColumnIndexToLoad = -1; switch (parcelFile->getMatrixLoadingDimension()) { case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: rowColumnIndexToLoad = columnIndex; break; case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: rowColumnIndexToLoad = rowIndex; break; } /* * If yoked, find other files yoked to the same group */ const YokingGroupEnum::Enum selectedYokingGroup = parcelFile->getYokingGroup(); std::vector parcelFilesToLoadFrom; if (selectedYokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) { for (int32_t i = 0; i < brain->getNumberOfConnectivityMatrixParcelFiles(); i++) { CiftiConnectivityMatrixParcelFile* pf = brain->getConnectivityMatrixParcelFile(i); if (pf->getYokingGroup() == selectedYokingGroup) { parcelFilesToLoadFrom.push_back(pf); } } } else { parcelFilesToLoadFrom.push_back(parcelFile); } const int32_t mapIndex = 0; /* * Load row/color for the "parcelFile" and any other files with * which it is yoked. */ for (std::vector::iterator iter = parcelFilesToLoadFrom.begin(); iter != parcelFilesToLoadFrom.end(); iter++) { CiftiConnectivityMatrixParcelFile* pf = *iter; switch (pf->getMatrixLoadingDimension()) { case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: pf->loadDataForColumnIndex(rowColumnIndexToLoad); pf->updateScalarColoringForMap(mapIndex); rowColumnInformationOut.push_back(pf->getFileNameNoPath() + " column index=" + AString::number(rowColumnIndexToLoad + CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI())); break; case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: pf->loadDataForRowIndex(rowColumnIndexToLoad); pf->updateScalarColoringForMap(mapIndex); rowColumnInformationOut.push_back(pf->getFileNameNoPath() + " row index=" + AString::number(rowColumnIndexToLoad + CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI())); break; } } return true; } bool CiftiConnectivityMatrixDataFileManager::loadRowOrColumnFromConnectivityMatrixFile( CiftiMappableConnectivityMatrixDataFile* ciftiConnMatrixFile, const int32_t rowIndex, const int32_t columnIndex, std::vector& rowColumnInformationOut) { const int32_t mapIndex = 0; if (rowIndex >= 0) { ciftiConnMatrixFile->loadDataForRowIndex(rowIndex); ciftiConnMatrixFile->updateScalarColoringForMap(mapIndex); rowColumnInformationOut.push_back(ciftiConnMatrixFile->getFileNameNoPath() + " row index=" + AString::number(rowIndex + CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI())); } else if (columnIndex >= 0) { ciftiConnMatrixFile->loadDataForColumnIndex(columnIndex); ciftiConnMatrixFile->updateScalarColoringForMap(mapIndex); rowColumnInformationOut.push_back(ciftiConnMatrixFile->getFileNameNoPath() + " column index=" + AString::number(columnIndex + CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI())); } return true; } /** * Load data for the given surface node index. * @param brain * Brain for which data is loaded. * @param surfaceFile * Surface File that contains the node (uses its structure). * @param nodeIndex * Index of the surface node. * @param rowColumnInformationOut * Appends one string for each row/column loaded * @return * true if any connectivity loaders are active, else false. */ bool CiftiConnectivityMatrixDataFileManager::loadDataForSurfaceNode(Brain* brain, const SurfaceFile* surfaceFile, const int32_t nodeIndex, std::vector& rowColumnInformationOut) { std::vector ciftiMatrixFiles; getDisplayedConnectivityMatrixFiles(brain, ciftiMatrixFiles); bool haveData = false; for (std::vector::iterator iter = ciftiMatrixFiles.begin(); iter != ciftiMatrixFiles.end(); iter++) { CiftiMappableConnectivityMatrixDataFile* cmf = *iter; if (cmf->isEmpty() == false) { const int32_t mapIndex = 0; int64_t rowIndex = -1; int64_t columnIndex = -1; cmf->loadMapDataForSurfaceNode(mapIndex, surfaceFile->getNumberOfNodes(), surfaceFile->getStructure(), nodeIndex, rowIndex, columnIndex); cmf->updateScalarColoringForMap(mapIndex); haveData = true; if (rowIndex >= 0) { /* * Get row/column info for node */ rowColumnInformationOut.push_back(cmf->getFileNameNoPath() + " vertex index=" + AString::number(nodeIndex) + ", row index=" + AString::number(rowIndex + CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI())); } else if (columnIndex >= 0) { /* * Get row/column info for node */ rowColumnInformationOut.push_back(cmf->getFileNameNoPath() + " vertex index=" + AString::number(nodeIndex) + ", column index=" + AString::number(columnIndex + CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI())); } } } if (haveData) { EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); } return haveData; } /** * Load data for each of the given surface node indices and average the data. * @param brain * Brain for which data is loaded. * @param surfaceFile * Surface File that contains the node (uses its structure). * @param nodeIndices * Indices of the surface nodes. * @return * true if any connectivity loaders are active, else false. */ bool CiftiConnectivityMatrixDataFileManager::loadAverageDataForSurfaceNodes(Brain* brain, const SurfaceFile* surfaceFile, const std::vector& nodeIndices) { std::vector ciftiMatrixFiles; getDisplayedConnectivityMatrixFiles(brain, ciftiMatrixFiles); bool haveData = false; for (std::vector::iterator iter = ciftiMatrixFiles.begin(); iter != ciftiMatrixFiles.end(); iter++) { CiftiMappableConnectivityMatrixDataFile* cmf = *iter; if (cmf->isEmpty() == false) { const int32_t mapIndex = 0; cmf->loadMapAverageDataForSurfaceNodes(mapIndex, surfaceFile->getNumberOfNodes(), surfaceFile->getStructure(), nodeIndices); cmf->updateScalarColoringForMap(mapIndex); haveData = true; } } if (haveData) { EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); } return haveData; } /** * Load data for the voxel near the given coordinate. * @param brain * Brain for which data is loaded. * @param xyz * Coordinate of voxel. * @param rowColumnInformationOut * Appends one string for each row/column loaded * @return * true if any connectivity loaders are active, else false. */ bool CiftiConnectivityMatrixDataFileManager::loadDataForVoxelAtCoordinate(Brain* brain, const float xyz[3], std::vector& rowColumnInformationOut) { std::vector ciftiMatrixFiles; getDisplayedConnectivityMatrixFiles(brain, ciftiMatrixFiles); bool haveData = false; for (std::vector::iterator iter = ciftiMatrixFiles.begin(); iter != ciftiMatrixFiles.end(); iter++) { CiftiMappableConnectivityMatrixDataFile* cmf = *iter; if (cmf->isEmpty() == false) { const int32_t mapIndex = 0; int64_t rowIndex; int64_t columnIndex; cmf->loadMapDataForVoxelAtCoordinate(mapIndex, xyz, rowIndex, columnIndex); cmf->updateScalarColoringForMap(mapIndex); haveData = true; if (rowIndex >= 0) { /* * Get row/column info for node */ rowColumnInformationOut.push_back(cmf->getFileNameNoPath() + " Voxel XYZ=" + AString::fromNumbers(xyz, 3, ",") + ", row index=" + AString::number(rowIndex + CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI())); } else if (columnIndex >= 0) { /* * Get row/column info for node */ rowColumnInformationOut.push_back(cmf->getFileNameNoPath() + " Voxel XYZ=" + AString::fromNumbers(xyz, 3, ",") + ", column index=" + AString::number(columnIndex + CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI())); } } } if (haveData) { EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); } return haveData; } /** * Load average data for the given voxel indices. * * @param brain * Brain for which data is loaded. * @param volumeDimensionIJK * Dimensions of the volume. * @param voxelIndices * Indices for averaging of data. * @return * true if any data was loaded, else false. * @throw DataFileException * If an error occurs. */ bool CiftiConnectivityMatrixDataFileManager::loadAverageDataForVoxelIndices(Brain* brain, const int64_t volumeDimensionIJK[3], const std::vector& voxelIndices) { std::vector ciftiMatrixFiles; getDisplayedConnectivityMatrixFiles(brain, ciftiMatrixFiles); bool haveData = false; for (std::vector::iterator iter = ciftiMatrixFiles.begin(); iter != ciftiMatrixFiles.end(); iter++) { CiftiMappableConnectivityMatrixDataFile* cmf = *iter; if (cmf->isEmpty() == false) { const int32_t mapIndex = 0; if (cmf->loadMapAverageDataForVoxelIndices(mapIndex, volumeDimensionIJK, voxelIndices)) { } haveData = true; cmf->updateScalarColoringForMap(mapIndex); } } if (haveData) { EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); } return haveData; } /** * @param brain * Brain for containing network files. * * @return True if there are enabled connectivity * files that retrieve data from the network. */ bool CiftiConnectivityMatrixDataFileManager::hasNetworkFiles(Brain* brain) const { std::vector ciftiMatrixFiles; getDisplayedConnectivityMatrixFiles(brain, ciftiMatrixFiles); for (std::vector::iterator iter = ciftiMatrixFiles.begin(); iter != ciftiMatrixFiles.end(); iter++) { CiftiMappableConnectivityMatrixDataFile* cmdf = *iter; if (cmdf->isEmpty() == false) { if (DataFile::isFileOnNetwork(cmdf->getFileName())) { const int32_t numMaps = cmdf->getNumberOfMaps(); for (int32_t i = 0; i < numMaps; i++) { if (cmdf->isMapDataLoadingEnabled(i)) { return true; } } } } } return false; } connectome-workbench-1.4.2/src/Brain/CiftiConnectivityMatrixDataFileManager.h000066400000000000000000000075561360521144700273520ustar00rootroot00000000000000#ifndef __CIFTI_CONNECTIVITY_MATRIX_DATA_FILE_MANAGER_H__ #define __CIFTI_CONNECTIVITY_MATRIX_DATA_FILE_MANAGER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "VoxelIJK.h" namespace caret { class Brain; class CiftiConnectivityMatrixParcelFile; class CiftiMappableConnectivityMatrixDataFile; class SurfaceFile; class CiftiConnectivityMatrixDataFileManager : public CaretObject { public: CiftiConnectivityMatrixDataFileManager(); virtual ~CiftiConnectivityMatrixDataFileManager(); bool loadDataForSurfaceNode(Brain* brain, const SurfaceFile* surfaceFile, const int32_t nodeIndex, std::vector& rowColumnInformationOut); bool loadAverageDataForSurfaceNodes(Brain* brain, const SurfaceFile* surfaceFile, const std::vector& nodeIndices); bool loadDataForVoxelAtCoordinate(Brain* brain, const float xyz[3], std::vector& rowColumnInformationOut); bool loadAverageDataForVoxelIndices(Brain* brain, const int64_t volumeDimensionIJK[3], const std::vector& voxelIndices); bool loadRowOrColumnFromParcelFile(Brain* brain, CiftiConnectivityMatrixParcelFile* ciftiConnMatrixFile, const int32_t rowIndex, const int32_t columnIndex, std::vector& rowColumnInformationOut); bool loadRowOrColumnFromConnectivityMatrixFile(CiftiMappableConnectivityMatrixDataFile* parcelFile, const int32_t rowIndex, const int32_t columnIndex, std::vector& rowColumnInformationOut); bool hasNetworkFiles(Brain* brain) const; private: CiftiConnectivityMatrixDataFileManager(const CiftiConnectivityMatrixDataFileManager&); CiftiConnectivityMatrixDataFileManager& operator=(const CiftiConnectivityMatrixDataFileManager&); public: // ADD_NEW_METHODS_HERE private: void getDisplayedConnectivityMatrixFiles(Brain* brain, std::vector& ciftiMatrixFilesOut) const; // ADD_NEW_MEMBERS_HERE }; #ifdef __CIFTI_CONNECTIVITY_MATRIX_DATA_FILE_MANAGER_DECLARE__ // #endif // __CIFTI_CONNECTIVITY_MATRIX_DATA_FILE_MANAGER_DECLARE__ } // namespace #endif //__CIFTI_CONNECTIVITY_MATRIX_DATA_FILE_MANAGER_H__ connectome-workbench-1.4.2/src/Brain/CiftiFiberTrajectoryManager.cxx000066400000000000000000000165301360521144700255560ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CIFTI_FIBER_TRAJECTORY_MANAGER_DECLARE__ #include "CiftiFiberTrajectoryManager.h" #undef __CIFTI_FIBER_TRAJECTORY_MANAGER_DECLARE__ #include "Brain.h" #include "CaretAssert.h" #include "CiftiFiberOrientationFile.h" #include "CiftiFiberTrajectoryFile.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SurfaceFile.h" using namespace caret; /** * \class caret::CiftiFiberTrajectoryManager * \brief Manages loading of trajectory data. * \ingroup Brain */ /** * Constructor. */ CiftiFiberTrajectoryManager::CiftiFiberTrajectoryManager() : CaretObject() { } /** * Destructor. */ CiftiFiberTrajectoryManager::~CiftiFiberTrajectoryManager() { } /** * Load data for the given surface node index. * * @param surfaceFile * Surface File that contains the node (uses its structure). * @param nodeIndex * Index of the surface node. * @return * true if any data was loaded, else false. */ bool CiftiFiberTrajectoryManager::loadDataForSurfaceNode(Brain* brain, const SurfaceFile* surfaceFile, const int32_t nodeIndex, std::vector& rowColumnInformationOut) { bool dataWasLoaded = false; /* * Load fiber trajectory data */ const int32_t numTrajFiles = brain->getNumberOfConnectivityFiberTrajectoryFiles(); for (int32_t iTrajFileIndex = 0; iTrajFileIndex < numTrajFiles; iTrajFileIndex++) { CiftiFiberTrajectoryFile* trajFile = brain->getConnectivityFiberTrajectoryFile(iTrajFileIndex); const int64_t rowIndex = trajFile->loadDataForSurfaceNode(surfaceFile->getStructure(), surfaceFile->getNumberOfNodes(), nodeIndex); if (rowIndex >= 0) { /* * Get row/column info for node */ rowColumnInformationOut.push_back(trajFile->getFileNameNoPath() + " nodeIndex=" + AString::number(nodeIndex) + ", row index= " + AString::number(rowIndex)); dataWasLoaded = true; } } return dataWasLoaded; } /** * Load data for the given surface node index. * * @param surfaceFile * Surface File that contains the node (uses its structure). * @param nodeIndex * Index of the surface node. * @return * true if any data was loaded, else false. */ bool CiftiFiberTrajectoryManager::loadDataAverageForSurfaceNodes(Brain* brain, const SurfaceFile* surfaceFile, const std::vector& nodeIndices) { bool dataWasLoaded = false; AString errorMessage; /* * Load fiber trajectory data */ const int32_t numTrajFiles = brain->getNumberOfConnectivityFiberTrajectoryFiles(); for (int32_t iTrajFileIndex = 0; iTrajFileIndex < numTrajFiles; iTrajFileIndex++) { CiftiFiberTrajectoryFile* trajFile = brain->getConnectivityFiberTrajectoryFile(iTrajFileIndex); try { trajFile->loadDataAverageForSurfaceNodes(surfaceFile->getStructure(), surfaceFile->getNumberOfNodes(), nodeIndices); dataWasLoaded = true; } catch (const DataFileException& dfe) { errorMessage.appendWithNewLine(dfe.whatString()); } } if (errorMessage.isEmpty() == false) { throw DataFileException(errorMessage); } return dataWasLoaded; } /** * Load data for the voxel near the given coordinate. * @param xyz * Coordinate of voxel. * @param rowColumnInformationOut * Appends one string for each row/column loaded * @return * true if any connectivity loaders are active, else false. */ bool CiftiFiberTrajectoryManager::loadDataForVoxelAtCoordinate(Brain* brain, const float xyz[3], std::vector& rowColumnInformationOut) { std::vector ciftiTrajFiles; brain->getConnectivityFiberTrajectoryFiles(ciftiTrajFiles); bool haveData = false; for (std::vector::iterator iter = ciftiTrajFiles.begin(); iter != ciftiTrajFiles.end(); iter++) { CiftiFiberTrajectoryFile* trajFile = *iter; if (trajFile->isEmpty() == false) { const int64_t rowIndex = trajFile->loadMapDataForVoxelAtCoordinate(xyz); if (rowIndex >= 0) { /* * Get row/column info for node */ rowColumnInformationOut.push_back(trajFile->getFileNameNoPath() + " Voxel XYZ=" + AString::fromNumbers(xyz, 3, ",") + ", row index= " + AString::number(rowIndex)); haveData = true; } } } return haveData; } /** * Load average data for the given voxel indices. * * @param volumeDimensionIJK * Dimensions of the volume. * @param voxelIndices * Indices for averaging of data. * @return * true if any data was loaded, else false. * @throw DataFileException * If an error occurs. */ bool CiftiFiberTrajectoryManager::loadAverageDataForVoxelIndices(Brain* brain, const int64_t volumeDimensionIJK[3], const std::vector& voxelIndices) { std::vector ciftiTrajFiles; brain->getConnectivityFiberTrajectoryFiles(ciftiTrajFiles); bool haveData = false; for (std::vector::iterator iter = ciftiTrajFiles.begin(); iter != ciftiTrajFiles.end(); iter++) { CiftiFiberTrajectoryFile* trajFile = *iter; if (trajFile->isEmpty() == false) { trajFile->loadMapAverageDataForVoxelIndices(volumeDimensionIJK, voxelIndices); haveData = true; } } return haveData; } connectome-workbench-1.4.2/src/Brain/CiftiFiberTrajectoryManager.h000066400000000000000000000051401360521144700251760ustar00rootroot00000000000000#ifndef __CIFTI_FIBER_TRAJECTORY_MANAGER_H__ #define __CIFTI_FIBER_TRAJECTORY_MANAGER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "VoxelIJK.h" namespace caret { class Brain; class SurfaceFile; class CiftiFiberTrajectoryManager : public CaretObject { public: CiftiFiberTrajectoryManager(); virtual ~CiftiFiberTrajectoryManager(); bool loadDataForSurfaceNode(Brain* brain, const SurfaceFile* surfaceFile, const int32_t nodeIndex, std::vector& rowColumnInformationOut); bool loadDataAverageForSurfaceNodes(Brain* brain, const SurfaceFile* surfaceFile, const std::vector& nodeIndices); bool loadDataForVoxelAtCoordinate(Brain* brain, const float xyz[3], std::vector& rowColumnInformationOut); bool loadAverageDataForVoxelIndices(Brain* brain, const int64_t volumeDimensionIJK[3], const std::vector& voxelIndices); // ADD_NEW_METHODS_HERE private: CiftiFiberTrajectoryManager(const CiftiFiberTrajectoryManager&); CiftiFiberTrajectoryManager& operator=(const CiftiFiberTrajectoryManager&); // ADD_NEW_MEMBERS_HERE }; #ifdef __CIFTI_FIBER_TRAJECTORY_MANAGER_DECLARE__ // #endif // __CIFTI_FIBER_TRAJECTORY_MANAGER_DECLARE__ } // namespace #endif //__CIFTI_FIBER_TRAJECTORY_MANAGER_H__ connectome-workbench-1.4.2/src/Brain/ClippingPlaneGroup.cxx000066400000000000000000000556121360521144700237540ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CLIPPING_PLANE_GROUP_DECLARE__ #include "ClippingPlaneGroup.h" #undef __CLIPPING_PLANE_GROUP_DECLARE__ #include "CaretAssert.h" #include "Plane.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ClippingPlaneGroup * \brief A group of clipping plane for clipping to a rectangular region * \ingroup Brain */ /** * Constructor. */ ClippingPlaneGroup::ClippingPlaneGroup() : CaretObject() { invalidateActiveClippingPlainEquations(); resetToDefaultValues(); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_displayClippingBoxStatus", &m_displayClippingBoxStatus); m_sceneAssistant->addArray("m_translation", m_translation, 3, 0.0); m_sceneAssistant->addArray("m_thickness", m_thickness, 3, 20.0); m_sceneAssistant->add("m_xAxisSelectionStatus", &m_xAxisSelectionStatus); m_sceneAssistant->add("m_yAxisSelectionStatus", &m_yAxisSelectionStatus); m_sceneAssistant->add("m_zAxisSelectionStatus", &m_zAxisSelectionStatus); m_sceneAssistant->add("m_surfaceSelectionStatus", &m_surfaceSelectionStatus); m_sceneAssistant->add("m_volumeSelectionStatus", &m_volumeSelectionStatus); m_sceneAssistant->add("m_featuresSelectionStatus", &m_featuresSelectionStatus); } /** * Destructor. */ ClippingPlaneGroup::~ClippingPlaneGroup() { delete m_sceneAssistant; invalidateActiveClippingPlainEquations(); } /** * Copy constructor. * @param obj * Object that is copied. */ ClippingPlaneGroup::ClippingPlaneGroup(const ClippingPlaneGroup& obj) : CaretObject(obj), SceneableInterface() { this->copyHelperClippingPlaneGroup(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ClippingPlaneGroup& ClippingPlaneGroup::operator=(const ClippingPlaneGroup& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperClippingPlaneGroup(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ClippingPlaneGroup::copyHelperClippingPlaneGroup(const ClippingPlaneGroup& obj) { for (int32_t i = 0; i < 3; i++) { m_translation[i] = obj.m_translation[i]; m_thickness[i] = obj.m_thickness[i]; } m_rotationMatrix = obj.m_rotationMatrix; m_xAxisSelectionStatus = obj.m_xAxisSelectionStatus; m_yAxisSelectionStatus = obj.m_yAxisSelectionStatus; m_zAxisSelectionStatus = obj.m_zAxisSelectionStatus; m_surfaceSelectionStatus = obj.m_surfaceSelectionStatus; m_volumeSelectionStatus = obj.m_volumeSelectionStatus; m_featuresSelectionStatus = obj.m_featuresSelectionStatus; m_displayClippingBoxStatus = obj.m_displayClippingBoxStatus; invalidateActiveClippingPlainEquations(); } /** * Reset the transformation. */ void ClippingPlaneGroup::resetTransformation() { for (int32_t i = 0; i < 3; i++) { m_translation[i] = 0.0; } m_thickness[0] = 180.0; m_thickness[1] = 250.0; m_thickness[2] = 220.0; m_rotationMatrix.identity(); invalidateActiveClippingPlainEquations(); } /** * Reset member values. */ void ClippingPlaneGroup::resetToDefaultValues() { resetTransformation(); m_displayClippingBoxStatus = false; m_xAxisSelectionStatus = false; m_yAxisSelectionStatus = false; m_zAxisSelectionStatus = false; m_surfaceSelectionStatus = true; m_volumeSelectionStatus = true; m_featuresSelectionStatus = true; invalidateActiveClippingPlainEquations(); } /** * @return The X-coordinate for the structure. * * @param structure * The structure. Note that right and left hemispheres are mirror flipped. */ float ClippingPlaneGroup::getXCoordinateForStructure(const StructureEnum::Enum structure) const { float x = m_translation[0]; if (StructureEnum::isLeft(structure)) { x = -x; } return x; } /** * Create the plane equation for the given plane identifier. * * @param planeIdentifier * Identifies plane that is created. * @param structure * The structure. Note that right and left hemispheres are mirror flipped. */ Plane* ClippingPlaneGroup::createClippingPlane(const PlaneIdentifier planeIdentifier, const StructureEnum::Enum structure) const { float normalVector[3] = { 0.0, 0.0, 0.0 }; float pointOnPlane[3] = { 0.0, 0.0, 0.0 }; /* * Note: the planes form a rectangular cuboid and we want to * clip what is OUTSIDE this rectangular cuboid. */ switch (planeIdentifier) { case PLANE_MINIMUM_X: /* * X Minimum */ normalVector[0] = 1.0; pointOnPlane[0] = getXCoordinateForStructure(structure) - (m_thickness[0] / 2.0); break; case PLANE_MAXIMUM_X: /* * X Maximum */ normalVector[0] = -1.0; pointOnPlane[0] = getXCoordinateForStructure(structure) + (m_thickness[0] / 2.0); break; case PLANE_MINIMUM_Y: /* * Y Minimum */ normalVector[1] = 1.0; pointOnPlane[1] = m_translation[1] - (m_thickness[1] / 2.0); break; case PLANE_MAXIMUM_Y: /* * Y Maximum */ normalVector[1] = -1.0; pointOnPlane[1] = m_translation[1] + (m_thickness[1] / 2.0); break; case PLANE_MINIMUM_Z: /* * Z Minimum */ normalVector[2] = 1.0; pointOnPlane[2] = m_translation[2] - (m_thickness[2] / 2.0); break; case PLANE_MAXIMUM_Z: /* * Z Maximum */ normalVector[2] = -1.0; pointOnPlane[2] = m_translation[2] + (m_thickness[2] / 2.0); break; default: CaretAssert(0); } Matrix4x4 rotMat = getRotationMatrixForStructure(structure); rotMat.multiplyPoint3(normalVector); rotMat.multiplyPoint3(pointOnPlane); Plane* plane = new Plane(normalVector, pointOnPlane); return plane; } /** * @return Planes representing the active clipping planes for the given * structure. * * @param structure * The structure. Note that right and left hemispheres are mirror flipped. */ std::vector ClippingPlaneGroup::getActiveClippingPlanesForStructure(const StructureEnum::Enum structure) const { updateActiveClippingPlainEquations(); std::vector planes; if (StructureEnum::isRight(structure)) { planes.insert(planes.end(), m_rightStructureActiveClippingPlanes.begin(), m_rightStructureActiveClippingPlanes.end()); } else { planes.insert(planes.end(), m_activeClippingPlanes.begin(), m_activeClippingPlanes.end()); } return planes; } /** * @return The rotation matrix. * * @param structure * Structure for the rotation matrix. A 'right' structure has rotations * 'mirror flipped'. */ Matrix4x4 ClippingPlaneGroup::getRotationMatrixForStructure(const StructureEnum::Enum structure) const { if (StructureEnum::isRight(structure)) { double rotationX, rotationY, rotationZ; m_rotationMatrix.getRotation(rotationX, rotationY, rotationZ); const int flipMode = 2; switch (flipMode) { case 1: rotationY = 180.0 - rotationY; rotationZ = 180.0 - rotationZ; break; case 2: rotationY = -rotationY; rotationZ = -rotationZ; break; case 3: rotationY = 180.0 - rotationY; rotationZ = -rotationZ; break; case 4: rotationY = - rotationY; rotationZ = 180.0 -rotationZ; break; } Matrix4x4 mat; mat.setRotation(rotationX, rotationY, rotationZ); return mat; // const double rotationFlippedY = 180.0 - rotationY; // const double rotationFlippedZ = 180.0 - rotationZ; // Matrix4x4 mat; // mat.setRotation(rotationX, //rotationFlippedX, // rotationFlippedY, // rotationFlippedZ); // return mat; } return m_rotationMatrix; } /** * Replace the rotation matrix. * * @param rotationMatrix * New rotation matrix. */ void ClippingPlaneGroup::setRotationMatrix(const Matrix4x4& rotationMatrix) { m_rotationMatrix = rotationMatrix; invalidateActiveClippingPlainEquations(); } /** * Get the rotation matrix using the given angles. * * @param rotationAngles * The X, Y, and Z rotation angles. */ void ClippingPlaneGroup::getRotationAngles(float rotationAngles[3]) const { double x, y, z; m_rotationMatrix.getRotation(x, y, z); rotationAngles[0] = x; rotationAngles[1] = y; rotationAngles[2] = z; } /** * Set the rotation matrix using the given angles. * * @param rotationAngles * The X, Y, and Z rotation angles. */ void ClippingPlaneGroup::setRotationAngles(const float rotationAngles[3]) { m_rotationMatrix.setRotation(rotationAngles[0], rotationAngles[1], rotationAngles[2]); invalidateActiveClippingPlainEquations(); } /** * Get the thickness values * * @param thickness * The thickness values. */ void ClippingPlaneGroup::getThickness(float thickness[3]) const { thickness[0] = m_thickness[0]; thickness[1] = m_thickness[1]; thickness[2] = m_thickness[2]; } /** * Set the translation values. * * @param translation * The translation values. */ void ClippingPlaneGroup::setTranslation(const float translation[3]) { m_translation[0] = translation[0]; m_translation[1] = translation[1]; m_translation[2] = translation[2]; invalidateActiveClippingPlainEquations(); } /** * Get the translation values * * @param translation * The translation values. */ void ClippingPlaneGroup::getTranslation(float translation[3]) const { translation[0] = m_translation[0]; translation[1] = m_translation[1]; translation[2] = m_translation[2]; } /** * Get the translation values for the given structure. * * @param structure * The structure. Note that right and left hemispheres are mirror flipped. * @param translation * The translation values. */ void ClippingPlaneGroup::getTranslationForStructure(const StructureEnum::Enum structure, float translation[3]) const { getTranslation(translation); translation[0] = getXCoordinateForStructure(structure); } /** * Set the thickness values. * * @param thickness * The thickness values. */ void ClippingPlaneGroup::setThickness(const float thickness[3]) { m_thickness[0] = thickness[0]; m_thickness[1] = thickness[1]; m_thickness[2] = thickness[2]; invalidateActiveClippingPlainEquations(); } /** * @return Is surface selected for clipping? */ bool ClippingPlaneGroup::isSurfaceSelected() const { return m_surfaceSelectionStatus; } /** * Set surface selected * * @param selected * New status. */ void ClippingPlaneGroup::setSurfaceSelected(const bool selected) { m_surfaceSelectionStatus = selected; invalidateActiveClippingPlainEquations(); } /** * @return Is volume selected for clipping? */ bool ClippingPlaneGroup::isVolumeSelected() const { return m_volumeSelectionStatus; } /** * Set volume selected * * @param selected * New status. */ void ClippingPlaneGroup::setVolumeSelected(const bool selected) { m_volumeSelectionStatus = selected; invalidateActiveClippingPlainEquations(); } /** * @return Is features selected for clipping? */ bool ClippingPlaneGroup::isFeaturesSelected() const { return m_featuresSelectionStatus; } /** * Set display clipping box selected * * @param selected * New status. */ void ClippingPlaneGroup::setDisplayClippingBoxSelected(const bool selected) { m_displayClippingBoxStatus = selected; invalidateActiveClippingPlainEquations(); } /** * @return Is display clipping box selected? */ bool ClippingPlaneGroup::isDisplayClippingBoxSelected() const { return m_displayClippingBoxStatus; } /** * @return Is features and any one or more axes selected for clipping? */ bool ClippingPlaneGroup::isFeaturesAndAnyAxisSelected() const { if (m_featuresSelectionStatus) { if (m_xAxisSelectionStatus || m_yAxisSelectionStatus || m_zAxisSelectionStatus) { return true; } } return false; } /** * Set features selected * * @param selected * New status. */ void ClippingPlaneGroup::setFeaturesSelected(const bool selected) { m_featuresSelectionStatus = selected; } /** * @return Is the X clipping axis selected? */ bool ClippingPlaneGroup::isXAxisSelected() const { return m_xAxisSelectionStatus; } /** * @return Is the Y clipping axis selected? */ bool ClippingPlaneGroup::isYAxisSelected() const { return m_yAxisSelectionStatus; } /** * @return Is the Z clipping axis selected? */ bool ClippingPlaneGroup::isZAxisSelected() const { return m_zAxisSelectionStatus; } /** * Set the selection status for the X-axis. * * @param xAxisSelected * New selection status for the X-axis. */ void ClippingPlaneGroup::setXAxisSelected(const bool xAxisSelected) { m_xAxisSelectionStatus = xAxisSelected; invalidateActiveClippingPlainEquations(); } /** * Set the selection status for the Y-axis. * * @param yAxisSelected * New selection status for the Y-axis. */ void ClippingPlaneGroup::setYAxisSelected(const bool yAxisSelected) { m_yAxisSelectionStatus = yAxisSelected; invalidateActiveClippingPlainEquations(); } /** * Set the selection status for the Z-axis. * * @param zAxisSelected * New selection status for the Z-axis. */ void ClippingPlaneGroup::setZAxisSelected(const bool zAxisSelected) { m_zAxisSelectionStatus = zAxisSelected; invalidateActiveClippingPlainEquations(); } /** * Is the coordinate inside the clipping planes? * * If a clipping plane for an axis is off, the coordinate is considered * to be inside the clipping plane. * * @param structure * The structure. Note that right and left hemispheres are mirror flipped. * @param xyz * The coordinate. * * @return * True if inside the clipping planes, else false. */ bool ClippingPlaneGroup::isCoordinateInsideClippingPlanesForStructure(const StructureEnum::Enum structure, const float xyz[3]) const { updateActiveClippingPlainEquations(); if (StructureEnum::isRight(structure)) { for (std::vector::iterator iter = m_rightStructureActiveClippingPlanes.begin(); iter != m_rightStructureActiveClippingPlanes.end(); iter++) { const Plane* plane = *iter; if (plane->signedDistanceToPlane(xyz) < 0.0) { return false; } } return true; } for (std::vector::iterator iter = m_activeClippingPlanes.begin(); iter != m_activeClippingPlanes.end(); iter++) { const Plane* plane = *iter; if (plane->signedDistanceToPlane(xyz) < 0.0) { return false; } } // USE THE CLIPPING PLANES EQUATIONS !!!! // if (m_xAxisSelectionStatus) { // const float x = getXCoordinateForStructure(structure); // const float minX = x - (m_thickness[0] / 2.0); // const float maxX = x + (m_thickness[0] / 2.0); // if (xyz[0] < minX) return false; // if (xyz[0] > maxX) return false; // } // // if (m_yAxisSelectionStatus) { // const float minY = m_translation[1] - (m_thickness[1] / 2.0); // const float maxY = m_translation[1] + (m_thickness[1] / 2.0); // if (xyz[1] < minY) return false; // if (xyz[1] > maxY) return false; // } // // if (m_zAxisSelectionStatus) { // const float minZ = m_translation[2] - (m_thickness[2] / 2.0); // const float maxZ = m_translation[2] + (m_thickness[2] / 2.0); // if (xyz[2] < minZ) return false; // if (xyz[2] > maxZ) return false; // } return true; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ClippingPlaneGroup::toString() const { return "ClippingPlaneGroup"; } /** * Update the active clipping planes. */ void ClippingPlaneGroup::updateActiveClippingPlainEquations() const { if (m_activeClippingPlanesValid) { return; } if (m_xAxisSelectionStatus) { m_activeClippingPlanes.push_back(createClippingPlane(PLANE_MINIMUM_X, StructureEnum::CORTEX_LEFT)); m_activeClippingPlanes.push_back(createClippingPlane(PLANE_MAXIMUM_X, StructureEnum::CORTEX_LEFT)); m_rightStructureActiveClippingPlanes.push_back(createClippingPlane(PLANE_MINIMUM_X, StructureEnum::CORTEX_RIGHT)); m_rightStructureActiveClippingPlanes.push_back(createClippingPlane(PLANE_MAXIMUM_X, StructureEnum::CORTEX_RIGHT)); } if (m_yAxisSelectionStatus) { m_activeClippingPlanes.push_back(createClippingPlane(PLANE_MINIMUM_Y, StructureEnum::CORTEX_LEFT)); m_activeClippingPlanes.push_back(createClippingPlane(PLANE_MAXIMUM_Y, StructureEnum::CORTEX_LEFT)); m_rightStructureActiveClippingPlanes.push_back(createClippingPlane(PLANE_MINIMUM_Y, StructureEnum::CORTEX_RIGHT)); m_rightStructureActiveClippingPlanes.push_back(createClippingPlane(PLANE_MAXIMUM_Y, StructureEnum::CORTEX_RIGHT)); } if (m_zAxisSelectionStatus) { m_activeClippingPlanes.push_back(createClippingPlane(PLANE_MINIMUM_Z, StructureEnum::CORTEX_LEFT)); m_activeClippingPlanes.push_back(createClippingPlane(PLANE_MAXIMUM_Z, StructureEnum::CORTEX_LEFT)); m_rightStructureActiveClippingPlanes.push_back(createClippingPlane(PLANE_MINIMUM_Z, StructureEnum::CORTEX_RIGHT)); m_rightStructureActiveClippingPlanes.push_back(createClippingPlane(PLANE_MAXIMUM_Z, StructureEnum::CORTEX_RIGHT)); } m_activeClippingPlanesValid = true; } /** * Invalidate and remove all of the active clipping planes. */ void ClippingPlaneGroup::invalidateActiveClippingPlainEquations() { m_activeClippingPlanesValid = false; for (std::vector::iterator iter = m_activeClippingPlanes.begin(); iter != m_activeClippingPlanes.end(); iter++) { delete *iter; } m_activeClippingPlanes.clear(); for (std::vector::iterator iter = m_rightStructureActiveClippingPlanes.begin(); iter != m_rightStructureActiveClippingPlanes.end(); iter++) { delete *iter; } m_rightStructureActiveClippingPlanes.clear(); } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* ClippingPlaneGroup::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ClippingPlaneGroup", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); float m[4][4]; m_rotationMatrix.getMatrix(m); sceneClass->addFloatArray("m_rotationMatrix", &m[0][0], 16); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ClippingPlaneGroup::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { resetToDefaultValues(); if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); float m[4][4]; const int32_t numElem = sceneClass->getFloatArrayValue("m_rotationMatrix", &m[0][0], 16); if (numElem == 16) { m_rotationMatrix.setMatrix(m); } else { m_rotationMatrix.identity(); } //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Brain/ClippingPlaneGroup.h000066400000000000000000000141651360521144700233770ustar00rootroot00000000000000#ifndef __CLIPPING_PLANE_GROUP_H__ #define __CLIPPING_PLANE_GROUP_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "Matrix4x4.h" #include "SceneableInterface.h" #include "StructureEnum.h" namespace caret { class Plane; class SceneClassAssistant; class ClippingPlaneGroup : public CaretObject, public SceneableInterface { public: ClippingPlaneGroup(); virtual ~ClippingPlaneGroup(); ClippingPlaneGroup(const ClippingPlaneGroup& obj); ClippingPlaneGroup& operator=(const ClippingPlaneGroup& obj); void resetTransformation(); void resetToDefaultValues(); std::vector getActiveClippingPlanesForStructure(const StructureEnum::Enum structure) const; void getTranslation(float translation[3]) const; void setTranslation(const float translation[3]); void getTranslationForStructure(const StructureEnum::Enum structure, float translation[3]) const; Matrix4x4 getRotationMatrixForStructure(const StructureEnum::Enum structure) const; void setRotationMatrix(const Matrix4x4& rotationMatrix); void getRotationAngles(float rotationAngles[3]) const; void setRotationAngles(const float rotationAngles[3]); void setRotation(const float rotation[4][4]); void getThickness(float thickness[3]) const; void setThickness(const float thickness[3]); bool isXAxisSelected() const; bool isYAxisSelected() const; bool isZAxisSelected() const; void setXAxisSelected(const bool xAxisSelected); void setYAxisSelected(const bool yAxisSelected); void setZAxisSelected(const bool zAxisSelected); bool isDisplayClippingBoxSelected() const; void setDisplayClippingBoxSelected(const bool selected); bool isSurfaceSelected() const; void setSurfaceSelected(const bool selected); bool isVolumeSelected() const; void setVolumeSelected(const bool selected); bool isFeaturesSelected() const; bool isFeaturesAndAnyAxisSelected() const; void setFeaturesSelected(const bool selected); bool isCoordinateInsideClippingPlanesForStructure(const StructureEnum::Enum structure, const float xyz[3]) const; // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implemetation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: enum PlaneIdentifier { PLANE_MINIMUM_X, PLANE_MAXIMUM_X, PLANE_MINIMUM_Y, PLANE_MAXIMUM_Y, PLANE_MINIMUM_Z, PLANE_MAXIMUM_Z }; void copyHelperClippingPlaneGroup(const ClippingPlaneGroup& obj); Plane* createClippingPlane(const PlaneIdentifier planeIdentifier, const StructureEnum::Enum structure) const; void updateActiveClippingPlainEquations() const; void invalidateActiveClippingPlainEquations(); /** * For all everthing EXCEPT right structures */ mutable std::vector m_activeClippingPlanes; /** * Mirror flipped for RIGHT structure */ mutable std::vector m_rightStructureActiveClippingPlanes; mutable bool m_activeClippingPlanesValid; SceneClassAssistant* m_sceneAssistant; float getXCoordinateForStructure(const StructureEnum::Enum structure) const; float m_translation[3]; Matrix4x4 m_rotationMatrix; float m_thickness[3]; bool m_xAxisSelectionStatus; bool m_yAxisSelectionStatus; bool m_zAxisSelectionStatus; bool m_surfaceSelectionStatus; bool m_volumeSelectionStatus; bool m_featuresSelectionStatus; bool m_displayClippingBoxStatus; // ADD_NEW_MEMBERS_HERE }; #ifdef __CLIPPING_PLANE_GROUP_DECLARE__ // #endif // __CLIPPING_PLANE_GROUP_DECLARE__ } // namespace #endif //__CLIPPING_PLANE_GROUP_H__ connectome-workbench-1.4.2/src/Brain/DataToolTipsManager.cxx000066400000000000000000000167411360521144700240540ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __DATA_TOOL_TIPS_MANAGER_DECLARE__ #include "DataToolTipsManager.h" #undef __DATA_TOOL_TIPS_MANAGER_DECLARE__ #include "Brain.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "EventManager.h" #include "IdentificationStringBuilder.h" #include "IdentificationTextGenerator.h" #include "Overlay.h" #include "OverlaySet.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "SelectionManager.h" using namespace caret; /** * \class caret::DataToolTipsManager * \brief Manages Data ToolTips. * \ingroup Brain */ /** * Constructor. * * @param enabledStatus * Enabled status for data tool tips */ DataToolTipsManager::DataToolTipsManager(const bool enabledStatus) : CaretObject() { m_enabledFlag = enabledStatus; m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); /*EventManager::get()->addEventListener(this, EventTypeEnum::);*/ } /** * Destructor. */ DataToolTipsManager::~DataToolTipsManager() { EventManager::get()->removeAllEventsFromListener(this); } /** * Get text for the tooltip. * * @param brain * The Brain. * @param browserTab * Browser tab in which tooltip is displayed * @param selectionManager * The selection manager. */ AString DataToolTipsManager::getToolTip(const Brain* brain, const BrowserTabContent* browserTab, const SelectionManager* selectionManager) const { CaretAssert(brain); CaretAssert(browserTab); CaretAssert(selectionManager); IdentificationTextGenerator itg; const AString text = itg.createToolTipText(brain, browserTab, selectionManager, this); return text; } /** * @return Is tips enabled? */ bool DataToolTipsManager::isEnabled() const { return m_enabledFlag; } /** * Set status for tips enabled * * @param status * New status. */ void DataToolTipsManager::setEnabled(const bool status) { m_enabledFlag = status; } /** * @return Is show primary anatomical surface enabled? */ bool DataToolTipsManager::isShowSurfacePrimaryAnatomical() const { return m_showSurfacePrimaryAnatomicalFlag; } /** * Set status for primary anatomical surface enabled * * @param status * New status. */ void DataToolTipsManager::setShowSurfacePrimaryAnatomical(const bool status) { m_showSurfacePrimaryAnatomicalFlag = status; } /** * @return Is show viewed surface enabled? */ bool DataToolTipsManager::isShowSurfaceViewed() const { return m_showSurfaceViewedFlag; } /** * Set status for viewed surface enabled * * @param status * New status. */ void DataToolTipsManager::setShowSurfaceViewed(const bool status) { m_showSurfaceViewedFlag = status; } /** * @return Is show volume underlayenabled? */ bool DataToolTipsManager::isShowVolumeUnderlay() const { return m_showVolumeUnderlayFlag; } /** * Set status for volume underlay enabled * * @param status * New status. */ void DataToolTipsManager::setShowVolumeUnderlay(const bool status) { m_showVolumeUnderlayFlag = status; } /** * @return Is show top enabled layer enabled? */ bool DataToolTipsManager::isShowTopEnabledLayer() const { return m_showTopEnabledLayerFlag; } /** * Set status for top layer enabled * * @param status * New status. */ void DataToolTipsManager::setShowTopEnabledLayer(const bool status) { m_showTopEnabledLayerFlag = status; } /** * @return Is show border enabled? */ bool DataToolTipsManager::isShowBorder() const { return m_showBorderFlag; } /** * Set status for show border * * @param status * New status. */ void DataToolTipsManager::setShowBorder(const bool status) { m_showBorderFlag = status; } /** * @return Is show focus enabled? */ bool DataToolTipsManager::isShowFocus() const { return m_showFocusFlag; } /** * Set status for show focus * * @param status * New status. */ void DataToolTipsManager::setShowFocus(const bool status) { m_showFocusFlag = status; } /** * @return Is show chart enabled? */ bool DataToolTipsManager::isShowChart() const { return m_showChartFlag; } /** * Set status for show chart * * @param status * New status. */ void DataToolTipsManager::setShowChart(const bool status) { m_showChartFlag = status; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString DataToolTipsManager::toString() const { return "DataToolTipsManager"; } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void DataToolTipsManager::receiveEvent(Event* /*event*/) { // if (event->getEventType() == EventTypeEnum::) { // eventName = dynamic_cast(event); // CaretAssert(eventName); // // event->setEventProcessed(); // } } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* DataToolTipsManager::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "DataToolTipsManager", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void DataToolTipsManager::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Brain/DataToolTipsManager.h000066400000000000000000000105331360521144700234720ustar00rootroot00000000000000#ifndef __DATA_TOOL_TIPS_MANAGER_H__ #define __DATA_TOOL_TIPS_MANAGER_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" namespace caret { class Brain; class BrowserTabContent; class SceneClassAssistant; class SelectionItemSurfaceNode; class SelectionItemVoxel; class SelectionManager; class DataToolTipsManager : public CaretObject, public EventListenerInterface, public SceneableInterface { public: DataToolTipsManager(const bool enabledStatus); virtual ~DataToolTipsManager(); DataToolTipsManager(const DataToolTipsManager&) = delete; DataToolTipsManager& operator=(const DataToolTipsManager&) = delete; AString getToolTip(const Brain* brain, const BrowserTabContent* browserTab, const SelectionManager* selectionManager) const; bool isEnabled() const; void setEnabled(const bool status); bool isShowSurfacePrimaryAnatomical() const; void setShowSurfacePrimaryAnatomical(const bool status); bool isShowSurfaceViewed() const; void setShowSurfaceViewed(const bool status); bool isShowVolumeUnderlay() const; void setShowVolumeUnderlay(const bool status); bool isShowTopEnabledLayer() const; void setShowTopEnabledLayer(const bool status); bool isShowBorder() const; void setShowBorder(const bool status); bool isShowFocus() const; void setShowFocus(const bool status); bool isShowChart() const; void setShowChart(const bool status); // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual void receiveEvent(Event* event); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implementation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: std::unique_ptr m_sceneAssistant; bool m_enabledFlag = true; bool m_showSurfacePrimaryAnatomicalFlag = true; bool m_showSurfaceViewedFlag = true; bool m_showVolumeUnderlayFlag = true; bool m_showTopEnabledLayerFlag = true; bool m_showBorderFlag = true; bool m_showFocusFlag = true; bool m_showChartFlag = true; // ADD_NEW_MEMBERS_HERE }; #ifdef __DATA_TOOL_TIPS_MANAGER_DECLARE__ // #endif // __DATA_TOOL_TIPS_MANAGER_DECLARE__ } // namespace #endif //__DATA_TOOL_TIPS_MANAGER_H__ connectome-workbench-1.4.2/src/Brain/DisplayProperties.cxx000066400000000000000000000030321360521144700236610ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __DISPLAY_PROPERTIES_DECLARE__ #include "DisplayProperties.h" #undef __DISPLAY_PROPERTIES_DECLARE__ #include "SceneClassAssistant.h" using namespace caret; /** * \class DisplayProperties * \brief Base class for all display properties. * * Base class for all display properties. */ /** * Constructor. */ DisplayProperties::DisplayProperties() : CaretObject() { m_sceneAssistant = new SceneClassAssistant(); } /** * Destructor. */ DisplayProperties::~DisplayProperties() { delete m_sceneAssistant; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString DisplayProperties::toString() const { return "DisplayProperties"; } connectome-workbench-1.4.2/src/Brain/DisplayProperties.h000066400000000000000000000051421360521144700233120ustar00rootroot00000000000000#ifndef __DISPLAY_PROPERTIES__H_ #define __DISPLAY_PROPERTIES__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "SceneableInterface.h" namespace caret { class SceneClassAssistant; class DisplayProperties : public CaretObject, public SceneableInterface { protected: DisplayProperties(); public: virtual ~DisplayProperties(); /** * Reset all settings to their defaults * and remove any data. */ virtual void reset() = 0; /** * Update due to changes in data. */ virtual void update() = 0; /** * Copy the display properties. * * @param sourceTabIndex * Index of tab from which properties are copied. * @param targetTabIndex * Index of tab to which properties are copied. */ virtual void copyDisplayProperties(const int32_t sourceTabIndex, const int32_t targetTabIndex) = 0; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) = 0; virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) = 0; private: DisplayProperties(const DisplayProperties&); DisplayProperties& operator=(const DisplayProperties&); public: virtual AString toString() const; protected: SceneClassAssistant* m_sceneAssistant; }; #ifdef __DISPLAY_PROPERTIES_DECLARE__ // #endif // __DISPLAY_PROPERTIES_DECLARE__ } // namespace #endif //__DISPLAY_PROPERTIES__H_ connectome-workbench-1.4.2/src/Brain/DisplayPropertiesAnnotation.cxx000066400000000000000000000414541360521144700257260ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __DISPLAY_PROPERTIES_ANNOTATION_DECLARE__ #include "DisplayPropertiesAnnotation.h" #undef __DISPLAY_PROPERTIES_ANNOTATION_DECLARE__ #include "Annotation.h" #include "AnnotationManager.h" #include "Brain.h" #include "CaretLogger.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneClassAssistant.h" #include "SceneObjectMapIntegerKey.h" using namespace caret; /** * \class caret::DisplayPropertiesAnnotation * \brief Contains display properties for annotations. * \ingroup Brain */ /** * Constructor. */ DisplayPropertiesAnnotation::DisplayPropertiesAnnotation(Brain* parentBrain) : DisplayProperties(), m_parentBrain(parentBrain) { CaretAssert(parentBrain); resetPrivate(); m_sceneAssistant->add("m_displayAnnotations", &m_displayAnnotations); m_sceneAssistant->add("m_displayTextAnnotations", &m_displayTextAnnotations); m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_displayGroup", m_displayGroup); m_sceneAssistant->addArray("m_displayWindowAnnotationsInSingleTabViews", m_displayWindowAnnotationsInSingleTabViews, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, true); } /** * Destructor. */ DisplayPropertiesAnnotation::~DisplayPropertiesAnnotation() { } /** * Update the properties for a new/modified annotation. * * @param annotation * The new/updated annotation. */ void DisplayPropertiesAnnotation::updateForNewAnnotation(const Annotation* annotation) { CaretAssert(annotation); switch (annotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: setDisplayWindowAnnotationsInSingleTabViews(annotation->getWindowIndex(), true); break; } setDisplayAnnotations(true); } /** * Copy the border display properties from one tab to another. * @param sourceTabIndex * Index of tab from which properties are copied. * @param targetTabIndex * Index of tab to which properties are copied. */ void DisplayPropertiesAnnotation::copyDisplayProperties(const int32_t sourceTabIndex, const int32_t targetTabIndex) { const DisplayGroupEnum::Enum displayGroup = this->getDisplayGroupForTab(sourceTabIndex); this->setDisplayGroupForTab(targetTabIndex, displayGroup); } /** * Reset all settings to default. * NOTE: reset() is virtual so can/should not be called from constructor. */ void DisplayPropertiesAnnotation::resetPrivate() { m_displayAnnotations = true; m_displayTextAnnotations = true; for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS; i++) { m_displayWindowAnnotationsInSingleTabViews[i] = true; } for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_displayGroup[i] = DisplayGroupEnum::DISPLAY_GROUP_TAB; } } /** * Reset all settings to their defaults * and remove any data. */ void DisplayPropertiesAnnotation::reset() { resetPrivate(); } /** * Update due to changes in data. */ void DisplayPropertiesAnnotation::update() { } /** * @return Status for displaying annotations */ bool DisplayPropertiesAnnotation::isDisplayAnnotations() const { return m_displayAnnotations; } /** * Set the display status for annotations * * @param status * New display status. */ void DisplayPropertiesAnnotation::setDisplayAnnotations(const bool status) { m_displayAnnotations = status; } /** * @return Status for displaying text annotations */ bool DisplayPropertiesAnnotation::isDisplayTextAnnotations() const { return m_displayTextAnnotations; } /** * Set the display status for text annotations * * @param status * New display status. */ void DisplayPropertiesAnnotation::setDisplayTextAnnotations(const bool status) { m_displayTextAnnotations = status; } /** * Get the display group for a given browser tab. * @param browserTabIndex * Index of browser tab. */ DisplayGroupEnum::Enum DisplayPropertiesAnnotation::getDisplayGroupForTab(const int32_t browserTabIndex) const { CaretAssertArrayIndex(this->displayGroup, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); return m_displayGroup[browserTabIndex]; } /** * Set the display group for a given browser tab. * @param browserTabIndex * Index of browser tab. * @param displayGroup * New value for display group. */ void DisplayPropertiesAnnotation::setDisplayGroupForTab(const int32_t browserTabIndex, const DisplayGroupEnum::Enum displayGroup) { CaretAssertArrayIndex(this->displayGroup, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); m_displayGroup[browserTabIndex] = displayGroup; } /** * Is the window annotation displayed in the given window index? * * @param windowIndex * Index of the window. * @return * True if displayed, else false. */ bool DisplayPropertiesAnnotation::isDisplayWindowAnnotationsInSingleTabViews(const int32_t windowIndex) const { CaretAssertArrayIndex(m_displayWindowAnnotationsInSingleTabViews, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, windowIndex); return m_displayWindowAnnotationsInSingleTabViews[windowIndex]; } /** * Set the window annotation displayed in the given window index. * * @param windowIndex * Index of the tab. * @param status * True if displayed, else false. */ void DisplayPropertiesAnnotation::setDisplayWindowAnnotationsInSingleTabViews(const int32_t windowIndex, const bool status) { CaretAssertArrayIndex(m_displayWindowAnnotationsInSingleTabViews, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, windowIndex); m_displayWindowAnnotationsInSingleTabViews[windowIndex] = status; } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* DisplayPropertiesAnnotation::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { const std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); SceneClass* sceneClass = new SceneClass(instanceName, "DisplayPropertiesAnnotation", 2); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void DisplayPropertiesAnnotation::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); if (sceneClass->getVersionNumber() <= 1) { restoreVersionOne(sceneClass); } switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } } /** * Restore version one that contains a type display for each tab * (before the file->group->annotation hierarchy). * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void DisplayPropertiesAnnotation::restoreVersionOne(const SceneClass* sceneClass) { m_displayTextAnnotations = true; /* * Version one did not have display groups so default the display group * in each to to "Tab". */ for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_displayGroup[i] = DisplayGroupEnum::DISPLAY_GROUP_TAB; } /* * Default version one selections to "on" */ bool stereoStatusInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; bool surfaceStatusInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; bool tabStatusInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { stereoStatusInTab[i] = true; surfaceStatusInTab[i] = true; tabStatusInTab[i] = true; } /* * Look for version one selections in the scene */ const SceneObjectMapIntegerKey* stereoAnnDisplay = sceneClass->getMapIntegerKey("m_displayModelAnnotations"); if (stereoAnnDisplay != NULL) { const std::vector mapKeys = stereoAnnDisplay->getKeys(); for (std::vector::const_iterator keyIter = mapKeys.begin(); keyIter != mapKeys.end(); keyIter++) { stereoStatusInTab[*keyIter] = stereoAnnDisplay->booleanValue(*keyIter); } } const SceneObjectMapIntegerKey* surfaceAnnDisplay = sceneClass->getMapIntegerKey("m_displaySurfaceAnnotations"); if (surfaceAnnDisplay != NULL) { const std::vector mapKeys = surfaceAnnDisplay->getKeys(); for (std::vector::const_iterator keyIter = mapKeys.begin(); keyIter != mapKeys.end(); keyIter++) { surfaceStatusInTab[*keyIter] = surfaceAnnDisplay->booleanValue(*keyIter); } } const SceneObjectMapIntegerKey* tabAnnDisplay = sceneClass->getMapIntegerKey("m_displayTabAnnotations"); if (tabAnnDisplay != NULL) { const std::vector mapKeys = tabAnnDisplay->getKeys(); for (std::vector::const_iterator keyIter = mapKeys.begin(); keyIter != mapKeys.end(); keyIter++) { tabStatusInTab[*keyIter] = tabAnnDisplay->booleanValue(*keyIter); } } bool windowStatus[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS]; const int32_t numWindowStatus = sceneClass->getBooleanArrayValue("m_displayWindowAnnotations", windowStatus, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS); /* * Apply version one selections to the annotations. */ std::vector allAnnotations = m_parentBrain->getAnnotationManager()->getAllAnnotations(); for (std::vector::iterator annIter = allAnnotations.begin(); annIter != allAnnotations.end(); annIter++) { Annotation* ann = *annIter; switch (ann->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: CaretAssertMessage(0, "This should never happen as CHART SPACE was never available in a version one scene"); break; case AnnotationCoordinateSpaceEnum::SPACER: CaretAssertMessage(0, "This should never happen as SPACER TAB SPACE was never available in a version one scene"); break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: if (stereoAnnDisplay != NULL) { for (int32_t iTab = 0; iTab < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; iTab++) { TriStateSelectionStatusEnum::Enum triStatus = TriStateSelectionStatusEnum::UNSELECTED; if (stereoStatusInTab[iTab]) { triStatus = TriStateSelectionStatusEnum::SELECTED; } ann->setItemDisplaySelected(DisplayGroupEnum::DISPLAY_GROUP_TAB, iTab, triStatus); } } break; case AnnotationCoordinateSpaceEnum::SURFACE: if (surfaceAnnDisplay != NULL) { for (int32_t iTab = 0; iTab < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; iTab++) { TriStateSelectionStatusEnum::Enum triStatus = TriStateSelectionStatusEnum::UNSELECTED; if (surfaceStatusInTab[iTab]) { triStatus = TriStateSelectionStatusEnum::SELECTED; } ann->setItemDisplaySelected(DisplayGroupEnum::DISPLAY_GROUP_TAB, iTab, triStatus); } } break; case AnnotationCoordinateSpaceEnum::TAB: if (tabAnnDisplay != NULL) { const int32_t tabIndex = ann->getTabIndex(); if ((tabIndex >= 0) && (tabIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)) { TriStateSelectionStatusEnum::Enum triStatus = TriStateSelectionStatusEnum::UNSELECTED; if (tabStatusInTab[tabIndex]) { triStatus = TriStateSelectionStatusEnum::SELECTED; } ann->setItemDisplaySelected(DisplayGroupEnum::DISPLAY_GROUP_TAB, tabIndex, triStatus); } } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: /* * Ignore annotations in viewport space. These are usually text annotations * in the graphics region such as chart labels. */ break; case AnnotationCoordinateSpaceEnum::WINDOW: if (numWindowStatus) { const int32_t windowIndex = ann->getWindowIndex(); if ((windowIndex >= 0) && (windowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)) { TriStateSelectionStatusEnum::Enum triStatus = TriStateSelectionStatusEnum::UNSELECTED; if (windowStatus[windowIndex]) { triStatus = TriStateSelectionStatusEnum::SELECTED; } /* * Note: For window annotations, the display group * and tab are ignored. Window status is set using * the window index contained in the annotation. */ const int32_t tabIndex = 0; ann->setItemDisplaySelected(DisplayGroupEnum::DISPLAY_GROUP_TAB, tabIndex, triStatus); } } break; } } } connectome-workbench-1.4.2/src/Brain/DisplayPropertiesAnnotation.h000066400000000000000000000070141360521144700253450ustar00rootroot00000000000000#ifndef __DISPLAY_PROPERTIES_ANNOTATION_H__ #define __DISPLAY_PROPERTIES_ANNOTATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "DisplayGroupEnum.h" #include "DisplayProperties.h" namespace caret { class Annotation; class Brain; class DisplayPropertiesAnnotation : public DisplayProperties { public: DisplayPropertiesAnnotation(Brain* parentBrain); virtual ~DisplayPropertiesAnnotation(); virtual void reset(); virtual void update(); bool isDisplayAnnotations() const; void setDisplayAnnotations(const bool status); bool isDisplayTextAnnotations() const; void setDisplayTextAnnotations(const bool status); DisplayGroupEnum::Enum getDisplayGroupForTab(const int32_t browserTabIndex) const; void setDisplayGroupForTab(const int32_t browserTabIndex, const DisplayGroupEnum::Enum displayGroup); bool isDisplayWindowAnnotationsInSingleTabViews(const int32_t windowIndex) const; void setDisplayWindowAnnotationsInSingleTabViews(const int32_t windowIndex, const bool status); void updateForNewAnnotation(const Annotation* annotation); virtual void copyDisplayProperties(const int32_t sourceTabIndex, const int32_t targetTabIndex); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // ADD_NEW_METHODS_HERE private: DisplayPropertiesAnnotation(const DisplayPropertiesAnnotation&); DisplayPropertiesAnnotation& operator=(const DisplayPropertiesAnnotation&); void resetPrivate(); void restoreVersionOne(const SceneClass* sceneClass); Brain* m_parentBrain; bool m_displayAnnotations; bool m_displayTextAnnotations; DisplayGroupEnum::Enum m_displayGroup[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; bool m_displayWindowAnnotationsInSingleTabViews[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS]; // ADD_NEW_MEMBERS_HERE }; #ifdef __DISPLAY_PROPERTIES_ANNOTATION_DECLARE__ // #endif // __DISPLAY_PROPERTIES_ANNOTATION_DECLARE__ } // namespace #endif //__DISPLAY_PROPERTIES_ANNOTATION_H__ connectome-workbench-1.4.2/src/Brain/DisplayPropertiesAnnotationTextSubstitution.cxx000066400000000000000000000227041360521144700312250ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __DISPLAY_PROPERTIES_ANNOTATION_EXT_SUBSTITUTION_DECLARE__ #include "DisplayPropertiesAnnotationTextSubstitution.h" #undef __DISPLAY_PROPERTIES_ANNOTATION_EXT_SUBSTITUTION_DECLARE__ #include "Annotation.h" #include "AnnotationManager.h" #include "AnnotationTextSubstitutionFile.h" #include "Brain.h" #include "CaretLogger.h" #include "EventManager.h" #include "EventAnnotationTextSubstitutionGet.h" #include "EventAnnotationTextSubstitutionInvalidate.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneClassAssistant.h" #include "SceneObjectMapIntegerKey.h" #include "ScenePathName.h" using namespace caret; /** * \class caret::DisplayPropertiesAnnotationTextSubstitution * \brief Contains display properties for annotations. * \ingroup Brain */ /** * Constructor. */ DisplayPropertiesAnnotationTextSubstitution::DisplayPropertiesAnnotationTextSubstitution(Brain* parentBrain) : DisplayProperties(), m_parentBrain(parentBrain) { CaretAssert(parentBrain); resetPrivate(); m_sceneAssistant->add("m_enableSubstitutionsFlag", &m_enableSubstitutionsFlag); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_TEXT_SUBSTITUTION_GET); } /** * Destructor. */ DisplayPropertiesAnnotationTextSubstitution::~DisplayPropertiesAnnotationTextSubstitution() { EventManager::get()->removeAllEventsFromListener(this); } /** * Copy the border display properties from one tab to another. * @param sourceTabIndex * Index of tab from which properties are copied. * @param targetTabIndex * Index of tab to which properties are copied. */ void DisplayPropertiesAnnotationTextSubstitution::copyDisplayProperties(const int32_t /*sourceTabIndex*/, const int32_t /*targetTabIndex*/) { } /** * Reset all settings to default. * NOTE: reset() is virtual so can/should not be called from constructor. */ void DisplayPropertiesAnnotationTextSubstitution::resetPrivate() { m_enableSubstitutionsFlag = true; m_selectedFile = NULL; } /** * Reset all settings to their defaults * and remove any data. */ void DisplayPropertiesAnnotationTextSubstitution::reset() { resetPrivate(); } /** * Update due to changes in data. */ void DisplayPropertiesAnnotationTextSubstitution::update() { } /** * Receive an event. * * @param event * The event that the receive can respond to. */ void DisplayPropertiesAnnotationTextSubstitution::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_TEXT_SUBSTITUTION_GET) { if (m_enableSubstitutionsFlag) { EventAnnotationTextSubstitutionGet* textSubEvent = dynamic_cast(event); CaretAssert(textSubEvent); AnnotationTextSubstitutionFile* annTextSubFile = getSelectedFile(); if (annTextSubFile != NULL) { annTextSubFile->getSubstitutionValues(textSubEvent); } textSubEvent->setEventProcessed(); } } } /** * @return Status for enabling text annotation substitutions */ bool DisplayPropertiesAnnotationTextSubstitution::isEnableSubstitutions() const { return m_enableSubstitutionsFlag; } /** * Set status for enabling text annotation substitutions * * @param status * New display status. */ void DisplayPropertiesAnnotationTextSubstitution::setEnableSubstitutions(const bool status) { m_enableSubstitutionsFlag = status; } /** * @return The selected file or NULL if no files available. */ AnnotationTextSubstitutionFile* DisplayPropertiesAnnotationTextSubstitution::getSelectedFile() { validateSelectedFile(); return m_selectedFile; } /** * @return The selected file or NULL if no files available. */ const AnnotationTextSubstitutionFile* DisplayPropertiesAnnotationTextSubstitution::getSelectedFile() const { validateSelectedFile(); return m_selectedFile; } /** * Validate the seleted annotation text sutbstitution file and if invalid, choose any * valid file. */ void DisplayPropertiesAnnotationTextSubstitution::validateSelectedFile() const { AnnotationTextSubstitutionFile* previousFile = m_selectedFile; std::vector files; m_parentBrain->getAnnotationTextSubstitutionFiles(files); if (std::find(files.begin(), files.end(), m_selectedFile) == files.end()) { m_selectedFile = NULL; } if (m_selectedFile == NULL) { if ( ! files.empty()) { CaretAssertVectorIndex(files, 0); m_selectedFile = files[0]; CaretAssert(m_selectedFile); } } if (m_selectedFile != previousFile) { EventManager::get()->sendEvent(EventAnnotationTextSubstitutionInvalidate().getPointer()); } } /** * Set the selected annotation text substitution file. * * @param selectedFile * The selected file. */ void DisplayPropertiesAnnotationTextSubstitution::setSelectedFile(AnnotationTextSubstitutionFile* selectedFile) { if (selectedFile != m_selectedFile) { EventManager::get()->sendEvent(EventAnnotationTextSubstitutionInvalidate().getPointer()); } m_selectedFile = selectedFile; } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* DisplayPropertiesAnnotationTextSubstitution::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { const std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); SceneClass* sceneClass = new SceneClass(instanceName, "DisplayPropertiesAnnotationTextSubstitution", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); AnnotationTextSubstitutionFile* selectedFile = getSelectedFile(); if (selectedFile != NULL) { sceneClass->addPathName("selectedFile", selectedFile->getFileName()); } switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void DisplayPropertiesAnnotationTextSubstitution::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); m_selectedFile = NULL; const ScenePathName* filePathName = sceneClass->getPathName("selectedFile"); if (filePathName != NULL) { const AString filename = filePathName->stringValue(); FileInformation fileInfo(filename); const AString fileNameNoPath = fileInfo.getFileName(); AnnotationTextSubstitutionFile* fileFullPath = NULL; AnnotationTextSubstitutionFile* fileNoPath = NULL; std::vector allFiles; m_parentBrain->getAnnotationTextSubstitutionFiles(allFiles); for (auto file : allFiles) { if (file->getFileName() == filename) { fileFullPath = file; break; } if (file->getFileNameNoPath() == fileNameNoPath) { fileNoPath = file; } } if (fileFullPath != NULL) { m_selectedFile = fileFullPath; } else if (fileNoPath != NULL) { m_selectedFile = fileNoPath; } } switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } } connectome-workbench-1.4.2/src/Brain/DisplayPropertiesAnnotationTextSubstitution.h000066400000000000000000000063171360521144700306540ustar00rootroot00000000000000#ifndef __DISPLAY_PROPERTIES_ANNOTATION_TEXT_SUBSTITUTION_H__ #define __DISPLAY_PROPERTIES_ANNOTATION_TEXT_SUBSTITUTION_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "DisplayGroupEnum.h" #include "DisplayProperties.h" #include "EventListenerInterface.h" namespace caret { class Annotation; class AnnotationTextSubstitutionFile; class Brain; class DisplayPropertiesAnnotationTextSubstitution : public DisplayProperties, public EventListenerInterface { public: DisplayPropertiesAnnotationTextSubstitution(Brain* parentBrain); virtual ~DisplayPropertiesAnnotationTextSubstitution(); virtual void receiveEvent(Event* event) override; virtual void reset(); virtual void update(); bool isEnableSubstitutions() const; void setEnableSubstitutions(const bool status); AnnotationTextSubstitutionFile* getSelectedFile(); const AnnotationTextSubstitutionFile* getSelectedFile() const; void setSelectedFile(AnnotationTextSubstitutionFile* selectedFile); virtual void copyDisplayProperties(const int32_t sourceTabIndex, const int32_t targetTabIndex); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // ADD_NEW_METHODS_HERE private: DisplayPropertiesAnnotationTextSubstitution(const DisplayPropertiesAnnotationTextSubstitution&); DisplayPropertiesAnnotationTextSubstitution& operator=(const DisplayPropertiesAnnotationTextSubstitution&); void resetPrivate(); void validateSelectedFile() const; Brain* m_parentBrain; mutable AnnotationTextSubstitutionFile* m_selectedFile; bool m_enableSubstitutionsFlag; // ADD_NEW_MEMBERS_HERE }; #ifdef __DISPLAY_PROPERTIES_ANNOTATION_EXT_SUBSTITUTION_DECLARE__ // #endif // __DISPLAY_PROPERTIES_ANNOTATION_EXT_SUBSTITUTION_DECLARE__ } // namespace #endif //__DISPLAY_PROPERTIES_ANNOTATION_TEXT_SUBSTITUTION_H__ connectome-workbench-1.4.2/src/Brain/DisplayPropertiesBorders.cxx000066400000000000000000000755121360521144700252160ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __DISPLAY_PROPERTIES_BORDERS_DECLARE__ #include "DisplayPropertiesBorders.h" #undef __DISPLAY_PROPERTIES_BORDERS_DECLARE__ #include "CaretAssert.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::DisplayPropertiesBorders * \brief Contains display properties for borders. * * Border display properties are available for every tab and also a * few 'display groups'. A number of methods in this class accept * both display group and tab index parameters. When the display * group is set to 'Tab', the tab index is used meaning that the * attribute requeted/sent is for use with a specifc tab. For an * other display group value, the attribute is for a display group * and the tab index is ignored. */ /** * Constructor. */ DisplayPropertiesBorders::DisplayPropertiesBorders() : DisplayProperties() { m_aboveSurfaceOffset = 0.0; const float defaultPointSize = 2.0; const float defaultLineSize = 1.0; const BorderDrawingTypeEnum::Enum defaultDrawingType = BorderDrawingTypeEnum::DRAW_AS_POINTS_SPHERES; const FeatureColoringTypeEnum::Enum defaultColoringType = FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_NAME; const CaretColorEnum::Enum defaultColor = CaretColorEnum::BLACK; const float defaultUnstretchedLinesLength = 5.0; const bool defaultUnstretchedLinesSelection = true; for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_displayGroup[i] = DisplayGroupEnum::getDefaultValue(); m_displayStatusInTab[i] = false; m_contralateralDisplayStatusInTab[i] = false; m_lineWidthInTab[i] = defaultLineSize; m_pointSizeInTab[i] = defaultPointSize; m_coloringTypeInTab[i] = defaultColoringType; m_drawingTypeInTab[i] = defaultDrawingType; m_standardColorTypeInTab[i] = defaultColor; m_unstretchedLinesLengthInTab[i] = defaultUnstretchedLinesLength; m_unstretchedLinesStatusInTab[i] = defaultUnstretchedLinesSelection; } for (int32_t i = 0; i < DisplayGroupEnum::NUMBER_OF_GROUPS; i++) { m_displayStatusInDisplayGroup[i] = false; m_contralateralDisplayStatusInDisplayGroup[i] = false; m_lineWidthInDisplayGroup[i] = defaultLineSize; m_pointSizeInDisplayGroup[i] = defaultPointSize; m_coloringTypeInDisplayGroup[i] = defaultColoringType; m_drawingTypeInDisplayGroup[i] = defaultDrawingType; m_standardColorTypeInDisplayGroup[i] = defaultColor; m_unstretchedLinesLengthInDisplayGroup[i] = defaultUnstretchedLinesLength; m_unstretchedLinesStatusInDisplayGroup[i] = defaultUnstretchedLinesSelection; } m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_displayGroup", m_displayGroup); m_sceneAssistant->addTabIndexedBooleanArray("m_displayStatusInTab", m_displayStatusInTab); m_sceneAssistant->addTabIndexedBooleanArray("m_contralateralDisplayStatusInTab", m_contralateralDisplayStatusInTab); m_sceneAssistant->addTabIndexedFloatArray("m_lineWidthInTab", m_lineWidthInTab); m_sceneAssistant->addTabIndexedFloatArray("m_pointSizeInTab", m_pointSizeInTab); m_sceneAssistant->addArray("m_displayStatusInDisplayGroup", m_displayStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, m_displayStatusInDisplayGroup[0]); m_sceneAssistant->addArray("m_contralateralDisplayStatusInDisplayGroup", m_contralateralDisplayStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, m_contralateralDisplayStatusInDisplayGroup[0]); m_sceneAssistant->addArray("m_lineWidthInDisplayGroup", m_lineWidthInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, defaultLineSize); m_sceneAssistant->addArray("m_pointSizeInDisplayGroup", m_pointSizeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, defaultPointSize); m_sceneAssistant->addArray("m_coloringTypeInDisplayGroup", m_coloringTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, defaultColoringType); m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_coloringTypeInTab", m_coloringTypeInTab); m_sceneAssistant->addArray("m_drawingTypeInDisplayGroup", m_drawingTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, BorderDrawingTypeEnum::DRAW_AS_POINTS_SPHERES); m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_drawingTypeInTab", m_drawingTypeInTab); m_sceneAssistant->addTabIndexedFloatArray("m_unstretchedLinesLengthInTab", m_unstretchedLinesLengthInTab); m_sceneAssistant->addTabIndexedBooleanArray("m_unstretchedLinesStatusInTab", m_unstretchedLinesStatusInTab); m_sceneAssistant->addArray("m_unstretchedLinesLengthInDisplayGroup", m_unstretchedLinesLengthInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, defaultUnstretchedLinesLength); m_sceneAssistant->addArray("m_unstretchedLinesStatusInDisplayGroup", m_unstretchedLinesStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, defaultUnstretchedLinesSelection); m_sceneAssistant->add("m_aboveSurfaceOffset", &m_aboveSurfaceOffset); m_sceneAssistant->addArray("m_standardColorTypeInDisplayGroup", m_standardColorTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, defaultColor); m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_standardColorTypeInTab", m_standardColorTypeInTab); } /** * Destructor. */ DisplayPropertiesBorders::~DisplayPropertiesBorders() { } /** * Reset all settings to their defaults * and remove any data. */ void DisplayPropertiesBorders::reset() { // for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { // this->displayStatus[i] = false; // this->contralateralDisplayStatus[i] = false; // this->displayGroup[i] = DisplayGroupEnum::DISPLAY_ALL_WINDOWS; // } } /** * Update due to changes in data. */ void DisplayPropertiesBorders::update() { } /** * Copy the border display properties from one tab to another. * @param sourceTabIndex * Index of tab from which properties are copied. * @param targetTabIndex * Index of tab to which properties are copied. */ void DisplayPropertiesBorders::copyDisplayProperties(const int32_t sourceTabIndex, const int32_t targetTabIndex) { const DisplayGroupEnum::Enum displayGroup = this->getDisplayGroupForTab(sourceTabIndex); this->setDisplayGroupForTab(targetTabIndex, displayGroup); this->m_contralateralDisplayStatusInTab[targetTabIndex] = this->m_contralateralDisplayStatusInTab[sourceTabIndex]; this->m_displayStatusInTab[targetTabIndex] = this->m_displayStatusInTab[sourceTabIndex]; this->m_drawingTypeInTab[targetTabIndex] = this->m_drawingTypeInTab[sourceTabIndex]; this->m_lineWidthInTab[targetTabIndex] = this->m_lineWidthInTab[sourceTabIndex]; this->m_pointSizeInTab[targetTabIndex] = this->m_pointSizeInTab[sourceTabIndex]; this->m_unstretchedLinesLengthInTab[targetTabIndex] = this->m_unstretchedLinesLengthInTab[sourceTabIndex]; this->m_standardColorTypeInDisplayGroup[targetTabIndex] = this->m_standardColorTypeInDisplayGroup[sourceTabIndex]; } /** * @return Display status of borders. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. */ bool DisplayPropertiesBorders::isDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_displayStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_displayStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_displayStatusInTab[tabIndex]; } return m_displayStatusInDisplayGroup[displayGroup]; } /** * Set the display status for borders for the given display group. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. * @param displayStatus * New status. */ void DisplayPropertiesBorders::setDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool displayStatus) { CaretAssertArrayIndex(m_displayStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_displayStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_displayStatusInTab[tabIndex] = displayStatus; } else { m_displayStatusInDisplayGroup[displayGroup] = displayStatus; } } /** * @return Contralateral display status of borders. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. */ bool DisplayPropertiesBorders::isContralateralDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_contralateralDisplayStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_displayStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_contralateralDisplayStatusInTab[tabIndex]; } return m_contralateralDisplayStatusInDisplayGroup[displayGroup]; } /** * Set the contralateral display status for borders. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. * @param contralateralDisplayStatus * New status. */ void DisplayPropertiesBorders::setContralateralDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool contralateralDisplayStatus) { CaretAssertArrayIndex(m_contralateralDisplayStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_displayStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_contralateralDisplayStatusInTab[tabIndex] = contralateralDisplayStatus; } else { m_contralateralDisplayStatusInDisplayGroup[displayGroup] = contralateralDisplayStatus; } } /** * Get the display group for a given browser tab. * @param browserTabIndex * Index of browser tab. */ DisplayGroupEnum::Enum DisplayPropertiesBorders::getDisplayGroupForTab(const int32_t browserTabIndex) const { CaretAssertArrayIndex(this->displayGroup, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); return m_displayGroup[browserTabIndex]; } /** * Set the display group for a given browser tab. * @param browserTabIndex * Index of browser tab. * @param displayGroup * New value for display group. */ void DisplayPropertiesBorders::setDisplayGroupForTab(const int32_t browserTabIndex, const DisplayGroupEnum::Enum displayGroup) { CaretAssertArrayIndex(this->displayGroup, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); m_displayGroup[browserTabIndex] = displayGroup; } /** * @return The point size. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. */ float DisplayPropertiesBorders::getPointSize(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_pointSizeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_displayStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_pointSizeInTab[tabIndex]; } return m_pointSizeInDisplayGroup[displayGroup]; } /** * Set the point size to the given value. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. * @param pointSize * New value for point size. */ void DisplayPropertiesBorders::setPointSize(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float pointSize) { CaretAssertArrayIndex(m_pointSizeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_displayStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_pointSizeInTab[tabIndex] = pointSize; } else { m_pointSizeInDisplayGroup[displayGroup] = pointSize; } } /** * @return The line width. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. */ float DisplayPropertiesBorders::getLineWidth(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_lineWidthInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_displayStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_lineWidthInTab[tabIndex]; } return m_lineWidthInDisplayGroup[displayGroup]; } /** * Set the line width to the given value. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. * @param lineWidth * New value for line width. */ void DisplayPropertiesBorders::setLineWidth(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float lineWidth) { CaretAssertArrayIndex(m_lineWidthInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_displayStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_lineWidthInTab[tabIndex] = lineWidth; } else { m_lineWidthInDisplayGroup[displayGroup] = lineWidth; } } /** * @return Is unstretched lines enabled? * * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. */ bool DisplayPropertiesBorders::isUnstretchedLinesEnabled(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_unstretchedLinesStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_unstretchedLinesStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_unstretchedLinesStatusInTab[tabIndex]; } return m_unstretchedLinesStatusInDisplayGroup[displayGroup]; } /** * Set the unstretched lines status to the given value. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. * @param unstretchedLinesEnabled * New value for line unstretched lines status. */ void DisplayPropertiesBorders::setUnstretchedLinesEnabled(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool unstretchedLinesEnabled) { CaretAssertArrayIndex(m_unstretchedLinesStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_unstretchedLinesStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_unstretchedLinesStatusInTab[tabIndex] = unstretchedLinesEnabled; } else { m_unstretchedLinesStatusInDisplayGroup[displayGroup] = unstretchedLinesEnabled; } } /** * @return Get unstretched lines length * * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. */ float DisplayPropertiesBorders::getUnstretchedLinesLength(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_unstretchedLinesLengthInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_unstretchedLinesLengthInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_unstretchedLinesLengthInTab[tabIndex]; } return m_unstretchedLinesLengthInDisplayGroup[displayGroup]; } /** * Set the unstretched lines length to the given value. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. * @param unstretchedLinesLength * New value for unstretched lines length. */ void DisplayPropertiesBorders::setUnstretchedLinesLength(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float unstretchedLinesLength) { CaretAssertArrayIndex(m_unstretchedLinesLengthInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_unstretchedLinesLengthInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_unstretchedLinesLengthInTab[tabIndex] = unstretchedLinesLength; } else { m_unstretchedLinesLengthInDisplayGroup[displayGroup] = unstretchedLinesLength; } } /** * @return Above surface offset. */ float DisplayPropertiesBorders::getAboveSurfaceOffset() const { return m_aboveSurfaceOffset; } /** * Set the above surface offset. * * @param offset * New value for above surface offset. */ void DisplayPropertiesBorders::setAboveSurfaceOffset(const float offset) { m_aboveSurfaceOffset = offset; } /** * @return The drawing type. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. */ BorderDrawingTypeEnum::Enum DisplayPropertiesBorders::getDrawingType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_drawingTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_displayStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_drawingTypeInTab[tabIndex]; } return m_drawingTypeInDisplayGroup[displayGroup]; } /** * Set the drawing type to the given value. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. * @param drawingType * New value for drawing type. */ void DisplayPropertiesBorders::setDrawingType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const BorderDrawingTypeEnum::Enum drawingType) { CaretAssertArrayIndex(m_drawingTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_displayStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_drawingTypeInTab[tabIndex] = drawingType; } else { m_drawingTypeInDisplayGroup[displayGroup] = drawingType; } } /** * @return The coloring type. * @param displayGroup * Display group. */ FeatureColoringTypeEnum::Enum DisplayPropertiesBorders::getColoringType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_coloringTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_coloringTypeInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_coloringTypeInTab[tabIndex]; } return m_coloringTypeInDisplayGroup[displayGroup]; } /** * Set the coloring type. * @param displayGroup * Display group. * @param coloringType * New value for coloring type. */ void DisplayPropertiesBorders::setColoringType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const FeatureColoringTypeEnum::Enum coloringType) { CaretAssertArrayIndex(m_coloringTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_coloringTypeInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_coloringTypeInTab[tabIndex] = coloringType; } else { m_coloringTypeInDisplayGroup[displayGroup] = coloringType; } } /** * @return The standard caret coloring type. * @param displayGroup * Display group. */ CaretColorEnum::Enum DisplayPropertiesBorders::getStandardColorType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_standardColorTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_standardColorTypeInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_standardColorTypeInTab[tabIndex]; } return m_standardColorTypeInDisplayGroup[displayGroup]; } /** * Set the caret coloring type. * @param displayGroup * Display group. * @param color * New color for coloring type. */ void DisplayPropertiesBorders::setStandardColorType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const CaretColorEnum::Enum color) { CaretAssertArrayIndex(m_standardColorTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_standardColorTypeInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_standardColorTypeInTab[tabIndex] = color; } else { m_standardColorTypeInDisplayGroup[displayGroup] = color; } } //template //const std::vector enumArrayToStrings(const ET enumArray[], // const std::vector& tabIndices) //{ // std::vector stringVector; // // const int32_t numTabs = static_cast(tabIndices.size()); // for (int32_t i = 0; i < numTabs; i++) { // const AString stringValue = ET::nameToString(enumArray[i], // false); // stringVector.push_back(stringValue); // } // return stringVector; //} // //template //class EnumConvert { //public: // static std::vector enumArrayToStringsForTabIndices(const ET enumArray[], // const std::vector& tabIndices) // { // std::vector stringVector; // // const int32_t numTabs = static_cast(tabIndices.size()); // for (int32_t i = 0; i < numTabs; i++) { // const int32_t tabIndex = tabIndices[i]; // const AString stringValue = T::toName(enumArray[tabIndex]); // stringVector.push_back(stringValue); // } // return stringVector; // } //}; /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* DisplayPropertiesBorders::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "DisplayPropertiesBorders", 1); const std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void DisplayPropertiesBorders::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } } connectome-workbench-1.4.2/src/Brain/DisplayPropertiesBorders.h000066400000000000000000000172631360521144700246420ustar00rootroot00000000000000#ifndef __DISPLAY_PROPERTIES_BORDERS__H_ #define __DISPLAY_PROPERTIES_BORDERS__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "BorderDrawingTypeEnum.h" #include "CaretColorEnum.h" #include "DisplayGroupEnum.h" #include "DisplayProperties.h" #include "FeatureColoringTypeEnum.h" namespace caret { class DisplayPropertiesBorders : public DisplayProperties { public: DisplayPropertiesBorders(); virtual ~DisplayPropertiesBorders(); virtual void reset(); virtual void update(); virtual void copyDisplayProperties(const int32_t sourceTabIndex, const int32_t targetTabIndex); bool isDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool displayStatus); bool isContralateralDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setContralateralDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool contralateralDisplayStatus); DisplayGroupEnum::Enum getDisplayGroupForTab(const int32_t browserTabIndex) const; void setDisplayGroupForTab(const int32_t browserTabIndex, const DisplayGroupEnum::Enum displayGroup); float getPointSize(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setPointSize(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float pointSize); float getLineWidth(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setLineWidth(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float lineWidth); BorderDrawingTypeEnum::Enum getDrawingType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setDrawingType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const BorderDrawingTypeEnum::Enum drawingType); FeatureColoringTypeEnum::Enum getColoringType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setColoringType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const FeatureColoringTypeEnum::Enum drawingType); CaretColorEnum::Enum getStandardColorType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setStandardColorType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const CaretColorEnum::Enum caretColor); bool isUnstretchedLinesEnabled(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setUnstretchedLinesEnabled(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool unstretchedLinesEnabled); float getUnstretchedLinesLength(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setUnstretchedLinesLength(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float unstretchedLinesLength); float getAboveSurfaceOffset() const; void setAboveSurfaceOffset(const float Offset); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: DisplayPropertiesBorders(const DisplayPropertiesBorders&); DisplayPropertiesBorders& operator=(const DisplayPropertiesBorders&); DisplayGroupEnum::Enum m_displayGroup[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; bool m_displayStatusInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; bool m_displayStatusInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; bool m_contralateralDisplayStatusInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; bool m_contralateralDisplayStatusInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; float m_pointSizeInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; float m_pointSizeInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; float m_lineWidthInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; float m_lineWidthInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; BorderDrawingTypeEnum::Enum m_drawingTypeInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; BorderDrawingTypeEnum::Enum m_drawingTypeInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; FeatureColoringTypeEnum::Enum m_coloringTypeInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; FeatureColoringTypeEnum::Enum m_coloringTypeInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; CaretColorEnum::Enum m_standardColorTypeInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; CaretColorEnum::Enum m_standardColorTypeInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; bool m_unstretchedLinesStatusInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; bool m_unstretchedLinesStatusInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; float m_unstretchedLinesLengthInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; float m_unstretchedLinesLengthInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; float m_aboveSurfaceOffset; }; #ifdef __DISPLAY_PROPERTIES_BORDERS_DECLARE__ // #endif // __DISPLAY_PROPERTIES_BORDERS_DECLARE__ } // namespace #endif //__DISPLAY_PROPERTIES_BORDERS__H_ connectome-workbench-1.4.2/src/Brain/DisplayPropertiesFiberOrientation.cxx000066400000000000000000001006401360521144700270500ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __DISPLAY_PROPERTIES_FIBER_ORIENTATION_DECLARE__ #include "DisplayPropertiesFiberOrientation.h" #undef __DISPLAY_PROPERTIES_FIBER_ORIENTATION_DECLARE__ #include "CaretAssert.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::DisplayPropertiesFiberOrientation * \brief Contains display properties for borders. * * Border display properties are available for every tab and also a * few 'display groups'. A number of methods in this class accept * both display group and tab index parameters. When the display * group is set to 'Tab', the tab index is used meaning that the * attribute requeted/sent is for use with a specifc tab. For an * other display group value, the attribute is for a display group * and the tab index is ignored. */ /** * Constructor. */ DisplayPropertiesFiberOrientation::DisplayPropertiesFiberOrientation() : DisplayProperties() { const float aboveLimit = 0.63; const float belowLimit = -0.63; const float minimumMagnitude = 0.05; const bool drawWithMagnitude = true; const float lengthMultiplier = 6.0; const float fanMultiplier = 3.0; const FiberOrientationColoringTypeEnum::Enum coloringType = FiberOrientationColoringTypeEnum::FIBER_COLORING_XYZ_AS_RGB; const FiberOrientationSymbolTypeEnum::Enum symbolType = FiberOrientationSymbolTypeEnum::FIBER_SYMBOL_LINES; const bool displaySphereOrientions = false; for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_displayGroup[i] = DisplayGroupEnum::getDefaultValue(); m_displayStatusInTab[i] = false; m_aboveLimitInTab[i] = aboveLimit; m_belowLimitInTab[i] = belowLimit; m_minimumMagnitudeInTab[i] = minimumMagnitude; m_drawWithMagnitudeInTab[i] = drawWithMagnitude; m_lengthMultiplierInTab[i] = lengthMultiplier; m_fiberColoringTypeInTab[i] = coloringType; m_fiberSymbolTypeInTab[i] = symbolType; m_fanMultiplierInTab[i] = fanMultiplier; m_displaySphereOrientationsInTab[i] = displaySphereOrientions; } for (int32_t i = 0; i < DisplayGroupEnum::NUMBER_OF_GROUPS; i++) { m_displayStatusInDisplayGroup[i] = false; m_aboveLimitInDisplayGroup[i] = aboveLimit; m_belowLimitInDisplayGroup[i] = belowLimit; m_minimumMagnitudeInDisplayGroup[i] = minimumMagnitude; m_drawWithMagnitudeInDisplayGroup[i] = drawWithMagnitude; m_lengthMultiplierInDisplayGroup[i] = lengthMultiplier; m_fiberColoringTypeInDisplayGroup[i] = coloringType; m_fiberSymbolTypeInDisplayGroup[i] = symbolType; m_fanMultiplierInDisplayGroup[i] = fanMultiplier; m_displaySphereOrientationsInDisplayGroup[i] = displaySphereOrientions; } m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_displayGroup", m_displayGroup); m_sceneAssistant->addTabIndexedBooleanArray("m_displayStatusInTab", m_displayStatusInTab); m_sceneAssistant->addTabIndexedFloatArray("m_aboveLimitInTab", m_aboveLimitInTab); m_sceneAssistant->addTabIndexedFloatArray("m_belowLimitInTab", m_belowLimitInTab); m_sceneAssistant->addTabIndexedFloatArray("m_minimumMagnitudeInTab", m_minimumMagnitudeInTab); m_sceneAssistant->addTabIndexedBooleanArray("m_drawWithMagnitudeInTab", m_drawWithMagnitudeInTab); m_sceneAssistant->addTabIndexedFloatArray("m_lengthMultiplierInTab", m_lengthMultiplierInTab); m_sceneAssistant->addTabIndexedFloatArray("m_fanMultiplierInTab", m_fanMultiplierInTab); m_sceneAssistant->addTabIndexedBooleanArray("m_displaySphereOrientationsInTab", m_displaySphereOrientationsInTab); m_sceneAssistant->addArray("m_drawingTypeInDisplayGroup", m_fiberColoringTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, FiberOrientationColoringTypeEnum::FIBER_COLORING_XYZ_AS_RGB); m_sceneAssistant->addArray("m_fiberSymbolTypeInDisplayGroup", m_fiberSymbolTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, FiberOrientationSymbolTypeEnum::FIBER_SYMBOL_LINES); m_sceneAssistant->addArray("m_displayStatusInDisplayGroup", m_displayStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, m_displayStatusInDisplayGroup[0]); m_sceneAssistant->addArray("m_aboveLimitInDisplayGroup", m_aboveLimitInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, m_aboveLimitInDisplayGroup[0]); m_sceneAssistant->addArray("m_belowLimitInDisplayGroup", m_belowLimitInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, m_belowLimitInDisplayGroup[0]); m_sceneAssistant->addArray("m_minimumMagnitudeInDisplayGroup", m_minimumMagnitudeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, m_minimumMagnitudeInDisplayGroup[0]); m_sceneAssistant->addArray("m_drawWithMagnitudeInDisplayGroup", m_drawWithMagnitudeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, m_drawWithMagnitudeInDisplayGroup[0]); m_sceneAssistant->addArray("m_lengthMultiplierInDisplayGroup", m_lengthMultiplierInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, m_lengthMultiplierInDisplayGroup[0]); m_sceneAssistant->addArray("m_fanMultiplierInDisplayGroup", m_fanMultiplierInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, m_fanMultiplierInDisplayGroup[0]); m_sceneAssistant->addArray("m_displaySphereOrientationsInDisplayGroup", m_displaySphereOrientationsInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, m_displaySphereOrientationsInDisplayGroup[0]); m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_fiberColoringTypeInTab", m_fiberColoringTypeInTab); m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_fiberSymbolTypeInTab", m_fiberSymbolTypeInTab); } /** * Destructor. */ DisplayPropertiesFiberOrientation::~DisplayPropertiesFiberOrientation() { } /** * Reset all settings to their defaults * and remove any data. */ void DisplayPropertiesFiberOrientation::reset() { } /** * Update due to changes in data. */ void DisplayPropertiesFiberOrientation::update() { } /** * Copy the fiber orientation display properties from one tab to another. * @param sourceTabIndex * Index of tab from which properties are copied. * @param targetTabIndex * Index of tab to which properties are copied. */ void DisplayPropertiesFiberOrientation::copyDisplayProperties(const int32_t sourceTabIndex, const int32_t targetTabIndex) { const DisplayGroupEnum::Enum displayGroup = this->getDisplayGroupForTab(sourceTabIndex); this->setDisplayGroupForTab(targetTabIndex, displayGroup); m_displayStatusInTab[targetTabIndex] = m_displayStatusInTab[sourceTabIndex]; m_aboveLimitInTab[targetTabIndex] = m_aboveLimitInTab[sourceTabIndex]; m_belowLimitInTab[targetTabIndex] = m_belowLimitInTab[sourceTabIndex]; m_minimumMagnitudeInTab[targetTabIndex] = m_minimumMagnitudeInTab[sourceTabIndex]; m_drawWithMagnitudeInTab[targetTabIndex] = m_drawWithMagnitudeInTab[sourceTabIndex]; m_lengthMultiplierInTab[targetTabIndex] = m_lengthMultiplierInTab[sourceTabIndex]; m_fiberColoringTypeInTab[targetTabIndex] = m_fiberColoringTypeInTab[sourceTabIndex]; m_fanMultiplierInTab[targetTabIndex] = m_fanMultiplierInTab[sourceTabIndex]; } /** * @return Display status of fiber orientations. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. */ bool DisplayPropertiesFiberOrientation::isDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_displayStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_displayStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_displayStatusInTab[tabIndex]; } return m_displayStatusInDisplayGroup[displayGroup]; } /** * Set the display status for fiber orientations for the given display group. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. * @param displayStatus * New status. */ void DisplayPropertiesFiberOrientation::setDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool displayStatus) { CaretAssertArrayIndex(m_displayStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_displayStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_displayStatusInTab[tabIndex] = displayStatus; } else { m_displayStatusInDisplayGroup[displayGroup] = displayStatus; } } /** * @return Display status of sphere orientations. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. */ bool DisplayPropertiesFiberOrientation::isSphereOrientationsDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_displaySphereOrientationsInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_displaySphereOrientationsInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_displaySphereOrientationsInTab[tabIndex]; } return m_displaySphereOrientationsInDisplayGroup[displayGroup]; } /** * Set the display status for sphere orientations for the given display group. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. * @param displayStatus * New status. */ void DisplayPropertiesFiberOrientation::setSphereOrientationsDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool displaySphereOrientations) { CaretAssertArrayIndex(m_displaySphereOrientationsInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_displaySphereOrientationsInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_displaySphereOrientationsInTab[tabIndex] = displaySphereOrientations; } else { m_displaySphereOrientationsInDisplayGroup[displayGroup] = displaySphereOrientations; } } /** * Get the display group for a given browser tab. * @param browserTabIndex * Index of browser tab. */ DisplayGroupEnum::Enum DisplayPropertiesFiberOrientation::getDisplayGroupForTab(const int32_t browserTabIndex) const { CaretAssertArrayIndex(this->displayGroup, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); return m_displayGroup[browserTabIndex]; } /** * Set the display group for a given browser tab. * @param browserTabIndex * Index of browser tab. * @param displayGroup * New value for display group. */ void DisplayPropertiesFiberOrientation::setDisplayGroupForTab(const int32_t browserTabIndex, const DisplayGroupEnum::Enum displayGroup) { CaretAssertArrayIndex(this->displayGroup, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); m_displayGroup[browserTabIndex] = displayGroup; } /** * @return Draw with magnitude status. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. */ bool DisplayPropertiesFiberOrientation::isDrawWithMagnitude(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_drawWithMagnitudeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_drawWithMagnitudeInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_drawWithMagnitudeInTab[tabIndex]; } return m_drawWithMagnitudeInDisplayGroup[displayGroup]; } /** * Set the draw with magnitude status for the given display group. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. * @param drawWithMagnitude * New status. */ void DisplayPropertiesFiberOrientation::setDrawWithMagnitude(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool drawWithMagnitude) { CaretAssertArrayIndex(m_drawWithMagnitudeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_drawWithMagnitudeInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_drawWithMagnitudeInTab[tabIndex] = drawWithMagnitude; } else { m_drawWithMagnitudeInDisplayGroup[displayGroup] = drawWithMagnitude; } } /** * @return The Above limit. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. */ float DisplayPropertiesFiberOrientation::getAboveLimit(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_aboveLimitInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_aboveLimitInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_aboveLimitInTab[tabIndex]; } return m_aboveLimitInDisplayGroup[displayGroup]; } /** * Set the above limit to the given value. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. * @param aboveLimit * New value for above limit. */ void DisplayPropertiesFiberOrientation::setAboveLimit(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float aboveLimit) { CaretAssertArrayIndex(m_aboveLimitInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_aboveLimitInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_aboveLimitInTab[tabIndex] = aboveLimit; } else { m_aboveLimitInDisplayGroup[displayGroup] = aboveLimit; } } /** * @return The below limit. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. */ float DisplayPropertiesFiberOrientation::getBelowLimit(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_belowLimitInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_belowLimitInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_belowLimitInTab[tabIndex]; } return m_belowLimitInDisplayGroup[displayGroup]; } /** * Set the below limit to the given value. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. * @param pointSize * New value for below limit. */ void DisplayPropertiesFiberOrientation::setBelowLimit(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float belowLimit) { CaretAssertArrayIndex(m_belowLimitInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_belowLimitInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_belowLimitInTab[tabIndex] = belowLimit; } else { m_belowLimitInDisplayGroup[displayGroup] = belowLimit; } } /** * Set the above and below limits for all display groups and tabs. * @param * Value for all above limits. * @param * Value for all below limits. */ void DisplayPropertiesFiberOrientation::setAboveAndBelowLimitsForAll(const float aboveLimit, const float belowLimit) { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_aboveLimitInTab[i] = aboveLimit; m_belowLimitInTab[i] = belowLimit; } for (int32_t i = 0; i < DisplayGroupEnum::NUMBER_OF_GROUPS; i++) { m_aboveLimitInDisplayGroup[i] = aboveLimit; m_belowLimitInDisplayGroup[i] = belowLimit; } } /** * @return The minimum magnitude. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. */ float DisplayPropertiesFiberOrientation::getMinimumMagnitude(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_minimumMagnitudeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_minimumMagnitudeInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_minimumMagnitudeInTab[tabIndex]; } return m_minimumMagnitudeInDisplayGroup[displayGroup]; } /** * Set the minimum magnitude to the given value. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. * @param minimumMagnitude * New value for minimum magnitude. */ void DisplayPropertiesFiberOrientation::setMinimumMagnitude(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float minimumMagnitude) { CaretAssertArrayIndex(m_minimumMagnitudeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_minimumMagnitudeInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_minimumMagnitudeInTab[tabIndex] = minimumMagnitude; } else { m_minimumMagnitudeInDisplayGroup[displayGroup] = minimumMagnitude; } } /** * @return The length multiplier. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. */ float DisplayPropertiesFiberOrientation::getLengthMultiplier(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_lengthMultiplierInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_lengthMultiplierInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_lengthMultiplierInTab[tabIndex]; } return m_lengthMultiplierInDisplayGroup[displayGroup]; } /** * Set the length multiplier to the given value. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. * @param lengthMultiplier * New value for length multiplier */ void DisplayPropertiesFiberOrientation::setLengthMultiplier(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float lengthMultiplier) { CaretAssertArrayIndex(m_lengthMultiplierInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_lengthMultiplierInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_lengthMultiplierInTab[tabIndex] = lengthMultiplier; } else { m_lengthMultiplierInDisplayGroup[displayGroup] = lengthMultiplier; } } /** * @return The coloring type. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. */ FiberOrientationColoringTypeEnum::Enum DisplayPropertiesFiberOrientation::getColoringType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_fiberColoringTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_fiberColoringTypeInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_fiberColoringTypeInTab[tabIndex]; } return m_fiberColoringTypeInDisplayGroup[displayGroup]; } /** * Set the coloring type to the given value. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. * @param coloringType * New value for coloring type. */ void DisplayPropertiesFiberOrientation::setColoringType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const FiberOrientationColoringTypeEnum::Enum coloringType) { CaretAssertArrayIndex(m_fiberColoringTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_fiberColoringTypeInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_fiberColoringTypeInTab[tabIndex] = coloringType; } else { m_fiberColoringTypeInDisplayGroup[displayGroup] = coloringType; } } /** * @return The symbol type. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. */ FiberOrientationSymbolTypeEnum::Enum DisplayPropertiesFiberOrientation::getSymbolType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_fiberSymbolTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_fiberSymbolTypeInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_fiberSymbolTypeInTab[tabIndex]; } return m_fiberSymbolTypeInDisplayGroup[displayGroup]; } /** * Set the symbol type to the given value. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. * @param symbolType * New value for symbol type. */ void DisplayPropertiesFiberOrientation::setSymbolType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const FiberOrientationSymbolTypeEnum::Enum symbolType) { CaretAssertArrayIndex(m_fiberSymbolTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_fiberSymbolTypeInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_fiberSymbolTypeInTab[tabIndex] = symbolType; } else { m_fiberSymbolTypeInDisplayGroup[displayGroup] = symbolType; } } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* DisplayPropertiesFiberOrientation::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "DisplayPropertiesFiberOrientation", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void DisplayPropertiesFiberOrientation::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } } /** * @return The fan multiplier. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. */ float DisplayPropertiesFiberOrientation::getFanMultiplier(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_fanMultiplierInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_fanMultiplierInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_fanMultiplierInTab[tabIndex]; } return m_fanMultiplierInDisplayGroup[displayGroup]; } /** * Set the fan multiplier to the given value. * @param displayGroup * The display group. * @param tabIndex * Index of browser tab. * @param lengthMultiplier * New value for fan multiplier */ void DisplayPropertiesFiberOrientation::setFanMultiplier(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float fanMultiplier) { CaretAssertArrayIndex(m_fanMultiplierInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_fanMultiplierInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_fanMultiplierInTab[tabIndex] = fanMultiplier; } else { m_fanMultiplierInDisplayGroup[displayGroup] = fanMultiplier; } } connectome-workbench-1.4.2/src/Brain/DisplayPropertiesFiberOrientation.h000066400000000000000000000204331360521144700264760ustar00rootroot00000000000000#ifndef __DISPLAY_PROPERTIES_FIBER_ORIENTATION__H_ #define __DISPLAY_PROPERTIES_FIBER_ORIENTATION__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "DisplayGroupEnum.h" #include "DisplayProperties.h" #include "FiberOrientationColoringTypeEnum.h" #include "FiberOrientationSymbolTypeEnum.h" namespace caret { class DisplayPropertiesFiberOrientation : public DisplayProperties { public: DisplayPropertiesFiberOrientation(); virtual ~DisplayPropertiesFiberOrientation(); virtual void reset(); virtual void update(); virtual void copyDisplayProperties(const int32_t sourceTabIndex, const int32_t targetTabIndex); bool isDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool displayStatus); bool isDrawWithMagnitude(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setDrawWithMagnitude(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool drawWithMagnitude); DisplayGroupEnum::Enum getDisplayGroupForTab(const int32_t browserTabIndex) const; void setDisplayGroupForTab(const int32_t browserTabIndex, const DisplayGroupEnum::Enum displayGroup); float getAboveLimit(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setAboveLimit(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float aboveLimit); void setAboveAndBelowLimitsForAll(const float aboveLimit, const float belowLimit); float getBelowLimit(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setBelowLimit(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float aboveLimit); float getMinimumMagnitude(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setMinimumMagnitude(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float minimumMagnitude); float getLengthMultiplier(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setLengthMultiplier(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float lengthMultiplier); float getFanMultiplier(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setFanMultiplier(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float fanMultiplier); FiberOrientationColoringTypeEnum::Enum getColoringType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setColoringType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const FiberOrientationColoringTypeEnum::Enum coloringType); FiberOrientationSymbolTypeEnum::Enum getSymbolType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setSymbolType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const FiberOrientationSymbolTypeEnum::Enum symbolType); bool isSphereOrientationsDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setSphereOrientationsDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool displaySphereOrientations); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: DisplayPropertiesFiberOrientation(const DisplayPropertiesFiberOrientation&); DisplayPropertiesFiberOrientation& operator=(const DisplayPropertiesFiberOrientation&); DisplayGroupEnum::Enum m_displayGroup[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; bool m_displayStatusInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; bool m_displayStatusInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; float m_aboveLimitInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; float m_aboveLimitInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; float m_belowLimitInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; float m_belowLimitInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; float m_minimumMagnitudeInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; float m_minimumMagnitudeInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; bool m_drawWithMagnitudeInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; bool m_drawWithMagnitudeInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; float m_lengthMultiplierInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; float m_lengthMultiplierInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; float m_fanMultiplierInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; float m_fanMultiplierInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; FiberOrientationColoringTypeEnum::Enum m_fiberColoringTypeInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; FiberOrientationColoringTypeEnum::Enum m_fiberColoringTypeInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; FiberOrientationSymbolTypeEnum::Enum m_fiberSymbolTypeInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; FiberOrientationSymbolTypeEnum::Enum m_fiberSymbolTypeInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; bool m_displaySphereOrientationsInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; bool m_displaySphereOrientationsInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; // friend class BrainOpenGLFixedPipeline; }; #ifdef __DISPLAY_PROPERTIES_FIBER_ORIENTATION_DECLARE__ // #endif // __DISPLAY_PROPERTIES_FIBER_ORIENTATION_DECLARE__ } // namespace #endif //__DISPLAY_PROPERTIES_FIBER_ORIENTATION__H_ connectome-workbench-1.4.2/src/Brain/DisplayPropertiesFoci.cxx000066400000000000000000000557011360521144700244740ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __DISPLAY_PROPERTIES_FOCI_DECLARE__ #include "DisplayPropertiesFoci.h" #undef __DISPLAY_PROPERTIES_FOCI_DECLARE__ #include "CaretAssert.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::DisplayPropertiesFoci * \brief Contains display properties for foci. */ /** * Constructor. */ DisplayPropertiesFoci::DisplayPropertiesFoci() : DisplayProperties() { const CaretColorEnum::Enum defaultColor = CaretColorEnum::BLACK; for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_displayGroup[i] = DisplayGroupEnum::getDefaultValue(); m_pasteOntoSurfaceInTab[i] = false; m_displayStatusInTab[i] = false; m_contralateralDisplayStatusInTab[i] = false; m_fociSizeInTab[i] = 4.0; m_coloringTypeInTab[i] = FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_NAME; m_drawingTypeInTab[i] = FociDrawingTypeEnum::DRAW_AS_SQUARES; m_standardColorTypeInTab[i] = defaultColor; } for (int32_t i = 0; i < DisplayGroupEnum::NUMBER_OF_GROUPS; i++) { m_pasteOntoSurfaceInDisplayGroup[i] = false; m_displayStatusInDisplayGroup[i] = false; m_contralateralDisplayStatusInDisplayGroup[i] = false; m_fociSizeInDisplayGroup[i] = 4.0; m_coloringTypeInDisplayGroup[i] = FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_NAME; m_drawingTypeInDisplayGroup[i] = FociDrawingTypeEnum::DRAW_AS_SQUARES; m_standardColorTypeInDisplayGroup[i] = defaultColor; } m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_displayGroup", m_displayGroup); m_sceneAssistant->addTabIndexedBooleanArray("m_pasteOntoSurfaceInTab", m_pasteOntoSurfaceInTab); m_sceneAssistant->addTabIndexedBooleanArray("m_displayStatusInTab", m_displayStatusInTab); m_sceneAssistant->addTabIndexedBooleanArray("m_contralateralDisplayStatusInTab", m_contralateralDisplayStatusInTab); m_sceneAssistant->addTabIndexedFloatArray("m_fociSizeInTab", m_fociSizeInTab); m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_coloringTypeInTab", m_coloringTypeInTab); m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_drawingTypeInTab", m_drawingTypeInTab); m_sceneAssistant->addArray("m_pasteOntoSurfaceInDisplayGroup", m_pasteOntoSurfaceInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, m_pasteOntoSurfaceInDisplayGroup[0]); m_sceneAssistant->addArray("m_displayStatusInDisplayGroup", m_displayStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, m_displayStatusInDisplayGroup[0]); m_sceneAssistant->addArray("m_contralateralDisplayStatusInDisplayGroup", m_contralateralDisplayStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, m_contralateralDisplayStatusInDisplayGroup[0]); m_sceneAssistant->addArray("m_fociSizeInDisplayGroup", m_fociSizeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, m_fociSizeInDisplayGroup[0]); m_sceneAssistant->addArray("m_coloringTypeInDisplayGroup", m_coloringTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, FeatureColoringTypeEnum::FEATURE_COLORING_TYPE_NAME); m_sceneAssistant->addArray("m_drawingTypeInDisplayGroup", m_drawingTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, FociDrawingTypeEnum::DRAW_AS_SQUARES); m_sceneAssistant->addArray("m_standardColorTypeInDisplayGroup", m_standardColorTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, defaultColor); m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_standardColorTypeInTab", m_standardColorTypeInTab); } /** * Destructor. */ DisplayPropertiesFoci::~DisplayPropertiesFoci() { } /** * Copy the border display properties from one tab to another. * @param sourceTabIndex * Index of tab from which properties are copied. * @param targetTabIndex * Index of tab to which properties are copied. */ void DisplayPropertiesFoci::copyDisplayProperties(const int32_t sourceTabIndex, const int32_t targetTabIndex) { const DisplayGroupEnum::Enum displayGroup = this->getDisplayGroupForTab(sourceTabIndex); this->setDisplayGroupForTab(targetTabIndex, displayGroup); m_coloringTypeInTab[targetTabIndex] = m_coloringTypeInTab[sourceTabIndex]; m_contralateralDisplayStatusInTab[targetTabIndex] = m_contralateralDisplayStatusInTab[sourceTabIndex]; m_displayStatusInTab[targetTabIndex] = m_displayStatusInTab[sourceTabIndex]; m_drawingTypeInTab[targetTabIndex] = m_drawingTypeInTab[sourceTabIndex]; m_fociSizeInTab[targetTabIndex] = m_fociSizeInTab[sourceTabIndex]; m_pasteOntoSurfaceInTab[targetTabIndex] = m_pasteOntoSurfaceInTab[sourceTabIndex]; m_standardColorTypeInTab[targetTabIndex] = m_standardColorTypeInTab[sourceTabIndex]; } /** * Reset all settings to their defaults * and remove any data. */ void DisplayPropertiesFoci::reset() { // for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { // m_displayStatus[i] = true; // m_contralateralDisplayStatus[i] = false; // m_displayGroup[i] = DisplayGroupEnum::DISPLAY_ALL_WINDOWS; // m_pasteOntoSurface[i] = false; // } } /** * Update due to changes in data. */ void DisplayPropertiesFoci::update() { } /** * @return Display status of foci. * @param displayGroup * Display group. */ bool DisplayPropertiesFoci::isDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_displayStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_displayStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_displayStatusInTab[tabIndex]; } return m_displayStatusInDisplayGroup[displayGroup]; } /** * Set the display status for foci. * @param displayGroup * Display group. * @param displayStatus * New status. */ void DisplayPropertiesFoci::setDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool displayStatus) { CaretAssertArrayIndex(m_displayStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_displayStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_displayStatusInTab[tabIndex] = displayStatus; } else { m_displayStatusInDisplayGroup[displayGroup] = displayStatus; } } /** * @return Contralateral display status of foci. * @param displayGroup * Display group. * @param browserTabIndex * Index of browser tab. */ bool DisplayPropertiesFoci::isContralateralDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_contralateralDisplayStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_contralateralDisplayStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_contralateralDisplayStatusInTab[tabIndex]; } return m_contralateralDisplayStatusInDisplayGroup[displayGroup]; } /** * Set the contralateral display status for foci. * @param displayGroup * Display group. * @param contralateralDisplayStatus * New status. */ void DisplayPropertiesFoci::setContralateralDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool contralateralDisplayStatus) { CaretAssertArrayIndex(m_contralateralDisplayStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_contralateralDisplayStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_contralateralDisplayStatusInTab[tabIndex] = contralateralDisplayStatus; } else { m_contralateralDisplayStatusInDisplayGroup[displayGroup] = contralateralDisplayStatus; } } /** * Get the display group for a given browser tab. * @param browserTabIndex * Index of browser tab. */ DisplayGroupEnum::Enum DisplayPropertiesFoci::getDisplayGroupForTab(const int32_t browserTabIndex) const { CaretAssertArrayIndex(m_displayGroup, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); return m_displayGroup[browserTabIndex]; } /** * Set the display group for a given browser tab. * @param browserTabIndex * Index of browser tab. * @param displayGroup * New value for display group. */ void DisplayPropertiesFoci::setDisplayGroupForTab(const int32_t browserTabIndex, const DisplayGroupEnum::Enum displayGroup) { CaretAssertArrayIndex(m_displayGroup, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); m_displayGroup[browserTabIndex] = displayGroup; } /** * @return The foci size. * @param displayGroup * Display group. */ float DisplayPropertiesFoci::getFociSize(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_fociSizeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_fociSizeInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_fociSizeInTab[tabIndex]; } return m_fociSizeInDisplayGroup[displayGroup]; } /** * Set the foci size to the given value. * @param displayGroup * Display group. * @param fociSize * New value for foci size. */ void DisplayPropertiesFoci::setFociSize(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float fociSize) { CaretAssertArrayIndex(m_fociSizeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_fociSizeInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_fociSizeInTab[tabIndex] = fociSize; } else { m_fociSizeInDisplayGroup[displayGroup] = fociSize; } } /** * @return The coloring type. * @param displayGroup * Display group. */ FeatureColoringTypeEnum::Enum DisplayPropertiesFoci::getColoringType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_coloringTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_coloringTypeInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_coloringTypeInTab[tabIndex]; } return m_coloringTypeInDisplayGroup[displayGroup]; } /** * Set the coloring type. * @param displayGroup * Display group. * @param coloringType * New value for coloring type. */ void DisplayPropertiesFoci::setColoringType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const FeatureColoringTypeEnum::Enum coloringType) { CaretAssertArrayIndex(m_coloringTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_coloringTypeInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_coloringTypeInTab[tabIndex] = coloringType; } else { m_coloringTypeInDisplayGroup[displayGroup] = coloringType; } } /** * @return The standard caret coloring type. * @param displayGroup * Display group. */ CaretColorEnum::Enum DisplayPropertiesFoci::getStandardColorType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_standardColorTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_standardColorTypeInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_standardColorTypeInTab[tabIndex]; } return m_standardColorTypeInDisplayGroup[displayGroup]; } /** * Set the caret coloring type. * @param displayGroup * Display group. * @param color * New color for coloring type. */ void DisplayPropertiesFoci::setStandardColorType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const CaretColorEnum::Enum color) { CaretAssertArrayIndex(m_standardColorTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_standardColorTypeInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_standardColorTypeInTab[tabIndex] = color; } else { m_standardColorTypeInDisplayGroup[displayGroup] = color; } } /** * @param displayGroup * Display group. * @return The drawing type. */ FociDrawingTypeEnum::Enum DisplayPropertiesFoci::getDrawingType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_drawingTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_drawingTypeInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_drawingTypeInTab[tabIndex]; } return m_drawingTypeInDisplayGroup[displayGroup]; } /** * Set the drawing type to the given value. * @param displayGroup * Display group. * @param drawingType * New value for drawing type. */ void DisplayPropertiesFoci::setDrawingType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const FociDrawingTypeEnum::Enum drawingType) { CaretAssertArrayIndex(m_drawingTypeInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_drawingTypeInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_drawingTypeInTab[tabIndex] = drawingType; } else { m_drawingTypeInDisplayGroup[displayGroup] = drawingType; } } /** * Set paste onto surface so the foci are placed directly on the surface. * @param displayGroup * Display group. * @param enabled * True if pasting foci onto surface is enabled. */ void DisplayPropertiesFoci::setPasteOntoSurface(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool enabled) { CaretAssertArrayIndex(m_pasteOntoSurfaceInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_pasteOntoSurfaceInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_pasteOntoSurfaceInTab[tabIndex] = enabled; } else { m_pasteOntoSurfaceInDisplayGroup[displayGroup] = enabled; } } /** * @param displayGroup * Display group. * @return True if foci are pasted onto surface. */ bool DisplayPropertiesFoci::isPasteOntoSurface(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_pasteOntoSurfaceInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_pasteOntoSurfaceInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_pasteOntoSurfaceInTab[tabIndex]; } return m_pasteOntoSurfaceInDisplayGroup[displayGroup]; } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* DisplayPropertiesFoci::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { const std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); SceneClass* sceneClass = new SceneClass(instanceName, "DisplayPropertiesFoci", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void DisplayPropertiesFoci::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } } connectome-workbench-1.4.2/src/Brain/DisplayPropertiesFoci.h000066400000000000000000000145671360521144700241260ustar00rootroot00000000000000#ifndef __DISPLAY_PROPERTIES_FOCI__H_ #define __DISPLAY_PROPERTIES_FOCI__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "CaretColorEnum.h" #include "DisplayGroupEnum.h" #include "DisplayProperties.h" #include "FeatureColoringTypeEnum.h" #include "FociDrawingTypeEnum.h" namespace caret { class DisplayPropertiesFoci : public DisplayProperties { public: DisplayPropertiesFoci(); virtual ~DisplayPropertiesFoci(); virtual void reset(); virtual void update(); virtual void copyDisplayProperties(const int32_t sourceTabIndex, const int32_t targetTabIndex); bool isDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool displayStatus); bool isContralateralDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setContralateralDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool contralateralDisplayStatus); DisplayGroupEnum::Enum getDisplayGroupForTab(const int32_t browserTabIndex) const; void setDisplayGroupForTab(const int32_t browserTabIndex, const DisplayGroupEnum::Enum displayGroup); float getFociSize(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setFociSize(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float pointSize); FeatureColoringTypeEnum::Enum getColoringType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setColoringType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const FeatureColoringTypeEnum::Enum coloringType); FociDrawingTypeEnum::Enum getDrawingType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setDrawingType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const FociDrawingTypeEnum::Enum drawingType); CaretColorEnum::Enum getStandardColorType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setStandardColorType(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const CaretColorEnum::Enum caretColor); void setPasteOntoSurface(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool enabled); bool isPasteOntoSurface(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: DisplayPropertiesFoci(const DisplayPropertiesFoci&); DisplayPropertiesFoci& operator=(const DisplayPropertiesFoci&); DisplayGroupEnum::Enum m_displayGroup[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; bool m_displayStatusInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; bool m_displayStatusInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; bool m_contralateralDisplayStatusInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; bool m_contralateralDisplayStatusInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; bool m_pasteOntoSurfaceInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; bool m_pasteOntoSurfaceInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; float m_fociSizeInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; float m_fociSizeInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; FeatureColoringTypeEnum::Enum m_coloringTypeInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; FeatureColoringTypeEnum::Enum m_coloringTypeInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; FociDrawingTypeEnum::Enum m_drawingTypeInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; FociDrawingTypeEnum::Enum m_drawingTypeInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; CaretColorEnum::Enum m_standardColorTypeInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; CaretColorEnum::Enum m_standardColorTypeInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; }; #ifdef __DISPLAY_PROPERTIES_FOCI_DECLARE__ // #endif // __DISPLAY_PROPERTIES_FOCI_DECLARE__ } // namespace #endif //__DISPLAY_PROPERTIES_FOCI__H_ connectome-workbench-1.4.2/src/Brain/DisplayPropertiesImages.cxx000066400000000000000000000531061360521144700250160ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __DISPLAY_PROPERTIES_IMAGES_DECLARE__ #include "DisplayPropertiesImages.h" #undef __DISPLAY_PROPERTIES_IMAGES_DECLARE__ #include "Brain.h" #include "CaretLogger.h" #include "DisplayPropertyDataBoolean.h" #include "DisplayPropertyDataFloat.h" #include "ImageFile.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "ScenePathName.h" #include "ScenePathNameArray.h" #include "ScenePrimitive.h" #include "ScenePrimitiveArray.h" using namespace caret; /** * \class caret::DisplayPropertiesImages * \brief Contains display properties for images. * \ingroup Brain */ /** * Constructor. */ DisplayPropertiesImages::DisplayPropertiesImages(Brain* parentBrain) : DisplayProperties(), m_parentBrain(parentBrain) { CaretAssert(parentBrain); const ImageDepthPositionEnum::Enum defaultImageDepth = ImageDepthPositionEnum::BACK; for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_displayGroup[i] = DisplayGroupEnum::getDefaultValue(); m_imageFileInTab[i] = NULL; } for (int32_t i = 0; i < DisplayGroupEnum::NUMBER_OF_GROUPS; i++) { m_imageFileInDisplayGroup[i] = NULL; } m_imageDepthPosition.initialize(defaultImageDepth); m_displayStatus.grabNew(new DisplayPropertyDataBoolean(false)); m_controlPointDisplayStatus.grabNew(new DisplayPropertyDataBoolean(true)); m_thresholdMinimum.grabNew(new DisplayPropertyDataFloat(0)); m_thresholdMaximum.grabNew(new DisplayPropertyDataFloat(255)); m_opacity.grabNew(new DisplayPropertyDataFloat(1.0)); m_sceneAssistant->add("m_displayStatus", "DisplayPropertyDataBoolean", m_displayStatus); m_sceneAssistant->add("m_controlPointDisplayStatus", "DisplayPropertyDataBoolean", m_controlPointDisplayStatus); m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_displayGroup", m_displayGroup); m_sceneAssistant->add("m_imageDepthPosition", "DisplayPropertyDataEnum", &m_imageDepthPosition); m_sceneAssistant->add("m_thresholdMinimum", "DisplayPropertyDataFloat", m_thresholdMinimum); m_sceneAssistant->add("m_thresholdMaximum", "DisplayPropertyDataFloat", m_thresholdMaximum); m_sceneAssistant->add("m_opacity", "DisplayPropertyDataFloat", m_opacity); } /** * Destructor. */ DisplayPropertiesImages::~DisplayPropertiesImages() { } /** * Copy the border display properties from one tab to another. * @param sourceTabIndex * Index of tab from which properties are copied. * @param targetTabIndex * Index of tab to which properties are copied. */ void DisplayPropertiesImages::copyDisplayProperties(const int32_t sourceTabIndex, const int32_t targetTabIndex) { const DisplayGroupEnum::Enum displayGroup = this->getDisplayGroupForTab(sourceTabIndex); this->setDisplayGroupForTab(targetTabIndex, displayGroup); m_displayStatus->copyValues(sourceTabIndex, targetTabIndex); } /** * Reset all settings to their defaults * and remove any data. */ void DisplayPropertiesImages::reset() { // for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { // m_displayStatus[i] = true; // m_contralateralDisplayStatus[i] = false; // m_displayGroup[i] = DisplayGroupEnum::DISPLAY_ALL_WINDOWS; // m_pasteOntoSurface[i] = false; // } } /** * Update due to changes in data. */ void DisplayPropertiesImages::update() { } /** * @return Display status of images. * @param displayGroup * Display group. * @param tabIndex * The tab index. */ bool DisplayPropertiesImages::isDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { return m_displayStatus->getValue(displayGroup, tabIndex); } /** * Set the display status for image. * @param displayGroup * Display group. * @param tabIndex * The tab index. * @param displayStatus * New status. */ void DisplayPropertiesImages::setDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool displayStatus) { m_displayStatus->setValue(displayGroup, tabIndex, displayStatus); } /** * @return Display status of image control points. * @param displayGroup * Display group. * @param tabIndex * The tab index. */ bool DisplayPropertiesImages::isControlPointsDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { return m_controlPointDisplayStatus->getValue(displayGroup, tabIndex); } /** * Set the display status for image control points. * @param displayGroup * Display group. * @param tabIndex * The tab index. * @param displayStatus * New status. */ void DisplayPropertiesImages::setControlPointsDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool displayStatus) { m_controlPointDisplayStatus->setValue(displayGroup, tabIndex, displayStatus); } /** * Get the display group for a given browser tab. * @param browserTabIndex * Index of browser tab. */ DisplayGroupEnum::Enum DisplayPropertiesImages::getDisplayGroupForTab(const int32_t browserTabIndex) const { CaretAssertArrayIndex(m_displayGroup, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); return m_displayGroup[browserTabIndex]; } /** * Set the display group for a given browser tab. * @param browserTabIndex * Index of browser tab. * @param displayGroup * New value for display group. */ void DisplayPropertiesImages::setDisplayGroupForTab(const int32_t browserTabIndex, const DisplayGroupEnum::Enum displayGroup) { CaretAssertArrayIndex(m_displayGroup, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); m_displayGroup[browserTabIndex] = displayGroup; } /** * Get the selected image file. * * @param displayGroup * Display group. * @param tabIndex * The tab index. * @return * The selected image file. */ ImageFile* DisplayPropertiesImages::getSelectedImageFile(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { ImageFile* imageFile = NULL; CaretAssertArrayIndex(m_imageFileInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_imageFileInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); imageFile = m_imageFileInTab[tabIndex]; } else { const int32_t displayGroupInt = DisplayGroupEnum::toIntegerCode(displayGroup); CaretAssertArrayIndex(m_imageFileInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, displayGroupInt); imageFile = m_imageFileInDisplayGroup[displayGroupInt]; } const std::vector allImageFiles = m_parentBrain->getAllImagesFiles(); if (imageFile != NULL) { if (std::find(allImageFiles.begin(), allImageFiles.end(), imageFile) == allImageFiles.end()) { imageFile = NULL; } } if (imageFile == NULL) { if ( ! allImageFiles.empty()) { imageFile = allImageFiles[0]; } if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_imageFileInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_imageFileInTab[tabIndex] = imageFile; } else { CaretAssertArrayIndex(m_imageFileInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, (int)displayGroup); m_imageFileInDisplayGroup[displayGroup] = imageFile; } } return imageFile; } /** * Set the selected image. * @param displayGroup * Display group. * @param tabIndex * The tab index. * @param imageFile * Newly selected image file. */ void DisplayPropertiesImages::setSelectedImageFile(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, ImageFile* imageFile) { CaretAssertArrayIndex(m_imageFileInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_imageFileInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_imageFileInTab[tabIndex] = imageFile; } else { m_imageFileInDisplayGroup[displayGroup] = imageFile; } } /** * Get the minimum threshold value. * * @param displayGroup * Selected display group. * @param tabIndex * Selected tab. * @return * Threshold value for given display group and tab. */ float DisplayPropertiesImages::getThresholdMinimum(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { return m_thresholdMinimum->getValue(displayGroup, tabIndex); } /** * Set the minimum threshold value. * * @param displayGroup * Selected display group. * @param tabIndex * Selected tab. * @param value * Threshold value for given display group and tab. */ void DisplayPropertiesImages::setThresholdMinimum(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float value) { m_thresholdMinimum->setValue(displayGroup, tabIndex, value); } /** * Get the maximum threshold value. * * @param displayGroup * Selected display group. * @param tabIndex * Selected tab. * @return * Threshold value for given display group and tab. */ float DisplayPropertiesImages::getThresholdMaximum(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { return m_thresholdMaximum->getValue(displayGroup, tabIndex); } /** * Set the maximum threshold value. * * @param displayGroup * Selected display group. * @param tabIndex * Selected tab. * @param value * Threshold value for given display group and tab. */ void DisplayPropertiesImages::setThresholdMaximum(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float value) { m_thresholdMaximum->setValue(displayGroup, tabIndex, value); } /** * Get the opacity value. * * @param displayGroup * Selected display group. * @param tabIndex * Selected tab. * @return * Opacity value for given display group and tab. */ float DisplayPropertiesImages::getOpacity(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { return m_opacity->getValue(displayGroup, tabIndex); } /** * Set the opacity value. * * @param displayGroup * Selected display group. * @param tabIndex * Selected tab. * @param value * Opacity value for given display group and tab. */ void DisplayPropertiesImages::setOpacity(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float value) { m_opacity->setValue(displayGroup, tabIndex, value); } /** * @return The image position type. * @param displayGroup * Selected display group. * @param tabIndex * Selected tab. */ ImageDepthPositionEnum::Enum DisplayPropertiesImages::getImagePosition(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { return m_imageDepthPosition.getValue(displayGroup, tabIndex); } /** * Set the image position type. * @param displayGroup * Selected display group. * @param tabIndex * Selected tab. * @param positionType * New value for position type. */ void DisplayPropertiesImages::setImagePosition(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const ImageDepthPositionEnum::Enum positionType) { m_imageDepthPosition.setValue(displayGroup, tabIndex, positionType); } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* DisplayPropertiesImages::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { const std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); SceneClass* sceneClass = new SceneClass(instanceName, "DisplayPropertiesImages", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } std::vector pathNamesTabs; for (int32_t iTab = 0; iTab < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; iTab++) { const ImageFile* imageFile = getSelectedImageFile(DisplayGroupEnum::DISPLAY_GROUP_TAB, iTab); if (imageFile != NULL) { pathNamesTabs.push_back(imageFile->getFileName()); } else { pathNamesTabs.push_back(""); } } ScenePathNameArray* tabArray = new ScenePathNameArray("m_imageFileInTab", pathNamesTabs); sceneClass->addChild(tabArray); std::vector pathNamesDisplayGroup; for (int32_t idg = 0; idg < DisplayGroupEnum::NUMBER_OF_GROUPS; idg++) { DisplayGroupEnum::Enum displayGroup = DisplayGroupEnum::fromIntegerCode(idg, NULL); const ImageFile* imageFile = getSelectedImageFile(displayGroup, 0); if (imageFile != NULL) { pathNamesDisplayGroup.push_back(imageFile->getFileName()); } else { pathNamesDisplayGroup.push_back(""); } } ScenePathNameArray* displayGroupArray = new ScenePathNameArray("m_imageFileInDisplayGroup", pathNamesDisplayGroup); sceneClass->addChild(displayGroupArray); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void DisplayPropertiesImages::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_imageFileInTab[i] = NULL; } for (int32_t i = 0; i < DisplayGroupEnum::NUMBER_OF_GROUPS; i++) { m_imageFileInDisplayGroup[i] = NULL; } if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } const ScenePathNameArray* tabArray = sceneClass->getPathNameArray("m_imageFileInTab"); if (tabArray != NULL) { const int32_t numElements = tabArray->getNumberOfArrayElements(); const int32_t maxElem = std::min(numElements, (int32_t)BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); for (int32_t iTab = 0; iTab < maxElem; iTab++) { const ScenePathName* spn = tabArray->getScenePathNameAtIndex(iTab); CaretAssert(spn); const AString filename = spn->stringValue(); if ( ! filename.isEmpty()) { m_imageFileInTab[iTab] = findImageFile(filename); } } } const ScenePathNameArray* displayGroupArray = sceneClass->getPathNameArray("m_imageFileInDisplayGroup"); if (displayGroupArray != NULL) { const int32_t numElements = displayGroupArray->getNumberOfArrayElements(); const int32_t maxElem = std::min(numElements, (int32_t)DisplayGroupEnum::NUMBER_OF_GROUPS); for (int32_t idg = 0; idg < maxElem; idg++) { const ScenePathName* spn = displayGroupArray->getScenePathNameAtIndex(idg); CaretAssert(spn); const AString filename = spn->stringValue(); if ( ! filename.isEmpty()) { DisplayGroupEnum::Enum displayGroup = DisplayGroupEnum::fromIntegerCode(idg, NULL); m_imageFileInDisplayGroup[displayGroup] = findImageFile(filename); } } } /* * Old scenes image display status for tab */ const SceneObjectMapIntegerKey* oldTabStatus = sceneClass->getMapIntegerKey("m_displayStatusInTab"); if (oldTabStatus != NULL) { const std::map& dataMap = oldTabStatus->getMap(); for (auto& tabPrim : dataMap) { const int32_t tabIndex = tabPrim.first; const ScenePrimitive* primitive = dynamic_cast(tabPrim.second); CaretAssert(primitive); m_displayStatus->setValue(DisplayGroupEnum::DISPLAY_GROUP_TAB, tabIndex, primitive->booleanValue()); } } /* * Old scenes image display status for display group */ const ScenePrimitiveArray* oldGroupStatus = sceneClass->getPrimitiveArray("m_displayStatusInDisplayGroup"); if (oldGroupStatus != NULL) { const int32_t numValues = std::min(oldGroupStatus->getNumberOfArrayElements(), static_cast(DisplayGroupEnum::NUMBER_OF_GROUPS)); for (int32_t i = 0; i < numValues; i++) { bool validFlag = false; const DisplayGroupEnum::Enum dg = DisplayGroupEnum::fromIntegerCode(i, &validFlag); CaretAssert(validFlag); m_displayStatus->setValue(dg, 0, oldGroupStatus->booleanValue(i)); } } } /** * Find an image file by matching the full path name to the name of the * image file name. If full path name does not match match to just * the name of the file without any path. * * @param imageFiles * All of the image files. * @param imageFileName * Name of the image file. * @return * Matched image file, otherwise NULL. */ ImageFile* DisplayPropertiesImages::findImageFile(const AString& imageFileName) const { ImageFile* fullPathNameFile = NULL; ImageFile* nameOnlyFile = NULL; FileInformation fileInfo(imageFileName); const AString nameNoPath = fileInfo.getFileName(); const std::vector allImageFiles = m_parentBrain->getAllImagesFiles(); for (std::vector::const_iterator iter = allImageFiles.begin(); iter != allImageFiles.end(); iter++) { ImageFile* imageFile = *iter; if (imageFile->getFileName() == imageFileName) { fullPathNameFile = imageFile; break; } if (imageFile->getFileNameNoPath() == nameNoPath) { nameOnlyFile = imageFile; } } if (fullPathNameFile != NULL) { return fullPathNameFile; } if (nameOnlyFile == NULL) { CaretLogWarning("Unable to find image file: " + imageFileName); } return nameOnlyFile; } connectome-workbench-1.4.2/src/Brain/DisplayPropertiesImages.h000066400000000000000000000136221360521144700244420ustar00rootroot00000000000000#ifndef __DISPLAY_PROPERTIES_IMAGES_H__ #define __DISPLAY_PROPERTIES_IMAGES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "CaretPointer.h" #include "DisplayGroupEnum.h" #include "DisplayProperties.h" #include "DisplayPropertyDataEnum.h" #include "ImageDepthPositionEnum.h" namespace caret { class Brain; class DisplayPropertyDataBoolean; class DisplayPropertyDataFloat; class ImageFile; class DisplayPropertiesImages : public DisplayProperties { public: DisplayPropertiesImages(Brain* parentBrain); virtual ~DisplayPropertiesImages(); virtual void reset(); virtual void update(); virtual void copyDisplayProperties(const int32_t sourceTabIndex, const int32_t targetTabIndex); bool isDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool displayStatus); bool isControlPointsDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setControlPointsDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool displayStatus); DisplayGroupEnum::Enum getDisplayGroupForTab(const int32_t browserTabIndex) const; void setDisplayGroupForTab(const int32_t browserTabIndex, const DisplayGroupEnum::Enum displayGroup); ImageFile* getSelectedImageFile(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setSelectedImageFile(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, ImageFile* imageFile); float getThresholdMinimum(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setThresholdMinimum(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float value); float getThresholdMaximum(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setThresholdMaximum(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float value); float getOpacity(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setOpacity(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float value); ImageDepthPositionEnum::Enum getImagePosition(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setImagePosition(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const ImageDepthPositionEnum::Enum positionType); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // ADD_NEW_METHODS_HERE private: DisplayPropertiesImages(const DisplayPropertiesImages&); DisplayPropertiesImages& operator=(const DisplayPropertiesImages&); ImageFile* findImageFile(const AString& imageFileName) const; Brain* m_parentBrain; DisplayGroupEnum::Enum m_displayGroup[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; CaretPointer m_displayStatus; CaretPointer m_controlPointDisplayStatus; mutable ImageFile* m_imageFileInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; mutable ImageFile* m_imageFileInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; DisplayPropertyDataEnum m_imageDepthPosition; CaretPointer m_thresholdMinimum; CaretPointer m_thresholdMaximum; CaretPointer m_opacity; // ADD_NEW_MEMBERS_HERE }; #ifdef __DISPLAY_PROPERTIES_IMAGES_DECLARE__ // #endif // __DISPLAY_PROPERTIES_IMAGES_DECLARE__ } // namespace #endif //__DISPLAY_PROPERTIES_IMAGES_H__ connectome-workbench-1.4.2/src/Brain/DisplayPropertiesLabels.cxx000066400000000000000000000127041360521144700250120ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __DISPLAY_PROPERTIES_LABELS_DECLARE__ #include "DisplayPropertiesLabels.h" #include "SceneClassAssistant.h" #include "SceneAttributes.h" #include "SceneClass.h" #undef __DISPLAY_PROPERTIES_LABELS_DECLARE__ using namespace caret; /** * \class caret::DisplayPropertiesLabels * \brief Display properties for labels */ /** * Constructor. */ DisplayPropertiesLabels::DisplayPropertiesLabels() : DisplayProperties() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_displayGroup[i] = DisplayGroupEnum::getDefaultValue(); } m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_displayGroup", m_displayGroup); } /** * Destructor. */ DisplayPropertiesLabels::~DisplayPropertiesLabels() { } /** * Copy the border display properties from one tab to another. * @param sourceTabIndex * Index of tab from which properties are copied. * @param targetTabIndex * Index of tab to which properties are copied. */ void DisplayPropertiesLabels::copyDisplayProperties(const int32_t sourceTabIndex, const int32_t targetTabIndex) { const DisplayGroupEnum::Enum displayGroup = this->getDisplayGroupForTab(sourceTabIndex); this->setDisplayGroupForTab(targetTabIndex, displayGroup); } /** * Reset all settings to their defaults * and remove any data. */ void DisplayPropertiesLabels::reset() { } /** * Update due to changes in data. */ void DisplayPropertiesLabels::update() { } /** * Get the display group for a given browser tab. * @param browserTabIndex * Index of browser tab. */ DisplayGroupEnum::Enum DisplayPropertiesLabels::getDisplayGroupForTab(const int32_t browserTabIndex) const { CaretAssertArrayIndex(m_displayGroup, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); return m_displayGroup[browserTabIndex]; } /** * Set the display group for a given browser tab. * @param browserTabIndex * Index of browser tab. * @param displayGroup * New value for display group. */ void DisplayPropertiesLabels::setDisplayGroupForTab(const int32_t browserTabIndex, const DisplayGroupEnum::Enum displayGroup) { CaretAssertArrayIndex(m_displayGroup, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); m_displayGroup[browserTabIndex] = displayGroup; } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* DisplayPropertiesLabels::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { const std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); SceneClass* sceneClass = new SceneClass(instanceName, "DisplayPropertiesLabels", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void DisplayPropertiesLabels::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } } connectome-workbench-1.4.2/src/Brain/DisplayPropertiesLabels.h000066400000000000000000000050461360521144700244400ustar00rootroot00000000000000#ifndef __DISPLAY_PROPERTIES_LABELS__H_ #define __DISPLAY_PROPERTIES_LABELS__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "DisplayGroupEnum.h" #include "DisplayProperties.h" namespace caret { class DisplayPropertiesLabels : public DisplayProperties { public: DisplayPropertiesLabels(); virtual ~DisplayPropertiesLabels(); virtual void reset(); virtual void update(); virtual void copyDisplayProperties(const int32_t sourceTabIndex, const int32_t targetTabIndex); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); DisplayGroupEnum::Enum getDisplayGroupForTab(const int32_t browserTabIndex) const; void setDisplayGroupForTab(const int32_t browserTabIndex, const DisplayGroupEnum::Enum displayGroup); private: DisplayPropertiesLabels(const DisplayPropertiesLabels&); DisplayPropertiesLabels& operator=(const DisplayPropertiesLabels&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE DisplayGroupEnum::Enum m_displayGroup[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; }; #ifdef __DISPLAY_PROPERTIES_LABELS_DECLARE__ // #endif // __DISPLAY_PROPERTIES_LABELS_DECLARE__ } // namespace #endif //__DISPLAY_PROPERTIES_LABELS__H_ connectome-workbench-1.4.2/src/Brain/DisplayPropertiesSurface.cxx000066400000000000000000000144111360521144700251750ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __DISPLAY_PROPERTIES_SURFACE_DECLARE__ #include "DisplayPropertiesSurface.h" #undef __DISPLAY_PROPERTIES_SURFACE_DECLARE__ #include "SceneClassAssistant.h" #include "SceneAttributes.h" #include "SceneClass.h" using namespace caret; /** * \class DisplayPropertiesSurface * \brief Display properties for surface drawing attributes. * * Display properties for surface drawing attributes. */ /** * Constructor. */ DisplayPropertiesSurface::DisplayPropertiesSurface() : DisplayProperties() { m_displayNormalVectors = false; m_linkSize = 2.0; m_nodeSize = 2.0; m_surfaceDrawingType = SurfaceDrawingTypeEnum::DRAW_AS_TRIANGLES; m_opacity = 1.0; m_sceneAssistant->add("m_displayNormalVectors", &m_displayNormalVectors); m_sceneAssistant->add("m_linkSize", &m_linkSize); m_sceneAssistant->add("m_nodeSize", &m_nodeSize); m_sceneAssistant->add("m_opacity", &m_opacity); m_sceneAssistant->add("m_surfaceDrawingType", &m_surfaceDrawingType); } /** * Destructor. */ DisplayPropertiesSurface::~DisplayPropertiesSurface() { } /** * Reset all settings to their defaults * and remove any data. */ void DisplayPropertiesSurface::reset() { } /** * Update due to changes in data. */ void DisplayPropertiesSurface::update() { } /** * Copy the display properties from one tab to another. * @param sourceTabIndex * Index of tab from which properties are copied. * @param targetTabIndex * Index of tab to which properties are copied. */ void DisplayPropertiesSurface::copyDisplayProperties(const int32_t /*sourceTabIndex*/, const int32_t /*targetTabIndex*/) { } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* DisplayPropertiesSurface::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "DisplayPropertiesSurface", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void DisplayPropertiesSurface::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } } /** * @return The surface drawing type */ SurfaceDrawingTypeEnum::Enum DisplayPropertiesSurface::getSurfaceDrawingType() const { return m_surfaceDrawingType; } /** * Set the surface drawing type. * * @param surfaceDrawingType * The surface drawing type */ void DisplayPropertiesSurface::setSurfaceDrawingType(const SurfaceDrawingTypeEnum::Enum surfaceDrawingType) { m_surfaceDrawingType = surfaceDrawingType; } /** * @return Node size. */ float DisplayPropertiesSurface::getNodeSize() const { return m_nodeSize; } /** * Set node size * * @param nodeSize * New node size. */ void DisplayPropertiesSurface::setNodeSize(const float nodeSize) { m_nodeSize = nodeSize; } /** * @return Link size. */ float DisplayPropertiesSurface::getLinkSize() const { return m_linkSize; } /** * Set link size. * * @param linkSize * New link size. */ void DisplayPropertiesSurface::setLinkSize(const float linkSize) { m_linkSize = linkSize; } /** * @return Display normal vectors. */ bool DisplayPropertiesSurface::isDisplayNormalVectors() const { return m_displayNormalVectors; } /** * Set display normal vectors. * * @param displayNormalVectors * New value for display normal vectors. */ void DisplayPropertiesSurface::setDisplayNormalVectors(const bool displayNormalVectors) { m_displayNormalVectors = displayNormalVectors; } /** * @return The overall surface opacity. */ float DisplayPropertiesSurface::getOpacity() const { return m_opacity; } /** * Set the overall surface opacity. * * @param opacity * New value for opacity. */ void DisplayPropertiesSurface::setOpacity(const float opacity) { m_opacity = opacity; } connectome-workbench-1.4.2/src/Brain/DisplayPropertiesSurface.h000066400000000000000000000055151360521144700246270ustar00rootroot00000000000000#ifndef __DISPLAY_PROPERTIES_SURFACE_H_ #define __DISPLAY_PROPERTIES_SURFACE_H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "DisplayProperties.h" #include "SurfaceDrawingTypeEnum.h" namespace caret { class Surface; class DisplayPropertiesSurface : public DisplayProperties { public: DisplayPropertiesSurface(); virtual ~DisplayPropertiesSurface(); void reset(); void update(); virtual void copyDisplayProperties(const int32_t sourceTabIndex, const int32_t targetTabIndex); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); SurfaceDrawingTypeEnum::Enum getSurfaceDrawingType() const; void setSurfaceDrawingType(const SurfaceDrawingTypeEnum::Enum surfaceDrawingType); float getNodeSize() const; void setNodeSize(const float nodeSize); float getLinkSize() const; void setLinkSize(const float linkSize); bool isDisplayNormalVectors() const; void setDisplayNormalVectors(const bool displayNormalVectors); float getOpacity() const; void setOpacity(const float opacity); private: DisplayPropertiesSurface(const DisplayPropertiesSurface&); DisplayPropertiesSurface& operator=(const DisplayPropertiesSurface&); float m_nodeSize; float m_linkSize; bool m_displayNormalVectors; SurfaceDrawingTypeEnum::Enum m_surfaceDrawingType; float m_opacity; }; #ifdef __DISPLAY_PROPERTIES_SURFACE_DECLARE__ #endif // __DISPLAY_PROPERTIES_SURFACE_DECLARE__ } // namespace #endif //__DISPLAY_PROPERTIES_SURFACE_H_ connectome-workbench-1.4.2/src/Brain/DisplayPropertiesVolume.cxx000066400000000000000000000104441360521144700250560ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __DISPLAY_PROPERTIES_VOLUME_DECLARE__ #include "DisplayPropertiesVolume.h" #undef __DISPLAY_PROPERTIES_VOLUME_DECLARE__ #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class DisplayPropertiesVolume * \brief Display properties for volume slices. * * Display properties for volume slices. */ /** * Constructor. */ DisplayPropertiesVolume::DisplayPropertiesVolume() : DisplayProperties() { m_opacity = 1.0f; m_sceneAssistant->add("m_opacity", &m_opacity); } /** * Destructor. */ DisplayPropertiesVolume::~DisplayPropertiesVolume() { } /** * Reset all settings to their defaults * and remove any data. */ void DisplayPropertiesVolume::reset() { m_opacity = 1.0f; } /** * Update due to changes in data. */ void DisplayPropertiesVolume::update() { } /** * Copy the display properties from one tab to another. * @param sourceTabIndex * Index of tab from which properties are copied. * @param targetTabIndex * Index of tab to which properties are copied. */ void DisplayPropertiesVolume::copyDisplayProperties(const int32_t /*sourceTabIndex*/, const int32_t /*targetTabIndex*/) { } /** * @return The overall surface opacity. */ float DisplayPropertiesVolume::getOpacity() const { return m_opacity; } /** * Set the overall surface opacity. * * @param opacity * New value for opacity. */ void DisplayPropertiesVolume::setOpacity(const float opacity) { m_opacity = opacity; } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* DisplayPropertiesVolume::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "DisplayPropertiesVolume", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void DisplayPropertiesVolume::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } } connectome-workbench-1.4.2/src/Brain/DisplayPropertiesVolume.h000066400000000000000000000041661360521144700245070ustar00rootroot00000000000000#ifndef __DISPLAY_PROPERTIES_VOLUME__H_ #define __DISPLAY_PROPERTIES_VOLUME__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "DisplayProperties.h" namespace caret { class Surface; class DisplayPropertiesVolume : public DisplayProperties { public: DisplayPropertiesVolume(); virtual ~DisplayPropertiesVolume(); void reset(); void update(); float getOpacity() const; void setOpacity(const float opacity); virtual void copyDisplayProperties(const int32_t sourceTabIndex, const int32_t targetTabIndex); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: DisplayPropertiesVolume(const DisplayPropertiesVolume&); DisplayPropertiesVolume& operator=(const DisplayPropertiesVolume&); float m_opacity = 1.0f; }; #ifdef __DISPLAY_PROPERTIES_VOLUME_DECLARE__ #endif // __DISPLAY_PROPERTIES_VOLUME_DECLARE__ } // namespace #endif //__DISPLAY_PROPERTIES_VOLUME__H_ connectome-workbench-1.4.2/src/Brain/DisplayPropertyDataBoolean.cxx000066400000000000000000000140461360521144700254520ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __DISPLAY_PROPERTY_DATA_BOOLEAN_DECLARE__ #include "DisplayPropertyDataBoolean.h" #undef __DISPLAY_PROPERTY_DATA_BOOLEAN_DECLARE__ #include "CaretAssert.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::DisplayPropertyDataBoolean * \brief Boolean data for display property tab/display group * \ingroup Brain */ /** * Constructor that initializes with the given default value. * * @param defaultValue * Default data value. */ DisplayPropertyDataBoolean::DisplayPropertyDataBoolean(const bool defaultValue) : CaretObject() { setAllValues(defaultValue); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->addTabIndexedBooleanArray("m_tabValues", m_tabValues); m_sceneAssistant->addArray("m_displayGroupValues", m_displayGroupValues, DisplayGroupEnum::NUMBER_OF_GROUPS, defaultValue); } /** * Destructor. */ DisplayPropertyDataBoolean::~DisplayPropertyDataBoolean() { delete m_sceneAssistant; } /** * Copy the values from one tab to another. * * @param sourceTabIndex * Index of tab from which values are copied. * @param targetTabIndex * Index of tab to which values are copied. */ void DisplayPropertyDataBoolean::copyValues(const int32_t sourceTabIndex, const int32_t targetTabIndex) { CaretAssertArrayIndex(m_tabValues, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, sourceTabIndex); CaretAssertArrayIndex(m_tabValues, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, targetTabIndex); m_tabValues[targetTabIndex] = m_tabValues[sourceTabIndex]; } /** * @return The data value. * * @param displayGroup * Display group. * @param tabIndex * Tab index. */ bool DisplayPropertyDataBoolean::getValue(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_displayGroupValues, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_tabValues, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_tabValues[tabIndex]; } return m_displayGroupValues[displayGroup]; } /** * Set all display groups and tabs to the given value. * * @param value * The value. */ void DisplayPropertyDataBoolean::setAllValues(const bool value) { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_tabValues[i] = value; } for (int32_t i = 0; i < DisplayGroupEnum::NUMBER_OF_GROUPS; i++) { m_displayGroupValues[i] = value; } } /** * Set the data value. * * @param displayGroup * Display group. * @param tabIndex * Tab index. * @param value * New value. */ void DisplayPropertyDataBoolean::setValue(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool value) { CaretAssertArrayIndex(m_displayGroupValues, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_tabValues, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_tabValues[tabIndex] = value; } else { m_displayGroupValues[displayGroup] = value; } } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* DisplayPropertyDataBoolean::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "DisplayPropertyDataBoolean", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void DisplayPropertyDataBoolean::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } connectome-workbench-1.4.2/src/Brain/DisplayPropertyDataBoolean.h000066400000000000000000000065021360521144700250750ustar00rootroot00000000000000#ifndef __DISPLAY_PROPERTY_DATA_BOOLEAN_H__ #define __DISPLAY_PROPERTY_DATA_BOOLEAN_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "CaretObject.h" #include "DisplayGroupEnum.h" #include "SceneableInterface.h" namespace caret { class SceneClassAssistant; class DisplayPropertyDataBoolean : public CaretObject, public SceneableInterface { public: DisplayPropertyDataBoolean(const bool defaultValue); virtual ~DisplayPropertyDataBoolean(); void setAllValues(const bool value); void copyValues(const int32_t sourceTabIndex, const int32_t targetTabIndex); bool getValue(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setValue(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool value); // ADD_NEW_METHODS_HERE virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implementation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: DisplayPropertyDataBoolean(const DisplayPropertyDataBoolean& obj); DisplayPropertyDataBoolean& operator=(const DisplayPropertyDataBoolean& obj); SceneClassAssistant* m_sceneAssistant; bool m_displayGroupValues[DisplayGroupEnum::NUMBER_OF_GROUPS]; bool m_tabValues[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; // ADD_NEW_MEMBERS_HERE }; #ifdef __DISPLAY_PROPERTY_DATA_BOOLEAN_DECLARE__ // #endif // __DISPLAY_PROPERTY_DATA_BOOLEAN_DECLARE__ } // namespace #endif //__DISPLAY_PROPERTY_DATA_BOOLEAN_H__ connectome-workbench-1.4.2/src/Brain/DisplayPropertyDataEnum.h000066400000000000000000000233061360521144700244230ustar00rootroot00000000000000#ifndef __DISPLAY_PROPERTY_DATA_ENUM_H__ #define __DISPLAY_PROPERTY_DATA_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "CaretAssert.h" #include "CaretObject.h" #include "DisplayGroupEnum.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "SceneableInterface.h" /** * \class caret::DisplayPropertyDataEnum * \brief Enumerated data for display property tab/display group * \ingroup Brain */ namespace caret { class SceneClassAssistant; template class DisplayPropertyDataEnum : public CaretObject, public SceneableInterface { public: /** * Constructor. */ DisplayPropertyDataEnum() : CaretObject() { m_sceneAssistant.grabNew(NULL); } /** * Initializes with the given default value. * * MUST BE CALLED BEFORE ANY OTHER METHOD !!! * * @param defaultValue * Default data value. */ void initialize(const ET defaultValue) { m_sceneAssistant.grabNew(new SceneClassAssistant()); /* * NOTE: must be called after creating scene class assistant */ setAllValues(defaultValue); m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_tabValues", m_tabValues); m_sceneAssistant->addArray("m_displayGroupValues", m_displayGroupValues, DisplayGroupEnum::NUMBER_OF_GROUPS, defaultValue); } /** * Destructor. */ virtual ~DisplayPropertyDataEnum() { } /** * Set all display groups and tabs to the given value. * * @param value * The value. */ void setAllValues(const ET value) { CaretAssertMessage(m_sceneAssistant.getPointer(), "Failed to call initialize(defaultValue) for the enumerated type"); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_tabValues[i] = value; } for (int32_t i = 0; i < DisplayGroupEnum::NUMBER_OF_GROUPS; i++) { m_displayGroupValues[i] = value; } } /** * Copy the values from one tab to another. * * @param sourceTabIndex * Index of tab from which values are copied. * @param targetTabIndex * Index of tab to which values are copied. */ void copyValues(const int32_t sourceTabIndex, const int32_t targetTabIndex) { CaretAssertMessage(m_sceneAssistant.getPointer(), "Failed to call initialize(defaultValue) for the enumerated type"); CaretAssertArrayIndex(m_tabValues, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, sourceTabIndex); CaretAssertArrayIndex(m_tabValues, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, targetTabIndex); m_tabValues[targetTabIndex] = m_tabValues[sourceTabIndex]; } /** * @return The data value. * * @param displayGroup * Display group. * @param tabIndex * Tab index. */ ET getValue(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertMessage(m_sceneAssistant.getPointer(), "Failed to call initialize(defaultValue) for the enumerated type"); CaretAssertArrayIndex(m_displayGroupValues, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_tabValues, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_tabValues[tabIndex]; } return m_displayGroupValues[displayGroup]; } /** * Set the data value. * * @param displayGroup * Display group. * @param tabIndex * Tab index. * @param value * New value. */ void setValue(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const ET value) { CaretAssertMessage(m_sceneAssistant.getPointer(), "Failed to call initialize(defaultValue) for the enumerated type"); CaretAssertArrayIndex(m_displayGroupValues, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_tabValues, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_tabValues[tabIndex] = value; } else { m_displayGroupValues[displayGroup] = value; } } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { CaretAssertMessage(m_sceneAssistant.getPointer(), "Failed to call initialize(defaultValue) for the enumerated type"); SceneClass* sceneClass = new SceneClass(instanceName, "DisplayPropertyDataEnum", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { CaretAssertMessage(m_sceneAssistant.getPointer(), "Failed to call initialize(defaultValue) for the enumerated type"); if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implementation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: DisplayPropertyDataEnum(const DisplayPropertyDataEnum& obj); DisplayPropertyDataEnum& operator=(const DisplayPropertyDataEnum& obj); CaretPointer m_sceneAssistant; ET m_displayGroupValues[DisplayGroupEnum::NUMBER_OF_GROUPS]; ET m_tabValues[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; // ADD_NEW_MEMBERS_HERE }; #ifdef __DISPLAY_PROPERTY_DATA_ENUM_DECLARE__ // #endif // __DISPLAY_PROPERTY_DATA_ENUM_DECLARE__ } // namespace #endif //__DISPLAY_PROPERTY_DATA_ENUM_H__ connectome-workbench-1.4.2/src/Brain/DisplayPropertyDataFloat.cxx000066400000000000000000000140101360521144700251270ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __DISPLAY_PROPERTY_DATA_FLOAT_DECLARE__ #include "DisplayPropertyDataFloat.h" #undef __DISPLAY_PROPERTY_DATA_FLOAT_DECLARE__ #include "CaretAssert.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::DisplayPropertyDataFloat * \brief Float data for display property tab/display group * \ingroup Brain */ /** * Constructor that initializes with the given default value. * * @param defaultValue * Default data value. */ DisplayPropertyDataFloat::DisplayPropertyDataFloat(const float defaultValue) : CaretObject() { setAllValues(defaultValue); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->addTabIndexedFloatArray("m_tabValues", m_tabValues); m_sceneAssistant->addArray("m_displayGroupValues", m_displayGroupValues, DisplayGroupEnum::NUMBER_OF_GROUPS, defaultValue); } /** * Destructor. */ DisplayPropertyDataFloat::~DisplayPropertyDataFloat() { delete m_sceneAssistant; } /** * Copy the values from one tab to another. * * @param sourceTabIndex * Index of tab from which values are copied. * @param targetTabIndex * Index of tab to which values are copied. */ void DisplayPropertyDataFloat::copyValues(const int32_t sourceTabIndex, const int32_t targetTabIndex) { CaretAssertArrayIndex(m_tabValues, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, sourceTabIndex); CaretAssertArrayIndex(m_tabValues, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, targetTabIndex); m_tabValues[targetTabIndex] = m_tabValues[sourceTabIndex]; } /** * @return The data value. * * @param displayGroup * Display group. * @param tabIndex * Tab index. */ float DisplayPropertyDataFloat::getValue(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { CaretAssertArrayIndex(m_displayGroupValues, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_tabValues, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_tabValues[tabIndex]; } return m_displayGroupValues[displayGroup]; } /** * Set all display groups and tabs to the given value. * * @param value * The value. */ void DisplayPropertyDataFloat::setAllValues(const float value) { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_tabValues[i] = value; } for (int32_t i = 0; i < DisplayGroupEnum::NUMBER_OF_GROUPS; i++) { m_displayGroupValues[i] = value; } } /** * Set the data value. * * @param displayGroup * Display group. * @param tabIndex * Tab index. * @param value * New value. */ void DisplayPropertyDataFloat::setValue(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float value) { CaretAssertArrayIndex(m_displayGroupValues, DisplayGroupEnum::NUMBER_OF_GROUPS, static_cast(displayGroup)); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_tabValues, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_tabValues[tabIndex] = value; } else { m_displayGroupValues[displayGroup] = value; } } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* DisplayPropertyDataFloat::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "DisplayPropertyDataFloat", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void DisplayPropertyDataFloat::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } connectome-workbench-1.4.2/src/Brain/DisplayPropertyDataFloat.h000066400000000000000000000064601360521144700245660ustar00rootroot00000000000000#ifndef __DISPLAY_PROPERTY_DATA_FLOAT_H__ #define __DISPLAY_PROPERTY_DATA_FLOAT_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "CaretObject.h" #include "DisplayGroupEnum.h" #include "SceneableInterface.h" namespace caret { class SceneClassAssistant; class DisplayPropertyDataFloat : public CaretObject, public SceneableInterface { public: DisplayPropertyDataFloat(const float defaultValue); virtual ~DisplayPropertyDataFloat(); void setAllValues(const float value); void copyValues(const int32_t sourceTabIndex, const int32_t targetTabIndex); float getValue(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setValue(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const float value); // ADD_NEW_METHODS_HERE virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implementation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: DisplayPropertyDataFloat(const DisplayPropertyDataFloat& obj); DisplayPropertyDataFloat& operator=(const DisplayPropertyDataFloat& obj); SceneClassAssistant* m_sceneAssistant; float m_displayGroupValues[DisplayGroupEnum::NUMBER_OF_GROUPS]; float m_tabValues[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; // ADD_NEW_MEMBERS_HERE }; #ifdef __DISPLAY_PROPERTY_DATA_FLOAT_DECLARE__ // #endif // __DISPLAY_PROPERTY_DATA_FLOAT_DECLARE__ } // namespace #endif //__DISPLAY_PROPERTY_DATA_FLOAT_H__ connectome-workbench-1.4.2/src/Brain/DummyFontTextRenderer.cxx000066400000000000000000000264341360521144700244700ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __DUMMY_FONT_TEXT_RENDERER_DECLARE__ #include "DummyFontTextRenderer.h" #undef __DUMMY_FONT_TEXT_RENDERER_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::DummyFontTextRenderer * \brief A dummy font text renderer used when no valid text renderer is available. * \ingroup Brain * * This "dummy" text renderer is used when a valid text renderer (Qt, FTGL) is * not available. Without this dummy text renderer, any graphics code that * draws text would need to check that the text renderer is valid. This * dummy text renderer does nothing other than prevent the software from * crashing. */ /** * Constructor. */ DummyFontTextRenderer::DummyFontTextRenderer() : BrainOpenGLTextRenderInterface() { } /** * Destructor. */ DummyFontTextRenderer::~DummyFontTextRenderer() { } /** * @return The font system is valid. */ bool DummyFontTextRenderer::isValid() const { return true; } /** * Draw annnotation text at the given viewport coordinates using * the the annotations attributes for the style of text. * * Depth testing is DISABLED when drawing text with this method. * * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param annotationText * Annotation text and attributes. */ void DummyFontTextRenderer::drawTextAtViewportCoords(const double /*viewportX*/, const double /*viewportY*/, const AnnotationText& /*annotationText*/, const DrawingFlags& /*flags*/) { } /** * Draw annnotation text at the given viewport coordinates using * the the annotations attributes for the style of text. * * Depth testing is ENABLED when drawing text with this method. * * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. * @param annotationText * Annotation text and attributes. */ void DummyFontTextRenderer::drawTextAtViewportCoords(const double /*viewportX*/, const double /*viewportY*/, const double /*viewportZ*/, const AnnotationText& /*annotationText*/, const DrawingFlags& /*flags*/) { } /** * Draw annnotation text at the given model coordinates using * the the annotations attributes for the style of text. * Text is drawn so that is in the plane of the screen (faces user) * * Depth testing is ENABLED when drawing text with this method. * * @param modelX * Model X-coordinate. * @param modelY * Model Y-coordinate. * @param modelZ * Model Z-coordinate. * @param annotationText * Annotation text and attributes. * @param flags * Drawing flags. */ void DummyFontTextRenderer::drawTextAtModelCoordsFacingUser(const double /*modelX*/, const double /*modelY*/, const double /*modelZ*/, const AnnotationText& /*annotationText*/, const DrawingFlags& /*flags*/) { } /** * Draw text in model space using the current model transformations. * * Depth testing is ENABLED when drawing text with this method. * * @param annotationText * Annotation text and attributes. * @param modelSpaceScaling * Scaling in the model space. * @param heightOrWidthForPercentageSizeText * If positive, use it to override width/height of viewport. * @param normalVector * Normal vector of text. * @param flags * Drawing flags. */ void DummyFontTextRenderer::drawTextInModelSpace(const AnnotationText& /* annotationText */, const float /*modelSpaceScaling*/, const float /*heightOrWidthForPercentageSizeText*/, const float* /*normalVector[3]*/, const DrawingFlags& /* flags */) { } /** * Get the bounds of text drawn in model space using the current model transformations. * * @param annotationText * Text that is to be drawn. * @param modelSpaceScaling * Scaling in the model space. * @param heightOrWidthForPercentageSizeText * Size of region used when converting percentage size to a fixed size * @param flags * Drawing flags. * @param bottomLeftOut * The bottom left corner of the text bounds. * @param bottomRightOut * The bottom right corner of the text bounds. * @param topRightOut * The top right corner of the text bounds. * @param topLeftOut * The top left corner of the text bounds. * @param underlineStartOut * Starting coordinate for drawing text underline. * @param underlineEndOut * Ending coordinate for drawing text underline. */ void DummyFontTextRenderer::getBoundsForTextInModelSpace(const AnnotationText& /*annotationText*/, const float /*modelSpaceScaling*/, const float /*heightOrWidthForPercentageSizeText*/, const DrawingFlags& /*flags*/, double* /*bottomLeftOut[3]*/, double* /*bottomRightOut[3]*/, double* /*topRightOut[3]*/, double* /*topLeftOut[3]*/, double* /*underlineStartOut[3]*/, double* /*underlineEndOut[3]*/) { } /** * Get the bounds of text (in pixels) using the given text * attributes. * * See http://ftgl.sourceforge.net/docs/html/metrics.png * * @param annotationText * Text that is to be drawn. * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. * @param viewportWidth * Height of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param bottomLeftOut * The bottom left corner of the text bounds. * @param bottomRightOut * The bottom right corner of the text bounds. * @param topRightOut * The top right corner of the text bounds. * @param topLeftOut * The top left corner of the text bounds. */ void DummyFontTextRenderer::getBoundsForTextAtViewportCoords(const AnnotationText& /*annotationText*/, const DrawingFlags& /*flags*/, const double /*viewportX*/, const double /*viewportY*/, const double /*viewportZ*/, const double /*viewportWidth*/, const double /*viewportHeight*/, double* /*bottomLeftOut[3]*/, double* /*bottomRightOut[3]*/, double* /*topRightOut[3]*/, double* /*topLeftOut[3]*/) { } /** * Get the bounds of text (in pixels) using the given text * attributes. NO MARGIN is placed around the text. * * See http://ftgl.sourceforge.net/docs/html/metrics.png * * @param annotationText * Text that is to be drawn. * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. * @param viewportWidth * Width of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param bottomLeftOut * The bottom left corner of the text bounds. * @param bottomRightOut * The bottom right corner of the text bounds. * @param topRightOut * The top right corner of the text bounds. * @param topLeftOut * The top left corner of the text bounds. */ void DummyFontTextRenderer::getBoundsWithoutMarginForTextAtViewportCoords(const AnnotationText& /*annotationText*/, const DrawingFlags& /*flags*/, const double /*viewportX*/, const double /*viewportY*/, const double /*viewportZ*/, const double /*viewportWidth*/, const double /*viewportHeight*/, double* /*bottomLeftOut[3]*/, double* /*bottomRightOut[3]*/, double* /*topRightOut[3]*/, double* /*topLeftOut[3]*/) { } /** * Get the estimated width and height of text (in pixels) using the given text * attributes. * * See http://ftgl.sourceforge.net/docs/html/metrics.png * * @param annotationText * Text for width and height estimation. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param widthOut * Estimated width of text. * @param heightOut * Estimated height of text. */ void DummyFontTextRenderer::getTextWidthHeightInPixels(const AnnotationText& /*annotationText*/, const DrawingFlags& /*flags*/, const double /*viewportWidth*/, const double /*viewportHeight*/, double& /*widthOut*/, double& /*heightOut*/) { } /** * @return Name of the text renderer. */ AString DummyFontTextRenderer::getName() const { return "Dummy (No OpenGL font system)"; } connectome-workbench-1.4.2/src/Brain/DummyFontTextRenderer.h000066400000000000000000000143571360521144700241160ustar00rootroot00000000000000#ifndef __DUMMY_FONT_TEXT_RENDERER_H__ #define __DUMMY_FONT_TEXT_RENDERER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainOpenGLTextRenderInterface.h" namespace caret { class DummyFontTextRenderer : public BrainOpenGLTextRenderInterface { public: DummyFontTextRenderer(); virtual ~DummyFontTextRenderer(); bool isValid() const; virtual void drawTextAtViewportCoords(const double viewportX, const double viewportY, const double viewportZ, const AnnotationText& annotationText, const DrawingFlags& flags) override; virtual void drawTextAtViewportCoords(const double viewportX, const double viewportY, const AnnotationText& annotationText, const DrawingFlags& flags) override; virtual void drawTextAtModelCoordsFacingUser(const double modelX, const double modelY, const double modelZ, const AnnotationText& annotationText, const DrawingFlags& flags) override; virtual void drawTextInModelSpace(const AnnotationText& annotationText, const float modelSpaceScaling, const float heightOrWidthForPercentageSizeText, const float normalVector[3], const DrawingFlags& flags) override; virtual void getTextWidthHeightInPixels(const AnnotationText& annotationText, const DrawingFlags& flags, const double viewportWidth, const double viewportHeight, double& widthOut, double& heightOut) override; virtual void getBoundsForTextInModelSpace(const AnnotationText& annotationText, const float modelSpaceScaling, const float heightOrWidthForPercentageSizeText, const DrawingFlags& flags, double bottomLeftOut[3], double bottomRightOut[3], double topRightOut[3], double topLeftOut[3], double underlineStartOut[3], double underlineEndOut[3]) override; virtual void getBoundsForTextAtViewportCoords(const AnnotationText& annotationText, const DrawingFlags& flags, const double viewportX, const double viewportY, const double viewportZ, const double viewportWidth, const double viewportHeight, double bottomLeftOut[3], double bottomRightOut[3], double topRightOut[3], double topLeftOut[3]) override; virtual void getBoundsWithoutMarginForTextAtViewportCoords(const AnnotationText& annotationText, const DrawingFlags& flags, const double viewportX, const double viewportY, const double viewportZ, const double viewportWidth, const double viewportHeight, double bottomLeftOut[3], double bottomRightOut[3], double topRightOut[3], double topLeftOut[3]) override; virtual AString getName() const; // ADD_NEW_METHODS_HERE private: DummyFontTextRenderer(const DummyFontTextRenderer&); DummyFontTextRenderer& operator=(const DummyFontTextRenderer&); // ADD_NEW_MEMBERS_HERE }; #ifdef __DUMMY_FONT_TEXT_RENDERER_DECLARE__ // #endif // __DUMMY_FONT_TEXT_RENDERER_DECLARE__ } // namespace #endif //__DUMMY_FONT_TEXT_RENDERER_H__ connectome-workbench-1.4.2/src/Brain/EventAnnotationColorBarGet.cxx000066400000000000000000000065161360521144700254110ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_ANNOTATION_COLOR_BAR_GET_DECLARE__ #include "EventAnnotationColorBarGet.h" #undef __EVENT_ANNOTATION_COLOR_BAR_GET_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventAnnotationColorBarGet * \brief Event to get annontation color bars for tab(s). * \ingroup Brain */ /** * Constructor for getting annotations for ALL tabs. */ EventAnnotationColorBarGet::EventAnnotationColorBarGet() : Event(EventTypeEnum::EVENT_ANNOTATION_COLOR_BAR_GET), m_allTabsFlag(true) { } /** * Constructor for getting annotations for the given tab index. * * @param tabIndex * Index of tab for which color bars are requested. */ EventAnnotationColorBarGet::EventAnnotationColorBarGet(const int32_t tabIndex) : Event(EventTypeEnum::EVENT_ANNOTATION_COLOR_BAR_GET), m_allTabsFlag(false) { m_tabIndices.insert(tabIndex); } /** * Constructor for getting annotations for the given tab indices. * * @param tabIndices * Indices of tabs for which color bars are requested. If * the indices are empty no colorbars will be gotten. */ EventAnnotationColorBarGet::EventAnnotationColorBarGet(const std::vector& tabIndices) : Event(EventTypeEnum::EVENT_ANNOTATION_COLOR_BAR_GET), m_allTabsFlag(false) { m_tabIndices.insert(tabIndices.begin(), tabIndices.end()); } /** * Destructor. */ EventAnnotationColorBarGet::~EventAnnotationColorBarGet() { } /** * Add annotation color bars. * * @param annotationColorBars * Annotation color bars that are added. */ void EventAnnotationColorBarGet::addAnnotationColorBars(const std::vector& annotationColorBars) { m_annotationColorBars.insert(m_annotationColorBars.end(), annotationColorBars.begin(), annotationColorBars.end()); } /** * Are annotation color bars requested for the given tab index. * * @param tabIndex * Index of tab. * @return * True if annotations are requested for the given tab index, else false. */ bool EventAnnotationColorBarGet::isGetAnnotationColorBarsForTabIndex(const int32_t tabIndex) { if (m_allTabsFlag) { return true; } else if (m_tabIndices.find(tabIndex) != m_tabIndices.end()) { return true; } return false; } /** * @return The annotation color bars after event completes. */ std::vector EventAnnotationColorBarGet::getAnnotationColorBars() const { return m_annotationColorBars; } connectome-workbench-1.4.2/src/Brain/EventAnnotationColorBarGet.h000066400000000000000000000042731360521144700250340ustar00rootroot00000000000000#ifndef __EVENT_ANNOTATION_COLOR_BAR_GET_H__ #define __EVENT_ANNOTATION_COLOR_BAR_GET_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class AnnotationColorBar; class EventAnnotationColorBarGet : public Event { public: EventAnnotationColorBarGet(); EventAnnotationColorBarGet(const int32_t tabIndex); EventAnnotationColorBarGet(const std::vector& tabIndices); virtual ~EventAnnotationColorBarGet(); void addAnnotationColorBars(const std::vector& colorBars); bool isGetAnnotationColorBarsForTabIndex(const int32_t tabIndex); std::vector getAnnotationColorBars() const; // ADD_NEW_METHODS_HERE private: EventAnnotationColorBarGet(const EventAnnotationColorBarGet&); EventAnnotationColorBarGet& operator=(const EventAnnotationColorBarGet&); bool m_allTabsFlag; std::set m_tabIndices; std::vector m_annotationColorBars; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_ANNOTATION_COLOR_BAR_GET_DECLARE__ // #endif // __EVENT_ANNOTATION_COLOR_BAR_GET_DECLARE__ } // namespace #endif //__EVENT_ANNOTATION_COLOR_BAR_GET_H__ connectome-workbench-1.4.2/src/Brain/EventBrainReset.cxx000066400000000000000000000026741360521144700232520ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_BRAIN_RESET_DECLARE__ #include "EventBrainReset.h" #undef __EVENT_BRAIN_RESET_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventBrainReset * \brief Event issued when brain is reset (new spec or scene loaded). * \ingroup Brain */ /** * Constructor. */ EventBrainReset::EventBrainReset(Brain* brain) : Event(EventTypeEnum::EVENT_BRAIN_RESET), m_brain(brain) { } /** * Destructor. */ EventBrainReset::~EventBrainReset() { } /** * @return Brain that was reset. */ Brain* EventBrainReset::getBrain() const { return m_brain; } connectome-workbench-1.4.2/src/Brain/EventBrainReset.h000066400000000000000000000030421360521144700226650ustar00rootroot00000000000000#ifndef __EVENT_BRAIN_RESET_H__ #define __EVENT_BRAIN_RESET_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class Brain; class EventBrainReset : public Event { public: EventBrainReset(Brain* brain); virtual ~EventBrainReset(); Brain* getBrain() const; // ADD_NEW_METHODS_HERE private: EventBrainReset(const EventBrainReset&); EventBrainReset& operator=(const EventBrainReset&); Brain* m_brain; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_BRAIN_RESET_DECLARE__ // #endif // __EVENT_BRAIN_RESET_DECLARE__ } // namespace #endif //__EVENT_BRAIN_RESET_H__ connectome-workbench-1.4.2/src/Brain/EventBrainStructureGetAll.cxx000066400000000000000000000053551360521144700252600ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_BRAIN_STRUCTURE_GET_ALL_DECLARE__ #include "EventBrainStructureGetAll.h" #undef __EVENT_BRAIN_STRUCTURE_GET_ALL_DECLARE__ #include "BrainStructure.h" #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventBrainStructureGetAll * \brief Get all brain structures. * \ingroup Brain */ /** * Constructor. */ EventBrainStructureGetAll::EventBrainStructureGetAll() : Event(EventTypeEnum::EVENT_BRAIN_STRUCTURE_GET_ALL) { } /** * Destructor. */ EventBrainStructureGetAll::~EventBrainStructureGetAll() { } /** * Add a brain structure. * * @param brainStructure * Brain structure that is added. */ void EventBrainStructureGetAll::addBrainStructure(BrainStructure* brainStructure) { m_brainStructures.push_back(brainStructure); } /** * @return Number of brain structures that were found. */ int32_t EventBrainStructureGetAll::getNumberOfBrainStructures() const { return m_brainStructures.size(); } /** * Get the brain structure at the given index. * * @param indx * Index of the brain structure. * @return * Brain structure at the given index. */ BrainStructure* EventBrainStructureGetAll::getBrainStructureByIndex(const int32_t indx) { CaretAssertVectorIndex(m_brainStructures, indx); return m_brainStructures[indx]; } /** * Get the brain structure of the specified type. * * @param structure * Type of structure. * @return * Brain structure with the given structure type or NULL if not found. */ BrainStructure* EventBrainStructureGetAll::getBrainStructureByStructure(const StructureEnum::Enum structure) { for (std::vector::iterator iter = m_brainStructures.begin(); iter != m_brainStructures.end(); iter++) { BrainStructure* bs = *iter; if (bs->getStructure() == structure) { return bs; } } return NULL; } connectome-workbench-1.4.2/src/Brain/EventBrainStructureGetAll.h000066400000000000000000000040241360521144700246750ustar00rootroot00000000000000#ifndef __EVENT_BRAIN_STRUCTURE_GET_ALL_H__ #define __EVENT_BRAIN_STRUCTURE_GET_ALL_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" #include "StructureEnum.h" namespace caret { class BrainStructure; class EventBrainStructureGetAll : public Event { public: EventBrainStructureGetAll(); virtual ~EventBrainStructureGetAll(); void addBrainStructure(BrainStructure* brainStructure); int32_t getNumberOfBrainStructures() const; BrainStructure* getBrainStructureByIndex(const int32_t indx); BrainStructure* getBrainStructureByStructure(const StructureEnum::Enum structure); private: EventBrainStructureGetAll(const EventBrainStructureGetAll&); EventBrainStructureGetAll& operator=(const EventBrainStructureGetAll&); public: // ADD_NEW_METHODS_HERE private: std::vector m_brainStructures; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_BRAIN_STRUCTURE_GET_ALL_DECLARE__ // #endif // __EVENT_BRAIN_STRUCTURE_GET_ALL_DECLARE__ } // namespace #endif //__EVENT_BRAIN_STRUCTURE_GET_ALL_H__ connectome-workbench-1.4.2/src/Brain/EventBrowserTabGet.cxx000066400000000000000000000032721360521144700237210ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventBrowserTabGet.h" using namespace caret; /** * Constructor. */ EventBrowserTabGet::EventBrowserTabGet(const int32_t tabNumber) : Event(EventTypeEnum::EVENT_BROWSER_TAB_GET) { this->tabNumber = tabNumber; this->browserTab = NULL; } /** * Destructor. */ EventBrowserTabGet::~EventBrowserTabGet() { } /** * Get the browser tab that is to be deleted. * * @return * Pointer to browser tab that is to be deleted. */ BrowserTabContent* EventBrowserTabGet::getBrowserTab() { return this->browserTab; } /** * Set the browser tab for the requested tab number. * @param browserTab The tab. */ void EventBrowserTabGet::setBrowserTab(BrowserTabContent* browserTab) { this->browserTab = browserTab; } /** * @return Returns the requested tab number. */ int32_t EventBrowserTabGet::getTabNumber() const { return this->tabNumber; } connectome-workbench-1.4.2/src/Brain/EventBrowserTabGet.h000066400000000000000000000032211360521144700233400ustar00rootroot00000000000000#ifndef __EVENT_BROWSER_TAB_GET_H__ #define __EVENT_BROWSER_TAB_GET_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class BrowserTabContent; /// Get a browser tab by its tab number class EventBrowserTabGet : public Event { public: EventBrowserTabGet(const int32_t tabNumber); virtual ~EventBrowserTabGet(); BrowserTabContent* getBrowserTab(); void setBrowserTab(BrowserTabContent* browserTab); int32_t getTabNumber() const; private: EventBrowserTabGet(const EventBrowserTabGet&); EventBrowserTabGet& operator=(const EventBrowserTabGet&); BrowserTabContent* browserTab; int32_t tabNumber; }; } // namespace #endif // __EVENT_BROWSER_TAB_GET_H__ connectome-workbench-1.4.2/src/Brain/EventBrowserTabGetAll.cxx000066400000000000000000000046101360521144700243470ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrowserTabContent.h" #include "CaretAssert.h" #include "EventBrowserTabGetAll.h" using namespace caret; /** * Constructor. */ EventBrowserTabGetAll::EventBrowserTabGetAll() : Event(EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL) { } /** * Destructor. */ EventBrowserTabGetAll::~EventBrowserTabGetAll() { } /** * @return The number of browser tabs. */ int32_t EventBrowserTabGetAll::getNumberOfBrowserTabs() const { return this->allBrowserTabs.size(); } /** * Get the browser tab at the given index. * @param indx * Index of the browser tab. * @return Browser tab at the given index. */ BrowserTabContent* EventBrowserTabGetAll::getBrowserTab(const int32_t indx) { CaretAssertVectorIndex(this->allBrowserTabs, indx); return this->allBrowserTabs[indx]; } /** * Add a browser tab. * @param browserTab * Tab that is added. */ void EventBrowserTabGetAll::addBrowserTab(BrowserTabContent* browserTab) { this->allBrowserTabs.push_back(browserTab); } /** * @return All browser tabs. */ std::vector EventBrowserTabGetAll::getAllBrowserTabs() const { return this->allBrowserTabs; } /** * @return The indices of all browser tabs. */ std::vector EventBrowserTabGetAll::getBrowserTabIndices() const { std::vector tabIndices; for (std::vector::const_iterator iter = allBrowserTabs.begin(); iter != allBrowserTabs.end(); iter++) { const BrowserTabContent* btc = *iter; tabIndices.push_back(btc->getTabNumber()); } return tabIndices; } connectome-workbench-1.4.2/src/Brain/EventBrowserTabGetAll.h000066400000000000000000000034351360521144700240000ustar00rootroot00000000000000#ifndef __EVENT_BROWSER_TAB_GET_ALL_H__ #define __EVENT_BROWSER_TAB_GET_ALL_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class BrowserTabContent; /// Get all browser tabs class EventBrowserTabGetAll : public Event { public: EventBrowserTabGetAll(); virtual ~EventBrowserTabGetAll(); int32_t getNumberOfBrowserTabs() const; BrowserTabContent* getBrowserTab(const int32_t indx); std::vector getAllBrowserTabs() const; void addBrowserTab(BrowserTabContent* browserTab); std::vector getBrowserTabIndices() const; private: EventBrowserTabGetAll(const EventBrowserTabGetAll&); EventBrowserTabGetAll& operator=(const EventBrowserTabGetAll&); std::vector allBrowserTabs; }; } // namespace #endif // __EVENT_BROWSER_TAB_GET_ALL_H__ connectome-workbench-1.4.2/src/Brain/EventBrowserTabGetAllViewed.cxx000066400000000000000000000064421360521144700255200ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_BROWSER_TAB_GET_ALL_VIEWED_DECLARE__ #include "EventBrowserTabGetAllViewed.h" #undef __EVENT_BROWSER_TAB_GET_ALL_VIEWED_DECLARE__ #include "BrowserTabContent.h" #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventBrowserTabGetAllViewed * \brief Event that gets all viewed browser tabs * \ingroup GuiQt * * For each window, it will add its selected browser tab. If * the window is in 'Tile Tabs' mode, all of its browser tabs * are added. */ /** * Constructor. */ EventBrowserTabGetAllViewed::EventBrowserTabGetAllViewed() : Event(EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL_VIEWED) { } /** * Destructor. */ EventBrowserTabGetAllViewed::~EventBrowserTabGetAllViewed() { } /** * Add a viewed browser tab. * * @param browserTabContent * Browser tab that is added. */ void EventBrowserTabGetAllViewed::addViewedBrowserTab(BrowserTabContent* browserTabContent) { m_viewedBrowserTabs.push_back(browserTabContent); } /** * @return A vector containing the viewed browser tabs */ std::vector EventBrowserTabGetAllViewed::getViewedBrowserTabs() const { return m_viewedBrowserTabs; } /** * @return A vector containing the indices of the viewed browser tabs. */ std::vector EventBrowserTabGetAllViewed::getViewdedBrowserTabIndices() const { std::vector tabIndices; for (std::vector::const_iterator iter = m_viewedBrowserTabs.begin(); iter != m_viewedBrowserTabs.end(); iter++) { const BrowserTabContent* btc = *iter; tabIndices.push_back(btc->getTabNumber()); } return tabIndices; } /** * @return A vector containing surface structures in the viewed browser tabs. */ std::vector EventBrowserTabGetAllViewed::getViewedSurfaceStructures() const { std::set structureSet; for (std::vector::const_iterator iter = m_viewedBrowserTabs.begin(); iter != m_viewedBrowserTabs.end(); iter++) { BrowserTabContent* btc = *iter; std::vector tabStructures = btc->getSurfaceStructuresDisplayed(); structureSet.insert(tabStructures.begin(), tabStructures.end()); } std::vector structuresOut(structureSet.begin(), structureSet.end()); return structuresOut; } connectome-workbench-1.4.2/src/Brain/EventBrowserTabGetAllViewed.h000066400000000000000000000040671360521144700251460ustar00rootroot00000000000000#ifndef __EVENT_BROWSER_TAB_GET_ALL_VIEWED_H__ #define __EVENT_BROWSER_TAB_GET_ALL_VIEWED_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" #include "StructureEnum.h" namespace caret { class BrowserTabContent; class EventBrowserTabGetAllViewed : public Event { public: EventBrowserTabGetAllViewed(); virtual ~EventBrowserTabGetAllViewed(); void addViewedBrowserTab(BrowserTabContent* browserTabContent); std::vector getViewedBrowserTabs() const; std::vector getViewdedBrowserTabIndices() const; std::vector getViewedSurfaceStructures() const; private: EventBrowserTabGetAllViewed(const EventBrowserTabGetAllViewed&); EventBrowserTabGetAllViewed& operator=(const EventBrowserTabGetAllViewed&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE std::vector m_viewedBrowserTabs; }; #ifdef __EVENT_BROWSER_TAB_GET_ALL_VIEWED_DECLARE__ // #endif // __EVENT_BROWSER_TAB_GET_ALL_VIEWED_DECLARE__ } // namespace #endif //__EVENT_BROWSER_TAB_GET_ALL_VIEWED_H__ connectome-workbench-1.4.2/src/Brain/EventBrowserWindowContent.cxx000066400000000000000000000076161360521144700253630ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_BROWSER_WINDOW_CONTENT_DECLARE__ #include "EventBrowserWindowContent.h" #undef __EVENT_BROWSER_WINDOW_CONTENT_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventBrowserWindowContent * \brief Evnets involving browser window content * \ingroup Brain */ /** * Constructor. * * @param mode * The mode. * @param browserWindowIndex * Index of the browser window. */ EventBrowserWindowContent::EventBrowserWindowContent(const Mode mode, const int32_t browserWindowIndex) : Event(EventTypeEnum::EVENT_BROWSER_WINDOW_CONTENT), m_mode(mode), m_browserWindowIndex(browserWindowIndex) { } /** * Destructor. */ EventBrowserWindowContent::~EventBrowserWindowContent() { } /** * @return Event that is sent to create new BrowserWindowContent * for the given window index. * * @param windowIndex * Index of the new window. */ std::unique_ptr EventBrowserWindowContent::newWindowContent(const int32_t windowIndex) { EventBrowserWindowContent* event = new EventBrowserWindowContent(Mode::NEW, windowIndex); std::unique_ptr pointer(event); return pointer; } /** * @return Event that is sent to create delete BrowserWindowContent * for the given window index. * * @param windowIndex * Index of the deleted window. */ std::unique_ptr EventBrowserWindowContent::deleteWindowContent(const int32_t windowIndex) { EventBrowserWindowContent* event = new EventBrowserWindowContent(Mode::DELETER, windowIndex); std::unique_ptr pointer(event); return pointer; } /** * @return Event that is sent to create get BrowserWindowContent * for the given window index. * * @param windowIndex * Index of the window. */ std::unique_ptr EventBrowserWindowContent::getWindowContent(const int32_t windowIndex) { EventBrowserWindowContent* event = new EventBrowserWindowContent(Mode::GET, windowIndex); std::unique_ptr pointer(event); return pointer; } /** * @return The mode. */ EventBrowserWindowContent::Mode EventBrowserWindowContent::getMode() const { return m_mode; } /** * @return Pointer to the browser window content. */ BrowserWindowContent* EventBrowserWindowContent::getBrowserWindowContent() { return m_browserWindowContent; } /** * Set the browser window content. * * @param browserWindowContent * Pointer to the browser window content. */ void EventBrowserWindowContent::setBrowserWindowContent(BrowserWindowContent* browserWindowContent) { m_browserWindowContent = browserWindowContent; } /** * @return Index of the browser window. */ int32_t EventBrowserWindowContent::getBrowserWindowIndex() const { return m_browserWindowIndex; } connectome-workbench-1.4.2/src/Brain/EventBrowserWindowContent.h000066400000000000000000000051131360521144700247760ustar00rootroot00000000000000#ifndef __EVENT_BROWSER_WINDOW_CONTENT_H__ #define __EVENT_BROWSER_WINDOW_CONTENT_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class BrowserWindowContent; class EventBrowserWindowContent : public Event { public: enum class Mode { DELETER, /* DELETE is reserved word in MS Visual Studio C++ */ GET, NEW }; static std::unique_ptr newWindowContent(const int32_t windowIndex); static std::unique_ptr deleteWindowContent(const int32_t windowIndex); static std::unique_ptr getWindowContent(const int32_t windowIndex); virtual ~EventBrowserWindowContent(); Mode getMode() const; BrowserWindowContent* getBrowserWindowContent(); void setBrowserWindowContent(BrowserWindowContent* browserWindowContent); int32_t getBrowserWindowIndex() const; // ADD_NEW_METHODS_HERE private: EventBrowserWindowContent(const Mode mode, const int32_t browserWindowIndex); EventBrowserWindowContent(const EventBrowserWindowContent&); EventBrowserWindowContent& operator=(const EventBrowserWindowContent&); const Mode m_mode; const int32_t m_browserWindowIndex = -1; BrowserWindowContent* m_browserWindowContent = NULL; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_BROWSER_WINDOW_CONTENT_DECLARE__ // #endif // __EVENT_BROWSER_WINDOW_CONTENT_DECLARE__ } // namespace #endif //__EVENT_BROWSER_WINDOW_CONTENT_H__ connectome-workbench-1.4.2/src/Brain/EventCaretMappableDataFilesAndMapsInDisplayedOverlays.cxx000066400000000000000000000130631360521144700326020ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS_DECLARE__ #include "EventCaretMappableDataFilesAndMapsInDisplayedOverlays.h" #undef __EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS_DECLARE__ #include "CaretAssert.h" #include "CaretMappableDataFile.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventCaretMappableDataFilesAndMapsInDisplayedOverlays * \brief Get caret mappable files and their map indices in displayed overlays * \ingroup Brain */ /** * Constructor. */ EventCaretMappableDataFilesAndMapsInDisplayedOverlays::EventCaretMappableDataFilesAndMapsInDisplayedOverlays() : Event(EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS) { } /** * Destructor. */ EventCaretMappableDataFilesAndMapsInDisplayedOverlays::~EventCaretMappableDataFilesAndMapsInDisplayedOverlays() { } /** * Add file and map displayed in an chart overlay. * * @param mapFile * File to add. * @param mapIndex * Index of selected map. */ void EventCaretMappableDataFilesAndMapsInDisplayedOverlays::addChartFileAndMap(CaretMappableDataFile* mapFile, const int32_t mapIndex) { { auto iter = m_mapFilesAndIndices.find(mapFile); if (iter != m_mapFilesAndIndices.end()) { iter->second.insert(mapIndex); } else { std::set indicesSet; indicesSet.insert(mapIndex); m_mapFilesAndIndices.insert(std::make_pair(mapFile, indicesSet)); } } auto iter = m_chartMapFilesAndIndices.find(mapFile); if (iter != m_chartMapFilesAndIndices.end()) { iter->second.insert(mapIndex); } else { std::set indicesSet; indicesSet.insert(mapIndex); m_chartMapFilesAndIndices.insert(std::make_pair(mapFile, indicesSet)); } } /** * Add file and map displayed in an brainordinate (surface/volume) overlay. * * @param mapFile * File to add. * @param mapIndex * Index of selected map. */ void EventCaretMappableDataFilesAndMapsInDisplayedOverlays::addBrainordinateFileAndMap(CaretMappableDataFile* mapFile, const int32_t mapIndex) { { auto iter = m_mapFilesAndIndices.find(mapFile); if (iter != m_mapFilesAndIndices.end()) { iter->second.insert(mapIndex); } else { std::set indicesSet; indicesSet.insert(mapIndex); m_mapFilesAndIndices.insert(std::make_pair(mapFile, indicesSet)); } } auto iter = m_surfaceVolumeMapFilesAndIndices.find(mapFile); if (iter != m_surfaceVolumeMapFilesAndIndices.end()) { iter->second.insert(mapIndex); } else { std::set indicesSet; indicesSet.insert(mapIndex); m_surfaceVolumeMapFilesAndIndices.insert(std::make_pair(mapFile, indicesSet)); } } /** * @return Files and maps selected in overlays for both brainordinates * (surfaces and volumes) and charts. */ std::vector EventCaretMappableDataFilesAndMapsInDisplayedOverlays::getFilesAndMaps() const { std::vector infoOut; for (auto iter : m_surfaceVolumeMapFilesAndIndices) { infoOut.push_back(FileInfo(OverlayType::BRAINORDINATE, iter.first, iter.second)); } for (auto iter : m_chartMapFilesAndIndices) { infoOut.push_back(FileInfo(OverlayType::CHART, iter.first, iter.second)); } return infoOut; } /** * @return Map containing with each pair a map file and map indices selected for the file. */ std::map> EventCaretMappableDataFilesAndMapsInDisplayedOverlays::getMapFilesAndIndices() const { return m_mapFilesAndIndices; } /** * Constructor. * * @param overlayType * Type of overlay * @param mapFile * Map file in the overlay(s) * @param mapIndices * Indices of maps selected in overlays */ EventCaretMappableDataFilesAndMapsInDisplayedOverlays::FileInfo::FileInfo(OverlayType overlayType, CaretMappableDataFile* mapFile, const std::set& mapIndices) : m_overlayType(overlayType), m_mapFile(mapFile), m_mapIndices(mapIndices) { } connectome-workbench-1.4.2/src/Brain/EventCaretMappableDataFilesAndMapsInDisplayedOverlays.h000066400000000000000000000063251360521144700322320ustar00rootroot00000000000000#ifndef __EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS_H__ #define __EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "Event.h" namespace caret { class CaretMappableDataFile; class EventCaretMappableDataFilesAndMapsInDisplayedOverlays : public Event { public: enum class OverlayType { BRAINORDINATE, CHART }; class FileInfo { public: FileInfo(OverlayType overlayType, CaretMappableDataFile* mapFile, const std::set& mapIndices); const OverlayType m_overlayType; CaretMappableDataFile* m_mapFile; const std::set m_mapIndices; }; EventCaretMappableDataFilesAndMapsInDisplayedOverlays(); virtual ~EventCaretMappableDataFilesAndMapsInDisplayedOverlays(); EventCaretMappableDataFilesAndMapsInDisplayedOverlays(const EventCaretMappableDataFilesAndMapsInDisplayedOverlays&) = delete; EventCaretMappableDataFilesAndMapsInDisplayedOverlays& operator=(const EventCaretMappableDataFilesAndMapsInDisplayedOverlays&) = delete; void addBrainordinateFileAndMap(CaretMappableDataFile* mapFile, const int32_t mapIndex); void addChartFileAndMap(CaretMappableDataFile* mapFile, const int32_t mapIndex); std::map> getMapFilesAndIndices() const; std::vector getFilesAndMaps() const; // ADD_NEW_METHODS_HERE private: std::map> m_mapFilesAndIndices; std::map> m_surfaceVolumeMapFilesAndIndices; std::map> m_chartMapFilesAndIndices; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS_DECLARE__ // #endif // __EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS_DECLARE__ } // namespace #endif //__EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS_H__ connectome-workbench-1.4.2/src/Brain/EventChartOverlayValidate.cxx000066400000000000000000000037551360521144700252720ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_CHART_OVERLAY_VALIDATE_DECLARE__ #include "EventChartOverlayValidate.h" #undef __EVENT_CHART_OVERLAY_VALIDATE_DECLARE__ #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventChartOverlayValidate * \brief Test a chart overlay for validity (it exists). * \ingroup Brain */ /** * Constructor. * * @param chartOverlay * Chart overlay for verification. */ EventChartOverlayValidate::EventChartOverlayValidate(const ChartTwoOverlay* chartOverlay) : Event(EventTypeEnum::EVENT_CHART_OVERLAY_VALIDATE), m_chartOverlay(chartOverlay) { m_valid = false; } /** * Destructor. */ EventChartOverlayValidate::~EventChartOverlayValidate() { } /** * @return true if the chart overlay was found to be valid. */ bool EventChartOverlayValidate::isValidChartOverlay() const { return m_valid; } /** * Set the validity if the given overlay is the overlay * that was passed to the constructor. * * @param chartOverlay * Chart overlay tested for match. */ void EventChartOverlayValidate::testValidChartOverlay(const ChartTwoOverlay* chartOverlay) { if (m_chartOverlay == chartOverlay) { m_valid = true; } } connectome-workbench-1.4.2/src/Brain/EventChartOverlayValidate.h000066400000000000000000000035731360521144700247150ustar00rootroot00000000000000#ifndef __EVENT_CHART_OVERLAY_VALIDATE_H__ #define __EVENT_CHART_OVERLAY_VALIDATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class ChartTwoOverlay; class EventChartOverlayValidate : public Event { public: EventChartOverlayValidate(const ChartTwoOverlay* chartOverlay); virtual ~EventChartOverlayValidate(); bool isValidChartOverlay() const; void testValidChartOverlay(const ChartTwoOverlay* chartOverlay); private: EventChartOverlayValidate(const EventChartOverlayValidate&); EventChartOverlayValidate& operator=(const EventChartOverlayValidate&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE const ChartTwoOverlay* m_chartOverlay; bool m_valid; }; #ifdef __EVENT_CHART_OVERLAY_VALIDATE_DECLARE__ // #endif // __EVENT_CHART_OVERLAY_VALIDATE_DECLARE__ } // namespace #endif //__EVENT_CHART_OVERLAY_VALIDATE_H__ connectome-workbench-1.4.2/src/Brain/EventDataFileAdd.cxx000066400000000000000000000030221360521144700232620ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_DATA_FILE_ADD_DECLARE__ #include "EventDataFileAdd.h" #undef __EVENT_DATA_FILE_ADD_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventDataFileAdd * \brief Add a data file to the Brain. * \ingroup Brain */ /** * Constructor. */ EventDataFileAdd::EventDataFileAdd(CaretDataFile* caretDataFile) : Event(EventTypeEnum::EVENT_DATA_FILE_ADD) { CaretAssert(caretDataFile); m_caretDataFile = caretDataFile; } /** * Destructor. */ EventDataFileAdd::~EventDataFileAdd() { } /** * @return Caret data file that is added to the brain. */ CaretDataFile* EventDataFileAdd::getCaretDataFile() { return m_caretDataFile; } connectome-workbench-1.4.2/src/Brain/EventDataFileAdd.h000066400000000000000000000031651360521144700227170ustar00rootroot00000000000000#ifndef __EVENT_DATA_FILE_ADD_H__ #define __EVENT_DATA_FILE_ADD_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class CaretDataFile; class EventDataFileAdd : public Event { public: EventDataFileAdd(CaretDataFile* caretDataFile); virtual ~EventDataFileAdd(); CaretDataFile* getCaretDataFile(); // ADD_NEW_METHODS_HERE private: EventDataFileAdd(const EventDataFileAdd&); EventDataFileAdd& operator=(const EventDataFileAdd&); CaretDataFile* m_caretDataFile; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_DATA_FILE_ADD_DECLARE__ // #endif // __EVENT_DATA_FILE_ADD_DECLARE__ } // namespace #endif //__EVENT_DATA_FILE_ADD_H__ connectome-workbench-1.4.2/src/Brain/EventDataFileDelete.cxx000066400000000000000000000031701360521144700240000ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_DATA_FILE_DELETE_DECLARE__ #include "EventDataFileDelete.h" #undef __EVENT_DATA_FILE_DELETE_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventDataFileDelete * \brief Event for deleting a data file from the brain. * \ingroup Brain */ /** * Constructor. * * @param caretDataFile * File that is deleted. */ EventDataFileDelete::EventDataFileDelete(CaretDataFile* caretDataFile) : Event(EventTypeEnum::EVENT_DATA_FILE_DELETE) { CaretAssert(caretDataFile); m_caretDataFile = caretDataFile; } /** * Destructor. */ EventDataFileDelete::~EventDataFileDelete() { } /** * @return Caret data file that is added to the brain. */ CaretDataFile* EventDataFileDelete::getCaretDataFile() { return m_caretDataFile; } connectome-workbench-1.4.2/src/Brain/EventDataFileDelete.h000066400000000000000000000032251360521144700234260ustar00rootroot00000000000000#ifndef __EVENT_DATA_FILE_DELETE_H__ #define __EVENT_DATA_FILE_DELETE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class CaretDataFile; class EventDataFileDelete : public Event { public: EventDataFileDelete(CaretDataFile* dataFile); virtual ~EventDataFileDelete(); CaretDataFile* getCaretDataFile(); // ADD_NEW_METHODS_HERE private: EventDataFileDelete(const EventDataFileDelete&); EventDataFileDelete& operator=(const EventDataFileDelete&); CaretDataFile* m_caretDataFile; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_DATA_FILE_DELETE_DECLARE__ // #endif // __EVENT_DATA_FILE_DELETE_DECLARE__ } // namespace #endif //__EVENT_DATA_FILE_DELETE_H__ connectome-workbench-1.4.2/src/Brain/EventDataFileRead.cxx000066400000000000000000000166001360521144700234530ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "EventDataFileRead.h" using namespace caret; /** * Constructor. * * @param loadIntoBrain * Brain into which file is loaded. */ EventDataFileRead::EventDataFileRead(Brain* loadIntoBrain) : Event(EventTypeEnum::EVENT_DATA_FILE_READ) { this->loadIntoBrain = loadIntoBrain; this->username = ""; this->password = ""; CaretAssert(this->loadIntoBrain); } /** * Destructor. */ EventDataFileRead::~EventDataFileRead() { } /** * Add a data file for reading. * * @param dataFileType * Type of data file. * @param dataFileName * Name of the data file. */ void EventDataFileRead::addDataFile(const DataFileTypeEnum::Enum dataFileType, const AString& dataFileName) { CaretAssert(dataFileType != DataFileTypeEnum::UNKNOWN); CaretAssert(dataFileName.isEmpty() == false); m_dataFiles.push_back(FileData(StructureEnum::INVALID, dataFileType, dataFileName, false)); } /** * Add a data file for reading. * * @param structure * Structure for file if not present in file. * @param dataFileType * Type of data file. * @param dataFileName * Name of the data file. */ void EventDataFileRead::addDataFile(const StructureEnum::Enum structure, const DataFileTypeEnum::Enum dataFileType, const AString& dataFileName) { //CaretAssert(structure != StructureEnum::INVALID); CaretAssert(dataFileType != DataFileTypeEnum::UNKNOWN); CaretAssert(dataFileName.isEmpty() == false); m_dataFiles.push_back(FileData(structure, dataFileType, dataFileName, false)); } /** * @return Number of data files to read. */ int32_t EventDataFileRead::getNumberOfDataFilesToRead() const { return m_dataFiles.size(); } /** * Get the name of the data file that is to be loaded. * * @param dataFileIndex * Index of the data file. * @return Name of data file to load. */ AString EventDataFileRead::getDataFileName(const int32_t dataFileIndex) const { CaretAssertVectorIndex(m_dataFiles, dataFileIndex); return m_dataFiles[dataFileIndex].m_dataFileName; } /** * Get the type of data file for loading. * * @param dataFileIndex * Index of the data file. * @return Type of file for loading. */ DataFileTypeEnum::Enum EventDataFileRead::getDataFileType(const int32_t dataFileIndex) const { CaretAssertVectorIndex(m_dataFiles, dataFileIndex); return m_dataFiles[dataFileIndex].m_dataFileType; } /** * Get brain into which file is loaded. * @return Brain into which file is loaded. */ Brain* EventDataFileRead::getLoadIntoBrain() { return this->loadIntoBrain; } /** * @param dataFileIndex * Index of the data file. * @return The structure associated with the data file. */ StructureEnum::Enum EventDataFileRead::getStructure(const int32_t dataFileIndex) const { CaretAssertVectorIndex(m_dataFiles, dataFileIndex); return m_dataFiles[dataFileIndex].m_structure; } /** * Get the error message for a file. * @param dataFileIndex * Index of the file. * @return * Error message. */ AString EventDataFileRead::getFileErrorMessage(const int32_t dataFileIndex) const { CaretAssertVectorIndex(m_dataFiles, dataFileIndex); return m_dataFiles[dataFileIndex].m_errorMessage; } /** * Set the error message for a file. * @param dataFileIndex * Index of the file. * @param errorMessage * Error message. */ void EventDataFileRead::setFileErrorMessage(const int32_t dataFileIndex, const AString& errorMessage) { CaretAssertVectorIndex(m_dataFiles, dataFileIndex); m_dataFiles[dataFileIndex].m_errorMessage = errorMessage; } /** * Was there an error reading the file at the given index. * @param dataFileIndex * Index of the file. * @return * true if there was an error, otherwise false. */ bool EventDataFileRead::isFileError(const int32_t dataFileIndex) const { CaretAssertVectorIndex(m_dataFiles, dataFileIndex); return (m_dataFiles[dataFileIndex].m_errorMessage.isEmpty() == false); } /** * @param dataFileIndex * Index of the data file. * @return True if the file could not be read due * to an invalid structure. */ bool EventDataFileRead::isFileErrorInvalidStructure(const int32_t dataFileIndex) const { CaretAssertVectorIndex(m_dataFiles, dataFileIndex); return m_dataFiles[dataFileIndex].m_invalidStructureError; } /** * Set the invalid structure status. * @param dataFileIndex * Index of the data file. * @param status * New invalid structure status (true if invalid). */ void EventDataFileRead::setFileErrorInvalidStructure(const int32_t dataFileIndex, const bool status) { CaretAssertVectorIndex(m_dataFiles, dataFileIndex); m_dataFiles[dataFileIndex].m_invalidStructureError = status; } /** * @return File that was read for the given index. */ CaretDataFile* EventDataFileRead::getDataFileRead(const int32_t dataFileIndex) { CaretAssertVectorIndex(m_dataFiles, dataFileIndex); return m_dataFiles[dataFileIndex].m_caretDataFileThatWasRead; } /** * Set the file that was read. * * @param dataFileIndex * Index of the file. * @param caretDataFile * Pointer to file that was read for given index. */ void EventDataFileRead::setDataFileRead(const int32_t dataFileIndex, CaretDataFile* caretDataFile) { CaretAssertVectorIndex(m_dataFiles, dataFileIndex); m_dataFiles[dataFileIndex].m_caretDataFileThatWasRead = caretDataFile; } /** * @return The username. */ AString EventDataFileRead::getUsername() const { return this->username; } /** * @return The password. */ AString EventDataFileRead::getPassword() const { return this->password; } /** * Set the username and password. * * @param username * Name of user account. * @param password * Password of user account. */ void EventDataFileRead::setUsernameAndPassword(const AString& username, const AString& password) { this->username = username; this->password = password; } /** * @param dataFileIndex * Index of the data file. * @return After file is read, mark it as modified. */ bool EventDataFileRead::isFileToBeMarkedModified(const int32_t dataFileIndex) const { CaretAssertVectorIndex(m_dataFiles, dataFileIndex); return m_dataFiles[dataFileIndex].m_markFileAsModified; } connectome-workbench-1.4.2/src/Brain/EventDataFileRead.h000066400000000000000000000102761360521144700231030ustar00rootroot00000000000000#ifndef __EVENT_DATA_FILE_READ_H__ #define __EVENT_DATA_FILE_READ_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "DataFileTypeEnum.h" #include "Event.h" #include "StructureEnum.h" namespace caret { class Brain; class CaretDataFile; /** * Event for reading one or more data files. */ class EventDataFileRead : public Event { public: EventDataFileRead(Brain* loadIntoBrain); virtual ~EventDataFileRead(); void addDataFile(const DataFileTypeEnum::Enum dataFileType, const AString& dataFileName); void addDataFile(const StructureEnum::Enum structure, const DataFileTypeEnum::Enum dataFileType, const AString& dataFileName); int32_t getNumberOfDataFilesToRead() const; AString getDataFileName(const int32_t dataFileIndex) const; DataFileTypeEnum::Enum getDataFileType(const int32_t dataFileIndex) const; Brain* getLoadIntoBrain(); StructureEnum::Enum getStructure(const int32_t dataFileIndex) const; AString getFileErrorMessage(const int32_t dataFileIndex) const; void setFileErrorMessage(const int32_t dataFileIndex, const AString& errorMessage); bool isFileError(const int32_t dataFileIndex) const; bool isFileErrorInvalidStructure(const int32_t dataFileIndex) const; void setFileErrorInvalidStructure(const int32_t dataFileIndex, const bool status); AString getUsername() const; AString getPassword() const; void setUsernameAndPassword(const AString& username, const AString& password); bool isFileToBeMarkedModified(const int32_t dataFileIndex) const; CaretDataFile* getDataFileRead(const int32_t dataFileIndex); void setDataFileRead(const int32_t dataFileIndex, CaretDataFile* caretDataFile); private: class FileData { public: FileData(const StructureEnum::Enum structure, const DataFileTypeEnum::Enum dataFileType, const AString& dataFileName, const bool markFileAsModified) : m_structure(structure), m_dataFileType(dataFileType), m_dataFileName(dataFileName), m_markFileAsModified(markFileAsModified) { m_invalidStructureError = false; m_caretDataFileThatWasRead = NULL; } ~FileData() { } StructureEnum::Enum m_structure; DataFileTypeEnum::Enum m_dataFileType; AString m_dataFileName; AString m_errorMessage; CaretDataFile* m_caretDataFileThatWasRead; bool m_markFileAsModified; bool m_invalidStructureError; }; std::vector m_dataFiles; EventDataFileRead(const EventDataFileRead&); EventDataFileRead& operator=(const EventDataFileRead&); Brain* loadIntoBrain; AString username; AString password; }; } // namespace #endif // __EVENT_DATA_FILE_READ_H__ connectome-workbench-1.4.2/src/Brain/EventDataFileReload.cxx000066400000000000000000000060441360521144700240070ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_DATA_FILE_RELOAD_DECLARE__ #include "EventDataFileReload.h" #undef __EVENT_DATA_FILE_RELOAD_DECLARE__ #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventDataFileReload * \brief Event for reloading a Caret Data File. * \ingroup Brain */ /** * Constructor. * * Note: If reload fails, the caretDataFile WILL BE DELETED and the pointer * must no longer be deferenced. * * @param brain * Brain into which file is reloaded. * @param caretDataFile * Caret data file that is reloaded. */ EventDataFileReload::EventDataFileReload(Brain* brain, CaretDataFile* caretDataFile) : Event(EventTypeEnum::EVENT_DATA_FILE_RELOAD), m_brain(brain), m_caretDataFile(caretDataFile) { } /** * Destructor. */ EventDataFileReload::~EventDataFileReload() { } /** * @return Brain into which file is loaded. */ Brain* EventDataFileReload::getBrain() { return this->m_brain; } /** * @return The Caret Data File that will be reloaded. */ CaretDataFile* EventDataFileReload::getCaretDataFile() { return m_caretDataFile; } /** * @return true if there was an error reloading the file, else false. */ bool EventDataFileReload::isError() const { const bool errorFlag = (m_errorMessage.isEmpty() == false); return errorFlag; } /** * @return The error message. */ AString EventDataFileReload::getErrorMessage() const { return m_errorMessage; } /** * Set there error message describing reloading error. * * @param errorMessage * Message describing the error. */ void EventDataFileReload::setErrorMessage(const AString& errorMessage) { m_errorMessage = errorMessage; } /** * @return The username. */ AString EventDataFileReload::getUsername() const { return m_username; } /** * @return The password. */ AString EventDataFileReload::getPassword() const { return m_password; } /** * Set the username and password. * * @param username * Name of user account. * @param password * Password of user account. */ void EventDataFileReload::setUsernameAndPassword(const AString& username, const AString& password) { m_username = username; m_password = password; } connectome-workbench-1.4.2/src/Brain/EventDataFileReload.h000066400000000000000000000044431360521144700234350ustar00rootroot00000000000000#ifndef __EVENT_DATA_FILE_RELOAD_H__ #define __EVENT_DATA_FILE_RELOAD_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class Brain; class CaretDataFile; class EventDataFileReload : public Event { public: EventDataFileReload(Brain* brain, CaretDataFile* caretDataFile); virtual ~EventDataFileReload(); Brain* getBrain(); CaretDataFile* getCaretDataFile(); bool isError() const; AString getErrorMessage() const; void setErrorMessage(const AString& errorMessage); AString getUsername() const; AString getPassword() const; void setUsernameAndPassword(const AString& username, const AString& password); private: EventDataFileReload(const EventDataFileReload&); EventDataFileReload& operator=(const EventDataFileReload&); public: // ADD_NEW_METHODS_HERE private: Brain* m_brain; CaretDataFile* m_caretDataFile; AString m_username; AString m_password; AString m_errorMessage; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_DATA_FILE_RELOAD_DECLARE__ // #endif // __EVENT_DATA_FILE_RELOAD_DECLARE__ } // namespace #endif //__EVENT_DATA_FILE_RELOAD_H__ connectome-workbench-1.4.2/src/Brain/EventGetBrainOpenGLTextRenderer.cxx000066400000000000000000000036021360521144700263000ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_GET_BRAIN_OPEN_G_L_TEXT_RENDERER_DECLARE__ #include "EventGetBrainOpenGLTextRenderer.h" #undef __EVENT_GET_BRAIN_OPEN_G_L_TEXT_RENDERER_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventGetBrainOpenGLTextRenderer * \brief Event to get a text renderer for a window * \ingroup Brain */ /** * Constructor. */ EventGetBrainOpenGLTextRenderer::EventGetBrainOpenGLTextRenderer() : Event(EventTypeEnum::EVENT_GET_TEXT_RENDERER_FOR_WINDOW) { m_textRenderer = NULL; } /** * Destructor. */ EventGetBrainOpenGLTextRenderer::~EventGetBrainOpenGLTextRenderer() { } /** * @return The text renderer found for the window. * (NULL if not found). */ BrainOpenGLTextRenderInterface* EventGetBrainOpenGLTextRenderer::getTextRenderer() const { return m_textRenderer; } /** * Set the text renderer. * * @param textRenderer * The text renderer. */ void EventGetBrainOpenGLTextRenderer::setTextRenderer(BrainOpenGLTextRenderInterface* textRenderer) { m_textRenderer = textRenderer; } connectome-workbench-1.4.2/src/Brain/EventGetBrainOpenGLTextRenderer.h000066400000000000000000000036411360521144700257300ustar00rootroot00000000000000#ifndef __EVENT_GET_BRAIN_OPEN_G_L_TEXT_RENDERER_H__ #define __EVENT_GET_BRAIN_OPEN_G_L_TEXT_RENDERER_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class BrainOpenGLTextRenderInterface; class EventGetBrainOpenGLTextRenderer : public Event { public: EventGetBrainOpenGLTextRenderer(); virtual ~EventGetBrainOpenGLTextRenderer(); BrainOpenGLTextRenderInterface* getTextRenderer() const; void setTextRenderer(BrainOpenGLTextRenderInterface* textRenderer); // ADD_NEW_METHODS_HERE private: EventGetBrainOpenGLTextRenderer(const EventGetBrainOpenGLTextRenderer&); EventGetBrainOpenGLTextRenderer& operator=(const EventGetBrainOpenGLTextRenderer&); BrainOpenGLTextRenderInterface* m_textRenderer; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_GET_BRAIN_OPEN_G_L_TEXT_RENDERER_DECLARE__ // #endif // __EVENT_GET_BRAIN_OPEN_G_L_TEXT_RENDERER_DECLARE__ } // namespace #endif //__EVENT_GET_BRAIN_OPEN_G_L_TEXT_RENDERER_H__ connectome-workbench-1.4.2/src/Brain/EventIdentificationHighlightLocation.cxx000066400000000000000000000060131360521144700274550ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "CaretAssert.h" #include "EventIdentificationHighlightLocation.h" using namespace caret; /** * Constructor for identification event of location. * * @parma tabIndex * Index of tab in which identification took place. This value may * be negative indicating that the identification request is not * for a specific browser tab. One source for this is the Select Brainordinate * option on the Information Window. * @param xyz * Stereotaxic location of selected item. */ EventIdentificationHighlightLocation::EventIdentificationHighlightLocation(const int32_t tabIndex, const float xyz[3], const LOAD_FIBER_ORIENTATION_SAMPLES_MODE loadFiberOrientationSamplesMode) : Event(EventTypeEnum::EVENT_IDENTIFICATION_HIGHLIGHT_LOCATION), m_tabIndex(tabIndex), m_loadFiberOrientationSamplesMode(loadFiberOrientationSamplesMode) { /* * NOTE: a negative value is allowed. */ CaretAssert(tabIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); m_xyz[0] = xyz[0]; m_xyz[1] = xyz[1]; m_xyz[2] = xyz[2]; } /** * Destructor. */ EventIdentificationHighlightLocation::~EventIdentificationHighlightLocation() { } /** * @return The stereotaxic location of the identification (valid for all). */ const float* EventIdentificationHighlightLocation::getXYZ() const { return m_xyz; } /** * Is the tab with the given index selected for identification operations? * * @param tabIndex * Index of tab. * @return True if tab is selected, else false. */ bool EventIdentificationHighlightLocation::isTabSelected(const int32_t tabIndex) const { /* * All tabs? */ if (m_tabIndex < 0) { return true; } else if (m_tabIndex == tabIndex) { return true; } return false; } /** * @return The mode for loading of fiber orientation samples. */ EventIdentificationHighlightLocation::LOAD_FIBER_ORIENTATION_SAMPLES_MODE EventIdentificationHighlightLocation::getLoadFiberOrientationSamplesMode() const { return m_loadFiberOrientationSamplesMode; } connectome-workbench-1.4.2/src/Brain/EventIdentificationHighlightLocation.h000066400000000000000000000044301360521144700271030ustar00rootroot00000000000000#ifndef __EVENT_IDENTIFICATION_HIGHLIGHT_LOCATION_H__ #define __EVENT_IDENTIFICATION_HIGHLIGHT_LOCATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" #include "StructureEnum.h" namespace caret { /// Highlight location of an indentification class EventIdentificationHighlightLocation : public Event { public: enum LOAD_FIBER_ORIENTATION_SAMPLES_MODE { LOAD_FIBER_ORIENTATION_SAMPLES_MODE_YES, LOAD_FIBER_ORIENTATION_SAMPLES_MODE_NO }; EventIdentificationHighlightLocation(const int32_t tabIndex, const float xyz[3], const LOAD_FIBER_ORIENTATION_SAMPLES_MODE loadFiberOrientationSamplesMode); virtual ~EventIdentificationHighlightLocation(); const float* getXYZ() const; bool isTabSelected(const int32_t tabIndex) const; LOAD_FIBER_ORIENTATION_SAMPLES_MODE getLoadFiberOrientationSamplesMode() const; private: EventIdentificationHighlightLocation(const EventIdentificationHighlightLocation&); EventIdentificationHighlightLocation& operator=(const EventIdentificationHighlightLocation&); const int32_t m_tabIndex; float m_xyz[3]; const LOAD_FIBER_ORIENTATION_SAMPLES_MODE m_loadFiberOrientationSamplesMode; }; } // namespace #endif // __EVENT_IDENTIFICATION_HIGHLIGHT_LOCATION_H__ connectome-workbench-1.4.2/src/Brain/EventModelAdd.cxx000066400000000000000000000024041360521144700226540ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "EventModelAdd.h" using namespace caret; /** * Constructor. * * @param model * Model to add. */ EventModelAdd::EventModelAdd(Model* model) : Event(EventTypeEnum::EVENT_MODEL_ADD) { m_model = model; CaretAssert(m_model); } /** * Destructor. */ EventModelAdd::~EventModelAdd() { } /** * @return Model that is to be added. */ Model* EventModelAdd::getModel() { return m_model; } connectome-workbench-1.4.2/src/Brain/EventModelAdd.h000066400000000000000000000025471360521144700223110ustar00rootroot00000000000000#ifndef __EVENT_MODEL_ADD_H__ #define __EVENT_MODEL_ADD_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class Model; /// Event for adding models class EventModelAdd : public Event { public: EventModelAdd(Model* model); virtual ~EventModelAdd(); Model* getModel(); private: EventModelAdd(const EventModelAdd&); EventModelAdd& operator=(const EventModelAdd&); Model* m_model; }; } // namespace #endif // __EVENT_MODEL_ADD_H__ connectome-workbench-1.4.2/src/Brain/EventModelDelete.cxx000066400000000000000000000023631360521144700233720ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "EventModelDelete.h" using namespace caret; /** * Constructor. */ EventModelDelete::EventModelDelete(Model* model) : Event(EventTypeEnum::EVENT_MODEL_DELETE) { m_model = model; CaretAssert(m_model); } /** * Destructor. */ EventModelDelete::~EventModelDelete() { } /** * @return Model that is to be deleted. */ Model* EventModelDelete::getModel() { return m_model; } connectome-workbench-1.4.2/src/Brain/EventModelDelete.h000066400000000000000000000026271360521144700230220ustar00rootroot00000000000000#ifndef __EVENT_MODEL_DELETE_H__ #define __EVENT_MODEL_DELETE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class Model; /// Event for deleting models class EventModelDelete : public Event { public: EventModelDelete(Model* model); virtual ~EventModelDelete(); Model* getModel(); private: EventModelDelete(const EventModelDelete&); EventModelDelete& operator=(const EventModelDelete&); Model* m_model; }; } // namespace #endif // __EVENT_MODEL_DELETE_H__ connectome-workbench-1.4.2/src/Brain/EventModelGetAll.cxx000066400000000000000000000052671360521144700233460ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "EventModelGetAll.h" #include "ModelSurface.h" using namespace caret; /** * Constructor. */ EventModelGetAll::EventModelGetAll() : Event(EventTypeEnum::EVENT_MODEL_GET_ALL) { } /** * Destructor. */ EventModelGetAll::~EventModelGetAll() { } /** * Add models. * @param modelsToAdd * These model added. */ void EventModelGetAll::addModels( const std::vector& modelsToAdd) { m_models.insert(m_models.end(), modelsToAdd.begin(), modelsToAdd.end()); } /** * Get the model. * * @return vector containing the model. */ const std::vector EventModelGetAll::getModels() const { return this->m_models; } /** * Is a model valid? * * @param model * Model that is checked for validity. * * @return true if valid, else false. */ bool EventModelGetAll::isModelValid( const Model* model) const { if (std::find(this->m_models.begin(), this->m_models.end(), model) != m_models.end()) { return true; } return false; } /** * Get the first model. * * @return Pointer to first model or * NULL if there are no model. */ Model* EventModelGetAll::getFirstModel() const { if (m_models.empty() == false) { return m_models[0]; } return NULL; } /** * Get the first model surface. * * @return Pointer to first model surface or * NULL if there are no model surfaces. */ ModelSurface* EventModelGetAll::getFirstModelSurface() const { ModelSurface* surfaceModelOut = NULL; const int32_t numModels = static_cast(m_models.size()); for (int32_t i = 0; i < numModels; i++) { surfaceModelOut = dynamic_cast(m_models[i]); if (surfaceModelOut != NULL) { break; } } return surfaceModelOut; } connectome-workbench-1.4.2/src/Brain/EventModelGetAll.h000066400000000000000000000033701360521144700227640ustar00rootroot00000000000000#ifndef __EVENT_GET_MODEL_DISPLAY_CONTROLLERS_H__ #define __EVENT_GET_MODEL_DISPLAY_CONTROLLERS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class Model; class ModelSurface; /// Event for getting models class EventModelGetAll : public Event { public: EventModelGetAll(); virtual ~EventModelGetAll(); void addModels(const std::vector& modelsToAdd); const std::vector getModels() const; bool isModelValid(const Model* model) const; Model* getFirstModel() const; ModelSurface* getFirstModelSurface() const; private: EventModelGetAll(const EventModelGetAll&); EventModelGetAll& operator=(const EventModelGetAll&); std::vector m_models; }; } // namespace #endif // __EVENT_GET_MODEL_DISPLAY_CONTROLLERS_H__ connectome-workbench-1.4.2/src/Brain/EventModelGetAllDisplayed.cxx000066400000000000000000000034521360521144700251770ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_MODEL_GET_ALL_DISPLAYED_DECLARE__ #include "EventModelGetAllDisplayed.h" #undef __EVENT_MODEL_GET_ALL_DISPLAYED_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventModelGetAllDisplayed * \brief Event to get the displayed models. * \ingroup Brain */ /** * Constructor. */ EventModelGetAllDisplayed::EventModelGetAllDisplayed() : Event(EventTypeEnum::EVENT_MODEL_GET_ALL_DISPLAYED) { } /** * Destructor. */ EventModelGetAllDisplayed::~EventModelGetAllDisplayed() { } /** * @return A set containing the displayed models. */ std::set EventModelGetAllDisplayed::getModels() const { return m_models; } /** * Add a model to the displayed models. * This method may be called more than once with the same model. * * @param model * The model. */ void EventModelGetAllDisplayed::addModel(Model* model) { if (model == NULL) { return; } m_models.insert(model); } connectome-workbench-1.4.2/src/Brain/EventModelGetAllDisplayed.h000066400000000000000000000033721360521144700246250ustar00rootroot00000000000000#ifndef __EVENT_MODEL_GET_ALL_DISPLAYED_H__ #define __EVENT_MODEL_GET_ALL_DISPLAYED_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class Model; class EventModelGetAllDisplayed : public Event { public: EventModelGetAllDisplayed(); virtual ~EventModelGetAllDisplayed(); std::set getModels() const; void addModel(Model* model); // ADD_NEW_METHODS_HERE private: EventModelGetAllDisplayed(const EventModelGetAllDisplayed&); EventModelGetAllDisplayed& operator=(const EventModelGetAllDisplayed&); std::set m_models; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_MODEL_GET_ALL_DISPLAYED_DECLARE__ // #endif // __EVENT_MODEL_GET_ALL_DISPLAYED_DECLARE__ } // namespace #endif //__EVENT_MODEL_GET_ALL_DISPLAYED_H__ connectome-workbench-1.4.2/src/Brain/EventModelSurfaceGet.cxx000066400000000000000000000032751360521144700242230ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "EventModelSurfaceGet.h" using namespace caret; /** * Constructor. */ EventModelSurfaceGet::EventModelSurfaceGet(const Surface* surface) : Event(EventTypeEnum::EVENT_MODEL_SURFACE_GET), surface(surface) { CaretAssert(surface); } /** * Destructor. */ EventModelSurfaceGet::~EventModelSurfaceGet() { } /** * @return The model surface that was found. */ ModelSurface* EventModelSurfaceGet::getModelSurface() { return m_modelSurface; } /** * Set the model surface. * @param modelSurface * Model surface that matches the specified surface. */ void EventModelSurfaceGet::setModelSurface(ModelSurface* modelSurface) { m_modelSurface = modelSurface; } /** * @return Returns the surface for which the model surface is requested. */ const Surface* EventModelSurfaceGet::getSurface() const { return this->surface; } connectome-workbench-1.4.2/src/Brain/EventModelSurfaceGet.h000066400000000000000000000033141360521144700236420ustar00rootroot00000000000000#ifndef __EVENT_MODEL_SURFACE_GET_H__ #define __EVENT_MODEL_SURFACE_GET_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class ModelSurface; class Surface; /// Find the Surface model that contains a specific Surface. class EventModelSurfaceGet : public Event { public: EventModelSurfaceGet(const Surface* surface); virtual ~EventModelSurfaceGet(); ModelSurface* getModelSurface(); void setModelSurface(ModelSurface* modelSurface); const Surface* getSurface() const; private: EventModelSurfaceGet(const EventModelSurfaceGet&); EventModelSurfaceGet& operator=(const EventModelSurfaceGet&); ModelSurface* m_modelSurface; const Surface* surface; }; } // namespace #endif // __EVENT_MODEL_SURFACE_GET_H__ connectome-workbench-1.4.2/src/Brain/EventNodeDataFilesGet.cxx000066400000000000000000000057451360521144700243200ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretAssert.h" #include "EventNodeDataFilesGet.h" #include "LabelFile.h" #include "MetricFile.h" #include "RgbaFile.h" using namespace caret; /** * Constructor for node data files that are * associated with ANY surface. */ EventNodeDataFilesGet::EventNodeDataFilesGet() : Event(EventTypeEnum::EVENT_GET_NODE_DATA_FILES), surface(NULL) { } /** * Constructor for node data files that are * associated with a specific surface. */ EventNodeDataFilesGet::EventNodeDataFilesGet(const Surface* surfaceIn) : Event(EventTypeEnum::EVENT_GET_NODE_DATA_FILES), surface(surfaceIn) { } /** * Destructor. */ EventNodeDataFilesGet::~EventNodeDataFilesGet() { } /** * Add a node data file. * @param nodeDataFile * Data file that is added. */ void EventNodeDataFilesGet::addFile(GiftiTypeFile* nodeDataFile) { CaretAssert(nodeDataFile); if (nodeDataFile->getNumberOfColumns() <= 0) { return; } LabelFile* lf = dynamic_cast(nodeDataFile); if (lf != NULL) { this->labelFiles.push_back(lf); return; } MetricFile* mf = dynamic_cast(nodeDataFile); if (mf != NULL) { this->metricFiles.push_back(mf); return; } RgbaFile* rf = dynamic_cast(nodeDataFile); if (rf != NULL) { this->rgbaFiles.push_back(rf); return; } CaretAssertMessage(0, "Unsupported vertex data file: " + AString(typeid(nodeDataFile).name()) + " New vertex data file added?"); } /** * @return Returns all data files. */ void EventNodeDataFilesGet::getAllFiles(std::vector& allFilesOut) const { allFilesOut.clear(); allFilesOut.insert(allFilesOut.end(), this->labelFiles.begin(), this->labelFiles.end()); allFilesOut.insert(allFilesOut.end(), this->metricFiles.begin(), this->metricFiles.end()); allFilesOut.insert(allFilesOut.end(), this->rgbaFiles.begin(), this->rgbaFiles.end()); } connectome-workbench-1.4.2/src/Brain/EventNodeDataFilesGet.h000066400000000000000000000051221360521144700237320ustar00rootroot00000000000000#ifndef __EVENT_NODE_DATA_FILES_GET_H__ #define __EVENT_NODE_DATA_FILES_GET_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class GiftiTypeFile; class LabelFile; class MetricFile; class Model; class RgbaFile; class Surface; /// Event that gets all node data files. class EventNodeDataFilesGet : public Event { public: EventNodeDataFilesGet(); EventNodeDataFilesGet(const Surface* surface); virtual ~EventNodeDataFilesGet(); void addFile(GiftiTypeFile* nodeDataFile); /** * @return Returns the surface for which associated data * files are requested. If NULL, then node data files * from all brain structures are requested. */ const Surface* getSurface() const { return this->surface; } /** @return Returns the label files. */ std::vector getLabelFiles() const { return this->labelFiles; } /** @return Returns the metric files. */ std::vector getMetricFiles() const { return this->metricFiles; } /** @return Returns the rgba files. */ std::vector getRgbaFiles() const { return this->rgbaFiles; } void getAllFiles(std::vector& allFilesOut) const; private: EventNodeDataFilesGet(const EventNodeDataFilesGet&); EventNodeDataFilesGet& operator=(const EventNodeDataFilesGet&); const Surface* surface; std::vector labelFiles; std::vector metricFiles; std::vector rgbaFiles; }; } // namespace #endif // __EVENT_NODE_DATA_FILES_GET_H__ connectome-workbench-1.4.2/src/Brain/EventNodeIdentificationColorsGetFromCharts.cxx000066400000000000000000000102131360521144700305520ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS_DECLARE__ #include "EventNodeIdentificationColorsGetFromCharts.h" #undef __EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventNodeIdentificationColorsGetFromCharts * \brief Get colors for node identification systems displayed in charts * \ingroup Brain */ /** * Constructor. * * @param structure * Structure for matching to nodes in charts. * @param tabIndex * Index of tab * @param nodeIndices * Indices of nodes for which chart colors are requested. */ EventNodeIdentificationColorsGetFromCharts::EventNodeIdentificationColorsGetFromCharts(const StructureEnum::Enum structure, const int32_t tabIndex, const std::vector& nodeIndices) : Event(EventTypeEnum::EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS) { m_structureName = StructureEnum::toName(structure); m_tabIndex = tabIndex; m_nodeIndices = nodeIndices; } /** * Destructor. */ EventNodeIdentificationColorsGetFromCharts::~EventNodeIdentificationColorsGetFromCharts() { } /** * Add a node and its color (this method is called by charts). * * @param nodeIndex * Index of the node. * @param rgb * RGB coloring for the node. */ void EventNodeIdentificationColorsGetFromCharts::addNode(const int32_t nodeIndex, const float rgb[3]) { if (m_nodeRgbColor.find(nodeIndex) != m_nodeRgbColor.end()) { return; } RgbColor rgbColor; rgbColor.rgb[0] = rgb[0] * 255.0; rgbColor.rgb[1] = rgb[1] * 255.0; rgbColor.rgb[2] = rgb[2] * 255.0; m_nodeRgbColor.insert(std::pair(nodeIndex, rgbColor)); } /** * Apply chart color to node. If there is chart coloring for the node * with the given index, it is applied. Otherwise, no action is taken. * This method is called by drawing code. * * @param nodeIndex * Index of the node. * @param rgb * Receives coloring for the node from the chart coloring (if available). */ void EventNodeIdentificationColorsGetFromCharts::applyChartColorToNode(const int32_t nodeIndex, uint8_t rgb[3]) { std::map::const_iterator iter = m_nodeRgbColor.find(nodeIndex); if (iter != m_nodeRgbColor.end()) { RgbColor rgbColor = iter->second; rgb[0] = rgbColor.rgb[0]; rgb[1] = rgbColor.rgb[1]; rgb[2] = rgbColor.rgb[2]; } } /** * @return Name of the surface node's structure. This method is called by charts. */ AString EventNodeIdentificationColorsGetFromCharts::getStructureName() const { return m_structureName; } /** * @return Index of tab where notification symbols are displayed. */ int32_t EventNodeIdentificationColorsGetFromCharts::getTabIndex() const { return m_tabIndex; } /** * @return Indices of nodes for which chart colors are requested. */ std::vector EventNodeIdentificationColorsGetFromCharts::getNodeIndices() const { return m_nodeIndices; } connectome-workbench-1.4.2/src/Brain/EventNodeIdentificationColorsGetFromCharts.h000066400000000000000000000052171360521144700302070ustar00rootroot00000000000000#ifndef __EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS_H__ #define __EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" #include "StructureEnum.h" namespace caret { class EventNodeIdentificationColorsGetFromCharts : public Event { public: EventNodeIdentificationColorsGetFromCharts(const StructureEnum::Enum structure, const int32_t tabIndex, const std::vector& nodeIndices); virtual ~EventNodeIdentificationColorsGetFromCharts(); void addNode(const int32_t nodeIndex, const float rgba[4]); void applyChartColorToNode(const int32_t nodeIndex, uint8_t rgba[4]); AString getStructureName() const; int32_t getTabIndex() const; std::vector getNodeIndices() const; // ADD_NEW_METHODS_HERE private: EventNodeIdentificationColorsGetFromCharts(const EventNodeIdentificationColorsGetFromCharts&); EventNodeIdentificationColorsGetFromCharts& operator=(const EventNodeIdentificationColorsGetFromCharts&); // ADD_NEW_MEMBERS_HERE AString m_structureName; int32_t m_tabIndex; std::vector m_nodeIndices; struct RgbColor { uint8_t rgb[3]; }; std::map m_nodeRgbColor; }; #ifdef __EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS_DECLARE__ // #endif // __EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS_DECLARE__ } // namespace #endif //__EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS_H__ connectome-workbench-1.4.2/src/Brain/EventOverlayValidate.cxx000066400000000000000000000034441360521144700243030ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_OVERLAY_VALIDATE_DECLARE__ #include "EventOverlayValidate.h" #undef __EVENT_OVERLAY_VALIDATE_DECLARE__ #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventOverlayValidate * \brief Test an overlay for validity (it exists). * \ingroup Brain */ /** * Constructor. */ EventOverlayValidate::EventOverlayValidate(const Overlay* overlay) : Event(EventTypeEnum::EVENT_OVERLAY_VALIDATE), m_overlay(overlay) { m_valid = false; } /** * Destructor. */ EventOverlayValidate::~EventOverlayValidate() { } /** * @return true if the overlay was found to be valid. */ bool EventOverlayValidate::isValidOverlay() const { return m_valid; } /** * Set the validity if the given overlay is the overlay * that was passed to the constructor. * * @param overlay * Overlay tested for match. */ void EventOverlayValidate::testValidOverlay(const Overlay* overlay) { if (m_overlay == overlay) { m_valid = true; } } connectome-workbench-1.4.2/src/Brain/EventOverlayValidate.h000066400000000000000000000034011360521144700237210ustar00rootroot00000000000000#ifndef __EVENT_OVERLAY_VALIDATE_H__ #define __EVENT_OVERLAY_VALIDATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class Overlay; class EventOverlayValidate : public Event { public: EventOverlayValidate(const Overlay* overlay); virtual ~EventOverlayValidate(); bool isValidOverlay() const; void testValidOverlay(const Overlay* overlay); private: EventOverlayValidate(const EventOverlayValidate&); EventOverlayValidate& operator=(const EventOverlayValidate&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE const Overlay* m_overlay; bool m_valid; }; #ifdef __EVENT_OVERLAY_VALIDATE_DECLARE__ // #endif // __EVENT_OVERLAY_VALIDATE_DECLARE__ } // namespace #endif //__EVENT_OVERLAY_VALIDATE_H__ connectome-workbench-1.4.2/src/Brain/EventSceneActive.cxx000066400000000000000000000036461360521144700234050ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_SCENE_ACTIVE_DECLARE__ #include "EventSceneActive.h" #undef __EVENT_SCENE_ACTIVE_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventSceneActive * \brief Event to get/set the active scene * \ingroup Brain * * Event to get/set the active scene. * The "active scene" is the scene that was last loaded * or created. If a spec file is loaded or the scene file * containing the scene is closed, the "active scene" * becomes invalid. */ /** * Constructor. * * @param mode * The mode of this event */ EventSceneActive::EventSceneActive(const Mode mode) : Event(EventTypeEnum::EVENT_SCENE_ACTIVE), m_mode(mode) { } /** * Destructor. */ EventSceneActive::~EventSceneActive() { } /** * @return The mode. */ EventSceneActive::Mode EventSceneActive::getMode() const { return m_mode; } /** * @return The scene */ Scene* EventSceneActive::getScene() const { return m_scene; } /** * Set the scene * New value for active scene. */ void EventSceneActive::setScene(Scene* scene) { m_scene = scene; } connectome-workbench-1.4.2/src/Brain/EventSceneActive.h000066400000000000000000000036601360521144700230260ustar00rootroot00000000000000#ifndef __EVENT_SCENE_ACTIVE_H__ #define __EVENT_SCENE_ACTIVE_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class Scene; class EventSceneActive : public Event { public: /** The mode of the event */ enum Mode { /** Get the active scene */ MODE_GET, /** Set the active scene */ MODE_SET }; EventSceneActive(const Mode mode); virtual ~EventSceneActive(); Mode getMode() const; Scene* getScene() const; void setScene(Scene* scene); EventSceneActive(const EventSceneActive&) = delete; EventSceneActive& operator=(const EventSceneActive&) = delete; // ADD_NEW_METHODS_HERE private: const Mode m_mode; Scene* m_scene = NULL; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_SCENE_ACTIVE_DECLARE__ // #endif // __EVENT_SCENE_ACTIVE_DECLARE__ } // namespace #endif //__EVENT_SCENE_ACTIVE_H__ connectome-workbench-1.4.2/src/Brain/EventSpacerTabGet.cxx000066400000000000000000000046111360521144700235110ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_SPACER_TAB_GET_DECLARE__ #include "EventSpacerTabGet.h" #undef __EVENT_SPACER_TAB_GET_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventSpacerTabGet * \brief Event for getting a spacer tag. * \ingroup Brain */ /** * Constructor. * * @param windowIndex * Index of the window * @param rowIndex * Index of the row * @param columnIndex * Index of the column */ EventSpacerTabGet::EventSpacerTabGet(const int32_t windowIndex, const int32_t rowIndex, const int32_t columnIndex) : Event(EventTypeEnum::EVENT_SPACER_TAB_GET), m_windowIndex(windowIndex), m_rowIndex(rowIndex), m_columnIndex(columnIndex), m_spacerTabContent(NULL) { } /** * Destructor. */ EventSpacerTabGet::~EventSpacerTabGet() { } /** * @return The window index. */ int32_t EventSpacerTabGet::getWindowIndex() const { return m_windowIndex; } /** * @return The row index. */ int32_t EventSpacerTabGet::getRowIndex() const { return m_rowIndex; } /** * @return The column index. */ int32_t EventSpacerTabGet::getColumnIndex() const { return m_columnIndex; } /** * @return The spacer tab. */ SpacerTabContent* EventSpacerTabGet::getSpacerTabContent() { return m_spacerTabContent; } /** * Set the spacer tab content. * * @param spacerTabContent * New value for the spacer tab content. */ void EventSpacerTabGet::setSpacerTabContent(SpacerTabContent* spacerTabContent) { m_spacerTabContent = spacerTabContent; } connectome-workbench-1.4.2/src/Brain/EventSpacerTabGet.h000066400000000000000000000041341360521144700231360ustar00rootroot00000000000000#ifndef __EVENT_SPACER_TAB_GET_H__ #define __EVENT_SPACER_TAB_GET_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class SpacerTabContent; class EventSpacerTabGet : public Event { public: EventSpacerTabGet(const int32_t windowIndex, const int32_t rowIndex, const int32_t columnIndex); virtual ~EventSpacerTabGet(); EventSpacerTabGet(const EventSpacerTabGet&) = delete; EventSpacerTabGet& operator=(const EventSpacerTabGet&) = delete; int32_t getWindowIndex() const; int32_t getRowIndex() const; int32_t getColumnIndex() const; SpacerTabContent* getSpacerTabContent(); void setSpacerTabContent(SpacerTabContent* spacerTabContent); // ADD_NEW_METHODS_HERE private: const int32_t m_windowIndex; const int32_t m_rowIndex; const int32_t m_columnIndex; SpacerTabContent* m_spacerTabContent = NULL; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_SPACER_TAB_GET_DECLARE__ // #endif // __EVENT_SPACER_TAB_GET_DECLARE__ } // namespace #endif //__EVENT_SPACER_TAB_GET_H__ connectome-workbench-1.4.2/src/Brain/EventSpecFileReadDataFiles.cxx000066400000000000000000000047271360521144700252600ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "EventSpecFileReadDataFiles.h" using namespace caret; /** * Constructor. * * @param loadIntoBrain * Brain into which file is loaded. * @param specFile * Spec file that has its files read. */ EventSpecFileReadDataFiles::EventSpecFileReadDataFiles(Brain* loadIntoBrain, SpecFile* specFile) : Event(EventTypeEnum::EVENT_SPEC_FILE_READ_DATA_FILES) { this->loadIntoBrain = loadIntoBrain; this->specFile = specFile; this->username = ""; this->password = ""; CaretAssert(this->loadIntoBrain); CaretAssert(this->specFile); } /** * Destructor. */ EventSpecFileReadDataFiles::~EventSpecFileReadDataFiles() { } /** * @return The spec file that is to have its data files loaded. */ SpecFile* EventSpecFileReadDataFiles::getSpecFile() { return this->specFile; } /** * @return The brain into which files is loaded. */ Brain* EventSpecFileReadDataFiles::getLoadIntoBrain() { return this->loadIntoBrain; } /** * @return The username. */ AString EventSpecFileReadDataFiles::getUsername() const { return this->username; } /** * @return The password. */ AString EventSpecFileReadDataFiles::getPassword() const { return this->password; } /** * Set the username and password. * * @param username * Name of user account. * @param password * Password of user account. */ void EventSpecFileReadDataFiles::setUsernameAndPassword(const AString& username, const AString& password) { this->username = username; this->password = password; } connectome-workbench-1.4.2/src/Brain/EventSpecFileReadDataFiles.h000066400000000000000000000041001360521144700246660ustar00rootroot00000000000000#ifndef __EVENT_SPEC_FILE_READ_DATA_FILES_H__ #define __EVENT_SPEC_FILE_READ_DATA_FILES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "DataFileTypeEnum.h" #include "Event.h" namespace caret { class Brain; class SpecFile; /** * Event for reading data files selected in a spec file. */ class EventSpecFileReadDataFiles : public Event { public: EventSpecFileReadDataFiles(Brain* loadIntoBrain, SpecFile* specFile); virtual ~EventSpecFileReadDataFiles(); SpecFile* getSpecFile(); Brain* getLoadIntoBrain(); AString getUsername() const; AString getPassword() const; void setUsernameAndPassword(const AString& username, const AString& password); private: EventSpecFileReadDataFiles(const EventSpecFileReadDataFiles&); EventSpecFileReadDataFiles& operator=(const EventSpecFileReadDataFiles&); Brain* loadIntoBrain; SpecFile* specFile; AString username; AString password; bool errorInvalidStructure; }; } // namespace #endif // __EVENT_SPEC_FILE_READ_DATA_FILES_H__ connectome-workbench-1.4.2/src/Brain/EventSurfacesGet.cxx000066400000000000000000000064141360521144700234230ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretAssert.h" #include "EventSurfacesGet.h" #include "Surface.h" using namespace caret; /** * Construct an event for getting surfaces from * all structures and surface types. Methods * are provided for constraining the surfaces * to those with specified structures and/or * surface types. */ EventSurfacesGet::EventSurfacesGet() : Event(EventTypeEnum::EVENT_SURFACES_GET) { } /** * Destructore. */ EventSurfacesGet::~EventSurfacesGet() { } /** * Add a surface. If the surface does not * meet any surface/structure constraints, * it will not be added. * * @param surface * Surface that is added. */ void EventSurfacesGet::addSurface(Surface* surface) { if (this->structureConstraints.empty() == false) { const StructureEnum::Enum structure = surface->getStructure(); if (std::find(this->structureConstraints.begin(), this->structureConstraints.end(), structure) == this->structureConstraints.end()) { return; } } if (this->surfaceTypeConstraints.empty() == false) { const SurfaceTypeEnum::Enum surfaceType = surface->getSurfaceType(); if (std::find(this->surfaceTypeConstraints.begin(), this->surfaceTypeConstraints.end(), surfaceType) == this->surfaceTypeConstraints.end()) { return; } } this->surfaces.push_back(surface); } /** * Add a structure contraints. If structure constraints * are added, only surface of the specified structures * are obtained. May be called more than once for * constraining to multiple surface types. * * @param structure * Structure for constraining selection. */ void EventSurfacesGet::addStructureConstraint(const StructureEnum::Enum structure) { this->structureConstraints.push_back(structure); } /** * Add a surface type contraints. If surface type constraints * are added, only surfaces of the specified surface types * are obtained. May be called more than once for constraining * to multiple surface types. * * @param surfaceType * Surface type for constraining selection. */ void EventSurfacesGet::addSurfaceTypeConstraint(const SurfaceTypeEnum::Enum surfaceType) { this->surfaceTypeConstraints.push_back(surfaceType); } /** * @return Surfaces that were obtained. */ std::vector EventSurfacesGet::getSurfaces() const { return this->surfaces; } connectome-workbench-1.4.2/src/Brain/EventSurfacesGet.h000066400000000000000000000035251360521144700230500ustar00rootroot00000000000000#ifndef __EVENT_SURFACES_GET_H__ #define __EVENT_SURFACES_GET_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" #include "StructureEnum.h" #include "SurfaceTypeEnum.h" namespace caret { class Surface; /// Get surfaces class EventSurfacesGet : public Event { public: EventSurfacesGet(); virtual ~EventSurfacesGet(); void addSurface(Surface* surface); void addStructureConstraint(const StructureEnum::Enum structure); void addSurfaceTypeConstraint(const SurfaceTypeEnum::Enum surfaceType); std::vector getSurfaces() const; private: EventSurfacesGet(const EventSurfacesGet&); EventSurfacesGet& operator=(const EventSurfacesGet&); std::vector surfaces; std::vector structureConstraints; std::vector surfaceTypeConstraints; }; } // namespace #endif // __EVENT_SURFACES_GET_H__ connectome-workbench-1.4.2/src/Brain/FeatureColoringTypeEnum.cxx000066400000000000000000000234071360521144700247660ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __FEATURE_COLORING_TYPE_ENUM_DECLARE__ #include "FeatureColoringTypeEnum.h" #undef __FEATURE_COLORING_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::FeatureColoringTypeEnum * \brief Coloring type for features. * \ingroup GuiQt */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ FeatureColoringTypeEnum::FeatureColoringTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ FeatureColoringTypeEnum::~FeatureColoringTypeEnum() { } /** * Initialize the enumerated metadata. */ void FeatureColoringTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(FeatureColoringTypeEnum(FEATURE_COLORING_TYPE_CLASS, "FEATURE_COLORING_TYPE_CLASS", "Class")); enumData.push_back(FeatureColoringTypeEnum(FEATURE_COLORING_TYPE_NAME, "FEATURE_COLORING_TYPE_NAME", "Name")); enumData.push_back(FeatureColoringTypeEnum(FEATURE_COLORING_TYPE_STANDARD_COLOR, "FEATURE_COLORING_TYPE_STANDARD_COLOR", "Standard Color")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const FeatureColoringTypeEnum* FeatureColoringTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const FeatureColoringTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString FeatureColoringTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const FeatureColoringTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ FeatureColoringTypeEnum::Enum FeatureColoringTypeEnum::fromName(const AString& nameIn, bool* isValidOut) { AString name = nameIn; /* * Translate foci coloring type that was replaced */ if (name == "FOCI_COLORING_TYPE_CLASS") { name = "FEATURE_COLORING_TYPE_CLASS"; } else if (name == "FOCI_COLORING_TYPE_NAME") { name = "FEATURE_COLORING_TYPE_NAME"; } if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = FEATURE_COLORING_TYPE_NAME; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const FeatureColoringTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type FeatureColoringTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString FeatureColoringTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const FeatureColoringTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ FeatureColoringTypeEnum::Enum FeatureColoringTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = FEATURE_COLORING_TYPE_NAME; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const FeatureColoringTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type FeatureColoringTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t FeatureColoringTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const FeatureColoringTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ FeatureColoringTypeEnum::Enum FeatureColoringTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = FEATURE_COLORING_TYPE_NAME; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const FeatureColoringTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type FeatureColoringTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void FeatureColoringTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void FeatureColoringTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(FeatureColoringTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void FeatureColoringTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(FeatureColoringTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Brain/FeatureColoringTypeEnum.h000066400000000000000000000064051360521144700244120ustar00rootroot00000000000000#ifndef __FEATURE_COLORING_TYPE_ENUM__H_ #define __FEATURE_COLORING_TYPE_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class FeatureColoringTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Use class for coloring */ FEATURE_COLORING_TYPE_CLASS, /** Use name for coloring */ FEATURE_COLORING_TYPE_NAME, /** Use color name for standard color */ FEATURE_COLORING_TYPE_STANDARD_COLOR }; ~FeatureColoringTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: FeatureColoringTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const FeatureColoringTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __FEATURE_COLORING_TYPE_ENUM_DECLARE__ std::vector FeatureColoringTypeEnum::enumData; bool FeatureColoringTypeEnum::initializedFlag = false; int32_t FeatureColoringTypeEnum::integerCodeCounter = 0; #endif // __FEATURE_COLORING_TYPE_ENUM_DECLARE__ } // namespace #endif //__FEATURE_COLORING_TYPE_ENUM__H_ connectome-workbench-1.4.2/src/Brain/FiberOrientationSamplesLoader.cxx000066400000000000000000000346211360521144700261260ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __FIBER_ORIENTATION_SAMPLES_LOADER_DECLARE__ #include "FiberOrientationSamplesLoader.h" #undef __FIBER_ORIENTATION_SAMPLES_LOADER_DECLARE__ #include "Brain.h" #include "CaretAssert.h" #include "CiftiFiberOrientationFile.h" #include "DataFileException.h" #include "FiberOrientation.h" #include "FileInformation.h" #include "EventIdentificationHighlightLocation.h" #include "EventManager.h" #include "SpecFile.h" #include "VolumeFile.h" using namespace caret; /** * \class caret::FiberOrientationSamplesLoader * \brief Loads Fiber Orientation samples display on a sphere in features toolbox * \ingroup Brain */ /** * Constructor. */ FiberOrientationSamplesLoader::FiberOrientationSamplesLoader() : CaretObject() { m_sampleVolumesLoadAttemptValid = false; m_sampleVolumesValid = false; for (int32_t i = 0; i < 3; i++) { m_sampleMagnitudeVolumes[i] = NULL; m_sampleThetaVolumes[i] = NULL; m_samplePhiVolumes[i] = NULL; } m_lastIdentificationValid = false; EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_IDENTIFICATION_HIGHLIGHT_LOCATION); } /** * Destructor. */ FiberOrientationSamplesLoader::~FiberOrientationSamplesLoader() { reset(); EventManager::get()->removeAllEventsFromListener(this); } /** * Reset all settings to their defaults * and remove any data. */ void FiberOrientationSamplesLoader::reset() { m_sampleVolumesLoadAttemptValid = false; m_sampleVolumesValid = false; for (int32_t i = 0; i < 3; i++) { if (m_sampleMagnitudeVolumes[i] != NULL) { delete m_sampleMagnitudeVolumes[i]; m_sampleMagnitudeVolumes[i] = NULL; } if (m_sampleThetaVolumes[i] != NULL) { delete m_sampleThetaVolumes[i]; m_sampleThetaVolumes[i] = NULL; } if (m_samplePhiVolumes[i] != NULL) { delete m_samplePhiVolumes[i]; m_samplePhiVolumes[i] = NULL; } } m_lastIdentificationValid = false; } /** * Receive events from the event manager. * * @param event * Event sent by event manager. */ void FiberOrientationSamplesLoader::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_IDENTIFICATION_HIGHLIGHT_LOCATION) { EventIdentificationHighlightLocation* idEvent = dynamic_cast(event); CaretAssert(idEvent); switch (idEvent->getLoadFiberOrientationSamplesMode()) { case EventIdentificationHighlightLocation::LOAD_FIBER_ORIENTATION_SAMPLES_MODE_NO: break; case EventIdentificationHighlightLocation::LOAD_FIBER_ORIENTATION_SAMPLES_MODE_YES: { const float* xyz = idEvent->getXYZ(); if (xyz != NULL) { m_lastIdentificationValid = true; m_lastIdentificationXYZ[0] = xyz[0]; m_lastIdentificationXYZ[1] = xyz[1]; m_lastIdentificationXYZ[2] = xyz[2]; } } break; } } } /** * Get the fiber orientation vectors for display on a sphere. * * @param brain * Brain for which vectors are loaded. * @param xVectors * Vectors for X-orientation. * @param yVectors * Vectors for Y-orientation. * @param zVectors * Vectors for Z-orientation. * @param fiberOrientation * The nearby fiber orientation * @param errorMessageOut * Will contain any error messages. * This error message will only be set in some cases when there is an * error. * @return * True if data is valid, else false. */ bool FiberOrientationSamplesLoader::getFiberOrientationSphericalSamplesVectors(Brain* brain, std::vector& xVectors, std::vector& yVectors, std::vector& zVectors, FiberOrientation* &fiberOrientationOut, AString& errorMessageOut) { CaretAssert(brain); errorMessageOut = ""; fiberOrientationOut = NULL; if (m_lastIdentificationValid) { if (loadSphericalOrientationVolumes(brain, errorMessageOut) == false) { return false; } if (brain->getNumberOfConnectivityFiberOrientationFiles() > 0) { CiftiFiberOrientationFile* cfof = brain->getConnectivityFiberOrientationFile(0); FiberOrientation* nearestFiberOrientation = cfof->getFiberOrientationNearestCoordinate(m_lastIdentificationXYZ, 3.0); if (nearestFiberOrientation != NULL) { fiberOrientationOut = nearestFiberOrientation; } } int64_t ijk[3]; m_sampleThetaVolumes[0]->enclosingVoxel(m_lastIdentificationXYZ, ijk); if (m_sampleThetaVolumes[0]->indexValid(ijk)) { std::vector dims; m_sampleThetaVolumes[0]->getDimensions(dims); const int64_t numberOfOrientations = dims[3]; xVectors.resize(numberOfOrientations); yVectors.resize(numberOfOrientations); zVectors.resize(numberOfOrientations); for (int32_t iAxis = 0; iAxis < 3; iAxis++) { for (int64_t iOrient = 0; iOrient < numberOfOrientations; iOrient++) { const float theta = m_sampleThetaVolumes[iAxis]->getValue(ijk[0], ijk[1], ijk[2], iOrient, 0); const float phi = m_samplePhiVolumes[iAxis]->getValue(ijk[0], ijk[1], ijk[2], iOrient, 0); const float magnitude = m_sampleMagnitudeVolumes[iAxis]->getValue(ijk[0], ijk[1], ijk[2], iOrient, 0); switch (iAxis) { case 0: { FiberOrientationSamplesVector& ov = xVectors[iOrient]; ov.direction[0] = -std::sin(theta) * std::cos(phi); ov.direction[1] = std::sin(theta) * std::sin(phi); ov.direction[2] = std::cos(theta); ov.magnitude = magnitude; ov.setColor(); } break; case 1: { FiberOrientationSamplesVector& ov = yVectors[iOrient]; ov.direction[0] = -std::sin(theta) * std::cos(phi); ov.direction[1] = std::sin(theta) * std::sin(phi); ov.direction[2] = std::cos(theta); ov.magnitude = magnitude; ov.setColor(); } break; case 2: { FiberOrientationSamplesVector& ov = zVectors[iOrient]; ov.direction[0] = -std::sin(theta) * std::cos(phi); ov.direction[1] = std::sin(theta) * std::sin(phi); ov.direction[2] = std::cos(theta); ov.magnitude = magnitude; ov.setColor(); } break; } } } return true; } } return false; } /** * Get the volumes containing the spherical orienations. * * @param brain * Brain for which vectors are loaded. * @param magnitudeVolumesOut * The volumes containing the magnitudes. * @param phiAngleVolumesOut * The volumes containing the phi angles. * @param thetaAngleVolumesOut * The volumes containing the theta angles. * */ bool FiberOrientationSamplesLoader::loadSphericalOrientationVolumes(Brain* brain, AString& errorMessageOut) { errorMessageOut = ""; FileInformation specFileInfo(brain->getSpecFile()->getFileName()); const AString directoryName = specFileInfo.getPathName(); if (m_sampleVolumesValid == false) { if (m_sampleVolumesLoadAttemptValid == false) { const AString filePrefix = "merged_"; const AString fileSuffix = "samples.nii.gz"; std::vector allVolumes; for (int32_t i = 0; i < 3; i++) { m_sampleMagnitudeVolumes[i] = new VolumeFile(); m_samplePhiVolumes[i] = new VolumeFile(); m_sampleThetaVolumes[i] = new VolumeFile(); const AString fileNumber = AString::number(i + 1); try { const AString magFileName = (filePrefix + "f" + fileNumber + fileSuffix); FileInformation magFileInfo(directoryName, magFileName); const AString magFilePath = magFileInfo.getAbsoluteFilePath(); m_sampleMagnitudeVolumes[i]->readFile(magFilePath); allVolumes.push_back(m_sampleMagnitudeVolumes[i]); } catch (const DataFileException& dfe) { if (errorMessageOut.isEmpty() == false) { errorMessageOut += "\n"; } errorMessageOut += dfe.whatString(); } try { const AString phiFileName = (filePrefix + "ph" + fileNumber + fileSuffix); FileInformation phiFileInfo(directoryName, phiFileName); const AString phiFilePath = phiFileInfo.getAbsoluteFilePath(); m_samplePhiVolumes[i]->readFile(phiFilePath); allVolumes.push_back(m_samplePhiVolumes[i]); } catch (const DataFileException& dfe) { if (errorMessageOut.isEmpty() == false) { errorMessageOut += "\n"; } errorMessageOut += dfe.whatString(); } try { const AString thetaFileName = (filePrefix + "th" + fileNumber + fileSuffix); FileInformation thetaFileInfo(directoryName, thetaFileName); const AString thetaFilePath = thetaFileInfo.getAbsoluteFilePath(); m_sampleThetaVolumes[i]->readFile(thetaFilePath); allVolumes.push_back(m_sampleThetaVolumes[i]); } catch (const DataFileException& dfe) { if (errorMessageOut.isEmpty() == false) { errorMessageOut += "\n"; } errorMessageOut += dfe.whatString(); } } if (errorMessageOut.isEmpty()) { std::vector dims; for (std::vector::iterator iter = allVolumes.begin(); iter != allVolumes.end(); iter++) { VolumeFile* vf = *iter; std::vector volDims; vf->getDimensions(volDims); if (dims.empty()) { dims = volDims; } else if (dims != volDims) { errorMessageOut += "ERROR: Sample volumes have mis-matched dimensions"; } } m_sampleVolumesValid = true; } m_sampleVolumesLoadAttemptValid = true; } } if (m_sampleVolumesValid) { return true; } return false; } connectome-workbench-1.4.2/src/Brain/FiberOrientationSamplesLoader.h000066400000000000000000000062451360521144700255540ustar00rootroot00000000000000#ifndef __FIBER_ORIENTATION_SAMPLES_LOADER_H__ #define __FIBER_ORIENTATION_SAMPLES_LOADER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "EventListenerInterface.h" #include "FiberOrientationSamplesVector.h" namespace caret { class Brain; class FiberOrientation; class VolumeFile; class FiberOrientationSamplesLoader : public CaretObject, public EventListenerInterface { public: FiberOrientationSamplesLoader(); virtual ~FiberOrientationSamplesLoader(); bool getFiberOrientationSphericalSamplesVectors(Brain* brain, std::vector& xVectors, std::vector& yVectors, std::vector& zVectors, FiberOrientation* &fiberOrientationOut, AString& errorMessageOut); void reset(); void receiveEvent(Event* event); private: FiberOrientationSamplesLoader(const FiberOrientationSamplesLoader&); FiberOrientationSamplesLoader& operator=(const FiberOrientationSamplesLoader&); bool loadSphericalOrientationVolumes(Brain* brain, AString& errorMessageOut); /** Tried to load sample volumes since last reset (they may or may not be valid) */ bool m_sampleVolumesLoadAttemptValid; /** Sample volumes were loaded and are valid */ bool m_sampleVolumesValid; /* sample magnitude volumes */ VolumeFile* m_sampleMagnitudeVolumes[3]; /* sample theta angle volumes */ VolumeFile* m_sampleThetaVolumes[3]; /* sample phi angle volumes */ VolumeFile* m_samplePhiVolumes[3]; /* last identified location */ float m_lastIdentificationXYZ[3]; /* last identification valid */ bool m_lastIdentificationValid; }; #ifdef __FIBER_ORIENTATION_SAMPLES_LOADER_DECLARE__ // #endif // __FIBER_ORIENTATION_SAMPLES_LOADER_DECLARE__ } // namespace #endif //__FIBER_ORIENTATION_SAMPLES_LOADER_H__ connectome-workbench-1.4.2/src/Brain/FiberOrientationSamplesVector.h000066400000000000000000000036651360521144700256130ustar00rootroot00000000000000#ifndef __FIBER_ORIENTATION_SAMPLES_VECTOR_H__ #define __FIBER_ORIENTATION_SAMPLES_VECTOR_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ namespace caret { /** * \struct caret::FiberOrientationSamplesVector * \brief Stores a fiber orientation samples vector * \ingroup Brain */ struct FiberOrientationSamplesVector { /** The direction vector */ float direction[3]; /** The magnitude (length) */ float magnitude; /** RGB coloring for vector */ float rgb[3]; /** * Set the RGB color to absolute values of the directional vector */ void setColor() { rgb[0] = (direction[0] >= 0.0) ? direction[0] : -direction[0]; rgb[1] = (direction[1] >= 0.0) ? direction[1] : -direction[1]; rgb[2] = (direction[2] >= 0.0) ? direction[2] : -direction[2]; } }; #ifdef __FIBER_ORIENTATION_SAMPLES_VECTOR_DECLARE__ // #endif // __FIBER_ORIENTATION_SAMPLES_VECTOR_DECLARE__ } // namespace #endif //__FIBER_ORIENTATION_SAMPLES_VECTOR_H__ connectome-workbench-1.4.2/src/Brain/FiberOrientationSymbolTypeEnum.cxx000066400000000000000000000227371360521144700263340ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __FIBER_ORIENTATION_SYMBOL_TYPE_ENUM_DECLARE__ #include "FiberOrientationSymbolTypeEnum.h" #undef __FIBER_ORIENTATION_SYMBOL_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::FiberOrientationSymbolTypeEnum * \brief * * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ FiberOrientationSymbolTypeEnum::FiberOrientationSymbolTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ FiberOrientationSymbolTypeEnum::~FiberOrientationSymbolTypeEnum() { } /** * Initialize the enumerated metadata. */ void FiberOrientationSymbolTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(FiberOrientationSymbolTypeEnum(FIBER_SYMBOL_FANS, "FIBER_SYMBOL_FANS", "Fans")); enumData.push_back(FiberOrientationSymbolTypeEnum(FIBER_SYMBOL_LINES, "FIBER_SYMBOL_LINES", "Lines")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const FiberOrientationSymbolTypeEnum* FiberOrientationSymbolTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const FiberOrientationSymbolTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString FiberOrientationSymbolTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const FiberOrientationSymbolTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ FiberOrientationSymbolTypeEnum::Enum FiberOrientationSymbolTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = FIBER_SYMBOL_LINES; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const FiberOrientationSymbolTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type FiberOrientationSymbolTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString FiberOrientationSymbolTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const FiberOrientationSymbolTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ FiberOrientationSymbolTypeEnum::Enum FiberOrientationSymbolTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = FIBER_SYMBOL_LINES; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const FiberOrientationSymbolTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type FiberOrientationSymbolTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t FiberOrientationSymbolTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const FiberOrientationSymbolTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ FiberOrientationSymbolTypeEnum::Enum FiberOrientationSymbolTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = FIBER_SYMBOL_LINES; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const FiberOrientationSymbolTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type FiberOrientationSymbolTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void FiberOrientationSymbolTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void FiberOrientationSymbolTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(FiberOrientationSymbolTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void FiberOrientationSymbolTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(FiberOrientationSymbolTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Brain/FiberOrientationSymbolTypeEnum.h000066400000000000000000000064101360521144700257470ustar00rootroot00000000000000#ifndef __FIBER_ORIENTATION_SYMBOL_TYPE_ENUM__H_ #define __FIBER_ORIENTATION_SYMBOL_TYPE_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class FiberOrientationSymbolTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Use Fans for drawing fibers */ FIBER_SYMBOL_FANS, /** Use Lines for drawing fibers */ FIBER_SYMBOL_LINES }; ~FiberOrientationSymbolTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: FiberOrientationSymbolTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const FiberOrientationSymbolTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __FIBER_ORIENTATION_SYMBOL_TYPE_ENUM_DECLARE__ std::vector FiberOrientationSymbolTypeEnum::enumData; bool FiberOrientationSymbolTypeEnum::initializedFlag = false; int32_t FiberOrientationSymbolTypeEnum::integerCodeCounter = 0; #endif // __FIBER_ORIENTATION_SYMBOL_TYPE_ENUM_DECLARE__ } // namespace #endif //__FIBER_ORIENTATION_SYMBOL_TYPE_ENUM__H_ connectome-workbench-1.4.2/src/Brain/FociDrawingTypeEnum.cxx000066400000000000000000000217541360521144700240750ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __FOCI_DRAWING_TYPE_ENUM_DECLARE__ #include "FociDrawingTypeEnum.h" #undef __FOCI_DRAWING_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::FociDrawingTypeEnum * \brief * * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ FociDrawingTypeEnum::FociDrawingTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ FociDrawingTypeEnum::~FociDrawingTypeEnum() { } /** * Initialize the enumerated metadata. */ void FociDrawingTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(FociDrawingTypeEnum(DRAW_AS_SPHERES, "DRAW_AS_SPHERES", "Spheres")); enumData.push_back(FociDrawingTypeEnum(DRAW_AS_SQUARES, "DRAW_AS_SQUARES", "Squares")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const FociDrawingTypeEnum* FociDrawingTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const FociDrawingTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString FociDrawingTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const FociDrawingTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ FociDrawingTypeEnum::Enum FociDrawingTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = DRAW_AS_SPHERES; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const FociDrawingTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type FociDrawingTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString FociDrawingTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const FociDrawingTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ FociDrawingTypeEnum::Enum FociDrawingTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = DRAW_AS_SPHERES; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const FociDrawingTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type FociDrawingTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t FociDrawingTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const FociDrawingTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ FociDrawingTypeEnum::Enum FociDrawingTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = DRAW_AS_SPHERES; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const FociDrawingTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type FociDrawingTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void FociDrawingTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void FociDrawingTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(FociDrawingTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void FociDrawingTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(FociDrawingTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Brain/FociDrawingTypeEnum.h000066400000000000000000000061401360521144700235120ustar00rootroot00000000000000#ifndef __FOCI_DRAWING_TYPE_ENUM__H_ #define __FOCI_DRAWING_TYPE_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class FociDrawingTypeEnum { public: /** * Enumerated values for foci drawing type. */ enum Enum { /** Draw as spheres */ DRAW_AS_SPHERES, /** Draw as squares*/ DRAW_AS_SQUARES }; ~FociDrawingTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: FociDrawingTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const FociDrawingTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __FOCI_DRAWING_TYPE_ENUM_DECLARE__ std::vector FociDrawingTypeEnum::enumData; bool FociDrawingTypeEnum::initializedFlag = false; int32_t FociDrawingTypeEnum::integerCodeCounter = 0; #endif // __FOCI_DRAWING_TYPE_ENUM_DECLARE__ } // namespace #endif //__FOCI_DRAWING_TYPE_ENUM__H_ connectome-workbench-1.4.2/src/Brain/FtglFontTextRenderer.cxx000066400000000000000000003011131360521144700242570ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /** * Qt licence is included since some of its GLWidget API is copied. */ /**************************************************************************** ** ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtOpenGL module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifdef HAVE_FREETYPE #define __FTGL_FONT_TEXT_RENDERER_DECLARE__ #include "FtglFontTextRenderer.h" #undef __FTGL_FONT_TEXT_RENDERER_DECLARE__ #include #include #include #include #include #include #include "AnnotationCoordinate.h" #include "AnnotationPointSizeText.h" #include "BrainOpenGL.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretOpenGLInclude.h" #include "GraphicsEngineDataOpenGL.h" #include "GraphicsOpenGLError.h" #include "GraphicsPrimitiveV3f.h" #include "GraphicsPrimitiveV3fN3f.h" #include "GraphicsShape.h" #include "GraphicsUtilitiesOpenGL.h" #include "MathFunctions.h" #include "Matrix4x4.h" #include using namespace FTGL; using namespace caret; static const bool debugPrintFlag = false; static const bool drawCrosshairsAtFontStartingCoordinate = false; /** * \class caret::FtglFontTextRenderer * \brief Text rendering using FTGL * \ingroup Brain * * Draws text using the FTGL library. * * FTGL's Texture font is used for drawing text. * The texture font is positioned using the current OpenGL * model view matrix which allows rotation and scaling. * * There are other font types such as Pixmap font. The * pixmap font was used, but it cannot be rotated nor * scaled. In addition, the pixmmap font drawing * requires a raster position and if the raster position * is slightly outside the viewport all text is clipped. */ /** * Constructor. */ FtglFontTextRenderer::FtglFontTextRenderer() : BrainOpenGLTextRenderInterface() { m_defaultFont = NULL; AnnotationPointSizeText defaultAnnotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); defaultAnnotationText.setFontPointSize(AnnotationTextFontPointSizeEnum::SIZE14); defaultAnnotationText.setFont(AnnotationTextFontNameEnum::VERA); defaultAnnotationText.setItalicStyleEnabled(false); defaultAnnotationText.setBoldStyleEnabled(false); defaultAnnotationText.setUnderlineStyleEnabled(false); m_defaultFont = getFont(defaultAnnotationText, FtglFontTypeEnum::TEXTURE, true); m_depthTestingStatus = DEPTH_TEST_NO; BrainOpenGL::getMinMaxLineWidth(m_lineWidthMinimum, m_lineWidthMaximum); } /** * Destructor. */ FtglFontTextRenderer::~FtglFontTextRenderer() { for (FONT_MAP_ITERATOR iter = m_fontNameToFontMap.begin(); iter != m_fontNameToFontMap.end(); iter++) { delete iter->second; } m_fontNameToFontMap.clear(); /* * Do not delete "m_defaultFont" since it points to a font * in m_fontNameToFontMap. Doing so would cause * a double delete. */ } /** * @return The font system is valid. */ bool FtglFontTextRenderer::isValid() const { return (m_defaultFont != NULL); } /* * Get the font with the given font attributes. * If the font is not created, return the default font. * * @param annotationText * Annotation Text that is to be drawn. * @param ftglFontType * Type of font. * @param heightOrWidthForPercentageSizeText * If positive, use it to override width/height of viewport. * @param creatingDefaultFontFlag * True if creating the default font. * @return * The FTGL font. If there are errors this value will * be NULL. */ FTFont* FtglFontTextRenderer::getFont(const AnnotationText& annotationText, const FtglFontTypeEnum ftglFontType, const float heightOrWidthForPercentageSizeText, const bool creatingDefaultFontFlag) { int32_t viewportWidth = m_viewportWidth; int32_t viewportHeight = m_viewportHeight; switch (annotationText.getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: { int32_t vp[4]; annotationText.getViewportCoordinateSpaceViewport(vp); viewportWidth = vp[2]; viewportHeight = vp[3]; } break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } if (heightOrWidthForPercentageSizeText > 0.0) { viewportHeight = heightOrWidthForPercentageSizeText; viewportWidth = heightOrWidthForPercentageSizeText; } bool tooSmallTextHeightValidFlag = false; AString fontTypeString; switch (ftglFontType) { case FtglFontTypeEnum::POLYGON: fontTypeString = "Polygon_"; /* Polygon text is never too small */ tooSmallTextHeightValidFlag = false; break; case FtglFontTypeEnum::TEXTURE: fontTypeString = "Texture_"; tooSmallTextHeightValidFlag = true; break; } const AString fontName = (fontTypeString + annotationText.getFontRenderingEncodedName(viewportWidth, viewportHeight)); /* * Has the font already has been created? */ FONT_MAP_ITERATOR fontIter = m_fontNameToFontMap.find(fontName); if (fontIter != m_fontNameToFontMap.end()) { FontData* fontData = fontIter->second; CaretAssert(fontData); /* * Set font "too small" status */ const bool tooSmallFlag = (fontData->m_font->FaceSize() <= AnnotationText::getTooSmallTextHeight()); annotationText.setFontTooSmallWhenLastDrawn(tooSmallFlag && tooSmallTextHeightValidFlag); return fontData->m_font; } /* * Create and save the font */ FontData* fontData = new FontData(annotationText, ftglFontType, viewportWidth, viewportHeight); if (fontData->m_valid) { /* * Request font is valid. */ m_fontNameToFontMap.insert(std::make_pair(fontName, fontData)); CaretLogFine("Created font with encoded name " + fontName); /* * Set font "too small" status */ const bool tooSmallFlag = (fontData->m_font->FaceSize() <= AnnotationText::getTooSmallTextHeight()); annotationText.setFontTooSmallWhenLastDrawn(tooSmallFlag && tooSmallTextHeightValidFlag); return fontData->m_font; } else { /* * Error creating font */ delete fontData; fontData = NULL; /* * Issue a message about failure to create font but * don't print same message more than once. */ if (std::find(m_failedFontNames.begin(), m_failedFontNames.end(), fontName) == m_failedFontNames.end()) { m_failedFontNames.insert(fontName); CaretLogSevere("Failed to create font with encoded name " + fontName); } } /* * Were we trying to create the default font? */ if (creatingDefaultFontFlag) { return NULL; } /* * Failed so use the default font. */ annotationText.setFontTooSmallWhenLastDrawn(false); return m_defaultFont; } /* * Get the font with the given font attributes. * If the font is not created, return the default font. * * @param annotationText * Annotation Text that is to be drawn. * @param ftglFontType * Type of font. * @param creatingDefaultFontFlag * True if creating the default font. * @return * The FTGL font. If there are errors this value will * be NULL. */ FTFont* FtglFontTextRenderer::getFont(const AnnotationText& annotationText, const FtglFontTypeEnum ftglFontType, const bool creatingDefaultFontFlag) { return getFont(annotationText, ftglFontType, -1.0, // negative indicates invalid height for percentage text creatingDefaultFontFlag); } /** * Convert a percentage height to a line width in pixels * * @param percentageHeight * Percentage of viewport height. * @return * Line width in pixels clamped to valid range */ double FtglFontTextRenderer::getLineWidthFromPercentageHeight(const double percentageHeight) const { float widthPixels = (percentageHeight / 100.0) * m_viewportHeight; if (widthPixels < m_lineWidthMinimum) { widthPixels = m_lineWidthMinimum; } else if (widthPixels > m_lineWidthMaximum) { widthPixels = m_lineWidthMaximum; } return widthPixels; } /** * Draw the text piceces at their assigned viewport coordinates. * * @param annotationText * Annotation text and attributes. * @param textMatrix * Text broken up into cells with viewport coordinates assigned. * */ void FtglFontTextRenderer::drawTextAtViewportCoordinatesInternal(const AnnotationText& annotationText, const TextStringGroup& textStringGroup) { FTFont* font = getFont(annotationText, FtglFontTypeEnum::TEXTURE, false); if (! font) { return; } if (annotationText.getText().isEmpty()) { return; } saveStateOfOpenGL(); BrainOpenGL::testForOpenGLError("At beginning of " "FtglFontTextRenderer::drawTextAtViewportCoordinatesInternal " "while drawing text: " + annotationText.getText()); /* * Depth testing ? */ switch (m_depthTestingStatus) { case DEPTH_TEST_NO: glDisable(GL_DEPTH_TEST); break; case DEPTH_TEST_YES: glEnable(GL_DEPTH_TEST); break; } /* * Get the viewport */ GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); /* * Get depth range for orthographic projection. */ GLdouble depthRange[2]; glGetDoublev(GL_DEPTH_RANGE, depthRange); /* * Set the orthographic projection so that its origin is in the bottom * left corner. It needs to be there since we are drawing in window * coordinates. We do not know the true size of the window but that * is okay since we can set the orthographic view so that the bottom * left corner is the origin and the top right corner is the top * right corner of the user's viewport. */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, (viewport[2]), 0, (viewport[3]), depthRange[0], depthRange[1]); /* * Viewing projection is just the identity matrix since * we are drawing in window coordinates. */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); if (debugPrintFlag || drawCrosshairsAtFontStartingCoordinate) { GLfloat savedRGBA[4]; glGetFloatv(GL_CURRENT_COLOR, savedRGBA); glColor3f(1.0, 0.0, 0.0); glLineWidth(1.0); glPushMatrix(); glTranslatef(textStringGroup.m_viewportX, textStringGroup.m_viewportY, 0.0); const float xy = 500.0; glBegin(GL_LINES); glVertex2f(-xy, 0.0); glVertex2f( xy, 0.0); glVertex2f(0.0, -xy); glVertex2f(0.0, xy); glEnd(); glPopMatrix(); glColor3f(savedRGBA[0], savedRGBA[1], savedRGBA[2]); } const double underlineOffsetY = (textStringGroup.m_underlineThickness / 2.0); double bottomLeft[3], bottomRight[3], topRight[3], topLeft[3], rotationPointXYZ[3]; textStringGroup.getViewportBounds(s_textMarginSize, bottomLeft, bottomRight, topRight, topLeft, rotationPointXYZ); rotationPointXYZ[2] = 0.0; glPushMatrix(); glLoadIdentity(); applyBackgroundColoring(textStringGroup); applyTextColoring(annotationText); const float rotationAngle = annotationText.getRotationAngle(); glTranslated(rotationPointXYZ[0], rotationPointXYZ[1], rotationPointXYZ[2]); glRotated(rotationAngle, 0.0, 0.0, -1.0); for (std::vector::const_iterator iter = textStringGroup.m_textStrings.begin(); iter != textStringGroup.m_textStrings.end(); iter++) { const TextString* ts = *iter; double x = ts->m_viewportX; double y = ts->m_viewportY; double z = ts->m_viewportZ; applyTextColoring(annotationText); for (std::vector::const_iterator charIter = ts->m_characters.begin(); charIter != ts->m_characters.end(); charIter++) { const TextCharacter* tc = *charIter; x += tc->m_offsetX; y += tc->m_offsetY; z += tc->m_offsetZ; const double offsetX = x - rotationPointXYZ[0]; const double offsetY = y - rotationPointXYZ[1]; const double offsetZ = z - rotationPointXYZ[2]; glPushMatrix(); glTranslated(offsetX, offsetY, offsetZ); font->Render(&tc->m_character, 1); glPopMatrix(); } if (ts->m_underlineThickness > 0.0) { glPushMatrix(); glTranslated(ts->m_viewportX - rotationPointXYZ[0], ts->m_viewportY - rotationPointXYZ[1], 0.0); const double underlineY = ts->m_stringGlyphsMinY + underlineOffsetY; uint8_t foregroundRgba[4]; annotationText.getTextColorRGBA(foregroundRgba); drawUnderline(ts->m_stringGlyphsMinX, ts->m_stringGlyphsMaxX, underlineY, z, ts->m_underlineThickness, foregroundRgba); glPopMatrix(); } } glLoadIdentity(); uint8_t foregroundRgba[4]; annotationText.getLineColorRGBA(foregroundRgba); if (foregroundRgba[3] > 0) { GraphicsPrimitiveV3f primitive(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN, foregroundRgba); primitive.addVertex(topLeft); primitive.addVertex(bottomLeft); primitive.addVertex(bottomRight); primitive.addVertex(topRight); primitive.setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, annotationText.getLineWidthPercentage()); GraphicsEngineDataOpenGL::draw(&primitive); } glPopMatrix(); BrainOpenGL::testForOpenGLError("At end of " "FtglFontTextRenderer::drawTextAtViewportCoordinatesInternal " "while drawing text: " + annotationText.getText()); restoreStateOfOpenGL(); } /** * Draw underline using the given coordinates. * * @param lineStartX * X start of underline * @param lineEndX * X end of underline * @param lineY * Y of underline * @param lineZ * Z of underline * @param underlineThickness * Thickness of underline * @param foregroundRGBA * Color for drawing underline. */ void FtglFontTextRenderer::drawUnderline(const double lineStartX, const double lineEndX, const double lineY, const double lineZ, const double underlineThickness, uint8_t foregroundRgba[4]) { /* * Need to enable anti-aliasing for smooth lines */ glPushAttrib(GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT); glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); std::vector underlineCoords; underlineCoords.insert(underlineCoords.end(), lineStartX); underlineCoords.insert(underlineCoords.end(), lineY); underlineCoords.insert(underlineCoords.end(), lineZ); underlineCoords.insert(underlineCoords.end(), lineEndX); underlineCoords.insert(underlineCoords.end(), lineY); underlineCoords.insert(underlineCoords.end(), lineZ); GraphicsShape::drawLinesByteColor(underlineCoords, foregroundRgba, GraphicsPrimitive::LineWidthType::PIXELS, underlineThickness); glPopAttrib(); } /** * Draw outline using the given coordinates. * * @param minX * X start of outline * @param maxX * X end of outline * @param minY * Y start of outline * @param maxY * Y end of outline * @param z * Z of outline * @param outlineThickness * Thickness of outline * @param foregroundRGBA * Color for drawing outline. */ void FtglFontTextRenderer::drawOutline(const double minX, const double maxX, const double minY, const double maxY, const double z, const double outlineThickness, uint8_t foregroundRgba[4]) { /* * Need to enable anti-aliasing for smooth lines */ glPushAttrib(GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT); glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); float bottomLeft[3] = { (float)minX, (float)minY, (float)z }; float bottomRight[3] = { (float)maxX, (float)minY, (float)z }; float topRight[3] = { (float)maxX, (float)maxY, (float)z }; float topLeft[3] = { (float)minX, (float)maxY, (float)z }; MathFunctions::expandBox(bottomLeft, bottomRight, topRight, topLeft, outlineThickness, outlineThickness); GraphicsShape::drawBoxOutlineByteColor(bottomLeft, bottomRight, topRight, topLeft, foregroundRgba, GraphicsPrimitive::LineWidthType::PIXELS, outlineThickness); glPopAttrib(); } /** * Draw an outline for 3D using the given coordinates. * * @param bottomLeft * Bottom left corner of annotation. * @param bottomRight * Bottom right corner of annotation. * @param topRight * Top right corner of annotation. * @param topLeft * Top left corner of annotation. * @param outlineThickness * Thickness of outline * @param foregroundRGBA * Color for drawing outline. */ void FtglFontTextRenderer::drawOutline3D(float bottomLeft[3], float bottomRight[3], float topRight[3], float topLeft[3], const double outlineThickness, uint8_t foregroundRgba[4]) { /* * Need to enable anti-aliasing for smooth lines */ glPushAttrib(GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT); glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); GraphicsShape::drawBoxOutlineByteColor(bottomLeft, bottomRight, topRight, topLeft, foregroundRgba, GraphicsPrimitive::LineWidthType::PIXELS, outlineThickness); glPopAttrib(); } /** * Draw annnotation text at the given viewport coordinates using * the the annotations attributes for the style of text. * * Depth testing is DISABLED when drawing text with this method. * * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param annotationText * Annotation text and attributes. */ void FtglFontTextRenderer::drawTextAtViewportCoords(const double viewportX, const double viewportY, const AnnotationText& annotationText, const DrawingFlags& flags) { setViewportHeight(); drawTextAtViewportCoordsInternal(DEPTH_TEST_NO, viewportX, viewportY, 0.0, annotationText, flags); } /** * Draw annnotation text at the given viewport coordinates using * the the annotations attributes for the style of text. * * Depth testing is ENABLED when drawing text with this method. * * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. * @param annotationText * Annotation text and attributes. */ void FtglFontTextRenderer::drawTextAtViewportCoords(const double viewportX, const double viewportY, const double viewportZ, const AnnotationText& annotationText, const DrawingFlags& flags) { setViewportHeight(); drawTextAtViewportCoordsInternal(DEPTH_TEST_YES, viewportX, viewportY, viewportZ, annotationText, flags); } /** * Draw annnotation text at the given viewport coordinates using * the the annotations attributes for the style of text and the * depth testing method. * * @param depthTesting * Type of depth testing when drawing text. * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. * @param annotationText * Annotation text and attributes. */ void FtglFontTextRenderer::drawTextAtViewportCoordsInternal(const DepthTestEnum depthTesting, const double viewportX, const double viewportY, const double viewportZ, const AnnotationText& annotationText, const DrawingFlags& flags) { if (annotationText.getText().isEmpty()) { return; } FTFont* font = getFont(annotationText, FtglFontTypeEnum::TEXTURE, false); if ( ! font) { return; } m_depthTestingStatus = depthTesting; if (annotationText.getLineWidthPercentage() <= 0.0f) { annotationText.convertObsoleteLineWidthPixelsToPercentageWidth(m_viewportHeight); } const double lineThicknessForViewportHeight = getLineWidthFromPercentageHeight(annotationText.getLineWidthPercentage()); TextStringGroup tsg(annotationText, flags, font, viewportX, viewportY, viewportZ, annotationText.getRotationAngle(), lineThicknessForViewportHeight); /* tsg.print(); */ drawTextAtViewportCoordinatesInternal(annotationText, tsg); } /** * Get the bounds of text (in pixels) using the given text * attributes. A margin is included around the text. * * See http://ftgl.sourceforge.net/docs/html/metrics.png * * @param annotationText * Text that is to be drawn. * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. * @param viewportWidth * Width of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param bottomLeftOut * The bottom left corner of the text bounds. * @param bottomRightOut * The bottom right corner of the text bounds. * @param topRightOut * The top right corner of the text bounds. * @param topLeftOut * The top left corner of the text bounds. */ void FtglFontTextRenderer::getBoundsForTextAtViewportCoords(const AnnotationText& annotationText, const DrawingFlags& flags, const double viewportX, const double viewportY, const double viewportZ, const double viewportWidth, const double viewportHeight, double bottomLeftOut[3], double bottomRightOut[3], double topRightOut[3], double topLeftOut[3]) { setViewportHeight(); m_viewportWidth = viewportWidth; m_viewportHeight = viewportHeight; FTFont* font = getFont(annotationText, FtglFontTypeEnum::TEXTURE, false); if ( ! font) { return; } BrainOpenGL::testForOpenGLError("At begininng of FtglFontTextRenderer::getBoundsForTextAtViewportCoords() while " "drawing text " + annotationText.getText()); if (annotationText.getLineWidthPercentage() <= 0.0f) { annotationText.convertObsoleteLineWidthPixelsToPercentageWidth(m_viewportHeight); } double lineThicknessForViewportHeight = getLineWidthFromPercentageHeight(annotationText.getLineWidthPercentage()); TextStringGroup textStringGroup(annotationText, flags, font, viewportX, viewportY, viewportZ, annotationText.getRotationAngle(), lineThicknessForViewportHeight); double rotationPointXYZ[3]; textStringGroup.getViewportBounds(s_textMarginSize, bottomLeftOut, bottomRightOut, topRightOut, topLeftOut, rotationPointXYZ); std::unique_ptr openglError = GraphicsUtilitiesOpenGL::getOpenGLError(); if (openglError) { AString sizeMessage; sizeMessage.appendWithNewLine("At end of FtglFontTextRenderer::getBoundsForTextAtViewportCoords()."); sizeMessage.appendWithNewLine(" Error may be caused by font size that is too small."); sizeMessage.appendWithNewLine(" Error may also occur with particular characters in a font."); sizeMessage.appendWithNewLine(" Text that caused error: \"" + annotationText.getText() + "\""); switch (annotationText.getFontSizeType()) { case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT: { const float percentSize = annotationText.getFontPercentViewportSize(); const float fontHeight = (percentSize / 100.0f) * viewportHeight; sizeMessage.appendWithNewLine(" Percent of viewport height=" + AString::number(percentSize, 'f', 2) + "%, viewport height=" + AString::number(viewportHeight) + " approximage font height=" + AString::number(fontHeight, 'f', 2)); } break; case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH: { const float percentSize = annotationText.getFontPercentViewportSize(); const float fontHeight = (percentSize / 100.0f) * viewportWidth; sizeMessage.appendWithNewLine(" Percent of viewport width=" + AString::number(percentSize, 'f', 2) + "%, viewport width=" + AString::number(viewportWidth) + " approximage font height=" + AString::number(fontHeight, 'f', 2)); } break; case AnnotationTextFontSizeTypeEnum::POINTS: sizeMessage.appendWithNewLine(" Font Size=" + AnnotationTextFontNameEnum::toGuiName(annotationText.getFont())); break; } sizeMessage.appendWithNewLine(openglError->getVerboseDescription()); CaretLogWarning(sizeMessage); } } /** * Get the bounds of text (in pixels) using the given text * attributes. NO MARGIN is included around the text. * * See http://ftgl.sourceforge.net/docs/html/metrics.png * * @param annotationText * Text that is to be drawn. * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. * @param viewportWidth * Width of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param bottomLeftOut * The bottom left corner of the text bounds. * @param bottomRightOut * The bottom right corner of the text bounds. * @param topRightOut * The top right corner of the text bounds. * @param topLeftOut * The top left corner of the text bounds. */ void FtglFontTextRenderer::getBoundsWithoutMarginForTextAtViewportCoords(const AnnotationText& annotationText, const DrawingFlags& flags, const double viewportX, const double viewportY, const double viewportZ, const double viewportWidth, const double viewportHeight, double bottomLeftOut[3], double bottomRightOut[3], double topRightOut[3], double topLeftOut[3]) { setViewportHeight(); m_viewportWidth = viewportWidth; m_viewportHeight = viewportHeight; FTFont* font = getFont(annotationText, FtglFontTypeEnum::TEXTURE, false); if ( ! font) { return; } BrainOpenGL::testForOpenGLError("At begininng of FtglFontTextRenderer::getBoundsForTextAtViewportCoords() while " "drawing text " + annotationText.getText()); if (annotationText.getLineWidthPercentage() <= 0.0f) { annotationText.convertObsoleteLineWidthPixelsToPercentageWidth(m_viewportHeight); } double lineThicknessForViewportHeight = getLineWidthFromPercentageHeight(annotationText.getLineWidthPercentage()); TextStringGroup textStringGroup(annotationText, flags, font, viewportX, viewportY, viewportZ, annotationText.getRotationAngle(), lineThicknessForViewportHeight); double rotationPointXYZ[3]; const double noMargin(0.0); textStringGroup.getViewportBounds(noMargin, bottomLeftOut, bottomRightOut, topRightOut, topLeftOut, rotationPointXYZ); std::unique_ptr openglError = GraphicsUtilitiesOpenGL::getOpenGLError(); if (openglError) { AString sizeMessage; sizeMessage.appendWithNewLine("At end of FtglFontTextRenderer::getBoundsForTextAtViewportCoords()."); sizeMessage.appendWithNewLine(" Error may be caused by font size that is too small."); sizeMessage.appendWithNewLine(" Error may also occur with particular characters in a font."); sizeMessage.appendWithNewLine(" Text that caused error: \"" + annotationText.getText() + "\""); switch (annotationText.getFontSizeType()) { case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT: { const float percentSize = annotationText.getFontPercentViewportSize(); const float fontHeight = (percentSize / 100.0f) * viewportHeight; sizeMessage.appendWithNewLine(" Percent of viewport height=" + AString::number(percentSize, 'f', 2) + "%, viewport height=" + AString::number(viewportHeight) + " approximage font height=" + AString::number(fontHeight, 'f', 2)); } break; case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH: { const float percentSize = annotationText.getFontPercentViewportSize(); const float fontHeight = (percentSize / 100.0f) * viewportWidth; sizeMessage.appendWithNewLine(" Percent of viewport width=" + AString::number(percentSize, 'f', 2) + "%, viewport width=" + AString::number(viewportWidth) + " approximage font height=" + AString::number(fontHeight, 'f', 2)); } break; case AnnotationTextFontSizeTypeEnum::POINTS: sizeMessage.appendWithNewLine(" Font Size=" + AnnotationTextFontNameEnum::toGuiName(annotationText.getFont())); break; } sizeMessage.appendWithNewLine(openglError->getVerboseDescription()); CaretLogWarning(sizeMessage); } } /** * Apply the background coloring by drawing a rectangle in the background * color that encloses the text. If the background color is * invalid (alpha => 0), no action is taken. * * @param annotationText * Annotation Text that is to be drawn. * @param bottomLeftOut * The bottom left corner of the text bounds. * @param bottomRightOut * The bottom right corner of the text bounds. * @param topRightOut * The top right corner of the text bounds. * @param topLeftOut * The top left corner of the text bounds. */ void FtglFontTextRenderer::applyBackgroundColoring(const TextStringGroup& textStringGroup) { double bottomLeft[3], bottomRight[3], topRight[3], topLeft[3], rotationPointXYZ[3]; textStringGroup.getViewportBounds(s_textMarginSize, bottomLeft, bottomRight, topRight, topLeft, rotationPointXYZ); float backgroundColor[4]; textStringGroup.m_annotationText.getBackgroundColorRGBA(backgroundColor); if (backgroundColor[3] > 0.0) { // const AString bg("Background for \"" + annotationText.getText() + ": BL=" // + AString::fromNumbers(bottomLeftOut, 3, ",") + " BR=" // + AString::fromNumbers(bottomRightOut, 3, ",") + " TR=" // + AString::fromNumbers(topRightOut, 3, ",") + " TL=" // + AString::fromNumbers(topLeftOut, 3, ",")); // std::cout << qPrintable(bg) << std::endl; glColor4fv(backgroundColor); glBegin(GL_TRIANGLE_STRIP); glVertex3dv(bottomLeft); glVertex3dv(bottomRight); glVertex3dv(topLeft); glVertex3dv(topRight); glEnd(); } } /** * Apply the foreground color. * * @param annotationText * Annotation Text that is to be drawn. */ void FtglFontTextRenderer::applyTextColoring(const AnnotationText& annotationText) { float textColor[4]; annotationText.getTextColorRGBA(textColor); glColor4fv(textColor); } /** * Set the height of the viewport. This method must be called * at the beginning of all public methods. */ void FtglFontTextRenderer::setViewportHeight() { GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); m_viewportWidth = viewport[2]; m_viewportHeight = viewport[3]; } /** * Get the estimated width and height of text (in pixels) using the given text * attributes. * * See http://ftgl.sourceforge.net/docs/html/metrics.png * * @param annotationText * Text for width and height estimation. * @param viewportWidth * Width of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param widthOut * Estimated width of text. * @param heightOut * Estimated height of text. */ void FtglFontTextRenderer::getTextWidthHeightInPixels(const AnnotationText& annotationText, const DrawingFlags& flags, const double viewportWidth, const double viewportHeight, double& widthOut, double& heightOut) { setViewportHeight(); m_viewportWidth = viewportWidth; m_viewportHeight = viewportHeight; double bottomLeft[3], bottomRight[3], topRight[3], topLeft[3]; if (annotationText.getRotationAngle() != 0.0) { /* * Any rotation must be removed as the rotation is applied to the viewport postions. * For example, if the text is rotated -90 degrees, the top-right and top-left will * be on the left and bottom-right and bottom-left will be on the right */ std::unique_ptr annotation = std::unique_ptr(annotationText.clone()); AnnotationText* textCopy = dynamic_cast(annotation.get()); CaretAssert(textCopy); textCopy->setRotationAngle(0.0); getBoundsForTextAtViewportCoords(*textCopy, flags, 0.0, 0.0, 0.0, viewportWidth, viewportHeight, bottomLeft, bottomRight, topRight, topLeft); } else { getBoundsForTextAtViewportCoords(annotationText, flags, 0.0, 0.0, 0.0, viewportWidth, viewportHeight, bottomLeft, bottomRight, topRight, topLeft); } widthOut = MathFunctions::distance3D(bottomLeft, bottomRight); heightOut = MathFunctions::distance3D(topLeft, bottomLeft); } /** * Draw annnotation text at the given model coordinates using * the the annotations attributes for the style of text. * Text is drawn so that is in the plane of the screen (faces user) * * Depth testing is ENABLED when drawing text with this method. * * @param modelX * Model X-coordinate. * @param modelY * Model Y-coordinate. * @param modelZ * Model Z-coordinate. * @param annotationText * Annotation text and attributes. * @param flags * Drawing flags. */ void FtglFontTextRenderer::drawTextAtModelCoordsFacingUser(const double modelX, const double modelY, const double modelZ, const AnnotationText& annotationText, const DrawingFlags& flags) { setViewportHeight(); m_depthTestingStatus = DEPTH_TEST_YES; GLdouble modelMatrix[16]; GLdouble projectionMatrix[16]; GLint viewport[4]; glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix); glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix); glGetIntegerv(GL_VIEWPORT, viewport); /* * Project model coordinate to a window coordinate. */ GLdouble windowX, windowY, windowZ; if (gluProject(modelX, modelY, modelZ, modelMatrix, projectionMatrix, viewport, &windowX, &windowY, &windowZ) == GL_TRUE) { /* * From OpenGL Programming Guide 3rd Ed, p 133: * * If the near value is 1.0 and the far value is 3.0, * objects must have z-coordinates between -1.0 and -3.0 in order to be visible. * So, negative the Z-value to be negative. */ windowZ = -windowZ; /* * Convert window coordinate to viewport coordinatde */ const double x = windowX - viewport[0]; const double y = windowY - viewport[1]; drawTextAtViewportCoordsInternal(DEPTH_TEST_YES, x, y, windowZ, annotationText, flags); } else { CaretLogSevere("gluProject() failed for drawing text at model coordinates."); } } /** * Get the bounds of text drawn in model space using the current model transformations. * * @param annotationText * Text that is to be drawn. * @param modelSpaceScaling * Scaling in the model space. * @param heightOrWidthForPercentageSizeText * Size of region used when converting percentage size to a fixed size * @param flags * Drawing flags. * @param bottomLeftOut * The bottom left corner of the text bounds. * @param bottomRightOut * The bottom right corner of the text bounds. * @param topRightOut * The top right corner of the text bounds. * @param topLeftOut * The top left corner of the text bounds. * @param underlineStartOut * Starting coordinate for drawing text underline. * @param underlineEndOut * Ending coordinate for drawing text underline. */ void FtglFontTextRenderer::getBoundsForTextInModelSpace(const AnnotationText& annotationText, const float /*modelSpaceScaling*/, const float heightOrWidthForPercentageSizeText, const DrawingFlags& flags, double bottomLeftOut[3], double bottomRightOut[3], double topRightOut[3], double topLeftOut[3], double underlineStartOut[3], double underlineEndOut[3]) { std::fill(bottomLeftOut, bottomLeftOut + 3, 0.0f); std::fill(bottomRightOut, bottomRightOut + 3, 0.0f); std::fill(topRightOut, topRightOut + 3, 0.0f); std::fill(topLeftOut, topLeftOut + 3, 0.0f); FTFont* font = getFont(annotationText, FtglFontTypeEnum::POLYGON, heightOrWidthForPercentageSizeText, false); if (! font) { return; } const float lineThicknessForViewportHeight(getLineThicknessPixelsInModelSpace(annotationText.getLineWidthPercentage(), heightOrWidthForPercentageSizeText, 0.0)); TextStringGroup textStringGroup(annotationText, flags, font, 0.0, 0.0, 0.0, annotationText.getRotationAngle(), lineThicknessForViewportHeight); double rotationPointXYZ[3]; textStringGroup.getViewportBounds(s_textMarginSize, bottomLeftOut, bottomRightOut, topRightOut, topLeftOut, rotationPointXYZ); underlineStartOut[0] = bottomLeftOut[0]; underlineStartOut[1] = bottomLeftOut[1]; underlineStartOut[2] = bottomLeftOut[2]; underlineEndOut[0] = bottomRightOut[0]; underlineEndOut[1] = bottomRightOut[1]; underlineEndOut[2] = bottomRightOut[2]; } /** * Get the line thickness for model space. * * @param lineWidthPercentage * The line width percentage. * @param heightOrWidthForPercentageSizeText * The height/width of region (surface) for percentage size text. * @param modelSpaceScaling * Scaling in model space. */ float FtglFontTextRenderer::getLineThicknessPixelsInModelSpace(const float lineWidthPercentage, const float heightOrWidthForPercentageSizeText, const float modelSpaceScaling) const { float lineThicknessPercentage = std::max(0.01f, (lineWidthPercentage / 100.f)); float lineThicknessPixels = (heightOrWidthForPercentageSizeText * lineThicknessPercentage); lineThicknessPixels *= modelSpaceScaling; return lineThicknessPixels; } /** * Draw text in model space using the current model transformations. * * Depth testing is ENABLED when drawing text with this method. * * @param annotationText * Annotation text and attributes. * @param modelSpaceScaling * Scaling in the model space. * @param heightOrWidthForPercentageSizeText * If positive, use it to override width/height of viewport. * @param normalVector * Normal vector of text. * @param flags * Drawing flags. */ void FtglFontTextRenderer::drawTextInModelSpace(const AnnotationText& annotationText, const float /*modelSpaceScaling*/, const float heightOrWidthForPercentageSizeText, const float* /*normalVector[3]*/, const DrawingFlags& flags) { FTFont* font = getFont(annotationText, FtglFontTypeEnum::POLYGON, heightOrWidthForPercentageSizeText, false); if (! font) { return; } const bool drawCrossFlag = false; if (drawCrossFlag) { const float a(100.0f); glLineWidth(3.0); glBegin(GL_LINES); glVertex3f(-a, 0, 0); glVertex3f( a, 0, 0); glVertex3f(0, -a, 0); glVertex3f(0, a, 0); glVertex3f(0, 0,-a); glVertex3f(0, 0, a); glEnd(); } AString text = (flags.isDrawSubstitutedText() ? annotationText.getTextWithSubstitutionsApplied() : annotationText.getText()); if (text.isEmpty()) { return; } const float lineThicknessForViewportHeight(getLineThicknessPixelsInModelSpace(annotationText.getLineWidthPercentage(), heightOrWidthForPercentageSizeText, 0.0)); TextStringGroup tsg(annotationText, flags, font, 0.0, 0.0, 0.0, annotationText.getRotationAngle(), lineThicknessForViewportHeight); drawTextInModelSpaceInternal(annotationText, tsg, heightOrWidthForPercentageSizeText); } /** * Draw the text piceces at their assigned model space. * * @param annotationText * Annotation text and attributes. * @param textStringGroup * Text broken up into characters with positions * @param heightOrWidthForPercentageSizeText * If positive, use it to override width/height of viewport. * */ void FtglFontTextRenderer::drawTextInModelSpaceInternal(const AnnotationText& annotationText, const TextStringGroup& textStringGroup, const float heightOrWidthForPercentageSizeText) { FTFont* font = getFont(annotationText, FtglFontTypeEnum::POLYGON, heightOrWidthForPercentageSizeText, false); if (! font) { return; } if (annotationText.getText().isEmpty()) { return; } saveStateOfOpenGL(); BrainOpenGL::testForOpenGLError("At beginning of " "FtglFontTextRenderer::drawTextInModelSpaceInternal " "while drawing text: " + annotationText.getText()); glEnable(GL_DEPTH_TEST); const double underlineOffsetY = (textStringGroup.m_underlineThickness / 2.0); double bottomLeft[3], bottomRight[3], topRight[3], topLeft[3], rotationPointXYZ[3]; textStringGroup.getViewportBounds(s_textMarginSize, bottomLeft, bottomRight, topRight, topLeft, rotationPointXYZ); rotationPointXYZ[2] = 0.0; glPushMatrix(); applyBackgroundColoring(textStringGroup); applyTextColoring(annotationText); const float rotationAngle = annotationText.getRotationAngle(); glTranslated(rotationPointXYZ[0], rotationPointXYZ[1], rotationPointXYZ[2]); glRotated(rotationAngle, 0.0, 0.0, -1.0); glPolygonOffset(-1.0, -1.0); glEnable(GL_POLYGON_OFFSET_FILL); for (std::vector::const_iterator iter = textStringGroup.m_textStrings.begin(); iter != textStringGroup.m_textStrings.end(); iter++) { const TextString* ts = *iter; double x = ts->m_viewportX; double y = ts->m_viewportY; double z = ts->m_viewportZ; applyTextColoring(annotationText); for (std::vector::const_iterator charIter = ts->m_characters.begin(); charIter != ts->m_characters.end(); charIter++) { const TextCharacter* tc = *charIter; x += tc->m_offsetX; y += tc->m_offsetY; z += tc->m_offsetZ; const double offsetX = x - rotationPointXYZ[0]; const double offsetY = y - rotationPointXYZ[1]; const double offsetZ = z - rotationPointXYZ[2]; glPushMatrix(); glTranslated(offsetX, offsetY, offsetZ); font->Render(&tc->m_character, 1); glPopMatrix(); } if (ts->m_underlineThickness > 0.0) { glPushMatrix(); glTranslated(ts->m_viewportX - rotationPointXYZ[0], ts->m_viewportY - rotationPointXYZ[1], 0.0); const double underlineY = ts->m_stringGlyphsMinY + underlineOffsetY; uint8_t foregroundRgba[4]; annotationText.getTextColorRGBA(foregroundRgba); drawUnderline(ts->m_stringGlyphsMinX, ts->m_stringGlyphsMaxX, underlineY, z, ts->m_underlineThickness, foregroundRgba); glPopMatrix(); } } if (annotationText.getLineColor() != CaretColorEnum::NONE) { glPushMatrix(); uint8_t foregroundRgba[4]; annotationText.getLineColorRGBA(foregroundRgba); const float thickness = ((annotationText.getLineWidthPercentage() / 100.0) * heightOrWidthForPercentageSizeText); GraphicsShape::drawOutlineRectangleVerticesAtInside(bottomLeft, bottomRight, topRight, topLeft, thickness, foregroundRgba); glPopMatrix(); } glDisable(GL_POLYGON_OFFSET_FILL); glPopMatrix(); BrainOpenGL::testForOpenGLError("At end of " "FtglFontTextRenderer::drawTextInModelSpaceInternal " "while drawing text: " + annotationText.getText()); restoreStateOfOpenGL(); } /** * Save the state of OpenGL. * Copied from Qt's qgl.cpp, qt_save_gl_state(). */ void FtglFontTextRenderer::saveStateOfOpenGL() { glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); glPushAttrib(GL_ALL_ATTRIB_BITS); glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glShadeModel(GL_FLAT); glDisable(GL_CULL_FACE); glDisable(GL_LIGHTING); glDisable(GL_STENCIL_TEST); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } /** * Restore the state of OpenGL. * Copied from Qt's qgl.cpp, qt_restore_gl_state(). */ void FtglFontTextRenderer::restoreStateOfOpenGL() { glMatrixMode(GL_TEXTURE); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glPopAttrib(); glPopClientAttrib(); } /** * Constructs invalid font data. */ FtglFontTextRenderer::FontData::FontData() { m_valid = false; m_font = NULL; } /** * Constructs a font with the given attributes. * Called should verify that this instance is valid (construction was successful). * * @param annotationText * Annotation Text that is to be drawn. * @param viewportWidth * Width of the viewport in which text is drawn. * @param viewportHeight * Height of the viewport in which text is drawn. */ FtglFontTextRenderer::FontData::FontData(const AnnotationText& annotationText, const FtglFontTypeEnum ftglFontType, const int32_t viewportWidth, const int32_t viewportHeight) : m_ftglFontType(ftglFontType) { m_valid = false; m_font = NULL; const AnnotationTextFontNameEnum::Enum fontName = annotationText.getFont(); AString fontFileName = AnnotationTextFontNameEnum::getResourceFontFileName(fontName); if (annotationText.isBoldStyleEnabled() && annotationText.isItalicStyleEnabled()) { fontFileName = AnnotationTextFontNameEnum::getResourceBoldItalicFontFileName(fontName); } else if (annotationText.isBoldStyleEnabled()) { fontFileName = AnnotationTextFontNameEnum::getResourceBoldFontFileName(fontName); } else if (annotationText.isItalicStyleEnabled()) { fontFileName = AnnotationTextFontNameEnum::getResourceItalicFontFileName(fontName); } CaretAssert( ! fontFileName.isEmpty()); /* * Open the font file in the Workbench resources */ QFile file(fontFileName); if (file.open(QFile::ReadOnly)) { /* * Read all data which MUST remain valid until the FTGL * font is no longer used. */ m_fontData = file.readAll(); const size_t numBytes = m_fontData.size(); if (numBytes > 0) { /* * Create the FTGL font. */ switch (m_ftglFontType) { case FtglFontTypeEnum::POLYGON: m_font = new FTGLPolygonFont((const unsigned char*)m_fontData.data(), numBytes); break; case FtglFontTypeEnum::TEXTURE: m_font = new FTTextureFont((const unsigned char*)m_fontData.data(), numBytes); break; } CaretAssert(m_font); /* * Font created successfully ? */ if ( ! m_font->Error()) { /* * Font size successful ? */ const int32_t fontSizePoints = annotationText.getFontSizeForDrawing(viewportWidth, viewportHeight); if (m_font->FaceSize(fontSizePoints)) { m_valid = true; CaretLogFine("Created font size=" + AString::number(fontSizePoints) + " from font file " + file.fileName()); } else { CaretLogSevere("Error creating font size " + AString::number(fontSizePoints) + " from font file " + file.fileName()); } } else { CaretLogSevere("Error creating FTGL Font from " + file.fileName() + ". Error code from FreeType is " + AString::number(m_font->Error())); } } else { CaretLogSevere("Error reading data for FTGL Font from " + file.fileName() + " error: " + file.errorString()); } } else { CaretLogSevere("Unable to open FTGL Font File " + file.fileName() + " error: " + file.errorString()); } if ( ! m_valid) { m_fontData.clear(); if (m_font != NULL) { delete m_font; m_font = NULL; } } } /** * Destructs font data. */ FtglFontTextRenderer::FontData::~FontData() { if (m_font != NULL) { delete m_font; m_font = NULL; } } /** * @return Name of the text renderer. */ AString FtglFontTextRenderer::getName() const { return "FTGL Text Renderer"; } /* ================================================================================== */ /** * Constructor. * * @param character * The character for this instance. * @param horizontalAdvance * The advance used when drawing the string in a horizontal orientation. * @param glyphMinX * Minimum X relative to the character's origin form FTGL/Freetype. * @param glyphMaxX * Maximum X relative to the character's origin form FTGL/Freetype. * @param glyphMinY * Minimum Y relative to the character's origin form FTGL/Freetype. * @param glyphMaxY * Maximum Y relative to the character's origin form FTGL/Freetype. */ FtglFontTextRenderer::TextCharacter::TextCharacter(const wchar_t& character, const double horizontalAdvance, const double glyphMinX, const double glyphMaxX, const double glyphMinY, const double glyphMaxY) : m_character(character), m_horizontalAdvance(horizontalAdvance), m_glyphMinX(glyphMinX), m_glyphMaxX(glyphMaxX), m_glyphMinY(glyphMinY), m_glyphMaxY(glyphMaxY), m_offsetX(0.0), m_offsetY(0.0), m_offsetZ(0.0) { } /** * Destructor. */ FtglFontTextRenderer::TextCharacter::~TextCharacter() { } /** * Print information about this string using the given offset. * * @param offsetString * Offset prepended to each line that is printed. */ void FtglFontTextRenderer::TextCharacter::print(const AString& offsetString) { const QString msg(offsetString + "Char: " + QString::fromWCharArray(&m_character, 1) + " horizAdvance=" + AString::number(m_horizontalAdvance) + " minX=" + AString::number(m_glyphMinX) + " maxX=" + AString::number(m_glyphMaxX) + " minY=" + AString::number(m_glyphMinY) + " maxY=" + AString::number(m_glyphMaxY)); const QString msg2(offsetString + " Offset x=" + AString::number(m_offsetX) + " y=" + AString::number(m_offsetY) + " z=" + AString::number(m_offsetZ)); std::cout << qPrintable(msg) << std::endl; std::cout << qPrintable(msg2) << std::endl; } /* ================================================================================== */ /** * Constructor * * @param textString * The text string. * @param textDrawingSpace * Text drawn in space. * @param orientation * Orientation of the text string. * @param underlineThickness * Thickness of underline for the text. * @param outlineThickness * Thickness of outline for the text. * @param font * Font for drawing the text string. */ FtglFontTextRenderer::TextString::TextString(const QString& textString, const TextDrawingSpace textDrawingSpace, const AnnotationTextOrientationEnum::Enum orientation, const double underlineThickness, const double outlineThickness, FTFont* font) : m_textDrawingSpace(textDrawingSpace), m_underlineThickness(underlineThickness), m_outlineThickness(outlineThickness), m_viewportX(0.0), m_viewportY(0.0), m_viewportZ(0.0), m_stringGlyphsMinX(0.0), m_stringGlyphsMaxX(0.0), m_stringGlyphsMinY(0.0), m_stringGlyphsMaxY(0.0) { /* * Split the string into individual characters. */ const int32_t numChars = textString.length(); for (int32_t i = 0; i < numChars; i++) { const std::wstring theWideCharStr = textString.mid(i, 2).toStdWString(); const wchar_t theWideChar = theWideCharStr.at(0); FTBBox bbox = font->BBox(theWideCharStr.c_str(), 1); /* * A space character has a valid horizontal advance. * BUT, the bounds of the space character are all zero and since * the bounds are used for stacked text vertical advance we need * some value so use the bounds for a lowercase 'o'. * * The L indicates a wide character (wchar_t) */ if ((theWideChar == L' ') && (orientation == AnnotationTextOrientationEnum::STACKED)) { bbox = font->BBox("o"); } double advanceValue = 0.0; if (i < (numChars - 1)) { /* * We need to use both the currrent AND the next character * when calculating the advance for it to be correct. * In some instances the bounding boxes of two adjacent * characters will overlap. An example is the character * sequence 'AV' especially with a 'serif' font that has * small horizontal lines attached to the bottom legs of * the 'A' and the top of the 'V'. * * See https://en.wikipedia.org/wiki/Kerning * and https://en.wikipedia.org/wiki/Serif */ advanceValue = font->Advance(theWideCharStr.c_str(), 1); } TextCharacter* tc = new TextCharacter(theWideChar, advanceValue, bbox.Lower().Xf(), bbox.Upper().Xf(), bbox.Lower().Yf(), bbox.Upper().Yf()); m_characters.push_back(tc); } /* * Set the offset for each character in this text string */ initializeTextCharacterOffsets(orientation); /* * Set the bounds of the characters in this string. */ setGlyphBounds(); } /** * Destructor. */ FtglFontTextRenderer::TextString::~TextString() { for (std::vector::iterator iter = m_characters.begin(); iter != m_characters.end(); iter++) { delete *iter; } m_characters.clear(); } /** * Initialize the offset of each character from * its preceding character. * * @param orientation * Orientation of the text string. */ void FtglFontTextRenderer::TextString::initializeTextCharacterOffsets(const AnnotationTextOrientationEnum::Enum orientation) { bool stackedTextFlag = false; switch (orientation) { case AnnotationTextOrientationEnum::HORIZONTAL: break; case AnnotationTextOrientationEnum::STACKED: stackedTextFlag = true; break; } double stringMinX = std::numeric_limits::max(); double stringMaxX = -std::numeric_limits::max(); //const float verticalSpacing = s_textMarginSize * 2.0; /* * For each character, set its offset from the previous character */ const int numChars = static_cast(m_characters.size()); for (int32_t iChar = 0; iChar < numChars; iChar++) { CaretAssertVectorIndex(m_characters, iChar); TextCharacter* tc = m_characters[iChar]; double offsetX = 0.0; double offsetY = 0.0; double offsetZ = 0.0; if (iChar > 0) { CaretAssertVectorIndex(m_characters, iChar - 1); const TextCharacter* prevChar = m_characters[iChar - 1]; if (stackedTextFlag) { double offsetY1 = prevChar->m_glyphMinY; double offsetY2 = 0.0; switch (m_textDrawingSpace) { case TextDrawingSpace::MODEL: offsetY2 = prevChar->m_glyphMaxY - prevChar->m_glyphMinY; offsetY2 = -(s_modelSpaceMarginPercentage * offsetY2); break; case TextDrawingSpace::VIEWPORT: offsetY2 = -(s_textMarginSize * 2.0); break; } double offsetY3 = -tc->m_glyphMaxY; offsetY = (offsetY1 + offsetY2 + offsetY3); } else { offsetX = prevChar->m_horizontalAdvance; } } tc->m_offsetX = offsetX; tc->m_offsetY = offsetY; tc->m_offsetZ = offsetZ; stringMinX = std::min(stringMinX, tc->m_glyphMinX); stringMaxX = std::max(stringMaxX, tc->m_glyphMaxX); } /* * When drawing stacked text, the characters * need their X offset adjusted so that they * are horizontally aligned in the center of * the "column" containing the text. */ if (stackedTextFlag) { /* * X-coordinate of character in the vertical column * so that the characters are centered horizontally * in the column. */ std::vector characterColumnCoordX(numChars, 0.0); const double columnWidth = stringMaxX - stringMinX; if (columnWidth > 0.0) { for (int32_t iChar = 0; iChar < numChars; iChar++) { CaretAssertVectorIndex(m_characters, iChar); TextCharacter* tc = m_characters[iChar]; const double characterWidth = tc->m_glyphMaxX - tc->m_glyphMinX; if (characterWidth > 0.0) { const double leftAndRightPadding = columnWidth - characterWidth; const double leftPadding = leftAndRightPadding / 2.0; const double characterX = leftPadding - tc->m_glyphMinX; // std::cout << "Char " << qPrintable(tc->m_character // + ": " // + " CharMinX=" // + QString::number(tc->m_glyphMinX) // + " CharMaxX=" // + QString::number(tc->m_glyphMaxX) // + " CharWidth=" // + QString::number(characterWidth) // + " Padding=" // + QString::number(leftPadding) // + " CharacterX=" // + QString::number(characterX)) << std::endl; if (leftPadding >= -0.01) { CaretAssertVectorIndex(characterColumnCoordX, iChar); characterColumnCoordX[iChar] = characterX; } else { CaretLogSevere("Text Character (" + QString::fromWCharArray(&tc->m_character, 1) + ") has invalid left padding=" + QString::number(leftPadding)); } } } /* * Set the character offsets. * SECOND and additional characters are offset from * the immediately previous character */ for (int32_t iChar = 0; iChar < numChars; iChar++) { CaretAssertVectorIndex(m_characters, iChar); TextCharacter* tc = m_characters[iChar]; if (iChar >= 1) { CaretAssertVectorIndex(m_characters, iChar - 1); CaretAssertVectorIndex(m_characters, iChar); tc->m_offsetX = characterColumnCoordX[iChar] - characterColumnCoordX[iChar - 1]; } else { CaretAssertVectorIndex(m_characters, iChar); tc->m_offsetX = characterColumnCoordX[iChar]; } } } } } /** * Print information about this string using the given offset. * * @param offsetString * Offset prepended to each line that is printed. */ void FtglFontTextRenderer::TextString::print(const AString& offsetString) { QString msg(offsetString + "Text String Bounds: minx=" + QString::number(m_stringGlyphsMinX) + " maxx=" + QString::number(m_stringGlyphsMaxX) + " miny=" + QString::number(m_stringGlyphsMinY) + " maxy=" + QString::number(m_stringGlyphsMaxY)); std::cout << qPrintable(msg) << std::endl; const QString doubleOffset(offsetString + offsetString); for (std::vector::iterator iter = m_characters.begin(); iter != m_characters.end(); iter++) { TextCharacter* tc = *iter; tc->print(doubleOffset); } } /** * Set the bounds of the glyphs for the text string. * The origin is at the first character. */ void FtglFontTextRenderer::TextString::setGlyphBounds() { m_stringGlyphsMinX = std::numeric_limits::max(); m_stringGlyphsMaxX = -std::numeric_limits::max(); m_stringGlyphsMinY = std::numeric_limits::max(); m_stringGlyphsMaxY = -std::numeric_limits::max(); double x = 0.0; double y = 0.0; for (std::vector::iterator iter = m_characters.begin(); iter != m_characters.end(); iter++) { TextCharacter* tc = *iter; x += tc->m_offsetX; y += tc->m_offsetY; const double left = x + tc->m_glyphMinX; const double right = x + tc->m_glyphMaxX; const double bottom = y + tc->m_glyphMinY - m_underlineThickness; const double top = y + tc->m_glyphMaxY; m_stringGlyphsMinX = std::min(m_stringGlyphsMinX, left); m_stringGlyphsMaxX = std::max(m_stringGlyphsMaxX, right); m_stringGlyphsMinY = std::min(m_stringGlyphsMinY, bottom); m_stringGlyphsMaxY = std::max(m_stringGlyphsMaxY, top); } } /** * Get the bounds of the text string in viewport coordinates. * * @param viewportMinX * Viewport minimum X. * @param viewportMaxX * Viewport maximum X. * @param viewportMinY * Viewport minimum Y. * @param viewportMaxY * Viewport minimum Y. */ void FtglFontTextRenderer::TextString::getTextBoundsInViewportCoordinates(double& viewportMinX, double& viewportMaxX, double& viewportMinY, double& viewportMaxY) const { viewportMinX = m_viewportX + m_stringGlyphsMinX; viewportMaxX = m_viewportX + m_stringGlyphsMaxX; viewportMinY = m_viewportY + m_stringGlyphsMinY; viewportMaxY = m_viewportY + m_stringGlyphsMaxY; } /* ================================================================================== */ /** * Constructor for a text string group. * * @param annotationText * The text annotation. * @param font * Font used for drawing the annotation. * @param viewportX * X-coordinate in the viewport. * @param viewportY * Y-coordinate in the viewport. * @param viewportZ * Z-coordinate in the viewport. * @param rotationAngle * Rotation angle for the text. * @param lineThicknessForViewportHeight * Line thickness adjusted for viewport height. */ FtglFontTextRenderer::TextStringGroup::TextStringGroup(const AnnotationText& annotationText, const DrawingFlags& flags, FTFont* font, const double viewportX, const double viewportY, const double viewportZ, const double rotationAngle, const double lineThicknessForViewportHeight) : m_annotationText(annotationText), m_font(font), m_viewportX(viewportX), m_viewportY(viewportY), m_viewportZ(viewportZ), m_rotationAngle(rotationAngle), m_underlineThickness(0.0), m_viewportBoundsMinX(0.0), m_viewportBoundsMaxX(0.0), m_viewportBoundsMinY(0.0), m_viewportBoundsMaxY(0.0), m_textDrawingSpace(TextDrawingSpace::VIEWPORT) { CaretAssert(font); m_textDrawingSpace = TextDrawingSpace::VIEWPORT; if (m_annotationText.isInSurfaceSpaceWithTangentOffset()) { m_textDrawingSpace = TextDrawingSpace::MODEL; } if (annotationText.getText().isEmpty()) { m_viewportBoundsMinX = m_viewportX; m_viewportBoundsMaxX = m_viewportY; m_viewportBoundsMinY = m_viewportX; m_viewportBoundsMaxY = m_viewportY; return; } /* * The underline for text is scaled with the size of the font * Underline is drawn anytime thickness is greater than zero */ if (annotationText.isUnderlineStyleEnabled()) { if (annotationText.getOrientation() == AnnotationTextOrientationEnum::HORIZONTAL) { m_underlineThickness = std::max((font->FaceSize() / 14.0), 1.0); } } /* * The outline for text is scaled with the size of the font * Outline is drawn anytime thickness is greater than zero * and is drawn using the foreground color */ float outlineThickness = 0.0; if (annotationText.getLineColor() != CaretColorEnum::NONE) { outlineThickness = lineThicknessForViewportHeight; } /* * Each row (horizontal text) or column (vertical text) is * separated by a newline character */ QString textString = (flags.isDrawSubstitutedText() ? m_annotationText.getTextWithSubstitutionsApplied() : m_annotationText.getText()); QStringList textList = textString.split('\n', QString::KeepEmptyParts); const int32_t textListSize = textList.size(); for (int32_t i = 0; i < textListSize; i++) { TextString* ts = new TextString(textList.at(i), m_textDrawingSpace, annotationText.getOrientation(), m_underlineThickness, outlineThickness, font); m_textStrings.push_back(ts); } initializeTextPositions(); updateTextBounds(); applyAlignmentsToTextStrings(); /* * Alignment moves text so bounds need to be updated */ updateTextBounds(); } /** * Destructor. */ FtglFontTextRenderer::TextStringGroup::~TextStringGroup() { for (std::vector::iterator iter = m_textStrings.begin(); iter != m_textStrings.end(); iter++) { delete *iter; } m_textStrings.clear(); } /** * Get the bounds of the all text that is drawn. The * bounds is used for selection and the background color. * * @param margin * Margin added around sides * @param bottomLeftOut * Coordinate of bottom left. * @param bottomRightOut * Coordinate of bottom right. * @param topRightOut * Coordinate of top right. * @param topLeftOut * Coordinate of top left. * @param rotationPointXYZOut * Output containing rotation point for bounds. */ void FtglFontTextRenderer::TextStringGroup::getViewportBounds(const double margin, double bottomLeftOut[3], double bottomRightOut[3], double topRightOut[3], double topLeftOut[3], double rotationPointXYZOut[3]) const { bottomLeftOut[0] = m_viewportBoundsMinX; bottomLeftOut[1] = m_viewportBoundsMinY; bottomLeftOut[2] = m_viewportZ; bottomRightOut[0] = m_viewportBoundsMaxX; bottomRightOut[1] = m_viewportBoundsMinY; bottomRightOut[2] = m_viewportZ; topRightOut[0] = m_viewportBoundsMaxX; topRightOut[1] = m_viewportBoundsMaxY; topRightOut[2] = m_viewportZ; topLeftOut[0] = m_viewportBoundsMinX; topLeftOut[1] = m_viewportBoundsMaxY; topLeftOut[2] = m_viewportZ; double rotationX = m_viewportBoundsMinX; double rotationY = m_viewportBoundsMinY; double rotationZ = m_viewportZ; switch (m_annotationText.getVerticalAlignment()) { case AnnotationTextAlignVerticalEnum::BOTTOM: switch (m_annotationText.getHorizontalAlignment()) { case AnnotationTextAlignHorizontalEnum::CENTER: rotationX = (bottomLeftOut[0] + bottomRightOut[0]) / 2.0; rotationY = (bottomLeftOut[1] + bottomRightOut[1]) / 2.0; rotationZ = (bottomLeftOut[2] + bottomRightOut[2]) / 2.0; break; case AnnotationTextAlignHorizontalEnum::LEFT: rotationX = bottomLeftOut[0]; rotationY = bottomLeftOut[1]; rotationZ = bottomLeftOut[2]; break; case AnnotationTextAlignHorizontalEnum::RIGHT: rotationX = bottomRightOut[0]; rotationY = bottomRightOut[1]; rotationZ = bottomRightOut[2]; break; } break; case AnnotationTextAlignVerticalEnum::MIDDLE: switch (m_annotationText.getHorizontalAlignment()) { case AnnotationTextAlignHorizontalEnum::CENTER: rotationX = (bottomLeftOut[0] + bottomRightOut[0] + topLeftOut[0] + topRightOut[0]) / 4.0; rotationY = (bottomLeftOut[1] + bottomRightOut[1] + topLeftOut[1] + topRightOut[1]) / 4.0; rotationZ = (bottomLeftOut[2] + bottomRightOut[2] + topLeftOut[2] + topRightOut[2]) / 4.0; break; case AnnotationTextAlignHorizontalEnum::LEFT: rotationX = (bottomLeftOut[0] + topLeftOut[0]) / 2.0; rotationY = (bottomLeftOut[1] + topLeftOut[1]) / 2.0; rotationZ = (bottomLeftOut[2] + topLeftOut[2]) / 2.0; break; case AnnotationTextAlignHorizontalEnum::RIGHT: rotationX = (topRightOut[0] + bottomRightOut[0]) / 2.0; rotationY = (topRightOut[1] + bottomRightOut[1]) / 2.0; rotationZ = (topRightOut[2] + bottomRightOut[2]) / 2.0; break; } break; case AnnotationTextAlignVerticalEnum::TOP: switch (m_annotationText.getHorizontalAlignment()) { case AnnotationTextAlignHorizontalEnum::CENTER: rotationX = (topLeftOut[0] + topRightOut[0]) / 2.0; rotationY = (topLeftOut[1] + topRightOut[1]) / 2.0; rotationZ = (topLeftOut[2] + topRightOut[2]) / 2.0; break; case AnnotationTextAlignHorizontalEnum::LEFT: rotationX = topLeftOut[0]; rotationY = topLeftOut[1]; rotationZ = topLeftOut[2]; break; case AnnotationTextAlignHorizontalEnum::RIGHT: rotationX = topRightOut[0]; rotationY = topRightOut[1]; rotationZ = topRightOut[2]; break; } break; } rotationPointXYZOut[0] = rotationX; rotationPointXYZOut[1] = rotationY; rotationPointXYZOut[2] = rotationZ; Matrix4x4 matrix; matrix.translate(-rotationX, -rotationY, 0.0); matrix.rotateZ(-m_rotationAngle); matrix.translate(rotationX, rotationY, 0.0); /* * Add margin to the viewport bounds. * Margin is NOT included when rotation point is computed * as it will move the rotation point to the wrong position. */ double boundsMargin = 0.0; switch (m_textDrawingSpace) { case TextDrawingSpace::MODEL: boundsMargin = GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(margin); break; case TextDrawingSpace::VIEWPORT: boundsMargin = margin; break; } bottomLeftOut[0] -= boundsMargin; bottomLeftOut[1] -= boundsMargin; bottomRightOut[0] += boundsMargin; bottomRightOut[1] -= boundsMargin; topRightOut[0] += boundsMargin; topRightOut[1] += boundsMargin; topLeftOut[0] -= boundsMargin; topLeftOut[1] += boundsMargin; matrix.multiplyPoint3(bottomLeftOut); matrix.multiplyPoint3(bottomRightOut); matrix.multiplyPoint3(topRightOut); matrix.multiplyPoint3(topLeftOut); } /** * Begin to postion the text strings. */ void FtglFontTextRenderer::TextStringGroup::initializeTextPositions() { double x = m_viewportX; double y = m_viewportY; double z = m_viewportZ; const int32_t numStrings = static_cast(m_textStrings.size()); for (int32_t iStr = 0; iStr < numStrings; iStr++) { CaretAssertVectorIndex(m_textStrings, iStr); TextString* textString = m_textStrings[iStr]; if (iStr >= 1) { CaretAssertVectorIndex(m_textStrings, iStr - 1); TextString* prevTextString = m_textStrings[iStr - 1]; switch (m_annotationText.getOrientation()) { case AnnotationTextOrientationEnum::HORIZONTAL: { /* * Move coordinate DOWN for next ROW of text */ const double offsetY1 = prevTextString->m_stringGlyphsMinY; double offsetY2 = 0.0; switch (m_textDrawingSpace) { case TextDrawingSpace::MODEL: offsetY2 = -(prevTextString->m_stringGlyphsMaxY - prevTextString->m_stringGlyphsMinY); offsetY2 = s_modelSpaceMarginPercentage * offsetY2; break; case TextDrawingSpace::VIEWPORT: offsetY2 = -(s_textMarginSize * 2.0); break; } const double offsetY3 = -textString->m_stringGlyphsMaxY; const double offsetY4 = 0.0; const double offsetY = (offsetY1 + offsetY2 + offsetY3 + offsetY4); y += offsetY; } break; case AnnotationTextOrientationEnum::STACKED: { /* * Move coordinate RIGHT for next COLUMN of text */ const double offsetX1 = prevTextString->m_stringGlyphsMaxX; double offsetX2 = 0.0; switch (m_textDrawingSpace) { case TextDrawingSpace::MODEL: offsetX2 = (prevTextString->m_stringGlyphsMaxX - prevTextString->m_stringGlyphsMinX); offsetX2 = s_modelSpaceMarginPercentage * offsetX2; break; case TextDrawingSpace::VIEWPORT: offsetX2 = s_textMarginSize; break; } const double offsetX3 = -textString->m_stringGlyphsMinX; const double offsetX = (offsetX1 + offsetX2 + offsetX3); x += offsetX; } break; } } textString->m_viewportX = x; textString->m_viewportY = y; textString->m_viewportZ = z; } } /** * Print info about the text. */ void FtglFontTextRenderer::TextStringGroup::print() { QString msg("Text String Group: " + m_annotationText.getText()); std::cout << qPrintable(msg) << std::endl; for (std::vector::iterator iter = m_textStrings.begin(); iter != m_textStrings.end(); iter++) { TextString* ts = *iter; ts->print(" "); } std::cout << std::endl; } /** * Update the bounds (extent) of the text. */ void FtglFontTextRenderer::TextStringGroup::updateTextBounds() { m_viewportBoundsMinX = std::numeric_limits::max(); m_viewportBoundsMaxX = -std::numeric_limits::max(); m_viewportBoundsMinY = std::numeric_limits::max(); m_viewportBoundsMaxY = -std::numeric_limits::max(); double x = 0.0; double y = 0.0; for (std::vector::iterator iter = m_textStrings.begin(); iter != m_textStrings.end(); iter++) { TextString* ts = *iter; double stringMinX = 0.0; double stringMaxX = 0.0; double stringMinY = 0.0; double stringMaxY = 0.0; ts->getTextBoundsInViewportCoordinates(stringMinX, stringMaxX, stringMinY, stringMaxY); const double left = x + stringMinX; const double right = x + stringMaxX; const double bottom = y + stringMinY; const double top = y + stringMaxY; m_viewportBoundsMinX = std::min(m_viewportBoundsMinX, left); m_viewportBoundsMaxX = std::max(m_viewportBoundsMaxX, right); m_viewportBoundsMinY = std::min(m_viewportBoundsMinY, bottom); m_viewportBoundsMaxY = std::max(m_viewportBoundsMaxY, top); } } /** * Adjust the positions of the horizontal text strings so * they are aligned properly for both horizontal and * vertical alignment. */ void FtglFontTextRenderer::TextStringGroup::applyAlignmentsToHorizontalTextStrings() { double dy = 0.0; switch (m_annotationText.getVerticalAlignment()) { case AnnotationTextAlignVerticalEnum::BOTTOM: dy = m_viewportY - m_viewportBoundsMinY; break; case AnnotationTextAlignVerticalEnum::MIDDLE: dy = m_viewportY - (m_viewportBoundsMinY + m_viewportBoundsMaxY) / 2.0; break; case AnnotationTextAlignVerticalEnum::TOP: dy = m_viewportY - m_viewportBoundsMaxY; break; } for (std::vector::iterator iter = m_textStrings.begin(); iter != m_textStrings.end(); iter++) { TextString* ts = *iter; double dx = 0.0; switch (m_annotationText.getHorizontalAlignment()) { case AnnotationTextAlignHorizontalEnum::CENTER: { const double centerX = (ts->m_stringGlyphsMinX + ts->m_stringGlyphsMaxX) / 2.0; dx = -centerX; } break; case AnnotationTextAlignHorizontalEnum::LEFT: dx = -ts->m_stringGlyphsMinX; break; case AnnotationTextAlignHorizontalEnum::RIGHT: dx = -ts->m_stringGlyphsMaxX; break; } ts->m_viewportX += dx; ts->m_viewportY += dy; } } /** * Adjust the positions of the stacked text strings so * they are aligned properly for both horizontal and * vertical alignment. */ void FtglFontTextRenderer::TextStringGroup::applyAlignmentsToStackedTextStrings() { double dx = 0.0; switch (m_annotationText.getHorizontalAlignment()) { case AnnotationTextAlignHorizontalEnum::CENTER: { const double centerX = (m_viewportBoundsMinX + m_viewportBoundsMaxX) / 2.0; dx = m_viewportX - centerX; } break; case AnnotationTextAlignHorizontalEnum::LEFT: dx = m_viewportX - m_viewportBoundsMinX; break; case AnnotationTextAlignHorizontalEnum::RIGHT: dx = m_viewportX - m_viewportBoundsMaxX; break; } for (std::vector::iterator iter = m_textStrings.begin(); iter != m_textStrings.end(); iter++) { TextString* ts = *iter; double dy = 0.0; switch (m_annotationText.getVerticalAlignment()) { case AnnotationTextAlignVerticalEnum::BOTTOM: dy = -ts->m_stringGlyphsMinY; break; case AnnotationTextAlignVerticalEnum::MIDDLE: dy = - (ts->m_stringGlyphsMinY + ts->m_stringGlyphsMaxY) / 2.0; break; case AnnotationTextAlignVerticalEnum::TOP: dy = -ts->m_stringGlyphsMaxY; break; } ts->m_viewportX += dx; ts->m_viewportY += dy; } } /** * Adjust the positions of the text strings so * they are aligned properly. */ void FtglFontTextRenderer::TextStringGroup::applyAlignmentsToTextStrings() { switch (m_annotationText.getOrientation()) { case AnnotationTextOrientationEnum::HORIZONTAL: applyAlignmentsToHorizontalTextStrings(); break; case AnnotationTextOrientationEnum::STACKED: applyAlignmentsToStackedTextStrings(); break; } } #endif // HAVE_FREETYPE connectome-workbench-1.4.2/src/Brain/FtglFontTextRenderer.h000066400000000000000000000406631360521144700237160ustar00rootroot00000000000000 #ifndef __FTGL_FONT_TEXT_RENDERER_H__ #define __FTGL_FONT_TEXT_RENDERER_H__ #ifdef HAVE_FREETYPE /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AnnotationTextAlignHorizontalEnum.h" #include "AnnotationTextOrientationEnum.h" #include "BrainOpenGLTextRenderInterface.h" class FTFont; namespace caret { class FtglFontTextRenderer : public BrainOpenGLTextRenderInterface { public: FtglFontTextRenderer(); virtual ~FtglFontTextRenderer(); bool isValid() const; virtual void drawTextAtViewportCoords(const double viewportX, const double viewportY, const AnnotationText& annotationText, const DrawingFlags& flags) override; virtual void drawTextAtViewportCoords(const double viewportX, const double viewportY, const double viewportZ, const AnnotationText& annotationText, const DrawingFlags& flags) override; virtual void drawTextAtModelCoordsFacingUser(const double modelX, const double modelY, const double modelZ, const AnnotationText& annotationText, const DrawingFlags& flags) override; virtual void drawTextInModelSpace(const AnnotationText& annotationText, const float modelSpaceScaling, const float heightOrWidthForPercentageSizeText, const float normalVector[3], const DrawingFlags& flags) override; virtual void getTextWidthHeightInPixels(const AnnotationText& annotationText, const DrawingFlags& flags, const double viewportWidth, const double viewportHeight, double& widthOut, double& heightOut) override; virtual void getBoundsForTextInModelSpace(const AnnotationText& annotationText, const float modelSpaceScaling, const float heightOrWidthForPercentageSizeText, const DrawingFlags& flags, double bottomLeftOut[3], double bottomRightOut[3], double topRightOut[3], double topLeftOut[3], double underlineStartOut[3], double underlineEndOut[3]) override; virtual void getBoundsForTextAtViewportCoords(const AnnotationText& annotationText, const DrawingFlags& flags, const double viewportX, const double viewportY, const double viewportZ, const double viewportWidth, const double viewportHeight, double bottomLeftOut[3], double bottomRightOut[3], double topRightOut[3], double topLeftOut[3]) override; virtual void getBoundsWithoutMarginForTextAtViewportCoords(const AnnotationText& annotationText, const DrawingFlags& flags, const double viewportX, const double viewportY, const double viewportZ, const double viewportWidth, const double viewportHeight, double bottomLeftOut[3], double bottomRightOut[3], double topRightOut[3], double topLeftOut[3]) override; virtual AString getName() const; private: enum DepthTestEnum { DEPTH_TEST_NO, DEPTH_TEST_YES }; enum class FtglFontTypeEnum { POLYGON, TEXTURE }; FtglFontTextRenderer(const FtglFontTextRenderer&); FtglFontTextRenderer& operator=(const FtglFontTextRenderer&); void drawTextAtViewportCoordsInternal(const DepthTestEnum depthTesting, const double viewportX, const double viewportY, const double viewportZ, const AnnotationText& annotationText, const DrawingFlags& flags); FTFont* getFont(const AnnotationText& annotationText, const FtglFontTypeEnum ftglFontType, const bool creatingDefaultFontFlag); FTFont* getFont(const AnnotationText& annotationText, const FtglFontTypeEnum ftglFontType, const float heightOrWidthForPercentageSizeText, const bool creatingDefaultFontFlag); void drawUnderline(const double lineStartX, const double lineEndX, const double lineY, const double lineZ, const double underlineThickness, uint8_t foregroundRgba[4]); void drawOutline(const double minX, const double maxX, const double minY, const double maxY, const double z, const double outlineThickness, uint8_t foregroundRgba[4]); void drawOutline3D(float bottomLeft[3], float bottomRight[3], float topRight[3], float topLeft[3], const double outlineThickness, uint8_t foregroundRgba[4]); double getLineWidthFromPercentageHeight(const double percentageHeight) const; float getLineThicknessPixelsInModelSpace(const float lineWidthPercentage, const float heightOrWidthForPercentageSizeText, const float modelSpaceScaling) const; class FontData { public: FontData(); FontData(const AnnotationText& annotationText, const FtglFontTypeEnum ftglFontType, const int32_t viewportWidth, const int32_t viewportHeight); ~FontData(); void initialize(const AString& fontFileName); FtglFontTypeEnum m_ftglFontType = FtglFontTypeEnum::TEXTURE; QByteArray m_fontData; FTFont* m_font; bool m_valid; }; /** * Drawing space of text */ enum class TextDrawingSpace { /** * Drawn in model space coordinates */ MODEL, /** * Drawn in viewport coordinates */ VIEWPORT }; /** * A text character */ class TextCharacter { public: TextCharacter(const wchar_t& character, const double horizontalAdvance, const double glyphMinX, const double glyphMaxX, const double glyphMinY, const double glyphMaxY); ~TextCharacter(); void print(const AString& offsetString); const wchar_t m_character; const double m_horizontalAdvance; /* * Bounding box that encloses text with 0.0 at the "pen" * http://www.freetype.org/freetype2/docs/glyphs/glyphs-3.html */ const double m_glyphMinX; const double m_glyphMaxX; const double m_glyphMinY; const double m_glyphMaxY; /* * Offset from previous character */ double m_offsetX; double m_offsetY; double m_offsetZ; }; /** * A string of text */ class TextString { public: TextString(const QString& textString, const TextDrawingSpace textDrawingSpace, const AnnotationTextOrientationEnum::Enum orientation, const double underlineThickness, const double outlineThickness, FTFont* font); ~TextString(); void print(const AString& offsetString); void setGlyphBounds(); void getTextBoundsInViewportCoordinates(double& viewportMinX, double& viewportMaxX, double& viewportMinY, double& viewportMaxY) const; const TextDrawingSpace m_textDrawingSpace; const double m_underlineThickness; const double m_outlineThickness; std::vector m_characters; double m_viewportX; double m_viewportY; double m_viewportZ; /* * Bounds relative to origin of first character */ double m_stringGlyphsMinX; double m_stringGlyphsMaxX; double m_stringGlyphsMinY; double m_stringGlyphsMaxY; private: void initializeTextCharacterOffsets(const AnnotationTextOrientationEnum::Enum orientation); }; /** * The "high level" text object containing strings of text */ class TextStringGroup { public: TextStringGroup(const AnnotationText& annotationText, const DrawingFlags& flags, FTFont* font, const double viewportX, const double viewportY, const double viewportZ, const double rotationAngle, const double lineThicknessForViewportHeight); ~TextStringGroup(); void getViewportBounds(const double margin, double bottomLeftOut[3], double bottomRightOut[3], double topRightOut[3], double topLeftOut[3], double rotationPointXYZOut[3]) const; void print(); std::vector m_textStrings; const AnnotationText& m_annotationText; FTFont* m_font; const double m_viewportX; const double m_viewportY; const double m_viewportZ; const double m_rotationAngle; double m_underlineThickness; /* * Bounds relative to origin of first character */ double m_viewportBoundsMinX; double m_viewportBoundsMaxX; double m_viewportBoundsMinY; double m_viewportBoundsMaxY; TextDrawingSpace m_textDrawingSpace; private: void applyAlignmentsToHorizontalTextStrings(); void applyAlignmentsToStackedTextStrings(); void applyAlignmentsToTextStrings(); void initializeTextPositions(); void updateTextBounds(); void splitTextIntoLines(); }; void drawTextAtViewportCoordinatesInternal(const AnnotationText& annotationText, const TextStringGroup& textStringGroup); void drawTextInModelSpaceInternal(const AnnotationText& annotationText, const TextStringGroup& textStringGroup, const float heightOrWidthForPercentageSizeText); void applyTextColoring(const AnnotationText& annotationText); void applyBackgroundColoring(const TextStringGroup& textStringGroup); void setViewportHeight(); void saveStateOfOpenGL(); void restoreStateOfOpenGL(); /** * The default font. DO NOT delete it since it points to * a font in "m_fontNameToFontMap". */ FTFont* m_defaultFont; /** * Map for caching fonts */ typedef std::map FONT_MAP; /** * Iterator for cached fonts. */ typedef FONT_MAP::iterator FONT_MAP_ITERATOR; /** * Caches fonts as they are created */ FONT_MAP m_fontNameToFontMap; /** * Tracks fonts that failed creation to avoid * printing an error message more than once. */ std::set m_failedFontNames; /** Depth testing enabled status */ DepthTestEnum m_depthTestingStatus; /** Width of the viewport */ int32_t m_viewportWidth; /** Height of the viewport */ int32_t m_viewportHeight; float m_lineWidthMinimum = 1.0f; float m_lineWidthMaximum = 5.0f; static const double s_textMarginSize; static const double s_modelSpaceMarginPercentage; }; #ifdef __FTGL_FONT_TEXT_RENDERER_DECLARE__ const double FtglFontTextRenderer::s_textMarginSize = 3.0; const double FtglFontTextRenderer::s_modelSpaceMarginPercentage = 0.2; #endif // __FTGL_FONT_TEXT_RENDERER_DECLARE__ } // namespace #endif // HAVE_FREETYPE #endif //__FTGL_FONT_TEXT_RENDERER_H__ connectome-workbench-1.4.2/src/Brain/GapsAndMargins.cxx000066400000000000000000000357001360521144700230440ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GAPS_AND_MARGINS_DECLARE__ #include "GapsAndMargins.h" #undef __GAPS_AND_MARGINS_DECLARE__ #include "BrowserTabContent.h" #include "CaretAssert.h" #include "EventBrowserTabNew.h" #include "EventManager.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::GapsAndMargins * \brief Gaps for surface montage and volume montage. Margins for tabs. * \ingroup Brain */ /** * Constructor. */ GapsAndMargins::GapsAndMargins() : CaretObject() { reset(); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->addArray("m_tabMarginsBottom", m_tabMarginsBottom, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, 0.0); m_sceneAssistant->addArray("m_tabMarginsLeft", m_tabMarginsLeft, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, 0.0); m_sceneAssistant->addArray("m_tabMarginsRight", m_tabMarginsRight, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, 0.0); m_sceneAssistant->addArray("m_tabMarginsTop", m_tabMarginsTop, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, 0.0); m_sceneAssistant->addArray("m_surfaceMontageHorizontalGaps", m_surfaceMontageHorizontalGaps, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, 0.0); m_sceneAssistant->addArray("m_surfaceMontageVerticalGaps", m_surfaceMontageVerticalGaps, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, 0.0); m_sceneAssistant->addArray("m_volumeMontageHorizontalGaps", m_volumeMontageHorizontalGaps, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, 0.0); m_sceneAssistant->addArray("m_volumeMontageVerticalGaps", m_volumeMontageVerticalGaps, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, 0.0); /* * Use processed event listener because we need to know the index * of the tab that was created */ EventManager::get()->addProcessedEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_NEW); } /** * Destructor. */ GapsAndMargins::~GapsAndMargins() { EventManager::get()->removeAllEventsFromListener(this); delete m_sceneAssistant; } /** * Receive an event. * * @param event * The event that the receive can respond to. */ void GapsAndMargins::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_NEW) { EventBrowserTabNew* newTabEvent = dynamic_cast(event); CaretAssert(newTabEvent); const BrowserTabContent* tab = newTabEvent->getBrowserTab(); CaretAssert(tab); if (tab != NULL) { const int32_t tabIndex = tab->getTabNumber(); CaretAssertArrayIndex(m_tabMarginsLeft, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); CaretAssertArrayIndex(m_tabMarginsRight, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); CaretAssertArrayIndex(m_tabMarginsBottom, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); CaretAssertArrayIndex(m_tabMarginsTop, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_tabMarginsLeft[tabIndex] = 0.0; m_tabMarginsRight[tabIndex] = 0.0; m_tabMarginsBottom[tabIndex] = 0.0; m_tabMarginsTop[tabIndex] = 0.0; } } } /** * Get a description of this object's content. * @return String describing this object's content. */ AString GapsAndMargins::toString() const { return "GapsAndMargins"; } void GapsAndMargins::reset() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_tabMarginsBottom[i] = 0.0; m_tabMarginsLeft[i] = 0.0; m_tabMarginsRight[i] = 0.0; m_tabMarginsTop[i] = 0.0; } for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS; i++) { m_surfaceMontageHorizontalGaps[i] = 0.0; m_surfaceMontageVerticalGaps[i] = 0.0; m_volumeMontageHorizontalGaps[i] = 0.0; m_volumeMontageVerticalGaps[i] = 0.0; } } /** * Get the LEFT margin for the given tab. * * @param tabIndex * Index of the tab. * @return * Left margin for the tab. */ float GapsAndMargins::getMarginLeftForTab(const int32_t tabIndex) const { CaretAssertArrayIndex(m_tabMarginsLeft, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_tabMarginsLeft[tabIndex]; } /** * Get the RIGHT margin for the given tab. * * @param tabIndex * Index of the tab. * @return * Right margin for the tab. */ float GapsAndMargins::getMarginRightForTab(const int32_t tabIndex) const { CaretAssertArrayIndex(m_tabMarginsRight, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_tabMarginsRight[tabIndex]; } /** * Get the BOTTOM margin for the given tab. * * @param tabIndex * Index of the tab. * @return * Bottom margin for the tab. */ float GapsAndMargins::getMarginBottomForTab(const int32_t tabIndex) const { CaretAssertArrayIndex(m_tabMarginsBottom, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_tabMarginsBottom[tabIndex]; } /** * Get the TOP margin for the given tab. * * @param tabIndex * Index of the tab. * @return * Top margin for the tab. */ float GapsAndMargins::getMarginTopForTab(const int32_t tabIndex) const { CaretAssertArrayIndex(m_tabMarginsTop, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_tabMarginsTop[tabIndex]; } /** * Set the LEFT margin for the given tab. * * @param tabIndex * Index of the tab. * @param margin * Left margin for the tab. */ void GapsAndMargins::setMarginLeftForTab(const int32_t tabIndex, const float margin) { CaretAssertArrayIndex(m_tabMarginsLeft, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_tabMarginsLeft[tabIndex] = margin; } /** * Set the RIGHT margin for the given tab. * * @param tabIndex * Index of the tab. * @param margin * Right margin for the tab. */ void GapsAndMargins::setMarginRightForTab(const int32_t tabIndex, const float margin) { CaretAssertArrayIndex(m_tabMarginsRight, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_tabMarginsRight[tabIndex] = margin; } /** * Set the BOTTOM margin for the given tab. * * @param tabIndex * Index of the tab. * @param margin * Bottom margin for the tab. */ void GapsAndMargins::setMarginBottomForTab(const int32_t tabIndex, const float margin) { CaretAssertArrayIndex(m_tabMarginsBottom, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_tabMarginsBottom[tabIndex] = margin; } /** * Set the Top margin for the given tab. * * @param tabIndex * Index of the tab. * @param margin * Top margin for the tab. */ void GapsAndMargins::setMarginTopForTab(const int32_t tabIndex, const float margin) { CaretAssertArrayIndex(m_tabMarginsTop, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_tabMarginsTop[tabIndex] = margin; } /** * @return The surface montage horizontal gap. * * @param windowIndex * Index of window. */ float GapsAndMargins::getSurfaceMontageHorizontalGapForWindow(const int32_t windowIndex) const { CaretAssertArrayIndex(m_surfaceMontageHorizontalGaps, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, windowIndex); return m_surfaceMontageHorizontalGaps[windowIndex]; } /** * @return The surface montage vertical gap. * * @param windowIndex * Index of window. */ float GapsAndMargins::getSurfaceMontageVerticalGapForWindow(const int32_t windowIndex) const { CaretAssertArrayIndex(m_surfaceMontageVerticalGaps, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, windowIndex); return m_surfaceMontageVerticalGaps[windowIndex]; } /** * @return The volume montage horizontal gap. * * @param windowIndex * Index of window. */ float GapsAndMargins::getVolumeMontageHorizontalGapForWindow(const int32_t windowIndex) const { CaretAssertArrayIndex(m_volumeMontageHorizontalGaps, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, windowIndex); return m_volumeMontageHorizontalGaps[windowIndex]; } /** * @return The volume montage vertical gap. * * @param windowIndex * Index of window. */ float GapsAndMargins::getVolumeMontageVerticalGapForWindow(const int32_t windowIndex) const { CaretAssertArrayIndex(m_volumeMontageVerticalGaps, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, windowIndex); return m_volumeMontageVerticalGaps[windowIndex]; } /** * Set the surface montage horizontal gap. * * @param windowIndex * Index of window. * @param gap * New value for horizontal gap. */ void GapsAndMargins::setSurfaceMontageHorizontalGapForWindow(const int32_t windowIndex, const float gap) { CaretAssertArrayIndex(m_surfaceMontageHorizontalGaps, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, windowIndex); m_surfaceMontageHorizontalGaps[windowIndex] = gap; } /** * Set the surface montage vertical gap. * * @param windowIndex * Index of window. * @param gap * New value for vertical gap. */ void GapsAndMargins::setSurfaceMontageVerticalGapForWindow(const int32_t windowIndex, const float gap) { CaretAssertArrayIndex(m_surfaceMontageVerticalGaps, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, windowIndex); m_surfaceMontageVerticalGaps[windowIndex] = gap; } /** * Set the volume montage horizontal gap. * * @param windowIndex * Index of window. * @param gap * New value for horizontal gap. */ void GapsAndMargins::setVolumeMontageHorizontalGapForWindow(const int32_t windowIndex, const float gap) { CaretAssertArrayIndex(m_volumeMontageHorizontalGaps, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, windowIndex); m_volumeMontageHorizontalGaps[windowIndex] = gap; } /** * Set the volume montage vertical gap. * * @param windowIndex * Index of window. * @param gap * New value for vertical gap. */ void GapsAndMargins::setVolumeMontageVerticalGapForWindow(const int32_t windowIndex, const float gap) { CaretAssertArrayIndex(m_volumeMontageVerticalGaps, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, windowIndex); m_volumeMontageVerticalGaps[windowIndex] = gap; } /** * Get the margins for drawing a tab. * * @param tabIndex * Index of the tab. * @param viewportWidth * Width of viewport. * @param viewportHeight * Height of viewport. * @param MarginOut * Margin for * @param MarginOut * Margin for * @param MarginOut * Margin for * @param MarginOut * Margin for */ void GapsAndMargins::getMarginsInPixelsForDrawing(const int32_t tabIndex, const int32_t viewportWidth, const int32_t viewportHeight, int32_t& leftMarginOut, int32_t& rightMarginOut, int32_t& bottomMarginOut, int32_t& topMarginOut) const { leftMarginOut = 0; rightMarginOut = 0; bottomMarginOut = 0; topMarginOut = 0; topMarginOut = static_cast(viewportHeight * (getMarginTopForTab(tabIndex) / 100.0)); bottomMarginOut = static_cast(viewportHeight * (getMarginBottomForTab(tabIndex) / 100.0)); leftMarginOut = static_cast(viewportWidth * (getMarginLeftForTab(tabIndex) / 100.0)); rightMarginOut = static_cast(viewportWidth * (getMarginRightForTab(tabIndex) / 100.0)); } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* GapsAndMargins::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "GapsAndMargins", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void GapsAndMargins::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Brain/GapsAndMargins.h000066400000000000000000000132421360521144700224660ustar00rootroot00000000000000#ifndef __GAPS_AND_MARGINS_H__ #define __GAPS_AND_MARGINS_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "CaretObject.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" namespace caret { class SceneClassAssistant; class GapsAndMargins : public CaretObject, public EventListenerInterface, public SceneableInterface { public: GapsAndMargins(); virtual ~GapsAndMargins(); virtual void receiveEvent(Event* event) override; float getMarginLeftForTab(const int32_t tabIndex) const; float getMarginRightForTab(const int32_t tabIndex) const; float getMarginBottomForTab(const int32_t tabIndex) const; float getMarginTopForTab(const int32_t tabIndex) const; void setMarginLeftForTab(const int32_t tabIndex, const float margin); void setMarginRightForTab(const int32_t tabIndex, const float margin); void setMarginBottomForTab(const int32_t tabIndex, const float margin); void setMarginTopForTab(const int32_t tabIndex, const float margin); float getSurfaceMontageHorizontalGapForWindow(const int32_t windowIndex) const; float getSurfaceMontageVerticalGapForWindow(const int32_t windowIndex) const; float getVolumeMontageHorizontalGapForWindow(const int32_t windowIndex) const; float getVolumeMontageVerticalGapForWindow(const int32_t windowIndex) const; void setSurfaceMontageHorizontalGapForWindow(const int32_t windowIndex, const float gap); void setSurfaceMontageVerticalGapForWindow(const int32_t windowIndex, const float gap); void setVolumeMontageHorizontalGapForWindow(const int32_t windowIndex, const float gap); void setVolumeMontageVerticalGapForWindow(const int32_t windowIndex, const float gap); void reset(); // ADD_NEW_METHODS_HERE virtual AString toString() const; void getMarginsInPixelsForDrawing(const int32_t tabIndex, const int32_t viewportWidth, const int32_t viewportHeight, int32_t& leftMarginOut, int32_t& rightMarginOut, int32_t& bottomMarginOut, int32_t& topMarginOut) const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implemetation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: GapsAndMargins(const GapsAndMargins&); GapsAndMargins& operator=(const GapsAndMargins&); SceneClassAssistant* m_sceneAssistant; float m_tabMarginsLeft[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; float m_tabMarginsRight[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; float m_tabMarginsBottom[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; float m_tabMarginsTop[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; float m_surfaceMontageHorizontalGaps[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS]; float m_surfaceMontageVerticalGaps[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS]; float m_volumeMontageHorizontalGaps[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS]; float m_volumeMontageVerticalGaps[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS]; // ADD_NEW_MEMBERS_HERE }; #ifdef __GAPS_AND_MARGINS_DECLARE__ // #endif // __GAPS_AND_MARGINS_DECLARE__ } // namespace #endif //__GAPS_AND_MARGINS_H__ connectome-workbench-1.4.2/src/Brain/IdentificationManager.cxx000066400000000000000000000520351360521144700244320ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __IDENTIFICATION_MANAGER_DECLARE__ #include "IdentificationManager.h" #undef __IDENTIFICATION_MANAGER_DECLARE__ #include "Brain.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPreferences.h" #include "EventBrowserTabGetAll.h" #include "EventManager.h" #include "IdentifiedItemNode.h" #include "IdentifiedItemVoxel.h" #include "MathFunctions.h" #include "SceneClassAssistant.h" #include "SceneClass.h" #include "ScenePrimitive.h" #include "SessionManager.h" using namespace caret; /** * \class caret::IdentificationManager * \brief Manages identified items. */ /** * Constructor. * * @param caretPreferences * The caret preferencers */ IdentificationManager::IdentificationManager(const CaretPreferences* caretPreferences) : SceneableInterface() { m_sceneAssistant = new SceneClassAssistant(); m_contralateralIdentificationEnabled = false; m_identificationSymbolColor = CaretColorEnum::WHITE; m_identificationContralateralSymbolColor = CaretColorEnum::LIME; m_identifcationSymbolSize = 3.0; m_identifcationMostRecentSymbolSize = 5.0; m_showSurfaceIdentificationSymbols = caretPreferences->isShowSurfaceIdentificationSymbols(); m_showVolumeIdentificationSymbols = caretPreferences->isShowVolumeIdentificationSymbols(); m_sceneAssistant->add("m_contralateralIdentificationEnabled", &m_contralateralIdentificationEnabled); m_sceneAssistant->add("m_identifcationSymbolSize", &m_identifcationSymbolSize); m_sceneAssistant->add("m_identifcationMostRecentSymbolSize", &m_identifcationMostRecentSymbolSize); m_sceneAssistant->add("m_identificationSymbolColor", &m_identificationSymbolColor); m_sceneAssistant->add("m_identificationContralateralSymbolColor", &m_identificationContralateralSymbolColor); m_sceneAssistant->add("m_showSurfaceIdentificationSymbols", &m_showSurfaceIdentificationSymbols); m_sceneAssistant->add("m_showVolumeIdentificationSymbols", &m_showVolumeIdentificationSymbols); removeAllIdentifiedItems(); } /** * Destructor. */ IdentificationManager::~IdentificationManager() { removeAllIdentifiedItems(); delete m_sceneAssistant; } /** * Add an identified item. * @param item * Identified item that is added. * NOTE: Takes ownership of this item and will delete, at the appropriate time. * If item is a node and contralateral identification is enabled, the contralateral * structure will be set in the node item. */ void IdentificationManager::addIdentifiedItem(IdentifiedItem* item) { CaretAssert(item); IdentifiedItemNode* nodeItem = dynamic_cast(item); if (nodeItem != NULL) { if (m_contralateralIdentificationEnabled) { const StructureEnum::Enum contralateralStructure = StructureEnum::getContralateralStructure(nodeItem->getStructure()); nodeItem->setContralateralStructure(contralateralStructure); } } addIdentifiedItemPrivate(item); } /** * Add an identified item. * @param item * Identified item that is added. * NOTE: Takes ownership of this item and will delete, at the appropriate time. */ void IdentificationManager::addIdentifiedItemPrivate(IdentifiedItem* item) { CaretAssert(item); m_mostRecentIdentifiedItem = item; m_identifiedItems.push_back(item); } /** * @return String containing identification text for information window. */ AString IdentificationManager::getIdentificationText() const { AString text; for (std::list::const_iterator iter = m_identifiedItems.begin(); iter != m_identifiedItems.end(); iter++) { const IdentifiedItem* item = *iter; if (text.isEmpty() == false) { text += "

"; } text += item->getText(); } return text; } /** * Remove all identification text. Node and voxels items have their text * removed and all other identification items are removed. */ void IdentificationManager::removeIdentificationText() { std::list idItemsToKeep; for (std::list::iterator iter = m_identifiedItems.begin(); iter != m_identifiedItems.end(); iter++) { IdentifiedItem* item = *iter; IdentifiedItemNode* nodeItem = dynamic_cast(item); IdentifiedItemVoxel* voxelItem = dynamic_cast(item); if ((nodeItem != NULL) || (voxelItem != NULL)) { item->clearText(); idItemsToKeep.push_back(item); } else { if (m_mostRecentIdentifiedItem == item) { m_mostRecentIdentifiedItem = NULL; } delete item; } } m_identifiedItems = idItemsToKeep; } /** * Get identified nodes for the surface with the given structure and * number of nodes. * * @param structure * The structure * @param surfaceNumberOfNodes * Number of nodes in surface. */ std::vector IdentificationManager::getNodeIdentifiedItemsForSurface(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes) const { std::vector nodeItemsOut; for (std::list::const_iterator iter = m_identifiedItems.begin(); iter != m_identifiedItems.end(); iter++) { const IdentifiedItem* item = *iter; const IdentifiedItemNode* nodeItem = dynamic_cast(item); if (nodeItem != NULL) { if (nodeItem->isValid()) { if (nodeItem->getSurfaceNumberOfNodes() == surfaceNumberOfNodes) { bool useIt = false; if (nodeItem->getStructure() == structure) { useIt = true; } else if (nodeItem->getContralateralStructure() == structure) { useIt = true; } if (useIt) { IdentifiedItemNode nodeID(*nodeItem); const float* symbolRGB = CaretColorEnum::toRGB(m_identificationSymbolColor); nodeID.setSymbolRGB(symbolRGB); const float* contralateralSymbolRGB = CaretColorEnum::toRGB(m_identificationContralateralSymbolColor); nodeID.setContralateralSymbolRGB(contralateralSymbolRGB); if (item == m_mostRecentIdentifiedItem) { nodeID.setSymbolSize(m_identifcationMostRecentSymbolSize); } else { nodeID.setSymbolSize(m_identifcationSymbolSize); } nodeItemsOut.push_back(nodeID); } } } } } return nodeItemsOut; } /** * @return All identified voxels. */ std::vector IdentificationManager::getIdentifiedItemsForVolume() const { std::vector itemsOut; for (std::list::const_iterator iter = m_identifiedItems.begin(); iter != m_identifiedItems.end(); iter++) { const IdentifiedItem* item = *iter; const IdentifiedItemVoxel* voxelItem = dynamic_cast(item); if (voxelItem != NULL) { if (voxelItem->isValid()) { IdentifiedItemVoxel voxelID(*voxelItem); const float* symbolRGB = CaretColorEnum::toRGB(m_identificationSymbolColor); voxelID.setSymbolRGB(symbolRGB); voxelID.setSymbolSize(m_identifcationSymbolSize); itemsOut.push_back(voxelID); } } } return itemsOut; } /** * Remove any identification for the node in the surface with the given * structure and number of nodes. * * @param structure * The structure * @param surfaceNumberOfNodes * Number of nodes in surface. * @param nodeIndex * Index of the node. */ void IdentificationManager::removeIdentifiedNodeItem(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const int32_t nodeIndex) { for (std::list::iterator iter = m_identifiedItems.begin(); iter != m_identifiedItems.end(); iter++) { IdentifiedItem* item = *iter; const IdentifiedItemNode* node = dynamic_cast(item); if (node != NULL) { if ((node->getStructure() == structure) || (node->getContralateralStructure() == structure)) { if ((node->getSurfaceNumberOfNodes() == surfaceNumberOfNodes) && (node->getNodeIndex() == nodeIndex)) { m_identifiedItems.erase(iter); delete item; return; } } } } } /** * Remove identified voxel at the given coordinate. * * @param xyz * Coordinates for voxel that is to be removed. */ void IdentificationManager::removeIdentifiedVoxelItem(const float xyz[3]) { const float tolerance = 0.01; for (std::list::iterator iter = m_identifiedItems.begin(); iter != m_identifiedItems.end(); iter++) { IdentifiedItem* item = *iter; const IdentifiedItemVoxel* voxel = dynamic_cast(item); if (voxel != NULL) { if (voxel->isValid()) { float voxelXYZ[3]; voxel->getXYZ(voxelXYZ); const float distSQ = MathFunctions::distanceSquared3D(xyz, voxelXYZ); if (distSQ < tolerance) { m_identifiedItems.erase(iter); delete item; return; } } } } } /** * Remove all identified items. */ void IdentificationManager::removeAllIdentifiedItems() { for (std::list::iterator iter = m_identifiedItems.begin(); iter != m_identifiedItems.end(); iter++) { IdentifiedItem* item = *iter; delete item; } m_identifiedItems.clear(); m_mostRecentIdentifiedItem = NULL; } /** * Remove all identification symbols while preserving text. * * Text from identification symbols for surface or volume are * inserted into new identified items and the symbol items * are removed. */ void IdentificationManager::removeAllIdentifiedSymbols() { std::list idItemsToKeep; for (std::list::iterator iter = m_identifiedItems.begin(); iter != m_identifiedItems.end(); iter++) { IdentifiedItem* item = *iter; IdentifiedItemNode* nodeItem = dynamic_cast(item); IdentifiedItemVoxel* voxelItem = dynamic_cast(item); IdentifiedItem* itemToKeep = NULL; if ((nodeItem != NULL) || (voxelItem != NULL)) { if (m_mostRecentIdentifiedItem == item) { m_mostRecentIdentifiedItem = NULL; } itemToKeep = new IdentifiedItem(item->getText()); delete item; } else { itemToKeep = item; } if (itemToKeep != NULL) { if (itemToKeep->getText().isEmpty()) { delete itemToKeep; itemToKeep = NULL; } else { idItemsToKeep.push_back(itemToKeep); } } } m_identifiedItems = idItemsToKeep; } /** * @return Status of contralateral identification. */ bool IdentificationManager::isContralateralIdentificationEnabled() const { return m_contralateralIdentificationEnabled; } /** * Set status of contralateral identification. * @param * New status. */ void IdentificationManager::setContralateralIdentificationEnabled(const bool enabled) { m_contralateralIdentificationEnabled = enabled; } /** * @return The size of the identification symbol */ float IdentificationManager::getIdentificationSymbolSize() const { return m_identifcationSymbolSize; } /** * Set the size of the identification symbol * @param symbolSize * New size of symbol. */ void IdentificationManager::setIdentificationSymbolSize(const float symbolSize) { m_identifcationSymbolSize = symbolSize; } /** * @return The size of the most recent identification symbol */ float IdentificationManager::getMostRecentIdentificationSymbolSize() const { return m_identifcationMostRecentSymbolSize; } /** * Set the size of the most recent identification symbol * @param symbolSize * New size of symbol. */ void IdentificationManager::setMostRecentIdentificationSymbolSize(const float symbolSize) { m_identifcationMostRecentSymbolSize = symbolSize; } /** * @return The color of the identification symbol. */ CaretColorEnum::Enum IdentificationManager::getIdentificationSymbolColor() const { return m_identificationSymbolColor; } /** * Set the color of the identification symbol. * @param color * New color. */ void IdentificationManager::setIdentificationSymbolColor(const CaretColorEnum::Enum color) { m_identificationSymbolColor = color; } /** * @return The color of the contralateral identification symbol. */ CaretColorEnum::Enum IdentificationManager::getIdentificationContralateralSymbolColor() const { return m_identificationContralateralSymbolColor; } /** * Set the color of the contralateral identification symbol. * @param color * New color. */ void IdentificationManager::setIdentificationContralateralSymbolColor(const CaretColorEnum::Enum color) { m_identificationContralateralSymbolColor = color; } /** * @return show surface identification symbols */ bool IdentificationManager::isShowSurfaceIdentificationSymbols() const { return m_showSurfaceIdentificationSymbols; } /** * Set show surface identification symbols * * @param showSurfaceIdentificationSymbols * New value for show surface identification symbols */ void IdentificationManager::setShowSurfaceIdentificationSymbols(const bool showSurfaceIdentificationSymbols) { m_showSurfaceIdentificationSymbols = showSurfaceIdentificationSymbols; } /** * @return show volume identification symbols */ bool IdentificationManager::isShowVolumeIdentificationSymbols() const { return m_showVolumeIdentificationSymbols; } /** * Set show volume identification symbols * * @param showVolumeIdentificationSymbols * New value for show volume identification symbols */ void IdentificationManager::setShowVolumeIdentificationSymbols(const bool showVolumeIdentificationSymbols) { m_showVolumeIdentificationSymbols = showVolumeIdentificationSymbols; } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* IdentificationManager::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } SceneClass* sceneClass = new SceneClass(instanceName, "IdentificationManager", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); for (std::list::iterator iter = m_identifiedItems.begin(); iter != m_identifiedItems.end(); iter++) { IdentifiedItem* item = *iter; sceneClass->addClass(item->saveToScene(sceneAttributes, "identifiedItem")); } return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. May be NULL for some types of scenes. */ void IdentificationManager::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } removeAllIdentifiedItems(); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); const int32_t numChildren = sceneClass->getNumberOfObjects(); for (int32_t i = 0; i < numChildren; i++) { const SceneObject* so = sceneClass->getObjectAtIndex(i); if (so->getName() == "identifiedItem") { const SceneClass* sc = dynamic_cast(so); if (sc != NULL) { const AString className = sc->getClassName(); if (className == "IdentifiedItem") { IdentifiedItem* item = new IdentifiedItem(); item->restoreFromScene(sceneAttributes, sc); if (item->isValid()) { addIdentifiedItemPrivate(item); } else { delete item; } } else if (className == "IdentifiedItemNode") { IdentifiedItemNode* item = new IdentifiedItemNode(); item->restoreFromScene(sceneAttributes, sc); if (item->isValid()) { addIdentifiedItemPrivate(item); } else { delete item; } } else if (className == "IdentifiedItemVoxel") { IdentifiedItemVoxel* item = new IdentifiedItemVoxel(); item->restoreFromScene(sceneAttributes, sc); if (item->isValid()) { addIdentifiedItemPrivate(item); } else { delete item; } } else { const AString msg = ("IdentifiedItem from scene is invalid. " "Has a new IdentifiedItem type been added? " "Class name=" + className); CaretAssertMessage(0, msg); CaretLogSevere(msg); } } } } /* * "m_volumeIdentificationEnabled" was removed when volume identification * was made a tab property. If this item is present in the scene, * update volume ID status in all tabs. */ const ScenePrimitive* idPrimitive = sceneClass->getPrimitive("m_volumeIdentificationEnabled"); if (idPrimitive != NULL) { const bool volumeID = sceneClass->getBooleanValue("m_volumeIdentificationEnabled"); EventBrowserTabGetAll allTabs; EventManager::get()->sendEvent(allTabs.getPointer()); std::vector tabContent = allTabs.getAllBrowserTabs(); for (std::vector::iterator iter = tabContent.begin(); iter != tabContent.end(); iter++) { BrowserTabContent* btc = *iter; btc->setIdentificationUpdatesVolumeSlices(volumeID); } } } connectome-workbench-1.4.2/src/Brain/IdentificationManager.h000066400000000000000000000116131360521144700240540ustar00rootroot00000000000000#ifndef __IDENTIFICATION_MANAGER_H__ #define __IDENTIFICATION_MANAGER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretColorEnum.h" #include "SceneableInterface.h" #include "StructureEnum.h" namespace caret { class CaretPreferences; class IdentifiedItem; class IdentifiedItemNode; class IdentifiedItemVoxel; class SceneClassAssistant; class IdentificationManager : public SceneableInterface { public: IdentificationManager(const CaretPreferences* caretPreferences); virtual ~IdentificationManager(); void addIdentifiedItem(IdentifiedItem* item); AString getIdentificationText() const; std::vector getNodeIdentifiedItemsForSurface(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes) const; std::vector getIdentifiedItemsForVolume() const; void removeIdentifiedNodeItem(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const int32_t nodeIndex); void removeIdentifiedVoxelItem(const float xyz[3]); void removeIdentificationText(); void removeAllIdentifiedItems(); void removeAllIdentifiedSymbols(); bool isContralateralIdentificationEnabled() const; void setContralateralIdentificationEnabled(const bool enabled); float getIdentificationSymbolSize() const; void setIdentificationSymbolSize(const float symbolSize); float getMostRecentIdentificationSymbolSize() const; void setMostRecentIdentificationSymbolSize(const float symbolSize); CaretColorEnum::Enum getIdentificationSymbolColor() const; void setIdentificationSymbolColor(const CaretColorEnum::Enum color); CaretColorEnum::Enum getIdentificationContralateralSymbolColor() const; void setIdentificationContralateralSymbolColor(const CaretColorEnum::Enum color); bool isShowSurfaceIdentificationSymbols() const; void setShowSurfaceIdentificationSymbols(const bool showSurfaceIdentificationSymbols); bool isShowVolumeIdentificationSymbols() const; void setShowVolumeIdentificationSymbols(const bool showVolumeIdentificationSymbols); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: IdentificationManager(const IdentificationManager&); IdentificationManager& operator=(const IdentificationManager&); public: // ADD_NEW_METHODS_HERE private: void addIdentifiedItemPrivate(IdentifiedItem* item); // ADD_NEW_MEMBERS_HERE SceneClassAssistant* m_sceneAssistant; std::list m_identifiedItems; AString m_previousIdentifiedItemsText; IdentifiedItem* m_mostRecentIdentifiedItem; bool m_contralateralIdentificationEnabled; float m_identifcationSymbolSize; float m_identifcationMostRecentSymbolSize; CaretColorEnum::Enum m_identificationSymbolColor; CaretColorEnum::Enum m_identificationContralateralSymbolColor; /** show surface identification symbols*/ bool m_showSurfaceIdentificationSymbols; /** show volume identification symbols*/ bool m_showVolumeIdentificationSymbols; }; #ifdef __IDENTIFICATION_MANAGER_DECLARE__ // #endif // __IDENTIFICATION_MANAGER_DECLARE__ } // namespace #endif //__IDENTIFICATION_MANAGER_H__ connectome-workbench-1.4.2/src/Brain/IdentificationStringBuilder.cxx000066400000000000000000000167101360521144700256350ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "IdentificationStringBuilder.h" using namespace caret; /** * Constructor. * * */ IdentificationStringBuilder::IdentificationStringBuilder() : HtmlStringBuilder() { } /** * Destructor */ IdentificationStringBuilder::~IdentificationStringBuilder() { } /** * Add text to the string. A newline is added at the end. * A colon is added after the bold text but in normal text. * If "normalText" is an empty string, no text is output. * * @param indentFlag Indent the text. * @param boldText The bold text that starts the line. * @param normalText The normal text placed after the bold text. * */ void IdentificationStringBuilder::addLine( const bool indentFlag, const AString& boldText, const AString& normalText) { if (normalText.length() <= 0) { return; } if (indentFlag) { addIndent(); } addBold(boldText); add(": "); add(normalText); this->addLineBreak(); } /** * Add text to the string. A newline is added at the end. * If "normalText" is an empty string, no text is output. * * @param indentFlag Indent the text. * @param normalText The normal text placed after the bold text. * */ void IdentificationStringBuilder::addLine( const bool indentFlag, const AString& normalText) { if (normalText.length() <= 0) { return; } if (indentFlag) { addIndent(); } add(normalText); this->addLineBreak();} /** * Add text to the string. A newline is added at the end. * A colon is added after the bold text but in normal text. * * @param indentFlag Indent the text. * @param boldText The bold text that starts the line. * @param number The number placed after the bold text. * @param displayOnlyIfNumberIsNonZeroFlag - only display text if * number is non-zero. * */ void IdentificationStringBuilder::addLine( const bool indentFlag, const AString& boldText, const int32_t number, const bool displayOnlyIfNumberIsNonZeroFlag) { bool displayIt = true; if (displayOnlyIfNumberIsNonZeroFlag) { displayIt = (number != 0); } if (displayIt) { addLine(indentFlag, boldText, AString::number(number)); } } /** * Add text to the string. A newline is added at the end. * A colon is added after the bold text but in normal text. * * @param indentFlag Indent the text. * @param boldText The bold text that starts the line. * @param number The number placed after the bold text. * @param displayOnlyIfNumberIsNonZeroFlag - only display text if * number is non-zero. * */ void IdentificationStringBuilder::addLine( const bool indentFlag, const AString& boldText, const float number, const bool displayOnlyIfNumberIsNonZeroFlag) { bool displayIt = true; if (displayOnlyIfNumberIsNonZeroFlag) { displayIt = (number != 0.0f); } if (displayIt) { addLine(indentFlag, boldText, AString::number(number)); } } /** * Add text to the string. A newline is added at the end. * A colon is added after the bold text but in normal text. * * @param indentFlag Indent the text. * @param boldText The bold text that starts the line. * @param floatArray The float array placed after the bold text. * @param floatArrayNumberOfElements Number of elements in the array. * @param displayOnlyIfNonZeroElementInArrayFlag - only display text if * array contains at least one non-zero element. * */ void IdentificationStringBuilder::addLine( const bool indentFlag, const AString& boldText, const float floatArray[], const int floatArrayNumberOfElements, const bool displayOnlyIfNonZeroElementInArrayFlag) { bool displayIt = true; if (displayOnlyIfNonZeroElementInArrayFlag) { displayIt = false; for (int64_t i = 0; i < floatArrayNumberOfElements; i++) { if (floatArray[i] != 0.0f) { displayIt = true; break; } } } if (displayIt) { AString sbf; sbf.reserve(1024); for (int i = 0; i < floatArrayNumberOfElements; i++) { if (i == 0) { sbf.append("("); } else { sbf.append(", "); } sbf.append(AString::number(floatArray[i])); if (i == (floatArrayNumberOfElements - 1)) { sbf.append(")"); } } addLine(indentFlag, boldText, sbf); } } /** * Add a list of objects using the "toString()" method. If an * object in the list is null, a single blank character is placed * into the values list. * @param indentFlag true if indentation is needed. * @param boldText Bold text that is displayed before the values. * @param objectList List of objects that have the toString() * value displayed. * @param displayOnlyIfNonNullElementInArrayFlag Text is only * displayed if one of the items in the list is not null. * */ void IdentificationStringBuilder::addLine( const bool indentFlag, const AString& boldText, const std::vector& objectList, const bool displayOnlyIfNonNullElementInArrayFlag) { bool displayIt = true; if (displayOnlyIfNonNullElementInArrayFlag) { displayIt = false; const int64_t numObjects = static_cast(objectList.size()); for (int64_t i = 0; i < numObjects; i++) { if (objectList[i] != NULL) { displayIt = true; break; } } } if (displayIt) { AString sbf; sbf.reserve(2048); int numItems = objectList.size(); for (int i = 0; i < numItems; i++) { if (i == 0) { sbf.append("("); } else { sbf.append(", "); } const CaretObject* obj = objectList[i]; if (obj != NULL) { sbf.append(obj->toString()); } if (i == (numItems - 1)) { sbf.append(")"); } } addLine(indentFlag, boldText, sbf); } } /** * Indent the line. */ void IdentificationStringBuilder::addIndent() { this->addSpaces(4); } connectome-workbench-1.4.2/src/Brain/IdentificationStringBuilder.h000066400000000000000000000053751360521144700252670ustar00rootroot00000000000000#ifndef __IDENTIFICATIONSTRINGBUILDER_H__ #define __IDENTIFICATIONSTRINGBUILDER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "HtmlStringBuilder.h" #include #include namespace caret { class IdentificationStringBuilder : public HtmlStringBuilder { public: IdentificationStringBuilder(); virtual ~IdentificationStringBuilder(); private: IdentificationStringBuilder(const IdentificationStringBuilder& o); IdentificationStringBuilder& operator=(const IdentificationStringBuilder& o); public: void addLine( const bool indentFlag, const AString& boldText, const AString& normalText); void addLine( const bool indentFlag, const AString& normalText); void addLine( const bool indentFlag, const AString& boldText, const int32_t number, const bool displayOnlyIfNumberIsNonZeroFlag); void addLine( const bool indentFlag, const AString& boldText, const float number, const bool displayOnlyIfNumberIsNonZeroFlag); void addLine(const bool indentFlag, const AString& boldText, const float floatArray[], const int floatArrayNumberOfElements, const bool displayOnlyIfNonZeroElementInArrayFlag); void addLine( const bool indentFlag, const AString& boldText, const std::vector& objectList, const bool displayOnlyIfNonNullElementInArrayFlag); void addIndent(); }; } // namespace #endif // __IDENTIFICATIONSTRINGBUILDER_H__ connectome-workbench-1.4.2/src/Brain/IdentificationTextGenerator.cxx000066400000000000000000002300751360521144700256550ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __IDENTIFICATION_TEXT_GENERATOR_DECLARE__ #include "IdentificationTextGenerator.h" #undef __IDENTIFICATION_TEXT_GENERATOR_DECLARE__ #include "Border.h" #include "Brain.h" #include "BrainStructure.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretMappableDataFile.h" #include "ChartDataCartesian.h" #include "ChartDataSource.h" #include "ChartModelDataSeries.h" #include "ChartTwoDataCartesian.h" #include "ChartableMatrixInterface.h" #include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileHistogramChart.h" #include "ChartableTwoFileLineSeriesChart.h" #include "ChartableTwoFileMatrixChart.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "CiftiMappableDataFile.h" #include "CaretVolumeExtension.h" #include "DataToolTipsManager.h" #include "EventBrowserTabGetAll.h" #include "EventManager.h" #include "FileInformation.h" #include "FociFile.h" #include "Focus.h" #include "GiftiLabel.h" #include "GraphicsPrimitive.h" #include "GraphicsPrimitiveV3f.h" #include "Histogram.h" #include "ImageFile.h" #include "MapFileDataSelector.h" #include "MetricDynamicConnectivityFile.h" #include "OverlaySet.h" #include "SelectionItemBorderSurface.h" #include "SelectionItemChartDataSeries.h" #include "SelectionItemChartFrequencySeries.h" #include "SelectionItemChartMatrix.h" #include "SelectionItemCiftiConnectivityMatrixRowColumn.h" #include "SelectionItemChartTimeSeries.h" #include "SelectionItemChartTwoHistogram.h" #include "SelectionItemChartTwoLineSeries.h" #include "SelectionItemChartTwoMatrix.h" #include "SelectionItemFocusSurface.h" #include "SelectionItemFocusVolume.h" #include "SelectionItemImage.h" #include "SelectionItemSurfaceNode.h" #include "SelectionItemVoxel.h" #include "SelectionManager.h" #include "IdentificationStringBuilder.h" #include "LabelFile.h" #include "MetricFile.h" #include "Surface.h" #include "VolumeDynamicConnectivityFile.h" #include "SurfaceProjectedItem.h" #include "SurfaceProjectionBarycentric.h" #include "SurfaceProjectionVanEssen.h" #include "VolumeFile.h" using namespace caret; /** * \class IdentificationTextGenerator * \brief Creates text describing selected data. * * Examine the selected data and generate descriptive text. */ /** * Constructor. */ IdentificationTextGenerator::IdentificationTextGenerator() : CaretObject() { } /** * Destructor. */ IdentificationTextGenerator::~IdentificationTextGenerator() { } /** * Create identification text from selection in the identification manager. * @param idManager * Identification manager containing selection. * @param brain * The brain. */ AString IdentificationTextGenerator::createIdentificationText(const SelectionManager* idManager, const Brain* brain) const { CaretAssert(idManager); CaretAssert(brain); IdentificationStringBuilder idText; const SelectionItemSurfaceNode* surfaceID = idManager->getSurfaceNodeIdentification(); this->generateSurfaceIdentificationText(idText, brain, surfaceID); this->generateSurfaceBorderIdentifcationText(idText, idManager->getSurfaceBorderIdentification(), false); this->generateSurfaceFociIdentifcationText(idText, idManager->getSurfaceFocusIdentification(), false); this->generateVolumeFociIdentifcationText(idText, idManager->getVolumeFocusIdentification()); this->generateVolumeIdentificationText(idText, brain, idManager->getVoxelIdentification()); this->generateChartDataSeriesIdentificationText(idText, idManager->getChartDataSeriesIdentification()); this->generateChartFrequencySeriesIdentificationText(idText, idManager->getChartFrequencySeriesIdentification()); this->generateChartTimeSeriesIdentificationText(idText, idManager->getChartTimeSeriesIdentification()); this->generateChartMatrixIdentificationText(idText, idManager->getChartMatrixIdentification()); this->generateCiftiConnectivityMatrixIdentificationText(idText, idManager->getCiftiConnectivityMatrixRowColumnIdentification()); this->generateChartTwoHistogramIdentificationText(idText, idManager->getChartTwoHistogramIdentification()); this->generateChartTwoLineSeriesIdentificationText(idText, idManager->getChartTwoLineSeriesIdentification()); this->generateChartTwoMatrixIdentificationText(idText, idManager->getChartTwoMatrixIdentification()); this->generateImageIdentificationText(idText, idManager->getImageIdentification()); return idText.toString(); } /** * Get text for the tooltip for a selected node. * * @param brain * The Brain. * @param browserTab * Browser tab in which tooltip is displayed * @param selectionManager * The selection manager. * @param dataToolTipsManager * The data tooltips manager * @param idText * String builder for identification text. */ AString IdentificationTextGenerator::createToolTipText(const Brain* brain, const BrowserTabContent* browserTab, const SelectionManager* selectionManager, const DataToolTipsManager* dataToolTipsManager) const { CaretAssert(brain); CaretAssert(browserTab); CaretAssert(selectionManager); CaretAssert(dataToolTipsManager); const SelectionItemSurfaceNode* selectedNode = selectionManager->getSurfaceNodeIdentification(); const SelectionItemVoxel* selectedVoxel = selectionManager->getVoxelIdentification(); IdentificationStringBuilder idText; if (selectedNode->isValid()) { generateSurfaceToolTip(brain, browserTab, selectionManager, dataToolTipsManager, idText); } else if (selectedVoxel->isValid()) { generateVolumeToolTip(browserTab, selectionManager, dataToolTipsManager, idText); } else { generateChartToolTip(selectionManager, dataToolTipsManager, idText); } AString text; if (idText.length() > 0) { text = idText.toStringWithHtmlBodyForToolTip(); } return text; } /** * Generate identification text for volume voxel identification. * * @param idText * String builder for identification text. * @param brain * The brain. * @param idVolumeVoxel * Information for volume voxel ID. */ void IdentificationTextGenerator::generateVolumeIdentificationText(IdentificationStringBuilder& idText, const Brain* brain, const SelectionItemVoxel* idVolumeVoxel) const { if (idVolumeVoxel->isValid() == false) { return; } int64_t ijk[3]; const VolumeMappableInterface* idVolumeFile = idVolumeVoxel->getVolumeFile(); idVolumeVoxel->getVoxelIJK(ijk); float x, y, z; idVolumeFile->indexToSpace(ijk[0], ijk[1], ijk[2], x, y, z); idText.addLine(false, "Voxel XYZ (" + AString::number(x) + ", " + AString::number(y) + ", " + AString::number(z) + ")"); const float xyz[3] = { x, y, z }; /* * Get all volume files */ std::vector volumeInterfaces; const int32_t numVolumeFiles = brain->getNumberOfVolumeFiles(); for (int32_t i = 0; i < numVolumeFiles; i++) { const VolumeFile* vf = brain->getVolumeFile(i); volumeInterfaces.push_back(vf); const VolumeDynamicConnectivityFile* volDynConnFile = vf->getVolumeDynamicConnectivityFile(); if (volDynConnFile != NULL) { if (volDynConnFile->isDataValid()) { volumeInterfaces.push_back(volDynConnFile); } } } /* * Get the CIFTI files that are volume mappable */ std::vector allCiftiMappableDataFiles; brain->getAllCiftiMappableDataFiles(allCiftiMappableDataFiles); for (std::vector::iterator ciftiMapIter = allCiftiMappableDataFiles.begin(); ciftiMapIter != allCiftiMappableDataFiles.end(); ciftiMapIter++) { const CiftiMappableDataFile* cmdf = *ciftiMapIter; if (cmdf->isEmpty() == false) { if (cmdf->isVolumeMappable()) { volumeInterfaces.push_back(cmdf); } } } /* * In first loop, show values for 'idVolumeFile' (the underlay volume) * In second loop, show values for all other volume files */ const int32_t numberOfVolumeMappableFiles = static_cast(volumeInterfaces.size()); for (int32_t iLoop = 0; iLoop < 2; iLoop++) { for (int32_t i = 0; i < numberOfVolumeMappableFiles; i++) { const VolumeMappableInterface* volumeInterfaceFile = volumeInterfaces[i]; const VolumeFile* volumeFile = dynamic_cast(volumeInterfaceFile); const CiftiMappableDataFile* ciftiFile = dynamic_cast(volumeInterfaceFile); CaretAssert((volumeFile != NULL) || (ciftiFile != NULL)); const CaretMappableDataFile* caretMappableDataFile = dynamic_cast(volumeInterfaceFile); CaretAssert(caretMappableDataFile != NULL); if (volumeInterfaceFile == idVolumeFile) { if (iLoop != 0) { continue; } } else if (iLoop == 0) { continue; } int64_t vfI, vfJ, vfK; volumeInterfaceFile->enclosingVoxel(x, y, z, vfI, vfJ, vfK); if (volumeInterfaceFile->indexValid(vfI, vfJ, vfK)) { if (volumeFile != NULL) { AString boldText = caretMappableDataFile->getFileNameNoPath(); boldText += (" IJK (" + AString::number(vfI) + ", " + AString::number(vfJ) + ", " + AString::number(vfK) + ") "); AString text; const int32_t numMaps = caretMappableDataFile->getNumberOfMaps(); for (int jMap = 0; jMap < numMaps; jMap++) { if (jMap > 0) { text += " "; } if (volumeFile != NULL) { if (volumeFile->getType() == SubvolumeAttributes::LABEL) { const int32_t labelIndex = static_cast(volumeFile->getValue(vfI, vfJ, vfK, jMap)); const GiftiLabelTable* glt = volumeFile->getMapLabelTable(jMap); const GiftiLabel* gl = glt->getLabel(labelIndex); if (gl != NULL) { text += gl->getName(); } else { text += ("LABLE_MISSING_FOR_INDEX=" + AString::number(labelIndex)); } } else if (volumeFile->getType() == SubvolumeAttributes::RGB) { if (volumeFile->getNumberOfComponents() == 4) { text += ("RGBA(" + AString::number(volumeFile->getValue(vfI, vfJ, vfK, jMap, 0)) + "," + AString::number(volumeFile->getValue(vfI, vfJ, vfK, jMap, 1)) + "," + AString::number(volumeFile->getValue(vfI, vfJ, vfK, jMap, 2)) + "," + AString::number(volumeFile->getValue(vfI, vfJ, vfK, jMap, 3)) + ")"); } else if (volumeFile->getNumberOfComponents() == 3) { text += ("RGB(" + AString::number(volumeFile->getValue(vfI, vfJ, vfK, jMap, 0)) + "," + AString::number(volumeFile->getValue(vfI, vfJ, vfK, jMap, 1)) + "," + AString::number(volumeFile->getValue(vfI, vfJ, vfK, jMap, 2)) + ")"); } } else { text += AString::number(volumeFile->getValue(vfI, vfJ, vfK, jMap)); } } else if (ciftiFile != NULL) { } } if (dynamic_cast(volumeFile) != NULL) { boldText.insert(0, (DataFileTypeEnum::toOverlayTypeName(DataFileTypeEnum::VOLUME_DYNAMIC) + " ")); } idText.addLine(true, boldText, text); } else if (ciftiFile != NULL) { if (ciftiFile->isEmpty() == false) { const int numMaps = ciftiFile->getNumberOfMaps(); std::vector mapIndices; for (int32_t i = 0; i < numMaps; i++) { mapIndices.push_back(i); } /* * Limit dense scalar and data series to maps selected in the overlays * from all tabs. */ bool limitMapIndicesFlag = false; switch (ciftiFile->getDataFileType()) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: limitMapIndicesFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: limitMapIndicesFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: limitMapIndicesFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: limitMapIndicesFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: limitMapIndicesFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: break; case DataFileTypeEnum::METRIC: break; case DataFileTypeEnum::METRIC_DYNAMIC: break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: CaretAssert(0); break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: break; } if (limitMapIndicesFlag) { getMapIndicesOfFileUsedInOverlays(ciftiFile, mapIndices); } AString textValue; int64_t voxelIJK[3]; if (ciftiFile->getVolumeVoxelIdentificationForMaps(mapIndices, xyz, voxelIJK, textValue)) { AString boldText = (DataFileTypeEnum::toOverlayTypeName(ciftiFile->getDataFileType()) + " " + ciftiFile->getFileNameNoPath() + " IJK (" + AString::number(voxelIJK[0]) + ", " + AString::number(voxelIJK[1]) + ", " + AString::number(voxelIJK[2]) + ") "); idText.addLine(true, boldText, textValue); } } } } } } } /** * Generate identification text for a surface node identification. * @param idText * String builder for identification text. * @param brain * The brain. * @param browserTabContent * Content of the browser tab. * @param idSurfaceNode * Information for surface node ID. */ void IdentificationTextGenerator::generateSurfaceIdentificationText(IdentificationStringBuilder& idText, const Brain* brain, const SelectionItemSurfaceNode* idSurfaceNode) const { const Surface* surface = idSurfaceNode->getSurface(); const int32_t nodeNumber = idSurfaceNode->getNodeNumber(); if ((surface != NULL) && (nodeNumber >= 0)) { AString surfaceID; surfaceID += ("VERTEX " + StructureEnum::toGuiName(surface->getStructure())); idText.addLine(false, surfaceID, nodeNumber, false); const float* xyz = surface->getCoordinate(nodeNumber); idText.addLine(true, SurfaceTypeEnum::toGuiName(surface->getSurfaceType()).toUpper() + " XYZ: " + AString::number(xyz[0]) + ", " + AString::number(xyz[1]) + ", " + AString::number(xyz[2])); const BrainStructure* brainStructure = surface->getBrainStructure(); CaretAssert(brainStructure); std::vector allCiftiMappableDataFiles; brain->getAllCiftiMappableDataFiles(allCiftiMappableDataFiles); for (std::vector::iterator ciftiMapIter = allCiftiMappableDataFiles.begin(); ciftiMapIter != allCiftiMappableDataFiles.end(); ciftiMapIter++) { const CiftiMappableDataFile* cmdf = *ciftiMapIter; AString boldText = (DataFileTypeEnum::toOverlayTypeName(cmdf->getDataFileType()) + " " + cmdf->getFileNameNoPath()); std::vector mapIndices; for (int32_t i = 0; i < cmdf->getNumberOfMaps(); i++) { mapIndices.push_back(i); } /* * Limit dense scalar and data series to maps selected in the overlays * from all tabs. */ bool limitMapIndicesFlag = false; switch (cmdf->getDataFileType()) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: limitMapIndicesFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: limitMapIndicesFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: limitMapIndicesFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: limitMapIndicesFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: limitMapIndicesFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: break; case DataFileTypeEnum::METRIC: break; case DataFileTypeEnum::METRIC_DYNAMIC: break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: CaretAssert(0); break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: break; } if (limitMapIndicesFlag) { getMapIndicesOfFileUsedInOverlays(cmdf, mapIndices); } AString textValue; const bool valid = cmdf->getSurfaceNodeIdentificationForMaps(mapIndices, surface->getStructure(), nodeNumber, surface->getNumberOfNodes(), textValue); if (valid) { idText.addLine(true, boldText, textValue); } } const int32_t numLabelFiles = brainStructure->getNumberOfLabelFiles(); for (int32_t i = 0; i < numLabelFiles; i++) { const LabelFile* lf = brainStructure->getLabelFile(i); AString boldText = "LABEL " + lf->getFileNameNoPath(); AString text; const int numMaps = lf->getNumberOfMaps(); for (int32_t j = 0; j < numMaps; j++) { AString labelName = lf->getLabelName(nodeNumber, j); if (labelName.isEmpty()) { labelName = ("Map-" + AString::number(j + 1)); } text += (" " + labelName); } idText.addLine(true, boldText, text); } std::vector metricDynConFiles; const int32_t numMetricFiles = brainStructure->getNumberOfMetricFiles(); for (int32_t i = 0; i < numMetricFiles; i++) { const MetricFile* mf = brainStructure->getMetricFile(i); AString boldText = "METRIC " + mf->getFileNameNoPath(); AString text; const int numMaps = mf->getNumberOfMaps(); for (int32_t j = 0; j < numMaps; j++) { text += (" " + AString::number(mf->getValue(nodeNumber, j))); } idText.addLine(true, boldText, text); const MetricDynamicConnectivityFile* mdcf = mf->getMetricDynamicConnectivityFile(); if (mdcf != NULL) { if (mdcf->isDataValid()) { if (mdcf->isEnabledAsLayer()) { AString boldText = "METRIC DYNAMIC " + mdcf->getFileNameNoPath(); AString text; const int numMaps = mdcf->getNumberOfMaps(); for (int32_t j = 0; j < numMaps; j++) { text += (" " + AString::number(mdcf->getValue(nodeNumber, j))); } idText.addLine(true, boldText, text); } } } } } } /** * Find the usage of the file's maps in all overlays. * * @param caretMappableDataFile * The file whose usage is desired. * @param mapIndicesOut * Indices of maps of the file that are used in overlays. */ void IdentificationTextGenerator::getMapIndicesOfFileUsedInOverlays(const CaretMappableDataFile* caretMappableDataFile, std::vector& mapIndicesOut) const { mapIndicesOut.clear(); EventBrowserTabGetAll allTabsEvent; EventManager::get()->sendEvent(allTabsEvent.getPointer()); const std::vector allTabs = allTabsEvent.getAllBrowserTabs(); for (std::vector::const_iterator tabIter = allTabs.begin(); tabIter != allTabs.end(); tabIter++) { BrowserTabContent* tabContent = *tabIter; OverlaySet* overlaySet = tabContent->getOverlaySet(); if (overlaySet != NULL) { std::vector mapIndices; overlaySet->getSelectedMapIndicesForFile(caretMappableDataFile, false, // true => enabled overlays mapIndices); mapIndicesOut.insert(mapIndicesOut.end(), mapIndices.begin(), mapIndices.end()); } } /* * Sort and remove all duplicates */ if (mapIndicesOut.empty() == false) { std::sort(mapIndicesOut.begin(), mapIndicesOut.end()); std::vector::iterator uniqueIter = std::unique(mapIndicesOut.begin(), mapIndicesOut.end()); mapIndicesOut.resize(std::distance(mapIndicesOut.begin(), uniqueIter)); } } /** * Generate identification text for a data series chart. * @param idText * String builder for identification text. * @param idChartDataSeries * Information for chart id. */ void IdentificationTextGenerator::generateChartDataSeriesIdentificationText(IdentificationStringBuilder& idText, const SelectionItemChartDataSeries* idChartDataSeries) const { if (idChartDataSeries->isValid()) { const ChartDataCartesian* chartDataCartesian = idChartDataSeries->getChartDataCartesian(); const ChartDataSource* chartDataSource = chartDataCartesian->getChartDataSource(); generateChartDataSourceText(idText, "DATA SERIES CHART", chartDataSource); } } /** * Generate identification text for a data series chart. * @param idText * String builder for identification text. * @param idChartDataSeries * Information for chart id. */ void IdentificationTextGenerator::generateChartFrequencySeriesIdentificationText(IdentificationStringBuilder& idText, const SelectionItemChartFrequencySeries* idChartFrequencySeries) const { if (idChartFrequencySeries->isValid()) { const ChartDataCartesian* chartDataCartesian = idChartFrequencySeries->getChartDataCartesian(); const ChartDataSource* chartDataSource = chartDataCartesian->getChartDataSource(); generateChartDataSourceText(idText, "FREQUENCY SERIES CHART", chartDataSource); } } /** * Generate identification text for a matrix chart. * @param idText * String builder for identification text. * @param idChartMatrix * Information for matrix chart id. */ void IdentificationTextGenerator::generateChartMatrixIdentificationText(IdentificationStringBuilder& idText, const SelectionItemChartMatrix* idChartMatrix) const { if (idChartMatrix->isValid()) { const ChartableMatrixInterface* chartMatrixInterface = idChartMatrix->getChartableMatrixInterface(); const CaretMappableDataFile* caretMappableDataFile = chartMatrixInterface->getMatrixChartCaretMappableDataFile(); const int32_t rowIndex = idChartMatrix->getMatrixRowIndex(); const int32_t columnIndex = idChartMatrix->getMatrixColumnIndex(); AString rowName; AString columnName; AString cellValue; const bool validData = chartMatrixInterface->getMatrixCellAttributes(rowIndex, columnIndex, cellValue, rowName, columnName); AString boldText("MATRIX CHART"); idText.addLine(false, boldText, caretMappableDataFile->getFileNameNoPath()); if (validData) { idText.addLine(true, ("Row " + AString::number(rowIndex + 1)), rowName); idText.addLine(true, ("Column " + AString::number(columnIndex + 1)), columnName); idText.addLine(true, "Value", cellValue); } } } /** * Generate identification text for a chart two histogram. * * @param idText * String builder for identification text. * @param idChartTwoHistogram * Information for selected chart two histogram. */ void IdentificationTextGenerator::generateChartTwoHistogramIdentificationText(IdentificationStringBuilder& idText, const SelectionItemChartTwoHistogram* idChartTwoHistogram) const { const int32_t mapIndex = idChartTwoHistogram->getMapIndex(); const int32_t bucketIndex = idChartTwoHistogram->getBucketIndex(); const bool allMapsFlag = idChartTwoHistogram->isAllMapsSelected(); if (idChartTwoHistogram->isValid()) { ChartableTwoFileHistogramChart* fileHistogramChart = idChartTwoHistogram->getFileHistogramChart(); CaretAssert(fileHistogramChart); CaretMappableDataFile* mapFile = fileHistogramChart->getCaretMappableDataFile(); CaretAssert(mapFile); { ChartableTwoFileHistogramChart* chartingDelegate = mapFile->getChartingDelegate()->getHistogramCharting(); CaretAssert(chartingDelegate); const Histogram* histogram = chartingDelegate->getHistogramForChartDrawing(mapIndex, allMapsFlag); CaretAssert(histogram); float bucketValue = 0.0; float bucketHeight = 0.0; if (histogram->getHistogramDisplayBucketDataValueAndHeight(bucketIndex, bucketValue, bucketHeight)) { AString boldText("Histogram"); idText.addLine(false, boldText, mapFile->getFileNameNoPath()); idText.addLine(true, "Bucket Index", (AString::number(bucketIndex))); idText.addLine(true, "Data Value at Bucket", (AString::number(bucketValue))); const int64_t bucketHeightInteger = static_cast(bucketHeight); idText.addLine(true, "Bucket Count", (AString::number(bucketHeightInteger))); } } } } /** * Generate identification text for a chart two line-series. * * @param idText * String builder for identification text. * @param idChartTwoLineSeries * Information for selected chart two line-series. */ void IdentificationTextGenerator::generateChartTwoLineSeriesIdentificationText(IdentificationStringBuilder& idText, const SelectionItemChartTwoLineSeries* idChartTwoLineSeries) const { if (idChartTwoLineSeries->isValid()) { const ChartableTwoFileLineSeriesChart* fileLineSeriesChart = idChartTwoLineSeries->getFileLineSeriesChart(); CaretAssert(fileLineSeriesChart); const CaretMappableDataFile* mapFile = fileLineSeriesChart->getCaretMappableDataFile(); CaretAssert(mapFile); const ChartTwoDataCartesian* cartesianData = idChartTwoLineSeries->getChartTwoCartesianData(); CaretAssert(cartesianData); const MapFileDataSelector* mapFileDataSelector = cartesianData->getMapFileDataSelector(); CaretAssert(mapFileDataSelector); int32_t primitiveIndex = idChartTwoLineSeries->getLineSegmentIndex(); AString boldText("Line Chart"); idText.addLine(false, boldText, mapFile->getFileNameNoPath()); cartesianData->getGraphicsPrimitive(); const GraphicsPrimitive* primitive = cartesianData->getGraphicsPrimitive(); CaretAssert(primitive); if (primitiveIndex >= 1) { float xyz1[3]; primitive->getVertexFloatXYZ(primitiveIndex - 1, xyz1); float xyz2[3]; primitive->getVertexFloatXYZ(primitiveIndex, xyz2); idText.addLine(true, "XY Start", AString::fromNumbers(xyz1, 2, ", ")); idText.addLine(true, "XY End ", AString::fromNumbers(xyz2, 2, ", ")); } else { float xyz[3]; primitive->getVertexFloatXYZ(primitiveIndex, xyz); idText.addLine(true, "XY", AString::fromNumbers(xyz, 2, ", ")); } generateMapFileSelectorText(idText, mapFileDataSelector); } } /** * Generate identification text for a chart two matrix. * * @param idText * String builder for identification text. * @param idChartTwoMatrix * Information for selected chart two matrix. */ void IdentificationTextGenerator::generateChartTwoMatrixIdentificationText(IdentificationStringBuilder& idText, const SelectionItemChartTwoMatrix* idChartTwoMatrix) const { if (idChartTwoMatrix->isValid()) { const ChartableTwoFileMatrixChart* matrixChart = idChartTwoMatrix->getFileMatrixChart(); CaretAssert(matrixChart); const int32_t rowIndex = idChartTwoMatrix->getRowIndex(); const int32_t colIndex = idChartTwoMatrix->getColumnIndex(); const CaretMappableDataFile* mapFile = matrixChart->getCaretMappableDataFile(); CaretAssert(mapFile); const bool newIdFlag = true; if (newIdFlag) { AString boldText("MATRIX "); idText.addLine(false, boldText, mapFile->getFileNameNoPath()); if ((rowIndex >= 0) && (matrixChart->hasRowSelection())) { const AString rowName = matrixChart->getRowName(rowIndex); if ( ! rowName.isEmpty()) { idText.addLine(true, ("Row " + AString::number(rowIndex + 1)), rowName); } } if ((colIndex >= 0) && (matrixChart->hasColumnSelection())) { const AString colName = matrixChart->getColumnName(colIndex); if ( ! colName.isEmpty()) { idText.addLine(true, ("Column " + AString::number(colIndex + 1)), colName); } } } else { AString boldText("MATRIX ROW/COLUMN"); idText.addLine(false, boldText, mapFile->getFileNameNoPath()); const CiftiMappableConnectivityMatrixDataFile* matrixFile = dynamic_cast(mapFile); if (rowIndex >= 0) { const AString rowName = (matrixFile != NULL) ? (" " + matrixFile->getRowName(rowIndex + 1)) : ""; idText.addLine(true, "Row", (AString::number(rowIndex + 1) + rowName)); } if (colIndex >= 0) { const AString colName = (matrixFile != NULL) ? (" " + matrixFile->getColumnName(colIndex + 1)) : ""; idText.addLine(true, "Column", (AString::number(colIndex + 1) + colName)); } } } } /** * Generate identification text for a CIFTI Connectivity Matrix Row/Column * @param idText * String builder for identification text. * @param idCiftiConnMatrix * Information for CIFTI Connectivity Matrix Row/Column. */ void IdentificationTextGenerator::generateCiftiConnectivityMatrixIdentificationText(IdentificationStringBuilder& idText, const SelectionItemCiftiConnectivityMatrixRowColumn* idCiftiConnMatrix) const { if (idCiftiConnMatrix->isValid()) { const CiftiMappableConnectivityMatrixDataFile* connMatrixFile = idCiftiConnMatrix->getCiftiConnectivityMatrixFile(); const int32_t rowIndex = idCiftiConnMatrix->getMatrixRowIndex(); const int32_t colIndex = idCiftiConnMatrix->getMatrixColumnIndex(); AString boldText("MATRIX ROW/COLUMN"); idText.addLine(false, boldText, connMatrixFile->getFileNameNoPath()); AString rowName = " "; AString colName = " "; bool validData = true; if (validData) { if (rowIndex >= 0) { idText.addLine(true, ("Row " + AString::number(rowIndex + CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI())), rowName); } if (colIndex >= 0) { idText.addLine(true, ("Column " + AString::number(colIndex + CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI())), colName); } } } } /** * Generate identification text for chart data source. * @param idText * String builder for identification text. * @param typeOfChartText * Text describing the type of chart. * @param chartDataSource * Source of chart data. */ void IdentificationTextGenerator::generateChartDataSourceText(IdentificationStringBuilder& idText, const AString& typeOfChartText, const ChartDataSource* chartDataSource) const { AString chartFileName = chartDataSource->getChartableFileName(); if (! chartFileName.isEmpty()) { chartFileName = FileInformation(chartFileName).getFileName(); } idText.addLine(false, typeOfChartText, chartDataSource->getChartableFileName()); switch (chartDataSource->getDataSourceMode()) { case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_INVALID: break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_FILE_ROW: { AString fileName; int32_t rowIndex; chartDataSource->getFileRow(fileName, rowIndex); idText.addLine(true, "File", fileName); idText.addLine(true, "Row", AString::number(rowIndex + 1)); } break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDEX: { AString structureName; int32_t numberOfNodes; int32_t nodeIndex; chartDataSource->getSurfaceNode(structureName, numberOfNodes, nodeIndex); idText.addLine(true, "Structure", structureName); idText.addLine(true, "Vertex Index", AString::number(nodeIndex)); } break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDICES_AVERAGE: { AString structureName; int32_t numberOfNodes; std::vector nodeIndices; chartDataSource->getSurfaceNodeAverage(structureName, numberOfNodes, nodeIndices); idText.addLine(true, "Structure", structureName); idText.addLine(true, "Vertex Average Count", AString::number(nodeIndices.size())); } break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_VOXEL_IJK: { float voxelXYZ[3]; chartDataSource->getVolumeVoxel(voxelXYZ); idText.addLine(true, "Voxel XYZ", AString::fromNumbers(voxelXYZ, 3, ",")); } break; } } /** * Generate text for a map file data selector. * @param idText * String builder for identification text. * @param mapFileDataSelector * The map file data selector. */ void IdentificationTextGenerator::generateMapFileSelectorText(IdentificationStringBuilder& idText, const MapFileDataSelector* mapFileDataSelector) const { switch (mapFileDataSelector->getDataSelectionType()) { case MapFileDataSelector::DataSelectionType::INVALID: break; case MapFileDataSelector::DataSelectionType::COLUMN_DATA: { CaretMappableDataFile* mapFile = NULL; AString mapFileName; int32_t columnIndex = -1; mapFileDataSelector->getColumnIndex(mapFile, mapFileName, columnIndex); idText.addLine(true, "Column File", mapFileName); idText.addLine(true, "Column Index", AString::number(columnIndex + 1)); } break; case MapFileDataSelector::DataSelectionType::ROW_DATA: { CaretMappableDataFile* mapFile = NULL; AString mapFileName; int32_t rowIndex = -1; mapFileDataSelector->getRowIndex(mapFile, mapFileName, rowIndex); idText.addLine(true, "Row File", mapFileName); idText.addLine(true, "Row Index", AString::number(rowIndex + 1)); } break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: { StructureEnum::Enum structure = StructureEnum::INVALID; int32_t numberOfVertices = 0; int32_t vertexIndex = -1; mapFileDataSelector->getSurfaceVertex(structure, numberOfVertices, vertexIndex); if ((structure != StructureEnum::INVALID) && (vertexIndex >= 0)) { idText.addLine(true, "Structure", StructureEnum::toGuiName(structure)); idText.addLine(true, "Vertex Index", AString::number(vertexIndex)); } } break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTICES_AVERAGE: { StructureEnum::Enum structure = StructureEnum::INVALID; int32_t numberOfVertices = 0; std::vector vertexIndices; mapFileDataSelector->getSurfaceVertexAverage(structure, numberOfVertices, vertexIndices); const int32_t averageCount = static_cast(vertexIndices.size()); if ((structure != StructureEnum::INVALID) && (averageCount > 0)) { idText.addLine(true, "Structure", StructureEnum::toGuiName(structure)); idText.addLine(true, "Vertex Average Count", AString::number(averageCount)); } } break; case MapFileDataSelector::DataSelectionType::VOLUME_XYZ: { float voxelXYZ[3]; mapFileDataSelector->getVolumeVoxelXYZ(voxelXYZ); idText.addLine(true, "Voxel XYZ", AString::fromNumbers(voxelXYZ, 3, ",")); } break; } } /** * Generate identification text for a time series chart. * @param idText * String builder for identification text. * @param idChartTimeSeries * Information for chart id. */ void IdentificationTextGenerator::generateChartTimeSeriesIdentificationText(IdentificationStringBuilder& idText, const SelectionItemChartTimeSeries* idChartTimeSeries) const { if (idChartTimeSeries->isValid()) { const ChartDataCartesian* chartDataCartesian = idChartTimeSeries->getChartDataCartesian(); const ChartDataSource* chartDataSource = chartDataCartesian->getChartDataSource(); generateChartDataSourceText(idText, "TIME SERIES CHART", chartDataSource); } } /** * Generate identification text for a surface border identification. * @param idText * String builder for identification text. * @param idSurfaceBorder * Information for surface border ID. * @param toolTipFlag * True if this is for tooltip. */ void IdentificationTextGenerator::generateSurfaceBorderIdentifcationText(IdentificationStringBuilder& idText, const SelectionItemBorderSurface* idSurfaceBorder, const bool toolTipFlag) const { if (idSurfaceBorder->isValid()) { const Border* border = idSurfaceBorder->getBorder(); const SurfaceProjectedItem* spi = border->getPoint(idSurfaceBorder->getBorderPointIndex()); float xyz[3]; spi->getProjectedPosition(*idSurfaceBorder->getSurface(), xyz, false); if (toolTipFlag) { bool indentFlag = false; idText.addLine(indentFlag, "Border", border->getName()); indentFlag = true; idText.addLine(indentFlag, "XYZ", AString::fromNumbers(xyz, 3, ",")); } else { AString boldText = ("BORDER " + StructureEnum::toGuiName(spi->getStructure()) + " Name: " + border->getName()); if (border->getClassName().isEmpty() == false) { boldText += (" ClassName: " + border->getClassName() + ": "); } const AString text = ("(" + AString::number(idSurfaceBorder->getBorderIndex()) + "," + AString::number(idSurfaceBorder->getBorderPointIndex()) + ") (" + AString::fromNumbers(xyz, 3, ",") + ")"); idText.addLine(false, boldText, text); } } } /** * Generate identification text for a surface focus identification. * @param idText * String builder for identification text. * @param idSurfaceFocus * Information for surface focus ID. * @param toolTipFlag * True if this is for tooltip. */ void IdentificationTextGenerator::generateSurfaceFociIdentifcationText(IdentificationStringBuilder& idText, const SelectionItemFocusSurface* idSurfaceFocus, const bool toolTipFlag) const { if (idSurfaceFocus->isValid()) { const Focus* focus = idSurfaceFocus->getFocus(); const int32_t projectionIndex = idSurfaceFocus->getFocusProjectionIndex(); const SurfaceProjectedItem* spi = focus->getProjection(projectionIndex); float xyzStereo[3]; spi->getStereotaxicXYZ(xyzStereo); if (toolTipFlag) { bool indentFlag = false; idText.addLine(indentFlag, "Focus", focus->getName()); indentFlag = true; idText.addLine(indentFlag, "XYZ", (spi->isStereotaxicXYZValid() ? AString::fromNumbers(xyzStereo, 3, ",") : "Invalid")); } else { idText.addLine(false, "FOCUS", focus->getName()); idText.addLine(true, "Index", AString::number(idSurfaceFocus->getFocusIndex())); float xyzProj[3]; spi->getProjectedPosition(*idSurfaceFocus->getSurface(), xyzProj, false); idText.addLine(true, "Structure", StructureEnum::toGuiName(spi->getStructure())); if (spi->isStereotaxicXYZValid()) { idText.addLine(true, "XYZ (Stereotaxic)", xyzStereo, 3, true); } else { idText.addLine(true, "XYZ (Stereotaxic)", "Invalid"); } bool projValid = false; AString xyzProjName = "XYZ (Projected)"; if (spi->getBarycentricProjection()->isValid()) { xyzProjName = "XYZ (Projected to Triangle)"; projValid = true; } else if (spi->getVanEssenProjection()->isValid()) { xyzProjName = "XYZ (Projected to Edge)"; projValid = true; } if (projValid) { idText.addLine(true, xyzProjName, xyzProj, 3, true); } else { idText.addLine(true, xyzProjName, "Invalid"); } const int32_t numberOfProjections = focus->getNumberOfProjections(); for (int32_t i = 0; i < numberOfProjections; i++) { if (i != projectionIndex) { const SurfaceProjectedItem* proj = focus->getProjection(i); AString projTypeName = ""; if (proj->getBarycentricProjection()->isValid()) { projTypeName = "Triangle"; } else if (proj->getVanEssenProjection()->isValid()) { projTypeName = "Edge"; } if (projTypeName.isEmpty() == false) { const AString txt = (StructureEnum::toGuiName(proj->getStructure()) + " (" + projTypeName + ")"); idText.addLine(true, "Ambiguous Projection", txt); } } } idText.addLine(true, "Area", focus->getArea()); idText.addLine(true, "Class Name", focus->getClassName()); idText.addLine(true, "Comment", focus->getComment()); idText.addLine(true, "Extent", focus->getExtent(), true); idText.addLine(true, "Geography", focus->getGeography()); idText.addLine(true, "Region of Interest", focus->getRegionOfInterest()); idText.addLine(true, "Statistic", focus->getStatistic()); } } } /** * Generate identification text for a volume focus identification. * @param idText * String builder for identification text. * @param idVolumeFocus * Information for surface focus ID. */ void IdentificationTextGenerator::generateVolumeFociIdentifcationText(IdentificationStringBuilder& idText, const SelectionItemFocusVolume* idVolumeFocus) const { if (idVolumeFocus->isValid()) { const Focus* focus = idVolumeFocus->getFocus(); const SurfaceProjectedItem* spi = focus->getProjection(idVolumeFocus->getFocusProjectionIndex()); float xyzVolume[3]; spi->getVolumeXYZ(xyzVolume); float xyzStereo[3]; spi->getStereotaxicXYZ(xyzStereo); idText.addLine(false, "FOCUS", focus->getName()); idText.addLine(true, "Index", AString::number(idVolumeFocus->getFocusIndex())); idText.addLine(true, "Structure", StructureEnum::toGuiName(spi->getStructure())); if (spi->isStereotaxicXYZValid()) { idText.addLine(true, "XYZ (Stereotaxic)", xyzStereo, 3, true); } else { idText.addLine(true, "XYZ (Stereotaxic)", "Invalid"); } AString xyzVolumeName = "XYZ (Volume)"; idText.addLine(true, xyzVolumeName, xyzVolume, 3, true); idText.addLine(true, "Area", focus->getArea()); idText.addLine(true, "Class Name", focus->getClassName()); idText.addLine(true, "Comment", focus->getComment()); idText.addLine(true, "Extent", focus->getExtent(), true); idText.addLine(true, "Geography", focus->getGeography()); idText.addLine(true, "Region of Interest", focus->getRegionOfInterest()); idText.addLine(true, "Statistic", focus->getStatistic()); } } /** * Generate identification text for image identification. * @param idText * String builder for identification text. * @param idImage * Information for image ID. */ void IdentificationTextGenerator::generateImageIdentificationText(IdentificationStringBuilder& idText, const SelectionItemImage* idImage) const { if (idImage->isValid()) { AString text = ("Image " + idImage->getImageFile()->getFileNameNoPath() + " Pixel IJ (" + AString::number(idImage->getPixelI()) + "," + AString::number(idImage->getPixelJ()) + ")"); uint8_t pixelRGBA[4] = { 0, 0, 0, 0 }; idImage->getPixelRGBA(pixelRGBA); text.append(" RGBA (" + AString::fromNumbers(pixelRGBA, 4, ",") + ")"); idText.addLine(false, text); } } /** * Get text for the tooltip for a selected node. * * @param brain * The Brain. * @param browserTab * Browser tab in which tooltip is displayed * @param selectionManager * The selection manager. * @param dataToolTipsManager * The data tooltips manager * @param idText * String builder for identification text. */ void IdentificationTextGenerator::generateSurfaceToolTip(const Brain* brain, const BrowserTabContent* browserTab, const SelectionManager* selectionManager, const DataToolTipsManager* dataToolTipsManager, IdentificationStringBuilder& idText) const { const SelectionItemSurfaceNode* nodeSelection = selectionManager->getSurfaceNodeIdentification(); CaretAssert(nodeSelection); if (nodeSelection->isValid()) { const Surface* surface = nodeSelection->getSurface(); CaretAssert(surface); int32_t surfaceNumberOfNodes = surface->getNumberOfNodes(); int32_t surfaceNodeIndex = nodeSelection->getNodeNumber(); StructureEnum::Enum surfaceStructure = surface->getStructure(); bool indentFlag = false; if ((surfaceStructure != StructureEnum::INVALID) && (surfaceNumberOfNodes > 0) && (surfaceNodeIndex >= 0)) { bool addVertexFlag(false); bool showSurfaceFlag = dataToolTipsManager->isShowSurfaceViewed(); if (dataToolTipsManager->isShowSurfacePrimaryAnatomical()) { const Surface* anatSurface = brain->getPrimaryAnatomicalSurfaceForStructure(surfaceStructure); if (anatSurface != NULL) { if (anatSurface->getNumberOfNodes() == surfaceNumberOfNodes) { float xyz[3]; anatSurface->getCoordinate(surfaceNodeIndex, xyz); idText.addLine(indentFlag, "Vertex", AString::number(surfaceNodeIndex)); indentFlag = true; addVertexFlag = false; idText.addLine(indentFlag, "Anatomy Surface", AString::fromNumbers(xyz, 3, ", ", 'f', 2)); if (surface == anatSurface) { showSurfaceFlag = false; } } } } if (showSurfaceFlag) { float xyz[3]; surface->getCoordinate(surfaceNodeIndex, xyz); if (addVertexFlag) { idText.addLine(indentFlag, "Vertex", AString::number(surfaceNodeIndex)); indentFlag = true; } idText.addLine(indentFlag, (SurfaceTypeEnum::toGuiName(surface->getSurfaceType()) + " Surface"), AString::fromNumbers(xyz, 3, ", ")); } if (dataToolTipsManager->isShowTopEnabledLayer()) { OverlaySet* overlaySet = const_cast(browserTab->getOverlaySet()); CaretAssert(overlaySet); Overlay* overlay = getTopEnabledOverlay(overlaySet); if (overlay != NULL) { CaretMappableDataFile* mapFile(NULL); int32_t mapIndex(-1); overlay->getSelectionData(mapFile, mapIndex); if ((mapFile != NULL) && (mapIndex >= 0)) { std::vector mapIndices { mapIndex }; AString textValue; mapFile->getSurfaceNodeIdentificationForMaps(mapIndices, surfaceStructure, surfaceNodeIndex, surfaceNumberOfNodes, textValue); if ( ! textValue.isEmpty()) { idText.addLine(indentFlag, "Top Enabled Layer", textValue); } } } } } } if (dataToolTipsManager->isShowBorder()) { const SelectionItemBorderSurface* borderSelection = selectionManager->getSurfaceBorderIdentification(); CaretAssert(borderSelection); if (borderSelection->isValid()) { generateSurfaceBorderIdentifcationText(idText, borderSelection, true); // const BorderFile* borderFile = borderSelection->getBorderFile(); // const int32_t borderIndex = borderSelection->getBorderIndex(); // if ((borderFile != NULL) // && (borderIndex >= 0)) { // const Border* border = borderFile->getBorder(borderIndex); // if (border != NULL) { // text.appendWithNewLine("Border: " // + border->getName()); // } // } } } if (dataToolTipsManager->isShowFocus()) { const SelectionItemFocusSurface* focusSelection = selectionManager->getSurfaceFocusIdentification(); CaretAssert(focusSelection); if (focusSelection->isValid()) { generateSurfaceFociIdentifcationText(idText, focusSelection, true); // const FociFile* fociFile = focusSelection->getFociFile(); // const int32_t focusIndex = focusSelection->getFocusIndex(); // if ((fociFile != NULL) // && (focusIndex >= 0)) { // const Focus* focus = fociFile->getFocus(focusIndex); // if (focus != NULL) { // text.appendWithNewLine("Focus: " // + focus->getName()); // } // } } } } /** * Get text for the tooltip for a selected node. * * @param browserTab * Browser tab in which tooltip is displayed * @param selectionManager * The selection manager. * @param dataToolTipsManager * The data tooltips manager * @param idText * String builder for identification text. */ void IdentificationTextGenerator::generateVolumeToolTip(const BrowserTabContent* browserTab, const SelectionManager* selectionManager, const DataToolTipsManager* dataToolTipsManager, IdentificationStringBuilder& idText) const { const SelectionItemVoxel* voxelSelection = selectionManager->getVoxelIdentification(); OverlaySet* overlaySet = const_cast(browserTab->getOverlaySet()); CaretAssert(overlaySet); double selectionXYZ[3]; voxelSelection->getModelXYZ(selectionXYZ); float xyz[3] { static_cast(selectionXYZ[0]), static_cast(selectionXYZ[1]), static_cast(selectionXYZ[2]) }; bool indentFlag = false; if (dataToolTipsManager->isShowVolumeUnderlay()) { Overlay* volumeUnderlay = overlaySet->getUnderlayContainingVolume(); if (volumeUnderlay != NULL) { CaretMappableDataFile* mapFile = NULL; int32_t mapIndex(-1); volumeUnderlay->getSelectionData(mapFile, mapIndex); VolumeMappableInterface* underlayVolumeInterface = NULL; if (mapFile != NULL) { underlayVolumeInterface = dynamic_cast(mapFile); CaretAssert(underlayVolumeInterface == overlaySet->getUnderlayVolume()); } if (underlayVolumeInterface != NULL) { /* * Update IJK and XYZ since selection XYZ may be * a different volume file. */ int64_t selectionIJK[3]; voxelSelection->getVoxelIJK(selectionIJK); int64_t ijk[3] { selectionIJK[0], selectionIJK[1], selectionIJK[2] }; bool validFlag(false); const float value = underlayVolumeInterface->getVoxelValue(xyz[0], xyz[1], xyz[2], &validFlag, mapIndex); if (validFlag) { underlayVolumeInterface->enclosingVoxel(xyz[0], xyz[1], xyz[2], ijk[0], ijk[1], ijk[2]); underlayVolumeInterface->indexToSpace(ijk, xyz); idText.addLine(indentFlag, "Underlay Value", AString::number(value, 'f')); indentFlag = true; idText.addLine(indentFlag, "IJK: ", AString::fromNumbers(ijk, 3, ", ")); idText.addLine(indentFlag, "XYZ", AString::fromNumbers(xyz, 3, ", ", 'f', 1)); } } } } if (dataToolTipsManager->isShowTopEnabledLayer()) { Overlay* overlay = getTopEnabledOverlay(overlaySet); if (overlay != NULL) { CaretMappableDataFile* mapFile(NULL); int32_t mapIndex(-1); overlay->getSelectionData(mapFile, mapIndex); if ((mapFile != NULL) && (mapIndex >= 0)) { std::vector mapIndices { mapIndex }; AString textValue; int64_t ijk[3]; mapFile->getVolumeVoxelIdentificationForMaps(mapIndices, xyz, ijk, textValue); if ( ! textValue.isEmpty()) { idText.addLine(indentFlag, ("Top Enabled Layer: " + textValue)); } } } } } /** * @return Get the top-most enabled overlay. NULL if no overlays enabled * * @param overlaySet * Overlay set for overlay. */ Overlay* IdentificationTextGenerator::getTopEnabledOverlay(OverlaySet* overlaySet) const { CaretAssert(overlaySet); const int32_t numberOfOverlays = overlaySet->getNumberOfDisplayedOverlays(); for (int32_t i = 0; i < numberOfOverlays; i++) { Overlay* overlay = overlaySet->getOverlay(i); CaretAssert(overlay); if (overlay->isEnabled()) { return overlay; } } return NULL; } /** * Get text for the tooltip for a selected node. * * @param selectionManager * The selection manager. * @param dataToolTipsManager * The data tooltips manager * @param idText * String builder for identification text. */ void IdentificationTextGenerator::generateChartToolTip(const SelectionManager* selectionManager, const DataToolTipsManager* dataToolTipsManager, IdentificationStringBuilder& idText) const { if (dataToolTipsManager->isShowChart()) { this->generateChartTwoHistogramIdentificationText(idText, selectionManager->getChartTwoHistogramIdentification()); this->generateChartTwoLineSeriesIdentificationText(idText, selectionManager->getChartTwoLineSeriesIdentification()); this->generateChartTwoMatrixIdentificationText(idText, selectionManager->getChartTwoMatrixIdentification()); } } /** * Get a description of this object's content. * @return String describing this object's content. */ AString IdentificationTextGenerator::toString() const { return "IdentificationTextGenerator"; } connectome-workbench-1.4.2/src/Brain/IdentificationTextGenerator.h000066400000000000000000000172431360521144700253020ustar00rootroot00000000000000#ifndef __IDENTIFICATION_TEXT_GENERATOR__H_ #define __IDENTIFICATION_TEXT_GENERATOR__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" namespace caret { class Brain; class BrowserTabContent; class CaretMappableDataFile; class ChartDataSource; class DataToolTipsManager; class MapFileDataSelector; class Overlay; class OverlaySet; class SelectionItemBorderSurface; class SelectionItemChartDataSeries; class SelectionItemChartFrequencySeries; class SelectionItemChartMatrix; class SelectionItemChartTwoHistogram; class SelectionItemChartTwoLineSeries; class SelectionItemChartTwoMatrix; class SelectionItemCiftiConnectivityMatrixRowColumn; class SelectionItemChartTimeSeries; class SelectionItemFocusSurface; class SelectionItemFocusVolume; class SelectionItemImage; class SelectionItemSurfaceNode; class SelectionItemVoxel; class SelectionManager; class IdentificationStringBuilder; class IdentificationTextGenerator : public CaretObject { public: IdentificationTextGenerator(); virtual ~IdentificationTextGenerator(); AString createIdentificationText(const SelectionManager* idManager, const Brain* brain) const; AString createToolTipText(const Brain* brain, const BrowserTabContent* browserTab, const SelectionManager* selectionManager, const DataToolTipsManager* dataToolTipsManager) const; private: IdentificationTextGenerator(const IdentificationTextGenerator&); IdentificationTextGenerator& operator=(const IdentificationTextGenerator&); public: virtual AString toString() const; private: void generateSurfaceToolTip(const Brain* brain, const BrowserTabContent* browserTab, const SelectionManager* selectionManager, const DataToolTipsManager* dataToolTipsManager, IdentificationStringBuilder& idText) const; void generateVolumeToolTip(const BrowserTabContent* browserTab, const SelectionManager* selectionManager, const DataToolTipsManager* dataToolTipsManager, IdentificationStringBuilder& idText) const; void generateChartToolTip(const SelectionManager* selectionManager, const DataToolTipsManager* dataToolTipsManager, IdentificationStringBuilder& idText) const; void generateSurfaceBorderIdentifcationText(IdentificationStringBuilder& idText, const SelectionItemBorderSurface* idSurfaceBorder, const bool toolTipFlag) const; void generateSurfaceFociIdentifcationText(IdentificationStringBuilder& idText, const SelectionItemFocusSurface* idSurfaceFocus, const bool toolTipFlag) const; void generateVolumeFociIdentifcationText(IdentificationStringBuilder& idText, const SelectionItemFocusVolume* idVolumeFocus) const; void generateSurfaceIdentificationText(IdentificationStringBuilder& idText, const Brain* brain, const SelectionItemSurfaceNode* idSurfaceNode) const; void generateImageIdentificationText(IdentificationStringBuilder& idText, const SelectionItemImage* idImage) const; void generateVolumeIdentificationText(IdentificationStringBuilder& idText, const Brain* brain, const SelectionItemVoxel* idVolumeVoxel) const; void generateChartDataSeriesIdentificationText(IdentificationStringBuilder& idText, const SelectionItemChartDataSeries* idChartDataSeries) const; void generateChartFrequencySeriesIdentificationText(IdentificationStringBuilder& idText, const SelectionItemChartFrequencySeries* idChartFrequencySeries) const; void generateChartMatrixIdentificationText(IdentificationStringBuilder& idText, const SelectionItemChartMatrix* idChartMatrix) const; void generateChartTwoHistogramIdentificationText(IdentificationStringBuilder& idText, const SelectionItemChartTwoHistogram* idChartTwoHistogram) const; void generateChartTwoLineSeriesIdentificationText(IdentificationStringBuilder& idText, const SelectionItemChartTwoLineSeries* idChartTwoLineSeries) const; void generateChartTwoMatrixIdentificationText(IdentificationStringBuilder& idText, const SelectionItemChartTwoMatrix* idChartTwoMatrix) const; void generateCiftiConnectivityMatrixIdentificationText(IdentificationStringBuilder& idText, const SelectionItemCiftiConnectivityMatrixRowColumn* idCiftiConnMatrix) const; void generateChartTimeSeriesIdentificationText(IdentificationStringBuilder& idText, const SelectionItemChartTimeSeries* idChartTimeSeries) const; void getMapIndicesOfFileUsedInOverlays(const CaretMappableDataFile* caretMappableDataFile, std::vector& mapIndicesOut) const; void generateChartDataSourceText(IdentificationStringBuilder& idText, const AString& typeOfChartText, const ChartDataSource* chartDataSource) const; void generateMapFileSelectorText(IdentificationStringBuilder& idText, const MapFileDataSelector* mapFileDataSelector) const; Overlay* getTopEnabledOverlay(OverlaySet* overlaySet) const; friend class DataToolTipsManager; }; #ifdef __IDENTIFICATION_TEXT_GENERATOR_DECLARE__ // #endif // __IDENTIFICATION_TEXT_GENERATOR_DECLARE__ } // namespace #endif //__IDENTIFICATION_TEXT_GENERATOR__H_ connectome-workbench-1.4.2/src/Brain/IdentificationWithColor.cxx000066400000000000000000000125751360521144700247770ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __IDENTIFICATION_WITH_COLOR_DECLARE__ #include "IdentificationWithColor.h" #undef __IDENTIFICATION_WITH_COLOR_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class IdentificationWithColor * \brief Assists with identification of items using colors. * * To perform identification of items, an identifier * is encoded as RGB colors. The color present at * the location of identification is then decoded * to recover the identifier. * * Since there can be many items, this class * should be used once for each type of item. */ /** * Constructor. */ IdentificationWithColor::IdentificationWithColor() : CaretObject() { this->itemCounter = 0; this->items.reserve(250000); } /** * Destructor. */ IdentificationWithColor::~IdentificationWithColor() { } /** * Gets an RGB color that is associated with the * specified indices. * @param rgb * Output color components. * @param dataType * Type of data. * @param index1 * First index of item. * @param index2 * Optional second index of item. * @param index3 * Optional third index of item. */ void IdentificationWithColor::addItem(uint8_t rgbOut[4], const SelectionItemDataTypeEnum::Enum dataType, const int32_t index1, const int32_t index2, const int32_t index3) { if (this->itemCounter >= static_cast(this->items.size())) { this->items.push_back(Item()); } IdentificationWithColor::encodeIntegerIntoRGB(this->itemCounter, rgbOut); rgbOut[3] = 255; Item& item = this->items[this->itemCounter]; item.dataType = dataType; item.rgb[0] = rgbOut[0]; item.rgb[1] = rgbOut[1]; item.rgb[2] = rgbOut[2]; item.index1 = index1; item.index2 = index2; item.index3 = index3; itemCounter++; } /** * Gets indices associated with an RGB color. * @param rgbOut * Output color components. * @param dataType * Type of data. * @param index1Out * Set to first index of item. * @param index2 * Set to second index of item. This paramter * may be NULL; * @param index3 * Set to third index of item. This paramter * may be NULL; */ void IdentificationWithColor::getItem(const uint8_t rgb[4], const SelectionItemDataTypeEnum::Enum dataType, int32_t* index1Out, int32_t* index2Out, int32_t* index3Out) const { CaretAssert(index1Out); const int32_t integerValue = IdentificationWithColor::decodeIntegerFromRGB(rgb); *index1Out = -1; if (index2Out != NULL) { *index2Out = -1; } if (index3Out != NULL) { *index3Out = -1; } if ((integerValue < 0) || (integerValue >= this->itemCounter)) { return; } const Item& item = this->items[integerValue]; if (dataType == item.dataType) { *index1Out = item.index1; if (index2Out != NULL) { *index2Out = item.index2; } if (index3Out != NULL) { *index3Out = item.index3; } } } /** * Reset for a new round of identification. * @param estimatedNumberOfItems * The estimated number of items. Must be non-negative * and can improve performance if greater than or equal * to the number of items. */ void IdentificationWithColor::reset(const int32_t estimatedNumberOfItems) { this->itemCounter = 0; if (estimatedNumberOfItems > static_cast(this->items.size())) { this->items.reserve(estimatedNumberOfItems); } } /** * Encode an integer as RGB values. * @param integerValue * Integer value. * @param rgbOut * Output RGB. */ void IdentificationWithColor::encodeIntegerIntoRGB(const int32_t integerValue, uint8_t rgbOut[3]) { rgbOut[2] = (uint8_t)(integerValue & 0xff); rgbOut[1] = (uint8_t)((integerValue >> 8) & 0xff); rgbOut[0] = (uint8_t)((integerValue >> 16) & 0xff); } /** * Decode an integer from RGB values. * @param rgb * RGB value. * @return The integer value. */ int32_t IdentificationWithColor::decodeIntegerFromRGB(const uint8_t rgb[3]) { int32_t r = rgb[0] & 0xff; int32_t g = rgb[1] & 0xff; int32_t b = rgb[2] & 0xff; int32_t colorValue = (r << 16) + (g << 8) + b; return colorValue; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString IdentificationWithColor::toString() const { return "IdentificationWithColor"; } connectome-workbench-1.4.2/src/Brain/IdentificationWithColor.h000066400000000000000000000053441360521144700244200ustar00rootroot00000000000000#ifndef __IDENTIFICATION_WITH_COLOR__H_ #define __IDENTIFICATION_WITH_COLOR__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "SelectionItemDataTypeEnum.h" namespace caret { class IdentificationWithColor : public CaretObject { public: IdentificationWithColor(); virtual ~IdentificationWithColor(); void addItem(uint8_t rgbOut[4], const SelectionItemDataTypeEnum::Enum dataType, const int32_t index1, const int32_t index2 = -1, const int32_t index3 = -1); void getItem(const uint8_t rgb[4], const SelectionItemDataTypeEnum::Enum dataType, int32_t* index1Out, int32_t* index2Out = NULL, int32_t* index3Out = NULL) const; void reset(const int32_t estimatedNumberOfItems = -1); private: IdentificationWithColor(const IdentificationWithColor&); IdentificationWithColor& operator=(const IdentificationWithColor&); static void encodeIntegerIntoRGB(const int32_t integerValue, uint8_t rgbOut[3]); static int32_t decodeIntegerFromRGB(const uint8_t rgb[3]); public: virtual AString toString() const; private: class Item { public: SelectionItemDataTypeEnum::Enum dataType; uint8_t rgb[3]; int32_t index1; int32_t index2; int32_t index3; }; std::vector items; int32_t itemCounter; }; #ifdef __IDENTIFICATION_WITH_COLOR_DECLARE__ // #endif // __IDENTIFICATION_WITH_COLOR_DECLARE__ } // namespace #endif //__IDENTIFICATION_WITH_COLOR__H_ connectome-workbench-1.4.2/src/Brain/IdentifiedItem.cxx000066400000000000000000000134341360521144700230710ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __IDENTIFIED_ITEM_DECLARE__ #include "IdentifiedItem.h" #undef __IDENTIFIED_ITEM_DECLARE__ #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::IdentifiedItem * \brief Describes an identified item. */ /** * Constructor. * */ IdentifiedItem::IdentifiedItem() : CaretObject() { initializeMembers(); } /** * Constructor. * * @param text * Text describing the identified item. */ IdentifiedItem::IdentifiedItem(const AString& text) : CaretObject() { initializeMembers(); m_text = text; } /** * Destructor. */ IdentifiedItem::~IdentifiedItem() { delete m_sceneAssistant; } /** * Copy constructor. * @param obj * Object that is copied. */ IdentifiedItem::IdentifiedItem(const IdentifiedItem& obj) : CaretObject(obj), SceneableInterface() { this->initializeMembers(); this->copyHelperIdentifiedItem(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ IdentifiedItem& IdentifiedItem::operator=(const IdentifiedItem& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperIdentifiedItem(obj); } return *this; } /** * Initialize a new instance of this class. */ void IdentifiedItem::initializeMembers() { m_text.clear(); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_text", &m_text); } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void IdentifiedItem::copyHelperIdentifiedItem(const IdentifiedItem& obj) { m_text = obj.m_text; } /** * @return Is this item valid? Typically only used when restoring * from scene. */ bool IdentifiedItem::isValid() const { if (m_text.isEmpty() == false) { return true; } return false; } /** * Append text to this item's text. */ void IdentifiedItem::appendText(const AString& text) { m_text += text; } /** * Clear the text for this item. */ void IdentifiedItem::clearText() { m_text = ""; } /** * @return The text describing the identified item. */ AString IdentifiedItem::getText() const { return m_text; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString IdentifiedItem::toString() const { return ("m_text=" + m_text); } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* IdentifiedItem::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "IdentifiedItem", 1); saveMembers(sceneAttributes, sceneClass); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. May be NULL for some types of scenes. */ void IdentifiedItem::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } restoreMembers(sceneAttributes, sceneClass); } /** * Restore members (protected function for derived classes). * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. */ void IdentifiedItem::restoreMembers(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } /** * Save members (protected function for derived classes). * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. */ void IdentifiedItem::saveMembers(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } connectome-workbench-1.4.2/src/Brain/IdentifiedItem.h000066400000000000000000000052011360521144700225070ustar00rootroot00000000000000#ifndef __IDENTIFIED_ITEM_H__ #define __IDENTIFIED_ITEM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "SceneableInterface.h" namespace caret { class SceneClassAssistant; class IdentifiedItem : public CaretObject, public SceneableInterface { public: IdentifiedItem(); IdentifiedItem(const AString& text); virtual ~IdentifiedItem(); IdentifiedItem(const IdentifiedItem& obj); IdentifiedItem& operator=(const IdentifiedItem& obj); // ADD_NEW_METHODS_HERE virtual bool isValid() const; void appendText(const AString& text); void clearText(); AString getText() const; virtual AString toString() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); protected: virtual void restoreMembers(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); virtual void saveMembers(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); private: void copyHelperIdentifiedItem(const IdentifiedItem& obj); void initializeMembers(); // ADD_NEW_MEMBERS_HERE AString m_text; SceneClassAssistant* m_sceneAssistant; friend class IdentificationManager; }; #ifdef __IDENTIFIED_ITEM_DECLARE__ // #endif // __IDENTIFIED_ITEM_DECLARE__ } // namespace #endif //__IDENTIFIED_ITEM_H__ connectome-workbench-1.4.2/src/Brain/IdentifiedItemNode.cxx000066400000000000000000000251321360521144700236750ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __IDENTIFIED_ITEM_NODE_DECLARE__ #include "IdentifiedItemNode.h" #undef __IDENTIFIED_ITEM_NODE_DECLARE__ #include "CaretPreferences.h" #include "SceneAttributes.h" #include "SceneClassAssistant.h" #include "SessionManager.h" using namespace caret; /** * \class caret::IdentifiedItem * \brief Describes an identified item. */ /** * Constructor. * * @param text * Text describing the identified item. * @param structure * Structure on which identification took place. * @param contralateralStructure * Contralateral of identification structure. * @param surfaceNumberOfNodes * Number of nodes in the surface on which identification took place. * @param nodeIndex * Index of node that was identified. * */ IdentifiedItemNode::IdentifiedItemNode() : IdentifiedItem() { initializeMembers(); } /** * Constructor. * * @param text * Text describing the identified item. * @param structure * Structure on which identification took place. * @param contralateralStructure * Contralateral of identification structure. * @param surfaceNumberOfNodes * Number of nodes in the surface on which identification took place. * @param nodeIndex * Index of node that was identified. * */ IdentifiedItemNode::IdentifiedItemNode(const AString& text, const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const int32_t nodeIndex) : IdentifiedItem(text) { initializeMembers(); m_structure = structure; m_surfaceNumberOfNodes = surfaceNumberOfNodes, m_nodeIndex = nodeIndex; } /** * Destructor. */ IdentifiedItemNode::~IdentifiedItemNode() { delete m_sceneAssistant; } /** * Copy constructor. * @param obj * Object that is copied. */ IdentifiedItemNode::IdentifiedItemNode(const IdentifiedItemNode& obj) : IdentifiedItem(obj) { initializeMembers(); this->copyHelperIdentifiedItemNode(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ IdentifiedItemNode& IdentifiedItemNode::operator=(const IdentifiedItemNode& obj) { if (this != &obj) { IdentifiedItem::operator=(obj); this->copyHelperIdentifiedItemNode(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void IdentifiedItemNode::copyHelperIdentifiedItemNode(const IdentifiedItemNode& obj) { m_structure = obj.m_structure; m_contralateralStructure = obj.m_contralateralStructure; m_surfaceNumberOfNodes = obj.m_surfaceNumberOfNodes; m_nodeIndex = obj.m_nodeIndex; m_symbolRGB[0] = obj.m_symbolRGB[0]; m_symbolRGB[1] = obj.m_symbolRGB[1]; m_symbolRGB[2] = obj.m_symbolRGB[2]; m_contralateralSymbolRGB[0] = obj.m_contralateralSymbolRGB[0]; m_contralateralSymbolRGB[1] = obj.m_contralateralSymbolRGB[1]; m_contralateralSymbolRGB[2] = obj.m_contralateralSymbolRGB[2]; m_symbolSize = obj.m_symbolSize; } /** * Initialize members of this class. */ void IdentifiedItemNode::initializeMembers() { m_structure = StructureEnum::INVALID; m_contralateralStructure = StructureEnum::INVALID; m_surfaceNumberOfNodes = -1, m_nodeIndex = -1; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_structure", &m_structure); m_sceneAssistant->add("m_contralateralStructure", &m_contralateralStructure); m_sceneAssistant->add("m_surfaceNumberOfNodes", &m_surfaceNumberOfNodes); m_sceneAssistant->add("m_nodeIndex", &m_nodeIndex); m_sceneAssistant->addArray("m_symbolRGB", m_symbolRGB, 3, 0); m_sceneAssistant->addArray("m_contralateralSymbolRGB", m_contralateralSymbolRGB, 3, 0); m_sceneAssistant->add("m_symbolSize", &m_symbolSize); } /** * @return Is this item valid? Typically only used when restoring * from scene. */ bool IdentifiedItemNode::isValid() const { if (m_structure == StructureEnum::INVALID) { return false; } if (m_surfaceNumberOfNodes <= 0) { return false; } if (m_nodeIndex < 0) { return false; } return true; } /** * @return The structure for the identified node. */ StructureEnum::Enum IdentifiedItemNode::getStructure() const { return m_structure; } /** * @return The contralateral structure of the identified node. */ StructureEnum::Enum IdentifiedItemNode::getContralateralStructure() const { return m_contralateralStructure; } /** * Set the contralateral structure. * @param contralateralStructure * The contralateral structure. */ void IdentifiedItemNode::setContralateralStructure(const StructureEnum::Enum contralateralStructure) { m_contralateralStructure = contralateralStructure; } /** * @return The number of nodes in the surface on which identification took place. */ int32_t IdentifiedItemNode::getSurfaceNumberOfNodes() const { return m_surfaceNumberOfNodes; } /** * @return The index of the surface node that was identified. */ int32_t IdentifiedItemNode::getNodeIndex() const { return m_nodeIndex; } /** * @return The color for the symbol's identification symbol. */ const float* IdentifiedItemNode::getSymbolRGB() const { return m_symbolRGB; } /** * @return The color for the symbol's identification symbol on the * contralateral surface. */ const float* IdentifiedItemNode::getContralateralSymbolRGB() const { return m_contralateralSymbolRGB; } /** * Get color for the identification symbol. * * @param rgbaOut * RGBA ranging 0 to 255. */ void IdentifiedItemNode::getSymbolRGBA(uint8_t rgbaOut[4]) const { rgbaOut[0] = static_cast(m_symbolRGB[0] * 255.0); rgbaOut[1] = static_cast(m_symbolRGB[1] * 255.0); rgbaOut[2] = static_cast(m_symbolRGB[2] * 255.0); rgbaOut[3] = 255; } /** * Get color for the contralateral identification symbol. * * @param rgbaOut * RGBA ranging 0 to 255. */ void IdentifiedItemNode::getContralateralSymbolRGB(uint8_t rgbaOut[4]) const { rgbaOut[0] = static_cast(m_contralateralSymbolRGB[0] * 255.0); rgbaOut[1] = static_cast(m_contralateralSymbolRGB[1] * 255.0); rgbaOut[2] = static_cast(m_contralateralSymbolRGB[2] * 255.0); rgbaOut[3] = 255; } /** * @return The size of the symbol. */ float IdentifiedItemNode::getSymbolSize() const { return m_symbolSize; } /** * Set the color for the identification symbol. * * @param rgb * Red, green, blue color components for identification system. */ void IdentifiedItemNode::setSymbolRGB(const float* rgb) { m_symbolRGB[0] = rgb[0]; m_symbolRGB[1] = rgb[1]; m_symbolRGB[2] = rgb[2]; } /** * Set the color for the contralateral identification symbol. * * @param rgb * Red, green, blue color components for identification system. */ void IdentifiedItemNode::setContralateralSymbolRGB(const float* rgb) { m_contralateralSymbolRGB[0] = rgb[0]; m_contralateralSymbolRGB[1] = rgb[1]; m_contralateralSymbolRGB[2] = rgb[2]; } /** * Set the size of the identification symbol. * * @param symbolSize * Size of identification symbol. */ void IdentifiedItemNode::setSymbolSize(const float symbolSize) { m_symbolSize = symbolSize; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString IdentifiedItemNode::toString() const { const AString s = (IdentifiedItem::toString() + ", m_structure=" + StructureEnum::toName(m_structure) + ", m_contralateralStructure=" + StructureEnum::toName(m_contralateralStructure) + ", m_surfaceNumberOfNodes=" + AString::number(m_surfaceNumberOfNodes) + ", m_nodeIndex=" + AString::number(m_nodeIndex)); return s; } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* IdentifiedItemNode::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } SceneClass* sceneClass = new SceneClass(instanceName, "IdentifiedItemNode", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); /* * Save data in parent class.+ */ saveMembers(sceneAttributes, sceneClass); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. May be NULL for some types of scenes. */ void IdentifiedItemNode::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); /* * Restores data in parent class. */ restoreMembers(sceneAttributes, sceneClass); } connectome-workbench-1.4.2/src/Brain/IdentifiedItemNode.h000066400000000000000000000067621360521144700233320ustar00rootroot00000000000000#ifndef __IDENTIFIED_ITEM_NODE_H__ #define __IDENTIFIED_ITEM_NODE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "IdentifiedItem.h" #include "StructureEnum.h" namespace caret { class IdentifiedItemNode : public IdentifiedItem { public: IdentifiedItemNode(); IdentifiedItemNode(const AString& text, const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const int32_t nodeIndex); virtual ~IdentifiedItemNode(); IdentifiedItemNode(const IdentifiedItemNode& obj); IdentifiedItemNode& operator=(const IdentifiedItemNode& obj); // ADD_NEW_METHODS_HERE virtual bool isValid() const; // AString getText() const; StructureEnum::Enum getStructure() const; StructureEnum::Enum getContralateralStructure() const; void setContralateralStructure(const StructureEnum::Enum contralateralStructure); int32_t getSurfaceNumberOfNodes() const; int32_t getNodeIndex() const; const float* getSymbolRGB() const; const float* getContralateralSymbolRGB() const; void getSymbolRGBA(uint8_t rgbaOut[4]) const; void getContralateralSymbolRGB(uint8_t rgbaOut[4]) const; float getSymbolSize() const; void setSymbolRGB(const float* rgb); void setContralateralSymbolRGB(const float* rgb); void setSymbolSize(const float symbolSize); virtual AString toString() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: void copyHelperIdentifiedItemNode(const IdentifiedItemNode& obj); void initializeMembers(); // ADD_NEW_MEMBERS_HERE StructureEnum::Enum m_structure; StructureEnum::Enum m_contralateralStructure; int32_t m_surfaceNumberOfNodes; int32_t m_nodeIndex; float m_symbolRGB[3]; float m_contralateralSymbolRGB[3]; float m_symbolSize; SceneClassAssistant* m_sceneAssistant; }; #ifdef __IDENTIFIED_ITEM_NODE_DECLARE__ // #endif // __IDENTIFIED_ITEM_NODE_DECLARE__ } // namespace #endif //__IDENTIFIED_ITEM_NODE_H__ connectome-workbench-1.4.2/src/Brain/IdentifiedItemVoxel.cxx000066400000000000000000000160641360521144700241110ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __IDENTIFIED_ITEM_VOXEL_DECLARE__ #include "IdentifiedItemVoxel.h" #undef __IDENTIFIED_ITEM_VOXEL_DECLARE__ #include "CaretAssert.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "SessionManager.h" using namespace caret; /** * \class caret::IdentifiedItemVoxel * \brief Identified voxel. * \ingroup Brain */ /** * Constructor. */ IdentifiedItemVoxel::IdentifiedItemVoxel() : IdentifiedItem() { initializeMembers(); } /** * Constructor. */ IdentifiedItemVoxel::IdentifiedItemVoxel(const AString& text, const float xyz[3]) : IdentifiedItem(text) { initializeMembers(); m_xyz[0] = xyz[0]; m_xyz[1] = xyz[1]; m_xyz[2] = xyz[2]; } /** * Destructor. */ IdentifiedItemVoxel::~IdentifiedItemVoxel() { delete m_sceneAssistant; } /** * Copy constructor. * @param obj * Object that is copied. */ IdentifiedItemVoxel::IdentifiedItemVoxel(const IdentifiedItemVoxel& obj) : IdentifiedItem(obj) { initializeMembers(); this->copyHelperIdentifiedItemVoxel(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ IdentifiedItemVoxel& IdentifiedItemVoxel::operator=(const IdentifiedItemVoxel& obj) { if (this != &obj) { IdentifiedItem::operator=(obj); this->copyHelperIdentifiedItemVoxel(obj); } return *this; } /** * Initialize members of this class. */ void IdentifiedItemVoxel::initializeMembers() { m_xyz[0] = 0.0; m_xyz[1] = 0.0; m_xyz[2] = 0.0; m_symbolRGB[0] = 0; m_symbolRGB[1] = 0; m_symbolRGB[1] = 0; m_symbolSize = 0.0; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->addArray("m_xyz", m_xyz, 3, 0.0); m_sceneAssistant->addArray("m_symbolRGB", m_symbolRGB, 3, 0); m_sceneAssistant->add("m_symbolSize", &m_symbolSize); } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void IdentifiedItemVoxel::copyHelperIdentifiedItemVoxel(const IdentifiedItemVoxel& obj) { m_xyz[0] = obj.m_xyz[0]; m_xyz[1] = obj.m_xyz[1]; m_xyz[2] = obj.m_xyz[2]; m_symbolRGB[0] = obj.m_symbolRGB[0]; m_symbolRGB[1] = obj.m_symbolRGB[1]; m_symbolRGB[2] = obj.m_symbolRGB[2]; m_symbolSize = obj.m_symbolSize; } /** * Get the coordinates of the identified voxel. * * @param xyzOut * Output with coordinates of voxel. */ void IdentifiedItemVoxel::getXYZ(float xyzOut[3]) const { xyzOut[0] = m_xyz[0]; xyzOut[1] = m_xyz[1]; xyzOut[2] = m_xyz[2]; } /** * @return Is this item valid? Typically only used when restoring * from scene. True if the symbol size is greater than zero, * else false. */ bool IdentifiedItemVoxel::isValid() const { if (m_symbolSize > 0.0) { return true; } return true; } /** * @return The color for the symbol's identification symbol. */ const float* IdentifiedItemVoxel::getSymbolRGB() const { return m_symbolRGB; } /** * Get color for the identification symbol. * * @param rgbaOut * RGBA ranging 0 to 255. */ void IdentifiedItemVoxel::getSymbolRGBA(uint8_t rgbaOut[4]) const { rgbaOut[0] = static_cast(m_symbolRGB[0] * 255.0); rgbaOut[1] = static_cast(m_symbolRGB[1] * 255.0); rgbaOut[2] = static_cast(m_symbolRGB[2] * 255.0); rgbaOut[3] = 255; } /** * @return The size of the symbol. */ float IdentifiedItemVoxel::getSymbolSize() const { return m_symbolSize; } /** * Set the color for the identification symbol. * * @param rgb * Red, green, blue color components for identification system. */ void IdentifiedItemVoxel::setSymbolRGB(const float* rgb) { m_symbolRGB[0] = rgb[0]; m_symbolRGB[1] = rgb[1]; m_symbolRGB[2] = rgb[2]; } /** * Set the size of the symbol. * * @param symbolSize * Size of the symbol. */ void IdentifiedItemVoxel::setSymbolSize(const float symbolSize) { m_symbolSize = symbolSize; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString IdentifiedItemVoxel::toString() const { const AString s = (IdentifiedItem::toString() + ", m_xyz=" + AString::fromNumbers(m_xyz, 3, ", ")); return s; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* IdentifiedItemVoxel::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "IdentifiedItemVoxel", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); /* * Save data in parent class. */ saveMembers(sceneAttributes, sceneClass); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void IdentifiedItemVoxel::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); /* * Restores data in parent class. */ restoreMembers(sceneAttributes, sceneClass); //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Brain/IdentifiedItemVoxel.h000066400000000000000000000063251360521144700235350ustar00rootroot00000000000000#ifndef __IDENTIFIED_ITEM_VOXEL_H__ #define __IDENTIFIED_ITEM_VOXEL_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "IdentifiedItem.h" namespace caret { class SceneClassAssistant; class IdentifiedItemVoxel : public IdentifiedItem{ public: IdentifiedItemVoxel(); IdentifiedItemVoxel(const AString& text, const float xyz[3]); virtual ~IdentifiedItemVoxel(); IdentifiedItemVoxel(const IdentifiedItemVoxel& obj); IdentifiedItemVoxel& operator=(const IdentifiedItemVoxel& obj); virtual bool isValid() const; void getXYZ(float xyzOut[3]) const; const float* getSymbolRGB() const; void getSymbolRGBA(uint8_t rgbaOut[4]) const; float getSymbolSize() const; void setSymbolRGB(const float* rgb); void setSymbolSize(const float symbolSize); virtual AString toString() const; // ADD_NEW_METHODS_HERE virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implemetation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: void copyHelperIdentifiedItemVoxel(const IdentifiedItemVoxel& obj); void initializeMembers(); float m_xyz[3]; float m_symbolRGB[3]; float m_symbolSize; SceneClassAssistant* m_sceneAssistant; // ADD_NEW_MEMBERS_HERE }; #ifdef __IDENTIFIED_ITEM_VOXEL_DECLARE__ // #endif // __IDENTIFIED_ITEM_VOXEL_DECLARE__ } // namespace #endif //__IDENTIFIED_ITEM_VOXEL_H__ connectome-workbench-1.4.2/src/Brain/ImageDepthPositionEnum.cxx000066400000000000000000000253171360521144700245720ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __IMAGE_DEPTH_POSITION_ENUM_DECLARE__ #include "ImageDepthPositionEnum.h" #undef __IMAGE_DEPTH_POSITION_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ImageDepthPositionEnum * \brief Depth position for images * * * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_imageDepthPositionEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void imageDepthPositionEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ImageDepthPositionEnum.h" * * Instatiate: * m_imageDepthPositionEnumComboBox = new EnumComboBoxTemplate(this); * m_imageDepthPositionEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_imageDepthPositionEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(imageDepthPositionEnumComboBoxItemActivated())); * * Update the selection: * m_imageDepthPositionEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ImageDepthPositionEnum::Enum VARIABLE = m_imageDepthPositionEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ImageDepthPositionEnum::ImageDepthPositionEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ImageDepthPositionEnum::~ImageDepthPositionEnum() { } /** * Initialize the enumerated metadata. */ void ImageDepthPositionEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ImageDepthPositionEnum(BACK, "BACK", "Back")); enumData.push_back(ImageDepthPositionEnum(FRONT, "FRONT", "Front")); enumData.push_back(ImageDepthPositionEnum(MIDDLE, "MIDDLE", "Middle")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ImageDepthPositionEnum* ImageDepthPositionEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ImageDepthPositionEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ImageDepthPositionEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ImageDepthPositionEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ImageDepthPositionEnum::Enum ImageDepthPositionEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ImageDepthPositionEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ImageDepthPositionEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ImageDepthPositionEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ImageDepthPositionEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ImageDepthPositionEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ImageDepthPositionEnum::Enum ImageDepthPositionEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ImageDepthPositionEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ImageDepthPositionEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ImageDepthPositionEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ImageDepthPositionEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ImageDepthPositionEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ImageDepthPositionEnum::Enum ImageDepthPositionEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ImageDepthPositionEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ImageDepthPositionEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ImageDepthPositionEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ImageDepthPositionEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ImageDepthPositionEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ImageDepthPositionEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ImageDepthPositionEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ImageDepthPositionEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Brain/ImageDepthPositionEnum.h000066400000000000000000000062371360521144700242170ustar00rootroot00000000000000#ifndef __IMAGE_DEPTH_POSITION_ENUM_H__ #define __IMAGE_DEPTH_POSITION_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ImageDepthPositionEnum { public: /** * Enumerated values. */ enum Enum { /** In back of models */ BACK, /** In front of models */ FRONT, /** In the middle of the models */ MIDDLE }; ~ImageDepthPositionEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ImageDepthPositionEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ImageDepthPositionEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __IMAGE_DEPTH_POSITION_ENUM_DECLARE__ std::vector ImageDepthPositionEnum::enumData; bool ImageDepthPositionEnum::initializedFlag = false; int32_t ImageDepthPositionEnum::integerCodeCounter = 0; #endif // __IMAGE_DEPTH_POSITION_ENUM_DECLARE__ } // namespace #endif //__IMAGE_DEPTH_POSITION_ENUM_H__ connectome-workbench-1.4.2/src/Brain/Model.cxx000066400000000000000000000361351360521144700212510ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "CaretLogger.h" #include "EventManager.h" #include "Model.h" #include "ModelSurface.h" #include "ModelVolume.h" #include "OverlaySet.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "Surface.h" using namespace caret; /** * Constructor. * @param m_modelType Type of this model. * @param brain Brain that 'owns' this model. */ Model::Model(const ModelTypeEnum::Enum modelType, Brain* brain) : CaretObject() { m_brain = brain; initializeMembersModel(); m_modelType = modelType; } /** * Destructor */ Model::~Model() { } void Model::initializeMembersModel() { } /** * @return The type of model. */ ModelTypeEnum::Enum Model::getModelType() const { return m_modelType; } /** * Get a String for use in the GUI. * * @return String for use in the GUI. * */ AString Model::toString() const { return getNameForGUI(true); } /** * Get a text description of the window's content. * * @param tabIndex * Index of the tab for content description. * @param descriptionOut * Description of the window's content. */ void Model::getDescriptionOfContent(const int32_t /*tabIndex*/, PlainTextStringBuilder& descriptionOut) const { descriptionOut.addLine(getNameForGUI(true)); } /** * Get the brain that created this model. * @return The brain. */ Brain* Model::getBrain() { return m_brain; } /** * Intended for overriding by sub-classes so that they * can selected the desired surfaces after file loading. */ void Model::initializeSelectedSurfaces() { /* nothing */ } /** * Get the chart overlay set for this model. * * @param tabIndex * Index for the chart overlay set. * @return * Chart overlay set or NULL if not valid for this model. */ ChartTwoOverlaySet* Model::getChartTwoOverlaySet(const int /*tabIndex*/) { return NULL; } /** * Get the chart overlay set for this model. * * @param tabIndex * Index for the chart overlay set. * @return * Chart overlay set or NULL if not valid for this model. */ const ChartTwoOverlaySet* Model::getChartTwoOverlaySet(const int /*tabIndex*/) const { return NULL; } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of the class' instance. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* Model::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "Model", 1); /* * Do not use scene assistant to save model type since special handling * is needed when it is restored. */ sceneClass->addEnumeratedType("m_modelType", m_modelType); if (m_modelType == ModelTypeEnum::MODEL_TYPE_SURFACE) { const ModelSurface* surfaceModel = dynamic_cast(this); CaretAssert(surfaceModel); sceneClass->addString("surfaceName", surfaceModel->getSurface()->getFileNameNoPath()); } /* * Get indices of tabs that are to be saved to scene. */ const std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); const int32_t numActiveTabs = static_cast(tabIndices.size()); /* * Save the overlays (except for yoking) */ std::vector overlaySetClassVector; for (int32_t iat = 0; iat < numActiveTabs; iat++) { const int32_t tabIndex = tabIndices[iat]; SceneClass* overlaySetClass = new SceneClass(("modelOverlay[" + AString::number(iat) + "]"), "OverlaySet", 1); overlaySetClass->addInteger("tabIndex", tabIndex); overlaySetClass->addChild(getOverlaySet(tabIndex)->saveToScene(sceneAttributes, "overlaySet")); overlaySetClassVector.push_back(overlaySetClass); } SceneClassArray* overlaySetClassArray = new SceneClassArray("m_overlaySet", overlaySetClassVector); sceneClass->addChild(overlaySetClassArray); /* * Save information specific to the type of model */ saveModelSpecificInformationToScene(sceneAttributes, sceneClass); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. May be NULL for some types of scenes. */ void Model::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } /* * This model was created by the parent scene class. * The model type in the scene should match what was saved. * If not, a serious (programming) error has occurred. */ const ModelTypeEnum::Enum savedModelType = sceneClass->getEnumeratedTypeValue("m_modelType", ModelTypeEnum::MODEL_TYPE_INVALID); if (savedModelType == ModelTypeEnum::MODEL_TYPE_INVALID) { CaretLogSevere("Non-matching model type when restoring scene: " + ModelTypeEnum::toName(savedModelType)); return; } if (savedModelType != m_modelType) { return; } setRestoredFromScene(true); if (m_modelType == ModelTypeEnum::MODEL_TYPE_SURFACE) { const AString surfaceName = sceneClass->getStringValue("surfaceName", "NOT-FOUND"); const ModelSurface* surfaceModel = dynamic_cast(this); CaretAssert(surfaceModel); if (surfaceName != surfaceModel->getSurface()->getFileNameNoPath()) { /* * Exit as this is not the surface for restoring (name does not match) */ return; } } /* * Restore the overlays (except for yoking) */ const SceneClassArray* overlaySetClassArray = sceneClass->getClassArray("m_overlaySet"); if (overlaySetClassArray != NULL) { const int32_t numSavedOverlaySets = overlaySetClassArray->getNumberOfArrayElements(); for (int32_t i = 0; i < numSavedOverlaySets; i++) { const SceneClass* overlaySceneClass = overlaySetClassArray->getClassAtIndex(i); const int32_t tabIndex = overlaySceneClass->getIntegerValue("tabIndex", -1); const SceneClass* overlayClass = overlaySceneClass->getClass("overlaySet"); if ((tabIndex >= 0) && (overlayClass != NULL)) { getOverlaySet(tabIndex)->restoreFromScene(sceneAttributes, overlayClass); } } } /* * Restore any information specific to type of model */ restoreModelSpecificInformationFromScene(sceneAttributes, sceneClass); /* * Check for transformations that are stored in the model's scene. * These are only present in older scene files (circa March 2013 * and earlier). */ m_oldSceneTransformations.resize(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_oldSceneTransformations[i].m_rotationValid = false; m_oldSceneTransformations[i].m_scalingValid = false; m_oldSceneTransformations[i].m_translationValid = false; } /* * Restore scaling */ const SceneClassArray* scalingClassArray = sceneClass->getClassArray("m_scaling"); if (scalingClassArray != NULL) { const int32_t numSavedScaling = scalingClassArray->getNumberOfArrayElements(); for (int32_t ism = 0; ism < numSavedScaling; ism++) { const SceneClass* scalingClass = scalingClassArray->getClassAtIndex(ism); const int32_t tabIndex = scalingClass->getIntegerValue("tabIndex", -1); if ((tabIndex >= 0) && (tabIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)) { m_oldSceneTransformations[tabIndex].m_scaling = scalingClass->getFloatValue("scaling", 1.0); m_oldSceneTransformations[tabIndex].m_scalingValid = true; } } } /* * Restore translation */ const SceneClassArray* translationClassArray = sceneClass->getClassArray("m_translation"); if (translationClassArray != NULL) { const int32_t numSavedTanslations = translationClassArray->getNumberOfArrayElements(); for (int32_t ism = 0; ism < numSavedTanslations; ism++) { const SceneClass* translationClass = translationClassArray->getClassAtIndex(ism); const int32_t tabIndex = translationClass->getIntegerValue("tabIndex", -1); const int32_t viewingTransformIndex = translationClass->getIntegerValue("viewingTransformIndex", -1); if ((tabIndex >= 0) && (tabIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)) { if (viewingTransformIndex == 0) { if (translationClass->getFloatArrayValue("translation", m_oldSceneTransformations[tabIndex].m_translation, 3) == 3) { m_oldSceneTransformations[tabIndex].m_translationValid = true; } } } } } /* * Restore rotation matrices */ const SceneClassArray* rotationMatrixClassArray = sceneClass->getClassArray("m_viewingRotationMatrix"); if (rotationMatrixClassArray != NULL) { const int32_t numSavedMatrices = rotationMatrixClassArray->getNumberOfArrayElements(); for (int32_t ism = 0; ism < numSavedMatrices; ism++) { const SceneClass* rotationMatrixClass = rotationMatrixClassArray->getClassAtIndex(ism); const int32_t tabIndex = rotationMatrixClass->getIntegerValue("tabIndex", -1); const int32_t viewingTransformIndex = rotationMatrixClass->getIntegerValue("viewingTransformIndex", -1); if ((tabIndex >= 0) && (tabIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)) { if (viewingTransformIndex == 0) { if (rotationMatrixClass->getFloatArrayValue("matrix", (float*)m_oldSceneTransformations[tabIndex].m_rotationMatrix, 16) == 16) { m_oldSceneTransformations[tabIndex].m_rotationValid = true; } } } } } } /** * Get transformations for a given tab from older scenes that were * created when the transformations were present in every model for * every tab. Transformations have since been moved into the * browser tab content. * * @param tabIndex * Index of tab for transformation. * @param translationOut * The translation for the given tab. * @param scalingOut * The scaling for the given tab. * @param rotationMatrixOut * The rotation matrix for the given tab. * @return * true if the transformations are valid, else false. */ bool Model::getOldSceneTransformation(const int tabIndex, float translationOut[3], float& scalingOut, float rotationMatrixOut[4][4]) const { if ((tabIndex >= 0) && (tabIndex < static_cast(m_oldSceneTransformations.size()))) { const OldSceneTransformation& ost = m_oldSceneTransformations[tabIndex]; if (ost.m_rotationValid && ost.m_scalingValid && ost.m_translationValid) { translationOut[0] = ost.m_translation[0]; translationOut[1] = ost.m_translation[1]; translationOut[2] = ost.m_translation[2]; scalingOut = ost.m_scaling; for (int32_t i = 0; i < 4; i++) { for (int32_t j = 0; j < 4; j++) { rotationMatrixOut[i][j] = ost.m_rotationMatrix[i][j]; } } return true; } } return false; } /** * Copy the tab content from the source tab index to the * destination tab index. * * @param sourceTabIndex * Source from which tab content is copied. * @param destinationTabIndex * Destination to which tab content is copied. */ void Model::copyTabContent(const int32_t /*sourceTabIndex*/, const int32_t /*destinationTabIndex*/) { } /** * @return True if model was restored from scene */ bool Model::isRestoredFromScene() const { return m_restoredFromSceneFlag; } /** * Set model was restored from scene. * * @param restoredStatus * New value for restored status. */ void Model::setRestoredFromScene(const bool restoredStatus) { m_restoredFromSceneFlag = restoredStatus; } connectome-workbench-1.4.2/src/Brain/Model.h000066400000000000000000000106661360521144700206770ustar00rootroot00000000000000#ifndef __MODEL_DISPLAY_CONTROLLER_H__ #define __MODEL_DISPLAY_CONTROLLER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "CaretObject.h" #include "ModelTypeEnum.h" #include "SceneableInterface.h" namespace caret { class Brain; class ChartTwoOverlaySet; class OverlaySet; class PlainTextStringBuilder; /// Base class for a model class Model : public CaretObject, public SceneableInterface { protected: Model(const ModelTypeEnum::Enum modelType, Brain* brain); virtual ~Model(); private: Model(const Model& o); Model& operator=(const Model& o); void initializeMembersModel(); public: virtual void initializeOverlays() = 0; Brain* getBrain(); ModelTypeEnum::Enum getModelType() const; virtual AString getNameForGUI(const bool includeStructureFlag) const = 0; virtual AString getNameForBrowserTab() const = 0; virtual AString toString() const; virtual void getDescriptionOfContent(const int32_t tabIndex, PlainTextStringBuilder& descriptionOut) const; virtual OverlaySet* getOverlaySet(const int tabIndex) = 0; virtual const OverlaySet* getOverlaySet(const int tabIndex) const = 0; virtual ChartTwoOverlaySet* getChartTwoOverlaySet(const int tabIndex); virtual const ChartTwoOverlaySet* getChartTwoOverlaySet(const int tabIndex) const; virtual void initializeSelectedSurfaces(); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); bool getOldSceneTransformation(const int tabIndex, float translationOut[3], float& scalingOut, float rotationMatrixOut[4][4]) const; virtual void copyTabContent(const int32_t sourceTabIndex, const int32_t destinationTabIndex); bool isRestoredFromScene() const; void setRestoredFromScene(const bool restoredStatus); protected: virtual void saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) = 0; virtual void restoreModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) = 0; /** Brain which contains the model */ Brain* m_brain; private: /** * Transformations in older scene files when transforms were stored * in each of the models for every tab. */ class OldSceneTransformation { public: float m_translation[3]; float m_scaling; float m_rotationMatrix[4][4]; bool m_translationValid; bool m_scalingValid; bool m_rotationValid; }; ModelTypeEnum::Enum m_modelType; std::vector m_oldSceneTransformations; bool m_restoredFromSceneFlag = false; }; } // namespace #endif // __MODEL_DISPLAY_CONTROLLER_H__ connectome-workbench-1.4.2/src/Brain/ModelChart.cxx000066400000000000000000002252451360521144700222350ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "Brain.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretMappableDataFile.h" #include "ChartAxis.h" #include "ChartableLineSeriesBrainordinateInterface.h" #include "CaretDataFileSelectionModel.h" #include "CaretLogger.h" #include "ChartableLineSeriesRowColumnInterface.h" #include "ChartableMatrixInterface.h" #include "ChartData.h" #include "ChartDataCartesian.h" #include "ChartDataSource.h" #include "ChartModelDataSeries.h" #include "ChartModelFrequencySeries.h" #include "ChartModelTimeSeries.h" #include "ChartingVersionEnum.h" #include "CiftiMappableDataFile.h" #include "CiftiScalarDataSeriesFile.h" #include "EventBrowserTabGetAll.h" #include "EventBrowserTabIndicesGetAll.h" #include "EventCaretMappableDataFilesGet.h" #include "EventManager.h" #include "EventNodeIdentificationColorsGetFromCharts.h" #include "ModelChart.h" #include "OverlaySet.h" #include "OverlaySetArray.h" #include "PlainTextStringBuilder.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneClassAssistant.h" #include "SceneObjectMapIntegerKey.h" #include "SurfaceFile.h" using namespace caret; /** * Constructor. * */ ModelChart::ModelChart(Brain* brain) : Model(ModelTypeEnum::MODEL_TYPE_CHART, brain) { std::vector overlaySurfaceStructures; m_overlaySetArray = new OverlaySetArray(overlaySurfaceStructures, Overlay::INCLUDE_VOLUME_FILES_YES, "Chart View"); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartableMatrixFileSelectionModel[i] = CaretDataFileSelectionModel::newInstanceForChartableMatrixParcelInterface(); m_chartableMatrixSeriesFileSelectionModel[i] = CaretDataFileSelectionModel::newInstanceForCaretDataFileType( DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES); } initializeCharts(); m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS); } /** * Destructor */ ModelChart::~ModelChart() { delete m_overlaySetArray; EventManager::get()->removeAllEventsFromListener(this); removeAllCharts(); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { delete m_chartableMatrixFileSelectionModel[i]; m_chartableMatrixFileSelectionModel[i] = NULL; delete m_chartableMatrixSeriesFileSelectionModel[i]; m_chartableMatrixSeriesFileSelectionModel[i] = NULL; } } void ModelChart::initializeCharts() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_selectedChartOneDataType[i] = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; m_chartModelDataSeries[i] = new ChartModelDataSeries(); m_chartModelDataSeries[i]->getLeftAxis()->setText("Value"); m_chartModelDataSeries[i]->getBottomAxis()->setText("Map Index"); m_chartModelFrequencySeries[i] = new ChartModelFrequencySeries(); m_chartModelFrequencySeries[i]->getLeftAxis()->setText("Value"); m_chartModelFrequencySeries[i]->getBottomAxis()->setText("Frequency"); m_chartModelTimeSeries[i] = new ChartModelTimeSeries(); m_chartModelTimeSeries[i]->getLeftAxis()->setText("Activity"); m_chartModelTimeSeries[i]->getBottomAxis()->setText("Time"); } } /** * Reset this model. */ void ModelChart::reset() { removeAllCharts(); initializeCharts(); } /** * Remove all of the charts. */ void ModelChart::removeAllCharts() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { if (m_chartModelDataSeries[i] != NULL) { delete m_chartModelDataSeries[i]; m_chartModelDataSeries[i] = NULL; } if (m_chartModelFrequencySeries[i] != NULL) { delete m_chartModelFrequencySeries[i]; m_chartModelFrequencySeries[i] = NULL; } if (m_chartModelTimeSeries[i] != NULL) { delete m_chartModelTimeSeries[i]; m_chartModelTimeSeries[i] = NULL; } } m_dataSeriesChartData.clear(); m_frequencySeriesChartData.clear(); m_timeSeriesChartData.clear(); m_previousChartMatrixFiles.clear(); } /** * Load chart data for an average of surface nodes. * * @param structure * The surface structure * @param surfaceNumberOfNodes * Number of nodes in surface. * @param nodeIndices * Indices of node. * @throws * DataFileException if there is an error loading data. */ void ModelChart::loadAverageChartDataForSurfaceNodes(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const std::vector& nodeIndices) { std::map > chartFileEnabledTabs; getTabsAndBrainordinateChartFilesForLineChartLoading(chartFileEnabledTabs); for (std::map >::iterator fileTabIter = chartFileEnabledTabs.begin(); fileTabIter != chartFileEnabledTabs.end(); fileTabIter++) { ChartableLineSeriesBrainordinateInterface* chartFile = fileTabIter->first; const std::vector tabIndices = fileTabIter->second; CaretAssert(chartFile); ChartData* chartData = chartFile->loadAverageLineSeriesChartDataForSurfaceNodes(structure, nodeIndices); if (chartData != NULL) { ChartDataSource* dataSource = chartData->getChartDataSource(); dataSource->setSurfaceNodeAverage(chartFile->getLineSeriesChartCaretMappableDataFile()->getFileName(), StructureEnum::toName(structure), surfaceNumberOfNodes, nodeIndices); addChartToChartModels(tabIndices, chartData); } } } /** * Load chart data for voxel at the given coordinate. * * @param xyz * Coordinate of voxel. * @throws * DataFileException if there is an error loading data. */ void ModelChart::loadChartDataForVoxelAtCoordinate(const float xyz[3]) { std::map > chartFileEnabledTabs; getTabsAndBrainordinateChartFilesForLineChartLoading(chartFileEnabledTabs); for (std::map >::iterator fileTabIter = chartFileEnabledTabs.begin(); fileTabIter != chartFileEnabledTabs.end(); fileTabIter++) { ChartableLineSeriesBrainordinateInterface* chartFile = fileTabIter->first; const std::vector tabIndices = fileTabIter->second; CaretAssert(chartFile); ChartData* chartData = chartFile->loadLineSeriesChartDataForVoxelAtCoordinate(xyz); if (chartData != NULL) { ChartDataSource* dataSource = chartData->getChartDataSource(); dataSource->setVolumeVoxel(chartFile->getLineSeriesChartCaretMappableDataFile()->getFileName(), xyz); addChartToChartModels(tabIndices, chartData); } } } /** * Load chart data for CIFTI Map files yoked to the given yoking group. * * @param mapYokingGroup * The map yoking group. * @param mapIndex * The map index. */ void ModelChart::loadChartDataForYokedCiftiMappableFiles(const MapYokingGroupEnum::Enum mapYokingGroup, const int32_t mapIndex) { if (mapYokingGroup == MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { return; } std::map > chartFileEnabledTabs; getTabsAndRowColumnChartFilesForLineChartLoading(chartFileEnabledTabs); for (std::map >::iterator fileTabIter = chartFileEnabledTabs.begin(); fileTabIter != chartFileEnabledTabs.end(); fileTabIter++) { ChartableLineSeriesRowColumnInterface* chartFile = fileTabIter->first; CaretAssert(chartFile); CiftiScalarDataSeriesFile* csdsf = dynamic_cast(chartFile); if (csdsf != NULL) { std::vector matchedTabIndices; const std::vector tabIndices = fileTabIter->second; for (std::vector::const_iterator tabIter = tabIndices.begin(); tabIter != tabIndices.end(); tabIter++) { const int32_t tabIndex = *tabIter; if (csdsf->getMatrixRowColumnMapYokingGroup(tabIndex) == mapYokingGroup) { matchedTabIndices.push_back(tabIndex); } } if ( ! matchedTabIndices.empty()) { ChartData* chartData = chartFile->loadLineSeriesChartDataForRow(mapIndex); if (chartData != NULL) { ChartDataSource* dataSource = chartData->getChartDataSource(); dataSource->setFileRow(chartFile->getLineSeriesChartCaretMappableDataFile()->getFileName(), mapIndex); addChartToChartModels(matchedTabIndices, chartData); } } } } } /** * Load chart data from given file at the given row. * * @param ciftiMapFile * The CIFTI file. * @param rowIndex * Index of row in the file. */ void ModelChart::loadChartDataForCiftiMappableFileRow(CiftiMappableDataFile* ciftiMapFile, const int32_t rowIndex) { CaretAssert(ciftiMapFile); std::map > chartFileEnabledTabs; getTabsAndRowColumnChartFilesForLineChartLoading(chartFileEnabledTabs); for (std::map >::iterator fileTabIter = chartFileEnabledTabs.begin(); fileTabIter != chartFileEnabledTabs.end(); fileTabIter++) { ChartableLineSeriesRowColumnInterface* chartFile = fileTabIter->first; if (ciftiMapFile == dynamic_cast(chartFile)) { const std::vector tabIndices = fileTabIter->second; CaretAssert(chartFile); ChartData* chartData = chartFile->loadLineSeriesChartDataForRow(rowIndex); if (chartData != NULL) { ChartDataSource* dataSource = chartData->getChartDataSource(); dataSource->setFileRow(chartFile->getLineSeriesChartCaretMappableDataFile()->getFileName(), rowIndex); addChartToChartModels(tabIndices, chartData); } } } } /** * Add the chart to the given tabs. * * @param tabIndices * Indices of tabs for chart data * @param chartData * Chart data that is added. */ void ModelChart::addChartToChartModels(const std::vector& tabIndices, ChartData* chartData) { CaretAssert(chartData); const ChartOneDataTypeEnum::Enum chartDataDataType = chartData->getChartDataType(); switch (chartDataDataType) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: CaretAssert(0); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: { ChartDataCartesian* cdc = dynamic_cast(chartData); CaretAssert(cdc); QSharedPointer cdcPtr(cdc); for (std::vector::const_iterator iter = tabIndices.begin(); iter != tabIndices.end(); iter++) { const int32_t tabIndex = *iter; CaretAssertArrayIndex(m_chartModelDataSeries, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_chartModelDataSeries[tabIndex]->addChartData(cdcPtr); } m_dataSeriesChartData.push_front(cdcPtr.toWeakRef()); } break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: { ChartDataCartesian* cdc = dynamic_cast(chartData); CaretAssert(cdc); QSharedPointer cdcPtr(cdc); for (std::vector::const_iterator iter = tabIndices.begin(); iter != tabIndices.end(); iter++) { const int32_t tabIndex = *iter; CaretAssertArrayIndex(m_chartModelFrequencySeries, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_chartModelFrequencySeries[tabIndex]->addChartData(cdcPtr); } m_frequencySeriesChartData.push_front(cdcPtr.toWeakRef()); } break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: { ChartDataCartesian* cdc = dynamic_cast(chartData); CaretAssert(cdc); QSharedPointer cdcPtr(cdc); for (std::vector::const_iterator iter = tabIndices.begin(); iter != tabIndices.end(); iter++) { const int32_t tabIndex = *iter; CaretAssertArrayIndex(m_chartModelTimeSeries, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_chartModelTimeSeries[tabIndex]->addChartData(cdcPtr); } m_timeSeriesChartData.push_front(cdcPtr.toWeakRef()); } break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: CaretAssert(0); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; } } /** * Get tabs and brainordinate chart files for loading chart data. * * @param chartBrainordinateFileEnabledTabsOut * Map with first being a chartable file and the second being * tabs for which that chartable file is enabled. */ void ModelChart::getTabsAndBrainordinateChartFilesForLineChartLoading(std::map >& chartBrainordinateFileEnabledTabsOut) const { chartBrainordinateFileEnabledTabsOut.clear(); std::map > chartFileEnabledTabs; getTabsAndLineSeriesChartFilesForLineChartLoading(chartFileEnabledTabs); for (std::map >::iterator iter = chartFileEnabledTabs.begin(); iter != chartFileEnabledTabs.end(); iter++) { ChartableLineSeriesBrainordinateInterface* brainChartFile = dynamic_cast(iter->first); if (brainChartFile != NULL) { chartBrainordinateFileEnabledTabsOut.insert(std::make_pair(brainChartFile, iter->second)); } } } /** * Get tabs and row column chart files for loading chart data. * * @param chartRowColumnFilesEnabledTabsOut * Map with first being a chartable file and the second being * tabs for which that chartable file is enabled. */ void ModelChart::getTabsAndRowColumnChartFilesForLineChartLoading(std::map >& chartRowColumnFilesEnabledTabsOut) const { chartRowColumnFilesEnabledTabsOut.clear(); std::map > chartFileEnabledTabs; getTabsAndLineSeriesChartFilesForLineChartLoading(chartFileEnabledTabs); for (std::map >::iterator iter = chartFileEnabledTabs.begin(); iter != chartFileEnabledTabs.end(); iter++) { ChartableLineSeriesRowColumnInterface* rowColChartFile = dynamic_cast(iter->first); if (rowColChartFile != NULL) { chartRowColumnFilesEnabledTabsOut.insert(std::make_pair(rowColChartFile, iter->second)); } } } /** * Get line series chart files for loading chart data. * * @param chartFileEnabledTabsOut * Map with first being a chartable file and the second being * tabs for which that chartable file is enabled. */ void ModelChart::getTabsAndLineSeriesChartFilesForLineChartLoading(std::map >& chartFileEnabledTabsOut) const { chartFileEnabledTabsOut.clear(); EventBrowserTabGetAll allTabsEvent; EventManager::get()->sendEvent(allTabsEvent.getPointer()); std::vector validTabIndices = allTabsEvent.getBrowserTabIndices(); std::vector chartFiles; m_brain->getAllChartableLineSeriesDataFiles(chartFiles); for (std::vector::iterator iter = chartFiles.begin(); iter != chartFiles.end(); iter++) { ChartableLineSeriesInterface* cf = *iter; std::vector chartFileTabIndices; for (std::vector::iterator tabIter = validTabIndices.begin(); tabIter != validTabIndices.end(); tabIter++) { const int32_t tabIndex = *tabIter; if (cf->isLineSeriesChartingEnabled(tabIndex)) { chartFileTabIndices.push_back(tabIndex); } } if ( ! chartFileTabIndices.empty()) { chartFileEnabledTabsOut.insert(std::make_pair(cf, chartFileTabIndices)); } } } /** * Load chart data for a surface node. * * @param structure * The surface structure * @param surfaceNumberOfNodes * Number of nodes in surface. * @param nodeIndex * Index of node. * @throws * DataFileException if there is an error loading data. */ void ModelChart::loadChartDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const int32_t nodeIndex) { std::map > chartFileEnabledTabs; getTabsAndBrainordinateChartFilesForLineChartLoading(chartFileEnabledTabs); for (std::map >::iterator fileTabIter = chartFileEnabledTabs.begin(); fileTabIter != chartFileEnabledTabs.end(); fileTabIter++) { ChartableLineSeriesBrainordinateInterface* chartFile = fileTabIter->first; const std::vector tabIndices = fileTabIter->second; CaretAssert(chartFile); ChartData* chartData = chartFile->loadLineSeriesChartDataForSurfaceNode(structure, nodeIndex); if (chartData != NULL) { ChartDataSource* dataSource = chartData->getChartDataSource(); dataSource->setSurfaceNode(chartFile->getLineSeriesChartCaretMappableDataFile()->getFileName(), StructureEnum::toName(structure), surfaceNumberOfNodes, nodeIndex); addChartToChartModels(tabIndices, chartData); } } } /** * Receive an event. * * @param event * The event that the receive can respond to. */ void ModelChart::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS) { EventNodeIdentificationColorsGetFromCharts* nodeChartID = dynamic_cast(event); CaretAssert(nodeChartID); EventBrowserTabGetAll allTabsEvent; EventManager::get()->sendEvent(allTabsEvent.getPointer()); std::vector validTabIndices = allTabsEvent.getBrowserTabIndices(); const AString structureName = nodeChartID->getStructureName(); std::vector cartesianChartData; for (std::list >::iterator dsIter = m_dataSeriesChartData.begin(); dsIter != m_dataSeriesChartData.end(); dsIter++) { QSharedPointer spCart = dsIter->toStrongRef(); if ( ! spCart.isNull()) { cartesianChartData.push_back(spCart.data()); } } for (std::list >::iterator tsIter = m_frequencySeriesChartData.begin(); tsIter != m_frequencySeriesChartData.end(); tsIter++) { QSharedPointer spCart = tsIter->toStrongRef(); if ( ! spCart.isNull()) { cartesianChartData.push_back(spCart.data()); } } for (std::list >::iterator tsIter = m_timeSeriesChartData.begin(); tsIter != m_timeSeriesChartData.end(); tsIter++) { QSharedPointer spCart = tsIter->toStrongRef(); if ( ! spCart.isNull()) { cartesianChartData.push_back(spCart.data()); } } /* * Iterate over node indices for which colors are desired. */ const std::vector nodeIndices = nodeChartID->getNodeIndices(); for (std::vector::const_iterator nodeIter = nodeIndices.begin(); nodeIter != nodeIndices.end(); nodeIter++) { const int32_t nodeIndex = *nodeIter; /* * Iterate over the data in the cartesian chart */ for (std::vector::iterator cdIter = cartesianChartData.begin(); cdIter != cartesianChartData.end(); cdIter++) { const ChartDataCartesian* cdc = *cdIter; const ChartDataSource* cds = cdc->getChartDataSource(); if (cds->isSurfaceNodeSourceOfData(structureName, nodeIndex)) { /* * Found node index so add its color to the event */ const CaretColorEnum::Enum color = cdc->getColor(); const float* rgb = CaretColorEnum::toRGB(color); nodeChartID->addNode(nodeIndex, rgb); break; } } } nodeChartID->setEventProcessed(); } } /** * Get the name for use in a GUI. * * @param includeStructureFlag - Prefix label with structure to which * this structure model belongs. * @return Name for use in a GUI. * */ AString ModelChart::getNameForGUI(const bool /*includeStructureFlag*/) const { AString name = "ChartOld"; return name; } /** * @return The name that should be displayed in the tab * displaying this model. */ AString ModelChart::getNameForBrowserTab() const { AString name = "ChartOld"; return name; } /** * Get the overlay set for the given tab. * @param tabIndex * Index of tab. * @return * Overlay set at the given tab index. */ OverlaySet* ModelChart::getOverlaySet(const int tabIndex) { CaretAssertArrayIndex(m_overlaySetArray, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_overlaySetArray->getOverlaySet(tabIndex); } /** * Get the overlay set for the given tab. * @param tabIndex * Index of tab. * @return * Overlay set at the given tab index. */ const OverlaySet* ModelChart::getOverlaySet(const int tabIndex) const { CaretAssertArrayIndex(m_overlaySetArray, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_overlaySetArray->getOverlaySet(tabIndex); } /** * Initilize the overlays for this model. */ void ModelChart::initializeOverlays() { m_overlaySetArray->initializeOverlaySelections(); } /** * Save version one charting information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param sceneClass * SceneClass to which model specific information is added. */ void ModelChart::saveVersionOneModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); std::set validChartDataIDs; saveChartModelsToScene(sceneAttributes, sceneClass, tabIndices, validChartDataIDs); sceneClass->addEnumeratedTypeArrayForTabIndices("m_selectedChartDataType", m_selectedChartOneDataType, tabIndices); /* * Save matrix chart models to scene. */ SceneObjectMapIntegerKey* matrixSceneMap = new SceneObjectMapIntegerKey("chartableMatrixFileSelectionModelMap", SceneObjectDataTypeEnum::SCENE_CLASS); std::vector matrixSelectionVector; for (std::vector::const_iterator tabIter = tabIndices.begin(); tabIter != tabIndices.end(); tabIter++) { const int32_t tabIndex = *tabIter; matrixSceneMap->addClass(tabIndex, m_chartableMatrixFileSelectionModel[tabIndex]->saveToScene(sceneAttributes, "m_chartableMatrixFileSelectionModel")); } sceneClass->addChild(matrixSceneMap); /* * Save matrix series chart models to scene. */ SceneObjectMapIntegerKey* matrixSeriesSceneMap = new SceneObjectMapIntegerKey("chartableMatrixSeriesFileSelectionModelMap", SceneObjectDataTypeEnum::SCENE_CLASS); std::vector matrixSeriesSelectionVector; for (std::vector::const_iterator tabIter = tabIndices.begin(); tabIter != tabIndices.end(); tabIter++) { const int32_t tabIndex = *tabIter; matrixSeriesSceneMap->addClass(tabIndex, m_chartableMatrixSeriesFileSelectionModel[tabIndex]->saveToScene(sceneAttributes, "m_chartableMatrixSeriesFileSelectionModel")); } sceneClass->addChild(matrixSeriesSceneMap); } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param sceneClass * SceneClass to which model specific information is added. */ void ModelChart::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); saveVersionOneModelSpecificInformationToScene(sceneAttributes, sceneClass); } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ModelChart::restoreModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { reset(); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); restoreVersionOneModelSpecificInformationFromScene(sceneAttributes, sceneClass); } /** * Restore information specific to the type of model from VERSION ONE scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ModelChart::restoreVersionOneModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { /* * Restore the chart models */ restoreVersionOneChartModelsFromScene(sceneAttributes, sceneClass); sceneClass->getEnumerateTypeArrayForTabIndices("m_selectedChartDataType", m_selectedChartOneDataType); /* * Restore matrix chart models from scene. */ const SceneObjectMapIntegerKey* matrixSceneMap = sceneClass->getMapIntegerKey("chartableMatrixFileSelectionModelMap"); if (matrixSceneMap != NULL) { const std::vector tabIndices = matrixSceneMap->getKeys(); for (std::vector::const_iterator tabIter = tabIndices.begin(); tabIter != tabIndices.end(); tabIter++) { const int32_t tabIndex = *tabIter; const SceneClass* sceneClass = matrixSceneMap->classValue(tabIndex); m_chartableMatrixFileSelectionModel[tabIndex]->restoreFromScene(sceneAttributes, sceneClass); } } /* * Restore matrix chart series models from scene. */ const SceneObjectMapIntegerKey* matrixSeriesSceneMap = sceneClass->getMapIntegerKey("chartableMatrixSeriesFileSelectionModelMap"); if (matrixSeriesSceneMap != NULL) { const std::vector tabIndices = matrixSeriesSceneMap->getKeys(); for (std::vector::const_iterator tabIter = tabIndices.begin(); tabIter != tabIndices.end(); tabIter++) { const int32_t tabIndex = *tabIter; const SceneClass* sceneClass = matrixSeriesSceneMap->classValue(tabIndex); m_chartableMatrixSeriesFileSelectionModel[tabIndex]->restoreFromScene(sceneAttributes, sceneClass); } } } /** * Save chart models to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param sceneClass * SceneClass to which model specific information is added. */ void ModelChart::saveChartModelsToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass, const std::vector& tabIndices, std::set& validChartDataIDsOut) { validChartDataIDsOut.clear(); std::set chartDataForSavingToSceneSet; /* * Save chart models to scene. */ std::vector chartModelVector; for (std::vector::const_iterator tabIter = tabIndices.begin(); tabIter != tabIndices.end(); tabIter++) { const int32_t tabIndex = *tabIter; ChartModel* chartModel = NULL; switch (getSelectedChartOneDataType(tabIndex)) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: chartModel = getSelectedFrequencySeriesChartModel(tabIndex); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: chartModel = getSelectedDataSeriesChartModel(tabIndex); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: chartModel = getSelectedTimeSeriesChartModel(tabIndex); break; } if (chartModel != NULL) { SceneClass* chartModelClass = chartModel->saveToScene(sceneAttributes, "chartModel"); if (chartModelClass == NULL) { continue; } SceneClass* chartClassContainer = new SceneClass("chartClassContainer", "ChartClassContainer", 1); chartClassContainer->addInteger("tabIndex", tabIndex); chartClassContainer->addEnumeratedType("chartDataType", chartModel->getChartDataType()); chartClassContainer->addClass(chartModelClass); chartModelVector.push_back(chartClassContainer); /* * Add chart data that is in models saved to scene. * */ std::vector chartDatasInModel = chartModel->getAllChartDatas(); chartDataForSavingToSceneSet.insert(chartDatasInModel.begin(), chartDatasInModel.end()); } } if ( ! chartModelVector.empty()) { SceneClassArray* modelArray = new SceneClassArray("chartModelArray", chartModelVector); sceneClass->addChild(modelArray); } if ( ! chartDataForSavingToSceneSet.empty()) { std::vector chartDataClassVector; for (std::set::iterator cdIter = chartDataForSavingToSceneSet.begin(); cdIter != chartDataForSavingToSceneSet.end(); cdIter++) { ChartData* chartData = *cdIter; SceneClass* chartDataClass = chartData->saveToScene(sceneAttributes, "chartData"); SceneClass* chartDataContainer = new SceneClass("chartDataContainer", "ChartDataContainer", 1); chartDataContainer->addEnumeratedType("chartDataType", chartData->getChartDataType()); chartDataContainer->addClass(chartDataClass); chartDataClassVector.push_back(chartDataContainer); } if ( ! chartDataClassVector.empty()) { SceneClassArray* dataArray = new SceneClassArray("chartDataArray", chartDataClassVector); sceneClass->addChild(dataArray); } } } /** * Restore the chart models from a VERSION ONE scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ModelChart::restoreVersionOneChartModelsFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { /* * Restore the chart models */ const SceneClassArray* chartModelArray = sceneClass->getClassArray("chartModelArray"); if (chartModelArray != NULL) { const int numElements = chartModelArray->getNumberOfArrayElements(); for (int32_t i = 0; i < numElements; i++) { const SceneClass* chartClassContainer = chartModelArray->getClassAtIndex(i); if (chartClassContainer != NULL) { const int32_t tabIndex = chartClassContainer->getIntegerValue("tabIndex", -1); const ChartOneDataTypeEnum::Enum chartDataType = chartClassContainer->getEnumeratedTypeValue("chartDataType", ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID); const SceneClass* chartModelClass = chartClassContainer->getClass("chartModel"); if ((tabIndex >= 0) && (chartDataType != ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) && (chartModelClass != NULL)) { CaretAssertArrayIndex(m_chartModelDataSeries, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); switch (chartDataType) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: CaretAssert(0); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: m_chartModelDataSeries[tabIndex]->restoreFromScene(sceneAttributes, chartModelClass); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: m_chartModelFrequencySeries[tabIndex]->restoreFromScene(sceneAttributes, chartModelClass); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: m_chartModelTimeSeries[tabIndex]->restoreFromScene(sceneAttributes, chartModelClass); break; } } } } } /* * Restore the chart data. */ std::vector > restoredChartData; const SceneClassArray* chartDataArray = sceneClass->getClassArray("chartDataArray"); if (chartDataArray != NULL) { const int numElements = chartDataArray->getNumberOfArrayElements(); for (int32_t i = 0; i < numElements; i++) { const SceneClass* chartDataContainer = chartDataArray->getClassAtIndex(i); if (chartDataContainer != NULL) { const ChartOneDataTypeEnum::Enum chartDataType = chartDataContainer->getEnumeratedTypeValue("chartDataType", ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID); const SceneClass* chartDataClass = chartDataContainer->getClass("chartData"); if ((chartDataType != ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) && (chartDataClass != NULL)) { ChartData* chartData = ChartData::newChartDataForChartDataType(chartDataType); CaretAssert(chartData); /* * The chart's points are saved in the scene and this * function call restores the points. This is part of * the original implementation. However, it was decided * that the when the scene is restored, the data should * be loaded from the file to reflect any changes made * to the data file. But, we still load the chart points * saved to the scene in case the file is missing. */ chartData->restoreFromScene(sceneAttributes, chartDataClass); /* * Now load the chart data from the file using the * information in the chart's data source. If this is * successful, then overwrite the chart data points * that were loaded from the scene file. * * Also need to copy the unique identifier so that * the chart data goes to the correct model. */ ChartData* newChartData = loadCartesianChartWhenRestoringScene(chartData); if (newChartData != NULL) { newChartData->setUniqueIdentifier(chartData->getUniqueIdentifier()); newChartData->copySelectionStatusForAllTabs(chartData); delete chartData; chartData = newChartData; } else { const AString msg("FAILED to load line chart data from file for " + chartData->getChartDataSource()->getDescription() + " so chart points from scene will be used. If content of the file " " has changed since the scene was created, the chart may not be accurate."); sceneAttributes->addToErrorMessage(msg); CaretLogWarning(msg); } restoredChartData.push_back(QSharedPointer(chartData)); } } } } /* * Have chart models restore pointers to chart data * The chart models use shared pointers are used since the chart * data may be in multiple tabs. User may remove the charts * from some tabs but not others and shared pointers make management * easier. */ for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartModelDataSeries[i]->restoreChartDataFromScene(sceneAttributes, restoredChartData); } for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartModelFrequencySeries[i]->restoreChartDataFromScene(sceneAttributes, restoredChartData); } for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartModelTimeSeries[i]->restoreChartDataFromScene(sceneAttributes, restoredChartData); } /* * The chart data are also saved here as weak pointers so * that they can be saved to a scene only one time. If */ for (std::vector >::iterator rcdIter = restoredChartData.begin(); rcdIter != restoredChartData.end(); rcdIter++) { QSharedPointer chartPointer = *rcdIter; switch (chartPointer->getChartDataType()) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: CaretAssert(0); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: CaretAssert(0); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: CaretAssert(0); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: { QSharedPointer cartChartPointer = chartPointer.dynamicCast(); CaretAssert( ! cartChartPointer.isNull()); m_dataSeriesChartData.push_back(cartChartPointer); } break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: { QSharedPointer cartChartPointer = chartPointer.dynamicCast(); CaretAssert( ! cartChartPointer.isNull()); m_frequencySeriesChartData.push_back(cartChartPointer); } break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: { QSharedPointer cartChartPointer = chartPointer.dynamicCast(); CaretAssert( ! cartChartPointer.isNull()); m_timeSeriesChartData.push_back(cartChartPointer); } break; } } } /** * Load the cartesian chart data using the given chart data source. * * @param chartData * ChartData that is cast to ChartDataCartesian and if successful, * the chart is duplicated using data from files. * @return * Pointer to successfully loaded chart data or NULL if not found or error. */ ChartData* ModelChart::loadCartesianChartWhenRestoringScene(const ChartData* chartData) { CaretAssert(chartData); ChartDataCartesian* chartDataOut = NULL; const ChartDataCartesian* cartesianChart = dynamic_cast(chartData); if (cartesianChart != NULL) { const ChartOneDataTypeEnum::Enum chartDataType = cartesianChart->getChartDataType(); std::vector chartableDataFiles; m_brain->getAllChartableLineSeriesDataFiles(chartableDataFiles); for (std::vector::iterator iter = chartableDataFiles.begin(); iter != chartableDataFiles.end(); iter++) { ChartableLineSeriesBrainordinateInterface* chartableBrainFile = dynamic_cast(*iter); ChartableLineSeriesRowColumnInterface* chartableRowColumnFile = dynamic_cast(*iter); if (chartableBrainFile != NULL) { if (chartableBrainFile->isLineSeriesChartDataTypeSupported(chartDataType)) { CaretMappableDataFile* chartMapFile = chartableBrainFile->getLineSeriesChartCaretMappableDataFile(); CaretAssert(chartMapFile); const ChartDataSource* chartDataSource = cartesianChart->getChartDataSource(); CaretAssert(chartDataSource); const AString chartMapFileName = chartMapFile->getFileName(); const AString chartSourceFileName = chartDataSource->getChartableFileName(); if (chartMapFileName == chartSourceFileName) { const ChartDataSourceModeEnum::Enum sourceMode = chartDataSource->getDataSourceMode(); switch (sourceMode) { case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_INVALID: break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_FILE_ROW: { CaretAssert(0); } break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDEX: { AString structureName; int32_t surfaceNumberOfNodes = -1; int32_t nodeIndex = -1; chartDataSource->getSurfaceNode(structureName, surfaceNumberOfNodes, nodeIndex); bool structureNameValid = false; const StructureEnum::Enum structure = StructureEnum::fromName(structureName, &structureNameValid); chartDataOut = chartableBrainFile->loadLineSeriesChartDataForSurfaceNode(structure, nodeIndex); } break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDICES_AVERAGE: { AString structureName; int32_t surfaceNumberOfNodes = -1; std::vector nodeIndices; chartDataSource->getSurfaceNodeAverage(structureName, surfaceNumberOfNodes, nodeIndices); bool structureNameValid = false; const StructureEnum::Enum structure = StructureEnum::fromName(structureName, &structureNameValid); chartDataOut = chartableBrainFile->loadAverageLineSeriesChartDataForSurfaceNodes(structure, nodeIndices); } break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_VOXEL_IJK: { float voxelXYZ[3]; chartDataSource->getVolumeVoxel(voxelXYZ); chartDataOut= chartableBrainFile->loadLineSeriesChartDataForVoxelAtCoordinate(voxelXYZ); } break; } } } } if (chartableRowColumnFile != NULL) { if (chartableRowColumnFile->isLineSeriesChartDataTypeSupported(chartDataType)) { CaretMappableDataFile* chartMapFile = chartableRowColumnFile->getLineSeriesChartCaretMappableDataFile(); CaretAssert(chartMapFile); const ChartDataSource* chartDataSource = cartesianChart->getChartDataSource(); CaretAssert(chartDataSource); const AString chartMapFileName = chartMapFile->getFileName(); const AString chartSourceFileName = chartDataSource->getChartableFileName(); if (chartMapFileName == chartSourceFileName) { const ChartDataSourceModeEnum::Enum sourceMode = chartDataSource->getDataSourceMode(); switch (sourceMode) { case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_INVALID: break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_FILE_ROW: { AString chartFileName; int32_t fileRowIndex; chartDataSource->getFileRow(chartFileName, fileRowIndex); chartDataOut = chartableRowColumnFile->loadLineSeriesChartDataForRow(fileRowIndex); } break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDEX: { CaretAssert(0); } break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDICES_AVERAGE: { CaretAssert(0); } break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_VOXEL_IJK: { CaretAssert(0); } break; } } } } } } if (chartDataOut != NULL) { /* * Copy the source of the chart (node, surface, voxel, etc) */ chartDataOut->getChartDataSource()->copy(chartData->getChartDataSource()); const ChartDataCartesian* chartCartData = dynamic_cast(chartData); if (chartCartData != NULL) { chartDataOut->setColor(chartCartData->getColor()); } } return chartDataOut; } /** * Get a text description of the window's content. * * @param tabIndex * Index of the tab for content description. * @param descriptionOut * Description of the window's content. */ void ModelChart::getDescriptionOfContent(const int32_t tabIndex, PlainTextStringBuilder& descriptionOut) const { ChartModel* chartModel = NULL; switch (getSelectedChartOneDataType(tabIndex)) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: { CaretDataFileSelectionModel* sm = m_chartableMatrixFileSelectionModel[tabIndex]; const CaretDataFile* caretFile = sm->getSelectedFile(); if (caretFile != NULL) { descriptionOut.addLine("Matrix (layer) chart for: " + caretFile->getFileNameNoPath()); return; } } break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: { CaretDataFileSelectionModel* sm = m_chartableMatrixSeriesFileSelectionModel[tabIndex]; const CaretDataFile* caretFile = sm->getSelectedFile(); if (caretFile != NULL) { descriptionOut.addLine("Matrix (series) chart for: " + caretFile->getFileNameNoPath()); return; } } break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: chartModel = const_cast(getSelectedDataSeriesChartModel(tabIndex)); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: chartModel = const_cast(getSelectedFrequencySeriesChartModel(tabIndex)); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: chartModel = const_cast(getSelectedTimeSeriesChartModel(tabIndex)); break; } const ChartModel* chartModelConst = chartModel; if (chartModel != NULL) { descriptionOut.addLine("Chart Type: " + ChartOneDataTypeEnum::toGuiName(chartModel->getChartDataType())); descriptionOut.pushIndentation(); const std::vector cdVec = chartModelConst->getAllChartDatas(); for (std::vector::const_iterator iter = cdVec.begin(); iter != cdVec.end(); iter++) { const ChartData* cd = *iter; if (cd->isSelected(tabIndex)) { descriptionOut.addLine(cd->getChartDataSource()->getDescription()); } } if (chartModel->isAverageChartDisplaySupported()) { if (chartModel->isAverageChartDisplaySelected()) { descriptionOut.addLine("Average Chart Displayed"); } } descriptionOut.popIndentation(); } else { descriptionOut.addLine("No charts to display"); } } /** * Copy the tab content from the source tab index to the * destination tab index. * * @param sourceTabIndex * Source from which tab content is copied. * @param destinationTabIndex * Destination to which tab content is copied. */ void ModelChart::copyTabContent(const int32_t sourceTabIndex, const int32_t destinationTabIndex) { Model::copyTabContent(sourceTabIndex, destinationTabIndex); m_overlaySetArray->copyOverlaySet(sourceTabIndex, destinationTabIndex); m_selectedChartOneDataType[destinationTabIndex] = m_selectedChartOneDataType[sourceTabIndex]; *m_chartModelDataSeries[destinationTabIndex] = *m_chartModelDataSeries[sourceTabIndex]; *m_chartModelFrequencySeries[destinationTabIndex] = *m_chartModelFrequencySeries[sourceTabIndex]; *m_chartModelTimeSeries[destinationTabIndex] = *m_chartModelTimeSeries[sourceTabIndex]; m_chartableMatrixFileSelectionModel[destinationTabIndex]->setSelectedFile(m_chartableMatrixFileSelectionModel[sourceTabIndex]->getSelectedFile()); m_chartableMatrixSeriesFileSelectionModel[destinationTabIndex]->setSelectedFile(m_chartableMatrixSeriesFileSelectionModel[sourceTabIndex]->getSelectedFile()); } /** * Set the type of chart selected in the given tab. * * @param tabIndex * Index of tab. * @param dataType * Type of data for chart. */ void ModelChart::setSelectedChartOneDataType(const int32_t tabIndex, const ChartOneDataTypeEnum::Enum dataType) { CaretAssertArrayIndex(m_selectedChartOneDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_selectedChartOneDataType[tabIndex] = dataType; } /** * Get the valid chart data types based upon the currently loaded files. * * @param validChartDataTypesOut * Output containing valid chart data types. */ void ModelChart::getValidChartOneDataTypes(std::vector& validChartDataTypesOut) const { validChartDataTypesOut.clear(); bool haveDataSeries = false; bool haveFrequencySeries = false; bool haveMatrixLayers = false; bool haveMatrixSeries = false; bool haveTimeSeries = false; std::vector allLineChartableFiles; m_brain->getAllChartableLineSeriesDataFiles(allLineChartableFiles); for (std::vector::iterator fileIter = allLineChartableFiles.begin(); fileIter != allLineChartableFiles.end(); fileIter++) { ChartableLineSeriesInterface* chartFile = *fileIter; std::vector chartDataTypes; chartFile->getSupportedLineSeriesChartDataTypes(chartDataTypes); for (std::vector::iterator typeIter = chartDataTypes.begin(); typeIter != chartDataTypes.end(); typeIter++) { const ChartOneDataTypeEnum::Enum cdt = *typeIter; switch (cdt) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: haveDataSeries = true; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: haveFrequencySeries = true; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: haveTimeSeries = true; break; } } } std::vector allMatrixChartableFiles; m_brain->getAllChartableMatrixDataFiles(allMatrixChartableFiles); for (std::vector::iterator fileIter = allMatrixChartableFiles.begin(); fileIter != allMatrixChartableFiles.end(); fileIter++) { ChartableMatrixInterface* chartFile = *fileIter; std::vector chartDataTypes; chartFile->getSupportedMatrixChartDataTypes(chartDataTypes); for (std::vector::iterator typeIter = chartDataTypes.begin(); typeIter != chartDataTypes.end(); typeIter++) { const ChartOneDataTypeEnum::Enum cdt = *typeIter; switch (cdt) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: haveMatrixLayers = true; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: haveMatrixSeries = true; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: break; } } } if (haveDataSeries) { validChartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES); } if (haveFrequencySeries) { validChartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES); } if (haveMatrixLayers) { validChartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER); } if (haveMatrixSeries) { validChartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES); } if (haveTimeSeries) { validChartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); } } /** * Get the type of chart selected in the given tab. * * @param tabIndex * Index of tab. * @return * Chart type in the given tab. */ ChartOneDataTypeEnum::Enum ModelChart::getSelectedChartOneDataType(const int32_t tabIndex) const { CaretAssertArrayIndex(m_selectedChartOneDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); ChartOneDataTypeEnum::Enum chartDataType = m_selectedChartOneDataType[tabIndex]; /* * Verify that the selected chart data type is valid. */ std::vector validChartDataTypes; getValidChartOneDataTypes(validChartDataTypes); if (std::find(validChartDataTypes.begin(), validChartDataTypes.end(), chartDataType) == validChartDataTypes.end()) { chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; } /* * If selected chart data type is invalid, find a valid chart type, * preferably one that contains data. */ if (chartDataType == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { if ( ! validChartDataTypes.empty()) { /* * Will become the the first valid chart data type that contains * data (if there is one) */ ChartOneDataTypeEnum::Enum chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; /* * Loop through all chart types (some or all valid charts * types may not contain data until the user commands loading of data) */ std::vector allChartDataTypes; ChartOneDataTypeEnum::getAllEnums(allChartDataTypes); for (std::vector::iterator iter = allChartDataTypes.begin(); iter != allChartDataTypes.end(); iter++) { const ChartOneDataTypeEnum::Enum cdt = *iter; if (std::find(validChartDataTypes.begin(), validChartDataTypes.end(), cdt) != validChartDataTypes.end()) { if (chartDataType == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { chartDataType = cdt; } switch (cdt) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: if (chartDataTypeWithValidData == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER; } break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: if (chartDataTypeWithValidData == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES; } break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: if (m_chartModelDataSeries[tabIndex]->getNumberOfChartData() > 0) { if (chartDataTypeWithValidData == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES; } } break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: if (m_chartModelFrequencySeries[tabIndex]->getNumberOfChartData() > 0) { if (chartDataTypeWithValidData == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES; } } break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: if (m_chartModelTimeSeries[tabIndex]->getNumberOfChartData() > 0) { if (chartDataTypeWithValidData == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { chartDataTypeWithValidData = ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES; } } break; } } } if (chartDataTypeWithValidData != ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { chartDataType = chartDataTypeWithValidData; } else if (chartDataType == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { chartDataType = validChartDataTypes[0]; } } } /* * Selected type may have changed due to loaded files changing */ m_selectedChartOneDataType[tabIndex] = chartDataType; return chartDataType; } /** * Update the chart overlay sets. * * @param tabIndex * Index of the tab. */ void ModelChart::updateChartOverlaySets(const int32_t /*tabIndex*/) { } /** * Get the data series chart model selected in the given tab. * * @param tabIndex * Index of tab. * @return * Data series chart model in the given tab. */ ChartModelDataSeries* ModelChart::getSelectedDataSeriesChartModel(const int32_t tabIndex) { const ChartModelDataSeries* model = getSelectedDataSeriesChartModelHelper(tabIndex); if (model == NULL) { return NULL; } ChartModelDataSeries* nonConstModel = const_cast(model); return nonConstModel; } /** * Get the data series chart model selected in the given tab. * * @param tabIndex * Index of tab. * @return * Data series chart model in the given tab. */ const ChartModelDataSeries* ModelChart::getSelectedDataSeriesChartModel(const int32_t tabIndex) const { return getSelectedDataSeriesChartModelHelper(tabIndex); } /** * Helper to get the data series chart model selected in the given tab. * * @param tabIndex * Index of tab. * @return * Data series chart model in the given tab. */ const ChartModelDataSeries* ModelChart::getSelectedDataSeriesChartModelHelper(const int32_t tabIndex) const { CaretAssertArrayIndex(m_chartModelDataSeries, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_chartModelDataSeries[tabIndex]; } /** * Get the time series chart model selected in the given tab. * * @param tabIndex * Index of tab. * @return * time series chart model in the given tab. */ ChartModelFrequencySeries* ModelChart::getSelectedFrequencySeriesChartModel(const int32_t tabIndex) { const ChartModelFrequencySeries* model = getSelectedFrequencySeriesChartModelHelper(tabIndex); if (model == NULL) { return NULL; } ChartModelFrequencySeries* nonConstModel = const_cast(model); return nonConstModel; } /** * Get the time series chart model selected in the given tab. * * @param tabIndex * Index of tab. * @return * time series chart model in the given tab. */ const ChartModelFrequencySeries* ModelChart::getSelectedFrequencySeriesChartModel(const int32_t tabIndex) const { return getSelectedFrequencySeriesChartModelHelper(tabIndex); } /** * Helper to get the time series chart model selected in the given tab. * * @param tabIndex * Index of tab. * @return * time series chart model in the given tab. */ const ChartModelFrequencySeries* ModelChart::getSelectedFrequencySeriesChartModelHelper(const int32_t tabIndex) const { CaretAssertArrayIndex(m_chartModelFrequencySeries, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_chartModelFrequencySeries[tabIndex]; } /** * Get the time series chart model selected in the given tab. * * @param tabIndex * Index of tab. * @return * time series chart model in the given tab. */ ChartModelTimeSeries* ModelChart::getSelectedTimeSeriesChartModel(const int32_t tabIndex) { const ChartModelTimeSeries* model = getSelectedTimeSeriesChartModelHelper(tabIndex); if (model == NULL) { return NULL; } ChartModelTimeSeries* nonConstModel = const_cast(model); return nonConstModel; } /** * Get the time series chart model selected in the given tab. * * @param tabIndex * Index of tab. * @return * time series chart model in the given tab. */ const ChartModelTimeSeries* ModelChart::getSelectedTimeSeriesChartModel(const int32_t tabIndex) const { return getSelectedTimeSeriesChartModelHelper(tabIndex); } /** * Helper to get the time series chart model selected in the given tab. * * @param tabIndex * Index of tab. * @return * time series chart model in the given tab. */ const ChartModelTimeSeries* ModelChart::getSelectedTimeSeriesChartModelHelper(const int32_t tabIndex) const { CaretAssertArrayIndex(m_chartModelTimeSeries, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_chartModelTimeSeries[tabIndex]; } /** * Get the chartable matrix parcel file selection model for the given tab. * * @param tabIndex * Index of the tab. * @return * Chartable file selection model for the tab. */ CaretDataFileSelectionModel* ModelChart::getChartableMatrixParcelFileSelectionModel(const int32_t tabIndex) { CaretAssertArrayIndex(m_chartableMatrixFileSelectionModel, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_chartableMatrixFileSelectionModel[tabIndex]; } /** * Get the chartable matrix series file selection model for the given tab. * * @param tabIndex * Index of the tab. * @return * Chartable file selection model for the tab. */ CaretDataFileSelectionModel* ModelChart::getChartableMatrixSeriesFileSelectionModel(const int32_t tabIndex) { CaretAssertArrayIndex(m_chartableMatrixSeriesFileSelectionModel, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_chartableMatrixSeriesFileSelectionModel[tabIndex]; } connectome-workbench-1.4.2/src/Brain/ModelChart.h000066400000000000000000000217151360521144700216560ustar00rootroot00000000000000#ifndef __MODEL_CHART_H__ #define __MODEL_CHART_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include "ChartOneDataTypeEnum.h" #include "EventListenerInterface.h" #include "MapYokingGroupEnum.h" #include "Model.h" #include "StructureEnum.h" namespace caret { class CaretDataFileSelectionModel; class ChartData; class ChartDataCartesian; class ChartDataSource; class ChartableLineSeriesBrainordinateInterface; class ChartableLineSeriesInterface; class ChartableLineSeriesRowColumnInterface; class ChartableMatrixInterface; class ChartModel; class ChartModelDataSeries; class ChartModelFrequencySeries; class ChartModelTimeSeries; class CiftiConnectivityMatrixParcelFile; class CiftiMappableDataFile; class OverlaySetArray; class SurfaceFile; /// Controls the display of a chart. class ModelChart : public Model, public EventListenerInterface { public: ModelChart(Brain* brain); virtual ~ModelChart(); void initializeOverlays(); AString getNameForGUI(const bool includeStructureFlag) const; virtual AString getNameForBrowserTab() const; void loadChartDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const int32_t nodeIndex); void loadAverageChartDataForSurfaceNodes(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const std::vector& nodeIndices); void loadChartDataForVoxelAtCoordinate(const float xyz[3]); void loadChartDataForCiftiMappableFileRow(CiftiMappableDataFile* ciftiMapFile, const int32_t rowIndex); void loadChartDataForYokedCiftiMappableFiles(const MapYokingGroupEnum::Enum mapYokingGroup, const int32_t mapIndex); OverlaySet* getOverlaySet(const int tabIndex); const OverlaySet* getOverlaySet(const int tabIndex) const; virtual void receiveEvent(Event* event); void getValidChartOneDataTypes(std::vector& validChartDataTypesOut) const; ChartOneDataTypeEnum::Enum getSelectedChartOneDataType(const int32_t tabIndex) const; void setSelectedChartOneDataType(const int32_t tabIndex, const ChartOneDataTypeEnum::Enum dataType); ChartModelDataSeries* getSelectedDataSeriesChartModel(const int32_t tabIndex); const ChartModelDataSeries* getSelectedDataSeriesChartModel(const int32_t tabIndex) const; ChartModelFrequencySeries* getSelectedFrequencySeriesChartModel(const int32_t tabIndex); const ChartModelFrequencySeries* getSelectedFrequencySeriesChartModel(const int32_t tabIndex) const; ChartModelTimeSeries* getSelectedTimeSeriesChartModel(const int32_t tabIndex); const ChartModelTimeSeries* getSelectedTimeSeriesChartModel(const int32_t tabIndex) const; virtual void getDescriptionOfContent(const int32_t tabIndex, PlainTextStringBuilder& descriptionOut) const; virtual void copyTabContent(const int32_t sourceTabIndex, const int32_t destinationTabIndex); void reset(); CaretDataFileSelectionModel* getChartableMatrixParcelFileSelectionModel(const int32_t tabIndex); CaretDataFileSelectionModel* getChartableMatrixSeriesFileSelectionModel(const int32_t tabIndex); protected: virtual void saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: ModelChart(const ModelChart&); ModelChart& operator=(const ModelChart&); void addChartToChartModels(const std::vector& tabIndices, ChartData* chartData); void initializeCharts(); void removeAllCharts(); const ChartModelDataSeries* getSelectedDataSeriesChartModelHelper(const int32_t tabIndex) const; const ChartModelFrequencySeries* getSelectedFrequencySeriesChartModelHelper(const int32_t tabIndex) const; const ChartModelTimeSeries* getSelectedTimeSeriesChartModelHelper(const int32_t tabIndex) const; void updateChartOverlaySets(const int32_t tabIndex); void saveChartModelsToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass, const std::vector& tabIndices, std::set& validChartDataIDsOut); void restoreVersionOneChartModelsFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); void getTabsAndBrainordinateChartFilesForLineChartLoading(std::map >& chartBrainordinateFileEnabledTabsOut) const; void getTabsAndRowColumnChartFilesForLineChartLoading(std::map >& chartRowColumnFilesEnabledTabsOut) const; void getTabsAndLineSeriesChartFilesForLineChartLoading(std::map >& chartFileEnabledTabsOut) const; ChartData* loadCartesianChartWhenRestoringScene(const ChartData* chartData); virtual void saveVersionOneModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); void restoreVersionOneModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); /** Overlays sets for this model and for each tab */ OverlaySetArray* m_overlaySetArray; mutable ChartOneDataTypeEnum::Enum m_selectedChartOneDataType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** Chart model for data-series data */ ChartModelDataSeries* m_chartModelDataSeries[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** Chart model for frequency-series data */ ChartModelFrequencySeries* m_chartModelFrequencySeries[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** Chart model for time-series data */ ChartModelTimeSeries* m_chartModelTimeSeries[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** Contains data series charts */ std::list > m_dataSeriesChartData; /** Contains time series charts */ std::list > m_frequencySeriesChartData; /** Contains time series charts */ std::list > m_timeSeriesChartData; std::vector m_previousChartMatrixFiles; CaretDataFileSelectionModel* m_chartableMatrixFileSelectionModel[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; CaretDataFileSelectionModel* m_chartableMatrixSeriesFileSelectionModel[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; std::unique_ptr m_sceneAssistant; friend class ModelChartTwo; }; } // namespace #endif // __MODEL_CHART_H__ connectome-workbench-1.4.2/src/Brain/ModelChartTwo.cxx000066400000000000000000001343641360521144700227300ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "AnnotationColorBar.h" #include "Brain.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretMappableDataFile.h" #include "CaretDataFileSelectionModel.h" #include "CaretLogger.h" #include "ChartData.h" #include "ChartDataCartesian.h" #include "ChartDataSource.h" #include "ChartableTwoFileDelegate.h" #include "ChartableMatrixParcelInterface.h" #include "ChartableMatrixSeriesInterface.h" #include "ChartMatrixDisplayProperties.h" #include "ChartModelDataSeries.h" #include "ChartModelFrequencySeries.h" #include "ChartModelTimeSeries.h" #include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileMatrixChart.h" #include "ChartableTwoFileLineSeriesChart.h" #include "ChartTwoLineSeriesHistory.h" #include "ChartTwoOverlay.h" #include "ChartTwoOverlaySet.h" #include "ChartTwoOverlaySetArray.h" #include "ChartingVersionEnum.h" #include "ConnectivityDataLoaded.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "CiftiMappableDataFile.h" #include "CiftiScalarDataSeriesFile.h" #include "EventBrowserTabGet.h" #include "EventBrowserTabGetAll.h" #include "EventBrowserTabIndicesGetAll.h" #include "EventCaretMappableDataFilesGet.h" #include "EventChartTwoLoadLineSeriesData.h" #include "EventManager.h" #include "EventNodeIdentificationColorsGetFromCharts.h" #include "MapFileDataSelector.h" #include "ModelChart.h" #include "ModelChartTwo.h" #include "OverlaySet.h" #include "OverlaySetArray.h" #include "PlainTextStringBuilder.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneClassAssistant.h" #include "SceneObjectMapIntegerKey.h" #include "SurfaceFile.h" using namespace caret; /** * Constructor. * */ ModelChartTwo::ModelChartTwo(Brain* brain) : Model(ModelTypeEnum::MODEL_TYPE_CHART_TWO, brain) { std::vector overlaySurfaceStructures; m_overlaySetArray = new OverlaySetArray(overlaySurfaceStructures, Overlay::INCLUDE_VOLUME_FILES_YES, "Chart View"); m_histogramChartOverlaySetArray = std::unique_ptr(new ChartTwoOverlaySetArray(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM, "Histogram Chart Overlays")); m_matrixChartOverlaySetArray = std::unique_ptr(new ChartTwoOverlaySetArray(ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX, "Matrix Chart Overlays")); m_lineSeriesChartOverlaySetArray = std::unique_ptr(new ChartTwoOverlaySetArray(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, "Line Series Chart Overlays")); initializeCharts(); m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_selectedChartTwoDataType", m_selectedChartTwoDataType); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS); } /** * Destructor */ ModelChartTwo::~ModelChartTwo() { delete m_overlaySetArray; EventManager::get()->removeAllEventsFromListener(this); removeAllCharts(); } void ModelChartTwo::initializeCharts() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_selectedChartTwoDataType[i] = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; } } /** * Reset this model. */ void ModelChartTwo::reset() { removeAllCharts(); initializeCharts(); } /** * Remove all of the charts. */ void ModelChartTwo::removeAllCharts() { } /** * Load chart data for a surface node. * * @param structure * The surface structure * @param surfaceNumberOfNodes * Number of nodes in surface. * @param nodeIndex * Index of node. * @throws * DataFileException if there is an error loading data. */ void ModelChartTwo::loadChartDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const int32_t nodeIndex) { std::vector tabIndices; EventBrowserTabIndicesGetAll tabIndicesEvent; EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); MapFileDataSelector mapFileDataSelector; mapFileDataSelector.setSurfaceVertex(structure, surfaceNumberOfNodes, nodeIndex); EventChartTwoLoadLineSeriesData chartTwoLineSeriesEvent(tabIndicesEvent.getAllBrowserTabIndices(), mapFileDataSelector); EventManager::get()->sendEvent(chartTwoLineSeriesEvent.getPointer()); } /** * Load chart data for an average of surface nodes. * * @param structure * The surface structure * @param surfaceNumberOfNodes * Number of nodes in surface. * @param nodeIndices * Indices of node. * @throws * DataFileException if there is an error loading data. */ void ModelChartTwo::loadAverageChartDataForSurfaceNodes(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const std::vector& nodeIndices) { std::vector tabIndices; EventBrowserTabIndicesGetAll tabIndicesEvent; EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); MapFileDataSelector mapFileDataSelector; mapFileDataSelector.setSurfaceVertexAverage(structure, surfaceNumberOfNodes, nodeIndices); EventChartTwoLoadLineSeriesData chartTwoLineSeriesEvent(tabIndicesEvent.getAllBrowserTabIndices(), mapFileDataSelector); EventManager::get()->sendEvent(chartTwoLineSeriesEvent.getPointer()); } /** * Load chart data for voxel at the given coordinate. * * @param xyz * Coordinate of voxel. * @throws * DataFileException if there is an error loading data. */ void ModelChartTwo::loadChartDataForVoxelAtCoordinate(const float xyz[3]) { std::vector tabIndices; EventBrowserTabIndicesGetAll tabIndicesEvent; EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); MapFileDataSelector mapFileDataSelector; mapFileDataSelector.setVolumeVoxelXYZ(xyz); EventChartTwoLoadLineSeriesData chartTwoLineSeriesEvent(tabIndicesEvent.getAllBrowserTabIndices(), mapFileDataSelector); EventManager::get()->sendEvent(chartTwoLineSeriesEvent.getPointer()); } /** * Load chart data from given file at the given row. * * @param ciftiMapFile * The CIFTI file. * @param rowIndex * Index of row in the file. */ void ModelChartTwo::loadChartDataForCiftiMappableFileRow(CiftiMappableDataFile* ciftiMapFile, const int32_t rowIndex) { CaretAssert(ciftiMapFile); //std::vector tabIndices; EventBrowserTabIndicesGetAll tabIndicesEvent; EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); MapFileDataSelector mapFileDataSelector; mapFileDataSelector.setRowIndex(ciftiMapFile, ciftiMapFile->getFileName(), rowIndex); EventChartTwoLoadLineSeriesData chartTwoLineSeriesEvent(tabIndicesEvent.getAllBrowserTabIndices(), mapFileDataSelector); EventManager::get()->sendEvent(chartTwoLineSeriesEvent.getPointer()); } /** * Load line chart data for yoked CIFTI scalar data series files * * @param mapYokingGroup * The map yoking group. * @param mapIndex * The map index. */ void ModelChartTwo::loadChartDataForYokedScalarDataSeriesFiles(const MapYokingGroupEnum::Enum mapYokingGroup, const int32_t mapIndex) { if (mapYokingGroup == MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { return; } EventBrowserTabIndicesGetAll tabIndicesEvent; EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); const std::vector tabIndices = tabIndicesEvent.getAllBrowserTabIndices(); /* * Find Cifti Scalar Data Series Files in valid Chart Overlays that * have chart line series data loading enabled */ std::set dataSeriesFiles; for (auto tabIndex : tabIndices) { CaretAssertArrayIndex(m_selectedChartTwoDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); if (m_selectedChartTwoDataType[tabIndex] == ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES) { const ChartTwoOverlaySet* overlaySet = m_lineSeriesChartOverlaySetArray->getChartTwoOverlaySet(tabIndex); CaretAssert(overlaySet); const int32_t numOverlays = overlaySet->getNumberOfDisplayedOverlays(); for (int32_t iOverlay = 0; iOverlay < numOverlays; iOverlay++) { const ChartTwoOverlay* overlay = overlaySet->getOverlay(iOverlay); CaretAssert(overlay); if (overlay->isEnabled() && overlay->isLineSeriesLoadingEnabled()) { if (overlay->getMapYokingGroup() == mapYokingGroup) { CaretMappableDataFile* mapFile = overlay->getSelectedMapFile(); if (mapFile != NULL) { if (mapFile->getDataFileType() == DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES) { CiftiScalarDataSeriesFile* scalarDataSeriesFile = dynamic_cast(mapFile); CaretAssert(scalarDataSeriesFile); dataSeriesFiles.insert(scalarDataSeriesFile); } } } } } } } for (auto seriesFile : dataSeriesFiles) { loadChartDataForCiftiMappableFileRow(seriesFile, mapIndex); } } /** * Select yoked row/column in scalar data series file's overlay * * @param mapYokingGroup * The map yoking group. * @param mapIndex * The map index. */ void ModelChartTwo::selectRowColumnInYokedScalarDataSeriesFileOverlay(const MapYokingGroupEnum::Enum mapYokingGroup, const int32_t mapIndex) { if (mapYokingGroup == MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { return; } EventBrowserTabIndicesGetAll tabIndicesEvent; EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); const std::vector tabIndices = tabIndicesEvent.getAllBrowserTabIndices(); /* * Find Cifti Scalar Data Series Files in valid Chart Overlays that * have the matching yoking group */ for (auto tabIndex : tabIndices) { CaretAssertArrayIndex(m_selectedChartTwoDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); if (m_selectedChartTwoDataType[tabIndex] == ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX) { ChartTwoOverlaySet* overlaySet = m_matrixChartOverlaySetArray->getChartTwoOverlaySet(tabIndex); CaretAssert(overlaySet); const int32_t numOverlays = overlaySet->getNumberOfDisplayedOverlays(); for (int32_t iOverlay = 0; iOverlay < numOverlays; iOverlay++) { ChartTwoOverlay* overlay = overlaySet->getOverlay(iOverlay); CaretAssert(overlay); if (overlay->isEnabled()) { if (overlay->getMapYokingGroup() == mapYokingGroup) { CaretMappableDataFile* mapFile = overlay->getSelectedMapFile(); if (mapFile != NULL) { if (mapFile->getDataFileType() == DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES) { overlay->setSelectionData(mapFile, mapIndex); } } } } } } } } /** * Receive an event. * * @param event * The event that the receive can respond to. */ void ModelChartTwo::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS) { EventNodeIdentificationColorsGetFromCharts* nodeChartID = dynamic_cast(event); CaretAssert(nodeChartID); EventBrowserTabGetAll allTabsEvent; EventManager::get()->sendEvent(allTabsEvent.getPointer()); std::vector validTabIndices = allTabsEvent.getBrowserTabIndices(); const AString structureName = nodeChartID->getStructureName(); std::vector cartesianChartData; // for (std::list >::iterator dsIter = m_dataSeriesChartData.begin(); // dsIter != m_dataSeriesChartData.end(); // dsIter++) { // QSharedPointer spCart = dsIter->toStrongRef(); // if ( ! spCart.isNull()) { // cartesianChartData.push_back(spCart.data()); // } // } // for (std::list >::iterator tsIter = m_frequencySeriesChartData.begin(); // tsIter != m_frequencySeriesChartData.end(); // tsIter++) { // QSharedPointer spCart = tsIter->toStrongRef(); // if ( ! spCart.isNull()) { // cartesianChartData.push_back(spCart.data()); // } // } // for (std::list >::iterator tsIter = m_timeSeriesChartData.begin(); // tsIter != m_timeSeriesChartData.end(); // tsIter++) { // QSharedPointer spCart = tsIter->toStrongRef(); // if ( ! spCart.isNull()) { // cartesianChartData.push_back(spCart.data()); // } // } // // // /* // * Iterate over node indices for which colors are desired. // */ // const std::vector nodeIndices = nodeChartID->getNodeIndices(); // for (std::vector::const_iterator nodeIter = nodeIndices.begin(); // nodeIter != nodeIndices.end(); // nodeIter++) { // const int32_t nodeIndex = *nodeIter; // // /* // * Iterate over the data in the cartesian chart // */ // for (std::vector::iterator cdIter = cartesianChartData.begin(); // cdIter != cartesianChartData.end(); // cdIter++) { // const ChartDataCartesian* cdc = *cdIter; // const ChartDataSource* cds = cdc->getChartDataSource(); // if (cds->isSurfaceNodeSourceOfData(structureName, nodeIndex)) { // /* // * Found node index so add its color to the event // */ // const CaretColorEnum::Enum color = cdc->getColor(); // const float* rgb = CaretColorEnum::toRGB(color); // nodeChartID->addNode(nodeIndex, // rgb); // break; // } // } // } nodeChartID->setEventProcessed(); } } /** * Get the name for use in a GUI. * * @param includeStructureFlag - Prefix label with structure to which * this structure model belongs. * @return Name for use in a GUI. * */ AString ModelChartTwo::getNameForGUI(const bool /*includeStructureFlag*/) const { AString name = "Chart"; return name; } /** * @return The name that should be displayed in the tab * displaying this model. */ AString ModelChartTwo::getNameForBrowserTab() const { AString name = "Chart"; return name; } /** * Get the overlay set for the given tab. * @param tabIndex * Index of tab. * @return * Overlay set at the given tab index. */ OverlaySet* ModelChartTwo::getOverlaySet(const int tabIndex) { CaretAssertArrayIndex(m_overlaySetArray, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_overlaySetArray->getOverlaySet(tabIndex); } /** * Get the overlay set for the given tab. * @param tabIndex * Index of tab. * @return * Overlay set at the given tab index. */ const OverlaySet* ModelChartTwo::getOverlaySet(const int tabIndex) const { CaretAssertArrayIndex(m_overlaySetArray, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_overlaySetArray->getOverlaySet(tabIndex); } /** * Initilize the overlays for this model. */ void ModelChartTwo::initializeOverlays() { m_overlaySetArray->initializeOverlaySelections(); } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param sceneClass * SceneClass to which model specific information is added. */ void ModelChartTwo::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { const std::vector validTabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); std::vector histogramChartTabIndices; std::vector lineSeriesChartTabIndices; std::vector matrixChartTabIndices; for (auto tabIndex : validTabIndices) { switch (m_selectedChartTwoDataType[tabIndex]) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: histogramChartTabIndices.push_back(tabIndex); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: lineSeriesChartTabIndices.push_back(tabIndex); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: matrixChartTabIndices.push_back(tabIndex); break; } } if ( ! histogramChartTabIndices.empty()) { SceneClass* histogramClass = m_histogramChartOverlaySetArray->saveTabIndicesToScene(histogramChartTabIndices, sceneAttributes, "m_histogramChartOverlaySetArray"); if (histogramClass != NULL) { sceneClass->addClass(histogramClass); } } if ( ! lineSeriesChartTabIndices.empty()) { SceneClass* lineSeriesClass = m_lineSeriesChartOverlaySetArray->saveTabIndicesToScene(lineSeriesChartTabIndices, sceneAttributes, "m_lineSeriesChartOverlaySetArray"); if (lineSeriesClass != NULL) { sceneClass->addClass(lineSeriesClass); } } if ( ! matrixChartTabIndices.empty()) { SceneClass* matrixClass = m_matrixChartOverlaySetArray->saveTabIndicesToScene(matrixChartTabIndices, sceneAttributes, "m_matrixChartOverlaySetArray"); if (matrixClass != NULL) { sceneClass->addClass(matrixClass); } } m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ModelChartTwo::restoreModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { reset(); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); m_histogramChartOverlaySetArray->restoreFromScene(sceneAttributes, sceneClass->getClass("m_histogramChartOverlaySetArray")); m_lineSeriesChartOverlaySetArray->restoreFromScene(sceneAttributes, sceneClass->getClass("m_lineSeriesChartOverlaySetArray")); m_matrixChartOverlaySetArray->restoreFromScene(sceneAttributes, sceneClass->getClass("m_matrixChartOverlaySetArray")); } /** * Try to restore a scene from a version one chart model * by copying data from the chart one model. * * @param modelChartOne * The charting version one model. */ void ModelChartTwo::restoreSceneFromChartOneModel(ModelChart* modelChartOne) { if (isRestoredFromScene()) { CaretAssert(0); } setRestoredFromScene(true); EventBrowserTabGetAll allTabsEvent; EventManager::get()->sendEvent(allTabsEvent.getPointer()); std::vector validTabIndices = allTabsEvent.getBrowserTabIndices(); bool haveLineSeriesModelsFlag = true; for (auto tabIndex : validTabIndices) { switch (modelChartOne->getSelectedChartOneDataType(tabIndex)) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: setSelectedChartTwoDataType(tabIndex, ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES); haveLineSeriesModelsFlag = true; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: setSelectedChartTwoDataType(tabIndex, ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX); restoreMatrixChartFromChartOneModel(modelChartOne, tabIndex); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: setSelectedChartTwoDataType(tabIndex, ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX); restoreMatrixChartFromChartOneModel(modelChartOne, tabIndex); break; } } if (haveLineSeriesModelsFlag) { restoreLineSeriesChartFromChartOneModel(modelChartOne); } } /** * Attempt to restore line series data from a chart version one scene. * * @param modelChartOne * The chart one model. */ void ModelChartTwo::restoreLineSeriesChartFromChartOneModel(ModelChart* modelChartOne) { CaretAssert(modelChartOne); std::set dataSources; int32_t maxDisplayCount = 0; std::vector validTabIndices; std::map dataFileNamesAndColors; /* * Loop through all tabs to find those containing line-series style charts */ for (int32_t iTab = 0; iTab < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; iTab++) { ChartModelCartesian* cartesianModel = NULL; switch (modelChartOne->getSelectedChartOneDataType(iTab)) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: cartesianModel = modelChartOne->getSelectedDataSeriesChartModel(iTab); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: cartesianModel = modelChartOne->getSelectedFrequencySeriesChartModel(iTab); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: cartesianModel = modelChartOne->getSelectedTimeSeriesChartModel(iTab); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; } if (cartesianModel != NULL) { validTabIndices.push_back(iTab); maxDisplayCount = std::max(maxDisplayCount, cartesianModel->getMaximumNumberOfChartDatasToDisplay()); /* * Examine all lines in the tab */ const int32_t numChartLines = cartesianModel->getNumberOfChartData(); for (int32_t i = (numChartLines - 1); i >= 0; i--) { const ChartData* chartData = cartesianModel->getChartDataAtIndex(i); if (chartData != NULL) { const ChartDataSource* chartDataSource = chartData->getChartDataSource(); if (chartData->isSelected(iTab)) { ChartDataSource dataSourceCopy(*chartDataSource); dataSources.insert(dataSourceCopy); const ChartDataCartesian* cartesianData = dynamic_cast(chartData); CaretColorEnum::Enum color = CaretColorEnum::RED; if (cartesianData != NULL) { color = cartesianData->getColor(); } dataFileNamesAndColors.insert(std::make_pair(chartDataSource->getChartableFileName(), color)); } } } } } std::vector allDataFiles; EventCaretMappableDataFilesGet eventGetMapDataFiles; EventManager::get()->sendEvent(eventGetMapDataFiles.getPointer()); eventGetMapDataFiles.getAllFiles(allDataFiles); std::vector overlayMapFiles; /* * Find the data files and setup for loading of * lines series data. */ for (const auto filenameAndColor : dataFileNamesAndColors) { const AString filename = filenameAndColor.first; CaretColorEnum::Enum color = filenameAndColor.second; CaretMappableDataFile* mapFileFullPath = NULL; CaretMappableDataFile* mapFileNoPath = NULL; for (auto mapFile : allDataFiles) { if (filename == mapFile->getFileName()) { mapFileFullPath = mapFile; } if (mapFile->getFileName().endsWith(filename)) { mapFileNoPath = mapFile; } } ChartTwoLineSeriesHistory* lineSeriesHistory = NULL; if (mapFileFullPath != NULL) { lineSeriesHistory = mapFileFullPath->getChartingDelegate()->getLineSeriesCharting()->getHistory(); overlayMapFiles.push_back(mapFileFullPath); } else if (mapFileNoPath != NULL) { lineSeriesHistory = mapFileNoPath->getChartingDelegate()->getLineSeriesCharting()->getHistory(); overlayMapFiles.push_back(mapFileNoPath); } else { CaretLogWarning("Unable to find data file with name: " + filename); } if (lineSeriesHistory != NULL) { lineSeriesHistory->setLoadingEnabled(true); if (maxDisplayCount <= 0) { maxDisplayCount = 1; } lineSeriesHistory->setDisplayCount(maxDisplayCount); lineSeriesHistory->setDefaultColor(color); } } /* * Send events to load line charts for the brainordinates * found in the older charts */ for (const auto& ds : dataSources) { MapFileDataSelector mapFileDataSelector; switch (ds.getDataSourceMode()) { case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_FILE_ROW: break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_INVALID: break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDEX: { int32_t surfaceNumberOfVertices = -1; int32_t vertexIndex = -1; AString structureName; ds.getSurfaceNode(structureName, surfaceNumberOfVertices, vertexIndex); bool validFlag = false; const StructureEnum::Enum structure = StructureEnum::fromName(structureName, &validFlag); if (validFlag) { mapFileDataSelector.setSurfaceVertex(structure, surfaceNumberOfVertices, vertexIndex); } else { CaretLogWarning("Unrecogized structure name :" + structureName); } } break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDICES_AVERAGE: { int32_t surfaceNumberOfVertices = -1; AString structureName; std::vector vertices; ds.getSurfaceNodeAverage(structureName, surfaceNumberOfVertices, vertices); bool validFlag = false; const StructureEnum::Enum structure = StructureEnum::fromName(structureName, &validFlag); if (validFlag) { mapFileDataSelector.setSurfaceVertexAverage(structure, surfaceNumberOfVertices, vertices); } else { CaretLogWarning("Unrecogized structure name :" + structureName); } } break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_VOXEL_IJK: { float xyz[3]; ds.getVolumeVoxel(xyz); mapFileDataSelector.setVolumeVoxelXYZ(xyz); } break; } if (mapFileDataSelector.getDataSelectionType() != MapFileDataSelector::DataSelectionType::INVALID) { EventChartTwoLoadLineSeriesData loadLineDataEvent(validTabIndices, mapFileDataSelector); EventManager::get()->sendEvent(loadLineDataEvent.getPointer()); } } /* * Put line-series chart files into chart overlays */ const int32_t maxChartOverlays = 3; const int32_t numChartOverlayMapFiles = std::min(maxChartOverlays, static_cast(overlayMapFiles.size())); for (auto tabIndex : validTabIndices) { for (int32_t i = 0; i < numChartOverlayMapFiles; i++) { CaretAssertVectorIndex(overlayMapFiles, i); getChartTwoOverlaySet(tabIndex)->getOverlay(i)->setSelectionData(overlayMapFiles[i], 0); } } } /** * Restore matrix from model one chart by copying from the model. * * @param modelChartOne * The charting version one model. * @param tabIndex * Index of tab being restored */ void ModelChartTwo::restoreMatrixChartFromChartOneModel(ModelChart* modelChartOne, const int32_t tabIndex) { CaretAssert(modelChartOne); CaretDataFileSelectionModel* fileSelectionModel = NULL; switch (modelChartOne->getSelectedChartOneDataType(tabIndex)) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: CaretAssert(0); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: fileSelectionModel = modelChartOne->getChartableMatrixParcelFileSelectionModel(tabIndex); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: fileSelectionModel = modelChartOne->getChartableMatrixSeriesFileSelectionModel(tabIndex); break; } CaretDataFile* caretDataFile = fileSelectionModel->getSelectedFile(); if (caretDataFile == NULL) { return; } CaretMappableDataFile* mapFile = dynamic_cast(caretDataFile); if (mapFile == NULL) { return; } ChartableTwoFileMatrixChart* fileMatrixChart = mapFile->getChartingDelegate()->getMatrixCharting(); if (fileMatrixChart == NULL) { return; } ChartableMatrixParcelInterface* chartOneMatrixParcelFile = dynamic_cast(mapFile); ChartableMatrixSeriesInterface* chartOneMatrixSeriesFile = dynamic_cast(mapFile); int32_t selectedRowColumnIndex = -1; MapYokingGroupEnum::Enum chartOneYoking = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; ChartMatrixDisplayProperties* chartOneMatrixDisplayProperties = NULL; if (chartOneMatrixParcelFile != NULL) { chartOneMatrixDisplayProperties = chartOneMatrixParcelFile->getChartMatrixDisplayProperties(tabIndex); switch (chartOneMatrixParcelFile->getMatrixLoadingDimension()) { case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: fileMatrixChart->setSelectedRowColumnDimension(ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN); break; case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: fileMatrixChart->setSelectedRowColumnDimension(ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW); break; } CiftiMappableConnectivityMatrixDataFile* connMatrixFile = dynamic_cast(mapFile); if (connMatrixFile != NULL) { const ConnectivityDataLoaded* connDataLoaded = connMatrixFile->getConnectivityDataLoaded(); if (connDataLoaded != NULL) { int64_t loadedRowIndex = -1; int64_t loadedColumnIndex = -1; connDataLoaded->getRowColumnLoading(loadedRowIndex, loadedColumnIndex); if (loadedRowIndex >= 0) { selectedRowColumnIndex = loadedRowIndex; } else if (loadedColumnIndex >= 0) { selectedRowColumnIndex = loadedColumnIndex; } } } } else if (chartOneMatrixSeriesFile != NULL) { chartOneMatrixDisplayProperties = chartOneMatrixSeriesFile->getChartMatrixDisplayProperties(tabIndex); chartOneYoking = chartOneMatrixSeriesFile->getMatrixRowColumnMapYokingGroup(tabIndex); fileMatrixChart->setSelectedRowColumnDimension(ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW); selectedRowColumnIndex = chartOneMatrixSeriesFile->getSelectedMapIndex(tabIndex); } else { CaretAssertMessage(0, "Has new matrix chart type been added?"); return; } CaretAssert(chartOneMatrixDisplayProperties); AnnotationColorBar* chartOneColorBar = chartOneMatrixDisplayProperties->getColorBar(); EventBrowserTabGet getTabEvent(tabIndex); EventManager::get()->sendEvent(getTabEvent.getPointer()); BrowserTabContent* browserTabContent = getTabEvent.getBrowserTab(); if (browserTabContent != NULL) { ChartTwoOverlaySet* chartTwoOverlaySet = browserTabContent->getChartTwoOverlaySet(); CaretAssert(chartTwoOverlaySet); for (int32_t iOverlay = 0; iOverlay < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; iOverlay++) { ChartTwoOverlay* chartTwoOverlay = chartTwoOverlaySet->getOverlay(iOverlay); CaretAssert(chartTwoOverlay); if (iOverlay == 0) { chartTwoOverlay->setEnabled(true); chartTwoOverlay->setSelectionData(mapFile, selectedRowColumnIndex); chartTwoOverlay->setMatrixTriangularViewingMode(ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL); chartTwoOverlay->setAllMapsSelected(false); chartTwoOverlay->setCartesianVerticalAxisLocation(ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT); chartTwoOverlay->setMapYokingGroup(chartOneYoking); AnnotationColorBar* chartTwoColorBar = chartTwoOverlay->getColorBar(); if ((chartOneColorBar != NULL) && (chartTwoColorBar != NULL)) { *chartTwoColorBar = *chartOneColorBar; } } else { chartTwoOverlay->setEnabled(false); } } } } /** * Copy the tab content from the source tab index to the * destination tab index. * * @param sourceTabIndex * Source from which tab content is copied. * @param destinationTabIndex * Destination to which tab content is copied. */ void ModelChartTwo::copyTabContent(const int32_t sourceTabIndex, const int32_t destinationTabIndex) { Model::copyTabContent(sourceTabIndex, destinationTabIndex); m_overlaySetArray->copyOverlaySet(sourceTabIndex, destinationTabIndex); CaretAssertArrayIndex(m_selectedChartTwoDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, sourceTabIndex); CaretAssertArrayIndex(m_selectedChartTwoDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, destinationTabIndex); m_selectedChartTwoDataType[destinationTabIndex] = m_selectedChartTwoDataType[sourceTabIndex]; m_histogramChartOverlaySetArray->copyChartOverlaySet(sourceTabIndex, destinationTabIndex); m_lineSeriesChartOverlaySetArray->copyChartOverlaySet(sourceTabIndex, destinationTabIndex); m_matrixChartOverlaySetArray->copyChartOverlaySet(sourceTabIndex, destinationTabIndex); } /** * Copy cartesian axes from one tab to another. * * @param sourceTabIndex * Source from which tab content is copied. * @param destinationTabIndex * Destination to which tab content is copied. */ void ModelChartTwo::copyChartTwoCartesianAxes(const int32_t sourceTabIndex, const int32_t destinationTabIndex) { CaretAssertArrayIndex(m_histogramChartOverlaySetArray, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, sourceTabIndex); CaretAssertArrayIndex(m_lineSeriesChartOverlaySetArray, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, destinationTabIndex); m_histogramChartOverlaySetArray->copyChartOverlaySetCartesianAxes(sourceTabIndex, destinationTabIndex); m_lineSeriesChartOverlaySetArray->copyChartOverlaySetCartesianAxes(sourceTabIndex, destinationTabIndex); } /** * Set the type of chart selected in the given tab. * * @param tabIndex * Index of tab. * @param dataType * Type of data for chart. */ void ModelChartTwo::setSelectedChartTwoDataType(const int32_t tabIndex, const ChartTwoDataTypeEnum::Enum dataType) { CaretAssertArrayIndex(m_selectedChartTwoDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_selectedChartTwoDataType[tabIndex] = dataType; } /** * Get the valid chart data types based upon the currently loaded files. * * @param validChartDataTypesOut * Output containing valid chart data types. */ void ModelChartTwo::getValidChartTwoDataTypes(std::vector& validChartDataTypesOut) const { validChartDataTypesOut.clear(); /** * Get the data files. */ std::vector allDataFiles; EventCaretMappableDataFilesGet eventGetMapDataFiles; EventManager::get()->sendEvent(eventGetMapDataFiles.getPointer()); eventGetMapDataFiles.getAllFiles(allDataFiles); std::set chartTypeSet; for (auto mapFile : allDataFiles) { ChartableTwoFileDelegate* chartFile = mapFile->getChartingDelegate(); std::vector fileChartTypes; chartFile->getSupportedChartTwoDataTypes(fileChartTypes); chartTypeSet.insert(fileChartTypes.begin(), fileChartTypes.end()); } validChartDataTypesOut.insert(validChartDataTypesOut.end(), chartTypeSet.begin(), chartTypeSet.end()); } /** * Get the type of chart selected in the given tab. * * @param tabIndex * Index of tab. * @return * Chart type in the given tab. */ ChartTwoDataTypeEnum::Enum ModelChartTwo::getSelectedChartTwoDataType(const int32_t tabIndex) const { CaretAssertArrayIndex(m_selectedChartTwoDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); ChartTwoDataTypeEnum::Enum chartDataType = m_selectedChartTwoDataType[tabIndex]; std::vector validChartDataTypes; getValidChartTwoDataTypes(validChartDataTypes); /* * Test if selected chart type is still valid */ if (std::find(validChartDataTypes.begin(), validChartDataTypes.end(), chartDataType) == validChartDataTypes.end()) { chartDataType = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; } /* * Find a valid chart type? */ if (chartDataType == ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID) { if ( ! validChartDataTypes.empty()) { CaretAssertVectorIndex(validChartDataTypes, 0); chartDataType = validChartDataTypes[0]; } } m_selectedChartTwoDataType[tabIndex] = chartDataType; return chartDataType; } /** * Update the chart overlay sets. * * @param tabIndex * Index of the tab. */ void ModelChartTwo::updateChartOverlaySets(const int32_t tabIndex) { CaretAssertArrayIndex(m_selectedChartTwoDataType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); switch (m_selectedChartTwoDataType[tabIndex]) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; } } /** * Get the chart overlay set for this model. * * @param tabIndex * Index for the chart overlay set. * @return * Chart overlay set or NULL if not valid for this model. */ ChartTwoOverlaySet* ModelChartTwo::getChartTwoOverlaySet(const int tabIndex) { ChartTwoOverlaySet* chartOverlaySet = NULL; switch (getSelectedChartTwoDataType(tabIndex)) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: chartOverlaySet = m_histogramChartOverlaySetArray->getChartTwoOverlaySet(tabIndex); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: chartOverlaySet = m_lineSeriesChartOverlaySetArray->getChartTwoOverlaySet(tabIndex); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: chartOverlaySet = m_matrixChartOverlaySetArray->getChartTwoOverlaySet(tabIndex); break; } return chartOverlaySet; } /** * Get the chart overlay set for this model. * * @param tabIndex * Index for the chart overlay set. * @return * Chart overlay set or NULL if not valid for this model. */ const ChartTwoOverlaySet* ModelChartTwo::getChartTwoOverlaySet(const int tabIndex) const { ModelChartTwo* nonConstModelChart = const_cast(this); CaretAssert(nonConstModelChart); const ChartTwoOverlaySet* chartOverlaySet = nonConstModelChart->getChartTwoOverlaySet(tabIndex); return chartOverlaySet; } connectome-workbench-1.4.2/src/Brain/ModelChartTwo.h000066400000000000000000000136431360521144700223510ustar00rootroot00000000000000#ifndef __MODEL_CHART_TWO_H__ #define __MODEL_CHART_TWO_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include "CaretDataFileSelectionModel.h" #include "ChartTwoDataTypeEnum.h" #include "EventListenerInterface.h" #include "MapYokingGroupEnum.h" #include "Model.h" #include "StructureEnum.h" namespace caret { class CaretDataFileSelectionModel; class ChartTwoOverlaySetArray; class CiftiConnectivityMatrixParcelFile; class CiftiMappableDataFile; class ModelChart; class OverlaySetArray; class SurfaceFile; /// Controls the display of a chart. class ModelChartTwo : public Model, public EventListenerInterface { public: ModelChartTwo(Brain* brain); virtual ~ModelChartTwo(); virtual void initializeOverlays() override; virtual AString getNameForGUI(const bool includeStructureFlag) const override; virtual AString getNameForBrowserTab() const override; void loadChartDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const int32_t nodeIndex); void loadAverageChartDataForSurfaceNodes(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const std::vector& nodeIndices); void loadChartDataForVoxelAtCoordinate(const float xyz[3]); void loadChartDataForCiftiMappableFileRow(CiftiMappableDataFile* ciftiMapFile, const int32_t rowIndex); void loadChartDataForYokedScalarDataSeriesFiles(const MapYokingGroupEnum::Enum mapYokingGroup, const int32_t mapIndex); void selectRowColumnInYokedScalarDataSeriesFileOverlay(const MapYokingGroupEnum::Enum mapYokingGroup, const int32_t mapIndex); virtual OverlaySet* getOverlaySet(const int tabIndex) override; virtual const OverlaySet* getOverlaySet(const int tabIndex) const override; virtual ChartTwoOverlaySet* getChartTwoOverlaySet(const int tabIndex) override; virtual const ChartTwoOverlaySet* getChartTwoOverlaySet(const int tabIndex) const override; virtual void receiveEvent(Event* event) override; void getValidChartTwoDataTypes(std::vector& validChartDataTypesOut) const; ChartTwoDataTypeEnum::Enum getSelectedChartTwoDataType(const int32_t tabIndex) const; void setSelectedChartTwoDataType(const int32_t tabIndex, const ChartTwoDataTypeEnum::Enum dataType); virtual void copyTabContent(const int32_t sourceTabIndex, const int32_t destinationTabIndex) override; void reset(); void restoreSceneFromChartOneModel(ModelChart* modelChartOne); void copyChartTwoCartesianAxes(const int32_t sourceTabIndex, const int32_t destinationTabIndex); protected: virtual void saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) override; virtual void restoreModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) override; private: ModelChartTwo(const ModelChartTwo&); ModelChartTwo& operator=(const ModelChartTwo&); void initializeCharts(); void removeAllCharts(); void updateChartOverlaySets(const int32_t tabIndex); void restoreMatrixChartFromChartOneModel(ModelChart* modelChartOne, const int32_t tabIndex); void restoreLineSeriesChartFromChartOneModel(ModelChart* modelChartOne); /** Overlays sets for this model and for each tab */ OverlaySetArray* m_overlaySetArray; mutable ChartTwoDataTypeEnum::Enum m_selectedChartTwoDataType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** Chart Overlay sets for XX data type */ std::unique_ptr m_histogramChartOverlaySetArray; /** Chart Overlay sets for XX data type */ std::unique_ptr m_lineSeriesChartOverlaySetArray; /** Chart Overlay sets for XX data type */ std::unique_ptr m_matrixChartOverlaySetArray; std::unique_ptr m_sceneAssistant; }; } // namespace #endif // __MODEL_CHART_TWO_H__ connectome-workbench-1.4.2/src/Brain/ModelSurface.cxx000066400000000000000000000166311360521144700225610ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "BrainStructure.h" #include "BrowserTabContent.h" #include "BoundingBox.h" #include "CaretAssert.h" #include "EventManager.h" #include "EventModelSurfaceGet.h" #include "ModelSurface.h" #include "Brain.h" #include "BrainOpenGL.h" #include "OverlaySet.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "Surface.h" using namespace caret; /** * Constructor. * @param surface - surface for this model. * */ ModelSurface::ModelSurface(Brain* brain, Surface* surface) : Model(ModelTypeEnum::MODEL_TYPE_SURFACE, brain) { CaretAssert(surface); initializeMembersModelSurface(); m_surface = surface; EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MODEL_SURFACE_GET); } /** * Destructor */ ModelSurface::~ModelSurface() { EventManager::get()->removeAllEventsFromListener(this); } /** * Receive an event. * * @param event * The event that the receive can respond to. */ void ModelSurface::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_MODEL_SURFACE_GET) { EventModelSurfaceGet* getSurfaceEvent = dynamic_cast(event); CaretAssert(getSurfaceEvent); /* * Looking for this model? */ if (getSurfaceEvent->getSurface() == getSurface()) { getSurfaceEvent->setModelSurface(this); getSurfaceEvent->setEventProcessed(); } } else { CaretAssertMessage(0, "Unexpected event: " + EventTypeEnum::toName(event->getEventType())); } } void ModelSurface::initializeMembersModelSurface() { m_surface = NULL; } /** * Get the surface in this model. * @return Surface in this model. */ Surface* ModelSurface::getSurface() { return m_surface; } /** * Get the surface in this model. * @return Surface in this model. */ const Surface* ModelSurface::getSurface() const { return m_surface; } /** * Get the name for use in a GUI. * * @param includeStructureFlag - Prefix label with structure to which * this structure model belongs. * @return Name for use in a GUI. * */ AString ModelSurface::getNameForGUI(const bool includeStructureFlag) const { AString name; if (includeStructureFlag) { const StructureEnum::Enum structure = m_surface->getStructure(); name += StructureEnum::toGuiName(structure); name += " "; } name += m_surface->getFileNameNoPath(); return name; } /** * @return The name that should be displayed in the tab * displaying this model. */ AString ModelSurface::getNameForBrowserTab() const { const StructureEnum::Enum structure = m_surface->getStructure(); AString name = StructureEnum::toGuiName(structure); if (structure == StructureEnum::CEREBELLUM) { name = "Cbllm"; } return name; } /** * Set the scaling so that the model fills the window. * */ //void //ModelSurface::setDefaultScalingToFitWindow() //{ // BoundingBox bounds; // m_surface->getBounds(bounds); // // float bigY = std::max(std::abs(bounds.getMinY()), bounds.getMaxY()); // float percentScreenY = BrainOpenGL::getModelViewingHalfWindowHeight() * 0.90f; // float scale = percentScreenY / bigY; // m_defaultModelScaling = scale; // // for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { // setScaling(i, m_defaultModelScaling); // } //} /** * Get the overlay set for the given tab. * @param tabIndex * Index of tab. * @return * Overlay set at the given tab index. */ OverlaySet* ModelSurface::getOverlaySet(const int tabIndex) { if (m_surface != NULL) { BrainStructure* brainStructure = m_surface->getBrainStructure(); if (brainStructure != NULL) { return brainStructure->getOverlaySet(tabIndex); } } return NULL; } /** * Get the overlay set for the given tab. * @param tabIndex * Index of tab. * @return * Overlay set at the given tab index. */ const OverlaySet* ModelSurface::getOverlaySet(const int tabIndex) const { if (m_surface != NULL) { const BrainStructure* brainStructure = m_surface->getBrainStructure(); if (brainStructure != NULL) { return brainStructure->getOverlaySet(tabIndex); } } return NULL; } /** * Initilize the overlays for this model. */ void ModelSurface::initializeOverlays() { } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param sceneClass * SceneClass to which model specific information is added. */ void ModelSurface::saveModelSpecificInformationToScene(const SceneAttributes* /*sceneAttributes*/, SceneClass* /*sceneClass*/) { /* nothing to add to scene */ } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ModelSurface::restoreModelSpecificInformationFromScene(const SceneAttributes* /*sceneAttributes*/, const SceneClass* /*sceneClass*/) { /* nothing to restore from scene */ } /** * Get a text description of the window's content. * * @param tabIndex * Index of the tab for content description. * @param descriptionOut * Description of the window's content. */ void ModelSurface::getDescriptionOfContent(const int32_t /*tabIndex*/, PlainTextStringBuilder& descriptionOut) const { AString msg; const Surface* surface = getSurface(); if (surface != NULL) { surface->getDescriptionOfContent(descriptionOut); } } /** * Copy the tab content from the source tab index to the * destination tab index. * * @param sourceTabIndex * Source from which tab content is copied. * @param destinationTabIndex * Destination to which tab content is copied. */ void ModelSurface::copyTabContent(const int32_t sourceTabIndex, const int32_t destinationTabIndex) { Model::copyTabContent(sourceTabIndex, destinationTabIndex); } connectome-workbench-1.4.2/src/Brain/ModelSurface.h000066400000000000000000000054751360521144700222120ustar00rootroot00000000000000#ifndef __MODEL_SURFACE_H__ #define __MODEL_SURFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventListenerInterface.h" #include "Model.h" namespace caret { class Surface; /// Controls the display of a surface. class ModelSurface : public Model, public EventListenerInterface { public: ModelSurface(Brain* brain, Surface* surface); virtual ~ModelSurface(); virtual void receiveEvent(Event* event); OverlaySet* getOverlaySet(const int tabIndex); const OverlaySet* getOverlaySet(const int tabIndex) const; void initializeOverlays(); virtual void getDescriptionOfContent(const int32_t tabIndex, PlainTextStringBuilder& descriptionOut) const; virtual void copyTabContent(const int32_t sourceTabIndex, const int32_t destinationTabIndex); private: ModelSurface(const ModelSurface&); ModelSurface& operator=(const ModelSurface&); private: void initializeMembersModelSurface(); public: Surface* getSurface(); const Surface* getSurface() const; AString getNameForGUI(const bool includeStructureFlag) const; virtual AString getNameForBrowserTab() const; //void setDefaultScalingToFitWindow(); protected: virtual void saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: /**Surface that uses this model */ Surface* m_surface; }; } // namespace #endif // __MODEL_SURFACE_H__ connectome-workbench-1.4.2/src/Brain/ModelSurfaceMontage.cxx000066400000000000000000001240651360521144700240750ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "BrainStructure.h" #include "BrowserTabContent.h" #include "BoundingBox.h" #include "Brain.h" #include "BrainOpenGL.h" #include "CaretAssert.h" #include "EventManager.h" #include "EventModelSurfaceGet.h" #include "ModelSurfaceMontage.h" #include "OverlaySet.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneClassAssistant.h" #include "SceneObjectMapIntegerKey.h" #include "ScenePrimitive.h" #include "SurfaceMontageConfigurationCerebellar.h" #include "SurfaceMontageConfigurationCerebral.h" #include "SurfaceMontageConfigurationFlatMaps.h" #include "SurfaceSelectionModel.h" using namespace caret; /** * Constructor. * @param surface - surface for this model. * */ ModelSurfaceMontage::ModelSurfaceMontage(Brain* brain) : Model(ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE, brain) { std::vector validSurfaceTypes; validSurfaceTypes.push_back(SurfaceTypeEnum::ANATOMICAL); validSurfaceTypes.push_back(SurfaceTypeEnum::RECONSTRUCTION); validSurfaceTypes.push_back(SurfaceTypeEnum::INFLATED); validSurfaceTypes.push_back(SurfaceTypeEnum::VERY_INFLATED); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_selectedConfigurationType[i] = SurfaceMontageConfigurationTypeEnum::CEREBRAL_CORTEX_CONFIGURATION; m_cerebellarConfiguration[i] = new SurfaceMontageConfigurationCerebellar(i); m_cerebralConfiguration[i] = new SurfaceMontageConfigurationCerebral(i); m_flatMapsConfiguration[i] = new SurfaceMontageConfigurationFlatMaps(i); } std::vector overlaySurfaceStructures; overlaySurfaceStructures.push_back(StructureEnum::CORTEX_LEFT); overlaySurfaceStructures.push_back(StructureEnum::CORTEX_RIGHT); } /** * Destructor */ ModelSurfaceMontage::~ModelSurfaceMontage() { EventManager::get()->removeAllEventsFromListener(this); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { delete m_cerebellarConfiguration[i]; delete m_cerebralConfiguration[i]; delete m_flatMapsConfiguration[i]; } } /** * Receive an event. * * @param event * The event that the receive can respond to. */ void ModelSurfaceMontage::receiveEvent(Event* /*event*/) { } /** * Initialize the selected surfaces. */ void ModelSurfaceMontage::initializeSelectedSurfaces() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_cerebellarConfiguration[i]->initializeSelectedSurfaces(); m_cerebralConfiguration[i]->initializeSelectedSurfaces(); m_flatMapsConfiguration[i]->initializeSelectedSurfaces(); } } /** * Get the name for use in a GUI. * * @param includeStructureFlag - Prefix label with structure to which * this structure model belongs. * @return Name for use in a GUI. * */ AString ModelSurfaceMontage::getNameForGUI(const bool /*includeStructureFlag*/) const { AString name = "Surface Montage"; return name; } /** * @return The name that should be displayed in the tab * displaying this model. */ AString ModelSurfaceMontage::getNameForBrowserTab() const { AString name = "Montage"; return name; } /** * Get the overlay set for the given tab. * @param tabIndex * Index of tab. * @return * Overlay set at the given tab index. */ OverlaySet* ModelSurfaceMontage::getOverlaySet(const int tabIndex) { return getSelectedConfiguration(tabIndex)->getOverlaySet(); } /** * Get the overlay set for the given tab. * @param tabIndex * Index of tab. * @return * Overlay set at the given tab index. */ const OverlaySet* ModelSurfaceMontage::getOverlaySet(const int tabIndex) const { return getSelectedConfiguration(tabIndex)->getOverlaySet(); } /** * Initilize the overlays for this model. */ void ModelSurfaceMontage::initializeOverlays() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_cerebellarConfiguration[i]->getOverlaySet()->initializeOverlays(); m_cerebralConfiguration[i]->getOverlaySet()->initializeOverlays(); m_flatMapsConfiguration[i]->getOverlaySet()->initializeOverlays(); } } /** * Get a surface for the given struture in the given tab. Since there * may be one surface of the given structure, the returned surface * may be different in future calls based upon the surfaces the user * has chosen for display. * * @param structure * Structure for the surface * @param windowTabNumber * Tab number of window. * @param Pointer to selected surface for given structure or NULL if not available. */ Surface* ModelSurfaceMontage::getSelectedSurface(const StructureEnum::Enum structure, const int32_t windowTabNumber) { std::vector selectionModels; switch (getSelectedConfigurationType(windowTabNumber)) { case SurfaceMontageConfigurationTypeEnum::CEREBELLAR_CORTEX_CONFIGURATION: { SurfaceMontageConfigurationCerebellar* smcc = getCerebellarConfiguration(windowTabNumber); if (structure == StructureEnum::CEREBELLUM) { selectionModels.push_back(smcc->getFirstSurfaceSelectionModel()); selectionModels.push_back(smcc->getSecondSurfaceSelectionModel()); } } break; case SurfaceMontageConfigurationTypeEnum::CEREBRAL_CORTEX_CONFIGURATION: { SurfaceMontageConfigurationCerebral* smcc = getCerebralConfiguration(windowTabNumber); switch (structure) { case StructureEnum::CORTEX_LEFT: selectionModels.push_back(smcc->getLeftFirstSurfaceSelectionModel()); selectionModels.push_back(smcc->getLeftSecondSurfaceSelectionModel()); break; case StructureEnum::CORTEX_RIGHT: selectionModels.push_back(smcc->getRightFirstSurfaceSelectionModel()); selectionModels.push_back(smcc->getRightSecondSurfaceSelectionModel()); break; default: break; } } break; case SurfaceMontageConfigurationTypeEnum::FLAT_CONFIGURATION: { SurfaceMontageConfigurationFlatMaps* smcfm = getFlatMapsConfiguration(windowTabNumber); switch (structure) { case StructureEnum::CEREBELLUM: selectionModels.push_back(smcfm->getCerebellumSurfaceSelectionModel()); break; case StructureEnum::CORTEX_LEFT: selectionModels.push_back(smcfm->getLeftSurfaceSelectionModel()); break; case StructureEnum::CORTEX_RIGHT: selectionModels.push_back(smcfm->getRightSurfaceSelectionModel()); break; default: break; } } break; } Surface* surfaceOut = NULL; for (std::vector::iterator iter = selectionModels.begin(); iter != selectionModels.end(); iter++) { SurfaceSelectionModel* sm = *iter; if (sm != NULL) { surfaceOut = sm->getSurface(); break; } } return surfaceOut; } /** * Get the selected configuration for the given tab. * * @param tabIndex * Index of tab for the selected configuration. */ SurfaceMontageConfigurationAbstract* ModelSurfaceMontage::getSelectedConfiguration(const int32_t tabIndex) { switch (getSelectedConfigurationType(tabIndex)) { case SurfaceMontageConfigurationTypeEnum::CEREBELLAR_CORTEX_CONFIGURATION: CaretAssertArrayIndex(m_cerebellarConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_cerebellarConfiguration[tabIndex]; break; case SurfaceMontageConfigurationTypeEnum::CEREBRAL_CORTEX_CONFIGURATION: CaretAssertArrayIndex(m_cerebralConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_cerebralConfiguration[tabIndex]; break; case SurfaceMontageConfigurationTypeEnum::FLAT_CONFIGURATION: CaretAssertArrayIndex(m_flatMapsConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_flatMapsConfiguration[tabIndex]; break; } return NULL; } /** * Get the selected configuration for the given tab. * * @param tabIndex * Index of tab for the selected configuration. */ const SurfaceMontageConfigurationAbstract* ModelSurfaceMontage::getSelectedConfiguration(const int32_t tabIndex) const { ModelSurfaceMontage* msm = const_cast(this); return msm->getSelectedConfiguration(tabIndex); } /** * @return The type of configuration in the given tab. * * @param tabIndex * Index of the tab. */ SurfaceMontageConfigurationTypeEnum::Enum ModelSurfaceMontage::getSelectedConfigurationType(const int32_t tabIndex) const { /* * Find valid configurations */ std::vector< SurfaceMontageConfigurationTypeEnum::Enum> validTypes; if (m_cerebellarConfiguration[tabIndex]->isValid()) { validTypes.push_back(SurfaceMontageConfigurationTypeEnum::CEREBELLAR_CORTEX_CONFIGURATION); } if (m_cerebralConfiguration[tabIndex]->isValid()) { validTypes.push_back(SurfaceMontageConfigurationTypeEnum::CEREBRAL_CORTEX_CONFIGURATION); } if (m_flatMapsConfiguration[tabIndex]->isValid()) { validTypes.push_back(SurfaceMontageConfigurationTypeEnum::FLAT_CONFIGURATION); } /* * Verify selected type is valid */ bool validTypeSelected = false; switch (m_selectedConfigurationType[tabIndex]) { case SurfaceMontageConfigurationTypeEnum::CEREBELLAR_CORTEX_CONFIGURATION: CaretAssertArrayIndex(m_cerebellarConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); if (m_cerebellarConfiguration[tabIndex]->isValid()) { validTypeSelected = true; } break; case SurfaceMontageConfigurationTypeEnum::CEREBRAL_CORTEX_CONFIGURATION: CaretAssertArrayIndex(m_cerebralConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); if (m_cerebralConfiguration[tabIndex]->isValid()) { validTypeSelected = true; } break; case SurfaceMontageConfigurationTypeEnum::FLAT_CONFIGURATION: CaretAssertArrayIndex(m_flatMapsConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); if (m_flatMapsConfiguration[tabIndex]->isValid()) { validTypeSelected = true; } break; } /* * If configuration type selected is not valid, choose another * configuration type. */ if ( ! validTypeSelected) { if ( ! validTypes.empty()) { m_selectedConfigurationType[tabIndex] = validTypes[0]; } } return m_selectedConfigurationType[tabIndex]; } /** * Set type of configuration in the given tab. * * @param tabIndex * Index of the tab. * @param configurationType * New configuration type for the tab index. */ void ModelSurfaceMontage::setSelectedConfigurationType(const int32_t tabIndex, const SurfaceMontageConfigurationTypeEnum::Enum configurationType) { m_selectedConfigurationType[tabIndex] = configurationType; } /** * Get the cerebellar configuration in the given tab. * * @param tabIndex * Index of tab. * @return * Cerebellar configuration. */ SurfaceMontageConfigurationCerebellar * ModelSurfaceMontage::getCerebellarConfiguration(const int32_t tabIndex) { CaretAssertArrayIndex(m_cerebellarConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_cerebellarConfiguration[tabIndex]; } /** * Get the cerebellar configuration in the given tab. * * @param tabIndex * Index of tab. * @return * Cerebellar configuration. */ const SurfaceMontageConfigurationCerebellar* ModelSurfaceMontage::getCerebellarConfiguration(const int32_t tabIndex) const { CaretAssertArrayIndex(m_cerebellarConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_cerebellarConfiguration[tabIndex]; } /** * Get the cerebral configuration in the given tab. * * @param tabIndex * Index of tab. * @return * Cerebral configuration. */ SurfaceMontageConfigurationCerebral * ModelSurfaceMontage::getCerebralConfiguration(const int32_t tabIndex) { CaretAssertArrayIndex(m_cerebralConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_cerebralConfiguration[tabIndex]; } /** * Get the cerebral configuration in the given tab. * * @param tabIndex * Index of tab. * @return * Cerebral configuration. */ const SurfaceMontageConfigurationCerebral* ModelSurfaceMontage::getCerebralConfiguration(const int32_t tabIndex) const { CaretAssertArrayIndex(m_cerebralConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_cerebralConfiguration[tabIndex]; } /** * Get the flat maps configuration in the given tab. * * @param tabIndex * Index of tab. * @return * Flat maps configuration. */ SurfaceMontageConfigurationFlatMaps * ModelSurfaceMontage::getFlatMapsConfiguration(const int32_t tabIndex) { CaretAssertArrayIndex(m_flatMapsConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_flatMapsConfiguration[tabIndex]; } /** * Get the flat maps configuration in the given tab. * * @param tabIndex * Index of tab. * @return * Flat maps configuration. */ const SurfaceMontageConfigurationFlatMaps* ModelSurfaceMontage::getFlatMapsConfiguration(const int32_t tabIndex) const { CaretAssertArrayIndex(m_flatMapsConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_flatMapsConfiguration[tabIndex]; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param sceneClass * SceneClass to which model specific information is added. */ void ModelSurfaceMontage::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { sceneClass->addInteger("montageVersion", 3); SceneObjectMapIntegerKey* cerebellarConfigurationMap = new SceneObjectMapIntegerKey("m_cerebellarConfiguration", SceneObjectDataTypeEnum::SCENE_CLASS); SceneObjectMapIntegerKey* cerebralConfigurationMap = new SceneObjectMapIntegerKey("m_cerebralConfiguration", SceneObjectDataTypeEnum::SCENE_CLASS); SceneObjectMapIntegerKey* flatConfigurationMap = new SceneObjectMapIntegerKey("m_flatMapsConfiguration", SceneObjectDataTypeEnum::SCENE_CLASS); /* * Get indices of tabs that are to be saved to scene. */ const std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); const int32_t numActiveTabs = static_cast(tabIndices.size()); sceneClass->addEnumeratedTypeArrayForTabIndices("m_selectedConfigurationType", m_selectedConfigurationType, tabIndices); for (int32_t i = 0; i < numActiveTabs; i++) { const int32_t tabIndex = tabIndices[i]; const AString tabString = ("[" + AString::number(tabIndex) + "]"); cerebellarConfigurationMap->addClass(tabIndex, m_cerebellarConfiguration[tabIndex]->saveToScene(sceneAttributes, "m_cerebellarConfiguration" + tabString)); cerebralConfigurationMap->addClass(tabIndex, m_cerebralConfiguration[tabIndex]->saveToScene(sceneAttributes, "m_cerebralConfiguration" + tabString)); flatConfigurationMap->addClass(tabIndex, m_flatMapsConfiguration[tabIndex]->saveToScene(sceneAttributes, "m_flatMapsConfiguration" + tabString)); } sceneClass->addChild(cerebellarConfigurationMap); sceneClass->addChild(cerebralConfigurationMap); sceneClass->addChild(flatConfigurationMap); // /* // * Surfaces // */ // SceneObjectMapIntegerKey* leftSurfaceMap = new SceneObjectMapIntegerKey("m_leftSurfaceSelectionModel", // SceneObjectDataTypeEnum::SCENE_CLASS); // SceneObjectMapIntegerKey* leftSecondSurfaceMap = new SceneObjectMapIntegerKey("m_leftSecondSurfaceSelectionModel", // SceneObjectDataTypeEnum::SCENE_CLASS); // SceneObjectMapIntegerKey* rightSurfaceMap = new SceneObjectMapIntegerKey("m_rightSurfaceSelectionModel", // SceneObjectDataTypeEnum::SCENE_CLASS); // SceneObjectMapIntegerKey* rightSecondSurfaceMap = new SceneObjectMapIntegerKey("m_rightSecondSurfaceSelectionModel", // SceneObjectDataTypeEnum::SCENE_CLASS); // for (int32_t iat = 0; iat < numActiveTabs; iat++) { // const int32_t tabIndex = tabIndices[iat]; // const AString tabString = ("[" + AString::number(tabIndex) + "]"); // // leftSurfaceMap->addClass(tabIndex, // m_leftSurfaceSelectionModel[tabIndex]->saveToScene(sceneAttributes, // "m_leftSurfaceSelectionModel" + tabString)); // leftSecondSurfaceMap->addClass(tabIndex, // m_leftSecondSurfaceSelectionModel[tabIndex]->saveToScene(sceneAttributes, // "m_leftSecondSurfaceSelectionModel" + tabString)); // rightSurfaceMap->addClass(tabIndex, // m_rightSurfaceSelectionModel[tabIndex]->saveToScene(sceneAttributes, // "m_rightSurfaceSelectionModel" + tabString)); // rightSecondSurfaceMap->addClass(tabIndex, // m_rightSecondSurfaceSelectionModel[tabIndex]->saveToScene(sceneAttributes, // "m_rightSecondSurfaceSelectionModel" + tabString)); // } // sceneClass->addChild(leftSurfaceMap); // sceneClass->addChild(leftSecondSurfaceMap); // sceneClass->addChild(rightSurfaceMap); // sceneClass->addChild(rightSecondSurfaceMap); // // /* // * Selections // */ // SceneObjectMapIntegerKey* rightEnabledMap = new SceneObjectMapIntegerKey("m_rightEnabled", // SceneObjectDataTypeEnum::SCENE_BOOLEAN); // SceneObjectMapIntegerKey* leftEnabledMap = new SceneObjectMapIntegerKey("m_leftEnabled", // SceneObjectDataTypeEnum::SCENE_BOOLEAN); // SceneObjectMapIntegerKey* firstSurfaceEnabledMap = new SceneObjectMapIntegerKey("m_firstSurfaceEnabled", // SceneObjectDataTypeEnum::SCENE_BOOLEAN); // SceneObjectMapIntegerKey* secondSurfaceEnabledMap = new SceneObjectMapIntegerKey("m_secondSurfaceEnabled", // SceneObjectDataTypeEnum::SCENE_BOOLEAN); // for (int32_t iat = 0; iat < numActiveTabs; iat++) { // const int32_t tabIndex = tabIndices[iat]; // rightEnabledMap->addBoolean(tabIndex, // m_rightEnabled[tabIndex]); // leftEnabledMap->addBoolean(tabIndex, // m_leftEnabled[tabIndex]); // firstSurfaceEnabledMap->addBoolean(tabIndex, // m_firstSurfaceEnabled[tabIndex]); // secondSurfaceEnabledMap->addBoolean(tabIndex, // m_secondSurfaceEnabled[tabIndex]); // } // sceneClass->addChild(rightEnabledMap); // sceneClass->addChild(leftEnabledMap); // sceneClass->addChild(firstSurfaceEnabledMap); // sceneClass->addChild(secondSurfaceEnabledMap); } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ModelSurfaceMontage::restoreModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { const int32_t montageVersion = sceneClass->getIntegerValue("montageVersion", 1); if (montageVersion >= 3) { /* * Restore Cerebellum */ const SceneObjectMapIntegerKey* cerebellumMap = sceneClass->getMapIntegerKey("m_cerebellarConfiguration"); if (cerebellumMap != NULL) { const std::map& structureMap = cerebellumMap->getMap(); for (std::map::const_iterator iter = structureMap.begin(); iter != structureMap.end(); iter++) { const int32_t key = iter->first; const SceneClass* cerebellarSceneClass = dynamic_cast(iter->second); cerebellarSceneClass->setRestored(true); // prevents "failed to restore" CaretAssertArrayIndex(m_cerebellarConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, key); m_cerebellarConfiguration[key]->restoreFromScene(sceneAttributes, cerebellarSceneClass); } } /* * Restore Cortext */ const SceneObjectMapIntegerKey* cerebralMap = sceneClass->getMapIntegerKey("m_cerebralConfiguration"); if (cerebellumMap != NULL) { const std::map& structureMap = cerebralMap->getMap(); for (std::map::const_iterator iter = structureMap.begin(); iter != structureMap.end(); iter++) { const int32_t key = iter->first; const SceneClass* cerebralSceneClass = dynamic_cast(iter->second); cerebralSceneClass->setRestored(true);// prevents "failed to restore" CaretAssertArrayIndex(m_cerebralConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, key); m_cerebralConfiguration[key]->restoreFromScene(sceneAttributes, cerebralSceneClass); } } /* * Restore flat maps */ const SceneObjectMapIntegerKey* flatMap = sceneClass->getMapIntegerKey("m_flatMapsConfiguration"); if (cerebellumMap != NULL) { const std::map& structureMap = flatMap->getMap(); for (std::map::const_iterator iter = structureMap.begin(); iter != structureMap.end(); iter++) { const int32_t key = iter->first; const SceneClass* flatClass = dynamic_cast(iter->second); flatClass->setRestored(true); // prevents "failed to restore" CaretAssertArrayIndex(m_flatMapsConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, key); m_flatMapsConfiguration[key]->restoreFromScene(sceneAttributes, flatClass); } } sceneClass->getEnumerateTypeArrayForTabIndices("m_selectedConfigurationType", m_selectedConfigurationType); } else { restoreFromSceneVersionTwoAndEarlier(sceneAttributes, sceneClass, montageVersion); return; } } /** * Restore information from the ModelSurfaceMontage that existed prior * to the cerebellar, cerebral, and flat montage configurations. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which information is restored. */ void ModelSurfaceMontage::restoreFromSceneVersionTwoAndEarlier(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass, const int32_t montageVersion) { /* * Restore left surface */ const SceneObjectMapIntegerKey* leftSurfaceMap = sceneClass->getMapIntegerKey("m_leftSurfaceSelectionModel"); if (leftSurfaceMap != NULL) { const std::map& surfaceMap = leftSurfaceMap->getMap(); for (std::map::const_iterator iter = surfaceMap.begin(); iter != surfaceMap.end(); iter++) { const int32_t key = iter->first; const SceneClass* surfaceClass = dynamic_cast(iter->second); CaretAssertArrayIndex(m_cerebralConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, key); SurfaceSelectionModel* ssm = m_cerebralConfiguration[key]->getLeftFirstSurfaceSelectionModel(); ssm->restoreFromScene(sceneAttributes, surfaceClass); } } /* * Restore left second surface */ const SceneObjectMapIntegerKey* leftSecondSurfaceMap = sceneClass->getMapIntegerKey("m_leftSecondSurfaceSelectionModel"); if (leftSecondSurfaceMap != NULL) { const std::map& surfaceMap = leftSecondSurfaceMap->getMap(); for (std::map::const_iterator iter = surfaceMap.begin(); iter != surfaceMap.end(); iter++) { const int32_t key = iter->first; const SceneClass* surfaceClass = dynamic_cast(iter->second); CaretAssertArrayIndex(m_cerebralConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, key); SurfaceSelectionModel* ssm = m_cerebralConfiguration[key]->getLeftSecondSurfaceSelectionModel(); ssm->restoreFromScene(sceneAttributes, surfaceClass); } } /* * Restore right surface */ const SceneObjectMapIntegerKey* rightSurfaceMap = sceneClass->getMapIntegerKey("m_rightSurfaceSelectionModel"); if (rightSurfaceMap != NULL) { const std::map& surfaceMap = rightSurfaceMap->getMap(); for (std::map::const_iterator iter = surfaceMap.begin(); iter != surfaceMap.end(); iter++) { const int32_t key = iter->first; const SceneClass* surfaceClass = dynamic_cast(iter->second); CaretAssertArrayIndex(m_cerebralConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, key); SurfaceSelectionModel* ssm = m_cerebralConfiguration[key]->getRightFirstSurfaceSelectionModel(); ssm->restoreFromScene(sceneAttributes, surfaceClass); } } /* * Restore right second surface */ const SceneObjectMapIntegerKey* rightSecondSurfaceMap = sceneClass->getMapIntegerKey("m_rightSecondSurfaceSelectionModel"); if (rightSecondSurfaceMap != NULL) { const std::map& surfaceMap = rightSecondSurfaceMap->getMap(); for (std::map::const_iterator iter = surfaceMap.begin(); iter != surfaceMap.end(); iter++) { const int32_t key = iter->first; const SceneClass* surfaceClass = dynamic_cast(iter->second); CaretAssertArrayIndex(m_cerebralConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, key); SurfaceSelectionModel* ssm = m_cerebralConfiguration[key]->getRightSecondSurfaceSelectionModel(); ssm->restoreFromScene(sceneAttributes, surfaceClass); } } if (montageVersion <= 1) { /* * Version 1 had only dual option so enable items added in version 2 */ for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { CaretAssertArrayIndex(m_cerebralConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, i); m_cerebralConfiguration[i]->setLeftEnabled(true); m_cerebralConfiguration[i]->setRightEnabled(true); m_cerebralConfiguration[i]->setFirstSurfaceEnabled(true); m_cerebralConfiguration[i]->setSecondSurfaceEnabled(true); } /* * Restore dual configuration as second surface */ const SceneObjectMapIntegerKey* dualConfigurationMap = sceneClass->getMapIntegerKey("m_dualConfigurationEnabled"); if (dualConfigurationMap != NULL) { const std::map& dataMap = dualConfigurationMap->getMap(); for (std::map::const_iterator iter = dataMap.begin(); iter != dataMap.end(); iter++) { const int32_t key = iter->first; const ScenePrimitive* primitive = dynamic_cast(iter->second); CaretAssertArrayIndex(m_cerebralConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, key); m_cerebralConfiguration[key]->setSecondSurfaceEnabled(primitive->booleanValue()); } } } else { /* * Restore left enabled */ const SceneObjectMapIntegerKey* leftEnabledMap = sceneClass->getMapIntegerKey("m_leftEnabled"); if (leftEnabledMap != NULL) { const std::map& dataMap = leftEnabledMap->getMap(); for (std::map::const_iterator iter = dataMap.begin(); iter != dataMap.end(); iter++) { const int32_t key = iter->first; const ScenePrimitive* primitive = dynamic_cast(iter->second); CaretAssertArrayIndex(m_cerebralConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, key); m_cerebralConfiguration[key]->setLeftEnabled(primitive->booleanValue()); } } /* * Restore right enabled */ const SceneObjectMapIntegerKey* rightEnabledMap = sceneClass->getMapIntegerKey("m_rightEnabled"); if (rightEnabledMap != NULL) { const std::map& dataMap = rightEnabledMap->getMap(); for (std::map::const_iterator iter = dataMap.begin(); iter != dataMap.end(); iter++) { const int32_t key = iter->first; const ScenePrimitive* primitive = dynamic_cast(iter->second); CaretAssertArrayIndex(m_cerebralConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, key); m_cerebralConfiguration[key]->setRightEnabled(primitive->booleanValue()); } } /* * Restore first surface enabled */ const SceneObjectMapIntegerKey* firstSurfaceEnabledMap = sceneClass->getMapIntegerKey("m_firstSurfaceEnabled"); if (firstSurfaceEnabledMap != NULL) { const std::map& dataMap = firstSurfaceEnabledMap->getMap(); for (std::map::const_iterator iter = dataMap.begin(); iter != dataMap.end(); iter++) { const int32_t key = iter->first; const ScenePrimitive* primitive = dynamic_cast(iter->second); CaretAssertArrayIndex(m_cerebralConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, key); m_cerebralConfiguration[key]->setFirstSurfaceEnabled(primitive->booleanValue()); } } /* * Restore second surface enabled */ const SceneObjectMapIntegerKey* secondSurfaceEnabledMap = sceneClass->getMapIntegerKey("m_secondSurfaceEnabled"); if (secondSurfaceEnabledMap != NULL) { const std::map& dataMap = secondSurfaceEnabledMap->getMap(); for (std::map::const_iterator iter = dataMap.begin(); iter != dataMap.end(); iter++) { const int32_t key = iter->first; const ScenePrimitive* primitive = dynamic_cast(iter->second); CaretAssertArrayIndex(m_cerebralConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, key); m_cerebralConfiguration[key]->setSecondSurfaceEnabled(primitive->booleanValue()); } } } /* * Previous surface montage did not have lateral/medial selections */ for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { CaretAssertArrayIndex(m_cerebralConfiguration, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, i); m_cerebralConfiguration[i]->setLateralEnabled(true); m_cerebralConfiguration[i]->setMedialEnabled(true); } } /** * Get the number of rows and columns in the displayed surface montage. * * @param tabIndex * Index of tab. * @param numberOfRowsOut * Number of rows in the displayed montage. * @param numberOfColumnsOut * Number of columns in the displayed montage. */ void ModelSurfaceMontage::getSurfaceMontageNumberOfRowsAndColumns(const int32_t tabIndex, int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) const { numberOfRowsOut = 1; numberOfColumnsOut = 1; ModelSurfaceMontage* nonConstMSM = const_cast(this); std::vector surfaceMontageViewports; nonConstMSM->getSurfaceMontageViewportsForTransformation(tabIndex, surfaceMontageViewports); SurfaceMontageViewport::getNumberOfRowsAndColumns(surfaceMontageViewports, numberOfRowsOut, numberOfColumnsOut); } /** * Get the montage viewports for drawing by OpenGL. The montage viewports * will be updated prior to returning them. OpenGL will update * the viewing dimensions (x, y, width, height) in the returned montage * viewports. * * @param tabIndex * Tab for which viewports are requested. * @param surfaceMontageViewports * The montage viewports. */ void ModelSurfaceMontage::getSurfaceMontageViewportsForDrawing(const int32_t tabIndex, std::vector& surfaceMontageViewports) { SurfaceMontageConfigurationAbstract* config = getSelectedConfiguration(tabIndex); if (config != NULL) { config->getSurfaceMontageViewportsForDrawing(surfaceMontageViewports); } else { surfaceMontageViewports.clear(); } } /** * Get the montage viewports that will be used by the mouse transformations. * * @param tabIndex * Tab for which viewports are requested. * @param surfaceMontageViewports * The montage viewports. */ void ModelSurfaceMontage::getSurfaceMontageViewportsForTransformation(const int32_t tabIndex, std::vector& surfaceMontageViewports) const { const SurfaceMontageConfigurationAbstract* config = getSelectedConfiguration(tabIndex); if (config != NULL) { config->getSurfaceMontageViewportsForTransformation(surfaceMontageViewports); } else { surfaceMontageViewports.clear(); } } /** * @return A string describing the model. */ AString ModelSurfaceMontage::toString() const { AString msg; msg.appendWithNewLine("Surface Montage: "); return msg; } /** * Get a text description of the window's content. * * @param tabIndex * Index of the tab for content description. * @param descriptionOut * Description of the window's content. */ void ModelSurfaceMontage::getDescriptionOfContent(const int32_t tabIndex, PlainTextStringBuilder& descriptionOut) const { const SurfaceMontageConfigurationAbstract* config = getSelectedConfiguration(tabIndex); if (config != NULL) { config->getDescriptionOfContent(descriptionOut); } } /** * Copy the tab content from the source tab index to the * destination tab index. * * @param sourceTabIndex * Source from which tab content is copied. * @param destinationTabIndex * Destination to which tab content is copied. */ void ModelSurfaceMontage::copyTabContent(const int32_t sourceTabIndex, const int32_t destinationTabIndex) { Model::copyTabContent(sourceTabIndex, destinationTabIndex); CaretAssertArrayIndex(m_selectedConfigurationType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, sourceTabIndex); CaretAssertArrayIndex(m_selectedConfigurationType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, destinationTabIndex); m_cerebellarConfiguration[destinationTabIndex]->copyConfiguration(m_cerebellarConfiguration[sourceTabIndex]); m_cerebralConfiguration[destinationTabIndex]->copyConfiguration(m_cerebralConfiguration[sourceTabIndex]); m_flatMapsConfiguration[destinationTabIndex]->copyConfiguration(m_flatMapsConfiguration[sourceTabIndex]); m_selectedConfigurationType[destinationTabIndex] = m_selectedConfigurationType[sourceTabIndex]; } connectome-workbench-1.4.2/src/Brain/ModelSurfaceMontage.h000066400000000000000000000132111360521144700235100ustar00rootroot00000000000000#ifndef __MODEL_SURFACE_MONTAGE_H__ #define __MODEL_SURFACE_MONTAGE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventListenerInterface.h" #include "Model.h" #include "StructureEnum.h" #include "SurfaceMontageViewport.h" #include "SurfaceMontageConfigurationTypeEnum.h" namespace caret { class SurfaceMontageConfigurationAbstract; class SurfaceMontageConfigurationCerebellar; class SurfaceMontageConfigurationCerebral; class SurfaceMontageConfigurationFlatMaps; /// Controls the display of a surface montage class ModelSurfaceMontage : public Model, public EventListenerInterface { public: ModelSurfaceMontage(Brain* brain); virtual ~ModelSurfaceMontage(); virtual void initializeSelectedSurfaces(); virtual void receiveEvent(Event* event); OverlaySet* getOverlaySet(const int tabIndex); const OverlaySet* getOverlaySet(const int tabIndex) const; void initializeOverlays(); Surface* getSelectedSurface(const StructureEnum::Enum structure, const int32_t windowTabNumber); AString getNameForGUI(const bool includeStructureFlag) const; virtual AString getNameForBrowserTab() const; void getSurfaceMontageNumberOfRowsAndColumns(const int32_t tabIndex, int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) const; void getSurfaceMontageViewportsForDrawing(const int32_t tabIndex, std::vector& surfaceMontageViewports); void getSurfaceMontageViewportsForTransformation(const int32_t tabIndex, std::vector& surfaceMontageViewports) const; SurfaceMontageConfigurationTypeEnum::Enum getSelectedConfigurationType(const int32_t tabIndex) const; void setSelectedConfigurationType(const int32_t tabIndex, const SurfaceMontageConfigurationTypeEnum::Enum configurationType); SurfaceMontageConfigurationAbstract* getSelectedConfiguration(const int32_t tabIndex); const SurfaceMontageConfigurationAbstract* getSelectedConfiguration(const int32_t tabIndex) const; SurfaceMontageConfigurationCerebellar * getCerebellarConfiguration(const int32_t tabIndex); const SurfaceMontageConfigurationCerebellar* getCerebellarConfiguration(const int32_t tabIndex) const; SurfaceMontageConfigurationCerebral * getCerebralConfiguration(const int32_t tabIndex); const SurfaceMontageConfigurationCerebral* getCerebralConfiguration(const int32_t tabIndex) const; SurfaceMontageConfigurationFlatMaps * getFlatMapsConfiguration(const int32_t tabIndex); const SurfaceMontageConfigurationFlatMaps* getFlatMapsConfiguration(const int32_t tabIndex) const; virtual AString toString() const; virtual void getDescriptionOfContent(const int32_t tabIndex, PlainTextStringBuilder& descriptionOut) const; virtual void copyTabContent(const int32_t sourceTabIndex, const int32_t destinationTabIndex); protected: virtual void saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: ModelSurfaceMontage(const ModelSurfaceMontage&); ModelSurfaceMontage& operator=(const ModelSurfaceMontage&); void restoreFromSceneVersionTwoAndEarlier(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass, const int32_t montageVersion); SurfaceMontageConfigurationCerebellar* m_cerebellarConfiguration[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; SurfaceMontageConfigurationCerebral* m_cerebralConfiguration[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; SurfaceMontageConfigurationFlatMaps* m_flatMapsConfiguration[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; mutable SurfaceMontageConfigurationTypeEnum::Enum m_selectedConfigurationType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; }; } // namespace #endif // __MODEL_SURFACE_MONTAGE_H__ connectome-workbench-1.4.2/src/Brain/ModelSurfaceSelector.cxx000066400000000000000000000321711360521144700242570ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __MODEL_SURFACE_SELECTOR_DECLARE__ #include "ModelSurfaceSelector.h" #undef __MODEL_SURFACE_SELECTOR_DECLARE__ #include "Brain.h" #include "BrainStructure.h" #include "EventManager.h" #include "EventModelGetAll.h" #include "ModelSurface.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "Surface.h" #include using namespace caret; /** * \class ModelSurfaceSelector * \brief Maintains selection of surface model * * Maintains selection of a surface model with the ability to limit the * surface models to those from a specific brain structure. */ /** * Constructor. */ ModelSurfaceSelector::ModelSurfaceSelector() : CaretObject() { m_defaultStructure = StructureEnum::ALL; m_selectedStructure = StructureEnum::ALL; m_selectedSurfaceModel = NULL; } /** * Destructor. */ ModelSurfaceSelector::~ModelSurfaceSelector() { } /** * @return The selected surface model. */ ModelSurface* ModelSurfaceSelector::getSelectedSurfaceModel() { this->updateSelector(); return m_selectedSurfaceModel; } /** * @return The selected structure. */ StructureEnum::Enum ModelSurfaceSelector::getSelectedStructure() { this->updateSelector(); return m_selectedStructure; } /** * Set the selected surface model. * * @param surfaceModel * Model that is selected. */ void ModelSurfaceSelector::setSelectedSurfaceModel(ModelSurface* surfaceModel) { m_selectedSurfaceModel = surfaceModel; if (m_selectedStructure != StructureEnum::ALL) { m_selectedStructure = surfaceModel->getSurface()->getStructure(); } this->updateSelector(); } /** * Set the selected structure. * * @param selectedStructure * Structure that is selected. */ void ModelSurfaceSelector::setSelectedStructure(const StructureEnum::Enum selectedStructure) { m_selectedStructure = selectedStructure; this->updateSelector(); } /** * Get the structures available for selection. * * @param selectableStructuresOut * Output containing structures that can be selected. */ void ModelSurfaceSelector::getSelectableStructures( std::vector& selectableStructuresOut) const { selectableStructuresOut.clear(); selectableStructuresOut.insert(selectableStructuresOut.end(), m_availableStructures.begin(), m_availableStructures.end()); } /** * Get the surface models available for selection. * * @param selectableSurfaceModelsOut * Output containing surface models that can be selected. */ void ModelSurfaceSelector::getSelectableSurfaceModels( std::vector& selectableSurfaceModelsOut) const { selectableSurfaceModelsOut.clear(); selectableSurfaceModelsOut.insert(selectableSurfaceModelsOut.end(), m_availableSurfaceModels.begin(), m_availableSurfaceModels.end()); } /** * Update the selector with the available surface models. */ void ModelSurfaceSelector::updateSelector(const std::vector modelDisplayModels) { m_allSurfaceModels.clear(); for (std::vector::const_iterator iter = modelDisplayModels.begin(); iter != modelDisplayModels.end(); iter++) { ModelSurface* surfaceModel = dynamic_cast(*iter); if (surfaceModel != NULL) { m_allSurfaceModels.push_back(surfaceModel); } } this->updateSelector(); } /** * Update the selector with the available surface models. */ void ModelSurfaceSelector::updateSelector() { bool haveCortexLeft = false; bool haveCortexRight = false; bool haveCerebellum = false; /* * Find the ALL surface models and structures */ for (std::vector::const_iterator iter = m_allSurfaceModels.begin(); iter != m_allSurfaceModels.end(); iter++) { ModelSurface* surfaceModel = *iter; const Surface* surface = surfaceModel->getSurface(); const StructureEnum::Enum structure = surface->getStructure(); switch (structure) { case StructureEnum::CEREBELLUM: haveCerebellum = true; break; case StructureEnum::CORTEX_LEFT: haveCortexLeft = true; break; case StructureEnum::CORTEX_RIGHT: haveCortexRight = true; break; default: break; } } /* * Determine which structures are available. */ m_availableStructures.clear(); m_availableStructures.push_back(StructureEnum::ALL); if (haveCerebellum) { m_availableStructures.push_back(StructureEnum::CEREBELLUM); } if (haveCortexLeft) { m_availableStructures.push_back(StructureEnum::CORTEX_LEFT); } if (haveCortexRight) { m_availableStructures.push_back(StructureEnum::CORTEX_RIGHT); } /* * Update the structure selection. */ if (std::find(m_availableStructures.begin(), m_availableStructures.end(), m_selectedStructure) == m_availableStructures.end()) { if (m_availableStructures.empty() == false) { m_selectedStructure = m_availableStructures[0]; } else { m_selectedStructure = m_defaultStructure; } } /* * Update the available surface models. */ m_availableSurfaceModels.clear(); for (std::vector::iterator iter = m_allSurfaceModels.begin(); iter != m_allSurfaceModels.end(); iter++) { ModelSurface* surfaceModel = *iter; const Surface* surface = surfaceModel->getSurface(); const StructureEnum::Enum structure = surface->getStructure(); bool useIt = false; if (m_selectedStructure == StructureEnum::ALL) { useIt = true; } else if (m_selectedStructure == structure) { useIt = true; } if (useIt) { m_availableSurfaceModels.push_back(surfaceModel); } } /* * Update the surface selection. */ if (std::find(m_availableSurfaceModels.begin(), m_availableSurfaceModels.end(), m_selectedSurfaceModel) == m_availableSurfaceModels.end()) { /* * Selected model is not found. */ m_selectedSurfaceModel = NULL; /* * First, see if a previous model for structure still exists, if so, use it. */ std::map::iterator iter = m_previousSelectedSurfaceModel.find(m_selectedStructure); if (iter != m_previousSelectedSurfaceModel.end()) { ModelSurface* previousModel = iter->second; if (std::find(m_availableSurfaceModels.begin(), m_availableSurfaceModels.end(), previousModel) != m_availableSurfaceModels.end()) { m_selectedSurfaceModel = previousModel; } } /* * Still not found? */ if (m_selectedSurfaceModel == NULL) { /* * Default to first */ if (m_availableSurfaceModels.empty() == false) { m_selectedSurfaceModel = m_availableSurfaceModels[0]; /* * Try to find and used the primary anatomical surface. */ Brain* brain = m_selectedSurfaceModel->getBrain(); if (brain != NULL) { BrainStructure* brainStructure = brain->getBrainStructure(m_selectedStructure, false); if (brainStructure != NULL) { const Surface* volInteractSurface = brainStructure->getPrimaryAnatomicalSurface(); if (volInteractSurface != NULL) { const int numSurfaceModels = static_cast(m_availableSurfaceModels.size()); for (int32_t i = 0; i < numSurfaceModels; i++) { if (m_availableSurfaceModels[i]->getSurface() == volInteractSurface) { m_selectedSurfaceModel = m_availableSurfaceModels[i]; break; } } } } } } } } /* * Save model for retrieval later. */ if (m_selectedSurfaceModel != NULL) { m_previousSelectedSurfaceModel[m_selectedStructure] = m_selectedSurfaceModel; } } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ModelSurfaceSelector::toString() const { AString msg = "selectedStructure=" + StructureEnum::toName(m_selectedStructure) + "selectedSurface="; if (m_selectedSurfaceModel != NULL) { msg += m_selectedSurfaceModel->getNameForGUI(false); } return msg; } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of the class' instance. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* ModelSurfaceSelector::saveToScene(const SceneAttributes* /*sceneAttributes*/, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ModelSurfaceSelector", 1); sceneClass->addEnumeratedType("m_selectedStructure", m_selectedStructure); if (m_selectedSurfaceModel != NULL) { const Surface* surface = m_selectedSurfaceModel->getSurface(); if (surface != NULL) { const AString filename = surface->getFileNameNoPath(); sceneClass->addString("surfaceFileName", filename); } } return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. May be NULL for some types of scenes. */ void ModelSurfaceSelector::restoreFromScene(const SceneAttributes* /*sceneAttributes*/, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_selectedStructure = sceneClass->getEnumeratedTypeValue("m_selectedStructure", m_selectedStructure); setSelectedStructure(m_selectedStructure); const AString surfaceFileName = sceneClass->getStringValue("surfaceFileName", ""); ModelSurface* matchedSurfaceModel = NULL; if (surfaceFileName.isEmpty() == false) { for (std::vector::iterator iter = m_availableSurfaceModels.begin(); iter != m_availableSurfaceModels.end(); iter++) { const Surface* surface = (*iter)->getSurface(); if (surfaceFileName == surface->getFileNameNoPath()) { matchedSurfaceModel = *iter; break; } } } /* * Note: setSelectedSurfaceModel() will update the content of * m_availableSurfaceModels and the above iterators will become * invalid. So setSelectedSurfaceModel() must be called outside * of the loop. * Bug found by JS. */ if (matchedSurfaceModel != NULL) { setSelectedSurfaceModel(matchedSurfaceModel); } } connectome-workbench-1.4.2/src/Brain/ModelSurfaceSelector.h000066400000000000000000000061621360521144700237050ustar00rootroot00000000000000#ifndef __MODEL_SURFACE_SELECTOR__H_ #define __MODEL_SURFACE_SELECTOR__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "SceneableInterface.h" #include "StructureEnum.h" namespace caret { class Model; class ModelSurface; class ModelSurfaceSelector : public CaretObject, public SceneableInterface { public: ModelSurfaceSelector(); virtual ~ModelSurfaceSelector(); ModelSurface* getSelectedSurfaceModel(); StructureEnum::Enum getSelectedStructure(); void setSelectedSurfaceModel(ModelSurface* surfaceModel); void setSelectedStructure(const StructureEnum::Enum selectedStructure); void getSelectableStructures( std::vector& selectableSructuresOut) const; void getSelectableSurfaceModels( std::vector& selectableSurfaceModelsOut) const; void updateSelector(const std::vector modelDisplayModels); AString toString() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: ModelSurfaceSelector(const ModelSurfaceSelector&); ModelSurfaceSelector& operator=(const ModelSurfaceSelector&); void updateSelector(); private: std::vector m_availableStructures; StructureEnum::Enum m_selectedStructure; StructureEnum::Enum m_defaultStructure; std::vector m_allSurfaceModels; std::vector m_availableSurfaceModels; ModelSurface* m_selectedSurfaceModel; std::map m_previousSelectedSurfaceModel; }; #ifdef __MODEL_SURFACE_SELECTOR_DECLARE__ // #endif // __MODEL_SURFACE_SELECTOR_DECLARE__ } // namespace #endif //__MODEL_SURFACE_SELECTOR__H_ connectome-workbench-1.4.2/src/Brain/ModelTypeEnum.cxx000066400000000000000000000210451360521144700227320ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __MODEL_DISPLAY_CONTROLLER_TYPE_ENUM_DECLARE__ #include "ModelTypeEnum.h" #undef __MODEL_DISPLAY_CONTROLLER_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * Constructor. * * @param enumValue * An enumerated value. * @param integerCode * Integer code for this enumerated value. * * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ModelTypeEnum::ModelTypeEnum(const Enum enumValue, const int32_t integerCode, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCode; this->name = name; this->guiName = guiName; } /** * Destructor. */ ModelTypeEnum::~ModelTypeEnum() { } /** * Initialize the enumerated metadata. */ void ModelTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ModelTypeEnum(MODEL_TYPE_INVALID, 0, "MODEL_TYPE_INVALID", "Invalid")); enumData.push_back(ModelTypeEnum(MODEL_TYPE_CHART, 1, "MODEL_TYPE_CHART", "Chart")); enumData.push_back(ModelTypeEnum(MODEL_TYPE_CHART_TWO, 2, "MODEL_TYPE_CHART_TWO", "Chart")); enumData.push_back(ModelTypeEnum(MODEL_TYPE_SURFACE, 3, "MODEL_TYPE_SURFACE", "Surface")); enumData.push_back(ModelTypeEnum(MODEL_TYPE_SURFACE_MONTAGE, 4, "MODEL_TYPE_SURFACE_MONTAGE", "Surface Montage")); enumData.push_back(ModelTypeEnum(MODEL_TYPE_VOLUME_SLICES, 5, "MODEL_TYPE_VOLUME_SLICES", "Volume")); enumData.push_back(ModelTypeEnum(MODEL_TYPE_WHOLE_BRAIN, 6, "MODEL_TYPE_WHOLE_BRAIN", "Whole Brain")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ModelTypeEnum* ModelTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ModelTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ModelTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ModelTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ModelTypeEnum::Enum ModelTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = MODEL_TYPE_INVALID; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ModelTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ModelTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ModelTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ModelTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param guiName * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ModelTypeEnum::Enum ModelTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = MODEL_TYPE_INVALID; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ModelTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ModelTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * @param enumValue * Enumerated value. * @return * Integer code for data type. */ int32_t ModelTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ModelTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ModelTypeEnum::Enum ModelTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = MODEL_TYPE_INVALID; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ModelTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ModelTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ModelTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } connectome-workbench-1.4.2/src/Brain/ModelTypeEnum.h000066400000000000000000000062001360521144700223530ustar00rootroot00000000000000#ifndef __MODEL_DISPLAY_CONTROLLER_TYPE_ENUM__H_ #define __MODEL_DISPLAY_CONTROLLER_TYPE_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { /// Enumerated type for class ModelTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Invalid */ MODEL_TYPE_INVALID, /** Chart */ MODEL_TYPE_CHART, /** Chart Two */ MODEL_TYPE_CHART_TWO, /** Surface */ MODEL_TYPE_SURFACE, /** Surface Montage */ MODEL_TYPE_SURFACE_MONTAGE, /** Volume Slices */ MODEL_TYPE_VOLUME_SLICES, /** Whole Brain */ MODEL_TYPE_WHOLE_BRAIN }; ~ModelTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); private: ModelTypeEnum(const Enum enumValue, const int32_t integerCode, const AString& name, const AString& guiName); static const ModelTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __MODEL_DISPLAY_CONTROLLER_TYPE_ENUM_DECLARE__ std::vector ModelTypeEnum::enumData; bool ModelTypeEnum::initializedFlag = false; #endif // __MODEL_DISPLAY_CONTROLLER_TYPE_ENUM_DECLARE__ } // namespace #endif //__MODEL_DISPLAY_CONTROLLER_TYPE_ENUM__H_ connectome-workbench-1.4.2/src/Brain/ModelVolume.cxx000066400000000000000000000145141360521144700224360ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Brain.h" #include "BrowserTabContent.h" #include "EventBrowserTabGet.h" #include "EventManager.h" #include "Overlay.h" #include "OverlaySet.h" #include "OverlaySetArray.h" #include "ModelVolume.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "SceneEnumeratedType.h" #include "VolumeFile.h" using namespace caret; /** * Constructor. * @param brain - brain to which this volume model belongs. * */ ModelVolume::ModelVolume(Brain* brain) : Model(ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES, brain) { std::vector overlaySurfaceStructures; m_overlaySetArray = new OverlaySetArray(overlaySurfaceStructures, Overlay::INCLUDE_VOLUME_FILES_YES, "Volume View"); m_lastVolumeFile = NULL; /* * Scene note: overlaySet is restored by parent class */ m_sceneAssistant = new SceneClassAssistant(); } /** * Destructor */ ModelVolume::~ModelVolume() { EventManager::get()->removeAllEventsFromListener(this); delete m_overlaySetArray; delete m_sceneAssistant; } /** * Get the name for use in a GUI. * * @param includeStructureFlag Prefix label with structure to which * this structure model belongs. * @return Name for use in a GUI. * */ AString ModelVolume::getNameForGUI(const bool /*includeStructureFlag*/) const { return "Volume"; } /** * @return The name that should be displayed in the tab * displaying this model. */ AString ModelVolume::getNameForBrowserTab() const { return "Volume"; } /** * Get the bottom-most active volume in the given window tab. * If no overlay is set to volume data, one will be set to a * volume if there is a volume loaded. * @param windowTabNumber * Tab number for content. * @return * Bottom-most volume or NULL if no volumes available. */ VolumeMappableInterface* ModelVolume::getUnderlayVolumeFile(const int32_t windowTabNumber) const { OverlaySet* overlaySet = m_overlaySetArray->getOverlaySet(windowTabNumber); VolumeMappableInterface* vf = overlaySet->getUnderlayVolume(); if (vf == NULL) { vf = overlaySet->setUnderlayToVolume(); } // EventBrowserTabGet getBrowserTabEvent(windowTabNumber); // EventManager::get()->sendEvent(getBrowserTabEvent.getPointer()); // BrowserTabContent* btc = getBrowserTabEvent.getBrowserTab(); // if (btc != NULL) { // OverlaySet* overlaySet = btc->getOverlaySet(); // vf = overlaySet->getUnderlayVolume(); // if (vf == NULL) { // vf = overlaySet->setUnderlayToVolume(); // } // } return vf; } /** * Update the model. * @param windowTabNumber * Tab number of window. */ void ModelVolume::updateModel(const int32_t /*windowTabNumber*/) { } /** * Receive events from the event manager. * * @param event * The event. */ void ModelVolume::receiveEvent(Event* /*event*/) { } /** * Get the overlay set for the given tab. * @param tabIndex * Index of tab. * @return * Overlay set at the given tab index. */ OverlaySet* ModelVolume::getOverlaySet(const int tabIndex) { return m_overlaySetArray->getOverlaySet(tabIndex); } /** * Get the overlay set for the given tab. * @param tabIndex * Index of tab. * @return * Overlay set at the given tab index. */ const OverlaySet* ModelVolume::getOverlaySet(const int tabIndex) const { return m_overlaySetArray->getOverlaySet(tabIndex); } /** * Initilize the overlays for this model. */ void ModelVolume::initializeOverlays() { m_overlaySetArray->initializeOverlaySelections(); } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param sceneClass * SceneClass to which model specific information is added. */ void ModelVolume::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ModelVolume::restoreModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } /** * Copy the tab content from the source tab index to the * destination tab index. * * @param sourceTabIndex * Source from which tab content is copied. * @param destinationTabIndex * Destination to which tab content is copied. */ void ModelVolume::copyTabContent(const int32_t sourceTabIndex, const int32_t destinationTabIndex) { Model::copyTabContent(sourceTabIndex, destinationTabIndex); m_overlaySetArray->copyOverlaySet(sourceTabIndex, destinationTabIndex); } connectome-workbench-1.4.2/src/Brain/ModelVolume.h000066400000000000000000000055161360521144700220650ustar00rootroot00000000000000#ifndef __MODEL_DISPLAY_CONTROLLER_VOLUME_H__ #define __MODEL_DISPLAY_CONTROLLER_VOLUME_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventListenerInterface.h" #include "Model.h" namespace caret { class Brain; class SceneClassAssistant; class OverlaySetArray; class VolumeMappableInterface; /// Controls the display of a volumes. class ModelVolume : public Model, public EventListenerInterface { public: ModelVolume(Brain* brain); virtual ~ModelVolume(); VolumeMappableInterface* getUnderlayVolumeFile(const int32_t windowTabNumber) const; void updateModel(const int32_t windowTabNumber); void receiveEvent(Event* event); OverlaySet* getOverlaySet(const int tabIndex); const OverlaySet* getOverlaySet(const int tabIndex) const; void initializeOverlays(); virtual void copyTabContent(const int32_t sourceTabIndex, const int32_t destinationTabIndex); protected: virtual void saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: ModelVolume(const ModelVolume&); ModelVolume& operator=(const ModelVolume&); private: public: AString getNameForGUI(const bool includeStructureFlag) const; virtual AString getNameForBrowserTab() const; private: VolumeMappableInterface* m_lastVolumeFile; /** Overlays sets for this model and for each tab */ OverlaySetArray* m_overlaySetArray; SceneClassAssistant* m_sceneAssistant; }; } // namespace #endif // __MODEL_DISPLAY_CONTROLLER_VOLUME_H__ connectome-workbench-1.4.2/src/Brain/ModelWholeBrain.cxx000066400000000000000000000566541360521144700232340ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __MODEL_WHOLE_BRAIN_DEFINE__ #include "ModelWholeBrain.h" #undef __MODEL_WHOLE_BRAIN_DEFINE__ #include "Brain.h" #include "BrainStructure.h" #include "BrowserTabContent.h" #include "EventBrowserTabGet.h" #include "EventManager.h" #include "EventModelGetAll.h" #include "EventSurfacesGet.h" #include "IdentificationManager.h" #include "ModelSurface.h" #include "OverlaySet.h" #include "OverlaySetArray.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneClassAssistant.h" #include "Surface.h" using namespace caret; /** * Constructor. * @param brain - brain to which this whole brain model belongs. * */ ModelWholeBrain::ModelWholeBrain(Brain* brain) : Model(ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN, brain) { if (s_anatomicalSurfaceTypes.empty()) { SurfaceTypeEnum::getAllAnatomicallyShapedEnums(s_anatomicalSurfaceTypes); } for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_selectedSurfaceType[i] = SurfaceTypeEnum::ANATOMICAL; m_cerebellumEnabled[i] = true; m_leftEnabled[i] = true; m_rightEnabled[i] = true; m_leftRightSeparation[i] = 0.0; m_cerebellumSeparation[i] = 0.0; } std::vector overlaySurfaceStructures; overlaySurfaceStructures.push_back(StructureEnum::CORTEX_LEFT); overlaySurfaceStructures.push_back(StructureEnum::CORTEX_RIGHT); overlaySurfaceStructures.push_back(StructureEnum::CEREBELLUM); m_overlaySetArray = new OverlaySetArray(overlaySurfaceStructures, Overlay::INCLUDE_VOLUME_FILES_YES, "All View"); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_IDENTIFICATION_HIGHLIGHT_LOCATION); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_selectedSurfaceType", m_selectedSurfaceType); m_sceneAssistant->addTabIndexedBooleanArray("m_leftEnabled", m_leftEnabled); m_sceneAssistant->addTabIndexedBooleanArray("m_rightEnabled", m_rightEnabled); m_sceneAssistant->addTabIndexedBooleanArray("m_cerebellumEnabled", m_cerebellumEnabled); m_sceneAssistant->addTabIndexedFloatArray("m_leftRightSeparation", m_leftRightSeparation); m_sceneAssistant->addTabIndexedFloatArray("m_cerebellumSeparation", m_cerebellumSeparation); } /** * Destructor */ ModelWholeBrain::~ModelWholeBrain() { EventManager::get()->removeAllEventsFromListener(this); delete m_overlaySetArray; delete m_sceneAssistant; } /** * Get the available surface types. * @param surfaceTypesOut * Output loaded with the available surface types. */ void ModelWholeBrain::getAvailableSurfaceTypes(std::vector& surfaceTypesOut) { updateModel(); surfaceTypesOut.clear(); surfaceTypesOut.insert(surfaceTypesOut.end(), m_availableSurfaceTypes.begin(), m_availableSurfaceTypes.end()); } /** * Get the selected surface type for the given tab. * * @param windowTabNumber * The tab. * @return * Surface type for the tab. */ SurfaceTypeEnum::Enum ModelWholeBrain::getSelectedSurfaceType(const int32_t windowTabNumber) { updateModel(); return m_selectedSurfaceType[windowTabNumber]; } /** * Update this model. */ void ModelWholeBrain::updateModel() { /* * Get all of the surfaces */ EventSurfacesGet surfaceEvent; EventManager::get()->sendEvent(surfaceEvent.getPointer()); std::vector allSurfaces = surfaceEvent.getSurfaces(); /* * Update the available surface types */ m_availableSurfaceTypes.clear(); for (std::vector::iterator surfIter = allSurfaces.begin(); surfIter != allSurfaces.end(); surfIter++) { m_availableSurfaceTypes.insert((*surfIter)->getSurfaceType()); } /* * Set the default surface type from the available anatomical types */ std::vector::iterator defaultSurfaceTypeIter = std::find_first_of(s_anatomicalSurfaceTypes.begin(), s_anatomicalSurfaceTypes.end(), m_availableSurfaceTypes.begin(), m_availableSurfaceTypes.end()); const SurfaceTypeEnum::Enum defaultSurfaceType = ((defaultSurfaceTypeIter != s_anatomicalSurfaceTypes.end()) ? *defaultSurfaceTypeIter : SurfaceTypeEnum::ANATOMICAL); /* * If the selected surface type in a tab is no longer valid, update * selected surface type. */ for (int32_t iTab = 0; iTab < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; iTab++) { if (std::find(m_availableSurfaceTypes.begin(), m_availableSurfaceTypes.end(), m_selectedSurfaceType[iTab]) == m_availableSurfaceTypes.end()) { m_selectedSurfaceType[iTab] = defaultSurfaceType; } } /* * Deselect any surfaces that are no longer valid. They will get updated * the next time getSelected */ for (int32_t tabIndex = 0; tabIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; tabIndex++) { for (std::map, Surface*>::iterator mapIter = m_selectedSurface[tabIndex].begin(); mapIter != m_selectedSurface[tabIndex].end(); mapIter++) { if (std::find(allSurfaces.begin(), allSurfaces.end(), mapIter->second) == allSurfaces.end()) { mapIter->second = NULL; } } } } ///** // * Update this model. // */ //void //ModelWholeBrain::updateModel() //{ // /* // * Get all model to find loaded surface types. // */ // EventModelGetAll eventGetModels; // EventManager::get()->sendEvent(eventGetModels.getPointer()); // const std::vector allModels = // eventGetModels.getModels(); // // /* // * Get ALL possible surface types. // */ // std::vector allSurfaceTypes; // SurfaceTypeEnum::getAllEnums(allSurfaceTypes); // const int32_t numEnumTypes = static_cast(allSurfaceTypes.size()); // std::vector surfaceTypeValid(numEnumTypes, false); // // /* // * Find surface types that are actually used. // */ // for (std::vector::const_iterator iter = allModels.begin(); // iter != allModels.end(); // iter++) { // ModelSurface* surfaceModel = // dynamic_cast(*iter); // if (surfaceModel != NULL) { // SurfaceTypeEnum::Enum surfaceType = surfaceModel->getSurface()->getSurfaceType(); // // for (int i = 0; i < numEnumTypes; i++) { // if (allSurfaceTypes[i] == surfaceType) { // surfaceTypeValid[i] = true; // break; // } // } // } // } // // /* // * Set the available surface types. // */ // m_availableSurfaceTypes.clear(); // for (int i = 0; i < numEnumTypes; i++) { // if (surfaceTypeValid[i]) { // m_availableSurfaceTypes.push_back(allSurfaceTypes[i]); // } // } // // // // /* // * Update the selected surface and volume types. // */ // for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { // if (std::find(m_availableSurfaceTypes.begin(), // m_availableSurfaceTypes.end(), // m_selectedSurfaceType[i]) == m_availableSurfaceTypes.end()) { // if (m_availableSurfaceTypes.empty() == false) { // m_selectedSurfaceType[i] = m_availableSurfaceTypes[0]; // } // else { // m_selectedSurfaceType[i] = SurfaceTypeEnum::ANATOMICAL; // } // } // // VolumeMappableInterface* vf = getUnderlayVolumeFile(i); // if (vf != NULL) { //// m_volumeSlicesSelected[i].updateForVolumeFile(vf); // } // } //} /** * Set the selected surface type. * @param windowTabNumber * Index of window tab. * @param surfaceType * New surface type. */ void ModelWholeBrain::setSelectedSurfaceType(const int32_t windowTabNumber, const SurfaceTypeEnum::Enum surfaceType) { m_selectedSurfaceType[windowTabNumber] = surfaceType; updateModel(); } /** * Get the name for use in a GUI. * * @param includeStructureFlag - Prefix label with structure to which * this structure model belongs. * @return Name for use in a GUI. * */ AString ModelWholeBrain::getNameForGUI(const bool /*includeStructureFlag*/) const { return "Whole Brain"; } /** * @return The name that should be displayed in the tab * displaying this model. */ AString ModelWholeBrain::getNameForBrowserTab() const { return "All "; } /** * Get the bottom-most active volume in the given window tab. * @param windowTabNumber * Tab number for content. * @return * Bottom-most volume or NULL if not available (such as * when all overlay are not volumes or they are disabled). */ VolumeMappableInterface* ModelWholeBrain::getUnderlayVolumeFile(const int32_t windowTabNumber) const { VolumeMappableInterface* vf = NULL; EventBrowserTabGet getBrowserTabEvent(windowTabNumber); EventManager::get()->sendEvent(getBrowserTabEvent.getPointer()); BrowserTabContent* btc = getBrowserTabEvent.getBrowserTab(); if (btc != NULL) { OverlaySet* overlaySet = btc->getOverlaySet(); if (overlaySet != NULL) { vf = overlaySet->getUnderlayVolume(); } } return vf; } /** * @return Return the surfaces displayed in the given tab. * @param windowTabIndex * THe tab. */ std::vector ModelWholeBrain::getSelectedSurfaces(const int32_t windowTabIndex) { std::vector surfaces; /* * Get the surfaces. */ Brain* brain = getBrain(); const int32_t numberOfBrainStructures = brain->getNumberOfBrainStructures(); for (int32_t i = 0; i < numberOfBrainStructures; i++) { BrainStructure* brainStructure = brain->getBrainStructure(i); const StructureEnum::Enum structure = brainStructure->getStructure(); Surface* surface = getSelectedSurface(structure, windowTabIndex); surfaces.push_back(surface); } return surfaces; } /** * Get the surface for the given structure in the given tab that is for * the currently selected surface type. * * @param structure * Structure for the surface * @param windowTabNumber * Tab number of window. * @param Pointer to selected surface for given structure or NULL if not available. */ Surface* ModelWholeBrain::getSelectedSurface(const StructureEnum::Enum structure, const int32_t windowTabNumber) { const SurfaceTypeEnum::Enum surfaceType = getSelectedSurfaceType(windowTabNumber); std::pair key = std::make_pair(structure, surfaceType); /* * Get the currently selected surface. */ Surface* s = m_selectedSurface[windowTabNumber][key]; /* * See if currently selected surface is valid. */ BrainStructure* brainStructure = m_brain->getBrainStructure(structure, false); if (brainStructure == NULL) { return NULL; } std::vector surfaces; brainStructure->getSurfacesOfType(surfaceType, surfaces); if (std::find(surfaces.begin(), surfaces.end(), s) == surfaces.end()) { s = NULL; } /* * If no selected surface, use first surface. */ if (s == NULL) { if (surfaces.empty() == false) { s = surfaces[0]; } } m_selectedSurface[windowTabNumber][key] = s; return s; } /** * Set the selected surface for the given structure in the given window tab * that is for the currently selected surface type. * surface type. * * @param structure * Structure for the surface * @param windowTabNumber * Tab number of window. * @param surface * Newly selected surface. */ void ModelWholeBrain::setSelectedSurface(const StructureEnum::Enum structure, const int32_t windowTabNumber, Surface* surface) { const SurfaceTypeEnum::Enum surfaceType = getSelectedSurfaceType(windowTabNumber); std::pair key = std::make_pair(structure, surfaceType); m_selectedSurface[windowTabNumber][key] = surface; } /** * Receive events from the event manager. * * @param event * The event. */ void ModelWholeBrain::receiveEvent(Event* /*event*/) { } /** * Get the overlay set for the given tab. * @param tabIndex * Index of tab. * @return * Overlay set at the given tab index. */ OverlaySet* ModelWholeBrain::getOverlaySet(const int tabIndex) { return m_overlaySetArray->getOverlaySet(tabIndex); } /** * Get the overlay set for the given tab. * @param tabIndex * Index of tab. * @return * Overlay set at the given tab index. */ const OverlaySet* ModelWholeBrain::getOverlaySet(const int tabIndex) const { return m_overlaySetArray->getOverlaySet(tabIndex); } /** * Initilize the overlays for this model. */ void ModelWholeBrain::initializeOverlays() { m_overlaySetArray->initializeOverlaySelections(); } /** * Initialize the selected surfaces. */ void ModelWholeBrain::initializeSelectedSurfaces() { std::vector surfaceTypes; getAvailableSurfaceTypes(surfaceTypes); if (std::find(surfaceTypes.begin(), surfaceTypes.end(), SurfaceTypeEnum::ANATOMICAL) != surfaceTypes.end()) { for (int32_t iTab = 0; iTab < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; iTab++) { setSelectedSurfaceType(iTab, SurfaceTypeEnum::ANATOMICAL); } } const int32_t numberOfStructures = m_brain->getNumberOfBrainStructures(); for (int32_t i = 0; i < numberOfStructures; i++) { const BrainStructure* brainStructure = m_brain->getBrainStructure(i); Surface* surface = const_cast(brainStructure->getPrimaryAnatomicalSurface()); if (surface != NULL) { const StructureEnum::Enum structure = brainStructure->getStructure(); for (int32_t iTab = 0; iTab < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; iTab++) { setSelectedSurface(structure, iTab, surface); } } } } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param sceneClass * SceneClass to which model specific information is added. */ void ModelWholeBrain::saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); const std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); const int32_t numTabs = static_cast(tabIndices.size()); std::vector classesForSelectedSurfaceArray; for (int32_t i = 0; i < numTabs; i++) { const int32_t tabIndex = tabIndices[i]; const SurfaceTypeEnum::Enum selectedSurfaceType = getSelectedSurfaceType(tabIndex); /* * Updates selected surfaces */ getSelectedSurfaces(tabIndex); for (std::map, Surface*>::iterator mapIter = m_selectedSurface[tabIndex].begin(); mapIter != m_selectedSurface[tabIndex].end(); mapIter++) { std::pair structureSurfaceType = mapIter->first; const SurfaceTypeEnum::Enum surfaceType = structureSurfaceType.second; if (surfaceType == selectedSurfaceType) { Surface* surface = mapIter->second; if (surface != NULL) { const StructureEnum::Enum structure = structureSurfaceType.first; const AString name = ("m_selectedSurface[" + AString::number(tabIndex) + "]"); SceneClass* surfaceClass = new SceneClass(name, "SurfaceSelectionMap", 1); surfaceClass->addInteger("tabIndex", tabIndex); surfaceClass->addEnumeratedType("structure", structure); surfaceClass->addEnumeratedType("surfaceType", surfaceType); surfaceClass->addString("surfaceName", surface->getFileNameNoPath()); classesForSelectedSurfaceArray.push_back(surfaceClass); } } } } sceneClass->addChild(new SceneClassArray("m_selectedSurface", classesForSelectedSurfaceArray)); } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ModelWholeBrain::restoreModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } /* * Restore selected surface */ const SceneClassArray* surfaceSelectionArray = sceneClass->getClassArray("m_selectedSurface"); if (surfaceSelectionArray != NULL) { const int32_t numClasses = surfaceSelectionArray->getNumberOfArrayElements(); for (int32_t ica = 0; ica < numClasses; ica++) { const SceneClass* surfaceClass = surfaceSelectionArray->getClassAtIndex(ica); const int32_t tabIndex = surfaceClass->getIntegerValue("tabIndex", -1); const StructureEnum::Enum structure = surfaceClass->getEnumeratedTypeValue("structure", StructureEnum::INVALID); const SurfaceTypeEnum::Enum surfaceType = surfaceClass->getEnumeratedTypeValue("surfaceType", SurfaceTypeEnum::UNKNOWN); const AString surfaceName = surfaceClass->getStringValue("surfaceName", ""); if ((tabIndex >= 0) && (structure != StructureEnum::INVALID) && (surfaceType != SurfaceTypeEnum::UNKNOWN) && (surfaceName.isEmpty() == false)) { BrainStructure* brainStructure = getBrain()->getBrainStructure(structure, false); if (brainStructure != NULL) { const int32_t numSurfaces = brainStructure->getNumberOfSurfaces(); for (int32_t i = 0; i < numSurfaces; i++) { Surface* surface = brainStructure->getSurface(i); const AString loadedSurfaceName = surface->getFileName(); if (loadedSurfaceName.endsWith(surfaceName)) { setSelectedSurfaceType(tabIndex, surfaceType); setSelectedSurface(structure, tabIndex, surface); break; } } } } } } /* * Need to do after */ m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } /** * Copy the tab content from the source tab index to the * destination tab index. * * @param sourceTabIndex * Source from which tab content is copied. * @param destinationTabIndex * Destination to which tab content is copied. */ void ModelWholeBrain::copyTabContent(const int32_t sourceTabIndex, const int32_t destinationTabIndex) { Model::copyTabContent(sourceTabIndex, destinationTabIndex); CaretAssertArrayIndex(m_selectedSurfaceType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, sourceTabIndex); CaretAssertArrayIndex(m_selectedSurfaceType, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, destinationTabIndex); m_selectedSurface[destinationTabIndex] = m_selectedSurface[sourceTabIndex]; m_selectedSurfaceType[destinationTabIndex] = m_selectedSurfaceType[sourceTabIndex]; m_leftEnabled[destinationTabIndex] = m_leftEnabled[sourceTabIndex]; m_rightEnabled[destinationTabIndex] = m_rightEnabled[sourceTabIndex]; m_cerebellumEnabled[destinationTabIndex] = m_cerebellumEnabled[sourceTabIndex]; m_leftRightSeparation[destinationTabIndex] = m_leftRightSeparation[sourceTabIndex]; m_cerebellumSeparation[destinationTabIndex] = m_cerebellumSeparation[sourceTabIndex]; m_overlaySetArray->copyOverlaySet(sourceTabIndex, destinationTabIndex); } connectome-workbench-1.4.2/src/Brain/ModelWholeBrain.h000066400000000000000000000121461360521144700226450ustar00rootroot00000000000000#ifndef __MODEL_WHOLE_BRAIN_H__ #define __MODEL_WHOLE_BRAIN_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "BrainConstants.h" #include "EventListenerInterface.h" #include "Model.h" #include "StructureEnum.h" #include "SurfaceTypeEnum.h" namespace caret { class Brain; class OverlaySetArray; class Surface; class SceneClassAssistant; class VolumeMappableInterface; /// Controls the display of a whole brain. class ModelWholeBrain : public Model, public EventListenerInterface { public: ModelWholeBrain(Brain* brain); virtual ~ModelWholeBrain(); VolumeMappableInterface* getUnderlayVolumeFile(const int32_t windowTabNumber) const; void getAvailableSurfaceTypes(std::vector& surfaceTypesOut); SurfaceTypeEnum::Enum getSelectedSurfaceType(const int32_t windowTabNumber); void setSelectedSurfaceType(const int32_t windowTabNumber, const SurfaceTypeEnum::Enum surfaceType); std::vector getSelectedSurfaces(const int32_t windowTabNumber); Surface* getSelectedSurface(const StructureEnum::Enum structure, const int32_t windowTabNumber); void setSelectedSurface(const StructureEnum::Enum structure, const int32_t windowTabNumber, Surface* surface); void receiveEvent(Event* event); OverlaySet* getOverlaySet(const int tabIndex); const OverlaySet* getOverlaySet(const int tabIndex) const; void initializeOverlays(); virtual void initializeSelectedSurfaces(); virtual void copyTabContent(const int32_t sourceTabIndex, const int32_t destinationTabIndex); void updateModel(); protected: virtual void saveModelSpecificInformationToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreModelSpecificInformationFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: ModelWholeBrain(const ModelWholeBrain&); ModelWholeBrain& operator=(const ModelWholeBrain&); public: AString getNameForGUI(const bool includeStructureFlag) const; virtual AString getNameForBrowserTab() const; private: /** Type of surface for display */ mutable SurfaceTypeEnum::Enum m_selectedSurfaceType[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** Selected surface for structure/surface-type */ std::map, Surface*> m_selectedSurface[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** Available surface types */ std::set m_availableSurfaceTypes; bool m_leftEnabled[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; bool m_rightEnabled[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; bool m_cerebellumEnabled[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; float m_leftRightSeparation[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; float m_cerebellumSeparation[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** Surface types that have an anatomical appearance. */ static std::vector s_anatomicalSurfaceTypes; // mutable VolumeSliceCoordinateSelection m_volumeSlicesSelected[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; VolumeMappableInterface* m_lastVolumeFile; /** Overlays sets for this model and for each tab */ OverlaySetArray* m_overlaySetArray; SceneClassAssistant* m_sceneAssistant; }; #ifdef __MODEL_WHOLE_BRAIN_DEFINE__ std::vector ModelWholeBrain::s_anatomicalSurfaceTypes; #endif // __MODEL_WHOLE_BRAIN_DEFINE__ } // namespace #endif // __MODEL_WHOLE_BRAIN_H__ connectome-workbench-1.4.2/src/Brain/MovieRecorder.cxx000066400000000000000000000505031360521144700227510ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __MOVIE_RECORDER_DECLARE__ #include "MovieRecorder.h" #undef __MOVIE_RECORDER_DECLARE__ #include #include #include #include #include #include "Brain.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "DataFileException.h" #include "FileInformation.h" #include "MovieRecorderVideoFormatTypeEnum.h" #include "ImageFile.h" #include "TextFile.h" using namespace caret; /** * \class caret::MovieRecorder * \brief Records images and creates movie file from images * \ingroup Brain */ /** * Constructor. */ MovieRecorder::MovieRecorder() : CaretObject() { const QString tempSubDir("WbViewMovie"); QDir tempDir(QDir::temp()); /* * "CD" will fail if temporary subdirectory does not exist */ if ( ! tempDir.cd(tempSubDir)) { /* * Try to create subdirectory */ if (tempDir.mkdir(tempSubDir)) { /* * Go to temp subdirectory */ tempDir.cd(tempSubDir); } } m_temporaryImagesDirectory = tempDir.absolutePath(); m_tempImageFileNamePrefix = "movie"; m_tempImageFileNameSuffix = ".png"; removeTemporaryImages(); } /** * Destructor. */ MovieRecorder::~MovieRecorder() { removeTemporaryImages(); } /** * Add an image to the movie, typically used during automatic mode recording * * @param image * Image that is added */ void MovieRecorder::addImageToMovie(const QImage* image) { if (image == NULL) { CaretLogSevere("Attempting to add NULL image to movie"); return; } if (getNumberOfFrames() <= 0) { std::cout << "Temporary Directory for movie images: " << std::endl << " " << m_temporaryImagesDirectory << std::endl << std::flush; } CaretAssert(m_tempImageSequenceNumberOfDigits > 0); /* * First image starts at 1 and is padded with zeros on the left */ const int32_t imageIndexInt = getNumberOfFrames() + 1; const QString imageIndex = QString::number(imageIndexInt).rightJustified(m_tempImageSequenceNumberOfDigits, '0'); const QString imageFileName(m_temporaryImagesDirectory + "/" + m_tempImageFileNamePrefix + imageIndex + m_tempImageFileNameSuffix); switch (m_imageWriteMode) { case ImageWriteMode::IMMEDITATE: if (image->save(imageFileName)) { if (m_imageFileNames.empty()) { m_firstImageWidth = image->width(); m_firstImageHeight = image->height(); } if ((image->width() == m_firstImageWidth) && (image->height() == m_firstImageHeight)) { m_imageFileNames.push_back(imageFileName); } else { CaretLogSevere("Attempting to create movie with images that are different sizes. " "First image width=" + QString::number(m_firstImageWidth) + ", height=" + QString::number(m_firstImageHeight) + " Image number=" + QString::number(imageIndexInt) + ", width=" + QString::number(image->width()) + ", height=" + QString::number(image->height())); } } else { CaretLogSevere("Saving temporary image failed: " + imageFileName); } break; case ImageWriteMode::PARALLEL: { ImageWriter* iw = new ImageWriter(image, imageFileName); m_imageWriters.push_back(iw); QFuture f = QtConcurrent::run(iw, &ImageWriter::writeImage); m_imageWriteResultFutures.push_back(f); m_imageFileNames.push_back(imageFileName); } break; } } /** * Add copies of an image to the movie for the given number of copies. * Typically used during manual mode recording. * * @param image * Image that is added * @param numberOfCopies * Number of copies for the image. */ void MovieRecorder::addImageToMovieWithCopies(const QImage* image, const int32_t numberOfCopies) { for (int32_t i = 0; i < numberOfCopies; i++) { addImageToMovie(image); } } /** * @return True if all images were written succussfully * if parallel image file writing is enabled. Returns * true if image writing mode is immediate. */ bool MovieRecorder::waitForImagesToFinishWriting() { bool allValid(true); switch (m_imageWriteMode) { case ImageWriteMode::IMMEDITATE: break; case ImageWriteMode::PARALLEL: { for (auto f : m_imageWriteResultFutures) { f.waitForFinished(); } } break; } return allValid; } /** * Remove all images and starting a new movie */ void MovieRecorder::removeTemporaryImages() { waitForImagesToFinishWriting(); m_imageWriteResultFutures.clear(); for (auto iw : m_imageWriters) { delete iw; } m_imageWriters.clear(); const QString nameFilter(m_tempImageFileNamePrefix + "*" + m_tempImageFileNameSuffix); QStringList allNameFilters; allNameFilters.append(nameFilter); QDir dir(m_temporaryImagesDirectory); QFileInfoList fileInfoList = dir.entryInfoList(allNameFilters, QDir::Files, QDir::Name); QListIterator iter(fileInfoList); while (iter.hasNext()) { QFile file(iter.next().absoluteFilePath()); if (file.exists()) { file.remove(); } } m_imageFileNames.clear(); m_firstImageWidth = -1; m_firstImageHeight = -1; } /** * @return The recording mode */ MovieRecorderModeEnum::Enum MovieRecorder::getRecordingMode() const { return m_recordingMode; } /** * Set the recording mode * * @param recordingMode * New recording mode */ void MovieRecorder::setRecordingMode(const MovieRecorderModeEnum::Enum recordingMode) { m_recordingMode = recordingMode; } /** * @return Index of window that is recorded */ int32_t MovieRecorder::getRecordingWindowIndex() const { return m_windowIndex; } /** * Set index of window that is recorded * * @param windowIndex * Index of window */ void MovieRecorder::setRecordingWindowIndex(const int32_t windowIndex) { m_windowIndex = windowIndex; } /** * @return Video resolution type */ MovieRecorderVideoResolutionTypeEnum::Enum MovieRecorder::getVideoResolutionType() const { return m_resolutionType; } /** * Set the video resolution type * * @param resolutionType * New resolution type */ void MovieRecorder::setVideoResolutionType(const MovieRecorderVideoResolutionTypeEnum::Enum resolutionType) { m_resolutionType = resolutionType; } /** * Get the video width and height * * @param widthOut * Output width * @param heightOut * Output height */ void MovieRecorder::getVideoWidthAndHeight(int32_t& widthOut, int32_t& heightOut) const { widthOut = 100; heightOut = 100; const MovieRecorderVideoResolutionTypeEnum::Enum dimType = getVideoResolutionType(); if (dimType == MovieRecorderVideoResolutionTypeEnum::CUSTOM) { getCustomWidthAndHeight(widthOut, heightOut); } else { MovieRecorderVideoResolutionTypeEnum::getWidthAndHeight(dimType, widthOut, heightOut); } } /** * Get the custom width and height * * @param widthOut * Output width * @param heightOut * Output height */ void MovieRecorder::getCustomWidthAndHeight(int32_t& widthOut, int32_t& heightOut) const { widthOut = m_customWidth; heightOut = m_customHeight; } /** * Set the custom width and height * * @param width * New width * @param height * New height */ void MovieRecorder::setCustomWidthAndHeight(const int32_t width, const int32_t height) { m_customWidth = width; m_customHeight = height; } /** * @return The capture region type */ MovieRecorderCaptureRegionTypeEnum::Enum MovieRecorder::getCaptureRegionType() const { return m_captureRegionType; } /** * Set the capture region type * * @param captureRegionType * New capture region type */ void MovieRecorder::setCaptureRegionType(const MovieRecorderCaptureRegionTypeEnum::Enum captureRegionType) { m_captureRegionType = captureRegionType; } /** * @return Name of movie file */ AString MovieRecorder::getMovieFileName() const { return m_movieFileName; } /** * Set name of movie file * * @param filename * New name for movie file */ void MovieRecorder::setMovieFileName(const AString& filename) { m_movieFileName = filename; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString MovieRecorder::toString() const { return "MovieRecorder"; } /** * @return The frame rate (number of frames per second) */ float MovieRecorder::getFramesRate() const { return m_frameRate; } /** * Set the frame rate (number of frames per second) * * @param frameRate * New frame rate */ void MovieRecorder::setFramesRate(const float frameRate) { m_frameRate = frameRate; } /** * @return True if temporary images should be removed * after creation of a movie */ bool MovieRecorder::isRemoveTemporaryImagesAfterMovieCreation() const { return m_removeTemporaryImagesAfterMovieCreationFlag; } /** * Set temporary images should be removed after creation of a movie * * @param status * New status */ void MovieRecorder::setRemoveTemporaryImagesAfterMovieCreation(const bool status) { m_removeTemporaryImagesAfterMovieCreationFlag = status; } /** * @return Number of frames (images) that have been recorded */ int32_t MovieRecorder::getNumberOfFrames() const { return m_imageFileNames.size(); } /** * Create the movie using images captured thus far * * @param filename * File name for movie. * @param errorMessageOut * Contains information if movie creation failed * @return * True if successful, else false */ bool MovieRecorder::createMovie(const AString& filename, AString& errorMessageOut) { errorMessageOut.clear(); if ( ! waitForImagesToFinishWriting()) { errorMessageOut = "There was a problem writing the image files."; return false; } m_movieFileName = filename; if (m_movieFileName.isEmpty()) { errorMessageOut = "Movie file name is invalid or empty"; return false; } FileInformation fileInfo(m_movieFileName); if (fileInfo.exists()) { errorMessageOut = ("Movie file exists, delete or change name: " + m_movieFileName); return false; } if (m_imageFileNames.empty()) { errorMessageOut.appendWithNewLine("No images have been recorded for the movie."); } if (m_movieFileName.isEmpty()) { errorMessageOut.appendWithNewLine("Movie file name is empty."); } if ( ! errorMessageOut.isEmpty()) { return false; } const AString sequenceDigitsPattern("%0" + AString::number(m_tempImageSequenceNumberOfDigits) + "d"); const AString imagesRegularExpressionMatch(m_temporaryImagesDirectory + "/" + m_tempImageFileNamePrefix + sequenceDigitsPattern + m_tempImageFileNameSuffix); QString workbenchHomeDir = SystemUtilities::getWorkbenchHome(); /* Qt after 5.? const QString ffmpegDir = qEnvironmentVariable("WORKBENCH_FFMPEG_DIR"); */ const QString ffmpegDir = qgetenv("WORKBENCH_FFMPEG_DIR").constData(); if ( ! ffmpegDir.isEmpty()) { workbenchHomeDir = ffmpegDir; } const bool qProcessPipeFlag(false); const QString textFileName(m_temporaryImagesDirectory + "/" + "images.txt"); const QString programName(workbenchHomeDir + "/ffmpeg"); FileInformation ffmpegInfo(programName); if ( ! ffmpegInfo.exists()) { errorMessageOut = ("Invalid path for ffmpeg: " + programName + "\n WORKBENCH_FFMPEG_DIR can be set to directory containing ffmpeg."); return false; } QStringList arguments; arguments.append("-threads"); arguments.append("4"); arguments.append("-framerate"); arguments.append(AString::number(m_frameRate)); if (qProcessPipeFlag) { /* list of images in file */ arguments.append("-f"); arguments.append("concat"); // arguments.append("-safe"); // arguments.append("0"); arguments.append("-i"); arguments.append(textFileName); } else { arguments.append("-i"); arguments.append(imagesRegularExpressionMatch); } arguments.append("-q:v"); arguments.append("1"); arguments.append(m_movieFileName); bool successFlag(false); if (qProcessPipeFlag) { successFlag = createMovieWithQProcessPipe(programName, arguments, textFileName, errorMessageOut); } else { const bool useQProcessFlag(true); if (useQProcessFlag) { successFlag = createMovieWithQProcess(programName, arguments, errorMessageOut); } else { successFlag = createMovieWithSystemCommand(programName, arguments, errorMessageOut); } } if (successFlag) { if (m_removeTemporaryImagesAfterMovieCreationFlag) { removeTemporaryImages(); } } return successFlag; } /** * Create the movie by using Qt's QProcess and using a * pipe to send the images to ffmpeg * * @param programName * Name of program * @param arguments * Arguments to program * @param errorMessageOut * Output containing error message * @return * True if movie was created or false if there was an error */ bool MovieRecorder::createMovieWithQProcessPipe(const QString& programName, const QStringList& arguments, const QString& textFileName, QString& errorMessageOut) { /* * https://trac.ffmpeg.org/wiki/Concatenate * https://trac.ffmpeg.org/wiki/Slideshow */ bool successFlag(false); TextFile textFile; try { for (const auto name : m_imageFileNames) { textFile.addLine("file " + name); } textFile.writeFile(textFileName); } catch (const DataFileException& dfe) { errorMessageOut = ("Error creating text file containing image names: " + dfe.whatString()); return false; } QProcess process; process.start(programName, arguments); process.closeWriteChannel(); const int noTimeout(-1); const bool finishedFlag = process.waitForFinished(noTimeout); if (finishedFlag) { if (process.exitStatus() == QProcess::NormalExit) { const int resultCode = process.exitCode(); if (resultCode == 0) { successFlag = true; } else { QByteArray results = process.readAllStandardError(); errorMessageOut = QString(results); } } else if (process.exitStatus() == QProcess::CrashExit) { errorMessageOut = "Running ffmpeg crashed"; } } else { errorMessageOut = "Creating movie was terminated for unknown reason"; } return successFlag; } /** * Create the movie by using Qt's QProcess * * @param programName * Name of program * @param arguments * Arguments to program * @param errorMessageOut * Output containing error message * @return * True if movie was created or false if there was an error */ bool MovieRecorder::createMovieWithQProcess(const QString& programName, const QStringList& arguments, QString& errorMessageOut) { bool successFlag(false); QProcess process; process.start(programName, arguments); process.closeWriteChannel(); const int noTimeout(-1); const bool finishedFlag = process.waitForFinished(noTimeout); if (finishedFlag) { if (process.exitStatus() == QProcess::NormalExit) { const int resultCode = process.exitCode(); if (resultCode == 0) { successFlag = true; } else { QByteArray results = process.readAllStandardError(); errorMessageOut = QString(results); } } else if (process.exitStatus() == QProcess::CrashExit) { errorMessageOut = "Running ffmpeg crashed"; } } else { errorMessageOut = "Creating movie was terminated for unknown reason"; } return successFlag; } /** * Create the movie by using the system command * * @param programName * Name of program * @param arguments * Arguments to program * @param errorMessageOut * Output containing error message * @return * True if movie was created or false if there was an error */ bool MovieRecorder::createMovieWithSystemCommand(const QString& programName, const QStringList& arguments, QString& errorMessageOut) { const AString commandString(programName + " " + arguments.join(" ")); const int result = system(commandString.toLatin1().constData()); bool successFlag(false); if (result == 0) { successFlag = true; } else { errorMessageOut = ("Running ffmpeg failed with code=" + AString::number(result)); } return successFlag; } /** * Constructor for image writer * * @param image * The image file * @param filename * Name of file */ MovieRecorder::ImageWriter::ImageWriter(const QImage* image, const QString& filename) : m_image(new QImage(*image)), m_filename(filename) { CaretAssert(m_image); } /** * Destructor */ MovieRecorder::ImageWriter::~ImageWriter() { } /** * Write the image * * @return True if written, false if error. */ bool MovieRecorder::ImageWriter::writeImage() { CaretAssert(m_image); return m_image->save(m_filename); } connectome-workbench-1.4.2/src/Brain/MovieRecorder.h000066400000000000000000000137401360521144700224000ustar00rootroot00000000000000#ifndef __MOVIE_RECORDER_H__ #define __MOVIE_RECORDER_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretObject.h" #include "MovieRecorderCaptureRegionTypeEnum.h" #include "MovieRecorderModeEnum.h" #include "MovieRecorderVideoResolutionTypeEnum.h" class QImage; class QStringList; namespace caret { class MovieRecorder : public CaretObject { public: MovieRecorder(); virtual ~MovieRecorder(); MovieRecorder(const MovieRecorder&) = delete; MovieRecorder& operator=(const MovieRecorder&) = delete; MovieRecorderModeEnum::Enum getRecordingMode() const; void addImageToMovie(const QImage* image); void addImageToMovieWithCopies(const QImage* image, const int32_t numberOfCopies); void setRecordingMode(const MovieRecorderModeEnum::Enum recordingMode); int32_t getRecordingWindowIndex() const; void setRecordingWindowIndex(const int32_t windowIndex); MovieRecorderVideoResolutionTypeEnum::Enum getVideoResolutionType() const; void setVideoResolutionType(const MovieRecorderVideoResolutionTypeEnum::Enum resolutionType); void getVideoWidthAndHeight(int32_t& widthOut, int32_t& heightOut) const; void getCustomWidthAndHeight(int32_t& widthOut, int32_t& heightOut) const; void setCustomWidthAndHeight(const int32_t width, const int32_t height); MovieRecorderCaptureRegionTypeEnum::Enum getCaptureRegionType() const; void setCaptureRegionType(const MovieRecorderCaptureRegionTypeEnum::Enum captureRegionType); AString getMovieFileName() const; void setMovieFileName(const AString& filename); int32_t getNumberOfFrames() const; float getFramesRate() const; void setFramesRate(const float frameRate); bool isRemoveTemporaryImagesAfterMovieCreation() const; void setRemoveTemporaryImagesAfterMovieCreation(const bool status); void removeTemporaryImages(); bool createMovie(const AString& filename, AString& errorMessageOut); // ADD_NEW_METHODS_HERE virtual AString toString() const; private: enum class ImageWriteMode { IMMEDITATE, PARALLEL }; /** * Used to write images in separate thread */ class ImageWriter { public: ImageWriter(const QImage* image, const QString& filename); ~ImageWriter(); bool writeImage(); private: std::unique_ptr m_image; const QString m_filename; }; // ADD_NEW_MEMBERS_HERE bool createMovieWithSystemCommand(const QString& programName, const QStringList& arguments, QString& errorMessageOut); bool createMovieWithQProcess(const QString& programName, const QStringList& arguments, QString& errorMessageOut); bool createMovieWithQProcessPipe(const QString& programName, const QStringList& arguments, const QString& textFileName, QString& errorMessageOut); bool waitForImagesToFinishWriting(); MovieRecorderModeEnum::Enum m_recordingMode = MovieRecorderModeEnum::MANUAL; MovieRecorderVideoResolutionTypeEnum::Enum m_resolutionType = MovieRecorderVideoResolutionTypeEnum::SD_640_480; MovieRecorderCaptureRegionTypeEnum::Enum m_captureRegionType = MovieRecorderCaptureRegionTypeEnum::GRAPHICS; int32_t m_windowIndex = 0; int32_t m_customWidth = 640; int32_t m_customHeight = 480; std::vector m_imageFileNames; std::vector> m_imageWriteResultFutures; std::vector m_imageWriters; ImageWriteMode m_imageWriteMode = ImageWriteMode::PARALLEL; mutable AString m_movieFileName; std::vector m_imageFrameFileNames; float m_frameRate = 30.0f; AString m_temporaryImagesDirectory; AString m_tempImageFileNamePrefix; AString m_tempImageFileNameSuffix; bool m_removeTemporaryImagesAfterMovieCreationFlag = true; const int32_t m_tempImageSequenceNumberOfDigits = 6; int32_t m_firstImageWidth = -1; int32_t m_firstImageHeight = -1; }; #ifdef __MOVIE_RECORDER_DECLARE__ #endif // __MOVIE_RECORDER_DECLARE__ } // namespace #endif //__MOVIE_RECORDER_H__ connectome-workbench-1.4.2/src/Brain/MovieRecorderCaptureRegionTypeEnum.cxx000066400000000000000000000264241360521144700271350ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __MOVIE_RECORDER_CAPTURE_REGION_TYPE_ENUM_DECLARE__ #include "MovieRecorderCaptureRegionTypeEnum.h" #undef __MOVIE_RECORDER_CAPTURE_REGION_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::MovieRecorderCaptureRegionTypeEnum * \brief * * * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_movieRecorderCaptureRegionTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void movieRecorderCaptureRegionTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "MovieRecorderCaptureRegionTypeEnum.h" * * Instatiate: * m_movieRecorderCaptureRegionTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_movieRecorderCaptureRegionTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_movieRecorderCaptureRegionTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(movieRecorderCaptureRegionTypeEnumComboBoxItemActivated())); * * Update the selection: * m_movieRecorderCaptureRegionTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const MovieRecorderCaptureRegionTypeEnum::Enum VARIABLE = m_movieRecorderCaptureRegionTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ MovieRecorderCaptureRegionTypeEnum::MovieRecorderCaptureRegionTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ MovieRecorderCaptureRegionTypeEnum::~MovieRecorderCaptureRegionTypeEnum() { } /** * Initialize the enumerated metadata. */ void MovieRecorderCaptureRegionTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(MovieRecorderCaptureRegionTypeEnum(GRAPHICS, "GRAPHICS", "Graphics")); enumData.push_back(MovieRecorderCaptureRegionTypeEnum(WINDOW, "WINDOW", "Window")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const MovieRecorderCaptureRegionTypeEnum* MovieRecorderCaptureRegionTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const MovieRecorderCaptureRegionTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString MovieRecorderCaptureRegionTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const MovieRecorderCaptureRegionTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ MovieRecorderCaptureRegionTypeEnum::Enum MovieRecorderCaptureRegionTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = MovieRecorderCaptureRegionTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const MovieRecorderCaptureRegionTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type MovieRecorderCaptureRegionTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString MovieRecorderCaptureRegionTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const MovieRecorderCaptureRegionTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ MovieRecorderCaptureRegionTypeEnum::Enum MovieRecorderCaptureRegionTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = MovieRecorderCaptureRegionTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const MovieRecorderCaptureRegionTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type MovieRecorderCaptureRegionTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t MovieRecorderCaptureRegionTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const MovieRecorderCaptureRegionTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ MovieRecorderCaptureRegionTypeEnum::Enum MovieRecorderCaptureRegionTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = MovieRecorderCaptureRegionTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const MovieRecorderCaptureRegionTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type MovieRecorderCaptureRegionTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void MovieRecorderCaptureRegionTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void MovieRecorderCaptureRegionTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(MovieRecorderCaptureRegionTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void MovieRecorderCaptureRegionTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(MovieRecorderCaptureRegionTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Brain/MovieRecorderCaptureRegionTypeEnum.h000066400000000000000000000063661360521144700265650ustar00rootroot00000000000000#ifndef __MOVIE_RECORDER_CAPTURE_REGION_TYPE_ENUM_H__ #define __MOVIE_RECORDER_CAPTURE_REGION_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class MovieRecorderCaptureRegionTypeEnum { public: /** * Enumerated values. */ enum Enum { /** */ GRAPHICS, /** */ WINDOW }; ~MovieRecorderCaptureRegionTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: MovieRecorderCaptureRegionTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const MovieRecorderCaptureRegionTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __MOVIE_RECORDER_CAPTURE_REGION_TYPE_ENUM_DECLARE__ std::vector MovieRecorderCaptureRegionTypeEnum::enumData; bool MovieRecorderCaptureRegionTypeEnum::initializedFlag = false; int32_t MovieRecorderCaptureRegionTypeEnum::integerCodeCounter = 0; #endif // __MOVIE_RECORDER_CAPTURE_REGION_TYPE_ENUM_DECLARE__ } // namespace #endif //__MOVIE_RECORDER_CAPTURE_REGION_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Brain/MovieRecorderModeEnum.cxx000066400000000000000000000246671360521144700244170ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __MOVIE_RECORDER_MODE_ENUM_DECLARE__ #include "MovieRecorderModeEnum.h" #undef __MOVIE_RECORDER_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::MovieRecorderModeEnum * \brief Mode for video recording * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_movieRecorderModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void movieRecorderModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "MovieRecorderModeEnum.h" * * Instatiate: * m_movieRecorderModeEnumComboBox = new EnumComboBoxTemplate(this); * m_movieRecorderModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_movieRecorderModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(movieRecorderModeEnumComboBoxItemActivated())); * * Update the selection: * m_movieRecorderModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const MovieRecorderModeEnum::Enum VARIABLE = m_movieRecorderModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ MovieRecorderModeEnum::MovieRecorderModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ MovieRecorderModeEnum::~MovieRecorderModeEnum() { } /** * Initialize the enumerated metadata. */ void MovieRecorderModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(MovieRecorderModeEnum(AUTOMATIC, "AUTOMATIC", "Automatic")); enumData.push_back(MovieRecorderModeEnum(MANUAL, "MANUAL", "Manual")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const MovieRecorderModeEnum* MovieRecorderModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const MovieRecorderModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString MovieRecorderModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const MovieRecorderModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ MovieRecorderModeEnum::Enum MovieRecorderModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = MovieRecorderModeEnum::MANUAL; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const MovieRecorderModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type MovieRecorderModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString MovieRecorderModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const MovieRecorderModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ MovieRecorderModeEnum::Enum MovieRecorderModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = MovieRecorderModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const MovieRecorderModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type MovieRecorderModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t MovieRecorderModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const MovieRecorderModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ MovieRecorderModeEnum::Enum MovieRecorderModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = MovieRecorderModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const MovieRecorderModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type MovieRecorderModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void MovieRecorderModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void MovieRecorderModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(MovieRecorderModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void MovieRecorderModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(MovieRecorderModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Brain/MovieRecorderModeEnum.h000066400000000000000000000061071360521144700240310ustar00rootroot00000000000000#ifndef __MOVIE_RECORDER_MODE_ENUM_H__ #define __MOVIE_RECORDER_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class MovieRecorderModeEnum { public: /** * Enumerated values. */ enum Enum { /** Automatic*/ AUTOMATIC, /** Manual */ MANUAL }; ~MovieRecorderModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: MovieRecorderModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const MovieRecorderModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __MOVIE_RECORDER_MODE_ENUM_DECLARE__ std::vector MovieRecorderModeEnum::enumData; bool MovieRecorderModeEnum::initializedFlag = false; int32_t MovieRecorderModeEnum::integerCodeCounter = 0; #endif // __MOVIE_RECORDER_MODE_ENUM_DECLARE__ } // namespace #endif //__MOVIE_RECORDER_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Brain/MovieRecorderVideoFormatTypeEnum.cxx000066400000000000000000000315721360521144700266050ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __MOVIE_RECORDER_VIDEO_FORMAT_TYPE_ENUM_DECLARE__ #include "MovieRecorderVideoFormatTypeEnum.h" #undef __MOVIE_RECORDER_VIDEO_FORMAT_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::MovieRecorderVideoFormatTypeEnum * \brief Format for video recording * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_movieRecorderVideoFormatTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void movieRecorderVideoFormatTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "MovieRecorderVideoFormatTypeEnum.h" * * Instatiate: * m_movieRecorderVideoFormatTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_movieRecorderVideoFormatTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_movieRecorderVideoFormatTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(movieRecorderVideoFormatTypeEnumComboBoxItemActivated())); * * Update the selection: * m_movieRecorderVideoFormatTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const MovieRecorderVideoFormatTypeEnum::Enum VARIABLE = m_movieRecorderVideoFormatTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * @param guiName * User-friendly name for use in user-interface. * @param filenameExtensionNoDot * Extension for file without a dot * @param fileDialogFilter * Filter for use in file dialogs */ MovieRecorderVideoFormatTypeEnum::MovieRecorderVideoFormatTypeEnum(const Enum enumValue, const AString& name, const AString& guiName, const AString& filenameExtensionNoDot, const AString& fileDialogFilter) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; this->filenameExtensionNoDot = filenameExtensionNoDot; this->fileDialogFilter = fileDialogFilter; } /** * Destructor. */ MovieRecorderVideoFormatTypeEnum::~MovieRecorderVideoFormatTypeEnum() { } /** * Initialize the enumerated metadata. */ void MovieRecorderVideoFormatTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(MovieRecorderVideoFormatTypeEnum(AVI, "AVI", "Avi", "avi", "AVI (*.avi)")); enumData.push_back(MovieRecorderVideoFormatTypeEnum(MPEG, "MPEG", "Mpeg", "mpg", "MPEG (*.mpg)")); enumData.push_back(MovieRecorderVideoFormatTypeEnum(MPEG_4, "MPEG_4", "Mpeg 4", "mp4", "MPEG 4 (*.mp4)")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const MovieRecorderVideoFormatTypeEnum* MovieRecorderVideoFormatTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const MovieRecorderVideoFormatTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString MovieRecorderVideoFormatTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const MovieRecorderVideoFormatTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ MovieRecorderVideoFormatTypeEnum::Enum MovieRecorderVideoFormatTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = MovieRecorderVideoFormatTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const MovieRecorderVideoFormatTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type MovieRecorderVideoFormatTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString MovieRecorderVideoFormatTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const MovieRecorderVideoFormatTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ MovieRecorderVideoFormatTypeEnum::Enum MovieRecorderVideoFormatTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = MovieRecorderVideoFormatTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const MovieRecorderVideoFormatTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type MovieRecorderVideoFormatTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t MovieRecorderVideoFormatTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const MovieRecorderVideoFormatTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ MovieRecorderVideoFormatTypeEnum::Enum MovieRecorderVideoFormatTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = MovieRecorderVideoFormatTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const MovieRecorderVideoFormatTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type MovieRecorderVideoFormatTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void MovieRecorderVideoFormatTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void MovieRecorderVideoFormatTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(MovieRecorderVideoFormatTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void MovieRecorderVideoFormatTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(MovieRecorderVideoFormatTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } /** * Get the filename extension for the video format */ AString MovieRecorderVideoFormatTypeEnum::toFileNameExtensionNoDot(Enum enumValue) { if (initializedFlag == false) initialize(); const MovieRecorderVideoFormatTypeEnum* enumInstance = findData(enumValue); return enumInstance->filenameExtensionNoDot; } /** * Get the file dialog filter for the video format */ AString MovieRecorderVideoFormatTypeEnum::toFileDialogFilter(Enum enumValue) { if (initializedFlag == false) initialize(); const MovieRecorderVideoFormatTypeEnum* enumInstance = findData(enumValue); return enumInstance->fileDialogFilter; } connectome-workbench-1.4.2/src/Brain/MovieRecorderVideoFormatTypeEnum.h000066400000000000000000000072221360521144700262250ustar00rootroot00000000000000#ifndef __MOVIE_RECORDER_VIDEO_FORMAT_TYPE_ENUM_H__ #define __MOVIE_RECORDER_VIDEO_FORMAT_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class MovieRecorderVideoFormatTypeEnum { public: /** * Enumerated values. */ enum Enum { /** AVI video */ AVI, /** MPEG */ MPEG, /** MPEG-4 video */ MPEG_4 }; ~MovieRecorderVideoFormatTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); static AString toFileNameExtensionNoDot(Enum enumValue); static AString toFileDialogFilter(Enum enumValue); private: MovieRecorderVideoFormatTypeEnum(const Enum enumValue, const AString& name, const AString& guiName, const AString& filenameExtensionNoDot, const AString& fileDialogFilter); static const MovieRecorderVideoFormatTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; AString filenameExtensionNoDot; AString fileDialogFilter; }; #ifdef __MOVIE_RECORDER_VIDEO_FORMAT_TYPE_ENUM_DECLARE__ std::vector MovieRecorderVideoFormatTypeEnum::enumData; bool MovieRecorderVideoFormatTypeEnum::initializedFlag = false; int32_t MovieRecorderVideoFormatTypeEnum::integerCodeCounter = 0; #endif // __MOVIE_RECORDER_VIDEO_FORMAT_TYPE_ENUM_DECLARE__ } // namespace #endif //__MOVIE_RECORDER_VIDEO_FORMAT_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Brain/MovieRecorderVideoResolutionTypeEnum.cxx000066400000000000000000000321601360521144700275120ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __MOVIE_RECORDER_VIDEO_RESOLUTION_TYPE_ENUM_DECLARE__ #include "MovieRecorderVideoResolutionTypeEnum.h" #undef __MOVIE_RECORDER_VIDEO_RESOLUTION_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::MovieRecorderVideoResolutionTypeEnum * \brief Resolutions for movie recording * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_MovieRecorderVideoResolutionTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void MovieRecorderVideoResolutionTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "MovieRecorderVideoResolutionTypeEnum.h" * * Instatiate: * m_MovieRecorderVideoResolutionTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_MovieRecorderVideoResolutionTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_MovieRecorderVideoResolutionTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(MovieRecorderVideoResolutionTypeEnumComboBoxItemActivated())); * * Update the selection: * m_MovieRecorderVideoResolutionTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const MovieRecorderVideoResolutionTypeEnum::Enum VARIABLE = m_MovieRecorderVideoResolutionTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ MovieRecorderVideoResolutionTypeEnum::MovieRecorderVideoResolutionTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ MovieRecorderVideoResolutionTypeEnum::~MovieRecorderVideoResolutionTypeEnum() { } /** * Initialize the enumerated metadata. */ void MovieRecorderVideoResolutionTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(MovieRecorderVideoResolutionTypeEnum(CUSTOM, "CUSTOM", "Custom")); enumData.push_back(MovieRecorderVideoResolutionTypeEnum(UHD_3840_2160, "UHD_3840_2160", "UHD (3840x2160)")); enumData.push_back(MovieRecorderVideoResolutionTypeEnum(FULL_HD_1920_1080, "FULL_HD_1920_1080", "Full HD (1920x1080)")); enumData.push_back(MovieRecorderVideoResolutionTypeEnum(HD_1280_720, "HD_1280_720", "HD Ready (1280x720)")); enumData.push_back(MovieRecorderVideoResolutionTypeEnum(SD_640_480, "SD_640_480", "SD (640x480)")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const MovieRecorderVideoResolutionTypeEnum* MovieRecorderVideoResolutionTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const MovieRecorderVideoResolutionTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString MovieRecorderVideoResolutionTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const MovieRecorderVideoResolutionTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ MovieRecorderVideoResolutionTypeEnum::Enum MovieRecorderVideoResolutionTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = MovieRecorderVideoResolutionTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const MovieRecorderVideoResolutionTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type MovieRecorderVideoResolutionTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString MovieRecorderVideoResolutionTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const MovieRecorderVideoResolutionTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ MovieRecorderVideoResolutionTypeEnum::Enum MovieRecorderVideoResolutionTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = MovieRecorderVideoResolutionTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const MovieRecorderVideoResolutionTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type MovieRecorderVideoResolutionTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t MovieRecorderVideoResolutionTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const MovieRecorderVideoResolutionTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ MovieRecorderVideoResolutionTypeEnum::Enum MovieRecorderVideoResolutionTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = MovieRecorderVideoResolutionTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const MovieRecorderVideoResolutionTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type MovieRecorderVideoResolutionTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void MovieRecorderVideoResolutionTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void MovieRecorderVideoResolutionTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(MovieRecorderVideoResolutionTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void MovieRecorderVideoResolutionTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(MovieRecorderVideoResolutionTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } /** * Get the width and height for given enumerated value. Output will be zeros * for custom. * * @param enumValue * Enumerated value. * @param widthOut * Output containing width * @param heightOut * Output containing height */ void MovieRecorderVideoResolutionTypeEnum::getWidthAndHeight(const Enum enumValue, int32_t& widthOut, int32_t& heightOut) { switch (enumValue) { case CUSTOM: break; case FULL_HD_1920_1080: widthOut = 1920; heightOut = 1080; break; case HD_1280_720: widthOut = 1280; heightOut = 720; break; case SD_640_480: widthOut = 640; heightOut = 480; break; case UHD_3840_2160: widthOut = 3840; heightOut = 2160; break; } } connectome-workbench-1.4.2/src/Brain/MovieRecorderVideoResolutionTypeEnum.h000066400000000000000000000071131360521144700271370ustar00rootroot00000000000000#ifndef __MOVIE_RECORDER_VIDEO_RESOLUTION_TYPE_ENUM_H__ #define __MOVIE_RECORDER_VIDEO_RESOLUTION_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class MovieRecorderVideoResolutionTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Custom */ CUSTOM, /** UHD */ UHD_3840_2160, /** Full HD */ FULL_HD_1920_1080, /** HD Ready */ HD_1280_720, /** SD */ SD_640_480 }; ~MovieRecorderVideoResolutionTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); static void getWidthAndHeight(const Enum enumValue, int32_t& widthOut, int32_t& heightOut); private: MovieRecorderVideoResolutionTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const MovieRecorderVideoResolutionTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __MOVIE_RECORDER_VIDEO_RESOLUTION_TYPE_ENUM_DECLARE__ std::vector MovieRecorderVideoResolutionTypeEnum::enumData; bool MovieRecorderVideoResolutionTypeEnum::initializedFlag = false; int32_t MovieRecorderVideoResolutionTypeEnum::integerCodeCounter = 0; #endif // __MOVIE_RECORDER_VIDEO_RESOLUTION_TYPE_ENUM_DECLARE__ } // namespace #endif //__MOVIE_RECORDER_VIDEO_RESOLUTION_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Brain/Overlay.cxx000066400000000000000000000700401360521144700216230ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __OVERLAY_DECLARE__ #include "Overlay.h" #undef __OVERLAY_DECLARE__ #include "AnnotationColorBar.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretMappableDataFile.h" #include "CiftiConnectivityMatrixDenseDynamicFile.h" #include "EventCaretMappableDataFilesGet.h" #include "EventManager.h" #include "EventOverlayValidate.h" #include "LabelFile.h" #include "MetricDynamicConnectivityFile.h" #include "MetricFile.h" #include "PlainTextStringBuilder.h" #include "RgbaFile.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "Surface.h" #include "VolumeDynamicConnectivityFile.h" #include "VolumeFile.h" using namespace caret; /** * \class Overlay * \brief An overlay for selection of mappable data. */ /** * Constructor for files in the given structurs and perhaps volume files. * * @param includeSurfaceStructures * Surface structures for files available in this overlay. * @param includeVolumeFiles * Include (or not) volume files. */ Overlay::Overlay(const std::vector& includeSurfaceStructures, const Overlay::IncludeVolumeFiles includeVolumeFiles) : m_includeSurfaceStructures(includeSurfaceStructures), m_includeVolumeFiles(includeVolumeFiles) { m_opacity = 1.0; m_selectedMapFile = NULL; m_selectedMapIndex = -1; m_name = "Overlay "; m_enabled = true; m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; m_wholeBrainVoxelDrawingMode = WholeBrainVoxelDrawingMode::DRAW_VOXELS_ON_TWO_D_SLICES; m_colorBar = new AnnotationColorBar(AnnotationAttributesDefaultTypeEnum::NORMAL); m_colorBar->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_opacity", &m_opacity); m_sceneAssistant->add("m_enabled", &m_enabled); m_sceneAssistant->add("m_wholeBrainVoxelDrawingMode", &m_wholeBrainVoxelDrawingMode); m_sceneAssistant->add("m_mapYokingGroup", &m_mapYokingGroup); m_sceneAssistant->add("m_colorBar", "AnnotationColorBar", m_colorBar); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_OVERLAY_VALIDATE); } /** * Destructor. */ Overlay::~Overlay() { EventManager::get()->removeAllEventsFromListener(this); delete m_colorBar; delete m_sceneAssistant; } /** * Receives events that this object is listening for. * * @param event * An event. */ void Overlay::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_OVERLAY_VALIDATE) { EventOverlayValidate* eov = dynamic_cast(event); CaretAssert(eov); eov->testValidOverlay(this); } } /** * Set the number of this overlay. * * @param overlayIndex * Index for this overlay. */ void Overlay::setOverlayNumber(const int32_t overlayIndex) { m_name = "Overlay " + AString::number(overlayIndex + 1); } /** * Get the opacity. * * @return The opacity. */ float Overlay::getOpacity() const { return m_opacity; } /** * Set the opacity. * * @param opacity * New value for opacity. */ void Overlay::setOpacity(const float opacity) { m_opacity = opacity; } /** * @return The voxel drawing mode for whole brain. */ WholeBrainVoxelDrawingMode::Enum Overlay::getWholeBrainVoxelDrawingMode() const { return m_wholeBrainVoxelDrawingMode; } /** * Set the voxel drawing mode for whole brain. * * @param wholeBrainVoxelDrawingMode * New mode. */ void Overlay::setWholeBrainVoxelDrawingMode(const WholeBrainVoxelDrawingMode::Enum wholeBrainVoxelDrawingMode) { m_wholeBrainVoxelDrawingMode = wholeBrainVoxelDrawingMode; } AString Overlay::getName() const { return m_name; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString Overlay::toString() const { PlainTextStringBuilder tb; getDescriptionOfContent(tb); return tb.getText(); } /** * Get a text description of the window's content. * * @param descriptionOut * Description of the window's content. */ void Overlay::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const { Overlay* me = const_cast(this); if (me != NULL) { if (me->isEnabled()) { CaretMappableDataFile* mapFile = NULL; int32_t mapIndex = 0; me->getSelectionData(mapFile, mapIndex); if (mapFile != NULL) { descriptionOut.addLine("File: "+ mapFile->getFileNameNoPath()); if (mapFile->hasMapAttributes()) { if ((mapIndex >= 0) && (mapIndex < mapFile->getNumberOfMaps())) { descriptionOut.addLine("Map Index: " + AString::number(mapIndex + 1)); descriptionOut.addLine("Map Name: " + mapFile->getMapName(mapIndex)); } } descriptionOut.addLine("Structure: " + StructureEnum::toGuiName(mapFile->getStructure())); } } } } /** * @return Enabled status for this surface overlay. */ bool Overlay::isEnabled() const { return m_enabled; } /** * Set the enabled status for this surface overlay. * @param enabled * New status. */ void Overlay::setEnabled(const bool enabled) { m_enabled = enabled; } /** * Copy the data from the given overlay to this overlay. * @param overlay * Overlay from which data is transferred. */ void Overlay::copyData(const Overlay* overlay) { CaretAssert(overlay); /* * These members are not copied since they * identify the overlay: * name * overlayIndex * */ m_opacity = overlay->m_opacity; m_enabled = overlay->m_enabled; m_selectedMapFile = overlay->m_selectedMapFile; m_selectedMapIndex = overlay->m_selectedMapIndex; m_mapYokingGroup = overlay->m_mapYokingGroup; *m_colorBar = *overlay->m_colorBar; } /** * Swap the data from the given overlay to this overlay. * @param overlay * Overlay from which data is transferred. */ void Overlay::swapData(Overlay* overlay) { Overlay* swapOverlay = new Overlay(m_includeSurfaceStructures, m_includeVolumeFiles); swapOverlay->copyData(overlay); overlay->copyData(this); copyData(swapOverlay); delete swapOverlay; } /** * Return the selection information. This method is typically * called to update the user-interface. * * @param selectedMapFileOut * The selected map file. May be NULL. * @param selectedMapIndexOut * Index of selected map in the selected file. */ void Overlay::getSelectionData(CaretMappableDataFile* &selectedMapFileOut, int32_t& selectedMapIndexOut) { std::vector mapFiles; getSelectionData(mapFiles, selectedMapFileOut, //mapUniqueID, selectedMapIndexOut); } /** * Return the selection information. This method is typically * called to update the user-interface. * * @param mapFilesOut * Contains all map files that can be selected. * @param selectedMapFileOut * The selected map file. May be NULL. * @param selectedMapUniqueIDOut * UniqueID of selected map. * @param selectedMapIndexOut * Index of selected map in the selected file. */ void Overlay::getSelectionData(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, //AString& selectedMapUniqueIDOut, int32_t& selectedMapIndexOut) { mapFilesOut.clear(); selectedMapFileOut = NULL; selectedMapIndexOut = -1; /** * Get the data files. */ std::vector allDataFiles; EventCaretMappableDataFilesGet eventGetMapDataFiles; EventManager::get()->sendEvent(eventGetMapDataFiles.getPointer()); eventGetMapDataFiles.getAllFiles(allDataFiles); bool showVolumeMapFiles = false; switch (m_includeVolumeFiles) { case INCLUDE_VOLUME_FILES_NO: break; case INCLUDE_VOLUME_FILES_YES: showVolumeMapFiles = true; break; } bool showSurfaceMapFiles = false; if ( ! m_includeSurfaceStructures.empty()) { showSurfaceMapFiles = true; } /* * Use only those data files that meet criteria. */ for (std::vector::iterator iter = allDataFiles.begin(); iter != allDataFiles.end(); iter++) { CaretMappableDataFile* mapFile = *iter; bool useIt = false; if (mapFile->isSurfaceMappable()) { if (showSurfaceMapFiles) { for (std::vector::const_iterator iter = m_includeSurfaceStructures.begin(); iter != m_includeSurfaceStructures.end(); iter++) { if (mapFile->isMappableToSurfaceStructure(*iter)) { useIt = true; break; } } } } if (mapFile->isVolumeMappable()) { if (showVolumeMapFiles) { useIt = true; } } if (useIt) { switch (mapFile->getDataFileType()) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: { CiftiConnectivityMatrixDenseDynamicFile* dynConnFile = dynamic_cast(mapFile); CaretAssert(dynConnFile); useIt = dynConnFile->isEnabledAsLayer(); } break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: break; case DataFileTypeEnum::METRIC: break; case DataFileTypeEnum::METRIC_DYNAMIC: { MetricDynamicConnectivityFile* metricDynFile = dynamic_cast(mapFile); CaretAssert(metricDynFile); useIt = metricDynFile->isEnabledAsLayer(); } break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: { VolumeDynamicConnectivityFile* volDynFile = dynamic_cast(mapFile); CaretAssert(volDynFile); useIt = volDynFile->isEnabledAsLayer(); } break; } } if (useIt) { mapFilesOut.push_back(mapFile); } } /* * Does selected data file still no longer exist? */ if (std::find(mapFilesOut.begin(), mapFilesOut.end(), m_selectedMapFile) == mapFilesOut.end()) { /* * Invalidate seleted file and disable yoking since * the selected file will change. */ m_selectedMapFile = NULL; m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; } /* * If selected data file is valid, see if selected * map is still valid. If not, use first map. */ if (m_selectedMapFile != NULL) { if (m_selectedMapIndex >= m_selectedMapFile->getNumberOfMaps()) { m_selectedMapIndex = m_selectedMapFile->getNumberOfMaps() - 1; } if (m_selectedMapIndex < 0) { m_selectedMapIndex = 0; } } else { /* * Use first map in first file that has one or more maps. */ if (m_selectedMapFile == NULL) { if (mapFilesOut.empty() == false) { for (std::vector::iterator iter = mapFilesOut.begin(); iter != mapFilesOut.end(); iter++) { CaretMappableDataFile* mapTypeFile = *iter; if (mapTypeFile->getNumberOfMaps() > 0) { m_selectedMapFile = mapTypeFile; m_selectedMapIndex = 0; } } } } } selectedMapFileOut = m_selectedMapFile; if (selectedMapFileOut != NULL) { // /* // * Update for overlay yoking // */ // if (m_mapYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { // const int32_t yokeMapIndex = MapYokingGroupEnum::getSelectedMapIndex(m_mapYokingGroup); // if ((yokeMapIndex >= 0) // && (yokeMapIndex < selectedMapFileOut->getNumberOfMaps())) { // m_selectedMapIndex = yokeMapIndex; // } // else if (yokeMapIndex >= selectedMapFileOut->getNumberOfMaps()) { // m_selectedMapIndex = selectedMapFileOut->getNumberOfMaps() - 1; // } // } // selectedMapIndexOut = m_selectedMapIndex; //m_selectedMapFile->getMapIndexFromUniqueID(selectedMapUniqueIDOut); } } /** * Set the selected map file and map. * @param selectedMapFile * File that is selected. * @param selectedMapName * Map name that is selected. */ void Overlay::setSelectionData(CaretMappableDataFile* selectedMapFile, const int32_t selectedMapIndex) { m_selectedMapFile = selectedMapFile; m_selectedMapIndex = selectedMapIndex; if (m_mapYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { if (m_selectedMapFile == NULL) { m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; } // if (selectedMapFile != NULL) { // MapYokingGroupEnum::setSelectedMapIndex(m_mapYokingGroup, // selectedMapIndex); // } // else { // m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; // } } } /** * @return Selected map yoking group. */ MapYokingGroupEnum::Enum Overlay::getMapYokingGroup() const { return m_mapYokingGroup; } /** * Set the map yoking group. * * @param mapYokingGroup * New value for map yoking group. */ void Overlay::setMapYokingGroup(const MapYokingGroupEnum::Enum mapYokingGroup) { m_mapYokingGroup = mapYokingGroup; } /** * @return The color bar displayed in graphics window. */ AnnotationColorBar* Overlay::getColorBar() { return m_colorBar; } /** * @return The color bar displayed in graphics window (const method). */ const AnnotationColorBar* Overlay::getColorBar() const { return m_colorBar; } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of the class' instance. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* Overlay::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "Overlay", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); std::vector mapFiles; CaretMappableDataFile* selectedMapFile = NULL; //AString selectedMapUniqueID; int32_t selectedMapIndex; getSelectionData(mapFiles, selectedMapFile, //selectedMapUniqueID, selectedMapIndex); if ((selectedMapFile != NULL) && (selectedMapIndex >= 0)) { sceneClass->addPathName("selectedMapFileNameWithPath", selectedMapFile->getFileName()); sceneClass->addString("selectedMapFile", selectedMapFile->getFileNameNoPath()); sceneClass->addString("selectedMapName", selectedMapFile->getMapName(selectedMapIndex)); sceneClass->addInteger("selectedMapIndex", selectedMapIndex); } else { sceneClass->addPathName("selectedMapFileNameWithPath", ""); sceneClass->addString("selectedMapFile", ""); sceneClass->addString("selectedMapName", ""); sceneClass->addInteger("selectedMapIndex", -1); } return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. May be NULL for some types of scenes. */ void Overlay::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } /* * Making a call to getSelectionData() to get the availble * map files */ std::vector mapFiles; CaretMappableDataFile* unusedSelectedMapFile = NULL; AString unusedSelectedMapUniqueID; int32_t unusedSelectedMapIndex; getSelectionData(mapFiles, unusedSelectedMapFile, //unusedSelectedMapUniqueID, unusedSelectedMapIndex); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); /* * "m_paletteDisplayedFlag" controlled display of palette colorbar * prior to the addition of AnnotationColorBar */ const AString paletteDisplayedFlagString = sceneClass->getStringValue("m_paletteDisplayedFlag"); if ( ! paletteDisplayedFlagString.isEmpty()) { m_colorBar->reset(); m_colorBar->setDisplayed(sceneClass->getBooleanValue("m_paletteDisplayedFlag")); } /* * OverlayYokingGroup was replaced by MapYokingGroup. * If an overlay yoking group is found, convert it to * a map yoking group. */ const AString overlayYokingGroupName = sceneClass->getEnumeratedTypeValueAsString("m_yokingGroup", ""); if ( ! overlayYokingGroupName.isEmpty()) { bool valid = false; const MapYokingGroupEnum::Enum mapGroup = MapYokingGroupEnum::fromOverlayYokingGroupEnumName(overlayYokingGroupName, &valid); if (valid) { m_mapYokingGroup = mapGroup; } } const AString selectedMapFileNameWithPath = sceneClass->getPathNameValue("selectedMapFileNameWithPath"); const AString selectedMapFileName = sceneClass->getStringValue("selectedMapFile", ""); const AString selectedMapUniqueID = sceneClass->getStringValue("selectedMapUniqueID", ""); const AString selectedMapName = sceneClass->getStringValue("selectedMapName", ""); const int32_t selectedMapIndex = sceneClass->getIntegerValue("selectedMapIndex", -1); bool found = false; /* * Is used when the file is found but a map is not matched */ CaretMappableDataFile* matchedMapFile = NULL; /* * First try to find file by filename INCLUDING path and map by unique ID */ /* * Find map by unique ID, map index, and map file */ CaretMappableDataFile* foundUniqueIdMapFile = NULL; int32_t foundUniqueIdMapIndex= -1; CaretMappableDataFile* foundMapNameFile = NULL; int32_t foundMapNameIndex = -1; CaretMappableDataFile* foundMapIndexFile = NULL; int32_t foundMapIndex = -1; /* * Try to match files twice. First time by name with path, then * by name without path. */ for (int iTries = 0; iTries < 2; iTries++) { for (std::vector::iterator iter = mapFiles.begin(); iter != mapFiles.end(); iter++) { CaretMappableDataFile* mapFile = *iter; bool testIt = false; switch (iTries) { case 0: { const AString fileName = mapFile->getFileName(); if (fileName == selectedMapFileNameWithPath) { testIt = true; } } break; case 1: { const AString fileName = mapFile->getFileNameNoPath(); if (fileName == selectedMapFileName) { testIt = true; } } break; } if (testIt) { CaretMappableDataFile* mapFile = *iter; matchedMapFile = mapFile; if (foundUniqueIdMapIndex < 0) { const int uniqueIndex = mapFile->getMapIndexFromUniqueID(selectedMapUniqueID); if (uniqueIndex >= 0) { foundUniqueIdMapFile = mapFile; foundUniqueIdMapIndex = uniqueIndex; } } if (foundMapNameIndex < 0) { if ( ! selectedMapName.isEmpty()) { const int mapNameIndex = mapFile->getMapIndexFromName(selectedMapName); if (mapNameIndex >= 0) { foundMapNameFile = mapFile; foundMapNameIndex = mapNameIndex; } } } if (foundMapIndex < 0) { if (selectedMapIndex >= 0) { if (selectedMapIndex < mapFile->getNumberOfMaps()) { foundMapIndexFile = mapFile; foundMapIndex = selectedMapIndex; } } } } } } if (! found) { if (foundMapIndex >= 0) { if (foundMapIndexFile != NULL) { setSelectionData(foundMapIndexFile, foundMapIndex); found = true; } } } if (! found) { if (foundUniqueIdMapIndex >= 0) { if (foundUniqueIdMapFile != NULL) { setSelectionData(foundUniqueIdMapFile, foundUniqueIdMapIndex); found = true; } } } if (! found) { if (foundMapNameIndex >= 0) { if (foundMapNameFile != NULL) { setSelectionData(foundMapNameFile, foundMapNameIndex); found = true; } } } if (found == false) { /* * If not found by unique ID, try to find map by name */ if (selectedMapName.isEmpty() == false) { for (std::vector::iterator iter = mapFiles.begin(); iter != mapFiles.end(); iter++) { CaretMappableDataFile* mapFile = *iter; const AString fileName = mapFile->getFileNameNoPath(); if (fileName == selectedMapFileName) { CaretMappableDataFile* mapFile = *iter; matchedMapFile = mapFile; const int32_t mapIndex = mapFile->getMapIndexFromName(selectedMapName); if (mapIndex >= 0) { setSelectionData(mapFile, mapIndex); found = true; break; } } } } } /* * If file found but not matching map, use first map from the file. * This may occur when the map does not have a name. */ if (found == false) { if (matchedMapFile != NULL) { if (matchedMapFile->getNumberOfMaps() > 0) { setSelectionData(matchedMapFile, 0); } } } } connectome-workbench-1.4.2/src/Brain/Overlay.h000066400000000000000000000121601360521144700212470ustar00rootroot00000000000000#ifndef __OVERLAY__H_ #define __OVERLAY__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "DataFileTypeEnum.h" #include "EventListenerInterface.h" #include "MapYokingGroupEnum.h" #include "PlainTextStringBuilder.h" #include "SceneableInterface.h" #include "WholeBrainVoxelDrawingMode.h" #include "StructureEnum.h" namespace caret { class AnnotationColorBar; class CaretMappableDataFile; class SceneClassAssistant; class Overlay : public CaretObject, public EventListenerInterface, public SceneableInterface { public: enum IncludeVolumeFiles { INCLUDE_VOLUME_FILES_YES, INCLUDE_VOLUME_FILES_NO }; Overlay(const std::vector& includeSurfaceStructures, const Overlay::IncludeVolumeFiles includeVolumeFiles); virtual ~Overlay(); virtual void receiveEvent(Event* event); float getOpacity() const; void setOpacity(const float opacity); AString getName() const; void setOverlayNumber(const int32_t overlayIndex); virtual AString toString() const; virtual void getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const; bool isEnabled() const; void setEnabled(const bool enabled); WholeBrainVoxelDrawingMode::Enum getWholeBrainVoxelDrawingMode() const; void setWholeBrainVoxelDrawingMode(const WholeBrainVoxelDrawingMode::Enum wholeBrainVoxelDrawingMode); void copyData(const Overlay* overlay); void swapData(Overlay* overlay); void getSelectionData(std::vector& mapFilesOut, CaretMappableDataFile* &selectedMapFileOut, int32_t& selectedMapIndexOut); void getSelectionData(CaretMappableDataFile* &selectedMapFileOut, int32_t& selectedMapIndexOut); void setSelectionData(CaretMappableDataFile* selectedMapFile, const int32_t selectedMapIndex); MapYokingGroupEnum::Enum getMapYokingGroup() const; void setMapYokingGroup(const MapYokingGroupEnum::Enum mapYokingGroup); AnnotationColorBar* getColorBar(); const AnnotationColorBar* getColorBar() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: Overlay(const Overlay&); Overlay& operator=(const Overlay&); /** Surface structures of data files displayed in this overlay */ const std::vector m_includeSurfaceStructures; /** Include volume files in this overlay */ const IncludeVolumeFiles m_includeVolumeFiles; /** Name of overlay (DO NOT COPY)*/ AString m_name; /** Index of this overlay (DO NOT COPY)*/ int32_t m_overlayIndex; /** opacity for overlay */ float m_opacity; /** enabled status */ mutable bool m_enabled; /** map yoking group */ MapYokingGroupEnum::Enum m_mapYokingGroup; /** available mappable files */ //std::vector m_mapFiles; /** selected mappable file */ CaretMappableDataFile* m_selectedMapFile; /** selected map index */ int32_t m_selectedMapIndex; /** selected data file map unique id */ //AString m_selectedMapUniqueID; /** Voxel drawing mode in Whole Brain View */ WholeBrainVoxelDrawingMode::Enum m_wholeBrainVoxelDrawingMode; /** The color bar displayed in the graphics window */ AnnotationColorBar* m_colorBar; /** helps with scene save/restore */ SceneClassAssistant* m_sceneAssistant; }; #ifdef __OVERLAY_DECLARE__ #endif // __OVERLAY_DECLARE__ } // namespace #endif //__OVERLAY__H_ connectome-workbench-1.4.2/src/Brain/OverlaySet.cxx000066400000000000000000001402601360521144700223010ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #define __OVERLAY_SET_DECLARE__ #include "OverlaySet.h" #undef __OVERLAY_SET_DECLARE__ #include "BrainStructure.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretMappableDataFile.h" #include "CiftiBrainordinateLabelFile.h" #include "CiftiBrainordinateScalarFile.h" #include "EventCaretMappableDataFilesGet.h" #include "EventManager.h" #include "EventMapYokingSelectMap.h" #include "EventMapYokingValidation.h" #include "LabelFile.h" #include "MetricFile.h" #include "ModelSurfaceMontage.h" #include "ModelVolume.h" #include "ModelWholeBrain.h" #include "Overlay.h" #include "PlainTextStringBuilder.h" #include "Scene.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneClassAssistant.h" #include "Surface.h" #include "VolumeFile.h" using namespace caret; /** * \class OverlaySet * \brief Contains a set of overlay assignments * * The maximum number of overlays is fixed. The number * of overlays presented to the user varies and is * controlled using the ToolBox in a Browser Window. * * The primary overlay is always the overlay at index zero. * The underlay is the overlay at (numberOfDisplayedOverlays - 1). * When models are colored, the overlays are assigned * starting with the underlay and concluding with the primary * overlay. */ /** * \class OverlaySet * \brief Contains a set of overlay assignments * * The maximum number of overlays is fixed. The number * of overlays presented to the user varies and is * controlled using the ToolBox in a Browser Window. * * The primary overlay is always the overlay at index zero. * The underlay is the overlay at (numberOfDisplayedOverlays - 1). * When models are colored, the overlays are assigned * starting with the underlay and concluding with the primary * overlay. */ /** * Constructor for the given surface structures, surface types, and volumes. * * @param name * Name for this overlay set * @param tabIndex * Index of tab for this overlay set. * @param includeSurfaceStructures * Surface structures for data files displayed in this overlay set. * @param includeVolumeFiles * Surface structures for data files displayed in this overlay set. */ OverlaySet::OverlaySet(const AString& name, const int32_t tabIndex, const std::vector& includeSurfaceStructures, const Overlay::IncludeVolumeFiles includeVolumeFiles) : CaretObject(), m_name(name), m_tabIndex(tabIndex), m_includeSurfaceStructures(includeSurfaceStructures), m_includeVolumeFiles(includeVolumeFiles) { m_numberOfDisplayedOverlays = BrainConstants::MINIMUM_NUMBER_OF_OVERLAYS; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_numberOfDisplayedOverlays", &m_numberOfDisplayedOverlays); for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { m_overlays[i] = new Overlay(includeSurfaceStructures, includeVolumeFiles); } EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_VALIDATION); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP); } /** * Destructor. */ OverlaySet::~OverlaySet() { EventManager::get()->removeAllEventsFromListener(this); for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { delete m_overlays[i]; } delete m_sceneAssistant; } /** * Copy the given overlay set to this overlay set. * @param overlaySet * Overlay set that is copied. */ void OverlaySet::copyOverlaySet(const OverlaySet* overlaySet) { for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { m_overlays[i]->copyData(overlaySet->getOverlay(i)); } m_numberOfDisplayedOverlays = overlaySet->m_numberOfDisplayedOverlays; } /** * @return Returns the top-most overlay regardless of its enabled status. */ Overlay* OverlaySet::getPrimaryOverlay() { return m_overlays[0]; } /** * @return Returns the underlay which is the lowest * displayed overlay. */ Overlay* OverlaySet::getUnderlay() { return m_overlays[getNumberOfDisplayedOverlays() - 1]; } /* * Get the bottom-most overlay that is a volume file for the given * browser tab. * @param browserTabContent * Content of browser tab. * @return Returns the bottom-most overlay that is set a a volume file. * Will return NULL if no, enabled overlays are set to a volume file. */ Overlay* OverlaySet::getUnderlayContainingVolume() { Overlay* underlayOut(NULL); const int32_t numOverlays = getNumberOfDisplayedOverlays(); for (int32_t i = (numOverlays - 1); i >= 0; i--) { if (m_overlays[i]->isEnabled()) { CaretMappableDataFile* mapFile = NULL; int32_t mapIndex; CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, i); m_overlays[i]->getSelectionData(mapFile, mapIndex); if (mapFile != NULL) { if (mapFile->isVolumeMappable()) { const VolumeMappableInterface* vf = dynamic_cast(mapFile); if (vf != NULL) { underlayOut = m_overlays[i]; break; } } } } } if (underlayOut == NULL) { /* * If we are here, either there are no volume files or * no overlays are enabled containing a volume file. * So, find the lowest layer than contains a volume file, * even if the layer is disabled. */ for (int32_t i = 0; i < numOverlays; i++) { CaretMappableDataFile* mapFile = NULL; int32_t mapIndex; CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, i); m_overlays[i]->getSelectionData(mapFile, mapIndex); if (mapFile != NULL) { if (mapFile->isVolumeMappable()) { const VolumeMappableInterface* vf = dynamic_cast(mapFile); if (vf != NULL) { underlayOut = m_overlays[i]; break; } } } } } return underlayOut; } /* * Get the bottom-most overlay that is a volume file for the given * browser tab and return its volume file. * @param browserTabContent * Content of browser tab. * @return Returns the bottom-most overlay that is set a a volume file. * Will return NULL if no, enabled overlays are set to a volume file. */ VolumeMappableInterface* OverlaySet::getUnderlayVolume() { VolumeMappableInterface* vf = NULL; Overlay* underlay = getUnderlayContainingVolume(); if (underlay != NULL) { CaretMappableDataFile* mapFile = NULL; int32_t mapIndex; underlay->getSelectionData(mapFile, mapIndex); if (mapFile != NULL) { vf = dynamic_cast(mapFile); } } return vf; } /** * If NO overlay (any overlay) is set to a volume, set the underlay to the first * volume that it finds. * @return Returns the volume file that was selected or NULL if no * volume file was found. */ VolumeMappableInterface* OverlaySet::setUnderlayToVolume() { VolumeMappableInterface * vf = getUnderlayVolume(); if (vf == NULL) { const int32_t overlayIndex = getNumberOfDisplayedOverlays() - 1; if (overlayIndex >= 0) { std::vector mapFiles; CaretMappableDataFile* mapFile; //AString mapUniqueID; int32_t mapIndex; m_overlays[overlayIndex]->getSelectionData(mapFiles, mapFile, //mapUniqueID, mapIndex); const int32_t numMapFiles = static_cast(mapFiles.size()); for (int32_t i = 0; i < numMapFiles; i++) { if (mapFiles[i]->isVolumeMappable()) { vf = dynamic_cast(mapFiles[i]); if (vf != NULL) { CaretMappableDataFile* cmdf = dynamic_cast(vf); CaretAssert(cmdf); m_overlays[overlayIndex]->setSelectionData(cmdf, 0); break; } } } } } return vf; } /** * Get the overlay at the specified index. * @param overlayNumber * Index of the overlay. * @return Overlay at the given index. */ const Overlay* OverlaySet::getOverlay(const int32_t overlayNumber) const { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, overlayNumber); return m_overlays[overlayNumber]; } /** * Get the overlay at the specified index. * @param overlayNumber * Index of the overlay. * @return Overlay at the given index. */ Overlay* OverlaySet::getOverlay(const int32_t overlayNumber) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, overlayNumber); return m_overlays[overlayNumber]; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString OverlaySet::toString() const { PlainTextStringBuilder tb; getDescriptionOfContent(tb); return tb.getText(); } /** * Get a text description of the window's content. * * @param descriptionOut * Description of the window's content. */ void OverlaySet::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const { descriptionOut.addLine("Overlay Set"); const int numOverlays = getNumberOfDisplayedOverlays(); for (int32_t i = 0; i < numOverlays; i++) { if (getOverlay(i)->isEnabled()) { descriptionOut.pushIndentation(); descriptionOut.addLine("Overlay " + AString::number(i + 1) + ": "); descriptionOut.pushIndentation(); getOverlay(i)->getDescriptionOfContent(descriptionOut); descriptionOut.popIndentation(); descriptionOut.popIndentation(); } } } /** * Add a displayed overlay. If the maximum * number of surface overlays is reached, * this method has no effect. */ void OverlaySet::addDisplayedOverlay() { m_numberOfDisplayedOverlays++; if (m_numberOfDisplayedOverlays > BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS) { m_numberOfDisplayedOverlays = BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; } } /** * @return Returns the number of displayed overlays. */ int32_t OverlaySet::getNumberOfDisplayedOverlays() const { return m_numberOfDisplayedOverlays; } /** * Sets the number of displayed overlays. * @param numberOfDisplayedOverlays * Number of overlays for display. */ void OverlaySet::setNumberOfDisplayedOverlays(const int32_t numberOfDisplayedOverlays) { const int32_t oldNumberOfDisplayedOverlays = m_numberOfDisplayedOverlays; m_numberOfDisplayedOverlays = numberOfDisplayedOverlays; if (m_numberOfDisplayedOverlays < BrainConstants::MINIMUM_NUMBER_OF_OVERLAYS) { m_numberOfDisplayedOverlays = BrainConstants::MINIMUM_NUMBER_OF_OVERLAYS; } if (m_numberOfDisplayedOverlays > BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS) { m_numberOfDisplayedOverlays = BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; } /* * If one overlay added (probably through GUI), * shift all overlays down one position so that * new overlay appears at the top */ const int32_t numberOfOverlaysAdded = m_numberOfDisplayedOverlays - oldNumberOfDisplayedOverlays; if (numberOfOverlaysAdded == 1) { for (int32_t i = (m_numberOfDisplayedOverlays - 1); i >= 0; i--) { moveDisplayedOverlayDown(i); } } } /** * Insert an overlay below this overlay * @param overlayIndex * Index of overlay for which an overlay is added below */ void OverlaySet::insertOverlayAbove(const int32_t overlayIndex) { if (m_numberOfDisplayedOverlays < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS) { m_numberOfDisplayedOverlays++; for (int32_t i = (m_numberOfDisplayedOverlays - 2); i >= overlayIndex; i--) { moveDisplayedOverlayDown(i); } } } /** * Insert an overlay above this overlay * @param overlayIndex * Index of overlay for which an overlay is added above */ void OverlaySet::insertOverlayBelow(const int32_t overlayIndex) { if (m_numberOfDisplayedOverlays < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS) { m_numberOfDisplayedOverlays++; for (int32_t i = (m_numberOfDisplayedOverlays - 2); i > overlayIndex; i--) { moveDisplayedOverlayDown(i); } } } /** * Remove a displayed overlay. This method will have * no effect if the minimum number of overlays are * displayed * * @param overlayIndex * Index of overlay for removal from display. */ void OverlaySet::removeDisplayedOverlay(const int32_t overlayIndex) { CaretAssertArrayIndex(m_overlays, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS, overlayIndex); m_overlays[overlayIndex]->setMapYokingGroup(MapYokingGroupEnum::MAP_YOKING_GROUP_OFF); if (m_numberOfDisplayedOverlays > BrainConstants::MINIMUM_NUMBER_OF_OVERLAYS) { m_numberOfDisplayedOverlays--; for (int32_t i = overlayIndex; i < m_numberOfDisplayedOverlays; i++) { m_overlays[i]->copyData(m_overlays[i+1]); } } } /** * Move the overlay at the given index up one level * (swap it with overlayIndex - 1). This method will * have no effect if the overlay is the top-most overlay. * * @param overlayIndex * Index of overlay that is to be moved up. */ void OverlaySet::moveDisplayedOverlayUp(const int32_t overlayIndex) { if (overlayIndex > 0) { m_overlays[overlayIndex]->swapData(m_overlays[overlayIndex - 1]); } } /** * Move the overlay at the given index down one level * (swap it with overlayIndex + 1). This method will * have no effect if the overlay is the bottom-most overlay. * * @param overlayIndex * Index of overlay that is to be moved down. */ void OverlaySet::moveDisplayedOverlayDown(const int32_t overlayIndex) { const int32_t nextOverlayIndex = overlayIndex + 1; if (nextOverlayIndex < m_numberOfDisplayedOverlays) { m_overlays[overlayIndex]->swapData(m_overlays[nextOverlayIndex]); } } /** * Match the desired names to maps (or file if no maps match) and optionally * structure to files/maps and return the matches. * * Note: If there are NO match names, all files are matched using the first * map in each file. * * @param matchedFilesOut * Output to which matched files are APPENDED. * @param matchedFileIndicesOut * Output to which matched file indices are APPENDED. * @param matchToStructures * If not empty, only include files that map to these structures. If * matchToVolumeData is true, this parameter is ignored. If this is (empty * OR All) AND matchToVolumeData is false, all structures match. * @param dataFileType * Data file type of desired files. * @param matchToVolumeData * Include only files that map to volume data. If true, matchToStructures * is ignored. * @param matchToNamesRegularExpressionText * Text for regular expression used for name matching. * @param matchToNamesRegularExpressionResult * Status of regular expression matching for inclusion of file. * @param matchOneFilePerStructure * If true, limit matched files so there is no more than one file * for each structure. * @param * True if matching files were found, else false. */ bool OverlaySet::findFilesWithMapNamed(std::vector& matchedFilesOut, std::vector& matchedFileIndicesOut, const std::vector& matchToStructures, const DataFileTypeEnum::Enum dataFileType, const bool matchToVolumeData, const AString& matchToNamesRegularExpressionText, const bool matchToNamesRegularExpressionResult, const bool matchOneFilePerStructure) { std::vector matchedFiles; std::vector matchedFileIndices; /* * Aggregate matching names and make them lower case */ QRegExp regularExpression; if (matchToNamesRegularExpressionText.isEmpty() == false) { regularExpression = QRegExp(matchToNamesRegularExpressionText); } /* * Get files matching data type */ EventCaretMappableDataFilesGet mapFileGetEvent(dataFileType); EventManager::get()->sendEvent(mapFileGetEvent.getPointer()); std::vector matchToMapFiles; mapFileGetEvent.getAllFiles(matchToMapFiles); const int32_t numberOfMatchFiles = static_cast(matchToMapFiles.size()); if (numberOfMatchFiles <= 0) { return false; } /* * Determine which files should be tested by examing * structure or if volume */ std::vector testMapFiles; for (int32_t iFile = 0; iFile < numberOfMatchFiles; iFile++) { bool fileMatchFlag = false; CaretMappableDataFile* mapFile = matchToMapFiles[iFile]; /* * Volume mappable files only? */ if (matchToVolumeData) { if (mapFile->isVolumeMappable()) { fileMatchFlag = true; } } /* * Test structures? */ if (matchToStructures.empty() == false) { const StructureEnum::Enum mapFileStructure = mapFile->getStructure(); /* * File maps to ALL structures? */ if (mapFileStructure == StructureEnum::ALL) { fileMatchFlag = true; } else { /* * Specific structutures */ if (std::find(matchToStructures.begin(), matchToStructures.end(), mapFileStructure) != matchToStructures.end()) { fileMatchFlag = true; } } } if (fileMatchFlag) { if (mapFile->getNumberOfMaps() > 0) { testMapFiles.push_back(mapFile); } } } /* * No files to test? */ const int32_t numTestFiles = static_cast(testMapFiles.size()); if (numTestFiles <= 0) { return false; } std::set matchedStructures; /* * If there are names to match */ if (matchToNamesRegularExpressionText.isEmpty() == false) { /* * First preference is matching MAP name */ for (int32_t iFile = 0; iFile < numTestFiles; iFile++) { CaretMappableDataFile* mapFile = testMapFiles[iFile]; const StructureEnum::Enum mapFileStructure = mapFile->getStructure(); if (matchOneFilePerStructure) { if (matchedStructures.find(mapFileStructure) != matchedStructures.end()) { continue; } } /* * If NOT matching, exclude files whose name matches */ if (matchToNamesRegularExpressionResult == false) { const AString fileName = mapFile->getFileNameNoPath().toLower(); const bool fileNameMatch = (regularExpression.indexIn(fileName) >= 0); if (fileNameMatch) { continue; } } const int32_t numMaps = mapFile->getNumberOfMaps(); for (int32_t iMap = 0; iMap < numMaps; iMap++) { const AString mapName = mapFile->getMapName(iMap).toLower(); const bool match = (regularExpression.indexIn(mapName) >= 0); if (match == matchToNamesRegularExpressionResult) { matchedFiles.push_back(mapFile); matchedFileIndices.push_back(iMap); matchedStructures.insert(mapFileStructure); break; } } } /* * Find matching FILE name if NO map matches */ if (matchedFiles.empty()) { for (int32_t iFile = 0; iFile < numTestFiles; iFile++) { CaretMappableDataFile* mapFile = testMapFiles[iFile]; const StructureEnum::Enum mapFileStructure = mapFile->getStructure(); if (matchOneFilePerStructure) { if (matchedStructures.find(mapFileStructure) != matchedStructures.end()) { continue; } } const AString fileName = mapFile->getFileNameNoPath().toLower(); const bool match = (regularExpression.indexIn(fileName) >= 0); if (match == matchToNamesRegularExpressionResult) { matchedFiles.push_back(mapFile); matchedFileIndices.push_back(0); matchedStructures.insert(mapFileStructure); } } } } else { /* * No names to match so just match to first map in each file */ for (int32_t iFile = 0; iFile < numTestFiles; iFile++) { CaretMappableDataFile* mapFile = testMapFiles[iFile]; const StructureEnum::Enum mapFileStructure = mapFile->getStructure(); if (matchOneFilePerStructure) { if (matchedStructures.find(mapFileStructure) != matchedStructures.end()) { continue; } } matchedFiles.push_back(mapFile); matchedFileIndices.push_back(0); matchedStructures.insert(mapFileStructure); } } CaretAssert(matchedFiles.size() == matchedFileIndices.size()); const bool filesFound = (matchedFiles.empty() == false); /* * APPEND to output, do not replace */ matchedFilesOut.insert(matchedFilesOut.end(), matchedFiles.begin(), matchedFiles.end()); matchedFileIndicesOut.insert(matchedFileIndicesOut.end(), matchedFileIndices.begin(), matchedFileIndices.end()); return filesFound; } /** * Find underlay files. * * @param matchToStructures * Structures to include. * @param includeVolumeFiles * Include volume files. * @param filesOut * Output containing files that were selected. * @param mapIndicesOut * Output containing maps indices in files that were selected. */ void OverlaySet::findUnderlayFiles( const std::vector& matchToStructures, const bool includeVolumeFiles, std::vector& filesOut, std::vector& mapIndicesOut) { /* * First, try to find CIFTI shape files */ if (findFilesWithMapNamed(filesOut, mapIndicesOut, matchToStructures, DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR, false, s_shapeMatchRegularExpressionText, true, true) == false) { /* * Second, try to find METRIC shape files */ findFilesWithMapNamed(filesOut, mapIndicesOut, matchToStructures, DataFileTypeEnum::METRIC, false, s_shapeMatchRegularExpressionText, true, true); } if (includeVolumeFiles) { std::vector volumeFiles = getVolumeFiles(); const int32_t numVolumes = static_cast(volumeFiles.size()); if (numVolumes > 0) { bool foundAnatomyVolume = false; for (int32_t i = 0; i < numVolumes; i++) { VolumeFile* vf = volumeFiles[i]; if (vf->getType() == SubvolumeAttributes::ANATOMY) { if (vf->getNumberOfMaps() > 0) { filesOut.push_back(vf); mapIndicesOut.push_back(0); foundAnatomyVolume = true; break; } } } if (foundAnatomyVolume == false) { for (int32_t i = 0; i < numVolumes; i++) { VolumeFile* vf = volumeFiles[i]; bool testIt = true; if (vf->getType() == SubvolumeAttributes::LABEL) { testIt = false; } if (testIt) { if (vf->getNumberOfMaps() > 0) { PaletteColorMapping* pcm = vf->getMapPaletteColorMapping(0); if (pcm != NULL) { const AString paletteName = pcm->getSelectedPaletteName(); if (paletteName.contains("gray") || paletteName.contains("grey")) { filesOut.push_back(vf); mapIndicesOut.push_back(0); foundAnatomyVolume = true; break; } } } } } } } } CaretAssert(filesOut.size() == mapIndicesOut.size()); } /** * @return All volume files. */ std::vector OverlaySet::getVolumeFiles() const { std::vector volumeFiles; EventCaretMappableDataFilesGet mapFileGetEvent(DataFileTypeEnum::VOLUME); EventManager::get()->sendEvent(mapFileGetEvent.getPointer()); std::vector matchToMapFiles; mapFileGetEvent.getAllFiles(matchToMapFiles); for (std::vector::iterator iter = matchToMapFiles.begin(); iter != matchToMapFiles.end(); iter++) { VolumeFile* vf = dynamic_cast(*iter); CaretAssert(vf); volumeFiles.push_back(vf); } return volumeFiles; } /** * Find middle layer files. * * @param matchToStructures * Structures to include. * @param includeVolumeFiles * Include volume files. * @param filesOut * Output containing files that were selected. * @param mapIndicesOut * Output containing maps indices in files that were selected. */ void OverlaySet::findMiddleLayerFiles(const std::vector& matchToStructures, const bool includeVolumeFiles, std::vector& filesOut, std::vector& mapIndicesOut) { std::vector matchToNames; /* * First, try to find CIFTI scalar files with myelin */ if (findFilesWithMapNamed(filesOut, mapIndicesOut, matchToStructures, DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR, includeVolumeFiles, s_myelinMatchRegularExpressionText, true, false) == false) { /* * Second, try to find METRIC files with neither shape nor myelin */ findFilesWithMapNamed(filesOut, mapIndicesOut, matchToStructures, DataFileTypeEnum::METRIC, includeVolumeFiles, s_myelinMatchRegularExpressionText, true, false); } /* * Second, try to find CIFTI scalar files with neither shape nor myelin */ if (findFilesWithMapNamed(filesOut, mapIndicesOut, matchToStructures, DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR, includeVolumeFiles, s_shapeMyelinMatchRegularExpressionText, false, false) == false) { /* * Second, try to find METRIC files with neither shape nor myelin */ findFilesWithMapNamed(filesOut, mapIndicesOut, matchToStructures, DataFileTypeEnum::METRIC, includeVolumeFiles, s_shapeMyelinMatchRegularExpressionText, false, false); } if (includeVolumeFiles) { std::vector volumeFiles = getVolumeFiles(); const int32_t numVolumes = static_cast(volumeFiles.size()); for (int32_t i = 0; i < numVolumes; i++) { VolumeFile* vf = volumeFiles[i]; if ((vf->getType() == SubvolumeAttributes::FUNCTIONAL)) { if (vf->getNumberOfMaps() > 0) { filesOut.push_back(vf); mapIndicesOut.push_back(0); break; } } } } CaretAssert(filesOut.size() == mapIndicesOut.size()); } /** * Find overlay files. * * @param matchToStructures * Structures to include. * @param includeVolumeFiles * Include volume files. * @param filesOut * Output containing files that were selected. * @param mapIndicesOut * Output containing maps indices in files that were selected. */ void OverlaySet::findOverlayFiles(const std::vector& matchToStructures, const bool includeVolumeFiles, std::vector& filesOut, std::vector& mapIndicesOut) { /* * First, try to find CIFTI LABEL files */ if (findFilesWithMapNamed(filesOut, mapIndicesOut, matchToStructures, DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL, includeVolumeFiles, "", true, true) == false) { /* * Second, try to find LABEL files */ findFilesWithMapNamed(filesOut, mapIndicesOut, matchToStructures, DataFileTypeEnum::LABEL, includeVolumeFiles, "", true, true); } if (includeVolumeFiles) { std::vector volumeFiles = getVolumeFiles(); const int32_t numVolumes = static_cast(volumeFiles.size()); for (int32_t i = 0; i < numVolumes; i++) { VolumeFile* vf = volumeFiles[i]; if (vf->getType() == SubvolumeAttributes::LABEL) { if (vf->getNumberOfMaps() > 0) { filesOut.push_back(vf); mapIndicesOut.push_back(0); break; } } } } CaretAssert(filesOut.size() == mapIndicesOut.size()); } /** * Initialize the overlays. */ void OverlaySet::initializeOverlays() { bool isMatchToVolumeUnderlay = false; bool isMatchToVolumeOverlays = false; switch (m_includeVolumeFiles) { case Overlay::INCLUDE_VOLUME_FILES_NO: break; case Overlay::INCLUDE_VOLUME_FILES_YES: /* * If no surface structures, then it must be volume slice view * so allow volumes to be in the overlays. */ if (m_includeSurfaceStructures.empty()) { isMatchToVolumeOverlays = true; } isMatchToVolumeUnderlay = true; break; } /* * Underlays consist of anatomical type data */ std::vector underlayMapFiles; std::vector underlayMapIndices; findUnderlayFiles(m_includeSurfaceStructures, isMatchToVolumeUnderlay, underlayMapFiles, underlayMapIndices); /* * Middle layers are Cifti labels or Gifti Labels * that do not contain shape data */ std::vector middleLayerMapFiles; std::vector middleLayerMapIndices; findMiddleLayerFiles(m_includeSurfaceStructures, isMatchToVolumeOverlays, middleLayerMapFiles, middleLayerMapIndices); /* * Overlays consist of Cifti scalars or Gifti Metric */ std::vector overlayMapFiles; std::vector overlayMapIndices; findOverlayFiles(m_includeSurfaceStructures, isMatchToVolumeOverlays, overlayMapFiles, overlayMapIndices); const int32_t numberOfUnderlayFiles = static_cast(underlayMapFiles.size()); /* * Number of overlay that are displayed. */ const int32_t numberOfDisplayedOverlays = getNumberOfDisplayedOverlays(); /* * Track overlay that were initialized */ std::vector overlayInitializedFlag(numberOfDisplayedOverlays, false); /* * Put in the shape files at the bottom * Note that highest overlay index is bottom */ int32_t overlayIndexForUnderlay = (numberOfDisplayedOverlays - 1); for (int32_t underlayFileIndex = 0; underlayFileIndex < numberOfUnderlayFiles; underlayFileIndex++) { if (overlayIndexForUnderlay >= 0) { Overlay* overlay = getOverlay(overlayIndexForUnderlay); overlay->setSelectionData(underlayMapFiles[underlayFileIndex], underlayMapIndices[underlayFileIndex]); overlayInitializedFlag[overlayIndexForUnderlay] = true; overlayIndexForUnderlay--; } else { break; } } /* * Combine overlay and middle layer files */ std::vector upperLayerFiles; std::vector upperLayerIndices; upperLayerFiles.insert(upperLayerFiles.end(), overlayMapFiles.begin(), overlayMapFiles.end()); upperLayerIndices.insert(upperLayerIndices.end(), overlayMapIndices.begin(), overlayMapIndices.end()); upperLayerFiles.insert(upperLayerFiles.end(), middleLayerMapFiles.begin(), middleLayerMapFiles.end()); upperLayerIndices.insert(upperLayerIndices.end(), middleLayerMapIndices.begin(), middleLayerMapIndices.end()); CaretAssert(upperLayerFiles.size() == upperLayerIndices.size()); const int32_t numberOfUpperFiles = static_cast(upperLayerFiles.size()); /* * Put in overlay and middle layer files */ for (int32_t upperFileIndex = 0; upperFileIndex < numberOfUpperFiles; upperFileIndex++) { /* * Find available overlay */ int32_t upperLayerOverlayIndex = -1; for (int32_t overlayIndex = 0; overlayIndex < numberOfDisplayedOverlays; overlayIndex++) { if (overlayInitializedFlag[overlayIndex] == false) { upperLayerOverlayIndex = overlayIndex; break; } } if (upperLayerOverlayIndex >= 0) { Overlay* upperLayerOverlay = getOverlay(upperLayerOverlayIndex); upperLayerOverlay->setSelectionData(upperLayerFiles[upperFileIndex], upperLayerIndices[upperFileIndex]); overlayInitializedFlag[upperLayerOverlayIndex] = true; } else { break; } } /* * Disable overlays that were not initialized */ for (int32_t i = 0; i < numberOfDisplayedOverlays; i++) { CaretAssertVectorIndex(overlayInitializedFlag, i); getOverlay(i)->setEnabled(overlayInitializedFlag[i]); } } /** * Get any label files that are selected and applicable for the given surface. * @param surface * Surface for which label files are desired. * @param labelFilesOut * Label files that are applicable to the given surface. * @param labelMapIndicesOut * Selected map indices in the output label files. */ void OverlaySet::getLabelFilesForSurface(const Surface* surface, std::vector& labelFilesOut, std::vector& labelMapIndicesOut) { CaretAssert(surface); labelFilesOut.clear(); labelMapIndicesOut.clear(); const int32_t numberOfOverlays = getNumberOfDisplayedOverlays(); for (int32_t i = 0; i < numberOfOverlays; i++) { Overlay* overlay = getOverlay(i); if (overlay->isEnabled()) { CaretMappableDataFile* mapFile; int32_t mapIndex; overlay->getSelectionData(mapFile, mapIndex); if (mapFile != NULL) { if (mapFile->getDataFileType() == DataFileTypeEnum::LABEL) { if (mapFile->getStructure() == surface->getStructure()) { LabelFile* labelFile = dynamic_cast(mapFile); labelFilesOut.push_back(labelFile); labelMapIndicesOut.push_back(mapIndex); } } } } } } /** * For the given caret mappable data file, find overlays in which the * file is selected and return the indices of the selected maps. * * @param caretMappableDataFile * The caret mappable data file. * @param isLimitToEnabledOverlays * If true, only include map indices for overlay that are enabled. * Otherwise, include map indices for all overlays. * @param selectedMapIndicesOut * Output containing map indices for the given caret mappable data files * that are selected as overlays in this overlay set. */ void OverlaySet::getSelectedMapIndicesForFile(const CaretMappableDataFile* caretMappableDataFile, const bool isLimitToEnabledOverlays, std::vector& selectedMapIndicesOut) const { selectedMapIndicesOut.clear(); /* * Put indices in a set to avoid duplicates and keep them sorted. */ std::set mapIndicesSet; const int32_t numberOfOverlays = getNumberOfDisplayedOverlays(); for (int32_t i = 0; i < numberOfOverlays; i++) { Overlay* overlay = const_cast(getOverlay(i)); bool checkIt = true; if (isLimitToEnabledOverlays) { if (overlay->isEnabled() == false) { checkIt = false; } } if (checkIt) { CaretMappableDataFile* mapFile; int32_t mapIndex; overlay->getSelectionData(mapFile, mapIndex); if (mapFile == caretMappableDataFile) { mapIndicesSet.insert(mapIndex); } } } selectedMapIndicesOut.insert(selectedMapIndicesOut.end(), mapIndicesSet.begin(), mapIndicesSet.end()); } /** * Reset the yoking status of all overlays to off. */ void OverlaySet::resetOverlayYokingToOff() { for (int i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { m_overlays[i]->setMapYokingGroup(MapYokingGroupEnum::MAP_YOKING_GROUP_OFF); } } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of the class' instance. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* OverlaySet::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "OverlaySet", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); // const int32_t numOverlaysToSave = BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; const int32_t numOverlaysToSave = getNumberOfDisplayedOverlays(); std::vector overlayClassVector; for (int i = 0; i < numOverlaysToSave; i++) { overlayClassVector.push_back(m_overlays[i]->saveToScene(sceneAttributes, "m_overlays")); } SceneClassArray* overlayClassArray = new SceneClassArray("m_overlays", overlayClassVector); sceneClass->addChild(overlayClassArray); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. May be NULL for some types of scenes. */ void OverlaySet::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); const SceneClassArray* overlayClassArray = sceneClass->getClassArray("m_overlays"); if (overlayClassArray != NULL) { const int32_t numOverlays = std::min(overlayClassArray->getNumberOfArrayElements(), (int32_t)BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS); for (int32_t i = 0; i < numOverlays; i++) { m_overlays[i]->restoreFromScene(sceneAttributes, overlayClassArray->getClassAtIndex(i)); } } } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void OverlaySet::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_MAP_YOKING_VALIDATION) { /* * The events intended for overlays are received here so that * only DISPLAYED overlays are updated. */ EventMapYokingValidation* mapYokeEvent = dynamic_cast(event); CaretAssert(mapYokeEvent); const MapYokingGroupEnum::Enum requestedYokingGroup = mapYokeEvent->getMapYokingGroup(); if (requestedYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { /* * Find all overlays with the requested yoking */ const int32_t overlayCount = getNumberOfDisplayedOverlays(); for (int32_t j = 0; j < overlayCount; j++) { Overlay* overlay = getOverlay(j); CaretMappableDataFile* mapFile = NULL; int32_t mapIndex = -1; overlay->getSelectionData(mapFile, mapIndex); if (mapFile != NULL) { mapYokeEvent->addMapYokedFile(mapFile, overlay->getMapYokingGroup(), m_tabIndex); } } } mapYokeEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP) { /* * The events intended for overlays are received here so that * only DISPLAYED overlays are updated. */ EventMapYokingSelectMap* selectMapEvent = dynamic_cast(event); CaretAssert(selectMapEvent); const MapYokingGroupEnum::Enum eventYokingGroup = selectMapEvent->getMapYokingGroup(); if (eventYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { const int32_t yokingGroupMapIndex = MapYokingGroupEnum::getSelectedMapIndex(eventYokingGroup); const bool yokingGroupSelectedStatus = MapYokingGroupEnum::isEnabled(eventYokingGroup); const CaretMappableDataFile* eventMapFile = selectMapEvent->getCaretMappableDataFile(); /* * Find all overlays with the requested yoking */ const int32_t overlayCount = getNumberOfDisplayedOverlays(); for (int32_t j = 0; j < overlayCount; j++) { Overlay* overlay = getOverlay(j); if (overlay->getMapYokingGroup() == selectMapEvent->getMapYokingGroup()) { CaretMappableDataFile* mapFile = NULL; int32_t mapIndex = -1; overlay->getSelectionData(mapFile, mapIndex); if (mapFile != NULL) { if (yokingGroupMapIndex < mapFile->getNumberOfMaps()) { overlay->setSelectionData(mapFile, yokingGroupMapIndex); } if (mapFile == eventMapFile) { /* only alter status if event was sent by mappable file */ if (selectMapEvent->getCaretMappableDataFile() != NULL) { overlay->setEnabled(yokingGroupSelectedStatus); } } } } } selectMapEvent->setEventProcessed(); } // const MapYokingGroupEnum::Enum mapYokingGroup = selectMapEvent->get } } connectome-workbench-1.4.2/src/Brain/OverlaySet.h000066400000000000000000000156221360521144700217310ustar00rootroot00000000000000#ifndef __OVERLAY_SET__H_ #define __OVERLAY_SET__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "CaretObject.h" #include "EventListenerInterface.h" #include "Overlay.h" #include "SceneableInterface.h" #include "StructureEnum.h" namespace caret { class BrowserTabContent; class LabelFile; class SceneClassAssistant; class Surface; class PlaneTextStringBuilder; class VolumeFile; class VolumeMappableInterface; class OverlaySet : public CaretObject, public EventListenerInterface, public SceneableInterface { public: OverlaySet(const AString& name, const int32_t tabIndex, const std::vector& includeSurfaceStructures, const Overlay::IncludeVolumeFiles includeVolumeFiles); virtual ~OverlaySet(); virtual void receiveEvent(Event* event); void copyOverlaySet(const OverlaySet* overlaySet); Overlay* getPrimaryOverlay(); Overlay* getUnderlay(); VolumeMappableInterface* getUnderlayVolume(); Overlay* getUnderlayContainingVolume(); Overlay* getOverlay(const int32_t overlayNumber); const Overlay* getOverlay(const int32_t overlayNumber) const; void addDisplayedOverlay(); void setNumberOfDisplayedOverlays(const int32_t numberOfDisplayedOverlays); int32_t getNumberOfDisplayedOverlays() const; void insertOverlayAbove(const int32_t overlayIndex); void insertOverlayBelow(const int32_t overlayIndex); void removeDisplayedOverlay(const int32_t overlayIndex); void moveDisplayedOverlayUp(const int32_t overlayIndex); void moveDisplayedOverlayDown(const int32_t overlayIndex); VolumeMappableInterface* setUnderlayToVolume(); void initializeOverlays(); void getSelectedMapIndicesForFile(const CaretMappableDataFile* caretMappableDataFile, const bool isLimitToEnabledOverlays, std::vector& selectedMapIndicesOut) const; void getLabelFilesForSurface(const Surface* surface, std::vector& labelFilesOut, std::vector& labelMapIndicesOut); void resetOverlayYokingToOff(); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); public: virtual AString toString() const; virtual void getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const; private: void findUnderlayFiles(const std::vector& matchToStructures, const bool includeVolumeFiles, std::vector& filesOut, std::vector& mapIndicesOut); void findMiddleLayerFiles(const std::vector& matchToStructures, const bool includeVolumeFiles, std::vector& filesOut, std::vector& mapIndicesOut); void findOverlayFiles(const std::vector& matchToStructures, const bool includeVolumeFiles, std::vector& filesOut, std::vector& mapIndicesOut); OverlaySet(const OverlaySet&); OverlaySet& operator=(const OverlaySet&); Overlay* m_overlays[BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS]; bool findFilesWithMapNamed(std::vector& matchedFilesOut, std::vector& matchedFileIndicesOut, const std::vector& matchToStructures, const DataFileTypeEnum::Enum dataFileType, const bool matchToVolumeData, const AString& matchToNamesRegularExpressionText, const bool matchToNamesRegularExpressionResult, const bool matchOneFilePerStructure); std::vector getVolumeFiles() const; AString m_name; int32_t m_tabIndex; /** Surface structures of data files displayed in this overlay */ const std::vector m_includeSurfaceStructures; /** Include volume files in this overlay */ const Overlay::IncludeVolumeFiles m_includeVolumeFiles; int32_t m_numberOfDisplayedOverlays; SceneClassAssistant* m_sceneAssistant; /** regular expression for matching myeline names - NOT saved to scenes */ static const AString s_myelinMatchRegularExpressionText; /** regular expression for matching shape names - NOT saved to scenes */ static const AString s_shapeMatchRegularExpressionText; /** regular expression for matching shape and myelin names - NOT saved to scenes */ static const AString s_shapeMyelinMatchRegularExpressionText; }; #ifdef __OVERLAY_SET_DECLARE__ AString const OverlaySet::s_myelinMatchRegularExpressionText = "(myelin)"; AString const OverlaySet::s_shapeMatchRegularExpressionText = "(sulc|shape|curv|depth|thick)"; AString const OverlaySet::s_shapeMyelinMatchRegularExpressionText = "(myelin|sulc|shape|curv|depth|thick)"; #endif // __OVERLAY_SET_DECLARE__ } // namespace #endif //__OVERLAY_SET__H_ connectome-workbench-1.4.2/src/Brain/OverlaySetArray.cxx000066400000000000000000000116151360521144700233010ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __OVERLAY_SET_ARRAY_DECLARE__ #include "OverlaySetArray.h" #undef __OVERLAY_SET_ARRAY_DECLARE__ #include "BrainConstants.h" #include "CaretAssert.h" #include "EventBrowserTabDelete.h" #include "EventManager.h" #include "OverlaySet.h" using namespace caret; /** * \class caret::OverlaySetArray * \brief Maintains an array of overlay sets for use with a model * \ingroup Brain */ /** * Constructor. * * @param includeSurfaceStructures * Surface structures for files available in this overlay. * @param includeVolumeFiles * Include (or not) volume files. * @param name * Name of model using this overlay set. This name is displayed * if there is an attempt to yoke models with incompatible overlays. */ OverlaySetArray::OverlaySetArray(const std::vector& includeSurfaceStructures, const Overlay::IncludeVolumeFiles includeVolumeFiles, const AString& name) : CaretObject(), m_name(name) { m_overlaySets.resize(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_overlaySets[i] = new OverlaySet(name, i, includeSurfaceStructures, includeVolumeFiles); } EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_DELETE); } /** * Destructor. */ OverlaySetArray::~OverlaySetArray() { EventManager::get()->removeAllEventsFromListener(this); for (std::vector::iterator iter = m_overlaySets.begin(); iter != m_overlaySets.end(); iter++) { delete *iter; } m_overlaySets.clear(); } /** * Get a description of this object's content. * @return String describing this object's content. */ AString OverlaySetArray::toString() const { return "OverlaySetArray"; } /** * @return The number of overlay sets. */ int32_t OverlaySetArray::getNumberOfOverlaySets() { return m_overlaySets.size(); } /** * Get the overlay set at the given index. * * @param indx * Index of overlay set. * @return * Overlay set at given index. */ OverlaySet* OverlaySetArray::getOverlaySet(const int32_t indx) { CaretAssertVectorIndex(m_overlaySets, indx); return m_overlaySets[indx]; } /** * Initialize the overlay selections. */ void OverlaySetArray::initializeOverlaySelections() { for (int32_t iTab = 0; iTab < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; iTab++) { CaretAssertVectorIndex(m_overlaySets, iTab); m_overlaySets[iTab]->initializeOverlays(); } } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void OverlaySetArray::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_DELETE) { EventBrowserTabDelete* deleteTabEvent = dynamic_cast(event); CaretAssert(deleteTabEvent); /* * Since tab is being deleted, reset any overlay yoking for the tab. */ const int32_t tabIndex = deleteTabEvent->getBrowserTabIndex(); if ((tabIndex > 0) && (tabIndex < getNumberOfOverlaySets())) { m_overlaySets[tabIndex]->resetOverlayYokingToOff(); } deleteTabEvent->setEventProcessed(); } } /** * Copy the overlay set from the source tab index to the * destination tab index. * * @param sourceTabIndex * Source from which tab content is copied. * @param destinationTabIndex * Destination to which tab content is copied. */ void OverlaySetArray::copyOverlaySet(const int32_t sourceTabIndex, const int32_t destinationTabIndex) { CaretAssertVectorIndex(m_overlaySets, sourceTabIndex); CaretAssertVectorIndex(m_overlaySets, destinationTabIndex); const OverlaySet* sourceOverlaySet = m_overlaySets[sourceTabIndex]; OverlaySet* destinationOverlaySet = m_overlaySets[destinationTabIndex]; destinationOverlaySet->copyOverlaySet(sourceOverlaySet); } connectome-workbench-1.4.2/src/Brain/OverlaySetArray.h000066400000000000000000000045431360521144700227300ustar00rootroot00000000000000#ifndef __OVERLAY_SET_ARRAY_H__ #define __OVERLAY_SET_ARRAY_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "EventListenerInterface.h" #include "Overlay.h" namespace caret { class OverlaySet; class OverlaySetArray : public CaretObject, public EventListenerInterface { public: OverlaySetArray(const std::vector& includeSurfaceStructures, const Overlay::IncludeVolumeFiles includeVolumeFiles, const AString& name); virtual ~OverlaySetArray(); int32_t getNumberOfOverlaySets(); OverlaySet* getOverlaySet(const int32_t indx); void initializeOverlaySelections(); void copyOverlaySet(const int32_t sourceTabIndex, const int32_t destinationTabIndex); private: OverlaySetArray(const OverlaySetArray&); OverlaySetArray& operator=(const OverlaySetArray&); public: // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual void receiveEvent(Event* event); private: // ADD_NEW_MEMBERS_HERE void initialize(); /** Name for this overlay set array */ AString m_name; /** The overlay sets */ std::vector m_overlaySets; }; #ifdef __OVERLAY_SET_ARRAY_DECLARE__ // #endif // __OVERLAY_SET_ARRAY_DECLARE__ } // namespace #endif //__OVERLAY_SET_ARRAY_H__ connectome-workbench-1.4.2/src/Brain/ProjectionViewTypeEnum.cxx000066400000000000000000000264011360521144700246420ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __PROJECTION_VIEW_TYPE_ENUM_DECLARE__ #include "ProjectionViewTypeEnum.h" #undef __PROJECTION_VIEW_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ProjectionViewTypeEnum * \brief Type for viewing models from left or right */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ProjectionViewTypeEnum::ProjectionViewTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ProjectionViewTypeEnum::~ProjectionViewTypeEnum() { } /** * Initialize the enumerated metadata. */ void ProjectionViewTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ProjectionViewTypeEnum(PROJECTION_VIEW_CEREBELLUM_ANTERIOR, "PROJECTION_VIEW_CEREBELLUM_ANTERIOR", "Cerebellum Anterior")); enumData.push_back(ProjectionViewTypeEnum(PROJECTION_VIEW_CEREBELLUM_DORSAL, "PROJECTION_VIEW_CEREBELLUM_DORSAL", "Cerebellum Dorsal")); enumData.push_back(ProjectionViewTypeEnum(PROJECTION_VIEW_CEREBELLUM_POSTERIOR, "PROJECTION_VIEW_CEREBELLUM_POSTERIOR", "Cerebellum Posterior")); enumData.push_back(ProjectionViewTypeEnum(PROJECTION_VIEW_CEREBELLUM_VENTRAL, "PROJECTION_VIEW_CEREBELLUM_VENTRAL", "Cerebellum Ventral")); enumData.push_back(ProjectionViewTypeEnum(PROJECTION_VIEW_CEREBELLUM_FLAT_SURFACE, "PROJECTION_VIEW_CEREBELLUM_FLAT_SURFACE", "Cerebellum Flat")); enumData.push_back(ProjectionViewTypeEnum(PROJECTION_VIEW_LEFT_LATERAL, "PROJECTION_VIEW_LEFT_LATERAL", "Left Lateral")); enumData.push_back(ProjectionViewTypeEnum(PROJECTION_VIEW_LEFT_MEDIAL, "PROJECTION_VIEW_LEFT_MEDIAL", "Left Medial")); enumData.push_back(ProjectionViewTypeEnum(PROJECTION_VIEW_LEFT_FLAT_SURFACE, "PROJECTION_VIEW_LEFT_FLAT_SURFACE", "Left Flat")); enumData.push_back(ProjectionViewTypeEnum(PROJECTION_VIEW_RIGHT_LATERAL, "PROJECTION_VIEW_RIGHT_LATERAL", "Right Lateral")); enumData.push_back(ProjectionViewTypeEnum(PROJECTION_VIEW_RIGHT_MEDIAL, "PROJECTION_VIEW_RIGHT_MEDIAL", "Right Medial")); enumData.push_back(ProjectionViewTypeEnum(PROJECTION_VIEW_RIGHT_FLAT_SURFACE, "PROJECTION_VIEW_RIGHT_FLAT_SURFACE", "Right Flat")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ProjectionViewTypeEnum* ProjectionViewTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ProjectionViewTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ProjectionViewTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ProjectionViewTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ProjectionViewTypeEnum::Enum ProjectionViewTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PROJECTION_VIEW_LEFT_LATERAL; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ProjectionViewTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ProjectionViewTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ProjectionViewTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ProjectionViewTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ProjectionViewTypeEnum::Enum ProjectionViewTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PROJECTION_VIEW_LEFT_LATERAL; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ProjectionViewTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ProjectionViewTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ProjectionViewTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ProjectionViewTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ProjectionViewTypeEnum::Enum ProjectionViewTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PROJECTION_VIEW_LEFT_LATERAL; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ProjectionViewTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ProjectionViewTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ProjectionViewTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ProjectionViewTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ProjectionViewTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ProjectionViewTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ProjectionViewTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Brain/ProjectionViewTypeEnum.h000066400000000000000000000100061360521144700242610ustar00rootroot00000000000000#ifndef __PROJECTION_VIEW_TYPE_ENUM_H__ #define __PROJECTION_VIEW_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ProjectionViewTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Viewing cerebellum in anterior orientation */ PROJECTION_VIEW_CEREBELLUM_ANTERIOR, /** Viewing cerebellum in dorsal orientation */ PROJECTION_VIEW_CEREBELLUM_DORSAL, /** Viewing cerebellum in posterior orientation */ PROJECTION_VIEW_CEREBELLUM_POSTERIOR, /** Viewing cerebellum in ventral orientation */ PROJECTION_VIEW_CEREBELLUM_VENTRAL, /** Viewing cerebellum in flat surface */ PROJECTION_VIEW_CEREBELLUM_FLAT_SURFACE, /** Viewing models from left lateral */ PROJECTION_VIEW_LEFT_LATERAL, /** Viewing models from left medial */ PROJECTION_VIEW_LEFT_MEDIAL, /** Viewing model left flat surface */ PROJECTION_VIEW_LEFT_FLAT_SURFACE, /** Viewing models from right */ PROJECTION_VIEW_RIGHT_LATERAL, /** Viewing models from right medial */ PROJECTION_VIEW_RIGHT_MEDIAL, /** Viewing model right flat surface */ PROJECTION_VIEW_RIGHT_FLAT_SURFACE }; ~ProjectionViewTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ProjectionViewTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ProjectionViewTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __PROJECTION_VIEW_TYPE_ENUM_DECLARE__ std::vector ProjectionViewTypeEnum::enumData; bool ProjectionViewTypeEnum::initializedFlag = false; int32_t ProjectionViewTypeEnum::integerCodeCounter = 0; #endif // __PROJECTION_VIEW_TYPE_ENUM_DECLARE__ } // namespace #endif //__PROJECTION_VIEW_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Brain/SelectionItem.cxx000066400000000000000000000152751360521144700227570ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_DECLARE__ #include "SelectionItem.h" #undef __SELECTION_ITEM_DECLARE__ #include using namespace caret; #include "SelectionItemDataTypeEnum.h" /** * \class SelectionItem * \brief Abstract class for selected items. * * Abstract class for selected items. */ /** * Constructor. */ SelectionItem::SelectionItem(const SelectionItemDataTypeEnum::Enum itemDataType) : CaretObject() { m_itemDataType = itemDataType; m_enabledForSelection = true; m_brain = NULL; m_screenDepth = 0.0; m_screenXYZ[0] = 0.0; m_screenXYZ[1] = 0.0; m_screenXYZ[2] = std::numeric_limits::max(); m_modelXYZ[0] = 0.0; m_modelXYZ[1] = 0.0; m_modelXYZ[2] = 0.0; } /** * Destructor. */ SelectionItem::~SelectionItem() { } /** * Copy constructor. * @param obj * Object that is copied. */ SelectionItem::SelectionItem(const SelectionItem& obj) : CaretObject(obj) { copyHelperSelectionItem(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ SelectionItem& SelectionItem::operator=(const SelectionItem& obj) { if (this != &obj) { CaretObject::operator=(obj); copyHelperSelectionItem(obj); } return *this; } /** * Helps with copying an object of this type. * @param ff * Object that is copied. */ void SelectionItem::copyHelperSelectionItem(const SelectionItem& idItem) { m_brain = idItem.m_brain; m_enabledForSelection = idItem.m_enabledForSelection; m_screenDepth = idItem.m_screenDepth; m_screenXYZ[0] = idItem.m_screenXYZ[0]; m_screenXYZ[1] = idItem.m_screenXYZ[1]; m_screenXYZ[2] = idItem.m_screenXYZ[2]; m_modelXYZ[0] = idItem.m_modelXYZ[0]; m_modelXYZ[1] = idItem.m_modelXYZ[1]; m_modelXYZ[2] = idItem.m_modelXYZ[2]; } /** * Reset this selection item. Deriving * classes should override this method to * reset its selection data and also call * the method in this class. */ void SelectionItem::reset() { m_brain = NULL; m_screenDepth = 0.0; m_screenXYZ[0] = 0.0; m_screenXYZ[1] = 0.0; m_screenXYZ[2] = std::numeric_limits::max(); m_modelXYZ[0] = 0.0; m_modelXYZ[1] = 0.0; m_modelXYZ[2] = 0.0; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString SelectionItem::toString() const { AString text = ""; text += ("Type: " + SelectionItemDataTypeEnum::toGuiName(m_itemDataType) + "\n"); text += ("Depth: " + AString::number(m_screenDepth) + "\n"); text += ("Model XYZ: " + AString::fromNumbers(m_modelXYZ, 3, ", ") + "\n"); text += ("Screen XYZ: " + AString::fromNumbers(m_screenXYZ, 3, ", ") + "\n"); return text; } /** * @return The type of selected item. */ SelectionItemDataTypeEnum::Enum SelectionItem::getItemDataType() const { return m_itemDataType; } /** * @return Data type enabled for selection. */ bool SelectionItem::isEnabledForSelection() const { return m_enabledForSelection; } /** * Set the data type enabled for selection. * @param enabled * New value for selection enabled status. */ void SelectionItem::setEnabledForSelection(const bool enabled) { m_enabledForSelection = enabled; } /** * @return Brain in which identification item resides. */ Brain* SelectionItem::getBrain() { return m_brain; } /** * Set the brain. * * param brain * Brain in which identification item resides. */ void SelectionItem::setBrain(Brain* brain) { m_brain = brain; } /** * @return Screen depth of item. */ double SelectionItem::getScreenDepth() const { return m_screenDepth; } /** * Set the screen depth of the item. * @param screenDepth * New value for screen depth. */ void SelectionItem::setScreenDepth(const double screenDepth) { m_screenDepth = screenDepth; } /** * Get the screen XYZ of the selected item. * @param screenXYZ * XYZ out. */ void SelectionItem::getScreenXYZ(double screenXYZ[3]) const { screenXYZ[0] = m_screenXYZ[0]; screenXYZ[1] = m_screenXYZ[1]; screenXYZ[2] = m_screenXYZ[2]; } /** * Set the screen XYZ of the selected item. * @param screenXYZ * new XYZ. */ void SelectionItem::setScreenXYZ(const double screenXYZ[3]) { m_screenXYZ[0] = screenXYZ[0]; m_screenXYZ[1] = screenXYZ[1]; m_screenXYZ[2] = screenXYZ[2]; } /** * Get the model XYZ of the selected item. * @param modelXYZ * XYZ out. */ void SelectionItem::getModelXYZ(double modelXYZ[3]) const { modelXYZ[0] = m_modelXYZ[0]; modelXYZ[1] = m_modelXYZ[1]; modelXYZ[2] = m_modelXYZ[2]; } /** * Set the model XYZ of the selected item. * @param modelXYZ * new XYZ. */ void SelectionItem::setModelXYZ(const double modelXYZ[3]) { m_modelXYZ[0] = modelXYZ[0]; m_modelXYZ[1] = modelXYZ[1]; m_modelXYZ[2] = modelXYZ[2]; } /** * Is the other screen depth closer to the viewer than the currently * selected item? So, if true is returned, then replace the * current identification item * * (1) If there is no selected item, true is immediately returned. * (2) If there is an selected item and the other screen depth is closer * to the viewer, true is returned. * (3) false is returned. * * @param otherScreenDepth * Screen depth for testing. * @return result of test. */ bool SelectionItem::isOtherScreenDepthCloserToViewer(const double otherScreenDepth) const { if (isValid() == false) { return true; } /* * Multiple annotations that are on top of each other may be drawn at the same * depth so using "<=" should select the one that appears to be "on top" to the user. */ if (m_itemDataType == SelectionItemDataTypeEnum::ANNOTATION) { if (otherScreenDepth <= m_screenDepth) { return true; } } else { if (otherScreenDepth < m_screenDepth) { return true; } } return false; } connectome-workbench-1.4.2/src/Brain/SelectionItem.h000066400000000000000000000054251360521144700224000ustar00rootroot00000000000000#ifndef __SELECTION_ITEM__H_ #define __SELECTION_ITEM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "SelectionItemDataTypeEnum.h" namespace caret { class Brain; class SelectionItem : public CaretObject { protected: SelectionItem(const SelectionItemDataTypeEnum::Enum itemDataType); SelectionItem(const SelectionItem&); SelectionItem& operator=(const SelectionItem&); public: virtual ~SelectionItem(); SelectionItemDataTypeEnum::Enum getItemDataType() const; bool isEnabledForSelection() const; void setEnabledForSelection(const bool enabled); Brain* getBrain(); void setBrain(Brain* brain); bool isOtherScreenDepthCloserToViewer(const double otherScreenDepth) const; double getScreenDepth() const; void setScreenDepth(const double screenDepth); void getScreenXYZ(double screenXYZ[3]) const; void setScreenXYZ(const double screenXYZ[3]); void getModelXYZ(double modelXYZ[3]) const; void setModelXYZ(const double modelXYZ[3]); /** * @return Is the selected item valid? */ virtual bool isValid() const = 0; virtual void reset(); private: public: virtual AString toString() const; protected: SelectionItemDataTypeEnum::Enum m_itemDataType; bool m_enabledForSelection; Brain* m_brain; double m_screenDepth; double m_screenXYZ[3]; double m_modelXYZ[3]; private: void copyHelperSelectionItem(const SelectionItem& idItem); }; #ifdef __SELECTION_ITEM_DECLARE__ // #endif // __SELECTION_ITEM_DECLARE__ } // namespace #endif //__SELECTION_ITEM__H_ connectome-workbench-1.4.2/src/Brain/SelectionItemAnnotation.cxx000066400000000000000000000077471360521144700250170ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_ANNOTATION_DECLARE__ #include "SelectionItemAnnotation.h" #undef __SELECTION_ITEM_ANNOTATION_DECLARE__ #include "AnnotationText.h" #include "CaretAssert.h" using namespace caret; /** * \class caret::SelectionItemAnnotation * \brief Contains information about a selected annotation. * \ingroup Brain */ /** * Constructor. */ SelectionItemAnnotation::SelectionItemAnnotation() : SelectionItem(SelectionItemDataTypeEnum::ANNOTATION) { } /** * Destructor. */ SelectionItemAnnotation::~SelectionItemAnnotation() { } /** * Reset this selection item. */ void SelectionItemAnnotation::reset() { SelectionItem::reset(); /* * Just have pointers to the annotations. * We do not 'own' them. */ m_annotationFile = NULL; m_annotation = NULL; m_sizingHandle = AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE; } /** * @return Is this selected item valid? */ bool SelectionItemAnnotation::isValid() const { return (m_annotation != NULL); } /** * @return The selected annotation. */ Annotation* SelectionItemAnnotation::getAnnotation() const { return m_annotation; } /** * @return The file containing the selected annotation. */ AnnotationFile* SelectionItemAnnotation::getAnnotationFile() const { return m_annotationFile; } /** * @return Sizing handle selected in the selected annotation. */ AnnotationSizingHandleTypeEnum::Enum SelectionItemAnnotation::getSizingHandle() const { return m_sizingHandle; } /** * Add a annotation to the selected annotations. * * @param annotationFile * File containing the annotation. * @param annotation. * Annotation that is added. * @param annotationSizingHandle * Sizing handle that is selected. */ void SelectionItemAnnotation::setAnnotation(AnnotationFile* annotationFile, Annotation* annotation, const AnnotationSizingHandleTypeEnum::Enum annotationSizingHandle) { CaretAssert(annotationFile); CaretAssert(annotation); m_annotationFile = annotationFile; m_annotation = annotation; m_sizingHandle = annotationSizingHandle; } /** * Get a description of m_ object's content. * @return String describing m_ object's content. */ AString SelectionItemAnnotation::toString() const { AString text = SelectionItem::toString(); text += ("Annotation type=" + AnnotationTypeEnum::toGuiName(m_annotation->getType()) + " sizeHandleType=" + AnnotationSizingHandleTypeEnum::toGuiName(m_sizingHandle)); AnnotationText* textAnn = dynamic_cast(m_annotation); if (textAnn != NULL) { text += (" text=" + textAnn->getText()); } // text += ("Surface: " + ((surface != NULL) ? surface->getFileNameNoPath() : "INVALID") + "\n"); // text += ("Border File: " + ((borderFile != NULL) ? borderFile->getFileNameNoPath() : "INVALID") + "\n"); // text += ("Border: " + ((border != NULL) ? border->getName() : "INVALID") + "\n"); // text += ("Border Index: " + AString::number(borderIndex) + "\n"); // text += ("Border Point Index: " + AString::number(borderPointIndex) + "\n"); return text; } connectome-workbench-1.4.2/src/Brain/SelectionItemAnnotation.h000066400000000000000000000045061360521144700244320ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_ANNOTATION_H__ #define __SELECTION_ITEM_ANNOTATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationSizingHandleTypeEnum.h" #include "SelectionItem.h" namespace caret { class Annotation; class AnnotationFile; class SelectionItemAnnotation : public SelectionItem { public: SelectionItemAnnotation(); virtual ~SelectionItemAnnotation(); virtual bool isValid() const; void reset(); virtual AString toString() const; Annotation* getAnnotation() const; AnnotationFile* getAnnotationFile() const; AnnotationSizingHandleTypeEnum::Enum getSizingHandle() const; void setAnnotation(AnnotationFile* annotationFile, Annotation* annotation, const AnnotationSizingHandleTypeEnum::Enum annotationSizingHandle); // ADD_NEW_METHODS_HERE private: SelectionItemAnnotation(const SelectionItemAnnotation&); SelectionItemAnnotation& operator=(const SelectionItemAnnotation&); AnnotationFile* m_annotationFile; Annotation* m_annotation; AnnotationSizingHandleTypeEnum::Enum m_sizingHandle; // ADD_NEW_MEMBERS_HERE }; #ifdef __SELECTION_ITEM_ANNOTATION_DECLARE__ // #endif // __SELECTION_ITEM_ANNOTATION_DECLARE__ } // namespace #endif //__SELECTION_ITEM_ANNOTATION_H__ connectome-workbench-1.4.2/src/Brain/SelectionItemBorderSurface.cxx000066400000000000000000000113671360521144700254240ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_BORDER_SURFACE_DECLARE__ #include "SelectionItemBorderSurface.h" #undef __SELECTION_ITEM_BORDER_SURFACE_DECLARE__ #include "Border.h" #include "BorderFile.h" #include "Surface.h" using namespace caret; /** * \class SelectionItemBorderSurface * \brief Contains information about the selected border. */ /** * Constructor. */ SelectionItemBorderSurface::SelectionItemBorderSurface() : SelectionItem(SelectionItemDataTypeEnum::BORDER_SURFACE) { this->surface = NULL; this->border = NULL; this->borderFile = NULL; this->borderIndex = -1; this->borderPointIndex = -1; } /** * Destructor. */ SelectionItemBorderSurface::~SelectionItemBorderSurface() { } /** * Reset this selection item. */ void SelectionItemBorderSurface::reset() { SelectionItem::reset(); this->surface = NULL; this->border = NULL; this->borderFile = NULL; this->borderIndex = -1; this->borderPointIndex = -1; } /** * @return Is this selected item valid? */ bool SelectionItemBorderSurface::isValid() const { return (this->border != NULL); } /** * @return Surface on which border was drawn. */ const Surface* SelectionItemBorderSurface::getSurface() const { return this->surface; } /** * @return Surface on which border was drawn. */ Surface* SelectionItemBorderSurface::getSurface() { return this->surface; } /** * Set the surface on which border was drawn. * @param surface * New value for surface. */ void SelectionItemBorderSurface::setSurface(Surface* surface) { this->surface = surface; } /** * @return The border that was selected. */ const Border* SelectionItemBorderSurface::getBorder() const { return this->border; } /** * @return The border that was selected. */ Border* SelectionItemBorderSurface::getBorder() { return this->border; } /** * Set the border that was selected. * @param border * New value for border. */ void SelectionItemBorderSurface::setBorder(Border* border) { this->border = border; } /** * @return The border file containing border that was selected. */ const BorderFile* SelectionItemBorderSurface::getBorderFile() const { return this->borderFile; } /** * @return The border file containing border that was selected. */ BorderFile* SelectionItemBorderSurface::getBorderFile() { return this->borderFile; } /** * Set the border file containing border that was selected. * @param borderFile * New value for border file. */ void SelectionItemBorderSurface::setBorderFile(BorderFile* borderFile) { this->borderFile = borderFile; } /** * return Index of selected border. */ int32_t SelectionItemBorderSurface::getBorderIndex() const { return this->borderIndex; } /** * Set index of selected border. * @param borderIndex * New value for border index. */ void SelectionItemBorderSurface::setBorderIndex(const int32_t borderIndex) { this->borderIndex = borderIndex; } /** * return Index of selected border. */ int32_t SelectionItemBorderSurface::getBorderPointIndex() const { return this->borderPointIndex; } /** * Set index of selected border. * @param borderIndex * New value for border index. */ void SelectionItemBorderSurface::setBorderPointIndex(const int32_t borderPointIndex) { this->borderPointIndex = borderPointIndex; } /** * Get a description of m_ object's content. * @return String describing m_ object's content. */ AString SelectionItemBorderSurface::toString() const { AString text = SelectionItem::toString(); text += ("Surface: " + ((surface != NULL) ? surface->getFileNameNoPath() : "INVALID") + "\n"); text += ("Border File: " + ((borderFile != NULL) ? borderFile->getFileNameNoPath() : "INVALID") + "\n"); text += ("Border: " + ((border != NULL) ? border->getName() : "INVALID") + "\n"); text += ("Border Index: " + AString::number(borderIndex) + "\n"); text += ("Border Point Index: " + AString::number(borderPointIndex) + "\n"); return text; } connectome-workbench-1.4.2/src/Brain/SelectionItemBorderSurface.h000066400000000000000000000050271360521144700250450ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_BORDER_SURFACE__H_ #define __SELECTION_ITEM_BORDER_SURFACE__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SelectionItem.h" namespace caret { class Border; class BorderFile; class Surface; class SelectionItemBorderSurface : public SelectionItem { public: SelectionItemBorderSurface(); virtual ~SelectionItemBorderSurface(); virtual bool isValid() const; Surface* getSurface(); const Surface* getSurface() const; Border* getBorder(); const Border* getBorder() const; void setBorder(Border* border); BorderFile* getBorderFile(); const BorderFile* getBorderFile() const; void setBorderFile(BorderFile* borderFile); void setSurface(Surface* surface); int32_t getBorderIndex() const; void setBorderIndex(const int32_t borderIndex); int32_t getBorderPointIndex() const; void setBorderPointIndex(const int32_t borderPointIndex); void reset(); virtual AString toString() const; private: SelectionItemBorderSurface(const SelectionItemBorderSurface&); SelectionItemBorderSurface& operator=(const SelectionItemBorderSurface&); Border* border; BorderFile* borderFile; Surface* surface; int32_t borderIndex; int32_t borderPointIndex; }; #ifdef __SELECTION_ITEM_BORDER_SURFACE_DECLARE__ // #endif // __SELECTION_ITEM_BORDER_SURFACE_DECLARE__ } // namespace #endif //__SELECTION_ITEM_BORDER_SURFACE__H_ connectome-workbench-1.4.2/src/Brain/SelectionItemChartDataSeries.cxx000066400000000000000000000102041360521144700256710ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_CHART_DATA_SERIES_DECLARE__ #include "SelectionItemChartDataSeries.h" #undef __SELECTION_ITEM_CHART_DATA_SERIES_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::SelectionItemChartDataSeries * \brief Contains selection of a data-series chart. * \ingroup Brain */ /** * Constructor. */ SelectionItemChartDataSeries::SelectionItemChartDataSeries() : SelectionItem(SelectionItemDataTypeEnum::CHART_DATA_SERIES) { m_chartModelDataSeries = NULL; m_chartDataCartesian = NULL; m_chartDataPointIndex = -1; } /** * Destructor. */ SelectionItemChartDataSeries::~SelectionItemChartDataSeries() { } /** * Copy constructor. * @param obj * Object that is copied. */ SelectionItemChartDataSeries::SelectionItemChartDataSeries(const SelectionItemChartDataSeries& obj) : SelectionItem(obj) { this->copyHelperSelectionItemChartDataSeries(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ SelectionItemChartDataSeries& SelectionItemChartDataSeries::operator=(const SelectionItemChartDataSeries& obj) { if (this != &obj) { SelectionItem::operator=(obj); this->copyHelperSelectionItemChartDataSeries(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void SelectionItemChartDataSeries::copyHelperSelectionItemChartDataSeries(const SelectionItemChartDataSeries& obj) { m_chartModelDataSeries = obj.m_chartModelDataSeries; m_chartDataCartesian = obj.m_chartDataCartesian; m_chartDataPointIndex = obj.m_chartDataPointIndex; } /** * @return True if the selected chart is valid, else false. */ bool SelectionItemChartDataSeries::isValid() const { if ((m_chartModelDataSeries != NULL) && (m_chartDataCartesian != NULL) && (m_chartDataPointIndex >= 0)) { return true; } return false; } /** * Reset the selections. */ void SelectionItemChartDataSeries::reset() { m_chartModelDataSeries = NULL; m_chartDataCartesian = NULL; m_chartDataPointIndex = -1; } /** * @return */ ChartModelDataSeries* SelectionItemChartDataSeries::getChartModelDataSeries() const { return m_chartModelDataSeries; } /** * @return */ ChartDataCartesian* SelectionItemChartDataSeries::getChartDataCartesian() const { return m_chartDataCartesian; } /** * @return */ int32_t SelectionItemChartDataSeries::getChartDataPointIndex() const { return m_chartDataPointIndex; } /** * Set the selected chart information. * * @param chartModelDataSeries * Data series chart model that was selected. * @param chartDataCartesian * Cartesian chart data that was selected. * @param chartDataPointIndex * Point index of selected chart data. */ void SelectionItemChartDataSeries::setChart(ChartModelDataSeries* chartModelDataSeries, ChartDataCartesian* chartDataCartesian, const int32_t chartDataPointIndex) { CaretAssert(chartModelDataSeries); CaretAssert(chartDataCartesian); CaretAssert(chartDataPointIndex >= 0); m_chartModelDataSeries = chartModelDataSeries; m_chartDataCartesian = chartDataCartesian; m_chartDataPointIndex = chartDataPointIndex; } connectome-workbench-1.4.2/src/Brain/SelectionItemChartDataSeries.h000066400000000000000000000046551360521144700253330ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_CHART_DATA_SERIES_H__ #define __SELECTION_ITEM_CHART_DATA_SERIES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SelectionItem.h" namespace caret { class ChartDataCartesian; class ChartModelDataSeries; class SelectionItemChartDataSeries : public SelectionItem { public: SelectionItemChartDataSeries(); virtual ~SelectionItemChartDataSeries(); SelectionItemChartDataSeries(const SelectionItemChartDataSeries& obj); SelectionItemChartDataSeries& operator=(const SelectionItemChartDataSeries& obj); virtual bool isValid() const; virtual void reset(); ChartModelDataSeries* getChartModelDataSeries() const; ChartDataCartesian* getChartDataCartesian() const; int32_t getChartDataPointIndex() const; void setChart(ChartModelDataSeries* chartModelDataSeries, ChartDataCartesian* chartDataCartesian, const int32_t chartDataPointIndex); // ADD_NEW_METHODS_HERE private: void copyHelperSelectionItemChartDataSeries(const SelectionItemChartDataSeries& obj); ChartModelDataSeries* m_chartModelDataSeries; ChartDataCartesian* m_chartDataCartesian; int32_t m_chartDataPointIndex; // ADD_NEW_MEMBERS_HERE }; #ifdef __SELECTION_ITEM_CHART_DATA_SERIES_DECLARE__ // #endif // __SELECTION_ITEM_CHART_DATA_SERIES_DECLARE__ } // namespace #endif //__SELECTION_ITEM_CHART_DATA_SERIES_H__ connectome-workbench-1.4.2/src/Brain/SelectionItemChartFrequencySeries.cxx000066400000000000000000000105211360521144700267630ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_CHART_FREQUENCY_SERIES_DECLARE__ #include "SelectionItemChartFrequencySeries.h" #undef __SELECTION_ITEM_CHART_FREQUENCY_SERIES_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::SelectionItemChartFrequencySeries * \brief Contains selection of a data-series chart. * \ingroup Brain */ /** * Constructor. */ SelectionItemChartFrequencySeries::SelectionItemChartFrequencySeries() : SelectionItem(SelectionItemDataTypeEnum::CHART_FREQUENCY_SERIES) { m_chartModelFrequencySeries = NULL; m_chartDataCartesian = NULL; m_chartDataPointIndex = -1; } /** * Destructor. */ SelectionItemChartFrequencySeries::~SelectionItemChartFrequencySeries() { } /** * Copy constructor. * @param obj * Object that is copied. */ SelectionItemChartFrequencySeries::SelectionItemChartFrequencySeries(const SelectionItemChartFrequencySeries& obj) : SelectionItem(obj) { this->copyHelperSelectionItemChartFrequencySeries(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ SelectionItemChartFrequencySeries& SelectionItemChartFrequencySeries::operator=(const SelectionItemChartFrequencySeries& obj) { if (this != &obj) { SelectionItem::operator=(obj); this->copyHelperSelectionItemChartFrequencySeries(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void SelectionItemChartFrequencySeries::copyHelperSelectionItemChartFrequencySeries(const SelectionItemChartFrequencySeries& obj) { m_chartModelFrequencySeries = obj.m_chartModelFrequencySeries; m_chartDataCartesian = obj.m_chartDataCartesian; m_chartDataPointIndex = obj.m_chartDataPointIndex; } /** * @return True if the selected chart is valid, else false. */ bool SelectionItemChartFrequencySeries::isValid() const { if ((m_chartModelFrequencySeries != NULL) && (m_chartDataCartesian != NULL) && (m_chartDataPointIndex >= 0)) { return true; } return false; } /** * Reset the selections. */ void SelectionItemChartFrequencySeries::reset() { m_chartModelFrequencySeries = NULL; m_chartDataCartesian = NULL; m_chartDataPointIndex = -1; } /** * @return */ ChartModelFrequencySeries* SelectionItemChartFrequencySeries::getChartModelFrequencySeries() const { return m_chartModelFrequencySeries; } /** * @return */ ChartDataCartesian* SelectionItemChartFrequencySeries::getChartDataCartesian() const { return m_chartDataCartesian; } /** * @return */ int32_t SelectionItemChartFrequencySeries::getChartDataPointIndex() const { return m_chartDataPointIndex; } /** * Set the selected chart information. * * @param chartModelFrequencySeries * Frequency series chart model that was selected. * @param chartDataCartesian * Cartesian chart data that was selected. * @param chartDataPointIndex * Point index of selected chart data. */ void SelectionItemChartFrequencySeries::setChart(ChartModelFrequencySeries* chartModelFrequencySeries, ChartDataCartesian* chartDataCartesian, const int32_t chartDataPointIndex) { CaretAssert(chartModelFrequencySeries); CaretAssert(chartDataCartesian); CaretAssert(chartDataPointIndex >= 0); m_chartModelFrequencySeries = chartModelFrequencySeries; m_chartDataCartesian = chartDataCartesian; m_chartDataPointIndex = chartDataPointIndex; } connectome-workbench-1.4.2/src/Brain/SelectionItemChartFrequencySeries.h000066400000000000000000000050261360521144700264140ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_CHART_FREQUENCY_SERIES_H__ #define __SELECTION_ITEM_CHART_FREQUENCY_SERIES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SelectionItem.h" namespace caret { class ChartDataCartesian; class ChartModelFrequencySeries; class SelectionItemChartFrequencySeries : public SelectionItem { public: SelectionItemChartFrequencySeries(); virtual ~SelectionItemChartFrequencySeries(); SelectionItemChartFrequencySeries(const SelectionItemChartFrequencySeries& obj); SelectionItemChartFrequencySeries& operator=(const SelectionItemChartFrequencySeries& obj); virtual bool isValid() const; virtual void reset(); ChartModelFrequencySeries* getChartModelFrequencySeries() const; ChartDataCartesian* getChartDataCartesian() const; int32_t getChartDataPointIndex() const; void setChart(ChartModelFrequencySeries* chartModelFrequencySeries, ChartDataCartesian* chartDataCartesian, const int32_t chartDataPointIndex); // ADD_NEW_METHODS_HERE private: void copyHelperSelectionItemChartFrequencySeries(const SelectionItemChartFrequencySeries& obj); ChartModelFrequencySeries* m_chartModelFrequencySeries; ChartDataCartesian* m_chartDataCartesian; int32_t m_chartDataPointIndex; // ADD_NEW_MEMBERS_HERE }; #ifdef __SELECTION_ITEM_CHART_FREQUENCY_SERIES_DECLARE__ // #endif // __SELECTION_ITEM_CHART_FREQUENCY_SERIES_DECLARE__ } // namespace #endif //__SELECTION_ITEM_CHART_FREQUENCY_SERIES_H__ connectome-workbench-1.4.2/src/Brain/SelectionItemChartMatrix.cxx000066400000000000000000000100401360521144700251070ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_CHART_MATRIX_DECLARE__ #include "SelectionItemChartMatrix.h" #undef __SELECTION_ITEM_CHART_MATRIX_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::SelectionItemChartMatrix * \brief Contains selection of a data-series chart. * \ingroup Brain */ /** * Constructor. */ SelectionItemChartMatrix::SelectionItemChartMatrix() : SelectionItem(SelectionItemDataTypeEnum::CHART_MATRIX) { m_chartableMatrixInterface = NULL; m_matrixRowIndex = -1; m_matrixColumnIndex = -1; } /** * Destructor. */ SelectionItemChartMatrix::~SelectionItemChartMatrix() { } /** * Copy constructor. * @param obj * Object that is copied. */ SelectionItemChartMatrix::SelectionItemChartMatrix(const SelectionItemChartMatrix& obj) : SelectionItem(obj) { this->copyHelperSelectionItemChartMatrix(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ SelectionItemChartMatrix& SelectionItemChartMatrix::operator=(const SelectionItemChartMatrix& obj) { if (this != &obj) { SelectionItem::operator=(obj); this->copyHelperSelectionItemChartMatrix(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void SelectionItemChartMatrix::copyHelperSelectionItemChartMatrix(const SelectionItemChartMatrix& obj) { m_chartableMatrixInterface = obj.m_chartableMatrixInterface; m_matrixRowIndex = obj.m_matrixRowIndex; m_matrixColumnIndex = obj.m_matrixColumnIndex; } /** * @return True if the selected chart is valid, else false. */ bool SelectionItemChartMatrix::isValid() const { if ((m_chartableMatrixInterface != NULL) && (m_matrixRowIndex >= 0) && (m_matrixColumnIndex >= 0)) { return true; } return false; } /** * Reset the selections. */ void SelectionItemChartMatrix::reset() { m_chartableMatrixInterface = NULL; m_matrixRowIndex = -1; m_matrixColumnIndex = -1; } /** * @return The Chartable Matrix Interface (file) */ ChartableMatrixInterface* SelectionItemChartMatrix::getChartableMatrixInterface() const { return m_chartableMatrixInterface; } /** * @return Matrix row index. */ int32_t SelectionItemChartMatrix::getMatrixRowIndex() const { return m_matrixRowIndex; } /** * @return Matrix column index. */ int32_t SelectionItemChartMatrix::getMatrixColumnIndex() const { return m_matrixColumnIndex; } /** * Set the selection information. * * @param chartableMatrixInterface * The chartable matrix interface (file) * @param matrixRowIndex * Row index * @param matrixColumnIndex * Column index */ void SelectionItemChartMatrix::setChartMatrix(ChartableMatrixInterface* chartableMatrixInterface, const int32_t matrixRowIndex, const int32_t matrixColumnIndex) { CaretAssert(chartableMatrixInterface); CaretAssert(matrixRowIndex >= 0); CaretAssert(matrixColumnIndex >= 0); m_chartableMatrixInterface = chartableMatrixInterface; m_matrixRowIndex = matrixRowIndex; m_matrixColumnIndex = matrixColumnIndex; } connectome-workbench-1.4.2/src/Brain/SelectionItemChartMatrix.h000066400000000000000000000045201360521144700245420ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_CHART_MATRIX_H__ #define __SELECTION_ITEM_CHART_MATRIX_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SelectionItem.h" namespace caret { class ChartableMatrixInterface; class SelectionItemChartMatrix : public SelectionItem { public: SelectionItemChartMatrix(); virtual ~SelectionItemChartMatrix(); SelectionItemChartMatrix(const SelectionItemChartMatrix& obj); SelectionItemChartMatrix& operator=(const SelectionItemChartMatrix& obj); virtual bool isValid() const; virtual void reset(); ChartableMatrixInterface* getChartableMatrixInterface() const; int32_t getMatrixRowIndex() const; int32_t getMatrixColumnIndex() const; void setChartMatrix(ChartableMatrixInterface* chartableMatrixInterface, const int32_t matrixRowIndex, const int32_t matrixColumnIndex); // ADD_NEW_METHODS_HERE private: void copyHelperSelectionItemChartMatrix(const SelectionItemChartMatrix& obj); ChartableMatrixInterface* m_chartableMatrixInterface; int32_t m_matrixRowIndex; int32_t m_matrixColumnIndex; // ADD_NEW_MEMBERS_HERE }; #ifdef __SELECTION_ITEM_CHART_MATRIX_DECLARE__ // #endif // __SELECTION_ITEM_CHART_MATRIX_DECLARE__ } // namespace #endif //__SELECTION_ITEM_CHART_MATRIX_H__ connectome-workbench-1.4.2/src/Brain/SelectionItemChartTimeSeries.cxx000066400000000000000000000102041360521144700257160ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_CHART_TIME_SERIES_DECLARE__ #include "SelectionItemChartTimeSeries.h" #undef __SELECTION_ITEM_CHART_TIME_SERIES_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::SelectionItemChartTimeSeries * \brief Contains selection of a time-series chart. * \ingroup Brain */ /** * Constructor. */ SelectionItemChartTimeSeries::SelectionItemChartTimeSeries() : SelectionItem(SelectionItemDataTypeEnum::CHART_TIME_SERIES) { m_chartModelTimeSeries = NULL; m_chartDataCartesian = NULL; m_chartDataPointIndex = -1; } /** * Destructor. */ SelectionItemChartTimeSeries::~SelectionItemChartTimeSeries() { } /** * Copy constructor. * @param obj * Object that is copied. */ SelectionItemChartTimeSeries::SelectionItemChartTimeSeries(const SelectionItemChartTimeSeries& obj) : SelectionItem(obj) { this->copyHelperSelectionItemChartTimeSeries(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ SelectionItemChartTimeSeries& SelectionItemChartTimeSeries::operator=(const SelectionItemChartTimeSeries& obj) { if (this != &obj) { SelectionItem::operator=(obj); this->copyHelperSelectionItemChartTimeSeries(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void SelectionItemChartTimeSeries::copyHelperSelectionItemChartTimeSeries(const SelectionItemChartTimeSeries& obj) { m_chartModelTimeSeries = obj.m_chartModelTimeSeries; m_chartDataCartesian = obj.m_chartDataCartesian; m_chartDataPointIndex = obj.m_chartDataPointIndex; } /** * @return True if the selected chart is valid, else false. */ bool SelectionItemChartTimeSeries::isValid() const { if ((m_chartModelTimeSeries != NULL) && (m_chartDataCartesian != NULL) && (m_chartDataPointIndex >= 0)) { return true; } return false; } /** * Reset the selections. */ void SelectionItemChartTimeSeries::reset() { m_chartModelTimeSeries = NULL; m_chartDataCartesian = NULL; m_chartDataPointIndex = -1; } /** * @return */ ChartModelTimeSeries* SelectionItemChartTimeSeries::getChartModelTimeSeries() const { return m_chartModelTimeSeries; } /** * @return */ ChartDataCartesian* SelectionItemChartTimeSeries::getChartDataCartesian() const { return m_chartDataCartesian; } /** * @return */ int32_t SelectionItemChartTimeSeries::getChartDataPointIndex() const { return m_chartDataPointIndex; } /** * Set the selected chart information. * * @param chartModelTimeSeries * Data series chart model that was selected. * @param chartDataCartesian * Cartesian chart data that was selected. * @param chartDataPointIndex * Point index of selected chart data. */ void SelectionItemChartTimeSeries::setChart(ChartModelTimeSeries* chartModelTimeSeries, ChartDataCartesian* chartDataCartesian, const int32_t chartDataPointIndex) { CaretAssert(chartModelTimeSeries); CaretAssert(chartDataCartesian); CaretAssert(chartDataPointIndex >= 0); m_chartModelTimeSeries = chartModelTimeSeries; m_chartDataCartesian = chartDataCartesian; m_chartDataPointIndex = chartDataPointIndex; } connectome-workbench-1.4.2/src/Brain/SelectionItemChartTimeSeries.h000066400000000000000000000046551360521144700253600ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_CHART_TIME_SERIES_H__ #define __SELECTION_ITEM_CHART_TIME_SERIES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SelectionItem.h" namespace caret { class ChartDataCartesian; class ChartModelTimeSeries; class SelectionItemChartTimeSeries : public SelectionItem { public: SelectionItemChartTimeSeries(); virtual ~SelectionItemChartTimeSeries(); SelectionItemChartTimeSeries(const SelectionItemChartTimeSeries& obj); SelectionItemChartTimeSeries& operator=(const SelectionItemChartTimeSeries& obj); virtual bool isValid() const; virtual void reset(); ChartModelTimeSeries* getChartModelTimeSeries() const; ChartDataCartesian* getChartDataCartesian() const; int32_t getChartDataPointIndex() const; void setChart(ChartModelTimeSeries* chartModelTimeSeries, ChartDataCartesian* chartDataCartesian, const int32_t chartDataPointIndex); // ADD_NEW_METHODS_HERE private: void copyHelperSelectionItemChartTimeSeries(const SelectionItemChartTimeSeries& obj); ChartModelTimeSeries* m_chartModelTimeSeries; ChartDataCartesian* m_chartDataCartesian; int32_t m_chartDataPointIndex; // ADD_NEW_MEMBERS_HERE }; #ifdef __SELECTION_ITEM_CHART_TIME_SERIES_DECLARE__ // #endif // __SELECTION_ITEM_CHART_TIME_SERIES_DECLARE__ } // namespace #endif //__SELECTION_ITEM_CHART_TIME_SERIES_H__ connectome-workbench-1.4.2/src/Brain/SelectionItemChartTwoHistogram.cxx000066400000000000000000000112161360521144700263000ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_CHART_TWO_HISTOGRAM_DECLARE__ #include "SelectionItemChartTwoHistogram.h" #undef __SELECTION_ITEM_CHART_TWO_HISTOGRAM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::SelectionItemChartTwoHistogram * \brief Selection of charting two histogram * \ingroup Brain */ /** * Constructor. */ SelectionItemChartTwoHistogram::SelectionItemChartTwoHistogram() : SelectionItem(SelectionItemDataTypeEnum::CHART_TWO_HISTOGRAM) { resetPrivate(); } /** * Destructor. */ SelectionItemChartTwoHistogram::~SelectionItemChartTwoHistogram() { } /** * Copy constructor. * @param obj * Object that is copied. */ SelectionItemChartTwoHistogram::SelectionItemChartTwoHistogram(const SelectionItemChartTwoHistogram& obj) : SelectionItem(obj) { this->copyHelperSelectionItemChartTwoHistogram(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ SelectionItemChartTwoHistogram& SelectionItemChartTwoHistogram::operator=(const SelectionItemChartTwoHistogram& obj) { if (this != &obj) { SelectionItem::operator=(obj); this->copyHelperSelectionItemChartTwoHistogram(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void SelectionItemChartTwoHistogram::copyHelperSelectionItemChartTwoHistogram(const SelectionItemChartTwoHistogram& obj) { m_fileHistogramChart = obj.m_fileHistogramChart; m_mapIndex = obj.m_mapIndex; m_bucketIndex = obj.m_bucketIndex; m_allMapsSelectedFlag = obj.m_allMapsSelectedFlag; } ChartableTwoFileHistogramChart* SelectionItemChartTwoHistogram::getFileHistogramChart() const { return m_fileHistogramChart; } /** * @return Index of map index selected. Also * should test isAllMapsSelected() */ int32_t SelectionItemChartTwoHistogram::getMapIndex() const { return m_mapIndex; } /** * @return Index of histogram bucket selected. */ int32_t SelectionItemChartTwoHistogram::getBucketIndex() const { return m_bucketIndex; } /** * @return Is all maps selected? */ bool SelectionItemChartTwoHistogram::isAllMapsSelected() const { return m_allMapsSelectedFlag; } /* * Set histogram identification. * * @param fileHistogramChart * The histogram chart. * @param mapIndex * Index of the map whose histogram is displayed (negative indicates all maps). * @param bucketIndex * Index of the histogram bucket. * @param allMapsSelected * True if all maps selected, else false. */ void SelectionItemChartTwoHistogram::setHistogramChart(ChartableTwoFileHistogramChart* fileHistogramChart, const int32_t mapIndex, const int32_t bucketIndex, const bool allMapsSelected) { m_fileHistogramChart = fileHistogramChart; m_mapIndex = mapIndex; m_bucketIndex = bucketIndex; m_allMapsSelectedFlag = allMapsSelected; } /** * @return True if the selected chart is valid, else false. */ bool SelectionItemChartTwoHistogram::isValid() const { /* * Map index is negative if all maps selected. */ if ((m_fileHistogramChart != NULL) && (m_bucketIndex >= 0) && ((m_mapIndex >= 0) || m_allMapsSelectedFlag)) { return true; } return false; } /** * Reset the selections PRIVATE. * Note that reset() is virtual and cannot * be called from constructor. */ void SelectionItemChartTwoHistogram::resetPrivate() { m_fileHistogramChart = NULL; m_mapIndex = -1; m_bucketIndex = -1; m_allMapsSelectedFlag = false; } /** * Reset the selections. */ void SelectionItemChartTwoHistogram::reset() { resetPrivate(); } connectome-workbench-1.4.2/src/Brain/SelectionItemChartTwoHistogram.h000066400000000000000000000051131360521144700257240ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_CHART_TWO_HISTOGRAM_H__ #define __SELECTION_ITEM_CHART_TWO_HISTOGRAM_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SelectionItem.h" namespace caret { class ChartableTwoFileHistogramChart; class SelectionItemChartTwoHistogram : public SelectionItem { public: SelectionItemChartTwoHistogram(); virtual ~SelectionItemChartTwoHistogram(); SelectionItemChartTwoHistogram(const SelectionItemChartTwoHistogram& obj); SelectionItemChartTwoHistogram& operator=(const SelectionItemChartTwoHistogram& obj); virtual bool isValid() const override; virtual void reset() override; ChartableTwoFileHistogramChart* getFileHistogramChart() const; int32_t getBucketIndex() const; int32_t getMapIndex() const; bool isAllMapsSelected() const; void setHistogramChart(ChartableTwoFileHistogramChart* fileHistogramChart, const int32_t mapIndex, const int32_t bucketIndex, const bool allMapsSelected); // ADD_NEW_METHODS_HERE private: void copyHelperSelectionItemChartTwoHistogram(const SelectionItemChartTwoHistogram& obj); void resetPrivate(); ChartableTwoFileHistogramChart* m_fileHistogramChart; int32_t m_mapIndex; int32_t m_bucketIndex; bool m_allMapsSelectedFlag; // ADD_NEW_MEMBERS_HERE }; #ifdef __SELECTION_ITEM_CHART_TWO_HISTOGRAM_DECLARE__ // #endif // __SELECTION_ITEM_CHART_TWO_HISTOGRAM_DECLARE__ } // namespace #endif //__SELECTION_ITEM_CHART_TWO_HISTOGRAM_H__ connectome-workbench-1.4.2/src/Brain/SelectionItemChartTwoLabel.cxx000066400000000000000000000074331360521144700253700ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_CHART_TWO_LABEL_DECLARE__ #include "SelectionItemChartTwoLabel.h" #undef __SELECTION_ITEM_CHART_TWO_LABEL_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::SelectionItemChartTwoLabel * \brief Selection of chart version two label * \ingroup Brain */ /** * Constructor. */ SelectionItemChartTwoLabel::SelectionItemChartTwoLabel() : SelectionItem(SelectionItemDataTypeEnum::CHART_TWO_LABEL) { m_chartTwoCartesianAxis = NULL; m_chartTwoOverlaySet = NULL; } /** * Destructor. */ SelectionItemChartTwoLabel::~SelectionItemChartTwoLabel() { } /** * Copy constructor. * @param obj * Object that is copied. */ SelectionItemChartTwoLabel::SelectionItemChartTwoLabel(const SelectionItemChartTwoLabel& obj) : SelectionItem(obj) { this->copyHelperSelectionItemChartTwoLabel(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ SelectionItemChartTwoLabel& SelectionItemChartTwoLabel::operator=(const SelectionItemChartTwoLabel& obj) { if (this != &obj) { SelectionItem::operator=(obj); this->copyHelperSelectionItemChartTwoLabel(obj); } return *this; } /** * @return The cartesian axis. */ const ChartTwoCartesianAxis* SelectionItemChartTwoLabel::getChartTwoCartesianAxis() const { return m_chartTwoCartesianAxis; } /** * @return The cartesian axis. */ ChartTwoCartesianAxis* SelectionItemChartTwoLabel::getChartTwoCartesianAxis() { return m_chartTwoCartesianAxis; } /** * @return The chart overlay set. */ ChartTwoOverlaySet* SelectionItemChartTwoLabel::getChartOverlaySet() { return m_chartTwoOverlaySet; } /** * @return The chart overlay set. */ const ChartTwoOverlaySet* SelectionItemChartTwoLabel::getChartOverlaySet() const { return m_chartTwoOverlaySet; } /** * Set selection. * * @param chartTwoCartesianAxis * The cartesian axis. * @param chartOverlaySet * The chart overlay set */ void SelectionItemChartTwoLabel::setChartTwoCartesianAxis(ChartTwoCartesianAxis* chartTwoCartesianAxis, ChartTwoOverlaySet* chartOverlaySet) { m_chartTwoCartesianAxis = chartTwoCartesianAxis; m_chartTwoOverlaySet = chartOverlaySet; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void SelectionItemChartTwoLabel::copyHelperSelectionItemChartTwoLabel(const SelectionItemChartTwoLabel& obj) { m_chartTwoCartesianAxis = obj.m_chartTwoCartesianAxis; m_chartTwoOverlaySet = obj.m_chartTwoOverlaySet; } /** * @return True if the selected chart label is valid, else false. */ bool SelectionItemChartTwoLabel::isValid() const { return ((m_chartTwoCartesianAxis != NULL) && (m_chartTwoOverlaySet != NULL)); } /** * Reset the selections. */ void SelectionItemChartTwoLabel::reset() { m_chartTwoCartesianAxis = NULL; m_chartTwoOverlaySet = NULL; } connectome-workbench-1.4.2/src/Brain/SelectionItemChartTwoLabel.h000066400000000000000000000046451360521144700250170ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_CHART_TWO_LABEL_H__ #define __SELECTION_ITEM_CHART_TWO_LABEL_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SelectionItem.h" namespace caret { class ChartTwoCartesianAxis; class ChartTwoOverlaySet; class SelectionItemChartTwoLabel : public SelectionItem { public: SelectionItemChartTwoLabel(); virtual ~SelectionItemChartTwoLabel(); SelectionItemChartTwoLabel(const SelectionItemChartTwoLabel& obj); SelectionItemChartTwoLabel& operator=(const SelectionItemChartTwoLabel& obj); virtual bool isValid() const override; virtual void reset() override; const ChartTwoCartesianAxis* getChartTwoCartesianAxis() const; ChartTwoCartesianAxis* getChartTwoCartesianAxis(); const ChartTwoOverlaySet* getChartOverlaySet() const; ChartTwoOverlaySet* getChartOverlaySet(); void setChartTwoCartesianAxis(ChartTwoCartesianAxis* ChartTwoCartesianAxis, ChartTwoOverlaySet* chartOverlaySet); // ADD_NEW_METHODS_HERE private: void copyHelperSelectionItemChartTwoLabel(const SelectionItemChartTwoLabel& obj); ChartTwoCartesianAxis* m_chartTwoCartesianAxis; ChartTwoOverlaySet* m_chartTwoOverlaySet; // ADD_NEW_MEMBERS_HERE }; #ifdef __SELECTION_ITEM_CHART_TWO_LABEL_DECLARE__ // #endif // __SELECTION_ITEM_CHART_TWO_LABEL_DECLARE__ } // namespace #endif //__SELECTION_ITEM_CHART_TWO_LABEL_H__ connectome-workbench-1.4.2/src/Brain/SelectionItemChartTwoLineSeries.cxx000066400000000000000000000101741360521144700264070ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_CHART_TWO_LINE_SERIES_DECLARE__ #include "SelectionItemChartTwoLineSeries.h" #undef __SELECTION_ITEM_CHART_TWO_LINE_SERIES_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::SelectionItemChartTwoLineSeries * \brief Selection of chart version two line series * \ingroup Brain */ /** * Constructor. */ SelectionItemChartTwoLineSeries::SelectionItemChartTwoLineSeries() : SelectionItem(SelectionItemDataTypeEnum::CHART_TWO_LINE_SERIES) { m_fileLineSeriesChart = NULL; m_chartTwoCartesianData = NULL; m_lineSegmentIndex = -1; } /** * Destructor. */ SelectionItemChartTwoLineSeries::~SelectionItemChartTwoLineSeries() { } /** * Copy constructor. * @param obj * Object that is copied. */ SelectionItemChartTwoLineSeries::SelectionItemChartTwoLineSeries(const SelectionItemChartTwoLineSeries& obj) : SelectionItem(obj) { this->copyHelperSelectionItemChartTwoLineSeries(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ SelectionItemChartTwoLineSeries& SelectionItemChartTwoLineSeries::operator=(const SelectionItemChartTwoLineSeries& obj) { if (this != &obj) { SelectionItem::operator=(obj); this->copyHelperSelectionItemChartTwoLineSeries(obj); } return *this; } /** * @return The File line series chart. */ const ChartableTwoFileLineSeriesChart* SelectionItemChartTwoLineSeries::getFileLineSeriesChart() const { return m_fileLineSeriesChart; } /** * @return The cartesian data. */ const ChartTwoDataCartesian* SelectionItemChartTwoLineSeries::getChartTwoCartesianData() const { return m_chartTwoCartesianData; } /** * @return The line segment index. */ int32_t SelectionItemChartTwoLineSeries::getLineSegmentIndex() const { return m_lineSegmentIndex; } /** * Set selection. * * @param fileLineSeriesChart * The line series chart. * @param chartTwoCartesianData * The cartesian data. * @param lineSegmentIndex * Index of the line segment. */ void SelectionItemChartTwoLineSeries::setLineSeriesChart(ChartableTwoFileLineSeriesChart* fileLineSeriesChart, ChartTwoDataCartesian* chartTwoCartesianData, const int32_t lineSegmentIndex) { m_fileLineSeriesChart = fileLineSeriesChart; m_chartTwoCartesianData = chartTwoCartesianData; m_lineSegmentIndex = lineSegmentIndex; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void SelectionItemChartTwoLineSeries::copyHelperSelectionItemChartTwoLineSeries(const SelectionItemChartTwoLineSeries& obj) { m_fileLineSeriesChart = obj.m_fileLineSeriesChart; m_chartTwoCartesianData = obj.m_chartTwoCartesianData; m_lineSegmentIndex = obj.m_lineSegmentIndex; } /** * @return True if the selected chart is valid, else false. */ bool SelectionItemChartTwoLineSeries::isValid() const { return ((m_fileLineSeriesChart != NULL) && (m_chartTwoCartesianData != NULL) && (m_lineSegmentIndex >= 0)); } /** * Reset the selections. */ void SelectionItemChartTwoLineSeries::reset() { m_fileLineSeriesChart = NULL; m_chartTwoCartesianData = NULL; m_lineSegmentIndex = -1; } connectome-workbench-1.4.2/src/Brain/SelectionItemChartTwoLineSeries.h000066400000000000000000000051051360521144700260320ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_CHART_TWO_LINE_SERIES_H__ #define __SELECTION_ITEM_CHART_TWO_LINE_SERIES_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SelectionItem.h" namespace caret { class ChartTwoDataCartesian; class ChartableTwoFileLineSeriesChart; class SelectionItemChartTwoLineSeries : public SelectionItem { public: SelectionItemChartTwoLineSeries(); virtual ~SelectionItemChartTwoLineSeries(); SelectionItemChartTwoLineSeries(const SelectionItemChartTwoLineSeries& obj); SelectionItemChartTwoLineSeries& operator=(const SelectionItemChartTwoLineSeries& obj); virtual bool isValid() const override; virtual void reset() override; const ChartableTwoFileLineSeriesChart* getFileLineSeriesChart() const; const ChartTwoDataCartesian* getChartTwoCartesianData() const; int32_t getLineSegmentIndex() const; void setLineSeriesChart(ChartableTwoFileLineSeriesChart* fileLineSeriesChart, ChartTwoDataCartesian* chartTwoCartesianData, const int32_t lineSegmentIndex); // ADD_NEW_METHODS_HERE private: void copyHelperSelectionItemChartTwoLineSeries(const SelectionItemChartTwoLineSeries& obj); ChartableTwoFileLineSeriesChart* m_fileLineSeriesChart; ChartTwoDataCartesian* m_chartTwoCartesianData; int32_t m_lineSegmentIndex; // ADD_NEW_MEMBERS_HERE }; #ifdef __SELECTION_ITEM_CHART_TWO_LINE_SERIES_DECLARE__ // #endif // __SELECTION_ITEM_CHART_TWO_LINE_SERIES_DECLARE__ } // namespace #endif //__SELECTION_ITEM_CHART_TWO_LINE_SERIES_H__ connectome-workbench-1.4.2/src/Brain/SelectionItemChartTwoMatrix.cxx000066400000000000000000000074221360521144700256130ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_CHART_TWO_MATRIX_DECLARE__ #include "SelectionItemChartTwoMatrix.h" #undef __SELECTION_ITEM_CHART_TWO_MATRIX_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::SelectionItemChartTwoMatrix * \brief Selection of chart two matrix * \ingroup Brain */ /** * Constructor. */ SelectionItemChartTwoMatrix::SelectionItemChartTwoMatrix() : SelectionItem(SelectionItemDataTypeEnum::CHART_TWO_MATRIX) { m_fileMatrixChart = NULL; m_rowIndex = -1; m_columnIndex = -1; } /** * Destructor. */ SelectionItemChartTwoMatrix::~SelectionItemChartTwoMatrix() { } /** * Copy constructor. * @param obj * Object that is copied. */ SelectionItemChartTwoMatrix::SelectionItemChartTwoMatrix(const SelectionItemChartTwoMatrix& obj) : SelectionItem(obj) { this->copyHelperSelectionItemChartTwoMatrix(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ SelectionItemChartTwoMatrix& SelectionItemChartTwoMatrix::operator=(const SelectionItemChartTwoMatrix& obj) { if (this != &obj) { SelectionItem::operator=(obj); this->copyHelperSelectionItemChartTwoMatrix(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void SelectionItemChartTwoMatrix::copyHelperSelectionItemChartTwoMatrix(const SelectionItemChartTwoMatrix& obj) { m_fileMatrixChart = obj.m_fileMatrixChart; m_rowIndex = obj.m_rowIndex; m_columnIndex = obj.m_columnIndex; } /** * @return True if the selected chart is valid, else false. */ bool SelectionItemChartTwoMatrix::isValid() const { if ((m_fileMatrixChart != NULL) && (m_rowIndex >= 0) && (m_columnIndex >= 0)) { return true; } return false; } /** * Reset the selections. */ void SelectionItemChartTwoMatrix::reset() { m_fileMatrixChart = NULL; m_rowIndex = -1; m_columnIndex = -1; } /** * @return Matrix chart that was selected. */ ChartableTwoFileMatrixChart* SelectionItemChartTwoMatrix::getFileMatrixChart() const { return m_fileMatrixChart; } /** * @return Row index selected. */ int32_t SelectionItemChartTwoMatrix::getRowIndex() const { return m_rowIndex; } /** * @return column index selected. */ int32_t SelectionItemChartTwoMatrix::getColumnIndex() const { return m_columnIndex; } /** * Set the matrix chart. * * @param fileMatrixChart * Matrix chart that was selected. * @param rowIndex * Index of row selected. * @param columnIndex * Index of column selected. */ void SelectionItemChartTwoMatrix::setMatrixChart(ChartableTwoFileMatrixChart* fileMatrixChart, const int32_t rowIndex, const int32_t columnIndex) { m_fileMatrixChart = fileMatrixChart; m_rowIndex = rowIndex; m_columnIndex = columnIndex; } connectome-workbench-1.4.2/src/Brain/SelectionItemChartTwoMatrix.h000066400000000000000000000045261360521144700252420ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_CHART_TWO_MATRIX_H__ #define __SELECTION_ITEM_CHART_TWO_MATRIX_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SelectionItem.h" namespace caret { class ChartableTwoFileMatrixChart; class SelectionItemChartTwoMatrix : public SelectionItem { public: SelectionItemChartTwoMatrix(); virtual ~SelectionItemChartTwoMatrix(); SelectionItemChartTwoMatrix(const SelectionItemChartTwoMatrix& obj); SelectionItemChartTwoMatrix& operator=(const SelectionItemChartTwoMatrix& obj); virtual bool isValid() const override; virtual void reset() override; ChartableTwoFileMatrixChart* getFileMatrixChart() const; int32_t getRowIndex() const; int32_t getColumnIndex() const; void setMatrixChart(ChartableTwoFileMatrixChart* fileMatrixChart, const int32_t rowIndex, const int32_t columnIndex); // ADD_NEW_METHODS_HERE private: void copyHelperSelectionItemChartTwoMatrix(const SelectionItemChartTwoMatrix& obj); ChartableTwoFileMatrixChart* m_fileMatrixChart; int32_t m_rowIndex; int32_t m_columnIndex; // ADD_NEW_MEMBERS_HERE }; #ifdef __SELECTION_ITEM_CHART_TWO_MATRIX_DECLARE__ // #endif // __SELECTION_ITEM_CHART_TWO_MATRIX_DECLARE__ } // namespace #endif //__SELECTION_ITEM_CHART_TWO_MATRIX_H__ connectome-workbench-1.4.2/src/Brain/SelectionItemCiftiConnectivityMatrixRowColumn.cxx000066400000000000000000000126711360521144700313650ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_CIFTI_CONNECTIVITY_MATRIX_ROW_COLUMN_DECLARE__ #include "SelectionItemCiftiConnectivityMatrixRowColumn.h" #undef __SELECTION_ITEM_CIFTI_CONNECTIVITY_MATRIX_ROW_COLUMN_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::SelectionItemCiftiConnectivityMatrixRowColumn * \brief Contains selection of a row or column in a CIFTI connectivity matrix file. * \ingroup Brain */ /** * Constructor. */ SelectionItemCiftiConnectivityMatrixRowColumn::SelectionItemCiftiConnectivityMatrixRowColumn() : SelectionItem(SelectionItemDataTypeEnum::CIFTI_CONNECTIVITY_MATRIX_ROW_COLUMN) { m_ciftiConnectivityMatrixFile = NULL; m_matrixRowIndex = -1; m_matrixColumnIndex = -1; } /** * Destructor. */ SelectionItemCiftiConnectivityMatrixRowColumn::~SelectionItemCiftiConnectivityMatrixRowColumn() { } /** * Copy constructor. * @param obj * Object that is copied. */ SelectionItemCiftiConnectivityMatrixRowColumn::SelectionItemCiftiConnectivityMatrixRowColumn(const SelectionItemCiftiConnectivityMatrixRowColumn& obj) : SelectionItem(obj) { this->copyHelperSelectionItemCiftiConnectivityMatrixRowColumn(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ SelectionItemCiftiConnectivityMatrixRowColumn& SelectionItemCiftiConnectivityMatrixRowColumn::operator=(const SelectionItemCiftiConnectivityMatrixRowColumn& obj) { if (this != &obj) { SelectionItem::operator=(obj); this->copyHelperSelectionItemCiftiConnectivityMatrixRowColumn(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void SelectionItemCiftiConnectivityMatrixRowColumn::copyHelperSelectionItemCiftiConnectivityMatrixRowColumn(const SelectionItemCiftiConnectivityMatrixRowColumn& obj) { m_ciftiConnectivityMatrixFile = obj.m_ciftiConnectivityMatrixFile; m_matrixRowIndex = obj.m_matrixRowIndex; m_matrixColumnIndex = obj.m_matrixColumnIndex; } /** * @return True if the CIFTI connectivity matrix row or column is valid, else false. */ bool SelectionItemCiftiConnectivityMatrixRowColumn::isValid() const { if (m_ciftiConnectivityMatrixFile != NULL) { if ((m_matrixRowIndex >= 0) || (m_matrixColumnIndex >= 0)) { return true; } } return false; } /** * Reset the selections. */ void SelectionItemCiftiConnectivityMatrixRowColumn::reset() { m_ciftiConnectivityMatrixFile = NULL; m_matrixRowIndex = -1; m_matrixColumnIndex = -1; } /** * @return CIFTI connectivity matrix file. */ CiftiMappableConnectivityMatrixDataFile* SelectionItemCiftiConnectivityMatrixRowColumn::getCiftiConnectivityMatrixFile() const { return m_ciftiConnectivityMatrixFile; } /** * @return CIFTI connectivity matrix row index. A negative value * indicates that the row index is invalid. */ int32_t SelectionItemCiftiConnectivityMatrixRowColumn::getMatrixRowIndex() const { return m_matrixRowIndex; } /** * @return CIFTI connectivity matrix column index. A negative value * indicates that the column index is invalid. */ int32_t SelectionItemCiftiConnectivityMatrixRowColumn::getMatrixColumnIndex() const { return m_matrixColumnIndex; } /** * Set the selection to a CIFTI connectivity matrix file row. * * @param ciftiConnectivityMatrixFile * The CIFTI connectivity matrix file * @param matrixRowIndex * Row index */ void SelectionItemCiftiConnectivityMatrixRowColumn::setFileRow(CiftiMappableConnectivityMatrixDataFile* ciftiConnectivityMatrixFile, const int32_t matrixRowIndex) { CaretAssert(ciftiConnectivityMatrixFile); CaretAssert(matrixRowIndex >= 0); m_ciftiConnectivityMatrixFile = ciftiConnectivityMatrixFile; m_matrixRowIndex = matrixRowIndex; m_matrixColumnIndex = -1; } /** * Set the selection to a CIFTI connectivity matrix file column. * * @param ciftiConnectivityMatrixFile * The CIFTI connectivity matrix file * @param matrixColumnIndex * Column index */ void SelectionItemCiftiConnectivityMatrixRowColumn::setFileColumn(CiftiMappableConnectivityMatrixDataFile* ciftiConnectivityMatrixFile, const int32_t matrixColumnIndex) { CaretAssert(ciftiConnectivityMatrixFile); CaretAssert(matrixColumnIndex >= 0); m_ciftiConnectivityMatrixFile = ciftiConnectivityMatrixFile; m_matrixRowIndex = -1; m_matrixColumnIndex = matrixColumnIndex; } connectome-workbench-1.4.2/src/Brain/SelectionItemCiftiConnectivityMatrixRowColumn.h000066400000000000000000000055201360521144700310050ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_CIFTI_CONNECTIVITY_MATRIX_ROW_COLUMN_H__ #define __SELECTION_ITEM_CIFTI_CONNECTIVITY_MATRIX_ROW_COLUMN_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SelectionItem.h" namespace caret { class CiftiMappableConnectivityMatrixDataFile; class SelectionItemCiftiConnectivityMatrixRowColumn : public SelectionItem { public: SelectionItemCiftiConnectivityMatrixRowColumn(); virtual ~SelectionItemCiftiConnectivityMatrixRowColumn(); SelectionItemCiftiConnectivityMatrixRowColumn(const SelectionItemCiftiConnectivityMatrixRowColumn& obj); SelectionItemCiftiConnectivityMatrixRowColumn& operator=(const SelectionItemCiftiConnectivityMatrixRowColumn& obj); virtual bool isValid() const; virtual void reset(); CiftiMappableConnectivityMatrixDataFile* getCiftiConnectivityMatrixFile() const; int32_t getMatrixRowIndex() const; int32_t getMatrixColumnIndex() const; void setFileRow(CiftiMappableConnectivityMatrixDataFile* ciftiConnectivityMatrixFile, const int32_t matrixRowIndex); void setFileColumn(CiftiMappableConnectivityMatrixDataFile* ciftiConnectivityMatrixFile, const int32_t matrixColumnIndex); // ADD_NEW_METHODS_HERE private: void copyHelperSelectionItemCiftiConnectivityMatrixRowColumn(const SelectionItemCiftiConnectivityMatrixRowColumn& obj); CiftiMappableConnectivityMatrixDataFile* m_ciftiConnectivityMatrixFile; int32_t m_matrixRowIndex; int32_t m_matrixColumnIndex; // ADD_NEW_MEMBERS_HERE }; #ifdef __SELECTION_ITEM_CIFTI_CONNECTIVITY_MATRIX_ROW_COLUMN_DECLARE__ // #endif // __SELECTION_ITEM_CIFTI_CONNECTIVITY_MATRIX_ROW_COLUMN_DECLARE__ } // namespace #endif //__SELECTION_ITEM_CIFTI_CONNECTIVITY_MATRIX_ROW_COLUMN_H__ connectome-workbench-1.4.2/src/Brain/SelectionItemDataTypeEnum.cxx000066400000000000000000000324771360521144700252430ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __SELECTION_ITEM_DATA_TYPE_ENUM_DECLARE__ #include "SelectionItemDataTypeEnum.h" #undef __SELECTION_ITEM_DATA_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ SelectionItemDataTypeEnum::SelectionItemDataTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ SelectionItemDataTypeEnum::~SelectionItemDataTypeEnum() { } /** * Initialize the enumerated metadata. */ void SelectionItemDataTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(SelectionItemDataTypeEnum(INVALID, "INVALID", "Invalid")); enumData.push_back(SelectionItemDataTypeEnum(ANNOTATION, "ANNOTATION", "Annotation")); enumData.push_back(SelectionItemDataTypeEnum(BORDER_SURFACE, "BORDER_SURFACE", "Surface Border")); enumData.push_back(SelectionItemDataTypeEnum(BORDER_VOLUME, "BORDER_VOLUME", "Volume Border")); enumData.push_back(SelectionItemDataTypeEnum(CHART_DATA_SERIES, "CHART_DATA_SERIES", "Data-Series Chart")); enumData.push_back(SelectionItemDataTypeEnum(CHART_FREQUENCY_SERIES, "CHART_FREQUENCY_SERIES", "Frequency-Series Chart")); enumData.push_back(SelectionItemDataTypeEnum(CHART_MATRIX, "CHART_MATRIX", "Matrix Chart")); enumData.push_back(SelectionItemDataTypeEnum(CHART_TIME_SERIES, "CHART_TIME_SERIES", "Time-Series Chart")); enumData.push_back(SelectionItemDataTypeEnum(CHART_TWO_HISTOGRAM, "CHART_TWO_HISTOGRAM", "Histogram Chart Two")); enumData.push_back(SelectionItemDataTypeEnum(CHART_TWO_LINE_SERIES, "CHART_TWO_LINE_SERIES", "Line-Series Chart Two")); enumData.push_back(SelectionItemDataTypeEnum(CHART_TWO_LABEL, "CHART_TWO_LABEL", "Label Chart Two")); enumData.push_back(SelectionItemDataTypeEnum(CHART_TWO_MATRIX, "CHART_TWO_MATRIX", "Matrix Chart Two")); enumData.push_back(SelectionItemDataTypeEnum(CIFTI_CONNECTIVITY_MATRIX_ROW_COLUMN, "CIFTI_CONNECTIVITY_MATRIX_ROW_COLUMN", "CIFTI Connectivity Row or Column")); enumData.push_back(SelectionItemDataTypeEnum(FOCUS_SURFACE, "FOCUS_SURFACE", "Surface Focus")); enumData.push_back(SelectionItemDataTypeEnum(FOCUS_VOLUME, "FOCUS_VOLUME", "Volume Focus")); enumData.push_back(SelectionItemDataTypeEnum(IMAGE, "IMAGE", "Image")); enumData.push_back(SelectionItemDataTypeEnum(IMAGE_CONTROL_POINT, "IMAGE_CONTROL_POINT", "Image Control Point")); enumData.push_back(SelectionItemDataTypeEnum(SURFACE_NODE, "SURFACE_NODE", "Surface Vertex")); enumData.push_back(SelectionItemDataTypeEnum(SURFACE_NODE_IDENTIFICATION_SYMBOL, "SURFACE_NODE_IDENTIFICATION_SYMBOL", "Surface Vertex Identification Symbol")); enumData.push_back(SelectionItemDataTypeEnum(SURFACE_TRIANGLE, "SURFACE_TRIANGLE", "Surface Triangle")); enumData.push_back(SelectionItemDataTypeEnum(VOXEL, "VOXEL", "Voxel")); enumData.push_back(SelectionItemDataTypeEnum(VOXEL_EDITING, "VOXEL_EDITING", "Voxel Editing")); enumData.push_back(SelectionItemDataTypeEnum(VOXEL_IDENTIFICATION_SYMBOL, "VOXEL_IDENTIFICATION_SYMBOL", "Voxel Identification Symbol")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const SelectionItemDataTypeEnum* SelectionItemDataTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const SelectionItemDataTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString SelectionItemDataTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const SelectionItemDataTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ SelectionItemDataTypeEnum::Enum SelectionItemDataTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = INVALID; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SelectionItemDataTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type SelectionItemDataTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString SelectionItemDataTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const SelectionItemDataTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param guiName * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ SelectionItemDataTypeEnum::Enum SelectionItemDataTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = INVALID; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SelectionItemDataTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type SelectionItemDataTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t SelectionItemDataTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const SelectionItemDataTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ SelectionItemDataTypeEnum::Enum SelectionItemDataTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = INVALID; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SelectionItemDataTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type SelectionItemDataTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void SelectionItemDataTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void SelectionItemDataTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(SelectionItemDataTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allGuiNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void SelectionItemDataTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(SelectionItemDataTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Brain/SelectionItemDataTypeEnum.h000066400000000000000000000110711360521144700246530ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_DATA_TYPE_ENUM__H_ #define __SELECTION_ITEM_DATA_TYPE_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { /** * \class SelectionItemDataTypeEnum * \brief Enumerated type for selected items * * Enumerated data type for selected items. */ class SelectionItemDataTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Invalid */ INVALID, /** Annotation */ ANNOTATION, /** Border on Surface */ BORDER_SURFACE, /** Border on Volume Slice */ BORDER_VOLUME, /** Data-Series Chart */ CHART_DATA_SERIES, /** Frequency-Series Chart */ CHART_FREQUENCY_SERIES, /** Matrix chart */ CHART_MATRIX, /** Time-Series Chart */ CHART_TIME_SERIES, /** Version Two Chart Histogram */ CHART_TWO_HISTOGRAM, /** Version Two Chart Label */ CHART_TWO_LABEL, /** Version Two Chart Line-Series */ CHART_TWO_LINE_SERIES, /** Version Two Chart Matrix */ CHART_TWO_MATRIX, /** CIFTI Connectivity Matrix Row or Column */ CIFTI_CONNECTIVITY_MATRIX_ROW_COLUMN, /** Focus on Surface */ FOCUS_SURFACE, /** Focus on Volume */ FOCUS_VOLUME, /* Image */ IMAGE, /* Image Control Point */ IMAGE_CONTROL_POINT, /** Surface Node*/ SURFACE_NODE, /** Surface Node Identification Symbol */ SURFACE_NODE_IDENTIFICATION_SYMBOL, /** Surface Triangle */ SURFACE_TRIANGLE, /** Volume Voxel */ VOXEL, /** Voxel Editing */ VOXEL_EDITING, /** Voxel identification symbol */ VOXEL_IDENTIFICATION_SYMBOL }; ~SelectionItemDataTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: SelectionItemDataTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const SelectionItemDataTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __SELECTION_ITEM_DATA_TYPE_ENUM_DECLARE__ std::vector SelectionItemDataTypeEnum::enumData; bool SelectionItemDataTypeEnum::initializedFlag = false; int32_t SelectionItemDataTypeEnum::integerCodeCounter = 0; #endif // __SELECTION_ITEM_DATA_TYPE_ENUM_DECLARE__ } // namespace #endif //__SELECTION_ITEM_DATA_TYPE_ENUM__H_ connectome-workbench-1.4.2/src/Brain/SelectionItemFocusSurface.cxx000066400000000000000000000113151360521144700252570ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_FOCUS_SURFACE_DECLARE__ #include "SelectionItemFocusSurface.h" #undef __SELECTION_ITEM_FOCUS_SURFACE_DECLARE__ #include "FociFile.h" #include "Focus.h" #include "Surface.h" using namespace caret; /** * \class SelectionItemFocusSurface * \brief Contains information about the selected focus. */ /** * Constructor. */ SelectionItemFocusSurface::SelectionItemFocusSurface() : SelectionItem(SelectionItemDataTypeEnum::FOCUS_SURFACE) { this->surface = NULL; this->focus = NULL; this->fociFile = NULL; this->focusIndex = -1; this->focusProjectionIndex = -1; } /** * Destructor. */ SelectionItemFocusSurface::~SelectionItemFocusSurface() { } /** * Reset this selection item. */ void SelectionItemFocusSurface::reset() { SelectionItem::reset(); this->surface = NULL; this->focus = NULL; this->fociFile = NULL; this->focusIndex = -1; this->focusProjectionIndex = -1; } /** * @return Is this selected item valid? */ bool SelectionItemFocusSurface::isValid() const { return (this->focus != NULL); } /** * @return Surface on which focus was drawn. */ const Surface* SelectionItemFocusSurface::getSurface() const { return this->surface; } /** * @return Surface on which focus was drawn. */ Surface* SelectionItemFocusSurface::getSurface() { return this->surface; } /** * Set the surface on which focus was drawn. * @param surface * New value for surface. */ void SelectionItemFocusSurface::setSurface(Surface* surface) { this->surface = surface; } /** * @return The focus that was selected. */ const Focus* SelectionItemFocusSurface::getFocus() const { return this->focus; } /** * @return The focus that was selected. */ Focus* SelectionItemFocusSurface::getFocus() { return this->focus; } /** * Set the focus that was selected. * @param focus * New value for focus. */ void SelectionItemFocusSurface::setFocus(Focus* focus) { this->focus = focus; } /** * @return The focus file containing focus that was selected. */ const FociFile* SelectionItemFocusSurface::getFociFile() const { return this->fociFile; } /** * @return The focus file containing focus that was selected. */ FociFile* SelectionItemFocusSurface::getFociFile() { return this->fociFile; } /** * Set the focus file containing focus that was selected. * @param fociFile * New value for focus file. */ void SelectionItemFocusSurface::setFociFile(FociFile* fociFile) { this->fociFile = fociFile; } /** * return Index of selected focus. */ int32_t SelectionItemFocusSurface::getFocusIndex() const { return this->focusIndex; } /** * Set index of selected focus. * @param focusIndex * New value for focus index. */ void SelectionItemFocusSurface::setFocusIndex(const int32_t focusIndex) { this->focusIndex = focusIndex; } /** * return Projection Index of selected focus. */ int32_t SelectionItemFocusSurface::getFocusProjectionIndex() const { return this->focusProjectionIndex; } /** * Set projection index of selected focus. * @param focusProjectionIndex * New value for focus index. */ void SelectionItemFocusSurface::setFocusProjectionIndex(const int32_t focusProjectionIndex) { this->focusProjectionIndex = focusProjectionIndex; } /** * Get a description of m_ object's content. * @return String describing m_ object's content. */ AString SelectionItemFocusSurface::toString() const { AString text = SelectionItem::toString(); text += ("Surface: " + ((surface != NULL) ? surface->getFileNameNoPath() : "INVALID") + "\n"); text += ("Foci File: " + ((fociFile != NULL) ? fociFile->getFileNameNoPath() : "INVALID") + "\n"); text += ("Focus: " + ((focus != NULL) ? focus->getName() : "INVALID") + "\n"); text += ("Focus Index: " + AString::number(focusIndex) + "\n"); text += ("Focus Projection Index: " + AString::number(focusProjectionIndex) + "\n"); return text; } connectome-workbench-1.4.2/src/Brain/SelectionItemFocusSurface.h000066400000000000000000000047571360521144700247200ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_FOCUS_SURFACE__H_ #define __SELECTION_ITEM_FOCUS_SURFACE__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SelectionItem.h" namespace caret { class Focus; class FociFile; class Surface; class SelectionItemFocusSurface : public SelectionItem { public: SelectionItemFocusSurface(); virtual ~SelectionItemFocusSurface(); virtual bool isValid() const; Surface* getSurface(); const Surface* getSurface() const; Focus* getFocus(); const Focus* getFocus() const; void setFocus(Focus* focus); FociFile* getFociFile(); const FociFile* getFociFile() const; void setFociFile(FociFile* fociFile); void setSurface(Surface* surface); int32_t getFocusIndex() const; void setFocusIndex(const int32_t focusIndex); int32_t getFocusProjectionIndex() const; void setFocusProjectionIndex(const int32_t focusIndex); void reset(); virtual AString toString() const; private: SelectionItemFocusSurface(const SelectionItemFocusSurface&); SelectionItemFocusSurface& operator=(const SelectionItemFocusSurface&); Focus* focus; FociFile* fociFile; Surface* surface; int32_t focusIndex; int32_t focusProjectionIndex; }; #ifdef __SELECTION_ITEM_FOCUS_SURFACE_DECLARE__ // #endif // __SELECTION_ITEM_FOCUS_SURFACE_DECLARE__ } // namespace #endif //__SELECTION_ITEM_FOCUS_SURFACE__H_ connectome-workbench-1.4.2/src/Brain/SelectionItemFocusVolume.cxx000066400000000000000000000117211360521144700251370ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_FOCUS_VOLUME_DECLARE__ #include "SelectionItemFocusVolume.h" #undef __SELECTION_ITEM_FOCUS_VOLUME_DECLARE__ #include "Focus.h" #include "FociFile.h" #include "VolumeFile.h" using namespace caret; /** * \class SelectionItemFocusVolume * \brief Contains information about the selected focus. */ /** * Constructor. */ SelectionItemFocusVolume::SelectionItemFocusVolume() : SelectionItem(SelectionItemDataTypeEnum::FOCUS_VOLUME) { this->volumeFile = NULL; this->focus = NULL; this->fociFile = NULL; this->focusIndex = -1; this->focusProjectionIndex = -1; } /** * Destructor. */ SelectionItemFocusVolume::~SelectionItemFocusVolume() { } /** * Reset this selection item. */ void SelectionItemFocusVolume::reset() { SelectionItem::reset(); this->volumeFile = NULL; this->focus = NULL; this->fociFile = NULL; this->focusIndex = -1; this->focusProjectionIndex = -1; } /** * @return Is this selected item valid? */ bool SelectionItemFocusVolume::isValid() const { return (this->focus != NULL); } /** * @return VolumeFile on which focus was drawn. */ const VolumeMappableInterface* SelectionItemFocusVolume::getVolumeFile() const { return this->volumeFile; } /** * @return VolumeFile on which focus was drawn. */ VolumeMappableInterface* SelectionItemFocusVolume::getVolumeFile() { return this->volumeFile; } /** * Set the volume file on which focus was drawn. * @param volumeFile * New value for volumeFile. */ void SelectionItemFocusVolume::setVolumeFile(VolumeMappableInterface* volumeFile) { this->volumeFile = volumeFile; } /** * @return The focus that was selected. */ const Focus* SelectionItemFocusVolume::getFocus() const { return this->focus; } /** * @return The focus that was selected. */ Focus* SelectionItemFocusVolume::getFocus() { return this->focus; } /** * Set the focus that was selected. * @param focus * New value for focus. */ void SelectionItemFocusVolume::setFocus(Focus* focus) { this->focus = focus; } /** * @return The focus file containing focus that was selected. */ const FociFile* SelectionItemFocusVolume::getFociFile() const { return this->fociFile; } /** * @return The focus file containing focus that was selected. */ FociFile* SelectionItemFocusVolume::getFociFile() { return this->fociFile; } /** * Set the focus file containing focus that was selected. * @param fociFile * New value for focus file. */ void SelectionItemFocusVolume::setFociFile(FociFile* fociFile) { this->fociFile = fociFile; } /** * return Index of selected focus. */ int32_t SelectionItemFocusVolume::getFocusIndex() const { return this->focusIndex; } /** * Set index of selected focus. * @param focusIndex * New value for focus index. */ void SelectionItemFocusVolume::setFocusIndex(const int32_t focusIndex) { this->focusIndex = focusIndex; } /** * return Projection Index of selected focus. */ int32_t SelectionItemFocusVolume::getFocusProjectionIndex() const { return this->focusProjectionIndex; } /** * Set projection index of selected focus. * @param focusProjectionIndex * New value for focus index. */ void SelectionItemFocusVolume::setFocusProjectionIndex(const int32_t focusProjectionIndex) { this->focusProjectionIndex = focusProjectionIndex; } /** * Get a description of m_ object's content. * @return String describing m_ object's content. */ AString SelectionItemFocusVolume::toString() const { AString name = "INVALID"; if (volumeFile != NULL) { CaretMappableDataFile* cmdf = dynamic_cast(volumeFile); if (cmdf != NULL) { name = cmdf->getFileNameNoPath(); } } AString text = SelectionItem::toString(); text += ("Volume File: " + name + "\n"); text += ("Foci File: " + ((fociFile != NULL) ? fociFile->getFileNameNoPath() : "INVALID") + "\n"); text += ("Focus: " + ((focus != NULL) ? focus->getName() : "INVALID") + "\n"); text += ("Focus Index: " + AString::number(focusIndex) + "\n"); text += ("Focus Projection Index: " + AString::number(focusProjectionIndex) + "\n"); return text; } connectome-workbench-1.4.2/src/Brain/SelectionItemFocusVolume.h000066400000000000000000000051011360521144700245570ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_FOCUS_VOLUME__H_ #define __SELECTION_ITEM_FOCUS_VOLUME__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SelectionItem.h" namespace caret { class Focus; class FociFile; class VolumeMappableInterface; class SelectionItemFocusVolume : public SelectionItem { public: SelectionItemFocusVolume(); virtual ~SelectionItemFocusVolume(); virtual bool isValid() const; VolumeMappableInterface* getVolumeFile(); const VolumeMappableInterface* getVolumeFile() const; Focus* getFocus(); const Focus* getFocus() const; void setFocus(Focus* focus); FociFile* getFociFile(); const FociFile* getFociFile() const; void setFociFile(FociFile* fociFile); void setVolumeFile(VolumeMappableInterface* volumeFile); int32_t getFocusIndex() const; void setFocusIndex(const int32_t focusIndex); int32_t getFocusProjectionIndex() const; void setFocusProjectionIndex(const int32_t focusIndex); void reset(); virtual AString toString() const; private: SelectionItemFocusVolume(const SelectionItemFocusVolume&); SelectionItemFocusVolume& operator=(const SelectionItemFocusVolume&); Focus* focus; FociFile* fociFile; VolumeMappableInterface* volumeFile; int32_t focusIndex; int32_t focusProjectionIndex; }; #ifdef __SELECTION_ITEM_FOCUS_VOLUME_DECLARE__ // #endif // __SELECTION_ITEM_FOCUS_VOLUME_DECLARE__ } // namespace #endif //__SELECTION_ITEM_FOCUS_VOLUME__H_ connectome-workbench-1.4.2/src/Brain/SelectionItemImage.cxx000066400000000000000000000072501360521144700237140ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_IMAGE_DECLARE__ #include "SelectionItemImage.h" #undef __SELECTION_ITEM_IMAGE_DECLARE__ #include "ImageFile.h" using namespace caret; /** * \class SelectionItemImage * \brief Contains information about the selected image. */ /** * Constructor. */ SelectionItemImage::SelectionItemImage() : SelectionItem(SelectionItemDataTypeEnum::IMAGE) { m_imageFile = NULL; m_pixelI = -1; m_pixelJ = -1; m_pixelRGBA[0] = 0; m_pixelRGBA[1] = 0; m_pixelRGBA[2] = 0; m_pixelRGBA[3] = 0; } /** * Destructor. */ SelectionItemImage::~SelectionItemImage() { } /** * @return Pixel I. */ int32_t SelectionItemImage::getPixelI() const { return m_pixelI; } /** * @return Pixel J. */ int32_t SelectionItemImage::getPixelJ() const { return m_pixelJ; } /** * Set pixel I * * @param i * Value for I. */ void SelectionItemImage::setPixelI(const int32_t i) { m_pixelI = i; } /** * Set pixel J * * @param j * Value for J. */ void SelectionItemImage::setPixelJ(const int32_t j) { m_pixelJ = j; } /** * Get the pixel RGBA value. * * @param pixelRGBAOut * Output containing pixel RGBA. */ void SelectionItemImage::getPixelRGBA(uint8_t pixelRGBAOut[4]) const { pixelRGBAOut[0] = m_pixelRGBA[0]; pixelRGBAOut[1] = m_pixelRGBA[1]; pixelRGBAOut[2] = m_pixelRGBA[2]; pixelRGBAOut[3] = m_pixelRGBA[3]; } /** * Set the pixel RGBA value. * * @param pixelRGBA * Pixel RGBA. */ void SelectionItemImage::setPixelRGBA(const uint8_t pixelRGBA[4]) { m_pixelRGBA[0] = pixelRGBA[0]; m_pixelRGBA[1] = pixelRGBA[1]; m_pixelRGBA[2] = pixelRGBA[2]; m_pixelRGBA[3] = pixelRGBA[3]; } /** * Reset this selection item. */ void SelectionItemImage::reset() { SelectionItem::reset(); m_imageFile = NULL; m_pixelI = -1; m_pixelJ = -1; m_pixelRGBA[0] = 0; m_pixelRGBA[1] = 0; m_pixelRGBA[2] = 0; m_pixelRGBA[3] = 0; } /** * @return Is this selected item valid? */ bool SelectionItemImage::isValid() const { return (m_imageFile != NULL); } /** * @return Image that was selected (NULL if not valid). */ const ImageFile* SelectionItemImage::getImageFile() const { return m_imageFile; } /** * @return Image that was selected (NULL if not valid). */ ImageFile* SelectionItemImage::getImageFile() { return m_imageFile; } /** * Set the image that was selected. * * @param imageFile * Pointer to selected image (NULL if not valid). */ void SelectionItemImage::setImageFile(ImageFile* imageFile) { m_imageFile = imageFile; } /** * Get a description of m_ object's content. * @return String describing m_ object's content. */ AString SelectionItemImage::toString() const { AString text = SelectionItem::toString(); text += ("ImageFile: " + ((m_imageFile != NULL) ? m_imageFile->getFileNameNoPath() : "INVALID") + "\n"); return text; } connectome-workbench-1.4.2/src/Brain/SelectionItemImage.h000066400000000000000000000042761360521144700233460ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_IMAGE__H_ #define __SELECTION_ITEM_IMAGE__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SelectionItem.h" namespace caret { class ImageFile; class SelectionItemImage : public SelectionItem { public: SelectionItemImage(); virtual ~SelectionItemImage(); virtual bool isValid() const; ImageFile* getImageFile(); const ImageFile* getImageFile() const; void setImageFile(ImageFile* imageFile); int32_t getPixelI() const; int32_t getPixelJ() const; void setPixelI(const int32_t i); void setPixelJ(const int32_t j); void getPixelRGBA(uint8_t pixelRGBAOut[4]) const; void setPixelRGBA(const uint8_t pixelRGBA[4]); virtual void reset(); virtual AString toString() const; private: SelectionItemImage(const SelectionItemImage&); SelectionItemImage& operator=(const SelectionItemImage&); ImageFile* m_imageFile; int32_t m_pixelI; int32_t m_pixelJ; uint8_t m_pixelRGBA[4]; }; #ifdef __SELECTION_ITEM_IMAGE_DECLARE__ // #endif // __SELECTION_ITEM_IMAGE_DECLARE__ } // namespace #endif //__SELECTION_ITEM_IMAGE__H_ connectome-workbench-1.4.2/src/Brain/SelectionItemImageControlPoint.cxx000066400000000000000000000120361360521144700262650ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_IMAGE_CONTROL_POINT_DECLARE__ #include "SelectionItemImageControlPoint.h" #undef __SELECTION_ITEM_IMAGE_CONTROL_POINT_DECLARE__ #include "ControlPointFile.h" #include "ImageFile.h" using namespace caret; /** * \class SelectionItemImageControlPoint * \brief Contains information about the selected control point. */ /** * Constructor. */ SelectionItemImageControlPoint::SelectionItemImageControlPoint() : SelectionItem(SelectionItemDataTypeEnum::IMAGE_CONTROL_POINT) { m_imageFile = NULL; m_controlPointFile = NULL; m_controlPoint = NULL; m_controlPointIndexInFile = -1; } /** * Destructor. */ SelectionItemImageControlPoint::~SelectionItemImageControlPoint() { } /** * Reset this selection item. */ void SelectionItemImageControlPoint::reset() { SelectionItem::reset(); m_imageFile = NULL; m_controlPointFile = NULL; m_controlPoint = NULL; m_controlPointIndexInFile = -1; } /** * @return Is this selected item valid? */ bool SelectionItemImageControlPoint::isValid() const { if (m_imageFile == NULL) { return false; } if (m_controlPointFile == NULL) { return false; } if (m_controlPoint == NULL) { return false; } if ((m_controlPointIndexInFile < 0) || (m_controlPointIndexInFile >= m_controlPointFile->getNumberOfControlPoints())) { return false; } return true; } /** * @return Image File that was selected (NULL if not valid). */ const ImageFile* SelectionItemImageControlPoint::getImageFile() const { return m_imageFile; } /** * @return Image File that was selected (NULL if not valid). */ ImageFile* SelectionItemImageControlPoint::getImageFile() { return m_imageFile; } /** * Set the image file that was selected. * * @param imageFile * Pointer to selected image file (NULL if not valid). */ void SelectionItemImageControlPoint::setImageFile(ImageFile* imageFile) { m_imageFile = imageFile; } /** * @return Control point that was selected (NULL if not valid). */ const ControlPointFile* SelectionItemImageControlPoint::getControlPointFile() const { return m_controlPointFile; } /** * @return Control point that was selected (NULL if not valid). */ ControlPointFile* SelectionItemImageControlPoint::getControlPointFile() { return m_controlPointFile; } /** * Set the control point file that was selected. * * @param controlPointFile * Pointer to selected control point file (NULL if not valid). */ void SelectionItemImageControlPoint::setControlPointFile(ControlPointFile* controlPointFile) { m_controlPointFile = controlPointFile; } /** * @return Index of the control point in the control point file (negative if invalid) */ int32_t SelectionItemImageControlPoint::getControlPointIndexInFile() const { return m_controlPointIndexInFile; } /** * Set the index of the control point in the file. * * @param controlPointIndexInFile * Index of the control point in the file. */ void SelectionItemImageControlPoint::setControlPointIndexInFile(const int32_t controlPointIndexInFile) { m_controlPointIndexInFile = controlPointIndexInFile; } /** * @return Pointer to the control point (NULL if invalid) */ ControlPoint3D* SelectionItemImageControlPoint::getControlPoint() { return m_controlPoint; } /** * @return Pointer to the control point (NULL if invalid) */ const ControlPoint3D* SelectionItemImageControlPoint::getControlPoint() const { return m_controlPoint; } /** * Set the control point. * * @param controlPoint * Pointer to the control point. */ void SelectionItemImageControlPoint::setControlPoint(ControlPoint3D* controlPoint) { m_controlPoint = controlPoint; } /** * Get a description of m_ object's content. * @return String describing m_ object's content. */ AString SelectionItemImageControlPoint::toString() const { AString text = SelectionItem::toString(); text += ("ImageFile: " + ((m_imageFile != NULL) ? m_imageFile->getFileNameNoPath() : "INVALID") + "\n"); text += ("ControlPointFile: " + ((m_imageFile != NULL) ? m_controlPointFile->getFileNameNoPath() : "INVALID") + "\n"); text += ("Index in File: " + AString::number(m_controlPointIndexInFile) + "\n"); return text; } connectome-workbench-1.4.2/src/Brain/SelectionItemImageControlPoint.h000066400000000000000000000052071360521144700257140ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_IMAGE_CONTROL_POINT_H_ #define __SELECTION_ITEM_IMAGE_CONTROL_POINT_H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SelectionItem.h" namespace caret { class ControlPointFile; class ControlPoint3D; class ImageFile; class SelectionItemImageControlPoint : public SelectionItem { public: SelectionItemImageControlPoint(); virtual ~SelectionItemImageControlPoint(); virtual bool isValid() const; ImageFile* getImageFile(); const ImageFile* getImageFile() const; void setImageFile(ImageFile* imageFile); ControlPointFile* getControlPointFile(); const ControlPointFile* getControlPointFile() const; void setControlPointFile(ControlPointFile* imageFile); int32_t getControlPointIndexInFile() const; void setControlPointIndexInFile(const int32_t controlPointIndexInFile); ControlPoint3D* getControlPoint(); const ControlPoint3D* getControlPoint() const; void setControlPoint(ControlPoint3D* controlPoint); virtual void reset(); virtual AString toString() const; private: SelectionItemImageControlPoint(const SelectionItemImageControlPoint&); SelectionItemImageControlPoint& operator=(const SelectionItemImageControlPoint&); ImageFile* m_imageFile; ControlPointFile* m_controlPointFile; ControlPoint3D* m_controlPoint; int32_t m_controlPointIndexInFile; }; #ifdef __SELECTION_ITEM_IMAGE_CONTROL_POINT_DECLARE__ // #endif // __SELECTION_ITEM_IMAGE_CONTROL_POINT_DECLARE__ } // namespace #endif //__SELECTION_ITEM_IMAGE_CONTROL_POINT_H_ connectome-workbench-1.4.2/src/Brain/SelectionItemSurfaceNode.cxx000066400000000000000000000106431360521144700250700ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_SURFACE_NODE_DECLARE__ #include "SelectionItemSurfaceNode.h" #undef __SELECTION_ITEM_SURFACE_NODE_DECLARE__ #include "Surface.h" using namespace caret; /** * \class SelectionItemSurfaceNode * \brief Selected node. * * Information about the selected node. */ /** * Constructor. */ SelectionItemSurfaceNode::SelectionItemSurfaceNode() : SelectionItem(SelectionItemDataTypeEnum::SURFACE_NODE) { m_surface = NULL; m_contralateralFlag = false; m_nodeNumber = -1; } /** * Destructor. */ SelectionItemSurfaceNode::~SelectionItemSurfaceNode() { } /** * Copy constructor. * @param obj * Object that is copied. */ SelectionItemSurfaceNode::SelectionItemSurfaceNode(const SelectionItemSurfaceNode& obj) : SelectionItem(obj) { copyHelperSelectionItemSurfaceNode(obj); } /** * Assignment operator. * @param obj * Data copied from obj to m_. * @return * Reference to m_ object. */ SelectionItemSurfaceNode& SelectionItemSurfaceNode::operator=(const SelectionItemSurfaceNode& obj) { if (this != &obj) { SelectionItem::operator=(obj); copyHelperSelectionItemSurfaceNode(obj); } return *this; } /** * Helps with copying an object of m_ type. * @param ff * Object that is copied. */ void SelectionItemSurfaceNode::copyHelperSelectionItemSurfaceNode(const SelectionItemSurfaceNode& idItem) { m_surface = idItem.m_surface; m_nodeNumber = idItem.m_nodeNumber; m_contralateralFlag = idItem.m_contralateralFlag; } /** * Reset the selection item. */ void SelectionItemSurfaceNode::reset() { SelectionItem::reset(); m_surface = NULL; m_nodeNumber = -1; m_contralateralFlag = false; } /** * @return Is m_ selected item valid? */ bool SelectionItemSurfaceNode::isValid() const { return ((m_surface != NULL) && (m_nodeNumber >= 0)); } /** * @return Surface containing selected node. */ const Surface* SelectionItemSurfaceNode::getSurface() const { return m_surface; } /** * @return Surface containing selected node. */ Surface* SelectionItemSurfaceNode::getSurface() { return m_surface; } /** * Set the surface containing the selected node. * @param surface * New value for surface. * */ void SelectionItemSurfaceNode::setSurface(Surface* surface) { m_surface = surface; } /** * return Number of selected node. */ int32_t SelectionItemSurfaceNode::getNodeNumber() const { return m_nodeNumber; } /** * Set node number that was selected. * @param nodeNumber * New value for node. */ void SelectionItemSurfaceNode::setNodeNumber(const int32_t nodeNumber) { m_nodeNumber = nodeNumber; } ///** // * @return Is m_ a contralateral identification? // */ //bool //SelectionItemSurfaceNode::isContralateral() const //{ // return m_contralateralFlag; //} // ///** // * Set contralateral identification status. // * @param status // * New status. // */ //void //SelectionItemSurfaceNode::setContralateral(const bool status) //{ // m_contralateralFlag = status; //} /** * Get a description of m_ object's content. * @return String describing m_ object's content. */ AString SelectionItemSurfaceNode::toString() const { AString text = SelectionItem::toString(); text += ("Surface: " + ((m_surface != NULL) ? m_surface->getFileNameNoPath() : "INVALID") + "\n"); text += "Vertex: " + AString::number(m_nodeNumber) + "\n"; if (isValid() && (m_surface != NULL)) { text += "Coordinate: " + AString::fromNumbers(m_surface->getCoordinate(m_nodeNumber), 3, ", ") + "\n"; } text += "Contralateral: " + AString::fromBool(m_contralateralFlag) + "\n"; return text; } connectome-workbench-1.4.2/src/Brain/SelectionItemSurfaceNode.h000066400000000000000000000043761360521144700245230ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_SURFACE_NODE__H_ #define __SELECTION_ITEM_SURFACE_NODE__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SelectionItem.h" namespace caret { class Surface; class SelectionItemSurfaceNode : public SelectionItem { public: SelectionItemSurfaceNode(); virtual ~SelectionItemSurfaceNode(); SelectionItemSurfaceNode(const SelectionItemSurfaceNode&); SelectionItemSurfaceNode& operator=(const SelectionItemSurfaceNode&); virtual bool isValid() const; Surface* getSurface(); const Surface* getSurface() const; void setSurface(Surface* surface); int32_t getNodeNumber() const; void setNodeNumber(const int32_t nodeNumber); // bool isContralateral() const; // // void setContralateral(const bool status); // virtual void reset(); virtual AString toString() const; private: void copyHelperSelectionItemSurfaceNode(const SelectionItemSurfaceNode& idItem); public: private: Surface* m_surface; int32_t m_nodeNumber; bool m_contralateralFlag; }; #ifdef __SELECTION_ITEM_SURFACE_NODE_DECLARE__ // #endif // __SELECTION_ITEM_SURFACE_NODE_DECLARE__ } // namespace #endif //__SELECTION_ITEM_SURFACE_NODE__H_ connectome-workbench-1.4.2/src/Brain/SelectionItemSurfaceNodeIdentificationSymbol.cxx000066400000000000000000000063231360521144700311300ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_SURFACE_NODE_IDENTIFICATION_SYMBOL_DECLARE__ #include "SelectionItemSurfaceNodeIdentificationSymbol.h" #undef __SELECTION_ITEM_SURFACE_NODE_IDENTIFICATION_SYMBOL_DECLARE__ #include "Surface.h" using namespace caret; /** * \class SelectionItemSurfaceNodeIdentificationSymbol * \brief Selected node symbol * * Information about the selected node symbol. */ /** * Constructor. */ SelectionItemSurfaceNodeIdentificationSymbol::SelectionItemSurfaceNodeIdentificationSymbol() : SelectionItem(SelectionItemDataTypeEnum::SURFACE_NODE_IDENTIFICATION_SYMBOL) { this->surface = NULL; this->nodeNumber = -1; } /** * Destructor. */ SelectionItemSurfaceNodeIdentificationSymbol::~SelectionItemSurfaceNodeIdentificationSymbol() { } /** * Reset this selection item. */ void SelectionItemSurfaceNodeIdentificationSymbol::reset() { SelectionItem::reset(); this->surface = NULL; this->nodeNumber = -1; } /** * @return Is this selected item valid? */ bool SelectionItemSurfaceNodeIdentificationSymbol::isValid() const { return (this->nodeNumber >= 0); } /** * @return Surface containing selected node. */ const Surface* SelectionItemSurfaceNodeIdentificationSymbol::getSurface() const { return this->surface; } /** * @return Surface containing selected node. */ Surface* SelectionItemSurfaceNodeIdentificationSymbol::getSurface() { return this->surface; } /** * Set the surface containing the selected node. * @param surface * New value for surface. * */ void SelectionItemSurfaceNodeIdentificationSymbol::setSurface(Surface* surface) { this->surface = surface; } /** * return Number of selected node. */ int32_t SelectionItemSurfaceNodeIdentificationSymbol::getNodeNumber() const { return this->nodeNumber; } /** * Set node number that was selected. * @param nodeNumber * New value for node. */ void SelectionItemSurfaceNodeIdentificationSymbol::setNodeNumber(const int32_t nodeNumber) { this->nodeNumber = nodeNumber; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString SelectionItemSurfaceNodeIdentificationSymbol::toString() const { AString text = SelectionItem::toString(); text += ("Surface: " + ((surface != NULL) ? surface->getFileNameNoPath() : "INVALID") + "\n"); text += "Vertex: " + AString::number(this->nodeNumber) + "\n"; return text; } connectome-workbench-1.4.2/src/Brain/SelectionItemSurfaceNodeIdentificationSymbol.h000066400000000000000000000043541360521144700305570ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_SURFACE_NODE_IDENTIFICATION_SYMBOL__H_ #define __SELECTION_ITEM_SURFACE_NODE_IDENTIFICATION_SYMBOL__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SelectionItem.h" namespace caret { class Surface; class SelectionItemSurfaceNodeIdentificationSymbol : public SelectionItem { public: SelectionItemSurfaceNodeIdentificationSymbol(); virtual ~SelectionItemSurfaceNodeIdentificationSymbol(); virtual bool isValid() const; Surface* getSurface(); const Surface* getSurface() const; void setSurface(Surface* surface); int32_t getNodeNumber() const; void setNodeNumber(const int32_t nodeNumber); virtual void reset(); virtual AString toString() const; private: SelectionItemSurfaceNodeIdentificationSymbol(const SelectionItemSurfaceNodeIdentificationSymbol&); SelectionItemSurfaceNodeIdentificationSymbol& operator=(const SelectionItemSurfaceNodeIdentificationSymbol&); public: private: Surface* surface; int32_t nodeNumber; }; #ifdef __SELECTION_ITEM_SURFACE_NODE_IDENTIFICATION_SYMBOL_DECLARE__ // #endif // __SELECTION_ITEM_SURFACE_NODE_IDENTIFICATION_SYMBOL_DECLARE__ } // namespace #endif //__SELECTION_ITEM_SURFACE_NODE_IDENTIFICATION_SYMBOL__H_ connectome-workbench-1.4.2/src/Brain/SelectionItemSurfaceTriangle.cxx000066400000000000000000000133401360521144700257450ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_SURFACE_TRIANGLE_DECLARE__ #include "SelectionItemSurfaceTriangle.h" #undef __SELECTION_ITEM_SURFACE_TRIANGLE_DECLARE__ #include #include "Surface.h" using namespace caret; /** * \class SelectionItemSurfaceTriangle * \brief Selected node. * * Information about the selected node. */ /** * Constructor. */ SelectionItemSurfaceTriangle::SelectionItemSurfaceTriangle() : SelectionItem(SelectionItemDataTypeEnum::SURFACE_TRIANGLE) { this->surface = NULL; this->triangleNumber = -1; this->nearestNodeNumber = -1; this->nearestNodeScreenXYZ[0] = 0.0; this->nearestNodeScreenXYZ[1] = 0.0; this->nearestNodeScreenXYZ[2] = std::numeric_limits::max(); this->nearestNodeModelXYZ[0] = 0.0; this->nearestNodeModelXYZ[1] = 0.0; this->nearestNodeModelXYZ[2] = 0.0; } /** * Destructor. */ SelectionItemSurfaceTriangle::~SelectionItemSurfaceTriangle() { } /** * Reset this selection item. */ void SelectionItemSurfaceTriangle::reset() { SelectionItem::reset(); this->surface = NULL; this->triangleNumber = -1; this->nearestNodeNumber = -1; this->nearestNodeScreenXYZ[0] = 0.0; this->nearestNodeScreenXYZ[1] = 0.0; this->nearestNodeScreenXYZ[2] = std::numeric_limits::max(); this->nearestNodeModelXYZ[0] = 0.0; this->nearestNodeModelXYZ[1] = 0.0; this->nearestNodeModelXYZ[2] = 0.0; } /** * return Is this selected item valid? */ bool SelectionItemSurfaceTriangle::isValid() const { return (this->triangleNumber >= 0); } /** * return Surface containing selected node. */ Surface* SelectionItemSurfaceTriangle::getSurface() { return this->surface; } /** * Set the surface containing the selected node. * @param surface * New value for surface. * */ void SelectionItemSurfaceTriangle::setSurface(Surface* surface) { this->surface = surface; } /** * return Number of selected triangle. */ int32_t SelectionItemSurfaceTriangle::getTriangleNumber() const { return this->triangleNumber; } /** * Set triangle number that was selected. * @param triangleNumber * New value for triangle. */ void SelectionItemSurfaceTriangle::setTriangleNumber(const int32_t triangleNumber) { this->triangleNumber = triangleNumber; } /** * @return Node nearest the mouse click in screen X&Y coordinates. * Will return negative if invalid. */ int32_t SelectionItemSurfaceTriangle::getNearestNodeNumber() const { return this->nearestNodeNumber; } /** * Set the node nearest to the mouse click in screen X&Y coordinates. * @param nearestNodeNumber * New value for the node. */ void SelectionItemSurfaceTriangle::setNearestNode(const int32_t nearestNodeNumber) { this->nearestNodeNumber = nearestNodeNumber; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString SelectionItemSurfaceTriangle::toString() const { AString text = SelectionItem::toString(); text += ("Surface: " + ((surface != NULL) ? surface->getFileNameNoPath() : "INVALID") + "\n"); text += "Triangle: " + AString::number(this->triangleNumber) + "\n"; text += "Nearest Vertex: " + AString::number(this->nearestNodeNumber) + "\n"; if (this->isValid() && (surface != NULL)) { if (this->nearestNodeNumber >= 0) { text += "Coordinate: " + AString::fromNumbers(surface->getCoordinate(this->nearestNodeNumber), 3, ", ") + "\n"; } } return text; } /** * Get the screen XYZ of the nearest node. * @param nearestNodeScreenXYZ * XYZ out. */ void SelectionItemSurfaceTriangle::getNearestNodeScreenXYZ(double nearestNodeScreenXYZ[3]) const { nearestNodeScreenXYZ[0] = this->nearestNodeScreenXYZ[0]; nearestNodeScreenXYZ[1] = this->nearestNodeScreenXYZ[1]; nearestNodeScreenXYZ[2] = this->nearestNodeScreenXYZ[2]; } /** * Set the screen XYZ of the nearest node. * @param nearestNodeScreenXYZ * new XYZ. */ void SelectionItemSurfaceTriangle::setNearestNodeScreenXYZ(const double nearestNodeScreenXYZ[3]) { this->nearestNodeScreenXYZ[0] = nearestNodeScreenXYZ[0]; this->nearestNodeScreenXYZ[1] = nearestNodeScreenXYZ[1]; this->nearestNodeScreenXYZ[2] = nearestNodeScreenXYZ[2]; } /** * Get the model XYZ of the nearest node. * @param nearestNodeModelXYZ * XYZ out. */ void SelectionItemSurfaceTriangle::getNearestNodeModelXYZ(double nearestNodeModelXYZ[3]) const { nearestNodeModelXYZ[0] = this->nearestNodeModelXYZ[0]; nearestNodeModelXYZ[1] = this->nearestNodeModelXYZ[1]; nearestNodeModelXYZ[2] = this->nearestNodeModelXYZ[2]; } /** * Set the model XYZ of the nearest node. * @param nearestNodeModelXYZ * new XYZ. */ void SelectionItemSurfaceTriangle::setNearestNodeModelXYZ(const double nearestNodeModelXYZ[3]) { this->nearestNodeModelXYZ[0] = nearestNodeModelXYZ[0]; this->nearestNodeModelXYZ[1] = nearestNodeModelXYZ[1]; this->nearestNodeModelXYZ[2] = nearestNodeModelXYZ[2]; } connectome-workbench-1.4.2/src/Brain/SelectionItemSurfaceTriangle.h000066400000000000000000000050521360521144700253730ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_SURFACE_TRIANGLE__H_ #define __SELECTION_ITEM_SURFACE_TRIANGLE__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SelectionItem.h" namespace caret { class Surface; class SelectionItemSurfaceTriangle : public SelectionItem { public: SelectionItemSurfaceTriangle(); virtual ~SelectionItemSurfaceTriangle(); virtual bool isValid() const; Surface* getSurface(); void setSurface(Surface* surface); int32_t getTriangleNumber() const; void setTriangleNumber(const int32_t triangleNumber); int32_t getNearestNodeNumber() const; void setNearestNode(const int32_t nearestNodeNumber); void getNearestNodeScreenXYZ(double screenXYZ[3]) const; void setNearestNodeScreenXYZ(const double screenXYZ[3]); void getNearestNodeModelXYZ(double modelXYZ[3]) const; void setNearestNodeModelXYZ(const double modelXYZ[3]); virtual void reset(); virtual AString toString() const; private: SelectionItemSurfaceTriangle(const SelectionItemSurfaceTriangle&); SelectionItemSurfaceTriangle& operator=(const SelectionItemSurfaceTriangle&); private: Surface* surface; int32_t triangleNumber; int32_t nearestNodeNumber; double nearestNodeScreenXYZ[3]; double nearestNodeModelXYZ[3]; }; #ifdef __SELECTION_ITEM_SURFACE_TRIANGLE_DECLARE__ // #endif // __SELECTION_ITEM_SURFACE_TRIANGLE_DECLARE__ } // namespace #endif //__SELECTION_ITEM_SURFACE_TRIANGLE__H_ connectome-workbench-1.4.2/src/Brain/SelectionItemVoxel.cxx000066400000000000000000000114741360521144700237720ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_VOXEL_DECLARE__ #include "SelectionItemVoxel.h" #undef __SELECTION_ITEM_VOXEL_DECLARE__ #include "CaretAssert.h" #include "VolumeFile.h" using namespace caret; /** * \class SelectionItemVoxel * \brief Selected voxel. * * Information about an selected voxel. */ /** * Constructor. */ SelectionItemVoxel::SelectionItemVoxel() : SelectionItem(SelectionItemDataTypeEnum::VOXEL) { /* * Note: reset() is virtual so cannot call from constructor. */ resetPrivate(); } /** * Constructor for child classes. * * @param itemDataType * The selection item data type for child class. */ SelectionItemVoxel::SelectionItemVoxel(const SelectionItemDataTypeEnum::Enum itemDataType) : SelectionItem(itemDataType) { /* * Note: reset() is virtual so cannot call from constructor. */ resetPrivate(); } /** * Destructor. */ SelectionItemVoxel::~SelectionItemVoxel() { } /** * Copy constructor. * @param obj * Object that is copied. */ SelectionItemVoxel::SelectionItemVoxel(const SelectionItemVoxel& obj) : SelectionItem(obj) { copyHelperSelectionItemVoxel(obj); } /** * Assignment operator. * @param obj * Data copied from obj to m_. * @return * Reference to m_ object. */ SelectionItemVoxel& SelectionItemVoxel::operator=(const SelectionItemVoxel& obj) { if (this != &obj) { SelectionItem::operator=(obj); copyHelperSelectionItemVoxel(obj); } return *this; } /** * Helps with copying an object of m_ type. * @param ff * Object that is copied. */ void SelectionItemVoxel::copyHelperSelectionItemVoxel(const SelectionItemVoxel& idItem) { m_volumeFile = idItem.m_volumeFile; m_voxelIJK[0] = idItem.m_voxelIJK[0]; m_voxelIJK[1] = idItem.m_voxelIJK[1]; m_voxelIJK[2] = idItem.m_voxelIJK[2]; } /** * Reset this selection item. */ void SelectionItemVoxel::reset() { SelectionItem::reset(); resetPrivate(); } /** * Reset this selection item. */ void SelectionItemVoxel::resetPrivate() { m_volumeFile = NULL; m_voxelIJK[0] = -1; m_voxelIJK[1] = -1; m_voxelIJK[2] = -1; } /** * @return The volume file. */ const VolumeMappableInterface* SelectionItemVoxel::getVolumeFile() const { return m_volumeFile; } /** * Get the voxel indices. * @param voxelIJK * Output containing voxel indices. */ void SelectionItemVoxel::getVoxelIJK(int64_t voxelIJK[3]) const { voxelIJK[0] = m_voxelIJK[0]; voxelIJK[1] = m_voxelIJK[1]; voxelIJK[2] = m_voxelIJK[2]; } /** * Set the volume file. * * @param brain * Brain containing the volume. * @param volumeFile * New value for volume file. * @param voxelIJK * New value for voxel indices. * @param screenDepth * The screen depth. */ void SelectionItemVoxel::setVoxelIdentification(Brain* brain, VolumeMappableInterface* volumeFile, const int64_t voxelIJK[3], const double screenDepth) { setBrain(brain); m_volumeFile = volumeFile; m_voxelIJK[0] = voxelIJK[0]; m_voxelIJK[1] = voxelIJK[1]; m_voxelIJK[2] = voxelIJK[2]; setScreenDepth(screenDepth); } /** * @return Is this selected item valid? */ bool SelectionItemVoxel::isValid() const { return (m_volumeFile != NULL); } /** * Get a description of this object's content. * @return String describing this object's content. */ AString SelectionItemVoxel::toString() const { AString text = SelectionItem::toString(); AString name = "INVALID"; if (m_volumeFile != NULL) { CaretMappableDataFile* cmdf = dynamic_cast(m_volumeFile); if (cmdf != NULL) { name = cmdf->getFileNameNoPath(); } } text += ("Volume: " + name); text += ("Voxel: " + AString::number(m_voxelIJK[0]) + ", " + AString::number(m_voxelIJK[1]) + ", " + AString::number(m_voxelIJK[2]) + "\n"); return text; } connectome-workbench-1.4.2/src/Brain/SelectionItemVoxel.h000066400000000000000000000044621360521144700234160ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_VOXEL__H_ #define __SELECTION_ITEM_VOXEL__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "SelectionItem.h" namespace caret { class VolumeMappableInterface; class SelectionItemVoxel : public SelectionItem { public: SelectionItemVoxel(); virtual ~SelectionItemVoxel(); SelectionItemVoxel(const SelectionItemVoxel&); SelectionItemVoxel& operator=(const SelectionItemVoxel&); virtual bool isValid() const; const VolumeMappableInterface* getVolumeFile() const; void getVoxelIJK(int64_t voxelIJK[3]) const; void setVoxelIdentification(Brain* brain, VolumeMappableInterface* volumeFile, const int64_t voxelIJK[3], const double screenDepth); virtual void reset(); virtual AString toString() const; protected: SelectionItemVoxel(const SelectionItemDataTypeEnum::Enum itemDataType); private: void copyHelperSelectionItemVoxel(const SelectionItemVoxel& idItem); void resetPrivate(); VolumeMappableInterface* m_volumeFile; int64_t m_voxelIJK[3]; }; #ifdef __SELECTION_ITEM_VOXEL_DECLARE__ // #endif // __SELECTION_ITEM_VOXEL_DECLARE__ } // namespace #endif //__SELECTION_ITEM_VOXEL__H_ connectome-workbench-1.4.2/src/Brain/SelectionItemVoxelEditing.cxx000066400000000000000000000060251360521144700252720ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_VOXEL_EDITING_DECLARE__ #include "SelectionItemVoxelEditing.h" #undef __SELECTION_ITEM_VOXEL_EDITING_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::SelectionItemVoxelEditing * \brief Information about selected voxel used in volume editing. * \ingroup Brain * * Reports selection of any voxel, even those that are * not displayed. This allows the user to select "off" voxels * so that they can be turned on when editing a volume. */ /** * Constructor. */ SelectionItemVoxelEditing::SelectionItemVoxelEditing() : SelectionItemVoxel(SelectionItemDataTypeEnum::VOXEL_EDITING) { m_volumeFileForEditing = NULL; } /** * Destructor. */ SelectionItemVoxelEditing::~SelectionItemVoxelEditing() { } /** * @return Volume file that is being edited. */ const VolumeFile* SelectionItemVoxelEditing::getVolumeFileForEditing() const { return m_volumeFileForEditing; } /** * @return Volume file that is being edited. */ VolumeFile* SelectionItemVoxelEditing::getVolumeFileForEditing() { return m_volumeFileForEditing; } /** * Set the volume file that is being edited. * * @param volumeFile * Volume file that is being edited. */ void SelectionItemVoxelEditing::setVolumeFileForEditing(VolumeFile* volumeFile) { m_volumeFileForEditing = volumeFile; } /** * Reset this selection item. */ void SelectionItemVoxelEditing::reset() { SelectionItemVoxel::reset(); m_volumeFileForEditing = NULL; } /** * Set the voxel diff XYZ (bottom left to top right * of screen drawing). * * @param voxelDiffXYZ * Difference from voxel bottom left to top right on screen. */ void SelectionItemVoxelEditing::setVoxelDiffXYZ(const float voxelDiffXYZ[3]) { m_voxelDiffXYZ[0] = voxelDiffXYZ[0]; m_voxelDiffXYZ[1] = voxelDiffXYZ[1]; m_voxelDiffXYZ[2] = voxelDiffXYZ[2]; } /** * Get the voxel diff XYZ (bottom left to top right * of screen drawing). * * @param voxelDiffXYZ * Difference from voxel bottom left to top right on screen. */ void SelectionItemVoxelEditing::getVoxelDiffXYZ(float voxelDiffXYZ[3]) const { voxelDiffXYZ[0] = m_voxelDiffXYZ[0]; voxelDiffXYZ[1] = m_voxelDiffXYZ[1]; voxelDiffXYZ[2] = m_voxelDiffXYZ[2]; } connectome-workbench-1.4.2/src/Brain/SelectionItemVoxelEditing.h000066400000000000000000000041101360521144700247100ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_VOXEL_EDITING_H__ #define __SELECTION_ITEM_VOXEL_EDITING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SelectionItemVoxel.h" namespace caret { class VolumeFile; class SelectionItemVoxelEditing : public SelectionItemVoxel { public: SelectionItemVoxelEditing(); virtual ~SelectionItemVoxelEditing(); const VolumeFile* getVolumeFileForEditing() const; VolumeFile* getVolumeFileForEditing(); void setVolumeFileForEditing(VolumeFile* volumeFile); void setVoxelDiffXYZ(const float voxelDiffXYZ[3]); void getVoxelDiffXYZ(float voxelDiffXYZ[3]) const; virtual void reset(); // ADD_NEW_METHODS_HERE private: SelectionItemVoxelEditing(const SelectionItemVoxelEditing&); SelectionItemVoxelEditing& operator=(const SelectionItemVoxelEditing&); VolumeFile* m_volumeFileForEditing; float m_voxelDiffXYZ[3]; // ADD_NEW_MEMBERS_HERE }; #ifdef __SELECTION_ITEM_VOXEL_EDITING_DECLARE__ // #endif // __SELECTION_ITEM_VOXEL_EDITING_DECLARE__ } // namespace #endif //__SELECTION_ITEM_VOXEL_EDITING_H__ connectome-workbench-1.4.2/src/Brain/SelectionItemVoxelIdentificationSymbol.cxx000066400000000000000000000103141360521144700300220ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SELECTION_ITEM_VOXEL_IDENTIFICATION_SYMBOL_DECLARE__ #include "SelectionItemVoxelIdentificationSymbol.h" #undef __SELECTION_ITEM_VOXEL_IDENTIFICATION_SYMBOL_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::SelectionItemVoxelIdentificationSymbol * \brief * \ingroup Brain * * */ /** * Constructor. */ SelectionItemVoxelIdentificationSymbol::SelectionItemVoxelIdentificationSymbol() : SelectionItem(SelectionItemDataTypeEnum::VOXEL_IDENTIFICATION_SYMBOL) { /* * Note: reset() is virtual so cannot call from constructor. */ resetPrivate(); } /** * Destructor. */ SelectionItemVoxelIdentificationSymbol::~SelectionItemVoxelIdentificationSymbol() { } /** * Copy constructor. * @param obj * Object that is copied. */ SelectionItemVoxelIdentificationSymbol::SelectionItemVoxelIdentificationSymbol(const SelectionItemVoxelIdentificationSymbol& obj) : SelectionItem(obj) { this->copyHelperSelectionItemVoxelIdentificationSymbol(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ SelectionItemVoxelIdentificationSymbol& SelectionItemVoxelIdentificationSymbol::operator=(const SelectionItemVoxelIdentificationSymbol& obj) { if (this != &obj) { SelectionItem::operator=(obj); this->copyHelperSelectionItemVoxelIdentificationSymbol(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void SelectionItemVoxelIdentificationSymbol::copyHelperSelectionItemVoxelIdentificationSymbol(const SelectionItemVoxelIdentificationSymbol& obj) { m_voxelXYZ[0] = obj.m_voxelXYZ[0]; m_voxelXYZ[1] = obj.m_voxelXYZ[1]; m_voxelXYZ[2] = obj.m_voxelXYZ[2]; m_voxelValid = obj.m_voxelValid; } /** * Get the coordinates of the voxel identification symbol. * * @param xyzOut * Coordinates of the voxel identification symbol. */ void SelectionItemVoxelIdentificationSymbol::getVoxelXYZ(float xyzOut[3]) const { xyzOut[0] = m_voxelXYZ[0]; xyzOut[1] = m_voxelXYZ[1]; xyzOut[2] = m_voxelXYZ[2]; } /** * Set the coordinates of the voxel identification symbol. * * @param xyzOut * Coordinates of the voxel identification symbol. */ void SelectionItemVoxelIdentificationSymbol::setVoxelXYZ(const float xyz[3]) { m_voxelXYZ[0] = xyz[0]; m_voxelXYZ[1] = xyz[1]; m_voxelXYZ[2] = xyz[2]; m_voxelValid = true; } /** * Reset this selection item. */ void SelectionItemVoxelIdentificationSymbol::reset() { SelectionItem::reset(); resetPrivate(); } /** * Reset this items data. */ void SelectionItemVoxelIdentificationSymbol::resetPrivate() { m_voxelValid = false; m_voxelXYZ[0] = 0.0; m_voxelXYZ[1] = 0.0; m_voxelXYZ[2] = 0.0; } /** * @return Is this selected item valid? */ bool SelectionItemVoxelIdentificationSymbol::isValid() const { return m_voxelValid; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString SelectionItemVoxelIdentificationSymbol::toString() const { AString text = SelectionItem::toString(); text += ("Voxel XYZ: " + AString::fromNumbers(m_voxelXYZ, 3, ", ") + "\n" + "Valid: " + AString::fromBool(m_voxelValid) + "\n"); return text; } connectome-workbench-1.4.2/src/Brain/SelectionItemVoxelIdentificationSymbol.h000066400000000000000000000043311360521144700274510ustar00rootroot00000000000000#ifndef __SELECTION_ITEM_VOXEL_IDENTIFICATION_SYMBOL_H__ #define __SELECTION_ITEM_VOXEL_IDENTIFICATION_SYMBOL_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SelectionItem.h" namespace caret { class SelectionItemVoxelIdentificationSymbol : public SelectionItem { public: SelectionItemVoxelIdentificationSymbol(); virtual ~SelectionItemVoxelIdentificationSymbol(); SelectionItemVoxelIdentificationSymbol(const SelectionItemVoxelIdentificationSymbol& obj); SelectionItemVoxelIdentificationSymbol& operator=(const SelectionItemVoxelIdentificationSymbol& obj); void getVoxelXYZ(float xyzOut[3]) const; void setVoxelXYZ(const float xyz[3]); virtual bool isValid() const; virtual void reset(); virtual AString toString() const; // ADD_NEW_METHODS_HERE private: void copyHelperSelectionItemVoxelIdentificationSymbol(const SelectionItemVoxelIdentificationSymbol& obj); void resetPrivate(); float m_voxelXYZ[3]; bool m_voxelValid; // ADD_NEW_MEMBERS_HERE }; #ifdef __SELECTION_ITEM_VOXEL_IDENTIFICATION_SYMBOL_DECLARE__ // #endif // __SELECTION_ITEM_VOXEL_IDENTIFICATION_SYMBOL_DECLARE__ } // namespace #endif //__SELECTION_ITEM_VOXEL_IDENTIFICATION_SYMBOL_H__ connectome-workbench-1.4.2/src/Brain/SelectionManager.cxx000066400000000000000000000630671360521144700234350ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretOpenGLInclude.h" #include #include #include "BrainConstants.h" #include "CaretAssert.h" #include "CaretLogger.h" #define __SELECTION_MANAGER_DECLARE__ #include "SelectionManager.h" #undef __SELECTION_MANAGER_DECLARE__ #include "SelectionItemAnnotation.h" #include "SelectionItemBorderSurface.h" #include "SelectionItemChartDataSeries.h" #include "SelectionItemChartFrequencySeries.h" #include "SelectionItemChartMatrix.h" #include "SelectionItemChartTimeSeries.h" #include "SelectionItemChartTwoHistogram.h" #include "SelectionItemChartTwoLabel.h" #include "SelectionItemChartTwoLineSeries.h" #include "SelectionItemChartTwoMatrix.h" #include "SelectionItemCiftiConnectivityMatrixRowColumn.h" #include "SelectionItemFocusSurface.h" #include "SelectionItemFocusVolume.h" #include "SelectionItemImage.h" #include "SelectionItemImageControlPoint.h" #include "SelectionItemSurfaceNode.h" #include "SelectionItemSurfaceNodeIdentificationSymbol.h" #include "SelectionItemSurfaceTriangle.h" #include "SelectionItemVoxel.h" #include "SelectionItemVoxelEditing.h" #include "SelectionItemVoxelIdentificationSymbol.h" #include "IdentificationTextGenerator.h" #include "Surface.h" using namespace caret; /** * \class SelectionManager * \brief Manages identification. * * Manages identification. */ /** * Constructor. */ SelectionManager::SelectionManager() : CaretObject() { m_annotationIdentification = new SelectionItemAnnotation(); m_surfaceBorderIdentification = new SelectionItemBorderSurface(); m_chartDataSeriesIdentification = new SelectionItemChartDataSeries(); m_chartDataFrequencyIdentification = new SelectionItemChartFrequencySeries(); m_chartMatrixIdentification = new SelectionItemChartMatrix(); m_chartTwoHistogramIdentification = std::unique_ptr(new SelectionItemChartTwoHistogram()); m_chartTwoLabelIdentification = std::unique_ptr(new SelectionItemChartTwoLabel()); m_chartTwoLineSeriesIdentification = std::unique_ptr(new SelectionItemChartTwoLineSeries()); m_chartTwoMatrixIdentification = std::unique_ptr(new SelectionItemChartTwoMatrix()); m_ciftiConnectivityMatrixRowColumnIdentfication = new SelectionItemCiftiConnectivityMatrixRowColumn(); m_chartTimeSeriesIdentification = new SelectionItemChartTimeSeries(); m_surfaceFocusIdentification = new SelectionItemFocusSurface(); m_volumeFocusIdentification = new SelectionItemFocusVolume(); m_imageIdentification = new SelectionItemImage(); m_imageControlPointIdentification = new SelectionItemImageControlPoint(); m_surfaceNodeIdentification = new SelectionItemSurfaceNode(); m_surfaceNodeIdentificationSymbol = new SelectionItemSurfaceNodeIdentificationSymbol(); m_surfaceTriangleIdentification = new SelectionItemSurfaceTriangle(); m_voxelIdentification = new SelectionItemVoxel(); m_voxelIdentificationSymbol = new SelectionItemVoxelIdentificationSymbol(); m_voxelEditingIdentification = new SelectionItemVoxelEditing(); m_allSelectionItems.push_back(m_annotationIdentification); m_allSelectionItems.push_back(m_surfaceBorderIdentification); m_allSelectionItems.push_back(m_chartDataSeriesIdentification); m_allSelectionItems.push_back(m_chartDataFrequencyIdentification); m_allSelectionItems.push_back(m_chartMatrixIdentification); m_allSelectionItems.push_back(m_chartTimeSeriesIdentification); m_allSelectionItems.push_back(m_chartTwoHistogramIdentification.get()); m_allSelectionItems.push_back(m_chartTwoLabelIdentification.get()); m_allSelectionItems.push_back(m_chartTwoLineSeriesIdentification.get()); m_allSelectionItems.push_back(m_chartTwoMatrixIdentification.get()); m_allSelectionItems.push_back(m_ciftiConnectivityMatrixRowColumnIdentfication); m_allSelectionItems.push_back(m_surfaceFocusIdentification); m_allSelectionItems.push_back(m_surfaceNodeIdentification); m_allSelectionItems.push_back(m_surfaceNodeIdentificationSymbol); m_allSelectionItems.push_back(m_surfaceTriangleIdentification); m_allSelectionItems.push_back(m_imageIdentification); m_allSelectionItems.push_back(m_imageControlPointIdentification); m_allSelectionItems.push_back(m_voxelIdentification); m_allSelectionItems.push_back(m_voxelIdentificationSymbol); m_allSelectionItems.push_back(m_voxelEditingIdentification); m_allSelectionItems.push_back(m_volumeFocusIdentification); m_surfaceSelectedItems.push_back(m_surfaceNodeIdentification); m_surfaceSelectedItems.push_back(m_surfaceTriangleIdentification); m_layeredSelectedItems.push_back(m_surfaceBorderIdentification); m_layeredSelectedItems.push_back(m_surfaceFocusIdentification); m_volumeSelectedItems.push_back(m_voxelIdentification); m_volumeSelectedItems.push_back(m_voxelEditingIdentification); m_volumeSelectedItems.push_back(m_volumeFocusIdentification); m_idTextGenerator = new IdentificationTextGenerator(); m_lastSelectedItem = NULL; reset(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_IDENTIFICATION_SYMBOL_REMOVAL); } /** * Destructor. */ SelectionManager::~SelectionManager() { reset(); delete m_annotationIdentification; m_annotationIdentification = NULL; delete m_surfaceBorderIdentification; m_surfaceBorderIdentification = NULL; delete m_chartDataSeriesIdentification; m_chartDataSeriesIdentification = NULL; delete m_chartDataFrequencyIdentification; m_chartDataFrequencyIdentification = NULL; delete m_chartMatrixIdentification; m_chartMatrixIdentification = NULL; delete m_chartTimeSeriesIdentification; m_chartTimeSeriesIdentification = NULL; delete m_ciftiConnectivityMatrixRowColumnIdentfication; m_ciftiConnectivityMatrixRowColumnIdentfication = NULL; delete m_surfaceFocusIdentification; m_surfaceFocusIdentification = NULL; delete m_imageIdentification; m_imageIdentification = NULL; delete m_imageControlPointIdentification; m_imageControlPointIdentification = NULL; delete m_surfaceNodeIdentification; m_surfaceNodeIdentification = NULL; delete m_surfaceNodeIdentificationSymbol; m_surfaceNodeIdentificationSymbol = NULL; delete m_surfaceTriangleIdentification; m_surfaceTriangleIdentification = NULL; delete m_voxelIdentification; m_voxelIdentification = NULL; delete m_voxelEditingIdentification; m_voxelEditingIdentification = NULL; delete m_voxelIdentificationSymbol; m_voxelIdentificationSymbol = NULL; delete m_volumeFocusIdentification; m_volumeFocusIdentification = NULL; delete m_idTextGenerator; m_idTextGenerator = NULL; if (m_lastSelectedItem != NULL) { delete m_lastSelectedItem; } EventManager::get()->removeAllEventsFromListener(this); } /** * Receive events from the event manager. * * @param event * The event. */ void SelectionManager::receiveEvent(Event* /*event*/) { } /** * Filter selections to arbitrate between triangle/node * and to remove any selections behind another selection. * * @param applySelectionBackgroundFiltering * If true (which is in most cases), if there are multiple items * selected, those items "behind" other items are not reported. * For example, suppose a focus is selected and there is a node * the focus. If this parameter is true, the node will NOT be * selected. If this parameter is false, the node will be * selected. */ void SelectionManager::filterSelections(const bool applySelectionBackgroundFiltering) { AString logText; for (std::vector::iterator iter = m_allSelectionItems.begin(); iter != m_allSelectionItems.end(); iter++) { SelectionItem* item = *iter; if (item->isValid()) { logText += ("\n" + item->toString() + "\n"); } } CaretLogFine("Selected Items BEFORE filtering: " + logText); SelectionItemSurfaceTriangle* triangleID = m_surfaceTriangleIdentification; SelectionItemSurfaceNode* nodeID = m_surfaceNodeIdentification; // // If both a node and triangle are found // if ((nodeID->getNodeNumber() >= 0) && (triangleID->getTriangleNumber() >= 0)) { // // Is node further from user than triangle? // double depthDiff = m_surfaceNodeIdentification->getScreenDepth() - triangleID->getScreenDepth(); if (depthDiff > 0.00001) { // // Do not use node // m_surfaceNodeIdentification->reset(); } } // // Have a triangle ? // const int32_t triangleNumber = triangleID->getTriangleNumber(); if (triangleNumber >= 0) { // // If no node, use node in nearest triangle // if (m_surfaceNodeIdentification->getNodeNumber() < 0) { const int32_t nearestNode = triangleID->getNearestNodeNumber(); if (nearestNode >= 0) { CaretLogFine("Switched vertex to triangle nearest vertex ." + AString::number(nearestNode)); nodeID->setNodeNumber(nearestNode); nodeID->setScreenDepth(triangleID->getScreenDepth()); nodeID->setSurface(triangleID->getSurface()); double xyz[3]; triangleID->getNearestNodeScreenXYZ(xyz); nodeID->setScreenXYZ(xyz); triangleID->getNearestNodeModelXYZ(xyz); nodeID->setModelXYZ(xyz); nodeID->setBrain(triangleID->getBrain()); } } } /* * See if node identification symbol is too far from selected node. * This may occur if the symbol is on the other side of the surface. */ if ((m_surfaceNodeIdentificationSymbol->getNodeNumber() >= 0) && (m_surfaceNodeIdentification->getNodeNumber() >= 0)) { const double depthDiff = (m_surfaceNodeIdentificationSymbol->getScreenDepth() - m_surfaceNodeIdentification->getScreenDepth()); if (depthDiff > 0.01) { m_surfaceNodeIdentificationSymbol->reset(); } else { m_surfaceNodeIdentification->reset(); } } if (m_voxelIdentificationSymbol->isValid() && m_voxelIdentification->isValid()) { const double depthDiff = (m_voxelIdentificationSymbol->getScreenDepth() - m_voxelIdentification->getScreenDepth()); if (depthDiff > 0.01) { m_voxelIdentificationSymbol->reset(); } else { m_voxelIdentification->reset(); } } if (applySelectionBackgroundFiltering) { clearDistantSelections(); } logText = ""; for (std::vector::iterator iter = m_allSelectionItems.begin(); iter != m_allSelectionItems.end(); iter++) { SelectionItem* item = *iter; if (item->isValid()) { logText += ("\n" + item->toString() + "\n"); } } CaretLogFine("Selected Items AFTER filtering: " + logText); } /** * Examine the selection groups and manipulate them * so that there are not items selected in more * than one group. */ void SelectionManager::clearDistantSelections() { std::vector* > itemGroups; /* * Make layers items slightly closer since they are * often pasted onto the surface. */ for (std::vector::iterator iter = m_layeredSelectedItems.begin(); iter != m_layeredSelectedItems.end(); iter++) { SelectionItem* item = *iter; item->setScreenDepth(item->getScreenDepth()* 0.99); } itemGroups.push_back(&m_layeredSelectedItems); itemGroups.push_back(&m_surfaceSelectedItems); itemGroups.push_back(&m_volumeSelectedItems); std::vector* minDepthGroup = NULL; double minDepth = std::numeric_limits::max(); for (std::vector* >::iterator iter = itemGroups.begin(); iter != itemGroups.end(); iter++) { std::vector* group = *iter; SelectionItem* minDepthItem = getMinimumDepthFromMultipleSelections(*group); if (minDepthItem != NULL) { double md = minDepthItem->getScreenDepth(); if (md < minDepth) { minDepthGroup = group; minDepth = md; } } } if (minDepthGroup != NULL) { for (std::vector* >::iterator iter = itemGroups.begin(); iter != itemGroups.end(); iter++) { std::vector* group = *iter; if (group != minDepthGroup) { for (std::vector::iterator iter = group->begin(); iter != group->end(); iter++) { SelectionItem* item = *iter; item->reset(); } } } } } /** * Reset all selected items except for the given selected item. * @param selectedItem * SelectedItem that is NOT reset. */ void SelectionManager::clearOtherSelectedItems(SelectionItem* selectedItem) { for (std::vector::iterator iter = m_allSelectionItems.begin(); iter != m_allSelectionItems.end(); iter++) { SelectionItem* item = *iter; if (item != selectedItem) { item->reset(); } } } /** * From the list of selectable items, find the item with the * minimum depth. * @param items List of selectable items. * @return Reference to selectable item with the minimum depth * or NULL if no valid selectable items in the list. */ SelectionItem* SelectionManager::getMinimumDepthFromMultipleSelections(std::vector items) const { double minDepth = std::numeric_limits::max(); SelectionItem* minDepthItem = NULL; for (std::vector::iterator iter = items.begin(); iter != items.end(); iter++) { SelectionItem* item = *iter; if (item->isValid()) { if (item->getScreenDepth() < minDepth) { minDepthItem = item; minDepth = item->getScreenDepth(); } } } return minDepthItem; } /** * Set the enabled status for all selection items. * * @param status * New status for ALL selection items. */ void SelectionManager::setAllSelectionsEnabled(const bool status) { for (std::vector::iterator iter = m_allSelectionItems.begin(); iter != m_allSelectionItems.end(); iter++) { SelectionItem* item = *iter; item->setEnabledForSelection(status); } } /** * Get text describing the current identification data. * @param brain * Brain containing the data. */ AString SelectionManager::getIdentificationText(const Brain* brain) const { CaretAssert(brain); const AString text = m_idTextGenerator->createIdentificationText(this, brain); return text; } /** * Reset all identification. */ void SelectionManager::reset() { for (std::vector::iterator iter = m_allSelectionItems.begin(); iter != m_allSelectionItems.end(); iter++) { SelectionItem* item = *iter; item->reset(); } } /** * @return Identification for annotations. */ SelectionItemAnnotation* SelectionManager::getAnnotationIdentification() { return m_annotationIdentification; } /** * @return Identification for annotations. */ const SelectionItemAnnotation* SelectionManager::getAnnotationIdentification() const { return m_annotationIdentification; } /** * @return Identification for image. */ SelectionItemImage* SelectionManager::getImageIdentification() { return m_imageIdentification; } /** * @return Identification for image. */ const SelectionItemImage* SelectionManager::getImageIdentification() const { return m_imageIdentification; } /** * @return Identification for image control point. */ SelectionItemImageControlPoint* SelectionManager::getImageControlPointIdentification() { return m_imageControlPointIdentification; } /** * @return Identification for image control point. */ const SelectionItemImageControlPoint* SelectionManager::getImageControlPointIdentification() const { return m_imageControlPointIdentification; } /** * @return Identification for surface node. */ SelectionItemSurfaceNode* SelectionManager::getSurfaceNodeIdentification() { return m_surfaceNodeIdentification; } /** * @return Identification for surface node. */ const SelectionItemSurfaceNode* SelectionManager::getSurfaceNodeIdentification() const { return m_surfaceNodeIdentification; } /** * @return Identification for surface node. */ const SelectionItemSurfaceNodeIdentificationSymbol* SelectionManager::getSurfaceNodeIdentificationSymbol() const { return m_surfaceNodeIdentificationSymbol; } /** * @return Identification for surface node. */ SelectionItemSurfaceNodeIdentificationSymbol* SelectionManager::getSurfaceNodeIdentificationSymbol() { return m_surfaceNodeIdentificationSymbol; } /** * @return Identification for surface triangle. */ SelectionItemSurfaceTriangle* SelectionManager::getSurfaceTriangleIdentification() { return m_surfaceTriangleIdentification; } /** * @return Identification for surface triangle. */ const SelectionItemSurfaceTriangle* SelectionManager::getSurfaceTriangleIdentification() const { return m_surfaceTriangleIdentification; } /** * @return Identification for voxels. */ const SelectionItemVoxel* SelectionManager::getVoxelIdentification() const { return m_voxelIdentification; } /** * @return Identification for voxels. */ SelectionItemVoxel* SelectionManager::getVoxelIdentification() { return m_voxelIdentification; } /** * @return Identification for voxel identification system. */ const SelectionItemVoxelIdentificationSymbol* SelectionManager::getVoxelIdentificationSymbol() const { return m_voxelIdentificationSymbol; } /** * @return Identification for voxels. */ SelectionItemVoxelIdentificationSymbol* SelectionManager::getVoxelIdentificationSymbol() { return m_voxelIdentificationSymbol; } /** * @return Identification for voxel editing. */ const SelectionItemVoxelEditing* SelectionManager::getVoxelEditingIdentification() const { return m_voxelEditingIdentification; } /** * @return Identification for voxel editing. */ SelectionItemVoxelEditing* SelectionManager::getVoxelEditingIdentification() { return m_voxelEditingIdentification; } /** * @return Identification for borders. */ SelectionItemBorderSurface* SelectionManager::getSurfaceBorderIdentification() { return m_surfaceBorderIdentification; } /** * @return Identification for borders. */ const SelectionItemBorderSurface* SelectionManager::getSurfaceBorderIdentification() const { return m_surfaceBorderIdentification; } /** * @return Identification for foci. */ SelectionItemFocusSurface* SelectionManager::getSurfaceFocusIdentification() { return m_surfaceFocusIdentification; } /** * @return Identification for foci. */ const SelectionItemFocusSurface* SelectionManager::getSurfaceFocusIdentification() const { return m_surfaceFocusIdentification; } /** * @return Identification for foci. */ SelectionItemFocusVolume* SelectionManager::getVolumeFocusIdentification() { return m_volumeFocusIdentification; } /** * @return Identification for foci. */ const SelectionItemFocusVolume* SelectionManager::getVolumeFocusIdentification() const { return m_volumeFocusIdentification; } /** * @return Identification for data-series chart. */ SelectionItemChartDataSeries* SelectionManager::getChartDataSeriesIdentification() { return m_chartDataSeriesIdentification; } /** * @return Identification for data-series chart (const method). */ const SelectionItemChartDataSeries* SelectionManager::getChartDataSeriesIdentification() const { return m_chartDataSeriesIdentification; } /** * @return Identification for frequency-series chart. */ SelectionItemChartFrequencySeries* SelectionManager::getChartFrequencySeriesIdentification() { return m_chartDataFrequencyIdentification; } /** * @return Identification for frequency-series chart (const method). */ const SelectionItemChartFrequencySeries* SelectionManager::getChartFrequencySeriesIdentification() const { return m_chartDataFrequencyIdentification; } /** * @return Identification for matrix chart. */ SelectionItemChartMatrix* SelectionManager::getChartMatrixIdentification() { return m_chartMatrixIdentification; } /** * @return Identification for matrix chart (const method) */ const SelectionItemChartMatrix* SelectionManager::getChartMatrixIdentification() const { return m_chartMatrixIdentification; } /** * @return Identification for chart two histogram identification */ SelectionItemChartTwoHistogram* SelectionManager::getChartTwoHistogramIdentification() { return m_chartTwoHistogramIdentification.get(); } /** * @return Identification for chart two histogram identification */ const SelectionItemChartTwoHistogram* SelectionManager::getChartTwoHistogramIdentification() const { return m_chartTwoHistogramIdentification.get(); } /** * @return Identification for chart two line series identification */ SelectionItemChartTwoLineSeries* SelectionManager::getChartTwoLineSeriesIdentification() { return m_chartTwoLineSeriesIdentification.get(); } /** * @return Identification for chart two line series identification */ const SelectionItemChartTwoLineSeries* SelectionManager::getChartTwoLineSeriesIdentification() const { return m_chartTwoLineSeriesIdentification.get(); } /** * @return Identification for chart two label identification */ SelectionItemChartTwoLabel* SelectionManager::getChartTwoLabelIdentification() { return m_chartTwoLabelIdentification.get(); } /** * @return Identification for chart two label identification */ const SelectionItemChartTwoLabel* SelectionManager::getChartTwoLabelIdentification() const { return m_chartTwoLabelIdentification.get(); } /** * @return Identification for chart two matrix identification. */ SelectionItemChartTwoMatrix* SelectionManager::getChartTwoMatrixIdentification() { return m_chartTwoMatrixIdentification.get(); } /** * @return Identification for chart two matrix identification. */ const SelectionItemChartTwoMatrix* SelectionManager::getChartTwoMatrixIdentification() const { return m_chartTwoMatrixIdentification.get(); } /** * @return Identification for CIFTI Connectivity Matrix Row/Column. */ SelectionItemCiftiConnectivityMatrixRowColumn* SelectionManager::getCiftiConnectivityMatrixRowColumnIdentification() { return m_ciftiConnectivityMatrixRowColumnIdentfication; } /** * @return Identification for CIFTI Connectivity Matrix Row/Column. */ const SelectionItemCiftiConnectivityMatrixRowColumn* SelectionManager::getCiftiConnectivityMatrixRowColumnIdentification() const { return m_ciftiConnectivityMatrixRowColumnIdentfication; } /** * @return Identification for time-series chart. */ SelectionItemChartTimeSeries* SelectionManager::getChartTimeSeriesIdentification() { return m_chartTimeSeriesIdentification; } /** * @return Identification for time-series chart (const method). */ const SelectionItemChartTimeSeries* SelectionManager::getChartTimeSeriesIdentification() const { return m_chartTimeSeriesIdentification; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString SelectionManager::toString() const { return "SelectionManager"; } /** * @return The last selected item (may be NULL). */ const SelectionItem* SelectionManager::getLastSelectedItem() const { return m_lastSelectedItem; } /** * Set the last selected item to the given item. * * @param lastItem * The last item that was selected; */ void SelectionManager::setLastSelectedItem(const SelectionItem* lastItem) { if (m_lastSelectedItem != NULL) { delete m_lastSelectedItem; } m_lastSelectedItem = NULL; if (lastItem != NULL) { const SelectionItemSurfaceNode* nodeID = dynamic_cast(lastItem); const SelectionItemVoxel* voxelID = dynamic_cast(lastItem); if (nodeID != NULL) { m_lastSelectedItem = new SelectionItemSurfaceNode(*nodeID); } else if (voxelID != NULL) { m_lastSelectedItem = new SelectionItemVoxel(*voxelID); } else { CaretAssertMessage(0, ("Unsupported last ID type" + lastItem->toString())); } } } connectome-workbench-1.4.2/src/Brain/SelectionManager.h000066400000000000000000000221241360521144700230470ustar00rootroot00000000000000#ifndef __SELECTION_MANAGER__H_ #define __SELECTION_MANAGER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "EventListenerInterface.h" namespace caret { class Annotation; class Brain; class BrowserTabContent; class SelectionItemAnnotation; class SelectionItem; class SelectionItemBorderSurface; class SelectionItemChartDataSeries; class SelectionItemChartFrequencySeries; class SelectionItemChartMatrix; class SelectionItemChartTimeSeries; class SelectionItemChartTwoHistogram; class SelectionItemChartTwoLabel; class SelectionItemChartTwoLineSeries; class SelectionItemChartTwoMatrix; class SelectionItemCiftiConnectivityMatrixRowColumn; class SelectionItemFocusSurface; class SelectionItemFocusVolume; class SelectionItemImage; class SelectionItemImageControlPoint; class SelectionItemSurfaceNode; class SelectionItemSurfaceNodeIdentificationSymbol; class SelectionItemSurfaceTriangle; class SelectionItemVoxel; class SelectionItemVoxelEditing; class SelectionItemVoxelIdentificationSymbol; class IdentificationTextGenerator; class Surface; class SelectionManager : public CaretObject, public EventListenerInterface { public: SelectionManager(); virtual ~SelectionManager(); void receiveEvent(Event* event); void reset(); SelectionItemAnnotation* getAnnotationIdentification(); const SelectionItemAnnotation* getAnnotationIdentification() const; SelectionItemBorderSurface* getSurfaceBorderIdentification(); const SelectionItemBorderSurface* getSurfaceBorderIdentification() const; SelectionItemFocusSurface* getSurfaceFocusIdentification(); const SelectionItemFocusSurface* getSurfaceFocusIdentification() const; SelectionItemFocusVolume* getVolumeFocusIdentification(); const SelectionItemFocusVolume* getVolumeFocusIdentification() const; SelectionItemImage* getImageIdentification(); const SelectionItemImage* getImageIdentification() const; SelectionItemImageControlPoint* getImageControlPointIdentification(); const SelectionItemImageControlPoint* getImageControlPointIdentification() const; SelectionItemSurfaceNode* getSurfaceNodeIdentification(); const SelectionItemSurfaceNode* getSurfaceNodeIdentification() const; SelectionItemSurfaceNodeIdentificationSymbol* getSurfaceNodeIdentificationSymbol(); const SelectionItemSurfaceNodeIdentificationSymbol* getSurfaceNodeIdentificationSymbol() const; SelectionItemSurfaceTriangle* getSurfaceTriangleIdentification(); const SelectionItemSurfaceTriangle* getSurfaceTriangleIdentification() const; const SelectionItemVoxel* getVoxelIdentification() const; SelectionItemVoxel* getVoxelIdentification(); SelectionItemVoxelIdentificationSymbol* getVoxelIdentificationSymbol(); const SelectionItemVoxelIdentificationSymbol* getVoxelIdentificationSymbol() const; SelectionItemVoxelEditing* getVoxelEditingIdentification(); const SelectionItemVoxelEditing* getVoxelEditingIdentification() const; SelectionItemChartDataSeries* getChartDataSeriesIdentification(); const SelectionItemChartDataSeries* getChartDataSeriesIdentification() const; SelectionItemChartFrequencySeries* getChartFrequencySeriesIdentification(); const SelectionItemChartFrequencySeries* getChartFrequencySeriesIdentification() const; SelectionItemChartMatrix* getChartMatrixIdentification(); const SelectionItemChartMatrix* getChartMatrixIdentification() const; SelectionItemChartTimeSeries* getChartTimeSeriesIdentification(); const SelectionItemChartTimeSeries* getChartTimeSeriesIdentification() const; SelectionItemCiftiConnectivityMatrixRowColumn* getCiftiConnectivityMatrixRowColumnIdentification(); const SelectionItemCiftiConnectivityMatrixRowColumn* getCiftiConnectivityMatrixRowColumnIdentification() const; SelectionItemChartTwoHistogram* getChartTwoHistogramIdentification(); const SelectionItemChartTwoHistogram* getChartTwoHistogramIdentification() const; SelectionItemChartTwoLineSeries* getChartTwoLineSeriesIdentification(); const SelectionItemChartTwoLineSeries* getChartTwoLineSeriesIdentification() const; SelectionItemChartTwoLabel* getChartTwoLabelIdentification(); const SelectionItemChartTwoLabel* getChartTwoLabelIdentification() const; SelectionItemChartTwoMatrix* getChartTwoMatrixIdentification(); const SelectionItemChartTwoMatrix* getChartTwoMatrixIdentification() const; AString getIdentificationText(const Brain* brain) const; void filterSelections(const bool applySelectionBackgroundFiltering); void clearDistantSelections(); void clearOtherSelectedItems(SelectionItem* selectedItem); const SelectionItem* getLastSelectedItem() const; void setLastSelectedItem(const SelectionItem* lastItem); void setAllSelectionsEnabled(const bool status); private: SelectionManager(const SelectionManager&); SelectionManager& operator=(const SelectionManager&); public: virtual AString toString() const; private: SelectionItem* getMinimumDepthFromMultipleSelections(std::vector items) const; /** ALL items */ std::vector m_allSelectionItems; /** Layered items (foci, borders, etc.) */ std::vector m_layeredSelectedItems; /** Surface items (nodes, triangles) */ std::vector m_surfaceSelectedItems; /** Volume items */ std::vector m_volumeSelectedItems; SelectionItemAnnotation* m_annotationIdentification; SelectionItemBorderSurface* m_surfaceBorderIdentification; SelectionItemChartDataSeries* m_chartDataSeriesIdentification; SelectionItemChartFrequencySeries* m_chartDataFrequencyIdentification; SelectionItemChartMatrix* m_chartMatrixIdentification; SelectionItemChartTimeSeries* m_chartTimeSeriesIdentification; std::unique_ptr m_chartTwoHistogramIdentification; std::unique_ptr m_chartTwoLineSeriesIdentification; std::unique_ptr m_chartTwoLabelIdentification; std::unique_ptr m_chartTwoMatrixIdentification; SelectionItemCiftiConnectivityMatrixRowColumn* m_ciftiConnectivityMatrixRowColumnIdentfication; SelectionItemFocusSurface* m_surfaceFocusIdentification; SelectionItemFocusVolume* m_volumeFocusIdentification; SelectionItemImage* m_imageIdentification; SelectionItemImageControlPoint* m_imageControlPointIdentification; SelectionItemSurfaceNode* m_surfaceNodeIdentification; SelectionItemSurfaceNodeIdentificationSymbol* m_surfaceNodeIdentificationSymbol; SelectionItemSurfaceTriangle* m_surfaceTriangleIdentification; IdentificationTextGenerator* m_idTextGenerator; SelectionItemVoxel* m_voxelIdentification; SelectionItemVoxelIdentificationSymbol* m_voxelIdentificationSymbol; SelectionItemVoxelEditing* m_voxelEditingIdentification; /** Last selected item DOES NOT GET PUT IN m_allSelectionItems */ SelectionItem* m_lastSelectedItem; }; #ifdef __SELECTION_MANAGER_DECLARE__ // #endif // __SELECTION_MANAGER_DECLARE__ } // namespace #endif //__SELECTION_MANAGER__H_ connectome-workbench-1.4.2/src/Brain/SessionManager.cxx000066400000000000000000001247341360521144700231320ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __SESSION_MANAGER_DECLARE__ #include "SessionManager.h" #undef __SESSION_MANAGER_DECLARE__ #include "ApplicationInformation.h" #include "BackgroundAndForegroundColorsSceneHelper.h" #include "Brain.h" #include "BrowserTabContent.h" #include "BrowserWindowContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPreferenceDataValue.h" #include "CaretPreferences.h" #include "CiftiConnectivityMatrixDataFileManager.h" #include "CiftiFiberTrajectoryManager.h" #include "DataToolTipsManager.h" #include "ElapsedTimer.h" #include "EventManager.h" #include "EventBrowserTabDelete.h" #include "EventBrowserTabGet.h" #include "EventBrowserTabGetAll.h" #include "EventBrowserTabIndicesGetAll.h" #include "EventBrowserTabNew.h" #include "EventBrowserTabNewClone.h" #include "EventBrowserWindowContent.h" #include "EventCaretPreferencesGet.h" #include "EventModelAdd.h" #include "EventModelDelete.h" #include "EventModelGetAll.h" #include "EventModelGetAllDisplayed.h" #include "EventProgressUpdate.h" #include "EventSpacerTabGet.h" #include "ImageCaptureSettings.h" #include "LogManager.h" #include "MapYokingGroupEnum.h" #include "ModelWholeBrain.h" #include "MovieRecorder.h" #include "Scene.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "ScenePrimitiveArray.h" #include "SpacerTabContent.h" #include "VolumeSurfaceOutlineSetModel.h" using namespace caret; /** * Constructor. */ SessionManager::SessionManager() : CaretObject(), EventListenerInterface(), SceneableInterface() { m_caretPreferences = new CaretPreferences(); m_imageCaptureDialogSettings = new ImageCaptureSettings(); m_ciftiConnectivityMatrixDataFileManager = new CiftiConnectivityMatrixDataFileManager(); m_ciftiFiberTrajectoryManager = new CiftiFiberTrajectoryManager(); m_dataToolTipsManager.reset(new DataToolTipsManager(m_caretPreferences->isShowDataToolTipsEnabled())); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_browserTabs[i] = NULL; } for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS; i++) { CaretAssertStdArrayIndex(m_browserWindowContent, i); m_browserWindowContent[i] = new BrowserWindowContent(i); } EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_DELETE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_INDICES_GET_ALL); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_NEW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_NEW_CLONE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_CONTENT); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CARET_PREFERENCES_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MODEL_ADD); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MODEL_DELETE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MODEL_GET_ALL); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MODEL_GET_ALL_DISPLAYED); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_SPACER_TAB_GET); Brain* brain = new Brain(m_caretPreferences); m_brains.push_back(brain); m_movieRecorder.reset(new MovieRecorder()); } /** * Destructor. */ SessionManager::~SessionManager() { /* * Delete browser tab content. Workbench requests deletion of tab content * as browser tabs are closed. However, command line does not issue * commands to delete tabs so this code will do so. */ for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { if (m_browserTabs[i] != NULL) { delete m_browserTabs[i]; m_browserTabs[i] = NULL; } } clearSpacerTabs(); std::for_each(m_browserWindowContent.begin(), m_browserWindowContent.end(), [](BrowserWindowContent* bwc) { if (bwc != NULL) delete bwc; } ); int32_t numberOfBrains = getNumberOfBrains(); for (int32_t i = (numberOfBrains - 1); i >= 0; i--) { delete m_brains[i]; } m_brains.clear(); EventManager::get()->removeAllEventsFromListener(this); delete m_ciftiConnectivityMatrixDataFileManager; delete m_ciftiFiberTrajectoryManager; delete m_imageCaptureDialogSettings; delete m_caretPreferences; } /** * Create the session manager. * This must be called one AND ONLY one time prior to any * other Caret mechanisms. * * @param applicationType * The type of application (command line or GUI). */ void SessionManager::createSessionManager(const ApplicationTypeEnum::Enum applicationType) { CaretAssertMessage((s_singletonSessionManager == NULL), "Session manager has already been created."); /* * Set the type of application. */ ApplicationInformation::setApplicationType(applicationType); /* * Create log manager. */ LogManager::createLogManager(); /* * Create event manager first. */ EventManager::createEventManager(); /* * Create session manager. */ s_singletonSessionManager = new SessionManager(); } /** * Delete the session manager. * This may only be called one time after session manager is created. */ void SessionManager::deleteSessionManager() { CaretAssertMessage((s_singletonSessionManager != NULL), "Session manager does not exist, cannot delete it."); delete s_singletonSessionManager; s_singletonSessionManager = NULL; /* * Session manager must be deleted before the event * manager is deleted. */ EventManager::deleteEventManager(); LogManager::deleteLogManager(); } /** * Get the one and only session manager. * * @return Pointer to the session manager. */ SessionManager* SessionManager::get() { CaretAssertMessage(s_singletonSessionManager, "Session manager was not created.\n" "It must be created with SessionManager::createSessionManager()."); return s_singletonSessionManager; } /** * Add a brain to this session. * In most cases, there is one brain per subject. * * @param shareDisplayPropertiesFlag * If true display properties are shared which * is appropriate for the GUI version of Caret. * For SumsDB, false may be appropriate to keep * each subject independent of the other. * * @return New brain that was added. */ Brain* SessionManager::addBrain(const bool /*shareDisplayPropertiesFlag*/) { CaretAssertMessage(0, "Adding brains not implemented at this time."); return NULL; } /** * Get the number of brains. * There is always at least one brain. * * @return Number of brains. */ int32_t SessionManager::getNumberOfBrains() const { return m_brains.size(); } /** * Get the brain at the specified index. * There is always one brain so passing * zero as the index will always work. * * @param brainIndex * Index of brain. * @return * Brain at specified index. */ Brain* SessionManager::getBrain(const int32_t brainIndex) const { CaretAssertVectorIndex(m_brains, brainIndex); return m_brains[brainIndex]; } /** * Clear all of the spacer tabs */ void SessionManager::clearSpacerTabs() { for (auto st : m_spacerTabsMap) { delete st.second; } m_spacerTabsMap.clear(); } /** * Get a description of this object's content. * @return String describing this object's content. */ AString SessionManager::toString() const { return "SessionManager"; } /** * Receive events. * * @param event * Event that needs to be processed. */ void SessionManager::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_NEW) { EventBrowserTabNew* tabEvent = dynamic_cast(event); CaretAssert(tabEvent); tabEvent->setEventProcessed(); bool createdTab = false; for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { if (m_browserTabs[i] == NULL) { BrowserTabContent* tab = new BrowserTabContent(i); tab->update(m_models); m_browserTabs[i] = tab; tabEvent->setBrowserTab(tab); createdTab = true; break; } } if ( ! createdTab) { tabEvent->setErrorMessage("Workbench is unable to create tabs, all tabs are in use."); } } else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_NEW_CLONE) { EventBrowserTabNewClone* cloneTabEvent = dynamic_cast(event); CaretAssert(cloneTabEvent); cloneTabEvent->setEventProcessed(); const int32_t cloneTabIndex = cloneTabEvent->getIndexOfBrowserTabThatWasCloned(); if ((cloneTabIndex < 0) || (cloneTabIndex >= BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)) { cloneTabEvent->setErrorMessage("Invalid tab for cloning index=" + AString::number(cloneTabIndex)); return; } int32_t newTabIndex(-1); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { if (m_browserTabs[i] == NULL) { newTabIndex = i; break; } } if (newTabIndex >= 0) { CaretAssertArrayIndex(m_browserTabs, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, cloneTabIndex); CaretAssertArrayIndex(m_browserTabs, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, newTabIndex); m_browserTabs[newTabIndex] = new BrowserTabContent(newTabIndex); m_browserTabs[newTabIndex]->update(m_models); m_browserTabs[newTabIndex]->cloneBrowserTabContent(m_browserTabs[cloneTabIndex]); cloneTabEvent->setNewBrowserTab(m_browserTabs[newTabIndex], newTabIndex); } else { cloneTabEvent->setErrorMessage("Workbench is unable to create tabs, all tabs are in use."); } } else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_DELETE) { EventBrowserTabDelete* tabEvent = dynamic_cast(event); CaretAssert(tabEvent); BrowserTabContent* tab = tabEvent->getBrowserTab(); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { if (m_browserTabs[i] == tab) { delete m_browserTabs[i]; m_browserTabs[i] = NULL; tabEvent->setEventProcessed(); break; } } } else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_GET) { EventBrowserTabGet* tabEvent = dynamic_cast(event); CaretAssert(tabEvent); tabEvent->setEventProcessed(); const int32_t tabNumber = tabEvent->getTabNumber(); CaretAssertArrayIndex(m_browserTabs, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabNumber); tabEvent->setBrowserTab(m_browserTabs[tabNumber]); } else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL) { EventBrowserTabGetAll* tabEvent = dynamic_cast(event); CaretAssert(tabEvent); tabEvent->setEventProcessed(); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { if (m_browserTabs[i] != NULL) { tabEvent->addBrowserTab(m_browserTabs[i]); } } } else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_INDICES_GET_ALL) { EventBrowserTabIndicesGetAll* tabEvent = dynamic_cast(event); CaretAssert(tabEvent); tabEvent->setEventProcessed(); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { if (m_browserTabs[i] != NULL) { tabEvent->addBrowserTabIndex(m_browserTabs[i]->getTabNumber()); } } } else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_CONTENT) { EventBrowserWindowContent* windowEvent = dynamic_cast(event); CaretAssert(windowEvent); windowEvent->setEventProcessed(); const int32_t windowIndex = windowEvent->getBrowserWindowIndex(); CaretAssertStdArrayIndex(m_browserWindowContent, windowIndex); CaretAssert(m_browserWindowContent[windowIndex]); switch (windowEvent->getMode()) { case EventBrowserWindowContent::Mode::DELETER: m_browserWindowContent[windowIndex]->setValid(false); break; case EventBrowserWindowContent::Mode::GET: windowEvent->setBrowserWindowContent(m_browserWindowContent[windowIndex]); break; case EventBrowserWindowContent::Mode::NEW: m_browserWindowContent[windowIndex]->setValid(true); windowEvent->setBrowserWindowContent(m_browserWindowContent[windowIndex]); break; } } else if (event->getEventType() == EventTypeEnum::EVENT_CARET_PREFERENCES_GET) { EventCaretPreferencesGet* preferencesEvent = dynamic_cast(event); CaretAssert(preferencesEvent); preferencesEvent->setCaretPreferences(m_caretPreferences); preferencesEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_MODEL_ADD) { EventModelAdd* addModelsEvent = dynamic_cast(event); CaretAssert(addModelsEvent); addModelsEvent->setEventProcessed(); m_models.push_back(addModelsEvent->getModel()); updateBrowserTabContents(); } else if (event->getEventType() == EventTypeEnum::EVENT_MODEL_DELETE) { EventModelDelete* deleteModelsEvent = dynamic_cast(event); CaretAssert(deleteModelsEvent); deleteModelsEvent->setEventProcessed(); Model* model = deleteModelsEvent->getModel(); std::vector::iterator iter = std::find(m_models.begin(), m_models.end(), model); CaretAssertMessage(iter != m_models.end(), "Trying to delete non-existent model"); m_models.erase(iter); updateBrowserTabContents(); } else if (event->getEventType() == EventTypeEnum::EVENT_MODEL_GET_ALL) { EventModelGetAll* getModelsEvent = dynamic_cast(event); CaretAssert(getModelsEvent); getModelsEvent->setEventProcessed(); getModelsEvent->addModels(m_models); } else if (event->getEventType() == EventTypeEnum::EVENT_MODEL_GET_ALL_DISPLAYED) { EventModelGetAllDisplayed* getDisplayedModelsEvent = dynamic_cast(event); CaretAssert(getDisplayedModelsEvent); for (const auto tab : m_browserTabs) { if (tab != NULL) { getDisplayedModelsEvent->addModel(tab->getModelForDisplay()); } } getDisplayedModelsEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_SPACER_TAB_GET) { EventSpacerTabGet* spacerTabEvent = dynamic_cast(event); CaretAssert(spacerTabEvent); SpacerTabContent* spacerTabContent = NULL; SpacerTabIndex spacerTabIndex(spacerTabEvent->getWindowIndex(), spacerTabEvent->getRowIndex(), spacerTabEvent->getColumnIndex()); auto iter = m_spacerTabsMap.find(spacerTabIndex); if (iter != m_spacerTabsMap.end()) { spacerTabContent = iter->second; CaretLogFiner("Found Spacer Tab Content: " + spacerTabContent->getTabName()); } else { spacerTabContent = new SpacerTabContent(spacerTabEvent->getWindowIndex(), spacerTabEvent->getRowIndex(), spacerTabEvent->getColumnIndex()); m_spacerTabsMap.insert(std::make_pair(spacerTabIndex, spacerTabContent)); CaretLogFiner("Created Spacer Tab Content: " + spacerTabContent->getTabName()); } CaretAssert(spacerTabContent); spacerTabEvent->setSpacerTabContent(spacerTabContent); spacerTabEvent->setEventProcessed(); } } /** * Update all of the browser tab contents since the models have changed. */ void SessionManager::updateBrowserTabContents() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { if (m_browserTabs[i] != NULL) { m_browserTabs[i]->update(m_models); } } } /** * @return The caret preferences */ CaretPreferences* SessionManager::getCaretPreferences() { return m_caretPreferences; } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* SessionManager::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } SceneClass* sceneClass = new SceneClass(instanceName, "SessionManager", 1); { /* * Save map yoking groups. */ std::vector mapYokingGroups; MapYokingGroupEnum::getAllEnums(mapYokingGroups); const int32_t numMapYokingGroups = static_cast(mapYokingGroups.size()); if (numMapYokingGroups > 0) { std::vector mapMapSelections(numMapYokingGroups, 1); CaretArray mapMapEnabled(numMapYokingGroups); for (int32_t i = 0; i < numMapYokingGroups; i++) { mapMapEnabled[i] = false; } for (int32_t i = 0; i < numMapYokingGroups; i++) { const MapYokingGroupEnum::Enum enumValue = mapYokingGroups[i]; if (enumValue != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { const int32_t groupIndex = MapYokingGroupEnum::toIntegerCode(enumValue); const int32_t mapIndex = MapYokingGroupEnum::getSelectedMapIndex(enumValue); mapMapSelections[groupIndex] = mapIndex; mapMapEnabled[groupIndex] = MapYokingGroupEnum::isEnabled(enumValue); } } sceneClass->addIntegerArray("MapYokingIndexArray", &mapMapSelections[0], numMapYokingGroups); sceneClass->addBooleanArray("MapYokingEnabledArray", &mapMapEnabled[0], numMapYokingGroups); } } /* * Save brains */ std::vector brainSceneClasses; const int32_t numBrains = m_brains.size(); for (int32_t i = 0; i < numBrains; i++) { brainSceneClasses.push_back(m_brains[i]->saveToScene(sceneAttributes, "m_brains")); } sceneClass->addChild(new SceneClassArray("m_brains", brainSceneClasses)); /* * Get the tabs that are to be included in the scene */ const std::vector tabIndicesForScene = sceneAttributes->getIndicesOfTabsForSavingToScene(); /* * Save browser tabs */ std::vector browserTabSceneClasses; for (int32_t tabIndex = 0; tabIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; tabIndex++) { if (std::find(tabIndicesForScene.begin(), tabIndicesForScene.end(), tabIndex) != tabIndicesForScene.end()) { BrowserTabContent* btc = m_browserTabs[tabIndex]; if (btc != NULL) { browserTabSceneClasses.push_back(btc->saveToScene(sceneAttributes, "m_browserTabs")); } } } sceneClass->addChild(new SceneClassArray("m_browserTabs", browserTabSceneClasses)); /* * Save browser windows */ SceneObjectMapIntegerKey* browserClassMap = new SceneObjectMapIntegerKey("browserWindowContentMap", SceneObjectDataTypeEnum::SCENE_CLASS); for (auto bw : m_browserWindowContent) { if (bw->isValid()) { browserClassMap->addClass(bw->getWindowIndex(), bw->saveToScene(sceneAttributes, "m_browserWindowContent")); } } sceneClass->addChild(browserClassMap); sceneClass->addChild(m_imageCaptureDialogSettings->saveToScene(sceneAttributes, "m_imageCaptureDialogSettings")); /* * Save the background and foreground colors to the scene */ const BackgroundAndForegroundColors* colorsPointer = m_caretPreferences->getBackgroundAndForegroundColors(); CaretAssert(colorsPointer); BackgroundAndForegroundColors colors(*colorsPointer); BackgroundAndForegroundColorsSceneHelper colorHelper(colors); sceneClass->addChild(colorHelper.saveToScene(sceneAttributes, "backgroundAndForegroundColors")); sceneClass->addClass(savePreferencesToScene(sceneAttributes, "ScenePreferenceDataValues")); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. May be NULL for some types of scenes. */ void SessionManager::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { /* * Default to user preferences for colors */ m_caretPreferences->setBackgroundAndForegroundColorsMode(BackgroundAndForegroundColorsModeEnum::USER_PREFERENCES); m_caretPreferences->invalidateSceneDataValues(); if (sceneClass == NULL) { return; } int32_t progressCounter = 0; const int32_t PROGRESS_RESTORING_BRAIN = progressCounter++; const int32_t PROGRESS_RESTORING_TABS = progressCounter++; const int32_t PROGRESS_RESTORING_GUI = progressCounter++; const int32_t PROGRESS_RESTORING_TOTAL = progressCounter++; ElapsedTimer timer; timer.start(); EventProgressUpdate progressEvent(0, PROGRESS_RESTORING_TOTAL, PROGRESS_RESTORING_BRAIN, "Restoring Brain"); EventManager::get()->sendEvent(progressEvent.getPointer()); if (progressEvent.isCancelled()) { resetBrains(true); return; } switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } { /* * Restore map yoking groups */ std::vector mapYokingGroups; MapYokingGroupEnum::getAllEnums(mapYokingGroups); const int32_t numMapYokingGroups = static_cast(mapYokingGroups.size()); if (numMapYokingGroups > 0) { std::vector mapIndexSelections(numMapYokingGroups, 1); sceneClass->getIntegerArrayValue("MapYokingIndexArray", &mapIndexSelections[0], numMapYokingGroups, 1); for (int32_t i = 0; i < numMapYokingGroups; i++) { bool isValid = false; const MapYokingGroupEnum::Enum enumValue = MapYokingGroupEnum::fromIntegerCode(i, &isValid); if (enumValue != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { if (isValid) { MapYokingGroupEnum::setSelectedMapIndex(enumValue, mapIndexSelections[i]); } else { MapYokingGroupEnum::setSelectedMapIndex(enumValue, 1); } } } const ScenePrimitiveArray* mapEnabledArray = sceneClass->getPrimitiveArray("MapYokingEnabledArray"); if (mapEnabledArray != NULL) { for (int32_t i = 0; i < numMapYokingGroups; i++) { bool isValid = false; const MapYokingGroupEnum::Enum enumValue = MapYokingGroupEnum::fromIntegerCode(i, &isValid); if (enumValue != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { /* * Enabled status was added on 10/17/2014. * Previous to this data, there was no enabled status and * we will assume enabled status was on. */ bool enabledStatus = true; if (isValid) { if (mapEnabledArray != NULL) { if (i < mapEnabledArray->getNumberOfArrayElements()) { enabledStatus = mapEnabledArray->booleanValue(i); } } } MapYokingGroupEnum::setEnabled(enumValue, enabledStatus); } } } } } { /* * Restore overlay yoking groups * Note: Overlay yoking groups were replaced by MapYokingGroupEnum * So if overlay yoking group is found, the scene was created * before map yoking groups. */ const ScenePrimitiveArray* overlayEnabledArray = sceneClass->getPrimitiveArray("OverlayYokingEnabledArray"); const ScenePrimitiveArray* mapIndexArray = sceneClass->getPrimitiveArray("OverlayYokingGroupArray"); if (mapIndexArray != NULL) { const int32_t numMapIndexElements = mapIndexArray->getNumberOfArrayElements(); for (int32_t i = 0; i < numMapIndexElements; i++) { bool isValid = false; const MapYokingGroupEnum::Enum enumValue = MapYokingGroupEnum::fromIntegerCode(i, &isValid); if (enumValue != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { if (isValid) { MapYokingGroupEnum::setSelectedMapIndex(enumValue, mapIndexArray->integerValue(i)); } else { MapYokingGroupEnum::setSelectedMapIndex(enumValue, 1); } } } if (overlayEnabledArray != NULL) { const int32_t numMapEnabledElements = overlayEnabledArray->getNumberOfArrayElements(); for (int32_t i = 0; i < numMapEnabledElements; i++) { bool isValid = false; const MapYokingGroupEnum::Enum enumValue = MapYokingGroupEnum::fromIntegerCode(i, &isValid); if (enumValue != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { /* * Enabled status was added on 10/17/2014. * Previous to this data, there was no enabled status and * we will assume enabled status was on. */ bool enabledStatus = true; if (isValid) { if (overlayEnabledArray != NULL) { if (i < overlayEnabledArray->getNumberOfArrayElements()) { enabledStatus = overlayEnabledArray->booleanValue(i); } } } MapYokingGroupEnum::setEnabled(enumValue, enabledStatus); } } } } } /* * Restore brains */ const SceneClassArray* brainArray = sceneClass->getClassArray("m_brains"); const int32_t numBrainClasses = brainArray->getNumberOfArrayElements(); for (int32_t i = 0; i < numBrainClasses; i++) { const SceneClass* brainClass = brainArray->getClassAtIndex(i); if (i < static_cast(m_brains.size())) { m_brains[i]->restoreFromScene(sceneAttributes, brainClass); } else { Brain* brain = new Brain(m_caretPreferences); brain->restoreFromScene(sceneAttributes, brainClass); } } CaretLogFine("Time to restore brain was " + QString::number(timer.getElapsedTimeSeconds(), 'f', 3) + " seconds"); timer.reset(); progressEvent.setProgress(PROGRESS_RESTORING_TABS, "Restoring Content of Browser Tabs"); EventManager::get()->sendEvent(progressEvent.getPointer()); if (progressEvent.isCancelled()) { resetBrains(true); return; } /* * Remove all tabs */ for (int32_t iTab = 0; iTab < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; iTab++) { if (m_browserTabs[iTab] != NULL) { delete m_browserTabs[iTab]; m_browserTabs[iTab] = NULL; } } /* * Remove all spacer tabs */ clearSpacerTabs(); /* * Restore tabs */ const SceneClassArray* browserTabArray = sceneClass->getClassArray("m_browserTabs"); const int32_t numBrowserTabClasses = browserTabArray->getNumberOfArrayElements(); for (int32_t i = 0; i < numBrowserTabClasses; i++) { const SceneClass* browserTabClass = browserTabArray->getClassAtIndex(i); BrowserTabContent* tab = new BrowserTabContent(i); tab->update(m_models); tab->getVolumeSurfaceOutlineSet()->selectSurfacesAfterSpecFileLoaded(m_brains[0], false); tab->restoreFromScene(sceneAttributes, browserTabClass); const int32_t tabIndex = tab->getTabNumber(); CaretAssert(tabIndex >= 0); m_browserTabs[tabIndex] = tab; } /* * Restore windows */ const SceneObjectMapIntegerKey* browserClassMap = sceneClass->getMapIntegerKey("browserWindowContentMap"); if (browserClassMap != NULL) { /* * m_browserWindowContent was added in Feb 2018 at which time the * aspect locking buttons for window and tab were consolidated into * one button. */ const std::vector windowIndices = browserClassMap->getKeys(); for (const auto windowIndex : windowIndices) { const SceneClass* windowClass = browserClassMap->classValue(windowIndex); CaretAssert(windowClass); CaretAssertStdArrayIndex(m_browserWindowContent, windowIndex); m_browserWindowContent[windowIndex]->restoreFromScene(sceneAttributes, windowClass); m_browserWindowContent[windowIndex]->setValid(true); } } else { /* * For scenes before Feb 2018, need to restore from the GUI's browser window * to the browser window content. */ const Scene* scene = sceneAttributes->getScene(); CaretAssert(scene); const SceneClass* guiManagerClass = scene->getClassWithName("guiManager"); if (guiManagerClass->getName() != "guiManager") { sceneAttributes->addToErrorMessage("Top level scene class should be guiManager but it is: " + guiManagerClass->getName()); return; } const SceneClassArray* browserWindowArray = guiManagerClass->getClassArray("m_brainBrowserWindows"); if (browserWindowArray != NULL) { const int32_t numBrowserClasses = browserWindowArray->getNumberOfArrayElements(); for (int32_t i = 0; i < numBrowserClasses; i++) { const SceneClass* browserClass = browserWindowArray->getClassAtIndex(i); CaretAssert(browserClass); int32_t windowIndex = browserClass->getIntegerValue("m_browserWindowIndex", -1); if (windowIndex < 0) { windowIndex = i; } CaretAssert(windowIndex >= 0); CaretAssertStdArrayIndex(m_browserWindowContent, windowIndex); m_browserWindowContent[windowIndex]->restoreFromOldBrainBrowserWindowScene(sceneAttributes, browserClass); m_browserWindowContent[windowIndex]->setValid(true); } } } const int32_t numValidBrowserWindows = std::count_if(m_browserWindowContent.begin(), m_browserWindowContent.end(), [](BrowserWindowContent* bwc) { return bwc->isValid(); }); if (numValidBrowserWindows <= 0) { sceneAttributes->addToErrorMessage("Scene error, no browser window content was restored"); return; } for (auto brainPtr : m_brains) { brainPtr->restoreModelChartOneToModelChartTwo(); } /* * Restore foreground and background colors to scene foreground and background colors */ if (sceneAttributes->isUseSceneForegroundAndBackgroundColors()) { BackgroundAndForegroundColors colors; BackgroundAndForegroundColorsSceneHelper colorHelper(colors); colorHelper.restoreFromScene(sceneAttributes, sceneClass->getClass("backgroundAndForegroundColors")); if (colorHelper.wasRestoredFromScene()) { m_caretPreferences->setBackgroundAndForegroundColorsMode(BackgroundAndForegroundColorsModeEnum::SCENE); m_caretPreferences->setSceneBackgroundAndForegroundColors(colors); } else { m_caretPreferences->setBackgroundAndForegroundColorsMode(BackgroundAndForegroundColorsModeEnum::USER_PREFERENCES); } } restorePreferencesFromScene(sceneAttributes, sceneClass->getClass("ScenePreferenceDataValues")); m_imageCaptureDialogSettings->restoreFromScene(sceneAttributes, sceneClass->getClass("m_imageCaptureDialogSettings")); CaretLogFine("Time to restore browser tab content was " + QString::number(timer.getElapsedTimeSeconds(), 'f', 3) + " seconds"); timer.reset(); progressEvent.setProgress(PROGRESS_RESTORING_GUI, "Restoring Graphical User Interface"); EventManager::get()->sendEvent(progressEvent.getPointer()); if (progressEvent.isCancelled()) { resetBrains(true); return; } } /** * Save items in preferences to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name for the scene class * * @return Pointer to scene class containing preferences */ SceneClass* SessionManager::savePreferencesToScene(const SceneAttributes* /*sceneAttributes*/, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ScenePreferences", 1); std::vector sceneDataValues = m_caretPreferences->getPreferenceSceneDataValues(); for (auto scv : sceneDataValues) { if (scv->isSavedToScenes()) { sceneClass->addString(scv->getName(), scv->getPreferenceValue().toString()); } } return sceneClass; } /** * Restore items in preferences from the scene * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass containing the preference items. */ void SessionManager::restorePreferencesFromScene(const SceneAttributes* /*sceneAttributes*/, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } const QString invalidValueName("InVaLiDvAlUe"); m_caretPreferences->invalidateSceneDataValues(); std::vector sceneDataValues = m_caretPreferences->getPreferenceSceneDataValues(); for (auto scv : sceneDataValues) { if (scv->isSavedToScenes()) { const QString name = scv->getName(); const QString value = sceneClass->getStringValue(scv->getName(), invalidValueName); if (value != invalidValueName) { scv->setSceneValue(QVariant(value)); } } } } /** * Reset the first brain and remove all other brains. */ void SessionManager::resetBrains(const bool keepSceneFiles) { const int32_t numBrains = static_cast(m_brains.size()); for (int32_t i = 0; i < numBrains; i++) { if (i > 0) { delete m_brains[i]; } else if (keepSceneFiles) { m_brains[i]->resetBrainKeepSceneFiles(); } else { m_brains[i]->resetBrain(); } } clearSpacerTabs(); if (numBrains > 1) { m_brains.resize(1); } } /** * @param The CIFTI connectivity matrix data file manager */ CiftiConnectivityMatrixDataFileManager* SessionManager::getCiftiConnectivityMatrixDataFileManager() { return m_ciftiConnectivityMatrixDataFileManager; } /** * @param The CIFTI connectivity matrix data file manager */ const CiftiConnectivityMatrixDataFileManager* SessionManager::getCiftiConnectivityMatrixDataFileManager() const { return m_ciftiConnectivityMatrixDataFileManager; } /** * @return The CIFTI Fiber Trajectory Manager */ CiftiFiberTrajectoryManager* SessionManager::getCiftiFiberTrajectoryManager() { return m_ciftiFiberTrajectoryManager; } /** * @return The CIFTI Fiber Trajectory Manager (const method) */ const CiftiFiberTrajectoryManager* SessionManager::getCiftiFiberTrajectoryManager() const { return m_ciftiFiberTrajectoryManager; } /** * @return The data tool tips manager */ DataToolTipsManager* SessionManager::getDataToolTipsManager() { return m_dataToolTipsManager.get(); } /** * @return The data tool tips manager (const method) */ const DataToolTipsManager* SessionManager::getDataToolTipsManager() const { return m_dataToolTipsManager.get(); } /** * @return Image capture settings for image capture dialog. */ ImageCaptureSettings* SessionManager::getImageCaptureDialogSettings() { return m_imageCaptureDialogSettings; } /** * @return Image capture settings for image capture dialog (const method) */ const ImageCaptureSettings* SessionManager::getImageCaptureDialogSettings() const { return m_imageCaptureDialogSettings; } /** * @return The movie recorder */ MovieRecorder* SessionManager::getMovieRecorder() { return m_movieRecorder.get(); } /** * @return The movie recorder (const method) */ const MovieRecorder* SessionManager::getMovieRecorder() const { return m_movieRecorder.get(); } connectome-workbench-1.4.2/src/Brain/SessionManager.h000066400000000000000000000130051360521144700225430ustar00rootroot00000000000000#ifndef __SESSION_MANAGER__H_ #define __SESSION_MANAGER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "ApplicationTypeEnum.h" #include "BrainConstants.h" #include "CaretObject.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" #include "SpacerTabIndex.h" namespace caret { class Brain; class BrowserTabContent; class BrowserWindowContent; class CaretPreferences; class CiftiConnectivityMatrixDataFileManager; class CiftiFiberTrajectoryManager; class DataToolTipsManager; class ImageCaptureSettings; class Model; class MovieRecorder; class SpacerTabContent; /// Manages a Caret session which contains 'global' brain data. class SessionManager : public CaretObject, public EventListenerInterface, public SceneableInterface { public: static void createSessionManager(const ApplicationTypeEnum::Enum applicationType); static void deleteSessionManager(); static SessionManager* get(); void receiveEvent(Event* event); Brain* addBrain(const bool shareDisplayPropertiesFlag); int32_t getNumberOfBrains() const; Brain* getBrain(const int32_t brainIndex) const; CaretPreferences* getCaretPreferences(); CiftiConnectivityMatrixDataFileManager* getCiftiConnectivityMatrixDataFileManager(); const CiftiConnectivityMatrixDataFileManager* getCiftiConnectivityMatrixDataFileManager() const; CiftiFiberTrajectoryManager* getCiftiFiberTrajectoryManager(); const CiftiFiberTrajectoryManager* getCiftiFiberTrajectoryManager() const; DataToolTipsManager* getDataToolTipsManager(); const DataToolTipsManager* getDataToolTipsManager() const; ImageCaptureSettings* getImageCaptureDialogSettings(); const ImageCaptureSettings* getImageCaptureDialogSettings() const; MovieRecorder* getMovieRecorder(); const MovieRecorder* getMovieRecorder() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: SessionManager(); virtual ~SessionManager(); SessionManager(const SessionManager&); SessionManager& operator=(const SessionManager&); public: virtual AString toString() const; private: void updateBrowserTabContents(); void resetBrains(const bool keepSceneFiles); void clearSpacerTabs(); SceneClass* savePreferencesToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); void restorePreferencesFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); /** The session manager */ static SessionManager* s_singletonSessionManager; /** The browser tabs */ BrowserTabContent* m_browserTabs[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** The browser window content */ std::array m_browserWindowContent; /** Holds valid models */ std::vector m_models; /** Holds all loaded brains */ std::vector m_brains; /** Caret's preferences */ CaretPreferences* m_caretPreferences; /** Loads connectivity matrix data */ CiftiConnectivityMatrixDataFileManager* m_ciftiConnectivityMatrixDataFileManager; /** Loads fiber trajectory data */ CiftiFiberTrajectoryManager* m_ciftiFiberTrajectoryManager; /** Data Tool Tips Manager */ std::unique_ptr m_dataToolTipsManager; /** Settings for image capture dialog */ ImageCaptureSettings* m_imageCaptureDialogSettings; /** Map to spacer tabs where key is window index, row index, column index */ std::map m_spacerTabsMap; std::unique_ptr m_movieRecorder; }; #ifdef __SESSION_MANAGER_DECLARE__ SessionManager* SessionManager::s_singletonSessionManager = NULL; #endif // __SESSION_MANAGER_DECLARE__ } // namespace #endif //__SESSION_MANAGER__H_ connectome-workbench-1.4.2/src/Brain/SpacerTabContent.cxx000066400000000000000000000046231360521144700234050ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SPACER_TAB_CONTENT_DECLARE__ #include "SpacerTabContent.h" #undef __SPACER_TAB_CONTENT_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::SpacerTabContent * \brief Content of a tile tabs 'spacer' * \ingroup Brain */ /** * Constructor. * * @param windowIndex * Index of the window. * @param rowIndex * Index of the row. * @param columnIndex * Index of the column. */ SpacerTabContent::SpacerTabContent(const int32_t windowIndex, const int32_t rowIndex, const int32_t columnIndex) : TabContentBase(), m_key(windowIndex, rowIndex, columnIndex) { } /** * Destructor. */ SpacerTabContent::~SpacerTabContent() { } /** * @return Name of the tab. */ AString SpacerTabContent::getTabName() const { AString s("Spacer " + getTabNamePrefix()); return s; } /** * @return Prefix name of the tab. */ AString SpacerTabContent::getTabNamePrefix() const { AString s("%1, %2"); s = s.arg(m_key.m_rowIndex).arg(m_key.m_columnIndex); return s; } /** * @return The spacer tab index. */ SpacerTabIndex SpacerTabContent::getSpacerTabIndex() const { return m_key; } /** * @return The Window index */ int32_t SpacerTabContent::getWindowIndex() const { return m_key.m_windowIndex; } /** * @return The row index */ int32_t SpacerTabContent::getRowIndex() const { return m_key.m_rowIndex; } /** * @return The column index */ int32_t SpacerTabContent::getColumnIndex() const { return m_key.m_columnIndex; } connectome-workbench-1.4.2/src/Brain/SpacerTabContent.h000066400000000000000000000040271360521144700230300ustar00rootroot00000000000000#ifndef __SPACER_TAB_CONTENT_H__ #define __SPACER_TAB_CONTENT_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "SpacerTabIndex.h" #include "TabContentBase.h" namespace caret { class SpacerTabContent : public TabContentBase { public: SpacerTabContent(const int32_t windowIndex, const int32_t rowIndex, const int32_t columnIndex); virtual ~SpacerTabContent(); SpacerTabContent(const SpacerTabContent&) = delete; SpacerTabContent& operator=(const SpacerTabContent&) = delete; virtual AString getTabName() const override; virtual AString getTabNamePrefix() const override; SpacerTabIndex getSpacerTabIndex() const; int32_t getWindowIndex() const; int32_t getRowIndex() const; int32_t getColumnIndex() const; // ADD_NEW_METHODS_HERE private: SpacerTabIndex m_key; // ADD_NEW_MEMBERS_HERE }; #ifdef __SPACER_TAB_CONTENT_DECLARE__ // #endif // __SPACER_TAB_CONTENT_DECLARE__ } // namespace #endif //__SPACER_TAB_CONTENT_H__ connectome-workbench-1.4.2/src/Brain/Surface.cxx000066400000000000000000000056271360521144700216030ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BoundingBox.h" #include "BrainStructure.h" #include "Surface.h" using namespace caret; /** * Constructor. */ Surface::Surface() { this->initializeMemberSurface(); } /** * Destructor. */ Surface::~Surface() { } /** * Copy constructor. * * @param s * Surface that is copied. */ Surface::Surface(const Surface& s) : SurfaceFile(s) { this->copyHelperSurface(s); } /** * Assignment operator. * * @param s * Contents of "s" are assigned to this. */ Surface& Surface::operator=(const Surface& s) { if (this != &s) { SurfaceFile::operator=(s); this->copyHelperSurface(s); } return *this; } /** * */ AString Surface::getNameForGUI(bool includeStructureFlag) const { AString msg; if (includeStructureFlag) { msg += StructureEnum::toGuiName(this->getStructure()); msg += " "; } msg += SurfaceTypeEnum::toGuiName(this->getSurfaceType()); msg += " "; msg += this->getFileNameNoPath(); return msg; } /** * Set a bounding box using this surface's coordinates. * * @param boundingBoxOut * Bounding box that is updated. */ void Surface::getBounds(BoundingBox& boundingBoxOut) const { boundingBoxOut.set(this->getCoordinate(0), this->getNumberOfNodes()); } /** * Initialize members of this class. */ void Surface::initializeMemberSurface() { this->brainStructure = NULL; } /** * Helps with copying this surface. */ void Surface::copyHelperSurface(const Surface& /*s*/) { this->initializeMemberSurface(); this->computeNormals(); } /** * @return Brain structure that holds this surface. */ const BrainStructure* Surface::getBrainStructure() const { return this->brainStructure; } /** * @return Brain structure that holds this surface. */ BrainStructure* Surface::getBrainStructure() { return this->brainStructure; } /** * Set brain structure that holds this surface. * @param brainStructure * New value for brain structure. */ void Surface::setBrainStructure(BrainStructure* brainStructure) { this->brainStructure = brainStructure; } connectome-workbench-1.4.2/src/Brain/Surface.h000066400000000000000000000034251360521144700212220ustar00rootroot00000000000000 #ifndef __SURFACE_H__ #define __SURFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "SurfaceFile.h" namespace caret { class BoundingBox; class BrainStructure; /** * Maintains view of some type of object. */ class Surface : public SurfaceFile { public: Surface(); ~Surface(); Surface(const Surface& s); Surface& operator=(const Surface& s); AString getNameForGUI(bool includeStructureFlag) const; void getBounds(BoundingBox& boundingBoxOut) const; const BrainStructure* getBrainStructure() const; BrainStructure* getBrainStructure(); void setBrainStructure(BrainStructure* brainStructure); private: void initializeMemberSurface(); void copyHelperSurface(const Surface& s); BrainStructure* brainStructure; }; } // namespace #endif // __SURFACE_H__ connectome-workbench-1.4.2/src/Brain/SurfaceDrawingTypeEnum.cxx000066400000000000000000000227521360521144700246040ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __SURFACE_DRAWING_TYPE_ENUM_DECLARE__ #include "SurfaceDrawingTypeEnum.h" #undef __SURFACE_DRAWING_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::SurfaceDrawingTypeEnum * \brief * * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ SurfaceDrawingTypeEnum::SurfaceDrawingTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ SurfaceDrawingTypeEnum::~SurfaceDrawingTypeEnum() { } /** * Initialize the enumerated metadata. */ void SurfaceDrawingTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(SurfaceDrawingTypeEnum(DRAW_HIDE, "DRAW_HIDE", "Hide")); enumData.push_back(SurfaceDrawingTypeEnum(DRAW_AS_LINKS, "DRAW_AS_LINKS", "Links (Edges)")); enumData.push_back(SurfaceDrawingTypeEnum(DRAW_AS_NODES, "DRAW_AS_NODES", "Vertices")); enumData.push_back(SurfaceDrawingTypeEnum(DRAW_AS_TRIANGLES, "DRAW_AS_TRIANGLES", "Triangles")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const SurfaceDrawingTypeEnum* SurfaceDrawingTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const SurfaceDrawingTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString SurfaceDrawingTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const SurfaceDrawingTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ SurfaceDrawingTypeEnum::Enum SurfaceDrawingTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = DRAW_AS_TRIANGLES; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SurfaceDrawingTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type SurfaceDrawingTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString SurfaceDrawingTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const SurfaceDrawingTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ SurfaceDrawingTypeEnum::Enum SurfaceDrawingTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = DRAW_AS_TRIANGLES; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SurfaceDrawingTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type SurfaceDrawingTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t SurfaceDrawingTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const SurfaceDrawingTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ SurfaceDrawingTypeEnum::Enum SurfaceDrawingTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = DRAW_AS_TRIANGLES; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SurfaceDrawingTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type SurfaceDrawingTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void SurfaceDrawingTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void SurfaceDrawingTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(SurfaceDrawingTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void SurfaceDrawingTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(SurfaceDrawingTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Brain/SurfaceDrawingTypeEnum.h000066400000000000000000000063531360521144700242300ustar00rootroot00000000000000#ifndef __SURFACE_DRAWING_TYPE_ENUM__H_ #define __SURFACE_DRAWING_TYPE_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class SurfaceDrawingTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Do not draw the surface */ DRAW_HIDE, /** Draw as links (edges) */ DRAW_AS_LINKS, /** Draw as nodes */ DRAW_AS_NODES, /** Draw as triangles */ DRAW_AS_TRIANGLES }; ~SurfaceDrawingTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: SurfaceDrawingTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const SurfaceDrawingTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __SURFACE_DRAWING_TYPE_ENUM_DECLARE__ std::vector SurfaceDrawingTypeEnum::enumData; bool SurfaceDrawingTypeEnum::initializedFlag = false; int32_t SurfaceDrawingTypeEnum::integerCodeCounter = 0; #endif // __SURFACE_DRAWING_TYPE_ENUM_DECLARE__ } // namespace #endif //__SURFACE_DRAWING_TYPE_ENUM__H_ connectome-workbench-1.4.2/src/Brain/SurfaceMontageConfigurationAbstract.cxx000066400000000000000000000212721360521144700273240ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SURFACE_MONTAGE_CONFIGURATION_ABSTRACT_DECLARE__ #include "SurfaceMontageConfigurationAbstract.h" #undef __SURFACE_MONTAGE_CONFIGURATION_ABSTRACT_DECLARE__ #include "CaretAssert.h" #include "OverlaySet.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::SurfaceMontageConfiguration * \brief Abstract class for surface montage configurations * \ingroup Brain */ /** * Constructor. * * @param supportsLayoutOrientation * True if the subclass supports layout orientation (landscape/portrait). */ SurfaceMontageConfigurationAbstract::SurfaceMontageConfigurationAbstract(const SurfaceMontageConfigurationTypeEnum::Enum configurationType, const SupportLayoutOrientation supportsLayoutOrientation) : CaretObject(), m_configurationType(configurationType), m_supportsLayoutOrientation(supportsLayoutOrientation) { m_sceneAssistant = new SceneClassAssistant(); m_overlaySet = NULL; m_layoutOrientation = SurfaceMontageLayoutOrientationEnum::LANDSCAPE_LAYOUT_ORIENTATION; /* * Note: Since these members are initialized by the constructor, * they do not need to be saved to the scene: * m_configuration * m_supportsLayoutOrientation * m_surfaceMontageViewports * */ m_sceneAssistant->add("m_layoutOrientation", &m_layoutOrientation); } /** * Destructor. */ SurfaceMontageConfigurationAbstract::~SurfaceMontageConfigurationAbstract() { delete m_sceneAssistant; CaretAssertMessage(m_overlaySet, "Did you forget to call setupOverlaySet() from subclass constructor?"); delete m_overlaySet; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString SurfaceMontageConfigurationAbstract::toString() const { return "SurfaceMontageConfiguration"; } /** * Setup the overlay set for the subclass. * * @param includeSurfaceStructures * Surface structures supported by subclass. */ void SurfaceMontageConfigurationAbstract::setupOverlaySet(const AString& overlaySetName, const int32_t tabIndex, const std::vector& includeSurfaceStructures) { m_overlaySet = new OverlaySet(overlaySetName, tabIndex, includeSurfaceStructures, Overlay::INCLUDE_VOLUME_FILES_NO); m_sceneAssistant->add("m_overlaySet", "OverlaySet", m_overlaySet); } /** * @return The overlay set */ OverlaySet* SurfaceMontageConfigurationAbstract::getOverlaySet() { CaretAssertMessage(m_overlaySet, "Did you forget to call setupOverlaySet() from subclass constructor?"); return m_overlaySet; } /** * @return The overlay set (const method) */ const OverlaySet* SurfaceMontageConfigurationAbstract::getOverlaySet() const { CaretAssertMessage(m_overlaySet, "Did you forget to call setupOverlaySet() from subclass constructor?"); return m_overlaySet; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* SurfaceMontageConfigurationAbstract::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "SurfaceMontageConfigurationAbstract", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); saveMembersToScene(sceneAttributes, sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void SurfaceMontageConfigurationAbstract::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); restoreMembersFromScene(sceneAttributes, sceneClass); } /** * @return The configuration type. */ SurfaceMontageConfigurationTypeEnum::Enum SurfaceMontageConfigurationAbstract::getConfigurationType() const { return m_configurationType; } /** * @return Configuration has a layout orientation. */ bool SurfaceMontageConfigurationAbstract::hasLayoutOrientation() const { return (m_supportsLayoutOrientation == SUPPORTS_LAYOUT_ORIENTATION_YES); } /** * @return The selected layout orientation. */ SurfaceMontageLayoutOrientationEnum::Enum SurfaceMontageConfigurationAbstract::getLayoutOrientation() const { return m_layoutOrientation; } /** * Set the layout orientation. * * @param layoutOrientation * New value for layout orientation. */ void SurfaceMontageConfigurationAbstract::setLayoutOrientation(const SurfaceMontageLayoutOrientationEnum::Enum layoutOrientation) { m_layoutOrientation = layoutOrientation; } /** * Get the montage viewports for drawing by OpenGL. The montage viewports * will be updated prior to returning them. OpenGL will update * the viewing dimensions (x, y, width, height) in the returned montage * viewports. * * @param surfaceMontageViewports * The montage viewports. */ void SurfaceMontageConfigurationAbstract::getSurfaceMontageViewportsForDrawing(std::vector& surfaceMontageViewports) { m_surfaceMontageViewports.clear(); updateSurfaceMontageViewports(m_surfaceMontageViewports); for (std::vector::iterator iter = m_surfaceMontageViewports.begin(); iter != m_surfaceMontageViewports.end(); iter++) { SurfaceMontageViewport& svp = *iter; surfaceMontageViewports.push_back(&svp); } } /** * Get the montage viewports that will be used by the mouse transformations. * * @param surfaceMontageViewports * The montage viewports. */ void SurfaceMontageConfigurationAbstract::getSurfaceMontageViewportsForTransformation(std::vector& surfaceMontageViewports) const { surfaceMontageViewports.clear(); for (std::vector::const_iterator iter = m_surfaceMontageViewports.begin(); iter != m_surfaceMontageViewports.end(); iter++) { const SurfaceMontageViewport& svp = *iter; surfaceMontageViewports.push_back(&svp); } } /** * Copy the given configuration to this configurtion. * * @param configuration. * Configuration that is copied. */ void SurfaceMontageConfigurationAbstract::copyConfiguration(SurfaceMontageConfigurationAbstract* configuration) { CaretAssert(m_configurationType == configuration->m_configurationType); m_overlaySet->copyOverlaySet(configuration->m_overlaySet); m_layoutOrientation = configuration->m_layoutOrientation; m_surfaceMontageViewports = configuration->m_surfaceMontageViewports; } connectome-workbench-1.4.2/src/Brain/SurfaceMontageConfigurationAbstract.h000066400000000000000000000123071360521144700267500ustar00rootroot00000000000000#ifndef __SURFACE_MONTAGE_CONFIGURATION_ABSTRACT_H__ #define __SURFACE_MONTAGE_CONFIGURATION_ABSTRACT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "SceneableInterface.h" #include "StructureEnum.h" #include "SurfaceMontageConfigurationTypeEnum.h" #include "SurfaceMontageLayoutOrientationEnum.h" #include "SurfaceMontageViewport.h" namespace caret { class OverlaySet; class PlainTextStringBuilder; class SceneClassAssistant; class SurfaceMontageViewport; class SurfaceMontageConfigurationAbstract : public CaretObject, public SceneableInterface { public: enum SupportLayoutOrientation { SUPPORTS_LAYOUT_ORIENTATION_YES, SUPPORTS_LAYOUT_ORIENTATION_NO, }; SurfaceMontageConfigurationAbstract(const SurfaceMontageConfigurationTypeEnum::Enum configuration, const SupportLayoutOrientation supportsLayoutOrientation); virtual ~SurfaceMontageConfigurationAbstract(); SurfaceMontageConfigurationTypeEnum::Enum getConfigurationType() const; virtual void initializeSelectedSurfaces() = 0; virtual bool isValid() = 0; OverlaySet* getOverlaySet(); const OverlaySet* getOverlaySet() const; bool hasLayoutOrientation() const; SurfaceMontageLayoutOrientationEnum::Enum getLayoutOrientation() const; void setLayoutOrientation(const SurfaceMontageLayoutOrientationEnum::Enum layoutOrientation); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); void getSurfaceMontageViewportsForDrawing(std::vector& surfaceMontageViewports); void getSurfaceMontageViewportsForTransformation(std::vector& surfaceMontageViewports) const; virtual void copyConfiguration(SurfaceMontageConfigurationAbstract* configuration); private: SurfaceMontageConfigurationAbstract(const SurfaceMontageConfigurationAbstract&); SurfaceMontageConfigurationAbstract& operator=(const SurfaceMontageConfigurationAbstract&); protected: /** * Update the montage viewports using the current selected surfaces and settings. * * @param surfaceMontageViewports * Will be loaded with the montage viewports. */ virtual void updateSurfaceMontageViewports(std::vector& surfaceMontageViewports) = 0; void setupOverlaySet(const AString& overlaySetName, const int32_t tabIndex, const std::vector& includeSurfaceStructures); virtual void saveMembersToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) = 0; virtual void restoreMembersFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) = 0; public: // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual void getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const = 0; virtual void getDisplayedSurfaces(std::vector& surfacesOut) const = 0; private: SceneClassAssistant* m_sceneAssistant; const SurfaceMontageConfigurationTypeEnum::Enum m_configurationType; const SupportLayoutOrientation m_supportsLayoutOrientation; SurfaceMontageLayoutOrientationEnum::Enum m_layoutOrientation; OverlaySet* m_overlaySet; std::vector m_surfaceMontageViewports; // ADD_NEW_MEMBERS_HERE friend class ModelSurfaceMontage; }; #ifdef __SURFACE_MONTAGE_CONFIGURATION_ABSTRACT_DECLARE__ // #endif // __SURFACE_MONTAGE_CONFIGURATION_ABSTRACT_DECLARE__ } // namespace #endif //__SURFACE_MONTAGE_CONFIGURATION_ABSTRACT_H__ connectome-workbench-1.4.2/src/Brain/SurfaceMontageConfigurationCerebellar.cxx000066400000000000000000000731601360521144700276240ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SURFACE_MONTAGE_CONFIGURATION_CEREBELLAR_DECLARE__ #include "SurfaceMontageConfigurationCerebellar.h" #undef __SURFACE_MONTAGE_CONFIGURATION_CEREBELLAR_DECLARE__ #include "CaretAssert.h" #include "PlainTextStringBuilder.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "Surface.h" #include "SurfaceSelectionModel.h" using namespace caret; /** * \class caret::SurfaceMontageConfigurationCerebellar * \brief Surface montage configuration for cerebellum. * \ingroup Brain */ /** * Constructor. */ SurfaceMontageConfigurationCerebellar::SurfaceMontageConfigurationCerebellar(const int32_t tabIndex) : SurfaceMontageConfigurationAbstract(SurfaceMontageConfigurationTypeEnum::CEREBELLAR_CORTEX_CONFIGURATION, SUPPORTS_LAYOUT_ORIENTATION_YES) { std::vector validSurfaceTypes; SurfaceTypeEnum::getAllEnumsExceptFlat(validSurfaceTypes); m_firstSurfaceSelectionModel = new SurfaceSelectionModel(StructureEnum::CEREBELLUM, validSurfaceTypes); m_secondSurfaceSelectionModel = new SurfaceSelectionModel(StructureEnum::CEREBELLUM, validSurfaceTypes); m_firstSurfaceEnabled = true; m_secondSurfaceEnabled = false; m_dorsalEnabled = true; m_ventralEnabled = true; m_anteriorEnabled = true; m_posteriorEnabled = true; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_firstSurfaceSelectionModel", "SurfaceSelectionModel", m_firstSurfaceSelectionModel); m_sceneAssistant->add("m_secondSurfaceSelectionModel", "SurfaceSelectionModel", m_secondSurfaceSelectionModel); m_sceneAssistant->add("m_firstSurfaceEnabled", &m_firstSurfaceEnabled); m_sceneAssistant->add("m_secondSurfaceEnabled", &m_secondSurfaceEnabled); m_sceneAssistant->add("m_dorsalEnabled", &m_dorsalEnabled); m_sceneAssistant->add("m_ventralEnabled", &m_ventralEnabled); m_sceneAssistant->add("m_anteriorEnabled", &m_anteriorEnabled); m_sceneAssistant->add("m_posteriorEnabled", &m_posteriorEnabled); std::vector supportedStructures; supportedStructures.push_back(StructureEnum::CEREBELLUM); setupOverlaySet("Cerebellar Montage", tabIndex, supportedStructures); } /** * Destructor. */ SurfaceMontageConfigurationCerebellar::~SurfaceMontageConfigurationCerebellar() { delete m_firstSurfaceSelectionModel; delete m_secondSurfaceSelectionModel; delete m_sceneAssistant; } /** * @return Is this configuration valid? */ bool SurfaceMontageConfigurationCerebellar::isValid() { const bool valid = (getFirstSurfaceSelectionModel()->getSurface() != NULL); return valid; } /** * Initialize the selected surfaces. */ void SurfaceMontageConfigurationCerebellar::initializeSelectedSurfaces() { } /** * @return First surface selection model. */ SurfaceSelectionModel* SurfaceMontageConfigurationCerebellar::getFirstSurfaceSelectionModel() { return m_firstSurfaceSelectionModel; } /** * @return First surface selection model. */ const SurfaceSelectionModel* SurfaceMontageConfigurationCerebellar::getFirstSurfaceSelectionModel() const { return m_firstSurfaceSelectionModel; } /** * @return Second surface selection model. */ SurfaceSelectionModel* SurfaceMontageConfigurationCerebellar::getSecondSurfaceSelectionModel() { return m_secondSurfaceSelectionModel; } /** * @return Second surface selection model. */ const SurfaceSelectionModel* SurfaceMontageConfigurationCerebellar::getSecondSurfaceSelectionModel() const { return m_secondSurfaceSelectionModel; } /** * @return Is first surface enabled. */ bool SurfaceMontageConfigurationCerebellar::isFirstSurfaceEnabled() const { return m_firstSurfaceEnabled; } /** * Set first surface enabled status. * * @param enabled * New enabled status. */ void SurfaceMontageConfigurationCerebellar::setFirstSurfaceEnabled(const bool enabled) { m_firstSurfaceEnabled = enabled; } /** * @return Is second surface enabled. */ bool SurfaceMontageConfigurationCerebellar::isSecondSurfaceEnabled() const { return m_secondSurfaceEnabled; } /** * Set first surface enabled status. * * @param enabled * New enabled status. */ void SurfaceMontageConfigurationCerebellar::setSecondSurfaceEnabled(const bool enabled) { m_secondSurfaceEnabled = enabled; } /** * @return Is dorsal enabled. */ bool SurfaceMontageConfigurationCerebellar::isDorsalEnabled() const { return m_dorsalEnabled; } /** * Set dorsal enabled. * * @param enabled * New enabled status. */ void SurfaceMontageConfigurationCerebellar::setDorsalEnabled(const bool enabled) { m_dorsalEnabled = enabled; } /** * @return Is ventral enabled. */ bool SurfaceMontageConfigurationCerebellar::isVentralEnabled() const { return m_ventralEnabled; } /** * Set ventral enabled. * * @param enabled * New enabled status. */ void SurfaceMontageConfigurationCerebellar::setVentralEnabled(const bool enabled) { m_ventralEnabled = enabled; } /** * @return Is anterior enabled. */ bool SurfaceMontageConfigurationCerebellar::isAnteriorEnabled() const { return m_anteriorEnabled; } /** * Set anterior enabled. * * @param enabled * New enabled status. */ void SurfaceMontageConfigurationCerebellar::setAnteriorEnabled(const bool enabled) { m_anteriorEnabled = enabled; } /** * @return Is posterior enabled. */ bool SurfaceMontageConfigurationCerebellar::isPosteriorEnabled() const { return m_posteriorEnabled; } /** * Set posterior enabled. * * @param enabled * New enabled status. */ void SurfaceMontageConfigurationCerebellar::setPosteriorEnabled(const bool enabled) { m_posteriorEnabled = enabled; } /** * Update the montage viewports using the current selected surfaces and settings. * * @param surfaceMontageViewports * Will be loaded with the montage viewports. */ void SurfaceMontageConfigurationCerebellar::updateSurfaceMontageViewports(std::vector& surfaceMontageViewports) { surfaceMontageViewports.clear(); std::vector anteriorViewports; std::vector dorsalViewports; std::vector posteriorViewports; std::vector ventralViewports; int32_t numFirst = 0; if (m_firstSurfaceEnabled) { Surface* surface = m_firstSurfaceSelectionModel->getSurface(); if (surface != NULL) { if (m_anteriorEnabled) { anteriorViewports.push_back(SurfaceMontageViewport(surface, ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_ANTERIOR)); numFirst++; } if (m_dorsalEnabled) { dorsalViewports.push_back(SurfaceMontageViewport(surface, ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_DORSAL)); numFirst++; } if (m_posteriorEnabled) { posteriorViewports.push_back(SurfaceMontageViewport(surface, ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_POSTERIOR)); numFirst++; } if (m_ventralEnabled) { ventralViewports.push_back(SurfaceMontageViewport(surface, ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_VENTRAL)); numFirst++; } } } int32_t numSecond = 0; if (m_secondSurfaceEnabled) { Surface* surface = m_secondSurfaceSelectionModel->getSurface(); if (surface != NULL) { if (m_anteriorEnabled) { anteriorViewports.push_back(SurfaceMontageViewport(surface, ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_ANTERIOR)); numSecond++; } if (m_dorsalEnabled) { dorsalViewports.push_back(SurfaceMontageViewport(surface, ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_DORSAL)); numSecond++; } if (m_posteriorEnabled) { posteriorViewports.push_back(SurfaceMontageViewport(surface, ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_POSTERIOR)); numSecond++; } if (m_ventralEnabled) { ventralViewports.push_back(SurfaceMontageViewport(surface, ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_VENTRAL)); numSecond++; } } } std::vector allViewports; allViewports.insert(allViewports.end(), dorsalViewports.begin(), dorsalViewports.end()); allViewports.insert(allViewports.end(), ventralViewports.begin(), ventralViewports.end()); allViewports.insert(allViewports.end(), anteriorViewports.begin(), anteriorViewports.end()); allViewports.insert(allViewports.end(), posteriorViewports.begin(), posteriorViewports.end()); const int32_t totalNum = numFirst + numSecond; CaretAssert(static_cast(allViewports.size()) == totalNum); if (totalNum == 1) { surfaceMontageViewports.insert(surfaceMontageViewports.end(), allViewports.begin(), allViewports.end()); CaretAssert(surfaceMontageViewports.size() == 1); surfaceMontageViewports[0].setRowAndColumn(0, 0); } else if (totalNum == 2) { surfaceMontageViewports.insert(surfaceMontageViewports.end(), allViewports.begin(), allViewports.end()); CaretAssert(surfaceMontageViewports.size() == 2); switch (getLayoutOrientation()) { case SurfaceMontageLayoutOrientationEnum::COLUMN_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[1].setRowAndColumn(1, 0); break; case SurfaceMontageLayoutOrientationEnum::LANDSCAPE_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[1].setRowAndColumn(0, 1); break; case SurfaceMontageLayoutOrientationEnum::PORTRAIT_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[1].setRowAndColumn(1, 0); break; case SurfaceMontageLayoutOrientationEnum::ROW_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[1].setRowAndColumn(0, 1); break; } } else if (totalNum == 3) { surfaceMontageViewports.insert(surfaceMontageViewports.end(), allViewports.begin(), allViewports.end()); CaretAssert(surfaceMontageViewports.size() == 3); int32_t dorsalIndex(-1); int32_t ventralIndex(-1); int32_t anteriorIndex(-1); int32_t posteriorIndex(-1); for (int32_t i = 0; i < 3; i++) { SurfaceMontageViewport& svp = surfaceMontageViewports[i]; switch (svp.getProjectionViewType()) { case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_ANTERIOR: svp.setRowAndColumn(1, 0); anteriorIndex = i; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_DORSAL: svp.setRowAndColumn(0, 0); dorsalIndex = i; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_POSTERIOR: svp.setRowAndColumn(1, 1); posteriorIndex = i; break; case ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_VENTRAL: svp.setRowAndColumn(0, 1); ventralIndex = i; break; default: CaretAssert(0); } } switch (getLayoutOrientation()) { case SurfaceMontageLayoutOrientationEnum::COLUMN_LAYOUT_ORIENTATION: { int32_t columnIndex = 0; if (dorsalIndex >= 0) { CaretAssertVectorIndex(surfaceMontageViewports, dorsalIndex); surfaceMontageViewports[dorsalIndex].setRowAndColumn(columnIndex, 0); columnIndex++; } if (ventralIndex >= 0) { CaretAssertVectorIndex(surfaceMontageViewports, ventralIndex); surfaceMontageViewports[ventralIndex].setRowAndColumn(columnIndex, 0); columnIndex++; } if (anteriorIndex >= 0) { CaretAssertVectorIndex(surfaceMontageViewports, anteriorIndex); surfaceMontageViewports[anteriorIndex].setRowAndColumn(columnIndex, 0); columnIndex++; } if (posteriorIndex >= 0) { CaretAssertVectorIndex(surfaceMontageViewports, posteriorIndex); surfaceMontageViewports[posteriorIndex].setRowAndColumn(columnIndex, 0); columnIndex++; } } break; case SurfaceMontageLayoutOrientationEnum::LANDSCAPE_LAYOUT_ORIENTATION: break; case SurfaceMontageLayoutOrientationEnum::PORTRAIT_LAYOUT_ORIENTATION: break; case SurfaceMontageLayoutOrientationEnum::ROW_LAYOUT_ORIENTATION: { int32_t rowIndex = 0; if (dorsalIndex >= 0) { CaretAssertVectorIndex(surfaceMontageViewports, dorsalIndex); surfaceMontageViewports[dorsalIndex].setRowAndColumn(0, rowIndex); rowIndex++; } if (ventralIndex >= 0) { CaretAssertVectorIndex(surfaceMontageViewports, ventralIndex); surfaceMontageViewports[ventralIndex].setRowAndColumn(0, rowIndex); rowIndex++; } if (anteriorIndex >= 0) { CaretAssertVectorIndex(surfaceMontageViewports, anteriorIndex); surfaceMontageViewports[anteriorIndex].setRowAndColumn(0, rowIndex); rowIndex++; } if (posteriorIndex >= 0) { CaretAssertVectorIndex(surfaceMontageViewports, posteriorIndex); surfaceMontageViewports[posteriorIndex].setRowAndColumn(0, rowIndex); rowIndex++; } } break; } } else if (totalNum == 4) { if ((numFirst == 4) || (numSecond == 4)){ surfaceMontageViewports.insert(surfaceMontageViewports.end(), allViewports.begin(), allViewports.end()); CaretAssert(surfaceMontageViewports.size() == 4); surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[1].setRowAndColumn(0, 1); surfaceMontageViewports[2].setRowAndColumn(1, 0); surfaceMontageViewports[3].setRowAndColumn(1, 1); } else if (numFirst == numSecond) { surfaceMontageViewports.insert(surfaceMontageViewports.end(), allViewports.begin(), allViewports.end()); CaretAssert(surfaceMontageViewports.size() == 4); surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[1].setRowAndColumn(0, 1); surfaceMontageViewports[2].setRowAndColumn(1, 0); surfaceMontageViewports[3].setRowAndColumn(1, 1); } else { CaretAssert(0); } switch (getLayoutOrientation()) { case SurfaceMontageLayoutOrientationEnum::COLUMN_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[2].setRowAndColumn(1, 0); surfaceMontageViewports[1].setRowAndColumn(2, 0); surfaceMontageViewports[3].setRowAndColumn(3, 0); break; case SurfaceMontageLayoutOrientationEnum::LANDSCAPE_LAYOUT_ORIENTATION: break; case SurfaceMontageLayoutOrientationEnum::PORTRAIT_LAYOUT_ORIENTATION: break; case SurfaceMontageLayoutOrientationEnum::ROW_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[2].setRowAndColumn(0, 1); surfaceMontageViewports[1].setRowAndColumn(0, 2); surfaceMontageViewports[3].setRowAndColumn(0, 3); break; } } else if (totalNum == 6) { surfaceMontageViewports.insert(surfaceMontageViewports.end(), allViewports.begin(), allViewports.end()); CaretAssert(surfaceMontageViewports.size() == 6); switch (getLayoutOrientation()) { case SurfaceMontageLayoutOrientationEnum::COLUMN_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[2].setRowAndColumn(1, 0); surfaceMontageViewports[4].setRowAndColumn(2, 0); surfaceMontageViewports[1].setRowAndColumn(3, 0); surfaceMontageViewports[3].setRowAndColumn(4, 0); surfaceMontageViewports[5].setRowAndColumn(5, 0); break; case SurfaceMontageLayoutOrientationEnum::LANDSCAPE_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[1].setRowAndColumn(1, 0); surfaceMontageViewports[2].setRowAndColumn(0, 1); surfaceMontageViewports[3].setRowAndColumn(1, 1); surfaceMontageViewports[4].setRowAndColumn(0, 2); surfaceMontageViewports[5].setRowAndColumn(1, 2); break; case SurfaceMontageLayoutOrientationEnum::PORTRAIT_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[1].setRowAndColumn(0, 1); surfaceMontageViewports[2].setRowAndColumn(1, 0); surfaceMontageViewports[3].setRowAndColumn(1, 1); surfaceMontageViewports[4].setRowAndColumn(2, 0); surfaceMontageViewports[5].setRowAndColumn(2, 1); break; case SurfaceMontageLayoutOrientationEnum::ROW_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[2].setRowAndColumn(0, 1); surfaceMontageViewports[4].setRowAndColumn(0, 2); surfaceMontageViewports[1].setRowAndColumn(0, 3); surfaceMontageViewports[3].setRowAndColumn(0, 4); surfaceMontageViewports[5].setRowAndColumn(0, 5); break; } } else if (totalNum == 8) { surfaceMontageViewports.insert(surfaceMontageViewports.end(), allViewports.begin(), allViewports.end()); CaretAssert(surfaceMontageViewports.size() == 8); switch (getLayoutOrientation()) { case SurfaceMontageLayoutOrientationEnum::COLUMN_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[2].setRowAndColumn(1, 0); surfaceMontageViewports[4].setRowAndColumn(2, 0); surfaceMontageViewports[6].setRowAndColumn(3, 0); surfaceMontageViewports[1].setRowAndColumn(4, 0); surfaceMontageViewports[3].setRowAndColumn(5, 0); surfaceMontageViewports[5].setRowAndColumn(6, 0); surfaceMontageViewports[7].setRowAndColumn(7, 0); break; case SurfaceMontageLayoutOrientationEnum::LANDSCAPE_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[1].setRowAndColumn(0, 2); surfaceMontageViewports[2].setRowAndColumn(0, 1); surfaceMontageViewports[3].setRowAndColumn(0, 3); surfaceMontageViewports[4].setRowAndColumn(1, 0); surfaceMontageViewports[5].setRowAndColumn(1, 2); surfaceMontageViewports[6].setRowAndColumn(1, 1); surfaceMontageViewports[7].setRowAndColumn(1, 3); break; case SurfaceMontageLayoutOrientationEnum::PORTRAIT_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[1].setRowAndColumn(0, 1); surfaceMontageViewports[2].setRowAndColumn(1, 0); surfaceMontageViewports[3].setRowAndColumn(1, 1); surfaceMontageViewports[4].setRowAndColumn(2, 0); surfaceMontageViewports[5].setRowAndColumn(2, 1); surfaceMontageViewports[6].setRowAndColumn(3, 0); surfaceMontageViewports[7].setRowAndColumn(3, 1); break; case SurfaceMontageLayoutOrientationEnum::ROW_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[2].setRowAndColumn(0, 1); surfaceMontageViewports[4].setRowAndColumn(0, 2); surfaceMontageViewports[6].setRowAndColumn(0, 3); surfaceMontageViewports[1].setRowAndColumn(0, 4); surfaceMontageViewports[3].setRowAndColumn(0, 5); surfaceMontageViewports[5].setRowAndColumn(0, 6); surfaceMontageViewports[7].setRowAndColumn(0, 7); break; } } else if (totalNum > 0) { CaretAssert(0); } // const int32_t numViewports = static_cast(surfaceMontageViewports.size()); // CaretAssert(totalNum == numViewports); // // std::cout << "Orientation: " << SurfaceMontageLayoutOrientationEnum::toName(getLayoutOrientation()) << std::endl; // for (int32_t i = 0; i < numViewports; i++) { // const SurfaceMontageViewport& svp = surfaceMontageViewports[i]; // std::cout << qPrintable("(" // + AString::number(svp.getRow()) // + "," // + AString::number(svp.getColumn()) // + ") " // + ProjectionViewTypeEnum::toName(svp.getProjectionViewType())) // << std::endl; // } // std::cout << std::endl; } /** * Save members to the given scene class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * @param sceneClass * sceneClass to which information is added. */ void SurfaceMontageConfigurationCerebellar::saveMembersToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which information is restored. */ void SurfaceMontageConfigurationCerebellar::restoreMembersFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } /** * Get a description of this object's content. * @return String describing this object's content. */ AString SurfaceMontageConfigurationCerebellar::toString() const { PlainTextStringBuilder tb; getDescriptionOfContent(tb); return tb.getText(); } /** * Get a text description of the instance's content. * * @param descriptionOut * Description of the instance's content. */ void SurfaceMontageConfigurationCerebellar::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const { descriptionOut.addLine("Cerebellar Montage: "); descriptionOut.pushIndentation(); const Surface* firstSurface = getFirstSurfaceSelectionModel()->getSurface(); if (firstSurface != NULL) { if (isFirstSurfaceEnabled()) { descriptionOut.addLine("Surface:"); descriptionOut.pushIndentation(); firstSurface->getDescriptionOfContent(descriptionOut); descriptionOut.popIndentation(); } } const Surface* secondSurface = getSecondSurfaceSelectionModel()->getSurface(); if (secondSurface != NULL) { if (isSecondSurfaceEnabled()) { descriptionOut.addLine("Surface:"); descriptionOut.pushIndentation(); secondSurface->getDescriptionOfContent(descriptionOut); descriptionOut.popIndentation(); } } AString viewsMsg = "Selected Views: "; if (isAnteriorEnabled()) { viewsMsg += " Anterior"; } if (isDorsalEnabled()) { viewsMsg += " Dorsal"; } if (isPosteriorEnabled()) { viewsMsg += " Posterior"; } if (isVentralEnabled()) { viewsMsg += " Ventral"; } descriptionOut.addLine(viewsMsg); descriptionOut.popIndentation(); } /** * Get all surfaces displayed in this configuration. * * @param surfaceOut * Will contain all displayed surfaces upon exit. */ void SurfaceMontageConfigurationCerebellar::getDisplayedSurfaces(std::vector& surfacesOut) const { surfacesOut.clear(); const Surface* firstSurface = getFirstSurfaceSelectionModel()->getSurface(); if (firstSurface != NULL) { if (isFirstSurfaceEnabled()) { surfacesOut.push_back(const_cast(firstSurface)); } } const Surface* secondSurface = getSecondSurfaceSelectionModel()->getSurface(); if (secondSurface != NULL) { if (isSecondSurfaceEnabled()) { if (secondSurface != firstSurface) { surfacesOut.push_back(const_cast(secondSurface)); } } } } /** * Copy the given configuration to this configurtion. * * @param configuration. * Configuration that is copied. */ void SurfaceMontageConfigurationCerebellar::copyConfiguration(SurfaceMontageConfigurationAbstract* configuration) { SurfaceMontageConfigurationCerebellar* cerebellarConfiguration = dynamic_cast(configuration); CaretAssert(cerebellarConfiguration); SurfaceMontageConfigurationAbstract::copyConfiguration(configuration); m_firstSurfaceSelectionModel->setSurface(cerebellarConfiguration->m_firstSurfaceSelectionModel->getSurface()); m_secondSurfaceSelectionModel->setSurface(cerebellarConfiguration->m_secondSurfaceSelectionModel->getSurface()); m_firstSurfaceEnabled = cerebellarConfiguration->m_firstSurfaceEnabled; m_secondSurfaceEnabled = cerebellarConfiguration->m_secondSurfaceEnabled; m_dorsalEnabled = cerebellarConfiguration->m_dorsalEnabled; m_ventralEnabled = cerebellarConfiguration->m_ventralEnabled; m_posteriorEnabled = cerebellarConfiguration->m_posteriorEnabled; m_anteriorEnabled = cerebellarConfiguration->m_anteriorEnabled; } connectome-workbench-1.4.2/src/Brain/SurfaceMontageConfigurationCerebellar.h000066400000000000000000000103371360521144700272460ustar00rootroot00000000000000#ifndef __SURFACE_MONTAGE_CONFIGURATION_CEREBELLAR_H__ #define __SURFACE_MONTAGE_CONFIGURATION_CEREBELLAR_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SurfaceMontageConfigurationAbstract.h" namespace caret { class SceneClassAssistant; class SurfaceSelectionModel; class SurfaceMontageConfigurationCerebellar : public SurfaceMontageConfigurationAbstract { public: SurfaceMontageConfigurationCerebellar(const int32_t tabIndex); virtual ~SurfaceMontageConfigurationCerebellar(); virtual void initializeSelectedSurfaces(); SurfaceSelectionModel* getFirstSurfaceSelectionModel(); const SurfaceSelectionModel* getFirstSurfaceSelectionModel() const; SurfaceSelectionModel* getSecondSurfaceSelectionModel(); const SurfaceSelectionModel* getSecondSurfaceSelectionModel() const; bool isFirstSurfaceEnabled() const; void setFirstSurfaceEnabled(const bool enabled); bool isSecondSurfaceEnabled() const; void setSecondSurfaceEnabled(const bool enabled); bool isDorsalEnabled() const; void setDorsalEnabled(const bool enabled); bool isVentralEnabled() const; void setVentralEnabled(const bool enabled); bool isAnteriorEnabled() const; void setAnteriorEnabled(const bool enabled); bool isPosteriorEnabled() const; void setPosteriorEnabled(const bool enabled); virtual void updateSurfaceMontageViewports(std::vector& surfaceMontageViewports); virtual bool isValid(); virtual void copyConfiguration(SurfaceMontageConfigurationAbstract* configuration); private: SurfaceMontageConfigurationCerebellar(const SurfaceMontageConfigurationCerebellar&); SurfaceMontageConfigurationCerebellar& operator=(const SurfaceMontageConfigurationCerebellar&); public: virtual AString toString() const; virtual void getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const; virtual void getDisplayedSurfaces(std::vector& surfacesOut) const; // ADD_NEW_METHODS_HERE protected: virtual void saveMembersToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreMembersFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: SceneClassAssistant* m_sceneAssistant; SurfaceSelectionModel* m_firstSurfaceSelectionModel; SurfaceSelectionModel* m_secondSurfaceSelectionModel; bool m_firstSurfaceEnabled; bool m_secondSurfaceEnabled; bool m_dorsalEnabled; bool m_ventralEnabled; bool m_anteriorEnabled; bool m_posteriorEnabled; // ADD_NEW_MEMBERS_HERE friend class ModelSurfaceMontage; }; #ifdef __SURFACE_MONTAGE_CONFIGURATION_CEREBELLAR_DECLARE__ // #endif // __SURFACE_MONTAGE_CONFIGURATION_CEREBELLAR_DECLARE__ } // namespace #endif //__SURFACE_MONTAGE_CONFIGURATION_CEREBELLAR_H__ connectome-workbench-1.4.2/src/Brain/SurfaceMontageConfigurationCerebral.cxx000066400000000000000000000762111360521144700273030ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SURFACE_MONTAGE_CONFIGURATION_CEREBRAL_DECLARE__ #include "SurfaceMontageConfigurationCerebral.h" #undef __SURFACE_MONTAGE_CONFIGURATION_CEREBRAL_DECLARE__ #include "BrainStructure.h" #include "CaretAssert.h" #include "EventBrainStructureGetAll.h" #include "EventManager.h" #include "PlainTextStringBuilder.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "Surface.h" #include "SurfaceSelectionModel.h" using namespace caret; /** * \class caret::SurfaceMontageConfigurationCerebral * \brief Surface montage cerebral cortext configuration. * \ingroup Brain */ /** * Constructor. */ SurfaceMontageConfigurationCerebral::SurfaceMontageConfigurationCerebral(const int32_t tabIndex) : SurfaceMontageConfigurationAbstract(SurfaceMontageConfigurationTypeEnum::CEREBRAL_CORTEX_CONFIGURATION, SUPPORTS_LAYOUT_ORIENTATION_YES) { std::vector validSurfaceTypes; SurfaceTypeEnum::getAllEnumsExceptFlat(validSurfaceTypes); m_leftFirstSurfaceSelectionModel = new SurfaceSelectionModel(StructureEnum::CORTEX_LEFT, validSurfaceTypes); m_leftSecondSurfaceSelectionModel = new SurfaceSelectionModel(StructureEnum::CORTEX_LEFT, validSurfaceTypes); m_rightFirstSurfaceSelectionModel = new SurfaceSelectionModel(StructureEnum::CORTEX_RIGHT, validSurfaceTypes); m_rightSecondSurfaceSelectionModel = new SurfaceSelectionModel(StructureEnum::CORTEX_RIGHT, validSurfaceTypes); m_leftEnabled = true; m_rightEnabled = true; m_firstSurfaceEnabled = true; m_secondSurfaceEnabled = false; m_lateralEnabled = true; m_medialEnabled = true; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_leftFirstSurfaceSelectionModel", "SurfaceSelectionModel", m_leftFirstSurfaceSelectionModel); m_sceneAssistant->add("m_leftSecondSurfaceSelectionModel", "SurfaceSelectionModel", m_leftSecondSurfaceSelectionModel); m_sceneAssistant->add("m_rightFirstSurfaceSelectionModel", "SurfaceSelectionModel", m_rightFirstSurfaceSelectionModel); m_sceneAssistant->add("m_rightSecondSurfaceSelectionModel", "SurfaceSelectionModel", m_rightSecondSurfaceSelectionModel); m_sceneAssistant->add("m_leftEnabled", &m_leftEnabled); m_sceneAssistant->add("m_rightEnabled", &m_rightEnabled); m_sceneAssistant->add("m_firstSurfaceEnabled", &m_firstSurfaceEnabled); m_sceneAssistant->add("m_secondSurfaceEnabled", &m_secondSurfaceEnabled); m_sceneAssistant->add("m_lateralEnabled", &m_lateralEnabled); m_sceneAssistant->add("m_medialEnabled", &m_medialEnabled); std::vector supportedStructures; supportedStructures.push_back(StructureEnum::CORTEX_LEFT); supportedStructures.push_back(StructureEnum::CORTEX_RIGHT); setupOverlaySet("Cerebral Montage", tabIndex, supportedStructures); } /** * Destructor. */ SurfaceMontageConfigurationCerebral::~SurfaceMontageConfigurationCerebral() { delete m_leftFirstSurfaceSelectionModel; delete m_leftSecondSurfaceSelectionModel; delete m_rightFirstSurfaceSelectionModel; delete m_rightSecondSurfaceSelectionModel; delete m_sceneAssistant; } /** * Initialize the selected surfaces. */ void SurfaceMontageConfigurationCerebral::initializeSelectedSurfaces() { EventBrainStructureGetAll brainStructureEvent; EventManager::get()->sendEvent(brainStructureEvent.getPointer()); Surface* leftAnatSurface = NULL; BrainStructure* leftBrainStructure = brainStructureEvent.getBrainStructureByStructure(StructureEnum::CORTEX_LEFT); if (leftBrainStructure != NULL) { leftAnatSurface = leftBrainStructure->getPrimaryAnatomicalSurface(); } Surface* rightAnatSurface = NULL; BrainStructure* rightBrainStructure = brainStructureEvent.getBrainStructureByStructure(StructureEnum::CORTEX_RIGHT); if (rightBrainStructure != NULL) { rightAnatSurface = rightBrainStructure->getPrimaryAnatomicalSurface(); } m_leftFirstSurfaceSelectionModel->setSurfaceToType(SurfaceTypeEnum::ANATOMICAL); if (leftAnatSurface != NULL) { m_leftFirstSurfaceSelectionModel->setSurface(leftAnatSurface); } m_leftSecondSurfaceSelectionModel->setSurfaceToType(SurfaceTypeEnum::INFLATED, SurfaceTypeEnum::VERY_INFLATED); m_rightFirstSurfaceSelectionModel->setSurfaceToType(SurfaceTypeEnum::ANATOMICAL); if (rightAnatSurface != NULL) { m_rightFirstSurfaceSelectionModel->setSurface(rightAnatSurface); } m_rightSecondSurfaceSelectionModel->setSurfaceToType(SurfaceTypeEnum::INFLATED, SurfaceTypeEnum::VERY_INFLATED); } /** * @return Is this configuration valid? */ bool SurfaceMontageConfigurationCerebral::isValid() { const bool valid = ((getLeftFirstSurfaceSelectionModel()->getSurface() != NULL) || (getRightFirstSurfaceSelectionModel()->getSurface() != NULL)); return valid; } /** * Update the montage viewports using the current selected surfaces and settings. * * @param surfaceMontageViewports * Will be loaded with the montage viewports. */ void SurfaceMontageConfigurationCerebral::updateSurfaceMontageViewports(std::vector& surfaceMontageViewports) { surfaceMontageViewports.clear(); std::vector leftLateralViewports; std::vector leftMedialViewports; std::vector rightLateralViewports; std::vector rightMedialViewports; if (m_leftEnabled) { if (m_firstSurfaceEnabled) { Surface* leftSurface = m_leftFirstSurfaceSelectionModel->getSurface(); if (leftSurface != NULL) { if (m_lateralEnabled) { SurfaceMontageViewport smv(leftSurface, ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_LATERAL); leftLateralViewports.push_back(smv); } if (m_medialEnabled) { SurfaceMontageViewport smv(leftSurface, ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_MEDIAL); leftMedialViewports.push_back(smv); } } } if (m_secondSurfaceEnabled) { Surface* leftSurface = m_leftSecondSurfaceSelectionModel->getSurface(); if (leftSurface != NULL) { if (m_lateralEnabled) { SurfaceMontageViewport smv(leftSurface, ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_LATERAL); leftLateralViewports.push_back(smv); } if (m_medialEnabled) { SurfaceMontageViewport smv(leftSurface, ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_MEDIAL); leftMedialViewports.push_back(smv); } } } } if (m_rightEnabled) { if (m_firstSurfaceEnabled) { Surface* rightSurface = m_rightFirstSurfaceSelectionModel->getSurface(); if (rightSurface != NULL) { if (m_lateralEnabled) { SurfaceMontageViewport smv(rightSurface, ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_LATERAL); rightLateralViewports.push_back(smv); } if (m_medialEnabled) { SurfaceMontageViewport smv(rightSurface, ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_MEDIAL); rightMedialViewports.push_back(smv); } } } } if (m_rightEnabled) { if (m_secondSurfaceEnabled) { Surface* rightSurface = m_rightSecondSurfaceSelectionModel->getSurface(); if (rightSurface != NULL) { if (m_lateralEnabled) { SurfaceMontageViewport smv(rightSurface, ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_LATERAL); rightLateralViewports.push_back(smv); } if (m_medialEnabled) { SurfaceMontageViewport smv(rightSurface, ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_MEDIAL); rightMedialViewports.push_back(smv); } } } } std::vector leftViewports; leftViewports.insert(leftViewports.end(), leftLateralViewports.begin(), leftLateralViewports.end()); leftViewports.insert(leftViewports.end(), leftMedialViewports.begin(), leftMedialViewports.end()); std::vector rightViewports; rightViewports.insert(rightViewports.end(), rightLateralViewports.begin(), rightLateralViewports.end()); rightViewports.insert(rightViewports.end(), rightMedialViewports.begin(), rightMedialViewports.end()); const int32_t numLeft = static_cast(leftViewports.size()); const int32_t numRight = static_cast(rightViewports.size()); const int32_t totalNum = numLeft + numRight; if (totalNum == 1) { surfaceMontageViewports.insert(surfaceMontageViewports.end(), leftViewports.begin(), leftViewports.end()); surfaceMontageViewports.insert(surfaceMontageViewports.end(), rightViewports.begin(), rightViewports.end()); CaretAssert(surfaceMontageViewports.size() == 1); surfaceMontageViewports[0].setRowAndColumn(0, 0); } else if (totalNum == 2) { surfaceMontageViewports.insert(surfaceMontageViewports.end(), leftViewports.begin(), leftViewports.end()); surfaceMontageViewports.insert(surfaceMontageViewports.end(), rightViewports.begin(), rightViewports.end()); CaretAssert(surfaceMontageViewports.size() == 2); switch (getLayoutOrientation()) { case SurfaceMontageLayoutOrientationEnum::COLUMN_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[1].setRowAndColumn(1, 0); break; case SurfaceMontageLayoutOrientationEnum::LANDSCAPE_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[1].setRowAndColumn(0, 1); break; case SurfaceMontageLayoutOrientationEnum::PORTRAIT_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[1].setRowAndColumn(1, 0); break; case SurfaceMontageLayoutOrientationEnum::ROW_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[1].setRowAndColumn(0, 1); break; } } else if (totalNum == 4) { if (numLeft == 4) { surfaceMontageViewports.insert(surfaceMontageViewports.end(), leftLateralViewports.begin(), leftLateralViewports.end()); surfaceMontageViewports.insert(surfaceMontageViewports.end(), leftMedialViewports.begin(), leftMedialViewports.end()); CaretAssert(surfaceMontageViewports.size() == 4); surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[1].setRowAndColumn(1, 0); surfaceMontageViewports[2].setRowAndColumn(0, 1); surfaceMontageViewports[3].setRowAndColumn(1, 1); } else if (numRight == 4) { surfaceMontageViewports.insert(surfaceMontageViewports.end(), rightLateralViewports.begin(), rightLateralViewports.end()); surfaceMontageViewports.insert(surfaceMontageViewports.end(), rightMedialViewports.begin(), rightMedialViewports.end()); CaretAssert(surfaceMontageViewports.size() == 4); surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[1].setRowAndColumn(1, 0); surfaceMontageViewports[2].setRowAndColumn(0, 1); surfaceMontageViewports[3].setRowAndColumn(1, 1); } else if (numLeft == numRight) { surfaceMontageViewports.insert(surfaceMontageViewports.end(), leftViewports.begin(), leftViewports.end()); surfaceMontageViewports.insert(surfaceMontageViewports.end(), rightViewports.begin(), rightViewports.end()); CaretAssert(surfaceMontageViewports.size() == 4); surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[1].setRowAndColumn(1, 0); surfaceMontageViewports[2].setRowAndColumn(0, 1); surfaceMontageViewports[3].setRowAndColumn(1, 1); } else { CaretAssert(0); } /* * Override layout for row/column layout */ switch (getLayoutOrientation()) { case SurfaceMontageLayoutOrientationEnum::COLUMN_LAYOUT_ORIENTATION: for (int32_t i = 0; i < 4; i++) { surfaceMontageViewports[i].setRowAndColumn(i, 0); } break; case SurfaceMontageLayoutOrientationEnum::LANDSCAPE_LAYOUT_ORIENTATION: break; case SurfaceMontageLayoutOrientationEnum::PORTRAIT_LAYOUT_ORIENTATION: break; case SurfaceMontageLayoutOrientationEnum::ROW_LAYOUT_ORIENTATION: for (int32_t i = 0; i < 4; i++) { surfaceMontageViewports[i].setRowAndColumn(0, i); } break; } } else if (totalNum == 8) { surfaceMontageViewports.insert(surfaceMontageViewports.end(), leftLateralViewports.begin(), leftLateralViewports.end()); surfaceMontageViewports.insert(surfaceMontageViewports.end(), leftMedialViewports.begin(), leftMedialViewports.end()); surfaceMontageViewports.insert(surfaceMontageViewports.end(), rightLateralViewports.begin(), rightLateralViewports.end()); surfaceMontageViewports.insert(surfaceMontageViewports.end(), rightMedialViewports.begin(), rightMedialViewports.end()); CaretAssert(surfaceMontageViewports.size() == 8); switch (getLayoutOrientation()) { case SurfaceMontageLayoutOrientationEnum::COLUMN_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[2].setRowAndColumn(1, 0); surfaceMontageViewports[1].setRowAndColumn(2, 0); surfaceMontageViewports[3].setRowAndColumn(3, 0); surfaceMontageViewports[4].setRowAndColumn(4, 0); surfaceMontageViewports[6].setRowAndColumn(5, 0); surfaceMontageViewports[5].setRowAndColumn(6, 0); surfaceMontageViewports[7].setRowAndColumn(7, 0); break; case SurfaceMontageLayoutOrientationEnum::LANDSCAPE_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[1].setRowAndColumn(1, 0); surfaceMontageViewports[2].setRowAndColumn(0, 1); surfaceMontageViewports[3].setRowAndColumn(1, 1); surfaceMontageViewports[4].setRowAndColumn(0, 2); surfaceMontageViewports[5].setRowAndColumn(1, 2); surfaceMontageViewports[6].setRowAndColumn(0, 3); surfaceMontageViewports[7].setRowAndColumn(1, 3); break; case SurfaceMontageLayoutOrientationEnum::PORTRAIT_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[1].setRowAndColumn(1, 0); surfaceMontageViewports[2].setRowAndColumn(0, 1); surfaceMontageViewports[3].setRowAndColumn(1, 1); surfaceMontageViewports[4].setRowAndColumn(2, 0); surfaceMontageViewports[5].setRowAndColumn(3, 0); surfaceMontageViewports[6].setRowAndColumn(2, 1); surfaceMontageViewports[7].setRowAndColumn(3, 1); break; case SurfaceMontageLayoutOrientationEnum::ROW_LAYOUT_ORIENTATION: surfaceMontageViewports[0].setRowAndColumn(0, 0); surfaceMontageViewports[2].setRowAndColumn(0, 1); surfaceMontageViewports[1].setRowAndColumn(0, 2); surfaceMontageViewports[3].setRowAndColumn(0, 3); surfaceMontageViewports[4].setRowAndColumn(0, 4); surfaceMontageViewports[6].setRowAndColumn(0, 5); surfaceMontageViewports[5].setRowAndColumn(0, 6); surfaceMontageViewports[7].setRowAndColumn(0, 7); break; } } else if (totalNum > 0) { CaretAssert(0); } CaretAssert(totalNum == static_cast(surfaceMontageViewports.size())); // std::cout << "Orientation: " << SurfaceMontageLayoutOrientationEnum::toName(getLayoutOrientation()) << std::endl; // for (int32_t i = 0; i < numViewports; i++) { // const SurfaceMontageViewport& svp = surfaceMontageViewports[i]; // std::cout << qPrintable("(" // + AString::number(svp.getRow()) // + "," // + AString::number(svp.getColumn()) // + ") " // + ProjectionViewTypeEnum::toName(svp.getProjectionViewType())) // << std::endl; // } // std::cout << std::endl; } /** * Save members to the given scene class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * @param sceneClass * sceneClass to which information is added. */ void SurfaceMontageConfigurationCerebral::saveMembersToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which information is restored. */ void SurfaceMontageConfigurationCerebral::restoreMembersFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } /** * @return Is left enabled? */ bool SurfaceMontageConfigurationCerebral::isLeftEnabled() const { return m_leftEnabled; } /** * Set left enabled * @param enabled * New status */ void SurfaceMontageConfigurationCerebral::setLeftEnabled(const bool enabled) { m_leftEnabled = enabled; } /** * @return Is right enabled? */ bool SurfaceMontageConfigurationCerebral::isRightEnabled() const { return m_rightEnabled; } /** * Set right enabled * @param enabled * New status */ void SurfaceMontageConfigurationCerebral::setRightEnabled(const bool enabled) { m_rightEnabled = enabled; } /** * @return Is lateral enabled? */ bool SurfaceMontageConfigurationCerebral::isLateralEnabled() const { return m_lateralEnabled; } /** * Set lateral enabled * @param enabled * New status */ void SurfaceMontageConfigurationCerebral::setLateralEnabled(const bool enabled) { m_lateralEnabled = enabled; } /** * @return Is medial enabled? */ bool SurfaceMontageConfigurationCerebral::isMedialEnabled() const { return m_medialEnabled; } /** * Set medial enabled * @param enabled * New status */ void SurfaceMontageConfigurationCerebral::setMedialEnabled(const bool enabled) { m_medialEnabled = enabled; } /** * @return Is enabled? */ bool SurfaceMontageConfigurationCerebral::isFirstSurfaceEnabled() const { return m_firstSurfaceEnabled; } /** * Set first surface enabled * @param enabled * New status */ void SurfaceMontageConfigurationCerebral::setFirstSurfaceEnabled(const bool enabled) { m_firstSurfaceEnabled = enabled; } /** * @return Is first surfce enabled? */ bool SurfaceMontageConfigurationCerebral::isSecondSurfaceEnabled() const { return m_secondSurfaceEnabled; } /** * Set second surface enabled * @param enabled * New status */ void SurfaceMontageConfigurationCerebral::setSecondSurfaceEnabled(const bool enabled) { m_secondSurfaceEnabled = enabled; } /** * @return the left first surface selection in this configuration. */ SurfaceSelectionModel* SurfaceMontageConfigurationCerebral::getLeftFirstSurfaceSelectionModel() { return m_leftFirstSurfaceSelectionModel; } /** * @return the left first surface selection in this configuration. */ const SurfaceSelectionModel* SurfaceMontageConfigurationCerebral::getLeftFirstSurfaceSelectionModel() const { return m_leftFirstSurfaceSelectionModel; } /** * @return the left second surface selection in this configuration. */ SurfaceSelectionModel* SurfaceMontageConfigurationCerebral::getLeftSecondSurfaceSelectionModel() { return m_leftSecondSurfaceSelectionModel; } /** * @return the left second surface selection in this configuration. */ const SurfaceSelectionModel* SurfaceMontageConfigurationCerebral::getLeftSecondSurfaceSelectionModel() const { return m_leftSecondSurfaceSelectionModel; } /** * @return the right first surface selection in this configuration. */ SurfaceSelectionModel* SurfaceMontageConfigurationCerebral::getRightFirstSurfaceSelectionModel() { return m_rightFirstSurfaceSelectionModel; } /** * @return the right first surface selection in this configuration. */ const SurfaceSelectionModel* SurfaceMontageConfigurationCerebral::getRightFirstSurfaceSelectionModel() const { return m_rightFirstSurfaceSelectionModel; } /** * @return the right second surface selection in this configuration. */ SurfaceSelectionModel* SurfaceMontageConfigurationCerebral::getRightSecondSurfaceSelectionModel() { return m_rightSecondSurfaceSelectionModel; } /** * @return the right second surface selection in this configuration. */ const SurfaceSelectionModel* SurfaceMontageConfigurationCerebral::getRightSecondSurfaceSelectionModel() const { return m_rightSecondSurfaceSelectionModel; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString SurfaceMontageConfigurationCerebral::toString() const { PlainTextStringBuilder tb; getDescriptionOfContent(tb); return tb.getText(); } /** * Get a text description of the instance's content. * * @param descriptionOut * Description of the instance's content. */ void SurfaceMontageConfigurationCerebral::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const { AString msg; descriptionOut.addLine("Cerebral Montage: "); descriptionOut.pushIndentation(); if (isLeftEnabled()) { if (isFirstSurfaceEnabled()) { const Surface* firstLeftSurface = getLeftFirstSurfaceSelectionModel()->getSurface(); if (firstLeftSurface != NULL) { descriptionOut.addLine("Left Surface:"); descriptionOut.pushIndentation(); firstLeftSurface->getDescriptionOfContent(descriptionOut); descriptionOut.popIndentation(); } } if (isSecondSurfaceEnabled()) { const Surface* secondLeftSurface = getLeftSecondSurfaceSelectionModel()->getSurface(); if (secondLeftSurface != NULL) { descriptionOut.addLine("Left Surface:"); descriptionOut.pushIndentation(); secondLeftSurface->getDescriptionOfContent(descriptionOut); descriptionOut.popIndentation(); } } } if (isRightEnabled()) { if (isFirstSurfaceEnabled()) { const Surface* firstRightSurface = getRightFirstSurfaceSelectionModel()->getSurface(); if (firstRightSurface != NULL) { descriptionOut.addLine("Right Surface:"); descriptionOut.pushIndentation(); firstRightSurface->getDescriptionOfContent(descriptionOut); descriptionOut.popIndentation(); } } if (isSecondSurfaceEnabled()) { const Surface* secondRightSurface = getRightSecondSurfaceSelectionModel()->getSurface(); if (secondRightSurface != NULL) { descriptionOut.addLine("Right Surface:"); descriptionOut.pushIndentation(); secondRightSurface->getDescriptionOfContent(descriptionOut); descriptionOut.popIndentation(); } } } AString viewsMsg = "Selected Views: "; if (isLateralEnabled()) { viewsMsg += " Lateral"; } if (isMedialEnabled()) { viewsMsg += " Medial"; } descriptionOut.addLine(viewsMsg); descriptionOut.popIndentation(); } /** * Get all surfaces displayed in this configuration. * * @param surfaceOut * Will contain all displayed surfaces upon exit. */ void SurfaceMontageConfigurationCerebral::getDisplayedSurfaces(std::vector& surfacesOut) const { surfacesOut.clear(); if (isLeftEnabled()) { Surface* firstLeftSurface = NULL;; if (isFirstSurfaceEnabled()) { firstLeftSurface = const_cast(getLeftFirstSurfaceSelectionModel()->getSurface()); if (firstLeftSurface != NULL) { surfacesOut.push_back(const_cast(firstLeftSurface)); } } if (isSecondSurfaceEnabled()) { const Surface* secondLeftSurface = getLeftSecondSurfaceSelectionModel()->getSurface(); if (secondLeftSurface != NULL) { if (secondLeftSurface != firstLeftSurface) { surfacesOut.push_back(const_cast(secondLeftSurface)); } } } } if (isRightEnabled()) { Surface* firstRightSurface = NULL; if (isFirstSurfaceEnabled()) { firstRightSurface = const_cast(getRightFirstSurfaceSelectionModel()->getSurface()); if (firstRightSurface != NULL) { surfacesOut.push_back(const_cast(firstRightSurface)); } } if (isSecondSurfaceEnabled()) { const Surface* secondRightSurface = getRightSecondSurfaceSelectionModel()->getSurface(); if (secondRightSurface != NULL) { if (secondRightSurface != firstRightSurface) { surfacesOut.push_back(const_cast(secondRightSurface)); } } } } } /** * Copy the given configuration to this configurtion. * * @param configuration. * Configuration that is copied. */ void SurfaceMontageConfigurationCerebral::copyConfiguration(SurfaceMontageConfigurationAbstract* configuration) { SurfaceMontageConfigurationAbstract::copyConfiguration(configuration); SurfaceMontageConfigurationCerebral* cerebralConfiguration = dynamic_cast(configuration); CaretAssert(cerebralConfiguration); m_leftFirstSurfaceSelectionModel->setSurface(cerebralConfiguration->m_leftFirstSurfaceSelectionModel->getSurface()); m_leftSecondSurfaceSelectionModel->setSurface(cerebralConfiguration->m_leftSecondSurfaceSelectionModel->getSurface()); m_rightFirstSurfaceSelectionModel->setSurface(cerebralConfiguration->m_rightFirstSurfaceSelectionModel->getSurface()); m_rightSecondSurfaceSelectionModel->setSurface(cerebralConfiguration->m_rightSecondSurfaceSelectionModel->getSurface()); m_leftEnabled = cerebralConfiguration->m_leftEnabled; m_rightEnabled = cerebralConfiguration->m_rightEnabled; m_firstSurfaceEnabled = cerebralConfiguration->m_firstSurfaceEnabled; m_secondSurfaceEnabled = cerebralConfiguration->m_secondSurfaceEnabled; m_lateralEnabled = cerebralConfiguration->m_lateralEnabled; m_medialEnabled = cerebralConfiguration->m_medialEnabled; } connectome-workbench-1.4.2/src/Brain/SurfaceMontageConfigurationCerebral.h000066400000000000000000000112531360521144700267230ustar00rootroot00000000000000#ifndef __SURFACE_MONTAGE_CONFIGURATION_CEREBRAL_H__ #define __SURFACE_MONTAGE_CONFIGURATION_CEREBRAL_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SurfaceMontageConfigurationAbstract.h" namespace caret { class SceneClassAssistant; class SurfaceSelectionModel; class SurfaceMontageConfigurationCerebral : public SurfaceMontageConfigurationAbstract { public: SurfaceMontageConfigurationCerebral(const int32_t tabIndex); virtual ~SurfaceMontageConfigurationCerebral(); SurfaceSelectionModel* getLeftFirstSurfaceSelectionModel(); const SurfaceSelectionModel* getLeftFirstSurfaceSelectionModel() const; SurfaceSelectionModel* getLeftSecondSurfaceSelectionModel(); const SurfaceSelectionModel* getLeftSecondSurfaceSelectionModel() const; SurfaceSelectionModel* getRightFirstSurfaceSelectionModel(); const SurfaceSelectionModel* getRightFirstSurfaceSelectionModel() const; SurfaceSelectionModel* getRightSecondSurfaceSelectionModel(); const SurfaceSelectionModel* getRightSecondSurfaceSelectionModel() const; bool isLeftEnabled() const; void setLeftEnabled(const bool enabled); bool isRightEnabled() const; void setRightEnabled(const bool enabled); bool isLateralEnabled() const; void setLateralEnabled(const bool enabled); bool isMedialEnabled() const; void setMedialEnabled(const bool enabled); bool isFirstSurfaceEnabled() const; void setFirstSurfaceEnabled(const bool enabled); bool isSecondSurfaceEnabled() const; void setSecondSurfaceEnabled(const bool enabled); virtual void initializeSelectedSurfaces(); virtual bool isValid(); virtual void updateSurfaceMontageViewports(std::vector& surfaceMontageViewports); virtual void copyConfiguration(SurfaceMontageConfigurationAbstract* configuration); private: SurfaceMontageConfigurationCerebral(const SurfaceMontageConfigurationCerebral&); SurfaceMontageConfigurationCerebral& operator=(const SurfaceMontageConfigurationCerebral&); public: virtual AString toString() const; virtual void getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const; virtual void getDisplayedSurfaces(std::vector& surfacesOut) const; // ADD_NEW_METHODS_HERE protected: virtual void saveMembersToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreMembersFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: SceneClassAssistant* m_sceneAssistant; SurfaceSelectionModel* m_leftFirstSurfaceSelectionModel; SurfaceSelectionModel* m_leftSecondSurfaceSelectionModel; SurfaceSelectionModel* m_rightFirstSurfaceSelectionModel; SurfaceSelectionModel* m_rightSecondSurfaceSelectionModel; bool m_leftEnabled; bool m_rightEnabled; bool m_firstSurfaceEnabled; bool m_secondSurfaceEnabled; bool m_lateralEnabled; bool m_medialEnabled; // ADD_NEW_MEMBERS_HERE friend class ModelSurfaceMontage; }; #ifdef __SURFACE_MONTAGE_CONFIGURATION_CEREBRAL_DECLARE__ // #endif // __SURFACE_MONTAGE_CONFIGURATION_CEREBRAL_DECLARE__ } // namespace #endif //__SURFACE_MONTAGE_CONFIGURATION_CEREBRAL_H__ connectome-workbench-1.4.2/src/Brain/SurfaceMontageConfigurationFlatMaps.cxx000066400000000000000000000332741360521144700272750ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SURFACE_MONTAGE_CONFIGURATION_FLAT_MAPS_DECLARE__ #include "SurfaceMontageConfigurationFlatMaps.h" #undef __SURFACE_MONTAGE_CONFIGURATION_FLAT_MAPS_DECLARE__ #include "CaretAssert.h" #include "PlainTextStringBuilder.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "Surface.h" #include "SurfaceSelectionModel.h" using namespace caret; /** * \class caret::SurfaceMontageConfigurationFlatMaps * \brief Surface montage configuration for flat maps. * \ingroup Brain */ /** * Constructor. */ SurfaceMontageConfigurationFlatMaps::SurfaceMontageConfigurationFlatMaps(const int32_t tabIndex) : SurfaceMontageConfigurationAbstract(SurfaceMontageConfigurationTypeEnum::FLAT_CONFIGURATION, SUPPORTS_LAYOUT_ORIENTATION_NO) { std::vector validSurfaceTypes; validSurfaceTypes.push_back(SurfaceTypeEnum::FLAT); m_leftSurfaceSelectionModel = new SurfaceSelectionModel(StructureEnum::CORTEX_LEFT, validSurfaceTypes); m_rightSurfaceSelectionModel = new SurfaceSelectionModel(StructureEnum::CORTEX_RIGHT, validSurfaceTypes); m_cerebellumSurfaceSelectionModel = new SurfaceSelectionModel(StructureEnum::CEREBELLUM, validSurfaceTypes); m_leftEnabled = true; m_rightEnabled = true; m_cerebellumEnabled = true; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_leftSurfaceSelectionModel", "SurfaceSelectionModel", m_leftSurfaceSelectionModel); m_sceneAssistant->add("m_rightSurfaceSelectionModel", "SurfaceSelectionModel", m_rightSurfaceSelectionModel); m_sceneAssistant->add("m_cerebellumSurfaceSelectionModel", "SurfaceSelectionModel", m_cerebellumSurfaceSelectionModel); m_sceneAssistant->add("m_leftEnabled", &m_leftEnabled); m_sceneAssistant->add("m_rightEnabled", &m_rightEnabled); m_sceneAssistant->add("m_cerebellumEnabled", &m_cerebellumEnabled); std::vector supportedStructures; supportedStructures.push_back(StructureEnum::CEREBELLUM); supportedStructures.push_back(StructureEnum::CORTEX_LEFT); supportedStructures.push_back(StructureEnum::CORTEX_RIGHT); setupOverlaySet("Flat Montage", tabIndex, supportedStructures); } /** * Destructor. */ SurfaceMontageConfigurationFlatMaps::~SurfaceMontageConfigurationFlatMaps() { delete m_leftSurfaceSelectionModel; delete m_rightSurfaceSelectionModel; delete m_cerebellumSurfaceSelectionModel; delete m_sceneAssistant; } /** * Initialize the selected surfaces. */ void SurfaceMontageConfigurationFlatMaps::initializeSelectedSurfaces() { } /** * @return Is this configuration valid? */ bool SurfaceMontageConfigurationFlatMaps::isValid() { const bool valid = ((getLeftSurfaceSelectionModel()->getSurface() != NULL) || (getRightSurfaceSelectionModel()->getSurface() != NULL) || (getCerebellumSurfaceSelectionModel()->getSurface() != NULL)); return valid; } /** * @return Is left enabled? */ bool SurfaceMontageConfigurationFlatMaps::isLeftEnabled() const { return m_leftEnabled; } /** * Set left enabled * @param enabled * New status */ void SurfaceMontageConfigurationFlatMaps::setLeftEnabled(const bool enabled) { m_leftEnabled = enabled; } /** * @return Is right enabled? */ bool SurfaceMontageConfigurationFlatMaps::isRightEnabled() const { return m_rightEnabled; } /** * Set right enabled * @param enabled * New status */ void SurfaceMontageConfigurationFlatMaps::setRightEnabled(const bool enabled) { m_rightEnabled = enabled; } /** * @return Is cerebellum enabled? */ bool SurfaceMontageConfigurationFlatMaps::isCerebellumEnabled() const { return m_cerebellumEnabled; } /** * Set cerebellum enabled * @param enabled * New status */ void SurfaceMontageConfigurationFlatMaps::setCerebellumEnabled(const bool enabled) { m_cerebellumEnabled = enabled; } /** * @return the left surface selection in this configuration. */ SurfaceSelectionModel* SurfaceMontageConfigurationFlatMaps::getLeftSurfaceSelectionModel() { return m_leftSurfaceSelectionModel; } /** * @return the left surface selection in this configuration. */ const SurfaceSelectionModel* SurfaceMontageConfigurationFlatMaps::getLeftSurfaceSelectionModel() const { return m_leftSurfaceSelectionModel; } /** * @return the right surface selection in this configuration. */ SurfaceSelectionModel* SurfaceMontageConfigurationFlatMaps::getRightSurfaceSelectionModel() { return m_rightSurfaceSelectionModel; } /** * @return the right surface selection in this configuration. */ const SurfaceSelectionModel* SurfaceMontageConfigurationFlatMaps::getRightSurfaceSelectionModel() const { return m_rightSurfaceSelectionModel; } /** * @return the cerebellum surface selection in this configuration. */ SurfaceSelectionModel* SurfaceMontageConfigurationFlatMaps::getCerebellumSurfaceSelectionModel() { return m_cerebellumSurfaceSelectionModel; } /** * @return the cerebellum surface selection in this configuration. */ const SurfaceSelectionModel* SurfaceMontageConfigurationFlatMaps::getCerebellumSurfaceSelectionModel() const { return m_cerebellumSurfaceSelectionModel; } /** * Update the montage viewports using the current selected surfaces and settings. * * @param surfaceMontageViewports * Will be loaded with the montage viewports. */ void SurfaceMontageConfigurationFlatMaps::updateSurfaceMontageViewports(std::vector& surfaceMontageViewports) { surfaceMontageViewports.clear(); if (m_leftEnabled) { Surface* leftSurface = m_leftSurfaceSelectionModel->getSurface(); if (leftSurface != NULL) { SurfaceMontageViewport smv(leftSurface, ProjectionViewTypeEnum::PROJECTION_VIEW_LEFT_FLAT_SURFACE); surfaceMontageViewports.push_back(smv); } } if (m_rightEnabled) { Surface* rightSurface = m_rightSurfaceSelectionModel->getSurface(); if (rightSurface != NULL) { SurfaceMontageViewport smv(rightSurface, ProjectionViewTypeEnum::PROJECTION_VIEW_RIGHT_FLAT_SURFACE); surfaceMontageViewports.push_back(smv); } } if (m_cerebellumEnabled) { Surface* cerebellumSurface = m_cerebellumSurfaceSelectionModel->getSurface(); if (cerebellumSurface != NULL) { SurfaceMontageViewport smv(cerebellumSurface, ProjectionViewTypeEnum::PROJECTION_VIEW_CEREBELLUM_FLAT_SURFACE); surfaceMontageViewports.push_back(smv); } } const int32_t numSurfaces = static_cast(surfaceMontageViewports.size()); for (int32_t i = 0; i < numSurfaces; i++) { switch (getLayoutOrientation()) { case SurfaceMontageLayoutOrientationEnum::COLUMN_LAYOUT_ORIENTATION: surfaceMontageViewports[i].setRowAndColumn(i, 0); break; case SurfaceMontageLayoutOrientationEnum::LANDSCAPE_LAYOUT_ORIENTATION: surfaceMontageViewports[i].setRowAndColumn(0, i); break; case SurfaceMontageLayoutOrientationEnum::PORTRAIT_LAYOUT_ORIENTATION: surfaceMontageViewports[i].setRowAndColumn(i, 0); break; case SurfaceMontageLayoutOrientationEnum::ROW_LAYOUT_ORIENTATION: surfaceMontageViewports[i].setRowAndColumn(0, i); break; } } } /** * Save members to the given scene class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * @param sceneClass * sceneClass to which information is added. */ void SurfaceMontageConfigurationFlatMaps::saveMembersToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which information is restored. */ void SurfaceMontageConfigurationFlatMaps::restoreMembersFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } /** * Get a description of this object's content. * @return String describing this object's content. */ AString SurfaceMontageConfigurationFlatMaps::toString() const { PlainTextStringBuilder tb; getDescriptionOfContent(tb); return tb.getText(); } /** * Get a text description of the instance's content. * * @param descriptionOut * Description of the instance's content. */ void SurfaceMontageConfigurationFlatMaps::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const { descriptionOut.addLine("Flat Montage: "); if (isLeftEnabled()) { const Surface* firstLeftSurface = getLeftSurfaceSelectionModel()->getSurface(); if (firstLeftSurface != NULL) { descriptionOut.addLine("Left Surface:"); descriptionOut.pushIndentation(); firstLeftSurface->getDescriptionOfContent(descriptionOut); descriptionOut.popIndentation(); } } if (isRightEnabled()) { const Surface* firstRightSurface = getRightSurfaceSelectionModel()->getSurface(); if (firstRightSurface != NULL) { descriptionOut.addLine("Right Surface:"); descriptionOut.pushIndentation(); firstRightSurface->getDescriptionOfContent(descriptionOut); descriptionOut.popIndentation(); } } if (isCerebellumEnabled()) { const Surface* cerebellumSurface = getCerebellumSurfaceSelectionModel()->getSurface(); if (cerebellumSurface != NULL) { descriptionOut.addLine("Cerebellum Surface:"); descriptionOut.pushIndentation(); cerebellumSurface->getDescriptionOfContent(descriptionOut); descriptionOut.popIndentation(); } } } /** * Get all surfaces displayed in this configuration. * * @param surfaceOut * Will contain all displayed surfaces upon exit. */ void SurfaceMontageConfigurationFlatMaps::getDisplayedSurfaces(std::vector& surfacesOut) const { surfacesOut.clear(); if (isLeftEnabled()) { const Surface* firstLeftSurface = getLeftSurfaceSelectionModel()->getSurface(); if (firstLeftSurface != NULL) { surfacesOut.push_back(const_cast(firstLeftSurface)); } } if (isRightEnabled()) { const Surface* firstRightSurface = getRightSurfaceSelectionModel()->getSurface(); if (firstRightSurface != NULL) { surfacesOut.push_back(const_cast(firstRightSurface)); } } if (isCerebellumEnabled()) { const Surface* cerebellumSurface = getCerebellumSurfaceSelectionModel()->getSurface(); if (cerebellumSurface != NULL) { surfacesOut.push_back(const_cast(cerebellumSurface)); } } } /** * Copy the given configuration to this configurtion. * * @param configuration. * Configuration that is copied. */ void SurfaceMontageConfigurationFlatMaps::copyConfiguration(SurfaceMontageConfigurationAbstract* configuration) { SurfaceMontageConfigurationAbstract::copyConfiguration(configuration); SurfaceMontageConfigurationFlatMaps* flatConfiguration = dynamic_cast(configuration); CaretAssert(flatConfiguration); m_leftSurfaceSelectionModel->setSurface(flatConfiguration->m_leftSurfaceSelectionModel->getSurface()); m_rightSurfaceSelectionModel->setSurface(flatConfiguration->m_rightSurfaceSelectionModel->getSurface()); m_cerebellumSurfaceSelectionModel->setSurface(flatConfiguration->m_cerebellumSurfaceSelectionModel->getSurface()); m_leftEnabled = flatConfiguration->m_leftEnabled; m_rightEnabled = flatConfiguration->m_rightEnabled; m_cerebellumEnabled = flatConfiguration->m_cerebellumEnabled; } connectome-workbench-1.4.2/src/Brain/SurfaceMontageConfigurationFlatMaps.h000066400000000000000000000077211360521144700267200ustar00rootroot00000000000000#ifndef __SURFACE_MONTAGE_CONFIGURATION_FLAT_MAPS_H__ #define __SURFACE_MONTAGE_CONFIGURATION_FLAT_MAPS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SurfaceMontageConfigurationAbstract.h" namespace caret { class SceneClassAssistant; class SurfaceSelectionModel; class SurfaceMontageConfigurationFlatMaps : public SurfaceMontageConfigurationAbstract { public: SurfaceMontageConfigurationFlatMaps(const int32_t tabIndex); virtual ~SurfaceMontageConfigurationFlatMaps(); virtual void initializeSelectedSurfaces(); virtual bool isValid(); SurfaceSelectionModel* getLeftSurfaceSelectionModel(); const SurfaceSelectionModel* getLeftSurfaceSelectionModel() const; SurfaceSelectionModel* getRightSurfaceSelectionModel(); const SurfaceSelectionModel* getRightSurfaceSelectionModel() const; SurfaceSelectionModel* getCerebellumSurfaceSelectionModel(); const SurfaceSelectionModel* getCerebellumSurfaceSelectionModel() const; bool isLeftEnabled() const; void setLeftEnabled(const bool enabled); bool isRightEnabled() const; void setRightEnabled(const bool enabled); bool isCerebellumEnabled() const; void setCerebellumEnabled(const bool enabled); virtual void updateSurfaceMontageViewports(std::vector& surfaceMontageViewports); virtual void copyConfiguration(SurfaceMontageConfigurationAbstract* configuration); private: SurfaceMontageConfigurationFlatMaps(const SurfaceMontageConfigurationFlatMaps&); SurfaceMontageConfigurationFlatMaps& operator=(const SurfaceMontageConfigurationFlatMaps&); public: virtual AString toString() const; virtual void getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const; virtual void getDisplayedSurfaces(std::vector& surfacesOut) const; // ADD_NEW_METHODS_HERE protected: virtual void saveMembersToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreMembersFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: SceneClassAssistant* m_sceneAssistant; SurfaceSelectionModel* m_leftSurfaceSelectionModel; SurfaceSelectionModel* m_rightSurfaceSelectionModel; SurfaceSelectionModel* m_cerebellumSurfaceSelectionModel; bool m_leftEnabled; bool m_rightEnabled; bool m_cerebellumEnabled; // ADD_NEW_MEMBERS_HERE friend class ModelSurfaceMontage; }; #ifdef __SURFACE_MONTAGE_CONFIGURATION_FLAT_MAPS_DECLARE__ // #endif // __SURFACE_MONTAGE_CONFIGURATION_FLAT_MAPS_DECLARE__ } // namespace #endif //__SURFACE_MONTAGE_CONFIGURATION_FLAT_MAPS_H__ connectome-workbench-1.4.2/src/Brain/SurfaceMontageConfigurationTypeEnum.cxx000066400000000000000000000272031360521144700273270ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __SURFACE_MONTAGE_CONFIGURATION_TYPE_ENUM_DECLARE__ #include "SurfaceMontageConfigurationTypeEnum.h" #undef __SURFACE_MONTAGE_CONFIGURATION_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::SurfaceMontageConfigurationTypeEnum * \brief * * * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_surfaceMontageConfigurationTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void surfaceMontageConfigurationTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "SurfaceMontageConfigurationTypeEnum.h" * * Instatiate: * m_surfaceMontageConfigurationTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_surfaceMontageConfigurationTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_surfaceMontageConfigurationTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(surfaceMontageConfigurationTypeEnumComboBoxItemActivated())); * * Update the selection: * m_surfaceMontageConfigurationTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const SurfaceMontageConfigurationTypeEnum::Enum VARIABLE = m_surfaceMontageConfigurationTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ SurfaceMontageConfigurationTypeEnum::SurfaceMontageConfigurationTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ SurfaceMontageConfigurationTypeEnum::~SurfaceMontageConfigurationTypeEnum() { } /** * Initialize the enumerated metadata. */ void SurfaceMontageConfigurationTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(SurfaceMontageConfigurationTypeEnum(CEREBELLAR_CORTEX_CONFIGURATION, "CEREBELLAR_CORTEX_CONFIGURATION", "Cerebellar Cortex")); enumData.push_back(SurfaceMontageConfigurationTypeEnum(CEREBRAL_CORTEX_CONFIGURATION, "CEREBRAL_CORTEX_CONFIGURATION", "Cerebral Cortex")); enumData.push_back(SurfaceMontageConfigurationTypeEnum(FLAT_CONFIGURATION, "FLAT_CONFIGURATION", "Flat Maps")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const SurfaceMontageConfigurationTypeEnum* SurfaceMontageConfigurationTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const SurfaceMontageConfigurationTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString SurfaceMontageConfigurationTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const SurfaceMontageConfigurationTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ SurfaceMontageConfigurationTypeEnum::Enum SurfaceMontageConfigurationTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = SurfaceMontageConfigurationTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SurfaceMontageConfigurationTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type SurfaceMontageConfigurationTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString SurfaceMontageConfigurationTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const SurfaceMontageConfigurationTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ SurfaceMontageConfigurationTypeEnum::Enum SurfaceMontageConfigurationTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = SurfaceMontageConfigurationTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SurfaceMontageConfigurationTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type SurfaceMontageConfigurationTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t SurfaceMontageConfigurationTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const SurfaceMontageConfigurationTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ SurfaceMontageConfigurationTypeEnum::Enum SurfaceMontageConfigurationTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = SurfaceMontageConfigurationTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SurfaceMontageConfigurationTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type SurfaceMontageConfigurationTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void SurfaceMontageConfigurationTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void SurfaceMontageConfigurationTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(SurfaceMontageConfigurationTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void SurfaceMontageConfigurationTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(SurfaceMontageConfigurationTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Brain/SurfaceMontageConfigurationTypeEnum.h000066400000000000000000000065311360521144700267550ustar00rootroot00000000000000#ifndef __SURFACE_MONTAGE_CONFIGURATION_TYPE_ENUM_H__ #define __SURFACE_MONTAGE_CONFIGURATION_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class SurfaceMontageConfigurationTypeEnum { public: /** * Enumerated values. */ enum Enum { /** */ CEREBELLAR_CORTEX_CONFIGURATION, /** */ CEREBRAL_CORTEX_CONFIGURATION, /** */ FLAT_CONFIGURATION }; ~SurfaceMontageConfigurationTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: SurfaceMontageConfigurationTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const SurfaceMontageConfigurationTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __SURFACE_MONTAGE_CONFIGURATION_TYPE_ENUM_DECLARE__ std::vector SurfaceMontageConfigurationTypeEnum::enumData; bool SurfaceMontageConfigurationTypeEnum::initializedFlag = false; int32_t SurfaceMontageConfigurationTypeEnum::integerCodeCounter = 0; #endif // __SURFACE_MONTAGE_CONFIGURATION_TYPE_ENUM_DECLARE__ } // namespace #endif //__SURFACE_MONTAGE_CONFIGURATION_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Brain/SurfaceMontageLayoutOrientationEnum.cxx000066400000000000000000000275531360521144700273570ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __SURFACE_MONTAGE_LAYOUT_ORIENTATION_ENUM_DECLARE__ #include "SurfaceMontageLayoutOrientationEnum.h" #undef __SURFACE_MONTAGE_LAYOUT_ORIENTATION_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::SurfaceMontageLayoutOrientationEnum * \brief Layout orientations for surface montage views * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_surfaceMontageLayoutOrientationEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void surfaceMontageLayoutOrientationEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "SurfaceMontageLayoutOrientationEnum.h" * * Instatiate: * m_surfaceMontageLayoutOrientationEnumComboBox = new EnumComboBoxTemplate(this); * m_surfaceMontageLayoutOrientationEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_surfaceMontageLayoutOrientationEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(surfaceMontageLayoutOrientationEnumComboBoxItemActivated())); * * Update the selection: * m_surfaceMontageLayoutOrientationEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const SurfaceMontageLayoutOrientationEnum::Enum VARIABLE = m_surfaceMontageLayoutOrientationEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ SurfaceMontageLayoutOrientationEnum::SurfaceMontageLayoutOrientationEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ SurfaceMontageLayoutOrientationEnum::~SurfaceMontageLayoutOrientationEnum() { } /** * Initialize the enumerated metadata. */ void SurfaceMontageLayoutOrientationEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(SurfaceMontageLayoutOrientationEnum(COLUMN_LAYOUT_ORIENTATION, "COLUMN_LAYOUT_ORIENTATION", "Column")); enumData.push_back(SurfaceMontageLayoutOrientationEnum(LANDSCAPE_LAYOUT_ORIENTATION, "LANDSCAPE_LAYOUT_ORIENTATION", "Landscape")); enumData.push_back(SurfaceMontageLayoutOrientationEnum(PORTRAIT_LAYOUT_ORIENTATION, "PORTRAIT_LAYOUT_ORIENTATION", "Portrait")); enumData.push_back(SurfaceMontageLayoutOrientationEnum(ROW_LAYOUT_ORIENTATION, "ROW_LAYOUT_ORIENTATION", "Row")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const SurfaceMontageLayoutOrientationEnum* SurfaceMontageLayoutOrientationEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const SurfaceMontageLayoutOrientationEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString SurfaceMontageLayoutOrientationEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const SurfaceMontageLayoutOrientationEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ SurfaceMontageLayoutOrientationEnum::Enum SurfaceMontageLayoutOrientationEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = LANDSCAPE_LAYOUT_ORIENTATION; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SurfaceMontageLayoutOrientationEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type SurfaceMontageLayoutOrientationEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString SurfaceMontageLayoutOrientationEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const SurfaceMontageLayoutOrientationEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ SurfaceMontageLayoutOrientationEnum::Enum SurfaceMontageLayoutOrientationEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = LANDSCAPE_LAYOUT_ORIENTATION; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SurfaceMontageLayoutOrientationEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type SurfaceMontageLayoutOrientationEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t SurfaceMontageLayoutOrientationEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const SurfaceMontageLayoutOrientationEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ SurfaceMontageLayoutOrientationEnum::Enum SurfaceMontageLayoutOrientationEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = LANDSCAPE_LAYOUT_ORIENTATION; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SurfaceMontageLayoutOrientationEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type SurfaceMontageLayoutOrientationEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void SurfaceMontageLayoutOrientationEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void SurfaceMontageLayoutOrientationEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(SurfaceMontageLayoutOrientationEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void SurfaceMontageLayoutOrientationEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(SurfaceMontageLayoutOrientationEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Brain/SurfaceMontageLayoutOrientationEnum.h000066400000000000000000000066501360521144700267770ustar00rootroot00000000000000#ifndef __SURFACE_MONTAGE_LAYOUT_ORIENTATION_ENUM_H__ #define __SURFACE_MONTAGE_LAYOUT_ORIENTATION_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class SurfaceMontageLayoutOrientationEnum { public: /** * Enumerated values. */ enum Enum { /** Column */ COLUMN_LAYOUT_ORIENTATION, /** Landscape */ LANDSCAPE_LAYOUT_ORIENTATION, /** Portrait */ PORTRAIT_LAYOUT_ORIENTATION, /** Row */ ROW_LAYOUT_ORIENTATION }; ~SurfaceMontageLayoutOrientationEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: SurfaceMontageLayoutOrientationEnum(const Enum enumValue, const AString& name, const AString& guiName); static const SurfaceMontageLayoutOrientationEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __SURFACE_MONTAGE_LAYOUT_ORIENTATION_ENUM_DECLARE__ std::vector SurfaceMontageLayoutOrientationEnum::enumData; bool SurfaceMontageLayoutOrientationEnum::initializedFlag = false; int32_t SurfaceMontageLayoutOrientationEnum::integerCodeCounter = 0; #endif // __SURFACE_MONTAGE_LAYOUT_ORIENTATION_ENUM_DECLARE__ } // namespace #endif //__SURFACE_MONTAGE_LAYOUT_ORIENTATION_ENUM_H__ connectome-workbench-1.4.2/src/Brain/SurfaceMontageViewport.cxx000066400000000000000000000144531360521144700246530ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SURFACE_MONTAGE_VIEWPORT_DECLARE__ #include "SurfaceMontageViewport.h" #undef __SURFACE_MONTAGE_VIEWPORT_DECLARE__ #include "CaretAssert.h" #include "Surface.h" #include "StructureEnum.h" using namespace caret; /** * \class caret::SurfaceMontageViewport * \brief Viewports in a surface montage */ /** * Constructor. * * @param surface * Surface in the montage. * @param projectionViewType * Projection view type. */ SurfaceMontageViewport::SurfaceMontageViewport(Surface* surface, const ProjectionViewTypeEnum::Enum projectionViewType) : CaretObject() { CaretAssert(surface); m_surface = surface; m_structure = surface->getStructure(); m_projectionViewType = projectionViewType; m_viewport[0] = -1; m_viewport[1] = -1; m_viewport[2] = -1; m_viewport[3] = -1; m_row = -1; m_column = -1; } /** * Destructor. */ SurfaceMontageViewport::~SurfaceMontageViewport() { } /** * @return true if the coordinates are inside the viewport, else false. * @param x * X-coordinate * @param y * Y-coordinate */ bool SurfaceMontageViewport::isInside(const int32_t x, const int32_t y) const { if (x < m_viewport[0]) return false; if (x > (m_viewport[0] + m_viewport[2])) return false; if (y < m_viewport[1]) return false; if (y > (m_viewport[1] + m_viewport[3])) return false; return true; } /** * Set the row and column. * * @param row * New value for row. * @param column * New value for column. */ void SurfaceMontageViewport::setRowAndColumn(const int32_t row, const int32_t column) { m_row = row; m_column = column; } /** * Get the viewport. * * @param viewportOut * Output containing viewport. */ void SurfaceMontageViewport::getViewport(int32_t viewportOut[4]) const { CaretAssert((m_viewport[0] >= 0) && (m_viewport[1] >= 0) && (m_viewport[2] > 0) && (m_viewport[3] > 1)); viewportOut[0] = m_viewport[0]; viewportOut[1] = m_viewport[1]; viewportOut[2] = m_viewport[2]; viewportOut[3] = m_viewport[3]; } /** * Set the viewport for this item. * @param viewport * Values for viewport. */ void SurfaceMontageViewport::setViewport(const int32_t viewport[4]) { m_viewport[0] = viewport[0]; m_viewport[1] = viewport[1]; m_viewport[2] = viewport[2]; m_viewport[3] = viewport[3]; } /** * @return Row of this item (0 is top) */ int32_t SurfaceMontageViewport::getRow() const { CaretAssert(m_row >= 0); return m_row; } /** * @return Column of this item (0 is left) */ int32_t SurfaceMontageViewport::getColumn() const { CaretAssert(m_column >= 0); return m_column; } /** * @return X-coordinate in viewport. */ int32_t SurfaceMontageViewport::getX() const { CaretAssert( m_viewport[0] >= 0); return m_viewport[0]; } /** * @return Y-Coordinate in viewport. */ int32_t SurfaceMontageViewport::getY() const { CaretAssert(m_viewport[1] >= 0); return m_viewport[1]; } /** * @return Width of viewport. */ int32_t SurfaceMontageViewport::getWidth() const { CaretAssert(m_viewport[2] > 0); return m_viewport[2]; } /** * @return Height of viewport. */ int32_t SurfaceMontageViewport::getHeight() const { CaretAssert(m_viewport[3] > 0); return m_viewport[3]; } /** * Find the number of rows and columns for the given montage viewports. * * @param montageViewports * The montage viewports. * @param numberOfRowsOut * Output number of rows. * @param numberOfColumnsOut * Output number of columns. */ void SurfaceMontageViewport::getNumberOfRowsAndColumns(const std::vector& montageViewports, int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) { std::vector vps(montageViewports.begin(), montageViewports.end()); getNumberOfRowsAndColumns(vps, numberOfRowsOut, numberOfColumnsOut); } /** * Find the number of rows and columns for the given montage viewports. * * @param montageViewports * The montage viewports. * @param numberOfRowsOut * Output number of rows. * @param numberOfColumnsOut * Output number of columns. */ void SurfaceMontageViewport::getNumberOfRowsAndColumns(const std::vector& montageViewports, int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) { numberOfRowsOut = 0; numberOfColumnsOut = 0; if (montageViewports.empty()) { return; } for (std::vector::const_iterator iter = montageViewports.begin(); iter != montageViewports.end(); iter++) { const SurfaceMontageViewport* svp = *iter; const int32_t row = svp->getRow(); const int32_t column = svp->getColumn(); if (row > numberOfRowsOut) { numberOfRowsOut = row; } if (column > numberOfColumnsOut) { numberOfColumnsOut = column; } } /* * Add one since row and column in viewports are indices that range 0 to 1 */ numberOfRowsOut++; numberOfColumnsOut++; } connectome-workbench-1.4.2/src/Brain/SurfaceMontageViewport.h000066400000000000000000000071461360521144700243010ustar00rootroot00000000000000#ifndef __SURFACE_MONTAGE_VIEWPORT_H__ #define __SURFACE_MONTAGE_VIEWPORT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "ProjectionViewTypeEnum.h" #include "StructureEnum.h" namespace caret { class Surface; class SurfaceMontageViewport : public CaretObject { public: // SurfaceMontageViewport(); SurfaceMontageViewport(Surface* surface, const ProjectionViewTypeEnum::Enum projectionViewType); virtual ~SurfaceMontageViewport(); /** * @return The surface in the viewport. */ Surface* getSurface() const { return m_surface; } ProjectionViewTypeEnum::Enum getProjectionViewType() const { return m_projectionViewType; } bool isInside(const int32_t x, const int32_t y) const; /** * @return Row of this item (0 is top) */ int32_t getRow() const; /** * @return Column of this item (0 is left) */ int32_t getColumn() const; void setRowAndColumn(const int32_t row, const int32_t column); /** * @return X-coordinate in viewport. */ int32_t getX() const; /** * @return Y-Coordinate in viewport. */ int32_t getY() const; /** * @return Width of viewport. */ int32_t getWidth() const; /** * @return Height of viewport. */ int32_t getHeight() const; void getViewport(int32_t viewportOut[4]) const; void setViewport(const int32_t viewport[4]); static void getNumberOfRowsAndColumns(const std::vector& montageViewports, int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut); static void getNumberOfRowsAndColumns(const std::vector& montageViewports, int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut); private: int32_t m_row; int32_t m_column; int32_t m_viewport[4]; Surface* m_surface; ProjectionViewTypeEnum::Enum m_projectionViewType; StructureEnum::Enum m_structure; // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE }; #ifdef __SURFACE_MONTAGE_VIEWPORT_DECLARE__ // #endif // __SURFACE_MONTAGE_VIEWPORT_DECLARE__ } // namespace #endif //__SURFACE_MONTAGE_VIEWPORT_H__ connectome-workbench-1.4.2/src/Brain/SurfaceNodeColoring.cxx000066400000000000000000001750121360521144700241020ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SURFACE_NODE_COLORING_DECLARE__ #include "SurfaceNodeColoring.h" #undef __SURFACE_NODE_COLORING_DECLARE__ #include "Brain.h" #include "BrainordinateRegionOfInterest.h" #include "BrainStructure.h" #include "BrowserTabContent.h" #include "EventBrowserTabGet.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPreferences.h" #include "CiftiBrainordinateDataSeriesFile.h" #include "CiftiBrainordinateLabelFile.h" #include "CiftiBrainordinateScalarFile.h" #include "CiftiConnectivityMatrixParcelFile.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "CiftiParcelLabelFile.h" #include "CiftiParcelScalarFile.h" #include "CiftiParcelSeriesFile.h" #include "DisplayPropertiesSurface.h" #include "GroupAndNameHierarchyModel.h" #include "DisplayPropertiesLabels.h" #include "EventManager.h" #include "EventModelSurfaceGet.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "GroupAndNameHierarchyGroup.h" #include "LabelFile.h" #include "LabelDrawingProperties.h" #include "MetricFile.h" #include "ModelSurface.h" #include "ModelSurfaceMontage.h" #include "ModelVolume.h" #include "ModelWholeBrain.h" #include "NodeAndVoxelColoring.h" #include "Overlay.h" #include "OverlaySet.h" #include "Palette.h" #include "PaletteColorMapping.h" #include "PaletteScalarAndColor.h" #include "RgbaFile.h" #include "SessionManager.h" #include "Surface.h" #include "TopologyHelper.h" using namespace caret; /** * Constructor. */ SurfaceNodeColoring::SurfaceNodeColoring() : CaretObject() { } /** * Destructor. */ SurfaceNodeColoring::~SurfaceNodeColoring() { } /** * Get a description of this object's content. * @return String describing this object's content. */ AString SurfaceNodeColoring::toString() const { return "SurfaceNodeColoring"; } /** * Assign color components to surface nodes. * If colors are currently valid, no changes are made to the surface coloring. * @param model * Model that is displayed. If NULL use find ModelSurface * for the surface. This case occurs when needing surface coloring * when surface outline is drawn on volume slices. * @param surface * Surface that is displayed. * @param browserTabIndex * Index of tab in which model is displayed. */ float* SurfaceNodeColoring::colorSurfaceNodes(Model* model, Surface* surface, const int32_t browserTabIndex) { CaretAssert(surface); ModelSurface* surfaceModel = dynamic_cast(model); ModelSurfaceMontage* surfaceMontageModel = dynamic_cast(model); ModelWholeBrain* wholeBrainModel = dynamic_cast(model); OverlaySet* overlaySet = NULL; float* rgba = NULL; EventBrowserTabGet getBrowserTab(browserTabIndex); EventManager::get()->sendEvent(getBrowserTab.getPointer()); BrowserTabContent* browserTabContent = getBrowserTab.getBrowserTab(); Brain* brain = NULL; if (model != NULL) { brain = model->getBrain(); } /* * For a NULL model, find and use the surface model for the * surface and in the same tab as the volume model. This typically * occurs when the volume surface outline is drawn over a volume slice. */ if (model == NULL) { EventModelSurfaceGet surfaceGet(surface); EventManager::get()->sendEvent(surfaceGet.getPointer()); surfaceModel = surfaceGet.getModelSurface(); CaretAssert(surfaceModel); if (surfaceModel != NULL) { brain = surfaceModel->getBrain(); } /* * If whole brain is displayed in the tab, use coloring * from whole brain instead of surface. */ if (browserTabContent != NULL) { ModelWholeBrain* wholeBrain = browserTabContent->getDisplayedWholeBrainModel(); if (wholeBrain != NULL) { wholeBrainModel = wholeBrain; brain = wholeBrainModel->getBrain(); surfaceModel = NULL; } ModelSurfaceMontage* surfMont = browserTabContent->getDisplayedSurfaceMontageModel(); if (surfMont != NULL) { surfaceMontageModel = surfMont; brain = surfaceMontageModel->getBrain(); surfaceModel = NULL; } } } /* * Get coloring and overlays for the valid model. */ if (surfaceModel != NULL) { rgba = surface->getSurfaceNodeColoringRgbaForBrowserTab(browserTabIndex); overlaySet = surfaceModel->getOverlaySet(browserTabIndex); } else if (surfaceMontageModel != NULL) { rgba = surface->getSurfaceMontageNodeColoringRgbaForBrowserTab(browserTabIndex); overlaySet = surfaceMontageModel->getOverlaySet(browserTabIndex); } else if (wholeBrainModel != NULL) { rgba = surface->getWholeBrainNodeColoringRgbaForBrowserTab(browserTabIndex); overlaySet = wholeBrainModel->getOverlaySet(browserTabIndex); } CaretAssert(overlaySet); /* * RGBA will be Non-NULL if the surface HAS valid coloring */ if (rgba != NULL) { return rgba; } /* * Drawing type for labels */ DisplayPropertiesLabels* displayPropertiesLabels = NULL; if (brain != NULL) { displayPropertiesLabels = brain->getDisplayPropertiesLabels(); } const int numNodes = surface->getNumberOfNodes(); const int numColorComponents = numNodes * 4; float *rgbaColor = new float[numColorComponents]; /* * Color the surface nodes */ this->colorSurfaceNodes(displayPropertiesLabels, browserTabIndex, surface, overlaySet, rgbaColor); if (surfaceModel != NULL) { surface->setSurfaceNodeColoringRgbaForBrowserTab(browserTabIndex, rgbaColor); rgba = surface->getSurfaceNodeColoringRgbaForBrowserTab(browserTabIndex); } else if (surfaceMontageModel != NULL) { surface->setSurfaceMontageNodeColoringRgbaForBrowserTab(browserTabIndex, rgbaColor); rgba = surface->getSurfaceMontageNodeColoringRgbaForBrowserTab(browserTabIndex); } else if (wholeBrainModel != NULL) { surface->setWholeBrainNodeColoringRgbaForBrowserTab(browserTabIndex, rgbaColor); rgba = surface->getWholeBrainNodeColoringRgbaForBrowserTab(browserTabIndex); } if(rgbaColor) delete [] rgbaColor; return rgba; } /** * Show brainordinate region of interest highlighting on the surface. * * @param brain * The brain. * @param surface * Surface on which highlighting is displayed. * @param rgbaNodeColors * Node coloring that is updated with highlighting. */ void SurfaceNodeColoring::showBrainordinateHighlightRegionOfInterest(const Brain* brain, const Surface* surface, float* rgbaNodeColors) { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); uint8_t foregroundColorByte[4]; prefs->getBackgroundAndForegroundColors()->getColorForegroundSurfaceView(foregroundColorByte); const float foregroundColor[4] = { static_cast(foregroundColorByte[0]) / 255.0f, static_cast(foregroundColorByte[1]) / 255.0f, static_cast(foregroundColorByte[2]) / 255.0f, 1.0f }; const BrainordinateRegionOfInterest* roi = brain->getBrainordinateHighlightRegionOfInterest(); CaretAssert(roi); if (roi->isBrainordinateHighlightingEnabled()) { const StructureEnum::Enum structure = surface->getStructure(); const int64_t surfaceNumberOfNodes = surface->getNumberOfNodes(); if (roi->hasNodesForSurfaceStructure(structure, surfaceNumberOfNodes)) { const std::vector& nodeIndices = roi->getNodesForSurfaceStructure(structure, surfaceNumberOfNodes); for (std::vector::const_iterator nodeIter = nodeIndices.begin(); nodeIter != nodeIndices.end(); nodeIter++) { const int64_t nodeIndex = *nodeIter; const int64_t rgbaIndex = nodeIndex * 4; CaretAssertArrayIndex(rgbaNodeColors, surfaceNumberOfNodes*4 , rgbaIndex + 3); rgbaNodeColors[rgbaIndex] = foregroundColor[0]; rgbaNodeColors[rgbaIndex+1] = foregroundColor[1]; rgbaNodeColors[rgbaIndex+2] = foregroundColor[2]; rgbaNodeColors[rgbaIndex+3] = foregroundColor[3]; } } } } /** * Assign color components to surface nodes. * * @param surface * Surface that has its nodes colored. * @param overlaySet * Surface overlay assignments for surface. * @param rgbaNodeColors * RGBA color components that are set by this method. */ void SurfaceNodeColoring::colorSurfaceNodes(const DisplayPropertiesLabels* displayPropertiesLabels, const int32_t browserTabIndex, const Surface* surface, OverlaySet* overlaySet, float* rgbaNodeColors) { const int32_t numNodes = surface->getNumberOfNodes(); const int32_t numberOfDisplayedOverlays = overlaySet->getNumberOfDisplayedOverlays(); /* * Default color. */ for (int32_t i = 0; i < numNodes; i++) { const int32_t i4 = i * 4; rgbaNodeColors[i4] = 0.70; rgbaNodeColors[i4+1] = 0.70; rgbaNodeColors[i4+2] = 0.70; rgbaNodeColors[i4+3] = 1.0; } const BrainStructure* brainStructure = surface->getBrainStructure(); CaretAssert(brainStructure); const Brain* brain = brainStructure->getBrain(); CaretAssert(brain); bool firstOverlayFlag = true; float* overlayRGBV = new float[numNodes * 4]; for (int32_t iOver = (numberOfDisplayedOverlays - 1); iOver >= 0; iOver--) { Overlay* overlay = overlaySet->getOverlay(iOver); if (overlay->isEnabled()) { std::vector mapFiles; CaretMappableDataFile* selectedMapFile; int32_t selectedMapIndex; overlay->getSelectionData(mapFiles, selectedMapFile, selectedMapIndex); DataFileTypeEnum::Enum mapDataFileType = DataFileTypeEnum::UNKNOWN; if (selectedMapFile != NULL) { mapDataFileType = selectedMapFile->getDataFileType(); } bool isColoringValid = false; switch (mapDataFileType) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: { CiftiMappableConnectivityMatrixDataFile* cmf = dynamic_cast(selectedMapFile); isColoringValid = assignCiftiMappableConnectivityMatrixColoring(brainStructure, cmf, selectedMapIndex, numNodes, overlayRGBV); } break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: { CiftiMappableConnectivityMatrixDataFile* cmf = dynamic_cast(selectedMapFile); isColoringValid = assignCiftiMappableConnectivityMatrixColoring(brainStructure, cmf, selectedMapIndex, numNodes, overlayRGBV); } break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: isColoringValid = this->assignCiftiDenseLabelColoring(displayPropertiesLabels, browserTabIndex, brainStructure, surface, dynamic_cast(selectedMapFile), selectedMapIndex, numNodes, overlayRGBV); break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: { CiftiMappableConnectivityMatrixDataFile* cmf = dynamic_cast(selectedMapFile); isColoringValid = assignCiftiMappableConnectivityMatrixColoring(brainStructure, cmf, selectedMapIndex, numNodes, overlayRGBV); } break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: isColoringValid = this->assignCiftiScalarColoring(brainStructure, dynamic_cast(selectedMapFile), selectedMapIndex, numNodes, overlayRGBV); break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: isColoringValid = this->assignCiftiDataSeriesColoring(brainStructure, dynamic_cast(selectedMapFile), selectedMapIndex, numNodes, overlayRGBV); break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: { CiftiMappableConnectivityMatrixDataFile* cmf = dynamic_cast(selectedMapFile); isColoringValid = assignCiftiMappableConnectivityMatrixColoring(brainStructure, cmf, selectedMapIndex, numNodes, overlayRGBV); } break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: { CiftiMappableConnectivityMatrixDataFile* cmf = dynamic_cast(selectedMapFile); isColoringValid = assignCiftiMappableConnectivityMatrixColoring(brainStructure, cmf, selectedMapIndex, numNodes, overlayRGBV); } break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: { CiftiParcelLabelFile* cplf = dynamic_cast(selectedMapFile); isColoringValid = assignCiftiParcelLabelColoring(displayPropertiesLabels, browserTabIndex, brainStructure, surface, cplf, selectedMapIndex, numNodes, overlayRGBV); } break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: isColoringValid = this->assignCiftiParcelScalarColoring(brainStructure, dynamic_cast(selectedMapFile), selectedMapIndex, numNodes, overlayRGBV); break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: isColoringValid = this->assignCiftiParcelSeriesColoring(brainStructure, dynamic_cast(selectedMapFile), selectedMapIndex, numNodes, overlayRGBV); break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: isColoringValid = this->assignLabelColoring(displayPropertiesLabels, browserTabIndex, brainStructure, surface, dynamic_cast(selectedMapFile), selectedMapIndex, numNodes, overlayRGBV); break; case DataFileTypeEnum::METRIC: case DataFileTypeEnum::METRIC_DYNAMIC: // same as metric isColoringValid = this->assignMetricColoring(brainStructure, dynamic_cast(selectedMapFile), selectedMapIndex, numNodes, overlayRGBV); break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: isColoringValid = this->assignRgbaColoring(brainStructure, dynamic_cast(selectedMapFile), selectedMapIndex, numNodes, overlayRGBV); break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: break; case DataFileTypeEnum::UNKNOWN: break; } if (isColoringValid) { if (selectedMapFile->isMappedWithPalette()) { const PaletteColorMapping* pcm = selectedMapFile->getMapPaletteColorMapping(selectedMapIndex); CaretAssert(pcm); bool hideDataFlag = false; bool showOutlineFlag = false; const PaletteThresholdOutlineDrawingModeEnum::Enum outlineMode = pcm->getThresholdOutlineDrawingMode(); switch (outlineMode) { case PaletteThresholdOutlineDrawingModeEnum::OFF: break; case PaletteThresholdOutlineDrawingModeEnum::OUTLINE: hideDataFlag = true; showOutlineFlag = true; break; case PaletteThresholdOutlineDrawingModeEnum::OUTLINE_AND_DATA: showOutlineFlag = true; break; } if (showOutlineFlag) { const CaretColorEnum::Enum outlineColor = pcm->getThresholdOutlineDrawingColor(); float outlineRGBA[4]; CaretColorEnum::toRGBAFloat(outlineColor, outlineRGBA); CaretPointer topologyHelper = surface->getTopologyHelper(); std::vector rgbaCopy(numNodes * 4); for (int32_t i = 0; i < (numNodes*4); i++) { rgbaCopy[i] = overlayRGBV[i]; } for (int32_t i = 0; i < numNodes; i++) { const int32_t i4 = i * 4; CaretAssertVectorIndex(rgbaCopy, i4 + 3); const float alpha = rgbaCopy[i4 + 3]; if (alpha > 0.0 ) { /* * If a node is the same color as all of its neighbors, * use the fill color. Otherwise, use the outline color. */ bool isLabelBoundaryNode = false; int32_t numNeighbors = 0; const int32_t* allNeighbors = topologyHelper->getNodeNeighbors(i, numNeighbors); for (int32_t n = 0; n < numNeighbors; n++) { const int32_t neighborNodeIndex = allNeighbors[n]; const int32_t n4 = neighborNodeIndex * 4; CaretAssertVectorIndex(rgbaCopy, n4 + 3); const float neighborAlpha = rgbaCopy[n4 + 3]; if (neighborAlpha <= 0.0) { isLabelBoundaryNode = true; break; } } CaretAssertArrayIndex(overlayRGBV, numNodes * 4, i4 + 3); if (isLabelBoundaryNode) { overlayRGBV[i4] = outlineRGBA[0]; overlayRGBV[i4+1] = outlineRGBA[1]; overlayRGBV[i4+2] = outlineRGBA[2]; overlayRGBV[i4+3] = 1.0; } else if (hideDataFlag) { overlayRGBV[i4+3] = 0.0; } } } } } } if (isColoringValid) { const float opacity = overlay->getOpacity(); const float oneMinusOpacity = 1.0 - opacity; for (int32_t i = 0; i < numNodes; i++) { const int32_t i4 = i * 4; const float valid = overlayRGBV[i4 + 3]; if (valid > 0.0 ) { if (opacity < 1.0) { if (firstOverlayFlag) { /* * When first overlay, there is nothing to * blend with */ rgbaNodeColors[i4] = (overlayRGBV[i4] * opacity); rgbaNodeColors[i4+1] = (overlayRGBV[i4+1] * opacity); rgbaNodeColors[i4+2] = (overlayRGBV[i4+2] * opacity); } else { /* * Blend with underlaying colors */ rgbaNodeColors[i4] = (overlayRGBV[i4] * opacity) + (rgbaNodeColors[i4] * oneMinusOpacity); rgbaNodeColors[i4+1] = (overlayRGBV[i4+1] * opacity) + (rgbaNodeColors[i4+1] * oneMinusOpacity); rgbaNodeColors[i4+2] = (overlayRGBV[i4+2] * opacity) + (rgbaNodeColors[i4+2] * oneMinusOpacity); } } else { /* * No opacity so simple replace coloring */ rgbaNodeColors[i4] = overlayRGBV[i4]; rgbaNodeColors[i4+1] = overlayRGBV[i4+1]; rgbaNodeColors[i4+2] = overlayRGBV[i4+2]; } } } firstOverlayFlag = false; } } } /* * Opacity from first overlay is used as overall surface opacity * so replace alpha with opacity */ const float opacity = brain->getDisplayPropertiesSurface()->getOpacity(); if (opacity < 1.0) { for (int32_t i = 0; i < numNodes; i++) { const int32_t i4 = i * 4; rgbaNodeColors[i4+3] = opacity; } } showBrainordinateHighlightRegionOfInterest(brain, surface, rgbaNodeColors); delete[] overlayRGBV; } /** * Assign label coloring to nodes * @param brainStructure * The brain structure that contains the data files. * @param labelFile * Label file that is selected. * @param labelMapUniqueID * UniqueID of selected map. * @param numberOfNodes * Number of nodes in surface. * @param rgbv * Color components set by this method. * Red, green, blue, valid. If the valid component is * zero, it indicates that the overlay did not assign * any coloring to the node. * @return * True if coloring is valid, else false. */ bool SurfaceNodeColoring::assignLabelColoring(const DisplayPropertiesLabels* displayPropertiesLabels, const int32_t browserTabIndex, const BrainStructure* /*brainStructure*/, const Surface* surface, const LabelFile* labelFile, const int32_t displayColumn, const int32_t numberOfNodes, float* rgbv) { if (labelFile == NULL) { return false; } if ( ! labelFile->isMappableToSurfaceStructure(surface->getStructure())) { return false; } const LabelDrawingProperties* props = labelFile->getLabelDrawingProperties(); LabelDrawingTypeEnum::Enum labelDrawingType = props->getDrawingType(); CaretColorEnum::Enum outlineColor = props->getOutlineColor(); const DisplayGroupEnum::Enum displayGroup = displayPropertiesLabels->getDisplayGroupForTab(browserTabIndex); const GroupAndNameHierarchyModel* classNameModel = labelFile->getGroupAndNameHierarchyModel(); if (classNameModel->isSelected(displayGroup, browserTabIndex) == false) { return false; } if (displayColumn < 0) { return false; } /* * Invalidate all coloring. */ for (int32_t i = 0; i < numberOfNodes; i++) { rgbv[i*4+3] = 0.0; } const GiftiLabelTable* labelTable = labelFile->getLabelTable(); CaretAssert(surface); CaretPointer topologyHelper = surface->getTopologyHelper(); /* * Assign colors from labels to nodes */ std::vector labelKeys; for (int32_t i = 0; i < numberOfNodes; i++) { labelKeys.push_back(labelFile->getLabelKey(i, displayColumn)); } const bool drawMedialWallFilledFlag = props->isDrawMedialWallFilled(); assignLabelTableColors(labelTable, labelDrawingType, outlineColor, topologyHelper, displayGroup, browserTabIndex, labelKeys, drawMedialWallFilledFlag, rgbv); return true; } /** * Assign label coloring to surface nodes. * * @param labelTable * The label table. * @param labelDrawingType * Label drawing type. * @param outlineColor * Outline color. * @param topologyHelper * The topology helper for node neighbors. * @param displayGroup * Selected Display Group * @param browserTabIndex * Index of browser tab. * @param labelIndices * Indices of labels for each node. * @param medialWallLabelKey * Index of the medial wall label key * @param drawMedialWallFilledFlag * True if medial wall is always filled * @param rgbv * RGB coloring. (4 per node). * */ void SurfaceNodeColoring::assignLabelTableColors(const GiftiLabelTable* labelTable, const LabelDrawingTypeEnum::Enum labelDrawingType, const CaretColorEnum::Enum outlineColor, const CaretPointer topologyHelper, const DisplayGroupEnum::Enum displayGroup, const int32_t browserTabIndex, const std::vector& labelIndices, const bool drawMedialWallFilledFlag, float* rgbv) { const int32_t numberOfIndices = static_cast(labelIndices.size()); /* * Invalidate all coloring. */ for (int32_t i = 0; i < numberOfIndices; i++) { rgbv[i*4+3] = 0.0; } float outlineRGBA[4]; CaretColorEnum::toRGBAFloat(outlineColor, outlineRGBA); outlineRGBA[3] = 1.0; /* * Assign colors from labels to nodes */ float nodeRGBA[4]; for (int32_t i = 0; i < numberOfIndices; i++) { CaretAssertVectorIndex(labelIndices, i); const int32_t labelKey= static_cast(labelIndices[i]); const GiftiLabel* label = labelTable->getLabel(labelKey); if (label == NULL) { continue; } const GroupAndNameHierarchyItem* nameItem = label->getGroupNameSelectionItem(); if (nameItem != NULL) { if (nameItem->isSelected(displayGroup, browserTabIndex) == false) { continue; } } /* * Initialize node color to its label's color */ label->getColor(nodeRGBA); if (nodeRGBA[3] <= 0.0) { continue; } /* * If a node is the same color as all of its neighbors, * use the fill color. Otherwise, use the outline color. */ bool isLabelBoundaryNode = false; int32_t numNeighbors = 0; const int32_t* allNeighbors = topologyHelper->getNodeNeighbors(i, numNeighbors); for (int32_t n = 0; n < numNeighbors; n++) { const int32_t neighborNodeIndex = allNeighbors[n]; CaretAssertVectorIndex(labelIndices, neighborNodeIndex); const int32_t neighborLabelKey = static_cast(labelIndices[neighborNodeIndex]); if (labelKey != neighborLabelKey) { isLabelBoundaryNode = true; break; } } /* * User may request that medial wall is always filled * and never receives outlining */ bool doOutlineFlag = true; if (drawMedialWallFilledFlag) { if (label->isMedialWallName()) { doOutlineFlag = false; } } if (doOutlineFlag) { switch (labelDrawingType) { case LabelDrawingTypeEnum::DRAW_FILLED: break; case LabelDrawingTypeEnum::DRAW_FILLED_WITH_OUTLINE_COLOR: if (isLabelBoundaryNode) { nodeRGBA[0] = outlineRGBA[0]; nodeRGBA[1] = outlineRGBA[1]; nodeRGBA[2] = outlineRGBA[2]; nodeRGBA[3] = outlineRGBA[3]; } break; case LabelDrawingTypeEnum::DRAW_OUTLINE_COLOR: if (isLabelBoundaryNode) { nodeRGBA[0] = outlineRGBA[0]; nodeRGBA[1] = outlineRGBA[1]; nodeRGBA[2] = outlineRGBA[2]; nodeRGBA[3] = outlineRGBA[3]; } else { nodeRGBA[3] = 0.0; } break; case LabelDrawingTypeEnum::DRAW_OUTLINE_LABEL_COLOR: if ( ! isLabelBoundaryNode) { nodeRGBA[3] = 0.0; } break; } } const int32_t i4 = i * 4; rgbv[i4] = nodeRGBA[0]; rgbv[i4+1] = nodeRGBA[1]; rgbv[i4+2] = nodeRGBA[2]; rgbv[i4+3] = nodeRGBA[3]; } } /** * Assign metric coloring to nodes * @param brainStructure * The brain structure that contains the data files. * @param metricFile * Metric file that is selected. * @param metricMapUniqueID * UniqueID of selected map. * @param numberOfNodes * Number of nodes in surface. * @param rgbv * Color components set by this method. * Red, green, blue, valid. If the valid component is * zero, it indicates that the overlay did not assign * any coloring to the node. * @return * True if coloring is valid, else false. */ bool SurfaceNodeColoring::assignMetricColoring(const BrainStructure* brainStructure, MetricFile* metricFile, const int32_t displayColumn, const int32_t numberOfNodes, float* rgbv) { if (displayColumn < 0) { return false; } if ( ! metricFile->isMappableToSurfaceStructure(brainStructure->getStructure())) { return false; } PaletteColorMapping* paletteColorMapping = metricFile->getPaletteColorMapping(displayColumn); bool useThreshMapFileFlag = false; switch (paletteColorMapping->getThresholdType()) { case PaletteThresholdTypeEnum::THRESHOLD_TYPE_FILE: useThreshMapFileFlag = true; break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED: break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED_AVERAGE_AREA: break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_NORMAL: break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF: break; } const float* metricDisplayData = metricFile->getValuePointerForColumn(displayColumn); float* metricThresholdData = const_cast(metricDisplayData); PaletteColorMapping* thresholdPaletteColorMapping = paletteColorMapping; if (useThreshMapFileFlag) { const CaretMappableDataFileAndMapSelectionModel* threshFileModel = metricFile->getMapThresholdFileSelectionModel(displayColumn); CaretAssert(threshFileModel); const CaretMappableDataFile* threshMapFile = threshFileModel->getSelectedFile(); if (threshMapFile != NULL) { const MetricFile* threshMetricFile = dynamic_cast(threshMapFile); if (threshMetricFile != NULL) { const int32_t threshMapIndex = threshFileModel->getSelectedMapIndex(); if ((threshMapIndex >= 0) && (threshMapIndex < threshMapFile->getNumberOfMaps())) { metricThresholdData = const_cast(threshMetricFile->getValuePointerForColumn(threshMapIndex)); thresholdPaletteColorMapping = const_cast(threshMapFile->getMapPaletteColorMapping(threshMapIndex)); CaretAssert(thresholdPaletteColorMapping); } } } } /* * Invalidate all coloring. */ for (int32_t i = 0; i < numberOfNodes; i++) { rgbv[i*4+3] = 0.0; } /* * Get min/max ranges. */ int thresholdColumn = metricFile->getColumnIndexFromColumnName(paletteColorMapping->getThresholdDataName()); if (thresholdColumn < 0) { thresholdColumn = displayColumn; } FastStatistics* statistics = NULL; switch (metricFile->getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: statistics = const_cast(metricFile->getFileFastStatistics()); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: statistics = const_cast(metricFile->getMapFastStatistics(displayColumn)); break; } CaretAssert(statistics); if (statistics != NULL) { NodeAndVoxelColoring::colorScalarsWithPalette(statistics, paletteColorMapping, metricDisplayData, thresholdPaletteColorMapping, metricThresholdData, numberOfNodes, rgbv); } return true; } /** * Assign cifti scalar coloring to nodes * @param brainStructure * The brain structure that contains the data files. * @param ciftiScalarFile * Cifti Scalar file that is selected. * @param ciftiMapUniqueID * UniqueID of selected map. * @param numberOfNodes * Number of nodes in surface. * @param rgbv * Color components set by this method. * Red, green, blue, valid. If the valid component is * zero, it indicates that the overlay did not assign * any coloring to the node. * @return * True if coloring is valid, else false. */ bool SurfaceNodeColoring::assignCiftiMappableConnectivityMatrixColoring(const BrainStructure* brainStructure, CiftiMappableConnectivityMatrixDataFile* ciftiConnectivityMatrixFile, const int32_t mapIndex, const int32_t numberOfNodes, float* rgbv) { CaretAssert(ciftiConnectivityMatrixFile); if (mapIndex < 0) { return false; } /* * Invalidate all coloring. */ for (int32_t i = 0; i < numberOfNodes; i++) { rgbv[i*4+3] = 0.0; } const StructureEnum::Enum structure = brainStructure->getStructure(); std::vector dataValues(numberOfNodes); ciftiConnectivityMatrixFile->getMapSurfaceNodeColoring(mapIndex, structure, rgbv, &dataValues[0], numberOfNodes); CiftiConnectivityMatrixParcelFile* parcelFile = dynamic_cast(ciftiConnectivityMatrixFile); if (parcelFile != NULL) { const Surface* surface = brainStructure->getPrimaryAnatomicalSurface(); CaretPointer topologyHelper = surface->getTopologyHelper(); std::set nodeSet; bool selectedParcelValid = false; selectedParcelValid = ciftiConnectivityMatrixFile->getParcelNodesElementForSelectedParcel(nodeSet,structure); std::vector selectedParcelNodes = std::vector(nodeSet.begin(), nodeSet.end()); if(selectedParcelValid) { const CaretColorEnum::Enum parcelColor = parcelFile->getSelectedParcelColor(); const float* rgb = CaretColorEnum::toRGB(parcelColor); CaretAssert(rgb); switch (parcelFile->getSelectedParcelColoringMode()) { case CiftiParcelColoringModeEnum::CIFTI_PARCEL_COLORING_OFF: break; case CiftiParcelColoringModeEnum::CIFTI_PARCEL_COLORING_FILL: { for(uint64_t pNode = 0; pNode < selectedParcelNodes.size(); pNode++) { int64_t nodeIndex = selectedParcelNodes[pNode]; if(nodeIndex >= 0 && nodeIndex < numberOfNodes) { uint64_t node4 = nodeIndex*4; rgbv[node4] = rgb[0]; rgbv[node4+1] = rgb[1]; rgbv[node4+2] = rgb[2]; rgbv[node4+3] = 1.0; continue; } } } break; case CiftiParcelColoringModeEnum::CIFTI_PARCEL_COLORING_OUTLINE: { /* * Check for any neighbors with different label key. */ //make a quick lookup table std::vector selectedNodesLookup(numberOfNodes,0); for(uint64_t pNode = 0;pNode < selectedParcelNodes.size();pNode++) { int64_t nodeIndex = selectedParcelNodes[pNode]; if(nodeIndex >= 0 && nodeIndex < (int64_t)selectedNodesLookup.size()) { selectedNodesLookup[nodeIndex] = 1; } } for(uint64_t pNode = 0;pNode < selectedParcelNodes.size();pNode++) { int32_t numNeighbors = 0; const int64_t nodeIndex = selectedParcelNodes[pNode]; const int32_t* allNeighbors = topologyHelper->getNodeNeighbors(nodeIndex, numNeighbors); for (int32_t n = 0; n < numNeighbors; n++) { const int32_t neighbor = allNeighbors[n]; if (!selectedNodesLookup[neighbor]) { int64_t node4 = nodeIndex*4; rgbv[node4] = rgb[0]; rgbv[node4+1] = rgb[1]; rgbv[node4+2] = rgb[2]; rgbv[node4+3] = 1.0; continue; } } } } break; } } } return true; } /** * Assign cifti dense label coloring to nodes * @param brainStructure * The brain structure that contains the data files. * @param ciftiLabelFile * Cifti Label file that is selected. * @param ciftiMapUniqueID * UniqueID of selected map. * @param numberOfNodes * Number of nodes in surface. * @param rgbv * Color components set by this method. * Red, green, blue, valid. If the valid component is * zero, it indicates that the overlay did not assign * any coloring to the node. * @return * True if coloring is valid, else false. */ bool SurfaceNodeColoring::assignCiftiDenseLabelColoring(const DisplayPropertiesLabels* displayPropertiesLabels, const int32_t browserTabIndex, const BrainStructure* brainStructure, const Surface* surface, CiftiBrainordinateLabelFile* ciftiLabelFile, const int32_t mapIndex, const int32_t numberOfNodes, float* rgbv) { CaretAssert(displayPropertiesLabels); CaretAssert(brainStructure); CaretAssert(ciftiLabelFile); CaretAssert(rgbv); Brain* brain = (Brain*)(brainStructure->getBrain()); std::vector allCiftiBrainordinateLabelFiles; brain->getConnectivityDenseLabelFiles(allCiftiBrainordinateLabelFiles); if (mapIndex < 0) { return false; } const DisplayGroupEnum::Enum displayGroup = displayPropertiesLabels->getDisplayGroupForTab(browserTabIndex); const LabelDrawingProperties* props = ciftiLabelFile->getLabelDrawingProperties(); LabelDrawingTypeEnum::Enum labelDrawingType = props->getDrawingType(); CaretColorEnum::Enum outlineColor = props->getOutlineColor(); /* * Invalidate all coloring. */ for (int32_t i = 0; i < numberOfNodes; i++) { rgbv[i*4+3] = 0.0; } /* * Update coloring */ if (ciftiLabelFile->isMapColoringValid(mapIndex) == false) { ciftiLabelFile->updateScalarColoringForMap(mapIndex); } std::vector dataValues(numberOfNodes); /* * Assigns colors for all nodes. */ const StructureEnum::Enum structure = brainStructure->getStructure(); ciftiLabelFile->getMapSurfaceNodeColoring(mapIndex, structure, rgbv, &dataValues[0], numberOfNodes); CaretAssert(surface); CaretPointer topologyHelper = surface->getTopologyHelper(); /* * All nodes are colored. Remove coloring for nodes whose * label is not selected. */ GiftiLabelTable* labelTable = ciftiLabelFile->getMapLabelTable(mapIndex); CaretAssert(labelTable); const bool drawMedialWallFilledFlag = props->isDrawMedialWallFilled(); assignLabelTableColors(labelTable, labelDrawingType, outlineColor, topologyHelper, displayGroup, browserTabIndex, dataValues, drawMedialWallFilledFlag, rgbv); return true; } /** * Assign cifti parcel label coloring to nodes * @param brainStructure * The brain structure that contains the data files. * @param ciftiParcelLabelFile * Cifti Parcel Label file that is selected. * @param mapIndex * Index of selected map. * @param numberOfNodes * Number of nodes in surface. * @param rgbv * Color components set by this method. * Red, green, blue, valid. If the valid component is * zero, it indicates that the overlay did not assign * any coloring to the node. * @return * True if coloring is valid, else false. */ bool SurfaceNodeColoring::assignCiftiParcelLabelColoring(const DisplayPropertiesLabels* displayPropertiesLabels, const int32_t browserTabIndex, const BrainStructure* brainStructure, const Surface* surface, CiftiParcelLabelFile* ciftiParcelLabelFile, const int32_t mapIndex, const int32_t numberOfNodes, float* rgbv) { CaretAssert(displayPropertiesLabels); CaretAssert(brainStructure); CaretAssert(ciftiParcelLabelFile); CaretAssert(rgbv); Brain* brain = (Brain*)(brainStructure->getBrain()); std::vector allCiftiBrainordinateLabelFiles; brain->getConnectivityDenseLabelFiles(allCiftiBrainordinateLabelFiles); if (mapIndex < 0) { return false; } const DisplayGroupEnum::Enum displayGroup = displayPropertiesLabels->getDisplayGroupForTab(browserTabIndex); const LabelDrawingProperties* props = ciftiParcelLabelFile->getLabelDrawingProperties(); LabelDrawingTypeEnum::Enum labelDrawingType = props->getDrawingType(); CaretColorEnum::Enum outlineColor = props->getOutlineColor(); /* * Invalidate all coloring. */ for (int32_t i = 0; i < numberOfNodes; i++) { rgbv[i*4+3] = 0.0; } /* * Update coloring */ if (ciftiParcelLabelFile->isMapColoringValid(mapIndex) == false) { ciftiParcelLabelFile->updateScalarColoringForMap(mapIndex); } std::vector dataValues(numberOfNodes); /* * Assigns colors for all nodes. */ const StructureEnum::Enum structure = brainStructure->getStructure(); ciftiParcelLabelFile->getMapSurfaceNodeColoring(mapIndex, structure, rgbv, &dataValues[0], numberOfNodes); CaretAssert(surface); CaretPointer topologyHelper = surface->getTopologyHelper(); /* * All nodes are colored. Remove coloring for nodes whose * label is not selected. */ GiftiLabelTable* labelTable = ciftiParcelLabelFile->getMapLabelTable(mapIndex); CaretAssert(labelTable); const bool drawMedialWallFilledFlag = props->isDrawMedialWallFilled(); assignLabelTableColors(labelTable, labelDrawingType, outlineColor, topologyHelper, displayGroup, browserTabIndex, dataValues, drawMedialWallFilledFlag, rgbv); return true; } /** * Assign cifti scalar coloring to nodes * @param brainStructure * The brain structure that contains the data files. * @param ciftiScalarFile * Cifti Scalar file that is selected. * @param ciftiMapUniqueID * UniqueID of selected map. * @param numberOfNodes * Number of nodes in surface. * @param rgbv * Color components set by this method. * Red, green, blue, valid. If the valid component is * zero, it indicates that the overlay did not assign * any coloring to the node. * @return * True if coloring is valid, else false. */ bool SurfaceNodeColoring::assignCiftiScalarColoring(const BrainStructure* brainStructure, CiftiBrainordinateScalarFile* ciftiScalarFile, const int32_t mapIndex, const int32_t numberOfNodes, float* rgbv) { Brain* brain = (Brain*)(brainStructure->getBrain()); std::vector allCiftiBrainordinateScalarFiles; brain->getConnectivityDenseScalarFiles(allCiftiBrainordinateScalarFiles); if (mapIndex < 0) { return false; } /* * Invalidate all coloring. */ for (int32_t i = 0; i < numberOfNodes; i++) { rgbv[i*4+3] = 0.0; } /* * Update coloring */ if (ciftiScalarFile->isMapColoringValid(mapIndex) == false) { ciftiScalarFile->updateScalarColoringForMap(mapIndex); } std::vector dataValues(numberOfNodes); const StructureEnum::Enum structure = brainStructure->getStructure(); ciftiScalarFile->getMapSurfaceNodeColoring(mapIndex, structure, rgbv, &dataValues[0], numberOfNodes); return true; } /** * Assign cifti parcel scalar coloring to nodes * @param brainStructure * The brain structure that contains the data files. * @param ciftiScalarFile * Cifti Scalar file that is selected. * @param ciftiMapUniqueID * UniqueID of selected map. * @param numberOfNodes * Number of nodes in surface. * @param rgbv * Color components set by this method. * Red, green, blue, valid. If the valid component is * zero, it indicates that the overlay did not assign * any coloring to the node. * @return * True if coloring is valid, else false. */ bool SurfaceNodeColoring::assignCiftiParcelScalarColoring(const BrainStructure* brainStructure, CiftiParcelScalarFile* ciftiParcelScalarFile, const int32_t mapIndex, const int32_t numberOfNodes, float* rgbv) { Brain* brain = (Brain*)(brainStructure->getBrain()); std::vector allCiftiParcelScalarFiles; brain->getConnectivityParcelScalarFiles(allCiftiParcelScalarFiles); if (mapIndex < 0) { return false; } /* * Invalidate all coloring. */ for (int32_t i = 0; i < numberOfNodes; i++) { rgbv[i*4+3] = 0.0; } /* * Update coloring */ if (ciftiParcelScalarFile->isMapColoringValid(mapIndex) == false) { ciftiParcelScalarFile->updateScalarColoringForMap(mapIndex); } std::vector dataValues(numberOfNodes); const StructureEnum::Enum structure = brainStructure->getStructure(); ciftiParcelScalarFile->getMapSurfaceNodeColoring(mapIndex, structure, rgbv, &dataValues[0], numberOfNodes); return true; } /** * Assign cifti scalar coloring to nodes * @param brainStructure * The brain structure that contains the data files. * @param ciftiDataSeriesFile * Cifti Data Series file that is selected. * @param ciftiMapUniqueID * UniqueID of selected map. * @param numberOfNodes * Number of nodes in surface. * @param rgbv * Color components set by this method. * Red, green, blue, valid. If the valid component is * zero, it indicates that the overlay did not assign * any coloring to the node. * @return * True if coloring is valid, else false. */ bool SurfaceNodeColoring::assignCiftiDataSeriesColoring(const BrainStructure* brainStructure, CiftiBrainordinateDataSeriesFile* ciftiDataSeriesFile, const int32_t mapIndex, const int32_t numberOfNodes, float* rgbv) { Brain* brain = (Brain*)(brainStructure->getBrain()); std::vector allCiftiDataSeriesFiles; brain->getConnectivityDataSeriesFiles(allCiftiDataSeriesFiles); if (mapIndex < 0) { return false; } /* * Invalidate all coloring. */ for (int32_t i = 0; i < numberOfNodes; i++) { rgbv[i*4+3] = 0.0; } /* * Update coloring */ if (ciftiDataSeriesFile->isMapColoringValid(mapIndex) == false) { ciftiDataSeriesFile->updateScalarColoringForMap(mapIndex); } /* * Get Coloring */ std::vector dataValues(numberOfNodes); const StructureEnum::Enum structure = brainStructure->getStructure(); ciftiDataSeriesFile->getMapSurfaceNodeColoring(mapIndex, structure, rgbv, &dataValues[0], numberOfNodes); return true; } /** * Assign cifti parcel series coloring to nodes * @param brainStructure * The brain structure that contains the data files. * @param ciftiParcelSeriesFile * Cifti Parcel Series file that is selected. * @param ciftiMapUniqueID * UniqueID of selected map. * @param numberOfNodes * Number of nodes in surface. * @param rgbv * Color components set by this method. * Red, green, blue, valid. If the valid component is * zero, it indicates that the overlay did not assign * any coloring to the node. * @return * True if coloring is valid, else false. */ bool SurfaceNodeColoring::assignCiftiParcelSeriesColoring(const BrainStructure* brainStructure, CiftiParcelSeriesFile* ciftiParcelSeriesFile, const int32_t mapIndex, const int32_t numberOfNodes, float* rgbv) { Brain* brain = (Brain*)(brainStructure->getBrain()); std::vector allCiftiParcelSeriesFiles; brain->getConnectivityParcelSeriesFiles(allCiftiParcelSeriesFiles); if (mapIndex < 0) { return false; } /* * Invalidate all coloring. */ for (int32_t i = 0; i < numberOfNodes; i++) { rgbv[i*4+3] = 0.0; } /* * Update coloring */ if (ciftiParcelSeriesFile->isMapColoringValid(mapIndex) == false) { ciftiParcelSeriesFile->updateScalarColoringForMap(mapIndex); } /* * Get Coloring */ std::vector dataValues(numberOfNodes); const StructureEnum::Enum structure = brainStructure->getStructure(); ciftiParcelSeriesFile->getMapSurfaceNodeColoring(mapIndex, structure, rgbv, &dataValues[0], numberOfNodes); return true; } /** * Assign RGBA coloring to nodes * @param brainStructure * The brain structure that contains the data files. * @param rgbaFile * RGBA file that is selected. * @param metricMapUniqueID * UniqueID of selected map. * @param numberOfNodes * Number of nodes in surface. * @param rgbv * Color components set by this method. * Red, green, blue, valid. If the valid component is * zero, it indicates that the overlay did not assign * any coloring to the node. * @return * True if coloring is valid, else false. */ bool SurfaceNodeColoring::assignRgbaColoring(const BrainStructure* brainStructure, const RgbaFile* rgbaFile, const int32_t /*mapIndex*/, const int32_t numberOfNodes, float* rgbv) { if ( ! rgbaFile->isMappableToSurfaceStructure(brainStructure->getStructure())) { return false; } if (rgbaFile->isEmpty()) { return false; } for (int32_t i = 0; i < numberOfNodes; i++) { const int32_t i4 = i * 4; rgbaFile->getVertexRGBA(i, &rgbv[i4]); } return true; } connectome-workbench-1.4.2/src/Brain/SurfaceNodeColoring.h000066400000000000000000000176351360521144700235350ustar00rootroot00000000000000#ifndef __SURFACE_NODE_COLORING__H_ #define __SURFACE_NODE_COLORING__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretColorEnum.h" #include "CaretObject.h" #include "CaretPointer.h" #include "DisplayGroupEnum.h" #include "LabelDrawingTypeEnum.h" namespace caret { class Brain; class BrainStructure; class BrowserTabContent; class CiftiMappableConnectivityMatrixDataFile; class CiftiBrainordinateDataSeriesFile; class CiftiBrainordinateLabelFile; class CiftiBrainordinateScalarFile; class CiftiParcelLabelFile; class CiftiParcelScalarFile; class CiftiParcelSeriesFile; class DisplayPropertiesLabels; class GiftiLabelTable; class Model; class LabelFile; class MetricFile; class OverlaySet; class Palette; class PaletteColorMapping; class RgbaFile; class Surface; class TopologyHelper; /// Performs coloring of surface nodes class SurfaceNodeColoring : public CaretObject { public: SurfaceNodeColoring(); virtual ~SurfaceNodeColoring(); float* colorSurfaceNodes(Model* model, Surface* surface, const int32_t browserTabIndex); private: SurfaceNodeColoring(const SurfaceNodeColoring&); SurfaceNodeColoring& operator=(const SurfaceNodeColoring&); public: virtual AString toString() const; private: enum MetricColorType { METRIC_COLOR_TYPE_NORMAL, METRIC_COLOR_TYPE_POS_THRESH_COLOR, METRIC_COLOR_TYPE_NEG_THRESH_COLOR, METRIC_COLOR_TYPE_DO_NOT_COLOR }; void colorSurfaceNodes(const DisplayPropertiesLabels* dpl, const int32_t browserTabIndex, const Surface* surface, OverlaySet* overlaySet, float* rgbaNodeColors); bool assignLabelColoring(const DisplayPropertiesLabels* dpl, const int32_t browserTabIndex, const BrainStructure* brainStructure, const Surface* surface, const LabelFile* labelFile, const int32_t mapIndex, const int32_t numberOfNodes, float* rgbv); bool assignCiftiDenseLabelColoring(const DisplayPropertiesLabels* displayPropertiesLabels, const int32_t browserTabIndex, const BrainStructure* brainStructure, const Surface* surface, CiftiBrainordinateLabelFile* ciftiLabelFile, const int32_t mapIndex, const int32_t numberOfNodes, float* rgbv); bool assignCiftiScalarColoring(const BrainStructure* brainStructure, CiftiBrainordinateScalarFile* ciftiScalarFile, const int32_t mapIndex, const int32_t numberOfNodes, float* rgbv); bool assignCiftiParcelLabelColoring(const DisplayPropertiesLabels* displayPropertiesLabels, const int32_t browserTabIndex, const BrainStructure* brainStructure, const Surface* surface, CiftiParcelLabelFile* ciftiParcelLabelFile, const int32_t mapIndex, const int32_t numberOfNodes, float* rgbv); bool assignCiftiParcelScalarColoring(const BrainStructure* brainStructure, CiftiParcelScalarFile* ciftiScalarFile, const int32_t mapIndex, const int32_t numberOfNodes, float* rgbv); bool assignCiftiDataSeriesColoring(const BrainStructure* brainStructure, CiftiBrainordinateDataSeriesFile* ciftiDataSeriesFile, const int32_t mapIndex, const int32_t numberOfNodes, float* rgbv); bool assignCiftiParcelSeriesColoring(const BrainStructure* brainStructure, CiftiParcelSeriesFile* ciftiParcelSeriesFile, const int32_t mapIndex, const int32_t numberOfNodes, float* rgbv); bool assignCiftiMappableConnectivityMatrixColoring(const BrainStructure* brainStructure, CiftiMappableConnectivityMatrixDataFile* ciftiConnectivityMatrixFile, const int32_t mapIndex, const int32_t numberOfNodes, float* rgbv); bool assignMetricColoring(const BrainStructure* brainStructure, MetricFile* metricFile, const int32_t mapIndex, const int32_t numberOfNodes, float* rgbv); bool assignRgbaColoring(const BrainStructure* brainStructure, const RgbaFile* rgbaFile, const int32_t mapIndex, const int32_t numberOfNodes, float* rgbv); void assignLabelTableColors(const GiftiLabelTable* labelTable, const LabelDrawingTypeEnum::Enum labelDrawingType, const CaretColorEnum::Enum outlineColor, const CaretPointer topologyHelper, const DisplayGroupEnum::Enum displayGroup, const int32_t browserTabIndex, const std::vector& labelIndices, const bool drawMedialWallFilledFlag, float* rgbv); void showBrainordinateHighlightRegionOfInterest(const Brain* brain, const Surface* surface, float* rgbaNodeColors); }; #ifdef __SURFACE_NODE_COLORING_DECLARE__ #endif // __SURFACE_NODE_COLORING_DECLARE__ } // namespace #endif //__SURFACE_NODE_COLORING__H_ connectome-workbench-1.4.2/src/Brain/SurfaceSelectionModel.cxx000066400000000000000000000376721360521144700244370ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __SURFACE_SELECTION_MODEL_DECLARE__ #include "SurfaceSelectionModel.h" #undef __SURFACE_SELECTION_MODEL_DECLARE__ #include "BrainStructure.h" #include "EventBrainStructureGetAll.h" #include "EventManager.h" #include "EventSurfacesGet.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "Surface.h" using namespace caret; /** * \class SurfaceSelection * \brief Maintains selection of a surface. * * Maintains selection of a surface. * * The constructors allow one to limit that available surfaces to those * from specified structures and surface types. * * If the selected surface becomes invalid, a different surface will * be selected. */ /** * Constructor for surfaces from a specific structure and of the given * surface types. * * @param structure * Limit to surfaces from this structure. * @param surfaceTypes * Types of surfaces that are available for selection. */ SurfaceSelectionModel::SurfaceSelectionModel(const StructureEnum::Enum structure, const std::vector& surfaceTypes) : CaretObject() { m_allowableStructures.push_back(structure); m_allowableSurfaceTypes = surfaceTypes; CaretAssert( ! surfaceTypes.empty()); } /** * Constructor for surfaces from any structure and of the given * surface types. * * @param surfaceTypes * Types of surfaces that are available for selection. */ SurfaceSelectionModel::SurfaceSelectionModel(const std::vector& surfaceTypes) : CaretObject() { m_allowableSurfaceTypes = surfaceTypes; CaretAssert( ! surfaceTypes.empty()); } /** * Destructor. */ SurfaceSelectionModel::~SurfaceSelectionModel() { } /** * @return The selected surface (NULL if none) */ Surface* SurfaceSelectionModel::getSurface() { updateModel(); return m_selectedSurface; } /** * @return The selected surface (NULL if none) */ const Surface* SurfaceSelectionModel::getSurface() const { updateModel(); return m_selectedSurface; } /** * Set the selected surface. * @param surface * New seleted surface. */ void SurfaceSelectionModel::setSurface(Surface* surface) { m_selectedSurface = surface; } /** * Set the selected surface to a surface of any of the given types with * first type having highest priority and last type having lowest priority. * * @param surfaceType * Highest priority type. * @param surfaceType2 * Second priority type. * @param surfaceType3 * Third priority type. * @param surfaceType4 * Fourth priority type. * @param surfaceType5 * Lowest priority type. */ void SurfaceSelectionModel::setSurfaceToType(const SurfaceTypeEnum::Enum surfaceType, const SurfaceTypeEnum::Enum surfaceType2, const SurfaceTypeEnum::Enum surfaceType3, const SurfaceTypeEnum::Enum surfaceType4, const SurfaceTypeEnum::Enum surfaceType5) { std::vector surfaces = getAvailableSurfaces(); std::vector surfaceTypes; surfaceTypes.push_back(surfaceType); if (surfaceType2 != SurfaceTypeEnum::UNKNOWN) { surfaceTypes.push_back(surfaceType2); } if (surfaceType3 != SurfaceTypeEnum::UNKNOWN) { surfaceTypes.push_back(surfaceType3); } if (surfaceType4 != SurfaceTypeEnum::UNKNOWN) { surfaceTypes.push_back(surfaceType4); } if (surfaceType5 != SurfaceTypeEnum::UNKNOWN) { surfaceTypes.push_back(surfaceType5); } for (std::vector::iterator typeIter = surfaceTypes.begin(); typeIter != surfaceTypes.end(); typeIter++) { const SurfaceTypeEnum::Enum type = *typeIter; for (std::vector::iterator surfaceIter = surfaces.begin(); surfaceIter != surfaces.end(); surfaceIter++) { Surface* s = *surfaceIter; if (s->getSurfaceType() == type) { setSurface(s); return; } } } } /** * @return A vector containing surfaces available * for selection. */ std::vector SurfaceSelectionModel::getAvailableSurfaces() const { std::vector unknownSurfaces; std::vector reconstructionSurfaces; std::vector anatomicalSurfaces; std::vector inflatedSurfaces; std::vector veryInflatedSurfaces; std::vector sphericalSurfaces; std::vector semiSphericalSurfaces; std::vector ellipsoidSurfaces; std::vector flatSurfaces; std::vector hullSurfaces; /* * Get ALL surfaces */ EventSurfacesGet getSurfacesEvent; EventManager::get()->sendEvent(getSurfacesEvent.getPointer()); std::vector allSurfaces = getSurfacesEvent.getSurfaces(); for (std::vector::iterator iter = allSurfaces.begin(); iter != allSurfaces.end(); iter++) { Surface* surface = *iter; /* * Filter by structure */ bool passesStructureTestFlag = false; if (m_allowableStructures.empty()) { passesStructureTestFlag = true; } else { const StructureEnum::Enum structure = surface->getStructure(); if (std::find(m_allowableStructures.begin(), m_allowableStructures.end(), structure) != m_allowableStructures.end()) { passesStructureTestFlag = true; } } if (passesStructureTestFlag) { const SurfaceTypeEnum::Enum surfaceType = surface->getSurfaceType(); if (std::find(m_allowableSurfaceTypes.begin(), m_allowableSurfaceTypes.end(), surfaceType) != m_allowableSurfaceTypes.end()) { switch (surfaceType) { case SurfaceTypeEnum::UNKNOWN: unknownSurfaces.push_back(surface); break; case SurfaceTypeEnum::RECONSTRUCTION: reconstructionSurfaces.push_back(surface); break; case SurfaceTypeEnum::ANATOMICAL: anatomicalSurfaces.push_back(surface); break; case SurfaceTypeEnum::INFLATED: inflatedSurfaces.push_back(surface); break; case SurfaceTypeEnum::VERY_INFLATED: veryInflatedSurfaces.push_back(surface); break; case SurfaceTypeEnum::SPHERICAL: sphericalSurfaces.push_back(surface); break; case SurfaceTypeEnum::SEMI_SPHERICAL: semiSphericalSurfaces.push_back(surface); break; case SurfaceTypeEnum::ELLIPSOID: ellipsoidSurfaces.push_back(surface); break; case SurfaceTypeEnum::FLAT: flatSurfaces.push_back(surface); break; case SurfaceTypeEnum::HULL: hullSurfaces.push_back(surface); break; } } } } std::vector surfacesOut; surfacesOut.insert(surfacesOut.end(), anatomicalSurfaces.begin(), anatomicalSurfaces.end()); surfacesOut.insert(surfacesOut.end(), reconstructionSurfaces.begin(), reconstructionSurfaces.end()); surfacesOut.insert(surfacesOut.end(), inflatedSurfaces.begin(), inflatedSurfaces.end()); surfacesOut.insert(surfacesOut.end(), veryInflatedSurfaces.begin(), veryInflatedSurfaces.end()); surfacesOut.insert(surfacesOut.end(), sphericalSurfaces.begin(), sphericalSurfaces.end()); surfacesOut.insert(surfacesOut.end(), semiSphericalSurfaces.begin(), semiSphericalSurfaces.end()); surfacesOut.insert(surfacesOut.end(), ellipsoidSurfaces.begin(), ellipsoidSurfaces.end()); surfacesOut.insert(surfacesOut.end(), hullSurfaces.begin(), hullSurfaces.end()); surfacesOut.insert(surfacesOut.end(), flatSurfaces.begin(), flatSurfaces.end()); surfacesOut.insert(surfacesOut.end(), unknownSurfaces.begin(), unknownSurfaces.end()); return surfacesOut; } /** * Update the model. * May be needed if the loaded surfaces change. */ void SurfaceSelectionModel::updateModel() const { std::vector surfaces = getAvailableSurfaces(); if (surfaces.empty()) { m_selectedSurface = NULL; return; } if (m_selectedSurface != NULL) { if (std::find(surfaces.begin(), surfaces.end(), m_selectedSurface) == surfaces.end()) { m_selectedSurface = NULL; } } if (m_selectedSurface == NULL) { EventBrainStructureGetAll brainStructureEvent; EventManager::get()->sendEvent(brainStructureEvent.getPointer()); const int32_t numBrainStructures = brainStructureEvent.getNumberOfBrainStructures(); for (int32_t i = 0; i < numBrainStructures; i++) { BrainStructure* bs = brainStructureEvent.getBrainStructureByIndex(i); /* * Use the primary anatomical surface if it is acceptable */ Surface* primaryAnatomicalSurface = NULL; if (m_allowableStructures.empty()) { primaryAnatomicalSurface = bs->getPrimaryAnatomicalSurface(); } else { const StructureEnum::Enum structure = bs->getStructure(); if (std::find(m_allowableStructures.begin(), m_allowableStructures.end(), structure) != m_allowableStructures.end()) { primaryAnatomicalSurface = bs->getPrimaryAnatomicalSurface(); break; } } if (primaryAnatomicalSurface != NULL) { if (std::find(surfaces.begin(), surfaces.end(), primaryAnatomicalSurface) != surfaces.end()) { m_selectedSurface = primaryAnatomicalSurface; break; } } } if (m_selectedSurface == NULL) { m_selectedSurface = surfaces[0]; } } } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of the class' instance. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* SurfaceSelectionModel::saveToScene(const SceneAttributes* /*sceneAttributes*/, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "SurfaceSelectionModel", 1); Surface* surface = getSurface(); if (surface != NULL) { sceneClass->addPathName("m_selectedSurfacePathName", surface->getFileName()); } return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. May be NULL for some types of scenes. */ void SurfaceSelectionModel::restoreFromScene(const SceneAttributes* /*sceneAttributes*/, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } std::vector allSurfaces = getAvailableSurfaces(); /* * Element "m_selectedSurfacePathName" replaces older elements * and fixes problem with absolute paths in the scene file */ const AString surfacePathName = sceneClass->getPathNameValue("m_selectedSurfacePathName"); Surface* pathNameMatchSurface = NULL; Surface* nameMatchSurface = NULL; if ( ! surfacePathName.isEmpty()) { for (auto surface : allSurfaces) { if (surface->getFileName() == surfacePathName) { pathNameMatchSurface = surface; break; } } } else { /* * For full path, find the best match using the right-most characters that * will contain any relative path. When scene files are moved to different * computers the full path may change the parts of the path nearest the * name of the file will match. */ const AString surfaceFileNameFullPath = sceneClass->getStringValue("m_selectedSurfaceFullPath", ""); int32_t pathNameMatchLength = 0; if ( ! surfaceFileNameFullPath.isEmpty()) { for (auto surface : allSurfaces) { const AString name = surface->getFileName(); const int32_t numMatch = name.countMatchingCharactersFromEnd(surfaceFileNameFullPath); if (numMatch > pathNameMatchLength) { pathNameMatchLength = numMatch; pathNameMatchSurface = surface; } } } /* * Match name of file with NO path * Always restore this so that the object is marked as restored * (within the 'get' method). Otherwise if compiled debug, this * object will get logged as 'not restored'. */ const AString surfaceFileName = sceneClass->getStringValue("m_selectedSurface", ""); if ( ! surfaceFileName.isEmpty()) { for (auto surface : allSurfaces) { if (surface->getFileNameNoPath() == surfaceFileName) { nameMatchSurface = surface; break; } } } } if (pathNameMatchSurface != NULL) { setSurface(pathNameMatchSurface); } else if (nameMatchSurface != NULL) { setSurface(nameMatchSurface); } else { setSurface(NULL); } } connectome-workbench-1.4.2/src/Brain/SurfaceSelectionModel.h000066400000000000000000000062751360521144700240570ustar00rootroot00000000000000#ifndef __SURFACE_SELECTION_MODEL_H__ #define __SURFACE_SELECTION_MODEL_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "SceneableInterface.h" #include "StructureEnum.h" #include "SurfaceTypeEnum.h" namespace caret { class Surface; class SurfaceSelectionModel : public CaretObject, public SceneableInterface { public: SurfaceSelectionModel(const StructureEnum::Enum structure, const std::vector& surfaceTypes); SurfaceSelectionModel(const std::vector& surfaceTypes); virtual ~SurfaceSelectionModel(); Surface* getSurface(); const Surface* getSurface() const; void setSurface(Surface* surface); void setSurfaceToType(const SurfaceTypeEnum::Enum surfaceType, const SurfaceTypeEnum::Enum surfaceType2 = SurfaceTypeEnum::UNKNOWN, const SurfaceTypeEnum::Enum surfaceType3 = SurfaceTypeEnum::UNKNOWN, const SurfaceTypeEnum::Enum surfaceType4 = SurfaceTypeEnum::UNKNOWN, const SurfaceTypeEnum::Enum surfaceType5 = SurfaceTypeEnum::UNKNOWN); std::vector getAvailableSurfaces() const; void updateModel() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: SurfaceSelectionModel(const SurfaceSelectionModel&); SurfaceSelectionModel& operator=(const SurfaceSelectionModel&); mutable Surface* m_selectedSurface; /** If empty, allow any structure, otherwise restrict to these structures */ std::vector m_allowableStructures; /** If empty, allow any surface type, otherwise restrict to these types */ std::vector m_allowableSurfaceTypes; }; #ifdef __SURFACE_SELECTION_MODEL_DECLARE__ // #endif // __SURFACE_SELECTION_MODEL_DECLARE__ } // namespace #endif //__SURFACE_SELECTION_MODEL_H__ connectome-workbench-1.4.2/src/Brain/TabContentBase.cxx000066400000000000000000000026771360521144700230510ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __TAB_CONTENT_BASE_DECLARE__ #include "TabContentBase.h" #undef __TAB_CONTENT_BASE_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::TabContentBase * \brief * \ingroup Brain * * */ /** * Constructor. */ TabContentBase::TabContentBase() : CaretObject() { } /** * Destructor. */ TabContentBase::~TabContentBase() { } /** * Get a description of this object's content. * @return String describing this object's content. */ AString TabContentBase::toString() const { return "TabContentBase"; } connectome-workbench-1.4.2/src/Brain/TabContentBase.h000066400000000000000000000032261360521144700224650ustar00rootroot00000000000000#ifndef __TAB_CONTENT_BASE_H__ #define __TAB_CONTENT_BASE_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" namespace caret { class TabContentBase : public CaretObject { public: TabContentBase(); virtual ~TabContentBase(); TabContentBase(const TabContentBase&) = delete; TabContentBase& operator=(const TabContentBase&) = delete; virtual AString getTabName() const = 0; virtual AString getTabNamePrefix() const = 0; // ADD_NEW_METHODS_HERE virtual AString toString() const; private: // ADD_NEW_MEMBERS_HERE }; #ifdef __TAB_CONTENT_BASE_DECLARE__ // #endif // __TAB_CONTENT_BASE_DECLARE__ } // namespace #endif //__TAB_CONTENT_BASE_H__ connectome-workbench-1.4.2/src/Brain/UserInputModeEnum.cxx000066400000000000000000000256641360521144700236060ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __USER_INPUT_MODE_ENUM_DECLARE__ #include "UserInputModeEnum.h" #undef __USER_INPUT_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::UserInputModeEnum * \brief User Input Modes for Browser Window * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_userInputModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void userInputModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "UserInputModeEnum.h" * * Instatiate: * m_userInputModeEnumComboBox = new EnumComboBoxTemplate(this); * m_userInputModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_userInputModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(userInputModeEnumComboBoxItemActivated())); * * Update the selection: * m_userInputModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const UserInputModeEnum::Enum VARIABLE = m_userInputModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ UserInputModeEnum::UserInputModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ UserInputModeEnum::~UserInputModeEnum() { } /** * Initialize the enumerated metadata. */ void UserInputModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(UserInputModeEnum(INVALID, "INVALID", "Invalid")); enumData.push_back(UserInputModeEnum(ANNOTATIONS, "ANNOTATIONS", "Annotations")); enumData.push_back(UserInputModeEnum(BORDERS, "BORDERS", "Borders")); enumData.push_back(UserInputModeEnum(FOCI, "FOCI", "Foci")); enumData.push_back(UserInputModeEnum(IMAGE, "IMAGE", "Image")); enumData.push_back(UserInputModeEnum(VIEW, "VIEW", "View")); enumData.push_back(UserInputModeEnum(VOLUME_EDIT, "VOLUME_EDIT", "Volume Edit")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const UserInputModeEnum* UserInputModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const UserInputModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString UserInputModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const UserInputModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ UserInputModeEnum::Enum UserInputModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = UserInputModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const UserInputModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type UserInputModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString UserInputModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const UserInputModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ UserInputModeEnum::Enum UserInputModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = UserInputModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const UserInputModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type UserInputModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t UserInputModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const UserInputModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ UserInputModeEnum::Enum UserInputModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = UserInputModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const UserInputModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type UserInputModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void UserInputModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void UserInputModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(UserInputModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void UserInputModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(UserInputModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Brain/UserInputModeEnum.h000066400000000000000000000063261360521144700232250ustar00rootroot00000000000000#ifndef __USER_INPUT_MODE_ENUM_H__ #define __USER_INPUT_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class UserInputModeEnum { public: /** * Enumerated values. */ enum Enum { /** Invalid */ INVALID, /** Annotations */ ANNOTATIONS, /** Borders */ BORDERS, /** Foci */ FOCI, /** Image */ IMAGE, /** View */ VIEW, /** Volume Edit */ VOLUME_EDIT }; ~UserInputModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: UserInputModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const UserInputModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __USER_INPUT_MODE_ENUM_DECLARE__ std::vector UserInputModeEnum::enumData; bool UserInputModeEnum::initializedFlag = false; int32_t UserInputModeEnum::integerCodeCounter = 0; #endif // __USER_INPUT_MODE_ENUM_DECLARE__ } // namespace #endif //__USER_INPUT_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Brain/ViewingTransformations.cxx000066400000000000000000000244771360521144700247410ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __VIEWING_TRANSFORMATIONS_DECLARE__ #include "ViewingTransformations.h" #undef __VIEWING_TRANSFORMATIONS_DECLARE__ #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ViewingTransformations * \brief Viewing transformations (pan/rotate/zoom). * \ingroup Brain */ /** * Constructor. */ ViewingTransformations::ViewingTransformations() : CaretObject() { m_sceneAssistant = new SceneClassAssistant(); m_rotationMatrix = new Matrix4x4(); m_translation[0] = 0.0; m_translation[1] = 0.0; m_translation[2] = 0.0; m_scaling = 1.0; m_rightCortexFlatMapOffset[0] = 0.0; m_rightCortexFlatMapOffset[1] = 0.0; m_rightCortexFlatMapZoomFactor = 1.0; m_sceneAssistant->addArray("m_translation", m_translation, 3, 0.0); m_sceneAssistant->add("m_scaling", &m_scaling); m_sceneAssistant->addArray("m_rightCortexFlatMapOffset", m_rightCortexFlatMapOffset, 2, 0.0); m_sceneAssistant->add("m_rightCortexFlatMapZoomFactor", &m_rightCortexFlatMapZoomFactor); } /** * Destructor. */ ViewingTransformations::~ViewingTransformations() { delete m_rotationMatrix; delete m_sceneAssistant; } /** * Copy constructor. * @param obj * Object that is copied. */ ViewingTransformations::ViewingTransformations(const ViewingTransformations& obj) : CaretObject(obj), SceneableInterface(obj) { this->copyHelperViewingTransformations(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ViewingTransformations& ViewingTransformations::operator=(const ViewingTransformations& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperViewingTransformations(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ViewingTransformations::copyHelperViewingTransformations(const ViewingTransformations& obj) { *m_rotationMatrix = *obj.m_rotationMatrix; m_translation[0] = obj.m_translation[0]; m_translation[1] = obj.m_translation[1]; m_translation[2] = obj.m_translation[2]; m_scaling = obj.m_scaling; m_rightCortexFlatMapOffset[0] = obj.m_rightCortexFlatMapOffset[0]; m_rightCortexFlatMapOffset[1] = obj.m_rightCortexFlatMapOffset[1]; m_rightCortexFlatMapZoomFactor = obj.m_rightCortexFlatMapZoomFactor; } /** * @return The viewing translation. */ const float* ViewingTransformations::getTranslation() const { return m_translation; } /** * Get the viewing translation. * * @param translationOut * Translation values output. */ void ViewingTransformations::getTranslation(float translationOut[3]) const { translationOut[0] = m_translation[0]; translationOut[1] = m_translation[1]; translationOut[2] = m_translation[2]; } /** * Set the viewing translation. * * @param translation * New translation values. */ void ViewingTransformations::setTranslation( const float translation[3]) { m_translation[0] = translation[0]; m_translation[1] = translation[1]; m_translation[2] = translation[2]; } /** * Set the viewing translation. * * @param translationX * New translation X-value. * @param translationY * New translation Y-value. * @param translationZ * New translation Z-value. */ void ViewingTransformations::setTranslation(const float translationX, const float translationY, const float translationZ) { m_translation[0] = translationX; m_translation[1] = translationY; m_translation[2] = translationZ; } /** * @return The viewing scaling. */ float ViewingTransformations::getScaling() const { return m_scaling; } /** * Set the viewing scaling. * @param scaling * New value for scaling. */ void ViewingTransformations::setScaling(const float scaling) { m_scaling = scaling; } /** * @return The rotation matrix. */ Matrix4x4 ViewingTransformations::getRotationMatrix() const { return *m_rotationMatrix; } /** * Set the rotation matrix. * * @param rotationMatrix * The new rotation matrix. */ void ViewingTransformations::setRotationMatrix(const Matrix4x4& rotationMatrix) { *m_rotationMatrix = rotationMatrix; } /** * Get the offset for the right cortex flat map. * * @param rightCortexFlatMapOffsetX * Output with X offset. * @param rightCortexFlatMapOffsetY * Output with Y offset. */ void ViewingTransformations::getRightCortexFlatMapOffset(float& rightCortexFlatMapOffsetX, float& rightCortexFlatMapOffsetY) const { rightCortexFlatMapOffsetX = m_rightCortexFlatMapOffset[0]; rightCortexFlatMapOffsetY = m_rightCortexFlatMapOffset[1]; } /** * Set the offset for the right cortex flat map. * * @param rightCortexFlatMapOffsetX * New X offset. * @param rightCortexFlatMapOffsetY * New Y offset. */ void ViewingTransformations::setRightCortexFlatMapOffset(const float rightCortexFlatMapOffsetX, const float rightCortexFlatMapOffsetY) { m_rightCortexFlatMapOffset[0] = rightCortexFlatMapOffsetX; m_rightCortexFlatMapOffset[1] = rightCortexFlatMapOffsetY; } /** * @return The right flat cortex flat map offset. */ float ViewingTransformations::getRightCortexFlatMapZoomFactor() const { return m_rightCortexFlatMapZoomFactor; } /** * Set the right flat cortex flat map offset. * * @param rightCortexFlatMapZoomFactor * The right flat cortex flat map offset. */ void ViewingTransformations::setRightCortexFlatMapZoomFactor(const float rightCortexFlatMapZoomFactor) { m_rightCortexFlatMapZoomFactor = rightCortexFlatMapZoomFactor; } /** * Reset the view to the default view for a SURFACE */ void ViewingTransformations::resetView() { setTranslation(0.0, 0.0, 0.0); m_rotationMatrix->identity(); setScaling(1.0); setRightCortexFlatMapOffset(0.0, 0.0); setRightCortexFlatMapZoomFactor(1.0); leftView(); } /** * Set to a right side view. */ void ViewingTransformations::rightView() { m_rotationMatrix->identity(); m_rotationMatrix->rotateY(-90.0); m_rotationMatrix->rotateZ(-90.0); } /** * set to a left side view. */ void ViewingTransformations::leftView() { m_rotationMatrix->identity(); m_rotationMatrix->rotateY(90.0); m_rotationMatrix->rotateZ(90.0); } /** * set to a anterior view. */ void ViewingTransformations::anteriorView() { m_rotationMatrix->identity(); m_rotationMatrix->setRotation(90.0, 0.0, -180.0); // m_rotationMatrix->rotateX(-90.0); // m_rotationMatrix->rotateY(180.0); } /** * set to a posterior view. */ void ViewingTransformations::posteriorView() { m_rotationMatrix->identity(); m_rotationMatrix->setRotation(-90.0, 0.0, 0.0); // m_rotationMatrix->rotateX(-90.0); } /** * set to a dorsal view. */ void ViewingTransformations::dorsalView() { // m_rotationMatrix->identity(); m_rotationMatrix->setRotation(0.0, 0.0, 90.0); } /** * set to a ventral view. */ void ViewingTransformations::ventralView() { // m_rotationMatrix->identity(); // m_rotationMatrix->rotateY(-180.0); m_rotationMatrix->setRotation(0.0, 180.0, 90.0); } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ViewingTransformations::toString() const { return "ViewingTransformations"; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* ViewingTransformations::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ViewingTransformations", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); /* * Save rotation matrices. */ float matrix[4][4]; m_rotationMatrix->getMatrix(matrix); sceneClass->addFloatArray("m_rotationMatrix", (float*)matrix, 16); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ViewingTransformations::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); /* * Restore rotation matrices. */ float matrix[4][4]; if (sceneClass->getFloatArrayValue("m_rotationMatrix", (float*)matrix, 16) == 16) { m_rotationMatrix->setMatrix(matrix); } else { m_rotationMatrix->identity(); } } connectome-workbench-1.4.2/src/Brain/ViewingTransformations.h000066400000000000000000000075441360521144700243620ustar00rootroot00000000000000#ifndef __VIEWING_TRANSFORMATIONS_H__ #define __VIEWING_TRANSFORMATIONS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "Matrix4x4.h" #include "SceneableInterface.h" namespace caret { class SceneClassAssistant; class ViewingTransformations : public CaretObject, public SceneableInterface { public: ViewingTransformations(); virtual ~ViewingTransformations(); ViewingTransformations(const ViewingTransformations& obj); ViewingTransformations& operator=(const ViewingTransformations& obj); const float* getTranslation() const; void getTranslation(float translationOut[3]) const; void setTranslation( const float translation[3]); void setTranslation(const float translationX, const float translationY, const float translationZ); float getScaling() const; void setScaling(const float scaling); Matrix4x4 getRotationMatrix() const; void setRotationMatrix(const Matrix4x4& rotationMatrix); void getRightCortexFlatMapOffset(float& rightCortexFlatMapOffsetX, float& rightCortexFlatMapOffsetY) const; void setRightCortexFlatMapOffset(const float rightCortexFlatMapOffsetX, const float rightCortexFlatMapOffsetY); float getRightCortexFlatMapZoomFactor() const; void setRightCortexFlatMapZoomFactor(const float rightCortexFlatMapZoomFactor); virtual void resetView(); virtual void rightView(); virtual void leftView(); virtual void anteriorView(); virtual void posteriorView(); virtual void dorsalView(); virtual void ventralView(); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // ADD_NEW_METHODS_HERE virtual AString toString() const; protected: /** Rotation matrix. */ Matrix4x4* m_rotationMatrix; /** Translation */ float m_translation[3]; /** Scaling. */ float m_scaling; /** Offset for right cortex flat map */ float m_rightCortexFlatMapOffset[2]; float m_rightCortexFlatMapZoomFactor; private: void copyHelperViewingTransformations(const ViewingTransformations& obj); SceneClassAssistant* m_sceneAssistant; // ADD_NEW_MEMBERS_HERE }; #ifdef __VIEWING_TRANSFORMATIONS_DECLARE__ // #endif // __VIEWING_TRANSFORMATIONS_DECLARE__ } // namespace #endif //__VIEWING_TRANSFORMATIONS_H__ connectome-workbench-1.4.2/src/Brain/ViewingTransformationsCerebellum.cxx000066400000000000000000000055231360521144700267300ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __VIEWING_TRANSFORMATIONS_CEREBELLUM_DECLARE__ #include "ViewingTransformationsCerebellum.h" #undef __VIEWING_TRANSFORMATIONS_CEREBELLUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ViewingTransformationsCerebellum * \brief Viewing transformations (pan/rotate/zoom) for cerebellum. * \ingroup Brain * * Extends ViewingTransformations with differences for cerebellum viewing. */ /** * Constructor. */ ViewingTransformationsCerebellum::ViewingTransformationsCerebellum() : ViewingTransformations() { } /** * Destructor. */ ViewingTransformationsCerebellum::~ViewingTransformationsCerebellum() { } /** * Copy constructor. * @param obj * Object that is copied. */ ViewingTransformationsCerebellum::ViewingTransformationsCerebellum(const ViewingTransformationsCerebellum& obj) : ViewingTransformations(obj) { this->copyHelperViewingTransformationsCerebellum(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ViewingTransformationsCerebellum& ViewingTransformationsCerebellum::operator=(const ViewingTransformationsCerebellum& obj) { if (this != &obj) { ViewingTransformations::operator=(obj); this->copyHelperViewingTransformationsCerebellum(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ViewingTransformationsCerebellum::copyHelperViewingTransformationsCerebellum(const ViewingTransformationsCerebellum& /*obj*/) { /* nothing to copy */ } /** * Reset the view to the default view. */ void ViewingTransformationsCerebellum::resetView() { ViewingTransformations::resetView(); dorsalView(); } /** * set to a dorsal view. */ void ViewingTransformationsCerebellum::dorsalView() { m_rotationMatrix->setRotation(0.0, 0.0, 0.0); } /** * set to a ventral view. */ void ViewingTransformationsCerebellum::ventralView() { m_rotationMatrix->setRotation(0.0, 180.0, 180.0); } connectome-workbench-1.4.2/src/Brain/ViewingTransformationsCerebellum.h000066400000000000000000000036371360521144700263610ustar00rootroot00000000000000#ifndef __VIEWING_TRANSFORMATIONS_CEREBELLUM_H__ #define __VIEWING_TRANSFORMATIONS_CEREBELLUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ViewingTransformations.h" namespace caret { class ViewingTransformationsCerebellum : public ViewingTransformations { public: ViewingTransformationsCerebellum(); virtual ~ViewingTransformationsCerebellum(); ViewingTransformationsCerebellum(const ViewingTransformationsCerebellum& obj); ViewingTransformationsCerebellum& operator=(const ViewingTransformationsCerebellum& obj); virtual void resetView(); virtual void ventralView(); virtual void dorsalView(); // ADD_NEW_METHODS_HERE private: void copyHelperViewingTransformationsCerebellum(const ViewingTransformationsCerebellum& obj); // ADD_NEW_MEMBERS_HERE }; #ifdef __VIEWING_TRANSFORMATIONS_CEREBELLUM_DECLARE__ // #endif // __VIEWING_TRANSFORMATIONS_CEREBELLUM_DECLARE__ } // namespace #endif //__VIEWING_TRANSFORMATIONS_CEREBELLUM_H__ connectome-workbench-1.4.2/src/Brain/ViewingTransformationsVolume.cxx000066400000000000000000000047441360521144700261240ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __VIEWING_TRANSFORMATIONS_VOLUME_DECLARE__ #include "ViewingTransformationsVolume.h" #undef __VIEWING_TRANSFORMATIONS_VOLUME_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ViewingTransformationsVolume * \brief Viewing transformations (pan/rotate/zoom) for volume. * \ingroup Brain * * Extends ViewingTransformations with differences for volume viewing. */ /** * Constructor. */ ViewingTransformationsVolume::ViewingTransformationsVolume() : ViewingTransformations() { } /** * Destructor. */ ViewingTransformationsVolume::~ViewingTransformationsVolume() { } /** * Copy constructor. * @param obj * Object that is copied. */ ViewingTransformationsVolume::ViewingTransformationsVolume(const ViewingTransformationsVolume& obj) : ViewingTransformations(obj) { this->copyHelperViewingTransformationsVolume(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ViewingTransformationsVolume& ViewingTransformationsVolume::operator=(const ViewingTransformationsVolume& obj) { if (this != &obj) { ViewingTransformations::operator=(obj); this->copyHelperViewingTransformationsVolume(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ViewingTransformationsVolume::copyHelperViewingTransformationsVolume(const ViewingTransformationsVolume& /*obj*/) { } /** * Reset the view to the default view for a VOLUME. */ void ViewingTransformationsVolume::resetView() { ViewingTransformations::resetView(); m_rotationMatrix->identity(); } connectome-workbench-1.4.2/src/Brain/ViewingTransformationsVolume.h000066400000000000000000000034271360521144700255460ustar00rootroot00000000000000#ifndef __VIEWING_TRANSFORMATIONS_VOLUME_H__ #define __VIEWING_TRANSFORMATIONS_VOLUME_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ViewingTransformations.h" namespace caret { class ViewingTransformationsVolume : public ViewingTransformations { public: ViewingTransformationsVolume(); virtual ~ViewingTransformationsVolume(); ViewingTransformationsVolume(const ViewingTransformationsVolume& obj); ViewingTransformationsVolume& operator=(const ViewingTransformationsVolume& obj); virtual void resetView(); // ADD_NEW_METHODS_HERE private: void copyHelperViewingTransformationsVolume(const ViewingTransformationsVolume& obj); // ADD_NEW_MEMBERS_HERE }; #ifdef __VIEWING_TRANSFORMATIONS_VOLUME_DECLARE__ // #endif // __VIEWING_TRANSFORMATIONS_VOLUME_DECLARE__ } // namespace #endif //__VIEWING_TRANSFORMATIONS_VOLUME_H__ connectome-workbench-1.4.2/src/Brain/VolumeSliceDrawingTypeEnum.cxx000066400000000000000000000256501360521144700254430ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __VOLUME_SLICE_DRAWING_TYPE_ENUM_DECLARE__ #include "VolumeSliceDrawingTypeEnum.h" #undef __VOLUME_SLICE_DRAWING_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::VolumeSliceDrawingTypeEnum * \brief Enumerated type for type of volume slice drawing * * Enumerated type for drawing a single slice or a montage of slices * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_volumeSliceDrawingTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void volumeSliceDrawingTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "VolumeSliceDrawingTypeEnum.h" * * Instatiate: * m_volumeSliceDrawingTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_volumeSliceDrawingTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_volumeSliceDrawingTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(volumeSliceDrawingTypeEnumComboBoxItemActivated())); * * Update the selection: * m_volumeSliceDrawingTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const VolumeSliceDrawingTypeEnum::Enum VARIABLE = m_volumeSliceDrawingTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ VolumeSliceDrawingTypeEnum::VolumeSliceDrawingTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ VolumeSliceDrawingTypeEnum::~VolumeSliceDrawingTypeEnum() { } /** * Initialize the enumerated metadata. */ void VolumeSliceDrawingTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(VolumeSliceDrawingTypeEnum(VOLUME_SLICE_DRAW_MONTAGE, "VOLUME_SLICE_DRAW_MONTAGE", "Draw a montage of slices")); enumData.push_back(VolumeSliceDrawingTypeEnum(VOLUME_SLICE_DRAW_SINGLE, "VOLUME_SLICE_DRAW_SINGLE", "Draw a single slice")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const VolumeSliceDrawingTypeEnum* VolumeSliceDrawingTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const VolumeSliceDrawingTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString VolumeSliceDrawingTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const VolumeSliceDrawingTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ VolumeSliceDrawingTypeEnum::Enum VolumeSliceDrawingTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = VolumeSliceDrawingTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const VolumeSliceDrawingTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type VolumeSliceDrawingTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString VolumeSliceDrawingTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const VolumeSliceDrawingTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ VolumeSliceDrawingTypeEnum::Enum VolumeSliceDrawingTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = VolumeSliceDrawingTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const VolumeSliceDrawingTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type VolumeSliceDrawingTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t VolumeSliceDrawingTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const VolumeSliceDrawingTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ VolumeSliceDrawingTypeEnum::Enum VolumeSliceDrawingTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = VolumeSliceDrawingTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const VolumeSliceDrawingTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type VolumeSliceDrawingTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void VolumeSliceDrawingTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void VolumeSliceDrawingTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(VolumeSliceDrawingTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void VolumeSliceDrawingTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(VolumeSliceDrawingTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Brain/VolumeSliceDrawingTypeEnum.h000066400000000000000000000063211360521144700250620ustar00rootroot00000000000000#ifndef __VOLUME_SLICE_DRAWING_TYPE_ENUM_H__ #define __VOLUME_SLICE_DRAWING_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class VolumeSliceDrawingTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Draw a montage of slices */ VOLUME_SLICE_DRAW_MONTAGE, /** Draw a single slice */ VOLUME_SLICE_DRAW_SINGLE }; ~VolumeSliceDrawingTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: VolumeSliceDrawingTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const VolumeSliceDrawingTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __VOLUME_SLICE_DRAWING_TYPE_ENUM_DECLARE__ std::vector VolumeSliceDrawingTypeEnum::enumData; bool VolumeSliceDrawingTypeEnum::initializedFlag = false; int32_t VolumeSliceDrawingTypeEnum::integerCodeCounter = 0; #endif // __VOLUME_SLICE_DRAWING_TYPE_ENUM_DECLARE__ } // namespace #endif //__VOLUME_SLICE_DRAWING_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Brain/VolumeSliceInterpolationEdgeEffectsMaskingEnum.cxx000066400000000000000000000322111360521144700314230ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __VOLUME_SLICE_INTERPOLATION_EDGE_EFFECTS_MASKING_ENUM_DECLARE__ #include "VolumeSliceInterpolationEdgeEffectsMaskingEnum.h" #undef __VOLUME_SLICE_INTERPOLATION_EDGE_EFFECTS_MASKING_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::VolumeSliceInterpolationEdgeEffectsMaskingEnum * \brief Enumerated type for edge effects masking. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_volumeSliceInterpolationEdgeEffectsMaskingEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void volumeSliceInterpolationEdgeEffectsMaskingEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "VolumeSliceInterpolationEdgeEffectsMaskingEnum.h" * * Instatiate: * m_volumeSliceInterpolationEdgeEffectsMaskingEnumComboBox = new EnumComboBoxTemplate(this); * m_volumeSliceInterpolationEdgeEffectsMaskingEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_volumeSliceInterpolationEdgeEffectsMaskingEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(volumeSliceInterpolationEdgeEffectsMaskingEnumComboBoxItemActivated())); * * Update the selection: * m_volumeSliceInterpolationEdgeEffectsMaskingEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum VARIABLE = m_volumeSliceInterpolationEdgeEffectsMaskingEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ VolumeSliceInterpolationEdgeEffectsMaskingEnum::VolumeSliceInterpolationEdgeEffectsMaskingEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ VolumeSliceInterpolationEdgeEffectsMaskingEnum::~VolumeSliceInterpolationEdgeEffectsMaskingEnum() { } AString VolumeSliceInterpolationEdgeEffectsMaskingEnum::getToolTip() { AString toolTip("" "Masking is used to remove edge effects from cubic
" "interpolation. In extreme instances, the artifacts
" "result in blocky and/or striped patterns.
" "
"); std::vector allEnums; getAllEnums(allEnums); for (const auto enumValue : allEnums) { AString description(toGuiName(enumValue) + " - "); switch (enumValue) { case OFF: description.append("No masking"); break; case LOOSE: description.append("Mask with Trilinear Interpolation"); break; case TIGHT: description.append("Mask with Enclosing Voxel"); break; } toolTip.append(description + "
"); } toolTip.append(""); return toolTip; } /** * Initialize the enumerated metadata. */ void VolumeSliceInterpolationEdgeEffectsMaskingEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(VolumeSliceInterpolationEdgeEffectsMaskingEnum(OFF, "OFF", "Masking Off")); enumData.push_back(VolumeSliceInterpolationEdgeEffectsMaskingEnum(LOOSE, "LOOSE", "Masking Loose")); enumData.push_back(VolumeSliceInterpolationEdgeEffectsMaskingEnum(TIGHT, "TIGHT", "Masking Tight")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const VolumeSliceInterpolationEdgeEffectsMaskingEnum* VolumeSliceInterpolationEdgeEffectsMaskingEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const VolumeSliceInterpolationEdgeEffectsMaskingEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString VolumeSliceInterpolationEdgeEffectsMaskingEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const VolumeSliceInterpolationEdgeEffectsMaskingEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum VolumeSliceInterpolationEdgeEffectsMaskingEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = VolumeSliceInterpolationEdgeEffectsMaskingEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const VolumeSliceInterpolationEdgeEffectsMaskingEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type VolumeSliceInterpolationEdgeEffectsMaskingEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString VolumeSliceInterpolationEdgeEffectsMaskingEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const VolumeSliceInterpolationEdgeEffectsMaskingEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum VolumeSliceInterpolationEdgeEffectsMaskingEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = VolumeSliceInterpolationEdgeEffectsMaskingEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const VolumeSliceInterpolationEdgeEffectsMaskingEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type VolumeSliceInterpolationEdgeEffectsMaskingEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t VolumeSliceInterpolationEdgeEffectsMaskingEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const VolumeSliceInterpolationEdgeEffectsMaskingEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum VolumeSliceInterpolationEdgeEffectsMaskingEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = VolumeSliceInterpolationEdgeEffectsMaskingEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const VolumeSliceInterpolationEdgeEffectsMaskingEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type VolumeSliceInterpolationEdgeEffectsMaskingEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void VolumeSliceInterpolationEdgeEffectsMaskingEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void VolumeSliceInterpolationEdgeEffectsMaskingEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(VolumeSliceInterpolationEdgeEffectsMaskingEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void VolumeSliceInterpolationEdgeEffectsMaskingEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(VolumeSliceInterpolationEdgeEffectsMaskingEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Brain/VolumeSliceInterpolationEdgeEffectsMaskingEnum.h000066400000000000000000000070171360521144700310560ustar00rootroot00000000000000#ifndef __VOLUME_SLICE_INTERPOLATION_EDGE_EFFECTS_MASKING_ENUM_H__ #define __VOLUME_SLICE_INTERPOLATION_EDGE_EFFECTS_MASKING_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class VolumeSliceInterpolationEdgeEffectsMaskingEnum { public: /** * Enumerated values. */ enum Enum { /** Off */ OFF, /** Loose - Trilinear */ LOOSE, /** Tight - Enclosing Voxel */ TIGHT }; ~VolumeSliceInterpolationEdgeEffectsMaskingEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); static AString getToolTip(); private: VolumeSliceInterpolationEdgeEffectsMaskingEnum(const Enum enumValue, const AString& name, const AString& guiName); static const VolumeSliceInterpolationEdgeEffectsMaskingEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __VOLUME_SLICE_INTERPOLATION_EDGE_EFFECTS_MASKING_ENUM_DECLARE__ std::vector VolumeSliceInterpolationEdgeEffectsMaskingEnum::enumData; bool VolumeSliceInterpolationEdgeEffectsMaskingEnum::initializedFlag = false; int32_t VolumeSliceInterpolationEdgeEffectsMaskingEnum::integerCodeCounter = 0; #endif // __VOLUME_SLICE_INTERPOLATION_EDGE_EFFECTS_MASKING_ENUM_DECLARE__ } // namespace #endif //__VOLUME_SLICE_INTERPOLATION_EDGE_EFFECTS_MASKING_ENUM_H__ connectome-workbench-1.4.2/src/Brain/VolumeSliceSettings.cxx000066400000000000000000000710611360521144700241560ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __VOLUME_SLICE_SETTINGS_DECLARE__ #include "VolumeSliceSettings.h" #undef __VOLUME_SLICE_SETTINGS_DECLARE__ #include "CaretPreferences.h" #include "DeveloperFlagsEnum.h" #include "CaretLogger.h" #include "PlainTextStringBuilder.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "SceneEnumeratedType.h" #include "SessionManager.h" #include "VolumeFile.h" using namespace caret; /** * \class caret::VolumeSliceSettings * \brief Settings that control the display of volume slices. * \ingroup Brain */ const static VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum defaultVolumeSliceInterpolationEdgeMaskType = VolumeSliceInterpolationEdgeEffectsMaskingEnum::LOOSE; /** * Constructor. */ VolumeSliceSettings::VolumeSliceSettings() : CaretObject() { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); m_sliceViewPlane = VolumeSliceViewPlaneEnum::AXIAL; m_slicePlanesAllViewLayout = prefs->getVolumeAllSlicePlanesLayout(); m_sliceDrawingType = VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE; m_sliceProjectionType = VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL; m_volumeSliceInterpolationEdgeEffectsMaskingType = defaultVolumeSliceInterpolationEdgeMaskType; m_montageNumberOfColumns = 6; m_montageNumberOfRows = 4; m_montageSliceSpacing = 5; m_sliceCoordinateAxial = 0.0; m_sliceCoordinateCoronal = 0.0; m_sliceCoordinateParasagittal = 0.0; m_sliceEnabledAxial = true; m_sliceEnabledCoronal = true; m_sliceEnabledParasagittal = true; m_initializedFlag = false; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_sliceViewPlane", &m_sliceViewPlane); m_sceneAssistant->add("m_slicePlanesAllViewLayout", &m_slicePlanesAllViewLayout); m_sceneAssistant->add("m_sliceDrawingType", &m_sliceDrawingType); m_sceneAssistant->add("m_sliceProjectionType", &m_sliceProjectionType); m_sceneAssistant->add("m_volumeSliceInterpolationEdgeEffectsMaskingType", &m_volumeSliceInterpolationEdgeEffectsMaskingType); m_sceneAssistant->add("m_montageNumberOfColumns", &m_montageNumberOfColumns); m_sceneAssistant->add("m_montageNumberOfRows", &m_montageNumberOfRows); m_sceneAssistant->add("m_montageSliceSpacing", &m_montageSliceSpacing); m_sceneAssistant->add("m_sliceCoordinateAxial", &m_sliceCoordinateAxial); m_sceneAssistant->add("m_sliceCoordinateCoronal", &m_sliceCoordinateCoronal); m_sceneAssistant->add("m_sliceCoordinateParasagittal", &m_sliceCoordinateParasagittal); m_sceneAssistant->add("m_sliceEnabledAxial", &m_sliceEnabledAxial); m_sceneAssistant->add("m_sliceEnabledCoronal", &m_sliceEnabledCoronal); m_sceneAssistant->add("m_sliceEnabledParasagittal", &m_sliceEnabledParasagittal); } /** * Destructor. */ VolumeSliceSettings::~VolumeSliceSettings() { delete m_sceneAssistant; } /** * Copy constructor. * @param obj * Object that is copied. */ VolumeSliceSettings::VolumeSliceSettings(const VolumeSliceSettings& obj) : CaretObject(obj), SceneableInterface(obj) { this->copyHelperVolumeSliceSettings(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ VolumeSliceSettings& VolumeSliceSettings::operator=(const VolumeSliceSettings& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperVolumeSliceSettings(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void VolumeSliceSettings::copyHelperVolumeSliceSettings(const VolumeSliceSettings& obj) { m_sliceViewPlane = obj.m_sliceViewPlane; m_slicePlanesAllViewLayout = obj.m_slicePlanesAllViewLayout; m_sliceDrawingType = obj.m_sliceDrawingType; m_sliceProjectionType = obj.m_sliceProjectionType; m_volumeSliceInterpolationEdgeEffectsMaskingType = obj.m_volumeSliceInterpolationEdgeEffectsMaskingType; m_montageNumberOfColumns = obj.m_montageNumberOfColumns; m_montageNumberOfRows = obj.m_montageNumberOfRows; m_montageSliceSpacing = obj.m_montageSliceSpacing; m_sliceCoordinateParasagittal = obj.m_sliceCoordinateParasagittal; m_sliceCoordinateCoronal = obj.m_sliceCoordinateCoronal; m_sliceCoordinateAxial = obj.m_sliceCoordinateAxial; m_sliceEnabledParasagittal = obj.m_sliceEnabledParasagittal; m_sliceEnabledCoronal = obj.m_sliceEnabledCoronal; m_sliceEnabledAxial = obj.m_sliceEnabledAxial; m_initializedFlag = true; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString VolumeSliceSettings::toString() const { return "VolumeSliceSettings"; } /** * Get a text description of the instance's content. * * @param modelType * Type of model. * @param descriptionOut * Description of the instance's content. */ void VolumeSliceSettings::getDescriptionOfContent(const ModelTypeEnum::Enum modelType, PlainTextStringBuilder& descriptionOut) const { bool volumeFlag = false; bool wholeBrainFlag = false; switch (modelType) { case ModelTypeEnum::MODEL_TYPE_CHART: break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: break; case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: volumeFlag = true; break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: wholeBrainFlag = true; break; } bool showParasagittalCoordinate = false; bool showCoronalCoordinate = false; bool showAxialCoordinate = false; descriptionOut.addLine("Volume Slice Settings: "); descriptionOut.pushIndentation(); if (volumeFlag) { descriptionOut.addLine(" View Plane: " + VolumeSliceViewPlaneEnum::toGuiName(m_sliceViewPlane)); showParasagittalCoordinate = true; showCoronalCoordinate = true; showAxialCoordinate = true; } if (wholeBrainFlag) { if (m_sliceEnabledParasagittal) { showParasagittalCoordinate = true; } if (m_sliceEnabledCoronal) { showCoronalCoordinate = true; } if (m_sliceEnabledAxial) { showAxialCoordinate = true; } } if (showParasagittalCoordinate) { descriptionOut.addLine(" Parasagittal (X-axis) Coordinate: " + AString::number(m_sliceCoordinateParasagittal, 'f', 3)); } if (showCoronalCoordinate) { descriptionOut.addLine(" Coronal (Y-axis) Coordinate: " + AString::number(m_sliceCoordinateCoronal, 'f', 3)); } if (showAxialCoordinate) { descriptionOut.addLine(" Axial (Z-axis) Coordinate: " + AString::number(m_sliceCoordinateAxial, 'f', 3)); } descriptionOut.popIndentation(); } /** * @return The slice view plane. * */ VolumeSliceViewPlaneEnum::Enum VolumeSliceSettings::getSliceViewPlane() const { return m_sliceViewPlane; } /** * Set the slice view plane. * @param windowTabNumber * New value for slice plane. */ void VolumeSliceSettings::setSliceViewPlane(const VolumeSliceViewPlaneEnum::Enum slicePlane) { m_sliceViewPlane = slicePlane; } /** * @return The layout for all slices view (grid, row, column) */ VolumeSliceViewAllPlanesLayoutEnum::Enum VolumeSliceSettings::getSlicePlanesAllViewLayout() const { return m_slicePlanesAllViewLayout; } /** * Set the layout for all slices view (grid, row, column) * * @param slicePlanesAllViewLayout * New value for layout. */ void VolumeSliceSettings::setSlicePlanesAllViewLayout(const VolumeSliceViewAllPlanesLayoutEnum::Enum slicePlanesAllViewLayout) { m_slicePlanesAllViewLayout = slicePlanesAllViewLayout; } /** * @return Type of slice drawing (single/montage) */ VolumeSliceDrawingTypeEnum::Enum VolumeSliceSettings::getSliceDrawingType() const { return m_sliceDrawingType; } /** * Set type of slice drawing (single/montage) * * @param sliceDrawingType * New value for slice drawing type. */ void VolumeSliceSettings::setSliceDrawingType(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType) { m_sliceDrawingType = sliceDrawingType; } /** * @return The masking used when drawing an oblique volume slice */ VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum VolumeSliceSettings::getVolumeSliceInterpolationEdgeEffectsMaskingType() const { return m_volumeSliceInterpolationEdgeEffectsMaskingType; } /** * Set the masking used when drawing an oblique volume slice. * * @param maskingType * Type of masking. */ void VolumeSliceSettings::setVolumeSliceInterpolationEdgeEffectsMaskingType(const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum maskingType) { m_volumeSliceInterpolationEdgeEffectsMaskingType = maskingType; } /** * @return Type of slice projection (oblique/orthogonal) */ VolumeSliceProjectionTypeEnum::Enum VolumeSliceSettings::getSliceProjectionType() const { return m_sliceProjectionType; } /** * Set type of slice projection (oblique/orthogonal) * * @param sliceProjectionType * New value for slice projection type. */ void VolumeSliceSettings::setSliceProjectionType(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType) { m_sliceProjectionType = sliceProjectionType; } /** * @return the montage number of columns for the given window tab. */ int32_t VolumeSliceSettings::getMontageNumberOfColumns() const { return m_montageNumberOfColumns; } /** * Set the montage number of columns in the given window tab. * @param montageNumberOfColumns * New value for montage number of columns */ void VolumeSliceSettings::setMontageNumberOfColumns(const int32_t montageNumberOfColumns) { m_montageNumberOfColumns = montageNumberOfColumns; } /** * @return the montage number of rows for the given window tab. */ int32_t VolumeSliceSettings::getMontageNumberOfRows() const { return m_montageNumberOfRows; } /** * Set the montage number of rows. * @param montageNumberOfRows * New value for montage number of rows */ void VolumeSliceSettings::setMontageNumberOfRows(const int32_t montageNumberOfRows) { m_montageNumberOfRows = montageNumberOfRows; } /** * @return the montage slice spacing. */ int32_t VolumeSliceSettings::getMontageSliceSpacing() const { return m_montageSliceSpacing; } /** * Set the montage slice spacing. * @param montageSliceSpacing * New value for montage slice spacing */ void VolumeSliceSettings::setMontageSliceSpacing(const int32_t montageSliceSpacing) { m_montageSliceSpacing = montageSliceSpacing; } /** * Set the selected slices to the origin. */ void VolumeSliceSettings::setSlicesToOrigin() { selectSlicesAtOrigin(); } /** * Reset the slices. */ void VolumeSliceSettings::reset() { m_sliceCoordinateAxial = 0.0; m_sliceCoordinateCoronal = 0.0; m_sliceCoordinateParasagittal = 0.0; m_sliceEnabledAxial = true; m_sliceEnabledCoronal = true; m_sliceEnabledParasagittal = true; m_initializedFlag = false; } /** * Update the slices coordinates so that they are valid for * the given VolumeFile. * @param volumeFile * File for which slice coordinates are made valid. */ void VolumeSliceSettings::updateForVolumeFile(const VolumeMappableInterface* volumeFile) { if (volumeFile == NULL) { reset(); return; } if (m_initializedFlag == false) { m_initializedFlag = true; selectSlicesAtOrigin(); } /* * These calls will make the slices valid */ getSliceIndexParasagittal(volumeFile); getSliceIndexCoronal(volumeFile); getSliceIndexAxial(volumeFile); } /** * Set the slice indices so that they are at the origin. */ void VolumeSliceSettings::selectSlicesAtOrigin() { m_sliceCoordinateAxial = 0.0; m_sliceCoordinateCoronal = 0.0; m_sliceCoordinateParasagittal = 0.0; } /** * Set the selected slices to the given coordinate. * @param xyz * Coordinate for selected slices. */ void VolumeSliceSettings::selectSlicesAtCoordinate(const float xyz[3]) { m_sliceCoordinateParasagittal = xyz[0]; m_sliceCoordinateCoronal = xyz[1]; m_sliceCoordinateAxial = xyz[2]; } /** * Get the slices for a volume in any orientation. * * @param volumeInterface * Volume interface for file used for slices and orientations. * @param parasagittalIndexOut * Output containing parasagittal index. * @param coronalIndexOut * Output containing coronal index. * @param axialIndexOut * Output containing axial index. */ void VolumeSliceSettings::getSlicesParasagittalCoronalAxial(const VolumeMappableInterface* volumeInterface, int64_t& parasagittalIndexOut, int64_t& coronalIndexOut, int64_t& axialIndexOut) const { CaretAssert(volumeInterface); std::vector dimensions; volumeInterface->getDimensions(dimensions); if (dimensions[2] >= 0) { std::vector dimensions; volumeInterface->getDimensions(dimensions); /* * Valid voxel range in space */ float minXYZ[3]; volumeInterface->indexToSpace(0, 0, 0, minXYZ); float maxXYZ[3]; volumeInterface->indexToSpace(dimensions[0] - 1, dimensions[1] - 1, dimensions[2] - 1, maxXYZ); for (int32_t i = 0; i < 3; i++) { if (minXYZ[i] > maxXYZ[i]) { std::swap(minXYZ[i], maxXYZ[i]); } } /* * Limit selected slice coordinates to space */ float xyz[3] = { m_sliceCoordinateParasagittal, m_sliceCoordinateCoronal, m_sliceCoordinateAxial }; for (int32_t i = 0; i < 3; i++) { if (xyz[i] < minXYZ[i]) { xyz[i] = minXYZ[i]; } else if (xyz[i] > maxXYZ[i]) { xyz[i] = maxXYZ[i]; } } int64_t indices[3]; volumeInterface->enclosingVoxel(xyz[0], xyz[1], xyz[2], indices[0], indices[1], indices[2]); CaretAssert((indices[0] >= 0) && (indices[0] < dimensions[0])); CaretAssert((indices[1] >= 0) && (indices[1] < dimensions[1])); CaretAssert((indices[2] >= 0) && (indices[2] < dimensions[2])); parasagittalIndexOut = indices[0]; coronalIndexOut = indices[1]; axialIndexOut = indices[2]; { const VolumeSpace& volumeSpace = volumeInterface->getVolumeSpace(); if (volumeSpace.isPlumb()) { VolumeSpace::OrientTypes orient[3]; volumeSpace.getOrientation(orient); for (int32_t i = 0; i < 3; i++) { switch (orient[i]) { case VolumeSpace::ANTERIOR_TO_POSTERIOR: case VolumeSpace::POSTERIOR_TO_ANTERIOR: coronalIndexOut = indices[i]; break; case VolumeSpace::INFERIOR_TO_SUPERIOR: case VolumeSpace::SUPERIOR_TO_INFERIOR: axialIndexOut = indices[i]; break; case VolumeSpace::LEFT_TO_RIGHT: case VolumeSpace::RIGHT_TO_LEFT: parasagittalIndexOut = indices[i]; break; } } } } } else { parasagittalIndexOut = 0; coronalIndexOut = 0; axialIndexOut = 0; } } /** * Set the selected slices for volume with any orientation. Just one * slice can be set by using a negative value for the other slices. * * @param volumeInterface * Volume interface for file used for slices and orientations. * @param newParasagittalIndex * New parasagittal index (ignored if less than zero) * @param newCoronalIndex * New coronal index (ignored if less than zero) * @param newAxialIndex * New axial index (ignored if less than zero) */ void VolumeSliceSettings::setSlicesParasagittalCoronalAxial(const VolumeMappableInterface* volumeInterface, const int64_t newParasagittalIndex, const int64_t newCoronalIndex, const int64_t newAxialIndex) { int64_t parasagittalIndex, coronalIndex, axialIndex; getSlicesParasagittalCoronalAxial(volumeInterface, parasagittalIndex, coronalIndex, axialIndex); if (newParasagittalIndex >= 0) { parasagittalIndex = newParasagittalIndex; } if (newCoronalIndex >= 0) { coronalIndex = newCoronalIndex; } if (newAxialIndex >= 0) { axialIndex = newAxialIndex; } int64_t indices[3] = { parasagittalIndex, coronalIndex, axialIndex }; { const VolumeSpace& volumeSpace = volumeInterface->getVolumeSpace(); if (volumeSpace.isPlumb()) { VolumeSpace::OrientTypes orient[3]; volumeSpace.getOrientation(orient); for (int32_t i = 0; i < 3; i++) { switch (orient[i]) { case VolumeSpace::ANTERIOR_TO_POSTERIOR: case VolumeSpace::POSTERIOR_TO_ANTERIOR: indices[i] = coronalIndex; break; case VolumeSpace::INFERIOR_TO_SUPERIOR: case VolumeSpace::SUPERIOR_TO_INFERIOR: indices[i] = axialIndex; break; case VolumeSpace::LEFT_TO_RIGHT: case VolumeSpace::RIGHT_TO_LEFT: indices[i] = parasagittalIndex; break; } } } } std::vector dimensions; volumeInterface->getDimensions(dimensions); for (int32_t i = 0; i < 3; i++) { if (indices[i] < 0) { indices[i] = 0; } else if (indices[i] >= dimensions[i]) { indices[i] = dimensions[i] - 1; } } float xyz[3]; volumeInterface->indexToSpace(indices, xyz); selectSlicesAtCoordinate(xyz); } /** * Return the axial slice index. * @return * Axial slice index or negative if invalid */ int64_t VolumeSliceSettings::getSliceIndexAxial(const VolumeMappableInterface* volumeFile) const { int64_t paraIndex, coronalIndex, axialIndex; getSlicesParasagittalCoronalAxial(volumeFile, paraIndex, coronalIndex, axialIndex); return axialIndex; } /** * Set the axial slice index. * @param * New value for axial slice index. */ void VolumeSliceSettings::setSliceIndexAxial(const VolumeMappableInterface* volumeFile, const int64_t sliceIndexAxial) { setSlicesParasagittalCoronalAxial(volumeFile, -1, -1, sliceIndexAxial); } /** * Return the coronal slice index. * @return * Coronal slice index. */ int64_t VolumeSliceSettings::getSliceIndexCoronal(const VolumeMappableInterface* volumeFile) const { int64_t paraIndex, coronalIndex, axialIndex; getSlicesParasagittalCoronalAxial(volumeFile, paraIndex, coronalIndex, axialIndex); return coronalIndex; } /** * Set the coronal slice index. * @param sliceIndexCoronal * New value for coronal slice index. */ void VolumeSliceSettings::setSliceIndexCoronal(const VolumeMappableInterface* volumeFile, const int64_t sliceIndexCoronal) { setSlicesParasagittalCoronalAxial(volumeFile, -1, sliceIndexCoronal, -1); } /** * Return the parasagittal slice index. * @return * Parasagittal slice index. */ int64_t VolumeSliceSettings::getSliceIndexParasagittal(const VolumeMappableInterface* volumeFile) const { int64_t paraIndex, coronalIndex, axialIndex; getSlicesParasagittalCoronalAxial(volumeFile, paraIndex, coronalIndex, axialIndex); return paraIndex; } /** * Set the parasagittal slice index. * @param sliceIndexParasagittal * New value for parasagittal slice index. */ void VolumeSliceSettings::setSliceIndexParasagittal(const VolumeMappableInterface* volumeFile, const int64_t sliceIndexParasagittal) { setSlicesParasagittalCoronalAxial(volumeFile, sliceIndexParasagittal, -1, -1); } /** * @return Coordinate of axial slice. */ float VolumeSliceSettings::getSliceCoordinateAxial() const { return m_sliceCoordinateAxial; } /** * Set the coordinate for the axial slice. * @param z * Z-coordinate for axial slice. */ void VolumeSliceSettings::setSliceCoordinateAxial(const float z) { m_sliceCoordinateAxial = z; } /** * @return Coordinate of coronal slice. */ float VolumeSliceSettings::getSliceCoordinateCoronal() const { return m_sliceCoordinateCoronal; } /** * Set the coordinate for the coronal slice. * @param y * Y-coordinate for coronal slice. */ void VolumeSliceSettings::setSliceCoordinateCoronal(const float y) { m_sliceCoordinateCoronal = y; } /** * @return Coordinate of parasagittal slice. */ float VolumeSliceSettings::getSliceCoordinateParasagittal() const { return m_sliceCoordinateParasagittal; } /** * Set the coordinate for the parasagittal slice. * @param x * X-coordinate for parasagittal slice. */ void VolumeSliceSettings::setSliceCoordinateParasagittal(const float x) { m_sliceCoordinateParasagittal = x; } /** * Is the parasagittal slice enabled? * @return * Enabled status of parasagittal slice. */ bool VolumeSliceSettings::isSliceParasagittalEnabled() const { return m_sliceEnabledParasagittal; } /** * Set the enabled status of the parasagittal slice. * @param sliceEnabledParasagittal * New enabled status. */ void VolumeSliceSettings::setSliceParasagittalEnabled(const bool sliceEnabledParasagittal) { m_sliceEnabledParasagittal = sliceEnabledParasagittal; } /** * Is the coronal slice enabled? * @return * Enabled status of coronal slice. */ bool VolumeSliceSettings::isSliceCoronalEnabled() const { return m_sliceEnabledCoronal; } /** * Set the enabled status of the coronal slice. * @param sliceEnabledCoronal * New enabled status. */ void VolumeSliceSettings::setSliceCoronalEnabled(const bool sliceEnabledCoronal) { m_sliceEnabledCoronal = sliceEnabledCoronal; } /** * Is the axial slice enabled? * @return * Enabled status of axial slice. */ bool VolumeSliceSettings::isSliceAxialEnabled() const { return m_sliceEnabledAxial; } /** * Set the enabled status of the axial slice. * @param sliceEnabledAxial * New enabled status. */ void VolumeSliceSettings::setSliceAxialEnabled(const bool sliceEnabledAxial) { m_sliceEnabledAxial = sliceEnabledAxial; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* VolumeSliceSettings::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "VolumeSliceSettings", 2); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void VolumeSliceSettings::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } /* * Added in scene version 2 or later */ m_sliceDrawingType = VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE; m_sliceProjectionType = VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL; m_volumeSliceInterpolationEdgeEffectsMaskingType = defaultVolumeSliceInterpolationEdgeMaskType; m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); if (sceneClass->getVersionNumber() < 2) { /* * Set slice drawing type and projection type using old slice view mode. */ const AString oldViewModeValue = sceneClass->getEnumeratedTypeValueAsString("m_sliceViewMode"); if (! oldViewModeValue.isEmpty()) { if (oldViewModeValue == "MONTAGE") { m_sliceDrawingType = VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_MONTAGE; m_sliceProjectionType = VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL; } else if (oldViewModeValue == "OBLIQUE") { m_sliceDrawingType = VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE; m_sliceProjectionType = VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE; } else if (oldViewModeValue == "ORTHOGONAL") { m_sliceDrawingType = VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE; m_sliceProjectionType = VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL; } else { CaretLogWarning("Unrecognized value for old m_sliceViewMode: " + oldViewModeValue); } } } /* * For scenes before all view layout, use GRID so that the * older scenes display correctly */ if (sceneClass->getObjectWithName("m_slicePlanesAllViewLayout") == NULL) { m_slicePlanesAllViewLayout = VolumeSliceViewAllPlanesLayoutEnum::GRID_LAYOUT; } /* * Restoring scene initialize all members. * If this is not done, the slices will be reset * in updateForVolumeFile(). */ m_initializedFlag = true; } connectome-workbench-1.4.2/src/Brain/VolumeSliceSettings.h000066400000000000000000000177641360521144700236150ustar00rootroot00000000000000#ifndef __VOLUME_SLICE_SETTINGS_H__ #define __VOLUME_SLICE_SETTINGS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "ModelTypeEnum.h" #include "SceneableInterface.h" #include "VolumeSliceDrawingTypeEnum.h" #include "VolumeSliceInterpolationEdgeEffectsMaskingEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "VolumeSliceViewAllPlanesLayoutEnum.h" #include "VolumeSliceViewPlaneEnum.h" namespace caret { class PlainTextStringBuilder; class SceneClassAssistant; class VolumeMappableInterface; class VolumeSliceCoordinateSelection; class VolumeSliceSettings : public CaretObject, public SceneableInterface { public: VolumeSliceSettings(); virtual ~VolumeSliceSettings(); VolumeSliceSettings(const VolumeSliceSettings& obj); VolumeSliceSettings& operator=(const VolumeSliceSettings& obj); VolumeSliceViewPlaneEnum::Enum getSliceViewPlane() const; void setSliceViewPlane(VolumeSliceViewPlaneEnum::Enum sliceAxisMode); VolumeSliceViewAllPlanesLayoutEnum::Enum getSlicePlanesAllViewLayout() const; void setSlicePlanesAllViewLayout(const VolumeSliceViewAllPlanesLayoutEnum::Enum slicePlanesAllViewLayout); VolumeSliceDrawingTypeEnum::Enum getSliceDrawingType() const; void setSliceDrawingType(const VolumeSliceDrawingTypeEnum::Enum sliceDrawingType); VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum getVolumeSliceInterpolationEdgeEffectsMaskingType() const; void setVolumeSliceInterpolationEdgeEffectsMaskingType(const VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum maskingType); VolumeSliceProjectionTypeEnum::Enum getSliceProjectionType() const; void setSliceProjectionType(const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType); int32_t getMontageNumberOfColumns() const; void setMontageNumberOfColumns(const int32_t montageNumberOfColumns); int32_t getMontageNumberOfRows() const; void setMontageNumberOfRows(const int32_t montageNumberOfRows); int32_t getMontageSliceSpacing() const; void setMontageSliceSpacing(const int32_t montageSliceSpacing); VolumeSliceCoordinateSelection* getSelectedVolumeSlices(VolumeMappableInterface* underlayVolumeFile); const VolumeSliceCoordinateSelection* getSelectedVolumeSlices(VolumeMappableInterface* underlayVolumeFile) const; void setSlicesToOrigin(); void getSlicesParasagittalCoronalAxial(const VolumeMappableInterface* volumeInterface, int64_t& parasagittalIndexOut, int64_t& coronalIndexOut, int64_t& axialIndexOut) const; void setSlicesParasagittalCoronalAxial(const VolumeMappableInterface* volumeInterface, const int64_t newParasagittalIndex, const int64_t newCoronalIndex, const int64_t newAxialIndex); float getSliceCoordinateAxial() const; void setSliceCoordinateAxial(const float x); float getSliceCoordinateCoronal() const; void setSliceCoordinateCoronal(const float y); float getSliceCoordinateParasagittal() const; void setSliceCoordinateParasagittal(const float z); int64_t getSliceIndexAxial(const VolumeMappableInterface* volumeFile) const; void setSliceIndexAxial(const VolumeMappableInterface* volumeFile, const int64_t sliceIndexAxial); int64_t getSliceIndexCoronal(const VolumeMappableInterface* volumeFile) const; void setSliceIndexCoronal(const VolumeMappableInterface* volumeFile, const int64_t sliceIndexCoronal); int64_t getSliceIndexParasagittal(const VolumeMappableInterface* volumeFile) const; void setSliceIndexParasagittal(const VolumeMappableInterface* volumeFile, const int64_t sliceIndexParasagittal); bool isSliceParasagittalEnabled() const; void setSliceParasagittalEnabled(const bool sliceEnabledParasagittal); bool isSliceCoronalEnabled() const; void setSliceCoronalEnabled(const bool sliceEnabledCoronal); bool isSliceAxialEnabled() const; void setSliceAxialEnabled(const bool sliceEnabledAxial); void updateForVolumeFile(const VolumeMappableInterface* volumeFile); void selectSlicesAtOrigin(); void selectSlicesAtCoordinate(const float xyz[3]); void reset(); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual void getDescriptionOfContent(const ModelTypeEnum::Enum modelType, PlainTextStringBuilder& descriptionOut) const; private: void copyHelperVolumeSliceSettings(const VolumeSliceSettings& obj); // ADD_NEW_MEMBERS_HERE /** Axis of slice being viewed */ VolumeSliceViewPlaneEnum::Enum m_sliceViewPlane; /** Layout of slice in all slices view */ VolumeSliceViewAllPlanesLayoutEnum::Enum m_slicePlanesAllViewLayout; /** Type of slice drawing (single/montage) */ VolumeSliceDrawingTypeEnum::Enum m_sliceDrawingType; /** Type of masking for oblique slice drawing */ VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum m_volumeSliceInterpolationEdgeEffectsMaskingType; /** Type of slice projection (oblique/orthogonal) */ VolumeSliceProjectionTypeEnum::Enum m_sliceProjectionType; /** Number of montage rows */ int32_t m_montageNumberOfRows; /** Number of montage columns */ int32_t m_montageNumberOfColumns; /** Montage slice spacing */ int32_t m_montageSliceSpacing; mutable float m_sliceCoordinateParasagittal; mutable float m_sliceCoordinateCoronal; mutable float m_sliceCoordinateAxial; bool m_sliceEnabledParasagittal; bool m_sliceEnabledCoronal; bool m_sliceEnabledAxial; bool m_initializedFlag; //VolumeFile* m_lastVolumeFile; SceneClassAssistant* m_sceneAssistant; }; #ifdef __VOLUME_SLICE_SETTINGS_DECLARE__ // #endif // __VOLUME_SLICE_SETTINGS_DECLARE__ } // namespace #endif //__VOLUME_SLICE_SETTINGS_H__ connectome-workbench-1.4.2/src/Brain/VolumeSurfaceOutlineColorOrTabModel.cxx000066400000000000000000000376311360521144700272430ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __VOLUME_SURFACE_OUTLINE_COLOR_OR_TAB_MODEL_DECLARE__ #include "VolumeSurfaceOutlineColorOrTabModel.h" #undef __VOLUME_SURFACE_OUTLINE_COLOR_OR_TAB_MODEL_DECLARE__ #include "BrainConstants.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "EventBrowserTabGet.h" #include "EventManager.h" #include "SceneClass.h" using namespace caret; /** * \class caret::VolumeSurfaceOutlineColorOrTabModel * \brief Model for selection of Color or Tab for Surface Outline * * Allows selection of a color or a browser tab for volume surface * outline. If a color is selected, the surface outline is drawn * in that color. If a browser tab is selected, the surface outline * is drawn in the current coloring for the selected surface using * the coloring assigned to the surface in the selected browser tab. * * Note: Only valid browser tabs are available for selection. */ /** * Constructor. */ VolumeSurfaceOutlineColorOrTabModel::VolumeSurfaceOutlineColorOrTabModel() : CaretObject() { m_selectedItem = NULL; for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { Item* item = new Item(i); m_allItems.push_back(item); } std::vector allColors; CaretColorEnum::getColorEnums(allColors); for (std::vector::iterator iter = allColors.begin(); iter != allColors.end(); iter++) { Item* item = new Item(*iter); m_allItems.push_back(item); } for (std::vector::iterator iter = m_allItems.begin(); iter != m_allItems.end(); iter++) { Item* item = *iter; if (item->isValid()) { m_selectedItem = const_cast(item); break; } } } /** * Destructor. */ VolumeSurfaceOutlineColorOrTabModel::~VolumeSurfaceOutlineColorOrTabModel() { for (std::vector::iterator iter = m_allItems.begin(); iter != m_allItems.end(); iter++) { Item* item = *iter; delete item; } m_allItems.clear(); } /** * Copy the given volume surface outline color or tab model. * @param modelToCopy * Model that is copied. */ void VolumeSurfaceOutlineColorOrTabModel::copyVolumeSurfaceOutlineColorOrTabModel(VolumeSurfaceOutlineColorOrTabModel* modelToCopy) { Item* otherItem = modelToCopy->getSelectedItem(); switch (otherItem->getItemType()) { case VolumeSurfaceOutlineColorOrTabModel::Item::ITEM_TYPE_COLOR: setColor(otherItem->getColor()); break; case VolumeSurfaceOutlineColorOrTabModel::Item::ITEM_TYPE_BROWSER_TAB: setBrowserTabIndex(otherItem->getBrowserTabIndex()); break; } } /** * @return All of the valid items for this model. */ std::vector VolumeSurfaceOutlineColorOrTabModel::getValidItems() { std::vector items; /* * Return all valid items */ for (std::vector::iterator iter = m_allItems.begin(); iter != m_allItems.end(); iter++) { Item* item = *iter; if (item->isValid()) { items.push_back(item); } } return items; } /** * @return Pointer to selected item (NULL if selection * is invalid. */ VolumeSurfaceOutlineColorOrTabModel::Item* VolumeSurfaceOutlineColorOrTabModel::getSelectedItem() { const int32_t numItems = static_cast(m_allItems.size()); /* * Make sure selected item is valid */ int32_t itemIndex = -1; if (m_selectedItem != NULL) { for (int32_t i = 0; i < numItems; i++) { if (m_allItems[i] == m_selectedItem) { if (m_allItems[i]->isValid() == false) { /* * Selected item is invalid */ m_selectedItem = NULL; } itemIndex = i; break; } } } if (m_selectedItem == NULL) { /* * Choose the previous valid item */ if (itemIndex >= 0) { for (int iBack = (itemIndex - 1); iBack >= 0; iBack--) { if (m_allItems[iBack]->isValid()) { m_selectedItem = m_allItems[iBack]; break; } } } if (m_selectedItem == NULL) { /* * Choose first valid item */ for (int i = 0; i < numItems; i++) { if (m_allItems[i]->isValid()) { m_selectedItem = m_allItems[i]; break; } } } } return m_selectedItem; } /** * Set the selected item. * @param item * New selected item. */ void VolumeSurfaceOutlineColorOrTabModel::setSelectedItem(const Item* item) { std::vector allItems = getValidItems(); const int32_t numItems = static_cast(allItems.size()); for (int32_t i = 0; i < numItems; i++) { if (item->equals(*allItems[i])) { m_selectedItem = allItems[i]; break; } } } /** * Set the selection to the given color. * @param color * Color that is to be selected. */ void VolumeSurfaceOutlineColorOrTabModel::setColor(const CaretColorEnum::Enum color) { std::vector allItems = getValidItems(); const int32_t numItems = static_cast(allItems.size()); for (int32_t i = 0; i < numItems; i++) { if (allItems[i]->getItemType() == Item::ITEM_TYPE_COLOR) { if (allItems[i]->getColor() == color) { setSelectedItem(allItems[i]); break; } } } } /** * Set the selection to the given browser tab. * @param browserTabIndex * Index of browser tab for selection. */ void VolumeSurfaceOutlineColorOrTabModel::setBrowserTabIndex(const int32_t browserTabIndex) { std::vector allItems = getValidItems(); const int32_t numItems = static_cast(allItems.size()); for (int32_t i = 0; i < numItems; i++) { if (allItems[i]->getItemType() == Item::ITEM_TYPE_BROWSER_TAB) { if (allItems[i]->getBrowserTabIndex() == browserTabIndex) { setSelectedItem(allItems[i]); break; } } } } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* VolumeSurfaceOutlineColorOrTabModel::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "VolumeSurfaceOutlineColorOrTabModel", 1); if (m_selectedItem != NULL) { sceneClass->addChild(m_selectedItem->saveToScene(sceneAttributes, "m_selectedItem")); } return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void VolumeSurfaceOutlineColorOrTabModel::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } Item item(0); item.restoreFromScene(sceneAttributes, sceneClass->getClass("m_selectedItem")); setSelectedItem(&item); } //====================================================================== /** * \class caret::VolumeSurfaceOutlineColorOrTabModel::Item * \brief An item in VolumeSurfaceOutlineColorOrTabModel. * * At this time, item is either a color or a browser * tab index. */ /** * Constructor for a Caret Color. * @param color * The caret color. */ VolumeSurfaceOutlineColorOrTabModel::Item::Item(const CaretColorEnum::Enum color) { m_color = color; m_browserTabIndex = 0; m_itemType = ITEM_TYPE_COLOR; } /** * Constructor for a browser tab. * @param browserTabIndex * Index of browser tab. */ VolumeSurfaceOutlineColorOrTabModel::Item::Item(const int32_t browserTabIndex) { m_color = CaretColorEnum::BLACK; m_browserTabIndex = browserTabIndex; m_itemType = ITEM_TYPE_BROWSER_TAB; } /** * Destructor. */ VolumeSurfaceOutlineColorOrTabModel::Item::~Item() { } /** * Copy constructor. * * @param * Item that is copied. */ VolumeSurfaceOutlineColorOrTabModel::Item::Item(const Item& item) : SceneableInterface(item) { m_color = item.m_color; m_browserTabIndex = item.m_browserTabIndex; m_itemType = item.m_itemType; } /** * Is this item equal to another item? * * @param item * Item for comparison. * @return * True if items are equal, else false. */ bool VolumeSurfaceOutlineColorOrTabModel::Item::equals(const Item& item) const { if (m_itemType == item.m_itemType) { switch (m_itemType) { case ITEM_TYPE_BROWSER_TAB: if (m_browserTabIndex == item.m_browserTabIndex) { return true; } break; case ITEM_TYPE_COLOR: if (m_color == item.m_color) { return true; } break; } } return false; } /** * @return Is this item valid? */ bool VolumeSurfaceOutlineColorOrTabModel::Item::isValid() const { bool valid = false; switch (m_itemType) { case ITEM_TYPE_BROWSER_TAB: if (getBrowserTabContent() != NULL) { valid = true; } break; case ITEM_TYPE_COLOR: valid = true; break; } return valid; } /** * @return Name of this item. */ AString VolumeSurfaceOutlineColorOrTabModel::Item::getName() { AString name = "PROGRAM ERROR"; switch(m_itemType) { case ITEM_TYPE_BROWSER_TAB: { // BrowserTabContent* btc = getBrowserTabContent(); // if (btc != NULL) { // name = ("Tab " // + AString::number(btc->getTabNumber() + 1)); // } name = ("Tab " + AString::number(m_browserTabIndex + 1)); } break; case ITEM_TYPE_COLOR: name = CaretColorEnum::toGuiName(m_color); break; } return name; } /** * @return Type of item. */ VolumeSurfaceOutlineColorOrTabModel::Item::ItemType VolumeSurfaceOutlineColorOrTabModel::Item::getItemType() const { return m_itemType; } /** * @return Pointer to browser tab in this item or NULL * if this item does NOT contain a browser tab. */ BrowserTabContent* VolumeSurfaceOutlineColorOrTabModel::Item::getBrowserTabContent() { EventBrowserTabGet getTabEvent(m_browserTabIndex); EventManager::get()->sendEvent(getTabEvent.getPointer()); BrowserTabContent* tabContent = getTabEvent.getBrowserTab(); return tabContent; } /** * @return Pointer to browser tab in this item or NULL * if this item does NOT contain a browser tab. */ const BrowserTabContent* VolumeSurfaceOutlineColorOrTabModel::Item::getBrowserTabContent() const { EventBrowserTabGet getTabEvent(m_browserTabIndex); EventManager::get()->sendEvent(getTabEvent.getPointer()); BrowserTabContent* tabContent = getTabEvent.getBrowserTab(); return tabContent; } /** * @return Index of browser tab in this item. This will always * return an integer greater than or equal to zero. Use isItemValid() * to ensure this item is valid. */ int32_t VolumeSurfaceOutlineColorOrTabModel::Item::getBrowserTabIndex() const { return m_browserTabIndex; } /** * @return Enumerated type for color in this item. Returned * value is undefined if a color is NOT in this item. */ CaretColorEnum::Enum VolumeSurfaceOutlineColorOrTabModel::Item::getColor() { return m_color; } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* VolumeSurfaceOutlineColorOrTabModel::Item::saveToScene(const SceneAttributes* /*sceneAttributes*/, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "VolumeSurfaceOutlineColorOrTabModel::Item", 1); sceneClass->addInteger("m_browserTabIndex", m_browserTabIndex); sceneClass->addEnumeratedType("m_color", m_color); switch (m_itemType) { case ITEM_TYPE_COLOR: sceneClass->addString("m_itemType", "ITEM_TYPE_COLOR"); break; case ITEM_TYPE_BROWSER_TAB: sceneClass->addString("m_itemType", "ITEM_TYPE_BROWSER_TAB"); break; } return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void VolumeSurfaceOutlineColorOrTabModel::Item::restoreFromScene(const SceneAttributes* /*sceneAttributes*/, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_browserTabIndex = sceneClass->getIntegerValue("m_browserTabIndex"); m_color = sceneClass->getEnumeratedTypeValue("m_color", CaretColorEnum::BLUE); const AString itemTypeName = sceneClass->getStringValue("m_itemType", "ITEM_TYPE_COLOR"); if (itemTypeName == "ITEM_TYPE_BROWSER_TAB") { m_itemType = ITEM_TYPE_BROWSER_TAB; } else if (itemTypeName == "ITEM_TYPE_COLOR") { m_itemType = ITEM_TYPE_COLOR; } else { CaretAssert(0); } } connectome-workbench-1.4.2/src/Brain/VolumeSurfaceOutlineColorOrTabModel.h000066400000000000000000000101041360521144700266520ustar00rootroot00000000000000#ifndef __VOLUME_SURFACE_OUTLINE_COLOR_OR_TAB_MODEL__H_ #define __VOLUME_SURFACE_OUTLINE_COLOR_OR_TAB_MODEL__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "CaretColorEnum.h" #include "CaretObject.h" #include "SceneableInterface.h" namespace caret { class BrowserTabContent; class SceneAttributes; class VolumeSurfaceOutlineColorOrTabModel : public CaretObject, public SceneableInterface { public: class Item : public SceneableInterface { public: /** * Type of item. */ enum ItemType { /** Item is a browser tab */ ITEM_TYPE_BROWSER_TAB, /** Item is a color */ ITEM_TYPE_COLOR }; Item(const CaretColorEnum::Enum color); Item(const int32_t browserTabIndex); Item(const Item& item); ~Item(); bool isValid() const; bool equals(const Item& item) const; AString getName(); ItemType getItemType() const; BrowserTabContent* getBrowserTabContent(); const BrowserTabContent* getBrowserTabContent() const; int32_t getBrowserTabIndex() const; CaretColorEnum::Enum getColor(); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: int32_t m_browserTabIndex; CaretColorEnum::Enum m_color; ItemType m_itemType; }; public: VolumeSurfaceOutlineColorOrTabModel(); virtual ~VolumeSurfaceOutlineColorOrTabModel(); std::vector getValidItems(); void copyVolumeSurfaceOutlineColorOrTabModel(VolumeSurfaceOutlineColorOrTabModel* modelToCopy); Item* getSelectedItem(); void setSelectedItem(const Item* item); void setColor(const CaretColorEnum::Enum color); void setBrowserTabIndex(const int32_t browserTabIndex); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: VolumeSurfaceOutlineColorOrTabModel(const VolumeSurfaceOutlineColorOrTabModel&); VolumeSurfaceOutlineColorOrTabModel& operator=(const VolumeSurfaceOutlineColorOrTabModel&); std::vector m_allItems; Item* m_selectedItem; }; #ifdef __VOLUME_SURFACE_OUTLINE_COLOR_OR_TAB_MODEL_DECLARE__ // #endif // __VOLUME_SURFACE_OUTLINE_COLOR_OR_TAB_MODEL_DECLARE__ } // namespace #endif //__VOLUME_SURFACE_OUTLINE_COLOR_OR_TAB_MODEL__H_ connectome-workbench-1.4.2/src/Brain/VolumeSurfaceOutlineModel.cxx000066400000000000000000000325601360521144700253100ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __VOLUME_SURFACE_OUTLINE_MODEL_DECLARE__ #include "VolumeSurfaceOutlineModel.h" #undef __VOLUME_SURFACE_OUTLINE_MODEL_DECLARE__ #include "EventManager.h" #include "EventSurfaceColoringInvalidate.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "SurfaceSelectionModel.h" #include "SurfaceTypeEnum.h" #include "VolumeMappableInterface.h" #include "VolumeSurfaceOutlineColorOrTabModel.h" #include "VolumeSurfaceOutlineModelCacheValue.h" using namespace caret; static const bool debugFlag(false); /** * \class VolumeSurfaceOutlineSelection * \brief Controls display of a volume surface outline. * * Controls display of a volume surface outline. */ /** * Constructor. */ VolumeSurfaceOutlineModel::VolumeSurfaceOutlineModel() : CaretObject() { std::vector validSurfaceTypes; validSurfaceTypes.push_back(SurfaceTypeEnum::ANATOMICAL); validSurfaceTypes.push_back(SurfaceTypeEnum::RECONSTRUCTION); validSurfaceTypes.push_back(SurfaceTypeEnum::INFLATED); validSurfaceTypes.push_back(SurfaceTypeEnum::VERY_INFLATED); m_displayed = false; m_thicknessPixelsObsolete = VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE; m_surfaceSelectionModel = new SurfaceSelectionModel(validSurfaceTypes); m_colorOrTabModel = new VolumeSurfaceOutlineColorOrTabModel(); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_displayed", &m_displayed); m_sceneAssistant->add("m_thickness", &m_thicknessPixelsObsolete); // NOTE: "m_thickness" is OLD name m_sceneAssistant->add("m_surfaceSelectionModel", "SurfaceSelectionModel", m_surfaceSelectionModel); m_sceneAssistant->add("m_colorOrTabModel", "VolumeSurfaceOutlineColorOrTabModel", m_colorOrTabModel); /* * Percentage viewport height thickness was added in Feb 2, 2017. * So, we set the perentage thickness to -1.0f so that when an older * scene is restored, the value will be -1.0f. The code that draws * the volume surface outline see this negative value and convert * the old pixel thickness to this new percentage thickness. * After adding to the scene assistant, default the percentage thickness. */ m_thicknessPercentageViewportHeight = -1.0f; m_sceneAssistant->add("m_thicknessPercentageViewportHeight", &m_thicknessPercentageViewportHeight); m_thicknessPercentageViewportHeight = VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PERCENTAGE_VIEWPORT_HEIGHT; EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_SURFACE_COLORING_INVALIDATE); } /** * Destructor. */ VolumeSurfaceOutlineModel::~VolumeSurfaceOutlineModel() { clearOutlineCache(); delete m_surfaceSelectionModel; delete m_colorOrTabModel; delete m_sceneAssistant; EventManager::get()->removeAllEventsFromListener(this); } /** * Copy the given volume surface outline model to this model. * @param modelToCopy * Model that is copied. */ void VolumeSurfaceOutlineModel::copyVolumeSurfaceOutlineModel(VolumeSurfaceOutlineModel* modelToCopy) { m_displayed = modelToCopy->m_displayed; m_thicknessPixelsObsolete = modelToCopy->m_thicknessPixelsObsolete; m_thicknessPercentageViewportHeight = modelToCopy->m_thicknessPercentageViewportHeight; m_surfaceSelectionModel->setSurface(modelToCopy->getSurface()); VolumeSurfaceOutlineColorOrTabModel* colorTabToCopy = modelToCopy->getColorOrTabModel(); m_colorOrTabModel->copyVolumeSurfaceOutlineColorOrTabModel(colorTabToCopy); clearOutlineCache(); } /** * Receive an event. * * @param event * The event that the receive can respond to. */ void VolumeSurfaceOutlineModel::receiveEvent(Event* event) { CaretAssert(event); if (event->getEventType() == EventTypeEnum::EVENT_SURFACE_COLORING_INVALIDATE) { EventSurfaceColoringInvalidate* colorEvent = dynamic_cast(event); CaretAssert(colorEvent); colorEvent->setEventProcessed(); clearOutlineCache(); } } /** * Get a description of this object's content. * @return String describing this object's content. */ AString VolumeSurfaceOutlineModel::toString() const { return "VolumeSurfaceOutlineSelection"; } /** * @return Is this surface outline displayed? */ bool VolumeSurfaceOutlineModel::isDisplayed() const { return m_displayed; } /** * Set the display status of the surface outline. * @param displayed * New display status. */ void VolumeSurfaceOutlineModel::setDisplayed(const bool displayed) { m_displayed = displayed; if ( ! m_displayed) { clearOutlineCache(); } } /** * @return Thickness for drawing surface outline */ float VolumeSurfaceOutlineModel::getThicknessPercentageViewportHeight() const { return m_thicknessPercentageViewportHeight; } /** * Set the thickness for drawing surface outline */ void VolumeSurfaceOutlineModel::setThicknessPercentageViewportHeight(const float thickness) { m_thicknessPercentageViewportHeight = thickness; } /** * @return Thickness for drawing surface (OBSOLETE) */ float VolumeSurfaceOutlineModel::getThicknessPixelsObsolete() const { return m_thicknessPixelsObsolete; } /** * Set the thickness for drawing the surface (OBSOLETE) * @param thickness * New value for thickness. */ void VolumeSurfaceOutlineModel::setThicknessPixelsObsolete(const float thickness) { m_thicknessPixelsObsolete = thickness; } /** * @return The surface selector used to select the surface. */ SurfaceSelectionModel* VolumeSurfaceOutlineModel::getSurfaceSelectionModel() { return m_surfaceSelectionModel; } /** * @return Get the selected surface. */ const Surface* VolumeSurfaceOutlineModel::getSurface() const { return m_surfaceSelectionModel->getSurface(); } /** * @return Get the selected surface. */ Surface* VolumeSurfaceOutlineModel::getSurface() { return m_surfaceSelectionModel->getSurface(); } /** * @return The model for color or tab selection. */ VolumeSurfaceOutlineColorOrTabModel* VolumeSurfaceOutlineModel::getColorOrTabModel() { return m_colorOrTabModel; } /** * @return The model for color or tab selection. */ const VolumeSurfaceOutlineColorOrTabModel* VolumeSurfaceOutlineModel::getColorOrTabModel() const { return m_colorOrTabModel; } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* VolumeSurfaceOutlineModel::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "VolumeSurfaceOutlineModel", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void VolumeSurfaceOutlineModel::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } clearOutlineCache(); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } /** * Set the outline primitives for the given cache key * * @param key * Key into the outline cache identifying axis and slice * @param primitivesOut * Input containing the primitives */ void VolumeSurfaceOutlineModel::setOutlineCachePrimitives(const VolumeMappableInterface* underlayVolume, const VolumeSurfaceOutlineModelCacheKey& key, const std::vector& primitives) { auto iter = m_outlineCache.find(key); if (iter != m_outlineCache.end()) { iter->second->setGraphicsPrimitive(primitives); return; } if (m_outlineCache.empty()) { m_outlineCacheInfo.update(this, underlayVolume); } if (debugFlag) { std::cout << "Adding " << key.toString() << std::endl; } VolumeSurfaceOutlineModelCacheValue* value = new VolumeSurfaceOutlineModelCacheValue(); value->setGraphicsPrimitive(primitives); m_outlineCache.insert(std::make_pair(key, value)); } /** * Get the outline primitives for the given cache key * * @param underlayVolume * The underlay volume * @param key * Key into the outline cache identifying axis and slice * @param primitivesOut * Output containing the primitives * @return * Truie if outline primitives valid, else false. */ bool VolumeSurfaceOutlineModel::getOutlineCachePrimitives(const VolumeMappableInterface* underlayVolume, const VolumeSurfaceOutlineModelCacheKey& key, std::vector& primitivesOut) { if ( ! m_outlineCacheInfo.isValid(this, underlayVolume)) { clearOutlineCache(); } auto iter = m_outlineCache.find(key); if (iter != m_outlineCache.end()) { primitivesOut = iter->second->getGraphicsPrimitives(); if (debugFlag) { std::cout << "Found " << iter->first.toString() << std::endl; } return true; } return false; } /** * Clear the outline cache */ void VolumeSurfaceOutlineModel::clearOutlineCache() { if (debugFlag) { if ( ! m_outlineCache.empty()) { std::cout << "Invalidating non-empty surface outline cache" << std::endl; } } m_outlineCacheInfo.clear(); for (auto iter : m_outlineCache) { delete iter.second; } m_outlineCache.clear(); } /* ==========================================================================================*/ /** * Constructor for outline cache */ VolumeSurfaceOutlineModel::OutlineCacheInfo::OutlineCacheInfo() { clear(); } /** * Destructor */ VolumeSurfaceOutlineModel::OutlineCacheInfo::~OutlineCacheInfo() { clear(); } /** * Clear the outline cache */ void VolumeSurfaceOutlineModel::OutlineCacheInfo::clear() { m_surface = NULL; m_thicknessPercentageViewportHeight = -1.0; m_colorItem.reset(); } /** * Is the outline cache valid? * * @param surfaceOutlineModel * The parent surface outline model * @param underlayVolume * The underlay volume * @return * True if cache is valid, else false */ bool VolumeSurfaceOutlineModel::OutlineCacheInfo::isValid(VolumeSurfaceOutlineModel* surfaceOutlineModel, const VolumeMappableInterface* underlayVolume) { bool validFlag(false); if (m_surface != NULL) { if ((m_surface == surfaceOutlineModel->getSurface()) && (m_underlayVolume == underlayVolume) && (m_thicknessPercentageViewportHeight == surfaceOutlineModel->getThicknessPercentageViewportHeight())) { if (m_colorItem != NULL) { if (m_colorItem->equals(*(surfaceOutlineModel->getColorOrTabModel()->getSelectedItem()))) { validFlag = true; } } } } return validFlag; } /** * Update the cache info from the parent surface outline model * * @param surfaceOutlineModel * The surface outline model * @param underlayVolume * The underlay volume */ void VolumeSurfaceOutlineModel::OutlineCacheInfo::update(VolumeSurfaceOutlineModel* surfaceOutlineModel, const VolumeMappableInterface* underlayVolume) { m_underlayVolume = underlayVolume; m_surface = surfaceOutlineModel->getSurface(); m_thicknessPercentageViewportHeight = surfaceOutlineModel->getThicknessPercentageViewportHeight(); m_colorItem.reset(new VolumeSurfaceOutlineColorOrTabModel::Item(*(surfaceOutlineModel->getColorOrTabModel()->getSelectedItem()))); } connectome-workbench-1.4.2/src/Brain/VolumeSurfaceOutlineModel.h000066400000000000000000000133111360521144700247260ustar00rootroot00000000000000#ifndef __VOLUME_SURFACE_OUTLINE_MODEL__H_ #define __VOLUME_SURFACE_OUTLINE_MODEL__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" #include "VolumeSurfaceOutlineColorOrTabModel.h" #include "VolumeSurfaceOutlineModelCacheKey.h" namespace caret { class GraphicsPrimitive; class Surface; class SceneAttributes; class SceneClassAssistant; class SurfaceSelectionModel; class VolumeMappableInterface; class VolumeSurfaceOutlineModelCacheValue; class VolumeSurfaceOutlineModel : public CaretObject, public EventListenerInterface, public SceneableInterface { public: VolumeSurfaceOutlineModel(); virtual ~VolumeSurfaceOutlineModel(); void copyVolumeSurfaceOutlineModel(VolumeSurfaceOutlineModel* modelToCopy); virtual void receiveEvent(Event* event) override; bool isDisplayed() const; void setDisplayed(const bool displayed); float getThicknessPercentageViewportHeight() const; void setThicknessPercentageViewportHeight(const float thickness); float getThicknessPixelsObsolete() const; void setThicknessPixelsObsolete(const float thickness); SurfaceSelectionModel* getSurfaceSelectionModel(); const Surface* getSurface() const; Surface* getSurface(); VolumeSurfaceOutlineColorOrTabModel* getColorOrTabModel(); const VolumeSurfaceOutlineColorOrTabModel* getColorOrTabModel() const; void setOutlineCachePrimitives(const VolumeMappableInterface* underlayVolume, const VolumeSurfaceOutlineModelCacheKey& key, const std::vector& primitives); bool getOutlineCachePrimitives(const VolumeMappableInterface* underlayVolume, const VolumeSurfaceOutlineModelCacheKey& key, std::vector& primitivesOut); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); static const float DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE; static const float DEFAULT_LINE_THICKNESS_PERCENTAGE_VIEWPORT_HEIGHT; private: VolumeSurfaceOutlineModel(const VolumeSurfaceOutlineModel&); VolumeSurfaceOutlineModel& operator=(const VolumeSurfaceOutlineModel&); public: virtual AString toString() const; private: void clearOutlineCache(); bool m_displayed; float m_thicknessPixelsObsolete; float m_thicknessPercentageViewportHeight; SurfaceSelectionModel* m_surfaceSelectionModel; VolumeSurfaceOutlineColorOrTabModel* m_colorOrTabModel; SceneClassAssistant* m_sceneAssistant; class OutlineCacheInfo { public: OutlineCacheInfo(); ~OutlineCacheInfo(); void clear(); bool isValid(VolumeSurfaceOutlineModel* surfaceOutlineModel, const VolumeMappableInterface* underlayVolume); void update(VolumeSurfaceOutlineModel* surfaceOutlineModel, const VolumeMappableInterface* underlayVolume); /** The underlay volume */ const VolumeMappableInterface* m_underlayVolume; /** Thickness when first outline is added to outline cache */ float m_thicknessPercentageViewportHeight = -1.0; /** Surface when first outline is added to outline cache */ Surface* m_surface = NULL; /** Color Or Tab selection item when first outline is added to cache */ std::unique_ptr m_colorItem; }; /** info about outline cache that tracks validity of cache */ OutlineCacheInfo m_outlineCacheInfo; /** Cache for volume surface outlines */ std::map m_outlineCache; }; #ifdef __VOLUME_SURFACE_OUTLINE_MODEL_DECLARE__ const float VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE = 2.0f; const float VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PERCENTAGE_VIEWPORT_HEIGHT = 0.4f; #endif // __VOLUME_SURFACE_OUTLINE_MODEL_DECLARE__ } // namespace #endif //__VOLUME_SURFACE_OUTLINE_MODEL__H_ connectome-workbench-1.4.2/src/Brain/VolumeSurfaceOutlineModelCacheKey.cxx000066400000000000000000000234161360521144700267050ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_KEY_DECLARE__ #include "VolumeSurfaceOutlineModelCacheKey.h" #undef __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_KEY_DECLARE__ #include #include "CaretAssert.h" #include "Plane.h" #include "VolumeMappableInterface.h" using namespace caret; /** * \class caret::VolumeSurfaceOutlineModelCacheKey * \brief Key for a cached volume surface outline model * \ingroup Brain */ /** * Constructor. * * @param underlayVolume * The underlay volume * @param sliceViewPlane * The orthogonal slice view plane * @param sliceCoordinate * Coordinate of slice in orthogonal view plane */ VolumeSurfaceOutlineModelCacheKey::VolumeSurfaceOutlineModelCacheKey(const VolumeMappableInterface* underlayVolume, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinate) : CaretObject(), m_mode(Mode::SLICE_VIEW_PLANE), m_sliceViewPlane(sliceViewPlane) { const float scaleFactor = computeScaleFactor(underlayVolume); m_sliceCoordinateScaled = static_cast(sliceCoordinate * scaleFactor); // CaretAssert(underlayVolume); // if (underlayVolume != NULL) { // float voxelSizesMM[3]; // underlayVolume->getVoxelSpacing(voxelSizesMM[0], // voxelSizesMM[1], // voxelSizesMM[2]); // // float voxelSize(0.0); // switch (sliceViewPlane) { // case VolumeSliceViewPlaneEnum::ALL: // voxelSize = voxelSizesMM[2]; // break; // case VolumeSliceViewPlaneEnum::AXIAL: // voxelSize = voxelSizesMM[2]; // break; // case VolumeSliceViewPlaneEnum::CORONAL: // voxelSize = voxelSizesMM[1]; // break; // case VolumeSliceViewPlaneEnum::PARASAGITTAL: // voxelSize = voxelSizesMM[0]; // break; // } // // if (voxelSize > 0.0) { // /* // * The coordinate for the slice is stored as an integer since // * since integer comparison is precise oppposed to a float comparison // * that requires some sort of tolerance. // * // * (1.0 / voxelSize) is used so that the scale factor will // * be larger for small voxels and prevent an outline from // * being used by adjacent volume slices // */ // const float scaleFactor = 10.0 * (1.0 / voxelSize); // m_sliceCoordinateScaled = static_cast(std::round(sliceCoordinate * scaleFactor)); // } // } } /** * Constructor. * * @param underlayVolume * The underlay volume * @param sliceViewPlane * The orthogonal slice view plane * @param sliceCoordinate * Coordinate of slice in orthogonal view plane */ VolumeSurfaceOutlineModelCacheKey::VolumeSurfaceOutlineModelCacheKey(const VolumeMappableInterface* underlayVolume, const Plane& plane) : m_mode(Mode::PLANE_EQUATION) { CaretAssert(underlayVolume); if (underlayVolume != NULL) { const float scaleFactor = computeScaleFactor(underlayVolume); double a, b, c, d; plane.getPlane(a, b, c, d); m_planeEquationScaled[0] = scaleFactor * a; m_planeEquationScaled[1] = scaleFactor * b; m_planeEquationScaled[2] = scaleFactor * c; m_planeEquationScaled[3] = scaleFactor * d; } } /** * Compute the scale that is used to scale float values into integers * * @param underlayVolume * The underlay volume whose voxel sizes are used to determine the scale factor * @return The scale factor */ float VolumeSurfaceOutlineModelCacheKey::computeScaleFactor(const VolumeMappableInterface* underlayVolume) const { float scaleFactor(10.0); if (underlayVolume != NULL) { float voxelSizesMM[3]; underlayVolume->getVoxelSpacing(voxelSizesMM[0], voxelSizesMM[1], voxelSizesMM[2]); const float voxelSize = std::min(std::min(voxelSizesMM[0], voxelSizesMM[1]), voxelSizesMM[2]); if (voxelSize > 0.0) { /* * The coordinate for the slice is stored as an integer since * since integer comparison is precise oppposed to a float comparison * that requires some sort of tolerance. * * (1.0 / voxelSize) is used so that the scale factor will * be larger for small voxels and prevent an outline from * being used by adjacent volume slices */ scaleFactor = 10.0 * (1.0 / voxelSize); } } return scaleFactor; } /** * Destructor. */ VolumeSurfaceOutlineModelCacheKey::~VolumeSurfaceOutlineModelCacheKey() { } /** * Copy constructor. * @param obj * Object that is copied. */ VolumeSurfaceOutlineModelCacheKey::VolumeSurfaceOutlineModelCacheKey(const VolumeSurfaceOutlineModelCacheKey& obj) : CaretObject(obj) { this->copyHelperVolumeSurfaceOutlineModelCacheKey(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ VolumeSurfaceOutlineModelCacheKey& VolumeSurfaceOutlineModelCacheKey::operator=(const VolumeSurfaceOutlineModelCacheKey& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperVolumeSurfaceOutlineModelCacheKey(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void VolumeSurfaceOutlineModelCacheKey::copyHelperVolumeSurfaceOutlineModelCacheKey(const VolumeSurfaceOutlineModelCacheKey& obj) { m_mode = obj.m_mode; m_sliceViewPlane = obj.m_sliceViewPlane; m_sliceCoordinateScaled = obj.m_sliceCoordinateScaled; m_planeEquationScaled = obj.m_planeEquationScaled; } ///** // * Equality operator. // * @param obj // * Instance compared to this for equality. // * @return // * True if this instance and 'obj' instance are considered equal. // */ //bool //VolumeSurfaceOutlineModelCacheKey::operator==(const VolumeSurfaceOutlineModelCacheKey& obj) const //{ // if (this == &obj) { // return true; // } // // /* perform equality testing HERE and return true if equal ! */ // if ((m_sliceViewPlane == obj.m_sliceViewPlane) // && (m_sliceCoordinateScaled == obj.m_sliceCoordinateScaled)) { // return true; // } // // return false; //} /** * Less than operator. * * @param obj * Instance compared to this for equality. * @return * True if this instance and 'obj' instance are considered equal. */ bool VolumeSurfaceOutlineModelCacheKey::operator<(const VolumeSurfaceOutlineModelCacheKey& obj) const { if (this == &obj) { return false; } if (m_mode == obj.m_mode) { switch (m_mode) { case Mode::PLANE_EQUATION: { for (int32_t i = 0; i < static_cast(m_planeEquationScaled.size()); i++) { if (m_planeEquationScaled[i] < obj.m_planeEquationScaled[i]) { return true; } else if (m_planeEquationScaled[i] > obj.m_planeEquationScaled[i]) { return false; } } } break; case Mode::SLICE_VIEW_PLANE: { if (static_cast(m_sliceViewPlane) < static_cast(obj.m_sliceViewPlane)) { return true; } else if (static_cast(m_sliceViewPlane) > static_cast(obj.m_sliceViewPlane)) { return false; } if (m_sliceCoordinateScaled < obj.m_sliceCoordinateScaled) { return true; } } break; } } else { if (static_cast(m_mode) < static_cast(obj.m_mode)) { return true; } } return false; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString VolumeSurfaceOutlineModelCacheKey::toString() const { QString str; switch (m_mode) { case Mode::PLANE_EQUATION: str = ("Plane Equation = " + AString::fromNumbers(&m_planeEquationScaled[0], m_planeEquationScaled.size(), ",")); break; case Mode::SLICE_VIEW_PLANE: str = ("Slice View Plane=" + VolumeSliceViewPlaneEnum::toName(m_sliceViewPlane) + ", " + "ScaledCoordinate=" + QString::number(m_sliceCoordinateScaled)); break; } return str; } connectome-workbench-1.4.2/src/Brain/VolumeSurfaceOutlineModelCacheKey.h000066400000000000000000000057071360521144700263350ustar00rootroot00000000000000#ifndef __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_KEY_H__ #define __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_KEY_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretObject.h" #include "Plane.h" #include "VolumeSliceViewPlaneEnum.h" namespace caret { class Plane; class VolumeMappableInterface; class VolumeSurfaceOutlineModelCacheKey : public CaretObject { public: VolumeSurfaceOutlineModelCacheKey(const VolumeMappableInterface* underlayVolume, const VolumeSliceViewPlaneEnum::Enum sliceViewPlane, const float sliceCoordinate); VolumeSurfaceOutlineModelCacheKey(const VolumeMappableInterface* underlayVolume, const Plane& plane); virtual ~VolumeSurfaceOutlineModelCacheKey(); VolumeSurfaceOutlineModelCacheKey(const VolumeSurfaceOutlineModelCacheKey& obj); VolumeSurfaceOutlineModelCacheKey& operator=(const VolumeSurfaceOutlineModelCacheKey& obj); // bool operator==(const VolumeSurfaceOutlineModelCacheKey& obj) const; bool operator<(const VolumeSurfaceOutlineModelCacheKey& obj) const; // ADD_NEW_METHODS_HERE virtual AString toString() const; private: enum class Mode { PLANE_EQUATION, SLICE_VIEW_PLANE }; void copyHelperVolumeSurfaceOutlineModelCacheKey(const VolumeSurfaceOutlineModelCacheKey& obj); float computeScaleFactor(const VolumeMappableInterface* underlayVolume) const; Mode m_mode; VolumeSliceViewPlaneEnum::Enum m_sliceViewPlane = VolumeSliceViewPlaneEnum::ALL; int64_t m_sliceCoordinateScaled = 100000; std::array m_planeEquationScaled; // ADD_NEW_MEMBERS_HERE }; #ifdef __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_KEY_DECLARE__ // #endif // __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_KEY_DECLARE__ } // namespace #endif //__VOLUME_SURFACE_OUTLINE_MODEL_CACHE_KEY_H__ connectome-workbench-1.4.2/src/Brain/VolumeSurfaceOutlineModelCacheValue.cxx000066400000000000000000000045301360521144700272250ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_VALUE_DECLARE__ #include "VolumeSurfaceOutlineModelCacheValue.h" #undef __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_VALUE_DECLARE__ #include "CaretAssert.h" #include "GraphicsPrimitive.h" using namespace caret; /** * \class caret::VolumeSurfaceOutlineModelCacheValue * \brief Data for a cached surface outline model * \ingroup Brain */ /** * Constructor. */ VolumeSurfaceOutlineModelCacheValue::VolumeSurfaceOutlineModelCacheValue() : CaretObject() { } /** * Destructor. */ VolumeSurfaceOutlineModelCacheValue::~VolumeSurfaceOutlineModelCacheValue() { deletePrimitives(); } /** * Delete the primitives. */ void VolumeSurfaceOutlineModelCacheValue::deletePrimitives() { for (auto p : m_contourLinePrimitives) { delete p; } m_contourLinePrimitives.clear(); } /** * @return Reference to the graphics primitives; */ std::vector VolumeSurfaceOutlineModelCacheValue::getGraphicsPrimitives() const { return m_contourLinePrimitives; } /** * Set the primitives in this cache. Any current primitives are replaced and destroyed */ void VolumeSurfaceOutlineModelCacheValue::setGraphicsPrimitive(const std::vector& primitives) { deletePrimitives(); m_contourLinePrimitives = primitives; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString VolumeSurfaceOutlineModelCacheValue::toString() const { return "VolumeSurfaceOutlineModelCacheValue"; } connectome-workbench-1.4.2/src/Brain/VolumeSurfaceOutlineModelCacheValue.h000066400000000000000000000041411360521144700266500ustar00rootroot00000000000000#ifndef __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_VALUE_H__ #define __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_VALUE_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" namespace caret { class GraphicsPrimitive; class VolumeSurfaceOutlineModelCacheValue : public CaretObject { public: VolumeSurfaceOutlineModelCacheValue(); virtual ~VolumeSurfaceOutlineModelCacheValue(); VolumeSurfaceOutlineModelCacheValue(const VolumeSurfaceOutlineModelCacheValue&) = delete; VolumeSurfaceOutlineModelCacheValue& operator=(const VolumeSurfaceOutlineModelCacheValue&) = delete; void setGraphicsPrimitive(const std::vector& primitives); std::vector getGraphicsPrimitives() const; // ADD_NEW_METHODS_HERE virtual AString toString() const; private: void deletePrimitives(); std::vector m_contourLinePrimitives; // ADD_NEW_MEMBERS_HERE }; #ifdef __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_VALUE_DECLARE__ // #endif // __VOLUME_SURFACE_OUTLINE_MODEL_CACHE_VALUE_DECLARE__ } // namespace #endif //__VOLUME_SURFACE_OUTLINE_MODEL_CACHE_VALUE_H__ connectome-workbench-1.4.2/src/Brain/VolumeSurfaceOutlineSetModel.cxx000066400000000000000000000345051360521144700257650ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __VOLUME_SURFACE_OUTLINE_SET_MODEL_DECLARE__ #include "VolumeSurfaceOutlineSetModel.h" #undef __VOLUME_SURFACE_OUTLINE_SET_MODEL_DECLARE__ #include "Brain.h" #include "BrainStructure.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "EventBrowserTabGetAll.h" #include "EventManager.h" #include "ModelSurface.h" #include "SceneClassAssistant.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "Surface.h" #include "SurfaceSelectionModel.h" #include "VolumeSurfaceOutlineColorOrTabModel.h" #include "VolumeSurfaceOutlineModel.h" #include "SceneableInterface.h" using namespace caret; /** * \class caret::VolumeSurfaceOutlineSetModel * \brief Holds a set of VolumeSurfaceOutlineModels * * Holds a set of VolumeSurfaceOutlineModels. Users * may add additional surface outline models up to * a fixed limit. There is also a minimum number * that are displayed. */ /** * Constructor. */ VolumeSurfaceOutlineSetModel::VolumeSurfaceOutlineSetModel() : CaretObject() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES; i++) { m_outlineModels[i] = new VolumeSurfaceOutlineModel(); } m_numberOfDisplayedVolumeSurfaceOutlines = 6; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_numberOfDisplayedVolumeSurfaceOutlines", &m_numberOfDisplayedVolumeSurfaceOutlines); } /** * Destructor. */ VolumeSurfaceOutlineSetModel::~VolumeSurfaceOutlineSetModel() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES; i++) { delete m_outlineModels[i]; } delete m_sceneAssistant; } /** * @return The number of volume surface outlines. */ int32_t VolumeSurfaceOutlineSetModel::getNumberOfDislayedVolumeSurfaceOutlines() const { return m_numberOfDisplayedVolumeSurfaceOutlines; } /** * Copy the given volume surface outline set model. * @param setModel * Model that is copied. */ void VolumeSurfaceOutlineSetModel::copyVolumeSurfaceOutlineSetModel(VolumeSurfaceOutlineSetModel* setModel) { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES; i++) { m_outlineModels[i]->copyVolumeSurfaceOutlineModel(setModel->getVolumeSurfaceOutlineModel(i)); } m_numberOfDisplayedVolumeSurfaceOutlines = setModel->getNumberOfDislayedVolumeSurfaceOutlines(); } /** * Set the number of volume surface outlines. * @param numberDisplayed * Number of displayed volume surface outlines. */ void VolumeSurfaceOutlineSetModel::setNumberOfDisplayedVolumeSurfaceOutlines(const int32_t numberDisplayed) { m_numberOfDisplayedVolumeSurfaceOutlines = numberDisplayed; if (m_numberOfDisplayedVolumeSurfaceOutlines < BrainConstants::MINIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES) { m_numberOfDisplayedVolumeSurfaceOutlines = BrainConstants::MINIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES; } if (m_numberOfDisplayedVolumeSurfaceOutlines > BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES) { m_numberOfDisplayedVolumeSurfaceOutlines = BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES; } } /** * @return The volume surface outline model at the given index. * @param indx * Index of volume surface outline model. */ VolumeSurfaceOutlineModel* VolumeSurfaceOutlineSetModel::getVolumeSurfaceOutlineModel(const int32_t indx) { CaretAssertArrayIndex(m_outlineModels, BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES, indx); return m_outlineModels[indx]; } /** * @return The volume surface outline model at the given index. * @param indx * Index of volume surface outline model. */ const VolumeSurfaceOutlineModel* VolumeSurfaceOutlineSetModel::getVolumeSurfaceOutlineModel(const int32_t indx) const { CaretAssertArrayIndex(m_outlineModels, BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES, indx); return m_outlineModels[indx]; } /** * Set the default selected surfaces after a spec file is loaded. * @searchForTabs * If true, examine the loaded tabs to find left and right surfaces. */ void VolumeSurfaceOutlineSetModel::selectSurfacesAfterSpecFileLoaded(Brain* brain, const bool searchForTabs) { EventBrowserTabGetAll getAllTabs; EventManager::get()->sendEvent(getAllTabs.getPointer()); /* * Find tabs with left/right */ int32_t leftTabIndex = -1; int32_t rightTabIndex = -1; const int numTabs = getAllTabs.getNumberOfBrowserTabs(); if (searchForTabs) { for (int32_t i = 0; i < numTabs; i++) { BrowserTabContent* tabContent = getAllTabs.getBrowserTab(i); ModelSurface* surfaceModel = tabContent->getDisplayedSurfaceModel(); if (surfaceModel != NULL) { const StructureEnum::Enum structure = surfaceModel->getSurface()->getStructure(); switch (structure) { case StructureEnum::CORTEX_LEFT: leftTabIndex = tabContent->getTabNumber(); break; case StructureEnum::CORTEX_RIGHT: rightTabIndex = tabContent->getTabNumber(); break; default: break; } } } } else { if (numTabs >= 1) { leftTabIndex = 0; } if (numTabs >= 2) { rightTabIndex = 1; } } Surface* leftMidThickSurface = NULL; Surface* leftWhiteSurface = NULL; Surface* leftPialSurface = NULL; BrainStructure* leftBrainStructure = brain->getBrainStructure(StructureEnum::CORTEX_LEFT, false); if (leftBrainStructure != NULL) { leftMidThickSurface = leftBrainStructure->getSurfaceContainingTextInName("midthick"); if (leftMidThickSurface == NULL) { leftMidThickSurface = leftBrainStructure->getPrimaryAnatomicalSurface(); } leftWhiteSurface = leftBrainStructure->getSurfaceContainingTextInName("white"); leftPialSurface = leftBrainStructure->getSurfaceContainingTextInName("pial"); } Surface* rightMidThickSurface = NULL; Surface* rightWhiteSurface = NULL; Surface* rightPialSurface = NULL; BrainStructure* rightBrainStructure = brain->getBrainStructure(StructureEnum::CORTEX_RIGHT, false); if (rightBrainStructure != NULL) { rightMidThickSurface = rightBrainStructure->getSurfaceContainingTextInName("midthick"); if (rightMidThickSurface == NULL) { rightMidThickSurface = rightBrainStructure->getPrimaryAnatomicalSurface(); } rightWhiteSurface = rightBrainStructure->getSurfaceContainingTextInName("white"); rightPialSurface = rightBrainStructure->getSurfaceContainingTextInName("pial"); } for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES; i++) { m_outlineModels[i]->getColorOrTabModel()->setColor(CaretColorEnum::BLACK); m_outlineModels[i]->setThicknessPixelsObsolete(VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE); } int nextOutlineIndex = 0; addSurfaceOutline(leftMidThickSurface, leftTabIndex, CaretColorEnum::BLACK, nextOutlineIndex); addSurfaceOutline(rightMidThickSurface, rightTabIndex, CaretColorEnum::BLACK, nextOutlineIndex); addSurfaceOutline(leftWhiteSurface, -1, CaretColorEnum::LIME, nextOutlineIndex); addSurfaceOutline(rightWhiteSurface, -1, CaretColorEnum::LIME, nextOutlineIndex); addSurfaceOutline(leftPialSurface, -1, CaretColorEnum::BLUE, nextOutlineIndex); addSurfaceOutline(rightPialSurface, -1, CaretColorEnum::BLUE, nextOutlineIndex); } /** * Add a surface outline at the given outlineIndex. The * outlineIndex is incremented. * * @param surface * Surface that is added. If NULL, no action is taken. * @param browserTabIndex * If greater than or equal to zero, the color source * is set to this tab index. * @param color * If browserTabIndex is less than zero, the color source * is set to this color. * @param outlineIndex * If an outline was added, it is placed at this value * and it is incremented. If this index is greater * than or equal to the number of available surface * outlines, no action is taken. */ void VolumeSurfaceOutlineSetModel::addSurfaceOutline(Surface* surface, const int32_t browserTabIndex, const CaretColorEnum::Enum color, int32_t& outlineIndex) { if (surface != NULL) { if (surface->getSurfaceType() == SurfaceTypeEnum::ANATOMICAL) { if (outlineIndex < BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES) { VolumeSurfaceOutlineModel* vsos = m_outlineModels[outlineIndex]; vsos->getSurfaceSelectionModel()->setSurface(surface); vsos->setThicknessPixelsObsolete(VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PIXELS_OBSOLETE); vsos->setThicknessPercentageViewportHeight(VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PERCENTAGE_VIEWPORT_HEIGHT); if (browserTabIndex >= 0) { vsos->getColorOrTabModel()->setBrowserTabIndex(browserTabIndex); } else { vsos->getColorOrTabModel()->setColor(color); } outlineIndex++; } } } } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* VolumeSurfaceOutlineSetModel::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "VolumeSurfaceOutlineSetModel", 2); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); std::vector outlineModelSceneClassVector; for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES; i++ ) { outlineModelSceneClassVector.push_back(m_outlineModels[i]->saveToScene(sceneAttributes, ("m_outlineModels[" + AString::number(i) + "]"))); } sceneClass->addChild(new SceneClassArray("m_outlineModels", outlineModelSceneClassVector)); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void VolumeSurfaceOutlineSetModel::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } const int32_t version = sceneClass->getVersionNumber(); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); const SceneClassArray* outlineModelsArrayClass = sceneClass->getClassArray("m_outlineModels"); if (outlineModelsArrayClass != NULL) { const int32_t maxNum = std::min(outlineModelsArrayClass->getNumberOfArrayElements(), (int32_t)BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES); for (int32_t i = 0; i < maxNum; i++) { m_outlineModels[i]->restoreFromScene(sceneAttributes, outlineModelsArrayClass->getClassAtIndex(i)); } /* * In older scenes, last was drawn on top. * Now, zero is drawn on top so need to reverse * the order of the volume surface outlines */ if (version < 2) { if (maxNum > 1) { const int32_t numDisplayed = getNumberOfDislayedVolumeSurfaceOutlines(); CaretAssertArrayIndex(m_outlineModels, BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES, numDisplayed - 1); std::reverse(m_outlineModels, m_outlineModels + numDisplayed); } } } } connectome-workbench-1.4.2/src/Brain/VolumeSurfaceOutlineSetModel.h000066400000000000000000000062351360521144700254110ustar00rootroot00000000000000#ifndef __VOLUME_SURFACE_OUTLINE_SET_MODEL__H_ #define __VOLUME_SURFACE_OUTLINE_SET_MODEL__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "CaretColorEnum.h" #include "CaretObject.h" #include "SceneableInterface.h" namespace caret { class Brain; class Surface; class SceneAttributes; class SceneClassAssistant; class VolumeSurfaceOutlineModel; class VolumeSurfaceOutlineSetModel : public CaretObject, public SceneableInterface { public: VolumeSurfaceOutlineSetModel(); virtual ~VolumeSurfaceOutlineSetModel(); void copyVolumeSurfaceOutlineSetModel(VolumeSurfaceOutlineSetModel* setModel); int32_t getNumberOfDislayedVolumeSurfaceOutlines() const; void setNumberOfDisplayedVolumeSurfaceOutlines(const int32_t numberDisplayed); VolumeSurfaceOutlineModel* getVolumeSurfaceOutlineModel(const int32_t indx); const VolumeSurfaceOutlineModel* getVolumeSurfaceOutlineModel(const int32_t indx) const; void selectSurfacesAfterSpecFileLoaded(Brain* brain, const bool searchForTabs); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: VolumeSurfaceOutlineSetModel(const VolumeSurfaceOutlineSetModel&); VolumeSurfaceOutlineSetModel& operator=(const VolumeSurfaceOutlineSetModel&); void addSurfaceOutline(Surface* surface, const int32_t browserTabIndex, const CaretColorEnum::Enum color, int32_t& outlineIndex); VolumeSurfaceOutlineModel* m_outlineModels[BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES]; int32_t m_numberOfDisplayedVolumeSurfaceOutlines; SceneClassAssistant* m_sceneAssistant; }; #ifdef __VOLUME_SURFACE_OUTLINE_SET_MODEL_DECLARE__ // #endif // __VOLUME_SURFACE_OUTLINE_SET_MODEL_DECLARE__ } // namespace #endif //__VOLUME_SURFACE_OUTLINE_SET_MODEL__H_ connectome-workbench-1.4.2/src/Brain/WholeBrainSurfaceSettings.cxx000066400000000000000000000151321360521144700252670ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WHOLE_BRAIN_SURFACE_SETTINGS_DECLARE__ #include "WholeBrainSurfaceSettings.h" #undef __WHOLE_BRAIN_SURFACE_SETTINGS_DECLARE__ #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::WholeBrainSurfaceSettings * \brief Surface settings for whole brain. * \ingroup Brain */ /** * Constructor. */ WholeBrainSurfaceSettings::WholeBrainSurfaceSettings() : CaretObject() { m_cerebellumEnabled = true; m_leftEnabled = true; m_rightEnabled = true; m_leftRightSeparation = 0.0; m_cerebellumSeparation = 0.0; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_leftEnabled", &m_leftEnabled); m_sceneAssistant->add("m_rightEnabled", &m_rightEnabled); m_sceneAssistant->add("m_cerebellumEnabled", &m_cerebellumEnabled); m_sceneAssistant->add("m_leftRightSeparation", &m_leftRightSeparation); m_sceneAssistant->add("m_cerebellumSeparation", &m_cerebellumSeparation); } /** * Destructor. */ WholeBrainSurfaceSettings::~WholeBrainSurfaceSettings() { delete m_sceneAssistant; } /** * Copy constructor. * @param obj * Object that is copied. */ WholeBrainSurfaceSettings::WholeBrainSurfaceSettings(const WholeBrainSurfaceSettings& obj) : CaretObject(obj), SceneableInterface(obj) { this->copyHelperWholeBrainSurfaceSettings(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ WholeBrainSurfaceSettings& WholeBrainSurfaceSettings::operator=(const WholeBrainSurfaceSettings& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperWholeBrainSurfaceSettings(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void WholeBrainSurfaceSettings::copyHelperWholeBrainSurfaceSettings(const WholeBrainSurfaceSettings& obj) { m_cerebellumEnabled = obj.m_cerebellumEnabled; m_leftEnabled = obj.m_leftEnabled; m_rightEnabled = obj.m_rightEnabled; m_leftRightSeparation = obj.m_leftRightSeparation; m_cerebellumSeparation = obj.m_cerebellumSeparation; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString WholeBrainSurfaceSettings::toString() const { return "WholeBrainSurfaceSettings"; } /** * @return Enabled status for left cerebral cortex. */ bool WholeBrainSurfaceSettings::isLeftEnabled() const { return m_leftEnabled; } /** * Set the enabled status for the left hemisphere. * @param windowTabNumber * Index of window tab. * @param enabled * New enabled status. */ void WholeBrainSurfaceSettings::setLeftEnabled(const bool enabled) { m_leftEnabled = enabled; } /** * @return Enabled status for right cerebral cortex. */ bool WholeBrainSurfaceSettings::isRightEnabled() const { return m_rightEnabled; } /** * Set the enabled status for the right hemisphere. * @param enabled * New enabled status. */ void WholeBrainSurfaceSettings::setRightEnabled(const bool enabled) { m_rightEnabled = enabled; } /** * @return Enabled status for cerebellum. */ bool WholeBrainSurfaceSettings::isCerebellumEnabled() const { return m_cerebellumEnabled; } /** * Set the enabled status for the cerebellum. * @param enabled * New enabled status. */ void WholeBrainSurfaceSettings::setCerebellumEnabled(const bool enabled) { m_cerebellumEnabled = enabled; } /** * @return The separation between the left and right surfaces. */ float WholeBrainSurfaceSettings::getLeftRightSeparation() const { return m_leftRightSeparation; } /** * Set the separation between the cerebellum and the left/right surfaces. * @param separation * New value for separation. */ void WholeBrainSurfaceSettings::setLeftRightSeparation(const float separation) { m_leftRightSeparation = separation; } /** * @return The separation between the left/right surfaces. */ float WholeBrainSurfaceSettings::getCerebellumSeparation() const { return m_cerebellumSeparation; } /** * Set the separation between the cerebellum and the eft and right surfaces. * @param separation * New value for separation. */ void WholeBrainSurfaceSettings::setCerebellumSeparation(const float separation) { m_cerebellumSeparation = separation; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* WholeBrainSurfaceSettings::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "WholeBrainSurfaceSettings", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void WholeBrainSurfaceSettings::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } connectome-workbench-1.4.2/src/Brain/WholeBrainSurfaceSettings.h000066400000000000000000000056521360521144700247220ustar00rootroot00000000000000#ifndef __WHOLE_BRAIN_SURFACE_SETTINGS_H__ #define __WHOLE_BRAIN_SURFACE_SETTINGS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "SceneableInterface.h" namespace caret { class SceneClassAssistant; class WholeBrainSurfaceSettings : public CaretObject, public SceneableInterface { public: WholeBrainSurfaceSettings(); virtual ~WholeBrainSurfaceSettings(); WholeBrainSurfaceSettings(const WholeBrainSurfaceSettings& obj); WholeBrainSurfaceSettings& operator=(const WholeBrainSurfaceSettings& obj); bool isLeftEnabled() const; void setLeftEnabled(const bool enabled); bool isRightEnabled() const; void setRightEnabled(const bool enabled); bool isCerebellumEnabled() const; void setCerebellumEnabled(const bool enabled); float getLeftRightSeparation() const; void setLeftRightSeparation(const float separation); float getCerebellumSeparation() const; void setCerebellumSeparation(const float separation); // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: void copyHelperWholeBrainSurfaceSettings(const WholeBrainSurfaceSettings& obj); SceneClassAssistant* m_sceneAssistant; bool m_leftEnabled; bool m_rightEnabled; bool m_cerebellumEnabled; float m_leftRightSeparation; float m_cerebellumSeparation; // ADD_NEW_MEMBERS_HERE }; #ifdef __WHOLE_BRAIN_SURFACE_SETTINGS_DECLARE__ // #endif // __WHOLE_BRAIN_SURFACE_SETTINGS_DECLARE__ } // namespace #endif //__WHOLE_BRAIN_SURFACE_SETTINGS_H__ connectome-workbench-1.4.2/src/Brain/WholeBrainVoxelDrawingMode.cxx000066400000000000000000000232441360521144700253770ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __WHOLE_BRAIN_VOXEL_DRAWING_MODE_ENUM_DECLARE__ #include "WholeBrainVoxelDrawingMode.h" #undef __WHOLE_BRAIN_VOXEL_DRAWING_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::WholeBrainVoxelDrawingMode * \brief Enumerated type for drawing of voxels in whole brain view. */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ WholeBrainVoxelDrawingMode::WholeBrainVoxelDrawingMode(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ WholeBrainVoxelDrawingMode::~WholeBrainVoxelDrawingMode() { } /** * Initialize the enumerated metadata. */ void WholeBrainVoxelDrawingMode::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(WholeBrainVoxelDrawingMode(DRAW_VOXELS_AS_THREE_D_CUBES, "DRAW_VOXELS_AS_THREE_D_CUBES", "Draw Voxels as Cubes (3D)")); enumData.push_back(WholeBrainVoxelDrawingMode(DRAW_VOXELS_AS_ROUNDED_THREE_D_CUBES, "DRAW_VOXELS_AS_ROUNDED_THREE_D_CUBES", "Draw Voxels as Rounded Cubes (3D)")); enumData.push_back(WholeBrainVoxelDrawingMode(DRAW_VOXELS_ON_TWO_D_SLICES, "DRAW_VOXELS_ON_TWO_D_SLICES", "Draw Voxels on Slices (2D)")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const WholeBrainVoxelDrawingMode* WholeBrainVoxelDrawingMode::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const WholeBrainVoxelDrawingMode* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WholeBrainVoxelDrawingMode::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const WholeBrainVoxelDrawingMode* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WholeBrainVoxelDrawingMode::Enum WholeBrainVoxelDrawingMode::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = DRAW_VOXELS_ON_TWO_D_SLICES; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WholeBrainVoxelDrawingMode& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WholeBrainVoxelDrawingMode")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WholeBrainVoxelDrawingMode::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const WholeBrainVoxelDrawingMode* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WholeBrainVoxelDrawingMode::Enum WholeBrainVoxelDrawingMode::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = DRAW_VOXELS_ON_TWO_D_SLICES; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WholeBrainVoxelDrawingMode& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WholeBrainVoxelDrawingMode")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t WholeBrainVoxelDrawingMode::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const WholeBrainVoxelDrawingMode* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ WholeBrainVoxelDrawingMode::Enum WholeBrainVoxelDrawingMode::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = DRAW_VOXELS_ON_TWO_D_SLICES; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WholeBrainVoxelDrawingMode& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WholeBrainVoxelDrawingMode")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void WholeBrainVoxelDrawingMode::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WholeBrainVoxelDrawingMode::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(WholeBrainVoxelDrawingMode::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WholeBrainVoxelDrawingMode::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(WholeBrainVoxelDrawingMode::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Brain/WholeBrainVoxelDrawingMode.h000066400000000000000000000066161360521144700250300ustar00rootroot00000000000000#ifndef __WHOLE_BRAIN_VOXEL_DRAWING_MODE_ENUM_H__ #define __WHOLE_BRAIN_VOXEL_DRAWING_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class WholeBrainVoxelDrawingMode { public: /** * Enumerated values. */ enum Enum { /** In Whole Brain, view volume data as 3D cubes */ DRAW_VOXELS_AS_THREE_D_CUBES, /** In Whole Brain, view volume data as Rounded 3D cubes */ DRAW_VOXELS_AS_ROUNDED_THREE_D_CUBES, /** In Whole Brain, view volume data on slices */ DRAW_VOXELS_ON_TWO_D_SLICES }; ~WholeBrainVoxelDrawingMode(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: WholeBrainVoxelDrawingMode(const Enum enumValue, const AString& name, const AString& guiName); static const WholeBrainVoxelDrawingMode* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __WHOLE_BRAIN_VOXEL_DRAWING_MODE_ENUM_DECLARE__ std::vector WholeBrainVoxelDrawingMode::enumData; bool WholeBrainVoxelDrawingMode::initializedFlag = false; int32_t WholeBrainVoxelDrawingMode::integerCodeCounter = 0; #endif // __WHOLE_BRAIN_VOXEL_DRAWING_MODE_ENUM_DECLARE__ } // namespace #endif //__WHOLE_BRAIN_VOXEL_DRAWING_MODE_ENUM_H__ connectome-workbench-1.4.2/src/CMakeLists.txt000077500000000000000000000573561360521144700212050ustar00rootroot00000000000000# # Minimum required version of CMAKE # CMAKE_MINIMUM_REQUIRED (VERSION 2.8) SET(WB_VERSION "1.4.2") # # Set to true for verbose output when debugging this file # SET(WB_CMAKE_VERBOSE_OUTPUT_FLAG TRUE) ########################################################################################## # # A function to get all user defined variables with a specified prefix # From https://cmake.org/Wiki/CMake/Tutorials/SettingVariableGroups # function (getListOfVarsStartingWith _prefix _varResult) get_cmake_property(_vars CACHE_VARIABLES) string (REGEX MATCHALL "(^|;)${_prefix}[A-Za-z0-9_]*" _matchedVars "${_vars}") set (${_varResult} ${_matchedVars} PARENT_SCOPE) endfunction() ########################################################################################## # # Workbench CACHE variables # TSC: use "CACHE " syntax in SET commands so they can be overridden by cmake options # set (WORKBENCH_QT5_DISABLE_DEPRECATED FALSE CACHE BOOL "If TRUE, use of Qt 5 deprecated functionality will cause compiler to fail") set (WORKBENCH_USE_CMAKE_AUTOMOC FALSE CACHE BOOL "If TRUE, use CMAKE_AUTOMOC command for generating 'moc' files") set (WORKBENCH_INCLUDE_HELP_HTML_RESOURCES TRUE CACHE BOOL "If TRUE, help (html) pages in src/Resources/Help are available in wb_view") set (WORKBENCH_USE_QT5 TRUE CACHE BOOL "If TRUE, require Qt5, else Qt4.Specify as argument to cmake: -DWORKBENCH_USE_QT5=TRUE") set (WORKBENCH_USE_QT5_QOPENGL_WIDGET FALSE CACHE BOOL "With Qt5, QOpenGLWidget instead of deprecated QGLWidget") set (WORKBENCH_MESA_DIR "" CACHE PATH "Directory containing Mesa's 'include' and 'lib' directories. Mesa is optional and used by wb_command's -show-scene operation.") ########################################################################################## # # Setting the compiler MUST be done before the PROJECT # statement or else an infinite loop will occur indicating # that the compiler has been redefined. # IF(APPLE) ADD_DEFINITIONS(-DCARET_OS_MACOSX) ELSEIF(UNIX) IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") ADD_DEFINITIONS(-DCARET_OS_LINUX) SET(CMAKE_POSITION_INDEPENDENT_CODE ON) ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") ELSEIF(WIN32) ADD_DEFINITIONS(-DCARET_OS_WINDOWS) # Policy CMP0020 is related to Qt # https://cmake.org/cmake/help/v3.5/policy/CMP0020.html if(POLICY CMP0020) cmake_policy(SET CMP0020 NEW) endif() IF(MSVC) ADD_DEFINITIONS(-DCARET_OS_WINDOWS_MSVC) ADD_DEFINITIONS(-D_USE_MATH_DEFINES -DNOMINMAX) SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -MP -wd4290 -wd4244 -wd4267 -wd4305 -wd4100 -wd4005" ) IF(CMAKE_CL_64) ELSE() ENDIF(CMAKE_CL_64) ELSE(MSVC) ENDIF(MSVC) ELSE(APPLE) MESSAGE(SEND_ERROR "Unrecognized operating system " ${CMAKE_SYSTEM_NAME}) ENDIF(APPLE) # # Intel compiler # IF (${CMAKE_CXX_COMPILER} MATCHES "^.*icpc$") ADD_DEFINITIONS("-W -Wall -Werror=return-type -Werror=switch -Wunused-parameter") ENDIF (${CMAKE_CXX_COMPILER} MATCHES "^.*icpc$") # # Clang compiler on Mac # UNSET(CLANG_FLAG) IF (${CMAKE_CXX_COMPILER} MATCHES "^.*clang\\+\\+.*") SET(CLANG_FLAG TRUE) ENDIF (${CMAKE_CXX_COMPILER} MATCHES "^.*clang\\+\\+.*") IF (${CMAKE_CXX_COMPILER} MATCHES "^.*clang2\\+\\+.*") SET(CLANG_FLAG TRUE) ENDIF (${CMAKE_CXX_COMPILER} MATCHES "^.*clang2\\+\\+.*") IF (CLANG_FLAG) ADD_DEFINITIONS("-W -Wall -Werror=return-type -Werror=switch -Wunused-parameter -Wno-deprecated-declarations") ENDIF (CLANG_FLAG) # # IF GNU compiler, functions without a return type or switch # statements that do not handle all of the enumerated types # are treated as an error. Also, all warnings. # IF (NOT MSVC) if (CMAKE_COMPILER_IS_GNUCC) execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) message("gcc version is: " ${GCC_VERSION}) if(${GCC_VERSION} VERSION_LESS "4.2") ADD_DEFINITIONS(-W -Wall) else() ADD_DEFINITIONS(-W -Wall -Werror=return-type -Werror=switch -Wunused-parameter) endif() if (${GCC_VERSION} VERSION_LESS "4.9") # there is no greater than or equal in CMake else() ADD_DEFINITIONS(-Wno-narrowing -Wno-unused-local-typedefs) endif() endif() ENDIF (NOT MSVC) ########################################################################################## # # If GNU compiler, use SIMD-based dot computation, if possible # SET(SIMD_RESULT "Search for SIMD disabled for compiler on this system.") if ((CMAKE_COMPILER_IS_GNUCC OR CLANG_FLAG) AND CMAKE_SIZEOF_VOID_P EQUAL 8) # # Define flag to avoid trying to compile SIMD stuff (coded for x86_64 only) # SET(WORKBENCH_USE_SIMD TRUE CACHE BOOL "try to compile with SIMD support") # # If we should try to use SIMD, check whether cpuinfo compiles # IF (WORKBENCH_USE_SIMD) TRY_COMPILE(CPUINFO_COMPILES ${CMAKE_CURRENT_BINARY_DIR}/cpuinfo_compile_test ${CMAKE_CURRENT_SOURCE_DIR}/kloewe/cpuinfo cpuinfo) # # Add the necessary definition and include directory to enable the # SIMD-based dot product implementations # IF (CPUINFO_COMPILES) ADD_DEFINITIONS(-DCARET_DOTFCN) INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/kloewe/dot/src) SET(SIMD_RESULT "Enabled") ELSE() SET(SIMD_RESULT "Failed when compiling with SIMD") ENDIF() ELSE (WORKBENCH_USE_SIMD) SET(SIMD_RESULT "Search for SIMD disabled, WORKBENCH_USE_SIMD=FALSE") ENDIF (WORKBENCH_USE_SIMD) endif ((CMAKE_COMPILER_IS_GNUCC OR CLANG_FLAG) AND CMAKE_SIZEOF_VOID_P EQUAL 8) #TSC: we require c++11, so it needs to be in the compile flags - in older cmake, this needs to be done manually IF (${CMAKE_VERSION} VERSION_LESS "3.1") IF (CMAKE_COMPILER_IS_GNUCC) include(CheckCXXCompilerFlag) CHECK_CXX_COMPILER_FLAG("-std=c++11" GCC_STD11) IF (${GCC_STD11}) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") ELSE (${GCC_STD11}) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") ENDIF (${GCC_STD11}) ENDIF (CMAKE_COMPILER_IS_GNUCC) ELSE (${CMAKE_VERSION} VERSION_LESS "3.1") SET(CMAKE_CXX_STANDARD 11) SET(CMAKE_CXX_STANDARD_REQUIRED TRUE) ENDIF (${CMAKE_VERSION} VERSION_LESS "3.1") ########################################################################################## # # OpenSSL # SET(OPENSSL_RESULT "Not Found") FIND_PACKAGE(OpenSSL) IF(OPENSSL_FOUND) INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) SET(OPENSSL_RESULT "${OPENSSL_VERSION} ${OPENSSL_LIBRARIES}") ELSE (OPENSSL_FOUND) MESSAGE("OpenSSL NOT FOUND. May need to define OPENSSL_ROOT_DIR when running CMake.") MESSAGE(" cmake -DOPENSSL_ROOT_DIR= \n") MESSAGE("See: https://cmake.org/cmake/help/v3.5/module/FindOpenSSL.html") ENDIF(OPENSSL_FOUND) ########################################################################################## # # Must have QT 4.8 or QT 5, recommended 5.6 or later # https://cmake.org/cmake/help/v3.5/manual/cmake-packages.7.html#manual:cmake-packages(7) # Modules List: http://doc.qt.io/qt-5/qtmodules.html # SET(WB_WEBKIT_COMPONENTS "") SET(WB_WEBKIT_LIBS "") SET(HAVE_QT_WEBKIT False) IF (HAVE_QT_WEBKIT) ADD_DEFINITIONS(-DHAVE_WEBKIT) SET (WB_WEBKIT_COMPONENTS "WebEngine WebEngineCore WebEngineWidgets") SET (WB_WEBKIT_LIBS "Qt5::WebEngine Qt5::WebEngineCore Qt5::WebEngineWidgets") ENDIF (HAVE_QT_WEBKIT) SET(QT_RESULT "Not Found") SET(CARET_QT5_LINK "") IF (WORKBENCH_USE_QT5) # # The OpenGL module is deprecated in Qt5 and # is needed only if QGLWidget is used for # the OpenGL graphics. # IF (NOT WORKBENCH_USE_QT5_QOPENGL_WIDGET) SET(WB_QT_OPENGL_MODULE "OpenGL") ENDIF () FIND_PACKAGE(Qt5 REQUIRED COMPONENTS Concurrent Core Gui Network ${WB_QT_OPENGL_MODULE} PrintSupport Test Widgets Xml ${WB_WEBKIT_COMPONENTS}) IF (WORKBENCH_USE_QT5_QOPENGL_WIDGET) # # QGLWidget is deprecated in Qt 5 and is replaced with QOpenGLWidget # # If WORKBENCH_USE_QT5_QOPENGL_WIDGET is defined, QOpenGLWidget is used # for OpenGL. Otherwise, QGLWidget is used. # add_definitions(-DWORKBENCH_USE_QT5_QOPENGL_WIDGET) ELSE (WORKBENCH_USE_QT5_QOPENGL_WIDGET) remove_definitions(-DWORKBENCH_USE_QT5_QOPENGL_WIDGET) ENDIF (WORKBENCH_USE_QT5_QOPENGL_WIDGET) IF (WORKBENCH_QT5_DISABLE_DEPRECATED) # Causes Qt to remove declarations for deprecated functionality add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050700) # Enable usage of replacements for Qt deprecated functionality in Workbench source code add_definitions(-DWORKBENCH_REPLACE_QT_DEPRECATED) ENDIF (WORKBENCH_QT5_DISABLE_DEPRECATED) #small hack to get the qt5 compile flag requirements into libraries SET(CARET_QT5_LINK "Qt5::Core") SET(QT_RESULT "${Qt5_VERSION}") ELSE () FIND_PACKAGE(Qt4 4.8 REQUIRED) IF(QT4_FOUND) INCLUDE(${QT_USE_FILE}) SET(QT_RESULT "${QTVERSION}") ELSE(QT4_FOUND) MESSAGE(SEND_ERROR "QT4 not found") ENDIF(QT4_FOUND) ENDIF () ########################################################################################## # # Try to find Qwt, otherwise use bundle # SET(QWT_RESULT "Not Found") IF (NOT WIN32) PKG_CHECK_MODULES(Qwt qwt) ENDIF (NOT WIN32) IF (Qwt_FOUND) SET(QWT_RESULT "Using Qwt Library ${Qwt_LIBRARIES}") ELSE (Qwt_FOUND) SET(QWT_RESULT "In Workbench Source Code") ENDIF (Qwt_FOUND) ########################################################################################## # # glm Math Library is header filess only containing C++ templates and functions. # Since there is no code to link, only need the path to the include files # https://glm.g-truc.net/0.9.9/index.html # SET(GLMATH_RESULT "Not Found") IF (NOT WIN32) PKG_CHECK_MODULES(GLMath glm) ENDIF (NOT WIN32) IF (GLMath_FOUND) SET(GLMATH_RESULT "Using OpenGL Math directory ${GLMath_INCLUDEDIR}") INCLUDE_DIRECTORIES("${GLMath_INCLUDEDIR}") ELSE (GLMath_FOUND) SET(GLMATH_RESULT "In Workbench Source Code") INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/GLMath") ENDIF (GLMath_FOUND) ########################################################################################## # # Need OpenGL # SET(OPENGL_RESULT "") FIND_PACKAGE(OpenGL REQUIRED) IF (OPENGL_FOUND) # # Need help finding includes on Apple # IF (APPLE) # When searching for the include directory, find the location # for the OpenGL framework rather than an individual header file. FIND_PATH(OPENGL_INCLUDE_DIR OpenGL.framework /System/Library/Frameworks /Library/Frameworks ~/Library/Frameworks) ENDIF (APPLE) # # OpenGL Include Directory # INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR}) MESSAGE("OpenGL Include Directory: ${OPENGL_INCLUDE_DIR}") MESSAGE("OpenGL Libraries: ${OPENGL_LIBRARIES}") SET(OPENGL_RESULT ${OPENGL_LIBRARIES}) ELSE (OPENGL_FOUND) MESSAGE(SEND_ERROR "OpenGL Libraries were not found") ENDIF (OPENGL_FOUND) ########################################################################################## # # Look for GLEW but only on Windows # SET(GLEW_RESULT "No") IF (WIN32) FIND_PACKAGE(GLEW) ENDIF () IF (GLEW_FOUND) SET(GLEW_RESULT "${GLEW_INCLUDE_DIRS} ${GLEW_LIBRARIES}") MESSAGE("GLEW Include Dirs: ${GLEW_INCLUDE_DIRS}") MESSAGE("GLEW Libraries: ${GLEW_LIBRARIES}") STRING(FIND ${GLEW_LIBRARIES} "glew32s.lib" GLEW_STATIC_LIB_NAME_INDEX) ADD_DEFINITIONS(-DHAVE_GLEW) IF (GLEW_STATIC_LIB_NAME_INDEX GREATER -1) ADD_DEFINITIONS(-DHAVE_GLEW_STATIC_LIB) MESSAGE("GLEW Static Library Found") ENDIF() INCLUDE_DIRECTORIES(${GLEW_INCLUDE_DIRS}) ELSE() SET(GLEW_LIBRARIES "") SET(GLEW_INCLUDE_DIRS "") IF (WIN32) MESSAGE(SEND_ERROR "GLEW not found and is required on Windows for finding OpenGL functions.\n" " Setting CMAKE_PREFIX_PATH to the GLEW installation directory when\n" " running CMAKE may help find GLEW.\n") ENDIF() ENDIF() ########################################################################################## # # The Find OpenMP package may not work on all systems and the user may # furnish the paths to the OpenMP files by using environment variables. # # The environment variables are: # OPENMP_COMPILE_OPTION=-fopenmp # OPENMP_HEADER_DIR=/usr/local/clang-openmp-opt/llvm/build/Release/include # OPENMP_LIB_DIR=/usr/local/clang-openmp-opt/llvm/build/Release/lib # UNSET(OPENMP_FOUND) IF (EXISTS $ENV{OPENMP_HEADER_DIR}) MESSAGE("OpenMP Header File: $ENV{OPENMP_HEADER_DIR}") IF (EXISTS $ENV{OPENMP_LIB_DIR}) MESSAGE("OpenMP Library File: $ENV{OPENMP_LIB_DIR}") SET (STUFF $ENV{OPENMP_COMPILE_OPTION}) IF (DEFINED STUFF) MESSAGE("OpenMP Compiler Option: $ENV{OPENMP_COMPILE_OPTION}") SET(OpenMP_CXX_FLAGS "-I$ENV{OPENMP_HEADER_DIR} $ENV{OPENMP_COMPILE_OPTION}") SET(OpenMP_C_FLAGS "-I$ENV{OPENMP_HEADER_DIR} $ENV{OPENMP_COMPILE_OPTION}") SET(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} -L$ENV{OPENMP_LIB_DIR}) SET(OPENMP_FOUND TRUE) ENDIF (DEFINED STUFF) ENDIF (EXISTS $ENV{OPENMP_LIB_DIR}) ENDIF (EXISTS $ENV{OPENMP_HEADER_DIR}) # # IF OpenMP not found through environment variables, # Use CMAKE's Find OpenMP module # IF (NOT OPENMP_FOUND) FIND_PACKAGE(OpenMP) ENDIF (NOT OPENMP_FOUND) # # If OpenMP is found, may need to set compiler and linker flags # SET(OPENMP_RESULT "Not Found") IF (OPENMP_FOUND) # add definitions will add the flag to the linker and resource compilers, which don't understand the openmp option SET(CMAKE_CXX_FLAGS "${OpenMP_CXX_FLAGS} ${CMAKE_CXX_FLAGS}") # # Try to link static with Intel Compiler # IF (${CMAKE_CXX_COMPILER} MATCHES "^.*icpc$") MESSAGE(WARNING "Intel Compiler Being Used") SET (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -openmp-link=static") SET (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-intel") ADD_DEFINITIONS("-static-intel") ENDIF() SET(OPENMP_RESULT "Yes") ELSE (OPENMP_FOUND) MESSAGE(WARNING "OpenMP was not found") IF (CLANG_FLAG) # # The clang compiler does not support OpenMP so it produces many warnings # with "Unknown pragma ignored". So, tell clang to ignore unknown pragmas # so the message is not printed. # ADD_DEFINITIONS("-Wno-unknown-pragmas") ENDIF (CLANG_FLAG) ENDIF(OPENMP_FOUND) ########################################################################################## # # MUST have ZLIB # SET(ZLIB_RESULT "Not Found") FIND_PACKAGE(ZLIB) IF ( ZLIB_FOUND ) INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIRS}) SET(ZLIB_RESULT ${ZLIB_VERSION_STRING}) ELSE (ZLIB_FOUND) MESSAGE(SEND_ERROR "ZLIB was not found. It may be necessary to define " "the variable ZLIB_ROOT when running cmake so that " "the FindZLIB module is able to find ZLIB.\n" " cmake -DZLIB_ROOT= \n" "See HINTS at " "https://cmake.org/cmake/help/v3.5/module/FindZLIB.html") ENDIF (ZLIB_FOUND) ########################################################################################## # # Try to find QuaZip, otherwise use bundled # SET(QUAZIP_RESULT "Not Found") FIND_PACKAGE(QuaZip QUIET) IF (QUAZIP_FOUND) SET(QUAZIP_RESULT "Using QuaZip Library ${QUAZIP_LIBRARIES}") ELSE (QUAZIP_FOUND) # # Quazip needs this defined here for static linking on windows # IF(WIN32) IF(MSVC) ADD_DEFINITIONS(-DQUAZIP_STATIC) ENDIF(MSVC) ENDIF(WIN32) SET(QUAZIP_RESULT "In Workbench Source Code") ENDIF (QUAZIP_FOUND) ########################################################################################## # # Find FreeType # SET(FREETYPE_RESULT "Not Found") SET(FTGL_RESULT "Must have FreeType to use FTGL") SET(FTGL_FONT_MODULE_FOR_LINKING "") IF (DEFINED WORKBENCH_FREETYPE_DIR) # FindFreeType looks for environment variable FREETYPE_DIR as a hint SET(ENV{FREETYPE_DIR} ${WORKBENCH_FREETYPE_DIR}) ENDIF () FIND_PACKAGE(Freetype) IF (FREETYPE_FOUND) IF (NOT WIN32) PKG_CHECK_MODULES(FTGL ftgl) ENDIF (NOT WIN32) IF (FTGL_FOUND) SET(FTGL_RESULT "Using FTGL Library ${FTGL_LIBRARIES}") ELSE (FTGL_FOUND) SET(FTGL_RESULT "In Workbench Source Code") ENDIF (FTGL_FOUND) ADD_DEFINITIONS(-DHAVE_FREETYPE) SET(FREETYPE_RESULT "${FREETYPE_VERSION_STRING} ${FREETYPE_LIBRARIES}") ELSE (FREETYPE_FOUND) SET (FREETYPE_LIBRARY "") SET (FREETYPE_LIBRARIES "") MESSAGE("FreeType library NOT found") MESSAGE(" Define the PATH to FreeType when running CMake") MESSAGE(" -DWORKBENCH_FREETYPE_DIR=") MESSAGE(" Where is the directory containing FreeType's") MESSAGE(" 'include' and 'lib' directories.") ENDIF (FREETYPE_FOUND) ########################################################################################## # # Fixes issue with XCode and newer version of CMake. # It prevents the ZERO_CHECK dependency from running # (which is very slow) every time a build is performed # in XCode. # IF (APPLE) SET (CMAKE_SUPPRESS_REGENERATION TRUE) ENDIF (APPLE) ########################################################################################## # # Test for offscreen MESA (optional library) # Mesa is used by wb_command's -show-scene. # If Mesa is not found, the "-show-scene" command will not be available. # SET(OSMESA_FOUND FALSE) SET(OSMESA_DEFINITION "") SET(OSMESA_OFFSCREEN_LIBRARY "") SET(OSMESA_GL_LIBRARY "") SET(OSMESA_GLU_LIBRARY "") SET(OSMESA_INCLUDE_DIRECTORY "") SET(OSMESA_RESULT "Not found") IF (EXISTS ${WORKBENCH_MESA_DIR}) IF (EXISTS ${WORKBENCH_MESA_DIR}/include/GL/osmesa.h) FIND_LIBRARY(OSMESA_LIBRARY_FOUND NAMES OSMesa OSMESA32 HINTS ${WORKBENCH_MESA_DIR}/lib) FIND_LIBRARY(OSMESA_GL_LIBRARY_FOUND NAMES GL OPENGL32 HINTS ${WORKBENCH_MESA_DIR}/lib) FIND_LIBRARY(OSMESA_GLU_LIBRARY_FOUND NAMES GLU GLU32 HINTS ${WORKBENCH_MESA_DIR}/lib) IF (EXISTS ${OSMESA_LIBRARY_FOUND} AND EXISTS ${OSMESA_GL_LIBRARY_FOUND} AND EXISTS ${OSMESA_GLU_LIBRARY_FOUND}) SET(OSMESA_DEFINITION -DHAVE_OSMESA) SET(OSMESA_OFFSCREEN_LIBRARY ${OSMESA_LIBRARY_FOUND}) SET(OSMESA_GL_LIBRARY ${OSMESA_GL_LIBRARY_FOUND}) SET(OSMESA_GLU_LIBRARY ${OSMESA_GLU_LIBRARY_FOUND}) SET(OSMESA_INCLUDE_DIRECTORY ${WORKBENCH_MESA_DIR}/include) SET(OSMESA_FOUND TRUE) SET(OSMESA_RESULT ${OSMESA_OFFSCREEN_LIBRARY}) ENDIF (EXISTS ${OSMESA_LIBRARY_FOUND} AND EXISTS ${OSMESA_GL_LIBRARY_FOUND} AND EXISTS ${OSMESA_GLU_LIBRARY_FOUND}) ENDIF (EXISTS ${WORKBENCH_MESA_DIR}/include/GL/osmesa.h) ENDIF (EXISTS ${WORKBENCH_MESA_DIR}) ########################################################################################## # # Definition for include Help Files in Resources # IF (WORKBENCH_INCLUDE_HELP_HTML_RESOURCES) ADD_DEFINITIONS(-DWORKBENCH_HAVE_HELP_HTML) ENDIF (WORKBENCH_INCLUDE_HELP_HTML_RESOURCES) ########################################################################################## # # All subdirectories that will be configured for building # IF (NOT QUAZIP_FOUND) ADD_SUBDIRECTORY ( Quazip ) ENDIF (NOT QUAZIP_FOUND) ADD_SUBDIRECTORY ( Common ) ADD_SUBDIRECTORY ( Xml ) ADD_SUBDIRECTORY ( Scenes ) ADD_SUBDIRECTORY ( OSMesaDummy ) IF (FREETYPE_FOUND AND NOT FTGL_FOUND) ADD_SUBDIRECTORY ( FtglFont ) ENDIF (FREETYPE_FOUND AND NOT FTGL_FOUND) ADD_SUBDIRECTORY ( Annotations ) ADD_SUBDIRECTORY ( Charting ) ADD_SUBDIRECTORY ( Palette ) ADD_SUBDIRECTORY ( QxtCore ) ADD_SUBDIRECTORY ( FilesBase ) ADD_SUBDIRECTORY ( Nifti ) ADD_SUBDIRECTORY ( Gifti ) ADD_SUBDIRECTORY ( Cifti ) ADD_SUBDIRECTORY ( Files ) ADD_SUBDIRECTORY ( OperationsBase ) ADD_SUBDIRECTORY ( Algorithms ) ADD_SUBDIRECTORY ( Operations ) ADD_SUBDIRECTORY ( Brain ) ADD_SUBDIRECTORY ( Graphics ) IF (NOT Qwt_FOUND) ADD_SUBDIRECTORY ( Qwt ) ENDIF (NOT Qwt_FOUND) ADD_SUBDIRECTORY ( GuiQt ) ADD_SUBDIRECTORY ( Commands ) ADD_SUBDIRECTORY ( Desktop ) ADD_SUBDIRECTORY ( CommandLine ) ADD_SUBDIRECTORY ( Tests ) if (WORKBENCH_USE_SIMD AND CPUINFO_COMPILES) ADD_SUBDIRECTORY ( kloewe/cpuinfo ) ADD_SUBDIRECTORY ( kloewe/dot ) ENDIF() ########################################################################################## # # CTest tests # ENABLE_TESTING() ########################################################################################## # # DEBUGGING ONLY # # Some find modules do not always document all of their variables. # If you know the prefix for the find module's variables, # this code can be used to print the variables by setting # DEBUG_VARIABLE_PREFIX to the prefix. # For example, set to "Q" to find all variables beginning from Qt # or to "OSMESA" to print all OSMESA variables. # SET(DEBUG_VARIABLE_PREFIX "") IF(NOT ("${DEBUG_VARIABLE_PREFIX}" STREQUAL "")) getListOfVarsStartingWith(${DEBUG_VARIABLE_PREFIX} allVars) foreach( debugVar IN LISTS allVars ) message(${MSG_TYPE} ${MSG_INDENT} "${debugVar}=${${debugVar}}" ) endforeach() ENDIF() ########################################################################################## # # Print Summary # IF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) SET(MSG_MODE "") #Optional SET(MSG_INDENT " ") MESSAGE(${MSG_MODE} "************* SUMMARY FROM RUNNING CMake ********************") FIND_PROGRAM(QMAKE_PROGRAM "qmake" NAMES "qmake.exe") MESSAGE(${MSG_MODE} "TOOLS:") MESSAGE(${MSG_MODE} ${MSG_INDENT} "CMake Build Type: ${CMAKE_BUILD_TYPE}") MESSAGE(${MSG_MODE} ${MSG_INDENT} "CMake Version: ${CMAKE_VERSION}") MESSAGE(${MSG_MODE} ${MSG_INDENT} "CXX Compiler ${CMAKE_CXX_COMPILER_ID}") MESSAGE(${MSG_MODE} ${MSG_INDENT} "CXX Compiler Version: ${CMAKE_CXX_COMPILER_VERSION}") MESSAGE(${MSG_MODE} ${MSG_INDENT} "CXX Compiler Flags: ${CMAKE_CXX_FLAGS}") MESSAGE(${MSG_MODE} ${MSG_INDENT} "CXX Compiler Path: ${CMAKE_CXX_COMPILER}") MESSAGE(${MSG_MODE} ${MSG_INDENT} "QMake Program: ${QMAKE_PROGRAM}") MESSAGE(${MSG_MODE} "WORKBENCH VARIABLES:") getListOfVarsStartingWith("WORKBENCH" allVars) foreach( var IN LISTS allVars ) get_property(docString CACHE ${var} PROPERTY HELPSTRING) message(${MSG_MODE} ${MSG_INDENT} "${var}=${${var}}" ) STRING(REPLACE "" "\n${MSG_INDENT}${MSG_INDENT}" docPrint ${docString}) message(${MSG_MODE} ${MSG_INDENT} ${MSG_INDENT} ${docPrint}) endforeach() MESSAGE(${MSG_MODE} "PACKAGES:") MESSAGE(${MSG_MODE} ${MSG_INDENT} "FTGL: " ${FTGL_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "FreeType: " ${FREETYPE_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "GLEW: " ${GLEW_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "GLMath: " ${GLMATH_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "OpenGL: " ${OPENGL_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "OpenMP: " ${OPENMP_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "OpenSSL: " ${OPENSSL_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "OSMESA: " ${OSMESA_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "Qt: " ${QT_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "QuaZip: " ${QUAZIP_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "Qwt: " ${QWT_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "SIMD: " ${SIMD_RESULT}) MESSAGE(${MSG_MODE} ${MSG_INDENT} "ZLIB: " ${ZLIB_RESULT}) MESSAGE(${MSG_MODE} "************* END SUMMARY FROM RUNNING CMake *****************") ENDIF(WB_CMAKE_VERBOSE_OUTPUT_FLAG) connectome-workbench-1.4.2/src/CMakeScripts/000077500000000000000000000000001360521144700207525ustar00rootroot00000000000000connectome-workbench-1.4.2/src/CMakeScripts/copy_mac_frameworks.sh000077500000000000000000000007241360521144700253460ustar00rootroot00000000000000#!/bin/sh # # This script copies adds the frameworks to the Mac Bundles # exeName=$1 for buildType in Debug/ Release/ RelWithDebInfo/ MinRelSize/ "" do echo "BUILD TYPE ${buildType}" appName=${buildType}${exeName}.app exeName=${appName}/Contents/MacOS/${exeName} echo "App ${appName}" echo "Exe ${exeName}" if [ -f ${exeName} ] ; then if [ ! -d ${appName}/Contents/Frameworks ] ; then macdeployqt ${appName} fi fi done connectome-workbench-1.4.2/src/CMakeScripts/copy_mac_icon.sh000077500000000000000000000010051360521144700241070ustar00rootroot00000000000000#!/bin/sh # # This script copies the mac icon into # into the Mac App's Resources directory. # exeName=$1 iconName=$2 for buildType in Debug/ Release/ RelWithDebInfo/ MinRelSize/ "" do echo "BUILD TYPE ${buildType}" appName=${buildType}${exeName}.app/Contents/MacOS/${exeName} echo "App ${appName}" if [ -f ${appName} ] ; then cp $iconName ${buildType}${exeName}.app/Contents/Resources #cp -R ${QTDIR}/src/gui/mac/qt_menu.nib ${buildType}${exeName}.app/Contents/Resources fi done connectome-workbench-1.4.2/src/CMakeScripts/copy_mac_nib.sh000077500000000000000000000020151360521144700237310ustar00rootroot00000000000000#!/bin/sh # # This script copies the qt_menu.nib directory from QT # into the Mac App's Resources directory. # exeName=$1 for buildType in Debug/ Release/ RelWithDebInfo/ MinRelSize/ "" do echo "BUILD TYPE ${buildType}" appName=${buildType}${exeName}.app/Contents/MacOS/${exeName} echo "App ${appName}" if [ -f ${appName} ] ; then if [ ! -d ${buildType}${exeName}.app/Contents/Resources ] ; then echo "Creating resources directory" mkdir ${buildType}${exeName}.app/Contents/Resources fi nib1=${QTDIR}/src/gui/mac/qt_menu.nib echo "nib1: ${nib1}" if [ -f ${nib1} ] ; then echo "Copying NIB file 1" cp -R ${QTDIR}/src/gui/mac/qt_menu.nib ${buildType}${exeName}.app/Contents/Resources fi nib2=${QTDIR}/lib/QtGui.framework/Versions/4/Resources/qt_menu.nib echo "nib2: ${nib2}" if [ -d ${nib2} ] ; then echo "Copying NIB file 2" cp -R ${nib2} ${buildType}${exeName}.app/Contents/Resources fi fi done connectome-workbench-1.4.2/src/CMakeScripts/git_commit_info.cmake.in000066400000000000000000000022111360521144700255230ustar00rootroot00000000000000FIND_PACKAGE(Git QUIET) IF(GIT_FOUND) EXECUTE_PROCESS( COMMAND ${GIT_EXECUTABLE} rev-parse HEAD OUTPUT_VARIABLE "COMMIT" OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET RESULT_VARIABLE commit_success ) IF(NOT ${commit_success} EQUAL 0) SET(COMMIT "unknown") ENDIF(NOT ${commit_success} EQUAL 0) EXECUTE_PROCESS( COMMAND ${GIT_EXECUTABLE} log -1 --pretty=format:%ai OUTPUT_VARIABLE "COMMIT_DATE" OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET RESULT_VARIABLE commit_date_success ) IF(NOT ${commit_date_success} EQUAL 0) SET(COMMIT_DATE "unknown") ENDIF(NOT ${commit_date_success} EQUAL 0) ELSE(GIT_FOUND) SET(COMMIT "unknown") SET(COMMIT_DATE "unknown") ENDIF(GIT_FOUND) #configure_file only detects changes to the input file, not changes to variable values being used (not surprising) #so, let the custom command that calls this script handle dependencies as to when it should run, then force it to run whenever this script is used by deleting the output first FILE(REMOVE ${OUTFILE}) CONFIGURE_FILE(${INFILE} ${OUTFILE} @ONLY) connectome-workbench-1.4.2/src/CMakeScripts/save.sh000077500000000000000000000011741360521144700222520ustar00rootroot00000000000000#/bin/sh -v set on echo "Current Directory" `pwd` if [ -f Debug/desktop.app/Contents/MacOS/desktop ] ; then # cp -R $QTDIR/src/gui/mac/qt_menu.nib Debug/desktop.app/Contents/Resources ; fi if [ -f Release/desktop.app/Contents/MacOS/desktop ] ; then echo "Exists" if [ ! -d Debug/desktop.app/Contents/Resources ] ; then mkdir Debug/desktop.app/Contents/Resources fi fi if [ -f RelWithDebInfo/desktop.app/Contents/MacOS/desktop ] ; then echo "Exists" fi if [ -f MinRelSize/desktop.app/Contents/MacOS/desktop ] ; then echo "Exists" fi if [ -f desktop.app/Contents/MacOS/desktop ] ; then echo "Exists" fi connectome-workbench-1.4.2/src/Charting/000077500000000000000000000000001360521144700201615ustar00rootroot00000000000000connectome-workbench-1.4.2/src/Charting/CMakeLists.txt000066400000000000000000000050221360521144700227200ustar00rootroot00000000000000 # # Name of Project # PROJECT(Charting) # # Qt include files # if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) endif() # # Create a library # ADD_LIBRARY(Charting ChartAxis.h ChartAxisCartesian.h ChartAxisLocationEnum.h ChartAxisTypeEnum.h ChartAxisUnitsEnum.h ChartData.h ChartDataCartesian.h ChartDataSource.h ChartDataSourceModeEnum.h ChartMatrixDisplayProperties.h ChartMatrixLoadingDimensionEnum.h ChartMatrixScaleModeEnum.h ChartModel.h ChartModelCartesian.h ChartModelDataSeries.h ChartModelFrequencySeries.h ChartModelTimeSeries.h ChartPoint.h ChartScaleAutoRanging.h ChartSelectionModeEnum.h ChartOneDataTypeEnum.h ChartingVersionEnum.h ChartTwoAxisScaleRangeModeEnum.h ChartTwoCartesianAxis.h ChartTwoCompoundDataType.h ChartTwoDataCartesian.h ChartTwoDataTypeEnum.h ChartTwoHistogramContentTypeEnum.h ChartTwoLineSeriesContentTypeEnum.h ChartTwoMatrixContentTypeEnum.h ChartTwoMatrixDisplayProperties.h ChartTwoMatrixLoadingDimensionEnum.h ChartTwoMatrixTriangularViewingModeEnum.h ChartTwoNumericSubdivisionsModeEnum.h ChartTwoLineSeriesHistory.h ChartTwoTitle.h EventChartTwoAttributesChanged.h EventChartTwoAxisGetDataRange.h EventChartTwoLoadLineSeriesData.h MapFileDataSelector.h ChartTwoAxisScaleRangeModeEnum.cxx ChartAxis.cxx ChartAxisCartesian.cxx ChartAxisLocationEnum.cxx ChartAxisTypeEnum.cxx ChartAxisUnitsEnum.cxx ChartData.cxx ChartDataCartesian.cxx ChartDataSource.cxx ChartDataSourceModeEnum.cxx ChartMatrixDisplayProperties.cxx ChartMatrixLoadingDimensionEnum.cxx ChartMatrixScaleModeEnum.cxx ChartModel.cxx ChartModelCartesian.cxx ChartModelDataSeries.cxx ChartModelFrequencySeries.cxx ChartModelTimeSeries.cxx ChartPoint.cxx ChartScaleAutoRanging.cxx ChartSelectionModeEnum.cxx ChartOneDataTypeEnum.cxx ChartingVersionEnum.cxx ChartTwoCartesianAxis.cxx ChartTwoCompoundDataType.cxx ChartTwoDataCartesian.cxx ChartTwoDataTypeEnum.cxx ChartTwoHistogramContentTypeEnum.cxx ChartTwoLineSeriesContentTypeEnum.cxx ChartTwoMatrixContentTypeEnum.cxx ChartTwoMatrixDisplayProperties.cxx ChartTwoMatrixLoadingDimensionEnum.cxx ChartTwoMatrixTriangularViewingModeEnum.cxx ChartTwoNumericSubdivisionsModeEnum.cxx ChartTwoLineSeriesHistory.cxx ChartTwoTitle.cxx EventChartTwoAttributesChanged.cxx EventChartTwoAxisGetDataRange.cxx EventChartTwoLoadLineSeriesData.cxx MapFileDataSelector.cxx ) TARGET_LINK_LIBRARIES(Charting ${CARET_QT5_LINK}) # # Include directories # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Annotations ${CMAKE_SOURCE_DIR}/Charting ${CMAKE_SOURCE_DIR}/Common ${CMAKE_SOURCE_DIR}/Graphics ${CMAKE_SOURCE_DIR}/Scenes ) connectome-workbench-1.4.2/src/Charting/ChartAxis.cxx000066400000000000000000000216701360521144700226010ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_AXIS_DECLARE__ #include "ChartAxis.h" #undef __CHART_AXIS_DECLARE__ #include "CaretAssert.h" #include "ChartAxisCartesian.h" #include "ChartScaleAutoRanging.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ChartAxis * \brief Contains information about a chart axis. * \ingroup Charting */ /** * Constructor. * * @param axisType * The axis type. * @param axisLocation. * Axis location. */ ChartAxis::ChartAxis(const ChartAxisTypeEnum::Enum axisType, const ChartAxisLocationEnum::Enum axisLocation) : CaretObject(), SceneableInterface(), m_axisType(axisType), m_axisLocation(axisLocation) { initializeMembersChartAxis(); } /** * Create and return an axis of the given type and at the given location. * * @param axisType * Type of axis. * @param axisLocation * Location of axis. * @return * Axis that was created. */ ChartAxis* ChartAxis::newChartAxisForTypeAndLocation(const ChartAxisTypeEnum::Enum axisType, const ChartAxisLocationEnum::Enum axisLocation) { ChartAxis* axis = NULL; switch (axisType) { case ChartAxisTypeEnum::CHART_AXIS_TYPE_CARTESIAN: axis = new ChartAxisCartesian(axisLocation); break; case ChartAxisTypeEnum::CHART_AXIS_TYPE_NONE: CaretAssert(0); break; } return axis; } /** * Destructor. */ ChartAxis::~ChartAxis() { delete m_sceneAssistant; } /** * Initialize members of a new instance. */ void ChartAxis::initializeMembersChartAxis() { m_parentChartModel = NULL; m_autoRangeScaleEnabled = true; m_axisUnits = ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE; m_labelFontSize = 12; m_visible = false; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_axisLocation", &m_axisLocation); m_sceneAssistant->add("m_autoRangeScaleEnabled", &m_autoRangeScaleEnabled); m_sceneAssistant->add("m_labelFontSize", &m_labelFontSize); m_sceneAssistant->add("m_visible", &m_visible); m_sceneAssistant->add("m_text", &m_text); } /** * Copy constructor. * @param obj * Object that is copied. */ ChartAxis::ChartAxis(const ChartAxis& obj) : CaretObject(obj), SceneableInterface(obj) { initializeMembersChartAxis(); copyHelperChartAxis(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ChartAxis& ChartAxis::operator=(const ChartAxis& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperChartAxis(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ChartAxis::copyHelperChartAxis(const ChartAxis& obj) { m_parentChartModel = NULL; m_axisType = obj.m_axisType; m_axisLocation = obj.m_axisLocation; m_text = obj.m_text; m_axisUnits = obj.m_axisUnits; m_labelFontSize = obj.m_labelFontSize; m_visible = obj.m_visible; m_autoRangeScaleEnabled = obj.m_autoRangeScaleEnabled; } /** * @return The type of the axis. */ ChartAxisTypeEnum::Enum ChartAxis::getAxisType() const { return m_axisType; } /** * @return The location of the axis. */ ChartAxisLocationEnum::Enum ChartAxis::getAxisLocation() const { return m_axisLocation; } /** * Set the parent chart model. * * @param parentChartModel * Chart in which this axis is used. */ void ChartAxis::setParentChartModel(ChartModel* parentChartModel) { m_parentChartModel = parentChartModel; } /** * @return The chart model that uses this axis (may be NULL). */ ChartModel* ChartAxis::getParentChartModel() { return m_parentChartModel; } /** * @return The chart model that uses this axis (may be NULL). */ const ChartModel* ChartAxis::getParentChartModel() const { return m_parentChartModel; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ChartAxis::toString() const { return "ChartAxis"; } /** * @return Text for axis label. */ AString ChartAxis::getText() const { return m_text; } /** * Set text for axis label. * * @param text * New text for label. */ void ChartAxis::setText(const AString& text) { m_text = text; } /** * @return Axis Units. */ ChartAxisUnitsEnum::Enum ChartAxis::getAxisUnits() const { return m_axisUnits; } /** * Set the units for the axis. * * @param axisUnits * New value for axis units. */ void ChartAxis::setAxisUnits(const ChartAxisUnitsEnum::Enum axisUnits) { m_axisUnits = axisUnits; } /** * Return the suffix for the axis units */ AString ChartAxis::getAxisUnitsSuffix() const { AString suffix; switch (m_axisUnits) { case ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE: break; case ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ: suffix = "hz"; break; case ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS: suffix = "s"; break; } return suffix; } /** * @return Font size for the label's text. */ int32_t ChartAxis::getLabelFontSize() const { return m_labelFontSize; } /** * Set font size for label's text. * * @param fontSize * New value for font size. */ void ChartAxis::setLabelFontSize(const float fontSize) { m_labelFontSize = static_cast(fontSize); } /** * @return True if this axis should be displayed. */ bool ChartAxis::isVisible() const { return m_visible; } /** * Set this axis should be displayed. * * @param visible * True if displayed, else false. */ void ChartAxis::setVisible(const bool visible) { m_visible = visible; } /** * Is auto range scale enabled (scale matches data) */ bool ChartAxis::isAutoRangeScaleEnabled() const { return m_autoRangeScaleEnabled; } /** * Set auto range scale enabled (scale matches data) * * @param autoRangeScaleEnabled * New status. */ void ChartAxis::setAutoRangeScaleEnabled(const bool autoRangeScaleEnabled) { m_autoRangeScaleEnabled = autoRangeScaleEnabled; if (m_autoRangeScaleEnabled) { updateForAutoRangeScale(); } } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of the class' instance. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* ChartAxis::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ChartAxis", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); saveSubClassDataToScene(sceneAttributes, sceneClass); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. May be NULL for some types of scenes. */ void ChartAxis::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); restoreSubClassDataFromScene(sceneAttributes, sceneClass); } connectome-workbench-1.4.2/src/Charting/ChartAxis.h000066400000000000000000000115721360521144700222260ustar00rootroot00000000000000#ifndef __CHART_AXIS_H__ #define __CHART_AXIS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "ChartAxisLocationEnum.h" #include "ChartAxisTypeEnum.h" #include "ChartAxisUnitsEnum.h" #include "SceneableInterface.h" namespace caret { class ChartModel; class SceneClassAssistant; class ChartAxis : public CaretObject, public SceneableInterface { public: enum Axis { AXIS_BOTTOM, AXIS_LEFT, AXIS_RIGHT, AXIS_TOP }; static ChartAxis* newChartAxisForTypeAndLocation(const ChartAxisTypeEnum::Enum axisType, const ChartAxisLocationEnum::Enum axisLocation); virtual ~ChartAxis(); ChartAxis(const ChartAxis&); ChartAxis& operator=(const ChartAxis&); /** * At times a copy of chart axis will be needed BUT it must be * the proper subclass so copy constructor and assignment operator * will function when this abstract, base class is used. Each * subclass will override this method so that the returned class * is of the proper type. * * @return Copy of this instance that is the actual subclass. */ virtual ChartAxis* clone() const = 0; void setParentChartModel(ChartModel* parentChartModel); ChartAxisTypeEnum::Enum getAxisType() const; ChartAxisLocationEnum::Enum getAxisLocation() const; AString getText() const; void setText(const AString& text); ChartAxisUnitsEnum::Enum getAxisUnits() const; void setAxisUnits(const ChartAxisUnitsEnum::Enum axisUnits); AString getAxisUnitsSuffix() const; int32_t getLabelFontSize() const; void setLabelFontSize(const float fontSize); bool isAutoRangeScaleEnabled() const; void setAutoRangeScaleEnabled(const bool autoRangeScaleEnabled); bool isVisible() const; void setVisible(const bool visible); /** * Update for auto range scale. */ virtual void updateForAutoRangeScale() = 0; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); protected: ChartAxis(const ChartAxisTypeEnum::Enum axisType, const ChartAxisLocationEnum::Enum axisLocation); ChartModel* getParentChartModel(); const ChartModel* getParentChartModel() const; virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) = 0; virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) = 0; private: void copyHelperChartAxis(const ChartAxis& obj); public: // ADD_NEW_METHODS_HERE virtual AString toString() const; private: void initializeMembersChartAxis(); ChartAxisTypeEnum::Enum m_axisType; ChartAxisLocationEnum::Enum m_axisLocation; ChartModel* m_parentChartModel; AString m_text; ChartAxisUnitsEnum::Enum m_axisUnits; int32_t m_labelFontSize; bool m_visible; bool m_autoRangeScaleEnabled; /** helps with scene save/restore */ SceneClassAssistant* m_sceneAssistant; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHART_AXIS_DECLARE__ // #endif // __CHART_AXIS_DECLARE__ } // namespace #endif //__CHART_AXIS_H__ connectome-workbench-1.4.2/src/Charting/ChartAxisCartesian.cxx000066400000000000000000000442561360521144700244400ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CHART_AXIS_CARTESIAN_DECLARE__ #include "ChartAxisCartesian.h" #undef __CHART_AXIS_CARTESIAN_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "ChartModelCartesian.h" #include "ChartScaleAutoRanging.h" #include "EventAlertUser.h" #include "EventManager.h" #include "MathFunctions.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ChartAxisCartesian * \brief Axes for Cartesian Data. * \ingroup Charting */ /** * Constructor. * * @param axisLocation. * Axis location. */ ChartAxisCartesian::ChartAxisCartesian(const ChartAxisLocationEnum::Enum axisLocation) : ChartAxis(ChartAxisTypeEnum::CHART_AXIS_TYPE_CARTESIAN, axisLocation) { initializeMembersChartAxisCartesian(); } /** * Destructor. */ ChartAxisCartesian::~ChartAxisCartesian() { delete m_sceneAssistant; } /** * Copy constructor. * @param obj * Object that is copied. */ ChartAxisCartesian::ChartAxisCartesian(const ChartAxisCartesian& obj) : ChartAxis(obj) { initializeMembersChartAxisCartesian(); this->copyHelperChartAxisCartesian(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ChartAxisCartesian& ChartAxisCartesian::operator=(const ChartAxisCartesian& obj) { if (this != &obj) { ChartAxis::operator=(obj); this->copyHelperChartAxisCartesian(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ChartAxisCartesian::copyHelperChartAxisCartesian(const ChartAxisCartesian& obj) { m_maximumValue = obj.m_maximumValue; m_minimumValue = obj.m_minimumValue; m_digitsRightOfDecimal = obj.m_digitsRightOfDecimal; } /** * Initialize class members. */ void ChartAxisCartesian::initializeMembersChartAxisCartesian() { m_minimumValue = 0.0; m_maximumValue = 1.0; m_digitsRightOfDecimal = 1; m_axisLabelsMinimumValue = 0.0; m_axisLabelsMaximumValue = 1.0; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_minimumValue", &m_minimumValue); m_sceneAssistant->add("m_maximumValue", &m_maximumValue); m_sceneAssistant->add("m_digitsRightOfDecimal", &m_digitsRightOfDecimal); m_sceneAssistant->add("m_axisLabelsMinimumValue", &m_axisLabelsMinimumValue); m_sceneAssistant->add("m_axisLabelsMaximumValue", &m_axisLabelsMaximumValue); } /** * @return Minimum value for axis. */ float ChartAxisCartesian::getMinimumValue() const { return m_minimumValue; } /** * Set minimum value for axis. * * @param minimumValue * New minimum value for axis. */ void ChartAxisCartesian::setMinimumValue(const float minimumValue) { m_minimumValue = minimumValue; } /** * @return Maximum value for axis. */ float ChartAxisCartesian::getMaximumValue() const { return m_maximumValue; } /** * Set maximum value for axis. * * @param maximumValue * New maximum value for axis. */ void ChartAxisCartesian::setMaximumValue(const float maximumValue) { m_maximumValue = maximumValue; } /** * Update for auto range scale. */ void ChartAxisCartesian::updateForAutoRangeScale() { if (isAutoRangeScaleEnabled()) { const ChartModel* chartModel = getParentChartModel(); CaretAssert(chartModel); const ChartModelCartesian* chartModelCartesian = dynamic_cast(chartModel); float minX, maxX, minY, maxY; chartModelCartesian->getBounds(minX, maxX, minY, maxY); float minValue = m_minimumValue; float maxValue = m_maximumValue; switch (getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: minValue = minX; maxValue = maxX; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: minValue = minY; maxValue = maxY; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: minValue = minY; maxValue = maxY; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: minValue = minX; maxValue = maxX; break; } m_minimumValue = minValue; m_maximumValue = maxValue; } double scaleStep = 0.0; double scaleMin = 0.0; double scaleMax = 0.0; int32_t digitsRightOfDecimal = 0; ChartScaleAutoRanging::createAutoScale(m_minimumValue, m_maximumValue, scaleMin, scaleMax, scaleStep, digitsRightOfDecimal); m_axisLabelsMinimumValue = scaleMin; m_axisLabelsMaximumValue = scaleMax; m_axisLabelsStepValue = scaleStep; m_digitsRightOfDecimal = digitsRightOfDecimal; /** * Use auto-scaled range for left and right axis */ if (isAutoRangeScaleEnabled()) { switch (getAxisLocation()) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: m_minimumValue = m_axisLabelsMinimumValue; m_maximumValue = m_axisLabelsMaximumValue; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: m_minimumValue = m_axisLabelsMinimumValue; m_maximumValue = m_axisLabelsMaximumValue; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: break; } } } /** * Get the axis labels and their positions for drawing the scale. * * @param axisLengthInPixels * Length of axis in pixels. * @param fontSizeInPixels * Size of the font in pixels. * @param labelOffsetInPixelsOut * Output containing offset in pixels for the scale labels. * @param labelTextOut * Output containing text for scale labels. */ void ChartAxisCartesian::getLabelsAndPositions(const float axisLengthInPixels, const float /*fontSizeInPixels*/, std::vector& labelOffsetInPixelsOut, std::vector& labelTextOut) { labelOffsetInPixelsOut.clear(); labelTextOut.clear(); if (axisLengthInPixels < 25.0) { return; } updateForAutoRangeScale(); float dataStart = m_minimumValue; float dataEnd = m_maximumValue; float dataRange = (m_maximumValue - m_minimumValue); if (dataRange <= 0.0) { return; } float labelsStart = m_axisLabelsMinimumValue; float labelsEnd = m_axisLabelsMaximumValue; /* * If the "labels end" or "labels start" value is not valid (infinity or not-a-number) there * are invalid values in the data and will cause the labels processing later * in this method to fail. So, alert the user that there is a problem in * the data. * * A set is used to track those models for which the user has * already been alerted. Otherwise, the alert message will be * displayed every time this method is called (which is many) and * the user will receive endless pop-ups. */ if ( (! MathFunctions::isNumeric(labelsStart)) || (! MathFunctions::isNumeric(labelsEnd))) { const ChartModel* chartModel = getParentChartModel(); CaretAssert(chartModel); const ChartModelCartesian* chartModelCartesian = dynamic_cast(chartModel); static std::set invalidChartModelCartesians; if (invalidChartModelCartesians.find(chartModelCartesian) == invalidChartModelCartesians.end()) { invalidChartModelCartesians.insert(chartModelCartesian); const AString msg("Invalid numbers (infinity or not-a-number) found when trying to create chart. " "Run \"wb_command -file-information\" on files being charted to find the file " "that contains invalid data so that the file can be fixed."); EventManager::get()->sendEvent(EventAlertUser(msg).getPointer()); } return; } float labelsRange = (m_axisLabelsMaximumValue - m_axisLabelsMinimumValue); if (labelsRange <= 0.0) { return; } const float tickLabelsStep = m_axisLabelsStepValue; if (tickLabelsStep <= 0.0) { return; } float labelValue = labelsStart; while (labelValue <= labelsEnd) { float labelParametricValue = (labelValue - dataStart) / dataRange; float labelValueForText = labelValue; if (dataRange >= 10.0) { /* * Is this the first label? */ if (labelValue <= labelsStart) { /* * Handles case when the minimum DATA value is just a little * bit greater than the minimum value for axis labels such * as in Data-Series data when the minimum data value is "1" * and the minimum axis label value is "0". Without this * code no value is displayed at the left edge of the axis. */ if (labelParametricValue < 0.0) { const float nextParametricValue = ((labelValue + tickLabelsStep) - dataStart) / dataRange; if (nextParametricValue > 0.05) { labelParametricValue = 0.0; labelValueForText = dataStart; } } } if (labelParametricValue < 0.0) { if (labelParametricValue >= -0.01) { labelParametricValue = 0.0; } } /* * Is this the last label? */ if (labelValue >= labelsEnd) { /* * Like above, ensures a value is displayed at the right * edge of the axis. */ if (labelParametricValue > 1.0) { const float prevParametricValue = ((labelValue - tickLabelsStep) - dataStart) / dataRange; if (prevParametricValue < 0.95) { labelParametricValue = 1.0; labelValueForText = dataEnd; } } } if (labelParametricValue > 1.0) { if (labelParametricValue < 1.01) { labelParametricValue = 1.0; } } } if ((labelParametricValue >= 0.0) && (labelParametricValue <= 1.0)) { const float labelPixelsPosition = axisLengthInPixels * labelParametricValue; const AString labelText = AString::number(labelValueForText, 'f', m_digitsRightOfDecimal); labelOffsetInPixelsOut.push_back(labelPixelsPosition); labelTextOut.push_back(labelText); } else { // std::cout << "Label value=" << labelValue << " parametric=" << labelParametricValue << " failed." << std::endl; } labelValue += tickLabelsStep; } } // 29 April 2014 ///** // * Get the axis labels and their positions for drawing the scale. // * // * @param axisLengthInPixels // * Length of axis in pixels. // * @param fontSizeInPixels // * Size of the font in pixels. // * @param labelOffsetInPixelsOut // * Output containing offset in pixels for the scale labels. // * @param labelTextOut // * Output containing text for scale labels. // */ //void //ChartAxisCartesian::getLabelsAndPositions(const float axisLengthInPixels, // const float /*fontSizeInPixels*/, // std::vector& labelOffsetInPixelsOut, // std::vector& labelTextOut) //{ // labelOffsetInPixelsOut.clear(); // labelTextOut.clear(); // // if (axisLengthInPixels < 25.0) { // return; // } // // updateForAutoRangeScale(); // // const float numberOfTicks = 5; // // float dataStart = m_minimumValue; // float dataEnd = m_maximumValue; // float dataRange = (m_maximumValue - m_minimumValue); // if (dataRange <= 0.0) { // return; // } // // float labelsStart = m_axisLabelsMinimumValue; // float labelsRange = (m_axisLabelsMaximumValue - m_axisLabelsMinimumValue); // if (labelsRange <= 0.0) { // return; // } // const float tickLabelsStep = labelsRange / numberOfTicks; // if (tickLabelsStep <= 0.0) { // return; // } // // float labelValue = labelsStart; // for (int32_t i = 0; i <= numberOfTicks; i++) { // float labelParametricValue = (labelValue - dataStart) / dataRange; // // float labelValueForText = labelValue; // // if (dataRange >= 10.0) { // if (i == 0) { // /* // * Handles case when the minimum DATA value is just a little // * bit greater than the minimum value for axis labels such // * as in Data-Series data when the minimum data value is "1" // * and the minimum axis label value is "0". Without this // * code no value is displayed at the left edge of the axis. // */ // if (labelParametricValue < 0.0) { // const float nextParametricValue = ((labelValue + tickLabelsStep) - dataStart) / dataRange; // if (nextParametricValue > 0.05) { // labelParametricValue = 0.0; // labelValueForText = dataStart; // } // } // } // // if (labelParametricValue < 0.0) { // if (labelParametricValue >= -0.01) { // labelParametricValue = 0.0; // } // } // // if (i == numberOfTicks) { // /* // * Like above, ensures a value is displayed at the right // * edge of the axis. // */ // if (labelParametricValue > 1.0) { // const float prevParametricValue = ((labelValue - tickLabelsStep) - dataStart) / dataRange; // if (prevParametricValue < 0.95) { // labelParametricValue = 1.0; // labelValueForText = dataEnd; // } // } // } // // if (labelParametricValue > 1.0) { // if (labelParametricValue < 1.01) { // labelParametricValue = 1.0; // } // } // } // // if ((labelParametricValue >= 0.0) // && (labelParametricValue <= 1.0)) { // const float labelPixelsPosition = axisLengthInPixels * labelParametricValue; // const AString labelText = AString::number(labelValueForText, 'f', m_digitsRightOfDecimal); // // labelOffsetInPixelsOut.push_back(labelPixelsPosition); // labelTextOut.push_back(labelText); // } // else { //// std::cout << "Label value=" << labelValue << " parametric=" << labelParametricValue << " failed." << std::endl; // } // // labelValue += tickLabelsStep; // } //} /** * At times a copy of chart data will be needed BUT it must be * the proper subclass so copy constructor and assignment operator * will no function when this abstract, base class is used. Each * subclass will override this method so that the returned class * is of the proper type. * * @return Copy of this instance that is the actual subclass. */ ChartAxis* ChartAxisCartesian::clone() const { ChartAxisCartesian* cloneCopy = new ChartAxisCartesian(*this); return cloneCopy; } /** * Save subclass data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void ChartAxisCartesian::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void ChartAxisCartesian::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } connectome-workbench-1.4.2/src/Charting/ChartAxisCartesian.h000066400000000000000000000060621360521144700240560ustar00rootroot00000000000000#ifndef __CHART_AXIS_CARTESIAN_H__ #define __CHART_AXIS_CARTESIAN_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ChartAxis.h" namespace caret { class ChartModelCartesian; class ChartAxisCartesian : public ChartAxis { public: virtual ~ChartAxisCartesian(); ChartAxisCartesian(const ChartAxisCartesian& obj); ChartAxisCartesian& operator=(const ChartAxisCartesian& obj); virtual ChartAxis* clone() const; float getMinimumValue() const; void setMinimumValue(const float minimumValue); float getMaximumValue() const; void setMaximumValue(const float maximumValue); void getLabelsAndPositions(const float axisLengthInPixels, const float fontSizeInPixels, std::vector& labelOffsetInPixelsOut, std::vector& labelTextOut); // ADD_NEW_METHODS_HERE protected: ChartAxisCartesian(const ChartAxisLocationEnum::Enum axisLocation); virtual void updateForAutoRangeScale(); virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: void copyHelperChartAxisCartesian(const ChartAxisCartesian& obj); void initializeMembersChartAxisCartesian(); SceneClassAssistant* m_sceneAssistant; mutable float m_maximumValue; mutable float m_minimumValue; mutable int32_t m_digitsRightOfDecimal; mutable float m_axisLabelsMinimumValue; mutable float m_axisLabelsMaximumValue; mutable float m_axisLabelsStepValue; // ADD_NEW_MEMBERS_HERE friend class ChartAxis; }; #ifdef __CHART_AXIS_CARTESIAN_DECLARE__ // #endif // __CHART_AXIS_CARTESIAN_DECLARE__ } // namespace #endif //__CHART_AXIS_CARTESIAN_H__ connectome-workbench-1.4.2/src/Charting/ChartAxisLocationEnum.cxx000066400000000000000000000276021360521144700251200ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CHART_AXIS_LOCATION_ENUM_DECLARE__ #include "ChartAxisLocationEnum.h" #undef __CHART_AXIS_LOCATION_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartAxisLocationEnum * \brief Location of a chart axis. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_chartAxisLocationEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void chartAxisLocationEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ChartAxisLocationEnum.h" * * Instatiate: * m_chartAxisLocationEnumComboBox = new EnumComboBoxTemplate(this); * m_chartAxisLocationEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_chartAxisLocationEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(chartAxisLocationEnumComboBoxItemActivated())); * * Update the selection: * m_chartAxisLocationEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ChartAxisLocationEnum::Enum VARIABLE = m_chartAxisLocationEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ChartAxisLocationEnum::ChartAxisLocationEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ChartAxisLocationEnum::~ChartAxisLocationEnum() { } /** * Initialize the enumerated metadata. */ void ChartAxisLocationEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ChartAxisLocationEnum(CHART_AXIS_LOCATION_BOTTOM, "CHART_AXIS_LOCATION_BOTTOM", "Bottom")); enumData.push_back(ChartAxisLocationEnum(CHART_AXIS_LOCATION_LEFT, "CHART_AXIS_LOCATION_LEFT", "Left")); enumData.push_back(ChartAxisLocationEnum(CHART_AXIS_LOCATION_RIGHT, "CHART_AXIS_LOCATION_RIGHT", "Right")); enumData.push_back(ChartAxisLocationEnum(CHART_AXIS_LOCATION_TOP, "CHART_AXIS_LOCATION_TOP", "Top")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ChartAxisLocationEnum* ChartAxisLocationEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ChartAxisLocationEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartAxisLocationEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartAxisLocationEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartAxisLocationEnum::Enum ChartAxisLocationEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartAxisLocationEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartAxisLocationEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartAxisLocationEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartAxisLocationEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartAxisLocationEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartAxisLocationEnum::Enum ChartAxisLocationEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartAxisLocationEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartAxisLocationEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartAxisLocationEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ChartAxisLocationEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartAxisLocationEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ChartAxisLocationEnum::Enum ChartAxisLocationEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartAxisLocationEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartAxisLocationEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartAxisLocationEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ChartAxisLocationEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartAxisLocationEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ChartAxisLocationEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartAxisLocationEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ChartAxisLocationEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } /** * Get the opposite axis for the given axis (left <--> right; top <--> bottom). * * @param axis * The axis. * @return * Opposite axis. */ ChartAxisLocationEnum::Enum ChartAxisLocationEnum::getOppositeAxis(const ChartAxisLocationEnum::Enum axis) { ChartAxisLocationEnum::Enum oppositeAxis = ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM; switch (axis) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: oppositeAxis = ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: oppositeAxis = ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: oppositeAxis = ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: oppositeAxis = ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM; break; } return oppositeAxis; } connectome-workbench-1.4.2/src/Charting/ChartAxisLocationEnum.h000066400000000000000000000065301360521144700245420ustar00rootroot00000000000000#ifndef __CHART_AXIS_LOCATION_ENUM_H__ #define __CHART_AXIS_LOCATION_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ChartAxisLocationEnum { public: /** * Enumerated values. */ enum Enum { /** Axis at bottom */ CHART_AXIS_LOCATION_BOTTOM, /** Axis at left */ CHART_AXIS_LOCATION_LEFT, /** Axis at right */ CHART_AXIS_LOCATION_RIGHT, /** Axis at top */ CHART_AXIS_LOCATION_TOP }; ~ChartAxisLocationEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); static ChartAxisLocationEnum::Enum getOppositeAxis(const ChartAxisLocationEnum::Enum axis); private: ChartAxisLocationEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ChartAxisLocationEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __CHART_AXIS_LOCATION_ENUM_DECLARE__ std::vector ChartAxisLocationEnum::enumData; bool ChartAxisLocationEnum::initializedFlag = false; int32_t ChartAxisLocationEnum::integerCodeCounter = 0; #endif // __CHART_AXIS_LOCATION_ENUM_DECLARE__ } // namespace #endif //__CHART_AXIS_LOCATION_ENUM_H__ connectome-workbench-1.4.2/src/Charting/ChartAxisTypeEnum.cxx000066400000000000000000000243621360521144700242710ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CHART_AXIS_TYPE_ENUM_DECLARE__ #include "ChartAxisTypeEnum.h" #undef __CHART_AXIS_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartAxisTypeEnum * \brief Type for a chart axis. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_chartAxisTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void chartAxisTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ChartAxisTypeEnum.h" * * Instatiate: * m_chartAxisTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_chartAxisTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_chartAxisTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(chartAxisTypeEnumComboBoxItemActivated())); * * Update the selection: * m_chartAxisTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ChartAxisTypeEnum::Enum VARIABLE = m_chartAxisTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ChartAxisTypeEnum::ChartAxisTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ChartAxisTypeEnum::~ChartAxisTypeEnum() { } /** * Initialize the enumerated metadata. */ void ChartAxisTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ChartAxisTypeEnum(CHART_AXIS_TYPE_NONE, "CHART_AXIS_TYPE_NONE", "None Axis")); enumData.push_back(ChartAxisTypeEnum(CHART_AXIS_TYPE_CARTESIAN, "CHART_AXIS_TYPE_CARTESIAN", "Cartesian Axis")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ChartAxisTypeEnum* ChartAxisTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ChartAxisTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartAxisTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartAxisTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartAxisTypeEnum::Enum ChartAxisTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartAxisTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartAxisTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartAxisTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartAxisTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartAxisTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartAxisTypeEnum::Enum ChartAxisTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartAxisTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartAxisTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartAxisTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ChartAxisTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartAxisTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ChartAxisTypeEnum::Enum ChartAxisTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartAxisTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartAxisTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartAxisTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ChartAxisTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartAxisTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ChartAxisTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartAxisTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ChartAxisTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Charting/ChartAxisTypeEnum.h000066400000000000000000000060651360521144700237160ustar00rootroot00000000000000#ifndef __CHART_AXIS_TYPE_ENUM_H__ #define __CHART_AXIS_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ChartAxisTypeEnum { public: /** * Enumerated values. */ enum Enum { /** No Type */ CHART_AXIS_TYPE_NONE, /** Cartesian Data */ CHART_AXIS_TYPE_CARTESIAN }; ~ChartAxisTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ChartAxisTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ChartAxisTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __CHART_AXIS_TYPE_ENUM_DECLARE__ std::vector ChartAxisTypeEnum::enumData; bool ChartAxisTypeEnum::initializedFlag = false; int32_t ChartAxisTypeEnum::integerCodeCounter = 0; #endif // __CHART_AXIS_TYPE_ENUM_DECLARE__ } // namespace #endif //__CHART_AXIS_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Charting/ChartAxisUnitsEnum.cxx000066400000000000000000000250411360521144700244450ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CHART_AXIS_UNITS_ENUM_DECLARE__ #include "ChartAxisUnitsEnum.h" #undef __CHART_AXIS_UNITS_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartAxisUnitsEnum * \brief Units for chart axes * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_chartDataAxisUnitsEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void chartDataAxisUnitsEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ChartAxisUnitsEnum.h" * * Instatiate: * m_chartDataAxisUnitsEnumComboBox = new EnumComboBoxTemplate(this); * m_chartDataAxisUnitsEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_chartDataAxisUnitsEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(chartDataAxisUnitsEnumComboBoxItemActivated())); * * Update the selection: * m_chartDataAxisUnitsEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ChartAxisUnitsEnum::Enum VARIABLE = m_chartDataAxisUnitsEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ChartAxisUnitsEnum::ChartAxisUnitsEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ChartAxisUnitsEnum::~ChartAxisUnitsEnum() { } /** * Initialize the enumerated metadata. */ void ChartAxisUnitsEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ChartAxisUnitsEnum(CHART_AXIS_UNITS_NONE, "CHART_AXIS_UNITS_NONE", "None")); enumData.push_back(ChartAxisUnitsEnum(CHART_AXIS_UNITS_FREQUENCY_HERTZ, "CHART_AXIS_UNITS_FREQUENCY_HERTZ", "Frequency")); enumData.push_back(ChartAxisUnitsEnum(CHART_AXIS_UNITS_TIME_SECONDS, "CHART_AXIS_UNITS_TIME_SECONDS", "Time")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ChartAxisUnitsEnum* ChartAxisUnitsEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ChartAxisUnitsEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartAxisUnitsEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartAxisUnitsEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartAxisUnitsEnum::Enum ChartAxisUnitsEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartAxisUnitsEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartAxisUnitsEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartAxisUnitsEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartAxisUnitsEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartAxisUnitsEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartAxisUnitsEnum::Enum ChartAxisUnitsEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartAxisUnitsEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartAxisUnitsEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartAxisUnitsEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ChartAxisUnitsEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartAxisUnitsEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ChartAxisUnitsEnum::Enum ChartAxisUnitsEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartAxisUnitsEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartAxisUnitsEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartAxisUnitsEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ChartAxisUnitsEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartAxisUnitsEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ChartAxisUnitsEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartAxisUnitsEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ChartAxisUnitsEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Charting/ChartAxisUnitsEnum.h000066400000000000000000000062161360521144700240750ustar00rootroot00000000000000#ifndef __CHART_AXIS_UNITS_ENUM_H__ #define __CHART_AXIS_UNITS_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ChartAxisUnitsEnum { public: /** * Enumerated values. */ enum Enum { /** No units */ CHART_AXIS_UNITS_NONE, /** Frequency units */ CHART_AXIS_UNITS_FREQUENCY_HERTZ, /** Time units */ CHART_AXIS_UNITS_TIME_SECONDS }; ~ChartAxisUnitsEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ChartAxisUnitsEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ChartAxisUnitsEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __CHART_AXIS_UNITS_ENUM_DECLARE__ std::vector ChartAxisUnitsEnum::enumData; bool ChartAxisUnitsEnum::initializedFlag = false; int32_t ChartAxisUnitsEnum::integerCodeCounter = 0; #endif // __CHART_AXIS_UNITS_ENUM_DECLARE__ } // namespace #endif //__CHART_AXIS_UNITS_ENUM_H__ connectome-workbench-1.4.2/src/Charting/ChartData.cxx000066400000000000000000000213631360521144700225450ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_DATA_DECLARE__ #include "ChartData.h" #undef __CHART_DATA_DECLARE__ #include "CaretAssert.h" #include "ChartDataCartesian.h" #include "ChartDataSource.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "SystemUtilities.h" using namespace caret; /** * \class caret::ChartData * \brief Base class for chart data. * \ingroup Charting */ /** * Constructor. * * @param chartDataType * Type of chart model. */ ChartData::ChartData(const ChartOneDataTypeEnum::Enum chartDataType) : CaretObject(), SceneableInterface(), m_chartDataType(chartDataType) { initializeMembersChartData(); } /** * Destructor. */ ChartData::~ChartData() { delete m_sceneAssistant; delete m_chartDataSource; } /** * Initialize members of a new instance. */ void ChartData::initializeMembersChartData() { m_chartDataSource = new ChartDataSource(); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_selectionStatus[i] = true; } m_uniqueIdentifier = SystemUtilities::createUniqueID(); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_chartDataSource", "ChartDataSource", m_chartDataSource); m_sceneAssistant->addTabIndexedBooleanArray("m_selectionStatus", m_selectionStatus); m_sceneAssistant->add("m_uniqueIdentifier", &m_uniqueIdentifier); } /** * Copy constructor. * @param obj * Object that is copied. */ ChartData::ChartData(const ChartData& obj) : CaretObject(obj), SceneableInterface(obj), m_chartDataType(obj.m_chartDataType) { initializeMembersChartData(); this->copyHelperChartData(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ChartData& ChartData::operator=(const ChartData& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperChartData(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ChartData::copyHelperChartData(const ChartData& obj) { CaretAssert(0); m_chartDataType = obj.m_chartDataType; *m_chartDataSource = *obj.m_chartDataSource; for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_selectionStatus[i] = obj.m_selectionStatus[i]; } } /** * Create a new instance of a chart for the given data type. * * @param chartDataType * Type of chart data. * @return * Pointer to new instance. */ ChartData* ChartData::newChartDataForChartDataType(const ChartOneDataTypeEnum::Enum chartDataType) { ChartData* chartData = NULL; switch (chartDataType) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: CaretAssert(0); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: CaretAssert(0); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: chartData = new ChartDataCartesian(chartDataType, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: chartData = new ChartDataCartesian(chartDataType, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: chartData = new ChartDataCartesian(chartDataType, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS); break; } return chartData; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* ChartData::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ChartData", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); saveSubClassDataToScene(sceneAttributes, sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ChartData::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); restoreSubClassDataFromScene(sceneAttributes, sceneClass); } /** * @return The chart data model type. */ ChartOneDataTypeEnum::Enum ChartData::getChartDataType() const { return m_chartDataType; } /** * @return The source of the chart data (const method). */ const ChartDataSource* ChartData::getChartDataSource() const { return m_chartDataSource; } /** * @return The source of the chart data. */ ChartDataSource* ChartData::getChartDataSource() { return m_chartDataSource; } /** * @return The selection status in the given tab * @param tabIndex * Index of the tab. */ bool ChartData::isSelected(const int32_t tabIndex) const { CaretAssertArrayIndex(m_selectionStatus, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_selectionStatus[tabIndex]; } /** * Set the selection status. * * @param selectionStatus * New selection status. */ void ChartData::setSelected(const int32_t tabIndex, const bool selectionStatus) { CaretAssertArrayIndex(m_selectionStatus, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_selectionStatus[tabIndex] = selectionStatus; /* * When selection status is true, * notify parent. */ // if (m_selectionStatus[tabIndex]) { // if (m_parentChartModel != NULL) { // m_parentChartModel->childChartDataSelectionChanged(this); // } // } } /** * Copy the selection status for all tabs from the given chart data to me. * * @param copyFrom * Chart data from which selection status is copied. */ void ChartData::copySelectionStatusForAllTabs(const ChartData* copyFrom) { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_selectionStatus[i] = copyFrom->m_selectionStatus[i]; } } /** * @return The Unique Identifier (UUID). */ AString ChartData::getUniqueIdentifier() const { return m_uniqueIdentifier; } /** * Set the unique identifier. * * @param uniqueIdentifier * The new unique identifier. */ void ChartData::setUniqueIdentifier(const AString& uniqueIdentifier) { m_uniqueIdentifier = uniqueIdentifier; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ChartData::toString() const { return "ChartData"; } connectome-workbench-1.4.2/src/Charting/ChartData.h000066400000000000000000000116511360521144700221710ustar00rootroot00000000000000#ifndef __CHART_DATA_H__ #define __CHART_DATA_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "CaretObject.h" #include "ChartOneDataTypeEnum.h" #include "SceneableInterface.h" namespace caret { class ChartDataSource; class SceneClassAssistant; class ChartData : public CaretObject, public SceneableInterface { public: static ChartData* newChartDataForChartDataType(const ChartOneDataTypeEnum::Enum chartDataType); virtual ~ChartData(); /** * At times a copy of chart data will be needed BUT it must be * the proper subclass so copy constructor and assignment operator * will function when this abstract, base class is used. Each * subclass will override this method so that the returned class * is of the proper type. * * @return Copy of this instance that is the actual subclass. */ virtual ChartData* clone() const = 0; ChartOneDataTypeEnum::Enum getChartDataType() const; const ChartDataSource* getChartDataSource() const; ChartDataSource* getChartDataSource(); bool isSelected(const int32_t tabIndex) const; void setSelected(const int32_t tabIndex, const bool selectionStatus); void clearSelected(); AString getUniqueIdentifier() const; void setUniqueIdentifier(const AString& uniqueIdentifier); void copySelectionStatusForAllTabs(const ChartData* copyFrom); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // ADD_NEW_METHODS_HERE virtual AString toString() const; protected: ChartData(const ChartOneDataTypeEnum::Enum chartDataType); ChartData(const ChartData& obj); ChartData& operator=(const ChartData& obj); /** * Save subclass data to the scene. sceneClass * will be valid and any scene data should be added to it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. */ virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) = 0; /** * Restore file data from the scene. The scene class * will be valid and any scene data may be obtained from it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) = 0; private: void initializeMembersChartData(); void copyHelperChartData(const ChartData& obj); SceneClassAssistant* m_sceneAssistant; ChartOneDataTypeEnum::Enum m_chartDataType; ChartDataSource* m_chartDataSource; bool m_selectionStatus[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; AString m_uniqueIdentifier; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHART_DATA_DECLARE__ // #endif // __CHART_DATA_DECLARE__ } // namespace #endif //__CHART_DATA_H__ connectome-workbench-1.4.2/src/Charting/ChartDataCartesian.cxx000066400000000000000000000325361360521144700244030ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_DATA_CARTESIAN_DECLARE__ #include "ChartDataCartesian.h" #undef __CHART_DATA_CARTESIAN_DECLARE__ #include #include #include "CaretAssert.h" #include "ChartPoint.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ChartDataCartesian * \brief Chart cartesian data. * \ingroup Charting */ /** * Constructor. * * @param chartDataType * Type of chart data model. * @param dataAxisUnitsX * Data units for X-axis. * @param dataAxisUnitsY * Data units for Y-axis. */ ChartDataCartesian::ChartDataCartesian(const ChartOneDataTypeEnum::Enum chartDataType, const ChartAxisUnitsEnum::Enum dataAxisUnitsX, const ChartAxisUnitsEnum::Enum dataAxisUnitsY) : ChartData(chartDataType), m_dataAxisUnitsX(dataAxisUnitsX), m_dataAxisUnitsY(dataAxisUnitsY) { initializeMembersChartDataCartesian(); } /** * Destructor. */ ChartDataCartesian::~ChartDataCartesian() { removeAllPoints(); delete m_sceneAssistant; } /** * Initialize members of a new instance. */ void ChartDataCartesian::initializeMembersChartDataCartesian() { m_boundsValid = false; m_color = CaretColorEnum::RED; m_timeStartInSecondsAxisX = 0.0; m_timeStepInSecondsAxisX = 1.0; std::vector colorEnums; CaretColorEnum::getColorEnums(colorEnums); const int32_t numCaretColors = static_cast(colorEnums.size()); bool colorFound = false; while ( ! colorFound) { ChartDataCartesian::caretColorIndex++; if (ChartDataCartesian::caretColorIndex >= numCaretColors) { ChartDataCartesian::caretColorIndex = 0; } if (colorEnums[ChartDataCartesian::caretColorIndex] == CaretColorEnum::BLACK) { /* do not use black */ } else if (colorEnums[ChartDataCartesian::caretColorIndex] == CaretColorEnum::WHITE) { /* do not use white */ } else { m_color = colorEnums[ChartDataCartesian::caretColorIndex]; colorFound = true; } } m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_dataAxisUnitsX", &m_dataAxisUnitsX); m_sceneAssistant->add("m_dataAxisUnitsY", &m_dataAxisUnitsY); m_sceneAssistant->add("m_color", &m_color); m_sceneAssistant->add("m_timeStartInSecondsAxisX", &m_timeStartInSecondsAxisX); m_sceneAssistant->add("m_timeStepInSecondsAxisX", &m_timeStepInSecondsAxisX); } /** * Remove all points in the model. */ void ChartDataCartesian::removeAllPoints() { for (std::vector::const_iterator iter = m_points.begin(); iter != m_points.end(); iter++) { delete *iter; } m_points.clear(); m_boundsValid = false; } /** * At times a copy of chart data will be needed BUT it must be * the proper subclass so copy constructor and assignment operator * will no function when this abstract, base class is used. Each * subclass will override this method so that the returned class * is of the proper type. * * @return Copy of this instance that is the actual subclass. */ ChartData* ChartDataCartesian::clone() const { ChartDataCartesian* cloneCopy = new ChartDataCartesian(*this); return cloneCopy; } /** * Copy constructor. * @param obj * Object that is copied. */ ChartDataCartesian::ChartDataCartesian(const ChartDataCartesian& obj) : ChartData(obj), m_dataAxisUnitsX(obj.m_dataAxisUnitsX), m_dataAxisUnitsY(obj.m_dataAxisUnitsY) { initializeMembersChartDataCartesian(); this->copyHelperChartDataCartesian(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ChartDataCartesian& ChartDataCartesian::operator=(const ChartDataCartesian& obj) { if (this != &obj) { ChartData::operator=(obj); this->copyHelperChartDataCartesian(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ChartDataCartesian::copyHelperChartDataCartesian(const ChartDataCartesian& obj) { CaretAssert(0); m_dataAxisUnitsX = obj.m_dataAxisUnitsX; m_dataAxisUnitsY = obj.m_dataAxisUnitsY; removeAllPoints(); for (std::vector::const_iterator iter = obj.m_points.begin(); iter != obj.m_points.end(); iter++) { const ChartPoint* cp = *iter; m_points.push_back(new ChartPoint(*cp)); } m_boundsValid = false; m_color = obj.m_color; m_timeStartInSecondsAxisX = obj.m_timeStartInSecondsAxisX; m_timeStepInSecondsAxisX = obj.m_timeStepInSecondsAxisX; } /** * Add a point. * * @param x * X-coordinate. * @param y * Y-coordinate. */ void ChartDataCartesian::addPoint(const float x, const float y) { m_points.push_back(new ChartPoint(x, y)); m_boundsValid = false; } /** * @return Number of points. */ int32_t ChartDataCartesian::getNumberOfPoints() const { return m_points.size(); } /** * Get the point at the given index. * * @param pointIndex * Index of point. * @return * Point at the given index. */ const ChartPoint* ChartDataCartesian::getPointAtIndex(const int32_t pointIndex) const { CaretAssertVectorIndex(m_points, pointIndex); return m_points[pointIndex]; } /** * Get the bounds of all of the points. * * @param xMinimumOut * Minimum X-coordinate of all points. * @param xMaximumOut * Maximum X-coordinate of all points. * @param yMinimumOut * Minimum Y-coordinate of all points. * @param yMaximumOut * Maximum Y-coordinate of all points. */ void ChartDataCartesian::getBounds(float& xMinimumOut, float& xMaximumOut, float& yMinimumOut, float& yMaximumOut) const { if (! m_boundsValid) { float xMin = 0.0; float xMax = 0.0; float yMin = 0.0; float yMax = 0.0; float zMin = 0.0; float zMax = 0.0; const int32_t numPoints = getNumberOfPoints(); if (numPoints > 0) { xMin = std::numeric_limits::max(); xMax = -std::numeric_limits::max(); yMin = std::numeric_limits::max(); yMax = -std::numeric_limits::max(); for (int32_t i = 0; i < numPoints; i++) { const float* xy = getPointAtIndex(i)->getXY(); const float x = xy[0]; const float y = xy[1]; if (x < xMin) xMin = x; if (x > xMax) xMax = x; if (y < yMin) yMin = y; if (y > yMax) yMax = y; } m_boundsValid = true; } m_bounds[0] = xMin; m_bounds[1] = xMax; m_bounds[2] = yMin; m_bounds[3] = yMax; m_bounds[4] = zMin; m_bounds[5] = zMax; } xMinimumOut = m_bounds[0]; xMaximumOut = m_bounds[1]; yMinimumOut = m_bounds[2]; yMaximumOut = m_bounds[3]; } /** * @return The time start in seconds for the X-Axis (Valid when * the X-axis is time) */ float ChartDataCartesian::getTimeStartInSecondsAxisX() const { return m_timeStartInSecondsAxisX; } /** * Set the time start in seconds for the X-Axis (Valid when * the X-axis is time) * * @param timeStartInSecondsAxisX * Time of first point in the X-axis. */ void ChartDataCartesian::setTimeStartInSecondsAxisX(const float timeStartInSecondsAxisX) { m_timeStartInSecondsAxisX = timeStartInSecondsAxisX; } /** * @return The time step in seconds for the X-Axis (Valid when * the X-axis is time) */ float ChartDataCartesian::getTimeStepInSecondsAxisX() const { return m_timeStepInSecondsAxisX; } /** * Set the time step in seconds for the X-Axis (Valid when * the X-axis is time) * * @param timeStepInSecondsAxisX * Number of seconds between consecutive points in X-axis. */ void ChartDataCartesian::setTimeStepInSecondsAxisX(const float timeStepInSecondsAxisX) { m_timeStepInSecondsAxisX = timeStepInSecondsAxisX; } /** * @return Data units for X axis */ ChartAxisUnitsEnum::Enum ChartDataCartesian::getDataAxisUnitsX() { return m_dataAxisUnitsX; } /** * @return Data units for Y axis */ ChartAxisUnitsEnum::Enum ChartDataCartesian::getDataAxisUnitsY() { return m_dataAxisUnitsY; } /** * @return Color for chart */ CaretColorEnum::Enum ChartDataCartesian::getColor() const { return m_color; } /** * Set the color for the chart. * * @param color * New color for chart. */ void ChartDataCartesian::setColor(const CaretColorEnum::Enum color) { m_color = color; } /** * Save subclass data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void ChartDataCartesian::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { SceneClass* chartDataCartesian = new SceneClass("chartDataCartesian", "ChartDataCartesian", 1); m_sceneAssistant->saveMembers(sceneAttributes, chartDataCartesian); const int32_t numPoints2D = getNumberOfPoints(); if (numPoints2D > 0) { chartDataCartesian->addInteger("numberOfPoints2D", numPoints2D); AString pointString; pointString.reserve(numPoints2D * 2 * 10); QTextStream textStream(&pointString, QIODevice::WriteOnly); for (int32_t i = 0; i < numPoints2D; i++) { const float* xy = m_points[i]->getXY(); textStream << xy[0] << " " << xy[1] << " "; } chartDataCartesian->addString("points2D", pointString); } sceneClass->addClass(chartDataCartesian); } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void ChartDataCartesian::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { removeAllPoints(); const SceneClass* chartDataCartesian = sceneClass->getClass("chartDataCartesian"); if (chartDataCartesian == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, chartDataCartesian); const int32_t numPoints2D = chartDataCartesian->getIntegerValue("numberOfPoints2D", -1); if (numPoints2D > 0) { AString pointString = chartDataCartesian->getStringValue("points2D", ""); if ( ! pointString.isEmpty()) { float x, y; QTextStream textStream(&pointString, QIODevice::ReadOnly); for (int32_t i = 0; i < numPoints2D; i++) { if (textStream.atEnd()) { sceneAttributes->addToErrorMessage("Tried to read " + AString::number(numPoints2D) + " but only got " + AString::number(i)); break; } textStream >> x; textStream >> y; m_points.push_back(new ChartPoint(x, y)); } } } } connectome-workbench-1.4.2/src/Charting/ChartDataCartesian.h000066400000000000000000000074101360521144700240210ustar00rootroot00000000000000#ifndef __CHART_DATA_CARTESIAN_H__ #define __CHART_DATA_CARTESIAN_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretColorEnum.h" #include "ChartAxisUnitsEnum.h" #include "ChartData.h" namespace caret { class ChartPoint; class ChartDataCartesian : public ChartData { public: ChartDataCartesian(const ChartOneDataTypeEnum::Enum chartDataType, const ChartAxisUnitsEnum::Enum dataAxisUnitsX, const ChartAxisUnitsEnum::Enum dataAxisUnitsY); virtual ~ChartDataCartesian(); virtual ChartData* clone() const; void addPoint(const float x, const float y); int32_t getNumberOfPoints() const; const ChartPoint* getPointAtIndex(const int32_t pointIndex) const; void getBounds(float& xMinimumOut, float& xMaximumOut, float& yMinimumOut, float& yMaximumOut) const; ChartAxisUnitsEnum::Enum getDataAxisUnitsX(); ChartAxisUnitsEnum::Enum getDataAxisUnitsY(); CaretColorEnum::Enum getColor() const; void setColor(const CaretColorEnum::Enum color); float getTimeStartInSecondsAxisX() const; void setTimeStartInSecondsAxisX(const float timeStart); float getTimeStepInSecondsAxisX() const; void setTimeStepInSecondsAxisX(const float timeStep); // ADD_NEW_METHODS_HERE protected: virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: ChartDataCartesian(const ChartDataCartesian& obj); ChartDataCartesian& operator=(const ChartDataCartesian& obj); void copyHelperChartDataCartesian(const ChartDataCartesian& obj); void initializeMembersChartDataCartesian(); void removeAllPoints(); std::vector m_points; mutable float m_bounds[6]; mutable bool m_boundsValid; ChartAxisUnitsEnum::Enum m_dataAxisUnitsX; ChartAxisUnitsEnum::Enum m_dataAxisUnitsY; CaretColorEnum::Enum m_color; float m_timeStartInSecondsAxisX; float m_timeStepInSecondsAxisX; static int32_t caretColorIndex; SceneClassAssistant* m_sceneAssistant; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHART_DATA_CARTESIAN_DECLARE__ int32_t ChartDataCartesian::caretColorIndex = 0; #endif // __CHART_DATA_CARTESIAN_DECLARE__ } // namespace #endif //__CHART_DATA_CARTESIAN_H__ connectome-workbench-1.4.2/src/Charting/ChartDataSource.cxx000066400000000000000000000455171360521144700237350ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __CHART_DATA_SOURCE_DECLARE__ #include "ChartDataSource.h" #undef __CHART_DATA_SOURCE_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "FileInformation.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ChartDataSource * \brief Contains source of data that is displayed in a chart. * \ingroup Charting */ /** * Constructor. */ ChartDataSource::ChartDataSource() : CaretObject(), SceneableInterface() { initializeMembersChartDataSource(); } /** * Destructor. */ ChartDataSource::~ChartDataSource() { delete m_sceneAssistant; } /** * Initialize members of a new instance. */ void ChartDataSource::initializeMembersChartDataSource() { m_dataSourceMode = ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_INVALID; m_nodeIndex = -1; m_voxelXYZ[0] = 0.0; m_voxelXYZ[1] = 0.0; m_voxelXYZ[2] = 0.0; m_fileRowIndex = -1; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_dataSourceMode", &m_dataSourceMode); m_sceneAssistant->add("m_nodeIndex", &m_nodeIndex); m_sceneAssistant->add("m_surfaceNumberOfNodes", &m_surfaceNumberOfNodes); m_sceneAssistant->add("m_surfaceStructureName", &m_surfaceStructureName); m_sceneAssistant->addArray("m_voxelXYZ", m_voxelXYZ, 3, -1); m_sceneAssistant->add("m_fileRowIndex", &m_fileRowIndex); } /** * Copy constructor. * @param obj * Object that is copied. */ ChartDataSource::ChartDataSource(const ChartDataSource& obj) : CaretObject(obj), SceneableInterface(obj) { initializeMembersChartDataSource(); this->copyHelperChartDataSource(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ChartDataSource& ChartDataSource::operator=(const ChartDataSource& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperChartDataSource(obj); } return *this; } /** * Equality operator. * * @param rhs * Other item for comparison. */ bool ChartDataSource::operator==(const ChartDataSource& rhs) const { if (this == &rhs) { return true; } if (m_chartableFileName != rhs.m_chartableFileName) { return false; } switch (m_dataSourceMode) { case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_FILE_ROW: if (m_fileRowIndex == rhs.m_fileRowIndex) { return true; } break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_INVALID: break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDEX: if ((m_surfaceStructureName == rhs.m_surfaceStructureName) && (m_surfaceNumberOfNodes == rhs.m_surfaceNumberOfNodes) && (m_nodeIndex == rhs.m_nodeIndex)) { return true; } break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDICES_AVERAGE: if ((m_surfaceStructureName == rhs.m_surfaceStructureName) && (m_surfaceNumberOfNodes == rhs.m_surfaceNumberOfNodes) && (m_nodeIndicesAverage == rhs.m_nodeIndicesAverage)) { return true; } break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_VOXEL_IJK: if ((m_voxelXYZ[0] == rhs.m_voxelXYZ[0]) && (m_voxelXYZ[1] == rhs.m_voxelXYZ[1]) && (m_voxelXYZ[2] == rhs.m_voxelXYZ[2])) { return true; } break; } return false; } /** * Equality operator. * * @param rhs * Other item for comparison. */ bool ChartDataSource::operator<(const ChartDataSource& rhs) const { if (this == &rhs) { return false; } if (m_chartableFileName != rhs.m_chartableFileName) { return false; } switch (m_dataSourceMode) { case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_FILE_ROW: return (m_fileRowIndex < rhs.m_fileRowIndex); break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_INVALID: break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDEX: if (m_surfaceStructureName < rhs.m_surfaceStructureName) { return true; } if (m_surfaceNumberOfNodes < rhs.m_surfaceNumberOfNodes) { return true; } if (m_nodeIndex < rhs.m_nodeIndex) { return true; } break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDICES_AVERAGE: if (m_surfaceStructureName < rhs.m_surfaceStructureName) { return true; } if (m_surfaceNumberOfNodes < rhs.m_surfaceNumberOfNodes) { return true; } if (m_nodeIndicesAverage.size() < rhs.m_nodeIndicesAverage.size()) { return true; } else if (m_nodeIndicesAverage.size() > rhs.m_nodeIndicesAverage.size()) { return false; } else if (m_nodeIndicesAverage.size() == rhs.m_nodeIndicesAverage.size()) { std::vector copyMe = m_nodeIndicesAverage; std::sort(copyMe.begin(), copyMe.end()); std::vector copyRhs = rhs.m_nodeIndicesAverage; std::sort(copyRhs.begin(), copyRhs.end()); const int32_t numItems = static_cast(copyMe.size()); for (int32_t i = 0; i < numItems; i++) { CaretAssertVectorIndex(copyMe, i); CaretAssertVectorIndex(copyRhs, i); if (copyMe[i] < copyRhs[i]) { return true; } else if (copyMe[i] > copyRhs[i]) { return false; } } } break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_VOXEL_IJK: if (m_voxelXYZ[0] < rhs.m_voxelXYZ[0]) { return true; } if (m_voxelXYZ[1] < rhs.m_voxelXYZ[1]) { return true; } if (m_voxelXYZ[2] < rhs.m_voxelXYZ[2]) { return true; } break; } return false; } /** * Copy the given data source to me. * * @param copyFrom * Chart data source that is copied to me. */ void ChartDataSource::copy(const ChartDataSource* copyFrom) { CaretAssert(copyFrom); copyHelperChartDataSource(*copyFrom); } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ChartDataSource::copyHelperChartDataSource(const ChartDataSource& obj) { m_dataSourceMode = obj.m_dataSourceMode; m_chartableFileName = obj.m_chartableFileName; m_nodeIndex = obj.m_nodeIndex; m_surfaceNumberOfNodes = obj.m_surfaceNumberOfNodes; m_surfaceStructureName = obj.m_surfaceStructureName; m_nodeIndicesAverage = obj.m_nodeIndicesAverage; m_voxelXYZ[0] = obj.m_voxelXYZ[0]; m_voxelXYZ[1] = obj.m_voxelXYZ[1]; m_voxelXYZ[2] = obj.m_voxelXYZ[2]; m_fileRowIndex = obj.m_fileRowIndex; } /** * @return Name of the chartable file. */ AString ChartDataSource::getChartableFileName() const { return m_chartableFileName; } /** * Setup for a surface node source. * * @param chartableFileName * Name of the chartable file. * @param surfaceStructureName * Name of surface structure. * @param surfaceNumberOfNodes * Number of nodes in the surface. * @param nodeIndex * Index of the surface node. */ void ChartDataSource::setSurfaceNode(const AString& chartableFileName, const AString& surfaceStructureName, const int32_t surfaceNumberOfNodes, const int32_t nodeIndex) { CaretAssert(nodeIndex >= 0); m_dataSourceMode = ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDEX; m_chartableFileName = chartableFileName; m_surfaceNumberOfNodes = surfaceNumberOfNodes; m_surfaceStructureName = surfaceStructureName; m_nodeIndex = nodeIndex; } /** * Is the given node the source of the data? * * @param surfaceStructureName * Name of surface structure. * @param nodeIndex * Index of the surface node. * @return * True if node is source of data, else false. */ bool ChartDataSource::isSurfaceNodeSourceOfData(const AString& surfaceStructureName, const int32_t nodeIndex) const { if (m_dataSourceMode == ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDEX) { if (m_nodeIndex == nodeIndex) { if (m_surfaceStructureName == surfaceStructureName) { return true; } } } return false; } /** * @return Mode indicating source of the data. */ ChartDataSourceModeEnum::Enum ChartDataSource::getDataSourceMode() const { return m_dataSourceMode; } /** * Get the surface node data source. * * @param surfaceStructureName * Name of surface structure. * @param surfaceNumberOfNodes * Number of nodes in the surface. * @param nodeIndex * Index of the surface node. */ void ChartDataSource::getSurfaceNode(AString& surfaceStructureName, int32_t& surfaceNumberOfNodes, int32_t& nodeIndex) const { surfaceStructureName = m_surfaceStructureName; surfaceNumberOfNodes = m_surfaceNumberOfNodes; nodeIndex = m_nodeIndex; } /** * Get the surface node average data source. * * @param surfaceStructureName * Name of surface structure. * @param surfaceNumberOfNodes * Number of nodes in the surface. * @param nodeIndices * Indices of the surface node. */ void ChartDataSource::getSurfaceNodeAverage(AString& surfaceStructureName, int32_t& surfaceNumberOfNodes, std::vector& nodeIndices) const { surfaceStructureName = m_surfaceStructureName; surfaceNumberOfNodes = m_surfaceNumberOfNodes; nodeIndices = m_nodeIndicesAverage; } /** * Get the surface node average data source. * * @param chartableFileName * Name of the chartable file. * @param surfaceStructureName * Name of surface structure. * @param surfaceNumberOfNodes * Number of nodes in the surface. * @param nodeIndices * Indices of the surface node. */ void ChartDataSource::setSurfaceNodeAverage(const AString& chartableFileName, const AString& surfaceStructureName, const int32_t surfaceNumberOfNodes, const std::vector& nodeIndices) { m_dataSourceMode = ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDICES_AVERAGE; m_chartableFileName = chartableFileName; m_surfaceStructureName = surfaceStructureName; m_surfaceNumberOfNodes = surfaceNumberOfNodes; m_nodeIndicesAverage = nodeIndices; } /** * Get the volume voxel data source. * * @param ijk * Indices of the voxel. */ void ChartDataSource::getVolumeVoxel(float xyz[3]) const { xyz[0] = m_voxelXYZ[0]; xyz[1] = m_voxelXYZ[1]; xyz[2] = m_voxelXYZ[2]; } /** * Set the volume voxel data source. * * @param chartableFileName * Name of the chartable file. * @param ijk * Indices of the voxel. */ void ChartDataSource::setVolumeVoxel(const AString& chartableFileName, const float xyz[3]) { m_dataSourceMode = ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_VOXEL_IJK; m_chartableFileName = chartableFileName; m_voxelXYZ[0] = xyz[0]; m_voxelXYZ[1] = xyz[1]; m_voxelXYZ[2] = xyz[2]; } /** * Get the file row data source. * * @param chartableFileName * Name of the file. * @param fileRowIndex * Index of the row. */ void ChartDataSource::getFileRow(AString& chartableFileName, int32_t& fileRowIndex) const { chartableFileName = m_chartableFileName; fileRowIndex = m_fileRowIndex; } /** * Set the file row data source. * * @param chartableFileName * Name of the file. * @param fileRowIndex * Index of the row. */ void ChartDataSource::setFileRow(const AString& chartableFileName, const int32_t fileRowIndex) { m_dataSourceMode = ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_FILE_ROW; m_chartableFileName = chartableFileName; m_fileRowIndex = fileRowIndex; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ChartDataSource::getDescription() const { AString s; switch (m_dataSourceMode) { case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_INVALID: break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_FILE_ROW: s += (" Row " + AString::number(m_fileRowIndex + 1)); break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDEX: s += (m_surfaceStructureName + ": Vertex " + AString::number(m_nodeIndex)); break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDICES_AVERAGE: s += (m_surfaceStructureName + ": Average of " + AString::number(m_nodeIndicesAverage.size()) + " Vertices"); break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_VOXEL_IJK: s += ("Voxel XYZ (" + AString::fromNumbers(m_voxelXYZ, 3, ",") + ")"); break; } if ( ! s.isEmpty()) { FileInformation fileInfo(m_chartableFileName); s += (" from " + fileInfo.getFileName()); } return s; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ChartDataSource::toString() const { AString s = "ChartDataSource"; return s; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* ChartDataSource::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ChartDataSource", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); sceneClass->addPathName("m_chartableFileName", m_chartableFileName); switch (m_dataSourceMode) { case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_INVALID: break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_FILE_ROW: break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDEX: break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDICES_AVERAGE: { const int32_t numNodes = static_cast(m_nodeIndicesAverage.size()); if (numNodes > 0) { sceneClass->addIntegerArray("m_nodeIndicesAverage", &m_nodeIndicesAverage[0], numNodes); } } break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_VOXEL_IJK: break; } return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ChartDataSource::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); m_chartableFileName = sceneClass->getPathNameValue("m_chartableFileName"); switch (m_dataSourceMode) { case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_INVALID: break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_FILE_ROW: break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDEX: break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDICES_AVERAGE: { const SceneClassArray* nodeArray = sceneClass->getClassArray("m_nodeIndicesAverage"); if (nodeArray != NULL) { const int32_t numNodes = nodeArray->getNumberOfArrayElements(); if (numNodes > 0) { m_nodeIndicesAverage.resize(numNodes); sceneClass->getIntegerArrayValue("m_nodeIndicesAverage", &m_nodeIndicesAverage[0], numNodes); } } } break; case ChartDataSourceModeEnum::CHART_DATA_SOURCE_MODE_VOXEL_IJK: break; } } connectome-workbench-1.4.2/src/Charting/ChartDataSource.h000066400000000000000000000106041360521144700233470ustar00rootroot00000000000000#ifndef __CHART_DATA_SOURCE_H__ #define __CHART_DATA_SOURCE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "ChartDataSourceModeEnum.h" #include "SceneableInterface.h" namespace caret { class SceneClassAssistant; class ChartDataSource : public CaretObject, public SceneableInterface { public: ChartDataSource(); virtual ~ChartDataSource(); ChartDataSource(const ChartDataSource&); ChartDataSource& operator=(const ChartDataSource&); bool operator==(const ChartDataSource&) const; bool operator<(const ChartDataSource&) const; void copy(const ChartDataSource* copyFrom); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); ChartDataSourceModeEnum::Enum getDataSourceMode() const; AString getChartableFileName() const; void getSurfaceNode(AString& surfaceStructureName, int32_t& surfaceNumberOfNodes, int32_t& nodeIndex) const; void setSurfaceNode(const AString& chartableFileName, const AString& surfaceStructureName, const int32_t surfaceNumberOfNodes, const int32_t nodeIndex); bool isSurfaceNodeSourceOfData(const AString& surfaceStructureName, const int32_t nodeIndex) const; void getSurfaceNodeAverage(AString& surfaceStructureName, int32_t& surfaceNumberOfNodes, std::vector& nodeIndices) const; void setSurfaceNodeAverage(const AString& chartableFileName, const AString& surfaceStructureName, const int32_t surfaceNumberOfNodes, const std::vector& nodeIndices); void getVolumeVoxel(float xyz[3]) const; void setVolumeVoxel(const AString& chartableFileName, const float xyz[3]); void getFileRow(AString& chartableFileName, int32_t& fileRowIndex) const; void setFileRow(const AString& chartableFileName, const int32_t fileRowIndex); AString getDescription() const; private: void copyHelperChartDataSource(const ChartDataSource& obj); public: // ADD_NEW_METHODS_HERE virtual AString toString() const; private: void initializeMembersChartDataSource(); SceneClassAssistant* m_sceneAssistant; ChartDataSourceModeEnum::Enum m_dataSourceMode; AString m_chartableFileName; int32_t m_surfaceNumberOfNodes; AString m_surfaceStructureName; std::vector m_nodeIndicesAverage; int32_t m_nodeIndex; float m_voxelXYZ[3]; int32_t m_fileRowIndex; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHART_DATA_SOURCE_DECLARE__ // #endif // __CHART_DATA_SOURCE_DECLARE__ } // namespace #endif //__CHART_DATA_SOURCE_H__ connectome-workbench-1.4.2/src/Charting/ChartDataSourceModeEnum.cxx000066400000000000000000000267161360521144700253670ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CHART_DATA_SOURCE_MODE_ENUM_DECLARE__ #include "ChartDataSourceModeEnum.h" #undef __CHART_DATA_SOURCE_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartDataSourceModeEnum * \brief Enumerated type for shource source of a chart. * * * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_chartDataSourceModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void chartDataSourceModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ChartDataSourceModeEnum.h" * * Instatiate: * m_chartDataSourceModeEnumComboBox = new EnumComboBoxTemplate(this); * m_chartDataSourceModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_chartDataSourceModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(chartDataSourceModeEnumComboBoxItemActivated())); * * Update the selection: * m_chartDataSourceModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ChartDataSourceModeEnum::Enum VARIABLE = m_chartDataSourceModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ChartDataSourceModeEnum::ChartDataSourceModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ChartDataSourceModeEnum::~ChartDataSourceModeEnum() { } /** * Initialize the enumerated metadata. */ void ChartDataSourceModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ChartDataSourceModeEnum(CHART_DATA_SOURCE_MODE_INVALID, "CHART_DATA_SOURCE_MODE_INVALID", "Invalid")); enumData.push_back(ChartDataSourceModeEnum(CHART_DATA_SOURCE_MODE_FILE_ROW, "CHART_DATA_SOURCE_MODE_FILE_ROW", "Chart Source File Row")); enumData.push_back(ChartDataSourceModeEnum(CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDEX, "CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDEX", "Chart Source Surface Node")); enumData.push_back(ChartDataSourceModeEnum(CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDICES_AVERAGE, "CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDICES_AVERAGE", "Chart Source Average of Surface Nodes")); enumData.push_back(ChartDataSourceModeEnum(CHART_DATA_SOURCE_MODE_VOXEL_IJK, "CHART_DATA_SOURCE_MODE_VOXEL_IJK", "Chart Source Voxel")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ChartDataSourceModeEnum* ChartDataSourceModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ChartDataSourceModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartDataSourceModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartDataSourceModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartDataSourceModeEnum::Enum ChartDataSourceModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartDataSourceModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartDataSourceModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartDataSourceModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartDataSourceModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartDataSourceModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartDataSourceModeEnum::Enum ChartDataSourceModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartDataSourceModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartDataSourceModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartDataSourceModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ChartDataSourceModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartDataSourceModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ChartDataSourceModeEnum::Enum ChartDataSourceModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartDataSourceModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartDataSourceModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartDataSourceModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ChartDataSourceModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartDataSourceModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ChartDataSourceModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartDataSourceModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ChartDataSourceModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Charting/ChartDataSourceModeEnum.h000066400000000000000000000067461360521144700250150ustar00rootroot00000000000000#ifndef __CHART_DATA_SOURCE_MODE_ENUM_H__ #define __CHART_DATA_SOURCE_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ChartDataSourceModeEnum { public: /** * Enumerated values. */ enum Enum { /** Invalid mode */ CHART_DATA_SOURCE_MODE_INVALID, /** Chart is from a file's row */ CHART_DATA_SOURCE_MODE_FILE_ROW, /** Chart is from a surface node index */ CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDEX, /** Chart is from an average of surface node indices */ CHART_DATA_SOURCE_MODE_SURFACE_NODE_INDICES_AVERAGE, /** Chart is from a voxel index */ CHART_DATA_SOURCE_MODE_VOXEL_IJK }; ~ChartDataSourceModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ChartDataSourceModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ChartDataSourceModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __CHART_DATA_SOURCE_MODE_ENUM_DECLARE__ std::vector ChartDataSourceModeEnum::enumData; bool ChartDataSourceModeEnum::initializedFlag = false; int32_t ChartDataSourceModeEnum::integerCodeCounter = 0; #endif // __CHART_DATA_SOURCE_MODE_ENUM_DECLARE__ } // namespace #endif //__CHART_DATA_SOURCE_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Charting/ChartMatrixDisplayProperties.cxx000066400000000000000000000276321360521144700265500ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_MATRIX_DISPLAY_PROPERTIES_DECLARE__ #include "ChartMatrixDisplayProperties.h" #undef __CHART_MATRIX_DISPLAY_PROPERTIES_DECLARE__ #include "AnnotationColorBar.h" #include "CaretAssert.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ChartMatrixDisplayProperties * \brief Properites for display of matrix charts. * \ingroup Charting */ /** * Constructor. */ ChartMatrixDisplayProperties::ChartMatrixDisplayProperties() : CaretObject() { m_scaleMode = ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_AUTO; m_cellWidth = 10.0; m_cellHeight = 10.0; m_highlightSelectedRowColumn = true; m_displayGridLines = true; m_colorBar = new AnnotationColorBar(AnnotationAttributesDefaultTypeEnum::NORMAL); resetPropertiesToDefault(); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_cellWidth", &m_cellWidth); m_sceneAssistant->add("m_cellHeight", &m_cellHeight); m_sceneAssistant->add("m_viewZooming", &m_viewZooming); m_sceneAssistant->addArray("m_viewPanning", m_viewPanning, 2, 0.0); m_sceneAssistant->add("m_highlightSelectedRowColumn", &m_highlightSelectedRowColumn); m_sceneAssistant->add("m_displayGridLines", &m_displayGridLines); m_sceneAssistant->add("m_colorBar", "AnnotationColorBar", m_colorBar); m_sceneAssistant->add("m_scaleMode", &m_scaleMode); } /** * Destructor. */ ChartMatrixDisplayProperties::~ChartMatrixDisplayProperties() { delete m_colorBar; delete m_sceneAssistant; } /** * Copy constructor. * @param obj * Object that is copied. */ ChartMatrixDisplayProperties::ChartMatrixDisplayProperties(const ChartMatrixDisplayProperties& obj) : CaretObject(obj), SceneableInterface() { this->copyHelperChartMatrixDisplayProperties(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ChartMatrixDisplayProperties& ChartMatrixDisplayProperties::operator=(const ChartMatrixDisplayProperties& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperChartMatrixDisplayProperties(obj); } return *this; } /** * Reset to the default. */ void ChartMatrixDisplayProperties::resetPropertiesToDefault() { m_viewPanning[0] = 0.0; m_viewPanning[1] = 0.0; m_viewZooming = 1.0; // m_cellWidth = 10.0; // m_cellHeight = 10.0; setScaleMode(ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_AUTO); } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ChartMatrixDisplayProperties::copyHelperChartMatrixDisplayProperties(const ChartMatrixDisplayProperties& obj) { m_viewPanning[0] = obj.m_viewPanning[0]; m_viewPanning[1] = obj.m_viewPanning[1]; m_viewZooming = obj.m_viewZooming; m_cellWidth = obj.m_cellWidth; m_cellHeight = obj.m_cellHeight; m_scaleMode = obj.m_scaleMode; *m_colorBar = *obj.m_colorBar; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ChartMatrixDisplayProperties::toString() const { return "ChartMatrixDisplayProperties"; } /** * @return Widgth of matrix cell in pixels */ float ChartMatrixDisplayProperties::getCellWidth() const { float cellWidth = m_cellWidth; switch (m_scaleMode) { case ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_AUTO: break; case ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_MANUAL: if (s_manualScaleModeWindowHeightScaling > 0.0) { cellWidth *= s_manualScaleModeWindowWidthScaling; } break; } return cellWidth; } /** * Set width of matrix cell in pixels * @param cellWidth * New value for size of matrix cell width in pixels */ void ChartMatrixDisplayProperties::setCellWidth(const float cellWidth) { m_cellWidth = cellWidth; } /** * @return Height of matrix cell in pixels */ float ChartMatrixDisplayProperties::getCellHeight() const { float cellHeight = m_cellHeight; switch (m_scaleMode) { case ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_AUTO: break; case ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_MANUAL: if (s_manualScaleModeWindowHeightScaling > 0.0) { cellHeight *= s_manualScaleModeWindowHeightScaling; } break; } return cellHeight; } /** * Set height of matrix cell in pixels * @param cellHeight * New value for size of matrix cell in pixels */ void ChartMatrixDisplayProperties::setCellHeight(const float cellHeight) { m_cellHeight = cellHeight; } /** * @return zooming for view of matrix */ float ChartMatrixDisplayProperties::getViewZooming() const { return m_viewZooming; } /** * Set zooming for view of matrix * @param viewZooming * New value for zooming for view of matrix */ void ChartMatrixDisplayProperties::setViewZooming(const float viewZooming) { m_viewZooming = viewZooming; setScaleMode(ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_MANUAL); } /** * @return panning for view of matrix */ void ChartMatrixDisplayProperties::getViewPanning(float viewPanningOut[2]) const { viewPanningOut[0] = m_viewPanning[0]; viewPanningOut[1] = m_viewPanning[1]; switch (m_scaleMode) { case ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_AUTO: break; case ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_MANUAL: if (s_manualScaleModeWindowWidthScaling > 0.0) { viewPanningOut[0] *= s_manualScaleModeWindowWidthScaling; } if (s_manualScaleModeWindowHeightScaling > 0.0) { viewPanningOut[1] *= s_manualScaleModeWindowHeightScaling; } break; } } /** * Set panning for view of matrix * @param viewPanning[2] * New value for panning for view of matrix */ void ChartMatrixDisplayProperties::setViewPanning(const float viewPanning[2]) { m_viewPanning[0] = viewPanning[0]; m_viewPanning[1] = viewPanning[1]; setScaleMode(ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_MANUAL); } /** * @return scale mode for view of matrix */ ChartMatrixScaleModeEnum::Enum ChartMatrixDisplayProperties::getScaleMode() const { return m_scaleMode; } /** * Set the scale mode. * * @param scaleMode * New value for scale mode. */ void ChartMatrixDisplayProperties::setScaleMode(const ChartMatrixScaleModeEnum::Enum scaleMode) { m_scaleMode = scaleMode; } /** * @return The color bar displayed in graphics window. */ AnnotationColorBar* ChartMatrixDisplayProperties::getColorBar() { return m_colorBar; } /** * @return The color bar displayed in graphics window (const method). */ const AnnotationColorBar* ChartMatrixDisplayProperties::getColorBar() const { return m_colorBar; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* ChartMatrixDisplayProperties::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ChartMatrixDisplayProperties", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ChartMatrixDisplayProperties::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); /* * "m_paletteDisplayedFlag" controlled display of palette colorbar * prior to the addition of AnnotationColorBar */ const AString colorBarDisplayedFlagString = sceneClass->getStringValue("m_colorBarDisplayed"); if ( ! colorBarDisplayedFlagString.isEmpty()) { m_colorBar->reset(); m_colorBar->setDisplayed(sceneClass->getBooleanValue("m_colorBarDisplayed")); } //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } /** * Is the selected row/column highlighted? */ bool ChartMatrixDisplayProperties::isSelectedRowColumnHighlighted() const { return m_highlightSelectedRowColumn; } /** * Set the selected row/column highlighted status. * * @param highlightStatus * New status for lighlighting selected row/column. */ void ChartMatrixDisplayProperties::setSelectedRowColumnHighlighted(const bool highlightStatus) { m_highlightSelectedRowColumn = highlightStatus; } /** * Are the grid lines displayed? */ bool ChartMatrixDisplayProperties::isGridLinesDisplayed() const { return m_displayGridLines; } /** * Set the grid lines displayed for the given tab. * * @param displayGridLines * True if grid lines are displayed, else false. */ void ChartMatrixDisplayProperties::setGridLinesDisplayed(const bool displayGridLines) { m_displayGridLines = displayGridLines; } /** * Set scaling of the manual width and heights for matrix cells. * When image capture is performed and the user is capturing the * image in a size different than the actual window size, the matrix * cell width and heights need to be scaled so that they are the same * percentage width and height of the window. * * If the scale mode is manual, these scaling values are used by * the getCellWidth() and getCellHeight() to adjust the pixel width * and height for matrix cell drawing. * * NOTE: THIS METHOD SHOULD BE CALLED JUST BEFORE IMAGE CAPTURE * WHEN SCALING OF MATRIX CELL WIDTH AND HEIGHT IS NEEDED. * IMMEDIATELY AFTER IMAGE CAPTURE, THIS METHOD SHOULD BE CALLED * WITH A VALUE OF ONE FOR BOTH THE WINDOW WIDTH AND HEIGHT SCALING. */ void ChartMatrixDisplayProperties::setManualScaleModeWindowWidthHeightScaling(const float windowWidthScaling, const float windowHeightScaling) { s_manualScaleModeWindowWidthScaling = windowWidthScaling; s_manualScaleModeWindowHeightScaling = windowHeightScaling; } connectome-workbench-1.4.2/src/Charting/ChartMatrixDisplayProperties.h000066400000000000000000000120301360521144700261570ustar00rootroot00000000000000#ifndef __CHART_MATRIX_DISPLAY_PROPERTIES_H__ #define __CHART_MATRIX_DISPLAY_PROPERTIES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "CaretObject.h" #include "ChartMatrixScaleModeEnum.h" #include "SceneableInterface.h" namespace caret { class AnnotationColorBar; class SceneClassAssistant; class ChartMatrixDisplayProperties : public CaretObject, public SceneableInterface { public: ChartMatrixDisplayProperties(); virtual ~ChartMatrixDisplayProperties(); ChartMatrixDisplayProperties(const ChartMatrixDisplayProperties& obj); ChartMatrixDisplayProperties& operator=(const ChartMatrixDisplayProperties& obj); float getCellWidth() const; void setCellWidth(const float cellSizeX); float getCellHeight() const; void setCellHeight(const float cellHeight); float getViewZooming() const; void setViewZooming(const float viewZooming); void getViewPanning(float viewPanningOut[2]) const; void setViewPanning(const float viewPanning[2]); ChartMatrixScaleModeEnum::Enum getScaleMode() const; void setScaleMode(const ChartMatrixScaleModeEnum::Enum scaleMode); bool isGridLinesDisplayed() const; void setGridLinesDisplayed(const bool displayGridLines); void resetPropertiesToDefault(); bool isSelectedRowColumnHighlighted() const; void setSelectedRowColumnHighlighted(const bool highlightStatus); AnnotationColorBar* getColorBar(); const AnnotationColorBar* getColorBar() const; // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); static void setManualScaleModeWindowWidthHeightScaling(const float windowWidthScaling, const float windowHeightScaling); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implemetation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: void copyHelperChartMatrixDisplayProperties(const ChartMatrixDisplayProperties& obj); SceneClassAssistant* m_sceneAssistant; /** matrix cell width in pixels*/ float m_cellWidth; /** matrix cell height in pixels*/ float m_cellHeight; /** zooming for view of matrix*/ float m_viewZooming; /** panning for view of matrix*/ float m_viewPanning[2]; /** scale mode for view of matrix*/ ChartMatrixScaleModeEnum::Enum m_scaleMode; /** Highlight the selected row/column */ bool m_highlightSelectedRowColumn; /** Display grid lines */ bool m_displayGridLines; /** The color bar displayed in the graphics window */ AnnotationColorBar* m_colorBar; static float s_manualScaleModeWindowWidthScaling; static float s_manualScaleModeWindowHeightScaling; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHART_MATRIX_DISPLAY_PROPERTIES_DECLARE__ float ChartMatrixDisplayProperties::s_manualScaleModeWindowWidthScaling = 1.0; float ChartMatrixDisplayProperties::s_manualScaleModeWindowHeightScaling = 1.0; #endif // __CHART_MATRIX_DISPLAY_PROPERTIES_DECLARE__ } // namespace #endif //__CHART_MATRIX_DISPLAY_PROPERTIES_H__ connectome-workbench-1.4.2/src/Charting/ChartMatrixLoadingDimensionEnum.cxx000066400000000000000000000263121360521144700271300ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CHART_MATRIX_LOADING_TYPE_ENUM_DECLARE__ #include "ChartMatrixLoadingDimensionEnum.h" #undef __CHART_MATRIX_LOADING_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartMatrixLoadingDimensionEnum * \brief Enumerated type for loading matrix data by row or column * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_ChartMatrixLoadingDimensionEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void ChartMatrixLoadingDimensionEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ChartMatrixLoadingDimensionEnum.h" * * Instatiate: * m_ChartMatrixLoadingDimensionEnumComboBox = new EnumComboBoxTemplate(this); * m_ChartMatrixLoadingDimensionEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_ChartMatrixLoadingDimensionEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(ChartMatrixLoadingDimensionEnumComboBoxItemActivated())); * * Update the selection: * m_ChartMatrixLoadingDimensionEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ChartMatrixLoadingDimensionEnum::Enum VARIABLE = m_ChartMatrixLoadingDimensionEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ChartMatrixLoadingDimensionEnum::ChartMatrixLoadingDimensionEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ChartMatrixLoadingDimensionEnum::~ChartMatrixLoadingDimensionEnum() { } /** * Initialize the enumerated metadata. */ void ChartMatrixLoadingDimensionEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ChartMatrixLoadingDimensionEnum(CHART_MATRIX_LOADING_BY_ROW, "CHART_MATRIX_LOADING_BY_ROW", "Row")); enumData.push_back(ChartMatrixLoadingDimensionEnum(CHART_MATRIX_LOADING_BY_COLUMN, "CHART_MATRIX_LOADING_BY_COLUMN", "Column")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ChartMatrixLoadingDimensionEnum* ChartMatrixLoadingDimensionEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ChartMatrixLoadingDimensionEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartMatrixLoadingDimensionEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartMatrixLoadingDimensionEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartMatrixLoadingDimensionEnum::Enum ChartMatrixLoadingDimensionEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartMatrixLoadingDimensionEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartMatrixLoadingDimensionEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartMatrixLoadingDimensionEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartMatrixLoadingDimensionEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartMatrixLoadingDimensionEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartMatrixLoadingDimensionEnum::Enum ChartMatrixLoadingDimensionEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartMatrixLoadingDimensionEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartMatrixLoadingDimensionEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartMatrixLoadingDimensionEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ChartMatrixLoadingDimensionEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartMatrixLoadingDimensionEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ChartMatrixLoadingDimensionEnum::Enum ChartMatrixLoadingDimensionEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartMatrixLoadingDimensionEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartMatrixLoadingDimensionEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartMatrixLoadingDimensionEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ChartMatrixLoadingDimensionEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartMatrixLoadingDimensionEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ChartMatrixLoadingDimensionEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartMatrixLoadingDimensionEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ChartMatrixLoadingDimensionEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Charting/ChartMatrixLoadingDimensionEnum.h000066400000000000000000000064031360521144700265540ustar00rootroot00000000000000#ifndef __CHART_MATRIX_LOADING_TYPE_ENUM_H__ #define __CHART_MATRIX_LOADING_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ChartMatrixLoadingDimensionEnum { public: /** * Enumerated values. */ enum Enum { /** Load data from column */ CHART_MATRIX_LOADING_BY_COLUMN, /** Load data from row */ CHART_MATRIX_LOADING_BY_ROW }; ~ChartMatrixLoadingDimensionEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ChartMatrixLoadingDimensionEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ChartMatrixLoadingDimensionEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __CHART_MATRIX_LOADING_TYPE_ENUM_DECLARE__ std::vector ChartMatrixLoadingDimensionEnum::enumData; bool ChartMatrixLoadingDimensionEnum::initializedFlag = false; int32_t ChartMatrixLoadingDimensionEnum::integerCodeCounter = 0; #endif // __CHART_MATRIX_LOADING_TYPE_ENUM_DECLARE__ } // namespace #endif //__CHART_MATRIX_LOADING_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Charting/ChartMatrixScaleModeEnum.cxx000066400000000000000000000253371360521144700255470ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CHART_MATRIX_SCALE_MODE_ENUM_DECLARE__ #include "ChartMatrixScaleModeEnum.h" #undef __CHART_MATRIX_SCALE_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartMatrixScaleModeEnum * \brief Scale mode for viewing chart matrices. * * * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_chartMatrixScaleModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void chartMatrixScaleModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ChartMatrixScaleModeEnum.h" * * Instatiate: * m_chartMatrixScaleModeEnumComboBox = new EnumComboBoxTemplate(this); * m_chartMatrixScaleModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_chartMatrixScaleModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(chartMatrixScaleModeEnumComboBoxItemActivated())); * * Update the selection: * m_chartMatrixScaleModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ChartMatrixScaleModeEnum::Enum VARIABLE = m_chartMatrixScaleModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ChartMatrixScaleModeEnum::ChartMatrixScaleModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ChartMatrixScaleModeEnum::~ChartMatrixScaleModeEnum() { } /** * Initialize the enumerated metadata. */ void ChartMatrixScaleModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ChartMatrixScaleModeEnum(CHART_MATRIX_SCALE_AUTO, "CHART_MATRIX_SCALE_AUTO", "Auto")); enumData.push_back(ChartMatrixScaleModeEnum(CHART_MATRIX_SCALE_MANUAL, "CHART_MATRIX_SCALE_MANUAL", "Manual")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ChartMatrixScaleModeEnum* ChartMatrixScaleModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ChartMatrixScaleModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartMatrixScaleModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartMatrixScaleModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartMatrixScaleModeEnum::Enum ChartMatrixScaleModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartMatrixScaleModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartMatrixScaleModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartMatrixScaleModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartMatrixScaleModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartMatrixScaleModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartMatrixScaleModeEnum::Enum ChartMatrixScaleModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartMatrixScaleModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartMatrixScaleModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartMatrixScaleModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ChartMatrixScaleModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartMatrixScaleModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ChartMatrixScaleModeEnum::Enum ChartMatrixScaleModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartMatrixScaleModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartMatrixScaleModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartMatrixScaleModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ChartMatrixScaleModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartMatrixScaleModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ChartMatrixScaleModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartMatrixScaleModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ChartMatrixScaleModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Charting/ChartMatrixScaleModeEnum.h000066400000000000000000000062511360521144700251660ustar00rootroot00000000000000#ifndef __CHART_MATRIX_SCALE_MODE_ENUM_H__ #define __CHART_MATRIX_SCALE_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ChartMatrixScaleModeEnum { public: /** * Enumerated values. */ enum Enum { /** Auto scale mode */ CHART_MATRIX_SCALE_AUTO, /** Manual scale mode */ CHART_MATRIX_SCALE_MANUAL }; ~ChartMatrixScaleModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ChartMatrixScaleModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ChartMatrixScaleModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __CHART_MATRIX_SCALE_MODE_ENUM_DECLARE__ std::vector ChartMatrixScaleModeEnum::enumData; bool ChartMatrixScaleModeEnum::initializedFlag = false; int32_t ChartMatrixScaleModeEnum::integerCodeCounter = 0; #endif // __CHART_MATRIX_SCALE_MODE_ENUM_DECLARE__ } // namespace #endif //__CHART_MATRIX_SCALE_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Charting/ChartModel.cxx000066400000000000000000000671111360521144700227350ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_MODEL_DECLARE__ #include "ChartModel.h" #undef __CHART_MODEL_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "ChartAxis.h" #include "ChartData.h" #include "ChartDataCartesian.h" #include "ChartDataSource.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneClassAssistant.h" #include "SceneStringArray.h" using namespace caret; /** * \class caret::ChartModel * \brief Base class for chart model * \ingroup Charting * * Base class for chart model that displays chart data of the same type. * Some data types may require mututal exclusive display. */ /** * Constructor. * * @param chartDataType * Model type of chart that is managed. * @param chartSelectionMode * The selection mode. */ ChartModel::ChartModel(const ChartOneDataTypeEnum::Enum chartDataType, const ChartSelectionModeEnum::Enum chartSelectionMode) : CaretObject(), SceneableInterface(), m_chartDataType(chartDataType), m_chartSelectionMode(chartSelectionMode) { m_bottomAxis = NULL; m_leftAxis = NULL; m_rightAxis = NULL; m_topAxis = NULL; switch (m_chartSelectionMode) { case ChartSelectionModeEnum::CHART_SELECTION_MODE_ANY: m_maximumNumberOfChartDatasToDisplay = 5; break; case ChartSelectionModeEnum::CHART_SELECTION_MODE_SINGLE: m_maximumNumberOfChartDatasToDisplay = 1; break; } m_averageChartDisplaySelected = false; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_maximumNumberOfChartDatasToDisplay", &m_maximumNumberOfChartDatasToDisplay); m_sceneAssistant->add("m_averageChartDisplaySelected", &m_averageChartDisplaySelected); } /** * Destructor. */ ChartModel::~ChartModel() { delete m_sceneAssistant; removeAllAxes(); removeChartDataPrivate(); } /** * Remove the data data. * NOTE: This method cannot be called by constructor/destructor since * it calls a virtual method. */ void ChartModel::removeChartData() { removeChartDataPrivate(); updateAfterChartDataHasBeenAddedOrRemoved(); } /** * Remove the data data. */ void ChartModel::removeChartDataPrivate() { m_chartDatas.clear(); } /** * Remove all axes. */ void ChartModel::removeAllAxes() { if (m_bottomAxis != NULL) { delete m_bottomAxis; m_bottomAxis = NULL; } if (m_leftAxis != NULL) { delete m_leftAxis; m_leftAxis = NULL; } if (m_rightAxis != NULL) { delete m_rightAxis; m_rightAxis = NULL; } if (m_topAxis != NULL) { delete m_topAxis; m_topAxis = NULL; } } /** * Copy constructor. * @param obj * Object that is copied. */ ChartModel::ChartModel(const ChartModel& obj) : CaretObject(obj), SceneableInterface(obj), m_chartDataType(obj.m_chartDataType), m_chartSelectionMode(obj.m_chartSelectionMode) { this->copyHelperChartModel(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ChartModel& ChartModel::operator=(const ChartModel& obj) { if (this != &obj) { this->copyHelperChartModel(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ChartModel::copyHelperChartModel(const ChartModel& obj) { m_chartDataType = obj.m_chartDataType; m_chartSelectionMode = obj.m_chartSelectionMode; m_maximumNumberOfChartDatasToDisplay = obj.m_maximumNumberOfChartDatasToDisplay; removeAllAxes(); if (obj.m_leftAxis != NULL) { setLeftAxis(obj.m_leftAxis->clone()); } if (obj.m_rightAxis != NULL) { setRightAxis(obj.m_rightAxis->clone()); } if (obj.m_bottomAxis != NULL) { setBottomAxis(obj.m_bottomAxis->clone()); } if (obj.m_topAxis != NULL) { setTopAxis(obj.m_topAxis->clone()); } m_averageChartDisplaySelected = obj.m_averageChartDisplaySelected; removeChartData(); m_chartDatas = obj.m_chartDatas; ChartData* selectedChartData = NULL; switch (m_chartSelectionMode) { case ChartSelectionModeEnum::CHART_SELECTION_MODE_ANY: break; case ChartSelectionModeEnum::CHART_SELECTION_MODE_SINGLE: { /* * If no item selected, choose oldest */ if (selectedChartData == NULL) { const int32_t numData = static_cast(m_chartDatas.size()); if (numData > 0) { const int32_t lastIndex = numData - 1; selectedChartData = m_chartDatas[lastIndex].data(); } } if (selectedChartData != NULL) { /* * Calling the setSelected method will ensure that * mutual exclusion for selection is maintained */ // selectedChartData->setSelected(true); } } break; } updateAfterChartDataHasBeenAddedOrRemoved(); } /** * @return The chart data type. */ ChartOneDataTypeEnum::Enum ChartModel::getChartDataType() const { return m_chartDataType; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ChartModel::toString() const { return "ChartModel"; } /** * @return Support for multiple chart display. Some chart types allow * it and others do not. */ ChartSelectionModeEnum::Enum ChartModel::getChartSelectionMode() const { return m_chartSelectionMode; } /** * Is this model empty (zero charts)? */ bool ChartModel::isEmpty() const { return m_chartDatas.empty(); } /** * Add a chart model to this controller. * * @param chartData * Model that is added. */ void ChartModel::addChartData(const QSharedPointer& chartData) { /* * If the display is limited to one chart and both the chart * in deque and the chart to add are both cartesian charts, * copy the chart color. */ if (getMaximumNumberOfChartDatasToDisplay() == 1) { if ( ! m_chartDatas.empty()) { ChartData* firstChartData = getChartDataAtIndex(0); ChartDataCartesian* cartesianChart = dynamic_cast(firstChartData); if (cartesianChart != NULL) { ChartDataCartesian* newCartesianChart = dynamic_cast(chartData.data()); if (newCartesianChart != NULL) { newCartesianChart->setColor(cartesianChart->getColor()); } } } } m_chartDatas.push_front(chartData); updateUsingMaximumNumberOfChartDatasToDisplay(); updateAfterChartDataHasBeenAddedOrRemoved(); } /** * Update so the number of charts is never greater than * the maximum. */ void ChartModel::updateUsingMaximumNumberOfChartDatasToDisplay() { /* * If needed, remove extra items at end of deque */ const int32_t numToRemove = (static_cast(m_chartDatas.size()) - m_maximumNumberOfChartDatasToDisplay); if (numToRemove > 0) { for (int32_t i = 0; i < numToRemove; i++) { m_chartDatas.pop_back(); } } switch (m_chartSelectionMode) { case ChartSelectionModeEnum::CHART_SELECTION_MODE_ANY: break; case ChartSelectionModeEnum::CHART_SELECTION_MODE_SINGLE: { /* * See if any item is selected */ bool haveSelectedItem = false; const int32_t numData = static_cast(m_chartDatas.size()); for (int32_t i = 0; i < numData; i++) { } /* * If no item selected, selected oldest */ if ( ! haveSelectedItem) { if (numData >= 0) { } } } break; } } /** * @return All chart datas (const method) */ std::vector ChartModel::getAllChartDatas() const { std::vector datasOut; for (std::deque >::const_iterator iter = m_chartDatas.begin(); iter != m_chartDatas.end(); iter++) { datasOut.push_back(iter->data()); } return datasOut; } /** * @return All chart datas. */ std::vector ChartModel::getAllChartDatas() { std::vector datasOut; for (std::deque >::const_iterator iter = m_chartDatas.begin(); iter != m_chartDatas.end(); iter++) { datasOut.push_back(iter->data()); } return datasOut; } /** * @return All SELECTED chart datas in the given tab. * @param tabIndex * Index of tab. */ std::vector ChartModel::getAllSelectedChartDatas(const int32_t tabIndex) const { std::vector datasOut; for (std::deque >::const_iterator iter = m_chartDatas.begin(); iter != m_chartDatas.end(); iter++) { ChartData* cd = iter->data(); if (cd->isSelected(tabIndex)) { datasOut.push_back(cd); } } return datasOut; } /** * @return Number of chart data. */ int32_t ChartModel::getNumberOfChartData() const { return m_chartDatas.size(); } /** * Get the chart data at the given index. * * @param chartDataIndex * Index of desired chart data. * @return * ChartData at the given index. */ ChartData* ChartModel::getChartDataAtIndex(const int32_t chartDataIndex) { CaretAssertVectorIndex(m_chartDatas, chartDataIndex); return m_chartDatas[chartDataIndex].data(); } /** * Get the chart data at the given index (const method). * * @param chartDataIndex * Index of desired chart data. * @return * ChartData at the given index. */ const ChartData* ChartModel::getChartDataAtIndex(const int32_t chartDataIndex) const { CaretAssertVectorIndex(m_chartDatas, chartDataIndex); return m_chartDatas[chartDataIndex].data(); } /** * Move the chart data at the given index by swapping with the chart * data at (chartDataIndex - 1). * * @param chartDataIndex * Index of the chart data. */ void ChartModel::moveChartDataAtIndexToOneLowerIndex(const int32_t chartDataIndex) { CaretAssertVectorIndex(m_chartDatas, chartDataIndex); if (chartDataIndex > 0) { std::swap(m_chartDatas[chartDataIndex], m_chartDatas[chartDataIndex - 1]); updateAfterChartDataHasBeenAddedOrRemoved(); } } /** * Move the chart data at the given index by swapping with the chart * data at (chartDataIndex + 1). * * @param chartDataIndex * Index of the chart data. */ void ChartModel::moveChartDataAtIndexToOneHigherIndex(const int32_t chartDataIndex) { CaretAssertVectorIndex(m_chartDatas, chartDataIndex); if (chartDataIndex < (static_cast(m_chartDatas.size()) - 1)) { std::swap(m_chartDatas[chartDataIndex], m_chartDatas[chartDataIndex + 1]); updateAfterChartDataHasBeenAddedOrRemoved(); } } /** * Remove the chart data at the given index. * * @param chartDataIndex * Index of the chart data. */ void ChartModel::removeChartAtIndex(const int32_t chartDataIndex) { CaretAssertVectorIndex(m_chartDatas, chartDataIndex); const int32_t lastIndex = m_chartDatas.size() - 1; for (int32_t i = chartDataIndex; i < lastIndex; i++) { CaretAssertVectorIndex(m_chartDatas, (i + 1)); m_chartDatas[i] = m_chartDatas[i + 1]; } m_chartDatas.resize(m_chartDatas.size() - 1); updateAfterChartDataHasBeenAddedOrRemoved(); } /** * @return Is average chart data display selected. * NOTE: Not all charts support an average. */ bool ChartModel::isAverageChartDisplaySelected() const { if (isAverageChartDisplaySupported()) { return m_averageChartDisplaySelected; } return false; } /** * Set the average chart data selected. * NOTE: Not all charts support an average. * * @param selected * New status. */ void ChartModel::setAverageChartDisplaySelected(const bool selected) { m_averageChartDisplaySelected = selected; } /** * @return The MAXIMUM number of chart models for display. * * NOTE: This value MAY BE GREATER than the actual number of chart models * that are available. */ int32_t ChartModel::getMaximumNumberOfChartDatasToDisplay() const { return m_maximumNumberOfChartDatasToDisplay; } /** * Set the number of most recent chart models for display. * * @param numberToDisplay * New number of most recent models for display. */ void ChartModel::setMaximumNumberOfChartDatasToDisplay(const int32_t numberToDisplay) { CaretAssert(numberToDisplay > 0); switch (m_chartSelectionMode) { case ChartSelectionModeEnum::CHART_SELECTION_MODE_ANY: m_maximumNumberOfChartDatasToDisplay = numberToDisplay; break; case ChartSelectionModeEnum::CHART_SELECTION_MODE_SINGLE: m_maximumNumberOfChartDatasToDisplay = 1; break; } updateUsingMaximumNumberOfChartDatasToDisplay(); updateAfterChartDataHasBeenAddedOrRemoved(); } /** * @return Chart Axis for left. NULL if axis not valid. */ ChartAxis* ChartModel::getLeftAxis() { return m_leftAxis; } /** * @return Chart Axis for left (const method). NULL if axis not valid. */ const ChartAxis* ChartModel::getLeftAxis() const { return m_leftAxis; } /** * Set the bottom axis. Replaces current axis. * * @param bottomAxis * New bottom axis. */ void ChartModel::setBottomAxis(ChartAxis* bottomAxis) { if (m_bottomAxis != NULL) { delete m_bottomAxis; } m_bottomAxis = bottomAxis; m_bottomAxis->setParentChartModel(this); } /** * @return Chart Axis for right. NULL if axis not valid. */ ChartAxis* ChartModel::getRightAxis() { return m_rightAxis; } /** * @return Chart Axis for right (const method). NULL if axis not valid. */ const ChartAxis* ChartModel::getRightAxis() const { return m_rightAxis; } /** * Set the right axis. Replaces current axis. * * @param rightAxis * New right axis. */ void ChartModel::setRightAxis(ChartAxis* rightAxis) { if (m_rightAxis != NULL) { delete m_rightAxis; } m_rightAxis = rightAxis; m_rightAxis->setParentChartModel(this); } /** * @return Chart Bottom for bottom. NULL if axis not valid. */ ChartAxis* ChartModel::getBottomAxis() { return m_bottomAxis; } /** * @return Chart Axis for bottom (const method). NULL if axis not valid. */ const ChartAxis* ChartModel::getBottomAxis() const { return m_bottomAxis; } /** * Set the left axis. Replaces current axis. * * @param leftAxis * New left axis. */ void ChartModel::setLeftAxis(ChartAxis* leftAxis) { if (m_leftAxis != NULL) { delete m_leftAxis; } m_leftAxis = leftAxis; m_leftAxis->setParentChartModel(this); } /** * @return Chart Axis for top. NULL if axis not valid. */ ChartAxis* ChartModel::getTopAxis() { return m_topAxis; } /** * @return Chart Axis for top (const method). NULL if axis not valid. */ const ChartAxis* ChartModel::getTopAxis() const { return m_topAxis; } /** * Set the top axis. Replaces current axis. * * @param topAxis * New top axis. */ void ChartModel::setTopAxis(ChartAxis* topAxis) { if (m_topAxis != NULL) { delete m_topAxis; } m_topAxis = topAxis; m_topAxis->setParentChartModel(this); } /** * Called by child ChartData when its selection status changes. * * If the selection mode is mutually exclusive, this method * ensures that no more than one child is selected. * * If the selection mode is NOT mutually exclusive, no * action is taken. */ void ChartModel::childChartDataSelectionChanged(ChartData* /*childChartData*/) { switch (m_chartSelectionMode) { case ChartSelectionModeEnum::CHART_SELECTION_MODE_ANY: break; case ChartSelectionModeEnum::CHART_SELECTION_MODE_SINGLE: // if (childChartData->isSelected()) { // const int32_t numChartData = static_cast(m_chartDatas.size()); // for (int32_t i = 0; i < numChartData; i++) { // ChartData* cd = m_chartDatas[i]; // if (cd != childChartData) { // cd->setSelected(false); // } // } // } break; } } /** * Update after chart data has been added or removed. */ void ChartModel::updateAfterChartDataHasBeenAddedOrRemoved() { if (m_bottomAxis != NULL) { m_bottomAxis->updateForAutoRangeScale(); } if (m_leftAxis != NULL) { m_leftAxis->updateForAutoRangeScale(); } if (m_rightAxis != NULL) { m_rightAxis->updateForAutoRangeScale(); } if (m_topAxis != NULL) { m_topAxis->updateForAutoRangeScale(); } } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of the class' instance. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* ChartModel::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { const int32_t numChartData = static_cast(m_chartDatas.size()); if (numChartData <= 0) { return NULL; } SceneClass* sceneClass = new SceneClass(instanceName, "ChartModel", 2); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); if (numChartData > 0) { std::vector chartDataUniqueIDs; for (int32_t i = 0; i < numChartData; i++) { chartDataUniqueIDs.push_back(m_chartDatas[i]->getUniqueIdentifier()); } sceneClass->addStringArray("chartUniqueIDsArray", &chartDataUniqueIDs[0], numChartData); } if (m_bottomAxis != NULL) { sceneClass->addEnumeratedType("bottomAxisType", m_bottomAxis->getAxisType()); sceneClass->addChild(m_bottomAxis->saveToScene(sceneAttributes, "m_bottomAxis")); } if (m_leftAxis != NULL) { sceneClass->addEnumeratedType("leftAxisType", m_leftAxis->getAxisType()); sceneClass->addChild(m_leftAxis->saveToScene(sceneAttributes, "m_leftAxis")); } if (m_rightAxis != NULL) { sceneClass->addEnumeratedType("rightAxisType", m_rightAxis->getAxisType()); sceneClass->addChild(m_rightAxis->saveToScene(sceneAttributes, "m_rightAxis")); } if (m_topAxis != NULL) { sceneClass->addEnumeratedType("topAxisType", m_topAxis->getAxisType()); sceneClass->addChild(m_topAxis->saveToScene(sceneAttributes, "m_topAxis")); } saveSubClassDataToScene(sceneAttributes, sceneClass); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. May be NULL for some types of scenes. */ void ChartModel::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } const int32_t versionNumber = sceneClass->getVersionNumber(); removeChartData(); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); removeAllAxes(); /* * Restore bottom axis */ const ChartAxisTypeEnum::Enum bottomAxisType = sceneClass->getEnumeratedTypeValue("bottomAxisType", ChartAxisTypeEnum::CHART_AXIS_TYPE_NONE); if (bottomAxisType != ChartAxisTypeEnum::CHART_AXIS_TYPE_NONE) { ChartAxis* axis = ChartAxis::newChartAxisForTypeAndLocation(bottomAxisType, ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM); axis->restoreFromScene(sceneAttributes, sceneClass->getClass("m_bottomAxis")); setBottomAxis(axis); } /* * Restore left axis */ const ChartAxisTypeEnum::Enum leftAxisType = sceneClass->getEnumeratedTypeValue("leftAxisType", ChartAxisTypeEnum::CHART_AXIS_TYPE_NONE); if (leftAxisType != ChartAxisTypeEnum::CHART_AXIS_TYPE_NONE) { ChartAxis* axis = ChartAxis::newChartAxisForTypeAndLocation(leftAxisType, ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT); axis->restoreFromScene(sceneAttributes, sceneClass->getClass("m_leftAxis")); setLeftAxis(axis); } if (versionNumber >= 2) { /* * Restore right axis */ const ChartAxisTypeEnum::Enum rightAxisType = sceneClass->getEnumeratedTypeValue("rightAxisType", ChartAxisTypeEnum::CHART_AXIS_TYPE_NONE); if (rightAxisType != ChartAxisTypeEnum::CHART_AXIS_TYPE_NONE) { ChartAxis* axis = ChartAxis::newChartAxisForTypeAndLocation(rightAxisType, ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT); axis->restoreFromScene(sceneAttributes, sceneClass->getClass("m_rightAxis")); setRightAxis(axis); } /* * Restore top axis */ const ChartAxisTypeEnum::Enum topAxisType = sceneClass->getEnumeratedTypeValue("topAxisType", ChartAxisTypeEnum::CHART_AXIS_TYPE_NONE); if (topAxisType != ChartAxisTypeEnum::CHART_AXIS_TYPE_NONE) { ChartAxis* axis = ChartAxis::newChartAxisForTypeAndLocation(topAxisType, ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP); axis->restoreFromScene(sceneAttributes, sceneClass->getClass("m_topAxis")); setTopAxis(axis); } } /* * Restore unique IDs of ChartData */ m_chartDataUniqueIDsRestoredFromScene.clear(); const ScenePrimitiveArray* chartUniqueIDsArray = sceneClass->getPrimitiveArray("chartUniqueIDsArray"); if (chartUniqueIDsArray != NULL) { const int32_t numElements = chartUniqueIDsArray->getNumberOfArrayElements(); m_chartDataUniqueIDsRestoredFromScene.resize(numElements); chartUniqueIDsArray->stringValues(m_chartDataUniqueIDsRestoredFromScene, ""); /* * Need to reverse order so that multiple charts are restored * in the correct order. Done here rather than when saving * scenes so that old scenes are restored correctly. */ if ( ! m_chartDataUniqueIDsRestoredFromScene.empty()) { std::reverse(m_chartDataUniqueIDsRestoredFromScene.begin(), m_chartDataUniqueIDsRestoredFromScene.end()); } } restoreSubClassDataFromScene(sceneAttributes, sceneClass); } /** * Restore chart data from scene by matching unique identifiers from charts * * @param restoredChartData * Chart data restored from scenes. */ void ChartModel::restoreChartDataFromScene(const SceneAttributes* sceneAttributes, std::vector >& restoredChartData) { const int32_t numChartUniqueIDsFromScene = static_cast(m_chartDataUniqueIDsRestoredFromScene.size()); if (numChartUniqueIDsFromScene > 0) { std::vector > chartDataVector(numChartUniqueIDsFromScene); /* * Need to keep chart data in same order as when scene was created */ for (int32_t i = 0; i < numChartUniqueIDsFromScene; i++) { for (std::vector >::iterator chartIter = restoredChartData.begin(); chartIter != restoredChartData.end(); chartIter++) { QSharedPointer cd = *chartIter; if (cd->getUniqueIdentifier() == m_chartDataUniqueIDsRestoredFromScene[i]) { if (cd->getChartDataType() == m_chartDataType) { chartDataVector[i] = cd; break; } } } } /* * Add the restored chart data */ for (int32_t i = 0; i < numChartUniqueIDsFromScene; i++) { QSharedPointer cd = chartDataVector[i]; if (cd.isNull()) { const AString msg("Failed to restore chart with Unique ID: " + m_chartDataUniqueIDsRestoredFromScene[i]); sceneAttributes->addToErrorMessage(msg); CaretLogSevere(msg); } else { addChartData(cd); } } } m_chartDataUniqueIDsRestoredFromScene.clear(); updateUsingMaximumNumberOfChartDatasToDisplay(); updateAfterChartDataHasBeenAddedOrRemoved(); } connectome-workbench-1.4.2/src/Charting/ChartModel.h000066400000000000000000000143311360521144700223560ustar00rootroot00000000000000#ifndef __CHART_MODEL_H__ #define __CHART_MODEL_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretObject.h" #include "ChartOneDataTypeEnum.h" #include "ChartSelectionModeEnum.h" #include "SceneableInterface.h" namespace caret { class ChartAxis; class ChartData; class SceneClassAssistant; class ChartModel : public CaretObject, public SceneableInterface { public: ChartModel(const ChartOneDataTypeEnum::Enum chartDataType, const ChartSelectionModeEnum::Enum chartSelectionMode); ChartModel(const ChartModel&); ChartModel& operator=(const ChartModel&); virtual ~ChartModel(); void removeChartData(); ChartOneDataTypeEnum::Enum getChartDataType() const; ChartSelectionModeEnum::Enum getChartSelectionMode() const; void addChartData(const QSharedPointer& chartData); virtual int32_t getMaximumNumberOfChartDatasToDisplay() const; void setMaximumNumberOfChartDatasToDisplay(const int32_t numberToDisplay); bool isEmpty() const; std::vector getAllChartDatas() const; std::vector getAllChartDatas(); std::vector getAllSelectedChartDatas(const int32_t tabIndex) const; int32_t getNumberOfChartData() const; ChartData* getChartDataAtIndex(const int32_t chartDataIndex); const ChartData* getChartDataAtIndex(const int32_t chartDataIndex) const; void moveChartDataAtIndexToOneLowerIndex(const int32_t chartDataIndex); void moveChartDataAtIndexToOneHigherIndex(const int32_t chartDataIndex); void removeChartAtIndex(const int32_t chartDataIndex); /** * @return Is an average of data supported? */ virtual bool isAverageChartDisplaySupported() const = 0; /** * Get the average for charts in the given tab. * * @param tabIndex * Index of the tab. * * @return * The average chart data. Will return NULL if either * no data to average or model does not support an average. * Includes only those chart data that are displayed. */ virtual const ChartData* getAverageChartDataForDisplay(const int32_t tabIndex) const = 0; bool isAverageChartDisplaySelected() const; void setAverageChartDisplaySelected(const bool selected); ChartAxis* getLeftAxis(); const ChartAxis* getLeftAxis() const; ChartAxis* getRightAxis(); const ChartAxis* getRightAxis() const; ChartAxis* getBottomAxis(); const ChartAxis* getBottomAxis() const; ChartAxis* getTopAxis(); const ChartAxis* getTopAxis() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); void restoreChartDataFromScene(const SceneAttributes* sceneAttributes, std::vector >& restoredChartData); // ADD_NEW_METHODS_HERE virtual AString toString() const; protected: void setBottomAxis(ChartAxis* leftAxis); void setLeftAxis(ChartAxis* leftAxis); void setRightAxis(ChartAxis* leftAxis); void setTopAxis(ChartAxis* leftAxis); virtual void updateAfterChartDataHasBeenAddedOrRemoved(); virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) = 0; virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) = 0; private: void copyHelperChartModel(const ChartModel& obj); void childChartDataSelectionChanged(ChartData* childChartData); void removeChartDataPrivate(); void removeAllAxes(); void updateUsingMaximumNumberOfChartDatasToDisplay(); ChartOneDataTypeEnum::Enum m_chartDataType; ChartSelectionModeEnum::Enum m_chartSelectionMode; std::deque > m_chartDatas; int32_t m_maximumNumberOfChartDatasToDisplay; ChartAxis* m_leftAxis; ChartAxis* m_rightAxis; ChartAxis* m_bottomAxis; ChartAxis* m_topAxis; std::vector m_chartDataUniqueIDsRestoredFromScene; bool m_averageChartDisplaySelected; /** helps with scene save/restore */ SceneClassAssistant* m_sceneAssistant; // ADD_NEW_MEMBERS_HERE friend class ChartData; }; #ifdef __CHART_MODEL_DECLARE__ // #endif // __CHART_MODEL_DECLARE__ } // namespace #endif //__CHART_MODEL_H__ connectome-workbench-1.4.2/src/Charting/ChartModelCartesian.cxx000066400000000000000000000241231360521144700245630ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __CHART_MODEL_CARTESIAN_DECLARE__ #include "ChartModelCartesian.h" #undef __CHART_MODEL_CARTESIAN_DECLARE__ #include "CaretAssert.h" #include "ChartAxis.h" #include "ChartAxisCartesian.h" #include "ChartDataCartesian.h" #include "ChartPoint.h" #include "ChartScaleAutoRanging.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ChartModelCartesian * \brief Chart Model for cartesian data. * \ingroup Charting */ /** * Constructor. * * @param chartDataDataType * The chart model data type. * @param dataAxisUnitsX * Units for the X-axis. * @param dataAxisUnitsY * Units for the Y-axis. */ ChartModelCartesian::ChartModelCartesian(const ChartOneDataTypeEnum::Enum chartDataType, const ChartAxisUnitsEnum::Enum dataAxisUnitsX, const ChartAxisUnitsEnum::Enum dataAxisUnitsY) : ChartModel(chartDataType, ChartSelectionModeEnum::CHART_SELECTION_MODE_ANY) { m_averageChartData = NULL; m_lineWidth = 1.0; setLeftAxis(ChartAxis::newChartAxisForTypeAndLocation(ChartAxisTypeEnum::CHART_AXIS_TYPE_CARTESIAN, ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT)); getLeftAxis()->setAxisUnits(dataAxisUnitsY); getLeftAxis()->setVisible(true); setBottomAxis(ChartAxis::newChartAxisForTypeAndLocation(ChartAxisTypeEnum::CHART_AXIS_TYPE_CARTESIAN, ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM)); getBottomAxis()->setAxisUnits(dataAxisUnitsX); getBottomAxis()->setVisible(true); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_lineWidth", &m_lineWidth); } /** * Destructor. */ ChartModelCartesian::~ChartModelCartesian() { if (m_averageChartData != NULL) { delete m_averageChartData; } delete m_sceneAssistant; } /** * Copy constructor. * @param obj * Object that is copied. */ ChartModelCartesian::ChartModelCartesian(const ChartModelCartesian& obj) : ChartModel(obj) { this->copyHelperChartModelCartesian(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ChartModelCartesian& ChartModelCartesian::operator=(const ChartModelCartesian& obj) { if (this != &obj) { ChartModel::operator=(obj); this->copyHelperChartModelCartesian(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ChartModelCartesian::copyHelperChartModelCartesian(const ChartModelCartesian& /*obj*/) { if (m_averageChartData != NULL) { delete m_averageChartData; m_averageChartData = NULL; } } /** * @return Is an average of data supported? */ bool ChartModelCartesian::isAverageChartDisplaySupported() const { return true; } /** * Get the average for charts in the given tab. * * @param tabIndex * Index of the tab. * * @return * The average chart data. Will return NULL if either * no data to average or model does not support an average. * Includes only those chart data that are displayed. */ const ChartData* ChartModelCartesian::getAverageChartDataForDisplay(const int32_t tabIndex) const { if (m_averageChartData != NULL) { delete m_averageChartData; m_averageChartData = NULL; } /* * Data may be from multiple files so compute an average of those * that match the first (newest) file. */ const std::vector allData = getAllSelectedChartDatas(tabIndex); if ( ! allData.empty()) { std::vector xValue; std::vector ySum; int64_t averageCounter = 0; ChartOneDataTypeEnum::Enum firstChartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; bool firstFlag = true; for (std::vector::const_iterator iter = allData.begin(); iter != allData.end(); iter++) { const ChartData* chartData = *iter; const ChartDataCartesian* cartesianData = dynamic_cast(chartData); CaretAssert(cartesianData); const int64_t numPoints = cartesianData->getNumberOfPoints(); if (firstFlag) { if (numPoints > 0) { firstFlag = false; xValue.resize(numPoints); ySum.resize(numPoints); for (int64_t i = 0; i < numPoints; i++) { const ChartPoint* point = cartesianData->getPointAtIndex(i); xValue[i] = point->getX(); ySum[i] = point->getY(); } firstChartDataType = cartesianData->getChartDataType(); averageCounter = 1; } } else { if (numPoints == static_cast(ySum.size())) { for (int64_t i = 0; i < numPoints; i++) { const ChartPoint* point = cartesianData->getPointAtIndex(i); ySum[i] += point->getY(); } averageCounter++; } } } if (averageCounter > 0) { const int64_t numPoints = static_cast(ySum.size()); for (int64_t i = 0; i < numPoints; i++) { ySum[i] /= averageCounter; } m_averageChartData = dynamic_cast(ChartData::newChartDataForChartDataType(firstChartDataType)); for (int32_t i = 0; i < numPoints; i++) { m_averageChartData->addPoint(xValue[i], ySum[i]); } } } return m_averageChartData; } /** * Get the bounds of all of the data in themodel. * * @param boundsMinX * Minimum X-coordinate of all points. * @param boundsMaxX * Maximum X-coordinate of all points. * @param boundsMinY * Minimum Y-coordinate of all points. * @param boundsMaxY * Maximum Y-coordinate of all points. */ void ChartModelCartesian::getBounds(float& boundsMinX, float& boundsMaxX, float& boundsMinY, float& boundsMaxY) const { boundsMinX = 0.0; boundsMaxX = 0.0; boundsMinY = 0.0; boundsMaxY = 0.0; const std::vector allData = getAllChartDatas(); if ( ! allData.empty()) { boundsMinX = std::numeric_limits::max(); boundsMaxX = -std::numeric_limits::max(); boundsMinY = std::numeric_limits::max(); boundsMaxY = -std::numeric_limits::max(); for (std::vector::const_iterator iter = allData.begin(); iter != allData.end(); iter++) { const ChartData* chartData = *iter; const ChartDataCartesian* cartesianData = dynamic_cast(chartData); CaretAssert(cartesianData); float xMin, xMax, yMin, yMax; cartesianData->getBounds(xMin, xMax, yMin, yMax); if (xMin < boundsMinX) boundsMinX = xMin; if (xMax > boundsMaxX) boundsMaxX = xMax; if (yMin < boundsMinY) boundsMinY = yMin; if (yMax > boundsMaxY) boundsMaxY = yMax; } } } /** * Get the line width for the chart. * * @return * Line width for the chart. */ float ChartModelCartesian::getLineWidth() const { return m_lineWidth; } /** * Set the line width for the chart. * * param lineWidth * Line width for chart. */ void ChartModelCartesian::setLineWidth(const float lineWidth) { m_lineWidth = lineWidth; } /** * Save subclass data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void ChartModelCartesian::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void ChartModelCartesian::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } connectome-workbench-1.4.2/src/Charting/ChartModelCartesian.h000066400000000000000000000057111360521144700242120ustar00rootroot00000000000000#ifndef __CHART_MODEL_CARTESIAN_H__ #define __CHART_MODEL_CARTESIAN_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ChartAxisUnitsEnum.h" #include "ChartModel.h" namespace caret { class ChartDataCartesian; class ChartModelCartesian : public ChartModel { public: ChartModelCartesian(const ChartOneDataTypeEnum::Enum chartDataType, const ChartAxisUnitsEnum::Enum dataAxisUnitsX, const ChartAxisUnitsEnum::Enum dataAxisUnitsY); virtual ~ChartModelCartesian(); ChartModelCartesian(const ChartModelCartesian& obj); ChartModelCartesian& operator=(const ChartModelCartesian& obj); void getBounds(float& boundsMinX, float& boundsMaxX, float& boundsMinY, float& boundsMaxY) const; virtual bool isAverageChartDisplaySupported() const; virtual const ChartData* getAverageChartDataForDisplay(const int32_t tabIndex) const; float getLineWidth() const; void setLineWidth(const float lineWidth); // ADD_NEW_METHODS_HERE protected: virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: void copyHelperChartModelCartesian(const ChartModelCartesian& obj); // void adjustAxisDefaultRange(float& minValue, // float& maxValue); SceneClassAssistant* m_sceneAssistant; mutable ChartDataCartesian* m_averageChartData; float m_lineWidth; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHART_MODEL_CARTESIAN_DECLARE__ // #endif // __CHART_MODEL_CARTESIAN_DECLARE__ } // namespace #endif //__CHART_MODEL_CARTESIAN_H__ connectome-workbench-1.4.2/src/Charting/ChartModelDataSeries.cxx000066400000000000000000000043601360521144700246770ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_MODEL_DATA_SERIES_DECLARE__ #include "ChartModelDataSeries.h" #undef __CHART_MODEL_DATA_SERIES_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartModelDataSeries * \brief Chart model for line series charts. * \ingroup Charting */ /** * Constructor. */ ChartModelDataSeries::ChartModelDataSeries() : ChartModelCartesian(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE) { } /** * Destructor. */ ChartModelDataSeries::~ChartModelDataSeries() { } /** * Copy constructor. * @param obj * Object that is copied. */ ChartModelDataSeries::ChartModelDataSeries(const ChartModelDataSeries& obj) : ChartModelCartesian(obj) { this->copyHelperChartModelDataSeries(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ChartModelDataSeries& ChartModelDataSeries::operator=(const ChartModelDataSeries& obj) { if (this != &obj) { ChartModelCartesian::operator=(obj); this->copyHelperChartModelDataSeries(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ChartModelDataSeries::copyHelperChartModelDataSeries(const ChartModelDataSeries& /*obj*/) { } connectome-workbench-1.4.2/src/Charting/ChartModelDataSeries.h000066400000000000000000000031731360521144700243250ustar00rootroot00000000000000#ifndef __CHART_MODEL_DATA_SERIES_H__ #define __CHART_MODEL_DATA_SERIES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ChartModelCartesian.h" namespace caret { class ChartModelDataSeries : public ChartModelCartesian { public: ChartModelDataSeries(); virtual ~ChartModelDataSeries(); ChartModelDataSeries(const ChartModelDataSeries& obj); ChartModelDataSeries& operator=(const ChartModelDataSeries& obj); // ADD_NEW_METHODS_HERE private: void copyHelperChartModelDataSeries(const ChartModelDataSeries& obj); // ADD_NEW_MEMBERS_HERE }; #ifdef __CHART_MODEL_DATA_SERIES_DECLARE__ // #endif // __CHART_MODEL_DATA_SERIES_DECLARE__ } // namespace #endif //__CHART_MODEL_DATA_SERIES_H__ connectome-workbench-1.4.2/src/Charting/ChartModelFrequencySeries.cxx000066400000000000000000000045441360521144700257730ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_MODEL_FREQUENCY_SERIES_DECLARE__ #include "ChartModelFrequencySeries.h" #undef __CHART_MODEL_FREQUENCY_SERIES_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartModelFrequencySeries * \brief Chart model for frequency series charts. * \ingroup Charting */ /** * Constructor. */ ChartModelFrequencySeries::ChartModelFrequencySeries() : ChartModelCartesian(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES, ChartAxisUnitsEnum::CHART_AXIS_UNITS_FREQUENCY_HERTZ, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE) { } /** * Destructor. */ ChartModelFrequencySeries::~ChartModelFrequencySeries() { } /** * Copy constructor. * @param obj * Object that is copied. */ ChartModelFrequencySeries::ChartModelFrequencySeries(const ChartModelFrequencySeries& obj) : ChartModelCartesian(obj) { this->copyHelperChartModelFrequencySeries(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ChartModelFrequencySeries& ChartModelFrequencySeries::operator=(const ChartModelFrequencySeries& obj) { if (this != &obj) { ChartModelCartesian::operator=(obj); this->copyHelperChartModelFrequencySeries(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ChartModelFrequencySeries::copyHelperChartModelFrequencySeries(const ChartModelFrequencySeries& /*obj*/) { } connectome-workbench-1.4.2/src/Charting/ChartModelFrequencySeries.h000066400000000000000000000033011360521144700254060ustar00rootroot00000000000000#ifndef __CHART_MODEL_FREQUENCY_SERIES_H__ #define __CHART_MODEL_FREQUENCY_SERIES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ChartModelCartesian.h" namespace caret { class ChartModelFrequencySeries : public ChartModelCartesian { public: ChartModelFrequencySeries(); virtual ~ChartModelFrequencySeries(); ChartModelFrequencySeries(const ChartModelFrequencySeries& obj); ChartModelFrequencySeries& operator=(const ChartModelFrequencySeries& obj); // ADD_NEW_METHODS_HERE private: void copyHelperChartModelFrequencySeries(const ChartModelFrequencySeries& obj); // ADD_NEW_MEMBERS_HERE }; #ifdef __CHART_MODEL_FREQUENCY_SERIES_DECLARE__ // #endif // __CHART_MODEL_FREQUENCY_SERIES_DECLARE__ } // namespace #endif //__CHART_MODEL_FREQUENCY_SERIES_H__ connectome-workbench-1.4.2/src/Charting/ChartModelTimeSeries.cxx000066400000000000000000000043701360521144700247250ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_MODEL_TIME_SERIES_DECLARE__ #include "ChartModelTimeSeries.h" #undef __CHART_MODEL_TIME_SERIES_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartModelTimeSeries * \brief Chart model for line series charts. * \ingroup Charting */ /** * Constructor. */ ChartModelTimeSeries::ChartModelTimeSeries() : ChartModelCartesian(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES, ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE) { } /** * Destructor. */ ChartModelTimeSeries::~ChartModelTimeSeries() { } /** * Copy constructor. * @param obj * Object that is copied. */ ChartModelTimeSeries::ChartModelTimeSeries(const ChartModelTimeSeries& obj) : ChartModelCartesian(obj) { this->copyHelperChartModelTimeSeries(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ChartModelTimeSeries& ChartModelTimeSeries::operator=(const ChartModelTimeSeries& obj) { if (this != &obj) { ChartModelCartesian::operator=(obj); this->copyHelperChartModelTimeSeries(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ChartModelTimeSeries::copyHelperChartModelTimeSeries(const ChartModelTimeSeries& /*obj*/) { } connectome-workbench-1.4.2/src/Charting/ChartModelTimeSeries.h000066400000000000000000000031731360521144700243520ustar00rootroot00000000000000#ifndef __CHART_MODEL_TIME_SERIES_H__ #define __CHART_MODEL_TIME_SERIES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ChartModelCartesian.h" namespace caret { class ChartModelTimeSeries : public ChartModelCartesian { public: ChartModelTimeSeries(); virtual ~ChartModelTimeSeries(); ChartModelTimeSeries(const ChartModelTimeSeries& obj); ChartModelTimeSeries& operator=(const ChartModelTimeSeries& obj); // ADD_NEW_METHODS_HERE private: void copyHelperChartModelTimeSeries(const ChartModelTimeSeries& obj); // ADD_NEW_MEMBERS_HERE }; #ifdef __CHART_MODEL_TIME_SERIES_DECLARE__ // #endif // __CHART_MODEL_TIME_SERIES_DECLARE__ } // namespace #endif //__CHART_MODEL_TIME_SERIES_H__ connectome-workbench-1.4.2/src/Charting/ChartOneDataTypeEnum.cxx000066400000000000000000000275271360521144700247060ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CHART_VERSION_ONE_DATA_TYPE_ENUM_DECLARE__ #include "ChartOneDataTypeEnum.h" #undef __CHART_VERSION_ONE_DATA_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartOneDataTypeEnum * \brief Enumerated type for type of VERSION ONE chart data. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_chartDataTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void chartDataTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ChartOneDataTypeEnum.h" * * Instatiate: * m_chartDataTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_chartDataTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_chartDataTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(chartDataTypeEnumComboBoxItemActivated())); * * Update the selection: * m_chartDataTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ChartOneDataTypeEnum::Enum VARIABLE = m_chartDataTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ChartOneDataTypeEnum::ChartOneDataTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ChartOneDataTypeEnum::~ChartOneDataTypeEnum() { } /** * Initialize the enumerated metadata. */ void ChartOneDataTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ChartOneDataTypeEnum(CHART_DATA_TYPE_INVALID, "CHART_DATA_TYPE_INVALID", "Invalid")); enumData.push_back(ChartOneDataTypeEnum(CHART_DATA_TYPE_LINE_DATA_SERIES, "CHART_DATA_TYPE_LINE_DATA_SERIES", "Data Series")); enumData.push_back(ChartOneDataTypeEnum(CHART_DATA_TYPE_LINE_FREQUENCY_SERIES, "CHART_DATA_TYPE_LINE_FREQUENCY_SERIES", "Frequency Series")); enumData.push_back(ChartOneDataTypeEnum(CHART_DATA_TYPE_LINE_TIME_SERIES, "CHART_DATA_TYPE_LINE_TIME_SERIES", "Time Series")); enumData.push_back(ChartOneDataTypeEnum(CHART_DATA_TYPE_MATRIX_LAYER, "CHART_DATA_TYPE_MATRIX_LAYER", "Matrix - Layer")); enumData.push_back(ChartOneDataTypeEnum(CHART_DATA_TYPE_MATRIX_SERIES, "CHART_DATA_TYPE_MATRIX_SERIES", "Matrix - Series")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ChartOneDataTypeEnum* ChartOneDataTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ChartOneDataTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartOneDataTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartOneDataTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param nameIn * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartOneDataTypeEnum::Enum ChartOneDataTypeEnum::fromName(const AString& nameIn, bool* isValidOut) { if (initializedFlag == false) initialize(); /* * Convert from obsolete names */ AString name(nameIn); if (name == "CHART_DATA_TYPE_MATRIX") { name = "CHART_DATA_TYPE_MATRIX_LAYER"; } else if (name == "CHART_DATA_TYPE_DATA_SERIES") { name = "CHART_DATA_TYPE_LINE_DATA_SERIES"; } else if (name == "CHART_DATA_TYPE_TIME_SERIES") { name = "CHART_DATA_TYPE_LINE_TIME_SERIES"; } bool validFlag = false; Enum enumValue = ChartOneDataTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartOneDataTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartOneDataTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartOneDataTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartOneDataTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param guiNameIn * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartOneDataTypeEnum::Enum ChartOneDataTypeEnum::fromGuiName(const AString& guiNameIn, bool* isValidOut) { if (initializedFlag == false) initialize(); AString guiName(guiNameIn); if (guiName == "Matrix") { guiName = "Matrix - Layer"; } bool validFlag = false; Enum enumValue = ChartOneDataTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartOneDataTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartOneDataTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ChartOneDataTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartOneDataTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ChartOneDataTypeEnum::Enum ChartOneDataTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartOneDataTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartOneDataTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartOneDataTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ChartOneDataTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartOneDataTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ChartOneDataTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartOneDataTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ChartOneDataTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Charting/ChartOneDataTypeEnum.h000066400000000000000000000067251360521144700243300ustar00rootroot00000000000000#ifndef __CHART_VERSION_ONE_DATA_TYPE_ENUM_H__ #define __CHART_VERSION_ONE_DATA_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ChartOneDataTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Invalid */ CHART_DATA_TYPE_INVALID, /** Line Data Series */ CHART_DATA_TYPE_LINE_DATA_SERIES, /** Line Frequency Series */ CHART_DATA_TYPE_LINE_FREQUENCY_SERIES, /** Line Time Series */ CHART_DATA_TYPE_LINE_TIME_SERIES, /** Matrix (connectivity in layer) */ CHART_DATA_TYPE_MATRIX_LAYER, /** Matrix (series data) */ CHART_DATA_TYPE_MATRIX_SERIES }; ~ChartOneDataTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ChartOneDataTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ChartOneDataTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __CHART_VERSION_ONE_DATA_TYPE_ENUM_DECLARE__ std::vector ChartOneDataTypeEnum::enumData; bool ChartOneDataTypeEnum::initializedFlag = false; int32_t ChartOneDataTypeEnum::integerCodeCounter = 0; #endif // __CHART_VERSION_ONE_DATA_TYPE_ENUM_DECLARE__ } // namespace #endif //__CHART_VERSION_ONE_DATA_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Charting/ChartPoint.cxx000066400000000000000000000050661360521144700227670ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_POINT_DECLARE__ #include "ChartPoint.h" #undef __CHART_POINT_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartPoint * \brief Point displayed in a chart. * \ingroup Charting */ /** * Constructor. * * @param x * X coordinate of point. * @param y * Y coordinate of point. */ ChartPoint::ChartPoint(const float x, const float y) : CaretObject() { m_xyz[0] = x; m_xyz[1] = y; m_xyz[2] = 0.0; } /** * Destructor. */ ChartPoint::~ChartPoint() { } /** * Copy constructor. * @param obj * Object that is copied. */ ChartPoint::ChartPoint(const ChartPoint& obj) : CaretObject(obj) { this->copyHelperChartPoint(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ChartPoint& ChartPoint::operator=(const ChartPoint& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperChartPoint(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ChartPoint::copyHelperChartPoint(const ChartPoint& obj) { m_xyz[0] = obj.m_xyz[0]; m_xyz[1] = obj.m_xyz[1]; m_xyz[2] = obj.m_xyz[2]; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ChartPoint::toString() const { return "ChartPoint"; } /** * @return Pointer to X & Y coordinates. */ const float* ChartPoint::getXY() const { return &m_xyz[0]; } /** * @return X coordinate. */ float ChartPoint::getX() const { return m_xyz[0]; } /** * @return Y coordinate. */ float ChartPoint::getY() const { return m_xyz[1]; } connectome-workbench-1.4.2/src/Charting/ChartPoint.h000066400000000000000000000033061360521144700224070ustar00rootroot00000000000000#ifndef __CHART_POINT_H__ #define __CHART_POINT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" namespace caret { class ChartPoint : public CaretObject { public: ChartPoint(const float x, const float y); virtual ~ChartPoint(); ChartPoint(const ChartPoint& obj); ChartPoint& operator=(const ChartPoint& obj); const float* getXY() const; float getX() const; float getY() const; // ADD_NEW_METHODS_HERE virtual AString toString() const; private: void copyHelperChartPoint(const ChartPoint& obj); float m_xyz[3]; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHART_POINT_DECLARE__ // #endif // __CHART_POINT_DECLARE__ } // namespace #endif //__CHART_POINT_H__ connectome-workbench-1.4.2/src/Charting/ChartScaleAutoRanging.cxx000066400000000000000000000342611360521144700250630ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __CHART_SCALE_AUTO_RANGING_DECLARE__ #include "ChartScaleAutoRanging.h" #undef __CHART_SCALE_AUTO_RANGING_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" using namespace caret; /** * \class caret::ChartScaleAutoRanging * \brief Adjust minimum and maximum value for auto ranging. * \ingroup Charting */ /** * Constructor. */ ChartScaleAutoRanging::ChartScaleAutoRanging() : CaretObject() { } /** * Destructor. */ ChartScaleAutoRanging::~ChartScaleAutoRanging() { } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ChartScaleAutoRanging::toString() const { return "ChartScaleAutoRanging"; } static const double smallNegValue = -1.0e-6; static const double smallPosValue = 1.0e-6; /** * Is the value roughly zero? * * @param value * The value * @return * True if value is roughly zero, else false. */ bool ChartScaleAutoRanging::isZero(const double value) { if ((value >= smallNegValue) && (value < smallPosValue)) { return true; } return false; } ///** // * Adjust the magnitude of a value so that it is an integral // * value that is more/less positive (if positive) or more/less negative // * (if negative). // * // * @param valueIn // * The input value. // * @param rangeIn // * Range between minimum and maximum values. // * @param increaseMagnitudeFlag // * True if increasing value, else false. // * @return // * The adjusted value. // */ //double //ChartScaleAutoRanging::adjustValueMagnitude(const double valueIn, // const double rangeIn, // const bool increaseMagnitudeFlag) //{ // double outputValue = valueIn; // double range = rangeIn; // // if (isZero(valueIn)) { // outputValue = 0.0; // } // else if (isZero(range)) { // outputValue = valueIn; // } // else { // double value = valueIn; // double scaleAmount = 1.0; // // /* // * If value is less than one scale it up to be // * greater than or equal to one // */ // if (range < 1.0) { // double originalRange = range; // int32_t counter = 0; // while (range < 1.0) { // scaleAmount *= 10.0; // range = originalRange * scaleAmount; // counter++; // if (counter > 10) { // /* // * Should never happen but don't get stuck in loop // */ // break; // } // } // // value *= scaleAmount; // } // // /* // * Only works for positive values // * Will be converted back to negative later // */ // bool flipFlag = false; // if (value < 0.0) { // flipFlag = true; // value = -value; // } // // /* // * Determine size of value (10s, 100s, 1000s, etc) // */ // const double rangeLog10 = std::log10(range); // double logLessOne = std::floor(rangeLog10); // if (logLessOne >= 1) { // --logLessOne; // } // else { // logLessOne = 0.0; // } // // const int64_t intLogValue = std::pow(10.0, logLessOne); // // /* // * Adust the value // */ // double adjValue = (increaseMagnitudeFlag // ? (value + intLogValue) // : (value - intLogValue)); // // bool addSmallPercentFlag = true; // if (addSmallPercentFlag) { // const double percentAmount = range * 0.05; // adjValue = (increaseMagnitudeFlag // ? (adjValue + percentAmount) // : (adjValue - percentAmount)); // } // // double intValue = (int64_t)adjValue; // if (intLogValue >= 1) { // intValue = (int64_t)adjValue / intLogValue; // } // // double newValue = intValue * intLogValue; // // if (flipFlag) { // newValue = -newValue; // } // // outputValue = newValue / scaleAmount; // } // // return outputValue; //} // ///** // * Increase the value. // * // * @param valueIn // * The input value. // * @param range // * Range between minimum and maximum values. // * @return // * The adjusted value. // */ //double //ChartScaleAutoRanging::adjustValueUp(double valueIn, // const double range) //{ // return adjustValueMagnitude(valueIn, range, true); //} // ///** // * Decrease the value. // * // * @param valueIn // * The input value. // * @param range // * Range between minimum and maximum values. // * @return // * The adjusted value. // */ //double //ChartScaleAutoRanging::adjustValueDown(double valueIn, // const double range) //{ // return adjustValueMagnitude(valueIn, range, false); //} // ///** // * Adjust the data min/max values to that they extend a little // * beyond the rannge of the data but at an integral value. // * // * @param minValueInOut // * Minimum value that is adjusted. // * @param maxValueInOut // * Maximum value that is adjusted. // */ //void //ChartScaleAutoRanging::adjustAxisDefaultRange(float& minValueInOut, // float& maxValueInOut) //{ // double maxValue = maxValueInOut; // double minValue = minValueInOut; // // /* // * Handle instance where max value is greater than // * min value. // */ // bool invertedRangeFlag = false; // double dataRange = maxValue - minValue; // if (dataRange < 0.0) { // std::swap(minValue, maxValue); // dataRange = -dataRange; // invertedRangeFlag = true; // } // // if (maxValue > 0) { // maxValue = adjustValueUp(maxValue, dataRange); // } // else if (maxValue < 0.0) { // maxValue = adjustValueDown(maxValue, dataRange); // } // // if (minValue > 0) { // minValue = adjustValueDown(minValue, dataRange); // } // else if (minValue < 0.0) { // minValue = adjustValueUp(minValue, dataRange); // } // // CaretLogFine("Range was (" // + AString::number(minValueInOut) // + ", " // + AString::number(maxValueInOut) // + ") now (" // + AString::number(minValue) // + ", " // + AString::number(maxValue) // + ")"); // // if (invertedRangeFlag) { // minValueInOut = maxValue; // maxValueInOut = minValue; // } // else { // minValueInOut = minValue; // maxValueInOut = maxValue; // } //} //#ifdef POW_NOT_TRUSTWORTHY ///* if roundoff errors in pow cause problems, use this: */ // //double expt(a, n) //double a; //register int n; //{ // double x; // // x = 1.; // if (n>0) for (; n>0; n--) x *= a; // else for (; n<0; n++) x /= a; // return x; //} // //#else //# define expt(a, n) pow(a, (double)(n)) //#endif static double expt(double a, int32_t n) { return std::pow(a, static_cast(n)); } /* * nicenum: find a "nice" number approximately equal to x. * Round the number if round=1, take ceiling if round=0 */ static double nicenum(double x, int round) { int expv; /* exponent of x */ double f; /* fractional part of x */ double nf; /* nice, rounded fraction */ expv = static_cast(std::floor(std::log10(x))); f = x/expt(10., expv); /* between 1 and 10 */ if (round) if (f<1.5) nf = 1.; else if (f<3.) nf = 2.; else if (f<7.) nf = 5.; else nf = 10.; else if (f<=1.) nf = 1.; else if (f<=2.) nf = 2.; else if (f<=5.) nf = 5.; else nf = 10.; return nf*expt(10., expv); } //#define NTICK 5 /* desired number of tick marks */ //void //loose_label(double min, double max) //{ // char str[6], temp[20]; // int nfrac; // double d; /* tick mark spacing */ // double graphmin, graphmax; /* graph range min and max */ // double range, x; // // /* we expect min!=max */ // range = nicenum(max-min, 0); // d = nicenum(range/(NTICK-1), 1); // graphmin = floor(min/d)*d; // graphmax = ceil(max/d)*d; // nfrac = std::max(-floor(log10(d)), (double)0); /* # of fractional digits to show */ // sprintf(str, "%%.%df", nfrac); /* simplest axis labels */ // // printf("graphmin=%g graphmax=%g increment=%g\n", graphmin, graphmax, d); // for (x=graphmin; x(std::max(-std::floor(log10(d)), (double)0)); /* # of fractional digits to show */ // sprintf(str, "%%.%df", nfrac); /* simplest axis labels */ // // printf("graphmin=%g graphmax=%g increment=%g\n", graphmin, graphmax, d); // for (x=graphmin; x #endif // __CHART_SCALE_AUTO_RANGING_DECLARE__ } // namespace #endif //__CHART_SCALE_AUTO_RANGING_H__ connectome-workbench-1.4.2/src/Charting/ChartSelectionModeEnum.cxx000066400000000000000000000251551360521144700252560ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CHART_SELECTION_MODE_ENUM_DECLARE__ #include "ChartSelectionModeEnum.h" #undef __CHART_SELECTION_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartSelectionModeEnum * \brief Enumerated type for chart selection mode. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_chartSelectionModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void chartSelectionModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ChartSelectionModeEnum.h" * * Instatiate: * m_chartSelectionModeEnumComboBox = new EnumComboBoxTemplate(this); * m_chartSelectionModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_chartSelectionModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(chartSelectionModeEnumComboBoxItemActivated())); * * Update the selection: * m_chartSelectionModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ChartSelectionModeEnum::Enum VARIABLE = m_chartSelectionModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ChartSelectionModeEnum::ChartSelectionModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ChartSelectionModeEnum::~ChartSelectionModeEnum() { } /** * Initialize the enumerated metadata. */ void ChartSelectionModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ChartSelectionModeEnum(CHART_SELECTION_MODE_ANY, "CHART_SELECTION_MODE_ANY", "Any item(s) can be selected")); enumData.push_back(ChartSelectionModeEnum(CHART_SELECTION_MODE_SINGLE, "CHART_SELECTION_MODE_SINGLE", "Only one item can be selected")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ChartSelectionModeEnum* ChartSelectionModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ChartSelectionModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartSelectionModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartSelectionModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartSelectionModeEnum::Enum ChartSelectionModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartSelectionModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartSelectionModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartSelectionModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartSelectionModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartSelectionModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartSelectionModeEnum::Enum ChartSelectionModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartSelectionModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartSelectionModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartSelectionModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ChartSelectionModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartSelectionModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ChartSelectionModeEnum::Enum ChartSelectionModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartSelectionModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartSelectionModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartSelectionModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ChartSelectionModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartSelectionModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ChartSelectionModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartSelectionModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ChartSelectionModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Charting/ChartSelectionModeEnum.h000066400000000000000000000063111360521144700246740ustar00rootroot00000000000000#ifndef __CHART_SELECTION_MODE_ENUM_H__ #define __CHART_SELECTION_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ChartSelectionModeEnum { public: /** * Enumerated values. */ enum Enum { /** Any number of items can be selected from none to all */ CHART_SELECTION_MODE_ANY, /** Only one item can be selected at any time */ CHART_SELECTION_MODE_SINGLE }; ~ChartSelectionModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ChartSelectionModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ChartSelectionModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __CHART_SELECTION_MODE_ENUM_DECLARE__ std::vector ChartSelectionModeEnum::enumData; bool ChartSelectionModeEnum::initializedFlag = false; int32_t ChartSelectionModeEnum::integerCodeCounter = 0; #endif // __CHART_SELECTION_MODE_ENUM_DECLARE__ } // namespace #endif //__CHART_SELECTION_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Charting/ChartTwoAxisScaleRangeModeEnum.cxx000066400000000000000000000273341360521144700266550ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CHART_TWO_AXIS_SCALE_RANGE_MODE_ENUM_DECLARE__ #include "ChartTwoAxisScaleRangeModeEnum.h" #undef __CHART_TWO_AXIS_SCALE_RANGE_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartTwoAxisScaleRangeModeEnum * \brief Chart Two Axis Scale Range Mode. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_chartTwoAxisScaleRangeModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void chartTwoAxisScaleRangeModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ChartTwoAxisScaleRangeModeEnum.h" * * Instatiate: * m_chartTwoAxisScaleRangeModeEnumComboBox = new EnumComboBoxTemplate(this); * m_chartTwoAxisScaleRangeModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_chartTwoAxisScaleRangeModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(chartTwoAxisScaleRangeModeEnumComboBoxItemActivated())); * * Update the selection: * m_chartTwoAxisScaleRangeModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ChartTwoAxisScaleRangeModeEnum::Enum VARIABLE = m_chartTwoAxisScaleRangeModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. * @param oldName * An older version of 'name' */ ChartTwoAxisScaleRangeModeEnum::ChartTwoAxisScaleRangeModeEnum(const Enum enumValue, const AString& name, const AString& guiName, const AString& oldName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; this->oldName = oldName; } /** * Destructor. */ ChartTwoAxisScaleRangeModeEnum::~ChartTwoAxisScaleRangeModeEnum() { } /** * Initialize the enumerated metadata. */ void ChartTwoAxisScaleRangeModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ChartTwoAxisScaleRangeModeEnum(AUTO, "AUTO", "Auto", "AXIS_DATA_RANGE_AUTO")); enumData.push_back(ChartTwoAxisScaleRangeModeEnum(DATA, "DATA", "Data", "AXIS_DATA_RANGE_DATA")); enumData.push_back(ChartTwoAxisScaleRangeModeEnum(USER, "USER", "User", "AXIS_DATA_RANGE_USER")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ChartTwoAxisScaleRangeModeEnum* ChartTwoAxisScaleRangeModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ChartTwoAxisScaleRangeModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartTwoAxisScaleRangeModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoAxisScaleRangeModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartTwoAxisScaleRangeModeEnum::Enum ChartTwoAxisScaleRangeModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoAxisScaleRangeModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoAxisScaleRangeModeEnum& d = *iter; if ((d.name == name) || (d.oldName == name)) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartTwoAxisScaleRangeModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartTwoAxisScaleRangeModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoAxisScaleRangeModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartTwoAxisScaleRangeModeEnum::Enum ChartTwoAxisScaleRangeModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoAxisScaleRangeModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoAxisScaleRangeModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartTwoAxisScaleRangeModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ChartTwoAxisScaleRangeModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoAxisScaleRangeModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ChartTwoAxisScaleRangeModeEnum::Enum ChartTwoAxisScaleRangeModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoAxisScaleRangeModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoAxisScaleRangeModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartTwoAxisScaleRangeModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ChartTwoAxisScaleRangeModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartTwoAxisScaleRangeModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ChartTwoAxisScaleRangeModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartTwoAxisScaleRangeModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ChartTwoAxisScaleRangeModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Charting/ChartTwoAxisScaleRangeModeEnum.h000066400000000000000000000070171360521144700262760ustar00rootroot00000000000000#ifndef __CHART_TWO_AXIS_SCALE_RANGE_MODE_ENUM_H__ #define __CHART_TWO_AXIS_SCALE_RANGE_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ChartTwoAxisScaleRangeModeEnum { public: /** * Enumerated values. */ enum Enum { /** Auto scales and pads for nice numeric scale values */ AUTO, /** Scales to minimum and maximum of data */ DATA, /** Scales to user-specified minimum and maximum */ /** */ USER }; ~ChartTwoAxisScaleRangeModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ChartTwoAxisScaleRangeModeEnum(const Enum enumValue, const AString& name, const AString& guiName, const AString& oldName); static const ChartTwoAxisScaleRangeModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; /** For older version of 'name' */ AString oldName; }; #ifdef __CHART_TWO_AXIS_SCALE_RANGE_MODE_ENUM_DECLARE__ std::vector ChartTwoAxisScaleRangeModeEnum::enumData; bool ChartTwoAxisScaleRangeModeEnum::initializedFlag = false; int32_t ChartTwoAxisScaleRangeModeEnum::integerCodeCounter = 0; #endif // __CHART_TWO_AXIS_SCALE_RANGE_MODE_ENUM_DECLARE__ } // namespace #endif //__CHART_TWO_AXIS_SCALE_RANGE_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Charting/ChartTwoCartesianAxis.cxx000066400000000000000000000733711360521144700251320ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_TWO_CARTESIAN_AXIS_DECLARE__ #include "ChartTwoCartesianAxis.h" #undef __CHART_TWO_CARTESIAN_AXIS_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "ChartScaleAutoRanging.h" #include "EventChartTwoAxisGetDataRange.h" #include "EventManager.h" #include "MathFunctions.h" #include "NumericTextFormatting.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ChartTwoCartesianAxis * \brief Chart Two Cartesian Axis Attributes. * \ingroup Charting */ /** * Constructor. * * @param axisLocation * Location of the axis (left, right, bottom, top) * @param parentChartOverlaySet * Parent of this axis. */ ChartTwoCartesianAxis::ChartTwoCartesianAxis(const ChartTwoOverlaySet* parentChartOverlaySet, const ChartAxisLocationEnum::Enum axisLocation) : CaretObject(), SceneableInterface(), m_parentChartOverlaySet(parentChartOverlaySet), m_axisLocation(axisLocation) { /* * Note: Parent chart overlay set is used for sending an event * to the parent to get the range of data. Note that parent * chart overlay is in 'Brain' module which we have no access. */ CaretAssert(m_parentChartOverlaySet); m_showTickmarks = true; m_showLabel = true; m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); m_sceneAssistant->add("m_displayedByUser", &m_displayedByUser); m_sceneAssistant->add("m_userScaleMinimumValue", &m_userScaleMinimumValue); m_sceneAssistant->add("m_userScaleMaximumValue", &m_userScaleMaximumValue); m_sceneAssistant->add("m_axisLabelsStepValue", &m_axisLabelsStepValue); m_sceneAssistant->add("m_userDigitsRightOfDecimal", &m_userDigitsRightOfDecimal); m_sceneAssistant->add("m_scaleRangeMode", &m_scaleRangeMode); m_sceneAssistant->add("m_units", &m_units); m_sceneAssistant->add("m_userNumericFormat", &m_userNumericFormat); m_sceneAssistant->add("m_numericSubdivsionsMode", &m_numericSubdivsionsMode); m_sceneAssistant->add("m_userNumberOfSubdivisions", &m_userNumberOfSubdivisions); m_sceneAssistant->add("m_enabledByChart", &m_enabledByChart); m_sceneAssistant->add("m_showTickmarks", &m_showTickmarks); m_sceneAssistant->add("m_showLabel", &m_showLabel); m_sceneAssistant->add("m_titleOverlayIndex", &m_titleOverlayIndex); m_sceneAssistant->add("m_labelTextSize", &m_labelTextSize); m_sceneAssistant->add("m_numericsTextSize", &m_numericsTextSize); m_sceneAssistant->add("m_numericsTextDisplayed", &m_numericsTextDisplayed); m_sceneAssistant->add("m_numericsTextRotated", &m_numericsTextRotated); m_sceneAssistant->add("m_paddingSize", &m_paddingSize); } /** * Destructor. */ ChartTwoCartesianAxis::~ChartTwoCartesianAxis() { } /** * Copy constructor. * @param obj * Object that is copied. */ ChartTwoCartesianAxis::ChartTwoCartesianAxis(const ChartTwoCartesianAxis& obj) : CaretObject(obj), SceneableInterface(obj), m_axisLocation(obj.m_axisLocation) { this->copyHelperChartTwoCartesianAxis(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ChartTwoCartesianAxis& ChartTwoCartesianAxis::operator=(const ChartTwoCartesianAxis& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperChartTwoCartesianAxis(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ChartTwoCartesianAxis::copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAxis& obj) { CaretAssert(m_axisLocation == obj.m_axisLocation); m_titleOverlayIndex = obj.m_titleOverlayIndex; m_displayedByUser = obj.m_displayedByUser; m_userScaleMinimumValue = obj.m_userScaleMinimumValue; m_userScaleMaximumValue = obj.m_userScaleMaximumValue; m_axisLabelsStepValue = obj.m_axisLabelsStepValue; m_userDigitsRightOfDecimal = obj.m_userDigitsRightOfDecimal; m_scaleRangeMode = obj.m_scaleRangeMode; m_units = obj.m_units; m_userNumericFormat = obj.m_userNumericFormat; m_numericSubdivsionsMode = obj.m_numericSubdivsionsMode; m_userNumberOfSubdivisions = obj.m_userNumberOfSubdivisions; m_enabledByChart = obj.m_enabledByChart; m_showTickmarks = obj.m_showTickmarks; m_showLabel = obj.m_showLabel; m_labelTextSize = obj.m_labelTextSize; m_numericsTextSize = obj.m_numericsTextSize; m_numericsTextDisplayed = obj.m_numericsTextDisplayed; m_numericsTextRotated = obj.m_numericsTextRotated; m_paddingSize = obj.m_paddingSize; limitUserScaleMinMaxToValidRange(); } /** * @return The axis location (left, right, bottom, top) */ ChartAxisLocationEnum::Enum ChartTwoCartesianAxis::getAxisLocation() const { return m_axisLocation; } /** * @return display the axis selected by user */ bool ChartTwoCartesianAxis::isDisplayedByUser() const { return m_displayedByUser; } /** * Set display the axis by user * @param displayedByUser * New value for display the axis */ void ChartTwoCartesianAxis::setDisplayedByUser(const bool displayedByUser) { m_displayedByUser = displayedByUser; } /** * Get the range of data for this axis. * * @param rangeMinimumOut * Minimum value allowed. * @param rangeMaximumOut * Maximum value allowed. */ void ChartTwoCartesianAxis::getDataRange(float& rangeMinimumOut, float& rangeMaximumOut) const { EventChartTwoAxisGetDataRange rangeEvent(m_parentChartOverlaySet, m_axisLocation); EventManager::get()->sendEvent(rangeEvent.getPointer()); if ( ! rangeEvent.getMinimumAndMaximumValues(rangeMinimumOut, rangeMaximumOut)) { rangeMinimumOut = 0.0f; rangeMaximumOut = 0.0f; } } /** * Limit the user scale min/max values to be within the valid range. */ void ChartTwoCartesianAxis::limitUserScaleMinMaxToValidRange() { // float minimumValue = 0.0f; // float maximumValue = 0.0f; // getDataRange(minimumValue, // maximumValue); // // m_userScaleMinimumValue = MathFunctions::limitRange(m_userScaleMinimumValue, // minimumValue, // maximumValue); // m_userScaleMaximumValue = MathFunctions::limitRange(m_userScaleMaximumValue, // minimumValue, // maximumValue); } /** * @return User's digits right of decimal point. */ int32_t ChartTwoCartesianAxis::getUserDigitsRightOfDecimal() const { return m_userDigitsRightOfDecimal; } /** * Set user's digits right of decimal point. * * @param digitsRightOfDecimal * Numer of digits right of decimal point. */ void ChartTwoCartesianAxis::setUserDigitsRightOfDecimal(const int32_t digitsRightOfDecimal) { m_userDigitsRightOfDecimal = digitsRightOfDecimal; } /** * @return User's number of subdivisions. */ int32_t ChartTwoCartesianAxis::getUserNumberOfSubdivisions() const { return m_userNumberOfSubdivisions; } /** * Set User's number of subdivisions * @param numberOfSubdivisions * New value for Number of subdivisions. */ void ChartTwoCartesianAxis::setUserNumberOfSubdivisions(const int32_t numberOfSubdivisions) { m_userNumberOfSubdivisions = numberOfSubdivisions; } /** * @return numeric subdivisions mode */ ChartTwoNumericSubdivisionsModeEnum::Enum ChartTwoCartesianAxis::getNumericSubdivsionsMode() const { return m_numericSubdivsionsMode; } /** * Set numeric subdivisions mode * * @param numericSubdivsionsMode * New value for numeric subdivisions mode */ void ChartTwoCartesianAxis::setNumericSubdivsionsMode(const ChartTwoNumericSubdivisionsModeEnum::Enum numericSubdivsionsMode) { m_numericSubdivsionsMode = numericSubdivsionsMode; } /** * @return User scale's minimum value */ float ChartTwoCartesianAxis::getUserScaleMinimumValue() const { return m_userScaleMinimumValue; } /** * @return User scale's maximum value */ float ChartTwoCartesianAxis::getUserScaleMaximumValue() const { return m_userScaleMaximumValue; } /** * Set User scale's maximum value * @param userScaleMaximumValue * New value for User scale's maximum value */ void ChartTwoCartesianAxis::setUserScaleMaximumValue(const float userScaleMaximumValue) { m_userScaleMaximumValue = userScaleMaximumValue; limitUserScaleMinMaxToValidRange(); } /** * Set User scale's minimum value * @param userScaleMinimumValue * New value for User scale's minimum value */ void ChartTwoCartesianAxis::setUserScaleMinimumValue(const float userScaleMinimumValue) { m_userScaleMinimumValue = userScaleMinimumValue; limitUserScaleMinMaxToValidRange(); } /** * @return Is the axis enabled because a chart is using it */ bool ChartTwoCartesianAxis::isEnabledByChart() const { return m_enabledByChart; } /** * Set the axis enabled because a chart is using it * * @param enabled * New enabled status */ void ChartTwoCartesianAxis::setEnabledByChart(const bool enabled) { m_enabledByChart = enabled; } /** * @return Show axis tickmarks */ bool ChartTwoCartesianAxis::isShowTickmarks() const { return m_showTickmarks; } /** * Set Show axis tickmarks * @param showTickmarks * New value for Show axis tickmarks */ void ChartTwoCartesianAxis::setShowTickmarks(const bool showTickmarks) { m_showTickmarks = showTickmarks; } /** * @return show axis label */ bool ChartTwoCartesianAxis::isShowLabel() const { return m_showLabel; } /** * Set show axis label * @param showLabel * New value for show axis label */ void ChartTwoCartesianAxis::setShowLabel(const bool showLabel) { m_showLabel = showLabel; } /** * @return Scale Range Mode */ ChartTwoAxisScaleRangeModeEnum::Enum ChartTwoCartesianAxis::getScaleRangeMode() const { return m_scaleRangeMode; } /** * Set Scale Range Mode * * @param scaleRangeMode * New value for Scale Range Mode */ void ChartTwoCartesianAxis::setScaleRangeMode(const ChartTwoAxisScaleRangeModeEnum::Enum scaleRangeMode) { m_scaleRangeMode = scaleRangeMode; } /** * @return Axis units */ CaretUnitsTypeEnum::Enum ChartTwoCartesianAxis::getUnits() const { return m_units; } /** * Set Axis units * * @param units * New value for Axis units */ void ChartTwoCartesianAxis::setUnits(const CaretUnitsTypeEnum::Enum units) { m_units = units; } /** * @return User's umeric format mode */ NumericFormatModeEnum::Enum ChartTwoCartesianAxis::getUserNumericFormat() const { return m_userNumericFormat; } /** * Set User's Numeric format mode * * @param numericFormat * New value for Numeric format mode */ void ChartTwoCartesianAxis::setUserNumericFormat(const NumericFormatModeEnum::Enum numericFormat) { m_userNumericFormat = numericFormat; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ChartTwoCartesianAxis::toString() const { return "ChartTwoCartesianAxis"; } /** * @return Index of overlay that supplies the label. * * @param maximumNumberOfOverlays * Maximum number of allowable overlays. */ int32_t ChartTwoCartesianAxis::getLabelOverlayIndex(const int32_t maximumNumberOfOverlays) const { if (m_titleOverlayIndex < 0) { m_titleOverlayIndex = 0; } else if (m_titleOverlayIndex >= maximumNumberOfOverlays) { m_titleOverlayIndex = 0; } return m_titleOverlayIndex; } /** * Set the index of the overlay that supplies the title. * * @param labelOverlayIndex * New value for label overlay index. */ void ChartTwoCartesianAxis::setLabelOverlayIndex(const int32_t labelOverlayIndex) { m_titleOverlayIndex = labelOverlayIndex; } /** * @return size of label text */ float ChartTwoCartesianAxis::getLabelTextSize() const { return m_labelTextSize; } /** * Set size of label text * * @param labelTextSize * New value for size of label text */ void ChartTwoCartesianAxis::setLabelTextSize(const float labelTextSize) { m_labelTextSize = labelTextSize; } /** * @return size of numerics text */ float ChartTwoCartesianAxis::getNumericsTextSize() const { return m_numericsTextSize; } /** * Set size of numerics text * * @param numericsTextSize * New value for size of numerics text */ void ChartTwoCartesianAxis::setNumericsTextSize(const float numericsTextSize) { m_numericsTextSize = numericsTextSize; } /** * @return display numeric text in scale */ bool ChartTwoCartesianAxis::isNumericsTextDisplayed() const { return m_numericsTextDisplayed; } /** * Set display numeric text in scale * * @param numericsTextDisplayed * New value for display numeric text in scale */ void ChartTwoCartesianAxis::setNumericsTextDisplayed(const bool numericsTextDisplayed) { m_numericsTextDisplayed = numericsTextDisplayed; } /** * @return rotate numeric text */ bool ChartTwoCartesianAxis::isNumericsTextRotated() const { return m_numericsTextRotated; } /** * Set rotate numeric text * * @param numericsTextRotated * New value for rotate numeric text */ void ChartTwoCartesianAxis::setNumericsTextRotated(const bool numericsTextRotated) { m_numericsTextRotated = numericsTextRotated; } /** * @return size of padding */ float ChartTwoCartesianAxis::getPaddingSize() const { return m_paddingSize; } /** * Set size of padding * * @param paddingSize * New value for size of padding */ void ChartTwoCartesianAxis::setPaddingSize(const float paddingSize) { m_paddingSize = paddingSize; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* ChartTwoCartesianAxis::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ChartTwoCartesianAxis", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ChartTwoCartesianAxis::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } // may not be in older scenes m_displayedByUser = true; m_numericsTextDisplayed = true; m_numericsTextRotated = false; m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } /** * Given the bounds of the data, determine the auto range minimum and maximum values. * * @param minimumValue * Minimum data value * @param maximumValue * Maximum data value * @param minimumOut * Output minimum value for autoranging. * @param maximumOut * Output maximum value for autoranging. * @param stepValueOut * Output step value for scale. * @param digitsRightOfDecimalOut * Output with digits right of decimal. * @return * True if output values are valid, else false. */ bool ChartTwoCartesianAxis::getAutoRangeMinimumAndMaximum(const float minimumValue, const float maximumValue, float& minimumOut, float& maximumOut, float& stepValueOut, int32_t& digitsRightOfDecimalOut) const { float minValue = minimumValue; float maxValue = maximumValue; if (maxValue > minValue) { double scaleStep = 0.0; double scaleMin = 0.0; double scaleMax = 0.0; int32_t digitsRightOfDecimal = 0; ChartScaleAutoRanging::createAutoScale(minValue, maxValue, scaleMin, scaleMax, scaleStep, digitsRightOfDecimal); minimumOut = scaleMin; maximumOut = scaleMax; stepValueOut = scaleStep; digitsRightOfDecimalOut = digitsRightOfDecimal; //m_rangeMinimumValue = minimumOut; //m_rangeMaximumValue = maximumOut; return true; } return false; } /** * Get the axis scale text values and their positions for drawing the scale. * * @param minimumDataValue * Minimum data value * @param maximumDataValue * Maximum data value * @param axisLength * Length of axis (no specific unit type is assumed) * @param minimumOut * Output minimum value for autoranging. * @param maximumOut * Output maximum value for autoranging. * @param scaleValuesOffsetInPixelsOut * Output containing offset in pixels for the scale values. * @param scaleValuesOut * Output containing text for scale values. * @return * True if output data is valid, else false. */ bool ChartTwoCartesianAxis::getScaleValuesAndOffsets(const float minimumDataValue, const float maximumDataValue, const float axisLength, float& minimumOut, float& maximumOut, std::vector& scaleValuesOffsetInPixelsOut, std::vector& scaleValuesOut) const { float minimumValue = minimumDataValue; float maximumValue = maximumDataValue; minimumOut = 0.0; maximumOut = 0.0; scaleValuesOffsetInPixelsOut.clear(); scaleValuesOut.clear(); if (axisLength <= 0.0) { CaretAssert(0); return false; } float labelsStart = 0.0; float labelsEnd = 0.0; float labelsStep = 1.0; int32_t labelsDigitsRightOfDecimal = 0; switch (m_scaleRangeMode) { case ChartTwoAxisScaleRangeModeEnum::AUTO: break; case ChartTwoAxisScaleRangeModeEnum::DATA: break; case ChartTwoAxisScaleRangeModeEnum::USER: switch (m_axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: minimumValue = m_userScaleMinimumValue; maximumValue = m_userScaleMaximumValue; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: minimumValue = m_userScaleMinimumValue; maximumValue = m_userScaleMaximumValue; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: minimumValue = m_userScaleMinimumValue; maximumValue = m_userScaleMaximumValue; break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: minimumValue = m_userScaleMinimumValue; maximumValue = m_userScaleMaximumValue; break; } break; } if ( ! getAutoRangeMinimumAndMaximum(minimumValue, maximumValue, labelsStart, labelsEnd, labelsStep, labelsDigitsRightOfDecimal)) { return false; } switch (m_scaleRangeMode) { case ChartTwoAxisScaleRangeModeEnum::AUTO: m_userScaleMinimumValue = labelsStart; m_userScaleMaximumValue = labelsEnd; break; case ChartTwoAxisScaleRangeModeEnum::DATA: { const double range = maximumDataValue - minimumDataValue; if (range > 0.0) { const int32_t numSteps = MathFunctions::round((labelsEnd - labelsStart) / labelsStep); if (numSteps > 0) { labelsStart = minimumDataValue; labelsEnd = maximumDataValue; labelsStep = range / numSteps; m_userScaleMinimumValue = labelsStart; m_userScaleMaximumValue = labelsEnd; } } } break; case ChartTwoAxisScaleRangeModeEnum::USER: // labelsStart = m_userScaleMinimumValue; // labelsEnd = m_userScaleMaximumValue; { const double range = m_userScaleMaximumValue - m_userScaleMinimumValue; if (range > 0.0) { const int32_t numSteps = MathFunctions::round((labelsEnd - labelsStart) / labelsStep); if (numSteps > 0) { labelsStart = m_userScaleMinimumValue; labelsEnd = m_userScaleMaximumValue; labelsStep = range / numSteps; m_userScaleMinimumValue = labelsStart; m_userScaleMaximumValue = labelsEnd; } } } break; } switch (m_numericSubdivsionsMode) { case ChartTwoNumericSubdivisionsModeEnum::AUTO: break; case ChartTwoNumericSubdivisionsModeEnum::USER: { const float labelsRange = labelsEnd - labelsStart; if (labelsRange <= 0.0) { return false; } const float dividend = (1.0 + m_userNumberOfSubdivisions); labelsStep = labelsRange / dividend; } break; } minimumOut = labelsStart; maximumOut = labelsEnd; /* * If the "labels end" or "labels start" value is not valid (infinity or not-a-number) there * are invalid values in the data and will cause the labels processing later * in this method to fail. So, alert the user that there is a problem in * the data. * * A set is used to track those models for which the user has * already been alerted. Otherwise, the alert message will be * displayed every time this method is called (which is many) and * the user will receive endless pop-ups. */ if ( (! MathFunctions::isNumeric(labelsStart)) || (! MathFunctions::isNumeric(labelsEnd))) { const AString msg("Invalid numbers (infinity or not-a-number) found when trying to create chart. " "Run \"wb_command -file-information\" on files being charted to find the file " "that contains invalid data so that the file can be fixed."); CaretLogWarning(msg); return false; } float labelsRange = (labelsEnd - labelsStart); if (labelsRange <= 0.0) { return false; } const float tickLabelsStep = labelsStep; if (tickLabelsStep <= 0.0) { return false; } const float onePercentRange = labelsRange * 0.01f; std::vector labelNumericValues; float labelValue = labelsStart; while (labelValue <= labelsEnd) { float labelParametricValue = (labelValue - labelsStart) / labelsRange; float labelValueForText = labelValue; if (labelsRange >= 10.0) { /* * Is this the first label? */ if (labelValue <= labelsStart) { /* * Handles case when the minimum DATA value is just a little * bit greater than the minimum value for axis labels such * as in Data-Series data when the minimum data value is "1" * and the minimum axis label value is "0". Without this * code no value is displayed at the left edge of the axis. */ if (labelParametricValue < 0.0) { const float nextParametricValue = ((labelValue + tickLabelsStep) - labelsStart) / labelsRange; if (nextParametricValue > 0.05) { labelParametricValue = 0.0; labelValueForText = labelsStart; } } } if (labelParametricValue < 0.0) { if (labelParametricValue >= -0.01) { labelParametricValue = 0.0; } } /* * Is this the last label? */ if (labelValue >= labelsEnd) { /* * Like above, ensures a value is displayed at the right * edge of the axis. */ if (labelParametricValue > 1.0) { const float prevParametricValue = ((labelValue - tickLabelsStep) - labelsStart) / labelsRange; if (prevParametricValue < 0.95) { labelParametricValue = 1.0; labelValueForText = labelsEnd; } } } if (labelParametricValue > 1.0) { if (labelParametricValue < 1.01) { labelParametricValue = 1.0; } } } if ((labelParametricValue >= 0.0) && (labelParametricValue <= 1.0)) { const float labelPixelsPosition = axisLength * labelParametricValue; labelNumericValues.push_back(labelValueForText); scaleValuesOffsetInPixelsOut.push_back(labelPixelsPosition); } else { // std::cout << "Label value=" << labelValue << " parametric=" << labelParametricValue << " failed." << std::endl; } labelValue += tickLabelsStep; /* * It is possible that 'labelValue' may be slightly greater than 'labelsEnd' * for the last label which results in the last label not displayed. * So, if the 'labelValue' is slightly greater than 'labelsEnd', * limit 'labelValue' so that the label at the end of the data range * is displayed. * * Example: labelValue = 73.9500046 * labelsEnd = 73.9499969 */ if (labelValue > labelsEnd) { const float diff = labelValue - labelsEnd; if (diff < onePercentRange) { labelValue = labelsEnd; } } } const int32_t numValues = static_cast(labelNumericValues.size()); if (numValues > 0) { scaleValuesOut.resize(numValues); NumericTextFormatting::formatValueRange(m_userNumericFormat, m_userDigitsRightOfDecimal, &labelNumericValues[0], &scaleValuesOut[0], labelNumericValues.size()); } CaretAssert(scaleValuesOffsetInPixelsOut.size() == scaleValuesOut.size()); return ( ! scaleValuesOut.empty()); } connectome-workbench-1.4.2/src/Charting/ChartTwoCartesianAxis.h000066400000000000000000000201741360521144700245500ustar00rootroot00000000000000#ifndef __CHART_TWO_CARTESIAN_AXIS_H__ #define __CHART_TWO_CARTESIAN_AXIS_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "ChartAxisLocationEnum.h" #include "CaretUnitsTypeEnum.h" #include "ChartTwoAxisScaleRangeModeEnum.h" #include "ChartTwoNumericSubdivisionsModeEnum.h" #include "NumericFormatModeEnum.h" #include "SceneableInterface.h" namespace caret { class ChartTwoOverlaySet; class SceneClassAssistant; class ChartTwoCartesianAxis : public CaretObject, public SceneableInterface { public: ChartTwoCartesianAxis(const ChartTwoOverlaySet* parentChartOverlaySet, const ChartAxisLocationEnum::Enum axisLocation); virtual ~ChartTwoCartesianAxis(); ChartTwoCartesianAxis(const ChartTwoCartesianAxis& obj); ChartTwoCartesianAxis& operator=(const ChartTwoCartesianAxis& obj); ChartAxisLocationEnum::Enum getAxisLocation() const; bool isDisplayedByUser() const; void setDisplayedByUser(const bool displayed); void getDataRange(float& rangeMinimumOut, float& rangeMaximumOut) const; float getUserScaleMinimumValue() const; void setUserScaleMinimumValue(const float value); float getUserScaleMaximumValue() const; void setUserScaleMaximumValue(const float value); int32_t getUserDigitsRightOfDecimal() const; void setUserDigitsRightOfDecimal(const int32_t digitsRightOfDecimal); ChartTwoAxisScaleRangeModeEnum::Enum getScaleRangeMode() const; void setScaleRangeMode(const ChartTwoAxisScaleRangeModeEnum::Enum scaleRangeMode); CaretUnitsTypeEnum::Enum getUnits() const; void setUnits(CaretUnitsTypeEnum::Enum units); NumericFormatModeEnum::Enum getUserNumericFormat() const; void setUserNumericFormat(const NumericFormatModeEnum::Enum numericFormat); ChartTwoNumericSubdivisionsModeEnum::Enum getNumericSubdivsionsMode() const; void setNumericSubdivsionsMode(const ChartTwoNumericSubdivisionsModeEnum::Enum numericSubdivsionsMode); int32_t getUserNumberOfSubdivisions() const; void setUserNumberOfSubdivisions(const int32_t numberOfSubdivisions); bool isEnabledByChart() const; void setEnabledByChart(const bool enabled); bool isShowTickmarks() const; void setShowTickmarks(const bool showTickmarks); bool isShowLabel() const; void setShowLabel(const bool showLabel); float getLabelTextSize() const; void setLabelTextSize(const float labelTextSize); float getNumericsTextSize() const; void setNumericsTextSize(const float numericsTextSize); bool isNumericsTextDisplayed() const; void setNumericsTextDisplayed(const bool numericsTextDisplayed); bool isNumericsTextRotated() const; void setNumericsTextRotated(const bool numericsTextRotated); float getPaddingSize() const; void setPaddingSize(const float paddingSize); bool getScaleValuesAndOffsets(const float minimumDataValue, const float maximumDataValue, const float axisLength, float& minimumOut, float& maximumOut, std::vector& scaleValuesOffsetInPixelsOut, std::vector& scaleValuesOut) const; int32_t getLabelOverlayIndex(const int32_t maximumNumberOfOverlays) const; void setLabelOverlayIndex(const int32_t labelOverlayIndex); // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implementation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: void copyHelperChartTwoCartesianAxis(const ChartTwoCartesianAxis& obj); bool getAutoRangeMinimumAndMaximum(const float minimumValue, const float maximumValue, float& minimumOut, float& maximumOut, float& stepValueOut, int32_t& digitsRightOfDecimalOut) const; void limitUserScaleMinMaxToValidRange(); const ChartTwoOverlaySet* m_parentChartOverlaySet; const ChartAxisLocationEnum::Enum m_axisLocation; std::unique_ptr m_sceneAssistant; mutable float m_userScaleMinimumValue = -100.0f; mutable float m_userScaleMaximumValue = 100.0f; float m_axisLabelsStepValue = 1.0f; int32_t m_userDigitsRightOfDecimal = 1; mutable int32_t m_titleOverlayIndex = 0; ChartTwoAxisScaleRangeModeEnum::Enum m_scaleRangeMode = ChartTwoAxisScaleRangeModeEnum::AUTO; CaretUnitsTypeEnum::Enum m_units = CaretUnitsTypeEnum::NONE; NumericFormatModeEnum::Enum m_userNumericFormat = NumericFormatModeEnum::AUTO; /** numeric subdivisions mode*/ ChartTwoNumericSubdivisionsModeEnum::Enum m_numericSubdivsionsMode = ChartTwoNumericSubdivisionsModeEnum::AUTO; int32_t m_userNumberOfSubdivisions = 2; /** size of label text*/ float m_labelTextSize = 2.5f; /** size of numerics text*/ float m_numericsTextSize = 2.5f; /** display numeric text in scale*/ bool m_numericsTextDisplayed = true; /** rotate numeric text*/ bool m_numericsTextRotated = false; /** size of padding*/ float m_paddingSize = 0.0f; bool m_enabledByChart = false; bool m_showTickmarks = true; /** show axis label*/ bool m_showLabel; /** user display the axis*/ bool m_displayedByUser = true; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHART_TWO_CARTESIAN_AXIS_DECLARE__ // #endif // __CHART_TWO_CARTESIAN_AXIS_DECLARE__ } // namespace #endif //__CHART_TWO_CARTESIAN_AXIS_H__ connectome-workbench-1.4.2/src/Charting/ChartTwoCompoundDataType.cxx000066400000000000000000000317311360521144700256060ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_TWO_COMPOUND_DATA_TYPE_DECLARE__ #include "ChartTwoCompoundDataType.h" #undef __CHART_TWO_COMPOUND_DATA_TYPE_DECLARE__ #include "CaretAssert.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ChartTwoCompoundDataType * \brief Compound type for type of chart * \ingroup Charting * * A compound type for matching chart types. * Equality is determined using several pieces of information. */ /** * Constructor. It is best to use the "new instance" methods. * * @param chartDataType * Chart data type. * @param histogramNumberOfBuckets * Number of bins in the histogram. * @param lineChartUnitsAxisX * Line chart x-axis units. * @param lineChartNumberOfElementsAxisX * Line chart x-axis number of elements. * @param matrixNumberOfRows * Matrix number of rows. * @param matrixNumberOfColumns * Matrix number of columns. */ ChartTwoCompoundDataType::ChartTwoCompoundDataType(const ChartTwoDataTypeEnum::Enum chartDataType, const int32_t histogramNumberOfBuckets, const CaretUnitsTypeEnum::Enum lineChartUnitsAxisX, const int32_t lineChartNumberOfElementsAxisX, const int32_t matrixNumberOfRows, const int32_t matrixNumberOfColumns) : CaretObject() { initializeChartTwoCompoundDataType(); m_chartDataType = chartDataType; m_histogramNumberOfBuckets = histogramNumberOfBuckets; m_lineChartUnitsAxisX = lineChartUnitsAxisX; m_lineChartNumberOfElementsAxisX = lineChartNumberOfElementsAxisX; m_matrixNumberOfRows = matrixNumberOfRows; m_matrixNumberOfColumns = matrixNumberOfColumns; } /** * Default constructor of invalid instance. */ ChartTwoCompoundDataType::ChartTwoCompoundDataType() { initializeChartTwoCompoundDataType(); } /** * Destructor. */ ChartTwoCompoundDataType::~ChartTwoCompoundDataType() { delete m_sceneAssistant; } /** * @return A new instance for a histogram chart. * * @param histogramNumberOfBins * Number of bins in the histogram. */ ChartTwoCompoundDataType ChartTwoCompoundDataType::newInstanceForHistogram(const int32_t histogramNumberOfBins) { return ChartTwoCompoundDataType(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM, histogramNumberOfBins, CaretUnitsTypeEnum::NONE, 0, 0, 0); } /** * @return A new instance for a line-series chart. * * @param lineChartUnitsAxisX * Line chart x-axis units. * @param lineChartNumberOfElementsAxisX * Line chart x-axis number of elements. */ ChartTwoCompoundDataType ChartTwoCompoundDataType::newInstanceForLineSeries(const CaretUnitsTypeEnum::Enum lineChartUnitsAxisX, const int32_t lineChartNumberOfElementsAxisX) { return ChartTwoCompoundDataType(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, 0, lineChartUnitsAxisX, lineChartNumberOfElementsAxisX, 0, 0); } /** * @return A new instance for a matrix chart. * * @param matrixNumberOfRows * Matrix number of rows. * @param matrixNumberOfColumns * Matrix number of columns. */ ChartTwoCompoundDataType ChartTwoCompoundDataType::newInstanceForMatrix(const int32_t matrixNumberOfRows, const int32_t matrixNumberOfColumns) { return ChartTwoCompoundDataType(ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX, 0, CaretUnitsTypeEnum::NONE, 0, matrixNumberOfRows, matrixNumberOfColumns); } /** * Copy constructor. * @param obj * Object that is copied. */ ChartTwoCompoundDataType::ChartTwoCompoundDataType(const ChartTwoCompoundDataType& obj) : CaretObject(obj), SceneableInterface(obj) { initializeChartTwoCompoundDataType(); this->copyHelperChartTwoCompoundDataType(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ChartTwoCompoundDataType& ChartTwoCompoundDataType::operator=(const ChartTwoCompoundDataType& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperChartTwoCompoundDataType(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ChartTwoCompoundDataType::copyHelperChartTwoCompoundDataType(const ChartTwoCompoundDataType& obj) { m_chartDataType = obj.m_chartDataType; m_lineChartUnitsAxisX = obj.m_lineChartUnitsAxisX; m_lineChartNumberOfElementsAxisX = obj.m_lineChartNumberOfElementsAxisX; m_matrixNumberOfRows = obj.m_matrixNumberOfRows; m_matrixNumberOfColumns = obj.m_matrixNumberOfColumns; } /** * Initialize an invalid instance of this class. */ void ChartTwoCompoundDataType::initializeChartTwoCompoundDataType() { m_chartDataType = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; m_lineChartUnitsAxisX = CaretUnitsTypeEnum::NONE; m_lineChartNumberOfElementsAxisX = 0; m_matrixNumberOfRows = 0; m_matrixNumberOfColumns = 0; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_chartDataType", &m_chartDataType); m_sceneAssistant->add("m_lineChartUnitsAxisX", &m_lineChartUnitsAxisX); m_sceneAssistant->add("m_lineChartNumberOfElementsAxisX", &m_lineChartNumberOfElementsAxisX); m_sceneAssistant->add("m_matrixNumberOfRows", &m_matrixNumberOfRows); m_sceneAssistant->add("m_matrixNumberOfColumns", &m_matrixNumberOfColumns); } /** * Equality operator. * * Charts must be same type. * Line charts must be same units OR same number of elements in X-axis. * Matrix charts must have same number of rows and columns. * * @param obj * Instance compared to this for equality. * @return * True if this instance and 'obj' instance are considered equal. */ bool ChartTwoCompoundDataType::operator==(const ChartTwoCompoundDataType& obj) const { if (this == &obj) { return true; } if (m_chartDataType == obj.m_chartDataType) { switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: return true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: return true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: { if (m_lineChartUnitsAxisX == obj.m_lineChartUnitsAxisX) { return true; } if (m_lineChartNumberOfElementsAxisX == obj.m_lineChartNumberOfElementsAxisX) { return true; } } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: if ((m_matrixNumberOfRows == obj.m_matrixNumberOfRows) && (m_matrixNumberOfColumns == obj.m_matrixNumberOfColumns)) { return true; } break; } } return false; } /** * @return Type of chart data. */ ChartTwoDataTypeEnum::Enum ChartTwoCompoundDataType::getChartTwoDataType() const { return m_chartDataType; } /** * @return Histogram number of buckets. */ int32_t ChartTwoCompoundDataType::getHistogramNumberOfBuckets() const { return m_histogramNumberOfBuckets; } /** * @return Line chart X-axis units. */ CaretUnitsTypeEnum::Enum ChartTwoCompoundDataType::getLineChartUnitsAxisX() const { return m_lineChartUnitsAxisX; } /** * @return Line chart number of element in the X-axis. */ int32_t ChartTwoCompoundDataType::getLineChartNumberOfElementsAxisX() const { return m_lineChartNumberOfElementsAxisX; } /** * @return Matrix number of rows. */ int32_t ChartTwoCompoundDataType::getMatrixNumberOfRows() const { return m_matrixNumberOfRows; } /** * @return Matrix number of columns. */ int32_t ChartTwoCompoundDataType::getMatrixNumberOfColumns() const { return m_matrixNumberOfColumns; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ChartTwoCompoundDataType::toString() const { const AString indent = " "; AString text = ("type=" + ChartTwoDataTypeEnum::toGuiName(m_chartDataType)); switch (m_chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: //text.appendWithNewLine(indent // + "buckets=" // + QString::number(m_histogramNumberOfBuckets)); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: text.appendWithNewLine(indent + "x=units=" + CaretUnitsTypeEnum::toName(m_lineChartUnitsAxisX)); text.appendWithNewLine(indent + "x-elements=" + AString::number(m_lineChartNumberOfElementsAxisX)); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: text.appendWithNewLine(indent + "rows=" + AString::number(m_matrixNumberOfRows)); text.appendWithNewLine(indent + "columns=" + AString::number(m_matrixNumberOfColumns)); break; } return text; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* ChartTwoCompoundDataType::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ChartTwoCompoundDataType", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ChartTwoCompoundDataType::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Charting/ChartTwoCompoundDataType.h000066400000000000000000000112011360521144700252210ustar00rootroot00000000000000#ifndef __CHART_TWO_COMPOUND_DATA_TYPE_H__ #define __CHART_TWO_COMPOUND_DATA_TYPE_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "CaretUnitsTypeEnum.h" #include "ChartTwoDataTypeEnum.h" #include "SceneableInterface.h" namespace caret { class SceneClassAssistant; class ChartTwoCompoundDataType : public CaretObject, public SceneableInterface { public: ChartTwoCompoundDataType(); ChartTwoCompoundDataType(const ChartTwoDataTypeEnum::Enum chartDataType, const int32_t histogramNumberOfBuckets, const CaretUnitsTypeEnum::Enum lineChartUnitsAxisX, const int32_t lineChartNumberOfElementsAxisX, const int32_t matrixNumberOfRows, const int32_t matrixNumberOfColumns); static ChartTwoCompoundDataType newInstanceForHistogram(const int32_t histogramNumberOfBuckets); static ChartTwoCompoundDataType newInstanceForLineSeries(const CaretUnitsTypeEnum::Enum lineChartUnitsAxisX, const int32_t lineChartNumberOfElementsAxisX); static ChartTwoCompoundDataType newInstanceForMatrix(const int32_t matrixNumberOfRows, const int32_t matrixNumberOfColumns); virtual ~ChartTwoCompoundDataType(); ChartTwoCompoundDataType(const ChartTwoCompoundDataType& obj); ChartTwoCompoundDataType& operator=(const ChartTwoCompoundDataType& obj); bool operator==(const ChartTwoCompoundDataType& obj) const; ChartTwoDataTypeEnum::Enum getChartTwoDataType() const; int32_t getHistogramNumberOfBuckets() const; CaretUnitsTypeEnum::Enum getLineChartUnitsAxisX() const; int32_t getLineChartNumberOfElementsAxisX() const; int32_t getMatrixNumberOfRows() const; int32_t getMatrixNumberOfColumns() const; // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implementation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: void copyHelperChartTwoCompoundDataType(const ChartTwoCompoundDataType& obj); void initializeChartTwoCompoundDataType(); SceneClassAssistant* m_sceneAssistant; ChartTwoDataTypeEnum::Enum m_chartDataType; int32_t m_histogramNumberOfBuckets; CaretUnitsTypeEnum::Enum m_lineChartUnitsAxisX; int32_t m_lineChartNumberOfElementsAxisX; int32_t m_matrixNumberOfRows; int32_t m_matrixNumberOfColumns; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHART_TWO_COMPOUND_DATA_TYPE_DECLARE__ // #endif // __CHART_TWO_COMPOUND_DATA_TYPE_DECLARE__ } // namespace #endif //__CHART_TWO_COMPOUND_DATA_TYPE_H__ connectome-workbench-1.4.2/src/Charting/ChartTwoDataCartesian.cxx000066400000000000000000000350161360521144700250710ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_TWO_DATA_CARTESIAN_DECLARE__ #include "ChartTwoDataCartesian.h" #undef __CHART_TWO_DATA_CARTESIAN_DECLARE__ #include #include #include "BoundingBox.h" #include "CaretAssert.h" #include "ChartPoint.h" #include "GraphicsPrimitiveV3f.h" #include "MapFileDataSelector.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "ScenePrimitiveArray.h" using namespace caret; /** * \class caret::ChartTwoDataCartesian * \brief Chart cartesian data. * \ingroup Charting */ /** * Constructor. * * @param chartDataType * Type of chart data model. * @param dataAxisUnitsX * Data units for X-axis. * @param dataAxisUnitsY * Data units for Y-axis. * @param graphicsPrimitiveType * Primitive type for graphics primitive drawing. */ ChartTwoDataCartesian::ChartTwoDataCartesian(const ChartTwoDataTypeEnum::Enum chartDataType, const CaretUnitsTypeEnum::Enum dataAxisUnitsX, const CaretUnitsTypeEnum::Enum dataAxisUnitsY, const GraphicsPrimitive::PrimitiveType graphicsPrimitiveType) : CaretObjectTracksModification(), m_dataAxisUnitsX(dataAxisUnitsX), m_dataAxisUnitsY(dataAxisUnitsY), m_graphicsPrimitiveType(graphicsPrimitiveType) { initializeMembersChartTwoDataCartesian(); switch (chartDataType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: CaretAssert(0); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: CaretAssert(0); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: CaretAssert(0); break; } } /** * Destructor. */ ChartTwoDataCartesian::~ChartTwoDataCartesian() { delete m_sceneAssistant; } /** * Initialize members of a new instance. */ void ChartTwoDataCartesian::initializeMembersChartTwoDataCartesian() { m_mapFileDataSelector = std::unique_ptr(new MapFileDataSelector()); m_selectionStatus = true; m_color = CaretColorEnum::RED; m_lineWidth = getDefaultLineWidth(); m_timeStartInSecondsAxisX = 0.0; m_timeStepInSecondsAxisX = 1.0; m_graphicsPrimitive = createGraphicsPrimitive(); std::vector colorEnums; CaretColorEnum::getColorEnumsNoBlackOrWhite(colorEnums); const int32_t numCaretColors = static_cast(colorEnums.size()); bool colorFound = false; while ( ! colorFound) { ChartTwoDataCartesian::caretColorIndex++; if (ChartTwoDataCartesian::caretColorIndex >= numCaretColors) { ChartTwoDataCartesian::caretColorIndex = 0; } if (colorEnums[ChartTwoDataCartesian::caretColorIndex] == CaretColorEnum::BLACK) { /* do not use black */ } else if (colorEnums[ChartTwoDataCartesian::caretColorIndex] == CaretColorEnum::WHITE) { /* do not use white */ } else { m_color = colorEnums[ChartTwoDataCartesian::caretColorIndex]; colorFound = true; } } setColor(m_color); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_selectionStatus", &m_selectionStatus); m_sceneAssistant->add("m_dataAxisUnitsX", &m_dataAxisUnitsX); m_sceneAssistant->add("m_dataAxisUnitsY", &m_dataAxisUnitsY); m_sceneAssistant->add("m_color", &m_color); m_sceneAssistant->add("m_lineWidth", &m_lineWidth); m_sceneAssistant->add("m_timeStartInSecondsAxisX", &m_timeStartInSecondsAxisX); m_sceneAssistant->add("m_timeStepInSecondsAxisX", &m_timeStepInSecondsAxisX); m_sceneAssistant->add("m_mapFileDataSelector", "MapFileDataSelector", m_mapFileDataSelector.get()); } /** * @return A new instance of the graphics primitive. */ std::unique_ptr ChartTwoDataCartesian::createGraphicsPrimitive() { float rgba[4]; CaretColorEnum::toRGBAFloat(m_color, rgba); /* * Note: LINES (line segments) are used so that individual segments can be identified. * Cannot use line strip since it is identified as a single item. */ return std::unique_ptr(GraphicsPrimitive::newPrimitiveV3f(m_graphicsPrimitiveType, rgba)); } /** * @return The map file data selector that will indicate the source of data for this data. */ const MapFileDataSelector* ChartTwoDataCartesian::getMapFileDataSelector() const { return m_mapFileDataSelector.get(); } /** * @param */ void ChartTwoDataCartesian::setMapFileDataSelector(const MapFileDataSelector& mapFileDataSelector) { *m_mapFileDataSelector = mapFileDataSelector; } /** * At times a copy of chart data will be needed BUT it must be * the proper subclass so copy constructor and assignment operator * will no function when this abstract, base class is used. Each * subclass will override this method so that the returned class * is of the proper type. * * @return Copy of this instance that is the actual subclass. */ ChartTwoDataCartesian* ChartTwoDataCartesian::clone() const { ChartTwoDataCartesian* cloneCopy = new ChartTwoDataCartesian(*this); return cloneCopy; } /** * Copy constructor. * @param obj * Object that is copied. */ ChartTwoDataCartesian::ChartTwoDataCartesian(const ChartTwoDataCartesian& obj) : CaretObjectTracksModification(obj), SceneableInterface(obj), m_dataAxisUnitsX(obj.m_dataAxisUnitsX), m_dataAxisUnitsY(obj.m_dataAxisUnitsY), m_graphicsPrimitiveType(obj.m_graphicsPrimitiveType) { initializeMembersChartTwoDataCartesian(); this->copyHelperChartTwoDataCartesian(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ChartTwoDataCartesian& ChartTwoDataCartesian::operator=(const ChartTwoDataCartesian& obj) { if (this != &obj) { CaretObjectTracksModification::operator=(obj); this->copyHelperChartTwoDataCartesian(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ChartTwoDataCartesian::copyHelperChartTwoDataCartesian(const ChartTwoDataCartesian& obj) { m_selectionStatus = obj.m_selectionStatus; *m_mapFileDataSelector = *obj.m_mapFileDataSelector; m_dataAxisUnitsX = obj.m_dataAxisUnitsX; m_dataAxisUnitsY = obj.m_dataAxisUnitsY; m_graphicsPrimitive.reset(dynamic_cast(obj.m_graphicsPrimitive->clone())); m_color = obj.m_color; m_lineWidth = obj.m_lineWidth; m_timeStartInSecondsAxisX = obj.m_timeStartInSecondsAxisX; m_timeStepInSecondsAxisX = obj.m_timeStepInSecondsAxisX; } /** * @return Graphics primitive for drawing cartesian data. */ GraphicsPrimitiveV3f* ChartTwoDataCartesian::getGraphicsPrimitive() const { m_graphicsPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, m_lineWidth); return m_graphicsPrimitive.get(); } /** * @return The selection status */ bool ChartTwoDataCartesian::isSelected() const { return m_selectionStatus; } /** * Set the selection status. * * @param selectionStatus * New selection status. */ void ChartTwoDataCartesian::setSelected(const bool selectionStatus) { m_selectionStatus = selectionStatus; /* * When selection status is true, * notify parent. */ // if (m_selectionStatus[tabIndex]) { // if (m_parentChartModel != NULL) { // m_parentChartModel->childChartTwoDataSelectionChanged(this); // } // } } /** * Add a point. * * @param x * X-coordinate. * @param y * Y-coordinate. */ void ChartTwoDataCartesian::addPoint(const float x, const float y) { m_graphicsPrimitive->addVertex(x, y); } /** * Get a bounds box for the cartesian data. * * @param boundingBoxOut * Output bounding box. * @return * True if bounding box is valid, else false. */ bool ChartTwoDataCartesian::getBounds(BoundingBox& boundingBoxOut) const { return m_graphicsPrimitive->getVertexBounds(boundingBoxOut); } /** * @return The time start in seconds for the X-Axis (Valid when * the X-axis is time) */ float ChartTwoDataCartesian::getTimeStartInSecondsAxisX() const { return m_timeStartInSecondsAxisX; } /** * Set the time start in seconds for the X-Axis (Valid when * the X-axis is time) * * @param timeStartInSecondsAxisX * Time of first point in the X-axis. */ void ChartTwoDataCartesian::setTimeStartInSecondsAxisX(const float timeStartInSecondsAxisX) { m_timeStartInSecondsAxisX = timeStartInSecondsAxisX; } /** * @return The time step in seconds for the X-Axis (Valid when * the X-axis is time) */ float ChartTwoDataCartesian::getTimeStepInSecondsAxisX() const { return m_timeStepInSecondsAxisX; } /** * Set the time step in seconds for the X-Axis (Valid when * the X-axis is time) * * @param timeStepInSecondsAxisX * Number of seconds between consecutive points in X-axis. */ void ChartTwoDataCartesian::setTimeStepInSecondsAxisX(const float timeStepInSecondsAxisX) { m_timeStepInSecondsAxisX = timeStepInSecondsAxisX; } /** * @return Data units for X axis */ CaretUnitsTypeEnum::Enum ChartTwoDataCartesian::getDataAxisUnitsX() { return m_dataAxisUnitsX; } /** * @return Data units for Y axis */ CaretUnitsTypeEnum::Enum ChartTwoDataCartesian::getDataAxisUnitsY() { return m_dataAxisUnitsY; } /** * @return Color for chart */ CaretColorEnum::Enum ChartTwoDataCartesian::getColor() const { return m_color; } /** * Set the color for the chart. * * @param color * New color for chart. */ void ChartTwoDataCartesian::setColor(const CaretColorEnum::Enum color) { m_color = color; if (m_graphicsPrimitive != NULL) { float rgba[4]; CaretColorEnum::toRGBAFloat(m_color, rgba); m_graphicsPrimitive->replaceAllVertexSolidFloatRGBA(rgba); } } /** * @return The line width. */ float ChartTwoDataCartesian::getLineWidth() const { return m_lineWidth; } /** * Set line width. * * @param lineWidth * New value for line width. */ void ChartTwoDataCartesian::setLineWidth(const float lineWidth) { m_lineWidth = lineWidth; m_graphicsPrimitive->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, m_lineWidth); } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* ChartTwoDataCartesian::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ChartTwoDataCartesian", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); // chartDataCartesian->addClass(m_mapFileDataSelector->saveToScene(sceneAttributes, // "m_mapFileDataSelector")); const std::vector& xyz = m_graphicsPrimitive->getFloatXYZ(); const int32_t numXYZ = static_cast(xyz.size()); if (numXYZ > 0) { sceneClass->addFloatArray("xyz", &xyz[0], numXYZ); } return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ChartTwoDataCartesian::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_graphicsPrimitive = createGraphicsPrimitive(); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); // m_mapFileDataSelector->restoreFromScene(sceneAttributes, chartDataCartesian->getClass("m_mapFileDataSelector")); const ScenePrimitiveArray* xyzArray = sceneClass->getPrimitiveArray("xyz"); if (xyzArray != NULL) { const int32_t numElements = xyzArray->getNumberOfArrayElements(); if (numElements > 0) { std::vector data(numElements); xyzArray->floatValues(&data[0], numElements, 0.0f); const int32_t numXYZ = (numElements / 3); for (int32_t i = 0; i < numXYZ; i++) { const int32_t i3 = i * 3; CaretAssertVectorIndex(data, i3+2); addPoint(data[i3], data[i3+1]); } } } setColor(getColor()); } connectome-workbench-1.4.2/src/Charting/ChartTwoDataCartesian.h000066400000000000000000000120261360521144700245120ustar00rootroot00000000000000#ifndef __CHART_TWO_DATA_CARTESIAN_H__ #define __CHART_TWO_DATA_CARTESIAN_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretColorEnum.h" #include "CaretObjectTracksModification.h" #include "CaretUnitsTypeEnum.h" #include "ChartTwoDataTypeEnum.h" #include "GraphicsPrimitive.h" #include "SceneableInterface.h" namespace caret { class ChartPoint; class GraphicsPrimitiveV3f; class MapFileDataSelector; class SceneClassAssistant; class ChartTwoDataCartesian : public CaretObjectTracksModification, public SceneableInterface { public: ChartTwoDataCartesian(const ChartTwoDataTypeEnum::Enum chartDataType, const CaretUnitsTypeEnum::Enum dataAxisUnitsX, const CaretUnitsTypeEnum::Enum dataAxisUnitsY, const GraphicsPrimitive::PrimitiveType graphicsPrimitiveType); virtual ~ChartTwoDataCartesian(); virtual ChartTwoDataCartesian* clone() const; bool isSelected() const; void setSelected(const bool selectionStatus); void addPoint(const float x, const float y); bool getBounds(BoundingBox& boundingBoxOut) const; GraphicsPrimitiveV3f* getGraphicsPrimitive() const; const MapFileDataSelector* getMapFileDataSelector() const; void setMapFileDataSelector(const MapFileDataSelector& mapFileDataSelector); CaretUnitsTypeEnum::Enum getDataAxisUnitsX(); CaretUnitsTypeEnum::Enum getDataAxisUnitsY(); CaretColorEnum::Enum getColor() const; void setColor(const CaretColorEnum::Enum color); float getLineWidth() const; void setLineWidth(const float lineWidth); float getTimeStartInSecondsAxisX() const; void setTimeStartInSecondsAxisX(const float timeStart); float getTimeStepInSecondsAxisX() const; void setTimeStepInSecondsAxisX(const float timeStep); // ADD_NEW_METHODS_HERE virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); /** * @return The default line width for cartesian charts. */ static float getDefaultLineWidth() { return 0.5f; } protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass); // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass); private: ChartTwoDataCartesian(const ChartTwoDataCartesian& obj); ChartTwoDataCartesian& operator=(const ChartTwoDataCartesian& obj); void copyHelperChartTwoDataCartesian(const ChartTwoDataCartesian& obj); void initializeMembersChartTwoDataCartesian(); std::unique_ptr createGraphicsPrimitive(); std::unique_ptr m_mapFileDataSelector; std::unique_ptr m_graphicsPrimitive; CaretUnitsTypeEnum::Enum m_dataAxisUnitsX; CaretUnitsTypeEnum::Enum m_dataAxisUnitsY; const GraphicsPrimitive::PrimitiveType m_graphicsPrimitiveType; bool m_selectionStatus; CaretColorEnum::Enum m_color; float m_lineWidth; float m_timeStartInSecondsAxisX; float m_timeStepInSecondsAxisX; static int32_t caretColorIndex; SceneClassAssistant* m_sceneAssistant; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHART_TWO_DATA_CARTESIAN_DECLARE__ int32_t ChartTwoDataCartesian::caretColorIndex = 0; #endif // __CHART_TWO_DATA_CARTESIAN_DECLARE__ } // namespace #endif //__CHART_TWO_DATA_CARTESIAN_H__ connectome-workbench-1.4.2/src/Charting/ChartTwoDataTypeEnum.cxx000066400000000000000000000257671360521144700247420ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CHART_TWO_DATA_TYPE_ENUM_DECLARE__ #include "ChartTwoDataTypeEnum.h" #undef __CHART_TWO_DATA_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartTwoDataTypeEnum * \brief ChartDrawingType * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_chartDrawingTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void chartDrawingTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ChartTwoDataTypeEnum.h" * * Instatiate: * m_chartDrawingTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_chartDrawingTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_chartDrawingTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(chartDrawingTypeEnumComboBoxItemActivated())); * * Update the selection: * m_chartDrawingTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ChartTwoDataTypeEnum::Enum VARIABLE = m_chartDrawingTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ChartTwoDataTypeEnum::ChartTwoDataTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ChartTwoDataTypeEnum::~ChartTwoDataTypeEnum() { } /** * Initialize the enumerated metadata. */ void ChartTwoDataTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ChartTwoDataTypeEnum(CHART_DATA_TYPE_INVALID, "CHART_DATA_TYPE_INVALID", "Invalid")); enumData.push_back(ChartTwoDataTypeEnum(CHART_DATA_TYPE_HISTOGRAM, "CHART_DATA_TYPE_HISTOGRAM", "Histogram")); enumData.push_back(ChartTwoDataTypeEnum(CHART_DATA_TYPE_LINE_SERIES, "CHART_DATA_TYPE_LINE_SERIES", "Line Series")); enumData.push_back(ChartTwoDataTypeEnum(CHART_DATA_TYPE_MATRIX, "CHART_DATA_TYPE_MATRIX", "Matrix")); /* If this fails (chart types change), update value for NUMBER_OF_CHART_DATA_TYPES */ CaretAssertMessage(enumData.size() == NUMBER_OF_CHART_DATA_TYPES, "Have chart types changed?"); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ChartTwoDataTypeEnum* ChartTwoDataTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ChartTwoDataTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartTwoDataTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoDataTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartTwoDataTypeEnum::Enum ChartTwoDataTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoDataTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoDataTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartTwoDataTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartTwoDataTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoDataTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartTwoDataTypeEnum::Enum ChartTwoDataTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoDataTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoDataTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartTwoDataTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ChartTwoDataTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoDataTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ChartTwoDataTypeEnum::Enum ChartTwoDataTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoDataTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoDataTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartTwoDataTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ChartTwoDataTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartTwoDataTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ChartTwoDataTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartTwoDataTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ChartTwoDataTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Charting/ChartTwoDataTypeEnum.h000066400000000000000000000064251360521144700243550ustar00rootroot00000000000000#ifndef __CHART_TWO_DATA_TYPE_ENUM_H__ #define __CHART_TWO_DATA_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ChartTwoDataTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Invalid */ CHART_DATA_TYPE_INVALID, /** Histogram */ CHART_DATA_TYPE_HISTOGRAM, /** Line Series */ CHART_DATA_TYPE_LINE_SERIES, /** Matrix */ CHART_DATA_TYPE_MATRIX }; ~ChartTwoDataTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); static const int32_t NUMBER_OF_CHART_DATA_TYPES = 4; private: ChartTwoDataTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ChartTwoDataTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __CHART_TWO_DATA_TYPE_ENUM_DECLARE__ std::vector ChartTwoDataTypeEnum::enumData; bool ChartTwoDataTypeEnum::initializedFlag = false; int32_t ChartTwoDataTypeEnum::integerCodeCounter = 0; #endif // __CHART_TWO_DATA_TYPE_ENUM_DECLARE__ } // namespace #endif //__CHART_TWO_DATA_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Charting/ChartTwoHistogramContentTypeEnum.cxx000066400000000000000000000263211360521144700273440ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CHART_TWO_HISTOGRAM_CONTENT_TYPE_ENUM_DECLARE__ #include "ChartTwoHistogramContentTypeEnum.h" #undef __CHART_TWO_HISTOGRAM_CONTENT_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartTwoHistogramContentTypeEnum * \brief Type of content for histograms. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_chartTwoHistogramContentTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void chartTwoHistogramContentTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ChartTwoHistogramContentTypeEnum.h" * * Instatiate: * m_chartTwoHistogramContentTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_chartTwoHistogramContentTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_chartTwoHistogramContentTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(chartTwoHistogramContentTypeEnumComboBoxItemActivated())); * * Update the selection: * m_chartTwoHistogramContentTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ChartTwoHistogramContentTypeEnum::Enum VARIABLE = m_chartTwoHistogramContentTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ChartTwoHistogramContentTypeEnum::ChartTwoHistogramContentTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ChartTwoHistogramContentTypeEnum::~ChartTwoHistogramContentTypeEnum() { } /** * Initialize the enumerated metadata. */ void ChartTwoHistogramContentTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ChartTwoHistogramContentTypeEnum(HISTOGRAM_CONTENT_TYPE_UNSUPPORTED, "HISTOGRAM_CONTENT_TYPE_UNSUPPORTED", "Unsupported")); enumData.push_back(ChartTwoHistogramContentTypeEnum(HISTOGRAM_CONTENT_TYPE_MAP_DATA, "HISTOGRAM_CONTENT_TYPE_MAP_DATA", "Map Data")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ChartTwoHistogramContentTypeEnum* ChartTwoHistogramContentTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ChartTwoHistogramContentTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartTwoHistogramContentTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoHistogramContentTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartTwoHistogramContentTypeEnum::Enum ChartTwoHistogramContentTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoHistogramContentTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoHistogramContentTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartTwoHistogramContentTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartTwoHistogramContentTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoHistogramContentTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartTwoHistogramContentTypeEnum::Enum ChartTwoHistogramContentTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoHistogramContentTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoHistogramContentTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartTwoHistogramContentTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ChartTwoHistogramContentTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoHistogramContentTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ChartTwoHistogramContentTypeEnum::Enum ChartTwoHistogramContentTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoHistogramContentTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoHistogramContentTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartTwoHistogramContentTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ChartTwoHistogramContentTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartTwoHistogramContentTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ChartTwoHistogramContentTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartTwoHistogramContentTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ChartTwoHistogramContentTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Charting/ChartTwoHistogramContentTypeEnum.h000066400000000000000000000064521360521144700267740ustar00rootroot00000000000000#ifndef __CHART_TWO_HISTOGRAM_CONTENT_TYPE_ENUM_H__ #define __CHART_TWO_HISTOGRAM_CONTENT_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ChartTwoHistogramContentTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Unsupported */ HISTOGRAM_CONTENT_TYPE_UNSUPPORTED, /** Map Data Content */ HISTOGRAM_CONTENT_TYPE_MAP_DATA }; ~ChartTwoHistogramContentTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ChartTwoHistogramContentTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ChartTwoHistogramContentTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __CHART_TWO_HISTOGRAM_CONTENT_TYPE_ENUM_DECLARE__ std::vector ChartTwoHistogramContentTypeEnum::enumData; bool ChartTwoHistogramContentTypeEnum::initializedFlag = false; int32_t ChartTwoHistogramContentTypeEnum::integerCodeCounter = 0; #endif // __CHART_TWO_HISTOGRAM_CONTENT_TYPE_ENUM_DECLARE__ } // namespace #endif //__CHART_TWO_HISTOGRAM_CONTENT_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Charting/ChartTwoLineSeriesContentTypeEnum.cxx000066400000000000000000000270271360521144700274550ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CHART_TWO_LINE_SERIES_CONTENT_TYPE_ENUM_DECLARE__ #include "ChartTwoLineSeriesContentTypeEnum.h" #undef __CHART_TWO_LINE_SERIES_CONTENT_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartTwoLineSeriesContentTypeEnum * \brief Type of content for line series charting. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_chartTwoLineSeriesContentTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void chartTwoLineSeriesContentTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ChartTwoLineSeriesContentTypeEnum.h" * * Instatiate: * m_chartTwoLineSeriesContentTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_chartTwoLineSeriesContentTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_chartTwoLineSeriesContentTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(chartTwoLineSeriesContentTypeEnumComboBoxItemActivated())); * * Update the selection: * m_chartTwoLineSeriesContentTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ChartTwoLineSeriesContentTypeEnum::Enum VARIABLE = m_chartTwoLineSeriesContentTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ChartTwoLineSeriesContentTypeEnum::ChartTwoLineSeriesContentTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ChartTwoLineSeriesContentTypeEnum::~ChartTwoLineSeriesContentTypeEnum() { } /** * Initialize the enumerated metadata. */ void ChartTwoLineSeriesContentTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ChartTwoLineSeriesContentTypeEnum(LINE_SERIES_CONTENT_UNSUPPORTED, "LINE_SERIES_CONTENT_UNSUPPORTED", "Unsupported")); enumData.push_back(ChartTwoLineSeriesContentTypeEnum(LINE_SERIES_CONTENT_BRAINORDINATE_DATA, "LINE_SERIES_CONTENT_BRAINORDINATE_DATA", "Brainordinate Data")); enumData.push_back(ChartTwoLineSeriesContentTypeEnum(LINE_SERIES_CONTENT_ROW_SCALAR_DATA, "LINE_SERIES_CONTENT_ROW_SCALAR_DATA", "Row Scalar Data")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ChartTwoLineSeriesContentTypeEnum* ChartTwoLineSeriesContentTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ChartTwoLineSeriesContentTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartTwoLineSeriesContentTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoLineSeriesContentTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartTwoLineSeriesContentTypeEnum::Enum ChartTwoLineSeriesContentTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoLineSeriesContentTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoLineSeriesContentTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartTwoLineSeriesContentTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartTwoLineSeriesContentTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoLineSeriesContentTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartTwoLineSeriesContentTypeEnum::Enum ChartTwoLineSeriesContentTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoLineSeriesContentTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoLineSeriesContentTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartTwoLineSeriesContentTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ChartTwoLineSeriesContentTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoLineSeriesContentTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ChartTwoLineSeriesContentTypeEnum::Enum ChartTwoLineSeriesContentTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoLineSeriesContentTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoLineSeriesContentTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartTwoLineSeriesContentTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ChartTwoLineSeriesContentTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartTwoLineSeriesContentTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ChartTwoLineSeriesContentTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartTwoLineSeriesContentTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ChartTwoLineSeriesContentTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Charting/ChartTwoLineSeriesContentTypeEnum.h000066400000000000000000000066331360521144700271020ustar00rootroot00000000000000#ifndef __CHART_TWO_LINE_SERIES_CONTENT_TYPE_ENUM_H__ #define __CHART_TWO_LINE_SERIES_CONTENT_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ChartTwoLineSeriesContentTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Unsupported */ LINE_SERIES_CONTENT_UNSUPPORTED, /** Brainordinate Data Content */ LINE_SERIES_CONTENT_BRAINORDINATE_DATA, /** Row Scalars Content */ LINE_SERIES_CONTENT_ROW_SCALAR_DATA }; ~ChartTwoLineSeriesContentTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ChartTwoLineSeriesContentTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ChartTwoLineSeriesContentTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __CHART_TWO_LINE_SERIES_CONTENT_TYPE_ENUM_DECLARE__ std::vector ChartTwoLineSeriesContentTypeEnum::enumData; bool ChartTwoLineSeriesContentTypeEnum::initializedFlag = false; int32_t ChartTwoLineSeriesContentTypeEnum::integerCodeCounter = 0; #endif // __CHART_TWO_LINE_SERIES_CONTENT_TYPE_ENUM_DECLARE__ } // namespace #endif //__CHART_TWO_LINE_SERIES_CONTENT_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Charting/ChartTwoLineSeriesHistory.cxx000066400000000000000000000437501360521144700260160ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_TWO_LINE_SERIES_HISTORY_DECLARE__ #include "ChartTwoLineSeriesHistory.h" #undef __CHART_TWO_LINE_SERIES_HISTORY_DECLARE__ #include "BoundingBox.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "ChartTwoDataCartesian.h" #include "MapFileDataSelector.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ChartTwoLineSeriesHistory * \brief Contains history of line series chart for a tab. * \ingroup Charting */ /** * Constructor. */ ChartTwoLineSeriesHistory::ChartTwoLineSeriesHistory(const GraphicsPrimitive::PrimitiveType defaultGraphicsPrimitiveType) : CaretObjectTracksModification(), SceneableInterface(), m_defaultGraphicsPrimitiveType(defaultGraphicsPrimitiveType) { initializeInstance(); } /** * Destructor. */ ChartTwoLineSeriesHistory::~ChartTwoLineSeriesHistory() { clearHistory(); delete m_sceneAssistant; } /** * Copy constructor. * @param obj * Object that is copied. */ ChartTwoLineSeriesHistory::ChartTwoLineSeriesHistory(const ChartTwoLineSeriesHistory& obj) : CaretObjectTracksModification(obj), SceneableInterface(obj), m_defaultGraphicsPrimitiveType(obj.m_defaultGraphicsPrimitiveType) { initializeInstance(); this->copyHelperChartTwoLineSeriesHistory(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ChartTwoLineSeriesHistory& ChartTwoLineSeriesHistory::operator=(const ChartTwoLineSeriesHistory& obj) { if (this != &obj) { CaretObjectTracksModification::operator=(obj); this->copyHelperChartTwoLineSeriesHistory(obj); } return *this; } bool ChartTwoLineSeriesHistory::isLoadingEnabled() const { return m_loadingEnabled; } /** * @return Default type of graphics primitive for this line-series history. */ GraphicsPrimitive::PrimitiveType ChartTwoLineSeriesHistory::getDefaultGraphicsPrimitiveType() const { return m_defaultGraphicsPrimitiveType; } /** * Set loading line series charts enabled * * @param loadingEnabled * New value for loading line series charts enabled */ void ChartTwoLineSeriesHistory::setLoadingEnabled(const bool loadingEnabled) { m_loadingEnabled = loadingEnabled; } /** * Generate the default color. */ CaretColorEnum::Enum ChartTwoLineSeriesHistory::generateDefaultColor() { /* * No black or white since they are used for backgrounds */ std::vector colors; CaretColorEnum::getColorEnumsNoBlackOrWhite(colors); CaretAssert( ! colors.empty()); CaretColorEnum::Enum color = colors[0]; const int32_t numColors = static_cast(colors.size()); CaretAssert(numColors > 0); if (s_defaultColorIndexGenerator < 0) { s_defaultColorIndexGenerator = 0; } else if (s_defaultColorIndexGenerator >= numColors) { s_defaultColorIndexGenerator = 0; } CaretAssertVectorIndex(colors, s_defaultColorIndexGenerator); color = colors[s_defaultColorIndexGenerator]; /* move to next color */ ++s_defaultColorIndexGenerator; return color; } /** * Validate the default color. */ void ChartTwoLineSeriesHistory::validateDefaultColor() { std::vector allEnums; CaretColorEnum::getColorAndOptionalEnums(allEnums, (CaretColorEnum::ColorOptions::OPTION_INCLUDE_CUSTOM_COLOR | CaretColorEnum::CaretColorEnum::OPTION_INCLUDE_NONE_COLOR)); if (std::find(allEnums.begin(), allEnums.end(), m_defaultColor) == allEnums.end()) { const AString msg("Default color enum is invalid. Integer value: " + AString::number((int)m_defaultColor)); CaretLogSevere(msg); m_defaultColor = CaretColorEnum::RED; } if (m_defaultColor == CaretColorEnum::CUSTOM) { const AString msg("Default color CUSTOM is not allowed"); CaretLogSevere(msg); m_defaultColor = CaretColorEnum::RED; } else if (m_defaultColor == CaretColorEnum::NONE) { const AString msg("Default color NONE is not allowed"); CaretLogSevere(msg); m_defaultColor = CaretColorEnum::RED; } } /** * Initialize an instance of this class. */ void ChartTwoLineSeriesHistory::initializeInstance() { m_defaultColor = ChartTwoLineSeriesHistory::generateDefaultColor(); validateDefaultColor(); m_defaultLineWidth = ChartTwoDataCartesian::getDefaultLineWidth(); const int32_t defaultHistoryCount = 1; m_loadingEnabled = false; m_sceneAssistant = new SceneClassAssistant(); m_displayCount = defaultHistoryCount; m_sceneAssistant->add("m_loadingEnabled", &m_loadingEnabled); m_sceneAssistant->add("m_defaultColor", &m_defaultColor); m_sceneAssistant->add("m_defaultLineWidth", &m_defaultLineWidth); m_sceneAssistant->add("m_displayCount", &m_displayCount); } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ChartTwoLineSeriesHistory::copyHelperChartTwoLineSeriesHistory(const ChartTwoLineSeriesHistory& obj) { m_loadingEnabled = obj.m_loadingEnabled; clearHistory(); for (const auto item : m_chartHistory) { ChartTwoDataCartesian* cartData = item->clone(); CaretAssert(cartData); addHistoryItemNoDefaults(cartData); } m_defaultColor = obj.m_defaultColor; m_defaultLineWidth = obj.m_defaultLineWidth; m_displayCount = obj.m_displayCount; validateDefaultColor(); } /** * @return The default color. */ CaretColorEnum::Enum ChartTwoLineSeriesHistory::getDefaultColor() const { return m_defaultColor; } /** * Set the default color. * * @param defaultColor New value for default color. */ void ChartTwoLineSeriesHistory::setDefaultColor(const CaretColorEnum::Enum defaultColor) { if (defaultColor != m_defaultColor) { m_defaultColor = defaultColor; validateDefaultColor(); setModified(); } } /** * @return Default width of lines */ float ChartTwoLineSeriesHistory::getDefaultLineWidth() const { return m_defaultLineWidth; } /** * Set Default width of lines * * @param defaultLineWidth * New value for Default width of lines */ void ChartTwoLineSeriesHistory::setDefaultLineWidth(const float defaultLineWidth) { if (defaultLineWidth != m_defaultLineWidth) { m_defaultLineWidth = defaultLineWidth; setModified(); } } /** * @return Count of items for display. */ int32_t ChartTwoLineSeriesHistory::getDisplayCount() const { return m_displayCount; } /** * Set count of items for display. * * @param count * New value for count. */ void ChartTwoLineSeriesHistory::setDisplayCount(const int32_t count) { if (count != m_displayCount) { m_displayCount = count; updateDisplayedHistoryItems(); setModified(); } } /** * Update the number of displayed history items. */ void ChartTwoLineSeriesHistory::updateDisplayedHistoryItems() { int32_t itemsDisplayedCount = 0; const int32_t historyCount = getHistoryCount(); for (int32_t i = 0; i < historyCount; i++) { ChartTwoDataCartesian* item = getHistoryItem(i); if (item->isSelected()) { itemsDisplayedCount++; if (itemsDisplayedCount > m_displayCount) { item->setSelected(false); } } } /* * Limit the number of history items to * avoid excessive memory usage */ const int32_t maximumItems = std::max(m_displayCount, s_maximumRetainedHistoryCount); if (historyCount > maximumItems) { for (int32_t i = maximumItems; i < historyCount; i++) { CaretAssertVectorIndex(m_chartHistory, i); CaretAssert(m_chartHistory[i]); delete m_chartHistory[i]; m_chartHistory[i]= NULL; } m_chartHistory.resize(maximumItems); } } /** * @return The maximum number of history items that are * retained. */ int32_t ChartTwoLineSeriesHistory::getMaximumRetainedHistoryCount() { return s_maximumRetainedHistoryCount; } /** * @return Count of items in history. */ int32_t ChartTwoLineSeriesHistory::getHistoryCount() const { return m_chartHistory.size(); } /** * Add a history item. This instance takes ownership of the item * and will delete it. Defaults such as line color and width assigned to item. * * @param historyItem * Added to history. */ void ChartTwoLineSeriesHistory::addHistoryItem(ChartTwoDataCartesian* historyItem) { CaretAssert(historyItem); /* * Do not add to history if new history item matches history * item at front of the deque */ if ( ! m_chartHistory.empty()) { const MapFileDataSelector* newFileMap = historyItem->getMapFileDataSelector(); const MapFileDataSelector* frontFileMap = m_chartHistory.at(0)->getMapFileDataSelector(); if (*newFileMap == *frontFileMap) { delete historyItem; return; } } historyItem->setColor(m_defaultColor); historyItem->setLineWidth(m_defaultLineWidth); addHistoryItemNoDefaults(historyItem); updateDisplayedHistoryItems(); } /** * Add a history item. No defaults are applied to the history items. * * @param historyItem * Added to history. */ void ChartTwoLineSeriesHistory::addHistoryItemNoDefaults(ChartTwoDataCartesian* historyItem) { CaretAssert(historyItem); m_chartHistory.push_front(historyItem); } /** * @return History item at the given index. * * @param index * Index of the item. */ ChartTwoDataCartesian* ChartTwoLineSeriesHistory::getHistoryItem(const int32_t index) { CaretAssertVectorIndex(m_chartHistory, index); return m_chartHistory[index]; } /** * @return History item at the given index (const method). * * @param index * Index of the item. */ const ChartTwoDataCartesian* ChartTwoLineSeriesHistory::getHistoryItem(const int32_t index) const { CaretAssertVectorIndex(m_chartHistory, index); return m_chartHistory[index]; } /** * Remove the history item at the given index * * @param index * Index of the item. */ void ChartTwoLineSeriesHistory::removeHistoryItem(const int32_t index) { CaretAssertVectorIndex(m_chartHistory, index); delete m_chartHistory[index]; m_chartHistory.erase(m_chartHistory.begin() + index); } /** * Move the history item down at the given index * * @param index * Index of the item. */ void ChartTwoLineSeriesHistory::moveDownHistoryItem(const int32_t index) { if (getHistoryCount() <= 1) { return; } const int32_t lastIndex = getHistoryCount() - 1; if (index < lastIndex) { std::swap(m_chartHistory[index], m_chartHistory[index + 1]); } } /** * Move the history item up at the given index * * @param index * Index of the item. */ void ChartTwoLineSeriesHistory::moveUpHistoryItem(const int32_t index) { if (getHistoryCount() <= 1) { return; } if (index > 0) { std::swap(m_chartHistory[index - 1], m_chartHistory[index]); } } /** * @return Clear the history. */ void ChartTwoLineSeriesHistory::clearHistory() { for (auto item : m_chartHistory) { delete item; } m_chartHistory.clear(); } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ChartTwoLineSeriesHistory::toString() const { return "ChartTwoLineSeriesHistory"; } /** * @return Is this instance modified? */ bool ChartTwoLineSeriesHistory::isModified() const { if (CaretObjectTracksModification::isModified()) { return true; } for (const auto item : m_chartHistory) { if (item->isModified()) { return true; } } return false; } /** * Clear modified status for this instance. */ void ChartTwoLineSeriesHistory::clearModified() { for (const auto item : m_chartHistory) { item->clearModified(); } } /** * Get a bounding box for data displayed within this overlay. * Bounds are provided for histogram and line-series charts only. * * @param boundingBox * Upon exit contains bounds for data within this overlay * @return * True if the bounds are valid, else false. */ bool ChartTwoLineSeriesHistory::getBounds(BoundingBox& boundingBoxOut) const { boundingBoxOut.resetForUpdate(); bool validFlag = false; for (const auto data : m_chartHistory) { CaretAssert(data); if (data->isSelected()) { BoundingBox boundingBox; if (data->getBounds(boundingBox)) { boundingBoxOut.update(boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMinZ()); boundingBoxOut.update(boundingBox.getMaxX(), boundingBox.getMaxY(), boundingBox.getMaxZ()); validFlag = true; } } } return validFlag; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* ChartTwoLineSeriesHistory::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ChartTwoLineSeriesHistory", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); /* * Save chart history but only the displayed items */ const int32_t numHistory = static_cast(m_chartHistory.size()); if (numHistory > 0) { SceneObjectMapIntegerKey* chartHistoryMap = new SceneObjectMapIntegerKey("m_chartHistoryMap", SceneObjectDataTypeEnum::SCENE_CLASS); for (int32_t i = 0; i < numHistory; i++) { CaretAssertVectorIndex(m_chartHistory, i); if (m_chartHistory[i]->isSelected()) { chartHistoryMap->addClass(i, m_chartHistory[i]->saveToScene(sceneAttributes, "m_chartHistory")); } } if (chartHistoryMap->isEmpty()) { delete chartHistoryMap; chartHistoryMap = NULL; } else { sceneClass->addChild(chartHistoryMap); } } // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ChartTwoLineSeriesHistory::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } clearHistory(); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); validateDefaultColor(); /* * Restore chart matrix properties * Need to reverse keys since items are added on at beginning */ const SceneObjectMapIntegerKey* chartHistoryMap = sceneClass->getMapIntegerKey("m_chartHistoryMap"); if (chartHistoryMap != NULL) { std::vector indices = chartHistoryMap->getKeys(); std::reverse(indices.begin(), indices.end()); for (auto itemIndex : indices) { const SceneClass* historyClass = chartHistoryMap->classValue(itemIndex); ChartTwoDataCartesian* historyItem = new ChartTwoDataCartesian(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, CaretUnitsTypeEnum::NONE, CaretUnitsTypeEnum::NONE, m_defaultGraphicsPrimitiveType); historyItem->restoreFromScene(sceneAttributes, historyClass); addHistoryItemNoDefaults(historyItem); } } //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Charting/ChartTwoLineSeriesHistory.h000066400000000000000000000122351360521144700254350ustar00rootroot00000000000000#ifndef __CHART_TWO_LINE_SERIES_HISTORY_H__ #define __CHART_TWO_LINE_SERIES_HISTORY_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "BrainConstants.h" #include "CaretColorEnum.h" #include "CaretObjectTracksModification.h" #include "GraphicsPrimitive.h" #include "SceneableInterface.h" namespace caret { class BoundingBox; class ChartTwoDataCartesian; class SceneClassAssistant; class ChartTwoLineSeriesHistory : public CaretObjectTracksModification, public SceneableInterface { public: ChartTwoLineSeriesHistory(const GraphicsPrimitive::PrimitiveType defaultGraphicsPrimitiveType); virtual ~ChartTwoLineSeriesHistory(); ChartTwoLineSeriesHistory(const ChartTwoLineSeriesHistory& obj); ChartTwoLineSeriesHistory& operator=(const ChartTwoLineSeriesHistory& obj); GraphicsPrimitive::PrimitiveType getDefaultGraphicsPrimitiveType() const; bool isLoadingEnabled() const; void setLoadingEnabled(const bool enabled); CaretColorEnum::Enum getDefaultColor() const; void setDefaultColor(const CaretColorEnum::Enum defaultColor); float getDefaultLineWidth() const; void setDefaultLineWidth(const float defaultLineWidth); int32_t getDisplayCount() const; void setDisplayCount(const int32_t count); int32_t getHistoryCount() const; void addHistoryItem(ChartTwoDataCartesian* historyItem); ChartTwoDataCartesian* getHistoryItem(const int32_t index); const ChartTwoDataCartesian* getHistoryItem(const int32_t index) const; void removeHistoryItem(const int32_t index); void moveDownHistoryItem(const int32_t index); void moveUpHistoryItem(const int32_t index); void clearHistory(); bool getBounds(BoundingBox& boundingBoxOut) const; // ADD_NEW_METHODS_HERE virtual AString toString() const override; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) override; virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) override; virtual bool isModified() const override; virtual void clearModified() override; static int32_t getMaximumRetainedHistoryCount(); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implementation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: void copyHelperChartTwoLineSeriesHistory(const ChartTwoLineSeriesHistory& obj); void initializeInstance(); void updateDisplayedHistoryItems(); void addHistoryItemNoDefaults(ChartTwoDataCartesian* historyItem); static CaretColorEnum::Enum generateDefaultColor(); void validateDefaultColor(); const GraphicsPrimitive::PrimitiveType m_defaultGraphicsPrimitiveType; bool m_loadingEnabled = false; SceneClassAssistant* m_sceneAssistant = NULL; std::deque m_chartHistory; CaretColorEnum::Enum m_defaultColor = CaretColorEnum::BLUE; float m_defaultLineWidth; int32_t m_displayCount; static int32_t s_defaultColorIndexGenerator; static const int32_t s_maximumRetainedHistoryCount; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHART_TWO_LINE_SERIES_HISTORY_DECLARE__ int32_t ChartTwoLineSeriesHistory::s_defaultColorIndexGenerator = 0; const int32_t ChartTwoLineSeriesHistory::s_maximumRetainedHistoryCount = 20; #endif // __CHART_TWO_LINE_SERIES_HISTORY_DECLARE__ } // namespace #endif //__CHART_TWO_LINE_SERIES_HISTORY_H__ connectome-workbench-1.4.2/src/Charting/ChartTwoMatrixContentTypeEnum.cxx000066400000000000000000000264351360521144700266610ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CHART_TWO_MATRIX_CONTENT_TYPE_ENUM_DECLARE__ #include "ChartTwoMatrixContentTypeEnum.h" #undef __CHART_TWO_MATRIX_CONTENT_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartTwoMatrixContentTypeEnum * \brief Type of content for matrix charting. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_chartTwoMatrixDataTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void chartTwoMatrixDataTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ChartTwoMatrixContentTypeEnum.h" * * Instatiate: * m_chartTwoMatrixDataTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_chartTwoMatrixDataTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_chartTwoMatrixDataTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(chartTwoMatrixDataTypeEnumComboBoxItemActivated())); * * Update the selection: * m_chartTwoMatrixDataTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ChartTwoMatrixContentTypeEnum::Enum VARIABLE = m_chartTwoMatrixDataTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ChartTwoMatrixContentTypeEnum::ChartTwoMatrixContentTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ChartTwoMatrixContentTypeEnum::~ChartTwoMatrixContentTypeEnum() { } /** * Initialize the enumerated metadata. */ void ChartTwoMatrixContentTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ChartTwoMatrixContentTypeEnum(MATRIX_CONTENT_UNSUPPORTED, "MATRIX_CONTENT_UNSUPPORTED", "Unsupported")); enumData.push_back(ChartTwoMatrixContentTypeEnum(MATRIX_CONTENT_BRAINORDINATE_MAPPABLE, "MATRIX_CONTENT_BRAINORDINATE_MAPPABLE", "Brainordinate Mappable")); enumData.push_back(ChartTwoMatrixContentTypeEnum(MATRIX_CONTENT_SCALARS, "MATRIX_CONTENT_SCALARS", "Scalars")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ChartTwoMatrixContentTypeEnum* ChartTwoMatrixContentTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ChartTwoMatrixContentTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartTwoMatrixContentTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoMatrixContentTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartTwoMatrixContentTypeEnum::Enum ChartTwoMatrixContentTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoMatrixContentTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoMatrixContentTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartTwoMatrixContentTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartTwoMatrixContentTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoMatrixContentTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartTwoMatrixContentTypeEnum::Enum ChartTwoMatrixContentTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoMatrixContentTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoMatrixContentTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartTwoMatrixContentTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ChartTwoMatrixContentTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoMatrixContentTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ChartTwoMatrixContentTypeEnum::Enum ChartTwoMatrixContentTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoMatrixContentTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoMatrixContentTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartTwoMatrixContentTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ChartTwoMatrixContentTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartTwoMatrixContentTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ChartTwoMatrixContentTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartTwoMatrixContentTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ChartTwoMatrixContentTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Charting/ChartTwoMatrixContentTypeEnum.h000066400000000000000000000065121360521144700263000ustar00rootroot00000000000000#ifndef __CHART_TWO_MATRIX_CONTENT_TYPE_ENUM_H__ #define __CHART_TWO_MATRIX_CONTENT_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ChartTwoMatrixContentTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Unsupported */ MATRIX_CONTENT_UNSUPPORTED, /** Brainordinate mappable content */ MATRIX_CONTENT_BRAINORDINATE_MAPPABLE, /** Scalar content */ MATRIX_CONTENT_SCALARS }; ~ChartTwoMatrixContentTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ChartTwoMatrixContentTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ChartTwoMatrixContentTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __CHART_TWO_MATRIX_CONTENT_TYPE_ENUM_DECLARE__ std::vector ChartTwoMatrixContentTypeEnum::enumData; bool ChartTwoMatrixContentTypeEnum::initializedFlag = false; int32_t ChartTwoMatrixContentTypeEnum::integerCodeCounter = 0; #endif // __CHART_TWO_MATRIX_CONTENT_TYPE_ENUM_DECLARE__ } // namespace #endif //__CHART_TWO_MATRIX_CONTENT_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Charting/ChartTwoMatrixDisplayProperties.cxx000066400000000000000000000174271360521144700272430ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_TWO_MATRIX_DISPLAY_PROPERTIES_DECLARE__ #include "ChartTwoMatrixDisplayProperties.h" #undef __CHART_TWO_MATRIX_DISPLAY_PROPERTIES_DECLARE__ #include "CaretAssert.h" #include "EventManager.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ChartTwoMatrixDisplayProperties * \brief Display properties for version two of Matrix charting. * \ingroup Charting */ /** * Constructor. */ ChartTwoMatrixDisplayProperties::ChartTwoMatrixDisplayProperties() : CaretObject(), EventListenerInterface(), SceneableInterface() { initializeInstance(); } /** * Destructor. */ ChartTwoMatrixDisplayProperties::~ChartTwoMatrixDisplayProperties() { EventManager::get()->removeAllEventsFromListener(this); delete m_sceneAssistant; } /** * Initialize a new instance of this class. */ void ChartTwoMatrixDisplayProperties::initializeInstance() { resetPropertiesToDefault(); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_cellPercentageZoomWidth", &m_cellPercentageZoomWidth); m_sceneAssistant->add("m_cellPercentageZoomHeight", &m_cellPercentageZoomHeight); m_sceneAssistant->add("m_displayGridLinesFlag", &m_displayGridLinesFlag); m_sceneAssistant->add("m_highlightSelectedRowColumnFlag", &m_highlightSelectedRowColumnFlag); // EventManager::get()->addEventListener(this, EventTypeEnum::); } /** * Copy constructor. * @param obj * Object that is copied. */ ChartTwoMatrixDisplayProperties::ChartTwoMatrixDisplayProperties(const ChartTwoMatrixDisplayProperties& obj) : CaretObject(obj), EventListenerInterface(), SceneableInterface(obj) { initializeInstance(); this->copyHelperChartTwoMatrixDisplayProperties(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ChartTwoMatrixDisplayProperties& ChartTwoMatrixDisplayProperties::operator=(const ChartTwoMatrixDisplayProperties& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperChartTwoMatrixDisplayProperties(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ChartTwoMatrixDisplayProperties::copyHelperChartTwoMatrixDisplayProperties(const ChartTwoMatrixDisplayProperties& obj) { m_cellPercentageZoomWidth = obj.m_cellPercentageZoomWidth; m_cellPercentageZoomHeight = obj.m_cellPercentageZoomHeight; m_displayGridLinesFlag = obj.m_displayGridLinesFlag; m_highlightSelectedRowColumnFlag = obj.m_highlightSelectedRowColumnFlag; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ChartTwoMatrixDisplayProperties::toString() const { return "ChartTwoMatrixDisplayProperties"; } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void ChartTwoMatrixDisplayProperties::receiveEvent(Event* /*event*/) { } /** * Reset the display properties to their default values. */ void ChartTwoMatrixDisplayProperties::resetPropertiesToDefault() { m_cellPercentageZoomWidth = 100.0; m_cellPercentageZoomHeight = 100.0; m_highlightSelectedRowColumnFlag = true; m_displayGridLinesFlag = false; } /** * @return Display grid lines status. */ bool ChartTwoMatrixDisplayProperties::isGridLinesDisplayed() const { return m_displayGridLinesFlag; } /** * Set the grid lines display status. * * @param displayGridLines * New status for display of grid lines. */ void ChartTwoMatrixDisplayProperties::setGridLinesDisplayed(const bool displayGridLines) { m_displayGridLinesFlag = displayGridLines; } /** * @return highlight selected row/column status. */ bool ChartTwoMatrixDisplayProperties::isSelectedRowColumnHighlighted() const { return m_highlightSelectedRowColumnFlag; } /** * Set the row/column highlighting status. * * @param highlightStatus * New highlighting status. */ void ChartTwoMatrixDisplayProperties::setSelectedRowColumnHighlighted(const bool highlightStatus) { m_highlightSelectedRowColumnFlag = highlightStatus; } /** * @return The cell percentage zoom width. */ float ChartTwoMatrixDisplayProperties::getCellPercentageZoomWidth() const { return m_cellPercentageZoomWidth; } /** * Set the cell percentage zoom width. * * @param cellPercentageZoomWidth * New value for cell percentage zoom width. */ void ChartTwoMatrixDisplayProperties::setCellPercentageZoomWidth(const float cellPercentageZoomWidth) { m_cellPercentageZoomWidth = cellPercentageZoomWidth; } /** * @return The cell percentage zoom height. */ float ChartTwoMatrixDisplayProperties::getCellPercentageZoomHeight() const { return m_cellPercentageZoomHeight; } /** * Set the cell percentage zoom height. * * @param cellPercentageZoomHeight * New value for cell percentage zoom height. */ void ChartTwoMatrixDisplayProperties::setCellPercentageZoomHeight(const float cellPercentageZoomHeight) { m_cellPercentageZoomHeight = cellPercentageZoomHeight; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* ChartTwoMatrixDisplayProperties::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ChartTwoMatrixDisplayProperties", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ChartTwoMatrixDisplayProperties::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Charting/ChartTwoMatrixDisplayProperties.h000066400000000000000000000074371360521144700266700ustar00rootroot00000000000000#ifndef __CHART_TWO_MATRIX_DISPLAY_PROPERTIES_H__ #define __CHART_TWO_MATRIX_DISPLAY_PROPERTIES_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" namespace caret { class SceneClassAssistant; class ChartTwoMatrixDisplayProperties : public CaretObject, public EventListenerInterface, public SceneableInterface { public: ChartTwoMatrixDisplayProperties(); virtual ~ChartTwoMatrixDisplayProperties(); ChartTwoMatrixDisplayProperties(const ChartTwoMatrixDisplayProperties& obj); ChartTwoMatrixDisplayProperties& operator=(const ChartTwoMatrixDisplayProperties& obj); bool isGridLinesDisplayed() const; void setGridLinesDisplayed(const bool displayGridLines); void resetPropertiesToDefault(); bool isSelectedRowColumnHighlighted() const; void setSelectedRowColumnHighlighted(const bool highlightStatus); float getCellPercentageZoomWidth() const; void setCellPercentageZoomWidth(const float cellPercentageZoomWidth); float getCellPercentageZoomHeight() const; void setCellPercentageZoomHeight(const float cellPercentageZoomHeight); // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual void receiveEvent(Event* event); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implementation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: void copyHelperChartTwoMatrixDisplayProperties(const ChartTwoMatrixDisplayProperties& obj); void initializeInstance(); SceneClassAssistant* m_sceneAssistant; float m_cellPercentageZoomHeight; float m_cellPercentageZoomWidth; bool m_highlightSelectedRowColumnFlag; bool m_displayGridLinesFlag; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHART_TWO_MATRIX_DISPLAY_PROPERTIES_DECLARE__ // #endif // __CHART_TWO_MATRIX_DISPLAY_PROPERTIES_DECLARE__ } // namespace #endif //__CHART_TWO_MATRIX_DISPLAY_PROPERTIES_H__ connectome-workbench-1.4.2/src/Charting/ChartTwoMatrixLoadingDimensionEnum.cxx000066400000000000000000000266111360521144700276240ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CHART_TWO_MATRIX_LOADING_TYPE_ENUM_DECLARE__ #include "ChartTwoMatrixLoadingDimensionEnum.h" #undef __CHART_TWO_MATRIX_LOADING_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartTwoMatrixLoadingDimensionEnum * \brief Enumerated type for loading matrix data by row or column * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_ChartTwoMatrixLoadingDimensionEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void ChartTwoMatrixLoadingDimensionEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ChartTwoMatrixLoadingDimensionEnum.h" * * Instatiate: * m_ChartTwoMatrixLoadingDimensionEnumComboBox = new EnumComboBoxTemplate(this); * m_ChartTwoMatrixLoadingDimensionEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_ChartTwoMatrixLoadingDimensionEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(ChartTwoMatrixLoadingDimensionEnumComboBoxItemActivated())); * * Update the selection: * m_ChartTwoMatrixLoadingDimensionEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ChartTwoMatrixLoadingDimensionEnum::Enum VARIABLE = m_ChartTwoMatrixLoadingDimensionEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ChartTwoMatrixLoadingDimensionEnum::ChartTwoMatrixLoadingDimensionEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ChartTwoMatrixLoadingDimensionEnum::~ChartTwoMatrixLoadingDimensionEnum() { } /** * Initialize the enumerated metadata. */ void ChartTwoMatrixLoadingDimensionEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ChartTwoMatrixLoadingDimensionEnum(CHART_MATRIX_LOADING_BY_ROW, "CHART_MATRIX_LOADING_BY_ROW", "Row")); enumData.push_back(ChartTwoMatrixLoadingDimensionEnum(CHART_MATRIX_LOADING_BY_COLUMN, "CHART_MATRIX_LOADING_BY_COLUMN", "Column")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ChartTwoMatrixLoadingDimensionEnum* ChartTwoMatrixLoadingDimensionEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ChartTwoMatrixLoadingDimensionEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartTwoMatrixLoadingDimensionEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoMatrixLoadingDimensionEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartTwoMatrixLoadingDimensionEnum::Enum ChartTwoMatrixLoadingDimensionEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoMatrixLoadingDimensionEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoMatrixLoadingDimensionEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartTwoMatrixLoadingDimensionEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartTwoMatrixLoadingDimensionEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoMatrixLoadingDimensionEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartTwoMatrixLoadingDimensionEnum::Enum ChartTwoMatrixLoadingDimensionEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoMatrixLoadingDimensionEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoMatrixLoadingDimensionEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartTwoMatrixLoadingDimensionEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ChartTwoMatrixLoadingDimensionEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoMatrixLoadingDimensionEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ChartTwoMatrixLoadingDimensionEnum::Enum ChartTwoMatrixLoadingDimensionEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoMatrixLoadingDimensionEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoMatrixLoadingDimensionEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartTwoMatrixLoadingDimensionEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ChartTwoMatrixLoadingDimensionEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartTwoMatrixLoadingDimensionEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ChartTwoMatrixLoadingDimensionEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartTwoMatrixLoadingDimensionEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ChartTwoMatrixLoadingDimensionEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Charting/ChartTwoMatrixLoadingDimensionEnum.h000066400000000000000000000064621360521144700272530ustar00rootroot00000000000000#ifndef __CHART_TWO_MATRIX_LOADING_TYPE_ENUM_H__ #define __CHART_TWO_MATRIX_LOADING_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ChartTwoMatrixLoadingDimensionEnum { public: /** * Enumerated values. */ enum Enum { /** Load data from column */ CHART_MATRIX_LOADING_BY_COLUMN, /** Load data from row */ CHART_MATRIX_LOADING_BY_ROW }; ~ChartTwoMatrixLoadingDimensionEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ChartTwoMatrixLoadingDimensionEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ChartTwoMatrixLoadingDimensionEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __CHART_TWO_MATRIX_LOADING_TYPE_ENUM_DECLARE__ std::vector ChartTwoMatrixLoadingDimensionEnum::enumData; bool ChartTwoMatrixLoadingDimensionEnum::initializedFlag = false; int32_t ChartTwoMatrixLoadingDimensionEnum::integerCodeCounter = 0; #endif // __CHART_TWO_MATRIX_LOADING_TYPE_ENUM_DECLARE__ } // namespace #endif //__CHART_TWO_MATRIX_LOADING_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Charting/ChartTwoMatrixTriangularViewingModeEnum.cxx000066400000000000000000000276301360521144700306510ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CHART_TWO_MATRIX_TRIANGULAR_VIEWING_MODE_ENUM_DECLARE__ #include "ChartTwoMatrixTriangularViewingModeEnum.h" #undef __CHART_TWO_MATRIX_TRIANGULAR_VIEWING_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartTwoMatrixTriangularViewingModeEnum * \brief Types of viewing for matrix. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_matrixViewingTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void matrixViewingTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ChartTwoMatrixTriangularViewingModeEnum.h" * * Instatiate: * m_matrixViewingTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_matrixViewingTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_matrixViewingTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(matrixViewingTypeEnumComboBoxItemActivated())); * * Update the selection: * m_matrixViewingTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ChartTwoMatrixTriangularViewingModeEnum::Enum VARIABLE = m_matrixViewingTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ChartTwoMatrixTriangularViewingModeEnum::ChartTwoMatrixTriangularViewingModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ChartTwoMatrixTriangularViewingModeEnum::~ChartTwoMatrixTriangularViewingModeEnum() { } /** * Initialize the enumerated metadata. */ void ChartTwoMatrixTriangularViewingModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ChartTwoMatrixTriangularViewingModeEnum(MATRIX_VIEW_FULL, "MATRIX_VIEW_FULL", "Full")); enumData.push_back(ChartTwoMatrixTriangularViewingModeEnum(MATRIX_VIEW_FULL_NO_DIAGONAL, "MATRIX_VIEW_FULL_NO_DIAGONAL", "Full No Diagonal")); enumData.push_back(ChartTwoMatrixTriangularViewingModeEnum(MATRIX_VIEW_LOWER_NO_DIAGONAL, "MATRIX_VIEW_LOWER_NO_DIAGONAL", "Lower No Diagonal")); enumData.push_back(ChartTwoMatrixTriangularViewingModeEnum(MATRIX_VIEW_UPPER_NO_DIAGONAL, "MATRIX_VIEW_UPPER_NO_DIAGONAL", "Upper No Diagonal")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ChartTwoMatrixTriangularViewingModeEnum* ChartTwoMatrixTriangularViewingModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ChartTwoMatrixTriangularViewingModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartTwoMatrixTriangularViewingModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoMatrixTriangularViewingModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartTwoMatrixTriangularViewingModeEnum::Enum ChartTwoMatrixTriangularViewingModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoMatrixTriangularViewingModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoMatrixTriangularViewingModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartTwoMatrixTriangularViewingModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartTwoMatrixTriangularViewingModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoMatrixTriangularViewingModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartTwoMatrixTriangularViewingModeEnum::Enum ChartTwoMatrixTriangularViewingModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoMatrixTriangularViewingModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoMatrixTriangularViewingModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartTwoMatrixTriangularViewingModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ChartTwoMatrixTriangularViewingModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoMatrixTriangularViewingModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ChartTwoMatrixTriangularViewingModeEnum::Enum ChartTwoMatrixTriangularViewingModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoMatrixTriangularViewingModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoMatrixTriangularViewingModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartTwoMatrixTriangularViewingModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ChartTwoMatrixTriangularViewingModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartTwoMatrixTriangularViewingModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ChartTwoMatrixTriangularViewingModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartTwoMatrixTriangularViewingModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ChartTwoMatrixTriangularViewingModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Charting/ChartTwoMatrixTriangularViewingModeEnum.h000066400000000000000000000071721360521144700302750ustar00rootroot00000000000000#ifndef __CHART_TWO_MATRIX_TRIANGULAR_VIEWING_MODE_ENUM_H__ #define __CHART_TWO_MATRIX_TRIANGULAR_VIEWING_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ChartTwoMatrixTriangularViewingModeEnum { public: /** * Enumerated values. */ enum Enum { /** View the full matrix */ MATRIX_VIEW_FULL, /** View the full matrix but hide the diagonal */ MATRIX_VIEW_FULL_NO_DIAGONAL, /** View the lower half of the matrix but hide the diagonal */ MATRIX_VIEW_LOWER_NO_DIAGONAL, /** View the upper half of the matrix but hide the diagonal */ MATRIX_VIEW_UPPER_NO_DIAGONAL }; ~ChartTwoMatrixTriangularViewingModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ChartTwoMatrixTriangularViewingModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ChartTwoMatrixTriangularViewingModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __CHART_TWO_MATRIX_TRIANGULAR_VIEWING_MODE_ENUM_DECLARE__ std::vector ChartTwoMatrixTriangularViewingModeEnum::enumData; bool ChartTwoMatrixTriangularViewingModeEnum::initializedFlag = false; int32_t ChartTwoMatrixTriangularViewingModeEnum::integerCodeCounter = 0; #endif // __CHART_TWO_MATRIX_TRIANGULAR_VIEWING_MODE_ENUM_DECLARE__ } // namespace #endif //__CHART_TWO_MATRIX_TRIANGULAR_VIEWING_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Charting/ChartTwoNumericSubdivisionsModeEnum.cxx000066400000000000000000000264451360521144700300320ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CHART_TWO_NUMERIC_SUBDIVISIONS_MODE_ENUM_DECLARE__ #include "ChartTwoNumericSubdivisionsModeEnum.h" #undef __CHART_TWO_NUMERIC_SUBDIVISIONS_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartTwoNumericSubdivisionsModeEnum * \brief Enumerated type for charting numeric subdivisions * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_chartTwoNumericSubdivisionsModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void chartTwoNumericSubdivisionsModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ChartTwoNumericSubdivisionsModeEnum.h" * * Instatiate: * m_chartTwoNumericSubdivisionsModeEnumComboBox = new EnumComboBoxTemplate(this); * m_chartTwoNumericSubdivisionsModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_chartTwoNumericSubdivisionsModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(chartTwoNumericSubdivisionsModeEnumComboBoxItemActivated())); * * Update the selection: * m_chartTwoNumericSubdivisionsModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ChartTwoNumericSubdivisionsModeEnum::Enum VARIABLE = m_chartTwoNumericSubdivisionsModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ChartTwoNumericSubdivisionsModeEnum::ChartTwoNumericSubdivisionsModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ChartTwoNumericSubdivisionsModeEnum::~ChartTwoNumericSubdivisionsModeEnum() { } /** * Initialize the enumerated metadata. */ void ChartTwoNumericSubdivisionsModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ChartTwoNumericSubdivisionsModeEnum(AUTO, "AUTO", "Auto")); enumData.push_back(ChartTwoNumericSubdivisionsModeEnum(USER, "USER", "User")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ChartTwoNumericSubdivisionsModeEnum* ChartTwoNumericSubdivisionsModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ChartTwoNumericSubdivisionsModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartTwoNumericSubdivisionsModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoNumericSubdivisionsModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartTwoNumericSubdivisionsModeEnum::Enum ChartTwoNumericSubdivisionsModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoNumericSubdivisionsModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoNumericSubdivisionsModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartTwoNumericSubdivisionsModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartTwoNumericSubdivisionsModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoNumericSubdivisionsModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartTwoNumericSubdivisionsModeEnum::Enum ChartTwoNumericSubdivisionsModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoNumericSubdivisionsModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoNumericSubdivisionsModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartTwoNumericSubdivisionsModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ChartTwoNumericSubdivisionsModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartTwoNumericSubdivisionsModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ChartTwoNumericSubdivisionsModeEnum::Enum ChartTwoNumericSubdivisionsModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartTwoNumericSubdivisionsModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartTwoNumericSubdivisionsModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartTwoNumericSubdivisionsModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ChartTwoNumericSubdivisionsModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartTwoNumericSubdivisionsModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ChartTwoNumericSubdivisionsModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartTwoNumericSubdivisionsModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ChartTwoNumericSubdivisionsModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Charting/ChartTwoNumericSubdivisionsModeEnum.h000066400000000000000000000064421360521144700274520ustar00rootroot00000000000000#ifndef __CHART_TWO_NUMERIC_SUBDIVISIONS_MODE_ENUM_H__ #define __CHART_TWO_NUMERIC_SUBDIVISIONS_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ChartTwoNumericSubdivisionsModeEnum { public: /** * Enumerated values. */ enum Enum { /** Automatic */ AUTO, /** User-defined subdivisions */ USER }; ~ChartTwoNumericSubdivisionsModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ChartTwoNumericSubdivisionsModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ChartTwoNumericSubdivisionsModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __CHART_TWO_NUMERIC_SUBDIVISIONS_MODE_ENUM_DECLARE__ std::vector ChartTwoNumericSubdivisionsModeEnum::enumData; bool ChartTwoNumericSubdivisionsModeEnum::initializedFlag = false; int32_t ChartTwoNumericSubdivisionsModeEnum::integerCodeCounter = 0; #endif // __CHART_TWO_NUMERIC_SUBDIVISIONS_MODE_ENUM_DECLARE__ } // namespace #endif //__CHART_TWO_NUMERIC_SUBDIVISIONS_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Charting/ChartTwoTitle.cxx000066400000000000000000000140321360521144700234420ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_TWO_TITLE_DECLARE__ #include "ChartTwoTitle.h" #undef __CHART_TWO_TITLE_DECLARE__ #include "CaretAssert.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ChartTwoTitle * \brief Title and its attributes for charts. * \ingroup Charting */ /** * Constructor. */ ChartTwoTitle::ChartTwoTitle() : CaretObjectTracksModification() { m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); reset(); m_sceneAssistant->add("m_displayed", &m_displayed); m_sceneAssistant->add("m_paddingSize", &m_paddingSize); m_sceneAssistant->add("m_text", &m_text); m_sceneAssistant->add("m_textSize", &m_textSize); } /** * Destructor. */ ChartTwoTitle::~ChartTwoTitle() { } /** * Copy constructor. * @param obj * Object that is copied. */ ChartTwoTitle::ChartTwoTitle(const ChartTwoTitle& obj) : CaretObjectTracksModification(obj), SceneableInterface(obj) { this->copyHelperChartTwoTitle(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ChartTwoTitle& ChartTwoTitle::operator=(const ChartTwoTitle& obj) { if (this != &obj) { CaretObjectTracksModification::operator=(obj); this->copyHelperChartTwoTitle(obj); } return *this; } /** * Reset this instance to its default values. */ void ChartTwoTitle::reset() { m_displayed = false; m_paddingSize = 1.0f; m_text = ""; m_textSize = 5.0f; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ChartTwoTitle::copyHelperChartTwoTitle(const ChartTwoTitle& obj) { m_displayed = obj.m_displayed; m_paddingSize = obj.m_paddingSize; m_text = obj.m_text; m_textSize = obj.m_textSize; } /** * @return Padding between title and edge of viewport */ float ChartTwoTitle::getPaddingSize() const { return m_paddingSize; } /** * Set Padding between title and edge of viewport * * @param paddingSize * New value for Padding between title and edge of viewport */ void ChartTwoTitle::setPaddingSize(const float paddingSize) { if (paddingSize != m_paddingSize) { m_paddingSize = paddingSize; setModified(); } } /** * @return Size of title characters when drawing */ float ChartTwoTitle::getTextSize() const { return m_textSize; } /** * Set Size of title characters when drawing * * @param textSize * New value for Size of title characters when drawing */ void ChartTwoTitle::setTextSize(const float textSize) { if (textSize != m_textSize) { m_textSize = textSize; setModified(); } } /** * @return text displayed as title */ AString ChartTwoTitle::getText() const { return m_text; } /** * Set text displayed as title * * @param text * New value for text displayed as title */ void ChartTwoTitle::setText(const AString& text) { if (text != m_text) { m_text = text; setModified(); } } /** * @return display status of title */ bool ChartTwoTitle::isDisplayed() const { return m_displayed; } /** * Set display status of title * * @param displayed * New value for display status of title */ void ChartTwoTitle::setDisplayed(const bool displayed) { if (displayed != m_displayed) { m_displayed = displayed; setModified(); } } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* ChartTwoTitle::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ChartTwoTitle", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ChartTwoTitle::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Charting/ChartTwoTitle.h000066400000000000000000000065351360521144700231000ustar00rootroot00000000000000#ifndef __CHART_TWO_TITLE_H__ #define __CHART_TWO_TITLE_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObjectTracksModification.h" #include "SceneableInterface.h" namespace caret { class SceneClassAssistant; class ChartTwoTitle : public CaretObjectTracksModification, public SceneableInterface { public: ChartTwoTitle(); virtual ~ChartTwoTitle(); ChartTwoTitle(const ChartTwoTitle& obj); ChartTwoTitle& operator=(const ChartTwoTitle& obj); float getPaddingSize() const; void setPaddingSize(const float paddingSize); float getTextSize() const; void setTextSize(const float textSize); AString getText() const; void setText(const AString& text); bool isDisplayed() const; void setDisplayed(const bool displayed); void reset(); // ADD_NEW_METHODS_HERE virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implementation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: void copyHelperChartTwoTitle(const ChartTwoTitle& obj); std::unique_ptr m_sceneAssistant; /** Padding between title and edge of viewport*/ float m_paddingSize; /** Size of title characters when drawing*/ float m_textSize; /** text displayed as title*/ AString m_text; /** display status of title*/ bool m_displayed; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHART_TWO_TITLE_DECLARE__ // #endif // __CHART_TWO_TITLE_DECLARE__ } // namespace #endif //__CHART_TWO_TITLE_H__ connectome-workbench-1.4.2/src/Charting/ChartingVersionEnum.cxx000066400000000000000000000246521360521144700246500ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CHARTING_VERSION_ENUM_DECLARE__ #include "ChartingVersionEnum.h" #undef __CHARTING_VERSION_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ChartingVersionEnum * \brief Version of Charting Implementation * * * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_chartingVersionEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void chartingVersionEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ChartingVersionEnum.h" * * Instatiate: * m_chartingVersionEnumComboBox = new EnumComboBoxTemplate(this); * m_chartingVersionEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_chartingVersionEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(chartingVersionEnumComboBoxItemActivated())); * * Update the selection: * m_chartingVersionEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ChartingVersionEnum::Enum VARIABLE = m_chartingVersionEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ChartingVersionEnum::ChartingVersionEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ChartingVersionEnum::~ChartingVersionEnum() { } /** * Initialize the enumerated metadata. */ void ChartingVersionEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ChartingVersionEnum(CHARTING_VERSION_ONE, "CHARTING_VERSION_ONE", "Charting Version One")); enumData.push_back(ChartingVersionEnum(CHARTING_VERSION_TWO, "CHARTING_VERSION_TWO", "Charting Version Two")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ChartingVersionEnum* ChartingVersionEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ChartingVersionEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartingVersionEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartingVersionEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartingVersionEnum::Enum ChartingVersionEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartingVersionEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartingVersionEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ChartingVersionEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ChartingVersionEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartingVersionEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ChartingVersionEnum::Enum ChartingVersionEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartingVersionEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartingVersionEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ChartingVersionEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ChartingVersionEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ChartingVersionEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ChartingVersionEnum::Enum ChartingVersionEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ChartingVersionEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ChartingVersionEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ChartingVersionEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ChartingVersionEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartingVersionEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ChartingVersionEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ChartingVersionEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ChartingVersionEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Charting/ChartingVersionEnum.h000066400000000000000000000060571360521144700242740ustar00rootroot00000000000000#ifndef __CHARTING_VERSION_ENUM_H__ #define __CHARTING_VERSION_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ChartingVersionEnum { public: /** * Enumerated values. */ enum Enum { /** */ CHARTING_VERSION_ONE, /** */ CHARTING_VERSION_TWO }; ~ChartingVersionEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ChartingVersionEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ChartingVersionEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __CHARTING_VERSION_ENUM_DECLARE__ std::vector ChartingVersionEnum::enumData; bool ChartingVersionEnum::initializedFlag = false; int32_t ChartingVersionEnum::integerCodeCounter = 0; #endif // __CHARTING_VERSION_ENUM_DECLARE__ } // namespace #endif //__CHARTING_VERSION_ENUM_H__ connectome-workbench-1.4.2/src/Charting/EventChartTwoAttributesChanged.cxx000066400000000000000000000130131360521144700267610ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_CHART_TWO_ATTRIBUTES_CHANGED_DECLARE__ #include "EventChartTwoAttributesChanged.h" #undef __EVENT_CHART_TWO_ATTRIBUTES_CHANGED_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventChartTwoAttributesChanged * \brief Event for change in chart two attributes * \ingroup Charting */ /** * Constructor. */ EventChartTwoAttributesChanged::EventChartTwoAttributesChanged() : Event(EventTypeEnum::EVENT_CHART_TWO_ATTRIBUTES_CHANGED) { } /** * Destructor. */ EventChartTwoAttributesChanged::~EventChartTwoAttributesChanged() { } /** * @return The mode. */ EventChartTwoAttributesChanged::Mode EventChartTwoAttributesChanged::getMode() const { return m_mode; } /** * Set for a change in a cartesian axis. * * @param yokingGroup * Selected yoking group. * @param chartTwoDataType * Type of chart. * @param cartesianAxis * Cartesian axis that is changed. */ void EventChartTwoAttributesChanged::setCartesianAxisChanged(const YokingGroupEnum::Enum yokingGroup, const ChartTwoDataTypeEnum::Enum chartTwoDataType, const ChartTwoCartesianAxis* cartesianAxis) { CaretAssert(cartesianAxis); m_mode = Mode::CARTESIAN_AXIS; m_yokingGroup = yokingGroup; m_chartTwoDataType = chartTwoDataType; m_cartesianAxis = const_cast(cartesianAxis); } /** * Get for a change in a cartesian axis. * * @param yokingGroupOut * Selected yoking group. * @param chartTwoDataTypeOut * Type of chart. * @param cartesianAxisOut * Cartesian axis that is changed. */ void EventChartTwoAttributesChanged::getCartesianAxisChanged(YokingGroupEnum::Enum &yokingGroupOut, ChartTwoDataTypeEnum::Enum &chartTwoDataTypeOut, ChartTwoCartesianAxis* &cartesianAxisOut) const { CaretAssert(m_mode == Mode::CARTESIAN_AXIS); yokingGroupOut = m_yokingGroup; chartTwoDataTypeOut = m_chartTwoDataType; cartesianAxisOut = m_cartesianAxis; } /** * Set for a change in line thickness. * * @param yokingGroup * Selected yoking group. * @param chartTwoDataType * Type of chart. * @param lineThickness * New line thickness */ void EventChartTwoAttributesChanged::setLineThicknessChanged(const YokingGroupEnum::Enum yokingGroup, const ChartTwoDataTypeEnum::Enum chartTwoDataType, const float lineThickness) { m_mode = Mode::LINE_THICKESS; m_yokingGroup = yokingGroup; m_chartTwoDataType = chartTwoDataType; m_lineThickness = lineThickness; } /** * Get for a change in line thickness * * @param yokingGroupOut * Selected yoking group. * @param chartTwoDataTypeOut * Type of chart. * @param lineThicknessOut * Output line thickness */ void EventChartTwoAttributesChanged::getLineThicknessChanged(YokingGroupEnum::Enum &yokingGroupOut, ChartTwoDataTypeEnum::Enum &chartTwoDataTypeOut, float& lineThicknessOut) const { CaretAssert(m_mode == Mode::LINE_THICKESS); yokingGroupOut = m_yokingGroup; chartTwoDataTypeOut = m_chartTwoDataType; lineThicknessOut = m_lineThickness; } /** * Set for a change in a title. * * @param yokingGroup * Selected yoking group. * @param chartTwoDataType * Type of chart. * @parm chartTitle * Chart title. */ void EventChartTwoAttributesChanged::setTitleChanged(const YokingGroupEnum::Enum yokingGroup, const ChartTwoDataTypeEnum::Enum chartTwoDataType, const ChartTwoTitle* chartTitle) { CaretAssert(chartTitle); m_mode = Mode::TITLE; m_yokingGroup = yokingGroup; m_chartTwoDataType = chartTwoDataType; m_chartTitle = const_cast(chartTitle); } /** * Get for a change in title. * * @param yokingGroupOut * Selected yoking group. * @param chartTwoDataTypeOut * Type of chart. * @parm chartTitleOut * Chart title. */ void EventChartTwoAttributesChanged::getTitleChanged(YokingGroupEnum::Enum &yokingGroupOut, ChartTwoDataTypeEnum::Enum &chartTwoDataTypeOut, ChartTwoTitle* &chartTitleOut) const { CaretAssert(m_mode == Mode::TITLE); yokingGroupOut = m_yokingGroup; chartTwoDataTypeOut = m_chartTwoDataType; chartTitleOut = m_chartTitle; } connectome-workbench-1.4.2/src/Charting/EventChartTwoAttributesChanged.h000066400000000000000000000073571360521144700264240ustar00rootroot00000000000000#ifndef __EVENT_CHART_TWO_ATTRIBUTES_CHANGED_H__ #define __EVENT_CHART_TWO_ATTRIBUTES_CHANGED_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "ChartTwoDataTypeEnum.h" #include "Event.h" #include "YokingGroupEnum.h" namespace caret { class ChartTwoCartesianAxis; class ChartTwoTitle; class EventChartTwoAttributesChanged : public Event { public: enum class Mode { INVALID, CARTESIAN_AXIS, LINE_THICKESS, TITLE }; EventChartTwoAttributesChanged(); ~EventChartTwoAttributesChanged(); Mode getMode() const; void setCartesianAxisChanged(const YokingGroupEnum::Enum yokingGroup, const ChartTwoDataTypeEnum::Enum chartTwoDataType, const ChartTwoCartesianAxis* cartesianAxis); void getCartesianAxisChanged(YokingGroupEnum::Enum &yokingGroupOut, ChartTwoDataTypeEnum::Enum &chartTwoDataTypeOut, ChartTwoCartesianAxis* &cartesianAxisOut) const; void setLineThicknessChanged(const YokingGroupEnum::Enum yokingGroup, const ChartTwoDataTypeEnum::Enum chartTwoDataType, const float lineThickness); void getLineThicknessChanged(YokingGroupEnum::Enum &yokingGroupOut, ChartTwoDataTypeEnum::Enum &chartTwoDataTypeOut, float& lineThicknessOut) const; void setTitleChanged(const YokingGroupEnum::Enum yokingGroup, const ChartTwoDataTypeEnum::Enum chartTwoDataType, const ChartTwoTitle* chartTitle); void getTitleChanged(YokingGroupEnum::Enum &yokingGroupOut, ChartTwoDataTypeEnum::Enum &chartTwoDataTypeOut, ChartTwoTitle* &chartTitleOut) const; // ADD_NEW_METHODS_HERE private: EventChartTwoAttributesChanged(const EventChartTwoAttributesChanged&); EventChartTwoAttributesChanged& operator=(const EventChartTwoAttributesChanged&); Mode m_mode = Mode::INVALID; YokingGroupEnum::Enum m_yokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; ChartTwoDataTypeEnum::Enum m_chartTwoDataType = ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID; ChartTwoCartesianAxis* m_cartesianAxis = NULL; ChartTwoTitle* m_chartTitle = NULL; float m_lineThickness = 1.0f; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_CHART_TWO_ATTRIBUTES_CHANGED_DECLARE__ // #endif // __EVENT_CHART_TWO_ATTRIBUTES_CHANGED_DECLARE__ } // namespace #endif //__EVENT_CHART_TWO_ATTRIBUTES_CHANGED_H__ connectome-workbench-1.4.2/src/Charting/EventChartTwoAxisGetDataRange.cxx000066400000000000000000000056411360521144700265040ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_CHART_TWO_AXIS_GET_DATA_RANGE_DECLARE__ #include "EventChartTwoAxisGetDataRange.h" #undef __EVENT_CHART_TWO_AXIS_GET_DATA_RANGE_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventChartTwoAxisGetDataRange * \brief Event to get the range of data for a chart two axis * \ingroup Charting */ /** * Constructor. */ EventChartTwoAxisGetDataRange::EventChartTwoAxisGetDataRange(const ChartTwoOverlaySet* chartOverlaySet, const ChartAxisLocationEnum::Enum chartAxisLocation) : Event(EventTypeEnum::EVENT_CHART_TWO_AXIS_GET_DATA_RANGE), m_chartOverlaySet(chartOverlaySet), m_chartAxisLocation(chartAxisLocation) { } /** * Destructor. */ EventChartTwoAxisGetDataRange::~EventChartTwoAxisGetDataRange() { } /** * @return The chart overlay set that contains the axis. */ const ChartTwoOverlaySet* EventChartTwoAxisGetDataRange::getChartOverlaySet() const { return m_chartOverlaySet; } /** * @return The location of the axis. */ ChartAxisLocationEnum::Enum EventChartTwoAxisGetDataRange::getChartAxisLocation() const { return m_chartAxisLocation; } /** * Get the minimum and maximum values. * * @param minimumValue * The minimum value. * @param maximumValue * The maximum value. * @return * True if the minimum and maximum are valid, else false. */ bool EventChartTwoAxisGetDataRange::getMinimumAndMaximumValues(float& minimumValue, float& maximumValue) const { minimumValue = m_minimumValue; maximumValue = m_maximumValue; return m_valuesValidFlag; } /** * Set the minimum and maximum values. * * @param minimumValue * The minimum value. * @param maximumValue * The maximum value. */ void EventChartTwoAxisGetDataRange::setMinimumAndMaximumValues(const float minimumValue, const float maximumValue) { m_minimumValue = minimumValue; m_maximumValue = maximumValue; m_valuesValidFlag = true; } connectome-workbench-1.4.2/src/Charting/EventChartTwoAxisGetDataRange.h000066400000000000000000000050121360521144700261210ustar00rootroot00000000000000#ifndef __EVENT_CHART_TWO_AXIS_GET_DATA_RANGE_H__ #define __EVENT_CHART_TWO_AXIS_GET_DATA_RANGE_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "ChartAxisLocationEnum.h" #include "Event.h" namespace caret { class ChartTwoOverlaySet; class EventChartTwoAxisGetDataRange : public Event { public: EventChartTwoAxisGetDataRange(const ChartTwoOverlaySet* chartOverlaySet, const ChartAxisLocationEnum::Enum chartAxisLocation); virtual ~EventChartTwoAxisGetDataRange(); const ChartTwoOverlaySet* getChartOverlaySet() const; ChartAxisLocationEnum::Enum getChartAxisLocation() const; bool getMinimumAndMaximumValues(float& minimumValue, float& maximumValue) const; void setMinimumAndMaximumValues(const float minimumValue, const float maximumValue); // ADD_NEW_METHODS_HERE private: EventChartTwoAxisGetDataRange(const EventChartTwoAxisGetDataRange&); EventChartTwoAxisGetDataRange& operator=(const EventChartTwoAxisGetDataRange&); const ChartTwoOverlaySet* m_chartOverlaySet; const ChartAxisLocationEnum::Enum m_chartAxisLocation; float m_minimumValue = 0.0f; float m_maximumValue = 0.0f; bool m_valuesValidFlag = false; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_CHART_TWO_AXIS_GET_DATA_RANGE_DECLARE__ // #endif // __EVENT_CHART_TWO_AXIS_GET_DATA_RANGE_DECLARE__ } // namespace #endif //__EVENT_CHART_TWO_AXIS_GET_DATA_RANGE_H__ connectome-workbench-1.4.2/src/Charting/EventChartTwoLoadLineSeriesData.cxx000066400000000000000000000042631360521144700270240ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA_DECLARE__ #include "EventChartTwoLoadLineSeriesData.h" #undef __EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventChartTwoLoadLineSeriesData * \brief Event for loading chart two line series data * \ingroup Charting */ /** * Constructor. * * @param validTabIndices * Indices of valid tabs. * @param mapFileDataSelector * Map file data selector that provides data selection criteria. */ EventChartTwoLoadLineSeriesData::EventChartTwoLoadLineSeriesData(const std::vector& validTabIndices, const MapFileDataSelector& mapFileDataSelector) : Event(EventTypeEnum::EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA), m_validTabIndices(validTabIndices), m_mapFileDataSelector(mapFileDataSelector) { } /** * Destructor. */ EventChartTwoLoadLineSeriesData::~EventChartTwoLoadLineSeriesData() { } /** * @return The valid tab indices. */ std::vector EventChartTwoLoadLineSeriesData::getValidTabIndices() const { return m_validTabIndices; } /** * @return Map file data selector that provides data selection criteria. */ MapFileDataSelector EventChartTwoLoadLineSeriesData::getMapFileDataSelector() const { return m_mapFileDataSelector; } connectome-workbench-1.4.2/src/Charting/EventChartTwoLoadLineSeriesData.h000066400000000000000000000044171360521144700264520ustar00rootroot00000000000000#ifndef __EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA_H__ #define __EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" #include "MapFileDataSelector.h" #include "StructureEnum.h" namespace caret { class EventChartTwoLoadLineSeriesData : public Event { public: EventChartTwoLoadLineSeriesData(const std::vector& validTabIndices, const MapFileDataSelector& mapFileDataSelector); // EventChartTwoLoadLineSeriesData(const std::vector& validTabIndices, // const MapFileDataSelector& mapFileDataSelector); virtual ~EventChartTwoLoadLineSeriesData(); MapFileDataSelector getMapFileDataSelector() const; std::vector getValidTabIndices() const; // ADD_NEW_METHODS_HERE private: EventChartTwoLoadLineSeriesData(const EventChartTwoLoadLineSeriesData&); EventChartTwoLoadLineSeriesData& operator=(const EventChartTwoLoadLineSeriesData&); const std::vector m_validTabIndices; MapFileDataSelector m_mapFileDataSelector; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA_DECLARE__ // #endif // __EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA_DECLARE__ } // namespace #endif //__EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA_H__ connectome-workbench-1.4.2/src/Charting/MapFileDataSelector.cxx000066400000000000000000000454011360521144700245210ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __MAP_FILE_DATA_SELECTOR_DECLARE__ #include "MapFileDataSelector.h" #undef __MAP_FILE_DATA_SELECTOR_DECLARE__ #include "CaretAssert.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::MapFileDataSelector * \brief Identifies data for selection in a map file * \ingroup Charting */ /** * Constructor. */ MapFileDataSelector::MapFileDataSelector() : CaretObject() { reset(); m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); m_sceneAssistant->add("m_surfaceNumberOfVertices", &m_surfaceNumberOfVertices); m_sceneAssistant->add("m_surfaceStructure", &m_surfaceStructure); m_sceneAssistant->add("m_surfaceVertexIndex", &m_surfaceVertexIndex); m_sceneAssistant->addArray("m_voxelXYZ", m_voxelXYZ, 3, 0.0f); m_sceneAssistant->add("m_columnIndex", &m_columnIndex); m_sceneAssistant->add("m_columnMapFileName", &m_columnMapFileName); m_sceneAssistant->add("m_rowIndex", &m_rowIndex); m_sceneAssistant->add("m_rowMapFileName", &m_rowMapFileName); } /** * Destructor. */ MapFileDataSelector::~MapFileDataSelector() { } /** * Copy constructor. * @param obj * Object that is copied. */ MapFileDataSelector::MapFileDataSelector(const MapFileDataSelector& obj) : CaretObject(obj), SceneableInterface(obj) { this->copyHelperMapFileDataSelector(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ MapFileDataSelector& MapFileDataSelector::operator=(const MapFileDataSelector& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperMapFileDataSelector(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void MapFileDataSelector::copyHelperMapFileDataSelector(const MapFileDataSelector& obj) { m_dataSelectionType = obj.m_dataSelectionType; m_surfaceNumberOfVertices = obj.m_surfaceNumberOfVertices; m_surfaceStructure = obj.m_surfaceStructure; m_surfaceVertexAverageIndices = obj.m_surfaceVertexAverageIndices; m_surfaceVertexIndex = obj.m_surfaceVertexIndex; m_voxelXYZ[0] = obj.m_voxelXYZ[0]; m_voxelXYZ[1] = obj.m_voxelXYZ[1]; m_voxelXYZ[2] = obj.m_voxelXYZ[2]; m_columnIndex = obj.m_columnIndex; m_columnMapFile = obj.m_columnMapFile; m_columnMapFileName = obj.m_columnMapFileName; m_rowIndex = obj.m_rowIndex; m_rowMapFile = obj.m_rowMapFile; m_rowMapFileName = obj.m_rowMapFileName; } /** * Equality operator. * * @param obj * Instance compared to 'this' instance. * * @return True if this and the compared instance are the same, else false. */ bool MapFileDataSelector::operator==(const MapFileDataSelector& obj) const { if (this == &obj) { return true; } if (m_dataSelectionType != obj.m_dataSelectionType) { return false; } switch (m_dataSelectionType) { case DataSelectionType::COLUMN_DATA: if (m_columnIndex == obj.m_columnIndex) { if ((m_columnMapFile == obj.m_columnMapFile) || (m_columnMapFileName == obj.m_columnMapFileName)) { return true; } } break; case DataSelectionType::INVALID: break; case DataSelectionType::ROW_DATA: if (m_rowIndex == obj.m_rowIndex) { if ((m_rowMapFile == obj.m_rowMapFile) || (m_rowMapFileName == obj.m_rowMapFileName)) { return true; } } break; case DataSelectionType::SURFACE_VERTEX: if ((m_surfaceNumberOfVertices == obj.m_surfaceNumberOfVertices) && (m_surfaceStructure == obj.m_surfaceStructure) && (m_surfaceVertexIndex == obj.m_surfaceVertexIndex)) { return true; } break; case DataSelectionType::SURFACE_VERTICES_AVERAGE: if ((m_surfaceNumberOfVertices == obj.m_surfaceNumberOfVertices) && (m_surfaceStructure == obj.m_surfaceStructure)) { if ( ! m_surfaceVertexAverageIndices.empty()) { if (std::equal(m_surfaceVertexAverageIndices.begin(), m_surfaceVertexAverageIndices.end(), obj.m_surfaceVertexAverageIndices.begin())) { return true; } } } break; case DataSelectionType::VOLUME_XYZ: if ((m_voxelXYZ[0] == obj.m_voxelXYZ[0]) && (m_voxelXYZ[1] == obj.m_voxelXYZ[1]) && (m_voxelXYZ[2] == obj.m_voxelXYZ[2])) { return true; } break; } return false; } /** * @return The data selection type. */ MapFileDataSelector::DataSelectionType MapFileDataSelector::getDataSelectionType() const { return m_dataSelectionType; } /** * @return Name of the data selection type. * * @param dataSelectionType * The data selection type. */ AString MapFileDataSelector::getDataSelectionTypeName(const DataSelectionType dataSelectionType) { AString dataSelectionTypeName; switch (dataSelectionType) { case DataSelectionType::INVALID: dataSelectionTypeName = "INVALID"; break; case DataSelectionType::COLUMN_DATA: dataSelectionTypeName = "COLUMN_DATA"; break; case DataSelectionType::ROW_DATA: dataSelectionTypeName = "ROW_DATA"; break; case DataSelectionType::SURFACE_VERTEX: dataSelectionTypeName = "SURFACE_VERTEX"; break; case DataSelectionType::SURFACE_VERTICES_AVERAGE: dataSelectionTypeName = "SURFACE_VERTICES_AVERAGE"; break; case DataSelectionType::VOLUME_XYZ: dataSelectionTypeName = "VOLUME_XYZ"; break; } CaretAssert( ! dataSelectionTypeName.isEmpty()); return dataSelectionTypeName; } /** * Get data for a surface vertex. * * @param surfaceStructure * The surface structure. * @param surfaceNumberOfVertices * Number of vertices in the surface. * @param surfaceVertexIndex * Index of the vertex. */ void MapFileDataSelector::getSurfaceVertex(StructureEnum::Enum& surfaceStructure, int32_t& surfaceNumberOfVertices, int32_t& surfaceVertexIndex) const { surfaceStructure = m_surfaceStructure; surfaceNumberOfVertices = m_surfaceNumberOfVertices; surfaceVertexIndex = m_surfaceVertexIndex; } /** * Set data for a surface vertex. * * @param surfaceStructure * The surface structure. * @param surfaceNumberOfVertices * Number of vertices in the surface. * @param surfaceVertexIndex * Index of the vertex. */ void MapFileDataSelector::setSurfaceVertex(const StructureEnum::Enum& surfaceStructure, const int32_t surfaceNumberOfVertices, const int32_t surfaceVertexIndex) { reset(); m_dataSelectionType = DataSelectionType::SURFACE_VERTEX; m_surfaceStructure = surfaceStructure; m_surfaceNumberOfVertices = surfaceNumberOfVertices; m_surfaceVertexIndex = surfaceVertexIndex; } /** * Get data for a surface vertex average. * * @param surfaceStructure * The surface structure. * @param surfaceNumberOfVertices * Number of vertices in the surface. * @param surfaceVertexAverageIndices * Indices of the vertex. */ void MapFileDataSelector::getSurfaceVertexAverage(StructureEnum::Enum& surfaceStructure, int32_t& surfaceNumberOfVertices, std::vector& surfaceVertexAverageIndices) const { surfaceStructure = m_surfaceStructure; surfaceNumberOfVertices = m_surfaceNumberOfVertices; surfaceVertexAverageIndices = m_surfaceVertexAverageIndices; } /** * Set data for a surface vertex average. * * @param surfaceStructure * The surface structure. * @param surfaceNumberOfVertices * Number of vertices in the surface. * @param surfaceVertexAverageIndices * Indices of the vertex. */ void MapFileDataSelector::setSurfaceVertexAverage(const StructureEnum::Enum& surfaceStructure, const int32_t surfaceNumberOfVertices, const std::vector& surfaceVertexAverageIndices) { reset(); m_dataSelectionType = DataSelectionType::SURFACE_VERTICES_AVERAGE; m_surfaceStructure = surfaceStructure; m_surfaceNumberOfVertices = surfaceNumberOfVertices; m_surfaceVertexAverageIndices = surfaceVertexAverageIndices; } /** * Get the stereotaxic coordinate of the volume voxel. * * @param voxelXYZ * The volume voxel XYZ. */ void MapFileDataSelector::getVolumeVoxelXYZ(float voxelXYZ[3]) const { voxelXYZ[0] = m_voxelXYZ[0]; voxelXYZ[1] = m_voxelXYZ[1]; voxelXYZ[2] = m_voxelXYZ[2]; } /** * Set the stereotaxic coordinate of the volume voxel. * * @param voxelXYZ * The volume voxel XYZ. */ void MapFileDataSelector::setVolumeVoxelXYZ(const float voxelXYZ[3]) { reset(); m_dataSelectionType = DataSelectionType::VOLUME_XYZ; m_voxelXYZ[0] = voxelXYZ[0]; m_voxelXYZ[1] = voxelXYZ[1]; m_voxelXYZ[2] = voxelXYZ[2]; } /** * Get the column index. * * @param columnMapFile * Data file for column loading. Could be an invalid pointer or NULL !!! * @param columnMapFileName * Name of column map file. * @param columnIndex * The column index. */ void MapFileDataSelector::getColumnIndex(CaretMappableDataFile* &columnMapFile, AString& columnMapFileName, int32_t &columnIndex) const { columnMapFile = m_columnMapFile; columnMapFileName = m_columnMapFileName; columnIndex = m_columnIndex; } /** * Set the column index. * * @param columnMapFile * Data file for column loading. * @param columnMapFileName * Name of column map file. * @param columnIndex * The column index. */ void MapFileDataSelector::setColumnIndex(CaretMappableDataFile* columnMapFile, const AString& columnMapFileName, const int32_t columnIndex) { reset(); m_dataSelectionType = DataSelectionType::COLUMN_DATA; m_columnMapFile = columnMapFile; m_columnMapFileName = columnMapFileName; m_columnIndex = columnIndex; } /** * Get the row index. * * @param rowMapFile * Data file for row loading. Could be an invalid pointer or NULL !!! * @param rowMapFileName * Name of row map file. * @param rowIndex * The row index. */ void MapFileDataSelector::getRowIndex(CaretMappableDataFile* &rowMapFile, AString& rowMapFileName, int32_t &rowIndex) const { rowIndex = m_rowIndex; rowMapFile = m_rowMapFile; rowMapFileName = m_rowMapFileName; } /** * Set the row index. * * @param rowMapFile * Data file for row loading. * @param rowMapFileName * Name of row map file. * @param rowIndex * The row index. */ void MapFileDataSelector::setRowIndex(CaretMappableDataFile* rowMapFile, const AString& rowMapFileName, const int32_t rowIndex) { reset(); m_dataSelectionType = DataSelectionType::ROW_DATA; m_rowMapFile = rowMapFile; m_rowMapFileName = rowMapFileName; m_rowIndex = rowIndex; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString MapFileDataSelector::toString() const { AString s; switch (m_dataSelectionType) { case DataSelectionType::INVALID: break; case DataSelectionType::COLUMN_DATA: s = ("Column " + AString::number(m_columnIndex + 1)); break; case DataSelectionType::ROW_DATA: s = ("Row " + AString::number(m_rowIndex + 1)); break; case DataSelectionType::SURFACE_VERTEX: s = ("Vertex " + StructureEnum::toGuiName(m_surfaceStructure) + " " + AString::number(m_surfaceVertexIndex + 1)); break; case DataSelectionType::SURFACE_VERTICES_AVERAGE: s = ("Vertex Average" + StructureEnum::toGuiName(m_surfaceStructure) + " count=" + AString::number(m_surfaceVertexAverageIndices.size())); break; case DataSelectionType::VOLUME_XYZ: s = ("Voxel " + AString::fromNumbers(m_voxelXYZ, 3, ",")); break; } return s; } /** * Reset to an invalid state. */ void MapFileDataSelector::reset() { m_dataSelectionType = DataSelectionType::INVALID; m_surfaceStructure = StructureEnum::INVALID; m_surfaceNumberOfVertices = -1; m_surfaceVertexIndex = -1; m_surfaceVertexAverageIndices.clear(); m_voxelXYZ[0] = 0.0f; m_voxelXYZ[1] = 0.0f; m_voxelXYZ[2] = 0.0f; m_columnIndex = -1; m_columnMapFile = NULL; m_columnMapFileName = ""; m_rowIndex = -1; m_rowMapFile = NULL; m_rowMapFileName = ""; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* MapFileDataSelector::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "MapFileDataSelector", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); sceneClass->addString("m_dataSelectionType", getDataSelectionTypeName(m_dataSelectionType)); const int32_t numVertices = static_cast(m_surfaceVertexAverageIndices.size()); if (numVertices > 0) { sceneClass->addIntegerArray("m_surfaceVertexAverageIndices", &m_surfaceVertexAverageIndices[0], numVertices); } // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void MapFileDataSelector::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } reset(); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); m_dataSelectionType = DataSelectionType::INVALID; const AString dataSelectionTypeName = sceneClass->getStringValue("m_dataSelectionType", "INVALID"); if (dataSelectionTypeName == getDataSelectionTypeName(DataSelectionType::INVALID)) { m_dataSelectionType = DataSelectionType::INVALID; } else if (dataSelectionTypeName == getDataSelectionTypeName(DataSelectionType::COLUMN_DATA)) { m_dataSelectionType = DataSelectionType::COLUMN_DATA; } else if (dataSelectionTypeName == getDataSelectionTypeName(DataSelectionType::ROW_DATA)) { m_dataSelectionType = DataSelectionType::ROW_DATA; } else if (dataSelectionTypeName == getDataSelectionTypeName(DataSelectionType::SURFACE_VERTEX)) { m_dataSelectionType = DataSelectionType::SURFACE_VERTEX; } else if (dataSelectionTypeName == getDataSelectionTypeName(DataSelectionType::SURFACE_VERTICES_AVERAGE)) { m_dataSelectionType = DataSelectionType::SURFACE_VERTICES_AVERAGE; } else if (dataSelectionTypeName ==getDataSelectionTypeName(DataSelectionType::VOLUME_XYZ)) { m_dataSelectionType = DataSelectionType::VOLUME_XYZ; } else { CaretAssertMessage(0, ("Invalid data selection type name \"" + dataSelectionTypeName + "\"")); } const SceneClassArray* vertexArray = sceneClass->getClassArray("m_surfaceVertexAverageIndices"); if (vertexArray != NULL) { const int32_t numVertices = vertexArray->getNumberOfArrayElements(); if (numVertices > 0) { m_surfaceVertexAverageIndices.resize(numVertices); sceneClass->getIntegerArrayValue("m_surfaceVertexAverageIndices", &m_surfaceVertexAverageIndices[0], numVertices); } } //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Charting/MapFileDataSelector.h000066400000000000000000000132601360521144700241440ustar00rootroot00000000000000#ifndef __MAP_FILE_DATA_SELECTOR_H__ #define __MAP_FILE_DATA_SELECTOR_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "SceneableInterface.h" #include "StructureEnum.h" namespace caret { class CaretMappableDataFile; class SceneClassAssistant; class MapFileDataSelector : public CaretObject, public SceneableInterface { public: enum class DataSelectionType { INVALID, COLUMN_DATA, ROW_DATA, SURFACE_VERTEX, SURFACE_VERTICES_AVERAGE, VOLUME_XYZ }; MapFileDataSelector(); virtual ~MapFileDataSelector(); MapFileDataSelector(const MapFileDataSelector& obj); MapFileDataSelector& operator=(const MapFileDataSelector& obj); bool operator==(const MapFileDataSelector& obj) const; DataSelectionType getDataSelectionType() const; static AString getDataSelectionTypeName(const DataSelectionType dataSelectionType); std::vector getValidTabIndices() const; void getSurfaceVertex(StructureEnum::Enum& surfaceStructure, int32_t& surfaceNumberOfVertices, int32_t& surfaceVertexIndex) const; void setSurfaceVertex(const StructureEnum::Enum& surfaceStructure, const int32_t surfaceNumberOfVertices, const int32_t surfaceVertexIndex); void getSurfaceVertexAverage(StructureEnum::Enum& surfaceStructure, int32_t& surfaceNumberOfVertices, std::vector& surfaceVertexIndices) const; void setSurfaceVertexAverage(const StructureEnum::Enum& surfaceStructure, const int32_t surfaceNumberOfVertices, const std::vector& surfaceVertexIndices); void getVolumeVoxelXYZ(float xyz[3]) const; void setVolumeVoxelXYZ(const float xyz[3]); void getColumnIndex(CaretMappableDataFile* &columnMapFile, AString& columnMapFileName, int32_t &columnIndex) const; void setColumnIndex(CaretMappableDataFile* columnMapFile, const AString& columnMapFileName, const int32_t columnIndex); void getRowIndex(CaretMappableDataFile* &rowMapFile, AString& rowMapFileName, int32_t &rowIndex) const; void setRowIndex(CaretMappableDataFile* rowMapFile, const AString& rowMapFileName, const int32_t rowIndex); void reset(); // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implementation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: void copyHelperMapFileDataSelector(const MapFileDataSelector& obj); std::unique_ptr m_sceneAssistant; DataSelectionType m_dataSelectionType = DataSelectionType::INVALID; int32_t m_surfaceNumberOfVertices = 0; StructureEnum::Enum m_surfaceStructure = StructureEnum::INVALID; std::vector m_surfaceVertexAverageIndices; int32_t m_surfaceVertexIndex = -1; float m_voxelXYZ[3]; int32_t m_columnIndex = -1; int32_t m_rowIndex = -1; CaretMappableDataFile* m_rowMapFile; CaretMappableDataFile* m_columnMapFile; AString m_rowMapFileName; AString m_columnMapFileName; // ADD_NEW_MEMBERS_HERE }; #ifdef __MAP_FILE_DATA_SELECTOR_DECLARE__ // #endif // __MAP_FILE_DATA_SELECTOR_DECLARE__ } // namespace #endif //__MAP_FILE_DATA_SELECTOR_H__ connectome-workbench-1.4.2/src/Cifti/000077500000000000000000000000001360521144700174605ustar00rootroot00000000000000connectome-workbench-1.4.2/src/Cifti/CMakeLists.txt000066400000000000000000000022021360521144700222140ustar00rootroot00000000000000 # # Name of Project # PROJECT (Cifti) # # Add QT for includes # if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) include_directories(${Qt5Network_INCLUDE_DIRS}) endif() IF (QT4_FOUND) SET(QT_DONT_USE_QTGUI) SET(QT_USE_QTNETWORK TRUE) INCLUDE(${QT_USE_FILE}) ENDIF () # # Create GIFTI Library # ADD_LIBRARY(Cifti CiftiInterface.h CiftiXMLOld.h CiftiXMLElements.h CiftiXMLReader.h CiftiXMLWriter.h CiftiFile.h CiftiXML.h CiftiMappingType.h CiftiBrainModelsMap.h CiftiLabelsMap.h CiftiParcelsMap.h CiftiScalarsMap.h CiftiSeriesMap.h CiftiVersion.h CiftiInterface.cxx CiftiXMLOld.cxx CiftiXMLElements.cxx CiftiXMLReader.cxx CiftiXMLWriter.cxx CiftiFile.cxx CiftiXML.cxx CiftiMappingType.cxx CiftiBrainModelsMap.cxx CiftiLabelsMap.cxx CiftiParcelsMap.cxx CiftiScalarsMap.cxx CiftiSeriesMap.cxx CiftiVersion.cxx ) TARGET_LINK_LIBRARIES(Cifti ${CARET_QT5_LINK}) # # Find Headers # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Annotations ${CMAKE_SOURCE_DIR}/FilesBase ${CMAKE_SOURCE_DIR}/Cifti ${CMAKE_SOURCE_DIR}/Palette ${CMAKE_SOURCE_DIR}/Gifti ${CMAKE_SOURCE_DIR}/Nifti ${CMAKE_SOURCE_DIR}/Xml ${CMAKE_SOURCE_DIR}/Common ) connectome-workbench-1.4.2/src/Cifti/CiftiBrainModelsMap.cxx000066400000000000000000001161771360521144700240350ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiBrainModelsMap.h" #include "DataFileException.h" #include #include using namespace std; using namespace caret; void CiftiBrainModelsMap::addSurfaceModel(const int64_t& numberOfNodes, const StructureEnum::Enum& structure, const float* roi) { vector tempVector;//pass-through to the other addSurfaceModel after converting roi to vector of indices tempVector.reserve(numberOfNodes);//to make it allocate only once for (int64_t i = 0; i < numberOfNodes; ++i) { if (roi == NULL || roi[i] > 0.0f) { tempVector.push_back(i); } } addSurfaceModel(numberOfNodes, structure, tempVector); } void CiftiBrainModelsMap::addSurfaceModel(const int64_t& numberOfNodes, const StructureEnum::Enum& structure, const vector& nodeList) { if (m_surfUsed.find(structure) != m_surfUsed.end()) { throw DataFileException("surface structures cannot be repeated in a brain models map"); } BrainModelPriv myModel; myModel.m_type = SURFACE; myModel.m_brainStructure = structure; myModel.m_surfaceNumberOfNodes = numberOfNodes; myModel.m_nodeIndices = nodeList; myModel.setupSurface(getNextStart());//do internal setup - also does error checking m_modelsInfo.push_back(myModel); m_surfUsed[structure] = m_modelsInfo.size() - 1; } void CiftiBrainModelsMap::BrainModelPriv::setupSurface(const int64_t& start) { if (m_surfaceNumberOfNodes < 1) { throw DataFileException("surface must have at least 1 vertex"); } m_modelStart = start; int64_t listSize = (int64_t)m_nodeIndices.size(); if (listSize == 0) { throw DataFileException("vertex list must have nonzero length");//NOTE: technically not required by Cifti-1, remove if problematic } m_modelEnd = start + listSize;//one after last vector used(m_surfaceNumberOfNodes, false); m_nodeToIndexLookup = vector(m_surfaceNumberOfNodes, -1);//reset all to -1 to start for (int64_t i = 0; i < listSize; ++i) { if (m_nodeIndices[i] < 0) { throw DataFileException("vertex list contains negative index"); } if (m_nodeIndices[i] >= m_surfaceNumberOfNodes) { throw DataFileException("vertex list contains an index that don't exist in the surface"); } if (used[m_nodeIndices[i]]) { throw DataFileException("vertex list contains reused index"); } used[m_nodeIndices[i]] = true; m_nodeToIndexLookup[m_nodeIndices[i]] = start + i; } } void CiftiBrainModelsMap::addVolumeModel(const StructureEnum::Enum& structure, const vector& ijkList) { if (m_volUsed.find(structure) != m_volUsed.end()) { throw DataFileException("volume structures cannot be repeated in a brain models map"); } int64_t listSize = (int64_t)ijkList.size(); if (listSize == 0) { throw DataFileException("voxel list must have nonzero length");//NOTE: technically not required by Cifti-1, remove if problematic } if (listSize % 3 != 0) { throw DataFileException("voxel list must have a length that is a multiple of 3"); } int64_t numElems = listSize / 3; const int64_t* dims = NULL; if (!m_ignoreVolSpace) { if (!m_haveVolumeSpace) { throw DataFileException("you must set the volume space before adding volume models"); } dims = m_volSpace.getDims(); } CaretCompact3DLookup > tempLookup = m_voxelToIndexLookup;//a copy of the lookup should be faster than other methods of checking for overlap and repeat int64_t nextStart = getNextStart(); for (int64_t index = 0; index < numElems; ++index)//do all error checking before adding to lookup { int64_t index3 = index * 3; if (ijkList[index3] < 0 || ijkList[index3 + 1] < 0 || ijkList[index3 + 2] < 0) { throw DataFileException("found negative index in voxel list"); } if (!m_ignoreVolSpace && (ijkList[index3] >= dims[0] || ijkList[index3 + 1] >= dims[1] || ijkList[index3 + 2] >= dims[2])) { throw DataFileException("found invalid index triple in voxel list: (" + AString::number(ijkList[index3]) + ", " + AString::number(ijkList[index3 + 1]) + ", " + AString::number(ijkList[index3 + 2]) + ")"); } if (tempLookup.find(ijkList[index3], ijkList[index3 + 1], ijkList[index3 + 2]) != NULL) { throw DataFileException("volume models may not reuse voxels, either internally or from other structures"); } tempLookup.at(ijkList[index3], ijkList[index3 + 1], ijkList[index3 + 2]) = pair(nextStart + index, structure); } m_voxelToIndexLookup = tempLookup; BrainModelPriv myModel; myModel.m_type = VOXELS; myModel.m_brainStructure = structure; myModel.m_voxelIndicesIJK = ijkList; myModel.m_modelStart = nextStart; myModel.m_modelEnd = nextStart + numElems;//one after last m_modelsInfo.push_back(myModel); m_volUsed[structure] = m_modelsInfo.size() - 1; } void CiftiBrainModelsMap::clear() { m_modelsInfo.clear(); m_haveVolumeSpace = false; m_ignoreVolSpace = false; m_voxelToIndexLookup.clear(); m_surfUsed.clear(); m_volUsed.clear(); } int64_t CiftiBrainModelsMap::getIndexForNode(const int64_t& node, const StructureEnum::Enum& structure) const { CaretAssert(node >= 0); map::const_iterator iter = m_surfUsed.find(structure); if (iter == m_surfUsed.end()) { return -1; } CaretAssertVectorIndex(m_modelsInfo, iter->second); const BrainModelPriv& myModel = m_modelsInfo[iter->second]; if (node >= myModel.m_surfaceNumberOfNodes) return -1; CaretAssertVectorIndex(myModel.m_nodeToIndexLookup, node); return myModel.m_nodeToIndexLookup[node]; } int64_t CiftiBrainModelsMap::getIndexForVoxel(const int64_t* ijk, StructureEnum::Enum* structureOut) const { return getIndexForVoxel(ijk[0], ijk[1], ijk[2], structureOut); } int64_t CiftiBrainModelsMap::getIndexForVoxel(const int64_t& i, const int64_t& j, const int64_t& k, StructureEnum::Enum* structureOut) const { const pair* iter = m_voxelToIndexLookup.find(i, j, k);//the lookup tolerates weirdness like negatives if (iter == NULL) return -1; if (structureOut != NULL) *structureOut = iter->second; return iter->first; } CiftiBrainModelsMap::IndexInfo CiftiBrainModelsMap::getInfoForIndex(const int64_t index) const { CaretAssert(index >= 0 && index < getLength()); IndexInfo ret; int numModels = (int)m_modelsInfo.size(); int low = 0, high = numModels - 1;//bisection search while (low != high) { int guess = (low + high) / 2; if (m_modelsInfo[guess].m_modelEnd > index)//modelEnd is 1 after last valid index, equal to next start if there is a next { if (m_modelsInfo[guess].m_modelStart > index) { high = guess - 1; } else { high = guess; low = guess; } } else { low = guess + 1; } } CaretAssert(index >= m_modelsInfo[low].m_modelStart && index < m_modelsInfo[low].m_modelEnd);//otherwise we have a broken invariant ret.m_structure = m_modelsInfo[low].m_brainStructure; ret.m_type = m_modelsInfo[low].m_type; if (ret.m_type == SURFACE) { ret.m_surfaceNode = m_modelsInfo[low].m_nodeIndices[index - m_modelsInfo[low].m_modelStart]; } else { int64_t baseIndex = 3 * (index - m_modelsInfo[low].m_modelStart); ret.m_ijk[0] = m_modelsInfo[low].m_voxelIndicesIJK[baseIndex]; ret.m_ijk[1] = m_modelsInfo[low].m_voxelIndicesIJK[baseIndex + 1]; ret.m_ijk[2] = m_modelsInfo[low].m_voxelIndicesIJK[baseIndex + 2]; } return ret; } int64_t CiftiBrainModelsMap::getLength() const { return getNextStart(); } vector CiftiBrainModelsMap::getModelInfo() const { vector ret; int numModels = (int)m_modelsInfo.size(); ret.resize(numModels); for (int i = 0; i < numModels; ++i) { ret[i].m_structure = m_modelsInfo[i].m_brainStructure; ret[i].m_type = m_modelsInfo[i].m_type; ret[i].m_indexStart = m_modelsInfo[i].m_modelStart; ret[i].m_indexCount = m_modelsInfo[i].m_modelEnd - m_modelsInfo[i].m_modelStart; } return ret; } int64_t CiftiBrainModelsMap::getNextStart() const { if (m_modelsInfo.size() == 0) return 0; return m_modelsInfo.back().m_modelEnd;//NOTE: the models are sorted by their index range, so this works } const vector& CiftiBrainModelsMap::getNodeList(const StructureEnum::Enum& structure) const { map::const_iterator iter = m_surfUsed.find(structure); if (iter == m_surfUsed.end()) { throw DataFileException("getNodeList called for nonexistant structure");//throw if it doesn't exist, because we don't have a reference to return - things should identify which structures exist before calling this } CaretAssertVectorIndex(m_modelsInfo, iter->second); return m_modelsInfo[iter->second].m_nodeIndices; } vector CiftiBrainModelsMap::getSurfaceMap(const StructureEnum::Enum& structure) const { vector ret; map::const_iterator iter = m_surfUsed.find(structure); if (iter == m_surfUsed.end()) { throw DataFileException("getSurfaceMap called for nonexistant structure");//also throw, for consistency } CaretAssertVectorIndex(m_modelsInfo, iter->second); const BrainModelPriv& myModel = m_modelsInfo[iter->second]; int64_t numUsed = (int64_t)myModel.m_nodeIndices.size(); ret.resize(numUsed); for (int64_t i = 0; i < numUsed; ++i) { ret[i].m_ciftiIndex = myModel.m_modelStart + i; ret[i].m_surfaceNode = myModel.m_nodeIndices[i]; } return ret; } int64_t CiftiBrainModelsMap::getSurfaceNumberOfNodes(const StructureEnum::Enum& structure) const { map::const_iterator iter = m_surfUsed.find(structure); if (iter == m_surfUsed.end()) { return -1; } CaretAssertVectorIndex(m_modelsInfo, iter->second); const BrainModelPriv& myModel = m_modelsInfo[iter->second]; return myModel.m_surfaceNumberOfNodes; } vector CiftiBrainModelsMap::getSurfaceStructureList() const { vector ret; ret.reserve(m_surfUsed.size());//we can use this to tell us how many there are, but it has reordered them int numModels = (int)m_modelsInfo.size(); for (int i = 0; i < numModels; ++i)//we need them in the order they occur in { if (m_modelsInfo[i].m_type == SURFACE) { ret.push_back(m_modelsInfo[i].m_brainStructure); } } return ret; } bool CiftiBrainModelsMap::hasSurfaceData(const StructureEnum::Enum& structure) const { map::const_iterator iter = m_surfUsed.find(structure); return (iter != m_surfUsed.end()); } vector CiftiBrainModelsMap::getFullVolumeMap() const { vector ret; int numModels = (int)m_modelsInfo.size(); for (int i = 0; i < numModels; ++i) { if (m_modelsInfo[i].m_type == VOXELS) { const BrainModelPriv& myModel = m_modelsInfo[i]; int64_t listSize = (int64_t)myModel.m_voxelIndicesIJK.size(); CaretAssert(listSize % 3 == 0); int64_t numUsed = listSize / 3; if (ret.size() == 0) ret.reserve(numUsed);//keep it from doing multiple expansion copies on the first model for (int64_t i = 0; i < numUsed; ++i) { int64_t i3 = i * 3; VolumeMap temp; temp.m_ciftiIndex = myModel.m_modelStart + i; temp.m_ijk[0] = myModel.m_voxelIndicesIJK[i3]; temp.m_ijk[1] = myModel.m_voxelIndicesIJK[i3 + 1]; temp.m_ijk[2] = myModel.m_voxelIndicesIJK[i3 + 2]; ret.push_back(temp); } } } return ret; } const VolumeSpace& CiftiBrainModelsMap::getVolumeSpace() const { CaretAssert(!m_ignoreVolSpace); if (!m_haveVolumeSpace) { throw DataFileException("getVolumeSpace called when no volume space exists"); } return m_volSpace; } vector CiftiBrainModelsMap::getVolumeStructureList() const { vector ret; ret.reserve(m_volUsed.size());//we can use this to tell us how many there are, but it has reordered them int numModels = (int)m_modelsInfo.size(); for (int i = 0; i < numModels; ++i)//we need them in the order they occur in { if (m_modelsInfo[i].m_type == VOXELS) { ret.push_back(m_modelsInfo[i].m_brainStructure); } } return ret; } vector CiftiBrainModelsMap::getVolumeStructureMap(const StructureEnum::Enum& structure) const { vector ret; map::const_iterator iter = m_volUsed.find(structure); if (iter == m_volUsed.end()) { throw DataFileException("getVolumeStructureMap called for nonexistant structure");//also throw, for consistency } CaretAssertVectorIndex(m_modelsInfo, iter->second); const BrainModelPriv& myModel = m_modelsInfo[iter->second]; int64_t listSize = (int64_t)myModel.m_voxelIndicesIJK.size(); CaretAssert(listSize % 3 == 0); int64_t numUsed = listSize / 3; ret.resize(numUsed); for (int64_t i = 0; i < numUsed; ++i) { int64_t i3 = i * 3; ret[i].m_ciftiIndex = myModel.m_modelStart + i; ret[i].m_ijk[0] = myModel.m_voxelIndicesIJK[i3]; ret[i].m_ijk[1] = myModel.m_voxelIndicesIJK[i3 + 1]; ret[i].m_ijk[2] = myModel.m_voxelIndicesIJK[i3 + 2]; } return ret; } const vector& CiftiBrainModelsMap::getVoxelList(const StructureEnum::Enum& structure) const { map::const_iterator iter = m_volUsed.find(structure); if (iter == m_volUsed.end()) { throw DataFileException("getVoxelList called for nonexistant structure");//throw if it doesn't exist, because we don't have a reference to return - things should identify which structures exist before calling this } CaretAssertVectorIndex(m_modelsInfo, iter->second); return m_modelsInfo[iter->second].m_voxelIndicesIJK; } bool CiftiBrainModelsMap::hasVolumeData() const { return (m_volUsed.size() != 0); } bool CiftiBrainModelsMap::hasVolumeData(const StructureEnum::Enum& structure) const { map::const_iterator iter = m_volUsed.find(structure); return (iter != m_volUsed.end()); } void CiftiBrainModelsMap::setVolumeSpace(const VolumeSpace& space) { for (map::const_iterator iter = m_volUsed.begin(); iter != m_volUsed.end(); ++iter)//the main time this loop isn't empty is parsing cifti-1 { CaretAssertVectorIndex(m_modelsInfo, iter->second); const BrainModelPriv& myModel = m_modelsInfo[iter->second]; int64_t listSize = (int64_t)myModel.m_voxelIndicesIJK.size(); CaretAssert(listSize % 3 == 0); for (int64_t i3 = 0; i3 < listSize; i3 += 3) { if (!space.indexValid(myModel.m_voxelIndicesIJK[i3], myModel.m_voxelIndicesIJK[i3 + 1], myModel.m_voxelIndicesIJK[i3 + 2])) { throw DataFileException("invalid voxel found for volume space"); } } } m_ignoreVolSpace = false; m_haveVolumeSpace = true; m_volSpace = space; } bool CiftiBrainModelsMap::operator==(const CiftiMappingType& rhs) const { if (rhs.getType() != getType()) return false; const CiftiBrainModelsMap& myrhs = dynamic_cast(rhs); CaretAssert(!m_ignoreVolSpace && !myrhs.m_ignoreVolSpace);//these should only be true while in the process of parsing cifti-1, never otherwise if (m_haveVolumeSpace != myrhs.m_haveVolumeSpace) return false; if (m_haveVolumeSpace && (m_volSpace != myrhs.m_volSpace)) return false; return (m_modelsInfo == myrhs.m_modelsInfo);//NOTE: these are sorted by index range, so this works } bool CiftiBrainModelsMap::approximateMatch(const CiftiMappingType& rhs, QString* explanation) const { if (rhs.getType() != getType()) { if (explanation != NULL) *explanation = CiftiMappingType::mappingTypeToName(rhs.getType()) + " mapping never matches " + CiftiMappingType::mappingTypeToName(getType()); return false; } const CiftiBrainModelsMap& myrhs = dynamic_cast(rhs);//there is no user-specified metadata, but we want informative messages, so copy and modify the code from == CaretAssert(!m_ignoreVolSpace && !myrhs.m_ignoreVolSpace);//these should only be true while in the process of parsing cifti-1, never otherwise if (m_haveVolumeSpace != myrhs.m_haveVolumeSpace) { if (explanation != NULL) *explanation = "one of the mappings has no volume data"; return false; } if (m_haveVolumeSpace && (m_volSpace != myrhs.m_volSpace)) { if (explanation != NULL) *explanation = "mappings have a different volume space"; return false; } if (m_modelsInfo != myrhs.m_modelsInfo) { if (explanation != NULL) *explanation = "mappings include different brainordinates"; return false; } return true; } /** * @return EQUAL if 'this' and 'rhs' contain the same models * SUBSET if each model in 'this' is contained in 'rhs' and 'rhs' contains models not in 'this' * NO if 'this' contains a model not in 'rhs' */ CiftiBrainModelsMap::MatchResult CiftiBrainModelsMap::testMatch(const CiftiMappingType& rhs) const { if (rhs.getType() != getType()) return CiftiBrainModelsMap::MatchResult::NO; const CiftiBrainModelsMap& myrhs = dynamic_cast(rhs); CaretAssert(!m_ignoreVolSpace && !myrhs.m_ignoreVolSpace);//these should only be true while in the process of parsing cifti-1, never otherwise if (m_haveVolumeSpace && ( ! myrhs.m_haveVolumeSpace)) return CiftiBrainModelsMap::MatchResult::NO; if (m_haveVolumeSpace && (m_volSpace != myrhs.m_volSpace)) return CiftiBrainModelsMap::MatchResult::NO; for (const auto& modelInfo : m_modelsInfo) { bool matched = false; for (const auto& rhsModelInfo : myrhs.m_modelsInfo) { if (modelInfo == rhsModelInfo) { matched = true; break; } } if (! matched) { return CiftiBrainModelsMap::MatchResult::NO; } } if (m_modelsInfo.size() == myrhs.m_modelsInfo.size()) { /* * A note in the equality operator indicates that models are * sorted by index range so if 'this' and 'rhs' have the * exact same models, they must be equal. The assertion * will fail if this wrong. */ CaretAssert(*this == rhs); return CiftiBrainModelsMap::MatchResult::EQUAL; } return CiftiBrainModelsMap::MatchResult::SUBSET; } bool CiftiBrainModelsMap::BrainModelPriv::operator==(const BrainModelPriv& rhs) const { if (m_brainStructure != rhs.m_brainStructure) return false; if (m_type != rhs.m_type) return false; if (m_modelStart != rhs.m_modelStart) return false; if (m_modelEnd != rhs.m_modelEnd) return false; if (m_type == SURFACE) { if (m_surfaceNumberOfNodes != rhs.m_surfaceNumberOfNodes) return false; int64_t listSize = (int64_t)m_nodeIndices.size(); CaretAssert((int64_t)rhs.m_nodeIndices.size() == listSize);//this should already be checked by start/end above for (int64_t i = 0; i < listSize; ++i) { if (m_nodeIndices[i] != rhs.m_nodeIndices[i]) return false; } } else { int64_t listSize = (int64_t)m_voxelIndicesIJK.size(); CaretAssert((int64_t)rhs.m_voxelIndicesIJK.size() == listSize);//this should already be checked by start/end above for (int64_t i = 0; i < listSize; ++i) { if (m_voxelIndicesIJK[i] != rhs.m_voxelIndicesIJK[i]) return false; } } return true; } void CiftiBrainModelsMap::readXML1(QXmlStreamReader& xml) { clear(); m_ignoreVolSpace = true;//because in cifti-1, the volume space is not in this element - so, we rely on CiftiXML to check for volume data, and set the volume space afterwards vector parsedModels; for (xml.readNext(); !xml.atEnd() && !xml.isEndElement(); xml.readNext()) { switch (xml.tokenType()) { case QXmlStreamReader::StartElement: { QStringRef name = xml.name(); if (name != "BrainModel") { throw DataFileException("unexpected element in brain models map: " + name.toString()); } ParseHelperModel thisModel; thisModel.parseBrainModel1(xml); if (xml.hasError()) return; parsedModels.push_back(thisModel); break;//the readNext in the for will remove the BrainModel end element } default: break; } } if (xml.hasError()) return; sort(parsedModels.begin(), parsedModels.end()); int64_t numModels = (int64_t)parsedModels.size();//because we haven't checked them for unique values of BrainStructure yet...yeah, its paranoid int64_t curOffset = 0; for (int64_t i = 0; i < numModels; ++i) { if (parsedModels[i].m_offset != curOffset) { if (parsedModels[i].m_offset < curOffset) { throw DataFileException("models overlap at index " + QString::number(parsedModels[i].m_offset) + ", model " + QString::number(i)); } else { throw DataFileException("index " + QString::number(curOffset) + " is not assigned to any model"); } } curOffset += parsedModels[i].m_count; } for (int64_t i = 0; i < numModels; ++i) { if (parsedModels[i].m_type == SURFACE) { addSurfaceModel(parsedModels[i].m_surfaceNumberOfNodes, parsedModels[i].m_brainStructure, parsedModels[i].m_nodeIndices); } else { addVolumeModel(parsedModels[i].m_brainStructure, parsedModels[i].m_voxelIndicesIJK); } } m_ignoreVolSpace = false;//in case there are no voxels, but some will be added later CaretAssert(xml.isEndElement() && xml.name() == "MatrixIndicesMap"); } void CiftiBrainModelsMap::readXML2(QXmlStreamReader& xml) { clear(); vector parsedModels; for (xml.readNext(); !xml.atEnd() && !xml.isEndElement(); xml.readNext()) { switch (xml.tokenType()) { case QXmlStreamReader::StartElement: { QStringRef name = xml.name(); if (name == "BrainModel") { ParseHelperModel thisModel; thisModel.parseBrainModel2(xml); if (xml.hasError()) break; parsedModels.push_back(thisModel); } else if (name == "Volume") { if (m_haveVolumeSpace) { throw DataFileException("Volume specified more than once in Brain Models mapping type"); } else { m_volSpace.readCiftiXML2(xml); if (xml.hasError()) return; m_haveVolumeSpace = true; } } else { throw DataFileException("unexpected element in brain models map: " + name.toString()); } break;//the readNext in the for will remove the BrainModel or Volume end element } default: break; } } if (xml.hasError()) return; sort(parsedModels.begin(), parsedModels.end()); int64_t numModels = (int64_t)parsedModels.size();//because we haven't checked them for unique values of BrainStructure yet...yeah, its paranoid int64_t curOffset = 0; for (int64_t i = 0; i < numModels; ++i) { if (parsedModels[i].m_offset != curOffset) { if (parsedModels[i].m_offset < curOffset) { throw DataFileException("models overlap at index " + QString::number(parsedModels[i].m_offset) + ", model " + QString::number(i)); } else { throw DataFileException("index " + QString::number(curOffset) + " is not assigned to any model"); } } curOffset += parsedModels[i].m_count; } for (int64_t i = 0; i < numModels; ++i) { if (parsedModels[i].m_type == SURFACE) { addSurfaceModel(parsedModels[i].m_surfaceNumberOfNodes, parsedModels[i].m_brainStructure, parsedModels[i].m_nodeIndices); } else { addVolumeModel(parsedModels[i].m_brainStructure, parsedModels[i].m_voxelIndicesIJK); } } CaretAssert(xml.isEndElement() && xml.name() == "MatrixIndicesMap"); } void CiftiBrainModelsMap::ParseHelperModel::parseBrainModel1(QXmlStreamReader& xml) { QXmlStreamAttributes attrs = xml.attributes(); if (!attrs.hasAttribute("ModelType")) { throw DataFileException("BrainModel missing required attribute ModelType"); } QStringRef value = attrs.value("ModelType"); if (value == "CIFTI_MODEL_TYPE_SURFACE") { m_type = SURFACE; } else if (value == "CIFTI_MODEL_TYPE_VOXELS") { m_type = VOXELS; } else { throw DataFileException("invalid value for ModelType: " + value.toString()); } if (!attrs.hasAttribute("BrainStructure")) { throw DataFileException("BrainModel missing required attribute BrainStructure"); } value = attrs.value("BrainStructure"); bool ok = false; m_brainStructure = StructureEnum::fromCiftiName(value.toString(), &ok); if (!ok) { throw DataFileException("invalid value for BrainStructure: " + value.toString()); } if (!attrs.hasAttribute("IndexOffset")) { throw DataFileException("BrainModel missing required attribute IndexOffset"); } value = attrs.value("IndexOffset"); m_offset = value.toString().toLongLong(&ok); if (!ok || m_offset < 0) { throw DataFileException("IndexOffset must be a non-negative integer"); } if (!attrs.hasAttribute("IndexCount")) { throw DataFileException("BrainModel missing required attribute IndexCount"); } value = attrs.value("IndexCount"); m_count = value.toString().toLongLong(&ok); if (!ok || m_count < 1)//NOTE: not technically required by cifti-1, would need some rewriting to support empty brainmodels { throw DataFileException("IndexCount must be a positive integer"); } if (m_type == SURFACE) { if (!attrs.hasAttribute("SurfaceNumberOfNodes")) { throw DataFileException("BrainModel missing required attribute SurfaceNumberOfNodes"); } value = attrs.value("SurfaceNumberOfNodes"); m_surfaceNumberOfNodes = value.toString().toLongLong(&ok); if (!ok || m_surfaceNumberOfNodes < 1) { throw DataFileException("SurfaceNumberOfNodes must be a positive integer"); } if (!xml.readNextStartElement())//special case in cifti-1 { m_nodeIndices.resize(m_count); for (int64_t i = 0; i < m_count; ++i) { m_nodeIndices[i] = i; } } else { if (xml.name() != "NodeIndices") { throw DataFileException("unexpected element in BrainModel of SURFACE type: " + xml.name().toString()); } m_nodeIndices = readIndexArray(xml); xml.readNext();//remove the end element of NodeIndices } if (xml.hasError()) return; if ((int64_t)m_nodeIndices.size() != m_count) { throw DataFileException("number of vertex indices does not match IndexCount"); } } else { if (!xml.readNextStartElement()) { throw DataFileException("BrainModel requires a child element"); } if (xml.name() != "VoxelIndicesIJK") { throw DataFileException("unexpected element in BrainModel of VOXELS type: " + xml.name().toString()); } m_voxelIndicesIJK = readIndexArray(xml); if (xml.hasError()) return; if (m_voxelIndicesIJK.size() % 3 != 0) { throw DataFileException("number of voxel indices is not a multiple of 3"); } if ((int64_t)m_voxelIndicesIJK.size() != m_count * 3) { throw DataFileException("number of voxel indices does not match IndexCount"); } xml.readNext();//remove the end element of VoxelIndicesIJK } while (!xml.atEnd() && !xml.isEndElement())//locate the end element of BrainModel { switch(xml.readNext()) { case QXmlStreamReader::StartElement: throw DataFileException("unexpected second element in BrainModel: " + xml.name().toString()); default: break; } } CaretAssert(xml.isEndElement() && xml.name() == "BrainModel"); } void CiftiBrainModelsMap::ParseHelperModel::parseBrainModel2(QXmlStreamReader& xml) { QXmlStreamAttributes attrs = xml.attributes(); if (!attrs.hasAttribute("ModelType")) { throw DataFileException("BrainModel missing required attribute ModelType"); } QStringRef value = attrs.value("ModelType"); if (value == "CIFTI_MODEL_TYPE_SURFACE") { m_type = SURFACE; } else if (value == "CIFTI_MODEL_TYPE_VOXELS") { m_type = VOXELS; } else { throw DataFileException("invalid value for ModelType: " + value.toString()); } if (!attrs.hasAttribute("BrainStructure")) { throw DataFileException("BrainModel missing required attribute BrainStructure"); } value = attrs.value("BrainStructure"); bool ok = false; m_brainStructure = StructureEnum::fromCiftiName(value.toString(), &ok); if (!ok) { throw DataFileException("invalid value for BrainStructure: " + value.toString()); } if (!attrs.hasAttribute("IndexOffset")) { throw DataFileException("BrainModel missing required attribute IndexOffset"); } value = attrs.value("IndexOffset"); m_offset = value.toString().toLongLong(&ok); if (!ok || m_offset < 0) { throw DataFileException("IndexOffset must be a non-negative integer"); } if (!attrs.hasAttribute("IndexCount")) { throw DataFileException("BrainModel missing required attribute IndexCount"); } value = attrs.value("IndexCount"); m_count = value.toString().toLongLong(&ok); if (!ok || m_count < 1) { throw DataFileException("IndexCount must be a positive integer"); } if (m_type == SURFACE) { if (!attrs.hasAttribute("SurfaceNumberOfVertices")) { throw DataFileException("BrainModel missing required attribute SurfaceNumberOfVertices"); } value = attrs.value("SurfaceNumberOfVertices"); m_surfaceNumberOfNodes = value.toString().toLongLong(&ok); if (!ok || m_surfaceNumberOfNodes < 1) { throw DataFileException("SurfaceNumberOfVertices must be a positive integer"); } if (!xml.readNextStartElement()) { throw DataFileException("BrainModel requires a child element"); } if (xml.name() != "VertexIndices") { throw DataFileException("unexpected element in BrainModel of SURFACE type: " + xml.name().toString()); } m_nodeIndices = readIndexArray(xml); if (xml.hasError()) return; if ((int64_t)m_nodeIndices.size() != m_count) { throw DataFileException("number of vertex indices does not match IndexCount"); } xml.readNext();//remove the end element of NodeIndices } else { if (!xml.readNextStartElement()) { throw DataFileException("BrainModel requires a child element"); } if (xml.name() != "VoxelIndicesIJK") { throw DataFileException("unexpected element in BrainModel of VOXELS type: " + xml.name().toString()); } m_voxelIndicesIJK = readIndexArray(xml); if (xml.hasError()) return; if (m_voxelIndicesIJK.size() % 3 != 0) { throw DataFileException("number of voxel indices is not a multiple of 3"); } if ((int64_t)m_voxelIndicesIJK.size() != m_count * 3) { throw DataFileException("number of voxel indices does not match IndexCount"); } xml.readNext();//remove the end element of VoxelIndicesIJK } while (!xml.atEnd() && !xml.isEndElement())//locate the end element of BrainModel { switch(xml.readNext()) { case QXmlStreamReader::StartElement: throw DataFileException("unexpected second element in BrainModel: " + xml.name().toString()); default: break; } } CaretAssert(xml.isEndElement() && xml.name() == "BrainModel"); } vector CiftiBrainModelsMap::ParseHelperModel::readIndexArray(QXmlStreamReader& xml) { vector ret; QString text = xml.readElementText();//raises error if it encounters a start element if (xml.hasError()) return ret; QStringList separated = text.split(QRegExp("\\s+"), QString::SkipEmptyParts); int64_t numElems = separated.size(); ret.reserve(numElems); for (int64_t i = 0; i < numElems; ++i) { bool ok = false; ret.push_back(separated[i].toLongLong(&ok)); if (!ok) { throw DataFileException("found noninteger in index array: " + separated[i]); } if (ret.back() < 0) { throw DataFileException("found negative integer in index array: " + separated[i]); } } return ret; } void CiftiBrainModelsMap::writeXML1(QXmlStreamWriter& xml) const { CaretAssert(!m_ignoreVolSpace); xml.writeAttribute("IndicesMapToDataType", "CIFTI_INDEX_TYPE_BRAIN_MODELS"); int numModels = (int)m_modelsInfo.size(); for (int i = 0; i < numModels; ++i) { const BrainModelPriv& myModel = m_modelsInfo[i]; xml.writeStartElement("BrainModel"); xml.writeAttribute("IndexOffset", QString::number(myModel.m_modelStart)); xml.writeAttribute("IndexCount", QString::number(myModel.m_modelEnd - myModel.m_modelStart)); xml.writeAttribute("BrainStructure", StructureEnum::toCiftiName(myModel.m_brainStructure)); if (myModel.m_type == SURFACE) { xml.writeAttribute("ModelType", "CIFTI_MODEL_TYPE_SURFACE"); xml.writeAttribute("SurfaceNumberOfNodes", QString::number(myModel.m_surfaceNumberOfNodes)); xml.writeStartElement("NodeIndices"); QString text = ""; int64_t numNodes = (int64_t)myModel.m_nodeIndices.size(); for (int64_t j = 0; j < numNodes; ++j) { if (j != 0) text += " "; text += QString::number(myModel.m_nodeIndices[j]); } xml.writeCharacters(text); xml.writeEndElement(); } else { xml.writeAttribute("ModelType", "CIFTI_MODEL_TYPE_VOXELS"); xml.writeStartElement("VoxelIndicesIJK"); QString text = ""; int64_t listSize = (int64_t)myModel.m_voxelIndicesIJK.size(); CaretAssert(listSize % 3 == 0); for (int64_t j = 0; j < listSize; j += 3) { text += QString::number(myModel.m_voxelIndicesIJK[j]) + " " + QString::number(myModel.m_voxelIndicesIJK[j + 1]) + " " + QString::number(myModel.m_voxelIndicesIJK[j + 2]) + "\n"; } xml.writeCharacters(text); xml.writeEndElement(); } xml.writeEndElement(); } } void CiftiBrainModelsMap::writeXML2(QXmlStreamWriter& xml) const { CaretAssert(!m_ignoreVolSpace); xml.writeAttribute("IndicesMapToDataType", "CIFTI_INDEX_TYPE_BRAIN_MODELS"); if (hasVolumeData())//could be m_haveVolumeSpace if we want to be able to write a volspace without having voxels, but that seems silly { m_volSpace.writeCiftiXML2(xml); } int numModels = (int)m_modelsInfo.size(); for (int i = 0; i < numModels; ++i) { const BrainModelPriv& myModel = m_modelsInfo[i]; xml.writeStartElement("BrainModel"); xml.writeAttribute("IndexOffset", QString::number(myModel.m_modelStart)); xml.writeAttribute("IndexCount", QString::number(myModel.m_modelEnd - myModel.m_modelStart)); xml.writeAttribute("BrainStructure", StructureEnum::toCiftiName(myModel.m_brainStructure)); if (myModel.m_type == SURFACE) { xml.writeAttribute("ModelType", "CIFTI_MODEL_TYPE_SURFACE"); xml.writeAttribute("SurfaceNumberOfVertices", QString::number(myModel.m_surfaceNumberOfNodes)); xml.writeStartElement("VertexIndices"); QString text = ""; int64_t numNodes = (int64_t)myModel.m_nodeIndices.size(); for (int64_t j = 0; j < numNodes; ++j) { if (j != 0) text += " "; text += QString::number(myModel.m_nodeIndices[j]); } xml.writeCharacters(text); xml.writeEndElement(); } else { xml.writeAttribute("ModelType", "CIFTI_MODEL_TYPE_VOXELS"); xml.writeStartElement("VoxelIndicesIJK"); QString text = ""; int64_t listSize = (int64_t)myModel.m_voxelIndicesIJK.size(); CaretAssert(listSize % 3 == 0); for (int64_t j = 0; j < listSize; j += 3) { text += QString::number(myModel.m_voxelIndicesIJK[j]) + " " + QString::number(myModel.m_voxelIndicesIJK[j + 1]) + " " + QString::number(myModel.m_voxelIndicesIJK[j + 2]) + "\n"; } xml.writeCharacters(text); xml.writeEndElement(); } xml.writeEndElement(); } } connectome-workbench-1.4.2/src/Cifti/CiftiBrainModelsMap.h000066400000000000000000000152471360521144700234560ustar00rootroot00000000000000#ifndef __CIFTI_BRAIN_MODELS_MAP_H__ #define __CIFTI_BRAIN_MODELS_MAP_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiMappingType.h" #include "CaretCompact3DLookup.h" #include "StructureEnum.h" #include "VolumeSpace.h" #include #include #include namespace caret { class CiftiBrainModelsMap : public CiftiMappingType { public: enum ModelType { SURFACE, VOXELS }; enum class MatchResult { EQUAL, NO, SUBSET }; struct SurfaceMap { int64_t m_ciftiIndex; int64_t m_surfaceNode; }; struct VolumeMap { int64_t m_ciftiIndex; int64_t m_ijk[3]; }; struct ModelInfo { ModelType m_type; StructureEnum::Enum m_structure; int64_t m_indexStart, m_indexCount;//these are intended only for summary info, use getSurfaceMap, etc for the index to vertex/voxel mappings }; struct IndexInfo { ModelType m_type; StructureEnum::Enum m_structure; int64_t m_surfaceNode;//only one of these two will be valid int64_t m_ijk[3]; }; bool hasVolumeData() const; bool hasVolumeData(const StructureEnum::Enum& structure) const; bool hasSurfaceData(const StructureEnum::Enum& structure) const; int64_t getIndexForNode(const int64_t& node, const StructureEnum::Enum& structure) const; int64_t getIndexForVoxel(const int64_t* ijk, StructureEnum::Enum* structureOut = NULL) const; int64_t getIndexForVoxel(const int64_t& i, const int64_t& j, const int64_t& k, StructureEnum::Enum* structureOut = NULL) const; IndexInfo getInfoForIndex(const int64_t index) const; std::vector getSurfaceMap(const StructureEnum::Enum& structure) const; std::vector getFullVolumeMap() const; std::vector getVolumeStructureMap(const StructureEnum::Enum& structure) const; const VolumeSpace& getVolumeSpace() const; int64_t getSurfaceNumberOfNodes(const StructureEnum::Enum& structure) const; std::vector getSurfaceStructureList() const; std::vector getVolumeStructureList() const; const std::vector& getNodeList(const StructureEnum::Enum& structure) const;//useful for copying mappings to a new dense mapping const std::vector& getVoxelList(const StructureEnum::Enum& structure) const; std::vector getModelInfo() const; CiftiBrainModelsMap() { m_haveVolumeSpace = false; m_ignoreVolSpace = false; } void addSurfaceModel(const int64_t& numberOfNodes, const StructureEnum::Enum& structure, const float* roi = NULL); void addSurfaceModel(const int64_t& numberOfNodes, const StructureEnum::Enum& structure, const std::vector& nodeList); void addVolumeModel(const StructureEnum::Enum& structure, const std::vector& ijkList); void setVolumeSpace(const VolumeSpace& space); void clear(); CiftiMappingType* clone() const { return new CiftiBrainModelsMap(*this); } MappingType getType() const { return BRAIN_MODELS; } int64_t getLength() const; bool operator==(const CiftiMappingType& rhs) const; bool approximateMatch(const CiftiMappingType& rhs, QString* explanation = NULL) const; MatchResult testMatch(const CiftiMappingType& rhs) const; void readXML1(QXmlStreamReader& xml); void readXML2(QXmlStreamReader& xml); void writeXML1(QXmlStreamWriter& xml) const; void writeXML2(QXmlStreamWriter& xml) const; private: struct BrainModelPriv { ModelType m_type; StructureEnum::Enum m_brainStructure; int64_t m_surfaceNumberOfNodes; std::vector m_nodeIndices; std::vector m_voxelIndicesIJK; int64_t m_modelStart, m_modelEnd;//stuff only needed for optimization - models are kept in sorted order by their index ranges std::vector m_nodeToIndexLookup; bool operator==(const BrainModelPriv& rhs) const; bool operator!=(const BrainModelPriv& rhs) const { return !((*this) == rhs); } void setupSurface(const int64_t& start); }; VolumeSpace m_volSpace; bool m_haveVolumeSpace, m_ignoreVolSpace;//second is needed for parsing cifti-1 std::vector m_modelsInfo; std::map m_surfUsed, m_volUsed; CaretCompact3DLookup > m_voxelToIndexLookup;//make one unified lookup rather than separate lookups per volume structure int64_t getNextStart() const; struct ParseHelperModel {//specifically to allow the parsed elements to be sorted before using addSurfaceModel/addVolumeModel ModelType m_type; StructureEnum::Enum m_brainStructure; int64_t m_surfaceNumberOfNodes; std::vector m_nodeIndices; std::vector m_voxelIndicesIJK; int64_t m_offset, m_count; bool operator<(const ParseHelperModel& rhs) const { if (m_offset < rhs.m_offset) return true; if (m_offset > rhs.m_offset) return false;//get the common cases first if (m_count < rhs.m_count) return true;//in case we have a zero-length model - this shouldn't happen, usually return false; } void parseBrainModel1(QXmlStreamReader& xml); void parseBrainModel2(QXmlStreamReader& xml); static std::vector readIndexArray(QXmlStreamReader& xml); }; }; } #endif //__CIFTI_BRAIN_MODELS_MAP_H__ connectome-workbench-1.4.2/src/Cifti/CiftiFile.cxx000066400000000000000000001151541360521144700220510ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiFile.h" #include "ByteOrderEnum.h" #include "CaretAssert.h" #include "CaretHttpManager.h" #include "CaretLogger.h" #include "DataFileException.h" #include "FileInformation.h" #include "MultiDimArray.h" #include "MultiDimIterator.h" #include "NiftiIO.h" using namespace std; using namespace caret; //private implementation classes namespace { class CiftiOnDiskImpl : public CiftiFile::WriteImplInterface { mutable NiftiIO m_nifti;//because file objects aren't stateless (current position), so reading "changes" them vector m_matrixDims;//store the dimensions even if the xml is forgotten CiftiXML m_xml;//we need to store the xml somewhere before it gets put into CiftiFile's copy public: CiftiOnDiskImpl(const QString& filename);//read-only CiftiOnDiskImpl(const QString& filename, const CiftiXML& xml, const CiftiVersion& version, const bool& swapEndian, const int16_t& datatype, const bool& rescale, const double& minval, const double& maxval);//make new empty file with read/write void getRow(float* dataOut, const std::vector& indexSelect, const bool& tolerateShortRead) const; void getColumn(float* dataOut, const int64_t& index) const; const CiftiXML& getCiftiXML() const { return m_xml; } QString getFilename() const { return m_nifti.getFilename(); } bool isSwapped() const { return m_nifti.getHeader().isSwapped(); } void setRow(const float* dataIn, const std::vector& indexSelect); void setColumn(const float* dataIn, const int64_t& index); void close(); void dropXML() { m_xml = CiftiXML(); m_nifti.dropExtensions(); } }; class CiftiMemoryImpl : public CiftiFile::WriteImplInterface { MultiDimArray m_array; public: CiftiMemoryImpl(const CiftiXML& xml); void getRow(float* dataOut, const std::vector& indexSelect, const bool& tolerateShortRead) const; void getColumn(float* dataOut, const int64_t& index) const; bool isInMemory() const { return true; } void setRow(const float* dataIn, const std::vector& indexSelect); void setColumn(const float* dataIn, const int64_t& index); }; class CiftiXnatImpl : public CiftiFile::ReadImplInterface { CiftiXML m_xml;//because we need to parse it to check the dimensions anyway CaretHttpRequest m_baseRequest; void init(const QString& url); void getReqAsFloats(float* data, const int64_t& dataSize, CaretHttpRequest& request) const; int64_t getSizeFromReq(CaretHttpRequest& request); public: CiftiXnatImpl(const QString& url, const QString& user, const QString& pass); CiftiXnatImpl(const QString& url);//reuse existing user/pass, or access non-protected url - in the future, maybe only the second use (private http manager) void getRow(float* dataOut, const std::vector& indexSelect, const bool& tolerateShortRead) const; void getColumn(float* dataOut, const int64_t& index) const; const CiftiXML& getCiftiXML() const { return m_xml; } }; bool shouldSwap(const CiftiFile::ENDIAN& endian) { if (ByteSwapping::isBigEndian()) { if (endian == CiftiFile::LITTLE) return true; } else { if (endian == CiftiFile::BIG) return true; } return false;//default for all other enum values is to write native endian } bool dontRewrite(const CiftiFile::ENDIAN& endian) { return (endian == CiftiFile::ANY); } } CiftiFile::ReadImplInterface::~ReadImplInterface() { } CiftiFile::WriteImplInterface::~WriteImplInterface() { } CiftiFile::CiftiFile(const QString& fileName) { m_endianPref = NATIVE; setWritingDataTypeNoScaling();//default argument is float32 openFile(fileName); } void CiftiFile::openFile(const QString& fileName) { close();//to make sure it closes everything first, even if the open throws CaretPointer newRead(new CiftiOnDiskImpl(FileInformation(fileName).getAbsoluteFilePath()));//this constructor opens existing file read-only m_readingImpl = newRead;//it should be noted that if the constructor throws (if the file isn't readable), new guarantees the memory allocated for the object will be freed m_xml = newRead->getCiftiXML(); newRead->dropXML();//save some memory, we don't need 2 copies of the xml - figure out if there is a better way to prevent copies m_xmlBroken = false; m_dims = m_xml.getDimensions(); m_onDiskVersion = m_xml.getParsedVersion(); m_fileName = fileName; } void CiftiFile::openURL(const QString& url, const QString& user, const QString& pass) { close();//to make sure it closes everything first, even if the open throws CaretPointer newRead(new CiftiXnatImpl(url, user, pass)); m_readingImpl = newRead; m_xml = newRead->getCiftiXML(); m_xmlBroken = false; m_dims = m_xml.getDimensions(); m_fileName = url; } void CiftiFile::openURL(const QString& url) { close();//to make sure it closes everything first, even if the open throws CaretPointer newRead(new CiftiXnatImpl(url)); m_readingImpl = newRead; m_xml = newRead->getCiftiXML(); m_xmlBroken = false; m_dims = m_xml.getDimensions(); m_fileName = url; } void CiftiFile::setWritingFile(const QString& fileName, const CiftiVersion& writingVersion, const ENDIAN& endian) { if (fileName != "" && m_xmlBroken) throw DataFileException("can't set cifti writing file when XML mappings have been forgotten"); m_writingFile = FileInformation(fileName).getAbsoluteFilePath();//always resolve paths as soon as they enter CiftiFile, in case some clown changes directory before writing data m_writingImpl.grabNew(NULL);//prevent writing to previous writing implementation, let the next set...() set up for writing m_onDiskVersion = writingVersion;//so that we can do on-disk writing with the old version m_fileName = fileName; m_endianPref = endian; } void CiftiFile::setWritingDataTypeNoScaling(const int16_t& type) { m_writingDataType = type;//could do some validation here m_doWriteScaling = false; m_minScalingVal = -1.0; m_maxScalingVal = 1.0; m_writingImpl.grabNew(NULL);//prevent writing to previous writing implementation, let the next set...() set up for writing } void CiftiFile::setWritingDataTypeAndScaling(const int16_t& type, const double& minval, const double& maxval) { m_writingDataType = type;//could do some validation here m_doWriteScaling = true; m_minScalingVal = minval; m_maxScalingVal = maxval; m_writingImpl.grabNew(NULL);//prevent writing to previous writing implementation, let the next set...() set up for writing } void CiftiFile::writeFile(const QString& fileName, const CiftiVersion& writingVersion, const ENDIAN& endian) { if (m_readingImpl == NULL || m_dims.empty()) throw DataFileException("writeFile called on uninitialized CiftiFile"); if (m_xmlBroken) throw DataFileException("can't write cifti file when XML mappings have been forgotten"); bool writeSwapped = shouldSwap(endian); FileInformation myInfo(fileName); QString canonicalFilename = myInfo.getCanonicalFilePath();//NOTE: returns EMPTY STRING for nonexistant file const CiftiOnDiskImpl* testImpl = dynamic_cast(m_readingImpl.getPointer()); bool collision = false, hadWriter = (m_writingImpl != NULL); if (testImpl != NULL && canonicalFilename != "" && FileInformation(testImpl->getFilename()).getCanonicalFilePath() == canonicalFilename) {//empty string test is so that we don't say collision if both are nonexistant - could happen if file is removed/unlinked while reading on some filesystems if (m_onDiskVersion == writingVersion && !m_xml.mutablesModified() && (dontRewrite(endian) || writeSwapped == testImpl->isSwapped())) return;//don't need to copy to itself collision = true;//we need to copy to memory temporarily CaretPointer tempMemory(new CiftiMemoryImpl(m_xml)); copyImplData(m_readingImpl, tempMemory, m_dims); m_readingImpl = tempMemory;//we are about to make the old reading impl very unhappy, replace it so that if we get an error while writing, we hang onto the memory version m_writingImpl.grabNew(NULL);//and make it re-magic the writing implementation again if data is set } CaretPointer tempWrite(new CiftiOnDiskImpl(myInfo.getAbsoluteFilePath(), m_xml, writingVersion, writeSwapped, m_writingDataType, m_doWriteScaling, m_minScalingVal, m_maxScalingVal)); copyImplData(m_readingImpl, tempWrite, m_dims); if (collision)//if we rewrote the file, we need the handle to the new file, and to dump the temporary in-memory version { m_onDiskVersion = writingVersion;//also record the current version number m_readingImpl = tempWrite;//replace the temporary memory version if (hadWriter)//if it was in read-write mode { m_writingImpl = tempWrite;//set the writer too } } m_xml.clearMutablesModified(); } void CiftiFile::close() { if (m_writingImpl != NULL) { m_writingImpl->close();//only writing implementations should ever throw errors on close, and specifically only on-disk } m_writingImpl.grabNew(NULL); m_readingImpl.grabNew(NULL); m_dims.clear(); m_xml = CiftiXML(); m_xmlBroken = false; m_writingFile = ""; m_fileName = ""; m_onDiskVersion = CiftiVersion();//for completeness, it gets reset on open anyway m_endianPref = NATIVE;//reset things to defaults setWritingDataTypeNoScaling();//default argument is float32 } void CiftiFile::convertToInMemory() { if (isInMemory()) return; m_writingFile = "";//make sure it doesn't do on-disk when set...() is called if (m_readingImpl == NULL) return;//not set up yet CaretPointer tempWrite(new CiftiMemoryImpl(m_xml));//if we get an error while reading, free the memory immediately, and don't leave m_readingImpl and m_writingImpl pointing to different things copyImplData(m_readingImpl, tempWrite, m_dims); m_writingImpl = tempWrite; m_readingImpl = tempWrite; } bool CiftiFile::isInMemory() const { if (m_readingImpl == NULL) { return (m_writingFile == "");//return what it would be if verifyWriteImpl() was called } else { return m_readingImpl->isInMemory(); } } void CiftiFile::getRow(float* dataOut, const vector& indexSelect, const bool& tolerateShortRead) const { if (m_dims.empty()) throw DataFileException("getRow called on uninitialized CiftiFile"); if (m_readingImpl == NULL) return;//NOT an error because we are pretending to have a matrix already, while we are waiting for setRow to actually start writing the file m_readingImpl->getRow(dataOut, indexSelect, tolerateShortRead); } void CiftiFile::getColumn(float* dataOut, const int64_t& index) const { if (m_dims.empty()) throw DataFileException("getColumn called on uninitialized CiftiFile"); if (m_dims.size() != 2) throw DataFileException("getColumn called on non-2D CiftiFile"); if (m_readingImpl == NULL) return;//NOT an error because we are pretending to have a matrix already, while we are waiting for setRow to actually start writing the file m_readingImpl->getColumn(dataOut, index); } void CiftiFile::setCiftiXML(const CiftiXML& xml, const bool useOldMetadata) { if (xml.getNumberOfDimensions() == 0) throw DataFileException("setCiftiXML called with 0-dimensional CiftiXML"); vector xmlDims = xml.getDimensions(); for (size_t i = 0; i < xmlDims.size(); ++i) { if (xmlDims[i] < 1) throw DataFileException("cifti xml dimensions must be greater than zero"); } m_readingImpl.grabNew(NULL);//drop old implementation, as it is now invalid due to XML (and therefore matrix size) change m_writingImpl.grabNew(NULL); if (useOldMetadata) { const GiftiMetaData* oldmd = m_xml.getFileMetaData(); if (oldmd != NULL) { GiftiMetaData newmd = *oldmd;//make a copy oldmd = NULL;//don't leave a potentially dangling pointer around m_xml = xml;//because this will result in a new pointer for the metadata GiftiMetaData* changemd = m_xml.getFileMetaData(); if (changemd != NULL) { *changemd = newmd; } } else { m_xml = xml; } } else { m_xml = xml; } m_dims = xmlDims; m_xmlBroken = false; } void CiftiFile::setCiftiXML(const CiftiXMLOld& xml, const bool useOldMetadata) { QString xmlText; xml.writeXML(xmlText); CiftiXML tempXML;//so that we can use the same code path tempXML.readXML(xmlText); if (tempXML.getDimensionLength(CiftiXML::ALONG_ROW) < 0) { CiftiSeriesMap& tempMap = tempXML.getSeriesMap(CiftiXML::ALONG_ROW); tempMap.setLength(xml.getDimensionLength(CiftiXMLOld::ALONG_ROW)); } if (tempXML.getDimensionLength(CiftiXML::ALONG_COLUMN) < 0) { CiftiSeriesMap& tempMap = tempXML.getSeriesMap(CiftiXML::ALONG_COLUMN); tempMap.setLength(xml.getDimensionLength(CiftiXMLOld::ALONG_COLUMN)); } setCiftiXML(tempXML, useOldMetadata); } void CiftiFile::forgetMapping(const int& direction) { if (direction >= m_xml.getNumberOfDimensions()) { CaretLogWarning("forgetMapping called on nonexistant dimension"); return; } int64_t mapLength = m_xml.getDimensionLength(direction); m_xml.setMap(direction, CiftiSeriesMap(mapLength));//keep the xml dimension length the same, because it is used in convertToInMemory m_xmlBroken = true; } void CiftiFile::setRow(const float* dataIn, const vector& indexSelect) { verifyWriteImpl(); m_writingImpl->setRow(dataIn, indexSelect); } void CiftiFile::setColumn(const float* dataIn, const int64_t& index) { verifyWriteImpl(); if (m_dims.size() != 2) throw DataFileException("setColumn called on non-2D CiftiFile"); m_writingImpl->setColumn(dataIn, index); } //compatibility with old interface void CiftiFile::getRow(float* dataOut, const int64_t& index, const bool& tolerateShortRead) const { if (m_dims.empty()) throw DataFileException("getRow called on uninitialized CiftiFile"); if (m_dims.size() != 2) throw DataFileException("getRow with single index called on non-2D CiftiFile"); if (m_readingImpl == NULL) return;//NOT an error because we are pretending to have a matrix already, while we are waiting for setRow to actually start writing the file vector tempvec(1, index);//could use a member if we need more speed m_readingImpl->getRow(dataOut, tempvec, tolerateShortRead); } void CiftiFile::getRow(float* dataOut, const int64_t& index) const { getRow(dataOut, index, false);//once CiftiInterface is gone, we can collapse this into a default value } int64_t CiftiFile::getNumberOfRows() const { if (m_dims.empty()) throw DataFileException("getNumberOfRows called on uninitialized CiftiFile"); if (m_dims.size() != 2) throw DataFileException("getNumberOfRows called on non-2D CiftiFile"); return m_dims[1];//length of a column } int64_t CiftiFile::getNumberOfColumns() const { if (m_dims.empty()) throw DataFileException("getNumberOfRows called on uninitialized CiftiFile"); if (m_dims.size() != 2) throw DataFileException("getNumberOfRows called on non-2D CiftiFile"); return m_dims[0];//length of a row } void CiftiFile::setRow(const float* dataIn, const int64_t& index) { verifyWriteImpl(); if (m_dims.size() != 2) throw DataFileException("setRow with single index called on non-2D CiftiFile"); vector tempvec(1, index);//could use a member if we need more speed m_writingImpl->setRow(dataIn, tempvec); } //*///end old compatibility functions void CiftiFile::verifyWriteImpl() {//this is where the magic happens - we want to emulate being a simple in-memory file, but actually be reading/writing on-disk when possible if (m_writingImpl != NULL) return; CaretAssert(!m_dims.empty());//if the xml hasn't been set, then we can't do anything meaningful if (m_dims.empty()) throw DataFileException("setRow or setColumn attempted on uninitialized CiftiFile"); if (m_writingFile == "") { if (m_readingImpl != NULL) { convertToInMemory(); } else { m_writingImpl.grabNew(new CiftiMemoryImpl(m_xml)); } } else {//NOTE: m_onDiskVersion gets set in setWritingFile if (m_xmlBroken) throw DataFileException("can't write file when XML mappings have been forgotten"); if (m_readingImpl != NULL) { CiftiOnDiskImpl* testImpl = dynamic_cast(m_readingImpl.getPointer()); if (testImpl != NULL) { QString canonicalCurrent = FileInformation(testImpl->getFilename()).getCanonicalFilePath();//returns "" if nonexistant, if unlinked while open if (canonicalCurrent != "" && canonicalCurrent == FileInformation(m_writingFile).getCanonicalFilePath())//these were already absolute { convertToInMemory();//save existing data in memory before we clobber file } } } m_writingImpl.grabNew(new CiftiOnDiskImpl(m_writingFile, m_xml, m_onDiskVersion, shouldSwap(m_endianPref), m_writingDataType, m_doWriteScaling, m_minScalingVal, m_maxScalingVal));//this constructor makes new file for writing if (m_readingImpl != NULL) { copyImplData(m_readingImpl, m_writingImpl, m_dims); } } m_readingImpl = m_writingImpl;//read-only implementations are set up in specialized functions } void CiftiFile::copyImplData(const ReadImplInterface* from, WriteImplInterface* to, const vector& dims) { vector iterateDims(dims.begin() + 1, dims.end()); vector scratchRow(dims[0]); for (MultiDimIterator iter(iterateDims); !iter.atEnd(); ++iter) { from->getRow(scratchRow.data(), *iter, false); to->setRow(scratchRow.data(), *iter); } } CiftiMemoryImpl::CiftiMemoryImpl(const CiftiXML& xml) { CaretAssert(xml.getNumberOfDimensions() != 0); m_array.resize(xml.getDimensions()); } void CiftiMemoryImpl::getRow(float* dataOut, const vector& indexSelect, const bool&) const { const float* ref = m_array.get(1, indexSelect); int64_t rowSize = m_array.getDimensions()[0];//we don't accept 0-D CiftiXML, so this will always work for (int64_t i = 0; i < rowSize; ++i) { dataOut[i] = ref[i]; } } void CiftiMemoryImpl::getColumn(float* dataOut, const int64_t& index) const { CaretAssert(m_array.getDimensions().size() == 2);//otherwise, CiftiFile shouldn't have called this const float* ref = m_array.get(2, vector());//empty vector is intentional, only 2 dimensions exist, so no more to select from int64_t rowSize = m_array.getDimensions()[0]; int64_t colSize = m_array.getDimensions()[1]; CaretAssert(index >= 0 && index < rowSize);//because we are doing the indexing math manually for speed for (int64_t i = 0; i < colSize; ++i) { dataOut[i] = ref[index + rowSize * i]; } } void CiftiMemoryImpl::setRow(const float* dataIn, const vector& indexSelect) { float* ref = m_array.get(1, indexSelect); int64_t rowSize = m_array.getDimensions()[0];//we don't accept 0-D CiftiXML, so this will always work for (int64_t i = 0; i < rowSize; ++i) { ref[i] = dataIn[i]; } } void CiftiMemoryImpl::setColumn(const float* dataIn, const int64_t& index) { CaretAssert(m_array.getDimensions().size() == 2);//otherwise, CiftiFile shouldn't have called this float* ref = m_array.get(2, vector());//empty vector is intentional, only 2 dimensions exist, so no more to select from int64_t rowSize = m_array.getDimensions()[0]; int64_t colSize = m_array.getDimensions()[1]; CaretAssert(index >= 0 && index < rowSize);//because we are doing the indexing math manually for speed for (int64_t i = 0; i < colSize; ++i) { ref[index + rowSize * i] = dataIn[i]; } } CiftiOnDiskImpl::CiftiOnDiskImpl(const QString& filename) {//opens existing file for reading m_nifti.openRead(filename);//read-only, so we don't need write permission to read a cifti file if (m_nifti.getNumComponents() != 1) throw DataFileException("complex or rgb datatype found in file '" + filename + "', these are not supported in cifti"); const NiftiHeader& myHeader = m_nifti.getHeader(); int numExts = (int)myHeader.m_extensions.size(), whichExt = -1; for (int i = 0; i < numExts; ++i) { if (myHeader.m_extensions[i]->m_ecode == NIFTI_ECODE_CIFTI) { whichExt = i; break; } } if (whichExt == -1) throw DataFileException("no cifti extension found in file '" + filename + "'"); m_xml.readXML(QByteArray(myHeader.m_extensions[whichExt]->m_bytes.data(), myHeader.m_extensions[whichExt]->m_bytes.size()));//CiftiXML should be under 2GB vector dimCheck = m_nifti.getDimensions(); if (dimCheck.size() < 5) { if (m_xml.getParsedVersion() == CiftiVersion(1, 0) && dimCheck.size() == 2)//QUIRK: we wrote some cifti-1 files with the dimensions in dim[1] and dim[2] { CaretLogWarning("invalid dimensions in cifti file '" + filename + "', attempting recovery");//becase cifti-1 was 2D only, we can try to recover vector dimFix(4, 1); dimFix.push_back(dimCheck[0]); dimFix.push_back(dimCheck[1]); dimCheck = dimFix; m_nifti.overrideDimensions(dimCheck);//will actually get overridden again below since cifti-1 has reversed first dims } else { throw DataFileException("invalid dimensions in cifti file '" + filename + "'"); } } for (int i = 0; i < 4; ++i) { if (dimCheck[i] != 1) throw DataFileException("non-singular dimension #" + QString::number(i + 1) + " in cifti file '" + filename + "'"); } if (m_xml.getParsedVersion().hasReversedFirstDims()) { while (dimCheck.size() < 6) dimCheck.push_back(1);//just in case int64_t temp = dimCheck[4];//note: nifti dim[5] is the 5th dimension, index 4 in this vector dimCheck[4] = dimCheck[5]; dimCheck[5] = temp; m_nifti.overrideDimensions(dimCheck); } if (m_xml.getNumberOfDimensions() + 4 != (int)dimCheck.size()) throw DataFileException("XML does not match number of nifti dimensions in file " + filename + "'"); for (int i = 4; i < (int)dimCheck.size(); ++i) { if (m_xml.getDimensionLength(i - 4) < 0)//CiftiXML will only let this happen with cifti-1 { m_xml.getSeriesMap(i - 4).setLength(dimCheck[i]);//and only in a series map } else { if (m_xml.getDimensionLength(i - 4) != dimCheck[i]) { throw DataFileException("xml and nifti header disagree on matrix dimensions"); } } } m_matrixDims = m_xml.getDimensions(); } namespace { void warnForBadExtension(const QString& filename, const CiftiXML& myXML) { char junk[16]; int32_t intent_code = myXML.getIntentInfo(CiftiVersion(), junk);//use default writing version to check file extension, older version is missing some intent codes switch (intent_code) { default: CaretLogWarning("unhandled cifti type in extension warning check, tell the developers what you just tried to do"); CaretAssert(0);//yes, let it fall through to "unknown" in release so that it at least looks for .nii case 3000://unknown if (!filename.contains(QRegExp("\\.[^.]*\\.nii$"))) { CaretLogWarning("cifti file of nonstandard mapping combination '" + filename + "' should be saved ending in ..nii, " + "but not an already used extension (don't use dtseries, dscalar, etc)."); } if (filename.contains(QRegExp("\\.(dconn|dtseries|pconn|ptseries|dscalar|dfan|fiberTEMP|dlabel|pscalar|pdconn|dpconn|pconnseries|pconnscalar)\\.nii$"))) { CaretLogWarning("cifti file of nonstandard mapping combination '" + filename + "' should NOT be saved using an already-used cifti extension, " + "please choose a different, reasonable cifti extension ending in ..nii"); } break; case 3001: if (!filename.endsWith(".dconn.nii")) { CaretLogWarning("dense by dense cifti file '" + filename + "' should be saved ending in .dconn.nii, see wb_command -cifti-help"); } break; case 3002: if (!filename.endsWith(".dtseries.nii")) { CaretLogWarning("series by dense cifti file '" + filename + "' should be saved ending in .dtseries.nii, see wb_command -cifti-help"); } break; case 3003: if (!filename.endsWith(".pconn.nii")) { CaretLogWarning("parcels by parcels cifti file '" + filename + "' should be saved ending in .pconn.nii, see wb_command -cifti-help"); } break; case 3004: if (!filename.endsWith(".ptseries.nii")) { CaretLogWarning("series by parcels cifti file '" + filename + "' should be saved ending in .ptseries.nii, see wb_command -cifti-help"); } break; case 3006://3005 unused in practice if (!(filename.endsWith(".dscalar.nii") || filename.endsWith(".dfan.nii") || filename.endsWith(".fiberTEMP.nii"))) {//there are additional special extensions in the standard for this mapping combination (specializations of scalar maps) //also include our fiberTEMP special extension CaretLogWarning("scalars by dense cifti file '" + filename + "' should be saved ending in .dscalar.nii, see wb_command -cifti-help"); } break; case 3007: if (!filename.endsWith(".dlabel.nii")) { CaretLogWarning("labels by dense cifti file '" + filename + "' should be saved ending in .dlabel.nii, see wb_command -cifti-help"); } break; case 3008: if (!filename.endsWith(".pscalar.nii")) { CaretLogWarning("scalars by parcels cifti file '" + filename + "' should be saved ending in .pscalar.nii, see wb_command -cifti-help"); } break; case 3009: if (!filename.endsWith(".pdconn.nii")) { CaretLogWarning("dense by parcels cifti file '" + filename + "' should be saved ending in .pdconn.nii, see wb_command -cifti-help"); } break; case 3010: if (!filename.endsWith(".dpconn.nii")) { CaretLogWarning("parcels by dense cifti file '" + filename + "' should be saved ending in .dpconn.nii, see wb_command -cifti-help"); } break; case 3011: if (!filename.endsWith(".pconnseries.nii")) { CaretLogWarning("parcels by parcels by series cifti file '" + filename + "' should be saved ending in .pconnseries.nii, see wb_command -cifti-help"); } break; case 3012: if (!filename.endsWith(".pconnscalar.nii")) { CaretLogWarning("parcels by parcels by scalar cifti file '" + filename + "' should be saved ending in .pconnscalar.nii, see wb_command -cifti-help"); } break; } } } CiftiOnDiskImpl::CiftiOnDiskImpl(const QString& filename, const CiftiXML& xml, const CiftiVersion& version, const bool& swapEndian, const int16_t& datatype, const bool& rescale, const double& minval, const double& maxval) {//starts writing new file warnForBadExtension(filename, xml); NiftiHeader outHeader; if (rescale) { outHeader.setDataTypeAndScaleRange(datatype, minval, maxval); } else { outHeader.setDataType(datatype); } if (outHeader.getNumComponents() != 1) { throw DataFileException("cifti cannot be written with multi-component nifti datatypes (i.e., complex, RGB)"); } char intentName[16]; int32_t intentCode = xml.getIntentInfo(version, intentName); outHeader.setIntent(intentCode, intentName); QByteArray xmlBytes = xml.writeXMLToQByteArray(version); CaretPointer outExtension(new NiftiExtension()); outExtension->m_ecode = NIFTI_ECODE_CIFTI; int numBytes = xmlBytes.size(); outExtension->m_bytes.resize(numBytes); for (int i = 0; i < numBytes; ++i) { outExtension->m_bytes[i] = xmlBytes[i]; } outHeader.m_extensions.push_back(outExtension); m_matrixDims = xml.getDimensions(); vector niftiDims(4, 1);//the reserved space and time dims niftiDims.insert(niftiDims.end(), m_matrixDims.begin(), m_matrixDims.end()); if (version.hasReversedFirstDims()) { vector headerDims = niftiDims; while (headerDims.size() < 6) headerDims.push_back(1);//just in case int64_t temp = headerDims[4]; headerDims[4] = headerDims[5]; headerDims[5] = temp; outHeader.setDimensions(headerDims);//give the header the reversed dimensions m_nifti.writeNew(filename, outHeader, 2, true, swapEndian); m_nifti.overrideDimensions(niftiDims);//and then tell the nifti reader to use the correct dimensions } else { outHeader.setDimensions(niftiDims); m_nifti.writeNew(filename, outHeader, 2, true, swapEndian); } m_matrixDims = xml.getDimensions(); //m_xml = xml;//a second copy of the being-written xml isn't needed, but might be okay m_xml = CiftiXML();//use an empty one instead } void CiftiOnDiskImpl::close() { m_nifti.close();//lets this throw when there is a writing problem dropXML(); } void CiftiOnDiskImpl::getRow(float* dataOut, const vector& indexSelect, const bool& tolerateShortRead) const { m_nifti.readData(dataOut, 5, indexSelect, tolerateShortRead);//5 means 4 reserved (space and time) plus the first cifti dimension } void CiftiOnDiskImpl::getColumn(float* dataOut, const int64_t& index) const { CaretAssert(m_matrixDims.size() == 2);//otherwise this shouldn't be called CaretAssert(index >= 0 && index < m_matrixDims[0]); CaretLogFine("getColumn called on CiftiOnDiskImpl, this will be slow");//generate logging messages at a low priority vector indexSelect(2); indexSelect[0] = index; int64_t colLength = m_matrixDims[1]; for (int64_t i = 0; i < colLength; ++i)//assume if they really want getColumn on disk, they don't want their pagecache obliterated, so read it 1 element at a time { indexSelect[1] = i; m_nifti.readData(dataOut + i, 4, indexSelect);//4 means just the 4 reserved dimensions, so 1 element of the matrix } } void CiftiOnDiskImpl::setRow(const float* dataIn, const vector& indexSelect) { m_nifti.writeData(dataIn, 5, indexSelect); } void CiftiOnDiskImpl::setColumn(const float* dataIn, const int64_t& index) { CaretAssert(m_matrixDims.size() == 2);//otherwise this shouldn't be called CaretAssert(index >= 0 && index < m_matrixDims[0]); CaretLogFine("setColumn called on CiftiOnDiskImpl, this will be slow");//generate logging messages at a low priority vector indexSelect(2); indexSelect[0] = index; int64_t colLength = m_matrixDims[1]; for (int64_t i = 0; i < colLength; ++i)//don't do RMW, so write it 1 element at a time { indexSelect[1] = i; m_nifti.writeData(dataIn + i, 4, indexSelect);//4 means just the 4 reserved dimensions, so 1 element of the matrix } } CiftiXnatImpl::CiftiXnatImpl(const QString& url, const QString& user, const QString& pass) { CaretHttpManager::setAuthentication(url, user, pass); init(url); } CiftiXnatImpl::CiftiXnatImpl(const QString& url) { init(url); } void CiftiXnatImpl::init(const QString& url) { m_baseRequest.m_url = url; m_baseRequest.m_method = CaretHttpManager::POST_ARGUMENTS; int32_t start = url.indexOf('?'); bool foundSearchID = false; bool foundResource = false; while ((!foundSearchID) && (!foundResource)) { if (start == -1) { throw DataFileException("Error: searchID not found in URL string"); } if (url.mid(start + 1, 9) == "searchID=") { foundSearchID = true; } else if (url.mid(start + 1, 9) == "resource=") { foundResource = true; } start = url.indexOf('&', start + 1); } m_baseRequest.m_queries.push_back(make_pair(AString("type"), AString("dconn"))); CaretHttpRequest metadata = m_baseRequest; if (foundResource) { metadata.m_queries.push_back(make_pair(AString("metadata"), AString("true"))); } else { metadata.m_queries.push_back(make_pair(AString("metadata"), AString(""))); } CaretHttpResponse myResponse; CaretHttpManager::httpRequest(metadata, myResponse); if (!myResponse.m_ok) { throw DataFileException("Error opening URL, response code: " + AString::number(myResponse.m_responseCode)); } myResponse.m_body.push_back('\0');//null terminate it so we can construct an AString easily - CaretHttpManager is nice and pre-reserves this room for this purpose AString theBody(myResponse.m_body.data()); m_xml.readXML(theBody); if (m_xml.getNumberOfDimensions() != 2) { throw DataFileException("only 2D cifti are supported via URL at this time"); } if (m_xml.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::SERIES && m_xml.getDimensionLength(CiftiXML::ALONG_ROW) < 1) { CaretHttpRequest rowRequest = m_baseRequest; rowRequest.m_queries.push_back(make_pair(AString("row-index"), AString("0"))); m_xml.getSeriesMap(CiftiXML::ALONG_ROW).setLength(getSizeFromReq(rowRequest)); } if (m_xml.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::SERIES && m_xml.getDimensionLength(CiftiXML::ALONG_COLUMN) < 1) { CaretHttpRequest columnRequest = m_baseRequest; columnRequest.m_queries.push_back(make_pair(AString("column-index"), AString("0"))); m_xml.getSeriesMap(CiftiXML::ALONG_COLUMN).setLength(getSizeFromReq(columnRequest)); } CaretLogFine("Connected URL: " + url + "\nRow/Column length:" + QString::number(m_xml.getDimensionLength(CiftiXML::ALONG_ROW)) + "/" + QString::number(m_xml.getDimensionLength(CiftiXML::ALONG_COLUMN))); } void CiftiXnatImpl::getReqAsFloats(float* data, const int64_t& dataSize, CaretHttpRequest& request) const { CaretHttpResponse myResponse; CaretHttpManager::httpRequest(request, myResponse); if (!myResponse.m_ok) { throw DataFileException("Error getting row, response code: " + AString::number(myResponse.m_responseCode)); } if (myResponse.m_body.size() % 4 != 0)//expect a multiple of 4 bytes { throw DataFileException("Bad reply, number of bytes is not a multiple of 4"); } int32_t numItems = *((int32_t*)myResponse.m_body.data()); if (ByteOrderEnum::isSystemBigEndian()) { ByteSwapping::swap(numItems); } if (numItems * 4 + 4 != (int64_t)myResponse.m_body.size()) { throw DataFileException("Bad reply, number of items does not match length of reply"); } if (dataSize != numItems) { throw DataFileException("Bad reply, number of items does not match header"); } float* myPointer = (float*)(myResponse.m_body.data() + 4);//skip the first element (which is an int32) for (int i = 0; i < numItems; ++i) { data[i] = myPointer[i]; } if (ByteOrderEnum::isSystemBigEndian()) { ByteSwapping::swapArray(data, numItems); } } int64_t CiftiXnatImpl::getSizeFromReq(CaretHttpRequest& request) { CaretHttpResponse myResponse; CaretHttpManager::httpRequest(request, myResponse); if (!myResponse.m_ok) { throw DataFileException("Error getting row, response code: " + AString::number(myResponse.m_responseCode)); } if (myResponse.m_body.size() % 4 != 0)//expect a multiple of 4 bytes { throw DataFileException("Bad reply, number of bytes is not a multiple of 4"); } int32_t numItems = *((int32_t*)myResponse.m_body.data()); if (ByteOrderEnum::isSystemBigEndian()) { ByteSwapping::swap(numItems); } if (numItems * 4 + 4 != (int64_t)myResponse.m_body.size()) { throw DataFileException("Bad reply, number of items does not match length of reply"); } return numItems; } void CiftiXnatImpl::getRow(float* dataOut, const vector& indexSelect, const bool&) const { CaretAssert(indexSelect.size() == 1); CaretHttpRequest rowRequest = m_baseRequest; rowRequest.m_queries.push_back(make_pair(AString("row-index"), AString::number(indexSelect[0]))); getReqAsFloats(dataOut, m_xml.getDimensionLength(CiftiXML::ALONG_ROW), rowRequest); } void CiftiXnatImpl::getColumn(float* dataOut, const int64_t& index) const { CaretHttpRequest columnRequest = m_baseRequest; columnRequest.m_queries.push_back(make_pair(AString("column-index"), AString::number(index))); getReqAsFloats(dataOut, m_xml.getDimensionLength(CiftiXML::ALONG_COLUMN), columnRequest); } connectome-workbench-1.4.2/src/Cifti/CiftiFile.h000066400000000000000000000140451360521144700214730ustar00rootroot00000000000000#ifndef __CIFTI_FILE_H__ #define __CIFTI_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretPointer.h" #include "CiftiInterface.h" #include "CiftiXML.h" #include "CiftiXMLOld.h" #include "MultiDimIterator.h" #include "nifti1.h" #include #include namespace caret { class CiftiFile : public CiftiInterface { public: enum ENDIAN { ANY,//so that writeFile() with default endian argument can do nothing after setWritingFile with any endian argument - uses native if there is no rewrite to avoid NATIVE,//as long as there are more than two options anyway, provide a convenience option so people don't need to figure out the machine endianness for a common case LITTLE, BIG }; CiftiFile() { m_endianPref = NATIVE; setWritingDataTypeNoScaling();//default argument is float32 m_xmlBroken = false; } explicit CiftiFile(const QString &fileName);//calls openFile void openFile(const QString& fileName);//starts on-disk reading void openURL(const QString& url, const QString& user, const QString& pass);//open from XNAT void openURL(const QString& url);//same, without user/pass (or curently, reusing existing auth if the server matches void setWritingFile(const QString& fileName, const CiftiVersion& writingVersion = CiftiVersion(), const ENDIAN& endian = NATIVE);//starts on-disk writing void writeFile(const QString& fileName, const CiftiVersion& writingVersion = CiftiVersion(), const ENDIAN& endian = ANY);//leaves current state as-is, rewrites if already writing to that filename and version mismatch void close();//closes the underlying file to flush it, so that exceptions can be thrown void convertToInMemory(); QString getFileName() const { return m_fileName; } bool isInMemory() const; void getRow(float* dataOut, const std::vector& indexSelect, const bool& tolerateShortRead = false) const;//tolerateShortRead is useful for on-disk writing when it is easiest to do RMW multiple times on a new file const std::vector& getDimensions() const { return m_dims; } MultiDimIterator getIteratorOverRows() const { return MultiDimIterator(std::vector(m_dims.begin() + 1, m_dims.end())); } void getColumn(float* dataOut, const int64_t& index) const;//for 2D only, will be slow if on disk! void setCiftiXML(const CiftiXML& xml, const bool useOldMetadata = true); void setCiftiXML(const CiftiXMLOld &xml, const bool useOldMetadata = true);//set xml from old implementation void setRow(const float* dataIn, const std::vector& indexSelect); void setColumn(const float* dataIn, const int64_t& index);//for 2D only, will be slow if on disk! ///data type and scaling options - should be set before setRow, etc, to avoid rewriting of file void setWritingDataTypeNoScaling(const int16_t& type = NIFTI_TYPE_FLOAT32); void setWritingDataTypeAndScaling(const int16_t& type, const double& minval, const double& maxval); void getRow(float* dataOut, const int64_t& index, const bool& tolerateShortRead) const;//backwards compatibility for old CiftiFile/CiftiInterface void getRow(float* dataOut, const int64_t& index) const; int64_t getNumberOfRows() const; int64_t getNumberOfColumns() const; void setRow(const float* dataIn, const int64_t& index);//backwards compatibility for old CiftiFile void forgetMapping(const int& direction);//HACK: reduce memory usage by modifying the XML class ReadImplInterface { public: virtual void getRow(float* dataOut, const std::vector& indexSelect, const bool& tolerateShortRead) const = 0; virtual void getColumn(float* dataOut, const int64_t& index) const = 0; virtual bool isInMemory() const { return false; } virtual ~ReadImplInterface(); }; //assume if you can write to it, you can also read from it class WriteImplInterface : public ReadImplInterface { public: virtual void setRow(const float* dataIn, const std::vector& indexSelect) = 0; virtual void setColumn(const float* dataIn, const int64_t& index) = 0; virtual void close() {} virtual ~WriteImplInterface(); }; private: std::vector m_dims; CaretPointer m_writingImpl;//this will be equal to m_readingImpl when non-null CaretPointer m_readingImpl; QString m_writingFile, m_fileName; //CiftiXML m_xml;//uncomment when we drop CiftiInterface CiftiVersion m_onDiskVersion; ENDIAN m_endianPref; bool m_doWriteScaling; int16_t m_writingDataType; double m_minScalingVal, m_maxScalingVal; bool m_xmlBroken;//sentinel for forgetMapping hack void verifyWriteImpl(); static void copyImplData(const ReadImplInterface* from, WriteImplInterface* to, const std::vector& dims); }; } #endif //__CIFTI_FILE_H__ connectome-workbench-1.4.2/src/Cifti/CiftiInterface.cxx000066400000000000000000000431721360521144700230720ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiInterface.h" #include "DataFileException.h" #include #include using namespace caret; using namespace std; CiftiInterface::CiftiInterface() { m_dataRangeValid = false; } void CiftiInterface::invalidateDataRange() { m_dataRangeValid = false; } bool CiftiInterface::getDataRangeFromAllMaps(float& minOut, float& maxOut) const { if (!m_dataRangeValid) { int64_t numRows = getNumberOfRows(), rowSize = getNumberOfColumns(); if (numRows <= 0 || rowSize <= 0) { maxOut = numeric_limits::max(); minOut = -maxOut; return false; } m_dataRangeMin = numeric_limits::max(); m_dataRangeMax = -m_dataRangeMin; vector tempRow(rowSize); for (int64_t row = 0; row < numRows; ++row) { getRow(tempRow.data(), row); for (int64_t i = 0; i < rowSize; ++i) { if (tempRow[i] > m_dataRangeMax) m_dataRangeMax = tempRow[i]; if (tempRow[i] < m_dataRangeMin) m_dataRangeMin = tempRow[i]; } } m_dataRangeValid = true; } minOut = m_dataRangeMin; maxOut = m_dataRangeMax; return true; } CiftiXMLOld CiftiInterface::getCiftiXMLOld() const { CiftiXMLOld ret; if (m_xml.getNumberOfDimensions() != 2) throw DataFileException("can't convert to old XML because number of dimensions isn't 2"); ret.readXML(m_xml.writeXMLToString(CiftiVersion(1, 0))); if (ret.getDimensionLength(CiftiXMLOld::ALONG_ROW) < 1) { ret.setRowNumberOfTimepoints(m_xml.getDimensionLength(CiftiXML::ALONG_ROW)); } if (ret.getDimensionLength(CiftiXMLOld::ALONG_COLUMN) < 1) { ret.setColumnNumberOfTimepoints(m_xml.getDimensionLength(CiftiXML::ALONG_COLUMN)); } return ret; } bool CiftiInterface::checkColumnIndex(int64_t index) const { if (index < 0 || index >= getNumberOfColumns()) { return false; } return true; } bool CiftiInterface::checkRowIndex(int64_t index) const { if (index < 0 || index >= getNumberOfRows()) { return false; } return true; } bool CiftiInterface::getColumnFromNode(float* columnOut, const int64_t node, const caret::StructureEnum::Enum structure) const { int64_t myIndex = -1; const CiftiMappingType& myGenMap = *(m_xml.getMap(CiftiXML::ALONG_ROW)); if (myGenMap.getType() == CiftiMappingType::BRAIN_MODELS) { const CiftiBrainModelsMap& myMap = (const CiftiBrainModelsMap&)myGenMap; myIndex = myMap.getIndexForNode(node, structure); } else if (myGenMap.getType() == CiftiMappingType::PARCELS) { const CiftiParcelsMap& myMap = (const CiftiParcelsMap&)myGenMap; myIndex = myMap.getIndexForNode(node, structure); } if (!checkColumnIndex(myIndex)) return false; getColumn(columnOut, myIndex); return true; } bool CiftiInterface::getColumnFromVoxel(float* columnOut, const int64_t* ijk) const { int64_t myIndex = -1; const CiftiMappingType& myGenMap = *(m_xml.getMap(CiftiXML::ALONG_ROW)); if (myGenMap.getType() == CiftiMappingType::BRAIN_MODELS) { const CiftiBrainModelsMap& myMap = (const CiftiBrainModelsMap&)myGenMap; myIndex = myMap.getIndexForVoxel(ijk); } else if (myGenMap.getType() == CiftiMappingType::PARCELS) { const CiftiParcelsMap& myMap = (const CiftiParcelsMap&)myGenMap; myIndex = myMap.getIndexForVoxel(ijk); } if (!checkColumnIndex(myIndex)) return false; getColumn(columnOut, myIndex); return true; } bool CiftiInterface::getRowFromNode(float* rowOut, const int64_t node, const caret::StructureEnum::Enum structure) const { int64_t myIndex = -1; const CiftiMappingType& myGenMap = *(m_xml.getMap(CiftiXML::ALONG_COLUMN)); if (myGenMap.getType() == CiftiMappingType::BRAIN_MODELS) { const CiftiBrainModelsMap& myMap = (const CiftiBrainModelsMap&)myGenMap; myIndex = myMap.getIndexForNode(node, structure); } else if (myGenMap.getType() == CiftiMappingType::PARCELS) { const CiftiParcelsMap& myMap = (const CiftiParcelsMap&)myGenMap; myIndex = myMap.getIndexForNode(node, structure); } if (!checkRowIndex(myIndex)) return false; getRow(rowOut, myIndex); return true; } bool CiftiInterface::getRowFromNode(float* rowOut, const int64_t node, const caret::StructureEnum::Enum structure, int64_t& rowIndexOut) const { rowIndexOut = -1; const CiftiMappingType& myGenMap = *(m_xml.getMap(CiftiXML::ALONG_COLUMN)); if (myGenMap.getType() == CiftiMappingType::BRAIN_MODELS) { const CiftiBrainModelsMap& myMap = (const CiftiBrainModelsMap&)myGenMap; rowIndexOut = myMap.getIndexForNode(node, structure); } else if (myGenMap.getType() == CiftiMappingType::PARCELS) { const CiftiParcelsMap& myMap = (const CiftiParcelsMap&)myGenMap; rowIndexOut = myMap.getIndexForNode(node, structure); } if (!checkRowIndex(rowIndexOut)) return false; getRow(rowOut, rowIndexOut); return true; } bool CiftiInterface::getRowFromVoxel(float* rowOut, const int64_t* ijk) const { int64_t myIndex = -1; const CiftiMappingType& myGenMap = *(m_xml.getMap(CiftiXML::ALONG_COLUMN)); if (myGenMap.getType() == CiftiMappingType::BRAIN_MODELS) { const CiftiBrainModelsMap& myMap = (const CiftiBrainModelsMap&)myGenMap; myIndex = myMap.getIndexForVoxel(ijk); } else if (myGenMap.getType() == CiftiMappingType::PARCELS) { const CiftiParcelsMap& myMap = (const CiftiParcelsMap&)myGenMap; myIndex = myMap.getIndexForVoxel(ijk); } if (!checkRowIndex(myIndex)) return false; getRow(rowOut, myIndex); return true; } bool CiftiInterface::getColumnFromVoxelCoordinate(float* columnOut, const float* xyz) const { int64_t myIndex = -1; int64_t ijk[3]; const CiftiMappingType& myGenMap = *(m_xml.getMap(CiftiXML::ALONG_ROW)); if (myGenMap.getType() == CiftiMappingType::BRAIN_MODELS) { const CiftiBrainModelsMap& myMap = (const CiftiBrainModelsMap&)myGenMap; myMap.getVolumeSpace().enclosingVoxel(xyz, ijk); myIndex = myMap.getIndexForVoxel(ijk); } else if (myGenMap.getType() == CiftiMappingType::PARCELS) { const CiftiParcelsMap& myMap = (const CiftiParcelsMap&)myGenMap; myMap.getVolumeSpace().enclosingVoxel(xyz, ijk); myIndex = myMap.getIndexForVoxel(ijk); } if (!checkColumnIndex(myIndex)) return false; getColumn(columnOut, myIndex); return true; } bool CiftiInterface::getRowFromVoxelCoordinate(float* rowOut, const float* xyz) const { int64_t myIndex = -1; int64_t ijk[3]; const CiftiMappingType& myGenMap = *(m_xml.getMap(CiftiXML::ALONG_COLUMN)); if (myGenMap.getType() == CiftiMappingType::BRAIN_MODELS) { const CiftiBrainModelsMap& myMap = (const CiftiBrainModelsMap&)myGenMap; myMap.getVolumeSpace().enclosingVoxel(xyz, ijk); myIndex = myMap.getIndexForVoxel(ijk); } else if (myGenMap.getType() == CiftiMappingType::PARCELS) { const CiftiParcelsMap& myMap = (const CiftiParcelsMap&)myGenMap; myMap.getVolumeSpace().enclosingVoxel(xyz, ijk); myIndex = myMap.getIndexForVoxel(ijk); } if (!checkRowIndex(myIndex)) return false; getRow(rowOut, myIndex); return true; } bool CiftiInterface::getRowFromVoxelCoordinate(float* rowOut, const float* xyz, int64_t& rowIndexOut) const { rowIndexOut = -1; int64_t ijk[3]; const CiftiMappingType& myGenMap = *(m_xml.getMap(CiftiXML::ALONG_COLUMN)); if (myGenMap.getType() == CiftiMappingType::BRAIN_MODELS) { const CiftiBrainModelsMap& myMap = (const CiftiBrainModelsMap&)myGenMap; myMap.getVolumeSpace().enclosingVoxel(xyz, ijk); rowIndexOut = myMap.getIndexForVoxel(ijk); } else if (m_xml.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::PARCELS) { const CiftiParcelsMap& myMap = (const CiftiParcelsMap&)myGenMap; myMap.getVolumeSpace().enclosingVoxel(xyz, ijk); rowIndexOut = myMap.getIndexForVoxel(ijk); } if (!checkRowIndex(rowIndexOut)) return false; getRow(rowOut, rowIndexOut); return true; } bool CiftiInterface::getColumnFromTimepoint(float* columnOut, const float seconds) const { const CiftiMappingType& myGenMap = *(m_xml.getMap(CiftiXML::ALONG_ROW)); if (myGenMap.getType() != CiftiMappingType::SERIES) return false; const CiftiSeriesMap& myMap = (const CiftiSeriesMap&)myGenMap; int64_t myIndex = (int64_t)floor((seconds - myMap.getStart()) / myMap.getStep() + 0.5f); if (!checkColumnIndex(myIndex)) return false; getColumn(columnOut, myIndex); return true; } //column and frame are the same value currently, this function exists only //to keep the concepts of frame and time separate from being conflated bool CiftiInterface::getColumnFromFrame(float* columnOut, const int frame) const { if(!checkColumnIndex(frame)) { return false; } getColumn(columnOut, frame); return true; } bool CiftiInterface::getRowFromTimepoint(float* rowOut, const float seconds) const { const CiftiMappingType& myGenMap = *(m_xml.getMap(CiftiXML::ALONG_COLUMN)); if (myGenMap.getType() != CiftiMappingType::SERIES) return false; const CiftiSeriesMap& myMap = (const CiftiSeriesMap&)myGenMap; int64_t myIndex = (int64_t)floor((seconds - myMap.getStart()) / myMap.getStep() + 0.5f); if (!checkColumnIndex(myIndex)) return false; getRow(rowOut, myIndex); return true; } bool CiftiInterface::getSurfaceMapForRows(vector& mappingOut, const StructureEnum::Enum structure) const { if (m_xml.getMappingType(CiftiXML::ALONG_ROW) != CiftiMappingType::BRAIN_MODELS) return false; mappingOut = m_xml.getBrainModelsMap(CiftiXML::ALONG_ROW).getSurfaceMap(structure);//will throw on structure missing return true; } bool CiftiInterface::getSurfaceMapForColumns(vector& mappingOut, const StructureEnum::Enum structure) const { if (m_xml.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) return false; mappingOut = m_xml.getBrainModelsMap(CiftiXML::ALONG_COLUMN).getSurfaceMap(structure);//will throw on structure missing return true; } bool CiftiInterface::getVolumeMapForRows(vector& mappingOut) const { if (m_xml.getMappingType(CiftiXML::ALONG_ROW) != CiftiMappingType::BRAIN_MODELS) return false; mappingOut = m_xml.getBrainModelsMap(CiftiXML::ALONG_ROW).getFullVolumeMap(); return true; } bool CiftiInterface::getVolumeMapForColumns(vector& mappingOut) const { if (m_xml.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) return false; mappingOut = m_xml.getBrainModelsMap(CiftiXML::ALONG_COLUMN).getFullVolumeMap(); return true; } int64_t CiftiInterface::getRowSurfaceNumberOfNodes(const StructureEnum::Enum structure) const { if (m_xml.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::BRAIN_MODELS) { return m_xml.getBrainModelsMap(CiftiXML::ALONG_ROW).getSurfaceNumberOfNodes(structure);//will throw on structure missing } if (m_xml.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::PARCELS) { return m_xml.getParcelsMap(CiftiXML::ALONG_ROW).getSurfaceNumberOfNodes(structure); } return -1; // if (m_xml.getMappingType(CiftiXML::ALONG_ROW) != CiftiMappingType::BRAIN_MODELS) return -1; // return m_xml.getBrainModelsMap(CiftiXML::ALONG_ROW).getSurfaceNumberOfNodes(structure);//will throw on structure missing } int64_t CiftiInterface::getColumnSurfaceNumberOfNodes(const StructureEnum::Enum structure) const { if (m_xml.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::BRAIN_MODELS) { return m_xml.getBrainModelsMap(CiftiXML::ALONG_COLUMN).getSurfaceNumberOfNodes(structure);//will throw on structure missing } if (m_xml.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::PARCELS) { return m_xml.getParcelsMap(CiftiXML::ALONG_COLUMN).getSurfaceNumberOfNodes(structure); } return -1; // if (m_xml.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) return -1; // return m_xml.getBrainModelsMap(CiftiXML::ALONG_COLUMN).getSurfaceNumberOfNodes(structure);//will throw on structure missing } bool CiftiInterface::getRowTimestep(float& seconds) const { if (m_xml.getMappingType(CiftiXML::ALONG_ROW) != CiftiMappingType::SERIES) return false; seconds = m_xml.getSeriesMap(CiftiXML::ALONG_ROW).getStep(); return true; } bool CiftiInterface::getColumnTimestep(float& seconds) const { if (m_xml.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::SERIES) return false; seconds = m_xml.getSeriesMap(CiftiXML::ALONG_COLUMN).getStep(); return true; } bool CiftiInterface::getVolumeAttributesForPlumb(VolumeSpace::OrientTypes orientOut[3], int64_t dimensionsOut[3], float originOut[3], float spacingOut[3]) const { for (int i = 0; i < m_xml.getNumberOfDimensions(); ++i) { if (m_xml.getMappingType(i) == CiftiMappingType::BRAIN_MODELS) { const CiftiBrainModelsMap& myMap = m_xml.getBrainModelsMap(i); if (myMap.hasVolumeData()) { if (!myMap.getVolumeSpace().isPlumb()) return false; myMap.getVolumeSpace().getOrientAndSpacingForPlumb(orientOut, spacingOut, originOut); const int64_t* dims = myMap.getVolumeSpace().getDims(); dimensionsOut[0] = dims[0]; dimensionsOut[1] = dims[1]; dimensionsOut[2] = dims[2]; return true; } } else if (m_xml.getMappingType(i) == CiftiMappingType::PARCELS) { const CiftiParcelsMap& myMap = m_xml.getParcelsMap(i); if (myMap.hasVolumeData()) { if (!myMap.getVolumeSpace().isPlumb()) return false; myMap.getVolumeSpace().getOrientAndSpacingForPlumb(orientOut, spacingOut, originOut); const int64_t* dims = myMap.getVolumeSpace().getDims(); dimensionsOut[0] = dims[0]; dimensionsOut[1] = dims[1]; dimensionsOut[2] = dims[2]; return true; } } } return false; } bool CiftiInterface::hasRowVolumeData() const { if (m_xml.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::BRAIN_MODELS) { return m_xml.getBrainModelsMap(CiftiXML::ALONG_ROW).hasVolumeData(); } else if (m_xml.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::PARCELS) { return m_xml.getParcelsMap(CiftiXML::ALONG_ROW).hasVolumeData(); } return false; } bool CiftiInterface::hasColumnVolumeData() const { if (m_xml.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::BRAIN_MODELS) { return m_xml.getBrainModelsMap(CiftiXML::ALONG_COLUMN).hasVolumeData(); } else if (m_xml.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::PARCELS) { return m_xml.getParcelsMap(CiftiXML::ALONG_COLUMN).hasVolumeData(); } return false; } bool CiftiInterface::hasRowSurfaceData(const StructureEnum::Enum structure) const { if (m_xml.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::BRAIN_MODELS) { return m_xml.getBrainModelsMap(CiftiXML::ALONG_ROW).hasSurfaceData(structure); } else if (m_xml.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::PARCELS) { return m_xml.getParcelsMap(CiftiXML::ALONG_ROW).hasSurfaceData(structure); } return false; } bool CiftiInterface::hasColumnSurfaceData(const StructureEnum::Enum structure) const { if (m_xml.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::BRAIN_MODELS) { return m_xml.getBrainModelsMap(CiftiXML::ALONG_COLUMN).hasSurfaceData(structure); } else if (m_xml.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::PARCELS) { return m_xml.getParcelsMap(CiftiXML::ALONG_COLUMN).hasSurfaceData(structure); } return false; } AString CiftiInterface::getMapNameForColumnIndex(const int& index) const { if (m_xml.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::SCALARS) { return m_xml.getScalarsMap(CiftiXML::ALONG_COLUMN).getMapName(index); } else if (m_xml.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::LABELS) { return m_xml.getLabelsMap(CiftiXML::ALONG_COLUMN).getMapName(index); } return ""; } AString CiftiInterface::getMapNameForRowIndex(const int& index) const { if (m_xml.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::SCALARS) { return m_xml.getScalarsMap(CiftiXML::ALONG_ROW).getMapName(index); } else if (m_xml.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::LABELS) { return m_xml.getLabelsMap(CiftiXML::ALONG_ROW).getMapName(index); } return ""; } CiftiInterface::~CiftiInterface() { } connectome-workbench-1.4.2/src/Cifti/CiftiInterface.h000066400000000000000000000143661360521144700225220ustar00rootroot00000000000000#ifndef __CIFTI_INTERFACE_H__ #define __CIFTI_INTERFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiXML.h" #include "CiftiXMLOld.h" namespace caret { class CiftiInterface { mutable bool m_dataRangeValid; mutable float m_dataRangeMin, m_dataRangeMax; protected: CiftiXML m_xml; CiftiInterface(); public: bool checkRowIndex(int64_t index) const; bool checkColumnIndex(int64_t index) const; ///get a row virtual void getRow(float* rowOut, const int64_t& rowIndex) const = 0; ///get a column virtual void getColumn(float* columnOut, const int64_t& columnIndex) const = 0; ///get row size virtual int64_t getNumberOfColumns() const = 0; ///get column size virtual int64_t getNumberOfRows() const = 0; ///get a reference to the XML structure const CiftiXML& getCiftiXML() const { return m_xml; } ///get the old XML structure CiftiXMLOld getCiftiXMLOld() const; ///get a row by surface and node - returns false if not found in mapping bool getRowFromNode(float* rowOut, const int64_t node, const StructureEnum::Enum structure) const; ///get a row by surface and node - returns false if not found in mapping bool getRowFromNode(float* rowOut, const int64_t node, const StructureEnum::Enum structure, int64_t& rowIndexOut) const; ///get a column by surface and node - returns false if not found in mapping bool getColumnFromNode(float* columnOut, const int64_t node, const StructureEnum::Enum structure) const; ///get a row by voxel index - returns false if not found in mapping bool getRowFromVoxel(float* rowOut, const int64_t* ijk) const; ///get a column by voxel index - returns false if not found in mapping bool getColumnFromVoxel(float* columnOut, const int64_t* ijk) const; ///get a row by voxel coordinate - returns false if not found in mapping bool getRowFromVoxelCoordinate(float* rowOut, const float* xyz) const; ///get a row by voxel coordinate - returns false if not found in mapping bool getRowFromVoxelCoordinate(float* rowOut, const float* xyz, int64_t& rowIndexOut) const; ///get a column by voxel coordinate - returns false if not found in mapping bool getColumnFromVoxelCoordinate(float* columnOut, const float* xyz) const; ///get a row by timepoint bool getRowFromTimepoint(float* rowOut, const float seconds) const; ///get a column by timepoint bool getColumnFromTimepoint(float* columnOut, const float seconds) const; ///get a column by frame bool getColumnFromFrame(float* columnOut, const int frame) const; ///get data range bool getDataRangeFromAllMaps(float& minOut, float& maxOut) const; ///called when something changes the data void invalidateDataRange(); ///get the mapping for a surface in rows, returns false and empty vector if not found bool getSurfaceMapForRows(std::vector& mappingOut, const StructureEnum::Enum structure) const; ///get the mapping for a surface in columns, returns false and empty vector if not found bool getSurfaceMapForColumns(std::vector& mappingOut, const StructureEnum::Enum structure) const; ///get the mapping for a surface in rows, returns false and empty vector if not found bool getVolumeMapForRows(std::vector& mappingOut) const; ///get the mapping for a surface in columns, returns false and empty vector if not found bool getVolumeMapForColumns(std::vector& mappingOut) const; ///get the original number of nodes of the surfaces used to make this cifti, for rows int64_t getRowSurfaceNumberOfNodes(const StructureEnum::Enum structure) const; ///get the original number of nodes of the surfaces used to make this cifti, for columns int64_t getColumnSurfaceNumberOfNodes(const StructureEnum::Enum structure) const; ///get the timestep for rows, returns false if not timeseries bool getRowTimestep(float& seconds) const; ///get the timestep for columns, returns false if not timeseries bool getColumnTimestep(float& seconds) const; ///get dimensions, spacing, origin for the volume attribute - returns false if not plumb - NOTE: only uses the volume space of the first dimension that has one bool getVolumeAttributesForPlumb(VolumeSpace::OrientTypes orientOut[3], int64_t dimensionsOut[3], float originOut[3], float spacingOut[3]) const; bool hasRowVolumeData() const; bool hasColumnVolumeData() const; bool hasRowSurfaceData(const StructureEnum::Enum structure) const; bool hasColumnSurfaceData(const StructureEnum::Enum structure) const; ///get the map name for an index along a column AString getMapNameForColumnIndex(const int& index) const; ///get the map name for an index along a row AString getMapNameForRowIndex(const int& index) const; virtual ~CiftiInterface(); }; } #endif //__CIFTI_INTERFACE_H__ connectome-workbench-1.4.2/src/Cifti/CiftiLabelsMap.cxx000066400000000000000000000254231360521144700230310ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiLabelsMap.h" #include "CaretAssert.h" #include "DataFileException.h" #include "CaretLogger.h" using namespace caret; void CiftiLabelsMap::clear() { m_maps.clear(); } GiftiLabelTable* CiftiLabelsMap::getMapLabelTable(const int64_t& index) const { CaretAssertVectorIndex(m_maps, index); return &(m_maps[index].m_labelTable); } GiftiMetaData* CiftiLabelsMap::getMapMetadata(const int64_t& index) const { CaretAssertVectorIndex(m_maps, index); return &(m_maps[index].m_metaData); } const QString& CiftiLabelsMap::getMapName(const int64_t& index) const { CaretAssertVectorIndex(m_maps, index); return m_maps[index].m_name; } int64_t CiftiLabelsMap::getIndexFromNumberOrName(const QString& numberOrName) const { bool ok = false; int64_t ret = numberOrName.toLongLong(&ok) - 1;//quirk: use string "1" as the first index if (ok) { if (ret < 0 || ret >= getLength()) return -1;//if it is a number, do not try to use it as a name, under any circumstances return ret; } else { int64_t length = getLength(); for (int64_t i = 0; i < length; ++i) { if (numberOrName == getMapName(i)) return i; } return -1; } } void CiftiLabelsMap::setLength(const int64_t& length) { CaretAssert(length > 0); m_maps.resize(length); } void CiftiLabelsMap::setMapName(const int64_t& index, const QString& mapName) const { CaretAssertVectorIndex(m_maps, index); m_maps[index].m_name = mapName; m_namesModified = true; } bool CiftiLabelsMap::approximateMatch(const CiftiMappingType& rhs, QString* explanation) const { switch (rhs.getType()) { case SCALARS: case SERIES://maybe? case LABELS: if (getLength() != rhs.getLength()) { if (explanation != NULL) *explanation = "mappings have different length"; return false; } else return true; default: if (explanation != NULL) *explanation = CiftiMappingType::mappingTypeToName(rhs.getType()) + " mapping never matches " + CiftiMappingType::mappingTypeToName(getType()); return false; } } bool CiftiLabelsMap::operator==(const CiftiMappingType& rhs) const { if (rhs.getType() != getType()) return false; const CiftiLabelsMap& myrhs = dynamic_cast(rhs); return (m_maps == myrhs.m_maps); } bool CiftiLabelsMap::LabelMap::operator==(const LabelMap& rhs) const { if (m_name != rhs.m_name) return false; if (m_labelTable != rhs.m_labelTable) return false; return (m_metaData == rhs.m_metaData); } void CiftiLabelsMap::readXML1(QXmlStreamReader& xml) { CaretLogFiner("parsing nonstandard labels mapping type in cifti-1"); clear(); for (xml.readNext(); !xml.atEnd() && !xml.isEndElement(); xml.readNext()) { switch (xml.tokenType()) { case QXmlStreamReader::StartElement: { if (xml.name() != "NamedMap") { throw DataFileException("unexpected element in labels map: " + xml.name().toString()); } LabelMap tempMap; tempMap.readXML1(xml); if (xml.hasError()) return; m_maps.push_back(tempMap); break; } default: break; } } } void CiftiLabelsMap::readXML2(QXmlStreamReader& xml) { clear(); for (xml.readNext(); !xml.atEnd() && !xml.isEndElement(); xml.readNext()) { switch (xml.tokenType()) { case QXmlStreamReader::StartElement: { if (xml.name() != "NamedMap") { throw DataFileException("unexpected element in labels map: " + xml.name().toString()); } LabelMap tempMap; tempMap.readXML2(xml); if (xml.hasError()) return; m_maps.push_back(tempMap); break; } default: break; } } } void CiftiLabelsMap::LabelMap::readXML1(QXmlStreamReader& xml) { bool haveName = false, haveTable = false, haveMetaData = false; for (xml.readNext(); !xml.atEnd() && !xml.isEndElement(); xml.readNext()) { switch (xml.tokenType()) { case QXmlStreamReader::StartElement: { QStringRef name = xml.name(); if (name == "MetaData") { if (haveMetaData) { throw DataFileException("MetaData specified multiple times in one NamedMap"); } m_metaData.readCiftiXML1(xml); if (xml.hasError()) return; haveMetaData = true; } else if (name == "LabelTable") { if (haveTable) { throw DataFileException("LabelTable specified multiple times in one NamedMap"); } m_labelTable.readFromQXmlStreamReader(xml); if (xml.hasError()) return; haveTable = true; } else if (name == "MapName") { if (haveName) { throw DataFileException("MapName specified multiple times in one NamedMap"); } m_name = xml.readElementText();//raises error if element encountered if (xml.hasError()) return; haveName = true; } else { throw DataFileException("unexpected element in NamedMap: " + name.toString()); } break; } default: break; } } if (!haveName) { throw DataFileException("NamedMap missing required child element MapName"); } if (!haveTable) { throw DataFileException("NamedMap in labels mapping missing required child element LabelTable"); } } void CiftiLabelsMap::LabelMap::readXML2(QXmlStreamReader& xml) { bool haveName = false, haveTable = false, haveMetaData = false; for (xml.readNext(); !xml.atEnd() && !xml.isEndElement(); xml.readNext()) { switch (xml.tokenType()) { case QXmlStreamReader::StartElement: { QStringRef name = xml.name(); if (name == "MetaData") { if (haveMetaData) { throw DataFileException("MetaData specified multiple times in one NamedMap"); } m_metaData.readCiftiXML2(xml); if (xml.hasError()) return; haveMetaData = true; } else if (name == "LabelTable") { if (haveTable) { throw DataFileException("LabelTable specified multiple times in one NamedMap"); } m_labelTable.readFromQXmlStreamReader(xml); if (xml.hasError()) return; haveTable = true; } else if (name == "MapName") { if (haveName) { throw DataFileException("MapName specified multiple times in one NamedMap"); } m_name = xml.readElementText();//raises error if element encountered if (xml.hasError()) return; haveName = true; } else { throw DataFileException("unexpected element in NamedMap: " + name.toString()); } break; } default: break; } } if (!haveName) { throw DataFileException("NamedMap missing required child element MapName"); } if (!haveTable) { throw DataFileException("NamedMap in labels mapping missing required child element LabelTable"); } } void CiftiLabelsMap::writeXML1(QXmlStreamWriter& xml) const { CaretLogFiner("writing nonstandard labels mapping type in cifti-1"); xml.writeAttribute("IndicesMapToDataType", "CIFTI_INDEX_TYPE_LABELS"); int64_t numMaps = (int64_t)m_maps.size(); for (int64_t i = 0; i < numMaps; ++i) { xml.writeStartElement("NamedMap"); xml.writeTextElement("MapName", m_maps[i].m_name); m_maps[i].m_metaData.writeCiftiXML1(xml); m_maps[i].m_labelTable.writeAsXML(xml); xml.writeEndElement(); } } void CiftiLabelsMap::writeXML2(QXmlStreamWriter& xml) const { int64_t numMaps = (int64_t)m_maps.size(); xml.writeAttribute("IndicesMapToDataType", "CIFTI_INDEX_TYPE_LABELS"); for (int64_t i = 0; i < numMaps; ++i) { xml.writeStartElement("NamedMap"); xml.writeTextElement("MapName", m_maps[i].m_name); m_maps[i].m_metaData.writeCiftiXML2(xml); m_maps[i].m_labelTable.writeAsXML(xml); xml.writeEndElement(); } } //support for internal objects that track modified status CiftiLabelsMap::CiftiLabelsMap() { m_namesModified = false; } CiftiLabelsMap::CiftiLabelsMap(const CiftiLabelsMap& rhs) { m_namesModified = false; m_maps = rhs.m_maps;//no idea what happens to the modification status of members here } CiftiLabelsMap& CiftiLabelsMap::operator=(const CiftiLabelsMap& rhs) { m_namesModified = false; m_maps = rhs.m_maps;//ditto return *this; } bool CiftiLabelsMap::mutablesModified() const { if (m_namesModified) return true; for (int64_t i = 0; i < getLength(); ++i) { if (getMapLabelTable(i)->isModified()) return true; if (getMapMetadata(i)->isModified()) return true; } return false; } void CiftiLabelsMap::clearMutablesModified() const { m_namesModified = false; for (int64_t i = 0; i < getLength(); ++i) { getMapLabelTable(i)->clearModified(); getMapMetadata(i)->clearModified(); } } connectome-workbench-1.4.2/src/Cifti/CiftiLabelsMap.h000066400000000000000000000060341360521144700224530ustar00rootroot00000000000000#ifndef __CIFTI_LABELS_MAP_H__ #define __CIFTI_LABELS_MAP_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiMappingType.h" #include "CaretPointer.h" #include "GiftiMetaData.h" #include "GiftiLabelTable.h" #include #include namespace caret { class CiftiLabelsMap : public CiftiMappingType { public: CiftiLabelsMap(); CiftiLabelsMap(const CiftiLabelsMap& rhs); CiftiLabelsMap& operator=(const CiftiLabelsMap& rhs); GiftiMetaData* getMapMetadata(const int64_t& index) const;//HACK: allow modification of label table and metadata within XML without setting the xml on a file again GiftiLabelTable* getMapLabelTable(const int64_t& index) const; const QString& getMapName(const int64_t& index) const; int64_t getIndexFromNumberOrName(const QString& numberOrName) const; QString getIndexName(const int64_t& index) const { return getMapName(index); } void setMapName(const int64_t& index, const QString& mapName) const;//HACK: ditto void setLength(const int64_t& length); void clear(); CiftiMappingType* clone() const { return new CiftiLabelsMap(*this); } MappingType getType() const { return LABELS; } int64_t getLength() const { return m_maps.size(); } bool operator==(const CiftiMappingType& rhs) const; bool approximateMatch(const CiftiMappingType& rhs, QString* explanation = NULL) const; void readXML1(QXmlStreamReader& xml); void readXML2(QXmlStreamReader& xml); void writeXML1(QXmlStreamWriter& xml) const; void writeXML2(QXmlStreamWriter& xml) const; bool mutablesModified() const; void clearMutablesModified() const; private: mutable bool m_namesModified; struct LabelMap { mutable QString m_name;//we need a better way to change metadata in an in-memory file mutable GiftiMetaData m_metaData;//ditto mutable GiftiLabelTable m_labelTable;//ditto bool operator==(const LabelMap& rhs) const; void readXML1(QXmlStreamReader& xml); void readXML2(QXmlStreamReader& xml); }; std::vector m_maps; }; } #endif //__CIFTI_LABELS_MAP_H__ connectome-workbench-1.4.2/src/Cifti/CiftiMappingType.cxx000066400000000000000000000036621360521144700234270ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiMappingType.h" #include "CaretAssert.h" using namespace caret; CiftiMappingType::~CiftiMappingType() {//to ensure that the class's vtable gets defined in an object file } int64_t CiftiMappingType::getIndexFromNumberOrName(const QString& numberOrName) const { bool ok = false; int64_t ret = numberOrName.toLongLong(&ok) - 1;//quirk: use string "1" as the first index if (!ok) return -1; if (ret < 0 || ret >= getLength()) return -1; return ret; } QString CiftiMappingType::getIndexName(const int64_t&) const { return ""; } QString CiftiMappingType::mappingTypeToName(const CiftiMappingType::MappingType& type) { switch (type) { case BRAIN_MODELS: return "BRAIN_MODELS"; case PARCELS: return "PARCELS"; case SERIES: return "SERIES"; case SCALARS: return "SCALARS"; case LABELS: return "LABELS"; } CaretAssert(0); return ""; } bool CiftiMappingType::mutablesModified() const { return false; } void CiftiMappingType::clearMutablesModified() const { //nothing } connectome-workbench-1.4.2/src/Cifti/CiftiMappingType.h000066400000000000000000000053531360521144700230530ustar00rootroot00000000000000#ifndef __CIFTI_MAPPING_TYPE_H__ #define __CIFTI_MAPPING_TYPE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "stdint.h" #include #include #include namespace caret { class CiftiMappingType { public: enum MappingType { BRAIN_MODELS = 1,//compatibility values with old XML enum, in case someone uses the wrong enum PARCELS = 3,//fibers doesn't exist in 2.0 SERIES = 4, SCALARS = 5, LABELS = 6 }; virtual CiftiMappingType* clone() const = 0;//make a copy, preserving the actual type - NOTE: this returns a dynamic allocation that is not owned by anything virtual MappingType getType() const = 0; virtual int64_t getLength() const = 0; virtual int64_t getIndexFromNumberOrName(const QString& numberOrName) const; virtual QString getIndexName(const int64_t& index) const; virtual bool operator==(const CiftiMappingType& rhs) const = 0;//used to check for merging mappings when writing the XML - must compare EVERYTHING that goes into the XML bool operator!=(const CiftiMappingType& rhs) const { return !((*this) == rhs); } virtual bool approximateMatch(const CiftiMappingType& rhs, QString* explanation = NULL) const = 0;//check if things like doing index-wise math would make sense virtual void readXML1(QXmlStreamReader& xml) = 0;//mainly to shorten the type-specific code in CiftiXML virtual void readXML2(QXmlStreamReader& xml) = 0; virtual void writeXML1(QXmlStreamWriter& xml) const = 0; virtual void writeXML2(QXmlStreamWriter& xml) const = 0; virtual bool mutablesModified() const; virtual void clearMutablesModified() const;//HACK: clear modified status on a const object virtual ~CiftiMappingType(); static QString mappingTypeToName(const MappingType& type); }; } #endif //__CIFTI_MAPPING_TYPE_H__ connectome-workbench-1.4.2/src/Cifti/CiftiParcelsMap.cxx000066400000000000000000000745261360521144700232300ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiParcelsMap.h" #include "DataFileException.h" #include "CaretLogger.h" #include #include using namespace std; using namespace caret; void CiftiParcelsMap::addParcel(const CiftiParcelsMap::Parcel& parcel) { int64_t thisParcel = m_parcels.size();//slight hack: current number of parcels will be this parcel's index for (int64_t i = 0; i < thisParcel; ++i)//also use it as endpoint of looping over existing parcels { if (parcel.m_name == m_parcels[i].m_name) { throw DataFileException("cannot add parcel with duplicate name '" + parcel.m_name + "'");//NOTE: technically this restriction isn't in the standard, but that was probably an oversight } } int64_t voxelListSize = (int64_t)parcel.m_voxelIndices.size(); CaretCompact3DLookup tempLookup = m_volLookup;//a copy of the lookup should be faster than other methods of checking for overlap and repeat if (voxelListSize != 0) { const int64_t* dims = NULL; if (!m_ignoreVolSpace) { if (!m_haveVolumeSpace) { throw DataFileException("you must set the volume space before adding parcels that use voxels"); } dims = m_volSpace.getDims(); } for (set::const_iterator iter = parcel.m_voxelIndices.begin(); iter != parcel.m_voxelIndices.end(); ++iter)//do all error checking before adding to lookup - might be unnecessary { if (iter->m_ijk[0] < 0 || iter->m_ijk[1] < 0 || iter->m_ijk[2] < 0) { throw DataFileException("found negative index triple in voxel list"); } if (!m_ignoreVolSpace && (iter->m_ijk[0] >= dims[0] || iter->m_ijk[1] >= dims[1] || iter->m_ijk[2] >= dims[2])) { throw DataFileException("found invalid index triple in voxel list"); } if (tempLookup.find(iter->m_ijk) != NULL) { throw DataFileException("parcels may not overlap in voxels"); } tempLookup.at(iter->m_ijk) = thisParcel; } } for (map >::const_iterator iter = parcel.m_surfaceNodes.begin(); iter != parcel.m_surfaceNodes.end(); ++iter) { map::const_iterator info = m_surfInfo.find(iter->first); if (info == m_surfInfo.end()) { throw DataFileException("you must set surfaces before adding parcels that use them"); } const set& nodeSet = iter->second; if (nodeSet.size() == 0) { throw DataFileException("parcels may not include empty node lists");//NOTE: technically not required by Cifti, change if problematic, but probably never allow empty list in internal state } for (set::const_iterator iter2 = nodeSet.begin(); iter2 != nodeSet.end(); ++iter2) { if (*iter2 < 0) { throw DataFileException("found negative vertex in parcel"); } if (*iter2 >= info->second.m_numNodes) { throw DataFileException("found invalid vertex in parcel"); } if (info->second.m_lookup[*iter2] != -1) { throw DataFileException("parcels may not overlap in vertices"); } } } if (voxelListSize != 0)//all error checking done, modify { m_volLookup = tempLookup; } for (map >::const_iterator iter = parcel.m_surfaceNodes.begin(); iter != parcel.m_surfaceNodes.end(); ++iter) { map::iterator info = m_surfInfo.find(iter->first); CaretAssert(info != m_surfInfo.end()); const set& nodeSet = iter->second; for (set::const_iterator iter2 = nodeSet.begin(); iter2 != nodeSet.end(); ++iter2) { CaretAssertVectorIndex(info->second.m_lookup, *iter2); info->second.m_lookup[*iter2] = thisParcel; } } m_parcels.push_back(parcel); } void CiftiParcelsMap::addSurface(const int64_t& numberOfNodes, const StructureEnum::Enum& structure) { map::const_iterator test = m_surfInfo.find(structure); if (test != m_surfInfo.end()) { throw DataFileException("parcel surface structures may not be used more than once"); } SurfaceInfo tempInfo; tempInfo.m_numNodes = numberOfNodes; tempInfo.m_lookup.resize(numberOfNodes, -1); m_surfInfo[structure] = tempInfo; } void CiftiParcelsMap::clear() { m_haveVolumeSpace = false; m_ignoreVolSpace = false; m_parcels.clear(); m_surfInfo.clear(); m_volLookup.clear(); } void CiftiParcelsMap::setVolumeSpace(const VolumeSpace& space) { const int64_t* dims = space.getDims(); int64_t numParcels = (int64_t)m_parcels.size(); for (int64_t i = 0; i < numParcels; ++i) { const set& voxelList = m_parcels[i].m_voxelIndices; for (set::const_iterator iter = voxelList.begin(); iter != voxelList.end(); ++iter) { if (iter->m_ijk[0] >= dims[0] || iter->m_ijk[1] >= dims[1] || iter->m_ijk[2] >= dims[2]) { throw DataFileException("parcels may not contain voxel indices outside the volume space"); } } } m_haveVolumeSpace = true; m_ignoreVolSpace = false; m_volSpace = space; } int64_t CiftiParcelsMap::getIndexForNode(const int64_t& node, const StructureEnum::Enum& structure) const { CaretAssert(node >= 0); map::const_iterator test = m_surfInfo.find(structure); if (test == m_surfInfo.end()) return -1; if (node >= test->second.m_numNodes) return -1; CaretAssertVectorIndex(test->second.m_lookup, node); return test->second.m_lookup[node]; } int64_t CiftiParcelsMap::getIndexForVoxel(const int64_t* ijk) const { return getIndexForVoxel(ijk[0], ijk[1], ijk[2]); } int64_t CiftiParcelsMap::getIndexForVoxel(const int64_t& i, const int64_t& j, const int64_t& k) const { const int64_t* test = m_volLookup.find(i, j, k);//the lookup tolerates weirdness like negatives if (test == NULL) return -1; return *test; } vector CiftiParcelsMap::getParcelSurfaceStructures() const { vector ret; ret.reserve(m_surfInfo.size()); for (map::const_iterator iter = m_surfInfo.begin(); iter != m_surfInfo.end(); ++iter) { ret.push_back(iter->first); } return ret; } int64_t CiftiParcelsMap::getIndexFromNumberOrName(const QString& numberOrName) const { bool ok = false; int64_t ret = numberOrName.toLongLong(&ok) - 1;//quirk: use string "1" as the first index if (ok) { if (ret < 0 || ret >= getLength()) return -1;//if it is a number, do not try to use it as a name, under any circumstances return ret; } else { int64_t length = getLength(); for (int64_t i = 0; i < length; ++i) { if (numberOrName == m_parcels[i].m_name) return i; } return -1; } } QString CiftiParcelsMap::getIndexName(const int64_t& index) const { CaretAssertVectorIndex(m_parcels, index); return m_parcels[index].m_name; } const VolumeSpace& CiftiParcelsMap::getVolumeSpace() const { CaretAssert(!m_ignoreVolSpace);//this should never be set except during parsing of cifti-1 if (!m_haveVolumeSpace) { throw DataFileException("getVolumeSpace called when no volume space exists"); } return m_volSpace; } int64_t CiftiParcelsMap::getSurfaceNumberOfNodes(const StructureEnum::Enum& structure) const { map::const_iterator iter = m_surfInfo.find(structure); if (iter == m_surfInfo.end()) return -1; return iter->second.m_numNodes; } bool CiftiParcelsMap::hasSurface(const StructureEnum::Enum& structure) const { return m_surfInfo.find(structure) != m_surfInfo.end(); } bool CiftiParcelsMap::hasSurfaceData(const StructureEnum::Enum& structure) const { if (m_surfInfo.find(structure) == m_surfInfo.end()) return false; int64_t numParcels = (int64_t)m_parcels.size(); for (int64_t i = 0; i < numParcels; ++i) { map >::const_iterator iter = m_parcels[i].m_surfaceNodes.find(structure); if (iter != m_parcels[i].m_surfaceNodes.end() && iter->second.size() != 0) return true; } return false; } bool CiftiParcelsMap::hasVolumeData() const { CaretAssert(!m_ignoreVolSpace); int64_t numParcels = (int64_t)m_parcels.size();//NOTE: this function is used when reading cifti-1 to determine whether it is an error to not have a volume space, so we can't just check m_haveVolumeSpace for (int64_t i = 0; i < numParcels; ++i) { if (m_parcels[i].m_voxelIndices.size() != 0) return true; } return false; } bool CiftiParcelsMap::approximateMatch(const CiftiMappingType& rhs, QString* explanation) const { if (rhs.getType() != getType()) { if (explanation != NULL) *explanation = CiftiMappingType::mappingTypeToName(rhs.getType()) + " mapping never matches " + CiftiMappingType::mappingTypeToName(getType()); return false; } const CiftiParcelsMap& myrhs = dynamic_cast(rhs); CaretAssert(!m_ignoreVolSpace && !myrhs.m_ignoreVolSpace); if (m_haveVolumeSpace != myrhs.m_haveVolumeSpace) { if (explanation != NULL) *explanation = "one of the mappings has no volume data"; return false; } if (m_haveVolumeSpace && (m_volSpace != myrhs.m_volSpace)) { if (explanation != NULL) *explanation = "mappings have a different volume space"; return false; } if (m_surfInfo.size() != myrhs.m_surfInfo.size()) { if (explanation != NULL) *explanation = "mappings have a different number of surfaces used"; return false;//as below, return false if they won't write the mapping part to xml the same - 1 to 1 compare only requires 1 simple loop } for (map::const_iterator iter = m_surfInfo.begin(); iter != m_surfInfo.end(); ++iter) { map::const_iterator rhsiter = myrhs.m_surfInfo.find(iter->first); if (rhsiter == myrhs.m_surfInfo.end()) {//technically, they might still have the same meaning, if the surface isn't used, but they will still write differently, so false if (explanation != NULL) *explanation = StructureEnum::toName(iter->first) + " surface expected but not found"; return false; } if (iter->second.m_numNodes != rhsiter->second.m_numNodes) { if (explanation != NULL) *explanation = "different number of vertices for surface " + StructureEnum::toName(iter->first); return false; } } if (m_parcels.size() != myrhs.m_parcels.size()) { if (explanation != NULL) *explanation = "different number of parcels"; return false; } for (int64_t i = 0; i < (int64_t)m_parcels.size(); ++i) { if (!m_parcels[i].approximateMatch(myrhs.m_parcels[i], explanation)) return false; } return true; } bool CiftiParcelsMap::operator==(const CiftiMappingType& rhs) const { if (rhs.getType() != getType()) return false; const CiftiParcelsMap& myrhs = dynamic_cast(rhs); CaretAssert(!m_ignoreVolSpace && !myrhs.m_ignoreVolSpace); if (m_haveVolumeSpace != myrhs.m_haveVolumeSpace) return false; if (m_haveVolumeSpace && m_volSpace != myrhs.m_volSpace) return false; if (m_surfInfo.size() != myrhs.m_surfInfo.size()) return false;//as below, return false if they won't write to xml the same - 1 to 1 compare only requires 1 simple loop for (map::const_iterator iter = m_surfInfo.begin(); iter != m_surfInfo.end(); ++iter) { map::const_iterator rhsiter = myrhs.m_surfInfo.find(iter->first); if (rhsiter == myrhs.m_surfInfo.end()) return false;//technically, they might still have the same meaning, if the surface isn't used, but they will still write differently, so false if (iter->second.m_numNodes != rhsiter->second.m_numNodes) return false; } return (m_parcels == myrhs.m_parcels); } bool CiftiParcelsMap::Parcel::operator==(const CiftiParcelsMap::Parcel& rhs) const { if (m_name != rhs.m_name) return false; if (m_voxelIndices != rhs.m_voxelIndices) return false; return (m_surfaceNodes == rhs.m_surfaceNodes); } //same, but don't test name bool CiftiParcelsMap::Parcel::approximateMatch(const CiftiParcelsMap::Parcel& rhs, QString* explanation) const { bool nameMatches = (m_name == rhs.m_name);//for more informative explanations if (m_voxelIndices != rhs.m_voxelIndices) { if (explanation != NULL) { if (nameMatches) { *explanation = "parcel '" + m_name + "' uses different voxels than parcel in other map"; } else { *explanation = "parcel '" + m_name + "' uses different voxels than same-index parcel '" + rhs.m_name + "' in other map"; } } return false; } if (m_surfaceNodes != rhs.m_surfaceNodes) { if (explanation != NULL) { if (nameMatches) { *explanation = "parcel '" + m_name + "' uses different surface vertices than parcel in other map"; } else { *explanation = "parcel '" + m_name + "' uses different surface vertices than same-index parcel '" + rhs.m_name + "' in other map"; } } return false; } return true; } void CiftiParcelsMap::readXML1(QXmlStreamReader& xml) { CaretLogFiner("parsing nonstandard parcels mapping type in cifti-1"); clear(); m_ignoreVolSpace = true;//cifti-1 has volume space outside the index map vector myParcels;//because we need to add the surfaces first while (xml.readNextStartElement()) { QStringRef name = xml.name(); if (name == "Surface") { QXmlStreamAttributes attrs = xml.attributes(); if (!attrs.hasAttribute("BrainStructure")) { throw DataFileException("Surface element missing required attribute BrainStructure"); } bool ok = false; StructureEnum::Enum tempStructure = StructureEnum::fromCiftiName(attrs.value("BrainStructure").toString(), &ok); if (!ok) { throw DataFileException("invalid value for BrainStructure: " + attrs.value("BrainStructure").toString()); } if (!attrs.hasAttribute("SurfaceNumberOfNodes")) { throw DataFileException("Surface element missing required attribute SurfaceNumberOfNodes"); } int64_t numNodes = attrs.value("SurfaceNumberOfNodes").toString().toLongLong(&ok); if (!ok || numNodes < 1) { throw DataFileException("invalid value for SurfaceNumberOfNodes: " + attrs.value("SurfaceNumberOfNodes").toString()); } addSurface(numNodes, tempStructure);//let the standard modification functions do error checking if (xml.readNextStartElement()) { throw DataFileException("unexpected element inside Surface: " + xml.name().toString()); } } else if (name == "Parcel") { myParcels.push_back(readParcel1(xml)); } else { throw DataFileException("unexpected element in parcels map: " + name.toString()); } } int64_t numParcels = (int64_t)myParcels.size(); for (int64_t i = 0; i < numParcels; ++i) { addParcel(myParcels[i]); } m_ignoreVolSpace = false;//in case there are no voxels, but some will be added later CaretAssert(xml.isEndElement() && xml.name() == "MatrixIndicesMap"); } void CiftiParcelsMap::readXML2(QXmlStreamReader& xml) { clear(); vector myParcels;//because we need to add the surfaces and volume space first while (xml.readNextStartElement()) { QStringRef name = xml.name(); if (name == "Surface") { QXmlStreamAttributes attrs = xml.attributes(); if (!attrs.hasAttribute("BrainStructure")) { throw DataFileException("Surface element missing required attribute BrainStructure"); } bool ok = false; StructureEnum::Enum tempStructure = StructureEnum::fromCiftiName(attrs.value("BrainStructure").toString(), &ok); if (!ok) { throw DataFileException("invalid value for BrainStructure: " + attrs.value("BrainStructure").toString()); } if (!attrs.hasAttribute("SurfaceNumberOfVertices")) { throw DataFileException("Surface element missing required attribute SurfaceNumberOfVertices"); } int64_t numNodes = attrs.value("SurfaceNumberOfVertices").toString().toLongLong(&ok); if (!ok || numNodes < 1) { throw DataFileException("invalid value for SurfaceNumberOfVertices: " + attrs.value("SurfaceNumberOfVertices").toString()); } addSurface(numNodes, tempStructure);//let the standard modification functions do error checking if (xml.readNextStartElement()) { throw DataFileException("unexpected element inside Surface: " + xml.name().toString()); } } else if (name == "Parcel") { myParcels.push_back(readParcel2(xml)); if (xml.hasError()) return; } else if (name == "Volume") { if (m_haveVolumeSpace) { throw DataFileException("Volume specified more than once in Parcels mapping type"); } else { m_volSpace.readCiftiXML2(xml); if (xml.hasError()) return; m_haveVolumeSpace = true; } } else { throw DataFileException("unexpected element in parcels map: " + name.toString()); } } int64_t numParcels = (int64_t)myParcels.size(); for (int64_t i = 0; i < numParcels; ++i) { addParcel(myParcels[i]); } CaretAssert(xml.isEndElement() && xml.name() == "MatrixIndicesMap"); } CiftiParcelsMap::Parcel CiftiParcelsMap::readParcel1(QXmlStreamReader& xml) { Parcel ret; bool haveVoxels = false; QXmlStreamAttributes attrs = xml.attributes(); if (!attrs.hasAttribute("Name")) { throw DataFileException("Parcel element missing required attribute Name"); } ret.m_name = attrs.value("Name").toString(); while (xml.readNextStartElement()) { QStringRef name = xml.name(); if (name == "Nodes") { QXmlStreamAttributes attrs1 = xml.attributes(); if (!attrs1.hasAttribute("BrainStructure")) { throw DataFileException("Nodes element missing required attribute BrainStructure"); } bool ok = false; StructureEnum::Enum myStructure = StructureEnum::fromCiftiName(attrs1.value("BrainStructure").toString(), &ok); if (!ok) { throw DataFileException("unrecognized value for BrainStructure: " + attrs1.value("BrainStructure").toString()); } if (ret.m_surfaceNodes.find(myStructure) != ret.m_surfaceNodes.end()) { throw DataFileException("Nodes elements may not reuse a BrainStructure within a Parcel"); } set& mySet = ret.m_surfaceNodes[myStructure]; vector array = readIndexArray(xml); if (xml.hasError()) return ret; int64_t arraySize = (int64_t)array.size(); for (int64_t i = 0; i < arraySize; ++i) { if (mySet.find(array[i]) != mySet.end()) { throw DataFileException("Nodes elements may not reuse indices"); } mySet.insert(array[i]); } } else if (name == "VoxelIndicesIJK") { if (haveVoxels) { throw DataFileException("VoxelIndicesIJK may only appear once in a Parcel"); } vector array = readIndexArray(xml); if (xml.hasError()) return ret; int64_t arraySize = (int64_t)array.size(); if (arraySize % 3 != 0) { throw DataFileException("number of indices in VoxelIndicesIJK must be a multiple of 3"); } for (int64_t index3 = 0; index3 < arraySize; index3 += 3) { VoxelIJK temp(array.data() + index3); if (ret.m_voxelIndices.find(temp) != ret.m_voxelIndices.end()) { throw DataFileException("VoxelIndicesIJK elements may not reuse voxels"); } ret.m_voxelIndices.insert(temp); } haveVoxels = true; } else { throw DataFileException("unexpected element in Parcel: " + name.toString()); } } CaretAssert(xml.isEndElement() && xml.name() == "Parcel"); return ret; } CiftiParcelsMap::Parcel CiftiParcelsMap::readParcel2(QXmlStreamReader& xml) { Parcel ret; bool haveVoxels = false; QXmlStreamAttributes attrs = xml.attributes(); if (!attrs.hasAttribute("Name")) { throw DataFileException("Parcel element missing required attribute Name"); } ret.m_name = attrs.value("Name").toString(); while (xml.readNextStartElement()) { QStringRef name = xml.name(); if (name == "Vertices") { QXmlStreamAttributes attrs1 = xml.attributes(); if (!attrs1.hasAttribute("BrainStructure")) { throw DataFileException("Vertices element missing required attribute BrainStructure"); } bool ok = false; StructureEnum::Enum myStructure = StructureEnum::fromCiftiName(attrs1.value("BrainStructure").toString(), &ok); if (!ok) { throw DataFileException("unrecognized value for BrainStructure: " + attrs1.value("BrainStructure").toString()); } if (ret.m_surfaceNodes.find(myStructure) != ret.m_surfaceNodes.end()) { throw DataFileException("Vertices elements may not reuse a BrainStructure within a Parcel"); } set& mySet = ret.m_surfaceNodes[myStructure]; vector array = readIndexArray(xml); if (xml.hasError()) return ret; int64_t arraySize = (int64_t)array.size(); for (int64_t i = 0; i < arraySize; ++i) { if (mySet.find(array[i]) != mySet.end()) { throw DataFileException("Vertices elements may not reuse indices"); } mySet.insert(array[i]); } } else if (name == "VoxelIndicesIJK") { if (haveVoxels) { throw DataFileException("VoxelIndicesIJK may only appear once in a Parcel"); } vector array = readIndexArray(xml); if (xml.hasError()) return ret; int64_t arraySize = (int64_t)array.size(); if (arraySize % 3 != 0) { throw DataFileException("number of indices in VoxelIndicesIJK must be a multiple of 3"); } for (int64_t index3 = 0; index3 < arraySize; index3 += 3) { VoxelIJK temp(array.data() + index3); if (ret.m_voxelIndices.find(temp) != ret.m_voxelIndices.end()) { throw DataFileException("VoxelIndicesIJK elements may not reuse voxels"); } ret.m_voxelIndices.insert(temp); } haveVoxels = true; } else { throw DataFileException("unexpected element in Parcel: " + name.toString()); } } CaretAssert(xml.isEndElement() && xml.name() == "Parcel"); return ret; } vector CiftiParcelsMap::readIndexArray(QXmlStreamReader& xml) { vector ret; QString text = xml.readElementText();//raises error if it encounters a start element if (xml.hasError()) return ret; QStringList separated = text.split(QRegExp("\\s+"), QString::SkipEmptyParts); int64_t numElems = separated.size(); ret.reserve(numElems); for (int64_t i = 0; i < numElems; ++i) { bool ok = false; ret.push_back(separated[i].toLongLong(&ok)); if (!ok) { throw DataFileException("found noninteger in index array: " + separated[i]); } } return ret; } void CiftiParcelsMap::writeXML1(QXmlStreamWriter& xml) const { CaretAssert(!m_ignoreVolSpace); CaretLogFiner("writing nonstandard parcels mapping type in cifti-1"); xml.writeAttribute("IndicesMapToDataType", "CIFTI_INDEX_TYPE_PARCELS"); for (map::const_iterator iter = m_surfInfo.begin(); iter != m_surfInfo.end(); ++iter) { xml.writeStartElement("Surface"); xml.writeAttribute("BrainStructure", StructureEnum::toCiftiName(iter->first)); xml.writeAttribute("SurfaceNumberOfNodes", QString::number(iter->second.m_numNodes)); xml.writeEndElement(); } int64_t numParcels = m_parcels.size(); for (int64_t i = 0; i < numParcels; ++i) { xml.writeStartElement("Parcel"); xml.writeAttribute("Name", m_parcels[i].m_name); int64_t numVoxels = (int64_t)m_parcels[i].m_voxelIndices.size(); if (numVoxels != 0) { xml.writeStartElement("VoxelIndicesIJK"); for (set::const_iterator iter = m_parcels[i].m_voxelIndices.begin(); iter != m_parcels[i].m_voxelIndices.end(); ++iter) { xml.writeCharacters(QString::number(iter->m_ijk[0]) + " " + QString::number(iter->m_ijk[1]) + " " + QString::number(iter->m_ijk[2]) + "\n"); } xml.writeEndElement(); } for (map >::const_iterator iter = m_parcels[i].m_surfaceNodes.begin(); iter != m_parcels[i].m_surfaceNodes.end(); ++iter) { if (iter->second.size() != 0)//prevent writing empty elements, regardless { xml.writeStartElement("Nodes"); xml.writeAttribute("BrainStructure", StructureEnum::toCiftiName(iter->first)); set::const_iterator iter2 = iter->second.begin();//which also allows us to write the first one outside the loop, to not add whitespace on the front or back xml.writeCharacters(QString::number(*iter2)); ++iter2; for (; iter2 != iter->second.end(); ++iter2) { xml.writeCharacters(" " + QString::number(*iter2)); } xml.writeEndElement(); } } xml.writeEndElement(); } } void CiftiParcelsMap::writeXML2(QXmlStreamWriter& xml) const { CaretAssert(!m_ignoreVolSpace); xml.writeAttribute("IndicesMapToDataType", "CIFTI_INDEX_TYPE_PARCELS"); if (hasVolumeData())//could be m_haveVolumeSpace if we want to be able to write a volspace without having voxels, but that seems silly { m_volSpace.writeCiftiXML2(xml); } for (map::const_iterator iter = m_surfInfo.begin(); iter != m_surfInfo.end(); ++iter) { xml.writeStartElement("Surface"); xml.writeAttribute("BrainStructure", StructureEnum::toCiftiName(iter->first)); xml.writeAttribute("SurfaceNumberOfVertices", QString::number(iter->second.m_numNodes)); xml.writeEndElement(); } int64_t numParcels = m_parcels.size(); for (int64_t i = 0; i < numParcels; ++i) { xml.writeStartElement("Parcel"); xml.writeAttribute("Name", m_parcels[i].m_name); int64_t numVoxels = (int64_t)m_parcels[i].m_voxelIndices.size(); if (numVoxels != 0) { xml.writeStartElement("VoxelIndicesIJK"); for (set::const_iterator iter = m_parcels[i].m_voxelIndices.begin(); iter != m_parcels[i].m_voxelIndices.end(); ++iter) { xml.writeCharacters(QString::number(iter->m_ijk[0]) + " " + QString::number(iter->m_ijk[1]) + " " + QString::number(iter->m_ijk[2]) + "\n"); } xml.writeEndElement(); } for (map >::const_iterator iter = m_parcels[i].m_surfaceNodes.begin(); iter != m_parcels[i].m_surfaceNodes.end(); ++iter) { if (iter->second.size() != 0)//prevent writing empty elements, regardless { xml.writeStartElement("Vertices"); xml.writeAttribute("BrainStructure", StructureEnum::toCiftiName(iter->first)); set::const_iterator iter2 = iter->second.begin();//which also allows us to write the first one outside the loop, to not add whitespace on the front or back xml.writeCharacters(QString::number(*iter2)); ++iter2; for (; iter2 != iter->second.end(); ++iter2) { xml.writeCharacters(" " + QString::number(*iter2)); } xml.writeEndElement(); } } xml.writeEndElement(); } } connectome-workbench-1.4.2/src/Cifti/CiftiParcelsMap.h000066400000000000000000000076601360521144700226500ustar00rootroot00000000000000#ifndef __CIFTI_PARCELS_MAP_H__ #define __CIFTI_PARCELS_MAP_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiMappingType.h" #include "CaretCompact3DLookup.h" #include "StructureEnum.h" #include "VolumeSpace.h" #include "VoxelIJK.h" #include #include #include namespace caret { class CiftiParcelsMap : public CiftiMappingType { public: struct Parcel { std::map > m_surfaceNodes; std::set m_voxelIndices; QString m_name; bool operator==(const Parcel& rhs) const; bool operator!=(const Parcel& rhs) const { return !((*this) == rhs); } bool approximateMatch(const Parcel& rhs, QString* explanation = NULL) const; }; bool hasVolumeData() const; bool hasSurface(const StructureEnum::Enum& structure) const;//only checks whether surface has been added/read bool hasSurfaceData(const StructureEnum::Enum& structure) const; const VolumeSpace& getVolumeSpace() const; int64_t getSurfaceNumberOfNodes(const StructureEnum::Enum& structure) const; int64_t getIndexForNode(const int64_t& node, const StructureEnum::Enum& structure) const; int64_t getIndexForVoxel(const int64_t* ijk) const; int64_t getIndexForVoxel(const int64_t& i, const int64_t& j, const int64_t& k) const; std::vector getParcelSurfaceStructures() const; const std::vector& getParcels() const { return m_parcels; } int64_t getIndexFromNumberOrName(const QString& numberOrName) const; QString getIndexName(const int64_t& index) const; CiftiParcelsMap() { m_haveVolumeSpace = false; m_ignoreVolSpace = false; } void addSurface(const int64_t& numberOfNodes, const StructureEnum::Enum& structure); void setVolumeSpace(const VolumeSpace& space); void addParcel(const Parcel& parcel); void clear(); CiftiMappingType* clone() const { return new CiftiParcelsMap(*this); } MappingType getType() const { return PARCELS; } int64_t getLength() const { return m_parcels.size(); } bool operator==(const CiftiMappingType& rhs) const; bool approximateMatch(const CiftiMappingType& rhs, QString* explanation = NULL) const; void readXML1(QXmlStreamReader& xml); void readXML2(QXmlStreamReader& xml); void writeXML1(QXmlStreamWriter& xml) const; void writeXML2(QXmlStreamWriter& xml) const; private: std::vector m_parcels; VolumeSpace m_volSpace; bool m_haveVolumeSpace, m_ignoreVolSpace;//second is needed for parsing cifti-1 struct SurfaceInfo { int64_t m_numNodes; std::vector m_lookup; }; CaretCompact3DLookup m_volLookup; std::map m_surfInfo; static Parcel readParcel1(QXmlStreamReader& xml); static Parcel readParcel2(QXmlStreamReader& xml); static std::vector readIndexArray(QXmlStreamReader& xml); }; } #endif //__CIFTI_PARCELS_MAP_H__ connectome-workbench-1.4.2/src/Cifti/CiftiScalarsMap.cxx000066400000000000000000000320241360521144700232120ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiScalarsMap.h" #include "CaretAssert.h" #include "DataFileException.h" #include "CaretLogger.h" //HACK: to compare metadata in a const function, we make a copy and remove the palette data - but metadata's copy intentionally breaks == because of the UUID, so we need to reset it #include "GiftiMetaDataXmlElements.h" using namespace caret; void CiftiScalarsMap::clear() { m_maps.clear(); } GiftiMetaData* CiftiScalarsMap::getMapMetadata(const int64_t& index) const { CaretAssertVectorIndex(m_maps, index); return &(m_maps[index].m_metaData); } const QString& CiftiScalarsMap::getMapName(const int64_t& index) const { CaretAssertVectorIndex(m_maps, index); return m_maps[index].m_name; } int64_t CiftiScalarsMap::getIndexFromNumberOrName(const QString& numberOrName) const { bool ok = false; int64_t ret = numberOrName.toLongLong(&ok) - 1;//quirk: use string "1" as the first index if (ok) { if (ret < 0 || ret >= getLength()) return -1;//if it is a number, do not try to use it as a name, under any circumstances return ret; } else { int64_t length = getLength(); for (int64_t i = 0; i < length; ++i) { if (numberOrName == getMapName(i)) return i; } return -1; } } PaletteColorMapping* CiftiScalarsMap::getMapPalette(const int64_t& index) const { CaretAssertVectorIndex(m_maps, index); return m_maps[index].getPalette(); } PaletteColorMapping* CiftiScalarsMap::ScalarMap::getPalette() const { if (m_palette != NULL) { return m_palette; } m_palette.grabNew(new PaletteColorMapping()); if (m_metaData.exists("PaletteColorMapping")) { try { m_palette->decodeFromStringXML(m_metaData.get("PaletteColorMapping")); } catch (XmlException& e) { CaretLogWarning("failed to parse palette settings from metadata: " + e.whatString()); } } return m_palette; } void CiftiScalarsMap::setLength(const int64_t& length) { CaretAssert(length > 0); m_maps.resize(length); } void CiftiScalarsMap::setMapName(const int64_t& index, const QString& mapName) const { CaretAssertVectorIndex(m_maps, index); m_maps[index].m_name = mapName; } bool CiftiScalarsMap::approximateMatch(const CiftiMappingType& rhs, QString* explanation) const { switch (rhs.getType()) { case SCALARS: case SERIES://maybe? case LABELS: if (getLength() != rhs.getLength()) { if (explanation != NULL) *explanation = "mappings have different length"; return false; } else return true; default: if (explanation != NULL) *explanation = CiftiMappingType::mappingTypeToName(rhs.getType()) + " mapping never matches " + CiftiMappingType::mappingTypeToName(getType()); return false; } } bool CiftiScalarsMap::operator==(const CiftiMappingType& rhs) const { if (rhs.getType() != getType()) return false; const CiftiScalarsMap& myrhs = dynamic_cast(rhs); return (m_maps == myrhs.m_maps); } bool CiftiScalarsMap::ScalarMap::operator==(const CiftiScalarsMap::ScalarMap& rhs) const { if (m_name != rhs.m_name) return false; if (*(getPalette()) != *(rhs.getPalette())) return false; GiftiMetaData mytemp = m_metaData, rhstemp = rhs.m_metaData; mytemp.remove("PaletteColorMapping");//we already compared the true palettes, so don't compare the metadata that may or may not encode them if (m_metaData.exists(GiftiMetaDataXmlElements::METADATA_NAME_UNIQUE_ID))//HACK: fix the copy-breaks-UUID silliness { mytemp.set(GiftiMetaDataXmlElements::METADATA_NAME_UNIQUE_ID, m_metaData.get(GiftiMetaDataXmlElements::METADATA_NAME_UNIQUE_ID)); } rhstemp.remove("PaletteColorMapping"); if (rhs.m_metaData.exists(GiftiMetaDataXmlElements::METADATA_NAME_UNIQUE_ID)) { rhstemp.set(GiftiMetaDataXmlElements::METADATA_NAME_UNIQUE_ID, rhs.m_metaData.get(GiftiMetaDataXmlElements::METADATA_NAME_UNIQUE_ID)); } return (mytemp == rhstemp); } CiftiScalarsMap::ScalarMap::ScalarMap(const CiftiScalarsMap::ScalarMap& rhs) { m_name = rhs.m_name; m_metaData = rhs.m_metaData; if (rhs.m_palette != NULL) m_palette.grabNew(new PaletteColorMapping(*(rhs.m_palette)));//we need to copy the palette, because it may no longer match the metadata } CiftiScalarsMap::ScalarMap& CiftiScalarsMap::ScalarMap::operator=(const CiftiScalarsMap::ScalarMap& rhs) { if (&rhs == this) return *this; m_name = rhs.m_name; m_metaData = rhs.m_metaData; if (rhs.m_palette == NULL) { m_palette.grabNew(NULL); } else { m_palette.grabNew(new PaletteColorMapping(*(rhs.m_palette)));//we need to copy the palette object, because it may no longer match the metadata } return *this; } void CiftiScalarsMap::readXML1(QXmlStreamReader& xml) { CaretLogFiner("parsing nonstandard scalars mapping type in cifti-1"); clear(); for (xml.readNext(); !xml.atEnd() && !xml.isEndElement(); xml.readNext()) { switch (xml.tokenType()) { case QXmlStreamReader::StartElement: { if (xml.name() != "NamedMap") { throw DataFileException("unexpected element in scalars map: " + xml.name().toString()); } m_maps.push_back(ScalarMap());//HACK: because operator= is deliberately broken by GiftiMetadata for UUID m_maps.back().readXML1(xml); if (xml.hasError()) return; break; } default: break; } } CaretAssert(xml.isEndElement() && xml.name() == "MatrixIndicesMap"); } void CiftiScalarsMap::readXML2(QXmlStreamReader& xml) { clear(); for (xml.readNext(); !xml.atEnd() && !xml.isEndElement(); xml.readNext()) { switch (xml.tokenType()) { case QXmlStreamReader::StartElement: { if (xml.name() != "NamedMap") { throw DataFileException("unexpected element in scalars map: " + xml.name().toString()); } m_maps.push_back(ScalarMap());//HACK: because operator= is deliberately broken by GiftiMetadata for UUID m_maps.back().readXML2(xml); if (xml.hasError()) return; break; } default: break; } } CaretAssert(xml.isEndElement() && xml.name() == "MatrixIndicesMap"); } void CiftiScalarsMap::ScalarMap::readXML1(QXmlStreamReader& xml) { bool haveName = false, haveMetaData = false; for (xml.readNext(); !xml.atEnd() && !xml.isEndElement(); xml.readNext()) { switch (xml.tokenType()) { case QXmlStreamReader::StartElement: { QStringRef name = xml.name(); if (name == "MetaData") { if (haveMetaData) { throw DataFileException("MetaData specified multiple times in one NamedMap"); } m_metaData.readCiftiXML1(xml); if (xml.hasError()) return; haveMetaData = true; } else if (name == "MapName") { if (haveName) { throw DataFileException("MapName specified multiple times in one NamedMap"); } m_name = xml.readElementText();//raises error if element encountered if (xml.hasError()) return; haveName = true; } else if (name == "LabelTable") { CaretLogWarning("ignoring LabelTable in Cifti-1 Scalars mapping"); xml.readElementText(QXmlStreamReader::SkipChildElements);//accept some malformed Cifti-1 files if (xml.hasError()) return; } else { throw DataFileException("unexpected element in NamedMap: " + name.toString()); } break; } default: break; } } if (!haveName) { throw DataFileException("NamedMap missing required child element MapName"); } CaretAssert(xml.isEndElement() && xml.name() == "NamedMap"); } void CiftiScalarsMap::ScalarMap::readXML2(QXmlStreamReader& xml) { bool haveName = false, haveMetaData = false; for (xml.readNext(); !xml.atEnd() && !xml.isEndElement(); xml.readNext()) { switch (xml.tokenType()) { case QXmlStreamReader::StartElement: { QStringRef name = xml.name(); if (name == "MetaData") { if (haveMetaData) { throw DataFileException("MetaData specified multiple times in one NamedMap"); } m_metaData.readCiftiXML2(xml); if (xml.hasError()) return; haveMetaData = true; } else if (name == "MapName") { if (haveName) { throw DataFileException("MapName specified multiple times in one NamedMap"); } m_name = xml.readElementText();//raises error if element encountered if (xml.hasError()) return; haveName = true; } else { throw DataFileException("unexpected element in NamedMap: " + name.toString()); } break; } default: break; } } if (!haveName) { throw DataFileException("NamedMap missing required child element MapName"); } CaretAssert(xml.isEndElement() && xml.name() == "NamedMap"); } void CiftiScalarsMap::writeXML1(QXmlStreamWriter& xml) const { CaretLogFiner("writing nonstandard scalars mapping type in cifti-1"); xml.writeAttribute("IndicesMapToDataType", "CIFTI_INDEX_TYPE_SCALARS"); int64_t numMaps = (int64_t)m_maps.size(); for (int64_t i = 0; i < numMaps; ++i) { xml.writeStartElement("NamedMap"); xml.writeTextElement("MapName", m_maps[i].m_name); if (m_maps[i].m_palette != NULL) { m_maps[i].m_metaData.set("PaletteColorMapping", m_maps[i].m_palette->encodeInXML()); } m_maps[i].m_metaData.writeCiftiXML1(xml); xml.writeEndElement(); } } void CiftiScalarsMap::writeXML2(QXmlStreamWriter& xml) const { int64_t numMaps = (int64_t)m_maps.size(); xml.writeAttribute("IndicesMapToDataType", "CIFTI_INDEX_TYPE_SCALARS"); for (int64_t i = 0; i < numMaps; ++i) { xml.writeStartElement("NamedMap"); xml.writeTextElement("MapName", m_maps[i].m_name); if (m_maps[i].m_palette != NULL) { m_maps[i].m_metaData.set("PaletteColorMapping", m_maps[i].m_palette->encodeInXML()); } m_maps[i].m_metaData.writeCiftiXML1(xml); xml.writeEndElement(); } } //support for internal objects that track modified status CiftiScalarsMap::CiftiScalarsMap() { m_namesModified = false; } CiftiScalarsMap::CiftiScalarsMap(const CiftiScalarsMap& rhs) { m_maps = rhs.m_maps; clearMutablesModified();//this newly created map is not modified } CiftiScalarsMap& CiftiScalarsMap::operator=(const CiftiScalarsMap& rhs) { m_maps = rhs.m_maps; clearMutablesModified();//this map isn't const, so don't count it as modified return *this; } CiftiScalarsMap::CiftiScalarsMap(const int64_t& length) { m_namesModified = false; setLength(length); } bool CiftiScalarsMap::mutablesModified() const { if (m_namesModified) return true; for (int64_t i = 0; i < getLength(); ++i) { if (m_maps[i].m_palette != NULL && m_maps[i].m_palette->isModified()) return true; if (getMapMetadata(i)->isModified()) return true; } return false; } void CiftiScalarsMap::clearMutablesModified() const { m_namesModified = false; for (int64_t i = 0; i < getLength(); ++i) { if (m_maps[i].m_palette != NULL) m_maps[i].m_palette->clearModified(); getMapMetadata(i)->clearModified(); } } connectome-workbench-1.4.2/src/Cifti/CiftiScalarsMap.h000066400000000000000000000065601360521144700226450ustar00rootroot00000000000000#ifndef __CIFTI_SCALARS_MAP_H__ #define __CIFTI_SCALARS_MAP_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiMappingType.h" #include "CaretPointer.h" #include "GiftiMetaData.h" #include "PaletteColorMapping.h" #include #include namespace caret { class CiftiScalarsMap : public CiftiMappingType { public: CiftiScalarsMap(); CiftiScalarsMap(const CiftiScalarsMap& rhs); CiftiScalarsMap& operator=(const CiftiScalarsMap& rhs); explicit CiftiScalarsMap(const int64_t& length); GiftiMetaData* getMapMetadata(const int64_t& index) const;//HACK: allow modification of palette and metadata within XML without setting the xml on a file again PaletteColorMapping* getMapPalette(const int64_t& index) const; const QString& getMapName(const int64_t& index) const; int64_t getIndexFromNumberOrName(const QString& numberOrName) const; QString getIndexName(const int64_t& index) const { return getMapName(index); } void setMapName(const int64_t& index, const QString& mapName) const;//HACK: ditto void setLength(const int64_t& length); void clear();//do we need this? CiftiMappingType* clone() const { return new CiftiScalarsMap(*this); } MappingType getType() const { return SCALARS; } int64_t getLength() const { return m_maps.size(); } bool operator==(const CiftiMappingType& rhs) const; bool approximateMatch(const CiftiMappingType& rhs, QString* explanation = NULL) const; void readXML1(QXmlStreamReader& xml); void readXML2(QXmlStreamReader& xml); void writeXML1(QXmlStreamWriter& xml) const; void writeXML2(QXmlStreamWriter& xml) const; bool mutablesModified() const; void clearMutablesModified() const; private: mutable bool m_namesModified; struct ScalarMap { mutable QString m_name;//we need a better way to change metadata in an in-memory file mutable GiftiMetaData m_metaData;//ditto mutable CaretPointer m_palette;//ditto - note, this actually gets written into the metadata PaletteColorMapping* getPalette() const; ScalarMap() {}; ScalarMap(const ScalarMap& rhs); ScalarMap& operator=(const ScalarMap& rhs); bool operator==(const ScalarMap& rhs) const; void readXML1(QXmlStreamReader& xml); void readXML2(QXmlStreamReader& xml); }; std::vector m_maps; }; } #endif //__CIFTI_SCALARS_MAP_H__ connectome-workbench-1.4.2/src/Cifti/CiftiSeriesMap.cxx000066400000000000000000000210501360521144700230510ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiSeriesMap.h" #include "CaretAssert.h" #include "DataFileException.h" #include "CaretLogger.h" #include using namespace caret; using namespace std; void CiftiSeriesMap::setLength(const int64_t& length) { CaretAssert(length > 0); m_length = length; } CiftiSeriesMap::Unit CiftiSeriesMap::stringToUnit(const QString& string, bool& ok) { ok = true; if (string == "SECOND") { return SECOND; } else if (string == "HERTZ") { return HERTZ; } else if (string == "METER") { return METER; } else if (string == "RADIAN") { return RADIAN; } ok = false; return SECOND; } QString CiftiSeriesMap::unitToString(const CiftiSeriesMap::Unit& theUnit) { switch (theUnit) { case SECOND: return "SECOND"; case HERTZ: return "HERTZ"; case METER: return "METER"; case RADIAN: return "RADIAN"; } CaretAssert(false); return "UNKNOWN"; } vector CiftiSeriesMap::getAllUnits() { vector ret; ret.push_back(SECOND); ret.push_back(HERTZ); ret.push_back(METER); ret.push_back(RADIAN); return ret; } void CiftiSeriesMap::readXML1(QXmlStreamReader& xml) { QXmlStreamAttributes attrs = xml.attributes(); float newStart = 0.0f, newStep = -1.0f, mult = 0.0f; bool ok = false; if (!attrs.hasAttribute("TimeStepUnits")) { throw DataFileException("timepoints mapping is missing required attribute TimeStepUnits"); } QStringRef unitString = attrs.value("TimeStepUnits"); if (unitString == "NIFTI_UNITS_SEC") { mult = 1.0f; } else if (unitString == "NIFTI_UNITS_MSEC") { mult = 0.001f; } else if (unitString == "NIFTI_UNITS_USEC") { mult = 0.000001f; } else { throw DataFileException("unrecognized value for TimeStepUnits: " + unitString.toString()); } if (attrs.hasAttribute("TimeStart"))//optional and nonstandard { newStart = mult * attrs.value("TimeStart").toString().toFloat(&ok); if (!ok) { throw DataFileException("unrecognized value for TimeStart: " + attrs.value("TimeStart").toString()); } } if (!attrs.hasAttribute("TimeStep")) { throw DataFileException("timepoints mapping is missing required attribute TimeStep"); } newStep = mult * attrs.value("TimeStep").toString().toFloat(&ok); if (!ok) { throw DataFileException("unrecognized value for TimeStep: " + attrs.value("TimeStep").toString()); } if (xml.readNextStartElement()) { throw DataFileException("unexpected element in timepoints map: " + xml.name().toString()); } m_length = -1;//cifti-1 doesn't know length in xml, must be set by checking the matrix m_start = newStart; m_step = newStep; m_unit = SECOND; CaretAssert(xml.isEndElement() && xml.name() == "MatrixIndicesMap"); } void CiftiSeriesMap::readXML2(QXmlStreamReader& xml) { QXmlStreamAttributes attrs = xml.attributes(); float newStart = 0.0f, newStep = -1.0f, mult = 0.0f; int64_t newLength = -1; Unit newUnit; bool ok = false; if (!attrs.hasAttribute("SeriesUnit")) { throw DataFileException("series mapping is missing required attribute SeriesUnit"); } QStringRef unitString = attrs.value("SeriesUnit"); if (unitString == "HERTZ") { newUnit = HERTZ; } else if (unitString == "METER") { newUnit = METER; } else if (unitString == "RADIAN") { newUnit = RADIAN; } else if (unitString == "SECOND") { newUnit = SECOND; } else { throw DataFileException("unrecognized value for SeriesUnit: " + unitString.toString()); } if (!attrs.hasAttribute("SeriesExponent")) { throw DataFileException("series mapping is missing required attribute SeriesExponent"); } int exponent = attrs.value("SeriesExponent").toString().toInt(&ok); if (!ok) { throw DataFileException("unrecognized value for SeriesExponent: " + attrs.value("SeriesExponent").toString()); } mult = pow(10.0f, exponent); if (!attrs.hasAttribute("SeriesStart")) { throw DataFileException("series mapping is missing required attribute SeriesStart"); } newStart = mult * attrs.value("SeriesStart").toString().toFloat(&ok); if (!ok) { throw DataFileException("unrecognized value for SeriesStart: " + attrs.value("SeriesStart").toString()); } if (!attrs.hasAttribute("SeriesStep")) { throw DataFileException("series mapping is missing required attribute SeriesStep"); } newStep = mult * attrs.value("SeriesStep").toString().toFloat(&ok); if (!ok) { throw DataFileException("unrecognized value for SeriesStep: " + attrs.value("SeriesStep").toString()); } if (!attrs.hasAttribute("NumberOfSeriesPoints")) { throw DataFileException("series mapping is missing required attribute NumberOfSeriesPoints"); } newLength = attrs.value("NumberOfSeriesPoints").toString().toLongLong(&ok); if (!ok) { throw DataFileException("unrecognized value for NumberOfSeriesPoints: " + attrs.value("NumberOfSeriesPoints").toString()); } if (newLength < 1) { throw DataFileException("NumberOfSeriesPoints must be positive"); } if (xml.readNextStartElement()) { throw DataFileException("unexpected element in series map: " + xml.name().toString()); } m_length = newLength; m_start = newStart; m_step = newStep; m_unit = newUnit; CaretAssert(xml.isEndElement() && xml.name() == "MatrixIndicesMap"); } void CiftiSeriesMap::writeXML1(QXmlStreamWriter& xml) const { CaretAssert(m_length != -1); if (m_unit != SECOND) { CaretLogWarning("changing series units to seconds for CIFTI-1 XML"); } xml.writeAttribute("IndicesMapToDataType", "CIFTI_INDEX_TYPE_TIME_POINTS"); float mult = 1.0f; QString unitString = "NIFTI_UNITS_SEC"; float test = m_step; if (test == 0.0f) test = m_start; if (test != 0.0f) { if (abs(test) < 0.00005f) { mult = 1000000.0f; unitString = "NIFTI_UNITS_USEC"; } else if (abs(test) < 0.05f) { mult = 1000.0f; unitString = "NIFTI_UNITS_MSEC"; } } xml.writeAttribute("TimeStepUnits", unitString); xml.writeAttribute("TimeStart", QString::number(mult * m_start, 'f', 7));//even though it is nonstandard, write it, always xml.writeAttribute("TimeStep", QString::number(mult * m_step, 'f', 7)); } void CiftiSeriesMap::writeXML2(QXmlStreamWriter& xml) const { CaretAssert(m_length != -1); xml.writeAttribute("IndicesMapToDataType", "CIFTI_INDEX_TYPE_SERIES"); int exponent = 0; float test = m_step; if (test == 0.0f) test = m_start; if (test != 0.0f) { exponent = 3 * (int)floor((log10(test) - log10(0.05f)) / 3.0f);//some magic to get the exponent that is a multiple of 3 that puts the test value in [0.05, 50] } float mult = pow(10.0f, -exponent); QString unitString; switch (m_unit) { case HERTZ: unitString = "HERTZ"; break; case METER: unitString = "METER"; break; case RADIAN: unitString = "RADIAN"; break; case SECOND: unitString = "SECOND"; break; } xml.writeAttribute("NumberOfSeriesPoints", QString::number(m_length)); xml.writeAttribute("SeriesExponent", QString::number(exponent)); xml.writeAttribute("SeriesStart", QString::number(mult * m_start, 'f', 7)); xml.writeAttribute("SeriesStep", QString::number(mult * m_step, 'f', 7)); xml.writeAttribute("SeriesUnit", unitString); } connectome-workbench-1.4.2/src/Cifti/CiftiSeriesMap.h000066400000000000000000000100341360521144700224760ustar00rootroot00000000000000#ifndef __CIFTI_SERIES_MAP_H__ #define __CIFTI_SERIES_MAP_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiMappingType.h" namespace caret { class CiftiSeriesMap : public CiftiMappingType { public: enum Unit { HERTZ, METER, RADIAN, SECOND };//should this go somewhere else? float getStart() const { return m_start; }//using getter/setter as style choice to match other mapping types float getStep() const { return m_step; }//getter for number of series points is getLength(), specified by CiftiIndexMap Unit getUnit() const { return m_unit; } CiftiSeriesMap() { m_start = 0.0f; m_step = 1.0f; m_unit = SECOND; m_length = -1;//to make it clear an improperly initialized series map object was used } CiftiSeriesMap(const int64_t& length, const float& start = 0.0f, const float& step = 1.0f, const Unit& unit = SECOND) { m_start = start; m_step = step; m_unit = unit; m_length = length; } void setStart(const float& start) { m_start = start; } void setStep(const float& step) { m_step = step; } void setUnit(const Unit& unit) { m_unit = unit; } void setLength(const int64_t& length); static Unit stringToUnit(const QString& string, bool& ok); static QString unitToString(const Unit& theUnit); static std::vector getAllUnits(); CiftiMappingType* clone() const { return new CiftiSeriesMap(*this); } MappingType getType() const { return SERIES; } int64_t getLength() const { return m_length; } bool operator==(const CiftiMappingType& rhs) const { if (rhs.getType() != getType()) return false; const CiftiSeriesMap& temp = dynamic_cast(rhs); return (temp.m_length == m_length && temp.m_unit == m_unit && temp.m_start == m_start && temp.m_step == m_step); } bool approximateMatch(const CiftiMappingType& rhs, QString* explanation = NULL) const { switch (rhs.getType()) { case SCALARS://maybe? case SERIES: case LABELS://maybe? if (getLength() != rhs.getLength()) { if (explanation != NULL) *explanation = "mappings have different length"; return false; } else return true; default: if (explanation != NULL) *explanation = CiftiMappingType::mappingTypeToName(rhs.getType()) + " mapping never matches " + CiftiMappingType::mappingTypeToName(getType()); return false; } } void readXML1(QXmlStreamReader& xml); void readXML2(QXmlStreamReader& xml); void writeXML1(QXmlStreamWriter& xml) const; void writeXML2(QXmlStreamWriter& xml) const; private: int64_t m_length; float m_start, m_step;//exponent gets applied to these on reading Unit m_unit; }; } #endif //__CIFTI_SERIES_MAP_H__ connectome-workbench-1.4.2/src/Cifti/CiftiVersion.cxx000066400000000000000000000063031360521144700226120ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiVersion.h" #include "DataFileException.h" using namespace caret; CiftiVersion::CiftiVersion() { m_major = 2; m_minor = 0; } CiftiVersion::CiftiVersion(const int16_t& major, const int16_t& minor) { m_major = major; m_minor = minor; } CiftiVersion::CiftiVersion(const QString& versionString) { int result = versionString.indexOf('.'); bool ok = false; if (result < 0) { m_minor = 0; m_major = versionString.toShort(&ok); if (!ok) throw DataFileException("improperly formatted CIFTI version string: '" + versionString + "'"); } else { if (result == 0) throw DataFileException("improperly formatted CIFTI version string: '" + versionString + "'"); m_major = versionString.mid(0, result).toShort(&ok); if (!ok) throw DataFileException("improperly formatted CIFTI version string: '" + versionString + "'"); m_minor = versionString.mid(result + 1).toShort(&ok); if (!ok) throw DataFileException("improperly formatted CIFTI version string: '" + versionString + "'"); } } bool CiftiVersion::hasReversedFirstDims() const { if (m_major == 1 && m_minor == 0) return true; return false; } bool CiftiVersion::operator<(const CiftiVersion& rhs) const { if (m_major < rhs.m_major) return true; if (m_major == rhs.m_major && m_minor < rhs.m_minor) return true; return false; } bool CiftiVersion::operator<=(const CiftiVersion& rhs) const { if (m_major < rhs.m_major) return true; if (m_major == rhs.m_major && m_minor <= rhs.m_minor) return true; return false; } bool CiftiVersion::operator==(const CiftiVersion& rhs) const { if (m_major == rhs.m_major && m_minor == rhs.m_minor) return true; return false; } bool CiftiVersion::operator!=(const CiftiVersion& rhs) const { return !(*this == rhs); } bool CiftiVersion::operator>(const caret::CiftiVersion& rhs) const { if (m_major > rhs.m_major) return true; if (m_major == rhs.m_major && m_minor > rhs.m_minor) return true; return false; } bool CiftiVersion::operator>=(const caret::CiftiVersion& rhs) const { if (m_major > rhs.m_major) return true; if (m_major == rhs.m_major && m_minor >= rhs.m_minor) return true; return false; } QString CiftiVersion::toString() const { QString ret = QString::number(m_major); if (m_minor != 0) ret += "." + QString::number(m_minor); return ret; } connectome-workbench-1.4.2/src/Cifti/CiftiVersion.h000066400000000000000000000033371360521144700222430ustar00rootroot00000000000000#ifndef __CIFTI_VERSION_H__ #define __CIFTI_VERSION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "stdint.h" namespace caret { class CiftiVersion { int16_t m_major, m_minor; public: int16_t getMajor() const { return m_major; } int16_t getMinor() const { return m_minor; } CiftiVersion(); CiftiVersion(const int16_t& major, const int16_t& minor); CiftiVersion(const QString& versionString); QString toString() const; bool operator<(const CiftiVersion& rhs) const; bool operator>(const CiftiVersion& rhs) const; bool operator==(const CiftiVersion& rhs) const; bool operator!=(const CiftiVersion& rhs) const; bool operator<=(const CiftiVersion& rhs) const; bool operator>=(const CiftiVersion& rhs) const; ///quirk tests bool hasReversedFirstDims() const; }; } #endif //__CIFTI_VERSION_H__ connectome-workbench-1.4.2/src/Cifti/CiftiXML.cxx000066400000000000000000001047341360521144700216340ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiXML.h" #include "CaretAssert.h" #include "DataFileException.h" #include "CaretLogger.h" #include "GiftiMetaData.h" #include "PaletteColorMapping.h" #include #include using namespace std; using namespace caret; int CiftiXML::directionFromString(const QString& input) { bool ok = false; int converted = input.toInt(&ok); if (ok) { if (converted < 1) throw DataFileException("invalid integer direction, use 1 or greater"); return converted - 1;//use 1-indexed convention for input } if (input == "ROW") return ALONG_ROW; if (input == "COLUMN") return ALONG_COLUMN;//should we also allow STACK? integers seem cleaner throw DataFileException("unrecognized direction string, please use an integer, 'ROW', or 'COLUMN'"); } QString CiftiXML::directionFromStringExplanation() { return "The direction can be either an integer starting from 1, or the strings 'ROW' or 'COLUMN'."; } CiftiXML::CiftiXML(const CiftiXML& rhs) { copyHelper(rhs); } CiftiXML& CiftiXML::operator=(const CiftiXML& rhs) { if (this != &rhs) copyHelper(rhs); return *this; } void CiftiXML::copyHelper(const CiftiXML& rhs) { int numDims = (int)rhs.m_indexMaps.size(); m_indexMaps.resize(numDims); for (int i = 0; i < numDims; ++i) { m_indexMaps[i] = CaretPointer(rhs.m_indexMaps[i]->clone()); } m_parsedVersion = rhs.m_parsedVersion; m_fileMetaData = rhs.m_fileMetaData; if (rhs.m_filePalette != NULL) { m_filePalette.grabNew(new PaletteColorMapping()); *(m_filePalette) = *(rhs.m_filePalette); } else { m_filePalette.grabNew(NULL); } } bool CiftiXML::operator==(const CiftiXML& rhs) const { int numDims = getNumberOfDimensions(); if (rhs.getNumberOfDimensions() != numDims) return false; if (m_fileMetaData != rhs.m_fileMetaData) return false; if ((*getFilePalette()) != (*rhs.getFilePalette())) return false; for (int i = 0; i < numDims; ++i) { const CiftiMappingType* left = getMap(i), *right = rhs.getMap(i); if (left == NULL && right == NULL) continue; if (left == NULL || right == NULL) return false;//only one NULL, due to above test if ((*left) != (*right)) return false;//finally can dereference them } return true; } bool CiftiXML::approximateMatch(const CiftiXML& rhs) const { int numDims = getNumberOfDimensions(); if (rhs.getNumberOfDimensions() != numDims) return false; for (int i = 0; i < numDims; ++i) { const CiftiMappingType* left = getMap(i), *right = rhs.getMap(i); if (left == NULL && right == NULL) continue; if (left == NULL || right == NULL) return false;//only one NULL, due to above test if (!left->approximateMatch(*right)) return false;//finally can dereference them } return true; } const CiftiMappingType* CiftiXML::getMap(const int& direction) const { CaretAssertVectorIndex(m_indexMaps, direction); return m_indexMaps[direction]; } CiftiMappingType* CiftiXML::getMap(const int& direction) { CaretAssertVectorIndex(m_indexMaps, direction); return m_indexMaps[direction]; } GiftiMetaData* CiftiXML::getFileMetaData() const { return &m_fileMetaData; } PaletteColorMapping* CiftiXML::getFilePalette() const { if (m_filePalette != NULL) { return m_filePalette; } m_filePalette.grabNew(new PaletteColorMapping()); if (m_fileMetaData.exists("PaletteColorMapping")) { try { m_filePalette->decodeFromStringXML(m_fileMetaData.get("PaletteColorMapping")); } catch (XmlException& e) { CaretLogWarning("failed to parse palette settings from metadata: " + e.whatString()); } } return m_filePalette; } const CiftiBrainModelsMap& CiftiXML::getBrainModelsMap(const int& direction) const { CaretAssertVectorIndex(m_indexMaps, direction); CaretAssert(getMappingType(direction) == CiftiMappingType::BRAIN_MODELS);//assert so we catch it in debug return dynamic_cast(*getMap(direction));//let release throw bad_cast or segfault } CiftiBrainModelsMap& CiftiXML::getBrainModelsMap(const int& direction) { CaretAssertVectorIndex(m_indexMaps, direction); CaretAssert(getMappingType(direction) == CiftiMappingType::BRAIN_MODELS);//assert so we catch it in debug return dynamic_cast(*getMap(direction));//let release throw bad_cast or segfault } const CiftiLabelsMap& CiftiXML::getLabelsMap(const int& direction) const { CaretAssertVectorIndex(m_indexMaps, direction); CaretAssert(getMappingType(direction) == CiftiMappingType::LABELS);//assert so we catch it in debug return dynamic_cast(*getMap(direction));//let release throw bad_cast or segfault } CiftiLabelsMap& CiftiXML::getLabelsMap(const int& direction) { CaretAssertVectorIndex(m_indexMaps, direction); CaretAssert(getMappingType(direction) == CiftiMappingType::LABELS);//assert so we catch it in debug return dynamic_cast(*getMap(direction));//let release throw bad_cast or segfault } const CiftiParcelsMap& CiftiXML::getParcelsMap(const int& direction) const { CaretAssertVectorIndex(m_indexMaps, direction); CaretAssert(getMappingType(direction) == CiftiMappingType::PARCELS);//assert so we catch it in debug return dynamic_cast(*getMap(direction));//let release throw bad_cast or segfault } CiftiParcelsMap& CiftiXML::getParcelsMap(const int& direction) { CaretAssertVectorIndex(m_indexMaps, direction); CaretAssert(getMappingType(direction) == CiftiMappingType::PARCELS);//assert so we catch it in debug return dynamic_cast(*getMap(direction));//let release throw bad_cast or segfault } const CiftiScalarsMap& CiftiXML::getScalarsMap(const int& direction) const { CaretAssertVectorIndex(m_indexMaps, direction); CaretAssert(getMappingType(direction) == CiftiMappingType::SCALARS);//assert so we catch it in debug return dynamic_cast(*getMap(direction));//let release throw bad_cast or segfault } CiftiScalarsMap& CiftiXML::getScalarsMap(const int& direction) { CaretAssertVectorIndex(m_indexMaps, direction); CaretAssert(getMappingType(direction) == CiftiMappingType::SCALARS);//assert so we catch it in debug return dynamic_cast(*getMap(direction));//let release throw bad_cast or segfault } const CiftiSeriesMap& CiftiXML::getSeriesMap(const int& direction) const { CaretAssertVectorIndex(m_indexMaps, direction); CaretAssert(getMappingType(direction) == CiftiMappingType::SERIES);//assert so we catch it in debug return dynamic_cast(*getMap(direction));//let release throw bad_cast or segfault } CiftiSeriesMap& CiftiXML::getSeriesMap(const int& direction) { CaretAssertVectorIndex(m_indexMaps, direction); CaretAssert(getMappingType(direction) == CiftiMappingType::SERIES);//assert so we catch it in debug return dynamic_cast(*getMap(direction));//let release throw bad_cast or segfault } int64_t CiftiXML::getDimensionLength(const int& direction) const { const CiftiMappingType* tempMap = getMap(direction); CaretAssert(tempMap != NULL); return tempMap->getLength(); } vector CiftiXML::getDimensions() const { vector ret(getNumberOfDimensions()); for (int i = 0; i < (int)ret.size(); ++i) { ret[i] = getDimensionLength(i); } return ret; } CiftiMappingType::MappingType CiftiXML::getMappingType(const int& direction) const { CaretAssertVectorIndex(m_indexMaps, direction); CaretAssert(m_indexMaps[direction] != NULL); return m_indexMaps[direction]->getType(); } void CiftiXML::setMap(const int& direction, const CiftiMappingType& mapIn) { CaretAssertVectorIndex(m_indexMaps, direction); if (mapIn.getType() == CiftiMappingType::LABELS) { for (int i = 0; i < getNumberOfDimensions(); ++i) { if (i != direction && m_indexMaps[i] != NULL && m_indexMaps[i]->getType() == CiftiMappingType::LABELS) { throw DataFileException("Cifti XML cannot contain a label mapping on more than one dimension"); } } } m_indexMaps[direction] = CaretPointer(mapIn.clone()); } void CiftiXML::setNumberOfDimensions(const int& num) { m_indexMaps.resize(num); } void CiftiXML::clear() { setNumberOfDimensions(0); m_filePalette.grabNew(NULL); m_fileMetaData.clear(false); m_parsedVersion = CiftiVersion(); } void CiftiXML::readXML(const QString& text) { QXmlStreamReader xml(text); readXML(xml); } void CiftiXML::readXML(const QByteArray& data) { QString text(data);//constructing a qstring appears to be the simplest way to remove trailing nulls, which otherwise trip an "Extra content at end of document" error readXML(text);//then put it through the string reader, just to simplify code paths } int32_t CiftiXML::getIntentInfo(const CiftiVersion& writingVersion, char intentNameOut[16]) const { int32_t ret; const char* name = NULL; if (writingVersion == CiftiVersion(1, 0))//cifti-1: unknown didn't exist, and "ConnDense" was default { ret = 3001;//default name = "ConnDense"; if (getNumberOfDimensions() > 0 && getMappingType(0) == CiftiMappingType::SERIES) { ret = 3002; name = "ConnDenseTime"; }//same logic as was actually used in CiftiFile if (getNumberOfDimensions() > 1 && getMappingType(1) == CiftiMappingType::SERIES) { ret = 3002; name = "ConnDenseTime"; }//NOTE: name for this code is different than cifti-2 } else if (writingVersion == CiftiVersion(1, 1) || writingVersion == CiftiVersion(2, 0)) {//cifti-2 ret = 3000;//default name = "ConnUnknown"; switch (getNumberOfDimensions()) { case 2: { CiftiMappingType::MappingType first = getMappingType(0), second = getMappingType(1); if (first == CiftiMappingType::BRAIN_MODELS && second == CiftiMappingType::BRAIN_MODELS) { ret = 3001; name = "ConnDense"; } if (first == CiftiMappingType::SERIES && second == CiftiMappingType::BRAIN_MODELS) { ret = 3002; name = "ConnDenseSeries"; } if (first == CiftiMappingType::PARCELS && second == CiftiMappingType::PARCELS) { ret = 3003; name = "ConnParcels"; } if (first == CiftiMappingType::SERIES && second == CiftiMappingType::PARCELS) { ret = 3004; name = "ConnParcelSries"; }//NOTE: 3005 is reserved but not used if (first == CiftiMappingType::SCALARS && second == CiftiMappingType::BRAIN_MODELS) { ret = 3006; name = "ConnDenseScalar"; } if (first == CiftiMappingType::LABELS && second == CiftiMappingType::BRAIN_MODELS) { ret = 3007; name = "ConnDenseLabel"; } if (first == CiftiMappingType::SCALARS && second == CiftiMappingType::PARCELS) { ret = 3008; name = "ConnParcelScalr"; } if (first == CiftiMappingType::BRAIN_MODELS && second == CiftiMappingType::PARCELS) { ret = 3009; name = "ConnParcelDense"; } if (first == CiftiMappingType::PARCELS && second == CiftiMappingType::BRAIN_MODELS) { ret = 3010; name = "ConnDenseParcel"; } break; } case 3: { CiftiMappingType::MappingType first = getMappingType(0), second = getMappingType(1), third = getMappingType(2); if (first == CiftiMappingType::PARCELS && second == CiftiMappingType::PARCELS && third == CiftiMappingType::SERIES) { ret = 3011; name = "ConnPPSr"; } if (first == CiftiMappingType::PARCELS && second == CiftiMappingType::PARCELS && third == CiftiMappingType::SCALARS) { ret = 3012; name = "ConnPPSc"; } break; } default: break; } } else { throw DataFileException("unknown cifti version: " + writingVersion.toString()); } int i; for (i = 0; i < 16 && name[i] != '\0'; ++i) intentNameOut[i] = name[i]; for (; i < 16; ++i) intentNameOut[i] = '\0'; return ret; } void CiftiXML::readXML(QXmlStreamReader& xml) { clear(); try { bool haveCifti = false; for (; !xml.atEnd(); xml.readNext()) { if (xml.isStartElement()) { QStringRef name = xml.name(); if (name == "CIFTI") { if (haveCifti) { throw DataFileException("CIFTI element may only be specified once"); } QXmlStreamAttributes attributes = xml.attributes(); if(attributes.hasAttribute("Version")) { m_parsedVersion = CiftiVersion(attributes.value("Version").toString()); } else { throw DataFileException("Cifti XML missing Version attribute."); } if (m_parsedVersion == CiftiVersion(1, 0))//switch/case on major/minor would be much harder to read { parseCIFTI1(xml); if (xml.hasError()) break; } else if (m_parsedVersion == CiftiVersion(1, 1)) { CaretLogWarning("parsing cifti version '1.1', this should not exist in the wild"); parseCIFTI2(xml);//we used "1.1" to test our cifti-2 implementation if (xml.hasError()) break; } else if (m_parsedVersion == CiftiVersion(2, 0)) { parseCIFTI2(xml); if (xml.hasError()) break; } else { throw DataFileException("unknown Cifti Version: '" + m_parsedVersion.toString()); } haveCifti = true; } else { throw DataFileException("unexpected root element in Cifti XML: " + name.toString()); } } } if (!xml.hasError() && !haveCifti) { throw DataFileException("CIFTI element not found"); } } catch (CaretException& e) { throw DataFileException("Cifti XML error: " + e.whatString());//so we can throw on error instead of doing a bunch of dancing with xml.raiseError and xml.hasError } if(xml.hasError()) { throw DataFileException("Cifti XML error: " + xml.errorString()); } } void CiftiXML::parseCIFTI1(QXmlStreamReader& xml) { QXmlStreamAttributes attributes = xml.attributes(); if (attributes.hasAttribute("NumberOfMatrices")) { if (attributes.value("NumberOfMatrices") != "1") { throw DataFileException("attribute NumberOfMatrices in CIFTI is required to be 1 for CIFTI-1"); } } else { throw DataFileException("missing attribute NumberOfMatrices in CIFTI"); } bool haveMatrix = false; while (!xml.atEnd()) { xml.readNext(); if (xml.isStartElement()) { QStringRef name = xml.name(); if (name == "Matrix") { if (haveMatrix) { throw DataFileException("Matrix element may only be specified once"); } parseMatrix1(xml); if (xml.hasError()) return; haveMatrix = true; } else { throw DataFileException("unexpected element in CIFTI: " + name.toString()); } } else if (xml.isEndElement()) { break; } } if (!haveMatrix) { throw DataFileException("Matrix element not found in CIFTI"); } if (xml.hasError()) return; CaretAssert(xml.isEndElement() && xml.name() == "CIFTI"); } void CiftiXML::parseCIFTI2(QXmlStreamReader& xml)//yes, these will often have largely similar code, but it seems cleaner than having only some functions split, or constantly rechecking the version {//also, helps keep changes to cifti-2 away from code that parses cifti-1 bool haveMatrix = false; while (!xml.atEnd()) { xml.readNext(); if (xml.hasError()) return; if (xml.isStartElement()) { QStringRef name = xml.name(); if (name == "Matrix") { if (haveMatrix) { throw DataFileException("Matrix element may only be specified once"); } parseMatrix2(xml); if (xml.hasError()) return; haveMatrix = true; } else { throw DataFileException("unexpected element in CIFTI: " + name.toString()); } } else if (xml.isEndElement()) { break; } } if (!haveMatrix) { throw DataFileException("Matrix element not found in CIFTI"); } CaretAssert(xml.isEndElement() && xml.name() == "CIFTI"); } void CiftiXML::parseMatrix1(QXmlStreamReader& xml) { VolumeSpace fileVolSpace; bool haveVolSpace = false, haveMetadata = false; while (!xml.atEnd()) { xml.readNext(); if (xml.hasError()) return; if (xml.isStartElement()) { QStringRef name = xml.name(); if (name == "MetaData") { if (haveMetadata) { throw DataFileException("MetaData may only be specified once in Matrix"); } m_fileMetaData.readCiftiXML1(xml); if (xml.hasError()) return; haveMetadata = true; } else if (name == "MatrixIndicesMap") { parseMatrixIndicesMap1(xml); if (xml.hasError()) return; } else if (name == "Volume") { if (haveVolSpace) { throw DataFileException("Volume may only be specified once in Matrix"); } fileVolSpace.readCiftiXML1(xml); if (xml.hasError()) return; haveVolSpace = true; } else if (name == "LabelTable") { CaretLogFiner("skipping unused LabelTable element in Matrix in CIFTI-1"); xml.readElementText(QXmlStreamReader::SkipChildElements); } else { throw DataFileException("unexpected element in Matrix: " + name.toString()); } } else if (xml.isEndElement()) { break; } } for (int i = 0; i < (int)m_indexMaps.size(); ++i) { if (m_indexMaps[i] == NULL) { int displaynum = i; if (displaynum < 2) displaynum = 1 - displaynum;//re-invert so that it shows the same number as the XML is missing throw DataFileException("missing mapping for dimension '" + QString::number(displaynum) + "'"); } switch (m_indexMaps[i]->getType()) { case CiftiMappingType::BRAIN_MODELS: { CiftiBrainModelsMap& myMap = dynamic_cast(*(m_indexMaps[i])); if (myMap.hasVolumeData()) { if (haveVolSpace) { myMap.setVolumeSpace(fileVolSpace);//also does the needed checking of voxel indices } else { throw DataFileException("BrainModels map uses voxels, but no Volume element exists"); } } break; } case CiftiMappingType::PARCELS: { CiftiParcelsMap& myMap = dynamic_cast(*(m_indexMaps[i])); if (myMap.hasVolumeData()) { if (haveVolSpace) { myMap.setVolumeSpace(fileVolSpace);//ditto } else { throw DataFileException("Parcels map uses voxels, but no Volume element exists"); } } break; } default: break; } } CaretAssert(xml.isEndElement() && xml.name() == "Matrix"); } void CiftiXML::parseMatrix2(QXmlStreamReader& xml) { bool haveMetadata = false; while (!xml.atEnd()) { xml.readNext(); if (xml.hasError()) return; if (xml.isStartElement()) { QStringRef name = xml.name(); if (name == "MetaData") { if (haveMetadata) { throw DataFileException("MetaData may only be specified once in Matrix"); } m_fileMetaData.readCiftiXML2(xml); if (xml.hasError()) return; haveMetadata = true; } else if (name == "MatrixIndicesMap") { parseMatrixIndicesMap2(xml); if (xml.hasError()) return; } else { throw DataFileException("unexpected element in Matrix: " + name.toString()); } } else if (xml.isEndElement()) { break; } } for (int i = 0; i < (int)m_indexMaps.size(); ++i) { if (m_indexMaps[i] == NULL) { throw DataFileException("missing mapping for dimension '" + QString::number(i) + "'"); } } CaretAssert(xml.isEndElement() && xml.name() == "Matrix"); } void CiftiXML::parseMatrixIndicesMap1(QXmlStreamReader& xml) { QXmlStreamAttributes attributes = xml.attributes(); if (!attributes.hasAttribute("AppliesToMatrixDimension")) { throw DataFileException("missing attribute AppliesToMatrixDimension in MatrixIndicesMap"); } if (!attributes.hasAttribute("IndicesMapToDataType")) { throw DataFileException("missing attribute IndicesMapToDataType in MatrixIndicesMap"); } QStringList values = attributes.value("AppliesToMatrixDimension").toString().split(','); bool ok = false; set used; for(int i = 0; i < values.size(); i++) { int parsed = values[i].toInt(&ok); if (!ok || parsed < 0) { throw DataFileException("bad value in AppliesToMatrixDimension list: " + values[i]); } if (parsed < 2) parsed = 1 - parsed;//in other words, 0 becomes 1 and 1 becomes 0, since cifti-1 had them reversed if (used.find(parsed) != used.end()) { throw DataFileException("AppliesToMatrixDimension contains repeated value: " + values[i]); } used.insert(parsed); } CaretPointer toRead; QStringRef type = attributes.value("IndicesMapToDataType"); if (type == "CIFTI_INDEX_TYPE_BRAIN_MODELS") { toRead = CaretPointer(new CiftiBrainModelsMap()); } else if (type == "CIFTI_INDEX_TYPE_TIME_POINTS") { toRead = CaretPointer(new CiftiSeriesMap()); } else if (type == "CIFTI_INDEX_TYPE_LABELS") {//this and below are nonstandard toRead = CaretPointer(new CiftiLabelsMap()); } else if (type == "CIFTI_INDEX_TYPE_PARCELS") { toRead = CaretPointer(new CiftiParcelsMap()); } else if (type == "CIFTI_INDEX_TYPE_SCALARS") { toRead = CaretPointer(new CiftiScalarsMap()); } else { throw DataFileException("invalid value for IndicesMapToDataType in CIFTI-1: " + type.toString()); } toRead->readXML1(xml);//this will warn (with 'finer' log level?) if it is nonstandard if (xml.hasError()) return; bool first = true; for (set::iterator iter = used.begin(); iter != used.end(); ++iter) { if (*iter >= (int)m_indexMaps.size()) m_indexMaps.resize(*iter + 1); if (first) { m_indexMaps[*iter] = toRead; first = false; } else { m_indexMaps[*iter] = CaretPointer(toRead->clone());//make in-memory information independent per-dimension, rather than dealing with deduplication everywhere } } CaretAssert(xml.isEndElement() && xml.name() == "MatrixIndicesMap"); } void CiftiXML::parseMatrixIndicesMap2(QXmlStreamReader& xml) { QXmlStreamAttributes attributes = xml.attributes(); if (!attributes.hasAttribute("AppliesToMatrixDimension")) { throw DataFileException("missing attribute AppliesToMatrixDimension in MatrixIndicesMap"); } if (!attributes.hasAttribute("IndicesMapToDataType")) { throw DataFileException("missing attribute IndicesMapToDataType in MatrixIndicesMap"); } QStringList values = attributes.value("AppliesToMatrixDimension").toString().split(','); bool ok = false; set used; for(int i = 0; i < values.size(); i++) { int parsed = values[i].toInt(&ok); if (!ok || parsed < 0) { throw DataFileException("bad value in AppliesToMatrixDimension list: " + values[i]); } if (used.find(parsed) != used.end()) { throw DataFileException("AppliesToMatrixDimension contains repeated value: " + values[i]); } used.insert(parsed); } CaretPointer toRead; QStringRef type = attributes.value("IndicesMapToDataType"); if (type == "CIFTI_INDEX_TYPE_BRAIN_MODELS") { toRead = CaretPointer(new CiftiBrainModelsMap()); } else if (type == "CIFTI_INDEX_TYPE_LABELS") { toRead = CaretPointer(new CiftiLabelsMap()); } else if (type == "CIFTI_INDEX_TYPE_PARCELS") { toRead = CaretPointer(new CiftiParcelsMap()); } else if (type == "CIFTI_INDEX_TYPE_SCALARS") { toRead = CaretPointer(new CiftiScalarsMap()); } else if (type == "CIFTI_INDEX_TYPE_SERIES") { toRead = CaretPointer(new CiftiSeriesMap()); } else { throw DataFileException("invalid value for IndicesMapToDataType in CIFTI-1: " + type.toString()); } toRead->readXML2(xml); if (xml.hasError()) return; bool first = true; for (set::iterator iter = used.begin(); iter != used.end(); ++iter) { if (*iter >= (int)m_indexMaps.size()) m_indexMaps.resize(*iter + 1); if (first) { m_indexMaps[*iter] = toRead; first = false; } else { m_indexMaps[*iter] = CaretPointer(toRead->clone());//make in-memory information independent per-dimension, rather than dealing with deduplication everywhere } } CaretAssert(xml.isEndElement() && xml.name() == "MatrixIndicesMap"); } QByteArray CiftiXML::writeXMLToQByteArray(const CiftiVersion& writingVersion) const { QByteArray ret; QXmlStreamWriter xml(&ret); xml.setAutoFormatting(true); xml.writeStartDocument(); writeXML(xml, writingVersion); xml.writeEndDocument(); return ret; } QString CiftiXML::writeXMLToString(const CiftiVersion& writingVersion) const { QString ret; QXmlStreamWriter xml(&ret); xml.setAutoFormatting(true); xml.writeStartDocument(); writeXML(xml, writingVersion); xml.writeEndDocument(); return ret; } void CiftiXML::writeXML(QXmlStreamWriter& xml, const CiftiVersion& writingVersion) const { xml.writeStartElement("CIFTI"); xml.writeAttribute("Version", writingVersion.toString()); if (writingVersion == CiftiVersion(1, 0))//switch/case on major/minor would be much harder to read { xml.writeAttribute("NumberOfMatrices", "1"); writeMatrix1(xml); } else if (writingVersion == CiftiVersion(1, 1)) {//we used "1.1" to test our cifti-2 implementation - should we even allow this? CaretLogWarning("writing cifti version '1.1', this should not exist in the wild"); writeMatrix2(xml); } else if (writingVersion == CiftiVersion(2, 0)) { writeMatrix2(xml); } else { throw DataFileException("unknown Cifti writing version: '" + writingVersion.toString() + "'"); } xml.writeEndElement(); } void CiftiXML::writeMatrix1(QXmlStreamWriter& xml) const { int numDims = (int)m_indexMaps.size(); bool haveVolData = false; VolumeSpace volSpace; for (int i = 0; i < numDims; ++i) { if (m_indexMaps[i] == NULL) throw DataFileException("dimension " + QString::number(i) + " was not given a mapping"); switch (m_indexMaps[i]->getType()) { case CiftiMappingType::BRAIN_MODELS: { const CiftiBrainModelsMap& myMap = dynamic_cast(*(m_indexMaps[i])); if (myMap.hasVolumeData()) { if (haveVolData) { if (myMap.getVolumeSpace() != volSpace) { throw DataFileException("cannot write different volume spaces for different dimensions in CIFTI-1"); } } else { haveVolData = true; volSpace = myMap.getVolumeSpace(); } } break; } case CiftiMappingType::PARCELS: { const CiftiParcelsMap& myMap = dynamic_cast(*(m_indexMaps[i])); if (myMap.hasVolumeData()) { if (haveVolData) { if (myMap.getVolumeSpace() != volSpace) { throw DataFileException("cannot write different volume spaces for different dimensions in CIFTI-1"); } } else { haveVolData = true; volSpace = myMap.getVolumeSpace(); } } break; } default: break; } } xml.writeStartElement("Matrix"); if (m_filePalette != NULL) { m_fileMetaData.set("PaletteColorMapping", m_filePalette->encodeInXML()); } m_fileMetaData.writeCiftiXML1(xml); if (haveVolData) { volSpace.writeCiftiXML1(xml); } vector used(numDims, false); for (int i = 0; i < numDims; ++i) { if (!used[i]) { used[i] = true; int outputNum = i; if (outputNum < 2) outputNum = 1 - outputNum;//ie, swap 0 and 1 QString appliesTo = QString::number(outputNum);//initialize containing just the current dimension for (int j = i + 1; j < numDims; ++j)//compare to all later unused dimensions for deduplication {//technically, shouldn't need to check for previously used as long as equality is exact, but means maybe fewer comparisons, and to prevent a bug in == from getting stranger behavior if (!used[j]) { if ((*m_indexMaps[i]) == (*m_indexMaps[j])) { outputNum = j; if (outputNum < 2) outputNum = 1 - outputNum; appliesTo += "," + QString::number(outputNum); used[j] = true; } } } xml.writeStartElement("MatrixIndicesMap");//should the CiftiIndexMap do this instead, and we pass appliesTo to it as string? probably not important, we won't use them in any other xml xml.writeAttribute("AppliesToMatrixDimension", appliesTo); m_indexMaps[i]->writeXML1(xml); xml.writeEndElement(); } } xml.writeEndElement(); } void CiftiXML::writeMatrix2(QXmlStreamWriter& xml) const { int numDims = (int)m_indexMaps.size(); for (int i = 0; i < numDims; ++i) { if (m_indexMaps[i] == NULL) throw DataFileException("dimension " + QString::number(i) + " was not given a mapping"); } xml.writeStartElement("Matrix"); if (m_filePalette != NULL) { m_fileMetaData.set("PaletteColorMapping", m_filePalette->encodeInXML()); } m_fileMetaData.writeCiftiXML2(xml); vector used(numDims, false); for (int i = 0; i < numDims; ++i) { if (!used[i]) { used[i] = true; QString appliesTo = QString::number(i);//initialize containing just the current dimension for (int j = i + 1; j < numDims; ++j)//compare to all later unused dimensions for deduplication {//technically, shouldn't need to check for previously used as long as equality is exact, but means maybe fewer comparisons, and to prevent a bug in == from getting stranger behavior if (!used[j]) { if ((*m_indexMaps[i]) == (*m_indexMaps[j])) { appliesTo += "," + QString::number(j); used[j] = true; } } } xml.writeStartElement("MatrixIndicesMap");//should the CiftiIndexMap do this instead, and we pass appliesTo to it as string? probably not important, we won't use them in any other xml xml.writeAttribute("AppliesToMatrixDimension", appliesTo); m_indexMaps[i]->writeXML2(xml); xml.writeEndElement(); } } xml.writeEndElement(); } bool CiftiXML::mutablesModified() const { if (m_fileMetaData.isModified()) return true; if (m_filePalette != NULL && m_filePalette->isModified()) return true; for (int d = 0; d < (int)m_indexMaps.size(); ++d) { if (m_indexMaps[d] != NULL && m_indexMaps[d]->mutablesModified()) return true; } return false; } void CiftiXML::clearMutablesModified() const { m_fileMetaData.clearModified(); if (m_filePalette != NULL) m_filePalette->clearModified(); for (int d = 0; d < (int)m_indexMaps.size(); ++d) { if (m_indexMaps[d] != NULL) m_indexMaps[d]->clearMutablesModified(); } } connectome-workbench-1.4.2/src/Cifti/CiftiXML.h000066400000000000000000000123541360521144700212550ustar00rootroot00000000000000#ifndef __CIFTI_XML_H__ #define __CIFTI_XML_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretPointer.h" #include "CiftiMappingType.h" #include "CiftiVersion.h" #include "GiftiMetaData.h" //could also be forward declared #include "PaletteColorMapping.h" //just include the mapping types themselves, for convenience #include "CiftiBrainModelsMap.h" #include "CiftiLabelsMap.h" #include "CiftiParcelsMap.h" #include "CiftiScalarsMap.h" #include "CiftiSeriesMap.h" #include #include #include namespace caret { class CiftiXML { public: enum { ALONG_ROW = 0, ALONG_COLUMN = 1, ALONG_STACK = 2//better name for this? }; int getNumberOfDimensions() const { return m_indexMaps.size(); } const CiftiVersion& getParsedVersion() const { return m_parsedVersion; } const CiftiMappingType* getMap(const int& direction) const;//can return null in unfilled XML object CiftiMappingType* getMap(const int& direction);//can return null in unfilled XML object GiftiMetaData* getFileMetaData() const;//HACK: allow modification of palette and metadata within XML without setting the xml on a file again PaletteColorMapping* getFilePalette() const; CiftiMappingType::MappingType getMappingType(const int& direction) const;//convenience functions const CiftiBrainModelsMap& getBrainModelsMap(const int& direction) const; CiftiBrainModelsMap& getBrainModelsMap(const int& direction); const CiftiLabelsMap& getLabelsMap(const int& direction) const; CiftiLabelsMap& getLabelsMap(const int& direction); const CiftiParcelsMap& getParcelsMap(const int& direction) const; CiftiParcelsMap& getParcelsMap(const int& direction); const CiftiScalarsMap& getScalarsMap(const int& direction) const; CiftiScalarsMap& getScalarsMap(const int& direction); const CiftiSeriesMap& getSeriesMap(const int& direction) const; CiftiSeriesMap& getSeriesMap(const int& direction); int64_t getDimensionLength(const int& direction) const; std::vector getDimensions() const; void setNumberOfDimensions(const int& num); void setMap(const int& direction, const CiftiMappingType& mapIn); void clear(); void readXML(QXmlStreamReader& xml); void readXML(const QString& text); void readXML(const QByteArray& data); QString writeXMLToString(const CiftiVersion& writingVersion = CiftiVersion()) const; QByteArray writeXMLToQByteArray(const CiftiVersion& writingVersion = CiftiVersion()) const; void writeXML(QXmlStreamWriter& xml, const CiftiVersion& writingVersion = CiftiVersion()) const; ///uses the mapping types to figure out what the intent info should be int32_t getIntentInfo(const CiftiVersion& writingVersion, char intentNameOut[16]) const; CiftiXML() { } CiftiXML(const CiftiXML& rhs); CiftiXML& operator=(const CiftiXML& rhs); bool operator==(const CiftiXML& rhs) const; bool operator!=(const CiftiXML& rhs) const { return !((*this) == rhs); } bool approximateMatch(const CiftiXML& rhs) const; bool mutablesModified() const; void clearMutablesModified() const;//HACK: clear modified status on a const object static int directionFromString(const QString& input);//convenience conversion function, throws on error static QString directionFromStringExplanation();//and explanation text private: std::vector > m_indexMaps; CiftiVersion m_parsedVersion; mutable GiftiMetaData m_fileMetaData;//hack to allow metadata to be modified without allowing dimension-changing operations mutable CaretPointer m_filePalette; void copyHelper(const CiftiXML& rhs); //parsing functions void parseCIFTI1(QXmlStreamReader& xml); void parseMatrix1(QXmlStreamReader& xml); void parseCIFTI2(QXmlStreamReader& xml); void parseMatrix2(QXmlStreamReader& xml); void parseMatrixIndicesMap1(QXmlStreamReader& xml); void parseMatrixIndicesMap2(QXmlStreamReader& xml); //writing functions void writeMatrix1(QXmlStreamWriter& xml) const; void writeMatrix2(QXmlStreamWriter& xml) const; }; } #endif //__CIFTI_XML_H__ connectome-workbench-1.4.2/src/Cifti/CiftiXMLElements.cxx000066400000000000000000000472051360521144700233300ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiXMLElements.h" #include "DataFileException.h" #include "GiftiLabelTable.h" #include "PaletteColorMapping.h" #include "VoxelIJK.h" #include #include using namespace caret; using namespace std; void CiftiBrainModelElement::setupLookup(CiftiMatrixIndicesMapElement& myMap) { if (m_modelType == CIFTI_MODEL_TYPE_SURFACE) { if (m_nodeIndices.size() == 0 && m_indexCount != 0) { if (m_indexCount != m_surfaceNumberOfNodes) { throw DataFileException("empty index list found with nonzero indexCount, but indexCount and surfaceNumberOfNodes don't match"); } m_nodeToIndexLookup.resize(m_surfaceNumberOfNodes); for (int i = 0; i < (int)m_surfaceNumberOfNodes; ++i) { m_nodeToIndexLookup[i] = i + m_indexOffset; } } else { if (m_indexCount != (int64_t)m_nodeIndices.size()) { throw DataFileException("indexCount and size of nodeIndices don't match"); } m_nodeToIndexLookup.resize(m_surfaceNumberOfNodes); for (int i = 0; i < (int)m_surfaceNumberOfNodes; ++i) { m_nodeToIndexLookup[i] = -1; } for (int i = 0; i < (int)m_indexCount; ++i) { m_nodeToIndexLookup[m_nodeIndices[i]] = i + m_indexOffset; } } } if (m_modelType == CIFTI_MODEL_TYPE_VOXELS) {//we need access to the Volume element to support the "empty list" behavior, but since it is never used, and will be removed from the spec, ignore it int64_t voxListSize = (int64_t)m_voxelIndicesIJK.size(); for (int64_t i = 0; i < voxListSize; i += 3) { myMap.m_voxelToIndexLookup.at(m_voxelIndicesIJK[i], m_voxelIndicesIJK[i + 1], m_voxelIndicesIJK[i + 2]) = m_indexOffset + (i / 3); } } } void CiftiMatrixIndicesMapElement::setupLookup() { if (m_indicesMapToDataType == CIFTI_INDEX_TYPE_BRAIN_MODELS) { stable_sort(m_brainModels.begin(), m_brainModels.end());//in order to make the overlapping range check easy, and so that iterating through maps goes linearly through the file int numModels = (int)m_brainModels.size(); set usedSurf, usedVol; for (int i = 0; i < numModels; ++i) { if (i > 0 && m_brainModels[i - 1].m_indexOffset + m_brainModels[i - 1].m_indexCount > m_brainModels[i].m_indexOffset) { throw DataFileException("overlapping index ranges found in a brain models dimension"); } switch (m_brainModels[i].m_modelType) { case CIFTI_MODEL_TYPE_SURFACE: if (usedSurf.find(m_brainModels[i].m_brainStructure) != usedSurf.end()) { throw DataFileException("structure " + StructureEnum::toName(m_brainModels[i].m_brainStructure) + " used multiple times in surface models"); } usedSurf.insert(m_brainModels[i].m_brainStructure); break; case CIFTI_MODEL_TYPE_VOXELS: if (usedVol.find(m_brainModels[i].m_brainStructure) != usedVol.end()) { throw DataFileException("structure " + StructureEnum::toName(m_brainModels[i].m_brainStructure) + " used multiple times in volume models"); } usedVol.insert(m_brainModels[i].m_brainStructure); break; case CIFTI_MODEL_TYPE_INVALID: CaretAssert(false); throw DataFileException("found 'invalid' brain model type, tell the developers"); break; } m_brainModels[i].setupLookup(*this); } } if (m_indicesMapToDataType != CIFTI_INDEX_TYPE_PARCELS) return; int numSurfs = (int)m_parcelSurfaces.size(); for (int i = 0; i < numSurfs; ++i) { m_parcelSurfaces[i].m_lookup.resize(m_parcelSurfaces[i].m_numNodes); for (int j = 0; j < m_parcelSurfaces[i].m_numNodes; ++j) { m_parcelSurfaces[i].m_lookup[j] = -1; } for (int j = i + 1; j < numSurfs; ++j) { if (m_parcelSurfaces[i].m_structure == m_parcelSurfaces[j].m_structure) { throw DataFileException("multiple surfaces with same structure found in a parcel map"); } } } int numParcels = (int)m_parcels.size(); for (int i = 0; i < numParcels; ++i) { const CiftiParcelElement& myParcel = m_parcels[i]; int numSurfParts = (int)myParcel.m_nodeElements.size(); vector surfUsed(m_parcelSurfaces.size(), false); for (int j = 0; j < numSurfParts; ++j) { const CiftiParcelNodesElement& myNodeElement = myParcel.m_nodeElements[j]; StructureEnum::Enum myStruct = myNodeElement.m_structure; int whichSurf; for (whichSurf = 0; whichSurf < numSurfs; ++whichSurf) { if (m_parcelSurfaces[whichSurf].m_structure == myStruct) break; } if (whichSurf >= numSurfs) { throw DataFileException("parcel '" + myParcel.m_parcelName + "' specifies a structure that doesn't match a specified surface"); } if (surfUsed[whichSurf]) { throw DataFileException("parcel '" + myParcel.m_parcelName + "' specified a surface structure more than once"); } CiftiParcelSurfaceElement& mySurf = m_parcelSurfaces[whichSurf]; surfUsed[whichSurf] = true; int numNodes = myNodeElement.m_nodes.size(); for (int k = 0; k < numNodes; ++k) { int64_t node = myNodeElement.m_nodes[k]; if (node < 0 || node >= mySurf.m_numNodes) { throw DataFileException("node number " + AString::number(node) + " is invalid for surface " + StructureEnum::toName(myStruct)); } if (mySurf.m_lookup[node] != -1) { throw DataFileException("surface node " + AString::number(node) + " in surface " + StructureEnum::toName(myStruct) + " specified more than once"); } mySurf.m_lookup[node] = i; } } int64_t voxListSize = (int64_t)myParcel.m_voxelIndicesIJK.size(); for (int64_t j = 0; j < voxListSize; j += 3) { int64_t* test = m_voxelToIndexLookup.find(myParcel.m_voxelIndicesIJK[j], myParcel.m_voxelIndicesIJK[j + 1], myParcel.m_voxelIndicesIJK[j + 2]); if (test != NULL && *test != i) { throw DataFileException("voxel " + AString::number(myParcel.m_voxelIndicesIJK[j]) + ", " + AString::number(myParcel.m_voxelIndicesIJK[j + 1]) + ", " + AString::number(myParcel.m_voxelIndicesIJK[j + 2]) + " used by more than one parcel"); } m_voxelToIndexLookup.at(myParcel.m_voxelIndicesIJK[j], myParcel.m_voxelIndicesIJK[j + 1], myParcel.m_voxelIndicesIJK[j + 2]) = i; } } } bool CiftiMatrixIndicesMapElement::operator==(const CiftiMatrixIndicesMapElement& rhs) const {//NOTE: don't check the applies to dimension vector, this should check only the mapping, not how it is used if (this == &rhs) return true;//compare pointers to skip checking object against itself if (m_indicesMapToDataType != rhs.m_indicesMapToDataType) return false; switch (m_indicesMapToDataType) { case CIFTI_INDEX_TYPE_INVALID: break;//is there anything to check? case CIFTI_INDEX_TYPE_BRAIN_MODELS: { if (m_brainModels.size() != rhs.m_brainModels.size()) return false; vector used(rhs.m_brainModels.size(), false);//prevent reuse, in case some idiocy winds up having overlapping mappings for (size_t i = 0; i < m_brainModels.size(); ++i)//need to allow the mappings to be placed in a different order, as long as the cifti index ranges line up { bool found = false; for (size_t j = 0; j < rhs.m_brainModels.size(); ++j) { if (!used[j] && m_brainModels[i] == rhs.m_brainModels[j]) { used[j] = true; found = true; break; } } if (!found) return false; } } break; case CIFTI_INDEX_TYPE_FIBERS: break;//??? case CIFTI_INDEX_TYPE_PARCELS: { if (m_parcels.size() != rhs.m_parcels.size() || m_parcelSurfaces.size() != rhs.m_parcelSurfaces.size()) return false; vector used(rhs.m_parcelSurfaces.size(), false); for (size_t i = 0; i < m_parcelSurfaces.size(); ++i) { bool found = false; for (size_t j = 0; j < rhs.m_parcelSurfaces.size(); ++j) { if (!used[j] && m_parcelSurfaces[i] == rhs.m_parcelSurfaces[j]) { used[j] = true; found = true; break; } } if (!found) return false; } for (size_t i = 0; i < m_parcels.size(); ++i) { if (m_parcels[i] != rhs.m_parcels[i]) return false; } } break; case CIFTI_INDEX_TYPE_TIME_POINTS: { if (m_numTimeSteps != rhs.m_numTimeSteps) return false; float timestep, rhtimestep; switch (m_timeStepUnits) { case NIFTI_UNITS_SEC: timestep = m_timeStep; break; case NIFTI_UNITS_MSEC: timestep = m_timeStep * 0.001f; break; case NIFTI_UNITS_USEC: timestep = m_timeStep * 0.000001f; break; default: return false; } switch (rhs.m_timeStepUnits) { case NIFTI_UNITS_SEC: rhtimestep = rhs.m_timeStep; break; case NIFTI_UNITS_MSEC: rhtimestep = rhs.m_timeStep * 0.001f; break; case NIFTI_UNITS_USEC: rhtimestep = rhs.m_timeStep * 0.000001f; break; default: return false; } const float TOLERANCE = 0.999f;//if they don't match exactly, and either one of them is zero, or their ratio is far from 1, say they don't match if (timestep != rhtimestep && (timestep == 0.0f || rhtimestep == 0.0f || timestep / rhtimestep < TOLERANCE || rhtimestep / timestep < TOLERANCE)) return false; } break; case CIFTI_INDEX_TYPE_LABELS: case CIFTI_INDEX_TYPE_SCALARS: { size_t size = m_namedMaps.size(); if (rhs.m_namedMaps.size() != size) return false; for (size_t i = 0; i < size; ++i) { if (m_namedMaps[i] != rhs.m_namedMaps[i]) return false; } } break; } return true; } bool CiftiBrainModelElement::operator==(const CiftiBrainModelElement& rhs) const { if (m_indexOffset != rhs.m_indexOffset) return false; if (m_indexCount != rhs.m_indexCount) return false; if (m_modelType != rhs.m_modelType) return false; if (m_brainStructure != rhs.m_brainStructure) return false; switch (m_modelType) { case CIFTI_MODEL_TYPE_SURFACE: { size_t numIndices = m_nodeIndices.size(), rhsIndices = rhs.m_nodeIndices.size(); if (m_surfaceNumberOfNodes != rhs.m_surfaceNumberOfNodes) return false; if (numIndices == 0) { if (rhsIndices != 0) { if ((int64_t)rhsIndices != rhs.m_indexCount) return false; for (size_t i = 0; i < rhsIndices; ++i) { if (rhs.m_nodeIndices[i] != (int64_t)i) return false; } } } else { if (rhsIndices == 0) { if ((int64_t)numIndices != m_indexCount) return false; for (size_t i = 0; i < numIndices; ++i) { if (m_nodeIndices[i] != (int64_t)i) return false; } } else { if (numIndices != rhsIndices) return false; for (size_t i = 0; i < numIndices; ++i) { if (m_nodeIndices[i] != rhs.m_nodeIndices[i]) return false; } } } } break; case CIFTI_MODEL_TYPE_VOXELS: { size_t numIndices = m_voxelIndicesIJK.size(), rhsIndices = m_voxelIndicesIJK.size(); if (numIndices != rhsIndices) return false; for (size_t i = 0; i < numIndices; ++i)//treat them as flat, even though they aren't { if (m_voxelIndicesIJK[i] != rhs.m_voxelIndicesIJK[i]) return false; } } break; case CIFTI_MODEL_TYPE_INVALID: CaretAssert(false); throw DataFileException("found 'invalid' brain model type, tell the developers"); break; } return true; } bool CiftiBrainModelElement::operator<(const CiftiBrainModelElement& rhs) const { return m_indexOffset < rhs.m_indexOffset; } bool CiftiNamedMapElement::operator==(const CiftiNamedMapElement& rhs) const { if (m_mapName != rhs.m_mapName) return false; if (m_labelTable == NULL) { if (rhs.m_labelTable != NULL) return false; } else { if (rhs.m_labelTable == NULL) return false; if (!m_labelTable->matches(*(rhs.m_labelTable))) return false; } return true; } CiftiNamedMapElement::CiftiNamedMapElement(const CiftiNamedMapElement& rhs) { m_mapName = rhs.m_mapName; m_defaultPalette = rhs.m_defaultPalette; m_mapMetaData = rhs.m_mapMetaData; if (rhs.m_palette != NULL) m_palette.grabNew(new PaletteColorMapping(*(rhs.m_palette))); if (rhs.m_labelTable != NULL) m_labelTable.grabNew(new GiftiLabelTable(*(rhs.m_labelTable))); } CiftiNamedMapElement& CiftiNamedMapElement::operator=(const CiftiNamedMapElement& rhs) { if (this == &rhs) return *this; m_mapName = rhs.m_mapName; m_mapMetaData = rhs.m_mapMetaData; if (rhs.m_palette != NULL) { m_palette.grabNew(new PaletteColorMapping(*(rhs.m_palette))); } else { m_palette.grabNew(NULL); } if (rhs.m_labelTable != NULL) { m_labelTable.grabNew(new GiftiLabelTable(*(rhs.m_labelTable))); } else { m_labelTable.grabNew(NULL); } return *this; } ///NOTE: this is not a standard equality test, it skips checking the nodes list because we do that elsewhere bool CiftiParcelNodesElement::operator==(const CiftiParcelNodesElement& rhs) const { if (m_structure != rhs.m_structure) return false; if (m_nodes.size() != rhs.m_nodes.size()) return false; /*for (size_t i = 0; i < m_nodes.size(); ++i) { if (m_nodes[i] != rhs.m_nodes[i]) return false; }//*///not needed, we check node equivalence by checking the lookup in each surface, this way wouldn't work for same nodes in different order anyway return true; } bool CiftiParcelElement::operator==(const CiftiParcelElement& rhs) const { if (m_parcelName != rhs.m_parcelName) return false; if (m_nodeElements.size() != rhs.m_nodeElements.size() || m_voxelIndicesIJK.size() != rhs.m_voxelIndicesIJK.size()) return false; vector used(rhs.m_nodeElements.size(), false); for (size_t i = 0; i < m_nodeElements.size(); ++i) { bool found = false; for (size_t j = 0; j < rhs.m_nodeElements.size(); ++j) { if (!used[j] && m_nodeElements[i] == rhs.m_nodeElements[j]) { found = true; used[j] = true; break; } } if (!found) return false; } set myvoxset, rhsvoxset;//different orders mean the same thing, so sort voxels, then compare for (size_t i = 0; i < m_voxelIndicesIJK.size(); i += 3) { myvoxset.insert(VoxelIJK(m_voxelIndicesIJK.data() + i)); rhsvoxset.insert(VoxelIJK(rhs.m_voxelIndicesIJK.data() + i)); } return (myvoxset == rhsvoxset); } bool CiftiParcelSurfaceElement::operator==(const CiftiParcelSurfaceElement& rhs) const { if (m_structure != rhs.m_structure) return false; if (m_numNodes != rhs.m_numNodes) return false; CaretAssert(m_numNodes == (int64_t)m_lookup.size()); CaretAssert(rhs.m_lookup.size() == m_lookup.size()); for (size_t i = 0; i < m_lookup.size(); ++i) {//check lookup instead of checking node lists in parcels if (m_lookup[i] != rhs.m_lookup[i]) return false; } return true; } CiftiMatrixElement::CiftiMatrixElement(const CiftiMatrixElement& rhs) { m_labelTable = rhs.m_labelTable; m_userMetaData = rhs.m_userMetaData; if (rhs.m_palette != NULL) m_palette.grabNew(new PaletteColorMapping(*(rhs.m_palette))); m_defaultPalette = rhs.m_defaultPalette; m_matrixIndicesMap = rhs.m_matrixIndicesMap; m_volume = rhs.m_volume; } CiftiMatrixElement& CiftiMatrixElement::operator=(const caret::CiftiMatrixElement& rhs) { if (this == &rhs) return *this; m_labelTable = rhs.m_labelTable; m_userMetaData = rhs.m_userMetaData; if (rhs.m_palette != NULL) m_palette.grabNew(new PaletteColorMapping(*(rhs.m_palette))); m_defaultPalette = rhs.m_defaultPalette; m_matrixIndicesMap = rhs.m_matrixIndicesMap; m_volume = rhs.m_volume; return *this; } CiftiNamedMapElement::CiftiNamedMapElement() {//just so that the destructors of GiftiLabelTable and PaletteColorMapping are resolved without including them into the .h m_defaultPalette = false; } CiftiNamedMapElement::~CiftiNamedMapElement() { } CiftiMatrixElement::CiftiMatrixElement() {//ditto m_defaultPalette = false; } CiftiMatrixElement::~CiftiMatrixElement() { } connectome-workbench-1.4.2/src/Cifti/CiftiXMLElements.h000066400000000000000000000231501360521144700227460ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #ifndef __CIFTI_XML_ELEMENTS #define __CIFTI_XML_ELEMENTS #include #include #include #include "AString.h" #include "CaretPointer.h" #include "CaretCompact3DLookup.h" #include "CiftiVersion.h" #include "nifti2.h" #include "StructureEnum.h" /* Cifti Defines */ namespace caret { class PaletteColorMapping; class GiftiLabelTable; /*! ModelType */ enum ModelType { CIFTI_MODEL_TYPE_INVALID, CIFTI_MODEL_TYPE_SURFACE=1,/*!< CIFTI_MODEL_TYPE_SURFACE*/ CIFTI_MODEL_TYPE_VOXELS=2/*!< CIFTI_MODEL_TYPE_VOXELS*/ }; /*! IndicesMapToDataType*/ enum IndicesMapToDataType { CIFTI_INDEX_TYPE_INVALID, CIFTI_INDEX_TYPE_BRAIN_MODELS=1,/*!< CIFTI_INDEX_TYPE_BRAIN_MODELS*/ CIFTI_INDEX_TYPE_FIBERS=2,/*!< CIFTI_INDEX_TYPE_FIBERS*/ CIFTI_INDEX_TYPE_PARCELS=3,/*!< CIFTI_INDEX_TYPE_PARCELS*/ CIFTI_INDEX_TYPE_TIME_POINTS=4,/*!< CIFTI_INDEX_TYPE_TIME_POINTS*/ CIFTI_INDEX_TYPE_SCALARS=5, CIFTI_INDEX_TYPE_LABELS=6 }; typedef int voxelIndexType; class CiftiMatrixIndicesMapElement; /// Cifti Brain Model XML Element class CiftiBrainModelElement { public: //CiftiBrainModelElement(); int64_t m_indexOffset; /*!< Index of first element in dimension of the matrix for this brain structure. The value is the number of elements, NOT the number of bytes. */ int64_t m_indexCount; /*!< Number of elements in this brain model. */ ModelType m_modelType; /*!< Type of model representing the brain structure. */ StructureEnum::Enum m_brainStructure; /*!< Identifies the brain structure. Valid values are contained in nifti2.h */ int64_t m_surfaceNumberOfNodes; /*!< This attribute contains the actual (or true) number of nodes in the surface that is associated with this BrainModel.*/ //children std::vector m_nodeIndices; /*!< Contains a list of nodes indices for a BrainModel with ModelType equal to CIFTI_MODEL_TYPE_SURFACE.*/ std::vector m_voxelIndicesIJK; /*!< Identifies the voxels that model a brain structure. */ std::vector m_nodeToIndexLookup;//used by CiftiXML to quickly lookup indexes by node number void setupLookup(CiftiMatrixIndicesMapElement& myMap);//convenience function to populate lookup bool operator==(const CiftiBrainModelElement& rhs) const; bool operator<(const CiftiBrainModelElement& rhs) const;//for sorting by starting index }; struct CiftiNamedMapElement { mutable AString m_mapName; mutable CaretPointer m_labelTable; mutable std::map m_mapMetaData;/*!< User Meta Data*/ mutable CaretPointer m_palette;//palette settings storage mutable bool m_defaultPalette;//secondary variable to enable resetting the palette to use defaults, which will make it not write the palette to file CiftiNamedMapElement(); CiftiNamedMapElement(const CiftiNamedMapElement& rhs);//to turn copy and assignment into a deep copy of the label table ~CiftiNamedMapElement(); CiftiNamedMapElement& operator=(const CiftiNamedMapElement& rhs); bool operator==(const CiftiNamedMapElement& rhs) const; bool operator!=(const CiftiNamedMapElement& rhs) const { return !(*this == rhs); } }; struct CiftiParcelNodesElement { StructureEnum::Enum m_structure; std::vector m_nodes; bool operator==(const CiftiParcelNodesElement& rhs) const; bool operator!=(const CiftiParcelNodesElement& rhs) const { return !(*this == rhs); } }; struct CiftiParcelElement { AString m_parcelName; std::vector m_nodeElements; std::vector m_voxelIndicesIJK; bool operator==(const CiftiParcelElement& rhs) const; bool operator!=(const CiftiParcelElement& rhs) const { return !(*this == rhs); } }; struct CiftiParcelSurfaceElement { StructureEnum::Enum m_structure; int64_t m_numNodes; std::vector m_lookup; bool operator==(const CiftiParcelSurfaceElement& rhs) const; bool operator!=(const CiftiParcelSurfaceElement& rhs) const { return !(*this == rhs); } }; /// Cifti Matrix Indices Map XML Element class CiftiMatrixIndicesMapElement { public: CiftiMatrixIndicesMapElement() { m_timeStep = -1.0; m_timeStart = -1.0; m_hasTimeStart = false; m_timeStepUnits = -1; m_numTimeSteps = -1; m_indicesMapToDataType = CIFTI_INDEX_TYPE_INVALID; } std::vector m_appliesToMatrixDimension; /*!< Lists the dimension(s) of the matrix to which this MatrixIndicesMap applies. */ IndicesMapToDataType m_indicesMapToDataType; /*!< Type of data to which the MatrixIndicesMap applies. */ double m_timeStep; /*!< Indicates amount of time between each timepoint. */ double m_timeStart; bool m_hasTimeStart; int m_timeStepUnits;/*!< Indicates units of TimeStep. */ int m_numTimeSteps;//used by CiftiXML to store the information that is critically lacking in the XML extension std::vector m_brainModels;/*!< A vector array of Brain Models */ CaretCompact3DLookup m_voxelToIndexLookup;//make one unified lookup rather than separate lookups per volume structure std::vector m_namedMaps; std::vector m_parcels; std::vector m_parcelSurfaces; void setupLookup(); bool operator==(const CiftiMatrixIndicesMapElement& rhs) const; }; /// Cifti Label XML Element class CiftiLabelElement { public: CiftiLabelElement() { m_red = m_green = m_blue = m_alpha = m_x = m_y = m_z = 0.0; m_key = 0; } unsigned long long m_key;/*!< Corresponding index, starting at zero, of a row and/or column of the connectivity matrix.*/ float m_red;/*!< Red color component for label. Value is floating point with range 0.0 to 1.0.*/ float m_green;/*!< Green color component for label. Value is floating point with range 0.0 to 1.0.*/ float m_blue;/*!< Blue color component for label. Value is floating point with range 0.0 to 1.0.*/ float m_alpha;/*!< Alpha color component for label. Value is floating point with range 0.0 to 1.0.*/ float m_x;/*!< X-coordinate of spatial location associated with the label. Value is floating point.*/ float m_y;/*!< Y-coordinate of spatial location associated with the label. Value is floating point.*/ float m_z;/*!< Z-coordinate of spatial location associated with the label. Value is floating point.*/ QString m_text;/*!< Text of the label.*/ }; /// Transformation Matrix Voxel Indices IJK to XYZ XML Element class TransformationMatrixVoxelIndicesIJKtoXYZElement { public: unsigned long m_dataSpace;/*!< Contains the name of the space of the voxels prior to application of the transformation matrix.*/ unsigned long m_transformedSpace;/*!< Contains the name of the space of the voxels after application of the transformation of voxel IJK indices to spatial XYZ coordinates. */ unsigned long m_unitsXYZ;/*!< Identifies the units of the spatial XYZ coordinates.*/ float m_transform[16];/*!< A 16 element matrix in row-major form which contains a matrix that for conversion of Voxel IJK Indices to spatial XYZ coordinates (+X=>right, +Y=>anterior, +Z=>posterior).*/ }; /// Cifti Volume XML Element class CiftiVolumeElement { public: std::vector m_transformationMatrixVoxelIndicesIJKtoXYZ;/*!< Vector array of 0 or more TransformationMatrixVoxelIndicesIJKtoXYZ*/ unsigned int m_volumeDimensions[3];/*!< Three integer values that indicate original dimensions of the volume from which the voxels were extracted.*/ }; /// Cifti Matrix XML Element class CiftiMatrixElement { public: CiftiMatrixElement(const CiftiMatrixElement& rhs); CiftiMatrixElement& operator=(const CiftiMatrixElement& rhs); CiftiMatrixElement(); ~CiftiMatrixElement(); std::vector m_labelTable;/*!< The Matrix's Label Table (optional)*///TODO: replace this with GiftiLabelTable (or remove? not being used for anything) mutable std::map m_userMetaData;/*!< User Meta Data*/ mutable CaretPointer m_palette;//palette settings storage mutable bool m_defaultPalette;//secondary variable to enable resetting the palette to use defaults, which will make it not write the palette to file std::vector m_matrixIndicesMap;/*!< Vector array of one or more Matrix Indices Map Elements*/ std::vector m_volume;/*!< Volume Element*/ }; /// Cifti Root XML Element class CiftiRootElement { public: CiftiRootElement() { m_numberOfMatrices = 0; } CiftiVersion m_version;/*!< Version String*/ unsigned long m_numberOfMatrices;/*!< Number of Matrices*/ std::vector m_matrices; /*!< Matrices, currently there is only matrix, but future versions may allow for more */ }; } #endif //__CIFTI_ELEMENTS connectome-workbench-1.4.2/src/Cifti/CiftiXMLOld.cxx000066400000000000000000002460111360521144700222660ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretAssert.h" #include "CiftiXMLOld.h" #include "DataFileContentInformation.h" #include "DataFileException.h" #include "FloatMatrix.h" #include "GiftiLabelTable.h" #include "Palette.h" #include "PaletteColorMapping.h" #include "CiftiXML.h" #include "CaretLogger.h" using namespace caret; using namespace std; /*void CiftiXMLOld::testNewXML(const QString& xmlString) { CiftiXML test1, test2; CiftiXMLOld compare1, compare2; AString stage; try { stage = "1_newRead1"; test1.readXML(AString(xmlString)); for (int i = 0; i < test1.getNumberOfDimensions(); ++i) { if (test1.getMappingType(i) == CiftiMappingType::SERIES) { CiftiSeriesMap myMap = test1.getSeriesMap(i); myMap.setLength(1);//there are asserts in series map that upon writing, it must know the length, so fake it for now test1.setMap(i, myMap); } } stage = "2_newWrite2"; AString newWritten2 = test1.writeXMLToString(CiftiVersion(1, 1)); stage = "3_newRead2"; test2.readXML(newWritten2); stage = "4_newCompare"; if (test1.getNumberOfDimensions() == test2.getNumberOfDimensions()) { for (int i = 0; i < test1.getNumberOfDimensions(); ++i) { if (*(test1.getMap(i)) != *(test2.getMap(i))) { CaretLogWarning("comparison in new cifti xml failed, dimension " + AString::number(i) + " not equal"); } } } else { CaretLogWarning("comparison in new cifti xml failed, different number of dimensions"); } stage = "5_newWrite1"; AString newWritten1 = test2.writeXMLToString(CiftiVersion(1, 0)); stage = "6_oldRead1"; compare1.readXML(newWritten1, false);//prevent recursively triggering test compare2.readXML(xmlString, false); if (!compare1.matchesForRows(compare2)) { CaretLogWarning("comparison in old xml failed for rows"); } if (!compare1.matchesForColumns(compare2)) { CaretLogWarning("comparison in old xml failed for columns"); } } catch (CaretException& e) { CaretLogWarning("error testing new xml: stage '" + stage + "', error: " + e.whatString()); } catch (std::exception& e) { CaretLogWarning("error testing new xml: stage '" + stage + "', error: " + e.what()); } catch (...) { CaretLogWarning("error testing new xml: stage '" + stage + "', unknown throw type"); } }//*/ /*void CiftiXMLOld::testNewXML(const QByteArray& xmlBytes) { CiftiXML test1, test2; CiftiXMLOld compare1, compare2; AString stage; try { stage = "1_newRead1"; test1.readXML(xmlBytes); for (int i = 0; i < test1.getNumberOfDimensions(); ++i) { if (test1.getMappingType(i) == CiftiMappingType::SERIES) { CiftiSeriesMap myMap = test1.getSeriesMap(i); myMap.setLength(1);//there are asserts in series map that upon writing, it must know the length, so fake it for now test1.setMap(i, myMap); } } stage = "2_newWrite2"; QByteArray newWritten2 = test1.writeXMLToQByteArray(CiftiVersion(1, 1)); stage = "3_newRead2"; test2.readXML(newWritten2); stage = "4_newCompare"; if (test1.getNumberOfDimensions() == test2.getNumberOfDimensions()) { for (int i = 0; i < test1.getNumberOfDimensions(); ++i) { if (*(test1.getMap(i)) != *(test2.getMap(i))) { CaretLogWarning("comparison in new cifti xml failed, dimension " + AString::number(i) + " not equal"); } } } else { CaretLogWarning("comparison in new cifti xml failed, different number of dimensions"); } stage = "5_newWrite1"; QByteArray newWritten1 = test2.writeXMLToQByteArray(CiftiVersion(1, 0)); stage = "6_oldRead1"; compare1.readXML(newWritten1, false);//prevent recursively triggering test compare2.readXML(xmlBytes, false); if (!compare1.matchesForRows(compare2)) { CaretLogWarning("comparison in old xml failed for rows"); } if (!compare1.matchesForColumns(compare2)) { CaretLogWarning("comparison in old xml failed for columns"); } } catch (CaretException& e) { CaretLogWarning("error testing new xml: stage '" + stage + "', error: " + e.whatString()); } catch (std::exception& e) { CaretLogWarning("error testing new xml: stage '" + stage + "', error: " + e.what()); } catch (...) { CaretLogWarning("error testing new xml: stage '" + stage + "', unknown throw type"); } }//*/ CiftiXMLOld::CiftiXMLOld() { m_dimToMapLookup.resize(2, -1);//assume matrix is 2D, for backwards compatibility with Row/Column functions } map* CiftiXMLOld::getFileMetaData() const { if (m_root.m_matrices.size() == 0) return NULL; return &(m_root.m_matrices[0].m_userMetaData); } int64_t CiftiXMLOld::getSurfaceIndex(const int64_t& node, const CiftiBrainModelElement* myElement) const { if (myElement == NULL || myElement->m_modelType != CIFTI_MODEL_TYPE_SURFACE) return -1; if (node < 0 || node > (int64_t)(myElement->m_surfaceNumberOfNodes)) return -1; CaretAssertVectorIndex(myElement->m_nodeToIndexLookup, node); return myElement->m_nodeToIndexLookup[node]; } int64_t CiftiXMLOld::getColumnIndexForNode(const int64_t& node, const StructureEnum::Enum& structure) const { return getSurfaceIndex(node, findSurfaceModel(m_dimToMapLookup[0], structure));//a column index is an index to get an entire column, so index ALONG a row } int64_t CiftiXMLOld::getRowIndexForNode(const int64_t& node, const StructureEnum::Enum& structure) const { return getSurfaceIndex(node, findSurfaceModel(m_dimToMapLookup[1], structure)); } int64_t CiftiXMLOld::getVolumeIndex(const int64_t* ijk, const int& myMapIndex) const { if (myMapIndex == -1 || m_root.m_matrices.size() == 0) return -1; CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]); if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_BRAIN_MODELS) { return -1; } if (m_root.m_matrices[0].m_volume.size() == 0) return -1; const CiftiVolumeElement& myVol = m_root.m_matrices[0].m_volume[0]; if (ijk[0] < 0 || ijk[0] >= (int64_t)myVol.m_volumeDimensions[0]) return -1;//some shortcuts to not search all the voxels on invalid coords if (ijk[1] < 0 || ijk[1] >= (int64_t)myVol.m_volumeDimensions[1]) return -1; if (ijk[2] < 0 || ijk[2] >= (int64_t)myVol.m_volumeDimensions[2]) return -1; const int64_t* test = myMap->m_voxelToIndexLookup.find(ijk); if (test == NULL) return -1; return *test; } int64_t CiftiXMLOld::getColumnIndexForVoxel(const int64_t* ijk) const { return getVolumeIndex(ijk, m_dimToMapLookup[0]); } int64_t CiftiXMLOld::getRowIndexForVoxel(const int64_t* ijk) const { return getVolumeIndex(ijk, m_dimToMapLookup[1]); } bool CiftiXMLOld::getSurfaceMap(const int& direction, vector& mappingOut, const StructureEnum::Enum& structure) const { if (direction < 0 || direction >= (int)m_dimToMapLookup.size()) { mappingOut.clear(); return false; } const CiftiBrainModelElement* myModel = findSurfaceModel(m_dimToMapLookup[direction], structure); if (myModel == NULL || myModel->m_modelType != CIFTI_MODEL_TYPE_SURFACE) { mappingOut.clear(); return false; } int64_t mappingSize = myModel->m_indexCount; mappingOut.resize(mappingSize); if (myModel->m_nodeIndices.size() == 0) { CaretAssert(myModel->m_indexCount == myModel->m_surfaceNumberOfNodes); for (int i = 0; i < mappingSize; ++i) { mappingOut[i].m_ciftiIndex = myModel->m_indexOffset + i; mappingOut[i].m_surfaceNode = i; } } else { for (int i = 0; i < mappingSize; ++i) { mappingOut[i].m_ciftiIndex = myModel->m_indexOffset + i; mappingOut[i].m_surfaceNode = myModel->m_nodeIndices[i]; } } return true; } bool CiftiXMLOld::getSurfaceMapForColumns(vector& mappingOut, const StructureEnum::Enum& structure) const { return getSurfaceMap(ALONG_COLUMN, mappingOut, structure); } bool CiftiXMLOld::getSurfaceMapForRows(vector& mappingOut, const StructureEnum::Enum& structure) const { return getSurfaceMap(ALONG_ROW, mappingOut, structure); } bool CiftiXMLOld::getVolumeMap(const int& direction, vector& mappingOut) const { mappingOut.clear(); if (direction < 0 || direction >= (int)m_dimToMapLookup.size()) { return false; } int myMapIndex = m_dimToMapLookup[direction]; if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]); if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_BRAIN_MODELS) { return false; } int64_t myIndex = 0; bool first = true; for (int64_t i = 0; i < (int64_t)myMap->m_brainModels.size(); ++i) { if (myMap->m_brainModels[i].m_modelType == CIFTI_MODEL_TYPE_VOXELS) { const vector& myVoxels = myMap->m_brainModels[i].m_voxelIndicesIJK; int64_t voxelArraySize = (int64_t)myVoxels.size(); int64_t modelOffset = myMap->m_brainModels[i].m_indexOffset; int64_t j1 = 0; if (first) { mappingOut.reserve(voxelArraySize / 3);//skip the tiny vector reallocs first = false; } for (int64_t j = 0; j < voxelArraySize; j += 3) { mappingOut.push_back(CiftiVolumeMap());//default constructor should be NOOP and get removed by compiler mappingOut[myIndex].m_ciftiIndex = modelOffset + j1; mappingOut[myIndex].m_ijk[0] = myVoxels[j]; mappingOut[myIndex].m_ijk[1] = myVoxels[j + 1]; mappingOut[myIndex].m_ijk[2] = myVoxels[j + 2]; ++j1; ++myIndex; } } } return true; } bool CiftiXMLOld::getVolumeMapForColumns(vector& mappingOut) const { return getVolumeMap(ALONG_COLUMN, mappingOut); } bool CiftiXMLOld::getVolumeMapForRows(vector& mappingOut) const { return getVolumeMap(ALONG_ROW, mappingOut); } void CiftiXMLOld::getVoxelInfoInDataFileContentInformation(const int& direction, DataFileContentInformation& dataFileInformation) const { if (direction < 0 || direction >= (int)m_dimToMapLookup.size()) { return; } int myMapIndex = m_dimToMapLookup[direction]; if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { return; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]); if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_BRAIN_MODELS) { return; } VolumeSpace volumeSpace; getVolumeSpace(volumeSpace); const int64_t* dims = volumeSpace.getDims(); dataFileInformation.addNameAndValue("Dimensions", AString::fromNumbers(dims, 3, ",")); VolumeSpace::OrientTypes orientation[3]; float spacing[3]; float origin[3]; volumeSpace.getOrientAndSpacingForPlumb(orientation, spacing, origin); dataFileInformation.addNameAndValue("Spacing", AString::fromNumbers(spacing, 3, ",")); dataFileInformation.addNameAndValue("Origin", AString::fromNumbers(origin, 3, ",")); const std::vector >& sform = volumeSpace.getSform(); for (uint32_t i = 0; i < sform.size(); i++) { dataFileInformation.addNameAndValue(("sform row " + AString::number(i)), AString::fromNumbers(sform[i], ",")); } int64_t myIndex = 0; for (int64_t i = 0; i < (int64_t)myMap->m_brainModels.size(); ++i) { if (myMap->m_brainModels[i].m_modelType == CIFTI_MODEL_TYPE_VOXELS) { const vector& myVoxels = myMap->m_brainModels[i].m_voxelIndicesIJK; int64_t voxelArraySize = (int64_t)myVoxels.size(); int64_t modelOffset = myMap->m_brainModels[i].m_indexOffset; int64_t j1 = 0; const AString structureName = StructureEnum::toGuiName(myMap->m_brainModels[i].m_brainStructure); for (int64_t j = 0; j < voxelArraySize; j += 3) { const int64_t ijk[3] = { myVoxels[j], myVoxels[j + 1], myVoxels[j + 2] }; float xyz[3]; volumeSpace.indexToSpace(ijk, xyz); const AString msg = ("ijk=(" + AString::fromNumbers(ijk, 3, ",") + "), xyz=(" + AString::fromNumbers(xyz, 3, ", ") + "), row=" + AString::number(modelOffset + j1) + " "); dataFileInformation.addNameAndValue(structureName, msg); ++j1; ++myIndex; } } } } bool CiftiXMLOld::getVolumeStructureMap(const int& direction, vector& mappingOut, const StructureEnum::Enum& structure) const { mappingOut.clear(); CaretAssertVectorIndex(m_dimToMapLookup, direction); int myMapIndex = m_dimToMapLookup[direction]; const CiftiBrainModelElement* myModel = findVolumeModel(myMapIndex, structure); if (myModel == NULL) { return false; } int64_t size = (int64_t)myModel->m_voxelIndicesIJK.size(); CaretAssert(size % 3 == 0); mappingOut.resize(size / 3); int64_t index = 0; for (int64_t i = 0; i < size; i += 3) { mappingOut[index].m_ciftiIndex = myModel->m_indexOffset + index; mappingOut[index].m_ijk[0] = myModel->m_voxelIndicesIJK[i]; mappingOut[index].m_ijk[1] = myModel->m_voxelIndicesIJK[i + 1]; mappingOut[index].m_ijk[2] = myModel->m_voxelIndicesIJK[i + 2]; ++index; } return true; } bool CiftiXMLOld::getVolumeStructureMapForColumns(vector& mappingOut, const StructureEnum::Enum& structure) const { return getVolumeStructureMap(ALONG_COLUMN, mappingOut, structure); } bool CiftiXMLOld::getVolumeStructureMapForRows(vector& mappingOut, const StructureEnum::Enum& structure) const { return getVolumeStructureMap(ALONG_ROW, mappingOut, structure); } bool CiftiXMLOld::getVolumeModelMappings(vector& mappingsOut, const int& myMapIndex) const { mappingsOut.clear(); if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]); if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_BRAIN_MODELS) { return false; } int numModels = (int)myMap->m_brainModels.size(); mappingsOut.reserve(numModels); for (int i = 0; i < numModels; ++i) { if (myMap->m_brainModels[i].m_modelType == CIFTI_MODEL_TYPE_VOXELS) { mappingsOut.push_back(CiftiVolumeStructureMap()); int whichMap = (int)mappingsOut.size() - 1; mappingsOut[whichMap].m_structure = myMap->m_brainModels[i].m_brainStructure; int numIndices = (int)myMap->m_brainModels[i].m_indexCount; mappingsOut[whichMap].m_map.resize(numIndices); for (int index = 0; index < numIndices; ++index) { mappingsOut[whichMap].m_map[index].m_ciftiIndex = myMap->m_brainModels[i].m_indexOffset + index; int64_t i3 = index * 3; mappingsOut[whichMap].m_map[index].m_ijk[0] = myMap->m_brainModels[i].m_voxelIndicesIJK[i3]; mappingsOut[whichMap].m_map[index].m_ijk[1] = myMap->m_brainModels[i].m_voxelIndicesIJK[i3 + 1]; mappingsOut[whichMap].m_map[index].m_ijk[2] = myMap->m_brainModels[i].m_voxelIndicesIJK[i3 + 2]; } } } return true; } bool CiftiXMLOld::getVolumeModelMapsForColumns(vector& mappingsOut) const { return getVolumeModelMappings(mappingsOut, m_dimToMapLookup[1]); } bool CiftiXMLOld::getVolumeModelMapsForRows(vector& mappingsOut) const { return getVolumeModelMappings(mappingsOut, m_dimToMapLookup[0]); } bool CiftiXMLOld::getStructureLists(const int& direction, vector& surfaceList, vector& volumeList) const { surfaceList.clear(); volumeList.clear(); if (direction < 0 || direction >= (int)m_dimToMapLookup.size()) { return false; } int myMapIndex = m_dimToMapLookup[direction]; if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]); if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_BRAIN_MODELS) { return false; } int numModels = (int)myMap->m_brainModels.size(); for (int i = 0; i < numModels; ++i) { switch (myMap->m_brainModels[i].m_modelType) { case CIFTI_MODEL_TYPE_SURFACE: surfaceList.push_back(myMap->m_brainModels[i].m_brainStructure); break; case CIFTI_MODEL_TYPE_VOXELS: volumeList.push_back(myMap->m_brainModels[i].m_brainStructure); break; default: break; } } return true; } bool CiftiXMLOld::getStructureListsForColumns(vector& surfaceList, vector& volumeList) const { return getStructureLists(ALONG_COLUMN, surfaceList, volumeList); } bool CiftiXMLOld::getStructureListsForRows(vector& surfaceList, vector& volumeList) const { return getStructureLists(ALONG_ROW, surfaceList, volumeList); } int CiftiXMLOld::getNumberOfBrainModels(const int& direction) const { CaretAssertVectorIndex(m_dimToMapLookup, direction); int myMapIndex = m_dimToMapLookup[direction]; if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { return -1; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]); if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_BRAIN_MODELS) { return -1; } return (int)myMap->m_brainModels.size();//reuse of type and structure combinations not allowed, so this is limited to number of structure enum values times number of model types (2) } CiftiBrainModelInfo CiftiXMLOld::getBrainModelInfo(const int& direction, const int& whichModel) const { CiftiBrainModelInfo ret; CaretAssertVectorIndex(m_dimToMapLookup, direction); int myMapIndex = m_dimToMapLookup[direction]; if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { return ret; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]); if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_BRAIN_MODELS) { return ret; } CaretAssertVectorIndex(myMap->m_brainModels, whichModel); ret.m_type = myMap->m_brainModels[whichModel].m_modelType; ret.m_structure = myMap->m_brainModels[whichModel].m_brainStructure; return ret; } void CiftiXMLOld::rootChanged() { m_dimToMapLookup.clear();//first, invalidate everything m_dimToMapLookup.resize(2, -1);//assume matrix is 2D, for backwards compatibility with Row/Column functions if (m_root.m_matrices.size() == 0) { return;//it shouldn't crash if it has no matrix, so return instead of throw } CiftiMatrixElement& myMatrix = m_root.m_matrices[0];//assume only one matrix int numMaps = (int)myMatrix.m_matrixIndicesMap.size(); for (int i = 0; i < numMaps; ++i) { CiftiMatrixIndicesMapElement& myMap = myMatrix.m_matrixIndicesMap[i]; int numDimensions = (int)myMap.m_appliesToMatrixDimension.size(); for (int j = 0; j < numDimensions; ++j) { if (myMap.m_appliesToMatrixDimension[j] < 0) throw DataFileException("negative value in m_appliesToMatrixDimension"); while (m_dimToMapLookup.size() <= (size_t)myMap.m_appliesToMatrixDimension[j]) { m_dimToMapLookup.push_back(-1); } m_dimToMapLookup[myMap.m_appliesToMatrixDimension[j]] = i; myMap.setupLookup(); } } } int64_t CiftiXMLOld::getColumnSurfaceNumberOfNodes(const StructureEnum::Enum& structure) const { return getSurfaceNumberOfNodes(ALONG_COLUMN, structure); } int64_t CiftiXMLOld::getRowSurfaceNumberOfNodes(const StructureEnum::Enum& structure) const { return getSurfaceNumberOfNodes(ALONG_ROW, structure); } int64_t CiftiXMLOld::getSurfaceNumberOfNodes(const int& direction, const StructureEnum::Enum& structure) const { if (direction < 0 || direction >= (int)m_dimToMapLookup.size()) return -1; if (m_root.m_matrices.size() == 0) return -1; CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, m_dimToMapLookup[direction]); const CiftiMatrixIndicesMapElement& myMap = m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[direction]]; IndicesMapToDataType myType = myMap.m_indicesMapToDataType; if (myType == CIFTI_INDEX_TYPE_BRAIN_MODELS) { const CiftiBrainModelElement* myModel = findSurfaceModel(m_dimToMapLookup[direction], structure); if (myModel == NULL) return -1; return myModel->m_surfaceNumberOfNodes; } else if (myType == CIFTI_INDEX_TYPE_PARCELS) { int numSurfs = (int)myMap.m_parcelSurfaces.size(); for (int i = 0; i < numSurfs; ++i) { if (myMap.m_parcelSurfaces[i].m_structure == structure) { return myMap.m_parcelSurfaces[i].m_numNodes; } } } return -1; } int64_t CiftiXMLOld::getVolumeIndex(const float* xyz, const int& myMapIndex) const { if (m_root.m_matrices.size() == 0) { return -1; } if (m_root.m_matrices[0].m_volume.size() == 0) { return -1; } const CiftiVolumeElement& myVol = m_root.m_matrices[0].m_volume[0]; if (myVol.m_transformationMatrixVoxelIndicesIJKtoXYZ.size() == 0) { return -1; } const TransformationMatrixVoxelIndicesIJKtoXYZElement& myTrans = myVol.m_transformationMatrixVoxelIndicesIJKtoXYZ[0];//oh the humanity FloatMatrix myMatrix = FloatMatrix::zeros(4, 4); for (int i = 0; i < 3; ++i)//NEVER trust the fourth row of input, NEVER! { for (int j = 0; j < 4; ++j) { myMatrix[i][j] = myTrans.m_transform[i * 4 + j]; } } switch (myTrans.m_unitsXYZ) { case NIFTI_UNITS_MM: break; case NIFTI_UNITS_METER: myMatrix *= 1000.0f; break; case NIFTI_UNITS_MICRON: myMatrix *= 0.001f; break; default: return -1; }; myMatrix[3][3] = 1.0f;//i COULD do this by making a fake volume file, but that seems kinda hacky FloatMatrix toIndexSpace = myMatrix.inverse();//invert to convert the other direction FloatMatrix myCoord = FloatMatrix::zeros(4, 1);//column vector myCoord[0][0] = xyz[0]; myCoord[1][0] = xyz[1]; myCoord[2][0] = xyz[2]; myCoord[3][0] = 1.0f; FloatMatrix myIndices = toIndexSpace * myCoord;//matrix multiply int64_t ijk[3]; ijk[0] = (int64_t)floor(myIndices[0][0] + 0.5f); ijk[1] = (int64_t)floor(myIndices[1][0] + 0.5f); ijk[2] = (int64_t)floor(myIndices[2][0] + 0.5f); return getVolumeIndex(ijk, myMapIndex); } int64_t CiftiXMLOld::getColumnIndexForVoxelCoordinate(const float* xyz) const { return getVolumeIndex(xyz, m_dimToMapLookup[0]); } int64_t CiftiXMLOld::getRowIndexForVoxelCoordinate(const float* xyz) const { return getVolumeIndex(xyz, m_dimToMapLookup[1]); } int64_t CiftiXMLOld::getTimestepIndex(const float& seconds, const int& myMapIndex) const { if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]); float myStep; if (!getTimestep(myStep, myMapIndex)) { return -1; } float rawIndex = seconds / myStep; int64_t ret = (int64_t)floor(rawIndex + 0.5f); if (ret < 0 || ret >= myMap->m_numTimeSteps) return -1;//NOTE: should this have a different error value if it is after the end of the timeseries return ret; } int64_t CiftiXMLOld::getColumnIndexForTimepoint(const float& seconds) const { return getTimestepIndex(seconds, m_dimToMapLookup[0]); } int64_t CiftiXMLOld::getRowIndexForTimepoint(const float& seconds) const { return getTimestepIndex(seconds, m_dimToMapLookup[1]); } bool CiftiXMLOld::getTimestep(float& seconds, const int& myMapIndex) const { if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]); if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_TIME_POINTS) { return false; } switch (myMap->m_timeStepUnits) { case NIFTI_UNITS_SEC: seconds = myMap->m_timeStep; break; case NIFTI_UNITS_MSEC: seconds = myMap->m_timeStep * 0.001f; break; case NIFTI_UNITS_USEC: seconds = myMap->m_timeStep * 0.000001f; break; default: return false; }; return true; } bool CiftiXMLOld::getColumnTimestep(float& seconds) const { return getTimestep(seconds, m_dimToMapLookup[1]); } bool CiftiXMLOld::getRowTimestep(float& seconds) const { return getTimestep(seconds, m_dimToMapLookup[0]); } bool CiftiXMLOld::getTimestart(float& seconds, const int& myMapIndex) const { if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]); if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_TIME_POINTS || myMap->m_hasTimeStart == false) { return false; } switch (myMap->m_timeStepUnits) { case NIFTI_UNITS_SEC: seconds = myMap->m_timeStart; break; case NIFTI_UNITS_MSEC: seconds = myMap->m_timeStart * 0.001f; break; case NIFTI_UNITS_USEC: seconds = myMap->m_timeStart * 0.000001f; break; default: return false; }; return true; } bool CiftiXMLOld::getColumnTimestart(float& seconds) const { return getTimestart(seconds, m_dimToMapLookup[1]); } bool CiftiXMLOld::getRowTimestart(float& seconds) const { return getTimestart(seconds, m_dimToMapLookup[0]); } bool CiftiXMLOld::getColumnNumberOfTimepoints(int& numTimepoints) const { if (m_dimToMapLookup[1] == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, m_dimToMapLookup[1]); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[1]]); if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_TIME_POINTS) { return false; } numTimepoints = myMap->m_numTimeSteps; return true; } bool CiftiXMLOld::getRowNumberOfTimepoints(int& numTimepoints) const { if (m_dimToMapLookup[0] == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, m_dimToMapLookup[0]); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[0]]); if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_TIME_POINTS) { return false; } numTimepoints = myMap->m_numTimeSteps; return true; } bool CiftiXMLOld::getParcelsForColumns(vector& parcelsOut) const { return getParcels(ALONG_COLUMN, parcelsOut); } bool CiftiXMLOld::getParcelsForRows(vector& parcelsOut) const { return getParcels(ALONG_ROW, parcelsOut); } bool CiftiXMLOld::getParcels(const int& direction, vector< CiftiParcelElement >& parcelsOut) const { CaretAssertVectorIndex(m_dimToMapLookup, direction); if (m_dimToMapLookup[direction] == -1 || m_root.m_matrices.size() == 0) { parcelsOut.clear(); return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, m_dimToMapLookup[direction]); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[direction]]); if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_PARCELS) { parcelsOut.clear(); return false; } parcelsOut = myMap->m_parcels; return true; } bool CiftiXMLOld::getParcelSurfaceStructures(const int& direction, vector& structuresOut) const { structuresOut.clear(); if (direction < 0 || direction >= (int)m_dimToMapLookup.size()) return false; if (m_dimToMapLookup[direction] == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, m_dimToMapLookup[direction]); const CiftiMatrixIndicesMapElement& myMap = m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[direction]]; if (myMap.m_indicesMapToDataType != CIFTI_INDEX_TYPE_PARCELS) return false; for (int i = 0; i < (int)myMap.m_parcelSurfaces.size(); ++i) { structuresOut.push_back(myMap.m_parcelSurfaces[i].m_structure); } return true; } int64_t CiftiXMLOld::getParcelForNode(const int64_t& node, const StructureEnum::Enum& structure, const int& myMapIndex) const { if (node < 0 || myMapIndex == -1 || m_root.m_matrices.size() == 0) { return -1; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); const CiftiMatrixIndicesMapElement& myMap = m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]; if (myMap.m_indicesMapToDataType != CIFTI_INDEX_TYPE_PARCELS) { return -1; } for (int i = 0; i < (int)myMap.m_parcelSurfaces.size(); ++i) { if (myMap.m_parcelSurfaces[i].m_structure == structure) { if (node < myMap.m_parcelSurfaces[i].m_numNodes) { return myMap.m_parcelSurfaces[i].m_lookup[node]; } else { return -1; } } } return -1; } int64_t CiftiXMLOld::getColumnParcelForNode(const int64_t& node, const StructureEnum::Enum& structure) const { return getParcelForNode(node, structure, m_dimToMapLookup[1]); } int64_t CiftiXMLOld::getRowParcelForNode(const int64_t& node, const caret::StructureEnum::Enum& structure) const { return getParcelForNode(node, structure, m_dimToMapLookup[0]); } int64_t CiftiXMLOld::getParcelForVoxel(const int64_t* ijk, const int& myMapIndex) const { if (ijk[0] < 0 || ijk[1] < 0 || ijk[2] < 0 || myMapIndex == -1 || m_root.m_matrices.size() == 0) { return -1; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); const CiftiMatrixIndicesMapElement& myMap = m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]; if (myMap.m_indicesMapToDataType != CIFTI_INDEX_TYPE_PARCELS) { return -1; } const int64_t* test = myMap.m_voxelToIndexLookup.find(ijk); if (test == NULL) return -1; return *test; } int64_t CiftiXMLOld::getColumnParcelForVoxel(const int64_t* ijk) const { return getParcelForVoxel(ijk, m_dimToMapLookup[1]); } int64_t CiftiXMLOld::getRowParcelForVoxel(const int64_t* ijk) const { return getParcelForVoxel(ijk, m_dimToMapLookup[0]); } bool CiftiXMLOld::setColumnNumberOfTimepoints(const int& numTimepoints) { if (m_dimToMapLookup[1] == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, m_dimToMapLookup[1]); CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[1]]); if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_TIME_POINTS) { return false; } myMap->m_numTimeSteps = numTimepoints; return true; } bool CiftiXMLOld::setRowNumberOfTimepoints(const int& numTimepoints) { if (m_dimToMapLookup[0] == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, m_dimToMapLookup[0]); CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[0]]); if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_TIME_POINTS) { return false; } myMap->m_numTimeSteps = numTimepoints; return true; } bool CiftiXMLOld::setTimestep(const float& seconds, const int& myMapIndex) { if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]); if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_TIME_POINTS) { return false; } float temp = 1.0f; getTimestart(temp, myMapIndex);//convert to seconds myMap->m_timeStart = temp; myMap->m_timeStepUnits = NIFTI_UNITS_SEC; myMap->m_timeStep = seconds; return true; } bool CiftiXMLOld::setColumnTimestep(const float& seconds) { return setTimestep(seconds, m_dimToMapLookup[1]); } bool CiftiXMLOld::setRowTimestep(const float& seconds) { return setTimestep(seconds, m_dimToMapLookup[0]); } bool CiftiXMLOld::setTimestart(const float& seconds, const int& myMapIndex) { if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]); if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_TIME_POINTS) { return false; } float temp = 1.0f; getTimestep(temp, myMapIndex);//convert timestep to seconds myMap->m_timeStep = temp; myMap->m_timeStepUnits = NIFTI_UNITS_SEC; myMap->m_timeStart = seconds; myMap->m_hasTimeStart = true; return true; } bool CiftiXMLOld::setColumnTimestart(const float& seconds) { return setTimestart(seconds, m_dimToMapLookup[1]); } bool CiftiXMLOld::setRowTimestart(const float& seconds) { return setTimestart(seconds, m_dimToMapLookup[0]); } bool CiftiXMLOld::getVolumeAttributesForPlumb(VolumeSpace::OrientTypes orientOut[3], int64_t dimensionsOut[3], float originOut[3], float spacingOut[3]) const { VolumeSpace mySpace; if (!getVolumeSpace(mySpace)) return false; const int64_t* myDims = mySpace.getDims(); dimensionsOut[0] = myDims[0]; dimensionsOut[1] = myDims[1]; dimensionsOut[2] = myDims[2]; mySpace.getOrientAndSpacingForPlumb(orientOut, spacingOut, originOut); return true; } bool CiftiXMLOld::getVolumeDimsAndSForm(int64_t dimsOut[3], vector >& sformOut) const { if (m_root.m_matrices.size() == 0) { return false; } if (m_root.m_matrices[0].m_volume.size() == 0) { return false; } const CiftiVolumeElement& myVol = m_root.m_matrices[0].m_volume[0]; if (myVol.m_transformationMatrixVoxelIndicesIJKtoXYZ.size() == 0) { return false; } const TransformationMatrixVoxelIndicesIJKtoXYZElement& myTrans = myVol.m_transformationMatrixVoxelIndicesIJKtoXYZ[0];//oh the humanity FloatMatrix myMatrix = FloatMatrix::zeros(3, 4);//no fourth row for (int i = 0; i < 3; ++i) { for (int j = 0; j < 4; ++j) { myMatrix[i][j] = myTrans.m_transform[i * 4 + j]; } } switch (myTrans.m_unitsXYZ) { case NIFTI_UNITS_MM: break; case NIFTI_UNITS_METER: myMatrix *= 1000.0f; break; case NIFTI_UNITS_MICRON: myMatrix *= 0.001f; break; default: return false; }; sformOut = myMatrix.getMatrix(); dimsOut[0] = myVol.m_volumeDimensions[0]; dimsOut[1] = myVol.m_volumeDimensions[1]; dimsOut[2] = myVol.m_volumeDimensions[2]; return true; } void CiftiXMLOld::setVolumeDimsAndSForm(const int64_t dims[3], const vector >& sform) { CaretAssert(sform.size() == 3 || sform.size() == 4); if (hasVolumeData(ALONG_COLUMN) || hasVolumeData(ALONG_ROW)) { VolumeSpace tempSpace; if (getVolumeSpace(tempSpace))//if it fails to get a volume space when it has volume data...allow it to set it, I guess { if (!tempSpace.matches(VolumeSpace(dims, sform))) { throw DataFileException("cannot change the volume space of cifti xml that already has volume mapping(s)"); } return; } } if (m_root.m_matrices.size() == 0) { m_root.m_matrices.resize(1); } if (m_root.m_matrices[0].m_volume.size() == 0) { m_root.m_matrices[0].m_volume.resize(1); } CiftiVolumeElement& myVol = m_root.m_matrices[0].m_volume[0]; if (myVol.m_transformationMatrixVoxelIndicesIJKtoXYZ.size() == 0) { myVol.m_transformationMatrixVoxelIndicesIJKtoXYZ.resize(1); } TransformationMatrixVoxelIndicesIJKtoXYZElement& myTrans = myVol.m_transformationMatrixVoxelIndicesIJKtoXYZ[0];//oh the humanity for (int i = 0; i < 3; ++i) { CaretAssert(sform[i].size() == 4); for (int j = 0; j < 4; ++j) { myTrans.m_transform[i * 4 + j] = sform[i][j]; } } myTrans.m_transform[12] = 0.0f;//force last row to be set to 0 0 0 1 internally for sanity, even though we don't use it myTrans.m_transform[13] = 0.0f; myTrans.m_transform[14] = 0.0f; myTrans.m_transform[15] = 1.0f; myTrans.m_unitsXYZ = NIFTI_UNITS_MM; myVol.m_volumeDimensions[0] = dims[0]; myVol.m_volumeDimensions[1] = dims[1]; myVol.m_volumeDimensions[2] = dims[2]; } bool CiftiXMLOld::getVolumeSpace(VolumeSpace& volSpaceOut) const { if (m_root.m_matrices.size() == 0) { return false; } if (m_root.m_matrices[0].m_volume.size() == 0) { return false; } const CiftiVolumeElement& myVol = m_root.m_matrices[0].m_volume[0]; if (myVol.m_transformationMatrixVoxelIndicesIJKtoXYZ.size() == 0) { return false; } const TransformationMatrixVoxelIndicesIJKtoXYZElement& myTrans = myVol.m_transformationMatrixVoxelIndicesIJKtoXYZ[0];//oh the humanity FloatMatrix myMatrix = FloatMatrix::zeros(3, 4);//no fourth row for (int i = 0; i < 3; ++i) { for (int j = 0; j < 4; ++j) { myMatrix[i][j] = myTrans.m_transform[i * 4 + j]; } } switch (myTrans.m_unitsXYZ) { case NIFTI_UNITS_MM: break; case NIFTI_UNITS_METER: myMatrix *= 1000.0f; break; case NIFTI_UNITS_MICRON: myMatrix *= 0.001f; break; default: return false; }; int64_t dims[3] = { myVol.m_volumeDimensions[0], myVol.m_volumeDimensions[1], myVol.m_volumeDimensions[2] }; volSpaceOut.setSpace(dims, myMatrix.getMatrix()); return true; } AString CiftiXMLOld::getMapName(const int& direction, const int64_t& index) const { if (m_dimToMapLookup[direction] == -1 || m_root.m_matrices.size() == 0) { return ""; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, m_dimToMapLookup[direction]); const CiftiMatrixIndicesMapElement& myMap = m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[direction]]; if (myMap.m_indicesMapToDataType != CIFTI_INDEX_TYPE_SCALARS && myMap.m_indicesMapToDataType != CIFTI_INDEX_TYPE_LABELS) { return ""; } CaretAssertVectorIndex(myMap.m_namedMaps, index); return myMap.m_namedMaps[index].m_mapName; } int64_t CiftiXMLOld::getMapIndexFromNameOrNumber(const int& direction, const AString& numberOrName) const { if (m_dimToMapLookup[direction] == -1 || m_root.m_matrices.size() == 0) { return -1; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, m_dimToMapLookup[direction]); const CiftiMatrixIndicesMapElement& myMap = m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[direction]]; bool ok = false; int32_t ret = numberOrName.toInt(&ok) - 1;//compensate for 1-indexing that command line parsing uses if (ok)//always work for integers, even when it is something like brain models or parcels, code that cares can check the mapping type { if (ret < 0 || ret >= getDimensionLength(direction)) { ret = -1; } } else {//DO NOT search by name if the string was parsed as an integer correctly, or some idiot who names their maps as integers will get confused //when getting map "12" out of a file after the file expands to more than 12 elements suddenly does something different if (myMap.m_indicesMapToDataType != CIFTI_INDEX_TYPE_SCALARS && myMap.m_indicesMapToDataType != CIFTI_INDEX_TYPE_LABELS) { return -1;//if we don't have map names to look at, return early rather than repeatedly trying to match against "" (which would be incorrect anyway) } int64_t numMaps = getDimensionLength(direction); ret = -1; for (int64_t i = 0; i < numMaps; ++i) { if (getMapName(direction, i) == numberOrName) { ret = i; break; } } } return ret; } AString CiftiXMLOld::getMapNameForColumnIndex(const int64_t& index) const { return getMapName(ALONG_COLUMN, index); } AString CiftiXMLOld::getMapNameForRowIndex(const int64_t& index) const { return getMapName(ALONG_ROW, index); } bool CiftiXMLOld::setMapNameForIndex(const int& direction, const int64_t& index, const AString& name) const { if (direction < 0 || direction >= (int)m_dimToMapLookup.size()) { return false; } int myMapIndex = m_dimToMapLookup[direction]; if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { return false; } const CiftiMatrixIndicesMapElement& myMap = m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]; if (myMap.m_indicesMapToDataType != CIFTI_INDEX_TYPE_SCALARS && myMap.m_indicesMapToDataType != CIFTI_INDEX_TYPE_LABELS) { return false; } CaretAssertVectorIndex(myMap.m_namedMaps, index); myMap.m_namedMaps[index].m_mapName = name; return true; } bool CiftiXMLOld::setMapNameForColumnIndex(const int64_t& index, const AString& name) const { return setMapNameForIndex(ALONG_COLUMN, index, name); } bool CiftiXMLOld::setMapNameForRowIndex(const int64_t& index, const AString& name) const { return setMapNameForIndex(ALONG_ROW, index, name); } GiftiLabelTable* CiftiXMLOld::getMapLabelTable(const int& direction, const int64_t& index) const { if (m_dimToMapLookup[direction] == -1 || m_root.m_matrices.size() == 0) { return NULL; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, m_dimToMapLookup[direction]); const CiftiMatrixIndicesMapElement& myMap = m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[direction]]; if (myMap.m_indicesMapToDataType != CIFTI_INDEX_TYPE_LABELS) { return NULL; } CaretAssertVectorIndex(myMap.m_namedMaps, index); return myMap.m_namedMaps[index].m_labelTable; } GiftiLabelTable* CiftiXMLOld::getLabelTableForColumnIndex(const int64_t& index) const { return getMapLabelTable(ALONG_COLUMN, index); } GiftiLabelTable* CiftiXMLOld::getLabelTableForRowIndex(const int64_t& index) const { return getMapLabelTable(ALONG_ROW, index); } bool CiftiXMLOld::setLabelTable(const int64_t& index, const GiftiLabelTable& labelTable, const int& myMapIndex) { if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); CiftiMatrixIndicesMapElement& myMap = m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]; if (myMap.m_indicesMapToDataType != CIFTI_INDEX_TYPE_LABELS) { return false; } CaretAssertVectorIndex(myMap.m_namedMaps, index); if (myMap.m_namedMaps[index].m_labelTable == NULL)//should never happen, but just in case { myMap.m_namedMaps[index].m_labelTable.grabNew(new GiftiLabelTable(labelTable)); } else { *(myMap.m_namedMaps[index].m_labelTable) = labelTable; } return true; } bool CiftiXMLOld::setLabelTableForColumnIndex(const int64_t& index, const GiftiLabelTable& labelTable) { return setLabelTable(index, labelTable, m_dimToMapLookup[1]); } bool CiftiXMLOld::setLabelTableForRowIndex(const int64_t& index, const GiftiLabelTable& labelTable) { return setLabelTable(index, labelTable, m_dimToMapLookup[0]); } bool CiftiXMLOld::hasVolumeData(const int& direction) const { if (direction < 0 || direction >= (int)m_dimToMapLookup.size()) { return false; } int myMapIndex = m_dimToMapLookup[direction]; if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]); if (m_root.m_matrices[0].m_volume.size() == 0) { return false; } if (myMap == NULL) { return false; } if (myMap->m_indicesMapToDataType == CIFTI_INDEX_TYPE_BRAIN_MODELS) { const CiftiVolumeElement& myVol = m_root.m_matrices[0].m_volume[0]; if (myVol.m_transformationMatrixVoxelIndicesIJKtoXYZ.size() == 0) { return false; } for (int64_t i = 0; i < (int64_t)myMap->m_brainModels.size(); ++i) { if (myMap->m_brainModels[i].m_modelType == CIFTI_MODEL_TYPE_VOXELS) { return true; } } } else if (myMap->m_indicesMapToDataType == CIFTI_INDEX_TYPE_PARCELS) { for (int64_t i = 0; i < (int64_t)myMap->m_parcels.size(); ++i) { if (myMap->m_parcels[i].m_voxelIndicesIJK.size() != 0) { return true; } }//TSC: I now think it should say true for parcels as long as there are voxels, useful for checking whether the volume XML element is needed } return false; } bool CiftiXMLOld::hasRowVolumeData() const { return hasVolumeData(ALONG_ROW); } bool CiftiXMLOld::hasColumnVolumeData() const { return hasVolumeData(ALONG_COLUMN); } bool CiftiXMLOld::hasColumnSurfaceData(const StructureEnum::Enum& structure) const { return hasSurfaceData(ALONG_COLUMN, structure); } bool CiftiXMLOld::hasRowSurfaceData(const StructureEnum::Enum& structure) const { return hasSurfaceData(ALONG_ROW, structure); } bool CiftiXMLOld::hasSurfaceData(const int& direction, const StructureEnum::Enum& structure) const { if (direction < 0 || direction >= (int)m_dimToMapLookup.size()) { return false; } int myMapIndex = m_dimToMapLookup[direction]; if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]); if (myMap->m_indicesMapToDataType == CIFTI_INDEX_TYPE_BRAIN_MODELS) { return (findSurfaceModel(m_dimToMapLookup[direction], structure) != NULL); } else if (myMap->m_indicesMapToDataType == CIFTI_INDEX_TYPE_PARCELS) { bool found = false; for (int i = 0; i < (int)myMap->m_parcelSurfaces.size(); ++i) { if (myMap->m_parcelSurfaces[i].m_structure == structure) { found = true;//TODO: figure out if we should just return true here } } if (!found) return false; for (int64_t i = 0; i < (int64_t)myMap->m_parcels.size(); ++i) { const CiftiParcelElement& myParcel = myMap->m_parcels[i]; for (int j = 0; j < (int)myParcel.m_nodeElements.size(); ++j) { const CiftiParcelNodesElement& myNodes = myParcel.m_nodeElements[j]; if (myNodes.m_structure == structure && myNodes.m_nodes.size() != 0) return true;//instead of checking that at least one parcel actually uses it } } return false; } else { return false; } } bool CiftiXMLOld::addSurfaceModelToColumns(const int& numberOfNodes, const StructureEnum::Enum& structure, const float* roi) { return addSurfaceModel(ALONG_COLUMN, numberOfNodes, structure, roi); } bool CiftiXMLOld::addSurfaceModelToRows(const int& numberOfNodes, const StructureEnum::Enum& structure, const float* roi) { return addSurfaceModel(ALONG_ROW, numberOfNodes, structure, roi); } bool CiftiXMLOld::addSurfaceModel(const int& direction, const int& numberOfNodes, const StructureEnum::Enum& structure, const float* roi) { CaretAssertVectorIndex(m_dimToMapLookup, direction); separateMaps(); if (m_dimToMapLookup[direction] == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, m_dimToMapLookup[direction]); CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[direction]]); if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_BRAIN_MODELS) return false; if (findSurfaceModel(m_dimToMapLookup[direction], structure) != NULL) return false; CiftiBrainModelElement tempModel; tempModel.m_brainStructure = structure; tempModel.m_modelType = CIFTI_MODEL_TYPE_SURFACE; tempModel.m_indexOffset = getNewRangeStart(m_dimToMapLookup[direction]); tempModel.m_surfaceNumberOfNodes = numberOfNodes; if (roi == NULL) { tempModel.m_indexCount = numberOfNodes; } else { tempModel.m_indexCount = 0; tempModel.m_nodeIndices.reserve(numberOfNodes); bool allNodes = true; for (int i = 0; i < numberOfNodes; ++i) { if (roi[i] > 0.0f) { tempModel.m_nodeIndices.push_back(i); } else { allNodes = false; } } if (allNodes) { tempModel.m_nodeIndices.clear(); tempModel.m_indexCount = numberOfNodes; } else { tempModel.m_indexCount = (unsigned long long)tempModel.m_nodeIndices.size(); } } myMap->m_brainModels.push_back(tempModel); myMap->m_brainModels.back().setupLookup(*myMap); return true; } bool CiftiXMLOld::addSurfaceModelToColumns(const int& numberOfNodes, const StructureEnum::Enum& structure, const vector& nodeList) { return addSurfaceModel(ALONG_COLUMN, numberOfNodes, structure, nodeList); } bool CiftiXMLOld::addSurfaceModelToRows(const int& numberOfNodes, const StructureEnum::Enum& structure, const vector& nodeList) { return addSurfaceModel(ALONG_ROW, numberOfNodes, structure, nodeList); } bool CiftiXMLOld::addSurfaceModel(const int& direction, const int& numberOfNodes, const StructureEnum::Enum& structure, const vector& nodeList) { CaretAssertVectorIndex(m_dimToMapLookup, direction); separateMaps(); if (m_dimToMapLookup[direction] == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, m_dimToMapLookup[direction]); CaretAssertMessage(checkSurfaceNodes(nodeList, numberOfNodes), "node list has node numbers that don't exist in the surface"); CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[direction]]);//call the check function inside an assert so it never does the check in release builds if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_BRAIN_MODELS) return false; if (findSurfaceModel(m_dimToMapLookup[direction], structure) != NULL) return false; CiftiBrainModelElement tempModel; tempModel.m_brainStructure = structure; tempModel.m_modelType = CIFTI_MODEL_TYPE_SURFACE; tempModel.m_indexOffset = getNewRangeStart(m_dimToMapLookup[direction]); tempModel.m_surfaceNumberOfNodes = numberOfNodes; tempModel.m_indexCount = (int64_t)nodeList.size(); if ((int)nodeList.size() == numberOfNodes) { bool sequential = true; for (int i = 0; i < numberOfNodes; ++i) { if (nodeList[i] != i) { sequential = false; break; } } if (!sequential) { tempModel.m_nodeIndices = nodeList; } } else { tempModel.m_nodeIndices = nodeList; } myMap->m_brainModels.push_back(tempModel); myMap->m_brainModels.back().setupLookup(*myMap); return true; } bool CiftiXMLOld::checkSurfaceNodes(const vector& nodeList, const int& numberOfNodes) const { int listSize = (int)nodeList.size(); for (int i = 0; i < listSize; ++i) { if (nodeList[i] < 0 || nodeList[i] >= numberOfNodes) return false; } return true; } bool CiftiXMLOld::addVolumeModel(const int& direction, const vector& ijkList, const StructureEnum::Enum& structure) { CaretAssertVectorIndex(m_dimToMapLookup, direction); separateMaps(); if (m_dimToMapLookup[direction] == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, m_dimToMapLookup[direction]); CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[direction]]); if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_BRAIN_MODELS) return false; if (findVolumeModel(m_dimToMapLookup[direction], structure) != NULL) return false; CaretAssertMessage(checkVolumeIndices(ijkList), "volume voxel list doesn't match cifti volume space, do setVolumeDimsAndSForm first"); CiftiBrainModelElement tempModel;//call the check function inside an assert so it never does the check in release builds tempModel.m_brainStructure = structure; tempModel.m_modelType = CIFTI_MODEL_TYPE_VOXELS; tempModel.m_indexOffset = getNewRangeStart(m_dimToMapLookup[direction]); tempModel.m_indexCount = ijkList.size() / 3; tempModel.m_voxelIndicesIJK = ijkList; myMap->m_brainModels.push_back(tempModel); return true; } bool CiftiXMLOld::addVolumeModelToColumns(const vector& ijkList, const StructureEnum::Enum& structure) { return addVolumeModel(ALONG_COLUMN, ijkList, structure); } bool CiftiXMLOld::addVolumeModelToRows(const vector& ijkList, const StructureEnum::Enum& structure) { return addVolumeModel(ALONG_ROW, ijkList, structure); } bool CiftiXMLOld::addParcelSurfaceToColumns(const int& numberOfNodes, const StructureEnum::Enum& structure) { return addParcelSurface(ALONG_COLUMN, numberOfNodes, structure); } bool CiftiXMLOld::addParcelSurfaceToRows(const int& numberOfNodes, const StructureEnum::Enum& structure) { return addParcelSurface(ALONG_ROW, numberOfNodes, structure); } bool CiftiXMLOld::addParcelSurface(const int& direction, const int& numberOfNodes, const caret::StructureEnum::Enum& structure) { if (direction < 0 || direction >= (int)m_dimToMapLookup.size()) { return false; } separateMaps(); if (numberOfNodes < 1 || m_dimToMapLookup[direction] == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, m_dimToMapLookup[direction]); CiftiMatrixIndicesMapElement& myMap = m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[direction]]; if (myMap.m_indicesMapToDataType != CIFTI_INDEX_TYPE_PARCELS) return false; CiftiParcelSurfaceElement tempSurf; tempSurf.m_numNodes = numberOfNodes; tempSurf.m_structure = structure; myMap.m_parcelSurfaces.push_back(tempSurf); myMap.setupLookup();//TODO: make the lookup maintenance incremental return true; } bool CiftiXMLOld::addParcelToColumns(const CiftiParcelElement& parcel) { return addParcel(ALONG_COLUMN, parcel); } bool CiftiXMLOld::addParcelToRows(const caret::CiftiParcelElement& parcel) { return addParcel(ALONG_ROW, parcel); } bool CiftiXMLOld::addParcel(const int& direction, const CiftiParcelElement& parcel) { if (direction < 0 || direction >= (int)m_dimToMapLookup.size()) { return false; } separateMaps(); if (m_dimToMapLookup[direction] == -1 || m_root.m_matrices.size() == 0) { return false; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, m_dimToMapLookup[direction]); CiftiMatrixIndicesMapElement& myMap = m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[direction]]; if (myMap.m_indicesMapToDataType != CIFTI_INDEX_TYPE_PARCELS) return false; if (!checkVolumeIndices(parcel.m_voxelIndicesIJK)) return false; myMap.m_parcels.push_back(parcel);//NOTE: setupLookup does error checking for nodes try { myMap.setupLookup();//TODO: make the lookup maintenance incremental, decide on throw vs bool return, separate sanity checking? } catch (...) { return false; } return true; } bool CiftiXMLOld::checkVolumeIndices(const vector& ijkList) const { int64_t listSize = (int64_t)ijkList.size(); if (listSize == 0) return true; if (listSize % 3 != 0) return false; int64_t dims[3]; vector > sform;//not used, but needed by the funciton if (!getVolumeDimsAndSForm(dims, sform)) return false; for (int i = 0; i < listSize; i += 3) { if (ijkList[i] < 0 || ijkList[i] >= dims[0]) return false; if (ijkList[i + 1] < 0 || ijkList[i + 1] >= dims[1]) return false; if (ijkList[i + 2] < 0 || ijkList[i + 2] >= dims[2]) return false; } return true; } void CiftiXMLOld::applyColumnMapToRows() { if (m_dimToMapLookup[0] == m_dimToMapLookup[1]) return; applyDimensionHelper(1, 0); } void CiftiXMLOld::applyRowMapToColumns() { if (m_dimToMapLookup[0] == m_dimToMapLookup[1]) return; applyDimensionHelper(0, 1); } void CiftiXMLOld::applyDimensionHelper(const int& from, const int& to) { if (m_root.m_matrices.size() == 0) return; CiftiMatrixElement& myMatrix = m_root.m_matrices[0];//assume only one matrix int numMaps = (int)myMatrix.m_matrixIndicesMap.size(); for (int i = 0; i < numMaps; ++i) { CiftiMatrixIndicesMapElement& myMap = myMatrix.m_matrixIndicesMap[i]; int numDimensions = (int)myMap.m_appliesToMatrixDimension.size(); for (int j = 0; j < numDimensions; ++j) { if (myMap.m_appliesToMatrixDimension[j] == to) { myMap.m_appliesToMatrixDimension.erase(myMap.m_appliesToMatrixDimension.begin() + j); --numDimensions; --j; break; } } for (int j = 0; j < numDimensions; ++j) { if (myMap.m_appliesToMatrixDimension[j] == from) { myMap.m_appliesToMatrixDimension.push_back(to); break; } } if (myMap.m_appliesToMatrixDimension.size() == 0) { myMatrix.m_matrixIndicesMap.erase(myMatrix.m_matrixIndicesMap.begin() + i); for (int j = 0; j < (int)m_dimToMapLookup.size(); ++j) { if (m_dimToMapLookup[j] > i) --m_dimToMapLookup[j]; } --numMaps; --i;//make sure we don't skip a map due to an erase } } m_dimToMapLookup[to] = m_dimToMapLookup[from]; } void CiftiXMLOld::resetColumnsToBrainModels() { resetDirectionToBrainModels(ALONG_COLUMN); } void CiftiXMLOld::resetRowsToBrainModels() { resetDirectionToBrainModels(ALONG_ROW); } void CiftiXMLOld::resetDirectionToBrainModels(const int& direction) { if (m_dimToMapLookup[direction] == -1) { m_dimToMapLookup[direction] = createMap(direction); } else { separateMaps(); } CiftiMatrixIndicesMapElement myMap; myMap.m_appliesToMatrixDimension.push_back(direction); myMap.m_indicesMapToDataType = CIFTI_INDEX_TYPE_BRAIN_MODELS; m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[direction]] = myMap; } void CiftiXMLOld::resetColumnsToTimepoints(const float& timestep, const int& timepoints, const float& timestart) { if (m_dimToMapLookup[1] == -1) { m_dimToMapLookup[1] = createMap(1); } else { separateMaps(); } CiftiMatrixIndicesMapElement myMap; myMap.m_appliesToMatrixDimension.push_back(1); myMap.m_indicesMapToDataType = CIFTI_INDEX_TYPE_TIME_POINTS; myMap.m_timeStepUnits = NIFTI_UNITS_SEC; myMap.m_timeStep = timestep; myMap.m_timeStart = timestart; myMap.m_hasTimeStart = true; myMap.m_numTimeSteps = timepoints; m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[1]] = myMap; } void CiftiXMLOld::resetRowsToTimepoints(const float& timestep, const int& timepoints, const float& timestart) { if (m_dimToMapLookup[0] == -1) { m_dimToMapLookup[0] = createMap(0); } else { separateMaps(); } CiftiMatrixIndicesMapElement myMap; myMap.m_appliesToMatrixDimension.push_back(0); myMap.m_indicesMapToDataType = CIFTI_INDEX_TYPE_TIME_POINTS; myMap.m_timeStepUnits = NIFTI_UNITS_SEC; myMap.m_timeStep = timestep; myMap.m_timeStart = timestart; myMap.m_hasTimeStart = true; myMap.m_numTimeSteps = timepoints; m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[0]] = myMap; } void CiftiXMLOld::resetColumnsToScalars(const int64_t& numMaps) { resetDirectionToScalars(ALONG_COLUMN, numMaps); } void CiftiXMLOld::resetRowsToScalars(const int64_t& numMaps) { resetDirectionToScalars(ALONG_ROW, numMaps); } void CiftiXMLOld::resetDirectionToScalars(const int& direction, const int64_t& numMaps) { CaretAssertVectorIndex(m_dimToMapLookup, direction); if (m_dimToMapLookup[direction] == -1) { m_dimToMapLookup[direction] = createMap(direction); } else { separateMaps(); } CiftiMatrixIndicesMapElement myMap; myMap.m_appliesToMatrixDimension.push_back(direction); myMap.m_indicesMapToDataType = CIFTI_INDEX_TYPE_SCALARS; myMap.m_namedMaps.resize(numMaps); m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[direction]] = myMap; } void CiftiXMLOld::resetColumnsToLabels(const int64_t& numMaps) { resetDirectionToLabels(ALONG_COLUMN, numMaps); } void CiftiXMLOld::resetRowsToLabels(const int64_t& numMaps) { resetDirectionToLabels(ALONG_ROW, numMaps); } void CiftiXMLOld::resetDirectionToLabels(const int& direction, const int64_t& numMaps) { CaretAssertVectorIndex(m_dimToMapLookup, direction); if (m_dimToMapLookup[direction] == -1) { m_dimToMapLookup[direction] = createMap(direction); } else { separateMaps(); } CiftiMatrixIndicesMapElement myMap; myMap.m_appliesToMatrixDimension.push_back(direction); myMap.m_indicesMapToDataType = CIFTI_INDEX_TYPE_LABELS; myMap.m_namedMaps.resize(numMaps); for (int64_t i = 0; i < numMaps; ++i) { myMap.m_namedMaps[i].m_labelTable.grabNew(new GiftiLabelTable()); } m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[direction]] = myMap; } void CiftiXMLOld::resetColumnsToParcels() { resetDirectionToParcels(ALONG_COLUMN); } void CiftiXMLOld::resetRowsToParcels() { resetDirectionToParcels(ALONG_ROW); } void CiftiXMLOld::resetDirectionToParcels(const int& direction) { CaretAssertVectorIndex(m_dimToMapLookup, direction); if (m_dimToMapLookup[direction] == -1) { m_dimToMapLookup[direction] = createMap(direction); } else { separateMaps(); } CiftiMatrixIndicesMapElement myMap; myMap.m_appliesToMatrixDimension.push_back(direction); myMap.m_indicesMapToDataType = CIFTI_INDEX_TYPE_PARCELS; m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[direction]] = myMap; } int CiftiXMLOld::createMap(int dimension) { CiftiMatrixIndicesMapElement tempMap; tempMap.m_appliesToMatrixDimension.push_back(dimension); if (m_root.m_matrices.size() == 0) { m_root.m_matrices.resize(1); m_root.m_numberOfMatrices = 1;//TODO: remove this variable } CiftiMatrixElement& myMatrix = m_root.m_matrices[0];//assume only one matrix myMatrix.m_matrixIndicesMap.push_back(tempMap); return myMatrix.m_matrixIndicesMap.size() - 1; } void CiftiXMLOld::separateMaps() { if (m_root.m_matrices.size() == 0) return; CiftiMatrixElement& myMatrix = m_root.m_matrices[0];//assume only one matrix int numMaps = (int)myMatrix.m_matrixIndicesMap.size(); for (int i = 0; i < numMaps; ++i)//don't need to loop over newly created maps { CiftiMatrixIndicesMapElement myMap = myMatrix.m_matrixIndicesMap[i];//make a copy because we are modifying this vector int numDimensions = (int)myMap.m_appliesToMatrixDimension.size(); for (int j = 1; j < numDimensions; ++j)//leave the first in place { int whichDim = myMap.m_appliesToMatrixDimension[j]; myMatrix.m_matrixIndicesMap.push_back(myMap); myMatrix.m_matrixIndicesMap.back().m_appliesToMatrixDimension.resize(1); myMatrix.m_matrixIndicesMap.back().m_appliesToMatrixDimension[0] = whichDim; m_dimToMapLookup[whichDim] = myMatrix.m_matrixIndicesMap.size() - 1; } myMatrix.m_matrixIndicesMap[i].m_appliesToMatrixDimension.resize(1);//ditch all but the first, they have their own maps } } int64_t CiftiXMLOld::getNewRangeStart(const int& myMapIndex) const { if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { CaretAssert(false); } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]); CaretAssert(myMap != NULL && myMap->m_indicesMapToDataType == CIFTI_INDEX_TYPE_BRAIN_MODELS); int numModels = (int)myMap->m_brainModels.size(); int64_t curRet = 0; for (int i = 0; i < numModels; ++i) { int64_t thisEnd = myMap->m_brainModels[i].m_indexOffset + myMap->m_brainModels[i].m_indexCount; if (thisEnd > curRet) { curRet = thisEnd; } } return curRet; } int64_t CiftiXMLOld::getDimensionLength(const int& direction) const { if (direction < 0 || direction >= (int)m_dimToMapLookup.size()) { throw DataFileException("getDimensionLength called on nonexistant dimension"); } int myMapIndex = m_dimToMapLookup[direction]; if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { throw DataFileException("getDimensionLength called on nonexistant dimension"); } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]); if (myMap->m_indicesMapToDataType == CIFTI_INDEX_TYPE_TIME_POINTS) { return myMap->m_numTimeSteps; } else if (myMap->m_indicesMapToDataType == CIFTI_INDEX_TYPE_BRAIN_MODELS) { return getNewRangeStart(m_dimToMapLookup[direction]); } else if (myMap->m_indicesMapToDataType == CIFTI_INDEX_TYPE_SCALARS || myMap->m_indicesMapToDataType == CIFTI_INDEX_TYPE_LABELS) { return myMap->m_namedMaps.size(); } else if (myMap->m_indicesMapToDataType == CIFTI_INDEX_TYPE_PARCELS) { return myMap->m_parcels.size(); } else { throw DataFileException("unknown cifti mapping type"); } } int64_t CiftiXMLOld::getNumberOfColumns() const {//number of columns is LENGTH OF A ROW return getDimensionLength(ALONG_ROW); } int64_t CiftiXMLOld::getNumberOfRows() const { return getDimensionLength(ALONG_COLUMN); } IndicesMapToDataType CiftiXMLOld::getColumnMappingType() const { if (m_dimToMapLookup[1] == -1 || m_root.m_matrices.size() == 0) { return CIFTI_INDEX_TYPE_INVALID; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, m_dimToMapLookup[1]); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[1]]); return myMap->m_indicesMapToDataType; } IndicesMapToDataType CiftiXMLOld::getRowMappingType() const { if (m_dimToMapLookup[0] == -1 || m_root.m_matrices.size() == 0) { return CIFTI_INDEX_TYPE_INVALID; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, m_dimToMapLookup[0]); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[0]]); return myMap->m_indicesMapToDataType; } IndicesMapToDataType CiftiXMLOld::getMappingType(const int& direction) const { if (direction < 0 || direction >= (int)m_dimToMapLookup.size()) { CaretAssertMessage(false, "CiftiXML::getMappingType called with invalid direction"); return CIFTI_INDEX_TYPE_INVALID; } if (m_dimToMapLookup[direction] == -1 || m_root.m_matrices.size() == 0) { return CIFTI_INDEX_TYPE_INVALID; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, m_dimToMapLookup[direction]); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[direction]]); return myMap->m_indicesMapToDataType; } const CiftiBrainModelElement* CiftiXMLOld::findSurfaceModel(const int& myMapIndex, const StructureEnum::Enum& structure) const { if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { return NULL; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]); if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_BRAIN_MODELS) return NULL; const vector& myModels = myMap->m_brainModels; int numModels = myModels.size(); for (int i = 0; i < numModels; ++i) { if (myModels[i].m_brainStructure == structure && myModels[i].m_modelType == CIFTI_MODEL_TYPE_SURFACE) { return &(myModels[i]); } } return NULL; } const CiftiBrainModelElement* CiftiXMLOld::findVolumeModel(const int& myMapIndex, const StructureEnum::Enum& structure) const { if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { return NULL; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); const CiftiMatrixIndicesMapElement* myMap = &(m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]); if (myMap->m_indicesMapToDataType != CIFTI_INDEX_TYPE_BRAIN_MODELS) return NULL; const vector& myModels = myMap->m_brainModels; int numModels = myModels.size(); for (int i = 0; i < numModels; ++i) { if (myModels[i].m_brainStructure == structure && myModels[i].m_modelType == CIFTI_MODEL_TYPE_VOXELS) { return &(myModels[i]); } } return NULL; } bool CiftiXMLOld::matchesForColumns(const CiftiXMLOld& rhs) const { return mappingMatches(ALONG_COLUMN, rhs, ALONG_COLUMN); } bool CiftiXMLOld::matchesForRows(const CiftiXMLOld& rhs) const { return mappingMatches(ALONG_ROW, rhs, ALONG_ROW); } bool CiftiXMLOld::mappingMatches(const int& direction, const CiftiXMLOld& other, const int& otherDirection) const { CaretAssertVectorIndex(m_dimToMapLookup, direction); CaretAssertVectorIndex(other.m_dimToMapLookup, otherDirection); if (m_root.m_matrices.size() == 0 || m_dimToMapLookup[direction] == -1) { return (other.m_root.m_matrices.size() == 0 || other.m_dimToMapLookup[otherDirection] == -1); } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, m_dimToMapLookup[direction]); CaretAssertVectorIndex(other.m_root.m_matrices[0].m_matrixIndicesMap, other.m_dimToMapLookup[otherDirection]); if (hasVolumeData(direction) && !(other.hasVolumeData(otherDirection) && matchesVolumeSpace(other))) return false; return (m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[direction]] == other.m_root.m_matrices[0].m_matrixIndicesMap[other.m_dimToMapLookup[otherDirection]]); } void CiftiXMLOld::copyMapping(const int& direction, const CiftiXMLOld& other, const int& otherDirection) { CaretAssert(direction > -1 && otherDirection > -1); if ((int)other.m_dimToMapLookup.size() <= otherDirection || other.m_dimToMapLookup[otherDirection] == -1) { throw DataFileException("copyMapping called with nonexistant mapping to copy"); } bool copyVolSpace = false, haveVoxels = false; for (int i = 0; i < (int)m_dimToMapLookup.size(); ++i) { if (i != direction && hasVolumeData(i)) { haveVoxels = true; } } if (other.hasVolumeData(otherDirection)) { if (haveVoxels) { if (!matchesVolumeSpace(other)) throw DataFileException("cannot copy mapping from other cifti due to volume space mismatch"); } else { copyVolSpace = true; } } else { if (!haveVoxels) { m_root.m_matrices[0].m_volume.clear(); } } if (m_dimToMapLookup[direction] == -1) { m_dimToMapLookup[direction] = createMap(direction); } else { separateMaps(); } if (copyVolSpace) {//we have checked that this is okay because if we have any voxel data, it is in the map that is about to be replaced m_root.m_matrices[0].m_volume = other.m_root.m_matrices[0].m_volume; } CiftiMatrixIndicesMapElement& myMap = m_root.m_matrices[0].m_matrixIndicesMap[m_dimToMapLookup[direction]]; myMap = other.m_root.m_matrices[0].m_matrixIndicesMap[other.m_dimToMapLookup[otherDirection]]; myMap.m_appliesToMatrixDimension.clear(); myMap.m_appliesToMatrixDimension.push_back(direction);//the member lookups should already be valid, copy works } map* CiftiXMLOld::getMapMetadata(const int& direction, const int& index) const { CaretAssertVectorIndex(m_dimToMapLookup, direction); int myMapIndex = m_dimToMapLookup[direction]; if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { return NULL; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); const CiftiMatrixIndicesMapElement& myMap = m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]; if (myMap.m_indicesMapToDataType != CIFTI_INDEX_TYPE_LABELS && myMap.m_indicesMapToDataType != CIFTI_INDEX_TYPE_SCALARS) { return NULL; } CaretAssertVectorIndex(myMap.m_namedMaps, index); return &(myMap.m_namedMaps[index].m_mapMetaData); } PaletteColorMapping* CiftiXMLOld::getFilePalette() const { if (m_root.m_matrices.size() == 0) return NULL; if (m_root.m_matrices[0].m_palette == NULL) {//load from metadata m_root.m_matrices[0].m_palette.grabNew(new PaletteColorMapping()); map::const_iterator myIter = m_root.m_matrices[0].m_userMetaData.find("PaletteColorMapping"); if (myIter != m_root.m_matrices[0].m_userMetaData.end()) { m_root.m_matrices[0].m_palette->decodeFromStringXML(myIter->second); } /*} else {//will be needed if we make default palettes a user preference if (m_root.m_matrices[0].m_defaultPalette) {//TODO: load the current defaults into the existing palette, find some way of only doing this if the defaults were modified since last time this was called }//*/ } return m_root.m_matrices[0].m_palette.getPointer(); } PaletteColorMapping* CiftiXMLOld::getMapPalette(const int& direction, const int& index) const { CaretAssertVectorIndex(m_dimToMapLookup, direction); int myMapIndex = m_dimToMapLookup[direction]; if (myMapIndex == -1 || m_root.m_matrices.size() == 0) { return NULL; } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, myMapIndex); const CiftiMatrixIndicesMapElement& myMap = m_root.m_matrices[0].m_matrixIndicesMap[myMapIndex]; if (myMap.m_indicesMapToDataType != CIFTI_INDEX_TYPE_SCALARS) { return NULL; } CaretAssertVectorIndex(myMap.m_namedMaps, index); const CiftiNamedMapElement& myElem = myMap.m_namedMaps[index]; if (myElem.m_palette == NULL) {//load from metadata myElem.m_palette.grabNew(new PaletteColorMapping()); map::const_iterator myIter = myElem.m_mapMetaData.find("PaletteColorMapping"); if (myIter != myElem.m_mapMetaData.end()) { myElem.m_palette->decodeFromStringXML(myIter->second); } /*} else {//will be needed if we make default palettes a user preference if (m_root.m_matrices[0].m_defaultPalette) {//TODO: load the current defaults into the existing palette, find some way of only doing this if the defaults were modified since last time this was called }//*/ } return myElem.m_palette; } bool CiftiXMLOld::operator==(const caret::CiftiXMLOld& rhs) const { if (this == &rhs) return true;//compare pointers to skip checking object against itself if (m_root.m_matrices.size() != 1 || m_root.m_matrices[0].m_matrixIndicesMap.size() != 2) { throw DataFileException("old CIFTI XML implementation only supports single-matrix, 2D cifti"); } if (m_root.m_matrices.size() != rhs.m_root.m_matrices.size()) return false; if (m_root.m_matrices[0].m_matrixIndicesMap.size() != rhs.m_root.m_matrices[0].m_matrixIndicesMap.size()) return false; if (!matchesVolumeSpace(rhs)) return false; if (!matchesForColumns(rhs)) return false; if (!matchesForRows(rhs)) return false; return true; } bool CiftiXMLOld::matchesVolumeSpace(const CiftiXMLOld& rhs) const { if (hasColumnVolumeData() || hasRowVolumeData()) { if (!(rhs.hasColumnVolumeData() || rhs.hasRowVolumeData())) { return false; } } else { if (rhs.hasColumnVolumeData() || rhs.hasRowVolumeData()) { return false; } else { return true;//don't check for matching/existing sforms if there are no voxel maps in either } } int64_t dims[3], rdims[3]; vector > sform, rsform; if (!getVolumeDimsAndSForm(dims, sform) || !rhs.getVolumeDimsAndSForm(rdims, rsform)) {//should NEVER happen CaretAssertMessage(false, "has*VolumeData() and getVolumeDimsAndSForm() disagree"); throw DataFileException("has*VolumeData() and getVolumeDimsAndSForm() disagree"); } const float TOLER_RATIO = 0.999f;//ratio a spacing element can mismatch by for (int i = 0; i < 3; ++i) { if (dims[i] != rdims[i]) return false; for (int j = 0; j < 4; ++j) { float left = sform[i][j]; float right = rsform[i][j]; if (left != right && (left == 0.0f || right == 0.0f || left / right < TOLER_RATIO || right / left < TOLER_RATIO)) return false; } } return true; } void CiftiXMLOld::swapMappings(const int& direction1, const int& direction2) { CaretAssertVectorIndex(m_dimToMapLookup, direction1); CaretAssertVectorIndex(m_dimToMapLookup, direction2); if (direction1 < 0 || direction1 >= (int)m_dimToMapLookup.size() || direction2 < 0 || direction2 >= (int)m_dimToMapLookup.size()) { throw DataFileException("invalid direction specified to swapMappings, notify the developers"); } int mapIndex1 = m_dimToMapLookup[direction1]; int mapIndex2 = m_dimToMapLookup[direction2]; if (mapIndex1 == -1 || mapIndex2 == -1 || m_root.m_matrices.size() == 0) { throw DataFileException("invalid direction specified to swapMappings, notify the developers"); } CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, mapIndex1); CaretAssertVectorIndex(m_root.m_matrices[0].m_matrixIndicesMap, mapIndex2); if (mapIndex1 == mapIndex2) return;//nothing to do if they refer to the same mapping CiftiMatrixIndicesMapElement& mapRef1 = m_root.m_matrices[0].m_matrixIndicesMap[mapIndex1];//give them shorter variable names CiftiMatrixIndicesMapElement& mapRef2 = m_root.m_matrices[0].m_matrixIndicesMap[mapIndex2]; m_dimToMapLookup[direction1] = mapIndex2;//swap them by changing the lookup values m_dimToMapLookup[direction2] = mapIndex1; int numApply = (int)mapRef1.m_appliesToMatrixDimension.size(), i;//but we also need to modify the "applies to" lists for (i = 0; i < numApply; ++i) { if (mapRef1.m_appliesToMatrixDimension[i] == direction1)//we made the references from the old lookup values, so these are same { mapRef1.m_appliesToMatrixDimension[i] = direction2;//change the "applies to" element break; } } CaretAssert(i < numApply);//otherwise, we didn't find the element to modify, ie, something went horribly wrong numApply = (int)mapRef2.m_appliesToMatrixDimension.size();//and for the other mapping for (i = 0; i < numApply; ++i) { if (mapRef2.m_appliesToMatrixDimension[i] == direction2) { mapRef2.m_appliesToMatrixDimension[i] = direction1; break; } } CaretAssert(i < numApply); } connectome-workbench-1.4.2/src/Cifti/CiftiXMLOld.h000066400000000000000000000626531360521144700217230ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #ifndef __CIFTI_XML_OLD__ #define __CIFTI_XML_OLD__ #include "StructureEnum.h" #include "CiftiXMLElements.h" #include "CiftiXMLReader.h" #include "CiftiXMLWriter.h" #include "VolumeBase.h" #include "VolumeSpace.h" #include #include namespace caret { class DataFileContentInformation; /// Simple Container class for storing Cifti XML meta data struct CiftiSurfaceMap { int64_t m_ciftiIndex; int64_t m_surfaceNode; }; struct CiftiVolumeMap { int64_t m_ciftiIndex; int64_t m_ijk[3]; }; struct CiftiVolumeStructureMap { std::vector m_map; StructureEnum::Enum m_structure; }; struct CiftiBrainModelInfo { ModelType m_type; StructureEnum::Enum m_structure; CiftiBrainModelInfo() { m_type = CIFTI_MODEL_TYPE_INVALID; m_structure = StructureEnum::INVALID; } }; class CiftiXMLOld { public: enum { ALONG_ROW = 0, ALONG_COLUMN = 1, ALONG_STACK = 2//better name for this? }; /** * Default Constructor * * Default Constructor */ CiftiXMLOld(); /** * Constructor * * Constructor, create class using already existing Cifti xml tree * @param xml_root */ //CiftiXML(CiftiRootElement &xml_root) { m_root = xml_root; rootChanged(); } /** * Constructor * * Constructor, create class using ASCII formatted byte array that * containes xml meta data text * @param bytes */ CiftiXMLOld(const QByteArray &bytes) { readXML(bytes); } /** * Constructor * * Constructor, create class using QString that contains xml * meta data text * @param xml_string */ CiftiXMLOld(const QString &xml_string) { readXML(xml_string); } /** * Constructor * * Constructor, create class using QXmlStreamReader. * QXmlStreamReader is assumed to be reading from Cifti XML * Text. * @param xml_stream */ CiftiXMLOld(QXmlStreamReader &xml_stream) { readXML(xml_stream); } /** * readXML * * readXML, replacing the currently Cifti XML Root, if it exists * @param bytes an ASCII formatted byte array that contains Cifti XML data */ void readXML(const QByteArray &bytes) { QString text(bytes);readXML(text); } /** * readXML * * readXML, replacing the currently Cifti XML Root, if it exists * @param text QString that contains Cifti XML data */ void readXML(const QString &text) {QXmlStreamReader xml(text); readXML(xml); } /** * readXML * * readXML, replacing the currently Cifti XML Root, if it exists * @param xml_stream */ void readXML(QXmlStreamReader &xml_stream) { CiftiXMLReader myReader; myReader.parseCiftiXML(xml_stream,m_root); rootChanged(); } /** * writeXML * * write the Cifti XML data to the supplied QString * @param text */ void writeXML(QString &text) const { text = ""; QXmlStreamWriter xml(&text); CiftiXMLWriter myWriter; myWriter.writeCiftiXML(xml,m_root); }//we don't use the old writer in testing, so it won't recurse /** * writeXML * * write the Cifti XML data to the supplied byte array. * @param bytes */ void writeXML(QByteArray &bytes) const { bytes.clear(); QXmlStreamWriter xml(&bytes); CiftiXMLWriter myWriter; myWriter.writeCiftiXML(xml,m_root); } //static void testNewXML(const QString& xmlString); //static void testNewXML(const QByteArray& xmlString); /** * setXMLRoot * * set the Cifti XML root * @param xml_root */ //void setXMLRoot (CiftiRootElement &xml_root) { m_root = xml_root; rootChanged(); } /** * getXMLRoot * * get a copy of the Cifti XML Root * @param xml_root */ //void getXMLRoot (CiftiRootElement &xml_root) const { xml_root = m_root; } const CiftiVersion& getVersion() const { return m_root.m_version; } ///get the row index for a node, returns -1 if it doesn't find a matching mapping int64_t getRowIndexForNode(const int64_t& node, const StructureEnum::Enum& structure) const; ///get the column index for a node, returns -1 if it doesn't find a matching mapping int64_t getColumnIndexForNode(const int64_t& node, const StructureEnum::Enum& structure) const; ///get the row index for a voxel, returns -1 if it doesn't find a matching mapping int64_t getRowIndexForVoxel(const int64_t* ijk) const; ///get the column index for a voxel, returns -1 if it doesn't find a matching mapping int64_t getColumnIndexForVoxel(const int64_t* ijk) const; ///get the column index for a voxel coordinate, returns -1 if the closest indexes have no cifti data int64_t getRowIndexForVoxelCoordinate(const float* xyz) const; ///get the column index for a voxel coordinate, returns -1 if the closest indexes have no cifti data int64_t getColumnIndexForVoxelCoordinate(const float* xyz) const; ///get row index for a timepoint int64_t getRowIndexForTimepoint(const float& seconds) const; ///get row index for a timepoint int64_t getColumnIndexForTimepoint(const float& seconds) const; ///get the mapping for a surface in rows, returns false and empty vector if not found bool getSurfaceMapForRows(std::vector& mappingOut, const StructureEnum::Enum& structure) const; ///get the mapping for a surface in columns, returns false and empty vector if not found bool getSurfaceMapForColumns(std::vector& mappingOut, const StructureEnum::Enum& structure) const; ///get the mapping for a surface in columns, returns false and empty vector if not found bool getSurfaceMap(const int& direction, std::vector& mappingOut, const StructureEnum::Enum& structure) const; ///get the mapping for a volume in rows, returns false and empty vector if not found bool getVolumeMapForRows(std::vector& mappingOut) const; ///get the mapping for a volume in columns, returns false and empty vector if not found bool getVolumeMapForColumns(std::vector& mappingOut) const; ///get the mapping for a volume, returns false and empty vector if not found bool getVolumeMap(const int& direction, std::vector& mappingOut) const; void getVoxelInfoInDataFileContentInformation(const int& direction, DataFileContentInformation& dataFileInformation) const; ///get the mapping for a volume structure in rows, returns false and empty vector if not found bool getVolumeStructureMapForRows(std::vector& mappingOut, const StructureEnum::Enum& structure) const; ///get the mapping for a volume structure in columns, returns false and empty vector if not found bool getVolumeStructureMapForColumns(std::vector& mappingOut, const StructureEnum::Enum& structure) const; ///get the mapping for a volume structure bool getVolumeStructureMap(const int& direction, std::vector& mappingOut, const StructureEnum::Enum& structure) const; ///get the lists of what structures exist bool getStructureListsForRows(std::vector& surfaceList, std::vector& volumeList) const; ///get the lists of what structures exist bool getStructureListsForColumns(std::vector& surfaceList, std::vector& volumeList) const; ///get the lists of what structures exist bool getStructureLists(const int& direction, std::vector& surfaceList, std::vector& volumeList) const; ///get the number of structures for a brain model mapping int getNumberOfBrainModels(const int& direction) const; ///get structure info by structure index CiftiBrainModelInfo getBrainModelInfo(const int& direction, const int& whichModel) const; ///get the list of volume parcels and their maps in rows, returns false and empty vector if not found bool getVolumeModelMapsForRows(std::vector& mappingsOut) const; ///get the list of volume parcels and their maps in columns, returns false and empty vector if not found bool getVolumeModelMapsForColumns(std::vector& mappingsOut) const; ///get the original number of nodes of the surfaces used to make this cifti, for rows int64_t getRowSurfaceNumberOfNodes(const StructureEnum::Enum& structure) const; ///get the original number of nodes of the surfaces used to make this cifti, for columns int64_t getColumnSurfaceNumberOfNodes(const StructureEnum::Enum& structure) const; ///get the original number of nodes of the surfaces used to make this cifti along a direction int64_t getSurfaceNumberOfNodes(const int& direction, const StructureEnum::Enum& structure) const; ///get the timestep for rows, returns false if not timeseries bool getRowTimestep(float& seconds) const; ///get the timestep for columns, returns false if not timeseries bool getColumnTimestep(float& seconds) const; ///get the timestart for rows, returns false if not set or not timeseries bool getRowTimestart(float& seconds) const; ///get the timestart for columns, returns false if not set or not timeseries bool getColumnTimestart(float& seconds) const; ///get the number of timepoints for rows, returns false if not timeseries, sets -1 if unknown number of timepoints bool getRowNumberOfTimepoints(int& numTimepoints) const; ///get the number of timepoints for rows, returns false if not timeseries, sets -1 if unknown number of timepoints bool getColumnNumberOfTimepoints(int& numTimepoints) const; ///get the parcels for rows bool getParcelsForRows(std::vector& parcelsOut) const; ///get the parcels for columns bool getParcelsForColumns(std::vector& parcelsOut) const; ///get the parcels for a dimension bool getParcels(const int& direction, std::vector& parcelsOut) const; ///get the parcel surface structures bool getParcelSurfaceStructures(const int& direction, std::vector& structuresOut) const; ///get the row parcel for a node int64_t getRowParcelForNode(const int64_t& node, const StructureEnum::Enum& structure) const; ///get the column parcel for a node int64_t getColumnParcelForNode(const int64_t& node, const StructureEnum::Enum& structure) const; ///get the row parcel for a voxel int64_t getRowParcelForVoxel(const int64_t* ijk) const; ///get the row parcel for a voxel int64_t getColumnParcelForVoxel(const int64_t* ijk) const; ///set the timestep for rows, returns false if not timeseries bool setRowTimestep(const float& seconds); ///set the timestep for columns, returns false if not timeseries bool setColumnTimestep(const float& seconds); ///set the timestart for rows, returns false if not set or not timeseries bool setRowTimestart(const float& seconds); ///set the timestart for columns, returns false if not set or not timeseries bool setColumnTimestart(const float& seconds); ///set the number of timepoints for rows, returns false if not timeseries bool setRowNumberOfTimepoints(const int& numTimepoints); ///set the number of timepoints for rows, returns false if not timeseries bool setColumnNumberOfTimepoints(const int& numTimepoints); ///set rows to be brain models, and clear the list of brain models for rows void resetRowsToBrainModels(); ///set columns to be brain models, and clear the list of brain models for columns void resetColumnsToBrainModels(); ///set direction to be brain models, and clear it void resetDirectionToBrainModels(const int& direction); ///add a surface brain model to the list of brain models for rows bool addSurfaceModelToRows(const int& numberOfNodes, const StructureEnum::Enum& structure, const float* roi = NULL); ///add a surface brain model to the list of brain models for columns bool addSurfaceModelToColumns(const int& numberOfNodes, const StructureEnum::Enum& structure, const float* roi = NULL); ///add a surface brain model to the list of brain models for rows bool addSurfaceModelToRows(const int& numberOfNodes, const StructureEnum::Enum& structure, const std::vector& nodeList); ///add a surface brain model to the list of brain models for columns bool addSurfaceModelToColumns(const int& numberOfNodes, const StructureEnum::Enum& structure, const std::vector& nodeList); ///add a volume brain model to the list of brain models for rows bool addVolumeModelToRows(const std::vector& ijkList, const StructureEnum::Enum& structure); ///add a volume brain model to the list of brain models for columns bool addVolumeModelToColumns(const std::vector& ijkList, const StructureEnum::Enum& structure); ///add surface or volume model by direction bool addSurfaceModel(const int& direction, const int& numberOfNodes, const StructureEnum::Enum& structure, const float* roi = NULL); bool addSurfaceModel(const int& direction, const int& numberOfNodes, const StructureEnum::Enum& structure, const std::vector& nodeList); bool addVolumeModel(const int& direction, const std::vector& ijkList, const StructureEnum::Enum& structure); ///add a surface to the list of parcel surfaces for rows bool addParcelSurfaceToRows(const int& numberOfNodes, const StructureEnum::Enum& structure); ///add a surface to the list of parcel surfaces for columns bool addParcelSurfaceToColumns(const int& numberOfNodes, const StructureEnum::Enum& structure); ///add a surface to the list of parcel surfaces bool addParcelSurface(const int& direction, const int& numberOfNodes, const StructureEnum::Enum& structure); ///add a parcel to rows bool addParcelToRows(const CiftiParcelElement& parcel); ///add a parcel to columns bool addParcelToColumns(const CiftiParcelElement& parcel); ///add a parcel to columns bool addParcel(const int& direction, const CiftiParcelElement& parcel); ///set rows to be of type timepoints void resetRowsToTimepoints(const float& timestep, const int& numTimepoints, const float& timestart = 0.0f); ///set columns to be of type timepoints void resetColumnsToTimepoints(const float& timestep, const int& numTimepoints, const float& timestart = 0.0f); ///set rows to be of type scalars void resetRowsToScalars(const int64_t& numMaps); ///set columns to be of type scalars void resetColumnsToScalars(const int64_t& numMaps); ///set a direction to scalars void resetDirectionToScalars(const int& direction, const int64_t& numMaps); ///set rows to be of type labels void resetRowsToLabels(const int64_t& numMaps); ///set columns to be of type labels void resetColumnsToLabels(const int64_t& numMaps); ///set a direction to labels void resetDirectionToLabels(const int& direction, const int64_t& numMaps); ///set rows to be of type parcels void resetRowsToParcels(); ///set columns to be of type parcels void resetColumnsToParcels(); ///set dimension to be of type parcels void resetDirectionToParcels(const int& direction); ///get the map name for an index along a column AString getMapNameForColumnIndex(const int64_t& index) const; ///get the map name for an index along a row AString getMapNameForRowIndex(const int64_t& index) const; ///get the map name for an index AString getMapName(const int& direction, const int64_t& index) const; ///get the index for a map number/name - NOTE: returns -1 if mapping type doesn't support names int64_t getMapIndexFromNameOrNumber(const int& direction, const AString& numberOrName) const; //HACK: const method returns non-const GiftiLabelTable pointer because getCiftiXML MUST return a const CiftiXML&, but we need to be able to change the label table ///get the label table for an index along a column GiftiLabelTable* getLabelTableForColumnIndex(const int64_t& index) const; //HACK: const method returns non-const GiftiLabelTable pointer because getCiftiXML MUST return a const CiftiXML&, but we need to be able to change the label table ///get the label table for an index along a row GiftiLabelTable* getLabelTableForRowIndex(const int64_t& index) const; //HACK: const method returns non-const GiftiLabelTable pointer because getCiftiXML MUST return a const CiftiXML&, but we need to be able to change the label table ///get the label table for an index GiftiLabelTable* getMapLabelTable(const int& direction, const int64_t& myMapIndex) const; ///set the map name for an index along a column bool setMapNameForColumnIndex(const int64_t& index, const AString& name) const; ///set the map name for an index along a row bool setMapNameForRowIndex(const int64_t& index, const AString& name) const; ///set the map name for an index bool setMapNameForIndex(const int& direction, const int64_t& index, const AString& name) const; ///set the label table for an index along a column bool setLabelTableForColumnIndex(const int64_t& index, const GiftiLabelTable& labelTable); ///set the label table for an index along a row bool setLabelTableForRowIndex(const int64_t& index, const GiftiLabelTable& labelTable); ///set the column map to also apply to rows void applyColumnMapToRows(); ///set the row map to also apply to columns void applyRowMapToColumns(); ///get the number of rows (column length) int64_t getNumberOfRows() const; ///get the number of columns (row length) int64_t getNumberOfColumns() const; ///get the length of a dimension int64_t getDimensionLength(const int& direction) const; ///get what mapping type the rows use IndicesMapToDataType getRowMappingType() const; ///get what mapping type the columns use IndicesMapToDataType getColumnMappingType() const; ///get what mapping type a dimension uses IndicesMapToDataType getMappingType(const int& direction) const; ///get dimensions, spacing, origin for the volume attribute - returns false if not plumb bool getVolumeAttributesForPlumb(VolumeSpace::OrientTypes orientOut[3], int64_t dimensionsOut[3], float originOut[3], float spacingOut[3]) const; ///get dimensions and sform, useful for making a volume bool getVolumeDimsAndSForm(int64_t dimsOut[3], std::vector >& sformOut) const; ///set the volume space void setVolumeDimsAndSForm(const int64_t dims[3], const std::vector >& sform); ///get volume space object bool getVolumeSpace(VolumeSpace& volSpaceOut) const; ///swap mappings between two directions void swapMappings(const int& direction1, const int& direction2); ///check what types of data it has bool hasRowVolumeData() const; bool hasColumnVolumeData() const; bool hasVolumeData(const int& direction) const; bool hasRowSurfaceData(const StructureEnum::Enum& structure) const; bool hasColumnSurfaceData(const StructureEnum::Enum& structure) const; bool hasSurfaceData(const int& direction, const StructureEnum::Enum& structure) const; ///comparison bool mappingMatches(const int& direction, const CiftiXMLOld& other, const int& otherDirection) const; bool matchesForRows(const CiftiXMLOld& rhs) const; bool matchesForColumns(const CiftiXMLOld& rhs) const; bool matchesVolumeSpace(const CiftiXMLOld& rhs) const; bool operator==(const CiftiXMLOld& rhs) const; bool operator!=(const CiftiXMLOld& rhs) const { return !((*this) == rhs); } ///take a mapping from another xml object void copyMapping(const int& direction, const CiftiXMLOld& other, const int& otherDirection); std::map* getFileMetaData() const; std::map* getMapMetadata(const int& direction, const int& index) const; //HACK: const method returns non-const PaletteColorMapping pointer because getCiftiXML MUST return a const CiftiXML&, but we need to be able to change the palette PaletteColorMapping* getFilePalette() const; PaletteColorMapping* getMapPalette(const int& direction, const int& index) const; protected: CiftiRootElement m_root; //int m_rowMapIndex, m_colMapIndex; std::vector m_dimToMapLookup; ///updates the member variables associated with our root, should only be needed after reading from XML void rootChanged(); ///convenience functions to grab the correct model out of the tree, to replace the rowLeft/rowRight stuff (since we might have other surfaces too) const CiftiBrainModelElement* findSurfaceModel(const int& myMapIndex, const StructureEnum::Enum& structure) const; const CiftiBrainModelElement* findVolumeModel(const int& myMapIndex, const StructureEnum::Enum& structure) const; ///some boilerplate to get the correct index in a particular mapping int64_t getSurfaceIndex(const int64_t& node, const CiftiBrainModelElement* myModel) const; int64_t getVolumeIndex(const int64_t* ijk, const int& myMapIndex) const; int64_t getVolumeIndex(const float* xyz, const int& myMapIndex) const; int64_t getTimestepIndex(const float& seconds, const int& myMapIndex) const; int64_t getParcelForNode(const int64_t& node, const StructureEnum::Enum& structure, const int& myMapIndex) const; int64_t getParcelForVoxel(const int64_t* ijk, const int& myMapIndex) const; ///boilerplate for map information bool getTimestep(float& seconds, const int& myMapIndex) const; bool getTimestart(float& seconds, const int& myMapIndex) const; bool setTimestep(const float& seconds, const int& myMapIndex); bool setTimestart(const float& seconds, const int& myMapIndex); bool setLabelTable(const int64_t& index, const GiftiLabelTable& labelTable, const int& myMapIndex); ///some boilerplate to retrieve mappings bool getVolumeModelMappings(std::vector& mappingsOut, const int& myMapIndex) const; ///miscellaneous bool checkVolumeIndices(const std::vector& ijkList) const; bool checkSurfaceNodes(const std::vector& nodeList, const int& numberOfNodes) const; void applyDimensionHelper(const int& from, const int& to); int64_t getNewRangeStart(const int& myMapIndex) const; void separateMaps(); int createMap(int dimension); }; } #endif //__CIFTI_XML_OLD__ connectome-workbench-1.4.2/src/Cifti/CiftiXMLReader.cxx000066400000000000000000000771451360521144700227640ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretLogger.h" #include "CiftiXMLElements.h" #include "CiftiXMLReader.h" #include "DataFileException.h" #include "GiftiLabelTable.h" using namespace caret; using namespace std; void CiftiXMLReader::parseCiftiXML(QXmlStreamReader &xml, CiftiRootElement &rootElement) { while (!xml.atEnd() && !xml.hasError()) { xml.readNext(); QString test = xml.name().toString(); if(xml.isStartElement()) { QString elementName = xml.name().toString(); if(elementName == "CIFTI") { QXmlStreamAttributes attributes = xml.attributes(); if(attributes.hasAttribute("Version")) { rootElement.m_version = CiftiVersion(attributes.value("Version").toString()); m_readingVersion = rootElement.m_version; if (m_readingVersion != CiftiVersion(1, 0)) xml.raiseError("cannot read version " + m_readingVersion.toString() + " with old XML code"); } else xml.raiseError("Cifti XML Header missing Version String."); if(attributes.hasAttribute("NumberOfMatrices")) rootElement.m_numberOfMatrices = attributes.value("NumberOfMatrices").toString().toULong(); else xml.raiseError("Cifti XML Header missing number of matrices."); } else if(elementName == "Matrix") { rootElement.m_matrices.push_back(CiftiMatrixElement()); parseMatrixElement(xml,rootElement.m_matrices.back()); } else xml.raiseError("unknown element in Cifti: " + elementName); } } if(xml.hasError()) { throw DataFileException("XML error: " + xml.errorString()); } else if(!xml.atEnd()) { CaretLogWarning("Finished parsing Cifti XML without error, but not at end of XML"); } if (rootElement.m_numberOfMatrices != rootElement.m_matrices.size()) { CaretLogWarning("NumberOfMatrices does not match number of elements"); } } void CiftiXMLReader::parseMatrixElement(QXmlStreamReader &xml, CiftiMatrixElement &matrixElement) { QString test = xml.name().toString(); while (!(xml.isEndElement() && (xml.name().toString() == "Matrix")) && !xml.hasError()) {// && xml.name() == "Matrix") { xml.readNext(); QString test2 = xml.name().toString(); if(xml.isStartElement()) { QString elementName = xml.name().toString(); if(elementName == "MetaData") { parseMetaData(xml,matrixElement.m_userMetaData); } else if(elementName == "LabelTable") { parseLabelTable(xml,matrixElement.m_labelTable); } else if(elementName == "MatrixIndicesMap") { matrixElement.m_matrixIndicesMap.push_back(CiftiMatrixIndicesMapElement()); parseMatrixIndicesMap(xml,matrixElement.m_matrixIndicesMap.back()); } else if(elementName == "Volume") { matrixElement.m_volume.push_back(CiftiVolumeElement()); parseVolume(xml,matrixElement.m_volume.back()); if (xml.hasError()) return; } else xml.raiseError("unknown element in Matrix: " + elementName); } } QString test2=xml.name().toString(); //check end element if(!xml.hasError()) if(!xml.isEndElement() || (xml.name().toString() != "Matrix")) xml.raiseError("Matrix end tag not found."); } void CiftiXMLReader::parseMetaData(QXmlStreamReader &xml, map &userMetaData) { while (!(xml.isEndElement() && (xml.name().toString() == "MetaData")) && !xml.hasError()) {// && xml.name() == "MetaData") { xml.readNext(); if(xml.isStartElement()) { QString elementName = xml.name().toString(); if(elementName == "MD") { parseMetaDataElement(xml,userMetaData); } else xml.raiseError("unknown element in MetaData: " + elementName); } } //check for end element if(!xml.isEndElement() || (xml.name().toString() != "MetaData")) xml.raiseError("MetaData end tag not found."); } void CiftiXMLReader::parseMetaDataElement(QXmlStreamReader &xml, map &userMetaData) { QString name; QString value; QString test; bool haveName = false, haveValue = false; while (!(xml.isEndElement() && (xml.name().toString() == "MD")) && !xml.hasError()) { test = xml.name().toString(); xml.readNext(); if(xml.isStartElement()) { QString elementName = xml.name().toString(); if(elementName == "Name") { xml.readNext(); if(xml.tokenType() != QXmlStreamReader::Characters) { return; } name = xml.text().toString(); haveName = true; xml.readNext(); if(!xml.isEndElement()) xml.raiseError("End element for meta data name tag not found."); } else if(elementName == "Value") { xml.readNext(); if(xml.tokenType() != QXmlStreamReader::Characters) { return; } value = xml.text().toString(); haveValue = true; xml.readNext(); if(!xml.isEndElement()) xml.raiseError("End element for meta data value tag not found."); } else xml.raiseError("unknown element in MD: " + elementName); } } if (!haveName || !haveValue) xml.raiseError("MD element is missing name or value"); userMetaData[name] = value; if(!xml.isEndElement() || (xml.name().toString() != "MD")) xml.raiseError("End element for MD tag not found"); } void CiftiXMLReader::parseLabelTable(QXmlStreamReader &xml, std::vector &labelTable) { while (!(xml.isEndElement() && (xml.name().toString() == "LabelTable"))&& !xml.hasError()) {// && xml.name() == "Matrix") { xml.readNext(); if(xml.isStartElement()) { QString elementName = xml.name().toString(); if(elementName == "Label") { labelTable.push_back(CiftiLabelElement()); parseLabel(xml,labelTable.back()); } else xml.raiseError("unknown element in LabelTable: " + elementName); } } //check end element if(!xml.isEndElement() || (xml.name().toString() != "LabelTable")) { xml.raiseError("End element for label table not found."); } } void CiftiXMLReader::parseLabel(QXmlStreamReader &xml, CiftiLabelElement &label) { if(!(xml.name().toString() == "Label")) xml.raiseError("Error parsing Label\n"); QXmlStreamAttributes attributes = xml.attributes(); //get attribute values if(attributes.hasAttribute("Key")) label.m_key = attributes.value("Key").toString().toULongLong(); else xml.raiseError("Label does not contain Key value\n"); if(attributes.hasAttribute("Red")) label.m_red = attributes.value("Red").toString().toFloat(); else xml.raiseError("Label does not contain Red value\n"); if(attributes.hasAttribute("Green")) label.m_green = attributes.value("Green").toString().toFloat(); else xml.raiseError("Label does not contain Green value\n"); if(attributes.hasAttribute("Blue")) label.m_blue = attributes.value("Blue").toString().toFloat(); else xml.raiseError("Label does not contain Blue value\n"); if(attributes.hasAttribute("Alpha")) label.m_alpha = attributes.value("Alpha").toString().toFloat(); else xml.raiseError("Label does not contain Alpha value\n"); if(attributes.hasAttribute("X")) label.m_x = attributes.value("X").toString().toFloat(); else xml.raiseError("Label does not contain X value\n"); if(attributes.hasAttribute("Y")) label.m_y = attributes.value("Y").toString().toFloat(); else xml.raiseError("Label does not contain Y value\n"); if(attributes.hasAttribute("Z")) label.m_z = attributes.value("Z").toString().toFloat(); else xml.raiseError("Label does not contain Z value\n"); //get Label Text xml.readNext(); if(xml.tokenType() != QXmlStreamReader::Characters) { return; } label.m_text = xml.text().toString(); //get end element xml.readNext(); if(!xml.isEndElement()) { xml.raiseError("End element for label not found."); } } void CiftiXMLReader::parseMatrixIndicesMap(QXmlStreamReader &xml, CiftiMatrixIndicesMapElement &matrixIndicesMap) { QXmlStreamAttributes attributes = xml.attributes(); //get attribute values if(attributes.hasAttribute("AppliesToMatrixDimension")) { QStringList values = attributes.value("AppliesToMatrixDimension").toString().split(','); bool ok = false; for(int i = 0;ireadFromQXmlStreamReader(xml);//we need to do something to read through the label table, so give it to the parser always if (!needLabels)//if it shouldn't exist, drop it { CaretLogWarning("found label table in a scalar map, discarding"); namedMap.m_labelTable.grabNew(NULL); } haveLabelTable = true; } else if (xml.name() == "MetaData") { if (haveMetaData) { xml.raiseError("MetaData specified more than once in NamedMap"); break; } parseMetaData(xml, namedMap.m_mapMetaData); haveMetaData = true; } else { xml.raiseError("unknown element in NamedMap: " + xml.name().toString()); break; } } xml.readNext(); } if (!xml.hasError() && (!haveName)) { xml.raiseError("NamedMap element is missing MapName element"); } if (!xml.hasError() && !haveLabelTable && needLabels) { xml.raiseError("NamedMap element is missing LabelTable element while type is CIFTI_INDEX_TYPE_LABELS"); } if (!xml.hasError() && (!xml.isEndElement() || xml.name() != "NamedMap")) { xml.raiseError("unexpected element in NamedMap: " + xml.name().toString()); } } void CiftiXMLReader::parseParcel(QXmlStreamReader& xml, CiftiParcelElement& parcel) { QXmlStreamAttributes attributes = xml.attributes(); if (attributes.hasAttribute("Name")) { parcel.m_parcelName = attributes.value("Name").toString(); } else { xml.raiseError("Required attribute 'Name' missing from Parcel"); } xml.readNext(); while (!xml.hasError() && !(xml.isEndElement() && xml.name() == "Parcel")) { if (xml.isStartElement()) { if (xml.name() == "Nodes") { parcel.m_nodeElements.push_back(CiftiParcelNodesElement()); parseParcelNodes(xml, parcel.m_nodeElements.back()); } else if (xml.name() == "VoxelIndicesIJK") { xml.readNext(); if(xml.tokenType() == QXmlStreamReader::Characters) { QString voxelIndicesIJK = xml.text().toString(); QStringList list = voxelIndicesIJK.split(QRegExp("\\D+"),QString::SkipEmptyParts); if(list.count()%3) xml.raiseError("VoxelIndicesIJK has an incomplete triplet"); bool ok = true; for(int i = 0;i namespace caret { class CiftiXMLReader { CiftiVersion m_readingVersion; void parseMatrixElement(QXmlStreamReader &xml, CiftiMatrixElement &matrixElement); void parseMetaData(QXmlStreamReader &xml, std::map &metaData); void parseMetaDataElement(QXmlStreamReader &xml, std::map &userMetaData); void parseLabelTable(QXmlStreamReader &xml, std::vector &labelElement); void parseLabel(QXmlStreamReader &xml, CiftiLabelElement &label); void parseMatrixIndicesMap(QXmlStreamReader &xml, CiftiMatrixIndicesMapElement &matrixIndicesMap); void parseBrainModel(QXmlStreamReader &xml, CiftiBrainModelElement &brainModel); void parseNamedMap(QXmlStreamReader &xml, CiftiNamedMapElement &namedMap, const bool needLabels); void parseParcel(QXmlStreamReader &xml, CiftiParcelElement& parcel); void parseParcelNodes(QXmlStreamReader &xml, CiftiParcelNodesElement& parcelNodes); void parseVolume(QXmlStreamReader &xml, CiftiVolumeElement &volume); void parseTransformationMatrixVoxelIndicesIJKtoXYZ(QXmlStreamReader &xml, TransformationMatrixVoxelIndicesIJKtoXYZElement &transform); public: void parseCiftiXML(QXmlStreamReader &xml, CiftiRootElement &rootElement); }; } #endif //__CIFTI_XML_READER_H__ connectome-workbench-1.4.2/src/Cifti/CiftiXMLWriter.cxx000066400000000000000000000367321360521144700230330ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiXMLWriter.h" #include "GiftiLabelTable.h" #include "PaletteColorMapping.h" using namespace caret; using namespace std; void CiftiXMLWriter::writeCiftiXML(QXmlStreamWriter &xml, const CiftiRootElement &rootElement) { m_writingVersion = CiftiVersion(1, 0);//HACK: this writer can't support other versions of XML, the structure is too closely tied to the 1.0 representation xml.setAutoFormatting(true); xml.writeStartElement("CIFTI"); xml.writeAttribute("Version", m_writingVersion.toString()); xml.writeAttribute("NumberOfMatrices",QString::number(rootElement.m_numberOfMatrices)); for(unsigned int i = 0;i metadataCopy = matrixElement.m_userMetaData;//since we may be modifying the map, we must make a copy of it if (matrixElement.m_palette != NULL) {//NULL palette means we didn't mess with palette at all if (matrixElement.m_defaultPalette && !(matrixElement.m_palette->isModified())) {//it is set to use the default palette instead of a custom palette, so remove the palette item from metadata, if it exists metadataCopy.erase("PaletteColorMapping"); } else { metadataCopy["PaletteColorMapping"] = matrixElement.m_palette->encodeInXML(); } } if(metadataCopy.size() > 0) writeMetaData(xml,metadataCopy); if(matrixElement.m_volume.size() > 0) writeVolume(xml, matrixElement.m_volume[0]); if(matrixElement.m_labelTable.size() > 0) writeLabelTable(xml, matrixElement.m_labelTable); for(unsigned int i = 0;i &metaData) { xml.writeStartElement("MetaData"); map::const_iterator i; for (i = metaData.begin(); i != metaData.end(); ++i) { writeMetaDataElement(xml,i->first,i->second); } xml.writeEndElement(); } void CiftiXMLWriter::writeMetaDataElement(QXmlStreamWriter &xml, const AString &name, const AString &value) { xml.writeStartElement("MD"); xml.writeStartElement("Name"); xml.writeCharacters(name); xml.writeEndElement();//Name xml.writeStartElement("Value"); xml.writeCharacters(value); xml.writeEndElement();//Value xml.writeEndElement();//MD } void CiftiXMLWriter::writeLabelTable(QXmlStreamWriter &xml, const std::vector &labelElement) { xml.writeStartElement("LabelTable"); for(unsigned int i=0;i0) { QString str; xml.writeAttribute("TimeStep",str.sprintf("%.10f",matrixIndicesMap.m_timeStep)); if (matrixIndicesMap.m_hasTimeStart) xml.writeAttribute("TimeStart",str.sprintf("%.10f",matrixIndicesMap.m_timeStart)); xml.writeAttribute("TimeStepUnits",timeStepUnits); } if(matrixIndicesMap.m_appliesToMatrixDimension.size()) { int lastElement = matrixIndicesMap.m_appliesToMatrixDimension.size() -1; QString appliesToMatrixDimension, str; for(int i = 0;i &ind = brainModel.m_voxelIndicesIJK; unsigned long long lastVoxelIndex = ind.size(); if(lastVoxelIndex) { xml.writeStartElement("VoxelIndicesIJK"); QString line( "%1 %2 %3\n"); if((lastVoxelIndex%3)) { std::cout << "Error writing BrainModel, invalid number of voxel indices:" << lastVoxelIndex << std::endl; return;//TODO throw exception } //else //std::cout << "voxel indices ok:" << lastVoxelIndex<< std::endl; for(unsigned int i = 0;i < lastVoxelIndex;i+=3) { xml.writeCharacters(line.arg(QString::number(ind[i]),QString::number(ind[i+1]),QString::number(ind[i+2]))); } xml.writeEndElement();//voxelIndicesIJK } xml.writeEndElement(); } void CiftiXMLWriter::writeNamedMap(QXmlStreamWriter& xml, const CiftiNamedMapElement& namedMap) { xml.writeStartElement("NamedMap"); xml.writeStartElement("MapName"); xml.writeCharacters(namedMap.m_mapName); xml.writeEndElement(); if (namedMap.m_labelTable != NULL) { namedMap.m_labelTable->writeAsXML(xml); } map metadataCopy = namedMap.m_mapMetaData;//make a copy because we may need to modify it to integrate palette if (namedMap.m_palette != NULL) {//NULL palette means we didn't mess with palette at all, leave metadata unchanged if (namedMap.m_defaultPalette && !(namedMap.m_palette->isModified())) {//it is set to use the default palette instead of a custom palette, so remove the palette item from metadata, if it exists metadataCopy.erase("PaletteColorMapping"); } else { metadataCopy["PaletteColorMapping"] = namedMap.m_palette->encodeInXML(); } } if (metadataCopy.size() != 0) { writeMetaData(xml, metadataCopy); } xml.writeEndElement(); } void CiftiXMLWriter::writeParcel(QXmlStreamWriter& xml, const CiftiParcelElement& parcel) { xml.writeStartElement("Parcel"); xml.writeAttribute("Name", parcel.m_parcelName); int numNodeElements = (int)parcel.m_nodeElements.size(); for (int i = 0; i < numNodeElements; ++i) { writeParcelNodes(xml, parcel.m_nodeElements[i]); } int numVoxInds = (int)parcel.m_voxelIndicesIJK.size(); if (numVoxInds > 0) { xml.writeStartElement("VoxelIndicesIJK"); xml.writeCharacters(AString::number(parcel.m_voxelIndicesIJK[0])); int state = 0; for (int i = 1; i < numVoxInds; ++i) { if (state >= 2) { state = 0; xml.writeCharacters("\n"); } else { ++state; xml.writeCharacters(" "); } xml.writeCharacters(AString::number(parcel.m_voxelIndicesIJK[i])); } xml.writeEndElement(); } xml.writeEndElement(); } void CiftiXMLWriter::writeParcelNodes(QXmlStreamWriter& xml, const CiftiParcelNodesElement& parcelNodes) { int numNodes = (int)parcelNodes.m_nodes.size(); if (numNodes > 0)//don't write empty elements even if they exist in the tree { xml.writeStartElement("Nodes"); xml.writeAttribute("BrainStructure", StructureEnum::toCiftiName(parcelNodes.m_structure)); xml.writeCharacters(AString::number(parcelNodes.m_nodes[0])); for (int i = 1; i < numNodes; ++i) { xml.writeCharacters(" "); xml.writeCharacters(AString::number(parcelNodes.m_nodes[i])); } xml.writeEndElement(); } } void CiftiXMLWriter::writeVolume(QXmlStreamWriter &xml, const CiftiVolumeElement &volume) { xml.writeStartElement("Volume"); QString str("%1,%2,%3"); xml.writeAttribute("VolumeDimensions", str.arg(QString::number(volume.m_volumeDimensions[0]),QString::number(volume.m_volumeDimensions[1]),QString::number(volume.m_volumeDimensions[2]))); for(unsigned int i = 0;i 0) xml.writeAttribute("DataSpace", dataSpaceString); if(transformedSpaceString.length() > 0) xml.writeAttribute("TransformedSpace", transformedSpaceString); if(unitsXYZString.length() > 0) xml.writeAttribute("UnitsXYZ", unitsXYZString); QString matrixString; for(int i = 0;i<12;i++) { matrixString += QString::number(transform.m_transform[i], 'f', 10) + " "; } for (int i = 0; i < 3; ++i)//always write 0 0 0 1, ignore the actual last row { matrixString += QString::number(0.0f, 'f', 10) + " "; } matrixString += QString::number(1.0f, 'f', 10); xml.writeCharacters(matrixString); xml.writeEndElement(); } void CiftiXMLWriter::getModelTypeString(int modelType, QString &modelTypeString) { if(modelType == CIFTI_MODEL_TYPE_SURFACE) modelTypeString = "CIFTI_MODEL_TYPE_SURFACE"; else if(modelType == CIFTI_MODEL_TYPE_VOXELS) modelTypeString = "CIFTI_MODEL_TYPE_VOXELS"; } void CiftiXMLWriter::getDataSpaceString(int dataSpace, QString &dataSpaceString) { if(dataSpace == NIFTI_XFORM_UNKNOWN) dataSpaceString = "NIFTI_XFORM_UNKNOWN"; else if(dataSpace == NIFTI_XFORM_SCANNER_ANAT) dataSpaceString = "NIFTI_XFORM_SCANNER_ANAT"; else if(dataSpace == NIFTI_XFORM_ALIGNED_ANAT) dataSpaceString = "NIFTI_XFORM_ALIGNED_ANAT"; else if(dataSpace == NIFTI_XFORM_TALAIRACH) dataSpaceString = "NIFTI_XFORM_TALAIRACH"; else if(dataSpace == NIFTI_XFORM_MNI_152) dataSpaceString = "NIFTI_XFORM_MNI_152"; } void CiftiXMLWriter::getUnitsXYZString(int unitsXYZ, QString &unitsXYZString) { if(unitsXYZ == NIFTI_UNITS_MM) unitsXYZString = "NIFTI_UNITS_MM"; else if(unitsXYZ == NIFTI_UNITS_MICRON) unitsXYZString = "NIFTI_UNITS_MICRON"; } connectome-workbench-1.4.2/src/Cifti/CiftiXMLWriter.h000066400000000000000000000050341360521144700224470ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #ifndef __CIFTI_XML_WRITER_H__ #define __CIFTI_XML_WRITER_H__ #include #include "CiftiXMLElements.h" namespace caret { class CiftiXMLWriter { CiftiVersion m_writingVersion; void writeMatrixElement(QXmlStreamWriter &xml, const CiftiMatrixElement &matrixElement); void writeMetaData(QXmlStreamWriter &xml, const std::map &metaData); void writeMetaDataElement(QXmlStreamWriter &xml, const AString &name, const AString &value); void writeLabelTable(QXmlStreamWriter &xml, const std::vector &labelElement); void writeLabel(QXmlStreamWriter &xml, const CiftiLabelElement &label); void writeMatrixIndicesMap(QXmlStreamWriter &xml, const CiftiMatrixIndicesMapElement &matrixIndicesMap); void writeBrainModel(QXmlStreamWriter &xml, const CiftiBrainModelElement &brainModel); void writeNamedMap(QXmlStreamWriter& xml, const CiftiNamedMapElement& namedMap); void writeParcel(QXmlStreamWriter& xml, const CiftiParcelElement& parcel); void writeParcelNodes(QXmlStreamWriter& xml, const CiftiParcelNodesElement& parcelNodes); void writeVolume(QXmlStreamWriter &xml, const CiftiVolumeElement &volume); void writeTransformationMatrixVoxelIndicesIJKtoXYZ(QXmlStreamWriter &xml, const TransformationMatrixVoxelIndicesIJKtoXYZElement &transform); void getModelTypeString(int modelType, QString &modelTypeString); void getDataSpaceString(int dataSpace, QString &dataSpaceString); void getUnitsXYZString(int UnitsXYZ, QString &unitsXYZString); public: void writeCiftiXML(QXmlStreamWriter &xml, const CiftiRootElement &rootElement); }; } #endif //__CIFTI_XML_WRITER_H__ connectome-workbench-1.4.2/src/Cifti/Doxyfile000066400000000000000000002045441360521144700211770ustar00rootroot00000000000000# Doxyfile 1.7.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = Cifti # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = ./doxy # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this # tag. The format is ext=language, where ext is a file extension, and language # is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, # C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions # you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. EXTENSION_MAPPING = # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen to replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penality. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will rougly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = NO # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = YES # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = YES # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. The create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = . # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = *.h \ *.cxx # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the stylesheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see #
# Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list. USE_INLINE_TREES = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client # using Javascript. Doxygen will generate the search PHP script and index # file to put on the web server. The advantage of the server # based approach is that it scales better to large projects and allows # full text search. The disadvances is that it is more difficult to setup # and does not have live searching capabilities. SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = YES # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will write a font called FreeSans.ttf to the output # directory and reference it in all dot files that doxygen generates. This # font does not include all possible unicode characters however, so when you need # these (or just want a differently looking font) you can specify the font name # using DOT_FONTNAME. You need need to make sure dot is able to find the font, # which can be done by putting it in a standard location or by setting the # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory # containing the font. DOT_FONTNAME = FreeSans.ttf # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the output directory to look for the # FreeSans.ttf font (which doxygen will put there itself). If you specify a # different font using DOT_FONTNAME you can set the path where dot # can find it using this tag. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = YES # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = YES # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = YES # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES connectome-workbench-1.4.2/src/Cifti/QUICKSTART000066400000000000000000000031141360521144700210740ustar00rootroot00000000000000The entry point for reading and writing Cifti data is the object CiftiFile. To get a handle to a Cifti File, use the following syntax: CiftiFile cf("testciftifile.dtseries.nii"), cf2;//starts on-disk reading, and makes an uninitialized second object cf2.setWritingFile("testoutcifti.dtseries.nii");//prepare on-disk writing mode //cf.convertToInMemory();//if you want to read entire file into memory now CiftiFile gives access to the file in two parts, the Cifti XML, and the Cifti Matrix data. To access the data use the following functions: //get the CiftiXML object, containing mapping info for each dimension const CiftiXML& xml = cf->getCiftiXML(); cf2->setCiftiXML(xml);//setting xml is required before writing rows of data, as the xml controls the dimensions and mapping info //read/write Cifti rows vector scratchRow(cf.getDimensions()[0]); //simplified functions for 2D only cf.getRow(scratchRow.data(), 0); cf2.setRow(scratchRow.data(), 0); //example specifically for 3D cifti vector indices(2, 0);//[0 0] cf.getRow(scratchRow.data(), indices); cf2.setRow(scratchRow.data(), indices); //write current state to a new Cifti File, without changing what file subsequent setRow calls set data in (if any) cf.writeFile("outputfile.dtseries.nii"); For more detailed information on how to manipulate Cifti data, look at the source files in the examples directory Other references: nitrc page: http://www.nitrc.org/projects/cifti/ effectively same library, available under BSD 2-clause, and adapted to work with either libxml++ or qt: https://github.com/Washington-University/CiftiLib connectome-workbench-1.4.2/src/Cifti/examples/000077500000000000000000000000001360521144700212765ustar00rootroot00000000000000connectome-workbench-1.4.2/src/Cifti/examples/datatype.cxx000066400000000000000000000053731360521144700236450ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*LICENSE_END*/ #include "CaretException.h" #include "CiftiFile.h" #include #include using namespace std; using namespace cifti; /**\file datatype.cxx This program reads a Cifti file from argv[1], and writes it out to argv[2] using 8-bit unsigned integer and data scaling. It uses a single CiftiFile object to do this, for simplicity - to see how to do something similar with two objects, which is more relevant for how you would do processing on cifti files, see rewrite.cxx. \include datatype.cxx */ int main(int argc, char** argv) { if (argc < 3) { cout << "usage: " << argv[0] << " " << endl; cout << " rewrite the input cifti file to the output filename, using uint8 and data scaling." << endl; return 1; } try { CiftiFile inputFile(argv[1]);//on-disk reading by default inputFile.setWritingDataTypeAndScaling(NIFTI_TYPE_UINT8, -1.0, 6.0);//tells it to use this datatype to best represent this specified range of values [-1.0, 6.0] whenever this instance is written inputFile.writeFile(argv[2]);//if the output filename is the same as the input filename, CiftiFile actually detects this and reads the input into memory first //otherwise, it will read and write one row at a time, using very little memory //inputFile.setWritingDataTypeNoScaling(NIFTI_TYPE_FLOAT32);//this is how you would revert back to writing as float32 without rescaling } catch (CaretException& e) { cerr << "Caught CaretException: " + e.whatString() << endl; return 1; } return 0; } connectome-workbench-1.4.2/src/Cifti/examples/rewrite.cxx000066400000000000000000000063471360521144700235150ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*LICENSE_END*/ #include "CaretException.h" #include "CiftiFile.h" #include #include using namespace std; using namespace caret; /**\file rewrite.cxx This program reads a Cifti file from argv[1], and writes it out to argv[2] with a second CiftiFile object. It uses on-disk reading and writing, so DO NOT have both filenames point to the same file, CiftiFile truncates without any warning when told to write to an existing file. \include rewrite.cxx */ int main(int argc, char** argv) { if (argc < 3) { cout << "this program requires two arguments: an input cifti file, and an output filename to write it to" << endl; return 1; } try { CiftiFile inputFile(argv[1]);//on-disk reading by default //inputFile.convertToInMemory();//if you want to read it into memory first CiftiFile outputFile; outputFile.setWritingFile(argv[2]);//sets up on-disk writing with default writing version, from CiftiVersion's default constructor outputFile.setCiftiXML(inputFile.getCiftiXML());//the CiftiXML is how you access all the mapping information const vector& dims = inputFile.getDimensions(); vector scratchRow(dims[0]);//read/write a row at a time for (MultiDimIterator iter = inputFile.getIteratorOverRows(); !iter.atEnd(); ++iter) {//helper class to iterate over 2D and 3D cifti with the same code - the "+ 1" is to drop the first dimension (row length) inputFile.getRow(scratchRow.data(), *iter); outputFile.setRow(scratchRow.data(), *iter); } outputFile.writeFile(argv[2]);//because we called setWritingFile with this filename (and default cifti version), this will return immediately //NOTE: if you call writeFile with a different writing version (takes its default from CiftiVersion constructor) than setWritingFile, it will rewrite the entire file after reading it into memory } catch (CaretException& e) { cerr << "Caught CaretException: " + e.whatString() << endl; return 1; } return 0; } connectome-workbench-1.4.2/src/Cifti/examples/xmlinfo.cxx000066400000000000000000000140111360521144700234730ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*LICENSE_END*/ #include "CaretException.h" #include "CiftiFile.h" #include #include using namespace std; using namespace caret; /**\file xmlinfo.cxx This program reads a Cifti file from argv[1], and prints out a summary of the XML. \include xmlinfo.cxx */ int main(int argc, char** argv) { if (argc < 2) { cout << "this program requires one argument: an input cifti file" << endl; return 1; } try { CiftiFile inputFile(argv[1]);//on-disk reading by default, and we only need the XML header anyway const CiftiXML& myXML = inputFile.getCiftiXML(); for (int whichDim = 0; whichDim < myXML.getNumberOfDimensions(); ++whichDim) { cout << "Dimension " << whichDim << ": "; switch (myXML.getMappingType(whichDim)) { case CiftiMappingType::BRAIN_MODELS: { const CiftiBrainModelsMap& myMap = myXML.getBrainModelsMap(whichDim); cout << "Brain Models, length " << myMap.getLength() << endl; vector myInfo = myMap.getModelInfo();//this is only summary info, same order as the models are in the cifti indices for (int i = 0; i < (int)myInfo.size(); ++i)//to get the lists of vertices/voxels for a model, see getSurfaceMap, getVolumeStructureMap, and getFullVolumeMap { switch (myInfo[i].m_type) { case CiftiBrainModelsMap::SURFACE: cout << " Surface " << StructureEnum::toName(myInfo[i].m_structure) << ": "; cout << myInfo[i].m_indexCount << " out of " << myMap.getSurfaceNumberOfNodes(myInfo[i].m_structure) << " vertices" << endl; break; case CiftiBrainModelsMap::VOXELS: cout << " Voxels " << StructureEnum::toName(myInfo[i].m_structure) << ": "; cout << myInfo[i].m_indexCount << " voxels" << endl; break; } } break; } case CiftiMappingType::LABELS: { const CiftiLabelsMap& myMap = myXML.getLabelsMap(whichDim); cout << "Labels, length " << myMap.getLength() << endl; for (int i = 0; i < myMap.getLength(); ++i) { cout << " Index " << i << ": " << myMap.getMapName(i) << endl; } break; } case CiftiMappingType::PARCELS: { const CiftiParcelsMap& myMap = myXML.getParcelsMap(whichDim); cout << "Parcels, length " << myMap.getLength() << endl; const vector& myParcels = myMap.getParcels(); for (int i = 0; i < (int)myParcels.size(); ++i) { cout << " Index " << i << ", name '" << myParcels[i].m_name << "': "; int numVerts = 0; for (map >::const_iterator iter = myParcels[i].m_surfaceNodes.begin(); iter != myParcels[i].m_surfaceNodes.end(); ++iter) { numVerts += iter->second.size(); } cout << numVerts << " vertices, " << myParcels[i].m_voxelIndices.size() << " voxels" << endl; } break; } case CiftiMappingType::SCALARS: { const CiftiScalarsMap& myMap = myXML.getScalarsMap(whichDim); cout << "Scalars, length " << myMap.getLength() << endl; for (int i = 0; i < myMap.getLength(); ++i) { cout << " Index " << i << ": " << myMap.getMapName(i) << endl; } break; } case CiftiMappingType::SERIES: { const CiftiSeriesMap& myMap = myXML.getSeriesMap(whichDim); cout << "Series, length " << myMap.getLength() << endl; cout << " Start: " << myMap.getStart() << endl; cout << " Step: " << myMap.getStep() << endl; cout << " Unit: " << CiftiSeriesMap::unitToString(myMap.getUnit()) << endl; break; } } cout << endl;//extra line break between dimensions } } catch (CaretException& e) { cerr << "Caught CaretException: " + e.whatString() << endl; return 1; } return 0; } connectome-workbench-1.4.2/src/CommandLine/000077500000000000000000000000001360521144700206105ustar00rootroot00000000000000connectome-workbench-1.4.2/src/CommandLine/CMakeLists.txt000066400000000000000000000057141360521144700233570ustar00rootroot00000000000000 # # Name of project # PROJECT (CommandLine) #cmake_policy(SET CMP0015 OLD) # # Add QT for includes # if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) # include_directories(${Qt5Network_INCLUDE_DIRS}) endif() IF (QT4_FOUND) SET(QT_USE_QTXML TRUE) SET(QT_USE_QTNETWORK TRUE) INCLUDE(${QT_USE_FILE}) ENDIF () # # Name of executable # set (EXE_NAME wb_command) # # Resources # SET (RESOURCES_QRC_FILE ../Resources/General/general_resources.qrc) IF (Qt5_FOUND) QT5_ADD_RESOURCES(IMAGE_RCS_SRCS ${RESOURCES_QRC_FILE}) ELSE (Qt5_FOUND) IF (QT4_FOUND) QT4_ADD_RESOURCES(IMAGE_RCS_SRCS ${RESOURCES_QRC_FILE}) ENDIF() ENDIF (Qt5_FOUND) # # Create the executable # Apple creates a bundle # IF (APPLE) ADD_EXECUTABLE(${EXE_NAME} MACOSX_BUNDLE wb_command.cxx ${IMAGE_RCS_SRCS} ) ELSE (APPLE) ADD_EXECUTABLE(${EXE_NAME} wb_command.cxx ${IMAGE_RCS_SRCS} ) ENDIF (APPLE) if(Qt5_FOUND) set(QT5_LINK_LIBS Qt5::Concurrent Qt5::Core Qt5::Gui Qt5::Network # Qt5::OpenGL # Qt5::PrintSupport Qt5::Test # Qt5::Widgets Qt5::Xml) endif() SET (MESA_OR_OPENGL_LIBRARIES "") IF (OSMESA_FOUND) SET(MESA_OR_OPENGL_LIBRARIES ${OSMESA_OFFSCREEN_LIBRARY} ${OSMESA_GL_LIBRARY} ${OSMESA_GLU_LIBRARY}) ELSE() IF (OPENGL_FOUND) SET(MESA_OR_OPENGL_LIBRARIES ${OPENGL_LIBRARIES}) ELSE() MESSAGE(SEND_ERROR "Must have either OpenGL or Mesa3D for command line") ENDIF() ENDIF() # # Libraries that are linked # Note: GLEW_LIBRARIES and OSMESA library variables will be empty and # have no effect if not available # TARGET_LINK_LIBRARIES(${EXE_NAME} Commands Operations Algorithms OperationsBase Brain Files Graphics ${FTGL_LIBRARIES} Annotations Palette Gifti Cifti Nifti Charting QxtCore FilesBase Scenes Xml Common ${QUAZIP_LIBRARIES} ${FREETYPE_LIBRARIES} ${QT_LIBRARIES} ${QT5_LINK_LIBS} ${GLEW_LIBRARIES} ${MESA_OR_OPENGL_LIBRARIES} ${ZLIB_LIBRARIES} ${LIBS}) INCLUDE(GNUInstallDirs) INSTALL(TARGETS ${EXE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) INSTALL(PROGRAMS wb_shortcuts DESTINATION ${CMAKE_INSTALL_BINDIR}) INSTALL(FILES bashcomplete_wb_command DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/bash-completion/completions RENAME wb_command) INSTALL(FILES bashcomplete_wb_shortcuts DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/bash-completion/completions RENAME wb_shortcuts) # # Find Headers # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/CommandLine ${CMAKE_SOURCE_DIR}/Commands ${CMAKE_SOURCE_DIR}/Operations ${CMAKE_SOURCE_DIR}/Algorithms ${CMAKE_SOURCE_DIR}/Annotations ${CMAKE_SOURCE_DIR}/OperationsBase ${CMAKE_SOURCE_DIR}/Brain ${CMAKE_SOURCE_DIR}/Charting ${CMAKE_SOURCE_DIR}/Palette ${CMAKE_SOURCE_DIR}/Files ${CMAKE_SOURCE_DIR}/Gifti ${CMAKE_SOURCE_DIR}/Cifti ${CMAKE_SOURCE_DIR}/Nifti ${CMAKE_SOURCE_DIR}/FilesBase ${CMAKE_SOURCE_DIR}/Scenes ${CMAKE_SOURCE_DIR}/Xml ${CMAKE_SOURCE_DIR}/Common ${QUAZIP_INCLUDE_DIRS} ) connectome-workbench-1.4.2/src/CommandLine/README.txt000066400000000000000000000003151360521144700223050ustar00rootroot00000000000000To add new commands, see the README.txt in Commands. For wb_shortcuts, note that its development does not take place in this repository, see https://github.com/Washington-University/wb_shortcuts instead. connectome-workbench-1.4.2/src/CommandLine/bashcomplete_wb_command000066400000000000000000000104361360521144700253730ustar00rootroot00000000000000# bash completion for wb_command # Copyright (C) 2016 Washington University School of Medicine # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #copy/symlink this file as /usr/share/bash-completion/completions/wb_command or copy contents to ~/.bash_completion function _wb_command() { #debug must be "false" or "true", because it *executes* it (because i'm lazy) local debug=false COMPREPLY=() #use bash-completion's hacks to deal with the word splitting we don't want local cur words cword #use only space for splitting _get_comp_words_by_ref -n "'"'"><=;|&(:' cur words cword #NOTE: cur has the partial word that is *before* the cursor, but words has the entire word under the cursor #wb_command doesn't need to know what the current partial word is, it spits out space-separated glob patterns and the like #but we will need it in compgen afterwards local wbopts="" if ! shopt -q extglob then #bash-completion enables extglob, but work around it if it isn't set wbopts="-noextglob" fi #only give wb_command the options coming *before* the one to complete, not even the partial word to complete #also don't include the executable name ${words[0]} $debug && echo $debug && echo "exe call: wb_command -completion $wbopts ${words[@]:1:$((cword - 1))}" local exereplyraw=`wb_command -completion $wbopts "${words[@]:1:$((cword - 1))}" 2> /dev/null` local exestatus=$? if [[ $exestatus != 0 ]] then return 1 fi $debug && echo "exereplayraw: $exereplyraw" #need to cause backslashes to escape spaces... local -a exereply IFS=' ' read -a exereply <<< "$exereplyraw" $debug && echo "exereply: ${exereply[@]}" for ((i = 0; i < ${#exereply[@]}; i += 2)) do $debug && echo "key: ${exereply[$i]}" $debug && echo "value: ${exereply[$((i + 1))]}" case "${exereply[$i]}" in fileglob) #bash_completion itself uses -f -X for file extension matching #using -G requires manually adding $cur before the pattern COMPREPLY+=(`compgen -o plusdirs -f -X "!${exereply[$((i + 1))]}" -- "$cur"`) ;; wordlist) #for the things accepted as bool, logging levels, maybe other uses COMPREPLY+=(`compgen -W "${exereply[$((i + 1))]}" -- "$cur"`) ;; esac done $debug && echo "COMPREPLY: ${COMPREPLY[@]}" return 0 } complete -o filenames -o bashdefault -o default -F _wb_command wb_command #completion for wb_shortcuts, for setups that just symlink this file as wb_shortcuts also function _wb_shortcuts () { COMPREPLY=() #use bash-completion's hacks to deal with the word splitting we don't want #we can only complete the first word, so only get cur and cword local cur cword #use only space for splitting _get_comp_words_by_ref -n "'"'"><=;|&(:' cur cword if ((cword != 1)) then return 0 fi local -a switches readarray -t switches < <(wb_shortcuts -list-functions | awk '{print $1}') local infoswitches=(-help -version -list-functions -all-functions-help) COMPREPLY=(`compgen -W "${switches[*]} ${infoswitches[*]}" -- "$cur"`) } complete -o filenames -o bashdefault -o default -F _wb_shortcuts wb_shortcuts connectome-workbench-1.4.2/src/CommandLine/bashcomplete_wb_shortcuts000066400000000000000000000036771360521144700260240ustar00rootroot00000000000000# bash completion for wb_command # Copyright (C) 2018 Washington University School of Medicine # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #copy/symlink this file as /usr/share/bash-completion/completions/wb_shortcuts, or copy contents to ~/.bash_completion function _wb_shortcuts () { COMPREPLY=() #use bash-completion's hacks to deal with the word splitting we don't want #we can only complete the first word, so only get cur and cword local cur cword #use only space for splitting _get_comp_words_by_ref -n "'"'"><=;|&(:' cur cword if ((cword != 1)) then return 0 fi local -a switches readarray -t switches < <(wb_shortcuts -list-functions | awk '{print $1}') local infoswitches=(-help -version -list-functions -all-functions-help) COMPREPLY=(`compgen -W "${switches[*]} ${infoswitches[*]}" -- "$cur"`) } complete -o filenames -o bashdefault -o default -F _wb_shortcuts wb_shortcuts connectome-workbench-1.4.2/src/CommandLine/wb_command.cxx000066400000000000000000000137051360521144700234500ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ //#include #include #include #include #include "AString.h" #include "CaretAssert.h" #include "CaretHttpManager.h" #include "CaretCommandLine.h" #include "CaretLogger.h" #include "CommandOperationManager.h" #include "ProgramParameters.h" #include "SessionManager.h" #include "SystemUtilities.h" #include "VolumeFile.h" using namespace caret; using namespace std; static int runCommand(int argc, char* argv[]) { ProgramParameters parameters(argc, argv); caret_global_commandLine_init(parameters); /* * Log the command parameters. */ CaretLogFine("Running: " + caret_global_commandLine); CommandOperationManager* commandManager = NULL; int ret = 0; try { commandManager = CommandOperationManager::getCommandOperationManager(); commandManager->runCommand(parameters); } catch (CaretException& e) { cerr << "\nWhile running:\n" << caret_global_commandLine.toLocal8Bit().constData() << "\n\nERROR: " << e.whatString().toLocal8Bit().constData() << endl << endl; ret = -1; } catch (bad_alloc& e) {//if we stop using a handler for new cerr << "\nWhile running:\n" << caret_global_commandLine.toLocal8Bit().constData() << "\n\nERROR: " << e.what() << endl; cerr << endl << "OUT OF MEMORY" << endl << endl << "This means that Workbench is unable to get memory that it needs." << endl << "Possible causes:" << endl << " (1) Your computer lacks sufficient RAM." << endl << " (2) Swap space is too small (you might increase it)." << endl << " (3) Your computer may be using an non-English character" << endl//is this relevant? << " set. Try switching to the English character set." << endl << endl; ret = -1; } catch (exception& e) { cerr << "\nWhile running:\n" << caret_global_commandLine.toLocal8Bit().constData() << "\n\nERROR: " << e.what() << endl << endl; ret = -1; } catch (...) { cerr << "\nWhile running:\n" << caret_global_commandLine.toLocal8Bit().constData() << "\n\nERROR: caught unknown exception type, rethrowing..." << endl << endl; if (commandManager != NULL) { CommandOperationManager::deleteCommandOperationManager(); } throw;//rethrow, the runtime might print the type } if (commandManager != NULL) { CommandOperationManager::deleteCommandOperationManager(); } return ret; } static int doCompletion(int argc, char* argv[]) { //we don't handle any interactive arguments in this file (only completion related arguments, which should never be used interactively) //so, just call completion on next level ProgramParameters parameters(argc, argv); caret_global_commandLine_init(parameters); try { parameters.nextString("-completion");//drop the completion switch bool useExtGlob = true;//bash-completion turns on extglob by default, so it is usually safe if (parameters.hasNext()) { if (parameters.nextString("test for option") == "-noextglob") { useExtGlob = false; } else { parameters.backup(); } } CommandOperationManager* commandManager = CommandOperationManager::getCommandOperationManager(); AString compHints = commandManager->doCompletion(parameters, useExtGlob); cout << compHints.toLocal8Bit().constData() << endl; } catch (...) { return 1; } return 0; } int main(int argc, char* argv[]) { srand(time(NULL)); //short-circuit to avoid things like palette initialization so that command line completion can be more responsive //also should be easier to avoid various logging statements, which we don't want (stderr would destroy the current prompt, and stdout would interfere with the completion output) if (argc > 1 && AString::fromLocal8Bit(argv[1]) == "-completion") { return doCompletion(argc, argv); } int result = 0; { /* * Handle uncaught exceptions */ SystemUtilities::setUnexpectedHandler(); /* * Create the session manager. */ SessionManager::createSessionManager(ApplicationTypeEnum::APPLICATION_TYPE_COMMAND_LINE); /* * Disable volume voxel coloring since it can be a little slow * and voxel coloring is not needed for any commands (at this * time). */ VolumeFile::setVoxelColoringEnabled(false); QCoreApplication myApp(argc, argv);//so that it doesn't need to link against gui result = runCommand(argc, argv); /* * Delete the session manager. */ SessionManager::deleteSessionManager(); CaretHttpManager::deleteHttpManager();//does this belong in some other singleton manager? myApp.processEvents();//since we don't exec(), let it clean up any ->deleteLater()s } /* * See if any objects were not deleted. */ CaretObject::printListOfObjectsNotDeleted(true); return result; } connectome-workbench-1.4.2/src/CommandLine/wb_shortcuts000077500000000000000000001223621360521144700232720ustar00rootroot00000000000000#!/bin/bash # Copyright (C) 2018 Washington University School of Medicine # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. set -ue global_cmd_line="$0 $*" global_script_name="wb_shortcuts" global_script_version="beta-0.5" function version () { echo "$global_script_name, version $global_script_version" } function usage () { version echo echo "Information options:" echo " -help display this help info" echo " -version display version info" echo " -list-functions show available functions" echo " -all-functions-help show all functions and their help info - VERY LONG" echo #wrap guide for 80 columns | echo "To get the help information of a function, run it without any additional" echo " arguments." echo echo "If the first argument is not recognized, all functions that start with the" echo " argument are displayed." echo } #the main function is so that we can put the main code before other function definitions #it simply gets called as 'main "$@"' after all functions are defined function main () { #NOTE: if we have a lot of functions, check_functions could cause a short startup delay, could make a debug setting to control it check_functions if (($# < 1)) then usage exit 0 fi case "$1" in (-version) version ;; (-help) usage ;; (-list-functions) list_functions ;; (-all-functions-help) all_functions_help ;; (*) #magic switch matching and function name conversion happens in here do_operation "$@" ;; esac } #automagic helpers for function matching #NOTE: mac still ships with a version of bash from 2007(!) #so, don't use associative arrays or anything fancy declare -a global_switch declare -a global_descrip function create_function () { local function_switch="$1" shift if [[ "$function_switch" == *' '* ]] then echo "ASSERT FAILURE: switch '$function_switch' contains space(s)" exit 1 fi if [[ "$function_switch" != "-"* ]] then echo "ASSERT FAILURE: switch '$function_switch' has no leading dash" exit 1 fi if [[ "$*" == "" ]] then echo "ASSERT FAILURE: switch '$function_switch' has empty short description" exit 1 fi #use $* in case they didn't quote the short description global_switch+=("$function_switch") global_descrip+=("$*") } function switch_to_func_name () { printf '%s' "$1" | sed 's/^-//' | sed 's/-/_/g' } #ADDING FUNCTIONS: #the function to call is automatically generated from the command switch (see above functions) #the function MUST follow the same naming convention #you can add names of temporary files before they are created by any command, to ensure that no extra files get left behind on failure #if the temporaries could be large, feel free to both add them to the list, and delete them manually create_function "-border-file-concatenate" "MERGE BORDER FILES" function border_file_concatenate () { local function_switch="$1" shift if (($# < 1)) then echo "`switch_to_descrip $function_switch`" echo " $global_script_name $function_switch" echo " " echo " | -from-file [-big-text] " echo " ..." echo #wrap guide for 80 columns | echo " Additional input files may be specified after the mandatory input file." echo echo " Any input argument can be replaced with a -from-file option followed by a" echo " text file. Each text file must have one data file per line. The" echo " -big-text option allows the use of very large text files (>1MB). This" echo " is otherwise considered an error, in order to prevent accidentally" echo " loading a data file into shell memory as a text file." echo return 0 fi if (($# < 2)) then error "function requires 2 or more arguments" fi local -a merge_arg_array for ((i = 2; i <= $#; ++i)) do if [[ "${!i}" == -* ]] then case "${!i}" in (-from-file) i=$((i + 1)) if ((i > $#)) then error "-from-file option requires an argument" fi local checksize=1 if [[ "${!i}" == -big-text ]] then checksize=0 i=$((i + 1)) fi local filename="${!i}" local nexti=$((i + 1)) #allow the option after the filename, too, because that is the easy place to put it if ((nexti <= $#)) && [[ "${!nexti}" == -big-text ]] then checksize=0 i=$((i + 1)) fi if ((checksize == 1)) then local filesize=`wc -c "$filename" | cut -d' ' -f1` if ((filesize > 1000000)) then error "file '${filename}' seems too large to be a text file" fi fi local -a filecontents readarray -t filecontents < "$filename" for ((j = 0; j < ${#filecontents[@]}; ++j)) do #ignore empty lines if [[ "${filecontents[$j]}" != "" ]] then merge_arg_array+=("-border" "${filecontents[$j]}") fi done ;; (*) error "unrecognized option '${!i}'" ;; esac else merge_arg_array+=("-border" "${!i}") fi done wb_command -border-merge "$1" "${merge_arg_array[@]}" } create_function "-cifti-concatenate" "MERGE MAPS OF CIFTI FILES" function cifti_concatenate () { local function_switch="$1" shift if (($# < 1)) then echo "`switch_to_descrip $function_switch`" echo " $global_script_name $function_switch" echo " [-map ] - use only the specified map from each input" echo " file" echo " " echo " | -from-file [-big-text] " echo " ..." echo #wrap guide for 80 columns | echo " Additional input files may be specified after the mandatory input file." echo echo " Any input argument can be replaced with a -from-file option followed by a" echo " text file. Each text file must have one data file per line. The" echo " -big-text option allows the use of very large text files (>1MB). This" echo " is otherwise considered an error, in order to prevent accidentally" echo " loading a data file into shell memory as a text file." echo echo " The -map option takes either a 1-based" echo " index or a map name, and causes the" echo " operation to use only one map from each input file." echo return 0 fi local -a maparg if [[ "$1" == "-map" ]] then if (($# < 2)) then error "-map option requires an argument" fi maparg=("-column" "$2") shift 2 fi if (($# < 2)) then error "function requires 2 or more arguments" fi local -a merge_arg_array for ((i = 2; i <= $#; ++i)) do if [[ "${!i}" == -* ]] then case "${!i}" in (-from-file) i=$((i + 1)) if ((i > $#)) then error "-from-file option requires an argument" fi local checksize=1 if [[ "${!i}" == -big-text ]] then checksize=0 i=$((i + 1)) fi local filename="${!i}" local nexti=$((i + 1)) #allow the option after the filename, too, because that is the easy place to put it if ((nexti <= $#)) && [[ "${!nexti}" == -big-text ]] then checksize=0 i=$((i + 1)) fi if ((checksize == 1)) then local filesize=`wc -c "$filename" | cut -d' ' -f1` if ((filesize > 1000000)) then error "file '${filename}' seems too large to be a text file" fi fi local -a filecontents readarray -t filecontents < "$filename" for ((j = 0; j < ${#filecontents[@]}; ++j)) do #ignore empty lines if [[ "${filecontents[$j]}" != "" ]] then merge_arg_array+=("-cifti" "${filecontents[$j]}" ${maparg[@]+"${maparg[@]}"}) fi done ;; (*) error "unrecognized option '${!i}'" ;; esac else #we INTENTIONALLY expand an empty array to 0 elements, but set -u doesn't like this, and there is no simple syntax to tell it to allow it #so, use complicated syntax to tell it to allow it #this syntax is apparently UNDOCUMENTED, but it came from stackoverflow, and it works, so it must be right #http://stackoverflow.com/questions/7577052/bash-empty-array-expansion-with-set-u merge_arg_array+=("-cifti" "${!i}" ${maparg[@]+"${maparg[@]}"}) fi done wb_command -cifti-merge "$1" "${merge_arg_array[@]}" } create_function "-cifti-demean" "DEMEAN/NORMALIZE AND CONCATENATE" function cifti_demean () { local function_switch="$1" shift if (($# < 1)) then echo "`switch_to_descrip $function_switch`" echo " $global_script_name $function_switch" echo " [-normalize] - also normalize input files" echo " " echo " " echo " ..." echo #wrap guide for 80 columns | echo " Demeans each input file (optionally normalizes by stdev) and then" echo " concatenates them. Additional input files may be specified after the" echo " mandatory input file." echo return 0 fi local normalize=0 if [[ "$1" == "-normalize" ]] then normalize=1 shift fi if (($# < 2)) then error "function requires 2 or more arguments" fi local tempext=$(echo "$1" | cut -f2- -d.) local -a merge_arg_array for ((i = 2; i <= $#; ++i)) do local tempext2=$(echo "${!i}" | cut -f2- -d.) #we might not make the stdev temporary, but it isn't a problem to add it anyway add_temporary_files "$1.temp${i}-mean-$$.dscalar.nii" "$1.temp${i}-normed-$$.$tempext2" "$1.temp${i}-stdev-$$.dscalar.nii" wb_command -cifti-reduce "${!i}" MEAN "$1.temp${i}-mean-$$.dscalar.nii" if [[ $normalize == 1 ]] then wb_command -cifti-reduce "${!i}" SAMPSTDEV "$1.temp${i}-stdev-$$.dscalar.nii" wb_command -cifti-math '(x - mean) / stdev' "$1.temp${i}-normed-$$.$tempext2" -fixnan 0 \ -var x "${!i}" \ -var mean "$1.temp${i}-mean-$$.dscalar.nii" -select 1 1 -repeat \ -var stdev "$1.temp${i}-stdev-$$.dscalar.nii" -select 1 1 -repeat rm -f "$1.temp${i}-mean-$$.dscalar.nii" "$1.temp${i}-stdev-$$.dscalar.nii" else wb_command -cifti-math 'x - mean' "$1.temp${i}-normed-$$.$tempext2" -fixnan 0 \ -var x "${!i}" \ -var mean "$1.temp${i}-mean-$$.dscalar.nii" -select 1 1 -repeat rm -f "$1.temp${i}-mean-$$.dscalar.nii" fi merge_arg_array+=("-cifti" "$1.temp${i}-normed-$$.$tempext2") done wb_command -cifti-merge "$1" "${merge_arg_array[@]}" #let the exit hook clean up the normed temporaries, we're done } create_function "-cifti-dlabel-split-cortex" "SEPARATE SURFACE LABELS INTO LEFT/RIGHT" function cifti_dlabel_split_cortex () { local function_switch="$1" shift if (($# < 1)) then echo "`switch_to_descrip $function_switch`" echo " $global_script_name $function_switch" echo " - input dlabel file" echo " - output - output dlabel file" echo #wrap guide for 80 columns | echo " For every label represented on left or right cortex, rename it with a" echo " prefix of 'L_' or 'R_', and change the label values as needed to keep" echo " the new names separate." echo return 0 fi if (($# != 2)) then error "function requires 2 arguments, $# provided" fi #to prevent it from also changing label keys in a multi-map dlabel (because gifti doesn't support label tables per-map), #we need to loop through the columns local i num_maps=`wb_command -file-information -only-number-of-maps "$1"` local -a mergeargs for ((i = 1; i <= num_maps; ++i)) do add_temporary_files "$2".temp$i.dlabel.nii "$2".temp$i.L.label.gii "$2".temp$i.R.label.gii "$2".temp$i.nii.gz add_temporary_files "$2".temp$i.L.txt "$2".temp$i.R.txt "$2".temp$i.vol.txt wb_command -cifti-merge "$2".temp$i.dlabel.nii -cifti "$1" -column $i wb_command -cifti-separate "$2".temp$i.dlabel.nii COLUMN -label CORTEX_LEFT "$2".temp$i.L.label.gii -label CORTEX_RIGHT "$2".temp$i.R.label.gii -volume-all "$2".temp$i.nii.gz -crop #these are temporary files and will be deleted regardless, go ahead and overwrite them #LEFT wb_command -gifti-label-add-prefix "$2".temp$i.L.label.gii L_ "$2".temp$i.L.label.gii #need to remove the unused ones from the table so we don't get stupid overlaps wb_command -label-export-table "$2".temp$i.L.label.gii "$2".temp$i.L.txt #mute the warning from loading a label as a metric wb_command -metric-label-import "$2".temp$i.L.label.gii \ "$2".temp$i.L.txt \ "$2".temp$i.L.label.gii \ -drop-unused-labels 2> /dev/null #RIGHT wb_command -gifti-label-add-prefix "$2".temp$i.R.label.gii R_ "$2".temp$i.R.label.gii #need to remove the unused ones from the table so we don't get stupid overlaps wb_command -label-export-table "$2".temp$i.R.label.gii "$2".temp$i.R.txt #mute the warning from loading a label as a metric wb_command -metric-label-import "$2".temp$i.R.label.gii \ "$2".temp$i.R.txt \ "$2".temp$i.R.label.gii \ -drop-unused-labels 2> /dev/null #VOLUME #need to also remove unused labels from this, too wb_command -volume-label-export-table "$2".temp$i.nii.gz 1 "$2".temp$i.vol.txt #no warning to mute wb_command -volume-label-import "$2".temp$i.nii.gz \ "$2".temp$i.vol.txt \ "$2".temp$i.nii.gz \ -drop-unused-labels wb_command -cifti-create-dense-from-template "$2".temp$i.dlabel.nii "$2".temp$i.dlabel.nii -label CORTEX_LEFT "$2".temp$i.L.label.gii -label CORTEX_RIGHT "$2".temp$i.R.label.gii -volume-all "$2".temp$i.nii.gz -from-cropped rm -f "$2".temp$i.L.label.gii "$2".temp$i.R.label.gii "$2".temp$i.nii.gz rm -f "$2".temp$i.L.txt "$2".temp$i.R.txt "$2".temp$i.vol.txt mergeargs+=(-cifti "$2".temp$i.dlabel.nii) done wb_command -cifti-merge "$2" "${mergeargs[@]}" #let the cleanup function remove the intermediate cifti files } create_function "-command-help-search" "SEARCH WB_COMMAND HELP" function command_help_search () { local function_switch="$1" shift if (($# < 1)) then echo "`switch_to_descrip $function_switch`" echo " $global_script_name $function_switch" echo " [-also-deprecated] - also search deprecated commands" echo " - grep pattern to search for" echo #wrap guide for 80 columns | echo " Searches for wb_command processing commands that contain the pattern." echo return 0 fi local -a switches readarray -t switches < <(wb_command -list-commands | awk '{print $1}') if [[ "$1" == "-also-deprecated" ]] then shift local -a depswitches readarray -t depswitches < <(wb_command -list-deprecated-commands | awk '{print $1}') switches+=("${depswitches[@]}") fi #we could add a -- option to denote end of options, but then it would be harder to search for -- rather than for an option if (($# < 1)) then error "function requires an argument" fi #requiring quotes when searching for a phrase is slightly inconvenient #on the other hand, a phrase could get split across lines, so that is error prone anyway #if (($# != 1)) #then # warning "more than one argument provided, check for unquoted spaces and spelling of options" #fi local i for ((i = 0; i < ${#switches[@]}; ++i)) do #use $* in case someone didn't quote, but keep it all in the pattern argument local matches=`wb_command "${switches[$i]}" | grep -i -e "$*"` if [[ "$matches" != "" ]] then printf '%s\n' "${switches[$i]}:" printf '%s\n\n' "$matches" fi done } create_function "-freesurfer-resample-prep" "CREATE MIDTHICKNESSES FROM FREESURFER" function freesurfer_resample_prep () { local function_switch="$1" shift if (($# < 1)) then echo "`switch_to_descrip $function_switch`" echo " $global_script_name $function_switch" echo " - the freesurfer white surface" echo " - the freesurfer pial surface" echo " " echo " " echo " - output - the midthickness on the current" echo " freesurfer mesh, in gifti format" echo " - output - likewise, on the new mesh" echo " - output - the freesurfer sphere converted to" echo " gifti, must end in '.surf.gii'" echo #wrap guide for 80 columns | echo " NOTE: freesurfer's mris_convert must be installed and in the \$PATH in" echo " order to use this function, for converting the surfaces to GIFTI format." echo echo " Generate the various surface files used for resampling individual data" echo " from FreeSurfer to fs_LR. This generates the gifti-format sphere, and" echo " both midthickness surfaces needed by the -area-surfs option of wb_command" echo " -metric-resample, -label-resample, and similar commands." echo return 0 fi if (($# != 7)) then error "function requires 7 arguments, $# provided" fi if [[ "$7" != *.surf.gii ]] then error " filename must end in '.surf.gii'" fi add_temporary_files "$5.temp$$.white.surf.gii" "$5.temp$$.pial.surf.gii" if [[ "$5" == */* ]] then #if output name includes a path (even relative), then we don't need to futz with it to prevent freesurfer from dumping the converted file in the INPUT file's directory mris_convert "$1" "$5.temp$$.white.surf.gii" mris_convert "$2" "$5.temp$$.pial.surf.gii" else #if you give freesurfer a bare filename with no path for output, it dumps it in the input directory, regardless of cwd #so, put ./ on the beginning to tell it to mend its ways mris_convert "$1" ./"$5.temp$$.white.surf.gii" mris_convert "$2" ./"$5.temp$$.pial.surf.gii" fi mris_convert "$3" "$7" wb_command -surface-average "$5" -surf "$5.temp$$.white.surf.gii" -surf "$5.temp$$.pial.surf.gii" rm -f "$5.temp$$.white.surf.gii" "$5.temp$$.pial.surf.gii" wb_command -surface-resample "$5" "$7" "$4" BARYCENTRIC "$6" } create_function "-import-probtrack-roi" "CONVERT ROI TRACKS TO CIFTI" function import_probtrack_roi () { local function_switch="$1" shift if (($# < 1)) then echo "`switch_to_descrip $function_switch`" echo " $global_script_name $function_switch" echo " - the text file from probtrackx2" echo " - the ROI used as the seed mask, as cifti" echo " - output - the data converted to cifti dscalar" echo #wrap guide for 80 columns | echo " The file should contain the ROI used as the mask, and should" echo " be in the desired brainordinate space." echo return 0 fi if (($# != 3)) then error "function requires 3 arguments, $# provided" fi local tempext=$(echo "$2" | cut -f2- -d.) #make temporaries based on the output file name add_temporary_files "$3.temp1-$$.$tempext" "$3.temp2-$$.dscalar.nii" wb_command -cifti-restrict-dense-map "$2" COLUMN "$3.temp1-$$.$tempext" -cifti-roi "$2" wb_command -cifti-convert -from-text "$1" "$3.temp1-$$.$tempext" "$3.temp2-$$.dscalar.nii" -reset-scalars rm -f "$3.temp1-$$.$tempext" wb_command -cifti-create-dense-from-template "$2" "$3" -cifti "$3.temp2-$$.dscalar.nii" rm -f "$3.temp2-$$.dscalar.nii" } create_function "-label-concatenate" "MERGE MAPS OF LABEL FILES" function label_concatenate () { local function_switch="$1" shift if (($# < 1)) then echo "`switch_to_descrip $function_switch`" echo " $global_script_name $function_switch" echo " [-map ] - use only the specified map from each input" echo " file" echo " " echo " | -from-file [-big-text] " echo " ..." echo #wrap guide for 80 columns | echo " Additional input files may be specified after the mandatory input file." echo echo " Any input argument can be replaced with a -from-file option followed by a" echo " text file. Each text file must have one data file per line. The" echo " -big-text option allows the use of very large text files (>1MB). This" echo " is otherwise considered an error, in order to prevent accidentally" echo " loading a data file into shell memory as a text file." echo echo " The -map option takes either a 1-based" echo " index or a map name, and causes the" echo " operation to use only one map from each input file." echo return 0 fi local -a maparg if [[ "$1" == "-map" ]] then if (($# < 2)) then error "-map option requires an argument" fi maparg=("-column" "$2") shift 2 fi if (($# < 2)) then error "function requires 2 or more arguments" fi local -a merge_arg_array local i for ((i = 2; i <= $#; ++i)) do if [[ "${!i}" == -* ]] then case "${!i}" in (-from-file) i=$((i + 1)) if ((i > $#)) then error "-from-file option requires an argument" fi local checksize=1 if [[ "${!i}" == -big-text ]] then checksize=0 i=$((i + 1)) fi local filename="${!i}" local nexti=$((i + 1)) #allow the option after the filename, too, because that is the easy place to put it if ((nexti <= $#)) && [[ "${!nexti}" == -big-text ]] then checksize=0 i=$((i + 1)) fi if ((checksize == 1)) then local filesize=`wc -c "$filename" | cut -d' ' -f1` if ((filesize > 1000000)) then error "file '${filename}' seems too large to be a text file" fi fi local -a filecontents readarray -t filecontents < "$filename" for ((j = 0; j < ${#filecontents[@]}; ++j)) do #ignore empty lines if [[ "${filecontents[$j]}" != "" ]] then merge_arg_array+=("-label" "${filecontents[$j]}" ${maparg[@]+"${maparg[@]}"}) fi done ;; (*) error "unrecognized option '${!i}'" ;; esac else merge_arg_array+=("-label" "${!i}" ${maparg[@]+"${maparg[@]}"}) fi done wb_command -label-merge "$1" "${merge_arg_array[@]}" } create_function "-metric-concatenate" "MERGE MAPS OF METRIC FILES" function metric_concatenate () { local function_switch="$1" shift if (($# < 1)) then echo "`switch_to_descrip $function_switch`" echo " $global_script_name $function_switch" echo " [-map ] - use only the specified map from each input" echo " file" echo " " echo " | -from-file [-big-text] " echo " ..." echo #wrap guide for 80 columns | echo " Additional input files may be specified after the mandatory input file." echo echo " Any input argument can be replaced with a -from-file option followed by a" echo " text file. Each text file must have one data file per line. The" echo " -big-text option allows the use of very large text files (>1MB). This" echo " is otherwise considered an error, in order to prevent accidentally" echo " loading a data file into shell memory as a text file." echo echo " The -map option takes either a 1-based" echo " index or a map name, and causes the" echo " operation to use only one map from each input file." echo return 0 fi local -a maparg if [[ "$1" == "-map" ]] then if (($# < 2)) then error "-map option requires an argument" fi maparg=("-column" "$2") shift 2 fi if (($# < 2)) then error "function requires 2 or more arguments" fi local -a merge_arg_array local i for ((i = 2; i <= $#; ++i)) do if [[ "${!i}" == -* ]] then case "${!i}" in (-from-file) i=$((i + 1)) if ((i > $#)) then error "-from-file option requires an argument" fi local checksize=1 if [[ "${!i}" == -big-text ]] then checksize=0 i=$((i + 1)) fi local filename="${!i}" local nexti=$((i + 1)) #allow the option after the filename, too, because that is the easy place to put it if ((nexti <= $#)) && [[ "${!nexti}" == -big-text ]] then checksize=0 i=$((i + 1)) fi if ((checksize == 1)) then local filesize=`wc -c "$filename" | cut -d' ' -f1` if ((filesize > 1000000)) then error "file '${filename}' seems too large to be a text file" fi fi local -a filecontents readarray -t filecontents < "$filename" for ((j = 0; j < ${#filecontents[@]}; ++j)) do #ignore empty lines if [[ "${filecontents[$j]}" != "" ]] then merge_arg_array+=("-metric" "${filecontents[$j]}" ${maparg[@]+"${maparg[@]}"}) fi done ;; (*) error "unrecognized option '${!i}'" ;; esac else merge_arg_array+=("-metric" "${!i}" ${maparg[@]+"${maparg[@]}"}) fi done wb_command -metric-merge "$1" "${merge_arg_array[@]}" } create_function "-scene-file-concatenate" "MERGE SCENES OF SCENE FILES" function scene_file_concatenate () { local function_switch="$1" shift if (($# < 1)) then echo "`switch_to_descrip $function_switch`" echo " $global_script_name $function_switch" echo " " echo " | -from-file [-big-text] " echo " ..." echo #wrap guide for 80 columns | echo " Additional input files may be specified after the mandatory input file." echo echo " Any input argument can be replaced with a -from-file option followed by a" echo " text file. Each text file must have one data file per line. The" echo " -big-text option allows the use of very large text files (>1MB). This" echo " is otherwise considered an error, in order to prevent accidentally" echo " loading a data file into shell memory as a text file." echo return 0 fi if (($# < 2)) then error "function requires 2 or more arguments" fi local -a merge_arg_array local i for ((i = 2; i <= $#; ++i)) do if [[ "${!i}" == -* ]] then case "${!i}" in (-from-file) i=$((i + 1)) if ((i > $#)) then error "-from-file option requires an argument" fi local checksize=1 if [[ "${!i}" == -big-text ]] then checksize=0 i=$((i + 1)) fi local filename="${!i}" local nexti=$((i + 1)) #allow the option after the filename, too, because that is the easy place to put it if ((nexti <= $#)) && [[ "${!nexti}" == -big-text ]] then checksize=0 i=$((i + 1)) fi if ((checksize == 1)) then local filesize=`wc -c "$filename" | cut -d' ' -f1` if ((filesize > 1000000)) then error "file '${filename}' seems too large to be a text file" fi fi local -a filecontents readarray -t filecontents < "$filename" for ((j = 0; j < ${#filecontents[@]}; ++j)) do #ignore empty lines if [[ "${filecontents[$j]}" != "" ]] then merge_arg_array+=("-scene-file" "${filecontents[$j]}") fi done ;; (*) error "unrecognized option '${!i}'" ;; esac else merge_arg_array+=("-scene-file" "${!i}") fi done wb_command -scene-file-merge "$1" "${merge_arg_array[@]}" } create_function "-volume-concatenate" "MERGE MAPS OF VOLUME FILES" function volume_concatenate () { local function_switch="$1" shift if (($# < 1)) then echo "`switch_to_descrip $function_switch`" echo " $global_script_name $function_switch" echo " [-map ] - use only the specified map from each input" echo " file" echo " " echo " | -from-file [-big-text] " echo " ..." echo #wrap guide for 80 columns | echo " Additional input files may be specified after the mandatory input file." echo echo " Any input argument can be replaced with a -from-file option followed by a" echo " text file. Each text file must have one data file per line. The" echo " -big-text option allows the use of very large text files (>1MB). This" echo " is otherwise considered an error, in order to prevent accidentally" echo " loading a data file into shell memory as a text file." echo echo " The -map option takes either a 1-based" echo " index or a map name, and causes the" echo " operation to use only one map from each input file." echo return 0 fi local -a maparg if [[ "$1" == "-map" ]] then if (($# < 2)) then error "-map option requires an argument" fi maparg=("-subvolume" "$2") shift 2 fi if (($# < 2)) then error "function requires 2 or more arguments" fi local -a merge_arg_array local i for ((i = 2; i <= $#; ++i)) do if [[ "${!i}" == -* ]] then case "${!i}" in (-from-file) i=$((i + 1)) if ((i > $#)) then error "-from-file option requires an argument" fi local checksize=1 if [[ "${!i}" == -big-text ]] then checksize=0 i=$((i + 1)) fi local filename="${!i}" local nexti=$((i + 1)) #allow the option after the filename, too, because that is the easy place to put it if ((nexti <= $#)) && [[ "${!nexti}" == -big-text ]] then checksize=0 i=$((i + 1)) fi if ((checksize == 1)) then local filesize=`wc -c "$filename" | cut -d' ' -f1` if ((filesize > 1000000)) then error "file '${filename}' seems too large to be a text file" fi fi local -a filecontents readarray -t filecontents < "$filename" for ((j = 0; j < ${#filecontents[@]}; ++j)) do #ignore empty lines if [[ "${filecontents[$j]}" != "" ]] then merge_arg_array+=("-volume" "${filecontents[$j]}" ${maparg[@]+"${maparg[@]}"}) fi done ;; (*) error "unrecognized option '${!i}'" ;; esac else merge_arg_array+=("-volume" "${!i}" ${maparg[@]+"${maparg[@]}"}) fi done wb_command -volume-merge "$1" "${merge_arg_array[@]}" } #additional helper functions function do_operation () { #use the existence of a short description to denote existence of the function local i for ((i = 0; i < ${#global_switch[@]}; ++i)) do if [[ "${global_switch[$i]}" == "$1" ]] then `switch_to_func_name "$1"` "$@" return $? fi done local maxlength=0 for ((i = 0; i < ${#global_switch[@]}; ++i)) do if [[ "${global_switch[$i]}" == "$1"* ]] then local thislength=`printf '%s' "${global_switch[$i]}" | wc -c` if (( thislength > maxlength )) then maxlength=$thislength fi fi done if (( maxlength == 0 )) then error "the switch '$1' does not match any functions" fi for ((i = 0; i < ${#global_switch[@]}; ++i)) do if [[ "${global_switch[$i]}" == "$1"* ]] then printf "%-${maxlength}s %s\n" "${global_switch[$i]}" "${global_descrip[$i]}" fi done | sort } function switch_to_descrip () { #because we aren't using associative arrays, because mac's ancient bash local i for ((i = 0; i < ${#global_switch[@]}; ++i)) do if [[ "${global_switch[$i]}" == "$1" ]] then printf '%s' "${global_descrip[$i]}" return 0 fi done return 1 } function list_functions () { local i maxlength=0 for ((i = 0; i < ${#global_switch[@]}; ++i)) do local thislength=`printf '%s' "${global_switch[$i]}" | wc -c` if (( thislength > maxlength )) then maxlength=$thislength fi done for ((i = 0; i < ${#global_switch[@]}; ++i)) do printf "%-${maxlength}s %s\n" "${global_switch[$i]}" "${global_descrip[$i]}" done | sort } function all_functions_help () { #assume that the commands all print their help info when given no additional arguments besides the command switch itself local i for ((i = 0; i < ${#global_switch[@]}; ++i)) do `switch_to_func_name "${global_switch[$i]}"` "${global_switch[$i]}" done } function error () { echo >&2 echo "While running:" echo "$global_cmd_line" >&2 echo >&2 echo "Error: $*" >&2 echo >&2 exit 1 } function warning () { echo >&2 echo "Warning: $*" >&2 echo >&2 } function check_functions () { local i for ((i = 0; i < ${#global_switch[@]}; ++i)) do local function_name=`switch_to_func_name "${global_switch[$i]}"` if [[ `type -t "$function_name"` != 'function' ]] then echo "ASSERT FAILURE: switch '${global_switch[$i]}' does not have matching function '$function_name'" exit 1 fi done } global_temporary_files=() function add_temporary_files () { global_temporary_files+=("$@") } function cleanup () { #unset variable gets tripped by @ expansion on empty array #so first test if the array is empty if ((${#global_temporary_files[@]} > 0)) then rm -f -- "${global_temporary_files[@]}" &> /dev/null fi } trap cleanup EXIT #start the main code, now that all the functions are defined main "$@" connectome-workbench-1.4.2/src/Commands/000077500000000000000000000000001360521144700201635ustar00rootroot00000000000000connectome-workbench-1.4.2/src/Commands/CMakeLists.txt000066400000000000000000000026061360521144700227270ustar00rootroot00000000000000# # Name of project # PROJECT (Commands) # # Need XML from Qt # SET(QT_DONT_USE_QTGUI) # # Add QT for includes # if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () # # Create the brain library # ADD_LIBRARY(Commands CommandClassAddMember.h CommandClassCreate.h CommandClassCreateAlgorithm.h CommandClassCreateBase.h CommandClassCreateEnum.h CommandClassCreateOperation.h CommandC11xTesting.h CommandException.h CommandOperation.h CommandOperationManager.h CommandParser.h CommandUnitTest.h CommandClassAddMember.cxx CommandClassCreate.cxx CommandClassCreateAlgorithm.cxx CommandClassCreateBase.cxx CommandClassCreateEnum.cxx CommandClassCreateOperation.cxx CommandC11xTesting.cxx CommandException.cxx CommandOperation.cxx CommandOperationManager.cxx CommandParser.cxx CommandUnitTest.cxx ) TARGET_LINK_LIBRARIES(Commands ${CARET_QT5_LINK}) # # Find Headers # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Commands ${CMAKE_SOURCE_DIR}/Algorithms ${CMAKE_SOURCE_DIR}/Annotations ${CMAKE_SOURCE_DIR}/Charting ${CMAKE_SOURCE_DIR}/Operations ${CMAKE_SOURCE_DIR}/OperationsBase ${CMAKE_SOURCE_DIR}/Brain ${CMAKE_SOURCE_DIR}/FilesBase ${CMAKE_SOURCE_DIR}/Files ${CMAKE_SOURCE_DIR}/Gifti ${CMAKE_SOURCE_DIR}/Cifti ${CMAKE_SOURCE_DIR}/Palette ${CMAKE_SOURCE_DIR}/Nifti ${CMAKE_SOURCE_DIR}/Scenes ${CMAKE_SOURCE_DIR}/Xml ${CMAKE_SOURCE_DIR}/Common ) connectome-workbench-1.4.2/src/Commands/CommandC11xTesting.cxx000066400000000000000000000104611360521144700242620ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include // Not on Intel #include #include #include "CaretAssert.h" #include "CommandC11xTesting.h" #include "ProgramParameters.h" using namespace caret; /** * Constructor. */ CommandC11xTesting::CommandC11xTesting() : CommandOperation("-c11x-test", "C11X Compiler Compatibility Testing") { } /** * Destructor. */ CommandC11xTesting::~CommandC11xTesting() { } AString CommandC11xTesting::getHelpInformation(const AString& /*programName*/) { AString helpInfo = ("\n" "Test for C11x support in compilers.\n" "\n" "Usage: \n" " \n" ); return helpInfo; } /** * Execute the operation. * * @param parameters * Parameters for the operation. * @throws CommandException * If the command failed. * @throws ProgramParametersException * If there is an error in the parameters. */ void CommandC11xTesting::executeOperation(ProgramParameters& /*parameters*/) { #ifdef WORKBENCH_HAVE_C11X Cpp11xTesting cppx; cppx.test(); #endif // WORKBENCH_HAVE_C11X } #ifdef WORKBENCH_HAVE_C11X /** * Constructor. * * Tests delegating constructor (calls another constructor within same class) * Not supported by Intel compiler */ Cpp11xTesting::Cpp11xTesting() /*: Cp11xTesting(5)*/ { } /** * Constructor. */ Cpp11xTesting::Cpp11xTesting(const int /*value*/) { } /** * Destructor. */ Cpp11xTesting::~Cpp11xTesting() { } /** * Test 'noexcept' keyword indicating no exception is thrown * Not supported by Intel Compiler */ //void //Cpp11xTesting::methodName() noexcept() //{ // //} void Cpp11xTesting::test() { std::cout << "Initialized value of X: " << m_x << std::endl; std::cout << std::endl; /* * Space no longer needed between consecutive '>' */ std::vector> vvi; /* * Initialization list for vector * Not supported by Intel Compiler */ std::vector values; // { 3, 8, 5 }; values.push_back(3); values.push_back(8); values.push_back(5); /* * Iterator over vector using both 'auto' and the new iterator */ std::cout << "Vector auto and new iterator: "; for (auto i : values) { std::cout << i << " "; } std::cout << std::endl; /* * 'nullptr' instead of NULL or zero. */ float* fptr = nullptr; if (fptr == nullptr) { std::cout << "nullptr works" << std::endl; } /* * Array initialization, new style * Not supported by Intel compiler */ //int a[] { 1, 3, 5 }; int a[] = { 1, 3, 5 }; /* * Iteration over array using both 'auto' and the new iterator */ std::cout << "Array auto and new iterator: "; for (auto i : a) { std::cout << i << " "; } std::cout << std::endl; /* * Tuple * Not supported by Intel compiler */ //std::tuple tp(5, 9.1, 12.5); //std::cout << "Tuple 2nd value: " << std::get<1>(tp) << std::endl; /* * Test Lambda */ auto l = [] (const char* s) { std::cout << "Lambda: " << s << std::endl; }; l("lambda test"); } /** * 'override' keyword would cause an error if superclass did not have methodName() * Not supported by Intel compiler */ //void //SubClass:methodName() override noexcept //{ // //} #endif // WORKBENCH_HAVE_C11X connectome-workbench-1.4.2/src/Commands/CommandC11xTesting.h000066400000000000000000000046021360521144700237070ustar00rootroot00000000000000#ifndef __COMMAND_C11X_TESTING__H__ #define __COMMAND_C11X_TESTING__H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CommandOperation.h" namespace caret { /// Command that adds members and getter/setter methods to a class class CommandC11xTesting : public CommandOperation { public: CommandC11xTesting(); virtual ~CommandC11xTesting(); virtual void executeOperation(ProgramParameters& parameters); AString getHelpInformation(const AString& /*programName*/); private: CommandC11xTesting(const CommandC11xTesting&); CommandC11xTesting& operator=(const CommandC11xTesting&); }; #ifdef WORKBENCH_HAVE_C11X class Cpp11xTesting { public: Cpp11xTesting(); Cpp11xTesting(const int value); // Intel does not suport 'noexcept' keyword //virtual void methodName() noexcept; virtual ~Cpp11xTesting(); void test(); private: Cpp11xTesting(const Cpp11xTesting&); Cpp11xTesting& operator=(const Cpp11xTesting&); /* * Initialization of a member's value. */ int m_x = 5; }; class SubClass : public Cpp11xTesting { SubClass() : Cpp11xTesting(5) { } virtual ~SubClass() { } // Intel does not support 'override' keyword //virtual void methodName() override noexcept; }; #endif // WORKBENCH_HAVE_C11X } // namespace #endif // __COMMAND_C11X_TESTING__H__ connectome-workbench-1.4.2/src/Commands/CommandClassAddMember.cxx000066400000000000000000000463511360521144700250250ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretAssert.h" #include "CommandClassAddMember.h" #include "CommandClassCreate.h" #include "DataFileException.h" #include "FileInformation.h" #include "ProgramParameters.h" #include "TextFile.h" using namespace caret; /** * Constructor. */ CommandClassAddMember::CommandClassAddMember() : CommandOperation("-class-add-member", "ADD MEMBER AND GETTER/SETTER TO SOURCE CODE FILES (.h and .cxx)") { } /** * Destructor. */ CommandClassAddMember::~CommandClassAddMember() { } AString CommandClassAddMember::getHelpInformation(const AString& /*programName*/) { AString helpInfo = ("\n" "Add members to class header (.h) and implementation (.cxx) files.\n" "\n" "Usage: \n" " [-add-to-files]\n" " [-m ]...\n" "\n" " If the -add-to-files is not specified, the code for the\n" " header and implementation files is printed to the \n" " terminal.\n" "\n" " If the -add-to-files is specified, the class files are\n" " expected to be in the current directory and named\n" " .h and .cxx. The header \n" " file must contain this text in its private section:\n" " " + CommandClassCreate::getNewMembersString() + "\n" " The implementation file must contain this text in\n" " its public section:\n" " " + CommandClassCreate::getNewMethodsString() + "\n" " If either of these text string are missing, the code \n" " that would have been added to the file(s) is printed\n" " to the terminal.\n" " \n" " For each member, three text strings separated by a space\n" " must be provided and they are the name of the member\n" " its data type, and a description of the member. If the\n" " description contains spaces the description must be\n" " enclosed in double quotes (\"\").\n" " \n" " If the data type begins with a capital letter, it is\n" " assumed to be the name of a class. In this case, both\n" " const and non-const getters are created but not setter\n" " is created. Otherwise, the data type is expected to be\n" " a primitive type and both a getter and a setter are\n" " created. Note that AString and QString are treated as\n" " primitive types.\n" " \n" ); return helpInfo; } /** * Execute the operation. * * @param parameters * Parameters for the operation. * @throws CommandException * If the command failed. * @throws ProgramParametersException * If there is an error in the parameters. */ void CommandClassAddMember::executeOperation(ProgramParameters& parameters) { bool isAddToFiles = false; AString headerMemberCode = ""; AString headerMethodCode = ""; AString implementationCode = ""; const AString indentText = " "; /* * Process parameters */ const AString className = parameters.nextString("Class Name"); while (parameters.hasNext()) { const AString param = parameters.nextString(""); if (param == "-add-to-files") { isAddToFiles = true; } else if (param == "-m") { /* * Adding a member */ AString name = parameters.nextString("Member name"); if (name.indexOf(" ") >= 0) { throw CommandException("Member named \"" + name + "\" cannot contain spaces."); } if (name.isEmpty()) { throw CommandException("A member name is empty."); } else { if (name[0].isLetter() == false) { throw CommandException("Member named \"" + name + "\" must begin with a letter."); } if (name.indexOf(" ") >= 0) { throw CommandException("Member named \"" + name + "\" cannot contain spaces."); } } AString dataType = parameters.nextString("Data type for member " + name); if (dataType.isEmpty()) { throw CommandException("A data type is empty."); } if (dataType.indexOf(" ") >= 0) { throw CommandException("Data Type named \"" + name + "\" cannot contain spaces."); } const AString description = parameters.nextString("Description for member " + name); /* * If first letter of data type is upper-case, assume it * is a class and use a pointer for the class. However, * treat AString and QString as primitive types. */ //bool isEnum = false; bool isString = false; bool isClass = false; const QChar firstDataTypeChar = dataType[0]; if (firstDataTypeChar.isUpper()) { if ((dataType == "AString") || (dataType == "QString")) { isString = true; } else if (dataType.endsWith("Enum")) { //isEnum = true; } else { isClass = true; } } const AString returnType = dataType + (isClass ? "*" : ""); /* * Determine partial name for getter and setter * handling removal or addition of "m_" for * member name. */ AString getSetName = name; AString parameterName = name; if (name.startsWith("m_")) { getSetName = name.mid(2); parameterName = name.mid(2); } else { name = "m_" + name; } /* * Create the names for the getter and setter methods */ QChar firstGetSetNameChar = getSetName[0]; if (firstGetSetNameChar.isLower()) { firstGetSetNameChar = firstGetSetNameChar.toUpper(); getSetName[0] = firstGetSetNameChar; } const AString getterName = (((dataType == "bool") ? "is" : "get") + getSetName); const AString setterName = ("set" + getSetName); /* * Declare the member for the header file */ if (isClass) { headerMemberCode += ("#include \n" "\n"); } if (description.isEmpty() == false) { headerMemberCode += (indentText + "/** " + description + "*/\n"); } headerMemberCode += (indentText + (isClass ? "std::unique_ptr<" : "") + dataType //returnType + (isClass ? ">" : "") + " " + name + ";" + "\n" + "\n"); const AString classColonName = (className + "::"); if (isClass) { implementationCode += ("\n" + indentText + name + " = std::unique_ptr<" + dataType + ">(new" + dataType + "());" + "\n" + "\n"); /* * For class members, create only getter methods * that are both const and non-const */ for (int32_t i = 0; i < 2; i++) { const bool isConstMethod = (i == 0); headerMethodCode += (indentText + (isConstMethod ? "const " : "") + returnType + " " + getterName + "()" + (isConstMethod ? " const" : "") + ";\n" + "\n"); implementationCode += ("/**\n" " * @return " + description + "\n" " */\n" + (isConstMethod ? "const " : "") + returnType + "\n" + classColonName + getterName + "()" + (isConstMethod ? " const" : "") + "\n" + "{\n" + " return " + name + ".get();\n" + "}\n" + "\n"); } } else { /* * Getter and setter in header file */ headerMethodCode += (indentText + returnType + " " + getterName + "() const;\n" + "\n"); headerMethodCode += (indentText + "void " + setterName + "(const " + dataType + (isString ? "& " : " ") + parameterName + ");\n" + "\n"); /* * Getter and setter in implementation file */ implementationCode += ("/**\n" " * @return " + description + "\n" " */\n" + returnType + "\n" + classColonName + getterName + "() const\n" + "{\n" + " return " + name + ";\n" + "}\n" + "\n"); implementationCode += ("/**\n" " * Set " + description + "\n" " *\n" " * @param " + parameterName + "\n" " * New value for " + description + "\n" " */\n" + "void\n" + classColonName + setterName + "(const " + dataType + (isString ? "& " : " ") + parameterName + ")\n" + "{\n" + " " + name + " = " + parameterName + ";\n" + "}\n" + "\n"); } } else { throw ProgramParametersException("Unrecognized parameter: " + param); } } if (headerMemberCode.isEmpty()) { throw CommandException("No members were specified."); } AString errorMessage; bool isWriteToTerminal = true; if (isAddToFiles) { const AString headerFileName = className + ".h"; const AString implementationFileName = className + ".cxx"; FileInformation headerInfo(headerFileName); if (headerInfo.exists() == false) { errorMessage += headerFileName + " was not found."; } FileInformation impInfo(implementationFileName); if (impInfo.exists() == false) { errorMessage += implementationFileName + " was not found."; } /* * Copy existing files to the temporary directory */ QDir tempDir = QDir::temp(); AString tempHeaderFileName = tempDir.absoluteFilePath(headerFileName); AString tempImplementationFileName = tempDir.absoluteFilePath(implementationFileName); try { TextFile headerTextFile; headerTextFile.readFile(headerFileName); headerTextFile.writeFile(tempHeaderFileName); TextFile implementationTextFile; implementationTextFile.readFile(implementationFileName); implementationTextFile.writeFile(tempImplementationFileName); std::cout << "Backup of header file: " << qPrintable(tempHeaderFileName) << std::endl; std::cout << "Backup of implementation file: " << qPrintable(tempImplementationFileName) << std::endl; AString headerText = headerTextFile.getText(); const int newMemberOffset = findInsertionOffset(headerText, CommandClassCreate::getNewMembersString()); if (newMemberOffset >= 0) { headerMemberCode += "\n"; headerText.insert(newMemberOffset, headerMemberCode); } else { if (errorMessage.isEmpty()) { errorMessage += "\n"; } errorMessage += ("Unable to insert new members in header file. Did not find text " + CommandClassCreate::getNewMembersString() + " in the file " + headerFileName); } const int newMethodDeclareOffset = findInsertionOffset(headerText, CommandClassCreate::getNewMethodsString()); if (newMethodDeclareOffset >= 0) { headerMethodCode += "\n"; headerText.insert(newMethodDeclareOffset, headerMethodCode); } else { if (errorMessage.isEmpty()) { errorMessage += "\n"; } errorMessage += ("Unable to insert new methods in header file. Did not find text " + CommandClassCreate::getNewMethodsString() + " in the file " + headerFileName); } if ((newMemberOffset >= 0) && (newMethodDeclareOffset >= 0)) { headerTextFile.replaceText(headerText); isWriteToTerminal = false; headerTextFile.writeFile(headerFileName); } implementationCode += "\n"; implementationTextFile.addText("\n" + implementationCode); implementationTextFile.writeFile(implementationFileName); } catch (const DataFileException& dfe) { throw CommandException(dfe); } } if (isWriteToTerminal) { std::cout << std::endl; std::cout << "Header Code Getter Setter -------------------------------------" << std::endl; std::cout << qPrintable(headerMethodCode) << std::endl; std::cout << "Header Code Declaration ---------------------------------------" << std::endl; std::cout << qPrintable(headerMemberCode) << std::endl; std::cout << "Implementation Code -------------------------------------------" << std::endl; std::cout << qPrintable(implementationCode) << std::endl; } if (errorMessage.isEmpty() == false) { throw CommandException(errorMessage); } } /** * Find the offset of the new line or carriage return in the given text * using the given search text. Offset is first character after the * new line or carriage return. * * @param text * Text that is searched. * @param searchForText * Text that is searched for. * @return * Offset of the search text in the text or negative if * the search text is not found. */ int CommandClassAddMember::findInsertionOffset(const AString& text, const AString& searchForText) { int indx = text.indexOf(searchForText); if (indx >= 0) { while (indx >= 0) { const QChar ch = text[indx]; if ((ch == '\n') || (ch == '\r')) { indx++; break; } indx--; } return indx; } return -1; } connectome-workbench-1.4.2/src/Commands/CommandClassAddMember.h000066400000000000000000000032671360521144700244510ustar00rootroot00000000000000#ifndef __COMMAND_CLASS_ADD_MEMBER__H__ #define __COMMAND_CLASS_ADD_MEMBER__H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CommandOperation.h" namespace caret { /// Command that adds members and getter/setter methods to a class class CommandClassAddMember : public CommandOperation { public: CommandClassAddMember(); virtual ~CommandClassAddMember(); virtual void executeOperation(ProgramParameters& parameters); AString getHelpInformation(const AString& /*programName*/); private: CommandClassAddMember(const CommandClassAddMember&); CommandClassAddMember& operator=(const CommandClassAddMember&); int findInsertionOffset(const AString& text, const AString& searchForText); }; } // namespace #endif // __COMMAND_CLASS_ADD_MEMBER__H__ connectome-workbench-1.4.2/src/Commands/CommandClassCreate.cxx000066400000000000000000000723651360521144700244140ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretAssertion.h" #include "CommandClassCreate.h" #include "DataFileException.h" #include "FileInformation.h" #include "ProgramParameters.h" #include "TextFile.h" using namespace caret; /** * Constructor. */ CommandClassCreate::CommandClassCreate() : CommandClassCreateBase("-class-create", "CREATE CLASS SOURCE CODE FILES (.h and .cxx)") { } /** * Destructor. */ CommandClassCreate::~CommandClassCreate() { } AString CommandClassCreate::getHelpInformation(const AString& /*programName*/) { AString helpInfo = ("\n" "Create class header (.h) and implementation (.cxx) files.\n" "\n" "Usage: \n" " [-copy] \n" " [-equal] \n" " [-event-class ]\n" " [-event-listener] \n" " [-no-parent] \n" " [-parent ] \n" " [-scene] \n" " [-scene-sub-class] \n" "\n" "\n" "Options: \n" " -copy\n" " Adds copy constructor and assignment operator\n" " \n" " -equal\n" " Adds equality operator.\n" " \n" " -event-class \n" " When creating an Event subclass, using this\n" " option will automatically set the parent\n" " class to Event and place the given event\n" " enumerated type value into the parameter\n" " for the Event class constructor.\n" " \n" " For the there is no need\n" " to prepend it with \"EventTypeEnum::\".\n" " \n" " -event-listener \n" " Implement the EventListenerInterface so\n" " that the class may listen for events.\n" " \n" " -no-parent\n" " Created class is not derived from any other\n" " class. By default, the parent class is\n" " CaretObject.\n" " \n" " -parent \n" " Specify the parent (derived from) class.\n" " By default, the parent class is CaretObject.\n" " \n" " -scene\n" " Implement the SceneableInterface so that \n" " instances of the class can be restored from \n" " and saved to scenes. \n" " \n" " -scene-sub-class\n" " Adds methods that can be called by the super- \n" " class so that this sub-class can save and \n" " restore data to and from scenes. \n" " \n" " This option should only be used when creating\n" " a class whose super class implements the \n" " SceneableInterface\n" " \n" ); return helpInfo; } /** * Execute the operation. * * @param parameters * Parameters for the operation. * @throws CommandException * If the command failed. * @throws ProgramParametersException * If there is an error in the parameters. */ void CommandClassCreate::executeOperation(ProgramParameters& parameters) { const AString className = parameters.nextString("Class Name"); AString derivedFromClassName = "CaretObject"; AString eventTypeEnumName; bool hasCopyAndAssignment = false; bool hasEqualityOperator = false; bool hasEventListener = false; bool hasScenes = false; bool hasScenesSubClass = false; while (parameters.hasNext()) { const AString& param = parameters.nextString("Create Class Parameter"); if (param == "-copy") { hasCopyAndAssignment = true; } else if (param == "-equal") { hasEqualityOperator = true; } else if (param == "-event-class") { eventTypeEnumName = parameters.nextString("Event Type Enum Name"); if (eventTypeEnumName.contains("::") == false) { eventTypeEnumName.insert(0, "EventTypeEnum::"); } } else if (param == "-event-listener") { hasEventListener = true; } else if (param == "-parent") { derivedFromClassName = parameters.nextString("Parent Class Name"); if (derivedFromClassName.isEmpty()) { throw CommandException("Parent class name is empty."); } else { if (derivedFromClassName[0].isUpper() == false) { throw CommandException("Parent class name must begin with a Capital Letter"); } } } else if (param == "-no-parent") { derivedFromClassName = ""; } else if (param == "-scene") { hasScenes = true; } else if (param == "-scene-sub-class") { hasScenesSubClass = true; } else { throw CommandException("Invalid parameter: " + param); } } if (hasScenes && hasScenesSubClass) { throw CommandException("Only one, but not both scene options " "may be specified: " "-scene -scene-sub-class"); } if (className.isEmpty()) { throw CommandException("class name is empty."); } AString errorMessage; if (eventTypeEnumName.isEmpty() == false) { derivedFromClassName = "Event"; if (className.startsWith("Event") == false) { errorMessage += ("Event classes must being with \"Event\"\n"); } } if (className[0].isUpper() == false) { errorMessage += "First letter of class name must be upper case.\n"; } const AString headerFileName = className + ".h"; const AString implementationFileName = className + ".cxx"; FileInformation headerInfo(headerFileName); if (headerInfo.exists()) { errorMessage += headerFileName + " exists and this command will not overwrite it.\n"; } FileInformation impInfo(implementationFileName); if (impInfo.exists()) { errorMessage += implementationFileName + " exists and this command will not overwrite it.\n"; } if (errorMessage.isEmpty() == false) { throw CommandException(errorMessage); } AString ifndefName; AString ifdefNameStaticDeclarations; this->getIfDefNames(className, ifndefName, ifdefNameStaticDeclarations); this->createHeaderFile(headerFileName, className, derivedFromClassName, ifndefName, ifdefNameStaticDeclarations, hasCopyAndAssignment, hasEqualityOperator, hasEventListener, hasScenes, hasScenesSubClass); this->createImplementationFile(implementationFileName, className, derivedFromClassName, eventTypeEnumName, ifdefNameStaticDeclarations, hasCopyAndAssignment, hasEqualityOperator, hasEventListener, hasScenes, hasScenesSubClass); } /** * Create and write the header (.h) file. * * @param outputFileName * Name for file that is written. * @param className * Name of class. * @param derivedFromClassName * Name of class from which this class is derived. * @param ifdefName * Name of "ifndef" value. * @param ifdefNameStaticDeclaration * Name for "infdef" of static declarations. * @param hasCopyAndAssignment * Has copy constructor and assignment operator. * @param hasEqualityOperator * Class implements equality operator * @param hasEventListener * Class implements the EventListener interface * @param hasSceneInterface * Class implements the SceneableInterface for scene support. * @param hasSubClassSceneSaving * Parent class implements the SceneableInterface so add methods * for saving sub-class data to scene that will be called by parent. */ void CommandClassCreate::createHeaderFile(const AString& outputFileName, const AString& className, const AString& derivedFromClassName, const AString& ifndefName, const AString& ifdefNameStaticDeclaration, const bool hasCopyAndAssignment, const bool hasEqualityOperator, const bool hasEventListener, const bool hasSceneInterface, const bool hasSubClassSceneSaving) { AString t; AString derivedFromDeclaration; if (derivedFromClassName.isEmpty() == false) { derivedFromDeclaration = (" : public " + derivedFromClassName); } t += ("#ifndef " + ifndefName + "\n"); t += ("#define " + ifndefName + "\n"); t += this->getCopyright(); t += ("\n"); if (m_useUniquePtrFlag) { t += ("\n"); t += ("#include \n"); t += ("\n"); } t += (this->getIncludeDeclaration(derivedFromClassName) + "\n"); t += ("\n"); if (hasEventListener) { t += (this->getIncludeDeclaration("EventListenerInterface") + "\n"); if (derivedFromDeclaration.isEmpty()) { derivedFromDeclaration += (" : "); } else { derivedFromDeclaration += (", "); } derivedFromDeclaration += ("public EventListenerInterface"); } if (hasSceneInterface) { t += (this->getIncludeDeclaration("SceneableInterface") + "\n"); if (derivedFromDeclaration.isEmpty()) { derivedFromDeclaration += (" : "); } else { derivedFromDeclaration += (", "); } derivedFromDeclaration += ("public SceneableInterface"); } t += ("\n"); t += ("\n"); t += ("namespace caret {\n"); if (hasSceneInterface) { t += (" class SceneClassAssistant;\n"); } t += ("\n"); t += (" class " + className + derivedFromDeclaration + " {\n"); t += (" \n"); if (derivedFromClassName.startsWith("Q") || derivedFromClassName.startsWith("WuQ")) { t += (" Q_OBJECT\n"); t += ("\n"); } t += (" public:\n"); t += (" " + className + "();\n"); t += (" \n"); t += (" virtual ~" + className + "();\n"); t += (" \n"); if (hasCopyAndAssignment) { t += (" " + className + "(const " + className + "& obj);\n"); t += ("\n"); t += (" " + className + "& operator=(const " + className + "& obj);\n"); t += (" \n"); } else { t += (" " + className + "(const " + className + "&) = delete;\n"); t += ("\n"); t += (" " + className + "& operator=(const " + className + "&) = delete;\n"); t += (" \n"); } if (hasEqualityOperator) { t += (" bool operator==(const " + className + "& obj) const;\n"); t += (" \n"); } t += ("\n"); t += (" " + getNewMethodsString() + "\n"); t += ("\n"); if (derivedFromClassName == "CaretObject") { t += (" virtual AString toString() const;\n"); t += (" \n"); } if (hasEventListener) { t += (" virtual void receiveEvent(Event* event);\n"); t += ("\n"); } if (hasSceneInterface) { t += (" virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes,\n"); t += (" const AString& instanceName);\n"); t += ("\n"); t += (" virtual void restoreFromScene(const SceneAttributes* sceneAttributes,\n"); t += (" const SceneClass* sceneClass);\n"); t += ("\n"); } if (hasSceneInterface || hasSubClassSceneSaving) { AString comment = ""; AString virtualZero =""; if (hasSceneInterface) { comment = "//"; virtualZero = " = 0"; } t += (" \n"); t += (" \n"); t += (" \n"); t += (" \n"); t += (" \n"); if (hasSceneInterface) { t += ("// If there will be sub-classes of this class that need to save\n"); t += ("// and restore data from scenes, these pure virtual methods can\n"); t += ("// be uncommented to force their implementation by sub-classes.\n"); } t += (comment + " protected: \n"); t += (comment + " virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes,\n"); t += (comment + " SceneClass* sceneClass)" + virtualZero + ";\n"); t += (comment + "\n"); t += (comment + " virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes,\n"); t += (comment + " const SceneClass* sceneClass)" + virtualZero + ";\n"); t += ("\n"); } t += (" private:\n"); if (hasCopyAndAssignment) { t += (" void copyHelper" + className + "(const " + className + "& obj);\n"); t += ("\n"); } if (hasSceneInterface || hasSubClassSceneSaving) { if (m_useUniquePtrFlag) { t += (" std::unique_ptr m_sceneAssistant;\n"); } else { t += (" SceneClassAssistant* m_sceneAssistant;\n"); } t += ("\n"); } t += (" " + getNewMembersString() + "\n"); t += ("\n"); t += (" };\n"); t += (" \n"); t += ("#ifdef " + ifdefNameStaticDeclaration + "\n"); t += (" // \n"); t += ("#endif // " + ifdefNameStaticDeclaration + "\n"); t += ("\n"); t += ("} // namespace\n"); t += ("#endif //" + ifndefName + "\n"); TextFile tf; tf.replaceText(t); try { tf.writeFile(outputFileName); } catch (const DataFileException& e) { throw CommandException(e); } } /** * Create and write the implementation (.cxx) file. * * @param outputFileName * Name for file that is written. * @param className * Name of class. * @param derivedFromClassName * Name of parent class * @param eventTypeEnumName * Name of event type enumerated type (if subclass of Event). * @param ifdefNameStaticDeclaration * Name for "infdef" of static declarations. * @param hasCopyAndAssignment * Has copy constructor and assignment operator. * @param hasEqualityOperator * Class implements equality operator * @param hasEventListener * Class implements the EventListener interface * @param hasSceneInterface * Class implements the SceneableInterface for scene support. * @param hasSubClassSceneSaving * Parent class implements the SceneableInterface so add methods * for saving sub-class data to scene that will be called by parent. */ void CommandClassCreate::createImplementationFile(const AString& outputFileName, const AString& className, const AString& derivedFromClassName, const AString& eventTypeEnumName, const AString& ifdefNameStaticDeclaration, const bool hasCopyAndAssignment, const bool hasEqualityOperator, const bool hasEventListener, const bool hasSceneInterface, const bool hasSubClassSceneSaving) { AString module; FileInformation dirInfo(QDir::currentPath()); if (dirInfo.exists()) { if (dirInfo.isDirectory()) { module = dirInfo.getFileName(); } } AString t; t += this->getCopyright(); t += ("#define " + ifdefNameStaticDeclaration + "\n"); t += ("#include \"" + className + ".h\"\n"); t += ("#undef " + ifdefNameStaticDeclaration + "\n"); t += ("\n"); t += (this->getIncludeDeclaration("CaretAssert") + "\n"); if (eventTypeEnumName.isEmpty() == false) { t += ("#include \"EventTypeEnum.h\"\n"); t += ("\n"); } if (hasEventListener) { t += (this->getIncludeDeclaration("EventManager") + "\n"); } if (hasSceneInterface || hasSubClassSceneSaving) { t += (this->getIncludeDeclaration("SceneClass") + "\n"); t += (this->getIncludeDeclaration("SceneClassAssistant") + "\n"); t += ("\n"); } t += ("using namespace caret;\n"); t += ("\n"); t += ("\n"); t += (" \n"); t += ("/**\n"); t += (" * \\class caret::" + className + " \n"); t += (" * \\brief \n"); if (module.isEmpty() == false) { t += (" * \\ingroup " + module + "\n"); } t += (" *\n"); t += (" * \n"); t += (" */\n"); t += ("\n"); t += ("/**\n"); t += (" * Constructor.\n"); t += (" */\n"); t += ("" + className + "::" + className + "()\n"); if (derivedFromClassName.isEmpty() == false) { t += (": " + derivedFromClassName + "("+ eventTypeEnumName + ")\n"); } t += ("{\n"); t += (" \n"); if (hasSceneInterface || hasSubClassSceneSaving) { if (m_useUniquePtrFlag) { t += (" m_sceneAssistant = std::unique_ptr(new SceneClassAssistant());\n"); } else { t += (" m_sceneAssistant = new SceneClassAssistant();\n"); } t += (" \n"); } if (hasEventListener) { t += ("// EventManager::get()->addEventListener(this, EventTypeEnum::);\n"); } t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * Destructor.\n"); t += (" */\n"); t += ("" + className + "::~" + className + "()\n"); t += ("{\n"); if (hasEventListener) { t += (" EventManager::get()->removeAllEventsFromListener(this);\n"); } if (hasSceneInterface || hasSubClassSceneSaving) { if ( ! m_useUniquePtrFlag) { t += (" delete m_sceneAssistant;\n"); } } t += ("}\n"); t += ("\n"); if (hasCopyAndAssignment) { t += ("/**\n"); t += (" * Copy constructor.\n"); t += (" * @param obj\n"); t += (" * Object that is copied.\n"); t += (" */\n"); t += ("" + className + "::" + className + "(const " + className + "& obj)\n"); t += (": " + derivedFromClassName + "(obj)\n"); t += ("{\n"); t += (" this->copyHelper" + className + "(obj);\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * Assignment operator.\n"); t += (" * @param obj\n"); t += (" * Data copied from obj to this.\n"); t += (" * @return \n"); t += (" * Reference to this object.\n"); t += (" */\n"); t += ("" + className + "&\n"); t += ("" + className + "::operator=(const " + className + "& obj)\n"); t += ("{\n"); t += (" if (this != &obj) {\n"); t += (" " + derivedFromClassName + "::operator=(obj);\n"); t += (" this->copyHelper" + className + "(obj);\n"); t += (" }\n"); t += (" return *this; \n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * Helps with copying an object of this type.\n"); t += (" * @param obj\n"); t += (" * Object that is copied.\n"); t += (" */\n"); t += ("void \n"); t += ("" + className + "::copyHelper" + className + "(const " + className + "& obj)\n"); t += ("{\n"); t += (" \n"); t += ("}\n"); t += ("\n"); } if (hasEqualityOperator) { t += ("/**\n"); t += (" * Equality operator.\n"); t += (" * @param obj\n"); t += (" * Instance compared to this for equality.\n"); t += (" * @return \n"); t += (" * True if this instance and 'obj' instance are considered equal.\n"); t += (" */\n"); t += ("bool\n"); t += ("" + className + "::operator==(const " + className + "& obj) const\n"); t += ("{\n"); t += (" if (this == &obj) {\n"); t += (" return true; \n"); t += (" }\n"); t += ("\n"); t += (" /* perform equality testing HERE and return true if equal ! */\n"); t += ("\n"); t += (" return false; \n"); t += ("}\n"); t += ("\n"); } if (derivedFromClassName == "CaretObject") { t += ("/**\n"); t += (" * Get a description of this object's content.\n"); t += (" * @return String describing this object's content.\n"); t += (" */\n"); t += ("AString \n"); t += ("" + className + "::toString() const\n"); t += ("{\n"); t += (" return \"" + className + "\";\n"); t += ("}\n"); t += ("\n"); } if (hasEventListener) { t += ("/**\n"); t += (" * Receive an event.\n"); t += (" *\n"); t += (" * @param event\n"); t += (" * An event for which this instance is listening.\n"); t += (" */\n"); t += ("void\n"); t += (className + "::receiveEvent(Event* event)\n"); t += ("{\n"); t += ("// if (event->getEventType() == EventTypeEnum::) {\n"); t += ("// eventName = dynamic_cast(event);\n"); t += ("// CaretAssert(eventName);\n"); t += ("//\n"); t += ("// event->setEventProcessed();\n"); t += ("// }\n"); t += ("}\n"); t += ("\n"); } if (hasSceneInterface) { t += ("/**\n"); t += (" * Save information specific to this type of model to the scene.\n"); t += (" *\n"); t += (" * @param sceneAttributes\n"); t += (" * Attributes for the scene. Scenes may be of different types\n"); t += (" * (full, generic, etc) and the attributes should be checked when\n"); t += (" * saving the scene.\n"); t += (" *\n"); t += (" * @param instanceName\n"); t += (" * Name of instance in the scene.\n"); t += (" */\n"); t += ("SceneClass*\n"); t += (className + "::saveToScene(const SceneAttributes* sceneAttributes,\n"); t += (" const AString& instanceName)\n"); t += ("{\n"); t += (" SceneClass* sceneClass = new SceneClass(instanceName,\n"); t += (" \"" + className + "\",\n"); t += (" 1);\n"); t += (" m_sceneAssistant->saveMembers(sceneAttributes,\n"); t += (" sceneClass);\n"); t += (" \n"); t += (" // Uncomment if sub-classes must save to scene\n"); t += (" //saveSubClassDataToScene(sceneAttributes,\n"); t += (" // sceneClass);\n"); t += (" \n"); t += (" return sceneClass;\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * Restore information specific to the type of model from the scene.\n"); t += (" *\n"); t += (" * @param sceneAttributes\n"); t += (" * Attributes for the scene. Scenes may be of different types\n"); t += (" * (full, generic, etc) and the attributes should be checked when\n"); t += (" * restoring the scene.\n"); t += (" *\n"); t += (" * @param sceneClass\n"); t += (" * sceneClass from which model specific information is obtained.\n"); t += (" */\n"); t += ("void\n"); t += (className + "::restoreFromScene(const SceneAttributes* sceneAttributes,\n"); t += (" const SceneClass* sceneClass)\n"); t += ("{\n"); t += (" if (sceneClass == NULL) {\n"); t += (" return;\n"); t += (" }\n"); t += (" \n"); t += (" m_sceneAssistant->restoreMembers(sceneAttributes,\n"); t += (" sceneClass); \n"); t += (" \n"); t += (" //Uncomment if sub-classes must restore from scene\n"); t += (" //restoreSubClassDataFromScene(sceneAttributes,\n"); t += (" // sceneClass);\n"); t += (" \n"); t += ("}\n"); t += ("\n"); } if (hasSubClassSceneSaving) { t += ("/**\n"); t += (" * Save subclass data to the scene.\n"); t += (" *\n"); t += (" * @param sceneAttributes\n"); t += (" * Attributes for the scene. Scenes may be of different types\n"); t += (" * (full, generic, etc) and the attributes should be checked when\n"); t += (" * restoring the scene.\n"); t += (" *\n"); t += (" * @param sceneClass\n"); t += (" * sceneClass to which data members should be added. Will always\n"); t += (" * be valid (non-NULL).\n"); t += (" */\n"); t += ("void\n"); t += (className + "::saveSubClassDataToScene(const SceneAttributes* sceneAttributes,\n"); t += (" SceneClass* sceneClass)\n"); t += ("{\n"); t += (" m_sceneAssistant->saveMembers(sceneAttributes,\n"); t += (" sceneClass);\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * Restore file data from the scene.\n"); t += (" *\n"); t += (" * @param sceneAttributes\n"); t += (" * Attributes for the scene. Scenes may be of different types\n"); t += (" * (full, generic, etc) and the attributes should be checked when\n"); t += (" * restoring the scene.\n"); t += (" *\n"); t += (" * @param sceneClass\n"); t += (" * sceneClass for the instance of a class that implements\n"); t += (" * this interface. Will NEVER be NULL.\n"); t += (" */\n"); t += ("void\n"); t += (className + "::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes,\n"); t += (" const SceneClass* sceneClass)\n"); t += ("{\n"); t += (" m_sceneAssistant->restoreMembers(sceneAttributes,\n"); t += (" sceneClass);\n"); t += ("}\n"); t += ("\n"); } TextFile tf; tf.replaceText(t); try { tf.writeFile(outputFileName); } catch (const DataFileException& e) { throw CommandException(e); } } connectome-workbench-1.4.2/src/Commands/CommandClassCreate.h000066400000000000000000000063541360521144700240340ustar00rootroot00000000000000#ifndef __COMMAND_CLASS_CREATE__H__ #define __COMMAND_CLASS_CREATE__H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CommandClassCreateBase.h" namespace caret { /// Command that creates class files. class CommandClassCreate : public CommandClassCreateBase { public: CommandClassCreate(); virtual ~CommandClassCreate(); virtual void executeOperation(ProgramParameters& parameters); AString getHelpInformation(const AString& /*programName*/); /** This String is used by the command that adds new members to a class */ static AString getNewMembersString() { return "// ADD_NEW_MEMBERS_HERE"; } /** This String is used by the command that adds new METHODS to a class */ static AString getNewMethodsString() { return "// ADD_NEW_METHODS_HERE"; } private: CommandClassCreate(const CommandClassCreate&); CommandClassCreate& operator=(const CommandClassCreate&); void createHeaderFile(const AString& outputFileName, const AString& className, const AString& derivedFromClassName, const AString& ifdefName, const AString& ifdefNameStaticDeclaration, const bool hasCopyAndAssignment, const bool hasEqualityOperator, const bool hasEventListener, const bool hasSceneInterface, const bool hasSubClassSceneSaving); void createImplementationFile(const AString& outputFileName, const AString& className, const AString& derivedFromClassName, const AString& eventTypeEnumName, const AString& ifdefNameStaticDeclaration, const bool hasCopyAndAssignment, const bool hasEqualityOperator, const bool hasEventListener, const bool hasSceneInterface, const bool hasSubClassSceneSaving); const bool m_useUniquePtrFlag = true; }; } // namespace #endif // __COMMAND_CLASS_CREATE_H__ connectome-workbench-1.4.2/src/Commands/CommandClassCreateAlgorithm.cxx000066400000000000000000000373471360521144700262640ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "CaretAssertion.h" #include "CommandClassCreateAlgorithm.h" #include "DataFileException.h" #include "FileInformation.h" #include "ProgramParameters.h" #include "TextFile.h" using namespace caret; /** * Constructor. */ CommandClassCreateAlgorithm::CommandClassCreateAlgorithm() : CommandClassCreateBase("-class-create-algorithm", "CREATE SOURCE CODE CLASS FILES (.h, .cxx) FOR ALGORITHM") { } /** * Destructor. */ CommandClassCreateAlgorithm::~CommandClassCreateAlgorithm() { } /** * @return The help information. */ AString CommandClassCreateAlgorithm::getHelpInformation(const AString& /*programName*/) { AString helpInfo = ("\n" "Create Algorithm Class header (.h) and implementation (.cxx) files.\n" "\n" "Usage: \n" " \n" " \n" "\n" " algorithm-class-name\n" " Required name of the algorithm class that MUST start with \"Algorithm\"\n" " \n" " command-line-switch\n" " Required command line switch for algorithm.\n" " \n" " short-description\n" " Required short description within double quotes.\n" " \n" ); return helpInfo; } /** * Execute the operation. * * @param parameters * Parameters for the operation. * @throws CommandException * If the command failed. * @throws ProgramParametersException * If there is an error in the parameters. */ void CommandClassCreateAlgorithm::executeOperation(ProgramParameters& parameters) { const AString algorithmClassName = parameters.nextString("Algorithm Class Name"); const AString commandLineSwitch = parameters.nextString("Command Line Switch"); const AString shortDescription = parameters.nextString("Short Description"); if (parameters.hasNext()) { const AString param = parameters.nextString("Parameter"); throw CommandException("Unexpected extra parameter: " + param); } AString errorMessage; if (algorithmClassName.isEmpty()) { throw CommandException("Algorithm Class Name is empty."); } else { if (algorithmClassName.startsWith("Algorithm") == false) { throw CommandException("Algorithm Class Name must start with \"Algorithm\".\n"); } if (algorithmClassName == "Algorithm") { throw CommandException("\"Algorithm\" is not allowed for Algorithm Class Name"); } } if (commandLineSwitch.isEmpty()) { throw CommandException("Command line switch is empty."); } else if (commandLineSwitch.startsWith("-") == false) { throw CommandException("Command line must begin with \"-\"."); } if (shortDescription.isEmpty()) { throw CommandException("Short description is empty."); } const AString headerFileName = algorithmClassName + ".h"; const AString implementationFileName = algorithmClassName + ".cxx"; FileInformation headerInfo(headerFileName); if (headerInfo.exists()) { errorMessage += headerFileName + " exists and this command will not overwrite it.\n"; } FileInformation impInfo(implementationFileName); if (impInfo.exists()) { errorMessage += implementationFileName + " exists and this command will not overwrite it.\n"; } if (errorMessage.isEmpty() == false) { throw CommandException(errorMessage); } AString ifndefName; AString ifdefNameStaticDeclarations; this->getIfDefNames(algorithmClassName, ifndefName, ifdefNameStaticDeclarations); this->createHeaderFile(headerFileName, algorithmClassName, ifndefName); this->createImplementationFile(implementationFileName, algorithmClassName, commandLineSwitch, shortDescription); } /** * Create and write the header (.h) file. * * @param outputFileName * Name for file that is written. * @param algorithmClassName * Name of algorithm type class. * @param ifndefName * Name of "ifndef" value. */ void CommandClassCreateAlgorithm::createHeaderFile(const AString& outputFileName, const AString& algorithmClassName, const AString& ifndefName) { AString t; t += ("#ifndef " + ifndefName + "\n"); t += ("#define " + ifndefName + "\n"); t += this->getCopyright(); t += ("\n"); t += ("#include \"AbstractAlgorithm.h\"\n"); t += ("\n"); t += ("namespace caret {\n"); t += ("\n"); t += (" class " + algorithmClassName + " : public AbstractAlgorithm {\n"); t += ("\n"); t += (" private:\n"); t += (" " + algorithmClassName + "(); \n"); t += ("\n"); t += (" protected:\n"); t += (" static float getSubAlgorithmWeight();\n"); t += ("\n"); t += (" static float getAlgorithmInternalWeight();\n"); t += ("\n"); t += (" public:\n"); t += (" " + algorithmClassName + "(ProgressObject* myProgObj /*INSERT PARAMETERS HERE*/); \n"); t += ("\n"); t += (" static OperationParameters* getParameters();\n"); t += ("\n"); t += (" static void useParameters(OperationParameters* myParams, \n"); t += (" ProgressObject* myProgObj);\n"); t += ("\n"); t += (" static AString getCommandSwitch();\n"); t += ("\n"); t += (" static AString getShortDescription();\n"); t += ("\n"); t += (" };\n"); t += ("\n"); t += (" typedef TemplateAutoOperation<" + algorithmClassName + "> Auto" + algorithmClassName + ";\n"); t += ("\n"); t += ("} // namespace\n"); t += ("\n"); t += ("#endif //" + ifndefName + "\n"); t += ("\n"); TextFile tf; tf.replaceText(t); try { tf.writeFile(outputFileName); } catch (const DataFileException& e) { throw CommandException(e); } } /** * Create and write the implementation (.cxx) file. * * @param outputFileName * Name for file that is written. * @param algorithmClassName * Name of algorithm type class. * @param commandLineSwitch * Command line switch for algorithm. * @param shortDescription * Short description of algorithm. */ void CommandClassCreateAlgorithm::createImplementationFile(const AString& outputFileName, const AString& algorithmClassName, const AString& commandLineSwitch, const AString& shortDescription) { AString t; t += this->getCopyright(); t += ("#include \"CaretAssert.h\"\n"); t += ("#include \"CaretLogger.h\"\n"); t += ("\n"); t += ("#include \"" + algorithmClassName + ".h\"\n"); t += ("#include \"AlgorithmException.h\"\n"); t += ("\n"); t += ("using namespace caret;\n"); t += ("\n"); t += ("/**\n"); t += (" * \\class caret::" + algorithmClassName + " \n"); t += (" * \\brief " + shortDescription + "\n"); t += (" *\n"); t += (" * \n"); t += (" */\n"); t += ("\n"); t += ("/**\n"); t += (" * @return Command line switch\n"); t += (" */\n"); t += ("AString\n"); t += ("" + algorithmClassName + "::getCommandSwitch()\n"); t += ("{\n"); t += (" return \"" + commandLineSwitch + "\";\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * @return Short description of algorithm\n"); t += (" */\n"); t += ("AString\n"); t += ("" + algorithmClassName + "::getShortDescription()\n"); t += ("{\n"); t += (" return \"" + shortDescription.toUpper() + "\";\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * @return Parameters for algorithm\n"); t += (" */\n"); t += ("OperationParameters*\n"); t += ("" + algorithmClassName + "::getParameters()\n"); t += ("{\n"); t += (" OperationParameters* ret = new OperationParameters();\n"); t += (" \n"); t += (" /*\n"); t += (" * Example parameters:\n"); t += (" *\n"); t += (" * ret->addSurfaceParameter(1, \"surface\", \"the surface to compute on\");\n"); t += (" *\n"); t += (" * ret->addMetricOutputParameter(2, \"metric\", \"the output metric\");\n"); t += (" *\n"); t += (" * OptionalParameter* columnSelect = ret->createOptionalParameter(3, \"-column\", \"select a single column\");\n"); t += (" *\n"); t += (" * columnSelect->addStringParameter(1, \"column\", \"the column number or name\")\n"); t += (" */\n"); t += (" AString helpText = (\"This is where you set the help text. DO NOT add the info about what the command line format is\"\n"); t += (" \"and do not give the command switch, short description, or the short descriptions of parameters. Do not indent,\"\n"); t += (" \"add newlines, or format the text in any way other than to separate paragraphs within the help text prose\");\n"); t += ("\n"); t += (" ret->setHelpText(helpText);\n"); t += (" \n"); t += (" return ret;\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * Use Parameters and perform algorithm\n"); t += (" * @param myParams\n"); t += (" * Parameters for algorithm\n"); t += (" * @param myProgObj\n"); t += (" * The progress object\n"); t += (" * @throws\n"); t += (" * AlgorithmException if errors\n"); t += (" */\n"); t += ("void\n"); t += ("" + algorithmClassName + "::useParameters(OperationParameters* myParams,\n"); t += (" ProgressObject* myProgObj)\n"); t += ("{\n"); t += (" /*\n"); t += (" * Example parameter processing:\n"); t += (" *\n"); t += (" * Gets the surface with key 1\n"); t += (" * SurfaceFile* mySurf = myParams->getSurface(1);\n"); t += (" *\n"); t += (" * Gets the output metric with key 2\n"); t += (" * MetricFile* myMetricOut = myParams->getOutputMetric(2);\n"); t += (" *\n"); t += (" * Gets optional parameter with key 3\n"); t += (" * OptionalParameter* columnSelect = myParams->getOptionalParameter(3);\n"); t += (" * int columnNum = -1;\n"); t += (" * if (columnSelect->m_present) {\n"); t += (" * columnNum = (int)myMetric->getMapIndexFromNameOrNumber(columnSelect->getString(1));\n"); t += (" * if (columnNum < 0) {\n"); t += (" * throw AlgorithmException(\"invalid column specified\");\n"); t += (" * }\n"); t += (" * }\n"); t += (" */\n"); t += (" \n"); t += (" /*\n"); t += (" * Constructs and executes the algorithm \n"); t += (" */\n"); t += (" " + algorithmClassName + "(myProgObj /* INSERT PARAMETERS HERE */);\n"); t += (" \n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * Constructor\n"); t += (" *\n"); t += (" * Calling the constructor will execute the algorithm\n"); t += (" *\n"); t += (" * @param myProgObj\n"); t += (" * Parameters for algorithm\n"); t += (" */\n"); t += (algorithmClassName + "::" + algorithmClassName + "(ProgressObject* myProgObj /* INSERT PARAMETERS HERE - may get compilation error if no parameters added */)\n"); t += (" : AbstractAlgorithm(myProgObj)\n"); t += ("{\n"); t += (" /*\n"); t += (" * Uncomment these if you use another algorithm inside here\n"); t += (" *\n"); t += (" * ProgressObject* subAlgProgress1 = NULL;\n"); t += (" * if (myProgObj != NULL) {\n"); t += (" * subAlgProgress1 = myProgObj->addAlgorithm(AlgorithmInsertNameHere::getAlgorithmWeight());\n"); t += (" * }\n"); t += (" */\n"); t += (" \n"); t += (" /*\n"); t += (" * Sets the algorithm up to use the progress object, and will \n"); t += (" * finish the progress object automatically when the algorithm terminates\n"); t += (" */\n"); t += (" LevelProgress myProgress(myProgObj);\n"); t += (" \n"); t += (" /*\n"); t += (" * How you say you are halfway done with the INTERNAL work of the algorithm\n"); t += (" * will report finished automatically when this function ends (myProgress goes out \n"); t += (" of scope, destructor triggers finish\n"); t += (" */\n"); t += (" //myProgress.reportProgress(0.5f);\n"); t += (" \n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * @return Algorithm internal weight\n"); t += (" */\n"); t += ("float\n"); t += ("" + algorithmClassName + "::getAlgorithmInternalWeight()\n"); t += ("{\n"); t += (" /*\n"); t += (" * override this if needed, if the progress bar isn't smooth\n"); t += (" */\n"); t += (" return 1.0f;\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * @return Algorithm sub-algorithm weight\n"); t += (" */\n"); t += ("float\n"); t += ("" + algorithmClassName + "::getSubAlgorithmWeight()\n"); t += ("{\n"); t += (" /*\n"); t += (" * If you use a subalgorithm\n"); t += (" */\n"); t += (" //return AlgorithmInsertNameHere::getAlgorithmWeight()\n"); t += (" return 0.0f;\n"); t += ("}\n"); t += ("\n"); TextFile tf; tf.replaceText(t); try { tf.writeFile(outputFileName); } catch (const DataFileException& e) { throw CommandException(e); } std::cout << std::endl; std::cout << "Algorithm was created successfully." << std::endl; std::cout << std::endl; std::cout << "Add the class files to Algorithms/CMakeLists.txt:" << std::endl; std::cout << " " << qPrintable(algorithmClassName) << ".h" << std::endl; std::cout << " " << qPrintable(algorithmClassName) << ".cxx" << std::endl; std::cout << std::endl; std::cout << "Add the header file and algorithm to Commands/CommandOperationManager.cxx:" << std::endl; std::cout << " #include \"" << qPrintable(algorithmClassName) << ".h\"" << std::endl; std::cout << " this->commandOperations.push_back(new CommandParser(new Auto" << algorithmClassName << "()));" << std::endl; std::cout << std::endl; } connectome-workbench-1.4.2/src/Commands/CommandClassCreateAlgorithm.h000066400000000000000000000041311360521144700256720ustar00rootroot00000000000000#ifndef __COMMAND_CLASS_CREATE_ALGORITHM_H__ #define __COMMAND_CLASS_CREATE_ALGORITHM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CommandClassCreateBase.h" namespace caret { /// Command that creates class files for an algorithm class CommandClassCreateAlgorithm : public CommandClassCreateBase { public: CommandClassCreateAlgorithm(); virtual ~CommandClassCreateAlgorithm(); virtual void executeOperation(ProgramParameters& parameters); AString getHelpInformation(const AString& /*programName*/); private: CommandClassCreateAlgorithm(const CommandClassCreateAlgorithm&); CommandClassCreateAlgorithm& operator=(const CommandClassCreateAlgorithm&); void createHeaderFile(const AString& outputFileName, const AString& algorithmClassName, const AString& ifndefName); void createImplementationFile(const AString& outputFileName, const AString& algorithmClassName, const AString& commandLineSwitch, const AString& shortDescription); }; } // namespace #endif // __COMMAND_CLASS_CREATE_ALGORITHM_H__ connectome-workbench-1.4.2/src/Commands/CommandClassCreateBase.cxx000066400000000000000000000111771360521144700252010ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretAssert.h" #include "CommandClassCreateBase.h" #include "ProgramParameters.h" #include "SystemUtilities.h" using namespace caret; /** * Constructor. */ CommandClassCreateBase::CommandClassCreateBase(const AString& commandLineSwitch, const AString& operationShortDescription) : CommandOperation(commandLineSwitch, operationShortDescription) { } /** * Destructor. */ CommandClassCreateBase::~CommandClassCreateBase() { } /** * Get the names for use with #ifdef declarations. * @param classNameIn * Name of class. * @param ifndefNameOut * Name for use with #ifndef at beginning of file. * @param ifdefNameStaticDeclarationOut * Name for use when declarating static members at * end of the header file. */ void CommandClassCreateBase::getIfDefNames(const AString& classNameIn, AString& ifndefNameOut, AString& ifdefNameStaticDeclarationOut) { ifndefNameOut = ""; ifdefNameStaticDeclarationOut = ""; const int32_t classNameLength = classNameIn.length(); ifndefNameOut += "_"; for (int32_t i = 0; i < classNameLength; i++) { QChar c = classNameIn[i]; if (c.isUpper()) { ifndefNameOut += "_"; } ifndefNameOut += c.toUpper(); } ifdefNameStaticDeclarationOut = ifndefNameOut + "_DECLARE__"; ifndefNameOut += "_H__"; } /** * Get the copyright. * @return Text containing copyright. */ AString CommandClassCreateBase::getCopyright() { const AString year = SystemUtilities::getYear(); AString text; text.append("\n"); text.append("/*LICENSE_START*/\n"); text.append("/*\n"); text.append(" * Copyright (C) " + year + " Washington University School of Medicine\n"); text.append(" *\n"); text.append(" * This program is free software; you can redistribute it and/or modify\n"); text.append(" * it under the terms of the GNU General Public License as published by\n"); text.append(" * the Free Software Foundation; either version 2 of the License, or\n"); text.append(" * (at your option) any later version.\n"); text.append(" *\n"); text.append(" * This program is distributed in the hope that it will be useful,\n"); text.append(" * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); text.append(" * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); text.append(" * GNU General Public License for more details.\n"); text.append(" *\n"); text.append(" * You should have received a copy of the GNU General Public License along\n"); text.append(" * with this program; if not, write to the Free Software Foundation, Inc.,\n"); text.append(" * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n"); text.append(" */\n"); text.append("/*LICENSE_END*/\n"); text.append("\n"); return text; } /** * Get the #include declaration for an include file. * @param includeFileName * Name of include file. * @return * Include declaration (no newline at end of line). */ AString CommandClassCreateBase::getIncludeDeclaration(const AString& includeFileName) const { if (includeFileName.isEmpty()) { return ""; } AString txt = "#include "; const QChar firstChar = includeFileName[0]; if (firstChar.isLower()) { txt += ("<" + includeFileName + ">"); } else if (firstChar == 'Q') { txt += ("<" + includeFileName + ">"); } else { AString dotH = ""; if (includeFileName.endsWith(".h") == false) { dotH = ".h"; } txt += ("\"" + includeFileName + dotH + "\""); } return txt; } connectome-workbench-1.4.2/src/Commands/CommandClassCreateBase.h000066400000000000000000000034731360521144700246260ustar00rootroot00000000000000#ifndef __COMMAND_CLASS_CREATE_BASE_H__ #define __COMMAND_CLASS_CREATE_BASE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CommandOperation.h" namespace caret { /// Base class for creating class files. class CommandClassCreateBase : public CommandOperation { protected: CommandClassCreateBase(const AString& commandLineSwitch, const AString& operationShortDescription); public: virtual ~CommandClassCreateBase(); private: CommandClassCreateBase(const CommandClassCreateBase&); CommandClassCreateBase& operator=(const CommandClassCreateBase&); protected: AString getIncludeDeclaration(const AString& includeFileName) const; AString getCopyright(); void getIfDefNames(const AString& className, AString& ifdefName, AString& ifdefNameStaticDeclaration); }; } // namespace #endif // __COMMAND_CLASS_CREATE_BASE_H__ connectome-workbench-1.4.2/src/Commands/CommandClassCreateEnum.cxx000066400000000000000000000734601360521144700252360ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "CaretAssertion.h" #include "CommandClassCreateEnum.h" #include "DataFileException.h" #include "FileInformation.h" #include "ProgramParameters.h" #include "TextFile.h" using namespace caret; /** * Constructor. */ CommandClassCreateEnum::CommandClassCreateEnum() : CommandClassCreateBase("-class-create-enum", "CREATE SOURCE CODE CLASS FILES (.h, .cxx) FOR ENUMERATED TYPE") { } /** * Destructor. */ CommandClassCreateEnum::~CommandClassCreateEnum() { } AString CommandClassCreateEnum::getHelpInformation(const AString& /*programName*/) { AString helpInfo = ("\n" "Create enumerated type header (.h) and implementation (.cxx) files.\n" "\n" "Usage: \n" " \n" " \n" "\n" " enum-class-name\n" " Name of the enumerated type. Must end in \"Enum\"\n" " \n" " number-of-values\n" " Number of values in the enumerated type.\n" " \n" " auto-number\n" " Automatically generated integer codes corresponding\n" " to the enumerated values. Value for this parameter\n" " are \"true\" and \"false\".\n" " \n" " [enum-name-1] [enum-name-2]...[enum-name-N]\n" " Optional names for the enumerated values. \n" " \n" " If the number of names listed is greater than\n" " the \"number-of-values\" parameter, the \"number-of-values\"\n" " will become the number of names. If the number\n" " of names is is less than the \"number-of-values\",\n" " empty entries will be created.\n" " \n" ); return helpInfo; } /** * Execute the operation. * * @param parameters * Parameters for the operation. * @throws CommandException * If the command failed. * @throws ProgramParametersException * If there is an error in the parameters. */ void CommandClassCreateEnum::executeOperation(ProgramParameters& parameters) { const AString enumClassName = parameters.nextString("Enum Class Name"); int32_t numberOfEnumValues = parameters.nextInt("Number of Enum Values"); const bool isAutoNumber = parameters.nextBoolean("Auto Number (true/false)"); std::vector enumValueNames; while (parameters.hasNext()) { enumValueNames.push_back(parameters.nextString("Enum Value")); } const int32_t numEnumValueNames = static_cast(enumValueNames.size()); if (numEnumValueNames > 0) { if (numEnumValueNames > numberOfEnumValues) { numberOfEnumValues = numEnumValueNames; } } if (enumClassName.isEmpty()) { throw CommandException("Enum class name is empty."); } AString errorMessage; if (enumClassName.endsWith("Enum") == false) { errorMessage += "Name of class MUST end with \"Enum\".\n"; } if (enumClassName[0].isLower()) { errorMessage += "First letter of class name must be upper case.\n"; } const AString headerFileName = enumClassName + ".h"; const AString implementationFileName = enumClassName + ".cxx"; FileInformation headerInfo(headerFileName); if (headerInfo.exists()) { errorMessage += headerFileName + " exists and this command will not overwrite it.\n"; } FileInformation impInfo(implementationFileName); if (impInfo.exists()) { errorMessage += implementationFileName + " exists and this command will not overwrite it.\n"; } if (errorMessage.isEmpty() == false) { throw CommandException(errorMessage); } AString ifndefName; AString ifdefNameStaticDeclarations; this->getIfDefNames(enumClassName, ifndefName, ifdefNameStaticDeclarations); this->createHeaderFile(headerFileName, enumClassName, ifndefName, ifdefNameStaticDeclarations, numberOfEnumValues, enumValueNames, isAutoNumber); this->createImplementationFile(implementationFileName, enumClassName, ifdefNameStaticDeclarations, numberOfEnumValues, enumValueNames, isAutoNumber); } /** * Create and write the header (.h) file. * * @param outputFileName * Name for file that is written. * @param enumClassName * Name of enumerated type class. * @param ifdefName * Name of "ifndef" value. * @param ifdefNameStaticDeclaration * Name for "infdef" of static declarations. * @param numberOfEnumValues * Number of enumerated type values. * @param enumValueNames * Names for the enumerated values. * @param isAutoNumber * Automatically assign numers/indices to the enumerated values. */ void CommandClassCreateEnum::createHeaderFile(const AString& outputFileName, const AString& enumClassName, const AString& ifndefName, const AString& ifdefNameStaticDeclaration, const int32_t numberOfEnumValues, const std::vector& enumValueNames, const bool isAutoNumber) { AString t; t += ("#ifndef " + ifndefName + "\n"); t += ("#define " + ifndefName + "\n"); t += this->getCopyright(); t += ("\n"); t += ("#include \n"); t += ("#include \n"); t += ("#include \"AString.h\"\n"); t += ("\n"); t += ("namespace caret {\n"); t += ("\n"); t += ("class " + enumClassName + " {\n"); t += ("\n"); t += ("public:\n"); t += (" /**\n"); t += (" * Enumerated values.\n"); t += (" */\n"); t += (" enum Enum {\n"); for (int indx = 0; indx < numberOfEnumValues; indx++) { t += (" /** */\n"); t += (" "); if (indx < static_cast(enumValueNames.size())) { t +=enumValueNames[indx]; } if (indx < (numberOfEnumValues - 1)) { t += (",\n"); } else { t += ("\n"); } } t += (" };\n"); t += ("\n"); t += ("\n"); t += (" ~" + enumClassName + "();\n"); t += ("\n"); t += (" static AString toName(Enum enumValue);\n"); t += (" \n"); t += (" static Enum fromName(const AString& name, bool* isValidOut);\n"); t += (" \n"); t += (" static AString toGuiName(Enum enumValue);\n"); t += (" \n"); t += (" static Enum fromGuiName(const AString& guiName, bool* isValidOut);\n"); t += (" \n"); t += (" static int32_t toIntegerCode(Enum enumValue);\n"); t += (" \n"); t += (" static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut);\n"); t += ("\n"); t += (" static void getAllEnums(std::vector& allEnums);\n"); t += ("\n"); t += (" static void getAllNames(std::vector& allNames, const bool isSorted);\n"); t += ("\n"); t += (" static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted);\n"); t += ("\n"); t += ("private:\n"); t += (" " + enumClassName + "(const Enum enumValue, \n"); if (isAutoNumber == false) { t += (" const int32_t integerCode, \n"); } t += (" const AString& name,\n"); t += (" const AString& guiName);\n"); t += ("\n"); t += (" static const " + enumClassName + "* findData(const Enum enumValue);\n"); t += ("\n"); t += (" /** Holds all instance of enum values and associated metadata */\n"); t += (" static std::vector<" + enumClassName + "> enumData;\n"); t += ("\n"); t += (" /** Initialize instances that contain the enum values and metadata */\n"); t += (" static void initialize();\n"); t += ("\n"); t += (" /** Indicates instance of enum values and metadata have been initialized */\n"); t += (" static bool initializedFlag;\n"); t += (" \n"); if (isAutoNumber) { t += (" /** Auto generated integer codes */\n"); t += (" static int32_t integerCodeCounter;\n"); t += (" \n"); } t += (" /** The enumerated type value for an instance */\n"); t += (" Enum enumValue;\n"); t += ("\n"); t += (" /** The integer code associated with an enumerated value */\n"); t += (" int32_t integerCode;\n"); t += ("\n"); t += (" /** The name, a text string that is identical to the enumerated value */\n"); t += (" AString name;\n"); t += (" \n"); t += (" /** A user-friendly name that is displayed in the GUI */\n"); t += (" AString guiName;\n"); t += ("};\n"); t += ("\n"); t += ("#ifdef " + ifdefNameStaticDeclaration + "\n"); t += ("std::vector<" + enumClassName + "> " + enumClassName + "::enumData;\n"); t += ("bool " + enumClassName + "::initializedFlag = false;\n"); if (isAutoNumber) { t += ("int32_t " + enumClassName + "::integerCodeCounter = 0; \n"); } t += ("#endif // " + ifdefNameStaticDeclaration + "\n"); t += ("\n"); t += ("} // namespace\n"); t += ("#endif //" + ifndefName + "\n"); TextFile tf; tf.replaceText(t); try { tf.writeFile(outputFileName); } catch (const DataFileException& e) { throw CommandException(e); } } /** * Create and write the implementation (.cxx) file. * * @param outputFileName * Name for file that is written. * @param enumClassName * Name of enumerated type class. * @param ifdefNameStaticDeclaration * Name for "infdef" of static declarations. * @param numberOfEnumValues * Number of enumerated type values. * @param enumValueNames * Names for the enumerated values. * @param isAutoNumber * Automatically assign numers/indices to the enumerated values. */ void CommandClassCreateEnum::createImplementationFile(const AString& outputFileName, const AString& enumClassName, const AString& ifdefNameStaticDeclaration, const int32_t numberOfEnumValues, const std::vector& enumValueNames, const bool isAutoNumber) { AString t; t += this->getCopyright(); t += ("#include \n"); t += ("#define " + ifdefNameStaticDeclaration + "\n"); t += ("#include \"" + enumClassName + ".h\"\n"); t += ("#undef " + ifdefNameStaticDeclaration + "\n"); t += ("\n"); t += ("#include \"CaretAssert.h\"\n"); t += ("\n"); t += ("using namespace caret;\n"); t += ("\n"); t += (" \n"); t += ("/**\n"); t += (" * \\class caret::" + enumClassName + " \n"); t += (" * \\brief \n"); t += (" *\n"); t += (" * \n"); t += (" *\n"); t += (getEnumComboBoxTemplateHelpInfo(enumClassName)); t += (" */\n"); t += ("\n"); t += ("/**\n"); t += (" * Constructor.\n"); t += (" *\n"); t += (" * @param enumValue\n"); t += (" * An enumerated value.\n"); if (isAutoNumber == false) { t += (" * @param integerCode\n"); t += (" * Integer code for this enumerated value.\n"); t += (" *\n"); } t += (" * @param name\n"); t += (" * Name of enumerated value.\n"); t += (" *\n"); t += (" * @param guiName\n"); t += (" * User-friendly name for use in user-interface.\n"); t += (" */\n"); t += ("" + enumClassName + "::" + enumClassName + "(const Enum enumValue,\n"); if (isAutoNumber == false) { t += (" const int32_t integerCode,\n"); } t += (" const AString& name,\n"); t += (" const AString& guiName)\n"); t += ("{\n"); t += (" this->enumValue = enumValue;\n"); if (isAutoNumber) { t += (" this->integerCode = integerCodeCounter++;\n"); } else { t += (" this->integerCode = integerCode;\n"); } t += (" this->name = name;\n"); t += (" this->guiName = guiName;\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * Destructor.\n"); t += (" */\n"); t += ("" + enumClassName + "::~" + enumClassName + "()\n"); t += ("{\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * Initialize the enumerated metadata.\n"); t += (" */\n"); t += ("void\n"); t += ("" + enumClassName + "::initialize()\n"); t += ("{\n"); t += (" if (initializedFlag) {\n"); t += (" return;\n"); t += (" }\n"); t += (" initializedFlag = true;\n"); t += ("\n"); for (int32_t indx = 0; indx < numberOfEnumValues; indx++) { AString name = ""; AString guiName = name; if (indx < static_cast(enumValueNames.size())) { name = enumValueNames[indx]; /* * Name: "NAME_OF_ENUM_VALUE" * guiName: "Name Of Enum Value" */ guiName = name.toLower(); const int numChars = guiName.length(); for (int32_t k = 0; k < numChars; k++) { if (k == 0) { guiName[k] = guiName[k].toUpper(); } else if (guiName[k] == '_') { guiName[k] = ' '; if (k < (numChars - 1)) { k++; guiName[k] = guiName[k].toUpper(); } } } } t += (" enumData.push_back(" + enumClassName + "(" + name + ", \n"); if (isAutoNumber == false) { t += (" " + AString::number(indx) + ", \n"); } t += (" \"" + name + "\", \n"); t += (" \"" + guiName + "\"));\n"); t += (" \n"); } t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * Find the data for and enumerated value.\n"); t += (" * @param enumValue\n"); t += (" * The enumerated value.\n"); t += (" * @return Pointer to data for this enumerated type\n"); t += (" * or NULL if no data for type or if type is invalid.\n"); t += (" */\n"); t += ("const " + enumClassName + "*\n"); t += ("" + enumClassName + "::findData(const Enum enumValue)\n"); t += ("{\n"); t += (" if (initializedFlag == false) initialize();\n"); t += ("\n"); t += (" size_t num = enumData.size();\n"); t += (" for (size_t i = 0; i < num; i++) {\n"); t += (" const " + enumClassName + "* d = &enumData[i];\n"); t += (" if (d->enumValue == enumValue) {\n"); t += (" return d;\n"); t += (" }\n"); t += (" }\n"); t += ("\n"); t += (" return NULL;\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * Get a string representation of the enumerated type.\n"); t += (" * @param enumValue \n"); t += (" * Enumerated value.\n"); t += (" * @return \n"); t += (" * String representing enumerated value.\n"); t += (" */\n"); t += ("AString \n"); t += ("" + enumClassName + "::toName(Enum enumValue) {\n"); t += (" if (initializedFlag == false) initialize();\n"); t += (" \n"); t += (" const " + enumClassName + "* enumInstance = findData(enumValue);\n"); t += (" return enumInstance->name;\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * Get an enumerated value corresponding to its name.\n"); t += (" * @param name \n"); t += (" * Name of enumerated value.\n"); t += (" * @param isValidOut \n"); t += (" * If not NULL, it is set indicating that a\n"); t += (" * enum value exists for the input name.\n"); t += (" * @return \n"); t += (" * Enumerated value.\n"); t += (" */\n"); t += ("" + enumClassName + "::Enum \n"); t += ("" + enumClassName + "::fromName(const AString& name, bool* isValidOut)\n"); t += ("{\n"); t += (" if (initializedFlag == false) initialize();\n"); t += (" \n"); t += (" bool validFlag = false;\n"); t += (" Enum enumValue = " + enumClassName + "::enumData[0].enumValue;\n"); t += (" \n"); t += (" for (std::vector<" + enumClassName + ">::iterator iter = enumData.begin();\n"); t += (" iter != enumData.end();\n"); t += (" iter++) {\n"); t += (" const " + enumClassName + "& d = *iter;\n"); t += (" if (d.name == name) {\n"); t += (" enumValue = d.enumValue;\n"); t += (" validFlag = true;\n"); t += (" break;\n"); t += (" }\n"); t += (" }\n"); t += (" \n"); t += (" if (isValidOut != 0) {\n"); t += (" *isValidOut = validFlag;\n"); t += (" }\n"); t += (" else if (validFlag == false) {\n"); t += (" CaretAssertMessage(0, AString(\"Name \" + name + \"failed to match enumerated value for type " + enumClassName + "\"));\n"); t += (" }\n"); t += (" return enumValue;\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * Get a GUI string representation of the enumerated type.\n"); t += (" * @param enumValue \n"); t += (" * Enumerated value.\n"); t += (" * @return \n"); t += (" * String representing enumerated value.\n"); t += (" */\n"); t += ("AString \n"); t += ("" + enumClassName + "::toGuiName(Enum enumValue) {\n"); t += (" if (initializedFlag == false) initialize();\n"); t += (" \n"); t += (" const " + enumClassName + "* enumInstance = findData(enumValue);\n"); t += (" return enumInstance->guiName;\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * Get an enumerated value corresponding to its GUI name.\n"); t += (" * @param s \n"); t += (" * Name of enumerated value.\n"); t += (" * @param isValidOut \n"); t += (" * If not NULL, it is set indicating that a\n"); t += (" * enum value exists for the input name.\n"); t += (" * @return \n"); t += (" * Enumerated value.\n"); t += (" */\n"); t += ("" + enumClassName + "::Enum \n"); t += ("" + enumClassName + "::fromGuiName(const AString& guiName, bool* isValidOut)\n"); t += ("{\n"); t += (" if (initializedFlag == false) initialize();\n"); t += (" \n"); t += (" bool validFlag = false;\n"); t += (" Enum enumValue = " + enumClassName + "::enumData[0].enumValue;\n"); t += (" \n"); t += (" for (std::vector<" + enumClassName + ">::iterator iter = enumData.begin();\n"); t += (" iter != enumData.end();\n"); t += (" iter++) {\n"); t += (" const " + enumClassName + "& d = *iter;\n"); t += (" if (d.guiName == guiName) {\n"); t += (" enumValue = d.enumValue;\n"); t += (" validFlag = true;\n"); t += (" break;\n"); t += (" }\n"); t += (" }\n"); t += (" \n"); t += (" if (isValidOut != 0) {\n"); t += (" *isValidOut = validFlag;\n"); t += (" }\n"); t += (" else if (validFlag == false) {\n"); t += (" CaretAssertMessage(0, AString(\"guiName \" + guiName + \"failed to match enumerated value for type " + enumClassName + "\"));\n"); t += (" }\n"); t += (" return enumValue;\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * Get the integer code for a data type.\n"); t += (" *\n"); t += (" * @return\n"); t += (" * Integer code for data type.\n"); t += (" */\n"); t += ("int32_t\n"); t += ("" + enumClassName + "::toIntegerCode(Enum enumValue)\n"); t += ("{\n"); t += (" if (initializedFlag == false) initialize();\n"); t += (" const " + enumClassName + "* enumInstance = findData(enumValue);\n"); t += (" return enumInstance->integerCode;\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * Find the data type corresponding to an integer code.\n"); t += (" *\n"); t += (" * @param integerCode\n"); t += (" * Integer code for enum.\n"); t += (" * @param isValidOut\n"); t += (" * If not NULL, on exit isValidOut will indicate if\n"); t += (" * integer code is valid.\n"); t += (" * @return\n"); t += (" * Enum for integer code.\n"); t += (" */\n"); t += ("" + enumClassName + "::Enum\n"); t += ("" + enumClassName + "::fromIntegerCode(const int32_t integerCode, bool* isValidOut)\n"); t += ("{\n"); t += (" if (initializedFlag == false) initialize();\n"); t += (" \n"); t += (" bool validFlag = false;\n"); t += (" Enum enumValue = " + enumClassName + "::enumData[0].enumValue;\n"); t += (" \n"); t += (" for (std::vector<" + enumClassName + ">::iterator iter = enumData.begin();\n"); t += (" iter != enumData.end();\n"); t += (" iter++) {\n"); t += (" const " + enumClassName + "& enumInstance = *iter;\n"); t += (" if (enumInstance.integerCode == integerCode) {\n"); t += (" enumValue = enumInstance.enumValue;\n"); t += (" validFlag = true;\n"); t += (" break;\n"); t += (" }\n"); t += (" }\n"); t += (" \n"); t += (" if (isValidOut != 0) {\n"); t += (" *isValidOut = validFlag;\n"); t += (" }\n"); t += (" else if (validFlag == false) {\n"); t += (" CaretAssertMessage(0, AString(\"Integer code \" + AString::number(integerCode) + \"failed to match enumerated value for type " + enumClassName + "\"));\n"); t += (" }\n"); t += (" return enumValue;\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * Get all of the enumerated type values. The values can be used\n"); t += (" * as parameters to toXXX() methods to get associated metadata.\n"); t += (" *\n"); t += (" * @param allEnums\n"); t += (" * A vector that is OUTPUT containing all of the enumerated values.\n"); t += (" */\n"); t += ("void\n"); t += ("" + enumClassName + "::getAllEnums(std::vector<" + enumClassName + "::Enum>& allEnums)\n"); t += ("{\n"); t += (" if (initializedFlag == false) initialize();\n"); t += (" \n"); t += (" allEnums.clear();\n"); t += (" \n"); t += (" for (std::vector<" + enumClassName + ">::iterator iter = enumData.begin();\n"); t += (" iter != enumData.end();\n"); t += (" iter++) {\n"); t += (" allEnums.push_back(iter->enumValue);\n"); t += (" }\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * Get all of the names of the enumerated type values.\n"); t += (" *\n"); t += (" * @param allNames\n"); t += (" * A vector that is OUTPUT containing all of the names of the enumerated values.\n"); t += (" * @param isSorted\n"); t += (" * If true, the names are sorted in alphabetical order.\n"); t += (" */\n"); t += ("void\n"); t += ("" + enumClassName + "::getAllNames(std::vector& allNames, const bool isSorted)\n"); t += ("{\n"); t += (" if (initializedFlag == false) initialize();\n"); t += (" \n"); t += (" allNames.clear();\n"); t += (" \n"); t += (" for (std::vector<" + enumClassName + ">::iterator iter = enumData.begin();\n"); t += (" iter != enumData.end();\n"); t += (" iter++) {\n"); t += (" allNames.push_back(" + enumClassName + "::toName(iter->enumValue));\n"); t += (" }\n"); t += (" \n"); t += (" if (isSorted) {\n"); t += (" std::sort(allNames.begin(), allNames.end());\n"); t += (" }\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * Get all of the GUI names of the enumerated type values.\n"); t += (" *\n"); t += (" * @param allNames\n"); t += (" * A vector that is OUTPUT containing all of the GUI names of the enumerated values.\n"); t += (" * @param isSorted\n"); t += (" * If true, the names are sorted in alphabetical order.\n"); t += (" */\n"); t += ("void\n"); t += ("" + enumClassName + "::getAllGuiNames(std::vector& allGuiNames, const bool isSorted)\n"); t += ("{\n"); t += (" if (initializedFlag == false) initialize();\n"); t += (" \n"); t += (" allGuiNames.clear();\n"); t += (" \n"); t += (" for (std::vector<" + enumClassName + ">::iterator iter = enumData.begin();\n"); t += (" iter != enumData.end();\n"); t += (" iter++) {\n"); t += (" allGuiNames.push_back(" + enumClassName + "::toGuiName(iter->enumValue));\n"); t += (" }\n"); t += (" \n"); t += (" if (isSorted) {\n"); t += (" std::sort(allGuiNames.begin(), allGuiNames.end());\n"); t += (" }\n"); t += ("}\n"); t += ("\n"); TextFile tf; tf.replaceText(t); try { tf.writeFile(outputFileName); } catch (const DataFileException& e) { throw CommandException(e); } } /** * Get a string containing information on how to use this enumerated type * with the EnumComboBoxTemplate in the GUI. * * @param enumClassName * Name of the enumerated type. * @return * String containing usage information. */ AString CommandClassCreateEnum::getEnumComboBoxTemplateHelpInfo(const AString& enumClassName) const { const AString firstLetter = enumClassName.left(1).toLower(); const AString memberName = ("m_" + firstLetter + enumClassName.mid(1) + "ComboBox"); const AString slotName = (memberName.mid(2) + "ItemActivated()"); const AString templateParameter = ("<" + enumClassName + "," + enumClassName + "::Enum>"); const AString setupIndentString(memberName.length() + QString("->setup<").length(), ' '); AString s(" * Using this enumerated type in the GUI with an EnumComboBoxTemplate\n" " * \n" " * Header File (.h)\n" " * Forward declare the data type:\n" " * class EnumComboBoxTemplate;\n" " * \n" " * Declare the member:\n" " * EnumComboBoxTemplate* " + memberName + ";\n" " * \n" " * Declare a slot that is called when user changes selection\n" " * private slots:\n" " * void " + slotName + ";\n" " * \n" " * Implementation File (.cxx)\n" " * Include the header files\n" " * #include \"EnumComboBoxTemplate.h\"\n" " * #include \"" + enumClassName + ".h\"\n" " * \n" " * Instatiate:\n" " * " + memberName + " = new EnumComboBoxTemplate(this);\n" " * " + memberName + "->setup" + templateParameter + "();\n" " * \n" " * Get notified when the user changes the selection: \n" " * QObject::connect(" + memberName + ", SIGNAL(itemActivated()),\n" " * this, SLOT(" + slotName + "));\n" " * \n" " * Update the selection:\n" " * " + memberName + "->setSelectedItem" + templateParameter + "(NEW_VALUE);\n" " * \n" " * Read the selection:\n" " * const " + enumClassName + "::Enum VARIABLE = " + memberName + "->getSelectedItem" + templateParameter + "();\n" " * \n"); return s; } connectome-workbench-1.4.2/src/Commands/CommandClassCreateEnum.h000066400000000000000000000050571360521144700246600ustar00rootroot00000000000000#ifndef __COMMAND_CLASS_CREATE_ENUM_H__ #define __COMMAND_CLASS_CREATE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CommandClassCreateBase.h" namespace caret { /// Command that creates class files for an enumerated type. class CommandClassCreateEnum : public CommandClassCreateBase { public: CommandClassCreateEnum(); virtual ~CommandClassCreateEnum(); virtual void executeOperation(ProgramParameters& parameters); AString getHelpInformation(const AString& /*programName*/); private: CommandClassCreateEnum(const CommandClassCreateEnum&); CommandClassCreateEnum& operator=(const CommandClassCreateEnum&); void createHeaderFile(const AString& outputFileName, const AString& enumClassName, const AString& ifdefName, const AString& ifdefNameStaticDeclaration, const int32_t numberOfEnumValues, const std::vector& enumValueNames, const bool isAutoNumber); void createImplementationFile(const AString& outputFileName, const AString& enumClassName, const AString& ifdefNameStaticDeclaration, const int32_t numberOfEnumValues, const std::vector& enumValueNames, const bool isAutoNumber); AString getEnumComboBoxTemplateHelpInfo(const AString& enumClassName) const; }; } // namespace #endif // __COMMAND_CLASS_CREATE_ENUM_H__ connectome-workbench-1.4.2/src/Commands/CommandClassCreateOperation.cxx000066400000000000000000000263211360521144700262640ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "CaretAssertion.h" #include "CommandClassCreateOperation.h" #include "DataFileException.h" #include "FileInformation.h" #include "ProgramParameters.h" #include "TextFile.h" using namespace caret; /** * Constructor. */ CommandClassCreateOperation::CommandClassCreateOperation() : CommandClassCreateBase("-class-create-operation", "CREATE SOURCE CODE CLASS FILES (.h, .cxx) FOR OPERATION") { } /** * Destructor. */ CommandClassCreateOperation::~CommandClassCreateOperation() { } AString CommandClassCreateOperation::getHelpInformation(const AString& /*programName*/) { AString helpInfo = ("\n" "Create Operation Class header (.h) and implementation (.cxx) files.\n" "\n" "Usage: \n" " \n" " \n" " [-no-parameters]\n" "\n" " operation-class-name\n" " Required name of the operation class that MUST start with \"Operation\"\n" " \n" " command-line-switch\n" " Required command line switch for operation.\n" " \n" " short-description\n" " Required short description within double quotes.\n" " \n" " -no-parameters\n" " Optional parameter if the operation does not use parameters.\n" " \n" ); return helpInfo; } /** * Execute the operation. * * @param parameters * Parameters for the operation. * @throws CommandException * If the command failed. * @throws ProgramParametersException * If there is an error in the parameters. */ void CommandClassCreateOperation::executeOperation(ProgramParameters& parameters) { const AString operationClassName = parameters.nextString("Operation Class Name"); const AString commandLineSwitch = parameters.nextString("Command Line Switch"); const AString shortDescription = parameters.nextString("Short Description"); bool hasParametersFlag = true; while (parameters.hasNext()) { const AString& param = parameters.nextString("Create Class Parameter"); if (param == "-no-parameters") { hasParametersFlag = false; } else { throw CommandException("Invalid parameter: " + param); } } AString errorMessage; if (operationClassName.isEmpty()) { throw CommandException("Operation Class Name is empty."); } else { if (operationClassName.startsWith("Operation") == false) { throw CommandException("Operation Class Name must start with \"Operation\".\n"); } if (operationClassName == "Operation") { throw CommandException("\"Operation\" is not allowed for Operation Class Name"); } } if (commandLineSwitch.isEmpty()) { throw CommandException("Command line switch is empty."); } else if (commandLineSwitch.startsWith("-") == false) { throw CommandException("Command line must begin with \"-\"."); } if (shortDescription.isEmpty()) { throw CommandException("Short description is empty."); } const AString headerFileName = operationClassName + ".h"; const AString implementationFileName = operationClassName + ".cxx"; FileInformation headerInfo(headerFileName); if (headerInfo.exists()) { errorMessage += headerFileName + " exists and this command will not overwrite it.\n"; } FileInformation impInfo(implementationFileName); if (impInfo.exists()) { errorMessage += implementationFileName + " exists and this command will not overwrite it.\n"; } if (errorMessage.isEmpty() == false) { throw CommandException(errorMessage); } AString ifndefName; AString ifdefNameStaticDeclarations; this->getIfDefNames(operationClassName, ifndefName, ifdefNameStaticDeclarations); this->createHeaderFile(headerFileName, operationClassName, ifndefName, hasParametersFlag); this->createImplementationFile(implementationFileName, operationClassName, commandLineSwitch, shortDescription); } /** * Create and write the header (.h) file. * * @param outputFileName * Name for file that is written. * @param operationClassName * Name of operation type class. * @param ifndefName * Name of "ifndef" value. * @param hasParameters * True if the operation has parameters. */ void CommandClassCreateOperation::createHeaderFile(const AString& outputFileName, const AString& operationClassName, const AString& ifndefName, const bool hasParameters) { AString t; t += ("#ifndef " + ifndefName + "\n"); t += ("#define " + ifndefName + "\n"); t += this->getCopyright(); t += ("\n"); t += ("#include \"AbstractOperation.h\"\n"); t += ("\n"); t += ("namespace caret {\n"); t += ("\n"); t += (" class " + operationClassName + " : public AbstractOperation {\n"); t += ("\n"); t += (" public:\n"); t += (" static OperationParameters* getParameters();\n"); t += ("\n"); t += (" static void useParameters(OperationParameters* myParams, \n"); t += (" ProgressObject* myProgObj);\n"); t += ("\n"); t += (" static AString getCommandSwitch();\n"); t += ("\n"); t += (" static AString getShortDescription();\n"); t += ("\n"); if (hasParameters == false) { t += (" static bool takesParameters() { return false; }\n"); t += ("\n"); } t += (" };\n"); t += ("\n"); t += (" typedef TemplateAutoOperation<" + operationClassName + "> Auto" + operationClassName + ";\n"); t += ("\n"); t += ("} // namespace\n"); t += ("\n"); t += ("#endif //" + ifndefName + "\n"); t += ("\n"); TextFile tf; tf.replaceText(t); try { tf.writeFile(outputFileName); } catch (const DataFileException& e) { throw CommandException(e); } } /** * Create and write the implementation (.cxx) file. * * @param outputFileName * Name for file that is written. * @param operationClassName * Name of operation type class. * @param commandLineSwitch * Command line switch for operation. * @param shortDescription * Short description of operation. */ void CommandClassCreateOperation::createImplementationFile(const AString& outputFileName, const AString& operationClassName, const AString& commandLineSwitch, const AString& shortDescription) { AString t; t += this->getCopyright(); t += ("#include \"CaretAssert.h\"\n"); t += ("#include \"CaretLogger.h\"\n"); t += ("\n"); t += ("#include \"" + operationClassName + ".h\"\n"); t += ("#include \"OperationException.h\"\n"); t += ("\n"); t += ("using namespace caret;\n"); t += ("\n"); t += ("/**\n"); t += (" * \\class caret::" + operationClassName + " \n"); t += (" * \\brief " + shortDescription + "\n"); t += (" *\n"); t += (" * \n"); t += (" */\n"); t += ("\n"); t += ("/**\n"); t += (" * @return Command line switch\n"); t += (" */\n"); t += ("AString\n"); t += ("" + operationClassName + "::getCommandSwitch()\n"); t += ("{\n"); t += (" return \"" + commandLineSwitch + "\";\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * @return Short description of operation\n"); t += (" */\n"); t += ("AString\n"); t += ("" + operationClassName + "::getShortDescription()\n"); t += ("{\n"); t += (" return \"" + shortDescription.toUpper() + "\";\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * @return Parameters for operation\n"); t += (" */\n"); t += ("OperationParameters*\n"); t += ("" + operationClassName + "::getParameters()\n"); t += ("{\n"); t += (" OperationParameters* ret = new OperationParameters();\n"); t += (" \n"); t += (" AString helpText;\n"); t += (" \n"); t += (" ret->setHelpText(helpText);\n"); t += (" \n"); t += (" return ret;\n"); t += ("}\n"); t += ("\n"); t += ("/**\n"); t += (" * Use Parameters and perform operation\n"); t += (" */\n"); t += ("void\n"); t += ("" + operationClassName + "::useParameters(OperationParameters* myParams,\n"); t += (" ProgressObject* myProgObj)\n"); t += ("{\n"); t += (" LevelProgress myProgress(myProgObj);\n"); t += (" \n"); t += ("}\n"); t += ("\n"); TextFile tf; tf.replaceText(t); try { tf.writeFile(outputFileName); } catch (const DataFileException& e) { throw CommandException(e); } std::cout << std::endl; std::cout << "Operation was created successfully." << std::endl; std::cout << std::endl; std::cout << "Add the class files to Operations/CMakeLists.txt:" << std::endl; std::cout << " " << qPrintable(operationClassName) << ".h" << std::endl; std::cout << " " << qPrintable(operationClassName) << ".cxx" << std::endl; std::cout << std::endl; std::cout << "Add the header file and operation to Commands/CommandOperationManager.cxx:" << std::endl; std::cout << " #include \"" << qPrintable(operationClassName) << ".h\"" << std::endl; std::cout << " this->commandOperations.push_back(new CommandParser(new Auto" << operationClassName << "()));" << std::endl; std::cout << std::endl; } connectome-workbench-1.4.2/src/Commands/CommandClassCreateOperation.h000066400000000000000000000042211360521144700257040ustar00rootroot00000000000000#ifndef __COMMAND_CLASS_CREATE_OPERATION_H__ #define __COMMAND_CLASS_CREATE_OPERATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CommandClassCreateBase.h" namespace caret { /// Command that creates class files for an operation class CommandClassCreateOperation : public CommandClassCreateBase { public: CommandClassCreateOperation(); virtual ~CommandClassCreateOperation(); virtual void executeOperation(ProgramParameters& parameters); AString getHelpInformation(const AString& /*programName*/); private: CommandClassCreateOperation(const CommandClassCreateOperation&); CommandClassCreateOperation& operator=(const CommandClassCreateOperation&); void createHeaderFile(const AString& outputFileName, const AString& operationClassName, const AString& ifndefName, const bool hasParameters); void createImplementationFile(const AString& outputFileName, const AString& operationClassName, const AString& commandLineSwitch, const AString& shortDescription); }; } // namespace #endif // __COMMAND_CLASS_CREATE_OPERATION_H__ connectome-workbench-1.4.2/src/Commands/CommandException.cxx000066400000000000000000000041731360521144700241510ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CommandException.h" #include using namespace caret; /** * Constructor. * */ CommandException::CommandException() : CaretException() { this->initializeMembersCommandException(); } /** * Constructor that uses stack trace from the exception * passed in as a parameter. * * @param e Any exception whose stack trace becomes * this exception's stack trace. * */ CommandException::CommandException( const CaretException& e) : CaretException(e) { this->initializeMembersCommandException(); } /** * Constructor. * * @param s Description of the exception. * */ CommandException::CommandException(const AString& s) : CaretException(s) { this->initializeMembersCommandException(); } /** * Copy Constructor. * @param e * Exception that is copied. */ CommandException::CommandException(const CommandException& e) : CaretException(e) { } /** * Assignment operator. * @param e * Exception that is copied. * @return * Copy of the exception. */ CommandException& CommandException::operator=(const CommandException& e) { if (this != &e) { CaretException::operator=(e); } return *this; } /** * Destructor */ CommandException::~CommandException() throw() { } void CommandException::initializeMembersCommandException() { } connectome-workbench-1.4.2/src/Commands/CommandException.h000066400000000000000000000027101360521144700235710ustar00rootroot00000000000000#ifndef __COMMAND_EXCEPTION_H__ #define __COMMAND_EXCEPTION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretException.h" namespace caret { /// An exception thrown during command processing. class CommandException : public CaretException { public: CommandException(); CommandException(const CaretException& e); CommandException(const AString& s); CommandException(const CommandException& e); CommandException& operator=(const CommandException& e); virtual ~CommandException() throw(); private: void initializeMembersCommandException(); }; } // namespace #endif // __COMMAND_EXCEPTION_H__ connectome-workbench-1.4.2/src/Commands/CommandOperation.cxx000066400000000000000000000054551360521144700241570ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CommandOperation.h" #include "CaretAssert.h" using namespace caret; /** * Constructor. * @param commandLineSwitch * Switch to select this command. * @param operationShortDescription * Short description of the command. */ CommandOperation::CommandOperation(const AString& commandLineSwitch, const AString& operationShortDescription) : CaretObject() { this->commandLineSwitch = commandLineSwitch; this->operationShortDescription = operationShortDescription; CaretAssert(commandLineSwitch != "-command-switch");//catch failure to change things in the command template for (int i = 0; i < commandLineSwitch.length(); ++i)//release build should optimize out empty loops { CaretAssert(commandLineSwitch[i].unicode() < 128); } } /** * Destructor. */ CommandOperation::~CommandOperation() { } /** * Execute the command. * * @param parameters * Parameters for the operation. * @throws CommandException * If the command failed. */ void CommandOperation::execute(ProgramParameters& parameters, const bool& preventProvenance) { if (preventProvenance) { disableProvenance();//let provenance-ignorant commands not need to deal with an unused parameter } this->executeOperation(parameters); } void CommandOperation::disableProvenance() { } void CommandOperation::setCiftiOutputDTypeAndScale(const int16_t&, const double&, const double&) { } void CommandOperation::setCiftiOutputDTypeNoScale(const int16_t&) { } AString CommandOperation::doCompletion(ProgramParameters&, const bool&) { return ""; } bool CommandOperation::takesParameters() { return true; } /** * Get the short description of the operation. */ AString CommandOperation::getOperationShortDescription() const { return this->operationShortDescription; } /** * Get the command line switch for selecting the operation. */ AString CommandOperation::getCommandLineSwitch() const { return this->commandLineSwitch; } connectome-workbench-1.4.2/src/Commands/CommandOperation.h000066400000000000000000000056121360521144700235770ustar00rootroot00000000000000#ifndef __COMMAND_OPERATION_H__ #define __COMMAND_OPERATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "CommandException.h" #include "ProgramParametersException.h" #include "AString.h" #include "nifti1.h" namespace caret { class ProgramParameters; /// Abstract class for a command operation. class CommandOperation : public CaretObject { public: virtual ~CommandOperation(); void execute(ProgramParameters& parameters, const bool& preventProvenance); virtual void setCiftiOutputDTypeAndScale(const int16_t& dtype, const double& minVal, const double& maxVal); virtual void setCiftiOutputDTypeNoScale(const int16_t& dtype); virtual AString doCompletion(ProgramParameters& parameters, const bool& useExtGlob); protected: /** * Execute the operation. * * @param parameters * Parameters for the operation. * @throws CommandException * If the command failed. * @throws ProgramParametersException * If there is an error in the parameters. */ virtual void executeOperation(ProgramParameters& parameters) = 0; virtual void disableProvenance(); CommandOperation(const AString& commandLineSwitch, const AString& operationShortDescription); private: CommandOperation(); CommandOperation(const CommandOperation&); CommandOperation& operator=(const CommandOperation&); public: AString getOperationShortDescription() const; AString getCommandLineSwitch() const; virtual AString getHelpInformation(const AString& programName) = 0; virtual bool takesParameters(); private: /** Short description listing commands purpose */ AString operationShortDescription; /** Switch on command line */ AString commandLineSwitch; }; } // namespace #endif // __COMMAND_OPERATION_H__ connectome-workbench-1.4.2/src/Commands/CommandOperationManager.cxx000066400000000000000000002235511360521144700254510ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __COMMAND_OPERATION_MANAGER_DEFINE__ #include "CommandOperationManager.h" #undef __COMMAND_OPERATION_MANAGER_DEFINE__ #include "AlgorithmAnnotationResample.h" #include "AlgorithmBorderResample.h" #include "AlgorithmBorderToVertices.h" #include "AlgorithmCiftiAllLabelsToROIs.h" #include "AlgorithmCiftiAverage.h" #include "AlgorithmCiftiAverageDenseROI.h" #include "AlgorithmCiftiAverageROICorrelation.h" #include "AlgorithmCiftiCorrelation.h" #include "AlgorithmCiftiCorrelationGradient.h" #include "AlgorithmCiftiCreateDenseScalar.h" #include "AlgorithmCiftiCreateDenseTimeseries.h" #include "AlgorithmCiftiCreateLabel.h" #include "AlgorithmCiftiCrossCorrelation.h" #include "AlgorithmCiftiDilate.h" #include "AlgorithmCiftiErode.h" #include "AlgorithmCiftiExtrema.h" #include "AlgorithmCiftiFalseCorrelation.h" #include "AlgorithmCiftiFindClusters.h" #include "AlgorithmCiftiGradient.h" #include "AlgorithmCiftiLabelAdjacency.h" #include "AlgorithmCiftiLabelModifyKeys.h" #include "AlgorithmCiftiLabelProbability.h" #include "AlgorithmCiftiLabelToBorder.h" #include "AlgorithmCiftiLabelToROI.h" #include "AlgorithmCiftiMergeDense.h" #include "AlgorithmCiftiMergeParcels.h" #include "AlgorithmCiftiPairwiseCorrelation.h" #include "AlgorithmCiftiParcellate.h" #include "AlgorithmCiftiParcelMappingToLabel.h" #include "AlgorithmCiftiReduce.h" #include "AlgorithmCiftiReorder.h" #include "AlgorithmCiftiReplaceStructure.h" #include "AlgorithmCiftiResample.h" #include "AlgorithmCiftiROIsFromExtrema.h" #include "AlgorithmCiftiSeparate.h" #include "AlgorithmCiftiSmoothing.h" #include "AlgorithmCiftiTranspose.h" #include "AlgorithmCiftiVectorOperation.h" #include "AlgorithmCreateSignedDistanceVolume.h" #include "AlgorithmFiberDotProducts.h" #include "AlgorithmFociResample.h" #include "AlgorithmGiftiAllLabelsToROIs.h" #include "AlgorithmGiftiLabelAddPrefix.h" #include "AlgorithmGiftiLabelToROI.h" #include "AlgorithmLabelDilate.h" #include "AlgorithmLabelErode.h" #include "AlgorithmLabelModifyKeys.h" #include "AlgorithmLabelProbability.h" #include "AlgorithmLabelResample.h" #include "AlgorithmLabelToBorder.h" #include "AlgorithmLabelToVolumeMapping.h" #include "AlgorithmMetricDilate.h" #include "AlgorithmMetricErode.h" #include "AlgorithmMetricEstimateFWHM.h" #include "AlgorithmMetricExtrema.h" #include "AlgorithmMetricFalseCorrelation.h" #include "AlgorithmMetricFillHoles.h" #include "AlgorithmMetricFindClusters.h" #include "AlgorithmMetricGradient.h" #include "AlgorithmMetricReduce.h" #include "AlgorithmMetricRegression.h" #include "AlgorithmMetricRemoveIslands.h" #include "AlgorithmMetricResample.h" #include "AlgorithmMetricROIsFromExtrema.h" #include "AlgorithmMetricROIsToBorder.h" #include "AlgorithmMetricSmoothing.h" #include "AlgorithmMetricTFCE.h" #include "AlgorithmMetricToVolumeMapping.h" #include "AlgorithmMetricVectorOperation.h" #include "AlgorithmMetricVectorTowardROI.h" #include "AlgorithmNodesInsideBorder.h" //-border-to-rois #include "AlgorithmSignedDistanceToSurface.h" #include "AlgorithmSurfaceAffineRegression.h" #include "AlgorithmSurfaceApplyAffine.h" #include "AlgorithmSurfaceApplyWarpfield.h" #include "AlgorithmSurfaceAverage.h" #include "AlgorithmSurfaceCortexLayer.h" #include "AlgorithmSurfaceCreateSphere.h" #include "AlgorithmSurfaceCurvature.h" #include "AlgorithmSurfaceDistortion.h" #include "AlgorithmSurfaceFlipLR.h" #include "AlgorithmSurfaceGenerateInflated.h" #include "AlgorithmSurfaceInflation.h" #include "AlgorithmSurfaceMatch.h" #include "AlgorithmSurfaceModifySphere.h" #include "AlgorithmSurfaceResample.h" #include "AlgorithmSurfaceSmoothing.h" #include "AlgorithmSurfaceSphereProjectUnproject.h" #include "AlgorithmSurfaceToSurface3dDistance.h" #include "AlgorithmSurfaceWedgeVolume.h" #include "AlgorithmVolumeAffineResample.h" #include "AlgorithmVolumeAllLabelsToROIs.h" #include "AlgorithmVolumeDilate.h" #include "AlgorithmVolumeDistortion.h" #include "AlgorithmVolumeErode.h" #include "AlgorithmVolumeEstimateFWHM.h" #include "AlgorithmVolumeExtrema.h" #include "AlgorithmVolumeFillHoles.h" #include "AlgorithmVolumeFindClusters.h" #include "AlgorithmVolumeGradient.h" #include "AlgorithmVolumeLabelModifyKeys.h" #include "AlgorithmVolumeLabelProbability.h" #include "AlgorithmVolumeLabelToROI.h" #include "AlgorithmVolumeLabelToSurfaceMapping.h" #include "AlgorithmVolumeParcelResampling.h" #include "AlgorithmVolumeParcelResamplingGeneric.h" #include "AlgorithmVolumeParcelSmoothing.h" #include "AlgorithmVolumeReduce.h" #include "AlgorithmVolumeRemoveIslands.h" #include "AlgorithmVolumeROIsFromExtrema.h" #include "AlgorithmVolumeSmoothing.h" #include "AlgorithmVolumeTFCE.h" #include "AlgorithmVolumeToSurfaceMapping.h" #include "AlgorithmVolumeVectorOperation.h" #include "AlgorithmVolumeWarpfieldAffineRegression.h" #include "AlgorithmVolumeWarpfieldResample.h" #include "OperationAddToSpecFile.h" #include "OperationBackendAverageDenseROI.h" #include "OperationBackendAverageROICorrelation.h" #include "OperationBorderExportColorTable.h" #include "OperationBorderFileExportToCaret5.h" #include "OperationBorderLength.h" #include "OperationBorderMerge.h" #include "OperationCiftiChangeMapping.h" #include "OperationCiftiChangeTimestep.h" #include "OperationCiftiConvert.h" #include "OperationCiftiConvertToScalar.h" #include "OperationCiftiCopyMapping.h" #include "OperationCiftiCreateDenseFromTemplate.h" #include "OperationCiftiCreateParcellatedFromTemplate.h" #include "OperationCiftiCreateScalarSeries.h" #include "OperationCiftiEstimateFWHM.h" #include "OperationCiftiExportDenseMapping.h" #include "OperationCiftiLabelExportTable.h" #include "OperationCiftiLabelImport.h" #include "OperationCiftiMath.h" #include "OperationCiftiMerge.h" #include "OperationCiftiPalette.h" #include "OperationCiftiResampleDconnMemory.h" #include "AlgorithmCiftiRestrictDenseMap.h" #include "OperationCiftiROIAverage.h" #include "OperationCiftiSeparateAll.h" #include "OperationCiftiStats.h" #include "OperationCiftiWeightedStats.h" #include "OperationConvertAffine.h" #include "OperationConvertFiberOrientations.h" #include "OperationConvertMatrix4ToMatrix2.h" #include "OperationConvertMatrix4ToWorkbenchSparse.h" #include "OperationConvertWarpfield.h" #include "OperationEstimateFiberBinghams.h" #include "OperationFileConvert.h" #include "OperationFileInformation.h" #include "OperationFociCreate.h" #include "OperationFociGetProjectionVertex.h" #include "OperationFociListCoords.h" #include "OperationGiftiConvert.h" #include "OperationLabelExportTable.h" #include "OperationLabelMask.h" #include "OperationLabelMerge.h" #include "OperationMetadataRemoveProvenance.h" #include "OperationMetadataStringReplace.h" #include "OperationMetricConvert.h" #include "OperationMetricLabelImport.h" #include "OperationMetricMask.h" #include "OperationMetricMath.h" #include "OperationMetricMerge.h" #include "OperationMetricPalette.h" #include "OperationMetricStats.h" #include "OperationMetricVertexSum.h" #include "OperationMetricWeightedStats.h" #include "OperationNiftiInformation.h" #include "OperationProbtrackXDotConvert.h" #include "OperationSceneFileMerge.h" #include "OperationSceneFileRelocate.h" #include "OperationSetMapName.h" #include "OperationSetMapNames.h" #include "OperationSetStructure.h" #include "OperationShowScene.h" #include "OperationSpecFileMerge.h" #include "OperationSpecFileRelocate.h" #include "OperationSurfaceClosestVertex.h" #include "OperationSurfaceCoordinatesToMetric.h" #include "OperationSurfaceCutResample.h" #include "OperationSurfaceFlipNormals.h" #include "OperationSurfaceGeodesicDistance.h" #include "OperationSurfaceGeodesicDistanceAllToAll.h" #include "OperationSurfaceGeodesicROIs.h" #include "OperationSurfaceInformation.h" #include "OperationSurfaceNormals.h" #include "OperationSurfaceSetCoordinates.h" #include "OperationSurfaceVertexAreas.h" #include "OperationVolumeCapturePlane.h" #include "OperationVolumeCopyExtensions.h" #include "OperationVolumeCreate.h" #include "OperationVolumeLabelExportTable.h" #include "OperationVolumeLabelImport.h" #include "OperationVolumeMath.h" #include "OperationVolumeMerge.h" #include "OperationVolumePalette.h" #include "OperationVolumeReorient.h" #include "OperationVolumeSetSpace.h" #include "OperationVolumeStats.h" #include "OperationVolumeWeightedStats.h" #include "OperationWbsparseMergeDense.h" #include "OperationZipSceneFile.h" #include "OperationZipSpecFile.h" #include "AlgorithmException.h" #include "ApplicationInformation.h" #include "CommandParser.h" #include "OperationException.h" #include "CommandClassAddMember.h" #include "CommandClassCreate.h" #include "CommandClassCreateAlgorithm.h" #include "CommandClassCreateEnum.h" #include "CommandClassCreateOperation.h" #include "CommandC11xTesting.h" #include "CommandUnitTest.h" #include "ProgramParameters.h" #include "CaretLogger.h" #include "dot_wrapper.h" #include "StructureEnum.h" #include #include using namespace caret; using namespace std; /** * Get the command operation manager. * * return * Pointer to the command operation manager. */ CommandOperationManager* CommandOperationManager::getCommandOperationManager() { if (singletonCommandOperationManager == NULL) { singletonCommandOperationManager = new CommandOperationManager(); } return singletonCommandOperationManager; } /** * Delete the command operation manager. */ void CommandOperationManager::deleteCommandOperationManager() { if (singletonCommandOperationManager != NULL) { delete singletonCommandOperationManager; singletonCommandOperationManager = NULL; } } /** * Constructor. */ CommandOperationManager::CommandOperationManager() { this->commandOperations.push_back(new CommandParser(new AutoAlgorithmAnnotationResample())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmBorderResample())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmBorderToVertices())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiAllLabelsToROIs())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiAverage())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiAverageDenseROI())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiAverageROICorrelation())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiCorrelation())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiCorrelationGradient())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiCreateDenseScalar())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiCreateDenseTimeseries())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiCreateLabel())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiCrossCorrelation())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiDilate())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiErode())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiExtrema())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiFalseCorrelation())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiFindClusters())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiGradient())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiLabelAdjacency())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiLabelModifyKeys())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiLabelProbability())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiLabelToBorder())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiLabelToROI())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiMergeDense())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiMergeParcels())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiPairwiseCorrelation())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiParcellate())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiParcelMappingToLabel())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiReduce())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiReorder())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiReplaceStructure())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiResample())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiRestrictDenseMap())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiROIsFromExtrema())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiSeparate())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiSmoothing())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiTranspose())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCiftiVectorOperation())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmCreateSignedDistanceVolume())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmFiberDotProducts())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmFociResample())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmGiftiAllLabelsToROIs())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmGiftiLabelAddPrefix())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmGiftiLabelToROI())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmLabelDilate())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmLabelErode())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmLabelModifyKeys())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmLabelProbability())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmLabelResample())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmLabelToBorder())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmLabelToVolumeMapping())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmMetricDilate())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmMetricErode())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmMetricEstimateFWHM())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmMetricExtrema())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmMetricFalseCorrelation())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmMetricFillHoles())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmMetricFindClusters())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmMetricGradient())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmMetricReduce())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmMetricRegression())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmMetricRemoveIslands())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmMetricResample())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmMetricROIsFromExtrema())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmMetricROIsToBorder())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmMetricSmoothing())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmMetricTFCE())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmMetricToVolumeMapping())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmMetricVectorOperation())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmMetricVectorTowardROI())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmNodesInsideBorder()));//-border-to-rois this->commandOperations.push_back(new CommandParser(new AutoAlgorithmSignedDistanceToSurface())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmSurfaceAffineRegression())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmSurfaceApplyAffine())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmSurfaceApplyWarpfield())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmSurfaceAverage())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmSurfaceCortexLayer())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmSurfaceCreateSphere())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmSurfaceCurvature())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmSurfaceDistortion())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmSurfaceFlipLR())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmSurfaceGenerateInflated())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmSurfaceInflation())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmSurfaceMatch())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmSurfaceModifySphere())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmSurfaceResample())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmSurfaceSmoothing())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmSurfaceSphereProjectUnproject())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmSurfaceToSurface3dDistance())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmSurfaceWedgeVolume())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeAffineResample())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeAllLabelsToROIs())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeDilate())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeDistortion())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeErode())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeEstimateFWHM())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeExtrema())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeFillHoles())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeFindClusters())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeGradient())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeLabelModifyKeys())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeLabelProbability())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeLabelToROI())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeLabelToSurfaceMapping())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeParcelResampling())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeParcelResamplingGeneric())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeParcelSmoothing())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeReduce())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeRemoveIslands())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeROIsFromExtrema())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeSmoothing())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeTFCE())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeToSurfaceMapping())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeVectorOperation())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeWarpfieldAffineRegression())); this->commandOperations.push_back(new CommandParser(new AutoAlgorithmVolumeWarpfieldResample())); this->commandOperations.push_back(new CommandParser(new AutoOperationAddToSpecFile())); this->commandOperations.push_back(new CommandParser(new AutoOperationBackendAverageDenseROI())); this->commandOperations.push_back(new CommandParser(new AutoOperationBackendAverageROICorrelation())); this->commandOperations.push_back(new CommandParser(new AutoOperationBorderExportColorTable())); this->commandOperations.push_back(new CommandParser(new AutoOperationBorderFileExportToCaret5())); this->commandOperations.push_back(new CommandParser(new AutoOperationBorderLength())); this->commandOperations.push_back(new CommandParser(new AutoOperationBorderMerge())); this->commandOperations.push_back(new CommandParser(new AutoOperationCiftiChangeMapping())); this->commandOperations.push_back(new CommandParser(new AutoOperationCiftiConvert())); this->commandOperations.push_back(new CommandParser(new AutoOperationCiftiCreateDenseFromTemplate())); this->commandOperations.push_back(new CommandParser(new AutoOperationCiftiCreateParcellatedFromTemplate())); this->commandOperations.push_back(new CommandParser(new AutoOperationCiftiCreateScalarSeries())); this->commandOperations.push_back(new CommandParser(new AutoOperationCiftiEstimateFWHM())); this->commandOperations.push_back(new CommandParser(new AutoOperationCiftiExportDenseMapping())); this->commandOperations.push_back(new CommandParser(new AutoOperationCiftiLabelExportTable())); this->commandOperations.push_back(new CommandParser(new AutoOperationCiftiLabelImport())); this->commandOperations.push_back(new CommandParser(new AutoOperationCiftiMath())); this->commandOperations.push_back(new CommandParser(new AutoOperationCiftiMerge())); this->commandOperations.push_back(new CommandParser(new AutoOperationCiftiPalette())); this->commandOperations.push_back(new CommandParser(new AutoOperationCiftiResampleDconnMemory())); this->commandOperations.push_back(new CommandParser(new AutoOperationCiftiROIAverage())); this->commandOperations.push_back(new CommandParser(new AutoOperationCiftiStats())); this->commandOperations.push_back(new CommandParser(new AutoOperationCiftiWeightedStats())); this->commandOperations.push_back(new CommandParser(new AutoOperationConvertAffine())); this->commandOperations.push_back(new CommandParser(new AutoOperationConvertFiberOrientations())); this->commandOperations.push_back(new CommandParser(new AutoOperationConvertMatrix4ToMatrix2())); this->commandOperations.push_back(new CommandParser(new AutoOperationConvertMatrix4ToWorkbenchSparse())); this->commandOperations.push_back(new CommandParser(new AutoOperationConvertWarpfield())); this->commandOperations.push_back(new CommandParser(new AutoOperationEstimateFiberBinghams())); this->commandOperations.push_back(new CommandParser(new AutoOperationFileConvert())); this->commandOperations.push_back(new CommandParser(new AutoOperationFileInformation())); this->commandOperations.push_back(new CommandParser(new AutoOperationFociCreate())); this->commandOperations.push_back(new CommandParser(new AutoOperationFociGetProjectionVertex())); this->commandOperations.push_back(new CommandParser(new AutoOperationFociListCoords())); this->commandOperations.push_back(new CommandParser(new AutoOperationGiftiConvert())); this->commandOperations.push_back(new CommandParser(new AutoOperationLabelExportTable())); this->commandOperations.push_back(new CommandParser(new AutoOperationLabelMask())); this->commandOperations.push_back(new CommandParser(new AutoOperationLabelMerge())); this->commandOperations.push_back(new CommandParser(new AutoOperationMetadataRemoveProvenance())); this->commandOperations.push_back(new CommandParser(new AutoOperationMetadataStringReplace())); this->commandOperations.push_back(new CommandParser(new AutoOperationMetricConvert())); this->commandOperations.push_back(new CommandParser(new AutoOperationMetricLabelImport())); this->commandOperations.push_back(new CommandParser(new AutoOperationMetricMask())); this->commandOperations.push_back(new CommandParser(new AutoOperationMetricMath())); this->commandOperations.push_back(new CommandParser(new AutoOperationMetricMerge())); this->commandOperations.push_back(new CommandParser(new AutoOperationMetricPalette())); this->commandOperations.push_back(new CommandParser(new AutoOperationMetricStats())); this->commandOperations.push_back(new CommandParser(new AutoOperationMetricWeightedStats())); this->commandOperations.push_back(new CommandParser(new AutoOperationNiftiInformation())); this->commandOperations.push_back(new CommandParser(new AutoOperationProbtrackXDotConvert())); this->commandOperations.push_back(new CommandParser(new AutoOperationSceneFileMerge())); this->commandOperations.push_back(new CommandParser(new AutoOperationSceneFileRelocate())); this->commandOperations.push_back(new CommandParser(new AutoOperationSetMapNames())); this->commandOperations.push_back(new CommandParser(new AutoOperationSetStructure())); if (OperationShowScene::isShowSceneCommandAvailable()) { this->commandOperations.push_back(new CommandParser(new AutoOperationShowScene())); } this->commandOperations.push_back(new CommandParser(new AutoOperationSpecFileMerge())); this->commandOperations.push_back(new CommandParser(new AutoOperationSpecFileRelocate())); this->commandOperations.push_back(new CommandParser(new AutoOperationSurfaceClosestVertex())); this->commandOperations.push_back(new CommandParser(new AutoOperationSurfaceCoordinatesToMetric())); this->commandOperations.push_back(new CommandParser(new AutoOperationSurfaceCutResample())); this->commandOperations.push_back(new CommandParser(new AutoOperationSurfaceFlipNormals())); this->commandOperations.push_back(new CommandParser(new AutoOperationSurfaceGeodesicDistance())); this->commandOperations.push_back(new CommandParser(new AutoOperationSurfaceGeodesicDistanceAllToAll())); this->commandOperations.push_back(new CommandParser(new AutoOperationSurfaceGeodesicROIs())); this->commandOperations.push_back(new CommandParser(new AutoOperationSurfaceInformation())); this->commandOperations.push_back(new CommandParser(new AutoOperationSurfaceNormals())); this->commandOperations.push_back(new CommandParser(new AutoOperationSurfaceSetCoordinates())); this->commandOperations.push_back(new CommandParser(new AutoOperationSurfaceVertexAreas())); this->commandOperations.push_back(new CommandParser(new AutoOperationVolumeCapturePlane())); this->commandOperations.push_back(new CommandParser(new AutoOperationVolumeCopyExtensions())); this->commandOperations.push_back(new CommandParser(new AutoOperationVolumeCreate())); this->commandOperations.push_back(new CommandParser(new AutoOperationVolumeLabelExportTable())); this->commandOperations.push_back(new CommandParser(new AutoOperationVolumeLabelImport())); this->commandOperations.push_back(new CommandParser(new AutoOperationVolumeMath())); this->commandOperations.push_back(new CommandParser(new AutoOperationVolumeMerge())); this->commandOperations.push_back(new CommandParser(new AutoOperationVolumePalette())); this->commandOperations.push_back(new CommandParser(new AutoOperationVolumeReorient())); this->commandOperations.push_back(new CommandParser(new AutoOperationVolumeSetSpace())); this->commandOperations.push_back(new CommandParser(new AutoOperationVolumeStats())); this->commandOperations.push_back(new CommandParser(new AutoOperationVolumeWeightedStats())); this->commandOperations.push_back(new CommandParser(new AutoOperationWbsparseMergeDense())); this->commandOperations.push_back(new CommandParser(new AutoOperationZipSceneFile())); this->commandOperations.push_back(new CommandParser(new AutoOperationZipSpecFile())); this->commandOperations.push_back(new CommandClassAddMember()); this->commandOperations.push_back(new CommandClassCreate()); this->commandOperations.push_back(new CommandClassCreateAlgorithm()); this->commandOperations.push_back(new CommandClassCreateEnum()); this->commandOperations.push_back(new CommandClassCreateOperation()); #ifdef WORKBENCH_HAVE_C11X this->commandOperations.push_back(new CommandC11xTesting()); #endif // WORKBENCH_HAVE_C11X this->commandOperations.push_back(new CommandUnitTest()); this->deprecatedOperations.push_back(new CommandParser(new AutoOperationCiftiChangeTimestep())); this->deprecatedOperations.push_back(new CommandParser(new AutoOperationCiftiConvertToScalar())); this->deprecatedOperations.push_back(new CommandParser(new AutoOperationCiftiCopyMapping())); this->deprecatedOperations.push_back(new CommandParser(new AutoOperationCiftiSeparateAll())); this->deprecatedOperations.push_back(new CommandParser(new AutoOperationMetricVertexSum())); this->deprecatedOperations.push_back(new CommandParser(new AutoOperationSetMapName())); } /** * Destructor. */ CommandOperationManager::~CommandOperationManager() { uint64_t numberOfCommands = this->commandOperations.size(); for (uint64_t i = 0; i < numberOfCommands; i++) { delete this->commandOperations[i]; this->commandOperations[i] = NULL; } this->commandOperations.clear(); uint64_t numberOfDeprecated = this->deprecatedOperations.size(); for (uint64_t i = 0; i < numberOfDeprecated; i++) { delete this->deprecatedOperations[i]; this->deprecatedOperations[i] = NULL; } this->deprecatedOperations.clear(); } namespace { //quick hack to convert type argument to internal integer int16_t stringToCiftiType(const AString& input) { map nameToCode; nameToCode["INT8"] = NIFTI_TYPE_INT8; nameToCode["UINT8"] = NIFTI_TYPE_UINT8; nameToCode["INT16"] = NIFTI_TYPE_INT16; nameToCode["UINT16"] = NIFTI_TYPE_UINT16; nameToCode["INT32"] = NIFTI_TYPE_INT32; nameToCode["UINT32"] = NIFTI_TYPE_UINT32; nameToCode["INT64"] = NIFTI_TYPE_INT64; nameToCode["UINT64"] = NIFTI_TYPE_UINT64; nameToCode["FLOAT32"] = NIFTI_TYPE_FLOAT32; nameToCode["FLOAT64"] = NIFTI_TYPE_FLOAT64; nameToCode["FLOAT128"] = NIFTI_TYPE_FLOAT128; map::iterator iter = nameToCode.find(input); if (iter == nameToCode.end()) { throw CommandException("Unrecognized cifti datatype: '" + input + "'"); } return iter->second; } } /** * Run a command. * * @param parameters * Reference to the command's parameters. * @throws CommandException * If the command failed. */ void CommandOperationManager::runCommand(ProgramParameters& parameters) { vector globalOptionArgs; bool preventProvenance = getGlobalOption(parameters, "-disable-provenance", 0, globalOptionArgs);//check these BEFORE we test if we have a command switch, because they remove the switch and arguments from the ProgramParameters if (getGlobalOption(parameters, "-logging", 1, globalOptionArgs)) { bool valid = false; const LogLevelEnum::Enum level = LogLevelEnum::fromName(globalOptionArgs[0], &valid); if (!valid) throw CommandException("unrecognized logging level: '" + globalOptionArgs[0] + "'"); CaretLogger::getLogger()->setLevel(level); } if (getGlobalOption(parameters, "-simd", 1, globalOptionArgs)) { bool valid = false; const DotSIMDEnum::Enum impl = DotSIMDEnum::fromName(globalOptionArgs[0], &valid); if (!valid) throw CommandException("unrecognized SIMD type: '" + globalOptionArgs[0] + "'"); DotSIMDEnum::Enum retval = dot_set_impl(impl); if (impl != DOT_AUTO && retval != impl) { CaretLogWarning("SIMD type '" + DotSIMDEnum::toName(impl) + "' not supported (could be cpu, compiler, or build options), using '" + DotSIMDEnum::toName(retval) + "'"); } } int16_t ciftiDType = NIFTI_TYPE_FLOAT32; bool ciftiScale = false; double ciftiMin = -1.0, ciftiMax = -1.0; if (getGlobalOption(parameters, "-cifti-output-datatype", 1, globalOptionArgs)) { ciftiDType = stringToCiftiType(globalOptionArgs[0]); } if (getGlobalOption(parameters, "-cifti-output-range", 2, globalOptionArgs)) { ciftiScale = true; bool valid = false; ciftiMin = globalOptionArgs[0].toDouble(&valid); if (!valid) throw CommandException("non-numeric option to -cifti-output-range: '" + globalOptionArgs[0] + "'"); ciftiMax = globalOptionArgs[1].toDouble(&valid); if (!valid) throw CommandException("non-numeric option to -cifti-output-range: '" + globalOptionArgs[1] + "'"); } const uint64_t numberOfCommands = this->commandOperations.size(); const uint64_t numberOfDeprecated = this->deprecatedOperations.size(); if (parameters.hasNext() == false) { printHelpInfo(); return; } AString commandSwitch; commandSwitch = fixUnicode(parameters.nextString("Command Name"), false); //hardcode program name, instead of taking it from the parameters, so that it doesn't include path or show wrapper script details const AString myProgramName = "wb_command"; if (commandSwitch == "-help") { printHelpInfo(); } else if (commandSwitch == "-arguments-help") { printArgumentsHelp(); } else if (commandSwitch == "-global-options") { printGlobalOptions(); } else if (commandSwitch == "-cifti-help") { printCiftiHelp(); } else if (commandSwitch == "-gifti-help") { printGiftiHelp(); } else if (commandSwitch == "-volume-help") { printVolumeHelp(); } else if (commandSwitch == "-parallel-help") { printParallelHelp(myProgramName); } else if (commandSwitch == "-version") { printVersionInfo(); } else if (commandSwitch == "-list-commands") { printAllCommands(); } else if (commandSwitch == "-list-deprecated-commands") { printDeprecatedCommands(); } else if (commandSwitch == "-all-commands-help") { printAllCommandsHelpInfo(myProgramName); } else { CommandOperation* operation = NULL; for (uint64_t i = 0; i < numberOfCommands; i++) { if (this->commandOperations[i]->getCommandLineSwitch() == commandSwitch) { operation = this->commandOperations[i]; break; } } if (operation == NULL) { for (uint64_t i = 0; i < numberOfDeprecated; i++) { if (this->deprecatedOperations[i]->getCommandLineSwitch() == commandSwitch) { operation = this->deprecatedOperations[i]; break; } } } if (operation == NULL) { if (!parameters.hasNext()) { printAllCommandsMatching(commandSwitch); } else { throw CommandException("Command \"" + commandSwitch + "\" not found."); } } else { if (!parameters.hasNext() && operation->takesParameters()) { cout << operation->getHelpInformation(myProgramName) << endl; } else { if (ciftiScale) { operation->setCiftiOutputDTypeAndScale(ciftiDType, ciftiMin, ciftiMax); } else { operation->setCiftiOutputDTypeNoScale(ciftiDType); } operation->execute(parameters, preventProvenance); } } } } AString CommandOperationManager::doCompletion(ProgramParameters& parameters, const bool& useExtGlob) { AString ret; vector globalOptionArgs; /*OptionInfo provInfo = */parseGlobalOption(parameters, "-disable-provenance", 0, globalOptionArgs, true);//we need to at least strip out the global options for other parsing to work OptionInfo loggingInfo = parseGlobalOption(parameters, "-logging", 1, globalOptionArgs, true);//the previous option doesn't take arguments, doesn't need completion testing if (loggingInfo.specified && !loggingInfo.complete) {//user is tab completing the logging option, and as it only takes one argument, we know what the completions are vector logLevels; LogLevelEnum::getAllEnums(logLevels); ret = "wordlist "; for (int i = 0; i < (int)logLevels.size(); ++i) { if (i != 0) ret += "\\ ";//backslash-escaped space to leave the list of levels as one word ret += LogLevelEnum::toName(logLevels[i]); } return ret; } OptionInfo simdInfo = parseGlobalOption(parameters, "-simd", 1, globalOptionArgs, true);//the previous option doesn't take arguments, doesn't need completion testing if (simdInfo.specified && !simdInfo.complete) {//user is tab completing the logging option, and as it only takes one argument, we know what the completions are vector simdTypes = DotSIMDEnum::getAllEnums(); ret = "wordlist "; for (int i = 0; i < (int)simdTypes.size(); ++i) { if (i != 0) ret += "\\ ";//backslash-escaped space to leave the list of levels as one word ret += DotSIMDEnum::toName(simdTypes[i]); } return ret; } OptionInfo ciftiDTypeInfo = parseGlobalOption(parameters, "-cifti-output-datatype", 1, globalOptionArgs, true); if (ciftiDTypeInfo.specified && !ciftiDTypeInfo.complete) { return "wordlist INT8 UINT8 INT16 UINT16 INT32 UINT32 INT64 UINT64 FLOAT32 FLOAT64 FLOAT128"; } OptionInfo ciftiRangeInfo = parseGlobalOption(parameters, "-cifti-output-range", 2, globalOptionArgs, true); if (ciftiRangeInfo.specified && !ciftiRangeInfo.complete) {//can't tab complete a literal number return ""; } ret = "wordlist -disable-provenance\\ -logging\\ -simd\\ -cifti-output-datatype\\ -cifti-output-range";//we could prevent suggesting an already-provided global option, but that would be a bit surprising const uint64_t numberOfCommands = this->commandOperations.size(); const uint64_t numberOfDeprecated = this->deprecatedOperations.size(); if (!parameters.hasNext()) {//suggest all commands, including deprecated and informational (order doesn't matter, bash sorts them before displaying) ret += "\\ -help\\ -arguments-help\\ -global-options\\ -parallel-help\\ -cifti-help\\ -gifti-help\\ -volume-help\\ -version\\ -list-commands\\ -list-deprecated-commands\\ -all-commands-help"; for (uint64_t i = 0; i < numberOfCommands; i++) { ret += "\\ " + commandOperations[i]->getCommandLineSwitch(); } for (uint64_t i = 0; i < numberOfDeprecated; i++) { ret += "\\ " + deprecatedOperations[i]->getCommandLineSwitch(); } return ret; } //only processing commands take additional arguments, so we can now ignore -help and similar AString commandSwitch; commandSwitch = fixUnicode(parameters.nextString("Command Name"), true); for (uint64_t i = 0; i < numberOfCommands; i++) { if (commandOperations[i]->getCommandLineSwitch() == commandSwitch) { AString commandCompletion = commandOperations[i]->doCompletion(parameters, useExtGlob); if (commandCompletion != "") { if (ret != "") ret += " "; ret += commandCompletion; } return ret; } } for (uint64_t i = 0; i < numberOfDeprecated; i++) { if (deprecatedOperations[i]->getCommandLineSwitch() == commandSwitch) { AString commandCompletion = deprecatedOperations[i]->doCompletion(parameters, useExtGlob); if (commandCompletion != "") { if (ret != "") ret += " "; ret += commandCompletion; } return ret; } } //if we get here, then the operation switch is wrong, or goes to an informational option return ret; } bool CommandOperationManager::getGlobalOption(ProgramParameters& parameters, const AString& optionString, const int& numArgs, vector& arguments) { OptionInfo retval = parseGlobalOption(parameters, optionString, numArgs, arguments, false); if (retval.specified && !retval.complete) { throw CommandException("missing argument #" + AString::number(arguments.size() + 1) + " to global option "); } return retval.specified; } CommandOperationManager::OptionInfo CommandOperationManager::parseGlobalOption(ProgramParameters& parameters, const AString& optionString, const int& numArgs, vector& arguments, const bool& quiet) { OptionInfo ret;//initializes to false, false, -1 int32_t initialIndex = parameters.getParameterIndex();//before returning, restore initial index - also, only search from current index onwards while (parameters.hasNext()) { bool hyphenReplaced = false; AString testRaw = parameters.nextString("global option"); AString test = testRaw.fixUnicodeHyphens(&hyphenReplaced, NULL, quiet); if (test == optionString) { if (!quiet && hyphenReplaced) { CaretLogWarning("replaced non-ascii hyphen/dash characters in global option '" + testRaw + "' with ascii '-'"); }//delay parameter removal until we know we have all arguments if (!quiet && ret.specified) { CaretLogInfo("global option '" + optionString + "' specified multiple times"); } arguments.clear(); OptionInfo temp;//initializes to false, false, -1 temp.specified = true; temp.index = parameters.getParameterIndex() - 1;//the function actually reports the index of the next parameter for (int i = 0; i < numArgs; ++i) { if (!parameters.hasNext()) { return temp;//complete is still false - since this is a fatal parsing error, don't reset the parameter index } arguments.push_back(parameters.nextString("global option argument")); } for (int i = 0; i < numArgs; ++i) { parameters.remove();//remove arguments } parameters.remove();//remove option switch temp.complete = true; ret = temp; } } parameters.setParameterIndex(initialIndex); return ret; } /** * Print all of the commands. */ void CommandOperationManager::printAllCommands() { map cmdMap; int64_t longestSwitch = 0; const uint64_t numberOfCommands = this->commandOperations.size(); for (uint64_t i = 0; i < numberOfCommands; i++) { CommandOperation* op = this->commandOperations[i]; const AString cmdSwitch = op->getCommandLineSwitch(); const int64_t switchLength = cmdSwitch.length(); if (switchLength > longestSwitch) { longestSwitch = switchLength; } cmdMap.insert(make_pair(cmdSwitch, op->getOperationShortDescription())); #ifndef NDEBUG const AString helpInfo = op->getHelpInformation("");//TSC: generating help info takes a little processing (populating and walking an OperationParameters tree for each command) if (helpInfo.isEmpty()) {//So, test the same define as for asserts and skip this check in release CaretLogSevere("Command has no help info: " + cmdSwitch); } #endif } for (map::iterator iter = cmdMap.begin(); iter != cmdMap.end(); iter++) { AString cmdSwitch = iter->first; cmdSwitch = cmdSwitch.leftJustified(longestSwitch + 2, ' '); AString description = iter->second; cout << qPrintable(cmdSwitch) << qPrintable(description) << endl; } } void CommandOperationManager::printDeprecatedCommands() { map cmdMap; int64_t longestSwitch = 0; const uint64_t numberOfDeprecated = this->deprecatedOperations.size(); for (uint64_t i = 0; i < numberOfDeprecated; i++) { CommandOperation* op = this->deprecatedOperations[i]; const AString cmdSwitch = op->getCommandLineSwitch(); const int64_t switchLength = cmdSwitch.length(); if (switchLength > longestSwitch) { longestSwitch = switchLength; } cmdMap.insert(make_pair(cmdSwitch, op->getOperationShortDescription())); #ifndef NDEBUG const AString helpInfo = op->getHelpInformation("");//TSC: generating help info takes a little processing (populating and walking an OperationParameters tree for each command) if (helpInfo.isEmpty()) {//So, test the same define as for asserts and skip this check in release CaretLogSevere("Command has no help info: " + cmdSwitch); } #endif } for (map::iterator iter = cmdMap.begin(); iter != cmdMap.end(); iter++) { AString cmdSwitch = iter->first; cmdSwitch = cmdSwitch.leftJustified(longestSwitch + 2, ' '); AString description = iter->second; cout << qPrintable(cmdSwitch) << qPrintable(description) << endl; } } /** * Print all of the commands matching a partial switch. */ void CommandOperationManager::printAllCommandsMatching(const AString& partialSwitch) { map cmdMap; int64_t longestSwitch = -1; const uint64_t numberOfCommands = this->commandOperations.size(); for (uint64_t i = 0; i < numberOfCommands; i++) { CommandOperation* op = this->commandOperations[i]; const AString cmdSwitch = op->getCommandLineSwitch(); if (cmdSwitch.startsWith(partialSwitch)) { const int64_t switchLength = cmdSwitch.length(); if (switchLength > longestSwitch) { longestSwitch = switchLength; } cmdMap.insert(make_pair(cmdSwitch, op->getOperationShortDescription())); #ifndef NDEBUG const AString helpInfo = op->getHelpInformation("");//TSC: generating help info takes a little processing (populating and walking an OperationParameters tree for each command) if (helpInfo.isEmpty()) {//So, test the same define as for asserts and skip this check in release CaretLogSevere("Command has no help info: " + cmdSwitch); } #endif } } if (longestSwitch == -1)//no command found { throw CommandException("the switch '" + partialSwitch + "' does not match any processing commands"); } for (map::iterator iter = cmdMap.begin(); iter != cmdMap.end(); iter++) { AString cmdSwitch = iter->first; if (cmdSwitch.startsWith(partialSwitch)) { cmdSwitch = cmdSwitch.leftJustified(longestSwitch + 2, ' '); AString description = iter->second; cout << qPrintable(cmdSwitch) << qPrintable(description) << endl; } } } /** * Get the command operations. * * @return * A vector containing the command operations. * Do not modify the returned value. */ vector CommandOperationManager::getCommandOperations() { return this->commandOperations; } void CommandOperationManager::printHelpInfo() { cout << ApplicationInformation().getSummaryInformationInString("\n"); //guide for wrap, assuming 80 columns: | cout << endl << "Information options:" << endl; cout << " -help show this help info" << endl; cout << " -arguments-help explain the format of subcommand help info" << endl; cout << " -global-options display options that can be added to any command" << endl; cout << " -parallel-help details on how wb_command uses parallelization" << endl; cout << " -cifti-help explain the cifti file format and related terms" << endl; cout << " -gifti-help explain the gifti file format (metric, surface)" << endl; cout << " -volume-help explain volume files, including label volumes" << endl; cout << " -version show extended version information" << endl; cout << " -list-commands list all processing subcommands" << endl; cout << " -list-deprecated-commands list deprecated subcommands" << endl; cout << " -all-commands-help show all processing subcommands and their help" << endl; cout << " info - VERY LONG" << endl; cout << endl; cout << "To get the help information of a processing subcommand, run it without any" << endl; cout << " additional arguments." << endl; cout << endl; cout << "If the first argument is not recognized, all processing commands that start" << endl; cout << " with the argument are displayed." << endl; cout << endl; } void CommandOperationManager::printArgumentsHelp() { //guide for wrap, assuming 80 columns: | cout << " To get the help information on a subcommand, run it without any additional" << endl; cout << " arguments. Options can occur in any order, however suboptions and arguments" << endl; cout << " to options must occur next to their parent option. The easiest way to get" << endl; cout << " this right is to specify options and arguments in the order they are listed." << endl; cout << " As an example, consider this abbreviated version of the -volume-math help" << endl; cout << " information:" << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << "$ wb_command -volume-math" << endl; cout << "EVALUATE EXPRESSION ON VOLUME FILES" << endl; cout << " wb_command -volume-math" << endl; cout << " - the expression to evaluate, in quotes" << endl; cout << " - output - the output volume" << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " [-fixnan] - replace NaN results with a value" << endl; cout << " - value to replace NaN with" << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " [-var] - repeatable - a volume file to use as a variable" << endl; cout << " - the name of the variable, as used in the expression" << endl; cout << " - the volume file to use as this variable" << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " [-subvolume] - select a single subvolume" << endl; cout << " - the subvolume number or name" << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " [-repeat] - reuse a single subvolume for each subvolume of calculation" << endl; cout << "..." << endl; cout << " The following functions are supported:" << endl; cout << "..." << endl; cout << " abs: 1 argument, the absolute value of the argument" << endl; cout << "..." << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " '' represents a required input parameter (required parameters" << endl; cout << " are marked with the < and > symbols), and ' - output' represents" << endl; cout << " a required output filename (marked by the presence of the word 'output')." << endl; cout << " '[-fixnan]' represents an option (marked with the [ and ] symbols), taking" << endl; cout << " one required parameter '' (the indentation level indicates what" << endl; cout << " parameters and suboptions are associated with a given option), and '[-var] -" << endl; cout << " repeatable' denotes a repeatable option (marked by the presence of the word" << endl; cout << " 'repeatable') with required parameters '' and '', and two" << endl; cout << " suboptions: '[-subvolume]', which has a required parameter '', and" << endl; cout << " '[-repeat]', which takes no parameters." << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " Each option starts a new scope, and all options and arguments end any scope" << endl; cout << " that they are not valid in. This means that for any option, you must" << endl; cout << " specify all of its arguments and any desired suboptions before specifying" << endl; cout << " any other option or argument on the same or a previous level. For example," << endl; cout << " this annotated command is valid:" << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << "$ wb_command -volume-math 'abs(x)' abs_x.nii.gz -fixnan 0 -var x x.nii.gz" << endl; cout << "annotation: " << endl; cout << endl; cout << " Here is another annotated command that results in the same output, but" << endl; cout << " uses a different order of the options:" << endl; cout << endl; cout << "$ wb_command -volume-math -fixnan 0 'abs(x)' -var x x.nii.gz abs_x.nii.gz" << endl; cout << "annotation: " << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " This next command is invalid, because the -fixnan option ends the scope of" << endl; cout << " the -var option before all of its required arguments are given:" << endl; cout << endl; cout << "wrong: wb_command -volume-math 'abs(x)' abs_x.nii.gz -var x -fixnan 0 x.nii.gz" << endl; cout << endl; //guide for wrap, assuming 80 columns: | cout << " This command is invalid because the -subvolume option occurs after the" << endl; cout << " scope of the -var option has ended due to the -fixnan option:" << endl; cout << endl; cout << "wrong: wb_command -volume-math 'abs(x)' abs_x.nii.gz -var x x.nii.gz -fixnan 0 -subvolume 1" << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " This command is similarly invalid because the -subvolume option occurs" << endl; cout << " after the scope of the -var option has ended due to the volume-out argument:" << endl; cout << endl; cout << "wrong: wb_command -volume-math 'abs(x)' -var x x.nii.gz abs_x.nii.gz -subvolume 1 -fixnan 0" << endl; cout << endl; } void CommandOperationManager::printGlobalOptions() { cout << "Global options (can be added to any command):" << endl; cout << endl; //guide for wrap, assuming 80 columns: | cout << " -disable-provenance don't generate provenance info in output" << endl; cout << " files" << endl; cout << endl; cout << " -cifti-output-datatype write cifti output with the given" << endl; cout << " datatype (default FLOAT32), note that" << endl; cout << " calculation precision is only float32," << endl; cout << " valid values are:" << endl; cout << " INT8" << endl; cout << " UINT8" << endl; cout << " INT16" << endl; cout << " UINT16" << endl; cout << " INT32" << endl; cout << " UINT32" << endl; cout << " INT64" << endl; cout << " UINT64" << endl; cout << " FLOAT32" << endl; cout << " FLOAT64" << endl; cout << " FLOAT128" << endl; cout << endl; //guide for wrap, assuming 80 columns: | cout << " -cifti-output-range write cifti output with scaling and offset" << endl; cout << " header fields such that and " << endl; cout << " are the most extreme values that can be" << endl; cout << " represented, mostly useful with integer" << endl; cout << " output datatypes (see above)" << endl; cout << endl; cout << " -logging set the logging level, valid values are:" << endl; vector logLevels; LogLevelEnum::getAllEnums(logLevels); for (vector::iterator iter = logLevels.begin(); iter != logLevels.end(); iter++) { cout << " " << LogLevelEnum::toName(*iter) << endl; } cout << endl;//add a line after the logging types for readability //guide for wrap, assuming 80 columns: | cout << " -simd set the SIMD implementation to use" << endl; cout << " (currently used only for correlation," << endl; cout << " default AUTO which selects fastest" << endl; cout << " supported), valid values are:" << endl; vector simdTypes = DotSIMDEnum::getAllEnums(); for (vector::iterator iter = simdTypes.begin(); iter != simdTypes.end(); iter++) { cout << " " << DotSIMDEnum::toName(*iter) << endl; } cout << endl; } void CommandOperationManager::printCiftiHelp() { //guide for wrap, assuming 80 columns: | cout << " The CIFTI format is a new data file format intended to make it easier to" << endl; cout << " work with data from multiple disjoint structures at the same time - often" << endl; cout << " this means both hemispheres of cortex as surface data, and other structures" << endl; cout << " as voxel data (amygdala, thalamus, putamen, etc). Additionally, it can" << endl; cout << " exclude locations that are uninteresting for the task at hand (medial wall," << endl; cout << " white matter, csf), preventing them from taking up room in the data of the" << endl; cout << " file. The set of structures and the locations in them that are used in a" << endl; cout << " cifti file are referred to as 'brainordinates', or for the specific case of" << endl; cout << " 'all gray matter locations', 'grayordinates'." << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " However, to explain the cifti format, it is easiest to work from the" << endl; cout << " opposite direction, as it is conceptually simpler. A single cifti file is a" << endl; cout << " single rectangular data matrix (usually 2 dimensions, but supports 3, and" << endl; cout << " may support more in the future), where each dimension is labeled with what" << endl; cout << " we call a 'mapping', each of which uses one of (currently) five possible" << endl; cout << " 'mapping types'. It is the combinations of these mapping types that give" << endl; cout << " rise to the diverse types of cifti files. A single mapping of type 'brain" << endl; cout << " models' (also known as 'dense') can represent both hemispheres and all" << endl; cout << " subcortical structures simultaneously, meaning that only a single matrix" << endl; cout << " dimension is used to represent over a dozen structures, both surface-based" << endl; cout << " and voxel-based. Each mapping contains all information needed to figure out" << endl; cout << " what every index along the matrix dimension means. By putting a dense" << endl; cout << " mapping along both dimensions in a 2D cifti file, you get a brainordinates" << endl; cout << " by brainordinates matrix, which is used for connectivity measures. Notably," << endl; cout << " even if two dimensions use the same mapping *type*, they can have different" << endl; cout << " information in them, for example a connectivity matrix between two different" << endl; cout << " parcellations." << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " The other mapping types that currently may be used in a cifti file are:" << endl; cout << " Parcels: each index refers to a named subset of the brainordinates (i.e." << endl; cout << " 'V1', and the surface vertices in V1)" << endl; cout << " Scalars: each index is simply given a name (i.e. 'Myelin')" << endl; cout << " Series: each index is assigned a quantity in a linear series (i.e., a" << endl; cout << " timeseries of 0 sec, 0.7 sec, 1.4 sec, ...)" << endl; cout << " Labels: each index is assigned a name (i.e., 'Visual Areas'), but also a" << endl; cout << " list of labels that maps integer data values to names and colors (i.e." << endl; cout << " {(5, 'V1', #ff0000), (7, 'V2', #00ff00), ...}" << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " The commands that operate on cifti files often require you to specify which" << endl; cout << " dimension they should operate on. Because cifti files can contain 3" << endl; cout << " dimensions, we specify them as which dimension to operate along, that is, " << endl; cout << " the ROW dimension refers to the mapping along the length of a row." << endl; cout << " Additionally, the ROW dimension is the *first* dimension in a cifti file," << endl; cout << " unlike 2D matrices in linear algebra. This means that increasing the value" << endl; cout << " of the first index moves rightwards in the matrix, not downwards." << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " The common types of cifti files and the mapping types they use are:" << endl; cout << " dconn: ROW is dense, COLUMN is dense" << endl; cout << " dscalar: ROW is scalars, COLUMN is dense" << endl; cout << " dtseries: ROW is series, COLUMN is dense" << endl; cout << " dlabel: ROW is labels, COLUMN is dense" << endl; cout << " pconn: ROW is parcels, COLUMN is parcels" << endl; cout << " pdconn: ROW is dense, COLUMN is parcels" << endl; cout << " dpconn: ROW is parcels, COLUMN is dense" << endl; cout << " pscalar: ROW is scalars, COLUMN is parcels" << endl; cout << " ptseries: ROW is series, COLUMN is parcels" << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " For the full details of the CIFTI format, see" << endl; cout << " http://www.nitrc.org/projects/cifti/" << endl; cout << endl;//guide for wrap, assuming 80 columns: | } void CommandOperationManager::printGiftiHelp() { //guide for wrap, assuming 80 columns: | cout << " The GIFTI format is an established data file format intended for use with" << endl; cout << " surface-based data. It has subtypes for geometry (.surf.gii), continuous" << endl; cout << " data (.func.gii, .shape.gii), and integer label data (.label.gii). The" << endl; cout << " files that contain data, rather than geometry, consist mainly of a 2D array," << endl; cout << " with one dimension having length equal to the number of vertices in the" << endl; cout << " surface. Label files (.label.gii) also contain a list of integer values" << endl; cout << " that are used in the file, plus a name and a color for each one. In" << endl; cout << " workbench, the files for continuous data are called 'metric files', and" << endl; cout << " .func.gii is usually the preferred extension, but there is no difference in" << endl; cout << " file format between .func.gii and .shape.gii. Geometry files are simply" << endl; cout << " called 'surface files', and must contain only the coordinate and triangle" << endl; cout << " arrays. Notably, other software may put data arrays (the equivalent of a" << endl; cout << " metric file) into the same file as the geometry information. Workbench does" << endl; cout << " not support this kind of combined format, and you must use other tools to" << endl; cout << " separate the data array from the geometry." << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " For the full details of the GIFTI format, see" << endl; cout << " http://www.nitrc.org/projects/gifti/" << endl; cout << endl;//guide for wrap, assuming 80 columns: | } void CommandOperationManager::printVolumeHelp() { //guide for wrap, assuming 80 columns: | cout << " Volume files are like 3 or 4 dimensional bitmaps, they represent a" << endl; cout << " rectangular grid of (often cubic) voxels, with each voxel having an" << endl; cout << " independent value. Workbench supports oblique volumes, but it is still" << endl; cout << " recommended to deoblique the data before processing it, as other tools may" << endl; cout << " give unexpected results for oblique volume files." << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " Workbench currently only supports volume files in NIfTI format, but supports" << endl; cout << " both version 1 and version 2 of the NIfTI standard:" << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " https://nifti.nimh.nih.gov/nifti-1" << endl; cout << " https://nifti.nimh.nih.gov/nifti-2" << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " Workbench writes volumes in NIfTI-1 format whenever possible, but if one of" << endl; cout << " the dimensions is longer than 32767, it will write the file in NIfTI-2" << endl; cout << " format instead. Specifying '.nii.gz' on the end of the filename will cause" << endl; cout << " workbench to automatically write the volume in compressed format, and this" << endl; cout << " is generally recommended as best practice for volume files." << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " The reason that workbench only supports NIfTI format is that it is widely" << endl; cout << " supported, has well-defined spacing and orientation information, is" << endl; cout << " relatively simple, and supports adding extensions to the header information." << endl; cout << " Workbench uses such an extension to store various things, such as names for" << endl; cout << " each frame in a volume file, storing palette display settings, provenance" << endl; cout << " information, and label names and colors for label-type volume files." << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " The header extension that workbench uses is derived from the caret5 NIfTI" << endl; cout << " extension, and has two main types: scalar-type volume files, and label-type" << endl; cout << " volume files. Commands that require a label volume as input check that the" << endl; cout << " extension is present and set to label type, and the label names, colors, and" << endl; cout << " integer keys are read from the extension. To import a label-like volume" << endl; cout << " into this format, use the -volume-label-import command. Note that other" << endl; cout << " tools will generally remove this label information when they write derived" << endl; cout << " or modified files, as will commands in workbench that are not designed" << endl; cout << " specifically for label volumes (e.g., -volume-math), so you may need to use" << endl; cout << " -volume-label-import after using such commands." << endl; cout << endl;//guide for wrap, assuming 80 columns: | } void CommandOperationManager::printParallelHelp(const AString& programName) { //guide for wrap, assuming 80 columns: | cout << " Many processing commands make use of multithreading so that scripts can" << endl; cout << " finish more quickly. By default, these commands will use all available" << endl; cout << " cores on the system. Because we use OpenMP for the parallelization, this" << endl; cout << " behavior can be controlled through various environment variables. In" << endl; cout << " particular, 'OMP_NUM_THREADS' will set the maximum number of threads it will" << endl; cout << " use, when exported as an environment variable. Additionally, some shells," << endl; cout << " such as bash, have syntax that allows you to set an environment variable for" << endl; cout << " a single command or script, for instance:" << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << "$ OMP_NUM_THREADS=4 "<< programName << " -volume-smoothing input.nii.gz 4 output.nii.gz" << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " If you have a multi-socket system, be aware that the parallelization can be" << endl; cout << " much slower when threads are on different sockets, and this interacts badly" << endl; cout << " with the default behavior of using all available cores. It is advisable to" << endl; cout << " use other tools to restrict the entire script to execute on a single socket," << endl; cout << " especially if a queueing system is involved." << endl; cout << endl;//guide for wrap, assuming 80 columns: | cout << " Also note that wb_view contains a few features that use multithreading" << endl; cout << " (dynamic connectivity, border optimize), which can be controlled by setting" << endl; cout << " the same environment variables before launching wb_view." << endl; cout << endl;//guide for wrap, assuming 80 columns: | } void CommandOperationManager::printVersionInfo() { ApplicationInformation myInfo; vector myLines; myInfo.getAllInformation(myLines); for (int i = 0; i < (int)myLines.size(); ++i) { cout << myLines[i] << endl; } } void CommandOperationManager::printAllCommandsHelpInfo(const AString& programName) { map cmdMap; const uint64_t numberOfCommands = this->commandOperations.size(); for (uint64_t i = 0; i < numberOfCommands; i++) { CommandOperation* op = this->commandOperations[i]; cmdMap[op->getCommandLineSwitch()] = op; } for (map::iterator iter = cmdMap.begin(); iter != cmdMap.end(); iter++) { cout << iter->first << endl; cout << iter->second->getHelpInformation(programName) << endl << endl; } } AString CommandOperationManager::fixUnicode(const AString& input, const bool& quiet) { bool hyphenReplaced = false, otherNonAscii = false; AString ret = input.fixUnicodeHyphens(&hyphenReplaced, &otherNonAscii, quiet); if (otherNonAscii) { throw CaretException("found non-ascii character in operation switch '" + input + "', but one that is not recognized as a dash/hyphen/minus"); } if (!quiet && hyphenReplaced) { CaretLogWarning("replaced non-ascii hyphen/dash characters in operation switch '" + input + "' with ascii '-'"); } return ret; } connectome-workbench-1.4.2/src/Commands/CommandOperationManager.h000066400000000000000000000067201360521144700250730ustar00rootroot00000000000000#ifndef __COMMAND_OPERATION_MANAGER_H__ #define __COMMAND_OPERATION_MANAGER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "CommandException.h" namespace caret { class CommandOperation; class ProgramParameters; /// Manages all command operations. class CommandOperationManager : public CaretObject { public: static CommandOperationManager* getCommandOperationManager(); static void deleteCommandOperationManager(); ~CommandOperationManager(); void runCommand(ProgramParameters& parameters); AString doCompletion(ProgramParameters& parameters, const bool& useExtGlob); std::vector getCommandOperations(); private: CommandOperationManager(); CommandOperationManager(const CommandOperationManager&); CommandOperationManager& operator=(const CommandOperationManager&); void printAllCommands(); void printDeprecatedCommands(); void printAllCommandsMatching(const AString& partialSwitch); void printAllCommandsHelpInfo(const AString& programName); void printHelpInfo(); void printArgumentsHelp(); void printGlobalOptions(); void printCiftiHelp(); void printGiftiHelp(); void printVolumeHelp(); void printParallelHelp(const AString& programName); void printVersionInfo(); bool getGlobalOption(ProgramParameters& parameters, const AString& optionString, const int& numArgs, std::vector& arguments); struct OptionInfo { bool specified; bool complete; int index;//only valid when complete is false, might not be needed OptionInfo() { specified = false; complete = false; index = -1; } }; OptionInfo parseGlobalOption(ProgramParameters& parameters, const AString& optionString, const int& numArgs, std::vector& arguments, const bool& quiet); static AString fixUnicode(const AString& input, const bool& quiet); private: std::vector commandOperations, deprecatedOperations; static CommandOperationManager* singletonCommandOperationManager; }; #ifdef __COMMAND_OPERATION_MANAGER_DEFINE__ CommandOperationManager* CommandOperationManager::singletonCommandOperationManager = NULL; #endif // __COMMAND_OPERATION_MANAGER_DEFINE__ } // namespace #endif // __COMMAND_OPERATION_MANAGER_H__ connectome-workbench-1.4.2/src/Commands/CommandParser.cxx000066400000000000000000001624611360521144700234540ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CommandParser.h" #include "AlgorithmException.h" #include "AnnotationFile.h" #include "ApplicationInformation.h" #include "BorderFile.h" #include "CaretAssert.h" #include "CaretCommandLine.h" #include "CaretDataFileHelper.h" #include "CaretLogger.h" #include "CiftiFile.h" #include "DataFileException.h" #include "FileInformation.h" #include "FociFile.h" #include "GiftiMetaData.h" #include "LabelFile.h" #include "MetricFile.h" #include "OperationException.h" #include "SurfaceFile.h" #include "VolumeFile.h" #include #include using namespace caret; using namespace std; const AString CommandParser::PROVENANCE_NAME = "Provenance"; const AString CommandParser::PARENT_PROVENANCE_NAME = "ParentProvenance"; const AString CommandParser::PROGRAM_PROVENANCE_NAME = "ProgramProvenance"; const AString CommandParser::CWD_PROVENANCE_NAME = "WorkingDirectory"; CommandParser::CommandParser(AutoOperationInterface* myAutoOper) : CommandOperation(myAutoOper->getCommandSwitch(), myAutoOper->getShortDescription()), OperationParserInterface(myAutoOper) { m_doProvenance = true; m_ciftiScale = false; m_ciftiDType = NIFTI_TYPE_FLOAT32; m_ciftiMax = -1.0;//these values won't get used, but don't leave them uninitialized m_ciftiMin = -1.0; } void CommandParser::disableProvenance() { m_doProvenance = false; } void CommandParser::setCiftiOutputDTypeAndScale(const int16_t& dtype, const double& minVal, const double& maxVal) { m_ciftiDType = dtype; m_ciftiMin = minVal; m_ciftiMax = maxVal; m_ciftiScale = true; } void CommandParser::setCiftiOutputDTypeNoScale(const int16_t& dtype) { m_ciftiDType = dtype; m_ciftiMax = -1.0;//for sanity, don't keep any previous value around m_ciftiMin = -1.0; m_ciftiScale = false; } void CommandParser::executeOperation(ProgramParameters& parameters) { CaretPointer myAlgParams(m_autoOper->getParameters());//could be an autopointer, but this is safer vector myOutAssoc; m_provenance = caret_global_commandLine; //the idea is to have m_provenance set before the command executes, so it can be overridden, but have m_parentProvenance set AFTER the processing is complete //the parent provenance should never be generated manually m_parentProvenance = "";//in case someone tries to use the same instance more than once m_workingDir = QDir::currentPath();//get the current path, in case some stupid command changes the working directory //these get set on output files during writeOutput (and for on-disk in provenanceBeforeOperation) parseComponent(myAlgParams.getPointer(), parameters, myOutAssoc);//parsing block parameters.verifyAllParametersProcessed(); makeOnDiskOutputs(myOutAssoc);//check for input on-disk files used as output on-disk files //code to show what arguments map to what parameters should go here if (m_doProvenance) provenanceBeforeOperation(myOutAssoc); m_autoOper->useParameters(myAlgParams.getPointer(), NULL);//TODO: progress status for caret_command? would probably get messed up by any command info output vector uncheckedWarnings = myAlgParams->findUncheckedParams("the command"); for (size_t i = 0; i < uncheckedWarnings.size(); ++i) { CaretLogWarning("developer warning: " + uncheckedWarnings[i]); } if (m_doProvenance) provenanceAfterOperation(myOutAssoc); //TODO: deallocate input files - give abstract parameter a virtual deallocate method? use CaretPointer and rely on reference counting? writeOutput(myOutAssoc); } void CommandParser::showParsedOperation(ProgramParameters& parameters) { CaretPointer myAlgParams(m_autoOper->getParameters());//could be an autopointer, but this is safer vector myOutAssoc; parseComponent(myAlgParams.getPointer(), parameters, myOutAssoc, true);//parsing block parameters.verifyAllParametersProcessed(); //don't execute or write parsed output } void CommandParser::parseComponent(ParameterComponent* myComponent, ProgramParameters& parameters, vector& outAssociation, bool debug) {//IMPORTANT: update completionComponent() and friends with any change to parsing logic for (int i = 0; i < (int)myComponent->m_paramList.size(); ++i) { bool hyphenReplaced = false; //TSC: until someone complains, I say non-ascii dashes don't belong on the command line, EVER AString rawArg = parameters.nextString(myComponent->m_paramList[i]->m_shortName); AString nextArg = rawArg.fixUnicodeHyphens(&hyphenReplaced); if (hyphenReplaced) { CaretLogWarning("replaced non-ascii hyphen/dash characters in argument '" + rawArg + "' with ascii '-'"); } if (!nextArg.isEmpty() && nextArg[0] == '-') { bool success = parseOption(nextArg, myComponent, parameters, outAssociation, debug); if (!success) { switch (myComponent->m_paramList[i]->getType()) { case OperationParametersEnum::STRING: case OperationParametersEnum::INT: case OperationParametersEnum::DOUBLE: break;//it is probably a negative number, so don't throw an exception unless it fails to parse as one default: throw ProgramParametersException("Invalid option \"" + nextArg + "\" while next required argument is <" + myComponent->m_paramList[i]->m_shortName + ">, option is either incorrect, or incorrectly placed"); }; } else { --i; continue;//so skip trying to parse it as a required argument } } const OperationParametersEnum::Enum nextType = myComponent->m_paramList[i]->getType();// need in catch statement below try { switch (myComponent->m_paramList[i]->getType()) { case OperationParametersEnum::ANNOTATION: { CaretPointer myFile(new AnnotationFile()); myFile->readFile(nextArg); if (m_doProvenance) { const GiftiMetaData* md = myFile->getFileMetaData(); if (md != NULL) { AString prov = md->get(PROVENANCE_NAME); if (prov != "") { m_parentProvenance += nextArg + ":\n" + prov + "\n\n"; } } } ((AnnotationParameter*)myComponent->m_paramList[i])->m_parameter = myFile; if (debug) { cout << "Parameter <" << myComponent->m_paramList[i]->m_shortName << "> opened file with name "; cout << nextArg << endl; } break; } case OperationParametersEnum::BOOL: { parameters.backup(); ((BooleanParameter*)myComponent->m_paramList[i])->m_parameter = parameters.nextBoolean(myComponent->m_paramList[i]->m_shortName); if (debug) { cout << "Parameter <" << myComponent->m_paramList[i]->m_shortName << "> parsed as "; cout << (((BooleanParameter*)myComponent->m_paramList[i])->m_parameter ? "true" : "false") << endl; } break; } case OperationParametersEnum::BORDER: { CaretPointer myFile(new BorderFile()); myFile->readFile(nextArg); if (m_doProvenance) { const GiftiMetaData* md = myFile->getFileMetaData(); if (md != NULL) { AString prov = md->get(PROVENANCE_NAME); if (prov != "") { m_parentProvenance += nextArg + ":\n" + prov + "\n\n"; } } } ((BorderParameter*)myComponent->m_paramList[i])->m_parameter = myFile; if (debug) { cout << "Parameter <" << myComponent->m_paramList[i]->m_shortName << "> opened file with name "; cout << nextArg << endl; } break; } case OperationParametersEnum::CIFTI: { FileInformation myInfo(nextArg); CaretPointer myFile(new CiftiFile()); myFile->openFile(nextArg); m_inputCiftiNames[myInfo.getCanonicalFilePath()] = myFile;//track input cifti, so we can check their size if (m_doProvenance)//just an optimization, if we aren't going to write provenance, don't generate it, either { const GiftiMetaData* md = myFile->getCiftiXML().getFileMetaData(); if (md != NULL) { if (md->exists(PROVENANCE_NAME)) { AString provenance = md->get(PROVENANCE_NAME); if (provenance != "") { m_parentProvenance += nextArg + ":\n" + provenance + "\n\n"; } } } } ((CiftiParameter*)myComponent->m_paramList[i])->m_parameter = myFile; if (debug) { cout << "Parameter <" << myComponent->m_paramList[i]->m_shortName << "> opened file with name "; cout << nextArg << endl; } break; } case OperationParametersEnum::DOUBLE: { parameters.backup(); ((DoubleParameter*)myComponent->m_paramList[i])->m_parameter = parameters.nextDouble(myComponent->m_paramList[i]->m_shortName); if (debug) { cout << "Parameter <" << myComponent->m_paramList[i]->m_shortName << "> parsed as "; cout << ((DoubleParameter*)myComponent->m_paramList[i])->m_parameter << endl; } break; } case OperationParametersEnum::FOCI: { CaretPointer myFile(new FociFile()); myFile->readFile(nextArg); if (m_doProvenance) { const GiftiMetaData* md = myFile->getFileMetaData(); if (md != NULL) { AString prov = md->get(PROVENANCE_NAME); if (prov != "") { m_parentProvenance += nextArg + ":\n" + prov + "\n\n"; } } } ((FociParameter*)myComponent->m_paramList[i])->m_parameter = myFile; if (debug) { cout << "Parameter <" << myComponent->m_paramList[i]->m_shortName << "> opened file with name "; cout << nextArg << endl; } break; } case OperationParametersEnum::INT: { parameters.backup(); ((IntegerParameter*)myComponent->m_paramList[i])->m_parameter = parameters.nextLong(myComponent->m_paramList[i]->m_shortName); if (debug) { cout << "Parameter <" << myComponent->m_paramList[i]->m_shortName << "> parsed as "; cout << ((IntegerParameter*)myComponent->m_paramList[i])->m_parameter << endl; } break; } case OperationParametersEnum::LABEL: { CaretPointer myFile(new LabelFile()); myFile->readFile(nextArg); if (m_doProvenance) { const GiftiMetaData* md = myFile->getFileMetaData(); if (md != NULL) { AString prov = md->get(PROVENANCE_NAME); if (prov != "") { m_parentProvenance += nextArg + ":\n" + prov + "\n\n"; } } } ((LabelParameter*)myComponent->m_paramList[i])->m_parameter = myFile; if (debug) { cout << "Parameter <" << myComponent->m_paramList[i]->m_shortName << "> opened file with name "; cout << nextArg << endl; } break; } case OperationParametersEnum::METRIC: { CaretPointer myFile(new MetricFile()); myFile->readFile(nextArg); if (m_doProvenance) { const GiftiMetaData* md = myFile->getFileMetaData(); if (md != NULL) { AString prov = md->get(PROVENANCE_NAME); if (prov != "") { m_parentProvenance += nextArg + ":\n" + prov + "\n\n"; } } } ((MetricParameter*)myComponent->m_paramList[i])->m_parameter = myFile; if (debug) { cout << "Parameter <" << myComponent->m_paramList[i]->m_shortName << "> opened file with name "; cout << nextArg << endl; } break; } case OperationParametersEnum::STRING: { ((StringParameter*)myComponent->m_paramList[i])->m_parameter = nextArg; if (debug) { cout << "Parameter <" << myComponent->m_paramList[i]->m_shortName << "> parsed as "; cout << ((StringParameter*)myComponent->m_paramList[i])->m_parameter << endl; } break; } case OperationParametersEnum::SURFACE: { CaretPointer myFile(new SurfaceFile()); myFile->readFile(nextArg); if (m_doProvenance) { const GiftiMetaData* md = myFile->getFileMetaData(); if (md != NULL) { AString prov = md->get(PROVENANCE_NAME); if (prov != "") { m_parentProvenance += nextArg + ":\n" + prov + "\n\n"; } } } ((SurfaceParameter*)myComponent->m_paramList[i])->m_parameter = myFile; if (debug) { cout << "Parameter <" << myComponent->m_paramList[i]->m_shortName << "> opened file with name "; cout << nextArg << endl; } break; } case OperationParametersEnum::VOLUME: { CaretPointer myFile(new VolumeFile()); myFile->readFile(nextArg); if (m_doProvenance) { const GiftiMetaData* md = myFile->getFileMetaData(); if (md != NULL) { AString prov = md->get(PROVENANCE_NAME); if (prov != "") { m_parentProvenance += nextArg + ":\n" + prov + "\n\n"; } } } ((VolumeParameter*)myComponent->m_paramList[i])->m_parameter = myFile; if (debug) { cout << "Parameter <" << myComponent->m_paramList[i]->m_shortName << "> opened file with name "; cout << nextArg << endl; } break; } }; } catch (const bad_alloc&) { switch (nextType) { case OperationParametersEnum::ANNOTATION: case OperationParametersEnum::BORDER: case OperationParametersEnum::CIFTI: case OperationParametersEnum::FOCI: case OperationParametersEnum::LABEL: case OperationParametersEnum::METRIC: case OperationParametersEnum::SURFACE: case OperationParametersEnum::VOLUME: /* * Provide information to the user about which * file caused the std::bad_alloc including * the size of the file. */ throw DataFileException(nextArg, CaretDataFileHelper::createBadAllocExceptionMessage(nextArg)); break; case OperationParametersEnum::DOUBLE: case OperationParametersEnum::INT: case OperationParametersEnum::STRING: case OperationParametersEnum::BOOL: throw DataFileException("Unable to allocate memory for input: " + nextArg); break; } } } for (int i = 0; i < (int)myComponent->m_outputList.size(); ++i) {//parse the output options of this component bool hyphenReplaced = false; //TSC: until someone complains, I say non-ascii dashes don't belong on the command line, EVER AString rawArg = parameters.nextString(myComponent->m_outputList[i]->m_shortName); AString nextArg = rawArg.fixUnicodeHyphens(&hyphenReplaced); if (hyphenReplaced) { CaretLogWarning("replaced non-ascii hyphen/dash characters in argument '" + rawArg + "' with ascii '-'"); } if (!nextArg.isEmpty() && nextArg[0] == '-') { bool success = parseOption(nextArg, myComponent, parameters, outAssociation, debug); if (!success) { throw ProgramParametersException("Invalid option \"" + nextArg + "\" while next reqired argument is <" + myComponent->m_outputList[i]->m_shortName + ">, option is either incorrect, or incorrectly placed"); } --i;//options do not set required arguments continue;//so rewind the index and skip trying to parse it as a required argument } OutputAssoc tempItem; tempItem.m_fileName = nextArg; tempItem.m_param = myComponent->m_outputList[i]; switch (myComponent->m_outputList[i]->getType())//allocate outputs that only have in-memory implementations { case OperationParametersEnum::ANNOTATION: { CaretPointer& myFile = ((AnnotationParameter*)(myComponent->m_outputList[i]))->m_parameter; myFile.grabNew(new AnnotationFile()); break; } case OperationParametersEnum::BORDER: { CaretPointer& myFile = ((BorderParameter*)(myComponent->m_outputList[i]))->m_parameter; myFile.grabNew(new BorderFile()); break; } case OperationParametersEnum::CIFTI: break;//we create this in makeOnDiskOutputs(), and do the metadata stuff in provenanceForOnDiskOutputs() for this type case OperationParametersEnum::FOCI: { CaretPointer& myFile = ((FociParameter*)(myComponent->m_outputList[i]))->m_parameter; myFile.grabNew(new FociFile()); break; } case OperationParametersEnum::LABEL: { CaretPointer& myFile = ((LabelParameter*)(myComponent->m_outputList[i]))->m_parameter; myFile.grabNew(new LabelFile()); break; } case OperationParametersEnum::METRIC: { CaretPointer& myFile = ((MetricParameter*)(myComponent->m_outputList[i]))->m_parameter; myFile.grabNew(new MetricFile()); break; } case OperationParametersEnum::SURFACE: { CaretPointer& myFile = ((SurfaceParameter*)(myComponent->m_outputList[i]))->m_parameter; myFile.grabNew(new SurfaceFile()); break; } case OperationParametersEnum::VOLUME: { CaretPointer& myFile = ((VolumeParameter*)(myComponent->m_outputList[i]))->m_parameter; myFile.grabNew(new VolumeFile()); break; } case OperationParametersEnum::DOUBLE://ignore these output types case OperationParametersEnum::INT: case OperationParametersEnum::STRING: case OperationParametersEnum::BOOL: CaretLogWarning("encountered ignored output type, " + OperationParametersEnum::toName(myComponent->m_outputList[i]->getType())); break; } outAssociation.push_back(tempItem); if (debug) { cout << "Output parameter <" << tempItem.m_param->m_shortName << "> given output name "; cout << tempItem.m_fileName << endl; } } parseRemainingOptions(myComponent, parameters, outAssociation, debug); } bool CommandParser::parseOption(const AString& mySwitch, ParameterComponent* myComponent, ProgramParameters& parameters, vector& outAssociation, bool debug) { for (uint32_t i = 0; i < myComponent->m_optionList.size(); ++i) { if (mySwitch == myComponent->m_optionList[i]->m_optionSwitch) { if (debug) { cout << "Now parsing option " << myComponent->m_optionList[i]->m_optionSwitch << endl; } if (myComponent->m_optionList[i]->m_present) { throw ProgramParametersException("Option \"" + mySwitch + "\" specified more than once"); } myComponent->m_optionList[i]->m_present = true; parseComponent(myComponent->m_optionList[i], parameters, outAssociation, debug); if (debug) { cout << "Finished parsing option " << myComponent->m_optionList[i]->m_optionSwitch << endl; } return true; } } for (uint32_t i = 0; i < myComponent->m_repeatableOptions.size(); ++i) { if (mySwitch == myComponent->m_repeatableOptions[i]->m_optionSwitch) { if (debug) { cout << "Now parsing repeatable option " << myComponent->m_repeatableOptions[i]->m_optionSwitch << endl; } myComponent->m_repeatableOptions[i]->m_instances.push_back(new ParameterComponent(myComponent->m_repeatableOptions[i]->m_template)); parseComponent(myComponent->m_repeatableOptions[i]->m_instances.back(), parameters, outAssociation, debug); if (debug) { cout << "Finished parsing repeatable option " << myComponent->m_repeatableOptions[i]->m_optionSwitch << endl; } return true; } } return false; } void CommandParser::parseRemainingOptions(ParameterComponent* myComponent, ProgramParameters& parameters, vector& outAssociation, bool debug) { while (parameters.hasNext()) { bool hyphenReplaced = false; //TSC: until someone complains, I say non-ascii dashes don't belong on the command line, EVER AString rawArg = parameters.nextString("option"); AString nextArg = rawArg.fixUnicodeHyphens(&hyphenReplaced); if (hyphenReplaced) { CaretLogWarning("replaced non-ascii hyphen/dash characters in argument '" + rawArg + "' with ascii '-'"); } if (!nextArg.isEmpty() && nextArg[0] == '-') { bool success = parseOption(nextArg, myComponent, parameters, outAssociation, debug); if (!success) { parameters.backup(); return; } } else { parameters.backup(); return; } } } AString CommandParser::doCompletion(ProgramParameters& parameters, const bool& useExtGlob) { CaretPointer myAlgParams(m_autoOper->getParameters());//could be an autopointer, but this is safer CompletionInfo ret = completionComponent(myAlgParams.getPointer(), parameters, useExtGlob); if (parameters.hasNext()) return "";//you're off the edge of the map, find the monsters yourself return ret.completionHints; } CommandParser::CompletionInfo CommandParser::completionComponent(ParameterComponent* myComponent, ProgramParameters& parameters, const bool& useExtGlob) { CompletionInfo ret;//initializes complete to false for (int i = 0; i < (int)myComponent->m_paramList.size(); ++i) { //a bit complicated... //if there is no next parameter, obviously we should do completion based on current mandatory parameter //if the next parameter starts with -, it must either be an option, numeric, or string // if the option hasn't been completed, return its completion info // *if the option is completed, but no parameters remain, need to add the mandatory argument completion to the returned completion info // if parameters remain after the option is completed, restart the iteration in order to be able take another option immediately if (parameters.hasNext()) { //TSC: until someone complains, I say non-ascii dashes don't belong on the command line, EVER AString rawArg = parameters.nextString(myComponent->m_paramList[i]->m_shortName); AString nextArg = rawArg.fixUnicodeHyphens(); if (!nextArg.isEmpty() && nextArg[0] == '-') { CompletionInfo optionInfo = completionOption(nextArg, myComponent, parameters, useExtGlob); if (!optionInfo.found) { switch (myComponent->m_paramList[i]->getType()) { case OperationParametersEnum::STRING: case OperationParametersEnum::INT: case OperationParametersEnum::DOUBLE: break;//it is probably a negative number, so let it parse as one default: //NOTE: we know the command will fail to parse, now what? break;//pretend it will parse as a filename, and continue? }; continue;//assume the parameter works in the given position and move on } else {//specified option switch did match an option if (!optionInfo.complete) {//if the option's mandatory parameters weren't completed, don't add any completion from the current context, just pass the result through return optionInfo; } if (!parameters.hasNext()) {//save these hints, then let it proceed to the completion section ret.completionHints = optionInfo.completionHints; } else { --i; continue;//so skip trying to parse it as a required argument, and restart the loop on the same iteration } } } else { continue;//parameter is empty or doesn't start with -, assume it works fine } }//the above conditional does a continue unless we need to do completion now switch (myComponent->m_paramList[i]->getType()) { case OperationParametersEnum::ANNOTATION: if (ret.completionHints != "") ret.completionHints += " "; if (useExtGlob) { ret.completionHints += "fileglob *.?(wb_)annot"; } else { ret.completionHints += "fileglob *.annot fileglob *.wb_annot"; } break; case OperationParametersEnum::BOOL: if (ret.completionHints != "") ret.completionHints += " "; ret.completionHints += "wordlist true\\ TRUE\\ false\\ FALSE"; break; case OperationParametersEnum::BORDER: if (ret.completionHints != "") ret.completionHints += " "; if (useExtGlob) { ret.completionHints += "fileglob *.?(wb_)border"; } else { ret.completionHints += "fileglob *.border fileglob *.wb_border"; } break; case OperationParametersEnum::CIFTI: if (ret.completionHints != "") ret.completionHints += " "; ret.completionHints += "fileglob *.*.nii";//cifti standard allows arbitrary secondary extensions, and volume files are nearly always .nii.gz anyway break;//could restrict it if someone complains (maybe a preference) case OperationParametersEnum::FOCI: if (ret.completionHints != "") ret.completionHints += " "; if (useExtGlob) { ret.completionHints += "fileglob *.?(wb_)foci"; } else { ret.completionHints += "fileglob *.foci fileglob *.wb_foci"; } break; case OperationParametersEnum::LABEL://is there a caret5 extension for this gifti file type? if (ret.completionHints != "") ret.completionHints += " "; ret.completionHints += "fileglob *.label.gii"; break; case OperationParametersEnum::METRIC://include the caret5 extension that is often the same format if (ret.completionHints != "") ret.completionHints += " "; if (useExtGlob)//also allow label files for now, see if anyone complains (maybe a preference) { ret.completionHints += "fileglob *.@(@(func|shape|label).gii|metric)"; } else { ret.completionHints += "fileglob *.func.gii fileglob *.shape.gii fileglob *.metric fileglob *.label.gii"; } break; case OperationParametersEnum::SURFACE: if (ret.completionHints != "") ret.completionHints += " "; ret.completionHints += "fileglob *.surf.gii"; break; case OperationParametersEnum::VOLUME: if (ret.completionHints != "") ret.completionHints += " "; if (useExtGlob) {//special functionality - when we have extglob, we can exclude common cifti extensions ret.completionHints += "fileglob !(*.dconn|*.dtseries|*.pconn|*.ptseries|*.dscalar|*.dlabel|*.pscalar|*.pdconn|*.dpconn|*.pconnseries|*.pconnscalar|*.plabel).nii?(.gz)"; } else {//when we don't...sorry - maybe have a preference to exclude uncompressed nifti in this condition (not great either) //if it is really a problem, we could introduce a "fileregexp" response type and do it manually with sed or grep ret.completionHints += "fileglob *.nii.gz fileglob *.nii"; } break; case OperationParametersEnum::STRING://for strings, since we use them for filenames sometimes, glob to filenames, I guess if (ret.completionHints != "") ret.completionHints += " "; ret.completionHints += "fileglob *"; break; case OperationParametersEnum::DOUBLE: case OperationParametersEnum::INT: //numeric types don't get any completion hints break; } AString optionHints = completionOptionHints(myComponent, useExtGlob); if (optionHints != "") { if (ret.completionHints != "") ret.completionHints += " "; ret.completionHints += optionHints; } return ret; } for (int i = 0; i < (int)myComponent->m_outputList.size(); ++i) {//parse the output options of this component if (parameters.hasNext()) { //TSC: until someone complains, I say non-ascii dashes don't belong on the command line, EVER AString rawArg = parameters.nextString(myComponent->m_outputList[i]->m_shortName); AString nextArg = rawArg.fixUnicodeHyphens(); if (!nextArg.isEmpty() && nextArg[0] == '-') { CompletionInfo optionInfo = completionOption(nextArg, myComponent, parameters, useExtGlob); if (!optionInfo.found) { //NOTE: we know the command will fail to parse, now what? continue;//pretend the parameter works in the given position and move on? } else {//specified option switch did match an option if (!optionInfo.complete) {//if the option's mandatory parameters weren't completed, don't add any completion from the current context, just pass the result through return optionInfo; } if (!parameters.hasNext()) {//save these hints, then let it proceed to the completion section ret.completionHints = optionInfo.completionHints; } else { --i; continue;//so skip trying to parse it as a required argument, and restart the loop on the same iteration } } } else { continue;//parameter is empty or doesn't start with -, assume it works fine } }//the above conditional does a continue unless we need to do completion now if (ret.completionHints != "") ret.completionHints += " "; ret.completionHints += "fileglob *";//we are specifying an output file, so glob to everything so they can easily reuse names from other format files AString optionHints = completionOptionHints(myComponent, useExtGlob); if (optionHints != "") { ret.completionHints += " " + optionHints; } return ret; } CompletionInfo remainInfo = completionRemainingOptions(myComponent, parameters, useExtGlob);//returns last option parsed (so, the one to do completion on, if applicable) if (remainInfo.found) { if (!remainInfo.complete) return remainInfo; if (!parameters.hasNext()) { AString localOpts = completionOptionHints(myComponent, useExtGlob); if (remainInfo.completionHints != "") remainInfo.completionHints += " "; remainInfo.completionHints += localOpts; return remainInfo; } } ret.complete = true; if (!parameters.hasNext())//no remaining options matched, but we are out of parameters, so fill in any options that could come next { ret.completionHints = completionOptionHints(myComponent, useExtGlob); } return ret; } CommandParser::CompletionInfo CommandParser::completionOption(const AString& mySwitch, ParameterComponent* myComponent, ProgramParameters& parameters, const bool& useExtGlob) { for (uint32_t i = 0; i < myComponent->m_optionList.size(); ++i) { if (mySwitch == myComponent->m_optionList[i]->m_optionSwitch) { if (myComponent->m_optionList[i]->m_present) { //NOTE: we know the parsing will fail here, now what? //pretend it is repeatable and move on, I guess } myComponent->m_optionList[i]->m_present = true; CompletionInfo optionInfo = completionComponent(myComponent->m_optionList[i], parameters, useExtGlob); optionInfo.found = true; return optionInfo; } } for (uint32_t i = 0; i < myComponent->m_repeatableOptions.size(); ++i) { if (mySwitch == myComponent->m_repeatableOptions[i]->m_optionSwitch) { myComponent->m_repeatableOptions[i]->m_instances.push_back(new ParameterComponent(myComponent->m_repeatableOptions[i]->m_template)); CompletionInfo optionInfo = completionComponent(myComponent->m_repeatableOptions[i]->m_instances.back(), parameters, useExtGlob); optionInfo.found = true; return optionInfo; } } return CompletionInfo();//found initializes to false } AString CommandParser::completionOptionHints(ParameterComponent* myComponent, const bool& /*useExtGlob*/) { AString ret; for (uint32_t i = 0; i < myComponent->m_optionList.size(); ++i) { if (!myComponent->m_optionList[i]->m_present) {//don't suggest non-repeatable options we already have if (ret == "") { ret = "wordlist "; } else { ret += "\\ "; } ret += myComponent->m_optionList[i]->m_optionSwitch; } } for (uint32_t i = 0; i < myComponent->m_repeatableOptions.size(); ++i) {//include all repeatable options if (ret == "") { ret = "wordlist "; } else { ret += "\\ "; } ret += myComponent->m_repeatableOptions[i]->m_optionSwitch; } return ret; } CommandParser::CompletionInfo CommandParser::completionRemainingOptions(ParameterComponent* myComponent, ProgramParameters& parameters, const bool& useExtGlob) {//NOTE: completionComponent will complete the local options if needed when found is false CompletionInfo prev; while (parameters.hasNext()) { //TSC: until someone complains, I say non-ascii dashes don't belong on the command line, EVER AString rawArg = parameters.nextString("option"); AString nextArg = rawArg.fixUnicodeHyphens(); if (!nextArg.isEmpty() && nextArg[0] == '-') { CompletionInfo temp = completionOption(nextArg, myComponent, parameters, useExtGlob); if (!temp.found) { parameters.backup(); return prev;//more things to parse, could return default constructed instead } prev = temp;//it was found, so update what we found } else {//more things to parse, but they don't go here parameters.backup(); return CompletionInfo();//found initializes to false } } return prev;//no parameters remain, return whatever was found } void CommandParser::provenanceBeforeOperation(const vector& outAssociation) { vector versionInfo;//need this for on-disk outputs, because we have to set it before the command executes ApplicationInformation myInfo; myInfo.getAllInformation(versionInfo); AString versionProvenance; for (int i = 0; i < (int)versionInfo.size(); ++i) { versionProvenance += versionInfo[i] + "\n"; } for (uint32_t i = 0; i < outAssociation.size(); ++i) { AbstractParameter* myParam = outAssociation[i].m_param; switch (myParam->getType()) { case OperationParametersEnum::CIFTI: { CiftiFile* myFile = ((CiftiParameter*)myParam)->m_parameter; CiftiXML myXML; CiftiSeriesMap tempMap; tempMap.setLength(1); tempMap.setStep(1.0f); tempMap.setStart(0.0f); tempMap.setUnit(CiftiSeriesMap::SECOND); myXML.setNumberOfDimensions(2); myXML.setMap(0, tempMap); myXML.setMap(1, tempMap); GiftiMetaData* mymd = myXML.getFileMetaData(); mymd->set(PROVENANCE_NAME, m_provenance); mymd->set(PROGRAM_PROVENANCE_NAME, versionProvenance);//cifti is on-disk, so set all provenance now, because we can't later mymd->set(CWD_PROVENANCE_NAME, m_workingDir); if (m_parentProvenance != "") { mymd->set(PARENT_PROVENANCE_NAME, m_parentProvenance); } myFile->setCiftiXML(myXML, false);//tells it to use this new metadata, rather than copying metadata from the old XML (which is default so that provenance metadata persists through naive usage) break; } default: break; } } } void CommandParser::provenanceAfterOperation(const vector& outAssociation) { vector versionInfo;//now we need this information for outputs that are in memory until written ApplicationInformation myInfo; myInfo.getAllInformation(versionInfo); AString versionProvenance; for (int i = 0; i < (int)versionInfo.size(); ++i) { versionProvenance += versionInfo[i] + "\n"; } for (uint32_t i = 0; i < outAssociation.size(); ++i) { AbstractParameter* myParam = outAssociation[i].m_param; GiftiMetaData* md = NULL; switch (myParam->getType()) { case OperationParametersEnum::BORDER: { BorderFile* myFile = ((BorderParameter*)myParam)->m_parameter; md = myFile->getFileMetaData(); break; } case OperationParametersEnum::FOCI: { FociFile* myFile = ((FociParameter*)myParam)->m_parameter; md = myFile->getFileMetaData(); break; } case OperationParametersEnum::LABEL: { LabelFile* myFile = ((LabelParameter*)myParam)->m_parameter; md = myFile->getFileMetaData(); break; } case OperationParametersEnum::METRIC: { MetricFile* myFile = ((MetricParameter*)myParam)->m_parameter; md = myFile->getFileMetaData(); break; } case OperationParametersEnum::SURFACE: { SurfaceFile* myFile = ((SurfaceParameter*)myParam)->m_parameter; md = myFile->getFileMetaData(); break; } case OperationParametersEnum::VOLUME: { VolumeFile* myFile = ((VolumeParameter*)myParam)->m_parameter; md = myFile->getFileMetaData(); break; } default: break; } if (md != NULL) { md->set(PROVENANCE_NAME, m_provenance); md->set(PROGRAM_PROVENANCE_NAME, versionProvenance); md->set(CWD_PROVENANCE_NAME, m_workingDir); if (m_parentProvenance != "") { md->set(PARENT_PROVENANCE_NAME, m_parentProvenance); } } } } void CommandParser::makeOnDiskOutputs(const vector& outAssociation) { for (uint32_t i = 0; i < outAssociation.size(); ++i) { AbstractParameter* myParam = outAssociation[i].m_param; switch (myParam->getType()) { case OperationParametersEnum::CIFTI: { CiftiParameter* myCiftiParam = (CiftiParameter*)myParam; FileInformation myInfo(outAssociation[i].m_fileName); map::iterator iter = m_inputCiftiNames.find(myInfo.getCanonicalFilePath()); if (iter != m_inputCiftiNames.end()) { vector dims = iter->second->getDimensions(); int64_t totalSize = sizeof(float); for (int j = 0; j < (int)dims.size(); ++j) { totalSize *= dims[j]; } if (totalSize > ((int64_t)2) * 1024 * 1024 * 1024)//suppress the message for non-large input files, on the assumption that the output file will be the same size { CaretLogInfo("Computing output file '" + outAssociation[i].m_fileName + "' in memory due to collision with input file"); } myCiftiParam->m_parameter.grabNew(new CiftiFile()); } else { myCiftiParam->m_parameter.grabNew(new CiftiFile()); myCiftiParam->m_parameter->setWritingFile(outAssociation[i].m_fileName); } if (m_ciftiScale) { myCiftiParam->m_parameter->setWritingDataTypeAndScaling(m_ciftiDType, m_ciftiMin, m_ciftiMax); } else { myCiftiParam->m_parameter->setWritingDataTypeNoScaling(m_ciftiDType); } break; } default: break; } } } void CommandParser::writeOutput(const vector& outAssociation) { for (uint32_t i = 0; i < outAssociation.size(); ++i) { AbstractParameter* myParam = outAssociation[i].m_param; switch (myParam->getType()) { case OperationParametersEnum::BOOL://ignores the name you give the output for now, but what gives primitive type output and how is it used? cout << "Output Boolean \"" << myParam->m_shortName << "\" value is " << ((BooleanParameter*)myParam)->m_parameter << endl; break; case OperationParametersEnum::BORDER: { BorderFile* myFile = ((BorderParameter*)myParam)->m_parameter; myFile->writeFile(outAssociation[i].m_fileName); break; } case OperationParametersEnum::CIFTI: { CiftiFile* myFile = ((CiftiParameter*)myParam)->m_parameter;//we can't set metadata here because the XML is already on disk, see provenanceForOnDiskOutputs myFile->writeFile(outAssociation[i].m_fileName);//this is basically a noop unless outputs and inputs collide, we opened ON_DISK and set cache file to this name back in makeOnDiskOutputs myFile->close();//if there is a problem flushing the file, let it throw here instead of doing a severe log message break; } case OperationParametersEnum::DOUBLE: cout << "Output Floating Point \"" << myParam->m_shortName << "\" value is " << ((DoubleParameter*)myParam)->m_parameter << endl; break; case OperationParametersEnum::INT: cout << "Output Integer \"" << myParam->m_shortName << "\" value is " << ((IntegerParameter*)myParam)->m_parameter << endl; break; case OperationParametersEnum::FOCI: { FociFile* myFile = ((FociParameter*)myParam)->m_parameter; myFile->writeFile(outAssociation[i].m_fileName); break; } case OperationParametersEnum::LABEL: { LabelFile* myFile = ((LabelParameter*)myParam)->m_parameter; myFile->writeFile(outAssociation[i].m_fileName); break; } case OperationParametersEnum::METRIC: { MetricFile* myFile = ((MetricParameter*)myParam)->m_parameter; myFile->writeFile(outAssociation[i].m_fileName); break; } case OperationParametersEnum::STRING: cout << "Output String \"" << myParam->m_shortName << "\" value is " << ((StringParameter*)myParam)->m_parameter << endl; break; case OperationParametersEnum::SURFACE: { SurfaceFile* myFile = ((SurfaceParameter*)myParam)->m_parameter; myFile->writeFile(outAssociation[i].m_fileName); break; } case OperationParametersEnum::VOLUME: { VolumeFile* myFile = ((VolumeParameter*)myParam)->m_parameter; myFile->writeFile(outAssociation[i].m_fileName); break; } default: CaretAssertMessage(false, "Writing of this parameter type has not been implemented in this parser");//assert instead of throw because this is a code error, not a user error throw CommandException("Internal parsing error, please let the developers know what you just tried to do");//but don't let release pass by it either } } } AString CommandParser::getHelpInformation(const AString& programName) { m_minIndent = 0; m_indentIncrement = 3; m_maxWidth = 79;//leave a space on the right edge of an 80-wide terminal so that it looks better - TODO: get the terminal width from some system call m_maxIndent = 31;//don't let indenting take up more than this int curIndent = m_minIndent; AString ret; ret = formatString(getOperationShortDescription(), curIndent, true); curIndent += m_indentIncrement; ret += getIndentString(curIndent) + programName + " " + getCommandLineSwitch() + "\n";//DO NOT format the command that people may want to copy and paste, added hyphens would be disastrous curIndent += m_indentIncrement; OperationParameters* myAlgParams = m_autoOper->getParameters(); addComponentDescriptions(ret, myAlgParams, curIndent); ret += "\n";//separate prose with a newline addHelpProse(ret, myAlgParams, curIndent); delete myAlgParams; return ret; } void CommandParser::addHelpComponent(AString& info, ParameterComponent* myComponent, int curIndent) { for (int i = 0; i < (int)myComponent->m_paramList.size(); ++i) { info += formatString("<" + myComponent->m_paramList[i]->m_shortName + ">", curIndent, true); } for (int i = 0; i < (int)myComponent->m_outputList.size(); ++i) { info += formatString("<" + myComponent->m_outputList[i]->m_shortName + ">", curIndent, true); } addHelpOptions(info, myComponent, curIndent); } void CommandParser::addHelpOptions(AString& info, ParameterComponent* myComponent, int curIndent) { for (int i = 0; i < (int)myComponent->m_optionList.size(); ++i) { info += formatString("[" + myComponent->m_optionList[i]->m_optionSwitch + "]", curIndent, true); addHelpComponent(info, myComponent->m_optionList[i], curIndent + m_indentIncrement);//indent arguments to options } for (int i = 0; i < (int)myComponent->m_repeatableOptions.size(); ++i) { info += formatString("[" + myComponent->m_repeatableOptions[i]->m_optionSwitch + "] (repeatable)", curIndent, true); addHelpComponent(info, &(myComponent->m_repeatableOptions[i]->m_template), curIndent + m_indentIncrement);//indent arguments to options } } void CommandParser::addHelpProse(AString& info, OperationParameters* myAlgParams, int curIndent) {//NOTE: does not currently format tabs well, don't use them AString* rawProse = &(myAlgParams->getHelpText());//friendlier name info += formatString(*rawProse, curIndent, false);//don't indent on added newlines in the prose } AString CommandParser::formatString(const AString& in, int curIndent, bool addIndent) {//NOTE: does not currently format tabs well, don't use them AString curIndentString = getIndentString(curIndent); bool haveAddedBreak = false; AString ret; int charMax = m_maxWidth - curIndentString.size(); int curIndex = 0; while (curIndex < in.size()) { if (addIndent) { if (haveAddedBreak) { curIndentString = getIndentString(curIndent + m_indentIncrement); charMax = m_maxWidth - curIndentString.size(); } else { curIndentString = getIndentString(curIndent); charMax = m_maxWidth - curIndentString.size(); } } int endIndex = curIndex; while (endIndex - curIndex < charMax && endIndex < in.size() && in[endIndex] != '\n') {//start by crawling until newline or at max width ++endIndex; } if (endIndex >= in.size()) { ret += curIndentString + in.mid(curIndex, endIndex - curIndex) + "\n"; } else { if (in[endIndex] == '\n') { while (endIndex < in.size() && in[endIndex] == '\n') {//crawl over any additional newlines ++endIndex; } haveAddedBreak = false; ret += curIndentString + in.mid(curIndex, endIndex - curIndex); } else { int savedEnd = endIndex; while (endIndex > curIndex && in[endIndex] != ' ') {//crawl in reverse until a space, or reaching curIndex - change this if you want hyphenation to take place more often than lines without any spaces --endIndex; } if (endIndex > curIndex) {//found a space we can break at while (endIndex > curIndex && in[endIndex] == ' ') {//don't print any of the spaces --endIndex; } if (endIndex > curIndex) { ++endIndex;//print the character before the space } haveAddedBreak = true; ret += curIndentString + in.mid(curIndex, endIndex - curIndex) + "\n"; } else {//hyphenate endIndex = savedEnd - 1; haveAddedBreak = true; ret += curIndentString + in.mid(curIndex, endIndex - curIndex) + "-\n"; } } } curIndex = endIndex; if (haveAddedBreak)//don't skip spaces after literal newlines { while (curIndex < in.size() && in[curIndex] == ' ') {//skip spaces ++curIndex; } } } return ret; } void CommandParser::addComponentDescriptions(AString& info, ParameterComponent* myComponent, int curIndent) { for (int i = 0; i < (int)myComponent->m_paramList.size(); ++i) { info += formatString("<" + myComponent->m_paramList[i]->m_shortName + "> - " + myComponent->m_paramList[i]->m_description, curIndent, true); } for (int i = 0; i < (int)myComponent->m_outputList.size(); ++i) { info += formatString("<" + myComponent->m_outputList[i]->m_shortName + "> - output - " + myComponent->m_outputList[i]->m_description, curIndent, true); } addOptionDescriptions(info, myComponent, curIndent); } void CommandParser::addOptionDescriptions(AString& info, ParameterComponent* myComponent, int curIndent) { for (int i = 0; i < (int)myComponent->m_optionList.size(); ++i) { info += "\n" + formatString("[" + myComponent->m_optionList[i]->m_optionSwitch + "] - " + myComponent->m_optionList[i]->m_description, curIndent, true); addComponentDescriptions(info, myComponent->m_optionList[i], curIndent + m_indentIncrement);//indent arguments to options } for (int i = 0; i < (int)myComponent->m_repeatableOptions.size(); ++i) { info += "\n" + formatString("[" + myComponent->m_repeatableOptions[i]->m_optionSwitch + "] - repeatable - " + myComponent->m_repeatableOptions[i]->m_description, curIndent, true); addComponentDescriptions(info, &(myComponent->m_repeatableOptions[i]->m_template), curIndent + m_indentIncrement);//indent arguments to options } } AString CommandParser::getIndentString(int desired) { AString space(" "); int num = desired; if (num > m_maxIndent) num = m_maxIndent; if (num < m_minIndent) num = m_minIndent; return space.repeated(num); } bool CommandParser::takesParameters() { return m_autoOper->takesParameters(); } connectome-workbench-1.4.2/src/Commands/CommandParser.h000066400000000000000000000113501360521144700230670ustar00rootroot00000000000000#ifndef __COMMAND_PARSER_H__ #define __COMMAND_PARSER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationParameters.h" #include "AbstractOperation.h" #include "CommandOperation.h" #include "ProgramParameters.h" #include "CommandException.h" #include "ProgramParametersException.h" #include #include namespace caret { class CommandParser : public CommandOperation, OperationParserInterface { int m_minIndent, m_maxIndent, m_indentIncrement, m_maxWidth; AString m_provenance, m_parentProvenance, m_workingDir; bool m_doProvenance, m_ciftiScale; double m_ciftiMin, m_ciftiMax; int16_t m_ciftiDType; const static AString PROVENANCE_NAME, PARENT_PROVENANCE_NAME, PROGRAM_PROVENANCE_NAME, CWD_PROVENANCE_NAME;//TODO: put this elsewhere? std::map m_inputCiftiNames; struct OutputAssoc {//how the output is stored is up to the parser, in the GUI it should load into memory without writing to disk AString m_fileName; AbstractParameter* m_param; }; struct CompletionInfo { bool complete, found;//found is only used for options AString completionHints;//only valid when hasNext returns false during the component CompletionInfo() { complete = false; found = false; } }; void parseComponent(ParameterComponent* myComponent, ProgramParameters& parameters, std::vector& outAssociation, bool debug = false); bool parseOption(const AString& mySwitch, ParameterComponent* myComponent, ProgramParameters& parameters, std::vector& outAssociation, bool debug); void parseRemainingOptions(ParameterComponent* myAlgParams, ProgramParameters& parameters, std::vector& outAssociation, bool debug); void provenanceBeforeOperation(const std::vector& outAssociation); void provenanceAfterOperation(const std::vector& outAssociation); void makeOnDiskOutputs(const std::vector& outAssociation);//ensures on-disk inputs aren't used as on-disk outputs, keeping outputs in-memory when needed void writeOutput(const std::vector& outAssociation); AString getIndentString(int desired); void addHelpComponent(AString& info, ParameterComponent* myComponent, int curIndent); void addHelpOptions(AString& info, ParameterComponent* myAlgParams, int curIndent); void addHelpProse(AString& info, OperationParameters* myAlgParams, int curIndent); void addComponentDescriptions(AString& info, ParameterComponent* myComponent, int curIndent); void addOptionDescriptions(AString& info, ParameterComponent* myComponent, int curIndent); AString formatString(const AString& in, int curIndent, bool addIndent); CompletionInfo completionComponent(ParameterComponent* myComponent, ProgramParameters& parameters, const bool& useExtGlob); CompletionInfo completionOption(const AString& mySwitch, ParameterComponent* myComponent, ProgramParameters& parameters, const bool& useExtGlob); AString completionOptionHints(ParameterComponent* myComponent, const bool& useExtGlob); CompletionInfo completionRemainingOptions(ParameterComponent* myComponent, ProgramParameters& parameters, const bool& useExtGlob); public: CommandParser(AutoOperationInterface* myAutoOper); void disableProvenance(); void setCiftiOutputDTypeAndScale(const int16_t& dtype, const double& minVal, const double& maxVal); void setCiftiOutputDTypeNoScale(const int16_t& dtype); void executeOperation(ProgramParameters& parameters); void showParsedOperation(ProgramParameters& parameters); AString doCompletion(ProgramParameters& parameters, const bool& useExtGlob); AString getHelpInformation(const AString& programName); bool takesParameters(); }; }; #endif //__COMMAND_PARSER_H__ connectome-workbench-1.4.2/src/Commands/CommandUnitTest.cxx000066400000000000000000000034021360521144700237640ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "CaretAssertion.h" #include "CommandUnitTest.h" #include "Plane.h" #include "SystemUtilities.h" using namespace caret; /** * Constructor. */ CommandUnitTest::CommandUnitTest() : CommandOperation("-unit-test", "UNIT TESTING") { } /** * Destructor. */ CommandUnitTest::~CommandUnitTest() { } /** * Execute the operation. * * @param parameters * Parameters for the operation. * @throws CommandException * If the command failed. * @throws ProgramParametersException * If there is an error in the parameters. */ void CommandUnitTest::executeOperation(ProgramParameters& /*parameters*/) { std::ostream* stream = &std::cout; CaretAssertion::unitTest(*stream, true); *stream << std::endl; Plane::unitTest(*stream, true); *stream << std::endl; SystemUtilities::unitTest(*stream, true); *stream << std::endl; } connectome-workbench-1.4.2/src/Commands/CommandUnitTest.h000066400000000000000000000030671360521144700234200ustar00rootroot00000000000000#ifndef __COMMAND_UNIT_TEST_H__ #define __COMMAND_UNIT_TEST_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CommandOperation.h" namespace caret { /// Command operation for unit testing. class CommandUnitTest : public CommandOperation { public: CommandUnitTest(); virtual ~CommandUnitTest(); virtual void executeOperation(ProgramParameters& parameters); AString getHelpInformation(const AString& /*programName*/) { return " "; }; virtual bool takesParameters() { return false; } private: CommandUnitTest(const CommandUnitTest&); CommandUnitTest& operator=(const CommandUnitTest&); }; } // namespace #endif // __COMMAND_UNIT_TEST_H__ connectome-workbench-1.4.2/src/Commands/README.txt000066400000000000000000000024531360521144700216650ustar00rootroot00000000000000Do not write new commands in this directory, that method is obsolete, new commands should be made as either Operations or Algorithms, as follows: The defining difference between Operations and Algorithms is that Algorithms provide a way for other workbench code to use their code easily. Operations, by contrast, often merely expose something already available internally to the command line. For instance, setting the name of a map in a file is a simple function call, so to expose that to the command line, an Operation is used. On the other hand, computing gradients is not built into any type of file object, so it is implemented inside an Algorithm class (which provides a way for other code to call it). Operations are also generally the right solution when the output does not fit into a common data file type (volume file, cifti file, etc) and the implementation is simple - for instance, doing a spatial reduction operation on a file results in one number per map, so the operations for this (-*-stats) print the numbers to the terminal rather than making an output file. Once you know whether the command should be an Algorithm or Operation, open either Algorithms/AlgorithmTemplate.h.txt or Operations/OperationTemplate.h.txt, and follow the instructions in the block comment just below the license notice. connectome-workbench-1.4.2/src/Common/000077500000000000000000000000001360521144700176525ustar00rootroot00000000000000connectome-workbench-1.4.2/src/Common/AString.cxx000066400000000000000000000715271360521144700217610ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AString.h" #include "CaretAssert.h" #include "CaretLogger.h" #include using namespace caret; std::ostream& operator << (std::ostream &lhs, const AString &rhs) { return lhs << rhs.toStdString(); } /** * Convert a vector of values into a string. * @param v * The vector of values. * @param separator * Inserted between each pair of values. * @return * String containing the vector's values separated * by the separator. */ AString AString::fromNumbers(const std::vector& v, const AString& separator) { AString s; for (uint64_t i = 0; i < v.size(); i++) { if (i > 0) { s += separator; } s += AString::number(v[i]); } return s; } /** * Convert a vector of values into a string. * @param v * The vector of values. * @param separator * Inserted between each pair of values. * @return * String containing the vector's values separated * by the separator. */ AString AString::fromNumbers(const std::vector& v, const AString& separator) { AString s; for (uint64_t i = 0; i < v.size(); i++) { if (i > 0) { s += separator; } s += AString::number(v[i]); } return s; } /** * Convert a vector of values into a string. * @param v * The vector of values. * @param separator * Inserted between each pair of values. * @return * String containing the vector's values separated * by the separator. */ AString AString::fromNumbers(const std::vector& v, const AString& separator) { AString s; for (uint64_t i = 0; i < v.size(); i++) { if (i > 0) { s += separator; } s += AString::number(v[i]); } return s; } /** * Convert a vector of values into a string. * @param v * The vector of values. * @param separator * Inserted between each pair of values. * @return * String containing the vector's values separated * by the separator. */ AString AString::fromNumbers(const std::vector& v, const AString& separator) { AString s; for (uint64_t i = 0; i < v.size(); i++) { if (i > 0) { s += separator; } s += AString::number(v[i]); } return s; } /** * Convert a vector of values into a string. * @param v * The vector of values. * @param separator * Inserted between each pair of values. * @return * String containing the vector's values separated * by the separator. */ AString AString::fromNumbers(const std::vector& v, const AString& separator) { AString s; for (uint64_t i = 0; i < v.size(); i++) { if (i > 0) { s += separator; } s += AString::number(v[i]); } return s; } /** * Convert a vector of values into a string. * @param v * The vector of values. * @param separator * Inserted between each pair of values. * @return * String containing the vector's values separated * by the separator. */ AString AString::fromNumbers(const std::vector& v, const AString& separator) { AString s; for (uint64_t i = 0; i < v.size(); i++) { if (i > 0) { s += separator; } s += AString::number(v[i]); } return s; } /** * Convert a vector of values into a string. * @param v * The vector of values. * @param separator * Inserted between each pair of values. * @param format * e format as [-]9.9e[+|-]999 * E format as [-]9.9E[+|-]999 * f format as [-]9.9 * g use e or f format, whichever is the most concise * G use E or f format, whichever is the most concise * @param precision * Maximum number of digits following decimal. * @return * String containing the vector's values separated * by the separator. */ AString AString::fromNumbers(const std::vector& v, const AString& separator, char format, const int32_t precision) { AString s; for (uint64_t i = 0; i < v.size(); i++) { if (i > 0) { s += separator; } s += AString::number(v[i], format, precision); } return s; } /** * Convert a vector of values into a string. * @param v * The vector of values. * @param separator * Inserted between each pair of values. * @param format * e format as [-]9.9e[+|-]999 * E format as [-]9.9E[+|-]999 * f format as [-]9.9 * g use e or f format, whichever is the most concise * G use E or f format, whichever is the most concise * @param precision * Maximum number of digits following decimal. * @return * String containing the vector's values separated * by the separator. */ AString AString::fromNumbers(const std::vector& v, const AString& separator, char format, const int32_t precision) { AString s; for (uint64_t i = 0; i < v.size(); i++) { if (i > 0) { s += separator; } s += AString::number(v[i], format, precision); } return s; } /** * Convert an array of values into a string. * @param array * The array of values. * @param numberOfElements * Number of elements in the array. * @param separator * Inserted between each pair of values. * @param format * e format as [-]9.9e[+|-]999 * E format as [-]9.9E[+|-]999 * f format as [-]9.9 * g use e or f format, whichever is the most concise * G use E or f format, whichever is the most concise * @param precision * Maximum number of digits following decimal. * @return * String containing the array values separated * by the separator. */ AString AString::fromNumbers(const float* array, const int64_t numberOfElements, const AString& separator, char format, const int32_t precision) { AString s; for (int64_t i = 0; i < numberOfElements; i++) { if (i > 0) { s += separator; } s += AString::number(array[i], format, precision); } return s; } /** * Convert an array of values into a string. * @param array * The array of values. * @param numberOfElements * Number of elements in the array. * @param separator * Inserted between each pair of values. * @return * String containing the array values separated * by the separator. */ AString AString::fromNumbers(const int8_t* array, const int64_t numberOfElements, const AString& separator) { AString s; for (int64_t i = 0; i < numberOfElements; i++) { if (i > 0) { s += separator; } s += AString::number(array[i]); } return s; } /** * Convert an array of values into a string. * @param array * The array of values. * @param numberOfElements * Number of elements in the array. * @param separator * Inserted between each pair of values. * @return * String containing the array values separated * by the separator. */ AString AString::fromNumbers(const uint8_t* array, const int64_t numberOfElements, const AString& separator) { AString s; for (int64_t i = 0; i < numberOfElements; i++) { if (i > 0) { s += separator; } s += AString::number(array[i]); } return s; } /** * Convert an array of values into a string. * @param array * The array of values. * @param numberOfElements * Number of elements in the array. * @param separator * Inserted between each pair of values. * @return * String containing the array values separated * by the separator. */ AString AString::fromNumbers(const int32_t* array, const int64_t numberOfElements, const AString& separator) { AString s; for (int64_t i = 0; i < numberOfElements; i++) { if (i > 0) { s += separator; } s += AString::number(array[i]); } return s; } /** * Convert an array of values into a string. * @param array * The array of values. * @param numberOfElements * Number of elements in the array. * @param separator * Inserted between each pair of values. * @return * String containing the array values separated * by the separator. */ AString AString::fromNumbers(const int64_t* array, const int64_t numberOfElements, const AString& separator) { AString s; for (int64_t i = 0; i < numberOfElements; i++) { if (i > 0) { s += separator; } s += AString::number(array[i]); } return s; } /** * Convert an array of values into a string. * @param array * The array of values. * @param numberOfElements * Number of elements in the array. * @param separator * Inserted between each pair of values. * @param format * e format as [-]9.9e[+|-]999 * E format as [-]9.9E[+|-]999 * f format as [-]9.9 * g use e or f format, whichever is the most concise * G use E or f format, whichever is the most concise * @param precision * Maximum number of digits following decimal. * @return * String containing the array values separated * by the separator. */ AString AString::fromNumbers(const double* array, const int64_t numberOfElements, const AString& separator, char format, const int32_t precision) { AString s; for (int64_t i = 0; i < numberOfElements; i++) { if (i > 0) { s += separator; } s += AString::number(array[i], format, precision); } return s; } /** * Convert the contents of given string to floats. Each * piece of text is converted to float. If a piece of * text does not convert to a float, it is ignored. This * should allow separation with characters other than * whitespace. * * @param s * String convert to floats. * @param numbersOut * Vector that will contain the given of this string * as numbers. */ void AString::toNumbers(const AString& s, std::vector& numbersOut) { AString copy = s; QTextStream stream(©); float floatValue; while (stream.atEnd() == false) { /* * Try to read a float value from the current position */ stream >> floatValue; /* * If the text stream could not create a float from * the current text position, the corrupt data flag * will be set. */ if (stream.status() == QTextStream::ReadCorruptData) { /* * Reset the status of the string (to OK) and * then read one character to remove the character * from the stream since it was not the start * of a number. */ stream.resetStatus(); QChar oneChar; stream >> oneChar; } else { numbersOut.push_back(floatValue); } } } /** * Convert the contents of given string to ints. Each * piece of text is converted to int. If a piece of * text does not convert to an int, it is ignored. This * should allow separation with characters other than * whitespace. * * @param s * String convert to ints. * @param numbersOut * Vector that will contain the given of this string * as numbers. */ void AString::toNumbers(const AString& s, std::vector& numbersOut) { AString copy = s; QTextStream stream(©); int intValue; while (stream.atEnd() == false) { /* * Try to read a int value from the current position */ stream >> intValue; /* * If the text stream could not create an int from * the current text position, the corrupt data flag * will be set. */ if (stream.status() == QTextStream::ReadCorruptData) { /* * Reset the status of the string (to OK) and * then read one character to remove the character * from the stream since it was not the start * of a number. */ stream.resetStatus(); QChar oneChar; stream >> oneChar; } else { numbersOut.push_back(intValue); } } } /** * Convert the string to a boolean value. * These case insensitive values are considered true: * true, t, 1, 1.0. All others are considered false. * * @return * Boolean value interpreted from contents of * this string. */ bool AString::toBool() const { const AString s = this->toLower(); if ((s == "true") || (s == "t") || (s == "1") || (s == "1.0")) { return true; } return false; } /** * Convert the boolean value to a string. * @param b * The boolean value. * @return "true" if true, else "false". */ AString AString::fromBool(const bool b) { if (b) { return "true"; } return "false"; } /** * Convert any URLs in this string to * HTML hyperlinks. * "http://www.wustl.edu" becomes "http://wwww.wustl.edu" * @param sin * String that may contain URLs. * @return * Input string with any URLs replace with hyperlinks. */ AString AString::convertURLsToHyperlinks() const { std::vector url; std::vector urlStart; const AString& sin = *this; if (sin.indexOf("http://") == -1) { return sin; } else { // // Create a modifiable copy // AString s(sin); // // loop since there may be more than one URL // bool done = false; int startPos = 0; while(done == false) { // // Find the beginning of the URL // const int httpStart = s.indexOf("http://", startPos); // // Was the start of a URL found // if (httpStart == -1) { done = true; } else { // // Find the end of the URL // int httpEnd = s.indexOfAnyChar(" \t\n\r", httpStart + 1); // // May not find end since end of string // int httpLength; if (httpEnd == -1) { httpLength = s.length() - httpStart; } else { httpLength = httpEnd - httpStart; } // // Get the http URL // const AString httpString = s.mid(httpStart, httpLength); url.push_back(httpString); urlStart.push_back(httpStart); // // Prepare for next search // startPos = httpStart; //if (startPos > 0) { startPos = startPos + 1; //} } } if (url.empty() == false) { const int startNum = static_cast(url.size()) - 1; for (int i = startNum; i >= 0; i--) { const int len = url[i].length(); // // Create the trailing part of the hyperlink and insert it // AString trailingHyperLink("\">"); trailingHyperLink.append(url[i]); trailingHyperLink.append(""); s.insert(urlStart[i] + len, trailingHyperLink); // // Insert the beginning of the hyperlink // s.insert(urlStart[i], " " and "" * * Replace some characters with their HTML escaped characters */ AString AString::convertToHtmlPage() const { return convertToHtmlPageWithCssFontHeight(-1); } /** * Convert the text string to an HTML page using the given font size * by enclosing text between: * "" and "" * * Note: This uses the font tag's size attribute which is not supported * by HTML5. * * Also replaces some characters with their HTML escaped characters * * @param fontSize * Size of the font. */ AString AString::convertToHtmlPageWithFontSize(const int fontSize) const { /* * If already HTML (assumes "html" is the first six characters), * no need to convert. */ if (this->startsWith("", Qt::CaseInsensitive)) { return *this; } AString htmlString(""); htmlString.append(""); htmlString.append(this->replaceHtmlSpecialCharactersWithEscapeCharacters()); htmlString.append(""); htmlString.append(""); return htmlString; } /** * Convert the text string to an HTML page using the given font height * by enclosing text between: * "

" * * Note: HTML produced by this method and displayed in a QTextBrowser had * some problems with cutting and pasting on some Macs not working. * * Also replaces some characters with their HTML escaped characters * * @param fontHeight * Height of the font (if negative no font height is applied). */ AString AString::convertToHtmlPageWithCssFontHeight(const int fontHeight) const { /* * If already HTML (assumes "html" is the first six characters), * no need to convert. */ if (this->startsWith("", Qt::CaseInsensitive)) { return *this; } AString htmlString(""); if (fontHeight > 0) { htmlString.append("

"); } htmlString.append(this->replaceHtmlSpecialCharactersWithEscapeCharacters()); if (fontHeight > 0) { htmlString.append("

"); } htmlString.append(""); return htmlString; } /** * @return A copy of this string with any HTML special characters replaced * by their escape sequences. */ AString AString::replaceHtmlSpecialCharactersWithEscapeCharacters() const { AString htmlString; const int64_t length = this->count(); for (int64_t i = 0; i < length; i++) { const QChar ch = this->at(i); switch (ch.toLatin1()) { case '&': htmlString.append("&"); break; case '<': htmlString.append("<"); break; case '>': htmlString.append(">"); break; case '\'': htmlString.append("'"); break; case '\"': htmlString.append("""); break; case ' ': htmlString.append(" "); break; case '\n': htmlString.append("
"); break; default: htmlString.append(ch); break; } } return htmlString; } AString AString::fixUnicodeHyphens(bool* hyphenReplaced, bool* hadOtherNonAscii, const bool& quiet) const { AString ret = this->normalized(QString::NormalizationForm_C);//first, normalize multi-char forms to their combined equivalents, etc, tons of nasties for (int i = 0; i < ret.length(); ++i) { ushort charCode = ret[i].unicode(); if (charCode > 127) { if ((charCode >= 8208 && charCode <= 8213) || //hyphens, dashes, bar charCode == 8722 || //minus charCode == 11834 || charCode == 11835 || //two and three em dash charCode == 65123 || //small hyphen-minus charCode == 65293)// { if (!quiet) CaretLogFine("character code " + AString::number(charCode) + " replaced with ascii dash"); ret[i] = '-'; if (hyphenReplaced != NULL) *hyphenReplaced = true; } else {//other stuff if (!quiet) CaretLogInfo("non-ascii character code " + AString::number(charCode) + " not recognized as dash/hyphen/minus"); if (hadOtherNonAscii != NULL) *hadOtherNonAscii = true; } } } return ret; } /** * Returns the index position of any character in * 'str' in this string. * @param str Characters that are searched * for in this string. * @param from String position (default is first character). */ int32_t AString::indexOfAnyChar(const AString& str, int from) const { const AString& s = *this; const int len = s.length(); if (from < 0)//use the same "from" logic as Qt { from += len;//-2 starts at second to last character if (from < 0) from = 0;//can't start before the beginning } const int len2 = str.length(); for (int i = from; i < len; i++) { for (int j = 0; j < len2; j++) { if (s[i] == str[j]) { return i; } } } return -1; } /** * @return The index position of the first character that is NOT * the character 'ch'. Returns -1 if all characters in the * string are 'ch'. */ int32_t AString::indexNotOf(const QChar& ch) const { const int32_t len = length(); for (int32_t i = 0; i < len; i++) { if (at(i) != ch) { return i; } } return -1; } /** * Return a 'C' char array containing the value * of the string. This method is necessary since * on an instance of Ubuntu Linux, an invalid ASCII * character is found on the end of data returned * by toLocal8Bit().constData();. This method * will replace any non-ascii characters with "_". * All trailing non ASCII characters will be removed. * * @return * Char array of ASCII characters with a string * terminator '\0' at the end. Caller MUST * free memory by running delete[] on the * returned array. */ char* AString::toCharArray() const { /* * Convert to a byte array */ QByteArray byteArray = this->toLocal8Bit(); const int32_t numBytes = byteArray.length(); if (numBytes > 0) { char* charOut = new char[numBytes + 1];//are there any byteArrays that don't already come with a line terminator? int32_t lastAsciiChar = -1; for (int32_t i = 0; i < numBytes; i++) { char c = byteArray.at(i); if ((c == 10) || ((c >= 32) && (c <= 126))) { charOut[i] = c; lastAsciiChar = i; } else if((c == 0) && i == (numBytes-1)) { charOut[i] = c; } else { charOut[i] = '_'; } } charOut[lastAsciiChar + 1] = '\0'; return charOut; } char* s = new char[1]; s[0] = 0; return s; } /** * If this string is not empty append a newline. * Next, append the given string. */ void AString::appendWithNewLine(const AString& str) { if (isEmpty() == false) { append("\n"); } append(str); } /** * Count the number of matching characters with the other string * starting at the end of the strings. * * Example: this="someText" rhs="moreText" => result=4 * @rhs * The other string. * @return * Number of character that match from the end of this and rhs. */ int64_t AString::countMatchingCharactersFromEnd(const AString& rhs) const { int64_t matchCount = 0; const int64_t myLength = length(); const int64_t rhsLength = rhs.length(); const int64_t minLength = std::min(myLength, rhsLength); for (int32_t offset = 1; offset <= minLength; offset++) { if (at(myLength - offset) == rhs.at(rhsLength - offset)) { matchCount++; } else { break; } } return matchCount; } /** * Find the longest common prefix in the given vector of strings. * * @param v * A vector of strings * @return * Longest common prefix found (may be an empty string). */ AString AString::findLongestCommonPrefix(const std::vector& stringVector) { AString longestPrefix; const int32_t numStrings = static_cast(stringVector.size()); if (numStrings == 1) { CaretAssertVectorIndex(stringVector, 0); longestPrefix = stringVector[0]; } else if (numStrings > 1) { /* * Find string with shortest name */ CaretAssertVectorIndex(stringVector, 0); AString shortestString = stringVector[0]; for (const auto name : stringVector) { if (name.length() < shortestString.length()) { shortestString = name; } } /* * Loop through each character in the shortest string * until a character does not match in any strings */ const int32_t numChars = static_cast(shortestString.length()); for (int32_t ich = 0; ich < numChars; ich++) { const QChar character = shortestString.at(ich); bool allMatchFlag = true; for (const auto name : stringVector) { CaretAssert(ich < name.length()); if (name.at(ich) != character) { allMatchFlag = false; } } if (allMatchFlag) { longestPrefix.append(character); } else { break; } } } /* * If the last character is a '/', remove it */ if (longestPrefix.length() > 1) { if (longestPrefix.endsWith('/')) { longestPrefix.resize(longestPrefix.length() - 1); } } const bool debugFlag = false; if (debugFlag) { std::cout << "Longest prefix: " << longestPrefix << std::endl; for (const auto name : stringVector) { std::cout << " " << name << std::endl; } } return longestPrefix; } /** * Convert a QStringList to an std::vector of AStrings. * * @param stringList * The QStringList * @return * Vector with elements copied from the string list. */ std::vector AString::stringListToVector(const QStringList& stringList) { std::vector sv(stringList.begin(), stringList.end()); return sv; } /** * Join the elements from the string vector adding 'separator' * between each of the elements. * * @param elements * Elements joined to form a string. * @param separtor * Characters added between each pair of elements. */ AString AString::join(const std::vector& elements, const AString& separator) { AString joinedString; const int32_t numElements = static_cast(elements.size()); for (int32_t i = 0; i < numElements; i++) { if (i > 0) { joinedString.append(separator); } CaretAssertVectorIndex(elements, i); joinedString.append(elements[i]); } return joinedString; } /** * Count the number of corresponding matching elements from the two vectors. * Compares first element in each, second element in each, etc and stops * when the elements at the same index are different or no more * elements in one of the vectors. * * @param v1 * The first vector. * @param v2 * The second vector. * @return * Number of matching elements. */ int32_t AString::matchingCount(const std::vector& v1, const std::vector& v2) { const int32_t count = std::min(v1.size(), v2.size()); if (count <= 0) { return 0; } int32_t matchCount = count; for (int32_t i = 0; i < count; i++) { CaretAssertVectorIndex(v1, i); CaretAssertVectorIndex(v2, i); if (v1[i] != v2[i]) { matchCount = i; break; } } return matchCount; } connectome-workbench-1.4.2/src/Common/AString.h000066400000000000000000000156211360521144700213770ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #ifndef ASTRING_H #define ASTRING_H #include #include #include namespace caret { class AString : public QString { public: AString() : QString() {} AString(const QChar *unicode, int size) : QString(unicode, size) {} explicit AString(const QChar *unicode) : QString(unicode) {} // Qt5: merge with the above AString(QChar c) : QString(c) {} AString(int size, QChar c) : QString(size, c) {} AString(const QLatin1String &latin1) : QString(latin1) {} AString(const QString &string) : QString(string) {} AString(const char *ch) : QString(ch){} AString(const QByteArray &a) : QString(a) {} AString(const Null &t) : QString(t) {} AString &operator=(const Null &t) { QString::operator=(t); return *this; } //AString(int size, Qt::Initialization) : QString(size,Qt::Initialization) {} //using QString::operator=; AString &operator=(QChar c) { QString::operator=(c); return *this;} AString &operator=(const QString &string) { QString::operator=(string); return *this;} AString &operator=(const QLatin1String &latin1) { QString::operator=(latin1); return *this;} AString &operator=(const char *ch) { QString::operator=(ch); return *this;} AString &operator=(const QByteArray &a) { QString::operator=(a); return *this;} AString &operator=(char c) { QString::operator=(c); return *this;} //std::string compatibility operator std::string () {return this->toStdString(); } //char * compatibility operator const char* () {return this->toLatin1(); } //double compatiblity operator double () {return this->toDouble(); } //float compatiblity operator float () { return this->toFloat(); } //int compatiblity operator int () { return this->toInt(); } //long compatiblity operator long () { return this->toLong(); } //long long compatiblity operator long long () { return this->toLongLong(); } //unsigned int compatiblity operator unsigned int () { return this->toUInt(); } //unsigned long compatiblity operator unsigned long () { return this->toULong(); } //unsigned long long compatiblity operator unsigned long long () { return this->toULongLong(); } /// convert to a const char* (the operator() does not work in C++ library I/O functions) //const char* c_str() const { return qPrintable(*this); } char* toCharArray() const; AString convertURLsToHyperlinks() const; AString convertToHtmlPage() const; AString convertToHtmlPageWithFontSize(const int fontSize) const; AString convertToHtmlPageWithCssFontHeight(const int fontHeight) const; int32_t indexOfAnyChar(const AString& str, int from = 0) const; int32_t indexNotOf(const QChar& ch) const; void appendWithNewLine(const AString& str); int64_t countMatchingCharactersFromEnd(const AString& rhs) const; static void toNumbers(const AString& s, std::vector& numbersOut); static void toNumbers(const AString& s, std::vector& numbersOut); bool toBool() const; //I may move these outside the class since they don't require access to the class's internals static AString fromNumbers(const std::vector& v, const AString& separator); static AString fromNumbers(const std::vector& v, const AString& separator); static AString fromNumbers(const std::vector& v, const AString& separator); static AString fromNumbers(const std::vector& v, const AString& separator); static AString fromNumbers(const std::vector& v, const AString& separator); static AString fromNumbers(const std::vector& v, const AString& separator); static AString fromNumbers(const std::vector& v, const AString& separator, const char format = 'g', const int32_t precision = 6); static AString fromNumbers(const std::vector& v, const AString& separator, const char format = 'g', const int32_t precision = 6); static AString fromNumbers(const float* array, const int64_t numberOfElements, const AString& separator, char format = 'g', const int32_t precision = 6); static AString fromNumbers(const uint8_t* array,const int64_t numberOfElements, const AString& separator); static AString fromNumbers(const int8_t* array,const int64_t numberOfElements, const AString& separator); static AString fromNumbers(const int32_t* array,const int64_t numberOfElements, const AString& separator); static AString fromNumbers(const int64_t* array,const int64_t numberOfElements, const AString& separator); static AString fromNumbers(const double* array, const int64_t numberOfElements, const AString& separator, const char format = 'g', const int32_t precision = 6); static AString fromBool(const bool b); AString replaceHtmlSpecialCharactersWithEscapeCharacters() const; AString fixUnicodeHyphens(bool* hyphenReplaced = NULL, bool* hadOtherNonAscii = NULL, const bool& quiet = false) const; static AString findLongestCommonPrefix(const std::vector& v); static std::vector stringListToVector(const QStringList& stringList); static AString join(const std::vector& elements, const AString& separator); static int32_t matchingCount(const std::vector& v1, const std::vector& v2); }; } #include #include std::ostream& operator << (std::ostream &lhs, const caret::AString &rhs); #endif // ASTRING_H connectome-workbench-1.4.2/src/Common/AStringNaturalComparison.cxx000066400000000000000000000153621360521144700253360ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __A_STRING_NATURAL_COMPARISON_DECLARE__ #include "AStringNaturalComparison.h" #undef __A_STRING_NATURAL_COMPARISON_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AStringNaturalComparison * \brief Class for performing a "natural comparison" of strings. * \ingroup Common * * This class is designed for use as a function object with the * Standard Template Library. However, it also contains a static * method for naturally comparing" two strings. * * Normal string comparison just compares the ASCII values of characters. * However, when the string contains numeric sequences, the strings are * sorted as expected. This class will perform string comparison where * any sequence of numbers is treated as a 'single character'. * * When the two 'characters' being compared are both non-numeric, they are * compared by their ASCII codes. When the two 'characters' being compared * are both numbers, a numeric comparison is performed. When one 'character' * is numeric and the other 'character' is non-numeric, the number is * considered "less than". * * Sequence produced by normal string comparison (note the position of 32abc): * 1xyz, 32abc, 4ab * * Sequence produced by natural string comparison (note the position of 32abc): * 1xyz, 4ab, 32abc */ /** * Constructor. */ AStringNaturalComparison::AStringNaturalComparison() { } /** * Destructor. */ AStringNaturalComparison::~AStringNaturalComparison() { } /** * Function object so that this class can be used as for * comparison in Standard Template Library containers. * * Performs a NATURAL COMPARISON where a contiguous sequence * of digits is treated as a single character so that text * string with numbers in them are properly sorted. * * @param s1 * First string for comparison. * @param s2 * Second string for comparison. * @return * Negative value if (s1 < s2), Positive if (s1 > s2), and * Zero if (s1 == s2). */ bool AStringNaturalComparison::operator() (const AString& s1, const AString& s2) const { const int32_t result = AStringNaturalComparison::compare(s1, s2); // std::cout << "Compare (" // << qPrintable(s1) // << ", " // << qPrintable(s2) // << "): " // << AString::fromBool(result) // << std::endl; if (result < 0) { return true; } return false; } /** * Static method for natural comparison of two strings. * * Performs a NATURAL COMPARISON where a contiguous sequence * of digits is treated as a single character so that text * string with numbers in them are properly sorted. * * @param string1 * First string for comparison. * @param string2 * Second string for comparison. * @return * Negative value if (string1 < string2), Positive if (string1 > string2), and * Zero if (string1 == string2). */ int32_t AStringNaturalComparison::compare(const AString& string1, const AString& string2) { const StringParser s1(string1); const StringParser s2(string2); bool s1IsNumber = false; bool s2IsNumber = false; /* * Loop through the 'characters' until corresponding * 'characters' do not match. * * Note that a consecutive sequence of digits is * considered a single 'character'. */ while (s1.hasMore() && s2.hasMore()) { const int64_t ch1 = s1.nextChar(s1IsNumber); const int64_t ch2 = s2.nextChar(s2IsNumber); CaretAssert(ch1 >= 0); CaretAssert(ch2 >= 0); if (s1IsNumber && s2IsNumber) { /* * Both 'character's are numbers */ if (ch1 < ch2) { return -1; } else if (ch1 > ch2) { return 1; } } else if (s1IsNumber) { return -1; } else if (s2IsNumber) { return 1; } else { /* * Both 'characters' are NOT numbers */ if (ch1 < ch2) { return -1; } else if (ch1 > ch2) { return 1; } } } /* * The shorter string is considered "less than" */ if (s1.hasMore()) { return 1; } else if (s2.hasMore()) { return -1; } /* * Strings must be identical. */ return 0; } /* ===================================================================== */ /** * \class caret::AStringNaturalComparison::StringParser * \brief Class for "String parsing" that treats any consecutive sequence * of numbers as a single character. * \ingroup Common */ /** * Constructor. * * @param s * String that will be parsed. */ AStringNaturalComparison::StringParser::StringParser(const AString& s) : m_s(s), m_pos(0), m_len(s.length()) { } /** * Returns the "next character" in the string. Any consecutive sequence of * digits is considered a single character. * * @param isNumberOut * If the value returned is a number, this parameter will be true, * else false. * @return * The unicode value for the next character or numeric value os a * sequence of digits. */ int64_t AStringNaturalComparison::StringParser::nextChar(bool& isNumberOut) const { isNumberOut = false; if (m_pos >= m_len) { return -1; } const QChar ch = m_s[m_pos]; ++m_pos; if (ch.isDigit()) { int64_t numericValue = ch.digitValue(); while (m_pos < m_len) { const QChar nextChar = m_s[m_pos]; if (nextChar.isDigit()) { ++m_pos; numericValue = (numericValue * 10) + nextChar.digitValue(); } else { break; } } isNumberOut = true; return numericValue; } else { return ch.unicode(); } return -1; } connectome-workbench-1.4.2/src/Common/AStringNaturalComparison.h000066400000000000000000000042671360521144700247650ustar00rootroot00000000000000#ifndef __A_STRING_NATURAL_COMPARISON_H__ #define __A_STRING_NATURAL_COMPARISON_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AString.h" namespace caret { class AStringNaturalComparison { public: AStringNaturalComparison(); AStringNaturalComparison(const AStringNaturalComparison&) { } virtual ~AStringNaturalComparison(); bool operator() (const AString& s1, const AString& s2) const; static int32_t compare(const AString& string1, const AString& string2); // ADD_NEW_METHODS_HERE private: AStringNaturalComparison& operator=(const AStringNaturalComparison&); // ADD_NEW_MEMBERS_HERE class StringParser { public: StringParser(const AString& s); int64_t nextChar(bool& isNumberOut) const; inline bool hasMore() const { return (m_pos < m_len); } private: const AString& m_s; mutable int32_t m_pos; int32_t m_len; }; }; #ifdef __A_STRING_NATURAL_COMPARISON_DECLARE__ // #endif // __A_STRING_NATURAL_COMPARISON_DECLARE__ } // namespace #endif //__A_STRING_NATURAL_COMPARISON_H__ connectome-workbench-1.4.2/src/Common/ApplicationInformation.cxx.in000066400000000000000000000152321360521144700254570ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __APPLICATION_INFORMATION_DECLARE__ #include "ApplicationInformation.h" #undef __APPLICATION_INFORMATION_DECLARE__ #include "CaretOMP.h" #include "FileInformation.h" using namespace caret; /** * \class caret::ApplicationInformation * \brief Provides application information. * * Provides application information (name, version, etc). */ /** * Constructor. */ ApplicationInformation::ApplicationInformation() : CaretObject() { this->workbenchSpecialVersion = WorkbenchSpecialVersionEnum::WORKBENCH_SPECIAL_VERSION_NO; //this->workbenchSpecialVersion = WorkbenchSpecialVersionEnum::WORKBENCH_SPECIAL_VERSION_FIRST_CHARTING; this->name = "Connectome Workbench"; this->nameForGuiLabel = this->name; switch (this->workbenchSpecialVersion) { case WorkbenchSpecialVersionEnum::WORKBENCH_SPECIAL_VERSION_NO: /* use default naming */ break; case WorkbenchSpecialVersionEnum::WORKBENCH_SPECIAL_VERSION_FIRST_CHARTING: this->name = "Connectome Workbench (First Charting Version)"; this->nameForGuiLabel = ("" "Connectome Workbench
" "(First Charting Version)" ""); break; } /* * Version now gets set at the top of the main CMakeLists.txt only. */ this->version = "@VERSION@"; this->commit = "Commit: @COMMIT@"; this->commitDate = "Commit Date: @COMMIT_DATE@"; #ifdef NDEBUG this->compiledWithDebugOn = "Compiled Debug: NO"; #else this->compiledWithDebugOn = "Compiled Debug: YES"; #endif // NDEBUG #ifdef CARET_OMP this->compiledWithOpenMP = "Compiled with OpenMP: YES"; #else this->compiledWithOpenMP = "Compiled with OpenMP: NO"; #endif this->operatingSystemName = "Operating System: Unknown"; #ifdef CARET_OS_LINUX this->operatingSystemName = "Operating System: Linux"; #endif // CARET_OS_MACOSX #ifdef CARET_OS_MACOSX this->operatingSystemName = "Operating System: Apple OSX"; #endif // CARET_OS_MACOSX #ifdef CARET_OS_WINDOWS this->operatingSystemName = "Operating System: Windows"; #endif // CARET_OS_MACOSX } /** * Destructor. */ ApplicationInformation::~ApplicationInformation() { } /** * @return Name of the application. */ AString ApplicationInformation::getName() const { return this->name; } /** * @return Name of the application formatted * specifically for use in a GUI QLabel. */ AString ApplicationInformation::getNameForGuiLabel() const { return this->nameForGuiLabel; } /** * @return Version of application. */ AString ApplicationInformation::getVersion() const { return this->version; } /** * @return Commit info of application. */ AString ApplicationInformation::getCommit() const { return this->commit; } /** * @return Text indicating if Workbench was compiled with Debug on. */ AString ApplicationInformation::getCompiledWithDebugStatus() const { return this->compiledWithDebugOn; } /** * Get all information. * @param informationValues * Output information. */ void ApplicationInformation::getAllInformation(std::vector& informationValues) const { informationValues.clear(); informationValues.push_back(this->name); informationValues.push_back("Type: " + ApplicationTypeEnum::toGuiName(s_applicationType)); informationValues.push_back("Version: " + this->version); informationValues.push_back("Qt Compiled Version: " + QString(QT_VERSION_STR)); informationValues.push_back("Qt Runtime Version: " + QString(qVersion())); informationValues.push_back(commit); informationValues.push_back(commitDate); informationValues.push_back(compiledWithOpenMP); #if defined COMPILER_NAME FileInformation fileInfo(COMPILER_NAME); informationValues.push_back(QString("Compiler: ") + fileInfo.getFileNameFollowedByPathNameForGUI()); #endif #if defined COMPILER_VERSION informationValues.push_back(QString("Compiler Version: ") + QString(COMPILER_VERSION)); #endif informationValues.push_back(this->compiledWithDebugOn); informationValues.push_back(this->operatingSystemName); } /** * Get all of the application information in a string with each line * separated by the given 'separator'. * * @param separator * The separator is placed between each line of information. A newline * ("\n") is commonly used for the separator. */ AString ApplicationInformation::getAllInformationInString(const AString& separator) const { std::vector informationValues; getAllInformation(informationValues); AString infoOut; for (std::vector::iterator iter = informationValues.begin(); iter != informationValues.end(); iter++) { infoOut += *iter; infoOut += separator; } return infoOut; } AString ApplicationInformation::getSummaryInformationInString(const AString& separator) const { AString infoOut = "Version: " + version + separator; infoOut += commitDate + separator; infoOut += operatingSystemName + separator; return infoOut; } /** * @return The Workbench Special Version * * Used for versions of Workbench that may or may * not be released and contains special functionality. */ WorkbenchSpecialVersionEnum::Enum ApplicationInformation::getWorkbenchSpecialVersion() const { return this->workbenchSpecialVersion; } /** * @return The type of application. */ ApplicationTypeEnum::Enum ApplicationInformation::getApplicationType() { return s_applicationType; } /** * Set the application type. * * @param applicationType * New value for application type. */ void ApplicationInformation::setApplicationType(const ApplicationTypeEnum::Enum applicationType) { s_applicationType = applicationType; } connectome-workbench-1.4.2/src/Common/ApplicationInformation.h000066400000000000000000000054501360521144700245000ustar00rootroot00000000000000#ifndef __APPLICATION_INFORMATION__H_ #define __APPLICATION_INFORMATION__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ApplicationTypeEnum.h" #include "CaretObject.h" #include "WorkbenchSpecialVersionEnum.h" namespace caret { class ApplicationInformation : public CaretObject { public: ApplicationInformation(); virtual ~ApplicationInformation(); AString getName() const; AString getNameForGuiLabel() const; AString getVersion() const; AString getCommit() const; void getAllInformation(std::vector& informationValues) const; AString getAllInformationInString(const AString& separator) const; AString getSummaryInformationInString(const AString& separator) const; AString getCompiledWithDebugStatus() const; WorkbenchSpecialVersionEnum::Enum getWorkbenchSpecialVersion() const; static ApplicationTypeEnum::Enum getApplicationType(); static void setApplicationType(const ApplicationTypeEnum::Enum applicationType); private: ApplicationInformation(const ApplicationInformation&); ApplicationInformation& operator=(const ApplicationInformation&); AString name; AString nameForGuiLabel; AString version; AString commit; AString commitDate; AString compiledWithDebugOn; AString operatingSystemName; AString compiledWithOpenMP; WorkbenchSpecialVersionEnum::Enum workbenchSpecialVersion; static ApplicationTypeEnum::Enum s_applicationType; }; #ifdef __APPLICATION_INFORMATION_DECLARE__ ApplicationTypeEnum::Enum ApplicationInformation::s_applicationType = ApplicationTypeEnum::APPLICATION_TYPE_INVALID; #endif // __APPLICATION_INFORMATION_DECLARE__ } // namespace #endif //__APPLICATION_INFORMATION__H_ connectome-workbench-1.4.2/src/Common/ApplicationTypeEnum.cxx000066400000000000000000000253031360521144700243330ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __APPLICATION_TYPE_ENUM_DECLARE__ #include "ApplicationTypeEnum.h" #undef __APPLICATION_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ApplicationTypeEnum * \brief * * * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_applicationTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void applicationTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ApplicationTypeEnum.h" * * Instatiate: * m_applicationTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_applicationTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_applicationTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(applicationTypeEnumComboBoxItemActivated())); * * Update the selection: * m_applicationTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ApplicationTypeEnum::Enum VARIABLE = m_applicationTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ApplicationTypeEnum::ApplicationTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ApplicationTypeEnum::~ApplicationTypeEnum() { } /** * Initialize the enumerated metadata. */ void ApplicationTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ApplicationTypeEnum(APPLICATION_TYPE_INVALID, "APPLICATION_TYPE_INVALID", "Invalid or Not Set")); enumData.push_back(ApplicationTypeEnum(APPLICATION_TYPE_COMMAND_LINE, "APPLICATION_TYPE_COMMAND_LINE", "Command Line Application")); enumData.push_back(ApplicationTypeEnum(APPLICATION_TYPE_GRAPHICAL_USER_INTERFACE, "APPLICATION_TYPE_GRAPHICAL_USER_INTERFACE", "Graphical User Interface Application")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ApplicationTypeEnum* ApplicationTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ApplicationTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ApplicationTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ApplicationTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ApplicationTypeEnum::Enum ApplicationTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ApplicationTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ApplicationTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ApplicationTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ApplicationTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ApplicationTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ApplicationTypeEnum::Enum ApplicationTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ApplicationTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ApplicationTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ApplicationTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ApplicationTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ApplicationTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ApplicationTypeEnum::Enum ApplicationTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ApplicationTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ApplicationTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ApplicationTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ApplicationTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ApplicationTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ApplicationTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ApplicationTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ApplicationTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/ApplicationTypeEnum.h000066400000000000000000000063041360521144700237600ustar00rootroot00000000000000#ifndef __APPLICATION_TYPE_ENUM_H__ #define __APPLICATION_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ApplicationTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Invalid */ APPLICATION_TYPE_INVALID, /** Command Line Application */ APPLICATION_TYPE_COMMAND_LINE, /** Graphical User Interface Application */ APPLICATION_TYPE_GRAPHICAL_USER_INTERFACE }; ~ApplicationTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ApplicationTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ApplicationTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __APPLICATION_TYPE_ENUM_DECLARE__ std::vector ApplicationTypeEnum::enumData; bool ApplicationTypeEnum::initializedFlag = false; int32_t ApplicationTypeEnum::integerCodeCounter = 0; #endif // __APPLICATION_TYPE_ENUM_DECLARE__ } // namespace #endif //__APPLICATION_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Common/BackgroundAndForegroundColors.cxx000066400000000000000000000363251360521144700263260ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BACKGROUND_AND_FOREGROUND_COLORS_DECLARE__ #include "BackgroundAndForegroundColors.h" #undef __BACKGROUND_AND_FOREGROUND_COLORS_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::BackgroundAndForegroundColors * \brief Contains background and foreground colors used in graphics drawing. * \ingroup Common */ /** * Constructor. */ BackgroundAndForegroundColors::BackgroundAndForegroundColors() : CaretObject() { reset(); } /** * Destructor. */ BackgroundAndForegroundColors::~BackgroundAndForegroundColors() { } /** * Copy constructor. * @param obj * Object that is copied. */ BackgroundAndForegroundColors::BackgroundAndForegroundColors(const BackgroundAndForegroundColors& obj) : CaretObject(obj) { copyHelperBackgroundAndForegroundColors(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ BackgroundAndForegroundColors& BackgroundAndForegroundColors::operator=(const BackgroundAndForegroundColors& obj) { if (this != &obj) { CaretObject::operator=(obj); copyHelperBackgroundAndForegroundColors(obj); } return *this; } /** * Equality operator * * @param obj * Compare 'this' to 'obj' for equality * @return * True if 'this' is equal to 'obj', else false. */ bool BackgroundAndForegroundColors::operator==(const BackgroundAndForegroundColors& obj) const { bool equalFlag(true); for (int32_t i = 0; i < 3; i++) { if (m_colorForegroundWindow[i] != obj.m_colorForegroundWindow[i]) { equalFlag = false; break; } if (m_colorBackgroundWindow[i] !=obj.m_colorBackgroundWindow[i]) { equalFlag = false; break; } if (m_colorForegroundAll[i] != obj.m_colorForegroundAll[i]) { equalFlag = false; break; } if (m_colorBackgroundAll[i] !=obj.m_colorBackgroundAll[i]) { equalFlag = false; break; } if (m_colorForegroundChart[i] != obj.m_colorForegroundChart[i]) { equalFlag = false; break; } if (m_colorBackgroundChart[i] != obj.m_colorBackgroundChart[i]) { equalFlag = false; break; } if (m_colorForegroundSurface[i] != obj.m_colorForegroundSurface[i]) { equalFlag = false; break; } if (m_colorBackgroundSurface[i] != obj.m_colorBackgroundSurface[i]) { equalFlag = false; break; } if (m_colorForegroundVolume[i] != obj.m_colorForegroundVolume[i]) { equalFlag = false; break; } if (m_colorBackgroundVolume[i] != obj.m_colorBackgroundVolume[i]) { equalFlag = false; break; } if (m_colorChartMatrixGridLines[i] != obj.m_colorChartMatrixGridLines[i]) { equalFlag = false; break; } if (m_colorChartHistogramThreshold[i] != obj.m_colorChartHistogramThreshold[i]) { equalFlag = false; break; } } return equalFlag; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void BackgroundAndForegroundColors::copyHelperBackgroundAndForegroundColors(const BackgroundAndForegroundColors& obj) { for (int32_t i = 0; i < 3; i++) { m_colorForegroundWindow[i] = obj.m_colorForegroundWindow[i]; m_colorBackgroundWindow[i] = obj.m_colorBackgroundWindow[i]; m_colorForegroundAll[i] = obj.m_colorForegroundAll[i]; m_colorBackgroundAll[i] = obj.m_colorBackgroundAll[i]; m_colorForegroundChart[i] = obj.m_colorForegroundChart[i]; m_colorBackgroundChart[i] = obj.m_colorBackgroundChart[i]; m_colorForegroundSurface[i] = obj.m_colorForegroundSurface[i]; m_colorBackgroundSurface[i] = obj.m_colorBackgroundSurface[i]; m_colorForegroundVolume[i] = obj.m_colorForegroundVolume[i]; m_colorBackgroundVolume[i] = obj.m_colorBackgroundVolume[i]; m_colorChartMatrixGridLines[i] = obj.m_colorChartMatrixGridLines[i]; m_colorChartHistogramThreshold[i] = obj.m_colorChartHistogramThreshold[i]; } } /** * Reset the colors to the default values. */ void BackgroundAndForegroundColors::reset() { const uint8_t backRed = 0; const uint8_t backGreen = 0; const uint8_t backBlue = 0; const uint8_t foreRed = 255; const uint8_t foreGreen = 255; const uint8_t foreBlue = 255; setColor(m_colorForegroundWindow, foreRed, foreGreen, foreBlue); setColor(m_colorBackgroundWindow, backRed, backGreen, backBlue); setColor(m_colorForegroundAll, foreRed, foreGreen, foreBlue); setColor(m_colorBackgroundAll, backRed, backGreen, backBlue); setColor(m_colorForegroundChart, foreRed, foreGreen, foreBlue); setColor(m_colorBackgroundChart, backRed, backGreen, backBlue); setColor(m_colorForegroundSurface, foreRed, foreGreen, foreBlue); setColor(m_colorBackgroundSurface, backRed, backGreen, backBlue); setColor(m_colorForegroundVolume, foreRed, foreGreen, foreBlue); setColor(m_colorBackgroundVolume, backRed, backGreen, backBlue); const uint8_t chartRed = 255; const uint8_t chartGreen = 255; const uint8_t chartBlue = 255; setColor(m_colorChartMatrixGridLines, chartRed, chartGreen, chartBlue); const uint8_t threshRed = 100; const uint8_t threshGreen = 100; const uint8_t threshBlue = 255; setColor(m_colorChartHistogramThreshold, threshRed, threshGreen, threshBlue); } /** * Get the foreground color for the window. * * @param colorForeground * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::getColorForegroundWindow(uint8_t colorForeground[3]) const { for (int32_t i = 0; i < 3; i++) { colorForeground[i] = m_colorForegroundWindow[i]; } } /** * Set the foreground color for the window. * * @param colorForeground * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::setColorForegroundWindow(const uint8_t colorForeground[3]) { for (int32_t i = 0; i < 3; i++) { m_colorForegroundWindow[i] = colorForeground[i]; } } /** * Get the background color for the window. * * @param colorBackground * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::getColorBackgroundWindow(uint8_t colorBackground[3]) const { for (int32_t i = 0; i < 3; i++) { colorBackground[i] = m_colorBackgroundWindow[i]; } } /** * Set the background color for the window. * * @param colorBackground * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::setColorBackgroundWindow(const uint8_t colorBackground[3]) { for (int32_t i = 0; i < 3; i++) { m_colorBackgroundWindow[i] = colorBackground[i]; } } /** * Get the foreground color for viewing the ALL model. * * @param colorForeground * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::getColorForegroundAllView(uint8_t colorForeground[3]) const { for (int32_t i = 0; i < 3; i++) { colorForeground[i] = m_colorForegroundAll[i]; } } /** * Set the foreground color for viewing the ALL model. * * @param colorForeground * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::setColorForegroundAllView(const uint8_t colorForeground[3]) { for (int32_t i = 0; i < 3; i++) { m_colorForegroundAll[i] = colorForeground[i]; } } /** * Get the background color for viewing the ALL model. * * @param colorBackground * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::getColorBackgroundAllView(uint8_t colorBackground[3]) const { for (int32_t i = 0; i < 3; i++) { colorBackground[i] = m_colorBackgroundAll[i]; } } /** * Set the background color for viewing the ALL model. * * @param colorBackground * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::setColorBackgroundAllView(const uint8_t colorBackground[3]) { for (int32_t i = 0; i < 3; i++) { m_colorBackgroundAll[i] = colorBackground[i]; } } /** * Get the foreground color for viewing the CHART model. * * @param colorForeground * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::getColorForegroundChartView(uint8_t colorForeground[3]) const { for (int32_t i = 0; i < 3; i++) { colorForeground[i] = m_colorForegroundChart[i]; } } /** * Set the foreground color for viewing the CHART model. * * @param colorForeground * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::setColorForegroundChartView(const uint8_t colorForeground[3]) { for (int32_t i = 0; i < 3; i++) { m_colorForegroundChart[i] = colorForeground[i]; } } /** * Get the background color for viewing the CHART model. * * @param colorBackground * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::getColorBackgroundChartView(uint8_t colorBackground[3]) const { for (int32_t i = 0; i < 3; i++) { colorBackground[i] = m_colorBackgroundChart[i]; } } /** * Set the background color for viewing the CHART model. * * @param colorBackground * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::setColorBackgroundChartView(const uint8_t colorBackground[3]) { for (int32_t i = 0; i < 3; i++) { m_colorBackgroundChart[i] = colorBackground[i]; } } /** * Get the foreground color for viewing the SURFACE model. * * @param colorForeground * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::getColorForegroundSurfaceView(uint8_t colorForeground[3]) const { for (int32_t i = 0; i < 3; i++) { colorForeground[i] = m_colorForegroundSurface[i]; } } /** * Set the foreground color for viewing the SURFACE model. * * @param colorForeground * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::setColorForegroundSurfaceView(const uint8_t colorForeground[3]) { for (int32_t i = 0; i < 3; i++) { m_colorForegroundSurface[i] = colorForeground[i]; } } /** * Get the background color for viewing the SURFACE model. * * @param colorBackground * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::getColorBackgroundSurfaceView(uint8_t colorBackground[3]) const { for (int32_t i = 0; i < 3; i++) { colorBackground[i] = m_colorBackgroundSurface[i]; } } /** * Get the background color for viewing the SURFACE model. * * @param colorBackground * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::setColorBackgroundSurfaceView(const uint8_t colorBackground[3]) { for (int32_t i = 0; i < 3; i++) { m_colorBackgroundSurface[i] = colorBackground[i]; } } /** * Get the foreground color for viewing the VOLUME model. * * @param colorForeground * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::getColorForegroundVolumeView(uint8_t colorForeground[3]) const { for (int32_t i = 0; i < 3; i++) { colorForeground[i] = m_colorForegroundVolume[i]; } } /** * Set the foreground color for viewing the VOLUME model. * * @param colorForeground * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::setColorForegroundVolumeView(const uint8_t colorForeground[3]) { for (int32_t i = 0; i < 3; i++) { m_colorForegroundVolume[i] = colorForeground[i]; } } /** * Get the background color for viewing the VOLUME model. * * @param colorBackground * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::getColorBackgroundVolumeView(uint8_t colorBackground[3]) const { for (int32_t i = 0; i < 3; i++) { colorBackground[i] = m_colorBackgroundVolume[i]; } } /** * Set the background color for viewing the VOLUME model. * * @param colorBackground * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::setColorBackgroundVolumeView(const uint8_t colorBackground[3]) { for (int32_t i = 0; i < 3; i++) { m_colorBackgroundVolume[i] = colorBackground[i]; } } /** * Get the color for chart matrix grid lines * * @param colorChartMatrixGridLines * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::getColorChartMatrixGridLines(uint8_t colorChartMatrixGridLines[3]) const { for (int32_t i = 0; i < 3; i++) { colorChartMatrixGridLines[i] = m_colorChartMatrixGridLines[i]; } } /** * Set the color for chart matrix grid lines * * @param colorChartMatrixGridLines * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::setColorChartMatrixGridLines(const uint8_t colorChartMatrixGridLines[3]) { for (int32_t i = 0; i < 3; i++) { m_colorChartMatrixGridLines[i] = colorChartMatrixGridLines[i]; } } /** * Get the color for chart histogram threshold * * @param colorChartHistogramThreshold * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::getColorChartHistogramThreshold(uint8_t colorChartHistogramThreshold[3]) const { for (int32_t i = 0; i < 3; i++) { colorChartHistogramThreshold[i] = m_colorChartHistogramThreshold[i]; } } /** * Set the color for chart histogram threshold * * @param colorChartHistogramThreshold * RGB color components ranging [0, 255]. */ void BackgroundAndForegroundColors::setColorChartHistogramThreshold(const uint8_t colorChartHistogramThreshold[3]) { for (int32_t i = 0; i < 3; i++) { m_colorChartHistogramThreshold[i] = colorChartHistogramThreshold[i]; } } /** * Set a color with the given color components that range 0 to 255. * * @param color * Color that is set. * @param red * Red component. * @param green * Green component. * @param blue * Blue component. */ void BackgroundAndForegroundColors::setColor(uint8_t color[3], const uint8_t red, const uint8_t green, const uint8_t blue) { color[0] = red; color[1] = green; color[2] = blue; } connectome-workbench-1.4.2/src/Common/BackgroundAndForegroundColors.h000066400000000000000000000114341360521144700257450ustar00rootroot00000000000000#ifndef __BACKGROUND_AND_FOREGROUND_COLORS_H__ #define __BACKGROUND_AND_FOREGROUND_COLORS_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" namespace caret { class BackgroundAndForegroundColors : public CaretObject { public: BackgroundAndForegroundColors(); virtual ~BackgroundAndForegroundColors(); BackgroundAndForegroundColors(const BackgroundAndForegroundColors& obj); BackgroundAndForegroundColors& operator=(const BackgroundAndForegroundColors& obj); bool operator==(const BackgroundAndForegroundColors& obj) const; void reset(); // ADD_NEW_METHODS_HERE void getColorBackgroundWindow(uint8_t colorBackground[3]) const; void setColorBackgroundWindow(const uint8_t colorBackground[3]); void getColorForegroundWindow(uint8_t colorForeground[3]) const; void setColorForegroundWindow(const uint8_t colorForeground[3]); void getColorForegroundAllView(uint8_t colorForeground[3]) const; void setColorForegroundAllView(const uint8_t colorForeground[3]); void getColorBackgroundAllView(uint8_t colorForeground[3]) const; void setColorBackgroundAllView(const uint8_t colorForeground[3]); void getColorForegroundChartView(uint8_t colorForeground[3]) const; void setColorForegroundChartView(const uint8_t colorForeground[3]); void getColorBackgroundChartView(uint8_t colorForeground[3]) const; void setColorBackgroundChartView(const uint8_t colorForeground[3]); void getColorForegroundSurfaceView(uint8_t colorForeground[3]) const; void setColorForegroundSurfaceView(const uint8_t colorForeground[3]); void getColorBackgroundSurfaceView(uint8_t colorForeground[3]) const; void setColorBackgroundSurfaceView(const uint8_t colorForeground[3]); void getColorForegroundVolumeView(uint8_t colorForeground[3]) const; void setColorForegroundVolumeView(const uint8_t colorForeground[3]); void getColorBackgroundVolumeView(uint8_t colorForeground[3]) const; void setColorBackgroundVolumeView(const uint8_t colorForeground[3]); void getColorChartMatrixGridLines(uint8_t colorChartMatrixGridLines[3]) const; void setColorChartMatrixGridLines(const uint8_t colorChartMatrixGridLines[3]); void getColorChartHistogramThreshold(uint8_t colorChartMatrixGridLines[3]) const; void setColorChartHistogramThreshold(const uint8_t colorChartMatrixGridLines[3]); private: void copyHelperBackgroundAndForegroundColors(const BackgroundAndForegroundColors& obj); void setColor(uint8_t color[3], const uint8_t red, const uint8_t green, const uint8_t blue); uint8_t m_colorBackgroundWindow[3]; uint8_t m_colorForegroundWindow[3]; uint8_t m_colorForegroundAll[3]; uint8_t m_colorBackgroundAll[3]; uint8_t m_colorForegroundChart[3]; uint8_t m_colorBackgroundChart[3]; uint8_t m_colorForegroundSurface[3]; uint8_t m_colorBackgroundSurface[3]; uint8_t m_colorForegroundVolume[3]; uint8_t m_colorBackgroundVolume[3]; uint8_t m_colorChartMatrixGridLines[3]; uint8_t m_colorChartHistogramThreshold[3]; // ADD_NEW_MEMBERS_HERE friend class BackgroundAndForegroundColorsSceneHelper; friend class CaretPreferences; }; #ifdef __BACKGROUND_AND_FOREGROUND_COLORS_DECLARE__ // #endif // __BACKGROUND_AND_FOREGROUND_COLORS_DECLARE__ } // namespace #endif //__BACKGROUND_AND_FOREGROUND_COLORS_H__ connectome-workbench-1.4.2/src/Common/BackgroundAndForegroundColorsModeEnum.cxx000066400000000000000000000267461360521144700277660ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __BACKGROUND_AND_FOREGROUND_COLORS_MODE_ENUM_DECLARE__ #include "BackgroundAndForegroundColorsModeEnum.h" #undef __BACKGROUND_AND_FOREGROUND_COLORS_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::BackgroundAndForegroundColorsModeEnum * \brief * * * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_backgroundAndForegroundColorsModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void backgroundAndForegroundColorsModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "BackgroundAndForegroundColorsModeEnum.h" * * Instatiate: * m_backgroundAndForegroundColorsModeEnumComboBox = new EnumComboBoxTemplate(this); * m_backgroundAndForegroundColorsModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_backgroundAndForegroundColorsModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(backgroundAndForegroundColorsModeEnumComboBoxItemActivated())); * * Update the selection: * m_backgroundAndForegroundColorsModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const BackgroundAndForegroundColorsModeEnum::Enum VARIABLE = m_backgroundAndForegroundColorsModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ BackgroundAndForegroundColorsModeEnum::BackgroundAndForegroundColorsModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ BackgroundAndForegroundColorsModeEnum::~BackgroundAndForegroundColorsModeEnum() { } /** * Initialize the enumerated metadata. */ void BackgroundAndForegroundColorsModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(BackgroundAndForegroundColorsModeEnum(SCENE, "SCENE", "Scene")); enumData.push_back(BackgroundAndForegroundColorsModeEnum(USER_PREFERENCES, "USER_PREFERENCES", "User Preferences")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const BackgroundAndForegroundColorsModeEnum* BackgroundAndForegroundColorsModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const BackgroundAndForegroundColorsModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString BackgroundAndForegroundColorsModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const BackgroundAndForegroundColorsModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ BackgroundAndForegroundColorsModeEnum::Enum BackgroundAndForegroundColorsModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = BackgroundAndForegroundColorsModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const BackgroundAndForegroundColorsModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type BackgroundAndForegroundColorsModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString BackgroundAndForegroundColorsModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const BackgroundAndForegroundColorsModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ BackgroundAndForegroundColorsModeEnum::Enum BackgroundAndForegroundColorsModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = BackgroundAndForegroundColorsModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const BackgroundAndForegroundColorsModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type BackgroundAndForegroundColorsModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t BackgroundAndForegroundColorsModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const BackgroundAndForegroundColorsModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ BackgroundAndForegroundColorsModeEnum::Enum BackgroundAndForegroundColorsModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = BackgroundAndForegroundColorsModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const BackgroundAndForegroundColorsModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type BackgroundAndForegroundColorsModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void BackgroundAndForegroundColorsModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void BackgroundAndForegroundColorsModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(BackgroundAndForegroundColorsModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void BackgroundAndForegroundColorsModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(BackgroundAndForegroundColorsModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/BackgroundAndForegroundColorsModeEnum.h000066400000000000000000000065141360521144700274020ustar00rootroot00000000000000#ifndef __BACKGROUND_AND_FOREGROUND_COLORS_MODE_ENUM_H__ #define __BACKGROUND_AND_FOREGROUND_COLORS_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class BackgroundAndForegroundColorsModeEnum { public: /** * Enumerated values. */ enum Enum { /** Scene Colors */ SCENE, /** User Preferences Colors */ USER_PREFERENCES }; ~BackgroundAndForegroundColorsModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: BackgroundAndForegroundColorsModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const BackgroundAndForegroundColorsModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __BACKGROUND_AND_FOREGROUND_COLORS_MODE_ENUM_DECLARE__ std::vector BackgroundAndForegroundColorsModeEnum::enumData; bool BackgroundAndForegroundColorsModeEnum::initializedFlag = false; int32_t BackgroundAndForegroundColorsModeEnum::integerCodeCounter = 0; #endif // __BACKGROUND_AND_FOREGROUND_COLORS_MODE_ENUM_DECLARE__ } // namespace #endif //__BACKGROUND_AND_FOREGROUND_COLORS_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Common/Base64.cxx000066400000000000000000000223521360521144700214260ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /*========================================================================= Program: Visualization Toolkit Module: $RCSfile: Base64.cxx,v $ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "CaretAssert.h" #include "Base64.h" using namespace caret; //---------------------------------------------------------------------------- static const unsigned char Base64EncodeTable[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; //---------------------------------------------------------------------------- inline static unsigned char Base64EncodeChar(unsigned char c) { CaretAssert( c < 65 ); return Base64EncodeTable[c]; } Base64::Base64() {} Base64::~Base64() {} //---------------------------------------------------------------------------- void Base64::EncodeTriplet(unsigned char i0, unsigned char i1, unsigned char i2, unsigned char *o0, unsigned char *o1, unsigned char *o2, unsigned char *o3) { *o0 = Base64EncodeChar((i0 >> 2) & 0x3F); *o1 = Base64EncodeChar(((i0 << 4) & 0x30)|((i1 >> 4) & 0x0F)); *o2 = Base64EncodeChar(((i1 << 2) & 0x3C)|((i2 >> 6) & 0x03)); *o3 = Base64EncodeChar(i2 & 0x3F); } //---------------------------------------------------------------------------- void Base64::EncodePair(unsigned char i0, unsigned char i1, unsigned char *o0, unsigned char *o1, unsigned char *o2, unsigned char *o3) { *o0 = Base64EncodeChar((i0 >> 2) & 0x3F); *o1 = Base64EncodeChar(((i0 << 4) & 0x30)|((i1 >> 4) & 0x0F)); *o2 = Base64EncodeChar(((i1 << 2) & 0x3C)); *o3 = '='; } //---------------------------------------------------------------------------- void Base64::EncodeSingle(unsigned char i0, unsigned char *o0, unsigned char *o1, unsigned char *o2, unsigned char *o3) { *o0 = Base64EncodeChar((i0 >> 2) & 0x3F); *o1 = Base64EncodeChar(((i0 << 4) & 0x30)); *o2 = '='; *o3 = '='; } //---------------------------------------------------------------------------- uint64_t Base64::encode(const unsigned char *input, uint64_t length, unsigned char *output, int32_t mark_end) { const unsigned char *ptr = input; const unsigned char *end = input + length; unsigned char *optr = output; // Encode complete triplet while ((end - ptr) >= 3) { Base64::EncodeTriplet(ptr[0], ptr[1], ptr[2], &optr[0], &optr[1], &optr[2], &optr[3]); ptr += 3; optr += 4; } // Encodes a 2-byte ending into 3 bytes and 1 pad byte and writes. if (end - ptr == 2) { Base64::EncodePair(ptr[0], ptr[1], &optr[0], &optr[1], &optr[2], &optr[3]); optr += 4; } // Encodes a 1-byte ending into 2 bytes and 2 pad bytes else if (end - ptr == 1) { Base64::EncodeSingle(ptr[0], &optr[0], &optr[1], &optr[2], &optr[3]); optr += 4; } // Do we need to mark the end else if (mark_end) { optr[0] = optr[1] = optr[2] = optr[3] = '='; optr += 4; } return optr - output; } //---------------------------------------------------------------------------- static const unsigned char Base64DecodeTable[256] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0x3E,0xFF,0xFF,0xFF,0x3F, 0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B, 0x3C,0x3D,0xFF,0xFF,0xFF,0x00,0xFF,0xFF, 0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06, 0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E, 0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16, 0x17,0x18,0x19,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20, 0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28, 0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30, 0x31,0x32,0x33,0xFF,0xFF,0xFF,0xFF,0xFF, //------------------------------------- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF }; //---------------------------------------------------------------------------- inline static unsigned char Base64DecodeChar(unsigned char c) { return Base64DecodeTable[c]; } //---------------------------------------------------------------------------- int Base64::DecodeTriplet(unsigned char i0, unsigned char i1, unsigned char i2, unsigned char i3, unsigned char *o0, unsigned char *o1, unsigned char *o2) { unsigned char d0, d1, d2, d3; d0 = Base64DecodeChar(i0); d1 = Base64DecodeChar(i1); d2 = Base64DecodeChar(i2); d3 = Base64DecodeChar(i3); // Make sure all characters were valid if (d0 == 0xFF || d1 == 0xFF || d2 == 0xFF || d3 == 0xFF) { return 0; } // Decode the 3 bytes *o0 = ((d0 << 2) & 0xFC) | ((d1 >> 4) & 0x03); *o1 = ((d1 << 4) & 0xF0) | ((d2 >> 2) & 0x0F); *o2 = ((d2 << 6) & 0xC0) | ((d3 >> 0) & 0x3F); // Return the number of bytes actually decoded if (i2 == '=') { return 1; } if (i3 == '=') { return 2; } return 3; } //---------------------------------------------------------------------------- uint64_t Base64::decode(const unsigned char *input, uint64_t length, unsigned char *output, uint64_t max_input_length) { const unsigned char *ptr = input; unsigned char *optr = output; // Decode complete triplet if (max_input_length) { const unsigned char *end = input + max_input_length; while (ptr < end) { int len = Base64::DecodeTriplet(ptr[0], ptr[1], ptr[2], ptr[3], &optr[0], &optr[1], &optr[2]); optr += len; if(len < 3) { return optr - output; } ptr += 4; } } else { unsigned char *oend = output + length; while ((oend - optr) >= 3) { int len = Base64::DecodeTriplet(ptr[0], ptr[1], ptr[2], ptr[3], &optr[0], &optr[1], &optr[2]); optr += len; if(len < 3) { return optr - output; } ptr += 4; } // Decode the last triplet unsigned char temp; if (oend - optr == 2) { int len = Base64::DecodeTriplet(ptr[0], ptr[1], ptr[2], ptr[3], &optr[0], &optr[1], &temp); optr += (len > 2 ? 2 : len); } else if (oend - optr == 1) { unsigned char temp2; int len = Base64::DecodeTriplet(ptr[0], ptr[1], ptr[2], ptr[3], &optr[0], &temp, &temp2); optr += (len > 2 ? 2 : len); } } return optr - output; } connectome-workbench-1.4.2/src/Common/Base64.h000066400000000000000000000120461360521144700210520ustar00rootroot00000000000000#ifndef __BASE64_H__ #define __BASE64_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /*========================================================================= Program: Visualization Toolkit Module: $RCSfile: Base64.h,v $ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ // .NAME Base64 - base64 encode and decode utilities. // .SECTION Description // Base64 implements base64 encoding and decoding. #include #include "CaretObject.h" namespace caret { /** * This is copied directly from VTK's vtkBase64Utilities class. */ class Base64 : public CaretObject { private: Base64(); ~Base64(); public: // Description: // Encode 'length' bytes from the input buffer and store the // encoded stream into the output buffer. Return the length of // the encoded stream. Note that the output buffer must be allocated // by the caller (length * 1.5 should be a safe estimate). // If 'mark_end' is true than an extra set of 4 bytes is added // to the end of the stream if the input is a multiple of 3 bytes. // These bytes are invalid chars and therefore they will stop the decoder // thus enabling the caller to decode a stream without actually knowing // how much data to expect (if the input is not a multiple of 3 bytes then // the extra padding needed to complete the encode 4 bytes will stop the // decoding anyway). static uint64_t encode(const unsigned char *input, uint64_t length, unsigned char *output, int32_t mark_end = 0); // Description: // Decode bytes from the input buffer and store the decoded stream // into the output buffer until 'length' bytes have been decoded. // Return the real length of the decoded stream (which should be equal to // 'length'). Note that the output buffer must be allocated by the caller. // If 'max_input_length' is not null, then it specifies the number of // encoded bytes that should be at most read from the input buffer. In // that case the 'length' parameter is ignored. This enables the caller // to decode a stream without actually knowing how much decoded data to // expect (of course, the buffer must be large enough). static uint64_t decode(const unsigned char *input, uint64_t length, unsigned char *output, uint64_t max_input_length = 0); private: // Description: // Decode 4 bytes into 3 bytes. static int DecodeTriplet(unsigned char i0, unsigned char i1, unsigned char i2, unsigned char i3, unsigned char *o0, unsigned char *o1, unsigned char *o2); // Description: // Encode 3 bytes into 4 bytes static void EncodeTriplet(unsigned char i0, unsigned char i1, unsigned char i2, unsigned char *o0, unsigned char *o1, unsigned char *o2, unsigned char *o3); // Description: // Encode 2 bytes into 4 bytes static void EncodePair(unsigned char i0, unsigned char i1, unsigned char *o0, unsigned char *o1, unsigned char *o2, unsigned char *o3); // Description: // Encode 1 byte into 4 bytes static void EncodeSingle(unsigned char i0, unsigned char *o0, unsigned char *o1, unsigned char *o2, unsigned char *o3); }; } // namespace #endif // __BASE64_H__ connectome-workbench-1.4.2/src/Common/BoundingBox.cxx000066400000000000000000000322101360521144700226120ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "BoundingBox.h" using namespace caret; /** * Constructor setup for update of an update method. * */ BoundingBox::BoundingBox() : CaretObject() { this->initializeMembersBoundingBox(); this->resetForUpdate(); } /** * Create a bounding box from a six-dimensional array containing * min-X, max-X, min-Y, max-Y, min-Z, max-Z. * * @param minMaxXYZ - array described above. * @throws IllegalArgumentException if the array does not contain six * elements or a min value is greater than a max value. * */ BoundingBox::BoundingBox( const float minMaxXYZ[]) : CaretObject() { this->initializeMembersBoundingBox(); for (int i = 0; i < 6; i++) { this->boundingBox[i] = minMaxXYZ[i]; } } /** * Copy constructor. * @param bb * BoundingBox that is copied. */ BoundingBox::BoundingBox(const BoundingBox& bb) : CaretObject(bb) { this->initializeMembersBoundingBox(); this->copyHelper(bb); } /** * Assignment operator. * @param bb * BoundingBox that replace this bounding box. */ BoundingBox& BoundingBox::operator=(const BoundingBox& bb) { if (this != &bb) { CaretObject::operator=(bb); this->copyHelper(bb); } return *this; } /** * Destructor */ BoundingBox::~BoundingBox() { } /** * Initialize data members. */ void BoundingBox::initializeMembersBoundingBox() { } /** * Helps with copy constructor and assignemnt operator. */ void BoundingBox::copyHelper(const BoundingBox& bo) { for (int i = 0; i < 6; i++) { this->boundingBox[i] = bo.boundingBox[i]; } } /** * Reset a new bounding box with the minimum and maximum values * all set to zero. */ void BoundingBox::resetZeros() { this->set(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); } /** * Reset a bounding box with the minimum values initialized to * the minimum float value and the maximum values initialized to the * maximum float value. Use one of the setMax() or setMinY() methods * to update this bounding box. */ void BoundingBox::resetWithMaximumExtent() { const float f = std::numeric_limits::max(); this->set(-f, f, -f, f, -f, f); } /** * Reset a bounding box with the minimum values initialized to * the maximum float value and the maximum values initialized to the * minimum float value. Use the update(float[]) method to update * the bounding box. */ void BoundingBox::resetForUpdate() { const float f = std::numeric_limits::max(); this->set(f, -f, f, -f, f, -f); } /** * Set bounding box using the array of points. * @param points3D * Array of three dimensional points. * @param numPoints * Number of points. */ void BoundingBox::set(const float* points3D, const int64_t numPoints) { this->resetForUpdate(); for (int64_t i = 0; i < numPoints; i++) { this->update(&points3D[i*3]); } } /** * Set a new bounding box. * @param minX Minimum X-coordinate for bounding box. * @param maxX Maximum X-coordinate for bounding box. * @param minY Minimum Y-coordinate for bounding box. * @param maxY Maximum Y-coordinate for bounding box. * @param minZ Minimum Z-coordinate for bounding box. * @param maxZ Maximum Z-coordinate for bounding box. */ void BoundingBox::set( const float minX, const float maxX, const float minY, const float maxY, const float minZ, const float maxZ) { this->boundingBox[0] = minX; this->boundingBox[1] = maxX; this->boundingBox[2] = minY; this->boundingBox[3] = maxY; this->boundingBox[4] = minZ; this->boundingBox[5] = maxZ; } /** * Set a bounding box from a six-dimensional array containing * min-X, max-X, min-Y, max-Y, min-Z, max-Z. * * @param minMaxXYZ - array described above. */ void BoundingBox::set(const float minMaxXYZ[6]) { this->boundingBox[0] = minMaxXYZ[0]; this->boundingBox[1] = minMaxXYZ[1]; this->boundingBox[2] = minMaxXYZ[2]; this->boundingBox[3] = minMaxXYZ[3]; this->boundingBox[4] = minMaxXYZ[4]; this->boundingBox[5] = minMaxXYZ[5]; } /** * Update the bounding box with the XYZ value passed in. The bound box * must have been created with newInstanceForUpdate() or properly * initialized by the user. * * @param xyz - Three dimensional array containing XYZ. * @throws IllegalArgumentException if array does not have three elements. * */ void BoundingBox::update(const float xyz[3]) { if (xyz[0] < this->boundingBox[0]) this->boundingBox[0] = xyz[0]; if (xyz[0] > this->boundingBox[1]) this->boundingBox[1] = xyz[0]; if (xyz[1] < this->boundingBox[2]) this->boundingBox[2] = xyz[1]; if (xyz[1] > this->boundingBox[3]) this->boundingBox[3] = xyz[1]; if (xyz[2] < this->boundingBox[4]) this->boundingBox[4] = xyz[2]; if (xyz[2] > this->boundingBox[5]) this->boundingBox[5] = xyz[2]; } /** * Update the bounding box with the XYZ value passed in. The bound box * must have been created with newInstanceForUpdate() or properly * initialized by the user. * * @param x * X-coordinate. * @param y * Y-coordinate. * @param Z * Z-coordinate. * @throws IllegalArgumentException if array does not have three elements. * */ void BoundingBox::update(const float x, const float y, const float z) { if (x < this->boundingBox[0]) this->boundingBox[0] = x; if (x > this->boundingBox[1]) this->boundingBox[1] = x; if (y < this->boundingBox[2]) this->boundingBox[2] = y; if (y > this->boundingBox[3]) this->boundingBox[3] = y; if (z < this->boundingBox[4]) this->boundingBox[4] = z; if (z > this->boundingBox[5]) this->boundingBox[5] = z; } /** * Get the bounds in an array. * @return Array of six containing minX, maxX, minY, maxY, minZ, maxZ. * */ const float* BoundingBox::getBounds() const { return this->boundingBox; } /** * Get the bounds in an array. * @param Output array of six containing minX, maxX, minY, maxY, minZ, maxZ. * */ void BoundingBox::getBounds(float bounds[6]) const { bounds[0] = this->boundingBox[0]; bounds[1] = this->boundingBox[1]; bounds[2] = this->boundingBox[2]; bounds[3] = this->boundingBox[3]; bounds[4] = this->boundingBox[4]; bounds[5] = this->boundingBox[5]; } /** * Get the X-Coordinate difference. * @return X-Coordinate difference. * */ float BoundingBox::getDifferenceX() const { return (this->boundingBox[1] - this->boundingBox[0]); } /** * Get the Y-Coordinate difference. * @return Y-Coordinate difference. * */ float BoundingBox::getDifferenceY() const { return (this->boundingBox[3] - this->boundingBox[2]); } /** * Get the Z-Coordinate difference. * @return Z-Coordinate difference. * */ float BoundingBox::getDifferenceZ() const { return (this->boundingBox[5] - this->boundingBox[4]); } /** * Get the X minimum value. * @return Its value. * */ float BoundingBox::getMinX() const { return this->boundingBox[0]; } /** * Get the X maximum value. * @return Its value. * */ float BoundingBox::getMaxX() const { return this->boundingBox[1]; } /** * Get the Y minimum value. * @return Its value. * */ float BoundingBox::getMinY() const { return this->boundingBox[2]; } /** * Get the Y maximum value. * @return Its value. * */ float BoundingBox::getMaxY() const { return this->boundingBox[3]; } /** * Get the Z minimum value. * @return Its value. * */ float BoundingBox::getMinZ() const { return this->boundingBox[4]; } /** * Get the Z maximum value. * @return Its value. * */ float BoundingBox::getMaxZ() const { return this->boundingBox[5]; } /** * Get the minimum XYZ of the bounding box. * @return Minimum XYZ of the bounding box. * in an array that the caller MUST delete[]; */ float* BoundingBox::getMinXYZ() const { float* f = new float[3]; f[0] = this->boundingBox[0]; f[1] = this->boundingBox[2]; f[2] = this->boundingBox[4]; return f; } /** * Get the maximum XYZ of the bounding box. * @return Maximum XYZ of the bounding box * in an array that the caller MUST delete[]; */ float* BoundingBox::getMaxXYZ() const { float* f = new float[3]; f[0] = this->boundingBox[1]; f[1] = this->boundingBox[3]; f[2] = this->boundingBox[5]; return f; } /** * Set the minimum X value. * @param value - new value. * */ void BoundingBox::setMinX(const float value) { this->boundingBox[0] = value; } /** * Set the maximum X value. * @param value - new value. * */ void BoundingBox::setMaxX(const float value) { this->boundingBox[1] = value; } /** * Set the minimum Y value. * @param value - new value. * */ void BoundingBox::setMinY(const float value) { this->boundingBox[2] = value; } /** * Set the maximum Y value. * @param value - new value. * */ void BoundingBox::setMaxY(const float value) { this->boundingBox[3] = value; } /** * Set the minimum Z value. * @param value - new value. * */ void BoundingBox::setMinZ(const float value) { this->boundingBox[4] = value; } /** * Set the maximum Z value. * @param value - new value. * */ void BoundingBox::setMaxZ(const float value) { this->boundingBox[5] = value; } /** * @return X-Coordinate at center of the bounding box. */ float BoundingBox::getCenterX() const { const float centerX = (this->boundingBox[0] + this->boundingBox[1]) * 0.5; return centerX; } /** * @return Y-Coordinate at center of the bounding box. */ float BoundingBox::getCenterY() const { const float centerY = (this->boundingBox[2] + this->boundingBox[3]) * 0.5; return centerY; } /** * @return Z-Coordinate at center of the bounding box. */ float BoundingBox::getCenterZ() const { const float centerZ = (this->boundingBox[4] + this->boundingBox[5]) * 0.5; return centerZ; } /** * Get the center of the bounding box. * @param centerOut * Three dimensional array into which the center is loaded. */ void BoundingBox::getCenter(float centerOut[3]) const { centerOut[0] = (this->boundingBox[0] + this->boundingBox[1]) * 0.5; centerOut[1] = (this->boundingBox[2] + this->boundingBox[3]) * 0.5; centerOut[2] = (this->boundingBox[4] + this->boundingBox[5]) * 0.5; } /** * Is the coordinate within the bounding box? * @param xyz - The coordinate. * @return True if coordinate is within the bounding box, else false. * */ bool BoundingBox::isCoordinateWithinBoundingBox(const float xyz[]) const { if (xyz[0] < this->boundingBox[0]) return false; if (xyz[0] > this->boundingBox[1]) return false; if (xyz[1] < this->boundingBox[2]) return false; if (xyz[1] > this->boundingBox[3]) return false; if (xyz[2] < this->boundingBox[4]) return false; if (xyz[2] > this->boundingBox[5]) return false; return true; } /** * Limit the given coordinate to the bounding box. * * @param xyz * The coordinate. */ void BoundingBox::limitCoordinateToBoundingBox(float xyz[3]) const { if (xyz[0] < this->boundingBox[0]) xyz[0] = this->boundingBox[0]; if (xyz[0] > this->boundingBox[1]) xyz[0] = this->boundingBox[1]; if (xyz[1] < this->boundingBox[2]) xyz[1] = this->boundingBox[2]; if (xyz[1] > this->boundingBox[3]) xyz[1] = this->boundingBox[3]; if (xyz[2] < this->boundingBox[4]) xyz[2] = this->boundingBox[4]; if (xyz[2] > this->boundingBox[5]) xyz[2] = this->boundingBox[5]; } /** * Limit the given coordinate to the bounding box. * * @param xyz * The coordinate. */ void BoundingBox::limitCoordinateToBoundingBox(double xyz[3]) const { if (xyz[0] < this->boundingBox[0]) xyz[0] = this->boundingBox[0]; if (xyz[0] > this->boundingBox[1]) xyz[0] = this->boundingBox[1]; if (xyz[1] < this->boundingBox[2]) xyz[1] = this->boundingBox[2]; if (xyz[1] > this->boundingBox[3]) xyz[1] = this->boundingBox[3]; if (xyz[2] < this->boundingBox[4]) xyz[2] = this->boundingBox[4]; if (xyz[2] > this->boundingBox[5]) xyz[2] = this->boundingBox[5]; } /** * Get String representation of bounding box. * @return String containing bounding box. * */ AString BoundingBox::toString() const { std::stringstream str; str << "BoundingBox=[" << this->boundingBox[0] << "," << this->boundingBox[1] << "," << this->boundingBox[2] << "," << this->boundingBox[3] << "," << this->boundingBox[4] << "," << this->boundingBox[5] << "]"; AString s = AString::fromStdString(str.str()); return s; } connectome-workbench-1.4.2/src/Common/BoundingBox.h000066400000000000000000000060061360521144700222430ustar00rootroot00000000000000#ifndef __BOUNDINGBOX_H__ #define __BOUNDINGBOX_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include namespace caret { /** * A bounding box - minimum and maximum X, Y, and Z values for something. */ class BoundingBox : public CaretObject { public: BoundingBox(); BoundingBox(const float minMaxXYZ[]); BoundingBox(const BoundingBox& bb); BoundingBox& operator=(const BoundingBox& co); virtual ~BoundingBox(); public: void resetZeros(); void resetWithMaximumExtent(); void resetForUpdate(); void set(const float* points3D, const int64_t numPoints); void set(const float minX, const float maxX, const float minY, const float maxY, const float minZ, const float maxZ); void set(const float minMaxXYZ[6]); void update(const float xyz[]); void update(const float x, const float y, const float z); const float* getBounds() const; void getBounds(float bounds[6]) const; float getDifferenceX() const; float getDifferenceY() const; float getDifferenceZ() const; float getMinX() const; float getMaxX() const; float getMinY() const; float getMaxY() const; float getMinZ() const; float getMaxZ() const; float* getMinXYZ() const; float* getMaxXYZ() const; void setMinX(const float value); void setMaxX(const float value); void setMinY(const float value); void setMaxY(const float value); void setMinZ(const float value); void setMaxZ(const float value); float getCenterX() const; float getCenterY() const; float getCenterZ() const; void getCenter(float centerOut[3]) const; bool isCoordinateWithinBoundingBox(const float xyz[]) const; void limitCoordinateToBoundingBox(float xyz[3]) const; void limitCoordinateToBoundingBox(double xyz[3]) const; AString toString() const; private: void initializeMembersBoundingBox(); void copyHelper(const BoundingBox& bo); private: float boundingBox[6]; }; } // namespace #endif // __BOUNDINGBOX_H__ connectome-workbench-1.4.2/src/Common/BrainConstants.cxx000066400000000000000000000016521360521144700233320ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BRAIN_CONSTANTS_DECLARE__ #include "BrainConstants.h" #undef __BRAIN_CONSTANTS_DECLARE__ connectome-workbench-1.4.2/src/Common/BrainConstants.h000066400000000000000000000040311360521144700227510ustar00rootroot00000000000000#ifndef __BRAIN_CONSTANTS__H_ #define __BRAIN_CONSTANTS__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include namespace caret { /// Constants for use in the Brain class BrainConstants { public: enum { /// Maximum number of browser windows MAXIMUM_NUMBER_OF_BROWSER_WINDOWS = 10, /// Maximum number of browser tabs MAXIMUM_NUMBER_OF_BROWSER_TABS = 100, /// Maximum number of overlays MAXIMUM_NUMBER_OF_OVERLAYS = 50, /// Minimum number of overlays MINIMUM_NUMBER_OF_OVERLAYS = 3, /// Minimum number of volume surface outlines MINIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES = 4, /// Maximum number of volume surface outlines MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES = 25 }; private: BrainConstants(); ~BrainConstants(); BrainConstants(const BrainConstants&); BrainConstants& operator=(const BrainConstants&); }; #ifdef __BRAIN_CONSTANTS_DECLARE__ #endif // __BRAIN_CONSTANTS_DECLARE__ } // namespace #endif //__BRAIN_CONSTANTS__H_ connectome-workbench-1.4.2/src/Common/ByteOrderEnum.cxx000066400000000000000000000107521360521144700231270ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BYTE_ORDER_DECLARE__ #include "ByteOrderEnum.h" #undef __BYTE_ORDER_DECLARE__ using namespace caret; /** * Constructor. * * @param e * An enumerated value. * @param name * Name of enumberated value. */ ByteOrderEnum::ByteOrderEnum( const Enum e, const AString& name) { this->e = e; this->name = name; } /** * Destructor. */ ByteOrderEnum::~ByteOrderEnum() { } /** * Get the system byte order. * @return * Byte order of the system. */ ByteOrderEnum::Enum ByteOrderEnum::getSystemEndian() { ByteOrderEnum::initialize(); return ByteOrderEnum::systemEndian; } /** * Is the system byte order little endian? * @return * true if system is little endian byte order. */ bool ByteOrderEnum::isSystemLittleEndian() { ByteOrderEnum::initialize(); return (ByteOrderEnum::systemEndian == ENDIAN_LITTLE); } /** * Is the system byte order big endian? * @return * true if system is big endian byte order. */ bool ByteOrderEnum::isSystemBigEndian() { ByteOrderEnum::initialize(); return (ByteOrderEnum::systemEndian == ENDIAN_BIG); } void ByteOrderEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ByteOrderEnum(ENDIAN_BIG,"ENDIAN_BIG")); enumData.push_back(ByteOrderEnum(ENDIAN_LITTLE,"ENDIAN_LITTLE")); uint32_t intVal = 0x00000001; unsigned char* c = (unsigned char*)&intVal; ByteOrderEnum::systemEndian = ByteOrderEnum::ENDIAN_BIG; if (*c == 0x01) systemEndian = ByteOrderEnum::ENDIAN_LITTLE; } /** * Get the enum value for this enumerated item. * @return the value for this enumerated item. */ ByteOrderEnum::Enum ByteOrderEnum::getEnum() const { return this->e; } /** * Get the enum name for this enumerated item. * @return the name for this enumerated item. */ AString ByteOrderEnum::getName() const { return this->name; } /** * Find the data for and enumerated value. * @param e * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ByteOrderEnum* ByteOrderEnum::findData(const Enum e) { initialize(); int64_t num = enumData.size(); for (int64_t i = 0; i < num; i++) { const ByteOrderEnum* d = &enumData[i]; if (d->e == e) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString ByteOrderEnum::toName(Enum e) { initialize(); AString s; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ByteOrderEnum& d = *iter; if (d.e == e) { s = d.name; break; } } return s; } /** * Get an enumerated value corresponding to its name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ByteOrderEnum::Enum ByteOrderEnum::fromName(const AString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = ENDIAN_LITTLE; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ByteOrderEnum& d = *iter; if (d.name == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } connectome-workbench-1.4.2/src/Common/ByteOrderEnum.h000066400000000000000000000040051360521144700225460ustar00rootroot00000000000000#ifndef __BYTE_ORDER_H__ #define __BYTE_ORDER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include namespace caret { /** * Byte order. */ class ByteOrderEnum { public: /** ENDIAN Types */ enum Enum { /** */ ENDIAN_BIG, /** */ ENDIAN_LITTLE }; ~ByteOrderEnum(); static ByteOrderEnum::Enum getSystemEndian(); static bool isSystemLittleEndian(); static bool isSystemBigEndian(); static AString toName(Enum e); static Enum fromName(const AString& s, bool* isValidOut); private: ByteOrderEnum(const Enum e, const AString& name); Enum getEnum() const; AString getName() const; static std::vector enumData; static void initialize(); static bool initializedFlag; static Enum systemEndian; Enum e; AString name; static const ByteOrderEnum* findData(const Enum e); }; #ifdef __BYTE_ORDER_DECLARE__ std::vector ByteOrderEnum::enumData; bool ByteOrderEnum::initializedFlag = false; ByteOrderEnum::Enum ByteOrderEnum::systemEndian; #endif // __BYTE_ORDER_DECLARE__ } // namespace #endif // __BYTE_ORDER_H__ connectome-workbench-1.4.2/src/Common/ByteSwapping.cxx000066400000000000000000000055101360521144700230130ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ByteSwapping.h" using namespace caret; /** * Swap bytes for the specified type. */ void ByteSwapping::swapBytes(int16_t* n, const uint64_t numToSwap) { for (uint64_t i = 0; i < numToSwap; i++) { char* bytes = (char*)&n[i]; char temp = bytes[0]; bytes[0] = bytes[1]; bytes[1] = temp; } } /** * Swap bytes for the specified type. */ void ByteSwapping::swapBytes(uint16_t* n, const uint64_t numToSwap) { swapBytes((int16_t*)n, numToSwap); } /** * Swap bytes for the specified type. */ void ByteSwapping::swapBytes(int32_t* n, const uint64_t numToSwap) { for (uint64_t i = 0; i < numToSwap; i++) { char* bytes = (char*)&n[i]; char temp = bytes[0]; bytes[0] = bytes[3]; bytes[3] = temp; temp = bytes[1]; bytes[1] = bytes[2]; bytes[2] = temp; } } /** * */ void ByteSwapping::swapBytes(uint32_t* n, const uint64_t numToSwap) { swapBytes((int32_t*)n, numToSwap); } /** * Swap bytes for the specified type. */ void ByteSwapping::swapBytes(int64_t* n, const uint64_t numToSwap) { for (uint64_t i = 0; i < numToSwap; i++) { char* bytes = (char*)&n[i]; char temp = bytes[0]; bytes[0] = bytes[7]; bytes[7] = temp; temp = bytes[1]; bytes[1] = bytes[6]; bytes[6] = temp; temp = bytes[2]; bytes[2] = bytes[5]; bytes[5] = temp; temp = bytes[3]; bytes[3] = bytes[4]; bytes[4] = temp; } } /** * Swap bytes for the specified type. */ void ByteSwapping::swapBytes(uint64_t* n, const uint64_t numToSwap) { swapBytes((int64_t*)n, numToSwap); } /** * Swap bytes for the specified type. */ void ByteSwapping::swapBytes(float* n, const uint64_t numToSwap) { swapBytes((int32_t*)n, numToSwap); } /** * Swap bytes for the specified type. */ void ByteSwapping::swapBytes(double* n, const uint64_t numToSwap) { swapBytes((int64_t*)n, numToSwap); } void ByteSwapping::swapBytes(long double* n, const uint64_t numToSwap) { swapArray(n, numToSwap); } connectome-workbench-1.4.2/src/Common/ByteSwapping.h000066400000000000000000000057251360521144700224500ustar00rootroot00000000000000#ifndef __BYTE_SWAPPING_H__ #define __BYTE_SWAPPING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include namespace caret { /** * This class contains static methods for byte swapping data, typically used * when reading binary data files. */ class ByteSwapping { private: ByteSwapping() { } ~ByteSwapping() { } public: static void swapBytes(uint8_t*, const uint64_t) { }//define them for completeness, so templated stuff can just call it without specializing static void swapBytes(int8_t*, const uint64_t) { } static void swapBytes(uint16_t* n, const uint64_t numToSwap); static void swapBytes(int16_t* n, const uint64_t numToSwap); static void swapBytes(int32_t* n, const uint64_t numToSwap); static void swapBytes(uint32_t* n, const uint64_t numToSwap); static void swapBytes(int64_t* n, const uint64_t numToSwap); static void swapBytes(uint64_t* n, const uint64_t numToSwap); static void swapBytes(float* n, const uint64_t numToSwap); static void swapBytes(double* n, const uint64_t numToSwap); static void swapBytes(long double* n, const uint64_t numToSwap); template static void swap(T& toSwap);//templated versions, to replace hand-coding variants template static void swapArray(T* toSwap, const uint64_t& count); inline static bool isBigEndian() { uint16_t test = 1; return (((char*)&test)[0] == 0); } }; template void ByteSwapping::swap(T& toSwap) { if (sizeof(T) == 1) return;//we could specialize 1-byte types, but this should optimize out T temp = toSwap; char* from = (char*)&temp; char* to = (char*)&toSwap; for (int i = 0; i < (int)sizeof(T); ++i) { to[i] = from[sizeof(T) - i - 1]; } } template void ByteSwapping::swapArray(T* toSwap, const uint64_t& count) { if (sizeof(T) == 1) return;//ditto for (uint64_t i = 0; i < count; ++i) { swap(toSwap[i]); } } } #endif // __BYTE_SWAPPING_H__ connectome-workbench-1.4.2/src/Common/CMakeLists.txt000066400000000000000000000212631360521144700224160ustar00rootroot00000000000000 # # Name of Project # PROJECT(Common) # # QT include files # SET(QT_USE_QTXML TRUE) SET(QT_DONT_USE_QTGUI TRUE) SET(QT_USE_QTNETWORK TRUE) if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) include_directories(${Qt5Gui_INCLUDE_DIRS}) include_directories(${Qt5Network_INCLUDE_DIRS}) include_directories(${Qt5Xml_INCLUDE_DIRS}) endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () #message("QT VERSION: " ${QT_VERSION_MAJOR} ${QT_VERSION_MINOR} ${QT_VERSION_PATCH}) # # With AUTOMOC, do not need to specify files # that contain Q_OBJECT macro for Qt to process with 'moc' # (meta-object compiler). # IF(WORKBENCH_USE_CMAKE_AUTOMOC) SET(CMAKE_AUTOMOC ON) ELSE() SET(MOC_INPUT_HEADER_FILES CaretHttpManager.h ) IF(Qt5_FOUND) QT5_WRAP_CPP(MOC_SOURCE_FILES ${MOC_INPUT_HEADER_FILES}) ENDIF() IF (QT4_FOUND) QT4_WRAP_CPP(MOC_SOURCE_FILES ${MOC_INPUT_HEADER_FILES}) ENDIF () ENDIF() # # Create a library # ADD_LIBRARY(Common ApplicationInformation.h ApplicationTypeEnum.h AString.h AStringNaturalComparison.h BackgroundAndForegroundColors.h BackgroundAndForegroundColorsModeEnum.h Base64.h BoundingBox.h BrainConstants.h ByteOrderEnum.h ByteSwapping.h CaretAssert.h CaretAssertion.h CaretBinaryFile.h CaretColorEnum.h CaretCommandLine.h CaretCompact3DLookup.h CaretCompactLookup.h CaretException.h CaretFunctionName.h CaretHeap.h CaretHttpManager.h CaretLogger.h CaretMathExpression.h CaretMutex.h CaretObject.h CaretObjectTracksModification.h CaretOMP.h CaretPointer.h CaretPointLocator.h CaretPreferenceDataValue.h CaretPreferences.h CaretTemporaryFile.h CaretUndoCommand.h CaretUndoStack.h CaretUnitsTypeEnum.h ConnectivityCorrelation.h CubicSpline.h DataCompressZLib.h DataFile.h DataFileContentCopyMoveInterface.h DataFileContentCopyMoveParameters.h DataFileContentInformation.h DataFileException.h DataFileInterface.h DataFileTypeEnum.h DescriptiveStatistics.h DeveloperFlagsEnum.h DisplayGroupAndTabItemInterface.h DisplayGroupEnum.h ElapsedTimer.h Event.h EventAlertUser.h EventBrowserTabDelete.h EventBrowserTabIndicesGetAll.h EventBrowserTabNew.h EventBrowserTabNewClone.h EventCaretPreferencesGet.h EventGetViewportSize.h EventListenerInterface.h EventManager.h EventPaletteGetByName.h EventProgressUpdate.h EventTileTabsConfigurationModification.h EventTypeEnum.h FastStatistics.h FileAdapter.h FileInformation.h FloatMatrix.h Histogram.h HtmlStringBuilder.h ImageCaptureMethodEnum.h JsonHelper.h Logger.h LogHandler.h LogHandlerStandardError.h LogLevelEnum.h LogManager.h LogRecord.h MathFunctionEnum.h MathFunctions.h MatrixFunctions.h ModelTransform.h MultiDimArray.h MultiDimIterator.h NetworkException.h NumericFormatModeEnum.h NumericTextFormatting.h OctTree.h OpenGLDrawingMethodEnum.h PlainTextStringBuilder.h Plane.h ProgramParameters.h ProgramParametersException.h ProgressObject.h ProgressReportingInterface.h ReductionEnum.h ReductionOperation.h SpacerTabIndex.h SpecFileDialogViewFilesTypeEnum.h SpeciesEnum.h StereotaxicSpaceEnum.h StringTableModel.h StructureEnum.h SystemUtilities.h TileTabsConfiguration.h TileTabsConfigurationLayoutTypeEnum.h TileTabsBaseConfiguration.h TileTabsGridLayoutConfiguration.h TileTabsGridModeEnum.h TileTabsGridRowColumnContentTypeEnum.h TileTabsGridRowColumnElement.h TileTabsGridRowColumnStretchTypeEnum.h TracksModificationInterface.h TriStateSelectionStatusEnum.h Vector3D.h VectorOperation.h VolumeSliceViewAllPlanesLayoutEnum.h VoxelIJK.h WorkbenchSpecialVersionEnum.h WuQMacro.h WuQMacroCommand.h WuQMacroCommandParameter.h WuQMacroCommandTypeEnum.h WuQMacroDataValueTypeEnum.h WuQMacroFile.h WuQMacroGroup.h WuQMacroGroupXmlStreamBase.h WuQMacroGroupXmlStreamReader.h WuQMacroGroupXmlStreamWriter.h WuQMacroModeEnum.h WuQMacroMouseEventInfo.h WuQMacroMouseEventTypeEnum.h WuQMacroShortCutKeyEnum.h WuQMacroStandardItemTypeEnum.h WuQMacroWidgetTypeEnum.h YokingGroupEnum.h ${MOC_SOURCE_FILES} ${CMAKE_BINARY_DIR}/Common/ApplicationInformation.cxx ApplicationTypeEnum.cxx AString.cxx AStringNaturalComparison.cxx BackgroundAndForegroundColors.cxx BackgroundAndForegroundColorsModeEnum.cxx Base64.cxx BoundingBox.cxx BrainConstants.cxx ByteOrderEnum.cxx ByteSwapping.cxx CaretAssertion.cxx CaretBinaryFile.cxx CaretColorEnum.cxx CaretCommandLine.cxx CaretException.cxx CaretHttpManager.cxx CaretLogger.cxx CaretMathExpression.cxx CaretObject.cxx CaretObjectTracksModification.cxx CaretPointLocator.cxx CaretPreferenceDataValue.cxx CaretPreferences.cxx CaretTemporaryFile.cxx CaretUndoCommand.cxx CaretUndoStack.cxx CaretUnitsTypeEnum.cxx ConnectivityCorrelation.cxx CubicSpline.cxx DataCompressZLib.cxx DataFile.cxx DataFileContentCopyMoveParameters.cxx DataFileContentInformation.cxx DataFileException.cxx DataFileTypeEnum.cxx DescriptiveStatistics.cxx DeveloperFlagsEnum.cxx DisplayGroupAndTabItemInterface.cxx DisplayGroupEnum.cxx ElapsedTimer.cxx Event.cxx EventAlertUser.cxx EventBrowserTabDelete.cxx EventBrowserTabIndicesGetAll.cxx EventBrowserTabNew.cxx EventBrowserTabNewClone.cxx EventCaretPreferencesGet.cxx EventGetViewportSize.cxx EventListenerInterface.cxx EventManager.cxx EventPaletteGetByName.cxx EventProgressUpdate.cxx EventTileTabsConfigurationModification.cxx EventTypeEnum.cxx FastStatistics.cxx FileAdapter.cxx FileInformation.cxx FloatMatrix.cxx Histogram.cxx HtmlStringBuilder.cxx ImageCaptureMethodEnum.cxx JsonHelper.cxx Logger.cxx LogHandler.cxx LogHandlerStandardError.cxx LogLevelEnum.cxx LogManager.cxx LogRecord.cxx MathFunctionEnum.cxx MathFunctions.cxx ModelTransform.cxx NetworkException.cxx NumericFormatModeEnum.cxx NumericTextFormatting.cxx OpenGLDrawingMethodEnum.cxx PlainTextStringBuilder.cxx Plane.cxx ProgramParameters.cxx ProgramParametersException.cxx ProgressObject.cxx ReductionEnum.cxx ReductionOperation.cxx SpacerTabIndex.cxx SpecFileDialogViewFilesTypeEnum.cxx SpeciesEnum.cxx StereotaxicSpaceEnum.cxx StringTableModel.cxx StructureEnum.cxx SystemUtilities.cxx TileTabsConfiguration.cxx TileTabsConfigurationLayoutTypeEnum.cxx TileTabsBaseConfiguration.cxx TileTabsGridLayoutConfiguration.cxx TileTabsGridModeEnum.cxx TileTabsGridRowColumnContentTypeEnum.cxx TileTabsGridRowColumnElement.cxx TileTabsGridRowColumnStretchTypeEnum.cxx TriStateSelectionStatusEnum.cxx Vector3D.cxx VectorOperation.cxx VolumeSliceViewAllPlanesLayoutEnum.cxx WorkbenchSpecialVersionEnum.cxx WuQMacro.cxx WuQMacroCommand.cxx WuQMacroCommandTypeEnum.cxx WuQMacroCommandParameter.cxx WuQMacroDataValueTypeEnum.cxx WuQMacroFile.cxx WuQMacroGroup.cxx WuQMacroGroupXmlStreamBase.cxx WuQMacroGroupXmlStreamReader.cxx WuQMacroGroupXmlStreamWriter.cxx WuQMacroModeEnum.cxx WuQMacroMouseEventInfo.cxx WuQMacroMouseEventTypeEnum.cxx WuQMacroShortCutKeyEnum.cxx WuQMacroStandardItemTypeEnum.cxx WuQMacroWidgetTypeEnum.cxx YokingGroupEnum.cxx ) ADD_DEFINITIONS(-DCOMPILER_NAME="${CMAKE_CXX_COMPILER}") ADD_DEFINITIONS(-DCOMPILER_VERSION="${CMAKE_CXX_COMPILER_VERSION}") # # Include directories # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Common ) SET (GIT_REPOSITORY "${CMAKE_SOURCE_DIR}/../.git") IF (EXISTS ${GIT_REPOSITORY}) ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_BINARY_DIR}/Common/ApplicationInformation.cxx COMMAND ${CMAKE_COMMAND} -DINFILE="${CMAKE_SOURCE_DIR}/Common/ApplicationInformation.cxx.in" -DOUTFILE="${CMAKE_BINARY_DIR}/Common/ApplicationInformation.cxx" -DVERSION="${WB_VERSION}" -P "${CMAKE_SOURCE_DIR}/CMakeScripts/git_commit_info.cmake.in" WORKING_DIRECTORY ${GIT_REPOSITORY}/.. DEPENDS ApplicationInformation.cxx.in ${CMAKE_SOURCE_DIR}/CMakeScripts/git_commit_info.cmake.in ${CMAKE_SOURCE_DIR}/CMakeLists.txt ${GIT_REPOSITORY}/HEAD ${GIT_REPOSITORY}/index COMMENT "Setting commit info" ) ELSE(EXISTS ${GIT_REPOSITORY}) ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_BINARY_DIR}/Common/ApplicationInformation.cxx COMMAND ${CMAKE_COMMAND} -DINFILE="${CMAKE_SOURCE_DIR}/Common/ApplicationInformation.cxx.in" -DOUTFILE="${CMAKE_BINARY_DIR}/Common/ApplicationInformation.cxx" -DVERSION="${WB_VERSION}" -P "${CMAKE_SOURCE_DIR}/CMakeScripts/git_commit_info.cmake.in" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/.. DEPENDS ApplicationInformation.cxx.in ${CMAKE_SOURCE_DIR}/CMakeScripts/git_commit_info.cmake.in ${CMAKE_SOURCE_DIR}/CMakeLists.txt COMMENT "No repository found, setting commit info to 'unknown'. Reconfigure to look for the repository again." ) ENDIF(EXISTS ${GIT_REPOSITORY}) # # Conditionally link the dot library to use the SIMD-based dot product implementation # IF (WORKBENCH_USE_SIMD AND CPUINFO_COMPILES) TARGET_LINK_LIBRARIES(Common dot ${CARET_QT5_LINK}) ELSE (WORKBENCH_USE_SIMD AND CPUINFO_COMPILES) TARGET_LINK_LIBRARIES(Common ${CARET_QT5_LINK}) ENDIF (WORKBENCH_USE_SIMD AND CPUINFO_COMPILES) connectome-workbench-1.4.2/src/Common/CaretAssert.h000066400000000000000000000154401360521144700222470ustar00rootroot00000000000000#ifndef __CARET_ASSERT_H__ #define __CARET_ASSERT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretAssertion.h" #ifdef NDEBUG #define CaretAssert(e) ((void)0) #define CaretAssertToDoWarning() ((void)0) #define CaretAssertToDoFatal() ((void)0) #define CaretAssertMessage(e, m) ((void)0) #define CaretAssertArrayIndex(a, n, i) ((void) 0) #define CaretAssertVectorIndex(v, i) ((void) 0) #define CaretAssertStdArrayIndex(v, i) ((void) 0) #define CaretUsedInDebugCompileOnly(e) ((void) 0) #define CaretParameterUsedInDebugCompileOnly(e) #else // NDEBUG /** * \def CaretUsedInDebugCompileOnly * * The code within the expression is compiled ONLY * if the compiler's "debug" option is enabled. It * can be used to eliminate "unused" compilation warnings * when debug is off for variables that are only * used in one of the CaretAssert() macros. * * Example: * std::vector v; * CaretUsedInDebugCompileOnly(const int index = 5 * x + y); * CaretAssertVectorIndex(v, index); * * @param e * Expression that is only present if compiled with debug on. */ #define CaretUsedInDebugCompileOnly(e) e /** * \def CaretParameterUsedInDebugCompileOnly * * The code within the expression is compiled ONLY * if the compiler's "debug" option is enabled. It * is used when a function parameter is only used * within a CaretAssert() macro. * * Example: * void function(const float a, * const int CaretParameterUsedInDebugCompileOnly(index)) { * CaretAssertVectorIndex(v, index); * } * * @param e * Expression that is only present if compiled with debug on. */ #define CaretParameterUsedInDebugCompileOnly(e) e /** * \def CaretAssert * * If the expression evaluates to zero, a message is printed * showing the file its line number. A call stack may also * be printed. Lastly, abort() is called. * @param e * Expression that is tested. */ #define CaretAssert(e) \ (((e) == 0) \ ? caret::CaretAssertion::assertFailed(#e, __FILE__, __LINE__) \ : (void)0) /** * \def CaretAssertToDoWarning * * Its purpose is to add "easy to find" reminders in the code * for items that will function without crashing but still * need some additional work. It is expected * CaretAssertToDoWarning will rarely, if ever, be in code that * is pushed to the main repository. * * A message is printed showing the file and its line number. * A call stack may also be printed. Does not call abort(). */ #define CaretAssertToDoWarning() \ caret::CaretAssertion::assertToDoWarning(__FILE__, __LINE__) /** * \def CaretAssertToDoFatal * * Its purpose is to add "easy to find" reminders in the code * for items that are unlikely to be encountered and that * will likely crash or cause significant errors * in the functionality. It is expected * CaretAssertToDoFatal will rarely, if ever, be in code that * is pushed to the main repository. * * A message is printed showing the file and its line number. * A call stack may also be printed. WILL CALL abort() * and terminate execution. */ #define CaretAssertToDoFatal() \ caret::CaretAssertion::assertToDoFatal(__FILE__, __LINE__) /** * \def CaretAssertMessage * * If the expression evaluates to zero, a message is printed * showing the file its line number. The users message is * then printed. A call stack may also * be printed. Lastly, abort() is called. * @param e * Expression that is tested. * @param m * Message that is printed. */ #define CaretAssertMessage(e, m) \ (((e) == 0) \ ? caret::CaretAssertion::assertFailed(#e, AString(m), __FILE__, __LINE__) \ : (void)0) /** * \def CaretAssertArrayIndex * * If the array index is out of bounds, a message is printed * listing the array name, the arrays number of elements, the * invalid array index, the name of the file, and the line * number in the file. A call stack may also * be printed. Lastly, abort() is called. * @param a * The array variable. * @param n * Number of elements in the array. * @param i * The index into the array. */ #define CaretAssertArrayIndex(a, n, i) \ ((((i) < 0) || ((i) >= (n))) \ ? caret::CaretAssertion::assertArrayIndexFailed(#a, n, i, __FILE__, __LINE__) \ : (void)0) /** * \def CaretAssertVectorIndex * * If the vector index is out of bounds, a message is printed * listing the vector name, the vector's number of elements, the * invalid vector index, the name of the file, and the line * number in the file. A call stack may also * be printed. Lastly, abort() is called. * @param v * The vector. * @param i * The index into the vector. */ #define CaretAssertVectorIndex(v, i) \ ((((i) < 0) || ((i) >= (static_cast(v.size())))) \ ? caret::CaretAssertion::assertVectorIndexFailed(#v, (static_cast(v.size())), i, __FILE__, __LINE__) \ : (void)0) /** * \def CaretAssertStdArrayIndex * * If the std array index is out of bounds, a message is printed * listing the std array name, the std array's number of elements, the * invalid std array index, the name of the file, and the line * number in the file. A call stack may also * be printed. Lastly, abort() is called. * @param a * The vector. * @param i * The index into the vector. */ #define CaretAssertStdArrayIndex(a, i) \ ((((i) < 0) || ((i) >= (static_cast(a.size())))) \ ? caret::CaretAssertion::assertStdArrayIndexFailed(#a, (static_cast(a.size())), i, __FILE__, __LINE__) \ : (void)0) #endif // NDEBUG #endif // __CARET_ASSERT_H__ connectome-workbench-1.4.2/src/Common/CaretAssertion.cxx000066400000000000000000000342361360521144700233340ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #define __CARET_ASSERTION_DEFINE__ #include "CaretAssertion.h" #undef __CARET_ASSERTION_DEFINE__ #include "CaretAssert.h" #include "SystemUtilities.h" using namespace caret; /** * Called when an assertion has failed. * The following events will occur: * Prints the expression that failed, the name of * file, and the line number in the file. If * a callstack (backtrace) is available, it will * also be printed. Lastly, abort() is called. * * * @param expression * Expression that failed assertion testing. * @param filename * Name of file in which assertion failed. * @param lineNumber * Line number where assertion failed. */ void CaretAssertion::assertFailed(const char* expression, const char* filename, const int64_t lineNumber) { CaretAssertion::assertFailed(expression, NULL, filename, lineNumber); } /** * Called for a CaretAssertToDoWarning() * * The following events will occur: * Prints the name of * file, and the line number in the file. If * a callstack (backtrace) is available, it will * also be printed. DOES NOT call abort. * * * @param filename * Name of file in which assertion failed. * @param lineNumber * Line number where assertion failed. */ void CaretAssertion::assertToDoWarning(const char* filename, const int64_t lineNumber) { std::cerr \ << "CaretAssertToDo WARNING" << std::endl << "File: " << filename << std::endl << "Line number: " << lineNumber << std::endl << std::endl; const AString s = SystemUtilities::getBackTrace(); if (s.isEmpty() == false) { std::cerr << s << std::endl << std::endl; } } /** * Called for a CaretAssertToDoFatal() * * The following events will occur: * Prints the name of * file, and the line number in the file. If * a callstack (backtrace) is available, it will * also be printed. Does call abort. * * * @param filename * Name of file in which assertion failed. * @param lineNumber * Line number where assertion failed. */ void CaretAssertion::assertToDoFatal(const char* filename, const int64_t lineNumber) { std::cerr \ << "CaretAssertToDo FATAL" << std::endl << "File: " << filename << std::endl << "Line number: " << lineNumber << std::endl << std::endl; const AString s = SystemUtilities::getBackTrace(); if (s.isEmpty() == false) { std::cerr << s << std::endl << std::endl; } if (CaretAssertion::unitTestFlag == false) { std::abort(); } } /** * Called when an assertion has failed. * The following events will occur: * Prints the expression that failed, the name of * file, and the line number in the file. If * a callstack (backtrace) is available, it will * also be printed. Lastly, abort() is called. * * * @param expression * Expression that failed assertion testing. * @param message * Message that is printed. * @param filename * Name of file in which assertion failed. * @param lineNumber * Line number where assertion failed. */ void CaretAssertion::assertFailed(const char* expression, const char* message, const char* filename, const int64_t lineNumber) { std::cerr \ << "Assertion Failure of expression \"" << expression << "\"" << std::endl << "File: " << filename << std::endl << "Line number: " << lineNumber << std::endl << std::endl; if (message != NULL) { std::cerr << "Message: " << message << std::endl << std::endl; } const AString s = SystemUtilities::getBackTrace(); if (s.isEmpty() == false) { std::cerr << s << std::endl << std::endl; } if (CaretAssertion::unitTestFlag == false) { std::abort(); } } /** * Called when an array index assertion has failed. * The following events will occur: * Prints the name of the array, the number of * elements in the array, the invalid array index, * the name of the file where the assertion failed, * the line number in the file. If * a callstack (backtrace) is available, it will * also be printed. Lastly, abort() is called. * * * @param arrayName * Name of the array. * @param arrayNumberOfElements * Number of elements in the array. * @param arrayIndex * Invalid array index. * @param filename * Name of file in which assertion failed. * @param lineNumber * Line number where assertion failed. */ void CaretAssertion::assertArrayIndexFailed(const char* arrayName, const int64_t arrayNumberOfElements, const int64_t arrayIndex, const char* filename, const int64_t lineNumber) { std::cerr \ << "Assertion of Array Bounds failed for array: " << arrayName << std::endl << "File: " << filename << std::endl << "Line number: " << lineNumber << std::endl; std::cerr << "Index: " << arrayIndex << std::endl << "Number of elements in array: " << arrayNumberOfElements << std::endl << std::endl; const AString s = SystemUtilities::getBackTrace(); if (s.isEmpty() == false) { std::cerr << s << std::endl << std::endl; } if (CaretAssertion::unitTestFlag == false) { std::abort(); } } /** * Called when an vector index assertion has failed. * The following events will occur: * Prints the name of the vector, the number of * elements in the vector, the invalid vector index, * the name of the file where the assertion failed, * the line number in the file. If * a callstack (backtrace) is available, it will * also be printed. Lastly, abort() is called. * * * @param vectorName * Name of the vector. * @param vectorNumberOfElements * Number of elements in the vector. * @param vectorIndex * Invalid vector index. * @param filename * Name of file in which assertion failed. * @param lineNumber * Line number where assertion failed. */ void CaretAssertion::assertVectorIndexFailed(const char* vectorName, const int64_t vectorNumberOfElements, const int64_t vectorIndex, const char* filename, const int64_t lineNumber) { std::cerr \ << "Assertion of Vector Bounds failed for vector: " << vectorName << std::endl << "File: " << filename << std::endl << "Line number: " << lineNumber << std::endl; std::cerr << "Index: " << vectorIndex << std::endl << "Number of elements in vector: " << vectorNumberOfElements << std::endl << std::endl; const AString s = SystemUtilities::getBackTrace(); if (s.isEmpty() == false) { std::cerr << s << std::endl << std::endl; } if (CaretAssertion::unitTestFlag == false) { std::abort(); } } /** * Called when a std array index assertion has failed. * The following events will occur: * Prints the name of the array, the number of * elements in the array, the invalid array index, * the name of the file where the assertion failed, * the line number in the file. If * a callstack (backtrace) is available, it will * also be printed. Lastly, abort() is called. * * * @param arrayName * Name of the array. * @param arrayNumberOfElements * Number of elements in the array. * @param arrayIndex * Invalid array index. * @param filename * Name of file in which assertion failed. * @param lineNumber * Line number where assertion failed. */ void CaretAssertion::assertStdArrayIndexFailed(const char* arrayName, const int64_t arrayNumberOfElements, const int64_t arrayIndex, const char* filename, const int64_t lineNumber) { std::cerr \ << "Assertion of Std Array Bounds failed for array: " << arrayName << std::endl << "File: " << filename << std::endl << "Line number: " << lineNumber << std::endl; std::cerr << "Index: " << arrayIndex << std::endl << "Number of elements in array: " << arrayNumberOfElements << std::endl << std::endl; const AString s = SystemUtilities::getBackTrace(); if (s.isEmpty() == false) { std::cerr << s << std::endl << std::endl; } if (CaretAssertion::unitTestFlag == false) { std::abort(); } } /** * Unit testing of assertions. * * @param stream * Stream to which messages are written. * @param isVerbose * Print detailed messages. */ void CaretAssertion::unitTest(std::ostream& stream, const bool isVerbose) { #ifdef NDEBUG if (isVerbose) { stream << "Unit testing of CaretAssertion will not take place since software is not compiled with debug on." << std::endl; } return; #else CaretAssertion::unitTestFlag = true; stream << "CaretAssertion::unitTest is starting" << std::endl; /* * Redirect std::err to the string stream. */ std::ostringstream str; std::streambuf* cerrSave = std::cerr.rdbuf(); std::cerr.rdbuf(str.rdbuf()); int32_t zero = 0; int32_t one = 1; CaretAssert(zero); CaretAssertion::unitTestHelper(stream, "Assert Zero", str.str(), false, isVerbose); str.str(""); CaretAssert(one); CaretAssertion::unitTestHelper(stream, "Assert One", str.str(), true, isVerbose); str.str(""); CaretAssertMessage(zero, "This test should fail along with this message being printed."); CaretAssertion::unitTestHelper(stream, "Assert Message Zero", str.str(), false, isVerbose); str.str(""); CaretAssertMessage(one, "This test SHOULD NOT fail."); CaretAssertion::unitTestHelper(stream, "Assert Message One", str.str(), true, isVerbose); str.str(""); /*int32_t someArray[] = { 1, 2, 3 }; someArray[1] = 2;//*/ CaretAssertArrayIndex(someArray, 3, -1); CaretAssertion::unitTestHelper(stream, "Assert Array Index -1", str.str(), false, isVerbose); str.str(""); CaretAssertArrayIndex(someArray, 3, 3); CaretAssertion::unitTestHelper(stream, "Assert Array Index 3", str.str(), false, isVerbose); str.str(""); CaretAssertArrayIndex(someArray, 3, 5); CaretAssertion::unitTestHelper(stream, "Assert Array Index 5", str.str(), false, isVerbose); str.str(""); CaretAssertArrayIndex(someArray, 3, 2); CaretAssertion::unitTestHelper(stream, "Assert Aray Index 2", str.str(), true, isVerbose); str.str(""); std::vector someVector; someVector.push_back(1); someVector.push_back(2); CaretAssertVectorIndex(someVector, 1); CaretAssertion::unitTestHelper(stream, "Assert Vector Index 1", str.str(), true, isVerbose); str.str(""); CaretAssertVectorIndex(someVector, -1); // Yes, do get signed/unsigned warning CaretAssertion::unitTestHelper(stream, "Assert Vector Index -1", str.str(), false, isVerbose); str.str(""); CaretAssertVectorIndex(someVector, 2); CaretAssertion::unitTestHelper(stream, "Assert Vector Index 2", str.str(), false, isVerbose); str.str(""); /* * Restore std::err */ std::cerr.rdbuf(cerrSave); stream << "CaretAssertion::unitTest has ended" << std::endl << std::endl;; CaretAssertion::unitTestFlag = false; #endif } void CaretAssertion::unitTestHelper(std::ostream& stream, const std::string& testName, const std::string& testOutput, const bool correctTestStatus, const bool isVerbose) { /* * Should test pass? */ if (correctTestStatus) { if (testOutput.empty() == false) { stream << "ERROR: CaretAssertion unit test failed but should have passed. " << std::endl << "Test Name: " << testName << std::endl << "Test Output: " << testOutput << std::endl << std::endl; } else if (isVerbose) { stream << "Test " << testName << " functioned correclty (passed)." << std::endl; } } else { if (testOutput.empty()) { stream << "ERROR: CaretAssertion unit test passed but should have failed." << std::endl << "Test Name: " << testName << std::endl << std::endl; } else if (isVerbose) { stream << "Test " << testName << " functioned correctly (failed)." << std::endl; } } } connectome-workbench-1.4.2/src/Common/CaretAssertion.h000066400000000000000000000067651360521144700227670ustar00rootroot00000000000000#ifndef __CARET_ASSERTION_H__ #define __CARET_ASSERTION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include namespace caret { /** * Contains static methods for assertion processing. * * DO NOT USE THIS CLASS!!!! * USE THE MACROS DEFINED IN CaretAssert.h */ class CaretAssertion { private: CaretAssertion(); CaretAssertion(const CaretAssertion& o); CaretAssertion& operator=(const CaretAssertion&); ~CaretAssertion(); public: static void assertFailed(const char* expression, const char* filename, const int64_t lineNumber); static void assertFailed(const char* expression, const char* message, const char* filename, const int64_t lineNumber); static void assertToDoWarning(const char* filename, const int64_t lineNumber); static void assertToDoFatal(const char* filename, const int64_t lineNumber); static void assertArrayIndexFailed(const char* arrayName, const int64_t arrayNumberOfElements, const int64_t arrayIndex, const char* filename, const int64_t lineNumber); static void assertVectorIndexFailed(const char* vectorName, const int64_t vectorNumberOfElements, const int64_t vectorIndex, const char* filename, const int64_t lineNumber); static void assertStdArrayIndexFailed(const char* arrayName, const int64_t arrayNumberOfElements, const int64_t arrayIndex, const char* filename, const int64_t lineNumber); static void unitTest(std::ostream& stream, const bool isVerbose); private: static void unitTestHelper(std::ostream& stream, const std::string& testOutput, const std::string& testName, const bool correctTestStatus, const bool isVerbose); static bool unitTestFlag; }; #ifdef __CARET_ASSERTION_DEFINE__ bool CaretAssertion::unitTestFlag = false; #endif // __CARET_ASSERTION_DEFINE__ } // namespace #endif // __CARET_ASSERTION_H__ connectome-workbench-1.4.2/src/Common/CaretBinaryFile.cxx000066400000000000000000000316431360521144700234100ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ //try to force large file support from zlib, any other file reading calls #ifndef CARET_OS_MACOSX #define _LARGEFILE64_SOURCE #define _LFS64_LARGEFILE 1 #define _FILE_OFFSET_BITS 64 #endif #include "CaretAssert.h" #include "CaretBinaryFile.h" #include "CaretLogger.h" #include "DataFileException.h" #include #include "zlib.h" #include using namespace caret; using namespace std; //private implementation classes namespace caret { #ifdef ZLIB_VERSION class ZFileImpl : public CaretBinaryFile::ImplInterface { gzFile m_zfile; const static int64_t CHUNK_SIZE; public: ZFileImpl() { m_zfile = NULL; } void open(const QString& filename, const CaretBinaryFile::OpenMode& opmode); void close(); void seek(const int64_t& position); int64_t pos(); int64_t size() { return -1; } void read(void* dataOut, const int64_t& count, int64_t* numRead); void write(const void* dataIn, const int64_t& count); ~ZFileImpl(); }; const int64_t ZFileImpl::CHUNK_SIZE = 1<<26;//64MiB, large enough for good performance, small enough for zlib, must convert to uint32 #endif //ZLIB_VERSION class QFileImpl : public CaretBinaryFile::ImplInterface { QFile m_file; const static int64_t CHUNK_SIZE; public: void open(const QString& filename, const CaretBinaryFile::OpenMode& opmode); void close(); void seek(const int64_t& position); int64_t pos(); int64_t size() { return m_file.size(); } void read(void* dataOut, const int64_t& count, int64_t* numRead); void write(const void* dataIn, const int64_t& count); }; const int64_t QFileImpl::CHUNK_SIZE = 1<<30;//1GiB, QT4 apparently chokes at more than 2GiB via buffer.read using int32 } CaretBinaryFile::ImplInterface::~ImplInterface() { } CaretBinaryFile::CaretBinaryFile(const QString& filename, const OpenMode& fileMode) { open(filename, fileMode); } void CaretBinaryFile::close() { m_curMode = NONE; if (m_impl == NULL) return; m_impl->close(); m_impl.grabNew(NULL); } QString CaretBinaryFile::getFilename() const { if (m_impl == NULL) return "";//don't throw, its not really a problem return m_impl->getFilename(); } bool CaretBinaryFile::getOpenForRead() { return (m_curMode & READ) != 0; } bool CaretBinaryFile::getOpenForWrite() { return (m_curMode & WRITE) != 0; } void CaretBinaryFile::open(const QString& filename, const OpenMode& opmode) { close(); if (opmode == NONE) throw DataFileException("can't open file with NONE mode"); if (filename.endsWith(".gz")) { #ifdef ZLIB_VERSION m_impl.grabNew(new ZFileImpl()); #else //ZLIB_VERSION throw DataFileException("can't open .gz file '" + filename + "', compiled without zlib support"); #endif //ZLIB_VERSION } else { m_impl.grabNew(new QFileImpl()); } m_impl->open(filename, opmode); m_curMode = opmode; } void CaretBinaryFile::read(void* dataOut, const int64_t& count, int64_t* numRead) { CaretAssert(count >= 0);//not sure about allowing 0 if (!getOpenForRead()) throw DataFileException("file is not open for reading"); m_impl->read(dataOut, count, numRead); } void CaretBinaryFile::seek(const int64_t& position) { CaretAssert(position >= 0); if (m_curMode == NONE) throw DataFileException("file is not open, can't seek"); m_impl->seek(position); } int64_t CaretBinaryFile::pos() { if (m_curMode == NONE) throw DataFileException("file is not open, can't report position"); return m_impl->pos(); } int64_t CaretBinaryFile::size() { if (m_curMode == NONE) throw DataFileException("file is not open, can't report size"); return m_impl->size(); } void CaretBinaryFile::write(const void* dataIn, const int64_t& count) { CaretAssert(count >= 0);//not sure about allowing 0 if (!getOpenForWrite()) throw DataFileException("file is not open for writing"); m_impl->write(dataIn, count); } #ifdef ZLIB_VERSION void ZFileImpl::open(const QString& filename, const CaretBinaryFile::OpenMode& opmode) { close();//don't need to, but just because m_fileName = filename; const char* mode = NULL; switch (opmode)//we only support a limited number of combinations, and the string modes are quirky { case CaretBinaryFile::READ: mode = "rb"; break; case CaretBinaryFile::WRITE_TRUNCATE: QFile::remove(filename);//attempt to remove file rather than truncating, to improve behavior with file symlinks mode = "wb";//you have to do "w+b" in order to ask it to not truncate, which zlib doesn't support anyway break; default: throw DataFileException("compressed file only supports READ and WRITE_TRUNCATE modes"); } #if !defined(CARET_OS_MACOSX) && ZLIB_VERNUM > 0x1232 m_zfile = gzopen64(filename.toLocal8Bit().constData(), mode); #else m_zfile = gzopen(filename.toLocal8Bit().constData(), mode); #endif if (m_zfile == NULL) { if (!QFile::exists(filename)) { if (!(opmode & CaretBinaryFile::TRUNCATE)) { throw DataFileException("failed to open compressed file '" + filename + "', file does not exist, or folder permissions prevent seeing it"); } else {//use same logic as QFile impl for now throw DataFileException("failed to open compressed file '" + filename + "', unable to create file"); } }//TODO: check gzerror and errno for more informative error messages throw DataFileException("failed to open compressed file '" + filename + "'"); } } void ZFileImpl::close() { if (m_zfile == NULL) return;//happens when closed and then destroyed, error opening if (gzclose(m_zfile) != 0) throw DataFileException("error closing compressed file '" + m_fileName + "'"); m_zfile = NULL; } void ZFileImpl::read(void* dataOut, const int64_t& count, int64_t* numRead) { if (m_zfile == NULL) throw DataFileException("read called on unopened ZFileImpl");//shouldn't happen int64_t totalRead = 0; int readret = 0;//to preserve the info of the read that broke early while (totalRead < count) { int64_t iterSize = min(count - totalRead, CHUNK_SIZE); readret = gzread(m_zfile, ((char*)dataOut) + totalRead, iterSize); if (readret < 1) break;//0 or -1 indicate eof or error totalRead += readret; } if (numRead == NULL) { if (totalRead != count) { if (readret < 0) throw DataFileException("error while reading compressed file '" + m_fileName + "'"); throw DataFileException("premature end of file in compressed file '" + m_fileName + "'"); } } else { *numRead = totalRead; } } void ZFileImpl::seek(const int64_t& position) { if (m_zfile == NULL) throw DataFileException("seek called on unopened ZFileImpl");//shouldn't happen if (pos() == position) return;//slight hack, since gzseek is slow or nonfunctional for some cases, so don't try it unless necessary #if !defined(CARET_OS_MACOSX) && ZLIB_VERNUM > 0x1232 int64_t ret = gzseek64(m_zfile, position, SEEK_SET); #else int64_t ret = gzseek(m_zfile, position, SEEK_SET); #endif if (ret != position) throw DataFileException("seek failed in compressed file '" + m_fileName + "'"); } int64_t ZFileImpl::pos() { if (m_zfile == NULL) throw DataFileException("pos called on unopened ZFileImpl");//shouldn't happen #if !defined(CARET_OS_MACOSX) && ZLIB_VERNUM > 0x1232 return gztell64(m_zfile); #else return gztell(m_zfile); #endif } void ZFileImpl::write(const void* dataIn, const int64_t& count) { if (m_zfile == NULL) throw DataFileException("read called on unopened ZFileImpl");//shouldn't happen int64_t totalWritten = 0; while (totalWritten < count) { int64_t iterSize = min(count - totalWritten, CHUNK_SIZE); int writeret = gzwrite(m_zfile, ((const char*)dataIn) + totalWritten, iterSize); if (writeret < 1) break;//0 or -1 indicate eof or error totalWritten += writeret; } if (totalWritten != count) throw DataFileException("failed to write to compressed file '" + m_fileName + "'"); } ZFileImpl::~ZFileImpl() { try//throwing from a destructor is a bad idea { close(); } catch (CaretException& e) {//handles DataFileException, should be the only culprit CaretLogSevere(e.whatString()); } catch (exception& e) { CaretLogSevere(e.what()); } catch (...) { CaretLogSevere("caught unknown exception type while closing a compressed file"); } } #endif //ZLIB_VERSION void QFileImpl::open(const QString& filename, const CaretBinaryFile::OpenMode& opmode) { close();//don't need to, but just because m_fileName = filename; QIODevice::OpenMode mode = QIODevice::NotOpen;//means 0 if (opmode & CaretBinaryFile::READ) mode |= QIODevice::ReadOnly; if (opmode & CaretBinaryFile::WRITE) mode |= QIODevice::WriteOnly; if (opmode & CaretBinaryFile::TRUNCATE) mode |= QIODevice::Truncate;//expect QFile to recognize silliness like TRUNCATE by itself m_file.setFileName(filename); if (mode & QIODevice::Truncate) m_file.remove();//attempt to delete the existing file rather than truncating, to improve behavior with file symlinks if (!m_file.open(mode)) { if (!m_file.exists()) { if (!(opmode & CaretBinaryFile::TRUNCATE)) { throw DataFileException("failed to open file '" + filename + "', file does not exist, or folder permissions prevent seeing it"); } else {//m_file.error() doesn't help identify this case, see below throw DataFileException("failed to open file '" + filename + "', unable to create file"); } } switch (m_file.error()) { case QFile::ResourceError://on linux at least, it never gives another code besides the unhelpful OpenError throw DataFileException("failed to open file '" + filename + "', too many open files, try 'ulimit -n 4096'"); default: if (opmode & CaretBinaryFile::WRITE) { throw DataFileException("failed to open file '" + filename + "' for writing"); } else { throw DataFileException("failed to open file '" + filename + "'"); } } } } void QFileImpl::close() { m_file.close(); } void QFileImpl::read(void* dataOut, const int64_t& count, int64_t* numRead) { int64_t total = 0; int64_t readret = -1; while (total < count) { int64_t maxToRead = min(count - total, CHUNK_SIZE); readret = m_file.read(((char*)dataOut) + total, maxToRead);//QFile chokes on large reads also if (readret < 1) break;//0 or -1 means error or eof total += readret; } if (numRead == NULL) { if (total != count) { if (readret < 0) throw DataFileException("error while reading file '" + m_fileName + "'"); throw DataFileException("premature end of file in '" + m_fileName + "'"); } } else { *numRead = total; } } void QFileImpl::seek(const int64_t& position) { if (!m_file.seek(position)) throw DataFileException("seek failed in file '" + m_fileName + "'"); } int64_t QFileImpl::pos() { return m_file.pos(); } void QFileImpl::write(const void* dataIn, const int64_t& count) { int64_t total = 0; int64_t writeret = -1; while (total < count) { int64_t maxToWrite = min(count - total, CHUNK_SIZE); writeret = m_file.write(((const char*)dataIn) + total, maxToWrite);//QFile probably also chokes on large writes if (writeret < 1) break;//0 or -1 means error or eof total += writeret; } const AString msg = ("failed to write file '" + m_fileName + "'. Tried to write " + AString::number(count) + " bytes but actually wrote " + AString::number(total) + " bytes."); if (total != count) throw DataFileException(msg); } connectome-workbench-1.4.2/src/Common/CaretBinaryFile.h000066400000000000000000000061521360521144700230320ustar00rootroot00000000000000#ifndef __CARET_BINARY_FILE_H__ #define __CARET_BINARY_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretPointer.h" #include #include namespace caret { //class to hide difference between compressed and standard binary file reading, and to automate error checking (throws if problem) class CaretBinaryFile { public: enum OpenMode { NONE = 0, READ = 1, WRITE = 2, READ_WRITE = 3,//for convenience TRUNCATE = 4, WRITE_TRUNCATE = 6,//ditto READ_WRITE_TRUNCATE = 7//ditto }; CaretBinaryFile() { } ///constructor that opens file CaretBinaryFile(const QString& filename, const OpenMode& fileMode = READ); void open(const QString& filename, const OpenMode& opmode = READ); void close(); QString getFilename() const;//not a reference because when no file is open, m_impl is NULL bool getOpenForRead(); bool getOpenForWrite(); void seek(const int64_t& position); int64_t pos(); void read(void* dataOut, const int64_t& count, int64_t* numRead = NULL);//throw if numRead is NULL and (error or end of file reached early) void write(const void* dataIn, const int64_t& count);//failure to complete write is always an exception int64_t size();//may return -1 if size cannot be determined efficiently class ImplInterface { protected: QString m_fileName;//filename is tracked here so error messages can be implementation-specific public: virtual void open(const QString& filename, const OpenMode& opmode) = 0; virtual void close() = 0; const QString& getFilename() const { return m_fileName; } virtual void seek(const int64_t& position) = 0; virtual int64_t pos() = 0; virtual int64_t size() = 0; virtual void read(void* dataOut, const int64_t& count, int64_t* numRead) = 0; virtual void write(const void* dataIn, const int64_t& count) = 0; virtual ~ImplInterface(); }; private: CaretPointer m_impl; OpenMode m_curMode;//so implementation classes don't have to track it }; } //namespace caret #endif //__CARET_BINARY_FILE_H__ connectome-workbench-1.4.2/src/Common/CaretColorEnum.cxx000066400000000000000000000440631360521144700232670ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CARET_COLOR_ENUM_DECLARE__ #include "CaretColorEnum.h" #undef __CARET_COLOR_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::CaretColorEnum * \brief Enumerate types for standard colors (HTML 4.01) * * Enumerated types for standard colors */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * @param guiName * User-friendly name for use in user-interface. * @param red * Red color component [0 - 1] * @param green * Green color component [0 - 1] * @param blue * Blue color component [0 - 1] */ CaretColorEnum::CaretColorEnum(const Enum enumValue, const AString& name, const AString& guiName, const float red, const float green, const float blue) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; this->rgb[0]= red; this->rgb[1]= green; this->rgb[2]= blue; } /** * Destructor. */ CaretColorEnum::~CaretColorEnum() { } /** * Initialize the enumerated metadata. */ void CaretColorEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(CaretColorEnum(NONE, "NONE", "None", 0, 0, 0)); enumData.push_back(CaretColorEnum(CUSTOM, "CUSTOM", "Custom", 1, 1, 1)); enumData.push_back(CaretColorEnum(AQUA, "AQUA", "Aqua", 0, 1, 1)); enumData.push_back(CaretColorEnum(BLACK, "BLACK", "Black", 0, 0, 0)); enumData.push_back(CaretColorEnum(BLUE, "BLUE", "Blue", 0, 0, 1)); enumData.push_back(CaretColorEnum(FUCHSIA, "FUCHSIA", "Fuchsia", 1, 0, 1)); enumData.push_back(CaretColorEnum(GRAY, "GRAY", "Gray", 0.50, 0.50, 0.50)); enumData.push_back(CaretColorEnum(GREEN, "GREEN", "Green", 0, 0.5, 0)); enumData.push_back(CaretColorEnum(LIME, "LIME", "Lime", 0, 1, 0)); enumData.push_back(CaretColorEnum(MAROON, "MAROON", "Maroon", 0.5, 0, 0)); enumData.push_back(CaretColorEnum(NAVY, "NAVY", "Navy", 0, 0, 0.5)); enumData.push_back(CaretColorEnum(OLIVE, "OLIVE", "Olive", 0.5, 0.5, 0)); enumData.push_back(CaretColorEnum(PURPLE, "PURPLE", "Purple", 0.5, 0, 0.5)); enumData.push_back(CaretColorEnum(RED, "RED", "Red", 1, 0, 0)); enumData.push_back(CaretColorEnum(SILVER, "SILVER", "Silver", 0.75, 0.75, 0.75)); enumData.push_back(CaretColorEnum(TEAL, "TEAL", "Teal", 0, 0.5, 0.5)); enumData.push_back(CaretColorEnum(WHITE, "WHITE", "White", 1, 1, 1)); enumData.push_back(CaretColorEnum(YELLOW, "YELLOW", "Yellow", 1, 1, 0)); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const CaretColorEnum* CaretColorEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const CaretColorEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString CaretColorEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const CaretColorEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ CaretColorEnum::Enum CaretColorEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = BLACK; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const CaretColorEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type CaretColorEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString CaretColorEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const CaretColorEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get the RGB components (ranging zero to one) of the enumerated type. * @param enumValue * Enumerated value. * @return Pointer to RGB components. */ const float* CaretColorEnum::toRGB(Enum enumValue) { if (initializedFlag == false) initialize(); const CaretColorEnum* enumInstance = findData(enumValue); return enumInstance->rgb; } /** * Get the RGBA components (ranging zero to one) of the enumerated type. * @param enumValue * Enumerated value. * @param rgbaOut * Output with RGB components [0.0, 1.0] and Alpha=1.0 */ void CaretColorEnum::toRGBAFloat(Enum enumValue, float rgbaOut[4]) { if (initializedFlag == false) initialize(); const CaretColorEnum* enumInstance = findData(enumValue); rgbaOut[0] = enumInstance->rgb[0]; rgbaOut[1] = enumInstance->rgb[1]; rgbaOut[2] = enumInstance->rgb[2]; rgbaOut[3] = 1.0; } /** * Get the RGBA components (ranging zero to one) of the enumerated type. * @param enumValue * Enumerated value. * @param rgbaOut * Output with RGB components [0, 255] and Alpha=255 */ void CaretColorEnum::toRGBAByte(Enum enumValue, uint8_t rgbaOut[4]) { float rgbaFloat[4]; toRGBAFloat(enumValue, rgbaFloat); rgbaOut[0] = static_cast(rgbaFloat[0] * 255.0); rgbaOut[1] = static_cast(rgbaFloat[1] * 255.0); rgbaOut[2] = static_cast(rgbaFloat[2] * 255.0); rgbaOut[3] = 255; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ CaretColorEnum::Enum CaretColorEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = BLACK; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const CaretColorEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type CaretColorEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t CaretColorEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const CaretColorEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ CaretColorEnum::Enum CaretColorEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = BLACK; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const CaretColorEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type CaretColorEnum")); } return enumValue; } /** * Get all of the enumerated type values THAT REPRESENT A COLOR. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allColorEnums * A vector that is OUTPUT containing all of the VALID COLOR enumerated values. * No optional enum values are included. */ void CaretColorEnum::getAllEnums(std::vector& allColorEnums) { if (initializedFlag == false) initialize(); getColorAndOptionalEnums(allColorEnums, OPTION_NO_OPTIONS); } /** * Get all of the enumerated type values THAT REPRESENT A COLOR. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allColorEnums * A vector that is OUTPUT containing all of the VALID COLOR enumerated values. * No optional enum values are included. */ void CaretColorEnum::getColorEnums(std::vector& allColorEnums) { if (initializedFlag == false) initialize(); getColorAndOptionalEnums(allColorEnums, OPTION_NO_OPTIONS); } /** * Get all of the enumerated type values THAT REPRESENT A COLOR except BLACK and WHITE. * The values can be used as parameters to toXXX() methods to get associated metadata. * * @param allColorEnums * A vector that is OUTPUT containing all of the VALID COLOR enumerated values. * No optional enum values are included. */ void CaretColorEnum::getColorEnumsNoBlackOrWhite(std::vector& allColorEnums) { if (initializedFlag == false) initialize(); getColorAndOptionalEnums(allColorEnums, OPTION_NO_OPTIONS); std::remove(allColorEnums.begin(), allColorEnums.end(), CaretColorEnum::BLACK); std::remove(allColorEnums.begin(), allColorEnums.end(), CaretColorEnum::WHITE); } /** * Get all of the enumerated type values THAT REPRESENT A COLOR and the specified * optional enums. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the VALID COLOR enumerated values * and also the optional enums. * @param colorOptions * Bitwise OR of the color options. */ void CaretColorEnum::getColorAndOptionalEnums(std::vector& allEnums, const int64_t colorOptions) { if (initializedFlag == false) initialize(); allEnums.clear(); const bool includeCustomColorFlag = (colorOptions & OPTION_INCLUDE_CUSTOM_COLOR); const bool includeNoneColorFlag = (colorOptions & OPTION_INCLUDE_NONE_COLOR); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const CaretColorEnum::Enum colorEnum = iter->enumValue; bool addColorEnumFlag = true; if (colorEnum == CUSTOM) { if ( ! includeCustomColorFlag) { addColorEnumFlag = false; } } else if (colorEnum == NONE) { if ( ! includeNoneColorFlag) { addColorEnumFlag = false; } } if (addColorEnumFlag) { allEnums.push_back(iter->enumValue); } } } ///** // * Get all of the names of the enumerated type values. // * // * @param allNames // * A vector that is OUTPUT containing all of the names of the enumerated values. // * @param isSorted // * If true, the names are sorted in alphabetical order. // */ //void //CaretColorEnum::getAllNames(std::vector& allNames, // const bool isSorted) //{ // if (initializedFlag == false) initialize(); // // allNames.clear(); // // std::vector allEnums; // CaretColorEnum::getColorEnums(allEnums); // for (std::vector::iterator iter = allEnums.begin(); // iter != allEnums.end(); // iter++) { // allNames.push_back(CaretColorEnum::toName(*iter)); // } // // if (isSorted) { // std::sort(allNames.begin(), allNames.end()); // } //} // ///** // * Get all of the GUI names of the enumerated type values. // * // * @param allNames // * A vector that is OUTPUT containing all of the GUI names of the enumerated values. // * @param isSorted // * If true, the names are sorted in alphabetical order. // */ //void //CaretColorEnum::getAllGuiNames(std::vector& allGuiNames, // const bool isSorted) //{ // if (initializedFlag == false) initialize(); // // allGuiNames.clear(); // // std::vector allEnums; // CaretColorEnum::getColorEnums(allEnums); // for (std::vector::iterator iter = allEnums.begin(); // iter != allEnums.end(); // iter++) { // allGuiNames.push_back(CaretColorEnum::toGuiName(*iter)); // } // // if (isSorted) { // std::sort(allGuiNames.begin(), allGuiNames.end()); // } //} connectome-workbench-1.4.2/src/Common/CaretColorEnum.h000066400000000000000000000106161360521144700227110ustar00rootroot00000000000000#ifndef __CARET_COLOR_ENUM__H_ #define __CARET_COLOR_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class CaretColorEnum { public: /** * Enumerated values. */ enum Enum { /** No coloring */ NONE, /** Custom coloring */ CUSTOM, /** AQUA */ AQUA, /** Black */ BLACK, /** Blue */ BLUE, /** Fuchsia */ FUCHSIA, /** Gray */ GRAY, /** Green */ GREEN, /** Lime */ LIME, /** Maroon */ MAROON, /** Navy Blue */ NAVY, /** Olive */ OLIVE, /** Purple */ PURPLE, /** Red */ RED, /** Silver */ SILVER, /** Teal */ TEAL, /** White */ WHITE, /** Yellow */ YELLOW }; enum ColorOptions { OPTION_NO_OPTIONS = 0, OPTION_INCLUDE_CUSTOM_COLOR = 1, OPTION_INCLUDE_NONE_COLOR = 2 }; ~CaretColorEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allColorEnums); static void getColorEnums(std::vector& allColorEnums); static void getColorEnumsNoBlackOrWhite(std::vector& allColorEnums); static void getColorAndOptionalEnums(std::vector& allEnums, const int64_t colorOptions); // static void getAllNames(std::vector& allNames, const bool isSorted); // // static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); static const float* toRGB(Enum enumValue); static void toRGBAFloat(Enum enumValue, float rgbaOut[4]); static void toRGBAByte(Enum enumValue, uint8_t rgbaOut[4]); private: CaretColorEnum(const Enum enumValue, const AString& name, const AString& guiName, const float red, const float green, const float blue); static const CaretColorEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; /** RGB color components */ float rgb[3]; }; #ifdef __CARET_COLOR_ENUM_DECLARE__ std::vector CaretColorEnum::enumData; bool CaretColorEnum::initializedFlag = false; int32_t CaretColorEnum::integerCodeCounter = 0; #endif // __CARET_COLOR_ENUM_DECLARE__ } // namespace #endif //__CARET_COLOR_ENUM__H_ connectome-workbench-1.4.2/src/Common/CaretCommandLine.cxx000066400000000000000000000055541360521144700235540ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretCommandLine.h" #include "ProgramParameters.h" using namespace caret; AString caret::caret_global_commandLine; namespace {//private namespace void add_parameter(const AString& param) { if (caret_global_commandLine.size() != 0) { caret_global_commandLine += " "; } if (param.indexOfAnyChar(" $();&<>\"`*?{|") != -1)//check for things that the shell is likely to treat specially EXCEPT for ' itself - assume bash for now, but ignore some more specialized cases {//NOTE: not checking for \ or replacing with \\, because it is rare except in windows native paths where it will wreak havok to double it if (param.indexOf('\'') != -1)//oh joy, ' also {//we COULD check if it is safe to use "", but "" and non-CDATA xml text don't look nice (we avoid CDATA in CIFTI because the matlab GIFTI toolbox at least used to choke on it after conversion) AString replaced = param; replaced.replace('\'', "'\\''");//that is '\'' caret_global_commandLine += "'" + replaced + "'"; } else { caret_global_commandLine += "'" + param + "'"; } } else { if (param.indexOf('\'') != -1)//has ' but no other problems, doesn't need quoting { AString replaced = param; replaced.replace('\'', "\\'");//that is \' caret_global_commandLine += replaced; } else { caret_global_commandLine += param; } } } } void caret::caret_global_commandLine_init(const ProgramParameters& params) { int32_t numParams = params.getNumberOfParameters(); caret_global_commandLine = ""; add_parameter(params.getProgramName()); for (int32_t i = 0; i < numParams; ++i) { add_parameter(params.getParameter(i)); } } void caret::caret_global_commandLine_init(const int& argc, const char *const * argv) { ProgramParameters params(argc, argv); caret_global_commandLine_init(params); } connectome-workbench-1.4.2/src/Common/CaretCommandLine.h000066400000000000000000000023251360521144700231720ustar00rootroot00000000000000#ifndef __CARET_COMMAND_LINE_H__ #define __CARET_COMMAND_LINE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AString.h" namespace caret { class ProgramParameters; extern AString caret_global_commandLine; void caret_global_commandLine_init(const ProgramParameters& params); void caret_global_commandLine_init(const int& argc, const char *const * argv); } #endif //__CARET_COMMAND_LINE_H__ connectome-workbench-1.4.2/src/Common/CaretCompact3DLookup.h000066400000000000000000000103751360521144700237570ustar00rootroot00000000000000#ifndef __CARET_COMPACT_3D_LOOKUP_H__ #define __CARET_COMPACT_3D_LOOKUP_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretCompactLookup.h" namespace caret { template class CaretCompact3DLookup { CaretCompactLookup > > m_lookup;//the whole point of this class is to deal with this ugliness public: ///creates the element if it didn't exist, and returns a reference to it T& at(const int64_t& index1, const int64_t& index2, const int64_t& index3); ///creates the element if it didn't exist, and returns a reference to it T& at(const int64_t index[3]) { return at(index[0], index[1], index[2]); } ///add or overwrite an element in the lookup void insert(const int64_t& index1, const int64_t& index2, const int64_t& index3, const T& value) { at(index1, index2, index3) = value; } ///add or overwrite an element in the lookup void insert(const int64_t index[3], const T& value) { at(index) = value; } ///returns a pointer to the desired element, or NULL if no such element is found T* find(const int64_t& index1, const int64_t& index2, const int64_t& index3); ///returns a pointer to the desired element, or NULL if no such element is found T* find(const int64_t index[3]) { return find(index[0], index[1], index[2]); } ///returns a pointer to the desired element, or NULL if no such element is found const T* find(const int64_t& index1, const int64_t& index2, const int64_t& index3) const; ///returns a pointer to the desired element, or NULL if no such element is found const T* find(const int64_t index[3]) const { return find(index[0], index[1], index[2]); } ///empties the lookup void clear(); }; template T& CaretCompact3DLookup::at(const int64_t& index1, const int64_t& index2, const int64_t& index3) { return m_lookup[index3][index2][index1];//a lot of complexity is hidden in those operator[]s } template T* CaretCompact3DLookup::find(const int64_t& index1, const int64_t& index2, const int64_t& index3) { typename CaretCompactLookup > >::iterator iter1 = m_lookup.find(index3);//oh the humanity if (iter1 == m_lookup.end()) return NULL; typename CaretCompactLookup >::iterator iter2 = iter1->find(index2); if (iter2 == iter1->end()) return NULL; typename CaretCompactLookup::iterator iter3 = iter2->find(index1); if (iter3 == iter2->end()) return NULL; return &(*iter3); } template const T* CaretCompact3DLookup::find(const int64_t& index1, const int64_t& index2, const int64_t& index3) const { typename CaretCompactLookup > >::const_iterator iter1 = m_lookup.find(index3);//oh the humanity if (iter1 == m_lookup.end()) return NULL; typename CaretCompactLookup >::const_iterator iter2 = iter1->find(index2); if (iter2 == iter1->end()) return NULL; typename CaretCompactLookup::const_iterator iter3 = iter2->find(index1); if (iter3 == iter2->end()) return NULL; return &(*iter3); } template void CaretCompact3DLookup::clear() { m_lookup.clear(); } } #endif //__CARET_COMPACT_3D_LOOKUP_H__ connectome-workbench-1.4.2/src/Common/CaretCompactLookup.h000066400000000000000000000225641360521144700235730ustar00rootroot00000000000000#ifndef __CARET_COMPACT_LOOKUP_H__ #define __CARET_COMPACT_LOOKUP_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "stdint.h" #include namespace caret { template class CaretCompactLookup { struct Chunk { int64_t start; std::vector elements; }; std::vector m_chunks; public: class iterator { CaretCompactLookup& m_container; std::size_t m_chunk; int64_t m_elem; iterator(CaretCompactLookup& container, std::size_t chunk, int64_t elem) : m_container(container), m_chunk(chunk), m_elem(elem) { } public: bool operator==(const iterator& rhs) const { if (&m_container != &(rhs.m_container)) return false; if (m_chunk != rhs.m_chunk) return false; if (m_elem != rhs.m_elem) return false; return true; } T& operator*() { CaretAssert(m_chunk < m_container.m_chunks.size()); CaretAssert(m_elem >= 0 && m_elem < (int64_t)m_container.m_chunks[m_chunk].elements.size()); return m_container.m_chunks[m_chunk].elements[m_elem]; } T* operator->() { CaretAssert(m_chunk < m_container.m_chunks.size()); CaretAssert(m_elem >= 0 && m_elem < (int64_t)m_container.m_chunks[m_chunk].elements.size()); return &(m_container.m_chunks[m_chunk].elements[m_elem]); } friend class CaretCompactLookup; }; class const_iterator { const CaretCompactLookup& m_container; std::size_t m_chunk; int64_t m_elem; const_iterator(const CaretCompactLookup& container, std::size_t chunk, std::size_t elem) : m_container(container), m_chunk(chunk), m_elem(elem) { } public: bool operator==(const const_iterator& rhs) const { if (&m_container != &(rhs.m_container)) return false; if (m_chunk != rhs.m_chunk) return false; if (m_elem != rhs.m_elem) return false; return true; } const T& operator*() { CaretAssert(m_chunk < m_container.m_chunks.size()); CaretAssert(m_elem >= 0 && m_elem < (int64_t)m_container.m_chunks[m_chunk].elements.size()); return m_container.m_chunks[m_chunk].elements[m_elem]; } const T* operator->() { CaretAssert(m_chunk < m_container.m_chunks.size()); CaretAssert(m_elem >= 0 && m_elem < (int64_t)m_container.m_chunks[m_chunk].elements.size()); return &(m_container.m_chunks[m_chunk].elements[m_elem]); } friend class CaretCompactLookup; }; ///creates the element if it didn't exist, and returns a reference to it T& operator[](const int64_t& index); ///returns an iterator pointing to the desired element, or one equal to end() if no such element is found iterator find(const int64_t& index); ///returns a const_iterator pointing to the desired element, or one equal to end() if no such element is found const_iterator find(const int64_t& index) const; iterator end(); const_iterator end() const; ///empties the lookup void clear(); }; template T& CaretCompactLookup::operator[](const int64_t& index) { std::size_t numChunks = m_chunks.size(); std::size_t low = 0, high = numChunks, guess;//NOTE: low is 0 because size_t is unsigned, really means -1 bool attach_low = false, attach_high = false; while (low < high)//bisection search for the chunk with the largest start value not greater than { guess = (low + high - 1) / 2;//which is why we subtract 1 here CaretAssert(guess < m_chunks.size()); if (m_chunks[guess].start > index) { high = guess; } else { low = guess + 1; } }//NOTE: low == high after loop ends if (high > 0 && m_chunks[high - 1].start + (int64_t)(m_chunks[high - 1].elements.size()) > index)//element exists, return it { CaretAssertVectorIndex(m_chunks[high -1].elements, index - m_chunks[high - 1].start); return m_chunks[high - 1].elements[index - m_chunks[high - 1].start]; } if (high > 0 && m_chunks[high - 1].start + (int64_t)(m_chunks[high - 1].elements.size()) == index) attach_low = true;//index is 1 beyond the range if (high < numChunks && m_chunks[high].start == index + 1) attach_high = true;//index is 1 before the next range if (attach_low) { std::vector& lowvec = m_chunks[high - 1].elements; std::size_t retIndex = lowvec.size(); lowvec.push_back(T()); if (attach_high) { std::vector& highvec = m_chunks[high].elements; lowvec.insert(lowvec.end(), highvec.begin(), highvec.end()); m_chunks.erase(m_chunks.begin() + high); } return lowvec[retIndex]; } else { if (attach_high) { std::vector& highvec = m_chunks[high].elements; highvec.insert(highvec.begin(), T());//add a new element to the start of the vector (yes, this could be slow) m_chunks[high].start = index;//and change the start value of the chunk return highvec[0]; } else { m_chunks.insert(m_chunks.begin() + high, Chunk()); m_chunks[high].start = index; m_chunks[high].elements.push_back(T()); return m_chunks[high].elements[0]; } } } template typename CaretCompactLookup::iterator CaretCompactLookup::find(const int64_t& index) { std::size_t numChunks = m_chunks.size(); std::size_t low = 0, high = numChunks, guess;//NOTE: low is 0 because size_t is unsigned, really means -1 while (low < high)//bisection search for the chunk with the largest start value not greater than { guess = (low + high - 1) / 2;//which is why we subtract 1 here CaretAssert(guess < m_chunks.size()); if (m_chunks[guess].start > index) { high = guess; } else { low = guess + 1; } }//NOTE: low == high after loop ends if (high > 0 && m_chunks[high - 1].start + (int64_t)(m_chunks[high - 1].elements.size()) > index)//element exists, return it { std::size_t outIndex = index - m_chunks[high - 1].start; CaretAssert(outIndex < m_chunks[high - 1].elements.size()); return iterator(*this, high - 1, outIndex); } return end(); } template typename CaretCompactLookup::const_iterator CaretCompactLookup::find(const int64_t& index) const { std::size_t numChunks = m_chunks.size(); std::size_t low = 0, high = numChunks, guess;//NOTE: low is 0 because size_t is unsigned, really means -1 while (low < high)//bisection search for the chunk with the largest start value not greater than { guess = (low + high - 1) / 2;//which is why we subtract 1 here CaretAssert(guess < m_chunks.size()); if (m_chunks[guess].start > index) { high = guess; } else { low = guess + 1; } }//NOTE: low == high after loop ends if (high > 0 && m_chunks[high - 1].start + (int64_t)(m_chunks[high - 1].elements.size()) > index)//element exists, return it { std::size_t outIndex = index - m_chunks[high - 1].start; CaretAssert(outIndex < m_chunks[high - 1].elements.size()); return const_iterator(*this, high - 1, outIndex); } return end(); } template typename CaretCompactLookup::iterator CaretCompactLookup::end() { return iterator(*this, 0, -1); } template typename CaretCompactLookup::const_iterator CaretCompactLookup::end() const { return const_iterator(*this, 0, -1); } template void CaretCompactLookup::clear() { m_chunks.clear(); } } #endif //__CARET_COMPACT_LOOKUP_H__ connectome-workbench-1.4.2/src/Common/CaretException.cxx000066400000000000000000000053231360521144700233160ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretException.h" #include "SystemUtilities.h" #include using namespace caret; /** * Constructor. * */ CaretException::CaretException() : std::runtime_error("") { this->initializeMembersCaretException(); } /** * Constructor. * * @param s Description of the exception. * */ CaretException::CaretException( const AString& s) : std::runtime_error(s.toStdString()) { this->initializeMembersCaretException(); this->exceptionDescription = s; } /** * Copy Constructor. * @param e * Exception that is copied. */ CaretException::CaretException(const CaretException& e) : std::runtime_error(e) { this->exceptionDescription = e.exceptionDescription; this->callStack = e.callStack; } /** * Assignment operator. * @param e * Exception that is copied. * @return * Copy of the exception. */ CaretException& CaretException::operator=(const CaretException& e) { if (this != &e) { std::runtime_error::operator=(e); this->exceptionDescription = e.exceptionDescription; this->callStack = e.callStack; } return *this; } /** * Destructor */ CaretException::~CaretException() throw() { } void CaretException::initializeMembersCaretException() { this->exceptionDescription = ""; this->callStack = SystemUtilities::getBackTrace(); } /** * Get the current call stack. * @return String containing the call stack. */; AString CaretException::getCallStack() const { return callStack; } /** * Get a message describing the exception. * @return A message describing the exception. */ AString CaretException::whatString() const throw() { return this->exceptionDescription; } /** * Allow subclasses to override the exception description. * * @param s Description of the exception. */ void CaretException::setExceptionDescription(const AString& s) { this->exceptionDescription = s; } connectome-workbench-1.4.2/src/Common/CaretException.h000066400000000000000000000032441360521144700227430ustar00rootroot00000000000000#ifndef __CARETEXCEPTION_H__ #define __CARETEXCEPTION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include namespace caret { /** * An exception thrown during Caret processing. */ class CaretException : public std::runtime_error { public: CaretException(); CaretException(const AString& s); CaretException(const CaretException& e); CaretException& operator=(const CaretException& e); virtual ~CaretException() throw(); virtual AString whatString() const throw(); AString getCallStack() const; protected: void setExceptionDescription(const AString& s); private: /// Description of the exception AString exceptionDescription; /// the call stack AString callStack; void initializeMembersCaretException(); }; } // namespace #endif // __CARETEXCEPTION_H__ connectome-workbench-1.4.2/src/Common/CaretFunctionName.h000066400000000000000000000023561360521144700233760ustar00rootroot00000000000000#ifndef __CARET_FUNCTION_NAME_H__ #define __CARET_FUNCTION_NAME_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #ifdef CARET_OS_WINDOWS_MSVC /** * \def __CARET_FUNCTION_NAME__ * * A macro that contains the name of the current * function. This macro's definition is platform * dependent (Visual C++ vs. GCC). */ #define __CARET_FUNCTION_NAME__ __FUNCSIG__ #else #define __CARET_FUNCTION_NAME__ __PRETTY_FUNCTION__ #endif #endif //__CARET_FUNCTION_NAME_H__ connectome-workbench-1.4.2/src/Common/CaretHeap.h000066400000000000000000000370421360521144700216650ustar00rootroot00000000000000#ifndef __CARET_HEAP__ #define __CARET_HEAP__ #include "CaretAssertion.h" /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "stdint.h" #include "CaretAssert.h" namespace caret { ///heap base used to be able to modify existing data's keys, and to automatically indirect the heap data through indexing, so that all heap reordering involves only integer assignments template class CaretHeapBase { struct DataStruct { K m_key; T m_data; int64_t m_index; DataStruct(const K& key, const T& data) : m_key(key), m_data(data) { } }; std::vector m_datastore; std::vector m_heap; std::vector m_unusedStore; ///primitive used to make the code a bit nicer, modifies the heap and the field in the data to point to it ///DOES NOT GUARANTEE CONSISTENT HEAP STATE void put(const int64_t& dataIndex, const int64_t& heapLoc); //uses curiously recurring template pattern to use child class's comparison without virtual - can't make a typedef missing template parameters, so this is the most convenient way for usage inline bool compare(const K& left, const K& right) { return C::mycompare(left, right); } void heapify_up(const int64_t& start); void heapify_down(const int64_t& start); protected: CaretHeapBase() { }//this is not a usable class by itself - use CaretMinHeap or CaretMaxHeap public: ///this heap is special, save the return value of push() and you can modify the key/data later (constant time for data, log(heapsize) time to change key) int64_t push(const T& data, const K& key); ///look at the data of the top element T& top(K* key = NULL); ///remove and return the top element T pop(K* key = NULL); ///modify the key, and reheapify void changekey(const int64_t& dataIndex, K key); ///delete the element with the key, and reheapify T remove(const int64_t& dataIndex, K* key = NULL); ///modify or just access the data - could be an operator[] but that would be kind of confusing T& data(const int64_t& dataIndex); ///preallocate for efficiency, if you know about how big it will be void reserve(int64_t expectedSize); ///retrieve the key value const K& getKey(const int64_t& dataIndex) const; ///check for empty bool isEmpty() const; ///get number of elements int64_t size() const; ///reset the heap void clear(); }; ///simpler heap base for more basic (and not indirected) use, give it pointers if your data struct is nontrivial template class CaretSimpleHeapBase { struct DataStruct { K m_key; T m_data; DataStruct(const K& key, const T& data) : m_key(key), m_data(data) { } }; std::vector m_heap; //uses curiously recurring template pattern to use child class's comparison without virtual inline bool compare(const K& left, const K& right) { return C::mycompare(left, right); } void heapify_up(const int64_t& start); void heapify_down(const int64_t& start); protected: CaretSimpleHeapBase() { }//this is not a usable class by itself - use CaretMinHeap or CaretMaxHeap public: void push(const T& data, const K& key); ///look at the data of the top element T& top(K* key = NULL); ///remove and return the top element T pop(K* key = NULL); ///preallocate for efficiency, if you know about how big it will be void reserve(int64_t expectedSize); ///check for empty bool isEmpty() const; ///get number of elements int64_t size() const; ///reset the heap void clear(); }; ///minheap with advanced features template class CaretMinHeap : public CaretHeapBase > { public: static inline bool mycompare(const K& left, const K& right) { return left < right; } }; ///maxheap with advanced features template class CaretMaxHeap : public CaretHeapBase > { public: static inline bool mycompare(const K& left, const K& right) { return right < left; } }; ///basic minheap template class CaretSimpleMinHeap : public CaretSimpleHeapBase > { public: static inline bool mycompare(const K& left, const K& right) { return left < right; } }; ///basic maxheap template class CaretSimpleMaxHeap : public CaretSimpleHeapBase > { public: static inline bool mycompare(const K& left, const K& right) { return right < left; } }; template void CaretHeapBase::changekey(const int64_t& dataIndex, K key) { CaretAssertVectorIndex(m_datastore, dataIndex); CaretAssert(m_datastore[dataIndex].m_index != -1); K oldkey = m_datastore[dataIndex].m_key; m_datastore[dataIndex].m_key = key; if (compare(oldkey, key)) { heapify_down(m_datastore[dataIndex].m_index); } else { heapify_up(m_datastore[dataIndex].m_index); } } template T CaretHeapBase::remove(const int64_t& dataIndex, K* key) { CaretAssertVectorIndex(m_datastore, dataIndex); CaretAssert(m_datastore[dataIndex].m_index != -1); int64_t myHeapIndex = m_datastore[dataIndex].m_index; T ret = m_datastore[dataIndex].m_data; if (key != NULL) *key = m_datastore[dataIndex].m_key; if (myHeapIndex < (int64_t)(m_heap.size() - 1))//don't try to do stuff other than removing it if it is the last element { K removedKey = m_datastore[dataIndex].m_key; K newKey = m_datastore[m_heap.back()].m_key; put(m_heap.back(), myHeapIndex);//replace the removed element's position with the last m_heap.pop_back(); if (compare(removedKey, newKey))//and heapify it { heapify_down(myHeapIndex); } else { heapify_up(myHeapIndex); } } else { m_heap.pop_back(); } m_unusedStore.push_back(dataIndex);//mark the removed data location as unused m_datastore[dataIndex].m_index = -1; return ret; } template T& CaretHeapBase::data(const int64_t& dataIndex) { CaretAssertVectorIndex(m_datastore, dataIndex); CaretAssert(m_datastore[dataIndex].m_index != -1); return m_datastore[dataIndex].m_data; } template void CaretHeapBase::heapify_down(const int64_t& start) { CaretAssertVectorIndex(m_heap, start); int64_t cur = start, nextInd = (start << 1) + 1, mySize = (int64_t)m_heap.size(); int64_t temp = m_heap[start];//save current data index, don't swap it around until we stop while (nextInd < mySize) { if (nextInd + 1 < mySize && compare(m_datastore[m_heap[nextInd + 1]].m_key, m_datastore[m_heap[nextInd]].m_key)) { ++nextInd; } if (compare(m_datastore[m_heap[nextInd]].m_key, m_datastore[temp].m_key)) { put(m_heap[nextInd], cur);//move the best child up cur = nextInd;//advance current nextInd = (cur << 1) + 1; } else { break; } } if (cur != start) put(temp, cur);//stopped, now we put it and finish, but only if we moved something } template void CaretHeapBase::heapify_up(const int64_t& start) { CaretAssertVectorIndex(m_heap, start); int64_t cur = start, nextInd = (start - 1) >> 1; int64_t temp = m_heap[start]; while (cur > 0) { if (compare(m_datastore[temp].m_key, m_datastore[m_heap[nextInd]].m_key)) { put(m_heap[nextInd], cur); cur = nextInd; nextInd = (cur - 1) >> 1; } else { break; } } if (cur != start) put(temp, cur); } template T CaretHeapBase::pop(K* key) { CaretAssert(m_heap.size() > 0); T ret = m_datastore[m_heap[0]].m_data; if (key != NULL) *key = m_datastore[m_heap[0]].m_key; m_unusedStore.push_back(m_heap[0]);//should this try garbage collection? currently, the T data will remain until overwritten...would require another level of indirection to fix m_datastore[m_heap[0]].m_index = -1; if (m_heap.size() > 1) { put(m_heap[m_heap.size() - 1], 0); m_heap.pop_back(); heapify_down(0); } else { m_heap.pop_back(); } return ret; } template int64_t CaretHeapBase::push(const T& data, const K& key) { int64_t dataLoc; if (m_unusedStore.size() > 0) { dataLoc = m_unusedStore[m_unusedStore.size() - 1]; m_datastore[dataLoc].m_key = key; m_datastore[dataLoc].m_data = data; m_unusedStore.pop_back(); } else { dataLoc = m_datastore.size(); m_datastore.push_back(DataStruct(key, data)); } m_datastore[dataLoc].m_index = (int64_t)m_heap.size(); m_heap.push_back(dataLoc); heapify_up(m_heap.size() - 1); return dataLoc; } template void CaretHeapBase::put(const int64_t& dataIndex, const int64_t& heapLoc) { CaretAssertVectorIndex(m_datastore, dataIndex); CaretAssertVectorIndex(m_heap, heapLoc); m_datastore[dataIndex].m_index = heapLoc; m_heap[heapLoc] = dataIndex; } template void CaretHeapBase::reserve(int64_t expectedSize) { if (expectedSize <= 0) return; m_heap.reserve(expectedSize); m_datastore.reserve(expectedSize); m_unusedStore.reserve(expectedSize);//expect them to eventually pop() everything } template T& CaretHeapBase::top(K* key) { CaretAssert(m_heap.size() > 0); if (key != NULL) *key = m_datastore[m_heap[0]].m_key; return m_datastore[m_heap[0]].m_data; } template bool CaretHeapBase::isEmpty() const { return m_heap.size() == 0; } template int64_t CaretHeapBase::size() const { return (int64_t)m_heap.size(); } template void CaretHeapBase::clear() { m_heap.clear(); m_datastore.clear(); m_unusedStore.clear(); } template void CaretSimpleHeapBase::heapify_down(const int64_t& start) { CaretAssertVectorIndex(m_heap, start); int64_t cur = start, nextInd = (start << 1) + 1, mySize = (int64_t)m_heap.size(); DataStruct temp = m_heap[start];//save current data, don't swap it around until we stop while (nextInd < mySize) { if (nextInd + 1 < mySize && compare(m_heap[nextInd + 1].m_key, m_heap[nextInd].m_key)) { ++nextInd; } if (compare(m_heap[nextInd].m_key, temp.m_key)) { m_heap[cur] = m_heap[nextInd];//move the best child up cur = nextInd;//advance current nextInd = (cur << 1) + 1; } else { break; } } if (cur != start) m_heap[cur] = temp;//stopped, now we put it and finish, but only if we moved something } template void CaretSimpleHeapBase::heapify_up(const int64_t& start) { CaretAssertVectorIndex(m_heap, start); int64_t cur = start, nextInd = (start - 1) >> 1; DataStruct temp = m_heap[start]; while (cur > 0) { if (compare(temp.m_key, m_heap[nextInd].m_key)) { m_heap[cur] = m_heap[nextInd]; cur = nextInd; nextInd = (cur - 1) >> 1; } else { break; } } if (cur != start) m_heap[cur] = temp; } template T CaretSimpleHeapBase::pop(K* key) { CaretAssert(m_heap.size() > 0); T ret = m_heap[0].m_data; if (key != NULL) *key = m_heap[0].m_key; if (m_heap.size() > 1) { m_heap[0] = m_heap[m_heap.size() - 1]; m_heap.pop_back(); heapify_down(0); } else { m_heap.pop_back(); } return ret; } template void CaretSimpleHeapBase::push(const T& data, const K& key) { m_heap.push_back(DataStruct(key, data)); heapify_up(m_heap.size() - 1); } template void CaretSimpleHeapBase::reserve(int64_t expectedSize) { if (expectedSize <= 0) return; m_heap.reserve(expectedSize); } template T& CaretSimpleHeapBase::top(K* key) { CaretAssert(m_heap.size() > 0); if (key != NULL) *key = m_heap[0].m_key; return m_heap[0].m_data; } template bool CaretSimpleHeapBase::isEmpty() const { return m_heap.size() == 0; } template int64_t CaretSimpleHeapBase::size() const { return (int64_t)m_heap.size(); } template void CaretSimpleHeapBase::clear() { m_heap.clear(); } } #endif //__CARET_HEAP__ connectome-workbench-1.4.2/src/Common/CaretHttpManager.cxx000066400000000000000000000435741360521144700236040ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretHttpManager.h" #include "CaretAssert.h" #include "CaretPointer.h" #include "CaretLogger.h" #include "NetworkException.h" #include #if QT_VERSION >= 0x050000 #include #endif // QT_VERSION using namespace caret; using namespace std; CaretHttpManager* CaretHttpManager::m_singleton = NULL; CaretHttpManager::CaretHttpManager() : QObject() { connect(&m_netMgr, SIGNAL(sslErrors(QNetworkReply*, const QList & )), this, SLOT(handleSslErrors(QNetworkReply*, const QList & ))); } CaretHttpManager* CaretHttpManager::getHttpManager() { if (m_singleton == NULL) { m_singleton = new CaretHttpManager(); } return m_singleton; } void CaretHttpManager::deleteHttpManager() { if (m_singleton != NULL) { delete m_singleton; } } QNetworkAccessManager* CaretHttpManager::getQNetManager() { return &(getHttpManager()->m_netMgr); } static QString caretHttpRequestToName(const CaretHttpRequest &caretHttpRequest) { QString name("Unknown"); switch (caretHttpRequest.m_method) { case CaretHttpManager::GET: name = "GET"; break; case CaretHttpManager::HEAD: name = "HEAD"; break; case CaretHttpManager::POST_ARGUMENTS: name = "POST ARGUMENTS"; break; case CaretHttpManager::POST_FILE: name = "POST FILE"; break; } return name; } static void logHeadersFromRequest(const QNetworkRequest& request, const CaretHttpRequest &caretHttpRequest) { AString infoText; infoText.appendWithNewLine("Request " + caretHttpRequestToName(caretHttpRequest) + ": " + request.url().toString()); infoText.appendWithNewLine(" Headers: "); QList readHeaderList = request.rawHeaderList(); const int numItems = readHeaderList.size(); if (numItems > 0) { for (int32_t i = 0; i < numItems; i++) { const QByteArray headerName = readHeaderList.at(i); if ( ! headerName.isEmpty()) { const QByteArray headerValue = request.rawHeader(headerName); infoText.appendWithNewLine(" Name: " + QString(headerName)); infoText.appendWithNewLine(" Value: " + QString(headerValue)); } } } else { infoText.appendWithNewLine(" Contains no headers"); } CaretLogFine(infoText); } void CaretHttpManager::getHeaders(const QNetworkReply& reply, std::map& headersOut) { QList readHeaderList = reply.rawHeaderList(); const int numItems = readHeaderList.size(); if (numItems > 0) { for (int32_t i = 0; i < numItems; i++) { const QByteArray headerName = readHeaderList.at(i); if ( ! headerName.isEmpty()) { const QByteArray headerValue = reply.rawHeader(headerName); headersOut.insert(make_pair(QString(headerName), QString(headerValue))); } } } } static void logHeadersFromReply(const QNetworkReply& reply, const CaretHttpRequest &caretHttpRequest, const CaretHttpResponse &caretHttpResponse) { AString infoText; infoText.appendWithNewLine("Reply " + caretHttpRequestToName(caretHttpRequest) + " URL (" + QString::number(caretHttpResponse.m_responseCode) + ") Header: "); bool errorFlag(false); if ( ! caretHttpResponse.m_responseCodeValid) { infoText.appendWithNewLine("RESPONSE CODE IS NOT VALID."); errorFlag = true; } const QNetworkReply::NetworkError networkErrorCode = reply.error(); if (networkErrorCode != QNetworkReply::NoError) { infoText.appendWithNewLine("Network Error Code (See QNetworkReply::NetworkError for description): " + QString::number(static_cast(networkErrorCode)) + "\nDescription: " + reply.errorString()); errorFlag = true; } if (errorFlag) { CaretLogWarning(infoText); return; } QList readHeaderList = reply.rawHeaderList(); const int numItems = readHeaderList.size(); if (numItems > 0) { for (int32_t i = 0; i < numItems; i++) { const QByteArray headerName = readHeaderList.at(i); if ( ! headerName.isEmpty()) { const QByteArray headerValue = reply.rawHeader(headerName); infoText.appendWithNewLine(" Name: " + QString(headerName)); infoText.appendWithNewLine(" Value: " + QString(headerValue)); } } } else { infoText.appendWithNewLine(" Contains no headers"); } CaretLogFine(infoText); } void CaretHttpManager::httpRequest(const CaretHttpRequest &request, CaretHttpResponse &response) { // /* // * Clear headers from response here only. // * For logging into Spring, it always redirects and the // * JSESSIONID is provided in the first reply but not // * in the reply from the redirect. // */ // response.m_headers.clear(); /* * Code for redirection is from the Qt HTTP example httpwindow.cpp. */ httpRequestPrivate(request, response); if (response.m_responseCode == 302) { if (response.m_redirectionUrlValid) { CaretHttpRequest redirectedRequest = request; redirectedRequest.m_url = response.m_redirectionUrl.toString(); CaretLogFine("Received and processing redirection request from " + request.m_url + " to " + redirectedRequest.m_url); CaretHttpResponse redirectedResponse; redirectedResponse.m_headers = response.m_headers; // copy headers from first attempt (may have JSESSIONID) httpRequestPrivate(redirectedRequest, redirectedResponse); /* need header from orginal and redirected response */ std::map allHeaders = response.m_headers; allHeaders.insert(redirectedRequest.m_headers.begin(), redirectedRequest.m_headers.end()); response = redirectedResponse; response.m_headers = allHeaders; if (redirectedResponse.m_body.size() > 0) { redirectedResponse.m_body.push_back(0); QString str(&redirectedResponse.m_body[0]); CaretLogFine("Redirected response content: " + str); //std::cout << "Redirected response content: " << qPrintable(str) << std::endl; } } } } void CaretHttpManager::httpRequestPrivate(const CaretHttpRequest &request, CaretHttpResponse &response) { QEventLoop myLoop; QNetworkRequest myRequest; myRequest.setSslConfiguration(QSslConfiguration::defaultConfiguration()); CaretHttpManager* myCaretMgr = getHttpManager(); AString myServerString = getServerString(request.m_url); bool have_auth = false; for (int i = 0; i < (int)myCaretMgr->m_authList.size(); ++i) { if (myServerString == myCaretMgr->m_authList[i].m_serverString) { QString unencoded = myCaretMgr->m_authList[i].m_user + ":" + myCaretMgr->m_authList[i].m_pass; myRequest.setRawHeader("Authorization", "Basic " + unencoded.toLocal8Bit().toBase64()); CaretLogFine("Found auth for URL " + request.m_url); have_auth = true; break; } } if (!have_auth) { CaretLogFine("NO AUTH FOUND for URL " + request.m_url); } QNetworkReply* myReply = NULL; /* * QUrl::addQueryItem() deprecated in Qt5: http://wiki.qt.io/Transition_from_Qt_4.x_to_Qt5 */ QUrl myUrl = QUrl::fromUserInput(request.m_url); #if QT_VERSION >= 0x050000 QUrlQuery myUrlQuery(QUrl::fromUserInput(request.m_url)); for (int32_t i = 0; i < (int32_t)request.m_queries.size(); ++i) { myUrlQuery.addQueryItem(request.m_queries[i].first, request.m_queries[i].second); } myUrl.setQuery(myUrlQuery); #else // QT_VERSION for (int32_t i = 0; i < (int32_t)request.m_queries.size(); ++i) { myUrl.addQueryItem(request.m_queries[i].first, request.m_queries[i].second); } #endif // QT_VERSION QNetworkAccessManager* myQNetMgr = &(myCaretMgr->m_netMgr); bool first = true; QByteArray postData; CaretPointer postUploadFile; // file needs to remain in scope until upload finished switch (request.m_method) { case POST_ARGUMENTS: { for (int32_t i = 0; i < (int32_t)request.m_arguments.size(); ++i) { if (!first) postData += "&"; if (request.m_arguments[i].second == "") { postData += request.m_arguments[i].first; } else { //postData += request.m_arguments[i].first + "=" + request.m_arguments[i].second; postData += QUrl::toPercentEncoding(request.m_arguments[i].first) + "=" + QUrl::toPercentEncoding(request.m_arguments[i].second); } first = false; } myRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); for (std::map::const_iterator headerIter = request.m_headers.begin(); headerIter != request.m_headers.end(); headerIter++) { myRequest.setRawHeader(headerIter->first.toLatin1(), headerIter->second.toLatin1()); } #if QT_VERSION >= 0x050000 //myUrl.setQuery(myUrlQuery); #endif // QT_VERSION myRequest.setUrl(myUrl); myReply = myQNetMgr->post(myRequest, postData); CaretLogFine("POST ARGUMENTS URL: " + myUrl.toString()); } break; case POST_FILE: { postUploadFile.grabNew(new QFile(request.m_uploadFileName)); if (postUploadFile->open(QFile::ReadOnly)) { //myRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); for (std::map::const_iterator headerIter = request.m_headers.begin(); headerIter != request.m_headers.end(); headerIter++) { myRequest.setRawHeader(headerIter->first.toLatin1(), headerIter->second.toLatin1()); // std::cout << "POST FILE header: " << qPrintable(headerIter->first) // << ": " << qPrintable(headerIter->second) << std::endl; } #if QT_VERSION >= 0x050000 myUrl.setQuery(myUrlQuery); #endif // QT_VERSION myRequest.setUrl(myUrl); myReply = myQNetMgr->post(myRequest, postUploadFile); CaretLogFine("POST FILE URL: " + myUrl.toString()); } else { } } break; case GET: for (int32_t i = 0; i < (int32_t)request.m_arguments.size(); ++i) { #if QT_VERSION >= 0x050000 myUrlQuery.addQueryItem(request.m_arguments[i].first, request.m_arguments[i].second); #else // QT_VERSION myUrl.addQueryItem(request.m_arguments[i].first, request.m_arguments[i].second); #endif // QT_VERSION } #if QT_VERSION >= 0x050000 myUrl.setQuery(myUrlQuery); #endif // QT_VERSION myRequest.setUrl(myUrl); CaretLogFine("GET URL: " + myUrl.toString()); myReply = myQNetMgr->get(myRequest); break; case HEAD: for (int32_t i = 0; i < (int32_t)request.m_arguments.size(); ++i) { #if QT_VERSION >= 0x050000 myUrlQuery.addQueryItem(request.m_arguments[i].first, request.m_arguments[i].second); #else // QT_VERSION myUrl.addQueryItem(request.m_arguments[i].first, request.m_arguments[i].second); #endif // QT_VERSION } #if QT_VERSION >= 0x050000 myUrl.setQuery(myUrlQuery); #endif // QT_VERSION myRequest.setUrl(myUrl); CaretLogFine("HEAD URL: " + myUrl.toString()); myReply = myQNetMgr->head(myRequest); break; }; //QObject::connect(myReply, SIGNAL(sslErrors(QList)), &myLoop, SLOT(quit())); //QObject::connect(myQNetMgr, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), myCaretMgr, SLOT(authenticationCallback(QNetworkReply*,QAuthenticator*))); QObject::connect(myReply, SIGNAL(finished()), &myLoop, SLOT(quit()));//this is safe, because nothing will hand this thread events except queued through this thread's event mechanism /*QObject::connect(myReply, SIGNAL(sslErrors(const QList & )), CaretHttpManager::getHttpManager(), SLOT(handleSslErrors(const QList & )));//*/ myLoop.exec();//so, they can only be delivered after myLoop.exec() starts response.m_method = request.m_method; response.m_ok = false; response.m_redirectionUrlValid = false; response.m_responseCode = -1; response.m_responseCodeValid = false; response.m_headers.clear(); response.m_errorMessage.clear(); const QVariant responseCodeVariant = myReply->attribute(QNetworkRequest::HttpStatusCodeAttribute); if ( ! responseCodeVariant.isNull()) { response.m_responseCode = myReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); response.m_responseCodeValid = true; } if (response.m_responseCode == 200) { response.m_ok = true; } else { QVariant redirectionTarget = myReply->attribute(QNetworkRequest::RedirectionTargetAttribute); if ( ! redirectionTarget.isNull()) { response.m_redirectionUrl = myUrl.resolved(redirectionTarget.toUrl()); if (response.m_redirectionUrl.isValid()) { response.m_redirectionUrlValid = true; } } } getHeaders(*myReply, response.m_headers); const bool showHeaderValues = false; if (showHeaderValues || (response.m_responseCode != 200)) { logHeadersFromRequest(myRequest, request); logHeadersFromReply(*myReply, request, response); } if (response.m_responseCode != 200) { AString s("QNetworkReply::NetworkError Code=" + AString::number((int)myReply->error()) + ", Error=" + myReply->errorString() + "\nURL=" + myUrl.toString(QUrl::None)); response.m_errorMessage = s; } QByteArray myBody = myReply->readAll(); int64_t mySize = myBody.size(); response.m_body.reserve(mySize + 1);//make room for the null terminator that will sometimes be added to the end response.m_body.resize(mySize);//but don't set size to include it for (int64_t i = 0; i < mySize; ++i) { response.m_body[i] = myBody[(int)i];//because QByteArray apparently just uses int - hope we won't need to transfer 2GB on a system that uses int32 for this } delete myReply; } void CaretHttpManager::setAuthentication(const AString& url, const AString& user, const AString& password) { CaretHttpManager* myCaretMgr = getHttpManager(); AString myServerString = getServerString(url); CaretLogFine("Setting auth for server " + myServerString); for (int i = 0; i < (int)myCaretMgr->m_authList.size(); ++i) { if (myServerString == myCaretMgr->m_authList[i].m_serverString) {//for the moment, only allow one auth token per server in one instance of caret, so replace myCaretMgr->m_authList[i].m_user = user; myCaretMgr->m_authList[i].m_pass = password; return; } }//not found, need to add AuthEntry myAuth; myAuth.m_serverString = myServerString; myAuth.m_user = user; myAuth.m_pass = password; myCaretMgr->m_authList.push_back(myAuth); } void CaretHttpManager::handleSslErrors(QNetworkReply* reply, const QList &/*errors*/) { /*qDebug() << "handleSslErrors: "; foreach (QSslError e, errors) { qDebug() << "ssl error: " << e; }*/ reply->ignoreSslErrors(); } /*void CaretHttpManager::authenticationCallback(QNetworkReply* reply, QAuthenticator* authenticator) { if (reply->url() != QUrl::fromUserInput(m_authURL))//note: a redirect will cause this to break, this is ON PURPOSE so that auth isn't sent to a redirect { throw NetworkException("Authentication requested from different URL than authentication set for"); } authenticator->setUser(m_authUser); authenticator->setPassword(m_authPass); m_authURL = ""; m_authUser = ""; m_authPass = ""; }//*/ //currently not used, because callback doesn't work for the way xnat is set up, and doesn't fit well with synchronous requests AString CaretHttpManager::getServerString(const AString& url) { QUrl fullURL = QUrl::fromUserInput(url); AString ret = fullURL.toEncoded(QUrl::RemovePath | QUrl::StripTrailingSlash | QUrl::RemoveQuery | QUrl::RemoveUserInfo); return ret; } connectome-workbench-1.4.2/src/Common/CaretHttpManager.h000066400000000000000000000063471360521144700232260ustar00rootroot00000000000000#ifndef __CARET_HTTP_MANAGER_H__ #define __CARET_HTTP_MANAGER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "stdint.h" #include "AString.h" namespace caret { struct CaretHttpRequest; struct CaretHttpResponse; class CaretHttpManager : public QObject { Q_OBJECT struct AuthEntry { AString m_serverString; AString m_user; AString m_pass; }; QNetworkAccessManager m_netMgr; CaretHttpManager(); static CaretHttpManager* m_singleton; std::vector m_authList; static AString getServerString(const AString& url); static void httpRequestPrivate(const CaretHttpRequest& request, CaretHttpResponse& response); static void getHeaders(const QNetworkReply& reply, std::map& headersOut); public: enum Method { GET, POST_ARGUMENTS, POST_FILE, HEAD }; static CaretHttpManager* getHttpManager(); static void deleteHttpManager(); static void httpRequest(const CaretHttpRequest& request, CaretHttpResponse& response); static QNetworkAccessManager* getQNetManager(); static void setAuthentication(const AString& url, const AString& user, const AString& password); public slots: void handleSslErrors(QNetworkReply* reply, const QList &/*errors*/); //void authenticationCallback(QNetworkReply* reply, QAuthenticator* authenticator); }; struct CaretHttpResponse { CaretHttpManager::Method m_method; std::vector m_body; bool m_ok; int32_t m_responseCode; bool m_responseCodeValid; QUrl m_redirectionUrl; bool m_redirectionUrlValid; AString m_errorMessage; std::map m_headers; // map so that newer values replace older values }; struct CaretHttpRequest { CaretHttpManager::Method m_method; AString m_url; AString m_uploadFileName; // used when mode is POST_FILE std::vector > m_arguments, m_queries;//arguments go to post data if method is POST_ARGUMENTS, queries stay as queries std::map m_headers; // map so that newer values replace older values }; } #endif // __CARET_HTTP_MANAGER_H__ connectome-workbench-1.4.2/src/Common/CaretLogger.cxx000066400000000000000000000017241360521144700226000ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /* * Need so that static members are allocated */ #define __CARET_LOGGER_DEFINE__ #include "CaretLogger.h" #undef __CARET_LOGGER_DEFINE__ connectome-workbench-1.4.2/src/Common/CaretLogger.h000066400000000000000000000142461360521144700222300ustar00rootroot00000000000000#ifndef __CARET_LOGGER__H_ #define __CARET_LOGGER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretFunctionName.h" #include "CaretObject.h" #include "Logger.h" namespace caret { /** * \brief The Caret Logger. * * This is the Caret Logger. Its single instance is created by * the LogManager. * * Do not use this class. Instead use the macro in this file * to send log messages at various levels. The macros are * designed so that the message is not created unless the * specific level (or below) is enabled. */ class CaretLogger { public: /** * Set the Caret logger * @param logger The logger's value. */ static void setLogger(Logger* logger) { CaretLogger::logger = logger; } /** * Get the Caret Logger. * @return The Caret logger */ inline static Logger* getLogger() { return CaretLogger::logger; } private: CaretLogger() { } ~CaretLogger() { } CaretLogger(const CaretLogger&); CaretLogger& operator=(const CaretLogger&); /** The caret logger. It is created by the LogManager. */ static Logger* logger; }; #ifdef __CARET_LOGGER_DEFINE__ Logger* CaretLogger::logger = NULL; #endif // __CARET_LOGGER_DEFINE__ } // namespace /** * \def CaretLogSevere * * Log a message at the SEVERE level. * Severe items typically prevent normal program execution. * @param TEXT * Text that is logged. */ #define CaretLogSevere(TEXT) \ ((caret::CaretLogger::getLogger()->isSevere()) \ ? caret::CaretLogger::getLogger()->log(caret::LogLevelEnum::SEVERE, __CARET_FUNCTION_NAME__, __FILE__, __LINE__, (TEXT)) \ : (void)0) /** * \def CaretLogWarning * * Log a message at the WARNING level. * Warning messages indicate potential problems. * @param TEXT * Text that is logged. */ #define CaretLogWarning(TEXT) \ ((caret::CaretLogger::getLogger()->isWarning()) \ ? caret::CaretLogger::getLogger()->log(caret::LogLevelEnum::WARNING, __CARET_FUNCTION_NAME__, __FILE__, __LINE__, (TEXT)) \ : (void)0) /** * \def CaretLogInfo * * Log a message at the INFO level. * Informational messages that may be helpful to end users. * @param TEXT * Text that is logged. */ #define CaretLogInfo(TEXT) \ ((caret::CaretLogger::getLogger()->isInfo()) \ ? caret::CaretLogger::getLogger()->log(caret::LogLevelEnum::INFO, __CARET_FUNCTION_NAME__, __FILE__, __LINE__, (TEXT)) \ : (void)0) /** * \def CaretLogConfig * * Log a message at the CONFIG level. * Configuration messages typically involve versions of * libraries, operating system, etc, and may help with * issues on specific configurations. * @param TEXT * Text that is logged. */ #define CaretLogConfig(TEXT) \ ((caret::CaretLogger::getLogger()->isConfig()) \ ? caret::CaretLogger::getLogger()->log(caret::LogLevelEnum::CONFIG, __CARET_FUNCTION_NAME__, __FILE__, __LINE__, (TEXT)) \ : (void)0) /** * \def CaretLogFine * * Log a message at the FINE level. * Fine messages are for developers such as minor, recoverable failures. * @param TEXT * Text that is logged. */ #define CaretLogFine(TEXT) \ ((caret::CaretLogger::getLogger()->isFine()) \ ? caret::CaretLogger::getLogger()->log(caret::LogLevelEnum::FINE, __CARET_FUNCTION_NAME__, __FILE__, __LINE__, (TEXT)) \ : (void)0) /** * \def CaretLogFiner * * Log a message at the FINER level. * Finer messages for for developers to provide detailed tracing messages. * Typically events and exceptions are logged at the this level. * @param TEXT * Text that is logged. */ #define CaretLogFiner(TEXT) \ ((caret::CaretLogger::getLogger()->isFiner()) \ ? caret::CaretLogger::getLogger()->log(caret::LogLevelEnum::FINER, __CARET_FUNCTION_NAME__, __FILE__, __LINE__, (TEXT)) \ : (void)0) /** * \def CaretLogFinest * * Log a message at the FINEST level. * Finest messages are for developers to provide highly detailed tracing messages. * @param TEXT * Text that is logged. */ #define CaretLogFinest(TEXT) \ ((caret::CaretLogger::getLogger()->isFinest()) \ ? caret::CaretLogger::getLogger()->log(caret::LogLevelEnum::FINEST, __CARET_FUNCTION_NAME__, __FILE__, __LINE__, (TEXT)) \ : (void)0) /** * \def CaretLogEntering * * Log a message indicating the function that one is in. * This is typically used when entering the function. * This message is logged at the FINER level. */ #define CaretLogEntering() \ ((caret::CaretLogger::getLogger()->isFiner()) \ ? caret::CaretLogger::getLogger()->entering(__CARET_FUNCTION_NAME__, __FILE__, __LINE__) \ : (void)0) /** * \def CaretLogExiting * * Log a message indicating the function that one is in. * This is typically used when entering the function. * This message is logged at the FINER level. */ #define CaretLogExiting() \ ((caret::CaretLogger::getLogger()->isFiner()) \ ? caret::CaretLogger::getLogger()->exiting(__CARET_FUNCTION_NAME__, __FILE__, __LINE__) \ : (void)0) /** * \def CaretLogThrowing * * Log a message at the FINER level for an exception class that is * derived from CaretException. * @param CARET_EXCEPTION * CaretException that is logged. */ #define CaretLogThrowing(CARET_EXCEPTION) \ ((caret::CaretLogger::getLogger()->isFiner()) \ ? caret::CaretLogger::getLogger()->throwingCaretException(__CARET_FUNCTION_NAME__, __FILE__, __LINE__, CARET_EXCEPTION) \ : (void)0) #endif //__CARET_LOGGER__H_ connectome-workbench-1.4.2/src/Common/CaretMathExpression.cxx000066400000000000000000001114451360521144700243340ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "CaretException.h" #include "CaretLogger.h" #include "CaretMathExpression.h" #include using namespace caret; using namespace std; CaretMathExpression::CaretMathExpression(const AString& expression) { m_input = expression; m_position = 0; m_end = m_input.size(); m_root = orExpr(); if (skipWhitespace())//if we DON'T hit the end of input, there are extra characters - like if the input is "x + 1 $blah" { throw CaretException("extra characters on end of expression input: '" + m_input.mid(m_position) + "'"); } CaretLogFiner("parsed '" + expression + "' as '" + toString() + "'"); } double CaretMathExpression::evaluate(const vector& variableValues) const { CaretAssert(variableValues.size() == m_varNames.size()); return m_root->eval(variableValues); } vector CaretMathExpression::getVarNames() const { vector ret(m_varNames.size()); for (map::const_iterator iter = m_varNames.begin(); iter != m_varNames.end(); ++iter) { CaretAssert(iter->second < (int)ret.size()); ret[iter->second] = iter->first; } return ret; } AString CaretMathExpression::getExpressionHelpInfo() { AString ret = AString("Expressions consist of constants, variables, operators, parentheses, and functions, in infix notation, such as 'exp(-x + 3) * scale'. ") + "Variables are strings of any length, using the characters a-z, A-Z, 0-9, and _, but may not take the name of a named constant. " + "Currently, there is only one named constant, PI. " + "The operators are +, -, *, /, ^, >, <, >=, <=, ==, !=, !, &&, ||. " + "These behave as in C, except that ^ is exponentiation, i.e. pow(x, y), and takes higher precedence than other binary operators (also, '-3^-4^-5' means '-(3^(-(4^-5)))'). " + "The <=, >=, ==, and != operators are given a small amount of wiggle room, equal to one millionth of the smaller of the absolute values of the values being compared.\n\n" + "Comparison and logical operators return 0 or 1, you can do masking with expressions like 'x * (mask > 0)'. " + "For all logical operators, an input is considered true iff it is greater than 0. " + "The expression '0 < x < 5' is not syntactically wrong, but it will NOT do what is desired, because it is evaluated left to right, i.e. '((0 < x) < 5)', " + "which will always return 1, as both possible results of a comparison are less than 5. A warning is generated if an expression of this type is detected. " + "Use something like 'x > 0 && x < 5' to get the desired behavior.\n\n" + "Whitespace between elements is ignored, ' sin ( 2 * x ) ' is equivalent to 'sin(2*x)', but 's in(2*x)' is an error. " + "Implied multiplication is not allowed, the expression '2x' will be parsed as a variable. " + "Parentheses are (), do not use [] or {}. " + "Functions require parentheses, the expression 'sin x' is an error.\n\n" + "The following functions are supported:\n\n"; vector myFuncs; MathFunctionEnum::getAllEnums(myFuncs); for (int i = 0; i < (int)myFuncs.size(); ++i) { ret += " " + MathFunctionEnum::toName(myFuncs[i]) + ": " + MathFunctionEnum::toExplanation(myFuncs[i]) + "\n"; } return ret; } double CaretMathExpression::MathNode::eval(const vector& values) const { double ret = 0.0; switch (m_type) { case OR: { int end = (int)m_arguments.size(); CaretAssert(end > 1); bool temp = (m_arguments[0]->eval(values) > 0.0); for (int i = 1; i < end; ++i) { if (temp) break;//lazy evaluation temp = (m_arguments[i]->eval(values) > 0.0);//don't need to actually do ||, we already know all the ones to the left are false } ret = temp ? 1.0 : 0.0; break; } case AND: { int end = (int)m_arguments.size(); CaretAssert(end > 1); bool temp = (m_arguments[0]->eval(values) > 0.0); for (int i = 1; i < end; ++i) { if (!temp) break;//lazy evaluation temp = (m_arguments[i]->eval(values) > 0.0);//don't need to actually do &&, we already know all the ones to the left are true } ret = temp ? 1.0 : 0.0; break; } case EQUAL: { int end = (int)m_arguments.size(); CaretAssert(end > 1); CaretAssert((int)m_invert.size() == end); ret = m_arguments[0]->eval(values); for (int i = 1; i < end; ++i) { double temp = m_arguments[i]->eval(values); float adjust = min(abs(ret), abs(temp)) / 1000000;//because == doesn't always work as expected, include a fudge factor based on the approximate precision of float bool equal = (ret >= m_arguments[i]->eval(values) - adjust) && (ret <= m_arguments[i]->eval(values) + adjust); if (m_invert[i]) { ret = equal ? 0.0 : 1.0; } else { ret = equal ? 1.0 : 0.0; } } break; } case GREATERLESS: { int end = (int)m_arguments.size();//yes, you can chain < and >, but it will produce a parsing warning, as it evaluates left to right CaretAssert(end > 1); CaretAssert((int)m_invert.size() == end); CaretAssert((int)m_inclusive.size() == end); ret = m_arguments[0]->eval(values); for (int i = 1; i < end; ++i) { double temp = m_arguments[i]->eval(values); if (m_inclusive[i]) { float adjust = min(abs(ret), abs(temp)) / 1000000;//because == doesn't always work as expected, include a fudge factor based on the approximate precision of float if (m_invert[i]) { ret = (ret <= temp + adjust ? 1.0 : 0.0);//don't trust booleans to cast to 0 and 1, just because } else { ret = (ret >= temp - adjust ? 1.0 : 0.0); } } else { if (m_invert[i]) { ret = (ret < temp ? 1.0 : 0.0); } else { ret = (ret > temp ? 1.0 : 0.0); } } } break; } case ADDSUB: { int end = (int)m_arguments.size(); CaretAssert(end > 1); CaretAssert((int)m_invert.size() == end); ret = m_arguments[0]->eval(values); for (int i = 1; i < end; ++i) { if (m_invert[i]) { ret -= m_arguments[i]->eval(values); } else { ret += m_arguments[i]->eval(values); } } break; } case MULTDIV: { int end = (int)m_arguments.size(); CaretAssert(end > 1); CaretAssert((int)m_invert.size() == end); ret = m_arguments[0]->eval(values); for (int i = 1; i < end; ++i) { if (m_invert[i]) { ret /= m_arguments[i]->eval(values); } else { ret *= m_arguments[i]->eval(values); } } break; } case NOT: CaretAssert(m_arguments.size() == 1); ret = ((m_arguments[0]->eval(values)) > 0.0) ? 0.0 : 1.0; break; case NEGATE: CaretAssert(m_arguments.size() == 1); ret = -(m_arguments[0]->eval(values)); break; case POW: { CaretAssert(m_arguments.size() == 2);//a^b^c always gets parsed into 2 power nodes, because -a^-b is -(a^(-b)) ret = pow(m_arguments[0]->eval(values), m_arguments[1]->eval(values)); break; } case FUNC: { switch (m_function)//this could be (partly) moved into MathFunctionEnum, but it wouldn't strictly be an enum class then { case MathFunctionEnum::SIN: CaretAssert(m_arguments.size() == 1); ret = sin(m_arguments[0]->eval(values)); break; case MathFunctionEnum::COS: CaretAssert(m_arguments.size() == 1); ret = cos(m_arguments[0]->eval(values)); break; case MathFunctionEnum::TAN: CaretAssert(m_arguments.size() == 1); ret = tan(m_arguments[0]->eval(values)); break; case MathFunctionEnum::ASIN: CaretAssert(m_arguments.size() == 1); ret = asin(m_arguments[0]->eval(values)); break; case MathFunctionEnum::ACOS: CaretAssert(m_arguments.size() == 1); ret = acos(m_arguments[0]->eval(values)); break; case MathFunctionEnum::ATAN: CaretAssert(m_arguments.size() == 1); ret = atan(m_arguments[0]->eval(values)); break; case MathFunctionEnum::SINH: CaretAssert(m_arguments.size() == 1); ret = sinh(m_arguments[0]->eval(values)); break; case MathFunctionEnum::COSH: CaretAssert(m_arguments.size() == 1); ret = cosh(m_arguments[0]->eval(values)); break; case MathFunctionEnum::TANH: CaretAssert(m_arguments.size() == 1); ret = tanh(m_arguments[0]->eval(values)); break; case MathFunctionEnum::ASINH: { CaretAssert(m_arguments.size() == 1); //ret = asinh(m_arguments[0].eval(values));//will work, and be preferred, when we use c++11, but doesn't work on windows with previous standard double arg = m_arguments[0]->eval(values); if (arg > 0) { ret = log(arg + sqrt(arg * arg + 1)); } else { ret = -log(-arg + sqrt(arg * arg + 1));//special case negative for stability in large negatives } break; } case MathFunctionEnum::ACOSH: { CaretAssert(m_arguments.size() == 1); //ret = acosh(m_arguments[0].eval(values)); double arg = m_arguments[0]->eval(values); ret = log(arg + sqrt(arg * arg - 1)); break; } case MathFunctionEnum::ATANH: { CaretAssert(m_arguments.size() == 1); //ret = atanh(m_arguments[0].eval(values)); double arg = m_arguments[0]->eval(values); ret = 0.5 * log((1 + arg) / (1 - arg)); break; } case MathFunctionEnum::LN: CaretAssert(m_arguments.size() == 1); ret = log(m_arguments[0]->eval(values)); break; case MathFunctionEnum::EXP: CaretAssert(m_arguments.size() == 1); ret = exp(m_arguments[0]->eval(values)); break; case MathFunctionEnum::LOG: CaretAssert(m_arguments.size() == 1); ret = log10(m_arguments[0]->eval(values)); break; case MathFunctionEnum::LOG2: CaretAssert(m_arguments.size() == 1); ret = log2(m_arguments[0]->eval(values)); break; case MathFunctionEnum::SQRT: CaretAssert(m_arguments.size() == 1); ret = sqrt(m_arguments[0]->eval(values)); break; case MathFunctionEnum::ABS: CaretAssert(m_arguments.size() == 1); ret = abs(m_arguments[0]->eval(values)); break; case MathFunctionEnum::FLOOR: CaretAssert(m_arguments.size() == 1); ret = floor(m_arguments[0]->eval(values)); break; case MathFunctionEnum::ROUND: { CaretAssert(m_arguments.size() == 1); double temp = m_arguments[0]->eval(values);//windows doesn't use c99 when compiling c++ earlier than c++11, so implement manually if (temp > 0.0) { ret = floor(temp + 0.5); } else { ret = ceil(temp - 0.5); } break; } case MathFunctionEnum::CEIL: CaretAssert(m_arguments.size() == 1); ret = ceil(m_arguments[0]->eval(values)); break; case MathFunctionEnum::ATAN2: CaretAssert(m_arguments.size() == 2); ret = atan2(m_arguments[0]->eval(values), m_arguments[1]->eval(values)); break; case MathFunctionEnum::MIN: { CaretAssert(m_arguments.size() == 2); ret = m_arguments[0]->eval(values); double other = m_arguments[1]->eval(values); if (ret > other) ret = other; break; } case MathFunctionEnum::MAX: { CaretAssert(m_arguments.size() == 2); ret = m_arguments[0]->eval(values); double other = m_arguments[1]->eval(values); if (ret < other) ret = other; break; } case MathFunctionEnum::MOD: { CaretAssert(m_arguments.size() == 2); double second = m_arguments[1]->eval(values); if (second == 0.0) { ret = 0.0; } else { double first = m_arguments[0]->eval(values); ret = first - second * floor(first / second); } break; } case MathFunctionEnum::CLAMP: { CaretAssert(m_arguments.size() == 3); ret = m_arguments[0]->eval(values); double low = m_arguments[1]->eval(values); double high = m_arguments[2]->eval(values); if (ret < low) { ret = low; } if (ret > high) { ret = high; } break; } case MathFunctionEnum::INVALID: CaretAssertMessage(0, "MathNode is type FUNC but INVALID function"); throw CaretException("parsing problem in CaretMathExpression"); } break; } case VAR: CaretAssertVectorIndex(values, m_varIndex); ret = values[m_varIndex]; break; case CONST: ret = m_constVal; break; case INVALID: CaretAssertMessage(0, "parsing left INVALID MathNode"); throw CaretException("parsing problem in CaretMathExpression"); } return ret; } AString CaretMathExpression::MathNode::toString(const std::vector& varNames) const { AString ret = ""; bool addParens = true; switch (m_type) { case OR: { int end = (int)m_arguments.size(); CaretAssert(end > 1); ret = m_arguments[0]->toString(varNames); for (int i = 1; i < end; ++i) { ret += "||" + m_arguments[i]->toString(varNames); } break; } case AND: { int end = (int)m_arguments.size(); CaretAssert(end > 1); ret = m_arguments[0]->toString(varNames); for (int i = 1; i < end; ++i) { ret += "&&" + m_arguments[i]->toString(varNames); } break; } case EQUAL: { int end = (int)m_arguments.size(); CaretAssert(end > 1); CaretAssert((int)m_invert.size() == end); ret = m_arguments[0]->toString(varNames); for (int i = 1; i < end; ++i) { if (m_invert[i]) { ret += "!=" + m_arguments[i]->toString(varNames); } else { ret += "==" + m_arguments[i]->toString(varNames); } } break; } case GREATERLESS: { int end = (int)m_arguments.size(); CaretAssert(end > 1); CaretAssert((int)m_invert.size() == end); CaretAssert((int)m_inclusive.size() == end); ret = m_arguments[0]->toString(varNames); for (int i = 1; i < end; ++i) { if (m_inclusive[i]) { if (m_invert[i]) { ret += "<=" + m_arguments[i]->toString(varNames); } else { ret += ">=" + m_arguments[i]->toString(varNames); } } else { if (m_invert[i]) { ret += "<" + m_arguments[i]->toString(varNames); } else { ret += ">" + m_arguments[i]->toString(varNames); } } } break; } case ADDSUB: { int end = (int)m_arguments.size(); CaretAssert(end > 1); CaretAssert((int)m_invert.size() == end); ret = m_arguments[0]->toString(varNames); for (int i = 1; i < end; ++i) { if (m_invert[i]) { ret += "-" + m_arguments[i]->toString(varNames); } else { ret += "+" + m_arguments[i]->toString(varNames); } } break; } case MULTDIV: { int end = (int)m_arguments.size(); CaretAssert(end > 1); CaretAssert((int)m_invert.size() == end); ret = m_arguments[0]->toString(varNames); for (int i = 1; i < end; ++i) { if (m_invert[i]) { ret += "/" + m_arguments[i]->toString(varNames); } else { ret += "*" + m_arguments[i]->toString(varNames); } } break; } case NOT: CaretAssert(m_arguments.size() == 1); ret = "!" + m_arguments[0]->toString(varNames); break; case NEGATE: CaretAssert(m_arguments.size() == 1); ret = "-" + m_arguments[0]->toString(varNames); break; case POW: CaretAssert(m_arguments.size() == 2); ret = m_arguments[0]->toString(varNames) + "^" + m_arguments[1]->toString(varNames); break; case FUNC: { addParens = false; int end = (int)m_arguments.size(); ret = MathFunctionEnum::toName(m_function) + "("; if (end > 0) ret += m_arguments[0]->toString(varNames);//allow for functions that take 0 arguments for (int i = 1; i < end; ++i) { ret += "," + m_arguments[i]->toString(varNames); } ret += ")"; break; } case VAR: addParens = false; CaretAssertVectorIndex(varNames, m_varIndex); ret = varNames[m_varIndex]; break; case CONST: addParens = false; if (m_constName != "") { ret = m_constName; } else { ret = AString::number(m_constVal, 'g', 15); } break; case INVALID: CaretAssertMessage(0, "toString called on invalid MathNode"); throw CaretException("parsing problem in CaretMathExpression"); } if (addParens) ret = "(" + ret + ")";//parenthesize almost everything return ret; } AString CaretMathExpression::toString() const { return m_root->toString(getVarNames()); } bool CaretMathExpression::skipWhitespace()//return false if end of input { while (m_position < m_end && m_input[m_position].isSpace()) ++m_position; return m_position < m_end; } bool CaretMathExpression::accept(const char& c) { if (!skipWhitespace()) return false;//end of input if (m_input[m_position] == c) { ++m_position; return true; } return false; } void CaretMathExpression::expect(const char& c, const int& exprStart) { CaretAssert(exprStart < m_end); if (!skipWhitespace()) throw CaretException("unexpected end of input while parsing '" + m_input.mid(exprStart) + "', expected '" + AString(c) + "'"); if (m_input[m_position] != c) throw CaretException("expected '" + AString(c) + "', got '" + m_input[m_position] + "' while parsing '" + m_input.mid(exprStart, m_position - exprStart + 1) + "'"); ++m_position; } CaretPointer CaretMathExpression::orExpr() { int start = m_position;//for error reporting CaretPointer temp = andExpr(); if (accept('|')) { CaretPointer ret(new MathNode(MathNode::OR)); ret->m_arguments.push_back(temp); do { expect('|', start); ret->m_arguments.push_back(andExpr()); } while (accept('|')); return ret; } return temp; } CaretPointer CaretMathExpression::andExpr() { int start = m_position;//for error reporting CaretPointer temp = equalExpr(); if (accept('&')) { CaretPointer ret(new MathNode(MathNode::AND)); ret->m_arguments.push_back(temp); do { expect('&', start); ret->m_arguments.push_back(equalExpr()); } while (accept('&')); return ret; } return temp; } CaretPointer CaretMathExpression::equalExpr() { int start = m_position;//for error reporting CaretPointer temp = greaterLessExpr(); bool good = false, invert;//means not equal if (accept('=')) { good = true; invert = false; } else if (accept('!')) { good = true; invert = true; } if (good) { CaretPointer ret(new MathNode(MathNode::EQUAL)); ret->m_arguments.push_back(temp); ret->m_invert.push_back(false);//first one isn't used, they apply to the operator to the left of the argument do { expect('=', start); ret->m_arguments.push_back(greaterLessExpr()); ret->m_invert.push_back(invert); good = false; if (accept('=')) { good = true; invert = false; } else if (accept('!')) { good = true; invert = true; } } while (good); if (ret->m_arguments.size() > 2) { CaretLogWarning("expression '" + m_input.mid(start, m_position - start) + "' will do equality comparison left to right"); } return ret; } return temp; } CaretPointer CaretMathExpression::greaterLessExpr() { int start = m_position;//for error reporting CaretPointer temp = addSubExpr(); bool good = false, invert, inclusive = false;//invert means less than if (accept('>')) { good = true; invert = false; } else if (accept('<')) { good = true; invert = true; } if (good && accept('=')) inclusive = true; if (good) { CaretPointer ret(new MathNode(MathNode::GREATERLESS)); ret->m_arguments.push_back(temp); ret->m_invert.push_back(false);//first one isn't used, they apply to the operator to the left of the argument ret->m_inclusive.push_back(false);//ditto do { ret->m_arguments.push_back(addSubExpr()); ret->m_invert.push_back(invert); ret->m_inclusive.push_back(inclusive); good = false; inclusive = false; if (accept('>')) { good = true; invert = false; } else if (accept('<')) { good = true; invert = true; } if (good && accept('=')) inclusive = true; } while (good); if (ret->m_arguments.size() > 2) { CaretLogWarning("expression '" + m_input.mid(start, m_position - start) + "' will do inequality comparison left to right"); } return ret; } return temp; } CaretPointer CaretMathExpression::addSubExpr() { CaretPointer temp = multDivExpr(); bool good = false, invert;//means subtract if (accept('+')) { good = true; invert = false; } else if (accept('-')) { good = true; invert = true; } if (good) { CaretPointer ret(new MathNode(MathNode::ADDSUB)); ret->m_arguments.push_back(temp); ret->m_invert.push_back(false);//first one isn't used, they apply to the operator to the left of the argument do { ret->m_arguments.push_back(multDivExpr()); ret->m_invert.push_back(invert); good = false; if (accept('+')) { good = true; invert = false; } else if (accept('-')) { good = true; invert = true; } } while (good); return ret; } return temp; } CaretPointer CaretMathExpression::multDivExpr() { CaretPointer temp = unaryExpr(); bool good = false, invert;//means divide if (accept('*')) { good = true; invert = false; } else if (accept('/')) { good = true; invert = true; } if (good) { CaretPointer ret(new MathNode(MathNode::MULTDIV)); ret->m_arguments.push_back(temp); ret->m_invert.push_back(false);//first one isn't used, they apply to the operator to the left of the argument do { ret->m_arguments.push_back(unaryExpr()); ret->m_invert.push_back(invert); good = false; if (accept('*')) { good = true; invert = false; } else if (accept('/')) { good = true; invert = true; } } while (good); return ret; } return temp; } CaretPointer CaretMathExpression::unaryExpr() { CaretPointer ret; if (accept('-')) { ret.grabNew(new MathNode(MathNode::NEGATE)); ret->m_arguments.push_back(unaryExpr());//allow -----x and other silliness, because it is more complicated to try to prevent it return ret; } else if (accept('!')) { ret.grabNew(new MathNode(MathNode::NOT)); ret->m_arguments.push_back(unaryExpr());//similarly, !!!!x...and !!--!---!!!!-!!-!!!1, etc return ret; } else if (accept('+')) {//unary plus does nothing return unaryExpr();//this is not infinitely recursive, accept() removes a char of input } return powExpr(); } CaretPointer CaretMathExpression::powExpr() { CaretPointer temp = funcExpr(); if (accept('^')) { CaretPointer ret(new MathNode(MathNode::POW)); ret->m_arguments.push_back(temp); ret->m_arguments.push_back(unaryExpr());//because -x^y is -(x^y), but x^-y is x^(-y) return ret; } return temp; } CaretPointer CaretMathExpression::funcExpr() { int start = m_position; if (accept('(')) { CaretPointer ret = orExpr(); expect(')', start); return ret; }//and now a non-predictive bit - checking for valid function name int funcnameEnd = m_input.indexOf('(', m_position); if (funcnameEnd != -1) { bool ok = false; MathFunctionEnum::Enum myfunc = MathFunctionEnum::fromName(m_input.mid(m_position, funcnameEnd - m_position).trimmed(), &ok); if (ok) { int numArgs = -1; switch(myfunc) { case MathFunctionEnum::SIN: case MathFunctionEnum::COS: case MathFunctionEnum::TAN: case MathFunctionEnum::ASIN: case MathFunctionEnum::ACOS: case MathFunctionEnum::ATAN: case MathFunctionEnum::SINH: case MathFunctionEnum::COSH: case MathFunctionEnum::TANH: case MathFunctionEnum::ASINH: case MathFunctionEnum::ACOSH: case MathFunctionEnum::ATANH: case MathFunctionEnum::LN: case MathFunctionEnum::EXP: case MathFunctionEnum::LOG: case MathFunctionEnum::LOG2: case MathFunctionEnum::SQRT: case MathFunctionEnum::ABS: case MathFunctionEnum::FLOOR: case MathFunctionEnum::ROUND: case MathFunctionEnum::CEIL: numArgs = 1; break; case MathFunctionEnum::ATAN2: case MathFunctionEnum::MIN: case MathFunctionEnum::MAX: case MathFunctionEnum::MOD: numArgs = 2; break; case MathFunctionEnum::CLAMP: numArgs = 3; break; case MathFunctionEnum::INVALID://this should not happen CaretAssert(false); } CaretPointer ret(new MathNode(MathNode::FUNC)); ret->m_function = myfunc; m_position = funcnameEnd + 1;//skip the ( of the function if (!accept(')'))//zero arguments case { ret->m_arguments.push_back(orExpr()); while (accept(',')) { ret->m_arguments.push_back(orExpr()); } expect(')', start); } if ((int)ret->m_arguments.size() != numArgs) throw CaretException("function '" + MathFunctionEnum::toName(myfunc) + "' takes " + AString::number(numArgs) + " argument(s), but was given " + AString::number(ret->m_arguments.size()) + ": '" + m_input.mid(start, m_position - start) + "'"); return ret; } } return terminal();//if it isn't parenthesis or a function, the only thing left is terminal } CaretPointer CaretMathExpression::terminal() { CaretPointer ret = tryLiteral();//try literal first, our relaxed rules for variable names overlap with integers if (ret != NULL) return ret; if (!skipWhitespace()) throw CaretException("unexpected end of input, expected operand");//now, try named constant/variable int varEnd = m_position; bool onlydigits = true; while (varEnd < m_end) { QChar thisChar = m_input[varEnd];//allow letters, numbers, and underscore if (!thisChar.isLetterOrNumber() && thisChar != '_') { break; } if (!thisChar.isDigit()) onlydigits = false;//if there are only digits, this is not a variable, tryLiteral failed on something that was intended to be a literal ++varEnd; } double constVal = 0.0f; AString identifier = m_input.mid(m_position, varEnd - m_position); if (identifier.size() == 0)//hit an invalid character or end of input before getting any valid characters {//figure out why we stopped, give appropriate error if (varEnd >= m_end) throw CaretException("unexpected end of input, expected operand"); throw CaretException("unexpected character '" + AString(m_input[varEnd]) + "' at beginning of operand");//if it fails for all prefix unary, parens, function, literal, variable, then this character can never start an operand } if (onlydigits) throw CaretException("error parsing literal value beginning with '" + identifier + "'"); m_position = varEnd; if (getNamedConstant(identifier, constVal)) { ret.grabNew(new MathNode(MathNode::CONST)); ret->m_constName = identifier; ret->m_constVal = constVal; return ret; } ret.grabNew(new MathNode(MathNode::VAR)); map::const_iterator iter = m_varNames.find(identifier); if (iter == m_varNames.end()) { int index = (int)m_varNames.size(); m_varNames.insert(make_pair(identifier, index)); ret->m_varIndex = index; } else { ret->m_varIndex = iter->second; } return ret; } CaretPointer CaretMathExpression::tryLiteral() { if (!skipWhitespace()) throw CaretException("unexpected end of input, expected operand");//now, try literal int litstart = m_position, litend = m_position; if (m_input[litend] == '-' || m_input[litend] == '+') ++litend;//allow literals to start with - or + : however, - will not happen, due to unary - (which does that so that -2^-2 works as -(2^(-2)) bool havedot = false, haveexp = false; while (litend < m_end) { QChar mychar = m_input[litend]; if (mychar.isDigit() || mychar == '.')//manually test for multiple '.' for better error messages, it can never be correct as a non-literal { ++litend; if (mychar == '.') { if (havedot) throw CaretException("multiple '.' characters in literal: '" + m_input.mid(litstart, litend - litstart) + "'"); havedot = true; } continue; } if (mychar == 'e' || mychar == 'E') {//scientific notation, don't throw on multiple 'e', because '2e-3e' is subtraction of two variables if (haveexp) return CaretPointer();//but do stop early, as it won't be a literal haveexp = true; ++litend; if (litend >= m_end) break; if (m_input[litend] == '-' || m_input[litend] == '+') ++litend;//allow + or - after e continue; }//spaces are not allowed inside literals break;//yes, break at the end of a while loop - anything we don't recognize as valid ends the loop } bool ok = false; double litVal = m_input.mid(litstart, litend - litstart).toDouble(&ok); if (!ok) return CaretPointer(); m_position = litend; CaretPointer ret(new MathNode(MathNode::CONST)); ret->m_constVal = litVal; return ret; } bool CaretMathExpression::getNamedConstant(const AString& name, double& valueOut) { if (name == "PI") { valueOut = 3.1415926535897932;//double can do about 16 decimal digits, give 17 for rounding return true; } return false;//presumably we will have more named constants later } connectome-workbench-1.4.2/src/Common/CaretMathExpression.h000066400000000000000000000066621360521144700237650ustar00rootroot00000000000000#ifndef __CARET_MATH_EXPRESSION_H__ #define __CARET_MATH_EXPRESSION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AString.h" #include "CaretPointer.h" #include "MathFunctionEnum.h" #include #include namespace caret { class CaretMathExpression { struct MathNode { enum ExprType { INVALID, OR, AND, EQUAL, GREATERLESS, ADDSUB, MULTDIV, NOT, NEGATE, POW, FUNC, VAR, CONST }; ExprType m_type; MathFunctionEnum::Enum m_function; AString m_constName; double m_constVal; int m_varIndex; std::vector m_invert;//whether it is subtract rather than add, or divide instead of multiply, or less instead of greater std::vector m_inclusive;//whether greater/less includes equals std::vector > m_arguments; MathNode() { m_type = INVALID; m_function = MathFunctionEnum::INVALID; } MathNode(const ExprType& type) { m_type = type; m_function = MathFunctionEnum::INVALID; } double eval(const std::vector& values) const; AString toString(const std::vector& varNames) const; }; std::map m_varNames; AString m_input; int m_position, m_end; CaretPointer m_root; bool skipWhitespace(); bool accept(const char& c); void expect(const char& c, const int& exprStart); CaretPointer orExpr();//hopefully we have enough stack space that we won't overflow without a hundred or so levels of parenthesis/functions/exponents CaretPointer andExpr(); CaretPointer equalExpr(); CaretPointer greaterLessExpr(); CaretPointer addSubExpr(); CaretPointer multDivExpr(); CaretPointer unaryExpr();//accepts --x, !!1, !--!-!!PI, etc CaretPointer powExpr(); CaretPointer funcExpr();//also parenthesis CaretPointer terminal();//literal, const, variable CaretPointer tryLiteral();//NOTE: does not throw except on early end of input, returns NULL on failure public: static AString getExpressionHelpInfo(); static bool getNamedConstant(const AString& name, double& valueOut); CaretMathExpression(const AString& expression); double evaluate(const std::vector& variableValues) const; std::vector getVarNames() const; AString toString() const;//the expression, with a lot of parentheses added }; } // namespace #endif //__CARET_MATH_EXPRESSION_H__ connectome-workbench-1.4.2/src/Common/CaretMutex.h000066400000000000000000000046351360521144700221140ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #ifndef __CARET_MUTEX_H__ #define __CARET_MUTEX_H__ #include "CaretOMP.h" //omp mutexes are faster than QMutex, especially without contention #ifdef CARET_OMP namespace caret { class CaretMutex { omp_lock_t m_lock; public: CaretMutex(const CaretMutex&) { omp_init_lock(&m_lock); };//allow copy, assign, but make them do nothing other than default construct CaretMutex& operator=(const CaretMutex&) { return *this; }; CaretMutex() { omp_init_lock(&m_lock); } ~CaretMutex() { omp_destroy_lock(&m_lock); } friend class CaretMutexLocker; }; class CaretMutexLocker { CaretMutex* m_mutex; CaretMutexLocker();//disallow default construction, assign CaretMutexLocker& operator=(const CaretMutexLocker& rhs); public: CaretMutexLocker(CaretMutex* mutex) { m_mutex = mutex; omp_set_lock(&(m_mutex->m_lock)); } ~CaretMutexLocker() { omp_unset_lock(&(m_mutex->m_lock)); } }; } #else //if we don't have openmp, fall back to QMutex #include namespace caret { class CaretMutex : public QMutex { public: CaretMutex(RecursionMode mode = NonRecursive) : QMutex(mode) { } CaretMutex(const CaretMutex&) : QMutex() { };//allow copy, assign, but make them do nothing other than default construct CaretMutex& operator=(const CaretMutex&) { return *this; }; }; class CaretMutexLocker : public QMutexLocker { public: CaretMutexLocker(CaretMutex* theMutex) : QMutexLocker(theMutex) { } }; } #endif #endif //__CARET_MUTEX_H__ connectome-workbench-1.4.2/src/Common/CaretOMP.h000066400000000000000000000042621360521144700214410ustar00rootroot00000000000000#ifndef __CARET_OMP_H__ #define __CARET_OMP_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ ///this include file is for anything specific to how we use openmp in caret, and also for convenience ///for instance, you don't need #ifdef guards around including this file, unlike omp.h #ifdef _OPENMP #include "omp.h" ///another define to use in guards, might be easier to remember #define CARET_OMP #endif //_OPENMP ///some defines for #pragma omp, in case we want to add default options (for workarounds or global options) ///if we never need to use these for workarounds or global options, so be it ///NOTE: neither "#pragma" nor "omp" can be put into a define and have it work correctly, so they can't be made that much more friendly ///defined regardless so the preprocessor and compiler aren't any more confused if _OPENMP isn't defined (will complain about ignoring pragma if used without guards) ///DO NOT add scheduling to this list, scheduling choice needs to be able to be changed #define CARET_PAR_OPTIONS #define CARET_FOR_OPTIONS #define CARET_SINGLE_OPTIONS ///and defines to combine them with the pragmas they are intended for ///use them as "#pragma omp CARET_PARFOR [other options]" #define CARET_PAR parallel CARET_PAR_OPTIONS #define CARET_FOR for CARET_FOR_OPTIONS #define CARET_PARFOR parallel for CARET_PAR_OPTIONS CARET_FOR_OPTIONS #define CARET_SINGLE single CARET_SINGLE_OPTIONS #endif //__CARET_OMP_H__ connectome-workbench-1.4.2/src/Common/CaretObject.cxx000066400000000000000000000105271360521144700225700ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __CARET_OBJECT_DECLARE_H__ #include "CaretObject.h" #undef __CARET_OBJECT_DECLARE_H__ #include "SystemUtilities.h" using namespace caret; /** * Constructor. * */ CaretObject::CaretObject() { this->initializeMembersCaretObject(); } /** * Copy constructor. * */ CaretObject::CaretObject(const CaretObject& co) { this->initializeMembersCaretObject(); this->copyHelper(co); } /** * Destructor */ CaretObject::~CaretObject() { #ifndef NDEBUG /* * Erase returns the number of objects deleted. * If zero, then the object has already been deleted. */ uint64_t numDeleted = CaretObject::allocatedObjects.erase(this); if (numDeleted <= 0) { std::cerr << "Destructor for a CaretObject called but the object is not allocated " << "and this implies that the object has already been deleted."; } #endif } CaretObject& CaretObject::operator=(const CaretObject& co) { if (this != &co) { this->copyHelper(co); } return *this; } void CaretObject::initializeMembersCaretObject() { #ifndef NDEBUG SystemBacktrace myBacktrace; SystemUtilities::getBackTrace(myBacktrace); CaretObject::allocatedObjects.insert( std::make_pair(this, myBacktrace)); /*CaretObject::allocatedObjects.insert( std::make_pair(this, SystemUtilities::getBackTrace()));//*/ #endif } void CaretObject::copyHelper(const CaretObject&) { } /** * Get String representation of caret object. * @return String containing caret object. * */ AString CaretObject::toString() const { AString s = "CaretObjectType=" + this->className(); return s; } /** * Get the class name of this object. * @return * Class name of the object. */ AString CaretObject::className() const { AString name(typeid(*this).name()); return name; } #ifdef NDEBUG /** * Do not print objects not deleted if NOT debug */ void CaretObject::printListOfObjectsNotDeleted(const bool) { } #else /** * Print a list of CaretObjects that were not deleted. */ void CaretObject::printListOfObjectsNotDeleted(const bool showCallStack) { int count = 0; if (CaretObject::allocatedObjects.empty() == false) { std::cout << "These Caret Objects were not deleted:" << std::endl; for (CARET_OBJECT_TRACKER_MAP_ITERATOR iter = CaretObject::allocatedObjects.begin(); iter != allocatedObjects.end(); iter++) { const unsigned long objectAddress = (long long)iter->first; //const CaretObject* caretObject = iter->first; const CaretObjectInfo& caretObjectInfo = iter->second; // below will crash if item has been deleted //std::cout << caretObject->toString().toStdString() << std::endl; std::cout << "Address (hex)=" << std::hex << objectAddress << std::endl; if (showCallStack) { std::cout << caretObjectInfo.m_backtrace.toSymbolString() << std::endl; } std::cout << std::endl; count++; } } if (count > 0) { std::cout << std::dec << count << " objects were not deleted." << std::endl; } } #endif /** * Constructor. * @param backtrace * The backtrace. */ CaretObject::CaretObjectInfo::CaretObjectInfo(const SystemBacktrace& backtrace) { m_backtrace = backtrace; } /** * Destructor. */ CaretObject::CaretObjectInfo::~CaretObjectInfo() { } connectome-workbench-1.4.2/src/Common/CaretObject.h000066400000000000000000000041751360521144700222170ustar00rootroot00000000000000#ifndef __CARETOBJECT_H__ #define __CARETOBJECT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "SystemUtilities.h" namespace caret { /** * A base class for all objects that are not derived * from third party libraries. */ class CaretObject { protected: CaretObject(); CaretObject(const CaretObject& o); CaretObject& operator=(const CaretObject& co); public: virtual ~CaretObject(); virtual AString toString() const; AString className() const; static void printListOfObjectsNotDeleted(const bool showCallStack); private: /** * Info about an allocated object. */ class CaretObjectInfo { public: CaretObjectInfo(const SystemBacktrace& backtrace); ~CaretObjectInfo(); SystemBacktrace m_backtrace; }; void copyHelper(const CaretObject& co); void initializeMembersCaretObject(); typedef std::map CARET_OBJECT_TRACKER_MAP; typedef CARET_OBJECT_TRACKER_MAP::iterator CARET_OBJECT_TRACKER_MAP_ITERATOR; static CARET_OBJECT_TRACKER_MAP allocatedObjects; }; #ifdef __CARET_OBJECT_DECLARE_H__ CaretObject::CARET_OBJECT_TRACKER_MAP CaretObject::allocatedObjects; #endif //__CARET_OBJECT_DECLARE_H__ } // namespace #endif // __CARETOBJECT_H__ connectome-workbench-1.4.2/src/Common/CaretObjectTracksModification.cxx000066400000000000000000000061651360521144700262710ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CARET_OBJECT_TRACKS_MODIFICATION_DECLARE__ #include "CaretObjectTracksModification.h" #undef __CARET_OBJECT_TRACKS_MODIFICATION_DECLARE__ using namespace caret; /** * \class caret::CaretObjectTracksModification * \brief CaretObject base class with implementation of tracks modification interface. */ /** * Constructor. */ CaretObjectTracksModification::CaretObjectTracksModification() : CaretObject(), TracksModificationInterface() { this->modifiedFlag = false; } /** * Destructor. */ CaretObjectTracksModification::~CaretObjectTracksModification() { } /** * Copy constructor. * @param obj * Object that is copied. */ CaretObjectTracksModification::CaretObjectTracksModification(const CaretObjectTracksModification& obj) : CaretObject(obj), TracksModificationInterface() { this->copyHelperCaretObjectTracksModification(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ CaretObjectTracksModification& CaretObjectTracksModification::operator=(const CaretObjectTracksModification& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperCaretObjectTracksModification(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void CaretObjectTracksModification::copyHelperCaretObjectTracksModification(const CaretObjectTracksModification& /*obj*/) { this->modifiedFlag = false; // do not copy modification status } /** * Set the status to modified. */ void CaretObjectTracksModification::setModified() { this->modifiedFlag = true; } /** * Set the status to unmodified. */ void CaretObjectTracksModification::clearModified() { this->modifiedFlag = false; } /** * Is the object modified? * @return true if modified, else false. */ bool CaretObjectTracksModification::isModified() const { return this->modifiedFlag; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString CaretObjectTracksModification::toString() const { const AString text = (CaretObject::toString() + "\nCaretObjectTracksModification::modifiedFlag=" + AString::fromBool(this->modifiedFlag)); return text; } connectome-workbench-1.4.2/src/Common/CaretObjectTracksModification.h000066400000000000000000000037251360521144700257150ustar00rootroot00000000000000#ifndef __CARET_OBJECT_TRACKS_MODIFICATION__H_ #define __CARET_OBJECT_TRACKS_MODIFICATION__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "TracksModificationInterface.h" namespace caret { class CaretObjectTracksModification : public CaretObject, public TracksModificationInterface { public: CaretObjectTracksModification(); virtual ~CaretObjectTracksModification(); CaretObjectTracksModification(const CaretObjectTracksModification& obj); CaretObjectTracksModification& operator=(const CaretObjectTracksModification& obj); virtual AString toString() const; virtual void setModified(); virtual void clearModified(); virtual bool isModified() const; private: void copyHelperCaretObjectTracksModification(const CaretObjectTracksModification& obj); bool modifiedFlag; }; #ifdef __CARET_OBJECT_TRACKS_MODIFICATION_DECLARE__ // #endif // __CARET_OBJECT_TRACKS_MODIFICATION_DECLARE__ } // namespace #endif //__CARET_OBJECT_TRACKS_MODIFICATION__H_ connectome-workbench-1.4.2/src/Common/CaretPointLocator.cxx000066400000000000000000000355551360521144700240070ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretPointLocator.h" #include "CaretHeap.h" #include using namespace caret; using namespace std; void CaretPointLocator::addPoint(Oct >* thisOct, const float point[3], const int64_t index, const int32_t pointSet) { if (thisOct->m_leaf) { thisOct->m_data.m_vector->push_back(Point(point, index, pointSet)); int curSize = (int)thisOct->m_data.m_vector->size(); if (curSize > NUM_POINTS_SPLIT) {//test that not all points are the same, or that they have some minimum percentage spread, or... vector& myVecRef = *(thisOct->m_data.m_vector); Vector3D minBox = myVecRef[0].m_point, maxBox = myVecRef[0].m_point, tempvec; tempvec[0] = thisOct->m_bounds[0][2] - thisOct->m_bounds[0][0]; tempvec[1] = thisOct->m_bounds[1][2] - thisOct->m_bounds[1][0]; tempvec[2] = thisOct->m_bounds[2][2] - thisOct->m_bounds[2][0]; float diagonal = tempvec.length(); bool safeToSplit = false; for (int i = 1; i < curSize; ++i) {//this will slow down if lots of stuff is continuously put in an Oct that is far too big - use random sampling? if (myVecRef[i].m_point[0] < minBox[0]) minBox[0] = myVecRef[i].m_point[0]; if (myVecRef[i].m_point[1] < minBox[1]) minBox[1] = myVecRef[i].m_point[1]; if (myVecRef[i].m_point[2] < minBox[2]) minBox[2] = myVecRef[i].m_point[2]; if (myVecRef[i].m_point[0] > maxBox[0]) maxBox[0] = myVecRef[i].m_point[0]; if (myVecRef[i].m_point[1] > maxBox[1]) maxBox[1] = myVecRef[i].m_point[1]; if (myVecRef[i].m_point[2] > maxBox[2]) maxBox[2] = myVecRef[i].m_point[2]; tempvec = minBox - maxBox; if (tempvec.length() > 0.01f * diagonal)//make sure points aren't all identical, would go to infinity recursively { safeToSplit = true; break; } } if (safeToSplit) { thisOct->makeChildren(); for (int i = 0; i < curSize; ++i) { addPoint(thisOct->containingChild(myVecRef[i].m_point), myVecRef[i].m_point, myVecRef[i].m_index, myVecRef[i].m_mySet); } thisOct->m_data.freeData(); } } } else { addPoint(thisOct->containingChild(point), point, index, pointSet); } } int32_t CaretPointLocator::addPointSet(const float* coordsIn, const int64_t numCoords) { CaretMutexLocker locked(&m_modifyMutex); int32_t setNum = newIndex(); if (numCoords < 1) return setNum; if (m_tree == NULL) { Vector3D minBox, maxBox; minBox = maxBox = coordsIn;//hack - first triple for (int64_t i = 1; i < numCoords; ++i) { int64_t i3 = i * 3; if (coordsIn[i3] < minBox[0]) minBox[0] = coordsIn[i3]; if (coordsIn[i3 + 1] < minBox[1]) minBox[1] = coordsIn[i3 + 1]; if (coordsIn[i3 + 2] < minBox[2]) minBox[2] = coordsIn[i3 + 2]; if (coordsIn[i3] > maxBox[0]) maxBox[0] = coordsIn[i3]; if (coordsIn[i3 + 1] > maxBox[1]) maxBox[1] = coordsIn[i3 + 1]; if (coordsIn[i3 + 2] > maxBox[2]) maxBox[2] = coordsIn[i3 + 2]; } m_tree = new Oct >(minBox, maxBox); } for (int64_t i = 0; i < numCoords; ++i) { int64_t i3 = i * 3; m_tree = m_tree->makeContains(coordsIn + i3);//make new root if needed addPoint(m_tree, coordsIn + i3, i, setNum);//and add the point } return setNum; } CaretPointLocator::CaretPointLocator(const float* coordsIn, const int64_t numCoords) { m_nextSetIndex = 1;//next set will be set #1 m_tree = NULL; if (numCoords >= 1) { Vector3D minBox, maxBox; minBox = maxBox = coordsIn;//hack - first triple for (int64_t i = 1; i < numCoords; ++i) { int64_t i3 = i * 3; if (coordsIn[i3] < minBox[0]) minBox[0] = coordsIn[i3]; if (coordsIn[i3 + 1] < minBox[1]) minBox[1] = coordsIn[i3 + 1]; if (coordsIn[i3 + 2] < minBox[2]) minBox[2] = coordsIn[i3 + 2]; if (coordsIn[i3] > maxBox[0]) maxBox[0] = coordsIn[i3]; if (coordsIn[i3 + 1] > maxBox[1]) maxBox[1] = coordsIn[i3 + 1]; if (coordsIn[i3 + 2] > maxBox[2]) maxBox[2] = coordsIn[i3 + 2]; } m_tree = new Oct >(minBox, maxBox); for (int64_t i = 0; i < numCoords; ++i) { int64_t i3 = i * 3; addPoint(m_tree, coordsIn + i3, i, 0);//this is set #0 } } } CaretPointLocator::CaretPointLocator(const float minBounds[3], const float maxBounds[3]) { m_nextSetIndex = 0; m_tree = new Oct >(minBounds, maxBounds); } int64_t CaretPointLocator::closestPoint(const float target[3], LocatorInfo* infoOut) const { if (m_tree == NULL) return -1; CaretSimpleMinHeap >*, float> myHeap; bool first = true; float bestDist2 = -1.0f, bestDist = -1.0f, tempf, curDist = m_tree->distToPoint(target); Vector3D bestPoint; int64_t bestIndex = -1; int32_t bestSet = -1; myHeap.push(m_tree, curDist); while (curDist < bestDist || first) { Oct >* thisOct = myHeap.pop(); if (thisOct->m_leaf) { vector& myVecRef = *(thisOct->m_data.m_vector); int curSize = (int)myVecRef.size(); for (int i = 0; i < curSize; ++i) { tempf = MathFunctions::distanceSquared3D(myVecRef[i].m_point, target); if (tempf < bestDist2 || first) { first = false; bestDist2 = tempf; bestPoint = myVecRef[i].m_point; bestSet = myVecRef[i].m_mySet; bestIndex = myVecRef[i].m_index; } } bestDist = sqrt(bestDist2); } else { for (int ii = 0; ii < 2; ++ii) { for (int ij = 0; ij < 2; ++ij) { for (int ik = 0; ik < 2; ++ik) { tempf = thisOct->m_children[ii][ij][ik]->distToPoint(target); if (tempf < bestDist || first) { myHeap.push(thisOct->m_children[ii][ij][ik], tempf); } } } } } if (myHeap.isEmpty()) { break;//allows us to use top() without violating an assertion } myHeap.top(&curDist);//get the key for the next item } if (infoOut != NULL) { infoOut->whichSet = bestSet; infoOut->coords = bestPoint; infoOut->index = bestIndex; } return bestIndex; } int64_t CaretPointLocator::closestPointLimited(const float target[3], const float& maxDist, LocatorInfo* infoOut) const { if (infoOut != NULL) { infoOut->whichSet = -1; infoOut->index = -1; } if (m_tree == NULL) return -1; float curDist2 = m_tree->distSquaredToPoint(target), maxDist2 = maxDist * maxDist; if (curDist2 > maxDist2) { return -1; } CaretSimpleMinHeap >*, float> myHeap; bool first = true; float bestDist2 = -1.0f, tempf; Vector3D bestPoint; int64_t bestIndex = -1; int32_t bestSet = -1; myHeap.push(m_tree, curDist2); while (curDist2 < bestDist2 || first) { Oct >* thisOct = myHeap.pop(); if (thisOct->m_leaf) { vector& myVecRef = *(thisOct->m_data.m_vector); int curSize = (int)myVecRef.size(); for (int i = 0; i < curSize; ++i) { tempf = MathFunctions::distanceSquared3D(myVecRef[i].m_point, target); if (tempf < bestDist2 || (first && tempf <= maxDist2)) { first = false; bestDist2 = tempf; bestPoint = myVecRef[i].m_point; bestSet = myVecRef[i].m_mySet; bestIndex = myVecRef[i].m_index; } } } else { for (int ii = 0; ii < 2; ++ii) { for (int ij = 0; ij < 2; ++ij) { for (int ik = 0; ik < 2; ++ik) { tempf = thisOct->m_children[ii][ij][ik]->distSquaredToPoint(target); if (tempf < bestDist2 || (first && tempf <= maxDist2)) { myHeap.push(thisOct->m_children[ii][ij][ik], tempf); } } } } } if (myHeap.isEmpty()) { break;//allows us to use top() without violating an assertion } myHeap.top(&curDist2);//get the key for the next item } if (infoOut != NULL) { infoOut->whichSet = bestSet; infoOut->coords = bestPoint; infoOut->index = bestIndex; } return bestIndex; } vector CaretPointLocator::pointsInRange(const float target[3], const float& maxDist) const {//each point occurs in only once in the tree, so we can use a vector vector ret; if (m_tree == NULL) return ret; float curDist2 = m_tree->distSquaredToPoint(target), maxDist2 = maxDist * maxDist; if (curDist2 > maxDist2) return ret; vector >*> myStack;//since we don't need the points sorted by distance myStack.push_back(m_tree); while (!myStack.empty()) { Oct >* thisOct = myStack.back(); myStack.pop_back(); if (thisOct->m_leaf) { vector& myVecRef = *(thisOct->m_data.m_vector); int curSize = (int)myVecRef.size(); for (int i = 0; i < curSize; ++i) { float tempf = MathFunctions::distanceSquared3D(myVecRef[i].m_point, target); if (tempf <= maxDist2) { ret.push_back(LocatorInfo(myVecRef[i].m_index, myVecRef[i].m_mySet, myVecRef[i].m_point)); } } } else { for (int ii = 0; ii < 2; ++ii) { for (int ij = 0; ij < 2; ++ij) { for (int ik = 0; ik < 2; ++ik) { float tempf = thisOct->m_children[ii][ij][ik]->distSquaredToPoint(target); if (tempf <= maxDist2) { myStack.push_back(thisOct->m_children[ii][ij][ik]); } } } } } } return ret; } bool CaretPointLocator::anyInRange(const float target[3], const float& maxDist) const { if (m_tree == NULL) return false; float curDist2 = m_tree->distSquaredToPoint(target), maxDist2 = maxDist * maxDist, tempf; if (curDist2 > maxDist2) return false; CaretSimpleMinHeap >*, float> myHeap;//closer octs are more likely to contain a close enough point myHeap.push(m_tree, curDist2); while (!myHeap.isEmpty()) { Oct >* thisOct = myHeap.pop(&curDist2); if (thisOct->m_leaf) { vector& myVecRef = *(thisOct->m_data.m_vector); int curSize = (int)myVecRef.size(); for (int i = 0; i < curSize; ++i) { tempf = MathFunctions::distanceSquared3D(myVecRef[i].m_point, target); if (tempf < maxDist2) { return true; } } } else { for (int ii = 0; ii < 2; ++ii) { for (int ij = 0; ij < 2; ++ij) { for (int ik = 0; ik < 2; ++ik) { tempf = thisOct->m_children[ii][ij][ik]->distSquaredToPoint(target); if (tempf <= maxDist2) { myHeap.push(thisOct->m_children[ii][ij][ik], tempf); } } } } } } return false; } int32_t CaretPointLocator::newIndex() { if (m_unusedIndexes.empty()) { return m_nextSetIndex++; } else { int32_t ret = m_unusedIndexes[m_unusedIndexes.size() - 1]; m_unusedIndexes.pop_back(); return ret; } } void CaretPointLocator::removePointSet(int32_t whichSet) { CaretMutexLocker locked(&m_modifyMutex); m_unusedIndexes.push_back(whichSet); removeSetHelper(m_tree, whichSet); } void CaretPointLocator::removeSetHelper(Oct >* thisOct, int32_t thisSet) { if (thisOct == NULL) return; if (thisOct->m_leaf) { vector& myVecRef = *(thisOct->m_data.m_vector); int curSize = (int)myVecRef.size(); bool match = false; for (int i = 0; i < curSize; ++i)//make sure something gets removed, so we don't have to do an allocation if it isn't needed { if (myVecRef[i].m_mySet == thisSet) { match = true; break; } } if (match) { vector tempvec; tempvec.reserve(curSize - 1);//because at least one is getting removed for (int i = 0; i < curSize; ++i) { if (myVecRef[i].m_mySet != thisSet) { tempvec.push_back(myVecRef[i]); } } myVecRef = tempvec; } } else { for (int ii = 0; ii < 2; ++ii) { for (int ij = 0; ij < 2; ++ij) { for (int ik = 0; ik < 2; ++ik) { removeSetHelper(thisOct->m_children[ii][ij][ik], thisSet); } } } } } connectome-workbench-1.4.2/src/Common/CaretPointLocator.h000066400000000000000000000103041360521144700234150ustar00rootroot00000000000000#ifndef __CARET_POINT_LOCATOR_H__ #define __CARET_POINT_LOCATOR_H__ #include "CaretAssertion.h" /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretMutex.h" #include "OctTree.h" #include "Vector3D.h" #include #include namespace caret { struct LocatorInfo { int64_t index; int32_t whichSet; Vector3D coords; LocatorInfo() { index = -1; whichSet = -1; } LocatorInfo(const int64_t& indexIn, const int32_t& whichSetIn, const Vector3D& coordsIn) : index(indexIn), whichSet(whichSetIn), coords(coordsIn) { } bool operator==(const LocatorInfo& rhs) const { return (index == rhs.index) && (whichSet == rhs.whichSet); }//ignore coords bool operator<(const LocatorInfo& rhs) const { if (whichSet == rhs.whichSet)//expect multi-set usage with pointsInRange to be rare, but still separate by whichSet if sorted { return index < rhs.index; } else { return whichSet < rhs.whichSet; } } }; class CaretPointLocator { struct Point { Vector3D m_point; int64_t m_index; int32_t m_mySet; Point(const float point[3], const int64_t index, const int32_t mySet) { m_point = point; m_index = index; m_mySet = mySet; } }; CaretMutex m_modifyMutex;//thread safety, don't let multiple threads modify the point sets at once Oct >* m_tree; int32_t m_nextSetIndex; std::vector m_unusedIndexes; void addPoint(Oct >* thisOct, const float point[3], const int64_t index, const int32_t pointSet); int32_t newIndex(); static const int NUM_POINTS_SPLIT = 100; void removeSetHelper(Oct >* thisOct, const int32_t thisSet); CaretPointLocator(); public: ///make an empty point locator with given bounding box (bounding box can expand later, but may be less efficient CaretPointLocator(const float minBounds[3], const float maxBounds[3]); ///make a point locator with the bounding box of this point set, and use this point set as set #0 CaretPointLocator(const float* coordsIn, const int64_t numCoords); ///convenience constructor for vectors CaretPointLocator(const std::vector coordsIn) : CaretPointLocator(coordsIn.data(), coordsIn.size() / 3) { } ///add a point set, SAVE THE RETURN VALUE because it is how you identify which point set found points belong to int32_t addPointSet(const float* coordsIn, const int64_t numCoords); int32_t addPointSet(const std::vector coordsIn) { return addPointSet(coordsIn.data(), coordsIn.size() / 3); } ///remove a point set by its set number void removePointSet(const int32_t whichSet); ///returns the index of the closest point, and optionally which point set and the coords int64_t closestPoint(const float target[3], LocatorInfo* infoOut = NULL) const; int64_t closestPointLimited(const float target[3], const float& maxDist, LocatorInfo* infoOut = NULL) const; std::vector pointsInRange(const float target[3], const float& maxDist) const; bool anyInRange(const float target[3], const float& maxDist) const; }; } #endif //__CARET_POINT_LOCATOR_H__ connectome-workbench-1.4.2/src/Common/CaretPointer.h000066400000000000000000000722011360521144700224240ustar00rootroot00000000000000#ifndef __CARET_POINTER_H__ #define __CARET_POINTER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretMutex.h" #include "CaretAssert.h" //NOTE: AFAIK, shared_ptr and raw pointers don't get along (can't pass to an old ownership-taking object without changing it to use shared_ptr) // so, these smart pointers have .releasePointer() which stops any smart pointer from deleting it (via an extra variable alongside the refcount) namespace caret { namespace _caret_pointer_impl {//namespace to hide things that shouldn't be used outside the header struct CaretPointerShare {//can't be member type because member types of templates on different types are incompatible int64_t m_refCount; bool m_doNotDelete; CaretPointerShare() { m_refCount = 1;//NOTE: don't initialize to 0, this way we don't have to change it every time we make one m_doNotDelete = false; } }; struct CaretPointerSyncShare {//same, but with mutex int64_t m_refCount; CaretMutex m_mutex;//protects m_refCount, m_doNotDelete bool m_doNotDelete; CaretPointerSyncShare() { m_refCount = 1; m_doNotDelete = false; } }; template class CaretPointerCommon {//provides only identical functionality between the four types - having a pointer member, and having ==, !=, a getPointer() method, and decay to pointer protected: T* m_pointer; CaretPointerCommon() { }//prevent standalone use, initialize with the share in derived classes public: template bool operator==(const T2* right) const { return m_pointer == right; } template bool operator!=(const T2* right) const { return !(*this == right); } template bool operator==(const CaretPointerCommon& right) const { return m_pointer == right.m_pointer; } template bool operator!=(const CaretPointerCommon& right) const { return !(*this == right); } operator T *const&() const { return m_pointer; }//never allow modifying the pointer, and also work when object is const template friend class CaretPointerCommon;//because for const compatibility, we need to access a different template's members }; template class CaretPointerBase : public CaretPointerCommon {//provides common functionality between just the 2 pointer types protected: using CaretPointerCommon::m_pointer; CaretPointerBase() { }//prevent standalone use public: T*& getPointer() { return m_pointer; } T *const& getPointer() const { return m_pointer; } T& operator*() const { CaretAssert(m_pointer != NULL); return *(m_pointer); } T *const& operator->() const { CaretAssert(m_pointer != NULL); return m_pointer; } }; template class CaretArrayBase : public CaretPointerCommon {//provides common functionality between just the 2 array types protected: using CaretPointerCommon::m_pointer; int64_t m_size; CaretArrayBase() { }//prevent standalone use, initialize size with share in derived classes public: T *const& getArray() const { return m_pointer; } template T& operator[](const I& index) { CaretAssert(m_pointer != NULL); CaretAssert(index >= 0 && (int64_t)index < m_size); return m_pointer[index]; } template const T& operator[](const I& index) const { CaretAssert(m_pointer != NULL); CaretAssert(index >= 0 && (int64_t)index < m_size); return m_pointer[index]; } const int64_t& size() const { return m_size; } }; } template class CaretPointerNonsync : public _caret_pointer_impl::CaretPointerBase { using _caret_pointer_impl::CaretPointerCommon::m_pointer; _caret_pointer_impl::CaretPointerShare* m_share; public: CaretPointerNonsync(); ~CaretPointerNonsync(); CaretPointerNonsync(const CaretPointerNonsync& right);//because a templated function apparently can't override default copy template CaretPointerNonsync(const CaretPointerNonsync& right); explicit CaretPointerNonsync(T* right); CaretPointerNonsync& operator=(const CaretPointerNonsync& right);//or default = template CaretPointerNonsync& operator=(const CaretPointerNonsync& right); void grabNew(T* right);//substitute for operator= to bare pointer int64_t getReferenceCount() const; ///breaks the hold on the pointer that is currently held by this, NO instances that are identical to this one will delete it (setting is per-pointer-capture-event, not per-object) T*const& releasePointer(); template friend class CaretPointerNonsync;//because for const compatibility, we need to access a different template's members }; template class CaretPointer : public _caret_pointer_impl::CaretPointerBase { using _caret_pointer_impl::CaretPointerCommon::m_pointer; _caret_pointer_impl::CaretPointerSyncShare* m_share; mutable CaretMutex m_mutex;//protects members from modification while reading, or from reading while modifying public: CaretPointer(); ~CaretPointer(); CaretPointer(const CaretPointer& right); template CaretPointer(const CaretPointer& right); explicit CaretPointer(T* right); CaretPointer& operator=(const CaretPointer& right); template CaretPointer& operator=(const CaretPointer& right); void grabNew(T* right); int64_t getReferenceCount() const; ///breaks the hold on the pointer that is currently held by this, NO instances that are identical to this one will delete it (setting is per-pointer-capture-event, not per-object) T*const& releasePointer(); template friend class CaretPointer; }; //separate array because delete and delete[] are different, and use indexing on one, and dereference/arrow on the other template class CaretArrayNonsync : public _caret_pointer_impl::CaretArrayBase { using _caret_pointer_impl::CaretPointerCommon::m_pointer; using _caret_pointer_impl::CaretArrayBase::m_size; _caret_pointer_impl::CaretPointerShare* m_share;//same share because it doesn't contain any specific information about what it is counting public: CaretArrayNonsync(); ~CaretArrayNonsync(); CaretArrayNonsync(const CaretArrayNonsync& right); template CaretArrayNonsync(const CaretArrayNonsync& right); CaretArrayNonsync(int64_t size);//for simpler construction CaretArrayNonsync(int64_t size, const T& initializer);//plus initialization CaretArrayNonsync& operator=(const CaretArrayNonsync& right); template CaretArrayNonsync& operator=(const CaretArrayNonsync& right); int64_t getReferenceCount() const; ///breaks the hold on the pointer that is currently held by this, NO instances will delete it (setting is per-pointer, not per-instance) T*const& releasePointer(); template friend class CaretArrayNonsync; }; template class CaretArray : public _caret_pointer_impl::CaretArrayBase { using _caret_pointer_impl::CaretPointerCommon::m_pointer; using _caret_pointer_impl::CaretArrayBase::m_size; _caret_pointer_impl::CaretPointerSyncShare* m_share;//same share because it doesn't contain any specific information about what it is counting mutable CaretMutex m_mutex;//protects members from modification while reading, or from reading while modifying public: CaretArray(); ~CaretArray(); CaretArray(const CaretArray& right); template CaretArray(const CaretArray& right); CaretArray(int64_t size);//for simpler construction CaretArray(int64_t size, const T& initializer);//plus initialization CaretArray& operator=(const CaretArray& right); template CaretArray& operator=(const CaretArray& right); int64_t getReferenceCount() const; ///breaks the hold on the pointer that is currently held by this, NO instances will delete it (setting is per-pointer, not per-instance) T*const& releasePointer(); template friend class CaretArray; }; //NOTE:begin pointer functions template CaretPointerNonsync::CaretPointerNonsync() { m_share = NULL; m_pointer = NULL; } template CaretPointerNonsync::CaretPointerNonsync(const CaretPointerNonsync& right) : _caret_pointer_impl::CaretPointerBase() { m_share = right.m_share; m_pointer = right.m_pointer; if (m_share != NULL) ++(m_share->m_refCount); } template template CaretPointerNonsync::CaretPointerNonsync(const CaretPointerNonsync& right) : _caret_pointer_impl::CaretPointerBase() { m_share = right.m_share; m_pointer = right.m_pointer; if (m_share != NULL) ++(m_share->m_refCount); } template CaretPointerNonsync::CaretPointerNonsync(T* right) { if (right == NULL) { m_share = NULL; m_pointer = NULL; } else { try { m_share = new _caret_pointer_impl::CaretPointerShare();//starts refcount at 1 } catch (...) {//don't leak the passed memory when exceptions happen delete right; throw; } m_pointer = right; } } template CaretPointerNonsync& CaretPointerNonsync::operator=(const CaretPointerNonsync& right) { if (this == &right) return *this;//short circuit self assignment CaretPointerNonsync temp(right);//copy construct from it, takes care type checking _caret_pointer_impl::CaretPointerShare* tempShare = temp.m_share;//swap the members T* tempPointer = temp.m_pointer; temp.m_share = m_share; temp.m_pointer = m_pointer; m_share = tempShare; m_pointer = tempPointer; return *this;//temp destructor takes care of the rest } template template CaretPointerNonsync& CaretPointerNonsync::operator=(const CaretPointerNonsync& right) {//self asignment won't hit this operator= CaretPointerNonsync temp(right);//copy construct from it, takes care of type checking _caret_pointer_impl::CaretPointerShare* tempShare = temp.m_share;//swap the members T* tempPointer = temp.m_pointer; temp.m_share = m_share; temp.m_pointer = m_pointer; m_share = tempShare; m_pointer = tempPointer; return *this;//temp destructor takes care of the rest } template void CaretPointerNonsync::grabNew(T* right) { if (right == NULL && m_pointer == NULL) return;//short circuit a case that doesn't need to do anything CaretPointerNonsync temp(right);//construct from the pointer _caret_pointer_impl::CaretPointerShare* tempShare = temp.m_share;//swap the members T* tempPointer = temp.m_pointer; temp.m_share = m_share; temp.m_pointer = m_pointer; m_share = tempShare; m_pointer = tempPointer;//destructor of temp takes care of the rest } template CaretPointerNonsync::~CaretPointerNonsync() { if (m_share == NULL) return; --(m_share->m_refCount); if (m_share->m_refCount == 0) { if (!m_share->m_doNotDelete) delete m_pointer; delete m_share; } } template int64_t CaretPointerNonsync::getReferenceCount() const { if (m_share == NULL) { return 0; } return m_share->m_refCount; } template T*const& CaretPointerNonsync::releasePointer() { if (m_share != NULL) { m_share->m_doNotDelete = true; } return m_pointer; } //NOTE:begin sync pointer functions template CaretPointer::CaretPointer() { m_share = NULL; m_pointer = NULL; } template CaretPointer::CaretPointer(const CaretPointer& right) : _caret_pointer_impl::CaretPointerBase() {//don't need to lock self during constructor CaretMutexLocker locked(&(right.m_mutex));//don't let right modify its share until our reference is counted if (right.m_share == NULL)//guarantees it won't be deleted, because right has a counted reference { m_share = NULL; m_pointer = NULL; } else { CaretMutexLocker locked2(&(right.m_share->m_mutex)); ++(right.m_share->m_refCount); m_share = right.m_share;//now our reference is counted and we have the share, we can unlock everything m_pointer = right.m_pointer; } } template template CaretPointer::CaretPointer(const CaretPointer& right) : _caret_pointer_impl::CaretPointerBase() {//don't need to lock self during constructor CaretMutexLocker locked(&(right.m_mutex));//don't let right modify its share until our reference is counted if (right.m_share == NULL)//guarantees it won't be deleted, because right has a counted reference { m_share = NULL; m_pointer = NULL; } else { CaretMutexLocker locked2(&(right.m_share->m_mutex)); ++(right.m_share->m_refCount); m_share = right.m_share;//now our reference is counted and we have the share, we can unlock everything m_pointer = right.m_pointer; } } template CaretPointer::CaretPointer(T* right) {//don't need to lock self during constructor if (right == NULL) { m_share = NULL; m_pointer = NULL; } else { try { m_share = new _caret_pointer_impl::CaretPointerSyncShare();//starts refcount at 1 } catch (...) { delete right; throw; } m_pointer = right; } } template CaretPointer& CaretPointer::operator=(const CaretPointer& right) { if (this == &right) return *this;//short circuit self assignment CaretPointer temp(right);//copy construct from it, takes care of locking and type checking _caret_pointer_impl::CaretPointerSyncShare* tempShare = temp.m_share;//prepare to swap the members T* tempPointer = temp.m_pointer; CaretMutexLocker locked(&m_mutex);//lock myself before using internal state temp.m_share = m_share; temp.m_pointer = m_pointer; m_share = tempShare; m_pointer = tempPointer; return *this;//temp destructor takes care of the rest } template template CaretPointer& CaretPointer::operator=(const CaretPointer& right) {//self asignment won't hit this operator= CaretPointer temp(right);//copy construct from it, takes care of locking and type checking _caret_pointer_impl::CaretPointerSyncShare* tempShare = temp.m_share;//prepare to swap the members T* tempPointer = temp.m_pointer; CaretMutexLocker locked(&m_mutex);//lock myself before using internal state temp.m_share = m_share; temp.m_pointer = m_pointer; m_share = tempShare; m_pointer = tempPointer; return *this;//temp destructor takes care of the rest } template void CaretPointer::grabNew(T* right) { if (right == NULL && m_pointer == NULL) return;//short circuit a case that doesn't need any mutexes CaretPointer temp(right);//construct from the pointer _caret_pointer_impl::CaretPointerSyncShare* tempShare = temp.m_share;//prepare to swap the members T* tempPointer = temp.m_pointer; CaretMutexLocker locked(&m_mutex);//lock myself before using internal state temp.m_share = m_share; temp.m_pointer = m_pointer; m_share = tempShare; m_pointer = tempPointer;//destructor of temp takes care of the rest } template CaretPointer::~CaretPointer() {//access during destructor is programmer error, don't lock self if (m_share == NULL) return; bool deleteShare = false; { CaretMutexLocker locked(&(m_share->m_mutex));//do lock the refcount, though --(m_share->m_refCount); if (m_share->m_refCount == 0) { deleteShare = true; if (!m_share->m_doNotDelete) delete m_pointer; } }//unlock refcount mutex before deleting the object that contains it, otherwise Very Bad Things if (deleteShare) { delete m_share; } } template int64_t CaretPointer::getReferenceCount() const { CaretMutexLocker locked(&m_mutex);//lock so that m_share can't be deleted in the middle if (m_share == NULL) { return 0; } return m_share->m_refCount; } template T*const& CaretPointer::releasePointer() { CaretMutexLocker locked(&m_mutex);//lock to keep m_share and m_pointer coherent until after return - must return the pointer that was released if (m_share != NULL) { m_share->m_doNotDelete = true; } return m_pointer; } //NOTE:begin array functions template CaretArrayNonsync::CaretArrayNonsync() { m_share = NULL; m_pointer = NULL; m_size = 0; } template CaretArrayNonsync::CaretArrayNonsync(const CaretArrayNonsync& right) : _caret_pointer_impl::CaretArrayBase() { m_share = right.m_share; m_pointer = right.m_pointer; m_size = right.m_size; if (m_share != NULL) ++(m_share->m_refCount); } template template CaretArrayNonsync::CaretArrayNonsync(const CaretArrayNonsync& right) : _caret_pointer_impl::CaretArrayBase() { m_share = right.m_share; m_pointer = right.m_pointer; m_size = right.m_size; if (m_share != NULL) ++(m_share->m_refCount); } template CaretArrayNonsync::CaretArrayNonsync(int64_t size) { if (size > 0) { m_share = new _caret_pointer_impl::CaretPointerShare(); try { m_pointer = new T[size]; } catch (...) {//don't leak share objects if we can't allocate the memory delete m_share; m_share = NULL;//also keep state consistent throw; } m_size = size; } else { m_share = NULL; m_pointer = NULL; m_size = 0; } } template CaretArrayNonsync::CaretArrayNonsync(int64_t size, const T& initializer) { if (size > 0) { m_share = new _caret_pointer_impl::CaretPointerShare(); try { m_pointer = new T[size]; } catch (...) { delete m_share; m_share = NULL; throw; } m_size = size; T* end = m_pointer + size, *iter = m_pointer; do { *iter = initializer;//somewhat optimized, since this code will probably get used many places ++iter; } while (iter != end); } else { m_share = NULL; m_pointer = NULL; m_size = 0; } } template CaretArrayNonsync& CaretArrayNonsync::operator=(const CaretArrayNonsync& right) { CaretArrayNonsync temp(right); _caret_pointer_impl::CaretPointerShare* tempShare = temp.m_share;//swap the shares and fill members T* tempPointer = temp.m_pointer; int64_t tempSize = temp.m_size; temp.m_share = m_share; temp.m_pointer = m_pointer; temp.m_size = m_size; m_share = tempShare; m_pointer = tempPointer; m_size = tempSize; return *this;//destructor of temp cleans up } template template CaretArrayNonsync& CaretArrayNonsync::operator=(const CaretArrayNonsync& right) { CaretArrayNonsync temp(right); _caret_pointer_impl::CaretPointerShare* tempShare = temp.m_share;//swap the shares and fill members T* tempPointer = temp.m_pointer; int64_t tempSize = temp.m_size; temp.m_share = m_share; temp.m_pointer = m_pointer; temp.m_size = m_size; m_share = tempShare; m_pointer = tempPointer; m_size = tempSize; return *this;//destructor of temp cleans up } template CaretArrayNonsync::~CaretArrayNonsync() { if (m_share == NULL) return; --(m_share->m_refCount); if (m_share->m_refCount == 0) { if (!m_share->m_doNotDelete) delete[] m_pointer; delete m_share; } } template int64_t CaretArrayNonsync::getReferenceCount() const { if (m_share == NULL) { return 0; } return m_share->m_refCount; } template T*const& CaretArrayNonsync::releasePointer() { if (m_share != NULL) { m_share->m_doNotDelete = true; } return m_pointer; } //NOTE:begin sync array functions template CaretArray::CaretArray() { m_share = NULL; m_pointer = NULL; m_size = 0; } template CaretArray::CaretArray(const CaretArray& right) : _caret_pointer_impl::CaretArrayBase() {//don't need to lock self during constructor CaretMutexLocker locked(&(right.m_mutex));//don't let right modify its share until our reference is counted if (right.m_share == NULL)//guarantees it won't be deleted, because right has a counted reference { m_share = NULL; m_pointer = NULL; m_size = 0; } else { CaretMutexLocker locked2(&(right.m_share->m_mutex)); ++(right.m_share->m_refCount); m_share = right.m_share;//now our reference is counted and we have the share, we can unlock everything m_pointer = right.m_pointer; m_size = right.m_size; } } template template CaretArray::CaretArray(const CaretArray& right) : _caret_pointer_impl::CaretArrayBase() {//don't need to lock self during constructor CaretMutexLocker locked(&(right.m_mutex));//don't let right modify its share until our reference is counted if (right.m_share == NULL)//guarantees it won't be deleted, because right has a counted reference { m_share = NULL; m_pointer = NULL; m_size = 0; } else { CaretMutexLocker locked2(&(right.m_share->m_mutex)); ++(right.m_share->m_refCount); m_share = right.m_share;//now our reference is counted and we have the share, we can unlock everything this->m_pointer = right.m_pointer; m_size = right.m_size; } } template CaretArray::CaretArray(int64_t size) { if (size > 0) { m_share = new _caret_pointer_impl::CaretPointerSyncShare(); try { m_pointer = new T[size]; } catch (...) { delete m_share; m_share = NULL; throw; } m_size = size; } else { m_share = NULL; m_pointer = NULL; m_size = 0; } } template CaretArray::CaretArray(int64_t size, const T& initializer) { if (size > 0) { m_share = new _caret_pointer_impl::CaretPointerSyncShare(); try { m_pointer = new T[size]; } catch (...) { delete m_share; m_share = NULL; throw; } m_size = size; T* end = m_pointer + size, *iter = m_pointer; do { *iter = initializer;//somewhat optimized, since this code will probably get used many places ++iter; } while (iter != end); } else { m_share = NULL; m_pointer = NULL; m_size = 0; } } template CaretArray& CaretArray::operator=(const CaretArray& right) { CaretArray temp(right);//copy construct from it, takes care of locking _caret_pointer_impl::CaretPointerSyncShare* tempShare = temp.m_share;//prepare to swap the shares and fill members T* tempPointer = temp.m_pointer; int64_t tempSize = temp.m_size; CaretMutexLocker locked(&m_mutex);//lock myself before using internal state temp.m_share = m_share; temp.m_pointer = m_pointer; temp.m_size = m_size; m_share = tempShare; m_pointer = tempPointer; m_size = tempSize; return *this;//destructor of temp cleans up } template template CaretArray& CaretArray::operator=(const CaretArray& right) { CaretArray temp(right);//copy construct from it, takes care of locking _caret_pointer_impl::CaretPointerSyncShare* tempShare = temp.m_share;//prepare to swap the shares and fill members T* tempPointer = temp.m_pointer; int64_t tempSize = temp.m_size; CaretMutexLocker locked(&m_mutex);//lock myself before using internal state temp.m_share = m_share; temp.m_pointer = m_pointer; temp.m_size = m_size; m_share = tempShare; m_pointer = tempPointer; m_size = tempSize; return *this;//destructor of temp cleans up } template CaretArray::~CaretArray() {//access during destructor is programmer error, don't lock self if (m_share == NULL) return; bool deleteShare = false; { CaretMutexLocker locked(&(m_share->m_mutex));//do lock the refcount, though --(m_share->m_refCount); if (m_share->m_refCount == 0) { deleteShare = true; if (!m_share->m_doNotDelete) delete[] m_pointer; } }//left refcount unlock before deleting the object that contains it if (deleteShare) { delete m_share; } } template int64_t CaretArray::getReferenceCount() const { CaretMutexLocker locked(&m_mutex);//lock to keep m_share from being deleted if (m_share == NULL) { return 0; } return m_share->m_refCount; } template T*const& CaretArray::releasePointer() { CaretMutexLocker locked(&m_mutex);//lock because m_pointer and m_share need to remain coherent if (m_share != NULL) { m_share->m_doNotDelete = true; } return m_pointer; } } #endif //__CARET_POINTER_H__ connectome-workbench-1.4.2/src/Common/CaretPreferenceDataValue.cxx000066400000000000000000000122341360521144700252240ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CARET_PREFERENCE_DATA_VALUE_DECLARE__ #include "CaretPreferenceDataValue.h" #undef __CARET_PREFERENCE_DATA_VALUE_DECLARE__ #include #include "CaretAssert.h" using namespace caret; /** * \class caret::CaretPreferenceDataValue * \brief Maintains a single caret preference data valud * \ingroup Common */ /** * Constructor. * * @param preferenceSettings * QSettings from caret preferences * @param preferenceName * Name of the preference * @param dataType * Data type of the preference * @param savedInScene * Indicates if item is saved to scene and may override the preference when scene restored. * @param defaultValue * Default value for the preference */ CaretPreferenceDataValue::CaretPreferenceDataValue(QSettings* preferenceSettings, const QString& preferenceName, const DataType dataType, const SavedInScene savedInScene, const QVariant defaultValue) : CaretObject(), m_preferenceSettings(preferenceSettings), m_preferenceName(preferenceName), m_dataType(dataType), m_savedInScene(savedInScene) { CaretAssert(m_preferenceSettings); CaretAssert( ! m_preferenceName.isEmpty()); CaretAssert( ! defaultValue.isNull()); m_dataValue = m_preferenceSettings->value(m_preferenceName, defaultValue); m_sceneDataValue = m_dataValue; } /** * Destructor. */ CaretPreferenceDataValue::~CaretPreferenceDataValue() { } /** * @return Name of preference */ QString CaretPreferenceDataValue::getName() const { return m_preferenceName; } /** * @return The data type */ CaretPreferenceDataValue::DataType CaretPreferenceDataValue::getDataType() const { return m_dataType; } /** * @return The data value. Some preferences may be overridden by * a scene value. If the scene value is valid, it is returned, * otherwise, the preference value is returned. * * @seealso getPreferenceValue() * * @param valueType * Type of value returned (active/preference/scene) */ QVariant CaretPreferenceDataValue::getValue(/*const ValueType valueType*/) const { QVariant valueOut; if (m_sceneDataValueValid) { valueOut = m_sceneDataValue; } else { valueOut = m_dataValue; } return valueOut; } /** * @return Always returns the preferences value. */ QVariant CaretPreferenceDataValue::getPreferenceValue() const { return m_dataValue; } /** * Set the value. This does invalidate the scene value. * * @param value * New value */ void CaretPreferenceDataValue::setValue(const QVariant& value) { /* * Setting value invalidates scene value */ m_sceneDataValueValid = false; if (value != m_dataValue) { m_dataValue = value; m_preferenceSettings->setValue(m_preferenceName, m_dataValue); m_preferenceSettings->sync(); } } /** * Set the scene value. Also sets the scene value valid. * * @param value * Value of parameter from the scene. */ void CaretPreferenceDataValue::setSceneValue(const QVariant& value) { m_sceneDataValue = value; m_sceneDataValueValid = true; switch (m_savedInScene) { case SavedInScene::SAVE_NO: /* do not allow scene value */ m_sceneDataValueValid = false; break; case SavedInScene::SAVE_YES: break; } } /** * Set the validity of the scene value. * * @param validStats * New validity status of the scene value */ void CaretPreferenceDataValue::setSceneValueValid(const bool validStatus) { m_sceneDataValueValid = validStatus; switch (m_savedInScene) { case SavedInScene::SAVE_NO: /* do not allow scene value */ m_sceneDataValueValid = false; break; case SavedInScene::SAVE_YES: break; } } /** * @return True if preferences is saved to scenes */ bool CaretPreferenceDataValue::isSavedToScenes() const { bool savedFlag(false); switch (m_savedInScene) { case SavedInScene::SAVE_NO: break; case SavedInScene::SAVE_YES: savedFlag = true; break; } return savedFlag; } connectome-workbench-1.4.2/src/Common/CaretPreferenceDataValue.h000066400000000000000000000056011360521144700246510ustar00rootroot00000000000000#ifndef __CARET_PREFERENCE_DATA_VALUE_H__ #define __CARET_PREFERENCE_DATA_VALUE_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretObject.h" class QSettings; namespace caret { class CaretPreferences; class CaretPreferenceDataValue : public CaretObject { public: enum class DataType { FLOAT, INTEGER, STRING }; enum class SavedInScene { SAVE_NO, SAVE_YES }; CaretPreferenceDataValue(QSettings* preferenceSettings, const QString& preferenceName, const DataType dataType, const SavedInScene savedInScene, const QVariant defaultValue); virtual ~CaretPreferenceDataValue(); CaretPreferenceDataValue(const CaretPreferenceDataValue&) = delete; CaretPreferenceDataValue& operator=(const CaretPreferenceDataValue&) = delete; QString getName() const; DataType getDataType() const; QVariant getPreferenceValue() const; QVariant getValue(/*const ValueType valueType*/) const; void setValue(const QVariant& value); void setSceneValue(const QVariant& value); void setSceneValueValid(const bool validStatus); bool isSavedToScenes() const; // ADD_NEW_METHODS_HERE private: QSettings* m_preferenceSettings; const QString m_preferenceName; const DataType m_dataType; const SavedInScene m_savedInScene; QVariant m_dataValue; QVariant m_sceneDataValue; bool m_sceneDataValueValid = false; // ADD_NEW_MEMBERS_HERE }; #ifdef __CARET_PREFERENCE_DATA_VALUE_DECLARE__ // #endif // __CARET_PREFERENCE_DATA_VALUE_DECLARE__ } // namespace #endif //__CARET_PREFERENCE_DATA_VALUE_H__ connectome-workbench-1.4.2/src/Common/CaretPreferences.cxx000066400000000000000000001547131360521144700236310ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CARET_PREFERENCES_DECLARE__ #include "CaretPreferences.h" #undef __CARET_PREFERENCES_DECLARE__ #include #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPreferenceDataValue.h" #include "ModelTransform.h" #include "TileTabsConfiguration.h" #include "WuQMacroGroup.h" using namespace caret; /** * \class caret::CaretPreferences * \brief Preferences for use in Caret. * * Maintains preferences for use in Caret. The * preferences are read only one time, when an * instance is created. If a preference is changed, * it is written. */ /** * Constructor. */ CaretPreferences::CaretPreferences() : CaretObject() { m_macros.reset(new WuQMacroGroup("Preferences")); this->qSettings = new QSettings("brainvis.wustl.edu", "Caret7"); this->readPreferences(); m_volumeCrossHairGapPreference.reset(new CaretPreferenceDataValue(this->qSettings, "volumeAxesCrosshairGap", CaretPreferenceDataValue::DataType::FLOAT, CaretPreferenceDataValue::SavedInScene::SAVE_YES, 0.0)); m_preferenceDataValues.push_back(m_volumeCrossHairGapPreference.get()); const QString defAllSliceLayout = VolumeSliceViewAllPlanesLayoutEnum::toName(VolumeSliceViewAllPlanesLayoutEnum::ROW_LAYOUT); m_volumeAllSlicePlanesLayout.reset(new CaretPreferenceDataValue(this->qSettings, "volumeAllSlicePlanesLayout", CaretPreferenceDataValue::DataType::STRING, CaretPreferenceDataValue::SavedInScene::SAVE_NO, defAllSliceLayout)); m_preferenceDataValues.push_back(m_volumeAllSlicePlanesLayout.get()); m_colorsMode = BackgroundAndForegroundColorsModeEnum::USER_PREFERENCES; } /** * Destructor. */ CaretPreferences::~CaretPreferences() { /** * Note DO NOT delete items in this vector as they are pointers to items * in unique_ptr's */ m_preferenceDataValues.clear(); this->removeAllCustomViews(); this->removeAllTileTabsConfigurations(); delete this->qSettings; } /** * Some preferences are temporarily overriden with a value from a scene * and these 'scene overrides' are invalidated by this method */ void CaretPreferences::invalidateSceneDataValues() { for (auto pdv : m_preferenceDataValues) { pdv->setSceneValueValid(false); } } /** * @return The scene data value for items that are saved to * and restored from scenes. Primarily for use by SessionManager. */ std::vector CaretPreferences::getPreferenceSceneDataValues() { return m_preferenceDataValues; } /** * Get the boolean value for the given preference name. * @param name * Name of the preference. * @param defaultValue * Value returned in the preference with the given name was not found. * @return * Boolean value of preference or defaultValue if the * named preference is not found. */ bool CaretPreferences::getBoolean(const AString& name, const bool defaultValue) { bool b = this->qSettings->value(name, defaultValue).toBool(); return b; } /** * Set the given preference name with the boolean value. * @param * Name of the preference. * @param * New value for preference. */ void CaretPreferences::setBoolean(const AString& name, const bool value) { this->qSettings->setValue(name, value); } /** * Get the boolean value for the given preference name. * @param name * Name of the preference. * @param defaultValue * Value returned in the preference with the given name was not found. * @return * Integer value of preference or defaultValue if the * named preference is not found. */ int CaretPreferences::getInteger(const AString& name, const int defaultValue) { int b = this->qSettings->value(name, defaultValue).toInt(); return b; } /** * Set the given preference name with the integer value. * @param * Name of the preference. * @param * New value for preference. */ void CaretPreferences::setInteger(const AString& name, const int value) { this->qSettings->setValue(name, value); } /** * Get the string value for the given preference name. * @param name * Name of the preference. * @param defaultValue * Value returned in the preference with the given name was not found. * @return * String value of preference or defaultValue if the * named preference is not found. */ AString CaretPreferences::getString(const AString& name, const AString& defaultValue) { AString s = this->qSettings->value(name, defaultValue).toString(); return s; } /** * Set the given preference name with the string value. * @param * Name of the preference. * @param * New value for preference. */ void CaretPreferences::setString(const AString& name, const AString& value) { this->qSettings->setValue(name, value); } /** * Remove all custom views. */ void CaretPreferences::removeAllCustomViews() { for (std::vector::iterator iter = this->customViews.begin(); iter != this->customViews.end(); iter++) { delete *iter; } this->customViews.clear(); } /** * @return Names of custom views sorted by name. May want to precede this * method with a call to 'readCustomViews(true)' so that the custom views * are the latest from the settings. */ std::vector CaretPreferences::getCustomViewNames() const { std::vector names; for (std::vector::const_iterator iter = this->customViews.begin(); iter != this->customViews.end(); iter++) { const ModelTransform* mt = *iter; names.push_back(mt->getName()); } std::sort(names.begin(), names.end()); return names; } /** * @return Names and comments of custom views sorted by name. May want to precede this * method with a call to 'readCustomViews(true)' so that the custom views * are the latest from the settings. */ std::vector > CaretPreferences::getCustomViewNamesAndComments() const { std::vector customViewNames = getCustomViewNames(); std::vector > namesAndComments; for (std::vector::const_iterator iter = customViewNames.begin(); iter != customViewNames.end(); iter++) { const AString name = *iter; ModelTransform modelTransform; if (getCustomView(name, modelTransform)) { const AString comment = modelTransform.getComment(); namesAndComments.push_back(std::make_pair(name, comment)); } } return namesAndComments; } /** * Get a custom view with the given name. * * @param customViewName * Name of requested custom view. * @param modelTransformOut * Custom view will be loaded into this model transform. * @return true if a custom view with the name exists. If no * custom view exists with the name, false is returned and * the model transform will be the identity transform. */ bool CaretPreferences::getCustomView(const AString& customViewName, ModelTransform& modelTransformOut) const { for (std::vector::const_iterator iter = this->customViews.begin(); iter != this->customViews.end(); iter++) { const ModelTransform* mt = *iter; if (customViewName == mt->getName()) { modelTransformOut = *mt; return true; } } modelTransformOut.setToIdentity(); return false; } /** * Add or update a custom view. If a custom view exists with the name * in the given model transform it is replaced. * * @param modelTransform * Custom view's model transform. */ void CaretPreferences::addOrReplaceCustomView(const ModelTransform& modelTransform) { bool addNewCustomView = true; for (std::vector::iterator iter = this->customViews.begin(); iter != this->customViews.end(); iter++) { ModelTransform* mt = *iter; if (mt->getName() == modelTransform.getName()) { *mt = modelTransform; addNewCustomView = false; break; } } if (addNewCustomView) { this->customViews.push_back(new ModelTransform(modelTransform)); } this->writeCustomViews(); } /** * Remove the custom view with the given name. * * @param customViewName * Name of custom view. */ void CaretPreferences::removeCustomView(const AString& customViewName) { for (std::vector::iterator iter = this->customViews.begin(); iter != this->customViews.end(); iter++) { ModelTransform* mt = *iter; if (mt->getName() == customViewName) { this->customViews.erase(iter); delete mt; break; } } this->writeCustomViews(); } /** * Write the custom views. */ void CaretPreferences::writeCustomViews() { /* * Remove "userViews" that were replaced by customView */ this->qSettings->remove("userViews"); this->qSettings->beginWriteArray(NAME_CUSTOM_VIEWS); const int32_t numViews = static_cast(this->customViews.size()); for (int32_t i = 0; i < numViews; i++) { this->qSettings->setArrayIndex(i); this->qSettings->setValue(AString::number(i), this->customViews[i]->getAsString()); } this->qSettings->endArray(); this->qSettings->sync(); } /** * Read macros from preferences * * @param performSync * If true, synchronize preferences before reading macros */ void CaretPreferences::readMacros(const bool performSync) { if (performSync) { this->qSettings->sync(); } const QString macrosXmlString = this->getString(NAME_MACROS); if (macrosXmlString.isEmpty()) { m_macros->clear(); } else { QString errorMessage; QString warningMessage; if ( ! m_macros->readXmlFromStringOld(macrosXmlString, errorMessage, warningMessage)) { CaretLogSevere("Reading macros from preferences: " + errorMessage); } else if ( ! warningMessage.isEmpty()) { CaretLogWarning(warningMessage); } } } /** * Write macros to preferences */ void CaretPreferences::writeMacros() { if ( ! m_macros->isModified()) { return; } QString macrosXmlString; if (m_macros->getNumberOfMacros() > 0) { QString errorMessage; if ( ! m_macros->writeXmlToString(macrosXmlString, errorMessage)) { CaretLogSevere("Writing macros to preferences: " + errorMessage); } } this->setString(NAME_MACROS, macrosXmlString); this->qSettings->sync(); } /** * Remove all of the tile tabs configurations. */ void CaretPreferences::removeAllTileTabsConfigurations() { for (std::vector::iterator iter = this->tileTabsConfigurations.begin(); iter != this->tileTabsConfigurations.end(); iter++) { delete *iter; } this->tileTabsConfigurations.clear(); } /** * Write the tile tabs configurations. */ void CaretPreferences::writeTileTabsConfigurations() { this->qSettings->beginWriteArray(NAME_TILE_TABS_CONFIGURATIONS); const int32_t numViews = static_cast(this->tileTabsConfigurations.size()); for (int32_t i = 0; i < numViews; i++) { this->qSettings->setArrayIndex(i); this->qSettings->setValue(AString::number(i), this->tileTabsConfigurations[i]->encodeInXML()); } this->qSettings->endArray(); this->qSettings->sync(); } /** * Read the tile tabs configuration. Since user's may want to use them * in multiple instance of workbench that are running, this method allows * the tile tab configurations to be read without affecting other preferences. * * @param performSync * Sync with preferences since preferences may have been changed * by a concurrently running workbench. */ void CaretPreferences::readTileTabsConfigurations(const bool performSync) { if (performSync) { this->qSettings->sync(); } this->removeAllTileTabsConfigurations(); /* * Read Configurations */ const int numConfigurations = this->qSettings->beginReadArray(NAME_TILE_TABS_CONFIGURATIONS); for (int i = 0; i < numConfigurations; i++) { this->qSettings->setArrayIndex(i); const AString configString = this->qSettings->value(AString::number(i)).toString(); TileTabsConfiguration* ttc = new TileTabsConfiguration(); AString errorMessage; if (ttc->decodeFromXML(configString, errorMessage)) { this->tileTabsConfigurations.push_back(ttc); } else { CaretLogWarning(errorMessage); delete ttc; } } this->qSettings->endArray(); } /** * @return The Tile tabs configurations sorted by name. */ std::vector CaretPreferences::getTileTabsConfigurationsSortedByName() const { /* * Copy the configurations and sort them by name. */ std::vector configurations; configurations.insert(configurations.end(), this->tileTabsConfigurations.begin(), this->tileTabsConfigurations.end()); std::sort(configurations.begin(), configurations.end(), TileTabsConfiguration::lessThanComparisonByName); return configurations; } /** * Get the tile tabs configuration with the given unique identifier. * * @param uniqueIdentifier * Unique identifier of the requested tile tabs configuration. * @return * Pointer to tile tabs configuration with the given unique identifier * or NULL is it does not exist. */ TileTabsConfiguration* CaretPreferences::getTileTabsConfigurationByUniqueIdentifier(const AString& uniqueIdentifier) { for (std::vector::const_iterator iter = this->tileTabsConfigurations.begin(); iter != this->tileTabsConfigurations.end(); iter++) { TileTabsConfiguration* ttc = *iter; if (ttc->getUniqueIdentifier() == uniqueIdentifier) { return ttc; } } return NULL; } /** * Get the tile tabs configuration with the given unique identifier. * * @param uniqueIdentifier * Unique identifier of the requested tile tabs configuration. * @return * Pointer to tile tabs configuration with the given unique identifier * or NULL is it does not exist. */ const TileTabsConfiguration* CaretPreferences::getTileTabsConfigurationByUniqueIdentifier(const AString& uniqueIdentifier) const { for (std::vector::const_iterator iter = this->tileTabsConfigurations.begin(); iter != this->tileTabsConfigurations.end(); iter++) { const TileTabsConfiguration* ttc = *iter; if (ttc->getUniqueIdentifier() == uniqueIdentifier) { return ttc; } } return NULL; } /** * Get the tile tabs configuration with the given name. * * @param name * Name of the requested tile tabs configuration. * @return * Pointer to tile tabs configuration with the given name * or NULL is it does not exist. */ TileTabsConfiguration* CaretPreferences::getTileTabsConfigurationByName(const AString& name) const { for (std::vector::const_iterator iter = this->tileTabsConfigurations.begin(); iter != this->tileTabsConfigurations.end(); iter++) { TileTabsConfiguration* ttc = *iter; if (name == ttc->getName()) { return ttc; } } return NULL; } /** * Add a new tile tabs configuration. * * @param tileTabsConfiguration * New tile tabs configuration that is added. */ void CaretPreferences::addTileTabsConfiguration(TileTabsConfiguration* tileTabsConfiguration) { this->tileTabsConfigurations.push_back(tileTabsConfiguration); this->writeTileTabsConfigurations(); } /** * Remove the tile tabs configuration with the given name. * * @param tileTabsUniqueIdentifier * Unique identifier of configuration that will be removed. */ void CaretPreferences::removeTileTabsConfigurationByUniqueIdentifier(const AString& tileTabsUniqueIdentifier) { for (std::vector::iterator iter = this->tileTabsConfigurations.begin(); iter != this->tileTabsConfigurations.end(); iter++) { TileTabsConfiguration* ttc = *iter; if (ttc->getUniqueIdentifier() == tileTabsUniqueIdentifier) { this->tileTabsConfigurations.erase(iter); delete ttc; break; } } this->writeTileTabsConfigurations(); } /** * @return Pointer to the background and foreground colors for * use when drawing graphics. The colors returned may be * either the user's preferences or the from the currently * loaded scene. */ const BackgroundAndForegroundColors* CaretPreferences::getBackgroundAndForegroundColors() const { switch (m_colorsMode) { case BackgroundAndForegroundColorsModeEnum::SCENE: return &this->sceneColors; break; case BackgroundAndForegroundColorsModeEnum::USER_PREFERENCES: return &this->userColors; break; } CaretAssert(0); return &this->userColors; } /** * @return The USER'S preferred background and foreground colors. * This method is used only by the PreferencesDialog to * update the user's preferred colors. */ BackgroundAndForegroundColors CaretPreferences::getUserBackgroundAndForegroundColors() { return this->userColors; } /** * Set the USER'S preferred background and foreground colors. * This method is used only by the PreferencesDialog to * update the user's preferred colors. */ void CaretPreferences::setUserBackgroundAndForegroundColors(const BackgroundAndForegroundColors& colors) { if (this->userColors == colors) { return; } /* * "in memory" colors */ this->userColors = colors; /* * Update preferences file with colors */ writeUnsignedByteArray(NAME_COLOR_BACKGROUND_WINDOW, this->userColors.m_colorBackgroundWindow, 3); writeUnsignedByteArray(NAME_COLOR_FOREGROUND_ALL, this->userColors.m_colorForegroundAll, 3); writeUnsignedByteArray(NAME_COLOR_BACKGROUND_ALL, this->userColors.m_colorBackgroundAll, 3); writeUnsignedByteArray(NAME_COLOR_FOREGROUND_CHART, this->userColors.m_colorForegroundChart, 3); writeUnsignedByteArray(NAME_COLOR_BACKGROUND_CHART, this->userColors.m_colorBackgroundChart, 3); writeUnsignedByteArray(NAME_COLOR_FOREGROUND_SURFACE, this->userColors.m_colorForegroundSurface, 3); writeUnsignedByteArray(NAME_COLOR_BACKGROUND_SURFACE, this->userColors.m_colorBackgroundSurface, 3); writeUnsignedByteArray(NAME_COLOR_FOREGROUND_VOLUME, this->userColors.m_colorForegroundVolume, 3); writeUnsignedByteArray(NAME_COLOR_BACKGROUND_VOLUME, this->userColors.m_colorBackgroundVolume, 3); writeUnsignedByteArray(NAME_COLOR_CHART_MATRIX_GRID_LINES, this->userColors.m_colorChartMatrixGridLines, 3); writeUnsignedByteArray(NAME_COLOR_CHART_HISTOGRAM_THRESHOLD, this->userColors.m_colorChartHistogramThreshold, 3); } /** * Set the SCENE background and foreground colors. * This method is called when scenes are restored. */ void CaretPreferences::setSceneBackgroundAndForegroundColors(const BackgroundAndForegroundColors& colors) { this->sceneColors = colors; } /** * @return Mode for background and foreground colors. */ BackgroundAndForegroundColorsModeEnum::Enum CaretPreferences::getBackgroundAndForegroundColorsMode() const { return m_colorsMode; } /** * Set the mode for background and foreground colors. * NOTE: This is a transient value and NOT saved to preferences. * * @param colorsMode * New colors mode. */ void CaretPreferences::setBackgroundAndForegroundColorsMode(const BackgroundAndForegroundColorsModeEnum::Enum colorsMode) { m_colorsMode = colorsMode; } /** * Get the previous spec files. * * @param previousSpecFiles * Will contain previous spec files. */ void CaretPreferences::getPreviousSpecFiles(std::vector& previousSpecFiles) const { previousSpecFiles = this->previousSpecFiles; } /** * Add to the previous spec files. * * @param specFileName * Spec file added to the previous spec files. */ void CaretPreferences::addToPreviousSpecFiles(const AString& specFileName) { if (specFileName.isEmpty() == false) { this->addToPrevious(this->previousSpecFiles, specFileName); } const int32_t num = static_cast(this->previousSpecFiles.size()); this->qSettings->beginWriteArray(NAME_PREVIOUS_SPEC_FILES); for (int i = 0; i < num; i++) { this->qSettings->setArrayIndex(i); this->qSettings->setValue(AString::number(i), this->previousSpecFiles[i]); } this->qSettings->endArray(); this->qSettings->sync(); } /** * Clear the previous spec files. */ void CaretPreferences::clearPreviousSpecFiles() { this->previousSpecFiles.clear(); this->addToPreviousSpecFiles(""); } /** * Get the previous scene files. * * @param previousSceneFiles * Will contain previous scene files. */ void CaretPreferences::getPreviousSceneFiles(std::vector& previousSceneFiles) const { previousSceneFiles = this->previousSceneFiles; } /** * Add to the previous scene files. * * @param sceneFileName * Scene file added to the previous scene files. */ void CaretPreferences::addToPreviousSceneFiles(const AString& sceneFileName) { if (sceneFileName.isEmpty() == false) { this->addToPrevious(this->previousSceneFiles, sceneFileName); } const int32_t num = static_cast(this->previousSceneFiles.size()); this->qSettings->beginWriteArray(NAME_PREVIOUS_SCENE_FILES); for (int i = 0; i < num; i++) { this->qSettings->setArrayIndex(i); this->qSettings->setValue(AString::number(i), this->previousSceneFiles[i]); } this->qSettings->endArray(); this->qSettings->sync(); } /** * Clear the previous scene files. */ void CaretPreferences::clearPreviousSceneFiles() { this->previousSceneFiles.clear(); this->addToPreviousSceneFiles(""); } /** * Get the directories that were used in the Open File Dialog. * * @param previousOpenFileDirectories * Will contain previous directories. */ void CaretPreferences::getPreviousOpenFileDirectories(std::vector& previousOpenFileDirectories) const { previousOpenFileDirectories = this->previousOpenFileDirectories; } /** * Get the directories that were used in the Open File Dialog. * * @param previousOpenFileDirectories * Will contain previous directories. */ void CaretPreferences::getPreviousOpenFileDirectories(QStringList& previousOpenFileDirectoriesList) const { previousOpenFileDirectoriesList.clear(); const int32_t numDirectories = static_cast(this->previousOpenFileDirectories.size()); for (int32_t i = 0; i < numDirectories; i++) { previousOpenFileDirectoriesList.append(this->previousOpenFileDirectories[i]); } } /** * Add to the previous directories that were used in the Open File Dialog. * * @param directoryName * Directory added to the previous directories from Open File Dialog. */ void CaretPreferences::addToPreviousOpenFileDirectories(const AString& directoryName) { this->addToPrevious(this->previousOpenFileDirectories, directoryName); const int32_t num = static_cast(this->previousOpenFileDirectories.size()); this->qSettings->beginWriteArray(NAME_PREVIOUS_OPEN_FILE_DIRECTORIES); for (int i = 0; i < num; i++) { this->qSettings->setArrayIndex(i); this->qSettings->setValue(AString::number(i), this->previousOpenFileDirectories[i]); } this->qSettings->endArray(); this->qSettings->sync(); } /** * Add to a list of previous, removing any matching entries * and limiting the size of the list. * * @param previousDeque * Deque containing the previous elements. * @param newName * Name that is added at the front. */ void CaretPreferences::addToPrevious(std::vector& previousVector, const AString& newName) { /* * Note: remove moves duplicate elements to after 'pos' but * does not change the size of the container so use erase * to remove the duplicate elements from the container. */ std::vector::iterator pos = std::remove(previousVector.begin(), previousVector.end(), newName); previousVector.erase(pos, previousVector.end()); const uint64_t MAX_ELEMENTS = 10; if (previousVector.size() > MAX_ELEMENTS) { previousVector.erase(previousVector.begin() + MAX_ELEMENTS, previousVector.end()); } previousVector.insert(previousVector.begin(), newName); } /** * @return The logging level. */ LogLevelEnum::Enum CaretPreferences::getLoggingLevel() const { return this->loggingLevel; } /** * Set the logging level. * Will also update the level in the Caret Logger. * @param loggingLevel * New value for logging level. */ void CaretPreferences::setLoggingLevel(const LogLevelEnum::Enum loggingLevel) { if (this->loggingLevel == loggingLevel) { return; } this->loggingLevel = loggingLevel; const AString name = LogLevelEnum::toName(this->loggingLevel); this->qSettings->setValue(NAME_LOGGING_LEVEL, name); this->qSettings->sync(); CaretLogger::getLogger()->setLevel(loggingLevel); } /** * @return The OpenGL Drawing method. */ OpenGLDrawingMethodEnum::Enum CaretPreferences::getOpenDrawingMethod() const { OpenGLDrawingMethodEnum::Enum drawMethod = this->openGLDrawingMethod; /* * Disable vertex buffers for now */ drawMethod = OpenGLDrawingMethodEnum::DRAW_WITH_VERTEX_BUFFERS_OFF; return drawMethod; } /** * Set the OpenGL Drawing method. * * @param openGLDrawingMethod * New value for OpenGL Drawing method. */ void CaretPreferences::setOpenGLDrawingMethod(const OpenGLDrawingMethodEnum::Enum openGLDrawingMethod) { if (this->openGLDrawingMethod == openGLDrawingMethod) { return; } this->openGLDrawingMethod = openGLDrawingMethod; this->setString(NAME_OPENGL_DRAWING_METHOD, OpenGLDrawingMethodEnum::toName(this->openGLDrawingMethod)); } /** * @return The view file type for manage files dialog. */ SpecFileDialogViewFilesTypeEnum::Enum CaretPreferences::getManageFilesViewFileType() const { return this->manageFilesViewFileType; } /** * Set the view file type for manage files dialog. * * @param manageFilesViewFileType * New view file type. */ void CaretPreferences::setManageFilesViewFileType(const SpecFileDialogViewFilesTypeEnum::Enum manageFilesViewFileType) { if (this->manageFilesViewFileType == manageFilesViewFileType) { return; } this->manageFilesViewFileType = manageFilesViewFileType; this->setString(NAME_MANAGE_FILES_VIEW_FILE_TYPE, SpecFileDialogViewFilesTypeEnum::toName(this->manageFilesViewFileType)); } /** * @return Show surface identification symbols? */ bool CaretPreferences::isShowSurfaceIdentificationSymbols() const { return this->showSurfaceIdentificationSymbols; } /** * Set show surface identification symbols. * * @param showSymbols * New status. */ void CaretPreferences::setShowSurfaceIdentificationSymbols(const bool showSymbols) { if (this->showSurfaceIdentificationSymbols == showSymbols) { return; } this->showSurfaceIdentificationSymbols = showSymbols; this->setBoolean(NAME_SHOW_SURFACE_IDENTIFICATION_SYMBOLS, this->showSurfaceIdentificationSymbols); } /** * @return Show volume identification symbols? */ bool CaretPreferences::isShowVolumeIdentificationSymbols() const { return this->showVolumeIdentificationSymbols; } /** * Set show volume identification symbols. * * @param showSymbols * New status. */ void CaretPreferences::setShowVolumeIdentificationSymbols(const bool showSymbols) { if (this->showVolumeIdentificationSymbols == showSymbols) { return; } this->showVolumeIdentificationSymbols = showSymbols; this->setBoolean(NAME_SHOW_VOLUME_IDENTIFICATION_SYMBOLS, this->showVolumeIdentificationSymbols); } /** * @return Is dynamic connectivity defaulted on? */ bool CaretPreferences::isDynamicConnectivityDefaultedOn() const { return this->dynamicConnectivityDefaultedOn; } /** * Set dynamic connectivity defaulted on. * * @param defaultedOn * New status. */ void CaretPreferences::setDynamicConnectivityDefaultedOn(const bool defaultedOn) { if (this->dynamicConnectivityDefaultedOn == defaultedOn) { return; } this->dynamicConnectivityDefaultedOn = defaultedOn; this->setBoolean(NAME_DYNAMIC_CONNECTIVITY_ON, defaultedOn); } /** * @return The image capture method. */ ImageCaptureMethodEnum::Enum CaretPreferences::getImageCaptureMethod() const { return this->imageCaptureMethod; } /** * Set the image capture method. * * @param imageCaptureMethod * New value for image capture method. */ void CaretPreferences::setImageCaptureMethod(const ImageCaptureMethodEnum::Enum imageCaptureMethod) { if (this->imageCaptureMethod == imageCaptureMethod) { return; } this->imageCaptureMethod = imageCaptureMethod; this->setString(NAME_IMAGE_CAPTURE_METHOD, ImageCaptureMethodEnum::toName(this->imageCaptureMethod)); } /** * @return Save remote login to preferences. */ bool CaretPreferences::isRemoteFilePasswordSaved() { return this->remoteFileLoginSaved; } /** * Set saving of remote login and password to preferences. * * @param saveRemoteLoginToPreferences * New status. */ void CaretPreferences::setRemoteFilePasswordSaved(const bool saveRemotePasswordToPreferences) { if (this->remoteFileLoginSaved == saveRemotePasswordToPreferences) { return; } this->remoteFileLoginSaved = saveRemotePasswordToPreferences; this->setBoolean(NAME_REMOTE_FILE_LOGIN_SAVED, this->remoteFileLoginSaved); this->qSettings->sync(); } /** * Get the remote file username and password * * @param userNameOut * Contains username upon exit * @param passwordOut * Contains password upon exit. */ void CaretPreferences::getRemoteFileUserNameAndPassword(AString& userNameOut, AString& passwordOut) const { userNameOut = this->remoteFileUserName; passwordOut = this->remoteFilePassword; } /** * Set the remote file username and password * * @param userName * New value for username. * @param passwordOut * New value for password. */ void CaretPreferences::setRemoteFileUserNameAndPassword(const AString& userName, const AString& password) { if ((this->remoteFileUserName == userName) && (this->remoteFilePassword == password)) { return; } this->remoteFileUserName = userName; this->remoteFilePassword = password; this->setString(NAME_REMOTE_FILE_USER_NAME, userName); this->setString(NAME_REMOTE_FILE_PASSWORD, password); this->qSettings->sync(); } /** * @return The BALSA username */ AString CaretPreferences::getBalsaUserName() const { return this->balsaUserName; } /** * Set the BALSA username * * @param userName * New value for BALSA username. */ void CaretPreferences::setBalsaUserName(const AString& userName) { if (this->balsaUserName == userName) { return; } this->balsaUserName = userName; this->setString(NAME_BALSA_USER_NAME, userName); } /** * @return Are axes crosshairs displayed? */ bool CaretPreferences::isVolumeAxesCrosshairsDisplayed() const { return this->displayVolumeAxesCrosshairs; } /** * Set axes crosshairs displayed * @param displayed * New status. */ void CaretPreferences::setVolumeAxesCrosshairsDisplayed(const bool displayed) { if (this->displayVolumeAxesCrosshairs == displayed) { return; } this->displayVolumeAxesCrosshairs = displayed; this->setBoolean(CaretPreferences::NAME_VOLUME_AXES_CROSSHAIRS, this->displayVolumeAxesCrosshairs); this->qSettings->sync(); } /** * @return The volume all slice planes layout */ VolumeSliceViewAllPlanesLayoutEnum::Enum CaretPreferences::getVolumeAllSlicePlanesLayout() const { QString stringValue(m_volumeAllSlicePlanesLayout->getValue().toString()); bool validFlag(false); VolumeSliceViewAllPlanesLayoutEnum::Enum enumValue = VolumeSliceViewAllPlanesLayoutEnum::fromName(stringValue, &validFlag); return enumValue; } /** * Set volume all slice planes layout * * @param allViewLayout * The all slice planes layout */ void CaretPreferences::setVolumeAllSlicePlanesLayout(const VolumeSliceViewAllPlanesLayoutEnum::Enum allViewLayout) { const QString stringValue = VolumeSliceViewAllPlanesLayoutEnum::toName(allViewLayout); m_volumeAllSlicePlanesLayout->setValue(stringValue); } /** * @return The crosshair gap */ float CaretPreferences::getVolumeCrosshairGap() const { return m_volumeCrossHairGapPreference->getValue().toFloat(); } /** * Set the volume crosshair gap * * @param gap * New value for crosshair gap. */ void CaretPreferences::setVolumeCrosshairGap(const float gap) { return m_volumeCrossHairGapPreference->setValue(gap); } /** * @return Are axes labels displayed? */ bool CaretPreferences::isVolumeAxesLabelsDisplayed() const { return this->displayVolumeAxesLabels; } /** * Set axes labels displayed * @param displayed * New status. */ void CaretPreferences::setVolumeAxesLabelsDisplayed(const bool displayed) { if (this->displayVolumeAxesLabels == displayed) { return; } this->displayVolumeAxesLabels = displayed; this->setBoolean(CaretPreferences::NAME_VOLUME_AXES_LABELS, this->displayVolumeAxesLabels); this->qSettings->sync(); } /** * @return Are montage axes coordinates displayed? */ bool CaretPreferences::isVolumeMontageAxesCoordinatesDisplayed() const { return this->displayVolumeAxesCoordinates; } /** * Set montage axes coordinates displayed * @param displayed * New status. */ void CaretPreferences::setVolumeMontageAxesCoordinatesDisplayed(const bool displayed) { if (this->displayVolumeAxesCoordinates == displayed) { return; } this->displayVolumeAxesCoordinates = displayed; this->setBoolean(CaretPreferences::NAME_VOLUME_AXES_COORDINATE, this->displayVolumeAxesCoordinates); this->qSettings->sync(); } /** * @return The volume montage gap. */ int32_t CaretPreferences::getVolumeMontageGap() const { return this->volumeMontageGap; } /** * Set the volume montage gap. * * @param volumeMontageGap * New value for montage gap. */ void CaretPreferences::setVolumeMontageGap(const int32_t volumeMontageGap) { if (this->volumeMontageGap == volumeMontageGap) { return; } this->volumeMontageGap = volumeMontageGap; this->setInteger(CaretPreferences::NAME_VOLUME_MONTAGE_GAP, this->volumeMontageGap); this->qSettings->sync(); } /** * @return The volume montage coordinate precision */ int32_t CaretPreferences::getVolumeMontageCoordinatePrecision() const { return this->volumeMontageCoordinatePrecision; } /** * Set the volume montage coordinate precision * * @param volumeMontageCoordinatePrecision * New value for montage coordinate precision */ void CaretPreferences::setVolumeMontageCoordinatePrecision(const int32_t volumeMontageCoordinatePrecision) { if (this->volumeMontageCoordinatePrecision == volumeMontageCoordinatePrecision) { return; } this->volumeMontageCoordinatePrecision = volumeMontageCoordinatePrecision; this->setInteger(CaretPreferences::NAME_VOLUME_MONTAGE_COORDINATE_PRECISION, this->volumeMontageCoordinatePrecision); this->qSettings->sync(); } /** * @return Is the splash screen enabled? */ bool CaretPreferences::isSplashScreenEnabled() const { return this->splashScreenEnabled; } /** * Set the splash screen enabled. * @param enabled * New status. */ void CaretPreferences::setSplashScreenEnabled(const bool enabled) { if (this->splashScreenEnabled == enabled) { return; } this->splashScreenEnabled = enabled; this->setBoolean(CaretPreferences::NAME_SPLASH_SCREEN, this->splashScreenEnabled); this->qSettings->sync(); } /** * @return Is the Develop Menu enabled? */ bool CaretPreferences::isDevelopMenuEnabled() const { return this->developMenuEnabled; } /** * Set the Develop Menu enabled. * @param enabled * New status. */ void CaretPreferences::setDevelopMenuEnabled(const bool enabled) { if (this->developMenuEnabled == enabled) { return; } this->developMenuEnabled = enabled; this->setBoolean(CaretPreferences::NAME_DEVELOP_MENU, this->developMenuEnabled); this->qSettings->sync(); } /** * @return Is Show Data ToolTips enabled? */ bool CaretPreferences::isShowDataToolTipsEnabled() const { return this->dataToolTipsEnabled; } /** * Set Show Data ToolTips enabled. * @param enabled * New status. */ void CaretPreferences::setShowDataToolTipsEnabled(const bool enabled) { if (this->dataToolTipsEnabled == enabled) { return; } this->dataToolTipsEnabled = enabled; this->setBoolean(CaretPreferences::NAME_DATA_TOOL_TIPS, this->dataToolTipsEnabled); this->qSettings->sync(); } /** * @param Is yoking defaulted on ? */ bool CaretPreferences::isYokingDefaultedOn() const { return this->yokingDefaultedOn; } /** * Set yoking defaulted on * * @param status * New status for yoking on. */ void CaretPreferences::setYokingDefaultedOn(const bool status) { if (this->yokingDefaultedOn == status) { return; } this->yokingDefaultedOn = status; this->setBoolean(CaretPreferences::NAME_YOKING_DEFAULT_ON, this->yokingDefaultedOn); this->qSettings->sync(); } /** * @param Is volume identification defaulted on ? */ bool CaretPreferences::isVolumeIdentificationDefaultedOn() const { return this->volumeIdentificationDefaultedOn; } /** * Set volume identification defaulted on * * @param status * New status for yoking on. */ void CaretPreferences::setVolumeIdentificationDefaultedOn(const bool status) { if (this->volumeIdentificationDefaultedOn == status) { return; } this->volumeIdentificationDefaultedOn = status; this->setBoolean(CaretPreferences::NAME_VOLUME_IDENTIFICATION_DEFAULTED_ON, this->volumeIdentificationDefaultedOn); this->qSettings->sync(); } /** * @return Pointer to the macros. */ WuQMacroGroup* CaretPreferences::getMacros() { return m_macros.get(); } /** * @return Const pointer to the macros. */ const WuQMacroGroup* CaretPreferences::getMacros() const { return m_macros.get(); } /** * Read an unsigned byte array to the preferences. * * @param name * Name for preferences * @param array * The array that is read. * @param numberOfElements * Number of elements in the array. */ void CaretPreferences::readUnsignedByteArray(const AString& name, uint8_t array[], const int32_t numberOfElements) { const int numAvailable = this->qSettings->beginReadArray(name); const int numToRead = std::min(numAvailable, numberOfElements); for (int i = 0; i < numToRead; i++) { this->qSettings->setArrayIndex(i); array[i] = static_cast(this->qSettings->value(AString::number(i)).toInt()); } this->qSettings->endArray(); } /** * Write an unsigned byte array to the preferences. * * @param name * Name for preferences * @param array * The array that is written. * @param numberOfElements * Number of elements in the array. */ void CaretPreferences::writeUnsignedByteArray(const AString& name, const uint8_t array[], const int32_t numberOfElements) { this->qSettings->beginWriteArray(name); for (int i = 0; i < numberOfElements; i++) { this->qSettings->setArrayIndex(i); this->qSettings->setValue(AString::number(i), array[i]); } this->qSettings->endArray(); this->qSettings->sync(); } /** * Initialize/Read the preferences */ void CaretPreferences::readPreferences() { userColors.reset(); uint8_t colorRGB[3] = { 0, 0, 0 }; userColors.getColorForegroundWindow(colorRGB); readUnsignedByteArray(NAME_COLOR_FOREGROUND_WINDOW, colorRGB, 3); userColors.setColorForegroundWindow(colorRGB); userColors.getColorBackgroundWindow(colorRGB); readUnsignedByteArray(NAME_COLOR_BACKGROUND_WINDOW, colorRGB, 3); userColors.setColorBackgroundWindow(colorRGB); userColors.getColorForegroundAllView(colorRGB); readUnsignedByteArray(NAME_COLOR_FOREGROUND_ALL, colorRGB, 3); userColors.setColorForegroundAllView(colorRGB); userColors.getColorBackgroundAllView(colorRGB); readUnsignedByteArray(NAME_COLOR_BACKGROUND_ALL, colorRGB, 3); userColors.setColorBackgroundAllView(colorRGB); userColors.getColorForegroundChartView(colorRGB); readUnsignedByteArray(NAME_COLOR_FOREGROUND_CHART, colorRGB, 3); userColors.setColorForegroundChartView(colorRGB); userColors.getColorBackgroundChartView(colorRGB); readUnsignedByteArray(NAME_COLOR_BACKGROUND_CHART, colorRGB, 3); userColors.setColorBackgroundChartView(colorRGB); userColors.getColorForegroundSurfaceView(colorRGB); readUnsignedByteArray(NAME_COLOR_FOREGROUND_SURFACE, colorRGB, 3); userColors.setColorForegroundSurfaceView(colorRGB); userColors.getColorBackgroundSurfaceView(colorRGB); readUnsignedByteArray(NAME_COLOR_BACKGROUND_SURFACE, colorRGB, 3); userColors.setColorBackgroundSurfaceView(colorRGB); userColors.getColorForegroundVolumeView(colorRGB); readUnsignedByteArray(NAME_COLOR_FOREGROUND_VOLUME, colorRGB, 3); userColors.setColorForegroundVolumeView(colorRGB); userColors.getColorBackgroundVolumeView(colorRGB); readUnsignedByteArray(NAME_COLOR_BACKGROUND_VOLUME, colorRGB, 3); userColors.setColorBackgroundVolumeView(colorRGB); userColors.getColorChartMatrixGridLines(colorRGB); readUnsignedByteArray(NAME_COLOR_CHART_MATRIX_GRID_LINES, colorRGB, 3); userColors.setColorChartMatrixGridLines(colorRGB); userColors.getColorChartHistogramThreshold(colorRGB); readUnsignedByteArray(NAME_COLOR_CHART_HISTOGRAM_THRESHOLD, colorRGB, 3); userColors.setColorChartHistogramThreshold(colorRGB); this->previousSpecFiles.clear(); const int numPrevSpec = this->qSettings->beginReadArray(NAME_PREVIOUS_SPEC_FILES); for (int i = 0; i < numPrevSpec; i++) { this->qSettings->setArrayIndex(i); previousSpecFiles.push_back(this->qSettings->value(AString::number(i)).toString()); } this->qSettings->endArray(); this->previousSceneFiles.clear(); const int numPrevScene = this->qSettings->beginReadArray(NAME_PREVIOUS_SCENE_FILES); for (int i = 0; i < numPrevScene; i++) { this->qSettings->setArrayIndex(i); previousSceneFiles.push_back(this->qSettings->value(AString::number(i)).toString()); } this->qSettings->endArray(); this->previousOpenFileDirectories.clear(); const int numPrevDir = this->qSettings->beginReadArray(NAME_PREVIOUS_OPEN_FILE_DIRECTORIES); for (int i = 0; i < numPrevDir; i++) { this->qSettings->setArrayIndex(i); previousOpenFileDirectories.push_back(this->qSettings->value(AString::number(i)).toString()); } this->qSettings->endArray(); this->readCustomViews(false); this->readTileTabsConfigurations(false); this->readMacros(false); AString levelName = this->qSettings->value(NAME_LOGGING_LEVEL, LogLevelEnum::toName(LogLevelEnum::INFO)).toString(); bool valid = false; LogLevelEnum::Enum logLevel = LogLevelEnum::fromName(levelName, &valid); if (valid == false) { logLevel = LogLevelEnum::INFO; } /* Do not call setLoggingLevel() as it will cause preferences to sync */ this->loggingLevel = logLevel; CaretLogger::getLogger()->setLevel(this->loggingLevel); ImageCaptureMethodEnum::Enum defaultCaptureType = ImageCaptureMethodEnum::IMAGE_CAPTURE_WITH_RENDER_PIXMAP; AString imageCaptureMethodName = this->qSettings->value(NAME_IMAGE_CAPTURE_METHOD, ImageCaptureMethodEnum::toName(defaultCaptureType)).toString(); bool validImageCaptureMethodName = false; this->imageCaptureMethod = ImageCaptureMethodEnum::fromName(imageCaptureMethodName, &validImageCaptureMethodName); if ( ! validImageCaptureMethodName) { this->imageCaptureMethod = defaultCaptureType; } AString openGLDrawingMethodName = this->qSettings->value(NAME_OPENGL_DRAWING_METHOD, OpenGLDrawingMethodEnum::toName(OpenGLDrawingMethodEnum::DRAW_WITH_VERTEX_BUFFERS_OFF)).toString(); bool validDrawingMethod = false; this->openGLDrawingMethod = OpenGLDrawingMethodEnum::fromName(openGLDrawingMethodName, &validDrawingMethod); if ( ! validDrawingMethod) { this->openGLDrawingMethod = OpenGLDrawingMethodEnum::DRAW_WITH_VERTEX_BUFFERS_OFF; } AString viewFileTypesName = this->qSettings->value(NAME_MANAGE_FILES_VIEW_FILE_TYPE, SpecFileDialogViewFilesTypeEnum::toName(SpecFileDialogViewFilesTypeEnum::VIEW_FILES_ALL)).toString(); bool viewFilesTypeValid = false; this->manageFilesViewFileType = SpecFileDialogViewFilesTypeEnum::fromName(viewFileTypesName, &viewFilesTypeValid); if ( ! viewFilesTypeValid) { this->manageFilesViewFileType = SpecFileDialogViewFilesTypeEnum::VIEW_FILES_ALL; } this->displayVolumeAxesLabels = this->getBoolean(CaretPreferences::NAME_VOLUME_AXES_LABELS, true); this->displayVolumeAxesCrosshairs = this->getBoolean(CaretPreferences::NAME_VOLUME_AXES_CROSSHAIRS, true); this->displayVolumeAxesCoordinates = this->getBoolean(CaretPreferences::NAME_VOLUME_AXES_COORDINATE, true); this->volumeMontageGap = this->getInteger(CaretPreferences::NAME_VOLUME_MONTAGE_GAP, 3); this->volumeMontageCoordinatePrecision = this->getInteger(CaretPreferences::NAME_VOLUME_MONTAGE_COORDINATE_PRECISION, 0); this->animationStartTime = 0.0;//this->qSettings->value(CaretPreferences::NAME_ANIMATION_START_TIME).toDouble(); this->splashScreenEnabled = this->getBoolean(CaretPreferences::NAME_SPLASH_SCREEN, true); this->developMenuEnabled = this->getBoolean(CaretPreferences::NAME_DEVELOP_MENU, false); this->dataToolTipsEnabled = this->getBoolean(CaretPreferences::NAME_DATA_TOOL_TIPS, true); this->yokingDefaultedOn = this->getBoolean(CaretPreferences::NAME_YOKING_DEFAULT_ON, true); this->volumeIdentificationDefaultedOn = this->getBoolean(CaretPreferences::NAME_VOLUME_IDENTIFICATION_DEFAULTED_ON, true); this->dynamicConnectivityDefaultedOn = this->getBoolean(CaretPreferences::NAME_DYNAMIC_CONNECTIVITY_ON, true); this->remoteFileUserName = this->getString(NAME_REMOTE_FILE_USER_NAME); this->remoteFilePassword = this->getString(NAME_REMOTE_FILE_PASSWORD); this->remoteFileLoginSaved = this->getBoolean(NAME_REMOTE_FILE_LOGIN_SAVED, false); this->balsaUserName = this->getString(NAME_BALSA_USER_NAME); this->showSurfaceIdentificationSymbols = this->getBoolean(NAME_SHOW_SURFACE_IDENTIFICATION_SYMBOLS, true); this->showVolumeIdentificationSymbols = this->getBoolean(NAME_SHOW_VOLUME_IDENTIFICATION_SYMBOLS, true); } /** * Read the custom views. Since user's may want to use them * in multiple instance of workbench that are running, this method allows * the custom views to be read without affecting other preferences. * * @param performSync * Sync with preferences since preferences may have been changed * by a concurrently running workbench. */ void CaretPreferences::readCustomViews(const bool performSync) { if (performSync) { this->qSettings->sync(); } this->removeAllCustomViews(); /* * Previously had "userViews" prior to CustomViews */ const int numUserViews = this->qSettings->beginReadArray("userViews"); for (int i = 0; i < numUserViews; i++) { this->qSettings->setArrayIndex(i); const AString viewString = this->qSettings->value(AString::number(i)).toString(); ModelTransform uv; if (uv.setFromString(viewString)) { this->customViews.push_back(new ModelTransform(uv)); } } this->qSettings->endArray(); /* * Read Custom Views */ const int numCustomViews = this->qSettings->beginReadArray(NAME_CUSTOM_VIEWS); for (int i = 0; i < numCustomViews; i++) { this->qSettings->setArrayIndex(i); const AString viewString = this->qSettings->value(AString::number(i)).toString(); ModelTransform uv; if (uv.setFromString(viewString)) { this->customViews.push_back(new ModelTransform(uv)); } } this->qSettings->endArray(); } void CaretPreferences::getAnimationStartTime(double& time) { time = animationStartTime; } void CaretPreferences::setAnimationStartTime(const double& time) { animationStartTime = time; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString CaretPreferences::toString() const { return "CaretPreferences"; } /** * Convert RGB bytes to Floats. * * @param bytesRGB * Byte RGB color [0, 255] INPUT * @param floatRGB * Float RGB color [0.0, 1.0] OUTPUT */ void CaretPreferences::byteRgbToFloatRgb(const uint8_t byteRGB[3], float floatRGB[3]) { for (int32_t i = 0; i < 3; i++) { floatRGB[i] = static_cast(byteRGB[i]) / 255.0; } } connectome-workbench-1.4.2/src/Common/CaretPreferences.h000066400000000000000000000436511360521144700232540ustar00rootroot00000000000000#ifndef __CARET_PREFERENCES__H_ #define __CARET_PREFERENCES__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "BackgroundAndForegroundColors.h" #include "BackgroundAndForegroundColorsModeEnum.h" #include "CaretObject.h" #include "LogLevelEnum.h" #include "ImageCaptureMethodEnum.h" #include "OpenGLDrawingMethodEnum.h" #include "SpecFileDialogViewFilesTypeEnum.h" #include "VolumeSliceViewAllPlanesLayoutEnum.h" class QSettings; class QStringList; namespace caret { class CaretPreferenceDataValue; class ModelTransform; class TileTabsConfiguration; class WuQMacroGroup; class CaretPreferences : public CaretObject { public: CaretPreferences(); virtual ~CaretPreferences(); const BackgroundAndForegroundColors* getBackgroundAndForegroundColors() const; BackgroundAndForegroundColors getUserBackgroundAndForegroundColors(); void setUserBackgroundAndForegroundColors(const BackgroundAndForegroundColors& colors); BackgroundAndForegroundColorsModeEnum::Enum getBackgroundAndForegroundColorsMode() const; void setSceneBackgroundAndForegroundColors(const BackgroundAndForegroundColors& colors); void setBackgroundAndForegroundColorsMode(const BackgroundAndForegroundColorsModeEnum::Enum colorsMode); void getPreviousSpecFiles(std::vector& previousSpecFiles) const; void addToPreviousSpecFiles(const AString& specFileName); void clearPreviousSpecFiles(); void getPreviousSceneFiles(std::vector& previousSceneFiles) const; void addToPreviousSceneFiles(const AString& specFileName); void clearPreviousSceneFiles(); void getPreviousOpenFileDirectories(std::vector& previousOpenFileDirectories) const; void getPreviousOpenFileDirectories(QStringList& previousOpenFileDirectories) const; void addToPreviousOpenFileDirectories(const AString& directoryName); LogLevelEnum::Enum getLoggingLevel() const; void setLoggingLevel(const LogLevelEnum::Enum loggingLevel); ImageCaptureMethodEnum::Enum getImageCaptureMethod() const; void setImageCaptureMethod(const ImageCaptureMethodEnum::Enum imageCaptureMethod); OpenGLDrawingMethodEnum::Enum getOpenDrawingMethod() const; void setOpenGLDrawingMethod(const OpenGLDrawingMethodEnum::Enum openGLDrawingMethod); VolumeSliceViewAllPlanesLayoutEnum::Enum getVolumeAllSlicePlanesLayout() const; void setVolumeAllSlicePlanesLayout(const VolumeSliceViewAllPlanesLayoutEnum::Enum allViewLayout); float getVolumeCrosshairGap() const; void setVolumeCrosshairGap(const float gap); bool isVolumeAxesCrosshairsDisplayed() const; void setVolumeAxesCrosshairsDisplayed(const bool displayed); bool isVolumeAxesLabelsDisplayed() const; void setVolumeAxesLabelsDisplayed(const bool displayed); bool isVolumeMontageAxesCoordinatesDisplayed() const; void setVolumeMontageAxesCoordinatesDisplayed(const bool displayed); int32_t getVolumeMontageGap() const; void setVolumeMontageGap(const int32_t volumeMontageGap); int32_t getVolumeMontageCoordinatePrecision() const; void setVolumeMontageCoordinatePrecision(const int32_t volumeMontageCoordinatePrecision); void setAnimationStartTime(const double &time); void getAnimationStartTime(double &time); bool isSplashScreenEnabled() const; void setSplashScreenEnabled(const bool enabled); bool isDevelopMenuEnabled() const; void setDevelopMenuEnabled(const bool enabled); bool isShowDataToolTipsEnabled() const; void setShowDataToolTipsEnabled(const bool enabled); void readTileTabsConfigurations(const bool performSync = true); std::vector getTileTabsConfigurationsSortedByName() const; TileTabsConfiguration* getTileTabsConfigurationByUniqueIdentifier(const AString& uniqueIdentifier); const TileTabsConfiguration* getTileTabsConfigurationByUniqueIdentifier(const AString& uniqueIdentifier) const; TileTabsConfiguration* getTileTabsConfigurationByName(const AString& name) const; void addTileTabsConfiguration(TileTabsConfiguration* tileTabsConfiguration); void removeTileTabsConfigurationByUniqueIdentifier(const AString& tileTabsUniqueIdentifier); void writeTileTabsConfigurations(); void readCustomViews(const bool performSync = true); std::vector getCustomViewNames() const; std::vector > getCustomViewNamesAndComments() const; bool getCustomView(const AString& customViewName, ModelTransform& modelTransformOut) const; void addOrReplaceCustomView(const ModelTransform& modelTransform); void removeCustomView(const AString& customViewName); bool isRemoteFilePasswordSaved(); void setRemoteFilePasswordSaved(const bool saveRemotePasswordToPreferences); void getRemoteFileUserNameAndPassword(AString& userNameOut, AString& passwordOut) const; void setRemoteFileUserNameAndPassword(const AString& userName, const AString& password); AString getBalsaUserName() const; void setBalsaUserName(const AString& userName); static void byteRgbToFloatRgb(const uint8_t byteRGB[3], float floatRGB[3]); bool isYokingDefaultedOn() const; void setYokingDefaultedOn(const bool status); bool isVolumeIdentificationDefaultedOn() const; void setVolumeIdentificationDefaultedOn(const bool status); SpecFileDialogViewFilesTypeEnum::Enum getManageFilesViewFileType() const; void setManageFilesViewFileType(const SpecFileDialogViewFilesTypeEnum::Enum manageFilesViewFileType); bool isShowSurfaceIdentificationSymbols() const; void setShowSurfaceIdentificationSymbols(const bool showSymbols); bool isShowVolumeIdentificationSymbols() const; void setShowVolumeIdentificationSymbols(const bool showSymbols); bool isDynamicConnectivityDefaultedOn() const; void setDynamicConnectivityDefaultedOn(const bool defaultedOn); WuQMacroGroup* getMacros(); const WuQMacroGroup* getMacros() const; void readMacros(const bool performSync = true); void writeMacros(); void invalidateSceneDataValues(); std::vector getPreferenceSceneDataValues(); private: CaretPreferences(const CaretPreferences&); CaretPreferences& operator=(const CaretPreferences&); public: virtual AString toString() const; private: bool getBoolean(const AString& name, const bool defaultValue = false); void setBoolean(const AString& name, const bool value); int getInteger(const AString& name, const int defaultValue = false); void setInteger(const AString& name, const int value); AString getString(const AString& name, const AString& defaultValue = ""); void setString(const AString& name, const AString& value); void addToPrevious(std::vector& previousVector, const AString& newName); void readUnsignedByteArray(const AString& name, uint8_t array[], const int32_t numberOfElements); void writeUnsignedByteArray(const AString& name, const uint8_t array[], const int32_t numberOfElements); void readPreferences(); void removeAllTileTabsConfigurations(); void removeAllCustomViews(); void writeCustomViews(); mutable QSettings* qSettings; BackgroundAndForegroundColors userColors; BackgroundAndForegroundColors sceneColors; /** NOTE: colors mode is NOT saved to preferences */ BackgroundAndForegroundColorsModeEnum::Enum m_colorsMode; std::vector previousSpecFiles; std::vector previousSceneFiles; std::vector previousOpenFileDirectories; LogLevelEnum::Enum loggingLevel; ImageCaptureMethodEnum::Enum imageCaptureMethod; OpenGLDrawingMethodEnum::Enum openGLDrawingMethod; std::vector customViews; std::vector tileTabsConfigurations; bool displayVolumeAxesCrosshairs; bool displayVolumeAxesLabels; bool displayVolumeAxesCoordinates; int32_t volumeMontageGap; int32_t volumeMontageCoordinatePrecision; std::unique_ptr m_volumeAllSlicePlanesLayout; std::unique_ptr m_volumeCrossHairGapPreference; std::vector m_preferenceDataValues; bool splashScreenEnabled; bool developMenuEnabled; double animationStartTime; bool volumeIdentificationDefaultedOn; bool showSurfaceIdentificationSymbols; bool showVolumeIdentificationSymbols; bool dynamicConnectivityDefaultedOn; bool yokingDefaultedOn; bool dataToolTipsEnabled; AString remoteFileUserName; AString remoteFilePassword; bool remoteFileLoginSaved; AString balsaUserName; SpecFileDialogViewFilesTypeEnum::Enum manageFilesViewFileType; std::unique_ptr m_macros; static const AString NAME_ANIMATION_START_TIME; static const AString NAME_BALSA_USER_NAME; static const AString NAME_VOLUME_AXES_CROSSHAIRS; static const AString NAME_VOLUME_AXES_LABELS; static const AString NAME_VOLUME_AXES_COORDINATE; static const AString NAME_VOLUME_MONTAGE_GAP; static const AString NAME_VOLUME_MONTAGE_COORDINATE_PRECISION; static const AString NAME_COLOR_BACKGROUND; static const AString NAME_COLOR_FOREGROUND; static const AString NAME_COLOR_BACKGROUND_WINDOW; static const AString NAME_COLOR_FOREGROUND_WINDOW; static const AString NAME_COLOR_BACKGROUND_ALL; static const AString NAME_COLOR_FOREGROUND_ALL; static const AString NAME_COLOR_BACKGROUND_CHART; static const AString NAME_COLOR_FOREGROUND_CHART; static const AString NAME_COLOR_BACKGROUND_SURFACE; static const AString NAME_COLOR_FOREGROUND_SURFACE; static const AString NAME_COLOR_BACKGROUND_VOLUME; static const AString NAME_COLOR_FOREGROUND_VOLUME; static const AString NAME_COLOR_CHART_MATRIX_GRID_LINES; static const AString NAME_COLOR_CHART_HISTOGRAM_THRESHOLD; static const AString NAME_DEVELOP_MENU; static const AString NAME_DATA_TOOL_TIPS; static const AString NAME_DYNAMIC_CONNECTIVITY_ON; static const AString NAME_IMAGE_CAPTURE_METHOD; static const AString NAME_LOGGING_LEVEL; static const AString NAME_MACROS; static const AString NAME_MANAGE_FILES_VIEW_FILE_TYPE; static const AString NAME_OPENGL_DRAWING_METHOD; static const AString NAME_PREVIOUS_SCENE_FILES; static const AString NAME_PREVIOUS_SPEC_FILES; static const AString NAME_PREVIOUS_OPEN_FILE_DIRECTORIES; static const AString NAME_SPLASH_SCREEN; static const AString NAME_CUSTOM_VIEWS; static const AString NAME_REMOTE_FILE_USER_NAME; static const AString NAME_REMOTE_FILE_PASSWORD; static const AString NAME_REMOTE_FILE_LOGIN_SAVED; static const AString NAME_SHOW_SURFACE_IDENTIFICATION_SYMBOLS; static const AString NAME_SHOW_VOLUME_IDENTIFICATION_SYMBOLS; static const AString NAME_TILE_TABS_CONFIGURATIONS; static const AString NAME_TILE_TABS_CONFIGURATIONS_TWO; static const AString NAME_VOLUME_IDENTIFICATION_DEFAULTED_ON; static const AString NAME_YOKING_DEFAULT_ON; }; #ifdef __CARET_PREFERENCES_DECLARE__ const AString CaretPreferences::NAME_ANIMATION_START_TIME = "animationStartTime"; const AString CaretPreferences::NAME_BALSA_USER_NAME = "balsaUserName"; const AString CaretPreferences::NAME_VOLUME_AXES_CROSSHAIRS = "volumeAxesCrosshairs"; const AString CaretPreferences::NAME_VOLUME_AXES_LABELS = "volumeAxesLabels"; const AString CaretPreferences::NAME_VOLUME_AXES_COORDINATE = "volumeAxesCoordinates"; const AString CaretPreferences::NAME_VOLUME_MONTAGE_GAP = "volumeMontageGap"; const AString CaretPreferences::NAME_VOLUME_MONTAGE_COORDINATE_PRECISION = "volumeMontageCoordinatePrecision"; const AString CaretPreferences::NAME_COLOR_BACKGROUND = "colorBackground"; const AString CaretPreferences::NAME_COLOR_FOREGROUND = "colorForeground"; const AString CaretPreferences::NAME_COLOR_BACKGROUND_WINDOW = "colorBackgroundWindow"; const AString CaretPreferences::NAME_COLOR_FOREGROUND_WINDOW = "colorForegroundWindow"; const AString CaretPreferences::NAME_COLOR_BACKGROUND_ALL = "colorBackgroundAll"; const AString CaretPreferences::NAME_COLOR_FOREGROUND_ALL = "colorForegroundAll"; const AString CaretPreferences::NAME_COLOR_BACKGROUND_CHART = "colorBackgroundChart"; const AString CaretPreferences::NAME_COLOR_FOREGROUND_CHART = "colorForegroundChart"; const AString CaretPreferences::NAME_COLOR_BACKGROUND_SURFACE = "colorBackgroundSurface"; const AString CaretPreferences::NAME_COLOR_FOREGROUND_SURFACE = "colorForegroundSurface"; const AString CaretPreferences::NAME_COLOR_BACKGROUND_VOLUME = "colorBackgroundVolume"; const AString CaretPreferences::NAME_COLOR_FOREGROUND_VOLUME = "colorForegroundVolume"; const AString CaretPreferences::NAME_COLOR_CHART_MATRIX_GRID_LINES = "colorChartMatrixGridLines"; const AString CaretPreferences::NAME_COLOR_CHART_HISTOGRAM_THRESHOLD = "colorChartHistogramThreshold"; const AString CaretPreferences::NAME_DEVELOP_MENU = "developMenu"; const AString CaretPreferences::NAME_DATA_TOOL_TIPS = "dataToolTips"; const AString CaretPreferences::NAME_DYNAMIC_CONNECTIVITY_ON = "dynamicConnectivityDefaultedOn"; const AString CaretPreferences::NAME_IMAGE_CAPTURE_METHOD = "imageCaptureMethod"; const AString CaretPreferences::NAME_LOGGING_LEVEL = "loggingLevel"; const AString CaretPreferences::NAME_MACROS = "macros"; const AString CaretPreferences::NAME_MANAGE_FILES_VIEW_FILE_TYPE = "manageFilesViewFileType"; const AString CaretPreferences::NAME_OPENGL_DRAWING_METHOD = "openGLDrawingMethod"; const AString CaretPreferences::NAME_PREVIOUS_SCENE_FILES = "previousSceneFiles"; const AString CaretPreferences::NAME_PREVIOUS_SPEC_FILES = "previousSpecFiles"; const AString CaretPreferences::NAME_PREVIOUS_OPEN_FILE_DIRECTORIES = "previousOpenFileDirectories"; const AString CaretPreferences::NAME_SPLASH_SCREEN = "splashScreen"; const AString CaretPreferences::NAME_CUSTOM_VIEWS = "customViews"; const AString CaretPreferences::NAME_REMOTE_FILE_USER_NAME = "remoteFileUserName"; const AString CaretPreferences::NAME_REMOTE_FILE_PASSWORD = "remoteFilePassword"; const AString CaretPreferences::NAME_REMOTE_FILE_LOGIN_SAVED = "removeFileLoginSaved"; const AString CaretPreferences::NAME_SHOW_SURFACE_IDENTIFICATION_SYMBOLS = "showSurfaceIdentificationSymbols"; const AString CaretPreferences::NAME_SHOW_VOLUME_IDENTIFICATION_SYMBOLS = "showVolumeIdentificationSymbols"; const AString CaretPreferences::NAME_TILE_TABS_CONFIGURATIONS = "tileTabsConfigurations"; const AString CaretPreferences::NAME_TILE_TABS_CONFIGURATIONS_TWO = "tileTabsConfigurationsTwo"; const AString CaretPreferences::NAME_VOLUME_IDENTIFICATION_DEFAULTED_ON = "volumeIdentificationDefaultedOn"; const AString CaretPreferences::NAME_YOKING_DEFAULT_ON = "yokingDefaultedOn"; #endif // __CARET_PREFERENCES_DECLARE__ } // namespace #endif //__CARET_PREFERENCES__H_ connectome-workbench-1.4.2/src/Common/CaretTemporaryFile.cxx000066400000000000000000000210601360521144700241360ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CARET_TEMPORARY_FILE_DECLARE__ #include "CaretTemporaryFile.h" #undef __CARET_TEMPORARY_FILE_DECLARE__ #include #include "CaretHttpManager.h" #include "DataFileException.h" using namespace caret; /** * \class caret::CaretTemporaryFile * \brief Reads and writes a temporary file. * \ingroup Common * * Reads and writes a temporary file. When an instance of this class * goes out of scope, the temporary file will be deleted. This class * is able to read a file that resides on an HTTP server (filename * starts with "http://"). * * QTemporaryFile is encapsulated by this class. */ /** * Constructor. */ CaretTemporaryFile::CaretTemporaryFile() : DataFile() { m_temporaryFile = NULL; initializeCaretTemporaryFile(); } /** * Destructor. */ CaretTemporaryFile::~CaretTemporaryFile() { delete m_temporaryFile; } /** * Initialize the temporary file.. */ void CaretTemporaryFile::initializeCaretTemporaryFile() { if (m_temporaryFile != NULL) { delete m_temporaryFile; } m_temporaryFile = new QTemporaryFile(); setFileName(m_temporaryFile->fileName()); } /** * Clear the temporary file. * Destroys the encapsulated QTemporaryFile. */ void CaretTemporaryFile::clear() { DataFile::clear(); initializeCaretTemporaryFile(); } /** * Is the file empty (contains no data)? * * @return * true if the file is empty, else false. */ bool CaretTemporaryFile::isEmpty() const { const bool fileEmpty = (m_temporaryFile->size() <= 0); return fileEmpty; } AString CaretTemporaryFile::getFileName() const { return m_temporaryFile->fileName(); } AString CaretTemporaryFile::getFileNameNoPath() const { CaretTemporaryFile* ctf = const_cast(this); ctf->setFileName(m_temporaryFile->fileName()); return DataFile::getFileNameNoPath(); } /** * This method does nothing as the temporary file's name * is generated by QTemporaryFile. * * @param filename * Name for file. */ void CaretTemporaryFile::setFileName(const AString& filename) { /* * Needed for getFileNameNoPath() functionality. */ DataFile::setFileName(filename); } /** * Read the file at the given path into the temporary file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully read. */ void CaretTemporaryFile::readFile(const AString& filename) { if (DataFile::isFileOnNetwork(filename)) { /* * Read file on network. * Sort of a kludge, read from the network as a string of bytes * and then write the bytes to a temporary file. */ CaretHttpRequest request; request.m_method = CaretHttpManager::GET; request.m_url = filename; CaretHttpResponse response; CaretHttpManager::httpRequest(request, response); if (response.m_ok == false) { QString msg = ("HTTP error HTTP Response Code=" + AString::number(response.m_responseCode)); throw DataFileException(filename, msg); } const int64_t numBytes = response.m_body.size(); if (numBytes > 0) { AString tempPath = QDir::tempPath(); if (!tempPath.endsWith('/')) tempPath += '/';//qt decided to make this behavior OS-dependent, for no apparent reason m_temporaryFile->setFileTemplate(tempPath + "qt_temp.XXXXXX." + filename.section('/', -1).section('.', 1));//strip all but the filename, then take all the parts of the extension if (m_temporaryFile->open()) { const int64_t numBytesWritten = m_temporaryFile->write(&response.m_body[0], numBytes); if (numBytesWritten != numBytes) { throw DataFileException(filename, " Tried to write " + QString::number(numBytes) + " bytes to temporary file " + m_temporaryFile->fileName() + " but only wrote " + AString::number(numBytesWritten) + " bytes."); } m_temporaryFile->close(); } else { throw DataFileException(filename, "Unable to open temporary file for writing its content."); } } else { throw DataFileException(filename, "Failed to read any data from file."); } } else { /* * Read local file. */ QFile file(filename); checkFileReadability(filename); if (file.open(QFile::ReadOnly)) { QByteArray byteArray = file.readAll(); file.close(); const int numBytes = byteArray.length(); if (numBytes > 0) { if (m_temporaryFile->open()) { const int64_t numBytesWritten = m_temporaryFile->write(byteArray); if (numBytesWritten != numBytes) { throw DataFileException(filename, " Tried to write " + QString::number(numBytes) + " bytes to temporary file " + m_temporaryFile->fileName() + " but only wrote " + AString::number(numBytesWritten) + " bytes."); } m_temporaryFile->close(); } else { throw DataFileException(m_temporaryFile->fileName(), "Unable to open temporary file for writing its content."); } } else { throw DataFileException(filename, "No data read from file, is it empty?"); } } else { throw DataFileException(filename, "Unable to open file for reading its content."); } } } /** * Write the contents of the temporary file to a local file with * the given name. * * @param filename * Name of the local data file. * @throws DataFileException * If the file was not successfully written. */ void CaretTemporaryFile::writeFile(const AString& filename) { checkFileWritability(filename); if (isEmpty()) { throw DataFileException(filename, "No data (temporary file is empty) to write to file."); } const QString tempFileName = m_temporaryFile->fileName(); QFile fileIn(tempFileName); if (fileIn.open(QFile::ReadOnly)) { QByteArray byteArray = fileIn.readAll(); fileIn.close(); QFile fileOut(filename); if (fileOut.open(QFile::WriteOnly)) { fileOut.write(byteArray); fileOut.close(); } else { fileOut.close(); throw DataFileException(filename, "Unable to open file for writing its content."); } } else { fileIn.close(); throw DataFileException(tempFileName, "Unable to open temporary file for reading its content."); } } connectome-workbench-1.4.2/src/Common/CaretTemporaryFile.h000066400000000000000000000040211360521144700235610ustar00rootroot00000000000000#ifndef __CARET_TEMPORARY_FILE_H__ #define __CARET_TEMPORARY_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "DataFile.h" class QTemporaryFile; namespace caret { class CaretTemporaryFile : public DataFile { public: CaretTemporaryFile(); virtual ~CaretTemporaryFile(); virtual void clear(); virtual bool isEmpty() const; virtual AString getFileName() const; virtual AString getFileNameNoPath() const; virtual void setFileName(const AString& filename); virtual void readFile(const AString& filename); virtual void writeFile(const AString& filename); // ADD_NEW_METHODS_HERE private: CaretTemporaryFile(const CaretTemporaryFile&); CaretTemporaryFile& operator=(const CaretTemporaryFile&); private: void initializeCaretTemporaryFile(); QTemporaryFile* m_temporaryFile; // ADD_NEW_MEMBERS_HERE }; #ifdef __CARET_TEMPORARY_FILE_DECLARE__ // #endif // __CARET_TEMPORARY_FILE_DECLARE__ } // namespace #endif //__CARET_TEMPORARY_FILE_H__ connectome-workbench-1.4.2/src/Common/CaretUndoCommand.cxx000066400000000000000000000136031360521144700235640ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /* * NOTE: The Qt license is included because the CaretUndoStack API * including the method comments is copied from QUndoStack. */ /**************************************************************************** ** ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtOpenGL module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #define __CARET_UNDO_COMMAND_DECLARE__ #include "CaretUndoCommand.h" #undef __CARET_UNDO_COMMAND_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" using namespace caret; /** * \class caret::CaretUndoCommand * \brief Abstract class for a command that supports 'undo' and 'redo'. * \ingroup Common * * Abstract class for commands that allow 'undo' and 'redo'. * * Design is based off Qt's QUndoCommand. * * While using QUndoCommand would be preferred, it cannot be used because * It is located in Qt's GUI module which is not accessible to * Caret's "lower level" modules. */ /** * Constructor. */ CaretUndoCommand::CaretUndoCommand() : CaretObject(), m_windowIndex(-1), m_mergeFlag(false) { } /** * Destructor. */ CaretUndoCommand::~CaretUndoCommand() { } /** * @return Description of command. */ AString CaretUndoCommand::getDescription() const { return m_description; } /** * Set description of command. * @param descripton * New value for description of command. */ void CaretUndoCommand::setDescription(const AString& description) { m_description = description; } /** * @return Is merge enabled for this command? * * When merge is enabled and a command is passed * to CaretUndoStack::push(), CaretUndoStack will * try to merge the command with the command at * the top of the undo stack. */ bool CaretUndoCommand::isMergeEnabled() const { return m_mergeFlag; } /** * Set the merge status for this command. * * When merge is enabled and a command is passed * to CaretUndoStack::push(), CaretUndoStack will * try to merge the command with the command at * the top of the undo stack. * * @param mergeStatus * New merge status for this command. */ void CaretUndoCommand::setMergeEnabled(const bool mergeStatus) { m_mergeFlag = mergeStatus; } /** * @return Index of window in which command is executed. * Will be negative if not valid. */ int32_t CaretUndoCommand::getWindowIndex() const { return m_windowIndex; } /** * Set index of window in which command is executed. * * @param windowIndex * Index of window. Will be negative if invalid. */ void CaretUndoCommand::setWindowIndex(const int32_t windowIndex) { m_windowIndex = windowIndex; } /** * Attempts to merge this command with command. Returns true on success; otherwise returns false. * * If this function returns true, calling this command's redo() must have the same effect as * redoing both this command and command. Similarly, calling this command's undo() must have * the same effect as undoing command and this command. * * The default implementation returns false. * * @return True if the given command was merged with this command, else false. */ bool CaretUndoCommand::mergeWith(const CaretUndoCommand* /*command*/) { CaretLogWarning("The default implementation of CaretUndoCommand::mergeWith() was called and this should never happened. " "This method should have been overriden by its sub class."); return false; } connectome-workbench-1.4.2/src/Common/CaretUndoCommand.h000066400000000000000000000112751360521144700232140ustar00rootroot00000000000000#ifndef __CARET_UNDO_COMMAND_H__ #define __CARET_UNDO_COMMAND_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /* * NOTE: The Qt license is included because the CaretUndoStack API * including the method comments is copied from QUndoStack. */ /**************************************************************************** ** ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtOpenGL module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "CaretObject.h" namespace caret { class CaretUndoCommand : public CaretObject { public: CaretUndoCommand(); virtual ~CaretUndoCommand(); AString getDescription() const; void setDescription(const AString& description); bool isMergeEnabled() const; void setMergeEnabled(const bool mergeStatus); virtual bool mergeWith(const CaretUndoCommand* command); int32_t getWindowIndex() const; void setWindowIndex(const int32_t windowIndex); /** * Operation that "redoes" the command. * * @param errorMessageOut * Output containing error message. * @return * True if the command executed successfully, else false. */ virtual bool redo(AString& errorMessageOut) = 0; /** * Operation that "undoes" the command. * * @param errorMessageOut * Output containing error message. * @return * True if the command executed successfully, else false. */ virtual bool undo(AString& errorMessageOut) = 0; // ADD_NEW_METHODS_HERE private: CaretUndoCommand(const CaretUndoCommand&); CaretUndoCommand& operator=(const CaretUndoCommand&); AString m_description; int32_t m_windowIndex; bool m_mergeFlag; // ADD_NEW_MEMBERS_HERE }; #ifdef __CARET_UNDO_COMMAND_DECLARE__ // #endif // __CARET_UNDO_COMMAND_DECLARE__ } // namespace #endif //__CARET_UNDO_COMMAND_H__ connectome-workbench-1.4.2/src/Common/CaretUndoStack.cxx000066400000000000000000000436561360521144700232660ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /* * NOTE: The Qt license is included because the CaretUndoStack API * including the method comments is copied from QUndoStack. */ /**************************************************************************** ** ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtOpenGL module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #define __CARET_UNDO_STACK_DECLARE__ #include "CaretUndoStack.h" #undef __CARET_UNDO_STACK_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretUndoCommand.h" using namespace caret; /** * \class caret::CaretUndoStack * \brief An abstract class for an undo stack implementation., * \ingroup Common * * Stack for undo and redo of commands. * * Design is based off Qt's QUndoStack. * * While using QUndoStack would be preferred, it cannot be used because: * (1) It is located in Qt's GUI module which is not accessible to * Caret's "lower level" modules. * (2) QUndoStack is targeted to text documents. * * An undo stack maintains a stack of commands that have been * applied to a document. * * New commands are pushed on the stack using push(). Commands can be undone * and redone using undo() and redo(). * * CaretUndoStack keeps track of the current command. This is the command which * will be executed by the next call to redo(). The index of this command is * returned by index(). If the top-most command on the stack has already * been redone, index() is equal to count(). */ /** * Constructs an empty undo stack in the "clean" state. */ CaretUndoStack::CaretUndoStack() : CaretObject() { m_undoLimit = 0; m_undoStackIndex = 0; } /** * Destroys the undo stack, deleting any commands that are on it. */ CaretUndoStack::~CaretUndoStack() { clear(); } /** * Returns true if there is a command available for redo; * otherwise returns false. * * This function returns false if the stack is empty or if the top * command on the stack has already been redone. * * While the Qt documentation states "Synonymous with index() == count()" * the actual QUndoStack code indicates the comment should be * "Synonymous with index() < count()". */ bool CaretUndoStack::canRedo() const { if (m_undoStack.empty()) { return false; } if (index() < count()) { return true; } return false; } /** * Returns true if there is a command available for undo; otherwise * returns false. * * This function returns false if the stack is empty, or if the bottom * command on the stack has already been undone. * * While the Qt documentation staties "Synonymous with index() == 0", viewing * the actual QUndoStack code indicates the comment should be * "Synonymous with index() > 0". */ bool CaretUndoStack::canUndo() const { if (m_undoStack.empty()) { return false; } if (index() > 0) { return true; } return false; } /** * @return Number of commands on the undo stack. */ int32_t CaretUndoStack::count() const { return m_undoStack.size(); } /** * Returns the index of the current command. This is the command that will * be executed on the next call to redo(). It is not always the top-most * command on the stack, since a number of commands may have been undone. * * @return Index of current command. This value ranges from 1 to count() * when the stack contains elements and zero when the stack is empty. */ int32_t CaretUndoStack::index() const { return m_undoStackIndex; } /** * Delete the command at the given index. The index of the current * command may change (if it is greater than the index). After * calling this method, the command that was at the index has * been deleted, so NEVER use it after calling this method. * * @param index * Index of command that is removed. */ void CaretUndoStack::deleteCommandAtIndex(const int32_t index) { if ((index >= 0) || (index < static_cast(m_undoStack.size()))) { CaretUndoCommand* undoCommand = m_undoStack.at(index); m_undoStack.erase(m_undoStack.begin() + index); delete undoCommand; } else { CaretLogWarning("CaretUndoStack::command() called with invalid index=" + AString::number(index)); } } /** * Clears the command stack by deleting all commands on it, and returns * the stack to the clean state. * * Commands are not undone or redone; the state of the edited object * remains unchanged. * * This function is usually used when the contents of the document * are abandoned. */ void CaretUndoStack::clear() { for (std::deque::iterator iter = m_undoStack.begin(); iter != m_undoStack.end(); iter++) { delete *iter; } m_undoStack.clear(); m_undoStackIndex = 0; } /** * Returns a const pointer to the command at index. * * This function returns a const pointer, because modifying a command, once * it has been pushed onto the stack and executed, almost always causes * corruption of the state of the document, if the command is later * undone or redone. * * @param index * Index of the item in the undo stack. * @return * Item at the given index or NULL if the index is invalid. */ const CaretUndoCommand* CaretUndoStack::command(const int32_t index) const { if ((index >= 0) || (index < static_cast(m_undoStack.size()))) { return m_undoStack.at(index); } else { CaretLogWarning("CaretUndoStack::command() called with invalid index=" + AString::number(index)); } return NULL; } /** * Execute (redo()) the command and then push the command. * * @seealso push() * * @param newCommand * Command that is executed and then pushed onto the stack. * @param windowIndex * Index of window (may be invalid => negative) * @param errorMessageOut * Output containing error message. * @return * True if the redo executed successfully, else false. */ bool CaretUndoStack::pushAndRedo(CaretUndoCommand* newCommand, const int32_t windowIndex, AString& errorMessageOut) { CaretAssert(newCommand); errorMessageOut.clear(); newCommand->setWindowIndex(windowIndex); const bool validFlag = newCommand->redo(errorMessageOut); newCommand->setWindowIndex(-1); push(newCommand); return validFlag; } /** * Pushes the given command onto the stack. Unlike QUndoStack the * command's redo() method IS NOT called. * * If commands were undone before cmd was pushed, the current command and * all commands above it are deleted. Hence cmd always ends up being the * top-most on the stack. * * If the command's merge status is set, an attempt will be made to * merge the given command with the command at the top of the stack. * If successful there is no need to push the new command onto the stack * since it has been merged and the command will be deleted. If merge * is NOT successful, the command will be pushed onto the stack. * * Once a command is pushed, the stack takes ownership of it. There are * no getters to return the command, since modifying it after it has been * executed will almost always lead to corruption of the document's state. * * @param newCommand * Command pushed onto the stack. */ void CaretUndoStack::push(CaretUndoCommand* newCommand) { if (index() < count()) { /* * Delete any commands that have been "undone" */ const int numToDeleteAtBack = count() - index(); for (int32_t i = 0; i < numToDeleteAtBack; i++) { delete m_undoStack.back(); m_undoStack.pop_back(); } } if (newCommand->isMergeEnabled()) { if ( ! m_undoStack.empty()) { CaretUndoCommand* command = m_undoStack.back(); CaretAssert(command); if (command->mergeWith(newCommand)) { delete newCommand; return; } } } m_undoStack.push_back(newCommand); if (m_undoLimit > 0) { /* * Delete oldest command(s) when undo limit is exceeded */ const int32_t numToDeleteAtFront = count() - m_undoLimit; for (int32_t i = 0; i < numToDeleteAtFront; i++) { delete m_undoStack.front(); m_undoStack.pop_front(); } } m_undoStackIndex = count(); } /** * Redoes the current command by calling QUndoCommand::redo(). * Increments the current command index. * * If the stack is empty, or if the top command on the stack has already * been redone, this function does nothing. * * @param windowIndex * Index of window in which redo was requested. * @param errorMessageOut * Output containing error message. * @return * True if the redo executed successfully, else false. */ bool CaretUndoStack::redoInWindow(const int32_t windowIndex, AString& errorMessageOut) { // redo(); errorMessageOut.clear(); if (m_undoStack.empty()) { errorMessageOut = "No command to redo."; return false; } bool validFlag = true; if ((m_undoStackIndex >= 0) && (m_undoStackIndex < count())) { CaretUndoCommand* command = m_undoStack.at(m_undoStackIndex); CaretAssert(command); command->setWindowIndex(windowIndex); validFlag = redoCommand(command, errorMessageOut); command->setWindowIndex(-1); ++m_undoStackIndex; } return validFlag; } /** * Redoes the current command by calling QUndoCommand::redo(). * Increments the current command index. * * If the stack is empty, or if the top command on the stack has already * been redone, this function does nothing. * * @param errorMessageOut * Output containing error message. * @return * True if the redo executed successfully, else false. */ bool CaretUndoStack::redo(AString& errorMessageOut) { return redoInWindow(-1, errorMessageOut); // if (m_undoStack.empty()) { // return; // } // // if ((m_undoStackIndex >= 0) // && (m_undoStackIndex < count())) { // redoCommand(m_undoStack.at(m_undoStackIndex)); // ++m_undoStackIndex; // } } /** * @return Returns the description of the command which will be * redone in the next call to redo(). */ AString CaretUndoStack::redoText() { AString text; if ( ! m_undoStack.empty()) { if ((m_undoStackIndex >= 0) && (m_undoStackIndex < count())) { text = m_undoStack.at(m_undoStackIndex)->getDescription(); } } return text; } /** * Undoes the command below the current command by calling QUndoCommand::undo(). * Decrements the current command index. * * If the stack is empty, or if the bottom command on the stack has already * been undone, this function does nothing. * * @param windowIndex * Index of window in which undo was requested. * @param errorMessageOut * Output containing error message. * @return * True if the redo executed successfully, else false. */ bool CaretUndoStack::undoInWindow(const int32_t windowIndex, AString& errorMessageOut) { // undo(); errorMessageOut.clear(); if (m_undoStack.empty()) { errorMessageOut = "No command to undo."; return false; } bool validFlag = true; if ((m_undoStackIndex > 0) && (m_undoStackIndex <= count())) { --m_undoStackIndex; CaretUndoCommand* command = m_undoStack.at(m_undoStackIndex); CaretAssert(command); command->setWindowIndex(windowIndex); validFlag = undoCommand(command, errorMessageOut); command->setWindowIndex(-1); } return validFlag; } /** * Undoes the command below the current command by calling QUndoCommand::undo(). * Decrements the current command index. * * If the stack is empty, or if the bottom command on the stack has already * been undone, this function does nothing. * * @param errorMessageOut * Output containing error message. * @return * True if the command executed successfully, else false.void */ bool CaretUndoStack::undo(AString& errorMessageOut) { return undoInWindow(-1, errorMessageOut); // if (m_undoStack.empty()) { // return; // } // // if ((m_undoStackIndex > 0) // && (m_undoStackIndex <= count())) { // --m_undoStackIndex; // undoCommand(m_undoStack.at(m_undoStackIndex)); // } } /** * @return Returns the description of the command which will be * undone in the next call to undo(). */ AString CaretUndoStack::undoText() { AString text; if ( ! m_undoStack.empty()) { if ((m_undoStackIndex > 0) && (m_undoStackIndex <= count())) { const int32_t undoIndex = m_undoStackIndex - 1; text = m_undoStack.at(undoIndex)->getDescription(); } } return text; } /** * When the number of commands on a stack exceedes the stack's undo limit, * commands are deleted from the bottom of the stack. The default * value is 0, which means that there is no limit. * * This property may only be set when the undo stack is empty, since setting * it on a non-empty stack might delete the command at the current index. * Calling setUndoLimit() on a non-empty stack and a warning is logged. * * @param undoLimit * New value for maximum number of undo commands. */ void CaretUndoStack::setUndoLimit(const int32_t undoLimit) { if (m_undoStack.empty()) { if (undoLimit >= 0) { m_undoLimit = undoLimit; } else { CaretLogWarning("CaretUndoStack::setUndoLimit() called with invalid value=" + AString::number(undoLimit)); } } else { CaretLogWarning("CaretUndoStack::setUndoLimit() called while undo stack contains elements." " New undo limit ignored."); } } /** * Apply a 'redo' using the given command. * * Subclasses may override this method. * * @param cmd * Command that performs a 'redo'. * @param errorMessageOut * Output containing error message. * @return * True if the command executed successfully, else false. */ bool CaretUndoStack::redoCommand(CaretUndoCommand* cmd, AString& errorMessageOut) { CaretAssert(cmd); const bool validFlag = cmd->redo(errorMessageOut); return validFlag; } /** * Apply an 'undo' using the given command. * * Subclasses may override this method. * * @param cmd * Command that performs a 'undo'. * @param errorMessageOut * Output containing error message. * @return * True if the command executed successfully, else false. */ bool CaretUndoStack::undoCommand(CaretUndoCommand* cmd, AString& errorMessageOut) { CaretAssert(cmd); return cmd->undo(errorMessageOut); } /** * Undo ALL changes. * * @param errorMessageOut * Output containing error message. * @return * True if the command executed successfully, else false. */ bool CaretUndoStack::undoAll(AString& errorMessageOut) { bool validFlag = true; while (canUndo()) { AString msg; if ( ! undo(msg)) { validFlag = false; errorMessageOut.appendWithNewLine(msg); } } return validFlag; } connectome-workbench-1.4.2/src/Common/CaretUndoStack.h000066400000000000000000000124311360521144700226760ustar00rootroot00000000000000#ifndef __CARET_UNDO_STACK_H__ #define __CARET_UNDO_STACK_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /* * NOTE: The Qt license is included because the CaretUndoStack API * including the method comments is copied from QUndoStack. */ /**************************************************************************** ** ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtOpenGL module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include "CaretObject.h" namespace caret { class CaretUndoCommand; class CaretUndoStack : public CaretObject { public: CaretUndoStack(); virtual ~CaretUndoStack(); bool canUndo() const; bool canRedo() const; void clear(); int32_t count() const; void deleteCommandAtIndex(const int32_t index); int32_t index() const; const CaretUndoCommand* command(const int32_t index) const; void push(CaretUndoCommand* newCommand); bool pushAndRedo(CaretUndoCommand* newCommand, const int32_t windowIndex, AString& errorMessageOut); bool redo(AString& errorMessageOut); bool redoInWindow(const int32_t windowIndex, AString& errorMessageOut); AString redoText(); bool undo(AString& errorMessageOut); bool undoInWindow(const int32_t windowIndex, AString& errorMessageOut); bool undoAll(AString& errorMessageOut); AString undoText(); void setUndoLimit(const int32_t undoLimit); // ADD_NEW_METHODS_HERE protected: virtual bool redoCommand(CaretUndoCommand* cmd, AString& errorMessageOut); virtual bool undoCommand(CaretUndoCommand* cmd, AString& errorMessageOut); private: CaretUndoStack(const CaretUndoStack&); CaretUndoStack& operator=(const CaretUndoStack&); /** * The undo "stack". A deque is used so that items * can be removed when the size of the "stack" exceeds * the undo limit. */ std::deque m_undoStack; /** * The index of the current command. */ int32_t m_undoStackIndex; int32_t m_undoLimit; // ADD_NEW_MEMBERS_HERE }; #ifdef __CARET_UNDO_STACK_DECLARE__ // #endif // __CARET_UNDO_STACK_DECLARE__ } // namespace #endif //__CARET_UNDO_STACK_H__ connectome-workbench-1.4.2/src/Common/CaretUnitsTypeEnum.cxx000066400000000000000000000255211360521144700241530ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CARET_UNITS_TYPE_ENUM_DECLARE__ #include "CaretUnitsTypeEnum.h" #undef __CARET_UNITS_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::CaretUnitsTypeEnum * \brief Units Type * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_caretUnitsTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void caretUnitsTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "CaretUnitsTypeEnum.h" * * Instatiate: * m_caretUnitsTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_caretUnitsTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_caretUnitsTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(caretUnitsTypeEnumComboBoxItemActivated())); * * Update the selection: * m_caretUnitsTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const CaretUnitsTypeEnum::Enum VARIABLE = m_caretUnitsTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ CaretUnitsTypeEnum::CaretUnitsTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ CaretUnitsTypeEnum::~CaretUnitsTypeEnum() { } /** * Initialize the enumerated metadata. */ void CaretUnitsTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(CaretUnitsTypeEnum(NONE, "NONE", "None")); enumData.push_back(CaretUnitsTypeEnum(HERTZ, "HERTZ", "Hertz")); enumData.push_back(CaretUnitsTypeEnum(METERS, "METERS", "Meters")); enumData.push_back(CaretUnitsTypeEnum(PARTS_PER_MILLION, "PARTS_PER_MILLION", "Parts Per Million")); enumData.push_back(CaretUnitsTypeEnum(RADIANS, "RADIANS", "Radians")); enumData.push_back(CaretUnitsTypeEnum(SECONDS, "SECONDS", "Seconds")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const CaretUnitsTypeEnum* CaretUnitsTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const CaretUnitsTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString CaretUnitsTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const CaretUnitsTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ CaretUnitsTypeEnum::Enum CaretUnitsTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = CaretUnitsTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const CaretUnitsTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type CaretUnitsTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString CaretUnitsTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const CaretUnitsTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ CaretUnitsTypeEnum::Enum CaretUnitsTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = CaretUnitsTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const CaretUnitsTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type CaretUnitsTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t CaretUnitsTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const CaretUnitsTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ CaretUnitsTypeEnum::Enum CaretUnitsTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = CaretUnitsTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const CaretUnitsTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type CaretUnitsTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void CaretUnitsTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void CaretUnitsTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(CaretUnitsTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void CaretUnitsTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(CaretUnitsTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/CaretUnitsTypeEnum.h000066400000000000000000000063301360521144700235750ustar00rootroot00000000000000#ifndef __CARET_UNITS_TYPE_ENUM_H__ #define __CARET_UNITS_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class CaretUnitsTypeEnum { public: /** * Enumerated values. */ enum Enum { /** none/unknown */ NONE, /** Hertz (frequency) */ HERTZ, /** Meters */ METERS, /** Parts per million */ PARTS_PER_MILLION, /** radians */ RADIANS, /** seconds */ SECONDS }; ~CaretUnitsTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: CaretUnitsTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const CaretUnitsTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __CARET_UNITS_TYPE_ENUM_DECLARE__ std::vector CaretUnitsTypeEnum::enumData; bool CaretUnitsTypeEnum::initializedFlag = false; int32_t CaretUnitsTypeEnum::integerCodeCounter = 0; #endif // __CARET_UNITS_TYPE_ENUM_DECLARE__ } // namespace #endif //__CARET_UNITS_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Common/ConnectivityCorrelation.cxx000066400000000000000000000727031360521144700252670ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CONNECTIVITY_CORRELATION_DECLARE__ #include "ConnectivityCorrelation.h" #undef __CONNECTIVITY_CORRELATION_DECLARE__ #include "CaretAssert.h" #include "CaretOMP.h" #include "dot_wrapper.h" using namespace caret; /** * \class caret::ConnectivityCorrelation * \brief Computes connectivity correlations * \ingroup Common * * Correlation from https://en.wikipedia.org/wiki/Pearson_product-moment_correlation_coefficient */ /** * Create new instance for data that is in one contiguous "chunk" of memory * * @param data * Points to first timepoint for first brainordinate * @param numberOfBrainordinates * Number of brainordinates * @param nextBrainordinateStride * Element offset between two consecutive brainordinates (eg: offset from first value for FIRST brainordinate * to first value for SECOND brainordinate, and so on) * @param numberOfTimePoints * Number of timepoints for each brainordinate * @param nextTimePointStride * Offset between two consecutive timepoints for a brainordinate * Use a value of "1" for contiguous data * @param errorMessageOut * Contains error information if NULL is returned * @return * Pointer to new instance or NULL if there is an error. * * Example: Nifti file with time-series data. Each 'brick' contains one timepoint * for all brainordinates. Brainordinates are "interleaved" * data = pointer to data * numberOfBrainordinates = dim[0] * dim[1] * dim[2] (sizeof a 'brick') * nextBrainordinateStride = 1 * numberOfTimePoints = number of timepoints * nextTimePointStride = dim[0] * dim[1] * dim[3] (sizeof a 'brick') */ ConnectivityCorrelation* ConnectivityCorrelation::newInstance(const float* data, const int64_t numberOfBrainordinates, const int64_t nextBrainordinateStride, const int64_t numberOfTimePoints, const int64_t nextTimePointStride, AString& errorMessageOut) { errorMessageOut.clear(); std::vector brainordinateDataPointers; for (int64_t i = 0; i < numberOfBrainordinates; i++) { const int64_t offset = i * nextBrainordinateStride; brainordinateDataPointers.push_back(data + offset); } CaretAssert(numberOfBrainordinates == static_cast(brainordinateDataPointers.size())); /* * While either of the other two factory methods can be called, the new instance * for brainordinates is faster when each brainordinates timepoint's are in a * contigous section of memory (nextTimePointStride == 1). */ ConnectivityCorrelation* instanceOut = newInstanceBrainordinates(brainordinateDataPointers, numberOfTimePoints, nextTimePointStride, errorMessageOut); return instanceOut; } /** * Create a new instance where each chunk of memory contains all timepoints for one brainordinate. * * @param brainordinateDataPointers * Each element points to all timepoints for one brainordinate * @param numberOfTimePoints * Number of timepoints for each brainordinate * @param nextTimePointStride * Offset between two consecutive timepoints for a brainordinate * Use a value of "1" for contiguous data * @param errorMessageOut * Contains error information if NULL is returned * @return * Pointer to new instance or NULL if there is an error. */ ConnectivityCorrelation* ConnectivityCorrelation::newInstanceBrainordinates(const std::vector& brainordinateDataPointers, const int64_t numberOfTimePoints, const int64_t nextTimePointStride, AString& errorMessageOut) { errorMessageOut.clear(); ConnectivityCorrelation* instanceOut = ((nextTimePointStride == 1) ? new ConnectivityCorrelation(DataTypeEnum::BRAINORDINATES_CONTIGUOUS_DATA) : new ConnectivityCorrelation(DataTypeEnum::BRAINORDINATES_NON_CONTIGUOUS_DATA)); const bool validFlag = instanceOut->initializeWithBrainordinates(brainordinateDataPointers, numberOfTimePoints, nextTimePointStride, errorMessageOut); if ( ! validFlag) { delete instanceOut; instanceOut = NULL; } return instanceOut; } /** * Create a new instance where each chunk of memory contains one timepoint for all brainordinates * * @param timePointDataPointers * Each element points to all brainordinates for one timepoint * @param numberOfBrainordinates * Number of brainordinates * @param nextBrainordinateStride * Element offset between two consecutive brainordinates (eg: offset from first value for FIRST brainordinate * to first value for SECOND brainordinate, and so on) * @param errorMessageOut * Contains error information if NULL is returned * @return * Pointer to new instance or NULL if there is an error. * * Example: GIFTI functional file (Metric) with time-series data. Each map contains one timepoint * for all brainordinates. * timePointDataPointers = pointer to each map's data * numberOfBrainordinates = Number of vertices in the GIFTI file * nextBrainordinateStride = 1 * numberOfTimePoints = number of maps in file (each map is one time point) */ ConnectivityCorrelation* ConnectivityCorrelation::newInstanceTimePoints(const std::vector& timePointDataPointers, const int64_t numberOfBrainordinates, const int64_t nextBrainordinateStride, AString& errorMessageOut) { errorMessageOut.clear(); ConnectivityCorrelation* instanceOut = new ConnectivityCorrelation(DataTypeEnum::TIMEPOINTS); const bool validFlag = instanceOut->initializeWithTimePoints(timePointDataPointers, numberOfBrainordinates, nextBrainordinateStride, errorMessageOut); if ( ! validFlag) { delete instanceOut; instanceOut = NULL; } return instanceOut; } /** * Constructor * * @param dataType * Type of data (brainordinate or timepoint) * */ ConnectivityCorrelation::ConnectivityCorrelation(const DataTypeEnum dataType) : m_dataType(dataType) { } /** * Destructor. */ ConnectivityCorrelation::~ConnectivityCorrelation() { } /** * Initialize a new instance where a chunk of memory contains all timepoints for one brainordinate. * * @param brainordinateDataPointers * Each element points to all timepoints for one brainordinate * @param numberOfTimePoints * Number of timepoints for each brainordinate * @param nextTimePointStride * Offset between two consecutive timepoints for a brainordinate * Use a value of "1" for contiguous data * @param errorMessageOut * Contains error information if NULL is returned * @return * Pointer to new instance or NULL if there is an error. */ bool ConnectivityCorrelation::initializeWithBrainordinates(const std::vector& brainordinateDataPointers, const int64_t numberOfTimePoints, const int64_t nextTimePointStride, AString& errorMessageOut) { switch (m_dataType) { case DataTypeEnum::BRAINORDINATES_CONTIGUOUS_DATA: break; case DataTypeEnum::BRAINORDINATES_NON_CONTIGUOUS_DATA: break; case DataTypeEnum::INVALID: CaretAssert(0); break; case DataTypeEnum::TIMEPOINTS: CaretAssert(0); break; } m_numberOfTimePoints = numberOfTimePoints; CaretAssert(brainordinateDataPointers.size() >= 2); CaretAssert(m_numberOfTimePoints >= 2); CaretAssert(nextTimePointStride >= 1); m_numberOfBrainordinates = static_cast(brainordinateDataPointers.size()); if (m_numberOfBrainordinates < 2) { errorMessageOut.appendWithNewLine("There must be at least two brainordinates"); } if (numberOfTimePoints < 2) { errorMessageOut.appendWithNewLine("There must be at least two time points"); } if (nextTimePointStride < 1) { errorMessageOut.appendWithNewLine("TimePoint stride must be at least one"); } if ( ! errorMessageOut.isEmpty()) { return false; } for (int64_t i = 0; i < m_numberOfBrainordinates; i++) { CaretAssertVectorIndex(brainordinateDataPointers, i); const float* dataPointer = brainordinateDataPointers[i]; CaretAssert(dataPointer); std::unique_ptr gd(new BrainordinateData(dataPointer, nextTimePointStride)); m_brainordinateData.push_back(std::move(gd)); } CaretAssert(static_cast(m_brainordinateData.size()) == m_numberOfBrainordinates); computeBrainordinateMeanAndSumSquared(); return true; } /** * Initialize a new instance where a chunk of memory contains all timepoints for one brainordinate. * * @param timePointDataPointers * Each element points to all brainordinates for one timepoint * @param numberOfBrainordinates * Number of brainordinates * @param nextBrainordinateStride * Element offset between two consecutive brainordinates (eg: offset from first value for FIRST brainordinate * to first value for SECOND brainordinate, and so on) * @param errorMessageOut * Contains error information if NULL is returned * @return * Pointer to new instance or NULL if there is an error. */ bool ConnectivityCorrelation::initializeWithTimePoints(const std::vector& timePointDataPointers, const int64_t numberOfBrainordinates, const int64_t nextBrainordinateStride, AString& errorMessageOut) { CaretAssert(m_dataType == DataTypeEnum::TIMEPOINTS); m_numberOfBrainordinates = numberOfBrainordinates; m_numberOfTimePoints = static_cast(timePointDataPointers.size()); CaretAssert(m_numberOfTimePoints >= 2); CaretAssert(nextBrainordinateStride >= 1); if (m_numberOfBrainordinates < 2) { errorMessageOut.appendWithNewLine("There must be at least two brainordinates"); } if (m_numberOfTimePoints < 2) { errorMessageOut.appendWithNewLine("There must be at least two time points"); } if (nextBrainordinateStride < 1) { errorMessageOut.appendWithNewLine("Brainordinate stride must be at least one"); } if ( ! errorMessageOut.isEmpty()) { return false; } for (int64_t i = 0; i < m_numberOfTimePoints; i++) { CaretAssertVectorIndex(timePointDataPointers, i); const float* dataPointer = timePointDataPointers[i]; CaretAssert(dataPointer); std::unique_ptr td(new TimePointData(dataPointer, nextBrainordinateStride)); m_timePointData.push_back(std::move(td)); } computeBrainordinateMeanAndSumSquared(); return true; } /** * Get correlation from the given brainordinate ROI to all other brainordinates * * @param brainordinateIndices * Index of brainordinates in the ROI to correlate to all other brainordinates * @param dataOut * Output with correlation values. */ void ConnectivityCorrelation::getCorrelationForBrainordinateROI(const std::vector& brainordinateIndices, std::vector& dataOut) { dataOut.resize(m_numberOfBrainordinates); std::fill(dataOut.begin(), dataOut.end(), 0.0); const int64_t numBrainordinatesInROI = static_cast(brainordinateIndices.size()); if (m_numberOfTimePoints > 1) { if (numBrainordinatesInROI > 0) { std::vector dataAverage(m_numberOfTimePoints, 0.0); for (int32_t iTime = 0; iTime < m_numberOfTimePoints; iTime++) { double timePointSum(0.0); for (int64_t jBrain = 0; jBrain < numBrainordinatesInROI; jBrain++) { CaretAssertVectorIndex(brainordinateIndices, jBrain); timePointSum += getDataValue(brainordinateIndices[jBrain], iTime); } dataAverage[iTime] = timePointSum / static_cast(numBrainordinatesInROI); } double sum(0.0); double sumSquared(0.0); for (int64_t j = 0; j < m_numberOfTimePoints; j++) { CaretAssertVectorIndex(dataAverage, j); const float d = dataAverage[j]; sum += d; sumSquared += (d * d); } const float mean = (sum / m_numberOfTimePoints); const float ssxxSquared = (sumSquared - (m_numberOfTimePoints * mean * mean)); const float ssxx = std::sqrt(ssxxSquared); const float* dataPtr = &dataAverage[0]; #pragma omp CARET_PARFOR schedule(dynamic) for (int32_t iBrain = 0; iBrain < m_numberOfBrainordinates; iBrain++) { CaretAssertVectorIndex(dataOut, iBrain); switch (m_dataType) { case DataTypeEnum::BRAINORDINATES_CONTIGUOUS_DATA: dataOut[iBrain] = correlationBrainordinateContiguousDataAux(dataPtr, mean, ssxx, iBrain); break; case DataTypeEnum::BRAINORDINATES_NON_CONTIGUOUS_DATA: dataOut[iBrain] = correlationBrainordinateNonContiguousDataAux(dataPtr, mean, ssxx, iBrain); break; case DataTypeEnum::INVALID: CaretAssert(0); break; case DataTypeEnum::TIMEPOINTS: dataOut[iBrain] = correlationTimePointDataAux(dataPtr, mean, ssxx, iBrain); break; } } } } } /** * Get correlation from the given brainordinate to all other brainordinates * * @param brainordinateIndex * Index of brainordinate to correlate to all other brainordinates * @param dataOut * Output with correlation values. */ void ConnectivityCorrelation::getCorrelationForBrainordinate(const int64_t brainordinateIndex, std::vector& dataOut) { CaretAssert(m_numberOfBrainordinates > 1); CaretAssert(m_numberOfTimePoints > 1); if (m_numberOfTimePoints > 0) { if (m_numberOfBrainordinates > 0) { dataOut.resize(m_numberOfBrainordinates); #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t i = 0; i < m_numberOfBrainordinates; i++) { CaretAssertVectorIndex(dataOut, i); switch (m_dataType) { case DataTypeEnum::BRAINORDINATES_CONTIGUOUS_DATA: dataOut[i] = correlationBrainordinateContiguousData(brainordinateIndex, i); break; case DataTypeEnum::BRAINORDINATES_NON_CONTIGUOUS_DATA: dataOut[i] = correlationBrainordinateNonContiguousData(brainordinateIndex, i); break; case DataTypeEnum::INVALID: CaretAssert(0); break; case DataTypeEnum::TIMEPOINTS: dataOut[i] = correlationTimePointData(brainordinateIndex, i); break; } } } } } /** * Get the correlation coefficient for the two given brainordinates * that contain CONTIGOUS data * * @param fromBrainordinateIndex * Index of a brainordinate * @param toBrainordinateIndex * Index of a second brainordinate. */ float ConnectivityCorrelation::correlationBrainordinateContiguousData(const int64_t fromBrainordinateIndex, const int64_t toBrainordinateIndex) const { CaretAssert(m_dataType == DataTypeEnum::BRAINORDINATES_CONTIGUOUS_DATA); CaretAssertVectorIndex(m_brainordinateData, fromBrainordinateIndex); const BrainordinateData* fromData = m_brainordinateData[fromBrainordinateIndex].get(); CaretAssertVectorIndex(m_meanSSData, fromBrainordinateIndex); const BrainordinateMeanSS* fromMeanSS = m_meanSSData[fromBrainordinateIndex].get(); return correlationBrainordinateContiguousDataAux(fromData->m_data, fromMeanSS->m_mean, fromMeanSS->m_sqrt_ssxx, toBrainordinateIndex); } /** * Get the correlation coefficient for the two given brainordinates * that contain CONTIGOUS data * * @param fromBrainordinateData * Data for the 'from' brainordinate * @param fromBrainordinateMean * Mean of the data for the 'from' brainordinate. * @param fromBrainordinateSSXX * Sum-squared of the data for the 'from' brainordinate. * @param toBrainordinateIndex * Index of the 'to' brainordinate. */ float ConnectivityCorrelation::correlationBrainordinateContiguousDataAux(const float* fromBrainordinateData, const float fromBrainordinateMean, const float fromBrainordinateSSXX, const int64_t toBrainordinateIndex) const { CaretAssert(m_dataType == DataTypeEnum::BRAINORDINATES_CONTIGUOUS_DATA); CaretAssertVectorIndex(m_brainordinateData, toBrainordinateIndex); const BrainordinateData* toGroup = m_brainordinateData[toBrainordinateIndex].get(); CaretAssertVectorIndex(m_meanSSData, toBrainordinateIndex); const BrainordinateMeanSS* toMeanSS = m_meanSSData[toBrainordinateIndex].get(); double xySum = dsdot(fromBrainordinateData, toGroup->m_data, m_numberOfTimePoints); const double ssxy = xySum - (m_numberOfTimePoints * fromBrainordinateMean * toMeanSS->m_mean); float correlationCoefficient = 0.0; if ((fromBrainordinateSSXX > 0.0) && (toMeanSS->m_sqrt_ssxx > 0.0)) { correlationCoefficient = (ssxy / (fromBrainordinateSSXX * toMeanSS->m_sqrt_ssxx)); } return correlationCoefficient; } /** * Get the correlation coefficient for the two given brainordinates * that contain NON-CONTIGOUS data * * @param fromBrainordinateIndex * Index of a brainordinate * @param toBrainordinateIndex * Index of a second brainordinate. */ float ConnectivityCorrelation::correlationBrainordinateNonContiguousData(const int64_t fromBrainordinateIndex, const int64_t toBrainordinateIndex) const { CaretAssertVectorIndex(m_brainordinateData, fromBrainordinateIndex); std::vector data(m_numberOfTimePoints); for (int32_t iTime = 0; iTime < m_numberOfTimePoints; iTime++) { data[iTime] = getDataValue(fromBrainordinateIndex, iTime); } CaretAssertVectorIndex(m_meanSSData, fromBrainordinateIndex); const BrainordinateMeanSS* fromMeanSS = m_meanSSData[fromBrainordinateIndex].get(); return correlationBrainordinateNonContiguousDataAux(&data[0], fromMeanSS->m_mean, fromMeanSS->m_sqrt_ssxx, toBrainordinateIndex); } /** * Get the correlation coefficient for the two given brainordinates * that contain NON-CONTIGOUS data * * @param fromBrainordinateData * Data for the 'from' brainordinate * @param fromBrainordinateMean * Mean of the data for the 'from' brainordinate. * @param fromBrainordinateSSXX * Sum-squared of the data for the 'from' brainordinate. * @param toBrainordinateIndex * Index of the 'to' brainordinate. */ float ConnectivityCorrelation::correlationBrainordinateNonContiguousDataAux(const float* fromBrainordinateData, const float fromBrainordinateMean, const float fromBrainordinateSSXX, const int64_t toBrainordinateIndex) const { CaretAssert(m_dataType == DataTypeEnum::BRAINORDINATES_NON_CONTIGUOUS_DATA); CaretAssertVectorIndex(m_brainordinateData, toBrainordinateIndex); const BrainordinateData* toGroup = m_brainordinateData[toBrainordinateIndex].get(); CaretAssertVectorIndex(m_meanSSData, toBrainordinateIndex); const BrainordinateMeanSS* toMeanSS = m_meanSSData[toBrainordinateIndex].get(); const float* toData = toGroup->m_data; const int64_t toStride = toGroup->m_dataStride; int64_t toOffset(0); double xySum(0.0); for (int32_t i = 0; i < m_numberOfTimePoints; i++) { xySum += (fromBrainordinateData[i] * toData[toOffset]); toOffset += toStride; } const double ssxy = xySum - (m_numberOfTimePoints * fromBrainordinateMean * toMeanSS->m_mean); float correlationCoefficient = 0.0; if ((fromBrainordinateSSXX > 0.0) && (toMeanSS->m_sqrt_ssxx > 0.0)) { correlationCoefficient = (ssxy / (fromBrainordinateSSXX * toMeanSS->m_sqrt_ssxx)); } return correlationCoefficient; } /** * Get the correlation coefficient for the two given brainordinates * that contain NON-CONTIGOUS data * * @param fromBrainordinateIndex * Index of a brainordinate * @param toBrainordinateIndex * Index of a second brainordinate. */ float ConnectivityCorrelation::correlationTimePointData(const int64_t fromBrainordinateIndex, const int64_t toBrainordinateIndex) const { CaretAssert(m_dataType == DataTypeEnum::TIMEPOINTS); CaretAssert((fromBrainordinateIndex >= 0) && (fromBrainordinateIndex < m_numberOfBrainordinates)); CaretAssert((toBrainordinateIndex >= 0) && (toBrainordinateIndex < m_numberOfBrainordinates)); std::vector data(m_numberOfTimePoints); for (int32_t iTime = 0; iTime < m_numberOfTimePoints; iTime++) { data[iTime] = getDataValue(fromBrainordinateIndex, iTime); } CaretAssertVectorIndex(m_meanSSData, fromBrainordinateIndex); const BrainordinateMeanSS* fromMeanSS = m_meanSSData[fromBrainordinateIndex].get(); return correlationTimePointDataAux(&data[0], fromMeanSS->m_mean, fromMeanSS->m_sqrt_ssxx, toBrainordinateIndex); } /** * Get the correlation coefficient for the two given brainordinates * that contain NON-CONTIGOUS data * * @param fromBrainordinateData * Data for the 'from' brainordinate * @param fromBrainordinateMean * Mean of the data for the 'from' brainordinate. * @param fromBrainordinateSSXX * Sum-squared of the data for the 'from' brainordinate. * @param toBrainordinateIndex * Index of the 'to' brainordinate. */ float ConnectivityCorrelation::correlationTimePointDataAux(const float* fromBrainordinateData, const float fromBrainordinateMean, const float fromBrainordinateSSXX, const int64_t toBrainordinateIndex) const { CaretAssert(m_dataType == DataTypeEnum::TIMEPOINTS); CaretAssert((toBrainordinateIndex >= 0) && (toBrainordinateIndex < m_numberOfBrainordinates)); CaretAssertVectorIndex(m_meanSSData, toBrainordinateIndex); const BrainordinateMeanSS* toMeanSS = m_meanSSData[toBrainordinateIndex].get(); double xySum(0.0); for (int32_t i = 0; i < m_numberOfTimePoints; i++) { CaretAssertVectorIndex(m_timePointData, i); const TimePointData* tpd = m_timePointData[i].get(); const int64_t toOffset = (toBrainordinateIndex * tpd->m_dataStride); xySum += (fromBrainordinateData[i] * tpd->m_data[toOffset]); } const double ssxy = xySum - (m_numberOfTimePoints * fromBrainordinateMean * toMeanSS->m_mean); float correlationCoefficient = 0.0; if ((fromBrainordinateSSXX > 0.0) && (toMeanSS->m_sqrt_ssxx > 0.0)) { correlationCoefficient = (ssxy / (fromBrainordinateSSXX * toMeanSS->m_sqrt_ssxx)); } return correlationCoefficient; } /** * Compute the mean and sum-squared for all brainordinates */ void ConnectivityCorrelation::computeBrainordinateMeanAndSumSquared() { const float numTimePointsFloat(m_numberOfTimePoints); /* * Set the size of the vector so that loop can run in parallel */ m_meanSSData.resize(m_numberOfBrainordinates); #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t i = 0; i < m_numberOfBrainordinates; i++) { double sum(0.0); double sumSquared(0.0); switch (m_dataType) { case DataTypeEnum::BRAINORDINATES_CONTIGUOUS_DATA: case DataTypeEnum::BRAINORDINATES_NON_CONTIGUOUS_DATA: { CaretAssertVectorIndex(m_brainordinateData, i); const float* data = m_brainordinateData[i]->m_data; CaretAssert(data); const int64_t stride = m_brainordinateData[i]->m_dataStride; for (int64_t j = 0; j < m_numberOfTimePoints; j++) { const int64_t offset = (j * stride); const float d = data[offset]; sum += d; sumSquared += (d * d); } } break; case DataTypeEnum::INVALID: CaretAssert(0); break; case DataTypeEnum::TIMEPOINTS: { for (int64_t j = 0; j < m_numberOfTimePoints; j++) { CaretAssertVectorIndex(m_timePointData, j); const int64_t offset = (i * m_timePointData[j]->m_dataStride); const float d = m_timePointData[j]->m_data[offset]; sum += d; sumSquared += (d * d); } } break; } const float mean = (sum / numTimePointsFloat); const float ssxxSquared = (sumSquared - (numTimePointsFloat * mean * mean)); const float ssxx = std::sqrt(ssxxSquared); BrainordinateMeanSS* bmss = new BrainordinateMeanSS(mean, ssxx); CaretAssertVectorIndex(m_meanSSData, i); m_meanSSData[i].reset(bmss); } CaretAssert(static_cast(m_meanSSData.size()) == m_numberOfBrainordinates); } connectome-workbench-1.4.2/src/Common/ConnectivityCorrelation.h000066400000000000000000000243021360521144700247040ustar00rootroot00000000000000#ifndef __CONNECTIVITY_CORRELATION_H__ #define __CONNECTIVITY_CORRELATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretAssert.h" #include "CaretObject.h" namespace caret { class ConnectivityCorrelation : public CaretObject { public: static ConnectivityCorrelation* newInstance(const float* data, const int64_t numberOfBrainordinates, const int64_t nextBrainordinateStride, const int64_t numberOfTimePoints, const int64_t nextTimePointStride, AString& errorMessageOut); static ConnectivityCorrelation* newInstanceBrainordinates(const std::vector& brainordinateDataPointers, const int64_t numberOfTimePoints, const int64_t nextTimePointStride, AString& errorMessageOut); static ConnectivityCorrelation* newInstanceTimePoints(const std::vector& timePointDataPointers, const int64_t numberOfBrainordinates, const int64_t nextBrainordinateStride, AString& errorMessageOut); /** * Destructor */ ~ConnectivityCorrelation(); ConnectivityCorrelation(const ConnectivityCorrelation&) = delete; ConnectivityCorrelation& operator=(const ConnectivityCorrelation&) = delete; void getCorrelationForBrainordinate(const int64_t brainordinateIndex, std::vector& dataOut); void getCorrelationForBrainordinateROI(const std::vector& brainordinateIndices, std::vector& dataOut); // ADD_NEW_METHODS_HERE private: enum class DataTypeEnum { INVALID, BRAINORDINATES_NON_CONTIGUOUS_DATA, BRAINORDINATES_CONTIGUOUS_DATA, TIMEPOINTS }; ConnectivityCorrelation(const DataTypeEnum dataType); /** * Contains timepoints for one brainordinate */ class BrainordinateData { public: /** * Constructor. * * @param data * Pointer to data containing a brainordinate's timepoints * @param dataStride * Offset between consecutive elements (1 for contiguous data) */ BrainordinateData(const float* data, const int64_t dataStride) : m_data(data), m_dataStride(dataStride) { } /* * @return Data value for this brainordinate at the given time point index * * @param timePointIndex * Index of the timepoint */ inline float getTimePointValue(const int64_t timePointIndex) const { return m_data[timePointIndex * m_dataStride]; } const float* m_data; const int64_t m_dataStride; }; class BrainordinateMeanSS { public: /* * Constructor * * @param mean * Mean value of 'data' * @param sqrtSumSquared * Square root of sum-squared of data */ BrainordinateMeanSS(const float mean, const float sqrtSumSquared) : m_mean(mean), m_sqrt_ssxx(sqrtSumSquared) { } const float m_mean; const float m_sqrt_ssxx; }; /** * Contains all brainordinate values for one timepoint */ class TimePointData { public: /** * Constructor. * * @param data * Pointer to data * @param dataStride * Offset between consecutive elements (1 for contiguous data) */ TimePointData(const float* data, const int64_t dataStride) : m_data(data), m_dataStride(dataStride) { } /* * @return Data value for this brainordinate at the given time point index * * @param timePointIndex * Index of the timepoint */ inline float getBrainordinateValue(const int64_t brainordinateIndex) const { return m_data[brainordinateIndex * m_dataStride]; } const float* m_data; const int64_t m_dataStride; }; /** * Get the data value for the given brainordinate and timepoint indices * * @param brainordinateIndex * Index of the brainordinate * @param timePointIndex * Index of the time point * @return * The data value */ inline float getDataValue(const int64_t brainordinateIndex, const int64_t timePointIndex) const { float dataValue(0.0); switch (m_dataType) { case DataTypeEnum::BRAINORDINATES_CONTIGUOUS_DATA: case DataTypeEnum::BRAINORDINATES_NON_CONTIGUOUS_DATA: CaretAssertVectorIndex(m_brainordinateData, brainordinateIndex); dataValue = m_brainordinateData[brainordinateIndex]->getTimePointValue(timePointIndex); break; case DataTypeEnum::INVALID: CaretAssert(0); break; case DataTypeEnum::TIMEPOINTS: CaretAssertVectorIndex(m_timePointData, timePointIndex); dataValue = m_timePointData[timePointIndex]->getBrainordinateValue(brainordinateIndex); break; } return dataValue; } bool initializeWithBrainordinates(const std::vector& brainordinateDataPointers, const int64_t numberOfTimePoints, const int64_t nextTimePointStride, AString& errorMessageOut); bool initializeWithTimePoints(const std::vector& timePointDataPointers, const int64_t numberOfBrainordinates, const int64_t nextBrainordinateStride, AString& errorMessageOut); void computeBrainordinateMeanAndSumSquared(); float correlationBrainordinateContiguousData(const int64_t fromBrainordinateIndex, const int64_t toBrainordinateIndex) const; float correlationBrainordinateContiguousDataAux(const float* fromBrainordinateData, const float fromBrainordinateMean, const float fromBrainordinateSSXX, const int64_t toBrainordinateIndex) const; float correlationBrainordinateNonContiguousData(const int64_t fromBrainordinateIndex, const int64_t toBrainordinateIndex) const; float correlationBrainordinateNonContiguousDataAux(const float* fromBrainordinateData, const float fromBrainordinateMean, const float fromBrainordinateSSXX, const int64_t toBrainordinateIndex) const; float correlationTimePointData(const int64_t fromBrainordinateIndex, const int64_t toBrainordinateIndex) const; float correlationTimePointDataAux(const float* fromBrainordinateData, const float fromBrainordinateMean, const float fromBrainordinateSSXX, const int64_t toBrainordinateIndex) const; DataTypeEnum m_dataType = DataTypeEnum::INVALID; int64_t m_numberOfBrainordinates = -1; int64_t m_numberOfTimePoints = -1; std::vector> m_brainordinateData; std::vector> m_timePointData; std::vector> m_meanSSData; // ADD_NEW_MEMBERS_HERE }; #ifdef __CONNECTIVITY_CORRELATION_DECLARE__ // #endif // __CONNECTIVITY_CORRELATION_DECLARE__ } // namespace #endif //__CONNECTIVITY_CORRELATION_H__ connectome-workbench-1.4.2/src/Common/CubicSpline.cxx000066400000000000000000000071271360521144700226050ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CubicSpline.h" #include "CaretAssert.h" using namespace caret; CubicSpline::CubicSpline() { } CubicSpline CubicSpline::hermite(float frac, bool lowEdge, bool highEdge) {//these equations are derived from hermite basis functions, plug the commented m0, m1 into the hermite representation to rederive CaretAssert(frac > -0.01f && frac < 1.01f);//give some leeway for rounding errors CubicSpline ret; float frac2 = frac * frac; float frac3 = frac2 * frac; if (lowEdge) {//edge case: m0 = p[2] - p[1] if (highEdge) {//edge case: m1 = p[2] - p[1] - makes it linear interpolation - why are you doing cubic spline with only 2 points? ret.m_weights[0] = 0.0f; ret.m_weights[1] = 1.0f - frac; ret.m_weights[2] = frac; ret.m_weights[3] = 0.0f; } else {//m1 = (p[3] - p[1]) / 2 ret.m_weights[0] = 0.0f; ret.m_weights[1] = 0.5f * frac3 - 0.5 * frac2 - frac + 1.0f;//.5t^3 - .5t^2 - t + 1 ret.m_weights[2] = -frac3 + frac2 + frac;//-t^3 + t^2 + t ret.m_weights[3] = 0.5f * frac3 - frac2;//.5t^3 - t^2 } } else {//m0 = (p[2] - p[0]) / 2 if (highEdge) {//edge case: m1 = p[2] - p[1] ret.m_weights[0] = -0.5f * frac3 + frac2 - 0.5f * frac;//-.5t^3 + t^2 - .5t ret.m_weights[1] = frac3 - 2.0f * frac2 + 1;//t^3 - 2t^2 + 1 ret.m_weights[2] = -0.5f * frac3 + frac2 + 0.5f * frac;//-.5t^3 + t^2 + .5t ret.m_weights[3] = 0.0f; } else {//m1 = (p[3] - p[1]) / 2 -- majority case ret.m_weights[0] = -0.5f * frac3 + frac2 - 0.5f * frac;//-.5t^3 + t^2 - .5t ret.m_weights[1] = 1.5f * frac3 - 2.5f * frac2 + 1.0f;//1.5t^3 - 2.5t^2 + 1 ret.m_weights[2] = -1.5f * frac3 + 2.0f * frac2 + 0.5f * frac;//-1.5t^3 + 2t^2 + .5t ret.m_weights[3] = 0.5f * frac3 - frac2;//.5t^3 - t^2 } } return ret; } CubicSpline CubicSpline::bspline(float frac, bool lowEdge, bool highEdge) { CaretAssert(frac > -0.01f && frac < 1.01f);//give some leeway for rounding errors CubicSpline ret; float frac2 = frac * frac; float frac3 = frac2 * frac; ret.m_weights[0] = (-frac3 + 3.0f * frac2 - 3.0f * frac + 1.0f) / 6.0f;//the standard blending function ret.m_weights[1] = (3.0f * frac3 - 6.0f * frac2 + 4.0f) / 6.0f; ret.m_weights[2] = (-3.0f * frac3 + 3.0f * frac2 + 3.0f * frac + 1.0f) / 6.0f; ret.m_weights[3] = frac3 / 6.0f; if (lowEdge) { ret.m_weights[1] += ret.m_weights[0];//pretend outside range repeats the edge value ret.m_weights[0] = 0.0f;//ignore input outside the range } if (highEdge) { ret.m_weights[2] += ret.m_weights[3];//ditto ret.m_weights[3] = 0.0f; } return ret; } connectome-workbench-1.4.2/src/Common/CubicSpline.h000066400000000000000000000051161360521144700222260ustar00rootroot00000000000000#ifndef __CUBIC_SPLINE_H__ #define __CUBIC_SPLINE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ namespace caret { class CubicSpline { float m_weights[4]; CubicSpline(); public: ///takes as input the fraction in [0, 1] along the middle (used) range of the spline, low and high edge set whether it doesn't have p[0] or p[3] to use, respectively static CubicSpline hermite(float frac, bool lowEdge, bool highEdge); ///NOTE: data should be deconvolved before using this spline static CubicSpline bspline(float frac, bool lowEdge, bool highEdge); //splines will be reused, so this part should be fast for the majority case (testing for if it is an edge case would slow it down for the majority case) ///evaluate the spline with these samples inline float evaluate(const float p0, const float p1, const float p2, const float p3) const { return p0 * m_weights[0] + p1 * m_weights[1] + p2 * m_weights[2] + p3 * m_weights[3]; } ///convenience function for edge evaluating without a dummy argument inline float evalLowEdge(const float p1, const float p2, const float p3) { return p1 * m_weights[1] + p2 * m_weights[2] + p3 * m_weights[3]; } ///convenience function for edge evaluating without a dummy argument inline float evalHighEdge(const float p0, const float p1, const float p2) { return p0 * m_weights[0] + p1 * m_weights[1] + p2 * m_weights[2]; } ///convenience function for edge evaluating without dummy arguments inline float evalBothEdge(const float p1, const float p2) { return p1 * m_weights[1] + p2 * m_weights[2]; } }; } #endif //__CUBIC_SPLINE_H__ connectome-workbench-1.4.2/src/Common/DataCompressZLib.cxx000066400000000000000000000100551360521144700235450ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /*========================================================================= Program: Visualization Toolkit Module: $RCSfile: DataCompressZLib.cxx,v $ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "DataCompressZLib.h" #include "MathFunctions.h" #include "zlib.h" using namespace caret; //---------------------------------------------------------------------------- DataCompressZLib::DataCompressZLib() { this->compressionLevel = Z_DEFAULT_COMPRESSION; } //---------------------------------------------------------------------------- DataCompressZLib::~DataCompressZLib() { } int32_t DataCompressZLib::getCompressionLevel() { return this->compressionLevel; } void DataCompressZLib::setCompressionLevel(const int32_t compressionLevel) { this->compressionLevel = MathFunctions::clamp(compressionLevel, 0, 9); } //---------------------------------------------------------------------------- uint64_t DataCompressZLib::compressData(const unsigned char* uncompressedData, uint64_t uncompressedSize, unsigned char* compressedData, const uint64_t compressionSpace) { uLongf compressedSize = compressionSpace; Bytef* cd = reinterpret_cast(compressedData); const Bytef* ud = reinterpret_cast(uncompressedData); // Call zlib's compress function. if(compress2(cd, &compressedSize, ud, uncompressedSize, this->compressionLevel) != Z_OK) { //vtkErrorMacro("Zlib error while compressing data."); return 0; } return compressedSize; } //---------------------------------------------------------------------------- uint64_t DataCompressZLib::uncompressData(const unsigned char* compressedData, uint64_t compressedSize, unsigned char* uncompressedData, uint64_t uncompressedSize) { uLongf decSize = uncompressedSize; Bytef* ud = reinterpret_cast(uncompressedData); const Bytef* cd = reinterpret_cast(compressedData); // Call zlib's uncompress function. if(uncompress(ud, &decSize, cd, compressedSize) != Z_OK) { //vtkErrorMacro("Zlib error while uncompressing data."); return 0; } // Make sure the output size matched that expected. if(decSize != uncompressedSize) { //vtkErrorMacro("Decompression produced incorrect size.\n" // "Expected " << uncompressedSize << " and got " << decSize); return 0; } return decSize; } //---------------------------------------------------------------------------- unsigned long DataCompressZLib::getMaximumCompressionSpace(unsigned long size) { // ZLib specifies that destination buffer must be 0.1% larger + 12 bytes. return size + (size+999)/1000 + 12; } connectome-workbench-1.4.2/src/Common/DataCompressZLib.h000066400000000000000000000062041360521144700231730ustar00rootroot00000000000000#ifndef __DATA_COMPRESS_ZLIB_H__ #define __DATA_COMPRESS_ZLIB_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /*========================================================================= Program: Visualization Toolkit Module: $RCSfile: DataCompressZLib.h,v $ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ // .NAME DataCompressZLib - Data compression using zlib. // .SECTION Description // DataCompressZLib provides a concrete vtkDataCompressor class // using zlib for compressing and uncompressing data. #include #include "CaretObject.h" namespace caret { /* * Copied from vtkZLibDataCompresson. */ class DataCompressZLib : public CaretObject { public: DataCompressZLib(); ~DataCompressZLib(); // Description: // Get the maximum space that may be needed to store data of the // given uncompressed size after compression. This is the minimum // size of the output buffer that can be passed to the four-argument // Compress method. unsigned long getMaximumCompressionSpace(unsigned long size); // Description: // Get/Set the compression level. //vtkSetClampMacro(CompressionLevel, int, 0, 9); //vtkGetMacro(CompressionLevel, int); int32_t getCompressionLevel(); void setCompressionLevel(const int32_t compressionLevel); // Compression method required by vtkDataCompressor. uint64_t compressData(const unsigned char* uncompressedData, uint64_t uncompressedSize, unsigned char* compressedData, const uint64_t compressionSpace); // Decompression method required by vtkDataCompressor. uint64_t uncompressData(const unsigned char* compressedData, uint64_t compressedSize, unsigned char* uncompressedData, uint64_t uncompressedSiz); protected: int compressionLevel; }; } // namespace #endif // __DATA_COMPRESS_ZLIB_H__ connectome-workbench-1.4.2/src/Common/DataFile.cxx000066400000000000000000000223311360521144700220500ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretLogger.h" #include "DataFile.h" #include "DataFileContentInformation.h" #include "DataFileException.h" #include "FileInformation.h" using namespace caret; /** * Constructor. */ DataFile::DataFile() : CaretObject(), DataFileInterface() { this->initializeMembersDataFile(); } /** * Destructor. */ DataFile::~DataFile() { this->initializeMembersDataFile(); } /** * Copy constructor. * @param df * Data file that is copied. */ DataFile::DataFile(const DataFile& df) : CaretObject(df), DataFileInterface() { this->copyHelperDataFile(df); } /** * Assignment operator. * @param df * Contents that is assigned to this file. * @return * This file assigned the contents of "df". */ DataFile& DataFile::operator=(const DataFile& df) { if (this != &df) { CaretObject::operator=(df); this->copyHelperDataFile(df); } return *this; } /** * Assists with copying file's contents. */ void DataFile::copyHelperDataFile(const DataFile& df) { m_filename = df.m_filename; m_fileReadWarnings = df.m_fileReadWarnings; m_modifiedFlag = false; m_timeOfLastReadOrWrite = QDateTime(); } /** * Initialize the members of the data file. */ void DataFile::initializeMembersDataFile() { m_filename = ""; m_fileReadWarnings.clear(); m_modifiedFlag = false; m_timeOfLastReadOrWrite = QDateTime(); } /** * Clear the contents of the file. */ void DataFile::clear() { this->initializeMembersDataFile(); } /** * @return Name of the data file including any path. */ AString DataFile::getFileName() const { return m_filename; } /** * @return Name of the data file excluding any path. */ AString DataFile::getFileNameNoPath() const { FileInformation fileInfo(m_filename); return fileInfo.getFileName(); } /** * Set the name of the data file. * This method is virtual so NEVER call it from * a constructor. Instead, use setFileNameProtected(). * * @param filename * New name of data file. */ void DataFile::setFileName(const AString& filename) { setFileNameProtected(filename); } /** * Set the name of the data file. * This method is NOT virtual so it may be called * from a constructor. * * @param filename * New name of data file. */ void DataFile::setFileNameProtected(const AString& filename) { if (m_filename != filename) { m_filename = filename; this->setModified(); } } /** * Add information about the file to the data file information. * * @param dataFileInformation * Consolidates information about a data file. */ void DataFile::addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) { dataFileInformation.addNameAndValue("Name", getFileName()); } /** * Set the status to modified. */ void DataFile::setModified() { m_modifiedFlag = true; } /** * Set the status to unmodified. */ void DataFile::clearModified() { m_modifiedFlag = false; /* * This method, clearModified(), is called by all file * types at the conclusion of readFile() and writeFile(). */ setTimeOfLastReadOrWrite(); } /** * Is the object modified? * @return true if modified, else false. */ bool DataFile::isModified() const { return m_modifiedFlag; } /** * @return True if a file with the current file name exists, else false. */ bool DataFile::exists() const { FileInformation fileInfo(getFileName()); return fileInfo.exists(); } /** * Is the filename a path on the network (http:// etc) * @param filename * Name of file. * @return true if filename appears to be a network path. */ bool DataFile::isFileOnNetwork(const AString& filename) { if (filename.startsWith("http://") || filename.startsWith("https://")) { return true; } return false; } /** * If the filename is local, make sure the file exists and * its permissions allow the file to be read. * * @param filename * Name of file. * @throws DataFileException * If there is a problem that will prevent the file from being read. */ void DataFile::checkFileReadability(const AString& filename) { if (filename.isEmpty()) { throw DataFileException("Name of file for reading is empty."); } if (isFileOnNetwork(filename)) { return; } FileInformation fileInfo(filename); if (fileInfo.exists() == false) { throw DataFileException(filename, "File does not exist."); } if (fileInfo.isDirectory()) { throw DataFileException(filename, "Filename is a directory, not a file."); } if (fileInfo.isReadable() == false) { throw DataFileException(filename, "File is not readable due its permissions."); } } /** * If the filename is local, see if the file exists and * its permissions allow the file to be written. * * @param filename * Name of file. * @throws DataFileException * If there is a problem that will prevent the file from being read. */ void DataFile::checkFileWritability(const AString& filename) { if (filename.isEmpty()) { throw DataFileException("Name of file for writing is empty."); } if (isFileOnNetwork(filename)) { return; } FileInformation fileInfo(filename); if (fileInfo.exists()) { if (fileInfo.isDirectory()) { throw DataFileException(filename, "Filename is a directory, not a file."); } if (fileInfo.isWritable() == false) { throw DataFileException(filename, "File is not writable due its permissions."); } } } /** * Add a warning (non-fatal) message about some issue while reading file file. * * @param warning * Warning message about some issue. */ void DataFile::addFileReadWarning(const AString& warning) { m_fileReadWarnings.appendWithNewLine(warning); } /** * @return Any warning message from reading the data file. * * NOTE: When this method is called, the warning message * is cleared for this file. */ AString DataFile::getFileReadWarnings() const { const AString warningMessage = m_fileReadWarnings; m_fileReadWarnings.clear(); return warningMessage; } /** * Set the time this file was last read or written to the current time. */ void DataFile::setTimeOfLastReadOrWrite() { m_timeOfLastReadOrWrite = getLastModifiedTime(); } /** * @return True if this file been modified since it was last read or written. * (modified by an external program)? * * If any of these conditions are met, false is returned: * (1) The name is empty; (2) The file is on the network; * (3) The file does not exist; (4) The modified time * from the file system is invalid; (5) The last time this * file was read or written is invalid. */ bool DataFile::isModifiedSinceTimeOfLastReadOrWrite() const { const QDateTime lastModTime = getLastModifiedTime(); if (lastModTime.isNull()) { return false; } if (m_timeOfLastReadOrWrite.isNull()) { return false; } CaretLogFine("Testing reload of " + getFileNameNoPath() + " last read/write: " + m_timeOfLastReadOrWrite.toString(Qt::ISODate) + " last modified: " + lastModTime.toString(Qt::ISODate) + ((m_timeOfLastReadOrWrite == lastModTime) ? " EQUAL" : " NOT EQUAL")); /* * If last modified time is newer than * time of file read or written */ if (lastModTime != m_timeOfLastReadOrWrite) { return true; } return false; } /** * @return True if this file been modified since it was last read or written. * (modified by an external program)? * * If any of these conditions are met, a null (.isNull()) is returned: * (1) The name is empty; (2) The file is on the network; * (3) The file does not exist; (4) The modified time * from the file system is invalid. */ QDateTime DataFile::getLastModifiedTime() const { QDateTime lastModTime; const AString name = getFileName(); if (name.isEmpty()) { return lastModTime; } if (isFileOnNetwork(name)) { return lastModTime; } QFileInfo fileInfo(name); if ( ! fileInfo.exists()) { return lastModTime; } lastModTime = fileInfo.lastModified(); return lastModTime; } connectome-workbench-1.4.2/src/Common/DataFile.h000066400000000000000000000067061360521144700215050ustar00rootroot00000000000000#ifndef __DATAFILE_H__ #define __DATAFILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretObject.h" #include "DataFileInterface.h" namespace caret { class DataFileContentInformation; /** * Abstract Data File. */ class DataFile : public CaretObject, public DataFileInterface { protected: DataFile(); virtual ~DataFile(); DataFile(const DataFile& s); DataFile& operator=(const DataFile&); void setFileNameProtected(const AString& filename); public: virtual AString getFileName() const; virtual AString getFileNameNoPath() const; virtual void setFileName(const AString& filename); virtual void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation); virtual void setPreferOnDiskReading(const bool&) { } /** * Read the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully read. */ virtual void readFile(const AString& filename) = 0; /** * Write the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully written. */ virtual void writeFile(const AString& filename) = 0; virtual void setModified(); virtual void clearModified(); virtual bool isModified() const; virtual void clear(); static bool isFileOnNetwork(const AString& filename); void checkFileReadability(const AString& filename); void checkFileWritability(const AString& filename); bool exists() const; void addFileReadWarning(const AString& warning); AString getFileReadWarnings() const; bool isModifiedSinceTimeOfLastReadOrWrite() const; private: void copyHelperDataFile(const DataFile& df); void initializeMembersDataFile(); void setTimeOfLastReadOrWrite(); QDateTime getLastModifiedTime() const; /** name of data file */ AString m_filename; /** warnings set when file was read */ mutable AString m_fileReadWarnings; /** modification status */ bool m_modifiedFlag; QDateTime m_timeOfLastReadOrWrite; }; } // namespace #endif // __DATAFILE_H__ connectome-workbench-1.4.2/src/Common/DataFileContentCopyMoveInterface.h000066400000000000000000000051351360521144700263360ustar00rootroot00000000000000#ifndef __DATA_FILE_CONTENT_COPY_MOVE_INTERFACE_H__ #define __DATA_FILE_CONTENT_COPY_MOVE_INTERFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" /** * \class caret::DataFileContentCopyMoveInterface * \brief Interface for data file that can copy their content to other files of same type * \ingroup Common */ namespace caret { class DataFile; class DataFileContentCopyMoveParameters; class DataFileContentCopyMoveInterface : public CaretObject { public: DataFileContentCopyMoveInterface() { } virtual ~DataFileContentCopyMoveInterface() { } /** * @return Pointer to DataFile that implements this interface */ virtual DataFile* getAsDataFile() = 0; /** * Append content from the given data file copy/move interface to this instance * * @param copyMoveParameters * Parameters used for copy/move. * @throws DataFileException * If there is an error. */ virtual void appendContentFromDataFile(const DataFileContentCopyMoveParameters& copyMoveParameters) = 0; /** * @return A new instance of the same file type. File is empty. */ virtual DataFileContentCopyMoveInterface* newInstanceOfDataFile() const = 0; private: DataFileContentCopyMoveInterface(const DataFileContentCopyMoveInterface&); DataFileContentCopyMoveInterface& operator=(const DataFileContentCopyMoveInterface&); // ADD_NEW_MEMBERS_HERE }; #ifdef __DATA_FILE_CONTENT_COPY_MOVE_INTERFACE_DECLARE__ // #endif // __DATA_FILE_CONTENT_COPY_MOVE_INTERFACE_DECLARE__ } // namespace #endif //__DATA_FILE_CONTENT_COPY_MOVE_INTERFACE_H__ connectome-workbench-1.4.2/src/Common/DataFileContentCopyMoveParameters.cxx000066400000000000000000000053171360521144700271160ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __DATA_FILE_CONTENT_COPY_MOVE_PARAMETERS_DECLARE__ #include "DataFileContentCopyMoveParameters.h" #undef __DATA_FILE_CONTENT_COPY_MOVE_PARAMETERS_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::DataFileContentCopyMoveParameters * \brief Parameters for copying/moving data in data files. * \ingroup Common */ /** * Constructor for data file that is copied/moved with all parameters off. * * @param dataFileCopyMoveInterface * Interface of file that is copied/moved. * @param windowIndex * Index of window (negative if invalid). */ DataFileContentCopyMoveParameters::DataFileContentCopyMoveParameters(const DataFileContentCopyMoveInterface* dataFileCopyMoveInterface, const int32_t windowIndex) : CaretObject(), m_dataFileCopyMoveInterface(dataFileCopyMoveInterface), m_windowIndex(windowIndex), m_optionSelectedItems(false) { } /** * Destructor. */ DataFileContentCopyMoveParameters::~DataFileContentCopyMoveParameters() { } /** * @return Copy/Move interface for file whose content is copy/moved. */ const DataFileContentCopyMoveInterface* DataFileContentCopyMoveParameters::getDataFileCopyMoveInterfaceToCopy() const { return m_dataFileCopyMoveInterface; } /** * @return Index of window (invalid if negative). */ int32_t DataFileContentCopyMoveParameters::getWindowIndex() const { return m_windowIndex; } /** * @return Is the option for copy/move selected items set? */ bool DataFileContentCopyMoveParameters::isOptionSelectedItems() const { return m_optionSelectedItems; } /** * Set the option for copy/move selected items. * * @param optionSelectedItems * New status for copy/move of selected items. */ void DataFileContentCopyMoveParameters::setOptionSelectedItems(const bool optionSelectedItems) { m_optionSelectedItems = optionSelectedItems; } connectome-workbench-1.4.2/src/Common/DataFileContentCopyMoveParameters.h000066400000000000000000000044711360521144700265430ustar00rootroot00000000000000#ifndef __DATA_FILE_CONTENT_COPY_MOVE_PARAMETERS_H__ #define __DATA_FILE_CONTENT_COPY_MOVE_PARAMETERS_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" namespace caret { class DataFileContentCopyMoveInterface; class DataFileContentCopyMoveParameters : public CaretObject { public: DataFileContentCopyMoveParameters(const DataFileContentCopyMoveInterface* dataFileCopyMoveInterface, const int32_t windowIndex); virtual ~DataFileContentCopyMoveParameters(); const DataFileContentCopyMoveInterface* getDataFileCopyMoveInterfaceToCopy() const; int32_t getWindowIndex() const; bool isOptionSelectedItems() const; void setOptionSelectedItems(const bool optionSelectedItems); // ADD_NEW_METHODS_HERE private: DataFileContentCopyMoveParameters(const DataFileContentCopyMoveParameters&); DataFileContentCopyMoveParameters& operator=(const DataFileContentCopyMoveParameters&); const DataFileContentCopyMoveInterface* m_dataFileCopyMoveInterface; const int32_t m_windowIndex; bool m_optionSelectedItems; // ADD_NEW_MEMBERS_HERE }; #ifdef __DATA_FILE_CONTENT_COPY_MOVE_PARAMETERS_DECLARE__ // #endif // __DATA_FILE_CONTENT_COPY_MOVE_PARAMETERS_DECLARE__ } // namespace #endif //__DATA_FILE_CONTENT_COPY_MOVE_PARAMETERS_H__ connectome-workbench-1.4.2/src/Common/DataFileContentInformation.cxx000066400000000000000000000137251360521144700256200ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __DATA_FILE_CONTENT_INFORMATION_DECLARE__ #include "DataFileContentInformation.h" #undef __DATA_FILE_CONTENT_INFORMATION_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::DataFileContentInformation * \brief Assembles and provides information about a data file. * \ingroup Common */ /** * Constructor. */ DataFileContentInformation::DataFileContentInformation() : CaretObject() { /* * Initialize options */ setOptionFlag(OPTION_SHOW_MAP_INFORMATION, true); setOptionFlag(OPTION_SHOW_CIFTI_LABEL_MAPPING, false); } /** * Destructor. */ DataFileContentInformation::~DataFileContentInformation() { } /** * Add a name and value pair. * * @param name * The name. * @param value * The value. */ void DataFileContentInformation::addNameAndValue(const AString& name, const AString& value) { QChar colonChar = ' '; if (name.indexNotOf(' ') >= 0) { colonChar = ':'; } m_namesAndValues.push_back(std::make_pair((name + colonChar), value)); } /** * Add a name and value pair. * * @param name * The name. * @param value * The value. */ void DataFileContentInformation::addNameAndValue(const AString& name, const int32_t value) { addNameAndValue(name, AString::number(value)); // m_namesAndValues.push_back(std::make_pair((name + ":"), // AString::number(value))); } /** * Add a name and value pair. * * @param name * The name. * @param value * The value. */ void DataFileContentInformation::addNameAndValue(const AString& name, const int64_t value) { addNameAndValue(name, AString::number(value)); // m_namesAndValues.push_back(std::make_pair((name + ":"), // AString::number(value))); } /** * Add a name and value pair. * * @param name * The name. * @param value * The value. */ void DataFileContentInformation::addNameAndValue(const AString& name, const double value, const int32_t precision) { addNameAndValue(name, AString::number(value, 'f', precision)); // m_namesAndValues.push_back(std::make_pair((name + ":"), // AString::number(value, 'f', precision))); } /** * Add a name and value pair. * * @param name * The name. * @param value * The value. */ void DataFileContentInformation::addNameAndValue(const AString& name, const bool value) { addNameAndValue(name, AString::fromBool(value)); // m_namesAndValues.push_back(std::make_pair((name + ":"), // AString::fromBool(value))); } /** * Add freeform text. * * @param text * Text that is added. */ void DataFileContentInformation::addText(const AString& text) { m_text.append(text); } /** * @return All of the information in a string. * * The names and labels are formatted so that the labels and * values are aligned. */ AString DataFileContentInformation::getInformationInString() const { AString textOut; const int32_t numNamesAndValues = static_cast(m_namesAndValues.size()); if (numNamesAndValues > 0) { int32_t longestLabelLength = 0; for (int32_t i = 0; i < numNamesAndValues; i++) { longestLabelLength = std::max(m_namesAndValues[i].first.length(), longestLabelLength); } longestLabelLength += 3; for (int32_t i = 0; i < numNamesAndValues; i++) { AString label = m_namesAndValues[i].first; textOut.appendWithNewLine(label.leftJustified(longestLabelLength) + m_namesAndValues[i].second); } textOut.append("\n"); } textOut.append(m_text); return textOut; } /** * Is an option flag on? * * @param optionFlag * The option flag. * @return * True if the option flag is on, else false. */ bool DataFileContentInformation::isOptionFlag(const OptionFlag optionFlag) const { std::map::const_iterator iter = m_optionFlags.find(optionFlag); if (iter != m_optionFlags.end()) { return iter->second; } return false; } /** * Set an option flag. * * @param optionFlag * The option flag. * @param flagValue * New value for option flag. */ void DataFileContentInformation::setOptionFlag(const OptionFlag optionFlag, const bool flagValue) { std::map::iterator iter = m_optionFlags.find(optionFlag); if (iter != m_optionFlags.end()) { iter->second = flagValue; } else { m_optionFlags.insert(std::pair(optionFlag, flagValue)); } } connectome-workbench-1.4.2/src/Common/DataFileContentInformation.h000066400000000000000000000063331360521144700252420ustar00rootroot00000000000000#ifndef __DATA_FILE_CONTENT_INFORMATION_H__ #define __DATA_FILE_CONTENT_INFORMATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" namespace caret { class DataFileContentInformation : public CaretObject { public: /** * Option flags for commands. * All options are off by default. * If an option should be on by default, call setOptionFlag() * from this class' constructor. */ enum OptionFlag { /** * Show information about each map for files that support maps. */ OPTION_SHOW_MAP_INFORMATION, /* * Show detailed information about CIFTI Label Mappings */ OPTION_SHOW_CIFTI_LABEL_MAPPING }; DataFileContentInformation(); virtual ~DataFileContentInformation(); void addNameAndValue(const AString& name, const AString& value); void addNameAndValue(const AString& name, const int32_t value); void addNameAndValue(const AString& name, const int64_t value); void addNameAndValue(const AString& name, const double value, const int32_t precision = 3); void addNameAndValue(const AString& name, const bool value); void addText(const AString& text); AString getInformationInString() const; bool isOptionFlag(const OptionFlag optionFlag) const; void setOptionFlag(const OptionFlag optionFlag, const bool flagValue); private: DataFileContentInformation(const DataFileContentInformation&); DataFileContentInformation& operator=(const DataFileContentInformation&); public: // ADD_NEW_METHODS_HERE private: std::vector > m_namesAndValues; AString m_text; std::map m_optionFlags; // ADD_NEW_MEMBERS_HERE }; #ifdef __DATA_FILE_CONTENT_INFORMATION_DECLARE__ // #endif // __DATA_FILE_CONTENT_INFORMATION_DECLARE__ } // namespace #endif //__DATA_FILE_CONTENT_INFORMATION_H__ connectome-workbench-1.4.2/src/Common/DataFileException.cxx000066400000000000000000000075631360521144700237410ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "DataFileException.h" #include "FileInformation.h" #include using namespace caret; /** * Constructor. * */ DataFileException::DataFileException() : CaretException() { this->initializeMembersDataFileException(); } /** * Constructor that uses stack trace from the exception * passed in as a parameter. * * @param e Any exception whose stack trace becomes * this exception's stack trace. * */ DataFileException::DataFileException( const CaretException& e) : CaretException(e) { this->initializeMembersDataFileException(); } /** * Constructor that accepts the exception messge. * * @param s Description of the exception. * */ DataFileException::DataFileException(const AString& s) : CaretException(s) { this->initializeMembersDataFileException(); } /** * Constructor that accepts name of file and the exception message. * * The exception message will become name of the file, a newline, * path of the file, a newline, and the description of the * exception. * * @param dataFileName Name of the data file that caused exception. * @param s Description of the exception. * */ DataFileException::DataFileException(const AString& dataFileName, const AString& s) : CaretException(s) { this->initializeMembersDataFileException(); AString msg; if ( ! dataFileName.isEmpty()) { FileInformation fileInfo(dataFileName); const AString pathName = fileInfo.getPathName(); msg.appendWithNewLine("NAME OF FILE: " + fileInfo.getFileName()); if ( ! pathName.isEmpty()) { if (pathName != ".") { msg.appendWithNewLine("PATH TO FILE: " + pathName); } } msg.append("\n"); } msg.appendWithNewLine(s); this->setExceptionDescription(msg); } /** * Copy Constructor. * @param e * Exception that is copied. */ DataFileException::DataFileException(const DataFileException& e) : CaretException(e) { this->errorInvalidStructure = e.errorInvalidStructure; } /** * Assignment operator. * @param e * Exception that is copied. * @return * Copy of the exception. */ DataFileException& DataFileException::operator=(const DataFileException& e) { if (this != &e) { CaretException::operator=(e); this->errorInvalidStructure = e.errorInvalidStructure; } return *this; } /** * Destructor */ DataFileException::~DataFileException() throw() { } void DataFileException::initializeMembersDataFileException() { this->errorInvalidStructure = false; } /** * @return True if the file could not be read due * to an invalid structure. */ bool DataFileException::isErrorInvalidStructure() const { return this->errorInvalidStructure; } /** * Set the invalid structure status when the file * cannot be read due to the structure being invalid. * * @param status * New invalid structure status (true if invalid). */ void DataFileException::setErrorInvalidStructure(const bool status) { this->errorInvalidStructure = status; } connectome-workbench-1.4.2/src/Common/DataFileException.h000066400000000000000000000033441360521144700233570ustar00rootroot00000000000000#ifndef __DATAFILEEXCEPTION_H__ #define __DATAFILEEXCEPTION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretException.h" namespace caret { /** * An exception thrown during data file operations. */ class DataFileException : public CaretException { public: DataFileException(); DataFileException(const CaretException& e); DataFileException(const AString& s); DataFileException(const AString& dataFileName, const AString& s); DataFileException(const DataFileException& e); DataFileException& operator=(const DataFileException& e); virtual ~DataFileException() throw(); bool isErrorInvalidStructure() const; void setErrorInvalidStructure(const bool status); private: void initializeMembersDataFileException(); bool errorInvalidStructure; }; } // namespace #endif // __DATAFILEEXCEPTION_H__ connectome-workbench-1.4.2/src/Common/DataFileInterface.h000066400000000000000000000050741360521144700233230ustar00rootroot00000000000000#ifndef __DATAFILEINTERFACE_H__ #define __DATAFILEINTERFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "TracksModificationInterface.h" namespace caret { /** * Abstract class for data file behavior. */ class DataFileInterface : public TracksModificationInterface { protected: DataFileInterface() { } virtual ~DataFileInterface() { } private: DataFileInterface(const DataFileInterface& s); DataFileInterface& operator=(const DataFileInterface&); public: /** * Is the file empty (contains no data)? * * @return * true if the file is empty, else false. */ virtual bool isEmpty() const = 0; /** * Get the name of the data file. * * @return Name of the data file. */ virtual AString getFileName() const = 0; /** * Set the name of the data file. * * @param filename * New name of data file. */ virtual void setFileName(const AString& filename) = 0; /** * Read the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully read. */ virtual void readFile(const AString& filename) = 0; /** * Write the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully written. */ virtual void writeFile(const AString& filename) = 0; }; } // namespace #endif // __DATAFILEINTERFACE_H__ connectome-workbench-1.4.2/src/Common/DataFileTypeEnum.cxx000066400000000000000000001064721360521144700235500ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __DATA_FILE_TYPE_ENUM_DECLARE__ #include "DataFileTypeEnum.h" #undef __DATA_FILE_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" using namespace caret; /** * \class caret::DataFileTypeEnum * \brief An enumerated type for data files. */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumberated value. * @param guiName * Name displayed in the user-interface * @param overlayTypeName * Name displayed in overlay type combo box * @param fileIsUsedWithOneStructure * True if file is used with ONE structure (eg node file (surface, metric, etc). * @param fileExtensionOne * File extension * @param fileExtensionTwo * Additional File extension * @param fileExtensionThree * Additional File extension */ DataFileTypeEnum::DataFileTypeEnum(const Enum enumValue, const AString& name, const AString& guiName, const AString& overlayTypeName, const bool fileIsUsedWithOneStructure, const AString& fileExtensionOne, const AString& fileExtensionTwo, const AString& fileExtensionThree, const AString& fileExtensionFour) { this->enumValue = enumValue; this->integerCode = DataFileTypeEnum::integerCodeGenerator++; this->name = name; this->guiName = guiName; this->overlayTypeName = overlayTypeName; this->oneStructureFlag = fileIsUsedWithOneStructure; if (fileExtensionOne.isEmpty() == false) { this->fileExtensions.push_back(fileExtensionOne); } if (fileExtensionTwo.isEmpty() == false) { this->fileExtensions.push_back(fileExtensionTwo); } if (fileExtensionThree.isEmpty() == false) { this->fileExtensions.push_back(fileExtensionThree); } if (fileExtensionFour.isEmpty() == false) { this->fileExtensions.push_back(fileExtensionFour); } AString filterText = this->guiName + " Files ("; for (std::vector::const_iterator iter = this->fileExtensions.begin(); iter != this->fileExtensions.end(); iter++) { if (iter != fileExtensions.begin()) { filterText += " "; } filterText += ("*." + *iter); } filterText += ")"; this->qFileDialogNameFilter = filterText; } /** * Destructor. */ DataFileTypeEnum::~DataFileTypeEnum() { } /** * Initialize the enumerated metadata. */ void DataFileTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(DataFileTypeEnum(ANNOTATION, "ANNOTATION", "Annotation", "ANNOTATION", false, "wb_annot")); enumData.push_back(DataFileTypeEnum(ANNOTATION_TEXT_SUBSTITUTION, "ANNOTATION_TEXT_SUBSTITUTION", "Annotation Text Substitution", "ANNOTATION TEXT SUBSTITUTION", false, "wb_annsub.csv")); enumData.push_back(DataFileTypeEnum(BORDER, "BORDER", "Border", "BORDER", true, "border", "wb_border")); enumData.push_back(DataFileTypeEnum(CONNECTIVITY_DENSE, "CONNECTIVITY_DENSE", "CIFTI - Dense", "CONNECTIVITY", false, "dconn.nii")); enumData.push_back(DataFileTypeEnum(CONNECTIVITY_DENSE_DYNAMIC, "CONNECTIVITY_DENSE_DYNAMIC", "CIFTI - Dense Dynamic", "CONNECTIVITY DYNAMIC", false, "dynconn.nii")); enumData.push_back(DataFileTypeEnum(CONNECTIVITY_DENSE_LABEL, "CONNECTIVITY_DENSE_LABEL", "CIFTI - Dense Label", "CIFTI LABELS", false, "dlabel.nii")); enumData.push_back(DataFileTypeEnum(CONNECTIVITY_DENSE_PARCEL, "CONNECTIVITY_DENSE_PARCEL", "CIFTI - Dense Parcel", "CIFTI DENSE PARCEL", false, "dpconn.nii")); enumData.push_back(DataFileTypeEnum(CONNECTIVITY_DENSE_SCALAR, "CONNECTIVITY_DENSE_SCALAR", "CIFTI - Dense Scalar", "CIFTI SCALARS", false, "dscalar.nii")); enumData.push_back(DataFileTypeEnum(CONNECTIVITY_DENSE_TIME_SERIES, "CONNECTIVITY_DENSE_TIME_SERIES", "CIFTI - Dense Data Series", "DATA SERIES", false, "dtseries.nii")); enumData.push_back(DataFileTypeEnum(CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY, "CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY", "CIFTI - Fiber Orientations TEMPORARY", "FIBER ORIENTATION TEMPORARY", false, "fiberTEMP.nii")); enumData.push_back(DataFileTypeEnum(CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY, "CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY", "CIFTI - Fiber Trajectory TEMPORARY", "FIBER TRAJECTORY TEMPORARY", false, "trajTEMP.wbsparse")); enumData.push_back(DataFileTypeEnum(CONNECTIVITY_PARCEL, "CONNECTIVITY_PARCEL", "CIFTI - Parcel", "CIFTI PARCEL", false, "pconn.nii")); enumData.push_back(DataFileTypeEnum(CONNECTIVITY_PARCEL_DENSE, "CONNECTIVITY_PARCEL_DENSE", "CIFTI - Parcel Dense", "CIFTI PARCEL DENSE", false, "pdconn.nii")); enumData.push_back(DataFileTypeEnum(CONNECTIVITY_PARCEL_LABEL, "CONNECTIVITY_PARCEL_LABEL", "CIFTI - Parcel Label", "CIFTI PARCEL LABEL", false, "plabel.nii")); enumData.push_back(DataFileTypeEnum(CONNECTIVITY_PARCEL_SCALAR, "CONNECTIVITY_PARCEL_SCALAR", "CIFTI - Parcel Scalar", "CIFTI PARCEL SCALAR", false, "pscalar.nii")); enumData.push_back(DataFileTypeEnum(CONNECTIVITY_PARCEL_SERIES, "CONNECTIVITY_PARCEL_SERIES", "CIFTI - Parcel Series", "CIFTI PARCEL SERIES", false, "ptseries.nii")); enumData.push_back(DataFileTypeEnum(CONNECTIVITY_SCALAR_DATA_SERIES, "CONNECTIVITY_SCALAR_DATA_SERIES", "CIFTI - Scalar Data Series", "CIFTI SCALAR DATA SERIES", false, "sdseries.nii")); enumData.push_back(DataFileTypeEnum(FOCI, "FOCI", "Foci", "FOCI", false, "foci", "wb_foci")); enumData.push_back(DataFileTypeEnum(IMAGE, "IMAGE", "Image", "IMAGE", false, "jpg", "jpeg", "png", "ppm")); enumData.push_back(DataFileTypeEnum(LABEL, "LABEL", "Label", "LABEL", true, "label.gii")); enumData.push_back(DataFileTypeEnum(METRIC, "METRIC", "Metric", "METRIC", true, "func.gii", "shape.gii")); enumData.push_back(DataFileTypeEnum(METRIC_DYNAMIC, "METRIC_DYNAMIC", "Metric - Dynamic", "METRIC_DYNAMIC", true, "func_dynconn")); // this file is never written enumData.push_back(DataFileTypeEnum(PALETTE, "PALETTE", "Palette", "PALETTE", false, "palette", "wb_palette")); enumData.push_back(DataFileTypeEnum(RGBA, "RGBA", "RGBA", "RGBA", true, "rgba.gii")); enumData.push_back(DataFileTypeEnum(SCENE, "SCENE", "Scene", "SCENE", false, "scene", "wb_scene")); enumData.push_back(DataFileTypeEnum(SPECIFICATION, "SPECIFICATION", "Specification", "SPECIFICATION", false, "spec", "wb_spec")); enumData.push_back(DataFileTypeEnum(SURFACE, "SURFACE", "Surface", "SURFACE", true, "surf.gii")); enumData.push_back(DataFileTypeEnum(UNKNOWN, "UNKNOWN", "Unknown", "UNKNOWN", false, "unknown")); enumData.push_back(DataFileTypeEnum(VOLUME, "VOLUME", "Volume", "VOLUME", false, "nii", "nii.gz")); enumData.push_back(DataFileTypeEnum(VOLUME_DYNAMIC, "VOLUME_DYNAMIC", "Volume - Dynamic", "VOLUME DYNAMIC", false, "vol_dynconn")); // this file is never written } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const DataFileTypeEnum* DataFileTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const DataFileTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString DataFileTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const DataFileTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ DataFileTypeEnum::Enum DataFileTypeEnum::fromName(const AString& nameIn, bool* isValidOut) { AString name = nameIn; if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = UNKNOWN; /* * Maintain compatibility with early spec files */ if (name.startsWith("SURFACE_")) { CaretLogWarning("Obsolete spec file tag \"" + name + "\", replace with SURFACE"); name = "SURFACE"; } else if (name.startsWith("VOLUME_")) { CaretLogWarning("Obsolete spec file tag \"" + name + "\", replace with VOLUME"); name = "VOLUME"; } for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const DataFileTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name \"" + name + "\" failed to match enumerated value for type DataFileTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString DataFileTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const DataFileTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get a short GUI string representation of the enumerated type. * Removes any "Connectivity - " or " TEMPORARY" from the toGuiName(). * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString DataFileTypeEnum::toShortGuiName(Enum enumValue) { const AString typeName = DataFileTypeEnum::toGuiName(enumValue); const AString connectivityPrefix("Connectivity - "); const int connectivityPrefixLength = connectivityPrefix.length(); const AString temporarySuffix(" TEMPORARY"); const int temporarySuffixLength = temporarySuffix.length(); AString text = typeName; if (text.startsWith(connectivityPrefix)) { text = text.mid(connectivityPrefixLength); } if (text.endsWith(temporarySuffix)) { text = text.left(text.length() - temporarySuffixLength); } return text; } /** * Get a Overlay Type Name representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString DataFileTypeEnum::toOverlayTypeName(Enum enumValue) { if (initializedFlag == false) initialize(); const DataFileTypeEnum* enumInstance = findData(enumValue); return enumInstance->overlayTypeName; } /** * Get an enumerated value corresponding to its overlay type name. * @param s * Overlay Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ DataFileTypeEnum::Enum DataFileTypeEnum::fromOverlayTypeName(const AString& overlayTypeName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = UNKNOWN; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const DataFileTypeEnum& d = *iter; if (d.overlayTypeName == overlayTypeName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName \"" + overlayTypeName + "\" failed to match enumerated value for type DataFileTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t DataFileTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const DataFileTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Get an enumerated value corresponding to its QFileDialog filter name. * @param qFileDialogNameFilter * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ DataFileTypeEnum::Enum DataFileTypeEnum::fromQFileDialogFilter(const AString& qFileDialogNameFilter, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = UNKNOWN; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const DataFileTypeEnum& d = *iter; if (d.qFileDialogNameFilter == qFileDialogNameFilter) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("qFileDialogNameFilter \"" + qFileDialogNameFilter + " \"failed to match enumerated value for type DataFileTypeEnum")); } return enumValue; } /** * Get the file filter text for use in a QFileDialog. * * @param enumValue * Enumerated type for file filter. * @return * Text containing file filter. */ AString DataFileTypeEnum::toQFileDialogFilter(const Enum enumValue) { if (initializedFlag == false) initialize(); const DataFileTypeEnum* enumInstance = findData(enumValue); return enumInstance->qFileDialogNameFilter; } /** * Is the file type used with a one structure (node based file, surface, label, etc.)? * @param enumValue * Enumerated type for file filter. * @return true if used with one structure, else false. */ bool DataFileTypeEnum::isFileUsedWithOneStructure(const Enum enumValue) { if (initializedFlag == false) initialize(); const DataFileTypeEnum* enumInstance = findData(enumValue); return enumInstance->oneStructureFlag; } /** * @return All valid file extensions for the given enum value. * @param enumValue * Enumerated type for file extensions. */ std::vector DataFileTypeEnum::getAllFileExtensions(const Enum enumValue) { if (initializedFlag == false) initialize(); const DataFileTypeEnum* enumInstance = findData(enumValue); return enumInstance->fileExtensions; } /** * @return All valid file extensions for all file types except UNKNOWN * and dynanmic connectivity files * * @param includeNonWritableFileTypesFlag * If true, include non-writable files such as dynamic connectvity files */ std::vector DataFileTypeEnum::getFilesExtensionsForEveryFile(const bool includeNonWritableFileTypesFlag) { std::vector allExtensions; for (std::vector::iterator enumIter = enumData.begin(); enumIter != enumData.end(); enumIter++) { bool validFlag(true); switch (enumIter->enumValue) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: validFlag = includeNonWritableFileTypesFlag; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: break; case DataFileTypeEnum::METRIC: break; case DataFileTypeEnum::METRIC_DYNAMIC: validFlag = includeNonWritableFileTypesFlag; break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: validFlag = false; break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: validFlag = includeNonWritableFileTypesFlag; break; } if (validFlag) { allExtensions.insert(allExtensions.end(), enumIter->fileExtensions.begin(), enumIter->fileExtensions.end()); } } return allExtensions; } /** * If the given filename does not contain a file extension that is valid * for the given data file type, add the first valid file extension from * the given data file type. * * @param filename * Name of file that may not have the correct file extension. * @param enumValue * The data file type. * @return * Input file name to which a file extension may have been added. */ AString DataFileTypeEnum::addFileExtensionIfMissing(const AString& filenameIn, const Enum enumValue) { AString filename = filenameIn; if (initializedFlag == false) initialize(); const DataFileTypeEnum* enumInstance = findData(enumValue); /* * See if filename ends with any of the available extensions for the * given data file type. */ for (std::vector::const_iterator iter = enumInstance->fileExtensions.begin(); iter != enumInstance->fileExtensions.end(); iter++) { const AString ext = ("." + *iter); if (filename.endsWith(ext)) { return filename; } } /* * Add default extension. */ const AString defaultExtension = DataFileTypeEnum::toFileExtension(enumValue); filename += ("." + defaultExtension); return filename; } /** * Get the primary file extension for the file type. * @param enumValue * The data file type. * @return * Extension for file type. */ AString DataFileTypeEnum::toFileExtension(const Enum enumValue) { if (initializedFlag == false) initialize(); const DataFileTypeEnum* enumInstance = findData(enumValue); AString ext = "file"; if (enumInstance->fileExtensions.empty() == false) { ext = enumInstance->fileExtensions[0]; } return ext; } /*** * Does the filename have a valid extension for the given file type? * * @param filename * Name of file that may not have the correct file extension. * @param enumValue * The data file type. * @return * True if the filename has a valid extension, else false. */ bool DataFileTypeEnum::isValidFileExtension(const AString& filename, const Enum enumValue) { if (initializedFlag == false) initialize(); const DataFileTypeEnum* enumInstance = findData(enumValue); /* * See if filename ends with any of the available extensions for the * given data file type. */ for (std::vector::const_iterator iter = enumInstance->fileExtensions.begin(); iter != enumInstance->fileExtensions.end(); iter++) { const AString ext = ("." + *iter); if (filename.endsWith(ext)) { return true; } } return false; } /** * For the filename, match its extension to a DataFileType enumerated type. * @param filename * Name of file. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ DataFileTypeEnum::Enum DataFileTypeEnum::fromFileExtension(const AString& filename, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = UNKNOWN; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const DataFileTypeEnum& d = *iter; const std::vector extensions = iter->fileExtensions; for (std::vector::const_iterator extIter = extensions.begin(); extIter != extensions.end(); extIter++) { /* * Need to add "." to avoid ambiguous matching ("dconn.nii, pdconn.nii) */ const AString extensionWithDot = ("." + *extIter); if (filename.endsWith(extensionWithDot)) { enumValue = d.enumValue; validFlag = true; break; } } if (validFlag) { break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("filename \"" + filename + " \"has no matching extensions in DataFileTypeEnum")); } return enumValue; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ DataFileTypeEnum::Enum DataFileTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = UNKNOWN; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const DataFileTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code \"" + AString::number(integerCode) + " \"failed to match enumerated value for type DataFileTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. * @param options * Bitwise mask for options */ void DataFileTypeEnum::getAllEnums(std::vector& allEnums, const uint32_t options) { if (initializedFlag == false) initialize(); allEnums.clear(); const bool includeDenseDynamicFlag = (options & OPTIONS_INCLUDE_CONNECTIVITY_DENSE_DYNAMIC); const bool includeMetricDynamicFlag = (options & OPTIONS_INCLUDE_METRIC_DENSE_DYNAMIC); const bool includeVolumeDynamicFlag = (options & OPTIONS_INCLUDE_VOLUME_DENSE_DYNAMIC); const bool includeUnknownFlag = (options & OPTIONS_INCLUDE_UNKNOWN); for (const auto dataType : enumData) { bool addEnumFlag(true); switch (dataType.enumValue) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: if ( ! includeDenseDynamicFlag) { addEnumFlag = false; } break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: break; case DataFileTypeEnum::METRIC: break; case DataFileTypeEnum::METRIC_DYNAMIC: if ( ! includeMetricDynamicFlag) { addEnumFlag = false; } break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: if ( ! includeUnknownFlag) { addEnumFlag = false; } break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: if ( ! includeVolumeDynamicFlag) { addEnumFlag = false; } break; } if (addEnumFlag) { allEnums.push_back(dataType.enumValue); } } } /** * Is the enumerated type a connectivity enumerated type? * @param enumValue * The enumerated type value. * @return * true if so, else false. */ bool DataFileTypeEnum::isConnectivityDataType(const Enum enumValue) { const AString name = DataFileTypeEnum::toName(enumValue); if (name.startsWith("CONNECTIVITY")) { return true; } return false; } /** * Get all connectivity enumerated type values. * @param connectivityEnumsOut * Will be loaded with all connectivity enumerated types. */ void DataFileTypeEnum::getAllConnectivityEnums(std::vector& connectivityEnumsOut) { if (initializedFlag == false) initialize(); connectivityEnumsOut.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { if (DataFileTypeEnum::isConnectivityDataType(iter->enumValue)) { connectivityEnumsOut.push_back(iter->enumValue); } } } connectome-workbench-1.4.2/src/Common/DataFileTypeEnum.h000066400000000000000000000160701360521144700231670ustar00rootroot00000000000000#ifndef __DATA_FILE_TYPE_ENUM__H_ #define __DATA_FILE_TYPE_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class DataFileTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Annotation */ ANNOTATION, /** Annotation Text Substitution */ ANNOTATION_TEXT_SUBSTITUTION, /** Border */ BORDER, /** Connectivity - Dense */ CONNECTIVITY_DENSE, /** Connectivity - Dense Dynamic (correlate from time-series)*/ CONNECTIVITY_DENSE_DYNAMIC, /** Connectivity - Dense Label */ CONNECTIVITY_DENSE_LABEL, /** Connectivity - Dense Parcel */ CONNECTIVITY_DENSE_PARCEL, /** Connectivity - Dense Scalar */ CONNECTIVITY_DENSE_SCALAR, /** Connectivity - Dense Time Series */ CONNECTIVITY_DENSE_TIME_SERIES, /** Connectivity - Fiber Orientations TEMPORARY */ CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY, /** Connectivity - Fiber Trajectory TEMPORARY */ CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY, /** Connectivity - Parcel */ CONNECTIVITY_PARCEL, /** Connectivity - Parcel Dense*/ CONNECTIVITY_PARCEL_DENSE, /** Connectivity - Parcel Label*/ CONNECTIVITY_PARCEL_LABEL, /** Connectivity - Parcel Scalar */ CONNECTIVITY_PARCEL_SCALAR, /** Connectivity - Parcel Series */ CONNECTIVITY_PARCEL_SERIES, /** Connectivity - Scalar Data Series */ CONNECTIVITY_SCALAR_DATA_SERIES, /** Foci */ FOCI, /** Image */ IMAGE, /** Labels */ LABEL, /** Metric */ METRIC, /** Metric Dynamic Connectivity */ METRIC_DYNAMIC, /** Palette */ PALETTE, /** RGBA */ RGBA, /** Scene */ SCENE, /** Specification */ SPECIFICATION, /** Surface */ SURFACE, /** Unknown */ UNKNOWN, /** Volume */ VOLUME, /** Volume Dynamic Connectivity*/ VOLUME_DYNAMIC }; /** * Options for getting all enumerated values. * Bitwise 'OR' for multiple options */ enum Options { /** No options */ OPTIONS_NONE = 0, /** Include the dense dynamic data file type */ OPTIONS_INCLUDE_CONNECTIVITY_DENSE_DYNAMIC = 1, /** Include the metric dynamic data file type */ OPTIONS_INCLUDE_METRIC_DENSE_DYNAMIC = 2, /** Include the volume dynamic data file type */ OPTIONS_INCLUDE_VOLUME_DENSE_DYNAMIC = 4, /** Include the unknown data file type */ OPTIONS_INCLUDE_UNKNOWN = 8 }; ~DataFileTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static AString toShortGuiName(Enum enumValue); static AString toOverlayTypeName(Enum enumValue); static Enum fromOverlayTypeName(const AString& overlayTypeName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums, const uint32_t options); static Enum fromQFileDialogFilter(const AString& qFileDialogNameFilter, bool* isValidOut); static AString toQFileDialogFilter(const Enum enumValue); static Enum fromFileExtension(const AString& filename, bool* isValidOut); static AString toFileExtension(const Enum enumValue); static bool isValidFileExtension(const AString& filename, const Enum enumValue); static std::vector getAllFileExtensions(const Enum enumValue); static std::vector getFilesExtensionsForEveryFile(const bool includeNonWritableFileTypesFlag = false); static bool isFileUsedWithOneStructure(const Enum enumValue); static bool isConnectivityDataType(const Enum enumValue); static void getAllConnectivityEnums(std::vector& connectivityEnumsOut); static AString addFileExtensionIfMissing(const AString& filename, const Enum enumValue); private: DataFileTypeEnum(const Enum enumValue, const AString& name, const AString& guiName, const AString& overlayTypeName, const bool fileIsUsedWithOneStructure, const AString& fileExtensionOne, const AString& fileExtensionTwo = "", const AString& fileExtensionThree = "", const AString& fileExtensionFour = ""); static const DataFileTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Automatically generates the integer code */ static int32_t integerCodeGenerator; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; /** Name for use in overlay selection */ AString overlayTypeName; /** Extension(s) for the file */ std::vector fileExtensions; /** Name filter for use in a QFileDialog */ AString qFileDialogNameFilter; /** Is file for use with one structure */ bool oneStructureFlag; }; #ifdef __DATA_FILE_TYPE_ENUM_DECLARE__ std::vector DataFileTypeEnum::enumData; bool DataFileTypeEnum::initializedFlag = false; int32_t DataFileTypeEnum::integerCodeGenerator = 0; #endif // __DATA_FILE_TYPE_ENUM_DECLARE__ } // namespace #endif //__DATA_FILE_TYPE_ENUM__H_ connectome-workbench-1.4.2/src/Common/DescriptiveStatistics.cxx000066400000000000000000000430571360521144700247430ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __DESCRIPTIVE_STATISTICS_DECLARE__ #include "DescriptiveStatistics.h" #undef __DESCRIPTIVE_STATISTICS_DECLARE__ #include #include #include #include "CaretAssert.h" #include "MathFunctions.h" using namespace caret; using namespace std; /** * \class caret::DescriptiveStatistics * \brief Contains descriptive statics for some group of data. * * Provides descriptive statistics for a group of data * that includes mininmum and maximum values, percentiles, * a histogram, and statistical measurements. */ /** * Constructor that allows setting the number of elements in the histogram. * * @param histogramNumberOfElements * Number of elemnents for the histogram. Must be positive!! * @param percentileDivisions * Number of percentiles. */ DescriptiveStatistics::DescriptiveStatistics(const int64_t histogramNumberOfElements, const int64_t percentileDivisions) : CaretObject() { m_histogramNumberOfElements = histogramNumberOfElements; CaretAssert(m_histogramNumberOfElements > 2); m_percentileDivisions = percentileDivisions; CaretAssert(m_percentileDivisions > 2); m_lastInputNumberOfValues = -1; m_histogram = new int64_t[m_histogramNumberOfElements]; m_positivePercentiles = new float[m_percentileDivisions]; m_negativePercentiles = new float[m_percentileDivisions]; this->invalidateData(); } /** * Destructor. */ DescriptiveStatistics::~DescriptiveStatistics() { if (m_histogram != NULL) { delete[] m_histogram; } if (m_positivePercentiles != NULL) { delete[] m_positivePercentiles; } if (m_negativePercentiles != NULL) { delete[] m_negativePercentiles; } } /** * Invalidate data so that next call to update() * recreates the statistics. */ void DescriptiveStatistics::invalidateData() { m_lastInputNumberOfValues = -1; m_validCount = 0; m_infCount = 0; m_negInfCount = 0; m_nanCount = 0; m_minimumValue = 0.0; m_maximumValue = 0.0; m_containsNegativeValues = false; m_containsPositiveValues = false; m_mean = 0.0; m_median = 0.0; m_standardDeviationPopulation = 0.0; m_standardDeviationSample = 0.0; } /** * Update the statistics with the given data but * limit the range of values to the given * minimum and maximum values. * * @param values * Values for which statistics are calculated. * @param numberOfValues * Number of elements in values array. * @param mostPositiveValueInclusive * Values more positive than this value are excluded. * @param leastPositiveValueInclusive * Values less positive than this value are excluded. * @param leastNegativeValueInclusive * Values less negative than this value are excluded. * @param mostNegativeValueInclusive * Values more negative than this value are excluded. * @param includeZeroValues * If true zero values (very near zero) are included. */ void DescriptiveStatistics::update(const std::vector& values, const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) { const float* valuesArray = (values.empty() ? NULL : &values[0]); const int64_t numberOfValues = (values.empty() ? 0 : values.size()); this->update(valuesArray, numberOfValues, mostPositiveValueInclusive, leastPositiveValueInclusive, leastNegativeValueInclusive, mostNegativeValueInclusive, includeZeroValues); } /** * Update the statistics with the given data but * limit the range of values to the given * minimum and maximum values. * * @param values * Values for which statistics are calculated. * @param numberOfValues * Number of elements in values array. * @param mostPositiveValueInclusive * Values more positive than this value are excluded. * @param leastPositiveValueInclusive * Values less positive than this value are excluded. * @param leastNegativeValueInclusive * Values less negative than this value are excluded. * @param mostNegativeValueInclusive * Values more negative than this value are excluded. * @param includeZeroValues * If true zero values (very near zero) are included. */ void DescriptiveStatistics::update(const float* valuesIn, const int64_t numberOfValuesIn, const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) { bool needUpdate = false; if (m_lastInputNumberOfValues <= 0) { needUpdate = true; } else { if ((numberOfValuesIn != m_lastInputNumberOfValues) || (mostPositiveValueInclusive != m_lastInputMostPositiveValueInclusive) || (leastPositiveValueInclusive != m_lastInputLeastPositiveValueInclusive) || (leastNegativeValueInclusive != m_lastInputLeastNegativeValueInclusive) || (mostNegativeValueInclusive != m_lastInputMostNegativeValueInclusive) || (includeZeroValues != m_lastInputIncludeZeroValues)) { needUpdate = true; } } if (needUpdate == false) { return; } this->invalidateData(); m_lastInputNumberOfValues = numberOfValuesIn; m_lastInputMostPositiveValueInclusive = mostPositiveValueInclusive; m_lastInputLeastPositiveValueInclusive = leastPositiveValueInclusive; m_lastInputLeastNegativeValueInclusive = leastNegativeValueInclusive; m_lastInputMostNegativeValueInclusive = mostNegativeValueInclusive; m_lastInputIncludeZeroValues = includeZeroValues; std::vector valuesVector; valuesVector.reserve(numberOfValuesIn); for (int64_t i = 0; i < numberOfValuesIn; i++) { bool useIt = false; const float v = valuesIn[i]; if (v >= leastPositiveValueInclusive) { if (v <= mostPositiveValueInclusive) { useIt = true; } } else if (v <= leastNegativeValueInclusive) { if (v >= mostNegativeValueInclusive) { useIt = true; } } if (useIt) { if (includeZeroValues == false) { if (MathFunctions::isZero(v)) { useIt = false; } } if (useIt) { valuesVector.push_back(v); } } } const float* values = (valuesVector.empty() ? NULL : &valuesVector[0]); const int64_t numberOfValues = static_cast(valuesVector.size()); std::fill(m_histogram, m_histogram + m_histogramNumberOfElements, 0.0); std::fill(m_positivePercentiles, m_positivePercentiles + m_percentileDivisions, 0.0); std::fill(m_negativePercentiles, m_negativePercentiles + m_percentileDivisions, 0.0); if (numberOfValues <= 0) { return; } if (numberOfValues == 1) { const float v = values[0]; m_mean = v; m_median = v; m_histogram[m_histogramNumberOfElements / 2] = v; fill(m_positivePercentiles, m_positivePercentiles + m_percentileDivisions, v); fill(m_negativePercentiles, m_negativePercentiles + m_percentileDivisions, v); m_minimumValue = v; m_maximumValue = v; return; } /* * Copy and sort the input data. */ float* sortedValues = new float[numberOfValues]; for (int64_t i = 0; i < numberOfValues; ++i) {//remove and count non-numerical values if (values[i] != values[i]) { ++m_nanCount; continue; } if (values[i] < -1.0f && (values[i] * 2.0f == values[i])) { ++m_negInfCount; continue; } if (values[i] > 1.0f && (values[i] * 2.0f == values[i])) { ++m_infCount; continue; } sortedValues[m_validCount] = values[i]; ++m_validCount; } sort(sortedValues, sortedValues + m_validCount); /* * Minimum and maximum values */ this->m_minimumValue = sortedValues[0]; this->m_maximumValue = sortedValues[numberOfValues - 1]; /* * Find most/least negative/positive indices in sorted data. */ int64_t mostNegativeIndex = -1; int64_t leastNegativeIndex = -1; int64_t leastPositiveIndex = -1; int64_t mostPositiveIndex = -1; if (sortedValues[0] < 0.0f) { mostNegativeIndex = 0; } if (sortedValues[0] > 0.0f) { leastPositiveIndex = 0; } if (sortedValues[m_validCount - 1] > 0.0f) { mostPositiveIndex = m_validCount - 1; } if (sortedValues[m_validCount - 1] < 0.0f) { leastNegativeIndex = m_validCount - 1; } if (leastNegativeIndex == -1 && leastPositiveIndex == -1) {//need to find where the zeros start and end int64_t start = -1, end = m_validCount, guess, nextEnd = m_validCount; while (end - start > 1) {//bisection search for last negative guess = (start + end) / 2; CaretAssertArrayIndex(sortedValues, m_validCount, guess); if (sortedValues[guess] < 0.0f) { start = guess; } else { end = guess; if (sortedValues[guess] > 0.0f) { nextEnd = guess;//save some time on the next search } } } leastNegativeIndex = start; end = nextEnd;//don't reinitialize start, it is just before the first nonnegative already while (end - start > 1) {//bisection search for first positive guess = (start + end) / 2; CaretAssertArrayIndex(sortedValues, m_validCount, guess); if (sortedValues[guess] > 0.0f) { end = guess; } else { start = guess; } } leastPositiveIndex = end; } /* * Determine negative percentiles * Note: that index 0 is least negative, last index is most negative */ const int64_t numNegativeValues = leastNegativeIndex - mostNegativeIndex + 1; if (mostNegativeIndex != -1) { m_containsNegativeValues = true; m_negativePercentiles[0] = sortedValues[leastNegativeIndex]; for (int64_t i = 1; i < m_percentileDivisions - 1; i++) { int64_t indx = leastNegativeIndex - (int64_t)(((double)i * (numNegativeValues - 1)) / m_percentileDivisions + 0.5); CaretAssertArrayIndex(sortedValues, m_validCount, indx); if (indx < 0) indx = 0; if (indx >= m_validCount) indx = m_validCount - 1; m_negativePercentiles[i] = sortedValues[indx]; } m_negativePercentiles[m_percentileDivisions - 1] = sortedValues[mostNegativeIndex]; } /* * Determine positive percentiles */ const int64_t numPositiveValues = mostPositiveIndex - leastPositiveIndex + 1; if (mostPositiveIndex != -1) { this->m_containsPositiveValues = true; m_positivePercentiles[0] = sortedValues[leastPositiveIndex]; for (int64_t i = 1; i < m_percentileDivisions - 1; i++) { int64_t indx = (int64_t)(((double)i * (numPositiveValues - 1)) / m_percentileDivisions + 0.5) + leastPositiveIndex; CaretAssertArrayIndex(sortedValues, m_validCount, indx); if (indx < 0) indx = 0; if (indx >= m_validCount) indx = m_validCount - 1; m_positivePercentiles[i] = sortedValues[indx]; } m_positivePercentiles[m_percentileDivisions - 1] = sortedValues[mostPositiveIndex]; } /* * Prepare for histogram of all data */ const float minValue = sortedValues[0]; const float maxValue = sortedValues[m_validCount - 1]; const float bucketSize = (maxValue - minValue) / m_histogramNumberOfElements; /* * Prepare for statistics */ double sum = 0.0; double sumSQ = 0.0; /* * Create histogram and statistics. */ for (int64_t i = 0; i < m_validCount; i++) { const float v = sortedValues[i]; int64_t indx = (v - minValue) / bucketSize; if (indx >= m_histogramNumberOfElements) indx = m_histogramNumberOfElements - 1;//NEVER trust floats to not have rounding errors when nonzero if (indx < 0) indx = 0;//probably not needed, involves subtracting equals CaretAssertArrayIndex(m_histogram, m_histogramNumberOfElements, indx); m_histogram[indx]++; sum += v; const float v2 = v * v; sumSQ += v2; } /* * Compute statistics of all. * Pop Variance = (sum(x^2) - [(sum(x))^2] / N) / N */ m_mean = sum / m_validCount; m_median = sortedValues[m_validCount / 2]; const double numerator = (sumSQ - ((sum*sum) / m_validCount)); m_standardDeviationPopulation = -1.0; m_standardDeviationSample = -1.0; if (m_validCount > 0) { m_standardDeviationPopulation = sqrt(numerator / m_validCount); if (m_validCount > 1) { m_standardDeviationSample = sqrt(numerator / (m_validCount - 1)); } } delete[] sortedValues; } /** * Update the statistics with the given data. * @param values * Values for which statistics are calculated. * @param numberOfValues * Number of elements in values array. */ void DescriptiveStatistics::update(const float* values, const int64_t numberOfValues) { this->update(values, numberOfValues, std::numeric_limits::max(), 0.0, 0.0, -std::numeric_limits::max(), true); } /** * Update the statistics with the given data. * @param values * Vector of values for which statistics are calculated. */ void DescriptiveStatistics::update(const std::vector& values) { this->update(values, std::numeric_limits::max(), 0.0, 0.0, -std::numeric_limits::max(), true); } /** * Get the value that is greater than 'percent' of positive values. * * @param percent * The percent which ranges inclusively from 0 to 100. * @return * Value that is greater than 'percent' of the positive values. */ float DescriptiveStatistics::getPositivePercentile(const float percent) const { const float myIndex = (percent / 100 * (m_percentileDivisions - 1));//noninteger index to interpolate at int64_t lowIndex = (int64_t)floor(myIndex); int64_t highIndex = (int64_t)ceil(myIndex); if (highIndex <= 0) return m_positivePercentiles[0]; if (lowIndex >= m_percentileDivisions - 1) return m_positivePercentiles[m_percentileDivisions - 1]; if (lowIndex == highIndex) return m_positivePercentiles[lowIndex]; float lowWeight = highIndex - myIndex; float highWeight = myIndex - lowIndex; return (lowWeight * m_positivePercentiles[lowIndex] + highWeight * m_positivePercentiles[highIndex]) / (lowWeight + highWeight); } /** * Get the value that is more negative than 'percent' of negative values. * * @param percent * The percent which ranges inclusively from 0 to 100. * @return * Value that is more negative than 'percent' of the negative values. */ float DescriptiveStatistics::getNegativePercentile(const float percent) const { const float myIndex = (percent / 100 * (m_percentileDivisions - 1));//noninteger index to interpolate at int64_t lowIndex = (int64_t)floor(myIndex); int64_t highIndex = (int64_t)ceil(myIndex); if (highIndex <= 0) return m_negativePercentiles[0]; if (lowIndex >= m_percentileDivisions - 1) return m_negativePercentiles[m_percentileDivisions - 1]; if (lowIndex == highIndex) return m_negativePercentiles[lowIndex]; float lowWeight = highIndex - myIndex; float highWeight = myIndex - lowIndex; return (lowWeight * m_negativePercentiles[lowIndex] + highWeight * m_negativePercentiles[highIndex]) / (lowWeight + highWeight); } /** * Get a description of this object's content. * @return String describing this object's content. */ AString DescriptiveStatistics::toString() const { return "DescriptiveStatistics"; } connectome-workbench-1.4.2/src/Common/DescriptiveStatistics.h000066400000000000000000000175731360521144700243740ustar00rootroot00000000000000#ifndef __DESCRIPTIVE_STATISTICS__H_ #define __DESCRIPTIVE_STATISTICS__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" namespace caret { class DescriptiveStatistics : public CaretObject { public: DescriptiveStatistics(const int64_t histogramNumberOfElements = 100, const int64_t percentileDivisions = 1001); virtual ~DescriptiveStatistics(); void update(const float* values, const int64_t numberOfValues); void update(const float* values, const int64_t numberOfValues, const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues); void update(const std::vector& values); void update(const std::vector& values, const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues); float getPositivePercentile(const float percent) const; float getNegativePercentile(const float percent) const; void invalidateData(); /** * @return Does the data contains positive values. */ bool hasPositiveValues() const { return this->m_containsPositiveValues; } /** * @return Does the data contains negative values. */ bool hasNegativeValues() const { return this->m_containsNegativeValues; } /** * @return The number of elements in the histogram. */ int64_t getHistogramNumberOfElements() const { return this->m_histogramNumberOfElements; } /** * @return Get the histogram for all values. The number of elements * is HISTOGRAM_NUMBER_OF_ELEMENTS. */ const int64_t* getHistogram() const { return this->m_histogram; } /** * @return The most positive value. */ float getMostPositiveValue() const { return this->m_positivePercentiles[m_percentileDivisions - 1]; } /** * @return The least positive value. */ float getLeastPositiveValue() const { return this->m_positivePercentiles[0]; } /** * @return The most negative value. */ float getMostNegativeValue() const { return this->m_negativePercentiles[m_percentileDivisions - 1]; } /** * @return The least negative value. */ float getLeastNegativeValue() const { return this->m_negativePercentiles[0]; } /** * @return The minimum value. */ float getMinimumValue() const { return this->m_minimumValue; } /** * @return The maximum value. */ float getMaximumValue() const { return this->m_maximumValue; } /** * @return The mean (average) value. */ float getMean() const { return this->m_mean; } /** * @return The median value. */ float getMedian() const { return this->m_median; } /** * @return The population standard deviation (divide by N). */ float getPopulationStandardDeviation() const { return this->m_standardDeviationPopulation; } /** * @return The sample standard deviation (divide by N - 1). */ float getStandardDeviationSample() const { return this->m_standardDeviationSample; } private: DescriptiveStatistics(const DescriptiveStatistics&); DescriptiveStatistics& operator=(const DescriptiveStatistics&); public: virtual AString toString() const; private: /** * Contains the histogram which provides the * distribution of the data. */ int64_t* m_histogram; /** * Contains the number of elements in the histograms. */ int64_t m_histogramNumberOfElements; ///contains number of divisions in the percentiles int64_t m_percentileDivisions; /** * Contains the negative percentiles. * * Index 0 contains the least negative value less than zero. * * Index 'X' contains the value that is less than * 'X' percent of values. * * The last index contains the most negative value. */ float* m_negativePercentiles; /** Indicates that negative data is present. */ bool m_containsNegativeValues; /** * Contains the positive percentiles. * * Index 0 contains the least positive value greater than zero. * * Index 'X' contains the value that is greater than * 'X' percent of values. * * The last index contains the greatest positive value. */ float* m_positivePercentiles; /** Indicates that positive data is present. */ bool m_containsPositiveValues; /** minimum value regardless of sign */ float m_minimumValue; /** maximum value regardless of sign */ float m_maximumValue; /** The mean (average) value. */ float m_mean; /** The population standard deviation of all values (divide by N). */ float m_standardDeviationPopulation; /** The sample standard deviation of all values (divide by N - 1). */ float m_standardDeviationSample; /** The median (middle) value. */ float m_median; ///counts of each class of number int64_t m_validCount, m_infCount, m_negInfCount, m_nanCount; /// last input value for number of (prevents unnecessary updates) int64_t m_lastInputNumberOfValues; /// last input value for most positive (prevents unnecessary updates) float m_lastInputMostPositiveValueInclusive; /// last input value for least positive (prevents unnecessary updates) float m_lastInputLeastPositiveValueInclusive; /// last input value for least negative (prevents unnecessary updates) float m_lastInputLeastNegativeValueInclusive; /// last input value for most negative (prevents unnecessary updates) float m_lastInputMostNegativeValueInclusive; /// last input value for include zeros (prevents unnecessary updates) bool m_lastInputIncludeZeroValues; }; #ifdef __DESCRIPTIVE_STATISTICS_DECLARE__ // #endif // __DESCRIPTIVE_STATISTICS_DECLARE__ } // namespace #endif //__DESCRIPTIVE_STATISTICS__H_ connectome-workbench-1.4.2/src/Common/DeveloperFlagsEnum.cxx000066400000000000000000000330341360521144700241300ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __DEVELOPER_FLAGS_ENUM_DECLARE__ #include "DeveloperFlagsEnum.h" #undef __DEVELOPER_FLAGS_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::DeveloperFlagsEnum * \brief Flags used during development. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_developerFlagsEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void developerFlagsEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "DeveloperFlagsEnum.h" * * Instatiate: * m_developerFlagsEnumComboBox = new EnumComboBoxTemplate(this); * m_developerFlagsEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_developerFlagsEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(developerFlagsEnumComboBoxItemActivated())); * * Update the selection: * m_developerFlagsEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const DeveloperFlagsEnum::Enum VARIABLE = m_developerFlagsEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * @param guiName * User-friendly name for use in user-interface. * @param checkable * Checkable status (NO, YES) * @param defaultValue * Default value for flag */ DeveloperFlagsEnum::DeveloperFlagsEnum(const Enum enumValue, const AString& name, const AString& guiName, const CheckableEnum checkable, const bool defaultValue) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; this->checkable = checkable; this->flagStatus = defaultValue; } /** * Destructor. */ DeveloperFlagsEnum::~DeveloperFlagsEnum() { } /** * Initialize the enumerated metadata. */ void DeveloperFlagsEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; std::vector checkableItems; checkableItems.push_back(DeveloperFlagsEnum(DEVELOPER_FLAG_UNUSED, "DEVELOPER_FLAG_UNUSED", "Developer Flag Unused", CheckableEnum::YES, false)); checkableItems.push_back(DeveloperFlagsEnum(DEVELOPER_FLAG_FLIP_PALETTE_NOT_DATA, "DEVELOPER_FLAG_FLIP_PALETTE_NOT_DATA", "Flip Palette Not Data", CheckableEnum::YES, false)); checkableItems.push_back(DeveloperFlagsEnum(DEVELOPER_FLAG_TEXTURE_VOLUME, "DEVELOPER_FLAG_TEXTURE_VOLUME", "Texture Volume Drawing", CheckableEnum::YES, false)); checkableItems.push_back(DeveloperFlagsEnum(DELELOPER_FLAG_VOXEL_SMOOTH, "DELELOPER_FLAG_VOXEL_SMOOTH", "Smooth Texture Volume Voxels", CheckableEnum::YES, false)); checkableItems.push_back(DeveloperFlagsEnum(DEVELOPER_FLAG_BALSA, "DEVELOPER_FLAG_BALSA", "Visit BALSA...", CheckableEnum::NO, false)); std::vector notCheckableItems; enumData.insert(enumData.end(), checkableItems.begin(), checkableItems.end()); enumData.insert(enumData.end(), notCheckableItems.begin(), notCheckableItems.end()); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ DeveloperFlagsEnum* DeveloperFlagsEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { DeveloperFlagsEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString DeveloperFlagsEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const DeveloperFlagsEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ DeveloperFlagsEnum::Enum DeveloperFlagsEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = DeveloperFlagsEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const DeveloperFlagsEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type DeveloperFlagsEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString DeveloperFlagsEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const DeveloperFlagsEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ DeveloperFlagsEnum::Enum DeveloperFlagsEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = DeveloperFlagsEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const DeveloperFlagsEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type DeveloperFlagsEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t DeveloperFlagsEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const DeveloperFlagsEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ DeveloperFlagsEnum::Enum DeveloperFlagsEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = DeveloperFlagsEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const DeveloperFlagsEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type DeveloperFlagsEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void DeveloperFlagsEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void DeveloperFlagsEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(DeveloperFlagsEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void DeveloperFlagsEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(DeveloperFlagsEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } /** * Is the developer flag set? * * @param enumValue * Enum value for flag * @return * True/False status for flag. */ bool DeveloperFlagsEnum::isFlag(const Enum enumValue) { if (initializedFlag == false) initialize(); const DeveloperFlagsEnum* enumInstance = findData(enumValue); return enumInstance->flagStatus; } /** * Set the developer flag. * * @param enumValue * Enum value for flag * @param flagStatus * True/False status for flag. */ void DeveloperFlagsEnum::setFlag(const Enum enumValue, const bool flagStatus) { if (initializedFlag == false) initialize(); DeveloperFlagsEnum* enumInstance = findData(enumValue); enumInstance->flagStatus = flagStatus; } /** * @return True if the developer flag is checkable */ bool DeveloperFlagsEnum::isCheckable(const Enum enumValue) { bool checkableStatus(false); if (initializedFlag == false) initialize(); DeveloperFlagsEnum* enumInstance = findData(enumValue); switch (enumInstance->checkable) { case CheckableEnum::NO: checkableStatus = false; break; case CheckableEnum::YES: checkableStatus = true; break; } return checkableStatus; } connectome-workbench-1.4.2/src/Common/DeveloperFlagsEnum.h000066400000000000000000000071501360521144700235550ustar00rootroot00000000000000#ifndef __DEVELOPER_FLAGS_ENUM_H__ #define __DEVELOPER_FLAGS_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class DeveloperFlagsEnum { public: /** * Enumerated values. */ enum Enum { DEVELOPER_FLAG_UNUSED, DEVELOPER_FLAG_FLIP_PALETTE_NOT_DATA, DEVELOPER_FLAG_TEXTURE_VOLUME, DELELOPER_FLAG_VOXEL_SMOOTH, DEVELOPER_FLAG_BALSA }; ~DeveloperFlagsEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); static bool isFlag(const Enum enumValue); static void setFlag(const Enum enumValue, const bool flagStatus); static bool isCheckable(const Enum enumValue); private: enum class CheckableEnum { NO, YES }; DeveloperFlagsEnum(const Enum enumValue, const AString& name, const AString& guiName, const CheckableEnum checkable, const bool defaultValue); static DeveloperFlagsEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; /** Flag status */ bool flagStatus; /** Checkable status */ CheckableEnum checkable; }; #ifdef __DEVELOPER_FLAGS_ENUM_DECLARE__ std::vector DeveloperFlagsEnum::enumData; bool DeveloperFlagsEnum::initializedFlag = false; int32_t DeveloperFlagsEnum::integerCodeCounter = 0; #endif // __DEVELOPER_FLAGS_ENUM_DECLARE__ } // namespace #endif //__DEVELOPER_FLAGS_ENUM_H__ connectome-workbench-1.4.2/src/Common/DisplayGroupAndTabItemInterface.cxx000066400000000000000000000214501360521144700265340ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __DISPLAY_GROUP_AND_TAB_ITEM_INTERFACE_DECLARE__ #include "DisplayGroupAndTabItemInterface.h" #undef __DISPLAY_GROUP_AND_TAB_ITEM_INTERFACE_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" using namespace caret; /** * \class caret::DisplayGroupAndTabItemInterface * \brief Interface for items in a display group tab selection hierarchy * \ingroup Common */ /** * Constructor. */ DisplayGroupAndTabItemInterface::DisplayGroupAndTabItemInterface() { } /** * Destructor. */ DisplayGroupAndTabItemInterface::~DisplayGroupAndTabItemInterface() { } ///** // * Copy constructor. // * @param obj // * Object that is copied. // */ //DisplayGroupAndTabItemInterface::DisplayGroupAndTabItemInterface(const DisplayGroupAndTabItemInterface& obj) //: CaretObject(obj) //{ // this->copyHelperDisplayGroupAndTabItemInterface(obj); //} // ///** // * Assignment operator. // * @param obj // * Data copied from obj to this. // * @return // * Reference to this object. // */ //DisplayGroupAndTabItemInterface& //DisplayGroupAndTabItemInterface::operator=(const DisplayGroupAndTabItemInterface& obj) //{ // if (this != &obj) { // CaretObject::operator=(obj); // this->copyHelperDisplayGroupAndTabItemInterface(obj); // } // return *this; //} // ///** // * Helps with copying an object of this type. // * @param obj // * Object that is copied. // */ //void //DisplayGroupAndTabItemInterface::copyHelperDisplayGroupAndTabItemInterface(const DisplayGroupAndTabItemInterface& obj) //{ // //} /** * Set the display status to SELECTED for the given tab and * UNSELECTED for all other tabs. * * @param tabIndex * Index of the tab. */ void DisplayGroupAndTabItemInterface::setItemDisplaySelectedInOneTab(const int32_t tabIndex) { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { setItemDisplaySelected(DisplayGroupEnum::DISPLAY_GROUP_TAB, i, TriStateSelectionStatusEnum::UNSELECTED); } setItemDisplaySelected(DisplayGroupEnum::DISPLAY_GROUP_TAB, tabIndex, TriStateSelectionStatusEnum::SELECTED); } /** * Set the display status to SELECTED for all tabs. */ void DisplayGroupAndTabItemInterface::setItemDisplaySelectedInAllTabs() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { setItemDisplaySelected(DisplayGroupEnum::DISPLAY_GROUP_TAB, i, TriStateSelectionStatusEnum::SELECTED); } } /** * Set the display status to SELECTED for all groups (except TAB). */ void DisplayGroupAndTabItemInterface::setItemDisplaySelectedInAllGroups() { std::vector groupEnums; DisplayGroupEnum::getAllEnumsExceptTab(groupEnums); for (std::vector::iterator iter = groupEnums.begin(); iter != groupEnums.end(); iter++) { setItemDisplaySelected(*iter, 0, TriStateSelectionStatusEnum::SELECTED); } } /** * Set the display status to UNSELECTED for all groups (except TAB). */ void DisplayGroupAndTabItemInterface::setItemDisplaySelectedInNoDisplayGroups() { std::vector groupEnums; DisplayGroupEnum::getAllEnumsExceptTab(groupEnums); for (auto group : groupEnums) { setItemDisplaySelected(group, 0, TriStateSelectionStatusEnum::UNSELECTED); } } /** * Set the display status to SELECTED for the given group (not TAB) and * UNSELECTED for all other groups (not TAB). * * @param tabIndex * Index of the tab. */ void DisplayGroupAndTabItemInterface::setItemDisplaySelectedInOneGroup(const DisplayGroupEnum::Enum displayGroup) { if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretLogWarning("DisplayGroupEnum::DISPLAY_GROUP_TAB not allowed."); return; } std::vector groupEnums; DisplayGroupEnum::getAllEnumsExceptTab(groupEnums); for (std::vector::iterator iter = groupEnums.begin(); iter != groupEnums.end(); iter++) { const DisplayGroupEnum::Enum enumValue = *iter; TriStateSelectionStatusEnum::Enum status = TriStateSelectionStatusEnum::UNSELECTED; if (displayGroup == enumValue) { status = TriStateSelectionStatusEnum::SELECTED; } setItemDisplaySelected(*iter, 0, status); } } /** * Helps with display selection status of all children. * * @param displayGroupTabInterface * Item that has all of its children selected for display. * @param displayGroup * The display group. * @param tabIndex * Index of the tab. * @return * Selection status for children. If there are no children, * 'UNSELECTED' is returned. */ TriStateSelectionStatusEnum::Enum DisplayGroupAndTabItemInterface::getChildrenDisplaySelectedHelper(DisplayGroupAndTabItemInterface* displayGroupTabInterface, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) { TriStateSelectionStatusEnum::Enum status = TriStateSelectionStatusEnum::UNSELECTED; std::vector children = displayGroupTabInterface->getItemChildren(); const int numChildren = static_cast(children.size()); if (numChildren > 0) { int32_t selectedCount = 0; int32_t partialSelectedCount = 0; for (int32_t i = 0; i < numChildren; i++) { CaretAssertVectorIndex(children, i); switch (children[i]->getItemDisplaySelected(displayGroup, tabIndex)) { case TriStateSelectionStatusEnum::PARTIALLY_SELECTED: partialSelectedCount++; break; case TriStateSelectionStatusEnum::SELECTED: selectedCount++; break; case TriStateSelectionStatusEnum::UNSELECTED: break; } } if (selectedCount == numChildren) { status = TriStateSelectionStatusEnum::SELECTED; } else if ((selectedCount > 0) || (partialSelectedCount > 0)) { status = TriStateSelectionStatusEnum::PARTIALLY_SELECTED; } } return status; } /** * Helps with display selection of all children. * * @param displayGroupTabInterface * Item that has all of its children selected for display. * @param displayGroup * The display group. * @param tabIndex * Index of the tab. * @param status * New selection status. * @return * True if there are children and their status was set, else false. */ bool DisplayGroupAndTabItemInterface::setChildrenDisplaySelectedHelper(DisplayGroupAndTabItemInterface* displayGroupTabInterface, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const TriStateSelectionStatusEnum::Enum status) { CaretAssert(displayGroupTabInterface); std::vector children = displayGroupTabInterface->getItemChildren(); for (std::vector::iterator childIter = children.begin(); childIter != children.end(); childIter++) { DisplayGroupAndTabItemInterface* child = *childIter; child->setItemDisplaySelected(displayGroup, tabIndex, status); } return ( ! children.empty()); } connectome-workbench-1.4.2/src/Common/DisplayGroupAndTabItemInterface.h000066400000000000000000000162571360521144700261720ustar00rootroot00000000000000#ifndef __DISPLAY_GROUP_AND_TAB_ITEM_INTERFACE_H__ #define __DISPLAY_GROUP_AND_TAB_ITEM_INTERFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "DisplayGroupEnum.h" #include "TriStateSelectionStatusEnum.h" namespace caret { class DisplayGroupAndTabItemInterface { protected: /** * Constructor */ DisplayGroupAndTabItemInterface(); public: /** * Destructor */ virtual ~DisplayGroupAndTabItemInterface(); /** * @return Number of children. */ virtual int32_t getNumberOfItemChildren() const = 0; /** * Get child at the given index. * * @param index * Index of the child. * @return * Child at the given index. */ virtual DisplayGroupAndTabItemInterface* getItemChild(const int32_t index) const = 0; /** * @return Children of this item. */ virtual std::vector getItemChildren() const = 0; /** * @return Parent of this item. */ virtual DisplayGroupAndTabItemInterface* getItemParent() const = 0; /** * Set the parent of this item. * * @param itemParent * Parent of this item. */ virtual void setItemParent(DisplayGroupAndTabItemInterface* itemParent) = 0; /** * @return Name of this item. */ virtual AString getItemName() const = 0; /** * Get the icon color for this item. Icon is filled with background * color, outline color is drawn around edges, and text color is small * square in center. For any colors that do not apply, use an alpha * value (last element) of zero. * * @param backgroundRgbaOut * Red, green, blue, alpha components for background ranging [0, 1]. * @param outlineRgbaOut * Red, green, blue, alpha components for outline ranging [0, 1]. * @param textRgbaOut * Red, green, blue, alpha components for text ranging [0, 1]. */ virtual void getItemIconColorsRGBA(float backgroundRgbaOut[4], float outlineRgbaOut[4], float textRgbaOut[4]) const = 0; /** * @return This item can be expanded. */ virtual bool isItemExpandable() const = 0; /** * @return Is this item expanded in the given display group/tab? * * @param displayGroup * The display group. * @param tabIndex * Index of the tab. */ virtual bool isItemExpanded(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const = 0; /** * Set this item's expanded status in the given display group/tab. * * @param displayGroup * The display group. * @param tabIndex * Index of the tab. * @param status * New expanded status. */ virtual void setItemExpanded(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool status) = 0; /** * Get display selection status in the given display group/tab? * * @param displayGroup * The display group. * @param tabIndex * Index of the tab. */ virtual TriStateSelectionStatusEnum::Enum getItemDisplaySelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const = 0; /** * Set display this item selected in the given display group/tab. * * @param displayGroup * The display group. * @param tabIndex * Index of the tab. * @param status * New selection status. */ virtual void setItemDisplaySelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const TriStateSelectionStatusEnum::Enum status) = 0; virtual void setItemDisplaySelectedInOneTab(const int32_t tabIndex); virtual void setItemDisplaySelectedInAllTabs(); virtual void setItemDisplaySelectedInAllGroups(); virtual void setItemDisplaySelectedInNoDisplayGroups(); virtual void setItemDisplaySelectedInOneGroup(const DisplayGroupEnum::Enum displayGroup); /** * Is this item selected for editing in the given window? * * @param windowIndex * Index of the window. * @return * Selection status. */ virtual bool isItemSelectedForEditingInWindow(const int32_t windowIndex) = 0; static TriStateSelectionStatusEnum::Enum getChildrenDisplaySelectedHelper(DisplayGroupAndTabItemInterface* displayGroupTabInterface, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex); static bool setChildrenDisplaySelectedHelper(DisplayGroupAndTabItemInterface* displayGroupTabInterface, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const TriStateSelectionStatusEnum::Enum status); // ADD_NEW_METHODS_HERE private: //DisplayGroupAndTabItemInterface(const DisplayGroupAndTabItemInterface& obj); //DisplayGroupAndTabItemInterface& operator=(const DisplayGroupAndTabItemInterface& obj); // ADD_NEW_MEMBERS_HERE }; #ifdef __DISPLAY_GROUP_AND_TAB_ITEM_INTERFACE_DECLARE__ // #endif // __DISPLAY_GROUP_AND_TAB_ITEM_INTERFACE_DECLARE__ } // namespace #endif //__DISPLAY_GROUP_AND_TAB_ITEM_INTERFACE_H__ connectome-workbench-1.4.2/src/Common/DisplayGroupEnum.cxx000066400000000000000000000250501360521144700236470ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __DISPLAY_GROUP_ENUM_DECLARE__ #include "DisplayGroupEnum.h" #undef __DISPLAY_GROUP_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::DisplayGroupEnum * \brief Enumerated types for grouping related data. * * This class provides an enumerated type that * can be used by other classes to group related * properties, typically display properties. */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ DisplayGroupEnum::DisplayGroupEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ DisplayGroupEnum::~DisplayGroupEnum() { } /** * Initialize the enumerated metadata. */ void DisplayGroupEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(DisplayGroupEnum(DISPLAY_GROUP_TAB, "DISPLAY_GROUP_TAB", "Tab")); enumData.push_back(DisplayGroupEnum(DISPLAY_GROUP_A, "DISPLAY_GROUP_A", "Group A")); enumData.push_back(DisplayGroupEnum(DISPLAY_GROUP_B, "DISPLAY_GROUP_B", "Group B")); enumData.push_back(DisplayGroupEnum(DISPLAY_GROUP_C, "DISPLAY_GROUP_C", "Group C")); enumData.push_back(DisplayGroupEnum(DISPLAY_GROUP_D, "DISPLAY_GROUP_D", "Group D")); if (static_cast(enumData.size()) != DisplayGroupEnum::NUMBER_OF_GROUPS) { CaretAssertMessage(0, "NUMBER_OF_GROUPS constant is incorrect. New ENUMs added?"); } } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const DisplayGroupEnum* DisplayGroupEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const DisplayGroupEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString DisplayGroupEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const DisplayGroupEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ DisplayGroupEnum::Enum DisplayGroupEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = getDefaultValue(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const DisplayGroupEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type DisplayGroupEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString DisplayGroupEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const DisplayGroupEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ DisplayGroupEnum::Enum DisplayGroupEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = getDefaultValue(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const DisplayGroupEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type DisplayGroupEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t DisplayGroupEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const DisplayGroupEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ DisplayGroupEnum::Enum DisplayGroupEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = getDefaultValue(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const DisplayGroupEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type DisplayGroupEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void DisplayGroupEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the enumerated type values for GROUPs. Like getAllEnums() * except TAB is excluded. DISPLAY_GROUP_A, DISPLAY_GROUP_B, etc. * * @param allGroupEnums * A vector that is OUTPUT containing all of the GROUP enumerated values (TAB excluded). */ void DisplayGroupEnum::getAllEnumsExceptTab(std::vector& allGroupEnums) { if (initializedFlag == false) initialize(); allGroupEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { if (iter->enumValue != DisplayGroupEnum::DISPLAY_GROUP_TAB) { allGroupEnums.push_back(iter->enumValue); } } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void DisplayGroupEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(DisplayGroupEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void DisplayGroupEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(DisplayGroupEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } /** * @return The default value for a display group. */ DisplayGroupEnum::Enum DisplayGroupEnum::getDefaultValue() { return DISPLAY_GROUP_A; } connectome-workbench-1.4.2/src/Common/DisplayGroupEnum.h000066400000000000000000000067611360521144700233040ustar00rootroot00000000000000#ifndef __DISPLAY_GROUP_ENUM__H_ #define __DISPLAY_GROUP_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class DisplayGroupEnum { public: /** * Enumerated values. */ enum Enum { /** Unique to Tab */ DISPLAY_GROUP_TAB, /** Group A */ DISPLAY_GROUP_A, /** Group B */ DISPLAY_GROUP_B, /** Group C */ DISPLAY_GROUP_C, /** Group D */ DISPLAY_GROUP_D /* IF A NEW ENUM IS ADDED UPDATE NUMBER_OF_GROUPS ENUM BELOW */ }; enum Misc { /** Number of groups, update if new enums are added */ NUMBER_OF_GROUPS = 5 }; ~DisplayGroupEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllEnumsExceptTab(std::vector& allGroupEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); static DisplayGroupEnum::Enum getDefaultValue(); private: DisplayGroupEnum(const Enum enumValue, const AString& name, const AString& guiName); static const DisplayGroupEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __DISPLAY_GROUP_ENUM_DECLARE__ std::vector DisplayGroupEnum::enumData; bool DisplayGroupEnum::initializedFlag = false; int32_t DisplayGroupEnum::integerCodeCounter = 0; #endif // __DISPLAY_GROUP_ENUM_DECLARE__ } // namespace #endif //__DISPLAY_GROUP_ENUM__H_ connectome-workbench-1.4.2/src/Common/ElapsedTimer.cxx000066400000000000000000000070301360521144700227540ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ELAPSED_TIMER_DECLARE__ #include "ElapsedTimer.h" #undef __ELAPSED_TIMER_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * Constructor. */ ElapsedTimer::ElapsedTimer() : CaretObject() { m_started = false; } /** * Destructor. */ ElapsedTimer::~ElapsedTimer() { } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ElapsedTimer::toString() const { return "ElapsedTimer"; } /** * Start the timer. */ void ElapsedTimer::start() { #ifdef CARET_OS_WINDOWS m_startTime.m_tickCount = GetTickCount();//TODO: find a good way to use getTickCount64() so it doesn't have a reset at 49 days of uptime #else gettimeofday(&(m_startTime.m_timeVal), NULL); #endif m_started = true; } /** * Reset the timer as if no time had elapsed. */ void ElapsedTimer::reset() { /* * Start will change the time to 'now'. */ this->start(); } /** * Get the elapsed time in seconds. * * @return Elapsed time in seconds. */ double ElapsedTimer::getElapsedTimeSeconds() const { return getElapsedTimeMilliseconds() / 1000.0; } /** * Get the elapsed time in milliseconds. * * @return Elapsed time in milliseconds. */ double ElapsedTimer::getElapsedTimeMilliseconds() const { CaretAssertMessage(m_started, "Timer has not been started"); MyTimeStore endTime; #ifdef CARET_OS_WINDOWS endTime.m_tickCount = GetTickCount();//TODO: find a good way to use getTickCount64() when possible so it doesn't have a reset at 49 days of uptime if (endTime.m_tickCount < m_startTime.m_tickCount)//check for the 49 day wrap { endTime.m_tickCount += ((uint64_t)1)<<32;//m_tickCount is 64 bit, so this doesn't overflow } const double diffTimeMilli = (double)(endTime.m_tickCount - m_startTime.m_tickCount);//contrary to its name, it returns milliseconds, not ticks #else gettimeofday(&(endTime.m_timeVal), NULL); double diffSeconds = endTime.m_timeVal.tv_sec - m_startTime.m_timeVal.tv_sec; double diffMicroseconds = endTime.m_timeVal.tv_usec - m_startTime.m_timeVal.tv_usec; /*if (diffMicroseconds < 0) {//this is only needed if we are displaying both parts separately diffMicroseconds += 1000000; diffSeconds -= 1;//don't forget to subtract the second you just added to microseconds }//*/ const double diffTimeMilli = diffSeconds * 1000.0 + (diffMicroseconds / 1000.0); #endif return diffTimeMilli; } /** * Print the given message followed by the elapsed time in seconds. * * @param message * Message that is printed before the seconds. */ void ElapsedTimer::printSeconds(const AString& message) { std::cout << message << " " << getElapsedTimeSeconds() << " seconds" << std::endl; } connectome-workbench-1.4.2/src/Common/ElapsedTimer.h000066400000000000000000000043621360521144700224060ustar00rootroot00000000000000#ifndef __ELAPSED_TIMER__H_ #define __ELAPSED_TIMER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #ifdef CARET_OS_WINDOWS #include "windows.h" #else #include #endif #include "CaretObject.h" namespace caret { //getTimeOfDay() isn't cross-platform, so use some ifdefs for windows #ifdef CARET_OS_WINDOWS struct MyTimeStore { uint64_t m_tickCount;//can store return from GetTickCount64() which doesn't reset at 49 days, but is vista and above only };//also useful for detecting and correcting for a wrap, can just add (uint64_t)1<<32 #else struct MyTimeStore { struct timeval m_timeVal; }; #endif /// An elapsed timer class ElapsedTimer : public CaretObject { public: ElapsedTimer(); virtual ~ElapsedTimer(); void start(); void reset(); double getElapsedTimeSeconds() const; double getElapsedTimeMilliseconds() const; void printSeconds(const AString& message); private: ElapsedTimer(const ElapsedTimer&); ElapsedTimer& operator=(const ElapsedTimer&); public: virtual AString toString() const; private: MyTimeStore m_startTime; bool m_started; }; #ifdef __ELAPSED_TIMER_DECLARE__ // #endif // __ELAPSED_TIMER_DECLARE__ } // namespace #endif //__ELAPSED_TIMER__H_ connectome-workbench-1.4.2/src/Common/Event.cxx000066400000000000000000000063371360521144700214700ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" using namespace caret; /** * Constructor. * * @param eventType * The type of the event. */ Event::Event(const EventTypeEnum::Enum eventType) { this->eventType = eventType; this->errorMessage = ""; this->errorStatus = false; this->eventProcessedCount = 0; } /** * Destructor. */ Event::~Event() { } /** * Get the type of event. * * @return * The event type. */ EventTypeEnum::Enum Event::getEventType() const { return this->eventType; } /** * Get a pointer to this event. The intention of this * method is to allow the sender of the event to create * this event ?statically? (not with new) and then send * "event"->getPointer() to the event manager since * &eventObject will not cast automatically to an * Event object pointer. * * @return * Pointer to this object with the base Event class. */ Event* Event::getPointer() { return this; } /** * Was there an error processing this event? * * @return * True if there was an error processing the * event else false. */ bool Event::isError() const { return this->errorStatus; } /** * Get the error message which is only * valid if isError() returns true. * * @return * A message describing the error. */ AString Event::getErrorMessage() const { return this->errorMessage; } /** * Consumer of an event can set the error message * to indicate that there was an error processing * the event. * * If the given error message is not empty, * calling this method will result in the error * status being set and the event manager will not * send this event to any other receivers. * * @param errorMessage * The error message. */ void Event::setErrorMessage(const AString& errorMessage) { if (errorMessage.isEmpty() == false) { this->errorMessage = errorMessage; this->errorStatus = true; } } /** * Set the this event was processed by a listener. */ void Event::setEventProcessed() { this->eventProcessedCount++; } /** * Get the number of times the event was processed. * * @preturn Count of receivers that processed this event. */ int32_t Event::getEventProcessCount() const { return this->eventProcessedCount; } /** * Get String representation of caret object. * @return String containing caret object. * */ AString Event::toString() const { AString s = EventTypeEnum::toName(this->eventType); return s; } connectome-workbench-1.4.2/src/Common/Event.h000066400000000000000000000040431360521144700211050ustar00rootroot00000000000000#ifndef __EVENT_H__ #define __EVENT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "EventTypeEnum.h" namespace caret { /// Base class for an event. class Event : public CaretObject { public: EventTypeEnum::Enum getEventType() const; virtual ~Event(); Event* getPointer(); bool isError() const; AString getErrorMessage() const; void setErrorMessage(const AString& errorMessage); virtual AString toString() const; void setEventProcessed(); int32_t getEventProcessCount() const; protected: Event(const EventTypeEnum::Enum eventType); private: Event(const Event&); Event& operator=(const Event&); /** The type of event */ EventTypeEnum::Enum eventType; /** The error message */ AString errorMessage; /** Tracks error status */ bool errorStatus; /** Number of times event was processed. */ int32_t eventProcessedCount; friend class EventManager; }; } // namespace #endif // __EVENT_H__ connectome-workbench-1.4.2/src/Common/EventAlertUser.cxx000066400000000000000000000037641360521144700233200ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_ALERT_USER_DECLARE__ #include "EventAlertUser.h" #undef __EVENT_ALERT_USER_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventAlertUser * \brief Event that alerts the user to a problem * \ingroup Common * * If there is a problem in non-GUI code, it may be desirable to inform * the user of a problem. However, when this type of problem occurs, * passing this information "up the call stack" may be problematic and * using an exception may not be possible or desired. * * In these instance this event class may be used. When there is a GUI, * this event is received by the GuiManager and a pop-up is presented * to the user. If there is not a GUI, the EventManager will not send * this event and instead, log the message at the severe level. */ /** * Constructor for an alert message. */ EventAlertUser::EventAlertUser(const AString& message) : Event(EventTypeEnum::EVENT_ALERT_USER), m_message(message) { } /** * Destructor. */ EventAlertUser::~EventAlertUser() { } /** * @return The message for the alert. */ AString EventAlertUser::getMessage() const { return m_message; } connectome-workbench-1.4.2/src/Common/EventAlertUser.h000066400000000000000000000030351360521144700227340ustar00rootroot00000000000000#ifndef __EVENT_ALERT_USER_H__ #define __EVENT_ALERT_USER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class EventAlertUser : public Event { public: EventAlertUser(const AString& message); virtual ~EventAlertUser(); AString getMessage() const; // ADD_NEW_METHODS_HERE private: EventAlertUser(const EventAlertUser&); EventAlertUser& operator=(const EventAlertUser&); const AString m_message; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_ALERT_USER_DECLARE__ // #endif // __EVENT_ALERT_USER_DECLARE__ } // namespace #endif //__EVENT_ALERT_USER_H__ connectome-workbench-1.4.2/src/Common/EventBrowserTabDelete.cxx000066400000000000000000000034241360521144700246000ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "EventBrowserTabDelete.h" using namespace caret; /** * Constructor. */ EventBrowserTabDelete::EventBrowserTabDelete(BrowserTabContent* browserTab, const int32_t browserTabIndex) : Event(EventTypeEnum::EVENT_BROWSER_TAB_DELETE), m_browserTab(browserTab), m_browserTabIndex(browserTabIndex) { CaretAssert(browserTab); } /** * Destructor. */ EventBrowserTabDelete::~EventBrowserTabDelete() { } /** * Get the browser tab that is to be deleted. * Note that this may point to a browser tab that * has been deleted and using the pointer in this * case could be a disaster. * * @return * Pointer to browser tab that is to be deleted. */ BrowserTabContent* EventBrowserTabDelete::getBrowserTab() { return m_browserTab; } /** * @return Index of browser tab being deleted. */ int32_t EventBrowserTabDelete::getBrowserTabIndex() const { return m_browserTabIndex; } connectome-workbench-1.4.2/src/Common/EventBrowserTabDelete.h000066400000000000000000000033011360521144700242170ustar00rootroot00000000000000#ifndef __EVENT_BROWSER_TAB_DELETE_H__ #define __EVENT_BROWSER_TAB_DELETE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class BrowserTabContent; /// Event for deleting a browser tab class EventBrowserTabDelete : public Event { public: EventBrowserTabDelete(BrowserTabContent* browserTab, const int32_t browserTabIndex); virtual ~EventBrowserTabDelete(); BrowserTabContent* getBrowserTab(); int32_t getBrowserTabIndex() const; private: EventBrowserTabDelete(const EventBrowserTabDelete&); EventBrowserTabDelete& operator=(const EventBrowserTabDelete&); BrowserTabContent* m_browserTab; const int32_t m_browserTabIndex; }; } // namespace #endif // __EVENT_BROWSER_TAB_DELETE_H__ connectome-workbench-1.4.2/src/Common/EventBrowserTabIndicesGetAll.cxx000066400000000000000000000045071360521144700260500ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __EVENT_BROWSER_TAB_INDICES_GET_ALL_DECLARE__ #include "EventBrowserTabIndicesGetAll.h" #undef __EVENT_BROWSER_TAB_INDICES_GET_ALL_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventBrowserTabIndicesGetAll * \brief Event to get indices of all valid browser tabs. * \ingroup Common */ /** * Constructor. */ EventBrowserTabIndicesGetAll::EventBrowserTabIndicesGetAll() : Event(EventTypeEnum::EVENT_BROWSER_TAB_INDICES_GET_ALL) { } /** * Destructor. */ EventBrowserTabIndicesGetAll::~EventBrowserTabIndicesGetAll() { } /** * Add the tab index of a valid browser tab. * * @parm browserTabIndex * Index of the browser tab. */ void EventBrowserTabIndicesGetAll::addBrowserTabIndex(const int32_t browserTabIndex) { m_browserTabIndices.push_back(browserTabIndex); } /** * @return Indices of all valid browser tabs. */ std::vector EventBrowserTabIndicesGetAll::getAllBrowserTabIndices() const { return m_browserTabIndices; } /** * Get the validity of a browser tab. * * @parm browserTabIndex * Index of the browser tab. * @return * True if browser tab index is valid, else false. */ bool EventBrowserTabIndicesGetAll::isValidBrowserTabIndex(const int32_t browserTabIndex) { if (std::find(m_browserTabIndices.begin(), m_browserTabIndices.end(), browserTabIndex) != m_browserTabIndices.end()) { return true; } return false; } connectome-workbench-1.4.2/src/Common/EventBrowserTabIndicesGetAll.h000066400000000000000000000036001360521144700254660ustar00rootroot00000000000000#ifndef __EVENT_BROWSER_TAB_INDICES_GET_ALL_H__ #define __EVENT_BROWSER_TAB_INDICES_GET_ALL_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class EventBrowserTabIndicesGetAll : public Event { public: EventBrowserTabIndicesGetAll(); virtual ~EventBrowserTabIndicesGetAll(); void addBrowserTabIndex(const int32_t browserTabIndex); std::vector getAllBrowserTabIndices() const; bool isValidBrowserTabIndex(const int32_t browserTabIndex); // ADD_NEW_METHODS_HERE private: EventBrowserTabIndicesGetAll(const EventBrowserTabIndicesGetAll&); EventBrowserTabIndicesGetAll& operator=(const EventBrowserTabIndicesGetAll&); std::vector m_browserTabIndices; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_BROWSER_TAB_INDICES_GET_ALL_DECLARE__ // #endif // __EVENT_BROWSER_TAB_INDICES_GET_ALL_DECLARE__ } // namespace #endif //__EVENT_BROWSER_TAB_INDICES_GET_ALL_H__ connectome-workbench-1.4.2/src/Common/EventBrowserTabNew.cxx000066400000000000000000000031011360521144700241170ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "EventBrowserTabNew.h" using namespace caret; /** * Constructor. */ EventBrowserTabNew::EventBrowserTabNew() : Event(EventTypeEnum::EVENT_BROWSER_TAB_NEW) { this->browserTab = NULL; } /** * Destructor. */ EventBrowserTabNew::~EventBrowserTabNew() { } /** * Get the browser tab that was created. * * @return * Pointer to browser tab that was created or * NULL if a browser tab could not be created. */ BrowserTabContent* EventBrowserTabNew::getBrowserTab() { return this->browserTab; } /** * Set the created browser tab. * * @param browserTab * Browser tab that was created. */ void EventBrowserTabNew::setBrowserTab(BrowserTabContent* browserTab) { this->browserTab = browserTab; } connectome-workbench-1.4.2/src/Common/EventBrowserTabNew.h000066400000000000000000000030501360521144700235470ustar00rootroot00000000000000#ifndef __EVENT_BROWSER_TAB_NEW_H__ #define __EVENT_BROWSER_TAB_NEW_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class BrowserTabContent; /// Event for creating a new browser tab class EventBrowserTabNew : public Event { public: EventBrowserTabNew(); virtual ~EventBrowserTabNew(); BrowserTabContent* getBrowserTab(); void setBrowserTab(BrowserTabContent* browserTab); private: EventBrowserTabNew(const EventBrowserTabNew&); EventBrowserTabNew& operator=(const EventBrowserTabNew&); BrowserTabContent* browserTab; }; } // namespace #endif // __EVENT_BROWSER_TAB_NEW_H__ connectome-workbench-1.4.2/src/Common/EventBrowserTabNewClone.cxx000066400000000000000000000050121360521144700251030ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_BROWSER_TAB_NEW_CLONE_DECLARE__ #include "EventBrowserTabNewClone.h" #undef __EVENT_BROWSER_TAB_NEW_CLONE_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventBrowserTabNewClone * \brief Get a browser tab that is cloned from another browser tab * \ingroup Common * * Get a browser tab that is cloned from another browser tab */ /** * Constructor. * * @param indexOfBrowserTabThatWillBeCloned * Index of browser tab that is cloned. */ EventBrowserTabNewClone::EventBrowserTabNewClone(const int32_t indexOfBrowserTabThatWillBeCloned) : Event(EventTypeEnum::EVENT_BROWSER_TAB_NEW_CLONE), m_indexOfBrowserTabThatWasClonded(indexOfBrowserTabThatWillBeCloned) { } /** * Destructor. */ EventBrowserTabNewClone::~EventBrowserTabNewClone() { } /** * @return The new browser tab. */ BrowserTabContent* EventBrowserTabNewClone::getNewBrowserTab() const { return m_newBrowserTabContent; } /** * Set the new browser tab and its index. * * @param newBrowserTab * The new browser tab. * @param newBrowserTabIndex * Index of the new browser tab. */ void EventBrowserTabNewClone::setNewBrowserTab(BrowserTabContent* newBrowserTab, const int32_t newBrowserTabIndex) { m_newBrowserTabContent = newBrowserTab; m_newBrowserTabIndex = newBrowserTabIndex; } /** * @return Index of the new browser index. */ int32_t EventBrowserTabNewClone::getNewBrowserTabIndex() const { return m_newBrowserTabIndex; } /** * @return Index of the browser tab that was cloned */ int32_t EventBrowserTabNewClone::getIndexOfBrowserTabThatWasCloned() const { return m_indexOfBrowserTabThatWasClonded; } connectome-workbench-1.4.2/src/Common/EventBrowserTabNewClone.h000066400000000000000000000042451360521144700245370ustar00rootroot00000000000000#ifndef __EVENT_BROWSER_TAB_NEW_CLONE_H__ #define __EVENT_BROWSER_TAB_NEW_CLONE_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class BrowserTabContent; class EventBrowserTabNewClone : public Event { public: EventBrowserTabNewClone(const int32_t indexOfBrowserTabThatWillBeCloned); virtual ~EventBrowserTabNewClone(); EventBrowserTabNewClone(const EventBrowserTabNewClone&) = delete; EventBrowserTabNewClone& operator=(const EventBrowserTabNewClone&) = delete; BrowserTabContent* getNewBrowserTab() const; void setNewBrowserTab(BrowserTabContent* newBrowserTab, const int32_t newBrowserTabIndex); int32_t getNewBrowserTabIndex() const; int32_t getIndexOfBrowserTabThatWasCloned() const; // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE const int32_t m_indexOfBrowserTabThatWasClonded = -1; BrowserTabContent* m_newBrowserTabContent = NULL; int32_t m_newBrowserTabIndex = -1; }; #ifdef __EVENT_BROWSER_TAB_NEW_CLONE_DECLARE__ // #endif // __EVENT_BROWSER_TAB_NEW_CLONE_DECLARE__ } // namespace #endif //__EVENT_BROWSER_TAB_NEW_CLONE_H__ connectome-workbench-1.4.2/src/Common/EventCaretPreferencesGet.cxx000066400000000000000000000034331360521144700252630ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_CARET_PREFERENCES_GET_DECLARE__ #include "EventCaretPreferencesGet.h" #undef __EVENT_CARET_PREFERENCES_GET_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventCaretPreferencesGet * \brief Event to get the Caret Preferences * \ingroup Common */ /** * Constructor. */ EventCaretPreferencesGet::EventCaretPreferencesGet() : Event(EventTypeEnum::EVENT_CARET_PREFERENCES_GET) { } /** * Destructor. */ EventCaretPreferencesGet::~EventCaretPreferencesGet() { } /** * Set the caret preferences. * * @param caretPreferences * Pointer to Caret Preferences */ void EventCaretPreferencesGet::setCaretPreferences(CaretPreferences* caretPreferences) { m_caretPreferences = caretPreferences; } /** * @return The caret preferences (NULL if caret preferences are invalid) */ CaretPreferences* EventCaretPreferencesGet::getCaretPreferences() const { return m_caretPreferences; } connectome-workbench-1.4.2/src/Common/EventCaretPreferencesGet.h000066400000000000000000000034501360521144700247070ustar00rootroot00000000000000#ifndef __EVENT_CARET_PREFERENCES_GET_H__ #define __EVENT_CARET_PREFERENCES_GET_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class CaretPreferences; class EventCaretPreferencesGet : public Event { public: EventCaretPreferencesGet(); virtual ~EventCaretPreferencesGet(); void setCaretPreferences(CaretPreferences* caretPreferences); CaretPreferences* getCaretPreferences() const; // ADD_NEW_METHODS_HERE private: EventCaretPreferencesGet(const EventCaretPreferencesGet&); EventCaretPreferencesGet& operator=(const EventCaretPreferencesGet&); CaretPreferences* m_caretPreferences = NULL; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_CARET_PREFERENCES_GET_DECLARE__ // #endif // __EVENT_CARET_PREFERENCES_GET_DECLARE__ } // namespace #endif //__EVENT_CARET_PREFERENCES_GET_H__ connectome-workbench-1.4.2/src/Common/EventGetViewportSize.cxx000066400000000000000000000065171360521144700245230ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_GET_VIEWPORT_SIZE_DECLARE__ #include "EventGetViewportSize.h" #undef __EVENT_GET_VIEWPORT_SIZE_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventGetViewportSize * \brief Event to get the viewport size for a tab. * \ingroup GuiQt */ /** * Constructor for finding size of a viewport * * @param mode * The mode. * @param index * Index of a tab or window. */ EventGetViewportSize::EventGetViewportSize(const Mode mode, const int32_t index) : Event(EventTypeEnum::EVENT_GET_VIEWPORT_SIZE), m_mode(mode), m_index(index), m_viewportValid(false) { m_viewport[0] = 0; m_viewport[1] = 0; m_viewport[2] = 0; m_viewport[3] = 0; } /** * Constructor for finding size of a viewport * * @param spacerTabIndex * Index of the spacer tab */ EventGetViewportSize::EventGetViewportSize(const SpacerTabIndex& spacerTabIndex) : Event(EventTypeEnum::EVENT_GET_VIEWPORT_SIZE), m_mode(MODE_SPACER_TAB_INDEX), m_index(-1), m_spacerTabIndex(spacerTabIndex), m_viewportValid(false) { } /** * Destructor. */ EventGetViewportSize::~EventGetViewportSize() { } /** * @return Is the viewport size valid (width and height greater than zero)? */ bool EventGetViewportSize::isViewportSizeValid() const { return m_viewportValid; } /** * @return The mode. */ EventGetViewportSize::Mode EventGetViewportSize::getMode() const { return m_mode; } /** * @return The tab/window index for which the viewport size is requested. */ int32_t EventGetViewportSize::getIndex() const { return m_index; } /** * @return The spacer tab index. */ SpacerTabIndex EventGetViewportSize::getSpacerTabIndex() const { return m_spacerTabIndex; } /** * Get the viewport size. * * @param viewportOut * Output containing viewport x, y, width, height. */ void EventGetViewportSize::getViewportSize(int32_t viewportOut[4]) const { viewportOut[0] = m_viewport[0]; viewportOut[1] = m_viewport[1]; viewportOut[2] = m_viewport[2]; viewportOut[3] = m_viewport[3]; } /** * Set the viewport size. * * @param viewport * Viewport x, y, width, height. */ void EventGetViewportSize::setViewportSize(const int32_t viewport[4]) { m_viewportValid = false; m_viewport[0] = viewport[0]; m_viewport[1] = viewport[1]; m_viewport[2] = viewport[2]; m_viewport[3] = viewport[3]; if ((m_viewport[2] > 0) && (m_viewport[3] > 0)) { m_viewportValid = true; } } connectome-workbench-1.4.2/src/Common/EventGetViewportSize.h000066400000000000000000000047111360521144700241420ustar00rootroot00000000000000#ifndef __EVENT_GET_VIEWPORT_SIZE_H__ #define __EVENT_GET_VIEWPORT_SIZE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" #include "SpacerTabIndex.h" namespace caret { class EventGetViewportSize : public Event { public: enum Mode { MODE_SPACER_TAB_INDEX, MODE_SURFACE_MONTAGE, MODE_TAB_BEFORE_MARGINS_INDEX, MODE_TAB_AFTER_MARGINS_INDEX, MODE_VOLUME_MONTAGE, MODE_WINDOW_INDEX, }; EventGetViewportSize(const Mode mode, const int32_t index); EventGetViewportSize(const SpacerTabIndex& spacerTabIndex); virtual ~EventGetViewportSize(); Mode getMode() const; int32_t getIndex() const; SpacerTabIndex getSpacerTabIndex() const; bool isViewportSizeValid() const; void getViewportSize(int32_t viewportOut[4]) const; void setViewportSize(const int32_t viewport[4]); // ADD_NEW_METHODS_HERE private: EventGetViewportSize(const EventGetViewportSize&); EventGetViewportSize& operator=(const EventGetViewportSize&); const Mode m_mode; const int32_t m_index = -1; SpacerTabIndex m_spacerTabIndex; bool m_viewportValid = false; int32_t m_viewport[4]; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_GET_VIEWPORT_SIZE_DECLARE__ // #endif // __EVENT_GET_VIEWPORT_SIZE_DECLARE__ } // namespace #endif //__EVENT_GET_VIEWPORT_SIZE_H__ connectome-workbench-1.4.2/src/Common/EventListenerInterface.cxx000066400000000000000000000024241360521144700250100ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventListenerInterface.h" #include "CaretAssert.h" #include "EventManager.h" using namespace caret; /** * \class caret::EventListenerInterface2 * \brief Interface for classes that listen for events * \ingroup Common */ /** * Constructor. */ EventListenerInterface::EventListenerInterface() { } /** * Destructor. */ EventListenerInterface::~EventListenerInterface() { EventManager::get()->verifyAllListenersRemoved(this); } connectome-workbench-1.4.2/src/Common/EventListenerInterface.h000066400000000000000000000037131360521144700244370ustar00rootroot00000000000000#ifndef __EVENT_LISTENER_INTERFACE_H__ #define __EVENT_LISTENER_INTERFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ namespace caret { class Event; /** * \brief Interface for objects receiving events. * * This interface must be implemented by any object that * wants to receive events. */ class EventListenerInterface { protected: /** * Constructor. */ EventListenerInterface(); /** * Destructor. */ virtual ~EventListenerInterface(); private: EventListenerInterface(const EventListenerInterface&) { } EventListenerInterface& operator=(const EventListenerInterface& ei); /*{ return *this; }//*/ //TSC: removed implementation to prevent "parameter unused" warnings, since it is private in an interface class public: /** * Receive an event. * * @param event * The event that the receive can respond to. */ virtual void receiveEvent(Event* event) = 0; }; } // namespace #endif // __EVENT_LISTENER_INTERFACE_H__ connectome-workbench-1.4.2/src/Common/EventManager.cxx000066400000000000000000000520351360521144700227570ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #define __EVENT_MANAGER_MAIN__ #include "Event.h" #include "EventManager.h" #undef __EVENT_MANAGER_MAIN__ #include "ApplicationInformation.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "EventAlertUser.h" #include "EventListenerInterface.h" #include "SystemUtilities.h" using namespace caret; /** * \class caret::EventManager * \brief The event manager. * * The event manager processes events * from senders to receivers. * * Events are sent by calling this class' sendEvent() * method. * * Objects that wish to receive events must (1) extend * publicly EventListenerInterface, (2) implement * EventListenerInterface's receiveEvent() method, * (3) Call one of two methods in EventManger, * addEventListener() or addProcessedEventListener() which * are typically called from the object's constructor, and * (4) call removeEventFromListener() or removeAllEventsFromListener * to cease listening for events which is typciall called * from the object's constructor. * * In most cases addEventListener() is used to request events. * addProcessedEventListener() is used when an object wants * to be notified of an event but not until after it has been * processed by at least one other receiver. For example, * a event for a new window may be sent. A receiver of the * event will create the new window. Other receivers may * want to know AFTER the window has been created in which * case these receivers will use addProcessedEventListener(). */ /** * Constructor. */ EventManager::EventManager() { m_eventIssuedCounter = 0; m_eventBlockingCounter.resize(EventTypeEnum::EVENT_COUNT, 0); } /** * Destructor. */ EventManager::~EventManager() { /* * Verify that all listeners were removed. */ for (int32_t i = 0; i < EventTypeEnum::EVENT_COUNT; i++) { EVENT_LISTENER_CONTAINER el = m_eventListeners[i]; if (el.empty() == false) { EventTypeEnum::Enum enumValue = static_cast(i); std::cout << "Not all listeners removed for event " << EventTypeEnum::toName(enumValue) << ", count is: " << el.size() << std::endl; } } /* * Verify that all processed listeners were removed. */ for (int32_t i = 0; i < EventTypeEnum::EVENT_COUNT; i++) { EVENT_LISTENER_CONTAINER el = m_eventProcessedListeners[i]; if (el.empty() == false) { EventTypeEnum::Enum enumValue = static_cast(i); std::cout << "Not all listeners removed for processed event " << EventTypeEnum::toName(enumValue) << ", count is: " << el.size() << std::endl; } } } /** * Create the event manager. */ void EventManager::createEventManager() { CaretAssertMessage((EventManager::s_singletonEventManager == NULL), "Event manager has already been created."); EventManager::s_singletonEventManager = new EventManager(); } /** * Delete the event manager. * This may only be called one time after event manager is created. */ void EventManager::deleteEventManager() { CaretAssertMessage((EventManager::s_singletonEventManager != NULL), "Event manager does not exist, cannot delete it."); delete EventManager::s_singletonEventManager; EventManager::s_singletonEventManager = NULL; } /** * Get the one and only event mangers. * * @return Pointer to the event manager. */ EventManager* EventManager::get() { CaretAssertMessage(EventManager::s_singletonEventManager, "Event manager was not created.\n" "It must be created with EventManager::createEventManager()."); return EventManager::s_singletonEventManager; } /** * Add a listener for a specific event. * * @param eventListener * Listener for an event. * @param listenForEventType * Type of event that is wanted. */ void EventManager::addEventListener(EventListenerInterface* eventListener, const EventTypeEnum::Enum listenForEventType) { #ifdef CONTAINER_VECTOR m_eventListeners[listenForEventType].push_back(eventListener); #elif CONTAINER_HASH_SET m_eventListeners[listenForEventType].insert(eventListener); #elif CONTAINER_SET m_eventListeners[listenForEventType].insert(eventListener); #else INTENTIONAL_COMPILER_ERROR_MISSING_CONTAINER_TYPE #endif } /** * Add a listener for a specific event but only receive the * event AFTER it has been processed. * * @param eventListener * Listener for an event. * @param listenForEventType * Type of event that is wanted. */ void EventManager::addProcessedEventListener(EventListenerInterface* eventListener, const EventTypeEnum::Enum listenForEventType) { #ifdef CONTAINER_VECTOR m_eventProcessedListeners[listenForEventType].push_back(eventListener); #elif CONTAINER_HASH_SET m_eventProcessedListeners[listenForEventType].insert(eventListener); #elif CONTAINER_SET m_eventProcessedListeners[listenForEventType].insert(eventListener); #else INTENTIONAL_COMPILER_ERROR_MISSING_CONTAINER_TYPE #endif } /** * Stop listening for an event. * * @param eventListener * Listener for an event. * @param listenForEventType * Type of event that is no longer wanted. */ void EventManager::removeEventFromListener(EventListenerInterface* eventListener, const EventTypeEnum::Enum listenForEventType) { #ifdef CONTAINER_VECTOR /* * Remove from NORMAL listeners */ EVENT_LISTENER_CONTAINER& listeners = m_eventListeners[listenForEventType]; EVENT_LISTENER_CONTAINER_ITERATOR eventIter = std::find(listeners.begin(), listeners.end(), eventListener); if (eventIter != listeners.end()) { listeners.erase(eventIter); } /* * Remove from PROCESSED listeners * These are issued AFTER all of the NORMAL listeners have been notified */ EVENT_LISTENER_CONTAINER& processedListeners = m_eventProcessedListeners[listenForEventType]; EVENT_LISTENER_CONTAINER_ITERATOR processedEventIter = std::find(processedListeners.begin(), processedListeners.end(), eventListener); if (processedEventIter != processedListeners.end()) { processedListeners.erase(processedEventIter); } #elif CONTAINER_HASH_SET m_eventListeners[listenForEventType].erase(eventListener); m_eventProcessedListeners[listenForEventType].erase(eventListener); #elif CONTAINER_SET m_eventListeners[listenForEventType].erase(eventListener); m_eventProcessedListeners[listenForEventType].erase(eventListener); #else INTENTIONAL_COMPILER_ERROR_MISSING_CONTAINER_TYPE #endif } /** * Stop listening for all events. * @param eventListener * Listener for all events. */ void EventManager::removeAllEventsFromListener(EventListenerInterface* eventListener) { for (int32_t i = 0; i < EventTypeEnum::EVENT_COUNT; i++) { removeEventFromListener(eventListener, static_cast(i)); } } /** * Send an event. * * @param event * Event that is sent. */ void EventManager::sendEvent(Event* event) { EventTypeEnum::Enum eventType = event->getEventType(); const AString eventNumberString = AString::number(m_eventIssuedCounter); const AString eventMessagePrefix = ("Event " + eventNumberString + ": " + event->toString() + " from thread: " + AString::number((uint64_t)QThread::currentThread()) + " "); const int32_t eventTypeIndex = static_cast(eventType); CaretAssertVectorIndex(m_eventBlockingCounter, eventTypeIndex); if (m_eventBlockingCounter[eventTypeIndex] > 0) { AString msg = (eventMessagePrefix + " is blocked. Blocking counter=" + AString::number(m_eventBlockingCounter[eventTypeIndex])); CaretLogFiner(msg); } else { if (eventType == EventTypeEnum::EVENT_ALERT_USER) { /* * Only send the ALERT USER event if there is a GUI. * Otherwise, simply log the alert message. */ EventAlertUser* alertEvent = dynamic_cast(event); CaretAssert(alertEvent); if (ApplicationInformation::getApplicationType() != ApplicationTypeEnum::APPLICATION_TYPE_GRAPHICAL_USER_INTERFACE) { CaretLogSevere(alertEvent->getMessage()); return; } } /* * Get listeners for event. */ EVENT_LISTENER_CONTAINER listeners = m_eventListeners[eventType]; const AString eventNumberString = AString::number(m_eventIssuedCounter); /* * Send event to each of the listeners. */ for (EVENT_LISTENER_CONTAINER_ITERATOR iter = listeners.begin(); iter != listeners.end(); iter++) { EventListenerInterface* listener = *iter; listener->receiveEvent(event); if (event->isError()) { CaretLogWarning("Event " + eventNumberString + " had error: " + event->toString() + ": " + event->getErrorMessage()); break; } } /* * Verify event was processed. */ if (event->getEventProcessCount() > 0) { /* * Send event to each of the PROCESSED listeners. */ EVENT_LISTENER_CONTAINER processedListeners = m_eventProcessedListeners[eventType]; for (EVENT_LISTENER_CONTAINER_ITERATOR iter = processedListeners.begin(); iter != processedListeners.end(); iter++) { EventListenerInterface* listener = *iter; listener->receiveEvent(event); if (event->isError()) { CaretLogWarning("Event " + eventNumberString + " had error: " + event->toString()); break; } } } else { } m_eventIssuedCounter++; } } /** * Send a "simple" event. A simple event is one for which there is no * specialized subclass of "Event". This method try to prevent sending * a "non-simple" event and it will need to be updated if an event * either has a specialized subclass added or removed. * * @param eventType * Event type that is sent. */ void EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) { switch (eventType) { case EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE: case EventTypeEnum::EVENT_BROWSER_WINDOW_MENUS_UPDATE: case EventTypeEnum::EVENT_MOVIE_RECORDING_DIALOG_UPDATE: case EventTypeEnum::EVENT_UPDATE_VOLUME_SLICE_INDICES_COORDS_TOOLBAR: { sendEvent(Event(eventType).getPointer()); } break; case EventTypeEnum::EVENT_INVALID: case EventTypeEnum::EVENT_COUNT: { const AString msg(EventTypeEnum::toName(eventType) + " should never be sent as an event."); CaretAssertMessage(0, msg); CaretLogSevere(msg); } break; case EventTypeEnum::EVENT_ALERT_USER: case EventTypeEnum::EVENT_ANNOTATION_ADD_TO_REMOVE_FROM_FILE: case EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET: case EventTypeEnum::EVENT_ANNOTATION_COLOR_BAR_GET: case EventTypeEnum::EVENT_ANNOTATION_CREATE_NEW_TYPE: case EventTypeEnum::EVENT_ANNOTATION_GET_DRAWN_IN_WINDOW: case EventTypeEnum::EVENT_ANNOTATION_GROUP_GET_WITH_KEY: case EventTypeEnum::EVENT_ANNOTATION_GROUPING: case EventTypeEnum::EVENT_ANNOTATION_TEXT_SUBSTITUTION_GET: case EventTypeEnum::EVENT_ANNOTATION_TEXT_SUBSTITUTION_INVALIDATE: case EventTypeEnum::EVENT_BRAIN_RESET: case EventTypeEnum::EVENT_BRAIN_STRUCTURE_GET_ALL: case EventTypeEnum::EVENT_BROWSER_TAB_DELETE: case EventTypeEnum::EVENT_BROWSER_TAB_GET: case EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL: case EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL_VIEWED: case EventTypeEnum::EVENT_BROWSER_TAB_INDICES_GET_ALL: case EventTypeEnum::EVENT_BROWSER_TAB_NEW: case EventTypeEnum::EVENT_BROWSER_TAB_NEW_CLONE: case EventTypeEnum::EVENT_BROWSER_WINDOW_CONTENT: case EventTypeEnum::EVENT_BROWSER_WINDOW_CREATE_TABS: case EventTypeEnum::EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET: case EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN: case EventTypeEnum::EVENT_BROWSER_WINDOW_NEW: case EventTypeEnum::EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION: case EventTypeEnum::EVENT_CARET_DATA_FILES_GET: case EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILES_GET: case EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS: case EventTypeEnum::EVENT_CARET_PREFERENCES_GET: case EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS: case EventTypeEnum::EVENT_CHART_MATRIX_YOKING_VALIDATION: case EventTypeEnum::EVENT_CHART_OVERLAY_VALIDATE: case EventTypeEnum::EVENT_CHART_TWO_ATTRIBUTES_CHANGED: case EventTypeEnum::EVENT_CHART_TWO_AXIS_GET_DATA_RANGE: case EventTypeEnum::EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA: case EventTypeEnum::EVENT_DATA_FILE_ADD: case EventTypeEnum::EVENT_DATA_FILE_DELETE: case EventTypeEnum::EVENT_DATA_FILE_READ: case EventTypeEnum::EVENT_DATA_FILE_RELOAD: case EventTypeEnum::EVENT_GET_DISPLAYED_DATA_FILES: case EventTypeEnum::EVENT_GET_NODE_DATA_FILES: case EventTypeEnum::EVENT_GET_OR_SET_USER_INPUT_MODE: case EventTypeEnum::EVENT_GET_TEXT_RENDERER_FOR_WINDOW: case EventTypeEnum::EVENT_GET_VIEWPORT_SIZE: case EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_BUFFER_OBJECT: case EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_TEXTURE_NAME: case EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT: case EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_TEXTURE_NAME: case EventTypeEnum::EVENT_GRAPHICS_TIMING_ONE_WINDOW: case EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS: case EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW: case EventTypeEnum::EVENT_HELP_VIEWER_DISPLAY: case EventTypeEnum::EVENT_IDENTIFICATION_HIGHLIGHT_LOCATION: case EventTypeEnum::EVENT_IDENTIFICATION_SYMBOL_REMOVAL: case EventTypeEnum::EVENT_IDENTIFICATION_REQUEST: case EventTypeEnum::EVENT_IMAGE_CAPTURE: case EventTypeEnum::EVENT_MAC_DOCK_MENU_UPDATE: case EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP: case EventTypeEnum::EVENT_MAP_YOKING_VALIDATION: case EventTypeEnum::EVENT_MODEL_ADD: case EventTypeEnum::EVENT_MODEL_DELETE: case EventTypeEnum::EVENT_MODEL_GET_ALL: case EventTypeEnum::EVENT_MODEL_GET_ALL_DISPLAYED: case EventTypeEnum::EVENT_MODEL_SURFACE_GET: case EventTypeEnum::EVENT_MOVIE_RECORDING_MANUAL_MODE_CAPTURE: case EventTypeEnum::EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS: case EventTypeEnum::EVENT_OPENGL_OBJECT_TO_WINDOW_TRANSFORM: case EventTypeEnum::EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE: case EventTypeEnum::EVENT_OVERLAY_SETTINGS_EDITOR_SHOW: case EventTypeEnum::EVENT_OVERLAY_VALIDATE: case EventTypeEnum::EVENT_PALETTE_COLOR_MAPPING_EDITOR_SHOW: case EventTypeEnum::EVENT_PALETTE_GET_BY_NAME: case EventTypeEnum::EVENT_SCENE_ACTIVE: case EventTypeEnum::EVENT_SHOW_FILE_DATA_READ_WARNING_DIALOG: case EventTypeEnum::EVENT_SPACER_TAB_GET: case EventTypeEnum::EVENT_SPEC_FILE_READ_DATA_FILES: case EventTypeEnum::EVENT_SURFACE_COLORING_INVALIDATE: case EventTypeEnum::EVENT_SURFACES_GET: case EventTypeEnum::EVENT_SURFACE_STRUCTURES_VALID_GET: case EventTypeEnum::EVENT_TILE_TABS_MODIFICATION: case EventTypeEnum::EVENT_TOOLBOX_SELECTION_DISPLAY: case EventTypeEnum::EVENT_USER_INTERFACE_UPDATE: case EventTypeEnum::EVENT_PROGRESS_UPDATE: case EventTypeEnum::EVENT_UPDATE_INFORMATION_WINDOWS: case EventTypeEnum::EVENT_UPDATE_VOLUME_EDITING_TOOLBAR: case EventTypeEnum::EVENT_UPDATE_YOKED_WINDOWS: { const AString msg(EventTypeEnum::toName(eventType) + " has an special subclass of class Event and should never be sent as an event."); CaretAssertMessage(0, msg); CaretLogSevere(msg); } break; } } /** * Block an event. A counter is used to track blocking of each * event type. Each time a request is made to block an event type, * the counter is incremented for that event type. When a request * is made to un-block the event, the counter is decremented. This * allows multiple requests for blocking an event to come from * different sections of the source code. Thus, anytime the * blocking counter is greater than zero for an event, the event * is blocked. * * @param eventType * Type of event to block. * @param blockStatus * Blocking status (true increments blocking counter, * false decrements blocking counter. */ void EventManager::blockEvent(const EventTypeEnum::Enum eventType, const bool blockStatus) { const int32_t eventTypeIndex = static_cast(eventType); CaretAssertVectorIndex(m_eventBlockingCounter, eventTypeIndex); const AString eventName = EventTypeEnum::toName(eventType); if (blockStatus) { m_eventBlockingCounter[eventTypeIndex]++; CaretLogFiner("Blocking event " + eventName + " blocking counter is now " + AString::number(m_eventBlockingCounter[eventTypeIndex])); } else { if (m_eventBlockingCounter[eventTypeIndex] > 0) { m_eventBlockingCounter[eventTypeIndex]--; CaretLogFiner("Unblocking event " + eventName + " blocking counter is now " + AString::number(m_eventBlockingCounter[eventTypeIndex])); } else { const AString message("Trying to unblock event " + eventName + " but it is not blocked"); CaretAssertMessage(0, message); CaretLogWarning(message); } } } /** * @return The cumulative number of events that have been sent. */ int64_t EventManager::getEventIssuedCounter() const { return m_eventIssuedCounter; } /** * Verify that all listeners have been removed from the given event listener. * * @param eventListener * The event listener. */ void EventManager::verifyAllListenersRemoved(EventListenerInterface* eventListener) { AString eventNames; for (int32_t i = 0; i < EventTypeEnum::EVENT_COUNT; i++) { const EventTypeEnum::Enum eventType = static_cast(i); if ((m_eventListeners[eventType].find(eventListener) != m_eventListeners[eventType].end()) || (m_eventProcessedListeners[eventType].find(eventListener) != m_eventProcessedListeners[eventType].end())) { eventNames.appendWithNewLine(" " + EventTypeEnum::toName(eventType)); } } if ( ! eventNames.isEmpty()) { SystemBacktrace myBacktrace; SystemUtilities::getBackTrace(myBacktrace); CaretLogSevere("Failed to remove events from class instance. Event names:\n" + eventNames + ":\n" + myBacktrace.toSymbolString()); } } connectome-workbench-1.4.2/src/Common/EventManager.h000066400000000000000000000112441360521144700224010ustar00rootroot00000000000000#ifndef __EVENT_MANAGER_H__ #define __EVENT_MANAGER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "EventTypeEnum.h" //#define CONTAINER_VECTOR 1 //#define CONTAINER_HASH_SET 1 #define CONTAINER_SET 1 #ifdef CONTAINER_VECTOR #include #elif CONTAINER_HASH_SET #include #include "CaretHashSet.h" #elif CONTAINER_SET #include #else INTENTIONAL_COMPILER_ERROR_MISSING_CONTAINER_TYPE #endif namespace caret { class Event; class EventListenerInterface; #ifdef CONTAINER_HASH_SET class EventListenerCompareHash { public: bool operator()(const EventListenerInterface* e1, const EventListenerInterface* e2) const { return (e1 == e2); } }; class EventListenerInterfaceHash { public: size_t operator()(const EventListenerInterface* p) const { EventListenerInterface* el = const_cast(p); return reinterpret_cast((void*)el); } }; #endif // CONTAINER_HASH_SET class EventManager : public CaretObject { public: static void createEventManager(); static void deleteEventManager(); static EventManager* get(); void addEventListener(EventListenerInterface* eventListener, const EventTypeEnum::Enum listenForEventType); void addProcessedEventListener(EventListenerInterface* eventListener, const EventTypeEnum::Enum listenForEventType); void removeEventFromListener(EventListenerInterface* eventListener, const EventTypeEnum::Enum listenForEventType); void removeAllEventsFromListener(EventListenerInterface* eventListener); void sendEvent(Event* event); void sendSimpleEvent(const EventTypeEnum::Enum eventType); void blockEvent(const EventTypeEnum::Enum eventToBlock, const bool blockStatus); int64_t getEventIssuedCounter() const; private: EventManager(); virtual ~EventManager(); void verifyAllListenersRemoved(EventListenerInterface* eventListener); /** * Define the container */ #ifdef CONTAINER_VECTOR typedef std::vector EVENT_LISTENER_CONTAINER; #elif CONTAINER_HASH_SET typedef caret::hash_set EVENT_LISTENER_CONTAINER; #elif CONTAINER_SET typedef std::set EVENT_LISTENER_CONTAINER; #else INTENTIONAL_COMPILER_ERROR_MISSING_CONTAINER_TYPE #endif /** * Iterator for the container */ typedef EVENT_LISTENER_CONTAINER::iterator EVENT_LISTENER_CONTAINER_ITERATOR; /** * The event listeners */ EVENT_LISTENER_CONTAINER m_eventListeners[EventTypeEnum::EVENT_COUNT]; /** * Special listeners that are notified AFTER the eventListeners */ EVENT_LISTENER_CONTAINER m_eventProcessedListeners[EventTypeEnum::EVENT_COUNT]; /** Counter that is incremented each time an event is issued */ int64_t m_eventIssuedCounter; /** A counter for blocking events of each type */ std::vector m_eventBlockingCounter; static EventManager* s_singletonEventManager; friend EventListenerInterface; }; #ifdef __EVENT_MANAGER_MAIN__ EventManager* EventManager::s_singletonEventManager = NULL; #endif // __EVENT_MANAGER_MAIN__ } // namespace #endif // __EVENT_MANAGER_H__ connectome-workbench-1.4.2/src/Common/EventPaletteGetByName.cxx000066400000000000000000000041741360521144700245400ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_PALETTE_GET_BY_NAME_DECLARE__ #include "EventPaletteGetByName.h" #undef __EVENT_PALETTE_GET_BY_NAME_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventPaletteGetByName * \brief Find a palette by name * \ingroup Common */ /** * Constructor. */ EventPaletteGetByName::EventPaletteGetByName(const AString& paletteName) : Event(EventTypeEnum::EVENT_PALETTE_GET_BY_NAME), m_paletteName(paletteName), m_palette(NULL) { } /** * Destructor. */ EventPaletteGetByName::~EventPaletteGetByName() { } /** * @return Name of desired palette. */ AString EventPaletteGetByName::getPaletteName() const { return m_paletteName; } /** * @return Palette that was found (NULL if no matching palette was found). */ Palette* EventPaletteGetByName::getPalette() const { return m_palette; } /** * Set the palette that matches by name. * * @param palette * Palette that matches name of desired palette. */ void EventPaletteGetByName::setPalette(Palette* palette) { CaretAssert(palette); if (m_palette != NULL) { CaretLogWarning("There appears to be more than one palette with name \"" + m_paletteName + "\""); } m_palette = palette; } connectome-workbench-1.4.2/src/Common/EventPaletteGetByName.h000066400000000000000000000034501360521144700241610ustar00rootroot00000000000000#ifndef __EVENT_PALETTE_GET_BY_NAME_H__ #define __EVENT_PALETTE_GET_BY_NAME_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class Palette; class EventPaletteGetByName : public Event { public: EventPaletteGetByName(const AString& paletteName); virtual ~EventPaletteGetByName(); AString getPaletteName() const; Palette* getPalette() const; void setPalette(Palette* palette); // ADD_NEW_METHODS_HERE private: EventPaletteGetByName(const EventPaletteGetByName&); EventPaletteGetByName& operator=(const EventPaletteGetByName&); const AString m_paletteName; Palette* m_palette; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_PALETTE_GET_BY_NAME_DECLARE__ // #endif // __EVENT_PALETTE_GET_BY_NAME_DECLARE__ } // namespace #endif //__EVENT_PALETTE_GET_BY_NAME_H__ connectome-workbench-1.4.2/src/Common/EventProgressUpdate.cxx000066400000000000000000000075041360521144700243550ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventProgressUpdate.h" using namespace caret; /** * \class caret::EventProgressUpdate * \brief Event for updating progress of a task in a progress dialog. */ EventProgressUpdate::EventProgressUpdate(ProgressObject* myObject): Event(EventTypeEnum::EVENT_PROGRESS_UPDATE), m_minimumProgressValue(0), m_maximumProgressValue(100), m_progressValue(0), m_progressMessage(""), m_cancelled(false) { m_amountUpdate = false; m_finished = false; m_textUpdate = false; m_starting = false; m_whichObject = myObject; } /** * Default constructor. * * If this instance is not modified and sent to a progress dialog * no updates will be made to the progress dialog. However, if the * user has cancelled the task, the cancel status will be set in * this instance after returning from the dialog. */ EventProgressUpdate::EventProgressUpdate() : Event(EventTypeEnum::EVENT_PROGRESS_UPDATE), m_minimumProgressValue(-1), m_maximumProgressValue(-1), m_progressValue(-1), m_progressMessage(""), m_cancelled(false) { /* nothing */ } /* * Constructor for display of progress in a progress dialog. * * @param minimumProgressValue * Minimum Progress. * @param maximumProgressValue * Maximum progress. * @param progressValue * Current progress (min <= current <= maximum) * @param progressMessage * Message for display in progress dialog. * */ EventProgressUpdate::EventProgressUpdate(const int minimumProgressValue, const int maximumProgressValue, const int progressValue, const QString& progressMessage) : Event(EventTypeEnum::EVENT_PROGRESS_UPDATE), m_minimumProgressValue(minimumProgressValue), m_maximumProgressValue(maximumProgressValue), m_progressValue(progressValue), m_progressMessage(progressMessage), m_cancelled(false) { } EventProgressUpdate::EventProgressUpdate(const QString& progressMessage) : Event(EventTypeEnum::EVENT_PROGRESS_UPDATE), m_minimumProgressValue(-1), m_maximumProgressValue(-1), m_progressValue(-1), m_progressMessage(progressMessage), m_cancelled(false) { } /** * Destructor. */ EventProgressUpdate::~EventProgressUpdate() { } /* * Set values for display of progress in a progress dialog. This method * allows a progress event to be reused and avoid reallocation, particularly * when updates are frequent. * * @param progressValue * Current progress (min <= current <= maximum) * @param progressMessage * Message for display in progress dialog. * */ void EventProgressUpdate::setProgress(const int progressValue, const QString& progressMessage) { m_progressValue = progressValue; m_progressMessage = progressMessage; } /* * Update only the progress message in the progress dialog. * * @param progressMessage * Message for display in progress dialog. * */ void EventProgressUpdate::setProgressMessage(const QString& progressMessage) { m_progressMessage = progressMessage; } connectome-workbench-1.4.2/src/Common/EventProgressUpdate.h000066400000000000000000000057321360521144700240030ustar00rootroot00000000000000#ifndef __EVENT_PROGRESS_UPDATE_H__ #define __EVENT_PROGRESS_UPDATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class ProgressObject; /// Event for updating the user-interface class EventProgressUpdate : public Event { public: EventProgressUpdate(); EventProgressUpdate(ProgressObject* myObject); EventProgressUpdate(const int minimumProgressValue, const int maximumProgressValue, const int progressValue, const QString& progressMessage); EventProgressUpdate(const QString& progressMessage); virtual ~EventProgressUpdate(); void setProgress(const int progressValue, const QString& progressMessage); void setProgressMessage(const QString& progressMessage); bool m_textUpdate, m_amountUpdate, m_finished, m_starting; ProgressObject* m_whichObject;//idea is for progress elements to check whether their object emitted this event or not, if not, ignore /** @return Did the user request cancellation of the task */ bool isCancelled() const { return m_cancelled; } /** @return Minimum progress value. */ int getMinimumProgressValue() const { return m_minimumProgressValue; } /** @return Maximum progress value */ int getMaximumProgressValue() const { return m_maximumProgressValue; } /** @return Current value of progress */ int getProgressValue() const { return m_progressValue; } /** @return Message displayed describing progress */ QString getProgressMessage() const { return m_progressMessage; } /** Request cancellation of the task */ void setCancelled() { m_cancelled = true; } private: EventProgressUpdate(const EventProgressUpdate&); EventProgressUpdate& operator=(const EventProgressUpdate&); int m_minimumProgressValue; int m_maximumProgressValue; int m_progressValue; QString m_progressMessage; bool m_cancelled; }; } // namespace #endif // __EVENT_PROGRESS_UPDATE_H__ connectome-workbench-1.4.2/src/Common/EventTileTabsConfigurationModification.cxx000066400000000000000000000065301360521144700301710ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_DECLARE__ #include "EventTileTabsConfigurationModification.h" #undef __EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventTileTabsConfigurationModification * \brief Event for modifying a tile tabs configuration. * \ingroup Common */ /** * Constructor. * * @param tileTabsConfiguration * Tile tabs configuration that will be modified * @param rowColumnIndex * Index of the row or column used for modification * @param rowColumnType * 'Row' or "Column' type * @param operation * Enumerated type with type of modification. */ EventTileTabsConfigurationModification::EventTileTabsConfigurationModification(TileTabsConfiguration* tileTabsConfiguration, const int32_t rowColumnIndex, const RowColumnType rowColumnType, const Operation operation) : Event(EventTypeEnum::EVENT_TILE_TABS_MODIFICATION), m_tileTabsConfiguration(tileTabsConfiguration), m_rowColumnIndex(rowColumnIndex), m_rowColumnType(rowColumnType), m_operation(operation), m_windowIndex(-1) { } /** * Destructor. */ EventTileTabsConfigurationModification::~EventTileTabsConfigurationModification() { } /** * @return Tile tabs configuration that is modified. */ TileTabsConfiguration* EventTileTabsConfigurationModification::getTileTabsConfiguration() { return m_tileTabsConfiguration; } /** * @return Index of the window. */ int32_t EventTileTabsConfigurationModification::getWindowIndex() const { return m_windowIndex; } /** * Set the window index. * * @param windowIndex * Index of the window. */ void EventTileTabsConfigurationModification::setWindowIndex(const int32_t windowIndex) { m_windowIndex = windowIndex; } /** * @return The index of the row or column. */ int32_t EventTileTabsConfigurationModification::getRowColumnIndex() const { return m_rowColumnIndex; } /** * @return The type ROW or COLUMN */ EventTileTabsConfigurationModification::RowColumnType EventTileTabsConfigurationModification::getRowColumnType() const { return m_rowColumnType; } /** * @return The operation. */ EventTileTabsConfigurationModification::Operation EventTileTabsConfigurationModification::getOperation() const { return m_operation; } connectome-workbench-1.4.2/src/Common/EventTileTabsConfigurationModification.h000066400000000000000000000061461360521144700276210ustar00rootroot00000000000000#ifndef __EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_H__ #define __EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class TileTabsConfiguration; class EventTileTabsConfigurationModification : public Event { public: /** * Row or Column */ enum class RowColumnType { COLUMN, ROW }; /** * Operation */ enum class Operation { DELETE_IT, /* DELETE is reserved word on Windows */ DUPLICATE_AFTER, DUPLICATE_BEFORE, INSERT_SPACER_BEFORE, INSERT_SPACER_AFTER, MOVE_AFTER, MOVE_BEFORE }; EventTileTabsConfigurationModification(TileTabsConfiguration* tileTabsConfiguration, const int32_t rowColumnIndex, const RowColumnType rowColumnType, const Operation operation); virtual ~EventTileTabsConfigurationModification(); EventTileTabsConfigurationModification(const EventTileTabsConfigurationModification&) = delete; EventTileTabsConfigurationModification& operator=(const EventTileTabsConfigurationModification&) = delete; TileTabsConfiguration* getTileTabsConfiguration(); int32_t getRowColumnIndex() const; RowColumnType getRowColumnType() const; Operation getOperation() const; int32_t getWindowIndex() const; void setWindowIndex(const int32_t windowIndex); // ADD_NEW_METHODS_HERE private: TileTabsConfiguration* m_tileTabsConfiguration; const int32_t m_rowColumnIndex; const RowColumnType m_rowColumnType; const Operation m_operation; int32_t m_windowIndex = -1; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_DECLARE__ // #endif // __EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_DECLARE__ } // namespace #endif //__EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_H__ connectome-workbench-1.4.2/src/Common/EventTypeEnum.cxx000066400000000000000000000645741360521144700231660ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_TYPE_ENUM_DECLARE__ #include "EventTypeEnum.h" #undef __EVENT_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" using namespace caret; /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumberated value. */ EventTypeEnum::EventTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->name = name; this->guiName = guiName; } /** * Destructor. */ EventTypeEnum::~EventTypeEnum() { } /** * Initialize the enumerated metadata. */ void EventTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(EventTypeEnum(EVENT_INVALID, "EVENT_INVALID", "Invalid Event")); enumData.push_back(EventTypeEnum(EVENT_ALERT_USER, "EVENT_ALERT_USER", "Alert user about something (if gui, a pop is displayed, otherwise logged at severe level")); enumData.push_back(EventTypeEnum(EVENT_ANNOTATION_ADD_TO_REMOVE_FROM_FILE, "EVENT_ANNOTATION_ADD_TO_REMOVE_FROM_FILE", "Event to add or remove an annotation from a file")); enumData.push_back(EventTypeEnum(EVENT_ANNOTATION_CHART_LABEL_GET, "EVENT_ANNOTATION_CHART_LABEL_GET", "Event to get annotation chart labels")); enumData.push_back(EventTypeEnum(EVENT_ANNOTATION_COLOR_BAR_GET, "EVENT_ANNOTATION_COLOR_BAR_GET", "Event to get annotation color bars from tab(s)")); enumData.push_back(EventTypeEnum(EVENT_ANNOTATION_CREATE_NEW_TYPE, "EVENT_ANNOTATION_CREATE_NEW_TYPE", "Event to create a new annotation of a particular type")); enumData.push_back(EventTypeEnum(EVENT_ANNOTATION_GET_DRAWN_IN_WINDOW, "EVENT_ANNOTATION_GET_DRAWN_IN_WINDOW", "Event for getting annotations drawn in a window")); enumData.push_back(EventTypeEnum(EVENT_ANNOTATION_GROUP_GET_WITH_KEY, "EVENT_ANNOTATION_GROUP_GET_WITH_KEY", "Event for getting an annotation group using its key")); enumData.push_back(EventTypeEnum(EVENT_ANNOTATION_GROUPING, "EVENT_ANNOTATION_GROUPING", "Event for annotation grouping")); enumData.push_back(EventTypeEnum(EVENT_ANNOTATION_TEXT_SUBSTITUTION_GET, "EVENT_ANNOTATION_TEXT_SUBSTITUTION_GET", "Get an annotation text substitution")); enumData.push_back(EventTypeEnum(EVENT_ANNOTATION_TEXT_SUBSTITUTION_INVALIDATE, "EVENT_ANNOTATION_TEXT_SUBSTITUTION_INVALIDATE", "Invalidate text substitutions in text annotations")); enumData.push_back(EventTypeEnum(EVENT_ANNOTATION_TOOLBAR_UPDATE, "EVENT_ANNOTATION_TOOLBAR_UPDATE", "Event to update annotation toolbar")); enumData.push_back(EventTypeEnum(EVENT_BRAIN_RESET, "EVENT_BRAIN_RESET", "Brain has been reset")); enumData.push_back(EventTypeEnum(EVENT_BRAIN_STRUCTURE_GET_ALL, "EVENT_BRAIN_STRUCTURE_GET_ALL", "Get all brain structures")); enumData.push_back(EventTypeEnum(EVENT_BROWSER_TAB_DELETE, "EVENT_BROWSER_TAB_DELETE", "Delete a browser tab")); enumData.push_back(EventTypeEnum(EVENT_BROWSER_TAB_GET, "EVENT_BROWSER_TAB_GET", "Get a browser tab by number")); enumData.push_back(EventTypeEnum(EVENT_BROWSER_TAB_GET_ALL, "EVENT_BROWSER_TAB_GET_ALL", "Get ALL browser tabs")); enumData.push_back(EventTypeEnum(EVENT_BROWSER_TAB_GET_ALL_VIEWED, "EVENT_BROWSER_TAB_GET_ALL_VIEWED", "Get ALL Viewed browser tabs")); enumData.push_back(EventTypeEnum(EVENT_BROWSER_TAB_INDICES_GET_ALL, "EVENT_BROWSER_TAB_INDICES_GET_ALL", "Browser Tab Indices Get All")); enumData.push_back(EventTypeEnum(EVENT_BROWSER_TAB_NEW, "EVENT_BROWSER_TAB_NEW", "Create a browser tab")); enumData.push_back(EventTypeEnum(EVENT_BROWSER_TAB_NEW_CLONE, "EVENT_BROWSER_TAB_NEW_CLONE", "Create a browser tab by cloning an existing browser tab")); enumData.push_back(EventTypeEnum(EVENT_BROWSER_WINDOW_CONTENT, "EVENT_BROWSER_WINDOW_CONTENT", "Event for browser window content")); enumData.push_back(EventTypeEnum(EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET, "EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET", "Get the content in a browser window")); enumData.push_back(EventTypeEnum(EVENT_BROWSER_WINDOW_CREATE_TABS, "EVENT_BROWSER_WINDOW_CREATE_TABS", "Create tabs (if needed) after loading data files")); enumData.push_back(EventTypeEnum(EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN, "EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN", "A Browser Window's graphics have been redrawn")); enumData.push_back(EventTypeEnum(EVENT_BROWSER_WINDOW_MENUS_UPDATE, "EVENT_BROWSER_WINDOW_MENUS_UPDATE", "Update the browser windows menus")); enumData.push_back(EventTypeEnum(EVENT_BROWSER_WINDOW_NEW, "EVENT_BROWSER_WINDOW_NEW", "Create a new browser window")); enumData.push_back(EventTypeEnum(EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION, "EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION", "Browser Window Tile Tab Operation")); enumData.push_back(EventTypeEnum(EVENT_CARET_DATA_FILES_GET, "EVENT_CARET_DATA_FILES_GET", "Get all Caret data files")); enumData.push_back(EventTypeEnum(EVENT_CARET_MAPPABLE_DATA_FILES_GET, "EVENT_CARET_MAPPABLE_DATA_FILES_GET", "Get all Caret Mappable data files")); enumData.push_back(EventTypeEnum(EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS, "EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS", "Get Caret Mappable data file maps viewed in overlays")); enumData.push_back(EventTypeEnum(EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS, "EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS", "Get all selected mappable data and map indices in displayed overlays")); enumData.push_back(EventTypeEnum(EVENT_CARET_PREFERENCES_GET, "EVENT_CARET_PREFERENCES_GET", "Get the Caret Preferences")); enumData.push_back(EventTypeEnum(EVENT_CHART_MATRIX_YOKING_VALIDATION, "EVENT_CHART_MATRIX_YOKING_VALIDATION", "Validate Yoking of matrix chart's rows/columns")); enumData.push_back(EventTypeEnum(EVENT_GRAPHICS_OPENGL_CREATE_BUFFER_OBJECT, "EVENT_GRAPHICS_OPENGL_CREATE_BUFFER_OBJECT", "Create an OpenGL Buffer Object for an OpenGL Context")); enumData.push_back(EventTypeEnum(EVENT_GRAPHICS_OPENGL_CREATE_TEXTURE_NAME, "EVENT_GRAPHICS_OPENGL_CREATE_TEXTURE_NAME", "Create an OpenGL Texture Name for an OpenGL Context")); enumData.push_back(EventTypeEnum(EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT, "EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT", "Delete an OpenGL Buffer Object for an OpenGL Context")); enumData.push_back(EventTypeEnum(EVENT_GRAPHICS_OPENGL_DELETE_TEXTURE_NAME, "EVENT_GRAPHICS_OPENGL_DELETE_TEXTURE_NAME", "Delete an OpenGL Texture Name for an OpenGL Context")); enumData.push_back(EventTypeEnum(EVENT_CHART_OVERLAY_VALIDATE, "EVENT_CHART_OVERLAY_VALIDATE", "Validate a chart overlay for validity (it exists)")); enumData.push_back(EventTypeEnum(EVENT_CHART_TWO_ATTRIBUTES_CHANGED, "EVENT_CHART_TWO_ATTRIBUTES_CHANGED", "GUI notification of the change in chart two atttributes")); enumData.push_back(EventTypeEnum(EVENT_CHART_TWO_AXIS_GET_DATA_RANGE, "EVENT_CHART_TWO_AXIS_GET_DATA_RANGE", "Get the range of data for a chart two axis")); enumData.push_back(EventTypeEnum(EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA, "EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA", "Load line series data for chart two implementation")); enumData.push_back(EventTypeEnum(EVENT_DATA_FILE_ADD, "EVENT_DATA_FILE_ADD", "Add a data file to the Brain")); enumData.push_back(EventTypeEnum(EVENT_DATA_FILE_DELETE, "EVENT_DATA_FILE_DELETE", "Delete a data file from the Brain")); enumData.push_back(EventTypeEnum(EVENT_DATA_FILE_READ, "EVENT_DATA_FILE_READ", "Read a data file into the Brain")); enumData.push_back(EventTypeEnum(EVENT_DATA_FILE_RELOAD, "EVENT_DATA_FILE_RELOAD", "Reopen a data file (replace it with saved version) in the Brain")); enumData.push_back(EventTypeEnum(EVENT_GET_DISPLAYED_DATA_FILES, "EVENT_GET_DISPLAYED_DATA_FILES", "Get data files displayed in windows/tabs")); enumData.push_back(EventTypeEnum(EVENT_GET_NODE_DATA_FILES, "EVENT_GET_NODE_DATA_FILES", "Get node data files")); enumData.push_back(EventTypeEnum(EVENT_GET_OR_SET_USER_INPUT_MODE, "EVENT_GET_OR_SET_USER_INPUT_MODE", "Get or set the user input mode")); enumData.push_back(EventTypeEnum(EVENT_GET_TEXT_RENDERER_FOR_WINDOW, "EVENT_GET_TEXT_RENDERER_FOR_WINDOW", "Get the text renderer for a window")); enumData.push_back(EventTypeEnum(EVENT_GET_VIEWPORT_SIZE, "EVENT_GET_VIEWPORT_SIZE", "Get the viewport size")); enumData.push_back(EventTypeEnum(EVENT_GRAPHICS_TIMING_ONE_WINDOW, "EVENT_GRAPHICS_TIMING_ONE_WINDOW", "Graphics timing in one window")); enumData.push_back(EventTypeEnum(EVENT_GRAPHICS_UPDATE_ALL_WINDOWS, "EVENT_GRAPHICS_UPDATE_ALL_WINDOWS", "Update all graphics windows")); enumData.push_back(EventTypeEnum(EVENT_GRAPHICS_UPDATE_ONE_WINDOW, "EVENT_GRAPHICS_UPDATE_ONE_WINDOW", "Update graphics in one window")); enumData.push_back(EventTypeEnum(EVENT_HELP_VIEWER_DISPLAY, "EVENT_HELP_VIEWER_DISPLAY", "Display the help viewer")); enumData.push_back(EventTypeEnum(EVENT_IDENTIFICATION_HIGHLIGHT_LOCATION, "EVENT_IDENTIFICATION_HIGHLIGHT_LOCATION", "Highlight the location when identification takes place")); enumData.push_back(EventTypeEnum(EVENT_IDENTIFICATION_REQUEST, "EVENT_IDENTIFICATION_REQUEST", "Request an identification operation")); enumData.push_back(EventTypeEnum(EVENT_IDENTIFICATION_SYMBOL_REMOVAL, "EVENT_IDENTIFICATION_SYMBOL_REMOVAL", "Remove all identification symbols")); enumData.push_back(EventTypeEnum(EVENT_IMAGE_CAPTURE, "EVENT_IMAGE_CAPTURE", "Capture an Image of Browser Window Graphics Region")); enumData.push_back(EventTypeEnum(EVENT_MAC_DOCK_MENU_UPDATE, "EVENT_MAC_DOCK_MENU_UPDATE", "Update the Mac Dock Menu")); enumData.push_back(EventTypeEnum(EVENT_MAP_YOKING_SELECT_MAP, "EVENT_MAP_YOKING_SELECT_MAP", "Map Yoking Select Map")); enumData.push_back(EventTypeEnum(EVENT_MAP_YOKING_VALIDATION, "EVENT_MAP_YOKING_VALIDATION", "Map Yoking Validation")); enumData.push_back(EventTypeEnum(EVENT_MODEL_ADD, "EVENT_MODEL_ADD", "Add a model")); enumData.push_back(EventTypeEnum(EVENT_MODEL_DELETE, "EVENT_MODEL_DELETE", "Delete a model")); enumData.push_back(EventTypeEnum(EVENT_MODEL_GET_ALL, "EVENT_MODEL_GET_ALL", "Get all models")); enumData.push_back(EventTypeEnum(EVENT_MODEL_GET_ALL_DISPLAYED, "EVENT_MODEL_GET_ALL_DISPLAYED", "Get all displayed models")); enumData.push_back(EventTypeEnum(EVENT_MODEL_SURFACE_GET, "EVENT_MODEL_SURFACE_GET", "Get a specific model surface")); enumData.push_back(EventTypeEnum(EVENT_MOVIE_RECORDING_MANUAL_MODE_CAPTURE, "EVENT_MOVIE_RECORDING_MANUAL_MODE_CAPTURE", "Movie recording manual mode capture")); enumData.push_back(EventTypeEnum(EVENT_MOVIE_RECORDING_DIALOG_UPDATE, "EVENT_MOVIE_RECORDING_DIALOG_UPDATE", "Update the movie recording dialog")); enumData.push_back(EventTypeEnum(EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS, "EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS", "Get the color for node identification symbols from all charts that contain nodes")); enumData.push_back(EventTypeEnum(EVENT_OPENGL_OBJECT_TO_WINDOW_TRANSFORM, "EVENT_OPENGL_OBJECT_TO_WINDOW_TRANSFORM", "Get transformation for converting object coordinates to window coordinates")); enumData.push_back(EventTypeEnum(EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE, "EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE", "Operating system requests open data file (Mac only)")); enumData.push_back(EventTypeEnum(EVENT_OVERLAY_SETTINGS_EDITOR_SHOW, "EVENT_OVERLAY_SETTINGS_EDITOR_SHOW", "Request display of overlay settings editor")); enumData.push_back(EventTypeEnum(EVENT_OVERLAY_VALIDATE, "EVENT_OVERLAY_VALIDATE", "Validate an overlay for validity (it exists)")); enumData.push_back(EventTypeEnum(EVENT_PALETTE_COLOR_MAPPING_EDITOR_SHOW, "EVENT_PALETTE_COLOR_MAPPING_EDITOR_SHOW", "Request display of palette color mapping editor")); enumData.push_back(EventTypeEnum(EVENT_PALETTE_GET_BY_NAME, "EVENT_PALETTE_GET_BY_NAME", "Read the selected files in a spec file")); enumData.push_back(EventTypeEnum(EVENT_SCENE_ACTIVE, "EVENT_SCENE_ACTIVE", "Get/Set the active scene")); enumData.push_back(EventTypeEnum(EVENT_SHOW_FILE_DATA_READ_WARNING_DIALOG, "EVENT_SHOW_FILE_DATA_READ_WARNING_DIALOG", "Show a dialog with warnings encountered reading data files")); enumData.push_back(EventTypeEnum(EVENT_SPACER_TAB_GET, "EVENT_SPACER_TAB_GET", "Get a spacer tagb")); enumData.push_back(EventTypeEnum(EVENT_SPEC_FILE_READ_DATA_FILES, "EVENT_SPEC_FILE_READ_DATA_FILES", "Read the selected data files in a spec file")); enumData.push_back(EventTypeEnum(EVENT_SURFACE_COLORING_INVALIDATE, "EVENT_SURFACE_COLORING_INVALIDATE", "Invalidate surface coloring")); enumData.push_back(EventTypeEnum(EVENT_SURFACES_GET, "EVENT_SURFACES_GET", "Get Surfaces")); enumData.push_back(EventTypeEnum(EVENT_SURFACE_STRUCTURES_VALID_GET, "EVENT_SURFACE_STRUCTURES_VALID_GET", "GGet valid surface strucutures and their number of node")); enumData.push_back(EventTypeEnum(EVENT_TILE_TABS_MODIFICATION, "EVENT_TILE_TABS_MODIFICATION", "Tile tabs modification")); enumData.push_back(EventTypeEnum(EVENT_TOOLBOX_SELECTION_DISPLAY, "EVENT_TOOLBOX_SELECTION_DISPLAY", "Display or hide the selection toolbox")); enumData.push_back(EventTypeEnum(EVENT_USER_INTERFACE_UPDATE, "EVENT_USER_INTERFACE_UPDATE", "Update the user-interface")); enumData.push_back(EventTypeEnum(EVENT_PROGRESS_UPDATE, "EVENT_PROGRESS_UPDATE", "Update the progress amount, text, or finished status")); enumData.push_back(EventTypeEnum(EVENT_UPDATE_INFORMATION_WINDOWS, "EVENT_UPDATE_INFORMATION_WINDOWS", "Update the information windows")); enumData.push_back(EventTypeEnum(EVENT_UPDATE_YOKED_WINDOWS, "EVENT_UPDATE_YOKED_WINDOWS", "Update yoked windows")); enumData.push_back(EventTypeEnum(EVENT_UPDATE_VOLUME_EDITING_TOOLBAR, "EVENT_UPDATE_VOLUME_EDITING_TOOLBAR", "Update the volume editing toolbar")); enumData.push_back(EventTypeEnum(EVENT_UPDATE_VOLUME_SLICE_INDICES_COORDS_TOOLBAR, "EVENT_UPDATE_VOLUME_SLICE_INDICES_COORDS_TOOLBAR", "Update the volume slices indices and coords in the toolbar")); enumData.push_back(EventTypeEnum(EVENT_COUNT, "EVENT_COUNT", "Count of events")); CaretAssertMessage((enumData.size() == static_cast(EVENT_COUNT + 1)), ("Number of EventTypeEnum::Enum values is incorrect.\n" "Have enumerated type been added?\n" "enumData.size()=" + AString::number(enumData.size()) + " EVENT_COUNT+1=" + AString::number(EVENT_COUNT + 1))); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const EventTypeEnum* EventTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const EventTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } AString msg("Failed to find EventTypeEnum for an enumerated value. The most likely causes is a failure " "to add the enumerated value in EventTypeEnum::initialize()"); CaretAssertMessage(0, msg); CaretLogSevere(msg); return &enumData[0]; // prevent crash } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString EventTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const EventTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ EventTypeEnum::Enum EventTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = EVENT_INVALID; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const EventTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type EventTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString EventTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const EventTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ EventTypeEnum::Enum EventTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = EVENT_INVALID; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const EventTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type EventTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void EventTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } connectome-workbench-1.4.2/src/Common/EventTypeEnum.h000066400000000000000000000255611360521144700226040ustar00rootroot00000000000000#ifndef __EVENT_TYPE_ENUM__H_ #define __EVENT_TYPE_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { /// Enumerated type for events. class EventTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Invalid event */ EVENT_INVALID, /** Alert user about something */ EVENT_ALERT_USER, /** Add annotation to or remove from a file */ EVENT_ANNOTATION_ADD_TO_REMOVE_FROM_FILE, /** Get annnotation chart labels */ EVENT_ANNOTATION_CHART_LABEL_GET, /** Get color bars from tab(s) */ EVENT_ANNOTATION_COLOR_BAR_GET, /** Annotation create new of a particular type */ EVENT_ANNOTATION_CREATE_NEW_TYPE, /** Get the annotations drawn in a window */ EVENT_ANNOTATION_GET_DRAWN_IN_WINDOW, /** Get an annotation group */ EVENT_ANNOTATION_GROUP_GET_WITH_KEY, /** Annotation grouping (group, regroup, ungroup) operation */ EVENT_ANNOTATION_GROUPING, /** Get annotation text substitutions */ EVENT_ANNOTATION_TEXT_SUBSTITUTION_GET, /** Invalid annotation text substitutions */ EVENT_ANNOTATION_TEXT_SUBSTITUTION_INVALIDATE, /** Annotation toolbar update */ EVENT_ANNOTATION_TOOLBAR_UPDATE, /** Inform that Brain has been reset (new spec or scene loaded) */ EVENT_BRAIN_RESET, /** Get all brain structures */ EVENT_BRAIN_STRUCTURE_GET_ALL, /** Delete a browser tab. */ EVENT_BROWSER_TAB_DELETE, /** Get a browser tab by tab number */ EVENT_BROWSER_TAB_GET, /** Get indices of all valid browser tabs */ EVENT_BROWSER_TAB_INDICES_GET_ALL, /** Get ALL (both viewed and not viewed) browser tabs */ EVENT_BROWSER_TAB_GET_ALL, /** Get ALL VIEWED browser tabs (tabs that are viewed in windows) */ EVENT_BROWSER_TAB_GET_ALL_VIEWED, /** Create a new browser tab */ EVENT_BROWSER_TAB_NEW, /** Create a new browser tab by cloning an existing browser tab */ EVENT_BROWSER_TAB_NEW_CLONE, /** Event for browser window content */ EVENT_BROWSER_WINDOW_CONTENT, /** Get the content of a browser window */ EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET, /** Create tabs after loading a file */ EVENT_BROWSER_WINDOW_CREATE_TABS, /** Issued after a browser window's graphicshave been redrawn */ EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN, /** Issued when displayed browser window menu's may change */ EVENT_BROWSER_WINDOW_MENUS_UPDATE, /** Create a new browser window */ EVENT_BROWSER_WINDOW_NEW, /** Browser tile tab operations */ EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION, /** Get caret data files */ EVENT_CARET_DATA_FILES_GET, /** Get CaretMappable data files */ EVENT_CARET_MAPPABLE_DATA_FILES_GET, /** Get CaretMappableDataFiles and their maps viewed as overlays */ EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS, /** Get all mappable files and selected maps in all displayed overlays */ EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS, /** Event to get the Caret Preferences */ EVENT_CARET_PREFERENCES_GET, /** Event for yoking the loading of matrix chart rows/columns */ EVENT_CHART_MATRIX_YOKING_VALIDATION, /** Validate that chart overlay is valid (it exists). */ EVENT_CHART_OVERLAY_VALIDATE, /** GUI notification of the change in chart two atttributes */ EVENT_CHART_TWO_ATTRIBUTES_CHANGED, /** Get the range of data for a chart two axis */ EVENT_CHART_TWO_AXIS_GET_DATA_RANGE, /** Load chart two line series data */ EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA, /** Add a data file into the Brain*/ EVENT_DATA_FILE_ADD, /** Delete a data file from the brain */ EVENT_DATA_FILE_DELETE, /** Read a data file into the Brain */ EVENT_DATA_FILE_READ, /** Reload (replace) a data file with its saved version in the brain*/ EVENT_DATA_FILE_RELOAD, /** Get data files that are display in windows/tabs */ EVENT_GET_DISPLAYED_DATA_FILES, /** Get node data files */ EVENT_GET_NODE_DATA_FILES, /** get or set the user input mode */ EVENT_GET_OR_SET_USER_INPUT_MODE, /** Get the text renderer for a window */ EVENT_GET_TEXT_RENDERER_FOR_WINDOW, /** Get the viewport size for model, tab, window */ EVENT_GET_VIEWPORT_SIZE, /** Create a buffer object for an OpenGL context */ EVENT_GRAPHICS_OPENGL_CREATE_BUFFER_OBJECT, /** Create a texture name for an OpenGL context */ EVENT_GRAPHICS_OPENGL_CREATE_TEXTURE_NAME, /** Delete a buffer object for an OpenGL context */ EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT, /** Delete a texture name for an OpenGL context */ EVENT_GRAPHICS_OPENGL_DELETE_TEXTURE_NAME, /** Time the OpenGL graphics in a window */ EVENT_GRAPHICS_TIMING_ONE_WINDOW, /** Update all graphics windows */ EVENT_GRAPHICS_UPDATE_ALL_WINDOWS, /** Update graphics in a window */ EVENT_GRAPHICS_UPDATE_ONE_WINDOW, /** Display the help viewer */ EVENT_HELP_VIEWER_DISPLAY, /** Highlight location when an identification occurs */ EVENT_IDENTIFICATION_HIGHLIGHT_LOCATION, /** Perform an identification operation */ EVENT_IDENTIFICATION_REQUEST, /** Remove all identification symbols */ EVENT_IDENTIFICATION_SYMBOL_REMOVAL, /** Browser window image capture */ EVENT_IMAGE_CAPTURE, /** Update the Mac Dock Menu */ EVENT_MAC_DOCK_MENU_UPDATE, /** Validate when adding a mapped file to mapped yoking */ EVENT_MAP_YOKING_SELECT_MAP, /** Select a map for mapped yoked files */ EVENT_MAP_YOKING_VALIDATION, /** model - ADD */ EVENT_MODEL_ADD, /** model - DELETE */ EVENT_MODEL_DELETE, /** model - get all*/ EVENT_MODEL_GET_ALL, /** model - get all displayed */ EVENT_MODEL_GET_ALL_DISPLAYED, /** model surface - get */ EVENT_MODEL_SURFACE_GET, /** Update the movie dialog */ EVENT_MOVIE_RECORDING_DIALOG_UPDATE, /** Movie manual mode image recording */ EVENT_MOVIE_RECORDING_MANUAL_MODE_CAPTURE, /** Get the color for a node's identification symbol from a chart that contains the node */ EVENT_NODE_IDENTIFICATION_COLORS_GET_FROM_CHARTS, /** Get the transformation for converting object coordinates to window coordinates */ EVENT_OPENGL_OBJECT_TO_WINDOW_TRANSFORM, /** open file request from the operating system (Mac only) for now */ EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE, /** request display of overlay settings editor */ EVENT_OVERLAY_SETTINGS_EDITOR_SHOW, /** Validate that overlay is valid (it exists). */ EVENT_OVERLAY_VALIDATE, /** request display of palette color mapping editor */ EVENT_PALETTE_COLOR_MAPPING_EDITOR_SHOW, /** Get a palette by name from a palette file */ EVENT_PALETTE_GET_BY_NAME, /** Get the active scene */ EVENT_SCENE_ACTIVE, /** Show a dialog containing warnings encountered when reading data files */ EVENT_SHOW_FILE_DATA_READ_WARNING_DIALOG, /** Get a spacer tab by tab number */ EVENT_SPACER_TAB_GET, /** Read the selected files in a spec file */ EVENT_SPEC_FILE_READ_DATA_FILES, /** Invalidate surface coloring */ EVENT_SURFACE_COLORING_INVALIDATE, /** Get surfaces */ EVENT_SURFACES_GET, /** Get valid surface strucutures and their number of nodes */ EVENT_SURFACE_STRUCTURES_VALID_GET, /** Tile tabs modification */ EVENT_TILE_TABS_MODIFICATION, /** Display/Hide the selection toolbox */ EVENT_TOOLBOX_SELECTION_DISPLAY, /** Update the User-Interface */ EVENT_USER_INTERFACE_UPDATE, /** Update the progress amount, text, or finished status */ EVENT_PROGRESS_UPDATE, /** Update the information windows */ EVENT_UPDATE_INFORMATION_WINDOWS, /** Update the volume editing toolbar */ EVENT_UPDATE_VOLUME_EDITING_TOOLBAR, /** Update the slice indices and coordinates in the toolbar */ EVENT_UPDATE_VOLUME_SLICE_INDICES_COORDS_TOOLBAR, /** Update yoked windows */ EVENT_UPDATE_YOKED_WINDOWS, /* THIS MUST ALWAYS BE LAST - NOT an event type but is number of event types */ EVENT_COUNT }; ~EventTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static void getAllEnums(std::vector& allEnums); private: EventTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const EventTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** The enumerated type value for an instance */ Enum enumValue; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __EVENT_TYPE_ENUM_DECLARE__ std::vector EventTypeEnum::enumData; bool EventTypeEnum::initializedFlag = false; #endif // __EVENT_TYPE_ENUM_DECLARE__ } // namespace #endif //__EVENT_TYPE_ENUM__H_ connectome-workbench-1.4.2/src/Common/FastStatistics.cxx000066400000000000000000000515451360521144700233600ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "FastStatistics.h" #include "CaretPointer.h" #include #include #include using namespace caret; using namespace std; const int64_t NUM_BUCKETS_PERCENTILE_HIST = 10000;//10,000 maximum to deal with some outliers outliers until I think of a better fix FastStatistics::FastStatistics() { reset(); } FastStatistics::FastStatistics(const float* data, const int64_t& dataCount) { update(data, dataCount); } void FastStatistics::reset() { m_posCount = 0; m_zeroCount = 0; m_negCount = 0; m_infCount = 0; m_negInfCount = 0; m_nanCount = 0; m_absCount = 0; m_mean = 0.0f; m_stdDevPop = 0.0f; m_stdDevSample = 0.0f; m_mostNeg = 0.0f; m_leastNeg = -numeric_limits::max(); m_leastPos = numeric_limits::max(); m_mostPos = 0.0f; m_leastAbs = numeric_limits::max(); m_mostAbs = 0.0; m_min = 0.0f; m_max = 0.0f; } void FastStatistics::update(const float* data, const int64_t& dataCount) { reset(); CaretArray positives(dataCount), negatives(dataCount), absolutes(dataCount); double sum = 0.0;//for numerical stability bool first = true;//so min can be positive and max can be negative for (int64_t i = 0; i < dataCount; ++i) { if (data[i] != data[i]) { ++m_nanCount; continue;//skip NaNs } if (data[i] == 0.0f)//test exactly zero (negative zero also tests equal), in case someone wants stats on something with miniscule values (percent of surface area per node?) { ++m_zeroCount; } else { if (data[i] < 0.0f) { if (data[i] * 2.0f == data[i]) { ++m_negInfCount; continue;//skip neg infs } else { negatives[m_negCount] = data[i]; ++m_negCount; if (data[i] > m_leastNeg) m_leastNeg = data[i]; if (data[i] < m_mostNeg) m_mostNeg = data[i]; absolutes[m_absCount] = -data[i]; if (absolutes[m_absCount] > m_mostAbs) m_mostAbs = absolutes[m_absCount]; if (absolutes[m_absCount] < m_leastAbs) m_leastAbs = absolutes[m_absCount]; ++m_absCount; } } else { if (data[i] * 2.0f == data[i]) { ++m_infCount; continue;//skip infs } else { positives[m_posCount] = data[i]; ++m_posCount; if (data[i] > m_mostPos) m_mostPos = data[i]; if (data[i] < m_leastPos) m_leastPos = data[i]; absolutes[m_absCount] = data[i]; if (absolutes[m_absCount] > m_mostAbs) m_mostAbs = absolutes[m_absCount]; if (absolutes[m_absCount] < m_leastAbs) m_leastAbs = absolutes[m_absCount]; ++m_absCount; } } } if (data[i] > m_max || first) m_max = data[i]; if (data[i] < m_min || first) m_min = data[i]; sum += data[i];//use a two-pass method for stability, only do mean this pass first = false; } int64_t totalGood = (m_negCount + m_zeroCount + m_posCount); m_mean = sum / totalGood; float tempf; double sum2 = 0.0; for (int64_t i = 0; i < dataCount; ++i) { if (data[i] != data[i]) continue;//skip NaNs if (data[i] < -1.0f && (data[i] * 2.0f == data[i])) continue;//exclude -inf if (data[i] > 1.0f && (data[i] * 2.0f == data[i])) continue;//exclude inf tempf = data[i] - m_mean; sum2 += tempf * tempf; } if (totalGood > 0) { m_stdDevPop = sqrt(sum2 / totalGood); if (totalGood > 1) { m_stdDevSample = sqrt(sum2 / (totalGood - 1)); } } int usebuckets = min(NUM_BUCKETS_PERCENTILE_HIST, dataCount); m_negPercentHist.update(usebuckets, negatives, m_negCount); m_posPercentHist.update(usebuckets, positives, m_posCount); m_absPercentHist.update(usebuckets, absolutes, m_absCount); if (m_negCount <= 0) { m_leastNeg = 0.0; m_mostNeg = 0.0; } if (m_posCount <= 0) { m_leastPos = 0.0; m_mostPos = 0.0; } if (m_absCount <= 0) { m_leastAbs = 0.0; m_mostAbs = 0.0; } } void FastStatistics::update(const float* data, const int64_t& dataCount, const float& minThreshInclusive, const float& maxThreshInclusive) { reset(); CaretArray positives(dataCount), negatives(dataCount), absolutes(dataCount); double sum = 0.0;//for numerical stability bool first = true;//so min can be positive and max can be negative for (int64_t i = 0; i < dataCount; ++i) { if (data[i] != data[i]) { ++m_nanCount; continue;//skip NaNs } if (data[i] < -1.0f && (data[i] * 2.0f == data[i])) { ++m_negInfCount; continue;//skip and count all infs, ignoring the range for now } if (data[i] > 1.0f && (data[i] * 2.0f == data[i])) { ++m_infCount; continue;//ditto } if (data[i] < minThreshInclusive || data[i] > maxThreshInclusive) {//we now have only numerical values continue;//skip them if they are outside the range } if (data[i] == 0.0f)//test exactly zero (negative zero also tests equal), in case someone wants stats on something with miniscule values (percent of surface area per node?) { ++m_zeroCount; } else { if (data[i] < 0.0f) { negatives[m_negCount] = data[i]; ++m_negCount; if (data[i] > m_leastNeg) m_leastNeg = data[i]; if (data[i] < m_mostNeg) m_mostNeg = data[i]; absolutes[m_absCount] = -data[i]; ++m_absCount; } else { positives[m_posCount] = data[i]; ++m_posCount; if (data[i] > m_mostPos) m_mostPos = data[i]; if (data[i] < m_leastPos) m_leastPos = data[i]; absolutes[m_absCount] = data[i]; ++m_absCount; } } if (data[i] > m_max || first) m_max = data[i]; if (data[i] < m_min || first) m_min = data[i]; sum += data[i];//use a two-pass method for stability, only do mean this pass first = false; } int64_t totalGood = (m_negCount + m_zeroCount + m_posCount); m_mean = sum / totalGood; float tempf; double sum2 = 0.0; for (int64_t i = 0; i < dataCount; ++i) { if (data[i] != data[i]) continue;//skip NaNs if (data[i] < -1.0f && (data[i] * 2.0f == data[i])) continue;//exclude -inf if (data[i] > 1.0f && (data[i] * 2.0f == data[i])) continue;//exclude inf tempf = data[i] - m_mean; sum2 += tempf * tempf; } if (totalGood > 0) { m_stdDevPop = sqrt(sum2 / totalGood); if (totalGood > 1) { m_stdDevSample = sqrt(sum2 / (totalGood - 1)); } } int usebuckets = min(NUM_BUCKETS_PERCENTILE_HIST, dataCount); m_negPercentHist.update(usebuckets, negatives, m_negCount);//10,000 will probably allow us to approximate the percentiles pretty closely, and eats only 80K of memory each m_posPercentHist.update(usebuckets, positives, m_posCount); m_absPercentHist.update(usebuckets, absolutes, m_absCount); if (m_negCount <= 0) { m_leastNeg = 0.0; m_mostNeg = 0.0; } if (m_posCount <= 0) { m_leastPos = 0.0; m_mostPos = 0.0; } if (m_absCount <= 0) { m_leastAbs = 0.0; m_mostAbs = 0.0; } } float FastStatistics::getApproxNegativePercentile(const float& percent) const { float rank = percent / 100.0f * m_negCount;//translate to rank rank = m_negCount - rank;//reverse it because negatives go the other direction, histogram is strictly directional towards positive if (rank <= 0) return m_mostNeg; if (rank >= m_negCount) return m_leastNeg; float histMin, histMax; m_negPercentHist.getRange(histMin, histMax); const vector& cumulative = m_negPercentHist.getHistogramCumulativeCounts(); int numBuckets = (int)cumulative.size(); int lowBound = -1, highBound = numBuckets, guess;//bisection search, "index" -1 is implicitly valued zero while (highBound - lowBound > 1) { guess = (lowBound + highBound) / 2; if (cumulative[guess] <= rank) { lowBound = guess; } else { highBound = guess; } } if (highBound == numBuckets) return m_mostPos;//the count mismatched the histogram somehow float bucketsize = (histMax - histMin) / numBuckets; int64_t curLower, curUpper = cumulative[highBound]; if (lowBound > -1) { curLower = cumulative[lowBound]; } else { curLower = 0; } if (highBound > 0 && ((highBound == 1 && cumulative[0] == 0) || (highBound > 1 && cumulative[highBound - 1] == cumulative[highBound - 2]))) {//tweak the function a bit if there is a bin that collected zero to the immediate left, to reduce discontinuities if (rank - curLower >= 1.0f) { ++curLower;//tweak the low end to start from one higher, to make it continuous with the tweak below } else { --highBound;//move left, because this interpolated rank doesn't fall within the highBound bucket --lowBound; curUpper = curLower + 1;//add one to the right end of the flat spot to give it nonzero slope while (lowBound > 0 && cumulative[highBound] == cumulative[lowBound - 1]) { --lowBound;//slide left boundary over the flat spot } if (lowBound == 0 && cumulative[lowBound] == 0) { --lowBound;//including if first bucket is zero, this shouldn't happen unless all valid values are equal (and a low count of values) } if (lowBound > -1) { curLower = cumulative[lowBound]; } else { curLower = 0; } } } float lowValue = histMin + (lowBound + 1) * bucketsize, highValue = histMin + (highBound + 1) * bucketsize; return lowValue + (highValue - lowValue) * (rank - curLower) / (curUpper - curLower); } float FastStatistics::getApproxPositivePercentile(const float& percent) const { float rank = percent / 100.0f * m_posCount;//translate to rank if (rank <= 0.0f) return m_leastPos; if (rank >= m_posCount) return m_mostPos; float histMin, histMax; m_posPercentHist.getRange(histMin, histMax); const vector& cumulative = m_posPercentHist.getHistogramCumulativeCounts(); int numBuckets = (int)cumulative.size(); int lowBound = -1, highBound = numBuckets, guess;//bisection search, "index" -1 is implicitly valued zero while (highBound - lowBound > 1) { guess = (lowBound + highBound) / 2; if (cumulative[guess] <= rank) { lowBound = guess; } else { highBound = guess; } } if (highBound == numBuckets) return m_mostPos;//the count mismatched the histogram somehow float bucketsize = (histMax - histMin) / numBuckets; int64_t curLower, curUpper = cumulative[highBound]; if (lowBound > -1) { curLower = cumulative[lowBound]; } else { curLower = 0; } if (highBound > 0 && ((highBound == 1 && cumulative[0] == 0) || (highBound > 1 && cumulative[highBound - 1] == cumulative[highBound - 2]))) {//tweak the function a bit if there is a bin that collected zero to the immediate left, to reduce discontinuities if (rank - curLower >= 1.0f) { ++curLower;//tweak the low end to start from one higher, to make it continuous with the tweak below } else { --highBound;//move left, because this interpolated rank doesn't fall within the highBound bucket --lowBound; curUpper = curLower + 1;//add one to the right end of the flat spot to give it nonzero slope while (lowBound > 0 && cumulative[highBound] == cumulative[lowBound - 1]) { --lowBound;//slide left boundary over the flat spot } if (lowBound == 0 && cumulative[lowBound] == 0) { --lowBound;//including if first bucket is zero, this shouldn't happen unless all valid values are equal (and a low count of values) } if (lowBound > -1) { curLower = cumulative[lowBound]; } else { curLower = 0; } } } float lowValue = histMin + (lowBound + 1) * bucketsize, highValue = histMin + (highBound + 1) * bucketsize; return lowValue + (highValue - lowValue) * (rank - curLower) / (curUpper - curLower); } float FastStatistics::getApproxAbsolutePercentile(const float& percent) const { float rank = percent / 100.0f * m_absCount;//translate to rank if (rank <= 0.0f) return m_leastAbs; if (rank >= m_absCount) return m_mostAbs; float histMin, histMax; m_absPercentHist.getRange(histMin, histMax); const vector& cumulative = m_absPercentHist.getHistogramCumulativeCounts(); int numBuckets = (int)cumulative.size(); int lowBound = -1, highBound = numBuckets, guess;//bisection search, "index" -1 is implicitly valued zero while (highBound - lowBound > 1) { guess = (lowBound + highBound) / 2; if (cumulative[guess] <= rank) { lowBound = guess; } else { highBound = guess; } } if (highBound == numBuckets) return m_mostAbs;//the count mismatched the histogram somehow float bucketsize = (histMax - histMin) / numBuckets; int64_t curLower, curUpper = cumulative[highBound]; if (lowBound > -1) { curLower = cumulative[lowBound]; } else { curLower = 0; } if (highBound > 0 && ((highBound == 1 && cumulative[0] == 0) || (highBound > 1 && cumulative[highBound - 1] == cumulative[highBound - 2]))) {//tweak the function a bit if there is a bin that collected zero to the immediate left, to reduce discontinuities if (rank - curLower >= 1.0f) { ++curLower;//tweak the low end to start from one higher, to make it continuous with the tweak below } else { --highBound;//move left, because this interpolated rank doesn't fall within the highBound bucket --lowBound; curUpper = curLower + 1;//add one to the right end of the flat spot to give it nonzero slope while (lowBound > 0 && cumulative[highBound] == cumulative[lowBound - 1]) { --lowBound;//slide left boundary over the flat spot } if (lowBound == 0 && cumulative[lowBound] == 0) { --lowBound;//including if first bucket is zero, this shouldn't happen unless all valid values are equal (and a low count of values) } if (lowBound > -1) { curLower = cumulative[lowBound]; } else { curLower = 0; } } } float lowValue = histMin + (lowBound + 1) * bucketsize, highValue = histMin + (highBound + 1) * bucketsize; return lowValue + (highValue - lowValue) * (rank - curLower) / (curUpper - curLower); } float FastStatistics::getApproximateMedian() const { int64_t totalGood = m_negCount + m_zeroCount + m_posCount; if (m_negCount > m_posCount) { if (m_zeroCount > (m_negCount - m_posCount)) { return 0.0f; } else { return getApproxNegativePercentile((m_negCount - m_posCount - m_zeroCount) * 50.0f / totalGood); } } else { if (m_zeroCount > (m_posCount - m_negCount)) { return 0.0f; } else { return getApproxNegativePercentile((m_posCount - m_negCount - m_zeroCount) * 50.0f / totalGood); } } } float FastStatistics::getValuePercentileHelper(const Histogram& histogram, const float numberOfDataValues, const bool negativeDataFlag, const float value) { float percentile = 0.0; const std::vector& cumulativeBuckets = histogram.getHistogramCumulativeCounts(); if ((numberOfDataValues > 0) && (! cumulativeBuckets.empty())) { float minValue = 0.0; float maxValue = 0.0; histogram.getRange(minValue, maxValue); if (value < minValue) { if (negativeDataFlag) { percentile = 100.0; } else { percentile = 0.0; } } else if (value > maxValue) { if (negativeDataFlag) { percentile = 0; } else { percentile = 100.0; } } else { const float histoRange = maxValue - minValue; if (histoRange > 0.0) { const int64_t numBuckets = cumulativeBuckets.size(); int64_t bucketIndex = static_cast(((value - minValue) / histoRange) * numBuckets); if (bucketIndex < 0) { bucketIndex = 0; } else if (bucketIndex >= numBuckets) { bucketIndex = numBuckets - 1; } CaretAssertVectorIndex(cumulativeBuckets, bucketIndex); float cumulativeValue = cumulativeBuckets[bucketIndex]; if (negativeDataFlag) { CaretAssertVectorIndex(cumulativeBuckets, numBuckets - 1); cumulativeValue = cumulativeBuckets[numBuckets - 1] - cumulativeBuckets[bucketIndex]; } percentile = (cumulativeValue / numberOfDataValues) * 100.0; } } } return percentile; } float FastStatistics::getNegativeValuePercentile(const float value) const { return getValuePercentileHelper(m_negPercentHist, m_negCount, true, value); } float FastStatistics::getAbsoluteValuePercentile(const float value) const { float dataValue = value; if (dataValue < 0.0) { dataValue = -dataValue; } return getValuePercentileHelper(m_absPercentHist, m_absCount, false, dataValue); } float FastStatistics::getPositiveValuePercentile(const float value) const { return getValuePercentileHelper(m_posPercentHist, m_posCount, false, value); // float percentile = 0.0; // // const std::vector& cumulativeBuckets = m_posPercentHist.getHistogramCumulativeCounts(); // if ( ! cumulativeBuckets.empty()) { // float minValue = 0.0; // float maxValue = 0.0; // m_posPercentHist.getRange(minValue, // maxValue); // if (value < minValue) { // percentile = 0.0; // } // else if (value > maxValue) { // percentile = 100.0; // } // else { // const float histoRange = maxValue - minValue; // if (histoRange > 0.0) { // const int64_t numBuckets = cumulativeBuckets.size(); // int64_t bucketIndex = static_cast(((value - minValue) / histoRange) * numBuckets); // if (bucketIndex < 0) { // bucketIndex = 0; // } // else if (bucketIndex >= numBuckets) { // bucketIndex = numBuckets - 1; // } // // CaretAssertVectorIndex(cumulativeBuckets, // bucketIndex); // const float cumulativeValue = cumulativeBuckets[bucketIndex]; // percentile = (cumulativeValue / m_posCount) * 100.0; // } // } // } // // return percentile; } connectome-workbench-1.4.2/src/Common/FastStatistics.h000066400000000000000000000076511360521144700230040ustar00rootroot00000000000000#ifndef __FAST_STATISTICS_H__ #define __FAST_STATISTICS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Histogram.h" namespace caret { ///this class does statistics that are linear in complexity only, NO SORTING, this means its percentiles are approximate, using interpolation from a histogram class FastStatistics { Histogram m_posPercentHist, m_negPercentHist, m_absPercentHist; float m_min, m_max, m_mean, m_stdDevPop, m_stdDevSample; float m_mostPos, m_leastPos, m_leastNeg, m_mostNeg, m_leastAbs, m_mostAbs; ///counts of each class of number int64_t m_posCount, m_zeroCount, m_negCount, m_infCount, m_negInfCount, m_nanCount, m_absCount; void reset(); static float getValuePercentileHelper(const Histogram& histogram, const float numberOfDataValues, const bool negativeDataFlag, const float value); public: FastStatistics(); FastStatistics(const float* data, const int64_t& dataCount); void update(const float* data, const int64_t& dataCount); ///statistics and display are really not that related, so for now, only include a continuous clipping range, excluding the middle from data will do weird things to standard deviation void update(const float* data, const int64_t& dataCount, const float& minThreshInclusive, const float& maxThreshInclusive); float getApproxPositivePercentile(const float& percent) const; float getApproxNegativePercentile(const float& percent) const; float getApproxAbsolutePercentile(const float& percent) const; void getCounts(int64_t& posCount, int64_t& zeroCount, int64_t& negCount, int64_t& infCount, int64_t& negInfCount, int64_t& nanCount) const { posCount = m_posCount; zeroCount = m_zeroCount; negCount = m_negCount; infCount = m_infCount; negInfCount = m_negInfCount; nanCount = m_nanCount; } void getNonzeroRanges(float& mostNegative, float& leastNegative, float& leastPositive, float& mostPositive) const { mostNegative = m_mostNeg; leastNegative = m_leastNeg; leastPositive = m_leastPos; mostPositive = m_mostPos; } float getMostNegativeValue() const { return m_mostNeg; } float getMostPositiveValue() const { return m_mostPos; } float getMin() const { return m_min; } float getMax() const { return m_max; } float getMean() const { return m_mean; } float getApproximateMedian() const; float getSampleStdDev() const { return m_stdDevSample; } float getPopulationStdDev() const { return m_stdDevPop; } float getPositiveValuePercentile(const float value) const; float getNegativeValuePercentile(const float value) const; float getAbsoluteValuePercentile(const float value) const; }; } #endif //__FAST_STATISTICS_H__ connectome-workbench-1.4.2/src/Common/FileAdapter.cxx000066400000000000000000000101441360521144700225560ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __FILE_ADAPTER_DECLARE__ #include "FileAdapter.h" #undef __FILE_ADAPTER_DECLARE__ #include "CaretAssert.h" #include "FileInformation.h" using namespace caret; /** * \class caret::FileAdapter * \brief Simplifies opening of files and streams. * * When an open method is called, the file is opened * in the appropriate mode, a stream is created, and * the stream is returned. When the destructor is * called it will take care of cleaning up any resources * and closing the file (if it has not already been * done by calling close(). * * If an instance of this class is created in a * try/catch block, create an instance of the class * statically (not NEW) so that if an exception is * thrown, the instance of this class will go out * of scope which results in the destructor being * called which cleans up resources and closes the * file. */ /** * Constructor. */ FileAdapter::FileAdapter() { m_file = NULL; m_textStream = NULL; } /** * */ FileAdapter::~FileAdapter() { close(); } /** * Open a file with the given name, create a QTextStream for * the file, and return the QTextStream. * * @filename * Name of file. * @errorMessagesOut * Contains information about errors if any occur. * @return * A pointer to the QTextStream that was created. DO NOT * destroy it or else disaster will likely occur. If this * returned value is NULL, it indicates that an error has * occurred and its description will be in the errorMessageOut * parameter. */ QTextStream* FileAdapter::openQTextStreamForWritingFile(const AString& filename, AString& errorMessageOut) { errorMessageOut = ""; if (m_file != NULL) { errorMessageOut = ("A file named " + m_file->fileName() + " is currently open with this FileAdapter"); return NULL; } if (m_file != NULL) { errorMessageOut = "This file is already open and has not been closed."; return NULL; } if (filename.isEmpty()) { errorMessageOut = "Filename contains no characters."; return NULL; } FileInformation fileInfo(filename); if (fileInfo.exists()) { if (fileInfo.isWritable() == false) { errorMessageOut = (filename + " exists but does not have writable permission."); return NULL; } } m_file = new QFile(filename); if (m_file->open(QFile::WriteOnly) == false) { errorMessageOut = ("Unable to open " + filename + " for writing: " + m_file->errorString()); delete m_file; m_file = NULL; return NULL; } m_textStream = new QTextStream(m_file); return m_textStream; } /** * If any streams are valid, they are deleted. * If the file is valid, its is flushed, closed * and deleted. */ void FileAdapter::close() { if (m_textStream != NULL) { m_textStream->flush(); delete m_textStream; m_textStream = NULL; } if (m_file != NULL) { m_file->flush(); m_file->close(); delete m_file; m_file = NULL; } } connectome-workbench-1.4.2/src/Common/FileAdapter.h000066400000000000000000000030321360521144700222010ustar00rootroot00000000000000#ifndef __FILE_ADAPTER__H_ #define __FILE_ADAPTER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" class QFile; class QTextStream; namespace caret { class FileAdapter : public CaretObject { public: FileAdapter(); ~FileAdapter(); QTextStream* openQTextStreamForWritingFile(const AString& filename, AString& errorMessageOut); void close(); private: QFile* m_file; QTextStream* m_textStream; }; #ifdef __FILE_ADAPTER_DECLARE__ // #endif // __FILE_ADAPTER_DECLARE__ } // namespace #endif //__FILE_ADAPTER__H_ connectome-workbench-1.4.2/src/Common/FileInformation.cxx000066400000000000000000000535321360521144700234730ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __FILE_INFORMATION_DECLARE__ #include "FileInformation.h" #undef __FILE_INFORMATION_DECLARE__ #include "CaretLogger.h" #include "DataFile.h" #include "DataFileTypeEnum.h" using namespace caret; /** * \class caret::FileInformation * \brief Information about a file path. * \ingroup Common * * Provides information about a path (file, directory, etc). Support for * remote files is provided. Some of the methods are not appropriate for * remote files and the method's documentation indicates any limitations. */ /** * Constructor. * @param file * Name of path for which information is obtained. */ FileInformation::FileInformation(const AString& file) : CaretObject() { m_isLocalFile = false; m_isRemoteFile = false; if (DataFile::isFileOnNetwork(file)) { m_urlInfo.setUrl(file); m_isRemoteFile = true; } else { m_fileInfo.setFile(file); m_isLocalFile = true; } } /** * Constructor. * @param path * Directory containing the file. * @param file * Name of path for which information is obtained. */ FileInformation::FileInformation(const AString& path, const AString& file) : CaretObject() { m_isLocalFile = false; m_isRemoteFile = false; if (DataFile::isFileOnNetwork(file) || DataFile::isFileOnNetwork(path)) { AString pathCopy = path; if (pathCopy.endsWith("/") == false) { /* * With adding a trailing slash: * path: http://brainvis.wustl.edu/john/workbench * file: ParcellationPilot_AverageT1w.nii.gz * CORRECT: http://brainvis.wustl.edu/john/workbench/ParcellationPilot_AverageT1w.nii.gz * * Without adding the trailing slash "workbench" is chopped off * INCORRECT: http://brainvis.wustl.edu/john/ParcellationPilot_AverageT1w.nii.gz */ pathCopy += "/"; } QUrl baseUrl(pathCopy); QUrl relativeUrl(file); m_urlInfo = baseUrl.resolved(relativeUrl); m_isRemoteFile = true; CaretLogFine("Path: " + path + "\n File: " + file + "\n Becomes " + m_urlInfo.toString()); } else { m_fileInfo.setFile(path, file); /* * Clean up path to remove any ".." (up a directory level). * Note that canonicalFilePath() will return an empty string * if the path does not point to a valid file. * * TSC: NEVER USE CANONICAL FOR THIS! canonical resolves symlinks, which is NOT DESIRED unless explicitly asked for (by calling a function including the word "canonical"). * */ if (getAbsoluteFilePath().contains("..")) { AString cleanedPath = QDir::cleanPath(m_fileInfo.absolutePath()); if (!cleanedPath.endsWith('/')) cleanedPath += "/";//because "/" and "/usr" are both possible results cleanedPath += m_fileInfo.fileName(); if (cleanedPath.isEmpty() == false) { m_fileInfo.setFile(cleanedPath); } } m_isLocalFile = true; } } /** * Destructor. */ FileInformation::~FileInformation() { } /** * @return True if the file is a local file, else false. */ bool FileInformation::isLocalFile() const { return m_isLocalFile; } /** * @return True if the file is a remote file, else false. */ bool FileInformation::isRemoteFile() const { return m_isRemoteFile; } /** * @return Absolute path including the name of the file. * * some logic that seems to be missing from QFileInfo: if absolute, * return path() + file() rather than using system call. * * Note: A remote file returns the original, full URL. */ AString FileInformation::getAbsoluteFilePath() const { if (m_isRemoteFile) { return m_urlInfo.toString(); } if (m_fileInfo.isAbsolute()) { return m_fileInfo.filePath(); } else { return m_fileInfo.absoluteFilePath(); } } /** * Removes the file. * Remove files cannot be removed. * * @return * true if file deleted successfully. */ bool FileInformation::remove() { if (m_isRemoteFile) { CaretLogSevere("Deleting remote file is not allowed: " + m_urlInfo.toString()); return false; } bool result = false; if (m_fileInfo.exists()) { result = QFile::remove(m_fileInfo.absoluteFilePath()); } return result; } /** * @return true if it exists, else false. * * A remote file always returns true. */ bool FileInformation::exists() const { if (m_isRemoteFile) { return true; } return m_fileInfo.exists(); } /** * @return true if it is file, else false. * * A remote file always returns true. */ bool FileInformation::isFile() const { if (m_isRemoteFile) { return true; } return m_fileInfo.isFile(); } /** * @return true if it is directory, else false. * * A remote file always returns false. */ bool FileInformation::isDirectory() const { if (m_isRemoteFile) { return false; } return m_fileInfo.isDir(); } /** * @return true if it is symbolic link, else false.0 * * A remote file always returns false. */ bool FileInformation::isSymbolicLink() const { if (m_isRemoteFile) { return false; } return m_fileInfo.isSymLink(); } /** * @return true if it is readable, else false. * * A remote file always returns true. */ bool FileInformation::isReadable() const { if (m_isRemoteFile) { return true; } return m_fileInfo.isReadable(); } /** * @return true if it is writable, else false. * * A remote file always returns false. */ bool FileInformation::isWritable() const { if (m_isRemoteFile) { return false; } return m_fileInfo.isWritable(); } /** * @return true if it is absolute path, else false. * * A remote file always returns true. */ bool FileInformation::isAbsolute() const { if (m_isRemoteFile) { return true; } return m_fileInfo.isAbsolute(); } /** * @return true if it is relative path, else false (remote file is never relative) * * A remote file always returns false. */ bool FileInformation::isRelative() const { if (m_isRemoteFile) { return false; } return m_fileInfo.isRelative(); } /** * @return true if it is hidden, else false. * * A remote file always returns false. */ bool FileInformation::isHidden() const { if (m_isRemoteFile) { return false; } return m_fileInfo.isHidden(); } /** * @return Size of the file in bytes. * * A remote file always returns 0. */ int64_t FileInformation::size() const { if (m_isRemoteFile) { return 0; } return m_fileInfo.size(); } /** * @return name of file followed by path in parenthesis. * * For example: /usr/local/file.txt * returns: file.txt (/usr/local) */ AString FileInformation::getFileNameFollowedByPathNameForGUI() const { AString name = getFileName(); const AString pn = getPathName(); if ( ! pn.isEmpty()) { name += (" (" + pn + ")"); } return name; } /** * @return Name of the file excluding any path. * * A remote file always anything after the last slash (/). If there is * no slash, an emtpy string is returned. */ AString FileInformation::getFileName() const { if (m_isRemoteFile) { QString name = m_urlInfo.toString(); const int indx = name.lastIndexOf('/'); if ((indx >= 0) && (indx < name.length())) { name = name.mid(indx + 1); return name; } else { return ""; } } return m_fileInfo.fileName(); } /** * @return Name of the file excluding any path and WITHOUT any extension. * * A remote file always anything after the last slash (/). If there is * no slash, an emtpy string is returned. */ AString FileInformation::getFileNameNoExtension() const { AString name = getFileName(); const AString ext = getFileExtension(); if ( ! ext.isEmpty()) { const int32_t extStartIndex = name.indexOf(ext); if (extStartIndex > 0) { name = name.left(extStartIndex - 1); } } return name; } /** * @return The file's path excluding the file's name. * * A remote file always everything before the last slash (/). If there is * no slash, the URL is returned. */ AString FileInformation::getPathName() const { if (m_isRemoteFile) { QString path = m_urlInfo.toString(); const int indx = path.lastIndexOf('/'); if (indx >= 1) { path = path.left(indx); return path; } else { return path; } } return m_fileInfo.path(); } /** * @return The full path to the file including the file name, resolving * any symlinks or ".." or "." components. This should give exactly one * string per file, no matter how many ways to get to a file there are * (except for hardlinks). * * Note: A remote file returns the original, full URL. */ AString FileInformation::getCanonicalFilePath() const { if (m_isRemoteFile) { return m_urlInfo.toString(); } return m_fileInfo.canonicalFilePath(); } /** * @return The full path to the file (excluding the file name), * resolving any symlinks or ".." or "." components. * * For a remote file, this returns getPathName(). */ AString FileInformation::getCanonicalPath() const { if (m_isRemoteFile) { return getPathName(); } return m_fileInfo.canonicalPath(); } /** * @return The file name's extension. * * Many Workbench files have filename extensions that include a * dot (nii.gz, pconn.nii, etc) AND users sometimes include dots * in the names of the files (Glasser_PilotIII.L.20k_fs_LR.shape.gii) * so FileInfo::suffix and FileInfo::completeSuffix methods will * not provide the correct file extension. * * This method will compare the end of the file's name to every Workbench * file extension. If there is a match, this extension is returned. * Otherwise FileInfo::suffix is called and that will return anything * after but not including the last dot. */ AString FileInformation::getFileExtension() const { const bool includeNonWritableFileTypesFlag(true); const std::vector workbenchExtensions = DataFileTypeEnum::getFilesExtensionsForEveryFile(includeNonWritableFileTypesFlag); for (std::vector::const_iterator extIter = workbenchExtensions.begin(); extIter != workbenchExtensions.end(); extIter++) { const AString extension = *extIter; if ( ! extension.isEmpty()) { if (getFileName().endsWith(extension)) { return extension; } } } // if (m_isRemoteFile) { // AString ext = getFileName(); // const int indx = ext.lastIndexOf('.'); // if ((indx >= 0) && (indx < ext.length())) { // ext = ext.mid(indx + 1); // return ext; // } // else { // return ""; // } // } return m_fileInfo.suffix(); } /** * Get the components for a filename. * * Example: /Volumes/myelin1/caret7_gui_design/data/HCP_demo/areas.border * Returns * absolutePathOut => /Volumes/myelin1/caret7_gui_design/data/HCP_demo * fileNameWithoutExtensionOut => areas * extensionWithoutDotOut => border * * @param absolutePathOut * Absolute path of file file. Could be empty if this instance * was created using a filename without a path. * @param fileNameWithoutExtensionOut * Name of the file without path and without extention. * @param extensionWithoutDotOut * Extension without the dot. Could be empty if filename does * not have an extension. */ void FileInformation::getFileComponents(AString& absolutePathOut, AString& fileNameWithoutExtensionOut, AString& extensionWithoutDotOut) const { absolutePathOut = getAbsolutePath(); fileNameWithoutExtensionOut = getFileNameNoExtension(); extensionWithoutDotOut = getFileExtension(); } /** * Assemble the file components into a file path and name. * * @param pathName * Path for file (may be absolute, relative, or empty). * @param fileNameWithoutExtension * Name of file without extension. * @param extensionWithoutDot * The file extension without the leading dot. */ AString FileInformation::assembleFileComponents(const AString& pathName, const AString& fileNameWithoutExtension, const AString& extensionWithoutDot) { AString name; if ( ! pathName.isEmpty()) { name += (pathName + "/"); } name += fileNameWithoutExtension; if ( ! extensionWithoutDot.isEmpty()) { /* * User might include dot at beginning of extension */ if (extensionWithoutDot.startsWith(".")) { name += extensionWithoutDot; } else { name += ("." + extensionWithoutDot); } } return name; } /** * Assemble the file components into a file path and name. * * @param pathName * Path for file (may be absolute, relative, or empty). * @param fileNameWithExtension * Name of file with extension. */ AString FileInformation::assembleFileComponents(const AString& pathName, const AString& fileNameWithExtension) { AString name; if ( ! pathName.isEmpty()) { name += (pathName + "/"); } name += fileNameWithExtension; return name; } /** * Create the file path for a file with the given name in the * computer system's temporary directory. * * @param fileName * Name of the file with an extension. Any path in the name is ignored. * @return * File path in the temporary directory with the given file name. */ AString FileInformation::createTemporaryFilePathName(const AString& fileName) { AString nameOut; FileInformation fileInfo(fileName); AString nameNoPath = fileInfo.getFileName(); if (nameNoPath.isEmpty()) { nameOut = FileInformation::assembleFileComponents(SystemUtilities::getTempDirectory(), "name_missing.tmp"); } else { nameOut = FileInformation::assembleFileComponents(SystemUtilities::getTempDirectory(), nameNoPath); } return nameOut; } /** * Replace the extension in a file name. * * @param fileName * Name of file * @param newExtension * New extension that replaces the extension in fileName * @return * fileName with extension replaced with newExtension. */ AString FileInformation::replaceExtension(const AString& fileName, const AString& newExtension) { AString thePath, theName, theExtension; FileInformation fileInfo(fileName); fileInfo.getFileComponents(thePath, theName, theExtension); const AString nameOut = assembleFileComponents(thePath, theName, newExtension); return nameOut; } /** * Convert, if needed, the file information to a local, absolute path. * * If the file is a remote file, the file name is added to the given current directory. * * If the file is local but a relative path, the filename is added to the given * current directory. * * If the file is local but an absolute path, the result of getAbsoluteFilePath() * is returned. * * @param currentDirectory * The current directory used by remote and relative file paths. * @param dataFileType * The type of data file. If the type is not UNKNOWN, and the * the file name does not end in the proper extension, the extension * is added to the file. @ @return * The local absolute file path. */ AString FileInformation::getAsLocalAbsoluteFilePath(const AString& currentDirectory, const DataFileTypeEnum::Enum dataFileType) const { AString thePath, theName, theExtension; getFileComponents(thePath, theName, theExtension); if (m_isLocalFile) { if (m_fileInfo.isRelative()) { thePath = currentDirectory; } } else if (m_isRemoteFile) { thePath = currentDirectory; theName = theName.replace("?", "_"); theName = theName.replace(":", "_"); theName = theName.replace("=", "_"); theName = theName.replace("@", "_"); } if (dataFileType != DataFileTypeEnum::UNKNOWN) { AString validExtension = ""; const std::vector validExtensions = DataFileTypeEnum::getAllFileExtensions(dataFileType); for (std::vector::const_iterator iter = validExtensions.begin(); iter != validExtensions.end(); iter++) { const AString ext = *iter; if (theExtension == ext) { validExtension = ext; break; } } if (validExtension.isEmpty()) { validExtension = DataFileTypeEnum::toFileExtension(dataFileType); } theExtension = validExtension; } const AString nameOut = assembleFileComponents(thePath, theName, theExtension); return nameOut; } /** * @return The file's absolute path. It DOES NOT include the file's name. * Note: A remote file returns everything up to the last slash. */ AString FileInformation::getAbsolutePath() const { if (m_isRemoteFile) { const AString fullName = m_urlInfo.toString(); const int lastSlashIndex = fullName.lastIndexOf("/"); if (lastSlashIndex > 0) { const AString thePath = fullName.left(lastSlashIndex); return thePath; } return fullName; } return m_fileInfo.absolutePath(); } AString FileInformation::getLastDirectory() const { QStringList myList = getPathName().split('/', QString::SkipEmptyParts);//QT always uses /, even on windows return myList[myList.size() - 1]; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString FileInformation::toString() const { if (m_isRemoteFile) { return ("FileInformation for " + m_urlInfo.toString()); } return ("FileInformation for " + m_fileInfo.absoluteFilePath()); } /** * For a remote file, strip the username and password from the URL * and return the URL (without username and password), the username, * and the password. If the file is local or does not contain * username/password, the equivalent of getFilePath() is the output URL. * * @param urlOut * The URL with the username and password removed. * @param * The username that was in the URL. * @param * The password that was in the URL. */ void FileInformation::getRemoteUrlUsernameAndPassword(AString& urlOut, AString& usernameOut, AString& passwordOut) const { urlOut = ""; usernameOut = ""; passwordOut = ""; if (m_isRemoteFile) { urlOut = m_urlInfo.toString(QUrl::RemoveUserInfo); usernameOut = m_urlInfo.userName(); passwordOut = m_urlInfo.password(); return; } urlOut = getAbsoluteFilePath(); } /** * Convert the number of bytes to a string that includes standard units * (ie: Bytes, Kilobytes, Megabytes, Gigabytes, etc.) * * @param numberOfBytes * The number of bytes. * @return * String with the size in standard units. */ AString FileInformation::fileSizeToStandardUnits(const int64_t numberOfBytes) { double bytes = numberOfBytes; short index = 0; static const char *labels[9] = {" Bytes", " Kilobytes", " Megabytes", " Gigabytes", " Terabytes", " Petabytes", " Exabytes", " Zettabytes", " Yottabytes"}; while (index < 8 && bytes > 1000.0f) { ++index; bytes = bytes / 1000.0f;//using 1024 would make it Kibibytes, etc } AString sizeString = AString::number(bytes, 'f', 2) + labels[index];//2 digits after decimal point return sizeString; } /** * Cleans the path. First, replaces any backward slashes with forward slashes * and then calls QDir::cleanPath(). Note that QDir::cleanPath() only converts * backward slashes to forward slashes when the native separator is a backward * slash (on Windows). Thus, if a path on Mac or Linux contains a backward * slash, QDir::cleanPath() will not convert to a forward slash. * * @param path * This input path. * @return * Path after cleaning. */ AString FileInformation::cleanPath(const AString& path) { AString pathOut(path); pathOut.replace(QLatin1Char('\\'), QLatin1Char('/')); pathOut = QDir::cleanPath(pathOut); return pathOut; } connectome-workbench-1.4.2/src/Common/FileInformation.h000066400000000000000000000103011360521144700231030ustar00rootroot00000000000000#ifndef __FILE_INFORMATION__H_ #define __FILE_INFORMATION__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "DataFileTypeEnum.h" #include #include namespace caret { class FileInformation : public CaretObject { public: FileInformation(const AString& file); FileInformation(const AString& path, const AString& file); virtual ~FileInformation(); bool isLocalFile() const; bool isRemoteFile() const; bool exists() const; bool isFile() const; bool isDirectory() const; bool isSymbolicLink() const; bool isReadable() const; bool isWritable() const; bool isAbsolute() const; bool isRelative() const; bool isHidden() const; int64_t size() const; AString getAsLocalAbsoluteFilePath(const AString& currentDirectory, const DataFileTypeEnum::Enum dataFileType) const; AString getFileNameFollowedByPathNameForGUI() const; AString getFileName() const; AString getFileNameNoExtension() const; AString getPathName() const; AString getAbsoluteFilePath() const; AString getCanonicalFilePath() const; AString getCanonicalPath() const; AString getFileExtension() const; AString getAbsolutePath() const; AString getLastDirectory() const; void getFileComponents(AString& absolutePathOut, AString& fileNameWithoutExtensionOut, AString& extensionWithoutDotOut) const; static AString assembleFileComponents(const AString& pathName, const AString& fileNameWithoutExtension, const AString& extensionWithoutDot); static AString assembleFileComponents(const AString& pathName, const AString& fileNameWithExtension); static AString createTemporaryFilePathName(const AString& fileNameWithExtension); static AString replaceExtension(const AString& fileName, const AString& newExtension); bool remove(); void getRemoteUrlUsernameAndPassword(AString& urlOut, AString& usernameOut, AString& passwordOut) const; static AString fileSizeToStandardUnits(const int64_t numberOfBytes); static AString cleanPath(const AString& path); private: FileInformation(const FileInformation&); FileInformation& operator=(const FileInformation&); public: virtual AString toString() const; private: QFileInfo m_fileInfo; QUrl m_urlInfo; bool m_isRemoteFile; bool m_isLocalFile; }; #ifdef __FILE_INFORMATION_DECLARE__ // #endif // __FILE_INFORMATION_DECLARE__ } // namespace #endif //__FILE_INFORMATION__H_ connectome-workbench-1.4.2/src/Common/FloatMatrix.cxx000066400000000000000000000240001360521144700226240ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "CaretException.h" #include "CaretLogger.h" #include "FloatMatrix.h" #include "MatrixFunctions.h" using namespace caret; using namespace std; bool FloatMatrix::checkDimensions() const { uint64_t rows = m_matrix.size(), cols; if (rows == 0) return true;//treat it as fine for now cols = m_matrix[0].size(); for (uint64_t i = 1; i < rows; ++i) { if (m_matrix[i].size() != cols) { return false; } } return true; } FloatMatrix::FloatMatrix(const vector >& matrixIn) { m_matrix = matrixIn; CaretAssert(checkDimensions()); } FloatMatrix::FloatMatrix(const int64_t& rows, const int64_t& cols) { resize(rows, cols, true); } bool FloatMatrix::operator!=(const FloatMatrix& right) const { return !(*this == right); } FloatMatrix FloatMatrix::operator*(const FloatMatrix& right) const { FloatMatrix ret; MatrixFunctions::multiply(m_matrix, right.m_matrix, ret.m_matrix); return ret; } FloatMatrix& FloatMatrix::operator*=(const FloatMatrix& right) { MatrixFunctions::multiply(m_matrix, right.m_matrix, m_matrix);//would need a copy anyway, so let it make the copy internally return *this; } FloatMatrix FloatMatrix::concatHoriz(const FloatMatrix& right) const { FloatMatrix ret; MatrixFunctions::horizCat(m_matrix, right.m_matrix, ret.m_matrix); return ret; } FloatMatrix FloatMatrix::concatVert(const FloatMatrix& bottom) const { FloatMatrix ret; MatrixFunctions::vertCat(m_matrix, bottom.m_matrix, ret.m_matrix); return ret; } FloatMatrix FloatMatrix::getRange(const int64_t firstRow, const int64_t afterLastRow, const int64_t firstCol, const int64_t afterLastCol) const { FloatMatrix ret; MatrixFunctions::getChunk(firstRow, afterLastRow, firstCol, afterLastCol, m_matrix, ret.m_matrix); return ret; } FloatMatrix FloatMatrix::identity(const int64_t rows) { FloatMatrix ret; MatrixFunctions::identity(rows, ret.m_matrix); return ret; } FloatMatrix FloatMatrix::inverse() const { FloatMatrix ret; MatrixFunctions::inverse(m_matrix, ret.m_matrix); return ret; } FloatMatrix& FloatMatrix::operator*=(const float& right) { MatrixFunctions::multiply(m_matrix, right, m_matrix);//internally makes a copy return *this; } FloatMatrix FloatMatrix::operator+(const FloatMatrix& right) const { FloatMatrix ret; MatrixFunctions::add(m_matrix, right.m_matrix, ret.m_matrix); return ret; } FloatMatrix& FloatMatrix::operator+=(const FloatMatrix& right) { MatrixFunctions::add(m_matrix, right.m_matrix, m_matrix); return *this; } FloatMatrix& FloatMatrix::operator+=(const float& right) { MatrixFunctions::add(m_matrix, right, m_matrix); return *this; } FloatMatrix FloatMatrix::operator-(const FloatMatrix& right) const { FloatMatrix ret; MatrixFunctions::subtract(m_matrix, right.m_matrix, ret.m_matrix); return ret; } FloatMatrix& FloatMatrix::operator-=(const FloatMatrix& right) { MatrixFunctions::subtract(m_matrix, right.m_matrix, m_matrix); return *this; } FloatMatrix& FloatMatrix::operator-=(const float& right) { MatrixFunctions::add(m_matrix, (-right), m_matrix); return *this; } FloatMatrix& FloatMatrix::operator/=(const float& right) { return ((*this) *= 1.0f / right); } bool FloatMatrix::operator==(const FloatMatrix& right) const { if (this == &right) { return true;//short circuit true on pointer equivalence } int64_t i, j, rows = (int64_t)m_matrix.size(), cols; if (rows != (int64_t)right.m_matrix.size()) { return false; } if (rows == 0) { return true;//don't try to get the second dimension } cols = (int64_t)m_matrix[0].size(); if (cols != (int64_t)right.m_matrix[0].size()) { return false; } for (i = 0; i < rows; ++i) { for (j = 0; j < cols; ++j) { if (m_matrix[i][j] != right.m_matrix[i][j]) { return false; } } } return true; } void FloatMatrix::getDimensions(int64_t& rows, int64_t& cols) const { rows = (int64_t)m_matrix.size(); if (rows == 0) { cols = 0; } else { cols = (int64_t)m_matrix[0].size(); } } FloatMatrixRowRef FloatMatrix::operator[](const int64_t& index) { CaretAssert(index > -1 && index < (int64_t)m_matrix.size()); FloatMatrixRowRef ret(m_matrix[index]); return ret; } ConstFloatMatrixRowRef FloatMatrix::operator[](const int64_t& index) const { CaretAssert(index > -1 && index < (int64_t)m_matrix.size()); ConstFloatMatrixRowRef ret(m_matrix[index]); return ret; } FloatMatrix FloatMatrix::reducedRowEchelon() const { FloatMatrix ret(*this); MatrixFunctions::rref(ret.m_matrix); return ret; } void FloatMatrix::resize(const int64_t rows, const int64_t cols, const bool destructive) { MatrixFunctions::resize(rows, cols, m_matrix, destructive); } FloatMatrix FloatMatrix::transpose() const { FloatMatrix ret; MatrixFunctions::transpose(m_matrix, ret.m_matrix); return ret; } float FloatMatrix::determinant() const { int64_t numRows = getNumberOfRows(), numCols = getNumberOfColumns(); if (numRows != numCols) throw CaretException("determinant() called on non-square matrix"); if (numRows == 0) return 1;//whatever if (numRows == 1) return m_matrix[0][0]; if (numRows == 2) return m_matrix[0][0] * m_matrix[1][1] - m_matrix[0][1] * m_matrix[1][0]; if (numRows == 3) return m_matrix[0][0] * m_matrix[1][1] * m_matrix[2][2] + m_matrix[0][1] * m_matrix[1][2] * m_matrix[2][0] + m_matrix[0][2] * m_matrix[1][0] * m_matrix[2][1] - m_matrix[0][0] * m_matrix[1][2] * m_matrix[2][1] - m_matrix[0][1] * m_matrix[1][0] * m_matrix[2][2] - m_matrix[0][2] * m_matrix[1][1] * m_matrix[2][0]; if (numRows > 7) { CaretLogWarning("determinant() called on matrix with size " + AString::number(numRows) + ", current algorithm is slow, O(n!) recursive"); } double ret = 0.0;//replace with LU decomposition if we need it before adding a real matrix library for (int64_t i = 0; i < numRows; ++i)//warning, O(n!) runtime { float minor = this->getRange(0, i, 1, numCols).concatVert(this->getRange(i + 1, numRows, 1, numCols)).determinant(), factor = (i % 2 ? -1.0f : 1.0f); ret += minor * factor; } return ret; } FloatMatrix FloatMatrix::zeros(const int64_t rows, const int64_t cols) { FloatMatrix ret; MatrixFunctions::zeros(rows, cols, ret.m_matrix); return ret; } FloatMatrix FloatMatrix::ones(const int64_t rows, const int64_t cols) { FloatMatrix ret; MatrixFunctions::ones(rows, cols, ret.m_matrix); return ret; } const vector >& FloatMatrix::getMatrix() const { return m_matrix; } void FloatMatrix::getAffineVectors(Vector3D& xvec, Vector3D& yvec, Vector3D& zvec, Vector3D& offset) const { if (m_matrix.size() < 3 || m_matrix.size() > 4 || m_matrix[0].size() != 4) { throw CaretException("getAffineVectors called on incorrectly sized matrix"); } xvec[0] = m_matrix[0][0]; xvec[1] = m_matrix[1][0]; xvec[2] = m_matrix[2][0]; yvec[0] = m_matrix[0][1]; yvec[1] = m_matrix[1][1]; yvec[2] = m_matrix[2][1]; zvec[0] = m_matrix[0][2]; zvec[1] = m_matrix[1][2]; zvec[2] = m_matrix[2][2]; offset[0] = m_matrix[0][3]; offset[1] = m_matrix[1][3]; offset[2] = m_matrix[2][3]; } FloatMatrix FloatMatrix::operator-() const { int64_t rows, cols; getDimensions(rows, cols); FloatMatrix ret = zeros(rows, cols); ret -= *this; return ret; } FloatMatrixRowRef::FloatMatrixRowRef(vector& therow) : m_row(therow) { } FloatMatrixRowRef& FloatMatrixRowRef::operator=(const FloatMatrixRowRef& right) { if (&m_row == &(right.m_row)) {//just in case vector isn't smart enough to check self assignment return *this; } CaretAssert(m_row.size() == right.m_row.size());//maybe this should be an exception, not an assertion? m_row = right.m_row; return *this; } FloatMatrixRowRef& FloatMatrixRowRef::operator=(const float& right) { for (int64_t i = 0; i < (int64_t)m_row.size(); ++i) { m_row[i] = right; } return *this; } float& FloatMatrixRowRef::operator[](const int64_t& index) { CaretAssert(index > -1 && index < (int64_t)m_row.size());//instead of segfaulting, explicitly check in debug return m_row[index]; } FloatMatrixRowRef::FloatMatrixRowRef(FloatMatrixRowRef& right) : m_row(right.m_row) { } FloatMatrixRowRef& FloatMatrixRowRef::operator=(const ConstFloatMatrixRowRef& right) { if (&m_row == &(right.m_row)) {//just in case vector isn't smart enough to check self assignment return *this; } CaretAssert(m_row.size() == right.m_row.size()); m_row = right.m_row; return *this; } const float& ConstFloatMatrixRowRef::operator[](const int64_t& index) { CaretAssert(index > -1 && index < (int64_t)m_row.size());//instead of segfaulting, explicitly check in debug return m_row[index]; } ConstFloatMatrixRowRef::ConstFloatMatrixRowRef(const ConstFloatMatrixRowRef& right) : m_row(right.m_row) { } ConstFloatMatrixRowRef::ConstFloatMatrixRowRef(const vector& therow) : m_row(therow) { } connectome-workbench-1.4.2/src/Common/FloatMatrix.h000066400000000000000000000136651360521144700222700ustar00rootroot00000000000000 #ifndef __FLOAT_MATRIX_H__ #define __FLOAT_MATRIX_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "stdint.h" #include "Vector3D.h" namespace caret { class ConstFloatMatrixRowRef {//needed to do [][] on a const FloatMatrix const std::vector& m_row; ConstFloatMatrixRowRef();//disallow default construction, this contains a reference public: ConstFloatMatrixRowRef(const ConstFloatMatrixRowRef& right);//copy constructor ConstFloatMatrixRowRef(const std::vector& therow); const float& operator[](const int64_t& index);//access element friend class FloatMatrixRowRef;//so it can check if it points to the same row }; class FloatMatrixRowRef {//needed to ensure some joker doesn't call mymatrix[1].resize();, while still allowing mymatrix[1][2] = 5; and mymatrix[1] = mymatrix[2]; std::vector& m_row; FloatMatrixRowRef();//disallow default construction, this contains a reference public: FloatMatrixRowRef(FloatMatrixRowRef& right);//copy constructor FloatMatrixRowRef(std::vector& therow); FloatMatrixRowRef& operator=(const FloatMatrixRowRef& right);//NOTE: copy row contents! FloatMatrixRowRef& operator=(const ConstFloatMatrixRowRef& right);//NOTE: copy row contents! FloatMatrixRowRef& operator=(const float& right);//NOTE: set all row values! float& operator[](const int64_t& index);//access element }; ///class for using single precision matrices (insulates other code from the MatrixFunctions templated header) ///errors will result in a matrix of size 0x0, or an assertion failure if the underlying vector isn't rectangular class FloatMatrix { std::vector > m_matrix; bool checkDimensions() const;//put this inside asserts at the end of functions public: FloatMatrix() { };//to make the compiler happy ///construct from a simple vector > FloatMatrix(const std::vector >& matrixIn); ///construct uninitialized with given size FloatMatrix(const int64_t& rows, const int64_t& cols); FloatMatrixRowRef operator[](const int64_t& index);//allow direct indexing to rows ConstFloatMatrixRowRef operator[](const int64_t& index) const;//allow direct indexing to rows while const FloatMatrix& operator+=(const FloatMatrix& right);//add to FloatMatrix& operator-=(const FloatMatrix& right);//subtract from FloatMatrix& operator*=(const FloatMatrix& right);//multiply by FloatMatrix& operator+=(const float& right);//add scalar to FloatMatrix& operator-=(const float& right);//subtract scalar from FloatMatrix& operator*=(const float& right);//multiply by scalar FloatMatrix& operator/=(const float& right);//divide by scalar FloatMatrix operator+(const FloatMatrix& right) const;//add FloatMatrix operator-(const FloatMatrix& right) const;//subtract FloatMatrix operator-() const;//negate FloatMatrix operator*(const FloatMatrix& right) const;//multiply bool operator==(const FloatMatrix& right) const;//compare bool operator!=(const FloatMatrix& right) const;//anti-compare ///return the inverse FloatMatrix inverse() const; ///return the reduced row echelon form FloatMatrix reducedRowEchelon() const; ///return the transpose FloatMatrix transpose() const; ///determinant - warning, uses slow O(n!) recursive algorithm float determinant() const; ///resize the matrix - keeps contents within bounds unless destructive is true (destructive is faster) void resize(const int64_t rows, const int64_t cols, const bool destructive = false); ///get the range of values from first until one before afterLast, as a new matrix FloatMatrix getRange(const int64_t firstRow, const int64_t afterLastRow, const int64_t firstCol, const int64_t afterLastCol) const; ///return a matrix formed by concatenating right to the right of this FloatMatrix concatHoriz(const FloatMatrix& right) const; ///returns a matrix formed by concatenating bottom to the bottom of this FloatMatrix concatVert(const FloatMatrix& bottom) const; ///get the dimensions void getDimensions(int64_t& rows, int64_t& cols) const; ///get the matrix as a vector const std::vector >& getMatrix() const; ///separate 3x4 or 4x4 into Vector3Ds, throw on wrong dimensions void getAffineVectors(Vector3D& xvec, Vector3D& yvec, Vector3D& zvec, Vector3D& offset) const; ///get number of rows int64_t getNumberOfRows() const { return (int64_t)m_matrix.size(); } ///get number of columns int64_t getNumberOfColumns() const { if (m_matrix.size() == 0) return 0; return (int64_t)m_matrix[0].size(); } ///return a matrix of zeros static FloatMatrix zeros(const int64_t rows, const int64_t cols); ///return a matrix of ones static FloatMatrix ones(const int64_t rows, const int64_t cols); ///return square identity matrix static FloatMatrix identity(const int64_t rows); }; } #endif //__FLOAT_MATRIX_H__ connectome-workbench-1.4.2/src/Common/Histogram.cxx000066400000000000000000000323651360521144700223440ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Histogram.h" #include "CaretAssert.h" #include using namespace caret; using namespace std; Histogram::Histogram(const int& numBuckets) { resize(numBuckets); reset(); } Histogram::Histogram(const float* data, const int64_t& dataCount) { CaretAssert(dataCount > 0); const int MIN_BUCKET_COUNT = 10; const int MAX_BUCKET_COUNT = 10000;//hits this max at 100 million int numBuckets = (int)sqrt((float)dataCount); if (numBuckets < MIN_BUCKET_COUNT) numBuckets = MIN_BUCKET_COUNT; if (numBuckets > MAX_BUCKET_COUNT) numBuckets = MAX_BUCKET_COUNT; resize(numBuckets); update(data, dataCount); } Histogram::Histogram(const int& numBuckets, const float* data, const int64_t& dataCount) { resize(numBuckets); update(data, dataCount); } void Histogram::resize(const int& buckets) { CaretAssert(buckets > 0); m_buckets.resize(buckets); m_cumulative.resize(buckets); m_display.resize(buckets); } void Histogram::reset() { m_posCount = 0; m_zeroCount = 0; m_negCount = 0; m_infCount = 0; m_negInfCount = 0; m_nanCount = 0; int numBuckets = (int)m_buckets.size(); for (int i = 0; i < numBuckets; ++i) { m_buckets[i] = 0; m_cumulative[i] = 0; m_display[i] = 0.0f; } m_displayHeightMax = 0.0; m_bucketMin = 0.0; m_bucketMax = 0.0; } void Histogram::update(const int& numBuckets, const float* data, const int64_t& dataCount) { resize(numBuckets); update(data, dataCount); } void Histogram::update(const float* data, const int64_t& dataCount) { int numBuckets = (int)m_buckets.size(); reset(); bool first = true; for (int64_t i = 0; i < dataCount; ++i) {//count value classes if (data[i] != data[i]) { ++m_nanCount; continue;//skip NaNs } if (data[i] == 0.0f)//test exactly zero (negative zero also tests equal), in case someone wants stats on something with miniscule values (percent of surface area per node?) { ++m_zeroCount; } else { if (data[i] < 0.0f) { if (data[i] * 2.0f == data[i]) { ++m_negInfCount; continue;//skip neg infs } else { ++m_negCount; } } else { if (data[i] * 2.0f == data[i]) { ++m_infCount; continue;//skip infs } else { ++m_posCount; } } } if (first) { first = false; m_bucketMin = data[i]; m_bucketMax = data[i]; } else { if (data[i] > m_bucketMax) { m_bucketMax = data[i]; } else if (data[i] < m_bucketMin) {//skip testing for new minimum if we found a new maximum m_bucketMin = data[i]; } } } if (first) { m_bucketMin = m_bucketMax = 0.0f; return;//our arrays are already zeroed, so just return if no valid data } if (m_bucketMin == m_bucketMax) { int64_t totalValid = m_negCount + m_posCount + m_zeroCount; for (int i = 0; i < numBuckets - 1; ++i) { m_cumulative[i] = (i + 1) * totalValid / numBuckets;//so, its not particularly useful if our range is zero, but split them evenly among buckets just for kicks if (i == 0) { m_buckets[i] = m_cumulative[i]; } else { m_buckets[i] = m_cumulative[i] - m_cumulative[i - 1]; } }//display is already zeroed, so just return m_cumulative[numBuckets - 1] = totalValid;//make sure the last one has all of them if (numBuckets > 1) { m_buckets[numBuckets - 1] = m_cumulative[numBuckets - 1] - m_cumulative[numBuckets - 2]; } else { m_buckets[numBuckets - 1] = m_cumulative[numBuckets - 1]; } return; } float bucketsize = (m_bucketMax - m_bucketMin) / numBuckets; for (int64_t i = 0; i < dataCount; ++i) {//determine histogram if (data[i] != data[i]) continue;//exclude NaN if (data[i] < -1.0f && (data[i] * 2.0f == data[i])) continue;//exclude -inf if (data[i] > 1.0f && (data[i] * 2.0f == data[i])) continue;//exclude inf int bucket = (int)((data[i] - m_bucketMin) / bucketsize);//doesn't really matter whether small negative floats truncate to a 0 integer if (bucket < 0) bucket = 0;//because of this if (bucket >= numBuckets) bucket = numBuckets - 1; CaretAssertVectorIndex(m_buckets, bucket); ++m_buckets[bucket]; } computeCumulative(); m_displayHeightMax = 0.0; for (int i = 0; i < numBuckets; ++i) {//compute display values by normalizing by bucket size m_display[i] = m_buckets[i] / bucketsize; if (m_display[i] > m_displayHeightMax) { m_displayHeightMax = m_display[i]; } } } void Histogram::update(const int32_t& numBuckets, const float* data, const int64_t& dataCount, float mostPositiveValueInclusive, float leastPositiveValueInclusive, float leastNegativeValueInclusive, float mostNegativeValueInclusive, const bool& includeZeroValues) { resize(numBuckets); update(data, dataCount, mostPositiveValueInclusive, leastPositiveValueInclusive, leastNegativeValueInclusive, mostNegativeValueInclusive, includeZeroValues); } void Histogram::update(const float* data, const int64_t& dataCount, float mostPositiveValueInclusive, float leastPositiveValueInclusive, float leastNegativeValueInclusive, float mostNegativeValueInclusive, const bool& includeZeroValues) { int numBuckets = (int)m_buckets.size(); reset(); if (mostNegativeValueInclusive > 0.0f) mostNegativeValueInclusive = 0.0f;//sanity check the inputs without asserting if (mostPositiveValueInclusive < 0.0f) mostPositiveValueInclusive = 0.0f; if (leastNegativeValueInclusive > 0.0f) leastNegativeValueInclusive = 0.0f; if (leastPositiveValueInclusive < 0.0f) leastPositiveValueInclusive = 0.0f; if ((mostPositiveValueInclusive >= leastPositiveValueInclusive && mostPositiveValueInclusive != 0.0f) || includeZeroValues) { m_bucketMax = mostPositiveValueInclusive; } else { m_bucketMax = leastNegativeValueInclusive; } if (mostNegativeValueInclusive != 0.0f || includeZeroValues) { m_bucketMin = mostNegativeValueInclusive; } else { m_bucketMin = leastPositiveValueInclusive; } float sanity = m_bucketMax + m_bucketMin; if (m_bucketMax <= m_bucketMin || sanity != sanity) {//bad input ranges, so collect counts, make a mock histogram if equal, and return (display values will be zeros) int64_t equalCount = 0; for (int64_t i = 0; i < dataCount; ++i) { if (data[i] != data[i]) { ++m_nanCount; continue; } if (data[i] < -1.0f && (data[i] * 2.0f == data[i])) { ++m_negInfCount; continue; } if (data[i] > 1.0f && (data[i] * 2.0f == data[i])) { ++m_infCount; continue; } if (data[i] == m_bucketMax) { ++equalCount; } } if (m_bucketMax == m_bucketMin) { if (m_bucketMax == 0.0f) { m_zeroCount = equalCount; } else { if (m_bucketMax < 0.0f) { m_negCount = equalCount; } else { m_posCount = equalCount; } } for (int i = 0; i < numBuckets - 1; ++i) { m_cumulative[i] = (i + 1) * equalCount / numBuckets;//so, its not particularly useful if our range is zero, but split them evenly among buckets just for kicks if (i == 0) { m_buckets[i] = m_cumulative[i]; } else { m_buckets[i] = m_cumulative[i] - m_cumulative[i - 1]; } }//display is already zeroed, so just return m_cumulative[numBuckets - 1] = equalCount;//make sure the last one has all of them if (numBuckets > 1) { m_buckets[numBuckets - 1] = m_cumulative[numBuckets - 1] - m_cumulative[numBuckets - 2]; } else { m_buckets[numBuckets - 1] = m_cumulative[numBuckets - 1]; } } return; } float bucketsize = (m_bucketMax - m_bucketMin) / numBuckets; for (int64_t i = 0; i < dataCount; ++i)//do the histogram {//count value classes if (data[i] != data[i]) { ++m_nanCount; continue;//skip NaNs } if (data[i] == 0.0f)//test exactly zero (negative zero also tests equal), in case someone wants stats on something with miniscule values (percent of surface area per node?) { if (!includeZeroValues) continue;//don't count what is excluded ++m_zeroCount; } else { if (data[i] < 0.0f) { if (data[i] * 2.0f == data[i]) { ++m_negInfCount; continue;//skip neg infs } else { if (data[i] > leastNegativeValueInclusive || data[i] < mostNegativeValueInclusive) continue;//exclude negatives outside range ++m_negCount; } } else { if (data[i] * 2.0f == data[i]) { ++m_infCount; continue;//skip infs } else { if (data[i] > mostPositiveValueInclusive || data[i] < leastPositiveValueInclusive) continue;//exclude negatives outside range ++m_posCount; } } } int bucket = (int)((data[i] - m_bucketMin) / bucketsize);//doesn't really matter whether small negative floats truncate to a 0 integer if (bucket < 0) bucket = 0;//because of this if (bucket >= numBuckets) bucket = numBuckets - 1; CaretAssertVectorIndex(m_buckets, bucket); ++m_buckets[bucket]; } computeCumulative(); m_displayHeightMax = 0.0; for (int i = 0; i < numBuckets; ++i) {//compute display values by normalizing by bucket size m_display[i] = m_buckets[i] / bucketsize; if (m_display[i] > m_displayHeightMax) { m_displayHeightMax = m_display[i]; } } } void Histogram::computeCumulative() { int numBuckets = (int)m_buckets.size(); int64_t accum = 0; for (int i = 0; i < numBuckets; ++i) { accum += m_buckets[i]; m_cumulative[i] = accum; } } /** * Get the data value and height for the histogram's bucket index. * * @param bucketIndex * The bucket index. * @param bucketDataValueOut * Output with data value at the bucket (x-axis) * @param bucketHeightOut * Output with height of bucket (y-axis) * @return * True if output values are positive, else false. */ bool Histogram::getHistogramDisplayBucketDataValueAndHeight( const int32_t bucketIndex, float& bucketDataValueOut, float& bucketHeightOut) const { bucketDataValueOut = 0.0; bucketHeightOut = 0.0; const std::vector& buckets = getHistogramDisplay(); const int32_t numberOfBuckets = static_cast(buckets.size()); if ((bucketIndex >= 0) && (bucketIndex < numberOfBuckets)) { CaretAssertVectorIndex(buckets, bucketIndex); float rangeMin = 0.0; float rangeMax = 0.0; getRange(rangeMin, rangeMax); bucketDataValueOut = rangeMin; if (rangeMax > rangeMin) { const float range = rangeMax - rangeMin; const float bucketWidth = range / numberOfBuckets; bucketDataValueOut = (rangeMin + (bucketIndex * bucketWidth)); } bucketHeightOut = buckets[bucketIndex]; return true; } return false; } connectome-workbench-1.4.2/src/Common/Histogram.h000066400000000000000000000111031360521144700217540ustar00rootroot00000000000000#ifndef __HISTOGRAM_H__ #define __HISTOGRAM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "stdint.h" namespace caret { class Histogram { std::vector m_buckets, m_cumulative; std::vector m_display; float m_bucketMin, m_bucketMax; float m_displayHeightMax; ///counts of each class of number int64_t m_posCount, m_zeroCount, m_negCount, m_infCount, m_negInfCount, m_nanCount; void resize(const int& buckets); void reset(); void computeCumulative(); void update(const float* data, const int64_t& dataCount, float mostPositiveValueInclusive, float leastPositiveValueInclusive, float leastNegativeValueInclusive, float mostNegativeValueInclusive, const bool& includeZeroValues); void update(const float* data, const int64_t& dataCount); public: Histogram(const int& numBuckets = 100); Histogram(const float* data, const int64_t& dataCount);//NOTE: automatically determines number of buckets by square root of dataCount, but with set minimum and maximum Histogram(const int& numBuckets, const float* data, const int64_t& dataCount); void update(const int& numBuckets, const float* data, const int64_t& dataCount); void update(const int32_t& numBuckets, const float* data, const int64_t& dataCount, float mostPositiveValueInclusive, float leastPositiveValueInclusive, float leastNegativeValueInclusive, float mostNegativeValueInclusive, const bool& includeZeroValues); ///get raw counts (useful mathematically) const std::vector& getHistogramCounts() const { return m_buckets; } const std::vector& getHistogramCumulativeCounts() const { return m_cumulative; } ///get display values - counts divided by bucket widths - will be consistent on the same data regardless of number of buckets or const std::vector& getHistogramDisplay() const { return m_display; } bool getHistogramDisplayBucketDataValueAndHeight( const int32_t bucketIndex, float& bucketDataValueOut, float& bucketHeightOut) const; int getNumberOfBuckets() const { return (int)m_buckets.size(); } void getCounts(int64_t& posCount, int64_t& zeroCount, int64_t& negCount, int64_t& infCount, int64_t& negInfCount, int64_t& nanCount) const { posCount = m_posCount; zeroCount = m_zeroCount; negCount = m_negCount; infCount = m_infCount; negInfCount = m_negInfCount; nanCount = m_nanCount; } /** * Get the low edge of the low bucket (x-min), and the high edge of the high bucket (x-max) * and the maximum display height (y-max). Low Y is always zero. */ void getRangeAndMaxDisplayHeight(float& histMin, float& histMax, float& displayHeightMax) const { histMin = m_bucketMin; histMax = m_bucketMax; displayHeightMax = m_displayHeightMax; } ///returns the low edge of the low bucket, and the high edge of the high bucket void getRange(float& histMin, float& histMax) const { histMin = m_bucketMin; histMax = m_bucketMax; } }; } #endif //__HISTOGRAM_H__ connectome-workbench-1.4.2/src/Common/HtmlStringBuilder.cxx000066400000000000000000000141651360521144700240070ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "HtmlStringBuilder.h" using namespace caret; /** * \class caret::HtmlStringBuilder * \brief Assists with constructing HTML text. */ /** * Constructor.mp * */ HtmlStringBuilder::HtmlStringBuilder() : CaretObject() { this->clear(); } /** * Destructor */ HtmlStringBuilder::~HtmlStringBuilder() { } /** * Append plain text (same as addText()). * * @param text - Plain text to add. * */ void HtmlStringBuilder::append(const AString& text) { this->stringBuilder.append(text); } /** * Clear the text. * */ void HtmlStringBuilder::clear() { this->stringBuilder.reserve(4096); this->stringBuilder = ""; } /** * Add plain text. * * @param text - Plain text to add. * */ void HtmlStringBuilder::add(const AString& text) { this->stringBuilder.append(text); } /** * Add plain text followed by a line break. * @param text - Plain text to add. * */ void HtmlStringBuilder::addLine(const AString& text) { this->stringBuilder.append(text); this->addLineBreak(); } /** * Append an integer. * * @param num Integer that is to be appended. * */ void HtmlStringBuilder::add(const int32_t num) { this->stringBuilder.append(AString::number(num)); } /** * Append a float. * * @param num Float that is to be appended. * */ void HtmlStringBuilder::add(const float num) { this->stringBuilder.append(AString::number(num)); } /** * Add bold text. * * @param text - Text that is made bold. * */ void HtmlStringBuilder::addBold(const AString& text) { this->stringBuilder.append(""); this->stringBuilder.append(text); this->stringBuilder.append(""); } /** * Add bold float. * * @param num - Number that is made bold. * */ void HtmlStringBuilder::addBold(const float num) { this->stringBuilder.append(""); this->stringBuilder.append(AString::number(num)); this->stringBuilder.append(""); } /** * Add bold int. * * @param num - Number that is made bold. * */ void HtmlStringBuilder::addBold(const int32_t num) { this->stringBuilder.append(""); this->stringBuilder.append(AString::number(num)); this->stringBuilder.append(""); } /** * Add a hyperlink to the text. * @param urlText - URL that is target. * @param linkText - Text displayed as hyperlink. * */ void HtmlStringBuilder::addHyperlink( const AString& urlText, const AString& linkText) { this->stringBuilder.append("
stringBuilder.append("http://"); this->stringBuilder.append(urlText); this->stringBuilder.append("/"); this->stringBuilder.append(linkText); this->stringBuilder.append("\">"); this->stringBuilder.append(linkText); this->stringBuilder.append(""); } /** * Ends a paragraph. * */ void HtmlStringBuilder::addParagraph() { this->stringBuilder.append("

"); } /** * Add a line break. * */ void HtmlStringBuilder::addLineBreak() { this->stringBuilder.append("

"); } /** * Add a line breaks. * @param numLineBreaks - Number of line breaks to add. * */ void HtmlStringBuilder::addLineBreaks(const int32_t numLineBreaks) { for (int i = 0; i < numLineBreaks; i++) { this->addLineBreak(); } } /** * Add a space. * */ void HtmlStringBuilder::addSpace() { this->stringBuilder.append(" "); } /** * Add a spaces. * @param numSpaces - Number of spaces. * */ void HtmlStringBuilder::addSpaces(const int32_t numSpaces) { for (int i = 0; i < numSpaces; i++) { this->addSpace(); } } /** * Get the total text length (includes HTML markup). * @return Length of text. * */ int32_t HtmlStringBuilder::length() { return this->stringBuilder.length(); } /** * Convert to a string in HTML format WITHOUT leading and trailing * HTML and BODY tags. * * @return String containing text. * */ AString HtmlStringBuilder::toString() const { return this->stringBuilder; } /** * Convert to a string in HTML format WITH leading and trailing * HTML and BODY tags. * * @return String containing text. * */ AString HtmlStringBuilder::toStringWithHtmlBodyForToolTip() { return toStringWithHtmlBodyPrivate(true); } /** * Convert to a string in HTML format WITH leading and trailing * HTML and BODY tags. * * @return String containing text. * */ AString HtmlStringBuilder::toStringWithHtmlBody() { return toStringWithHtmlBodyPrivate(false); } /** * Convert to a string in HTML format WITH leading and trailing * HTML and BODY tags. * * @param toolTipFlag * If true, set the style so text does not wrap when * placed into a QToolTip (see QToolTip documentation). * @return String containing text. * */ AString HtmlStringBuilder::toStringWithHtmlBodyPrivate(const bool toolTipFlag) { AString sb; sb.reserve(this->stringBuilder.length() + 100); sb.append(""); if (toolTipFlag) { sb.append("

"); } /* * If the string ends with a line break, remove the line break */ const AString lastBreak("

"); if (this->stringBuilder.endsWith(lastBreak)) { this->stringBuilder.resize(this->stringBuilder.length() - lastBreak.length()); } sb.append(this->stringBuilder); if (toolTipFlag) { sb.append("

"); } sb.append(""); return sb; } connectome-workbench-1.4.2/src/Common/HtmlStringBuilder.h000066400000000000000000000046741360521144700234400ustar00rootroot00000000000000#ifndef __HTMLSTRINGBUILDER_H__ #define __HTMLSTRINGBUILDER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include class StringBuilder; namespace caret { class HtmlStringBuilder : public CaretObject { public: HtmlStringBuilder(); virtual ~HtmlStringBuilder(); private: HtmlStringBuilder(const HtmlStringBuilder& o); HtmlStringBuilder& operator=(const HtmlStringBuilder& o); public: void append(const AString& text); void clear(); void add(const AString& text); void addLine(const AString& text); void add(const int32_t num); void add(const float num); void addBold(const AString& text); void addBold(const float num); void addBold(const int32_t num); void addHyperlink( const AString& urlText, const AString& linkText); void addParagraph(); void addLineBreak(); void addLineBreaks(const int32_t numLineBreaks); void addSpace(); void addSpaces(const int32_t numSpaces); int32_t length(); AString toString() const; AString toStringWithHtmlBody(); AString toStringWithHtmlBodyForToolTip(); private: AString toStringWithHtmlBodyPrivate(const bool toolTipFlag); AString stringBuilder; }; } // namespace #endif // __HTMLSTRINGBUILDER_H__ connectome-workbench-1.4.2/src/Common/ImageCaptureMethodEnum.cxx000066400000000000000000000256041360521144700247410ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __IMAGE_CAPTURE_METHOD_ENUM_DECLARE__ #include "ImageCaptureMethodEnum.h" #undef __IMAGE_CAPTURE_METHOD_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ImageCaptureMethodEnum * \brief Enumerated type for image capture method used in QGLWidget * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_imageCaptureMethodEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void imageCaptureMethodEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ImageCaptureMethodEnum.h" * * Instatiate: * m_imageCaptureMethodEnumComboBox = new EnumComboBoxTemplate(this); * m_imageCaptureMethodEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_imageCaptureMethodEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(imageCaptureMethodEnumComboBoxItemActivated())); * * Update the selection: * m_imageCaptureMethodEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ImageCaptureMethodEnum::Enum VARIABLE = m_imageCaptureMethodEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ImageCaptureMethodEnum::ImageCaptureMethodEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ImageCaptureMethodEnum::~ImageCaptureMethodEnum() { } /** * Initialize the enumerated metadata. */ void ImageCaptureMethodEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ImageCaptureMethodEnum(IMAGE_CAPTURE_WITH_RENDER_PIXMAP, "IMAGE_CAPTURE_WITH_RENDER_PIXMAP", "Render Pixmap")); enumData.push_back(ImageCaptureMethodEnum(IMAGE_CAPTURE_WITH_GRAB_FRAME_BUFFER, "IMAGE_CAPTURE_WITH_GRAB_FRAME_BUFFER", "Grab Frame Buffer")); enumData.push_back(ImageCaptureMethodEnum(IMAGE_CAPTURE_WITH_OFFSCREEN_FRAME_BUFFER, "IMAGE_CAPTURE_WITH_OFFSCREEN_FRAME_BUFFER", "Offscreen Frame Buffer")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ImageCaptureMethodEnum* ImageCaptureMethodEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ImageCaptureMethodEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ImageCaptureMethodEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ImageCaptureMethodEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ImageCaptureMethodEnum::Enum ImageCaptureMethodEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ImageCaptureMethodEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ImageCaptureMethodEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ImageCaptureMethodEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ImageCaptureMethodEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ImageCaptureMethodEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ImageCaptureMethodEnum::Enum ImageCaptureMethodEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ImageCaptureMethodEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ImageCaptureMethodEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ImageCaptureMethodEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ImageCaptureMethodEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ImageCaptureMethodEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ImageCaptureMethodEnum::Enum ImageCaptureMethodEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ImageCaptureMethodEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ImageCaptureMethodEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ImageCaptureMethodEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ImageCaptureMethodEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ImageCaptureMethodEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ImageCaptureMethodEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ImageCaptureMethodEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ImageCaptureMethodEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/ImageCaptureMethodEnum.h000066400000000000000000000065361360521144700243710ustar00rootroot00000000000000#ifndef __IMAGE_CAPTURE_METHOD_ENUM_H__ #define __IMAGE_CAPTURE_METHOD_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ImageCaptureMethodEnum { public: /** * Enumerated values. */ enum Enum { /** Capture the image with QGLWidget::renderPixmap() */ IMAGE_CAPTURE_WITH_RENDER_PIXMAP, /** Capture the image with QGLWidget::grabFrameBuffer() */ IMAGE_CAPTURE_WITH_GRAB_FRAME_BUFFER, /** Capture with QOffscreenSurface and QOpenGLFramebufferObject */ IMAGE_CAPTURE_WITH_OFFSCREEN_FRAME_BUFFER }; ~ImageCaptureMethodEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ImageCaptureMethodEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ImageCaptureMethodEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __IMAGE_CAPTURE_METHOD_ENUM_DECLARE__ std::vector ImageCaptureMethodEnum::enumData; bool ImageCaptureMethodEnum::initializedFlag = false; int32_t ImageCaptureMethodEnum::integerCodeCounter = 0; #endif // __IMAGE_CAPTURE_METHOD_ENUM_DECLARE__ } // namespace #endif //__IMAGE_CAPTURE_METHOD_ENUM_H__ connectome-workbench-1.4.2/src/Common/JsonHelper.cxx000066400000000000000000000063041360521144700224520ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __JSON_HELPER_DECLARE__ #include "JsonHelper.h" #undef __JSON_HELPER_DECLARE__ #include #include #include #include #include "CaretAssert.h" using namespace caret; /** * \class caret::JsonHelper * \brief Helper class for JSON processing. * \ingroup Common */ /** * Constructor. */ JsonHelper::JsonHelper() { } /** * Destructor. */ JsonHelper::~JsonHelper() { } /** * Convert the JSON Array to a String representation * * @param jsonValue * The JSON Value * @return * The string representation of the value. */ AString JsonHelper::jsonArrayToString(const QJsonArray& jsonArray) { const QJsonDocument contentJson = QJsonDocument(jsonArray); const AString s = contentJson.toJson(QJsonDocument::Compact); return s; } /** * Determine type of content in the value and return its string representation * * @param jsonValue * The JSON Value * @return * The string representation of the value. */ AString JsonHelper::jsonValueToString(const QJsonValue& jsonValue) { AString typeString("Invalid: "); AString contentString; QJsonDocument contentJson; switch (jsonValue.type()) { case QJsonValue::Array: typeString = "Array: "; contentJson = QJsonDocument(jsonValue.toArray()); break; case QJsonValue::Bool: typeString = "Bool: "; contentString = AString::fromBool(jsonValue.toBool()); break; case QJsonValue::Double: typeString = "Double: "; contentString = AString::fromBool(jsonValue.toDouble()); break; case QJsonValue::Null: typeString = "Null: "; contentString = ""; break; case QJsonValue::Object: typeString = "Object: "; contentJson = QJsonDocument(jsonValue.toObject()); break; case QJsonValue::String: typeString = "String: "; contentString = jsonValue.toString(); break; case QJsonValue::Undefined: typeString = "Undefined: "; contentString = ""; break; } AString s(typeString); if (contentJson.isNull()) { s.append(contentString); } else { s.append(contentJson.toJson(QJsonDocument::Compact)); } return s; } connectome-workbench-1.4.2/src/Common/JsonHelper.h000066400000000000000000000031101360521144700220670ustar00rootroot00000000000000#ifndef __JSON_HELPER_H__ #define __JSON_HELPER_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AString.h" class QJsonArray; class QJsonValue; namespace caret { class JsonHelper { public: static AString jsonArrayToString(const QJsonArray& jsonArray); static AString jsonValueToString(const QJsonValue& jsonValue); // ADD_NEW_METHODS_HERE private: JsonHelper(); virtual ~JsonHelper(); JsonHelper(const JsonHelper&); JsonHelper& operator=(const JsonHelper&); // ADD_NEW_MEMBERS_HERE }; #ifdef __JSON_HELPER_DECLARE__ // #endif // __JSON_HELPER_DECLARE__ } // namespace #endif //__JSON_HELPER_H__ connectome-workbench-1.4.2/src/Common/LogHandler.cxx000066400000000000000000000023541360521144700224210ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __LOG_HANDLER_DECLARE__ #include "LogHandler.h" #undef __LOG_HANDLER_DECLARE__ using namespace caret; /** * Constructor. */ LogHandler::LogHandler() : CaretObject() { } /** * Destructor. */ LogHandler::~LogHandler() { } /** * Get a description of this object's content. * @return String describing this object's content. */ AString LogHandler::toString() const { return "LogHandler"; } connectome-workbench-1.4.2/src/Common/LogHandler.h000066400000000000000000000037621360521144700220520ustar00rootroot00000000000000#ifndef __LOG_HANDLER__H_ #define __LOG_HANDLER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" namespace caret { class LogRecord; /** * \brief Processes log record sent by a Logger. * * A Handler takes log record messages and * does something with them. This is an abstract * class and must be subclassed. * * This class emulates Java's java.util.logging.Handler. */ class LogHandler : public CaretObject { public: /// close the handler and free resources virtual void close() = 0; /// flush any buffered output virtual void flush() = 0; /// Publish a log record virtual void publish(const LogRecord& logRecord) = 0; virtual ~LogHandler(); protected: LogHandler(); private: LogHandler(const LogHandler&); LogHandler& operator=(const LogHandler&); public: virtual AString toString() const; private: }; #ifdef __LOG_HANDLER_DECLARE__ // #endif // __LOG_HANDLER_DECLARE__ } // namespace #endif //__LOG_HANDLER__H_ connectome-workbench-1.4.2/src/Common/LogHandlerStandardError.cxx000066400000000000000000000054651360521144700251220ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __LOG_HANDLER_STANDARD_ERROR_DECLARE__ #include "LogHandlerStandardError.h" #undef __LOG_HANDLER_STANDARD_ERROR_DECLARE__ #include "FileInformation.h" #include "LogRecord.h" using namespace caret; using namespace std; /** * Constructor. */ LogHandlerStandardError::LogHandlerStandardError() : LogHandler() { } /** * Destructor. */ LogHandlerStandardError::~LogHandlerStandardError() { } /** * Get a description of this object's content. * @return String describing this object's content. */ AString LogHandlerStandardError::toString() const { return "LogHandlerStandardError"; } /** * close the handler and free resources. */ void LogHandlerStandardError::close() { // nothing to close } /** * Flush any buffered output. */ void LogHandlerStandardError::flush() { std::cerr.flush(); } /** * Publish a log record. * * @param logRecord * Logging record that is sent to standard error. */ void LogHandlerStandardError::publish(const LogRecord& logRecord) { cerr << endl; cerr << LogLevelEnum::toHintedName(logRecord.getLevel()) << ": " << logRecord.getText().toLocal8Bit().constData() << endl; #ifndef NDEBUG if (logRecord.getMethodName().isEmpty() == false) {//in debug, also give method name and source location cerr << "Method: " << logRecord.getMethodName() << endl; } cerr << "Location: " << logRecord.getFilename() << ":" << AString::number(logRecord.getLineNumber()) << endl; #else if (LogLevelEnum::toIntegerCode(logRecord.getLevel()) >= LogLevelEnum::toIntegerCode(LogLevelEnum::SEVERE))//in release, give method and simplified source location only for severe or worse { if (logRecord.getMethodName().isEmpty() == false) { cerr << "Method: " << logRecord.getMethodName() << endl; } cerr << "Location: " << FileInformation(logRecord.getFilename()).getFileName() << ":" << AString::number(logRecord.getLineNumber()) << endl; } #endif cerr << endl; } connectome-workbench-1.4.2/src/Common/LogHandlerStandardError.h000066400000000000000000000035341360521144700245420ustar00rootroot00000000000000#ifndef __LOG_HANDLER_STANDARD_ERROR__H_ #define __LOG_HANDLER_STANDARD_ERROR__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "LogHandler.h" namespace caret { class LogRecord; /** * \brief * * */ class LogHandlerStandardError : public LogHandler { public: LogHandlerStandardError(); virtual ~LogHandlerStandardError(); virtual void close(); virtual void flush(); virtual void publish(const LogRecord& logRecord); private: LogHandlerStandardError(const LogHandlerStandardError&); LogHandlerStandardError& operator=(const LogHandlerStandardError&); public: virtual AString toString() const; private: }; #ifdef __LOG_HANDLER_STANDARD_ERROR_DECLARE__ // #endif // __LOG_HANDLER_STANDARD_ERROR_DECLARE__ } // namespace #endif //__LOG_HANDLER_STANDARD_ERROR__H_ connectome-workbench-1.4.2/src/Common/LogLevelEnum.cxx000066400000000000000000000242571360521144700227460ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __LOG_LEVEL_ENUM_DECLARE__ #include "LogLevelEnum.h" #undef __LOG_LEVEL_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * Constructor. * * @param enumValue * An enumerated value. * @param integerCode * Integer code for this enumerated value. * * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ LogLevelEnum::LogLevelEnum(const Enum enumValue, const int32_t integerCode, const AString& name, const AString& guiName, const AString& hintedName) { this->enumValue = enumValue; this->integerCode = integerCode; this->name = name; this->guiName = guiName; this->hintedName = hintedName; } /** * Destructor. */ LogLevelEnum::~LogLevelEnum() { } /** * Initialize the enumerated metadata. */ void LogLevelEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(LogLevelEnum(SEVERE, 800, "SEVERE", "Severe", "SEVERE")); enumData.push_back(LogLevelEnum(WARNING, 700, "WARNING", "Warning", "WARNING")); enumData.push_back(LogLevelEnum(INFO, 600, "INFO", "Information", "Info")); enumData.push_back(LogLevelEnum(CONFIG, 500, "CONFIG", "Configuration", "Config")); enumData.push_back(LogLevelEnum(FINE, 400, "FINE", "Fine (Tracing)", "Fine")); enumData.push_back(LogLevelEnum(FINER, 300, "FINER", "Finer (Detailed Tracing)", "Finer")); enumData.push_back(LogLevelEnum(FINEST, 200, "FINEST", "Finest (Very Detailed Tracing)", "Finest")); enumData.push_back(LogLevelEnum(ALL, 100, "ALL", "All", "ALL"));//shouldn't get used in messages - do we even need this? FINEST should show everything enumData.push_back(LogLevelEnum(OFF, 0, "OFF", "Off", "Off"));//also shouldn't get used in messages } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const LogLevelEnum* LogLevelEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const LogLevelEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString LogLevelEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const LogLevelEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ LogLevelEnum::Enum LogLevelEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = OFF; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const LogLevelEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + " failed to match enumerated value for type LogLevelEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString LogLevelEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const LogLevelEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ LogLevelEnum::Enum LogLevelEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = OFF; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const LogLevelEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + " failed to match enumerated value for type LogLevelEnum")); } return enumValue; } AString LogLevelEnum::toHintedName(LogLevelEnum::Enum enumValue) { if (initializedFlag == false) initialize(); const LogLevelEnum* enumInstance = findData(enumValue); CaretAssert(enumInstance != NULL); return enumInstance->hintedName; } LogLevelEnum::Enum LogLevelEnum::fromHintedName(const AString& hintedName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = OFF; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const LogLevelEnum& d = *iter; if (d.hintedName == hintedName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("hintedName " + hintedName + " failed to match enumerated value for type LogLevelEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t LogLevelEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const LogLevelEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ LogLevelEnum::Enum LogLevelEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = OFF; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const LogLevelEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type LogLevelEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void LogLevelEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } connectome-workbench-1.4.2/src/Common/LogLevelEnum.h000066400000000000000000000073021360521144700223630ustar00rootroot00000000000000#ifndef __LOG_LEVEL_ENUM__H_ #define __LOG_LEVEL_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { /** * \brief Log level. * * The log level defines a standard logging levels that are used to * control logging output. The levels are ordered and enabling * logging at a given level enables logging at all higher levels. * This class emulates the Java class java.util.logging.Level. */ class LogLevelEnum { public: /** * Enumerated values. */ enum Enum { /** serious failure */ SEVERE, /** potential problem */ WARNING, /** informational messages */ INFO, /** configuration messages, versions of libraries etc. */ CONFIG, /** Detailed information */ FINE, /** More detailed information */ FINER, /** Very detailed information, all Events are logged at this level */ FINEST, /** Log all records */ ALL, /** */ OFF }; ~LogLevelEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static AString toHintedName(Enum enumValue); static Enum fromHintedName(const AString& hintedName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); private: LogLevelEnum(const Enum enumValue, const int32_t integerCode, const AString& name, const AString& guiName, const AString& hintedName); static const LogLevelEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; /** A name that emphasizes important levels with all-caps */ AString hintedName; }; #ifdef __LOG_LEVEL_ENUM_DECLARE__ std::vector LogLevelEnum::enumData; bool LogLevelEnum::initializedFlag = false; #endif // __LOG_LEVEL_ENUM_DECLARE__ } // namespace #endif //__LOG_LEVEL_ENUM__H_ connectome-workbench-1.4.2/src/Common/LogManager.cxx000066400000000000000000000076311360521144700224210ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __LOG_MANAGER_DECLARE__ #include "CaretLogger.h" #include "LogManager.h" #undef __LOG_MANAGER_DECLARE__ #include "CaretAssert.h" #include "Logger.h" #include "LogHandlerStandardError.h" using namespace caret; /** * Constructor. */ LogManager::LogManager() : CaretObject() { } /** * Destructor. */ LogManager::~LogManager() { /* * Delete all of the loggers. */ for (std::vector::iterator iter = this->loggers.begin(); iter != this->loggers.end(); iter++) { delete (*iter); } } /** * Add a named logger. This does nothing an returns false * if a logger with the same name is already registered. * The Logger factory methods call this method to register * newly created loggers. The LogManager will 'delete' * any registed loggers when the LogManager is deleted. * * @param logger * Logger that is added. * @return * true if logger was successfully registered, false if * a logger with the same name already exists. */ bool LogManager::addLogger(Logger* logger) { CaretAssert(logger); Logger* existingLogger = this->getLogger(logger->getName()); if (existingLogger != NULL) { return false; } this->loggers.push_back(logger); return true; } /** * Find a named logger. * * @param name * Name of the logger. * @return * Matching logger or NULL if none found. */ Logger* LogManager::getLogger(const AString& name) { /* * Find logger with matching name. */ for (std::vector::iterator iter = this->loggers.begin(); iter != this->loggers.end(); iter++) { Logger* logger = *iter; if (logger->getName() == name) { return logger; } } return NULL; } /** * Return the global LogManager object. * * @return The global LogManager object. */ LogManager* LogManager::getLogManager() { return LogManager::singletonLogManager; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString LogManager::toString() const { return "LogManager"; } /** * Create the log manager. * This must be called one AND ONLY one time. */ void LogManager::createLogManager() { CaretAssertMessage((LogManager::singletonLogManager == NULL), "Log manager has already been created."); LogManager::singletonLogManager = new LogManager(); Logger* caretLoggerInstance = Logger::getLogger("CaretLogger"); caretLoggerInstance->setLevel(LogLevelEnum::CONFIG); //caretLoggerInstance->setLevel(LogLevelEnum::FINEST); caretLoggerInstance->addLogHandler(new LogHandlerStandardError()); CaretLogger::setLogger(caretLoggerInstance); } /** * Delete the log manager. * This may only be called one time after log manager is created. */ void LogManager::deleteLogManager() { CaretAssertMessage((LogManager::singletonLogManager != NULL), "Log manager does not exist, cannot delete it."); delete LogManager::singletonLogManager; LogManager::singletonLogManager = NULL; } connectome-workbench-1.4.2/src/Common/LogManager.h000066400000000000000000000042611360521144700220420ustar00rootroot00000000000000#ifndef __LOG_MANAGER__H_ #define __LOG_MANAGER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" namespace caret { class Logger; /** * \brief The logging manager. * * There is one global LogManager that keeps track of all * Loggers. The LogManager must be initialized prior to * creating any Loggers. Whn the LogManager is deleted * all loggers are also deleted. * This class emulates Java's java.util.logging.LogManager. */ class LogManager : public CaretObject { public: static void createLogManager(); static void deleteLogManager(); bool addLogger(Logger* logger); Logger* getLogger(const AString& name); static LogManager* getLogManager(); private: LogManager(); virtual ~LogManager(); LogManager(const LogManager&); LogManager& operator=(const LogManager&); /** All loggers */ std::vector loggers; /** Global log manager */ static LogManager* singletonLogManager; public: virtual AString toString() const; private: }; #ifdef __LOG_MANAGER_DECLARE__ LogManager* LogManager::singletonLogManager = NULL; #endif // __LOG_MANAGER_DECLARE__ } // namespace #endif //__LOG_MANAGER__H_ connectome-workbench-1.4.2/src/Common/LogRecord.cxx000066400000000000000000000043621360521144700222630ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __LOG_RECORD_DECLARE__ #include "LogRecord.h" #undef __LOG_RECORD_DECLARE__ using namespace caret; /** * Constructor. * * @param level * Logging level for message. * @param methodName * Method that logged the message. * @param filename * Name of file that originated the message. * @param lineNumber * Line number of message. * @param text * Text description. */ LogRecord::LogRecord(const LogLevelEnum::Enum level, const AString& methodName, const AString& filename, const int32_t lineNumber, const AString& text) : CaretObject() { this->level = level; this->methodName = methodName; this->filename = filename; this->lineNumber = lineNumber; this->text = text; } /** * Destructor. */ LogRecord::~LogRecord() { } /** * Get a description of this log record. * @return String describing this log record. */ AString LogRecord::toString() const { AString s = "Level=" + LogLevelEnum::toName(this->level); if (this->methodName.isEmpty() == false) { s += " Method=" + this->methodName; } if (this->filename.isEmpty() == false) { s += " File=" + this->filename; } if (this->lineNumber >= 0) { s += " Line=" + AString::number(this->lineNumber); } if (this->text.isEmpty() == false) { s += " Text=" + this->text; } return s; } connectome-workbench-1.4.2/src/Common/LogRecord.h000066400000000000000000000050701360521144700217050ustar00rootroot00000000000000#ifndef __LOG_RECORD__H_ #define __LOG_RECORD__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "LogLevelEnum.h" namespace caret { /** * \brief Log record. * * A record for a single logging message * This class emulates the Java calss java.util.logging. */ class LogRecord : public CaretObject { public: LogRecord(const LogLevelEnum::Enum level, const AString& methodName, const AString& filename, const int32_t lineNumber, const AString& text); virtual ~LogRecord(); LogLevelEnum::Enum getLevel() const { return level; } /** * @return Text message. */ AString getText() const { return text; } /** * @return Method name that logged message. */ AString getMethodName() const { return methodName; } /** * @return Filename in which message was logged. */ AString getFilename() const { return filename; } /** * @return Line number at which message was logged. */ int32_t getLineNumber() const { return lineNumber; } private: LogRecord(const LogRecord&); LogRecord& operator=(const LogRecord&); public: virtual AString toString() const; private: LogLevelEnum::Enum level; AString text; AString methodName; AString filename; int32_t lineNumber; }; #ifdef __LOG_RECORD_DECLARE__ // #endif // __LOG_RECORD_DECLARE__ } // namespace #endif //__LOG_RECORD__H_ connectome-workbench-1.4.2/src/Common/Logger.cxx000066400000000000000000000227101360521144700216170ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __LOGGER_DECLARE__ #include "Logger.h" #undef __LOGGER_DECLARE__ #include "CaretAssert.h" #include "LogHandler.h" #include "LogManager.h" #include "LogRecord.h" using namespace caret; /** * Constructor. */ Logger::Logger(const AString& name) : CaretObject() { this->name = name; this->setLevel(LogLevelEnum::ALL); } /** * Destructor. */ Logger::~Logger() { for (std::vector::iterator iter = this->logHandlers.begin(); iter != this->logHandlers.end(); iter++) { LogHandler* lh = *iter; delete lh; } } /** * Find or create a logger with the specified name. * If a logger exists with the given name, it is returned. * Otherwise, a new Logger is created and returned. * Never delete the returned Logger as it will be * deleted when the LogManager is deleted. */ Logger* Logger::getLogger(const AString& name) { CaretAssertMessage((name.isEmpty() == false), "Logger name must not be empty string."); Logger* existingLogger = LogManager::getLogManager()->getLogger(name); if (existingLogger != NULL) { return existingLogger; } Logger* logger = new Logger(name); CaretUsedInDebugCompileOnly(bool exists = LogManager::getLogManager()->addLogger(logger)); CaretAssertMessage(exists, "Trying to add logger and logger with name exists."); return logger; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString Logger::toString() const { return ("Logger " + this->name); } /** * Log a message. * * @param logLevel * Logging level for message. The levels OFF and ALL * are not permitted. * @param methodName * Name of method. * @param filename * Name of file that originated the message. * @param lineNumber * Line number of message. * @param text * Text description. * */ void Logger::log(const LogLevelEnum::Enum logLevel, const AString& methodName, const AString& filename, const int32_t lineNumber, const AString& text) { switch (logLevel) { case LogLevelEnum::OFF: case LogLevelEnum::ALL: Logger::log(LogLevelEnum::SEVERE, methodName, filename, lineNumber, "Cannot log record with level = OFF or ALL for: " + text); break; case LogLevelEnum::FINEST: if (this->finestLoggingEnabled == false) return; break; case LogLevelEnum::FINER: if (this->finerLoggingEnabled == false) return; break; case LogLevelEnum::FINE: if (this->fineLoggingEnabled == false) return; break; case LogLevelEnum::CONFIG: if (this->configLoggingEnabled == false) return; break; case LogLevelEnum::INFO: if (this->infoLoggingEnabled == false) return; break; case LogLevelEnum::WARNING: if (this->warningLoggingEnabled == false) return; break; case LogLevelEnum::SEVERE: if (this->severeLoggingEnabled == false) return; break; } const LogRecord logRecord(logLevel, methodName, filename, lineNumber, text); /* * Send to all of the handlers. */ for (std::vector::iterator iter = this->logHandlers.begin(); iter != this->logHandlers.end(); iter++) { LogHandler* lh = *iter; lh->publish(logRecord); } } /** * Log throwing of a CaretException derived class. * A log record with the message THROW at the level * FINER is logged. * @param methodName * Name of method. * @param filename * Name of file that originated the message. * @param lineNumber * Line number of message. * */ void Logger::throwingCaretException(const AString& methodName, const AString& filename, const int32_t lineNumber, CaretException& caretException) { Logger::log(LogLevelEnum::FINER, methodName, filename, lineNumber, "THROW " + AString(typeid(caretException).name()) + ": " + caretException.whatString()); } /** * Log a method entry. A log record with * the message ENTRY at the level FINER * is logged. * @param methodName * Name of method. * @param filename * Name of file that originated the message. * @param lineNumber * Line number of message. */ void Logger::entering(const AString& methodName, const AString& filename, const int32_t lineNumber) { Logger::log(LogLevelEnum::FINER, "", filename, lineNumber, "ENTRY: " + methodName); } /** * Log a method return. A log record with * the message RETURN at the level FINER * is logged. * @param methodName * Name of method. * @param filename * Name of file that originated the message. * @param lineNumber * Line number of message. */ void Logger::exiting(const AString& methodName, const AString& filename, const int32_t lineNumber) { Logger::log(LogLevelEnum::FINER, "", filename, lineNumber, "RETURN: " + methodName); } /** * Get the current logging level. * * @return Current logging level. */ LogLevelEnum::Enum Logger::getLevel() const { return this->level; } /** * Set the logging level. * * @param level * New level for logging. */ void Logger::setLevel(const LogLevelEnum::Enum level) { this->level = level; this->severeLoggingEnabled = false; this->warningLoggingEnabled = false; this->infoLoggingEnabled = false; this->configLoggingEnabled = false; this->fineLoggingEnabled = false; this->finerLoggingEnabled = false; this->finestLoggingEnabled = false; /* * Code is a bit verbose but eliminates * fall-through warning from compiler */ switch (this->level) { case LogLevelEnum::OFF: break; case LogLevelEnum::ALL: this->finestLoggingEnabled = true; this->finerLoggingEnabled = true; this->fineLoggingEnabled = true; this->configLoggingEnabled = true; this->infoLoggingEnabled = true; this->warningLoggingEnabled = true; this->severeLoggingEnabled = true; break; case LogLevelEnum::FINEST: this->finestLoggingEnabled = true; this->finerLoggingEnabled = true; this->fineLoggingEnabled = true; this->configLoggingEnabled = true; this->infoLoggingEnabled = true; this->warningLoggingEnabled = true; this->severeLoggingEnabled = true; break; case LogLevelEnum::FINER: this->finerLoggingEnabled = true; this->fineLoggingEnabled = true; this->configLoggingEnabled = true; this->infoLoggingEnabled = true; this->warningLoggingEnabled = true; this->severeLoggingEnabled = true; break; case LogLevelEnum::FINE: this->fineLoggingEnabled = true; this->configLoggingEnabled = true; this->infoLoggingEnabled = true; this->warningLoggingEnabled = true; this->severeLoggingEnabled = true; break; case LogLevelEnum::CONFIG: this->configLoggingEnabled = true; this->infoLoggingEnabled = true; this->warningLoggingEnabled = true; this->severeLoggingEnabled = true; break; case LogLevelEnum::INFO: this->infoLoggingEnabled = true; this->warningLoggingEnabled = true; this->severeLoggingEnabled = true; break; case LogLevelEnum::WARNING: this->warningLoggingEnabled = true; this->severeLoggingEnabled = true; break; case LogLevelEnum::SEVERE: this->severeLoggingEnabled = true; break; } } /** * Add a log handler to a logger. This object * will take care deleting the handlers that * it uses. * * @param logHandler * Handler that is added. */ void Logger::addLogHandler(LogHandler* logHandler) { this->logHandlers.push_back(logHandler); } connectome-workbench-1.4.2/src/Common/Logger.h000066400000000000000000000104651360521144700212500ustar00rootroot00000000000000#ifndef __LOGGER_H__ #define __LOGGER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "CaretException.h" #include "LogLevelEnum.h" namespace caret { class LogHandler; /*! * \brief Logs messages. * * Logger logs messages that are sent to registered handlers. * Each logger has an associated level. Only messages with * a level equal to or 'above' the level are forwarded to * handlers. If the message is to be forwarded, a LogRecord * is created and then forwarded to the registered handlers. * This class emulates the Java class java.util.logging. */ class Logger : public CaretObject { public: virtual ~Logger(); static Logger* getLogger(const AString& name); void log(const LogLevelEnum::Enum logLevel, const AString& methodName, const AString& filename, const int32_t lineNumber, const AString& text); void entering(const AString& methodName, const AString& filename, const int32_t lineNumber); void exiting(const AString& methodName, const AString& filename, const int32_t lineNumber); void throwingCaretException(const AString& methodName, const AString& filename, const int32_t lineNumber, CaretException& caretException); LogLevelEnum::Enum getLevel() const; void setLevel(const LogLevelEnum::Enum level); void addLogHandler(LogHandler* logHandler); /** @return Is severe logging enabled? */ inline bool isSevere() const { return this->severeLoggingEnabled; } /** @return Is warning logging enabled? */ inline bool isWarning() const { return this->warningLoggingEnabled; } /** @return Is info logging enabled? */ inline bool isInfo() const { return this->infoLoggingEnabled; } /** @return Is config logging enabled? */ inline bool isConfig() const { return this->configLoggingEnabled; } /** @return Is fine logging enabled? */ inline bool isFine() const { return this->fineLoggingEnabled; } /** @return Is finer logging enabled? */ inline bool isFiner() const { return this->finerLoggingEnabled; } /** @return Is finest logging enabled? */ inline bool isFinest() const { return this->finestLoggingEnabled; } /** @return Name of this logger. */ AString getName() const { return this->name; } private: Logger(const AString& name); Logger(const Logger&); Logger& operator=(const Logger&); AString name; bool severeLoggingEnabled; bool warningLoggingEnabled; bool infoLoggingEnabled; bool configLoggingEnabled; bool fineLoggingEnabled; bool finerLoggingEnabled; bool finestLoggingEnabled; LogLevelEnum::Enum level; std::vector logHandlers; public: virtual AString toString() const; private: }; #ifdef __LOGGER_DECLARE__ #endif // __LOGGER_DECLARE__ } // namespace #endif //__LOGGER_H__ connectome-workbench-1.4.2/src/Common/MathFunctionEnum.cxx000066400000000000000000000171551360521144700236330ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __MATH_FUNCTION_ENUM_DECLARE__ #include "MathFunctionEnum.h" #undef __MATH_FUNCTION_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * Constructor. * * @param enumValue * An enumerated value. * @param integerCode * Integer code for this enumerated value. * * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ MathFunctionEnum::MathFunctionEnum(const Enum enumValue, const AString& name, const AString& explanation) { this->enumValue = enumValue; this->name = name; this->explanation = explanation; } /** * Destructor. */ MathFunctionEnum::~MathFunctionEnum() { } /** * Initialize the enumerated metadata. */ void MathFunctionEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(MathFunctionEnum(SIN, "sin", "1 argument, the sine of the argument (units are radians)")); enumData.push_back(MathFunctionEnum(COS, "cos", "1 argument, the cosine of the argument (units are radians)")); enumData.push_back(MathFunctionEnum(TAN, "tan", "1 argument, the tangent of the argument (units are radians)")); enumData.push_back(MathFunctionEnum(ASIN, "asin", "1 argument, the inverse of sine of the argument, in radians")); enumData.push_back(MathFunctionEnum(ACOS, "acos", "1 argument, the inverse of cosine of the argument, in radians")); enumData.push_back(MathFunctionEnum(ATAN, "atan", "1 argument, the inverse of tangent of the argument, in radians")); enumData.push_back(MathFunctionEnum(ATAN2, "atan2", "2 arguments, atan2(y, x) returns the inverse of tangent of (y/x), in radians, determining quadrant by the sign of both arguments")); enumData.push_back(MathFunctionEnum(SINH, "sinh", "1 argument, the hyperbolic sine of the argument")); enumData.push_back(MathFunctionEnum(COSH, "cosh", "1 argument, the hyperbolic cosine of the argument")); enumData.push_back(MathFunctionEnum(TANH, "tanh", "1 argument, the hyperboloc tangent of the argument")); enumData.push_back(MathFunctionEnum(ASINH, "asinh", "1 argument, the inverse hyperbolic sine of the argument")); enumData.push_back(MathFunctionEnum(ACOSH, "acosh", "1 argument, the inverse hyperbolic cosine of the argument")); enumData.push_back(MathFunctionEnum(ATANH, "atanh", "1 argument, the inverse hyperboloc tangent of the argument")); enumData.push_back(MathFunctionEnum(LN, "ln", "1 argument, the natural logarithm of the argument")); enumData.push_back(MathFunctionEnum(EXP, "exp", "1 argument, the constant e raised to the power of the argument")); enumData.push_back(MathFunctionEnum(LOG, "log", "1 argument, the base 10 logarithm of the argument")); enumData.push_back(MathFunctionEnum(LOG2, "log2", "1 argument, the base 2 logarithm of the argument")); enumData.push_back(MathFunctionEnum(SQRT, "sqrt", "1 argument, the square root of the argument")); enumData.push_back(MathFunctionEnum(ABS, "abs", "1 argument, the absolute value of the argument")); enumData.push_back(MathFunctionEnum(FLOOR, "floor", "1 argument, the largest integer not greater than the argument")); enumData.push_back(MathFunctionEnum(ROUND, "round", "1 argument, the nearest integer, with ties rounded away from zero")); enumData.push_back(MathFunctionEnum(CEIL, "ceil", "1 argument, the smallest integer not less than the argument")); enumData.push_back(MathFunctionEnum(MIN, "min", "2 arguments, min(x, y) returns y if (x > y), x otherwise")); enumData.push_back(MathFunctionEnum(MAX, "max", "2 arguments, max(x, y) returns y if (x < y), x otherwise")); enumData.push_back(MathFunctionEnum(MOD, "mod", "2 arguments, mod(x, y) = x - y * floor(x / y), or 0 if y == 0")); enumData.push_back(MathFunctionEnum(CLAMP, "clamp", "3 arguments, clamp(x, low, high) = min(max(x, low), high)")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const MathFunctionEnum* MathFunctionEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const MathFunctionEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString MathFunctionEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const MathFunctionEnum* enumInstance = findData(enumValue); if (enumInstance == NULL) return ""; return enumInstance->name; } /** * Get a string explaining the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString MathFunctionEnum::toExplanation(Enum enumValue) { if (initializedFlag == false) initialize(); const MathFunctionEnum* enumInstance = findData(enumValue); if (enumInstance == NULL) return ""; return enumInstance->explanation; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ MathFunctionEnum::Enum MathFunctionEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = INVALID; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const MathFunctionEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type MathFunctionEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values * except ALL. */ void MathFunctionEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } connectome-workbench-1.4.2/src/Common/MathFunctionEnum.h000066400000000000000000000056231360521144700232550ustar00rootroot00000000000000#ifndef __MATH_FUNCTION_ENUM__H_ #define __MATH_FUNCTION_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { /** * \brief Enumerated type for a structure in a brain. * * Enumerated types for math functions. */ class MathFunctionEnum { public: /** * Enumerated values. */ enum Enum { INVALID, SIN, COS, TAN, ASIN, ACOS, ATAN, ATAN2, SINH, COSH, TANH, ASINH, ACOSH, ATANH, LN, EXP, LOG, LOG2, SQRT, ABS, FLOOR, ROUND, CEIL, MIN, MAX, MOD, CLAMP }; ~MathFunctionEnum(); static AString toName(Enum enumValue); static AString toExplanation(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static void getAllEnums(std::vector& allEnums); private: MathFunctionEnum(const Enum enumValue, const AString& name, const AString& explanation); static const MathFunctionEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** The enumerated type value for an instance */ Enum enumValue; /** The name, a text string that is identical to the enumerated value */ AString name; /** An explanation of the function */ AString explanation; }; #ifdef __MATH_FUNCTION_ENUM_DECLARE__ std::vector MathFunctionEnum::enumData; bool MathFunctionEnum::initializedFlag = false; #endif // __MATH_FUNCTION_ENUM_DECLARE__ } // namespace #endif //__MATH_FUNCTION_ENUM__H_ connectome-workbench-1.4.2/src/Common/MathFunctions.cxx000066400000000000000000002245641360521144700231750ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkBase64Utilities.h,v $ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include #include #include "MathFunctions.h" #include "CaretAssert.h" #include "CaretLogger.h" using namespace caret; using namespace std; MathFunctions::MathFunctions() : CaretObject() { } /** * Destructor */ MathFunctions::~MathFunctions() { } /** * Calulate the number of combinations for choosing "k" elements * from a total of "n" elements. * * Formula: [n!/(k!*(n-k!)) * If k > (n-k): [n(n-1)(n-2)...(k+1)] / (n-k)! * If k < (n-k): [n(n-1)(n-2)...(n-k+1)] / k! * * @param n - total number of elements. * @param k - number of elements to choose. * @return - number of combinations. * */ int64_t MathFunctions::combinations( const int64_t n, const int64_t k) { int64_t denominator = 1; int64_t nmk = n - k; int64_t iStart = 1; if (k > nmk) { iStart = k + 1; denominator = MathFunctions::factorial(nmk); } else { iStart = nmk + 1; denominator = MathFunctions::factorial(k); } int64_t numerator = 1; for (int64_t i = iStart; i <= n; i++) { numerator *= i; } int64_t numCombosLong = numerator / denominator; int64_t numCombos = (int)numCombosLong; return numCombos; } /** * Calulate the number of permuations for choosing "k" elements * from a total of "n" elements. * * Formula: [n!/(n-m)!] = n(n-1)(n-2)...(n-m+1). * * @param n - total number of elements. * @param k - number of elements to choose. * @return - number of combinations. * */ int64_t MathFunctions::permutations( const int64_t n, const int64_t k) { int64_t iStart = n - k + 1; int numPerms = 1; for (int i = iStart; i <= n; i++) { numPerms *= i; } return numPerms; } /** * Calculate the factorial for a number. * * @param n - the number. * @return - its factiorial * */ int64_t MathFunctions::factorial(const int64_t n) { int64_t num = 1; for (int64_t i = 1; i <= n; i++) { num *= i; } return num; } /** * Compute a normal vector from three vertices and make it a unit vector. * * @param v1 the first vertex, an array of three floats. * @param v2 the first vertex, an array of three floats. * @param v3 the first vertex, an array of three floats. * @param normalVectorOut A three-dimensional array passed into which * the normal vector is loaded. * @return true if vector is valid (non-zero length). * */ bool MathFunctions::normalVector( const float v1[3], const float v2[3], const float v3[3], float normalVectorOut[3]) { /* * DOUBLE PRECISION is needed when points are a small or sliver triangle. */ double a0 = v3[0] - v2[0]; double a1 = v3[1] - v2[1]; double a2 = v3[2] - v2[2]; double b0 = v1[0] - v2[0]; double b1 = v1[1] - v2[1]; double b2 = v1[2] - v2[2]; double nv0 = (a1 * b2 - a2 * b1); double nv1 = (a2 * b0 - a0 * b2); double nv2 = (a0 * b1 - a1 * b0); double length = std::sqrt(nv0*nv0 + nv1*nv1 + nv2*nv2); bool valid = false; if (length != 0.0) { nv0 /= length; nv1 /= length; nv2 /= length; valid = true; } normalVectorOut[0] = (float)nv0; normalVectorOut[1] = (float)nv1; normalVectorOut[2] = (float)nv2; return valid; } /** * Compute a normal vector from three vertices and make it a unit vector. * * @param v1 the first vertex, an array of three floats. * @param v2 the first vertex, an array of three floats. * @param v3 the first vertex, an array of three floats. * @param normalVectorOut A three-dimensional array passed into which * the normal vector is loaded. * @return true if vector is valid (non-zero length). * */ bool MathFunctions::normalVector( const double v1[3], const double v2[3], const double v3[3], double normalVectorOut[3]) { double a0 = v3[0] - v2[0]; double a1 = v3[1] - v2[1]; double a2 = v3[2] - v2[2]; double b0 = v1[0] - v2[0]; double b1 = v1[1] - v2[1]; double b2 = v1[2] - v2[2]; double nv0 = (a1 * b2 - a2 * b1); double nv1 = (a2 * b0 - a0 * b2); double nv2 = (a0 * b1 - a1 * b0); double length = std::sqrt(nv0*nv0 + nv1*nv1 + nv2*nv2); bool valid = false; if (length != 0.0) { nv0 /= length; nv1 /= length; nv2 /= length; valid = true; } normalVectorOut[0] = nv0; normalVectorOut[1] = nv1; normalVectorOut[2] = nv2; return valid; } /** * Compute a normal vector from three vertices and but the returned * vector IS NOT a unit vector. * * @param v1 the first vertex, an array of three floats. * @param v2 the first vertex, an array of three floats. * @param v3 the first vertex, an array of three floats. * @return The normal vector, an array of three floats. * */ void MathFunctions::normalVectorDirection( const float v1[3], const float v2[3], const float v3[3], float directionOut[3]) { float a[] = { v3[0] - v2[0], v3[1] - v2[1], v3[2] - v2[2] }; float b[] = { v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2] }; directionOut[0] = (a[1] * b[2] - a[2] * b[1]); directionOut[1] = (a[2] * b[0] - a[0] * b[2]); directionOut[2] = (a[0] * b[1] - a[1] * b[0]); } /** * Cross product of two 3D vectors. * @param v1 The first vector, an array of three floats. * @param v2 The first vector, an array of three floats. * @param resultOut Output containing the cross product. * */ void MathFunctions::crossProduct( const float v1[], const float v2[], float resultOut[]) { resultOut[0] = v1[1] * v2[2] - v1[2] * v2[1]; resultOut[1] = v1[2] * v2[0] - v1[0] * v2[2]; resultOut[2] = v1[0] * v2[1] - v1[1] * v2[0]; } /** * Cross product of two 3D vectors. * @param v1 The first vector, an array of three floats. * @param v2 The first vector, an array of three floats. * @param resultOut Output containing the cross product. * */ void MathFunctions::crossProduct( const double v1[], const double v2[], double resultOut[]) { resultOut[0] = v1[1] * v2[2] - v1[2] * v2[1]; resultOut[1] = v1[2] * v2[0] - v1[0] * v2[2]; resultOut[2] = v1[0] * v2[1] - v1[1] * v2[0]; } /** * Cross product of two 3D vectors with normalizing both the * input and output vectors. * * @param x1 The first vector, an array of three floats. * @param x2 The first vector, an array of three floats. * @return The cross product, an array of three floats. * */ void MathFunctions::normalizedCrossProduct( const float x1[], const float x2[], float resultOut[]) { float v1[3] = { x1[0], x1[1], x1[2] }; MathFunctions::normalizeVector(v1); float v2[3] = { x2[0], x2[1], x2[2] }; MathFunctions::normalizeVector(v2); MathFunctions::crossProduct(v1, v2, resultOut); MathFunctions::normalizeVector(resultOut); } /** * Normalize a 3D vector (make its length 1.0). * * @param vectorsAll Array containing the XYZ components * of the vectors. * @param offset Offset of the vector's X-component in the * vectorsAll array. * @return The length of the vector prior to normalization. * */ float MathFunctions::normalizeVector( float vectorsAll[], const int32_t offset) { float len = MathFunctions::vectorLength(vectorsAll, offset); if (len != 0.0) { vectorsAll[offset] /= len; vectorsAll[offset+1] /= len; vectorsAll[offset+2] /= len; } return len; } /** * Normalize a 3D vector (make its length 1.0). * * @param vectorInOut vector that is normalized. * @return The length of the vector prior to normalization. * */ float MathFunctions::normalizeVector(float vector[3]) { float len = vectorLength(vector); if (len != 0.0) { vector[0] /= len; vector[1] /= len; vector[2] /= len; } return len; } /** * Normalize a 3D vector (make its length 1.0). * * @param vectorInOut vector that is normalized. * @return The length of the vector prior to normalization. * */ double MathFunctions::normalizeVector(double vector[3]) { double len = vectorLength(vector); if (len != 0.0) { vector[0] /= len; vector[1] /= len; vector[2] /= len; } return len; } /** * Get length of vector. * * @param vector Vector whose length is computed. * * @return The length of the vector. * */ float MathFunctions::vectorLength(const float vector[3]) { float len = (float)std::sqrt(vector[0]*vector[0] + vector[1]*vector[1] + vector[2]*vector[2]); return len; } /** * Get length of vector. * * @param vectorsAll Array containing three-dimensional vectors. * @param offset Offset of vector's X-component in vectorsAll array. * * @return The length of the vector. * */ float MathFunctions::vectorLength( const float vectorsAll[], const int32_t offset) { float len = (float)std::sqrt(vectorsAll[offset]*vectorsAll[offset] + vectorsAll[offset+1]*vectorsAll[offset+1] + vectorsAll[offset+2]*vectorsAll[offset+2]); return len; } /** * Get length of vector. * * @param vector Vector whose length is computed. * * @return The length of the vector. * */ double MathFunctions::vectorLength(const double vector[3]) { double len = std::sqrt(vector[0]*vector[0] + vector[1]*vector[1] + vector[2]*vector[2]); return len; } /** * Get the squared distance between two 3D points. * * @param p1 Point 1 (3 element array) * @param p2 Point 2 (3 element array) * @return Distance squared between the two points. * */ float MathFunctions::distanceSquared3D( const float p1[3], const float p2[3]) { float dx = p1[0] - p2[0]; float dy = p1[1] - p2[1]; float dz = p1[2] - p2[2]; float distSQ = dx*dx + dy*dy + dz*dz; return distSQ; } /** * Get the squared distance between two 3D coordinates. * * @param xyzAll Array containing all of the XYZ coordinates. * @param offsetCoord1 Offset of the first coordinates X-coordinate. * @param offsetCoord2 Offset of the second coordinates X-coordinate. * @return Distance squared between the two coordinates. * */ float MathFunctions::distanceSquared3D( const float xyzAll[], const int32_t offsetCoord1, const int32_t offsetCoord2) { float dx = xyzAll[offsetCoord1] - xyzAll[offsetCoord2]; float dy = xyzAll[offsetCoord1+1] - xyzAll[offsetCoord2+1]; float dz = xyzAll[offsetCoord1+2] - xyzAll[offsetCoord2+2]; float distSQ = dx*dx + dy*dy + dz*dz; return distSQ; } /** * Get the distance between two 3D points. * * @param p1 Point 1 (3 element array) * @param p2 Point 2 (3 element array) * @return Distance between the two points. * */ float MathFunctions::distance3D( const float p1[3], const float p2[3]) { float dist = distanceSquared3D(p1, p2); if (dist != 0.0f) { dist = (float)std::sqrt(dist); } return dist; } /** * Get the squared distance between two 3D points. * * @param p1 Point 1 (3 element array) * @param p2 Point 2 (3 element array) * @return Distance squared between the two points. * */ double MathFunctions::distanceSquared3D( const double p1[3], const double p2[3]) { double dx = p1[0] - p2[0]; double dy = p1[1] - p2[1]; double dz = p1[2] - p2[2]; double distSQ = dx*dx + dy*dy + dz*dz; return distSQ; // double dist = distanceSquared3D(p1, p2); // if (dist != 0.0f) { // dist = std::sqrt(dist); // } // return dist; } /** * Get the distance between two 3D points. * * @param p1 Point 1 (3 element array) * @param p2 Point 2 (3 element array) * @return Distance between the two points. * */ double MathFunctions::distance3D( const double p1[3], const double p2[3]) { double dist = distanceSquared3D(p1, p2); if (dist != 0.0f) { dist = std::sqrt(dist); } return dist; } /** * subtract vectors (3d) result = v1 - v2. * @param v1 1st vector input * @param v2 2nd vector input * @return 3D vector containing result of subtraction. * */ void MathFunctions::subtractVectors( const float v1[3], const float v2[3], float resultOut[3]) { resultOut[0] = v1[0] - v2[0]; resultOut[1] = v1[1] - v2[1]; resultOut[2] = v1[2] - v2[2]; } /** * subtract vectors (3d) result = v1 - v2. * @param v1 1st vector input * @param v2 2nd vector input * @return 3D vector containing result of subtraction. * */ void MathFunctions::subtractVectors(const double v1[3], const double v2[3], double resultOut[3]) { resultOut[0] = v1[0] - v2[0]; resultOut[1] = v1[1] - v2[1]; resultOut[2] = v1[2] - v2[2]; } void MathFunctions::addVectors(const float v1[3], const float v2[3], float resultOut[3]) { resultOut[0] = v1[0] + v2[0]; resultOut[1] = v1[1] + v2[1]; resultOut[2] = v1[2] + v2[2]; } /** * Create the unit vector for a vector that starts at startXYZ and * ends at endXYZ. * * @param startXYZ - Starting position of vector. * @param endXYZ - Ending position of vector. * @param Unit vector starting at startXYZ and pointing to endXYZ. * */ void MathFunctions::createUnitVector( const float startXYZ[3], const float endXYZ[3], float resultOut[3]) { resultOut[0] = endXYZ[0] - startXYZ[0]; resultOut[1] = endXYZ[1] - startXYZ[1]; resultOut[2] = endXYZ[2] - startXYZ[2]; MathFunctions::normalizeVector(resultOut); } /** * Create the unit vector for a vector that starts at startXYZ and * ends at endXYZ. * * @param startXYZ - Starting position of vector. * @param endXYZ - Ending position of vector. * @param Unit vector starting at startXYZ and pointing to endXYZ. * */ void MathFunctions::createUnitVector( const double startXYZ[3], const double endXYZ[3], double resultOut[3]) { resultOut[0] = endXYZ[0] - startXYZ[0]; resultOut[1] = endXYZ[1] - startXYZ[1]; resultOut[2] = endXYZ[2] - startXYZ[2]; MathFunctions::normalizeVector(resultOut); } /** * Dot produce of three dimensional vectors. * @param p1 vector 1 * @param p2 vector 2 * @return Dot product of the two vectors. * */ float MathFunctions::dotProduct( const float p1[3], const float p2[3]) { float dot = p1[0]*p2[0] + p1[1]*p2[1] + p1[2]*p2[2]; return dot; } /** * Dot produce of three dimensional vectors. * @param p1 vector 1 * @param p2 vector 2 * @return Dot product of the two vectors. * */ double MathFunctions::dotProduct( const double p1[3], const double p2[3]) { return p1[0]*p2[0] + p1[1]*p2[1] + p1[2]*p2[2]; } /** * Add an offset to a vector * * @param v * The vector * @param offset * Offset added to the vector. */ void MathFunctions::addOffsetToVector(double v[3], const double offset[3]) { v[0] += offset[0]; v[1] += offset[1]; v[2] += offset[2]; } /** * Subtract an offset from a vector * * @param v * The vector * @param offset * Offset subtracted from the vector. */ void MathFunctions::subtractOffsetFromVector(double v[3], const double offset[3]) { v[0] -= offset[0]; v[1] -= offset[1]; v[2] -= offset[2]; } /** * Calculate the area for a triangle. * @param v1 - XYZ coordinates for vertex 1 * @param v2 - XYZ coordinates for vertex 2 * @param v3 - XYZ coordinates for vertex 3 * * @return Area of triangle. * */ float MathFunctions::triangleArea( const float v1[3], const float v2[3], const float v3[3]) { /* * Using doubles for the intermediate calculations * produces results different from that if floats * were used in the "area" equation. I'm * assuming double is more accurate (JWH). */ double a = MathFunctions::distanceSquared3D(v1,v2); double b = MathFunctions::distanceSquared3D(v2,v3); double c = MathFunctions::distanceSquared3D(v3,v1); float area = (float)(0.25f* std::sqrt(std::abs(4.0*a*c - (a-b+c)*(a-b+c)))); return area; } /** * Calculate the area for a triangle (with doubles) * @param v1 - XYZ coordinates for vertex 1 * @param v2 - XYZ coordinates for vertex 2 * @param v3 - XYZ coordinates for vertex 3 * * @return Area of triangle. * */ float MathFunctions::triangleArea(const double v1[3], const double v2[3], const double v3[3]) { /* * Using doubles for the intermediate calculations * produces results different from that if floats * were used in the "area" equation. I'm * assuming double is more accurate (JWH). */ double a = MathFunctions::distanceSquared3D(v1,v2); double b = MathFunctions::distanceSquared3D(v2,v3); double c = MathFunctions::distanceSquared3D(v3,v1); float area = (float)(0.25f* std::sqrt(std::abs(4.0*a*c - (a-b+c)*(a-b+c)))); return area; } /** * Calculate the area of a triangle formed by 3 coordinates. * @param xyzAll One-dimensional array containing the XYZ coordinates. * @param offsetCoord1 Offset of node 1's X-coordinate which is * followed by the Y- and Z-coordinates. * @param offsetCoord2 Offset of node 2's X-coordinate which is * followed by the Y- and Z-coordinates. * @param offsetCoord3 Offset of node 3's X-coordinate which is * followed by the Y- and Z-coordinates. * @return Area of the triangle formed by the coordinates. * */ float MathFunctions::triangleArea( const float xyzAll[], const int32_t offsetCoord1, const int32_t offsetCoord2, const int32_t offsetCoord3) { /* * Using doubles for the intermediate calculations * produces results different from that if floats * were used in the "area" equation. I'm * assuming double is more accurate (JWH). */ double a = MathFunctions::distanceSquared3D(xyzAll, offsetCoord1, offsetCoord2); double b = MathFunctions::distanceSquared3D(xyzAll, offsetCoord2, offsetCoord3); double c = MathFunctions::distanceSquared3D(xyzAll, offsetCoord3, offsetCoord1); float area = (float)(0.25f* std::sqrt(std::abs(4.0*a*c - (a-b+c)*(a-b+c)))); return area; } /** * Compute the signed area of a triangle in 2D. * @param p1 - 1st coordinate of triangle * @param p2 - 2nd coordinate of triangle * @param p3 - 3rd coordinate of triangle * @return Signed area of triangle which is positive if the vertices * are in counter-clockwise orientation or negative if the vertices * are in clockwise orientation. * */ float MathFunctions::triangleAreaSigned2D( const float p1[2], const float p2[2], const float p3[2]) { /* * Prior to 07 Dec 2017, this area calculation was performed * using floats. However, when a triangle edge was very small, * the area calculation was incorrect (did not match the area * produced by triangleAreaSigned3D() and often with the incorrect * sign). Using double precision values corrects the problem. * * When calculated as floats in this equation, changing the order * even affected the area calculation: * * float area = ( p1[0]*p2[1] + p2[0]*p3[1] + p3[0]*p1[1] * - p1[1]*p2[0] - p2[1]*p3[0] - p3[1]*p1[0] ) * 0.5f; */ const double x1 = p1[0]; const double y1 = p1[1]; const double x2 = p2[0]; const double y2 = p2[1]; const double x3 = p3[0]; const double y3 = p3[1]; const double area = ( x1*y2 + x2*y3 + x3*y1 - y1*x2 - y2*x3 - y3*x1) * 0.5; return area; } /** * Compute the signed area of a triangle in 3D. * @param referenceNormal - Normal vector. * @param p1 - 1st coordinate of triangle * @param p2 - 2nd coordinate of triangle * @param p3 - 3rd coordinate of triangle * @return Signed area of triangle which is positive if the vertices * are in counter-clockwise orientation or negative if the vertices * are in clockwise orientation. * */ float MathFunctions::triangleAreaSigned3D( const float referenceNormal[3], const float p1[3], const float p2[3], const float p3[3]) { // // Area of the triangle formed by the three points // float area = triangleArea(p1, p2, p3); // // Normal for the three points // float triangleNormal[3]; MathFunctions::normalVector(p1, p2, p3, triangleNormal); // // Dot Product is the cosine of the angle between the two normals. When this value is less // than zero, the absolute angle between the normals is greater than 90 degrees. // float dot = MathFunctions::dotProduct(referenceNormal, triangleNormal); if (dot < 0.0) { area = -area; } return area; } /** * this method solves Ay = x for y. * From vtkMath. * * @param A * 3x3 matrix. * @param x * Input vector. * @param y * Output vector. */ void MathFunctions::vtkLinearSolve3x3( const float A[3][3], const float x[3], float y[3]) { int index[3]; float B[3][3]; for (int i = 0; i < 3; i++) { B[i][0] = A[i][0]; B[i][1] = A[i][1]; B[i][2] = A[i][2]; y[i] = x[i]; } vtkLUFactor3x3(B,index); vtkLUSolve3x3(B,index,y); } /** * Backsubstitution with an LU-decomposed matrix. * From vtkMath. * * @param A * 3x3 matrix. * @param index * * @param x * Output vector. */ void MathFunctions::vtkLUSolve3x3( const float A[3][3], const int32_t index[3], float x[3]) { float sum; // forward substitution sum = x[index[0]]; x[index[0]] = x[0]; x[0] = sum; sum = x[index[1]]; x[index[1]] = x[1]; x[1] = sum - A[1][0]*x[0]; sum = x[index[2]]; x[index[2]] = x[2]; x[2] = sum - A[2][0]*x[0] - A[2][1]*x[1]; // back substitution x[2] = x[2]*A[2][2]; x[1] = (x[1] - A[1][2]*x[2])*A[1][1]; x[0] = (x[0] - A[0][1]*x[1] - A[0][2]*x[2])*A[0][0]; } /** * Unrolled LU factorization of a 3x3 matrix with pivoting. * From vtkMath. * * @param A * 3x3 matrix. * @param index * */ void MathFunctions::vtkLUFactor3x3( float A[3][3], int32_t index[3]) { int i,maxI; float tmp,largest; float scale[3]; // Loop over rows to get implicit scaling information for ( i = 0; i < 3; i++ ) { largest = std::abs(A[i][0]); if ((tmp = std::abs(A[i][1])) > largest) { largest = tmp; } if ((tmp = std::abs(A[i][2])) > largest) { largest = tmp; } scale[i] = (1.0f)/largest; } // Loop over all columns using Crout's method // first column largest = scale[0]*std::abs(A[0][0]); maxI = 0; if ((tmp = scale[1]*std::abs(A[1][0])) >= largest) { largest = tmp; maxI = 1; } if ((tmp = scale[2]*std::abs(A[2][0])) >= largest) { maxI = 2; } if (maxI != 0) { //vtkSwapVectors3(A[maxI],A[0]); float tmpSwap[3] = { A[maxI][0], A[maxI][1], A[maxI][2] }; A[maxI][0] = A[0][0]; A[maxI][1] = A[0][1]; A[maxI][2] = A[0][2]; A[0][0] = tmpSwap[0]; A[0][1] = tmpSwap[1]; A[0][2] = tmpSwap[2]; scale[maxI] = scale[0]; } index[0] = maxI; A[0][0] = (1.0f)/A[0][0]; A[1][0] *= A[0][0]; A[2][0] *= A[0][0]; // second column A[1][1] -= A[1][0]*A[0][1]; A[2][1] -= A[2][0]*A[0][1]; largest = scale[1]*std::abs(A[1][1]); maxI = 1; if ((tmp = scale[2]*std::abs(A[2][1])) >= largest) { maxI = 2; //vtkSwapVectors3(A[2],A[1]); float tmpSwap[3] = { A[2][0], A[2][1], A[2][2] }; A[2][0] = A[1][0]; A[2][1] = A[1][1]; A[2][2] = A[1][2]; A[1][0] = tmpSwap[0]; A[1][1] = tmpSwap[1]; A[1][2] = tmpSwap[2]; scale[2] = scale[1]; } index[1] = maxI; A[1][1] = (1.0f)/A[1][1]; A[2][1] *= A[1][1]; // third column A[1][2] -= A[1][0]*A[0][2]; A[2][2] -= A[2][0]*A[0][2] + A[2][1]*A[1][2]; //largest = scale[2]*std::abs(A[2][2]); index[2] = 2; A[2][2] = (1.0f)/A[2][2]; } /** * 2x2 Determinant. * From vtkMath. * * @param a * element top left. * @param b * element top right. * @param c * element bottom left. * @param d * element bottom right. * @return * The determinant. */ double MathFunctions::vtkDeterminant2x2(double a, double b, double c, double d) { return (a * d - b * c); } /** * Invert 3x3 Matrix. * From vtkMath. * * @param A * Input 3x3 matrix. * @param AI * Output 3x3 matrix. */ void MathFunctions::vtkInvert3x3(const double A[3][3], double AI[3][3]) { double a1 = A[0][0]; double b1 = A[0][1]; double c1 = A[0][2]; double a2 = A[1][0]; double b2 = A[1][1]; double c2 = A[1][2]; double a3 = A[2][0]; double b3 = A[2][1]; double c3 = A[2][2]; // Compute the adjoint double d1 = vtkDeterminant2x2( b2, b3, c2, c3); double d2 = - vtkDeterminant2x2( a2, a3, c2, c3); double d3 = vtkDeterminant2x2( a2, a3, b2, b3); double e1 = - vtkDeterminant2x2( b1, b3, c1, c3); double e2 = vtkDeterminant2x2( a1, a3, c1, c3); double e3 = - vtkDeterminant2x2( a1, a3, b1, b3); double f1 = vtkDeterminant2x2( b1, b2, c1, c2); double f2 = - vtkDeterminant2x2( a1, a2, c1, c2); double f3 = vtkDeterminant2x2( a1, a2, b1, b2); // Divide by the determinant double det = a1*d1 + b1*d2 + c1*d3; AI[0][0] = d1/det; AI[1][0] = d2/det; AI[2][0] = d3/det; AI[0][1] = e1/det; AI[1][1] = e2/det; AI[2][1] = e3/det; AI[0][2] = f1/det; AI[1][2] = f2/det; AI[2][2] = f3/det; } /** * Multipley 3x3 matrices C = A * B. * From vtkMath. * * @param A * 3x3 matrix. * @param B * 3x3 matrix. * @param C * Output 3x3 matrix. */ void MathFunctions::vtkMultiply3x3(const double A[3][3], const double B[3][3], double C[3][3]) { double D[3][3]; for (int i = 0; i < 3; i++) { D[0][i] = A[0][0]*B[0][i] + A[0][1]*B[1][i] + A[0][2]*B[2][i]; D[1][i] = A[1][0]*B[0][i] + A[1][1]*B[1][i] + A[1][2]*B[2][i]; D[2][i] = A[2][0]*B[0][i] + A[2][1]*B[1][i] + A[2][2]*B[2][i]; } for (int j = 0; j < 3; j++) { C[j][0] = D[j][0]; C[j][1] = D[j][1]; C[j][2] = D[j][2]; } } #define VTK_ROTATE(a,i,j,k,l) g=a[i][j];h=a[k][l];a[i][j]=g-s*(h+g*tau);\ a[k][l]=h+s*(g-h*tau) #define VTK_MAX_ROTATIONS 20 //#undef VTK_MAX_ROTATIONS //#define VTK_MAX_ROTATIONS 50 // Jacobi iteration for the solution of eigenvectors/eigenvalues of a nxn // real symmetric matrix. Square nxn matrix a; size of matrix in n; // output eigenvalues in w; and output eigenvectors in v. Resulting // eigenvalues/vectors are sorted in decreasing order; eigenvectors are // normalized. int MathFunctions::vtkJacobiN(double **a, int n, double *w, double **v) { int i, j, k, iq, ip, numPos; double tresh, theta, tau, t, sm, s, h, g, c, tmp; double bspace[4], zspace[4]; double *b = bspace; double *z = zspace; // only allocate memory if the matrix is large if (n > 4) { b = new double[n]; z = new double[n]; } // initialize for (ip=0; ip 3 && (fabs(w[ip])+g) == fabs(w[ip]) && (fabs(w[iq])+g) == fabs(w[iq])) { a[ip][iq] = 0.0; } else if (fabs(a[ip][iq]) > tresh) { h = w[iq] - w[ip]; if ( (fabs(h)+g) == fabs(h)) { t = (a[ip][iq]) / h; } else { theta = 0.5*h / (a[ip][iq]); t = 1.0 / (fabs(theta)+sqrt(1.0+theta*theta)); if (theta < 0.0) { t = -t; } } c = 1.0 / sqrt(1+t*t); s = t*c; tau = s/(1.0+c); h = t*a[ip][iq]; z[ip] -= h; z[iq] += h; w[ip] -= h; w[iq] += h; a[ip][iq]=0.0; // ip already shifted left by 1 unit for (j = 0;j <= ip-1;j++) { VTK_ROTATE(a,j,ip,j,iq); } // ip and iq already shifted left by 1 unit for (j = ip+1;j <= iq-1;j++) { VTK_ROTATE(a,ip,j,j,iq); } // iq already shifted left by 1 unit for (j=iq+1; j= VTK_MAX_ROTATIONS ) { CaretLogWarning("vtkMath::Jacobi: Error extracting eigenfunctions"); return 0; } // sort eigenfunctions these changes do not affect accuracy for (j=0; j= tmp) // why exchage if same? { k = i; tmp = w[k]; } } if (k != j) { w[k] = w[j]; w[j] = tmp; for (i=0; i> 1) + (n & 1); for (j=0; j= 0.0 ) { numPos++; } } // if ( numPos < ceil(double(n)/double(2.0)) ) if ( numPos < ceil_half_n) { for(i=0; i 4) { delete [] b; delete [] z; } return 1; } #undef VTK_ROTATE #undef VTK_MAX_ROTATIONS /** * Given a unit vector 'x', find two other unit vectors 'y' and 'z' which * which form an orthonormal set. * From vtkMath. * * @param x * Unit vector. * @param y * Unit vector. * @param z * Unit vector. * @param theta * Angle? */ void MathFunctions::vtkPerpendiculars(const double x[3], double y[3], double z[3], double theta) { int dx,dy,dz; double x2 = x[0]*x[0]; double y2 = x[1]*x[1]; double z2 = x[2]*x[2]; double r = sqrt(x2 + y2 + z2); // transpose the vector to avoid divide-by-zero error if (x2 > y2 && x2 > z2) { dx = 0; dy = 1; dz = 2; } else if (y2 > z2) { dx = 1; dy = 2; dz = 0; } else { dx = 2; dy = 0; dz = 1; } double a = x[dx]/r; double b = x[dy]/r; double c = x[dz]/r; double tmp = sqrt(a*a+c*c); if (theta != 0) { double sintheta = sin(theta); double costheta = cos(theta); if (y) { y[dx] = (c*costheta - a*b*sintheta)/tmp; y[dy] = sintheta*tmp; y[dz] = (-a*costheta - b*c*sintheta)/tmp; } if (z) { z[dx] = (-c*sintheta - a*b*costheta)/tmp; z[dy] = costheta*tmp; z[dz] = (a*sintheta - b*c*costheta)/tmp; } } else { if (y) { y[dx] = c/tmp; y[dy] = 0; y[dz] = -a/tmp; } if (z) { z[dx] = -a*b/tmp; z[dy] = tmp; z[dz] = -b*c/tmp; } } } /** * Determine if 2D line segments intersect. * Algorithm from http://mathworld.wolfram.com/Line-LineIntersection.html * * @param p1 Line 1 end point 1. * @param p2 Line 1 end point 2. * @param q1 Line 2 end point 1. * @param q2 Line 2 end point 2. * @param tolerance Tolerance around the vertices (essentially * lengthens lines by this quantity). Caret5 set this * parameter to 0.01. * @param intersectionOut Location of intersection. * @return true if the line segments intersect else false. * The intersection MUST BE within the range of * each of the line segments. */ bool MathFunctions::lineIntersection2D( const float p1[2], const float p2[2], const float q1[2], const float q2[2], const float tolerance, float intersectionOut[2]) { double tol = tolerance; double x1 = p1[0]; double y1 = p1[1]; double x2 = p2[0]; double y2 = p2[1]; double x3 = q1[0]; double y3 = q1[1]; double x4 = q2[0]; double y4 = q2[1]; double denom = ((x1 - x2) * (y3 - y4)) - ((x3 - x4) * (y1 - y2)); if (denom != 0.0) { double a = (x1 * y2) - (x2 * y1); double c = (x3 * y4) - (x4 * y3); double x = ((a * (x3 - x4)) - (c * (x1 - x2))) / denom; double y = ((a * (y3 - y4)) - (c * (y1 - y2))) / denom; double pxMax = std::max(x1, x2) + tol; double pxMin = std::min(x1, x2) - tol; double pyMax = std::max(y1, y2) + tol; double pyMin = std::min(y1, y2) - tol; double qxMax = std::max(x3, x4) + tol; double qxMin = std::min(x3, x4) - tol; double qyMax = std::max(y3, y4) + tol; double qyMin = std::min(y3, y4) - tol; intersectionOut[0] = (float)x; intersectionOut[1] = (float)y; if ((x >= pxMin) && (x <= pxMax) && (x >= qxMin) && (x <= qxMax) && (y >= pyMin) && (y <= pyMax) && (y >= qyMin) && (y <= qyMax)) { return true; } } return false; } /** * Determine if 2D vectors intersect. * Algorithm from http://mathworld.wolfram.com/Line-LineIntersection.html * * @param p1 Vector 1 end point 1. * @param p2 Vector 1 end point 2. * @param q1 Vector 2 end point 1. * @param q2 Vector 2 end point 2. * @param tolerance Tolerance around the vertices (essentially * lengthens lines by this quantity). Caret5 set this * parameter to 0.01. * @param intersectionOut Location of intersection. * @return true if the vectors intersect. */ bool MathFunctions::vectorIntersection2D( const float p1[2], const float p2[2], const float q1[2], const float q2[2], const float /*tolerance*/, float intersectionOut[2]) { // double tol = tolerance; double x1 = p1[0]; double y1 = p1[1]; double x2 = p2[0]; double y2 = p2[1]; double x3 = q1[0]; double y3 = q1[1]; double x4 = q2[0]; double y4 = q2[1]; double denom = ((x1 - x2) * (y3 - y4)) - ((x3 - x4) * (y1 - y2)); if (denom != 0.0) { double a = (x1 * y2) - (x2 * y1); double c = (x3 * y4) - (x4 * y3); double x = ((a * (x3 - x4)) - (c * (x1 - x2))) / denom; double y = ((a * (y3 - y4)) - (c * (y1 - y2))) / denom; intersectionOut[0] = (float)x; intersectionOut[1] = (float)y; return true; } return false; } /** * Determine if a ray intersects a plane. * @param p1 - 1st point defining the plane * @param p2 - 2nd point defining the plane * @param p3 - 3rd point defining the plane * @param rayOrigin - origin of the ray * @param rayVector - vector defining the ray * @param intersectionXYZandDistance - An array of four that will contain * the XYZ or the intersection point and the distance from the plane. * @return true if the ray intersects the plane, else false. * */ bool MathFunctions::rayIntersectPlane( const float p1[3], const float p2[3], const float p3[3], const float rayOrigin[3], const float rayVector[3], float intersectionXYZandDistance[4]) { // Convert the ray into a unit vector // double ray[3] = { rayVector[0], rayVector[1], rayVector[2] }; MathFunctions::normalizeVector(ray); // // Normal of plane // float normal[3]; MathFunctions::normalVector(p1, p2, p3, normal); // // Compute the plane equation // double A = normal[0]; double B = normal[1]; double C = normal[2]; double D = -(A*p1[0] + B*p1[1] + C*p1[2]); // // Parametric coordinate of where ray intersects plane // double denom = A * ray[0] + B * ray[1] + C * ray[2]; if (denom != 0) { const double t = -(A * rayOrigin[0] + B * rayOrigin[1] + C * rayOrigin[2] + D) / denom; intersectionXYZandDistance[0] = (float)(rayOrigin[0] + ray[0] * t); intersectionXYZandDistance[1] = (float)(rayOrigin[1] + ray[1] * t); intersectionXYZandDistance[2] = (float)(rayOrigin[2] + ray[2] * t); intersectionXYZandDistance[3] = (float)t; return true; } return false; } /** * Project a point to a plane. * @param pt - the point to project. * @param origin - point in the plane. * @param normal - normal vector of plane. * @return The projected position of "pt" on the plane. * */ void MathFunctions::projectPoint( const float pt[3], const float origin[3], const float normal[3], float projectedPointOut[3]) { float xo[3] = { pt[0] - origin[0], pt[1] - origin[1], pt[2] - origin[2] }; float t = MathFunctions::dotProduct(normal, xo); projectedPointOut[0] = pt[0] - t * normal[0]; projectedPointOut[1] = pt[1] - t * normal[1]; projectedPointOut[2] = pt[2] - t * normal[2]; } /** * Get the signed distance from the plane to the "queryPoint". * A positive distance indicates "queryPoint" is above the plane * and a negative distance indicates "queryPoint" is below * the plane. * * @param planeNormal - plane's normal vector. * @param pointInPlane - point on the plane. * @param queryPoint - the query point for which distance to plane is sought. * * @return Distance from the plane to the query point. * */ float MathFunctions::signedDistanceFromPlane( const float planeNormal[3], const float pointInPlane[3], const float queryPoint[3]) { // Find out where query point projects on the plane // float queryPointProjectedOntoPlane[3]; MathFunctions::projectPoint(queryPoint, pointInPlane, planeNormal, queryPointProjectedOntoPlane); float dx = planeNormal[0] * (queryPoint[0] - queryPointProjectedOntoPlane[0]); float dy = planeNormal[1] * (queryPoint[1] - queryPointProjectedOntoPlane[1]); float dz = planeNormal[2] * (queryPoint[2] - queryPointProjectedOntoPlane[2]); float dist = dx + dy + dz; return dist; } /** * Limit the "value" to be inclusively between the minimum and maximum. * @param value - Value for testing. * @param minimumValue - Minimum inclusive value. * @param maximumValue - Maximum inclusive value. * @return Value limited inclusively to the minimum and maximum values. * */ int32_t MathFunctions::limitRange( const int32_t value, const int32_t minimumValue, const int32_t maximumValue) { if (value < minimumValue) { return minimumValue; } if (value > maximumValue) { return maximumValue; } return value; } /** * Limit the "value" to be inclusively between the minimum and maximum. * @param value - Value for testing. * @param minimumValue - Minimum inclusive value. * @param maximumValue - Maximum inclusive value. * @return Value limited inclusively to the minimum and maximum values. * */ float MathFunctions::limitRange( const float value, const float minimumValue, const float maximumValue) { if (value < minimumValue) { return minimumValue; } if (value > maximumValue) { return maximumValue; } return value; } /** * Limit the "value" to be inclusively between the minimum and maximum. * @param value - Value for testing. * @param minimumValue - Minimum inclusive value. * @param maximumValue - Maximum inclusive value. * @return Value limited inclusively to the minimum and maximum values. * */ double MathFunctions::limitRange( const double value, const double minimumValue, const double maximumValue) { if (value < minimumValue) { return minimumValue; } if (value > maximumValue) { return maximumValue; } return value; } /** * Find the distance from the point to the line defined by p1 and p2. * Formula is from * "http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html". * * @param p1 - First coordinate in line. * @param p2 - Second coordinate in line. * @param point - coordinate for which distance to line is sought. * @return Distance from point to the line (p1, p2). * */ float MathFunctions::distanceToLine3D( const float p1[3], const float p2[3], const float point[3]) { float dv2v1[3]; MathFunctions::subtractVectors(p2, p1, dv2v1); float dv1pt[3]; MathFunctions::subtractVectors(p1, point, dv1pt); float crossed[3]; MathFunctions::crossProduct(dv2v1, dv1pt, crossed); float numerator = MathFunctions::vectorLength(crossed); float denomenator = MathFunctions::vectorLength(dv2v1); float dist = numerator / denomenator; return dist; } /** * Determine if two arrays are equal, same number of elements and * corresponding elements equal. * * @param a - first array. * @param b - second array. * @return true if arrays are equal, else false. * */ bool MathFunctions::arraysEqual( const float a[], const float b[], const int numElements) { for (int i = 0; i < numElements; i++) { if (a[i] != b[i]) { return false; } } return true; } /** * Get the average of two coordinates. * @param c1 - coordinate 1 * @param c2 - coordinate 2 * @param outputAverage A three-dimensional array into * which the average of the two coordinates is * placed. * */ void MathFunctions::averageOfTwoCoordinates(const float c1[3], const float c2[3], float outputAverage[3]) { outputAverage[0] = (c1[0] + c2[0]) / 2.0f; outputAverage[1] = (c1[1] + c2[1]) / 2.0f; outputAverage[2] = (c1[2] + c2[2]) / 2.0f; } /** * Get the average of three coordinates. * @param c1 - coordinate 1 * @param c2 - coordinate 2 * @param c3 - coordinate 3 * @param outputAverage A three-dimensional array into * which the average of the three coordinates is * placed. * */ void MathFunctions::averageOfThreeCoordinates( const float c1[3], const float c2[3], const float c3[3], float outputAverage[3]) { outputAverage[0] = (c1[0] + c2[0] + c3[0]) / 3.0f; outputAverage[1] = (c1[1] + c2[1] + c3[1]) / 3.0f; outputAverage[2] = (c1[2] + c2[2] + c3[2]) / 3.0f; } /** * Calculate the average of 3 coordinates. * @param xyzAll One-dimensional array containing the XYZ coordinates. * @param offsetCoord1 Offset of node 1's X-coordinate which is * followed by the Y- and Z-coordinates. * @param offsetCoord2 Offset of node 2's X-coordinate which is * followed by the Y- and Z-coordinates. * @param offsetCoord3 Offset of node 3's X-coordinate which is * followed by the Y- and Z-coordinates. * @param outputAverage 3 dimensional array passed in, into which * the average is placed. * @param outputOffset Offset of average into outputAverage array. * */ void MathFunctions::averageOfThreeCoordinates( const float xyzAll[], const int32_t offsetCoord1, const int32_t offsetCoord2, const int32_t offsetCoord3, float outputAverage[], const int32_t outputOffset) { outputAverage[outputOffset] = (xyzAll[offsetCoord1] + xyzAll[offsetCoord2] + xyzAll[offsetCoord3]) / 3.0f; outputAverage[outputOffset+1] = (xyzAll[offsetCoord1+1] + xyzAll[offsetCoord2+1] + xyzAll[offsetCoord3+1]) / 3.0f; outputAverage[outputOffset+2] = (xyzAll[offsetCoord1+2] + xyzAll[offsetCoord2+2] + xyzAll[offsetCoord3+2]) / 3.0f; } /** * Get the average of four coordinates. * @param c1 - coordinate 1 * @param c2 - coordinate 2 * @param c3 - coordinate 1 * @param c4 - coordinate 2 * @param outputAverage A three-dimensional array into * which the average of the four coordinates is * placed. * */ void MathFunctions::averageOfFourCoordinates(const float c1[3], const float c2[3], const float c3[3], const float c4[3], float outputAverage[3]) { outputAverage[0] = (c1[0] + c2[0] + c3[0] + c4[0]) / 4.0f; outputAverage[1] = (c1[1] + c2[1] + c3[1] + c4[1]) / 4.0f; outputAverage[2] = (c1[2] + c2[2] + c3[2] + c4[2]) / 4.0f; } /** * Angle formed by p1, p2, p3 (angle at p2). Returned angle is in radians. * This method uses Java Math.acos() and produces highly accurate results. * @param p1 - point. * @param p2 - point. * @param p3 - point. * @return Angle formed by points. * */ float MathFunctions::angle( const float p1[3], const float p2[3], const float p3[3]) { // // Vector from P2 to P1 // float v21[3] = { p1[0] - p2[0], p1[1] - p2[1], p1[2] - p2[2] }; // // Vector from P2 to P3 // float v23[3] = { p3[0] - p2[0], p3[1] - p2[1], p3[2] - p2[2] }; // // Normalize the vectors // float v21len = MathFunctions::normalizeVector(v21); float v23len = MathFunctions::normalizeVector(v23); float angleOut = 0.0f; if ((v21len > 0.0) && (v23len > 0.0)) { // // angle is inverse cosine of the dot product // and be sure to handle numerical errors. // float dot = MathFunctions::dotProduct(v21, v23); if (dot > 1.0f) dot = 1.0f; else if (dot < -1.0f) dot = -1.0f; angleOut = (float)std::acos(dot); } return angleOut; } /** * Signed angle for "jik". * @param pi - point. * @param pj - point. * @param pk - point. * @param n - normal * @return signed angle formed by the points. * */ float MathFunctions::signedAngle( const float pi[3], const float pj[3], const float pk[3], const float n[3]) { float x1 = pj[0] - pi[0]; float y1 = pj[1] - pi[1]; float z1 = pj[2] - pi[2]; float x2 = pk[0] - pi[0]; float y2 = pk[1] - pi[1]; float z2 = pk[2] - pi[2]; /* s = |(ji)||(ki)| sin(phi) by cross product */ float dx = y1*z2 - y2*z1; float dy = x2*z1 - x1*z2; float dz = x1*y2 - x2*y1; float t = (dx*n[0]) + (dy*n[1]) + (dz*n[2]); float s = (float)std::sqrt((dx*dx) + (dy*dy) + (dz*dz)); if (t < 0.0f) { s = -s; } /* c = |(ji)||(ki)| cos(phi) by inner product */ float c = x1*x2 + y1*y2 + z1*z2; float phi = (float)std::atan2(s,c); return phi; } /** * @return The angle formed by two vectors. * cos = (u . v) / (||u|| * ||v||) * * @param u * First vector. * @param v * Second vector. */ float MathFunctions::angleInDegreesBetweenVectors(const float u[3], const float v[3]) { float angle = 0.0; const float numerator = MathFunctions::dotProduct(u, v); const float uLength = MathFunctions::vectorLength(u); const float vLength = MathFunctions::vectorLength(v); const float denominator = uLength * vLength; if (denominator > 0.0) { float a = numerator / denominator; if (a > 1.0) { a = 1.0; } else if (a < -1.0) { a = -1.0; } const float angleRadians = std::acos(a); angle = MathFunctions::toDegrees(angleRadians); } return angle; } /** * Determine if an integer is an odd number. * @param number Integer to test. * @return true if integer is odd, else false. * */ bool MathFunctions::isOddNumber(const int32_t number) { bool result = ((number & 1) != 0); return result; } /** * Determine if an integer is an odd number. * @param number Integer to test. * @return true if integer is odd, else false. * */ bool MathFunctions::isEvenNumber(const int32_t number) { bool result = ((number & 1) == 0); return result; } /** * Determine if two arrays are equal. * @param a1 First array. * @param a2 Second array. * @param tolerance Allowable difference in elements at same index. * @return true if arrays are of same length and corresponding * elements have a difference less than tolerance. * */ bool MathFunctions::compareArrays( const float a1[], const float a2[], const int numElements, const float tolerance) { for (int i = 0; i < numElements; i++) { float diff = a1[i] - a2[i]; if (diff < 0.0f) diff = -diff; if (diff > tolerance) { return false; } } return true; } /** * Clamp a value to the range minimum to maximum. * @param value Value for clamping. * @param minimum Minimum allowed value. * @param maximum Maximum allowed value. * @return Value clamped to minimum and maximum. * */ int32_t MathFunctions::clamp( const int32_t value, const int32_t minimum, const int32_t maximum) { return MathFunctions::limitRange(value, minimum, maximum); } /** * Clamp a value to the range minimum to maximum. * @param value Value for clamping. * @param minimum Minimum allowed value. * @param maximum Maximum allowed value. * @return Value clamped to minimum and maximum. * */ float MathFunctions::clamp( const float value, const float minimum, const float maximum) { return MathFunctions::limitRange(value, minimum, maximum); } /** * convert degrees to radians. * @param * degrees value converted to radians. * @return * the corresponding radians value. */ float MathFunctions::toRadians(float degrees) { float radians = degrees * (M_PI / 180.0f); return radians; } /** * convert radians to degrees. * @param * degrees value converted to degrees. * @return * the corresponding degrees value. */ float MathFunctions::toDegrees(float radians) { float degrees = radians * (180.0f / M_PI); return degrees; } /** * Distance SQUARED from (x1, y1) to (x2, y2) * @param X-coordinate of first point. * @param Y-coordinate of first point. * @param X-coordinate of second point. * @param Y-coordinate of second point. * @return Distance squared between the points. */ double MathFunctions::distanceSquared2D(const double x1, const double y1, const double x2, const double y2) { const double dx = x2 - x1; const double dy = y2 - y1; const double d = (dx*dx) + (dy*dy); return d; } uint32_t MathFunctions::gcd(uint32_t num1, uint32_t num2) { if (num1 == 0 || num2 == 0) {//catch zeros return 0;//gcd(0,x)=gcd(x,0)=0, seems less confusing than returning x } //modulus method for good worst-case asymptotic performance uint32_t temp; if (num2 > num1)//num1 kept as the larger number to simplify the code { temp = num1; num1 = num2; num2 = temp; } while (num2) {//maintain num2 as the smaller number temp = num1 % num2;//modulus to reduce the larger as much as possible, result will be smaller than num2 num1 = num2;//so, we need to swap them num2 = temp;//when result becomes zero, num1 is our gcd } return num1; } bool MathFunctions::isInf(const float number) { return (abs(number) == numeric_limits::infinity()); } bool MathFunctions::isNaN(const float number) { return (number != number); } bool MathFunctions::isNegInf(const float number) { return (number == -numeric_limits::infinity()); } bool MathFunctions::isNumeric(const float number) { return (!isNaN(number) && !isInf(number)); } bool MathFunctions::isPosInf(const float number) { return (number > 1.0f && number * 2.0f == number); } void MathFunctions::quaternToMatrix(const float cijk[4], float matrix[3][3]) {//formula from http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion double qlengthsqr = cijk[0] * cijk[0] + cijk[1] * cijk[1] + cijk[2] * cijk[2] + cijk[3] * cijk[3]; double mult = 0.0; if (qlengthsqr > 0.0f) { mult = 2.0f / qlengthsqr; } double ijkmult[4] = { cijk[1] * mult, cijk[2] * mult, cijk[3] * mult }; double wX = cijk[0] * ijkmult[0], wY = cijk[0] * ijkmult[1], wZ = cijk[0] * ijkmult[2]; double xX = cijk[1] * ijkmult[0], xY = cijk[1] * ijkmult[1], xZ = cijk[1] * ijkmult[2]; double yY = cijk[2] * ijkmult[1], yZ = cijk[2] * ijkmult[2]; double zZ = cijk[3] * ijkmult[2]; matrix[0][0] = 1.0 - (yY + zZ);//equals nifti1 formula because for unit quaternion, a*a + b*b + c*c + d*d = 1, and yY = 2 * c*c matrix[0][1] = xY - wZ; matrix[0][2] = xZ + wY; matrix[1][0] = xY + wZ; matrix[1][1] = 1.0 - (xX + zZ); matrix[1][2] = yZ - wX; matrix[2][0] = xZ - wY; matrix[2][1] = yZ + wX; matrix[2][2] = 1.0 - (xX + yY); } void MathFunctions::quaternToMatrix(const double cijk[4], double matrix[3][3]) {//formula from http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion double qlengthsqr = cijk[0] * cijk[0] + cijk[1] * cijk[1] + cijk[2] * cijk[2] + cijk[3] * cijk[3]; double mult = 0.0; if (qlengthsqr > 0.0f) { mult = 2.0f / qlengthsqr; } double ijkmult[4] = { cijk[1] * mult, cijk[2] * mult, cijk[3] * mult }; double wX = cijk[0] * ijkmult[0], wY = cijk[0] * ijkmult[1], wZ = cijk[0] * ijkmult[2]; double xX = cijk[1] * ijkmult[0], xY = cijk[1] * ijkmult[1], xZ = cijk[1] * ijkmult[2]; double yY = cijk[2] * ijkmult[1], yZ = cijk[2] * ijkmult[2]; double zZ = cijk[3] * ijkmult[2]; matrix[0][0] = 1.0 - (yY + zZ);//equals nifti1 formula because for unit quaternion, a*a + b*b + c*c + d*d = 1, and yY = 2 * c*c matrix[0][1] = xY - wZ; matrix[0][2] = xZ + wY; matrix[1][0] = xY + wZ; matrix[1][1] = 1.0 - (xX + zZ); matrix[1][2] = yZ - wX; matrix[2][0] = xZ - wY; matrix[2][1] = yZ + wX; matrix[2][2] = 1.0 - (xX + yY); } bool MathFunctions::matrixToQuatern(const float matrix[3][3], float cijk[4]) {//formulas from http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion const float toler = 0.0001f; float ivec[3] = { matrix[0][0], matrix[1][0], matrix[2][0] }; float jvec[3] = { matrix[0][1], matrix[1][1], matrix[2][1] }; float kvec[3] = { matrix[0][2], matrix[1][2], matrix[2][2] }; if (!(std::abs(1.0f - normalizeVector(ivec)) <= toler)) return false;//use the "not less than or equal to" trick to catch NaNs if (!(std::abs(1.0f - normalizeVector(jvec)) <= toler)) return false; if (!(std::abs(1.0f - normalizeVector(kvec)) <= toler)) return false; if (!(dotProduct(ivec, jvec) <= toler)) return false; if (!(dotProduct(ivec, kvec) <= toler)) return false; if (!(dotProduct(jvec, kvec) <= toler)) return false; float tempvec[3]; crossProduct(ivec, jvec, tempvec); if (!(dotProduct(tempvec, kvec) >= 0.9f)) return false;//i cross j must be k, otherwise it contains a flip int method = 0; double trace = matrix[0][0] + matrix[1][1] + matrix[2][2]; if (trace < 0.0) { method = 1; float tempf = matrix[0][0]; if (matrix[1][1] > tempf) { method = 2; tempf = matrix[1][1]; } if (matrix[2][2] > tempf) { method = 3; } } switch (method) { case 0: { double r = std::sqrt(1.0 + trace); double s = 0.5 / r; cijk[0] = 0.5 * r; cijk[1] = (matrix[2][1] - matrix[1][2]) * s; cijk[2] = (matrix[0][2] - matrix[2][0]) * s; cijk[3] = (matrix[1][0] - matrix[0][1]) * s; } break; case 1: { double r = std::sqrt(1.0 + matrix[0][0] - matrix[1][1] - matrix[2][2]); double s = 0.5 / r; cijk[0] = (matrix[2][1] - matrix[1][2]) * s; cijk[1] = 0.5 * r; cijk[2] = (matrix[0][1] + matrix[1][0]) * s; cijk[3] = (matrix[2][0] + matrix[0][2]) * s; } break; case 2: {//DISCLAIMER: these last two were worked out by pattern since they aren't on wikipedia double r = std::sqrt(1.0 - matrix[0][0] + matrix[1][1] - matrix[2][2]); double s = 0.5 / r; cijk[0] = (matrix[0][2] - matrix[2][0]) * s; cijk[1] = (matrix[0][1] + matrix[1][0]) * s; cijk[2] = 0.5 * r; cijk[3] = (matrix[1][2] + matrix[2][1]) * s; } break; case 3: { double r = std::sqrt(1.0 - matrix[0][0] - matrix[1][1] + matrix[2][2]); double s = 0.5 / r; cijk[0] = (matrix[1][0] - matrix[0][1]) * s; cijk[1] = (matrix[2][0] + matrix[0][2]) * s; cijk[2] = (matrix[1][2] + matrix[2][1]) * s; cijk[3] = 0.5 * r; } break; default: return false; } if (cijk[0] < 0.0f) { cijk[0] = -cijk[0]; cijk[1] = -cijk[1]; cijk[2] = -cijk[2]; cijk[3] = -cijk[3]; } return true; } bool MathFunctions::matrixToQuatern(const double matrix[3][3], double cijk[4]) {//formulas from http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion const float toler = 0.0001f; double ivec[3] = { matrix[0][0], matrix[1][0], matrix[2][0] }; double jvec[3] = { matrix[0][1], matrix[1][1], matrix[2][1] }; double kvec[3] = { matrix[0][2], matrix[1][2], matrix[2][2] }; if (!(std::abs(1.0f - normalizeVector(ivec)) <= toler)) return false;//use the "not less than or equal to" trick to catch NaNs if (!(std::abs(1.0f - normalizeVector(jvec)) <= toler)) return false; if (!(std::abs(1.0f - normalizeVector(kvec)) <= toler)) return false; if (!(dotProduct(ivec, jvec) <= toler)) return false; if (!(dotProduct(ivec, kvec) <= toler)) return false; if (!(dotProduct(jvec, kvec) <= toler)) return false; double tempvec[3]; crossProduct(ivec, jvec, tempvec); if (!(dotProduct(tempvec, kvec) >= 0.9f)) return false;//i cross j must be k, otherwise it contains a flip int method = 0; double trace = matrix[0][0] + matrix[1][1] + matrix[2][2]; if (trace < 0.0) { method = 1; float tempf = matrix[0][0]; if (matrix[1][1] > tempf) { method = 2; tempf = matrix[1][1]; } if (matrix[2][2] > tempf) { method = 3; } } switch (method) { case 0: { double r = std::sqrt(1.0 + trace); double s = 0.5 / r; cijk[0] = 0.5 * r; cijk[1] = (matrix[2][1] - matrix[1][2]) * s; cijk[2] = (matrix[0][2] - matrix[2][0]) * s; cijk[3] = (matrix[1][0] - matrix[0][1]) * s; } break; case 1: { double r = std::sqrt(1.0 + matrix[0][0] - matrix[1][1] - matrix[2][2]); double s = 0.5 / r; cijk[0] = (matrix[2][1] - matrix[1][2]) * s; cijk[1] = 0.5 * r; cijk[2] = (matrix[0][1] + matrix[1][0]) * s; cijk[3] = (matrix[2][0] + matrix[0][2]) * s; } break; case 2: {//DISCLAIMER: these last two were worked out by pattern since they aren't on wikipedia double r = std::sqrt(1.0 - matrix[0][0] + matrix[1][1] - matrix[2][2]); double s = 0.5 / r; cijk[0] = (matrix[0][2] - matrix[2][0]) * s; cijk[1] = (matrix[0][1] + matrix[1][0]) * s; cijk[2] = 0.5 * r; cijk[3] = (matrix[1][2] + matrix[2][1]) * s; } break; case 3: { double r = std::sqrt(1.0 - matrix[0][0] - matrix[1][1] + matrix[2][2]); double s = 0.5 / r; cijk[0] = (matrix[1][0] - matrix[0][1]) * s; cijk[1] = (matrix[2][0] + matrix[0][2]) * s; cijk[2] = (matrix[1][2] + matrix[2][1]) * s; cijk[3] = 0.5 * r; } break; default: return false; } if (cijk[0] < 0.0f) { cijk[0] = -cijk[0]; cijk[1] = -cijk[1]; cijk[2] = -cijk[2]; cijk[3] = -cijk[3]; } return true; } /** * Return the remainder from the resulting division using the given values. * * This method is written to match the result produced by the remainder() * function that is part of C99 but not supported on all platforms. * * Code may appear verbose but it avoid functions calls to fabs(), ceil(), * and floor(). * * Note: X is the numerator. * Y is the denominator. * * The remainder() functions compute the value r such that r = x - n*y, * where n is the integer nearest the exact value of x/y. * * If there are two integers closest to x/y, n shall be the even one. * * @param numerator * The numerator. * @param denominator * The denominator. * @return * The remainder from numerator divided by denominator. */ double MathFunctions::remainder(const double numerator, const double denominator) { if (denominator == 0.0) { return 0.0; } const double quotient = numerator / denominator; /* * Integer value greater than or equal to the quotient * and its difference with the quotient (ceiling) */ const int64_t nearestIntegerOne = static_cast(quotient + 0.5); double diffOne = quotient - nearestIntegerOne; if (diffOne < 0.0) diffOne = -diffOne; /* * Integer value less than or equal to the quotient * and its difference with the quotient (floor) */ const int64_t nearestIntegerTwo = static_cast(quotient - 0.5); double diffTwo = quotient - nearestIntegerTwo; if (diffTwo < 0.0) diffTwo = -diffTwo; /* * Helps determine if the two integer value are the same * distance from the quotient (value will be very close * to zero). */ double diffOneTwo = diffOne - diffTwo; if (diffOneTwo < 0.0) diffOneTwo = -diffOneTwo; int64_t nearestInteger = 0; /* * If the two integer values are the same distance from zero */ if (diffOneTwo < 0.000001) { /* * Use the integer that is even. * Note that if an integer is even, first bit is zero. */ if ((nearestIntegerOne & 1) == 0) { nearestInteger = nearestIntegerOne; } else { nearestInteger = nearestIntegerTwo; } } else if (diffOne < diffTwo) { nearestInteger = nearestIntegerOne; } else { nearestInteger = nearestIntegerTwo; } const double remainderValue = numerator - nearestInteger * denominator; return remainderValue; } /** * Return the value rounded to the nearest integral (integer) value. * * @param value * Value that is rounded. * @return * Value rounded to nearest integral value. */ double MathFunctions::round(const double value) { if (value < 0.0) { return std::ceil(value - 0.5f); } return std::floor(value + 0.5f); } float MathFunctions::q_func(const float& x) {//when using c++11 or later, could use erfc instead of this approximation if (x == 0.0f) return 0.5f;//below approximation is NaN for 0! if (isInf(x)) { if (x > 0.0f) return 0;//inf return 1;//-inf } float ret; if (x < 0.0f) { ret = 1.0f - (1.0f - exp(1.4f * x)) * exp(-x * x / 2) / (x * -1.135f * sqrt(2 * 3.1415926f)); } else { ret = (1.0f - exp(-1.4f * x)) * exp(-x * x / 2) / (x * 1.135f * sqrt(2 * 3.1415926f)); } //formula from http://en.wikipedia.org/wiki/Q-function //references http://users.auth.gr/users/9/3/028239/public_html/pdf/Q_Approxim.pdf //which gives formula and constants for erfc, need to substitute and simplify //however, is wrong for negatives, so we substitute -x and subtract from 1 if (!isNumeric(ret)) { CaretAssert(abs(x) < 0.00001f);//should only be possible for very small inputs, so check before returning the answer for 0 return 0.5f; } return ret; } /** * Expand a box by given amounts in X and Y. * * @param bottomLeft * Bottom left corner of annotation. * @param bottomRight * Bottom right corner of annotation. * @param topRight * Top right corner of annotation. * @param topLeft * Top left corner of annotation. * @param extraSpaceX * Extra space to add in X. * @param extraSpaceY * Extra space to add in Y. */ void MathFunctions::expandBox(float bottomLeft[3], float bottomRight[3], float topRight[3], float topLeft[3], const float extraSpaceX, const float extraSpaceY) { float widthVector[3]; MathFunctions::subtractVectors(topRight, topLeft, widthVector); MathFunctions::normalizeVector(widthVector); float heightVector[3]; MathFunctions::subtractVectors(topLeft, bottomLeft, heightVector); MathFunctions::normalizeVector(heightVector); const float widthSpacingX = extraSpaceX * widthVector[0]; const float widthSpacingY = extraSpaceY * widthVector[1]; const float heightSpacingX = extraSpaceX * heightVector[0]; const float heightSpacingY = extraSpaceY * heightVector[1]; topLeft[0] += (-widthSpacingX + heightSpacingX); topLeft[1] += (-widthSpacingY + heightSpacingY); topRight[0] += (widthSpacingX + heightSpacingX); topRight[1] += (widthSpacingY + heightSpacingY); bottomLeft[0] += (-widthSpacingX - heightSpacingX); bottomLeft[1] += (-widthSpacingY - heightSpacingY); bottomRight[0] += (widthSpacingX - heightSpacingX); bottomRight[1] += (widthSpacingY - heightSpacingY); } /** * Expand the end points of a line. * * @param u * First point in line. * @param v * Second point in line. * #param extraSpacePercent * Percentage amount to expand the points. */ void MathFunctions::expandLinePercentage3D(float u[3], float v[3], const float extraSpacePercent) { float vector[3]; MathFunctions::subtractVectors(v, u, vector); const float length = MathFunctions::normalizeVector(vector) / 2.0; const float extraVector[3] { vector[0] * (length * extraSpacePercent), vector[1] * (length * extraSpacePercent), vector[2] * (length * extraSpacePercent) }; for (int32_t i = 0; i < 3; i++) { u[i] -= extraVector[i]; v[i] += extraVector[i]; } } /** * Expand the end points of a line. * * @param u * First point in line. * @param v * Second point in line. * #param extraSpacePixels * Pixels amount to expand the points. */ void MathFunctions::expandLinePixels3D(double u[3], double v[3], const double extraSpacePixels) { double vector[3]; MathFunctions::subtractVectors(v, u, vector); MathFunctions::normalizeVector(vector); const double halfExtra = extraSpacePixels / 2.0; const double extraVector[3] { vector[0] * halfExtra, vector[1] * halfExtra, vector[2] * halfExtra }; for (int32_t i = 0; i < 3; i++) { u[i] -= extraVector[i]; v[i] += extraVector[i]; } } /** * Expand a box by given amounts in X and Y. * * @param bottomLeft * Bottom left corner of annotation. * @param bottomRight * Bottom right corner of annotation. * @param topRight * Top right corner of annotation. * @param topLeft * Top left corner of annotation. * @param extraSpacePixels * Extra space to add, ion pixels. */ void MathFunctions::expandBoxPixels3D(double bottomLeft[3], double bottomRight[3], double topRight[3], double topLeft[3], const double extraSpacePixels) { expandLinePixels3D(bottomLeft, bottomRight, extraSpacePixels); expandLinePixels3D(topLeft, topRight, extraSpacePixels); expandLinePixels3D(bottomLeft, topLeft, extraSpacePixels); expandLinePixels3D(bottomRight, topRight, extraSpacePixels); } /** * Expand a box by given amounts in X and Y. * * @param bottomLeft * Bottom left corner of annotation. * @param bottomRight * Bottom right corner of annotation. * @param topRight * Top right corner of annotation. * @param topLeft * Top left corner of annotation. * @param extraSpacePercentage * Extra space to add, percentage is zero to one with one interpreted as 100%. */ void MathFunctions::expandBoxPercentage3D(float bottomLeft[3], float bottomRight[3], float topRight[3], float topLeft[3], const float extraSpacePercentage) { expandLinePercentage3D(bottomLeft, bottomRight, extraSpacePercentage); expandLinePercentage3D(topLeft, topRight, extraSpacePercentage); expandLinePercentage3D(bottomLeft, topLeft, extraSpacePercentage); expandLinePercentage3D(bottomRight, topRight, extraSpacePercentage); } connectome-workbench-1.4.2/src/Common/MathFunctions.h000066400000000000000000000352301360521144700226100ustar00rootroot00000000000000#ifndef __MATHFUNCTIONS_H__ #define __MATHFUNCTIONS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkBase64Utilities.h,v $ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "CaretObject.h" #include namespace caret { /** * Various mathematical functions. */ class MathFunctions : public CaretObject { private: MathFunctions(); public: virtual ~MathFunctions(); public: static int64_t combinations( const int64_t n, const int64_t k); static int64_t permutations( const int64_t n, const int64_t k); static int64_t factorial(const int64_t n); static bool normalVector( const float v1[3], const float v2[3], const float v3[3], float normalVectorOut[3]); static bool normalVector( const double v1[3], const double v2[3], const double v3[3], double normalVectorOut[3]); static void normalVectorDirection( const float v1[3], const float v2[3], const float v3[3], float directionOut[3]); static void crossProduct( const float v1[], const float v2[], float resultOut[]); static void crossProduct( const double v1[], const double v2[], double resultOut[]); static void normalizedCrossProduct( const float x1[], const float x2[], float resultOut[]); static float normalizeVector( float vectorsAll[], const int32_t offset); static float normalizeVector(float vectorInOut[3]); static double normalizeVector(double vectorInOut[3]); static float vectorLength(const float vector[3]); static float vectorLength( const float vectorsAll[], const int32_t offset); static double vectorLength(const double vector[3]); static float distanceSquared3D( const float p1[3], const float p2[3]); static float distanceSquared3D( const float xyzAll[], const int32_t offsetCoord1, const int32_t offsetCoord2); static float distance3D( const float p1[3], const float p2[3]); static double distanceSquared3D( const double p1[3], const double p2[3]); static double distance3D( const double p1[3], const double p2[3]); static double distanceSquared2D(const double x1, const double y1, const double x2, const double y2); static void subtractVectors(const float v1[3], const float v2[3], float resultOut[3]); static void subtractVectors(const double v1[3], const double v2[3], double resultOut[3]); static void addVectors( const float v1[3], const float v2[3], float resultOut[3]); static void createUnitVector( const float startXYZ[3], const float endXYZ[3], float unitVectorOut[3]); static void createUnitVector( const double startXYZ[3], const double endXYZ[3], double unitVectorOut[3]); static float dotProduct( const float p1[3], const float p2[3]); static double dotProduct( const double p1[3], const double p2[3]); static void addOffsetToVector(double v[3], const double offset[3]); static void subtractOffsetFromVector(double v[3], const double offset[3]); static float triangleArea( const float v1[3], const float v2[3], const float v3[3]); static float triangleArea(const double v1[3], const double v2[3], const double v3[3]); static float triangleArea( const float xyzAll[], const int32_t offsetCoord1, const int32_t offsetCoord2, const int32_t offsetCoord3); static float triangleAreaSigned2D( const float p1[3], const float p2[3], const float p3[3]); static float triangleAreaSigned3D( const float referenceNormal[3], const float p1[3], const float p2[3], const float p3[3]); static void vtkLinearSolve3x3( const float A[3][3], const float x[], float y[]); static void vtkLUSolve3x3( const float A[3][3], const int32_t index[], float x[]); static void vtkLUFactor3x3( float A[3][3], int32_t index[]); static void vtkInvert3x3(const double A[3][3], double AI[3][3]); static void vtkMultiply3x3(const double A[3][3], const double B[3][3], double C[3][3]); static int vtkJacobiN(double **a, int n, double *w, double **v); static void vtkPerpendiculars(const double x[3], double y[3], double z[3], double theta); static double vtkDeterminant2x2(double a, double b, double c, double d); static bool lineIntersection2D( const float p1[3], const float p2[3], const float q1[3], const float q2[3], const float tolerance, float intersectionOut[3]); static bool vectorIntersection2D( const float p1[3], const float p2[3], const float q1[3], const float q2[3], const float tolerance, float intersectionOut[3]); static bool rayIntersectPlane( const float p1[3], const float p2[3], const float p3[3], const float rayOrigin[3], const float rayVector[3], float intersectionXYZandDistance[3]); static void projectPoint( const float pt[3], const float origin[3], const float normal[3], float projectedPointOut[3]); static float signedDistanceFromPlane( const float planeNormal[3], const float pointInPlane[3], const float queryPoint[3]); static int32_t limitRange( const int32_t value, const int32_t minimumValue, const int32_t maximumValue); static float limitRange( const float value, const float minimumValue, const float maximumValue); static double limitRange( const double value, const double minimumValue, const double maximumValue); static float distanceToLine3D( const float p1[3], const float p2[3], const float point[3]); static bool arraysEqual( const float a[], const float b[], const int32_t numElements); static void averageOfTwoCoordinates( const float c1[3], const float c2[3], float outputAverage[3]); static void averageOfThreeCoordinates( const float c1[3], const float c2[3], const float c3[3], float outputAverage[3]); static void averageOfThreeCoordinates( const float xyzAll[], const int32_t offsetCoord1, const int32_t offsetCoord2, const int32_t offsetCoord3, float outputAverage[], const int32_t outputOffset); static void averageOfFourCoordinates(const float c1[3], const float c2[3], const float c3[3], const float c4[3], float outputAverage[3]); static float angle( const float p1[3], const float p2[3], const float p3[3]); static float signedAngle( const float pi[3], const float pj[3], const float pk[3], const float n[3]); static float angleInDegreesBetweenVectors(const float u[3], const float v[3]); static bool isOddNumber(const int32_t number); static bool isEvenNumber(const int32_t number); static bool isNaN(const float number); static bool isPosInf(const float number); static bool isNegInf(const float number); ///true if either inf or -inf static bool isInf(const float number); ///true only if not NaN, inf, or -inf static bool isNumeric(const float number); static bool compareArrays( const float a1[], const float a2[], const int32_t numElemets, const float tolerance); static int32_t clamp( const int32_t value, const int32_t minimum, const int32_t maximum); static float clamp( const float value, const float minimum, const float maximum); static float toRadians(float angle); static float toDegrees(float radians); ///greatest common divisor static uint32_t gcd(uint32_t num1, uint32_t num2); /** * Is the value very, very close to zero? * @param value * Value to test. * @return true if approximately zero, else false. */ static inline bool isZero(const float value) { if (value > 0.00001) return false; if (value < -0.00001) return false; return true; } ///convert quaternion to rotation matrix static void quaternToMatrix(const float cijk[4], float matrix[3][3]); ///convert quaternion to rotation matrix static void quaternToMatrix(const double cijk[4], double matrix[3][3]); ///try to convert 3x3 matrix to quaternion (return false if not a rotation matrix) static bool matrixToQuatern(const float matrix[3][3], float cijk[4]); ///try to convert 3x3 matrix to quaternion (return false if not a rotation matrix) static bool matrixToQuatern(const double matrix[3][3], double cijk[4]); static double remainder(const double numerator, const double denominator); static double round(const double value); ///one minus cdf of standard normal distribution static float q_func(const float& x); static void expandBox(float bottomLeft[3], float bottomRight[3], float topRight[3], float topLeft[3], const float extraSpaceX, const float extraSpaceY); static void expandBoxPixels3D(double bottomLeft[3], double bottomRight[3], double topRight[3], double topLeft[3], const double extraSpacePixels); static void expandBoxPercentage3D(float bottomLeft[3], float bottomRight[3], float topRight[3], float topLeft[3], const float extraSpacePercentage); static void expandLinePercentage3D(float u[3], float v[3], const float extraSpacePercent); static void expandLinePixels3D(double u[3], double v[3], const double extraSpacePixels); }; } // namespace #endif // __MATHFUNCTIONS_H__ connectome-workbench-1.4.2/src/Common/MatrixFunctions.h000066400000000000000000000603751360521144700231730ustar00rootroot00000000000000#ifndef __MATRIX_UTILITIES_H__ #define __MATRIX_UTILITIES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "stdint.h" using namespace std; //because I don't want to type std:: every other line //NOTICE: this is not intended to be used outisde of FloatMatrix.cxx and DoubleMatrix.cxx, use at your own risk //NOTICE: this is NOT meant to be as error friendly as matlab, it will check some things, error condition is a 0x0 matrix result //if a matrix has a row shorter than the first row, expect a segfault. Calling checkDim will look for this, but it is a relatively slow operation to do on every input, so it is not used internally. namespace caret { class MatrixFunctions { typedef int64_t msize_t;//NOTE: must be signed due to using -1 as a sentinel public: /// /// matrix multiplication /// template static void multiply(const vector > &left, const vector > &right, vector > &result); /// /// scalar multiplication /// template static void multiply(const vector > &left, const T2 right, vector > &result); /// /// reduced row echelon form /// template static void rref(vector > &inout); /// /// matrix inversion - wrapper to rref for now /// template static void inverse(const vector > &in, vector > &result); /// /// matrix addition - for simple code /// template static void add(const vector > &left, const vector > &right, vector > &result); /// /// scalar addition - for simple code /// template static void add(const vector > &left, const T2 right, vector > &result); /// /// matrix subtraction - for simple code /// template static void subtract(const vector > &left, const vector > &right, vector > &result); /// /// transpose - for simple code /// template static void transpose(const vector > &in, vector > &result); /// /// debugging - verify matrix is rectangular and show its dimensions - returns true if rectangular /// template static bool checkDim(const vector > &in); /// /// allocate a matrix, don't initialize /// template static void resize(const msize_t rows, const msize_t columns, vector > &result, bool destructive = false); /// /// allocate a matrix of specified size /// template static void zeros(const msize_t rows, const msize_t columns, vector > &result); /// /// allocate a matrix of specified size /// template static void ones(const msize_t rows, const msize_t columns, vector > &result); /// /// make an identity matrix /// template static void identity(const msize_t size, vector > &result); /// /// horizontally concatenate matrices /// template static void horizCat(const vector > &left, const vector > &right, vector > &result); /// /// vertically concatenate matrices /// template static void vertCat(const vector > &top, const vector > &bottom, vector > &result); /// /// grab a piece of a matrix /// template static void getChunk(const msize_t firstrow, const msize_t lastrow, const msize_t firstcol, const msize_t lastcol, const vector > &in, vector > &result); private: /// /// reduced row echelon form that is faster on larger matrices, is called by rref() if the matrix is big enough /// template static void rref_big(vector > &inout); }; template void MatrixFunctions::multiply(const vector >& left, const vector >& right, vector >& result) {//the stupid multiply O(n^3) - the O(n^2.78) version might not be that hard to implement with the other functions here, but not as stable msize_t leftrows = (msize_t)left.size(), rightrows = (msize_t)right.size(), leftcols, rightcols; vector > tempstorage, *tresult = &result;//pointer because you can't change a reference bool copyout = false; if (&left == &result || &right == &result) { copyout = true; tresult = &tempstorage; } if (leftrows && rightrows) { leftcols = (msize_t)left[0].size(); rightcols = (msize_t)right[0].size(); if (leftcols && rightcols && (rightrows == leftcols)) { resize(leftrows, rightcols, (*tresult), true);//could use zeros(), but common index last lets us zero at the same time msize_t i, j, k; for (i = 0; i < leftrows; ++i) { for (j = 0; j < rightcols; ++j) { A accum = 0; for (k = 0; k < leftcols; ++k) { accum += left[i][k] * right[k][j]; } (*tresult)[i][j] = accum; } } } else { result.resize(0); return; } } else { result.resize(0); return; } if (copyout) { result = tempstorage; } } template void MatrixFunctions::multiply(const vector > &left, const T2 right, vector > &result) { msize_t leftrows = (msize_t)left.size(), leftcols; bool doresize = true; if (&left == &result) { doresize = false;//don't resize if an input is an output } if (leftrows) { leftcols = (msize_t)left[0].size(); if (leftcols) { if (doresize) resize(leftrows, leftcols, result, true); msize_t i, j; for (i = 0; i < leftrows; ++i) { for (j = 0; j < leftcols; ++j) { result[i][j] = left[i][j] * right; } } } else { result.resize(0); return; } } else { result.resize(0); return; } } template void MatrixFunctions::rref_big(vector > &inout) { msize_t rows = (msize_t)inout.size(), cols; if (rows > 0) { cols = (msize_t)inout[0].size(); if (cols > 0) { vector pivots(rows, -1), missingPivots; msize_t i, j, k, myrow = 0; msize_t pivotrow; T tempval; for (i = 0; i < cols; ++i) { if (myrow >= rows) break;//no pivots left tempval = 0; pivotrow = -1; for (j = myrow; j < rows; ++j) {//only search below for new pivot if (abs(inout[j][i]) > tempval) { pivotrow = (msize_t)j; tempval = abs(inout[j][i]); } } if (pivotrow == -1) {//naively expect linearly dependence to show as an exact zero missingPivots.push_back(i);//record the missing pivot continue;//move to the next column } inout[pivotrow].swap(inout[myrow]);//STL swap via pointers for constant time row swap pivots[myrow] = i;//save the pivot location for back substitution tempval = inout[myrow][i]; inout[myrow][i] = (T)1; for (j = i + 1; j < cols; ++j) { inout[myrow][j] /= tempval;//divide row by pivot } for (j = myrow + 1; j < rows; ++j) {//zero ONLY below pivot for now tempval = inout[j][i]; inout[j][i] = (T)0; for (k = i + 1; k < cols; ++k) { inout[j][k] -= tempval * inout[myrow][k]; } } ++myrow;//increment row on successful pivot } msize_t numMissing = (msize_t)missingPivots.size(); if (myrow > 1)//if there is only 1 pivot, there is no back substitution to do { msize_t lastPivotCol = pivots[myrow - 1]; for (i = myrow - 1; i > 0; --i)//loop through pivots, can't zero above the top pivot so exclude it { msize_t pivotCol = pivots[i]; for (j = i - 1; j >= 0; --j)//loop through rows above pivot { tempval = inout[j][pivotCol]; inout[j][pivotCol] = (T)0;//flat zero the entry above the pivot for (k = numMissing - 1; k >= 0; --k)//back substitute within pivot range where pivots are missing { msize_t missingCol = missingPivots[k]; if (missingCol <= pivotCol) break;//equals will never trip, but whatever inout[j][missingCol] -= tempval * inout[i][missingCol]; } for (k = lastPivotCol + 1; k < cols; ++k)//loop through elements that are outside the pivot area { inout[j][k] -= tempval * inout[i][k]; } } } } } else { inout.resize(0); return; } } else { inout.resize(0); return; } } template void MatrixFunctions::rref(vector > &inout) { msize_t rows = (msize_t)inout.size(), cols; if (rows) { cols = (msize_t)inout[0].size(); if (cols) { if (rows > 7 || cols > 7)//when the matrix has this many rows/columns, it is faster to allocate storage for tracking pivots, and back substitute { rref_big(inout); return; } msize_t i, j, k, myrow = 0; msize_t pivotrow; T tempval; for (i = 0; i < cols; ++i) { if (myrow >= rows) break;//no pivots left tempval = 0; pivotrow = -1; for (j = myrow; j < rows; ++j) {//only search below for new pivot if (abs(inout[j][i]) > tempval) { pivotrow = (msize_t)j; tempval = abs(inout[j][i]); } } if (pivotrow == -1)//it may be a good idea to include a "very small value" check here, but it could mess up if used on a matrix with all values very small {//naively expect linearly dependence to show as an exact zero continue;//move to the next column } inout[pivotrow].swap(inout[myrow]);//STL swap via pointers for constant time row swap tempval = inout[myrow][i]; inout[myrow][i] = 1; for (j = i + 1; j < cols; ++j) { inout[myrow][j] /= tempval;//divide row by pivot } for (j = 0; j < myrow; ++j) {//zero above pivot tempval = inout[j][i]; inout[j][i] = 0; for (k = i + 1; k < cols; ++k) { inout[j][k] -= tempval * inout[myrow][k]; } } for (j = myrow + 1; j < rows; ++j) {//zero below pivot tempval = inout[j][i]; inout[j][i] = 0; for (k = i + 1; k < cols; ++k) { inout[j][k] -= tempval * inout[myrow][k]; } } ++myrow;//increment row on successful pivot } } else { inout.resize(0); return; } } else { inout.resize(0); return; } } template void MatrixFunctions::inverse(const vector > &in, vector > &result) {//rref implementation, there are faster (more complicated) ways - if it isn't invertible, it will hand back something strange msize_t inrows = (msize_t)in.size(), incols; if (inrows) { incols = (msize_t)in[0].size(); if (incols == inrows) { vector > inter, inter2; identity(incols, inter2); horizCat(in, inter2, inter); rref(inter); getChunk(0, inrows, incols, incols * 2, inter, result);//already using a local variable, doesn't need to check for reference duplicity } else { result.resize(0); return; } } else { result.resize(0); return; } } template void MatrixFunctions::add(const vector >& left, const vector >& right, vector >& result) { msize_t inrows = (msize_t)left.size(), incols; bool doresize = true; if (&left == &result || &right == &result) { doresize = false;//don't resize if an input is an output - this is ok for addition, don't need a copy } if (inrows) { incols = (msize_t)left[0].size(); if (inrows == (msize_t)right.size() && incols == (msize_t)right[0].size())//short circuit evaluation will protect against segfault { if (doresize) resize(inrows, incols, result, true); for (msize_t i = 0; i < inrows; ++i) { for (msize_t j = 0; j < incols; ++j) { result[i][j] = left[i][j] + right[i][j]; } } } else { result.resize(0);//use empty matrix for error condition return; } } else { result.resize(0); return; } } template void MatrixFunctions::add(const vector >& left, const T2 right, vector >& result) { msize_t inrows = (msize_t)left.size(), incols; bool doresize = true; if (&left == &result) { doresize = false;//don't resize if an input is an output - this is ok for addition, don't need a copy } if (inrows) { incols = (msize_t)left[0].size(); if (doresize) resize(inrows, incols, result, true); for (msize_t i = 0; i < inrows; ++i) { for (msize_t j = 0; j < incols; ++j) { result[i][j] = left[i][j] + right; } } } else { result.resize(0); return; } } template void MatrixFunctions::subtract(const vector >& left, const vector >& right, vector >& result) { msize_t inrows = (msize_t)left.size(), incols; bool doresize = true; if (&left == &result || &right == &result) { doresize = false;//don't resize if an input is an output } if (inrows) { incols = (msize_t)left[0].size(); if (inrows == (msize_t)right.size() && incols == (msize_t)right[0].size())//short circuit evaluation will protect against segfault { if (doresize) resize(inrows, incols, result, true); for (msize_t i = 0; i < inrows; ++i) { for (msize_t j = 0; j < incols; ++j) { result[i][j] = left[i][j] - right[i][j]; } } } else { result.resize(0); return; } } else { result.resize(0); return; } } template void MatrixFunctions::transpose(const vector > &in, vector > &result) { msize_t inrows = (msize_t)in.size(), incols; vector > tempstorage, *tresult = &result; bool copyout = false; if (&in == &result) { copyout = true; tresult = &tempstorage; } if (inrows) { incols = (msize_t)in[0].size(); resize(incols, inrows, (*tresult), true); for (msize_t i = 0; i < inrows; ++i) { for (msize_t j = 0; j < incols; ++j) { (*tresult)[j][i] = in[i][j]; } } } else { result.resize(0); } if (copyout) { result = tempstorage; } } template bool MatrixFunctions::checkDim(const vector > &in) { bool ret = true; msize_t rows = (msize_t)in.size(), columns; if (rows) { columns = (msize_t)in[0].size(); for (msize_t i = 1; i < rows; ++i) { if (in[i].size() != columns) { ret = false; } } } return ret; } template void MatrixFunctions::resize(const msize_t rows, const msize_t columns, vector >& result, bool destructive) { if (destructive && result.size() && ((msize_t)result.capacity() < rows || (msize_t)result[0].capacity() < columns)) {//for large matrices, copying to preserve contents is slow result.resize(0);//not intended to dealloc, just to set number of items to copy to zero }//default is nondestructive resize, copies everything result.resize(rows); for (msize_t i = 0; i < (const msize_t)rows; ++i) {//naive method, may end up copying everything twice if both row and col resizes require realloc result[i].resize(columns); } } template void MatrixFunctions::zeros(const msize_t rows, const msize_t columns, vector >& result) { resize(rows, columns, result, true); for (msize_t i = 0; i < rows; ++i) { for (msize_t j = 0; j < columns; ++j) { result[i][j] = 0;//should cast to float or double fine } } } template void MatrixFunctions::ones(const msize_t rows, const msize_t columns, vector >& result) { resize(rows, columns, result, true); for (msize_t i = 0; i < rows; ++i) { for (msize_t j = 0; j < columns; ++j) { result[i][j] = 1;//should cast to float or double fine } } } template void MatrixFunctions::identity(const msize_t size, vector >& result) { resize(size, size, result, true); for (msize_t i = 0; i < (const msize_t)size; ++i) { for (msize_t j = 0; j < (const msize_t)size; ++j) { result[i][j] = ((i == j) ? 1 : 0);//ditto, forgive the ternary } } } template void MatrixFunctions::horizCat(const vector >& left, const vector >& right, vector >& result) { msize_t inrows = (msize_t)left.size(), leftcols, rightcols; if (inrows > 0 && inrows == (msize_t)right.size()) { vector > tempstorage, *tresult = &result; bool copyout = false; if (&left == &result || &right == &result) { copyout = true; tresult = &tempstorage; } leftcols = (msize_t)left[0].size(); rightcols = (msize_t)right[0].size(); (*tresult) = left;//use STL copy to start resize(inrows, leftcols + rightcols, (*tresult));//values survive nondestructive resize for (msize_t i = 0; i < inrows; ++i) { for (msize_t j = 0; j < rightcols; ++j) { (*tresult)[i][j + leftcols] = right[i][j]; } } if (copyout) { result = tempstorage; } } else {//handle special cases if (inrows == 0 || right.size() == 0)//allow concatenating any empty matrix to any matrix { if (inrows == 0) { result = right; } else { result = left; } } else { result.resize(0); } } } template void MatrixFunctions::vertCat(const vector >& top, const vector >& bottom, vector >& result) { msize_t toprows = (msize_t)top.size(), botrows = (msize_t)bottom.size(), incols; if (toprows && botrows) { incols = (msize_t)top[0].size(); if (incols == (msize_t)bottom[0].size()) { vector > tempstorage, *tresult = &result; bool copyout = false; if (&top == &result || &bottom == &result) { copyout = true; tresult = &tempstorage; } (*tresult) = top; resize(toprows + botrows, incols, (*tresult));//nondestructive resize for (msize_t i = 0; i < botrows; ++i) { for (msize_t j = 0; j < incols; ++j) { (*tresult)[i + toprows][j] = bottom[i][j]; } } if (copyout) { result = tempstorage; } } else { result.resize(0); } } else {//handle special cases if (toprows == 0 || botrows == 0)//allow concatenation of empty matrix to any matrix { if (toprows == 0) { result = bottom; } else { result = top; } } else { result.resize(0); } } } template void MatrixFunctions::getChunk(const msize_t firstrow, const msize_t lastrow, const msize_t firstcol, const msize_t lastcol, const vector >& in, vector >& result) { msize_t outrows = lastrow - firstrow; msize_t outcols = lastcol - firstcol; if (lastrow <= firstrow || lastcol <= firstcol || firstrow < 0 || firstcol < 0 || lastrow > (msize_t)in.size() || lastcol > (msize_t)in[0].size()) { result.resize(0); return; } vector > tempstorage, *tresult = &result; bool copyout = false; if (&in == &result) { copyout = true; tresult = &tempstorage; } resize(outrows, outcols, (*tresult), true); for (msize_t i = 0; i < outrows; ++i) { for (msize_t j = 0; j < outcols; ++j) { (*tresult)[i][j] = in[i + firstrow][j + firstcol]; } } if (copyout) { result = tempstorage; } } } #endif connectome-workbench-1.4.2/src/Common/ModelTransform.cxx000066400000000000000000000407341360521144700233420ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __MODEL_TRANSFORM_DECLARE__ #include "ModelTransform.h" #undef __MODEL_TRANSFORM_DECLARE__ #include #include "CaretLogger.h" using namespace caret; /** * \class caret::ModelTransform * \brief Translation, Rotation, and Scaling for a model. * * Translation, Rotation, and Scaling for a model. */ /** * Constructor. */ ModelTransform::ModelTransform() : CaretObject() { this->name = ""; this->comment = ""; setToIdentity(); } /** * Destructor. */ ModelTransform::~ModelTransform() { } /** * Set the view to the identity matrix. */ void ModelTransform::setToIdentity() { this->translation[0] = 0.0; this->translation[1] = 0.0; this->translation[2] = 0.0; for (int32_t i = 0; i < 4; i++) { for (int32_t j = 0; j < 4; j++) { if (i == j) { this->rotation[i][j] = 1.0; this->obliqueRotation[i][j] = 1.0; } else { this->rotation[i][j] = 0.0; this->obliqueRotation[i][j] = 0.0; } } } this->rightCortexFlatMapOffsetXY[0] = 0.0; this->rightCortexFlatMapOffsetXY[1] = 0.0; this->rightCortexFlatMapZoomFactor = 1.0; this->scaling = 1.0; } /** * Copy constructor. * @param ModelTransform * View that is copied. */ ModelTransform::ModelTransform(const ModelTransform& ModelTransform) : CaretObject(ModelTransform) { this->copyHelper(ModelTransform); } /** * Assignment operator. * @param ModelTransform * View that is copied to this view. * @return * Reference to this object. */ ModelTransform& ModelTransform::operator=(const ModelTransform& ModelTransform) { if (this != &ModelTransform) { CaretObject::operator=(ModelTransform); this->copyHelper(ModelTransform); } return *this; } /** * Less than operator. * @param view * View compared to this view. * @return * Returns result of a name comparison. */ bool ModelTransform::operator<(const ModelTransform& view) const { return (this->name < view.name); } /** * Equality operator. * @param view * View compared to this view. * @return * Returns true if views have same name. */ bool ModelTransform::operator==(const ModelTransform& view) const { return (this->name == view.name); } /** * Get the translation * @param translation * Output translation. */ void ModelTransform::getTranslation(float translation[3]) const { translation[0] = this->translation[0]; translation[1] = this->translation[1]; translation[2] = this->translation[2]; } /** * Get the rotation matrix. * @param rotation * Output rotation matrix. */ void ModelTransform::getRotation(float rotation[4][4]) const { for (int32_t i = 0; i < 4; i++) { for (int32_t j = 0; j < 4; j++) { rotation[i][j] = this->rotation[i][j]; } } } /** * Get the offset for drawing the right cortex flat map. * * @param rightCortexFlatMapOffsetX * Output contining offset X. * @param rightCortexFlatMapOffsetX * Output contining offset Y. */ void ModelTransform::getRightCortexFlatMapOffset(float& rightCortexFlatMapOffsetX, float& rightCortexFlatMapOffsetY) const { rightCortexFlatMapOffsetX = this->rightCortexFlatMapOffsetXY[0]; rightCortexFlatMapOffsetY = this->rightCortexFlatMapOffsetXY[1]; } /** * @return Zoom factor for right cortex flat map. */ float ModelTransform::getRightCortexFlatMapZoomFactor() const { return this->rightCortexFlatMapZoomFactor; } /** * Get the oblique rotation matrix. * @param obliqueRotation * Output oblique rotation matrix. */ void ModelTransform::getObliqueRotation(float obliqueRotation[4][4]) const { for (int32_t i = 0; i < 4; i++) { for (int32_t j = 0; j < 4; j++) { obliqueRotation[i][j] = this->obliqueRotation[i][j]; } } } /** * @return The scaling. */ float ModelTransform::getScaling() const { return this->scaling; } /** * @return Name of the view. */ AString ModelTransform::getName() const { return this->name; } /** * Set the name of the view. * @param name * New name for view. */ void ModelTransform::setName(const AString& name) { this->name = name; } /** * @return Comment of the view. */ AString ModelTransform::getComment() const { return this->comment; } /** * Set the comment of the view. * @param comment * New comment for view. */ void ModelTransform::setComment(const AString& comment) { this->comment = comment; } /** * Set the translation * @param translation * New translation. */ void ModelTransform::setTranslation(const float translation[3]) { this->translation[0] = translation[0]; this->translation[1] = translation[1]; this->translation[2] = translation[2]; } /** * Set the translation * @param translationX * New translation X-value. * @param translationY * New translation Y-value. * @param translationZ * New translation Z-value. */ void ModelTransform::setTranslation(const float translationX, const float translationY, const float translationZ) { this->translation[0] = translationX; this->translation[1] = translationY; this->translation[2] = translationZ; } /** * Set the rotation matrix. * @param rotation * New rotation matrix. */ void ModelTransform::setRotation(const float rotation[4][4]) { for (int32_t i = 0; i < 4; i++) { for (int32_t j = 0; j < 4; j++) { this->rotation[i][j] = rotation[i][j]; } } } /** * Set the oblique rotation matrix. * @param obliqueRotation * New oblique rotation matrix. */ void ModelTransform::setObliqueRotation(const float obliqueRotation[4][4]) { for (int32_t i = 0; i < 4; i++) { for (int32_t j = 0; j < 4; j++) { this->obliqueRotation[i][j] = obliqueRotation[i][j]; } } } /** * Set the offset for drawing the right cortex flat map. * * @param rightCortexFlatMapOffsetX * Input contining offset X. * @param rightCortexFlatMapOffsetY * Input contining offset Y. */ void ModelTransform::setRightCortexFlatMapOffset(const float rightCortexFlatMapOffsetX, const float rightCortexFlatMapOffsetY) { this->rightCortexFlatMapOffsetXY[0] = rightCortexFlatMapOffsetX; this->rightCortexFlatMapOffsetXY[1] = rightCortexFlatMapOffsetY; } /** * Set the right cortex flat map zoom factor. * * @param rightCortexFlatMapZoomFactor * Zoom factor for right cortex flat map. */ void ModelTransform::setRightCortexFlatMapZoomFactor(const float rightCortexFlatMapZoomFactor) { this->rightCortexFlatMapZoomFactor = rightCortexFlatMapZoomFactor; } /** * Set the scaling * @param scaling * New value for scaling. */ void ModelTransform::setScaling(const float scaling) { this->scaling = scaling; } /** * Returns the user view in a string that contains, * separated by commas: View Name, translation[3], * rotation[4][4], scaling, obliqueRotation[4][4], * and rightCortexFlatMapOffset[2]; */ AString ModelTransform::getAsString() const { AString s = (this->name + s_separatorInPreferences + this->comment + s_separatorInPreferences + AString::number(this->translation[0]) + s_separatorInPreferences + AString::number(this->translation[1]) + s_separatorInPreferences + AString::number(this->translation[2])); for (int32_t i = 0; i < 4; i++) { for (int32_t j = 0; j < 4; j++) { s += (s_separatorInPreferences + AString::number(this->rotation[i][j])); } } s += (s_separatorInPreferences + AString::number(this->scaling)); for (int32_t i = 0; i < 4; i++) { for (int32_t j = 0; j < 4; j++) { s += (s_separatorInPreferences + AString::number(this->obliqueRotation[i][j])); } } s += (s_separatorInPreferences + AString::number(this->rightCortexFlatMapOffsetXY[0])); s += (s_separatorInPreferences + AString::number(this->rightCortexFlatMapOffsetXY[1])); s += (s_separatorInPreferences + AString::number(this->rightCortexFlatMapZoomFactor)); return s; } /** * Set the user view from a string that contains, * separated by commas: View Name, translation[3], * rotation[4][4], scaling, obliqueRotation[4][4], * and rightCortexFlatMapOffset[2]; */ bool ModelTransform::setFromString(const AString& s) { bool hasComment = false; bool hasObliqueRotation = false; bool hasRightFlatMapOffset = false; bool hasRightFlatMapZoomFactor = false; QStringList sl; if (s.contains(s_separatorInPreferences)) { sl = s.split(s_separatorInPreferences, QString::KeepEmptyParts); const int numElements = sl.count(); if (numElements == 41) { hasComment = true; hasObliqueRotation = true; hasRightFlatMapOffset = true; hasRightFlatMapZoomFactor = true; } else if (numElements == 40) { hasComment = true; hasObliqueRotation = true; hasRightFlatMapOffset = true; } else if (numElements == 38) { hasComment = true; hasObliqueRotation = true; } else if (numElements == 22) { hasComment = true; } else { CaretLogSevere("User view string does not contain 22, 38, or 40 elements"); return false; } } else { sl = s.split(",", QString::KeepEmptyParts); const int numElements = sl.count(); if (numElements != 21) { CaretLogSevere("User view string does not contain 21 elements"); return false; } } int ctr = 0; this->name = sl.at(ctr++); if (hasComment) { this->comment = sl.at(ctr++); } else { this->comment = ""; } this->translation[0] = sl.at(ctr++).toFloat(); this->translation[1] = sl.at(ctr++).toFloat(); this->translation[2] = sl.at(ctr++).toFloat(); for (int32_t i = 0; i < 4; i++) { for (int32_t j = 0; j < 4; j++) { this->rotation[i][j] = sl.at(ctr++).toFloat(); } } this->scaling = sl.at(ctr++).toFloat(); if (hasObliqueRotation) { for (int32_t i = 0; i < 4; i++) { for (int32_t j = 0; j < 4; j++) { this->obliqueRotation[i][j] = sl.at(ctr++).toFloat(); } } } else { for (int32_t i = 0; i < 4; i++) { for (int32_t j = 0; j < 4; j++) { if (i == j) { this->obliqueRotation[i][j] = 1.0; } else { this->obliqueRotation[i][j] = 0.0; } } } } if (hasRightFlatMapOffset) { this->rightCortexFlatMapOffsetXY[0] = sl.at(ctr++).toFloat(); this->rightCortexFlatMapOffsetXY[1] = sl.at(ctr++).toFloat(); } else { this->rightCortexFlatMapOffsetXY[0] = 0; this->rightCortexFlatMapOffsetXY[1] = 0; } if (hasRightFlatMapZoomFactor) { this->rightCortexFlatMapZoomFactor = sl.at(ctr++).toFloat(); } else { this->rightCortexFlatMapZoomFactor = 1.0; } return true; } /** * Copy all data from the given user view to this user view. * @param ModelTransform * View from which data is copied. */ void ModelTransform::copyHelper(const ModelTransform& modelTransform) { this->name = modelTransform.name; this->comment = modelTransform.comment; this->translation[0] = modelTransform.translation[0]; this->translation[1] = modelTransform.translation[1]; this->translation[2] = modelTransform.translation[2]; for (int32_t i = 0; i < 4; i++) { for (int32_t j = 0; j < 4; j++) { this->rotation[i][j] = modelTransform.rotation[i][j]; this->obliqueRotation[i][j] = modelTransform.obliqueRotation[i][j]; } } this->scaling = modelTransform.scaling; this->rightCortexFlatMapOffsetXY[0] = modelTransform.rightCortexFlatMapOffsetXY[0]; this->rightCortexFlatMapOffsetXY[1] = modelTransform.rightCortexFlatMapOffsetXY[1]; this->rightCortexFlatMapZoomFactor = modelTransform.rightCortexFlatMapZoomFactor; } /** * Set panning, rotation, oblique rotation, and zoom. * * @param panX * X-Panning. * @param panY * Y-Panning. * @param panZ * Z-Panning. * @param rotationMatrix * 4x4 rotation matrix. * @param obliqueRotationMatrix * 4x4 oblique rotation matrix. * @param zoom * Zooming. * @param rightCortexFlatMapOffsetX * Offset X for right cortex flat map. * @param rightCortexFlatMapOffsetY * Offset Y for right cortex flat map. * @param rightCortexFlatMapZoomFactor * Zoom factor for right cortex flat map. */ void ModelTransform::setPanningRotationMatrixAndZoom(const float panX, const float panY, const float panZ, const float rotationMatrix[4][4], const float obliqueRotationMatrix[4][4], const float zoom, const float rightCortexFlatMapOffsetX, const float rightCortexFlatMapOffsetY, const float rightCortexFlatMapZoomFactor) { this->setTranslation(panX, panY, panZ); setRotation(rotationMatrix); setObliqueRotation(obliqueRotationMatrix); this->setScaling(zoom); this->setRightCortexFlatMapOffset(rightCortexFlatMapOffsetX, rightCortexFlatMapOffsetY); this->setRightCortexFlatMapZoomFactor(rightCortexFlatMapZoomFactor); } /** * Get pan, rotation, oblique rotation, and zoom. * * @param panX * X-Panning. * @param panY * Y-Panning. * @param rotationMatrix * 4x4 rotation matrix. * @param obliqueRotationMatrix * 4x4 oblique rotation matrix. * @param zoom * Zooming. * @param rightCortexFlatMapOffsetX * Offset X for right cortex flat map. * @param rightCortexFlatMapOffsetY * Offset Y for right cortex flat map. * @param rightCortexFlatMapZoomFactor * Zoom factor for right cortex flat map. */ void ModelTransform::getPanningRotationMatrixAndZoom(float& panX, float& panY, float& panZ, float rotationMatrix[4][4], float obliqueRotationMatrix[4][4], float& zoom, float& rightCortexFlatMapOffsetX, float& rightCortexFlatMapOffsetY, float& rightCortexFlatMapZoomFactor) const { panX = this->translation[0]; panY = this->translation[1]; panZ = this->translation[2]; getRotation(rotationMatrix); getObliqueRotation(obliqueRotationMatrix); zoom = getScaling(); getRightCortexFlatMapOffset(rightCortexFlatMapOffsetX, rightCortexFlatMapOffsetY); rightCortexFlatMapZoomFactor = this->getRightCortexFlatMapZoomFactor(); } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ModelTransform::toString() const { return ("ModelTransform: " + this->getAsString()); } connectome-workbench-1.4.2/src/Common/ModelTransform.h000066400000000000000000000114731360521144700227650ustar00rootroot00000000000000#ifndef __MODEL_TRANSFORM_H__ #define __MODEL_TRANSFORM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" namespace caret { class ModelTransform : public CaretObject { public: ModelTransform(); virtual ~ModelTransform(); ModelTransform(const ModelTransform&); ModelTransform& operator=(const ModelTransform&); AString getName() const; void getTranslation(float translation[3]) const; void getRotation(float rotation[4][4]) const; void getObliqueRotation(float obliqueRotation[4][4]) const; void getRightCortexFlatMapOffset(float& rightCortexFlatMapOffsetX, float& rightCortexFlatMapOffsetY) const; float getRightCortexFlatMapZoomFactor() const; float getScaling() const; void setName(const AString& name); AString getComment() const; void setComment(const AString& comment); void setTranslation(const float translation[3]); void setTranslation(const float translationX, const float translationY, const float translationZ); void setRotation(const float rotation[4][4]); void setObliqueRotation(const float obliqueRotation[4][4]); void setRightCortexFlatMapOffset(const float rightCortexFlatMapOffsetX, const float rightCortexFlatMapOffsetY); void setRightCortexFlatMapZoomFactor(const float rightCortexFlatMapZoomFactor); void setScaling(const float scaling); void setPanningRotationMatrixAndZoom(const float panX, const float panY, const float panZ, const float rotationMatrix[4][4], const float obliqueRotationMatrix[4][4], const float zoom, const float rightCortexFlatMapOffsetX, const float rightCortexFlatMapOffsetY, const float rightCortexFlatMapZoomFactor); void getPanningRotationMatrixAndZoom(float& panX, float& panY, float& panZ, float rotationMatrix[4][4], float obliqueRotationMatrix[4][4], float& zoom, float& rightCortexFlatMapOffsetX, float& rightCortexFlatMapOffsetY, float& rightCortexFlatMapZoomFactor) const; AString getAsString() const; bool setFromString(const AString& s); void setToIdentity(); bool operator<(const ModelTransform& view) const; bool operator==(const ModelTransform& view) const; public: virtual AString toString() const; private: void copyHelper(const ModelTransform& ModelTransform); AString name; AString comment; float translation[3]; float rotation[4][4]; float obliqueRotation[4][4]; float scaling; float rightCortexFlatMapOffsetXY[2]; float rightCortexFlatMapZoomFactor; static const QString s_separatorInPreferences; }; #ifdef __MODEL_TRANSFORM_DECLARE__ const QString ModelTransform::s_separatorInPreferences = "::::"; #endif // __MODEL_TRANSFORM_DECLARE__ } // namespace #endif //__MODEL_TRANSFORM_H__ connectome-workbench-1.4.2/src/Common/MultiDimArray.h000066400000000000000000000073411360521144700225530ustar00rootroot00000000000000#ifndef __MULTI_DIM_ARRAY_H__ #define __MULTI_DIM_ARRAY_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "stdint.h" #include namespace caret { template class MultiDimArray { std::vector m_dims, m_skip;//always use int64_t for indexes internally std::vector m_data; template int64_t index(const int& fullDims, const std::vector& indexSelect) const;//assume we never need over 2 billion dimensions public: const std::vector& getDimensions() const { return m_dims; } template void resize(const std::vector& dims);//destructive resize template T& at(const std::vector& pos); template const T& at(const std::vector& pos) const; template T* get(const int& fullDims, const std::vector& indexSelect);//subarray reference selection template const T* get(const int& fullDims, const std::vector& indexSelect) const; }; template template void MultiDimArray::resize(const std::vector& dims) { m_dims = std::vector(dims.begin(), dims.end()); m_skip.resize(m_dims.size()); if (dims.size() == 0) { m_data.clear(); return; } int64_t numElems = 1; for (int i = 0; i < (int)m_dims.size(); ++i) { CaretAssert(m_dims[i] > 0); m_skip[i] = numElems; numElems *= m_dims[i]; } m_data.resize(numElems); } template template int64_t MultiDimArray::index(const int& fullDims, const std::vector& indexSelect) const { CaretAssert(fullDims + indexSelect.size() == m_dims.size()); int64_t ret = 0; for (int i = fullDims; i < (int)m_dims.size(); ++i) { CaretAssert(indexSelect[i - fullDims] >= 0 && indexSelect[i - fullDims] < m_dims[i]); ret += m_skip[i] * indexSelect[i - fullDims]; } return ret; } template template T& MultiDimArray::at(const std::vector& pos) { return m_data[index(0, pos)]; } template template const T& MultiDimArray::at(const std::vector& pos) const { return m_data[index(0, pos)]; } template template T* MultiDimArray::get(const int& fullDims, const std::vector& indexSelect) { return m_data.data() + index(fullDims, indexSelect); } template template const T* MultiDimArray::get(const int& fullDims, const std::vector& indexSelect) const { return m_data.data() + index(fullDims, indexSelect); } } #endif //__MULTI_DIM_ARRAY_H__ connectome-workbench-1.4.2/src/Common/MultiDimIterator.h000066400000000000000000000076621360521144700232740ustar00rootroot00000000000000#ifndef __MULTI_DIM_ITERATOR_H__ #define __MULTI_DIM_ITERATOR_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "stdint.h" #include namespace caret { template class MultiDimIterator { std::vector m_dims, m_pos; bool m_atEnd; void gotoBegin(); void gotoLast(); public: explicit MultiDimIterator(const std::vector& dimensions); void operator++(); void operator++(int); void operator--(); void operator--(int); const std::vector& operator*() const { return m_pos; } bool atEnd() const { return m_atEnd; } }; template MultiDimIterator::MultiDimIterator(const std::vector& dimensions) { m_dims = dimensions; gotoBegin(); } template void MultiDimIterator::gotoBegin() { m_pos = std::vector(m_dims.size(), 0); m_atEnd = false; size_t numDims = m_dims.size(); for (size_t i = 0; i < numDims; ++i) { if (m_dims[i] < 1) { m_atEnd = true; break; } } } template void MultiDimIterator::gotoLast() { m_pos = std::vector(m_dims.size()); m_atEnd = false; size_t numDims = m_dims.size(); for (size_t i = 0; i < numDims; ++i) { m_pos[i] = m_dims[i] - 1; if (m_dims[i] < 1) { m_atEnd = true; } } } template void MultiDimIterator::operator++() { if (atEnd())//wrap around { gotoBegin(); return; } if (m_dims.size() == 0) { m_atEnd = true;//special case: no dimensions works the same as 1 dimension of length 1 return; } size_t numDims = m_dims.size(); for (size_t i = 0; i < numDims; ++i) { ++m_pos[i]; if (m_pos[i] < m_dims[i]) return; m_pos[i] = 0; } m_atEnd = true;//if we didn't return already, all of them wrapped, so we are at the end } template void MultiDimIterator::operator++(int) { ++(*this); } template void MultiDimIterator::operator--() { if (atEnd())//wrap around { gotoLast(); return; } if (m_dims.size() == 0) { m_atEnd = true;//special case: no dimensions works the same as 1 dimension of length 1 return; } size_t numDims = m_dims.size(); for (size_t i = 0; i < numDims; ++i) { if (m_pos[i] > 0) { --m_pos[i]; return; } else { m_pos[i] = m_dims[i] - 1; } } m_atEnd = true;//if we didn't return already, all of them wrapped, so we are at the end } template void MultiDimIterator::operator--(int) { --(*this); } } #endif //__MULTI_DIM_ITERATOR_H__ connectome-workbench-1.4.2/src/Common/NetworkException.cxx000066400000000000000000000026201360521144700237060ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "NetworkException.h" using namespace caret; /** * Constructor. * */ NetworkException::NetworkException() : CaretException() { } /** * Constructor that uses stack trace from the exception * passed in as a parameter. * * @param e Any exception whose stack trace becomes * this exception's stack trace. * */ NetworkException::NetworkException( const CaretException& e) : CaretException(e) { } /** * Constructor. * * @param s Description of the exception. * */ NetworkException::NetworkException(const AString& s) : CaretException(s) { } connectome-workbench-1.4.2/src/Common/NetworkException.h000066400000000000000000000023641360521144700233400ustar00rootroot00000000000000#ifndef __NETWORK_EXCEPTION_H__ #define __NETWORK_EXCEPTION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretException.h" namespace caret { /** * An exception thrown during network operations */ class NetworkException : public CaretException { public: NetworkException(); NetworkException(const CaretException& e); NetworkException(const AString& s); }; } // namespace #endif // __NETWORK_EXCEPTION_H__ connectome-workbench-1.4.2/src/Common/NumericFormatModeEnum.cxx000066400000000000000000000251351360521144700246110ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __NUMERIC_FORMAT_MODE_ENUM_DECLARE__ #include "NumericFormatModeEnum.h" #undef __NUMERIC_FORMAT_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::NumericFormatModeEnum * \brief Format mode for floating point numbers into text * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_numericFormatModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void numericFormatModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "NumericFormatModeEnum.h" * * Instatiate: * m_numericFormatModeEnumComboBox = new EnumComboBoxTemplate(this); * m_numericFormatModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_numericFormatModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(numericFormatModeEnumComboBoxItemActivated())); * * Update the selection: * m_numericFormatModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const NumericFormatModeEnum::Enum VARIABLE = m_numericFormatModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ NumericFormatModeEnum::NumericFormatModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ NumericFormatModeEnum::~NumericFormatModeEnum() { } /** * Initialize the enumerated metadata. */ void NumericFormatModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(NumericFormatModeEnum(AUTO, "AUTO", "Auto")); enumData.push_back(NumericFormatModeEnum(DECIMAL, "DECIMAL", "Decimal")); enumData.push_back(NumericFormatModeEnum(SCIENTIFIC, "SCIENTIFIC", "Scientific")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const NumericFormatModeEnum* NumericFormatModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const NumericFormatModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString NumericFormatModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const NumericFormatModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ NumericFormatModeEnum::Enum NumericFormatModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = NumericFormatModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const NumericFormatModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type NumericFormatModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString NumericFormatModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const NumericFormatModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ NumericFormatModeEnum::Enum NumericFormatModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = NumericFormatModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const NumericFormatModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type NumericFormatModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t NumericFormatModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const NumericFormatModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ NumericFormatModeEnum::Enum NumericFormatModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = NumericFormatModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const NumericFormatModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type NumericFormatModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void NumericFormatModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void NumericFormatModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(NumericFormatModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void NumericFormatModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(NumericFormatModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/NumericFormatModeEnum.h000066400000000000000000000061561360521144700242400ustar00rootroot00000000000000#ifndef __NUMERIC_FORMAT_MODE_ENUM_H__ #define __NUMERIC_FORMAT_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class NumericFormatModeEnum { public: /** * Enumerated values. */ enum Enum { /** Auto */ AUTO, /** Decimal */ DECIMAL, /** Scientific */ SCIENTIFIC }; ~NumericFormatModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: NumericFormatModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const NumericFormatModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __NUMERIC_FORMAT_MODE_ENUM_DECLARE__ std::vector NumericFormatModeEnum::enumData; bool NumericFormatModeEnum::initializedFlag = false; int32_t NumericFormatModeEnum::integerCodeCounter = 0; #endif // __NUMERIC_FORMAT_MODE_ENUM_DECLARE__ } // namespace #endif //__NUMERIC_FORMAT_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Common/NumericTextFormatting.cxx000066400000000000000000000457641360521144700247200ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __NUMERIC_TEXT_FORMATTING_DECLARE__ #include "NumericTextFormatting.h" #undef __NUMERIC_TEXT_FORMATTING_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" using namespace caret; #include "MathFunctions.h" /** * \class caret::NumericTextFormatting * \brief Formats numeric values for display as text. * \ingroup Common */ /** * Constructor. */ NumericTextFormatting::NumericTextFormatting() : CaretObject() { } /** * Destructor. */ NumericTextFormatting::~NumericTextFormatting() { } /** * If there are trailing zeros after the decimal point, remove * any after the first zero. Change a negative zero (-0) to zero (0); * * @param textValueIn * Text representation of the value. * @reutrn * Value after cleanup of zeros. */ AString NumericTextFormatting::cleanZerosInValueText(const AString& textValueIn) { AString textValue = textValueIn; const int dotIndex = textValue.indexOf('.'); if (dotIndex > 0) { /* * Remove any trailing zeros */ for (int32_t i = (textValue.length() - 1); i >= (dotIndex + 2); --i) { if (textValue[i] == '0') { textValue[i] = ' '; } else { break; } } } textValue = textValue.trimmed(); if (textValue == "-0.0") { textValue = "0"; } else if (textValue == "-0") { textValue = "0"; } else if (textValue == "0.0") { textValue = "0"; } textValue = textValue.trimmed(); return textValue; } /** * If there is a leading zero in the exponent, remove it * to save space (-2.1e+03 => -2.1e+3) * * @param numericFormat * How to format the numbers when converted to text. * @param textValueIn * Text representation of the value. * @reutrn * Value after cleanup of zeros. */ AString NumericTextFormatting::removeLeadingZeroFromExponent(const NumericFormatModeEnum::Enum numericFormat, const AString& textValueIn) { AString textValue = textValueIn; AString ePlusMinus = ""; int eIndex = textValue.indexOf("e+"); if (eIndex < 0) { eIndex = textValue.indexOf("e-"); } /* * Regular expression that matches something like 0.000e+00 (zero !!!) */ static QRegExp zeroRegExp("^0\\.0+e[\\+-]0+$"); if (eIndex > 0) { if (textValue.indexOf(zeroRegExp) >= 0) { textValue = "0"; } else { AString eText = textValue.mid(eIndex, 2); AString mantissaText = textValue.left(eIndex); AString exponentText = textValue.mid(eIndex + 2); switch (numericFormat) { case NumericFormatModeEnum::AUTO: /* * Remove trailing zeros from mantissa */ mantissaText = cleanZerosInValueText(mantissaText); break; case NumericFormatModeEnum::DECIMAL: break; case NumericFormatModeEnum::SCIENTIFIC: break; } /* * Remove leading zeros from exponent and * keep last zero */ for (int32_t i = 0; i < (exponentText.length() - 1); i++) { if (exponentText[i] == '0') { exponentText[i] = ' '; } else { break; } } exponentText = exponentText.trimmed(); textValue = (mantissaText + eText + exponentText); // std::cout << " Sci Value " // << textValueIn // << " Mantissa: " << mantissaText // << " e: " << eText // << " Exponent: " << exponentText << std::endl; } } return textValue; } /** * Format a number for display. * * @param numericFormat * How to format the numbers when converted to text. * @param value * The value for formatting. * @param format * Formatting to use for number ('f' fixed, 'e' scientific). * @param fieldWidth * * @param precision * Digits right of the decimal point * @return * Text representation of number with formatting applied. */ AString NumericTextFormatting::formatNumberForDisplay(const NumericFormatModeEnum::Enum numericFormat, const double value, const char format, const int fieldWidth, const int precision) { if (MathFunctions::isNaN(value)) { return "NaN"; } else if (MathFunctions::isInf(value)) { return "Inf"; } else if (MathFunctions::isNegInf(value)) { return "-Inf"; } else if (MathFunctions::isPosInf(value)) { return "Inf"; } const double absValue = ((value < 0.0) ? -value : value); AString numberValue = QString("%1").arg(absValue, fieldWidth, format, precision); numberValue = removeLeadingZeroFromExponent(numericFormat, numberValue); AString textValue; if (value < 0.0) { textValue = "-"; } textValue += numberValue; if ( ! textValue.contains('e')) { switch (numericFormat) { case NumericFormatModeEnum::AUTO: textValue = cleanZerosInValueText(textValue); break; case NumericFormatModeEnum::DECIMAL: break; case NumericFormatModeEnum::SCIENTIFIC: break; } } return textValue; } /** * Get format and precision based upon value of the number. * * @param valueIn * The number. * @param formatOut * Output format (fixed 'f' or scientific 'e') * @param precisionOut * Number of digits right of decimal point. */ void NumericTextFormatting::getFormatAndPrecision(const float valueIn, char& formatOut, int& precisionOut) { const float value = ((valueIn < 0.0) ? -valueIn : valueIn); if (value >= 10000) { formatOut = 'e'; precisionOut = 3; } else if (value >= 100) { formatOut = 'f'; precisionOut = 0; } else if (value >= 10) { formatOut = 'f'; precisionOut = 1; } else if (value >= 1) { formatOut = 'f'; precisionOut = 2; } else if (value >= 0.01) { formatOut = 'f'; precisionOut = 3; } else { formatOut = 'e'; precisionOut = 3; } } /** * Format the negative and positive values by using the value of the range (min to max) * to set format and precision for all values. * * @param numericFormatIn * How to format the numbers when converted to text. * @param numericFormatPrecisionIn * Precision used the numeric format is not automatic. * @param negativeValuesIn * The negative input values array. Must be at least two elements and * the values must be sorted from smallest to largest. * @param negativeFormattedValuesOut * Output containing negativevalues formatted as text. * @param negativeBumberOfValues * Number of negativevalues in the arrays and both the input and output * arrays must sized to this value. * @param positiveValuesIn * The positive input values array. Must be at least two elements and * the values must be sorted from smallest to largest. * @param positiveFormattedValuesOut * Output containing positive values formatted as text. * @param positiveNumberOfValues * Number of positive values in the arrays and both the input and output * arrays must sized to this value. */ void NumericTextFormatting::formatValueRangeNegPos(const NumericFormatModeEnum::Enum numericFormatIn, const int32_t numericFormatPrecisionIn, const float negativeValuesIn[], AString negativeFormattedValuesOut[], const int32_t negativeNumberOfValues, const float positiveValuesIn[], AString positiveFormattedValuesOut[], const int32_t positiveNumberOfValues) { NumericFormatModeEnum::Enum numericFormat = numericFormatIn; int32_t numericFormatPrecision = numericFormatPrecisionIn; if (negativeNumberOfValues > 0) { formatValueRange(numericFormat, numericFormatPrecision, negativeValuesIn, negativeFormattedValuesOut, negativeNumberOfValues); } if (positiveNumberOfValues > 0) { formatValueRange(numericFormat, numericFormatPrecision, positiveValuesIn, positiveFormattedValuesOut, positiveNumberOfValues); } switch (numericFormat) { case NumericFormatModeEnum::AUTO: removeDotZeroIfAllIntegers(negativeFormattedValuesOut, negativeNumberOfValues, positiveFormattedValuesOut, positiveNumberOfValues); break; case NumericFormatModeEnum::DECIMAL: break; case NumericFormatModeEnum::SCIENTIFIC: break; } } /** * If all of the positive and negative text values represent integers * (contain no decimal or end with decimal followed by zeros), * strip off decimal and trailing zeros. * * @param negativeFormattedValues * Negative values formatted as text. * @param negativeBumberOfValues * Number of negative values. * @param positiveFormattedValues * Positive values formatted as text. * @param positiveNumberOfValues * Number of positive values. */ void NumericTextFormatting::removeDotZeroIfAllIntegers(AString negativeFormattedValues[], const int32_t negativeNumberOfValues, AString positiveFormattedValues[], const int32_t positiveNumberOfValues) { std::vector allValues(negativeFormattedValues, negativeFormattedValues + negativeNumberOfValues); allValues.insert(allValues.end(), positiveFormattedValues, positiveFormattedValues + positiveNumberOfValues); for (auto& text: allValues) { const int32_t len = text.length(); /* * Does this text end with a decimal followed by all zeros */ const int32_t decimalIndex = text.indexOf('.'); if (decimalIndex >= 0) { for (int32_t j = decimalIndex + 1; j < len; j++) { if (text[j] != '0') { /* * Non-zero trailing value so not integer value */ return; } } if (decimalIndex >= 0) { /* * Chop off decimal and zeros * "text" is a reference so changes value in allValues vector */ text.resize(decimalIndex); } else { /* if no decimal found, then value is already integer */ } } } for (int32_t i = 0; i < negativeNumberOfValues; i++) { CaretAssertArrayIndex(negativeFormattedValues, negativeNumberOfValues, i); CaretAssertVectorIndex(allValues, i); negativeFormattedValues[i] = allValues[i]; } for (int32_t i = 0; i < positiveNumberOfValues; i++) { CaretAssertArrayIndex(positiveFormattedValues, positiveNumberOfValues, i); const int32_t j = i + negativeNumberOfValues; CaretAssertVectorIndex(allValues, j); positiveFormattedValues[i] = allValues[j]; } } /** * Format the values by using the value of the range (min to max) * to set format and precision for all values. * * @param numericFormat * How to format the numbers when converted to text. * @param numericFormatPrecision * Precision used the numeric format is not automatic. * @param valuesIn * The input values array. Must be at least two elements and * the values must be sorted from smallest to largest. * @param formattedValuesOut * Output containing values formatted as text. * @param numberOfValues * Number of values in the arrays and both the input and output * arrays must sized to this value. */ void NumericTextFormatting::formatValueRange(const NumericFormatModeEnum::Enum numericFormat, const int32_t numericFormatPrecision, const float valuesIn[], AString formattedValuesOut[], const int32_t numberOfValues) { for (int32_t i = 0; i < numberOfValues; i++) { formattedValuesOut[i] = ""; } if (numberOfValues < 2) { CaretLogSevere("NumericTextFormatting::formatValueRange requires at least two values."); return; } const double range = valuesIn[numberOfValues - 1] - valuesIn[0]; if (MathFunctions::isNaN(range)) { for (int32_t i = 0; i < numberOfValues; i++) { formattedValuesOut[i] = "0"; } formattedValuesOut[0] = "NaN"; formattedValuesOut[numberOfValues - 1] = "NaN"; return; } char format = 'f'; int precision = 0; switch (numericFormat) { case NumericFormatModeEnum::AUTO: getFormatAndPrecision(range, format, precision); break; case NumericFormatModeEnum::DECIMAL: format = 'f'; precision = numericFormatPrecision; break; case NumericFormatModeEnum::SCIENTIFIC: format = 'e'; precision = numericFormatPrecision; break; } const int FIELD_WIDTH = 0; for (int32_t i = 0; i < numberOfValues; i++) { const double value = valuesIn[i]; AString textValue = formatNumberForDisplay(numericFormat, value, format, FIELD_WIDTH, precision); formattedValuesOut[i] = textValue; } } /** * Format the values by using the value of the range (min to max) * to set format and precision for all values. * * @param valuesIn * The input values array. Must be at least two elements and * the values must be sorted from smallest to largest. * @param formattedValuesOut * Output containing values formatted as text. * @param numberOfValues * Number of values in the arrays and both the input and output * arrays must sized to this value. */ void NumericTextFormatting::formatValueRange(const float valuesIn[], AString formattedValuesOut[], const int32_t numberOfValues) { NumericTextFormatting::formatValueRange(NumericFormatModeEnum::AUTO, 0, valuesIn, formattedValuesOut, numberOfValues); } /** * Format the values by formatting the negative and positive * ranges separately. * * @param negMaxNegMinPosMinPosMaxValuesIn * [0] => most negative value * [1] => least negative value * [2] => least positive value * [3] => most positive value * [0] <= [1] <= 0.0 <= [2] <= [3] * @param formattedValuesOut * Output containing values formatted as text. */ void NumericTextFormatting::formatValueRangeNegativeAndPositive(const float negMaxNegMinPosMinPosMaxValuesIn[4], AString formattedValuesOut[4]) { formatValueRange(&negMaxNegMinPosMinPosMaxValuesIn[0], &formattedValuesOut[0], 2); formatValueRange(&negMaxNegMinPosMinPosMaxValuesIn[2], &formattedValuesOut[2], 2); } /** * Format the value. * * @param valuesn * The input values. * @return * Value formatted as text. */ AString NumericTextFormatting::formatValue(const float value) { char format = 'f'; int precision = 0; getFormatAndPrecision(value, format, precision); const int FIELD_WIDTH = 0; AString textValue = formatNumberForDisplay(NumericFormatModeEnum::AUTO, value, format, FIELD_WIDTH, precision); return textValue; } /** * Format each of the values. * * @param valuesIn * The input values array. * @param formattedValuesOut * Output containing values formatted as text. * @param numberOfValues * Number of values in the arrays and both the input and output * arrays must sized to this value. */ void NumericTextFormatting::formatValuesIndividually(const float valuesIn[], AString formattedValuesOut[], const int32_t numberOfValues) { for (int32_t i = 0; i < numberOfValues; i++) { formattedValuesOut[i] = formatValue(valuesIn[i]); } } connectome-workbench-1.4.2/src/Common/NumericTextFormatting.h000066400000000000000000000106471360521144700243350ustar00rootroot00000000000000#ifndef __NUMERIC_TEXT_FORMATTING_H__ #define __NUMERIC_TEXT_FORMATTING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "NumericFormatModeEnum.h" namespace caret { class NumericTextFormatting : public CaretObject { public: static void formatValueRangeNegativeAndPositive(const float negMaxNegMinPosMinPosMaxValuesIn[4], AString formattedValuesOut[4]); static void formatValueRange(const float valuesIn[], AString formattedValuesOut[], const int32_t numberOfValues); static void formatValueRange(const NumericFormatModeEnum::Enum numericFormat, const int32_t numericFormatPrecision, const float valuesIn[], AString formattedValuesOut[], const int32_t numberOfValues); static void formatValueRangeNegPos(const NumericFormatModeEnum::Enum numericFormat, const int32_t numericFormatPrecision, const float negativeValuesIn[], AString negativeFormattedValuesOut[], const int32_t negativeNumberOfValues, const float positiveValuesIn[], AString positiveFormattedValuesOut[], const int32_t positiveNumberOfValues); static AString formatValue(const float valueIn); static void formatValuesIndividually(const float valuesIn[], AString formattedValuesOut[], const int32_t numberOfValues); static AString cleanZerosInValueText(const AString& textValueIn); // ADD_NEW_METHODS_HERE private: NumericTextFormatting(); virtual ~NumericTextFormatting(); NumericTextFormatting(const NumericTextFormatting&); NumericTextFormatting& operator=(const NumericTextFormatting&); static AString removeLeadingZeroFromExponent(const NumericFormatModeEnum::Enum numericFormat, const AString& textValueIn); static AString formatNumberForDisplay(const NumericFormatModeEnum::Enum numericFormat, const double value, const char format, const int fieldWidth, const int precision); static void getFormatAndPrecision(const float valueIn, char& formatOut, int& precisionOut); static void removeDotZeroIfAllIntegers(AString negativeFormattedValues[], const int32_t negativeNumberOfValues, AString positiveFormattedValues[], const int32_t positiveNumberOfValues); // ADD_NEW_MEMBERS_HERE }; #ifdef __NUMERIC_TEXT_FORMATTING_DECLARE__ // #endif // __NUMERIC_TEXT_FORMATTING_DECLARE__ } // namespace #endif //__NUMERIC_TEXT_FORMATTING_H__ connectome-workbench-1.4.2/src/Common/OctTree.h000066400000000000000000000356721360521144700214050ustar00rootroot00000000000000#ifndef __OCT_TREE_H__ #define __OCT_TREE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "MathFunctions.h" #include namespace caret { ///low level Oct structure with a bunch of helper members, use it to build your own tree of Octs, possibly by extension template struct Oct { //data T m_data; //children Oct* m_children[2][2][2]; Oct* m_parent; bool m_leaf; float m_bounds[3][3]; Oct(); Oct(const float minCoords[3], const float maxCoords[3]); ~Oct(); void makeChildren(); void makeChildrenExcept(const int octant[3]); void deleteChildren(); ///makes an Oct with this node as the child specified by octant Oct* makeParent(const int octant[3]); Oct* makeContains(const float pointToContain[3]); float distToPoint(const float point[3]); float distSquaredToPoint(const float point[3]); bool lineIntersects(const float p1[3], const float p2[3]); bool rayIntersects(const float start[3], const float p2[3]); bool lineSegmentIntersects(const float start[3], const float end[3]); bool pointInside(const float point[3]); bool boundsOverlaps(const float minCoords[3], const float maxCoords[3]); ///returns which child Oct the point would be contained in if the point were inside this Oct Oct* containingChild(const float point[3], int* whichOct = NULL); }; ///simple templated vector pointer that can be deleted, since you shouldn't rely on any method for actually deleting a vector's memory, for convenience template struct LeafVector { std::vector* m_vector; LeafVector() { m_vector = new std::vector(); } ~LeafVector() { freeData(); } void freeData() { if (m_vector != NULL) { delete m_vector; m_vector = NULL; } } T& operator[](const int64_t index) { return (*m_vector)[index]; } const T& operator[](const int64_t index) const { return (*m_vector)[index]; } }; template Oct::Oct() { for (int i = 0; i < 2; ++i) { m_children[i][0][0] = NULL; m_children[i][0][1] = NULL; m_children[i][1][0] = NULL; m_children[i][1][1] = NULL; } m_parent = NULL; m_leaf = true; } template Oct::Oct(const float minCoords[3], const float maxCoords[3]) { for (int i = 0; i < 2; ++i) { m_children[i][0][0] = NULL; m_children[i][0][1] = NULL; m_children[i][1][0] = NULL; m_children[i][1][1] = NULL; } m_parent = NULL; m_leaf = true; for (int i = 0; i < 3; ++i) { m_bounds[i][0] = minCoords[i]; m_bounds[i][2] = maxCoords[i]; m_bounds[i][1] = (m_bounds[i][0] + m_bounds[i][2]) * 0.5f; } } template Oct::~Oct() { deleteChildren(); } template void Oct::makeChildren() { m_leaf = false; int ijk[3]; for (ijk[0] = 0; ijk[0] < 2; ++ijk[0]) { for (ijk[1] = 0; ijk[1] < 2; ++ijk[1]) { for (ijk[2] = 0; ijk[2] < 2; ++ijk[2]) { Oct* temp = new Oct(); m_children[ijk[0]][ijk[1]][ijk[2]] = temp; temp->m_parent = this; for (int m = 0; m < 3; ++m) { temp->m_bounds[m][0] = m_bounds[m][ijk[m]]; temp->m_bounds[m][2] = m_bounds[m][ijk[m] + 1]; temp->m_bounds[m][1] = (temp->m_bounds[m][0] + temp->m_bounds[m][2]) * 0.5f; } } } } } template void Oct::makeChildrenExcept(const int octant[3]) { m_leaf = false; int ijk[3]; for (ijk[0] = 0; ijk[0] < 2; ++ijk[0]) { for (ijk[1] = 0; ijk[1] < 2; ++ijk[1]) { for (ijk[2] = 0; ijk[2] < 2; ++ijk[2]) { if (ijk[0] != octant[0] && ijk[1] != octant[1] && ijk[2] != octant[2]) {//avoiding one new/delete pair should be worth 8 times this conditional Oct* temp = new Oct(); m_children[ijk[0]][ijk[1]][ijk[2]] = temp; temp->m_parent = this; for (int m = 0; m < 3; ++m) { temp->m_bounds[m][0] = m_bounds[m][ijk[m]]; temp->m_bounds[m][2] = m_bounds[m][ijk[m] + 1]; temp->m_bounds[m][1] = (temp->m_bounds[m][0] + temp->m_bounds[m][2]) * 0.5f; } } } } } } template void Oct::deleteChildren() { m_leaf = true; for (int i = 0; i < 2; ++i) { for (int j = 0; j < 2; ++j) { for (int k = 0; k < 2; ++k) { if (m_children[i][j][k] != NULL) { delete m_children[i][j][k]; m_children[i][j][k] = NULL; } } } } } template Oct* Oct::makeParent(const int octant[3]) { Oct* ret = new Oct(); for (int i = 0; i < 3; ++i) { ret->m_bounds[i][octant[i]] = m_bounds[i][0]; ret->m_bounds[i][octant[i] + 1] = m_bounds[i][2]; ret->m_bounds[i][(octant[i] + 2) % 3] = (octant[i] ? (2.0f * m_bounds[i][0] - m_bounds[i][2]) : (2.0f * m_bounds[i][2] - m_bounds[i][0])); } ret->makeChildrenExcept(octant); ret->m_children[octant[0]][octant[1]][octant[2]] = this; m_parent = ret; return ret; } template Oct* Oct::makeContains(const float pointToContain[3]) { Oct* ret = this; while (!ret->pointInside(pointToContain)) { int octant[3]; octant[0] = (pointToContain[0] < m_bounds[0][1] ? 1 : 0);//use midpoint to intelligently pick best division when more than one division would contain it octant[1] = (pointToContain[1] < m_bounds[1][1] ? 1 : 0); octant[2] = (pointToContain[2] < m_bounds[2][1] ? 1 : 0); ret = ret->makeParent(octant); } return ret; } template float Oct::distToPoint(const float point[3]) { float temp[3]; for (int i = 0; i < 3; ++i) { if (point[i] < m_bounds[i][0]) { temp[i] = m_bounds[i][0] - point[i]; } else { if (point[i] > m_bounds[i][2]) { temp[i] = m_bounds[i][2] - point[i]; } else { temp[i] = 0.0f; } } } return MathFunctions::vectorLength(temp); } template float Oct::distSquaredToPoint(const float point[3]) { float temp[3]; for (int i = 0; i < 3; ++i) { if (point[i] < m_bounds[i][0]) { temp[i] = m_bounds[i][0] - point[i]; } else { if (point[i] > m_bounds[i][2]) { temp[i] = m_bounds[i][2] - point[i]; } else { temp[i] = 0.0f; } } } return temp[0] * temp[0] + temp[1] * temp[1] + temp[2] * temp[2]; } template bool Oct::lineIntersects(const float p1[3], const float p2[3]) { float direction[3]; float curlow = 1.0f, curhigh = -1.0f;//quiet compiler, make default say "false", but we use pointInside logic on zero length queries MathFunctions::subtractVectors(p2, p1, direction); bool first = true; for (int i = 0; i < 3; ++i) { if (direction[i] != 0.0f) { float templow; float temphigh; if (direction[i] > 0.0f) { templow = (m_bounds[i][0] - p1[i]) / direction[i];//compute the range of t over which this line lies between the planes for this axis temphigh = (m_bounds[i][2] - p1[i]) / direction[i]; } else { templow = (m_bounds[i][2] - p1[i]) / direction[i];//compute the range of t over which this line lies between the planes for this axis temphigh = (m_bounds[i][0] - p1[i]) / direction[i]; } if (first) { first = false; curlow = templow; curhigh = temphigh; } else { if (templow > curlow) curlow = templow;//intersect the ranges if (temphigh < curhigh) curhigh = temphigh; } if (curhigh < curlow) return false;//if intersection is null, false } else { if (p1[i] < m_bounds[i][0] || p1[i] > m_bounds[i][2]) return false; } } return true; } template bool Oct::rayIntersects(const float start[3], const float p2[3]) { float direction[3]; float curlow = 1.0f, curhigh = -1.0f;//quiet compiler, make default say "false", but we use pointInside logic on zero length queries MathFunctions::subtractVectors(p2, start, direction); bool first = true; for (int i = 0; i < 3; ++i) { if (direction[i] != 0.0f) { float templow; float temphigh; if (direction[i] > 0.0f) { templow = (m_bounds[i][0] - start[i]) / direction[i];//compute the range of t over which this line lies between the planes for this axis temphigh = (m_bounds[i][2] - start[i]) / direction[i]; } else { templow = (m_bounds[i][2] - start[i]) / direction[i];//compute the range of t over which this line lies between the planes for this axis temphigh = (m_bounds[i][0] - start[i]) / direction[i]; } if (first) { first = false; curlow = templow; curhigh = temphigh; } else { if (templow > curlow) curlow = templow;//intersect the ranges if (temphigh < curhigh) curhigh = temphigh; } if (curhigh < curlow || curhigh < 0.0f) return false;//if intersection is null or has no positive range, false } else { if (start[i] < m_bounds[i][0] || start[i] > m_bounds[i][2]) return false; } } return true; } template bool Oct::lineSegmentIntersects(const float start[3], const float end[3]) { float direction[3]; float curlow = 1.0f, curhigh = -1.0f;//quiet compiler, make default say "false", but we use pointInside logic on zero length queries MathFunctions::subtractVectors(end, start, direction);//parameterize the line segment to the range [0, 1] of t bool first = true; for (int i = 0; i < 3; ++i) { if (direction[i] != 0.0f) { float templow; float temphigh; if (direction[i] > 0.0f) { templow = (m_bounds[i][0] - start[i]) / direction[i];//compute the range of t over which this line lies between the planes for this axis temphigh = (m_bounds[i][2] - start[i]) / direction[i]; } else { templow = (m_bounds[i][2] - start[i]) / direction[i];//compute the range of t over which this line lies between the planes for this axis temphigh = (m_bounds[i][0] - start[i]) / direction[i]; } if (first) { first = false; curlow = templow; curhigh = temphigh; } else { if (templow > curlow) curlow = templow;//intersect the ranges if (temphigh < curhigh) curhigh = temphigh; } if (curhigh < curlow || curhigh < 0.0f || curlow > 1.0f) return false;//if intersection is null or has no positive range, or has no range less than 1, false } else { if (start[i] < m_bounds[i][0] || start[i] > m_bounds[i][2]) return false; } } return true; } template bool Oct::pointInside(const float point[3]) { for (int i = 0; i < 3; ++i) { if (point[i] < m_bounds[i][0] || point[i] > m_bounds[i][2]) return false;//be permissive, equal to boundary falls into both, though for traversal, strictly less than the boundary is the test condition } return true; } template bool Oct::boundsOverlaps(const float minCoords[3], const float maxCoords[3]) { for (int i = 0; i < 3; ++i) { if (maxCoords[i] < m_bounds[i][0] || minCoords[i] > m_bounds[i][2]) return false;//be permissive, equal to boundary falls into both } return true; } template Oct* Oct::containingChild(const float point[3], int* whichOct) { int myOct[3]; for (int i = 0; i < 3; ++i) { myOct[i] = (point[i] < m_bounds[i][1] ? 0 : 1);//strictly less than, using only the midpoint is how traversal works, even if the point isn't inside the Oct if (whichOct != NULL) whichOct[i] = myOct[i]; } return m_children[myOct[0]][myOct[1]][myOct[2]]; } } #endif //__OCT_TREE_H__ connectome-workbench-1.4.2/src/Common/OpenGLDrawingMethodEnum.cxx000066400000000000000000000252501360521144700250300ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __OPEN_G_L_DRAWING_METHOD_ENUM_DECLARE__ #include "OpenGLDrawingMethodEnum.h" #undef __OPEN_G_L_DRAWING_METHOD_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::OpenGLDrawingMethodEnum * \brief * * * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_openGLDrawingMethodEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void openGLDrawingMethodEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "OpenGLDrawingMethodEnum.h" * * Instatiate: * m_openGLDrawingMethodEnumComboBox = new EnumComboBoxTemplate(this); * m_openGLDrawingMethodEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_openGLDrawingMethodEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(openGLDrawingMethodEnumComboBoxItemActivated())); * * Update the selection: * m_openGLDrawingMethodEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const OpenGLDrawingMethodEnum::Enum VARIABLE = m_openGLDrawingMethodEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ OpenGLDrawingMethodEnum::OpenGLDrawingMethodEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ OpenGLDrawingMethodEnum::~OpenGLDrawingMethodEnum() { } /** * Initialize the enumerated metadata. */ void OpenGLDrawingMethodEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(OpenGLDrawingMethodEnum(DRAW_WITH_VERTEX_BUFFERS_OFF, "DRAW_WITH_VERTEX_BUFFERS_OFF", "Off")); enumData.push_back(OpenGLDrawingMethodEnum(DRAW_WITH_VERTEX_BUFFERS_ON, "DRAW_WITH_VERTEX_BUFFERS_ON", "On")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const OpenGLDrawingMethodEnum* OpenGLDrawingMethodEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const OpenGLDrawingMethodEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString OpenGLDrawingMethodEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const OpenGLDrawingMethodEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ OpenGLDrawingMethodEnum::Enum OpenGLDrawingMethodEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = OpenGLDrawingMethodEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const OpenGLDrawingMethodEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type OpenGLDrawingMethodEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString OpenGLDrawingMethodEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const OpenGLDrawingMethodEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ OpenGLDrawingMethodEnum::Enum OpenGLDrawingMethodEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = OpenGLDrawingMethodEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const OpenGLDrawingMethodEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type OpenGLDrawingMethodEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t OpenGLDrawingMethodEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const OpenGLDrawingMethodEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ OpenGLDrawingMethodEnum::Enum OpenGLDrawingMethodEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = OpenGLDrawingMethodEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const OpenGLDrawingMethodEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type OpenGLDrawingMethodEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void OpenGLDrawingMethodEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void OpenGLDrawingMethodEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(OpenGLDrawingMethodEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void OpenGLDrawingMethodEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(OpenGLDrawingMethodEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/OpenGLDrawingMethodEnum.h000066400000000000000000000062711360521144700244570ustar00rootroot00000000000000#ifndef __OPEN_G_L_DRAWING_METHOD_ENUM_H__ #define __OPEN_G_L_DRAWING_METHOD_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class OpenGLDrawingMethodEnum { public: /** * Enumerated values. */ enum Enum { /** OpenGL Vertex Buffers Off */ DRAW_WITH_VERTEX_BUFFERS_OFF, /** OpenGL Vertex Buffers On */ DRAW_WITH_VERTEX_BUFFERS_ON }; ~OpenGLDrawingMethodEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: OpenGLDrawingMethodEnum(const Enum enumValue, const AString& name, const AString& guiName); static const OpenGLDrawingMethodEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __OPEN_G_L_DRAWING_METHOD_ENUM_DECLARE__ std::vector OpenGLDrawingMethodEnum::enumData; bool OpenGLDrawingMethodEnum::initializedFlag = false; int32_t OpenGLDrawingMethodEnum::integerCodeCounter = 0; #endif // __OPEN_G_L_DRAWING_METHOD_ENUM_DECLARE__ } // namespace #endif //__OPEN_G_L_DRAWING_METHOD_ENUM_H__ connectome-workbench-1.4.2/src/Common/PlainTextStringBuilder.cxx000066400000000000000000000051451360521144700250110ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __PLAIN_TEXT_STRING_BUILDER_DECLARE__ #include "PlainTextStringBuilder.h" #undef __PLAIN_TEXT_STRING_BUILDER_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" using namespace caret; /** * \class caret::PlainTextStringBuilder * \brief * \ingroup Common * * */ /** * Constructor. */ PlainTextStringBuilder::PlainTextStringBuilder() : CaretObject() { m_currentIndentationCount = 0; m_indentationNumberOfSpaces = 3; } /** * Constructor. */ PlainTextStringBuilder::PlainTextStringBuilder(const int32_t indentationNumberOfSpaces) : CaretObject() { m_currentIndentationCount = 0; m_indentationNumberOfSpaces = indentationNumberOfSpaces; } /** * Destructor. */ PlainTextStringBuilder::~PlainTextStringBuilder() { } /** * Clear the text. Does not change amount of indentation. */ void PlainTextStringBuilder::clear() { m_text = ""; } /** * Increase the indentation. */ void PlainTextStringBuilder::pushIndentation() { m_currentIndentationCount += m_indentationNumberOfSpaces; } /** * Decrease the indentation. */ void PlainTextStringBuilder::popIndentation() { m_currentIndentationCount -= m_indentationNumberOfSpaces; if (m_currentIndentationCount < 0) { CaretLogSevere("Indentation pops exceeds pushes (indent < 0)"); m_currentIndentationCount = 0; } } /** * Add the text preceded by indentation and followed by a newline. * * @param text * Text that is added. */ void PlainTextStringBuilder::addLine(const AString& text) { m_text += (AString().fill(' ', m_currentIndentationCount) + text + "\n"); } /** * @return The text */ AString PlainTextStringBuilder::getText() const { return m_text; } connectome-workbench-1.4.2/src/Common/PlainTextStringBuilder.h000066400000000000000000000040371360521144700244350ustar00rootroot00000000000000#ifndef __PLAIN_TEXT_STRING_BUILDER_H__ #define __PLAIN_TEXT_STRING_BUILDER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" namespace caret { class PlainTextStringBuilder : public CaretObject { public: PlainTextStringBuilder(); PlainTextStringBuilder(const int32_t indentationNumberOfSpaces); virtual ~PlainTextStringBuilder(); void clear(); void pushIndentation(); void popIndentation(); /** Add the text preceded by indentation and followed by a newline */ void addLine(const AString& text); /** Get the text */ AString getText() const; private: PlainTextStringBuilder(const PlainTextStringBuilder&); PlainTextStringBuilder& operator=(const PlainTextStringBuilder&); AString m_text; int32_t m_indentationNumberOfSpaces; int32_t m_currentIndentationCount; // ADD_NEW_MEMBERS_HERE }; #ifdef __PLAIN_TEXT_STRING_BUILDER_DECLARE__ // #endif // __PLAIN_TEXT_STRING_BUILDER_DECLARE__ } // namespace #endif //__PLAIN_TEXT_STRING_BUILDER_H__ connectome-workbench-1.4.2/src/Common/Plane.cxx000066400000000000000000000353571360521144700214520ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "MathFunctions.h" #include "Plane.h" using namespace caret; /** * Construct an invalid plane. * Intended for use by the assignement operator. */ Plane::Plane() : CaretObject() { m_pointOnPlane[0] = 0.0; m_pointOnPlane[1] = 0.0; m_pointOnPlane[2] = 0.0; m_normalVector[0] = 0.0; m_normalVector[1] = 0.0; m_normalVector[2] = 0.0; m_validPlaneFlag = false; m_A = m_normalVector[0]; m_B = m_normalVector[1]; m_C = m_normalVector[2]; m_D = 0.0; } /** * Construct a plane from three points that are on the plane. * These points should be in counter-clockwise order. * * @param p1 Point on plane. * @param p2 Point on plane. * @param p3 Point on plane. * */ Plane::Plane(const float p1[3], const float p2[3], const float p3[3]) : CaretObject() { m_pointOnPlane[0] = p1[0]; m_pointOnPlane[1] = p1[1]; m_pointOnPlane[2] = p1[2]; double p2d[3] = { p2[0], p2[1], p2[2] }; double p3d[3] = { p3[0], p3[1], p3[2] }; m_validPlaneFlag = MathFunctions::normalVector(m_pointOnPlane, p2d, p3d, m_normalVector); // // Compute the plane equation // m_A = m_normalVector[0]; m_B = m_normalVector[1]; m_C = m_normalVector[2]; m_D = -(m_A*p1[0] + m_B*p1[1] + m_C*p1[2]); } /** * Construct a plane from a unit normal vector (length = 1) and a point on the plane. * * @param normalVector * The normal vector of the plane. * @param pointOnPlane * A point on the plane. */ Plane::Plane(const float unitNormalVector[3], const float pointOnPlane[3]) { m_pointOnPlane[0] = pointOnPlane[0]; m_pointOnPlane[1] = pointOnPlane[1]; m_pointOnPlane[2] = pointOnPlane[2]; m_normalVector[0] = unitNormalVector[0]; m_normalVector[1] = unitNormalVector[1]; m_normalVector[2] = unitNormalVector[2]; m_A = m_normalVector[0]; m_B = m_normalVector[1]; m_C = m_normalVector[2]; m_D = (-m_A * m_pointOnPlane[0] -m_B * m_pointOnPlane[1] -m_C * m_pointOnPlane[2]); m_validPlaneFlag = (MathFunctions::vectorLength(m_normalVector) > 0.0); } /** * Copy constructor. * @param p * Object that is copied. */ Plane::Plane(const Plane& p) : CaretObject(p) { this->copyHelperPlane(p); } /** * Assignment operator. * @param p * Data copied from obj to this. * @return * Reference to this object. */ Plane& Plane::operator=(const Plane& p) { if (this != &p) { CaretObject::operator=(p); this->copyHelperPlane(p); } return *this; } /** * Helps with copying an object of this type. * @param p * Object that is copied. */ void Plane::copyHelperPlane(const Plane& p) { m_A = p.m_A; m_B = p.m_B; m_C = p.m_C; m_D = p.m_D; m_normalVector[0] = p.m_normalVector[0]; m_normalVector[1] = p.m_normalVector[1]; m_normalVector[2] = p.m_normalVector[2]; m_pointOnPlane[0] = p.m_pointOnPlane[0]; m_pointOnPlane[1] = p.m_pointOnPlane[1]; m_pointOnPlane[2] = p.m_pointOnPlane[2]; m_validPlaneFlag = p.m_validPlaneFlag; } /** * Destructor */ Plane::~Plane() { } /** * Is the plane valid? * @return true if plane is valid, else false. * */ bool Plane::isValidPlane() const { return m_validPlaneFlag; } /** * Find the points where a triangle intersects the plane. * @param t1 First point in triangle. * @param t2 Second point in triangle. * @param t3 Third point in triangle. * @param intersectionPointOut1 If there is intersection, * this will be loaded with one intersection point. * @param intersectionPointOut2 If there is intersection, * this will be loaded with other intersection point. * @return true if any two edges of the triangle intersect * the plane, else false. * */ bool Plane::triangleIntersectPlane( const float t1[3], const float t2[3], const float t3[3], float intersectionPointOut1[3], float intersectionPointOut2[3]) const { float* intersection = intersectionPointOut1; int count = 0; if (lineSegmentIntersectPlane(t1, t2, intersection)) { count++; intersection = intersectionPointOut2; } if (lineSegmentIntersectPlane(t2, t3, intersection)) { count++; if (count == 2) { return true; } intersection = intersectionPointOut2; } if (lineSegmentIntersectPlane(t3, t1, intersection)) { count++; if (count == 2) { return true; } } return false; } /** * Get the plane. * * @param aOut * The value of 'A' * @param bOut * The value of 'B' * @param cOut * The value of 'C' * @param dOut * The value of 'D' */ void Plane::getPlane(double& aOut, double& bOut, double& cOut, double& dOut) const { aOut = m_A; bOut = m_B; cOut = m_C; dOut = m_D; } /** * Get the plane's normal vector. * * @param normalVectorOut * On exit, contains the plane's normal vector. */ void Plane::getNormalVector(double normalVectorOut[3]) const { normalVectorOut[0] = m_normalVector[0]; normalVectorOut[1] = m_normalVector[1]; normalVectorOut[2] = m_normalVector[2]; } /** * Get the plane's normal vector. * * @param normalVectorOut * On exit, contains the plane's normal vector. */ void Plane::getNormalVector(float normalVectorOut[3]) const { normalVectorOut[0] = m_normalVector[0]; normalVectorOut[1] = m_normalVector[1]; normalVectorOut[2] = m_normalVector[2]; } /** * Get absolute distance of point from the plane. * @param p Point. * @return Absolute distance of "p" from plane. * */ double Plane::absoluteDistanceToPlane(const float p[3]) const { double dist = (m_A * p[0] + m_B * p[1] + m_C * p[2] + m_D); if (dist < 0.0f) dist = -dist; return dist; } /** * Get signed distance of point from the plane. * @param p Point. * @return Signed distance of "p" from plane. * */ double Plane::signedDistanceToPlane(const float p[3]) const { double dist = (m_A * p[0] + m_B * p[1] + m_C * p[2] + m_D); return dist; } /** * Find the intersection of a line segment with the plane. * @param lp1 start of line. * @param lp2 end of line. * @param intersectionOut If the line intersects the plane, * the point of intersection will be loaded into this. If * there is no intersection, the values of this array will * not be altered. * @return true if the line segment intersects the plane, * else false. * */ bool Plane::lineSegmentIntersectPlane( const float lp1[3], const float lp2[3], float intersectionOut[3]) const { /* * Ray formed by lp1 ==> lp2 (NOT a unit vector; do not normalize) */ double r0 = lp2[0] - lp1[0]; double r1 = lp2[1] - lp1[1]; double r2 = lp2[2] - lp1[2]; /* * Denominator is dot product of the plane's normal * and the ray. If it is zero, that means the ray * is parallel to the plane. * * Perhaps should test for value near zero, and, * if it is, see if line end points are very * close to plane, and, if so, use the line * endpoints, projected to the plane, as the * intersection. */ double denominator = (m_A * r0) + (m_B * r1) + (m_C * r2); if (denominator == 0.0) { return false; } /* * "t" is the normalized distance of plane from the line origin to * the endpoint of the line. * * (0 <= t <= 1): The line intersects the plane with one point * above the plane and one point below the plane. * * (t > 1): Vector (P1, P2) point towards plane but both are * on same side of the plane. * * (t < 0): Vector (P1, P2) point away from plane but both are * on same side of the plane. */ double numerator = -((m_A * lp1[0]) + (m_B * lp1[1]) + (m_C * lp1[2]) + m_D); double t = numerator / denominator; if ((t >= 0.0f) && (t <= 1.0f)) { intersectionOut[0] = (float)(lp1[0] + r0 * t); intersectionOut[1] = (float)(lp1[1] + r1 * t); intersectionOut[2] = (float)(lp1[2] + r2 * t); return true; } return false; } /** * Project the given point to the plane. * @param pointIn * Point that will be projected. * @param pointProjectedOut * Coordinates of point after projection to the plane. */ void Plane::projectPointToPlane(const float pointIn[3], float pointProjectedOut[3]) const { double xo[3] = { pointIn[0] - m_pointOnPlane[0], pointIn[1] - m_pointOnPlane[1], pointIn[2] - m_pointOnPlane[2] }; float t = MathFunctions::dotProduct(m_normalVector, xo); pointProjectedOut[0] = pointIn[0] - (t * m_normalVector[0]); pointProjectedOut[1] = pointIn[1] - (t * m_normalVector[1]); pointProjectedOut[2] = pointIn[2] - (t * m_normalVector[2]); } /** * Determine if and where a ray intersects the plane. * * @param rayOrigin * Origin of the ray * @param rayVector * Vector defining the ray. * @param intersectionXYZandDistance * Coordinate of where the ray intersects the plane (XYZ) and the * distance of the ray origin from the plane. * @return * True if the ray intersects the plane, else false. */ bool Plane::rayIntersection(const float rayOrigin[3], const float rayVector[3], float intersectionXYZandDistance[4]) { /* Convert the ray into a unit vector * */ double ray[3] = { rayVector[0], rayVector[1], rayVector[2] }; MathFunctions::normalizeVector(ray); /* * Parametric coordinate of where ray intersects plane */ double denom = m_A * ray[0] + m_B * ray[1] + m_C * ray[2]; if (denom != 0) { const double t = -(m_A * rayOrigin[0] + m_B * rayOrigin[1] + m_C * rayOrigin[2] + m_D) / denom; intersectionXYZandDistance[0] = (float)(rayOrigin[0] + ray[0] * t); intersectionXYZandDistance[1] = (float)(rayOrigin[1] + ray[1] * t); intersectionXYZandDistance[2] = (float)(rayOrigin[2] + ray[2] * t); intersectionXYZandDistance[3] = (float)t; return true; } return false; } /** * @return String describing the plane. * */ AString Plane::toString() const { AString s; if (isValidPlane()) { s = (AString::number(m_A) + "x + " + AString::number(m_B) + "y + " + AString::number(m_C) + "z + " + AString::number(m_D)); } else { s = "invalid"; } return s; } /** * Unit test the class. * */ void Plane::unitTest(std::ostream& stream, const bool /*isVerbose*/) { stream << "Plane::unitTest is starting" << std::endl; Plane::unitTest1(stream); Plane::unitTest2(stream); Plane::unitTest3(stream); stream << "Plane::unitTest has ended" << std::endl; } /** * Unit test a plane and line intersection. * @param testName Name of test. * @param p1 Plane Point 1. * @param p2 Plane Point 2. * @param p3 Plane Point 3. * @param l1 Line End Point 1. * @param l2 Line End Point 2. * @param correctIntersectionPoint * @param intersectionValid * */ void Plane::unitTestLineIntersectPlane(std::ostream& stream, const AString& testName, const float p1[3], const float p2[3], const float p3[3], const float l1[3], const float l2[3], const float correctIntersectionPoint[3], const bool intersectionValid) { float intersection[3]; Plane p(p1, p2, p3); bool result = p.lineSegmentIntersectPlane(l1, l2, intersection); AString sb; if (intersectionValid && result) { if (MathFunctions::compareArrays(correctIntersectionPoint, intersection, 3, 0.001f)) { return; } sb.append("Intersection should be " + AString::fromNumbers(correctIntersectionPoint, 3, ",")); sb.append(" but is " + AString::fromNumbers(intersection, 3, ",")); } else if (intersectionValid != result) { sb.append("intersection " + AString::fromBool(result) + " but should be " + AString::fromBool(intersectionValid)); } if (sb.length() > 0) { sb = ("Line/Plane Intersection Test " + testName + " FAILED: " + sb); stream << sb.toStdString() << std::endl; } } void Plane::unitTest1(std::ostream& stream) { float p1[] = { -50.0f, -60.0f, 2.0f }; float p2[] = { 50.0f, -60.0f, 2.0f }; float p3[] = { 50.0f, 60.0f, 2.0f }; float l1[] = { 25.0f, 10.0f, -3.0f }; float l2[] = { 25.0f, 10.0f, 7.0f }; float correctIntersectionPoint[] = { 25.0f, 10.0f, 2.0f }; Plane::unitTestLineIntersectPlane(stream, "1", p1, p2, p3, l1, l2, correctIntersectionPoint, true); } void Plane::unitTest2(std::ostream& stream) { float p1[] = { -50.0f, -60.0f, 2.0f }; float p2[] = { 50.0f, -60.0f, 2.0f }; float p3[] = { 50.0f, 60.0f, 2.0f }; float l1[] = { 25.0f, 10.0f, 7.0f }; float l2[] = { 25.0f, 10.0f, 9.0f }; float correctIntersectionPoint[3]; Plane::unitTestLineIntersectPlane(stream, "2", p1, p2, p3, l1, l2, correctIntersectionPoint, false);} void Plane::unitTest3(std::ostream& stream) { float p1[] = { -50.0f, -60.0f, 2.0f }; float p2[] = { 50.0f, -60.0f, 2.0f }; float p3[] = { 50.0f, 60.0f, 2.0f }; float l1[] = { 25.0f, 10.0f, -5.0f }; float l2[] = { 25.0f, 10.0f, -3.0f }; float correctIntersectionPoint[3]; Plane::unitTestLineIntersectPlane(stream, "3", p1, p2, p3, l1, l2, correctIntersectionPoint, false); } connectome-workbench-1.4.2/src/Common/Plane.h000066400000000000000000000077451360521144700210770ustar00rootroot00000000000000#ifndef __PLANE_H__ #define __PLANE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" namespace caret { ///Operations on a plane. class Plane : public CaretObject { public: Plane(); Plane(const float p1[3], const float p2[3], const float p3[3]); Plane(const float unitNormalVector[3], const float pointOnPlane[3]); virtual ~Plane(); Plane(const Plane& p); Plane& operator=(const Plane& p); bool isValidPlane() const; bool triangleIntersectPlane( const float t1[3], const float t2[3], const float t3[3], float intersectionPointOut1[3], float intersectionPointOut2[3]) const; double absoluteDistanceToPlane(const float p[3]) const; double signedDistanceToPlane(const float p[3]) const; bool lineSegmentIntersectPlane( const float lp1[3], const float lp2[3], float intersectionOut[3]) const; void projectPointToPlane(const float pointIn[3], float pointProjectedOut[3]) const; void getPlane(double& aOut, double& bOut, double& cOut, double& dOut) const; void getNormalVector(double normalVectorOut[3]) const; void getNormalVector(float normalVectorOut[3]) const; bool rayIntersection(const float rayOrigin[3], const float rayVector[3], float intersectionXYZandDistance[4]); virtual AString toString() const; static void unitTest(std::ostream& stream, const bool isVerbose); private: static void unitTestLineIntersectPlane(std::ostream& stream, const AString& testName, const float p1[3], const float p2[3], const float p3[3], const float l1[3], const float l2[3], const float correctIntersectionPoint[3], const bool intersectionValid); static void unitTest1(std::ostream& stream); static void unitTest2(std::ostream& stream); static void unitTest3(std::ostream& stream); void copyHelperPlane(const Plane& p); double m_pointOnPlane[3]; double m_normalVector[3]; bool m_validPlaneFlag; double m_A; double m_B; double m_C; double m_D; }; } // namespace #endif // __PLANE_H__ connectome-workbench-1.4.2/src/Common/ProgramParameters.cxx000066400000000000000000000216071360521144700240370ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretAssert.h" #include "ProgramParameters.h" using namespace caret; /** * Constructor. * * @param argc * Number of parameters. * @param argv * Array containing the parameters. */ ProgramParameters::ProgramParameters(int argc, const char *const argv[]) : CaretObject() { this->initializeMembersProgramParameters(); if (argc > 0) { this->programName = AString::fromLocal8Bit(argv[0]); } for (int32_t i = 1; i < argc; i++) { this->addParameter(AString::fromLocal8Bit(argv[i])); } } /** * Constructor. */ ProgramParameters::ProgramParameters() : CaretObject() { this->initializeMembersProgramParameters(); } /** * Destructor */ ProgramParameters::~ProgramParameters() { this->initializeMembersProgramParameters(); } void ProgramParameters::initializeMembersProgramParameters() { this->parameterIndex = 0; this->parameters.clear(); } /** * Add a parameter. * @param p New parameter. * */ void ProgramParameters::addParameter(const AString& p) { this->parameters.push_back(p); } /** * See if there are more parameters available. * * @return true if more parameters available else false. * */ bool ProgramParameters::hasNext() const { return (this->parameterIndex < static_cast(this->parameters.size())); } /** * Verifies that all parameters have been processed. * * @throws ProgramParametersException If there are more parameters. * */ void ProgramParameters::verifyAllParametersProcessed() { if (this->hasNext()) { throw ProgramParametersException("Unexpected parameter: " + nextString("unexpected")); } } /** * Get the next parameter as a string. * * @param parameterName - name of the parameter. * @return The parameter. * @throws ProgramParametersException If there are no more parameters. * */ AString ProgramParameters::nextString(const AString& parameterName) { if (this->hasNext() == false) { throw ProgramParametersException(parameterName + " is missing (No more parameters)."); } CaretAssertVectorIndex(this->parameters, this->parameterIndex); AString s = this->parameters[this->parameterIndex]; this->parameterIndex++; return s; } /** * Get the next parameter as a boolean * * @param parameterName - name of the parameter. * @return boolean value of parameter. * * @throws ProgramParametersException If there are no more parameters or the * next parameter does not represent a boolean value. * */ bool ProgramParameters::nextBoolean(const AString& parameterName) { AString s = this->nextString(parameterName).toLower(); if ((s == "true") || (s == "t")) { return true; } else if ((s == "false") || (s == "f")) { return false; } throw ProgramParametersException(parameterName + " is not a boolean value (true/false) but is \"" + s + "\"."); return false; } /** * Get the next parameter as a int. * * @param parameterName - name of the parameter. * @return int value of parameter. * @throws ProgramParametersException If there are no more parameters or the * next parameter does not represent an integer value. * */ int32_t ProgramParameters::nextInt(const AString& parameterName) { AString s = this->nextString(parameterName); bool ok = false; int32_t i = s.toInt(&ok); if (!ok) { throw ProgramParametersException(parameterName + " needs an integer, got \"" + s + "\"."); } return i; } /** * Get the next parameter as a long. * * @param parameterName - name of the parameter. * @return inlongt value of parameter. * @throws ProgramParametersException If there are no more parameters or the * next parameter does not represent an integer value. * */ int64_t ProgramParameters::nextLong(const AString& parameterName) { AString s = this->nextString(parameterName); bool ok = false; int64_t i = s.toLong(&ok); if (!ok) { throw ProgramParametersException(parameterName + " needs an integer, got \"" + s + "\"."); } return i; } /** * Get the next parameter as a float. * * @param parameterName - name of the parameter. * @return float value of parameter. * @throws ProgramParametersException If there are no more parameters or the * next parameter does not represent an float value. * */ float ProgramParameters::nextFloat(const AString& parameterName) { AString s = this->nextString(parameterName); bool ok = false; float f = s.toFloat(&ok); if (!ok) { throw ProgramParametersException(parameterName + " needs a floating point, got \"" + s + "\"."); } return f; } /** * Get the next parameter as a double. * * @param parameterName - name of the parameter. * @return double value of parameter. * @throws ProgramParametersException If there are no more parameters or the * next parameter does not represent an double value. * */ double ProgramParameters::nextDouble(const AString& parameterName) { AString s = this->nextString(parameterName); bool ok = false; double d = s.toDouble(&ok); if (!ok) { throw ProgramParametersException(parameterName + " needs a floating point, got \"" + s + "\"."); } return d; } /** * Backup to the previous parameter. If currently at the first * parameter, this command does nothing. * */ void ProgramParameters::backup() { if (this->parameterIndex > 0) { this->parameterIndex--; } } /** * Remove the parameter that was last retrieved with one of the * "next()" methods. */ void ProgramParameters::remove() { this->backup(); CaretAssertVectorIndex(this->parameters, this->parameterIndex); this->parameters.erase(this->parameters.begin() + this->parameterIndex); } /** * Get the current index of the parameter iterator. * @return Index of parameter iterator. * */ int32_t ProgramParameters::getParameterIndex() const { return this->parameterIndex; } /** * Set the current index of the parameter iterator. * @param indx New index of parameter iterator. * @throws ParameterException If index is not valid for parameters * unless the index is zero and there are no parameters. * */ void ProgramParameters::setParameterIndex(const int32_t indx) { CaretAssert(indx >= 0 && indx <= (int32_t)this->parameters.size());//less or equal to size is intentional, having an index of one past the end is a valid state, notably needed by setParameterIndex(0) on empty ProgramParameters this->parameterIndex = indx; } /** * Get the number of parameters. * * @return The number of parameters. * */ int32_t ProgramParameters::getNumberOfParameters() const { return this->parameters.size(); } /** * Get a parameter at the specified index. * * @param index - index of parameter. * @return The parameter at the specified index. * */ AString ProgramParameters::getParameter(const int32_t indx) const { CaretAssertVectorIndex(this->parameters, indx); return this->parameters[indx]; } /** * Get all of the parameters, separated by a space. * @return All parameters in a String. * */ AString ProgramParameters::getAllParametersInString() const { AString str; int num = this->getNumberOfParameters(); for (int i = 0; i < num; i++) { if (i > 0) { str += " "; } str += this->getParameter(i); } return str; } /** * Get all of the parameters, separated by a space. * @return All parameters in a String. * */ AString ProgramParameters::getAllParametersQuotedInString() const { AString str; int num = this->getNumberOfParameters(); for (int i = 0; i < num; i++) { if (i > 0) { str += " "; } str += "\"" + this->getParameter(i) + "\""; } return str; } /** * Get the name of the program. * @return * Name of the program. */ AString ProgramParameters::getProgramName() const { return this->programName; } connectome-workbench-1.4.2/src/Common/ProgramParameters.h000066400000000000000000000046641360521144700234700ustar00rootroot00000000000000#ifndef __PROGRAMPARAMETERS_H__ #define __PROGRAMPARAMETERS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "ProgramParametersException.h" #include #include #include namespace caret { /** * Simplifies access to program parameters. */ class ProgramParameters : public CaretObject { public: ProgramParameters(int argc, const char *const argv[]); ProgramParameters(); virtual ~ProgramParameters(); private: ProgramParameters(const ProgramParameters&); ProgramParameters& operator=(const ProgramParameters&); private: void initializeMembersProgramParameters(); public: void addParameter(const AString& p); bool hasNext() const; void verifyAllParametersProcessed(); AString nextString(const AString& parameterName); bool nextBoolean(const AString& parameterName); int32_t nextInt(const AString& parameterName); int64_t nextLong(const AString& parameterName); float nextFloat(const AString& parameterName); double nextDouble(const AString& parameterName); void backup(); void remove(); int32_t getParameterIndex() const; void setParameterIndex(const int32_t index); int32_t getNumberOfParameters() const; AString getParameter(const int32_t index) const; AString getAllParametersInString() const; AString getAllParametersQuotedInString() const; AString getProgramName() const; private: /**The parameters. */ std::vector parameters; /**Current index in parameters. */ int32_t parameterIndex; AString programName; }; } // namespace #endif // __PROGRAMPARAMETERS_H__ connectome-workbench-1.4.2/src/Common/ProgramParametersException.cxx000066400000000000000000000045031360521144700257120ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ProgramParametersException.h" #include using namespace caret; /** * Constructor. * */ ProgramParametersException::ProgramParametersException() : CaretException() { this->initializeMembersProgramParametersException(); } /** * Constructor that uses stack trace from the exception * passed in as a parameter. * * @param e Any exception whose stack trace becomes * this exception's stack trace. * */ ProgramParametersException::ProgramParametersException( const CaretException& e) : CaretException(e) { this->initializeMembersProgramParametersException(); } /** * Constructor. * * @param s Description of the exception. * */ ProgramParametersException::ProgramParametersException(const AString& s) : CaretException(s) { this->initializeMembersProgramParametersException(); } /** * Copy Constructor. * @param e * Exception that is copied. */ ProgramParametersException::ProgramParametersException(const ProgramParametersException& e) : CaretException(e) { } /** * Assignment operator. * @param e * Exception that is copied. * @return * Copy of the exception. */ ProgramParametersException& ProgramParametersException::operator=(const ProgramParametersException& e) { if (this != &e) { CaretException::operator=(e); } return *this; } /** * Destructor */ ProgramParametersException::~ProgramParametersException() throw() { } void ProgramParametersException::initializeMembersProgramParametersException() { } connectome-workbench-1.4.2/src/Common/ProgramParametersException.h000066400000000000000000000031501360521144700253340ustar00rootroot00000000000000#ifndef __PROGRAM_PARAMETERS_EXCEPTION_H__ #define __PROGRAM_PARAMETERS_EXCEPTION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretException.h" namespace caret { /** * An exception thrown during parameter processing. */ class ProgramParametersException : public CaretException { public: ProgramParametersException(); ProgramParametersException(const CaretException& e); ProgramParametersException(const AString& s); ProgramParametersException(const ProgramParametersException& e); ProgramParametersException& operator=(const ProgramParametersException& e); virtual ~ProgramParametersException() throw(); private: void initializeMembersProgramParametersException(); }; } // namespace #endif // __PROGRAM_PARAMETERS_EXCEPTION_H__ connectome-workbench-1.4.2/src/Common/ProgressObject.cxx000066400000000000000000000202121360521144700233260ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ProgressObject.h" #include "CaretAssert.h" #include "EventProgressUpdate.h" #include "EventManager.h" #include using namespace std; using namespace caret; ///decrease these values to reduce progress bar overhead everywhere ///or, manually set them for any fast algorithm that calls reportProgress a lot (or change it so it calls reportProgress less often) const float ProgressObject::MAX_CHILD_RESOLUTION = 0.01f;//up to 100 calls per child algorithm const float ProgressObject::MAX_INTERNAL_RESOLUTION = 0.001f;//up to 1000 calls during internal processing ProgressObject* ProgressObject::addAlgorithm(const float weight, const float childResolution) { CaretAssertMessage(weight > 0.0f, "nonpositive weight in ProgressObject::addAlgorithm"); if (m_disabled) return this;//disabled short circuits everything, can't track progress if an algorithm ignores and forwards the pointer ProgressInfo newInfo; newInfo.completed = false; newInfo.curProgress = 0.0f; newInfo.weight = weight; newInfo.progObjRef = new ProgressObject(weight, childResolution); newInfo.progObjRef->m_parent = this; newInfo.progObjRef->m_parentIndex = m_children.size(); m_children.push_back(newInfo); float childWeight = 0.0f; vector::iterator myend = m_children.end(); for (vector::iterator iter = m_children.begin(); iter != myend; ++iter) { childWeight += iter->weight; } m_totalWeight = childWeight + m_nonChildWeight; return newInfo.progObjRef; } void ProgressObject::algorithmStartSentinel() { if (m_sentinelPassed) { m_disabled = true;//if it hits start twice (passed through an algorithm without interaction), disable it } else { m_sentinelPassed = true; } } void ProgressObject::finishLevel() { if (m_finished) return;//don't finish twice m_currentProgress = m_totalWeight; m_finished = true; if (m_parent != NULL) { m_parent->m_children[m_parentIndex].completed = true; m_parent->updateProgress(); } EventProgressUpdate myUpdate(this); myUpdate.m_finished = true; EventManager::get()->sendEvent(myUpdate.getPointer()); } void ProgressObject::forceFinish() { finishLevel();//this function is mostly to insert the word "force" so people think twice about using it } float ProgressObject::getCurrentProgressFraction() { if (m_totalWeight <= 0.0f) return 0.0f; return m_currentProgress / m_totalWeight; } float ProgressObject::getCurrentProgressPercent() { return getCurrentProgressFraction() * 100.0f; } const AString& ProgressObject::getTaskDescription() { return m_description; } ProgressObject::ProgressObject(const float weight, const float childResolution) { m_currentProgress = 0.0f; m_disabled = false; m_finished = false; m_lastReported = 0.0f; m_nonChildProgress = 0.0f; m_nonChildWeight = weight; m_parent = NULL; m_sentinelPassed = false; m_totalWeight = weight; m_childResolution = childResolution; } LevelProgress::LevelProgress(ProgressObject* myProgObj, const float finishedProgress, const float internalWeight, const float internalResolution) { CaretAssertMessage(internalWeight > 0.0f, "nonpositive weight in ProgressObject::startLevel"); m_lastReported = 0.0f; m_maximum = finishedProgress; m_progObjRef = myProgObj; m_internalResolution = max(internalResolution, ProgressObject::MAX_INTERNAL_RESOLUTION);//the lower the value, the more often it updates if (m_progObjRef != NULL) { m_progObjRef->setInternalWeight(internalWeight); EventProgressUpdate myUpdate(myProgObj); myUpdate.m_starting = true; EventManager::get()->sendEvent(myUpdate.getPointer()); } } void ProgressObject::setInternalWeight(const float& myInternalWeight) { m_nonChildWeight = myInternalWeight; float childWeight = 0.0f; vector::iterator myend = m_children.end(); for (vector::iterator iter = m_children.begin(); iter != myend; ++iter) { childWeight += iter->weight; } m_totalWeight = childWeight + m_nonChildWeight; } void ProgressObject::updateProgress() { if (m_disabled) return; if (m_finished) { return;//nothing to do, finishLevel() should have taken care of everything } float totalWeightComplete = 0.0f;//recalculating the sum is thread-safe, as long as float assignment is atomic vector::iterator myend = m_children.end(); for (vector::iterator iter = m_children.end(); iter < myend; ++iter) { if (iter->completed) { totalWeightComplete += iter->weight; } else { totalWeightComplete += iter->curProgress * iter->weight; } } if (m_nonChildProgress > 0.0f && m_nonChildWeight > 0.0f) { totalWeightComplete += m_nonChildProgress * m_nonChildWeight; } if (totalWeightComplete < m_totalWeight) { if (totalWeightComplete < 0.0f) { m_currentProgress = 0.0f; } else { m_currentProgress = totalWeightComplete / m_totalWeight; } } else { m_currentProgress = 1.0f; } if (m_parent != NULL) { m_parent->m_children[m_parentIndex].curProgress = m_currentProgress; if (m_currentProgress - m_lastReported > m_childResolution) {//don't recurse unless progress has changed more than the resolution specified m_lastReported = m_currentProgress; m_parent->updateProgress(); } } EventProgressUpdate myUpdate(this);//just send the event, LevelProgress should already have checked if the amount of change was significant myUpdate.m_amountUpdate = true; EventManager::get()->sendEvent(myUpdate.getPointer()); } bool ProgressObject::isDisabled() { return m_disabled; } ProgressObject::~ProgressObject() { finishLevel();//so that things listening for progress events are kept consistent vector::iterator myend = m_children.end(); for (vector::iterator iter = m_children.begin(); iter != myend; ++iter) { if (iter->progObjRef != NULL) { delete iter->progObjRef; iter->progObjRef = NULL; } } } void LevelProgress::reportProgress(const float currentTotal) { if (m_progObjRef == NULL || m_progObjRef->m_disabled) return; float curProgress = currentTotal / m_maximum; if (curProgress > 1.0f) { curProgress = 1.0f; } if (curProgress < m_lastReported) { curProgress = m_lastReported; } m_progObjRef->m_nonChildProgress = curProgress; if (curProgress - m_lastReported > m_internalResolution) { m_lastReported = curProgress; m_progObjRef->updateProgress(); } } void LevelProgress::setTask(const AString& taskDescription) {//maybe this should be in a setter in m_progObjRef, here for coherence with progress reporting if (m_progObjRef == NULL) return; m_progObjRef->m_description = taskDescription; EventProgressUpdate myUpdate(m_progObjRef); myUpdate.m_textUpdate = true; EventManager::get()->sendEvent(myUpdate.getPointer()); } LevelProgress::~LevelProgress() { if (m_progObjRef == NULL) return; m_progObjRef->finishLevel();//finish level on destruction of the object, for automatic detection of algorithm finishing } connectome-workbench-1.4.2/src/Common/ProgressObject.h000066400000000000000000000121161360521144700227570ustar00rootroot00000000000000#ifndef __PROGRESS_OBJECT_H__ #define __PROGRESS_OBJECT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "stdint.h" #include #include "AString.h" namespace caret { class LevelProgress; //NOTE: this tries to intelligently avoid doing recursive progress updates when the value doesn't change much class ProgressObject { struct ProgressInfo { ProgressObject* progObjRef;//used to clean up the memory on finish() float weight; float curProgress; bool completed; }; std::vector m_children; float m_totalWeight; float m_nonChildWeight; float m_nonChildProgress; float m_currentProgress; float m_lastReported; float m_childResolution; AString m_description; ProgressObject* m_parent; int32_t m_parentIndex;//which index in parent's vector this object is bool m_sentinelPassed; bool m_disabled;//disables itself if sentinel called twice bool m_finished; void updateProgress();//used by LevelProgress to report changes void finishLevel();//moves this progress object to 100%, then updates parent if not NULL void setInternalWeight(const float& myInternalWeight);//used by LevelProgress when you start a level ProgressObject(); public: //don't always report progress, in case someone uses this in an inner loop const static float MAX_CHILD_RESOLUTION; const static float MAX_INTERNAL_RESOLUTION; ///fill in weight with the ...Algorithm::getAlgorithmWeight() function at the root level (before starting the algorithm) ///if using multiple algorithms at the root level (shame!), sum their weights first, then use addAlgorithm to get objects for each ProgressObject(const float weight, const float childResolution = MAX_CHILD_RESOLUTION); ~ProgressObject(); ///call this on progress objects you make after an algorithm returns to ensure it finishes (in case it ignores the object) void forceFinish(); ///add an algorithm to this algorithm's progress status, and get a pointer to give to that algorithm ///fill in weight with the ...Algorithm::getAlgorithmWeight() function ProgressObject* addAlgorithm(const float weight, const float childResolution = MAX_CHILD_RESOLUTION); ///DO NOT USE: used by AbstractAlgorithm constructor to check for algorithms that ignore the object void algorithmStartSentinel(); ///get progress as a fraction of 1 (in range [0, 1]) float getCurrentProgressFraction(); ///get progress as percent (in range [0, 100]) float getCurrentProgressPercent(); ///get the description of the current task const AString& getTaskDescription(); ///true if algorithmStartSentinel disabled the object bool isDisabled(); //TODO: make something to return the statuses of all in-progress (nonzero curProgress) tasks for the entire tree, for detailed progress info //TODO: set up callbacks so progress changes don't have to be polled for friend class LevelProgress;//so that LevelProgress can report progress, but nothing else can }; class LevelProgress {//reports progress on processing done in this level float m_maximum; float m_lastReported; float m_internalResolution; ProgressObject* m_progObjRef; LevelProgress(); public: LevelProgress(ProgressObject* myProgObj, const float finishedProgress = 1.0f, const float internalWeight = 1.0f, const float internalResolution = ProgressObject::MAX_INTERNAL_RESOLUTION); ///call with the fraction of finishedProgress passed to ProgressObject::startLevel (default 1.0) that this algorithm has done internally ///work done by subalgorithms is automatically added and updated as progress is made, you do not need to call this unless the current algorithm does direct processing void reportProgress(const float currentTotal); ///set a description for current task, like the name of the subalgorithm you are about to call void setTask(const AString& taskDescription);//yes, this reaches through the class, but it is better to have both reporting functions on the same object ~LevelProgress();//automatically finishes level }; } #endif //__PROGRESS_OBJECT_H__ connectome-workbench-1.4.2/src/Common/ProgressReportingInterface.h000066400000000000000000000071671360521144700253550ustar00rootroot00000000000000#ifndef __PROGRESS_REPORTING_INTERFACE_H__ #define __PROGRESS_REPORTING_INTERFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /** * \class caret::ProgressReportingInterface * \brief Interface for any process that may display progress in the GUI * * This interface is intended for any task that takes a non-trivial * amount of time to run. It allows display of the task's progress, * usually in the user-interface's progress dialog and provides feedback * to the user about how much work has been and still needs to be completed. * The interface also provides a mechanism for the user to cancel the * task and the task to detect that the user has requested the task * be cancelled. */ #include "AString.h" namespace caret { class ProgressReportingInterface { public: ProgressReportingInterface() { /* nothing */ } virtual ~ProgressReportingInterface() { /* nothing */ } /** * Used by task to set the range of progress reporting. * * @param minimumProgress * The minimum amount reported (typically zero). * @param maximumProgress * The maximum amount of progress. */ virtual void setProgressRange(const int minimumProgress, const int maximumProgress) = 0; /** * Used by task to set the current progress. * * @param progress * The current progress within range of the minimum and maximum. */ virtual void setProgressValue(const int progress) = 0; /** * Used by task to set the message describing the task's activity. * * @param message * Message that is displayed. */ virtual void setProgressMessage(const AString& message) = 0; /** * Used by the user-interface to request that the task end as * soon as possible. */ virtual void setCancelRequested() = 0; /** * @return "true" if a request been made to cancel the task, else false. * * Used by the task to see if the task should end as soon as * possible. If so, the task should clean up after itself * (release resources); */ virtual bool isCancelRequested() const = 0; private: ProgressReportingInterface(const ProgressReportingInterface&); ProgressReportingInterface& operator=(const ProgressReportingInterface&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE }; #ifdef __PROGRESS_REPORTING_INTERFACE_DECLARE__ // #endif // __PROGRESS_REPORTING_INTERFACE_DECLARE__ } // namespace #endif //__PROGRESS_REPORTING_INTERFACE_H__ connectome-workbench-1.4.2/src/Common/ReductionEnum.cxx000066400000000000000000000140371360521144700231640ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ReductionEnum.h" #include "CaretAssert.h" using namespace caret; using namespace std; vector ReductionEnum::enumData; bool ReductionEnum::initializedFlag = false; /** * Constructor. * * @param enumValue * An enumerated value. * @param integerCode * Integer code for this enumerated value. * * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ReductionEnum::ReductionEnum(const Enum enumValue, const AString& name, const AString& explanation) { this->enumValue = enumValue; this->name = name; this->explanation = explanation; } /** * Destructor. */ ReductionEnum::~ReductionEnum() { } /** * Initialize the enumerated metadata. */ void ReductionEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ReductionEnum(MAX, "MAX", "the maximum value")); enumData.push_back(ReductionEnum(MIN, "MIN", "the minimum value")); enumData.push_back(ReductionEnum(INDEXMAX, "INDEXMAX", "the 1-based index of the maximum value")); enumData.push_back(ReductionEnum(INDEXMIN, "INDEXMIN", "the 1-based index of the minimum value")); enumData.push_back(ReductionEnum(SUM, "SUM", "add all values")); enumData.push_back(ReductionEnum(PRODUCT, "PRODUCT", "multiply all values")); enumData.push_back(ReductionEnum(MEAN, "MEAN", "the mean of the data")); enumData.push_back(ReductionEnum(STDEV, "STDEV", "the standard deviation (N denominator)")); enumData.push_back(ReductionEnum(SAMPSTDEV, "SAMPSTDEV", "the sample standard deviation (N-1 denominator)")); enumData.push_back(ReductionEnum(VARIANCE, "VARIANCE", "the variance of the data")); enumData.push_back(ReductionEnum(TSNR, "TSNR", "mean divided by sample standard deviation (N-1 denominator)")); enumData.push_back(ReductionEnum(COV, "COV", "sample standard deviation (N-1 denominator) divided by mean")); enumData.push_back(ReductionEnum(L2NORM, "L2NORM", "square root of sum of squares")); enumData.push_back(ReductionEnum(MEDIAN, "MEDIAN", "the median of the data")); enumData.push_back(ReductionEnum(MODE, "MODE", "the mode of the data")); enumData.push_back(ReductionEnum(COUNT_NONZERO, "COUNT_NONZERO", "the number of nonzero elements in the data")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ReductionEnum* ReductionEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ReductionEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ReductionEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ReductionEnum* enumInstance = findData(enumValue); if (enumInstance == NULL) return ""; return enumInstance->name; } /** * Get a string explaining the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ReductionEnum::toExplanation(Enum enumValue) { if (initializedFlag == false) initialize(); const ReductionEnum* enumInstance = findData(enumValue); if (enumInstance == NULL) return ""; return enumInstance->explanation; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ReductionEnum::Enum ReductionEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = INVALID; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ReductionEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ReductionEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values * except ALL. */ void ReductionEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } connectome-workbench-1.4.2/src/Common/ReductionEnum.h000066400000000000000000000050611360521144700226060ustar00rootroot00000000000000#ifndef __REDUCTION_ENUM_H__ #define __REDUCTION_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { /** * \brief Enumerated type for a structure in a brain. * * Enumerated types for reduction operators. */ class ReductionEnum { public: /** * Enumerated values. */ enum Enum { INVALID, MAX, MIN, INDEXMAX, INDEXMIN, SUM, MEAN, STDEV, SAMPSTDEV, VARIANCE, TSNR, COV, L2NORM, PRODUCT, MEDIAN, MODE, COUNT_NONZERO }; ~ReductionEnum(); static AString toName(Enum enumValue); static AString toExplanation(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static void getAllEnums(std::vector& allEnums); private: ReductionEnum(const Enum enumValue, const AString& name, const AString& explanation); static const ReductionEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** The enumerated type value for an instance */ Enum enumValue; /** The name, a text string that is identical to the enumerated value */ AString name; /** An explanation of the function */ AString explanation; }; } // namespace #endif //__REDUCTION_ENUM_H__ connectome-workbench-1.4.2/src/Common/ReductionOperation.cxx000066400000000000000000000516151360521144700242230ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ReductionOperation.h" #include "CaretAssert.h" #include "CaretException.h" #include "MathFunctions.h" #include #include #include #include using namespace caret; using namespace std; float ReductionOperation::reduce(const float* data, const int64_t& numElems, const ReductionEnum::Enum& type) { CaretAssert(numElems > 0); switch (type) { case ReductionEnum::INVALID: throw CaretException("reduction requested with 'INVALID' method"); case ReductionEnum::SAMPSTDEV://all of these start by taking the average, for stability case ReductionEnum::TSNR: case ReductionEnum::COV: if (numElems < 2) throw CaretException("taking the sample standard deviation of 1 element would require dividing by zero"); case ReductionEnum::MEAN: case ReductionEnum::STDEV: case ReductionEnum::VARIANCE: case ReductionEnum::SUM: { double sum = 0.0; for (int64_t i = 0; i < numElems; ++i) sum += data[i]; switch (type) { case ReductionEnum::SUM: return sum; case ReductionEnum::MEAN: return sum / numElems; default: { float mean = sum / numElems; double residsqr = 0.0; for (int64_t i = 0; i < numElems; ++i) { float tempf = data[i] - mean; residsqr += tempf * tempf; } switch(type) { case ReductionEnum::STDEV: return sqrt(residsqr / numElems); case ReductionEnum::SAMPSTDEV: return sqrt(residsqr / (numElems - 1)); case ReductionEnum::VARIANCE: return residsqr / numElems; case ReductionEnum::TSNR: return mean / sqrt(residsqr / (numElems - 1)); case ReductionEnum::COV: return sqrt(residsqr / (numElems - 1)) / mean; default: CaretAssertMessage(0, "unhandled type in sum-based reduction"); return 0.0f; } } } } case ReductionEnum::L2NORM: { double sum = 0.0; for (int64_t i = 0; i < numElems; ++i) sum += data[i] * data[i]; return sqrt(sum); } case ReductionEnum::PRODUCT: { double prod = 1.0; for (int64_t i = 0; i < numElems; ++i) prod *= data[i]; return prod; } case ReductionEnum::MAX: { float max = data[0]; for (int64_t i = 1; i < numElems; ++i) if (data[i] > max) max = data[i]; return max; } case ReductionEnum::MIN: { float min = data[0]; for (int64_t i = 1; i < numElems; ++i) if (data[i] < min) min = data[i]; return min; } case ReductionEnum::INDEXMAX: { float max = data[0]; int64_t index = 0; for (int64_t i = 1; i < numElems; ++i) { if (data[i] > max) { max = data[i]; index = i; } } return index + 1;//1-based, to match gui and column arguments } case ReductionEnum::INDEXMIN: { float min = data[0]; int64_t index = 0; for (int64_t i = 1; i < numElems; ++i) { if (data[i] < min) { min = data[i]; index = i; } } return index + 1; } case ReductionEnum::MEDIAN: { vector dataCopy(numElems); for (int64_t i = 0; i < numElems; ++i) dataCopy[i] = data[i]; sort(dataCopy.begin(), dataCopy.end()); if ((numElems & 1) == 0)//if even, average middle two { return (dataCopy[numElems / 2 - 1] + dataCopy[numElems / 2]) / 2.0f; } else { return dataCopy[numElems / 2];//otherwise, take the center } } case ReductionEnum::MODE: { vector dataCopy(numElems); for (int64_t i = 0; i < numElems; ++i) dataCopy[i] = data[i]; sort(dataCopy.begin(), dataCopy.end());//sort to put same-value next to each other, a hash based map could be faster for large arrays, but oh well int bestCount = 0, curCount = 1; float bestval = -1.0f, curval = dataCopy[0]; for (int64_t i = 1; i < numElems; ++i)//search for largest contiguous region { if (dataCopy[i] == curval) { ++curCount; } else { if (curCount > bestCount) { bestval = curval; bestCount = curCount; } curval = dataCopy[i]; curCount = 1; } } if (curCount > bestCount) { bestval = curval; bestCount = curCount; } return bestval; } case ReductionEnum::COUNT_NONZERO: { int64_t count = 0; for (int64_t i = 0; i < numElems; ++i) { if (data[i] != 0.0f) { ++count; } } return count; } } CaretAssertMessage(false, "unhandled reduction type"); return 0.0f; } float ReductionOperation::reduceExcludeDev(const float* data, const int64_t& numElems, const ReductionEnum::Enum& type, const float& numDevBelow, const float& numDevAbove) { CaretAssert(numElems > 0); double sum = 0.0; int64_t validNum = 0; for (int64_t i = 0; i < numElems; ++i) { if (MathFunctions::isNumeric(data[i])) { ++validNum; sum += data[i]; } } if (validNum == 0) throw CaretException("all input values to reduceExcludeDev were non-numeric"); float mean = sum / validNum; double residsqr = 0.0; for (int64_t i = 0; i < numElems; ++i) { if (MathFunctions::isNumeric(data[i])) { float tempf = data[i] - mean; residsqr += tempf * tempf; } } float stdev = sqrt(residsqr / validNum); float low = mean - numDevBelow * stdev, high = mean + numDevAbove * stdev; switch (type)//special case things that use indices { case ReductionEnum::INDEXMAX: { float max = 0.0f; int64_t index = -1; bool first = true; for (int64_t i = 0; i < numElems; ++i) { if (MathFunctions::isNumeric(data[i]) && data[i] >= low && data[i] <= high && (first || data[i] > max)) { first = false; max = data[i]; index = i; } } return index + 1;//1-based, to match gui and column arguments } case ReductionEnum::INDEXMIN: { float min = 0.0f; int64_t index = -1; bool first = true; for (int64_t i = 0; i < numElems; ++i) { if (MathFunctions::isNumeric(data[i]) && data[i] >= low && data[i] <= high && (first || data[i] < min)) { first = false; min = data[i]; index = i; } } return index + 1;//1-based, to match gui and column arguments } default: break; } vector excluded; excluded.reserve(validNum); for (int64_t i = 0; i < numElems; ++i) { if (MathFunctions::isNumeric(data[i]) && data[i] >= low && data[i] <= high) excluded.push_back(data[i]); } if (excluded.size() == 0) throw CaretException("exclusion parameters to reduceExcludeDev resulted in no usable data"); if (type == ReductionEnum::SAMPSTDEV && excluded.size() < 2) throw CaretException("SAMPSTDEV requested in reduceExcludeDev when only 1 element passed the exclusion parameters"); return reduce(excluded.data(), excluded.size(), type); } float ReductionOperation::reduceOnlyNumeric(const float* data, const int64_t& numElems, const ReductionEnum::Enum& type) { CaretAssert(numElems > 0); switch (type)//special case things that use indices { case ReductionEnum::INDEXMAX: { float max = 0.0f; int64_t index = -1; bool first = true; for (int64_t i = 0; i < numElems; ++i) { if (MathFunctions::isNumeric(data[i]) && (first || data[i] > max)) { first = false; max = data[i]; index = i; } } if (first) throw CaretException("all input values to reduceOnlyNumeric were non-numeric"); return index + 1;//1-based, to match gui and column arguments } case ReductionEnum::INDEXMIN: { float min = 0.0f; int64_t index = -1; bool first = true; for (int64_t i = 0; i < numElems; ++i) { if (MathFunctions::isNumeric(data[i]) && (first || data[i] < min)) { first = false; min = data[i]; index = i; } } if (first) throw CaretException("all input values to reduceOnlyNumeric were non-numeric"); return index + 1;//1-based, to match gui and column arguments } default: break; } vector excluded; excluded.reserve(numElems); for (int64_t i = 0; i < numElems; ++i) { if (MathFunctions::isNumeric(data[i])) excluded.push_back(data[i]); } if (excluded.size() < 1) throw CaretException("all input values to reduceOnlyNumeric were non-numeric"); if (type == ReductionEnum::SAMPSTDEV && excluded.size() < 2) throw CaretException("SAMPSTDEV requested in reduceOnlyNumeric when only 1 element is numeric"); return reduce(excluded.data(), excluded.size(), type); } namespace { struct ValWeight {//for sorting based only on value, but keeping weight associated float value, weight; ValWeight(float v, float w) { value = v; weight = w; } inline bool operator<(const ValWeight& rhs) const { return value < rhs.value; } }; } float ReductionOperation::reduceWeighted(const float* data, const float* weights, const int64_t& numElems, const ReductionEnum::Enum& type) { CaretAssert(numElems > 0); switch (type) { case ReductionEnum::INVALID: throw CaretException("weighted reduction requested with 'INVALID' method"); case ReductionEnum::INDEXMAX: case ReductionEnum::INDEXMIN: case ReductionEnum::MIN: case ReductionEnum::MAX: case ReductionEnum::PRODUCT: case ReductionEnum::COUNT_NONZERO: throw CaretException("weighted reduction not supported for '" + ReductionEnum::toName(type) + "' method"); case ReductionEnum::SAMPSTDEV://all of these start by taking the average, for stability case ReductionEnum::TSNR: case ReductionEnum::COV: if (numElems < 2) throw CaretException("'SAMPSTDEV' weighted reduction on 1 element would require dividing by zero"); case ReductionEnum::MEAN: case ReductionEnum::STDEV: case ReductionEnum::VARIANCE: case ReductionEnum::SUM: { double accum = 0.0, weightsum = 0.0f; for (int i = 0; i < numElems; ++i) { accum += data[i] * weights[i]; weightsum += weights[i]; } if (type == ReductionEnum::SUM) return accum; const float mean = accum / weightsum; if (type == ReductionEnum::MEAN) return mean; accum = 0.0; double weightsum2 = 0.0;//for weighted sample stdev for (int i = 0; i < numElems; ++i) { float tempf = data[i] - mean; accum += weights[i] * tempf * tempf; weightsum2 += weights[i] * weights[i]; } switch (type) { case ReductionEnum::STDEV: return sqrt(accum / weightsum); case ReductionEnum::VARIANCE: return accum / weightsum; case ReductionEnum::SAMPSTDEV: return sqrt(accum / (weightsum - weightsum2 / weightsum));//http://en.wikipedia.org/wiki/Weighted_arithmetic_mean#Weighted_sample_variance case ReductionEnum::TSNR: return mean / sqrt(accum / (weightsum - weightsum2 / weightsum)); case ReductionEnum::COV: return sqrt(accum / (weightsum - weightsum2 / weightsum)) / mean; default: CaretAssertMessage(0, "unhandled type in sum-based reduction"); return 0.0f; } } case ReductionEnum::L2NORM: { double sum = 0.0; for (int64_t i = 0; i < numElems; ++i) sum += weights[i] * data[i] * data[i]; return sqrt(sum);//if all weights are 1, this should match unweighted, so don't divide by sum of weights } case ReductionEnum::MEDIAN: { vector toSort; toSort.reserve(numElems); for (int i = 0; i < numElems; ++i) { toSort.push_back(ValWeight(data[i], weights[i])); } stable_sort(toSort.begin(), toSort.end()); vector weightaccum(numElems); weightaccum[0] = toSort[0].weight; for (int i = 1; i < numElems; ++i) { weightaccum[i] = weightaccum[i - 1] + toSort[i].weight; } double target = weightaccum.back() / 2; int64_t index = (int64_t)(lower_bound(weightaccum.begin(), weightaccum.end(), target) - weightaccum.begin()); if (index == numElems) --index;//deal with edge cases from things like negative weights if (numElems > 1 && index < (numElems - 1) && weightaccum[index] == target)//only average on exact equals, according to https://en.wikipedia.org/wiki/Weighted_median {//could instead always interpolate return (toSort[index].value + toSort[index + 1].value) / 2; } else { return toSort[index].value; } } case ReductionEnum::MODE: { vector toSort; toSort.reserve(numElems); for (int i = 0; i < numElems; ++i) { toSort.push_back(ValWeight(data[i], weights[i])); } stable_sort(toSort.begin(), toSort.end()); float bestweight = -numeric_limits::infinity(), curweight = toSort[0].weight; float bestval = toSort[0].value, curval = toSort[0].value; for (int i = 1; i < numElems; ++i) { if (toSort[i].value == curval) { curweight += toSort[i].weight; } else { if (curweight > bestweight) { bestval = curval; bestweight = curweight; } curval = toSort[i].value; curweight = toSort[i].weight; } } if (curweight > bestweight) { bestval = curval; bestweight = curweight; } return bestval; } } CaretAssertMessage(false, "unhandled reduction type"); return 0.0f; } float ReductionOperation::reduceWeightedOnlyNumeric(const float* data, const float* weights, const int64_t& numElems, const ReductionEnum::Enum& type) { CaretAssert(numElems > 0); switch (type) { case ReductionEnum::INVALID: throw CaretException("weighted reduction requested with 'INVALID' method"); case ReductionEnum::INDEXMAX: case ReductionEnum::INDEXMIN: case ReductionEnum::MIN: case ReductionEnum::MAX: case ReductionEnum::PRODUCT: case ReductionEnum::COUNT_NONZERO: throw CaretException("weighted reduction not supported for '" + ReductionEnum::toName(type) + "' method"); default: break; } vector excluded, exweights; excluded.reserve(numElems); exweights.reserve(numElems); for (int64_t i = 0; i < numElems; ++i) { if (MathFunctions::isNumeric(data[i])) { excluded.push_back(data[i]); exweights.push_back(weights[i]); } } if (excluded.size() < 1) throw CaretException("all input values to reduceWeightedOnlyNumeric were non-numeric"); if (type == ReductionEnum::SAMPSTDEV && excluded.size() < 2) throw CaretException("SAMPSTDEV requested in reduceWeightedOnlyNumeric when only 1 element is numeric"); return reduceWeighted(excluded.data(), exweights.data(), excluded.size(), type); } float ReductionOperation::reduceWeightedExcludeDev(const float* data, const float* weights, const int64_t& numElems, const ReductionEnum::Enum& type, const float& numDevBelow, const float& numDevAbove) { CaretAssert(numElems > 0); switch (type) { case ReductionEnum::INVALID: throw CaretException("weighted reduction requested with 'INVALID' method"); case ReductionEnum::INDEXMAX: case ReductionEnum::INDEXMIN: case ReductionEnum::MIN: case ReductionEnum::MAX: case ReductionEnum::PRODUCT: case ReductionEnum::COUNT_NONZERO: throw CaretException("weighted reduction not supported for '" + ReductionEnum::toName(type) + "' method"); default: break; } double accum = 0.0, weightsum = 0.0f;//compute weighted stdev int64_t numValid = 0; for (int i = 0; i < numElems; ++i) { if (MathFunctions::isNumeric(data[i])) { accum += data[i] * weights[i]; weightsum += weights[i]; ++numValid; } } const float mean = accum / weightsum; accum = 0.0; for (int i = 0; i < numElems; ++i) { if (MathFunctions::isNumeric(data[i])) { float tempf = data[i] - mean; accum += weights[i] * tempf * tempf; } } float stdev = sqrt(accum / weightsum); float low = mean - stdev * numDevBelow, high = mean + stdev * numDevAbove; vector excluded, exweights; excluded.reserve(numValid); exweights.reserve(numValid); for (int64_t i = 0; i < numElems; ++i) { if (MathFunctions::isNumeric(data[i]) && data[i] >= low && data[i] <= high) { excluded.push_back(data[i]); exweights.push_back(weights[i]); } } if (excluded.size() < 1) throw CaretException("all input values to reduceWeightedExcludeDev were non-numeric"); if (type == ReductionEnum::SAMPSTDEV && excluded.size() < 2) throw CaretException("SAMPSTDEV requested in reduceWeightedExcludeDev when only 1 element is numeric"); return reduceWeighted(excluded.data(), exweights.data(), excluded.size(), type); } AString ReductionOperation::getHelpInfo() { AString ret; vector myEnums; ReductionEnum::getAllEnums(myEnums); int numEnums = (int)myEnums.size(); for (int i = 0; i < numEnums; ++i) { ret += ReductionEnum::toName(myEnums[i]) + ": " + ReductionEnum::toExplanation(myEnums[i]) + "\n"; } return ret; } connectome-workbench-1.4.2/src/Common/ReductionOperation.h000066400000000000000000000041131360521144700236370ustar00rootroot00000000000000#ifndef __REDUCTION_OPERATION_H__ #define __REDUCTION_OPERATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AString.h" #include "ReductionEnum.h" namespace caret { class ReductionOperation { public: static float reduce(const float* data, const int64_t& numElems, const ReductionEnum::Enum& type); ///reduce, with exclusion based on number of standard deviations static float reduceExcludeDev(const float* data, const int64_t& numElems, const ReductionEnum::Enum& type, const float& numDevBelow, const float& numDevAbove); static float reduceOnlyNumeric(const float* data, const int64_t& numElems, const ReductionEnum::Enum& type); ///weighted versions, do not accept all reduction types static float reduceWeighted(const float* data, const float* weights, const int64_t& numElems, const ReductionEnum::Enum& type); static float reduceWeightedExcludeDev(const float* data, const float* weights, const int64_t& numElems, const ReductionEnum::Enum& type, const float& numDevBelow, const float& numDevAbove); static float reduceWeightedOnlyNumeric(const float* data, const float* weights, const int64_t& numElems, const ReductionEnum::Enum& type); static AString getHelpInfo(); }; } #endif //__REDUCTION_OPERATION_H__ connectome-workbench-1.4.2/src/Common/SpacerTabIndex.cxx000066400000000000000000000150451360521144700232370ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SPACER_TAB_INDEX_DECLARE__ #include "SpacerTabIndex.h" #undef __SPACER_TAB_INDEX_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::SpacerTabIndex * \brief Index of a spacer tab in a tile tabs configuration * \ingroup Scenes */ /** * Constructor of invalid element. */ SpacerTabIndex::SpacerTabIndex() : CaretObject(), m_windowIndex(-1), m_rowIndex(-1), m_columnIndex(-1) { } /** * Constructor with indices */ SpacerTabIndex::SpacerTabIndex(const int32_t windowIndex, const int32_t rowIndex, const int32_t columnIndex) : CaretObject(), m_windowIndex(windowIndex), m_rowIndex(rowIndex), m_columnIndex(columnIndex) { } /** * Destructor. */ SpacerTabIndex::~SpacerTabIndex() { } /** * Copy constructor. * @param obj * Object that is copied. */ SpacerTabIndex::SpacerTabIndex(const SpacerTabIndex& obj) : CaretObject(obj) { this->copyHelperSpacerTabIndex(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ SpacerTabIndex& SpacerTabIndex::operator=(const SpacerTabIndex& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperSpacerTabIndex(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void SpacerTabIndex::copyHelperSpacerTabIndex(const SpacerTabIndex& obj) { m_windowIndex = obj.m_windowIndex; m_rowIndex = obj.m_rowIndex; m_columnIndex = obj.m_columnIndex; } /** * Inequality operator. * @param obj * Instance compared to this for equality. * @return * True if this instance and 'obj' instance are considered NOT equal. */ bool SpacerTabIndex::operator!=(const SpacerTabIndex& obj) const { return ( ! (*this == obj)); } /** * Equality operator. * @param obj * Instance compared to this for equality. * @return * True if this instance and 'obj' instance are considered equal. */ bool SpacerTabIndex::operator==(const SpacerTabIndex& obj) const { if (this == &obj) { return true; } if ((m_windowIndex == obj.m_windowIndex) && (m_rowIndex == obj.m_rowIndex) && (m_columnIndex == obj.m_columnIndex)) { return true; } return false; } /** * Comparison operator. * * @param rhs * Other instance for comparison * @return True if 'this' is less than 'rhs', else false. */ bool SpacerTabIndex::operator<(const SpacerTabIndex& rhs) const { if (m_windowIndex != rhs.m_windowIndex) { return (m_windowIndex < rhs.m_windowIndex); } if (m_rowIndex != rhs.m_rowIndex) { return (m_rowIndex < rhs.m_rowIndex); } if (m_columnIndex != rhs.m_columnIndex) { return (m_columnIndex < rhs.m_columnIndex); } return false; } /** * @return True if the index is valid, else false. */ bool SpacerTabIndex::isValid() const { if ((m_windowIndex >= 0) && (m_rowIndex >= 0) && (m_columnIndex >= 0)) { return true; } return false; } /** * @return The window index */ int32_t SpacerTabIndex::getWindowIndex() const { return m_windowIndex; } /** * @return The row index */ int32_t SpacerTabIndex::getRowIndex() const { return m_rowIndex; } /** * @return The column index */ int32_t SpacerTabIndex::getColumnIndex() const { return m_columnIndex; } /** * Set the row index. * * @param rowIndex * New row index. */ void SpacerTabIndex::setRowIndex(const int32_t rowIndex) { m_rowIndex = rowIndex; } /** * Set the column index. * * @param columnIndex * New column index. */ void SpacerTabIndex::setColumnIndex(const int32_t columnIndex) { m_columnIndex = columnIndex; } /** * Reset to invalid indices. */ void SpacerTabIndex::reset() { m_windowIndex = -1; m_rowIndex = -1; m_columnIndex = -1; } /** * @return Format for XML attribute (window index, row index, * and column index separated by commas). * NOTE: THESE INDICES START AT ZERO */ AString SpacerTabIndex::getXmlAttributeText() const { AString s("%1,%2,%3"); s = s.arg(m_windowIndex).arg(m_rowIndex).arg(m_columnIndex); return s; } /** * Set from XML text in the form (w,r,c) where 'w' is the * window index, 'r' is the row index, and 'c' is the * column index. * NOTE: THESE INDICES START AT ZERO */ void SpacerTabIndex::setFromXmlAttributeText(const AString& text) { reset(); if ( ! text.isEmpty()) { std::vector indices; AString::toNumbers(text, indices); if (indices.size() >= 3) { m_windowIndex = indices[0]; m_rowIndex = indices[1]; m_columnIndex = indices[2]; } } } /** * @return Row and column in text form (eg: "Row=2, Column=3") * for use in the GUI and viewed by user. * NOTE: THESE INDICES START AT ONE */ AString SpacerTabIndex::getRowColumnGuiText() const { AString s("Row=%1, Column=%2"); s = s.arg(m_rowIndex+1).arg(m_columnIndex+1); return s; } /** * @return Window, row, and column in text form (eg: "Window=1, Row=2, Column=3") * for use in the GUI and viewed by user. * NOTE: THESE INDICES START AT ONE */ AString SpacerTabIndex::getWindowRowColumnGuiText() const { AString s("Window=%1, "); s = s.arg(m_windowIndex+1); s.append(getRowColumnGuiText()); return s; } /** * Get a description of this object's content. * @return String describing this object's content. * NOTE: THESE INDICES START AT ZERO */ AString SpacerTabIndex::toString() const { AString s("SpacerTabIndex: windowIndex=%1, rowIndex=%2, columnIndex=%3"); s = s.arg(m_windowIndex).arg(m_rowIndex).arg(m_columnIndex); return s; } connectome-workbench-1.4.2/src/Common/SpacerTabIndex.h000066400000000000000000000052311360521144700226600ustar00rootroot00000000000000#ifndef __SPACER_TAB_INDEX_H__ #define __SPACER_TAB_INDEX_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" namespace caret { class SceneClassAssistant; class SpacerTabIndex : public CaretObject { public: SpacerTabIndex(); SpacerTabIndex(const int32_t windowIndex, const int32_t rowIndex, const int32_t columnIndex); virtual ~SpacerTabIndex(); SpacerTabIndex(const SpacerTabIndex& obj); SpacerTabIndex& operator=(const SpacerTabIndex& obj); bool operator==(const SpacerTabIndex& obj) const; bool operator!=(const SpacerTabIndex& obj) const; bool operator<(const SpacerTabIndex& rhs) const; bool isValid() const; void reset(); int32_t getWindowIndex() const; int32_t getRowIndex() const; int32_t getColumnIndex() const; AString getRowColumnGuiText() const; AString getWindowRowColumnGuiText() const; AString getXmlAttributeText() const; void setFromXmlAttributeText(const AString& text); void setRowIndex(const int32_t rowIndex); void setColumnIndex(const int32_t columnIndex); // ADD_NEW_METHODS_HERE virtual AString toString() const; private: void copyHelperSpacerTabIndex(const SpacerTabIndex& obj); int32_t m_windowIndex; int32_t m_rowIndex; int32_t m_columnIndex; // ADD_NEW_MEMBERS_HERE friend class SpacerTabContent; }; #ifdef __SPACER_TAB_INDEX_DECLARE__ // #endif // __SPACER_TAB_INDEX_DECLARE__ } // namespace #endif //__SPACER_TAB_INDEX_H__ connectome-workbench-1.4.2/src/Common/SpecFileDialogViewFilesTypeEnum.cxx000066400000000000000000000273411360521144700265240ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __SPEC_FILE_DIALOG_VIEW_FILES_TYPE_ENUM_DECLARE__ #include "SpecFileDialogViewFilesTypeEnum.h" #undef __SPEC_FILE_DIALOG_VIEW_FILES_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::SpecFileDialogViewFilesTypeEnum * \brief Enumerated type for view files selection in Spec File Dialog * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_specFileDialogViewFilesTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void specFileDialogViewFilesTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "SpecFileDialogViewFilesTypeEnum.h" * * Instatiate: * m_specFileDialogViewFilesTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_specFileDialogViewFilesTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_specFileDialogViewFilesTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(specFileDialogViewFilesTypeEnumComboBoxItemActivated())); * * Update the selection: * m_specFileDialogViewFilesTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const SpecFileDialogViewFilesTypeEnum::Enum VARIABLE = m_specFileDialogViewFilesTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ SpecFileDialogViewFilesTypeEnum::SpecFileDialogViewFilesTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ SpecFileDialogViewFilesTypeEnum::~SpecFileDialogViewFilesTypeEnum() { } /** * Initialize the enumerated metadata. */ void SpecFileDialogViewFilesTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(SpecFileDialogViewFilesTypeEnum(VIEW_FILES_ALL, "VIEW_FILES_ALL", "All")); enumData.push_back(SpecFileDialogViewFilesTypeEnum(VIEW_FILES_LOADED, "VIEW_FILES_LOADED", "Loaded")); enumData.push_back(SpecFileDialogViewFilesTypeEnum(VIEW_FILES_LOADED_MODIFIED, "VIEW_FILES_LOADED_MODIFIED", "Loaded:Modified")); enumData.push_back(SpecFileDialogViewFilesTypeEnum(VIEW_FILES_LOADED_NOT_MODIFIED, "VIEW_FILES_LOADED_NOT_MODIFIED", "Loaded:Not Modified")); enumData.push_back(SpecFileDialogViewFilesTypeEnum(VIEW_FILES_NOT_LOADED, "VIEW_FILES_NOT_LOADED", "Not Loaded")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const SpecFileDialogViewFilesTypeEnum* SpecFileDialogViewFilesTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const SpecFileDialogViewFilesTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString SpecFileDialogViewFilesTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const SpecFileDialogViewFilesTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ SpecFileDialogViewFilesTypeEnum::Enum SpecFileDialogViewFilesTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = SpecFileDialogViewFilesTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SpecFileDialogViewFilesTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type SpecFileDialogViewFilesTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString SpecFileDialogViewFilesTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const SpecFileDialogViewFilesTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ SpecFileDialogViewFilesTypeEnum::Enum SpecFileDialogViewFilesTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = SpecFileDialogViewFilesTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SpecFileDialogViewFilesTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type SpecFileDialogViewFilesTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t SpecFileDialogViewFilesTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const SpecFileDialogViewFilesTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ SpecFileDialogViewFilesTypeEnum::Enum SpecFileDialogViewFilesTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = SpecFileDialogViewFilesTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SpecFileDialogViewFilesTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type SpecFileDialogViewFilesTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void SpecFileDialogViewFilesTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void SpecFileDialogViewFilesTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(SpecFileDialogViewFilesTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void SpecFileDialogViewFilesTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(SpecFileDialogViewFilesTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/SpecFileDialogViewFilesTypeEnum.h000066400000000000000000000065721360521144700261540ustar00rootroot00000000000000#ifndef __SPEC_FILE_DIALOG_VIEW_FILES_TYPE_ENUM_H__ #define __SPEC_FILE_DIALOG_VIEW_FILES_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class SpecFileDialogViewFilesTypeEnum { public: /** * Enumerated values. */ enum Enum { /** */ VIEW_FILES_ALL, /** */ VIEW_FILES_LOADED, /** */ VIEW_FILES_LOADED_MODIFIED, /** */ VIEW_FILES_LOADED_NOT_MODIFIED, /** */ VIEW_FILES_NOT_LOADED }; ~SpecFileDialogViewFilesTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: SpecFileDialogViewFilesTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const SpecFileDialogViewFilesTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __SPEC_FILE_DIALOG_VIEW_FILES_TYPE_ENUM_DECLARE__ std::vector SpecFileDialogViewFilesTypeEnum::enumData; bool SpecFileDialogViewFilesTypeEnum::initializedFlag = false; int32_t SpecFileDialogViewFilesTypeEnum::integerCodeCounter = 0; #endif // __SPEC_FILE_DIALOG_VIEW_FILES_TYPE_ENUM_DECLARE__ } // namespace #endif //__SPEC_FILE_DIALOG_VIEW_FILES_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Common/SpeciesEnum.cxx000066400000000000000000000254411360521144700226240ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __SPECIES_ENUM_DECLARE__ #include "SpeciesEnum.h" #undef __SPECIES_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * Constructor. * * @param enumValue * An enumerated value. * @param integerCode * Integer code for this enumerated value. * * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ SpeciesEnum::SpeciesEnum(const Enum enumValue, const int32_t integerCode, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCode; this->name = name; this->guiName = guiName; } /** * Destructor. */ SpeciesEnum::~SpeciesEnum() { } /** * Initialize the enumerated metadata. */ void SpeciesEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(SpeciesEnum(TYPE_UNKNOWN, 0, "TYPE_UNKNOWN", "Unknown")); enumData.push_back(SpeciesEnum(TYPE_BABOON, 1, "TYPE_BABOON", "Baboon")); enumData.push_back(SpeciesEnum(TYPE_CHIMPANZEE, 2, "TYPE_CHIMPANZEE", "Chimpanzee")); enumData.push_back(SpeciesEnum(TYPE_FERRET, 3, "TYPE_FERRET", "Ferret")); enumData.push_back(SpeciesEnum(TYPE_GALAGO, 4, "TYPE_GALAGO", "Galago")); enumData.push_back(SpeciesEnum(TYPE_GIBBON, 5, "TYPE_GIBBON", "Gibbon")); enumData.push_back(SpeciesEnum(TYPE_GORILLA, 6, "TYPE_GORILLA", "Gorilla")); enumData.push_back(SpeciesEnum(TYPE_HUMAN, 7, "TYPE_HUMAN", "Human")); enumData.push_back(SpeciesEnum(TYPE_MACAQUE, 8, "TYPE_MACAQUE", "Macaque")); enumData.push_back(SpeciesEnum(TYPE_MOUSE, 9, "TYPE_MOUSE", "Mouse")); enumData.push_back(SpeciesEnum(TYPE_ORANGUTAN, 10, "TYPE_ORANGUTAN", "Orangutan")); enumData.push_back(SpeciesEnum(TYPE_RAT, 11, "TYPE_RAT", "Rat")); enumData.push_back(SpeciesEnum(TYPE_OTHER, 12, "TYPE_OTHER", "Other not specified")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const SpeciesEnum* SpeciesEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const SpeciesEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString SpeciesEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const SpeciesEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ SpeciesEnum::Enum SpeciesEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = TYPE_UNKNOWN; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SpeciesEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type SpeciesEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString SpeciesEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const SpeciesEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ SpeciesEnum::Enum SpeciesEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = TYPE_UNKNOWN; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SpeciesEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type SpeciesEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t SpeciesEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const SpeciesEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ SpeciesEnum::Enum SpeciesEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = TYPE_UNKNOWN; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SpeciesEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type SpeciesEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void SpeciesEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void SpeciesEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(SpeciesEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void SpeciesEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(SpeciesEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/SpeciesEnum.h000066400000000000000000000065611360521144700222530ustar00rootroot00000000000000#ifndef __SPECIES_ENUM__H_ #define __SPECIES_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { /** * \brief Enumerated type for species. * * Species enumerated type. */ class SpeciesEnum { public: /** * Enumerated values. */ enum Enum { /// unknown TYPE_UNKNOWN, /// baboon TYPE_BABOON, /// chimpanzee TYPE_CHIMPANZEE, /// ferret TYPE_FERRET, /// galago TYPE_GALAGO, /// gibbon TYPE_GIBBON, /// gorilla TYPE_GORILLA, /// human TYPE_HUMAN, /// macaque monkey TYPE_MACAQUE, /// mouse TYPE_MOUSE, /// orangutan TYPE_ORANGUTAN, /// rat TYPE_RAT, /// other TYPE_OTHER }; ~SpeciesEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: SpeciesEnum(const Enum enumValue, const int32_t integerCode, const AString& name, const AString& guiName); static const SpeciesEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __SPECIES_ENUM_DECLARE__ std::vector SpeciesEnum::enumData; bool SpeciesEnum::initializedFlag = false; #endif // __SPECIES_ENUM_DECLARE__ } // namespace #endif //__SPECIES_ENUM__H_ connectome-workbench-1.4.2/src/Common/StereotaxicSpaceEnum.cxx000066400000000000000000000555761360521144700245130ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __STEREOTAXIC_SPACE_ENUM_DECLARE__ #include "StereotaxicSpaceEnum.h" #undef __STEREOTAXIC_SPACE_ENUM_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" using namespace caret; /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ StereotaxicSpaceEnum::StereotaxicSpaceEnum(const Enum enumValue, const AString& name, const AString& guiName, const int32_t dimI, const int32_t dimJ, const int32_t dimK, const float voxelSizeX, const float voxelSizeY, const float voxelSizeZ, const float originX, const float originY, const float originZ) { this->enumValue = enumValue; this->name = name; this->guiName = guiName; this->volumeDimensions[0] = dimI; this->volumeDimensions[1] = dimJ; this->volumeDimensions[2] = dimK; this->volumeVoxelSizes[0] = voxelSizeX; this->volumeVoxelSizes[1] = voxelSizeY; this->volumeVoxelSizes[2] = voxelSizeZ; this->volumeOrigin[0] = originX; this->volumeOrigin[1] = originY; this->volumeOrigin[2] = originZ; } /** * Destructor. */ StereotaxicSpaceEnum::~StereotaxicSpaceEnum() { } /** * Get the dimensions for a stereotaxic space. * * @param enumValue * Input - Enumerated type for stereotaxic space. * @param dimensionsOut * Output - Dimensions for the stereotaxic space. */ void StereotaxicSpaceEnum::toDimensions(const Enum enumValue, int32_t dimensionsOut[3]) { const StereotaxicSpaceEnum* enumInstance = findData(enumValue); dimensionsOut[0] = enumInstance->volumeDimensions[0]; dimensionsOut[1] = enumInstance->volumeDimensions[1]; dimensionsOut[2] = enumInstance->volumeDimensions[2]; } /** * Get the voxel sizes for a stereotaxic space. * * @param enumValue * Input - Enumerated type for stereotaxic space. * @param voxelSizesOut * Output - Voxel sizes for the stereotaxic space. */ void StereotaxicSpaceEnum::toVoxelSizes(const Enum enumValue, float voxelSizesOut[3]) { const StereotaxicSpaceEnum* enumInstance = findData(enumValue); voxelSizesOut[0] = enumInstance->volumeVoxelSizes[0]; voxelSizesOut[1] = enumInstance->volumeVoxelSizes[1]; voxelSizesOut[2] = enumInstance->volumeVoxelSizes[2]; } /** * Get the origin for a stereotaxic space. * * @param enumValue * Input - Enumerated type for stereotaxic space. * @param originOut * Output - Origin for the stereotaxic space. */ void StereotaxicSpaceEnum::toOrigin(const Enum enumValue, float originOut[3]) { const StereotaxicSpaceEnum* enumInstance = findData(enumValue); originOut[0] = enumInstance->volumeOrigin[0]; originOut[1] = enumInstance->volumeOrigin[1]; originOut[2] = enumInstance->volumeOrigin[2]; } /** * Initialize the enumerated metadata. */ void StereotaxicSpaceEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(StereotaxicSpaceEnum(SPACE_UNKNOWN, "SPACE_UNKNOWN", "Unknown", 0, 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); enumData.push_back(StereotaxicSpaceEnum(SPACE_OTHER, "SPACE_OTHER", "Other not specified", 0, 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); enumData.push_back(StereotaxicSpaceEnum(SPACE_AFNI_TALAIRACH, "SPACE_AFNI_TALAIRACH", "AFNI", 161, 191, 151, 1.0, 1.0, 1.0, -80.0, -110.0, -65.0)); enumData.push_back(StereotaxicSpaceEnum(SPACE_FLIRT, "SPACE_FLIRT", "FLIRT", 182, 217, 182, 1.0, 1.0, 1.0, -90.0, -126.0, -72.0)); enumData.push_back(StereotaxicSpaceEnum(SPACE_FLIRT_222, "SPACE_FLIRT_222", "FLIRT-222", 91, 109, 91, 2.0, 2.0, 2.0, -90.0, -126.0, -72.0)); enumData.push_back(StereotaxicSpaceEnum(SPACE_MACAQUE_F6, "SPACE_MACAQUE_F6", "MACAQUE-F6", 143, 187, 118, 0.5, 0.5, 0.5, -35.75, -54.75, -30.25)); enumData.push_back(StereotaxicSpaceEnum(SPACE_MACAQUE_F99, "SPACE_MACAQUE_F99", "MACAQUE-F99", 143, 187, 118, 0.5, 0.5, 0.5, -35.75, -54.75, -30.25)); enumData.push_back(StereotaxicSpaceEnum(SPACE_MRITOTAL, "SPACE_MRITOTAL", "MRITOTAL", 182, 217, 182, 1.0, 1.0, 1.0, -90.0, -126.0, -72.0)); enumData.push_back(StereotaxicSpaceEnum(SPACE_SPM, "SPACE_SPM", "SPM", 182, 217, 182, 1.0, 1.0, 1.0, -90.0, -126.0, -72.0)); enumData.push_back(StereotaxicSpaceEnum(SPACE_SPM_95, "SPACE_SPM_95", "SPM95", 182, 217, 182, 1.0, 1.0, 1.0, -90.0, -126.0, -72.0)); enumData.push_back(StereotaxicSpaceEnum(SPACE_SPM_96, "SPACE_SPM_96", "SPM96", 182, 217, 182, 1.0, 1.0, 1.0, -90.0, -126.0, -72.0)); enumData.push_back(StereotaxicSpaceEnum(SPACE_SPM_99, "SPACE_SPM_99", "SPM99", 182, 217, 182, 1.0, 1.0, 1.0, -90.0, -126.0, -72.0)); enumData.push_back(StereotaxicSpaceEnum(SPACE_SPM_2, "SPACE_SPM_2", "SPM2", 182, 217, 182, 1.0, 1.0, 1.0, -90.0, -126.0, -72.0)); enumData.push_back(StereotaxicSpaceEnum(SPACE_SPM_5, "SPACE_SPM_5", "SPM5", 182, 217, 182, 1.0, 1.0, 1.0, -90.0, -126.0, -72.0)); enumData.push_back(StereotaxicSpaceEnum(SPACE_T88, "SPACE_T88", "T88", 161, 191, 151, 1.0, 1.0, 1.0, -80.0, -110.0, -65.0)); enumData.push_back(StereotaxicSpaceEnum(SPACE_WU_7112B, "SPACE_WU_7112B", "711-2B", 176, 208, 176, 1.0, 1.0, 1.0, -88.5, -123.5, -75.5)); enumData.push_back(StereotaxicSpaceEnum(SPACE_WU_7112B_111, "SPACE_WU_7112B_111", "711-2B-111", 176, 208, 176, 1.0, 1.0, 1.0, -88.5, -123.5, -75.5)); enumData.push_back(StereotaxicSpaceEnum(SPACE_WU_7112B_222, "SPACE_WU_7112B_222", "711-2B-222", 128, 128, 75, 2.0, 2.0, 2.0, -128, -128, -69)); enumData.push_back(StereotaxicSpaceEnum(SPACE_WU_7112B_333, "SPACE_WU_7112B_333", "711-2B-333", 48, 64, 48, 3.0, 3.0, 3.0, -72.0, -106.5, -61.5)); enumData.push_back(StereotaxicSpaceEnum(SPACE_WU_7112C, "SPACE_WU_7112C", "711-2C", 176, 208, 176, 1.0, 1.0, 1.0, -88.5, -123.5, -75.5)); enumData.push_back(StereotaxicSpaceEnum(SPACE_WU_7112C_111, "SPACE_WU_7112C_111", "711-2C-111", 176, 208, 176, 1.0, 1.0, 1.0, -88.5, -123.5, -75.5)); enumData.push_back(StereotaxicSpaceEnum(SPACE_WU_7112C_222, "SPACE_WU_7112C_222", "711-2C-222", 128, 128, 75, 2.0, 2.0, 2.0, -128, -128, -69)); enumData.push_back(StereotaxicSpaceEnum(SPACE_WU_7112C_333, "SPACE_WU_7112C_333", "711-2C-333", 48, 64, 48, 3.0, 3.0, 3.0, -72.0, -106.5, -61.5)); enumData.push_back(StereotaxicSpaceEnum(SPACE_WU_7112O, "SPACE_WU_7112O", "711-2O", 176, 208, 176, 1.0, 1.0, 1.0, -88.5, -123.5, -75.5)); enumData.push_back(StereotaxicSpaceEnum(SPACE_WU_7112O_111, "SPACE_WU_7112O_111", "711-2O-111", 176, 208, 176, 1.0, 1.0, 1.0, -88.5, -123.5, -75.5)); enumData.push_back(StereotaxicSpaceEnum(SPACE_WU_7112O_222, "SPACE_WU_7112O_222", "711-2O-222", 128, 128, 75, 2.0, 2.0, 2.0, -128, -128, -69)); enumData.push_back(StereotaxicSpaceEnum(SPACE_WU_7112O_333, "SPACE_WU_7112O_333", "711-2O-333", 48, 64, 48, 3.0, 3.0, 3.0, -72.0, -106.5, -61.5)); enumData.push_back(StereotaxicSpaceEnum(SPACE_WU_7112Y, "SPACE_WU_7112Y", "711-2Y", 176, 208, 176, 1.0, 1.0, 1.0, -88.5, -123.5, -75.5)); enumData.push_back(StereotaxicSpaceEnum(SPACE_WU_7112Y_111, "SPACE_WU_7112Y_111", "711-2Y-111", 176, 208, 176, 1.0, 1.0, 1.0, -88.5, -123.5, -75.5)); enumData.push_back(StereotaxicSpaceEnum(SPACE_WU_7112Y_222, "SPACE_WU_7112Y_222", "711-2Y-222", 128, 128, 75, 2.0, 2.0, 2.0, -128, -128, -69)); enumData.push_back(StereotaxicSpaceEnum(SPACE_WU_7112Y_333, "SPACE_WU_7112Y_333", "711-2Y-333", 48, 64, 48, 3.0, 3.0, 3.0, -72.0, -106.5, -61.5)); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const StereotaxicSpaceEnum* StereotaxicSpaceEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const StereotaxicSpaceEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString StereotaxicSpaceEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const StereotaxicSpaceEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ StereotaxicSpaceEnum::Enum StereotaxicSpaceEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = SPACE_UNKNOWN; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const StereotaxicSpaceEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type StereotaxicSpaceEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString StereotaxicSpaceEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const StereotaxicSpaceEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ StereotaxicSpaceEnum::Enum StereotaxicSpaceEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = SPACE_UNKNOWN; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const StereotaxicSpaceEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type StereotaxicSpaceEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t StereotaxicSpaceEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const StereotaxicSpaceEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ StereotaxicSpaceEnum::Enum StereotaxicSpaceEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = SPACE_UNKNOWN; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const StereotaxicSpaceEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type StereotaxicSpaceEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void StereotaxicSpaceEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void StereotaxicSpaceEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(StereotaxicSpaceEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void StereotaxicSpaceEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(StereotaxicSpaceEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/StereotaxicSpaceEnum.h000066400000000000000000000136531360521144700241260ustar00rootroot00000000000000#ifndef __STEREOTAXIC_SPACE_ENUM__H_ #define __STEREOTAXIC_SPACE_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { /** * \brief * * */ class StereotaxicSpaceEnum { public: /** * Enumerated values. */ enum Enum { /// unknown space SPACE_UNKNOWN, /// other space SPACE_OTHER, /// AFNI Talairach space SPACE_AFNI_TALAIRACH, /// FLIRT space SPACE_FLIRT, /// FLIRT 222 space SPACE_FLIRT_222, /// macaque atlas SPACE_MACAQUE_F6, /// Macaque F99 SPACE_MACAQUE_F99, /// MRITOTAL space SPACE_MRITOTAL, /// SPM space SPACE_SPM, /// SPM 95 space SPACE_SPM_95, /// SPM 95 space SPACE_SPM_96, /// SPM 99 Template space SPACE_SPM_99, /// SPM 2 Template space SPACE_SPM_2, /// SPM 5 space SPACE_SPM_5, /// Talairach 88 space (same as AFNI) SPACE_T88, /// Washington University 711-2B space SPACE_WU_7112B, /// Washington University 711-2B 1mm voxelspace SPACE_WU_7112B_111, /// Washington University 711-2B 2mm voxelspace SPACE_WU_7112B_222, /// Washington University 711-2B 3mm voxelspace SPACE_WU_7112B_333, /// Washington University 711-2C space SPACE_WU_7112C, /// Washington University 711-2C 1mm voxelspace SPACE_WU_7112C_111, /// Washington University 711-2C 2mm voxelspace SPACE_WU_7112C_222, /// Washington University 711-2C 3mm voxelspace SPACE_WU_7112C_333, /// Washington University 711-2O space SPACE_WU_7112O, /// Washington University 711-2O 1mm voxelspace SPACE_WU_7112O_111, /// Washington University 711-2O 2mm voxelspace SPACE_WU_7112O_222, /// Washington University 711-2O 3mm voxelspace SPACE_WU_7112O_333, /// Washington University 711-2Y space SPACE_WU_7112Y, /// Washington University 711-2Y 1mm voxelspace SPACE_WU_7112Y_111, /// Washington University 711-2Y 2mm voxelspace SPACE_WU_7112Y_222, /// Washington University 711-2Y 3mm voxelspace SPACE_WU_7112Y_333 }; ~StereotaxicSpaceEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); static void toDimensions(const Enum enumValue, int32_t dimensionsOut[3]); static void toVoxelSizes(const Enum enumValue, float voxelSizesOut[3]); static void toOrigin(const Enum enumValue, float originOut[3]); private: StereotaxicSpaceEnum(const Enum enumValue, const AString& name, const AString& guiName, const int32_t dimI, const int32_t dimJ, const int32_t dimK, const float voxelSizeX, const float voxelSizeY, const float voxelSizeZ, const float originX, const float originY, const float originZ); static const StereotaxicSpaceEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; /** Volume Dimensions */ int32_t volumeDimensions[3]; /** Volume Origin */ float volumeOrigin[3]; /** Volume Voxel Sizes */ float volumeVoxelSizes[3]; }; #ifdef __STEREOTAXIC_SPACE_ENUM_DECLARE__ std::vector StereotaxicSpaceEnum::enumData; bool StereotaxicSpaceEnum::initializedFlag = false; int32_t StereotaxicSpaceEnum::integerCodeCounter = 0; #endif // __STEREOTAXIC_SPACE_ENUM_DECLARE__ } // namespace #endif //__STEREOTAXIC_SPACE_ENUM__H_ connectome-workbench-1.4.2/src/Common/StringTableModel.cxx000066400000000000000000000157201360521144700236020ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __STRING_TABLE_MODEL_DECLARE__ #include "StringTableModel.h" #undef __STRING_TABLE_MODEL_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::StringTableModel * \brief Creates a two-dimension table of strings. * \ingroup Common */ /** * Constructor that creates a table of the specified dimensions * with all column alignment set to right. * * @param numberOfRows * Number of rows. * @param numColumns * Number of columns. * @param floatingPointPrecision * Precision for floating point data. */ StringTableModel::StringTableModel(const int32_t numberOfRows, const int32_t numberOfColumns, const int32_t floatingPointPrecision) : CaretObject(), m_numberOfRows(numberOfRows), m_numberOfColumns(numberOfColumns), m_floatingPointPrecsion(floatingPointPrecision) { CaretAssert(m_numberOfRows > 0); CaretAssert(m_numberOfColumns > 0); m_stringTable.resize(m_numberOfRows * m_numberOfColumns); m_columnAlignment.resize(m_numberOfColumns, ALIGN_RIGHT); } /** * Destructor. */ StringTableModel::~StringTableModel() { } /** * Set column alignment. * * @param column * Column for which alignment is set. * @param alignment * New alignment value. */ void StringTableModel::setColumnAlignment(const int32_t column, const Alignment alignment) { CaretAssertVectorIndex(m_columnAlignment, column); m_columnAlignment[column] = alignment; } /** * Set an element in the table with a string. * * @param row * Row index. * @param column * Column. * @param value * String value for given row/column. */ void StringTableModel::setElement(const int32_t row, const int32_t column, const AString& value) { const int32_t offset = getOffset(row, column); CaretAssertVectorIndex(m_stringTable, offset); m_stringTable[offset] = value; } /** * Set an element in the table with a C-style string. * * @param row * Row index. * @param column * Column. * @param value * C-Style string value for given row/column. */ void StringTableModel::setElement(const int32_t row, const int32_t column, const char* value) { setElement(row, column, AString(value)); } /** * Set an element in the table with a boolean value. * * @param row * Row index. * @param column * Column. * @param value * Boolean value for given row/column. */ void StringTableModel::setElement(const int32_t row, const int32_t column, const bool value) { setElement(row, column, AString::fromBool(value)); } /** * Set an element in the table with a 32-bit integer. * * @param row * Row index. * @param column * Column. * @param value * Integer value for given row/column. */ void StringTableModel::setElement(const int32_t row, const int32_t column, const int32_t value) { setElement(row, column, AString::number(value)); } /** * Set an element in the table with a 64-bit integer. * * @param row * Row index. * @param column * Column. * @param value * 64-Bit integer value for given row/column. */ void StringTableModel::setElement(const int32_t row, const int32_t column, const int64_t value) { setElement(row, column, AString::number(value)); } /** * Set an element in the table with floating point value. * * @param row * Row index. * @param column * Column. * @param value * Floating point value for given row/column. */ void StringTableModel::setElement(const int32_t row, const int32_t column, const double value) { setElement(row, column, AString::number(value, 'f', m_floatingPointPrecsion)); } /** * Get the offset to an element in the table. * * @param row * Row index. * @param column * Column. * @return * Offset of element and given row and column. */ int32_t StringTableModel::getOffset(const int32_t row, const int32_t column) const { CaretAssertArrayIndex(m_stringTable, m_numberOfRows, row); CaretAssertArrayIndex(m_stringTable, m_numberOfColumns, column); const int32_t offset = ((row * m_numberOfColumns) + column); return offset; } /** * @return The table formatted into a text string. */ AString StringTableModel::getInString() const { std::vector columnWidths(m_numberOfColumns, 0); for (int32_t j = 0; j < m_numberOfColumns; j++) { int32_t width = 0; for (int32_t i = 0; i < m_numberOfRows; i++) { width = std::max(m_stringTable[getOffset(i, j)].length(), width); } // if (width > 0) { // width += 3; // } columnWidths[j] = width; } AString textOut; for (int32_t i = 0; i < m_numberOfRows; i++) { for (int32_t j = 0; j < m_numberOfColumns; j++) { const int32_t offset = getOffset(i, j); CaretAssertVectorIndex(m_stringTable, offset); AString txt = m_stringTable[offset]; CaretAssertVectorIndex(m_columnAlignment, j); switch (m_columnAlignment[j]) { case ALIGN_LEFT: textOut.append(txt.leftJustified(columnWidths[j])); break; case ALIGN_RIGHT: textOut.append(txt.rightJustified(columnWidths[j])); break; } textOut.append(" "); } textOut.append("\n"); } return textOut; } connectome-workbench-1.4.2/src/Common/StringTableModel.h000066400000000000000000000060371360521144700232300ustar00rootroot00000000000000#ifndef __STRING_TABLE_MODEL_H__ #define __STRING_TABLE_MODEL_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" namespace caret { class StringTableModel : public CaretObject { public: enum Alignment { ALIGN_LEFT, ALIGN_RIGHT }; StringTableModel(const int32_t numberOfRows, const int32_t numberOfColumns, const int32_t floatingPointPrecision = 3); virtual ~StringTableModel(); void setElement(const int32_t row, const int32_t column, const AString& value); void setElement(const int32_t row, const int32_t column, const char* value); void setElement(const int32_t row, const int32_t column, const int32_t value); void setElement(const int32_t row, const int32_t column, const int64_t value); void setElement(const int32_t row, const int32_t column, const double value); void setElement(const int32_t row, const int32_t column, const bool value); void setColumnAlignment(const int32_t column, const Alignment alignment); AString getInString() const; private: StringTableModel(const StringTableModel&); StringTableModel& operator=(const StringTableModel&); int32_t getOffset(const int32_t row, const int32_t column) const; const int32_t m_numberOfRows; const int32_t m_numberOfColumns; const int32_t m_floatingPointPrecsion; std::vector m_stringTable; std::vector m_columnAlignment; // ADD_NEW_MEMBERS_HERE }; #ifdef __STRING_TABLE_MODEL_DECLARE__ // #endif // __STRING_TABLE_MODEL_DECLARE__ } // namespace #endif //__STRING_TABLE_MODEL_H__ connectome-workbench-1.4.2/src/Common/StructureEnum.cxx000066400000000000000000000622071360521144700232320ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __STRUCTURE_ENUM_DECLARE__ #include "StructureEnum.h" #undef __STRUCTURE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * Constructor. * * @param enumValue * An enumerated value. * @param integerCode * Integer code for this enumerated value. * * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ StructureEnum::StructureEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = StructureEnum::integerCodeGenerator++; this->name = name; this->guiName = guiName; } /** * Destructor. */ StructureEnum::~StructureEnum() { } /** * Initialize the enumerated metadata. */ void StructureEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; //TSC: WARNING: the order of these determines the standard order of the structures in some -cifti-create-* commands, DO NOT reorder any *existing* entries enumData.push_back(StructureEnum(CORTEX_LEFT, "CORTEX_LEFT", "CortexLeft")); enumData.push_back(StructureEnum(CORTEX_RIGHT, "CORTEX_RIGHT", "CortexRight")); enumData.push_back(StructureEnum(CEREBELLUM, "CEREBELLUM", "Cerebellum")); enumData.push_back(StructureEnum(ACCUMBENS_LEFT, "ACCUMBENS_LEFT", "AccumbensLeft")); enumData.push_back(StructureEnum(ACCUMBENS_RIGHT, "ACCUMBENS_RIGHT", "AccumbensRight")); enumData.push_back(StructureEnum(ALL, "ALL", "All")); enumData.push_back(StructureEnum(ALL_GREY_MATTER, "ALL_GREY_MATTER", "AllGreyMatter")); enumData.push_back(StructureEnum(ALL_WHITE_MATTER, "ALL_WHITE_MATTER", "AllWhiteMatter")); enumData.push_back(StructureEnum(AMYGDALA_LEFT, "AMYGDALA_LEFT", "AmygdalaLeft")); enumData.push_back(StructureEnum(AMYGDALA_RIGHT, "AMYGDALA_RIGHT", "AmygdalaRight")); enumData.push_back(StructureEnum(BRAIN_STEM, "BRAIN_STEM", "BrainStem")); enumData.push_back(StructureEnum(CAUDATE_LEFT, "CAUDATE_LEFT", "CaudateLeft")); enumData.push_back(StructureEnum(CAUDATE_RIGHT, "CAUDATE_RIGHT", "CaudateRight")); enumData.push_back(StructureEnum(CEREBELLAR_WHITE_MATTER_LEFT, "CEREBELLAR_WHITE_MATTER_LEFT", "CerebellarWhiteMatterLeft")); enumData.push_back(StructureEnum(CEREBELLAR_WHITE_MATTER_RIGHT, "CEREBELLAR_WHITE_MATTER_RIGHT", "CerebellarWhiteMatterRight")); enumData.push_back(StructureEnum(CEREBELLUM_LEFT, "CEREBELLUM_LEFT", "CerebellumLeft")); enumData.push_back(StructureEnum(CEREBELLUM_RIGHT, "CEREBELLUM_RIGHT", "CerebellumRight")); enumData.push_back(StructureEnum(CEREBRAL_WHITE_MATTER_LEFT, "CEREBRAL_WHITE_MATTER_LEFT", "CerebralWhiteMatterLeft")); enumData.push_back(StructureEnum(CEREBRAL_WHITE_MATTER_RIGHT, "CEREBRAL_WHITE_MATTER_RIGHT", "CerebralWhiteMatterRight")); enumData.push_back(StructureEnum(CORTEX, "CORTEX", "Cortex")); enumData.push_back(StructureEnum(DIENCEPHALON_VENTRAL_LEFT, "DIENCEPHALON_VENTRAL_LEFT", "DiencephalonVentralLeft")); enumData.push_back(StructureEnum(DIENCEPHALON_VENTRAL_RIGHT, "DIENCEPHALON_VENTRAL_RIGHT", "DiencephalonVentralRight")); enumData.push_back(StructureEnum(HIPPOCAMPUS_LEFT, "HIPPOCAMPUS_LEFT", "HippocampusLeft")); enumData.push_back(StructureEnum(HIPPOCAMPUS_RIGHT, "HIPPOCAMPUS_RIGHT", "HippocampusRight")); enumData.push_back(StructureEnum(INVALID, "INVALID", "Invalid")); enumData.push_back(StructureEnum(OTHER, "OTHER", "Other")); enumData.push_back(StructureEnum(OTHER_GREY_MATTER, "OTHER_GREY_MATTER", "OtherGreyMatter")); enumData.push_back(StructureEnum(OTHER_WHITE_MATTER, "OTHER_WHITE_MATTER", "OtherWhiteMatter")); enumData.push_back(StructureEnum(PALLIDUM_LEFT, "PALLIDUM_LEFT", "PallidumLeft")); enumData.push_back(StructureEnum(PALLIDUM_RIGHT, "PALLIDUM_RIGHT", "PallidumRight")); enumData.push_back(StructureEnum(PUTAMEN_LEFT, "PUTAMEN_LEFT", "PutamenLeft")); enumData.push_back(StructureEnum(PUTAMEN_RIGHT, "PUTAMEN_RIGHT", "PutamenRight")); // enumData.push_back(StructureEnum(SUBCORTICAL_WHITE_MATTER_LEFT, // "SUBCORTICAL_WHITE_MATTER_LEFT", // "SubcorticalWhiteMatterLeft")); // // enumData.push_back(StructureEnum(SUBCORTICAL_WHITE_MATTER_RIGHT, // "SUBCORTICAL_WHITE_MATTER_RIGHT", // "SubcorticalWhiteMatterRight")); enumData.push_back(StructureEnum(THALAMUS_LEFT, "THALAMUS_LEFT", "ThalamusLeft")); enumData.push_back(StructureEnum(THALAMUS_RIGHT, "THALAMUS_RIGHT", "ThalamusRight")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const StructureEnum* StructureEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const StructureEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString StructureEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const StructureEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ StructureEnum::Enum StructureEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = INVALID; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const StructureEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type StructureEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString StructureEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const StructureEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ StructureEnum::Enum StructureEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = INVALID; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const StructureEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type StructureEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString StructureEnum::toCiftiName(Enum enumValue) { if (initializedFlag == false) initialize(); const StructureEnum* enumInstance = findData(enumValue); return "CIFTI_STRUCTURE_" + enumInstance->name; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ StructureEnum::Enum StructureEnum::fromCiftiName(const AString& ciftiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = INVALID; if (ciftiName.startsWith("CIFTI_STRUCTURE_")) { QString toMatch = ciftiName.mid(16); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const StructureEnum& d = *iter; if (toMatch == d.name) { enumValue = d.enumValue; validFlag = true; break; } } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + ciftiName + "failed to match enumerated value for type StructureEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t StructureEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const StructureEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ StructureEnum::Enum StructureEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = INVALID; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const StructureEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type StructureEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values * except ALL. */ void StructureEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { StructureEnum::Enum value =iter->enumValue; if (value == ALL) { // nothing } else { allEnums.push_back(iter->enumValue); } } } /** * Is this 'right' structure? * @param enumValue * The enumerated type. * @return * true if the enumerated value represents a 'right' structure, else false. */ bool StructureEnum::isRight(const Enum enumValue) { switch (enumValue) { case ACCUMBENS_RIGHT: case AMYGDALA_RIGHT: case CAUDATE_RIGHT: case CEREBELLAR_WHITE_MATTER_RIGHT: case CEREBELLUM_RIGHT: case CEREBRAL_WHITE_MATTER_RIGHT: case CORTEX_RIGHT: case DIENCEPHALON_VENTRAL_RIGHT: case HIPPOCAMPUS_RIGHT: case PALLIDUM_RIGHT: case PUTAMEN_RIGHT: case THALAMUS_RIGHT: return true; case ALL://avoid default so smart compilers can warn when a new structure isn't added here case ALL_GREY_MATTER: case ALL_WHITE_MATTER: case BRAIN_STEM: case CEREBELLUM: case CORTEX: case INVALID: case OTHER: case OTHER_GREY_MATTER: case OTHER_WHITE_MATTER: return false;//visually separate none/both from opposite cases case ACCUMBENS_LEFT: case AMYGDALA_LEFT: case CAUDATE_LEFT: case CEREBELLAR_WHITE_MATTER_LEFT: case CEREBELLUM_LEFT: case CEREBRAL_WHITE_MATTER_LEFT: case CORTEX_LEFT: case DIENCEPHALON_VENTRAL_LEFT: case HIPPOCAMPUS_LEFT: case PALLIDUM_LEFT: case PUTAMEN_LEFT: case THALAMUS_LEFT: return false; } CaretAssert(false); return false; } /** * Is this 'left' structure? * @param enumValue * The enumerated type. * @return * true if the enumerated value represents a 'left' structure, else false. */ bool StructureEnum::isLeft(const Enum enumValue) { switch (enumValue) { case ACCUMBENS_LEFT: case AMYGDALA_LEFT: case CAUDATE_LEFT: case CEREBELLAR_WHITE_MATTER_LEFT: case CEREBELLUM_LEFT: case CEREBRAL_WHITE_MATTER_LEFT: case CORTEX_LEFT: case DIENCEPHALON_VENTRAL_LEFT: case HIPPOCAMPUS_LEFT: case PALLIDUM_LEFT: case PUTAMEN_LEFT: case THALAMUS_LEFT: return true; case ALL://avoid default so smart compilers can warn when a new structure isn't added here case ALL_GREY_MATTER: case ALL_WHITE_MATTER: case BRAIN_STEM: case CEREBELLUM: case CORTEX: case INVALID: case OTHER: case OTHER_GREY_MATTER: case OTHER_WHITE_MATTER: return false;//visually separate none/both from opposite cases case ACCUMBENS_RIGHT: case AMYGDALA_RIGHT: case CAUDATE_RIGHT: case CEREBELLAR_WHITE_MATTER_RIGHT: case CEREBELLUM_RIGHT: case CEREBRAL_WHITE_MATTER_RIGHT: case CORTEX_RIGHT: case DIENCEPHALON_VENTRAL_RIGHT: case HIPPOCAMPUS_RIGHT: case PALLIDUM_RIGHT: case PUTAMEN_RIGHT: case THALAMUS_RIGHT: return false; } CaretAssert(false); return false; } /** * Is this a 'single' structure? The structure must be a valid type. * * @param enumValue * The enumerated type. * @return * true if the enumerated value represents a 'single' structure, else false. */ bool StructureEnum::isSingleStructure(const Enum enumValue) { bool singleStructureFlag = true; switch (enumValue) { case ACCUMBENS_LEFT: break; case ACCUMBENS_RIGHT: break; case ALL: singleStructureFlag = false; break; case ALL_GREY_MATTER: singleStructureFlag = false; break; case ALL_WHITE_MATTER: singleStructureFlag = false; break; case AMYGDALA_LEFT: break; case AMYGDALA_RIGHT: break; case BRAIN_STEM: break; case CAUDATE_LEFT: break; case CAUDATE_RIGHT: break; case CEREBELLAR_WHITE_MATTER_LEFT: break; case CEREBELLAR_WHITE_MATTER_RIGHT: break; case CEREBELLUM: break; case CEREBELLUM_LEFT: break; case CEREBELLUM_RIGHT: break; case CEREBRAL_WHITE_MATTER_LEFT: break; case CEREBRAL_WHITE_MATTER_RIGHT: break; case CORTEX: break; case CORTEX_LEFT: break; case CORTEX_RIGHT: break; case DIENCEPHALON_VENTRAL_LEFT: break; case DIENCEPHALON_VENTRAL_RIGHT: break; case HIPPOCAMPUS_LEFT: break; case HIPPOCAMPUS_RIGHT: break; case INVALID: singleStructureFlag = false; break; case PALLIDUM_LEFT: break; case PALLIDUM_RIGHT: break; case OTHER: singleStructureFlag = false; break; case OTHER_GREY_MATTER: singleStructureFlag = false; break; case OTHER_WHITE_MATTER: singleStructureFlag = false; break; case PUTAMEN_LEFT: break; case PUTAMEN_RIGHT: break; // case SUBCORTICAL_WHITE_MATTER_LEFT: // contralateralStructure = SUBCORTICAL_WHITE_MATTER_RIGHT; // break; // case SUBCORTICAL_WHITE_MATTER_RIGHT: // contralateralStructure = SUBCORTICAL_WHITE_MATTER_LEFT; // break; case THALAMUS_LEFT: break; case THALAMUS_RIGHT: break; } return singleStructureFlag; } /** * Are the two structure's cortices and contralateral (is one CortexLeft * and one CortexRight)? * * @param enumValueA * First structure enumerated type. * @param enumValueB * Second structure enumerated type. * @return * True if one is CORTEX_LEFT and one is CORTEX_LEFT. */ bool StructureEnum::isCortexContralateral(const Enum enumValueA, const Enum enumValueB) { if ((enumValueA == CORTEX_LEFT) && (enumValueB == CORTEX_RIGHT)) { return true; } if ((enumValueA == CORTEX_RIGHT) && (enumValueB == CORTEX_LEFT)) { return true; } return false; } /** * For the given structure return its contralateral structure. * Thats is, if this is a left/right structure return its * corresponding structure from the other side. * * @param enumValue * Structure for which contralateral structure is desired. * @return The contralateral structure or NULL if it does * not have a contralateral structure. */ StructureEnum::Enum StructureEnum::getContralateralStructure(const Enum enumValue) { StructureEnum::Enum contralateralStructure = INVALID; switch (enumValue) { case ACCUMBENS_LEFT: contralateralStructure = ACCUMBENS_RIGHT; break; case ACCUMBENS_RIGHT: contralateralStructure = ACCUMBENS_LEFT; break; case ALL: contralateralStructure = INVALID; break; case ALL_GREY_MATTER: break; case ALL_WHITE_MATTER: break; case AMYGDALA_LEFT: contralateralStructure = AMYGDALA_RIGHT; break; case AMYGDALA_RIGHT: contralateralStructure = AMYGDALA_LEFT; break; case BRAIN_STEM: contralateralStructure = INVALID; break; case CAUDATE_LEFT: contralateralStructure = CAUDATE_RIGHT; break; case CAUDATE_RIGHT: contralateralStructure = CAUDATE_LEFT; break; case CEREBELLAR_WHITE_MATTER_LEFT: contralateralStructure= CEREBELLAR_WHITE_MATTER_RIGHT; break; case CEREBELLAR_WHITE_MATTER_RIGHT: contralateralStructure = CEREBELLAR_WHITE_MATTER_LEFT; break; case CEREBELLUM: contralateralStructure = INVALID; break; case CEREBELLUM_LEFT: contralateralStructure = CEREBELLUM_RIGHT; break; case CEREBELLUM_RIGHT: contralateralStructure = CEREBELLUM_LEFT; break; case CEREBRAL_WHITE_MATTER_LEFT: contralateralStructure = CEREBELLAR_WHITE_MATTER_RIGHT; break; case CEREBRAL_WHITE_MATTER_RIGHT: contralateralStructure = CEREBELLAR_WHITE_MATTER_LEFT; break; case CORTEX: break; case CORTEX_LEFT: contralateralStructure = CORTEX_RIGHT; break; case CORTEX_RIGHT: contralateralStructure = CORTEX_LEFT; break; case DIENCEPHALON_VENTRAL_LEFT: contralateralStructure = DIENCEPHALON_VENTRAL_RIGHT; break; case DIENCEPHALON_VENTRAL_RIGHT: contralateralStructure = DIENCEPHALON_VENTRAL_LEFT; break; case HIPPOCAMPUS_LEFT: contralateralStructure = HIPPOCAMPUS_RIGHT; break; case HIPPOCAMPUS_RIGHT: contralateralStructure = HIPPOCAMPUS_LEFT; break; case INVALID: contralateralStructure = INVALID; break; case PALLIDUM_LEFT: contralateralStructure = PALLIDUM_RIGHT; break; case PALLIDUM_RIGHT: contralateralStructure = PALLIDUM_LEFT; break; case OTHER: contralateralStructure = INVALID; break; case OTHER_GREY_MATTER: break; case OTHER_WHITE_MATTER: break; case PUTAMEN_LEFT: contralateralStructure = PUTAMEN_RIGHT; break; case PUTAMEN_RIGHT: contralateralStructure = PUTAMEN_LEFT; break; // case SUBCORTICAL_WHITE_MATTER_LEFT: // contralateralStructure = SUBCORTICAL_WHITE_MATTER_RIGHT; // break; // case SUBCORTICAL_WHITE_MATTER_RIGHT: // contralateralStructure = SUBCORTICAL_WHITE_MATTER_LEFT; // break; case THALAMUS_LEFT: contralateralStructure = THALAMUS_RIGHT; break; case THALAMUS_RIGHT: contralateralStructure = THALAMUS_LEFT; break; } return contralateralStructure; } connectome-workbench-1.4.2/src/Common/StructureEnum.h000066400000000000000000000126241360521144700226550ustar00rootroot00000000000000#ifndef __STRUCTURE_ENUM__H_ #define __STRUCTURE_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { /** * \brief Enumerated type for a structure in a brain. * * Enumerated types for the individual structures in a brain. */ class StructureEnum { public: /** * Enumerated values. */ enum Enum { /** Invalid */ INVALID, /** All Strucures */ ALL, /** All white matter */ ALL_WHITE_MATTER, /** All grey matter */ ALL_GREY_MATTER, /** Left Nucleus Accumbens */ ACCUMBENS_LEFT, /** Right Nucleus Accumbens */ ACCUMBENS_RIGHT, /** Left Amygdala */ AMYGDALA_LEFT, /** Right Amygdala */ AMYGDALA_RIGHT, /** Brain Stem */ BRAIN_STEM, /** Left Caudate */ CAUDATE_LEFT, /** Right Caudate */ CAUDATE_RIGHT, /** Cerebellar white matter left */ CEREBELLAR_WHITE_MATTER_LEFT, /** Cerebellar white matter right */ CEREBELLAR_WHITE_MATTER_RIGHT, /** Cerebellum */ CEREBELLUM, /** Left Cerebellum */ CEREBELLUM_LEFT, /** Right Cerebellum */ CEREBELLUM_RIGHT, /** Cerebral white matter left */ CEREBRAL_WHITE_MATTER_LEFT, /** Cerebral white matter right */ CEREBRAL_WHITE_MATTER_RIGHT, /** Cortex not specified */ CORTEX, /** Left Cerebral Cortex */ CORTEX_LEFT, /** Right Cerebral Cortex*/ CORTEX_RIGHT, /** Left Ventral Diencephalon */ DIENCEPHALON_VENTRAL_LEFT, /** Right Ventral Diencephalon */ DIENCEPHALON_VENTRAL_RIGHT, /** Left Hippocampus */ HIPPOCAMPUS_LEFT, /** Right Hippocampus */ HIPPOCAMPUS_RIGHT, /** Left Pallidum */ PALLIDUM_LEFT, /** Right Pallidum */ PALLIDUM_RIGHT, /** Other structure not specified */ OTHER, /** Other grey matter */ OTHER_GREY_MATTER, /** Other white matter */ OTHER_WHITE_MATTER, /** Left Putamen */ PUTAMEN_LEFT, /** Right Putamen */ PUTAMEN_RIGHT, // /** Left Subcortical White Matter */ // SUBCORTICAL_WHITE_MATTER_LEFT, // /** Right Subcortical White Matter */ // SUBCORTICAL_WHITE_MATTER_RIGHT, /** Left Thalamus */ THALAMUS_LEFT, /** Right Thalamus */ THALAMUS_RIGHT }; ~StructureEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static AString toCiftiName(Enum enumValue); static Enum fromCiftiName(const AString& ciftiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static bool isRight(const Enum enumValue); static bool isLeft(const Enum enumValue); static bool isSingleStructure(const Enum enumValue); static bool isCortexContralateral(const Enum enumValueA, const Enum enumValueB); static Enum getContralateralStructure(const Enum enumValue); private: StructureEnum(const Enum enumValue, const AString& name, const AString& guiName); static const StructureEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; static int32_t integerCodeGenerator; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __STRUCTURE_ENUM_DECLARE__ std::vector StructureEnum::enumData; bool StructureEnum::initializedFlag = false; int32_t StructureEnum::integerCodeGenerator = 0; #endif // __STRUCTURE_ENUM_DECLARE__ } // namespace #endif //__STRUCTURE_ENUM__H_ connectome-workbench-1.4.2/src/Common/SystemUtilities.cxx000066400000000000000000000436551360521144700235730ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #ifdef CARET_OS_WINDOWS #include #else #include #endif #include #include #include #include #include #include "CaretOMP.h" #ifndef _WIN32 #include "execinfo.h" #else #include "Windows.h" #endif #include "CaretCommandLine.h" #include "CaretLogger.h" #include "SystemUtilities.h" using namespace caret; AString commandLine;//used to store the command line for output by unexpected handler /** * Constructor. */ SystemUtilities::SystemUtilities() { } /** * Destructor */ SystemUtilities::~SystemUtilities() { } #include /** * Get the backtrace in a string with each frame * separated by a newline character. * * @return * String containing the backtrace. */ AString SystemUtilities::getBackTrace() { /* #ifdef CARET_OS_WINDOWS return ""; #else // CARET_OS_WINDOWS std::stringstream str; void* callstack[1024]; int numFrames = backtrace(callstack, 1024); char** symbols = backtrace_symbols(callstack, numFrames); for (int i = 0; i < numFrames; i++) { str << symbols[i] << std::endl; } return AString::fromStdString(str.str()); #endif // CARET_OS_WINDOWS */ std::vector backTrace; SystemUtilities::getBackTrace(backTrace); std::stringstream str; for (std::vector::const_iterator iter = backTrace.begin(); iter != backTrace.end(); iter++) { str << *iter << std::endl; } return AString::fromStdString(str.str()); } /** * Get the backtrace with the frames in a vector of strings. * * @param backTraceOut * Vector of string containg the call stack. */ void SystemUtilities::getBackTrace(std::vector& backTraceOut) { backTraceOut.clear(); #ifdef CARET_OS_WINDOWS #else // CARET_OS_WINDOWS void* callstack[1024]; int numFrames = backtrace(callstack, 1024); char** symbols = backtrace_symbols(callstack, numFrames); for (int i = 0; i < numFrames; i++) { backTraceOut.push_back(symbols[i]); } free(symbols); #endif // CARET_OS_WINDOWS } void SystemUtilities::getBackTrace(SystemBacktrace& backTraceOut) { #ifdef CARET_OS_WINDOWS #else // CARET_OS_WINDOWS backTraceOut.m_numFrames = backtrace(backTraceOut.m_callstack, 1024); #endif // CARET_OS_WINDOWS } SystemBacktrace::SystemBacktrace() { #ifndef CARET_OS_WINDOWS m_numFrames = 0; #endif } /** * @return String containing the backtrace symbols. */ AString SystemBacktrace::toSymbolString() const { std::stringstream str; #ifdef CARET_OS_WINDOWS #else // CARET_OS_WINDOWS char** symbols = backtrace_symbols(m_callstack, m_numFrames); for (int i = 0; i < m_numFrames; ++i) { str << symbols[i] << std::endl; } free(symbols); #endif // CARET_OS_WINDOWS return AString::fromStdString(str.str()); } /** * Get the temporary directory. * * @return Path of temporary directory. * */ AString SystemUtilities::getTempDirectory() { return QDir::tempPath(); } /** * Get the user's name. * * @return Name of user. * */ AString SystemUtilities::getUserName() { #ifdef CARET_OS_WINDOWS const QString name(getenv("USERNAME")); #else // CARET_OS_WINDOWS QString name(getlogin()); if (name.isEmpty()) { name = getenv("USERNAME"); } #endif // CARET_OS_WINDOWS return name; } /** * @return The four digit year. */ AString SystemUtilities::getYear() { QDateTime dateTime = QDateTime::currentDateTime(); AString s = dateTime.toString("yyyy"); return s; } /** * Get the date as ISO format yyyy-mm-dd (2009-12-09) * * @return A string containing the date. * */ AString SystemUtilities::getDate() { QDateTime dateTime = QDateTime::currentDateTime(); AString s = dateTime.toString("yyyy:MM:dd"); return s; } /** * Get the time as ISO format hh:mm:ss (11:42:28) * * @return A string containing the time. * */ AString SystemUtilities::getTime() { QDateTime dateTime = QDateTime::currentDateTime(); AString s = dateTime.toString("hh:mm:ss"); return s; } /** * Get the date and time as month, day, year, hour:min:sec AM/PM * * @return Data and Time. * */ AString SystemUtilities::getDateAndTime() { AString s = (SystemUtilities::getDate() + "T" + SystemUtilities::getTime()); return s; } /** * Is the operating system the Microsoft Windows operating system? * * @return true if the operating system is Microsoft Windows. * */ bool SystemUtilities::isWindowsOperatingSystem() { #ifdef CARET_OS_WINDOWS return true; #endif return false; } /** * Is the operating system the Mac OSX operating system? * * @return true if the operating system is Mac OSX. * */ bool SystemUtilities::isMacOperatingSystem() { #ifdef CARET_OS_MACOSX return true; #endif return false; } /** * Get the number of processors in the computer. * * @return The number of processors. * */ int32_t SystemUtilities::getNumberOfProcessors() { #ifdef CARET_OMP return omp_get_num_procs(); #endif return 1; } /** * Unit testing of assertions. * * @param stream * Stream to which messages are written. * @param isVerbose * Print detailed messages. */ void SystemUtilities::unitTest(std::ostream& stream, const bool /*isVerbose*/) { #ifdef NDEBUG stream << "Unit testing of CaretAssertion will not take place since software is not compiled with debug on." << std::endl; return; #endif stream << "SystemUtilities::unitTest is starting" << std::endl; /* * Redirect std::err to the string stream. */ std::ostringstream str; std::streambuf* cerrSave = std::cerr.rdbuf(); std::cerr.rdbuf(str.rdbuf()); testRelativePath("/surface02/john/caret_data/HUMAN.COLIN.ATLAS", "/surface02/john/caret_data/HUMAN.COLIN.ATLAS/RIGHT_HEM", ".."); testRelativePath("/surface02/john/caret_data/HUMAN.COLIN.ATLAS/RIGHT_HEM", "/surface02/john/caret_data/HUMAN.COLIN.ATLAS", "RIGHT_HEM"); testRelativePath("/surface02/john/caret_data/HUMAN.COLIN.ATLAS/RIGHT_HEM/subdir", "/surface02/john/caret_data/HUMAN.COLIN.ATLAS/RIGHT_HEM", "subdir"); testRelativePath("/surface02/john/caret_data/HUMAN.COLIN.ATLAS/LEFT_HEM/subdir", "/surface02/john/caret_data/HUMAN.COLIN.ATLAS/RIGHT_HEM", "../LEFT_HEM/subdir"); testRelativePath("root:/var/etc", "remove:/usr/local", "root:/var/etc"); // testRelativePath("/Volumes/DS4600/caret7_gui_design/data/HCP_demo/Glasser_PilotIII.L.very_inflated.20k_fs_LR.surf.gii", // "/Volumes/DS4600/caret7_gui_design/data/HCP_demo/border.spec", // "border.spec"); /* * Restore std::err */ std::cerr.rdbuf(cerrSave); stream << "SystemUtilities::unitTest has ended" << std::endl << std::endl;; } /** * Test the relative path method. * @param otherPath - determine relative path to otherpath * @param myPath - from myPath * @param correctResult - The correct result * @return true if test passes. * */ bool SystemUtilities::testRelativePath( const AString& otherPath, const AString& myPath, const AString& correctResult) { bool correctFlag = false; AString result = relativePath(otherPath, myPath); if (result == correctResult) { correctFlag = true; } else { std::cerr << "SystemUtilities.relativePath() failed:" << std::endl; std::cerr << " otherPath: " + otherPath << std::endl; std::cerr << " myPath: " + myPath << std::endl; std::cerr << " result: " + result << std::endl; std::cerr << " correct: " + correctResult << std::endl; } return correctFlag; } /** * @return A Universally Unique Identifier (UUID). */ AString SystemUtilities::createUniqueID() { const AString uuid = QUuid::createUuid().toString(); return uuid; } /** * Given the directory "mypath", determine the relative path to "otherpath". * Both input paths must be absolute paths, otherwise, otherPathIn is * returned. * * Examples: * otherpath - "/surface02/john/caret_data/HUMAN.COLIN.ATLAS" * mypath - "/surface02/john/caret_data/HUMAN.COLIN.ATLAS/RIGHT_HEM" * result - ".."; * * otherpath - "/surface02/john/caret_data/HUMAN.COLIN.ATLAS/RIGHT_HEM/subdir" * mypath - "/surface02/john/caret_data/HUMAN.COLIN.ATLAS/RIGHT_HEM" * result - "subdir"; * * otherpath - "/surface02/john/caret_data/HUMAN.COLIN.ATLAS/LEFT_HEM/subdir" * mypath - "/surface02/john/caret_data/HUMAN.COLIN.ATLAS/RIGHT_HEM" * result - "../LEFT_HEM/subdir"; * * @param otherPathIn - The path for which relative path is sought. * @param myPathIn - Get the path from this * @return The relative path * */ AString SystemUtilities::relativePath( const AString& otherPathIn, const AString& myPathIn) { AString result = otherPathIn; // // Check for either path being empty // if (otherPathIn.isEmpty() || myPathIn.isEmpty()) { return result; } #ifdef CARET_OS_WINDOWS // // Both paths must be absolute paths // if (otherPathIn.indexOf(":") < 0) { return result; } if (myPathIn.indexOf(":") < 0) { return result; } #else // // Both paths must be absolute paths // if ((otherPathIn[0] != '/') || (myPathIn[0] != '/')) { return result; } #endif QStringList otherPath = QDir::cleanPath(otherPathIn).split(QRegExp("[/\\\\]"), QString::SkipEmptyParts); QStringList myPath = QDir::cleanPath(myPathIn).split(QRegExp("[/\\\\]"), QString::SkipEmptyParts); const unsigned int minLength = std::min(myPath.size(), otherPath.size()); int sameCount = 0; for (unsigned int i = 0; i < minLength; i++) { if (myPath[i] == otherPath[i]) { //cout << "Match: |" << myPath[i] << "|" << std::endl; sameCount++; } else { break; } } //cout << "same count: " << sameCount << std::endl; // // Is root of both paths different // if (sameCount == 0) { result = otherPathIn; } /* * Always use a forward slash for the separator, even on Windows, * so that paths are valid on Unix (Qt does not handle backslashes * properly on Unix) */ const AString separatorCharacter("/"); // // Is other path a subdirectory of mypath // if (sameCount == myPath.size()) { result = ""; for (int j = sameCount; j < otherPath.size(); j++) { result.append(otherPath[j]); if (j < (otherPath.size() - 1)) { result.append(separatorCharacter); } } } // // otherpath is above this one // result = ""; for (int j = sameCount; j < myPath.size(); j++) { result.append(".."); if (j < (myPath.size() - 1)) { result.append(separatorCharacter); } } for (int k = sameCount; k < otherPath.size(); k++) { if (result.isEmpty() == false) { result.append(separatorCharacter); } result.append(otherPath[k]); } return result; } /** * Unexpected handler */ static void unexpectedHandler() { std::cerr << "While running '" << caret_global_commandLine << "':" << std::endl; std::cerr << std::endl; std::cerr << "ERROR: unhandled exception." << std::endl; //if (theMainWindow != NULL) { const AString msg("Workbench will be terminating due to an unexpected exception.\n" "abort() will be called and a core file may be created."); std::cerr << msg << std::endl; //QMessageBox::critical(theMainWindow, "ERROR", msg); //} std::cerr << SystemUtilities::getBackTrace() << std::endl; abort(); } /** * New handler */ static void newHandler() { std::cerr << "While running '" << caret_global_commandLine << "':" << std::endl; std::ostringstream str; str << "\n" << "OUT OF MEMORY\n" << "\n" << "This means that Workbench is unable to get memory that it needs.\n" << "Possible causes:\n" << " (1) Your computer lacks sufficient RAM.\n" << " (2) Swap space is too small (you might increase it).\n" << " (3) Your computer may be using an non-English character \n" << " set. Try switching to the English character set.\n" << "\n"; std::cerr << str.str().c_str() << std::endl; std::cerr << SystemUtilities::getBackTrace() << std::endl; abort(); //if (theMainWindow != NULL) { // QMessageBox::critical(theMainWindow, "OUT OF MEMORY", // "Out of memory, Caret terminating"); // std::exit(-1); //} } /** * Set the handler for an unexpected (uncaught) exception. */ void SystemUtilities::setUnexpectedHandler() { std::set_unexpected(unexpectedHandler); } /** * Set the handler for when "operator new" is unable to allocate memory. * This new handler will print a message to the terminal containing a * backtrace and then calls abort to end the program. * * NOTE: If this new handler is set, "operator new" WILL NOT * throw a std::bad_alloc exception. */ void SystemUtilities::setNewHandler() { std::set_new_handler(newHandler); } /** * Return the current directory as indicated * by the system. In most cases, use the * methods in Brain to get and set the current * directory since it may be possible to have * multiple Brains each of which has its current * directory set to the directory containing the * SpecFile that was read. * * @return The path of the current directory. */ AString SystemUtilities::systemCurrentDirectory() { return QDir::currentPath(); } /* * From http://developer.qt.nokia.com/wiki/How_to_create_a_splash_screen_with_an_induced_delay */ class Sleeper : public QThread { public: static void sleepSeconds(const float seconds) { if (seconds > 0.0) { const unsigned long milliseconds = seconds * 1000.0; QThread::msleep(milliseconds); } } }; /** * Sleep for the specified number of seconds. The minimum * is one millisecond (0.001). * @param numberOfSeconds * Number of seconds to sleep. */ void SystemUtilities::sleepSeconds(const float numberOfSeconds) { Sleeper::sleepSeconds(numberOfSeconds); } /** * Get the workbench home directory * @return workbenchHomeDirectory * The path to the workbench installation */ AString SystemUtilities::getWorkbenchHome() { static QString workbenchHomeDirectory; if(workbenchHomeDirectory.isEmpty() == false) { return workbenchHomeDirectory; } QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); workbenchHomeDirectory = env.value ( AString("WORKBENCH_HOME") ); if (workbenchHomeDirectory.isEmpty()) { workbenchHomeDirectory = QCoreApplication::applicationDirPath(); if (workbenchHomeDirectory.isEmpty() == false) { #ifdef CARET_OS_MACOSX const bool appFlag = (workbenchHomeDirectory.indexOf(".app/") > 0); if (appFlag) { QDir dir(workbenchHomeDirectory); dir.cdUp(); dir.cdUp(); dir.cdUp(); workbenchHomeDirectory = dir.absolutePath(); } #endif } CaretLogFine("Workbench Home Directory: " + workbenchHomeDirectory); } return workbenchHomeDirectory = QDir::toNativeSeparators(workbenchHomeDirectory); } /** * @return The fully qualifed domain name for the local host. * * If failure, an empty string is returned and a message * is sent to the logger. * * If the address is a "loopback" (127.0.0.1) it typically * indicates that there is not a valid network connection * and an empty string is returned and a message is logged. */ AString SystemUtilities::getLocalHostName() { /* * NOTE: THIS FUNCTION DOES NOT SEEM TO WORK ON MACOS 10.14 MOJAVE. * THE LOCALHOST NAME IS .LOCAL WHERE IS THE COMPUTER'NAME * AND QHostInfo::fromName() DOES NOT MAKE IT FULLY QUALIFIED */ QString hostName; QHostInfo hostInfo = QHostInfo::fromName(QHostInfo::localHostName()); if (hostInfo.error() == QHostInfo::NoError) { for (auto address : hostInfo.addresses()) { if (address.isLoopback()) { CaretLogFine("Lookup of host found loopback address (localhost). May not have valid network connection"); return ""; } } hostName = hostInfo.hostName(); } else { CaretLogWarning("Lookup of local host name failed: " + hostInfo.errorString()); } return hostName; } connectome-workbench-1.4.2/src/Common/SystemUtilities.h000066400000000000000000000051541360521144700232100ustar00rootroot00000000000000#ifndef __SYSTEMUTILITIES_H__ #define __SYSTEMUTILITIES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include namespace caret { class SystemBacktrace { #ifdef CARET_OS_WINDOWS #else // CARET_OS_WINDOWS void* m_callstack[1024]; int m_numFrames; #endif // CARET_OS_WINDOWS public: SystemBacktrace(); AString toSymbolString() const; friend class SystemUtilities; }; /** * Methods to help out with files and directories. */ class SystemUtilities { private: SystemUtilities(); public: virtual ~SystemUtilities(); public: static AString getBackTrace(); static void getBackTrace(std::vector& backTraceOut); static void getBackTrace(SystemBacktrace& backTraceOut); static AString getTempDirectory(); static AString getUserName(); static AString getYear(); static AString getDate(); static AString getTime(); static AString getDateAndTime(); static bool isWindowsOperatingSystem(); static bool isMacOperatingSystem(); static int32_t getNumberOfProcessors(); static AString createUniqueID(); static void unitTest(std::ostream& stream, const bool isVerbose); static bool testRelativePath( const AString& otherPath, const AString& myPath, const AString& correctResult); static AString relativePath( const AString& otherPathIn, const AString& myPathIn); static void setUnexpectedHandler(); static void setNewHandler(); static AString systemCurrentDirectory(); static void sleepSeconds(const float numberOfSeconds); static AString getWorkbenchHome(); static AString getLocalHostName(); }; } // namespace #endif // __SYSTEMUTILITIES_H__ connectome-workbench-1.4.2/src/Common/TileTabsBaseConfiguration.cxx000066400000000000000000000211541360521144700254330ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __TILE_TABS_BASE_CONFIGURATION_DECLARE__ #include "TileTabsBaseConfiguration.h" #undef __TILE_TABS_BASE_CONFIGURATION_DECLARE__ #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "SystemUtilities.h" #include "TileTabsGridLayoutConfiguration.h" using namespace caret; /** * \class caret::TileTabsBaseConfiguration * \brief Defines a tile tabs configuration * \ingroup Common */ /** * Constructor that creates a 2 by 2 configuration. */ TileTabsBaseConfiguration::TileTabsBaseConfiguration(const TileTabsConfigurationLayoutTypeEnum::Enum layoutType) : CaretObject(), m_layoutType(layoutType) { initializeTileTabsBaseConfiguration(); } /** * Destructor. */ TileTabsBaseConfiguration::~TileTabsBaseConfiguration() { } /** * Copy constructor. * * NOTE: Unique identifier remains the same ! See also: newCopyWithNewUniqueIdentifier() * * @param obj * Object that is copied. */ TileTabsBaseConfiguration::TileTabsBaseConfiguration(const TileTabsBaseConfiguration& obj) : CaretObject(obj), m_layoutType(obj.m_layoutType) { const AString savedUniqueID = m_uniqueIdentifier; initializeTileTabsBaseConfiguration(); m_uniqueIdentifier = savedUniqueID; this->copyHelperTileTabsBaseConfiguration(obj); } /** * Assignment operator. * * NOTE: Unique identifier remains the same ! See also: newCopyWithNewUniqueIdentifier() * * @param obj * Data copied from obj to this. * @return * Reference to this object. */ TileTabsBaseConfiguration& TileTabsBaseConfiguration::operator=(const TileTabsBaseConfiguration& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperTileTabsBaseConfiguration(obj); } return *this; } /** * Initialize an instance of a tile tabs configuration. */ void TileTabsBaseConfiguration::initializeTileTabsBaseConfiguration() { m_name.clear(); m_uniqueIdentifier = SystemUtilities::createUniqueID(); } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void TileTabsBaseConfiguration::copyHelperTileTabsBaseConfiguration(const TileTabsBaseConfiguration& obj) { if (this == &obj) { return; } m_name = obj.m_name; //DO NOT CHANGE THE UNIQUE IDENTIFIER: m_uniqueIdentifier } /** * Copies the tile tabs configuration rows, columns, and * stretch factors. Name is NOT copied. */ void TileTabsBaseConfiguration::copy(const TileTabsBaseConfiguration& rhs) { CaretAssertToDoFatal(); // need to do this a different way AString savedName = m_name; copyHelperTileTabsBaseConfiguration(rhs); m_name = savedName; } /** * @return Type of layout for the configuration */ TileTabsConfigurationLayoutTypeEnum::Enum TileTabsBaseConfiguration::getLayoutType() const { return m_layoutType; } /** * @return the name of the tile tabs configuration. */ AString TileTabsBaseConfiguration::getName() const { return m_name; } /** * @return Get the unique identifier that uniquely identifies each configuration. */ AString TileTabsBaseConfiguration::getUniqueIdentifier() const { return m_uniqueIdentifier; } /** * Set the name of the tile tabs configuration. * * @param name * New name for configuration. */ void TileTabsBaseConfiguration::setName(const AString& name) { m_name = name; } /** * Set the unique identifier of the tile tabs configuration. * * @param uniqueID * New unique identifier for configuration. */ void TileTabsBaseConfiguration::setUniqueIdentifierProtected(const AString& uniqueID) { m_uniqueIdentifier = uniqueID; } /** * @return Encoded tile tabs configuration in XML */ AString TileTabsBaseConfiguration::encodeInXML() const { AString s; encodeInXML(s); return s; } /** * Decode the tile tabs configuration from XML * * @param xmlString * String containing XML. * @param errorMessageOut * Contains error information if decoding fails. * @return * Pointer to the configuration or NULL if there was an error. */ TileTabsBaseConfiguration* TileTabsBaseConfiguration::decodeFromXML(const AString& xmlString, AString& errorMessageOut) { errorMessageOut.clear(); TileTabsBaseConfiguration* configurationOut(NULL); QXmlStreamReader xml(xmlString); if (xml.readNextStartElement()) { const QStringRef tagName(xml.name()); if (tagName == TileTabsGridLayoutConfiguration::s_v1_rootTagName) { TileTabsGridLayoutConfiguration* v1 = new TileTabsGridLayoutConfiguration(); v1->decodeFromXML(xml, tagName.toString()); configurationOut = v1; } else if (tagName == TileTabsGridLayoutConfiguration::s_v2_rootTagName) { TileTabsGridLayoutConfiguration* v2 = new TileTabsGridLayoutConfiguration(); v2->decodeFromXML(xml, tagName.toString()); configurationOut = v2; } else { xml.raiseError("TileTabsBaseConfiguration first element is " + xml.name().toString() + " but should be " + TileTabsGridLayoutConfiguration::s_v1_rootTagName + " or " + TileTabsGridLayoutConfiguration::s_v2_rootTagName); } } else { xml.raiseError("TileTabsBaseConfiguration failed to find start elemnent."); } if (xml.hasError()) { errorMessageOut = ("Tile Tabs Configuration Read Error at line number=" + AString::number(xml.lineNumber()) + " column number=" + AString::number(xml.columnNumber()) + " description=" + xml.errorString()); if (configurationOut != NULL) { delete configurationOut; configurationOut = NULL; } return configurationOut; } const bool debugFlag(false); if (debugFlag) { // AString xmlText = encodeInXMLWithStreamWriterVersionTwo(); // std::cout << std::endl << "NEW: " << xmlText << std::endl << std::endl; // AString em; // TileTabsBaseConfiguration temp; // QXmlStreamReader tempReader(xmlText); // tempReader.readNextStartElement(); // temp.decodeFromXMLWithStreamReaderVersionTwo(tempReader); // if (tempReader.hasError()) { // std::cout << "Decode error: " << tempReader.errorString() << std::endl; // } // else { // std::cout << "Decoded: " << temp.toString() << std::endl; // } // // std::cout << std::endl; } return configurationOut; } /** * @return String version of an instance. */ AString TileTabsBaseConfiguration::toString() const { AString s("Name: %1, Unique ID: %2\n"); s = s.arg(m_name).arg(m_uniqueIdentifier); // // int32_t indx(0); // for (const auto item : m_columns) { // s.append(" Column " + AString::number(indx) + ": " + item.toString() + "\n"); // indx++; // } // indx = 0; // for (const auto item : m_rows) { // s.append(" Row " + AString::number(indx) + ": " + item.toString() + "\n"); // indx++; // } return s; } /** * Compare two tile tabs configurations by name. * * @param ttc1 * First tile tab configuration. * @param ttc2 * Second tile tab configuration. * @return * True if ttc1 is "less than" when compared by name, else false. */ bool TileTabsBaseConfiguration::lessThanComparisonByName(const TileTabsBaseConfiguration* ttc1, const TileTabsBaseConfiguration* ttc2) { if (ttc1->getName() < ttc2->getName()) { return true; } return false; } connectome-workbench-1.4.2/src/Common/TileTabsBaseConfiguration.h000066400000000000000000000075711360521144700250670ustar00rootroot00000000000000#ifndef __TILE_TABS_BASE_CONFIGURATION_H__ #define __TILE_TABS_BASE_CONFIGURATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretException.h" #include "CaretObject.h" #include "TileTabsConfigurationLayoutTypeEnum.h" #include "TileTabsGridModeEnum.h" #include "TileTabsGridRowColumnElement.h" class QXmlStreamReader; class QXmlStreamWriter; namespace caret { class TileTabsBaseConfiguration : public CaretObject { protected: TileTabsBaseConfiguration(const TileTabsConfigurationLayoutTypeEnum::Enum layoutType); public: virtual ~TileTabsBaseConfiguration(); TileTabsBaseConfiguration(const TileTabsBaseConfiguration& obj); TileTabsBaseConfiguration& operator=(const TileTabsBaseConfiguration& obj); void copy(const TileTabsBaseConfiguration& rhs); virtual TileTabsBaseConfiguration* newCopyWithNewUniqueIdentifier() const = 0; TileTabsConfigurationLayoutTypeEnum::Enum getLayoutType() const; AString getName() const; void setName(const AString& name); AString getUniqueIdentifier() const; AString encodeInXML() const; static TileTabsBaseConfiguration* decodeFromXML(const AString& xmlString, AString& errorMessageOut); AString toString() const override; static bool lessThanComparisonByName(const TileTabsBaseConfiguration* ttc1, const TileTabsBaseConfiguration* ttc2); // ADD_NEW_METHODS_HERE protected: /** * Decode the configuration using the given XML stream reader and root element * If there is an error, xml.raiseError() should be used to specify the error * and caller of this method can test for the error using xml.isError(). * * @param xml * The XML stream reader. * @param rootElement * The root element. */ virtual void decodeFromXML(QXmlStreamReader& xml, const QString& rootElementText) = 0; /** * Encode the configuration in XML. * * @param xmlTextOut * Contains XML representation of configuration. */ virtual void encodeInXML(AString& xmlTextOut) const = 0; void setUniqueIdentifierProtected(const AString& uniqueID); void copyHelperTileTabsBaseConfiguration(const TileTabsBaseConfiguration& obj); private: void initializeTileTabsBaseConfiguration(); // ADD_NEW_MEMBERS_HERE const TileTabsConfigurationLayoutTypeEnum::Enum m_layoutType; AString m_name; /** Unique identifier does not get copied */ AString m_uniqueIdentifier; }; #ifdef __TILE_TABS_BASE_CONFIGURATION_DECLARE__ #endif // __TILE_TABS_BASE_CONFIGURATION_DECLARE__ } // namespace #endif //__TILE_TABS_BASE_CONFIGURATION_H__ connectome-workbench-1.4.2/src/Common/TileTabsConfiguration.cxx000066400000000000000000001105001360521144700246320ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __TILE_TABS_CONFIGURATION_DECLARE__ #include "TileTabsConfiguration.h" #undef __TILE_TABS_CONFIGURATION_DECLARE__ #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "SystemUtilities.h" using namespace caret; /** * \class caret::TileTabsConfiguration * \brief Defines a tile tabs configuration * \ingroup Common */ /** * Constructor that creates a 2 by 2 configuration. */ TileTabsConfiguration::TileTabsConfiguration() : CaretObject() { initialize(); } /** * Destructor. */ TileTabsConfiguration::~TileTabsConfiguration() { } /** * Copy constructor. * * NOTE: Unique identifier remains the same ! See also: newCopyWithNewUniqueIdentifier() * * @param obj * Object that is copied. */ TileTabsConfiguration::TileTabsConfiguration(const TileTabsConfiguration& obj) : CaretObject(obj) { const AString savedUniqueID = m_uniqueIdentifier; initialize(); m_uniqueIdentifier = savedUniqueID; this->copyHelperTileTabsConfiguration(obj); } /** * Assignment operator. * * NOTE: Unique identifier remains the same ! See also: newCopyWithNewUniqueIdentifier() * * @param obj * Data copied from obj to this. * @return * Reference to this object. */ TileTabsConfiguration& TileTabsConfiguration::operator=(const TileTabsConfiguration& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperTileTabsConfiguration(obj); } return *this; } /** * Copy this instance and give it a new unique identifier. * Note that copy constructor does not create a new unique identifier. * * @return The new Copy. */ TileTabsConfiguration* TileTabsConfiguration::newCopyWithNewUniqueIdentifier() const { TileTabsConfiguration* newCopy = new TileTabsConfiguration(*this); CaretAssert(newCopy); newCopy->m_uniqueIdentifier = SystemUtilities::createUniqueID(); return newCopy; } /** * Initialize an instance of a tile tabs configuration. */ void TileTabsConfiguration::initialize() { setNumberOfRows(2); setNumberOfColumns(2); m_name.clear(); m_uniqueIdentifier = SystemUtilities::createUniqueID(); m_centeringCorrectionEnabled = false; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void TileTabsConfiguration::copyHelperTileTabsConfiguration(const TileTabsConfiguration& obj) { if (this == &obj) { return; } m_name = obj.m_name; m_columns = obj.m_columns; m_rows = obj.m_rows; m_centeringCorrectionEnabled = obj.m_centeringCorrectionEnabled; //DO NOT CHANGE THE UNIQUE IDENTIFIER: m_uniqueIdentifier } /** * Copies the tile tabs configuration rows, columns, and * stretch factors. Name is NOT copied. */ void TileTabsConfiguration::copy(const TileTabsConfiguration& rhs) { AString savedName = m_name; copyHelperTileTabsConfiguration(rhs); m_name = savedName; } /** * Get infoformation for the given elemnent in the columns. * * @param Information for element. */ TileTabsGridRowColumnElement* TileTabsConfiguration::getColumn(const int32_t columnIndex) { CaretAssertVectorIndex(m_columns, columnIndex); return &m_columns[columnIndex]; } /** * Get infoformation for the given elemnent in the columns. * * @param Information for element. */ const TileTabsGridRowColumnElement* TileTabsConfiguration::getColumn(const int32_t columnIndex) const { CaretAssertVectorIndex(m_columns, columnIndex); return &m_columns[columnIndex]; } /** * Get infoformation for the given elemnent in the rows. * * @param Information for element. */ TileTabsGridRowColumnElement* TileTabsConfiguration::getRow(const int32_t rowIndex) { CaretAssertVectorIndex(m_rows, rowIndex); return &m_rows[rowIndex]; } /** * Get infoformation for the given elemnent in the rows. * * @param Information for element. */ const TileTabsGridRowColumnElement* TileTabsConfiguration::getRow(const int32_t rowIndex) const { CaretAssertVectorIndex(m_rows, rowIndex); return &m_rows[rowIndex]; } /** * Get the row heights and column widths for this tile tabs configuration using the * given window width and height. * * @param windowWidth * Width of window. * @param windowHeight * Height of window. * @param numberOfModelsToDraw * Number of models to draw. * @param configurationMode * The tile tabs configuration mode * @param rowHeightsOut * Output containing height of each row. * @param columnWidthsOut * Output containing width of each column. * @return * True if the ouput is valid, else false. */ bool TileTabsConfiguration::getRowHeightsAndColumnWidthsForWindowSize(const int32_t windowWidth, const int32_t windowHeight, const int32_t numberOfModelsToDraw, const TileTabsGridModeEnum::Enum configurationMode, std::vector& rowHeightsOut, std::vector& columnWidthsOut) { /* * NOTE: When computing widths and heights, do not round. * Rounding may cause the bottom most row or column to extend * outside the graphics region. Shrinking the last row or * column is not desired since it might cause the last model * to be drawn slightly smaller than the others. */ int32_t numRows = 0; int32_t numCols = 0; rowHeightsOut.clear(); columnWidthsOut.clear(); switch (configurationMode) { case TileTabsGridModeEnum::AUTOMATIC: { /* * Update number of rows/columns in the default configuration * so that if a scene is saved, the correct number of rows * and columns are saved to the scene. */ updateAutomaticConfigurationRowsAndColumns(numberOfModelsToDraw); numRows = getNumberOfRows(); numCols = getNumberOfColumns(); for (int32_t i = 0; i < numRows; i++) { rowHeightsOut.push_back(windowHeight / numRows); } for (int32_t i = 0; i < numCols; i++) { columnWidthsOut.push_back(windowWidth / numCols); } } break; case TileTabsGridModeEnum::CUSTOM: { /* * Rows/columns from user configuration */ numRows = getNumberOfRows(); numCols = getNumberOfColumns(); /* * Determine height of each row */ float rowPercentTotal = 0.0; float rowStretchTotal = 0.0; for (int32_t i = 0; i < numRows; i++) { const TileTabsGridRowColumnElement* e = getRow(i); switch (e->getStretchType()) { case TileTabsGridRowColumnStretchTypeEnum::PERCENT: rowPercentTotal += (e->getPercentStretch() / 100.0); break; case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: rowStretchTotal += e->getWeightStretch(); break; } } float windowWeightHeight = windowHeight; if (rowPercentTotal > 0.0) { if (rowPercentTotal >= 1.0) { windowWeightHeight = 0.0; } else { windowWeightHeight = (1.0 - rowPercentTotal) * windowHeight; } } for (int32_t i = 0; i < numRows; i++) { int32_t h = 0; const TileTabsGridRowColumnElement* e = getRow(i); switch (e->getStretchType()) { case TileTabsGridRowColumnStretchTypeEnum::PERCENT: h = (e->getPercentStretch() / 100.0) * windowHeight; break; case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: if (rowStretchTotal > 0.0) { h = static_cast((e->getWeightStretch() / rowStretchTotal) * windowWeightHeight); } break; } rowHeightsOut.push_back(h); } /* * Determine width of each column */ float columnPercentTotal = 0.0; float columnStretchTotal = 0.0; for (int32_t i = 0; i < numCols; i++) { const TileTabsGridRowColumnElement* e = getColumn(i); switch (e->getStretchType()) { case TileTabsGridRowColumnStretchTypeEnum::PERCENT: columnPercentTotal += (e->getPercentStretch() / 100.0); break; case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: columnStretchTotal += e->getWeightStretch(); break; } } float windowWeightWidth = windowWidth; if (columnPercentTotal > 0.0) { if (columnPercentTotal >= 1.0) { windowWeightWidth = 0.0; } else { windowWeightWidth = (1.0 - columnPercentTotal) * windowWidth; } } for (int32_t i = 0; i < numCols; i++) { int32_t w = 0; const TileTabsGridRowColumnElement* e = getColumn(i); switch (e->getStretchType()) { case TileTabsGridRowColumnStretchTypeEnum::PERCENT: w = (e->getPercentStretch() / 100.0) * windowWidth; break; case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: if (columnStretchTotal > 0.0) { w = static_cast((e->getWeightStretch() / columnStretchTotal) * windowWeightWidth); } break; } columnWidthsOut.push_back(w); } } break; } if ((numRows == static_cast(rowHeightsOut.size())) && (numCols == static_cast(columnWidthsOut.size()))) { // /* // * Verify all rows fit within the window // */ // int32_t rowHeightsSum = 0; // for (int32_t i = 0; i < numRows; i++) { // rowHeightsSum += rowHeightsOut[i]; // } // if (rowHeightsSum > windowHeight) { // CaretLogSevere("PROGRAM ERROR: Tile Tabs total row heights exceed window height"); //// rowHeightsOut[numRows - 1] -= (rowHeightsSum - windowHeight); // } // // /* // * Adjust width of last column so that it does not extend beyond viewport // */ // int32_t columnWidthsSum = 0; // for (int32_t i = 0; i < numCols; i++) { // columnWidthsSum += columnWidthsOut[i]; // } // if (columnWidthsSum > windowWidth) { // CaretLogSevere("PROGRAM ERROR: Tile Tabs total row heights exceed window height"); //// columnWidthsOut[numCols - 1] = columnWidthsSum - windowWidth; // } // // CaretLogFiner("Tile Tabs Row Heights: " // + AString::fromNumbers(rowHeightsOut, ", ")); // CaretLogFiner("Tile Tabs Column Widths: " // + AString::fromNumbers(columnWidthsOut, ", ")); return true; } const QString msg("Row and heights failed rows=" + AString::number(numRows) + " rowHeights=" + AString::number(rowHeightsOut.size()) + " cols=" + AString::number(numCols) + " rowHeights=" + AString::number(columnWidthsOut.size())); CaretAssertMessage(0, msg); CaretLogSevere(msg); return false; } /** * @return the name of the tile tabs configuration. */ AString TileTabsConfiguration::getName() const { return m_name; } /** * @return Get the unique identifier that uniquely identifies each configuration. */ AString TileTabsConfiguration::getUniqueIdentifier() const { return m_uniqueIdentifier; } /** * Set the name of the tile tabs configuration. * * @param name * New name for configuration. */ void TileTabsConfiguration::setName(const AString& name) { m_name = name; } /** * @return Number of rows. */ int32_t TileTabsConfiguration::getNumberOfRows() const { return m_rows.size(); } /** * Set number of rows. * * @param numberOfRows * New number of rows. */ void TileTabsConfiguration::setNumberOfRows(const int32_t numberOfRows) { m_rows.resize(numberOfRows); } /** * @return Number of columns. */ int32_t TileTabsConfiguration::getNumberOfColumns() const { return m_columns.size(); } /** * Set number of rows. * * @param numberOfColumns * New number of rows. */ void TileTabsConfiguration::setNumberOfColumns(const int32_t numberOfColumns) { m_columns.resize(numberOfColumns); } /** * Get the number of rows and columns for an automatic layout with the * given number of tabs. * @param numberOfTabs * Number of tabs. * @param numberOfRowsOut * Output with number of rows. * @param numberOfColumnsOut * Output with number of columns. */ void TileTabsConfiguration::getRowsAndColumnsForNumberOfTabs(const int32_t numberOfTabs, int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) { CaretAssert(numberOfTabs >= 0); numberOfRowsOut = (int)std::sqrt((double)numberOfTabs); numberOfColumnsOut = numberOfRowsOut; int32_t row2 = numberOfRowsOut * numberOfRowsOut; if (row2 < numberOfTabs) { numberOfColumnsOut++; } if ((numberOfRowsOut * numberOfColumnsOut) < numberOfTabs) { numberOfRowsOut++; } } /** * @return True if the centering correction is enabled. */ bool TileTabsConfiguration::isCenteringCorrectionEnabled() const { return m_centeringCorrectionEnabled; } /** * Set the enabled status of the centering correction * * @param status * New status for enabling the centering correction */ void TileTabsConfiguration::setCenteringCorrectionEnabled(const bool status) { m_centeringCorrectionEnabled = status; } /** * Updates the number of rows and columns for the automatic configuration * based upon the number of tabs. * * Since screen width typically exceeds height, ensure the number of * columns is always greater than the number of rows. */ void TileTabsConfiguration::updateAutomaticConfigurationRowsAndColumns(const int32_t numberOfTabs) { int32_t numRows(0), numCols(0); getRowsAndColumnsForNumberOfTabs(numberOfTabs, numRows, numCols); setNumberOfRows(numRows); setNumberOfColumns(numCols); } /** * @return Encoded tile tabs configuration in XML */ AString TileTabsConfiguration::encodeInXML() const { return encodeVersionInXML(2); } /** * @return Encoded tile tabs configuration in XML * using the give XML version of TileTabsConfiguration. */ AString TileTabsConfiguration::encodeVersionInXML(const int32_t versionNumber) const { AString s; switch (versionNumber) { case 1: s = encodeInXMLWithStreamWriterVersionOne(); break; case 2: s = encodeInXMLWithStreamWriterVersionTwo(); break; default: CaretAssertMessage(0, "Requested invalid version=" + AString::number(versionNumber)); break; } return s; } /** * @return Encoded tile tabs configuration in XML with Stream Writer */ AString TileTabsConfiguration::encodeInXMLWithStreamWriterVersionOne() const { AString xmlString; QXmlStreamWriter writer(&xmlString); writer.setAutoFormatting(true); writer.writeStartElement(s_v1_rootTagName); writer.writeStartElement(s_v1_versionTagName); writer.writeAttribute(s_v1_versionNumberAttributeName, "1"); writer.writeEndElement(); writer.writeTextElement(s_nameTagName, m_name); writer.writeTextElement(s_uniqueIdentifierTagName, m_uniqueIdentifier); const int32_t numberOfRows = getNumberOfRows(); writer.writeStartElement(s_v1_rowStretchFactorsTagName); writer.writeAttribute(s_v1_rowStretchFactorsSelectedCountAttributeName, AString::number(numberOfRows)); writer.writeAttribute(s_v1_rowStretchFactorsTotalCountAttributeName, AString::number(numberOfRows)); std::vector rowStretchFactors; for (const auto e : m_rows) { rowStretchFactors.push_back(e.getWeightStretch()); } writer.writeCharacters(AString::fromNumbers(rowStretchFactors, " ")); writer.writeEndElement(); const int32_t numberOfColumns = getNumberOfColumns(); writer.writeStartElement(s_v1_columnStretchFactorsTagName); writer.writeAttribute(s_v1_columnStretchFactorsSelectedCountAttributeName, AString::number(numberOfColumns)); writer.writeAttribute(s_v1_columnStretchFactorsTotalCountAttributeName, AString::number(numberOfColumns)); std::vector columnStretchFactors; for (const auto e : m_columns) { columnStretchFactors.push_back(e.getWeightStretch()); } writer.writeCharacters(AString::fromNumbers(columnStretchFactors, " ")); writer.writeEndElement(); writer.writeEndElement(); return xmlString; } /** * @return Encoded tile tabs configuration in XML with Stream Writer */ AString TileTabsConfiguration::encodeInXMLWithStreamWriterVersionTwo() const { AString xmlString; QXmlStreamWriter writer(&xmlString); writer.setAutoFormatting(true); writer.writeStartElement(s_v2_rootTagName); writer.writeAttribute(s_v2_versionAttributeName, "2"); writer.writeTextElement(s_nameTagName, m_name); writer.writeTextElement(s_uniqueIdentifierTagName, m_uniqueIdentifier); writer.writeTextElement(s_v2_centeringCorrectionName, AString::fromBool(m_centeringCorrectionEnabled)); encodeRowColumnElement(writer, s_v2_columnsTagName, m_columns); encodeRowColumnElement(writer, s_v2_rowsTagName, m_rows); writer.writeEndElement(); return xmlString; } /** * Encode a vector of elements into xml. * * @param writer * The XML stream writer. * @param tagName * Tag name for enclosing the elements. * @param elements * Vector of elements added to XML. */ void TileTabsConfiguration::encodeRowColumnElement(QXmlStreamWriter& writer, const AString tagName, const std::vector& elements) const { writer.writeStartElement(tagName); for (const auto e : elements) { writer.writeStartElement(s_v2_elementTagName); writer.writeAttribute(s_v2_contentTypeAttributeName, TileTabsGridRowColumnContentTypeEnum::toName(e.getContentType())); writer.writeAttribute(s_v2_stretchTypeAttributeName, TileTabsGridRowColumnStretchTypeEnum::toName(e.getStretchType())); writer.writeAttribute(s_v2_percentStretchAttributeName, AString::number(e.getPercentStretch(), 'f', 2)); writer.writeAttribute(s_v2_weightStretchAttributeName, AString::number(e.getWeightStretch(), 'f', 2)); writer.writeEndElement(); } writer.writeEndElement(); } /** * Decode the tile tabs configuration from XML with stream reader. * * @param xmlString * String containing XML. * @param errorMessageOut * Will contain error information. * @return * True if decoding is successful, else false. */ bool TileTabsConfiguration::decodeFromXMLWithStreamReader(const AString& xmlString, AString& errorMessageOut) { m_centeringCorrectionEnabled = false; QXmlStreamReader xml(xmlString); if (xml.readNextStartElement()) { const QStringRef tagName(xml.name()); if (tagName == s_v1_rootTagName) { decodeFromXMLWithStreamReaderVersionOne(xml); } else if (tagName == s_v2_rootTagName) { /* * Version 2 uses a different root tag than version 1. The reason is that * the older code for decoding from XML will throw an exception if it * encounters invalid elements or the version number is invalid. The problem * is that the exception is not caught and wb_view will terminate. */ QString versionNumberText("Unknown"); const QXmlStreamAttributes atts = xml.attributes(); if (atts.hasAttribute(s_v2_versionAttributeName)) { versionNumberText = atts.value(s_v2_versionAttributeName).toString(); } if (versionNumberText == "2") { decodeFromXMLWithStreamReaderVersionTwo(xml); } else { xml.raiseError("TileTabsConfiguration invalid version=" + versionNumberText); } } else { xml.raiseError("TileTabsConfiguration first element is " + xml.name().toString() + " but should be " + s_v1_rootTagName + " or " + s_v2_rootTagName); } } else { xml.raiseError("TileTabsConfiguration failed to find start elemnent."); } if (xml.hasError()) { errorMessageOut = ("Tile Tabs Configuration Read Error at line number=" + AString::number(xml.lineNumber()) + " column number=" + AString::number(xml.columnNumber()) + " description=" + xml.errorString()); return false; } const bool debugFlag(false); if (debugFlag) { AString xmlText = encodeInXMLWithStreamWriterVersionTwo(); std::cout << std::endl << "NEW: " << xmlText << std::endl << std::endl; AString em; TileTabsConfiguration temp; QXmlStreamReader tempReader(xmlText); tempReader.readNextStartElement(); temp.decodeFromXMLWithStreamReaderVersionTwo(tempReader); if (tempReader.hasError()) { std::cout << "Decode error: " << tempReader.errorString() << std::endl; } else { std::cout << "Decoded: " << temp.toString() << std::endl; } std::cout << std::endl; } return true; } /** * Decode Version One of the tile tabs configuration from XML with stream reader. * * @param xml * Stream XML parser. */ void TileTabsConfiguration::decodeFromXMLWithStreamReaderVersionOne(QXmlStreamReader& xml) { std::set invalidElements; AString name; AString uniqueID; std::vector rowStretchFactors; std::vector columnStretchFactors; int32_t numberOfRows(0); int32_t numberOfColumns(0); QString message; while ( ! xml.atEnd()) { xml.readNext(); if (xml.isStartElement()) { const QStringRef tagName(xml.name()); if (tagName == s_v1_versionTagName) { /* ignore */ } else if (tagName == s_nameTagName) { name = xml.readElementText(); } else if (tagName == s_uniqueIdentifierTagName) { uniqueID = xml.readElementText(); } else if (tagName == s_v1_rowStretchFactorsTagName) { QXmlStreamAttributes atts = xml.attributes(); if (atts.hasAttribute(s_v1_rowStretchFactorsSelectedCountAttributeName)) { numberOfRows = atts.value(s_v1_rowStretchFactorsSelectedCountAttributeName).toInt(); } AString::toNumbers(xml.readElementText(), rowStretchFactors); } else if (tagName == s_v1_columnStretchFactorsTagName) { QXmlStreamAttributes atts = xml.attributes(); if (atts.hasAttribute(s_v1_columnStretchFactorsSelectedCountAttributeName)) { numberOfColumns = atts.value(s_v1_columnStretchFactorsSelectedCountAttributeName).toInt(); } AString::toNumbers(xml.readElementText(), columnStretchFactors); } else { invalidElements.insert(tagName.toString()); xml.skipCurrentElement(); } } } static int32_t missingNameCounter = 1; if (name.isEmpty()) { name = ("Config_V1_" + AString::number(missingNameCounter)); missingNameCounter++; } if (uniqueID.isEmpty()) { uniqueID = SystemUtilities::createUniqueID(); } if (rowStretchFactors.empty()) { message.append(s_v1_rowStretchFactorsTagName + " not found or invalid. "); } if (columnStretchFactors.empty()) { message.append(s_v1_columnStretchFactorsTagName + " not found or invalid. "); } if (numberOfRows <= 0) { message.append(s_v1_rowStretchFactorsTagName + " attribute " + s_v1_rowStretchFactorsSelectedCountAttributeName + " is missing or invalid." ); } if (numberOfRows <= 0) { message.append(s_v1_columnStretchFactorsTagName + " attribute " + s_v1_columnStretchFactorsSelectedCountAttributeName + " is missing or invalid." ); } if ( ! invalidElements.empty()) { /* * If invalid elements were encountered, don't throw */ AString msg("Invalid element(s) ignored: "); for (const auto s : invalidElements) { msg.append(s + " "); } CaretLogWarning(msg); } if (message.isEmpty()) { m_name = name; m_uniqueIdentifier = uniqueID; m_rows.clear(); m_columns.clear(); for (int32_t i = 0; i < numberOfRows; i++) { TileTabsGridRowColumnElement element; CaretAssertVectorIndex(rowStretchFactors, i); element.setWeightStretch(rowStretchFactors[i]); element.setContentType(TileTabsGridRowColumnContentTypeEnum::TAB); element.setStretchType(TileTabsGridRowColumnStretchTypeEnum::WEIGHT); m_rows.push_back(element); } CaretAssert(numberOfRows == static_cast(m_rows.size())); for (int32_t i = 0; i < numberOfColumns; i++) { TileTabsGridRowColumnElement element; CaretAssertVectorIndex(columnStretchFactors, i); element.setWeightStretch(columnStretchFactors[i]); element.setContentType(TileTabsGridRowColumnContentTypeEnum::TAB); element.setStretchType(TileTabsGridRowColumnStretchTypeEnum::WEIGHT); m_columns.push_back(element); } CaretAssert(numberOfColumns == static_cast(m_columns.size())); } else { xml.raiseError(message); } } /** * Decode Version Two of the tile tabs configuration from XML with stream reader. * * @param xml * Stream XML parser. */ void TileTabsConfiguration::decodeFromXMLWithStreamReaderVersionTwo(QXmlStreamReader& xml) { m_rows.clear(); m_columns.clear(); m_uniqueIdentifier.clear(); std::set invalidElements; AString name; AString uniqueID; QString message; enum class ReadMode { OTHER, COLUMNS, ROWS }; ReadMode readMode = ReadMode::OTHER; AString centeringCorrectionTextString; while ( ! xml.atEnd()) { xml.readNext(); if (xml.isStartElement()) { const QStringRef tagName(xml.name()); if (tagName == s_nameTagName) { name = xml.readElementText(); } else if (tagName == s_uniqueIdentifierTagName) { uniqueID = xml.readElementText(); } else if (tagName == s_v2_columnsTagName) { readMode = ReadMode::COLUMNS; } else if (tagName == s_v2_rowsTagName) { readMode = ReadMode::ROWS; } else if (tagName == s_v2_centeringCorrectionName) { centeringCorrectionTextString = xml.readElementText(); } else if (tagName == s_v2_elementTagName) { switch (readMode) { case ReadMode::OTHER: CaretAssert(0); break; case ReadMode::COLUMNS: { AString errorMessage; TileTabsGridRowColumnElement e; if (decodeRowColumnElement(xml, e, errorMessage)) { m_columns.push_back(e); } else { message.append(errorMessage); } } break; case ReadMode::ROWS: { AString errorMessage; TileTabsGridRowColumnElement e; if (decodeRowColumnElement(xml, e, errorMessage)) { m_rows.push_back(e); } else { message.append(errorMessage); } } break; } } else { invalidElements.insert(tagName.toString()); xml.skipCurrentElement(); } } else if (xml.isEndElement()) { const QStringRef tagName(xml.name()); if (tagName == s_v2_columnsTagName) { readMode = ReadMode::OTHER; } else if (tagName == s_v2_rowsTagName) { readMode = ReadMode::OTHER; } } } static int32_t missingNameCounter = 1; if (name.isEmpty()) { name = ("Config_" + AString::number(missingNameCounter)); missingNameCounter++; } if (uniqueID.isEmpty()) { uniqueID = SystemUtilities::createUniqueID(); } if ( ! invalidElements.empty()) { /* * If invalid elements were encountered, don't throw */ AString msg("Invalid element(s) ignored: "); for (const auto s : invalidElements) { msg.append(s + " "); } CaretLogWarning(msg); } if (message.isEmpty()) { m_name = name; m_uniqueIdentifier = uniqueID; /* * Only set centering correction if it is found. This allows usage * of the default value in the event this is not found in the XML. */ if ( ! centeringCorrectionTextString.isEmpty()) { m_centeringCorrectionEnabled = centeringCorrectionTextString.toBool(); } } else { xml.raiseError(message); } } /** * Decode elements in a row or column. * * @param reader * The XML stream reader. * @param element * row/column element that is read * @param errorMessageOut * Contains error information. * @return * True if read successfully, else false. */ bool TileTabsConfiguration::decodeRowColumnElement(QXmlStreamReader& reader, TileTabsGridRowColumnElement& element, AString& errorMessageOut) { const QXmlStreamAttributes atts = reader.attributes(); errorMessageOut.clear(); if (atts.hasAttribute(s_v2_contentTypeAttributeName)) { bool validFlag(false); const AString s = atts.value(s_v2_contentTypeAttributeName).toString(); element.setContentType(TileTabsGridRowColumnContentTypeEnum::fromName(s, &validFlag)); if ( ! validFlag) { errorMessageOut.append("Content type \"" + s + "\" is not valid. "); } } else { errorMessageOut.append("Content type is missing. "); } if (atts.hasAttribute(s_v2_stretchTypeAttributeName)) { bool validFlag(false); const AString s = atts.value(s_v2_stretchTypeAttributeName).toString(); element.setStretchType(TileTabsGridRowColumnStretchTypeEnum::fromName(s, &validFlag)); if ( ! validFlag) { errorMessageOut.append("Stretch type \"" + s + "\" is not valid. "); } } else { errorMessageOut.append("Stretch type is missing. "); } if (atts.hasAttribute(s_v2_percentStretchAttributeName)) { const float f = atts.value(s_v2_percentStretchAttributeName).toFloat(); if ((f >= 0.0) && (f < 100.0)) { element.setPercentStretch(f); } else { errorMessageOut.append("Stretch percentage=" + AString::number(f) + " is invalid."); } } else { errorMessageOut.append("Stretch percentage is missing. "); } if (atts.hasAttribute(s_v2_weightStretchAttributeName)) { const float f = atts.value(s_v2_weightStretchAttributeName).toFloat(); if ((f >= 0.0) && (f < 100.0)) { element.setWeightStretch(f); } else { errorMessageOut.append("Stretch weight=" + AString::number(f) + " is invalid."); } } else { errorMessageOut.append("Stretch weight is missing. "); } if (errorMessageOut.isEmpty()) { return true; } return false; } /** * Decode the tile tabs configuration from XML using DOM * * @param xmlString * String containing XML. * @param errorMessageOut * Contains error information if decoding fails. * @return * True if configuration was successfully read from the XML, else false. */ bool TileTabsConfiguration::decodeFromXML(const AString& xmlString, AString& errorMessageOut) { errorMessageOut.clear(); return decodeFromXMLWithStreamReader(xmlString, errorMessageOut); } /** * @return String version of an instance. */ AString TileTabsConfiguration::toString() const { AString s("Name: %1, Unique ID: %2\n"); s = s.arg(m_name).arg(m_uniqueIdentifier); int32_t indx(0); for (const auto item : m_columns) { s.append(" Column " + AString::number(indx) + ": " + item.toString() + "\n"); indx++; } indx = 0; for (const auto item : m_rows) { s.append(" Row " + AString::number(indx) + ": " + item.toString() + "\n"); indx++; } return s; } /** * Compare two tile tabs configurations by name. * * @param ttc1 * First tile tab configuration. * @param ttc2 * Second tile tab configuration. * @return * True if ttc1 is "less than" when compared by name, else false. */ bool TileTabsConfiguration::lessThanComparisonByName(const TileTabsConfiguration* ttc1, const TileTabsConfiguration* ttc2) { if (ttc1->getName() < ttc2->getName()) { return true; } return false; } connectome-workbench-1.4.2/src/Common/TileTabsConfiguration.h000066400000000000000000000206031360521144700242630ustar00rootroot00000000000000#ifndef __TILE_TABS_CONFIGURATION_H__ #define __TILE_TABS_CONFIGURATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretException.h" #include "CaretObject.h" #include "TileTabsGridModeEnum.h" #include "TileTabsGridRowColumnElement.h" class QXmlStreamReader; class QXmlStreamWriter; namespace caret { class TileTabsConfiguration : public CaretObject { public: TileTabsConfiguration(); virtual ~TileTabsConfiguration(); TileTabsConfiguration(const TileTabsConfiguration& obj); TileTabsConfiguration& operator=(const TileTabsConfiguration& obj); void copy(const TileTabsConfiguration& rhs); TileTabsConfiguration* newCopyWithNewUniqueIdentifier() const; bool getRowHeightsAndColumnWidthsForWindowSize(const int32_t windowWidth, const int32_t windowHeight, const int32_t numberOfModelsToDraw, const TileTabsGridModeEnum::Enum configurationMode, std::vector& rowHeightsOut, std::vector& columnWidthsOut); AString getName() const; void setName(const AString& name); AString getUniqueIdentifier() const; int32_t getNumberOfRows() const; void setNumberOfRows(const int32_t numberOfRows); int32_t getNumberOfColumns() const; void setNumberOfColumns(const int32_t numberOfColumns); TileTabsGridRowColumnElement* getColumn(const int32_t columnIndex); const TileTabsGridRowColumnElement* getColumn(const int32_t columnIndex) const; TileTabsGridRowColumnElement* getRow(const int32_t rowIndex); const TileTabsGridRowColumnElement* getRow(const int32_t rowIndex) const; AString encodeInXML() const; AString encodeVersionInXML(const int32_t versionNumber) const; bool decodeFromXML(const AString& xmlString, AString& errorMessageOut); void updateAutomaticConfigurationRowsAndColumns(const int32_t numberOfTabs); bool isCenteringCorrectionEnabled() const; void setCenteringCorrectionEnabled(const bool status); AString toString() const override; static bool lessThanComparisonByName(const TileTabsConfiguration* ttc1, const TileTabsConfiguration* ttc2); static void getRowsAndColumnsForNumberOfTabs(const int32_t numberOfTabs, int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut); // ADD_NEW_METHODS_HERE private: void copyHelperTileTabsConfiguration(const TileTabsConfiguration& obj); bool decodeFromXMLWithStreamReader(const AString& xmlString, AString& errorMessageOut); void decodeFromXMLWithStreamReaderVersionOne(QXmlStreamReader& xml); void decodeFromXMLWithStreamReaderVersionTwo(QXmlStreamReader& xml); AString encodeInXMLWithStreamWriterVersionOne() const; AString encodeInXMLWithStreamWriterVersionTwo() const; void encodeRowColumnElement(QXmlStreamWriter& writer, const AString tagName, const std::vector& elements) const; bool decodeRowColumnElement(QXmlStreamReader& reader, TileTabsGridRowColumnElement& element, AString& errorMessageOut); void initialize(); // ADD_NEW_MEMBERS_HERE AString m_name; /** Unique identifier does not get copied */ AString m_uniqueIdentifier; std::vector m_columns; std::vector m_rows; bool m_centeringCorrectionEnabled = false; static const AString s_nameTagName; static const AString s_uniqueIdentifierTagName; static const AString s_v1_rootTagName; static const AString s_v1_versionTagName; static const AString s_v1_versionNumberAttributeName; static const AString s_v1_columnStretchFactorsTagName; static const AString s_v1_columnStretchFactorsSelectedCountAttributeName; static const AString s_v1_columnStretchFactorsTotalCountAttributeName; static const AString s_v1_rowStretchFactorsTagName; static const AString s_v1_rowStretchFactorsSelectedCountAttributeName; static const AString s_v1_rowStretchFactorsTotalCountAttributeName; static const AString s_v2_rootTagName; static const AString s_v2_versionAttributeName; static const AString s_v2_columnsTagName; static const AString s_v2_contentTypeAttributeName; static const AString s_v2_elementTagName; static const AString s_v2_percentStretchAttributeName; static const AString s_v2_rowsTagName; static const AString s_v2_stretchTypeAttributeName; static const AString s_v2_weightStretchAttributeName; static const AString s_v2_centeringCorrectionName; }; #ifdef __TILE_TABS_CONFIGURATION_DECLARE__ const AString TileTabsConfiguration::s_nameTagName = "Name"; const AString TileTabsConfiguration::s_uniqueIdentifierTagName = "UniqueIdentifier"; const AString TileTabsConfiguration::s_v1_rootTagName = "TileTabsConfiguration"; const AString TileTabsConfiguration::s_v1_versionTagName = "Version"; const AString TileTabsConfiguration::s_v1_versionNumberAttributeName = "Number"; const AString TileTabsConfiguration::s_v1_columnStretchFactorsTagName = "ColumnStretchFactors"; const AString TileTabsConfiguration::s_v1_columnStretchFactorsSelectedCountAttributeName = "SelectedRowCount"; const AString TileTabsConfiguration::s_v1_columnStretchFactorsTotalCountAttributeName = "TotalRowCount"; const AString TileTabsConfiguration::s_v1_rowStretchFactorsTagName = "RowStretchFactors"; const AString TileTabsConfiguration::s_v1_rowStretchFactorsSelectedCountAttributeName = "SelectedColumnCount"; const AString TileTabsConfiguration::s_v1_rowStretchFactorsTotalCountAttributeName = "TotalColumnCount"; const AString TileTabsConfiguration::s_v2_rootTagName = "TileTabsConfigurationTwo"; const AString TileTabsConfiguration::s_v2_versionAttributeName = "Version"; const AString TileTabsConfiguration::s_v2_columnsTagName = "Columns"; const AString TileTabsConfiguration::s_v2_contentTypeAttributeName = "ContentType"; const AString TileTabsConfiguration::s_v2_elementTagName = "Element"; const AString TileTabsConfiguration::s_v2_percentStretchAttributeName = "PercentStretch"; const AString TileTabsConfiguration::s_v2_rowsTagName = "Rows"; const AString TileTabsConfiguration::s_v2_stretchTypeAttributeName = "StretchType"; const AString TileTabsConfiguration::s_v2_weightStretchAttributeName = "WeightStretch"; const AString TileTabsConfiguration::s_v2_centeringCorrectionName = "CenteringCorrection"; #endif // __TILE_TABS_CONFIGURATION_DECLARE__ } // namespace #endif //__TILE_TABS_CONFIGURATION_H__ connectome-workbench-1.4.2/src/Common/TileTabsConfigurationLayoutTypeEnum.cxx000066400000000000000000000264241360521144700275320ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_DECLARE__ #include "TileTabsConfigurationLayoutTypeEnum.h" #undef __TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::TileTabsConfigurationLayoutTypeEnum * \brief Types of tile tabs layouts * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_tileTabsConfigurationLayoutTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void tileTabsConfigurationLayoutTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "TileTabsConfigurationLayoutTypeEnum.h" * * Instatiate: * m_tileTabsConfigurationLayoutTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_tileTabsConfigurationLayoutTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_tileTabsConfigurationLayoutTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(tileTabsConfigurationLayoutTypeEnumComboBoxItemActivated())); * * Update the selection: * m_tileTabsConfigurationLayoutTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const TileTabsConfigurationLayoutTypeEnum::Enum VARIABLE = m_tileTabsConfigurationLayoutTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ TileTabsConfigurationLayoutTypeEnum::TileTabsConfigurationLayoutTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ TileTabsConfigurationLayoutTypeEnum::~TileTabsConfigurationLayoutTypeEnum() { } /** * Initialize the enumerated metadata. */ void TileTabsConfigurationLayoutTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(TileTabsConfigurationLayoutTypeEnum(GRID, "GRID", "Grid")); enumData.push_back(TileTabsConfigurationLayoutTypeEnum(MANUAL, "MANUAL", "Manual")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const TileTabsConfigurationLayoutTypeEnum* TileTabsConfigurationLayoutTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const TileTabsConfigurationLayoutTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString TileTabsConfigurationLayoutTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const TileTabsConfigurationLayoutTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ TileTabsConfigurationLayoutTypeEnum::Enum TileTabsConfigurationLayoutTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = TileTabsConfigurationLayoutTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const TileTabsConfigurationLayoutTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type TileTabsConfigurationLayoutTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString TileTabsConfigurationLayoutTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const TileTabsConfigurationLayoutTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ TileTabsConfigurationLayoutTypeEnum::Enum TileTabsConfigurationLayoutTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = TileTabsConfigurationLayoutTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const TileTabsConfigurationLayoutTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type TileTabsConfigurationLayoutTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t TileTabsConfigurationLayoutTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const TileTabsConfigurationLayoutTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ TileTabsConfigurationLayoutTypeEnum::Enum TileTabsConfigurationLayoutTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = TileTabsConfigurationLayoutTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const TileTabsConfigurationLayoutTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type TileTabsConfigurationLayoutTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void TileTabsConfigurationLayoutTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void TileTabsConfigurationLayoutTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(TileTabsConfigurationLayoutTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void TileTabsConfigurationLayoutTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(TileTabsConfigurationLayoutTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/TileTabsConfigurationLayoutTypeEnum.h000066400000000000000000000064001360521144700271470ustar00rootroot00000000000000#ifndef __TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_H__ #define __TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class TileTabsConfigurationLayoutTypeEnum { public: /** * Enumerated values. */ enum Enum { /** */ GRID, /** */ MANUAL }; ~TileTabsConfigurationLayoutTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: TileTabsConfigurationLayoutTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const TileTabsConfigurationLayoutTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_DECLARE__ std::vector TileTabsConfigurationLayoutTypeEnum::enumData; bool TileTabsConfigurationLayoutTypeEnum::initializedFlag = false; int32_t TileTabsConfigurationLayoutTypeEnum::integerCodeCounter = 0; #endif // __TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_DECLARE__ } // namespace #endif //__TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Common/TileTabsGridLayoutConfiguration.cxx000066400000000000000000001054011360521144700266420ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __TILE_TABS_GRID_LAYOUT_CONFIGURATION_DECLARE__ #include "TileTabsGridLayoutConfiguration.h" #undef __TILE_TABS_GRID_LAYOUT_CONFIGURATION_DECLARE__ #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "SystemUtilities.h" using namespace caret; /** * \class caret::TileTabsGridLayoutConfiguration * \brief Defines a tile tabs configuration * \ingroup Common */ /** * Constructor that creates a 2 by 2 configuration. */ TileTabsGridLayoutConfiguration::TileTabsGridLayoutConfiguration() : TileTabsBaseConfiguration(TileTabsConfigurationLayoutTypeEnum::GRID) { initialize(); } /** * Destructor. */ TileTabsGridLayoutConfiguration::~TileTabsGridLayoutConfiguration() { } /** * Copy constructor. * * NOTE: Unique identifier remains the same ! See also: newCopyWithNewUniqueIdentifier() * * @param obj * Object that is copied. */ TileTabsGridLayoutConfiguration::TileTabsGridLayoutConfiguration(const TileTabsGridLayoutConfiguration& obj) : TileTabsBaseConfiguration(obj) { initialize(); this->copyHelperTileTabsGridLayoutConfiguration(obj); } /** * Assignment operator. * * NOTE: Unique identifier remains the same ! See also: newCopyWithNewUniqueIdentifier() * * @param obj * Data copied from obj to this. * @return * Reference to this object. */ TileTabsGridLayoutConfiguration& TileTabsGridLayoutConfiguration::operator=(const TileTabsGridLayoutConfiguration& obj) { if (this != &obj) { TileTabsBaseConfiguration::operator=(obj); this->copyHelperTileTabsGridLayoutConfiguration(obj); } return *this; } /** * Copy this instance and give it a new unique identifier. * Note that copy constructor does not create a new unique identifier. * * @return The new Copy. */ TileTabsGridLayoutConfiguration* TileTabsGridLayoutConfiguration::newCopyWithNewUniqueIdentifier() const { TileTabsGridLayoutConfiguration* newCopy = new TileTabsGridLayoutConfiguration(*this); CaretAssert(newCopy); return newCopy; } /** * Initialize an instance of a tile tabs configuration. */ void TileTabsGridLayoutConfiguration::initialize() { setNumberOfRows(2); setNumberOfColumns(2); m_centeringCorrectionEnabled = false; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void TileTabsGridLayoutConfiguration::copyHelperTileTabsGridLayoutConfiguration(const TileTabsGridLayoutConfiguration& obj) { if (this == &obj) { return; } copyHelperTileTabsBaseConfiguration(obj); m_columns = obj.m_columns; m_rows = obj.m_rows; m_centeringCorrectionEnabled = obj.m_centeringCorrectionEnabled; } /** * Copies the tile tabs configuration rows, columns, and * stretch factors. Name is NOT copied. */ void TileTabsGridLayoutConfiguration::copy(const TileTabsGridLayoutConfiguration& rhs) { AString savedName = getName(); copyHelperTileTabsGridLayoutConfiguration(rhs); setName(savedName); } /** * Get infoformation for the given elemnent in the columns. * * @param Information for element. */ TileTabsGridRowColumnElement* TileTabsGridLayoutConfiguration::getColumn(const int32_t columnIndex) { CaretAssertVectorIndex(m_columns, columnIndex); return &m_columns[columnIndex]; } /** * Get infoformation for the given elemnent in the columns. * * @param Information for element. */ const TileTabsGridRowColumnElement* TileTabsGridLayoutConfiguration::getColumn(const int32_t columnIndex) const { CaretAssertVectorIndex(m_columns, columnIndex); return &m_columns[columnIndex]; } /** * Get infoformation for the given elemnent in the rows. * * @param Information for element. */ TileTabsGridRowColumnElement* TileTabsGridLayoutConfiguration::getRow(const int32_t rowIndex) { CaretAssertVectorIndex(m_rows, rowIndex); return &m_rows[rowIndex]; } /** * Get infoformation for the given elemnent in the rows. * * @param Information for element. */ const TileTabsGridRowColumnElement* TileTabsGridLayoutConfiguration::getRow(const int32_t rowIndex) const { CaretAssertVectorIndex(m_rows, rowIndex); return &m_rows[rowIndex]; } /** * Get the row heights and column widths for this tile tabs configuration using the * given window width and height. * * @param windowWidth * Width of window. * @param windowHeight * Height of window. * @param numberOfModelsToDraw * Number of models to draw. * @param configurationMode * The tile tabs configuration mode * @param rowHeightsOut * Output containing height of each row. * @param columnWidthsOut * Output containing width of each column. * @return * True if the ouput is valid, else false. */ bool TileTabsGridLayoutConfiguration::getRowHeightsAndColumnWidthsForWindowSize(const int32_t windowWidth, const int32_t windowHeight, const int32_t numberOfModelsToDraw, const TileTabsGridModeEnum::Enum configurationMode, std::vector& rowHeightsOut, std::vector& columnWidthsOut) { /* * NOTE: When computing widths and heights, do not round. * Rounding may cause the bottom most row or column to extend * outside the graphics region. Shrinking the last row or * column is not desired since it might cause the last model * to be drawn slightly smaller than the others. */ int32_t numRows = 0; int32_t numCols = 0; rowHeightsOut.clear(); columnWidthsOut.clear(); switch (configurationMode) { case TileTabsGridModeEnum::AUTOMATIC: { /* * Update number of rows/columns in the default configuration * so that if a scene is saved, the correct number of rows * and columns are saved to the scene. */ updateAutomaticConfigurationRowsAndColumns(numberOfModelsToDraw); numRows = getNumberOfRows(); numCols = getNumberOfColumns(); for (int32_t i = 0; i < numRows; i++) { rowHeightsOut.push_back(windowHeight / numRows); } for (int32_t i = 0; i < numCols; i++) { columnWidthsOut.push_back(windowWidth / numCols); } } break; case TileTabsGridModeEnum::CUSTOM: { /* * Rows/columns from user configuration */ numRows = getNumberOfRows(); numCols = getNumberOfColumns(); /* * Determine height of each row */ float rowPercentTotal = 0.0; float rowStretchTotal = 0.0; for (int32_t i = 0; i < numRows; i++) { const TileTabsGridRowColumnElement* e = getRow(i); switch (e->getStretchType()) { case TileTabsGridRowColumnStretchTypeEnum::PERCENT: rowPercentTotal += (e->getPercentStretch() / 100.0); break; case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: rowStretchTotal += e->getWeightStretch(); break; } } float windowWeightHeight = windowHeight; if (rowPercentTotal > 0.0) { if (rowPercentTotal >= 1.0) { windowWeightHeight = 0.0; } else { windowWeightHeight = (1.0 - rowPercentTotal) * windowHeight; } } for (int32_t i = 0; i < numRows; i++) { int32_t h = 0; const TileTabsGridRowColumnElement* e = getRow(i); switch (e->getStretchType()) { case TileTabsGridRowColumnStretchTypeEnum::PERCENT: h = (e->getPercentStretch() / 100.0) * windowHeight; break; case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: if (rowStretchTotal > 0.0) { h = static_cast((e->getWeightStretch() / rowStretchTotal) * windowWeightHeight); } break; } rowHeightsOut.push_back(h); } /* * Determine width of each column */ float columnPercentTotal = 0.0; float columnStretchTotal = 0.0; for (int32_t i = 0; i < numCols; i++) { const TileTabsGridRowColumnElement* e = getColumn(i); switch (e->getStretchType()) { case TileTabsGridRowColumnStretchTypeEnum::PERCENT: columnPercentTotal += (e->getPercentStretch() / 100.0); break; case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: columnStretchTotal += e->getWeightStretch(); break; } } float windowWeightWidth = windowWidth; if (columnPercentTotal > 0.0) { if (columnPercentTotal >= 1.0) { windowWeightWidth = 0.0; } else { windowWeightWidth = (1.0 - columnPercentTotal) * windowWidth; } } for (int32_t i = 0; i < numCols; i++) { int32_t w = 0; const TileTabsGridRowColumnElement* e = getColumn(i); switch (e->getStretchType()) { case TileTabsGridRowColumnStretchTypeEnum::PERCENT: w = (e->getPercentStretch() / 100.0) * windowWidth; break; case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: if (columnStretchTotal > 0.0) { w = static_cast((e->getWeightStretch() / columnStretchTotal) * windowWeightWidth); } break; } columnWidthsOut.push_back(w); } } break; } if ((numRows == static_cast(rowHeightsOut.size())) && (numCols == static_cast(columnWidthsOut.size()))) { // /* // * Verify all rows fit within the window // */ // int32_t rowHeightsSum = 0; // for (int32_t i = 0; i < numRows; i++) { // rowHeightsSum += rowHeightsOut[i]; // } // if (rowHeightsSum > windowHeight) { // CaretLogSevere("PROGRAM ERROR: Tile Tabs total row heights exceed window height"); //// rowHeightsOut[numRows - 1] -= (rowHeightsSum - windowHeight); // } // // /* // * Adjust width of last column so that it does not extend beyond viewport // */ // int32_t columnWidthsSum = 0; // for (int32_t i = 0; i < numCols; i++) { // columnWidthsSum += columnWidthsOut[i]; // } // if (columnWidthsSum > windowWidth) { // CaretLogSevere("PROGRAM ERROR: Tile Tabs total row heights exceed window height"); //// columnWidthsOut[numCols - 1] = columnWidthsSum - windowWidth; // } // // CaretLogFiner("Tile Tabs Row Heights: " // + AString::fromNumbers(rowHeightsOut, ", ")); // CaretLogFiner("Tile Tabs Column Widths: " // + AString::fromNumbers(columnWidthsOut, ", ")); return true; } const QString msg("Row and heights failed rows=" + AString::number(numRows) + " rowHeights=" + AString::number(rowHeightsOut.size()) + " cols=" + AString::number(numCols) + " rowHeights=" + AString::number(columnWidthsOut.size())); CaretAssertMessage(0, msg); CaretLogSevere(msg); return false; } /** * @return Number of rows. */ int32_t TileTabsGridLayoutConfiguration::getNumberOfRows() const { return m_rows.size(); } /** * Set number of rows. * * @param numberOfRows * New number of rows. */ void TileTabsGridLayoutConfiguration::setNumberOfRows(const int32_t numberOfRows) { m_rows.resize(numberOfRows); } /** * @return Number of columns. */ int32_t TileTabsGridLayoutConfiguration::getNumberOfColumns() const { return m_columns.size(); } /** * Set number of rows. * * @param numberOfColumns * New number of rows. */ void TileTabsGridLayoutConfiguration::setNumberOfColumns(const int32_t numberOfColumns) { m_columns.resize(numberOfColumns); } /** * Get the number of rows and columns for an automatic layout with the * given number of tabs. * @param numberOfTabs * Number of tabs. * @param numberOfRowsOut * Output with number of rows. * @param numberOfColumnsOut * Output with number of columns. */ void TileTabsGridLayoutConfiguration::getRowsAndColumnsForNumberOfTabs(const int32_t numberOfTabs, int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) { CaretAssert(numberOfTabs >= 0); numberOfRowsOut = (int)std::sqrt((double)numberOfTabs); numberOfColumnsOut = numberOfRowsOut; int32_t row2 = numberOfRowsOut * numberOfRowsOut; if (row2 < numberOfTabs) { numberOfColumnsOut++; } if ((numberOfRowsOut * numberOfColumnsOut) < numberOfTabs) { numberOfRowsOut++; } } /** * @return True if the centering correction is enabled. */ bool TileTabsGridLayoutConfiguration::isCenteringCorrectionEnabled() const { return m_centeringCorrectionEnabled; } /** * Set the enabled status of the centering correction * * @param status * New status for enabling the centering correction */ void TileTabsGridLayoutConfiguration::setCenteringCorrectionEnabled(const bool status) { m_centeringCorrectionEnabled = status; } /** * Updates the number of rows and columns for the automatic configuration * based upon the number of tabs. * * Since screen width typically exceeds height, ensure the number of * columns is always greater than the number of rows. */ void TileTabsGridLayoutConfiguration::updateAutomaticConfigurationRowsAndColumns(const int32_t numberOfTabs) { int32_t numRows(0), numCols(0); getRowsAndColumnsForNumberOfTabs(numberOfTabs, numRows, numCols); setNumberOfRows(numRows); setNumberOfColumns(numCols); } /** * Encode the configuration in XML. * * @param xmlTextOut * Contains XML representation of configuration. */ void TileTabsGridLayoutConfiguration::encodeInXML(AString& xmlTextOut) const { xmlTextOut = encodeVersionInXML(2); } /** * @return Encoded tile tabs configuration in XML * using the give XML version of TileTabsGridLayoutConfiguration. */ AString TileTabsGridLayoutConfiguration::encodeVersionInXML(const int32_t versionNumber) const { AString s; switch (versionNumber) { case 1: s = encodeInXMLWithStreamWriterVersionOne(); break; case 2: s = encodeInXMLWithStreamWriterVersionTwo(); break; default: CaretAssertMessage(0, "Requested invalid version=" + AString::number(versionNumber)); break; } return s; } /** * @return Encoded tile tabs configuration in XML with Stream Writer */ AString TileTabsGridLayoutConfiguration::encodeInXMLWithStreamWriterVersionOne() const { AString xmlString; QXmlStreamWriter writer(&xmlString); writer.setAutoFormatting(true); writer.writeStartElement(s_v1_rootTagName); writer.writeStartElement(s_v1_versionTagName); writer.writeAttribute(s_v1_versionNumberAttributeName, "1"); writer.writeEndElement(); writer.writeTextElement(s_nameTagName, getName()); writer.writeTextElement(s_uniqueIdentifierTagName, getUniqueIdentifier()); const int32_t numberOfRows = getNumberOfRows(); writer.writeStartElement(s_v1_rowStretchFactorsTagName); writer.writeAttribute(s_v1_rowStretchFactorsSelectedCountAttributeName, AString::number(numberOfRows)); writer.writeAttribute(s_v1_rowStretchFactorsTotalCountAttributeName, AString::number(numberOfRows)); std::vector rowStretchFactors; for (const auto e : m_rows) { rowStretchFactors.push_back(e.getWeightStretch()); } writer.writeCharacters(AString::fromNumbers(rowStretchFactors, " ")); writer.writeEndElement(); const int32_t numberOfColumns = getNumberOfColumns(); writer.writeStartElement(s_v1_columnStretchFactorsTagName); writer.writeAttribute(s_v1_columnStretchFactorsSelectedCountAttributeName, AString::number(numberOfColumns)); writer.writeAttribute(s_v1_columnStretchFactorsTotalCountAttributeName, AString::number(numberOfColumns)); std::vector columnStretchFactors; for (const auto e : m_columns) { columnStretchFactors.push_back(e.getWeightStretch()); } writer.writeCharacters(AString::fromNumbers(columnStretchFactors, " ")); writer.writeEndElement(); writer.writeEndElement(); return xmlString; } /** * @return Encoded tile tabs configuration in XML with Stream Writer */ AString TileTabsGridLayoutConfiguration::encodeInXMLWithStreamWriterVersionTwo() const { AString xmlString; QXmlStreamWriter writer(&xmlString); writer.setAutoFormatting(true); writer.writeStartElement(s_v2_rootTagName); writer.writeAttribute(s_v2_versionAttributeName, "2"); writer.writeTextElement(s_nameTagName, getName()); writer.writeTextElement(s_uniqueIdentifierTagName, getUniqueIdentifier()); writer.writeTextElement(s_v2_centeringCorrectionName, AString::fromBool(m_centeringCorrectionEnabled)); encodeRowColumnElement(writer, s_v2_columnsTagName, m_columns); encodeRowColumnElement(writer, s_v2_rowsTagName, m_rows); writer.writeEndElement(); return xmlString; } /** * Encode a vector of elements into xml. * * @param writer * The XML stream writer. * @param tagName * Tag name for enclosing the elements. * @param elements * Vector of elements added to XML. */ void TileTabsGridLayoutConfiguration::encodeRowColumnElement(QXmlStreamWriter& writer, const AString tagName, const std::vector& elements) const { writer.writeStartElement(tagName); for (const auto e : elements) { writer.writeStartElement(s_v2_elementTagName); writer.writeAttribute(s_v2_contentTypeAttributeName, TileTabsGridRowColumnContentTypeEnum::toName(e.getContentType())); writer.writeAttribute(s_v2_stretchTypeAttributeName, TileTabsGridRowColumnStretchTypeEnum::toName(e.getStretchType())); writer.writeAttribute(s_v2_percentStretchAttributeName, AString::number(e.getPercentStretch(), 'f', 2)); writer.writeAttribute(s_v2_weightStretchAttributeName, AString::number(e.getWeightStretch(), 'f', 2)); writer.writeEndElement(); } writer.writeEndElement(); } /** * Decode the configuration using the given XML stream reader and root element * If there is an error, xml.raiseError() should be used to specify the error * and caller of this method can test for the error using xml.isError(). * * @param xml * The XML stream reader. * @param rootElement * The root element. */ void TileTabsGridLayoutConfiguration::decodeFromXML(QXmlStreamReader& xml, const QString& rootElementText) { CaretAssert( ! rootElementText.isEmpty()); m_centeringCorrectionEnabled = false; if (rootElementText == s_v1_rootTagName) { decodeFromXMLWithStreamReaderVersionOne(xml); } else if (rootElementText == s_v2_rootTagName) { /* * Version 2 uses a different root tag than version 1. The reason is that * the older code for decoding from XML will throw an exception if it * encounters invalid elements or the version number is invalid. The problem * is that the exception is not caught and wb_view will terminate. */ QString versionNumberText("Unknown"); const QXmlStreamAttributes atts = xml.attributes(); if (atts.hasAttribute(s_v2_versionAttributeName)) { versionNumberText = atts.value(s_v2_versionAttributeName).toString(); } if (versionNumberText == "2") { decodeFromXMLWithStreamReaderVersionTwo(xml); } else { xml.raiseError("TileTabsGridLayoutConfiguration invalid version=" + versionNumberText); } } else { xml.raiseError("TileTabsGridLayoutConfiguration first element is " + xml.name().toString() + " but should be " + s_v1_rootTagName + " or " + s_v2_rootTagName); } // const bool debugFlag(false); // if (debugFlag) { // AString xmlText = encodeInXMLWithStreamWriterVersionTwo(); // std::cout << std::endl << "NEW: " << xmlText << std::endl << std::endl; // AString em; // TileTabsGridLayoutConfiguration temp; // QXmlStreamReader tempReader(xmlText); // tempReader.readNextStartElement(); // temp.decodeFromXMLWithStreamReaderVersionTwo(tempReader); // if (tempReader.hasError()) { // std::cout << "Decode error: " << tempReader.errorString() << std::endl; // } // else { // std::cout << "Decoded: " << temp.toString() << std::endl; // } // // std::cout << std::endl; // } // return true; } /** * Decode Version One of the tile tabs configuration from XML with stream reader. * * @param xml * Stream XML parser. */ void TileTabsGridLayoutConfiguration::decodeFromXMLWithStreamReaderVersionOne(QXmlStreamReader& xml) { std::set invalidElements; AString name; AString uniqueID; std::vector rowStretchFactors; std::vector columnStretchFactors; int32_t numberOfRows(0); int32_t numberOfColumns(0); QString message; while ( ! xml.atEnd()) { xml.readNext(); if (xml.isStartElement()) { const QStringRef tagName(xml.name()); if (tagName == s_v1_versionTagName) { /* ignore */ } else if (tagName == s_nameTagName) { name = xml.readElementText(); } else if (tagName == s_uniqueIdentifierTagName) { uniqueID = xml.readElementText(); } else if (tagName == s_v1_rowStretchFactorsTagName) { QXmlStreamAttributes atts = xml.attributes(); if (atts.hasAttribute(s_v1_rowStretchFactorsSelectedCountAttributeName)) { numberOfRows = atts.value(s_v1_rowStretchFactorsSelectedCountAttributeName).toInt(); } AString::toNumbers(xml.readElementText(), rowStretchFactors); } else if (tagName == s_v1_columnStretchFactorsTagName) { QXmlStreamAttributes atts = xml.attributes(); if (atts.hasAttribute(s_v1_columnStretchFactorsSelectedCountAttributeName)) { numberOfColumns = atts.value(s_v1_columnStretchFactorsSelectedCountAttributeName).toInt(); } AString::toNumbers(xml.readElementText(), columnStretchFactors); } else { invalidElements.insert(tagName.toString()); xml.skipCurrentElement(); } } } static int32_t missingNameCounter = 1; if (name.isEmpty()) { name = ("Config_V1_" + AString::number(missingNameCounter)); missingNameCounter++; } if (uniqueID.isEmpty()) { uniqueID = SystemUtilities::createUniqueID(); } if (rowStretchFactors.empty()) { message.append(s_v1_rowStretchFactorsTagName + " not found or invalid. "); } if (columnStretchFactors.empty()) { message.append(s_v1_columnStretchFactorsTagName + " not found or invalid. "); } if (numberOfRows <= 0) { message.append(s_v1_rowStretchFactorsTagName + " attribute " + s_v1_rowStretchFactorsSelectedCountAttributeName + " is missing or invalid." ); } if (numberOfRows <= 0) { message.append(s_v1_columnStretchFactorsTagName + " attribute " + s_v1_columnStretchFactorsSelectedCountAttributeName + " is missing or invalid." ); } if ( ! invalidElements.empty()) { /* * If invalid elements were encountered, don't throw */ AString msg("Invalid element(s) ignored: "); for (const auto s : invalidElements) { msg.append(s + " "); } CaretLogWarning(msg); } if (message.isEmpty()) { setName(name); setUniqueIdentifierProtected(uniqueID); m_rows.clear(); m_columns.clear(); for (int32_t i = 0; i < numberOfRows; i++) { TileTabsGridRowColumnElement element; CaretAssertVectorIndex(rowStretchFactors, i); element.setWeightStretch(rowStretchFactors[i]); element.setContentType(TileTabsGridRowColumnContentTypeEnum::TAB); element.setStretchType(TileTabsGridRowColumnStretchTypeEnum::WEIGHT); m_rows.push_back(element); } CaretAssert(numberOfRows == static_cast(m_rows.size())); for (int32_t i = 0; i < numberOfColumns; i++) { TileTabsGridRowColumnElement element; CaretAssertVectorIndex(columnStretchFactors, i); element.setWeightStretch(columnStretchFactors[i]); element.setContentType(TileTabsGridRowColumnContentTypeEnum::TAB); element.setStretchType(TileTabsGridRowColumnStretchTypeEnum::WEIGHT); m_columns.push_back(element); } CaretAssert(numberOfColumns == static_cast(m_columns.size())); } else { xml.raiseError(message); } } /** * Decode Version Two of the tile tabs configuration from XML with stream reader. * * @param xml * Stream XML parser. */ void TileTabsGridLayoutConfiguration::decodeFromXMLWithStreamReaderVersionTwo(QXmlStreamReader& xml) { m_rows.clear(); m_columns.clear(); setName(""); setUniqueIdentifierProtected(""); std::set invalidElements; AString name; AString uniqueID; QString message; enum class ReadMode { OTHER, COLUMNS, ROWS }; ReadMode readMode = ReadMode::OTHER; AString centeringCorrectionTextString; while ( ! xml.atEnd()) { xml.readNext(); if (xml.isStartElement()) { const QStringRef tagName(xml.name()); if (tagName == s_nameTagName) { name = xml.readElementText(); } else if (tagName == s_uniqueIdentifierTagName) { uniqueID = xml.readElementText(); } else if (tagName == s_v2_columnsTagName) { readMode = ReadMode::COLUMNS; } else if (tagName == s_v2_rowsTagName) { readMode = ReadMode::ROWS; } else if (tagName == s_v2_centeringCorrectionName) { centeringCorrectionTextString = xml.readElementText(); } else if (tagName == s_v2_elementTagName) { switch (readMode) { case ReadMode::OTHER: CaretAssert(0); break; case ReadMode::COLUMNS: { AString errorMessage; TileTabsGridRowColumnElement e; if (decodeRowColumnElement(xml, e, errorMessage)) { m_columns.push_back(e); } else { message.append(errorMessage); } } break; case ReadMode::ROWS: { AString errorMessage; TileTabsGridRowColumnElement e; if (decodeRowColumnElement(xml, e, errorMessage)) { m_rows.push_back(e); } else { message.append(errorMessage); } } break; } } else { invalidElements.insert(tagName.toString()); xml.skipCurrentElement(); } } else if (xml.isEndElement()) { const QStringRef tagName(xml.name()); if (tagName == s_v2_columnsTagName) { readMode = ReadMode::OTHER; } else if (tagName == s_v2_rowsTagName) { readMode = ReadMode::OTHER; } } } static int32_t missingNameCounter = 1; if (name.isEmpty()) { name = ("Config_" + AString::number(missingNameCounter)); missingNameCounter++; } if (uniqueID.isEmpty()) { uniqueID = SystemUtilities::createUniqueID(); } if ( ! invalidElements.empty()) { /* * If invalid elements were encountered, don't throw */ AString msg("Invalid element(s) ignored: "); for (const auto s : invalidElements) { msg.append(s + " "); } CaretLogWarning(msg); } if (message.isEmpty()) { setName(name); setUniqueIdentifierProtected(uniqueID); /* * Only set centering correction if it is found. This allows usage * of the default value in the event this is not found in the XML. */ if ( ! centeringCorrectionTextString.isEmpty()) { m_centeringCorrectionEnabled = centeringCorrectionTextString.toBool(); } } else { xml.raiseError(message); } } /** * Decode elements in a row or column. * * @param reader * The XML stream reader. * @param element * row/column element that is read * @param errorMessageOut * Contains error information. * @return * True if read successfully, else false. */ bool TileTabsGridLayoutConfiguration::decodeRowColumnElement(QXmlStreamReader& reader, TileTabsGridRowColumnElement& element, AString& errorMessageOut) { const QXmlStreamAttributes atts = reader.attributes(); errorMessageOut.clear(); if (atts.hasAttribute(s_v2_contentTypeAttributeName)) { bool validFlag(false); const AString s = atts.value(s_v2_contentTypeAttributeName).toString(); element.setContentType(TileTabsGridRowColumnContentTypeEnum::fromName(s, &validFlag)); if ( ! validFlag) { errorMessageOut.append("Content type \"" + s + "\" is not valid. "); } } else { errorMessageOut.append("Content type is missing. "); } if (atts.hasAttribute(s_v2_stretchTypeAttributeName)) { bool validFlag(false); const AString s = atts.value(s_v2_stretchTypeAttributeName).toString(); element.setStretchType(TileTabsGridRowColumnStretchTypeEnum::fromName(s, &validFlag)); if ( ! validFlag) { errorMessageOut.append("Stretch type \"" + s + "\" is not valid. "); } } else { errorMessageOut.append("Stretch type is missing. "); } if (atts.hasAttribute(s_v2_percentStretchAttributeName)) { const float f = atts.value(s_v2_percentStretchAttributeName).toFloat(); if ((f >= 0.0) && (f < 100.0)) { element.setPercentStretch(f); } else { errorMessageOut.append("Stretch percentage=" + AString::number(f) + " is invalid."); } } else { errorMessageOut.append("Stretch percentage is missing. "); } if (atts.hasAttribute(s_v2_weightStretchAttributeName)) { const float f = atts.value(s_v2_weightStretchAttributeName).toFloat(); if ((f >= 0.0) && (f < 100.0)) { element.setWeightStretch(f); } else { errorMessageOut.append("Stretch weight=" + AString::number(f) + " is invalid."); } } else { errorMessageOut.append("Stretch weight is missing. "); } if (errorMessageOut.isEmpty()) { return true; } return false; } /** * @return String version of an instance. */ AString TileTabsGridLayoutConfiguration::toString() const { AString s = TileTabsBaseConfiguration::toString(); int32_t indx(0); for (const auto item : m_columns) { s.append(" Column " + AString::number(indx) + ": " + item.toString() + "\n"); indx++; } indx = 0; for (const auto item : m_rows) { s.append(" Row " + AString::number(indx) + ": " + item.toString() + "\n"); indx++; } return s; } connectome-workbench-1.4.2/src/Common/TileTabsGridLayoutConfiguration.h000066400000000000000000000205671360521144700263000ustar00rootroot00000000000000#ifndef __TILE_TABS_GRID_LAYOUT_CONFIGURATION_H__ #define __TILE_TABS_GRID_LAYOUT_CONFIGURATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretException.h" #include "TileTabsBaseConfiguration.h" #include "TileTabsGridModeEnum.h" #include "TileTabsGridRowColumnElement.h" class QXmlStreamReader; class QXmlStreamWriter; namespace caret { class TileTabsGridLayoutConfiguration : public TileTabsBaseConfiguration { public: TileTabsGridLayoutConfiguration(); virtual ~TileTabsGridLayoutConfiguration(); TileTabsGridLayoutConfiguration(const TileTabsGridLayoutConfiguration& obj); TileTabsGridLayoutConfiguration& operator=(const TileTabsGridLayoutConfiguration& obj); void copy(const TileTabsGridLayoutConfiguration& rhs); virtual TileTabsGridLayoutConfiguration* newCopyWithNewUniqueIdentifier() const override; bool getRowHeightsAndColumnWidthsForWindowSize(const int32_t windowWidth, const int32_t windowHeight, const int32_t numberOfModelsToDraw, const TileTabsGridModeEnum::Enum configurationMode, std::vector& rowHeightsOut, std::vector& columnWidthsOut); int32_t getNumberOfRows() const; void setNumberOfRows(const int32_t numberOfRows); int32_t getNumberOfColumns() const; void setNumberOfColumns(const int32_t numberOfColumns); TileTabsGridRowColumnElement* getColumn(const int32_t columnIndex); const TileTabsGridRowColumnElement* getColumn(const int32_t columnIndex) const; TileTabsGridRowColumnElement* getRow(const int32_t rowIndex); const TileTabsGridRowColumnElement* getRow(const int32_t rowIndex) const; void updateAutomaticConfigurationRowsAndColumns(const int32_t numberOfTabs); bool isCenteringCorrectionEnabled() const; void setCenteringCorrectionEnabled(const bool status); virtual AString toString() const override; static void getRowsAndColumnsForNumberOfTabs(const int32_t numberOfTabs, int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut); // ADD_NEW_METHODS_HERE protected: public: virtual void decodeFromXML(QXmlStreamReader& xml, const QString& rootElement) override; virtual void encodeInXML(AString& xmlTextOut) const override; private: void copyHelperTileTabsGridLayoutConfiguration(const TileTabsGridLayoutConfiguration& obj); void decodeFromXMLWithStreamReaderVersionOne(QXmlStreamReader& xml); void decodeFromXMLWithStreamReaderVersionTwo(QXmlStreamReader& xml); AString encodeVersionInXML(const int32_t versionNumber) const; AString encodeInXMLWithStreamWriterVersionOne() const; AString encodeInXMLWithStreamWriterVersionTwo() const; void encodeRowColumnElement(QXmlStreamWriter& writer, const AString tagName, const std::vector& elements) const; bool decodeRowColumnElement(QXmlStreamReader& reader, TileTabsGridRowColumnElement& element, AString& errorMessageOut); void initialize(); // ADD_NEW_MEMBERS_HERE std::vector m_columns; std::vector m_rows; bool m_centeringCorrectionEnabled = false; static const AString s_nameTagName; static const AString s_uniqueIdentifierTagName; static const AString s_v1_rootTagName; static const AString s_v1_versionTagName; static const AString s_v1_versionNumberAttributeName; static const AString s_v1_columnStretchFactorsTagName; static const AString s_v1_columnStretchFactorsSelectedCountAttributeName; static const AString s_v1_columnStretchFactorsTotalCountAttributeName; static const AString s_v1_rowStretchFactorsTagName; static const AString s_v1_rowStretchFactorsSelectedCountAttributeName; static const AString s_v1_rowStretchFactorsTotalCountAttributeName; static const AString s_v2_rootTagName; static const AString s_v2_versionAttributeName; static const AString s_v2_columnsTagName; static const AString s_v2_contentTypeAttributeName; static const AString s_v2_elementTagName; static const AString s_v2_percentStretchAttributeName; static const AString s_v2_rowsTagName; static const AString s_v2_stretchTypeAttributeName; static const AString s_v2_weightStretchAttributeName; static const AString s_v2_centeringCorrectionName; friend class TileTabsBaseConfiguration; }; #ifdef __TILE_TABS_GRID_LAYOUT_CONFIGURATION_DECLARE__ const AString TileTabsGridLayoutConfiguration::s_nameTagName = "Name"; const AString TileTabsGridLayoutConfiguration::s_uniqueIdentifierTagName = "UniqueIdentifier"; const AString TileTabsGridLayoutConfiguration::s_v1_rootTagName = "TileTabsGridLayoutConfiguration"; const AString TileTabsGridLayoutConfiguration::s_v1_versionTagName = "Version"; const AString TileTabsGridLayoutConfiguration::s_v1_versionNumberAttributeName = "Number"; const AString TileTabsGridLayoutConfiguration::s_v1_columnStretchFactorsTagName = "ColumnStretchFactors"; const AString TileTabsGridLayoutConfiguration::s_v1_columnStretchFactorsSelectedCountAttributeName = "SelectedRowCount"; const AString TileTabsGridLayoutConfiguration::s_v1_columnStretchFactorsTotalCountAttributeName = "TotalRowCount"; const AString TileTabsGridLayoutConfiguration::s_v1_rowStretchFactorsTagName = "RowStretchFactors"; const AString TileTabsGridLayoutConfiguration::s_v1_rowStretchFactorsSelectedCountAttributeName = "SelectedColumnCount"; const AString TileTabsGridLayoutConfiguration::s_v1_rowStretchFactorsTotalCountAttributeName = "TotalColumnCount"; const AString TileTabsGridLayoutConfiguration::s_v2_rootTagName = "TileTabsGridLayoutConfigurationTwo"; const AString TileTabsGridLayoutConfiguration::s_v2_versionAttributeName = "Version"; const AString TileTabsGridLayoutConfiguration::s_v2_columnsTagName = "Columns"; const AString TileTabsGridLayoutConfiguration::s_v2_contentTypeAttributeName = "ContentType"; const AString TileTabsGridLayoutConfiguration::s_v2_elementTagName = "Element"; const AString TileTabsGridLayoutConfiguration::s_v2_percentStretchAttributeName = "PercentStretch"; const AString TileTabsGridLayoutConfiguration::s_v2_rowsTagName = "Rows"; const AString TileTabsGridLayoutConfiguration::s_v2_stretchTypeAttributeName = "StretchType"; const AString TileTabsGridLayoutConfiguration::s_v2_weightStretchAttributeName = "WeightStretch"; const AString TileTabsGridLayoutConfiguration::s_v2_centeringCorrectionName = "CenteringCorrection"; #endif // __TILE_TABS_GRID_LAYOUT_CONFIGURATION_DECLARE__ } // namespace #endif //__TILE_TABS_GRID_LAYOUT_CONFIGURATION_H__ connectome-workbench-1.4.2/src/Common/TileTabsGridModeEnum.cxx000066400000000000000000000246241360521144700243550ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __TILE_TABS_GRID_MODE_ENUM_DECLARE__ #include "TileTabsGridModeEnum.h" #undef __TILE_TABS_GRID_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::TileTabsGridModeEnum * \brief Enumerated type for Grid Tile Tab Configuration Mode (auto, custom) * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_TileTabsGridModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void TileTabsGridModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "TileTabsGridModeEnum.h" * * Instatiate: * m_TileTabsGridModeEnumComboBox = new EnumComboBoxTemplate(this); * m_TileTabsGridModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_TileTabsGridModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(TileTabsGridModeEnumComboBoxItemActivated())); * * Update the selection: * m_TileTabsGridModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const TileTabsGridModeEnum::Enum VARIABLE = m_TileTabsGridModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ TileTabsGridModeEnum::TileTabsGridModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ TileTabsGridModeEnum::~TileTabsGridModeEnum() { } /** * Initialize the enumerated metadata. */ void TileTabsGridModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(TileTabsGridModeEnum(AUTOMATIC, "AUTOMATIC", "Automatic")); enumData.push_back(TileTabsGridModeEnum(CUSTOM, "CUSTOM", "Custom")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const TileTabsGridModeEnum* TileTabsGridModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const TileTabsGridModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString TileTabsGridModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const TileTabsGridModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ TileTabsGridModeEnum::Enum TileTabsGridModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = TileTabsGridModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const TileTabsGridModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type TileTabsGridModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString TileTabsGridModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const TileTabsGridModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ TileTabsGridModeEnum::Enum TileTabsGridModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = TileTabsGridModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const TileTabsGridModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type TileTabsGridModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t TileTabsGridModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const TileTabsGridModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ TileTabsGridModeEnum::Enum TileTabsGridModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = TileTabsGridModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const TileTabsGridModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type TileTabsGridModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void TileTabsGridModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void TileTabsGridModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(TileTabsGridModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void TileTabsGridModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(TileTabsGridModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/TileTabsGridModeEnum.h000066400000000000000000000061441360521144700237770ustar00rootroot00000000000000#ifndef __TILE_TABS_GRID_MODE_ENUM_H__ #define __TILE_TABS_GRID_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class TileTabsGridModeEnum { public: /** * Enumerated values. */ enum Enum { /** Workbench creates tab layout */ AUTOMATIC, /** User customizes tab layout */ CUSTOM }; ~TileTabsGridModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: TileTabsGridModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const TileTabsGridModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __TILE_TABS_GRID_MODE_ENUM_DECLARE__ std::vector TileTabsGridModeEnum::enumData; bool TileTabsGridModeEnum::initializedFlag = false; int32_t TileTabsGridModeEnum::integerCodeCounter = 0; #endif // __TILE_TABS_GRID_MODE_ENUM_DECLARE__ } // namespace #endif //__TILE_TABS_GRID_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Common/TileTabsGridRowColumnContentTypeEnum.cxx000066400000000000000000000265461360521144700276200ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __TILE_TABS_GRID_ROW_COLUMN_CONTENT_TYPE_ENUM_DECLARE__ #include "TileTabsGridRowColumnContentTypeEnum.h" #undef __TILE_TABS_GRID_ROW_COLUMN_CONTENT_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::TileTabsGridRowColumnContentTypeEnum * \brief Content type for a row or column in a tile tabs grid * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_TileTabsGridRowColumnContentTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void TileTabsGridRowColumnContentTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "TileTabsGridRowColumnContentTypeEnum.h" * * Instatiate: * m_TileTabsGridRowColumnContentTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_TileTabsGridRowColumnContentTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_TileTabsGridRowColumnContentTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(TileTabsGridRowColumnContentTypeEnumComboBoxItemActivated())); * * Update the selection: * m_TileTabsGridRowColumnContentTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const TileTabsGridRowColumnContentTypeEnum::Enum VARIABLE = m_TileTabsGridRowColumnContentTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ TileTabsGridRowColumnContentTypeEnum::TileTabsGridRowColumnContentTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ TileTabsGridRowColumnContentTypeEnum::~TileTabsGridRowColumnContentTypeEnum() { } /** * Initialize the enumerated metadata. */ void TileTabsGridRowColumnContentTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(TileTabsGridRowColumnContentTypeEnum(SPACE, "SPACE", "Space")); enumData.push_back(TileTabsGridRowColumnContentTypeEnum(TAB, "TAB", "Tab")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const TileTabsGridRowColumnContentTypeEnum* TileTabsGridRowColumnContentTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const TileTabsGridRowColumnContentTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString TileTabsGridRowColumnContentTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const TileTabsGridRowColumnContentTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ TileTabsGridRowColumnContentTypeEnum::Enum TileTabsGridRowColumnContentTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = TileTabsGridRowColumnContentTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const TileTabsGridRowColumnContentTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type TileTabsGridRowColumnContentTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString TileTabsGridRowColumnContentTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const TileTabsGridRowColumnContentTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ TileTabsGridRowColumnContentTypeEnum::Enum TileTabsGridRowColumnContentTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = TileTabsGridRowColumnContentTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const TileTabsGridRowColumnContentTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type TileTabsGridRowColumnContentTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t TileTabsGridRowColumnContentTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const TileTabsGridRowColumnContentTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ TileTabsGridRowColumnContentTypeEnum::Enum TileTabsGridRowColumnContentTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = TileTabsGridRowColumnContentTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const TileTabsGridRowColumnContentTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type TileTabsGridRowColumnContentTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void TileTabsGridRowColumnContentTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void TileTabsGridRowColumnContentTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(TileTabsGridRowColumnContentTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void TileTabsGridRowColumnContentTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(TileTabsGridRowColumnContentTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/TileTabsGridRowColumnContentTypeEnum.h000066400000000000000000000064361360521144700272410ustar00rootroot00000000000000#ifndef __TILE_TABS_GRID_ROW_COLUMN_CONTENT_TYPE_ENUM_H__ #define __TILE_TABS_GRID_ROW_COLUMN_CONTENT_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class TileTabsGridRowColumnContentTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Space */ SPACE, /** Tab */ TAB }; ~TileTabsGridRowColumnContentTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: TileTabsGridRowColumnContentTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const TileTabsGridRowColumnContentTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __TILE_TABS_GRID_ROW_COLUMN_CONTENT_TYPE_ENUM_DECLARE__ std::vector TileTabsGridRowColumnContentTypeEnum::enumData; bool TileTabsGridRowColumnContentTypeEnum::initializedFlag = false; int32_t TileTabsGridRowColumnContentTypeEnum::integerCodeCounter = 0; #endif // __TILE_TABS_GRID_ROW_COLUMN_CONTENT_TYPE_ENUM_DECLARE__ } // namespace #endif //__TILE_TABS_GRID_ROW_COLUMN_CONTENT_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Common/TileTabsGridRowColumnElement.cxx000066400000000000000000000114321360521144700260740ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __TILE_TABS_GRID_ROW_COLUMN_ELEMENT_DECLARE__ #include "TileTabsGridRowColumnElement.h" #undef __TILE_TABS_GRID_ROW_COLUMN_ELEMENT_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::TileTabsGridRowColumnElement * \brief Contents on an element in a Tile Tabs Configuration grid row or column. * \ingroup Common */ /** * Constructor. */ TileTabsGridRowColumnElement::TileTabsGridRowColumnElement() : CaretObject() { clear(); } /** * Destructor. */ TileTabsGridRowColumnElement::~TileTabsGridRowColumnElement() { } /** * Copy constructor. * @param obj * Object that is copied. */ TileTabsGridRowColumnElement::TileTabsGridRowColumnElement(const TileTabsGridRowColumnElement& obj) : CaretObject(obj) { this->copyHelperTileTabsGridRowColumnElement(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ TileTabsGridRowColumnElement& TileTabsGridRowColumnElement::operator=(const TileTabsGridRowColumnElement& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperTileTabsGridRowColumnElement(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void TileTabsGridRowColumnElement::copyHelperTileTabsGridRowColumnElement(const TileTabsGridRowColumnElement& obj) { m_contentType = obj.m_contentType; m_stretchType = obj.m_stretchType; m_percentStretch = obj.m_percentStretch; m_weightStretch = obj.m_weightStretch; } /** * Clear this instance. */ void TileTabsGridRowColumnElement::clear() { m_contentType = TileTabsGridRowColumnContentTypeEnum::TAB; m_stretchType = TileTabsGridRowColumnStretchTypeEnum::WEIGHT; m_percentStretch = 20.0; m_weightStretch = 1.0; } /** * @return Content type (spacer or tab) */ TileTabsGridRowColumnContentTypeEnum::Enum TileTabsGridRowColumnElement::getContentType() const { return m_contentType; } /** * Set the content type (spacer or tab) * * @param contentType * New value for content type. */ void TileTabsGridRowColumnElement::setContentType(const TileTabsGridRowColumnContentTypeEnum::Enum contentType) { m_contentType = contentType; } /** * @return The stretch type (percent or weight) */ TileTabsGridRowColumnStretchTypeEnum::Enum TileTabsGridRowColumnElement::getStretchType() const { return m_stretchType; } /** * Set the stretch type (percent or weight) * * @param stretchType * New value for stretch type. */ void TileTabsGridRowColumnElement::setStretchType(const TileTabsGridRowColumnStretchTypeEnum::Enum stretchType) { m_stretchType = stretchType; } /** * @return The percent stretch value. */ float TileTabsGridRowColumnElement::getPercentStretch() const { return m_percentStretch; } /** * Set the percent stretch value. * * @param percentStretch * New value for percent stretch. */ void TileTabsGridRowColumnElement::setPercentStretch(const float percentStretch) { m_percentStretch = percentStretch; } /** * @return The weight stretch value. */ float TileTabsGridRowColumnElement::getWeightStretch() const { return m_weightStretch; } /** * Set the weight stretch value. * * @param weightStretch * New value for weight stretch. */ void TileTabsGridRowColumnElement::setWeightStretch(const float weightStretch) { m_weightStretch = weightStretch; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString TileTabsGridRowColumnElement::toString() const { AString s("TileTabsGridRowColumnElement: "); s.append("ContentType=" + TileTabsGridRowColumnContentTypeEnum::toGuiName(m_contentType)); s.append(" StretchType=" + TileTabsGridRowColumnStretchTypeEnum::toGuiName(m_stretchType)); s.append(" PercentStretch=" + AString::number(m_percentStretch)); s.append(" WeightStretch=" + AString::number(m_weightStretch)); return s; } connectome-workbench-1.4.2/src/Common/TileTabsGridRowColumnElement.h000066400000000000000000000055161360521144700255270ustar00rootroot00000000000000#ifndef __TILE_TABS_GRID_ROW_COLUMN_ELEMENT_H__ #define __TILE_TABS_GRID_ROW_COLUMN_ELEMENT_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "TileTabsGridRowColumnContentTypeEnum.h" #include "TileTabsGridRowColumnStretchTypeEnum.h" namespace caret { class TileTabsGridRowColumnElement : public CaretObject { public: TileTabsGridRowColumnElement(); virtual ~TileTabsGridRowColumnElement(); TileTabsGridRowColumnElement(const TileTabsGridRowColumnElement& obj); TileTabsGridRowColumnElement& operator=(const TileTabsGridRowColumnElement& obj); void clear(); TileTabsGridRowColumnContentTypeEnum::Enum getContentType() const; void setContentType(const TileTabsGridRowColumnContentTypeEnum::Enum contentType); TileTabsGridRowColumnStretchTypeEnum::Enum getStretchType() const; void setStretchType(const TileTabsGridRowColumnStretchTypeEnum::Enum stretchType); float getPercentStretch() const; void setPercentStretch(const float percentStretch); float getWeightStretch() const; void setWeightStretch(const float weightStretch); // ADD_NEW_METHODS_HERE virtual AString toString() const; private: void copyHelperTileTabsGridRowColumnElement(const TileTabsGridRowColumnElement& obj); TileTabsGridRowColumnContentTypeEnum::Enum m_contentType = TileTabsGridRowColumnContentTypeEnum::TAB; TileTabsGridRowColumnStretchTypeEnum::Enum m_stretchType = TileTabsGridRowColumnStretchTypeEnum::WEIGHT; float m_percentStretch = 20.0; float m_weightStretch = 1.0; // ADD_NEW_MEMBERS_HERE }; #ifdef __TILE_TABS_GRID_ROW_COLUMN_ELEMENT_DECLARE__ // #endif // __TILE_TABS_GRID_ROW_COLUMN_ELEMENT_DECLARE__ } // namespace #endif //__TILE_TABS_GRID_ROW_COLUMN_ELEMENT_H__ connectome-workbench-1.4.2/src/Common/TileTabsGridRowColumnStretchTypeEnum.cxx000066400000000000000000000265561360521144700276230ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __TILE_TABS_GRID_ROW_COLUMN_STRETCH_TYPE_ENUM_DECLARE__ #include "TileTabsGridRowColumnStretchTypeEnum.h" #undef __TILE_TABS_GRID_ROW_COLUMN_STRETCH_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::TileTabsGridRowColumnStretchTypeEnum * \brief Stretch type for tile tabs grid configuration. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_TileTabsGridRowColumnStretchTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void TileTabsGridRowColumnStretchTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "TileTabsGridRowColumnStretchTypeEnum.h" * * Instatiate: * m_TileTabsGridRowColumnStretchTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_TileTabsGridRowColumnStretchTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_TileTabsGridRowColumnStretchTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(TileTabsGridRowColumnStretchTypeEnumComboBoxItemActivated())); * * Update the selection: * m_TileTabsGridRowColumnStretchTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const TileTabsGridRowColumnStretchTypeEnum::Enum VARIABLE = m_TileTabsGridRowColumnStretchTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ TileTabsGridRowColumnStretchTypeEnum::TileTabsGridRowColumnStretchTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ TileTabsGridRowColumnStretchTypeEnum::~TileTabsGridRowColumnStretchTypeEnum() { } /** * Initialize the enumerated metadata. */ void TileTabsGridRowColumnStretchTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(TileTabsGridRowColumnStretchTypeEnum(PERCENT, "PERCENT", "Percent")); enumData.push_back(TileTabsGridRowColumnStretchTypeEnum(WEIGHT, "WEIGHT", "Weight")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const TileTabsGridRowColumnStretchTypeEnum* TileTabsGridRowColumnStretchTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const TileTabsGridRowColumnStretchTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString TileTabsGridRowColumnStretchTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const TileTabsGridRowColumnStretchTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ TileTabsGridRowColumnStretchTypeEnum::Enum TileTabsGridRowColumnStretchTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = TileTabsGridRowColumnStretchTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const TileTabsGridRowColumnStretchTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type TileTabsGridRowColumnStretchTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString TileTabsGridRowColumnStretchTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const TileTabsGridRowColumnStretchTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ TileTabsGridRowColumnStretchTypeEnum::Enum TileTabsGridRowColumnStretchTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = TileTabsGridRowColumnStretchTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const TileTabsGridRowColumnStretchTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type TileTabsGridRowColumnStretchTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t TileTabsGridRowColumnStretchTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const TileTabsGridRowColumnStretchTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ TileTabsGridRowColumnStretchTypeEnum::Enum TileTabsGridRowColumnStretchTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = TileTabsGridRowColumnStretchTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const TileTabsGridRowColumnStretchTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type TileTabsGridRowColumnStretchTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void TileTabsGridRowColumnStretchTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void TileTabsGridRowColumnStretchTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(TileTabsGridRowColumnStretchTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void TileTabsGridRowColumnStretchTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(TileTabsGridRowColumnStretchTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/TileTabsGridRowColumnStretchTypeEnum.h000066400000000000000000000064501360521144700272370ustar00rootroot00000000000000#ifndef __TILE_TABS_GRID_ROW_COLUMN_STRETCH_TYPE_ENUM_H__ #define __TILE_TABS_GRID_ROW_COLUMN_STRETCH_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class TileTabsGridRowColumnStretchTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Percent */ PERCENT, /** Weight */ WEIGHT }; ~TileTabsGridRowColumnStretchTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: TileTabsGridRowColumnStretchTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const TileTabsGridRowColumnStretchTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __TILE_TABS_GRID_ROW_COLUMN_STRETCH_TYPE_ENUM_DECLARE__ std::vector TileTabsGridRowColumnStretchTypeEnum::enumData; bool TileTabsGridRowColumnStretchTypeEnum::initializedFlag = false; int32_t TileTabsGridRowColumnStretchTypeEnum::integerCodeCounter = 0; #endif // __TILE_TABS_GRID_ROW_COLUMN_STRETCH_TYPE_ENUM_DECLARE__ } // namespace #endif //__TILE_TABS_GRID_ROW_COLUMN_STRETCH_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Common/TracksModificationInterface.h000066400000000000000000000073751360521144700254350ustar00rootroot00000000000000#ifndef __TRACKSMODIFICATION_H__ #define __TRACKSMODIFICATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ namespace caret { /** * \brief Interface for tracking object modification status. * * Interface for tracking an objects modification status. *
* setModified() should set a boolean that indicates * the modified status. *
* clearModified() should clear the boolean that indicates * the modified status AND should call clearModified() * on any members that implement this interface. *
* isModified() should return the boolean that indicates * the modified status. *
*
* When a class DOES extend a class that implements this * interface, it must implement the clearModified() * and the isModified() ONLY IF it contains members * that implement this interface. *
* The clearMethod() must call the parent's clearModified() * method and the clearModified() method on any member * classes that implement this interface. *
* The isModified() method must first call the parent's * isModified() method, and, if true, true true. Otherwise, * return true if a member is modified. * *
* An alternative model of this interface is to add * methods such as addTrackable(TracksModificationInterface) * and removeTrackable(TracksModificationInterface) that * could be used to query and reset the modification status * of any members in the implementing class and subclasses. * In this case, the isModified(), setModified(), and * clearModified() methods would only need to be implemented * in the top-level class. In this case the * addTrackable() and removeTrackable() classes may be * better off in a separate interface. */ class TracksModificationInterface { protected: /** * Constructor. */ TracksModificationInterface() { } /** * Destructor. */ virtual ~TracksModificationInterface() { } private: TracksModificationInterface(const TracksModificationInterface&); TracksModificationInterface& operator=(const TracksModificationInterface&); public: /** * Set the status to modified. */ virtual void setModified() = 0; /** * Set the status to unmodified. */ virtual void clearModified() = 0; /** * Is the object modified? * @return true if modified, else false. */ virtual bool isModified() const = 0; }; class TracksModification : public TracksModificationInterface { /** modification status */ bool modifiedFlag; protected: TracksModification() { modifiedFlag = false; } public: /** * Set the status to modified. */ virtual void setModified() { modifiedFlag = true; } /** * Set the status to unmodified. */ virtual void clearModified() { modifiedFlag = false; } /** * Is the object modified? * @return true if modified, else false. */ virtual bool isModified() const { return modifiedFlag; } }; } // namespace #endif // __TRACKSMODIFICATION_H__ connectome-workbench-1.4.2/src/Common/TriStateSelectionStatusEnum.cxx000066400000000000000000000260511360521144700260400ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __TRI_STATE_SELECTION_STATUS_ENUM_DECLARE__ #include "TriStateSelectionStatusEnum.h" #undef __TRI_STATE_SELECTION_STATUS_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::TriStateSelectionStatusEnum * \brief * * * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_triStateSelectionStatusEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void triStateSelectionStatusEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "TriStateSelectionStatusEnum.h" * * Instatiate: * m_triStateSelectionStatusEnumComboBox = new EnumComboBoxTemplate(this); * m_triStateSelectionStatusEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_triStateSelectionStatusEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(triStateSelectionStatusEnumComboBoxItemActivated())); * * Update the selection: * m_triStateSelectionStatusEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const TriStateSelectionStatusEnum::Enum VARIABLE = m_triStateSelectionStatusEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ TriStateSelectionStatusEnum::TriStateSelectionStatusEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ TriStateSelectionStatusEnum::~TriStateSelectionStatusEnum() { } /** * Initialize the enumerated metadata. */ void TriStateSelectionStatusEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(TriStateSelectionStatusEnum(UNSELECTED, "UNSELECTED", "Unselected")); enumData.push_back(TriStateSelectionStatusEnum(PARTIALLY_SELECTED, "PARTIALLY_SELECTED", "Partially Selected")); enumData.push_back(TriStateSelectionStatusEnum(SELECTED, "SELECTED", "Selected")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const TriStateSelectionStatusEnum* TriStateSelectionStatusEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const TriStateSelectionStatusEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString TriStateSelectionStatusEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const TriStateSelectionStatusEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ TriStateSelectionStatusEnum::Enum TriStateSelectionStatusEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = TriStateSelectionStatusEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const TriStateSelectionStatusEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type TriStateSelectionStatusEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString TriStateSelectionStatusEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const TriStateSelectionStatusEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ TriStateSelectionStatusEnum::Enum TriStateSelectionStatusEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = TriStateSelectionStatusEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const TriStateSelectionStatusEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type TriStateSelectionStatusEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t TriStateSelectionStatusEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const TriStateSelectionStatusEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ TriStateSelectionStatusEnum::Enum TriStateSelectionStatusEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = TriStateSelectionStatusEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const TriStateSelectionStatusEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type TriStateSelectionStatusEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void TriStateSelectionStatusEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void TriStateSelectionStatusEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(TriStateSelectionStatusEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void TriStateSelectionStatusEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(TriStateSelectionStatusEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/TriStateSelectionStatusEnum.h000066400000000000000000000062761360521144700254740ustar00rootroot00000000000000#ifndef __TRI_STATE_SELECTION_STATUS_ENUM_H__ #define __TRI_STATE_SELECTION_STATUS_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class TriStateSelectionStatusEnum { public: /** * Enumerated values. */ enum Enum { /** */ UNSELECTED, /** */ PARTIALLY_SELECTED, /** */ SELECTED }; ~TriStateSelectionStatusEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: TriStateSelectionStatusEnum(const Enum enumValue, const AString& name, const AString& guiName); static const TriStateSelectionStatusEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __TRI_STATE_SELECTION_STATUS_ENUM_DECLARE__ std::vector TriStateSelectionStatusEnum::enumData; bool TriStateSelectionStatusEnum::initializedFlag = false; int32_t TriStateSelectionStatusEnum::integerCodeCounter = 0; #endif // __TRI_STATE_SELECTION_STATUS_ENUM_DECLARE__ } // namespace #endif //__TRI_STATE_SELECTION_STATUS_ENUM_H__ connectome-workbench-1.4.2/src/Common/Vector3D.cxx000066400000000000000000000124001360521144700220240ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "MathFunctions.h" #include "Vector3D.h" using namespace std; using namespace caret; Vector3D Vector3D::cross(const Vector3D& right) const { Vector3D ret; MathFunctions::crossProduct(m_vec, right.m_vec, ret.m_vec); return ret; } float Vector3D::dot(const Vector3D& right) const { return MathFunctions::dotProduct(m_vec, right.m_vec); } float Vector3D::length() const { return MathFunctions::vectorLength(m_vec); } float Vector3D::lengthsquared() const { return m_vec[0] * m_vec[0] + m_vec[1] * m_vec[1] + m_vec[2] * m_vec[2]; } Vector3D Vector3D::normal(float* origLength) const { Vector3D ret = *this; if (origLength != NULL) { *origLength = MathFunctions::normalizeVector(ret.m_vec); } else { MathFunctions::normalizeVector(ret.m_vec); } return ret; } float Vector3D::distToLine(const Vector3D& p1, const Vector3D& p2, Vector3D* closePointOut) const { Vector3D diff = p2 - p1; float origLength; Vector3D diffHat = diff.normal(&origLength); if (origLength == 0.0f)//line is degenerate, return distance to point - we could return zero, but this seems like it would be better behaved { if (closePointOut != NULL) *closePointOut = p1; return (*this - p1).length(); } float distAlong = diffHat.dot(*this - p1); Vector3D closePoint = p1 + diffHat * distAlong; if (closePointOut != NULL) *closePointOut = closePoint; return (*this - closePoint).length(); } float Vector3D::distToLineSegment(const Vector3D& p1, const Vector3D& p2, Vector3D* closePointOut) const { float origLength; Vector3D diffHat = (p2 - p1).normal(&origLength); if (origLength == 0.0f)//line segment is degenerate, return distance to point { if (closePointOut != NULL) *closePointOut = p1; return (*this - p1).length(); } float distAlong = diffHat.dot(*this - p1); if (distAlong < 0.0f) distAlong = 0.0f; if (distAlong > origLength) distAlong = origLength; Vector3D closePoint = p1 + diffHat * distAlong; if (closePointOut != NULL) *closePointOut = closePoint; return (*this - closePoint).length(); } Vector3D::Vector3D() { m_vec[0] = 0.0f; m_vec[1] = 0.0f; m_vec[2] = 0.0f; } Vector3D::Vector3D(const float& x, const float& y, const float& z) { m_vec[0] = x; m_vec[1] = y; m_vec[2] = z; } Vector3D::Vector3D(const float* right) { m_vec[0] = right[0]; m_vec[1] = right[1]; m_vec[2] = right[2]; } float& Vector3D::operator[](const int64_t& index) { CaretAssert(index > -1 && index < 3); return m_vec[index]; } const float& Vector3D::operator[](const int64_t& index) const { CaretAssert(index > -1 && index < 3); return m_vec[index]; } float& Vector3D::operator[](const int32_t& index) { CaretAssert(index > -1 && index < 3); return m_vec[index]; } const float& Vector3D::operator[](const int32_t& index) const { CaretAssert(index > -1 && index < 3); return m_vec[index]; } Vector3D Vector3D::operator*(const float& right) const { Vector3D ret = *this; ret *= right; return ret; } Vector3D& Vector3D::operator*=(const float& right) { m_vec[0] *= right; m_vec[1] *= right; m_vec[2] *= right; return *this; } Vector3D caret::operator*(const float& left, const Vector3D& right) { return right * left; } Vector3D Vector3D::operator+(const Vector3D& right) const { Vector3D ret = *this; ret += right; return ret; } Vector3D& Vector3D::operator+=(const Vector3D& right) { m_vec[0] += right.m_vec[0]; m_vec[1] += right.m_vec[1]; m_vec[2] += right.m_vec[2]; return *this; } Vector3D Vector3D::operator-(const Vector3D& right) const { Vector3D ret = *this; ret -= right; return ret; } Vector3D Vector3D::operator-() const { Vector3D ret; ret.m_vec[0] = -m_vec[0]; ret.m_vec[1] = -m_vec[1]; ret.m_vec[2] = -m_vec[2]; return ret; } Vector3D& Vector3D::operator-=(const Vector3D& right) { m_vec[0] -= right.m_vec[0]; m_vec[1] -= right.m_vec[1]; m_vec[2] -= right.m_vec[2]; return *this; } Vector3D Vector3D::operator/(const float& right) const { Vector3D ret = *this; ret /= right; return ret; } Vector3D& Vector3D::operator/=(const float& right) { m_vec[0] /= right; m_vec[1] /= right; m_vec[2] /= right; return *this; } Vector3D& Vector3D::operator=(const float* right) { m_vec[0] = right[0]; m_vec[1] = right[1]; m_vec[2] = right[2]; return *this; } connectome-workbench-1.4.2/src/Common/Vector3D.h000066400000000000000000000051651360521144700214630ustar00rootroot00000000000000#ifndef __VECTOR_3D_H__ #define __VECTOR_3D_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" namespace caret { class Vector3D { float m_vec[3]; public: //vector functions float dot(const Vector3D& right) const; Vector3D cross(const Vector3D& right) const; Vector3D normal(float* origLength = NULL) const; float length() const; float lengthsquared() const; //geometry functions float distToLine(const Vector3D& p1, const Vector3D& p2, Vector3D* closePointOut = NULL) const; float distToLineSegment(const Vector3D& p1, const Vector3D& p2, Vector3D* closePointOut = NULL) const; //constructors Vector3D(); Vector3D(const float& x, const float& y, const float& z); Vector3D(const float* right); //compatibility operators float& operator[](const int64_t& index); const float& operator[](const int64_t& index) const; float& operator[](const int32_t& index); const float& operator[](const int32_t& index) const; Vector3D& operator=(const float* right); //numerical operators Vector3D& operator+=(const Vector3D& right); Vector3D& operator-=(const Vector3D& right); Vector3D& operator*=(const float& right); Vector3D& operator/=(const float& right); Vector3D operator+(const Vector3D& right) const; Vector3D operator-(const Vector3D& right) const; Vector3D operator-() const; Vector3D operator*(const float& right) const; Vector3D operator/(const float& right) const;//NOTE: doesn't really make sense to have the other division, unlike multiplication inline operator float*() { return m_vec; } }; Vector3D operator*(const float& left, const Vector3D& right); } #endif //__VECTOR_3D_H__ connectome-workbench-1.4.2/src/Common/VectorOperation.cxx000066400000000000000000000053441360521144700235270ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "VectorOperation.h" #include "CaretAssert.h" using namespace std; using namespace caret; VectorOperation::Operation VectorOperation::stringToOperation(const AString& string, bool& ok) { ok = true; if (string == "DOT") { return DOT; } else if (string == "CROSS") { return CROSS; } else if (string == "ADD") { return ADD; } else if (string == "SUBTRACT") { return SUBTRACT; } ok = false; return DOT;//have to return something } AString VectorOperation::operationToString(const VectorOperation::Operation& myOp) { switch (myOp) { case DOT: return "DOT"; case CROSS: return "CROSS"; case ADD: return "ADD"; case SUBTRACT: return "SUBTRACT"; } return ""; } vector VectorOperation::getAllOperations() { vector ret; ret.push_back(DOT); ret.push_back(CROSS); ret.push_back(ADD); ret.push_back(SUBTRACT); return ret; } bool VectorOperation::operationReturnsScalar(const VectorOperation::Operation& myOp) { switch (myOp) { case DOT: return true; default: return false; } } Vector3D VectorOperation::doVectorOperation(const Vector3D& first, const Vector3D& second, const Operation& myOp) { switch (myOp) { case CROSS: return first.cross(second); case ADD: return first + second; case SUBTRACT: return first - second; default: CaretAssert(false); return Vector3D(); } } float VectorOperation::doScalarOperation(const Vector3D& first, const Vector3D& second, const VectorOperation::Operation& myOp) { switch (myOp) { case DOT: return first.dot(second); default: CaretAssert(false); return 0.0f; } } connectome-workbench-1.4.2/src/Common/VectorOperation.h000066400000000000000000000033341360521144700231510ustar00rootroot00000000000000#ifndef __VECTOR_OPERATION_H__ #define __VECTOR_OPERATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AString.h" #include "Vector3D.h" #include namespace caret { ///helper class for doing user-specified operations on 3D vectors class VectorOperation { public: enum Operation { DOT, CROSS, ADD, SUBTRACT }; static Operation stringToOperation(const AString& string, bool& ok); static AString operationToString(const Operation& myOp); static std::vector getAllOperations(); static bool operationReturnsScalar(const Operation& myOp); static Vector3D doVectorOperation(const Vector3D& first, const Vector3D& second, const Operation& myOp); static float doScalarOperation(const Vector3D& first, const Vector3D& second, const Operation& myOp); }; } #endif //__VECTOR_OPERATION_H__ connectome-workbench-1.4.2/src/Common/VolumeSliceViewAllPlanesLayoutEnum.cxx000066400000000000000000000266671360521144700273200ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __VOLUME_SLICE_VIEW_ALL_PLANES_LAYOUT_ENUM_DECLARE__ #include "VolumeSliceViewAllPlanesLayoutEnum.h" #undef __VOLUME_SLICE_VIEW_ALL_PLANES_LAYOUT_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::VolumeSliceViewAllPlanesLayoutEnum * \brief Enumerated type for layout in slice view all mode. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_volumeSliceViewAllPlanesLayoutEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void volumeSliceViewAllPlanesLayoutEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "VolumeSliceViewAllPlanesLayoutEnum.h" * * Instatiate: * m_volumeSliceViewAllPlanesLayoutEnumComboBox = new EnumComboBoxTemplate(this); * m_volumeSliceViewAllPlanesLayoutEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_volumeSliceViewAllPlanesLayoutEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(volumeSliceViewAllPlanesLayoutEnumComboBoxItemActivated())); * * Update the selection: * m_volumeSliceViewAllPlanesLayoutEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const VolumeSliceViewAllPlanesLayoutEnum::Enum VARIABLE = m_volumeSliceViewAllPlanesLayoutEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ VolumeSliceViewAllPlanesLayoutEnum::VolumeSliceViewAllPlanesLayoutEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ VolumeSliceViewAllPlanesLayoutEnum::~VolumeSliceViewAllPlanesLayoutEnum() { } /** * Initialize the enumerated metadata. */ void VolumeSliceViewAllPlanesLayoutEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(VolumeSliceViewAllPlanesLayoutEnum(GRID_LAYOUT, "GRID_LAYOUT", "Grid")); enumData.push_back(VolumeSliceViewAllPlanesLayoutEnum(COLUMN_LAYOUT, "COLUMN_LAYOUT", "Column")); enumData.push_back(VolumeSliceViewAllPlanesLayoutEnum(ROW_LAYOUT, "ROW_LAYOUT", "Row")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const VolumeSliceViewAllPlanesLayoutEnum* VolumeSliceViewAllPlanesLayoutEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const VolumeSliceViewAllPlanesLayoutEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString VolumeSliceViewAllPlanesLayoutEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const VolumeSliceViewAllPlanesLayoutEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ VolumeSliceViewAllPlanesLayoutEnum::Enum VolumeSliceViewAllPlanesLayoutEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = VolumeSliceViewAllPlanesLayoutEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const VolumeSliceViewAllPlanesLayoutEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type VolumeSliceViewAllPlanesLayoutEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString VolumeSliceViewAllPlanesLayoutEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const VolumeSliceViewAllPlanesLayoutEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ VolumeSliceViewAllPlanesLayoutEnum::Enum VolumeSliceViewAllPlanesLayoutEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = VolumeSliceViewAllPlanesLayoutEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const VolumeSliceViewAllPlanesLayoutEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type VolumeSliceViewAllPlanesLayoutEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t VolumeSliceViewAllPlanesLayoutEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const VolumeSliceViewAllPlanesLayoutEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ VolumeSliceViewAllPlanesLayoutEnum::Enum VolumeSliceViewAllPlanesLayoutEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = VolumeSliceViewAllPlanesLayoutEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const VolumeSliceViewAllPlanesLayoutEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type VolumeSliceViewAllPlanesLayoutEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void VolumeSliceViewAllPlanesLayoutEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void VolumeSliceViewAllPlanesLayoutEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(VolumeSliceViewAllPlanesLayoutEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void VolumeSliceViewAllPlanesLayoutEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(VolumeSliceViewAllPlanesLayoutEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/VolumeSliceViewAllPlanesLayoutEnum.h000066400000000000000000000064501360521144700267310ustar00rootroot00000000000000#ifndef __VOLUME_SLICE_VIEW_ALL_PLANES_LAYOUT_ENUM_H__ #define __VOLUME_SLICE_VIEW_ALL_PLANES_LAYOUT_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class VolumeSliceViewAllPlanesLayoutEnum { public: /** * Enumerated values. */ enum Enum { /** */ GRID_LAYOUT, /** */ COLUMN_LAYOUT, /** */ ROW_LAYOUT }; ~VolumeSliceViewAllPlanesLayoutEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: VolumeSliceViewAllPlanesLayoutEnum(const Enum enumValue, const AString& name, const AString& guiName); static const VolumeSliceViewAllPlanesLayoutEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __VOLUME_SLICE_VIEW_ALL_PLANES_LAYOUT_ENUM_DECLARE__ std::vector VolumeSliceViewAllPlanesLayoutEnum::enumData; bool VolumeSliceViewAllPlanesLayoutEnum::initializedFlag = false; int32_t VolumeSliceViewAllPlanesLayoutEnum::integerCodeCounter = 0; #endif // __VOLUME_SLICE_VIEW_ALL_PLANES_LAYOUT_ENUM_DECLARE__ } // namespace #endif //__VOLUME_SLICE_VIEW_ALL_PLANES_LAYOUT_ENUM_H__ connectome-workbench-1.4.2/src/Common/VoxelIJK.h000066400000000000000000000040351360521144700214600ustar00rootroot00000000000000#ifndef __VOXEL_IJK_H__ #define __VOXEL_IJK_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "stdint.h" namespace caret { struct VoxelIJK { int64_t m_ijk[3]; VoxelIJK() { } VoxelIJK(int64_t i, int64_t j, int64_t k) { m_ijk[0] = i; m_ijk[1] = j; m_ijk[2] = k; } template VoxelIJK(const T ijk[3]) { m_ijk[0] = ijk[0]; m_ijk[1] = ijk[1]; m_ijk[2] = ijk[2]; } bool operator<(const VoxelIJK& rhs) const//so it can be the key of a map { if (m_ijk[2] < rhs.m_ijk[2]) return true;//compare such that when sorted, m_ijk[0] moves fastest if (m_ijk[2] > rhs.m_ijk[2]) return false; if (m_ijk[1] < rhs.m_ijk[1]) return true; if (m_ijk[1] > rhs.m_ijk[1]) return false; return (m_ijk[0] < rhs.m_ijk[0]); } bool operator==(const VoxelIJK& rhs) const { return (m_ijk[0] == rhs.m_ijk[0] && m_ijk[1] == rhs.m_ijk[1] && m_ijk[2] == rhs.m_ijk[2]); } bool operator!=(const VoxelIJK& rhs) const { return !((*this) == rhs); } inline operator int64_t*() { return m_ijk; } }; } #endif //__VOXEL_IJK_H__ connectome-workbench-1.4.2/src/Common/WorkbenchSpecialVersionEnum.cxx000066400000000000000000000257121360521144700260230ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __WORKBENCH_SPECIAL_VERSION_ENUM_DECLARE__ #include "WorkbenchSpecialVersionEnum.h" #undef __WORKBENCH_SPECIAL_VERSION_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::WorkbenchSpecialVersionEnum * \brief Identifies versions of Workbench with special functionality. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_workbenchSpecialVersionEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void workbenchSpecialVersionEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "WorkbenchSpecialVersionEnum.h" * * Instatiate: * m_workbenchSpecialVersionEnumComboBox = new EnumComboBoxTemplate(this); * m_workbenchSpecialVersionEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_workbenchSpecialVersionEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(workbenchSpecialVersionEnumComboBoxItemActivated())); * * Update the selection: * m_workbenchSpecialVersionEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const WorkbenchSpecialVersionEnum::Enum VARIABLE = m_workbenchSpecialVersionEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ WorkbenchSpecialVersionEnum::WorkbenchSpecialVersionEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ WorkbenchSpecialVersionEnum::~WorkbenchSpecialVersionEnum() { } /** * Initialize the enumerated metadata. */ void WorkbenchSpecialVersionEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(WorkbenchSpecialVersionEnum(WORKBENCH_SPECIAL_VERSION_NO, "WORKBENCH_SPECIAL_VERSION_NO", "Workbench Special Version No")); enumData.push_back(WorkbenchSpecialVersionEnum(WORKBENCH_SPECIAL_VERSION_FIRST_CHARTING, "WORKBENCH_SPECIAL_VERSION_FIRST_CHARTING", "Old Charting")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const WorkbenchSpecialVersionEnum* WorkbenchSpecialVersionEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const WorkbenchSpecialVersionEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WorkbenchSpecialVersionEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const WorkbenchSpecialVersionEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WorkbenchSpecialVersionEnum::Enum WorkbenchSpecialVersionEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WorkbenchSpecialVersionEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WorkbenchSpecialVersionEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WorkbenchSpecialVersionEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WorkbenchSpecialVersionEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const WorkbenchSpecialVersionEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WorkbenchSpecialVersionEnum::Enum WorkbenchSpecialVersionEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WorkbenchSpecialVersionEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WorkbenchSpecialVersionEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WorkbenchSpecialVersionEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t WorkbenchSpecialVersionEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const WorkbenchSpecialVersionEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ WorkbenchSpecialVersionEnum::Enum WorkbenchSpecialVersionEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WorkbenchSpecialVersionEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WorkbenchSpecialVersionEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WorkbenchSpecialVersionEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void WorkbenchSpecialVersionEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WorkbenchSpecialVersionEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(WorkbenchSpecialVersionEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WorkbenchSpecialVersionEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(WorkbenchSpecialVersionEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/WorkbenchSpecialVersionEnum.h000066400000000000000000000063671360521144700254550ustar00rootroot00000000000000#ifndef __WORKBENCH_SPECIAL_VERSION_ENUM_H__ #define __WORKBENCH_SPECIAL_VERSION_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class WorkbenchSpecialVersionEnum { public: /** * Enumerated values. */ enum Enum { /** Not a special version */ WORKBENCH_SPECIAL_VERSION_NO, /** First Implementation of Charting */ WORKBENCH_SPECIAL_VERSION_FIRST_CHARTING }; ~WorkbenchSpecialVersionEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: WorkbenchSpecialVersionEnum(const Enum enumValue, const AString& name, const AString& guiName); static const WorkbenchSpecialVersionEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __WORKBENCH_SPECIAL_VERSION_ENUM_DECLARE__ std::vector WorkbenchSpecialVersionEnum::enumData; bool WorkbenchSpecialVersionEnum::initializedFlag = false; int32_t WorkbenchSpecialVersionEnum::integerCodeCounter = 0; #endif // __WORKBENCH_SPECIAL_VERSION_ENUM_DECLARE__ } // namespace #endif //__WORKBENCH_SPECIAL_VERSION_ENUM_H__ connectome-workbench-1.4.2/src/Common/WuQMacro.cxx000066400000000000000000000262601360521144700221020ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_DECLARE__ #include "WuQMacro.h" #undef __WU_Q_MACRO_DECLARE__ #include #include "CaretAssert.h" #include "WuQMacroCommand.h" #include "WuQMacroMouseEventInfo.h" #include "WuQMacroStandardItemTypeEnum.h" using namespace caret; /** * \class caret::WuQMacro * \brief Contains a sequence of WuQMacroCommand's * \ingroup WuQMacro * * Subclasses QStandardItem so that instance can be in a tree widget */ /** * Constructor. */ WuQMacro::WuQMacro() : QStandardItem(), TracksModificationInterface() { setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); m_uniqueIdentifier = QUuid::createUuid().toString(); } /** * Destructor. */ WuQMacro::~WuQMacro() { clearCommands(); } /** * Clear (remove) all commands in this macro */ void WuQMacro::clearCommands() { const int32_t numItems = rowCount(); removeRows(0, numItems); CaretAssert(rowCount() == 0); } /** * Copy constructor. * @param obj * Object that is copied. */ WuQMacro::WuQMacro(const WuQMacro& obj) : QStandardItem(obj), TracksModificationInterface() { setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); m_uniqueIdentifier = QUuid::createUuid().toString(); this->copyHelperWuQMacro(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ WuQMacro& WuQMacro::operator=(const WuQMacro& obj) { if (this != &obj) { QStandardItem::operator=(obj); this->copyHelperWuQMacro(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void WuQMacro::copyHelperWuQMacro(const WuQMacro& obj) { /* Note: unique identifier is NOT copied */ clearCommands(); const int32_t numRows = obj.rowCount(); for (int32_t i = 0; i < numRows; i++) { const QStandardItem* item = obj.child(i); CaretAssert(item); const WuQMacroCommand* command = dynamic_cast(item); CaretAssert(command); WuQMacroCommand* commandCopy = new WuQMacroCommand(*command); CaretAssert(commandCopy); appendMacroCommand(commandCopy); } setText(obj.text()); m_description = obj.m_description; m_shortCutKey = obj.m_shortCutKey; } /** * @return The type of this item for Qt */ int WuQMacro::type() const { /* * This must be different than the type returned by of macro * subclasses of QStandardItem */ return WuQMacroStandardItemTypeEnum::toIntegerCode(WuQMacroStandardItemTypeEnum::MACRO); } /** * Append a macro command to this macro * * @param macroCommand * The macro command. */ void WuQMacro::appendMacroCommand(WuQMacroCommand* macroCommand) { CaretAssert(macroCommand); const int32_t numCommands = getNumberOfMacroCommands(); if (numCommands > 0) { WuQMacroCommand* lastCommand = getMacroCommandAtIndex(numCommands - 1); /* * 'Compact' macro commands for mouse events */ if (lastCommand->isMouseEventMatch(macroCommand)) { WuQMacroMouseEventInfo* lastMouseInfo = lastCommand->getMouseEventInfo(); CaretAssert(lastMouseInfo); const WuQMacroMouseEventInfo* mouseInfo = macroCommand->getMouseEventInfo(); CaretAssert(mouseInfo); const int32_t numXY = mouseInfo->getNumberOfLocalXY(); for (int32_t i = 0; i < numXY; i++) { lastMouseInfo->addLocalXY(mouseInfo->getLocalX(i), mouseInfo->getLocalY(i)); } /* * No longer needed since mouse x/y appended to last command */ delete macroCommand; macroCommand = NULL; } } if (macroCommand != NULL) { appendRow(macroCommand); } setModified(); } /** * Insert the given macro command at the given index * * @param index * Index of where to insert the macro command * @param macroCommand * Macro command to insert. */ void WuQMacro::insertMacroCommandAtIndex(const int32_t index, WuQMacroCommand* macroCommand) { CaretAssert((index >= 0) && (index <= getNumberOfMacroCommands())); CaretAssert(macroCommand); insertRow(index, macroCommand); setModified(); } /** * @return The unique identifier */ QString WuQMacro::getUniqueIdentifier() const { return m_uniqueIdentifier; } /** * Set unique identifier of macro * * @param uniqueIdentifier * New unique identifier */void WuQMacro::setUniqueIdentifier(const QString& uniqueIdentifier) { if (uniqueIdentifier.isEmpty()) { return; } if (m_uniqueIdentifier != uniqueIdentifier) { m_uniqueIdentifier = uniqueIdentifier; setModified(); } } /** * @return Name of macro */ QString WuQMacro::getName() const { return text(); } /** * Set name of macro * * @param name * New name */ void WuQMacro::setName(const QString& name) { if (name != text()) { setText(name); setModified(); } } /** * @return Description of macro */ QString WuQMacro::getDescription() const { return m_description; } /** * Set description of macro * * @param description * New description */ void WuQMacro::setDescription(const QString& description) { if (m_description != description) { m_description = description; setModified(); } } /** * @return The short cut key */ WuQMacroShortCutKeyEnum::Enum WuQMacro::getShortCutKey() const { return m_shortCutKey; } /** * Set the short cut key * * @param shortCutKey * New short cut key */ void WuQMacro::setShortCutKey(const WuQMacroShortCutKeyEnum::Enum shortCutKey) { if (m_shortCutKey != shortCutKey) { m_shortCutKey = shortCutKey; setModified(); } } /** * @return The number of macro commands in this macro */ int32_t WuQMacro::getNumberOfMacroCommands() const { return rowCount(); } /** * @return * The macro command at the given index * @param index * Index of the macro command */ const WuQMacroCommand* WuQMacro::getMacroCommandAtIndex(const int32_t index) const { CaretAssert((index >= 0) && (index < rowCount())); QStandardItem* item = child(index); CaretAssert(item); WuQMacroCommand* command = dynamic_cast(item); CaretAssert(command); return command; } /** * @return * The macro command at the given index * @param index * Index of the macro command */ WuQMacroCommand* WuQMacro::getMacroCommandAtIndex(const int32_t index) { CaretAssert((index >= 0) && (index < rowCount())); QStandardItem* item = child(index); CaretAssert(item); WuQMacroCommand* command = dynamic_cast(item); CaretAssert(command); return command; } /** * @return * Index of the given macro command * @param macroCommand * The macro command */ int32_t WuQMacro::getIndexOfMacroCommand(const WuQMacroCommand* macroCommand) const { CaretAssert(macroCommand); const int32_t num = getNumberOfMacroCommands(); for (int32_t i = 0; i < num; i++) { if (getMacroCommandAtIndex(i) == macroCommand) { return i; break; } } return -1; } /** * Delete macro command at the given index * * @param index * Index of macro command */ void WuQMacro::deleteMacroCommandAtIndex(const int32_t index) { CaretAssert((index >= 0) && (index < getNumberOfMacroCommands())); removeRow(index); setModified(); } /** * Delete the given macro command * @param macroCommand */ void WuQMacro::deleteMacroCommand(WuQMacroCommand* macroCommand) { const int32_t index = getIndexOfMacroCommand(macroCommand); if (index >= 0) { deleteMacroCommandAtIndex(index); } } /** * Move the given macro command down one position * * @param macroCommand */ void WuQMacro::moveMacroCommandDown(WuQMacroCommand* macroCommand) { const int32_t index = getIndexOfMacroCommand(macroCommand); if ((index >= 0) && (index < getNumberOfMacroCommands() - 1)) { /* Note that take child removes item but does not remove row */ QStandardItem* item = takeChild(index); removeRow(index); CaretAssert(item); insertMacroCommandAtIndex(index + 1, dynamic_cast(item)); } } /** * Move the given macro command up one position * * @param macroCommand */ void WuQMacro::moveMacroCommandUp(WuQMacroCommand* macroCommand) { const int32_t index = getIndexOfMacroCommand(macroCommand); if ((index > 0) && (index < getNumberOfMacroCommands())) { /* Note that take child removes item but does not remove row */ QStandardItem* item = takeChild(index); removeRow(index); CaretAssert(item); insertMacroCommandAtIndex(index - 1, dynamic_cast(item)); } } /** * @return True if this instance is modified */ bool WuQMacro::isModified() const { if (m_modifiedStatusFlag) { return true; } const int32_t numItems = getNumberOfMacroCommands(); for (int32_t i = 0; i < numItems; i++) { if (getMacroCommandAtIndex(i)->isModified()) { return true; } } return false; } /** * Clear the modified status */ void WuQMacro::clearModified() { m_modifiedStatusFlag = false; const int32_t numItems = getNumberOfMacroCommands(); for (int32_t i = 0; i < numItems; i++) { getMacroCommandAtIndex(i)->clearModified(); } } /** * Set the modification status to modified */ void WuQMacro::setModified() { m_modifiedStatusFlag = true; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString WuQMacro::toString() const { QString s("WuQMacro\n"); s.append("Name=" + text() + "\n"); s.append("Description=" + m_description + "\n"); s.append("ShortCutKey=" + WuQMacroShortCutKeyEnum::toGuiName(m_shortCutKey) + "\n"); s.append("UUID=" + m_uniqueIdentifier + "\n"); const int32_t numItems = getNumberOfMacroCommands(); for (int32_t i = 0; i < numItems; i++) { s.append(getMacroCommandAtIndex(i)->toString()); } return s; } connectome-workbench-1.4.2/src/Common/WuQMacro.h000066400000000000000000000066761360521144700215400ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_H__ #define __WU_Q_MACRO_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "TracksModificationInterface.h" #include "WuQMacroShortCutKeyEnum.h" namespace caret { class WuQMacroCommand; class WuQMacro : public QStandardItem, public TracksModificationInterface { public: WuQMacro(); virtual ~WuQMacro(); WuQMacro(const WuQMacro& obj); WuQMacro& operator=(const WuQMacro& obj); void appendMacroCommand(WuQMacroCommand* macroCommand); void insertMacroCommandAtIndex(const int32_t index, WuQMacroCommand* macroCommand); int32_t getNumberOfMacroCommands() const; const WuQMacroCommand* getMacroCommandAtIndex(const int32_t index) const; WuQMacroCommand* getMacroCommandAtIndex(const int32_t index); int32_t getIndexOfMacroCommand(const WuQMacroCommand* macroCommand) const; void deleteMacroCommandAtIndex(const int32_t index); void deleteMacroCommand(WuQMacroCommand* macroCommand); void moveMacroCommandDown(WuQMacroCommand* macroCommand); void moveMacroCommandUp(WuQMacroCommand* macroCommand); QString getUniqueIdentifier() const; void setUniqueIdentifier(const QString& uniqueIdentifier); QString getName() const; void setName(const QString& name); QString getDescription() const; void setDescription(const QString& description); WuQMacroShortCutKeyEnum::Enum getShortCutKey() const; void setShortCutKey(const WuQMacroShortCutKeyEnum::Enum shortCutKey); virtual AString toString() const; virtual bool isModified() const override; virtual void clearModified() override; virtual void setModified() override; virtual int type() const override; // ADD_NEW_METHODS_HERE private: void copyHelperWuQMacro(const WuQMacro& obj); void clearCommands(); QString m_uniqueIdentifier; QString m_description; WuQMacroShortCutKeyEnum::Enum m_shortCutKey = WuQMacroShortCutKeyEnum::Key_None; bool m_modifiedStatusFlag = false; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_MACRO_DECLARE__ // #endif // __WU_Q_MACRO_DECLARE__ } // namespace #endif //__WU_Q_MACRO_H__ connectome-workbench-1.4.2/src/Common/WuQMacroCommand.cxx000066400000000000000000000577711360521144700234140ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_COMMAND_DECLARE__ #include "WuQMacroCommand.h" #undef __WU_Q_MACRO_COMMAND_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "WuQMacroCommandParameter.h" #include "WuQMacroMouseEventInfo.h" #include "WuQMacroStandardItemTypeEnum.h" using namespace caret; /** * \class caret::WuQMacroCommand * \brief Issues a QObject's signal so that its slots execute * \ingroup WuQMacro */ /** * Create a new instance of a macro comand for a custom command * * @param commandType * Type of command * @param customOperationTypeName * Name of a custom operation * @param mouseEventInfo * Information about mouse event. * @param widgetType * Type of widget * @param version * Version of command * @param objectName * Name of object * @param objectDescriptiveName * Descriptive name of macro command * @param objectToolTip * ToolTip for object * @param delayInSeconds * Delay in seconds * @param errorMessageOut * Output with error messag if new instance fails * @return * The widget command or NULL if failure */ WuQMacroCommand* WuQMacroCommand::newInstanceCustomCommand(const QString& customOperationName, const int32_t version, const QString& objectName, const QString& objectDescriptiveName, const QString& objectToolTip, const float delayInSeconds, QString& errorMessageOut) { errorMessageOut.clear(); if (customOperationName.isEmpty()) { errorMessageOut = "Custom operation may not be empty for a custom operation macro command"; return NULL; } WuQMacroMouseEventInfo* mouseEventInfo(NULL); WuQMacroCommand* mc = new WuQMacroCommand(WuQMacroCommandTypeEnum::CUSTOM_OPERATION, customOperationName, mouseEventInfo, WuQMacroWidgetTypeEnum::INVALID, version, objectName, objectDescriptiveName, objectToolTip, delayInSeconds); return mc; } /** * Create a new instance of a macro command for mouse operation * * @param commandType * Type of command * @param customOperationTypeName * Name of a custom operation * @param mouseEventInfo * Information about mouse event (will take ownership) * @param widgetType * Type of widget * @param version * Version of command * @param objectName * Name of object * @param objectDescriptiveName * Descriptive name of macro command * @param objectToolTip * ToolTip for object * @param delayInSeconds * Delay in seconds * @param errorMessageOut * Output with error messag if new instance fails * @return * The widget command or NULL if failure */ WuQMacroCommand* WuQMacroCommand::newInstanceMouseCommand(WuQMacroMouseEventInfo* mouseEventInfo, const int32_t version, const QString& objectName, const QString& objectDescriptiveName, const QString& objectToolTip, const float delayInSeconds, QString& errorMessageOut) { errorMessageOut.clear(); if (mouseEventInfo == NULL) { errorMessageOut = "Mouse info is invalid (NULL) for a macro mouse command"; return NULL; } const QString customOperationName(""); WuQMacroCommand* mc = new WuQMacroCommand(WuQMacroCommandTypeEnum::MOUSE, customOperationName, mouseEventInfo, WuQMacroWidgetTypeEnum::INVALID, version, objectName, objectDescriptiveName, objectToolTip, delayInSeconds); return mc; } /** * Create a new instance of a macro command for a Qt Widget * * @param commandType * Type of command * @param customOperationTypeName * Name of a custom operation * @param mouseEventInfo * Information about mouse event. * @param widgetType * Type of widget * @param version * Version of command * @param objectName * Name of object * @param objectDescriptiveName * Descriptive name of macro command * @param objectToolTip * ToolTip for object * @param delayInSeconds * Delay in seconds * @param errorMessageOut * Output with error messag if new instance fails * @return * The widget command or NULL if failure */ WuQMacroCommand* WuQMacroCommand::newInstanceWidgetCommand(const WuQMacroWidgetTypeEnum::Enum widgetType, const int32_t version, const QString& objectName, const QString& objectDescriptiveName, const QString& objectToolTip, const float delayInSeconds, QString& errorMessageOut) { errorMessageOut.clear(); if (widgetType == WuQMacroWidgetTypeEnum::INVALID) { errorMessageOut = "Widget type is invalid for Widget Macro Command"; return NULL; } const QString customOperationName(""); WuQMacroMouseEventInfo* mouseEventInfo(NULL); WuQMacroCommand* mc = new WuQMacroCommand(WuQMacroCommandTypeEnum::WIDGET, customOperationName, mouseEventInfo, widgetType, version, objectName, objectDescriptiveName, objectToolTip, delayInSeconds); return mc; } /** * Constructor for a macro command * * @param commandType * Type of command * @param customOperationTypeName * Name of a custom operation * @param mouseEventInfo * Information about mouse event. * @param widgetType * Type of widget * @param version * Version of command * @param objectName * Name of object * @param objectDescriptiveName * Descriptive name of macro command * @param objectToolTip * ToolTip for object * @param delayInSeconds * Delay in seconds */ WuQMacroCommand::WuQMacroCommand(const WuQMacroCommandTypeEnum::Enum commandType, const QString& customOperationTypeName, WuQMacroMouseEventInfo* mouseEventInfo, const WuQMacroWidgetTypeEnum::Enum widgetType, const int32_t version, const QString& objectName, const QString& objectDescriptiveName, const QString& objectToolTip, const float delayInSeconds) : QStandardItem(), TracksModificationInterface(), m_commandType(commandType), m_customOperationTypeName(customOperationTypeName), m_macroMouseEvent(mouseEventInfo), m_widgetType(widgetType), m_version(version), m_objectName(objectName), m_descriptiveName(objectDescriptiveName), m_delayInSeconds(delayInSeconds) { if (objectDescriptiveName.isEmpty()) { CaretLogWarning("Empty descriptive name for " + objectName); } switch (m_commandType) { case WuQMacroCommandTypeEnum::CUSTOM_OPERATION: break; case WuQMacroCommandTypeEnum::MOUSE: CaretAssert(m_macroMouseEvent); setText("Mouse"); break; case WuQMacroCommandTypeEnum::WIDGET: break; } setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); setToolTip(objectToolTip); updateTitle(); setModified(); } /** * Destructor. */ WuQMacroCommand::~WuQMacroCommand() { if (m_macroMouseEvent != NULL) { delete m_macroMouseEvent; } removeAllParameters(); } /** * Copy constructor. * @param obj * Object that is copied. */ WuQMacroCommand::WuQMacroCommand(const WuQMacroCommand& obj) : QStandardItem(obj), TracksModificationInterface() { setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); this->copyHelperWuQMacroCommand(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ WuQMacroCommand& WuQMacroCommand::operator=(const WuQMacroCommand& obj) { if (this != &obj) { QStandardItem::operator=(obj); this->copyHelperWuQMacroCommand(obj); } return *this; } /** * @return The type of this item for Qt */ int WuQMacroCommand::type() const { /* * This must be different than the type returned by of macro * subclasses of QStandardItem */ return WuQMacroStandardItemTypeEnum::toIntegerCode(WuQMacroStandardItemTypeEnum::MACRO_COMMAND); } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void WuQMacroCommand::copyHelperWuQMacroCommand(const WuQMacroCommand& obj) { m_commandType = obj.m_commandType; m_customOperationTypeName = obj.m_customOperationTypeName; if (m_macroMouseEvent != NULL) { m_macroMouseEvent = NULL; } if (obj.m_macroMouseEvent != NULL) { m_macroMouseEvent = new WuQMacroMouseEventInfo(*obj.m_macroMouseEvent); } m_widgetType = obj.m_widgetType; m_version = obj.m_version; m_objectName = obj.m_objectName; m_descriptiveName = obj.m_descriptiveName; m_delayInSeconds = obj.m_delayInSeconds; removeAllParameters(); for (const auto p : obj.m_parameters) { m_parameters.push_back(new WuQMacroCommandParameter(*p)); } setText(obj.text()); updateTitle(); setModified(); } /** * Update the title for this command */ void WuQMacroCommand::updateTitle() { QString title = "Unknown"; QVariant dataValue; if (getNumberOfParameters() > 0) { CaretAssertVectorIndex(m_parameters, 0); dataValue = m_parameters[0]->getValue(); } QVariant dataValueTwo; if (getNumberOfParameters() > 1) { CaretAssertVectorIndex(m_parameters, 1); dataValueTwo = m_parameters[1]->getValue(); } switch (m_widgetType) { case WuQMacroWidgetTypeEnum::ACTION: title = ("Turn " + QString((dataValue.toBool() ? "On" : "Off"))); break; case WuQMacroWidgetTypeEnum::ACTION_CHECKABLE: title = ("Turn " + QString((dataValue.toBool() ? "On" : "Off"))); break; case WuQMacroWidgetTypeEnum::ACTION_GROUP: title = ("Select Name " + dataValue.toString() + " else " + " index " + QString::number(dataValueTwo.toInt())); break; case WuQMacroWidgetTypeEnum::BUTTON_GROUP: title = ("Select Name " + dataValue.toString() + " else " + " index " + QString::number(dataValueTwo.toInt())); break; case WuQMacroWidgetTypeEnum::CHECK_BOX: title = ("Turn " + QString((dataValue.toBool() ? "On" : "Off"))); break; case WuQMacroWidgetTypeEnum::COMBO_BOX: title = ("Select Name " + dataValue.toString() + " else " + " index " + QString::number(dataValueTwo.toInt())); break; case WuQMacroWidgetTypeEnum::DOUBLE_SPIN_BOX: title = ("Set to value " + QString::number(dataValue.toFloat())); break; case WuQMacroWidgetTypeEnum::INVALID: break; case WuQMacroWidgetTypeEnum::LINE_EDIT: title = ("Set to text " + dataValue.toString()); break; case WuQMacroWidgetTypeEnum::LIST_WIDGET: title = ("Select Name " + dataValue.toString() + " else " + " index " + QString::number(dataValueTwo.toInt())); break; case WuQMacroWidgetTypeEnum::MACRO_WIDGET_ACTION: title = "Set value"; break; case WuQMacroWidgetTypeEnum::MENU: title = ("Select Name " + dataValue.toString() + " else " + " index " + QString::number(dataValueTwo.toInt())); break; case WuQMacroWidgetTypeEnum::PUSH_BUTTON: title = ("Click Button"); break; case WuQMacroWidgetTypeEnum::PUSH_BUTTON_CHECKABLE: title = ("Turn " + QString((dataValue.toBool() ? "On" : "Off"))); break; case WuQMacroWidgetTypeEnum::RADIO_BUTTON: title = "Click Button"; break; case WuQMacroWidgetTypeEnum::SLIDER: title = ("Move to " + AString::number(dataValue.toInt())); break; case WuQMacroWidgetTypeEnum::SPIN_BOX: title = ("Set to " + AString::number(dataValue.toInt())); break; case WuQMacroWidgetTypeEnum::TAB_BAR: title = ("Select Name " + dataValue.toString() + " else " + " index " + QString::number(dataValueTwo.toInt())); break; case WuQMacroWidgetTypeEnum::TAB_WIDGET: title = ("Select Name " + dataValue.toString() + " else " + " index " + QString::number(dataValueTwo.toInt())); break; case WuQMacroWidgetTypeEnum::TOOL_BUTTON: title = ("Click Button"); break; case WuQMacroWidgetTypeEnum::TOOL_BUTTON_CHECKABLE: title = ("Turn " + QString((dataValue.toBool() ? "On" : "Off"))); break; } if ( ! m_descriptiveName.isEmpty()) { setText(m_descriptiveName); } else { setText(title + " " + m_objectName); } } /** * @return The command type */ WuQMacroCommandTypeEnum::Enum WuQMacroCommand::getCommandType() const { return m_commandType; } /** * @return The command's widget type */ WuQMacroWidgetTypeEnum::Enum WuQMacroCommand::getWidgetType() const { return m_widgetType; } /** * @return Version of the command */ int32_t WuQMacroCommand::getVersion() const { return m_version; } /** * Add a parameter to the macro command * * @param dataType * Data type of the parameter * @param name * Name of the parameter * @param value * Value of the parameter */ void WuQMacroCommand::addParameter(const WuQMacroDataValueTypeEnum::Enum dataType, const QString& name, const QVariant& value) { WuQMacroCommandParameter* parameter = new WuQMacroCommandParameter(dataType, name, value); addParameter(parameter); } /** * Add a parameter to the macro command * * @param parameter * Parameter to add */ void WuQMacroCommand::addParameter(WuQMacroCommandParameter* parameter) { CaretAssert(parameter); if (parameter == NULL) { return; } m_parameters.push_back(parameter); setModified(); } /** * @return The number of parameters */ int32_t WuQMacroCommand::getNumberOfParameters() const { return m_parameters.size(); } /** * @return Parameter at the given index * * @param index * Index of the parameter. */ WuQMacroCommandParameter* WuQMacroCommand::getParameterAtIndex(const int32_t index) { CaretAssertVectorIndex(m_parameters, index); return m_parameters[index]; } /** * @return Parameter at the given index (const method) * * @param index * Index of the parameter. */ const WuQMacroCommandParameter* WuQMacroCommand::getParameterAtIndex(const int32_t index) const { CaretAssertVectorIndex(m_parameters, index); return m_parameters[index]; } /** * Get the index of the given parameter in this macro * * @param parameter * Paramater for which index is requested * @return * Index of parameter or -1 If not found */ int32_t WuQMacroCommand::getIndexOfParameter(const WuQMacroCommandParameter* parameter) const { CaretAssert(parameter); const int32_t numParams = getNumberOfParameters(); for (int32_t i = 0; i < numParams; i++) { CaretAssertVectorIndex(m_parameters, i); if (m_parameters[i] == parameter) { return i; } } return -1; } /** * Remove all parameters in this command */ void WuQMacroCommand::removeAllParameters() { for (auto p : m_parameters) { delete p; } m_parameters.clear(); } /** * @return The object's name */ QString WuQMacroCommand::getObjectName() const { return m_objectName; } /** * @return The object's descriptive name */ QString WuQMacroCommand::getDescriptiveName() const { return m_descriptiveName; } /** * @return ToolTip for the object */ QString WuQMacroCommand::getObjectToolTip() const { return toolTip(); } /** * Set the object's tooltip * * @param objectToolTip * New value for object tooltip */ void WuQMacroCommand::setObjectToolTip(const QString& objectToolTip) { if (toolTip() != objectToolTip) { setToolTip(objectToolTip); setModified(); } } /** * @return Point to mouse event information */ const WuQMacroMouseEventInfo* WuQMacroCommand::getMouseEventInfo() const { return m_macroMouseEvent; } /** * @return Point to mouse event information */ WuQMacroMouseEventInfo* WuQMacroCommand::getMouseEventInfo() { return m_macroMouseEvent; } /** * Set the mouse event info * * @param mouseEventInfo * The new mouse event info */ void WuQMacroCommand::setMouseEventInfo(WuQMacroMouseEventInfo* mouseEventInfo) { if (m_macroMouseEvent != NULL) { delete m_macroMouseEvent; m_macroMouseEvent = NULL; } m_macroMouseEvent = mouseEventInfo; if (m_macroMouseEvent != NULL) { QString title; switch (m_macroMouseEvent->getMouseEventType()) { case WuQMacroMouseEventTypeEnum::BUTTON_PRESS: title = "Mouse Press "; break; case WuQMacroMouseEventTypeEnum::BUTTON_RELEASE: title = "Mouse Release "; break; case WuQMacroMouseEventTypeEnum::DOUBLE_CLICKED: title = "Mouse Double Click "; break; case WuQMacroMouseEventTypeEnum::MOVE: title = "Mouse Move "; break; } title.append(m_objectName); setText(title); } } /** * @return True if this command the same mouse event type as the given command. * Must be mouse move events only. * * @param command * The other command */ bool WuQMacroCommand::isMouseEventMatch(const WuQMacroCommand* command) const { if (command->getCommandType() == WuQMacroCommandTypeEnum::MOUSE) { if (getCommandType() == WuQMacroCommandTypeEnum::MOUSE) { const WuQMacroMouseEventInfo* myMouse = getMouseEventInfo(); CaretAssert(myMouse); const WuQMacroMouseEventInfo* otherMouse = command->getMouseEventInfo(); CaretAssert(otherMouse); if ((myMouse->getMouseEventType() == WuQMacroMouseEventTypeEnum::MOVE) && (myMouse->getMouseEventType() == WuQMacroMouseEventTypeEnum::MOVE)) { if ((myMouse->getMouseButton() == otherMouse->getMouseButton()) && (myMouse->getMouseButtonsMask() == otherMouse->getMouseButtonsMask()) && (myMouse->getKeyboardModifiersMask() == otherMouse->getKeyboardModifiersMask()) && (myMouse->getWidgetWidth() == otherMouse->getWidgetWidth()) && (myMouse->getWidgetHeight() == otherMouse->getWidgetHeight())) { return true; } } } } return false; } /** * @return Delay in seconds */ float WuQMacroCommand::getDelayInSeconds() const { return m_delayInSeconds; } /** * Set delay in seconds * * @param seconds * New delay value */ void WuQMacroCommand::setDelayInSeconds(const float seconds) { if (seconds != m_delayInSeconds) { m_delayInSeconds = seconds; setModified(); } } /** * @return The custom operation command type name * Used when class type is WuQMacroWidgetTypeEnum::CUSTOM_OPERATION */ QString WuQMacroCommand::getCustomOperationTypeName() const { return m_customOperationTypeName; } /** * Set the custom operation command type name * Used when class type is WuQMacroWidgetTypeEnum::CUSTOM_OPERATION * * @param customOperationCommandTypeName * New value */ void WuQMacroCommand::setCustomOperationTypeName(const QString& customOperationTypeName) { if (m_customOperationTypeName != customOperationTypeName) { m_customOperationTypeName = customOperationTypeName; setModified(); } } /** * @return True if this instance is modified */ bool WuQMacroCommand::isModified() const { if (m_modifiedStatusFlag) { return true; } for (const auto p : m_parameters) { if (p->isModified()) { return true; } } return false; } /** * Clear the modified status */ void WuQMacroCommand::clearModified() { m_modifiedStatusFlag = false; for (auto p : m_parameters) { p->clearModified(); } } /** * Set the modification status to modified */ void WuQMacroCommand::setModified() { m_modifiedStatusFlag = true; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString WuQMacroCommand::toString() const { QString s("WuQMacroCommand text=%1 name=%2, commandType=%3, widgetType=%4"); s = s.arg(text() ).arg(m_objectName ).arg(WuQMacroCommandTypeEnum::toName(m_commandType) ).arg(WuQMacroWidgetTypeEnum::toName(m_widgetType)); for (const auto p : m_parameters) { s.append(", value=" + p->getValue().toString()); } return s; } connectome-workbench-1.4.2/src/Common/WuQMacroCommand.h000066400000000000000000000150221360521144700230200ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_COMMAND_H__ #define __WU_Q_MACRO_COMMAND_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "TracksModificationInterface.h" #include "WuQMacroCommandTypeEnum.h" #include "WuQMacroDataValueTypeEnum.h" #include "WuQMacroWidgetTypeEnum.h" class QObject; namespace caret { class WuQMacroCommandParameter; class WuQMacroMouseEventInfo; class WuQMacroCommand : public QStandardItem, public TracksModificationInterface { public: static WuQMacroCommand* newInstanceCustomCommand(const QString& customOperationName, const int32_t version, const QString& objectName, const QString& objectDescriptiveName, const QString& objectToolTip, const float delay, QString& errorMessageOut); static WuQMacroCommand* newInstanceMouseCommand(WuQMacroMouseEventInfo* mouseEventInfo, const int32_t version, const QString& objectName, const QString& objectDescriptiveName, const QString& objectToolTip, const float delay, QString& errorMessageOut); static WuQMacroCommand* newInstanceWidgetCommand(const WuQMacroWidgetTypeEnum::Enum widgetType, const int32_t version, const QString& objectName, const QString& objectDescriptiveName, const QString& objectToolTip, const float delay, QString& errorMessageOut); WuQMacroCommand(const WuQMacroCommandTypeEnum::Enum commandType, const QString& customOperationTypeName, WuQMacroMouseEventInfo* mouseEventInfo, const WuQMacroWidgetTypeEnum::Enum widgetType, const int32_t version, const QString& objectName, const QString& objectDescriptiveName, const QString& objectToolTip, const float delayValue); virtual ~WuQMacroCommand(); WuQMacroCommand(const WuQMacroCommand& obj); WuQMacroCommand& operator=(const WuQMacroCommand& obj); WuQMacroCommandTypeEnum::Enum getCommandType() const; WuQMacroWidgetTypeEnum::Enum getWidgetType() const; int32_t getVersion() const; QString getObjectName() const; QString getDescriptiveName() const; QString getObjectToolTip() const; void setObjectToolTip(const QString& objectToolTip); void addParameter(WuQMacroCommandParameter* parameter); void addParameter(const WuQMacroDataValueTypeEnum::Enum dataType, const QString& name, const QVariant& value); int32_t getNumberOfParameters() const; WuQMacroCommandParameter* getParameterAtIndex(const int32_t); const WuQMacroCommandParameter* getParameterAtIndex(const int32_t) const; int32_t getIndexOfParameter(const WuQMacroCommandParameter* parameter) const; WuQMacroMouseEventInfo* getMouseEventInfo(); const WuQMacroMouseEventInfo* getMouseEventInfo() const; void setMouseEventInfo(WuQMacroMouseEventInfo* mouseEventInfo); bool isMouseEventMatch(const WuQMacroCommand* command) const; float getDelayInSeconds() const; void setDelayInSeconds(const float seconds); QString getCustomOperationTypeName() const; void setCustomOperationTypeName(const QString& customOperationTypeName); // ADD_NEW_METHODS_HERE virtual bool isModified() const override; virtual void clearModified() override; virtual void setModified() override; virtual AString toString() const; virtual int type() const override; private: void copyHelperWuQMacroCommand(const WuQMacroCommand& obj); void updateTitle(); void removeAllParameters(); WuQMacroCommandTypeEnum::Enum m_commandType; QString m_customOperationTypeName; WuQMacroMouseEventInfo* m_macroMouseEvent; WuQMacroWidgetTypeEnum::Enum m_widgetType; int32_t m_version; QString m_objectName; QString m_descriptiveName; float m_delayInSeconds = 1.0f; std::vector m_parameters; bool m_modifiedStatusFlag = false; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_MACRO_COMMAND_DECLARE__ // #endif // __WU_Q_MACRO_COMMAND_DECLARE__ } // namespace #endif //__WU_Q_MACRO_COMMAND_H__ connectome-workbench-1.4.2/src/Common/WuQMacroCommandParameter.cxx000066400000000000000000000075571360521144700252520ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_COMMAND_PARAMETER_DECLARE__ #include "WuQMacroCommandParameter.h" #undef __WU_Q_MACRO_COMMAND_PARAMETER_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::WuQMacroCommandParameter * \brief A paramater contained in a WuQMacroCommand * \ingroup Common */ /** * Constructor. */ WuQMacroCommandParameter::WuQMacroCommandParameter() : CaretObjectTracksModification() { } /** * Constructor. * * @param dataType * Data type of the parameter * @param name * Name of the parameter * @param value * Value of the parameter */ WuQMacroCommandParameter::WuQMacroCommandParameter(const WuQMacroDataValueTypeEnum::Enum dataType, const QString& name, const QVariant& value) : CaretObjectTracksModification(), m_dataType(dataType), m_name(name), m_value(value) { } /** * Destructor. */ WuQMacroCommandParameter::~WuQMacroCommandParameter() { } /** * Copy constructor. * @param obj * Object that is copied. */ WuQMacroCommandParameter::WuQMacroCommandParameter(const WuQMacroCommandParameter& obj) : CaretObjectTracksModification(obj) { this->copyHelperWuQMacroCommandParameter(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ WuQMacroCommandParameter& WuQMacroCommandParameter::operator=(const WuQMacroCommandParameter& obj) { if (this != &obj) { CaretObjectTracksModification::operator=(obj); this->copyHelperWuQMacroCommandParameter(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void WuQMacroCommandParameter::copyHelperWuQMacroCommandParameter(const WuQMacroCommandParameter& obj) { m_dataType = obj.m_dataType; m_name = obj.m_name; m_customDataType = obj.m_customDataType; m_value = obj.m_value; setModified(); } /** * @return Data type of this parameter */ WuQMacroDataValueTypeEnum::Enum WuQMacroCommandParameter::getDataType() const { return m_dataType; } /** * @return Name of this parameter */ QString WuQMacroCommandParameter::getName() const { return m_name; } /** * @return Value of this parameter */ QVariant WuQMacroCommandParameter::getValue() const { return m_value; } /** * Set the value of this parameter * * @param value * New value of parameter */ void WuQMacroCommandParameter::setValue(const QVariant& value) { if (value != m_value) { m_value = value; setModified(); } } /** * @return The custom type data type name */ QString WuQMacroCommandParameter::getCustomDataType() const { return m_customDataType; } /** * Set the custom type data type name * * @param customDataType * The custom data type */ void WuQMacroCommandParameter::setCustomDataType(const QString& customDataType) { if (m_customDataType != customDataType) { m_customDataType = customDataType; setModified(); } } connectome-workbench-1.4.2/src/Common/WuQMacroCommandParameter.h000066400000000000000000000047671360521144700246770ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_COMMAND_PARAMETER_H__ #define __WU_Q_MACRO_COMMAND_PARAMETER_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretObjectTracksModification.h" #include "WuQMacroDataValueTypeEnum.h" namespace caret { class WuQMacroCommandParameter : public CaretObjectTracksModification { public: WuQMacroCommandParameter(const WuQMacroDataValueTypeEnum::Enum dataType, const QString& name, const QVariant& value); WuQMacroCommandParameter(); virtual ~WuQMacroCommandParameter(); WuQMacroCommandParameter(const WuQMacroCommandParameter& obj); WuQMacroCommandParameter& operator=(const WuQMacroCommandParameter& obj); WuQMacroDataValueTypeEnum::Enum getDataType() const; QString getName() const; QVariant getValue() const; void setValue(const QVariant& value); QString getCustomDataType() const; void setCustomDataType(const QString& userDataType); // ADD_NEW_METHODS_HERE private: void copyHelperWuQMacroCommandParameter(const WuQMacroCommandParameter& obj); WuQMacroDataValueTypeEnum::Enum m_dataType = WuQMacroDataValueTypeEnum::INVALID; QString m_name; QString m_customDataType; QVariant m_value; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_MACRO_COMMAND_PARAMETER_DECLARE__ // #endif // __WU_Q_MACRO_COMMAND_PARAMETER_DECLARE__ } // namespace #endif //__WU_Q_MACRO_COMMAND_PARAMETER_H__ connectome-workbench-1.4.2/src/Common/WuQMacroCommandTypeEnum.cxx000066400000000000000000000253671360521144700250770ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __WU_Q_MACRO_COMMAND_TYPE_ENUM_DECLARE__ #include "WuQMacroCommandTypeEnum.h" #undef __WU_Q_MACRO_COMMAND_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::WuQMacroCommandTypeEnum * \brief Enumerated type for command type in a WuQMacroCommand * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_wuQMacroCommandTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void wuQMacroCommandTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "WuQMacroCommandTypeEnum.h" * * Instatiate: * m_wuQMacroCommandTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_wuQMacroCommandTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_wuQMacroCommandTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(wuQMacroCommandTypeEnumComboBoxItemActivated())); * * Update the selection: * m_wuQMacroCommandTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const WuQMacroCommandTypeEnum::Enum VARIABLE = m_wuQMacroCommandTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ WuQMacroCommandTypeEnum::WuQMacroCommandTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ WuQMacroCommandTypeEnum::~WuQMacroCommandTypeEnum() { } /** * Initialize the enumerated metadata. */ void WuQMacroCommandTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(WuQMacroCommandTypeEnum(CUSTOM_OPERATION, "CUSTOM_OPERATION", "CustomOperation")); enumData.push_back(WuQMacroCommandTypeEnum(MOUSE, "MOUSE", "Mouse")); enumData.push_back(WuQMacroCommandTypeEnum(WIDGET, "WIDGET", "Widget")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const WuQMacroCommandTypeEnum* WuQMacroCommandTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const WuQMacroCommandTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WuQMacroCommandTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroCommandTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WuQMacroCommandTypeEnum::Enum WuQMacroCommandTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WuQMacroCommandTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroCommandTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WuQMacroCommandTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WuQMacroCommandTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroCommandTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WuQMacroCommandTypeEnum::Enum WuQMacroCommandTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WuQMacroCommandTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroCommandTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WuQMacroCommandTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t WuQMacroCommandTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroCommandTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ WuQMacroCommandTypeEnum::Enum WuQMacroCommandTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WuQMacroCommandTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroCommandTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WuQMacroCommandTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void WuQMacroCommandTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WuQMacroCommandTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(WuQMacroCommandTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WuQMacroCommandTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(WuQMacroCommandTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/WuQMacroCommandTypeEnum.h000066400000000000000000000063001360521144700245060ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_COMMAND_TYPE_ENUM_H__ #define __WU_Q_MACRO_COMMAND_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class WuQMacroCommandTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Custom operation */ CUSTOM_OPERATION, /** Mouse Operation */ MOUSE, /** Widget or Action Signal/Slot */ WIDGET }; ~WuQMacroCommandTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: WuQMacroCommandTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const WuQMacroCommandTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __WU_Q_MACRO_COMMAND_TYPE_ENUM_DECLARE__ std::vector WuQMacroCommandTypeEnum::enumData; bool WuQMacroCommandTypeEnum::initializedFlag = false; int32_t WuQMacroCommandTypeEnum::integerCodeCounter = 0; #endif // __WU_Q_MACRO_COMMAND_TYPE_ENUM_DECLARE__ } // namespace #endif //__WU_Q_MACRO_COMMAND_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Common/WuQMacroDataValueTypeEnum.cxx000066400000000000000000000275321360521144700253630ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __WU_Q_MACRO_DATA_VALUE_TYPE_ENUM_DECLARE__ #include "WuQMacroDataValueTypeEnum.h" #undef __WU_Q_MACRO_DATA_VALUE_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::WuQMacroDataValueTypeEnum * \brief Enumerated type for macro data values * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_wuQMacroDataValueTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void wuQMacroDataValueTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "WuQMacroDataValueTypeEnum.h" * * Instatiate: * m_wuQMacroDataValueTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_wuQMacroDataValueTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_wuQMacroDataValueTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(wuQMacroDataValueTypeEnumComboBoxItemActivated())); * * Update the selection: * m_wuQMacroDataValueTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const WuQMacroDataValueTypeEnum::Enum VARIABLE = m_wuQMacroDataValueTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ WuQMacroDataValueTypeEnum::WuQMacroDataValueTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ WuQMacroDataValueTypeEnum::~WuQMacroDataValueTypeEnum() { } /** * Initialize the enumerated metadata. */ void WuQMacroDataValueTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(WuQMacroDataValueTypeEnum(INVALID, "INVALID", "Invalid")); enumData.push_back(WuQMacroDataValueTypeEnum(AXIS, "AXIS", "Axis")); enumData.push_back(WuQMacroDataValueTypeEnum(BOOLEAN, "BOOLEAN", "Boolean")); enumData.push_back(WuQMacroDataValueTypeEnum(FLOAT, "FLOAT", "Float")); enumData.push_back(WuQMacroDataValueTypeEnum(INTEGER, "INTEGER", "Integer")); enumData.push_back(WuQMacroDataValueTypeEnum(MOUSE, "MOUSE", "Mouse")); enumData.push_back(WuQMacroDataValueTypeEnum(NONE, "NONE", "None")); enumData.push_back(WuQMacroDataValueTypeEnum(STRING, "STRING", "String")); enumData.push_back(WuQMacroDataValueTypeEnum(STRING_LIST, "STRING_LIST", "StringList")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const WuQMacroDataValueTypeEnum* WuQMacroDataValueTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const WuQMacroDataValueTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WuQMacroDataValueTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroDataValueTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WuQMacroDataValueTypeEnum::Enum WuQMacroDataValueTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WuQMacroDataValueTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroDataValueTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WuQMacroDataValueTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WuQMacroDataValueTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroDataValueTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WuQMacroDataValueTypeEnum::Enum WuQMacroDataValueTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WuQMacroDataValueTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroDataValueTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WuQMacroDataValueTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t WuQMacroDataValueTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroDataValueTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ WuQMacroDataValueTypeEnum::Enum WuQMacroDataValueTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WuQMacroDataValueTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroDataValueTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WuQMacroDataValueTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void WuQMacroDataValueTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WuQMacroDataValueTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(WuQMacroDataValueTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WuQMacroDataValueTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(WuQMacroDataValueTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/WuQMacroDataValueTypeEnum.h000066400000000000000000000066741360521144700250140ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_DATA_VALUE_TYPE_ENUM_H__ #define __WU_Q_MACRO_DATA_VALUE_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class WuQMacroDataValueTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Invalid */ INVALID, /** Axis */ AXIS, /** Boolean */ BOOLEAN, /** Float */ FLOAT, /** Integer */ INTEGER, /** Mouse */ MOUSE, /** None (no data value associated with object */ NONE, /** String */ STRING, /** String List*/ STRING_LIST }; ~WuQMacroDataValueTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: WuQMacroDataValueTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const WuQMacroDataValueTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __WU_Q_MACRO_DATA_VALUE_TYPE_ENUM_DECLARE__ std::vector WuQMacroDataValueTypeEnum::enumData; bool WuQMacroDataValueTypeEnum::initializedFlag = false; int32_t WuQMacroDataValueTypeEnum::integerCodeCounter = 0; #endif // __WU_Q_MACRO_DATA_VALUE_TYPE_ENUM_DECLARE__ } // namespace #endif //__WU_Q_MACRO_DATA_VALUE_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Common/WuQMacroFile.cxx000066400000000000000000000137511360521144700227030ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_FILE_DECLARE__ #include "WuQMacroFile.h" #undef __WU_Q_MACRO_FILE_DECLARE__ #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "DataFileException.h" #include "WuQMacro.h" #include "WuQMacroGroup.h" #include "WuQMacroGroupXmlStreamReader.h" #include "WuQMacroGroupXmlStreamWriter.h" using namespace caret; /** * \class caret::WuQMacroFile * \brief File for storing macros * \ingroup Common */ /** * Constructor. */ WuQMacroFile::WuQMacroFile() : DataFile() { m_macroGroup.reset(new WuQMacroGroup("File")); } /** * Destructor. */ WuQMacroFile::~WuQMacroFile() { } /** * @return True if this file is empty (has no macros) */ bool WuQMacroFile::isEmpty() const { return (m_macroGroup->getNumberOfMacros() == 0); } /** * @return Macro group in this file */ WuQMacroGroup* WuQMacroFile::getMacroGroup() { return m_macroGroup.get(); } /** * @return Macro group in this file (const method) */ const WuQMacroGroup* WuQMacroFile::getMacroGroup() const { return m_macroGroup.get(); } /** * @return File filter for macro file in a QFileDialog */ QString WuQMacroFile::getFileDialogFilter() { QString f("Macros (*" + getFileExtension() + ")"); return f; } /** * @return Extension for a macro file */ QString WuQMacroFile::getFileExtension() { return ".wb_macro"; } /** * Set the status to unmodified. */ void WuQMacroFile::clearModified() { DataFile::clearModified(); m_macroGroup->clearModified(); } /** * Is the object modified? * @return true if modified, else false. */ bool WuQMacroFile::isModified() const { if (DataFile::isModified()) { return true; } if (m_macroGroup->isModified()) { return true; } return false; } /** * Clear the contents of the file. */ void WuQMacroFile::clear() { m_macroGroup->clear(); } /** * Append macros in the given group to this file * * @param macroGroup * The macro group whose macros are appended to this macro group */ void WuQMacroFile::appendMacroGroup(const WuQMacroGroup* macroGroup) { const int32_t numMacros = macroGroup->getNumberOfMacros(); for (int32_t i = 0; i < numMacros; i++) { const WuQMacro* macro = macroGroup->getMacroAtIndex(i); CaretAssert(macro); addMacro(new WuQMacro(*macro)); } setModified(); } /** * Add a macro to this file. * This file will take ownership of the macro. * * @param macro * Macro to add to file */ void WuQMacroFile::addMacro(WuQMacro* macro) { CaretAssert(macro); m_macroGroup->addMacro(macro); } /** * Set the macro group's name to the name of the file * without the extension */ void WuQMacroFile::setMacroGroupName(const QString& filename) { if (filename.isEmpty()) { return; } QFileInfo fileInfo(filename); QString macroGroupName(fileInfo.fileName()); const int extIndex = macroGroupName.indexOf(getFileExtension()); if (extIndex > 0) { macroGroupName.resize(extIndex); } m_macroGroup->setName(macroGroupName); } /** * Read the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully read. */ void WuQMacroFile::readFile(const AString& filename) { if (filename.isEmpty()) { throw DataFileException("Filename is empty"); } QFile file(filename); if (file.open(QFile::ReadOnly)) { setMacroGroupName(filename); QTextStream textStream(&file); const QString fileContentString = textStream.readAll(); QString errorMessage; WuQMacroGroupXmlStreamReader reader; if ( ! reader.readFromString(fileContentString, m_macroGroup.get(), errorMessage)) { file.close(); throw DataFileException(errorMessage); } setFileName(filename); clearModified(); } else { throw DataFileException("Unable to open file for writing: " + filename); } } /** * Write the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully written. */ void WuQMacroFile::writeFile(const AString& filename) { if (filename.isEmpty()) { throw DataFileException("Filename is empty"); } QFile file(filename); if (file.open(QFile::WriteOnly)) { setMacroGroupName(filename); /* * Place the macro group into a string */ QString fileContentString; WuQMacroGroupXmlStreamWriter writer; writer.writeToString(m_macroGroup.get(), fileContentString); /* * Write string containing macros and close file */ QTextStream textStream(&file); textStream << fileContentString; file.close(); setFileName(filename); clearModified(); } else { throw DataFileException("Unable to open file for writing: " + filename); } } connectome-workbench-1.4.2/src/Common/WuQMacroFile.h000066400000000000000000000042531360521144700223250ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_FILE_H__ #define __WU_Q_MACRO_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "DataFile.h" namespace caret { class WuQMacro; class WuQMacroGroup; class WuQMacroFile : public DataFile { public: WuQMacroFile(); virtual ~WuQMacroFile(); virtual bool isEmpty() const override; WuQMacroGroup* getMacroGroup(); const WuQMacroGroup* getMacroGroup() const; virtual void readFile(const AString& filename) override; virtual void writeFile(const AString& filename) override; static QString getFileDialogFilter(); static QString getFileExtension(); virtual void clearModified(); virtual bool isModified() const; virtual void clear(); void addMacro(WuQMacro* macro); void appendMacroGroup(const WuQMacroGroup* macroGroup); // ADD_NEW_METHODS_HERE private: void setMacroGroupName(const QString& filename); std::unique_ptr m_macroGroup; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_MACRO_FILE_DECLARE__ // #endif // __WU_Q_MACRO_FILE_DECLARE__ } // namespace #endif //__WU_Q_MACRO_FILE_H__ connectome-workbench-1.4.2/src/Common/WuQMacroGroup.cxx000066400000000000000000000324201360521144700231120ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_GROUP_DECLARE__ #include "WuQMacroGroup.h" #undef __WU_Q_MACRO_GROUP_DECLARE__ #include #include "CaretAssert.h" #include "WuQMacro.h" #include "WuQMacroGroupXmlStreamReader.h" #include "WuQMacroGroupXmlStreamWriter.h" using namespace caret; /** * \class caret::WuQMacroGroup * \brief Contains a group of macros * \ingroup WuQMacro */ /** * Constructor. * * @param name * Name of group */ WuQMacroGroup::WuQMacroGroup(const QString& name) : QStandardItemModel(), TracksModificationInterface(), m_name(name) { m_uniqueIdentifier = QUuid::createUuid().toString(); } /** * Destructor. */ WuQMacroGroup::~WuQMacroGroup() { clearPrivate(); } /** * Clear (remove all macros) */ void WuQMacroGroup::clearPrivate() { /* Note: Do not clear unique identifier */ } /** * @return Name of group */ QString WuQMacroGroup::getName() const { return m_name; } /** * Set name of group * * @param name * Name of group */ void WuQMacroGroup::setName(const QString& name) { if (m_name != name) { m_name = name; setModified(); } } /** * @return The unique identifier */ QString WuQMacroGroup::getUniqueIdentifier() const { return m_uniqueIdentifier; } /** * Set unique identifier of macro * * @param uniqueIdentifier * New unique identifier */void WuQMacroGroup::setUniqueIdentifier(const QString& uniqueIdentifier) { if (uniqueIdentifier.isEmpty()) { return; } if (m_uniqueIdentifier != uniqueIdentifier) { m_uniqueIdentifier = uniqueIdentifier; setModified(); } } /** * Add a macro * * @param macro * Macro added to this group. This group will take ownership of the macro. */ void WuQMacroGroup::addMacro(WuQMacro* macro) { appendRow(macro); setModified(); } /** * Insert the given macro at the given index * * @param index * Index of where to insert the macro * @param macro * Macro to insert. */ void WuQMacroGroup::insertMacroAtIndex(const int32_t index, WuQMacro* macro) { CaretAssert((index >= 0) && (index <= getNumberOfMacros())); CaretAssert(macro); insertRow(index, macro); setModified(); } /** * Append macros in the given group to this group * * @param macroGroup * The macro group whose macros are appended to this macro group */ void WuQMacroGroup::appendMacroGroup(const WuQMacroGroup* macroGroup) { const int32_t numMacros = macroGroup->getNumberOfMacros(); for (int32_t i = 0; i < numMacros; i++) { const WuQMacro* macro = macroGroup->getMacroAtIndex(i); CaretAssert(macro); appendRow(new WuQMacro(*macro)); } setModified(); } /** * @return Number of macros in group */ int32_t WuQMacroGroup::getNumberOfMacros() const { return rowCount(); } /** * @return Is this empty (contains no macros) ? */ bool WuQMacroGroup::isEmpty() const { return (getNumberOfMacros() <= 0); } /** * Get the macro with the given name * * @param name * Name of the macro * @return * Pointer to macro with the name or NULL if not found */ WuQMacro* WuQMacroGroup::getMacroByName(const QString& name) { const int32_t numItems = rowCount(); for (int32_t i = 0; i < numItems; i++) { WuQMacro* macro = getMacroAtIndex(i); if (macro->getName() == name) { return macro; } } return NULL; } /** * Get the macro with the given name * * @param name * Name of the macro * @return * Pointer to macro with the name or NULL if not found */ const WuQMacro* WuQMacroGroup::getMacroByName(const QString& name) const { const int32_t numItems = rowCount(); for (int32_t i = 0; i < numItems; i++) { const WuQMacro* macro = getMacroAtIndex(i); if (macro->getName() == name) { return macro; } } return NULL; } /** * Get the macro with the given unique identifier * * @param uniqueIdentifier * Unique identifier of the macro * @return * Pointer to macro with the unique identifier or NULL if not found */ WuQMacro* WuQMacroGroup::getMacroWithUniqueIdentifier(const QString& uniqueIdentifier) { const int32_t numItems = rowCount(); for (int32_t i = 0; i < numItems; i++) { WuQMacro* macro = getMacroAtIndex(i); if (macro->getUniqueIdentifier() == uniqueIdentifier) { return macro; } } return NULL; } /** * Get the macro with the given unique identifier (const method) * * @param uniqueIdentifier * Unique identifier of the macro * @return * Pointer to macro with the unique identifier or NULL if not found */ const WuQMacro* WuQMacroGroup::getMacroWithUniqueIdentifier(const QString& uniqueIdentifier) const { const int32_t numItems = rowCount(); for (int32_t i = 0; i < numItems; i++) { const WuQMacro* macro = getMacroAtIndex(i); if (macro->getUniqueIdentifier() == uniqueIdentifier) { return macro; } } return NULL; } /** * Get the macro with the given short cut key * * @param name * Name of the macro * @return * Pointer to macro with the short cut key or NULL if not found */ WuQMacro* WuQMacroGroup::getMacroWithShortCutKey(const WuQMacroShortCutKeyEnum::Enum shortCutKey) { const int32_t numItems = rowCount(); for (int32_t i = 0; i < numItems; i++) { WuQMacro* macro = getMacroAtIndex(i); if (macro->getShortCutKey() == shortCutKey) { return macro; } } return NULL; } /** * Get the macro with the given short cut key * * @param name * Name of the macro * @return * Pointer to macro with the short cut key or NULL if not found */ const WuQMacro* WuQMacroGroup::getMacroWithShortCutKey(const WuQMacroShortCutKeyEnum::Enum shortCutKey) const { const int32_t numItems = rowCount(); for (int32_t i = 0; i < numItems; i++) { const WuQMacro* macro = getMacroAtIndex(i); if (macro->getShortCutKey() == shortCutKey) { return macro; } } return NULL; } /** * @return * Macro at the given index * @param index * Index of the macro */ WuQMacro* WuQMacroGroup::getMacroAtIndex(const int32_t index) { CaretAssert((index >= 0) && (index < rowCount())); QStandardItem* standardItem = item(index); CaretAssert(standardItem); WuQMacro* macro = dynamic_cast(standardItem); CaretAssert(macro); return macro; } /** * @return * Macro at the given index * @param index * Index of the macro */ const WuQMacro* WuQMacroGroup::getMacroAtIndex(const int32_t index) const { CaretAssert((index >= 0) && (index < rowCount())); QStandardItem* standardItem = item(index); CaretAssert(standardItem); WuQMacro* macro = dynamic_cast(standardItem); CaretAssert(macro); return macro; } /** * Get the index of the given macro * * @param macro * The macro for index * @return * Index of macro or -1 if not found */ int32_t WuQMacroGroup::getIndexOfMacro(const WuQMacro* macro) { const int32_t count = getNumberOfMacros(); for (int32_t i = 0; i < count; i++) { if (getMacroAtIndex(i) == macro) { return i; } } return -1; } /** * @return True if this macro group contains the given macro * * @param macro * Macro for inclusion testing */ bool WuQMacroGroup::containsMacro(const WuQMacro* macro) { const int32_t index = getIndexOfMacro(macro); if (index >= 0) { return true; } else { return false; } } /** * Delete the given macro from this group * * @param macro * Macro for deletion */ void WuQMacroGroup::deleteMacro(const WuQMacro* macro) { const int32_t index = getIndexOfMacro(macro); if (index >= 0) { deleteMacroAtIndex(index); } } /** * Delete the macro at the given index * * @param index * Index of macro for deletion */ void WuQMacroGroup::deleteMacroAtIndex(const int32_t index) { /* * Note that 'takeItem' removes the item and the * row becomes NULL so also need to remove the row. */ CaretAssert((index >= 0) && (index < rowCount())); QStandardItem* item = takeItem(index); CaretAssert(item); removeRow(index); delete item; setModified(); } /** * Move the given macro down one position * * @param macro */ void WuQMacroGroup::moveMacroDown(WuQMacro* macro) { const int32_t index = getIndexOfMacro(macro); if ((index >= 0) && (index < getNumberOfMacros() - 1)) { /* Note that take item removes item but does not remove row */ QStandardItem* item = takeItem(index); removeRow(index); CaretAssert(item); insertMacroAtIndex(index + 1, dynamic_cast(item)); } } /** * Move the given macro up one position * * @param macro */ void WuQMacroGroup::moveMacroUp(WuQMacro* macro) { const int32_t index = getIndexOfMacro(macro); if ((index > 0) && (index < getNumberOfMacros())) { /* Note that take child removes item but does not remove row */ QStandardItem* item = takeItem(index); removeRow(index); CaretAssert(item); insertMacroAtIndex(index - 1, dynamic_cast(item)); } } /** * Take all macros from this macro group. After calling * this method, 'this' macro group contains no macros * * @return All macros from this group. */ std::vector WuQMacroGroup::takeAllMacros() { std::vector macrosOut; const int32_t numMacros = rowCount(); for (int32_t i = 0; i < numMacros; i++) { WuQMacro* macro = dynamic_cast(takeItem(i)); CaretAssert(macro); macrosOut.push_back(macro); } removeRows(0, numMacros); CaretAssert(rowCount() == 0); return macrosOut; } /** * @return True if this instance is modified */ bool WuQMacroGroup::isModified() const { if (m_modifiedStatusFlag) { return true; } const int32_t count = getNumberOfMacros(); for (int32_t i = 0; i < count; i++) { if (getMacroAtIndex(i)->isModified()) { return true; break; } } return false; } /** * Clear the modified status */ void WuQMacroGroup::clearModified() { m_modifiedStatusFlag = false; const int32_t count = getNumberOfMacros(); for (int32_t i = 0; i < count; i++) { getMacroAtIndex(i)->clearModified(); } } /** * Set the modification status to modified */ void WuQMacroGroup::setModified() { m_modifiedStatusFlag = true; } /** * Read from a string containing XML. If successful, * the modified status is cleared. * * @param xmlString * String containing XML * @param errorMessageOut * Contains error information if reading fails * @param nonFatalWarningMessageOut * May contain non-fatal warnings when reading is successful * @return * True if successful, else false */ bool WuQMacroGroup::readXmlFromStringOld(const QString& xmlString, QString& errorMessageOut, QString& nonFatalWarningMessageOut) { errorMessageOut.clear(); nonFatalWarningMessageOut.clear(); WuQMacroGroupXmlStreamReader reader; if ( ! reader.readFromString(xmlString, this, errorMessageOut)) { return false; } clearModified(); return true; } /** * Write to a string containing XML. If successful, * the modified status is cleared. * * @param xmlString * String to which XML is written * @param errorMessageOut * Contains error information if reading fails * @return * True if successful, else false */ bool WuQMacroGroup::writeXmlToString(QString& xmlString, QString& errorMessageOut) { xmlString.clear(); errorMessageOut.clear(); WuQMacroGroupXmlStreamWriter writer; writer.writeToString(this, xmlString); clearModified(); return true; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString WuQMacroGroup::toString() const { QString s("WuQMacroGroup name=" + m_name + "\n"); const int32_t count = getNumberOfMacros(); for (int32_t i = 0; i < count; i++) { s.append(getMacroAtIndex(i)->toString() + "\n"); } return s; } connectome-workbench-1.4.2/src/Common/WuQMacroGroup.h000066400000000000000000000075131360521144700225440ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_GROUP_H__ #define __WU_Q_MACRO_GROUP_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretObjectTracksModification.h" #include "TracksModificationInterface.h" #include "WuQMacroShortCutKeyEnum.h" namespace caret { class WuQMacro; class WuQMacroGroup : public QStandardItemModel, public TracksModificationInterface { public: WuQMacroGroup(const QString& groupName); virtual ~WuQMacroGroup(); QString getName() const; void setName(const QString& name); QString getUniqueIdentifier() const; void setUniqueIdentifier(const QString& uniqueIdentifier); void addMacro(WuQMacro* macro); void insertMacroAtIndex(const int32_t index, WuQMacro* macro); void appendMacroGroup(const WuQMacroGroup* macroGroup); int32_t getNumberOfMacros() const; bool isEmpty() const; WuQMacro* getMacroByName(const QString& name); const WuQMacro* getMacroByName(const QString& name) const; WuQMacro* getMacroAtIndex(const int32_t index); const WuQMacro* getMacroAtIndex(const int32_t index) const; int32_t getIndexOfMacro(const WuQMacro* macro); WuQMacro* getMacroWithUniqueIdentifier(const QString& uniqueIdentifier); const WuQMacro* getMacroWithUniqueIdentifier(const QString& uniqueIdentifier) const; WuQMacro* getMacroWithShortCutKey(const WuQMacroShortCutKeyEnum::Enum shortCutKey); const WuQMacro* getMacroWithShortCutKey(const WuQMacroShortCutKeyEnum::Enum shortCutKey) const; bool containsMacro(const WuQMacro* macro); void deleteMacro(const WuQMacro* macro); void deleteMacroAtIndex(const int32_t index); void moveMacroDown(WuQMacro* macro); void moveMacroUp(WuQMacro* macro); std::vector takeAllMacros(); virtual bool isModified() const override; virtual void clearModified() override; virtual void setModified() override; bool readXmlFromStringOld(const QString& xmlString, QString& errorMessageOut, QString& nonFatalWarningMessageOut); bool writeXmlToString(QString& xmlString, QString& errorMessageOut); // ADD_NEW_METHODS_HERE virtual AString toString() const; private: void clearPrivate(); QString m_uniqueIdentifier; QString m_name; bool m_modifiedStatusFlag = false; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_MACRO_GROUP_DECLARE__ // #endif // __WU_Q_MACRO_GROUP_DECLARE__ } // namespace #endif //__WU_Q_MACRO_GROUP_H__ connectome-workbench-1.4.2/src/Common/WuQMacroGroupXmlStreamBase.cxx000066400000000000000000000030431360521144700255410ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_GROUP_XML_STREAM_BASE_DECLARE__ #include "WuQMacroGroupXmlStreamBase.h" #undef __WU_Q_MACRO_GROUP_XML_STREAM_BASE_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::WuQMacroGroupXmlStreamBase * \brief Base class for reading/writing macro group in XML * \ingroup Common */ /** * Constructor. */ WuQMacroGroupXmlStreamBase::WuQMacroGroupXmlStreamBase() : CaretObject() { } /** * Destructor. */ WuQMacroGroupXmlStreamBase::~WuQMacroGroupXmlStreamBase() { } /** * Get a description of this object's content. * @return String describing this object's content. */ AString WuQMacroGroupXmlStreamBase::toString() const { return "WuQMacroGroupXmlStreamBase"; } connectome-workbench-1.4.2/src/Common/WuQMacroGroupXmlStreamBase.h000066400000000000000000000152771360521144700252020ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_GROUP_XML_STREAM_BASE_H__ #define __WU_Q_MACRO_GROUP_XML_STREAM_BASE_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" namespace caret { class WuQMacroGroupXmlStreamBase : public CaretObject { protected: WuQMacroGroupXmlStreamBase(); public: virtual ~WuQMacroGroupXmlStreamBase(); WuQMacroGroupXmlStreamBase(const WuQMacroGroupXmlStreamBase&) = delete; WuQMacroGroupXmlStreamBase& operator=(const WuQMacroGroupXmlStreamBase&) = delete; // ADD_NEW_METHODS_HERE virtual AString toString() const; static const QString ATTRIBUTE_COMMAND_TYPE; static const QString ATTRIBUTE_NAME; static const QString ATTRIBUTE_OBJECT_DESCRIPTIVE_NAME; static const QString ATTRIBUTE_DELAY; static const QString ATTRIBUTE_SHORT_CUT_KEY; static const QString ATTRIBUTE_UNIQUE_IDENTIFIER; static const QString ATTRIBUTE_CUSTOM_OPERATION_TYPE_NAME; static const QString ATTRIBUTE_VERSION; static const QString ATTRIBUTE_WIDGET_TYPE; static const QString ATTRIBUTE_MOUSE_BUTTON; static const QString ATTRIBUTE_MOUSE_BUTTONS_MASK; static const QString ATTRIBUTE_MOUSE_EVENT_TYPE; static const QString ATTRIBUTE_MOUSE_KEYBOARD_MODIFIERS_MASK; static const QString ATTRIBUTE_MOUSE_LOCAL_X; static const QString ATTRIBUTE_MOUSE_LOCAL_Y; static const QString ATTRIBUTE_MOUSE_SCREEN_X; static const QString ATTRIBUTE_MOUSE_SCREEN_Y; static const QString ATTRIBUTE_MOUSE_WIDGET_WIDTH; static const QString ATTRIBUTE_MOUSE_WIDGET_HEIGHT; static const QString ATTRIBUTE_MOUSE_WINDOW_X; static const QString ATTRIBUTE_MOUSE_WINDOW_Y; static const QString ATTRIBUTE_MACRO_COMMAND_PARAMETER_DATA_TYPE; static const QString ATTRIBUTE_MACRO_COMMAND_PARAMETER_NAME; static const QString ATTRIBUTE_MACRO_COMMAND_PARAMETER_CUSTOM_DATA_TYPE; static const QString ATTRIBUTE_MACRO_COMMAND_PARAMETER_VALUE; static const QString ELEMENT_DESCRIPTION; static const QString ELEMENT_MACRO; static const QString ELEMENT_MACRO_COMMAND; static const QString ELEMENT_MACRO_COMMAND_MOUSE_EVENT_INFO; static const QString ELEMENT_MACRO_COMMAND_PARAMETER; static const QString ELEMENT_MACRO_COMMAND_TOOL_TIP; static const QString ELEMENT_MACRO_GROUP; static const QString VALUE_BOOL_FALSE; static const QString VALUE_BOOL_TRUE; static const QString VALUE_VERSION_ONE; private: // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_MACRO_GROUP_XML_STREAM_BASE_DECLARE__ const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_COMMAND_TYPE = "CommandType"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_NAME = "Name"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_CUSTOM_OPERATION_TYPE_NAME = "CustomOperationTypeName"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_DELAY = "Delay"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_OBJECT_DESCRIPTIVE_NAME = "DescriptiveName"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_SHORT_CUT_KEY = "ShortCutKey"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_UNIQUE_IDENTIFIER = "UniqueIdentifier"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_VERSION = "Version"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_WIDGET_TYPE = "WidgetType"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_BUTTON = "MouseButton"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_BUTTONS_MASK = "MouseButtonsMask"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_EVENT_TYPE = "MouseEventType"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_KEYBOARD_MODIFIERS_MASK = "KeyboardModifiersMask"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_LOCAL_X = "LocalX"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_LOCAL_Y = "LocalY"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_SCREEN_X = "ScreenX"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_SCREEN_Y = "ScreenY"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_WIDGET_WIDTH = "WidgetWidth"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_WIDGET_HEIGHT = "WidgetHeight"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_WINDOW_X = "WindowX"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MOUSE_WINDOW_Y = "WindowY"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MACRO_COMMAND_PARAMETER_DATA_TYPE = "DataType"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MACRO_COMMAND_PARAMETER_NAME = "Name"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MACRO_COMMAND_PARAMETER_CUSTOM_DATA_TYPE = "CustomDataType"; const QString WuQMacroGroupXmlStreamBase::ATTRIBUTE_MACRO_COMMAND_PARAMETER_VALUE = "Value"; const QString WuQMacroGroupXmlStreamBase::ELEMENT_DESCRIPTION = "Description"; const QString WuQMacroGroupXmlStreamBase::ELEMENT_MACRO = "Macro"; const QString WuQMacroGroupXmlStreamBase::ELEMENT_MACRO_COMMAND = "MacroCommand"; const QString WuQMacroGroupXmlStreamBase::ELEMENT_MACRO_COMMAND_MOUSE_EVENT_INFO = "MouseEventInfo"; const QString WuQMacroGroupXmlStreamBase::ELEMENT_MACRO_COMMAND_PARAMETER = "Parameter"; const QString WuQMacroGroupXmlStreamBase::ELEMENT_MACRO_COMMAND_TOOL_TIP = "ToolTip"; const QString WuQMacroGroupXmlStreamBase::ELEMENT_MACRO_GROUP = "MacroGroup"; const QString WuQMacroGroupXmlStreamBase::VALUE_BOOL_FALSE = "false"; const QString WuQMacroGroupXmlStreamBase::VALUE_BOOL_TRUE = "true"; const QString WuQMacroGroupXmlStreamBase::VALUE_VERSION_ONE = "1"; #endif // __WU_Q_MACRO_GROUP_XML_STREAM_BASE_DECLARE__ } // namespace #endif //__WU_Q_MACRO_GROUP_XML_STREAM_BASE_H__ connectome-workbench-1.4.2/src/Common/WuQMacroGroupXmlStreamReader.cxx000066400000000000000000000636261360521144700261060ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_GROUP_XML_STREAM_READER_DECLARE__ #include "WuQMacroGroupXmlStreamReader.h" #undef __WU_Q_MACRO_GROUP_XML_STREAM_READER_DECLARE__ #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "WuQMacro.h" #include "WuQMacroCommand.h" #include "WuQMacroCommandParameter.h" #include "WuQMacroGroup.h" #include "WuQMacroMouseEventInfo.h" using namespace caret; /** * \class caret::WuQMacroGroupXmlStreamReader * \brief Reads macro group from XML format * \ingroup Common */ /** * Constructor. */ WuQMacroGroupXmlStreamReader::WuQMacroGroupXmlStreamReader() : WuQMacroGroupXmlStreamBase() { } /** * Destructor. */ WuQMacroGroupXmlStreamReader::~WuQMacroGroupXmlStreamReader() { } /** * Read XML from the given string into the given macro group * * @param xmlString * The string containing XML * @param macroGroup * The macro group * @param errorMessageOut * Output error message * @return * True if successful, else false is returned and description in errorMessageOut */ bool WuQMacroGroupXmlStreamReader::readFromString(const QString& xmlString, WuQMacroGroup* macroGroup, QString& errorMessageOut) { errorMessageOut.clear(); CaretAssert(macroGroup); macroGroup->clear(); if (xmlString.isEmpty()) { errorMessageOut = "String that should contain XML is empty."; return false; } QXmlStreamReader xmlReader(xmlString); if (xmlReader.atEnd()) { xmlReader.raiseError("At end when trying to start reading. Appears to have no XML content."); } else { xmlReader.readNextStartElement(); readMacroGroup(xmlReader, macroGroup); } if (xmlReader.hasError()) { errorMessageOut = xmlReader.errorString(); macroGroup->clear(); return false; } macroGroup->clearModified(); return true; } /** * Read macro group from the given XML stream reader. It assumes that * the start element for the macro group has already been read and is * the current element. If xmlReader.hasError() is set after this * method is called, there was an error reading the macro group. * * @param xmlReader * The XML stream reader * @param macroGroup * The macro group */ void WuQMacroGroupXmlStreamReader::readMacroGroup(QXmlStreamReader& xmlReader, WuQMacroGroup* macroGroup) { if (xmlReader.name() == ELEMENT_MACRO_GROUP) { const QXmlStreamAttributes attributes = xmlReader.attributes(); const QStringRef name = attributes.value(ATTRIBUTE_NAME); const QStringRef versionText = attributes.value(ATTRIBUTE_VERSION); QString uniqueIdentifier = attributes.value(ATTRIBUTE_UNIQUE_IDENTIFIER).toString(); if (uniqueIdentifier.isEmpty()) { addToWarnings(xmlReader, ELEMENT_MACRO_GROUP + " is missing attribute or value is empty: " + ATTRIBUTE_UNIQUE_IDENTIFIER); } if (versionText.isEmpty()) { xmlReader.raiseError(ATTRIBUTE_VERSION + " is missing from element " + ELEMENT_MACRO_GROUP); } else if (versionText == VALUE_VERSION_ONE) { macroGroup->setName(name.toString()); macroGroup->setUniqueIdentifier(uniqueIdentifier); readVersionOne(xmlReader, macroGroup); } else { xmlReader.raiseError(ATTRIBUTE_VERSION + "=" + versionText.toString() + " is not supported by " + ELEMENT_MACRO_GROUP + ". Check for software update."); } } else { xmlReader.raiseError("Element should be \"" + ELEMENT_MACRO_GROUP + "\" but is \"" + xmlReader.text().toString() + "\" while reading MacroGroup"); } if ( ! m_warningMessage.isEmpty()) { CaretLogWarning("Reading Macro's Warnings: " + m_warningMessage); m_warningMessage.clear(); } } /** * Read version one of macro group * * @param xmlReader * The XML stream reader * @param macroGroup * The macro group */ void WuQMacroGroupXmlStreamReader::readVersionOne(QXmlStreamReader& xmlReader, WuQMacroGroup* macroGroup) { CaretAssert(macroGroup); WuQMacro* macro(NULL); /* * Gets set when ending scene info directory element is read */ bool endElementFound(false); while ( (! xmlReader.atEnd()) && ( ! endElementFound)) { xmlReader.readNext(); if (xmlReader.isStartElement()) { const QString elementName = xmlReader.name().toString(); if (elementName == ELEMENT_MACRO) { macro = readMacroVersionOne(xmlReader); if (macro != NULL) { macroGroup->addMacro(macro); } } else { addToWarnings(xmlReader, "Unexpected element=" + elementName + "\""); xmlReader.skipCurrentElement(); } } else if (xmlReader.isEndElement()) { if (xmlReader.name() == ELEMENT_MACRO_GROUP) { endElementFound = true; } } } } /** * Read version one of macro * * @param xmlReader * The XML stream reader * @return The macro */ WuQMacro* WuQMacroGroupXmlStreamReader::readMacroVersionOne(QXmlStreamReader& xmlReader) { WuQMacro* macro(NULL); const QXmlStreamAttributes attributes = xmlReader.attributes(); QString macroName = attributes.value(ATTRIBUTE_NAME).toString(); QString shortCutKeyString = attributes.value(ATTRIBUTE_SHORT_CUT_KEY).toString(); if (shortCutKeyString.isEmpty()) { shortCutKeyString = WuQMacroShortCutKeyEnum::toName(WuQMacroShortCutKeyEnum::Key_None); addToWarnings(xmlReader, ELEMENT_MACRO + " is missing attribute or value is empty: " + ATTRIBUTE_SHORT_CUT_KEY); } QString uniqueIdentifier = attributes.value(ATTRIBUTE_UNIQUE_IDENTIFIER).toString(); if (uniqueIdentifier.isEmpty()) { addToWarnings(xmlReader, ELEMENT_MACRO + " is missing attribute or value is empty: " + ATTRIBUTE_UNIQUE_IDENTIFIER); } bool validShortCutKey(false); WuQMacroShortCutKeyEnum::Enum shortCutKey = WuQMacroShortCutKeyEnum::fromName(shortCutKeyString, &validShortCutKey); if ( ! validShortCutKey) { shortCutKey = WuQMacroShortCutKeyEnum::Key_None; addToWarnings(xmlReader, ELEMENT_MACRO + " attribute " + ATTRIBUTE_SHORT_CUT_KEY + " has invalid value " + shortCutKeyString); } if (macroName.isEmpty()) { addToWarnings(xmlReader, ELEMENT_MACRO + " is missing attribute or value is empty: " + ATTRIBUTE_NAME); static uint32_t missingCounter = 1; macroName = ("Missing Name_" + QString::number(missingCounter)); } macro = new WuQMacro(); macro->setName(macroName); macro->setShortCutKey(shortCutKey); macro->setUniqueIdentifier(uniqueIdentifier); /* * Gets set when ending scene info directory element is read */ bool endElementFound(false); while ( (! xmlReader.atEnd()) && ( ! endElementFound)) { xmlReader.readNext(); if (xmlReader.isStartElement()) { const QString elementName = xmlReader.name().toString(); if (elementName == ELEMENT_MACRO_COMMAND) { WuQMacroCommand* command = readMacroCommandVersionOne(xmlReader); if (command != NULL) { macro->appendMacroCommand(command); } } else if (elementName == ELEMENT_DESCRIPTION) { const QString text = xmlReader.readElementText(); macro->setDescription(text); } else { addToWarnings(xmlReader, "Unexpected element=" + elementName + "\""); xmlReader.skipCurrentElement(); } } else if (xmlReader.isEndElement()) { if (xmlReader.name() == ELEMENT_MACRO) { endElementFound = true; } } } return macro; } WuQMacroCommand* WuQMacroGroupXmlStreamReader::readMacroCommandVersionOne(QXmlStreamReader& xmlReader) { WuQMacroCommand* macroCommand(NULL); std::unique_ptr commandContent(readMacroCommandAttributesVersionOne(xmlReader)); if (commandContent != NULL) { /* * Gets set when ending scene info directory element is read */ bool endElementFound(false); while ( (! xmlReader.atEnd()) && ( ! endElementFound)) { xmlReader.readNext(); if (xmlReader.isStartElement()) { const QString elementName = xmlReader.name().toString(); if (elementName == ELEMENT_MACRO_COMMAND_MOUSE_EVENT_INFO) { WuQMacroMouseEventInfo* mouseEventInfo = readMacroMouseEventInfo(xmlReader); if (mouseEventInfo != NULL) { commandContent->m_mouseInfo = mouseEventInfo; } } else if (elementName == ELEMENT_MACRO_COMMAND_TOOL_TIP) { const QString text = xmlReader.readElementText(); commandContent->m_toolTip = text; } else if (elementName == ELEMENT_MACRO_COMMAND_PARAMETER) { WuQMacroCommandParameter* parameter = readMacroCommandParameter(xmlReader); if (parameter != NULL) { commandContent->m_parameters.push_back(parameter); } } else { addToWarnings(xmlReader, "Unexpected element=" + elementName + "\""); xmlReader.skipCurrentElement(); } } else if (xmlReader.isEndElement()) { if (xmlReader.name() == ELEMENT_MACRO_COMMAND) { endElementFound = true; QString errorMessage; switch (commandContent->m_commandType) { case WuQMacroCommandTypeEnum::CUSTOM_OPERATION: macroCommand = WuQMacroCommand::newInstanceCustomCommand(commandContent->m_customOperationTypeName, commandContent->m_version, commandContent->m_objectName, commandContent->m_descriptiveName, commandContent->m_toolTip, commandContent->m_delay, errorMessage); break; case WuQMacroCommandTypeEnum::MOUSE: macroCommand = WuQMacroCommand::newInstanceMouseCommand(commandContent->m_mouseInfo, commandContent->m_version, commandContent->m_objectName, commandContent->m_descriptiveName, commandContent->m_toolTip, commandContent->m_delay, errorMessage); break; case WuQMacroCommandTypeEnum::WIDGET: macroCommand = WuQMacroCommand::newInstanceWidgetCommand(commandContent->m_widgetType, commandContent->m_version, commandContent->m_objectName, commandContent->m_descriptiveName, commandContent->m_toolTip, commandContent->m_delay, errorMessage); break; } if (macroCommand != NULL) { for (auto p : commandContent->m_parameters) { macroCommand->addParameter(p); } } else { CaretLogSevere("Error reading macro due to error: " + errorMessage); } } } } } else { xmlReader.skipCurrentElement(); } return macroCommand; } /** * Read version one of macro command parameter * * @param xmlReader * The XML stream reader * @Return The macro parameter */ WuQMacroCommandParameter* WuQMacroGroupXmlStreamReader::readMacroCommandParameter(QXmlStreamReader& xmlReader) { const QXmlStreamAttributes attributes = xmlReader.attributes(); const QStringRef dataTypeString = attributes.value(ATTRIBUTE_MACRO_COMMAND_PARAMETER_DATA_TYPE); const QString parameterName = attributes.value(ATTRIBUTE_MACRO_COMMAND_PARAMETER_NAME).toString(); const QString customDataType = attributes.value(ATTRIBUTE_MACRO_COMMAND_PARAMETER_CUSTOM_DATA_TYPE).toString(); const QStringRef valueString = attributes.value(ATTRIBUTE_MACRO_COMMAND_PARAMETER_VALUE); QString es; if (dataTypeString.isEmpty()) es.append(ATTRIBUTE_MACRO_COMMAND_PARAMETER_DATA_TYPE + " "); if ( ! es.isEmpty()) { addToWarnings(xmlReader, ELEMENT_MACRO_COMMAND_PARAMETER + " is missing attribute(s): " + es); return NULL; } bool dataTypeValid(false); WuQMacroDataValueTypeEnum::Enum dataType = WuQMacroDataValueTypeEnum::fromName(dataTypeString.toString(), &dataTypeValid); if (! dataTypeValid) { addToWarnings(xmlReader, (dataTypeString.toString() + " is not valid for attribute " + ATTRIBUTE_MACRO_COMMAND_PARAMETER_DATA_TYPE + " ")); return NULL; } QVariant value; switch (dataType) { case WuQMacroDataValueTypeEnum::AXIS: value.setValue(valueString.toString()); break; case WuQMacroDataValueTypeEnum::INVALID: value.setValue(QString("")); break; case WuQMacroDataValueTypeEnum::BOOLEAN: { const bool boolValue = ((valueString == VALUE_BOOL_TRUE) ? true : false); value.setValue(boolValue); } break; case WuQMacroDataValueTypeEnum::FLOAT: { const double floatValue = valueString.toFloat(); value.setValue(floatValue); } break; case WuQMacroDataValueTypeEnum::INTEGER: { const int32_t intValue = valueString.toInt(); value.setValue(intValue); } break; case WuQMacroDataValueTypeEnum::MOUSE: CaretAssertMessage(0, "Mouse is special case handled above"); break; case WuQMacroDataValueTypeEnum::NONE: value.setValue(QString()); break; case WuQMacroDataValueTypeEnum::STRING: value.setValue(valueString.toString()); break; case WuQMacroDataValueTypeEnum::STRING_LIST: value.setValue(valueString.toString()); break; } WuQMacroCommandParameter* parameter = new WuQMacroCommandParameter(dataType, parameterName, value); parameter->setCustomDataType(customDataType); return parameter; } /** * Read version one of macro command attributes into a command * * @param xmlReader * The XML stream reader * @Return The macro command's content */ WuQMacroGroupXmlStreamReader::MacroCommandContent* WuQMacroGroupXmlStreamReader::readMacroCommandAttributesVersionOne(QXmlStreamReader& xmlReader) { const QXmlStreamAttributes attributes = xmlReader.attributes(); const QStringRef objectName = attributes.value(ATTRIBUTE_NAME); const QStringRef delayString = attributes.value(ATTRIBUTE_DELAY); const QStringRef versionString = attributes.value(ATTRIBUTE_VERSION); const QStringRef descriptiveNameString = attributes.value(ATTRIBUTE_OBJECT_DESCRIPTIVE_NAME); const QStringRef commandTypeString = attributes.value(ATTRIBUTE_COMMAND_TYPE); const QStringRef widgetTypeString = attributes.value(ATTRIBUTE_WIDGET_TYPE); const QStringRef customOperationCommandNameString = attributes.value(ATTRIBUTE_CUSTOM_OPERATION_TYPE_NAME); QString es; if (objectName.isEmpty()) es.append(ATTRIBUTE_NAME + " "); if (commandTypeString.isEmpty()) es.append(ATTRIBUTE_WIDGET_TYPE + " "); bool commandTypeValid(false); const WuQMacroCommandTypeEnum::Enum commandType = WuQMacroCommandTypeEnum::fromName(commandTypeString.toString(), &commandTypeValid); if (commandTypeValid) { if (widgetTypeString.isEmpty()) { es.append(ATTRIBUTE_WIDGET_TYPE + " "); } } else { es.append(ATTRIBUTE_COMMAND_TYPE + " "); } if ( ! es.isEmpty()) { addToWarnings(xmlReader, ELEMENT_MACRO_COMMAND + " is missing attribute(s): " + es); return NULL; } bool objectTypeValid(false); WuQMacroWidgetTypeEnum::Enum widgetType = WuQMacroWidgetTypeEnum::fromName(widgetTypeString.toString(), &objectTypeValid); if (! objectTypeValid) { es.append(widgetTypeString.toString() + " is not valid for attribute " + ATTRIBUTE_WIDGET_TYPE + " "); return NULL; } if ( ! es.isEmpty()) { addToWarnings(xmlReader, es); return NULL; } const int32_t versionNumber = (versionString.isEmpty() ? 1 : versionString.toInt()); bool valid(false); float delayValue = delayString.toFloat(&valid); if ( ! valid) { delayValue = 1.0; } MacroCommandContent* macroCommandContent = new MacroCommandContent(); macroCommandContent->m_commandType = commandType; macroCommandContent->m_customOperationTypeName = customOperationCommandNameString.toString(); macroCommandContent->m_widgetType = widgetType; macroCommandContent->m_version = versionNumber; macroCommandContent->m_objectName = objectName.toString(); macroCommandContent->m_descriptiveName = descriptiveNameString.toString(); macroCommandContent->m_delay = delayValue; return macroCommandContent; } /** * @param xmlReader * The XML stream reader * @return Read and return the mouse event information */ WuQMacroMouseEventInfo* WuQMacroGroupXmlStreamReader::readMacroMouseEventInfo(QXmlStreamReader& xmlReader) { const QXmlStreamAttributes attributes = xmlReader.attributes(); const QString mouseEventTypeString = attributes.value(ATTRIBUTE_MOUSE_EVENT_TYPE).toString(); const QString xLocalString = attributes.value(ATTRIBUTE_MOUSE_LOCAL_X).toString(); const QString yLocalString = attributes.value(ATTRIBUTE_MOUSE_LOCAL_Y).toString(); const QString mouseButtonString = attributes.value(ATTRIBUTE_MOUSE_BUTTON).toString(); const QString mouseButtonsMaskString = attributes.value(ATTRIBUTE_MOUSE_BUTTONS_MASK).toString(); const QString keyboardModifiersMaskString = attributes.value(ATTRIBUTE_MOUSE_KEYBOARD_MODIFIERS_MASK).toString(); const QString widgetWidthString = attributes.value(ATTRIBUTE_MOUSE_WIDGET_WIDTH).toString(); const QString widgetHeightString = attributes.value(ATTRIBUTE_MOUSE_WIDGET_HEIGHT).toString(); QString es; if (mouseEventTypeString.isEmpty()) es.append(ATTRIBUTE_MOUSE_EVENT_TYPE + " "); if (mouseButtonString.isEmpty()) es.append(ATTRIBUTE_MOUSE_BUTTON + " "); if (mouseButtonsMaskString.isEmpty()) es.append(ATTRIBUTE_MOUSE_BUTTONS_MASK + " "); if (keyboardModifiersMaskString.isEmpty()) es.append(ATTRIBUTE_MOUSE_KEYBOARD_MODIFIERS_MASK + " "); if (widgetWidthString.isEmpty()) es.append(ATTRIBUTE_MOUSE_WIDGET_WIDTH + " "); if (widgetHeightString.isEmpty()) es.append(ATTRIBUTE_MOUSE_WIDGET_HEIGHT + " "); if ( ! es.isEmpty()) { addToWarnings(xmlReader, ELEMENT_MACRO_COMMAND_MOUSE_EVENT_INFO + " is missing required attribute(s): " + es); return NULL; } bool validMouseEventTypeFlag(false); const WuQMacroMouseEventTypeEnum::Enum mouseEventType = WuQMacroMouseEventTypeEnum::fromName(mouseEventTypeString, &validMouseEventTypeFlag); if ( ! validMouseEventTypeFlag) { addToWarnings(xmlReader, mouseEventTypeString + " is not valid for attribute " + ATTRIBUTE_MOUSE_EVENT_TYPE); return NULL; } WuQMacroMouseEventInfo* mouseInfo = new WuQMacroMouseEventInfo(mouseEventType, mouseButtonString.toUInt(), mouseButtonsMaskString.toUInt(), keyboardModifiersMaskString.toUInt(), widgetWidthString.toInt(), widgetHeightString.toInt()); if (( ! xLocalString.isEmpty()) && ( ! yLocalString.isEmpty())) { mouseInfo->addLocalXY(xLocalString.toInt(), yLocalString.toInt()); } QString xyString = xmlReader.readElementText(); if ( ! xyString.isEmpty()) { QTextStream stream(&xyString); while ( ! stream.atEnd()) { int32_t x, y; stream >> x; if ( ! stream.atEnd()) { stream >> y; mouseInfo->addLocalXY(x, y); } } } return mouseInfo; } /** * Add to the warning message. Warnings are used to skip over invalid * elements instead of declaring the entire XML invalid. * * @param xmlReader * The XML stream reader * @param warning * The warning message */ void WuQMacroGroupXmlStreamReader::addToWarnings(QXmlStreamReader& xmlReader, const QString& warning) { if ( ! m_warningMessage.isEmpty()) { m_warningMessage.append("\n"); } m_warningMessage.append("Line=" + QString::number(xmlReader.lineNumber()) + ", Column=" + QString::number(xmlReader.columnNumber()) + ": " + warning); } connectome-workbench-1.4.2/src/Common/WuQMacroGroupXmlStreamReader.h000066400000000000000000000070511360521144700255210ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_GROUP_XML_STREAM_READER_H__ #define __WU_Q_MACRO_GROUP_XML_STREAM_READER_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "WuQMacroCommandTypeEnum.h" #include "WuQMacroGroupXmlStreamBase.h" #include "WuQMacroWidgetTypeEnum.h" class QXmlStreamReader; namespace caret { class WuQMacro; class WuQMacroCommand; class WuQMacroCommandParameter; class WuQMacroGroup; class WuQMacroMouseEventInfo; class WuQMacroGroupXmlStreamReader : public WuQMacroGroupXmlStreamBase { public: WuQMacroGroupXmlStreamReader(); virtual ~WuQMacroGroupXmlStreamReader(); WuQMacroGroupXmlStreamReader(const WuQMacroGroupXmlStreamReader&) = delete; WuQMacroGroupXmlStreamReader& operator=(const WuQMacroGroupXmlStreamReader&) = delete; bool readFromString(const QString& xmlString, WuQMacroGroup* macroGroup, QString& errorMessageOut); void readMacroGroup(QXmlStreamReader& xmlReader, WuQMacroGroup* macroGroup); // ADD_NEW_METHODS_HERE private: class MacroCommandContent { public: WuQMacroCommandTypeEnum::Enum m_commandType = WuQMacroCommandTypeEnum::WIDGET; QString m_customOperationTypeName; WuQMacroMouseEventInfo* m_mouseInfo = NULL; // DO NOT DELETE WuQMacroWidgetTypeEnum::Enum m_widgetType = WuQMacroWidgetTypeEnum::INVALID; int32_t m_version = - 1; QString m_objectName; QString m_descriptiveName; QString m_toolTip; float m_delay = 1.0f; std::vector m_parameters; // DO NOT DELETE }; WuQMacroMouseEventInfo* readMacroMouseEventInfo(QXmlStreamReader& xmlReader); void readVersionOne(QXmlStreamReader& xmlReader, WuQMacroGroup* macroGroup); WuQMacro* readMacroVersionOne(QXmlStreamReader& xmlReader); MacroCommandContent* readMacroCommandAttributesVersionOne(QXmlStreamReader& xmlReader); WuQMacroCommand* readMacroCommandVersionOne(QXmlStreamReader& xmlReader); WuQMacroCommandParameter* readMacroCommandParameter(QXmlStreamReader& xmlReader); void addToWarnings(QXmlStreamReader& xmlReader, const QString& warning); QString m_warningMessage; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_MACRO_GROUP_XML_STREAM_READER_DECLARE__ // #endif // __WU_Q_MACRO_GROUP_XML_STREAM_READER_DECLARE__ } // namespace #endif //__WU_Q_MACRO_GROUP_XML_STREAM_READER_H__ connectome-workbench-1.4.2/src/Common/WuQMacroGroupXmlStreamWriter.cxx000066400000000000000000000240711360521144700261470ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_GROUP_XML_STREAM_WRITER_DECLARE__ #include "WuQMacroGroupXmlStreamWriter.h" #undef __WU_Q_MACRO_GROUP_XML_STREAM_WRITER_DECLARE__ #include #include #include "CaretAssert.h" #include "WuQMacro.h" #include "WuQMacroCommand.h" #include "WuQMacroCommandParameter.h" #include "WuQMacroGroup.h" #include "WuQMacroMouseEventInfo.h" using namespace caret; /** * \class caret::WuQMacroGroupXmlStreamWriter * \brief Writes contents of macro group to XML format * \ingroup Common */ /** * Constructor */ WuQMacroGroupXmlStreamWriter::WuQMacroGroupXmlStreamWriter() : WuQMacroGroupXmlStreamBase() { } /** * Destructor. */ WuQMacroGroupXmlStreamWriter::~WuQMacroGroupXmlStreamWriter() { } /** * Wite the given macro group to the given xml writer * * @param xmlWriter * The XML stream writer * @param macroGroup * Macro group that is written to XML */ void WuQMacroGroupXmlStreamWriter::writeXml(QXmlStreamWriter* xmlWriter, const WuQMacroGroup* macroGroup) { CaretAssert(xmlWriter); CaretAssert(macroGroup); if (macroGroup->getNumberOfMacros() <= 0) { return; } m_xmlStreamWriter = xmlWriter; m_xmlStreamWriter->writeStartElement(ELEMENT_MACRO_GROUP); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_NAME, macroGroup->getName()); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_VERSION, "1"); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_UNIQUE_IDENTIFIER, macroGroup->getUniqueIdentifier()); const int32_t numMacros = macroGroup->getNumberOfMacros(); for (int32_t i = 0; i < numMacros; i++) { const WuQMacro* macro = macroGroup->getMacroAtIndex(i); CaretAssert(macro); writeMacroToXML(macro); } m_xmlStreamWriter->writeEndElement(); m_xmlStreamWriter = NULL; } /** * Write the macro group to a text string * * @param macroGroup * Macro group that is written to XML * @param contentTextString * Pointer to string to which XML is written */ void WuQMacroGroupXmlStreamWriter::writeToString(const WuQMacroGroup* macroGroup, QString& contentTextString) { CaretAssert(macroGroup); contentTextString.clear(); std::unique_ptr xmlWriter(new QXmlStreamWriter(&contentTextString)); xmlWriter->setAutoFormatting(true); writeXml(xmlWriter.get(), macroGroup); } /** * Write a macro to XML format * * @param macro * The macro */ void WuQMacroGroupXmlStreamWriter::writeMacroToXML(const WuQMacro* macro) { CaretAssert(macro); m_xmlStreamWriter->writeStartElement(ELEMENT_MACRO); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_NAME, macro->getName()); const QString shortCutText = WuQMacroShortCutKeyEnum::toName(macro->getShortCutKey()); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_SHORT_CUT_KEY, shortCutText); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_UNIQUE_IDENTIFIER, macro->getUniqueIdentifier()); m_xmlStreamWriter->writeTextElement(ELEMENT_DESCRIPTION, macro->getDescription()); const int32_t numCommands = macro->getNumberOfMacroCommands(); for (int32_t i = 0; i < numCommands; i++) { const WuQMacroCommand* macroCommand = macro->getMacroCommandAtIndex(i); CaretAssert(macroCommand); writeMacroCommandToXML(macroCommand); } m_xmlStreamWriter->writeEndElement(); } /** * Write a macro command to XML format * * @param macroCommand * The macro command */ void WuQMacroGroupXmlStreamWriter::writeMacroCommandToXML(const WuQMacroCommand* macroCommand) { CaretAssert(macroCommand); m_xmlStreamWriter->writeStartElement(ELEMENT_MACRO_COMMAND); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_NAME, macroCommand->getObjectName()); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_COMMAND_TYPE, WuQMacroCommandTypeEnum::toName(macroCommand->getCommandType())); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_WIDGET_TYPE, WuQMacroWidgetTypeEnum::toName(macroCommand->getWidgetType())); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_VERSION, QString::number(macroCommand->getVersion())); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_OBJECT_DESCRIPTIVE_NAME, macroCommand->getDescriptiveName()); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_DELAY, QString::number(macroCommand->getDelayInSeconds(), 'f', 2)); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_CUSTOM_OPERATION_TYPE_NAME, macroCommand->getCustomOperationTypeName()); switch (macroCommand->getCommandType()) { case WuQMacroCommandTypeEnum::CUSTOM_OPERATION: break; case WuQMacroCommandTypeEnum::MOUSE: writeMacroMouseEventInfo(macroCommand->getMouseEventInfo()); break; case WuQMacroCommandTypeEnum::WIDGET: break; } const QString toolTip = macroCommand->getObjectToolTip(); if (toolTip != NULL) { m_xmlStreamWriter->writeTextElement(ELEMENT_MACRO_COMMAND_TOOL_TIP, toolTip); } const int32_t numberOfParameters = macroCommand->getNumberOfParameters(); for (int32_t i = 0; i < numberOfParameters; i++) { const WuQMacroCommandParameter* parameter = macroCommand->getParameterAtIndex(i); CaretAssert(parameter); m_xmlStreamWriter->writeStartElement(ELEMENT_MACRO_COMMAND_PARAMETER); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_MACRO_COMMAND_PARAMETER_DATA_TYPE, WuQMacroDataValueTypeEnum::toName(parameter->getDataType())); const QVariant value(parameter->getValue()); QString stringValue; switch (parameter->getDataType()) { case WuQMacroDataValueTypeEnum::INVALID: break; case WuQMacroDataValueTypeEnum::AXIS: stringValue = value.toString(); break; case WuQMacroDataValueTypeEnum::BOOLEAN: stringValue = (value.toBool() ? VALUE_BOOL_TRUE : VALUE_BOOL_FALSE); break; case WuQMacroDataValueTypeEnum::FLOAT: stringValue = QString::number(value.toFloat()); break; case WuQMacroDataValueTypeEnum::INTEGER: stringValue = QString::number(value.toInt()); break; case WuQMacroDataValueTypeEnum::MOUSE: stringValue = "MouseEvent"; break; case WuQMacroDataValueTypeEnum::NONE: stringValue = ""; break; case WuQMacroDataValueTypeEnum::STRING: stringValue = value.toString(); break; case WuQMacroDataValueTypeEnum::STRING_LIST: stringValue = value.toString(); break; } m_xmlStreamWriter->writeAttribute(ATTRIBUTE_MACRO_COMMAND_PARAMETER_NAME, parameter->getName()); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_MACRO_COMMAND_PARAMETER_CUSTOM_DATA_TYPE, parameter->getCustomDataType()); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_MACRO_COMMAND_PARAMETER_VALUE, stringValue); m_xmlStreamWriter->writeEndElement(); } m_xmlStreamWriter->writeEndElement(); } /** * Write a macro mouse event info to XML format * * @param mouseEventInfo * The macro mouse event info */ void WuQMacroGroupXmlStreamWriter::writeMacroMouseEventInfo(const WuQMacroMouseEventInfo* mouseEventInfo) { CaretAssert(mouseEventInfo); m_xmlStreamWriter->writeStartElement(ELEMENT_MACRO_COMMAND_MOUSE_EVENT_INFO); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_MOUSE_BUTTON, QString::number(mouseEventInfo->getMouseButton())); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_MOUSE_BUTTONS_MASK, QString::number(mouseEventInfo->getMouseButtonsMask())); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_MOUSE_EVENT_TYPE, WuQMacroMouseEventTypeEnum::toName(mouseEventInfo->getMouseEventType())); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_MOUSE_KEYBOARD_MODIFIERS_MASK, QString::number(mouseEventInfo->getKeyboardModifiersMask())); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_MOUSE_WIDGET_WIDTH, QString::number(mouseEventInfo->getWidgetWidth())); m_xmlStreamWriter->writeAttribute(ATTRIBUTE_MOUSE_WIDGET_HEIGHT, QString::number(mouseEventInfo->getWidgetHeight())); QString xyString; QTextStream textStream(&xyString); const int32_t numXY = mouseEventInfo->getNumberOfLocalXY(); for (int32_t i = 0; i < numXY; i++) { textStream << mouseEventInfo->getLocalX(i) << " " << mouseEventInfo->getLocalY(i) << " "; } m_xmlStreamWriter->writeCharacters(xyString); m_xmlStreamWriter->writeEndElement(); } connectome-workbench-1.4.2/src/Common/WuQMacroGroupXmlStreamWriter.h000066400000000000000000000045101360521144700255700ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_GROUP_XML_STREAM_WRITER_H__ #define __WU_Q_MACRO_GROUP_XML_STREAM_WRITER_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "WuQMacroGroupXmlStreamBase.h" class QXmlStreamWriter; namespace caret { class WuQMacro; class WuQMacroCommand; class WuQMacroGroup; class WuQMacroMouseEventInfo; class WuQMacroGroupXmlStreamWriter : public WuQMacroGroupXmlStreamBase { public: WuQMacroGroupXmlStreamWriter(); virtual ~WuQMacroGroupXmlStreamWriter(); void writeXml(QXmlStreamWriter* xmlStreamWriter, const WuQMacroGroup* macroGroup); void writeToString(const WuQMacroGroup* macroGroup, QString& contentTextString); WuQMacroGroupXmlStreamWriter(const WuQMacroGroupXmlStreamWriter&) = delete; WuQMacroGroupXmlStreamWriter& operator=(const WuQMacroGroupXmlStreamWriter&) = delete; // ADD_NEW_METHODS_HERE private: void writeMacroToXML(const WuQMacro* macro); void writeMacroCommandToXML(const WuQMacroCommand* macroCommand); void writeMacroMouseEventInfo(const WuQMacroMouseEventInfo* mouseEventInfo); QXmlStreamWriter* m_xmlStreamWriter; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_MACRO_GROUP_XML_STREAM_WRITER_DECLARE__ // #endif // __WU_Q_MACRO_GROUP_XML_STREAM_WRITER_DECLARE__ } // namespace #endif //__WU_Q_MACRO_GROUP_XML_STREAM_WRITER_H__ connectome-workbench-1.4.2/src/Common/WuQMacroModeEnum.cxx000066400000000000000000000250461360521144700235350ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __WU_Q_MACRO_MODE_ENUM_DECLARE__ #include "WuQMacroModeEnum.h" #undef __WU_Q_MACRO_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::WuQMacroModeEnum * \brief * * * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_wuQMacroModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void wuQMacroModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "WuQMacroModeEnum.h" * * Instatiate: * m_wuQMacroModeEnumComboBox = new EnumComboBoxTemplate(this); * m_wuQMacroModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_wuQMacroModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(wuQMacroModeEnumComboBoxItemActivated())); * * Update the selection: * m_wuQMacroModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const WuQMacroModeEnum::Enum VARIABLE = m_wuQMacroModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ WuQMacroModeEnum::WuQMacroModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ WuQMacroModeEnum::~WuQMacroModeEnum() { } /** * Initialize the enumerated metadata. */ void WuQMacroModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(WuQMacroModeEnum(OFF, "OFF", "Off")); enumData.push_back(WuQMacroModeEnum(RECORDING_INSERT_COMMANDS, "RECORDING_INSERT_COMMANDS", "Recording Insert Commands")); enumData.push_back(WuQMacroModeEnum(RECORDING_NEW_MACRO, "RECORDING_NEW_MACRO", "Recording New Macro")); enumData.push_back(WuQMacroModeEnum(RUNNING, "RUNNING", "Running")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const WuQMacroModeEnum* WuQMacroModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const WuQMacroModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WuQMacroModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WuQMacroModeEnum::Enum WuQMacroModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WuQMacroModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WuQMacroModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WuQMacroModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WuQMacroModeEnum::Enum WuQMacroModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WuQMacroModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WuQMacroModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t WuQMacroModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ WuQMacroModeEnum::Enum WuQMacroModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WuQMacroModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WuQMacroModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void WuQMacroModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WuQMacroModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(WuQMacroModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WuQMacroModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(WuQMacroModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/WuQMacroModeEnum.h000066400000000000000000000062501360521144700231560ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_MODE_ENUM_H__ #define __WU_Q_MACRO_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class WuQMacroModeEnum { public: /** * Enumerated values. */ enum Enum { /** Off */ OFF, /** Recording and inserting commands into a macro */ RECORDING_INSERT_COMMANDS, /** Recording a new macro */ RECORDING_NEW_MACRO, /** Macro is running */ RUNNING }; ~WuQMacroModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: WuQMacroModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const WuQMacroModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __WU_Q_MACRO_MODE_ENUM_DECLARE__ std::vector WuQMacroModeEnum::enumData; bool WuQMacroModeEnum::initializedFlag = false; int32_t WuQMacroModeEnum::integerCodeCounter = 0; #endif // __WU_Q_MACRO_MODE_ENUM_DECLARE__ } // namespace #endif //__WU_Q_MACRO_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Common/WuQMacroMouseEventInfo.cxx000066400000000000000000000157721360521144700247370ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_MOUSE_EVENT_INFO_DECLARE__ #include "WuQMacroMouseEventInfo.h" #undef __WU_Q_MACRO_MOUSE_EVENT_INFO_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::WuQMacroMouseEventInfo * \brief Information about and related to a QMouseEvent * \ingroup Common */ /** * Constructor. * @param mouseEventType * Type of mouse event * @param mouseButton * Button that caused the event * @param mouseButtonsMask * Mask with buttons down during mouse event * @param keyboardModifiersMask * Mask with any keys down during mouse event * @param widgetWidth * Width of widget where mouse event occurred * @param widgetHeight * Width of widget where mouse event occurred */ WuQMacroMouseEventInfo::WuQMacroMouseEventInfo(const WuQMacroMouseEventTypeEnum::Enum mouseEventType, const uint32_t mouseButton, const uint32_t mouseButtonsMask, const uint32_t keyboardModifiersMask, const int32_t widgetWidth, const int32_t widgetHeight) : CaretObject(), m_mouseEventType(mouseEventType), m_mouseButton(mouseButton), m_mouseButtonsMask(mouseButtonsMask), m_keyboardModifiersMask(keyboardModifiersMask), m_widgetWidth(widgetWidth), m_widgetHeight(widgetHeight) { } /** * Destructor. */ WuQMacroMouseEventInfo::~WuQMacroMouseEventInfo() { } /** * Copy constructor. * @param obj * Object that is copied. */ WuQMacroMouseEventInfo::WuQMacroMouseEventInfo(const WuQMacroMouseEventInfo& obj) : CaretObject(obj) { this->copyHelperWuQMacroMouseEventInfo(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ WuQMacroMouseEventInfo& WuQMacroMouseEventInfo::operator=(const WuQMacroMouseEventInfo& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperWuQMacroMouseEventInfo(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void WuQMacroMouseEventInfo::copyHelperWuQMacroMouseEventInfo(const WuQMacroMouseEventInfo& obj) { m_mouseEventType = obj.m_mouseEventType; m_localXY = obj.m_localXY; m_mouseButton = obj.m_mouseButton; m_mouseButtonsMask = obj.m_mouseButtonsMask; m_keyboardModifiersMask = obj.m_keyboardModifiersMask; m_widgetWidth = obj.m_widgetWidth; m_widgetHeight = obj.m_widgetHeight; } /** * Widget size may change so scale the x and y position to fit new widget size * * @param newWidth * Current width of widget * @param newHeight * Current height of widget * @param localX * Local X position * @param localY * Local Y position * @param xLocalOut * Output with adjusted local-X position * @param yLocalOut * Output with adjusted local-Y position */ void WuQMacroMouseEventInfo::getLocalPositionRescaledToWidgetSize(const int32_t newWidth, const int32_t newHeight, const int32_t localX, const int32_t localY, int32_t& xLocalOut, int32_t& yLocalOut) const { xLocalOut = localX; yLocalOut = localY; if ((newWidth != m_widgetWidth) || (newHeight != m_widgetHeight)) { const float normalizedWidth = (static_cast(localX) / static_cast(m_widgetWidth)); const float normalizedHeight = (static_cast(localY) / static_cast(m_widgetHeight)); xLocalOut = (newWidth * normalizedWidth); yLocalOut = (newHeight * normalizedHeight); } } /** * @return Type of the mouse event */ WuQMacroMouseEventTypeEnum::Enum WuQMacroMouseEventInfo::getMouseEventType() const { return m_mouseEventType; } /** * Append local mouse X/Y coordinates * * @param localX * The local X-coordinate * @param localY * The local Y-coordinate */ void WuQMacroMouseEventInfo::addLocalXY(const int32_t localX, const int32_t localY) { m_localXY.push_back(localX); m_localXY.push_back(localY); } int32_t WuQMacroMouseEventInfo::getNumberOfLocalXY() const { const int32_t num = (m_localXY.size() / 2); return num; } /** * @return X-coordinate of mouse relative to widget at the given index * * @param index * Index of the coordinate */ int32_t WuQMacroMouseEventInfo::getLocalX(const int32_t index) const { const int32_t offset = (index * 2); CaretAssertVectorIndex(m_localXY, offset); return m_localXY[offset]; } /** * @return Y-coordinate of mouse relative to widget at the given index * * @param index * Index of the coordinate */ int32_t WuQMacroMouseEventInfo::getLocalY(const int32_t index) const { const int32_t offset = (index * 2) + 1; CaretAssertVectorIndex(m_localXY, offset); return m_localXY[offset]; } /** * @return Button that caused the event */ uint32_t WuQMacroMouseEventInfo::getMouseButton() const { return m_mouseButton; } /** * @return Mask with buttons down during mouse event */ uint32_t WuQMacroMouseEventInfo::getMouseButtonsMask() const { return m_mouseButtonsMask; } /** * @@return Mask with any keys down during mouse event */ uint32_t WuQMacroMouseEventInfo::getKeyboardModifiersMask() const { return m_keyboardModifiersMask; } /** * @return Width of widget where mouse event occurred */ int32_t WuQMacroMouseEventInfo::getWidgetWidth() const { return m_widgetWidth; } /** * @return Width of widget where mouse event occurred */ int32_t WuQMacroMouseEventInfo::getWidgetHeight() const { return m_widgetHeight; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString WuQMacroMouseEventInfo::toString() const { return "WuQMacroMouseEventInfo"; } connectome-workbench-1.4.2/src/Common/WuQMacroMouseEventInfo.h000066400000000000000000000075071360521144700243610ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_MOUSE_EVENT_INFO_H__ #define __WU_Q_MACRO_MOUSE_EVENT_INFO_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "WuQMacroMouseEventTypeEnum.h" namespace caret { class WuQMacroMouseEventInfo : public CaretObject { public: WuQMacroMouseEventInfo(const WuQMacroMouseEventTypeEnum::Enum mouseEventType, const uint32_t mouseButton, const uint32_t mouseButtonsMask, const uint32_t keyboardModifiersMask, const int32_t widgetWidth, const int32_t widgetHeight); virtual ~WuQMacroMouseEventInfo(); WuQMacroMouseEventInfo(const WuQMacroMouseEventInfo&); WuQMacroMouseEventInfo& operator=(const WuQMacroMouseEventInfo&); void getLocalPositionRescaledToWidgetSize(const int32_t widgetWidth, const int32_t widgetHeight, const int32_t localX, const int32_t localY, int32_t& xOut, int32_t& yOut) const; WuQMacroMouseEventTypeEnum::Enum getMouseEventType() const; void addLocalXY(const int32_t localX, const int32_t localY); int32_t getNumberOfLocalXY() const; int32_t getLocalX(const int32_t index) const; int32_t getLocalY(const int32_t index) const; uint32_t getMouseButton() const; uint32_t getMouseButtonsMask() const; uint32_t getKeyboardModifiersMask() const; int32_t getWidgetWidth() const; int32_t getWidgetHeight() const; // ADD_NEW_METHODS_HERE virtual AString toString() const; private: void copyHelperWuQMacroMouseEventInfo(const WuQMacroMouseEventInfo& obj); /** Type of mouse event */ WuQMacroMouseEventTypeEnum::Enum m_mouseEventType; /** Positions of mouse relative to widget */ std::vector m_localXY; /** Button that caused the event */ uint32_t m_mouseButton; /** Mask with buttons down during mouse event */ uint32_t m_mouseButtonsMask; /** Mask with any keys down during mouse event */ uint32_t m_keyboardModifiersMask; /** Width of widget where mouse event occurred */ int32_t m_widgetWidth; /** Width of widget where mouse event occurred */ int32_t m_widgetHeight; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_MACRO_MOUSE_EVENT_INFO_DECLARE__ // #endif // __WU_Q_MACRO_MOUSE_EVENT_INFO_DECLARE__ } // namespace #endif //__WU_Q_MACRO_MOUSE_EVENT_INFO_H__ connectome-workbench-1.4.2/src/Common/WuQMacroMouseEventTypeEnum.cxx000066400000000000000000000262071360521144700256050ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __WU_Q_MACRO_MOUSE_EVENT_TYPE_ENUM_DECLARE__ #include "WuQMacroMouseEventTypeEnum.h" #undef __WU_Q_MACRO_MOUSE_EVENT_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::WuQMacroMouseEventTypeEnum * \brief Types of mouse events * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_wuQMacroMouseEventTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void wuQMacroMouseEventTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "WuQMacroMouseEventTypeEnum.h" * * Instatiate: * m_wuQMacroMouseEventTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_wuQMacroMouseEventTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_wuQMacroMouseEventTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(wuQMacroMouseEventTypeEnumComboBoxItemActivated())); * * Update the selection: * m_wuQMacroMouseEventTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const WuQMacroMouseEventTypeEnum::Enum VARIABLE = m_wuQMacroMouseEventTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ WuQMacroMouseEventTypeEnum::WuQMacroMouseEventTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ WuQMacroMouseEventTypeEnum::~WuQMacroMouseEventTypeEnum() { } /** * Initialize the enumerated metadata. */ void WuQMacroMouseEventTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(WuQMacroMouseEventTypeEnum(BUTTON_PRESS, "BUTTON_PRESS", "Button-Press")); enumData.push_back(WuQMacroMouseEventTypeEnum(BUTTON_RELEASE, "BUTTON_RELEASE", "Button-Release")); enumData.push_back(WuQMacroMouseEventTypeEnum(DOUBLE_CLICKED, "DOUBLE_CLICKED", "Double-Clicked")); enumData.push_back(WuQMacroMouseEventTypeEnum(MOVE, "MOVE", "Move")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const WuQMacroMouseEventTypeEnum* WuQMacroMouseEventTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const WuQMacroMouseEventTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WuQMacroMouseEventTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroMouseEventTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WuQMacroMouseEventTypeEnum::Enum WuQMacroMouseEventTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WuQMacroMouseEventTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroMouseEventTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WuQMacroMouseEventTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WuQMacroMouseEventTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroMouseEventTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WuQMacroMouseEventTypeEnum::Enum WuQMacroMouseEventTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WuQMacroMouseEventTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroMouseEventTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WuQMacroMouseEventTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t WuQMacroMouseEventTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroMouseEventTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ WuQMacroMouseEventTypeEnum::Enum WuQMacroMouseEventTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WuQMacroMouseEventTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroMouseEventTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WuQMacroMouseEventTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void WuQMacroMouseEventTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WuQMacroMouseEventTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(WuQMacroMouseEventTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WuQMacroMouseEventTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(WuQMacroMouseEventTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/WuQMacroMouseEventTypeEnum.h000066400000000000000000000064631360521144700252340ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_MOUSE_EVENT_TYPE_ENUM_H__ #define __WU_Q_MACRO_MOUSE_EVENT_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class WuQMacroMouseEventTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Mouse button is pressed */ BUTTON_PRESS, /** Mouse button is released */ BUTTON_RELEASE, /** Mouse is double-clicked */ DOUBLE_CLICKED, /** Mouse is moved */ MOVE }; ~WuQMacroMouseEventTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: WuQMacroMouseEventTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const WuQMacroMouseEventTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __WU_Q_MACRO_MOUSE_EVENT_TYPE_ENUM_DECLARE__ std::vector WuQMacroMouseEventTypeEnum::enumData; bool WuQMacroMouseEventTypeEnum::initializedFlag = false; int32_t WuQMacroMouseEventTypeEnum::integerCodeCounter = 0; #endif // __WU_Q_MACRO_MOUSE_EVENT_TYPE_ENUM_DECLARE__ } // namespace #endif //__WU_Q_MACRO_MOUSE_EVENT_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Common/WuQMacroShortCutKeyEnum.cxx000066400000000000000000000414721360521144700250760ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __WU_Q_MACRO_SHORT_CUT_KEY_ENUM_DECLARE__ #include "WuQMacroShortCutKeyEnum.h" #undef __WU_Q_MACRO_SHORT_CUT_KEY_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::WuQMacroShortCutKeyEnum * \brief Shortcut keys for running macros * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_wuQMacroShortCutKeyEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void wuQMacroShortCutKeyEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "WuQMacroShortCutKeyEnum.h" * * Instatiate: * m_wuQMacroShortCutKeyEnumComboBox = new EnumComboBoxTemplate(this); * m_wuQMacroShortCutKeyEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_wuQMacroShortCutKeyEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(wuQMacroShortCutKeyEnumComboBoxItemActivated())); * * Update the selection: * m_wuQMacroShortCutKeyEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const WuQMacroShortCutKeyEnum::Enum VARIABLE = m_wuQMacroShortCutKeyEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ WuQMacroShortCutKeyEnum::WuQMacroShortCutKeyEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ WuQMacroShortCutKeyEnum::~WuQMacroShortCutKeyEnum() { } /** * Initialize the enumerated metadata. */ void WuQMacroShortCutKeyEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(WuQMacroShortCutKeyEnum(Key_None, "Key_None", "None")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_A, "Key_A", "A")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_B, "Key_B", "B")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_C, "Key_C", "C")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_D, "Key_D", "D")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_E, "Key_E", "E")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_F, "Key_F", "F")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_G, "Key_G", "G")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_H, "Key_H", "H")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_I, "Key_I", "I")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_J, "Key_J", "J")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_K, "Key_K", "K")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_L, "Key_L", "L")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_M, "Key_M", "M")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_N, "Key_N", "N")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_O, "Key_O", "O")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_P, "Key_P", "P")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_Q, "Key_Q", "Q")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_R, "Key_R", "R")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_S, "Key_S", "S")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_T, "Key_T", "T")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_U, "Key_U", "U")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_V, "Key_V", "V")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_W, "Key_W", "W")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_X, "Key_X", "X")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_Y, "Key_Y", "Y")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_Z, "Key_Z", "Z")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_0, "Key_0", "0")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_1, "Key_1", "1")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_2, "Key_2", "2")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_3, "Key_3", "3")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_4, "Key_4", "4")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_5, "Key_5", "5")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_6, "Key_6", "6")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_7, "Key_7", "7")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_8, "Key_8", "8")); enumData.push_back(WuQMacroShortCutKeyEnum(Key_9, "Key_9", "9")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const WuQMacroShortCutKeyEnum* WuQMacroShortCutKeyEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const WuQMacroShortCutKeyEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WuQMacroShortCutKeyEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroShortCutKeyEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WuQMacroShortCutKeyEnum::Enum WuQMacroShortCutKeyEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WuQMacroShortCutKeyEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroShortCutKeyEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WuQMacroShortCutKeyEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WuQMacroShortCutKeyEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroShortCutKeyEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WuQMacroShortCutKeyEnum::Enum WuQMacroShortCutKeyEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WuQMacroShortCutKeyEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroShortCutKeyEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WuQMacroShortCutKeyEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t WuQMacroShortCutKeyEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroShortCutKeyEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ WuQMacroShortCutKeyEnum::Enum WuQMacroShortCutKeyEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WuQMacroShortCutKeyEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroShortCutKeyEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WuQMacroShortCutKeyEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void WuQMacroShortCutKeyEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WuQMacroShortCutKeyEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(WuQMacroShortCutKeyEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WuQMacroShortCutKeyEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(WuQMacroShortCutKeyEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } /** * Find the data type corresponding to a Qt::Key enum value. * If not valid, the none key (Key_None) is returned. * * @param qtKeyEnum * The Qt::Key enum value * @return * Enum for integer code. */ WuQMacroShortCutKeyEnum::Enum WuQMacroShortCutKeyEnum::fromQtKeyEnum(const int32_t qtKeyEnum) { if (initializedFlag == false) initialize(); int32_t shortCutKeyInteger = -1; if ((qtKeyEnum >= Qt::Key_A) && (qtKeyEnum <= Qt::Key_Z)) { shortCutKeyInteger = (WuQMacroShortCutKeyEnum::toIntegerCode(Key_A) + (qtKeyEnum - (int)Qt::Key_A)); } else if ((qtKeyEnum >= Qt::Key_0) && (qtKeyEnum <= Qt::Key_9)) { shortCutKeyInteger = (WuQMacroShortCutKeyEnum::toIntegerCode(Key_0) + (qtKeyEnum - (int)Qt::Key_0)); } else { shortCutKeyInteger = WuQMacroShortCutKeyEnum::toIntegerCode(Key_None); } bool validFlag = false; const Enum enumValue = WuQMacroShortCutKeyEnum::fromIntegerCode(shortCutKeyInteger, &validFlag); CaretAssert(validFlag); return enumValue; } connectome-workbench-1.4.2/src/Common/WuQMacroShortCutKeyEnum.h000066400000000000000000000102761360521144700245210ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_SHORT_CUT_KEY_ENUM_H__ #define __WU_Q_MACRO_SHORT_CUT_KEY_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class WuQMacroShortCutKeyEnum { public: /** * Enumerated values. */ enum Enum { /** No Key */ Key_None, /** */ Key_A, /** */ Key_B, /** */ Key_C, /** */ Key_D, /** */ Key_E, /** */ Key_F, /** */ Key_G, /** */ Key_H, /** */ Key_I, /** */ Key_J, /** */ Key_K, /** */ Key_L, /** */ Key_M, /** */ Key_N, /** */ Key_O, /** */ Key_P, /** */ Key_Q, /** */ Key_R, /** */ Key_S, /** */ Key_T, /** */ Key_U, /** */ Key_V, /** */ Key_W, /** */ Key_X, /** */ Key_Y, /** */ Key_Z, /** */ Key_0, /** */ Key_1, /** */ Key_2, /** */ Key_3, /** */ Key_4, /** */ Key_5, /** */ Key_6, /** */ Key_7, /** */ Key_8, /** */ Key_9 }; ~WuQMacroShortCutKeyEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); static Enum fromQtKeyEnum(const int32_t qtKeyEnum); private: WuQMacroShortCutKeyEnum(const Enum enumValue, const AString& name, const AString& guiName); static const WuQMacroShortCutKeyEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __WU_Q_MACRO_SHORT_CUT_KEY_ENUM_DECLARE__ std::vector WuQMacroShortCutKeyEnum::enumData; bool WuQMacroShortCutKeyEnum::initializedFlag = false; int32_t WuQMacroShortCutKeyEnum::integerCodeCounter = 0; #endif // __WU_Q_MACRO_SHORT_CUT_KEY_ENUM_DECLARE__ } // namespace #endif //__WU_Q_MACRO_SHORT_CUT_KEY_ENUM_H__ connectome-workbench-1.4.2/src/Common/WuQMacroStandardItemTypeEnum.cxx000066400000000000000000000276551360521144700261020ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __WU_Q_MACRO_STANDARD_ITEM_TYPE_ENUM_DECLARE__ #include "WuQMacroStandardItemTypeEnum.h" #undef __WU_Q_MACRO_STANDARD_ITEM_TYPE_ENUM_DECLARE__ #include #include "CaretAssert.h" using namespace caret; /** * \class caret::WuQMacroStandardItemTypeEnum * \brief Enumerated type for macro items in a QStandardItemModel * * Macros and macro command are displayed in the GUI using a * QStandardItem. The QStandardItem documentation recommends * overriding the type() method and returning a value greater * than or equal to UserType. This enumerated type provides * these values. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_wuQMacroStandardItemTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void wuQMacroStandardItemTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "WuQMacroStandardItemTypeEnum.h" * * Instatiate: * m_wuQMacroStandardItemTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_wuQMacroStandardItemTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_wuQMacroStandardItemTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(wuQMacroStandardItemTypeEnumComboBoxItemActivated())); * * Update the selection: * m_wuQMacroStandardItemTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const WuQMacroStandardItemTypeEnum::Enum VARIABLE = m_wuQMacroStandardItemTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param integerCode * Integer code for this enumerated value. * * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ WuQMacroStandardItemTypeEnum::WuQMacroStandardItemTypeEnum(const Enum enumValue, const int32_t integerCode, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCode; this->name = name; this->guiName = guiName; } /** * Destructor. */ WuQMacroStandardItemTypeEnum::~WuQMacroStandardItemTypeEnum() { } /** * Initialize the enumerated metadata. */ void WuQMacroStandardItemTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; int32_t typeOffset = QStandardItem::UserType + 1; const int32_t invalidType(typeOffset++); const int32_t macroType(typeOffset++); const int32_t macroCommandType(typeOffset++); enumData.push_back(WuQMacroStandardItemTypeEnum(INVALID, invalidType, "INVALID", "Invalid")); enumData.push_back(WuQMacroStandardItemTypeEnum(MACRO, macroType, "MACRO", "Macro")); enumData.push_back(WuQMacroStandardItemTypeEnum(MACRO_COMMAND, macroCommandType, "MACRO_COMMAND", "Macro Command")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const WuQMacroStandardItemTypeEnum* WuQMacroStandardItemTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const WuQMacroStandardItemTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WuQMacroStandardItemTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroStandardItemTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WuQMacroStandardItemTypeEnum::Enum WuQMacroStandardItemTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WuQMacroStandardItemTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroStandardItemTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WuQMacroStandardItemTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WuQMacroStandardItemTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroStandardItemTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WuQMacroStandardItemTypeEnum::Enum WuQMacroStandardItemTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WuQMacroStandardItemTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroStandardItemTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WuQMacroStandardItemTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t WuQMacroStandardItemTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroStandardItemTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ WuQMacroStandardItemTypeEnum::Enum WuQMacroStandardItemTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WuQMacroStandardItemTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroStandardItemTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WuQMacroStandardItemTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void WuQMacroStandardItemTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WuQMacroStandardItemTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(WuQMacroStandardItemTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WuQMacroStandardItemTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(WuQMacroStandardItemTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/WuQMacroStandardItemTypeEnum.h000066400000000000000000000062441360521144700255160ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_STANDARD_ITEM_TYPE_ENUM_H__ #define __WU_Q_MACRO_STANDARD_ITEM_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class WuQMacroStandardItemTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Type that is invalid */ INVALID, /** Type for a macro */ MACRO, /** Type for a macro command */ MACRO_COMMAND }; ~WuQMacroStandardItemTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: WuQMacroStandardItemTypeEnum(const Enum enumValue, const int32_t integerCode, const AString& name, const AString& guiName); static const WuQMacroStandardItemTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __WU_Q_MACRO_STANDARD_ITEM_TYPE_ENUM_DECLARE__ std::vector WuQMacroStandardItemTypeEnum::enumData; bool WuQMacroStandardItemTypeEnum::initializedFlag = false; #endif // __WU_Q_MACRO_STANDARD_ITEM_TYPE_ENUM_DECLARE__ } // namespace #endif //__WU_Q_MACRO_STANDARD_ITEM_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Common/WuQMacroWidgetTypeEnum.cxx000066400000000000000000000351271360521144700247370ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __WU_Q_MACRO_WIDGET_TYPE_ENUM_DECLARE__ #include "WuQMacroWidgetTypeEnum.h" #undef __WU_Q_MACRO_WIDGET_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::WuQMacroWidgetTypeEnum * \brief Enumerated type for widgets in a macro command * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_WuQMacroWidgetTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void WuQMacroWidgetTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "WuQMacroWidgetTypeEnum.h" * * Instatiate: * m_WuQMacroWidgetTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_WuQMacroWidgetTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_WuQMacroWidgetTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(WuQMacroWidgetTypeEnumComboBoxItemActivated())); * * Update the selection: * m_WuQMacroWidgetTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const WuQMacroWidgetTypeEnum::Enum VARIABLE = m_WuQMacroWidgetTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ WuQMacroWidgetTypeEnum::WuQMacroWidgetTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ WuQMacroWidgetTypeEnum::~WuQMacroWidgetTypeEnum() { } /** * Initialize the enumerated metadata. */ void WuQMacroWidgetTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(WuQMacroWidgetTypeEnum(INVALID, "INVALID", "Invalid")); enumData.push_back(WuQMacroWidgetTypeEnum(ACTION, "ACTION", "QAction")); enumData.push_back(WuQMacroWidgetTypeEnum(ACTION_CHECKABLE, "ACTION_CHECKABLE", "QActionCheckable")); enumData.push_back(WuQMacroWidgetTypeEnum(ACTION_GROUP, "ACTION_GROUP", "QActionGroup")); enumData.push_back(WuQMacroWidgetTypeEnum(BUTTON_GROUP, "BUTTON_GROUP", "QButtonGroup")); enumData.push_back(WuQMacroWidgetTypeEnum(CHECK_BOX, "CHECK_BOX", "QCheckBox")); enumData.push_back(WuQMacroWidgetTypeEnum(COMBO_BOX, "COMBO_BOX", "QComboBox")); enumData.push_back(WuQMacroWidgetTypeEnum(DOUBLE_SPIN_BOX, "DOUBLE_SPIN_BOX", "QDoubleSpinBox")); enumData.push_back(WuQMacroWidgetTypeEnum(LINE_EDIT, "LINE_EDIT", "QLineEdit")); enumData.push_back(WuQMacroWidgetTypeEnum(LIST_WIDGET, "LIST_WIDGET", "QListWidget")); enumData.push_back(WuQMacroWidgetTypeEnum(MACRO_WIDGET_ACTION, "MACRO_WIDGET_ACTION", "caret::WuQMacroWidgetAction")); enumData.push_back(WuQMacroWidgetTypeEnum(MENU, "MENU", "QMenu")); enumData.push_back(WuQMacroWidgetTypeEnum(PUSH_BUTTON, "PUSH_BUTTON", "QPushButton")); enumData.push_back(WuQMacroWidgetTypeEnum(PUSH_BUTTON_CHECKABLE, "PUSH_BUTTON_CHECKABLE", "QPushButtonCheckable")); enumData.push_back(WuQMacroWidgetTypeEnum(RADIO_BUTTON, "RADIO_BUTTON", "QRadioButton")); enumData.push_back(WuQMacroWidgetTypeEnum(SLIDER, "SLIDER", "QSlider")); enumData.push_back(WuQMacroWidgetTypeEnum(SPIN_BOX, "SPIN_BOX", "QSpinBox")); enumData.push_back(WuQMacroWidgetTypeEnum(TAB_BAR, "TAB_BAR", "QTabBar")); enumData.push_back(WuQMacroWidgetTypeEnum(TAB_WIDGET, "TAB_WIDGET", "QTabWidget")); enumData.push_back(WuQMacroWidgetTypeEnum(TOOL_BUTTON, "TOOL_BUTTON", "QToolButton")); enumData.push_back(WuQMacroWidgetTypeEnum(TOOL_BUTTON_CHECKABLE, "TOOL_BUTTON_CHECKABLE", "QToolButtonCheckable")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const WuQMacroWidgetTypeEnum* WuQMacroWidgetTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const WuQMacroWidgetTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WuQMacroWidgetTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroWidgetTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WuQMacroWidgetTypeEnum::Enum WuQMacroWidgetTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WuQMacroWidgetTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroWidgetTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WuQMacroWidgetTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WuQMacroWidgetTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroWidgetTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param guiNameIn * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WuQMacroWidgetTypeEnum::Enum WuQMacroWidgetTypeEnum::fromGuiName(const AString& guiNameIn, bool* isValidOut) { if (initializedFlag == false) initialize(); /* * Some widgets are extended from Qt Widgets and end with the Qt Name */ AString guiName(guiNameIn); for (auto alias : s_widgetClassNameAliases) { if (alias.second == guiName) { guiName = alias.first; break; } } bool validFlag = false; Enum enumValue = WuQMacroWidgetTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroWidgetTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WuQMacroWidgetTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t WuQMacroWidgetTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const WuQMacroWidgetTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ WuQMacroWidgetTypeEnum::Enum WuQMacroWidgetTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WuQMacroWidgetTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WuQMacroWidgetTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WuQMacroWidgetTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void WuQMacroWidgetTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WuQMacroWidgetTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(WuQMacroWidgetTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WuQMacroWidgetTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(WuQMacroWidgetTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } /** * Add a widget alias for class names * * @param widgetName * The name of a Qt widget class * @param aliasWidgetName * Name of class that is derived from Qt widget with name 'widgetName' */ void WuQMacroWidgetTypeEnum::addWidgetClassNameAlias(const QString& widgetName, const QString& aliasWidgetName) { s_widgetClassNameAliases.push_back(std::make_pair(widgetName, aliasWidgetName)); } connectome-workbench-1.4.2/src/Common/WuQMacroWidgetTypeEnum.h000066400000000000000000000123731360521144700243620ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_WIDGET_TYPE_ENUM_H__ #define __WU_Q_MACRO_WIDGET_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class WuQMacroWidgetTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Invalid type */ INVALID, /** a QAction (not checkable) */ ACTION, /** a Checkable QAction */ ACTION_CHECKABLE, /** a QAction Group */ ACTION_GROUP, /** a QButtonGroup */ BUTTON_GROUP, /** a QCheckBox */ CHECK_BOX, /** a QComboBox */ COMBO_BOX, /** a QDoubleSpinBox */ DOUBLE_SPIN_BOX, /** a QLineEdit */ LINE_EDIT, /** a QListWidget */ LIST_WIDGET, /** a Macro Widget Action */ MACRO_WIDGET_ACTION, /** a QMenu */ MENU, /** a QPushButton(not checkable) */ PUSH_BUTTON, /** a Checkable QPushButton */ PUSH_BUTTON_CHECKABLE, /** a QRadioButton */ RADIO_BUTTON, /** a QSlider */ SLIDER, /** a QSpinBox */ SPIN_BOX, /** a QTabBar */ TAB_BAR, /** a QTabWidget */ TAB_WIDGET, /** a QToolButton (not checkable) */ TOOL_BUTTON, /** a Checkable QToolButton */ TOOL_BUTTON_CHECKABLE }; /* switch (m_objectType) { case WuQMacroWidgetTypeEnum::ACTION: break; case WuQMacroWidgetTypeEnum::CHECK_BOX: break; case WuQMacroWidgetTypeEnum::COMBO_BOX: break; case WuQMacroWidgetTypeEnum::DOUBLE_SPIN_BOX: break; case WuQMacroWidgetTypeEnum::INVALID: break; case WuQMacroWidgetTypeEnum::LINE_EDIT: break; case WuQMacroWidgetTypeEnum::LIST_WIDGET: break; case WuQMacroWidgetTypeEnum::MENU: break; case WuQMacroWidgetTypeEnum::PUSH_BUTTON: break; case WuQMacroWidgetTypeEnum::RADIO_BUTTON: break; case WuQMacroWidgetTypeEnum::SLIDER: break; case WuQMacroWidgetTypeEnum::SPIN_BOX: break; case WuQMacroWidgetTypeEnum::TAB_BAR: break; case WuQMacroWidgetTypeEnum::TAB_WIDGET: break; case WuQMacroWidgetTypeEnum::TOOL_BUTTON: break; } */ ~WuQMacroWidgetTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); static void addWidgetClassNameAlias(const QString& widgetName, const QString& aliasWidgetName); private: WuQMacroWidgetTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const WuQMacroWidgetTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; /** Aliases for widget 'first' is QWidget, 'second' is alias */ static std::vector> s_widgetClassNameAliases; }; #ifdef __WU_Q_MACRO_WIDGET_TYPE_ENUM_DECLARE__ std::vector WuQMacroWidgetTypeEnum::enumData; bool WuQMacroWidgetTypeEnum::initializedFlag = false; int32_t WuQMacroWidgetTypeEnum::integerCodeCounter = 0; std::vector> WuQMacroWidgetTypeEnum::s_widgetClassNameAliases; #endif // __WU_Q_MACRO_WIDGET_TYPE_ENUM_DECLARE__ } // namespace #endif //__WU_Q_MACRO_WIDGET_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Common/YokingGroupEnum.cxx000066400000000000000000000236661360521144700235150ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __YOKING_GROUP_ENUM_DECLARE__ #include "YokingGroupEnum.h" #undef __YOKING_GROUP_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::YokingGroupEnum * \brief Enumerated type for yoking views of model. */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ YokingGroupEnum::YokingGroupEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ YokingGroupEnum::~YokingGroupEnum() { } /** * Initialize the enumerated metadata. */ void YokingGroupEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(YokingGroupEnum(YOKING_GROUP_OFF, "YOKING_GROUP_OFF", "Off")); enumData.push_back(YokingGroupEnum(YOKING_GROUP_A, "YOKING_GROUP_A", "Group A")); enumData.push_back(YokingGroupEnum(YOKING_GROUP_B, "YOKING_GROUP_B", "Group B")); enumData.push_back(YokingGroupEnum(YOKING_GROUP_C, "YOKING_GROUP_C", "Group C")); enumData.push_back(YokingGroupEnum(YOKING_GROUP_D, "YOKING_GROUP_D", "Group D")); enumData.push_back(YokingGroupEnum(YOKING_GROUP_E, "YOKING_GROUP_E", "Group E")); enumData.push_back(YokingGroupEnum(YOKING_GROUP_F, "YOKING_GROUP_F", "Group F")); enumData.push_back(YokingGroupEnum(YOKING_GROUP_G, "YOKING_GROUP_G", "Group G")); enumData.push_back(YokingGroupEnum(YOKING_GROUP_H, "YOKING_GROUP_H", "Group H")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const YokingGroupEnum* YokingGroupEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const YokingGroupEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString YokingGroupEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const YokingGroupEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ YokingGroupEnum::Enum YokingGroupEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = YOKING_GROUP_OFF; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const YokingGroupEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type YokingGroupEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString YokingGroupEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const YokingGroupEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ YokingGroupEnum::Enum YokingGroupEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = YOKING_GROUP_OFF; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const YokingGroupEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type YokingGroupEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t YokingGroupEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const YokingGroupEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ YokingGroupEnum::Enum YokingGroupEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = YOKING_GROUP_OFF; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const YokingGroupEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type YokingGroupEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void YokingGroupEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void YokingGroupEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(YokingGroupEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void YokingGroupEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(YokingGroupEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Common/YokingGroupEnum.h000066400000000000000000000065031360521144700231310ustar00rootroot00000000000000#ifndef __YOKING_GROUP_ENUM_H__ #define __YOKING_GROUP_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class YokingGroupEnum { public: /** * Enumerated values. */ enum Enum { /** Off */ YOKING_GROUP_OFF, /** Group A */ YOKING_GROUP_A, /** Group B */ YOKING_GROUP_B, /** Group C */ YOKING_GROUP_C, /** Group D */ YOKING_GROUP_D, /** Group E */ YOKING_GROUP_E, /** Group F */ YOKING_GROUP_F, /** Group G */ YOKING_GROUP_G, /** Group H */ YOKING_GROUP_H }; ~YokingGroupEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: YokingGroupEnum(const Enum enumValue, const AString& name, const AString& guiName); static const YokingGroupEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __YOKING_GROUP_ENUM_DECLARE__ std::vector YokingGroupEnum::enumData; bool YokingGroupEnum::initializedFlag = false; int32_t YokingGroupEnum::integerCodeCounter = 0; #endif // __YOKING_GROUP_ENUM_DECLARE__ } // namespace #endif //__YOKING_GROUP_ENUM_H__ connectome-workbench-1.4.2/src/Common/createMacroShortCutKeyEnum.sh000077500000000000000000000007411360521144700254320ustar00rootroot00000000000000#!/bin/sh /mnt/myelin/distribution/caret7_distribution/workbench/bin_macosx64/wb_command \ -class-create-enum WuQMacroShortCutKeyEnum 37 true \ Key_None \ Key_A \ Key_B \ Key_C \ Key_D \ Key_E \ Key_F \ Key_G \ Key_H \ Key_I \ Key_J \ Key_K \ Key_L \ Key_M \ Key_N \ Key_O \ Key_P \ Key_Q \ Key_R \ Key_S \ Key_T \ Key_U \ Key_V \ Key_W \ Key_X \ Key_Y \ Key_Z \ Key_0 \ Key_1 \ Key_2 \ Key_3 \ Key_4 \ Key_5 \ Key_6 \ Key_7 \ Key_8 \ Key_9 connectome-workbench-1.4.2/src/Common/dot_wrapper.h000066400000000000000000000065061360521144700223600ustar00rootroot00000000000000#ifndef DOT_WRAPPER_H #define DOT_WRAPPER_H //workbench is strictly c++, so we don't actually need ifdef guards on this //we also don't expose any libraries, so it doesn't really matter whether it switches to c++ name mangling when we disable SIMD //but hey, whatever #ifdef __cplusplus extern "C" { #endif #ifdef _WIN32 #define inline __inline #endif #ifdef CARET_DOTFCN #include "dot.h" #else inline double dsdot (const float *a, const float *b, int n) { double sum = 0; for (int k = 0; k < n; k++) sum += a[k] * b[k]; return sum; } // dsdot() //copy enum from dot.h //renamed to dot_flags in both files for less conflict chance typedef enum { DOT_NAIVE = 1, DOT_SSE2 = 2, DOT_AVX = 3, DOT_AVXFMA = 4, DOT_AVX512 = 5, DOT_AVX512FMA = 6, DOT_AUTO = 100 } dot_flags; //and dummy implementation of dot_set_impl inline dot_flags dot_set_impl (dot_flags) { return DOT_NAIVE; } #endif #ifdef __cplusplus } #endif //convenience helpers for the enum #include "AString.h" #include "CaretAssert.h" #include namespace caret { class DotSIMDEnum { public: typedef dot_flags Enum; static inline std::vector getAllEnums() { std::vector ret; ret.push_back(DOT_NAIVE); ret.push_back(DOT_SSE2); ret.push_back(DOT_AVX); ret.push_back(DOT_AVXFMA); ret.push_back(DOT_AVX512); ret.push_back(DOT_AVX512FMA); ret.push_back(DOT_AUTO); return ret; } static inline Enum fromName(const AString& name, bool* isValidOut = NULL) { bool valid = false; Enum ret = DOT_NAIVE; if (name == "NAIVE") { ret = DOT_NAIVE; valid = true; } else if (name == "SSE2") { ret = DOT_SSE2; valid = true; } else if (name == "AVX") { ret = DOT_AVX; valid = true; } else if (name == "AVXFMA") { ret = DOT_AVXFMA; valid = true; } else if (name == "AVX512") { ret = DOT_AVX512; valid = true; } else if (name == "AVX512FMA") { ret = DOT_AVX512FMA; valid = true; } else if (name == "AUTO") { ret = DOT_AUTO; valid = true; } if (isValidOut == NULL) { CaretAssert(valid); } else { *isValidOut = valid; } return ret; } static inline AString toName(const Enum& value) { switch (value) { case DOT_NAIVE: return "NAIVE"; case DOT_SSE2: return "SSE2"; case DOT_AVX: return "AVX"; case DOT_AVXFMA: return "AVXFMA"; case DOT_AVX512: return "AVX512"; case DOT_AVX512FMA: return "AVX512FMA"; case DOT_AUTO: return "AUTO"; default: CaretAssert(0); } return ""; } }; } #endif connectome-workbench-1.4.2/src/Desktop/000077500000000000000000000000001360521144700200335ustar00rootroot00000000000000connectome-workbench-1.4.2/src/Desktop/CMakeLists.txt000066400000000000000000000133161360521144700225770ustar00rootroot00000000000000# # Name of Project # PROJECT(Desktop) # # Name of executable # set (EXE_NAME wb_view) # # QT Include directories # if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) include_directories(${Qt5Network_INCLUDE_DIRS}) if(Qt5OpenGL_FOUND) include_directories(${Qt5OpenGL_INCLUDE_DIRS}) endif() include_directories(${Qt5Widgets_INCLUDE_DIRS}) endif() IF (QT4_FOUND) SET(QT_USE_QTXML TRUE) SET(QT_USE_QTOPENGL TRUE) SET(QT_USE_QTNETWORK TRUE) INCLUDE(${QT_USE_FILE}) ENDIF () # # Added by JWH to eliminate OpenGL linking errors in Ubuntu Linux # IF (UNIX) IF (NOT APPLE) FIND_PACKAGE(OpenGL) ENDIF (NOT APPLE) ENDIF (UNIX) # # Resources # Help can be excluded # SET (RESOURCES_QRC_FILE ../Resources/General/general_resources.qrc ../Resources/Gui/gui_resources.qrc) IF (WORKBENCH_INCLUDE_HELP_HTML_RESOURCES) LIST (APPEND RESOURCES_QRC_FILE ../Resources/Help/help_resources.qrc) ENDIF (WORKBENCH_INCLUDE_HELP_HTML_RESOURCES) IF (Qt5_FOUND) QT5_ADD_RESOURCES(IMAGE_RCS_SRCS ${RESOURCES_QRC_FILE}) ELSE (Qt5_FOUND) IF (QT4_FOUND) QT4_ADD_RESOURCES(IMAGE_RCS_SRCS ${RESOURCES_QRC_FILE}) ENDIF() ENDIF (Qt5_FOUND) # # Create the executable # Apple creates a bundle # IF (APPLE) ADD_EXECUTABLE(${EXE_NAME} MACOSX_BUNDLE desktop.cxx ${IMAGE_RCS_SRCS} ) # # This is a customized Info.Plist for Mac so that a spec # file can be opened using Finder # SET_TARGET_PROPERTIES( ${EXE_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/../mac_plist/MacOSXBundleInfo.plist.in ) # SET_TARGET_PROPERTIES( # ${EXE_NAME} # PROPERTIES # RESOURCE # ${QT_BINARY_DIR}/../src/gui/mac/qt_menu.nib # ) ENDIF (APPLE) IF (WIN32) ADD_EXECUTABLE(${EXE_NAME} desktop.cxx ${IMAGE_RCS_SRCS} ${CMAKE_SOURCE_DIR}/../icons/windows/workbench.rc ) ENDIF (WIN32) IF (NOT APPLE) IF (UNIX) ADD_EXECUTABLE(${EXE_NAME} desktop.cxx ${IMAGE_RCS_SRCS} ) ENDIF (UNIX) ENDIF (NOT APPLE) if(Qt5OpenGL_FOUND) set(QT5_OPENGL_LIB_NAME Qt5::OpenGL) endif() if(Qt5_FOUND) set(QT5_LINK_LIBS Qt5::Concurrent Qt5::Core Qt5::Gui Qt5::Network ${QT5_OPENGL_LIB_NAME} Qt5::PrintSupport Qt5::Test ${WB_WEBKIT_LIBS} Qt5::Widgets Qt5::Xml) endif() # # Libraries that are linked # TARGET_LINK_LIBRARIES(${EXE_NAME} GuiQt Commands Operations Algorithms OperationsBase ${Qwt_LIBRARIES} OSMesaDummy Brain Files Graphics ${FTGL_LIBRARIES} Annotations Charting Palette Cifti Gifti Nifti QxtCore FilesBase Scenes Xml Common ${GLEW_LIBRARIES} ${QUAZIP_LIBRARIES} ${FREETYPE_LIBRARIES} ${QT_LIBRARIES} ${QT5_LINK_LIBS} ${ZLIB_LIBRARIES} #${LIBS} ) INCLUDE(GNUInstallDirs) INSTALL(TARGETS ${EXE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) IF(WIN32) TARGET_LINK_LIBRARIES(${EXE_NAME} opengl32 glu32 ) ENDIF(WIN32) IF (UNIX) IF (NOT APPLE) TARGET_LINK_LIBRARIES(${EXE_NAME} ${OPENGL_LIBRARIES} gobject-2.0 ) ENDIF (NOT APPLE) # EXECUTE_PROCESS(COMMAND uname -n OUTPUT_VARIABLE MACHINE_NAME) # MESSAGE("MACHINE_NAME: ${MACHINE_NAME}") # IF (${MACHINE_NAME} MATCHES "linuxbuild") # MESSAGE("is linuxbuild") # SET_TARGET_PROPERTIES(${EXE_NAME} # PROPERTIES # LINK_FLAGS "-Wl,-E" # LINK_FLAGS_DEBUG "-Wl,-E" # LINK_FLAGS_RELEASE "-Wl,-E") # ENDIF() ENDIF (UNIX) # # At this time, Cocoa needs to be explicitly added for Apple Mac # IF (APPLE) #SET (QT_MAC_USE_COCOA TRUE) TARGET_LINK_LIBRARIES(${EXE_NAME} "-framework Cocoa" "-framework OpenGL" ) ENDIF (APPLE) # # Find Headers # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Desktop ${CMAKE_SOURCE_DIR}/Algorithms ${CMAKE_SOURCE_DIR}/Commands ${CMAKE_SOURCE_DIR}/GuiQt ${CMAKE_SOURCE_DIR}/Brain ${CMAKE_SOURCE_DIR}/Graphics ${CMAKE_SOURCE_DIR}/FilesBase ${CMAKE_SOURCE_DIR}/Files ${CMAKE_SOURCE_DIR}/Palette ${CMAKE_SOURCE_DIR}/Cifti ${CMAKE_SOURCE_DIR}/Gifti ${CMAKE_SOURCE_DIR}/Nifti ${Qwt_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/Scenes ${CMAKE_SOURCE_DIR}/Xml ${CMAKE_SOURCE_DIR}/Common ) # # Apple needs qt_menu.nib directory copied # into application's Resources directory # # Apple needs framework # IF (APPLE) ADD_CUSTOM_COMMAND( TARGET ${EXE_NAME} POST_BUILD COMMAND ${CMAKE_SOURCE_DIR}/CMakeScripts/copy_mac_nib.sh ${EXE_NAME} ###COMMAND ${CMAKE_SOURCE_DIR}/CMakeScripts/copy_mac_frameworks.sh ${EXE_NAME} ) ENDIF (APPLE) IF (APPLE) SET (MACOSX_BUNDLE_INFO_STRING wb_view Copyright 2015 ) SET (MACOSX_BUNDLE_ICON_FILE workbench.icns ) ##SET (MACOSX_BUNDLE_GUI_IDENTIFIER wb_view ) ## Underscore is not valid in MACOSX_BUNDLE_GUI_IDENTIFIER SET (MACOSX_BUNDLE_GUI_IDENTIFIER workbench ) SET (MACOSX_BUNDLE_LONG_VERSION_STRING wb_view) SET (MACOSX_BUNDLE_BUNDLE_NAME wb_view) SET (MACOSX_BUNDLE_SHORT_VERSION_STRING ${WB_VERSION}) SET (MACOSX_BUNDLE_BUNDLE_VERSION ${WB_VERSION}) SET (MACOSX_BUNDLE_COPYRIGHT 2015 ) ADD_CUSTOM_COMMAND( TARGET ${EXE_NAME} POST_BUILD COMMAND ${CMAKE_SOURCE_DIR}/CMakeScripts/copy_mac_icon.sh ${EXE_NAME} ${CMAKE_SOURCE_DIR}/../icons/mac/wb_view.icns COMMAND ${CMAKE_SOURCE_DIR}/CMakeScripts/copy_mac_icon.sh ${EXE_NAME} ${CMAKE_SOURCE_DIR}/../icons/mac/workbench.icns COMMAND ${CMAKE_SOURCE_DIR}/CMakeScripts/copy_mac_icon.sh ${EXE_NAME} ${CMAKE_SOURCE_DIR}/../icons/mac/spec_file.icns COMMAND ${CMAKE_SOURCE_DIR}/CMakeScripts/copy_mac_icon.sh ${EXE_NAME} ${CMAKE_SOURCE_DIR}/../icons/mac/data_file.icns ) ENDIF (APPLE) connectome-workbench-1.4.2/src/Desktop/desktop.cxx000066400000000000000000001113301360521144700222270ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /* * When GLEW is used, CaretOpenGLInclude.h will include "Gl/glew.h". * Gl/glew.h MUST BE BEFORE Gl/gl.h and Gl/gl.h is included by * some Qt classes so, we must include CaretOpenGL.h first. */ #include "CaretOpenGLInclude.h" #include #include #include #ifndef WORKBENCH_USE_QT5_QOPENGL_WIDGET #include #endif #include #include #include #include #include #include #include "ApplicationInformation.h" #include "BrainBrowserWindow.h" #include "BrainOpenGL.h" #include "BrainOpenGLWidget.h" #include "CaretAssert.h" #include "CaretCommandLine.h" #include "CaretHttpManager.h" #include "CaretLogger.h" #include "CaretPreferences.h" #include "CommandOperationManager.h" #include "EventBrowserWindowNew.h" #include "EventManager.h" #include "FileInformation.h" #include "GuiManager.h" #include "MacApplication.h" #include "ProgramParameters.h" #include "SessionManager.h" #include "SplashScreen.h" #include "SystemUtilities.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" static bool caretLoggerIsValid = false; using namespace caret; using namespace std; #if QT_VERSION >= 0x050000 /** * Handles message produced by Qt 5 */ static void messageHandlerForQt5(QtMsgType type, const QMessageLogContext& context, const QString& msg) { const AString backtrace = SystemUtilities::getBackTrace(); const AString contextInfo = (" Context Info File (" + QString(context.file) + ") Function (" + QString(context.function) + ") Line (" + QString::number(context.line) + ") Version (" + QString::number(context.version) + ") Category (" + QString(context.category) + ")"); const AString message = (AString(msg) + "\n" + contextInfo + "\n" + backtrace); if (caretLoggerIsValid) { bool abortFlag = false; bool displayedFlag = false; switch (type) { case QtDebugMsg: CaretLogInfo(message); displayedFlag = CaretLogger::getLogger()->isInfo(); break; case QtWarningMsg: CaretLogWarning(message); displayedFlag = CaretLogger::getLogger()->isWarning(); break; case QtCriticalMsg: CaretLogSevere(message); displayedFlag = CaretLogger::getLogger()->isSevere(); break; case QtFatalMsg: cerr << "Qt Fatal: " << message << endl; abortFlag = true;//fatal will cause an abort, so always display it, bypassing logger entirely displayedFlag = true; break; #if QT_VERSION >= 0x050500 case QtInfoMsg: CaretLogInfo(message); displayedFlag = CaretLogger::getLogger()->isInfo(); break; #endif } /* * Beep to alert user about an error!!! */ if (displayedFlag && (type != QtDebugMsg))//don't beep for debug { GuiManager::beep(); } #ifndef NDEBUG if (!displayedFlag) { cerr << "DEBUG: Qt "; switch (type) { case QtDebugMsg: cerr << "Debug "; break; case QtWarningMsg: cerr << "Warning "; break; case QtCriticalMsg: cerr << "Critical "; break; case QtFatalMsg: cerr << "FATAL (?!?) ";//should never happen break; #if QT_VERSION >= 0x050500 case QtInfoMsg: std::cerr << "Info "; break; #endif } cerr << "message hidden" << endl; } #endif if (abortFlag) { std::abort(); } } else { switch (type) { case QtDebugMsg: std::cerr << "Qt Debug: " << message << std::endl; break; case QtWarningMsg: std::cerr << "Qt Warning: " << message << std::endl; break; case QtCriticalMsg: std::cerr << "Qt Critical: " << message << std::endl; break; case QtFatalMsg: std::cerr << "Qt Fatal: " << message << std::endl; std::abort(); break; #if QT_VERSION >= 0x050500 case QtInfoMsg: std::cerr << "Qt Info: " << message << std::endl; break; #endif } } } #else // QT_VERSION /** * Handles message produced by Qt 4. */ static void messageHandlerForQt4(QtMsgType type, const char* msg) { const AString backtrace = SystemUtilities::getBackTrace(); const AString message = (AString(msg) + "\n" + backtrace); if (caretLoggerIsValid) { bool abortFlag = false; bool displayedFlag = false; switch (type) { case QtDebugMsg: CaretLogInfo(message); displayedFlag = CaretLogger::getLogger()->isInfo(); break; case QtWarningMsg: CaretLogWarning(message); displayedFlag = CaretLogger::getLogger()->isWarning(); break; case QtCriticalMsg: CaretLogSevere(message); displayedFlag = CaretLogger::getLogger()->isSevere(); break; case QtFatalMsg: cerr << "Qt Fatal: " << message << endl; abortFlag = true;//fatal will cause an abort, so always display it, bypassing logger entirely displayedFlag = true; break; } /* * Beep to alert user about an error!!! */ if (displayedFlag && (type != QtDebugMsg))//don't beep for debug { GuiManager::beep(); } #ifndef NDEBUG if (!displayedFlag) { cerr << "DEBUG: Qt "; switch (type) { case QtDebugMsg: cerr << "Debug "; break; case QtWarningMsg: cerr << "Warning "; break; case QtCriticalMsg: cerr << "Critical "; break; case QtFatalMsg: cerr << "FATAL (?!?) ";//should never happen break; } cerr << "message hidden" << endl; } #endif if (abortFlag) { std::abort(); } } else { switch (type) { case QtDebugMsg: std::cerr << "Qt Debug: " << message << std::endl; break; case QtWarningMsg: std::cerr << "Qt Warning: " << message << std::endl; break; case QtCriticalMsg: std::cerr << "Qt Critical: " << message << std::endl; break; case QtFatalMsg: std::cerr << "Qt Fatal: " << message << std::endl; std::abort(); break; } } } #endif // QT_VERSION //struct for communicating stuff back to main from parseCommandLine struct ProgramState { vector fileList; int windowSizeXY[2]; int windowPosXY[2]; int graphicsSizeXY[2]; bool showSplash; AString specFileNameLoadWithDialog; AString specFileNameLoadAll; AString sceneFileName; AString sceneNameOrNumber; ProgramState(); }; //declare the functions associated with command line void printHelp(const AString& progName); void parseCommandLine(const AString& progName, ProgramParameters* myParams, ProgramState& myState); int main(int argc, char* argv[]) { srand(time(NULL)); int result; { /* * Handle uncaught exceptions */ SystemUtilities::setUnexpectedHandler(); /* * Create the session manager. */ SessionManager::createSessionManager(ApplicationTypeEnum::APPLICATION_TYPE_GRAPHICAL_USER_INTERFACE); caretLoggerIsValid = true; /* * Parameters for the program. */ ProgramParameters parameters(argc, argv); caret_global_commandLine_init(parameters); //begin parsing command line ProgramState myState; FileInformation progInfo(argv[0]); AString progName = progInfo.getFileName(); parseCommandLine(progName, ¶meters, myState); /* * Log the command parameters. */ CaretLogFine("Running: " + caret_global_commandLine); /* * Setup OpenGL if using Qt 5's QOpenGLWidget. * QOpenGLWidget's documentation indicates that * default format must be initizlied before * QApplication is created. */ #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); BrainOpenGLWidget::initializeDefaultGLFormat(); #endif //change the default graphics system on mac to avoid rendering performance issues with qwtplotter #ifdef CARET_OS_MACOSX // Qt-Deprecated: QApplication::setGraphicsSystem("raster"); MacApplication app(argc, argv); #else //CARET_OS_MACOSX QApplication app(argc, argv); #endif //CARET_OS_MACOSX /* * Create the GUI Manager. * Moved here as part of WB-842. In OSX Mojave (10.14), * the open file event appears to be delivered very quickly * so the GUI manager need to be created sooner than * before. */ GuiManager::createGuiManager(); app.processEvents(); ApplicationInformation applicationInformation; QApplication::addLibraryPath( QApplication::applicationDirPath() + QDir::separator() + "plugins"); QApplication::setApplicationName(applicationInformation.getName()); QApplication::setApplicationVersion(applicationInformation.getVersion()); QApplication::setOrganizationDomain("brainvis.wustl.edu"); QApplication::setOrganizationName("Van Essen Lab"); /* * Override the system local to US - English */ QLocale::setDefault(QLocale(QLocale::English, QLocale::UnitedStates)); /* * Make sure OpenGL is available. */ const QString noOpenGLMessage("OpenGL (3D Graphics System) is not available. " "This may be caused by missing or outdated OpenGL libraries." #ifdef CARET_OS_LINUX "On Linux, this may be caused by a missing plugin " "library /xcbglintegrations/libqxcb-glx-integration.so." #endif ); #ifndef WORKBENCH_USE_QT5_QOPENGL_WIDGET if ( ! QGLFormat::hasOpenGL()) { app.processEvents(); WuQMessageBox::errorOk(NULL, noOpenGLMessage); app.processEvents(); return -1; } #endif /* * Setup OpenGL if NOT using Qt 5's QOpenGLWidget */ #ifndef WORKBENCH_USE_QT5_QOPENGL_WIDGET BrainOpenGLWidget::initializeDefaultGLFormat(); #endif #if QT_VERSION >= 0x050000 qInstallMessageHandler(messageHandlerForQt5);//this handler uses CaretLogger and GuiManager, so we must install it after the logger is available and the application is created #else // QT_VERSION qInstallMsgHandler(messageHandlerForQt4);//this handler uses CaretLogger and GuiManager, so we must install it after the logger is available and the application is created #endif // QT_VERSION /* * Log debug status */ CaretLogConfig(applicationInformation.getCompiledWithDebugStatus()); /* * Enabled the desired splash screen based upon user preferences * and command line options. Do not show selection splash screen * if there has listed files on the command line. */ CaretPreferences* preferences = SessionManager::get()->getCaretPreferences(); bool showSelectionSplashScreen = preferences->isSplashScreenEnabled(); bool showImageSplashScreen = (! showSelectionSplashScreen); if ( ! myState.showSplash) { showSelectionSplashScreen = false; showImageSplashScreen = false; } /* * DISABLE IMAGE SPLASH SCREEN */ showImageSplashScreen = false; /* * Splash Screen */ QPixmap splashPixmap; QSplashScreen splashScreen; if (showImageSplashScreen) { if (WuQtUtilities::loadPixmap(":/Splash/hcp.png", splashPixmap)) { splashScreen.setPixmap(splashPixmap); splashScreen.showMessage("Starting Workbench..."); splashScreen.show(); app.processEvents(); SystemUtilities::sleepSeconds(2); } } /* * Letting the App process events will allow the message for a * double-clicked spec file in Mac OSX to get processed. */ app.processEvents(); /* * Now that events have processed, see if there was a request for * a data file to open. */ const AString dataFileNameFromOS = GuiManager::get()->getNameOfDataFileToOpenAfterStartup(); if ( ! dataFileNameFromOS.isEmpty()) { showSelectionSplashScreen = false; if (dataFileNameFromOS.endsWith(DataFileTypeEnum::toFileExtension(DataFileTypeEnum::SPECIFICATION))) { myState.specFileNameLoadWithDialog = dataFileNameFromOS; } else { myState.fileList.push_back(dataFileNameFromOS); } } /* * Show file selection splash screen if enabled via user's preferences */ if (showSelectionSplashScreen) { /* * Show selection splash screen. * Need to process events since QApplication::exec() has not * been called. */ SplashScreen splashScreen(NULL); app.processEvents(); if (splashScreen.exec()) { const QString dataFileName = splashScreen.getSelectedDataFileName(); if ( ! dataFileName.isEmpty()) { myState.fileList.clear(); if (dataFileName.endsWith(DataFileTypeEnum::toFileExtension(DataFileTypeEnum::SPECIFICATION))) { myState.specFileNameLoadWithDialog = dataFileName; } else { myState.fileList.push_back(dataFileName); } } } } /* * Create and display a main window. * If not done as pointer, the event object is listed as an * object that was not deleted by CaretObject::printListOfObjectsNotDeleted * since it does not go out of scope. */ EventBrowserWindowNew newBrowserWindow(NULL, NULL); EventManager::get()->sendEvent(newBrowserWindow.getPointer()); splashScreen.close(); BrainBrowserWindow* myWindow = GuiManager::get()->getBrowserWindowByWindowIndex(0); if ( ! myWindow->hasValidOpenGL()) { app.processEvents(); WuQMessageBox::errorOk(NULL, noOpenGLMessage); app.processEvents(); return -1; } /** * Test for the required OpenGL version is available. */ AString requiredOpenGLMessage; if ( ! BrainOpenGL::testForRequiredOpenGLVersion(requiredOpenGLMessage)) { app.processEvents(); if ( ! WuQMessageBox::warningAcceptReject(NULL, requiredOpenGLMessage, "Continue", "Exit")) { return -1; } } /* * Initialize GLEW if it is being used */ AString glewErrorMessage; #ifdef HAVE_GLEW GLenum err = glewInit(); if (GLEW_OK != err) { /* Problem: glewInit failed, something is seriously wrong. */ glewErrorMessage = ("GLEW failed to initialize.\n" + AString(reinterpret_cast(glewGetErrorString(err)))); CaretLogSevere(glewErrorMessage); } CaretLogInfo("Status: Using GLEW version " + AString(reinterpret_cast(glewGetString(GLEW_VERSION)))); #endif /* HAVE_GLEW */ if ( ! glewErrorMessage.isEmpty()) { app.processEvents(); WuQMessageBox::errorOk(NULL, glewErrorMessage); app.processEvents(); return -1; } if ((myState.windowSizeXY[0] > 0) && (myState.windowSizeXY[1] > 0)) { if (myState.windowPosXY[0] > 0 && myState.windowPosXY[1] > 0) { myWindow->setGeometry(myState.windowPosXY[0], myState.windowPosXY[1], myState.windowSizeXY[0], myState.windowSizeXY[1]); } else { myWindow->setFixedSize(myState.windowSizeXY[0], myState.windowSizeXY[1]); } } else { if (myState.windowPosXY[0] > 0 && myState.windowPosXY[1] > 0) { myState.windowSizeXY[0] = myWindow->width(); myState.windowSizeXY[1] = myWindow->height(); myWindow->setGeometry(myState.windowPosXY[0], myState.windowPosXY[1], myState.windowSizeXY[0], myState.windowSizeXY[1]); } } if (myState.graphicsSizeXY[0] > 0 && myState.graphicsSizeXY[1] > 0) { myWindow->setGraphicsWidgetFixedSize(myState.graphicsSizeXY[0], myState.graphicsSizeXY[1]); } if ( ! myState.specFileNameLoadAll.isEmpty()) { myWindow->loadFilesFromCommandLine({ myState.specFileNameLoadAll }, BrainBrowserWindow::LOAD_SPEC_FILE_CONTENTS_VIA_COMMAND_LINE); } else if ( ! myState.specFileNameLoadWithDialog.isEmpty()) { myWindow->loadFilesFromCommandLine({ myState.specFileNameLoadWithDialog }, BrainBrowserWindow::LOAD_SPEC_FILE_WITH_DIALOG_VIA_COMMAND_LINE); } if (! myState.fileList.empty()) { myWindow->loadFilesFromCommandLine(myState.fileList, BrainBrowserWindow::LOAD_SPEC_FILE_WITH_DIALOG); } if ( ! myState.sceneFileName.isEmpty()) { myWindow->loadSceneFromCommandLine(myState.sceneFileName, myState.sceneNameOrNumber); } #ifndef WORKBENCH_USE_QT5_QOPENGL_WIDGET if (QGLPixelBuffer::hasOpenGLPbuffers()) { CaretLogConfig("OpenGL PBuffers are supported"); } else { CaretLogConfig("OpenGL PBuffers are NOT supported"); } #endif /* * Log local (language, country) */ QLocale sytemLocale = QLocale::system(); CaretLogConfig("Local Language=" + QLocale::languageToString(sytemLocale.language()) + " Country=" + QLocale::countryToString(sytemLocale.country())); /* * Resolution of screens */ AString screenSizeText = "Screen Sizes: "; QDesktopWidget* dw = QApplication::desktop(); const int numScreens = dw->screenCount(); for (int i = 0; i < numScreens; i++) { const QRect rect = dw->screenGeometry(i); const int x = rect.x(); const int y = rect.y(); const int w = rect.width(); const int h = rect.height(); screenSizeText.appendWithNewLine("Screen index=" + AString::number(i) + ", x=" + AString::number(x) + ", y=" + AString::number(y) + ", w=" + AString::number(w) + ", h=" + AString::number(h)); } screenSizeText.appendWithNewLine("Primary Screen=" + AString::number(dw->primaryScreen())); if (dw->isVirtualDesktop()) { screenSizeText.appendWithNewLine("Virtual Desktop=YES"); } else { screenSizeText.appendWithNewLine("Virtual Desktop=NO"); } QWidget* screenWidget = dw->screen(); QRect screenWidgetRect = screenWidget->geometry(); screenSizeText.appendWithNewLine("Desktop: x=" + AString::number(screenWidgetRect.x()) + ", y=" + AString::number(screenWidgetRect.y()) + ", w=" + AString::number(screenWidgetRect.width()) + ", h=" + AString::number(screenWidgetRect.height())); screenSizeText.appendWithNewLine("Logical DPI: x=" + AString::number(dw->logicalDpiX()) + ", y=" + AString::number(dw->logicalDpiY())); screenSizeText.appendWithNewLine("Physical DPI: x=" + AString::number(dw->physicalDpiX()) + ", y=" + AString::number(dw->physicalDpiY())); screenSizeText.appendWithNewLine("Width/height (mm): x=" + AString::number(dw->widthMM()) + ", y=" + AString::number(dw->heightMM())); CaretLogConfig(screenSizeText); /* * Start the app which will launch the main window. */ result = app.exec(); /* * Hiding the window removes it from the event loop on Windows, which is necessary to * prevent paint events from causing assertion errors when the Window is destroyed * Although this is a Window's only bug, it's probably good practice to do on all platforms */ //theMainWindow->hide(); /* * Delete the GUI Manager. */ GuiManager::deleteGuiManager(); /* * Delete the command manager */ CommandOperationManager::deleteCommandOperationManager(); /* * Delete the session manager. */ SessionManager::deleteSessionManager(); CaretHttpManager::deleteHttpManager(); } /* * See if any objects were not deleted. */ CaretObject::printListOfObjectsNotDeleted(true); //FreeConsole(); return result; } void printHelp(const AString& progName) { cout << "Usage: " << progName << " [options] [files]" << endl << endl << " [files], if present, can be a single spec file, or multiple data files" << endl << endl << "Options:" << endl << " -help" << endl << " display this usage text" << endl << endl << " -graphics-size " << endl << " Set the size of the graphics region." << endl << " If this option is used you WILL NOT be able" << endl << " to change the size of the graphic region. It" << endl << " may be useful when image captures of a particular" << endl << " size are desired." << endl << endl << " -logging " << endl << " Set the logging level." << endl << " Valid Levels are:" << endl; std::vector logLevels; LogLevelEnum::getAllEnums(logLevels); for (std::vector::iterator iter = logLevels.begin(); iter != logLevels.end(); iter++) { cout << " " << qPrintable(LogLevelEnum::toName(*iter)) << endl; } cout << endl << " -mac-menu-duplicate" << endl << " MacOS Only - Adds menus to the top of the Browser Window " << endl << " that duplicate the menu bar at the top of the window. " << endl << " The menus are similar to that on Linux and Windows. " << endl << " May be useful for creating tutorial images." << endl << " This functionality is EXPERIMENTAL and subject to " << endl << " removal in future versions of wb_view." << endl << endl << " -no-splash" << endl << " disable all splash screens" << endl << endl << " -scene-load " << endl << " load the specified scene file and display the scene " << endl << " in the file that matches by name or number. Name" << endl << " takes precedence over number. The scene numbers " << endl << " start at one." << endl << " " << endl << endl << " -style " << endl << " change the window style to the specified style" << endl << " the following styles are valid on this system:" << endl; QStringList styleList = QStyleFactory::keys(); QStringListIterator styleListIterator(styleList); while (styleListIterator.hasNext()) { cout << " " << qPrintable(styleListIterator.next()) << endl; } cout << " The selected style is listed on the About wb_view dialog" << endl << " available from the File Menu (On Macs: wb_view Menu). " << endl << " Press the \"More\" button to see the selected style." << endl << " Other styles may be available on other systems." << endl << endl << " -spec-load-all" << endl << " load all files in the given spec file, don't show spec file dialog" << endl << endl << " -window-size " << endl << " Set the size of the browser window" << endl << endl << " -window-pos " << endl << " Set the position of the browser window" << endl << endl; } void parseCommandLine(const AString& progName, ProgramParameters* myParams, ProgramState& myState) { bool hasFatalError = false; const AString moreThanOneSpecFileErrorMessage("More than one spec file is NOT allowed in options"); try { while (myParams->hasNext()) { AString thisParam = myParams->nextString("option"); if (thisParam[0] == '-') { if (thisParam == "-style") { myParams->nextString("style");//discard, QApplication handles this } else if (thisParam == "-help") { printHelp(progName); exit(0); } else if (thisParam == "-logging") { if (myParams->hasNext()) { const AString logLevelName = myParams->nextString("Logging Level").toUpper(); bool valid = false; const LogLevelEnum::Enum level = LogLevelEnum::fromName(logLevelName, &valid); if (valid) { /* * Note settings logging level in preferences will also * set logging level in the caret logger. */ CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setLoggingLevel(level); } else { cerr << "Invalid logging level \"" << qPrintable(logLevelName) << "\" for \"-logging\" option" << std::endl; hasFatalError = true; } } } else if (thisParam == "-mac-menu-duplicate") { BrainBrowserWindow::setEnableMacDuplicateMenuBar(true); } else if (thisParam == "-no-splash") { myState.showSplash = false; } else if (thisParam == "-scene-load") { if (myParams->hasNext()) { myState.sceneFileName = myParams->nextString("Scene File Name"); if (myParams->hasNext()) { myState.sceneNameOrNumber = myParams->nextString("Scene Name or Number"); } else { cerr << "Missing scene name/number for \"-scene\" option" << std::endl; hasFatalError = true; } } else { cerr << "Missing scene file name for \"-scene\" option" << std::endl; hasFatalError = true; } } else if (thisParam == "-spec-load-all") { if ( ! myState.specFileNameLoadAll.isEmpty()) { cerr << qPrintable(moreThanOneSpecFileErrorMessage) << endl; } else if (myParams->hasNext()) { myState.specFileNameLoadAll = myParams->nextString("Spec File Name"); } else { cerr << "Missing spec file name for \"-spec\" option" << endl; hasFatalError = true; } } else if (thisParam == "-graphics-size") { if (myParams->hasNext()) { myState.graphicsSizeXY[0] = myParams->nextInt("Graphics Size X"); } else { cerr << "Missing X & Y sizes for graphics" << endl; hasFatalError = true; } if (myParams->hasNext()) { myState.graphicsSizeXY[1] = myParams->nextInt("Graphics Size Y"); } else { cerr << "Missing Y sizes for graphics" << endl; hasFatalError = true; } } else if (thisParam == "-window-size") { if (myParams->hasNext()) { myState.windowSizeXY[0] = myParams->nextInt("Window Size X"); } else { cerr << "Missing X & Y sizes for window" << endl; hasFatalError = true; } if (myParams->hasNext()) { myState.windowSizeXY[1] = myParams->nextInt("Window Size Y"); } else { cerr << "Missing Y sizes for window" << endl; hasFatalError = true; } } else if (thisParam == "-window-pos") { if (myParams->hasNext()) { myState.windowPosXY[0] = myParams->nextInt("Window Position X"); } else { cerr << "Missing X & Y position for window" << endl; hasFatalError = true; } if (myParams->hasNext()) { myState.windowPosXY[1] = myParams->nextInt("Window Position Y"); } else { cerr << "Missing Y position for window" << endl; hasFatalError = true; } } else if (thisParam.startsWith("-psn")) { /* * 21 April 2014 (Did not have this problem before this date) * * IGNORE this parameter. For some reason, when a Mac * version is started from Finder, a "-psn" parameter * is being added to the parameters. If this parameter * is not ignored, Workbench starts, the icon bounces * a few times, and then Workbench quits (due to * "unrecognized option", below), and the user is * not given any error message. * * http://stackoverflow.com/questions/10242115/os-x-strange-psn-command-line-parameter-when-launched-from-finder * http://trac.wxwidgets.org/ticket/15432 */ } else if (thisParam == "-NSDocumentRevisionsDebugMode") { /* * When wb_view is started within Apple's XCode, these parameters are added * so ignore them: * -NSDocumentRevisionsDebugMode YES */ if (myParams->hasNext()) { myParams->nextString("Argument to -NSDocumentRevisionsDebugMode"); } } else { cerr << "unrecognized option \"" << thisParam << "\"" << endl; printHelp(progName); hasFatalError = true; } } else { if (thisParam.endsWith(DataFileTypeEnum::toFileExtension(DataFileTypeEnum::SPECIFICATION))) { if ( ! myState.specFileNameLoadWithDialog.isEmpty()) { cerr << qPrintable(moreThanOneSpecFileErrorMessage) << endl; hasFatalError = true; } else { myState.specFileNameLoadWithDialog = thisParam; } } else { myState.fileList.push_back(thisParam); } } } } catch (const ProgramParametersException& e) { cerr << e.whatString() << std::endl; hasFatalError = true; } if ( ( ! myState.specFileNameLoadWithDialog.isEmpty()) && ( ! myState.specFileNameLoadAll.isEmpty())) { cerr << qPrintable(moreThanOneSpecFileErrorMessage) << endl; hasFatalError = true; } if (hasFatalError) { exit(-1); } /* * If any files are listed, disable splash screen */ if ( ! myState.fileList.empty()) { myState.showSplash = false; } if ( ! myState.sceneFileName.isEmpty()) { myState.showSplash = false; } if ( ! myState.specFileNameLoadWithDialog.isEmpty()) { myState.showSplash = false; } if ( ! myState.specFileNameLoadAll.isEmpty()) { myState.showSplash = false; } } ProgramState::ProgramState() { sceneFileName = ""; sceneNameOrNumber = ""; windowSizeXY[0] = -1; windowSizeXY[1] = -1; windowPosXY[0] = -1; windowPosXY[1] = -1; graphicsSizeXY[0] = -1; graphicsSizeXY[1] = -1; showSplash = true; } connectome-workbench-1.4.2/src/Files/000077500000000000000000000000001360521144700174645ustar00rootroot00000000000000connectome-workbench-1.4.2/src/Files/AffineFile.cxx000066400000000000000000000223161360521144700222040ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AffineFile.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "DataFileException.h" #include "FileInformation.h" #include "NiftiIO.h" #include #include #include using namespace caret; using namespace std; AffineFile::AffineFile() { m_matrix = FloatMatrix::identity(4);//use 4x4 convention for in-memory } void AffineFile::setMatrix(const FloatMatrix& matrix) { int64_t inRows, inCols; matrix.getDimensions(inRows, inCols); CaretAssert(inCols == 4 && inRows > 2 && inRows < 5); m_matrix = FloatMatrix::identity(4);//set the final 0 0 0 1 row m_matrix[0] = matrix[0];//copy ONLY the rows that should change m_matrix[1] = matrix[1]; m_matrix[2] = matrix[2]; } FloatMatrix AffineFile::read34(const AString& filename) { FileInformation affineInfo(filename); if (!affineInfo.exists()) throw DataFileException("affine file '" + filename + "' does not exist"); fstream affineFile(filename.toLocal8Bit().constData(), fstream::in); if (!affineFile.good()) throw DataFileException("error opening file '" + filename + "' for reading"); FloatMatrix ret = FloatMatrix::identity(4);//to ensure the right size and the fourth 0 0 0 1 row for (int i = 0; i < 3; ++i)//DO NOT read the fourth row from the file into the matrix { for (int j = 0; j < 4; ++j) { affineFile >> ret[i][j]; if (!affineFile) throw DataFileException("error while reading file '" + filename + "'"); } } return ret; } void AffineFile::write44(const FloatMatrix& out, const AString& filename) { fstream affineFile(filename.toLocal8Bit().constData(), fstream::out); if (!affineFile.good()) { throw DataFileException("error opening file '" + filename + "' for writing"); } affineFile.setf(ios::fixed, ios::floatfield); affineFile.precision(10);//flirt appears to use 10, so do the same for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { affineFile << out[i][j]; if (j < 3) affineFile << " ";//double space like flirt if (!affineFile) throw DataFileException("error while writing file '" + filename + "'"); } affineFile << endl; } } void AffineFile::readWorld(const AString& filename, bool inverse) { FloatMatrix temp = read34(filename); if (inverse) temp = temp.inverse();//support reading reverse affines m_matrix = temp; } void AffineFile::writeWorld(const AString& filename, bool inverse) const { FloatMatrix temp = m_matrix; if (inverse) temp = temp.inverse();//and writing write44(temp, filename); } void AffineFile::readFlirt(const AString& filename, const AString& sourceName, const AString& targetName) { FloatMatrix flirtMat = read34(filename); FloatMatrix sourceMat, sourceScale, targetMat, targetScale; getFSLQuirks(sourceName, sourceMat, sourceScale); getFSLQuirks(targetName, targetMat, targetScale); //via aff_conv : world = targmat * trgscale^-1 * input * srcscale * sourcemat^-1 m_matrix = targetMat * targetScale.inverse() * flirtMat * sourceScale * sourceMat.inverse(); } void AffineFile::writeFlirt(const AString& filename, const AString& sourceName, const AString& targetName) const { FloatMatrix sourceMat, sourceScale, targetMat, targetScale; getFSLQuirks(sourceName, sourceMat, sourceScale); getFSLQuirks(targetName, targetMat, targetScale); FloatMatrix flirtMat = targetScale * targetMat.inverse() * m_matrix * sourceMat * sourceScale.inverse(); write44(flirtMat, filename); } void AffineFile::getFSLQuirks(const AString& niftiName, FloatMatrix& outSform, FloatMatrix& outScale) { NiftiIO myIO; myIO.openRead(niftiName); outSform = FloatMatrix(myIO.getHeader().getSForm());//NOTE: this is expected to return a 4x4 matrix with the 0 0 0 1 row intact outScale = FloatMatrix(myIO.getHeader().getFSLSpace()); } void AffineFile::readITK(const AString& filename) {//odd text format, need special parsing FileInformation itkInfo(filename); if (!itkInfo.exists()) throw DataFileException(filename, "ITK affine file does not exist"); fstream itkFile(filename.toLocal8Bit().constData(), fstream::in); if (!itkFile.good()) throw DataFileException(filename, "error opening file for reading"); string myline; if (!getline(itkFile, myline)) throw DataFileException(filename, "ITK affine file is empty"); if (myline != "#Insight Transform File V1.0") throw DataFileException(filename, "wrong header line for ITK affine file"); bool haveParam = false, haveFixed = false;//maybe they can be reordered, so just wait for both vector params(12, 0.0f), fixed(3, 0.0f); while (!(haveParam && haveFixed)) { if (!getline(itkFile, myline)) throw DataFileException(filename, "ITK affine file is truncated"); if (AString::fromStdString(myline).startsWith("Transform: ")) { if (myline != "Transform: MatrixOffsetTransformBase_double_3_3") throw DataFileException(filename, "unrecognized transformation type in ITK affine file"); } else if (!haveParam && AString::fromStdString(myline).startsWith("Parameters: ")) {//don't parse more than one Parameters line, to make sure we get the first stringstream parsestring(myline); string junk; parsestring >> junk;//strip "Parameters: " for (size_t i = 0; i < params.size(); ++i) { if (!(parsestring >> params[i])) throw DataFileException(filename, "expected 12 values in Parameters line, only parsed " + AString::number(i)); } haveParam = true; if (parsestring >> junk) CaretLogWarning("found extra characters on end of Parameters line in file '" + filename + "'"); } else if (!haveFixed && AString::fromStdString(myline).startsWith("FixedParameters: ")) {//ditto stringstream parsestring(myline); string junk; parsestring >> junk;//strip "FixedParameters: " for (size_t i = 0; i < fixed.size(); ++i) { if (!(parsestring >> fixed[i])) throw DataFileException(filename, "expected 3 values in FixedParameters line, only parsed " + AString::number(i)); } haveFixed = true; if (parsestring >> junk) CaretLogWarning("found extra characters on end of FixedParameters line in file '" + filename + "'"); } } FloatMatrix temp = FloatMatrix::identity(4);//to ensure the right size and the fourth 0 0 0 1 row for (int i = 0; i < 3; ++i) { temp[i][3] = params[9 + i] + fixed[i];//"ComputeOffset", https://github.com/hinerm/ITK/blob/master/Modules/Core/Transform/include/itkMatrixOffsetTransformBase.hxx#L729 for (int j = 0; j < 3; ++j) { temp[i][j] = params[i * 3 + j];//https://afni.nimh.nih.gov/afni/community/board/read.php?1,94478 temp[i][3] -= temp[i][j] * fixed[j];//the rest of the first link } } FloatMatrix flips = FloatMatrix::identity(4); flips[0][0] = -1; flips[1][1] = -1;//this is its own inverse, so we don't need to compute the inverse m_matrix = (flips * temp * flips).inverse();//convert from reverse, LPS transform to forwards, RAS transform } void AffineFile::writeITK(const AString& filename) const { fstream itkFile(filename.toLocal8Bit().constData(), fstream::out); FloatMatrix flips = FloatMatrix::identity(4); flips[0][0] = -1; flips[1][1] = -1;//this is its own inverse, so we don't need to compute the inverse FloatMatrix temp = (flips * m_matrix * flips).inverse();//convert from forwards RAS to inverse LPS if (!itkFile.good()) throw DataFileException(filename, "error opening ITK affine file for writing"); itkFile.setf(ios::fixed, ios::floatfield); itkFile.precision(16);//ITK uses 16 because it uses doubles, we only use single, but make them look similar anyway itkFile << "#Insight Transform File V1.0" << endl; itkFile << "#Transform 0" << endl; itkFile << "Transform: MatrixOffsetTransformBase_double_3_3" << endl; itkFile << "Parameters: "; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { itkFile << " " << temp[i][j]; } } for (int i = 0; i < 3; ++i)//use 0, 0, 0 center to eliminate translation/offset conversion silliness { itkFile << " " << temp[i][3]; } itkFile << endl; itkFile << "FixedParameters: 0 0 0" << endl; } connectome-workbench-1.4.2/src/Files/AffineFile.h000066400000000000000000000043561360521144700216350ustar00rootroot00000000000000#ifndef __AFFINE_FILE_H__ #define __AFFINE_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AString.h" #include "FloatMatrix.h" namespace caret { class AffineFile { FloatMatrix m_matrix; static FloatMatrix read34(const AString& filename);//helper to read a simple text affine static void write44(const FloatMatrix& out, const AString& filename);//helper for writing static void getFSLQuirks(const AString& niftiName, FloatMatrix& outSform, FloatMatrix& outScale);//just a convenience wrapper around the vector > version in NiftiHeaderIO public: AffineFile(); void readWorld(const AString& filename, bool inverse = false);//forward nifti coordinate transform, optionally reverse void writeWorld(const AString& filename, bool inverse = false) const; void readFlirt(const AString& filename, const AString& sourceName, const AString& targetName);//flirt convention matrix, requires source/target volumes void writeFlirt(const AString& filename, const AString& sourceName, const AString& targetName) const; void readITK(const AString& filename);//reverse, LPS rather than RAS, with strange encoding for translation void writeITK(const AString& filename) const; const FloatMatrix& getMatrix() const { return m_matrix; } void setMatrix(const FloatMatrix& matrix);//needs to do sanity checking, so don't inline }; } #endif //__AFFINE_FILE_H__ connectome-workbench-1.4.2/src/Files/AnnotationFile.cxx000066400000000000000000002414421360521144700231310ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_FILE_DECLARE__ #include "AnnotationFile.h" #undef __ANNOTATION_FILE_DECLARE__ #include "AnnotationBox.h" #include "AnnotationCoordinate.h" #include "AnnotationFileXmlReader.h" #include "AnnotationFileXmlWriter.h" #include "AnnotationGroup.h" #include "AnnotationLine.h" #include "AnnotationOval.h" #include "AnnotationPercentSizeText.h" #include "AnnotationPointSizeText.h" #include "BrainConstants.h" #include "CaretAssert.h" #include "CaretColorEnum.h" #include "CaretLogger.h" #include "DataFileContentCopyMoveParameters.h" #include "DataFileException.h" #include "DisplayGroupAndTabItemHelper.h" #include "EventAnnotationAddToRemoveFromFile.h" #include "EventAnnotationGroupGetWithKey.h" #include "EventAnnotationGrouping.h" #include "EventAnnotationTextSubstitutionInvalidate.h" #include "EventBrowserTabDelete.h" #include "EventBrowserTabNewClone.h" #include "EventManager.h" #include "EventTileTabsConfigurationModification.h" #include "GiftiMetaData.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::AnnotationFile * \brief File containing annotations. * \ingroup Files */ /** * Constructor for annotation file that saves annotations to a file. */ AnnotationFile::AnnotationFile() : CaretDataFile(DataFileTypeEnum::ANNOTATION), EventListenerInterface(), DataFileContentCopyMoveInterface(), DisplayGroupAndTabItemInterface(), m_fileSubType(ANNOTATION_FILE_SAVE_TO_FILE) { initializeAnnotationFile(); } /** * Constructor for annotation file that accepts a sub file type * so that annotations may be saved to a file or a scene. * * This method is intended for use by the "Brain" for its * scene annotation file. * * @param fileSubType * Type of saving of annotations. */ AnnotationFile::AnnotationFile(const AnnotationFileSubType fileSubType) : CaretDataFile(DataFileTypeEnum::ANNOTATION), m_fileSubType(fileSubType) { initializeAnnotationFile(); } /** * Destructor. */ AnnotationFile::~AnnotationFile() { clearPrivate(); EventManager::get()->removeAllEventsFromListener(this); delete m_displayGroupAndTabItemHelper; delete m_sceneAssistant; } /** * Clear the content of this file. * This method is virtual so do not call from constructor/destructor. */ void AnnotationFile::clear() { const AString nameOfFile = getFileName(); CaretDataFile::clear(); clearPrivate(); switch (m_fileSubType) { case ANNOTATION_FILE_SAVE_TO_FILE: break; case ANNOTATION_FILE_SAVE_TO_SCENE: { /* * Do not clear the name of the scene annotation file. */ const bool modStatus = isModified(); setFileName(nameOfFile); if ( ! modStatus) { clearModified(); } } break; } } /** * Clear the content of this file. */ void AnnotationFile::clearPrivate() { m_metadata->clear(); m_annotationGroups.clear(); m_removedAnnotations.clear(); } /** * Set the selection for editing status of all annotations. * * @param windowIndex * Index of window for annotation selection. * @param selectedStatus * New selection status for all annotations. */ void AnnotationFile::setAllAnnotationsSelectedForEditing(const int32_t windowIndex, const bool selectedStatus) { std::vector allAnnotations; getAllAnnotations(allAnnotations); for (std::vector::iterator iter = allAnnotations.begin(); iter != allAnnotations.end(); iter++) { (*iter)->setSelectedForEditing(windowIndex, selectedStatus); } } /** * Copy constructor. * @param obj * Object that is copied. */ AnnotationFile::AnnotationFile(const AnnotationFile& obj) : CaretDataFile(obj), EventListenerInterface(), DataFileContentCopyMoveInterface(), DisplayGroupAndTabItemInterface(obj), m_fileSubType(obj.m_fileSubType) { initializeAnnotationFile(); this->copyHelperAnnotationFile(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ AnnotationFile& AnnotationFile::operator=(const AnnotationFile& obj) { if (this != &obj) { CaretDataFile::operator=(obj); this->copyHelperAnnotationFile(obj); } return *this; } /** * Initialize an instance of an annotation file. */ void AnnotationFile::initializeAnnotationFile() { m_uniqueKeyGenerator = 0; m_metadata.grabNew(new GiftiMetaData()); m_displayGroupAndTabItemHelper = new DisplayGroupAndTabItemHelper(); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_displayGroupAndTabItemHelper", "DisplayGroupAndTabItemHelper", m_displayGroupAndTabItemHelper); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_ADD_TO_REMOVE_FROM_FILE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_GROUP_GET_WITH_KEY); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_GROUPING); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_TEXT_SUBSTITUTION_INVALIDATE); /* NEED THIS AFTER Tile Tabs have been modified */ EventManager::get()->addProcessedEventListener(this, EventTypeEnum::EVENT_TILE_TABS_MODIFICATION); EventManager::get()->addProcessedEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_DELETE); EventManager::get()->addProcessedEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_NEW_CLONE); } /** * Get the coordinate space annotation group with the given annotation's space and for tab/window * spaces, the tab/window index. If the group does not exist, it will be created. * * @param annotation * Annotation whose group is needed. * @return * Group for the coordinateSpace. */ AnnotationGroup* AnnotationFile::getSpaceAnnotationGroup(const Annotation* annotation) { const AnnotationCoordinateSpaceEnum::Enum annotationSpace = annotation->getCoordinateSpace(); SpacerTabIndex annotationSpacerTabIndex; int32_t annotationTabOrWindowIndex = -1; switch (annotationSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: annotationSpacerTabIndex = annotation->getSpacerTabIndex(); break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: annotationTabOrWindowIndex = annotation->getTabIndex(); break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: annotationTabOrWindowIndex = annotation->getWindowIndex(); break; } for (AnnotationGroupIterator groupIter = m_annotationGroups.begin(); groupIter != m_annotationGroups.end(); groupIter++) { AnnotationGroup* group = (*groupIter).data(); if (group->getGroupType() == AnnotationGroupTypeEnum::SPACE) { if (group->getCoordinateSpace() == annotationSpace) { switch (annotationSpace) { case AnnotationCoordinateSpaceEnum::CHART: case AnnotationCoordinateSpaceEnum::STEREOTAXIC: case AnnotationCoordinateSpaceEnum::SURFACE: return group; break; case AnnotationCoordinateSpaceEnum::SPACER: if (annotationSpacerTabIndex == group->getSpacerTabIndex()) { return group; } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::TAB: case AnnotationCoordinateSpaceEnum::WINDOW: if (annotationTabOrWindowIndex == group->getTabOrWindowIndex()) { return group; } break; } } } } switch (annotationSpace) { case AnnotationCoordinateSpaceEnum::CHART: case AnnotationCoordinateSpaceEnum::STEREOTAXIC: case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: CaretAssert((annotationTabOrWindowIndex >= 0) && (annotationTabOrWindowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)); break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: CaretAssert((annotationTabOrWindowIndex >= 0) && (annotationTabOrWindowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)); break; } AnnotationGroup* group = new AnnotationGroup(this, AnnotationGroupTypeEnum::SPACE, generateUniqueKey(), annotationSpace, annotationTabOrWindowIndex, annotationSpacerTabIndex); group->setItemParent(this); m_annotationGroups.push_back(QSharedPointer(group)); return group; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void AnnotationFile::copyHelperAnnotationFile(const AnnotationFile& obj) { CaretAssertMessage(0, "Copying of annotation file not implemented. " "Will need to check subtype or have a 'clone' method' that each " "subclass (AnnotationText) implements."); *m_displayGroupAndTabItemHelper = *obj.m_displayGroupAndTabItemHelper; } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void AnnotationFile::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_ADD_TO_REMOVE_FROM_FILE) { EventAnnotationAddToRemoveFromFile* annEvent = dynamic_cast(event); CaretAssert(annEvent); AnnotationFile* annotationFile = annEvent->getAnnotationFile(); Annotation* annotation = annEvent->getAnnotation(); switch (annEvent->getMode()) { case EventAnnotationAddToRemoveFromFile::MODE_CREATE: if (annotationFile == this) { if (restoreAnnotationAddIfNotFound(annotation)) { annEvent->setSuccessful(true); } } break; case EventAnnotationAddToRemoveFromFile::MODE_CUT: if (removeAnnotationWithUndoRedo(annotation)) { annEvent->setSuccessful(true); } break; case EventAnnotationAddToRemoveFromFile::MODE_DELETE: if (removeAnnotationWithUndoRedo(annotation)) { annEvent->setSuccessful(true); } break; case EventAnnotationAddToRemoveFromFile::MODE_DUPLICATE: if (annotationFile == this) { if (restoreAnnotationAddIfNotFound(annotation)) { annEvent->setSuccessful(true); } } break; case EventAnnotationAddToRemoveFromFile::MODE_PASTE: if (annotationFile == this) { if (restoreAnnotationAddIfNotFound(annotation)) { annEvent->setSuccessful(true); } } break; case EventAnnotationAddToRemoveFromFile::MODE_UNCREATE: if (annotationFile == this) { if (removeAnnotationWithUndoRedo(annotation)) { annEvent->setSuccessful(true); } } break; case EventAnnotationAddToRemoveFromFile::MODE_UNCUT: if (restoreAnnotation(annotation)) { annEvent->setSuccessful(true); } break; case EventAnnotationAddToRemoveFromFile::MODE_UNDELETE: if (restoreAnnotation(annotation)) { annEvent->setSuccessful(true); } break; case EventAnnotationAddToRemoveFromFile::MODE_UNDUPLICATE: if (annotationFile == this) { if (removeAnnotationWithUndoRedo(annotation)) { annEvent->setSuccessful(true); } } break; case EventAnnotationAddToRemoveFromFile::MODE_UNPASTE: if (annotationFile == this) { if (removeAnnotationWithUndoRedo(annotation)) { annEvent->setSuccessful(true); } } break; } } else if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_GROUP_GET_WITH_KEY) { EventAnnotationGroupGetWithKey* getGroupEvent = dynamic_cast(event); CaretAssert(getGroupEvent); const AnnotationGroupKey groupKey = getGroupEvent->getGroupKey(); for (AnnotationGroupIterator groupIter = m_annotationGroups.begin(); groupIter != m_annotationGroups.end(); groupIter++) { AnnotationGroup* group = (*groupIter).data(); if (groupKey == group->getAnnotationGroupKey()) { getGroupEvent->setAnnotationGroup(group); getGroupEvent->setEventProcessed(); return; } } } else if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_GROUPING) { EventAnnotationGrouping* groupEvent = dynamic_cast(event); CaretAssert(event); if (groupEvent->getAnnotationGroupKey().getAnnotationFile() == this) { switch (groupEvent->getMode()) { case EventAnnotationGrouping::MODE_INVALID: break; case EventAnnotationGrouping::MODE_GROUP: processGroupingAnnotations(groupEvent); break; case EventAnnotationGrouping::MODE_REGROUP: processRegroupingAnnotations(groupEvent); break; case EventAnnotationGrouping::MODE_UNGROUP: processUngroupingAnnotations(groupEvent); break; } } } else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_DELETE) { EventBrowserTabDelete* deleteEvent = dynamic_cast(event); CaretAssert(deleteEvent); const int32_t tabIndex = deleteEvent->getBrowserTabIndex(); removeAnnotationsInTab(tabIndex); } else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_NEW_CLONE) { EventBrowserTabNewClone* cloneTabEvent = dynamic_cast(event); CaretAssert(cloneTabEvent); const int32_t cloneToTabIndex = cloneTabEvent->getNewBrowserTabIndex(); const int32_t cloneFromTabIndex = cloneTabEvent->getIndexOfBrowserTabThatWasCloned(); cloneAnnotationsFromTabToTab(cloneFromTabIndex, cloneToTabIndex); } else if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_TEXT_SUBSTITUTION_INVALIDATE) { EventAnnotationTextSubstitutionInvalidate* textSubEvent = dynamic_cast(event); CaretAssert(textSubEvent); for (auto ag : m_annotationGroups) { std::vector annotations; ag->getAllAnnotations(annotations); for (auto ann : annotations) { ann->invalidateTextSubstitution(); } } textSubEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_TILE_TABS_MODIFICATION) { EventTileTabsConfigurationModification* modEvent = dynamic_cast(event); CaretAssert(modEvent); updateSpacerAnnotationsAfterTileTabsModification(modEvent); } } /** * @return True if this file is empty, else false. */ bool AnnotationFile::isEmpty() const { for (AnnotationGroupConstIterator groupIter = m_annotationGroups.begin(); groupIter != m_annotationGroups.end(); groupIter++) { if ( ! (*groupIter)->isEmpty()) { return false; } } return true; } /** * @return The structure for this file. */ StructureEnum::Enum AnnotationFile::getStructure() const { return StructureEnum::ALL; } /** * Set the structure for this file. * @param structure * New structure for this file. */ void AnnotationFile::setStructure(const StructureEnum::Enum /*structure*/) { /* nothing */ } /** * @return Get access to the file's metadata. */ GiftiMetaData* AnnotationFile::getFileMetaData() { return m_metadata; } /** * @return Get access to unmodifiable file's metadata. */ const GiftiMetaData* AnnotationFile::getFileMetaData() const { return m_metadata; } /** * Add information about the content of this file. * * @param dataFileInformation * Will contain information about this file. */ void AnnotationFile::addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) { CaretDataFile::addToDataFileContentInformation(dataFileInformation); } /** * Private method for adding annotations to this file. * * In the GUI, annotations are added using the AnnotationRedoUndoCommand * which allows undo/redo operations. * * @param annotation * Annotation that is added. * @param uniqueKey * Unique key for the annotation. */ void AnnotationFile::addAnnotationPrivate(Annotation* annotation, const int32_t uniqueKey) { if (annotation->getType() == AnnotationTypeEnum::TEXT) { AnnotationPointSizeText* pointSizeAnnotation = dynamic_cast(annotation); if (pointSizeAnnotation != NULL) { CaretLogWarning("Point size text annotations are not supported in AnnotationFile. " "The annotation has been discarded."); delete annotation; return; } } CaretAssert(uniqueKey > 0); if (uniqueKey <= 0) { CaretLogSevere("invalid key less than zero."); } AnnotationGroup* group = getSpaceAnnotationGroup(annotation); CaretAssert(group); annotation->setUniqueKey(uniqueKey); group->addAnnotationPrivate(annotation); setModified(); } void AnnotationFile::addAnnotationPrivateSharedPointer(QSharedPointer& annotation, const int32_t uniqueKey) { if (annotation->getType() == AnnotationTypeEnum::TEXT) { AnnotationPointSizeText* pointSizeAnnotation = dynamic_cast(annotation.data()); if (pointSizeAnnotation != NULL) { CaretLogWarning("Point size text annotations are not supported in AnnotationFile. " "The annotation has been discarded."); return; } } CaretAssert(uniqueKey > 0); if (uniqueKey <= 0) { CaretLogSevere("invalid key less than zero."); } AnnotationGroup* group = getSpaceAnnotationGroup(annotation.data()); CaretAssert(group); annotation->setUniqueKey(uniqueKey); group->addAnnotationPrivateSharedPointer(annotation); setModified(); } /** * Add an annotation to this file while the file is being read. * File will take ownership of the annotation. * * In the GUI, annotations are added using the AnnotationRedoUndoCommand * which allows undo/redo operations. * * @param annotation * Annotation that is added. */ void AnnotationFile::addAnnotationDuringFileVersionOneReading(Annotation* annotation) { addAnnotationPrivate(annotation, generateUniqueKey()); } /** * Add a group while reading an annotation file. * * @param groupType * Type of annotation group. * @param coordinateSpace * Coordinate space of the group's annotaitons. * @param tabOrWindowIndex * Tab or window index for groups in tab or window space. * @param uniqueKey * Unique key for the annotation group. * @param annotations * Annotation that are members of the group. * @throw DataFileException * If there is an error. */ void AnnotationFile::addAnnotationGroupDuringFileReading(const AnnotationGroupTypeEnum::Enum groupType, const AnnotationCoordinateSpaceEnum::Enum coordinateSpace, const int32_t tabOrWindowIndex, const SpacerTabIndex& spacerTabIndex, const int32_t uniqueKey, const std::vector& annotations) { switch (groupType) { case AnnotationGroupTypeEnum::INVALID: throw DataFileException("INVALID group type is not allowed while annotation file."); break; case AnnotationGroupTypeEnum::SPACE: break; case AnnotationGroupTypeEnum::USER: break; } switch (coordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: if ( ! spacerTabIndex.isValid()) { throw DataFileException("Invalid spacer tab index for group while reading annotation file: " + spacerTabIndex.toString()); } break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: throw DataFileException("VIEWPORT coordinate space is not allowed for group while annotation file."); break; case AnnotationCoordinateSpaceEnum::TAB: case AnnotationCoordinateSpaceEnum::WINDOW: if ((tabOrWindowIndex < 0) || (tabOrWindowIndex >= BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)) { throw DataFileException("Invalid tab/window index for group while reading annotation file: " + QString::number(tabOrWindowIndex)); } break; } if (uniqueKey <= 0) { throw DataFileException("Invalid unique key for group while reading annotation file: " + AString::number(uniqueKey)); } for (AnnotationGroupIterator groupIter = m_annotationGroups.begin(); groupIter != m_annotationGroups.end(); groupIter++) { QSharedPointer group = *groupIter; if (group->getUniqueKey() == uniqueKey) { throw DataFileException("More than one group using unique key " + AString::number(uniqueKey) + " while reading annotation file."); } /* * For default groups (NOT user groups), there may not be * more than one group of each type. * * There is: * - One group for stereotaxic * - One group for surface * - One group for each Tab * - One group for each Window */ if (group->getGroupType() == groupType) { if (groupType == AnnotationGroupTypeEnum::SPACE) { if (group->getCoordinateSpace() == coordinateSpace) { switch (coordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: case AnnotationCoordinateSpaceEnum::STEREOTAXIC: case AnnotationCoordinateSpaceEnum::SURFACE: throw DataFileException("There is more than one annotation space group with space " + AnnotationCoordinateSpaceEnum::toGuiName(coordinateSpace) + ". Only one space group for each space is allowed."); break; case AnnotationCoordinateSpaceEnum::SPACER: if (spacerTabIndex == group->getSpacerTabIndex()) { throw DataFileException("There is more than one annotation space group with space " + AnnotationCoordinateSpaceEnum::toGuiName(coordinateSpace) + " for spacer tab " + spacerTabIndex.toString() + ". Only one space group for each space is allowed."); } break; case AnnotationCoordinateSpaceEnum::TAB: if (tabOrWindowIndex == group->getTabOrWindowIndex()) { throw DataFileException("There is more than one annotation space group with space " + AnnotationCoordinateSpaceEnum::toGuiName(coordinateSpace) + " for tab " + AString::number(tabOrWindowIndex) + ". Only one space group for each space is allowed."); } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: if (tabOrWindowIndex == group->getTabOrWindowIndex()) { throw DataFileException("There is more than one annotation space group with space " + AnnotationCoordinateSpaceEnum::toGuiName(coordinateSpace) + " for window " + AString::number(tabOrWindowIndex) + ". Only one space group for each space is allowed."); } break; } } } } } AnnotationGroup* group = new AnnotationGroup(this, groupType, uniqueKey, coordinateSpace, tabOrWindowIndex, spacerTabIndex); for (std::vector::const_iterator annIter = annotations.begin(); annIter != annotations.end(); annIter++) { group->addAnnotationPrivate(*annIter); } group->setItemParent(this); m_annotationGroups.push_back(QSharedPointer(group)); } /** * Restore an annotation that had been removed and possibly * add if it was not restored (probably creating a new * annotation). * * @param annotation * Annotation that is restored. * @return * True if the annotation was restored or added, * otherwise false. */ bool AnnotationFile::restoreAnnotationAddIfNotFound(Annotation* annotation) { if (restoreAnnotation(annotation)) { return true; } addAnnotationPrivate(annotation, generateUniqueKey()); return true; } /** * Restore an annotation that had been removed. * * @param annotation * Annotation that is restored. * @return * True if the annotation was restored otherwise false. */ bool AnnotationFile::restoreAnnotation(Annotation* annotation) { for (std::set >::iterator iter = m_removedAnnotations.begin(); iter != m_removedAnnotations.end(); iter++) { QSharedPointer annotationPointer = *iter; if (annotationPointer.data() == annotation) { addAnnotationPrivateSharedPointer(annotationPointer, annotationPointer->getUniqueKey()); m_removedAnnotations.erase(iter); setModified(); /* * Successfully restored */ return true; } } return false; } /** * Remove the annotation for use with REDO/UNDO. * NOTE: The annotation is NOT deleted but instead * it is saved so that it can be 'undeleted' or 're-pasted'. * * @param annotation * Annotation that is removed. * @return * True if the annotation was removed, otherwise false. */ bool AnnotationFile::removeAnnotationWithUndoRedo(Annotation* annotation) { return removeAnnotationPrivate(annotation, true); // for (AnnotationGroupIterator groupIter = m_annotationGroups.begin(); // groupIter != m_annotationGroups.end(); // groupIter++) { // QSharedPointer group = *groupIter; // QSharedPointer removedAnnotationPointer; // if (group->removeAnnotation(annotation, // removedAnnotationPointer)) { // // removedAnnotationPointer->invalidateAnnotationGroupKey(); // // m_removedAnnotations.insert(removedAnnotationPointer); // // /* // * Remove group if it is empty. // */ // if (group->isEmpty()) { // m_annotationGroups.erase(groupIter); // } // // setModified(); // return true; // } // } // // /* // * Annotation not in this file // */ // return false; } /** * Remove the * * @param annotation * Annotation that is removed. * @param keepAnnotationForUndoRedoFlag * If true, keep the annotation available for any * undo or redo operation. * @return * True if the annotation was removed, otherwise false. */ bool AnnotationFile::removeAnnotationPrivate(Annotation* annotation, const bool keepAnnotationForUndoRedoFlag) { for (AnnotationGroupIterator groupIter = m_annotationGroups.begin(); groupIter != m_annotationGroups.end(); groupIter++) { QSharedPointer group = *groupIter; QSharedPointer removedAnnotationPointer; if (group->removeAnnotation(annotation, removedAnnotationPointer)) { removedAnnotationPointer->invalidateAnnotationGroupKey(); if (keepAnnotationForUndoRedoFlag) { m_removedAnnotations.insert(removedAnnotationPointer); } /* * Remove group if it is empty. */ if (group->isEmpty()) { m_annotationGroups.erase(groupIter); } setModified(); return true; } } /* * Annotation not in this file */ return false; } /** * Clone annotations in 'fromTabIndex' to 'toTabIndex' * * @param fromTabIndex * Clone annotations from this tab index * @param toTabIndex * Clone annotations into this tab index * @return * True if any annotations were cloned. */ bool AnnotationFile::cloneAnnotationsFromTabToTab(const int32_t fromTabIndex, const int32_t toTabIndex) { /* * Find annotation group(s) in tab space * with the given tab index. */ bool annotationsWereClonedFlag(false); for (AnnotationGroupIterator groupIter = m_annotationGroups.begin(); groupIter != m_annotationGroups.end(); groupIter++) { QSharedPointer& group = *groupIter; if (group->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::TAB) { if (group->getTabOrWindowIndex() == fromTabIndex) { std::vector annotations; group->getAllAnnotations(annotations); for (auto ann : annotations) { CaretAssert(ann->getTabIndex() == fromTabIndex); Annotation* newAnn = ann->clone(); newAnn->setTabIndex(toTabIndex); addAnnotationPrivate(newAnn, generateUniqueKey()); annotationsWereClonedFlag = true; } } } } return annotationsWereClonedFlag; } /** * Remove all annotations in tab space in the given tab. * * @param tabIndex * Index of the tab. * @return * True if any annotations were removed. */ bool AnnotationFile::removeAnnotationsInTab(const int32_t tabIndex) { std::vector groupsToRemoveIterators; /* * Find annotation group(s) in tab space * with the given tab index. */ for (AnnotationGroupIterator groupIter = m_annotationGroups.begin(); groupIter != m_annotationGroups.end(); groupIter++) { QSharedPointer& group = *groupIter; if (group->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::TAB) { if (group->getTabOrWindowIndex() == tabIndex) { groupsToRemoveIterators.push_back(groupIter); } } } /* * Remove the groups (shared pointers will do all deleting) * NOTE: MUST delete iterators that are closest to the end first * as any iterators that point to elements at the erased iterator * or beyond are invalidated. */ const int32_t numGroupsToRemove = static_cast(groupsToRemoveIterators.size()); for (int32_t i = (numGroupsToRemove - 1); i >= 0; i--) { CaretAssertVectorIndex(groupsToRemoveIterators, i); m_annotationGroups.erase(groupsToRemoveIterators[i]); } return ( ! groupsToRemoveIterators.empty()); } /** * Get all annotations in this file. * * @param annotationsOut * Output containing all annotations. */ void AnnotationFile::getAllAnnotations(std::vector& annotationsOut) const { annotationsOut.clear(); for (AnnotationGroupConstIterator groupIter = m_annotationGroups.begin(); groupIter != m_annotationGroups.end(); groupIter++) { std::vector groupAnnotations; (*groupIter)->getAllAnnotations(groupAnnotations); annotationsOut.insert(annotationsOut.end(), groupAnnotations.begin(), groupAnnotations.end()); } } /** * Get all annotation groups in this file. * * @param annotationGroupsOut * Output containing all annotation groups. */ void AnnotationFile::getAllAnnotationGroups(std::vector& annotationGroupsOut) const { annotationGroupsOut.clear(); for (AnnotationGroupConstIterator groupIter = m_annotationGroups.begin(); groupIter != m_annotationGroups.end(); groupIter++) { annotationGroupsOut.push_back((*groupIter).data()); } } /** * Does this file contain annotations in the given coordinate space? * * @param coordinateSpace * The coordinate space. * @return * True if there are annotations in the given coordinate space, else false. */ bool AnnotationFile::hasAnnotationsInCoordinateSpace(const AnnotationCoordinateSpaceEnum::Enum coordinateSpace) const { for (const auto groupIter : m_annotationGroups) { if (groupIter->getCoordinateSpace() == coordinateSpace) { return true; } } return false; } /** * Group annotations. * * @param groupingEvent * The grouping event. */ void AnnotationFile::processGroupingAnnotations(EventAnnotationGrouping* groupingEvent) { CaretAssert(groupingEvent); AnnotationGroupKey spaceGroupKey = groupingEvent->getAnnotationGroupKey(); std::vector annotationsToGroup = groupingEvent->getAnnotations(); if (annotationsToGroup.size() < 2) { groupingEvent->setErrorMessage("PROGRAM ERROR: Trying to group annotations less than two annotations"); CaretAssert(0); return; } AnnotationGroupIterator spaceGroupIter = m_annotationGroups.end(); for (spaceGroupIter = m_annotationGroups.begin(); spaceGroupIter != m_annotationGroups.end(); spaceGroupIter++) { AnnotationGroup* group = (*spaceGroupIter).data(); if (group->getAnnotationGroupKey().getGroupType() == AnnotationGroupTypeEnum::SPACE) { if (group->containsAllAnnotation(annotationsToGroup)) { break; } } } if (spaceGroupIter == m_annotationGroups.end()) { groupingEvent->setErrorMessage("Did not find annotations in a space group. This may occur when " "annotations have been ungrouped, an annotation is modified that moves " "it to a different group or the annotation is deleted, and there " "is an attempt to regroup the annotations."); return; } AnnotationGroup* spaceGroup = (*spaceGroupIter).data(); CaretAssert(spaceGroup); // AnnotationGroupKey spaceGroupKey = groupingEvent->getAnnotationGroupKey(); // // AnnotationGroup* spaceGroup = NULL; // AnnotationGroupIterator spaceGroupIter = m_annotationGroups.end(); // for (spaceGroupIter = m_annotationGroups.begin(); // spaceGroupIter != m_annotationGroups.end(); // spaceGroupIter++) { // QSharedPointer groupPointer = *spaceGroupIter; // if (spaceGroupKey == groupPointer->getAnnotationGroupKey()) { // spaceGroup = groupPointer.data(); // break; // } // } // // if (spaceGroup == NULL) { // groupingEvent->setErrorMessage("PROGRAM ERROR: Did not find space group for source of grouping annotations"); // return; // } groupingEvent->setEventProcessed(); if (spaceGroup->getGroupType() != AnnotationGroupTypeEnum::SPACE) { groupingEvent->setErrorMessage("PROGRAM ERROR: Trying to group annotations in a NON-space group"); CaretAssert(0); return; } bool allValidFlag = true; std::vector > movedAnnotations; for (std::vector::iterator annIter = annotationsToGroup.begin(); annIter != annotationsToGroup.end(); annIter++) { QSharedPointer annPtr; if (spaceGroup->removeAnnotation(*annIter, annPtr)) { movedAnnotations.push_back(annPtr); } else { allValidFlag = false; break; } } if ( ! allValidFlag) { for (std::vector >::iterator annPtrIter = movedAnnotations.begin(); annPtrIter != movedAnnotations.end(); annPtrIter++) { spaceGroup->addAnnotationPrivateSharedPointer(*annPtrIter); } groupingEvent->setErrorMessage("PROGRAM ERROR: Failed to remove an anntotation from its space group."); return; } AnnotationGroup* group = new AnnotationGroup(this, AnnotationGroupTypeEnum::USER, generateUniqueKey(), spaceGroup->getCoordinateSpace(), spaceGroup->getTabOrWindowIndex(), spaceGroup->getSpacerTabIndex()); for (std::vector >::iterator annPtrIter = movedAnnotations.begin(); annPtrIter != movedAnnotations.end(); annPtrIter++) { group->addAnnotationPrivateSharedPointer(*annPtrIter); } group->setItemParent(this); groupingEvent->setGroupKeyToWhichAnnotationsWereMoved(group->getAnnotationGroupKey()); /* * If space group becomes empty, remove it. * Need to remove it before adding new group, otherwise * iterator will become invalid */ if (spaceGroup->isEmpty()) { m_annotationGroups.erase(spaceGroupIter); } /* * Add new user group */ m_annotationGroups.push_back(QSharedPointer(group)); setModified(); } /** * Group annotations. * * @param groupingEvent * The grouping event. */ void AnnotationFile::processUngroupingAnnotations(EventAnnotationGrouping* groupingEvent) { CaretAssert(groupingEvent); AnnotationGroupKey userGroupKey = groupingEvent->getAnnotationGroupKey(); AnnotationGroupIterator userGroupIter = m_annotationGroups.end(); for (userGroupIter = m_annotationGroups.begin(); userGroupIter != m_annotationGroups.end(); userGroupIter++) { if (userGroupKey == (*userGroupIter)->getAnnotationGroupKey()) { break; } } if (userGroupIter == m_annotationGroups.end()) { groupingEvent->setErrorMessage("PROGRAM ERROR: Did not find group for ungrouping annotations"); return; } AnnotationGroup* userGroup = (*userGroupIter).data(); CaretAssert(userGroup); if (userGroup->getGroupType() != AnnotationGroupTypeEnum::USER) { groupingEvent->setErrorMessage("PROGRAM ERROR: Trying to ungroup annotations in a NON-user group"); CaretAssert(0); return; } std::vector > allGroupAnnotations; userGroup->removeAllAnnotations(allGroupAnnotations); /** * Remove the group since it is empty. Must be done before adding annotations back to * space group since the space group may not exist and if a new * space group is created the iterator will be invalid. */ m_annotationGroups.erase(userGroupIter); for (std::vector >::iterator annIter = allGroupAnnotations.begin(); annIter != allGroupAnnotations.end(); annIter++) { QSharedPointer annPtr = *annIter; AnnotationGroup* spaceGroup = getSpaceAnnotationGroup(annPtr.data()); spaceGroup->addAnnotationPrivateSharedPointer(annPtr); } groupingEvent->setEventProcessed(); setModified(); } /** * Group annotations. * * @param groupingEvent * The grouping event. */ void AnnotationFile::processRegroupingAnnotations(EventAnnotationGrouping* groupingEvent) { CaretAssert(groupingEvent); /* * Unique key of group that annotations were once a member of */ const int32_t userGroupUniqueKey = groupingEvent->getAnnotationGroupKey().getUserGroupUniqueKey(); CaretAssert(userGroupUniqueKey > 0); std::vector annotations; std::set groups; /* * Find annotations in ONE space group that were * previously assigned to the previous user group. */ //AnnotationGroupIterator spaceGroupIter = m_annotationGroups.end(); for (AnnotationGroupIterator spaceGroupIter = m_annotationGroups.begin(); spaceGroupIter != m_annotationGroups.end(); spaceGroupIter++) { AnnotationGroup* group = (*spaceGroupIter).data(); switch (group->getGroupType()) { case AnnotationGroupTypeEnum::INVALID: break; case AnnotationGroupTypeEnum::SPACE: { std::vector groupAnnotations; group->getAllAnnotations(groupAnnotations); for (std::vector::iterator annIter = groupAnnotations.begin(); annIter != groupAnnotations.end(); annIter++) { Annotation* ann = *annIter; if (ann->getAnnotationGroupKey().getUserGroupUniqueKey() == userGroupUniqueKey) { groups.insert(group); annotations.push_back(ann); } } } break; case AnnotationGroupTypeEnum::USER: break; } } const int32_t windowIndex = groupingEvent->getWindowIndex(); /* * Annotations must be in one space group (same space!) */ if (groups.size() == 1) { AnnotationGroup* spaceGroup = *(groups.begin()); const int32_t numAnn = static_cast(annotations.size()); if (numAnn > 1) { AnnotationGroup* group = new AnnotationGroup(this, AnnotationGroupTypeEnum::USER, reuseUniqueKeyOrGenerateNewUniqueKey(userGroupUniqueKey), spaceGroup->getCoordinateSpace(), spaceGroup->getTabOrWindowIndex(), spaceGroup->getSpacerTabIndex()); bool allValidFlag = true; std::vector > movedAnnotations; for (std::vector::iterator annIter = annotations.begin(); annIter != annotations.end(); annIter++) { QSharedPointer annPtr; if (spaceGroup->removeAnnotation(*annIter, annPtr)) { movedAnnotations.push_back(annPtr); } else { allValidFlag = false; break; } } if ( ! allValidFlag) { for (std::vector >::iterator annPtrIter = movedAnnotations.begin(); annPtrIter != movedAnnotations.end(); annPtrIter++) { spaceGroup->addAnnotationPrivateSharedPointer(*annPtrIter); } groupingEvent->setErrorMessage("PROGRAM ERROR: Failed to remove an anntotation from its space group."); return; } for (std::vector >::iterator annPtrIter = movedAnnotations.begin(); annPtrIter != movedAnnotations.end(); annPtrIter++) { if ((windowIndex >= 0) && (windowIndex < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)) { (*annPtrIter)->setSelectedForEditing(windowIndex, true); } group->addAnnotationPrivateSharedPointer(*annPtrIter); } group->setItemParent(this); m_annotationGroups.push_back(QSharedPointer(group)); /* * If the space group is empty it is no longer needed * so delete it. */ if (spaceGroup->isEmpty()) { for (AnnotationGroupIterator spaceGroupIter = m_annotationGroups.begin(); spaceGroupIter != m_annotationGroups.end(); spaceGroupIter++) { if (spaceGroup == (*spaceGroupIter).data()) { m_annotationGroups.erase(spaceGroupIter); break; } } } groupingEvent->setGroupKeyToWhichAnnotationsWereMoved(group->getAnnotationGroupKey()); setModified(); } else { groupingEvent->setErrorMessage("ERROR: Unable to regroup annotations due to only one annotation for regrouping."); } } else { groupingEvent->setErrorMessage("ERROR: Annotations that were in a previous group are no longer " "in the same space group."); } } /** * Clear drawn in window status for all annotations. */ void AnnotationFile::clearAllAnnotationsDrawnInWindowStatus() { std::vector allAnnotations; getAllAnnotations(allAnnotations); for (std::vector::iterator annIter = allAnnotations.begin(); annIter != allAnnotations.end(); annIter++) { (*annIter)->clearDrawnInWindowStatusForAllWindows(); } } /** * Get annotations drawin in the given window. * * @param windowIndex * Index of the window. * @param annotationsOut * Output containing annotations with draw in window status set for * the given window index. */ void AnnotationFile::getAllAnnotationWithDrawnInWindowStatusSet(const int32_t windowIndex, std::vector& annotationsOut) { std::vector allAnnotations; getAllAnnotations(allAnnotations); for (std::vector::iterator annIter = allAnnotations.begin(); annIter != allAnnotations.end(); annIter++) { if ((*annIter)->isDrawnInWindowStatus(windowIndex)) { annotationsOut.push_back(*annIter); } } } /** * @return true if file is modified, else false. */ bool AnnotationFile::isModified() const { if (CaretDataFile::isModified()) { return true; } if (m_metadata->isModified()) { return true; } for (AnnotationGroupConstIterator iter = m_annotationGroups.begin(); iter != m_annotationGroups.end(); iter++) { if ((*iter)->isModified()) { return true; } } return false; } /** * Clear the modified status of this file. */ void AnnotationFile::clearModified() { CaretDataFile::clearModified(); m_metadata->clearModified(); for (AnnotationGroupIterator groupIter = m_annotationGroups.begin(); groupIter != m_annotationGroups.end(); groupIter++) { (*groupIter)->clearModified(); } } /** * Reuse the given unique key (if it is not used in a group or annotation * and is less than the current value of the unique key generator. Otherwise, * generate a new unique key. * * @param reuseUniqueKey * Key that is requested and tested to see if it can be used. * @return * The input key if it can be reused, otherwise, a new key. */ int32_t AnnotationFile::reuseUniqueKeyOrGenerateNewUniqueKey(const int32_t reuseUniqueKey) { bool canBeReusedFlag = true; /* * Search the groups and the annotations within the groups to * see if the desired unique key is already used. */ for (AnnotationGroupIterator groupIter = m_annotationGroups.begin(); groupIter != m_annotationGroups.end(); groupIter++) { AnnotationGroup* group = (*groupIter).data(); if (group->getUniqueKey() == reuseUniqueKey) { canBeReusedFlag = false; break; } else { std::vector groupAnnotations; group->getAllAnnotations(groupAnnotations); for (std::vector::iterator annIter = groupAnnotations.begin(); annIter != groupAnnotations.end(); annIter++) { if ((*annIter)->getUniqueKey() == reuseUniqueKey) { canBeReusedFlag = false; break; } } } } /* * Check annotations that were deleted since they can be undeleted */ if (canBeReusedFlag) { for (std::set >::iterator removedAnnIter = m_removedAnnotations.begin(); removedAnnIter != m_removedAnnotations.end(); removedAnnIter++) { if ((*removedAnnIter)->getUniqueKey() == reuseUniqueKey) { canBeReusedFlag = false; } } } int32_t outputUniqueKey = -1; if (canBeReusedFlag) { outputUniqueKey = reuseUniqueKey; } else { outputUniqueKey = generateUniqueKey(); } return outputUniqueKey; } /** * @return A new unique key (each annotation and * annotation group in the file contains a unique key. */ int32_t AnnotationFile::generateUniqueKey() { if (m_uniqueKeyGenerator < 0) { m_uniqueKeyGenerator = 0; } m_uniqueKeyGenerator++; return m_uniqueKeyGenerator; } /** * Update the unqiue keys after reading the file * Older files did not have unique keys */ void AnnotationFile::updateUniqueKeysAfterReadingFile() { /* * Find maximum unique identifier from annotations AND annotation groups */ int32_t maximumKeyFound = 0; for (AnnotationGroupIterator groupIter = m_annotationGroups.begin(); groupIter != m_annotationGroups.end(); groupIter++) { maximumKeyFound = std::max(maximumKeyFound, (*groupIter)->getMaximumUniqueKey()); } m_uniqueKeyGenerator = maximumKeyFound; } /** * Read the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully read. */ void AnnotationFile::readFile(const AString& filename) { clear(); checkFileReadability(filename); AnnotationFileXmlReader reader; reader.readFile(filename, this); updateUniqueKeysAfterReadingFile(); setFileName(filename); clearModified(); } /** * Write the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully written. */ void AnnotationFile::writeFile(const AString& filename) { /* * JWH, 11 Sep 2019 * WB-866 removed the ".annot" extension for the annotation file. * It is possible that a user may have a disk annotation file in * multiple scenes. If this message caused the user to change * the file extension from ".annot" to ".wb_annot", it could break * other scenes if they are not updated. * So, continue avoiding a log message if ".annot" extension is present. */ if (!(filename.endsWith(".annot") || filename.endsWith(".wb_annot"))) { CaretLogWarning("annotation file '" + filename + "' should be saved ending in .annot"); } checkFileWritability(filename); setFileName(filename); AnnotationFileXmlWriter writer; writer.writeFile(this); clearModified(); } /** * Save subclass data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void AnnotationFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); switch (m_fileSubType) { case ANNOTATION_FILE_SAVE_TO_FILE: break; case ANNOTATION_FILE_SAVE_TO_SCENE: if ( ! isEmpty()) { try { AnnotationFileXmlWriter writer; QString fileContentInString; writer.writeFileToString(this, fileContentInString); sceneClass->addString("AnnotationFileContent", fileContentInString); } catch (const DataFileException& dfe) { sceneAttributes->addToErrorMessage(dfe.whatString()); } } break; } /* * Save groups to scene */ for (AnnotationGroupIterator groupIter = m_annotationGroups.begin(); groupIter != m_annotationGroups.end(); groupIter++) { AnnotationGroup* group = (*groupIter).data(); const int32_t uniqueKey = group->getUniqueKey(); SceneClass* groupClass = group->saveToScene(sceneAttributes, AnnotationGroup::getSceneClassNameForAnnotationUniqueKey(uniqueKey)); sceneClass->addClass(groupClass); } } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void AnnotationFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); switch (m_fileSubType) { case ANNOTATION_FILE_SAVE_TO_FILE: break; case ANNOTATION_FILE_SAVE_TO_SCENE: QString fileContentInString = sceneClass->getStringValue("AnnotationFileContent"); if ( ! fileContentInString.isEmpty()) { try { AnnotationFileXmlReader reader; reader.readFileFromString(fileContentInString, this); updateUniqueKeysAfterReadingFile(); clearModified(); } catch (const DataFileException& dfe) { sceneAttributes->addToErrorMessage(dfe.whatString()); } } break; } /* * Restore groups from scene */ for (AnnotationGroupIterator groupIter = m_annotationGroups.begin(); groupIter != m_annotationGroups.end(); groupIter++) { AnnotationGroup* group = (*groupIter).data(); const int32_t uniqueKey = group->getUniqueKey(); const SceneClass* annClass = sceneClass->getClass(AnnotationGroup::getSceneClassNameForAnnotationUniqueKey(uniqueKey)); if (sceneClass != NULL) { group->restoreFromScene(sceneAttributes, annClass); } } } /** * @return Pointer to DataFile that implements this interface */ DataFile* AnnotationFile::getAsDataFile() { DataFile* dataFile = dynamic_cast(this); CaretAssert(this); return dataFile; } /** * Append content from the given data file copy/move interface to this instance * * @param copyMoveParameters * Parameters used for copy/move. * @throws DataFileException * If there is an error. */ void AnnotationFile::appendContentFromDataFile(const DataFileContentCopyMoveParameters& copyMoveParameters) { const AnnotationFile* copyFromFile = dynamic_cast(copyMoveParameters.getDataFileCopyMoveInterfaceToCopy()); if (copyFromFile == NULL) { throw DataFileException("Trying to copy content to annotation file from a file that is not an " "annotation file."); } const bool selectedAnnotationsFlag = copyMoveParameters.isOptionSelectedItems(); const int32_t windowIndex = copyMoveParameters.getWindowIndex(); if (selectedAnnotationsFlag) { if (windowIndex < 0) { throw DataFileException("Requested copying of selected annotations but window index is invalid."); } } std::vector annotationGroups; copyFromFile->getAllAnnotationGroups(annotationGroups); for (std::vector::iterator groupIter = annotationGroups.begin(); groupIter != annotationGroups.end(); groupIter++) { const AnnotationGroup* groupToCopy = *groupIter; CaretAssert(groupToCopy); /* * Find that annotations that are to be copied. */ const int32_t numAnnInGroup = groupToCopy->getNumberOfAnnotations(); std::vector annotationsToCopy; for (int32_t ia = 0; ia < numAnnInGroup; ia++) { const Annotation* annToCopy = groupToCopy->getAnnotation(ia); CaretAssert(annToCopy); bool copyFlag = true; if (selectedAnnotationsFlag) { if (annToCopy->isSelectedForEditing(windowIndex)) { /* Nothing */ } else { copyFlag = false; } } if (copyFlag) { annotationsToCopy.push_back(annToCopy); } } /* * If there are are annotations to copy, * clone them and add to the proper group. */ if ( ! annotationsToCopy.empty()) { AnnotationGroup* group = NULL; switch (groupToCopy->getGroupType()) { case AnnotationGroupTypeEnum::INVALID: break; case AnnotationGroupTypeEnum::SPACE: /* * All annotations in a group are in identical spaces * so use the first annotation to find the space group. */ group = getSpaceAnnotationGroup(groupToCopy->getAnnotation(0)); break; case AnnotationGroupTypeEnum::USER: /* * Create a new user group */ group = new AnnotationGroup(this, AnnotationGroupTypeEnum::USER, generateUniqueKey(), groupToCopy->getCoordinateSpace(), groupToCopy->getTabOrWindowIndex(), groupToCopy->getSpacerTabIndex()); group->setItemParent(this); m_annotationGroups.push_back(QSharedPointer(group)); break; } CaretAssert(group); /* * Copy annotations and add them to the group. */ for (std::vector::const_iterator iter = annotationsToCopy.begin(); iter != annotationsToCopy.end(); iter++) { const Annotation* annToCopy = *iter; Annotation* clonedAnn = annToCopy->clone(); clonedAnn->setUniqueKey(generateUniqueKey()); group->addAnnotationPrivate(clonedAnn); } } } } /** * @return A new instance of the same file type. File is empty. */ DataFileContentCopyMoveInterface* AnnotationFile::newInstanceOfDataFile() const { return new AnnotationFile(); } /** * @return Number of children. */ int32_t AnnotationFile::getNumberOfItemChildren() const { return m_annotationGroups.size(); } /** * Get child at the given index. * * @param index * Index of the child. * @return * Child at the given index. */ DisplayGroupAndTabItemInterface* AnnotationFile::getItemChild(const int32_t index) const { CaretAssertVectorIndex(m_annotationGroups, index); return m_annotationGroups[index].data(); } /** * @return Children of this item. */ std::vector AnnotationFile::getItemChildren() const { std::vector children; for (AnnotationGroupConstIterator groupIter = m_annotationGroups.begin(); groupIter != m_annotationGroups.end(); groupIter++) { children.push_back((*groupIter).data()); } return children; } /** * @return Parent of this item. */ DisplayGroupAndTabItemInterface* AnnotationFile::getItemParent() const { return m_displayGroupAndTabItemHelper->getParent(); } /** * Set the parent of this item. * * @param itemParent * Parent of this item. */ void AnnotationFile::setItemParent(DisplayGroupAndTabItemInterface* itemParent) { m_displayGroupAndTabItemHelper->setParent(itemParent); } /** * @return Name of this item. */ AString AnnotationFile::getItemName() const { return getFileNameNoPath(); } /** * Get the icon color for this item. Icon is filled with background * color, outline color is drawn around edges, and text color is small * square in center. For any colors that do not apply, use an alpha * value (last element) of zero. * * @param backgroundRgbaOut * Red, green, blue, alpha components for background ranging [0, 1]. * @param outlineRgbaOut * Red, green, blue, alpha components for outline ranging [0, 1]. * @param textRgbaOut * Red, green, blue, alpha components for text ranging [0, 1]. */ void AnnotationFile::getItemIconColorsRGBA(float backgroundRgbaOut[4], float outlineRgbaOut[4], float textRgbaOut[4]) const { backgroundRgbaOut[0] = 0.0; backgroundRgbaOut[1] = 0.0; backgroundRgbaOut[2] = 0.0; backgroundRgbaOut[3] = 0.0; outlineRgbaOut[0] = 0.0; outlineRgbaOut[1] = 0.0; outlineRgbaOut[2] = 0.0; outlineRgbaOut[3] = 0.0; textRgbaOut[0] = 0.0; textRgbaOut[1] = 0.0; textRgbaOut[2] = 0.0; textRgbaOut[3] = 0.0; } /** * @return This item can be expanded. */ bool AnnotationFile::isItemExpandable() const { return true; } /** * @return Is this item expanded in the given display group/tab? * * @param displayGroup * The display group. * @param tabIndex * Index of the tab. */ bool AnnotationFile::isItemExpanded(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { return m_displayGroupAndTabItemHelper->isExpanded(displayGroup, tabIndex); } /** * Set this item's expanded status in the given display group/tab. * * @param displayGroup * The display group. * @param tabIndex * Index of the tab. * @param status * New expanded status. */ void AnnotationFile::setItemExpanded(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool status) { m_displayGroupAndTabItemHelper->setExpanded(displayGroup, tabIndex, status); } /** * Get display selection status in the given display group/tab? * * @param displayGroup * The display group. * @param tabIndex * Index of the tab. */ TriStateSelectionStatusEnum::Enum AnnotationFile::getItemDisplaySelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { TriStateSelectionStatusEnum::Enum status = TriStateSelectionStatusEnum::UNSELECTED; const int numChildren = static_cast(m_annotationGroups.size()); if (numChildren > 0) { int32_t selectedCount = 0; int32_t partialSelectedCount = 0; for (int32_t i = 0; i < numChildren; i++) { CaretAssertVectorIndex(m_annotationGroups, i); switch (m_annotationGroups[i]->getItemDisplaySelected(displayGroup, tabIndex)) { case TriStateSelectionStatusEnum::PARTIALLY_SELECTED: partialSelectedCount++; break; case TriStateSelectionStatusEnum::SELECTED: selectedCount++; break; case TriStateSelectionStatusEnum::UNSELECTED: break; } } if (selectedCount == numChildren) { status = TriStateSelectionStatusEnum::SELECTED; } else if ((selectedCount > 0) || (partialSelectedCount > 0)) { status = TriStateSelectionStatusEnum::PARTIALLY_SELECTED; } } return status; } /** * Set display this item selected in the given display group/tab. * * @param displayGroup * The display group. * @param tabIndex * Index of the tab. * @param status * New selection status. */ void AnnotationFile::setItemDisplaySelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const TriStateSelectionStatusEnum::Enum status) { // m_displayGroupAndTabItemHelper->setSelected(displayGroup, // tabIndex, // status); /* * Note: An annotation file's selection status is based * of the the file's annotation groups so we do not need to set * an explicit selection status for the file. */ DisplayGroupAndTabItemInterface::setChildrenDisplaySelectedHelper(this, displayGroup, tabIndex, status); DisplayGroupAndTabItemInterface::setChildrenDisplaySelectedHelper(this, displayGroup, tabIndex, status); } /** * Is this item selected for editing in the given window? * * @param windowIndex * Index of the window. * @return * Selection status. */ bool AnnotationFile::isItemSelectedForEditingInWindow(const int32_t /*windowIndex*/) { /* * The annotation file is never selected for editing. */ return false; } /** * Update spacer annotations after tile tabs configuration is modified. * * @param modEvent * The tile tabs modify event. */ void AnnotationFile::updateSpacerAnnotationsAfterTileTabsModification(const EventTileTabsConfigurationModification* modEvent) { const int32_t rowColumnIndex = modEvent->getRowColumnIndex(); const bool rowFlag = (modEvent->getRowColumnType() == EventTileTabsConfigurationModification::RowColumnType::ROW); int32_t deleteIndex(-1); int32_t shiftStartIndex(-1); int32_t duplicateFromIndex(-1); int32_t duplicateToIndex(-1); int32_t moveOneIndex(-1); int32_t moveTwoIndex(-1); switch (modEvent->getOperation()) { case EventTileTabsConfigurationModification::Operation::DELETE_IT: deleteIndex = rowColumnIndex; shiftStartIndex = rowColumnIndex + 1; break; case EventTileTabsConfigurationModification::Operation::DUPLICATE_AFTER: { shiftStartIndex = rowColumnIndex + 1; duplicateFromIndex = rowColumnIndex; duplicateToIndex = rowColumnIndex + 1; } break; case EventTileTabsConfigurationModification::Operation::DUPLICATE_BEFORE: { shiftStartIndex = rowColumnIndex; duplicateFromIndex = rowColumnIndex + 1; duplicateToIndex = rowColumnIndex; } break; case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_BEFORE: shiftStartIndex = rowColumnIndex; break; case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_AFTER: shiftStartIndex = rowColumnIndex + 1; break; case EventTileTabsConfigurationModification::Operation::MOVE_AFTER: moveOneIndex = rowColumnIndex; moveTwoIndex = rowColumnIndex + 1; break; case EventTileTabsConfigurationModification::Operation::MOVE_BEFORE: moveOneIndex = rowColumnIndex; moveTwoIndex = rowColumnIndex - 1; break; } std::vector deleteAnnotations; std::vector duplicatedAnnotations; std::vector, Annotation*>> modifiedAnnotations; std::set processedAnnotations; const int32_t windowIndex = modEvent->getWindowIndex(); for (auto group : m_annotationGroups) { std::vector> removeAnnotationsFromGroup; if (group->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::SPACER) { const int32_t numAnn = group->getNumberOfAnnotations(); for (int32_t iAnn = 0; iAnn < numAnn; iAnn++) { Annotation* ann = group->getAnnotation(iAnn); CaretAssert(ann); SpacerTabIndex spacerTabIndex = ann->getSpacerTabIndex(); if (spacerTabIndex.getWindowIndex() == windowIndex) { int32_t rowIndex = spacerTabIndex.getRowIndex(); int32_t columnIndex = spacerTabIndex.getColumnIndex(); switch (modEvent->getOperation()) { case EventTileTabsConfigurationModification::Operation::DELETE_IT: { int32_t rcIndex = (rowFlag ? rowIndex : columnIndex); if (rcIndex == deleteIndex) { deleteAnnotations.push_back(ann); } /* * Shift annotations */ if (rcIndex >= shiftStartIndex) { rcIndex = rcIndex - 1; if (rowFlag) { rowIndex = rcIndex; } else { columnIndex = rcIndex; } } } break; case EventTileTabsConfigurationModification::Operation::DUPLICATE_AFTER: case EventTileTabsConfigurationModification::Operation::DUPLICATE_BEFORE: { int32_t rcIndex = (rowFlag ? rowIndex : columnIndex); /* * Shift annotations */ if (rcIndex >= shiftStartIndex) { rcIndex = rcIndex + 1; } /* * Then duplicate and yes, ok to use rowIndex even though it has changed */ if (rcIndex == duplicateFromIndex) { Annotation* dupAnn = ann->clone(); SpacerTabIndex dupAnnSTI = dupAnn->getSpacerTabIndex(); if (rowFlag) { dupAnnSTI.setRowIndex(duplicateToIndex); } else { dupAnnSTI.setColumnIndex(duplicateToIndex); } dupAnn->setSpacerTabIndex(dupAnnSTI); CaretLogFine("Copying from " + AString::number(rcIndex) + " to " + AString::number(duplicateToIndex) + " " + ann->toString()); duplicatedAnnotations.push_back(dupAnn); } if (rowFlag) { rowIndex = rcIndex; } else { columnIndex = rcIndex; } } break; case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_BEFORE: case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_AFTER: { int32_t rcIndex = (rowFlag ? rowIndex : columnIndex); if (rcIndex >= shiftStartIndex) { rcIndex = rcIndex + 1; } if (rowFlag) { rowIndex = rcIndex; } else { columnIndex = rcIndex; } } break; case EventTileTabsConfigurationModification::Operation::MOVE_AFTER: case EventTileTabsConfigurationModification::Operation::MOVE_BEFORE: { int32_t rcIndex = (rowFlag ? rowIndex : columnIndex); int32_t newIndex(-1); if (rcIndex == moveOneIndex) { newIndex = moveTwoIndex; } else if (rcIndex == moveTwoIndex) { newIndex = moveOneIndex; } if (newIndex >= 0) { if (rowFlag) { rowIndex = newIndex; } else { columnIndex = newIndex; } } } break; } if ((rowIndex != spacerTabIndex.getRowIndex()) || (columnIndex != spacerTabIndex.getColumnIndex())) { spacerTabIndex.setRowIndex(rowIndex); spacerTabIndex.setColumnIndex(columnIndex); ann->setSpacerTabIndex(spacerTabIndex); CaretLogFine("Moved from " + ann->getSpacerTabIndex().toString() + " to " + spacerTabIndex.toString() + " " + ann->toString()); modifiedAnnotations.push_back(std::make_pair(group, ann)); } } } } } /* * Move modified annotations into correct annotation group. */ for (auto groupAndAnn : modifiedAnnotations) { QSharedPointer group = groupAndAnn.first; Annotation* ann = groupAndAnn.second; QSharedPointer annSharedPointer; if (group->removeAnnotation(ann, annSharedPointer)) { addAnnotationPrivateSharedPointer(annSharedPointer, ann->getUniqueKey()); } } /* * Add duplicated anntotations. */ for (auto ann : duplicatedAnnotations) { addAnnotationPrivate(ann, generateUniqueKey()); } /* * Delete annotations */ for (auto ann : deleteAnnotations) { const bool keepAnnotationForUndoRedoFlag(false); removeAnnotationPrivate(ann, keepAnnotationForUndoRedoFlag); } } connectome-workbench-1.4.2/src/Files/AnnotationFile.h000066400000000000000000000231571360521144700225570ustar00rootroot00000000000000#ifndef __ANNOTATION_FILE_H__ #define __ANNOTATION_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AnnotationCoordinateSpaceEnum.h" #include "AnnotationGroupTypeEnum.h" #include "CaretDataFile.h" #include "CaretPointer.h" #include "DataFileContentCopyMoveInterface.h" #include "DisplayGroupAndTabItemInterface.h" #include "EventAnnotationGrouping.h" #include "EventListenerInterface.h" #include "EventTileTabsConfigurationModification.h" namespace caret { class Annotation; class AnnotationGroup; class DisplayGroupAndTabItemHelper; class SceneClassAssistant; class SpacerTabIndex; class AnnotationFile : public CaretDataFile, public EventListenerInterface, public DataFileContentCopyMoveInterface, public DisplayGroupAndTabItemInterface { public: /** * Sub-type of the annotation file */ enum AnnotationFileSubType { /** * Normal annotation file which saves its annotation * to a file */ ANNOTATION_FILE_SAVE_TO_FILE, /** * Special variant of annotation file that restores and saves the * annotations with the scene methods. This is used by the * "Brain" for the scene annotation file that is only saved * to scenes and never saved to a file. */ ANNOTATION_FILE_SAVE_TO_SCENE }; AnnotationFile(); AnnotationFile(const AnnotationFileSubType fileSubType); virtual ~AnnotationFile(); AnnotationFile(const AnnotationFile& obj); AnnotationFile& operator=(const AnnotationFile& obj); virtual bool isEmpty() const override; virtual void clear(); virtual StructureEnum::Enum getStructure() const; virtual void setStructure(const StructureEnum::Enum structure); virtual GiftiMetaData* getFileMetaData(); virtual const GiftiMetaData* getFileMetaData() const; void getAllAnnotations(std::vector& annotationsOut) const; void getAllAnnotationGroups(std::vector& annotationGroupsOut) const; void clearAllAnnotationsDrawnInWindowStatus(); void getAllAnnotationWithDrawnInWindowStatusSet(const int32_t windowIndex, std::vector& annotationsOut); virtual void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation); void setAllAnnotationsSelectedForEditing(const int32_t windowIndex, const bool selectedStatus); virtual void receiveEvent(Event* event); virtual void readFile(const AString& filename); virtual void writeFile(const AString& filename); virtual bool isModified() const; virtual void clearModified(); virtual DataFile* getAsDataFile(); virtual void appendContentFromDataFile(const DataFileContentCopyMoveParameters& copyMoveParameters); virtual DataFileContentCopyMoveInterface* newInstanceOfDataFile() const; bool hasAnnotationsInCoordinateSpace(const AnnotationCoordinateSpaceEnum::Enum coordinateSpace) const; // ADD_NEW_METHODS_HERE virtual int32_t getNumberOfItemChildren() const; virtual DisplayGroupAndTabItemInterface* getItemChild(const int32_t index) const; virtual std::vector getItemChildren() const; virtual DisplayGroupAndTabItemInterface* getItemParent() const; virtual void setItemParent(DisplayGroupAndTabItemInterface* itemParent); virtual AString getItemName() const; virtual void getItemIconColorsRGBA(float backgroundRgbaOut[4], float outlineRgbaOut[4], float textRgbaOut[4]) const; virtual bool isItemExpandable() const; virtual bool isItemExpanded(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; virtual void setItemExpanded(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool status); virtual TriStateSelectionStatusEnum::Enum getItemDisplaySelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; virtual void setItemDisplaySelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const TriStateSelectionStatusEnum::Enum status); virtual bool isItemSelectedForEditingInWindow(const int32_t windowIndex); protected: virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: void copyHelperAnnotationFile(const AnnotationFile& obj); void clearPrivate(); void initializeAnnotationFile(); void addAnnotationPrivate(Annotation* annotation, const int32_t uniqueKey); void addAnnotationPrivateSharedPointer(QSharedPointer& annotation, const int32_t uniqueKey); void addAnnotationDuringFileVersionOneReading(Annotation* annotation); void addAnnotationGroupDuringFileReading(const AnnotationGroupTypeEnum::Enum groupType, const AnnotationCoordinateSpaceEnum::Enum coordinateSpace, const int32_t tabOrWindowIndex, const SpacerTabIndex& spacerTabIndex, const int32_t uniqueKey, const std::vector& annotations); void processGroupingAnnotations(EventAnnotationGrouping* groupingEvent); void processUngroupingAnnotations(EventAnnotationGrouping* groupingEvent); void processRegroupingAnnotations(EventAnnotationGrouping* groupingEvent); bool restoreAnnotation(Annotation* annotation); bool restoreAnnotationAddIfNotFound(Annotation* annotation); bool removeAnnotationWithUndoRedo(Annotation* annotation); bool removeAnnotationPrivate(Annotation* annotation, const bool keepAnnotationForUndoRedoFlag); bool cloneAnnotationsFromTabToTab(const int32_t fromTabIndex, const int32_t toTabIndex); bool removeAnnotationsInTab(const int32_t tabIndex); int32_t generateUniqueKey(); int32_t reuseUniqueKeyOrGenerateNewUniqueKey(const int32_t reuseUniqueKey); void updateUniqueKeysAfterReadingFile(); AnnotationGroup* getSpaceAnnotationGroup(const Annotation* annotation); void updateSpacerAnnotationsAfterTileTabsModification(const EventTileTabsConfigurationModification* modEvent); const AnnotationFileSubType m_fileSubType; SceneClassAssistant* m_sceneAssistant; CaretPointer m_metadata; DisplayGroupAndTabItemHelper* m_displayGroupAndTabItemHelper; int32_t m_uniqueKeyGenerator; std::vector > m_annotationGroups; /** * Contains annotation that have been delete/removed so that * they can be 'undeleted' or 're-pasted'. */ std::set > m_removedAnnotations; typedef std::vector >::iterator AnnotationGroupIterator; typedef std::vector >::const_iterator AnnotationGroupConstIterator; // ADD_NEW_MEMBERS_HERE friend class AnnotationFileXmlReader; }; #ifdef __ANNOTATION_FILE_DECLARE__ // #endif // __ANNOTATION_FILE_DECLARE__ } // namespace #endif //__ANNOTATION_FILE_H__ connectome-workbench-1.4.2/src/Files/AnnotationFileXmlFormatBase.cxx000066400000000000000000000032761360521144700255570ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_FILE_XML_FORMAT_BASE_DECLARE__ #include "AnnotationFileXmlFormatBase.h" #undef __ANNOTATION_FILE_XML_FORMAT_BASE_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationFileXmlFormatBase * \brief Base class for Annotation File XML reader/writer. * \ingroup Files * * This class is the base class for the Annotation File XML format * reader and writer. It contains XML tags used by the reader and * writer. */ /** * Constructor. */ AnnotationFileXmlFormatBase::AnnotationFileXmlFormatBase() : CaretObject() { } /** * Destructor. */ AnnotationFileXmlFormatBase::~AnnotationFileXmlFormatBase() { } /** * Get a description of this object's content. * @return String describing this object's content. */ AString AnnotationFileXmlFormatBase::toString() const { return "AnnotationFileXmlFormatBase"; } connectome-workbench-1.4.2/src/Files/AnnotationFileXmlFormatBase.h000066400000000000000000000255401360521144700252020ustar00rootroot00000000000000#ifndef __ANNOTATION_FILE_XML_FORMAT_BASE_H__ #define __ANNOTATION_FILE_XML_FORMAT_BASE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" namespace caret { class AnnotationFileXmlFormatBase : public CaretObject { protected: AnnotationFileXmlFormatBase(); public: virtual ~AnnotationFileXmlFormatBase(); // ADD_NEW_METHODS_HERE virtual AString toString() const; private: AnnotationFileXmlFormatBase(const AnnotationFileXmlFormatBase&); AnnotationFileXmlFormatBase& operator=(const AnnotationFileXmlFormatBase&); protected: static const QString ATTRIBUTE_BACKGROUND_CARET_COLOR; static const QString ATTRIBUTE_BACKGROUND_CUSTOM_RGBA; static const QString ATTRIBUTE_COORDINATE_SPACE; static const QString ATTRIBUTE_COORD_X; static const QString ATTRIBUTE_COORD_Y; static const QString ATTRIBUTE_COORD_Z; static const QString ATTRIBUTE_COORD_SURFACE_STRUCTURE; static const QString ATTRIBUTE_COORD_SURFACE_NUMBER_OF_NODES; static const QString ATTRIBUTE_COORD_SURFACE_NODE_INDEX; static const QString ATTRIBUTE_COORD_SURFACE_NODE_OFFSET; static const QString ATTRIBUTE_COORD_SURFACE_NODE_OFFSET_VECTOR_TYPE; static const QString ATTRIBUTE_FOREGROUND_CARET_COLOR; static const QString ATTRIBUTE_FOREGROUND_CUSTOM_RGBA; static const QString ATTRIBUTE_FOREGROUND_LINE_WIDTH_PIXELS; static const QString ATTRIBUTE_FOREGROUND_LINE_WIDTH_PERCENTAGE; static const QString ATTRIBUTE_GROUP_TYPE; static const QString ATTRIBUTE_HEIGHT; static const QString ATTRIBUTE_IMAGE_WIDTH; static const QString ATTRIBUTE_IMAGE_HEIGHT; static const QString ATTRIBUTE_LINE_END_ARROW; static const QString ATTRIBUTE_LINE_START_ARROW; static const QString ATTRIBUTE_ROTATION_ANGLE; static const QString ATTRIBUTE_SPACER_TAB_INDEX; static const QString ATTRIBUTE_TAB_INDEX; static const QString ATTRIBUTE_TAB_OR_WINDOW_INDEX; static const QString ATTRIBUTE_TEXT_CARET_COLOR; static const QString ATTRIBUTE_TEXT_CUSTOM_RGBA; static const QString ATTRIBUTE_TEXT_CONNECT_BRAINORDINATE; static const QString ATTRIBUTE_TEXT_FONT_BOLD; static const QString ATTRIBUTE_TEXT_FONT_ITALIC; static const QString ATTRIBUTE_TEXT_FONT_NAME; static const QString ATTRIBUTE_TEXT_FONT_POINT_SIZE; static const QString ATTRIBUTE_TEXT_FONT_PERCENT_VIEWPORT_SIZE; static const QString ATTRIBUTE_TEXT_FONT_UNDERLINE; static const QString ATTRIBUTE_TEXT_HORIZONTAL_ALIGNMENT; static const QString ATTRIBUTE_TEXT_ORIENTATION; static const QString ATTRIBUTE_TEXT_VERTICAL_ALIGNMENT; static const QString ATTRIBUTE_UNIQUE_KEY; static const QString ATTRIBUTE_VERSION; static const QString ATTRIBUTE_WIDTH; static const QString ATTRIBUTE_WINDOW_INDEX; static const QString ELEMENT_ANNOTATION_FILE; static const QString ELEMENT_ARROW; static const QString ELEMENT_BOX; static const QString ELEMENT_COORDINATE_ONE; static const QString ELEMENT_COORDINATE_TWO; static const QString ELEMENT_GROUP; static const QString ELEMENT_IMAGE; static const QString ELEMENT_IMAGE_RGBA_BYTES_IN_BASE64; static const QString ELEMENT_LINE; static const QString ELEMENT_OVAL; static const QString ELEMENT_PERCENT_SIZE_TEXT; static const QString ELEMENT_PERCENT_WIDTH_SIZE_TEXT; static const QString ELEMENT_POINT_SIZE_TEXT; static const QString ELEMENT_TEXT_OBSOLETE; static const QString ELEMENT_TEXT_DATA; static const int32_t XML_VERSION_ONE; static const int32_t XML_VERSION_TWO; static const int32_t XML_VERSION_THREE; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_FILE_XML_FORMAT_BASE_DECLARE__ const QString AnnotationFileXmlFormatBase::ATTRIBUTE_BACKGROUND_CARET_COLOR = "backgroundCaretColor"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_BACKGROUND_CUSTOM_RGBA = "backgroundCustomRGBA"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_COORDINATE_SPACE = "coordinateSpace"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_COORD_X = "x"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_COORD_Y = "y"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_COORD_Z = "z"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_COORD_SURFACE_STRUCTURE = "structure"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_COORD_SURFACE_NUMBER_OF_NODES = "numberOfNodes"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_COORD_SURFACE_NODE_INDEX = "nodeIndex"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_COORD_SURFACE_NODE_OFFSET = "nodeOffset"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_COORD_SURFACE_NODE_OFFSET_VECTOR_TYPE = "nodeOffsetVectorType"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_FOREGROUND_CARET_COLOR = "foregroundCaretColor"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_FOREGROUND_CUSTOM_RGBA = "foregroundCustomRGBA"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_FOREGROUND_LINE_WIDTH_PIXELS = "foregroundLineWidth"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_FOREGROUND_LINE_WIDTH_PERCENTAGE = "foregroundLineWidthPercentage"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_GROUP_TYPE = "groupType"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_HEIGHT = "height"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_IMAGE_WIDTH = "imageWidth"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_IMAGE_HEIGHT = "imageHeight"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_LINE_END_ARROW = "endArrow"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_LINE_START_ARROW = "startArrow"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_ROTATION_ANGLE = "rotationAngle"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_SPACER_TAB_INDEX = "spacerTabIndex"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_TAB_INDEX = "tabIndex"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_TAB_OR_WINDOW_INDEX = "tabOrWindowIndex"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_TEXT_CARET_COLOR = "textCaretColor"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_TEXT_CUSTOM_RGBA = "textCustomRGBA"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_TEXT_CONNECT_BRAINORDINATE = "connectBrainordinate"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_TEXT_FONT_BOLD = "fontBold"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_TEXT_FONT_ITALIC = "fontItalic"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_TEXT_FONT_NAME = "fontName"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_TEXT_FONT_POINT_SIZE = "fontPointSize"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_TEXT_FONT_PERCENT_VIEWPORT_SIZE = "fontPercentViewportSize"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_TEXT_FONT_UNDERLINE = "fontUnderline"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_TEXT_HORIZONTAL_ALIGNMENT = "horizontalAlignment"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_TEXT_ORIENTATION = "orientation"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_TEXT_VERTICAL_ALIGNMENT = "verticalAlignment"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_UNIQUE_KEY = "uniqueKey"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_VERSION = "version"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_WIDTH = "width"; const QString AnnotationFileXmlFormatBase::ATTRIBUTE_WINDOW_INDEX = "windowIndex"; const QString AnnotationFileXmlFormatBase::ELEMENT_ANNOTATION_FILE = "AnnotationFile"; const QString AnnotationFileXmlFormatBase::ELEMENT_ARROW = "arrow"; const QString AnnotationFileXmlFormatBase::ELEMENT_BOX = "box"; const QString AnnotationFileXmlFormatBase::ELEMENT_COORDINATE_ONE = "coordOne"; const QString AnnotationFileXmlFormatBase::ELEMENT_COORDINATE_TWO = "coordTwo"; const QString AnnotationFileXmlFormatBase::ELEMENT_GROUP = "group"; const QString AnnotationFileXmlFormatBase::ELEMENT_IMAGE = "image"; const QString AnnotationFileXmlFormatBase::ELEMENT_IMAGE_RGBA_BYTES_IN_BASE64 = "imageRgbaBytesInBase64"; const QString AnnotationFileXmlFormatBase::ELEMENT_LINE = "line"; const QString AnnotationFileXmlFormatBase::ELEMENT_OVAL = "oval"; const QString AnnotationFileXmlFormatBase::ELEMENT_PERCENT_SIZE_TEXT = "percentSizeText"; const QString AnnotationFileXmlFormatBase::ELEMENT_PERCENT_WIDTH_SIZE_TEXT = "percentWidthSizeText"; const QString AnnotationFileXmlFormatBase::ELEMENT_POINT_SIZE_TEXT = "pointSizeText"; const QString AnnotationFileXmlFormatBase::ELEMENT_TEXT_OBSOLETE = "text"; const QString AnnotationFileXmlFormatBase::ELEMENT_TEXT_DATA = "textData"; const int32_t AnnotationFileXmlFormatBase::XML_VERSION_ONE = 1; const int32_t AnnotationFileXmlFormatBase::XML_VERSION_TWO = 2; const int32_t AnnotationFileXmlFormatBase::XML_VERSION_THREE = 3; #endif // __ANNOTATION_FILE_XML_FORMAT_BASE_DECLARE__ } // namespace #endif //__ANNOTATION_FILE_XML_FORMAT_BASE_H__ connectome-workbench-1.4.2/src/Files/AnnotationFileXmlReader.cxx000066400000000000000000001473321360521144700247400ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #define __ANNOTATION_FILE_XML_READER_DECLARE__ #include "AnnotationFileXmlReader.h" #undef __ANNOTATION_FILE_XML_READER_DECLARE__ #include "AnnotationBox.h" #include "AnnotationCoordinate.h" #include "AnnotationFile.h" #include "AnnotationGroup.h" #include "AnnotationImage.h" #include "AnnotationLine.h" #include "AnnotationOval.h" #include "AnnotationPercentSizeText.h" #include "AnnotationPointSizeText.h" #include "CaretAssert.h" #include "DataFileException.h" #include "GiftiXmlElements.h" #include "XmlStreamReaderHelper.h" using namespace caret; /** * \class caret::AnnotationFileXmlReader * \brief Read Annotation File from XML format. * \ingroup Files */ /** * Constructor. */ AnnotationFileXmlReader::AnnotationFileXmlReader() : AnnotationFileXmlFormatBase() { m_stream.grabNew(new QXmlStreamReader()); m_streamHelper.grabNew(NULL); } /** * Destructor. */ AnnotationFileXmlReader::~AnnotationFileXmlReader() { } /** * Read the given annotation file in XML format. * * @param filename * Name of file. * @param annotationFile * Read into this annotation file. * @throws * DataFileException if there is an error reading the file. */ void AnnotationFileXmlReader::readFile(const QString& filename, AnnotationFile* annotationFile) { m_fileVersionNumber = -1; CaretAssert(annotationFile); m_filename = filename; /* * Open the file */ QFile file(m_filename); if ( ! file.open(QFile::ReadOnly)) { const QString msg("Error opening for reading." + file.errorString()); throw DataFileException(m_filename, msg); } /* * Create an XML stream writer */ m_stream.grabNew(new QXmlStreamReader(&file)); readFileContentFromXmlStreamReader(filename, annotationFile); file.close(); if (m_stream->hasError()) { m_streamHelper->throwDataFileException("There was an error reading the annotation file in XML format (reported by QXmlStreamReader): " + m_stream->errorString()); } } /** * Read the given annotation file contained in a string in XML format. * * @param fileInString * String containing the file. * @param annotationFile * Read into this annotation file. * @throws * DataFileException if there is an error reading the file. */ void AnnotationFileXmlReader::readFileFromString(const QString& fileInString, AnnotationFile* annotationFile) { /* * Create an XML stream writer */ m_stream.grabNew(new QXmlStreamReader(fileInString)); readFileContentFromXmlStreamReader("AnnotationsInSceneFile", annotationFile); if (m_stream->hasError()) { m_streamHelper->throwDataFileException("There was an error reading the annotation file in XML format (reported by QXmlStreamReader): " + m_stream->errorString()); } } /** * Read content of the file from the XML stream reader. * * @param filename * Name of the file. * @param annotationFile * Read into this annotation file. * @throws * DataFileException if there is an error reading the file. */ void AnnotationFileXmlReader::readFileContentFromXmlStreamReader(const QString& filename, AnnotationFile* annotationFile) { /* * Create the helper for reading XML */ if (m_streamHelper != NULL) { m_streamHelper.grabNew(NULL); } m_streamHelper.grabNew(new XmlStreamReaderHelper(filename, m_stream)); if (m_stream->atEnd()) { m_streamHelper->throwDataFileException("Error reading. File appears to have no XML content."); } const bool fileElementValid = m_stream->readNextStartElement(); if ( ! fileElementValid) { m_streamHelper->throwDataFileException("Appears to have no XML elements."); } const QStringRef fileElementName = m_stream->name(); if (fileElementName != ELEMENT_ANNOTATION_FILE) { m_streamHelper->throwDataFileException("First element is " + fileElementName.toString() + " but should be " + ELEMENT_ANNOTATION_FILE); } QXmlStreamAttributes fileAttributes = m_stream->attributes(); const QStringRef versionText = fileAttributes.value(ATTRIBUTE_VERSION); if (versionText.isEmpty()) { m_streamHelper->throwDataFileException("Version attribute (" + ATTRIBUTE_VERSION + ") is missing from the file element " + ELEMENT_ANNOTATION_FILE); } m_fileVersionNumber = versionText.toString().toInt(); if (m_fileVersionNumber == XML_VERSION_ONE) { readVersionOne(annotationFile); } else if (m_fileVersionNumber == XML_VERSION_TWO) { readVersionTwo(annotationFile); } else if (m_fileVersionNumber == XML_VERSION_THREE) { /* * NOTE: version 3 added new coordinate space "SPACER " * and otherwise is the same as version 2 format */ readVersionTwo(annotationFile); } else { m_streamHelper->throwDataFileException("File version number " + versionText.toString() + " is not supported by this version of the software."); } } /** * Read a version one Annotation XML file. * * @param annotationFile * Add annotations to this file. */ void AnnotationFileXmlReader::readVersionOne(AnnotationFile* annotationFile) { while (m_stream->readNextStartElement()) { bool skipCurrentElementFlag = true; const QString elementName = m_stream->name().toString(); if (elementName == GiftiXmlElements::TAG_METADATA) { m_streamHelper->readMetaData(annotationFile->getFileMetaData()); skipCurrentElementFlag = false; } else if (elementName == ELEMENT_BOX) { CaretPointer annotation(new AnnotationBox(AnnotationAttributesDefaultTypeEnum::NORMAL)); readTwoDimensionalAnnotation(ELEMENT_BOX, annotation); annotationFile->addAnnotationDuringFileVersionOneReading(annotation.releasePointer()); } else if (elementName == ELEMENT_IMAGE) { CaretPointer annotation(new AnnotationImage(AnnotationAttributesDefaultTypeEnum::NORMAL)); readTwoDimensionalAnnotation(ELEMENT_IMAGE, annotation); annotationFile->addAnnotationDuringFileVersionOneReading(annotation.releasePointer()); } else if (elementName == ELEMENT_LINE) { CaretPointer annotation(new AnnotationLine(AnnotationAttributesDefaultTypeEnum::NORMAL)); readOneDimensionalAnnotation(ELEMENT_LINE, annotation); annotationFile->addAnnotationDuringFileVersionOneReading(annotation.releasePointer()); } else if (elementName == ELEMENT_OVAL) { CaretPointer annotation(new AnnotationOval(AnnotationAttributesDefaultTypeEnum::NORMAL)); readTwoDimensionalAnnotation(ELEMENT_OVAL, annotation); annotationFile->addAnnotationDuringFileVersionOneReading(annotation.releasePointer()); } else if (elementName == ELEMENT_PERCENT_SIZE_TEXT) { CaretPointer annotation(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL)); readTwoDimensionalAnnotation(ELEMENT_PERCENT_SIZE_TEXT, annotation); annotationFile->addAnnotationDuringFileVersionOneReading(annotation.releasePointer()); } else if (elementName == ELEMENT_PERCENT_WIDTH_SIZE_TEXT) { CaretPointer annotation(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL, AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH)); readTwoDimensionalAnnotation(ELEMENT_PERCENT_WIDTH_SIZE_TEXT, annotation); annotationFile->addAnnotationDuringFileVersionOneReading(annotation.releasePointer()); } else if (elementName == ELEMENT_POINT_SIZE_TEXT) { CaretPointer annotation(new AnnotationPointSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL)); readTwoDimensionalAnnotation(ELEMENT_POINT_SIZE_TEXT, annotation); annotationFile->addAnnotationDuringFileVersionOneReading(annotation.releasePointer()); } else if (elementName == ELEMENT_TEXT_OBSOLETE) { CaretPointer annotation(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL)); readTwoDimensionalAnnotation(ELEMENT_TEXT_OBSOLETE, annotation); annotationFile->addAnnotationDuringFileVersionOneReading(annotation.releasePointer()); } else { m_streamHelper->throwDataFileException("Unexpected XML element " + elementName); } /* * These elements have no other child elements so move on */ if (skipCurrentElementFlag) { m_stream->skipCurrentElement(); } } } /** * Read a version two Annotation XML file. * * @param annotationFile * Add annotations to this file. */ void AnnotationFileXmlReader::readVersionTwo(AnnotationFile* annotationFile) { while (m_stream->readNextStartElement()) { bool skipCurrentElementFlag = true; const QString elementName = m_stream->name().toString(); if (elementName == GiftiXmlElements::TAG_METADATA) { m_streamHelper->readMetaData(annotationFile->getFileMetaData()); skipCurrentElementFlag = false; } else if (elementName == ELEMENT_GROUP) { readGroup(annotationFile); skipCurrentElementFlag = false; } else { m_streamHelper->throwDataFileException("Unexpected XML element " + elementName); } /* * These elements have no other child elements so move on */ if (skipCurrentElementFlag) { m_stream->skipCurrentElement(); } } } /** * Read the next start element which should be a coordinate * with the given element name. * * @param annotation * One-dimensional annotation that has its data read. * @throw * DataFileException */ void AnnotationFileXmlReader::readCoordinate(const QString& coordinateElementName, AnnotationCoordinate* coordinate) { CaretAssert(coordinate); const bool elementValid = m_stream->readNextStartElement(); if ( ! elementValid) { m_streamHelper->throwDataFileException("Failed to read element " + coordinateElementName); } if (m_stream->name() != coordinateElementName) { m_streamHelper->throwDataFileException("Expected elment " + coordinateElementName + " but read element " + m_stream->name().toString()); } const QXmlStreamAttributes attributes = m_stream->attributes(); /* * XYZ coordinate */ const float xyz[3] = { m_streamHelper->getRequiredAttributeFloatValue(attributes, coordinateElementName, ATTRIBUTE_COORD_X), m_streamHelper->getRequiredAttributeFloatValue(attributes, coordinateElementName, ATTRIBUTE_COORD_Y), m_streamHelper->getRequiredAttributeFloatValue(attributes, coordinateElementName, ATTRIBUTE_COORD_Z) }; coordinate->setXYZ(xyz); /* * Surface coordinate */ const int32_t numberOfNodes = m_streamHelper->getRequiredAttributeIntValue(attributes, coordinateElementName, ATTRIBUTE_COORD_SURFACE_NUMBER_OF_NODES); const int32_t nodeIndex = m_streamHelper->getRequiredAttributeIntValue(attributes, coordinateElementName, ATTRIBUTE_COORD_SURFACE_NODE_INDEX); const QString structureValueString = m_streamHelper->getRequiredAttributeStringValue(attributes, coordinateElementName, ATTRIBUTE_COORD_SURFACE_STRUCTURE); const float offsetDistance = m_streamHelper->getRequiredAttributeFloatValue(attributes, coordinateElementName, ATTRIBUTE_COORD_SURFACE_NODE_OFFSET); const QString offsetVectorString = m_streamHelper->getOptionalAttributeStringValue(attributes, coordinateElementName, ATTRIBUTE_COORD_SURFACE_NODE_OFFSET_VECTOR_TYPE, "CENTROID_THRU_VERTEX"); bool structureValid = false; StructureEnum::Enum structure = StructureEnum::fromName(structureValueString, &structureValid); bool offsetVectorValid = false; AnnotationSurfaceOffsetVectorTypeEnum::Enum offsetVector = AnnotationSurfaceOffsetVectorTypeEnum::fromName(offsetVectorString, &offsetVectorValid); if ( ! offsetVectorValid) { offsetVector = AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX; } if (structureValid) { coordinate->setSurfaceSpace(structure, numberOfNodes, nodeIndex, offsetDistance, offsetVector); } else { m_streamHelper->throwDataFileException("Invalid value " + structureValueString + " for attribute " + ATTRIBUTE_COORD_SURFACE_STRUCTURE); } /* * No other child elements so move on */ m_stream->skipCurrentElement(); } /** * Read the attributes common to all annotation elements. * * @param annotation * The annotation. * @param annotationElementName * Name of element of annotation. * @param attributes * The XML attributes. * @throw * DataFileException if there is an error reading the attributes. */ void AnnotationFileXmlReader::readAnnotationAttributes(Annotation* annotation, const QString& annotationElementName, const QXmlStreamAttributes& attributes) { CaretAssert(annotation); { /* * Coordinate space */ const QString valueString = m_streamHelper->getRequiredAttributeStringValue(attributes, annotationElementName, ATTRIBUTE_COORDINATE_SPACE); bool valid = false; AnnotationCoordinateSpaceEnum::Enum value = AnnotationCoordinateSpaceEnum::fromName(valueString, &valid); if (valid) { annotation->setCoordinateSpace(value); } else { m_streamHelper->throwDataFileException("Invalid value " + valueString + " for attribute " + ATTRIBUTE_COORDINATE_SPACE); } } { /* * Background color */ const QString valueString = m_streamHelper->getRequiredAttributeStringValue(attributes, annotationElementName, ATTRIBUTE_BACKGROUND_CARET_COLOR); bool valid = false; CaretColorEnum::Enum value = CaretColorEnum::fromName(valueString, &valid); if (valid) { annotation->setBackgroundColor(value); } else { m_streamHelper->throwDataFileException("Invalid value " + valueString + " for attribute " + ATTRIBUTE_BACKGROUND_CARET_COLOR); } } { /* * Background custom color */ const QString valueString = m_streamHelper->getRequiredAttributeStringValue(attributes, annotationElementName, ATTRIBUTE_BACKGROUND_CUSTOM_RGBA); std::vector rgba; AString::toNumbers(valueString, rgba); if (rgba.size() == 4) { annotation->setCustomBackgroundColor(&rgba[0]); } else { m_streamHelper->throwDataFileException(ATTRIBUTE_BACKGROUND_CUSTOM_RGBA + " must contain 4 elements but " + valueString + " contains " + QString::number(rgba.size()) + " elements"); } } { /* * Foreground color */ const QString valueString = m_streamHelper->getRequiredAttributeStringValue(attributes, annotationElementName, ATTRIBUTE_FOREGROUND_CARET_COLOR); bool valid = false; CaretColorEnum::Enum value = CaretColorEnum::fromName(valueString, &valid); if (valid) { annotation->setLineColor(value); } else { m_streamHelper->throwDataFileException("Invalid value " + valueString + " for attribute " + ATTRIBUTE_FOREGROUND_CARET_COLOR); } } { /* * Foreground custom color */ const QString valueString = m_streamHelper->getRequiredAttributeStringValue(attributes, annotationElementName, ATTRIBUTE_FOREGROUND_CUSTOM_RGBA); std::vector rgba; AString::toNumbers(valueString, rgba); if (rgba.size() == 4) { annotation->setCustomLineColor(&rgba[0]); } else { m_streamHelper->throwDataFileException(ATTRIBUTE_FOREGROUND_CUSTOM_RGBA + " must contain 4 elements but " + valueString + " contains " + QString::number(rgba.size()) + " elements"); } } /* * Foreground line width */ annotation->setLineWidthPixelsObsolete(m_streamHelper->getRequiredAttributeFloatValue(attributes, annotationElementName, ATTRIBUTE_FOREGROUND_LINE_WIDTH_PIXELS)); /* * Line width percentage added on July 26, 2017. * A "negative value" indicates it is missing and the percentage width * may be set by graphics code that attempts to set the percentage using * the obsolete pixel width and viewport height. */ annotation->setLineWidthPercentage(m_streamHelper->getOptionalAttributeFloatValue(attributes, annotationElementName, ATTRIBUTE_FOREGROUND_LINE_WIDTH_PERCENTAGE, -1.0f)); /* * Tab Index */ annotation->setTabIndex(m_streamHelper->getRequiredAttributeIntValue(attributes, annotationElementName, ATTRIBUTE_TAB_INDEX)); /* * Window Index */ annotation->setWindowIndex(m_streamHelper->getRequiredAttributeIntValue(attributes, annotationElementName, ATTRIBUTE_WINDOW_INDEX)); /* * Spacer Tab Index added as part of WB-668 */ const AString spacerTabText = m_streamHelper->getOptionalAttributeStringValue(attributes, annotationElementName, ATTRIBUTE_SPACER_TAB_INDEX, ""); SpacerTabIndex spacerTabIndex; if ( ! spacerTabText.isEmpty()) { spacerTabIndex.setFromXmlAttributeText(spacerTabText); } annotation->setSpacerTabIndex(spacerTabIndex); /* * Unique Key */ if (m_fileVersionNumber >= XML_VERSION_TWO) { annotation->setUniqueKey(m_streamHelper->getRequiredAttributeIntValue(attributes, annotationElementName, ATTRIBUTE_UNIQUE_KEY)); } } /** * Read a one dimensional annotation. * * @param annotationElementName * Name of one-dimensional attribute. * @param annotation * One-dimensional annotation that has its data read. */ void AnnotationFileXmlReader::readOneDimensionalAnnotation(const QString& annotationElementName, AnnotationOneDimensionalShape* annotation) { CaretAssert(annotation); const QXmlStreamAttributes attributes = m_stream->attributes(); readAnnotationAttributes(annotation, annotationElementName, attributes); AnnotationLine* line = dynamic_cast(annotation); if (line != NULL) { line->setDisplayEndArrow(m_streamHelper->getOptionalAttributeBoolValue(attributes, annotationElementName, ATTRIBUTE_LINE_END_ARROW, false)); line->setDisplayStartArrow(m_streamHelper->getOptionalAttributeBoolValue(attributes, annotationElementName, ATTRIBUTE_LINE_START_ARROW, false)); } readCoordinate(ELEMENT_COORDINATE_ONE, annotation->getStartCoordinate()); readCoordinate(ELEMENT_COORDINATE_TWO, annotation->getEndCoordinate()); } /** * Read an annotation group. * * @param annotationFile * File that is being read. */ void AnnotationFileXmlReader::readGroup(AnnotationFile* annotationFile) { const QXmlStreamAttributes attributes = m_stream->attributes(); /* * Coordinate space */ AnnotationCoordinateSpaceEnum::Enum coordSpace = AnnotationCoordinateSpaceEnum::VIEWPORT; { const QString valueString = m_streamHelper->getRequiredAttributeStringValue(attributes, ELEMENT_GROUP, ATTRIBUTE_COORDINATE_SPACE); bool valid = false; coordSpace = AnnotationCoordinateSpaceEnum::fromName(valueString, &valid); if ( ! valid) { m_streamHelper->throwDataFileException("While reading annotation group, invalid value " + valueString + " for attribute " + ATTRIBUTE_COORDINATE_SPACE); } } /* * Group tyoe */ AnnotationGroupTypeEnum::Enum groupType = AnnotationGroupTypeEnum::INVALID; { const QString valueString = m_streamHelper->getRequiredAttributeStringValue(attributes, ELEMENT_GROUP, ATTRIBUTE_GROUP_TYPE); bool valid = false; groupType = AnnotationGroupTypeEnum::fromName(valueString, &valid); if ( ! valid) { m_streamHelper->throwDataFileException("While reading annotation group, invalid value " + valueString + " for attribute " + ATTRIBUTE_GROUP_TYPE); } } const int32_t tabOrWindowIndex = m_streamHelper->getRequiredAttributeIntValue(attributes, ELEMENT_GROUP, ATTRIBUTE_TAB_OR_WINDOW_INDEX); /* * Spacer Tab Index added as part of WB-668 */ const AString spacerTabText = m_streamHelper->getOptionalAttributeStringValue(attributes, ELEMENT_GROUP, ATTRIBUTE_SPACER_TAB_INDEX, ""); SpacerTabIndex spacerTabIndex; if ( ! spacerTabText.isEmpty()) { spacerTabIndex.setFromXmlAttributeText(spacerTabText); } const int32_t uniqueKey = m_streamHelper->getRequiredAttributeIntValue(attributes, ELEMENT_GROUP, ATTRIBUTE_UNIQUE_KEY); std::vector annotations; while (m_stream->readNextStartElement()) { bool skipCurrentElementFlag = true; const QString elementName = m_stream->name().toString(); if (elementName == ELEMENT_BOX) { CaretPointer annotation(new AnnotationBox(AnnotationAttributesDefaultTypeEnum::NORMAL)); readTwoDimensionalAnnotation(ELEMENT_BOX, annotation); annotations.push_back(annotation.releasePointer()); } else if (elementName == ELEMENT_IMAGE) { CaretPointer annotation(new AnnotationImage(AnnotationAttributesDefaultTypeEnum::NORMAL)); readTwoDimensionalAnnotation(ELEMENT_IMAGE, annotation); annotations.push_back(annotation.releasePointer()); } else if (elementName == ELEMENT_LINE) { CaretPointer annotation(new AnnotationLine(AnnotationAttributesDefaultTypeEnum::NORMAL)); readOneDimensionalAnnotation(ELEMENT_LINE, annotation); annotations.push_back(annotation.releasePointer()); } else if (elementName == ELEMENT_OVAL) { CaretPointer annotation(new AnnotationOval(AnnotationAttributesDefaultTypeEnum::NORMAL)); readTwoDimensionalAnnotation(ELEMENT_OVAL, annotation); annotations.push_back(annotation.releasePointer()); } else if (elementName == ELEMENT_PERCENT_SIZE_TEXT) { CaretPointer annotation(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL)); readTwoDimensionalAnnotation(ELEMENT_PERCENT_SIZE_TEXT, annotation); annotations.push_back(annotation.releasePointer()); } else if (elementName == ELEMENT_PERCENT_WIDTH_SIZE_TEXT) { CaretPointer annotation(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL)); readTwoDimensionalAnnotation(ELEMENT_PERCENT_WIDTH_SIZE_TEXT, annotation); annotationFile->addAnnotationDuringFileVersionOneReading(annotation.releasePointer()); } else if (elementName == ELEMENT_POINT_SIZE_TEXT) { CaretPointer annotation(new AnnotationPointSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL)); readTwoDimensionalAnnotation(ELEMENT_POINT_SIZE_TEXT, annotation); annotations.push_back(annotation.releasePointer()); } else if (elementName == ELEMENT_TEXT_OBSOLETE) { CaretPointer annotation(new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::NORMAL)); readTwoDimensionalAnnotation(ELEMENT_TEXT_OBSOLETE, annotation); annotations.push_back(annotation.releasePointer()); } else { m_streamHelper->throwDataFileException("Unexpected XML element " + elementName); } /* * These elements have no other child elements so move on */ if (skipCurrentElementFlag) { m_stream->skipCurrentElement(); } } if ( ! annotations.empty()) { annotationFile->addAnnotationGroupDuringFileReading(groupType, coordSpace, tabOrWindowIndex, spacerTabIndex, uniqueKey, annotations); } } /** * Read a two dimensional annotation. * * @param annotationElementName * Name of two-dimensional attribute. * @param annotation * Two-dimensional annotation that has its data read. */ void AnnotationFileXmlReader::readTwoDimensionalAnnotation(const QString& annotationElementName, AnnotationTwoDimensionalShape* annotation) { CaretAssert(annotation); const QXmlStreamAttributes attributes = m_stream->attributes(); readAnnotationAttributes(annotation, annotationElementName, attributes); /* * Shape width */ annotation->setWidth(m_streamHelper->getRequiredAttributeFloatValue(attributes, annotationElementName, ATTRIBUTE_WIDTH)); /* * Shape height */ annotation->setHeight(m_streamHelper->getRequiredAttributeFloatValue(attributes, annotationElementName, ATTRIBUTE_HEIGHT)); /* * Shape rotation angle */ annotation->setRotationAngle(m_streamHelper->getRequiredAttributeFloatValue(attributes, annotationElementName, ATTRIBUTE_ROTATION_ANGLE)); /* * Read the coordinate */ readCoordinate(ELEMENT_COORDINATE_ONE, annotation->getCoordinate()); /* * Is this an image annotation? */ AnnotationImage* imageAnn = dynamic_cast(annotation); if (imageAnn != NULL) { readImageDataElement(imageAnn); } /* * Is this a text annotation? */ AnnotationText* textAnn = dynamic_cast(annotation); if (textAnn != NULL) { readTextDataElement(textAnn, annotationElementName); } } /** * Read the image annotation element. * * @param imageAnnotation * Image annotation that has its element data read. * @throw * DataFileException */ void AnnotationFileXmlReader::readImageDataElement(AnnotationImage* imageAnnotation) { CaretAssert(imageAnnotation); const bool elementValid = m_stream->readNextStartElement(); if ( ! elementValid) { m_streamHelper->throwDataFileException("Failed to read element " + ELEMENT_IMAGE_RGBA_BYTES_IN_BASE64); } if (m_stream->name() != ELEMENT_IMAGE_RGBA_BYTES_IN_BASE64) { m_streamHelper->throwDataFileException("Expected elment " + ELEMENT_IMAGE_RGBA_BYTES_IN_BASE64 + " but read element " + m_stream->name().toString()); } const QXmlStreamAttributes attributes = m_stream->attributes(); const int32_t imageWidth = m_streamHelper->getRequiredAttributeIntValue(attributes, ELEMENT_IMAGE_RGBA_BYTES_IN_BASE64, ATTRIBUTE_IMAGE_WIDTH); const int32_t imageHeight = m_streamHelper->getRequiredAttributeIntValue(attributes, ELEMENT_IMAGE_RGBA_BYTES_IN_BASE64, ATTRIBUTE_IMAGE_HEIGHT); const int32_t numberOfBytes = imageWidth * imageHeight * 4; /* * Read the image bytes in base64 encoding which will also finish reading through * the closing element. */ const QString imageChars = m_stream->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement); if (m_stream->hasError()) { m_streamHelper->throwDataFileException("There was an error reading the image annotation's image bytes: " + m_stream->errorString()); } QByteArray imageBytes = QByteArray::fromBase64(imageChars.toLatin1()); if (imageBytes.size() == numberOfBytes) { const uint8_t* imageBytesPointer = (const uint8_t*)(imageBytes.data()); imageAnnotation->setImageBytesRGBA(imageBytesPointer, imageWidth, imageHeight); } else { m_streamHelper->throwDataFileException("There was an error reading the image annotations image bytes. " "The number of bytes read was " + AString::number(imageBytes.size()) + " but the number of bytes expected was " + AString::number(numberOfBytes)); } } /** * Read the text annotation element. * * @param textAnnotation * Text annotation that has its element data read. * @param annotationTextElementName * Name of the annotation element. * @throw * DataFileException */ void AnnotationFileXmlReader::readTextDataElement(AnnotationText *textAnnotation, const QString& annotationTextElementName) { CaretAssert(textAnnotation); const bool elementValid = m_stream->readNextStartElement(); if ( ! elementValid) { m_streamHelper->throwDataFileException("Failed to read element " + ELEMENT_TEXT_DATA); } if (m_stream->name() != ELEMENT_TEXT_DATA) { m_streamHelper->throwDataFileException("Expected elment " + ELEMENT_TEXT_DATA + " but read element " + m_stream->name().toString()); } const QXmlStreamAttributes attributes = m_stream->attributes(); bool haveTextColorFlag = false; { /* * Background color */ const QString valueString = m_streamHelper->getOptionalAttributeStringValue(attributes, annotationTextElementName, ATTRIBUTE_TEXT_CARET_COLOR, ""); if ( ! valueString.isEmpty()) { bool valid = false; CaretColorEnum::Enum value = CaretColorEnum::fromName(valueString, &valid); if (valid) { textAnnotation->setTextColor(value); haveTextColorFlag = true; } else { m_streamHelper->throwDataFileException("Invalid value " + valueString + " for attribute " + ATTRIBUTE_TEXT_CARET_COLOR); } } } bool haveCustomTextColorFlag = false; { /* * Background custom color */ const QString valueString = m_streamHelper->getOptionalAttributeStringValue(attributes, annotationTextElementName, ATTRIBUTE_TEXT_CUSTOM_RGBA, ""); if ( ! valueString.isEmpty()) { std::vector rgba; AString::toNumbers(valueString, rgba); if (rgba.size() == 4) { textAnnotation->setCustomTextColor(&rgba[0]); haveCustomTextColorFlag = true; } else { m_streamHelper->throwDataFileException(ATTRIBUTE_TEXT_CUSTOM_RGBA + " must contain 4 elements but " + valueString + " contains " + QString::number(rgba.size()) + " elements"); } } } if (haveTextColorFlag && haveCustomTextColorFlag) { /* nothing */ } else { /* * Older (pre Workbench 1.2) annotations did not have a text color * and the text was drawn using the foreground color. * So, copy the foreground color to the text color and set * the foreground color to none. */ textAnnotation->setTextColor(textAnnotation->getLineColor()); float rgba[4]; textAnnotation->getCustomLineColor(rgba); textAnnotation->setCustomTextColor(rgba); textAnnotation->setLineColor(CaretColorEnum::NONE); } textAnnotation->setBoldStyleEnabled(m_streamHelper->getRequiredAttributeBoolValue(attributes, ELEMENT_TEXT_DATA, ATTRIBUTE_TEXT_FONT_BOLD)); textAnnotation->setItalicStyleEnabled(m_streamHelper->getRequiredAttributeBoolValue(attributes, ELEMENT_TEXT_DATA, ATTRIBUTE_TEXT_FONT_ITALIC)); textAnnotation->setUnderlineStyleEnabled(m_streamHelper->getRequiredAttributeBoolValue(attributes, ELEMENT_TEXT_DATA, ATTRIBUTE_TEXT_FONT_UNDERLINE)); { const QString defaultValue = AnnotationTextConnectTypeEnum::toName(AnnotationTextConnectTypeEnum::ANNOTATION_TEXT_CONNECT_NONE); const QString valueString = m_streamHelper->getOptionalAttributeStringValue(attributes, ELEMENT_TEXT_DATA, ATTRIBUTE_TEXT_CONNECT_BRAINORDINATE, defaultValue); bool valid = false; AnnotationTextConnectTypeEnum::Enum connectValue = AnnotationTextConnectTypeEnum::fromName(valueString, &valid); if (valid) { textAnnotation->setConnectToBrainordinate(connectValue); } else { m_streamHelper->throwDataFileException("Invalid value " + valueString + " for attribute " + ATTRIBUTE_TEXT_CONNECT_BRAINORDINATE); } } { const QString valueString = m_streamHelper->getRequiredAttributeStringValue(attributes, ELEMENT_TEXT_DATA, ATTRIBUTE_TEXT_FONT_NAME); bool valid = false; AnnotationTextFontNameEnum::Enum fontName = AnnotationTextFontNameEnum::fromName(valueString, &valid); if (valid) { textAnnotation->setFont(fontName); } else { m_streamHelper->throwDataFileException("Invalid value " + valueString + " for attribute " + ATTRIBUTE_TEXT_FONT_NAME); } } if ((annotationTextElementName != ELEMENT_PERCENT_SIZE_TEXT) && (annotationTextElementName != ELEMENT_PERCENT_WIDTH_SIZE_TEXT)) { const QString valueString = m_streamHelper->getRequiredAttributeStringValue(attributes, ELEMENT_TEXT_DATA, ATTRIBUTE_TEXT_FONT_POINT_SIZE, "fontSize"); bool valid = false; AnnotationTextFontPointSizeEnum::Enum fontPointSize = AnnotationTextFontPointSizeEnum::fromName(valueString, &valid); if (valid) { textAnnotation->setFontPointSizeProtected(fontPointSize); } else { m_streamHelper->throwDataFileException("Invalid value " + valueString + " for attribute " + ATTRIBUTE_TEXT_FONT_POINT_SIZE); } } { const QString valueString = m_streamHelper->getRequiredAttributeStringValue(attributes, ELEMENT_TEXT_DATA, ATTRIBUTE_TEXT_HORIZONTAL_ALIGNMENT); bool valid = false; AnnotationTextAlignHorizontalEnum::Enum alignment = AnnotationTextAlignHorizontalEnum::fromName(valueString, &valid); if (valid) { textAnnotation->setHorizontalAlignment(alignment); } else { m_streamHelper->throwDataFileException("Invalid value " + valueString + " for attribute " + ATTRIBUTE_TEXT_HORIZONTAL_ALIGNMENT); } } { const QString valueString = m_streamHelper->getRequiredAttributeStringValue(attributes, ELEMENT_TEXT_DATA, ATTRIBUTE_TEXT_VERTICAL_ALIGNMENT); bool valid = false; AnnotationTextAlignVerticalEnum::Enum alignment = AnnotationTextAlignVerticalEnum::fromName(valueString, &valid); if (valid) { textAnnotation->setVerticalAlignment(alignment); } else { m_streamHelper->throwDataFileException("Invalid value " + valueString + " for attribute " + ATTRIBUTE_TEXT_VERTICAL_ALIGNMENT); } } { const QString valueString = m_streamHelper->getRequiredAttributeStringValue(attributes, ELEMENT_TEXT_DATA, ATTRIBUTE_TEXT_ORIENTATION); bool valid = false; AnnotationTextOrientationEnum::Enum orientation = AnnotationTextOrientationEnum::fromName(valueString, &valid); if (valid) { textAnnotation->setOrientation(orientation); } else { m_streamHelper->throwDataFileException("Invalid value " + valueString + " for attribute " + ATTRIBUTE_TEXT_ORIENTATION); } } if (annotationTextElementName == ELEMENT_PERCENT_SIZE_TEXT) { textAnnotation->setFontPercentViewportSizeProtected(m_streamHelper->getRequiredAttributeFloatValue(attributes, ELEMENT_TEXT_DATA, ATTRIBUTE_TEXT_FONT_PERCENT_VIEWPORT_SIZE)); } else if (annotationTextElementName == ELEMENT_PERCENT_WIDTH_SIZE_TEXT) { textAnnotation->setFontPercentViewportSizeProtected(m_streamHelper->getRequiredAttributeFloatValue(attributes, ELEMENT_TEXT_DATA, ATTRIBUTE_TEXT_FONT_PERCENT_VIEWPORT_SIZE)); } else { textAnnotation->setFontPercentViewportSizeProtected(m_streamHelper->getOptionalAttributeFloatValue(attributes, ELEMENT_TEXT_DATA, ATTRIBUTE_TEXT_FONT_PERCENT_VIEWPORT_SIZE, 5.0)); } if (annotationTextElementName == ELEMENT_TEXT_OBSOLETE) { } else if (annotationTextElementName == ELEMENT_PERCENT_SIZE_TEXT) { /* * Will cause warning or assertion failure if invalid value */ textAnnotation->setFontPercentViewportSizeProtected(textAnnotation->getFontPercentViewportSizeProtected()); } else if (annotationTextElementName == ELEMENT_PERCENT_WIDTH_SIZE_TEXT) { /* * Will cause warning or assertion failure if invalid value */ textAnnotation->setFontPercentViewportSizeProtected(textAnnotation->getFontPercentViewportSizeProtected()); } else if (annotationTextElementName == ELEMENT_POINT_SIZE_TEXT) { } else { m_streamHelper->throwDataFileException("Unrecognized text element name \"" + annotationTextElementName + "\" expected " + ELEMENT_PERCENT_SIZE_TEXT + " or " + ELEMENT_PERCENT_WIDTH_SIZE_TEXT + " or " + ELEMENT_POINT_SIZE_TEXT); } /* * Read the annotation's text which will also finish reading through * the closing element. */ const QString textChars = m_stream->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement); if (m_stream->hasError()) { m_streamHelper->throwDataFileException("There was an error reading the text annotation's characters: " + m_stream->errorString()); } textAnnotation->setText(textChars); if (m_stream->hasError()) { m_streamHelper->throwDataFileException("There was an error reading the annotation file in XML format (reported by QXmlStreamReader): " + m_stream->errorString()); } } connectome-workbench-1.4.2/src/Files/AnnotationFileXmlReader.h000066400000000000000000000072111360521144700243540ustar00rootroot00000000000000#ifndef __ANNOTATION_FILE_XML_READER_H__ #define __ANNOTATION_FILE_XML_READER_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationFileXmlFormatBase.h" #include "CaretPointer.h" class QXmlStreamAttributes; class QXmlStreamReader; namespace caret { class Annotation; class AnnotationCoordinate; class AnnotationFile; class AnnotationGroup; class AnnotationImage; class AnnotationOneDimensionalShape; class AnnotationText; class AnnotationTwoDimensionalShape; class XmlStreamReaderHelper; class AnnotationFileXmlReader : public AnnotationFileXmlFormatBase { public: AnnotationFileXmlReader(); virtual ~AnnotationFileXmlReader(); void readFile(const QString& filename, AnnotationFile* annotationFile); void readFileFromString(const QString& fileInString, AnnotationFile* annotationFile); // ADD_NEW_METHODS_HERE private: AnnotationFileXmlReader(const AnnotationFileXmlReader&); AnnotationFileXmlReader& operator=(const AnnotationFileXmlReader&); void readFileContentFromXmlStreamReader(const QString& filename, AnnotationFile* annotationFile); void readVersionOne(AnnotationFile* annotationFile); void readVersionTwo(AnnotationFile* annotationFile); void readGroup(AnnotationFile* annotationFile); void readOneDimensionalAnnotation(const QString& annotationElementName, AnnotationOneDimensionalShape* annotation); void readTwoDimensionalAnnotation(const QString& annotationElementName, AnnotationTwoDimensionalShape* annotation); void readCoordinate(const QString& coordinateElementName, AnnotationCoordinate* coordinate); void readAnnotationAttributes(Annotation* annotation, const QString& annotationElementName, const QXmlStreamAttributes& attributes); void readImageDataElement(AnnotationImage* imageAnnotation); void readTextDataElement(AnnotationText* textAnnotation, const QString& annotationTextElementName); CaretPointer m_stream; CaretPointer m_streamHelper; QString m_filename; int32_t m_fileVersionNumber; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_FILE_XML_READER_DECLARE__ // #endif // __ANNOTATION_FILE_XML_READER_DECLARE__ } // namespace #endif //__ANNOTATION_FILE_XML_READER_H__ connectome-workbench-1.4.2/src/Files/AnnotationFileXmlWriter.cxx000066400000000000000000000555761360521144700250220ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __ANNOTATION_FILE_XML_WRITER_DECLARE__ #include "AnnotationFileXmlWriter.h" #undef __ANNOTATION_FILE_XML_WRITER_DECLARE__ #include "AnnotationBox.h" #include "AnnotationCoordinate.h" #include "AnnotationFile.h" #include "AnnotationGroup.h" #include "AnnotationImage.h" #include "AnnotationLine.h" #include "AnnotationOval.h" #include "AnnotationText.h" #include "CaretAssert.h" #include "DataFileException.h" #include "XmlStreamWriterHelper.h" #include "XmlUtilities.h" using namespace caret; /** * \class caret::AnnotationFileXmlWriter * \brief Writes an Annotation File in XML format. * \ingroup Files */ /** * Constructor. */ AnnotationFileXmlWriter::AnnotationFileXmlWriter() : AnnotationFileXmlFormatBase() { m_stream.grabNew(NULL); m_streamHelper.grabNew(NULL); } /** * Destructor. */ AnnotationFileXmlWriter::~AnnotationFileXmlWriter() { } /** * Write the given Annotation File in XML format. Name of the file * is obtained from the file. * * @param annotationFile * Annotation File written in XML format. * @throws * DataFileException if there is an error writing the file. */ void AnnotationFileXmlWriter::writeFile(const AnnotationFile* annotationFile) { CaretAssert(annotationFile); const QString filename = annotationFile->getFileName(); if (filename.isEmpty()) { throw DataFileException("Name for writing annotation file is empty."); } /* * Open the file */ QFile file(filename); if ( ! file.open(QFile::WriteOnly)) { throw DataFileException(filename, "Error opening for writing: " + file.errorString()); } /* * Create an XML stream writer */ m_stream.grabNew(new QXmlStreamWriter(&file)); writeFileContentToXmlStreamWriter(annotationFile, filename); file.close(); if (m_stream->hasError()) { throw DataFileException(filename, "There was an error writing the annotation file in XML format (reported by QXmlStreamWriter)."); } } /** * Write the given Annotation File in XML format into the given string. * * @param annotationFile * The annotation file written to the stream writer. * @param fileContentString * Will contain XML version of the file on exit. * @throws * DataFileException if there is an error writing the file. */ void AnnotationFileXmlWriter::writeFileToString(const AnnotationFile* annotationFile, QString& fileContentString) { fileContentString.clear(); m_stream.grabNew(new QXmlStreamWriter(&fileContentString)); writeFileContentToXmlStreamWriter(annotationFile, "Scene Annotation File"); if (m_stream->hasError()) { throw DataFileException("There was an error writing the scene annotation file in XML format (reported by QXmlStreamWriter)."); } } /** * Write the content of the file to the XML Stream Writer. * * @param annotationFile * The annotation file written to the stream writer. * @param filename * Name of the file. */ void AnnotationFileXmlWriter::writeFileContentToXmlStreamWriter(const AnnotationFile* annotationFile, const QString& filename) { CaretAssert(m_stream); m_stream->setAutoFormatting(true); /* * Create the helper for reading XML */ if (m_streamHelper != NULL) { m_streamHelper.grabNew(NULL); } m_streamHelper.grabNew(new XmlStreamWriterHelper(filename, m_stream)); m_stream->writeStartDocument(); m_stream->writeStartElement(ELEMENT_ANNOTATION_FILE); /* * To improve backward compatibility, only write version 3 if there * are annotations in 'spacer' coordinate space. */ if (annotationFile->hasAnnotationsInCoordinateSpace(AnnotationCoordinateSpaceEnum::SPACER)) { m_stream->writeAttribute(ATTRIBUTE_VERSION, AString::number(XML_VERSION_THREE)); } else { m_stream->writeAttribute(ATTRIBUTE_VERSION, AString::number(XML_VERSION_TWO)); } m_streamHelper->writeMetaData(annotationFile->getFileMetaData()); // std::vector annotations; // annotationFile->getAllAnnotations(annotations); // const int32_t numberOfAnnotations = static_cast(annotations.size()); // for (int32_t i = 0; i < numberOfAnnotations; i++) { // CaretAssertVectorIndex(annotations, i); // const Annotation* annotation = annotations[i]; // CaretAssert(annotation); // // switch (annotation->getType()) { // case AnnotationTypeEnum::BOX: // writeBox(dynamic_cast(annotation)); // break; // case AnnotationTypeEnum::COLOR_BAR: // CaretAssertMessage(0, "Color bar is NEVER written to an annotation file"); // break; // case AnnotationTypeEnum::IMAGE: // writeImage(dynamic_cast(annotation)); // break; // case AnnotationTypeEnum::LINE: // writeLine(dynamic_cast(annotation)); // break; // case AnnotationTypeEnum::OVAL: // writeOval(dynamic_cast(annotation)); // break; // case AnnotationTypeEnum::TEXT: // writeText(dynamic_cast(annotation)); // break; // } // } std::vector annotationGroups; annotationFile->getAllAnnotationGroups(annotationGroups); for (std::vector::iterator groupIter = annotationGroups.begin(); groupIter != annotationGroups.end(); groupIter++) { writeGroup(*groupIter); } m_stream->writeEndElement(); // ELEMENT_ANNOTATION_FILE m_stream->writeEndDocument(); } /** * Write the given annotation group in XML. * * @param group * The annotation group. */ void AnnotationFileXmlWriter::writeGroup(const AnnotationGroup* group) { CaretAssert(group); if (group->isEmpty()) { return; } m_stream->writeStartElement(ELEMENT_GROUP); m_stream->writeAttribute(ATTRIBUTE_COORDINATE_SPACE, AnnotationCoordinateSpaceEnum::toName(group->getCoordinateSpace())); m_stream->writeAttribute(ATTRIBUTE_GROUP_TYPE, AnnotationGroupTypeEnum::toName(group->getGroupType())); m_stream->writeAttribute(ATTRIBUTE_TAB_OR_WINDOW_INDEX, QString::number(group->getTabOrWindowIndex())); m_stream->writeAttribute(ATTRIBUTE_SPACER_TAB_INDEX, group->getSpacerTabIndex().getXmlAttributeText()); m_stream->writeAttribute(ATTRIBUTE_UNIQUE_KEY, QString::number(group->getUniqueKey())); std::vector annotations; group->getAllAnnotations(annotations); for (std::vector::iterator annIter = annotations.begin(); annIter != annotations.end(); annIter++) { const Annotation* annotation = *annIter; CaretAssert(annotation); switch (annotation->getType()) { case AnnotationTypeEnum::BOX: writeBox(dynamic_cast(annotation)); break; case AnnotationTypeEnum::COLOR_BAR: CaretAssertMessage(0, "Color bar is NEVER written to an annotation file"); break; case AnnotationTypeEnum::IMAGE: writeImage(dynamic_cast(annotation)); break; case AnnotationTypeEnum::LINE: writeLine(dynamic_cast(annotation)); break; case AnnotationTypeEnum::OVAL: writeOval(dynamic_cast(annotation)); break; case AnnotationTypeEnum::TEXT: writeText(dynamic_cast(annotation)); break; } } // const AString indicesString = AString::fromNumbers(group->getAnnotationUniqueIdentifiers(), " "); // m_stream->writeCharacters(indicesString); m_stream->writeEndElement(); } /** * Write the given annotation box in XML. * * @param box * The annotation box. */ void AnnotationFileXmlWriter::writeBox(const AnnotationBox* box) { CaretAssert(box); writeTwoDimensionalAnnotation(box, ELEMENT_BOX); } /** * Write the given annotation image in XML. * * @param image * The annotation image. */ void AnnotationFileXmlWriter::writeImage(const AnnotationImage* image) { CaretAssert(image); const int32_t imageWidth = image->getImageWidth(); const int32_t imageHeight = image->getImageHeight(); const int32_t numberOfBytes = imageWidth * imageHeight * 4; if (numberOfBytes <= 0) { return; } const uint8_t* imageBytesRGBA = image->getImageBytesRGBA(); QByteArray byteArray((const char*)imageBytesRGBA, numberOfBytes); QByteArray byteArrayBase64(byteArray.toBase64()); const QString stringBase64(QString::fromLatin1(byteArrayBase64.constData(), byteArrayBase64.size())); QXmlStreamAttributes attributes; getTwoDimAnnotationPropertiesAsAttributes(image, attributes); QXmlStreamAttributes imageDataAttributes; imageDataAttributes.append(ATTRIBUTE_IMAGE_WIDTH, AString::number(image->getImageWidth())); imageDataAttributes.append(ATTRIBUTE_IMAGE_HEIGHT, AString::number(image->getImageHeight())); m_stream->writeStartElement(ELEMENT_IMAGE); m_stream->writeAttributes(attributes); writeCoordinate(image->getCoordinate(), ELEMENT_COORDINATE_ONE); m_stream->writeStartElement(ELEMENT_IMAGE_RGBA_BYTES_IN_BASE64); m_stream->writeAttributes(imageDataAttributes); m_stream->writeCharacters(stringBase64); m_stream->writeEndElement(); m_stream->writeEndElement(); } /** * Write the given annotation line in XML. * * @param line * The annotation line. */ void AnnotationFileXmlWriter::writeLine(const AnnotationLine* line) { CaretAssert(line); writeOneDimensionalAnnotation(line, ELEMENT_LINE); } /** * Write the given annotation oval in XML. * * @param oval * The annotation oval. */ void AnnotationFileXmlWriter::writeOval(const AnnotationOval* oval) { CaretAssert(oval); writeTwoDimensionalAnnotation(oval, ELEMENT_OVAL); } /** * Write the given annotation text in XML. * * @param text * The annotation text. */ void AnnotationFileXmlWriter::writeText(const AnnotationText* text) { CaretAssert(text); QXmlStreamAttributes attributes; getTwoDimAnnotationPropertiesAsAttributes(text, attributes); QXmlStreamAttributes textDataAttributes; textDataAttributes.append(ATTRIBUTE_TEXT_CARET_COLOR, CaretColorEnum::toName(text->getTextColor())); float rgba[4]; text->getCustomTextColor(rgba); textDataAttributes.append(ATTRIBUTE_TEXT_CUSTOM_RGBA, realArrayToString(rgba, 4)); textDataAttributes.append(ATTRIBUTE_TEXT_FONT_BOLD, AString::fromBool(text->isBoldStyleEnabled())); textDataAttributes.append(ATTRIBUTE_TEXT_FONT_ITALIC, AString::fromBool(text->isItalicStyleEnabled())); textDataAttributes.append(ATTRIBUTE_TEXT_FONT_NAME, AnnotationTextFontNameEnum::toName(text->getFont())); textDataAttributes.append(ATTRIBUTE_TEXT_FONT_POINT_SIZE, AnnotationTextFontPointSizeEnum::toName(text->getFontPointSizeProtected())); textDataAttributes.append(ATTRIBUTE_TEXT_FONT_UNDERLINE, AString::fromBool(text->isUnderlineStyleEnabled())); textDataAttributes.append(ATTRIBUTE_TEXT_HORIZONTAL_ALIGNMENT, AnnotationTextAlignHorizontalEnum::toName(text->getHorizontalAlignment())); textDataAttributes.append(ATTRIBUTE_TEXT_ORIENTATION, AnnotationTextOrientationEnum::toName(text->getOrientation())); textDataAttributes.append(ATTRIBUTE_TEXT_VERTICAL_ALIGNMENT, AnnotationTextAlignVerticalEnum::toName(text->getVerticalAlignment())); textDataAttributes.append(ATTRIBUTE_TEXT_FONT_PERCENT_VIEWPORT_SIZE, AString::number(text->getFontPercentViewportSizeProtected())); textDataAttributes.append(ATTRIBUTE_TEXT_CONNECT_BRAINORDINATE, AnnotationTextConnectTypeEnum::toName(text->getConnectToBrainordinate())); QString annotationElementName; switch (text->getFontSizeType()) { case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT: annotationElementName = ELEMENT_PERCENT_SIZE_TEXT; break; case AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_WIDTH: annotationElementName = ELEMENT_PERCENT_WIDTH_SIZE_TEXT; break; case AnnotationTextFontSizeTypeEnum::POINTS: annotationElementName = ELEMENT_POINT_SIZE_TEXT; break; } CaretAssert( ! annotationElementName.isEmpty()); m_stream->writeStartElement(annotationElementName); m_stream->writeAttributes(attributes); writeCoordinate(text->getCoordinate(), ELEMENT_COORDINATE_ONE); /* * Write the text data. * Note: QXmlStreamWriter::writeCharacters() will replace special * characters (& " ' < >) with escape sequences */ m_stream->writeStartElement(ELEMENT_TEXT_DATA); m_stream->writeAttributes(textDataAttributes); m_stream->writeCharacters(text->getText()); m_stream->writeEndElement(); m_stream->writeEndElement(); } /* * Get the annotation's properties in XML attributes. * * @param annotation * The Annotation. * @param attributes * XML attributes to which properties are appended. */ void AnnotationFileXmlWriter::getAnnotationPropertiesAsAttributes(const Annotation* annotation, QXmlStreamAttributes& attributes) { CaretAssert(annotation); attributes.append(ATTRIBUTE_COORDINATE_SPACE, AnnotationCoordinateSpaceEnum::toName(annotation->getCoordinateSpace())); attributes.append(ATTRIBUTE_BACKGROUND_CARET_COLOR, CaretColorEnum::toName(annotation->getBackgroundColor())); float rgba[4]; annotation->getCustomBackgroundColor(rgba); attributes.append(ATTRIBUTE_BACKGROUND_CUSTOM_RGBA, realArrayToString(rgba, 4)); attributes.append(ATTRIBUTE_FOREGROUND_CARET_COLOR, CaretColorEnum::toName(annotation->getLineColor())); annotation->getCustomLineColor(rgba); attributes.append(ATTRIBUTE_FOREGROUND_CUSTOM_RGBA, realArrayToString(rgba, 4)); attributes.append(ATTRIBUTE_FOREGROUND_LINE_WIDTH_PIXELS, QString::number(annotation->getLineWidthPixelsObsolete())); attributes.append(ATTRIBUTE_FOREGROUND_LINE_WIDTH_PERCENTAGE, QString::number(annotation->getLineWidthPercentage())); attributes.append(ATTRIBUTE_TAB_INDEX, QString::number(annotation->getTabIndex())); attributes.append(ATTRIBUTE_WINDOW_INDEX, QString::number(annotation->getWindowIndex())); attributes.append(ATTRIBUTE_SPACER_TAB_INDEX, annotation->getSpacerTabIndex().getXmlAttributeText()); attributes.append(ATTRIBUTE_UNIQUE_KEY, QString::number(annotation->getUniqueKey())); } /* * Get the two-dim annotation's properties in XML attributes. * * @param shape * The two-dim annotation. * @param attributes * XML attributes to which properties are appended. */ void AnnotationFileXmlWriter::getTwoDimAnnotationPropertiesAsAttributes(const AnnotationTwoDimensionalShape* shape, QXmlStreamAttributes& attributes) { CaretAssert(shape); getAnnotationPropertiesAsAttributes(shape, attributes); attributes.append(ATTRIBUTE_WIDTH, QString::number(shape->getWidth())); attributes.append(ATTRIBUTE_HEIGHT, QString::number(shape->getHeight())); attributes.append(ATTRIBUTE_ROTATION_ANGLE, QString::number(shape->getRotationAngle())); } /** * Write the given two dimensional annotation in XML. * * @param shape * The two-dimensional annotation. * @param annotationXmlElement * The XML element for the annotation. */ void AnnotationFileXmlWriter::writeTwoDimensionalAnnotation(const AnnotationTwoDimensionalShape* shape, const QString& annotationXmlElement) { CaretAssert(shape); QXmlStreamAttributes attributes; getTwoDimAnnotationPropertiesAsAttributes(shape, attributes); m_stream->writeStartElement(annotationXmlElement); m_stream->writeAttributes(attributes); writeCoordinate(shape->getCoordinate(), ELEMENT_COORDINATE_ONE); m_stream->writeEndElement(); } /** * Write the given one dimensional annotation in XML. * * @param shape * The one-dimensional annotation. * @param annotationXmlElement * The XML element for the annotation. */ void AnnotationFileXmlWriter::writeOneDimensionalAnnotation(const AnnotationOneDimensionalShape* shape, const QString& annotationXmlElement) { CaretAssert(shape); QXmlStreamAttributes attributes; getAnnotationPropertiesAsAttributes(shape, attributes); const AnnotationLine* line = dynamic_cast(shape); if (line != NULL) { attributes.append(ATTRIBUTE_LINE_END_ARROW, AString::fromBool(line->isDisplayEndArrow())); attributes.append(ATTRIBUTE_LINE_START_ARROW, AString::fromBool(line->isDisplayStartArrow())); } m_stream->writeStartElement(annotationXmlElement); m_stream->writeAttributes(attributes); writeCoordinate(shape->getStartCoordinate(), ELEMENT_COORDINATE_ONE); writeCoordinate(shape->getEndCoordinate(), ELEMENT_COORDINATE_TWO); m_stream->writeEndElement(); } /** * Write the given annotation coordinate in XML. * * @param coordinate * The annotation coordinate. * @param coordinateXmlElement * The XML element for the annotation coordinate. */ void AnnotationFileXmlWriter::writeCoordinate(const AnnotationCoordinate* coordinate, const QString& coordinateXmlElement) { CaretAssert(coordinate); float xyz[3]; coordinate->getXYZ(xyz); StructureEnum::Enum structure = StructureEnum::INVALID; int32_t numberOfNodes = -1; int32_t nodeIndex = -1; float nodeOffset = AnnotationCoordinate::getDefaultSurfaceOffsetLength(); AnnotationSurfaceOffsetVectorTypeEnum::Enum surfaceOffsetVectorType = AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX; coordinate->getSurfaceSpace(structure, numberOfNodes, nodeIndex, nodeOffset, surfaceOffsetVectorType); m_stream->writeStartElement(coordinateXmlElement); m_stream->writeAttribute(ATTRIBUTE_COORD_X, realToString(xyz[0])); m_stream->writeAttribute(ATTRIBUTE_COORD_Y, realToString(xyz[1])); m_stream->writeAttribute(ATTRIBUTE_COORD_Z, realToString(xyz[2])); m_stream->writeAttribute(ATTRIBUTE_COORD_SURFACE_STRUCTURE, StructureEnum::toName(structure)); m_stream->writeAttribute(ATTRIBUTE_COORD_SURFACE_NUMBER_OF_NODES, QString::number(numberOfNodes)); m_stream->writeAttribute(ATTRIBUTE_COORD_SURFACE_NODE_INDEX, QString::number(nodeIndex)); m_stream->writeAttribute(ATTRIBUTE_COORD_SURFACE_NODE_OFFSET, realToString(nodeOffset)); m_stream->writeAttribute(ATTRIBUTE_COORD_SURFACE_NODE_OFFSET_VECTOR_TYPE, AnnotationSurfaceOffsetVectorTypeEnum::toName(surfaceOffsetVectorType)); m_stream->writeEndElement(); } /** * Convert a real value to a string format. * * @param value * Value that is converted * @return * String format for value. */ QString AnnotationFileXmlWriter::realToString(const float value) const { return QString::number(value, 'f', 6); } /** * Convert an array of real values to string format. * * @param values * Array of values that are converted * @return * String format for values */ QString AnnotationFileXmlWriter::realArrayToString(const float values[], const int32_t numberOfValues) const { QString text; for (int32_t i = 0; i < numberOfValues; i++) { if (i > 0) { text.append(";"); } text.append(realToString(values[i])); } return text; } connectome-workbench-1.4.2/src/Files/AnnotationFileXmlWriter.h000066400000000000000000000075401360521144700244330ustar00rootroot00000000000000#ifndef __ANNOTATION_FILE_XML_WRITER_H__ #define __ANNOTATION_FILE_XML_WRITER_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationFileXmlFormatBase.h" #include "CaretPointer.h" class QXmlStreamAttributes; class QXmlStreamWriter; namespace caret { class Annotation; class AnnotationBox; class AnnotationCoordinate; class AnnotationFile; class AnnotationGroup; class AnnotationImage; class AnnotationLine; class AnnotationOneDimensionalShape; class AnnotationOval; class AnnotationText; class AnnotationTwoDimensionalShape; class XmlStreamWriterHelper; class AnnotationFileXmlWriter : public AnnotationFileXmlFormatBase { public: AnnotationFileXmlWriter(); virtual ~AnnotationFileXmlWriter(); void writeFile(const AnnotationFile* annotationFile); void writeFileToString(const AnnotationFile* annotationFile, QString& fileContentString); // ADD_NEW_METHODS_HERE private: AnnotationFileXmlWriter(const AnnotationFileXmlWriter&); AnnotationFileXmlWriter& operator=(const AnnotationFileXmlWriter&); QString realToString(const float value) const; QString realArrayToString(const float values[], const int32_t numberOfValues) const; void getAnnotationPropertiesAsAttributes(const Annotation* annotation, QXmlStreamAttributes& attributes); void getTwoDimAnnotationPropertiesAsAttributes(const AnnotationTwoDimensionalShape* shape, QXmlStreamAttributes& attributes); void writeFileContentToXmlStreamWriter(const AnnotationFile* annotationFile, const QString& filename); void writeBox(const AnnotationBox* box); void writeCoordinate(const AnnotationCoordinate* coordinate, const QString& coordinateXmlElement); void writeGroup(const AnnotationGroup* group); void writeImage(const AnnotationImage* image); void writeLine(const AnnotationLine* line); void writeOneDimensionalAnnotation(const AnnotationOneDimensionalShape* shape, const QString& annotationXmlElement); void writeTwoDimensionalAnnotation(const AnnotationTwoDimensionalShape* shape, const QString& annotationXmlElement); void writeOval(const AnnotationOval* oval); void writeText(const AnnotationText* text); CaretPointer m_stream; CaretPointer m_streamHelper; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_FILE_XML_WRITER_DECLARE__ #endif // __ANNOTATION_FILE_XML_WRITER_DECLARE__ } // namespace #endif //__ANNOTATION_FILE_XML_WRITER_H__ connectome-workbench-1.4.2/src/Files/AnnotationTextSubstitutionFile.cxx000066400000000000000000000523161360521144700264330ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_TEXT_SUBSTITUTION_FILE_DECLARE__ #include "AnnotationTextSubstitutionFile.h" #undef __ANNOTATION_TEXT_SUBSTITUTION_FILE_DECLARE__ #include #include #include "DataFileException.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "EventManager.h" #include "EventMapYokingSelectMap.h" #include "EventMapYokingValidation.h" #include "EventAnnotationTextSubstitutionGet.h" #include "EventAnnotationTextSubstitutionInvalidate.h" #include "GiftiMetaData.h" #include "qxtcsvmodel.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::AnnotationTextSubstitutionFile * \brief Substitutes text within text annotations * \ingroup Files */ /** * Constructor. */ AnnotationTextSubstitutionFile::AnnotationTextSubstitutionFile() : CaretDataFile(DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION) { initializeAnnotationTextSubstitutionFile(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_VALIDATION); } /** * Destructor. */ AnnotationTextSubstitutionFile::~AnnotationTextSubstitutionFile() { EventManager::get()->removeAllEventsFromListener(this); } /** * Copy constructor. * @param obj * Object that is copied. */ AnnotationTextSubstitutionFile::AnnotationTextSubstitutionFile(const AnnotationTextSubstitutionFile& obj) : CaretDataFile(obj), EventListenerInterface() { initializeAnnotationTextSubstitutionFile(); this->copyHelperAnnotationTextSubstitutionFile(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ AnnotationTextSubstitutionFile& AnnotationTextSubstitutionFile::operator=(const AnnotationTextSubstitutionFile& obj) { if (this != &obj) { CaretDataFile::operator=(obj); this->copyHelperAnnotationTextSubstitutionFile(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void AnnotationTextSubstitutionFile::copyHelperAnnotationTextSubstitutionFile(const AnnotationTextSubstitutionFile& obj) { *m_metadata = *obj.m_metadata; m_dataValues = obj.m_dataValues; m_numberOfSubstitutions = obj.m_numberOfSubstitutions; m_numberOfValues = obj.m_numberOfValues; m_substitutionNameToIndexMap = obj.m_substitutionNameToIndexMap; m_mapYokingGroup = obj.m_mapYokingGroup; setSelectedValueIndexPrivate(obj.m_selectedValueIndex); } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void AnnotationTextSubstitutionFile::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP) { EventMapYokingSelectMap* mapEvent = dynamic_cast(event); CaretAssert(mapEvent); if (mapEvent->getMapYokingGroup() == m_mapYokingGroup) { setSelectedValueIndex(mapEvent->getMapIndex()); } event->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_MAP_YOKING_VALIDATION) { EventMapYokingValidation* yokeEvent = dynamic_cast(event); CaretAssert(yokeEvent); if (yokeEvent->getMapYokingGroup() != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { yokeEvent->addAnnotationTextSubstitutionFile(this, m_mapYokingGroup); } } } /** * Initialize an instance of an annotation substitution file. */ void AnnotationTextSubstitutionFile::initializeAnnotationTextSubstitutionFile() { m_metadata.reset(new GiftiMetaData()); clearPrivate(); m_sceneAssistant.reset(new SceneClassAssistant()); m_sceneAssistant->add("m_selectedValueIndex", &m_selectedValueIndex); m_sceneAssistant->add("m_mapYokingGroup", &m_mapYokingGroup); } /** * @return The structure for this file. */ StructureEnum::Enum AnnotationTextSubstitutionFile::getStructure() const { return StructureEnum::ALL; } /** * Set the structure for this file. * @param structure * New structure for this file. */ void AnnotationTextSubstitutionFile::setStructure(const StructureEnum::Enum /*structure*/) { /* nothing */ } /** * @return Get access to the file's metadata. */ GiftiMetaData* AnnotationTextSubstitutionFile::getFileMetaData() { return m_metadata.get(); } /** * @return Get access to unmodifiable file's metadata. */ const GiftiMetaData* AnnotationTextSubstitutionFile::getFileMetaData() const { return m_metadata.get(); } /** * @return True if this file is empty, else false. */ bool AnnotationTextSubstitutionFile::isEmpty() const { return m_dataValues.empty(); } /** * Clear the content of this file. * This method is virtual so do not call from constructor/destructor. */ void AnnotationTextSubstitutionFile::clear() { CaretDataFile::clear(); clearPrivate(); } /** * Clear the content of this file. */ void AnnotationTextSubstitutionFile::clearPrivate() { m_metadata->clear(); m_dataValues.clear(); m_substitutionNameToIndexMap.clear(); m_numberOfSubstitutions = 0; m_numberOfValues = 0; m_mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; m_selectedValueIndex = -1; /* invalid so text substitutions get invalidated */ } /** * @return true if file is modified, else false. */ bool AnnotationTextSubstitutionFile::isModified() const { if (CaretDataFile::isModified()) { return true; } if (m_metadata->isModified()) { return true; } return false; } /** * @return Number of substitutions in the file. */ int32_t AnnotationTextSubstitutionFile::getNumberOfSubstitutions() const { return m_numberOfSubstitutions; } /** * @return Number of values for each substitutions in the file. */ int32_t AnnotationTextSubstitutionFile::getNumberOfValues() const { return m_numberOfValues; } /** * For the substitution at the given index, get the value at the given index. * * @param textSubstitutionIndex * Index of the text substitution * @param valueIndex * Index of the value in the text substitution */ AString AnnotationTextSubstitutionFile::getTextSubstitution(const int32_t textSubstitutionIndex, const int32_t valueIndex) const { CaretAssert((textSubstitutionIndex >=0) && (textSubstitutionIndex < m_numberOfSubstitutions)); CaretAssert((valueIndex >= 0) && (valueIndex < m_numberOfValues)); const int32_t substitutionOffset = (textSubstitutionIndex * m_numberOfValues); const int32_t dataIndex = substitutionOffset + valueIndex; CaretAssertVectorIndex(m_dataValues, dataIndex); const AString value(m_dataValues[dataIndex]); return value; } /** * For the substitution at the given name, get the value at the given index. * * @param textSubstitutionName * Name of the text substitution * @param valueIndex * Index of the value in the text substitution */ AString AnnotationTextSubstitutionFile::getTextSubstitution(const AString& textSubstitutionName, const int32_t valueIndex) const { /* * Convert name to a substitution index */ const int32_t textSubstitutionIndex = getColumnIndexForSubstitutionName(textSubstitutionName); AString text; if (textSubstitutionIndex >= 0) { text = getTextSubstitution(textSubstitutionIndex, valueIndex); } return text; } /** * Get text substitution values for the given event. * * @param substituteEvent * The text substitution event. */ void AnnotationTextSubstitutionFile::getSubstitutionValues(EventAnnotationTextSubstitutionGet* substituteEvent) const { const std::vector& substitutionNames = substituteEvent->getSubstitutionNames(); for (const auto name : substitutionNames) { AString value = getTextSubstitution(name, getSelectedValueIndex()); substituteEvent->setSubstitutionValueForName(name, value); } } /** * Save subclass data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void AnnotationTextSubstitutionFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * @return True if this file type supports writing, else false. * * By default, this method returns true. Files that do not support * writing should override this method and return false. */ bool AnnotationTextSubstitutionFile::supportsWriting() const { return false; } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void AnnotationTextSubstitutionFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } void AnnotationTextSubstitutionFile::cleanCsvModel(QxtCsvModel* csvModel, const AString& filename) { /* * QxtCsvModel interprets blank lines as rows. * So, find blank rows at end and reduce number of rows */ int32_t lastValidRowIndex = -1; for (int32_t iRow = 0; iRow < m_numberOfValues; iRow++) { bool validRowFlag = false; for (int32_t iCol = 0; iCol < m_numberOfSubstitutions; iCol++) { const QModelIndex modelIndex = csvModel->index(iRow, iCol); if ( ! modelIndex.isValid()) { throw DataFileException("Getting QModelIndex failed for row=" + AString::number(iRow) + " and column=" + AString::number(iCol) + " for file " + filename); } const QVariant dataVariant = csvModel->data(modelIndex, Qt::DisplayRole); AString cell = dataVariant.toString(); if ( ! cell.isEmpty()) { validRowFlag = true; /* * Remove double quotes from ends of a cell */ if (cell.startsWith('\"') && cell.endsWith('\"')) { cell = cell.mid(1, cell.length() - 2); csvModel->setData(modelIndex, cell, Qt::DisplayRole); } } } if (validRowFlag) { lastValidRowIndex = iRow; } } if (lastValidRowIndex >= 0) { int32_t numberOfValidRows = lastValidRowIndex + 1; m_numberOfValues = numberOfValidRows; } } /** * Read the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully read. */ void AnnotationTextSubstitutionFile::readFile(const AString& filename) { clear(); try { checkFileReadability(filename); QFile file(filename); if ( ! file.open(QFile::ReadOnly)) { throw DataFileException("Unable to open " + filename + " for reading."); } /* * Excel writes CSV files using '\r' between lines. * QxtCsvModel uses QIODevice::readLine(), and Qt's documentation * indicates that QIODevice::readLine() uses only '\n' as a line separator. * See http://doc.qt.io/Qt-5/qiodevice.html#readLine */ AString fileContent = file.readAll(); fileContent = fileContent.trimmed(); fileContent = fileContent.replace('\r', '\n'); fileContent = fileContent.replace("\n\n", "\n"); QByteArray byteArray(fileContent.toLatin1()); QBuffer buffer(&byteArray); const bool hasHeaderFlag(false); const QChar separator(','); QxtCsvModel csvModel; csvModel.setSource(&buffer, hasHeaderFlag, separator); m_numberOfSubstitutions = csvModel.columnCount(); m_numberOfValues = csvModel.rowCount(); if ((m_numberOfSubstitutions > 0) && (m_numberOfValues > 0)) { cleanCsvModel(&csvModel, filename); } const int32_t numberOfValues = (m_numberOfSubstitutions * m_numberOfValues); if (numberOfValues <= 0) { throw DataFileException(filename + " is empty or reading failed."); } /* * Read data from the CSV Model. * Data is stored in Column Major Order so * All values for first column, then * all values for second column, etc. */ m_dataValues.reserve(numberOfValues); for (int32_t iColumn = 0; iColumn < m_numberOfSubstitutions; iColumn++) { for (int32_t iRow = 0; iRow < m_numberOfValues; iRow++) { const QModelIndex modelIndex = csvModel.index(iRow, iColumn); if ( ! modelIndex.isValid()) { throw DataFileException("Getting QModelIndex failed for row=" + AString::number(iRow) + " and column=" + AString::number(iColumn) + " for file " + filename); } const QVariant dataVariant = csvModel.data(modelIndex, Qt::DisplayRole); m_dataValues.push_back(dataVariant.toString()); } } CaretAssert(numberOfValues == static_cast(m_dataValues.size())); } catch (const DataFileException& dfe) { clear(); throw dfe; } /* * At this time, the file does not support 'names' for the substitutions * * Column names in Excel are A, B, ..., Z, AA, AB, ..., AZ, BA, BB, ... */ for (int32_t iColumn = 0; iColumn < m_numberOfSubstitutions; iColumn++) { const AString columnName = columnIndexToDefaultSubstitutionName(iColumn); m_substitutionNameToIndexMap.insert(std::make_pair(columnName, iColumn)); } setFileName(filename); clearModified(); } /** * Convert a column index into a default subsitution name (AA, AB, ..., BA, ...) that * is the same as the column names in Excel. * * @param columnIndex * Index of the column. * @return * The default name for the column. */ AString AnnotationTextSubstitutionFile::columnIndexToDefaultSubstitutionName(const int32_t columnIndex) const { CaretAssert(columnIndex >= 0); AString columnName; const int32_t zeroCharacterUnicodeValue(48); const int32_t nineCharacterUnicodeValue(57); const int32_t aCharacterUnicodeValue(97); const int32_t pCharacterUnicodeValue(112); /* * Use QString's number() method to generate a Base 26 number * from the column index. The characters int he Base 26 number * are 0 to 9, and 'a' to 'p'. */ const QString baseTwentySixChars(QString::number(columnIndex, 26)); const int32_t numChars = baseTwentySixChars.length(); for (int32_t iChar = 0; iChar < numChars; iChar++) { QChar unicodeChar = baseTwentySixChars.at(iChar).toLower(); int32_t unicodeValue = unicodeChar.unicode(); int32_t offsetFromCapitalA = -1; if ((unicodeValue >= zeroCharacterUnicodeValue) && (unicodeValue <= nineCharacterUnicodeValue)) { offsetFromCapitalA = unicodeValue - zeroCharacterUnicodeValue; } else if ((unicodeValue >= aCharacterUnicodeValue) && (unicodeValue <= pCharacterUnicodeValue)) { offsetFromCapitalA = unicodeValue - aCharacterUnicodeValue + 10; } else { CaretAssertMessage(0, ("Unicode character=" + QString(unicodeChar) + " unicode value=" + AString::number(unicodeValue) + " is not a digit nor uppercase character")); } if ((numChars > 1) && (iChar == 0)) { --offsetFromCapitalA; } CaretAssert((offsetFromCapitalA >= 0) && (offsetFromCapitalA < 26)); columnName.append('A' + offsetFromCapitalA); } return columnName; } /** * Get the column containing substitutions for the given substitution name. * The name should be a valid name. * * @param substitutionName * Name of the substitution * @return * Column for the name or -1 if name not found. */ int32_t AnnotationTextSubstitutionFile::getColumnIndexForSubstitutionName(const AString substitutionName) const { int32_t columnIndex = -1; const auto iter = m_substitutionNameToIndexMap.find(substitutionName); if (iter != m_substitutionNameToIndexMap.end()) { columnIndex = iter->second; } else { CaretLogWarning("Requesting column for invalid substitution name \"" + substitutionName + "\""); } return columnIndex; } /** * @return The selected map yoking group for this file. */ MapYokingGroupEnum::Enum AnnotationTextSubstitutionFile::getMapYokingGroup() const { return m_mapYokingGroup; } /** * Set the map yoking group for this file. * * @param mapYokingGroup * New map yoking group selection. */ void AnnotationTextSubstitutionFile::setMapYokingGroup(const MapYokingGroupEnum::Enum mapYokingGroup) { m_mapYokingGroup = mapYokingGroup; } /** * @return The selected value (map) index. */ int32_t AnnotationTextSubstitutionFile::getSelectedValueIndex() const { /* validates index */ setSelectedValueIndexPrivate(m_selectedValueIndex); return m_selectedValueIndex; } /** * Set the selected value index. * * @param valueIndex * New value for index. */ void AnnotationTextSubstitutionFile::setSelectedValueIndex(const int32_t valueIndex) { setSelectedValueIndexPrivate(valueIndex); } /** * Set the selected value index. Private method that invalidates text substitutions * and ensures selected value index is valid. * * @param valueIndex * New value for index. */ void AnnotationTextSubstitutionFile::setSelectedValueIndexPrivate(const int32_t valueIndex) const { int32_t previousValueIndex = m_selectedValueIndex; m_selectedValueIndex = valueIndex; if (m_selectedValueIndex < 0) { m_selectedValueIndex = 0; } else if (m_selectedValueIndex >= m_numberOfValues) { m_selectedValueIndex = m_numberOfValues - 1; } if (previousValueIndex != m_selectedValueIndex) { EventManager::get()->sendEvent(EventAnnotationTextSubstitutionInvalidate().getPointer()); } } /** * Write the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully written. */ void AnnotationTextSubstitutionFile::writeFile(const AString& /*filename*/) { throw DataFileException("Writing of Annotation Text Substitution Files is not supported."); } connectome-workbench-1.4.2/src/Files/AnnotationTextSubstitutionFile.h000066400000000000000000000113701360521144700260530ustar00rootroot00000000000000#ifndef __ANNOTATION_TEXT_SUBSTITUTION_FILE_H__ #define __ANNOTATION_TEXT_SUBSTITUTION_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretDataFile.h" #include "EventListenerInterface.h" #include "MapYokingGroupEnum.h" class QxtCsvModel; namespace caret { class EventAnnotationTextSubstitutionGet; class SceneClassAssistant; class AnnotationTextSubstitutionFile : public CaretDataFile, public EventListenerInterface { public: AnnotationTextSubstitutionFile(); virtual ~AnnotationTextSubstitutionFile(); AnnotationTextSubstitutionFile(const AnnotationTextSubstitutionFile& obj); AnnotationTextSubstitutionFile& operator=(const AnnotationTextSubstitutionFile& obj); // ADD_NEW_METHODS_HERE void getSubstitutionValues(EventAnnotationTextSubstitutionGet* substituteEvent) const; virtual StructureEnum::Enum getStructure() const override; virtual void setStructure(const StructureEnum::Enum structure) override; virtual GiftiMetaData* getFileMetaData() override; virtual const GiftiMetaData* getFileMetaData() const override; virtual bool isEmpty() const override; virtual void clear() override; virtual void receiveEvent(Event* event) override; virtual void readFile(const AString& filename) override; virtual void writeFile(const AString& filename) override; virtual bool supportsWriting() const override; virtual bool isModified() const override; int32_t getNumberOfSubstitutions() const; int32_t getNumberOfValues() const; AString getTextSubstitution(const int32_t textSubstitutionIndex, const int32_t valueIndex) const; AString getTextSubstitution(const AString& textSubstitutionName, const int32_t valueIndex) const; MapYokingGroupEnum::Enum getMapYokingGroup() const; void setMapYokingGroup(const MapYokingGroupEnum::Enum mapYokingGroup); int32_t getSelectedValueIndex() const; void setSelectedValueIndex(const int32_t valueIndex); protected: virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: void copyHelperAnnotationTextSubstitutionFile(const AnnotationTextSubstitutionFile& obj); void clearPrivate(); void initializeAnnotationTextSubstitutionFile(); AString columnIndexToDefaultSubstitutionName(const int32_t columnIndex) const; int32_t getColumnIndexForSubstitutionName(const AString substitutionName) const; void setSelectedValueIndexPrivate(const int32_t valueIndex) const; void cleanCsvModel(QxtCsvModel* csvModel, const AString& filename); std::unique_ptr m_metadata; std::unique_ptr m_sceneAssistant; std::vector m_dataValues; std::map m_substitutionNameToIndexMap; int32_t m_numberOfSubstitutions; int32_t m_numberOfValues; MapYokingGroupEnum::Enum m_mapYokingGroup; mutable int32_t m_selectedValueIndex; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_TEXT_SUBSTITUTION_FILE_DECLARE__ // #endif // __ANNOTATION_TEXT_SUBSTITUTION_FILE_DECLARE__ } // namespace #endif //__ANNOTATION_TEXT_SUBSTITUTION_FILE_H__ connectome-workbench-1.4.2/src/Files/Border.cxx000066400000000000000000001573021360521144700214350ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BORDER_DECLARE__ #include "Border.h" #undef __BORDER_DECLARE__ #include #include #include #include #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPointer.h" #include "DataFileException.h" #include "GeodesicHelper.h" #include "MathFunctions.h" #include "SurfaceFile.h" #include "SurfaceProjectedItem.h" #include "SurfaceProjectionBarycentric.h" #include "XmlWriter.h" using namespace caret; using namespace std; /** * \class caret::Border * \brief A border is a connected line segment on a source or volume. */ /** * Constructor. */ Border::Border() : CaretObjectTracksModification() { m_copyOfBorderPriorToLastEditing = NULL; clear(); // m_color = CaretColorEnum::BLACK; // m_selectionClassNameModificationStatus = true; // name/class is new!! } /** * Create a new border using the given surface's node indices. * * @param borderName * Name for border. * @param surfaceFile * The surface file. * @param nodeIndices * Indices of the surface nodes. * @return * Pointer to the newly created border. */ Border* Border::newInstanceFromSurfaceNodes(const AString& borderName, const SurfaceFile* surfaceFile, std::vector& nodeIndices) { CaretAssert(surfaceFile); Border* border = new Border(); border->setName(borderName); const int32_t numNodes = static_cast(nodeIndices.size()); for (int32_t i = 0; i < numNodes; i++) { const int32_t nodeIndex = nodeIndices[i]; const float* xyz = surfaceFile->getCoordinate(nodeIndex); SurfaceProjectedItem* spi = new SurfaceProjectedItem(); spi->setStereotaxicXYZ(xyz); spi->setStructure(surfaceFile->getStructure()); border->addPoint(spi); } return border; } /** * Destructor. */ Border::~Border() { clear(); } /** * Copy constructor. * @param obj * Object that is copied. */ Border::Border(const Border& obj) : CaretObjectTracksModification(obj) { m_copyOfBorderPriorToLastEditing = NULL; copyHelperBorder(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ Border& Border::operator=(const Border& obj) { if (this != &obj) { CaretObjectTracksModification::operator=(obj); copyHelperBorder(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void Border::copyHelperBorder(const Border& obj) { clear(); const int32_t numPoints = obj.getNumberOfPoints(); for (int32_t i = 0; i < numPoints; i++) { SurfaceProjectedItem* spi = new SurfaceProjectedItem(*obj.m_points[i]); addPoint(spi); } m_name = obj.m_name; m_className = obj.m_className; m_closed = obj.m_closed; clearModified(); setNameOrClassModified(); // new name/class so modified } /** * Clear the border. * Removes all points, resets names, etc. */ void Border::clear() { removeAllPoints(); m_closed = false; m_groupNameSelectionItem = NULL; m_classRgbaColor[0] = 0.0; m_classRgbaColor[1] = 0.0; m_classRgbaColor[2] = 0.0; m_classRgbaColor[3] = 1.0; m_classRgbaColorValid = false; m_nameRgbaColor[0] = 0.0; m_nameRgbaColor[1] = 0.0; m_nameRgbaColor[2] = 0.0; m_nameRgbaColor[3] = 1.0; m_nameRgbaColorValid = false; if (m_copyOfBorderPriorToLastEditing != NULL) { delete m_copyOfBorderPriorToLastEditing; m_copyOfBorderPriorToLastEditing = NULL; } m_name = ""; m_className = ""; setNameOrClassModified(); // new name/class so modified } /** * @return Structure to which this border is assigned. */ StructureEnum::Enum Border::getStructure() const { StructureEnum::Enum structure = StructureEnum::INVALID; if (m_points.empty() == false) { structure = m_points[0]->getStructure(); } return structure; } void Border::setStructure(const StructureEnum::Enum& structure) { int numPoints = getNumberOfPoints(); for (int i = 0; i < numPoints; ++i) { getPoint(i)->setStructure(structure); } } /** * @return Is the class RGBA color valid? */ bool Border::isClassRgbaValid() const { return m_classRgbaColorValid; } /** * Set then class RGBA color invalid. */ void Border::setClassRgbaInvalid() { m_classRgbaColorValid = false; } /** * @return The class RGBA color components * ranging zero to one. */ const float* Border::getClassRgba() const { return m_classRgbaColor; } /** * Get the class RGBA color components * ranging zero to one. */ void Border::getClassRgba(float rgba[4]) const { rgba[0] = m_classRgbaColor[0]; rgba[1] = m_classRgbaColor[1]; rgba[2] = m_classRgbaColor[2]; rgba[3] = m_classRgbaColor[3]; } /** * Set the RGBA color components assigned to the class. * @param rgba * Red, green, blue, alpha ranging zero to one. */ void Border::setClassRgba(const float rgba[3]) { m_classRgbaColor[0] = rgba[0]; m_classRgbaColor[1] = rgba[1]; m_classRgbaColor[2] = rgba[2]; m_classRgbaColor[3] = rgba[3]; m_classRgbaColorValid = true; } /** * @return Is the name RGBA color valid? */ bool Border::isNameRgbaValid() const { return m_nameRgbaColorValid; } /** * Set then name RGBA color invalid. */ void Border::setNameRgbaInvalid() { m_nameRgbaColorValid = false; } /** * @return The name RGBA color components * ranging zero to one. */ const float* Border::getNameRgba() const { return m_nameRgbaColor; } /** * Get the name RGBA color components * ranging zero to one. */ void Border::getNameRgba(float rgba[4]) const { rgba[0] = m_nameRgbaColor[0]; rgba[1] = m_nameRgbaColor[1]; rgba[2] = m_nameRgbaColor[2]; rgba[3] = m_nameRgbaColor[3]; } /** * Set the RGBA color components assigned to the name. * @param rgba * Red, green, blue, alpha ranging zero to one. */ void Border::setNameRgba(const float rgba[4]) { m_nameRgbaColor[0] = rgba[0]; m_nameRgbaColor[1] = rgba[1]; m_nameRgbaColor[2] = rgba[2]; m_nameRgbaColor[3] = rgba[3]; m_nameRgbaColorValid = true; } /** * @return True if all points are on the * same structure, else false. */ bool Border::verifyAllPointsOnSameStructure() const { const int32_t numPoints = getNumberOfPoints(); if (numPoints <= 1) { return true; } StructureEnum::Enum structure = m_points[0]->getStructure(); for (int32_t i = 1; i < numPoints; i++) { if (m_points[i]->getStructure() != structure) { return false; } } return true; } bool Border::verifyForSurfaceNumberOfNodes(const int32_t& numNodes) const { int32_t numPoints = getNumberOfPoints(); for (int j = 0; j < numPoints; ++j) { const SurfaceProjectionBarycentric* thisProj = getPoint(j)->getBarycentricProjection();//addPoint makes sure these are always valid const int32_t* nodes = thisProj->getTriangleNodes(); for (int k = 0; k < 3; ++k) { if (nodes[k] >= numNodes) { return false; } } } return true; } /** * Remove all points in this border. */ void Border::removeAllPoints() { const int32_t numPoints =getNumberOfPoints(); for (int32_t i = 0; i < numPoints; i++) { delete m_points[i]; } m_points.clear(); setModified(); } /** * @return the name of the border. */ AString Border::getName() const { return m_name; } /** * Set the name of the border. * @param name * New name for border. */ void Border::setName(const AString& name) { if (m_name != name) { m_name = name; setModified(); setNameOrClassModified(); } } /** * @return the class name of the border. */ AString Border::getClassName() const { return m_className; } /** * Set the class name of the border. * @param className * New class name for border. */ void Border::setClassName(const AString& className) { if (m_className != className) { m_className = className; setModified(); setNameOrClassModified(); } } /** * @return Number of points in the border. */ int32_t Border::getNumberOfPoints() const { return m_points.size(); } /** * Get the border point at the given index. * @param indx * Index of desired border point. * @return * Pointer to border point. */ const SurfaceProjectedItem* Border::getPoint(const int32_t indx) const { CaretAssertVectorIndex(m_points, indx); return m_points[indx]; } /** * Get the border point at the given index. * @param indx * Index of desired border point. * @return * Pointer to border point. */ SurfaceProjectedItem* Border::getPoint(const int32_t indx) { CaretAssertVectorIndex(m_points, indx); return m_points[indx]; } /** * Returns the index of the border point nearest * the given XYZ coordinate and within the * given maximum distance. * * @param surfaceFile * Surface file used for unprojecting border points * and producing XYZ coordinates. * @param xyz * The XYZ coordinates for which nearest border * point is desired. * @param maximumDistance * Border points searched are limited to those * within this distance from the XYZ coordinate. * @param distanceToNearestPointOut * If a point is found within the maximum distance * @return * Index of nearest border point or negative if * no border points is within the maximum distance. */ int32_t Border::findPointIndexNearestXYZ(const SurfaceFile* surfaceFile, const float xyz[3], const float maximumDistance, float& distanceToNearestPointOut) const { CaretAssert(surfaceFile); const int32_t numPoints = getNumberOfPoints(); if (numPoints <= 0) { return -1; } if (surfaceFile->getStructure() != getStructure()) { return -1; } int32_t nearestIndex = -1; float nearestDistanceSQ = maximumDistance * maximumDistance; float pointXYZ[3]; for (int32_t i = 0; i < numPoints; i++) { if (m_points[i]->getProjectedPosition(*surfaceFile, pointXYZ, true)) { const float distSQ = MathFunctions::distanceSquared3D(xyz, pointXYZ); if (distSQ <= nearestDistanceSQ) { nearestDistanceSQ = distSQ; nearestIndex = i; } } } if (nearestIndex >= 0) { distanceToNearestPointOut = std::sqrt(nearestDistanceSQ); } return nearestIndex; } /** * Add a point to the border. NOTE: the border * takes ownership of the point and will delete * it. After calling this method DO NOT ever * use the point passed to this method. * * @param point * Point that is added to the border. */ void Border::addPoint(SurfaceProjectedItem* point) { if (m_points.size() != 0 && m_points[0]->getStructure() != point->getStructure()) { delete point;//keep our word and handle deleting the argument throw DataFileException("attempt to add point of different structure to a border"); } if (!point->getBarycentricProjection()->isValid()) { delete point; throw DataFileException("attempt to add point without valid barycentric projection to border"); } const int32_t* nodes = point->getBarycentricProjection()->getTriangleNodes(); for (int k = 0; k < 3; ++k) { if (nodes[k] < 0) { delete point; throw DataFileException("attempt to add point using negative node number"); } } m_points.push_back(point); setModified(); } /** * Add copies of points from the given border starting * at startPointIndex and adding a total of pointCount * points. * * @param border * Border from which points are copied. * @param startPointIndex * Index of first point that is copied from border. * If this value is negative, points will be copied * starting from the first point in the border. * @param pointCount * Number of points that are copied. If this value * is negative all of the remaining points in the * border are copied. If zero, none are copied. */ void Border::addPoints(const Border* border, const int32_t startPointIndex, const int32_t pointCount) { CaretAssert(border); const int32_t startIndex = (startPointIndex >= 0) ? startPointIndex : 0; const int32_t endIndex = (pointCount >= 0) ? (startIndex + pointCount) : border->getNumberOfPoints(); for (int32_t i = startIndex; i < endIndex; i++) { SurfaceProjectedItem* spi = new SurfaceProjectedItem(*border->getPoint(i)); addPoint(spi); } } bool Border::isClosed() const { return m_closed; } void Border::setClosed(const bool& closed) { m_closed = closed; } /** * Add points to the border so that the last point * connects to the first point. */ void Border::addPointsToCloseBorderWithGeodesic(const SurfaceFile* surfaceFile) { const int32_t numberOfPoints = getNumberOfPoints(); if (numberOfPoints < 3) { return; } /* * Index of surface node nearest first border point */ float firstBorderPointXYZ[3]; m_points[0]->getProjectedPosition(*surfaceFile, firstBorderPointXYZ, true); const int firstNodeIndex = surfaceFile->closestNode(firstBorderPointXYZ); if (firstNodeIndex < 0) { return; } /* * Index of surface node nearest last border point */ float lastBorderPointXYZ[3]; m_points[numberOfPoints - 1]->getProjectedPosition(*surfaceFile, lastBorderPointXYZ, true); const int lastNodeIndex = surfaceFile->closestNode(lastBorderPointXYZ); if (lastNodeIndex < 0) { return; } /* * Geodesics from node nearest last border point */ std::vector nodeParents; std::vector nodeDistances; CaretPointer geoHelp = surfaceFile->getGeodesicHelper(); geoHelp->getGeoFromNode(lastNodeIndex, nodeDistances, nodeParents, true); /* * Get path along border points */ const int32_t numberOfSurfaceNodes = surfaceFile->getNumberOfNodes(); std::vector pathFromFirstNodeToLastNode; int32_t geoNodeIndex = firstNodeIndex; int32_t failCounter = 0; while (geoNodeIndex >= 0) { geoNodeIndex = nodeParents[geoNodeIndex]; if (geoNodeIndex == lastNodeIndex) { geoNodeIndex = -1; } else if (geoNodeIndex >= 0) { pathFromFirstNodeToLastNode.push_back(geoNodeIndex); } failCounter ++; if (failCounter > numberOfSurfaceNodes) { CaretLogWarning("Geodesic path for closing border failed."); pathFromFirstNodeToLastNode.clear(); } } /* * Add points to border. */ const float triangleAreas[3] = { 1.0, 0.0, 0.0 }; const StructureEnum::Enum structure = surfaceFile->getStructure(); const int32_t numNewPoints = static_cast(pathFromFirstNodeToLastNode.size()); for (int32_t i = (numNewPoints - 1); i >= 0; i--) { const int32_t nodeIndex = pathFromFirstNodeToLastNode[i]; const float* xyz = surfaceFile->getCoordinate(nodeIndex); SurfaceProjectedItem* spi = new SurfaceProjectedItem(); spi->setStereotaxicXYZ(xyz); spi->setStructure(structure); SurfaceProjectionBarycentric* bp = spi->getBarycentricProjection(); bp->setTriangleAreas(triangleAreas); const int32_t triangleNodes[3] = { nodeIndex, nodeIndex, nodeIndex }; bp->setTriangleNodes(triangleNodes); bp->setValid(true); addPoint(spi); } } /** * Remove the point at the given index. * @param indx * Index of point for removal. */ void Border::removePoint(const int32_t indx) { CaretAssertVectorIndex(m_points, indx); delete m_points[indx]; m_points.erase(m_points.begin() + indx); setModified(); } /** * Remove the first point from the border. */ void Border::removeFirstPoint() { const int numPoints = getNumberOfPoints(); if (numPoints > 0) { removePoint(0); } } /** * Remove the last point from the border. */ void Border::removeLastPoint() { const int numPoints = getNumberOfPoints(); if (numPoints > 0) { removePoint(numPoints - 1); } } /** * Reverse the order of points in a border. */ void Border::reverse() { std::reverse(m_points.begin(), m_points.end()); setModified(); } /** * Revise a border by extending from a of point border. * * @param surfaceFile * Surface on which border extension is performed. * @param pointIndex * Point nearest the first point in the segment. * @param segment * A border segment containing the extension. * @throws BorderException * If there is an error revising the border. */ void Border::reviseExtendFromPointIndex(SurfaceFile* surfaceFile, const int32_t pointIndex, const Border* segment) { const int32_t numPoints = getNumberOfPoints(); if (numPoints <= 2) { throw BorderException("Border being update contains less than two points"); } const int numberOfSegmentPoints = segment->getNumberOfPoints(); if (numberOfSegmentPoints <= 0) { throw BorderException("Border segment for extending contains no points"); } if ((pointIndex < 0) || (pointIndex >= numPoints)) { throw BorderException("Point index for extending border is invalid."); } /* * Copy the border just in case something goes wrong */ /* * Lengths from point index to start and end points */ const float distToStart = getSegmentLength(surfaceFile, 0, pointIndex); const float distToEnd = getSegmentLength(surfaceFile, pointIndex, numPoints - 1); /* * Create a temporary border */ Border tempBorder; /* * Add on to start or ending end of border */ if (distToStart < distToEnd) { /* * Reverse the new segment and it becomes the first part of the border */ Border segmentCopy = *segment; segmentCopy.reverse(); tempBorder.addPoints(&segmentCopy); /* * Add points from this border starting AFTER pointIndex * to the last point) */ const int32_t startPointIndex = pointIndex + 1; if (startPointIndex < numPoints) { tempBorder.addPoints(this, startPointIndex); } } else { /* * Add points from this border from the first point to * the point BEFORE pointIndex */ const int32_t pointCount = pointIndex; if (pointCount > 0) { tempBorder.addPoints(this, 0, pointCount); } /* * Add the new segment */ tempBorder.addPoints(segment); } replacePointsWithUndoSaving(&tempBorder); } /** * Revise a border by extending from the end of a border. * * @param surfaceFile * Surface on which border extension is performed. * @param segment * A border segment containing the extension. * @throws BorderException * If there is an error revising the border. */ void Border::reviseExtendFromEnd(SurfaceFile* surfaceFile, const Border* segment) { const int32_t numPoints = getNumberOfPoints(); if (numPoints <= 0) { throw BorderException("Border being update contains no points"); } const int numberOfSegmentPoints = segment->getNumberOfPoints(); if (numberOfSegmentPoints <= 0) { throw BorderException("Border segment for extending contains no points"); } /* * Get coordinate of first point in new segment */ float segmentStartXYZ[3]; if (segment->getPoint(0)->getProjectedPosition(*surfaceFile, segmentStartXYZ, true) == false) { throw BorderException("First point in extending segment has invalid coordinate. Redraw."); } /* * Find point in this border nearest start of new segment */ const float distanceTolerance = 5.0; float distanceToStartOfNewSegment = 0.0; const int32_t borderPointNearestNewSegmentStart = findPointIndexNearestXYZ(surfaceFile, segmentStartXYZ, distanceTolerance, distanceToStartOfNewSegment); if (borderPointNearestNewSegmentStart < 0) { throw BorderException("New segment does not start near an existing border"); } /* * Get distance from both ends of existing border to first * point in new segment */ float borderStartXYZ[3]; getPoint(0)->getProjectedPosition(*surfaceFile, borderStartXYZ, true); const float distToStart = MathFunctions::distance3D(borderStartXYZ, segmentStartXYZ); float borderEndXYZ[3]; getPoint(numPoints - 1)->getProjectedPosition(*surfaceFile, borderEndXYZ, true); const float distToEnd = MathFunctions::distance3D(borderEndXYZ, segmentStartXYZ); /* * Add on to start or ending end of border */ int32_t startPointIndex = -1; int32_t endPointIndex = -1; bool reverseOrderFlag = false; if (distToStart < distToEnd) { if (distToStart > distanceTolerance) { throw BorderException("New segment does not start near the end of a border."); } endPointIndex = borderPointNearestNewSegmentStart; reverseOrderFlag = true; } else { if (distToEnd > distanceTolerance) { throw BorderException("New segment does not start near the end of a border."); } startPointIndex = borderPointNearestNewSegmentStart; } /* * If needed, swap point indices * if (reverseOrderFlag) { std::swap(startPointIndex, endPointIndex); } */ /* * Create a temporary border */ Border tempBorder; /* * Add in points prior to updated points */ if (startPointIndex >= 0) { tempBorder.addPoints(this, 0, startPointIndex); } /* * Add new points */ Border segmentCopy = *segment; if (reverseOrderFlag) { segmentCopy.reverse(); } tempBorder.addPoints(&segmentCopy); /* * Add in points after updated points */ if (endPointIndex >= 0) { tempBorder.addPoints(this, (endPointIndex + 1)); } replacePointsWithUndoSaving(&tempBorder); } /** * Revise a border by erasing from the end of a border. * * @param surfaceFile * Surface on which border erasing is performed. * @param segment * A border segment containing the erasing. * @throws BorderException * If there is an error revising the border. */ void Border::reviseEraseFromEnd(SurfaceFile* surfaceFile, const Border* segment) { /* * Get coordinate of first and last points in the segment */ const int numberOfSegmentPoints = segment->getNumberOfPoints(); if (numberOfSegmentPoints <= 0) { throw BorderException("Border segment for erasing contains no points"); } float segmentStartXYZ[3]; if (segment->getPoint(0)->getProjectedPosition(*surfaceFile, segmentStartXYZ, true) == false) { throw BorderException("First point in erase segment has invalid coordinate. Redraw."); } float segmentEndXYZ[3]; if (segment->getPoint(numberOfSegmentPoints - 1)->getProjectedPosition(*surfaceFile, segmentEndXYZ, true) == false) { throw BorderException("End point in erase segment has invalid coordinate. Redraw."); } const float tolerance = 10.0; /* * Find points in this border nearest the first and * last points in the erase segment */ float distanceToStartPoint = 0.0; int32_t startPointIndex = findPointIndexNearestXYZ(surfaceFile, segmentStartXYZ, tolerance, distanceToStartPoint); if (startPointIndex < 0) { throw BorderException("Start of segment drawn for erasing is not close enough to existing border"); } float distanceToEndPoint = 0.0; int32_t endPointIndex = findPointIndexNearestXYZ(surfaceFile, segmentEndXYZ, tolerance, distanceToEndPoint); if (endPointIndex < 0) { throw BorderException("End of segment drawn for erasing is not close enough to existing border"); } /* * If needed, swap point indices */ const bool reverseOrderFlag = (startPointIndex > endPointIndex); if (reverseOrderFlag) { std::swap(startPointIndex, endPointIndex); } /* * Create a temporary border */ Border tempBorder; /* * Add in points prior to updated points */ if (startPointIndex >= 0) { tempBorder.addPoints(this, 0, startPointIndex); } /* * Add in points after updated points */ if (endPointIndex >= 0) { tempBorder.addPoints(this, (endPointIndex + 1)); } saveBorderForUndoEditing(); replacePoints(&tempBorder); } /** * Revise a border by replacing a segment in a border. * * @param surfaceFile * Surface on which border segment replacement is performed. * @param segment * A border containing the new segment. * @throws BorderException * If there is an error replacing the segment in the border. */ void Border::reviseReplaceSegment(SurfaceFile* surfaceFile, const Border* segment) { /* * Get coordinate of first and last points in the segment */ const int numberOfSegmentPoints = segment->getNumberOfPoints(); if (numberOfSegmentPoints < 2) { throw BorderException("Border segment for replacing contains less than 2 points"); } float segmentStartXYZ[3]; if (segment->getPoint(0)->getProjectedPosition(*surfaceFile, segmentStartXYZ, true) == false) { throw BorderException("First point in replace segment has invalid coordinate. Redraw."); } float segmentEndXYZ[3]; if (segment->getPoint(numberOfSegmentPoints - 1)->getProjectedPosition(*surfaceFile, segmentEndXYZ, true) == false) { throw BorderException("End point in replace segment has invalid coordinate. Redraw."); } const float tolerance = 10.0; /* * Locate points in this border that are nearest the start * and end points in the new border segment. */ float distanceOfFirstSegmentPointToThisBorder = 0.0; int32_t lowestPointIndex = findPointIndexNearestXYZ(surfaceFile, segmentStartXYZ, tolerance, distanceOfFirstSegmentPointToThisBorder); if (lowestPointIndex < 0) { throw BorderException("Start of segment drawn for replacing is not close enough to existing border"); } float distanceOfLastSegmentPointToThisBorder = 0.0; int32_t highestPointIndex = findPointIndexNearestXYZ(surfaceFile, segmentEndXYZ, tolerance, distanceOfLastSegmentPointToThisBorder); if (highestPointIndex < 0) { throw BorderException("End of segment drawn for replacing is not close enough to existing border"); } /* * Swap lowest and highest point indexes so that lowest < highest */ if (lowestPointIndex > highestPointIndex) { std::swap(lowestPointIndex, highestPointIndex); } /* * Length in this border from lowest to highest point index */ const float lowestToHighestLength = getSegmentLength(surfaceFile, lowestPointIndex, highestPointIndex); /* * Length in this border from highest to lowest point index (assumes border * is closed. */ const float highestToLowestLength = getSegmentLength(surfaceFile, highestPointIndex, lowestPointIndex); /* * Create a temporary border */ Border newBorder; Border newBorderSecondSegment; /* * Keep part of this border that between low and high * indices that is the LONGEST */ if (lowestToHighestLength > highestToLowestLength) { /* * Keep part of this border from lowest index to highest index */ const int32_t lowToHighCount = highestPointIndex - lowestPointIndex + 1; newBorder.addPoints(this, lowestPointIndex, lowToHighCount); } else { /* * Keep segment from highest index to end */ const int32_t highToEndCount = getNumberOfPoints() - highestPointIndex; newBorderSecondSegment.addPoints(this, highestPointIndex, highToEndCount); /* * Keep segment from start to lowest point index * NOTE: Segments need to be separate otherwise * linear border will become closed. */ const int32_t startToLowCount = lowestPointIndex + 1; newBorder.addPoints(this, 0, startToLowCount); } const int32_t newBorderNumberOfPoints = newBorder.getNumberOfPoints(); if (newBorderNumberOfPoints > 0) { float newBorderLastXYZ[3]; if (newBorder.getPoint(newBorderNumberOfPoints - 1)->getProjectedPosition(*surfaceFile, newBorderLastXYZ, true)) { /* * Get position of first and last points in the new segment. */ float segmentFirstPointXYZ[3]; const bool validFirstPoint = segment->getPoint(0)->getProjectedPosition(*surfaceFile, segmentFirstPointXYZ, true); float segmentLastPointXYZ[3]; const bool validLastPoint = segment->getPoint(numberOfSegmentPoints - 1)->getProjectedPosition(*surfaceFile, segmentLastPointXYZ, true); if (validFirstPoint && validLastPoint) { /* * Distance to last point in border being created * to first and last point in new segment */ const float firstDistance = MathFunctions::distance3D(newBorderLastXYZ, segmentFirstPointXYZ); const float lastDistance = MathFunctions::distance3D(newBorderLastXYZ, segmentLastPointXYZ); /* * Remove endpoint(s) of new segment if they are very * close to a point in this border that is being updated */ Border trimmedSegment(*segment); const float distanceTolerance = 1.0; if (distanceOfFirstSegmentPointToThisBorder < distanceTolerance) { trimmedSegment.removeLastPoint(); } if (distanceOfLastSegmentPointToThisBorder < distanceTolerance) { trimmedSegment.removeFirstPoint(); } const int32_t numTrimmedSegmentPoints = trimmedSegment.getNumberOfPoints(); if (numTrimmedSegmentPoints > 0) { if (firstDistance < lastDistance) { /* * Add new segment onto the end of the existing border piece */ newBorder.addPoints(&trimmedSegment, 0, numTrimmedSegmentPoints); } else { /* * New segment is probably opposite orientation * (clockwise/counter-clockwise) that border that is * being edited. */ Border reversedSegment(trimmedSegment); reversedSegment.reverse(); newBorder.addPoints(&reversedSegment, 0, reversedSegment.getNumberOfPoints()); } } if (newBorderSecondSegment.getNumberOfPoints() > 0) { newBorder.addPoints(&newBorderSecondSegment, 0, newBorderSecondSegment.getNumberOfPoints()); } /* * Replace this border with the newly created border */ replacePointsWithUndoSaving(&newBorder); } else { throw BorderException("Border replacement failed: First or last point in new segment failed to project."); } } else { throw BorderException("Border replacement failed: Failed to project original border segment."); } } else { throw BorderException("Border replacement failed: No points were kept from original border."); } } ///** // * Revise a border by replacing a segment in a border. // * // * @param surfaceFile // * Surface on which border segment replacement is performed. // * @param segment // * A border containing the new segment. // * @throws BorderException // * If there is an error replacing the segment in the border. // */ //void //Border::reviseReplaceSegment(SurfaceFile* surfaceFile, // const Border* segment) //{ // /* // * Get coordinate of first and last points in the segment // */ // const int numberOfSegmentPoints = segment->getNumberOfPoints(); // if (numberOfSegmentPoints <= 0) { // throw BorderException("Border segment for erasing contains no points"); // } // float segmentStartXYZ[3]; // if (segment->getPoint(0)->getProjectedPosition(*surfaceFile, // segmentStartXYZ, // true) == false) { // throw BorderException("First point in erase segment has invalid coordinate. Redraw."); // } // // float segmentEndXYZ[3]; // if (segment->getPoint(numberOfSegmentPoints - 1)->getProjectedPosition(*surfaceFile, // segmentEndXYZ, // true) == false) { // throw BorderException("End point in erase segment has invalid coordinate. Redraw."); // } // // const float tolerance = 10.0; // // /* // * Find points in this border nearest the first and // * last points in the erase segment // */ // float distanceToStartPoint = 0.0; // int32_t segmentStartPointIndex = findPointIndexNearestXYZ(surfaceFile, // segmentStartXYZ, // tolerance, // distanceToStartPoint); // if (segmentStartPointIndex < 0) { // throw BorderException("Start of segment drawn for erasing is not close enough to existing border"); // } // float distanceToEndPoint = 0.0; // int32_t segmentEndPointIndex = findPointIndexNearestXYZ(surfaceFile, // segmentEndXYZ, // tolerance, // distanceToEndPoint); // if (segmentEndPointIndex < 0) { // throw BorderException("End of segment drawn for erasing is not close enough to existing border"); // } // // /* // * Make copy of segment // */ // Border replacementSegment(*segment); // // /* // * If needed, swap point indices and reverse order in segment // */ // const bool reverseOrderFlag = (segmentStartPointIndex > segmentEndPointIndex); // if (reverseOrderFlag) { // std::swap(segmentStartPointIndex, segmentEndPointIndex); // } // // /* // * Determine which segment in border to replace by using the // * segment with the minimal length. // */ // const float startToEndLength = getSegmentLength(surfaceFile, // segmentStartPointIndex, // segmentEndPointIndex); // const float endToStartLength = getSegmentLength(surfaceFile, // segmentEndPointIndex, // segmentStartPointIndex); // // /* // * Create a temporary border // */ // Border tempBorder; // // if (startToEndLength < endToStartLength) { // /* // * Add in points from start of border // */ // if (segmentStartPointIndex >= 0) { // tempBorder.addPoints(this, // 0, // segmentStartPointIndex); // } // // /* // * Add new points // */ // if (reverseOrderFlag) { // replacementSegment.reverse(); // } // tempBorder.addPoints(&replacementSegment); // // /* // * Add in points from end of border // */ // if (segmentEndPointIndex >= 0) { // tempBorder.addPoints(this, // (segmentEndPointIndex + 1)); // } // } // else { // /* // * Add new points // */ // tempBorder.addPoints(&replacementSegment); // // /* // * Add points from start to end // */ // const int32_t numSegmentPoints = (segmentEndPointIndex // - segmentStartPointIndex // + 1); // tempBorder.addPoints(this, // segmentStartPointIndex, // numSegmentPoints); // } // // replacePoints(&tempBorder); //} /** * Get the length of the border segment formed by the all of the points * using the starting and ending point indices (inclusively). * * When (segmentStartPointIndex < endPointIndex), the segment length is that * formed by the points from startPointIndex to endPointIndex. * * When (segmentStartPointIndex > endPointIndex), the segment length is that * formed by startPointIndex to the last point, last point to first point * and first point to endPointIndex. (Assumes border is a circular border). * * @param segmentStartPointIndex * Index of first border point in the border segement. * @param segmentEndPointIndex * Index of last border point in the border segment. * @param surfaceFile * Surface on which straightline distance between border points * is calculated. */ float Border::getSegmentLength(SurfaceFile* surfaceFile, const int32_t segmentStartPointIndex, const int32_t segmentEndPointIndex) { CaretAssert(surfaceFile); const int32_t numPoints = getNumberOfPoints(); if (numPoints <= 1) { return 0.0; } const int32_t lastPointIndex = numPoints - 1; CaretAssert((segmentStartPointIndex >= 0) && (segmentStartPointIndex < numPoints)); CaretAssert((segmentEndPointIndex >= 0) && (segmentEndPointIndex < numPoints)); float segmentLength = 0.0; if (segmentStartPointIndex > segmentEndPointIndex) { CaretAssert(segmentStartPointIndex <= lastPointIndex); const float d1 = getSegmentLength(surfaceFile, segmentStartPointIndex, lastPointIndex); float d2 = 0.0; { float xyz[3], xyzNext[3]; if (m_points[lastPointIndex]->getProjectedPosition(*surfaceFile, xyz, true) && m_points[0]->getProjectedPosition(*surfaceFile, xyzNext, true)) { d2 = MathFunctions::distance3D(xyz, xyzNext); } } CaretAssert(0 <= segmentEndPointIndex); const float d3 = getSegmentLength(surfaceFile, 0, segmentEndPointIndex); segmentLength = (d1 + d2 + d3); } else { for (int32_t i = segmentStartPointIndex; i < segmentEndPointIndex; i++) { float xyz[3], xyzNext[3]; const int32_t iNext = i + 1; CaretAssert(iNext < numPoints); if (m_points[i]->getProjectedPosition(*surfaceFile, xyz, true) && m_points[iNext]->getProjectedPosition(*surfaceFile, xyzNext, true)) { segmentLength += MathFunctions::distance3D(xyz, xyzNext); } } } return segmentLength; } /** * Replace the points in this border with points from the given border. * An "undo" copy of the border is also created. * * @param border Border whose points are copied into this border. */ void Border::replacePointsWithUndoSaving(const Border* border) { saveBorderForUndoEditing(); replacePoints(border); } /** * Replace the points in this border with * the given border. * @param border Border whose points are copied * into this border. */ void Border::replacePoints(const Border* border) { removeAllPoints(); const int32_t numPoints = border->getNumberOfPoints(); for (int i = 0; i < numPoints; i++) { SurfaceProjectedItem* spi = new SurfaceProjectedItem(*border->getPoint(i)); addPoint(spi); } } /** * Set modification status of name/class to modified. * * Name/Class modification status is used * by the selection controls that display * borders based upon selected classes and * names. */ void Border::setNameOrClassModified() { m_groupNameSelectionItem = NULL; m_nameRgbaColorValid = false; m_classRgbaColorValid = false; } /** * Set the selection item for the group/name hierarchy. * * @param item * The selection item from the group/name hierarchy. */ void Border::setGroupNameSelectionItem(GroupAndNameHierarchyItem* item) { m_groupNameSelectionItem = item; } /** * @return The selection item for the Group/Name selection hierarchy. * May be NULL in some circumstances. */ const GroupAndNameHierarchyItem* Border::getGroupNameSelectionItem() const { return m_groupNameSelectionItem; } /** * Save the border for undo editing. */ void Border::saveBorderForUndoEditing() { if (m_copyOfBorderPriorToLastEditing == NULL) { m_copyOfBorderPriorToLastEditing = new Border(*this); } else { m_copyOfBorderPriorToLastEditing->replacePoints(this); } } /** * @return True if last editing of border can be "undone". */ bool Border::isUndoBorderValid() const { if (m_copyOfBorderPriorToLastEditing != NULL) { return true; } return false; } /** * Undo the last editing of this border. */ void Border::undoLastBorderEditing() { if (m_copyOfBorderPriorToLastEditing != NULL) { replacePoints(m_copyOfBorderPriorToLastEditing); delete m_copyOfBorderPriorToLastEditing; m_copyOfBorderPriorToLastEditing = NULL; } } /** * Get a description of this object's content. * @return String describing this object's content. */ AString Border::toString() const { return "Border " + m_name; } /** * Write the border to the XML Writer. * @param xmlWriter * Writer for XML output. */ void Border::writeAsXML(XmlWriter& xmlWriter) { xmlWriter.writeStartElement(XML_TAG_BORDER); xmlWriter.writeElementCharacters(XML_TAG_NAME, m_name); if (m_className.isEmpty() == false) { xmlWriter.writeElementCharacters(XML_TAG_CLASS_NAME, m_className); } const int32_t numPoints = getNumberOfPoints(); for (int32_t i = 0; i < numPoints; i++) { m_points[i]->writeAsXML(xmlWriter); } xmlWriter.writeEndElement(); } void Border::writeXML3(QXmlStreamWriter& xml) const { xml.writeStartElement("BorderPart"); xml.writeAttribute("Closed", (isClosed() ? "True" : "False")); int numPoints = getNumberOfPoints(); xml.writeStartElement("Vertices"); for (int p = 0; p < numPoints; ++p) { const SurfaceProjectionBarycentric* thisBary = getPoint(p)->getBarycentricProjection(); const int32_t* nodes = thisBary->getTriangleNodes(); xml.writeCharacters(AString::number(nodes[0]) + " " + AString::number(nodes[1]) + " " + AString::number(nodes[2]) + "\n"); } xml.writeEndElement(); xml.writeStartElement("Weights"); for (int p = 0; p < numPoints; ++p) { const SurfaceProjectionBarycentric* thisBary = getPoint(p)->getBarycentricProjection(); const float* weights = thisBary->getTriangleAreas(); xml.writeCharacters(AString::number(weights[0]) + " " + AString::number(weights[1]) + " " + AString::number(weights[2]) + "\n"); } xml.writeEndElement(); xml.writeEndElement();//BorderPart } void Border::readXML1(QXmlStreamReader& xml) { clear(); CaretAssert(xml.isStartElement() && xml.name() == "Border"); bool haveName = false, haveClass = false, haveColorType = false; for (xml.readNext(); !xml.atEnd() && !xml.isEndElement(); xml.readNext()) { if (xml.isStartElement()) { QStringRef name = xml.name(); if (name == "Name") { if (haveName) throw DataFileException("multiple Name elements in one Border element"); m_name = xml.readElementText();//sets error on unexpected child element if (xml.hasError()) throw DataFileException("XML parsing error in Name: " + xml.errorString()); haveName = true; } else if (name == "ClassName") { if (haveClass) throw DataFileException("multiple ClassName elements in one Border element"); m_className = xml.readElementText();//sets error on unexpected child element if (xml.hasError()) throw DataFileException("XML parsing error in ClassName: " + xml.errorString()); haveClass = true; } else if (name == "ColorName") {//a gui setting that caret5 wrote into the border file, so ignore it if (haveColorType) throw DataFileException("multiple ColorName elements in one Border element"); xml.readElementText();//errors on unexpected element if (xml.hasError()) throw DataFileException("XML parsing error in ColorName: " + xml.errorString()); haveColorType = true; } else if (name == "SurfaceProjectedItem") { CaretPointer myItem(new SurfaceProjectedItem());//again, because current interface requires ownership passing of pointer myItem->readBorderFileXML1(xml); addPoint(myItem.releasePointer()); } else { throw DataFileException("unexpected element in Border: " + name.toString()); } } } if (xml.hasError()) throw DataFileException("XML parsing error in Border: " + xml.errorString()); CaretAssert(xml.isEndElement() && xml.name() == "Border"); if (getNumberOfPoints() > 1 && (*getPoint(0) == *getPoint(getNumberOfPoints() - 1))) { m_closed = true; removeLastPoint(); } } void Border::readXML3(QXmlStreamReader& xml) { clear(); CaretAssert(xml.isStartElement() && xml.name() == "BorderPart"); QXmlStreamAttributes myAttrs = xml.attributes(); if (!myAttrs.hasAttribute("Closed")) throw DataFileException("BorderPart element missing required attribute Closed"); QStringRef closedStr = myAttrs.value("Closed"); if (closedStr == "True") { setClosed(true); } else if (closedStr == "False") { setClosed(false); } else { throw DataFileException("unrecognized value for Closed attribute in BorderPart: " + closedStr.toString()); } vector vertices; vector weights; bool haveVertices = false, haveWeights = false; for (xml.readNext(); !xml.atEnd() && !xml.isEndElement(); xml.readNext()) { if (xml.isStartElement()) { QStringRef name = xml.name(); if (name == "Vertices") { if (haveVertices) throw DataFileException("multiple Vertices elements in one BorderPart element"); QString vertexText = xml.readElementText();//errors on unexpected element if (xml.hasError()) throw DataFileException("XML parsing error in Vertices: " + xml.errorString()); QStringList vertexStrings = vertexText.split(QRegExp("\\s+"), QString::SkipEmptyParts); int numItems = (int)vertexStrings.size(); if (numItems % 3 != 0) throw DataFileException("number of items in Vertices element text is not a multiple of 3"); for (int i = 0; i < numItems; ++i) { bool ok = false; int tempVal = vertexStrings[i].toInt(&ok); if (!ok) throw DataFileException("non-integer item in Vertices text: " + vertexStrings[i]); if (tempVal < 0) throw DataFileException("negative value in Vertices"); vertices.push_back(tempVal); } haveVertices = true; } else if (name == "Weights") { if (haveWeights) throw DataFileException("multiple Weights elements in one BorderPart element"); QString vertexText = xml.readElementText();//errors on unexpected element if (xml.hasError()) throw DataFileException("XML parsing error in Weights: " + xml.errorString()); QStringList vertexStrings = vertexText.split(QRegExp("\\s+"), QString::SkipEmptyParts); int numItems = (int)vertexStrings.size(); if (numItems % 3 != 0) throw DataFileException("number of items in Weights element text is not a multiple of 3"); for (int i = 0; i < numItems; ++i) { bool ok = false; float tempVal = vertexStrings[i].toFloat(&ok); if (!ok) throw DataFileException("non-numeric item in Weights text: " + vertexStrings[i]); if (tempVal < 0.0f) { CaretLogWarning("negative value in Weights, set to zero"); tempVal = 0.0f; } weights.push_back(tempVal); } haveWeights = true; } else { throw DataFileException("unexpected element in BorderPart: " + name.toString()); } } } if (xml.hasError()) throw DataFileException("XML parsing error in BorderPart: " + xml.errorString()); CaretAssert(xml.isEndElement() && xml.name() == "BorderPart"); if (!haveVertices || !haveWeights) throw DataFileException("BorderPart missing required Vertices or Weights element"); if (vertices.size() != weights.size()) throw DataFileException("Vertices and Weights don't contain the same number of elements"); int numPoints = (int)vertices.size() / 3; for (int i = 0; i < numPoints; ++i) { int i3 = i * 3; CaretPointer myItem(new SurfaceProjectedItem());//because addPoint takes ownership of a raw pointer myItem->setStructure(StructureEnum::ALL);//HACK: placeholder because structure is a file attribute in v3, not a border attribute SurfaceProjectionBarycentric* myBary = myItem->getBarycentricProjection(); myBary->setTriangleNodes(vertices.data() + i3); myBary->setTriangleAreas(weights.data() + i3); myBary->setValid(true);//signed distance from surface iniializes to 0 addPoint(myItem.releasePointer()); } } connectome-workbench-1.4.2/src/Files/Border.h000066400000000000000000000153211360521144700210540ustar00rootroot00000000000000#ifndef __BORDER__H_ #define __BORDER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BorderException.h" #include "CaretObjectTracksModification.h" #include "StructureEnum.h" #include "XmlException.h" class QXmlStreamReader; class QXmlStreamWriter; namespace caret { class GroupAndNameHierarchyItem; class SurfaceFile; class SurfaceProjectedItem; class XmlWriter; class Border : public CaretObjectTracksModification { public: Border(); virtual ~Border(); Border(const Border& obj); Border& operator=(const Border& obj); static Border* newInstanceFromSurfaceNodes(const AString& borderName, const SurfaceFile* surfaceFile, std::vector& nodeIndices); virtual AString toString() const; void clear(); AString getName() const; void setName(const AString& name); AString getClassName() const; void setClassName(const AString& name); StructureEnum::Enum getStructure() const; void setStructure(const StructureEnum::Enum& structure); bool verifyAllPointsOnSameStructure() const; bool verifyForSurfaceNumberOfNodes(const int32_t& numNodes) const; int32_t getNumberOfPoints() const; const SurfaceProjectedItem* getPoint(const int32_t indx) const; SurfaceProjectedItem* getPoint(const int32_t indx); int32_t findPointIndexNearestXYZ(const SurfaceFile* surfaceFile, const float xyz[3], const float maximumDistance, float& distanceToNearestPointOut) const; void addPoint(SurfaceProjectedItem* point); void addPoints(const Border* border, const int32_t startPointIndex = -1, const int32_t pointCount = -1); bool isClosed() const; void setClosed(const bool& closed); void addPointsToCloseBorderWithGeodesic(const SurfaceFile* surfaceFile); void removeAllPoints(); void removePoint(const int32_t indx); void removeFirstPoint(); void removeLastPoint(); void replacePointsWithUndoSaving(const Border* border); void reverse(); void reviseExtendFromPointIndex(SurfaceFile* surfaceFile, const int32_t pointIndex, const Border* segment); void reviseExtendFromEnd(SurfaceFile* surfaceFile, const Border* segment); void reviseEraseFromEnd(SurfaceFile* surfaceFile, const Border* segment); void reviseReplaceSegment(SurfaceFile* surfaceFile, const Border* segment); void writeAsXML(XmlWriter& xmlWriter); void writeXML3(QXmlStreamWriter& xml) const; void readXML1(QXmlStreamReader& xml); void readXML3(QXmlStreamReader& xml); void setGroupNameSelectionItem(GroupAndNameHierarchyItem* item); const GroupAndNameHierarchyItem* getGroupNameSelectionItem() const; bool isClassRgbaValid() const; void setClassRgbaInvalid(); const float* getClassRgba() const; void getClassRgba(float rgba[4]) const; void setClassRgba(const float rgba[4]); bool isNameRgbaValid() const; void setNameRgbaInvalid(); const float* getNameRgba() const; void getNameRgba(float rgba[4]) const; void setNameRgba(const float rgba[4]); bool isUndoBorderValid() const; void undoLastBorderEditing(); static const AString XML_TAG_BORDER; static const AString XML_TAG_NAME; static const AString XML_TAG_CLASS_NAME; private: void copyHelperBorder(const Border& obj); void setNameOrClassModified(); float getSegmentLength(SurfaceFile* surfaceFile, const int32_t startPointIndex, const int32_t endPointIndex); void replacePoints(const Border* border); void saveBorderForUndoEditing(); AString m_name; AString m_className; std::vector m_points; bool m_closed; /** RGBA color component assigned to border's class name */ float m_classRgbaColor[4]; /** RGBA color components assigned to border's class name validity */ bool m_classRgbaColorValid; /** RGBA color components assigned to focus' name */ float m_nameRgbaColor[4]; /** RGBA color components assigned to focus' name validity */ bool m_nameRgbaColorValid; /** Selection status of this border in the group/name hierarchy */ GroupAndNameHierarchyItem* m_groupNameSelectionItem; /** * When "this" border is edited, a copy of "this" is placed into * this member so that the border can be restored if the editing * was not satisfactory. */ Border* m_copyOfBorderPriorToLastEditing; }; #ifdef __BORDER_DECLARE__ const AString Border::XML_TAG_BORDER = "Border"; const AString Border::XML_TAG_CLASS_NAME = "ClassName"; const AString Border::XML_TAG_NAME = "Name"; #endif // __BORDER_DECLARE__ } // namespace #endif //__BORDER__H_ connectome-workbench-1.4.2/src/Files/BorderException.cxx000066400000000000000000000034541360521144700233120ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BorderException.h" #include using namespace caret; /** * Constructor. * */ BorderException::BorderException() : CaretException() { this->initializeMembersBorderException(); } /** * Constructor. * * @param s Description of the exception. * */ BorderException::BorderException( const AString& s) : CaretException(s) { this->initializeMembersBorderException(); } /** * Copy Constructor. * @param e * Exception that is copied. */ BorderException::BorderException(const BorderException& e) : CaretException(e) { } /** * Assignment operator. * @param e * Exception that is copied. * @return * Copy of the exception. */ BorderException& BorderException::operator=(const BorderException& e) { if (this != &e) { CaretException::operator=(e); } return *this; } /** * Destructor */ BorderException::~BorderException() throw() { } void BorderException::initializeMembersBorderException() { } connectome-workbench-1.4.2/src/Files/BorderException.h000066400000000000000000000026461360521144700227410ustar00rootroot00000000000000#ifndef __BORDER_EXCEPTION_H__ #define __BORDER_EXCEPTION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretException.h" namespace caret { /** * An exception thrown during Border processing. */ class BorderException : public CaretException { public: BorderException(); BorderException(const AString& s); BorderException(const BorderException& e); BorderException& operator=(const BorderException& e); virtual ~BorderException() throw(); private: void initializeMembersBorderException(); }; } // namespace #endif // __BORDER_EXCEPTION_H__ connectome-workbench-1.4.2/src/Files/BorderFile.cxx000066400000000000000000002752271360521144700222440ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #define __BORDER_FILE_DECLARE__ #include "BorderFile.h" #undef __BORDER_FILE_DECLARE__ #include "Border.h" #include "BorderPointFromSearch.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "DataFileContentInformation.h" #include "DataFileException.h" #include "GroupAndNameHierarchyModel.h" #include "FileAdapter.h" #include "FileInformation.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "GiftiMetaData.h" #include "MathFunctions.h" #include "SurfaceFile.h" #include "SurfaceProjectedItem.h" #include "SurfaceProjectionBarycentric.h" #include "TextFile.h" #include "XmlAttributes.h" #include "XmlSaxParser.h" #include "XmlWriter.h" using namespace caret; using namespace std; /** * \class caret::BorderFile * \brief File containing borders. */ /** * Constructor. */ BorderFile::BorderFile() : CaretDataFile(DataFileTypeEnum::BORDER) { initializeBorderFile(); } /** * Destructor. */ BorderFile::~BorderFile() { delete m_classColorTable; delete m_nameColorTable; delete m_metadata; for (std::vector::iterator iter = m_borders.begin(); iter != m_borders.end(); iter++) { delete *iter; } m_borders.clear(); delete m_classNameHierarchy; } /** * Initialize members of a border file. */ void BorderFile::initializeBorderFile() { m_classColorTable = new GiftiLabelTable(); m_nameColorTable = new GiftiLabelTable(); m_classNameHierarchy = new GroupAndNameHierarchyModel(); m_metadata = new GiftiMetaData(); m_forceUpdateOfGroupAndNameHierarchy = true; m_structure = StructureEnum::ALL; m_numNodes = -1; } /** * Copy constructor. * @param obj * Object that is copied. */ BorderFile::BorderFile(const BorderFile& obj) : CaretDataFile(obj) { initializeBorderFile(); copyHelperBorderFile(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ BorderFile& BorderFile::operator=(const BorderFile& obj) { if (this != &obj) { clear(); CaretDataFile::operator=(obj); copyHelperBorderFile(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void BorderFile::copyHelperBorderFile(const BorderFile& obj) { *m_classColorTable = *obj.m_classColorTable; *m_nameColorTable = *obj.m_nameColorTable; if (m_classNameHierarchy != NULL) { delete m_classNameHierarchy; } m_classNameHierarchy = new GroupAndNameHierarchyModel(); *m_metadata = *obj.m_metadata; const int32_t numBorders = obj.getNumberOfBorders(); for (int32_t i = 0; i < numBorders; i++) { m_borders.push_back(new Border(*obj.getBorder(i))); } m_forceUpdateOfGroupAndNameHierarchy = true; setModified(); } /** * @return Is this border file empty (contains zero borders)? */ bool BorderFile::isEmpty() const { return m_borders.empty(); } /** * @return The structure for this file. */ StructureEnum::Enum BorderFile::getStructure() const { return m_structure; } /** * @return Structures of all borders. In most cases, this method * is equivalent to getStructure(). However, there are some older, * obsolete border files that contain borders for multiple structures * in which case this returns the structures for those borders such as * CORTEX_LEFT and CORTEX_RIGHT. */ std::vector BorderFile::getAllBorderStructures() const { std::set uniqueStructures; const int32_t numBorders = getNumberOfBorders(); for (int32_t i = 0; i < numBorders; i++) { uniqueStructures.insert(getBorder(i)->getStructure()); } std::vector structures(uniqueStructures.begin(), uniqueStructures.end()); return structures; } /** * Create new border files each of which contains a border for a single structure. * If there is not a border file name for for a structure, no file will be * produced for that file and it is not considered an error. * * @param singleStructureFileNames * Each 'pair' is the filename for a structure. * @param structureNumberOfNodes * Each pair is the number of nodes for a structure. This parameter is * optional and when available, is used to validate the barycentric * node indices in a border. * @param singleStructureBorderFilesOut * On output contains border files for each of the structures. * @param errorMessageOut * If unsuccessful will contain description of error(s). * @return * True if successful and all files were created, else false. */ bool BorderFile::splitIntoSingleStructureFiles(const std::map& singleStructureFileNames, const std::map& structureNumberOfNodes, std::vector& singleStructureBorderFilesOut, AString& errorMessageOut) const { singleStructureBorderFilesOut.clear(); errorMessageOut.clear(); /* * Create single structure border files. */ std::map structureBorderFiles; for (std::map::const_iterator nameIter = singleStructureFileNames.begin(); nameIter != singleStructureFileNames.end(); nameIter++) { const StructureEnum::Enum structure = nameIter->first; if (StructureEnum::isSingleStructure(structure)) { /* * Create the border file and set the structure */ BorderFile* borderFile = new BorderFile(); borderFile->setFileName(nameIter->second); borderFile->setStructure(structure); /* * Set number of nodes for border file (if available) */ const std::map::const_iterator structNumNodesIter = structureNumberOfNodes.find(structure); if (structNumNodesIter != structureNumberOfNodes.end()) { const int32_t numNodes = structNumNodesIter->second; borderFile->setNumberOfNodes(numNodes); } /* * Add to border file for each structure. */ structureBorderFiles.insert(std::make_pair(structure, borderFile)); } else { errorMessageOut.appendWithNewLine("Structure " + StructureEnum::toGuiName(structure) + " is not a 'single' type structure."); } } /* * Copy borders to the appropriate single-structure files. */ const int32_t numBorders = getNumberOfBorders(); for (int32_t i = 0; i < numBorders; i++) { const Border* border = getBorder(i); CaretAssert(border); const StructureEnum::Enum structure = border->getStructure(); /* * Find output file with same structure as this border */ std::map::iterator fileIter = structureBorderFiles.find(structure); if (fileIter != structureBorderFiles.end()) { if (border->verifyAllPointsOnSameStructure()) { /* * Surface number of nodes may be available */ int32_t surfaceNumberOfNodes = 0; const std::map::const_iterator structNumNodesIter = structureNumberOfNodes.find(structure); if (structNumNodesIter != structureNumberOfNodes.end()) { surfaceNumberOfNodes = structNumNodesIter->second; } /* * If possible verify border node indices valid for structure */ bool copyBorderFlag = false; if (surfaceNumberOfNodes > 0) { if (border->verifyForSurfaceNumberOfNodes(surfaceNumberOfNodes)) { copyBorderFlag = true; } else { errorMessageOut.appendWithNewLine("Border index=" + AString::number(i) + " name=" + border->getName() + " contains an incompatible number of nodes for structure " + StructureEnum::toGuiName(structure)); } } else { /* * Unable to verify number of nodes so assume okay */ copyBorderFlag = true; } if (copyBorderFlag) { Border* borderCopy = new Border(*border); fileIter->second->addBorder(borderCopy); const GiftiLabel* nameLabel = m_nameColorTable->getLabelBestMatching(border->getName()); fileIter->second->getNameColorTable()->addLabel(nameLabel); const GiftiLabel* classLabel = m_classColorTable->getLabelBestMatching(border->getClassName()); fileIter->second->getClassColorTable()->addLabel(classLabel); } } else { errorMessageOut.appendWithNewLine("Border index=" + AString::number(i) + " name=" + border->getName() + " is an invalid border that contains points on multiple structures"); } } } if (errorMessageOut.isEmpty()) { /* * Success: return the single structure border files that were created. */ for (std::map::iterator fileIter = structureBorderFiles.begin(); fileIter != structureBorderFiles.end(); fileIter++) { singleStructureBorderFilesOut.push_back(fileIter->second); } return true; } /* * Had an error so delete any single structure border files that were created. */ for (std::map::iterator fileIter = structureBorderFiles.begin(); fileIter != structureBorderFiles.end(); fileIter++) { delete fileIter->second; } return false; } /** * Set the structure for this file. * @param structure * New structure for this file. */ void BorderFile::setStructure(const StructureEnum::Enum structure) { if (m_structure == StructureEnum::ALL && m_borders.size() != 0) {//not really sure what this should do, so throw an error for now throw DataFileException(getFileName(), "attempt to set structure on multi-structure border file"); } int numBorders = (int)m_borders.size(); for (int i = 0; i < numBorders; ++i) { Border* thisBorder = m_borders[i]; int numPoints = thisBorder->getNumberOfPoints(); for (int j = 0; j < numPoints; ++j) { thisBorder->getPoint(j)->setStructure(structure); } } m_structure = structure; setModified(); } /** * @return Get access to the file's metadata. */ GiftiMetaData* BorderFile::getFileMetaData() { return m_metadata; } /** * @return Get access to unmodifiable file's metadata. */ const GiftiMetaData* BorderFile::getFileMetaData() const { return m_metadata; } /** * Clear the border file. */ void BorderFile::clear() { CaretDataFile::clear(); m_classNameHierarchy->clear(); m_classColorTable->clear(); m_nameColorTable->clear(); m_metadata->clear(); const int32_t numBorders = getNumberOfBorders(); for (int32_t i = 0; i < numBorders; i++) { delete m_borders[i]; } m_borders.clear(); m_structure = StructureEnum::ALL; m_numNodes = -1; m_borderMDKeys.clear(); m_borderMDValues.clear(); } int32_t BorderFile::getNumberOfNodes() const { if (m_structure == StructureEnum::ALL) return -1;//TSC: i think multi-structure should always return -1 return m_numNodes; } void BorderFile::setNumberOfNodes(const int32_t& numNodes) { if (numNodes < 1) { throw DataFileException(getFileName(), "attempt to set non-positive number of vertices on border file"); } int numBorders = (int)m_borders.size(); for (int i = 0; i < numBorders; ++i) { if (!m_borders[i]->verifyForSurfaceNumberOfNodes(numNodes)) { throw DataFileException(getFileName(), "cannot set border file number of vertices less than the vertices used by its borders"); } } m_numNodes = numNodes;//even if we are currently multi-structure, remember the number of nodes that was set setModified(); } /** * If the number of nodes is not valid, it may indicate an old border file * that allows borders from multiple structures. So, examine all of the * borders and if ALL of the borders resized on the same structure, set the * number of nodes. * * @param structureToNodeCount * A map containing the number of nodes for each valid structure. * @throw DataFileException * If a border is not valid for its corresponding structure * (meaning, a node index used by a border is greater than the * number of nodes in the corresponding structure). */ void BorderFile::updateNumberOfNodesIfSingleStructure(const std::map& structureToNodeCount) { if (getNumberOfNodes() > 0) { return; } const int32_t numBorders = getNumberOfBorders(); /* * Verify that all borders in this file are for the same structure */ bool allStructuresMatchFlag = true; StructureEnum::Enum firstBorderStructure = StructureEnum::INVALID; for (int32_t i = 0; i < numBorders; i++) { const StructureEnum::Enum structure = m_borders[i]->getStructure(); if (i == 0) { firstBorderStructure = structure; } else { if (structure != firstBorderStructure) { allStructuresMatchFlag = false; break; } } } /* * If all of the borders in this file are for the same structure, * see if the number of nodes is available for the structure, and if so, * set the number of borders for the file. */ if (allStructuresMatchFlag) { if ((firstBorderStructure != StructureEnum::INVALID) && (firstBorderStructure != StructureEnum::ALL)) { const std::map::const_iterator iter = structureToNodeCount.find(firstBorderStructure); if (iter != structureToNodeCount.end()) { const int32_t numNodes = iter->second; setNumberOfNodes(numNodes); setStructure(firstBorderStructure); CaretLogInfo("Updated border file: " + getFileNameNoPath() + " structure=" + StructureEnum::toGuiName(firstBorderStructure) + " number-of-nodes=" + AString::number(numNodes)); } } } } /** * @return the number of borders. */ int32_t BorderFile::getNumberOfBorders() const { return m_borders.size(); } /** * Get the border at the given index. * @param indx * Index of the border. * @return * Border at the given index. */ Border* BorderFile::getBorder(const int32_t indx) { CaretAssertVectorIndex(m_borders, indx); return m_borders[indx]; } /** * Is the given border in this border file? * * @param border * The border being queried * @return * True if the border is in this file, else false. */ bool BorderFile::containsBorder(const Border* border) const { if (std::find(m_borders.begin(), m_borders.end(), border) != m_borders.end()) { return true; } return false; } /** * Get the border at the given index. * @param indx * Index of the border. * @return * Border at the given index. */ const Border* BorderFile::getBorder(const int32_t indx) const { CaretAssertVectorIndex(m_borders, indx); return m_borders[indx]; } /** * Find ALL borders that have one endpoint within the given distance * of the first point of the given border segment. * * @param displayGroup * Display group in which border is tested for display. * @param browserTabIndex * Tab index in which border is displayed. * @param surfaceFile * Surface file used for unprojection of border points. * @param borderSegment * The border segment. * @param maximumDistance * Maximum distance coordinate can be from a border point. * @param borderPointsOut * Contains result of search. */ void BorderFile::findAllBordersWithEndPointNearSegmentFirstPoint(const DisplayGroupEnum::Enum displayGroup, const int32_t browserTabIndex, const SurfaceFile* surfaceFile, const Border* borderSegment, const float maximumDistance, std::vector& borderPointsOut) const { CaretAssert(surfaceFile); CaretAssert(borderSegment); borderPointsOut.clear(); if (borderSegment->getNumberOfPoints() < 2) { return; } float segFirstXYZ[3]; if (! borderSegment->getPoint(0)->getProjectedPosition(*surfaceFile, segFirstXYZ, false)) { /* * Point did not unproject */ return; } BorderFile* nonConstBorderFile = const_cast(this); const int32_t numBorders = getNumberOfBorders(); for (int32_t borderIndex = 0; borderIndex < numBorders; borderIndex++) { Border* border = m_borders[borderIndex]; if (nonConstBorderFile->isBorderDisplayed(displayGroup, browserTabIndex, border) == false) { continue; } if (border->getStructure() == surfaceFile->getStructure()) { /* * Test first endpoint */ const int32_t numPoints = border->getNumberOfPoints(); float nearestPointDistanceSquared = -1.0; int32_t neartestPointIndex = -1; if (numPoints > 0) { float pointXYZ[3]; if (border->getPoint(0)->getProjectedPosition(*surfaceFile, pointXYZ, false)) { nearestPointDistanceSquared = MathFunctions::distanceSquared3D(pointXYZ, segFirstXYZ); neartestPointIndex = 0; } } /* * Test last endpoint */ if (numPoints > 1) { const int32_t lastPointIndex = numPoints - 1; float pointXYZ[3]; if (border->getPoint(lastPointIndex)->getProjectedPosition(*surfaceFile, pointXYZ, false)) { const float dist2 = MathFunctions::distanceSquared3D(pointXYZ, segFirstXYZ); if (nearestPointDistanceSquared >= 0.0) { if (dist2 < nearestPointDistanceSquared) { neartestPointIndex = lastPointIndex; nearestPointDistanceSquared = dist2; } } else { neartestPointIndex = lastPointIndex; nearestPointDistanceSquared = dist2; } } } if (neartestPointIndex >= 0) { const float nearestPointDistance = std::sqrt(nearestPointDistanceSquared); if (nearestPointDistance <= maximumDistance) { BorderPointFromSearch bpo; bpo.setData(const_cast(this), border, borderIndex, neartestPointIndex, nearestPointDistance); borderPointsOut.push_back(bpo); } } } } } /** * Find ALL borders that have any point within the given distance * of the first point of the given border segment. * * @param displayGroup * Display group in which border is tested for display. * @param browserTabIndex * Tab index in which border is displayed. * @param surfaceFile * Surface file used for unprojection of border points. * @param borderSegment * The border segment. * @param maximumDistance * Maximum distance coordinate can be from a border point. * @param borderPointsOut * Contains result of search. */ void BorderFile::findAllBordersWithAnyPointNearSegmentFirstPoint(const DisplayGroupEnum::Enum displayGroup, const int32_t browserTabIndex, const SurfaceFile* surfaceFile, const Border* borderSegment, const float maximumDistance, std::vector& borderPointsOut) const { CaretAssert(surfaceFile); CaretAssert(borderSegment); borderPointsOut.clear(); if (borderSegment->getNumberOfPoints() < 2) { return; } float segFirstXYZ[3]; if (! borderSegment->getPoint(0)->getProjectedPosition(*surfaceFile, segFirstXYZ, false)) { /* * Point did not unproject */ return; } BorderFile* nonConstBorderFile = const_cast(this); const int32_t numBorders = getNumberOfBorders(); for (int32_t borderIndex = 0; borderIndex < numBorders; borderIndex++) { Border* border = m_borders[borderIndex]; if (nonConstBorderFile->isBorderDisplayed(displayGroup, browserTabIndex, border) == false) { continue; } if (border->getStructure() == surfaceFile->getStructure()) { /* * Test all points */ float nearestPointDistanceSquared = std::numeric_limits::max(); int32_t nearestPointIndex = -1; const int32_t numPoints = border->getNumberOfPoints(); for (int32_t pointIndex = 0; pointIndex < numPoints; pointIndex++) { float pointXYZ[3]; if (border->getPoint(pointIndex)->getProjectedPosition(*surfaceFile, pointXYZ, false)) { const float distSQ = MathFunctions::distanceSquared3D(pointXYZ, segFirstXYZ); if (distSQ < nearestPointDistanceSquared) { nearestPointDistanceSquared = distSQ; nearestPointIndex = pointIndex; } } } if (nearestPointIndex >= 0) { const float nearestPointDistance = std::sqrt(nearestPointDistanceSquared); if (nearestPointDistance <= maximumDistance) { BorderPointFromSearch bpo; bpo.setData(const_cast(this), border, borderIndex, nearestPointIndex, nearestPointDistance); borderPointsOut.push_back(bpo); } } } } } /** * Find ALL borders that have ANY points within the given distance * of the two given coordinates. * * @param displayGroup * Display group in which border is tested for display. * @param browserTabIndex * Tab index in which border is displayed. * @param surfaceFile * Surface file used for unprojection of border points. * @param borderSegment * The border segment. * @param maximumDistance * Maximum distance coordinate can be from a border point. * @param borderPointsOut * Contains result of search. */ void BorderFile::findAllBordersWithPointsNearBothSegmentEndPoints(const DisplayGroupEnum::Enum displayGroup, const int32_t browserTabIndex, const SurfaceFile* surfaceFile, const Border* borderSegment, const float maximumDistance, std::vector& borderPointsOut) const { CaretAssert(surfaceFile); CaretAssert(borderSegment); borderPointsOut.clear(); if (borderSegment->getNumberOfPoints() < 2) { return; } float segFirstXYZ[3], segLastXYZ[3]; const int32_t segLpIndex = borderSegment->getNumberOfPoints() - 1; if (borderSegment->getPoint(0)->getProjectedPosition(*surfaceFile, segFirstXYZ, false) && borderSegment->getPoint(segLpIndex)->getProjectedPosition(*surfaceFile, segLastXYZ, false)) { /* OK - both points have valid coordinates */ } else { /* One or both points failed to project */ return; } BorderFile* nonConstBorderFile = const_cast(this); const int32_t numBorders = getNumberOfBorders(); for (int32_t borderIndex = 0; borderIndex < numBorders; borderIndex++) { Border* border = m_borders[borderIndex]; if (nonConstBorderFile->isBorderDisplayed(displayGroup, browserTabIndex, border) == false) { continue; } if (border->getStructure() == surfaceFile->getStructure()) { /* * Test first query point */ float distance1 = 0.0; const int32_t nearestIndex1 = border->findPointIndexNearestXYZ(surfaceFile, segFirstXYZ, maximumDistance, distance1); float distance2 = 0.0; const int32_t nearestIndex2 = border->findPointIndexNearestXYZ(surfaceFile, segLastXYZ, maximumDistance, distance2); if ((nearestIndex1 >= 0) && (nearestIndex2 >= 0)) { const float averageDistance = (distance1 + distance2) / 2.0; BorderPointFromSearch bpo; bpo.setData(const_cast(this), border, borderIndex, nearestIndex1, averageDistance); borderPointsOut.push_back(bpo); } } } } /** * Find ALL borders that have ANY points within the given * region of interest. Since all borders are projected to * the surface, * * @param displayGroup * Display group in which border is tested for display. * @param browserTabIndex * Tab index in which border is displayed. * @param surfaceFile * Surface file used for unprojection of border points. * @param nodesInROI * Indices if a node is inside (true) or outside (false) the ROI. * Number of elements MUST BE the number of nodes in the surface. * @param insideCountAndBorderOut * Output vector pair with first being number of border points inside the ROI and * and second is the corresponding border. */ void BorderFile::findBordersInsideRegionOfInterest(const DisplayGroupEnum::Enum displayGroup, const int32_t browserTabIndex, const SurfaceFile* surfaceFile, const std::vector& nodesInROI, std::vector >& insideCountAndBorderOut) const { CaretAssert(surfaceFile); CaretAssert(surfaceFile->getNumberOfNodes() == static_cast(nodesInROI.size())); insideCountAndBorderOut.clear(); const StructureEnum::Enum surfaceStructure = surfaceFile->getStructure(); BorderFile* nonConstBorderFile = const_cast(this); const int32_t numBorders = getNumberOfBorders(); for (int32_t borderIndex = 0; borderIndex < numBorders; borderIndex++) { Border* border = m_borders[borderIndex]; if (nonConstBorderFile->isBorderDisplayed(displayGroup, browserTabIndex, border) == false) { continue; } if (border->getStructure() == surfaceStructure) { // const int32_t numberOfPoints = border->getNumberOfPoints(); // for (int32_t iPoint = 0; iPoint < numberOfPoints; iPoint++) { // const SurfaceProjectedItem* spi = border->getPoint(iPoint); // CaretAssert(spi); // const SurfaceProjectionBarycentric* bary = spi->getBarycentricProjection(); // if (bary != NULL) { // const int32_t* pointNodes = bary->getTriangleNodes(); // const int32_t p1 = pointNodes[0]; // const int32_t p2 = pointNodes[1]; // const int32_t p3 = pointNodes[2]; // if ((p1 < surfaceNumberOfNodes) // && (p2 < surfaceNumberOfNodes) // && (p3 < surfaceNumberOfNodes)) { // if (nodesInROI[p1] // || nodesInROI[p2] // || nodesInROI[p3]) { // bordersOut.push_back(border); // break; // } // } // } // } /* * Get all node indices from the border * Note that the node indices may be used by more than one border point barycentric projection * so first get all UNIQUE node indices that are used by the border points */ std::set borderNodeIndicesInsideROI; const int32_t numberOfPoints = border->getNumberOfPoints(); for (int32_t iPoint = 0; iPoint < numberOfPoints; iPoint++) { const SurfaceProjectedItem* spi = border->getPoint(iPoint); CaretAssert(spi); const SurfaceProjectionBarycentric* bary = spi->getBarycentricProjection(); if (bary != NULL) { const int32_t* pointNodes = bary->getTriangleNodes(); borderNodeIndicesInsideROI.insert(pointNodes[0]); borderNodeIndicesInsideROI.insert(pointNodes[1]); borderNodeIndicesInsideROI.insert(pointNodes[2]); } } int32_t borderNodesInsideROICount = 0; for (std::set::iterator iter = borderNodeIndicesInsideROI.begin(); iter != borderNodeIndicesInsideROI.end(); iter++) { const int32_t nodeIndex = *iter; CaretAssertVectorIndex(nodesInROI, nodeIndex); if (nodesInROI[nodeIndex]) { borderNodesInsideROICount++; } } if (borderNodesInsideROICount > 0) { insideCountAndBorderOut.push_back(std::make_pair(borderNodesInsideROICount, border)); } } } } /** * Add a border. NOTE: This border file * takes ownership of the 'border' and * will handle deleting it. After calling * this method, the caller must never * do anything with the border that was passed * to this method. * * @param border * Border added to this border file. */ void BorderFile::addBorder(Border* border) { int numPoints = border->getNumberOfPoints(); if (numPoints == 0) { delete border;//keep our word and handle deleting the argument throw DataFileException(getFileName(), "attempt to add border with zero points"); }//NOTE: Border itself makes sure all points are on one structure, and have barycentric projections if (m_borders.empty())//TSC: i'm not actually sure if we want border files to automatically set their structure from the borders { m_structure = border->getStructure(); } else { if (m_structure != StructureEnum::ALL && m_structure != border->getPoint(0)->getStructure()) { m_structure = StructureEnum::ALL; } } if (m_numNodes != -1) { if (!border->verifyForSurfaceNumberOfNodes(m_numNodes)) { delete border; throw DataFileException(getFileName(), "attempt to add border that has too large vertex indices for surface"); } } m_borders.push_back(border); // DO NOT WANT to add entries to name and class tables when the names are // not an exact match as partial matches are acceptable. // const AString name = border->getName(); // if (name.isEmpty() == false) { // const int32_t nameColorKey = m_nameColorTable->getLabelKeyFromName(name); // if (nameColorKey < 0) { // m_nameColorTable->addLabel(name, 0.0f, 0.0f, 0.0f, 1.0f); // } // } // const AString className = border->getClassName(); // if (className.isEmpty() == false) { // const int32_t classColorKey = m_classColorTable->getLabelKeyFromName(className); // if (classColorKey < 0) { // m_classColorTable->addLabel(className, 0.0f, 0.0f, 0.0f, 1.0f); // } // } m_forceUpdateOfGroupAndNameHierarchy = true; setModified(); } /** * Remove the border at the given index. * @param indx * Index of border for removal. */ void BorderFile::removeBorder(const int32_t indx) { CaretAssertVectorIndex(m_borders, indx); Border* border = getBorder(indx); m_borders.erase(m_borders.begin() + indx); delete border; if (m_structure == StructureEnum::ALL) { int numBorders = (int)m_borders.size(); bool singleStructure = true; for (int i = 1; i < numBorders; ++i) { if (m_borders[i]->getStructure() != m_borders[0]->getStructure()) { singleStructure = false; break; } } if (singleStructure) { if (numBorders != 0)//have it remember its structure when the last border is removed { m_structure = m_borders[0]->getStructure(); } } } m_forceUpdateOfGroupAndNameHierarchy = true; setModified(); } /** * Remove the border. * @param border * Border that will be removed and DELETED. */ void BorderFile::removeBorder(Border* border) { const int32_t numBorders = getNumberOfBorders(); for (int32_t i = 0;i < numBorders; i++) { if (m_borders[i] == border) { removeBorder(i); return; } } CaretLogWarning("Attempting to delete border not in border file with name: " + border->getName()); } /** * Is the given border, that MUST be in this file, displayed? * @param displayGroup * Display group in which border is tested for display. * @param browserTabIndex * Tab index in which border is displayed. * @param border * Border that is tested to see if it is displayed. * @return * true if border is displayed, else false. */ bool BorderFile::isBorderDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t browserTabIndex, const Border* border) { const GroupAndNameHierarchyItem* selectionItem = border->getGroupNameSelectionItem(); if (selectionItem != NULL) { if (selectionItem->isSelected(displayGroup, browserTabIndex) == false) { return false; } } return true; } /** * @return The class and name hierarchy. */ GroupAndNameHierarchyModel* BorderFile::getGroupAndNameHierarchyModel() { m_classNameHierarchy->update(this, m_forceUpdateOfGroupAndNameHierarchy); m_forceUpdateOfGroupAndNameHierarchy = false; return m_classNameHierarchy; } /** * @return The class color table. */ GiftiLabelTable* BorderFile::getClassColorTable() { return m_classColorTable; } /** * @return The class color table. */ const GiftiLabelTable* BorderFile::getClassColorTable() const { return m_classColorTable; } /** * @return The name color table. */ GiftiLabelTable* BorderFile::getNameColorTable() { return m_nameColorTable; } /** * @return The name color table. */ const GiftiLabelTable* BorderFile::getNameColorTable() const { return m_nameColorTable; } int BorderFile::getIndexForBorderMetadataKey(const AString& key) const { for (int i = 0; i < (int)m_borderMDKeys.size(); ++i)//for now, the dumb way, we don't expect hundreds of keys - can speed it up with a secondary map if needed { if (m_borderMDKeys[i] == key) return i;//NOTE: if we use a second structure to speed this up, make sure parseBorderMDNames3 also updates it! } return -1; } const AString& BorderFile::getBorderMetadataKey(const int& index) const { CaretAssert(index >= 0 && index < (int)m_borderMDKeys.size()); return m_borderMDKeys[index]; } int BorderFile::addBorderMetadataKey(const AString& key) { int checkKey = getIndexForBorderMetadataKey(key); if (checkKey != -1) return checkKey; m_borderMDKeys.push_back(key);//NOTE: if we use a second structure to speed this up, make sure parseBorderMDNames3 also updates it! for (map, vector >::iterator iter = m_borderMDValues.begin(); iter != m_borderMDValues.end(); ++iter) { iter->second.push_back(AString()); CaretAssert(iter->second.size() == m_borderMDKeys.size()); } setModified(); return m_borderMDKeys.size() - 1; } void BorderFile::removeBorderMetadataKey(const int& index) { CaretAssert(index >= 0 && index < (int)m_borderMDKeys.size()); m_borderMDKeys.erase(m_borderMDKeys.begin() + index); for (map, vector >::iterator iter = m_borderMDValues.begin(); iter != m_borderMDValues.end(); ++iter) { iter->second.erase(iter->second.begin() + index); CaretAssert(iter->second.size() == m_borderMDKeys.size()); } setModified(); } void BorderFile::clearBorderMetaData() { m_borderMDKeys.clear(); m_borderMDValues.clear(); } AString BorderFile::getBorderMetadataValue(const AString& name, const AString& className, const int& index) const { CaretAssert(index >= 0 && index < (int)m_borderMDKeys.size()); map, vector >::const_iterator iter = m_borderMDValues.find(make_pair(name, className)); if (iter == m_borderMDValues.end()) return AString(); CaretAssert(iter->second.size() == m_borderMDKeys.size()); return iter->second[index]; } void BorderFile::setBorderMetadataValue(const AString& name, const AString& className, const int& index, const AString& value) { CaretAssert(index >= 0 && index < (int)m_borderMDKeys.size()); //TODO: check if such a border actually exists? maybe not needed map, vector >::iterator iter = m_borderMDValues.find(make_pair(name, className)); if (iter == m_borderMDValues.end()) { if (value == "") return;//don't create the metadata values array if we only store the empty string iter = m_borderMDValues.insert(make_pair(make_pair(name, className), vector(m_borderMDKeys.size()))).first; } CaretAssert(iter->second.size() == m_borderMDKeys.size()); iter->second[index] = value; setModified(); } /** * Version 1 foci files contained one color table for both names * and classes. Newer versions of the foci file keep them in * separate tables. * * @param oldColorTable * Old color table that is split into name and class color tables. */ void BorderFile::createNameAndClassColorTables(const GiftiLabelTable* oldColorTable) { CaretAssert(oldColorTable); m_classColorTable->clear(); m_nameColorTable->clear(); std::set nameSet; std::set classSet; const int numBorders = getNumberOfBorders(); for (int32_t i = 0; i < numBorders; i++) { const Border* border = getBorder(i); nameSet.insert(border->getName()); classSet.insert(border->getClassName()); } /* * Create colors for only the "best matching" color. */ for (std::set::iterator iter = nameSet.begin(); iter != nameSet.end(); iter++) { const AString colorName = *iter; const GiftiLabel* oldLabel = oldColorTable->getLabelBestMatching(colorName); if (oldLabel != NULL) { const AString bestMatchingName = oldLabel->getName(); const int32_t labelKey = m_nameColorTable->getLabelKeyFromName(bestMatchingName); if (labelKey < 0) { float rgba[4] = { 0.0, 0.0, 0.0, 1.0 }; oldLabel->getColor(rgba); m_nameColorTable->addLabel(bestMatchingName, rgba[0], rgba[1], rgba[2], rgba[3]); } } } /* * Create a color for each class name using the best matching color */ for (std::set::iterator iter = classSet.begin(); iter != classSet.end(); iter++) { const AString colorName = *iter; const GiftiLabel* label = oldColorTable->getLabelBestMatching(colorName); float rgba[4] = { 0.0, 0.0, 0.0, 1.0 }; if (label != NULL) { label->getColor(rgba); } m_classColorTable->addLabel(colorName, rgba[0], rgba[1], rgba[2], rgba[3]); } } /** * @return A string list containing all border names * sorted in alphabetical order. */ QStringList BorderFile::getAllBorderNamesSorted() const { std::set nameSet; const int32_t numFoci = getNumberOfBorders(); for (int32_t i = 0;i < numFoci; i++) { nameSet.insert(m_borders[i]->getName()); } QStringList sl; for (std::set::iterator iter = nameSet.begin(); iter != nameSet.end(); iter++) { sl += *iter; } return sl; } /** * Invalidate all assigned colors. */ void BorderFile::invalidateAllAssignedColors() { const int32_t numBorders = getNumberOfBorders(); for (int32_t i = 0; i < numBorders; i++) { m_borders[i]->setClassRgbaInvalid(); m_borders[i]->setNameRgbaInvalid(); } m_forceUpdateOfGroupAndNameHierarchy = true; } /** * @return The version of the file as a number. */ int32_t BorderFile::getFileVersion() { return s_borderFileVersion; } /** * @return The version of the file as a string. */ AString BorderFile::getFileVersionAsString() { return AString::number(s_borderFileVersion); } /** * Read the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully read. */ void BorderFile::readFile(const AString& filename) { clear(); checkFileReadability(filename); setFileName(filename); { QFile inFile(filename); if (!inFile.open(QIODevice::ReadOnly)) throw DataFileException(filename, "failed to open file for reading"); QXmlStreamReader myReader(&inFile); readXML(myReader); } /*BorderFileSaxReader saxReader(this); std::unique_ptr parser(XmlSaxParser::createXmlParser()); try { parser->parseFile(filename, &saxReader); } catch (const XmlSaxParserException& e) { clear(); setFileName(""); int lineNum = e.getLineNumber(); int colNum = e.getColumnNumber(); AString msg = "Parse Error while reading " + filename; if ((lineNum >= 0) && (colNum >= 0)) { msg += (" line/col (" + AString::number(e.getLineNumber()) + "/" + AString::number(e.getColumnNumber()) + ")"); } msg += (": " + e.whatString()); DataFileException dfe(msg); CaretLogThrowing(dfe); throw dfe; }//*/ setFileName(filename); m_classNameHierarchy->update(this, true); m_forceUpdateOfGroupAndNameHierarchy = false; m_classNameHierarchy->setAllSelected(true); CaretLogFiner("CLASS/NAME Table for : " + getFileNameNoPath() + "\n" + m_classNameHierarchy->toString()); clearModified(); } /** * Write the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully written. */ void BorderFile::writeFile(const AString& filename) { if (canWriteAsVersion(3)) { writeFile(filename, 3); } else { CaretLogWarning("border file missing information required for writing as version 3, falling back to older format"); writeFile(filename, 1); } } /** * @return Error message for attempting a gui operation on an obsolete, multi-structure border file. */ AString BorderFile::getObsoleteMultiStructureFormatMessage() { return ("This border file (" + getFileNameNoPath() + ") contains borders for multiple structures and must be split into single-structure border files. " "This can be done in the gui, using a selection in the Data menu, " "or on the command line using -file-convert with the -border-version-convert option."); } void BorderFile::writeFile(const AString& filename, const int& version) { if ( ! isSingleStructure()) { throw DataFileException(filename, "Writing multi-structure border files is no longer supported. " "Any existing multi-structure border files should be split into single-structure border files. " "This can be done on the command line using -file-convert with the -border-version-convert option, " "or in the gui, using a selection in the Data menu."); } if (!canWriteAsVersion(version)) throw DataFileException(filename, "cannot write border file as version '" + AString::number(version) + "'"); if (!(filename.endsWith(".border") || filename.endsWith(".wb_border"))) { CaretLogWarning("border file '" + filename + "' should be saved ending in .border"); } checkFileWritability(filename); setFileName(filename); QFile::remove(filename);//delete it if it exists, to play better with file symlinks switch (version) { case 3: { QFile myFile(filename); if (!myFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) throw DataFileException(filename, "could not open for writing"); QXmlStreamWriter myXML(&myFile); myXML.setAutoFormatting(true); writeVersion3(myXML); break; } case 1: { // // Format the version string so that it ends with at most one zero // const AString versionString = AString::number(1.0); // // Open the file // FileAdapter file; AString errorMessage; QTextStream* textStream = file.openQTextStreamForWritingFile(getFileName(), errorMessage); if (textStream == NULL) { throw DataFileException(getFileName(), errorMessage); } // // Create the xml writer // XmlWriter xmlWriter(*textStream); // // Write header info // xmlWriter.writeStartDocument("1.0"); // // Write GIFTI root element // XmlAttributes attributes; //attributes.addAttribute("xmlns:xsi", // "http://www.w3.org/2001/XMLSchema-instance"); //attributes.addAttribute("xsi:noNamespaceSchemaLocation", // "http://brainvis.wustl.edu/caret6/xml_schemas/GIFTI_Caret.xsd"); attributes.addAttribute(BorderFile::XML_ATTRIBUTE_VERSION, versionString); xmlWriter.writeStartElement(BorderFile::XML_TAG_BORDER_FILE, attributes); // // Write Metadata // if (m_metadata != NULL) { m_metadata->writeAsXML(xmlWriter); } // // Write the class color table // xmlWriter.writeStartElement(XML_TAG_CLASS_COLOR_TABLE); m_classColorTable->writeAsXML(xmlWriter); xmlWriter.writeEndElement(); // // Write the name color table // xmlWriter.writeStartElement(XML_TAG_NAME_COLOR_TABLE); m_nameColorTable->writeAsXML(xmlWriter); xmlWriter.writeEndElement(); // // Write borders // const int32_t numBorders = getNumberOfBorders(); for (int32_t i = 0; i < numBorders; i++) { if (m_borders[i]->getNumberOfPoints() < 1) { CaretLogWarning("skipped writing zero-point border: '" + m_borders[i]->getName() + "'"); continue; } m_borders[i]->writeAsXML(xmlWriter); } xmlWriter.writeEndElement(); xmlWriter.writeEndDocument(); file.close(); break; } default: CaretAssertMessage(0, "unimplemented writer for claimed supported version"); break; } clearModified(); } bool BorderFile::canWriteAsVersion(const int& version) const { switch (version) { case 1: return true; case 3: if (!StructureEnum::isSingleStructure(m_structure)) return false; if (m_numNodes == -1) return false; return true; default: return false; } } void BorderFile::writeVersion3(QXmlStreamWriter& output) const { CaretAssert(canWriteAsVersion(3));//if this function is made public, this should also throw output.writeStartDocument(); output.writeStartElement("BorderFile"); output.writeAttribute("Version", "3"); output.writeAttribute("Structure", StructureEnum::toName(m_structure)); output.writeAttribute("SurfaceNumberOfVertices", AString::number(m_numNodes)); m_metadata->writeBorderFileXML3(output); int numBorderMDKeys = (int)m_borderMDKeys.size(); if (numBorderMDKeys > 0) { output.writeStartElement("BorderMetaDataNames"); for (int i = 0; i < numBorderMDKeys; ++i) { output.writeStartElement("Name"); output.writeCharacters(m_borderMDKeys[i]);//CDATA? output.writeEndElement(); } output.writeEndElement(); } int numBorders = getNumberOfBorders(); vector used(numBorders, false);//multi-part border behavior for (int i = 0; i < numBorders; ++i) { if (used[i]) continue; const Border* classBorder = getBorder(i); AString thisClass = classBorder->getClassName();//hierarchical representation in file output.writeStartElement("Class"); output.writeAttribute("Name", thisClass); writeColorHelper(output, getClassColorTable()->getLabelBestMatching(thisClass)); //writeColorHelper(output, getClassColorTable()->getLabel(thisClass)); for (int j = i; j < numBorders; ++j) { if (used[j]) continue; const Border* nameBorder = getBorder(j); if (nameBorder->getClassName() == thisClass) { AString thisName = nameBorder->getName();//multipart borders output.writeStartElement("Border"); output.writeAttribute("Name", thisName); writeColorHelper(output, getNameColorTable()->getLabelBestMatching(thisName)); //writeColorHelper(output, getNameColorTable()->getLabel(thisName)); map, vector >::const_iterator iter = m_borderMDValues.find(make_pair(thisName, thisClass)); if (iter != m_borderMDValues.end()) { CaretAssert(iter->second.size() == m_borderMDKeys.size()); output.writeStartElement("BorderMetaDataValues"); for (int k = 0; k < (int)m_borderMDKeys.size(); ++k) { output.writeStartElement("Value"); output.writeCharacters(iter->second[k]);//CDATA? output.writeEndElement(); } output.writeEndElement(); } for (int k = j; k < numBorders; ++k) { if (used[k]) continue; const Border* thisBorder = getBorder(k); if (thisBorder->getNumberOfPoints() < 1) { used[k] = true; CaretLogWarning("skipped writing zero-point border: '" + thisBorder->getName() + "'"); continue; } if (thisBorder->getName() == thisName && thisBorder->getClassName() == thisClass) { used[k] = true; thisBorder->writeXML3(output); } } output.writeEndElement();//Border } } output.writeEndElement();//Class } output.writeEndElement();//BorderFile } void BorderFile::writeColorHelper(QXmlStreamWriter& output, const GiftiLabel* colorLabel) const { if (colorLabel == NULL)//default to black if we somehow have no color { output.writeAttribute("Red", AString::number(0.0f)); output.writeAttribute("Green", AString::number(0.0f)); output.writeAttribute("Blue", AString::number(0.0f)); } else { output.writeAttribute("Red", AString::number(colorLabel->getRed())); output.writeAttribute("Green", AString::number(colorLabel->getGreen())); output.writeAttribute("Blue", AString::number(colorLabel->getBlue())); } } void BorderFile::readXML(QXmlStreamReader& xml) { clear(); bool haveRoot = false; while (!xml.atEnd()) { switch(xml.tokenType()) { case QXmlStreamReader::StartElement: { if (xml.name() != "BorderFile") throw DataFileException(getFileName(), "unexpected root element: " + xml.name().toString()); if (haveRoot) throw DataFileException(getFileName(), "multiple BorderFile elements in one file"); QXmlStreamAttributes myAttrs = xml.attributes(); if (!myAttrs.hasAttribute("Version")) throw DataFileException(getFileName(), "missing required attribute Version of element BorderFile"); QStringRef versionStr = myAttrs.value("Version"); if (versionStr == "1" || versionStr == "1.0") { parseBorderFile1(xml); } else if (versionStr == "3") { parseBorderFile3(xml); } else { throw DataFileException(getFileName(), "unrecognized border file version: " + versionStr.toString()); } haveRoot = true; break; } default: break; } xml.readNext(); } if (xml.hasError()) throw DataFileException(getFileName(), "XML parsing error in root of border file: " + xml.errorString()); if (!haveRoot) throw DataFileException(getFileName(), "BorderFile root element not found"); clearModified(); } void BorderFile::parseBorderFile1(QXmlStreamReader& xml) { CaretAssert(xml.isStartElement() && xml.name() == "BorderFile"); bool haveSingleTable = false, haveClassTable = false, haveNameTable = false; GiftiLabelTable singleTable; for (xml.readNext(); !xml.atEnd() && !xml.isEndElement(); xml.readNext()) { switch(xml.tokenType()) { case QXmlStreamReader::StartElement: { QStringRef name = xml.name(); if (name == "MetaData") { m_metadata->readBorderFileXML1(xml); if (xml.hasError()) throw DataFileException(getFileName(), "XML parsing error in MetaData: " + xml.errorString()); } else if (name == "BorderClassColorTable") { if (haveSingleTable) throw DataFileException(getFileName(), "file has both single-table and split-table coloring information"); if (haveClassTable) throw DataFileException(getFileName(), "file has multiple BorderClassColorTable elements"); if (!xml.readNextStartElement()) { if (xml.hasError()) throw DataFileException(getFileName(), "XML parsing error in BorderClassColorTable: " + xml.errorString()); throw DataFileException(getFileName(), "empty BorderClassColorTable found"); } m_classColorTable->readFromQXmlStreamReader(xml); xml.readNextStartElement();//find the end element of BorderClassColorTable if (xml.hasError()) throw DataFileException(getFileName(), "XML parsing error in BorderClassColorTable: " + xml.errorString()); haveClassTable = true; } else if (name == "BorderNameColorTable") { if (haveSingleTable) throw DataFileException(getFileName(), "file has both single-table and split-table coloring information"); if (haveNameTable) throw DataFileException(getFileName(), "file has multiple BorderNameColorTable elements"); if (!xml.readNextStartElement()) { if (xml.hasError()) throw DataFileException(getFileName(), "XML parsing error in BorderNameColorTable: " + xml.errorString()); throw DataFileException(getFileName(), "empty BorderNameColorTable found"); } m_nameColorTable->readFromQXmlStreamReader(xml); xml.readNextStartElement();//find the end element of BorderNameColorTable if (xml.hasError()) throw DataFileException(getFileName(), "XML parsing error in BorderNameColorTable: " + xml.errorString()); haveNameTable = true; } else if (name == "LabelTable") { if (haveNameTable || haveClassTable) throw DataFileException(getFileName(), "file has both single-table and split-table coloring information"); if (haveSingleTable) throw DataFileException(getFileName(), "file has multiple LabelTable elements"); singleTable.readFromQXmlStreamReader(xml); if (xml.hasError()) throw DataFileException(getFileName(), "XML parsing error in LabelTable: " + xml.errorString()); haveSingleTable = true; } else if (name == "Border") { CaretPointer toParse(new Border());//so throw can clean up, but we can also release the Border pointer toParse->readXML1(xml); if (toParse->getNumberOfPoints() > 0) { addBorder(toParse.releasePointer()); } else { CaretLogWarning("ignored border with zero points: '" + toParse->getName() + "'"); } } else { throw DataFileException(getFileName(), "unexpected element in BorderFile: " + name.toString()); } break; } default: break; } } if (haveSingleTable) { createNameAndClassColorTables(&singleTable); } if (xml.hasError()) throw DataFileException(getFileName(), "XML parsing error in BorderFile: " + xml.errorString()); CaretAssert(xml.isEndElement() && xml.name() == "BorderFile"); if (!haveSingleTable && (!haveClassTable || !haveNameTable)) { throw DataFileException(getFileName(), "border file is missing a required color table"); } } void BorderFile::parseBorderFile3(QXmlStreamReader& xml) { CaretAssert(xml.isStartElement() && xml.name() == "BorderFile"); QXmlStreamAttributes myAttrs = xml.attributes(); bool ok = false; if (!myAttrs.hasAttribute("Structure")) throw DataFileException(getFileName(), "BorderFile is missing required attribute Structure"); StructureEnum::Enum myStructure = StructureEnum::fromName(myAttrs.value("Structure").toString(), &ok); if (!ok) throw DataFileException(getFileName(), "unrecognized structure: " + myAttrs.value("Structure").toString()); setStructure(myStructure); if (!myAttrs.hasAttribute("SurfaceNumberOfVertices")) throw DataFileException(getFileName(), "BorderFile is missing required attribute SurfaceNumberOfVertices"); int myNumNodes = myAttrs.value("SurfaceNumberOfVertices").toString().toInt(&ok); if (!ok) throw DataFileException(getFileName(), "non-integer number of vertices: " + myAttrs.value("SurfaceNumberOfVertices").toString()); if (myNumNodes < 1) throw DataFileException(getFileName(), "number of vertices too small: "); setNumberOfNodes(myNumNodes); bool haveFileMD = false, haveBorderMDNames = false; set classNames; for (xml.readNext(); !xml.atEnd() && !xml.isEndElement(); xml.readNext()) { if (xml.isStartElement()) { QStringRef name = xml.name(); if (name == "MetaData") { if (haveFileMD) throw DataFileException(getFileName(), "file has multiple MetaData elements"); m_metadata->readBorderFileXML3(xml); if (xml.hasError()) throw DataFileException(getFileName(), "XML parsing error in MetaData: " + xml.errorString()); haveFileMD = true; } else if (name == "BorderMetaDataNames") { if (haveBorderMDNames) throw DataFileException(getFileName(), "file has multiple BorderMetaDataNames elements"); parseBorderMDNames3(xml); haveBorderMDNames = true; } else if (name == "Class") { AString className = parseClass3(xml); if (!classNames.insert(className).second) throw DataFileException(getFileName(), "multiple classes using same name: " + className); } else { throw DataFileException(getFileName(), "unexpected element in BorderFile: " + name.toString()); } } } if (xml.hasError()) throw DataFileException(getFileName(), "XML parsing error in BorderFile: " + xml.errorString()); CaretAssert(xml.isEndElement() && xml.name() == "BorderFile"); for (map, vector >::const_iterator iter = m_borderMDValues.begin(); iter != m_borderMDValues.end(); ++iter) {//someone could put the BorderMetaDataNames after a class, so check at the very end if (iter->second.size() != m_borderMDKeys.size()) { throw DataFileException(getFileName(), "wrong number of border metadata values for border " + iter->first.first + ", class " + iter->first.second); } } } void BorderFile::parseBorderMDNames3(QXmlStreamReader& xml) { CaretAssert(xml.isStartElement() && xml.name() == "BorderMetaDataNames"); for (xml.readNext(); !xml.atEnd() && !xml.isEndElement(); xml.readNext()) { if (xml.isStartElement()) { QStringRef name = xml.name(); if (name == "Name") { QString mdName = xml.readElementText();//errors on unexpected element if (xml.hasError()) throw DataFileException(getFileName(), "XML parsing error in Name: " + xml.errorString()); int checkIndex = getIndexForBorderMetadataKey(mdName); if (checkIndex != -1) throw DataFileException(getFileName(), "duplicate border metadata name: " + mdName); m_borderMDKeys.push_back(mdName);//NOTE: do NOT use addBorderMetadataKey, as if there are borders with metadata before this, it will mess things up } else { throw DataFileException(getFileName(), "unexpected element in BorderMetaDataNames: " + name.toString()); } } } if (xml.hasError()) throw DataFileException(getFileName(), "XML parsing error in BorderMetaDataNames: " + xml.errorString()); CaretAssert(xml.isEndElement() && xml.name() == "BorderMetaDataNames"); } AString BorderFile::parseClass3(QXmlStreamReader& xml) { CaretAssert(xml.isStartElement() && xml.name() == "Class"); QXmlStreamAttributes myAttrs = xml.attributes(); if (!myAttrs.hasAttribute("Name")) throw DataFileException(getFileName(), "Class is missing required attribute Name"); AString className = myAttrs.value("Name").toString(); float colorRGB[3]; colorAttribHelper3(getFileName(), xml, colorRGB); m_classColorTable->addLabel(className, colorRGB[0], colorRGB[1], colorRGB[2]); set borderNames; for (xml.readNext(); !xml.atEnd() && !xml.isEndElement(); xml.readNext()) { if (xml.isStartElement()) { QStringRef name = xml.name(); if (name == "Border") { AString borderName = parseBorder3(xml, className); if (!borderNames.insert(borderName).second) throw DataFileException(getFileName(), "multiple borders in one class using same name: " + borderName); } else { throw DataFileException(getFileName(), "unexpected element in Class: " + name.toString()); } } } if (xml.hasError()) throw DataFileException(getFileName(), "XML parsing error in Class: " + xml.errorString()); CaretAssert(xml.isEndElement() && xml.name() == "Class"); if (borderNames.size() == 0) throw DataFileException(getFileName(), "Class " + className + " has no Border elements"); return className; } AString BorderFile::parseBorder3(QXmlStreamReader& xml, const AString& className) { CaretAssert(xml.isStartElement() && xml.name() == "Border"); bool haveMDValues = false; int numBorderParts = 0; QXmlStreamAttributes myAttrs = xml.attributes(); if (!myAttrs.hasAttribute("Name")) throw DataFileException(getFileName(), "Class is missing required attribute Name"); AString borderName = myAttrs.value("Name").toString(); float colorRGB[3]; colorAttribHelper3(getFileName(), xml, colorRGB); m_nameColorTable->addLabel(borderName, colorRGB[0], colorRGB[1], colorRGB[2]); for (xml.readNext(); !xml.atEnd() && !xml.isEndElement(); xml.readNext()) { if (xml.isStartElement()) { QStringRef name = xml.name(); if (name == "BorderPart") { CaretPointer thisBorder(new Border());//again, because the current interface/internals take ownership of raw pointers thisBorder->readXML3(xml); thisBorder->setStructure(getStructure()); thisBorder->setClassName(className); thisBorder->setName(borderName); if (!thisBorder->verifyForSurfaceNumberOfNodes(getNumberOfNodes())) throw DataFileException(getFileName(), "BorderPart uses node numbers larger than are valid for its surface"); if (thisBorder->getNumberOfPoints() > 0) { addBorder(thisBorder.releasePointer()); } else { CaretLogWarning("ignored border with zero points: '" + thisBorder->getName() + "'"); } ++numBorderParts; } else if (name == "BorderMetaDataValues") { if (haveMDValues) throw DataFileException(getFileName(), "Border has multiple BorderMetaDataValues elements"); m_borderMDValues[make_pair(borderName, className)] = parseBorderMDValues3(getFileName(), xml); haveMDValues = true; } else { throw DataFileException(getFileName(), "unexpected element in Border: " + name.toString()); } } } if (xml.hasError()) throw DataFileException(getFileName(), "XML parsing error in Border: " + xml.errorString()); CaretAssert(xml.isEndElement() && xml.name() == "Border"); if (numBorderParts == 0) throw DataFileException(getFileName(), "Border has no BorderPart elements"); return borderName; } void BorderFile::colorAttribHelper3(const AString& filename, QXmlStreamReader& xml, float rgbOut[3]) { QXmlStreamAttributes myAttrs = xml.attributes(); bool ok = false; if (!myAttrs.hasAttribute("Red")) throw DataFileException(filename, xml.name().toString() + " element missing required attribute Red"); rgbOut[0] = myAttrs.value("Red").toString().toFloat(&ok); if (!ok) throw DataFileException(filename, "non-numeric Red attribute of " + xml.name().toString() + ": " + myAttrs.value("Red").toString()); if (!myAttrs.hasAttribute("Green")) throw DataFileException(filename, xml.name().toString() + " element missing required attribute Green"); rgbOut[1] = myAttrs.value("Green").toString().toFloat(&ok); if (!ok) throw DataFileException(filename, "non-numeric Green attribute of " + xml.name().toString() + ": " + myAttrs.value("Green").toString()); if (!myAttrs.hasAttribute("Blue")) throw DataFileException(filename, xml.name().toString() + " element missing required attribute Blue"); rgbOut[2] = myAttrs.value("Blue").toString().toFloat(&ok); if (!ok) throw DataFileException(filename, "non-numeric Blue attribute of " + xml.name().toString() + ": " + myAttrs.value("Blue").toString()); } vector BorderFile::parseBorderMDValues3(const AString& filename, QXmlStreamReader& xml) { CaretAssert(xml.isStartElement() && xml.name() == "BorderMetaDataValues"); vector ret; for (xml.readNext(); !xml.atEnd() && !xml.isEndElement(); xml.readNext()) { if (xml.isStartElement()) { QStringRef name = xml.name(); if (name == "Value") { ret.push_back(xml.readElementText());//errors on unexpected element if (xml.hasError()) throw DataFileException(filename, "XML parsing error in BorderMetaDataValues: " + xml.errorString()); } else { throw DataFileException(filename, "unexpected element in BorderMetaDataValues: " + name.toString()); } } } if (xml.hasError()) throw DataFileException(filename, "XML parsing error in BorderMetaDataValues: " + xml.errorString()); CaretAssert(xml.isEndElement() && xml.name() == "BorderMetaDataValues"); return ret; } /** * @return Is this border file modified? */ bool BorderFile::isModified() const { if (CaretDataFile::isModified()) { return true; } if (m_metadata->isModified()) { return true; } if (m_classColorTable->isModified()) { return true; } if (m_nameColorTable->isModified()) { return true; } /* * Note, these members do not affect modification status: * classNameHierarchy */ const int32_t numBorders = getNumberOfBorders(); for (int32_t i = 0; i < numBorders; i++) { if (m_borders[i]->isModified()) { return true; } } return false; } /** * Clear the modification status of this border file. */ void BorderFile::clearModified() { CaretDataFile::clearModified(); m_metadata->clearModified(); m_classColorTable->clearModified(); m_nameColorTable->clearModified(); const int32_t numBorders = getNumberOfBorders(); for (int32_t i = 0; i < numBorders; i++) { m_borders[i]->clearModified(); } } /** * Add information about the file to the data file information. * * @param dataFileInformation * Consolidates information about a data file. */ void BorderFile::addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) { CaretDataFile::addToDataFileContentInformation(dataFileInformation); const std::vector allStructures = getAllBorderStructures(); if (allStructures.size() >= 2) { AString structuresText; for (std::vector::const_iterator iter = allStructures.begin(); iter != allStructures.end(); iter++) { structuresText += (StructureEnum::toGuiName(*iter) + " "); } dataFileInformation.addNameAndValue("Border Structures", structuresText); } int nameSize = 4, classSize = 0;//reserve space for headings, but classSize is only to know how much to reserve() BorderMultiPartHelper myHelp(this); for (int i = 0; i < (int)myHelp.borderPieceList.size(); ++i) { CaretAssert(myHelp.borderPieceList[i].size() > 0); const Border* thisPart = getBorder(myHelp.borderPieceList[i][0]); nameSize = max(nameSize, thisPart->getName().length()); classSize = max(classSize, thisPart->getClassName().length()); } nameSize += 3;//minimum number spaces between fields int numberSize = max(8, AString::number(myHelp.borderPieceList.size()).length() + 3);//spacing for border index AString header = AString("INDEX").leftJustified(numberSize) + AString("NAME").leftJustified(nameSize) + "CLASS"; dataFileInformation.addText(header); for (int i = 0; i < (int)myHelp.borderPieceList.size(); ++i) { CaretAssert(myHelp.borderPieceList[i].size() > 0); const Border* thisPart = getBorder(myHelp.borderPieceList[i][0]); AString line; line.reserve(numberSize + nameSize + classSize + 1); line = "\n" + AString::number(i + 1).leftJustified(numberSize); line += thisPart->getName().leftJustified(nameSize); line += thisPart->getClassName(); dataFileInformation.addText(line); } } /** * Export this border file to Caret5 formatted border color and * border projection files. * * @param surfaceFiles * Surface files for unprojection of borders. * @param outputCaret5FilesPrefix * Prefix for Caret5 output files. */ void BorderFile::exportToCaret5Format(const std::vector& surfaceFiles, const AString& outputCaret5FilesPrefix) { AString errorMessage; if (getNumberOfBorders() <= 0) { errorMessage.appendWithNewLine("This border file contains zero borders."); } if (outputCaret5FilesPrefix.isEmpty()) { errorMessage.appendWithNewLine("Caret5 output file prefix is empty."); } if ( ! errorMessage.isEmpty()) { throw DataFileException(getFileName(), errorMessage); } /* * In Caret7, each border contains a Structure attribute and a Caret7 * border file may contain borders from more than one structure. However, * Caret5 borders do not contain a structure attribute and so each * Caret5 border file contains borders for one structure only. * * So, group borders by structure. * */ std::map > bordersPerStructuresMap; for (std::vector::iterator borderIter = m_borders.begin(); borderIter != m_borders.end(); borderIter++) { Border* border = *borderIter; if (border->getNumberOfPoints() > 0) { const StructureEnum::Enum structure = border->getStructure(); std::map >::iterator iter = bordersPerStructuresMap.find(structure); if (iter != bordersPerStructuresMap.end()) { iter->second.push_back(border); } else { std::vector borderVector; borderVector.push_back(border); bordersPerStructuresMap.insert(std::pair >(structure, borderVector)); } } } int32_t filesWrittenCount = 0; /* * Surface are needed for unprojecting to create border files. * This will track missing surface structure types. */ std::set missingSurfaceStructures; /* * Place borders for each structure in separate files. */ for (std::map >::iterator iter = bordersPerStructuresMap.begin(); iter != bordersPerStructuresMap.end(); iter++) { const StructureEnum::Enum structure = iter->first; const std::vector& borderVector = iter->second; const int32_t numberOfBorders = static_cast(borderVector.size()); AString structureName = "unknown"; if (structure == StructureEnum::CEREBELLUM) { structureName = "cerebellum"; } else if (StructureEnum::isLeft(structure)) { structureName = "left"; } else if (StructureEnum::isRight(structure)) { structureName = "right"; } AString headerText; headerText.appendWithNewLine("BeginHeader"); headerText.appendWithNewLine("comment exported from wb_view file " + getFileNameNoPath()); headerText.appendWithNewLine("encoding ASCII"); headerText.appendWithNewLine("structure " + structureName); headerText.appendWithNewLine("EndHeader"); if (numberOfBorders > 0) { bool allBorderProjectionsValid = true; AString borderProjFileText; borderProjFileText.appendWithNewLine(headerText); borderProjFileText.appendWithNewLine(AString::number(numberOfBorders)); bool allBordersValid = true; AString borderFileText; borderFileText.appendWithNewLine(headerText); borderFileText.appendWithNewLine(AString::number(numberOfBorders)); for (int32_t iBorder = 0; iBorder < numberOfBorders; iBorder++) { const Border* border = borderVector[iBorder]; const int32_t numPoints = border->getNumberOfPoints(); const AString name = border->getName(); /* * Border Projection * Write index, number of points, name, * sampling density/variance/topography/uncertainty * * Center (0, 0, 0) */ borderProjFileText.appendWithNewLine(AString::number(iBorder) + " " + AString::number(numPoints) + " " + name + " 20.0 1.0 0.0 1.0"); borderProjFileText.appendWithNewLine("0.0 0.0 0.0"); /* * Border * Write index, number of points, name, * sampling density/variance/topography/uncertainty * * Center (0, 0, 0) */ borderFileText.appendWithNewLine(AString::number(iBorder) + " " + AString::number(numPoints) + " " + name + " 20.0 1.0 0.0 1.0"); borderFileText.appendWithNewLine("0.0 0.0 0.0"); for (int32_t jPoint = 0; jPoint < numPoints; jPoint++) { const SurfaceProjectedItem* spi = border->getPoint(jPoint); const SurfaceProjectionBarycentric* baryProj = spi->getBarycentricProjection(); if (baryProj->isValid()) { const float* triangleAreas = baryProj->getTriangleAreas(); const int32_t* triangleNodes = baryProj->getTriangleNodes(); /* * Add points nodes, section, areas, and radius */ borderProjFileText.appendWithNewLine(AString::number(triangleNodes[0]) + " " + AString::number(triangleNodes[1]) + " " + AString::number(triangleNodes[2]) + " 0 " + AString::number(triangleAreas[0], 'f', 6) + " " + AString::number(triangleAreas[1], 'f', 6) + " " + AString::number(triangleAreas[2], 'f', 6) + " 0.0"); } else { allBorderProjectionsValid = false; } if ( ! surfaceFiles.empty()) { SurfaceFile* surface = NULL; for (std::vector::const_iterator surfaceIter = surfaceFiles.begin(); surfaceIter != surfaceFiles.end(); surfaceIter++) { SurfaceFile* sf = *surfaceIter; if (sf->getStructure() == structure) { surface = sf; break; } } if (surface != NULL) { float xyz[3]; if (spi->getProjectedPosition(*surface, xyz, false)) { /* * Add point index, section, xyz, and radius */ borderFileText.appendWithNewLine(AString::number(jPoint) + " 0 " + AString::number(xyz[0], 'f', 3) + " " + AString::number(xyz[1], 'f', 3) + " " + AString::number(xyz[2], 'f', 3) + " 0.0"); } else { allBordersValid = false; } } else { missingSurfaceStructures.insert(structure); allBordersValid = false; } } else { missingSurfaceStructures.insert(structure); allBordersValid = false; } } } if (allBorderProjectionsValid) { try { const AString filename = (outputCaret5FilesPrefix + "_" + StructureEnum::toName(structure) + ".borderproj"); TextFile borderProjectionFile; borderProjectionFile.addText(borderProjFileText); borderProjectionFile.writeFile(filename); filesWrittenCount++; } catch (const DataFileException& dfe) { errorMessage.appendWithNewLine(dfe.whatString()); } } else { errorMessage.appendWithNewLine("There were failures creating at least one border projection for structure: " + StructureEnum::toName(structure)); } if (allBordersValid) { try { const AString filename = (outputCaret5FilesPrefix + "_" + StructureEnum::toName(structure) + ".border"); TextFile borderFile; borderFile.addText(borderFileText); borderFile.writeFile(filename); filesWrittenCount++; } catch (const DataFileException& dfe) { errorMessage.appendWithNewLine(dfe.whatString()); } } else { errorMessage.appendWithNewLine("There were failures creating at least one border for structure: " + StructureEnum::toName(structure)); } } } for (std::set::iterator missingStructureIter = missingSurfaceStructures.begin(); missingStructureIter != missingSurfaceStructures.end(); missingStructureIter++) { errorMessage.appendWithNewLine("No surface was available for structure: " + StructureEnum::toName(*missingStructureIter)); } if (filesWrittenCount > 0) { try { const AString filename = (outputCaret5FilesPrefix + ".bordercolor"); GiftiLabelTable* colorTable = getNameColorTable(); colorTable->exportToCaret5ColorFile(filename); } catch (const GiftiException& ge) { errorMessage.appendWithNewLine(ge.whatString()); } } if ( ! errorMessage.isEmpty()) { throw DataFileException(getFileName(), errorMessage); } } BorderMultiPartHelper::BorderMultiPartHelper(const BorderFile* bf) { int numBorderParts = bf->getNumberOfBorders(); for (int i = 0; i < numBorderParts; ++i) { const Border* thisPart = bf->getBorder(i); map, int>::const_iterator iter = stringLookup.find(make_pair(thisPart->getName(), thisPart->getClassName())); if (iter == stringLookup.end()) { stringLookup.insert(make_pair(make_pair(thisPart->getName(), thisPart->getClassName()), (int)borderPieceList.size())); borderPieceList.push_back(vector(1, i)); } else { borderPieceList[iter->second].push_back(i); } } } int BorderMultiPartHelper::fromNumberOrName(const AString& ident) const { bool ok = false; int whichBorder = ident.toInt(&ok) - 1;//first border is "1" if (ok) { if (whichBorder < 0 || whichBorder >= (int)borderPieceList.size()) return -1; return whichBorder; } else {//only search for name if the string isn't a number, to prevent surprises for (std::map, int>::const_iterator iter = stringLookup.begin(); iter != stringLookup.end(); ++iter) { if (iter->first.first == ident) { return iter->second; } } return -1; } } connectome-workbench-1.4.2/src/Files/BorderFile.h000066400000000000000000000251351360521144700216600ustar00rootroot00000000000000#ifndef __BORDER_FILE__H_ #define __BORDER_FILE__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretDataFile.h" #include "CaretPointer.h" #include "DisplayGroupEnum.h" #include #include class QXmlStreamReader; class QXmlStreamWriter; namespace caret { class Border; class BorderPointFromSearch; class GroupAndNameHierarchyModel; class GiftiLabel; class GiftiLabelTable; class SurfaceFile; class SurfaceProjectedItem; class BorderFile : public CaretDataFile { public: BorderFile(); virtual ~BorderFile(); BorderFile(const BorderFile& obj); BorderFile& operator=(const BorderFile& obj); virtual void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation); StructureEnum::Enum getStructure() const; void setStructure(const StructureEnum::Enum structure); std::vector getAllBorderStructures() const; bool splitIntoSingleStructureFiles(const std::map& singleStructureFileNames, const std::map& structureNumberOfNodes, std::vector& singleStructureBorderFilesOut, AString& errorMessageOut) const; GiftiMetaData* getFileMetaData(); const GiftiMetaData* getFileMetaData() const; void readFile(const AString& filename); void writeFile(const AString& filename); void writeFile(const AString& filename, const int& version); void clear(); bool isEmpty() const; int32_t getNumberOfNodes() const; void setNumberOfNodes(const int32_t& numNodes); void updateNumberOfNodesIfSingleStructure(const std::map& structureToNodeCount); int32_t getNumberOfBorders() const; Border* getBorder(const int32_t indx); const Border* getBorder(const int32_t indx) const; bool containsBorder(const Border* border) const; void findAllBordersWithEndPointNearSegmentFirstPoint(const DisplayGroupEnum::Enum displayGroup, const int32_t browserTabIndex, const SurfaceFile* surfaceFile, const Border* borderSegment, const float maximumDistance, std::vector& borderPointsOut) const; void findAllBordersWithAnyPointNearSegmentFirstPoint(const DisplayGroupEnum::Enum displayGroup, const int32_t browserTabIndex, const SurfaceFile* surfaceFile, const Border* borderSegment, const float maximumDistance, std::vector& borderPointsOut) const; void findAllBordersWithPointsNearBothSegmentEndPoints(const DisplayGroupEnum::Enum displayGroup, const int32_t browserTabIndex, const SurfaceFile* surfaceFile, const Border* borderSegment, const float maximumDistance, std::vector& borderPointsOut) const; void findBordersInsideRegionOfInterest(const DisplayGroupEnum::Enum displayGroup, const int32_t browserTabIndex, const SurfaceFile* surfaceFile, const std::vector& nodesInROI, std::vector >& insideCountAndBorderOut) const; void addBorder(Border* border); void removeBorder(const int32_t indx); void removeBorder(Border* border); bool isBorderDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t browserTabIndex, const Border* border); GiftiLabelTable* getClassColorTable(); const GiftiLabelTable* getClassColorTable() const; GiftiLabelTable* getNameColorTable(); const GiftiLabelTable* getNameColorTable() const; int getNumberOfBorderMetadataKeys() const { return (int)m_borderMDKeys.size(); } int getIndexForBorderMetadataKey(const AString& key) const; const AString& getBorderMetadataKey(const int& index) const; //only adds if it doesn't already exist, and returns index int addBorderMetadataKey(const AString& key); void removeBorderMetadataKey(const int& index); void clearBorderMetaData(); AString getBorderMetadataValue(const AString& name, const AString& className, const int& index) const; void setBorderMetadataValue(const AString& name, const AString& className, const int& index, const AString& value); void createNameAndClassColorTables(const GiftiLabelTable* oldColorTable); GroupAndNameHierarchyModel* getGroupAndNameHierarchyModel(); const GroupAndNameHierarchyModel* getGroupAndNameHierarchyModel() const; QStringList getAllBorderNamesSorted() const; static int32_t getFileVersion(); static AString getFileVersionAsString(); void exportToCaret5Format(const std::vector& surfaceFiles, const AString& outputCaret5FilesPrefix); AString getObsoleteMultiStructureFormatMessage(); /** XML Tag for BorderFile element */ static const AString XML_TAG_BORDER_FILE; /** XML Tag for Version attribute */ static const AString XML_ATTRIBUTE_VERSION; /** XML Tag for Name Color Table */ static const AString XML_TAG_NAME_COLOR_TABLE; /** XML Tag for Class Color Table */ static const AString XML_TAG_CLASS_COLOR_TABLE; virtual bool isModified() const; virtual void clearModified(); void invalidateAllAssignedColors(); private: void copyHelperBorderFile(const BorderFile& obj); void initializeBorderFile(); bool canWriteAsVersion(const int& version) const; void writeVersion3(QXmlStreamWriter& output) const; void writeColorHelper(QXmlStreamWriter& output, const GiftiLabel* colorLabel) const; void readXML(QXmlStreamReader& xml); void parseBorderFile1(QXmlStreamReader& xml);//there is no version 2, because the SAX parser pretended to support version 2 when it didn't exist void parseBorderFile3(QXmlStreamReader& xml);//so, to make the new format give reasonable error messages in old releases, make the new format version 3 void parseBorderMDNames3(QXmlStreamReader& xml); AString parseClass3(QXmlStreamReader& xml); AString parseBorder3(QXmlStreamReader& xml, const AString& className); static void colorAttribHelper3(const AString& filename, QXmlStreamReader& xml, float rgbOut[3]); static std::vector parseBorderMDValues3(const AString& filename, QXmlStreamReader& xml); GiftiMetaData* m_metadata; std::vector m_borders; /** Holds colors assigned to classes */ GiftiLabelTable* m_classColorTable; /** Holds colors assigned to names */ GiftiLabelTable* m_nameColorTable; /** Holds class and name hierarchy used for display selection */ mutable GroupAndNameHierarchyModel* m_classNameHierarchy; /** force an update of the class and name hierarchy */ bool m_forceUpdateOfGroupAndNameHierarchy; StructureEnum::Enum m_structure; int32_t m_numNodes; std::vector m_borderMDKeys; std::map, std::vector > m_borderMDValues;//because each "Border" is really just a part of a border /** Version of this BorderFile */ static const int32_t s_borderFileVersion; }; struct BorderMultiPartHelper { std::map, int> stringLookup; std::vector > borderPieceList; BorderMultiPartHelper(const BorderFile* bf); int fromNumberOrName(const AString& ident) const; }; #ifdef __BORDER_FILE_DECLARE__ const AString BorderFile::XML_TAG_BORDER_FILE = "BorderFile"; const AString BorderFile::XML_ATTRIBUTE_VERSION = "Version"; const AString BorderFile::XML_TAG_NAME_COLOR_TABLE = "BorderNameColorTable"; const AString BorderFile::XML_TAG_CLASS_COLOR_TABLE = "BorderClassColorTable"; const int32_t BorderFile::s_borderFileVersion = 2; #endif // __BORDER_FILE_DECLARE__ } // namespace #endif //__BORDER_FILE__H_ connectome-workbench-1.4.2/src/Files/BorderLengthHelper.cxx000066400000000000000000000241141360521144700237310ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Border.h" #include "BorderLengthHelper.h" #include "CaretAssert.h" #include "CaretException.h" #include "GeodesicHelper.h" #include "SurfaceFile.h" #include "SurfaceProjectedItem.h" #include "SurfaceProjectionBarycentric.h" #include "Vector3D.h" #include #include using namespace caret; using namespace std; BorderLengthHelper::BorderLengthHelper(const SurfaceFile* mySurf, const float* correctedAreas) { m_surface = mySurf; m_corrAreas = correctedAreas; mySurf->computeNodeAreas(m_currAreas); if (correctedAreas == NULL) { m_geoHelp = mySurf->getGeodesicHelper(); } else { CaretPointer myBase(new GeodesicHelperBase(mySurf, correctedAreas)); m_geoHelp.grabNew(new GeodesicHelper(myBase)); } } namespace { float segmentLength(const SurfaceProjectedItem* start, const SurfaceProjectedItem* end, GeodesicHelper* myGeoHelp, const SurfaceFile* mySurf, const float* correctedAreas, const float* currAreas) { const SurfaceProjectionBarycentric* startBary = start->getBarycentricProjection(), *endBary = end->getBarycentricProjection(); CaretAssert(startBary->isValid() && endBary->isValid()); const int32_t* startNodes = startBary->getTriangleNodes(), *endNodes = endBary->getTriangleNodes(); const float* nodeCoords = mySurf->getCoordinateData(); Vector3D startPos, endPos; startBary->unprojectToSurface(*mySurf, startPos, 0.0f, true);//in case something silly is in the signed distance endBary->unprojectToSurface(*mySurf, endPos, 0.0f, true); int numSame = 0; int sameVerts[3] = {-1, -1, -1}; set startSet(startNodes, startNodes + 3), endSet(endNodes, endNodes + 3);//use sets in case a strange border file repeats vertices in a projection for (set::iterator iter = startSet.begin(); iter != startSet.end(); ++iter) { if (endSet.find(*iter) != endSet.end()) { sameVerts[numSame] = *iter; ++numSame; } } if (numSame == (int)startSet.size() || numSame == (int)endSet.size()) {//if vertices are repeated, and all of one set match, count it as same triangle numSame = 3; } switch (numSame) { case 3://same triangle if (correctedAreas != NULL)//apply area correction approximation - currently, just average the vertex areas and sqrt {//we could integrate along the path, but expansion should be fairly smooth anyway float correctionFactor = sqrt(correctedAreas[startNodes[0]] + correctedAreas[startNodes[1]] + correctedAreas[startNodes[2]]) / sqrt(currAreas[startNodes[0]] + currAreas[startNodes[1]] + currAreas[startNodes[2]]); return (startPos - endPos).length() * correctionFactor; } else { return (startPos - endPos).length(); } case 2://use unfolding of triangle { Vector3D neigh1Coord = nodeCoords + sameVerts[0] * 3;//neigh1 and neigh2 are the shared vertices Vector3D neigh2Coord = nodeCoords + sameVerts[1] * 3; float abmag, efmag; Vector3D abhat = (neigh2Coord - neigh1Coord).normal(&abmag);//a is neigh1, b is neigh2, b - a = (vector)ab Vector3D ac = endPos - neigh1Coord;//c is endpoint, c - a = (vector)ac Vector3D ad = abhat * abhat.dot(ac);//d is the point on the shared edge that endpoint (c) is closest to Vector3D d = neigh1Coord + ad;//this way we can "unfold" the triangles by projecting the distance of cd, from point d, along the unit vector of the startpoint to closest point on shared edge Vector3D ea = neigh1Coord - startPos;//e is the startpoint, a - e = (vector)ea Vector3D tempvec = abhat * abhat.dot(ea);//find vector fa, f being the point on shared edge closest to e, the startpoint Vector3D efhat = (ea - tempvec).normal(&efmag);//and subtract it to obtain only the perpendicular, normalize to get unit vector float cdmag = (d - endPos).length();//get the length from shared edge to endpoint Vector3D g = d + efhat * cdmag;//get point g, the unfolded position of endpoint Vector3D eg = g - startPos;//this is the vector from base (e) to endpoint after unfolding (g), this is our distance, as long as the tetralateral is convex float tempf = efmag / (efmag + cdmag);//now we need to check that the path stays inside the tetralateral (ie, that it is convex) Vector3D eh = eg * tempf;//this is a vector from e (startpoint) to the point on the shared edge that the full path (eg) crosses Vector3D ah = eh - ea;//eh - ea = eh + ae = ae + eh = ah, vector from neigh1 to the point on shared edge the path goes through tempf = ah.dot(abhat);//get the component along ab so we can test that it is positive and less than |ab| if (tempf <= 0.0f) { tempf = 0.0f; } else if (tempf >= abmag) {//tetralateral is concave or triangular (degenerate), so clamp the point through the shared edge to an endpoint tempf = abmag; } Vector3D crosspoint = neigh1Coord + abhat * tempf; if (correctedAreas != NULL)//apply area correction approximation - currently, just average the vertex areas on the shared edge and sqrt {//we could compute the amount of the path in each triangle exactly, and integrate along the path, but expansion should be fairly smooth anyway float correctionFactor = sqrt(correctedAreas[sameVerts[0]] + correctedAreas[sameVerts[1]]) / sqrt(currAreas[sameVerts[0]] + currAreas[sameVerts[1]]); return ((crosspoint - startPos).length() + (endPos - crosspoint).length()) * correctionFactor; } else { return ((crosspoint - startPos).length() + (endPos - crosspoint).length()); } } case 1://brute force tests of to vertex, geodesic, to end case 0: { float bestLength = -1.0f; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { vector pathNodes; vector pathDists; myGeoHelp->getPathToNode(startNodes[i], endNodes[j], pathNodes, pathDists, true);//we want the distance, not the path, so use the more accurate distances float startLength, endLength; if (correctedAreas != NULL)//apply area correction approximation - currently, just average the vertex areas and sqrt {//we could integrate along the path, but expansion should be fairly smooth anyway float startCorrFactor = sqrt(correctedAreas[startNodes[0]] + correctedAreas[startNodes[1]] + correctedAreas[startNodes[2]]) / sqrt(currAreas[startNodes[0]] + currAreas[startNodes[1]] + currAreas[startNodes[2]]); float endCorrFactor = sqrt(correctedAreas[endNodes[0]] + correctedAreas[endNodes[1]] + correctedAreas[endNodes[2]]) / sqrt(currAreas[endNodes[0]] + currAreas[endNodes[1]] + currAreas[endNodes[2]]); startLength = (Vector3D(nodeCoords + startNodes[i] * 3) - startPos).length() * startCorrFactor; endLength = (endPos - Vector3D(nodeCoords + endNodes[j] * 3)).length() * endCorrFactor; } else { startLength = (Vector3D(nodeCoords + startNodes[i] * 3) - startPos).length(); endLength = (endPos - Vector3D(nodeCoords + endNodes[j] * 3)).length(); } float totalLength = pathDists.back() + startLength + endLength; if (totalLength < bestLength || bestLength == -1.0f) { bestLength = totalLength; } } } return bestLength; } default://should never be other values CaretAssert(false); throw CaretException("internal error, tell the developers what you just tried to do"); } } } float BorderLengthHelper::length(const Border* myBorder) { int numPoints = myBorder->getNumberOfPoints(); double totalLength = 0.0f; for (int i = 1; i < numPoints; ++i) { totalLength += segmentLength(myBorder->getPoint(i - 1), myBorder->getPoint(i), m_geoHelp, m_surface, m_corrAreas, m_currAreas.data()); } if (myBorder->isClosed() && numPoints > 1) { totalLength += segmentLength(myBorder->getPoint(numPoints - 1), myBorder->getPoint(0), m_geoHelp, m_surface, m_corrAreas, m_currAreas.data()); } return totalLength; } BorderLengthHelper::~BorderLengthHelper() {//for CaretPointer destructor to not be instantiated on a forward declaration } connectome-workbench-1.4.2/src/Files/BorderLengthHelper.h000066400000000000000000000027001360521144700233530ustar00rootroot00000000000000#ifndef __BORDER_LENGTH_HELPER_H__ #define __BORDER_LENGTH_HELPER_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretPointer.h" #include namespace caret { class Border; class GeodesicHelper; class SurfaceFile; class BorderLengthHelper { const SurfaceFile* m_surface; CaretPointer m_geoHelp; const float* m_corrAreas; std::vector m_currAreas; public: BorderLengthHelper(const SurfaceFile* mySurf, const float* correctedAreas = NULL); float length(const Border* myBorder); ~BorderLengthHelper(); }; } #endif //__BORDER_LENGTH_HELPER_H__ connectome-workbench-1.4.2/src/Files/BorderPointFromSearch.h000066400000000000000000000151401360521144700240370ustar00rootroot00000000000000#ifndef __BORDER_POINT_FROM_SEARCH_H__ #define __BORDER_POINT_FROM_SEARCH_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "CaretObject.h" /** * \class caret::BorderPointFromSearch * \brief Contains result of searching for a border point. * \ingroup Files */ namespace caret { class BorderPointFromSearch : public CaretObject { public: /** * Constructor. */ BorderPointFromSearch() { reset(); } /** * Copy constructor. * * @param rhs * Instance copied to this instance. */ BorderPointFromSearch(const BorderPointFromSearch& rhs) : CaretObject(rhs) { this->copyHelperBorderPointFromSearch(rhs); } /** * Destructor. */ virtual ~BorderPointFromSearch() { } /** * Copy constructor. * * @param rhs * Instance copied to this instance. * @return * Reference to this instance. */ BorderPointFromSearch& operator=(const BorderPointFromSearch& rhs) { if (this != &rhs) { CaretObject::operator=(rhs); this->copyHelperBorderPointFromSearch(rhs); } return *this; } /** * Comparison operator using distance. * * @param rhs * Compared to rhs * @param * True if 'this' is less than 'rhs'. */ bool operator<(const BorderPointFromSearch& rhs) const { if (isValid() && rhs.isValid()) { return (m_distance < rhs.m_distance); } else if (isValid()) { return true; } return false; } /* * Reset the data to invalid. */ void reset() { m_borderFile = NULL; m_border = NULL; m_borderIndex = -1; m_borderPointIndex = -1; m_distance = -1.0; } /** * Replace this instance with the given instance if the given * instance's distance is less than this instance's distance * or if this instance is invalid. * * @param rhs * The other instance. */ void replaceWithNearerDistance(const BorderPointFromSearch& rhs) { if ( ! rhs.isValid()) { return; } bool replaceMeFlag = false; if (isValid()) { if (rhs.m_distance < m_distance) { replaceMeFlag = true; } } else { replaceMeFlag = true; } if (replaceMeFlag) { copyHelperBorderPointFromSearch(rhs); } } /** * Set the data. * * @param borderFile * The border file. * @param border * The border * @param borderIndex * Index of border in the border file * @param borderPointIndex * Index of point in the border * @param distance * Distance of border point from the search point. */ void setData(BorderFile* borderFile, Border* border, const int32_t borderIndex, const int32_t borderPointIndex, const float distance) { m_borderFile = borderFile; m_border = border; m_borderIndex = borderIndex; m_borderPointIndex = borderPointIndex; m_distance = distance; CaretAssert(m_borderFile); CaretAssert(m_border); CaretAssert(m_borderIndex >= 0); CaretAssert(m_borderPointIndex >= 0); CaretAssert(m_distance >= 0.0); } /** @return Is this item valid */ inline bool isValid() const { return ((m_borderFile != NULL) && (m_border != NULL) && (m_borderIndex >= 0) && (m_borderPointIndex >= 0) && (m_distance >= 0.0)); } /** @return Border file containing the point */ inline BorderFile* borderFile() { return m_borderFile; } /** @return The border */ inline Border* border() { return m_border; } /** @return Index of the border in the border file */ inline int32_t borderIndex() { return m_borderIndex; } /** @return Index of the border point */ inline int32_t borderPointIndex() { return m_borderPointIndex; } /** @return Distance to the border point from the search point */ inline float distance() { return m_distance; } private: /** * Helps with copying an object of this type. * @param rhs * Object that is copied. */ void copyHelperBorderPointFromSearch(const BorderPointFromSearch& rhs) { m_borderFile = rhs.m_borderFile; m_border = rhs.m_border; m_borderIndex = rhs.m_borderIndex; m_borderPointIndex = rhs.m_borderPointIndex; m_distance = rhs.m_distance; } BorderFile* m_borderFile; Border* m_border; int32_t m_borderIndex; int32_t m_borderPointIndex; float m_distance; }; #ifdef __BORDER_POINT_FROM_SEARCH_DECLARE__ // #endif // __BORDER_POINT_FROM_SEARCH_DECLARE__ } // namespace #endif //__BORDER_POINT_FROM_SEARCH_H__ connectome-workbench-1.4.2/src/Files/BorderTracingHelper.cxx000066400000000000000000000132541360521144700241020ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BorderTracingHelper.h" #include "Border.h" #include "BorderFile.h" #include "SurfaceProjectedItem.h" #include "SurfaceProjectionBarycentric.h" #include "SurfaceFile.h" #include "TopologyHelper.h" using namespace caret; using namespace std; BorderTracingHelper::BorderTracingHelper(const SurfaceFile* surfIn) { m_numNodes = surfIn->getNumberOfNodes(); m_structure = surfIn->getStructure(); m_topoHelp = surfIn->getTopologyHelper();//doesn't need sorted, because we may need to walk in "reverse", so don't rely on sorting } vector > BorderTracingHelper::tracePrivate(vector& marked, const float& placement) { vector > ret; const vector& myEdgeInfo = m_topoHelp->getEdgeInfo(); const vector& myTileInfo = m_topoHelp->getTileInfo(); vector edgeUsed(myEdgeInfo.size(), 0); float nodeWeights[3] = { 1.0f - placement, placement, 0.0f }; while (true) { bool foundStart = false, closed = true; int curInNode = -1, curEdge = -1, curOutNode = -1; for (int i = 0; i < m_numNodes; ++i) { if (marked[i] != 0) { const vector& edges = m_topoHelp->getNodeEdges(i); int numEdges = (int)edges.size(); for (int j = 0; j < numEdges; ++j) { const TopologyEdgeInfo& thisEdge = myEdgeInfo[edges[j]]; int testNode = (thisEdge.node2 == i ? thisEdge.node1 : thisEdge.node2); if (marked[testNode] == 0 && edgeUsed[edges[j]] == 0) { if (!foundStart || thisEdge.numTiles == 1) { foundStart = true; curInNode = i; curEdge = edges[j]; curOutNode = testNode; if (thisEdge.numTiles == 1) { closed = false; break;//if we found the end of an open border, stop searching } } } } } } if (!foundStart) break; CaretPointer newBorder(new Border());//in case something throws newBorder->setClosed(closed); int startInNode = curInNode, startOutNode = curOutNode; int prevThirdNode = -1; do { edgeUsed[curEdge] = 1;//don't start another border from this edge const TopologyEdgeInfo& myEdge = myEdgeInfo[curEdge];//to remove some redundant indexing CaretPointer newPoint(new SurfaceProjectedItem());//ditto newPoint->setStructure(m_structure); newPoint->getBarycentricProjection()->setProjectionSurfaceNumberOfNodes(m_numNodes); int32_t triNodes[3] = { curInNode, curOutNode, myEdge.tiles[0].node3 };//always use the first tile, as it will always exist newPoint->getBarycentricProjection()->setTriangleNodes(triNodes); newPoint->getBarycentricProjection()->setTriangleAreas(nodeWeights); newPoint->getBarycentricProjection()->setValid(true); newBorder->addPoint(newPoint.releasePointer());//NOTE: addPoint takes ownership of a RAW POINTER - shared_ptr won't release a pointer int useTile = 0; if (myEdge.tiles[0].node3 == prevThirdNode) { if (myEdge.numTiles == 1) break; useTile = 1; } int nextNode = myEdge.tiles[useTile].node3; int edgeMove = 0; if (marked[nextNode] == 0) { edgeMove = (myEdge.tiles[useTile].edgeReversed == (myEdge.node1 == curInNode) ? 1 : 2);//some magic to find the next edge via the lookups prevThirdNode = curOutNode; curOutNode = nextNode; } else { edgeMove = (myEdge.tiles[useTile].edgeReversed == (myEdge.node1 == curInNode) ? 2 : 1);//rather than searching the edges on the tile or such prevThirdNode = curInNode; curInNode = nextNode; } int edgeIndex = (myEdge.tiles[useTile].whichEdge + edgeMove) % 3;//modify the edge index within the tile by the magic offset curEdge = myTileInfo[myEdge.tiles[useTile].tile].edges[edgeIndex].edge;//and pull out the global index of the edge CaretAssert(myEdgeInfo[curEdge].node1 == curInNode || myEdgeInfo[curEdge].node1 == curOutNode);//assert to make sure the magic worked CaretAssert(myEdgeInfo[curEdge].node2 == curInNode || myEdgeInfo[curEdge].node2 == curOutNode); } while (curInNode != startInNode || curOutNode != startOutNode); ret.push_back(newBorder); } return ret; } connectome-workbench-1.4.2/src/Files/BorderTracingHelper.h000066400000000000000000000072461360521144700235330ustar00rootroot00000000000000#ifndef __BORDER_TRACING_HELPER_H__ #define __BORDER_TRACING_HELPER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "CaretPointer.h" #include "StructureEnum.h" #include "TopologyHelper.h" #include namespace caret { class Border; class SurfaceFile; class BorderTracingHelper { int m_numNodes; StructureEnum::Enum m_structure; CaretPointer m_topoHelp; BorderTracingHelper();//no default BorderTracingHelper(const BorderTracingHelper&);//no copy BorderTracingHelper& operator=(const BorderTracingHelper&);//no assign std::vector > tracePrivate(std::vector& marked, const float& placement); public: BorderTracingHelper(const SurfaceFile* surfIn); template std::vector > traceData(T* data, const Test& myTester, const float& placement = 0.33f); //some useful selection objects class LabelSelect { int32_t m_select; LabelSelect(); public: LabelSelect(const int32_t& value) : m_select(value) { } bool operator() (const int32_t& toTest) const { return toTest == m_select; } }; template class LessThan { T m_threshold; bool m_inclusive; LessThan(); public: LessThan(const T& value, const bool& inclusive) : m_threshold(value), m_inclusive(inclusive) { } bool operator() (const T& toTest) const { if (m_inclusive) { return toTest <= m_threshold; } else { return toTest < m_threshold; } } }; template class GreaterThan { T m_threshold; bool m_inclusive; GreaterThan(); public: GreaterThan(const T& value, const bool& inclusive) : m_threshold(value), m_inclusive(inclusive) { } bool operator() (const T& toTest) const { if (m_inclusive) { return toTest >= m_threshold; } else { return toTest > m_threshold; } } }; }; template std::vector > BorderTracingHelper::traceData(T* data, const Test& myTester, const float& placement) { CaretAssert(placement >= 0.0f && placement <= 1.0f); std::vector marked(m_numNodes); for (int i = 0; i < m_numNodes; ++i) { marked[i] = (myTester(data[i]) ? 1 : 0); } return tracePrivate(marked, placement); } }//namespace #endif //__BORDER_TRACING_HELPER_H__ connectome-workbench-1.4.2/src/Files/BrainordinateRegionOfInterest.cxx000066400000000000000000000625041360521144700261470ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __BRAINORDINATE_REGION_OF_INTEREST_DECLARE__ #include "BrainordinateRegionOfInterest.h" #undef __BRAINORDINATE_REGION_OF_INTEREST_DECLARE__ #include "BoundingBox.h" #include "CaretAssert.h" #include "CiftiBrainordinateLabelFile.h" #include "CiftiMappableDataFile.h" #include "CiftiParcelsMap.h" #include "EventSurfaceStructuresValidGet.h" #include "EventManager.h" #include "GiftiLabelTable.h" #include "LabelFile.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::BrainordinateRegionOfInterest * \brief Contains a region of interest * \ingroup Files * * Contains a region of interest that may include nodes from multiple * surfaces and voxels within a volume space. */ /** * Constructor. */ BrainordinateRegionOfInterest::BrainordinateRegionOfInterest() : CaretObject() { clear(); m_sceneAssistant = new SceneClassAssistant(); } /** * Destructor. */ BrainordinateRegionOfInterest::~BrainordinateRegionOfInterest() { clear(); delete m_sceneAssistant; } /** * Copy constructor. * @param obj * Object that is copied. */ BrainordinateRegionOfInterest::BrainordinateRegionOfInterest(const BrainordinateRegionOfInterest& obj) : CaretObject(obj), SceneableInterface(obj) { this->copyHelperBrainordinateRegionOfInterest(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ BrainordinateRegionOfInterest& BrainordinateRegionOfInterest::operator=(const BrainordinateRegionOfInterest& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperBrainordinateRegionOfInterest(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void BrainordinateRegionOfInterest::copyHelperBrainordinateRegionOfInterest(const BrainordinateRegionOfInterest& obj) { clear(); m_highlighingEnabled = obj.m_highlighingEnabled; for (std::vector::const_iterator iter = obj.m_surfaceNodesInfo.begin(); iter != obj.m_surfaceNodesInfo.end(); iter++) { const SurfaceNodesInfo* sni = *iter; m_surfaceNodesInfo.push_back(new SurfaceNodesInfo(*sni)); } m_voxelSize[0] = obj.m_voxelSize[0]; m_voxelSize[1] = obj.m_voxelSize[1]; m_voxelSize[2] = obj.m_voxelSize[2]; /* * Voxel sizes must be non-negative */ CaretAssert(m_voxelSize[0] >= 0.0); CaretAssert(m_voxelSize[1] >= 0.0); CaretAssert(m_voxelSize[2] >= 0.0); m_voxelXYZ = obj.m_voxelXYZ; } /** * Clear this region of interest. */ void BrainordinateRegionOfInterest::clear() { for (std::vector::iterator iter = m_surfaceNodesInfo.begin(); iter != m_surfaceNodesInfo.end(); iter++) { SurfaceNodesInfo* sni = *iter; CaretAssert(sni); delete sni; } m_surfaceNodesInfo.clear(); m_voxelSize[0] = 0.0; m_voxelSize[1] = 0.0; m_voxelSize[2] = 0.0; m_voxelXYZ.clear(); m_highlighingEnabled = false; } /** * @return True if this region of interest contains a surface with * valid nodes, else false. */ bool BrainordinateRegionOfInterest::hasSurfaceNodes() const { for (std::vector::const_iterator iter = m_surfaceNodesInfo.begin(); iter != m_surfaceNodesInfo.end(); iter++) { const SurfaceNodesInfo* sni = *iter; CaretAssert(sni); if ( ! sni->m_surfaceNodeIndices.empty()) { return true; } } return false; } /** * Does this region of interest contains surface nodes for the surface * with the given structure and number of nodes? * * @param structure * The surface's structure. * @param surfaceNumberOfNodes * Number of nodes in surface. * @return * True if found, else false. */ bool BrainordinateRegionOfInterest::hasNodesForSurfaceStructure(const StructureEnum::Enum structure, const int64_t surfaceNumberOfNodes) const { for (std::vector::const_iterator iter = m_surfaceNodesInfo.begin(); iter != m_surfaceNodesInfo.end(); iter++) { const SurfaceNodesInfo* sni = *iter; CaretAssert(sni); if ( ! sni->m_surfaceNodeIndices.empty()) { if ((sni->m_structure == structure) && (sni->m_surfaceNumberOfNodes == surfaceNumberOfNodes)) { return true; } } } return false; } /** * Get the nodes in the region of interest for the surface * with the given structure and number of nodes? * * @param structure * The surface's structure. * @param surfaceNumberOfNodes * Number of nodes in surface. * @return * Vector containing node indices. Empty if surface node found. */ const std::vector& BrainordinateRegionOfInterest::getNodesForSurfaceStructure(const StructureEnum::Enum structure, const int64_t surfaceNumberOfNodes) const { for (std::vector::const_iterator iter = m_surfaceNodesInfo.begin(); iter != m_surfaceNodesInfo.end(); iter++) { const SurfaceNodesInfo* sni = *iter; CaretAssert(sni); if ( ! sni->m_surfaceNodeIndices.empty()) { if ((sni->m_structure == structure) && (sni->m_surfaceNumberOfNodes == surfaceNumberOfNodes)) { return sni->m_surfaceNodeIndices; } } } return s_emptySurfaceNodes; } /** * @return True if the region of interest contains volume voxels. */ bool BrainordinateRegionOfInterest::hasVolumeVoxels() const { if ( ! m_voxelXYZ.empty()) { return true; } return false; } /** * Get the volume voxel size. * * @param voxelSizeOut * Size of the volume voxels. */ void BrainordinateRegionOfInterest::getVolumeVoxelSize(float voxelSizeOut[3]) const { /* * Voxel sizes must be non-negative */ CaretAssert(m_voxelSize[0] >= 0.0); CaretAssert(m_voxelSize[1] >= 0.0); CaretAssert(m_voxelSize[2] >= 0.0); voxelSizeOut[0] = m_voxelSize[0]; voxelSizeOut[1] = m_voxelSize[1]; voxelSizeOut[2] = m_voxelSize[2]; } /** * Get the volume voxels in the region-of-interest. * * @return * XYZ coordinates of the voxels. (3 per voxel ==> XYZ) * Empty if no voxels ni region of interest. */ const std::vector& BrainordinateRegionOfInterest::getVolumeVoxelsXYZ() const { return m_voxelXYZ; } /** * Set the nodes in the region of interest for the surface * with the given structure and number of nodes. If there is an * ROI for the struture and number of nodes, it is replaced. * * @param structure * The surface's structure. * @param surfaceNumberOfNodes * Number of nodes in surface. * @param surfaceNodeIndices * The surface node indices. */ void BrainordinateRegionOfInterest::setSurfaceNodes(const StructureEnum::Enum structure, const int64_t surfaceNumberOfNodes, const std::vector& surfaceNodeIndices) { int64_t replaceAtIndex = -1; const int64_t numItems = static_cast(m_surfaceNodesInfo.size()); for (int64_t i = 0; i < numItems; i++) { const SurfaceNodesInfo* sni = m_surfaceNodesInfo[i]; CaretAssert(sni); if ((sni->m_structure == structure) && (sni->m_surfaceNumberOfNodes == surfaceNumberOfNodes)) { delete sni; m_surfaceNodesInfo[i] = NULL; replaceAtIndex = i; break; } } SurfaceNodesInfo* sni = new SurfaceNodesInfo(structure, surfaceNumberOfNodes, surfaceNodeIndices); if (replaceAtIndex >= 0) { CaretAssertVectorIndex(m_surfaceNodesInfo, replaceAtIndex); CaretAssert(m_surfaceNodesInfo[replaceAtIndex] = NULL); m_surfaceNodesInfo[replaceAtIndex] = sni; } else { m_surfaceNodesInfo.push_back(sni); } } /** * Set the volume voxels in the region of interest. Replaces all * voxels in the region of interest. * * @param voxelSize * Size of the voxels. * @param voxelsXYZ * Coordinates of the voxels (3 per voxel ==> XYZ) */ void BrainordinateRegionOfInterest::setVolumeVoxels(const float voxelSize[3], const std::vector& voxelsXYZ) { m_voxelSize[0] = std::fabs(voxelSize[0]); m_voxelSize[1] = std::fabs(voxelSize[1]); m_voxelSize[2] = std::fabs(voxelSize[2]); m_voxelXYZ = voxelsXYZ; /* * Voxel sizes must be non-negative */ CaretAssert(m_voxelSize[0] >= 0.0); CaretAssert(m_voxelSize[1] >= 0.0); CaretAssert(m_voxelSize[2] >= 0.0); } /** * @return Is brainordinate highlighting enabled * */ bool BrainordinateRegionOfInterest::isBrainordinateHighlightingEnabled() const { return m_highlighingEnabled; } /** * Set brainordinate highlighting. * * @param enabled * New status for highlighting. */ void BrainordinateRegionOfInterest::setBrainordinateHighlightingEnabled(const bool enabled) { m_highlighingEnabled = enabled; } /** * Set the region of interest to the brainordinates in the given named label * from the labels used for loading data in the given CIFTI file. * * @param ciftiMappableDataFile * The CIFTI file. * @param mapIndex * Index of the map. * @param labelName * Name of the parcel. * @param errorMessageOut * Will contain error message upon exit. * @return * True if successful. If failure, false is returned and errorMessageOut * will contain cause of failure. */ bool BrainordinateRegionOfInterest::setWithLabelFileLabel(const CaretMappableDataFile* caretMappableDataFile, const int32_t mapIndex, const AString& labelName, AString& errorMessageOut) { clear(); errorMessageOut.clear(); if (caretMappableDataFile == NULL) { errorMessageOut = "File is not valid (NULL)"; return false; } if ( ! caretMappableDataFile->isMappedWithLabelTable()) { errorMessageOut = "File is not mapped with a label table."; return false; } if ((mapIndex < 0) || (mapIndex >= caretMappableDataFile->getNumberOfMaps())) { errorMessageOut = ("Map index=" + AString::number(mapIndex) + " is invalid for file " + caretMappableDataFile->getFileNameNoPath()); return false; } if (labelName.isEmpty()) { errorMessageOut = "Label name is empty."; return false; } const GiftiLabelTable* labelTable = caretMappableDataFile->getMapLabelTable(mapIndex); CaretAssert(labelTable); if (labelTable != NULL) { const int64_t labelKey = labelTable->getLabelKeyFromName(labelName); if (labelKey < 0) { errorMessageOut = ("Label " + labelName + " not found in label table."); return false; } const LabelFile* labelFile = dynamic_cast(caretMappableDataFile); const CiftiBrainordinateLabelFile* ciftiLabelFile = dynamic_cast(caretMappableDataFile); if (labelFile != NULL) { const StructureEnum::Enum structure = labelFile->getStructure(); int64_t surfaceNumberOfNodes = labelFile->getNumberOfNodes(); std::vector nodeIndices; labelFile->getNodeIndicesWithLabelKey(mapIndex, labelKey, nodeIndices); if (nodeIndices.empty()) { errorMessageOut = ("No vertices found for label " + labelName); return false; } std::vector nodeIndices64(nodeIndices.begin(), nodeIndices.end()); setSurfaceNodes(structure, surfaceNumberOfNodes, nodeIndices64); return true; } else if (ciftiLabelFile != NULL) { bool haveBrainordinatesFlag = false; EventSurfaceStructuresValidGet structureNumberOfNodesEvent; EventManager::get()->sendEvent(structureNumberOfNodesEvent.getPointer()); std::map structNodes = structureNumberOfNodesEvent.getStructuresAndNumberOfNodes(); for (std::map::iterator structNodeIter = structNodes.begin(); structNodeIter != structNodes.end(); structNodeIter++) { const StructureEnum::Enum structure = structNodeIter->first; const int32_t surfaceNumberOfNodes = structNodeIter->second; std::vector nodeIndices; ciftiLabelFile->getNodeIndicesWithLabelKey(structure, surfaceNumberOfNodes, mapIndex, labelKey, nodeIndices); if ( ! nodeIndices.empty()) { std::vector nodeIndices64(nodeIndices.begin(), nodeIndices.end()); setSurfaceNodes(structure, surfaceNumberOfNodes, nodeIndices64); haveBrainordinatesFlag = true; } } std::vector voxelsXYZ; ciftiLabelFile->getVoxelCoordinatesWithLabelKey(mapIndex, labelKey, voxelsXYZ); if ( ! voxelsXYZ.empty()) { m_voxelXYZ.insert(m_voxelXYZ.end(), voxelsXYZ.begin(), voxelsXYZ.end()); ciftiLabelFile->getVoxelSpacing(m_voxelSize[0], m_voxelSize[1], m_voxelSize[2]); m_voxelSize[0] = std::fabs(m_voxelSize[0]); m_voxelSize[1] = std::fabs(m_voxelSize[1]); m_voxelSize[2] = std::fabs(m_voxelSize[2]); haveBrainordinatesFlag = true; } if (haveBrainordinatesFlag) { return true; } errorMessageOut = ("No brainordinates found for label " + labelName); return false; } } errorMessageOut = (caretMappableDataFile->getFileNameNoPath() + " is not a label type file or not recognized as label file (programming error)."); return false; } /** * Set the region of interest to the brainordinates in the given named parcel * from the parcels used for loading data in the given CIFTI file. * * @param ciftiMappableDataFile * The CIFTI file. * @param mapIndex * Index of the map. * @param parcelName * Name of the parcel. * @param errorMessageOut * Will contain error message upon exit. * @return * True if successful. If failure, false is returned and errorMessageOut * will contain cause of failure. */ bool BrainordinateRegionOfInterest::setWithCiftiParcelLoadingBrainordinates(const CiftiMappableDataFile* ciftiMappableDataFile, const int32_t mapIndex, const AString& parcelName, AString& errorMessageOut) { clear(); errorMessageOut.clear(); if (ciftiMappableDataFile == NULL) { errorMessageOut = "File is not valid (NULL)"; return false; } if ((mapIndex < 0) || (mapIndex >= ciftiMappableDataFile->getNumberOfMaps())) { errorMessageOut = ("Map index=" + AString::number(mapIndex) + " is invalid for file " + ciftiMappableDataFile->getFileNameNoPath()); return false; } const CiftiParcelsMap* ciftiParcelsMap = ciftiMappableDataFile->getCiftiParcelsMapForLoading(); return setWithCiftiParcelBrainordinates(ciftiMappableDataFile, ciftiParcelsMap, parcelName, errorMessageOut); } /** * Set the region of interest to the brainordinates in the given named parcel * from the parcels used for mapping data in the given CIFTI file. * * @param ciftiMappableDataFile * The CIFTI file. * @param mapIndex * Index of the map. * @param parcelName * Name of the parcel. * @param errorMessageOut * Will contain error message upon exit. * @return * True if successful. If failure, false is returned and errorMessageOut * will contain cause of failure. */ bool BrainordinateRegionOfInterest::setWithCiftiParcelMappingBrainordinates(const CiftiMappableDataFile* ciftiMappableDataFile, const int32_t mapIndex, const AString& parcelName, AString& errorMessageOut) { clear(); errorMessageOut.clear(); if (ciftiMappableDataFile == NULL) { errorMessageOut = "File is not valid (NULL)"; return false; } if ((mapIndex < 0) || (mapIndex >= ciftiMappableDataFile->getNumberOfMaps())) { errorMessageOut = ("Map index=" + AString::number(mapIndex) + " is invalid for file " + ciftiMappableDataFile->getFileNameNoPath()); return false; } const CiftiParcelsMap* ciftiParcelsMap = ciftiMappableDataFile->getCiftiParcelsMapForBrainordinateMapping(); return setWithCiftiParcelBrainordinates(ciftiMappableDataFile, ciftiParcelsMap, parcelName, errorMessageOut); } /** * Set the region of interest to the brainordinates in the given named parcel * from the given CIFTI parcels map in the given CIFTI file. * * @param ciftiMappableDataFile * The CIFTI file. * @param ciftiParcelsMap * The CIFTI Parcels Map. * @param parcelName * Name of the parcel. * @param errorMessageOut * Will contain error message upon exit. * @return * True if successful. If failure, false is returned and errorMessageOut * will contain cause of failure. */ bool BrainordinateRegionOfInterest::setWithCiftiParcelBrainordinates(const CiftiMappableDataFile* ciftiMappableDataFile, const CiftiParcelsMap* ciftiParcelsMap, const AString& parcelName, AString& errorMessageOut) { if (parcelName.isEmpty()) { errorMessageOut = "Parcel name is empty."; return false; } if (ciftiParcelsMap == NULL) { errorMessageOut = ("No parcels map in " + ciftiMappableDataFile->getFileNameNoPath()); return false; } const int64_t parcelIndex = ciftiParcelsMap->getIndexFromNumberOrName(parcelName); if (parcelIndex < 0) { errorMessageOut = ("Parcel name=" + parcelName + " not found in parcels map for file " + ciftiMappableDataFile->getFileNameNoPath()); return false; } const std::vector& allParcels = ciftiParcelsMap->getParcels(); CaretAssertVectorIndex(allParcels, parcelIndex); const CiftiParcelsMap::Parcel& parcel = allParcels[parcelIndex]; for (std::map >::const_iterator iter = parcel.m_surfaceNodes.begin(); iter != parcel.m_surfaceNodes.end(); iter++) { const StructureEnum::Enum structure = iter->first; const std::set& nodeSet = iter->second; int64_t surfaceNumberOfNodes = ciftiParcelsMap->getSurfaceNumberOfNodes(structure); std::vector nodeVector(nodeSet.begin(), nodeSet.end()); setSurfaceNodes(structure, surfaceNumberOfNodes, nodeVector); } if (ciftiParcelsMap->hasVolumeData()) { const VolumeSpace& volumeSpace = ciftiParcelsMap->getVolumeSpace(); const std::set& voxelSetIJK = parcel.m_voxelIndices; for (std::set::iterator voxelIter = voxelSetIJK.begin(); voxelIter != voxelSetIJK.end(); voxelIter++) { const VoxelIJK& voxelIJK = *voxelIter; float xyz[3]; volumeSpace.indexToSpace(voxelIJK.m_ijk, xyz); m_voxelXYZ.push_back(xyz[0]); m_voxelXYZ.push_back(xyz[1]); m_voxelXYZ.push_back(xyz[2]); } if ( ! m_voxelXYZ.empty()) { VolumeSpace::OrientTypes orientation[3]; float origin[3]; volumeSpace.getOrientAndSpacingForPlumb(orientation, m_voxelSize, origin); m_voxelSize[0] = std::fabs(m_voxelSize[0]); m_voxelSize[1] = std::fabs(m_voxelSize[1]); m_voxelSize[2] = std::fabs(m_voxelSize[2]); /* * Voxel sizes must be non-negative */ CaretAssert(m_voxelSize[0] >= 0.0); CaretAssert(m_voxelSize[1] >= 0.0); CaretAssert(m_voxelSize[2] >= 0.0); } } return true; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString BrainordinateRegionOfInterest::toString() const { return "BrainordinateRegionOfInterest"; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* BrainordinateRegionOfInterest::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "BrainordinateRegionOfInterest", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void BrainordinateRegionOfInterest::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Files/BrainordinateRegionOfInterest.h000066400000000000000000000145031360521144700255700ustar00rootroot00000000000000#ifndef __BRAINORDINATE_REGION_OF_INTEREST_H__ #define __BRAINORDINATE_REGION_OF_INTEREST_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "SceneableInterface.h" #include "StructureEnum.h" namespace caret { class CaretMappableDataFile; class CiftiMappableDataFile; class CiftiParcelsMap; class SceneClassAssistant; class BrainordinateRegionOfInterest : public CaretObject, public SceneableInterface { public: BrainordinateRegionOfInterest(); virtual ~BrainordinateRegionOfInterest(); BrainordinateRegionOfInterest(const BrainordinateRegionOfInterest& obj); BrainordinateRegionOfInterest& operator=(const BrainordinateRegionOfInterest& obj); void clear(); bool hasSurfaceNodes() const; bool hasNodesForSurfaceStructure(const StructureEnum::Enum structure, const int64_t surfaceNumberOfNodes) const; const std::vector& getNodesForSurfaceStructure(const StructureEnum::Enum structure, const int64_t surfaceNumberOfNodes) const; bool hasVolumeVoxels() const; void getVolumeVoxelSize(float voxelSizeOut[3]) const; const std::vector& getVolumeVoxelsXYZ() const; void setSurfaceNodes(const StructureEnum::Enum structure, const int64_t surfaceNumberOfNodes, const std::vector& surfaceNodeIndices); void setVolumeVoxels(const float voxelSize[3], const std::vector& voxelsXYZ); bool isBrainordinateHighlightingEnabled() const; void setBrainordinateHighlightingEnabled(const bool highlighting); bool setWithLabelFileLabel(const CaretMappableDataFile* caretMappableDataFile, const int32_t mapIndex, const AString& labelName, AString& errorMessageOut); bool setWithCiftiParcelLoadingBrainordinates(const CiftiMappableDataFile* ciftiMappableDataFile, const int32_t mapIndex, const AString& parcelName, AString& errorMessageOut); bool setWithCiftiParcelMappingBrainordinates(const CiftiMappableDataFile* ciftiMappableDataFile, const int32_t mapIndex, const AString& parcelName, AString& errorMessageOut); // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implemetation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: void copyHelperBrainordinateRegionOfInterest(const BrainordinateRegionOfInterest& obj); bool setWithCiftiParcelBrainordinates(const CiftiMappableDataFile* ciftiMappableDataFile, const CiftiParcelsMap* ciftiParcelsMap, const AString& parcelName, AString& errorMessageOut); SceneClassAssistant* m_sceneAssistant; class SurfaceNodesInfo { public: SurfaceNodesInfo(const StructureEnum::Enum structure, const int64_t surfaceNumberOfNodes, const std::vector& surfaceNodeIndices) : m_structure(structure), m_surfaceNumberOfNodes(surfaceNumberOfNodes), m_surfaceNodeIndices(surfaceNodeIndices) { /* nothing */ } ~SurfaceNodesInfo() { } const StructureEnum::Enum m_structure; const int64_t m_surfaceNumberOfNodes; const std::vector m_surfaceNodeIndices; }; std::vector m_surfaceNodesInfo; float m_voxelSize[3]; std::vector m_voxelXYZ; static std::vector s_emptySurfaceNodes; bool m_highlighingEnabled; // ADD_NEW_MEMBERS_HERE }; #ifdef __BRAINORDINATE_REGION_OF_INTEREST_DECLARE__ std::vector BrainordinateRegionOfInterest::s_emptySurfaceNodes; #endif // __BRAINORDINATE_REGION_OF_INTEREST_DECLARE__ } // namespace #endif //__BRAINORDINATE_REGION_OF_INTEREST_H__ connectome-workbench-1.4.2/src/Files/CMakeLists.txt000077500000000000000000000175111360521144700222340ustar00rootroot00000000000000# # Name of project # PROJECT (Files) # # Add QT for includes # if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) include_directories(${Qt5Gui_INCLUDE_DIRS}) include_directories(${Qt5Network_INCLUDE_DIRS}) endif() IF (QT4_FOUND) SET(QT_DONT_USE_QTGUI) SET(QT_USE_QTNETWORK TRUE) INCLUDE(${QT_USE_FILE}) ENDIF () # # Files Library # ADD_LIBRARY(Files AffineFile.h AnnotationFile.h AnnotationFileXmlFormatBase.h AnnotationFileXmlReader.h AnnotationFileXmlWriter.h AnnotationTextSubstitutionFile.h Border.h BorderException.h BorderFile.h BorderLengthHelper.h BorderPointFromSearch.h BorderTracingHelper.h BrainordinateRegionOfInterest.h CaretDataFile.h CaretDataFileHelper.h CaretDataFileSelectionModel.h CaretMappableDataFile.h CaretMappableDataFileAndMapSelectionModel.h CaretSparseFile.h CaretVolumeExtension.h ChartableLineSeriesBrainordinateInterface.h ChartableLineSeriesInterface.h ChartableLineSeriesRowColumnInterface.h ChartableMatrixInterface.h ChartableMatrixParcelInterface.h ChartableMatrixSeriesInterface.h ChartableTwoFileDelegate.h ChartableTwoFileBaseChart.h ChartableTwoFileHistogramChart.h ChartableTwoFileLineSeriesChart.h ChartableTwoFileMatrixChart.h CiftiBrainordinateDataSeriesFile.h CiftiBrainordinateLabelFile.h CiftiBrainordinateScalarFile.h CiftiConnectivityMatrixDenseFile.h CiftiConnectivityMatrixDenseDynamicFile.h CiftiConnectivityMatrixDenseParcelFile.h CiftiConnectivityMatrixParcelFile.h CiftiConnectivityMatrixParcelDenseFile.h CiftiFiberOrientationFile.h CiftiFiberTrajectoryFile.h CiftiMappableDataFile.h CiftiMappableConnectivityMatrixDataFile.h CiftiParcelColoringModeEnum.h CiftiParcelLabelFile.h CiftiParcelReordering.h CiftiParcelReorderingModel.h CiftiParcelSeriesFile.h CiftiParcelScalarFile.h CiftiScalarDataSeriesFile.h ConnectivityDataLoaded.h ControlPointFile.h EventCaretDataFilesGet.h EventCaretMappableDataFileMapsViewedInOverlays.h EventCaretMappableDataFilesGet.h EventChartMatrixParcelYokingValidation.h EventGetDisplayedDataFiles.h EventMapYokingSelectMap.h EventMapYokingValidation.h EventSurfaceColoringInvalidate.h EventSurfaceStructuresValidGet.h Fiber.h FiberOrientation.h FiberOrientationColoringTypeEnum.h FiberOrientationTrajectory.h FiberTrajectoryColorModel.h FiberTrajectoryMapProperties.h FiberTrajectoryDisplayModeEnum.h FilePathNamePrefixCompactor.h FociFile.h FociFileSaxReader.h Focus.h GeodesicHelper.h GiftiTypeFile.h GroupAndNameCheckStateEnum.h GroupAndNameHierarchyGroup.h GroupAndNameHierarchyItem.h GroupAndNameHierarchyModel.h GroupAndNameHierarchyName.h ImageCaptureDimensionsModeEnum.h ImageCaptureSettings.h ImageFile.h ImageResolutionUnitsEnum.h ImageSpatialUnitsEnum.h LabelDrawingProperties.h LabelDrawingTypeEnum.h LabelFile.h MapYokingGroupEnum.h MetricDynamicConnectivityFile.h MetricFile.h MetricSmoothingObject.h NodeAndVoxelColoring.h OxfordSparseThreeFile.h PaletteFile.h RgbaFile.h RibbonMappingHelper.h SceneDataFileInfo.h SceneFile.h SceneFileSaxReader.h SceneFileXmlStreamBase.h SceneFileXmlStreamReader.h SceneFileXmlStreamWriter.h SignedDistanceHelper.h SparseVolumeIndexer.h SpecFile.h SpecFileDataFileTypeGroup.h SpecFileDataFile.h SpecFileSaxReader.h SceneFileXmlStreamFormatTester.h StudyMetaDataLink.h StudyMetaDataLinkSet.h StudyMetaDataLinkSetSaxReader.h SurfaceFile.h SurfacePlaneIntersectionToContour.h SurfaceProjectedItem.h SurfaceProjectedItemSaxReader.h SurfaceProjection.h SurfaceProjectionBarycentric.h SurfaceProjectionVanEssen.h SurfaceProjector.h SurfaceProjectorException.h SurfaceResamplingHelper.h SurfaceResamplingMethodEnum.h SurfaceTypeEnum.h TextFile.h TopologyHelper.h VolumeDynamicConnectivityFile.h VolumeEditingModeEnum.h VolumeFile.h VolumeFileEditorDelegate.h VolumeFileVoxelColorizer.h VolumeMapUndoCommand.h VolumePaddingHelper.h VolumeSliceProjectionTypeEnum.h VolumeSpline.h VtkFileExporter.h WarpfieldFile.h XmlStreamReaderHelper.h XmlStreamWriterHelper.h AffineFile.cxx AnnotationFile.cxx AnnotationFileXmlFormatBase.cxx AnnotationFileXmlReader.cxx AnnotationFileXmlWriter.cxx AnnotationTextSubstitutionFile.cxx Border.cxx BorderException.cxx BorderFile.cxx BorderLengthHelper.cxx BorderTracingHelper.cxx BrainordinateRegionOfInterest.cxx CaretDataFile.cxx CaretDataFileHelper.cxx CaretDataFileSelectionModel.cxx CaretMappableDataFile.cxx CaretMappableDataFileAndMapSelectionModel.cxx CaretSparseFile.cxx CaretVolumeExtension.cxx ChartableLineSeriesInterface.cxx ChartableMatrixInterface.cxx ChartableTwoFileDelegate.cxx ChartableTwoFileBaseChart.cxx ChartableTwoFileHistogramChart.cxx ChartableTwoFileLineSeriesChart.cxx ChartableTwoFileMatrixChart.cxx CiftiBrainordinateDataSeriesFile.cxx CiftiBrainordinateLabelFile.cxx CiftiBrainordinateScalarFile.cxx CiftiConnectivityMatrixDenseFile.cxx CiftiConnectivityMatrixDenseDynamicFile.cxx CiftiConnectivityMatrixDenseParcelFile.cxx CiftiConnectivityMatrixParcelFile.cxx CiftiConnectivityMatrixParcelDenseFile.cxx CiftiFiberOrientationFile.cxx CiftiFiberTrajectoryFile.cxx CiftiMappableDataFile.cxx CiftiMappableConnectivityMatrixDataFile.cxx CiftiParcelColoringModeEnum.cxx CiftiParcelLabelFile.cxx CiftiParcelReordering.cxx CiftiParcelReorderingModel.cxx CiftiParcelSeriesFile.cxx CiftiParcelScalarFile.cxx CiftiScalarDataSeriesFile.cxx ConnectivityDataLoaded.cxx ControlPointFile.cxx EventCaretDataFilesGet.cxx EventCaretMappableDataFileMapsViewedInOverlays.cxx EventCaretMappableDataFilesGet.cxx EventChartMatrixParcelYokingValidation.cxx EventGetDisplayedDataFiles.cxx EventMapYokingSelectMap.cxx EventMapYokingValidation.cxx EventSurfaceColoringInvalidate.cxx EventSurfaceStructuresValidGet.cxx Fiber.cxx FiberOrientation.cxx FiberOrientationColoringTypeEnum.cxx FiberOrientationTrajectory.cxx FiberTrajectoryColorModel.cxx FiberTrajectoryDisplayModeEnum.cxx FiberTrajectoryMapProperties.cxx FilePathNamePrefixCompactor.cxx FociFile.cxx FociFileSaxReader.cxx Focus.cxx GeodesicHelper.cxx GiftiTypeFile.cxx GroupAndNameCheckStateEnum.cxx GroupAndNameHierarchyGroup.cxx GroupAndNameHierarchyItem.cxx GroupAndNameHierarchyModel.cxx GroupAndNameHierarchyName.cxx ImageCaptureDimensionsModeEnum.cxx ImageCaptureSettings.cxx ImageFile.cxx ImageResolutionUnitsEnum.cxx ImageSpatialUnitsEnum.cxx LabelDrawingProperties.cxx LabelDrawingTypeEnum.cxx LabelFile.cxx MapYokingGroupEnum.cxx MetricDynamicConnectivityFile.cxx MetricFile.cxx MetricSmoothingObject.cxx NodeAndVoxelColoring.cxx OxfordSparseThreeFile.cxx PaletteFile.cxx RgbaFile.cxx RibbonMappingHelper.cxx SceneDataFileInfo.cxx SceneFile.cxx SceneFileSaxReader.cxx SceneFileXmlStreamBase.cxx SceneFileXmlStreamFormatTester.cxx SceneFileXmlStreamReader.cxx SceneFileXmlStreamWriter.cxx SignedDistanceHelper.cxx SparseVolumeIndexer.cxx SpecFile.cxx SpecFileDataFileTypeGroup.cxx SpecFileDataFile.cxx SpecFileSaxReader.cxx StudyMetaDataLink.cxx StudyMetaDataLinkSet.cxx StudyMetaDataLinkSetSaxReader.cxx SurfaceFile.cxx SurfacePlaneIntersectionToContour.cxx SurfaceProjectedItem.cxx SurfaceProjectedItemSaxReader.cxx SurfaceProjection.cxx SurfaceProjectionBarycentric.cxx SurfaceProjectionVanEssen.cxx SurfaceProjector.cxx SurfaceProjectorException.cxx SurfaceResamplingHelper.cxx SurfaceResamplingMethodEnum.cxx SurfaceTypeEnum.cxx TextFile.cxx TopologyHelper.cxx VolumeDynamicConnectivityFile.cxx VolumeEditingModeEnum.cxx VolumeFile.cxx VolumeFileEditorDelegate.cxx VolumeFileVoxelColorizer.cxx VolumeMapUndoCommand.cxx VolumePaddingHelper.cxx VolumeSliceProjectionTypeEnum.cxx VolumeSpline.cxx VtkFileExporter.cxx WarpfieldFile.cxx XmlStreamReaderHelper.cxx XmlStreamWriterHelper.cxx ) TARGET_LINK_LIBRARIES(Files ${CARET_QT5_LINK}) # # Find Headers # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Annotations ${CMAKE_SOURCE_DIR}/Charting ${CMAKE_SOURCE_DIR}/Files ${CMAKE_SOURCE_DIR}/FilesBase ${CMAKE_SOURCE_DIR}/Graphics ${CMAKE_SOURCE_DIR}/Cifti ${CMAKE_SOURCE_DIR}/Palette ${CMAKE_SOURCE_DIR}/Gifti ${CMAKE_SOURCE_DIR}/Nifti ${CMAKE_SOURCE_DIR}/QxtCore ${CMAKE_SOURCE_DIR}/Scenes ${CMAKE_SOURCE_DIR}/Xml ${CMAKE_SOURCE_DIR}/Common ) connectome-workbench-1.4.2/src/Files/CaretDataFile.cxx000066400000000000000000000327111360521144700226440ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CARET_DATA_FILE_DECLARE__ #include "CaretDataFile.h" #undef __CARET_DATA_FILE_DECLARE__ #include "CaretMappableDataFile.h" #include "DataFileContentInformation.h" #include "SceneClass.h" using namespace caret; /** * \class caret::CaretDataFile * \brief A data file with abstract methods for caret data * * This class is essentially an interface that defines methods * that are supported by most Caret Data Files. */ /** * Constructor. */ CaretDataFile::CaretDataFile(const DataFileTypeEnum::Enum dataFileType) : DataFile(), SceneableInterface() { m_dataFileType = dataFileType; AString name = ("untitled_" + AString::number(s_defaultFileNameCounter) + "." + DataFileTypeEnum::toFileExtension(m_dataFileType)); s_defaultFileNameCounter++; setFileNameProtected(name); } /** * Destructor. */ CaretDataFile::~CaretDataFile() { } /** * @return The type of this data file. */ DataFileTypeEnum::Enum CaretDataFile::getDataFileType() const { return m_dataFileType; } /** * Override the default data type for the file. * Use this with extreme caution as using a type invalid * with the file may cause disaster. * * @param dataFileType * New value for file's data type. */ void CaretDataFile::setDataFileType(const DataFileTypeEnum::Enum dataFileType) { m_dataFileType = dataFileType; } /** * Copy constructor. * @param cdf * Instance that is copied to this. */ CaretDataFile::CaretDataFile(const CaretDataFile& cdf) : DataFile(cdf), SceneableInterface(cdf) { copyDataCaretDataFile(cdf); } /** * Assignment operator. * @param cdf * Instance that is assigned to this. */ CaretDataFile& CaretDataFile::operator=(const CaretDataFile& cdf) { if (this != &cdf) { DataFile::operator=(cdf); copyDataCaretDataFile(cdf); } return *this; } /** * Assists with copying instances of this class. * @param cdf * Instance that is copied to this. */ void CaretDataFile::copyDataCaretDataFile(const CaretDataFile& cdf) { m_dataFileType = cdf.m_dataFileType; } /** * @return Is this file mapped to a valid single structure ? */ bool CaretDataFile::isSingleStructure() const { return StructureEnum::isSingleStructure(getStructure()); } /** * Add information about the file to the data file information. * * @param dataFileInformation * Consolidates information about a data file. */ void CaretDataFile::addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) { DataFile::addToDataFileContentInformation(dataFileInformation); const DataFileTypeEnum::Enum dataFileType = getDataFileType(); bool validExtensionFlag = false; const DataFileTypeEnum::Enum extensionFileType = DataFileTypeEnum::fromFileExtension(getFileName(), &validExtensionFlag); if (dataFileType != extensionFileType) { const AString msg("Incorrect filename extension. It should be \"" + DataFileTypeEnum::toFileExtension(dataFileType) + "\""); dataFileInformation.addNameAndValue("WARNING EXTENSION", msg); } dataFileInformation.addNameAndValue("Type", DataFileTypeEnum::toGuiName(m_dataFileType)); std::vector allStructures; StructureEnum::getAllEnums(allStructures); CaretMappableDataFile* cmdf = dynamic_cast(this); if (cmdf != NULL) { AString structureNames; for (std::vector::iterator iter = allStructures.begin(); iter != allStructures.end(); iter++) { if (cmdf->isMappableToSurfaceStructure(*iter)) { structureNames.append(StructureEnum::toGuiName(*iter) + " "); } } dataFileInformation.addNameAndValue("Structure", structureNames); } else { dataFileInformation.addNameAndValue("Structure", StructureEnum::toGuiName(getStructure())); } } /** * Set the username and password for reading files, typically from * a database or website. * * @param username * Account's username. * @param password * Account's password. */ void CaretDataFile::setFileReadingUsernameAndPassword(const AString& username, const AString& password) { s_fileReadingUsername = username; s_fileReadingPassword = password; } /** * @return The username for file reading from database or website. */ AString CaretDataFile::getFileReadingUsername() { return s_fileReadingUsername; } /** * @return The password for file reading from database or website. */ AString CaretDataFile::getFileReadingPassword() { return s_fileReadingPassword; } /** * Create a scene for an instance of a class. * * NOTE: In most cases, subclasses should not override this method but * instead override saveFileDataToScene() use it to add data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. If there is no data for the scene, a NULL pointer * will be returned. */ SceneClass* CaretDataFile::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "CaretDataFile", 1); saveFileDataToScene(sceneAttributes, sceneClass); if (sceneClass->getNumberOfObjects() <= 0) { delete sceneClass; sceneClass = NULL; } // const int32_t numMaps = getNumberOfMaps(); // if (numMaps > 0) { // bool* mapEnabledArray = new bool[numMaps]; // for (int32_t i = 0; i < numMaps; i++) { // mapEnabledArray[i] = m_mapContent[i]->m_dataLoadingEnabled; // } // // sceneClass->addBooleanArray("mapEnabled", // mapEnabledArray, // numMaps); // delete[] mapEnabledArray; // } return sceneClass; } /** * Restore the state of an instance of a class. * * * NOTE: In most cases, subclasses should not override this method but * instead override restoreFileDataFromScene() use it to access * data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. May be NULL for some types of scenes. */ void CaretDataFile::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } /* * Resoration of file data from the scene may cause * a modified palette status if the palette color * mapping was saved to the scene. We want to * keep this modified status so that if the scene * is resaved, the modified palette information * is added to the scene. */ restoreFileDataFromScene(sceneAttributes, sceneClass); } /** * Save file data from the scene. For subclasses that need to * save to a scene, this method should be overriden. sceneClass * will be valid and any scene data should be added to it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. */ void CaretDataFile::saveFileDataToScene(const SceneAttributes* /*sceneAttributes*/, SceneClass* /*sceneClass*/) { /* Nothing as subclasses needing to save to scenes will override. */ } /** * Restore file data from the scene. For subclasses that need to * restore from a scene, this method should be overridden. The scene class * will be valid and any scene data may be obtained from it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void CaretDataFile::restoreFileDataFromScene(const SceneAttributes* /*sceneAttributes*/, const SceneClass* /*sceneClass*/) { /* Nothing as subclasses needing to restore from scenes will override. */ } /** * @return True if this file type supports writing, else false. * * By default, this method returns true. Files that do not support * writing should override this method and return false. */ bool CaretDataFile::supportsWriting() const { return true; } /** * @return The name of the file with both the file's path and * filename's extension removed. * * First, the filename is tested to see if it ends with any of the valid * file extensions for the DataFileTypeEnum. If any of the extensions match, * the filename, with the extension removed, is returned. The valud * file extensions are used since many GIFTI and CIFTI files contain * a "." in their extensions (eg: .surf.gii .dconn.nii). * * /mnt/path/anatomical.surf.gii "returns" anatomical * * Second, the last "/" (directory separator) is found to locate where * the name of the file, excluding the path, is located. Using just * the name of the file, anything before the last "." is returned. * removed. * * Third, if there is not "." in the name of the file * the equivalent of getFileName() is returned. */ AString CaretDataFile::getFileNameNoPathNoExtension() const { AString nameNoExt = getFileNameNoExtension(); const int lastSlashIndex = std::max(nameNoExt.lastIndexOf("/"), nameNoExt.lastIndexOf("\\")); if (lastSlashIndex >= 0) { if ((lastSlashIndex + 1) < nameNoExt.length()) { nameNoExt = nameNoExt.mid(lastSlashIndex + 1); } } return nameNoExt; } /** * @return The name (and path if present) of the file with the * filename's extension removed. * * First, the filename is tested to see if it ends with any of the valid * file extensions for the DataFileTypeEnum. If any of the extensions match, * the filename, with the extension removed, is returned. The valud * file extensions are used since many GIFTI and CIFTI files contain * a "." in their extensions (eg: .surf.gii .dconn.nii). * * /mnt/path/anatomical.surf.gii "returns" /mnt/path/anatomical * * Second, the last "/" (directory separator) is found to locate where * the name of the file, excluding the path, is located. Using just * the name of the file, anything before the last "." is returned. * removed. * * Third, if there is not "." in the name of the file * the equivalent of getFileName() is returned. */ AString CaretDataFile::getFileNameNoExtension() const { AString name = getFileName(); std::vector dataFileTypeExtensions = DataFileTypeEnum::getAllFileExtensions(getDataFileType()); /* * Test using file type extensions */ for (std::vector::iterator iter = dataFileTypeExtensions.begin(); iter != dataFileTypeExtensions.end(); iter++) { const AString ext = *iter; const int offset = name.lastIndexOf(ext); if (offset > 0) { name.resize(offset - 1); return name; } } /* * Look for the last "." and the last forward slash or back slash * * Dont' was to chop off a "." in the path (eg: /mnt/back.up/file) */ const int lastSlashIndex = std::max(name.lastIndexOf("/"), name.lastIndexOf("\\")); const int dotIndex = name.lastIndexOf("."); if (lastSlashIndex > 0) { if (dotIndex > lastSlashIndex) { name.resize(dotIndex); } } else { if (dotIndex > 0) { name.resize(dotIndex); } } return name; } connectome-workbench-1.4.2/src/Files/CaretDataFile.h000066400000000000000000000100711360521144700222640ustar00rootroot00000000000000#ifndef __CARET_DATA_FILE__H_ #define __CARET_DATA_FILE__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "DataFile.h" #include "DataFileTypeEnum.h" #include "SceneableInterface.h" #include "StructureEnum.h" namespace caret { class GiftiMetaData; class CaretDataFile : public DataFile, public SceneableInterface { public: CaretDataFile(const DataFileTypeEnum::Enum dataFileType); virtual ~CaretDataFile(); virtual bool isSingleStructure() const; /** * @return The structure for this file. */ virtual StructureEnum::Enum getStructure() const = 0; /** * Set the structure for this file. * @param structure * New structure for this file. */ virtual void setStructure(const StructureEnum::Enum structure) = 0; DataFileTypeEnum::Enum getDataFileType() const; /** * @return Get access to the file's metadata. */ virtual GiftiMetaData* getFileMetaData() = 0; /** * @return Get access to unmodifiable file's metadata. */ virtual const GiftiMetaData* getFileMetaData() const = 0; virtual AString getFileNameNoExtension() const; virtual AString getFileNameNoPathNoExtension() const; virtual void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation); virtual bool supportsWriting() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); static void setFileReadingUsernameAndPassword(const AString& username, const AString& password); static AString getFileReadingUsername(); static AString getFileReadingPassword(); protected: CaretDataFile(const CaretDataFile& cdf); CaretDataFile& operator=(const CaretDataFile& cdf); void setDataFileType(const DataFileTypeEnum::Enum dataFileType); virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: void copyDataCaretDataFile(const CaretDataFile& cdf); DataFileTypeEnum::Enum m_dataFileType; /** A counter that is used when creating default file names */ static int64_t s_defaultFileNameCounter; static AString s_fileReadingUsername; static AString s_fileReadingPassword; }; #ifdef __CARET_DATA_FILE_DECLARE__ int64_t CaretDataFile::s_defaultFileNameCounter = 1; AString CaretDataFile::s_fileReadingUsername = ""; AString CaretDataFile::s_fileReadingPassword = ""; #endif // __CARET_DATA_FILE_DECLARE__ } // namespace #endif //__CARET_DATA_FILE__H_ connectome-workbench-1.4.2/src/Files/CaretDataFileHelper.cxx000066400000000000000000000421641360521144700240070ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CARET_DATA_FILE_HELPER_DECLARE__ #include "CaretDataFileHelper.h" #undef __CARET_DATA_FILE_HELPER_DECLARE__ #include "AnnotationFile.h" #include "AnnotationTextSubstitutionFile.h" #include "BorderFile.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CiftiBrainordinateDataSeriesFile.h" #include "CiftiBrainordinateLabelFile.h" #include "CiftiBrainordinateScalarFile.h" #include "CiftiConnectivityMatrixDenseFile.h" #include "CiftiConnectivityMatrixDenseDynamicFile.h" #include "CiftiConnectivityMatrixDenseParcelFile.h" #include "CiftiConnectivityMatrixParcelDenseFile.h" #include "CiftiConnectivityMatrixParcelFile.h" #include "CiftiFile.h" #include "CiftiParcelLabelFile.h" #include "CiftiParcelScalarFile.h" #include "CiftiParcelSeriesFile.h" #include "CiftiFiberOrientationFile.h" #include "CiftiFiberTrajectoryFile.h" #include "CiftiScalarDataSeriesFile.h" #include "FileInformation.h" #include "FociFile.h" #include "ImageFile.h" #include "LabelFile.h" #include "MetricFile.h" #include "PaletteFile.h" #include "RgbaFile.h" #include "SceneFile.h" #include "SpecFile.h" #include "SurfaceFile.h" #include "VolumeFile.h" #include "nifti2.h" using namespace caret; /** * \class caret::CaretDataFileHelper * \brief Contains static methods to help out with CaretDataFile subclasses. * \ingroup Files */ /** * Constructor. */ CaretDataFileHelper::CaretDataFileHelper() { } /** * Destructor. */ CaretDataFileHelper::~CaretDataFileHelper() { } /** * Read any CaretDataFile subclass. * * @param filename * Name of file. * @return * Pointer to the data file after reading the file. * @throw * DataFileException if unable to read the file for any reason. */ CaretDataFile* CaretDataFileHelper::readAnyCaretDataFile(const AString& filename, const bool& preferOnDisk) { bool isValid = false; const DataFileTypeEnum::Enum dataFileType = DataFileTypeEnum::fromFileExtension(filename, &isValid); CaretDataFile* caretDataFile = NULL; DataFileException dataFileException; bool dataFileExceptionValid = false; /* * If filename's extension is valid, try to read * the file using the matching file type. */ if (isValid && (dataFileType != DataFileTypeEnum::UNKNOWN)) { caretDataFile = createCaretDataFileForFileType(dataFileType); CaretAssert(caretDataFile); try { readCaretDataFile(caretDataFile, filename, preferOnDisk); } catch (const DataFileException& dfe) { delete caretDataFile; caretDataFile = NULL; dataFileException = dfe; dataFileExceptionValid = true; } } else { dataFileException = DataFileException(filename, "Filename extension does not match any supported data file."); dataFileExceptionValid = true; } if (caretDataFile == NULL) { /* * Examine contents of file to determine file type. * Filename could have wrong extension. */ const DataFileTypeEnum::Enum dataFileType = getDataFileTypeFromFileContent(filename); if (dataFileType != DataFileTypeEnum::UNKNOWN) { caretDataFile = createCaretDataFileForFileType(dataFileType); CaretAssert(dataFileType); CaretLogInfo("File " + filename + " appears to be of type " + DataFileTypeEnum::toGuiName(dataFileType) + " from examination of file content."); try { readCaretDataFile(caretDataFile, filename, preferOnDisk); /* * File was read successfully, exception no longer valid */ dataFileExceptionValid = false; } catch (const DataFileException& dfe) { delete caretDataFile; caretDataFile = NULL; /* * Do not override exception from reading * using the file's extension */ if ( ! dataFileExceptionValid) { dataFileException = dfe; dataFileExceptionValid = true; } } } else { CaretAssert(dataFileExceptionValid); } } if (dataFileExceptionValid) { throw dataFileException; } CaretAssert(caretDataFile); // if (( ! isValid) // || (dataFileType == DataFileTypeEnum::UNKNOWN)) { // throw DataFileException(filename, // "Filename extension does not match any supported data file."); // } // try { // if (preferOnDisk) caretDataFile->setPreferOnDiskReading(true);//NOTE: because Dense Connectivity also pays attention to this, never change default behaviors away from on disk // try { // caretDataFile->readFile(filename); // } // catch (const std::bad_alloc& badAlloc) { // /* // * This DataFileException will be caught // * in the outer try/catch and it will // * clean up to avoid memory leaks. // */ // throw DataFileException(filename, // createBadAllocExceptionMessage(filename)); // } // } // catch (const DataFileException& dfe) { // delete caretDataFile; // caretDataFile = NULL; // // DataFileTypeEnum::Enum dft = getDataFileTypeFromFileContent(filename); // std::cout << "File " << filename << " may be " << DataFileTypeEnum::toGuiName(dft) << std::endl; // // throw dfe; // // } return caretDataFile; } /** * Read the given data file using the given filename. * * @param caretDataFile * Caret data file instance into which data is read. * @param filename * Name of the file. * @throw * DataFileException if unable to read the file for any reason. */ void CaretDataFileHelper::readCaretDataFile(CaretDataFile* caretDataFile, const AString& filename, const bool& preferOnDisk) { try { if (preferOnDisk) caretDataFile->setPreferOnDiskReading(true);//NOTE: because Dense Connectivity also pays attention to this, never change default behaviors away from on disk try { caretDataFile->readFile(filename); } catch (const std::bad_alloc&) { /* * This DataFileException will be caught * in the outer try/catch and it will * clean up to avoid memory leaks. */ throw DataFileException(filename, createBadAllocExceptionMessage(filename)); } } catch (const DataFileException& dfe) { throw dfe; } } /** * Creates a useful error message when a std::bad_alloc exception occurs. * * @param filename * Name of file that caused the std::bad_alloc exception. * @return * Message with info about the file. */ AString CaretDataFileHelper::createBadAllocExceptionMessage(const AString& filename) { FileInformation fileInfo(filename); AString message("Unable to allocate memory for reading the file."); if (fileInfo.exists()) { // float bytes = (float)fileInfo.size(); // short index = 0; // static const char *labels[9] = {" Bytes", " Kilobytes", " Megabytes", " Gigabytes", " Terabytes", " Petabytes", " Exabytes", " Zettabytes", " Yottabytes"}; // while (index < 8 && bytes > 1000.0f) // { // ++index; // bytes = bytes / 1000.0f;//using 1024 would make it Kibibytes, etc // } // AString sizeString = AString::number(bytes, 'f', 2) + labels[index];//2 digits after decimal point const AString sizeString = FileInformation::fileSizeToStandardUnits(fileInfo.size()); message.appendWithNewLine("File Size: " + sizeString); message.appendWithNewLine(""); message.appendWithNewLine("Note: The amount of memory required to read a data file may be " "substantially larger than the size of the file due to the way the " "file's data is organized in memory or compression of data within the file."); } return message; } /** * Create an instance of a caret data file matching the given data file type. * * @param dataFileType * Type of data file. * @return * New instance of file except if type is UNKNOWN which returns NULL. */ CaretDataFile* CaretDataFileHelper::createCaretDataFileForFileType(const DataFileTypeEnum::Enum dataFileType) { CaretDataFile* caretDataFile = NULL; switch (dataFileType) { case DataFileTypeEnum::ANNOTATION: caretDataFile = new AnnotationFile(); break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: caretDataFile = new AnnotationTextSubstitutionFile(); break; case DataFileTypeEnum::BORDER: caretDataFile = new BorderFile(); break; case DataFileTypeEnum::CONNECTIVITY_DENSE: caretDataFile = new CiftiConnectivityMatrixDenseFile(); break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: CaretAssertMessage(0, "Never create a dense dynamic file."); break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: caretDataFile = new CiftiBrainordinateLabelFile(); break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: caretDataFile = new CiftiConnectivityMatrixDenseParcelFile(); break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: caretDataFile = new CiftiBrainordinateScalarFile(); break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: caretDataFile = new CiftiBrainordinateDataSeriesFile(); break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: caretDataFile = new CiftiFiberOrientationFile(); break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: caretDataFile = new CiftiFiberTrajectoryFile(); break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: caretDataFile = new CiftiConnectivityMatrixParcelFile(); break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: caretDataFile = new CiftiConnectivityMatrixParcelDenseFile(); break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: caretDataFile = new CiftiParcelLabelFile(); break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: caretDataFile = new CiftiParcelScalarFile(); break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: caretDataFile = new CiftiParcelSeriesFile(); break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: caretDataFile = new CiftiScalarDataSeriesFile(); break; case DataFileTypeEnum::FOCI: caretDataFile = new FociFile(); break; case DataFileTypeEnum::IMAGE: caretDataFile = new ImageFile(); break; case DataFileTypeEnum::LABEL: caretDataFile = new LabelFile(); break; case DataFileTypeEnum::METRIC: caretDataFile = new MetricFile(); break; case DataFileTypeEnum::METRIC_DYNAMIC: CaretAssertMessage(0, "Never create a metric dynamic file"); break; case DataFileTypeEnum::PALETTE: caretDataFile = new PaletteFile(); break; case DataFileTypeEnum::RGBA: caretDataFile = new RgbaFile(); break; case DataFileTypeEnum::SCENE: caretDataFile = new SceneFile(); break; case DataFileTypeEnum::SPECIFICATION: caretDataFile = new SpecFile(); break; case DataFileTypeEnum::SURFACE: caretDataFile = new SurfaceFile(); break; case DataFileTypeEnum::UNKNOWN: CaretAssert(0); break; case DataFileTypeEnum::VOLUME: caretDataFile = new VolumeFile(); break; case DataFileTypeEnum::VOLUME_DYNAMIC: CaretAssertMessage(0, "Never create a Volume Dynamic file"); break; } return caretDataFile; } /** * Examine the content of a file to determine the file type. * * @param filename * Name of file. * @return * Type of file if it can be determined else the unknown file type. */ DataFileTypeEnum::Enum CaretDataFileHelper::getDataFileTypeFromFileContent(const AString& filename) { DataFileTypeEnum::Enum dataFileType = DataFileTypeEnum::UNKNOWN; if (DataFile::isFileOnNetwork(filename)) { return dataFileType; } if (filename.endsWith(".nii")) { try { CiftiFile ciftiFile; ciftiFile.openFile(filename); const CiftiXML ciftiXML = ciftiFile.getCiftiXML(); char intentName[16]; const int32_t intentType = ciftiXML.getIntentInfo(CiftiVersion(), intentName); switch (intentType) { case NIFTI_INTENT_CONNECTIVITY_UNKNOWN: // 3000; break; case NIFTI_INTENT_CONNECTIVITY_DENSE: // 3001; dataFileType = DataFileTypeEnum::CONNECTIVITY_DENSE; break; case NIFTI_INTENT_CONNECTIVITY_DENSE_SERIES: // 3002; dataFileType = DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES; break; case NIFTI_INTENT_CONNECTIVITY_PARCELLATED: // 3003; dataFileType = DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL; break; case NIFTI_INTENT_CONNECTIVITY_PARCELLATED_SERIES: // 3004; dataFileType = DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES; break; case NIFTI_INTENT_CONNECTIVITY_DENSE_TRAJECTORY: // 3005; dataFileType = DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY; break; case NIFTI_INTENT_CONNECTIVITY_DENSE_SCALARS: // 3006; dataFileType = DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR; break; case NIFTI_INTENT_CONNECTIVITY_DENSE_LABELS: // 3007; dataFileType = DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL; break; case NIFTI_INTENT_CONNECTIVITY_PARCELLATED_SCALAR: // 3008; dataFileType = DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR; break; case NIFTI_INTENT_CONNECTIVITY_PARCELLATED_DENSE: // 3009; dataFileType = DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE; break; case NIFTI_INTENT_CONNECTIVITY_DENSE_PARCELLATED: // 3010; dataFileType = DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL; break; // case NIFTI_INTENT_CONNECTIVITY_PARCELLATED_PARCELLATED_SERIES: // 3011; // dataFileType = DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES // break; // case NIFTI_INTENT_CONNECTIVITY_PARCELLATED_PARCELLATED_SCALAR: // 3012; // dataFileType = DataFileTypeEnum::CONNECTIVITY_DENSE; // break; default: CaretLogInfo(filename + " has unrecognized CIFTI intent type=" + AString::number(intentType)); break; } } catch (const DataFileException&) { CaretLogInfo(filename + " could not be read as a CIFTI file"); } } return dataFileType; } connectome-workbench-1.4.2/src/Files/CaretDataFileHelper.h000066400000000000000000000042711360521144700234310ustar00rootroot00000000000000#ifndef __CARET_DATA_FILE_HELPER_H__ #define __CARET_DATA_FILE_HELPER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AString.h" #include "DataFileTypeEnum.h" namespace caret { class CaretDataFile; class CaretDataFileHelper { public: static CaretDataFile* readAnyCaretDataFile(const AString& filename, const bool& preferOnDisk = false); static AString createBadAllocExceptionMessage(const AString& filename); static DataFileTypeEnum::Enum getDataFileTypeFromFileContent(const AString& filename); static CaretDataFile* createCaretDataFileForFileType(const DataFileTypeEnum::Enum dataFileType); private: CaretDataFileHelper(); virtual ~CaretDataFileHelper(); CaretDataFileHelper(const CaretDataFileHelper&); CaretDataFileHelper& operator=(const CaretDataFileHelper&); static void readCaretDataFile(CaretDataFile* caretDataFile, const AString& filename, const bool& preferOnDisk); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE }; #ifdef __CARET_DATA_FILE_HELPER_DECLARE__ // #endif // __CARET_DATA_FILE_HELPER_DECLARE__ } // namespace #endif //__CARET_DATA_FILE_HELPER_H__ connectome-workbench-1.4.2/src/Files/CaretDataFileSelectionModel.cxx000066400000000000000000000427201360521144700254740ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CARET_DATA_FILE_SELECTION_MODEL_DECLARE__ #include "CaretDataFileSelectionModel.h" #undef __CARET_DATA_FILE_SELECTION_MODEL_DECLARE__ #include "CaretAssert.h" #include "CaretDataFile.h" #include "CaretMappableDataFile.h" #include "ChartableMatrixParcelInterface.h" #include "EventCaretDataFilesGet.h" #include "EventCaretMappableDataFilesGet.h" #include "EventManager.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::CaretDataFileSelectionModel * \brief Selection model for a CaretDataFile. * \ingroup Files * * Maintains selection of a type of CaretDataFile. Used in the GUI * by CaretDataFileSelectionComboBox. */ /** * Constructor. This constructor is private and one of the static * factory methods should be used to create new instances of * this class. * * @param mappableDataFile * Mappable data file for matching brainordinates. * @param structure * Structure for the files. * @param fileMode * File mode that indicates how files are chosen. */ CaretDataFileSelectionModel::CaretDataFileSelectionModel(const CaretMappableDataFile* mappableDataFile, const StructureEnum::Enum structure, const FileMode fileMode) : CaretObject(), m_mappableDataFile(mappableDataFile), m_fileMode(fileMode), m_structure(structure) { switch (m_fileMode) { case FILE_MODE_DATA_FILE_TYPE_ENUM: break; case FILE_MODE_CHARTABLE_MATRIX_PARCEL_INTERFACE: break; case FILE_MODE_MAPS_TO_SAME_BRAINORDINATES: CaretAssert(m_mappableDataFile); break; case FILE_MODE_MULTI_STRUCTURE_BORDER_FILES: break; } m_overrideOfAvailableFilesValid = false; m_sceneAssistant = new SceneClassAssistant(); m_dataFileTypes.clear(); } /** * Destructor. */ CaretDataFileSelectionModel::~CaretDataFileSelectionModel() { delete m_sceneAssistant; } /** * Create a new instance of a Caret Data File Selection Model that * matches a mappable data file's brainordinate mapping. * * @param dataFileType * Type of the data file. */ CaretDataFileSelectionModel* CaretDataFileSelectionModel::newInstanceMapsToSameBrainordinates(const CaretMappableDataFile* mappableDataFile) { CaretDataFileSelectionModel* model = new CaretDataFileSelectionModel(mappableDataFile, StructureEnum::ALL, FILE_MODE_MAPS_TO_SAME_BRAINORDINATES); return model; } /** * Create a new instance of a Caret Data File Selection Model that * selects files of the given Data File Type. * * @param dataFileType * Type of the data file. */ CaretDataFileSelectionModel* CaretDataFileSelectionModel::newInstanceForCaretDataFileType(const DataFileTypeEnum::Enum dataFileType) { CaretDataFileSelectionModel* model = new CaretDataFileSelectionModel(NULL, StructureEnum::ALL, FILE_MODE_DATA_FILE_TYPE_ENUM); model->m_dataFileTypes.push_back(dataFileType); return model; } /** * Create a new instance of a Caret Data File Selection Model that * selects files of the given Data File Types. * * @param dataFileTypes * Types of the data file. */ CaretDataFileSelectionModel* CaretDataFileSelectionModel::newInstanceForCaretDataFileTypes(const std::vector& dataFileTypes) { CaretDataFileSelectionModel* model = new CaretDataFileSelectionModel(NULL, StructureEnum::ALL, FILE_MODE_DATA_FILE_TYPE_ENUM); model->m_dataFileTypes.insert(model->m_dataFileTypes.end(), dataFileTypes.begin(), dataFileTypes.end()); return model; } /** * Create a new instance of a Caret Data File Selection Model that * selects files of the given Data File Types for the given structure. * * @param structure * Structure for files. Files with the identical structure are used * as well as those files with structure 'ALL'. * @param dataFileTypes * Types of the data file. */ CaretDataFileSelectionModel* CaretDataFileSelectionModel::newInstanceForCaretDataFileTypesInStructure(const StructureEnum::Enum structure, const std::vector& dataFileTypes) { CaretDataFileSelectionModel* model = new CaretDataFileSelectionModel(NULL, structure, FILE_MODE_DATA_FILE_TYPE_ENUM); model->m_dataFileTypes.insert(model->m_dataFileTypes.end(), dataFileTypes.begin(), dataFileTypes.end()); return model; } /** * Create a new instance of a Caret Data File Selection Model that * selects files that implement the chartable matrix parcel interface. */ CaretDataFileSelectionModel* CaretDataFileSelectionModel::newInstanceForChartableMatrixParcelInterface() { CaretDataFileSelectionModel* model = new CaretDataFileSelectionModel(NULL, StructureEnum::ALL, FILE_MODE_CHARTABLE_MATRIX_PARCEL_INTERFACE); return model; } /** * Create a new instance of a Caret Data File Selection Model that * selectes multi-structure border files. */ CaretDataFileSelectionModel* CaretDataFileSelectionModel::newInstanceForMultiStructureBorderFiles() { CaretDataFileSelectionModel* model = new CaretDataFileSelectionModel(NULL, StructureEnum::ALL, FILE_MODE_MULTI_STRUCTURE_BORDER_FILES); return model; } /** * Copy constructor. * @param obj * Object that is copied. */ CaretDataFileSelectionModel::CaretDataFileSelectionModel(const CaretDataFileSelectionModel& obj) : CaretObject(obj), SceneableInterface(), m_mappableDataFile(obj.m_mappableDataFile), m_fileMode(obj.m_fileMode) { this->copyHelperCaretDataFileSelectionModel(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ CaretDataFileSelectionModel& CaretDataFileSelectionModel::operator=(const CaretDataFileSelectionModel& obj) { if (this != &obj) { CaretAssert(m_fileMode == obj.m_fileMode); CaretObject::operator=(obj); this->copyHelperCaretDataFileSelectionModel(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void CaretDataFileSelectionModel::copyHelperCaretDataFileSelectionModel(const CaretDataFileSelectionModel& obj) { m_structure = obj.m_structure; m_dataFileTypes = obj.m_dataFileTypes; m_selectedFile = obj.m_selectedFile; m_overrideOfAvailableFilesValid = obj.m_overrideOfAvailableFilesValid; m_overrideOfAvailableFiles = obj.m_overrideOfAvailableFiles; } /** * @return The selected file or NULL if no file is available. */ CaretDataFile* CaretDataFileSelectionModel::getSelectedFile() { updateSelection(); return m_selectedFile; } /** * @return The selected file or NULL if no file is available. */ const CaretDataFile* CaretDataFileSelectionModel::getSelectedFile() const { updateSelection(); return m_selectedFile; } /** * Set the selected file or NULL if no file is available. * * @param selectedFile * Set the selected file. */ void CaretDataFileSelectionModel::setSelectedFile(CaretDataFile* selectedFile) { m_selectedFile = selectedFile; } /** * @return Files available for selection. */ std::vector CaretDataFileSelectionModel::getAvailableFiles() const { if (m_overrideOfAvailableFilesValid) { return m_overrideOfAvailableFiles; } std::vector caretDataFiles; switch (m_fileMode) { case FILE_MODE_DATA_FILE_TYPE_ENUM: { caretDataFiles = EventCaretDataFilesGet::getCaretDataFilesForTypes(m_dataFileTypes); } break; case FILE_MODE_CHARTABLE_MATRIX_PARCEL_INTERFACE: { std::vector allFiles = EventCaretDataFilesGet::getAllCaretDataFiles(); for (auto dataFile : allFiles) { ChartableMatrixParcelInterface* chartParcelFile = dynamic_cast(dataFile); /* * Want files that ARE parcel chartable */ if (chartParcelFile != NULL) { CaretMappableDataFile* mapFile = chartParcelFile->getMatrixChartCaretMappableDataFile(); caretDataFiles.push_back(mapFile); } } } break; case FILE_MODE_MAPS_TO_SAME_BRAINORDINATES: { CaretAssert(m_mappableDataFile); EventCaretMappableDataFilesGet mapFilesGetEvent; EventManager::get()->sendEvent(mapFilesGetEvent.getPointer()); std::vector mapFiles; mapFilesGetEvent.getAllFiles(mapFiles); /* * Allow the same file to be included since this is used * by thresholding and may want to threshold with a map * in the same file. */ for (auto mf : mapFiles) { switch (m_mappableDataFile->getBrainordinateMappingMatch(mf)) { case CaretMappableDataFile::BrainordinateMappingMatch::EQUAL: caretDataFiles.push_back(mf); break; case CaretMappableDataFile::BrainordinateMappingMatch::NO: break; case CaretMappableDataFile::BrainordinateMappingMatch::SUBSET: caretDataFiles.push_back(mf); break; } } } break; case FILE_MODE_MULTI_STRUCTURE_BORDER_FILES: { std::vector borderFiles = EventCaretDataFilesGet::getCaretDataFilesForType(DataFileTypeEnum::BORDER); for (auto file : borderFiles) { if ( ! file->isSingleStructure()) { caretDataFiles.push_back(file); } } } break; } if (m_structure == StructureEnum::ALL) { return caretDataFiles; } std::vector caretDataFilesOut; for (std::vector::iterator iter = caretDataFiles.begin(); iter != caretDataFiles.end(); iter++) { CaretDataFile* cdf = *iter; const StructureEnum::Enum fileStructure = cdf->getStructure(); if ((fileStructure == StructureEnum::ALL) || (fileStructure == StructureEnum::INVALID)) { caretDataFilesOut.push_back(cdf); } else if (fileStructure == m_structure) { caretDataFilesOut.push_back(cdf); } } return caretDataFilesOut; } /** * Override the available files with the given files. Once this method * is called, these will be the available files until this method is called * again. * * @param availableFiles * Files that will be used in this model. */ void CaretDataFileSelectionModel::overrideAvailableDataFiles(std::vector& availableFiles) { m_overrideOfAvailableFiles = availableFiles; m_overrideOfAvailableFilesValid = true; } /** * @return Structure used in this model. */ StructureEnum::Enum CaretDataFileSelectionModel::getStructure() const { return m_structure; } /** * Set the structure used for this model. * * @param structure * New structure for this model. */ void CaretDataFileSelectionModel::setStructure(const StructureEnum::Enum structure) { m_structure = structure; updateSelection(); } /** * Update the selected file. */ void CaretDataFileSelectionModel::updateSelection() const { std::vector caretDataFiles = getAvailableFiles(); if (caretDataFiles.empty()) { m_selectedFile = NULL; return; } if (m_selectedFile != NULL) { if (std::find(caretDataFiles.begin(), caretDataFiles.end(), m_selectedFile) == caretDataFiles.end()) { m_selectedFile = NULL; } } if (m_selectedFile == NULL) { if (! caretDataFiles.empty()) { m_selectedFile = caretDataFiles[0]; } } } /** * Get a description of this object's content. * @return String describing this object's content. */ AString CaretDataFileSelectionModel::toString() const { return "CaretDataFileSelectionModel"; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* CaretDataFileSelectionModel::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "CaretDataFileSelectionModel", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); CaretDataFile* caretDataFile = getSelectedFile(); if (caretDataFile != NULL) { sceneClass->addPathName("selectedFileNameWithPath", caretDataFile->getFileName()); sceneClass->addString("selectedFileNameNoPath", caretDataFile->getFileNameNoPath()); } // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void CaretDataFileSelectionModel::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } setSelectedFile(NULL); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); bool foundFileFlag = false; const AString selectedFileNameWithPath = sceneClass->getPathNameValue("selectedFileNameWithPath"); if ( ! selectedFileNameWithPath.isEmpty()) { std::vector caretDataFiles = getAvailableFiles(); for (std::vector::iterator iter = caretDataFiles.begin(); iter != caretDataFiles.end(); iter++) { CaretDataFile* cdf = *iter; if (cdf->getFileName() == selectedFileNameWithPath) { setSelectedFile(cdf); foundFileFlag = true; break; } } } const AString selectedFileNameNoPath = sceneClass->getStringValue("selectedFileNameNoPath", ""); if ( ! foundFileFlag) { if ( ! selectedFileNameNoPath.isEmpty()) { std::vector caretDataFiles = getAvailableFiles(); for (std::vector::iterator iter = caretDataFiles.begin(); iter != caretDataFiles.end(); iter++) { CaretDataFile* cdf = *iter; if (cdf->getFileNameNoPath() == selectedFileNameNoPath) { setSelectedFile(cdf); break; } } } } //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Files/CaretDataFileSelectionModel.h000066400000000000000000000130651360521144700251210ustar00rootroot00000000000000#ifndef __CARET_DATA_FILE_SELECTION_MODEL_H__ #define __CARET_DATA_FILE_SELECTION_MODEL_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "DataFileTypeEnum.h" #include "SceneableInterface.h" #include "StructureEnum.h" namespace caret { class CaretDataFile; class CaretMappableDataFile; class SceneClassAssistant; class CaretDataFileSelectionModel : public CaretObject, public SceneableInterface { public: static CaretDataFileSelectionModel* newInstanceMapsToSameBrainordinates(const CaretMappableDataFile* mappableDataFile); static CaretDataFileSelectionModel* newInstanceForCaretDataFileType(const DataFileTypeEnum::Enum dataFileType); static CaretDataFileSelectionModel* newInstanceForCaretDataFileTypes(const std::vector& dataFileTypes); static CaretDataFileSelectionModel* newInstanceForCaretDataFileTypesInStructure( const StructureEnum::Enum structure, const std::vector& dataFileTypes); static CaretDataFileSelectionModel* newInstanceForChartableMatrixParcelInterface(); static CaretDataFileSelectionModel* newInstanceForMultiStructureBorderFiles(); virtual ~CaretDataFileSelectionModel(); CaretDataFileSelectionModel(const CaretDataFileSelectionModel& obj); CaretDataFileSelectionModel& operator=(const CaretDataFileSelectionModel& obj); CaretDataFile* getSelectedFile(); const CaretDataFile* getSelectedFile() const; StructureEnum::Enum getStructure() const; void setStructure(const StructureEnum::Enum structure); std::vector getAvailableFiles() const; void overrideAvailableDataFiles(std::vector& availableFiles); /** * @return Selected file dynamically cast to the templated * data file type. */ template inline T* getSelectedFileOfType() { CaretDataFile* cdf = getSelectedFile(); if (cdf != NULL) { return dynamic_cast(getSelectedFile()); } return NULL; } void setSelectedFile(CaretDataFile* selectedFile); // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implemetation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: enum FileMode { FILE_MODE_CHARTABLE_MATRIX_PARCEL_INTERFACE, FILE_MODE_DATA_FILE_TYPE_ENUM, FILE_MODE_MAPS_TO_SAME_BRAINORDINATES, FILE_MODE_MULTI_STRUCTURE_BORDER_FILES }; CaretDataFileSelectionModel(const CaretMappableDataFile* mappableDataFile, const StructureEnum::Enum structure, const FileMode fileMode); void copyHelperCaretDataFileSelectionModel(const CaretDataFileSelectionModel& obj); void updateSelection() const; const CaretMappableDataFile* m_mappableDataFile; const FileMode m_fileMode; std::vector m_overrideOfAvailableFiles; bool m_overrideOfAvailableFilesValid; StructureEnum::Enum m_structure; std::vector m_dataFileTypes; mutable CaretDataFile* m_selectedFile; SceneClassAssistant* m_sceneAssistant; // ADD_NEW_MEMBERS_HERE }; #ifdef __CARET_DATA_FILE_SELECTION_MODEL_DECLARE__ // #endif // __CARET_DATA_FILE_SELECTION_MODEL_DECLARE__ } // namespace #endif //__CARET_DATA_FILE_SELECTION_MODEL_H__ connectome-workbench-1.4.2/src/Files/CaretMappableDataFile.cxx000066400000000000000000001510631360521144700243100ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CARET_MAPPABLE_DATA_FILE_DECLARE__ #include "CaretMappableDataFile.h" #undef __CARET_MAPPABLE_DATA_FILE_DECLARE__ #include #include "CaretLogger.h" #include "ChartDataCartesian.h" #include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileHistogramChart.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "CiftiXML.h" #include "DataFileContentInformation.h" #include "EventManager.h" #include "FastStatistics.h" #include "FileInformation.h" #include "GiftiLabelTable.h" #include "GiftiMetaDataXmlElements.h" #include "Histogram.h" #include "LabelDrawingProperties.h" #include "NodeAndVoxelColoring.h" #include "PaletteColorMapping.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneAttributes.h" #include "ScenePrimitive.h" #include "StringTableModel.h" #include "VolumeFile.h" using namespace caret; /** * Constructor. */ CaretMappableDataFile::CaretMappableDataFile(const DataFileTypeEnum::Enum dataFileType) : CaretDataFile(dataFileType) { initializeCaretMappableDataFileInstance(dataFileType); } /** * Destructor. */ CaretMappableDataFile::~CaretMappableDataFile() { } /** * Constructor. * @param cmdf * Instance that is copied. */ CaretMappableDataFile::CaretMappableDataFile(const CaretMappableDataFile& cmdf) : CaretDataFile(cmdf) { initializeCaretMappableDataFileInstance(cmdf.getDataFileType()); this->copyCaretMappableDataFile(cmdf); } /** * Assignment operator. * @param cmdf * Instance that is assigned to this. * @return * Reference to this instance. */ CaretMappableDataFile& CaretMappableDataFile::operator=(const CaretMappableDataFile& cmdf) { if (this != &cmdf) { CaretDataFile::operator=(cmdf); this->copyCaretMappableDataFile(cmdf); } return *this; } /** * Initialize a new instance. * * @param dataFileType * Type of data file. */ void CaretMappableDataFile::initializeCaretMappableDataFileInstance(const DataFileTypeEnum::Enum /*dataFileType*/) { m_labelDrawingProperties = std::unique_ptr(new LabelDrawingProperties()); m_applyToAllMapsSelected = false; } /** * Assists with copying instances of this class. */ void CaretMappableDataFile::copyCaretMappableDataFile(const CaretMappableDataFile& cmdf) { *m_labelDrawingProperties = *cmdf.m_labelDrawingProperties; m_mapThresholdFileSelectionModels.clear(); } // note: method is documented in header file bool CaretMappableDataFile::hasMapAttributes() const { return true; } /** * Is this file able to map to the given structure? Some data files, such * as CIFTI files, are able to map to multiple surface structure. The default * implementation of this method simply compares the given structure to * getStructure() and returns true if they are the same value, else false. * * @param structure * Structure for testing mappability status. * @return True if this file is able to map to the given structure, else false. */ bool CaretMappableDataFile::isMappableToSurfaceStructure(const StructureEnum::Enum structure) const { if (getStructure() == StructureEnum::ALL) { return true; } if (structure == getStructure()) { return true; } return false; } // note: method is documented in header file int32_t CaretMappableDataFile::getMapIndexFromNameOrNumber(const AString& mapName) const { bool ok = false; int32_t ret = mapName.toInt(&ok) - 1;//compensate for 1-indexing that command line parsing uses if (ok) { if (ret < 0 || ret >= getNumberOfMaps()) { ret = -1; } } else {//DO NOT search by name if the string was parsed as an integer correctly, or some idiot who names their maps as integers will get confused //when getting map "12" out of a file after the file expands to more than 12 elements suddenly does something different ret = getMapIndexFromName(mapName); } return ret; } // note: method is documented in header file int32_t CaretMappableDataFile::getMapIndexFromName(const AString& mapName) const { int32_t numMaps = getNumberOfMaps(); for (int32_t i = 0; i < numMaps; ++i) { if (mapName == getMapName(i)) { return i; } } return -1; } // note: method is documented in header file int32_t CaretMappableDataFile::getMapIndexFromUniqueID(const AString& uniqueID) const { int32_t numMaps = getNumberOfMaps(); for (int32_t i = 0; i < numMaps; ++i) { if (uniqueID == getMapUniqueID(i)) { return i; } } return -1; } // note: method is documented in header file void CaretMappableDataFile::updateScalarColoringForAllMaps() { const int32_t numMaps = getNumberOfMaps(); for (int32_t iMap = 0; iMap < numMaps; iMap++) { updateScalarColoringForMap(iMap); } invalidateHistogramChartColoring(); } /** * @return True if this file is mapped using a palette and all palettes * are equal, otherwise false. */ bool CaretMappableDataFile::isPaletteColorMappingEqualForAllMaps() const { if ( ! isMappedWithPalette()) { return false; } const int32_t numMaps = getNumberOfMaps(); if (numMaps <= 0) { return false; } /* * Some files use one palette color mapping for all maps * and this can be detected if the pointer to palette * color mapping is the same for all maps. */ bool pointerTheSameFlag = true; const PaletteColorMapping* firstPCM = getMapPaletteColorMapping(0); for (int32_t iMap = 1; iMap < numMaps; iMap++) { if (firstPCM != getMapPaletteColorMapping(iMap)) { pointerTheSameFlag = false; break; } } if (pointerTheSameFlag) { return true; } /* * Compare each palette color mapping to the first palette color mapping */ for (int32_t iMap = 1; iMap < numMaps; iMap++) { if (*firstPCM != *getMapPaletteColorMapping(iMap)) { return false; } } return true; } /** * Apply palette coloring from the given map to all other maps in the file. * * @param mapIndex * Index of the map. */ void CaretMappableDataFile::applyPaletteColorMappingToAllMaps(const int32_t mapIndex) { if ( ! isMappedWithPalette()) { return; } const int32_t numMaps = getNumberOfMaps(); if (numMaps <= 1) { return; } const PaletteColorMapping* mapColoring = getMapPaletteColorMapping(mapIndex); for (int32_t i = 0; i < numMaps; i++) { if (i != mapIndex) { PaletteColorMapping* pcm = getMapPaletteColorMapping(i); pcm->copy(*mapColoring, false); } } } /** * Invalidate all histogram coloring for this file. */ void CaretMappableDataFile::invalidateHistogramChartColoring() { getChartingDelegate()->getHistogramCharting()->invalidateAllColoring(); } // note: method is documented in header file NiftiTimeUnitsEnum::Enum CaretMappableDataFile::getMapIntervalUnits() const { return NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN; } // note: method is documented in header file void CaretMappableDataFile::getMapIntervalStartAndStep(float& firstMapUnitsValueOut, float& mapIntervalStepValueOut) const { firstMapUnitsValueOut = 1.0; mapIntervalStepValueOut = 1.0; } /** * Get the minimum and maximum values from ALL maps in this file. * Note that not all files (due to size of file) are able to provide * the minimum and maximum values from the file. The return value * indicates success/failure. If the failure (false) is returned * the returned values are likely +/- the maximum float values. * * @param dataRangeMinimumOut * Minimum data value found. * @param dataRangeMaximumOut * Maximum data value found. * @return * True if the values are valid, else false. */ bool CaretMappableDataFile::getDataRangeFromAllMaps(float& dataRangeMinimumOut, float& dataRangeMaximumOut) const { dataRangeMaximumOut = std::numeric_limits::max(); dataRangeMinimumOut = -dataRangeMaximumOut; return false; } /** * Save file data from the scene. For subclasses that need to * save to a scene, this method should be overriden. sceneClass * will be valid and any scene data should be added to it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. */ void CaretMappableDataFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { CaretDataFile::saveFileDataToScene(sceneAttributes, sceneClass); sceneClass->addClass(m_labelDrawingProperties->saveToScene(sceneAttributes, "m_labelDrawingProperties")); if (m_chartingDelegate != NULL) { SceneClass* chartDelegateScene = m_chartingDelegate->saveToScene(sceneAttributes, "m_chartingDelegate"); if (chartDelegateScene != NULL) { sceneClass->addClass(chartDelegateScene); } } if (isMappedWithPalette()) { /* * 03 March 2017 * Note: Palette (m_paletteNormalizationMode) normalization is no * longer added to scenes since the palette normalization is a file * property stored in the file's metadata. */ /* * WB-690 request normalization mode be saved to scenes * so adding it back in. */ sceneClass->addEnumeratedType("m_paletteNormalizationMode", getPaletteNormalizationMode()); sceneClass->addBoolean("m_applyToAllMapsSelected", m_applyToAllMapsSelected); if (sceneAttributes->isModifiedPaletteSettingsSavedToScene()) { std::vector pcmClassVector; const int32_t numMaps = getNumberOfMaps(); for (int32_t i = 0; i < numMaps; i++) { const PaletteColorMapping* pcmConst = getMapPaletteColorMapping(i); bool savePaletteFlag = false; switch (pcmConst->getModifiedStatus()) { case PaletteModifiedStatusEnum::MODIFIED: savePaletteFlag = true; break; case PaletteModifiedStatusEnum::MODIFIED_BY_SHOW_SCENE: savePaletteFlag = true; break; case PaletteModifiedStatusEnum::UNMODIFIED: break; } if (savePaletteFlag) { PaletteColorMapping* pcm = const_cast(pcmConst); try { const AString xml = pcm->encodeInXML(); SceneClass* pcmClass = new SceneClass("savedPaletteColorMapping", "SavedPaletteColorMapping", 1); pcmClass->addString("mapName", getMapName(i)); pcmClass->addInteger("mapIndex", i); pcmClass->addInteger("mapCount", numMaps); pcmClass->addString("mapColorMapping", xml); pcmClassVector.push_back(pcmClass); } catch (const XmlException& e) { sceneAttributes->addToErrorMessage("Failed to encode palette color mapping for file: " + getFileNameNoPath() + " Map Name: " + getMapName(i) + " Map Index: " + AString::number(i) + ". " + e.whatString()); } } } if ( ! pcmClassVector.empty()) { SceneClassArray* pcmArray = new SceneClassArray("savedPaletteColorMappingArray", pcmClassVector); sceneClass->addChild(pcmArray); } } { /* * Save thresholds for each map */ SceneObjectMapIntegerKey* sceneThreshMap = new SceneObjectMapIntegerKey("m_mapThresholdFileSelectionModels", SceneObjectDataTypeEnum::SCENE_CLASS); const int32_t numMaps = getNumberOfMaps(); for (int32_t iMap = 0; iMap < numMaps; iMap++) { CaretMappableDataFileAndMapSelectionModel* threshSel = getMapThresholdFileSelectionModel(iMap); if ((threshSel->getSelectedFile() != this) || (threshSel->getSelectedMapIndex() != iMap)) { sceneThreshMap->addClass(iMap, threshSel->saveToScene(sceneAttributes, "threshSelElement")); } } if (sceneThreshMap->isEmpty()) { delete sceneThreshMap; } else { sceneClass->addChild(sceneThreshMap); } } } } /** * Restore file data from the scene. For subclasses that need to * restore from a scene, this method should be overridden. The scene class * will be valid and any scene data may be obtained from it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void CaretMappableDataFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { CaretDataFile::restoreFileDataFromScene(sceneAttributes, sceneClass); m_labelDrawingProperties->restoreFromScene(sceneAttributes, sceneClass->getClass("m_labelDrawingProperties")); const SceneClass* chartingDelegateClass = sceneClass->getClass("m_chartingDelegate"); ChartableTwoFileDelegate* chartDelegate = getChartingDelegate(); chartDelegate->updateAfterFileChanged(); if (chartingDelegateClass != NULL) { CaretAssert(chartDelegate); chartDelegate->restoreFromScene(sceneAttributes, chartingDelegateClass); } if (isMappedWithPalette()) { /* * Palette normalization was no longer saved to scenes after * palette normalization was saved in mappable files's metadata. */ std::vector paletteNormalizationModes; getPaletteNormalizationModesSupported(paletteNormalizationModes); if ( ! paletteNormalizationModes.empty()) { const AString paletteNormStringValue = sceneClass->getEnumeratedTypeValueAsString("m_paletteNormalizationMode"); if ( ! paletteNormStringValue.isEmpty()) { bool validFlag = false; const PaletteNormalizationModeEnum::Enum palNormValue = PaletteNormalizationModeEnum::fromName(paletteNormStringValue, &validFlag); if (validFlag) { if (std::find(paletteNormalizationModes.begin(), paletteNormalizationModes.end(), palNormValue) != paletteNormalizationModes.end()) { /* * Do not allow the metadata's modification status * to change or else many files will have a modified * status after restoration of the scene. */ const bool metadataModFlag = getFileMetaData()->isModified(); setPaletteNormalizationMode(palNormValue); if ( ! metadataModFlag) { getFileMetaData()->clearModified(); } } } } } const int32_t numMaps = getNumberOfMaps(); const SceneClassArray* pcmArray = sceneClass->getClassArray("savedPaletteColorMappingArray"); if (pcmArray != NULL) { const int32_t numElements = pcmArray->getNumberOfArrayElements(); for (int32_t i = 0; i < numElements; i++) { const SceneClass* pcmClass = pcmArray->getClassAtIndex(i); const AString mapName = pcmClass->getStringValue("mapName"); const int32_t mapIndex = pcmClass->getIntegerValue("mapIndex", -1); const int32_t mapCount = pcmClass->getIntegerValue("mapCount", -1); const AString pcmString = pcmClass->getStringValue("mapColorMapping"); int32_t restoreMapIndex = -1; /* * Try to find map that has the saved name AND index. */ if (restoreMapIndex < 0) { if ((mapIndex >= 0) && (mapIndex < numMaps)) { if (getMapName(mapIndex) == mapName) { restoreMapIndex = mapIndex; } } } /* * If map count has not changed, give preference to * map index over map name */ if (mapCount == numMaps) { /* * Try to find map that has the saved map index. */ if (restoreMapIndex < 0) { if ((mapIndex >= 0) && (mapIndex < numMaps)) { restoreMapIndex = mapIndex; } } /* * Try to find map that has the saved map name. */ if (restoreMapIndex < 0) { if ( ! mapName.isEmpty()) { restoreMapIndex = getMapIndexFromName(mapName); } } } else { /* * Try to find map that has the saved map name. */ if (restoreMapIndex < 0) { if ( ! mapName.isEmpty()) { restoreMapIndex = getMapIndexFromName(mapName); } } /* * Try to find map that has the saved map index. */ if (restoreMapIndex < 0) { if ((mapIndex >= 0) && (mapIndex < numMaps)) { restoreMapIndex = mapIndex; } } } if (restoreMapIndex >= 0) { try { PaletteColorMapping pcm; pcm.decodeFromStringXML(pcmString); PaletteColorMapping* pcmMap = getMapPaletteColorMapping(restoreMapIndex); pcmMap->copy(pcm, true); pcmMap->clearModified(); /* * WB-522 When palette loaded from scene, * mark it as modified. */ pcmMap->setSceneModified(); /* * Volume file needs it's map coloring updated since * palette has changed. */ VolumeFile* volumeFile = dynamic_cast(this); if (volumeFile != NULL) { volumeFile->updateScalarColoringForMap(restoreMapIndex); } } catch (const XmlException& e) { sceneAttributes->addToErrorMessage("Failed to decode palette color mapping for file: " + getFileNameNoPath() + " Map Name: " + getMapName(i) + " Map Index: " + AString::number(i) + ". " + e.whatString()); } } else { const AString msg = ("Unable to find map for restoring palette settings for file: " + getFileNameNoPath() + " Map Name: " + mapName + " Map Index: " + AString::number(mapIndex)); sceneAttributes->addToErrorMessage(msg); } } } { m_mapThresholdFileSelectionModels.clear(); const SceneObjectMapIntegerKey* sceneThreshMap = sceneClass->getMapIntegerKey("m_mapThresholdFileSelectionModels"); if (sceneThreshMap != NULL) { const std::vector keys = sceneThreshMap->getKeys(); for (auto mapIndex : keys) { CaretAssert(mapIndex < getNumberOfMaps()); const SceneClass* threshSel = dynamic_cast(sceneThreshMap->getObject(mapIndex)); CaretAssert(threshSel); getMapThresholdFileSelectionModel(mapIndex)->restoreFromScene(sceneAttributes, threshSel); } } } updateAfterFileDataChanges(); /* * Must restore after call to updateAfterFileDataChanges() to since * that method initializes 'm_applyToAllMapsSelected'. * * This was added by WB-781 Apply to All Maps for ColorBar so that * the 'apply to all maps' status is saved to and restored from scenes. */ const ScenePrimitive* applyToAllMapsPrimitive = sceneClass->getPrimitive("m_applyToAllMapsSelected"); if (applyToAllMapsPrimitive != NULL) { m_applyToAllMapsSelected = applyToAllMapsPrimitive->booleanValue(); } /* * README ABOUT IMPORTANCE OF MODIFIED COLOR PALLETTE MAPPING STATUS MUST REMAIN ON * * (1) The user may modify the palette color mapping for a map/file. This modified palette * color mapping is saved to the scene so that the user does not need to save the actual * data file. When the scene is restored, the palette color mapping is restored from the * scene and applied to the file. As a result, the file will contain a 'modified palette * color mapping status'. * * (2) This 'modified palette color mapping status' must remain ON so that if the user * saves a scene, the modified status is added to the scene and will be restored from * the scene at a later time. As a result, the scene will display correctly. * * (3) If the 'modified palette color mapping status' was NOT left on and the user * saved a scene, the scene would not display correctly due to the palette color mapping * no longer being added to the scene. */ } } /** * Add information about the file to the data file information. * * @param dataFileInformation * Consolidates information about a data file. */ void CaretMappableDataFile::addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) { CaretDataFile::addToDataFileContentInformation(dataFileInformation); const int64_t dataSizeInBytes = getDataSizeUncompressedInBytes(); if (dataSizeInBytes >= 0) { dataFileInformation.addNameAndValue("Data Size", FileInformation::fileSizeToStandardUnits(dataSizeInBytes)); } dataFileInformation.addNameAndValue("Maps to Surface", isSurfaceMappable()); dataFileInformation.addNameAndValue("Maps to Volume", isVolumeMappable()); dataFileInformation.addNameAndValue("Maps with LabelTable", isMappedWithLabelTable()); dataFileInformation.addNameAndValue("Maps with Palette", isMappedWithPalette()); if (isMappedWithPalette()) { dataFileInformation.addNameAndValue("All Map Palettes Equal", isPaletteColorMappingEqualForAllMaps()); NiftiTimeUnitsEnum::Enum timeUnits = getMapIntervalUnits(); switch (timeUnits) { case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: break; case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: break; case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: break; case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: break; case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: break; case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: break; } dataFileInformation.addNameAndValue("Map Interval Units", NiftiTimeUnitsEnum::toName(timeUnits)); if (timeUnits != NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN) { float mapIntervalStart, mapIntervalStep; getMapIntervalStartAndStep(mapIntervalStart, mapIntervalStep); dataFileInformation.addNameAndValue("Map Interval Start", mapIntervalStart); dataFileInformation.addNameAndValue("Map Interval Step", mapIntervalStep); } } bool showMapFlag = (isMappedWithLabelTable() || isMappedWithPalette()); /* * Do not show maps on CIFTI connectivity matrix data because * they do not have maps, they have a matrix. */ const bool ciftiMatrixFlag = (dynamic_cast(this) != NULL); if (ciftiMatrixFlag) { showMapFlag = false; } /* * Did user override display of map information? */ if ( ! dataFileInformation.isOptionFlag(DataFileContentInformation::OPTION_SHOW_MAP_INFORMATION)) { showMapFlag = false; } if (showMapFlag) { const int32_t numMaps = getNumberOfMaps(); dataFileInformation.addNameAndValue("Number of Maps", numMaps); if (numMaps > 0) { int columnCount = 0; const int COL_INDEX = columnCount++; int32_t COL_MIN = -1; int32_t COL_MAX = -1; int32_t COL_MEAN = -1; int32_t COL_DEV = -1; int32_t COL_PCT_POS = -1; int32_t COL_PCT_NEG = -1; int32_t COL_INF_NAN = -1; if (isMappedWithPalette()) { COL_MIN = columnCount++; COL_MAX = columnCount++; COL_MEAN = columnCount++; COL_DEV = columnCount++; COL_PCT_POS = columnCount++; COL_PCT_NEG = columnCount++; COL_INF_NAN = columnCount++; } const int COL_NAME = columnCount++; /* * Include a row for the column titles */ const int32_t tableRowCount = numMaps + 1; StringTableModel stringTable(tableRowCount, columnCount); stringTable.setElement(0, COL_INDEX, "Map"); if (COL_MIN >= 0) { stringTable.setElement(0, COL_MIN, "Minimum"); } if (COL_MAX >= 0) { stringTable.setElement(0, COL_MAX, "Maximum"); } if (COL_MEAN >= 0) { stringTable.setElement(0, COL_MEAN, "Mean"); } if (COL_DEV >= 0) { stringTable.setElement(0, COL_DEV, "Sample Dev"); } if (COL_PCT_POS >= 0) { stringTable.setElement(0, COL_PCT_POS, "% Positive"); } if (COL_PCT_NEG >= 0) { stringTable.setElement(0, COL_PCT_NEG, "% Negative"); } if (COL_INF_NAN >= 0) { stringTable.setElement(0, COL_INF_NAN, "Inf/NaN"); } stringTable.setElement(0, COL_NAME, "Map Name"); stringTable.setColumnAlignment(COL_NAME, StringTableModel::ALIGN_LEFT); for (int32_t mapIndex = 0; mapIndex < numMaps; mapIndex++) { const int32_t tableRow = mapIndex + 1; CaretAssert(COL_INDEX >= 0); CaretAssert(COL_NAME >= 0); stringTable.setElement(tableRow, COL_INDEX, (mapIndex + 1)); stringTable.setElement(tableRow, COL_NAME, getMapName(mapIndex)); const FastStatistics* stats = const_cast(this)->getMapFastStatistics(mapIndex); if (isMappedWithPalette() && (stats != NULL)) { const Histogram* histogram = getMapHistogram(mapIndex); int64_t posCount = 0; int64_t zeroCount = 0; int64_t negCount = 0; int64_t infCount = 0; int64_t negInfCount = 0; int64_t nanCount = 0; histogram->getCounts(posCount, zeroCount, negCount, infCount, negInfCount, nanCount); const int64_t numInfinityAndNotANumber = (infCount + negInfCount + nanCount); const double totalCount = (posCount + zeroCount + negCount + numInfinityAndNotANumber); const double pctPositive = (posCount / totalCount) * 100.0; const double pctNegative = (negCount / totalCount) * 100.0; if (COL_MIN >= 0) { stringTable.setElement(tableRow, COL_MIN, stats->getMin()); } if (COL_MAX >= 0) { stringTable.setElement(tableRow, COL_MAX, stats->getMax()); } if (COL_MEAN >= 0) { stringTable.setElement(tableRow, COL_MEAN, stats->getMean()); } if (COL_DEV >= 0) { stringTable.setElement(tableRow, COL_DEV, stats->getSampleStdDev()); } if (COL_PCT_POS >= 0) { stringTable.setElement(tableRow, COL_PCT_POS, pctPositive); } if (COL_PCT_NEG >= 0) { stringTable.setElement(tableRow, COL_PCT_NEG, pctNegative); } if (COL_INF_NAN >= 0) { stringTable.setElement(tableRow, COL_INF_NAN, numInfinityAndNotANumber); } } } dataFileInformation.addText("\n" + stringTable.getInString() + "\n"); } } if (showMapFlag) { if (isMappedWithLabelTable()) { /* * Show label table for each map. * However, some files contain only a single label table used * for all maps and this condition is detected if the first * two label tables use the same pointer. */ const int32_t numMaps = getNumberOfMaps(); bool haveLabelTableForEachMap = false; if (numMaps > 1) { if (getMapLabelTable(0) != getMapLabelTable(1)) { haveLabelTableForEachMap = true; } } for (int32_t mapIndex = 0; mapIndex < numMaps; mapIndex++) { const AString labelTableName = ("Label table for " + (haveLabelTableForEachMap ? ("map " + AString::number(mapIndex + 1) + ": " + getMapName(mapIndex)) : ("ALL maps")) + "\n"); dataFileInformation.addText(labelTableName + getMapLabelTable(mapIndex)->toFormattedString(" ") + "\n"); if ( ! haveLabelTableForEachMap) { break; } } } } } /** * @return File histogram number of buckets. */ int32_t CaretMappableDataFile::getFileHistogramNumberOfBuckets() const { /* * Metadata returns zero if integer value not found */ const GiftiMetaData* metadata = getFileMetaData(); CaretAssert(metadata); int32_t numBuckets = metadata->getInt(GiftiMetaDataXmlElements::HISTOGRAM_NUMBER_OF_BUCKETS); if (numBuckets <= 0) { numBuckets = 100; } return numBuckets; } /** * Set the file histogram number of buckets. * * @param numberOfBuckets * Number of buckets. */ void CaretMappableDataFile::setFileHistogramNumberOfBuckets(const int32_t numberOfBuckets) { GiftiMetaData* metadata = getFileMetaData(); CaretAssert(metadata); metadata->setInt(GiftiMetaDataXmlElements::HISTOGRAM_NUMBER_OF_BUCKETS, numberOfBuckets); } /** * @return True if any of the maps in this file contain a * color mapping that possesses a modified status. */ bool CaretMappableDataFile::isModifiedPaletteColorMapping() const { if (isMappedWithPalette()) { const int32_t numMaps = getNumberOfMaps(); for (int32_t i = 0; i < numMaps; i++) { if (getMapPaletteColorMapping(i)->isModified()) { return true; } } } return false; } /** * @return The modified status for aall palettes in this file. * Note that 'modified' overrides any 'modified by show scene'. */ PaletteModifiedStatusEnum::Enum CaretMappableDataFile::getPaletteColorMappingModifiedStatus() const { PaletteModifiedStatusEnum::Enum modStatus = PaletteModifiedStatusEnum::UNMODIFIED; if (isMappedWithPalette()) { const int32_t numMaps = getNumberOfMaps(); for (int32_t i = 0; i < numMaps; i++) { switch (getMapPaletteColorMapping(i)->getModifiedStatus()) { case PaletteModifiedStatusEnum::MODIFIED: modStatus = PaletteModifiedStatusEnum::MODIFIED; break; case PaletteModifiedStatusEnum::MODIFIED_BY_SHOW_SCENE: modStatus = PaletteModifiedStatusEnum::MODIFIED_BY_SHOW_SCENE; break; case PaletteModifiedStatusEnum::UNMODIFIED: break; } if (modStatus == PaletteModifiedStatusEnum::MODIFIED) { /* * 'MODIFIED' overrides 'MODIFIED_BY_SHOW_SCENE' * so no need to continue loop */ break; } } } return modStatus; } /** * @return True if the file is modified in any way EXCEPT for * the palette color mapping. Also see isModified(). */ bool CaretMappableDataFile::isModifiedExcludingPaletteColorMapping() const { if (CaretDataFile::isModified()) { return true; } return false; } /** * @return True if the file is modified in any way including * the palette color mapping. * * NOTE: While this method overrides that in the super class, * it is NOT virtual here. Thus subclasses cannot override * this method and instead, subclasses should overrride * isModifiedExcludingPaletteColorMapping(). */ bool CaretMappableDataFile::isModified() const { if (isModifiedExcludingPaletteColorMapping()) { return true; } if (isModifiedPaletteColorMapping()) { return true; } return false; } /** * Clear data in this file. */ void CaretMappableDataFile::clear() { CaretDataFile::clear(); m_chartingDelegate.reset(); m_mapThresholdFileSelectionModels.clear(); } /** * Clear the modified status of this file. */ void CaretMappableDataFile::clearModified() { CaretDataFile::clearModified(); if (m_chartingDelegate != NULL) { m_chartingDelegate->clearModified(); } } /** * Create cartesian chart data from the given data. * * @param * Data for the Y-axis. * @return * Pointer to the ChartDataCartesian instance. */ ChartDataCartesian* CaretMappableDataFile::helpCreateCartesianChartData(const std::vector& data) { const int64_t numData = static_cast(data.size()); /* * Some files may have time data but initially assume data-series */ bool timeSeriesFlag = false; float convertTimeToSeconds = 1.0; switch (getMapIntervalUnits()) { case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: break; case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: timeSeriesFlag = true; convertTimeToSeconds = 1000.0; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: break; case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: convertTimeToSeconds = 1.0; timeSeriesFlag = true; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: break; case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: convertTimeToSeconds = 1000000.0; timeSeriesFlag = true; break; } ChartDataCartesian* chartData = NULL; if (timeSeriesFlag) { chartData = new ChartDataCartesian(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES, ChartAxisUnitsEnum::CHART_AXIS_UNITS_TIME_SECONDS, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); } else { chartData = new ChartDataCartesian(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); } if (chartData != NULL) { float timeStart = 0.0; float timeStep = 1.0; if (timeSeriesFlag) { getMapIntervalStartAndStep(timeStart, timeStep); timeStart *= convertTimeToSeconds; timeStep *= convertTimeToSeconds; chartData->setTimeStartInSecondsAxisX(timeStart); chartData->setTimeStepInSecondsAxisX(timeStep); } for (int64_t i = 0; i < numData; i++) { float xValue = i; if (timeSeriesFlag) { /* * X-Value is "time" */ xValue = timeStart + (i * timeStep); } else { /* * X-Value is the map index and map indices start at one */ xValue = i + 1; } chartData->addPoint(xValue, data[i]); } } return chartData; } /** * Helper for getting chart data types supported by files that create * charts from brainordinates (multi-map files). * The chart data types are a function of the map interval units. * * @param chartDataTypesOut * Chart types supported by this file. */ void CaretMappableDataFile::helpGetSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { chartDataTypesOut.clear(); switch (getMapIntervalUnits()) { case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: chartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES); break; case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: chartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); break; case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: CaretLogSevere("Units - PPM not supported"); CaretAssertMessage(0, "Units - PPM not supported"); break; case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: chartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); break; case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: chartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES); break; case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: chartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); break; } } /** * Is a medial wall label in the label table for the given map index? * * NOTE: This does not test to see if a data element in * the map is set to the key of the medial wall label. So, it is * possible that true is returned but no vertices or voxels are * assigned to the medial wall. * * @param mapIndex * Index of the map. * @return * True if map the map's label table contains a medial wall label, * else false. */ bool CaretMappableDataFile::isMedialWallLabelInMapLabelTable(const int32_t mapIndex) const { if (isMappedWithLabelTable()) { const GiftiLabelTable* labelTable = getMapLabelTable(mapIndex); return labelTable->hasMedialWallLabel(); } return false; } /** * @return The label drawing properties for this file. A valid pointer * will always be returned even if the file does not provide label data. */ LabelDrawingProperties* CaretMappableDataFile::getLabelDrawingProperties() { return m_labelDrawingProperties.get(); } /** * @return The label drawing properties for this file. A valid pointer * will always be returned even if the file does not provide label data. */ const LabelDrawingProperties* CaretMappableDataFile::getLabelDrawingProperties() const { return m_labelDrawingProperties.get(); } /** * @return The charting delegate for this file. Pointer * will never be NULL, even if file does not support charting. */ ChartableTwoFileDelegate* CaretMappableDataFile::getChartingDelegate() { if (m_chartingDelegate == NULL) { m_chartingDelegate = std::unique_ptr(new ChartableTwoFileDelegate(this)); m_chartingDelegate->updateAfterFileChanged(); } return m_chartingDelegate.get(); } /* * @return The charting delegate for this file. Pointer * will never be NULL, even if file does not support charting. */ const ChartableTwoFileDelegate* CaretMappableDataFile::getChartingDelegate() const { if (m_chartingDelegate == NULL) { CaretMappableDataFile* thisFile = const_cast(this); m_chartingDelegate = std::unique_ptr(new ChartableTwoFileDelegate(thisFile)); m_chartingDelegate->updateAfterFileChanged(); } return m_chartingDelegate.get(); } /** * Update the map threshold file selection models. */ void CaretMappableDataFile::updateMapThresholdFileSelectionModels() { const int32_t numMaps = getNumberOfMaps(); const int32_t numThresh = static_cast(m_mapThresholdFileSelectionModels.size()); if (numMaps > numThresh) { for (int32_t i = numThresh; i < numMaps; i++) { std::unique_ptr threshSel(new CaretMappableDataFileAndMapSelectionModel(this)); threshSel->setSelectedFile(this); threshSel->setSelectedMapIndex(i); m_mapThresholdFileSelectionModels.push_back(std::move(threshSel)); } } else if (numThresh > numMaps) { m_mapThresholdFileSelectionModels.resize(numMaps); } } /** * @return The thresholding file selection model for the given map index. */ CaretMappableDataFileAndMapSelectionModel* CaretMappableDataFile::getMapThresholdFileSelectionModel(const int32_t mapIndex) { updateMapThresholdFileSelectionModels(); CaretAssertVectorIndex(m_mapThresholdFileSelectionModels, mapIndex); return m_mapThresholdFileSelectionModels[mapIndex].get(); } /** * Update the charting delegate after changes (add a row/column, etc.) * are made to the data file. */ void CaretMappableDataFile::updateAfterFileDataChanges() { if (m_chartingDelegate) { m_chartingDelegate->updateAfterFileChanged(); } m_applyToAllMapsSelected = isPaletteColorMappingEqualForAllMaps(); } /** * @return Is apply palette color mapping to all maps selected. */ bool CaretMappableDataFile::isApplyPaletteColorMappingToAllMaps() const { return m_applyToAllMapsSelected; } /** * Set apply palette color mapping to all maps. Only sets the status, * it does not change any palette color mapping. * * @param selected * New selected status. */ void CaretMappableDataFile::setApplyPaletteColorMappingToAllMaps(const bool selected) { m_applyToAllMapsSelected = selected; } /** * @return True if file is mapped with a palette and one * palette is used for all maps. */ bool CaretMappableDataFile::isOnePaletteUsedForAllMaps() const { return false; } /** * @return The palette normalization mode for the file. * The default is NORMALIZATION_SELECTED_MAP_DATA. */ PaletteNormalizationModeEnum::Enum CaretMappableDataFile::getPaletteNormalizationMode() const { const AString textValue = getFileMetaData()->get(GiftiMetaDataXmlElements::METADATA_PALETTE_NORMALIZATION_MODE); bool validFlag = false; PaletteNormalizationModeEnum::Enum modeValue = PaletteNormalizationModeEnum::fromName(textValue, &validFlag); if ( ! validFlag) { modeValue = getDefaultPaletteNormalizationMode(); } ensurePaletteNormalizationModeIsSupported(modeValue); return modeValue; } /** * Set the palette normalization mode for the file. If the mode is not supported by the * file, the mode is not changed. * * @param mode * New value for palette normalization mode. */ void CaretMappableDataFile::setPaletteNormalizationMode(const PaletteNormalizationModeEnum::Enum modeIn) { PaletteNormalizationModeEnum::Enum mode = modeIn; ensurePaletteNormalizationModeIsSupported(mode); getFileMetaData()->set(GiftiMetaDataXmlElements::METADATA_PALETTE_NORMALIZATION_MODE, PaletteNormalizationModeEnum::toName(mode)); } /** * Ensure that the given palette normalization mode is supported by the instance of this file. * If not supported, it is changed to that returned by getDefaultPaletteNormalizationMode(). * * @param modeInOut * Normalization mode that may be changed to a supported mode. */ void CaretMappableDataFile::ensurePaletteNormalizationModeIsSupported(PaletteNormalizationModeEnum::Enum& modeInOut) const { std::vector validModes; getPaletteNormalizationModesSupported(validModes); if (std::find(validModes.begin(), validModes.end(), modeInOut) == validModes.end()) { modeInOut = getDefaultPaletteNormalizationMode(); } } /** * @return The default palette normalization mode for this file which is always * the first mode in the supported modes from getPaletteNormalizationModesSupported(). */ PaletteNormalizationModeEnum::Enum CaretMappableDataFile::getDefaultPaletteNormalizationMode() const { PaletteNormalizationModeEnum::Enum mode = PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA; std::vector validModes; getPaletteNormalizationModesSupported(validModes); if ( ! validModes.empty()) { CaretAssertVectorIndex(validModes, 0); mode = validModes[0]; } return mode; } /** * @return Is the data in the file mapped to colors using * Red, Green, Blue, Alpha values. */ bool CaretMappableDataFile::isMappedWithRGBA() const { return false; } bool CaretMappableDataFile::hasCiftiXML() const { return false; } const CiftiXML CaretMappableDataFile::getCiftiXML() const { return CiftiXML(); } /** * Get the identification information for a surface node in the given maps. * * @param mapIndices * Indices of maps for which identification information is requested. * @param structure * Structure of the surface. * @param nodeIndex * Index of the node. * @param numberOfNodes * Number of nodes in the surface. * @param textOut * Output containing identification information. */ bool CaretMappableDataFile::getSurfaceNodeIdentificationForMaps(const std::vector& /*mapIndices*/, const StructureEnum::Enum /*structure*/, const int /*nodeIndex*/, const int32_t /*numberOfNodes*/, AString& textOut) const { textOut.clear(); return false; } /** * Get the identification information for a surface node in the given maps. * * @param mapIndices * Indices of maps for which identification information is requested. * @param xyz * Coordinate of voxel. * @param ijkOut * Voxel indices of value. * @param textOut * Output containing identification information. */ bool CaretMappableDataFile::getVolumeVoxelIdentificationForMaps(const std::vector& /*mapIndices*/, const float* /*xyz[3]*/, int64_t* /*ijkOut[3]*/, AString& textOut) const { textOut.clear(); return false; } connectome-workbench-1.4.2/src/Files/CaretMappableDataFile.h000066400000000000000000000533451360521144700237410ustar00rootroot00000000000000#ifndef __CARET_MAPPABLE_DATA_FILE__H_ #define __CARET_MAPPABLE_DATA_FILE__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretDataFile.h" #include "CaretMappableDataFileAndMapSelectionModel.h" #include "ChartOneDataTypeEnum.h" #include "CaretPointer.h" #include "CiftiXML.h" #include "NiftiEnums.h" #include "PaletteModifiedStatusEnum.h" #include "PaletteNormalizationModeEnum.h" namespace caret { class ChartDataCartesian; class ChartableTwoFileDelegate; class FastStatistics; class GiftiMetaData; class GiftiLabelTable; class Histogram; class LabelDrawingProperties; class MapFileDataSelector; class PaletteColorMapping; /** * \class caret::CaretMappableDataFile * \brief A Caret data file that is mappable to surfaces and/or volumes. * * This class is essentially an interface that defines methods for * files that are 'mappable', as an overlay, to surfaces and/or volumes. * Use of a common interface simplifies selection and application * of these data files. * * For a GIFTI File, the number of maps is the number of data arrays * in the GIFTI file. For a volume, it may be the number of time points. * * Note that Caret5 used the term 'column'. */ class CaretMappableDataFile : public CaretDataFile { public: /** * Result for brainordinate mapping match */ enum class BrainordinateMappingMatch { /** Both files map to exact same brainordinates */ EQUAL, /** File do not match to same brainordinates */ NO, /** File matches to a subset of the other file's brainordinates **/ SUBSET }; CaretMappableDataFile(const DataFileTypeEnum::Enum dataFileType); virtual ~CaretMappableDataFile(); virtual void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation); /** * @return Is the data mappable to a surface? */ virtual bool isSurfaceMappable() const = 0; /** * @return Is the data mappable to a volume? */ virtual bool isVolumeMappable() const = 0; /** * @return The number of maps in the file. * Note: Caret5 used the term 'columns'. */ virtual int32_t getNumberOfMaps() const = 0; virtual bool isMappableToSurfaceStructure(const StructureEnum::Enum structure) const; /** * @return True if the file has map attributes (name and metadata). * For files that do not have map attributes, they should override * this method and return false. If not overriden, this method * returns true. * * Some files (such as CIFTI Connectivity Matrix Files and CIFTI * Data-Series Files) do not have Map Attributes and thus there * is no map name nor map metadata and options to edit these * attributes should not be presented to the user. * * These CIFTI files do contain palette color mapping but it is * associated with the file. To simplify palette color mapping editing * these file will return the file's palette color mapping for any * calls to getMapPaletteColorMapping(). */ virtual bool hasMapAttributes() const; /** * Get the name of the map at the given index. * * @param mapIndex * Index of the map. * @return * Name of the map. */ virtual AString getMapName(const int32_t mapIndex) const = 0; /** * Find the index of the map that uses the given name. * * @param mapName * Name of the desired map. * @return * Index of the map using the given name. If there is more * than one map with the given name, this method is likely * to return the index of the first map with the name. */ virtual int32_t getMapIndexFromName(const AString& mapName) const; /** * Find the index of the map that uses the given name. * * @param mapName * Name of the desired map. * @return * Index of the map using the given name. If there is more * than one map with the given name, this method is likely * to return the index of the first map with the name. */ virtual int32_t getMapIndexFromNameOrNumber(const AString& mapName) const; /** * Set the name of the map at the given index. * * If the file does not have map attributes (hasMapAttributes()) * calling this method will have not change the file. * * @param mapIndex * Index of the map. * @param mapName * New name for the map. */ virtual void setMapName(const int32_t mapIndex, const AString& mapName) = 0; /** * Get the metadata for the map at the given index * * If the file does not have map attributes (hasMapAttributes()) * a valid metadata object will be returned but changing its * content will have no effect on the file. * * @param mapIndex * Index of the map. * @return * Metadata for the map (const value). */ virtual const GiftiMetaData* getMapMetaData(const int32_t mapIndex) const = 0; /** * Get the metadata for the map at the given index * * If the file does not have map attributes (hasMapAttributes()) * a valid metadata object will be returned but changing its * content will have no effect on the file. * * @param mapIndex * Index of the map. * @return * Metadata for the map. */ virtual GiftiMetaData* getMapMetaData(const int32_t mapIndex) = 0; /** * Get the unique ID (UUID) for the map at the given index. * * @param mapIndex * Index of the map. * @return * String containing UUID for the map. */ virtual AString getMapUniqueID(const int32_t mapIndex) const = 0; /** * Find the index of the map that uses the given unique ID (UUID). * * @param uniqueID * Unique ID (UUID) of the desired map. * @return * Index of the map using the given UUID. */ virtual int32_t getMapIndexFromUniqueID(const AString& uniqueID) const; /** * @return Is the data in the file mapped to colors using * a palette. */ virtual bool isMappedWithPalette() const = 0; virtual bool isOnePaletteUsedForAllMaps() const; /** * @return The estimated size of data after it is uncompressed * and loaded into RAM. A negative value indicates that the * file size cannot be computed. */ virtual int64_t getDataSizeUncompressedInBytes() const = 0; /** * Get statistics describing the distribution of data * mapped with a color palette at the given index. * * @param mapIndex * Index of the map. * @return * Fast statistics for data (will be NULL for data * not mapped using a palette). */ virtual const FastStatistics* getMapFastStatistics(const int32_t mapIndex) = 0; /** * Get a histogram for the map at the given index. * * @param mapIndex * Index of the map. * @return * Histogram for data (will be NULL for data * not mapped using a palette). */ virtual const Histogram* getMapHistogram(const int32_t mapIndex) = 0; /** * Get a histogram for the map at the given index of data * mapped with a color palette at the given index for * data within the given ranges. * * @param mapIndex * Index of the map. * @param mostPositiveValueInclusive * Values more positive than this value are excluded. * @param leastPositiveValueInclusive * Values less positive than this value are excluded. * @param leastNegativeValueInclusive * Values less negative than this value are excluded. * @param mostNegativeValueInclusive * Values more negative than this value are excluded. * @param includeZeroValues * If true zero values (very near zero) are included. * @return * Histogram for data (will be NULL for data * not mapped using a palette). */ virtual const Histogram* getMapHistogram(const int32_t mapIndex, const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) = 0; /** * Get statistics describing the distribution of data * mapped with a color palette for all data within the file. * * @return * Fast statistics for data (will be NULL for data * not mapped using a palette). */ virtual const FastStatistics* getFileFastStatistics() = 0; /** * Get histogram describing the distribution of data * mapped with a color palette for all data within * the file. * * @return * Histogram for data (will be NULL for data * not mapped using a palette). */ virtual const Histogram* getFileHistogram() = 0; /** * Get histogram describing the distribution of data * mapped with a color palette for all data in the file * within the given range of values. * * @param mostPositiveValueInclusive * Values more positive than this value are excluded. * @param leastPositiveValueInclusive * Values less positive than this value are excluded. * @param leastNegativeValueInclusive * Values less negative than this value are excluded. * @param mostNegativeValueInclusive * Values more negative than this value are excluded. * @param includeZeroValues * If true zero values (very near zero) are included. * @return * Descriptive statistics for data (will be NULL for data * not mapped using a palette). */ virtual const Histogram* getFileHistogram(const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) = 0; int32_t getFileHistogramNumberOfBuckets() const; void setFileHistogramNumberOfBuckets(const int32_t numberOfBuckets); /** * Get the palette color mapping for the map at the given index. * * @param mapIndex * Index of the map. * @return * Palette color mapping for the map (will be NULL for data * not mapped using a palette). */ virtual PaletteColorMapping* getMapPaletteColorMapping(const int32_t mapIndex) = 0; /** * Get the palette color mapping for the map at the given index. * * @param mapIndex * Index of the map. * @return * Palette color mapping for the map (constant) (will be NULL for data * not mapped using a palette). */ virtual const PaletteColorMapping* getMapPaletteColorMapping(const int32_t mapIndex) const = 0; /** * @return Is the data in the file mapped to colors using * a label table. */ virtual bool isMappedWithLabelTable() const = 0; /** * @return Is the data in the file mapped to colors using * Red, Green, Blue, Alpha values. */ virtual bool isMappedWithRGBA() const; /** * Get the label table for the map at the given index. * * @param mapIndex * Index of the map. * @return * Label table for the map (will be NULL for data * not mapped using a label table). */ virtual GiftiLabelTable* getMapLabelTable(const int32_t mapIndex) = 0; /** * Get the label table for the map at the given index. * * @param mapIndex * Index of the map. * @return * Label table for the map (constant) (will be NULL for data * not mapped using a label table). */ virtual const GiftiLabelTable* getMapLabelTable(const int32_t mapIndex) const = 0; bool isMedialWallLabelInMapLabelTable(const int32_t mapIndex) const; /** * Get the palette normalization modes that are supported by the file. * * @param modesSupportedOut * Palette normalization modes supported by a file. Will be * empty for files that are not mapped with a palette. If there * is more than one suppported mode, the first mode in the * vector is assumed to be the default mode. */ virtual void getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) const = 0; PaletteNormalizationModeEnum::Enum getPaletteNormalizationMode() const; void setPaletteNormalizationMode(const PaletteNormalizationModeEnum::Enum mode); /** * Update coloring for all maps. * * @param paletteFile * Palette file containing palettes. */ virtual void updateScalarColoringForAllMaps(); /** * Update coloring for a map. * * @param mapIndex * Index of map. * @param paletteFile * Palette file containing palettes. */ virtual void updateScalarColoringForMap(const int32_t mapIndex) = 0; void invalidateHistogramChartColoring(); void applyPaletteColorMappingToAllMaps(const int32_t mapIndex); bool isApplyPaletteColorMappingToAllMaps() const; void setApplyPaletteColorMappingToAllMaps(const bool selected); /** * @return The units for the 'interval' between two consecutive maps. */ virtual NiftiTimeUnitsEnum::Enum getMapIntervalUnits() const; /** * Get the units value for the first map and the * quantity of units between consecutive maps. If the * units for the maps is unknown, value of one (1) are * returned for both output values. * * @param firstMapUnitsValueOut * Output containing units value for first map. * @param mapIntervalStepValueOut * Output containing number of units between consecutive maps. */ virtual void getMapIntervalStartAndStep(float& firstMapUnitsValueOut, float& mapIntervalStepValueOut) const; /* documented in cxx file */ virtual bool getDataRangeFromAllMaps(float& dataRangeMinimumOut, float& dataRangeMaximumOut) const; /* documented in cxx file */ virtual bool isModifiedExcludingPaletteColorMapping() const; /* documented in cxx file. */ virtual bool isModifiedPaletteColorMapping() const; /* documented in cxx file. */ virtual PaletteModifiedStatusEnum::Enum getPaletteColorMappingModifiedStatus() const; /** * Check whether the file contains Cifti XML (all cifti types and also wbsparse have it) */ virtual bool hasCiftiXML() const; /** * Get the Cifti XML, if the file has it * This could be faster if it returned a reference, but then it would have to throw when there is no xml object */ virtual const CiftiXML getCiftiXML() const; /* documented in cxx file. */ virtual bool isModified() const override final; virtual void clearModified() override; virtual void clear(); void initializeCaretMappableDataFileInstance(const DataFileTypeEnum::Enum dataFileType); LabelDrawingProperties* getLabelDrawingProperties(); const LabelDrawingProperties* getLabelDrawingProperties() const; ChartableTwoFileDelegate* getChartingDelegate(); const ChartableTwoFileDelegate* getChartingDelegate() const; virtual void getDataForSelector(const MapFileDataSelector& mapFileDataSelector, std::vector& dataOut) const = 0; CaretMappableDataFileAndMapSelectionModel* getMapThresholdFileSelectionModel(const int32_t mapIndex); /** * Are all brainordinates in this file also in the given file? * That is, the brainordinates are equal to or a subset of the brainordinates * in the given file. * * @param mapFile * The given map file. * @return * Match status. */ virtual BrainordinateMappingMatch getBrainordinateMappingMatch(const CaretMappableDataFile* mapFile) const = 0; virtual bool getSurfaceNodeIdentificationForMaps(const std::vector& mapIndices, const StructureEnum::Enum structure, const int nodeIndex, const int32_t numberOfNodes, AString& textOut) const; virtual bool getVolumeVoxelIdentificationForMaps(const std::vector& mapIndices, const float xyz[3], int64_t ijkOut[3], AString& textOut) const; void updateAfterFileDataChanges(); protected: CaretMappableDataFile(const CaretMappableDataFile&); CaretMappableDataFile& operator=(const CaretMappableDataFile&); ChartDataCartesian* helpCreateCartesianChartData(const std::vector& data); void helpGetSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: void copyCaretMappableDataFile(const CaretMappableDataFile&); void ensurePaletteNormalizationModeIsSupported(PaletteNormalizationModeEnum::Enum& modeInOut) const; PaletteNormalizationModeEnum::Enum getDefaultPaletteNormalizationMode() const; bool isPaletteColorMappingEqualForAllMaps() const; void updateMapThresholdFileSelectionModels(); std::unique_ptr m_labelDrawingProperties; mutable std::unique_ptr m_chartingDelegate; std::vector> m_mapThresholdFileSelectionModels; /** * Added by WB-781 Apply to All Maps for ColorBar. * This value is saved to scenes but NOT to the data file. */ bool m_applyToAllMapsSelected = false; }; #ifdef __CARET_MAPPABLE_DATA_FILE_DECLARE__ // #endif // __CARET_MAPPABLE_DATA_FILE_DECLARE__ } // namespace #endif //__CARET_MAPPABLE_DATA_FILE__H_ connectome-workbench-1.4.2/src/Files/CaretMappableDataFileAndMapSelectionModel.cxx000066400000000000000000000371241360521144700302210ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTION_MODEL_DECLARE__ #include "CaretMappableDataFileAndMapSelectionModel.h" #undef __CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTION_MODEL_DECLARE__ #include "CaretAssert.h" #include "CaretDataFileSelectionModel.h" #include "CaretLogger.h" #include "CaretMappableDataFile.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::CaretMappableDataFileAndMapSelectionModel * \brief Model for selection of a CaretMappableDataFile and map index. * \ingroup Files */ /** * Constructor for files that map to the same brainordinates as the given file. * * @param caretMappableDataFile * Mappable data file. */ CaretMappableDataFileAndMapSelectionModel::CaretMappableDataFileAndMapSelectionModel(const CaretMappableDataFile* caretMappableDataFile) : CaretObject(), m_mode(Mode::MAP_TO_SAME_BRAINORDINATES), m_mappableDataFile(caretMappableDataFile) { std::vector dataFileTypesVector; performConstruction(dataFileTypesVector); } /** * Constructor for instance that will contain files of the given data type. * * @param dataFileType * Type of data files available for selection. */ CaretMappableDataFileAndMapSelectionModel::CaretMappableDataFileAndMapSelectionModel(const DataFileTypeEnum::Enum dataFileType) : CaretObject(), m_mode(Mode::MATCH_DATA_FILE_TYPES), m_mappableDataFile(NULL) { std::vector dataFileTypesVector; dataFileTypesVector.push_back(dataFileType); performConstruction(dataFileTypesVector); } /** * Constructor for instance that will contain files of the given data types. * * @param dataFileTypes * Types of data files available for selection. */ CaretMappableDataFileAndMapSelectionModel::CaretMappableDataFileAndMapSelectionModel(const std::vector& dataFileTypes) : CaretObject(), m_mode(Mode::MATCH_DATA_FILE_TYPES), m_mappableDataFile(NULL) { performConstruction(dataFileTypes); } /** * Destructor. */ CaretMappableDataFileAndMapSelectionModel::~CaretMappableDataFileAndMapSelectionModel() { delete m_caretDataFileSelectionModel; delete m_sceneAssistant; } /** * Validate that any data file types are mappable data files * and remove any non-mappable data file types. */ void CaretMappableDataFileAndMapSelectionModel::validateDataFileTypes() { std::vector mappableDataFileTypes; for (const auto dataFileType : m_dataFileTypes) { bool isMappableFile = false; switch (dataFileType) { case DataFileTypeEnum::ANNOTATION: CaretAssert(0); break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: CaretAssert(0); break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: isMappableFile = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: isMappableFile = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: isMappableFile = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: isMappableFile = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: isMappableFile = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: isMappableFile = true; break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: isMappableFile = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: isMappableFile = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: isMappableFile = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: isMappableFile = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: isMappableFile = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: isMappableFile = true; break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: isMappableFile = true; break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: isMappableFile = true; break; case DataFileTypeEnum::METRIC: isMappableFile = true; break; case DataFileTypeEnum::METRIC_DYNAMIC: isMappableFile = true;; break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: isMappableFile = true; break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: break; case DataFileTypeEnum::VOLUME: isMappableFile = true; break; case DataFileTypeEnum::VOLUME_DYNAMIC: isMappableFile = true; break; } CaretAssert(isMappableFile); if (isMappableFile) { mappableDataFileTypes.push_back(dataFileType); } else { CaretLogSevere(DataFileTypeEnum::toGuiName(dataFileType) + " is not a valid mappable data file."); } } if (m_dataFileTypes.size() != mappableDataFileTypes.size()) { /* * Update without non-mappable data file types. */ m_dataFileTypes = mappableDataFileTypes; } } /** * Finish construction for an instance of this class. * * @param dataFileTypes * Types of data files available for selection. */ void CaretMappableDataFileAndMapSelectionModel::performConstruction(const std::vector& dataFileTypes) { m_dataFileTypes = dataFileTypes; switch (m_mode) { case Mode::MAP_TO_SAME_BRAINORDINATES: CaretAssert(m_mappableDataFile); m_caretDataFileSelectionModel = CaretDataFileSelectionModel::newInstanceMapsToSameBrainordinates(m_mappableDataFile); break; case Mode::MATCH_DATA_FILE_TYPES: validateDataFileTypes(); m_caretDataFileSelectionModel = CaretDataFileSelectionModel::newInstanceForCaretDataFileTypes(dataFileTypes); break; } m_selectedMapIndex = -1; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_caretDataFileSelectionModel", "CaretDataFileSelectionModel", m_caretDataFileSelectionModel); m_sceneAssistant->add("m_selectedMapIndex", &m_selectedMapIndex); } /** * Copy constructor. * @param obj * Object that is copied. */ CaretMappableDataFileAndMapSelectionModel::CaretMappableDataFileAndMapSelectionModel(const CaretMappableDataFileAndMapSelectionModel& obj) : CaretObject(obj), SceneableInterface(obj), m_mode(obj.m_mode), m_mappableDataFile(obj.m_mappableDataFile) { this->copyHelperCaretMappableDataFileAndMapSelectionModel(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ CaretMappableDataFileAndMapSelectionModel& CaretMappableDataFileAndMapSelectionModel::operator=(const CaretMappableDataFileAndMapSelectionModel& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperCaretMappableDataFileAndMapSelectionModel(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void CaretMappableDataFileAndMapSelectionModel::copyHelperCaretMappableDataFileAndMapSelectionModel(const CaretMappableDataFileAndMapSelectionModel& obj) { *m_caretDataFileSelectionModel = *obj.m_caretDataFileSelectionModel; m_selectedMapIndex = obj.m_selectedMapIndex; } /** * @return The data file selection model. */ CaretDataFileSelectionModel* CaretMappableDataFileAndMapSelectionModel::getCaretDataFileSelectionModel() { return m_caretDataFileSelectionModel; } /** * @return the selected file. */ CaretMappableDataFile* CaretMappableDataFileAndMapSelectionModel::getSelectedFile() { return dynamic_cast(m_caretDataFileSelectionModel->getSelectedFile()); } /** * @return the selected file. */ const CaretMappableDataFile* CaretMappableDataFileAndMapSelectionModel::getSelectedFile() const { return dynamic_cast(m_caretDataFileSelectionModel->getSelectedFile()); } /** * @return the selected map index (-1 if no map available). */ int32_t CaretMappableDataFileAndMapSelectionModel::getSelectedMapIndex() const { const CaretMappableDataFile* cmdf = getSelectedFile(); if (cmdf != NULL) { const int32_t numMaps = cmdf->getNumberOfMaps(); if (numMaps > 0) { if (m_selectedMapIndex < 0) { m_selectedMapIndex = 0; } else if (m_selectedMapIndex >= numMaps) { m_selectedMapIndex = numMaps - 1; } } else { m_selectedMapIndex = -1; } } else { m_selectedMapIndex = -1; } return m_selectedMapIndex; } /** * @return the files in this model. */ std::vector CaretMappableDataFileAndMapSelectionModel::getAvailableFiles() const { switch (m_mode) { case Mode::MAP_TO_SAME_BRAINORDINATES: break; case Mode::MATCH_DATA_FILE_TYPES: break; } std::vector caretDataFiles = m_caretDataFileSelectionModel->getAvailableFiles(); std::vector mappableFiles; for (std::vector::iterator iter = caretDataFiles.begin(); iter != caretDataFiles.end(); iter++) { CaretMappableDataFile* cmdf = dynamic_cast(*iter); if (cmdf != NULL) { mappableFiles.push_back(cmdf); } } return mappableFiles; } /** * Override the available files with the given files. Once this method * is called, these will be the available files until this method is called * again. * * @param availableFiles * Files that will be used in this model. */ void CaretMappableDataFileAndMapSelectionModel::overrideAvailableDataFiles(std::vector& availableFiles) { std::vector files(availableFiles.begin(), availableFiles.end()); m_caretDataFileSelectionModel->overrideAvailableDataFiles(files); } /** * Set the selected file * * @param selectedFile * New selected file. */ void CaretMappableDataFileAndMapSelectionModel::setSelectedFile(CaretMappableDataFile* selectedFile) { if (selectedFile != NULL) { switch (m_mode) { case Mode::MAP_TO_SAME_BRAINORDINATES: break; case Mode::MATCH_DATA_FILE_TYPES: { const DataFileTypeEnum::Enum fileType = selectedFile->getDataFileType(); if (std::find(m_dataFileTypes.begin(), m_dataFileTypes.end(), fileType) == m_dataFileTypes.end()) { AString validFileTypeNames; for (std::vector::const_iterator typeIter = m_dataFileTypes.begin(); typeIter != m_dataFileTypes.end(); typeIter++) { const DataFileTypeEnum::Enum dataFileType = *typeIter; validFileTypeNames.append(DataFileTypeEnum::toName(dataFileType) + " "); } const AString msg("Attempting to set file that is of type " + DataFileTypeEnum::toGuiName(fileType) + " but model is for type(s) " + validFileTypeNames); CaretAssertMessage(0, msg); CaretLogSevere(msg); return; } } break; } } m_caretDataFileSelectionModel->setSelectedFile(selectedFile); } /** * Set the selected map index * * @param mapIndex * New selected map index. */ void CaretMappableDataFileAndMapSelectionModel::setSelectedMapIndex(const int32_t mapIndex) { m_selectedMapIndex = mapIndex; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* CaretMappableDataFileAndMapSelectionModel::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "CaretMappableDataFileAndMapSelectionModel", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void CaretMappableDataFileAndMapSelectionModel::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Files/CaretMappableDataFileAndMapSelectionModel.h000066400000000000000000000114761360521144700276500ustar00rootroot00000000000000#ifndef __CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTION_MODEL_H__ #define __CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTION_MODEL_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "DataFileTypeEnum.h" #include "SceneableInterface.h" namespace caret { class CaretDataFileSelectionModel; class CaretMappableDataFile; class SceneClassAssistant; class CaretMappableDataFileAndMapSelectionModel : public CaretObject, public SceneableInterface { public: CaretMappableDataFileAndMapSelectionModel(const CaretMappableDataFile* caretMappableDataFile); CaretMappableDataFileAndMapSelectionModel(const DataFileTypeEnum::Enum dataFileType); CaretMappableDataFileAndMapSelectionModel(const std::vector& dataFileTypes); virtual ~CaretMappableDataFileAndMapSelectionModel(); CaretMappableDataFileAndMapSelectionModel(const CaretMappableDataFileAndMapSelectionModel& obj); CaretMappableDataFileAndMapSelectionModel& operator=(const CaretMappableDataFileAndMapSelectionModel& obj); CaretDataFileSelectionModel* getCaretDataFileSelectionModel(); CaretMappableDataFile* getSelectedFile(); const CaretMappableDataFile* getSelectedFile() const; int32_t getSelectedMapIndex() const; std::vector getAvailableFiles() const; void overrideAvailableDataFiles(std::vector& availableFiles); /** * @return Selected file dynamically cast to the templated * data file type. */ template inline T* getSelectedFileOfType() { CaretMappableDataFile* cmdf = getSelectedFile(); if (cmdf != NULL) { return dynamic_cast(getSelectedFile()); } return NULL; } void setSelectedFile(CaretMappableDataFile* selectedFile); void setSelectedMapIndex(const int32_t mapIndex); // ADD_NEW_METHODS_HERE virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implemetation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: enum class Mode { MAP_TO_SAME_BRAINORDINATES, MATCH_DATA_FILE_TYPES }; void copyHelperCaretMappableDataFileAndMapSelectionModel(const CaretMappableDataFileAndMapSelectionModel& obj); void performConstruction(const std::vector& dataFileTypes); void validateDataFileTypes(); const Mode m_mode; const CaretMappableDataFile* m_mappableDataFile; SceneClassAssistant* m_sceneAssistant; std::vector m_dataFileTypes; CaretDataFileSelectionModel* m_caretDataFileSelectionModel; mutable int32_t m_selectedMapIndex; // ADD_NEW_MEMBERS_HERE }; #ifdef __CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTION_MODEL_DECLARE__ // #endif // __CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTION_MODEL_DECLARE__ } // namespace #endif //__CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTION_MODEL_H__ connectome-workbench-1.4.2/src/Files/CaretSparseFile.cxx000066400000000000000000000313701360521144700232300ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretSparseFile.h" #include "ByteOrderEnum.h" #include "ByteSwapping.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "FileInformation.h" #include using namespace caret; using namespace std; const char magic[] = "\0\0\0\0cst\0"; CaretSparseFile::CaretSparseFile(const AString& fileName) { readFile(fileName); } void CaretSparseFile::readFile(const AString& filename) { m_file.close(); if (filename.endsWith(".gz")) { throw DataFileException("wbsparse files cannot be read while compressed"); } m_file.open(filename); FileInformation fileInfo(filename);//useful later for file size, but create it now to reduce the amount of time between file open and size check char buf[8]; m_file.read(buf, 8); for (int i = 0; i < 8; ++i) { if (buf[i] != magic[i]) throw DataFileException("file has the wrong magic string"); } m_file.read(m_dims, 2 * sizeof(int64_t)); if (ByteOrderEnum::isSystemBigEndian()) { ByteSwapping::swapBytes(m_dims, 2); } if (m_dims[0] < 1 || m_dims[1] < 1) throw DataFileException("both dimensions must be positive"); m_indexArray.resize(m_dims[1] + 1); vector lengthArray(m_dims[1]); m_file.read(lengthArray.data(), m_dims[1] * sizeof(int64_t)); if (ByteOrderEnum::isSystemBigEndian()) { ByteSwapping::swapBytes(lengthArray.data(), m_dims[1]); } m_indexArray[0] = 0; for (int64_t i = 0; i < m_dims[1]; ++i) { if (lengthArray[i] > m_dims[0] || lengthArray[i] < 0) throw DataFileException("impossible value found in length array"); m_indexArray[i + 1] = m_indexArray[i] + lengthArray[i]; } m_valuesOffset = 8 + 2 * sizeof(int64_t) + m_dims[1] * sizeof(int64_t); int64_t xml_offset = m_valuesOffset + m_indexArray[m_dims[1]] * 2 * sizeof(int64_t); if (xml_offset >= fileInfo.size()) throw DataFileException("file is truncated"); int64_t xml_length = fileInfo.size() - xml_offset; if (xml_length < 1) throw DataFileException("file is truncated"); m_file.seek(xml_offset); const int64_t seekResult = m_file.pos(); if (seekResult != xml_offset) { const AString msg = ("Tried to seek to " + AString::number(xml_offset) + " but got an offset of " + AString::number(seekResult)); throw DataFileException(msg); } QByteArray myXMLBytes(xml_length, '\0'); m_file.read(myXMLBytes.data(), xml_length); m_xml.readXML(myXMLBytes); if (m_xml.getDimensionLength(CiftiXML::ALONG_ROW) != m_dims[0] || m_xml.getDimensionLength(CiftiXML::ALONG_COLUMN) != m_dims[1]) { throw DataFileException("cifti XML doesn't match dimensions of sparse file"); } } CaretSparseFile::~CaretSparseFile() { } void CaretSparseFile::getRow(const int64_t& index, int64_t* rowOut) { CaretAssert(index >= 0 && index < m_dims[1]); int64_t start = m_indexArray[index], end = m_indexArray[index + 1]; int64_t numToRead = (end - start) * 2; m_scratchArray.resize(numToRead); m_file.seek(m_valuesOffset + start * sizeof(int64_t) * 2); m_file.read(m_scratchArray.data(), numToRead * sizeof(int64_t)); if (ByteOrderEnum::isSystemBigEndian()) { ByteSwapping::swapBytes(m_scratchArray.data(), numToRead); } int64_t curIndex = 0; for (int64_t i = 0; i < numToRead; i += 2) { int64_t index = m_scratchArray[i]; if (index < curIndex || index >= m_dims[0]) throw DataFileException("impossible index value found in file"); while (curIndex < index) { rowOut[curIndex] = 0; ++curIndex; } ++curIndex; rowOut[index] = m_scratchArray[i + 1]; } while (curIndex < m_dims[0]) { rowOut[curIndex] = 0; ++curIndex; } } void CaretSparseFile::getRowSparse(const int64_t& index, vector& indicesOut, vector& valuesOut) { CaretAssert(index >= 0 && index < m_dims[1]); int64_t start = m_indexArray[index], end = m_indexArray[index + 1]; int64_t numToRead = (end - start) * 2, numNonzero = end - start; m_scratchArray.resize(numToRead); m_file.seek(m_valuesOffset + start * sizeof(int64_t) * 2); m_file.read(m_scratchArray.data(), numToRead * sizeof(int64_t)); if (ByteOrderEnum::isSystemBigEndian()) { ByteSwapping::swapBytes(m_scratchArray.data(), numToRead); } indicesOut.resize(numNonzero); valuesOut.resize(numNonzero); int64_t lastIndex = -1; for (int64_t i = 0; i < numNonzero; ++i) { indicesOut[i] = m_scratchArray[i * 2]; valuesOut[i] = m_scratchArray[i * 2 + 1]; if (indicesOut[i] <= lastIndex || indicesOut[i] >= m_dims[0]) throw DataFileException("impossible index value found in file"); lastIndex = indicesOut[i]; } } void CaretSparseFile::getFibersRow(const int64_t& index, FiberFractions* rowOut) { if (m_scratchRow.size() != (size_t)m_dims[0]) m_scratchRow.resize(m_dims[0]); getRow(index, (int64_t*)m_scratchRow.data()); for (int64_t i = 0; i < m_dims[0]; ++i) { if (m_scratchRow[i] == 0) { rowOut[i].zero(); } else { decodeFibers(m_scratchRow[i], rowOut[i]); } } } void CaretSparseFile::getFibersRowSparse(const int64_t& index, vector& indicesOut, vector& valuesOut) { getRowSparse(index, indicesOut, m_scratchSparseRow); size_t numNonzero = m_scratchSparseRow.size(); valuesOut.resize(numNonzero); for (size_t i = 0; i < numNonzero; ++i) { decodeFibers(((uint64_t*)m_scratchSparseRow.data())[i], valuesOut[i]); } } void CaretSparseFile::decodeFibers(const uint64_t& coded, FiberFractions& decoded) { decoded.fiberFractions.resize(3); decoded.totalCount = coded>>32; uint32_t temp = coded & ((1LL<<32) - 1); const static uint32_t MASK = ((1<<10) - 1); decoded.distance = (temp & MASK); decoded.fiberFractions[1] = ((temp>>10) & MASK) / 1000.0f; decoded.fiberFractions[0] = ((temp>>20) & MASK) / 1000.0f; decoded.fiberFractions[2] = 1.0f - decoded.fiberFractions[0] - decoded.fiberFractions[1]; if (decoded.fiberFractions[2] < -0.002f || (temp & (3<<30))) { throw DataFileException("error decoding value '" + AString::number(coded) + "' from workbench sparse trajectory file"); } if (decoded.fiberFractions[2] < 0.0f) decoded.fiberFractions[2] = 0.0f; } void FiberFractions::zero() { totalCount = 0; fiberFractions.clear(); distance = 0.0f; } CaretSparseFileWriter::CaretSparseFileWriter(const AString& fileName, const CiftiXML& xml) { if (!fileName.endsWith(".trajTEMP.wbsparse")) {//for now (and maybe forever), this format is single-purpose CaretLogWarning("sparse trajectory file '" + fileName + "' should be saved ending in .trajTEMP.wbsparse"); } m_finished = false; int64_t dimensions[2] = { xml.getDimensionLength(CiftiXML::ALONG_ROW), xml.getDimensionLength(CiftiXML::ALONG_COLUMN) }; if (dimensions[0] < 1 || dimensions[1] < 1) throw DataFileException("both dimensions must be positive"); m_xml = xml; m_dims[0] = dimensions[0];//CiftiXML doesn't support 3 dimensions yet, so we do this m_dims[1] = dimensions[1]; if (fileName.endsWith(".gz")) { throw DataFileException("wbsparse files cannot be written compressed"); }//because after we finish writing the data, we have to come back and write the lengths array m_file.open(fileName, CaretBinaryFile::WRITE_TRUNCATE); m_file.write(magic, 8); int64_t tempdims[2] = { m_dims[0], m_dims[1] }; if (ByteOrderEnum::isSystemBigEndian()) { ByteSwapping::swapBytes(tempdims, 2); } m_file.write(tempdims, 2 * sizeof(int64_t)); m_lengthArray.resize(m_dims[1], 0);//initialize the memory so that valgrind won't complain m_file.write(m_lengthArray.data(), m_dims[1] * sizeof(uint64_t));//write it to get the file to the correct length m_nextRowIndex = 0; m_valuesOffset = 8 + 2 * sizeof(int64_t) + m_dims[1] * sizeof(int64_t); } void CaretSparseFileWriter::writeRow(const int64_t& index, const int64_t* row) { CaretAssert(index < m_dims[1]); CaretAssert(index >= m_nextRowIndex); while (m_nextRowIndex < index) { m_lengthArray[m_nextRowIndex] = 0; ++m_nextRowIndex; } m_scratchArray.clear(); int64_t count = 0; for (int64_t i = 0; i < m_dims[0]; ++i) { if (row[i] != 0) { m_scratchArray.push_back(i); m_scratchArray.push_back(row[i]); ++count; } } m_lengthArray[index] = count; if (ByteOrderEnum::isSystemBigEndian()) { ByteSwapping::swapBytes(m_scratchArray.data(), m_scratchArray.size()); } m_file.write(m_scratchArray.data(), m_scratchArray.size() * sizeof(int64_t)); m_nextRowIndex = index + 1; if (m_nextRowIndex == m_dims[1]) finish(); } void CaretSparseFileWriter::writeRowSparse(const int64_t& index, const vector& indices, const vector& values) { CaretAssert(index < m_dims[1]); CaretAssert(index >= m_nextRowIndex); CaretAssert(indices.size() == values.size()); while (m_nextRowIndex < index) { m_lengthArray[m_nextRowIndex] = 0; ++m_nextRowIndex; } m_scratchArray.clear(); size_t numNonzero = indices.size();//assume no zeros m_lengthArray[index] = numNonzero; int64_t lastIndex = -1; for (size_t i = 0; i < numNonzero; ++i) { if (indices[i] <= lastIndex || indices[i] >= m_dims[0]) throw DataFileException("indices must be sorted when writing sparse rows"); lastIndex = indices[i]; m_scratchArray.push_back(indices[i]); m_scratchArray.push_back(values[i]); } if (ByteOrderEnum::isSystemBigEndian()) { ByteSwapping::swapBytes(m_scratchArray.data(), m_scratchArray.size()); } m_file.write(m_scratchArray.data(), m_scratchArray.size() * sizeof(int64_t)); m_nextRowIndex = index + 1; if (m_nextRowIndex == m_dims[1]) finish(); } void CaretSparseFileWriter::writeFibersRow(const int64_t& index, const FiberFractions* row) { if (m_scratchRow.size() != (size_t)m_dims[0]) m_scratchRow.resize(m_dims[0]); for (int64_t i = 0; i < m_dims[0]; ++i) { if (row[i].totalCount == 0) { m_scratchRow[i] = 0; } else { encodeFibers(row[i], m_scratchRow[i]); } } writeRow(index, (int64_t*)m_scratchRow.data()); } void CaretSparseFileWriter::writeFibersRowSparse(const int64_t& index, const vector& indices, const vector& values) { size_t numNonzero = values.size();//assume no zeros m_scratchSparseRow.resize(numNonzero); for (size_t i = 0; i < numNonzero; ++i) { encodeFibers(values[i], ((uint64_t*)m_scratchSparseRow.data())[i]); } writeRowSparse(index, indices, m_scratchSparseRow); } void CaretSparseFileWriter::finish() { if (m_finished) return; m_finished = true; while (m_nextRowIndex < m_dims[1]) { m_lengthArray[m_nextRowIndex] = 0; ++m_nextRowIndex; } QByteArray myXMLBytes = m_xml.writeXMLToQByteArray(); m_file.write(myXMLBytes.constData(), myXMLBytes.size()); m_file.seek(8 + 2 * sizeof(int64_t)); if (ByteOrderEnum::isSystemBigEndian()) { ByteSwapping::swapBytes(m_lengthArray.data(), m_lengthArray.size()); } m_file.write(m_lengthArray.data(), m_lengthArray.size() * sizeof(uint64_t)); m_file.close(); } CaretSparseFileWriter::~CaretSparseFileWriter() { finish(); } void CaretSparseFileWriter::encodeFibers(const FiberFractions& orig, uint64_t& coded) { coded = (((uint64_t)orig.totalCount)<<32) | (myclamp(orig.fiberFractions[0] * 1000.0f + 0.5f)<<20) | (myclamp(orig.fiberFractions[1] * 1000.0f + 0.5f)<<10) | (myclamp(orig.distance)); } uint32_t CaretSparseFileWriter::myclamp(const int& x) { if (x >= 1000) return 1000; if (x <= 0) return 0; return x; } connectome-workbench-1.4.2/src/Files/CaretSparseFile.h000066400000000000000000000104111360521144700226460ustar00rootroot00000000000000#ifndef __CARET_SPARSE_FILE_H__ #define __CARET_SPARSE_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "stdint.h" #include "AString.h" #include "CaretBinaryFile.h" #include "CiftiXML.h" #include "DataFile.h" #include "DataFileException.h" namespace caret { struct FiberFractions { uint32_t totalCount; // total number of streamline that go through the voxel std::vector fiberFractions; // fraction of totalCount for each fiber (3 orientation for now, could be zero) float distance; // average distance from seed across all streamlines void zero(); }; class CaretSparseFile /* : public DataFile */ { static void decodeFibers(const uint64_t& coded, FiberFractions& decoded);//takes a uint because right shift on signed is implementation dependent CaretBinaryFile m_file; int64_t m_dims[2], m_valuesOffset; std::vector m_indexArray, m_scratchRow; std::vector m_scratchArray, m_scratchSparseRow; CaretSparseFile(const CaretSparseFile& rhs); CiftiXML m_xml; public: const int64_t* getDimensions() { return m_dims; } CaretSparseFile() {}; virtual void readFile(const AString& filename); virtual void writeFile(const AString&) { throw DataFileException("writeFile not implemented for CaretSparseFile"); } CaretSparseFile(const AString& fileName); ///get a reference to the XML data const CiftiXML& getCiftiXML() const { return m_xml; } void getRow(const int64_t& index, int64_t* rowOut); void getRowSparse(const int64_t& index, std::vector& indicesOut, std::vector& valuesOut); void getFibersRow(const int64_t& index, FiberFractions* rowOut); void getFibersRowSparse(const int64_t& index, std::vector& indicesOut, std::vector& valuesOut); virtual ~CaretSparseFile(); }; class CaretSparseFileWriter { static void encodeFibers(const FiberFractions& orig, uint64_t& coded); static uint32_t myclamp(const int& x); CaretBinaryFile m_file; int64_t m_dims[2], m_valuesOffset, m_nextRowIndex; bool m_finished; std::vector m_lengthArray, m_scratchRow; std::vector m_scratchArray, m_scratchSparseRow; CaretSparseFileWriter(const CaretSparseFileWriter& rhs); CiftiXML m_xml; public: CaretSparseFileWriter(const AString& fileName, const CiftiXML& xml); ~CaretSparseFileWriter(); ///you must write the rows in order, though you can skip empty rows void writeRow(const int64_t& index, const int64_t* row); ///you must write the rows in order, though you can skip empty rows void writeRowSparse(const int64_t& index, const std::vector& indices, const std::vector& values); ///you must write the rows in order, though you can skip empty rows void writeFibersRow(const int64_t& index, const FiberFractions* row); ///you must write the rows in order, though you can skip empty rows void writeFibersRowSparse(const int64_t& index, const std::vector& indices, const std::vector& values); ///call this if no rows remain to be written void finish(); }; } #endif //__CARET_SPARSE_FILE_H__ connectome-workbench-1.4.2/src/Files/CaretVolumeExtension.cxx000066400000000000000000000462401360521144700243410ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretVolumeExtension.h" #include "XmlSaxParser.h" #include "GiftiMetaData.h" #include "GiftiMetaDataSaxReader.h" #include "GiftiMetaDataXmlElements.h" #include "GiftiXmlElements.h" #include "PaletteColorMapping.h" #include "PaletteColorMappingSaxReader.h" #include "PaletteColorMappingXmlElements.h" #include "PaletteNormalizationModeEnum.h" #include "CaretLogger.h" #include "XmlUnexpectedElementSaxParser.h" #include using namespace caret; using namespace std; //where should these go? static const AString CARET_VOL_EXT_ROOT = "CaretExtension"; static const AString CARET_VOL_EXT_COMMENT = "Comment"; static const AString CARET_VOL_EXT_DATE = "Date"; static const AString CARET_VOL_EXT_VOL_INFO = "VolumeInformation"; static const AString CARET_VOL_EXT_VI_COMMENT = "Comment"; static const AString CARET_VOL_EXT_VI_GUI_LABEL = "GuiLabel"; static const AString CARET_VOL_EXT_VI_STUDY_META_SET = "StudyMetaDataLinkSet"; static const AString CARET_VOL_EXT_VI_STUDY_META_LINK = "StudyMetaDataLink"; static const AString CARET_VOL_EXT_VI_TYPE = "VolumeType"; void CaretVolumeExtension::clear() { m_comment.clear(); m_date.clear(); m_attributes.clear(); m_metadata.clear(); } void CaretVolumeExtension::readFromXmlString(const AString& s) { CaretVolumeExtensionXMLReader myReader(this); CaretPointer myParser(XmlSaxParser::createXmlParser()); try { myParser->parseString(s, &myReader); } catch (XmlSaxParserException& e) { CaretLogWarning(AString("Failed to parse caret volume extension: ") + e.whatString()); } } void CaretVolumeExtension::writeAsXML(XmlWriter& xmlWriter) { xmlWriter.writeStartDocument("1.0"); xmlWriter.writeStartElement(CARET_VOL_EXT_ROOT); if (!m_comment.isEmpty()) xmlWriter.writeElementCData(CARET_VOL_EXT_COMMENT, m_comment); time_t mytime = time(NULL);//we don't have a class to deal with ISO 8601 dates, so use some C struct tm* timeinfo = localtime(&mytime);//note: this is a pointer to a static global in C library code, don't try to delete char buf[101];//we actually only need 20 bytes, but hey strftime(buf, 100, "%Y-%m-%dT%H:%M:%S", timeinfo); xmlWriter.writeElementCData(CARET_VOL_EXT_DATE, AString(buf)); if ( ! m_metadata.isEmpty()) { /* * Prior to "WB-664 Data normalization should be saved in file", VolumeFile did not contain * file metadata. If one attempts to read a volume file containing metadata with older * versions of wb_view/wb_command or Caret5, XML parsing of the CaretVolumeExtension will * immediately cease if an unexpected element is encountered. So, to minimize isses with * older versions of software, DO NOT write file metadata if it contains only one * element that is the default value (selected map) of palette normalization. */ bool writeFileMetaDataFlag = true; if (m_metadata.getNumberOfMetaData() == 1) { const AString normalizationValueString = m_metadata.get(GiftiMetaDataXmlElements::METADATA_PALETTE_NORMALIZATION_MODE); if ( ! normalizationValueString.isEmpty()) { if (normalizationValueString == PaletteNormalizationModeEnum::toName(PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA)) { writeFileMetaDataFlag = false; } } } if (writeFileMetaDataFlag) { m_metadata.writeAsXML(xmlWriter); } } int numVols = (int)m_attributes.size(); for (int i = 0; i < numVols; ++i) { m_attributes[i]->writeAsXML(xmlWriter, i); } xmlWriter.writeEndElement();//just to make it clean xmlWriter.writeEndDocument();//so, this just flushes } void SubvolumeAttributes::writeAsXML(XmlWriter& xmlWriter, int index) { XmlAttributes myattrs; myattrs.addAttribute("Index", AString::number(index)); xmlWriter.writeStartElement(CARET_VOL_EXT_VOL_INFO, myattrs); if (!m_comment.isEmpty()) xmlWriter.writeElementCData(CARET_VOL_EXT_VI_COMMENT, m_comment); if (!m_guiLabel.isEmpty()) xmlWriter.writeElementCData(CARET_VOL_EXT_VI_GUI_LABEL, m_guiLabel); if (m_labelTable != NULL) m_labelTable->writeAsXML(xmlWriter);//expect the extension to not have stuff it doesn't need, so just write everything it has m_studyMetadata.writeAsXML(xmlWriter); if (m_palette != NULL) m_palette->writeAsXML(xmlWriter); AString typeString; switch (m_type) { case ANATOMY: typeString = "Anatomy"; break; case FUNCTIONAL: typeString = "Functional"; break; case LABEL: typeString = "Label"; break; case RGB: typeString = "RGB"; break; case SEGMENTATION: typeString = "Segmentation"; break; case VECTOR: typeString = "Vector"; break; default: typeString = "Unknown"; } xmlWriter.writeElementCData(CARET_VOL_EXT_VI_TYPE, typeString); if ( ! m_metadata.isEmpty()) { m_metadata.writeAsXML(xmlWriter); } xmlWriter.writeEndElement(); } void StudyMetadataLinkSet::writeAsXML(XmlWriter& xmlWriter) {//TODO: something xmlWriter.writeStartElement(CARET_VOL_EXT_VI_STUDY_META_SET); xmlWriter.writeEndElement(); } CaretVolumeExtensionXMLReader::CaretVolumeExtensionXMLReader(CaretVolumeExtension* toFill): XmlSaxParserHandlerInterface() { CaretAssert(toFill != NULL); m_toFill = toFill; m_viIndex = -1; m_unexpectedXmlElementSaxParser.grabNew(NULL); } void CaretVolumeExtensionXMLReader::characters(const char* ch) { CaretAssert(m_charDataStack.size() != 0); CaretAssert(m_stateStack.size() != 0); switch (m_stateStack.back()) { case LABEL_TABLE: CaretAssert(m_labelReader != NULL); m_labelReader->characters(ch); break; case PALETTE_COLOR_MAPPING: CaretAssert(m_paletteReader != NULL); m_paletteReader->characters(ch); break; case ROOT_META_DATA: case VI_META_DATA: CaretAssert(m_metadataReader); m_metadataReader->characters(ch); break; case UNEXPECTED_XML: CaretAssert(m_unexpectedXmlElementSaxParser); m_unexpectedXmlElementSaxParser->characters(ch); break; default: m_charDataStack.back() += ch; } } void CaretVolumeExtensionXMLReader::endDocument() { if (m_stateStack.size() != 0) { throw XmlSaxParserException("end of document while still in an element state"); } } void CaretVolumeExtensionXMLReader::endElement(const AString& namespaceURI, const AString& localName, const AString& qualifiedName) { CaretAssert(m_charDataStack.size() != 0); CaretAssert(m_stateStack.size() != 0); AString elemCharData = m_charDataStack.back(); State myState = m_stateStack.back(); bool popState = true; switch (myState) { case INVALID: throw XmlSaxParserException("encountered end element in INVALID state"); break; case CARET_EXTENSION: break; case ROOT_COMMENT: m_toFill->m_comment = elemCharData; break; case DATE: m_toFill->m_date = elemCharData; break; case VOLUME_INFORMATION: m_viIndex = -1; break; case VI_COMMENT: CaretAssertVectorIndex(m_toFill->m_attributes, m_viIndex); m_toFill->m_attributes[m_viIndex]->m_comment = elemCharData; break; case GUI_LABEL: CaretAssertVectorIndex(m_toFill->m_attributes, m_viIndex); m_toFill->m_attributes[m_viIndex]->m_guiLabel = elemCharData; break; case LABEL_TABLE: CaretAssert(m_labelReader != NULL); m_labelReader->endElement(namespaceURI, localName, qualifiedName); if (qualifiedName == GiftiXmlElements::TAG_LABEL_TABLE) { m_labelReader->endDocument(); m_labelReader.grabNew(NULL);//make it delete now so that it can't make related bugs more confusing } else { popState = false; } break; case STUDY_META_DATA_LINK_SET: if (qualifiedName == CARET_VOL_EXT_VI_STUDY_META_SET) {//TODO: something } else { popState = false; } break; case PALETTE_COLOR_MAPPING: CaretAssert(m_paletteReader != NULL); m_paletteReader->endElement(namespaceURI, localName, qualifiedName); if (qualifiedName == PaletteColorMappingXmlElements::XML_TAG_PALETTE_COLOR_MAPPING) { m_paletteReader->endDocument(); m_paletteReader.grabNew(NULL);//ditto } else { popState = false; } break; case ROOT_META_DATA: case VI_META_DATA: CaretAssert(m_metadataReader); m_metadataReader->endElement(namespaceURI, localName, qualifiedName); if (qualifiedName == GiftiXmlElements::TAG_METADATA) { m_metadataReader->endDocument(); m_metadataReader.grabNew(NULL); } else { popState = false; } break; case VOLUME_TYPE: CaretAssertVectorIndex(m_toFill->m_attributes, m_viIndex); if (elemCharData == "Anatomy") { m_toFill->m_attributes[m_viIndex]->m_type = SubvolumeAttributes::ANATOMY; } else if (elemCharData == "Functional") { m_toFill->m_attributes[m_viIndex]->m_type = SubvolumeAttributes::FUNCTIONAL; } else if (elemCharData == "Label") { m_toFill->m_attributes[m_viIndex]->m_type = SubvolumeAttributes::LABEL; } else if (elemCharData == "RGB") { m_toFill->m_attributes[m_viIndex]->m_type = SubvolumeAttributes::RGB; } else if (elemCharData == "Segmentation") { m_toFill->m_attributes[m_viIndex]->m_type = SubvolumeAttributes::SEGMENTATION; } else if (elemCharData == "Vector") { m_toFill->m_attributes[m_viIndex]->m_type = SubvolumeAttributes::VECTOR; } else { m_toFill->m_attributes[m_viIndex]->m_type = SubvolumeAttributes::UNKNOWN; } break; case UNEXPECTED_XML: CaretAssert(m_unexpectedXmlElementSaxParser); switch (m_unexpectedXmlElementSaxParser->endElement(namespaceURI, localName, qualifiedName)) { case XmlUnexpectedElementSaxParser::ReturnCodeEnum::DONE: warning(XmlSaxParserException("Unexpected XML ignored:\n" + m_unexpectedXmlElementSaxParser->getUnexpectedContentXML())); m_unexpectedXmlElementSaxParser.grabNew(NULL); break; case XmlUnexpectedElementSaxParser::ReturnCodeEnum::ERROR: throw XmlSaxParserException("Processing of unexpected elements failed: " + m_unexpectedXmlElementSaxParser->getUnexpectedContentXML()); break; case XmlUnexpectedElementSaxParser::ReturnCodeEnum::NOT_DONE: popState = false; break; } break; } if (popState) { m_stateStack.pop_back(); m_charDataStack.pop_back(); } } void CaretVolumeExtensionXMLReader::error(const XmlSaxParserException& exception) { CaretLogWarning(AString("encountered non-fatal XML error in CaretVolumeExtension: ") + exception.whatString()); } void CaretVolumeExtensionXMLReader::fatalError(const XmlSaxParserException& exception) {//all of our members are self-deleting, no worries, just throw throw XmlSaxParserException(exception);//throw a copy of it rather than the original reference, not sure if it matters } void CaretVolumeExtensionXMLReader::startDocument() { } void CaretVolumeExtensionXMLReader::startElement(const AString& uri, const AString& localName, const AString& qName, const XmlAttributes& atts) { bool addState = true; State nextState = INVALID; AString invalidInfo = qName; if(m_stateStack.size() == 0) { if (qName != CARET_VOL_EXT_ROOT) { throw XmlSaxParserException(AString("CaretVolumeExtension encountered unexpected root element: ") + qName); } nextState = CARET_EXTENSION; } else { switch (m_stateStack.back()) { case INVALID://should NEVER happen, INVALID throws instead of pushing, so should never be on the stack throw XmlSaxParserException("something has gone wrong in the CaretVolumeExtension parser"); break; case ROOT_COMMENT://these should not have child elements, let INVALID catch them case DATE: case VI_COMMENT: case GUI_LABEL: case VOLUME_TYPE: break; case CARET_EXTENSION: if (qName == CARET_VOL_EXT_COMMENT) { nextState = ROOT_COMMENT; } else if (qName == CARET_VOL_EXT_DATE) { nextState = DATE; } else if (qName == CARET_VOL_EXT_VOL_INFO) { nextState = VOLUME_INFORMATION; m_viIndex = atts.getValueAsInt("Index"); if (m_viIndex < 0) { throw XmlSaxParserException("negative number encountered in VolumeInformation index"); } if ((int)m_toFill->m_attributes.size() <= m_viIndex) { m_toFill->m_attributes.resize(m_viIndex + 1);//don't worry, CaretPointer copy is relatively cheap } m_toFill->m_attributes[m_viIndex].grabNew(new SubvolumeAttributes()); } else if (qName == GiftiXmlElements::TAG_METADATA) { nextState = ROOT_META_DATA; m_metadataReader.grabNew(new GiftiMetaDataSaxReader(&m_toFill->m_metadata)); m_metadataReader->startDocument(); m_metadataReader->startElement(uri, localName, qName, atts); }//anything else gets caught in INVALID below break; case VOLUME_INFORMATION: if (qName == CARET_VOL_EXT_VI_COMMENT) { nextState = VI_COMMENT; } else if (qName == CARET_VOL_EXT_VI_GUI_LABEL) { nextState = GUI_LABEL; } else if (qName == GiftiXmlElements::TAG_LABEL_TABLE) { nextState = LABEL_TABLE; CaretAssertVectorIndex(m_toFill->m_attributes, m_viIndex); m_toFill->m_attributes[m_viIndex]->m_labelTable.grabNew(new GiftiLabelTable()); m_labelReader.grabNew(new GiftiLabelTableSaxReader(m_toFill->m_attributes[m_viIndex]->m_labelTable)); m_labelReader->startDocument(); m_labelReader->startElement(uri, localName, qName, atts); } else if (qName == CARET_VOL_EXT_VI_STUDY_META_SET) { nextState = STUDY_META_DATA_LINK_SET;//TODO: something } else if (qName == PaletteColorMappingXmlElements::XML_TAG_PALETTE_COLOR_MAPPING) { nextState = PALETTE_COLOR_MAPPING; CaretAssertVectorIndex(m_toFill->m_attributes, m_viIndex); m_toFill->m_attributes[m_viIndex]->m_palette.grabNew(new PaletteColorMapping); m_paletteReader.grabNew(new PaletteColorMappingSaxReader(m_toFill->m_attributes[m_viIndex]->m_palette)); m_paletteReader->startDocument(); m_paletteReader->startElement(uri, localName, qName, atts); } else if (qName == GiftiXmlElements::TAG_METADATA) { nextState = VI_META_DATA; CaretAssertVectorIndex(m_toFill->m_attributes, m_viIndex); m_metadataReader.grabNew(new GiftiMetaDataSaxReader(&m_toFill->m_attributes[m_viIndex]->m_metadata)); m_metadataReader->startDocument(); m_metadataReader->startElement(uri, localName, qName, atts); } else if (qName == CARET_VOL_EXT_VI_TYPE) { nextState = VOLUME_TYPE; } break; case LABEL_TABLE: addState = false; CaretAssert(m_labelReader != NULL); m_labelReader->startElement(uri, localName, qName, atts); break; case STUDY_META_DATA_LINK_SET: addState = false;//TODO: something break; case PALETTE_COLOR_MAPPING: addState = false; CaretAssert(m_paletteReader != NULL); m_paletteReader->startElement(uri, localName, qName, atts); break; case ROOT_META_DATA: case VI_META_DATA: addState = false; CaretAssert(m_metadataReader); m_metadataReader->startElement(uri, localName, qName, atts); break; case UNEXPECTED_XML: addState = false; CaretAssert(m_unexpectedXmlElementSaxParser); m_unexpectedXmlElementSaxParser->startElement(uri, localName, qName, atts); break; } } if (addState) { if (nextState == INVALID) { /* * If the invalid element name is not empty, * then we are processing child elements of the * invalid element. */ CaretAssert(m_unexpectedXmlElementSaxParser == NULL); m_unexpectedXmlElementSaxParser.grabNew(new XmlUnexpectedElementSaxParser()); m_unexpectedXmlElementSaxParser->startElement(uri, localName, qName, atts); nextState = UNEXPECTED_XML; } m_stateStack.push_back(nextState); m_charDataStack.push_back(AString()); } } void CaretVolumeExtensionXMLReader::warning(const caret::XmlSaxParserException& exception) { CaretLogWarning(AString("encountered XML warning in CaretVolumeExtension: ") + exception.whatString()); } connectome-workbench-1.4.2/src/Files/CaretVolumeExtension.h000066400000000000000000000107521360521144700237650ustar00rootroot00000000000000#ifndef __CARET_VOLUME_EXTENSION__ #define __CARET_VOLUME_EXTENSION__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "GiftiLabelTable.h" #include "PaletteColorMapping.h" #include "CaretPointer.h" #include #include "XmlWriter.h" #include "XmlSaxParserHandlerInterface.h" #include "PaletteColorMappingSaxReader.h" #include "GiftiLabelTableSaxReader.h" #include "GiftiMetaData.h" #include "GiftiMetaDataSaxReader.h" namespace caret { class XmlUnexpectedElementSaxParser; struct StudyMetadataLinkSet { void writeAsXML(XmlWriter& xmlWriter); };//TODO: make this do something useful struct SubvolumeAttributes { enum VolumeType { UNKNOWN, ANATOMY, FUNCTIONAL, LABEL, RGB, SEGMENTATION, VECTOR };//TODO: make this into a caret enum class? AString m_comment; AString m_guiLabel; CaretPointer m_labelTable; GiftiMetaData m_metadata; StudyMetadataLinkSet m_studyMetadata; CaretPointer m_palette; VolumeType m_type; SubvolumeAttributes() { m_type = UNKNOWN; } void writeAsXML(XmlWriter& xmlWriter, int index); }; struct CaretVolumeExtension { GiftiMetaData m_metadata; AString m_comment; AString m_date;//TODO: make a class to handle ISO-8601 dates std::vector > m_attributes; void writeAsXML(XmlWriter& xmlWriter); void readFromXmlString(const AString& s); void clear(); }; class CaretVolumeExtensionXMLReader : public XmlSaxParserHandlerInterface { enum State { INVALID, CARET_EXTENSION, ROOT_COMMENT, DATE, VOLUME_INFORMATION, VI_COMMENT, GUI_LABEL, LABEL_TABLE, STUDY_META_DATA_LINK_SET, PALETTE_COLOR_MAPPING, VOLUME_TYPE, ROOT_META_DATA, VI_META_DATA, UNEXPECTED_XML }; std::vector m_stateStack; CaretVolumeExtension* m_toFill; std::vector m_charDataStack; int m_viIndex; CaretPointer m_paletteReader; CaretPointer m_labelReader; CaretPointer m_metadataReader; CaretPointer m_unexpectedXmlElementSaxParser; CaretVolumeExtensionXMLReader();//disallow default construction CaretVolumeExtensionXMLReader(const CaretVolumeExtensionXMLReader&);//disallow copy CaretVolumeExtensionXMLReader& operator=(const CaretVolumeExtensionXMLReader&);//disallow assignment public: CaretVolumeExtensionXMLReader(CaretVolumeExtension* toFill); virtual void startElement(const AString& uri, const AString& localName, const AString& qName, const XmlAttributes& atts) ; virtual void endElement(const AString& namespaceURI, const AString& localName, const AString& qualifiedName) ; virtual void characters(const char* ch); virtual void warning(const XmlSaxParserException& exception); virtual void error(const XmlSaxParserException& exception); virtual void fatalError(const XmlSaxParserException& exception); virtual void startDocument(); virtual void endDocument(); }; } #endif //__CARET_VOLUME_EXTENSION__ connectome-workbench-1.4.2/src/Files/ChartableLineSeriesBrainordinateInterface.h000066400000000000000000000077011360521144700300350ustar00rootroot00000000000000#ifndef __CHARTABLE_BRAINORDINATE_INTERFACE_H__ #define __CHARTABLE_BRAINORDINATE_INTERFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ChartableLineSeriesInterface.h" #include "StructureEnum.h" namespace caret { class ChartDataCartesian; /** * \class caret::ChartableLineSeriesBrainordinateInterface * \brief Interface for files that are able to produce line series brainordinate charts. * \ingroup Files */ class ChartableLineSeriesBrainordinateInterface : public ChartableLineSeriesInterface { protected: ChartableLineSeriesBrainordinateInterface() { } virtual ~ChartableLineSeriesBrainordinateInterface() { } public: /** * Load charting data for the surface with the given structure and node index. * * @param structure * The surface's structure. * @param nodeIndex * Index of the node. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ virtual ChartDataCartesian* loadLineSeriesChartDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t nodeIndex) = 0; /** * Load average charting data for the surface with the given structure and node indices. * * @param structure * The surface's structure. * @param nodeIndices * Indices of the node. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ virtual ChartDataCartesian* loadAverageLineSeriesChartDataForSurfaceNodes(const StructureEnum::Enum structure, const std::vector& nodeIndices) = 0; /** * Load charting data for the voxel enclosing the given coordinate. * * @param xyz * Coordinate of voxel. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ virtual ChartDataCartesian* loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]) = 0; private: // ChartableLineSeriesBrainordinateInterface(const ChartableLineSeriesBrainordinateInterface&); // // ChartableLineSeriesBrainordinateInterface& operator=(const ChartableLineSeriesBrainordinateInterface&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE }; #ifdef __CHARTABLE_BRAINORDINATE_INTERFACE_DECLARE__ // #endif // __CHARTABLE_BRAINORDINATE_INTERFACE_DECLARE__ } // namespace #endif //__CHARTABLE_BRAINORDINATE_INTERFACE_H__ connectome-workbench-1.4.2/src/Files/ChartableLineSeriesInterface.cxx000066400000000000000000000050561360521144700257070ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHARTABLE_LINE_SERIES_INTERFACE_DECLARE__ #include "ChartableLineSeriesInterface.h" #undef __CHARTABLE_LINE_SERIES_INTERFACE_DECLARE__ #include "CaretMappableDataFile.h" using namespace caret; /** * \class caret::ChartableLineSeriesInterface * \brief Interface for files that are able to produce line charts charts. * \ingroup Files */ /** * Is the given chart data type supported by this file. * * @param chartDataType * Chart data type for testing support. * @return * True if chart data type is supported by the file, else false. */ bool ChartableLineSeriesInterface::isLineSeriesChartDataTypeSupported(const ChartOneDataTypeEnum::Enum chartDataType) const { std::vector validTypes; getSupportedLineSeriesChartDataTypes(validTypes); if (std::find(validTypes.begin(), validTypes.end(), chartDataType) != validTypes.end()) { return true; } return false; } /** * @return The CaretMappableDataFile that implements this interface. * Will be NULL if this interface is not implemented by a CaretMappableDataFile. */ CaretMappableDataFile* ChartableLineSeriesInterface::getLineSeriesChartCaretMappableDataFile() { CaretMappableDataFile* cmdf = dynamic_cast(this); CaretAssert(cmdf); return cmdf; } /** * @return The CaretMappableDataFile that implements this interface. * Will be NULL if this interface is not implemented by a CaretMappableDataFile. */ const CaretMappableDataFile* ChartableLineSeriesInterface::getLineSeriesChartCaretMappableDataFile() const { const CaretMappableDataFile* cmdf = dynamic_cast(this); CaretAssert(cmdf); return cmdf; } connectome-workbench-1.4.2/src/Files/ChartableLineSeriesInterface.h000066400000000000000000000065451360521144700253400ustar00rootroot00000000000000#ifndef __CHARTABLE_LINE_SERIES_INTERFACE_H__ #define __CHARTABLE_LINE_SERIES_INTERFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ChartOneDataTypeEnum.h" #include "StructureEnum.h" namespace caret { //class CaretMappableDataFile; class ChartDataCartesian; class CaretMappableDataFile; class ChartableLineSeriesInterface { protected: ChartableLineSeriesInterface() { } virtual ~ChartableLineSeriesInterface() { } public: /** * @return The CaretMappableDataFile that implements this interface. */ virtual CaretMappableDataFile* getLineSeriesChartCaretMappableDataFile(); /** * @return The CaretMappableDataFile that implements this interface. */ virtual const CaretMappableDataFile* getLineSeriesChartCaretMappableDataFile() const; /** * @return Is charting enabled for this file in the given tab? */ virtual bool isLineSeriesChartingEnabled(const int32_t tabIndex) const = 0; /** * @return Return true if the file's current state supports * charting data, else false. Typically a brainordinate file * is chartable if it contains more than one map. */ virtual bool isLineSeriesChartingSupported() const = 0; /** * Set charting enabled for this file in the given tab * * @param enabled * New status for charting enabled. */ virtual void setLineSeriesChartingEnabled(const int32_t tabIndex, const bool enabled) = 0; /** * Get chart data types supported by the file. * * @param chartDataTypesOut * Chart types supported by this file. */ virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const = 0; bool isLineSeriesChartDataTypeSupported(const ChartOneDataTypeEnum::Enum chartDataType) const; private: // ChartableLineSeriesInterface(const ChartableLineSeriesInterface&); // // ChartableLineSeriesInterface& operator=(const ChartableLineSeriesInterface&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE }; #ifdef __CHARTABLE_LINE_SERIES_INTERFACE_DECLARE__ // #endif // __CHARTABLE_LINE_SERIES_INTERFACE_DECLARE__ } // namespace #endif //__CHARTABLE_LINE_SERIES_INTERFACE_H__ connectome-workbench-1.4.2/src/Files/ChartableLineSeriesRowColumnInterface.h000066400000000000000000000056721360521144700272060ustar00rootroot00000000000000#ifndef __CHARTABLE_LINE_SERIES_ROW_COLUMN_INTERFACE_H__ #define __CHARTABLE_LINE_SERIES_ROW_COLUMN_INTERFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ChartableLineSeriesInterface.h" namespace caret { class ChartDataCartesian; /** * \class caret::ChartableLineSeriesRowColumnInterface * \brief Interface for charts that load a row and/or column of data. * \ingroup Files */ class ChartableLineSeriesRowColumnInterface : public ChartableLineSeriesInterface { public: ChartableLineSeriesRowColumnInterface() { } virtual ~ChartableLineSeriesRowColumnInterface() { }; /** * Load charting data for the given column index. * * @param columnIndex * Index of the column. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ virtual ChartDataCartesian* loadLineSeriesChartDataForColumn(const int32_t columnIndex) = 0; /** * Load charting data for the given row index. * * @param rowIndex * Index of the row. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ virtual ChartDataCartesian* loadLineSeriesChartDataForRow(const int32_t rowIndex) = 0; // ADD_NEW_METHODS_HERE private: ChartableLineSeriesRowColumnInterface(const ChartableLineSeriesRowColumnInterface&); ChartableLineSeriesRowColumnInterface& operator=(const ChartableLineSeriesRowColumnInterface&); // ADD_NEW_MEMBERS_HERE }; #ifdef __CHARTABLE_LINE_SERIES_ROW_COLUMN_INTERFACE_DECLARE__ // #endif // __CHARTABLE_LINE_SERIES_ROW_COLUMN_INTERFACE_DECLARE__ } // namespace #endif //__CHARTABLE_LINE_SERIES_ROW_COLUMN_INTERFACE_H__ connectome-workbench-1.4.2/src/Files/ChartableMatrixInterface.cxx000066400000000000000000000064201360521144700251050ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHARTABLE_MATRIX_INTERFACE_DECLARE__ #include "ChartableMatrixInterface.h" #undef __CHARTABLE_MATRIX_INTERFACE_DECLARE__ #include "CaretMappableDataFile.h" #include "CiftiMappableDataFile.h" using namespace caret; /** * \class caret::ChartableMatrixInterface * \brief Interface for files that are able to produce charts. * \ingroup Files */ /** * Is the given chart data type supported by this file. * * @param chartDataType * Chart data type for testing support. * @return * True if chart data type is supported by the file, else false. */ bool ChartableMatrixInterface::isMatrixChartDataTypeSupported(const ChartOneDataTypeEnum::Enum chartDataType) const { std::vector validTypes; getSupportedMatrixChartDataTypes(validTypes); if (std::find(validTypes.begin(), validTypes.end(), chartDataType) != validTypes.end()) { return true; } return false; } /** * @return The CaretMappableDataFile that implements this interface. * Will be NULL if this interface is not implemented by a CaretMappableDataFile. */ CaretMappableDataFile* ChartableMatrixInterface::getMatrixChartCaretMappableDataFile() { CaretMappableDataFile* cmdf = dynamic_cast(this); CaretAssert(cmdf); return cmdf; } /** * @return The CaretMappableDataFile that implements this interface. * Will be NULL if this interface is not implemented by a CaretMappableDataFile. */ const CaretMappableDataFile* ChartableMatrixInterface::getMatrixChartCaretMappableDataFile() const { const CaretMappableDataFile* cmdf = dynamic_cast(this); CaretAssert(cmdf); return cmdf; } /** * @return The CaretMappableDataFile that implements this interface. * Will be NULL if this interface is not implemented by a CaretMappableDataFile. */ CiftiMappableDataFile* ChartableMatrixInterface::getMatrixChartCiftiMappableDataFile() { CiftiMappableDataFile* cmdf = dynamic_cast(this); CaretAssert(cmdf); return cmdf; } /** * @return The CaretMappableDataFile that implements this interface. * Will be NULL if this interface is not implemented by a CaretMappableDataFile. */ const CiftiMappableDataFile* ChartableMatrixInterface::getMatrixChartCiftiMappableDataFile() const { const CiftiMappableDataFile* cmdf = dynamic_cast(this); CaretAssert(cmdf); return cmdf; } connectome-workbench-1.4.2/src/Files/ChartableMatrixInterface.h000066400000000000000000000147141360521144700245370ustar00rootroot00000000000000#ifndef __CHARTABLE_MATRIX_INTERFACE_H__ #define __CHARTABLE_MATRIX_INTERFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretColorEnum.h" #include "ChartOneDataTypeEnum.h" #include "ChartMatrixLoadingDimensionEnum.h" #include "CiftiParcelColoringModeEnum.h" #include "YokingGroupEnum.h" namespace caret { class CaretMappableDataFile; class ChartMatrixDisplayProperties; class CiftiMappableDataFile; class CiftiParcelsMap; class ChartableMatrixInterface { protected: ChartableMatrixInterface() { } virtual ~ChartableMatrixInterface() { } public: /** * Get the matrix dimensions. * * @param numberOfRowsOut * Number of rows in the matrix. * @param numberOfColumnsOut * Number of rows in the matrix. */ virtual void getMatrixDimensions(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) const = 0; /** * Get the matrix RGBA coloring for this matrix data creator. * * @param numberOfRowsOut * Number of rows in the coloring matrix. * @param numberOfColumnsOut * Number of rows in the coloring matrix. * @param rgbaOut * RGBA coloring output with number of elements * (numberOfRowsOut * numberOfColumnsOut * 4). * @return * True if data output data is valid, else false. */ virtual bool getMatrixDataRGBA(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut, std::vector& rgbaOut) const = 0; /** * Get the value, row name, and column name for a cell in the matrix. * * @param rowIndex * The row index. * @param columnIndex * The column index. * @param cellValueOut * Output containing value in the cell. * @param rowNameOut * Name of row corresponding to row index. * @param columnNameOut * Name of column corresponding to column index. * @return * True if the output values are valid (valid row/column indices). */ virtual bool getMatrixCellAttributes(const int32_t rowIndex, const int32_t columnIndex, AString& cellValueOut, AString& rowNameOut, AString& columnNameOut) const = 0; /** * @return The matrix display properties for the given tab. * @param tabIndex * Index of tab. */ virtual const ChartMatrixDisplayProperties* getChartMatrixDisplayProperties(const int32_t tabIndex) const = 0; /** * @return The matrix display properties for the given tab. * @param tabIndex * Index of tab. */ virtual ChartMatrixDisplayProperties* getChartMatrixDisplayProperties(const int32_t tabIndex) = 0; /** * @return The CaretMappableDataFile that implements this interface. */ virtual CaretMappableDataFile* getMatrixChartCaretMappableDataFile(); /** * @return The CaretMappableDataFile that implements this interface (const methdod). */ virtual const CaretMappableDataFile* getMatrixChartCaretMappableDataFile() const; /** * @return The CiftiMappableDataFile that implements this interface. * May be NULL ! */ virtual CiftiMappableDataFile* getMatrixChartCiftiMappableDataFile(); /** * @return The CiftiMappableDataFile that implements this interface (const methdod). * May be NULL ! */ virtual const CiftiMappableDataFile* getMatrixChartCiftiMappableDataFile() const; /** * @return Is charting enabled for this file in the given tab? */ virtual bool isMatrixChartingEnabled(const int32_t tabIndex) const = 0; /** * @return Return true if the file's current state supports * charting data, else false. Typically a brainordinate file * is chartable if it contains more than one map. */ virtual bool isMatrixChartingSupported() const = 0; /** * Set charting enabled for this file in the given tab * * @param enabled * New status for charting enabled. */ virtual void setMatrixChartingEnabled(const int32_t tabIndex, const bool enabled) = 0; /** * Get chart data types supported by the file. * * @param chartDataTypesOut * Chart types supported by this file. */ virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const = 0; bool isMatrixChartDataTypeSupported(const ChartOneDataTypeEnum::Enum chartDataType) const; // ADD_NEW_METHODS_HERE private: ChartableMatrixInterface(const ChartableMatrixInterface&); ChartableMatrixInterface& operator=(const ChartableMatrixInterface&); // ADD_NEW_MEMBERS_HERE }; #ifdef __CHARTABLE_MATRIX_INTERFACE_DECLARE__ // #endif // __CHARTABLE_MATRIX_INTERFACE_DECLARE__ } // namespace #endif //__CHARTABLE_MATRIX_INTERFACE_H__ connectome-workbench-1.4.2/src/Files/ChartableMatrixParcelInterface.h000066400000000000000000000156541360521144700256720ustar00rootroot00000000000000#ifndef __CHARTABLE_MATRIX_PARCEL_REORDER_INTERFACE_H__ #define __CHARTABLE_MATRIX_PARCEL_REORDER_INTERFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ChartableMatrixInterface.h" namespace caret { class CiftiParcelLabelFile; class CiftiParcelReordering; class ChartableMatrixParcelInterface : public ChartableMatrixInterface { protected: ChartableMatrixParcelInterface() { } virtual ~ChartableMatrixParcelInterface() { } public: /** * Get the selected parcel label file used for reordering of parcels. * * @param compatibleParcelLabelFilesOut * All Parcel Label files that are compatible with file implementing * this interface. * @param selectedParcelLabelFileOut * The selected parcel label file used for reordering the parcels. * May be NULL! * @param selectedParcelLabelFileMapIndexOut * Map index in the selected parcel label file. * @param enabledStatusOut * Enabled status of reordering. */ virtual void getSelectedParcelLabelFileAndMapForReordering(std::vector& compatibleParcelLabelFilesOut, CiftiParcelLabelFile* &selectedParcelLabelFileOut, int32_t& selectedParcelLabelFileMapIndexOut, bool& enabledStatusOut) const = 0; /** * Set the selected parcel label file used for reordering of parcels. * * @param selectedParcelLabelFile * The selected parcel label file used for reordering the parcels. * May be NULL! * @param selectedParcelLabelFileMapIndex * Map index in the selected parcel label file. * @param enabledStatus * Enabled status of reordering. */ virtual void setSelectedParcelLabelFileAndMapForReordering(CiftiParcelLabelFile* selectedParcelLabelFile, const int32_t selectedParcelLabelFileMapIndex, const bool enabledStatus) = 0; /** * Create the parcel reordering for the given map index using * the given parcel label file and its map index. * * @param parcelLabelFile * The selected parcel label file used for reordering the parcels. * @param parcelLabelFileMapIndex * Map index in the selected parcel label file. * @param errorMessageOut * Error message output. Will only be non-empty if NULL is returned. * @return * Pointer to parcel reordering or NULL if not found. */ virtual bool createParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex, AString& errorMessageOut) = 0; /** * Get the parcel reordering for the given map index that was created using * the given parcel label file and its map index. * * @param parcelLabelFile * The selected parcel label file used for reordering the parcels. * @param parcelLabelFileMapIndex * Map index in the selected parcel label file. * @return * Pointer to parcel reordering or NULL if not found. */ virtual const CiftiParcelReordering* getParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex) const = 0; /** * @return Coloring mode for selected parcel. */ virtual CiftiParcelColoringModeEnum::Enum getSelectedParcelColoringMode() const = 0; /** * Set the coloring mode for selected parcel. * * @param coloringMode * New value for coloring mode. */ virtual void setSelectedParcelColoringMode(const CiftiParcelColoringModeEnum::Enum coloringMode) = 0; /** * @return Color for selected parcel. */ virtual CaretColorEnum::Enum getSelectedParcelColor() const = 0; /** * @return True if loading attributes (column/row, yoking) are * supported by this file type. */ virtual bool isSupportsLoadingAttributes() = 0; /** * @return The matrix loading type (by row/column). */ virtual ChartMatrixLoadingDimensionEnum::Enum getMatrixLoadingDimension() const = 0; /** * Set the matrix loading type (by row/column). * * @param matrixLoadingType * New value for matrix loading type. */ virtual void setMatrixLoadingDimension(const ChartMatrixLoadingDimensionEnum::Enum matrixLoadingType) = 0; /** * Set color for selected parcel. * * @param color * New color for selected parcel. */ virtual void setSelectedParcelColor(const CaretColorEnum::Enum color) = 0; /** * @return Selected yoking group. */ virtual YokingGroupEnum::Enum getYokingGroup() const = 0; /** * Set the selected yoking group. * * @param yokingGroup * New value for yoking group. */ virtual void setYokingGroup(const YokingGroupEnum::Enum yokingType) = 0; private: ChartableMatrixParcelInterface(const ChartableMatrixParcelInterface&); ChartableMatrixParcelInterface& operator=(const ChartableMatrixParcelInterface&); // ADD_NEW_MEMBERS_HERE }; #ifdef __CHARTABLE_MATRIX_INTERFACE_PARCEL_REORDER_DECLARE__ // #endif // __CHARTABLE_MATRIX_INTERFACE_PARCEL_REORDER_DECLARE__ } // namespace #endif //__CHARTABLE_MATRIX_PARCEL_REORDER_INTERFACE_H__ connectome-workbench-1.4.2/src/Files/ChartableMatrixSeriesInterface.h000066400000000000000000000043221360521144700257040ustar00rootroot00000000000000#ifndef __CHARTABLE_MATRIX_SERIES_INTERFACE_H__ #define __CHARTABLE_MATRIX_SERIES_INTERFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ChartableMatrixInterface.h" #include "MapYokingGroupEnum.h" namespace caret { class ChartableMatrixSeriesInterface : public ChartableMatrixInterface { public: ChartableMatrixSeriesInterface() { } virtual ~ChartableMatrixSeriesInterface() { } virtual MapYokingGroupEnum::Enum getMatrixRowColumnMapYokingGroup(const int32_t tabIndex) const = 0; virtual void setMatrixRowColumnMapYokingGroup(const int32_t tabIndex, const MapYokingGroupEnum::Enum yokingType) = 0; virtual int32_t getSelectedMapIndex(const int32_t tabIndex) const = 0; virtual void setSelectedMapIndex(const int32_t tabIndex, const int32_t mapIndex) = 0; // ADD_NEW_METHODS_HERE private: ChartableMatrixSeriesInterface(const ChartableMatrixSeriesInterface&); ChartableMatrixSeriesInterface& operator=(const ChartableMatrixSeriesInterface&); // ADD_NEW_MEMBERS_HERE }; #ifdef __CHARTABLE_MATRIX_SERIES_INTERFACE_DECLARE__ // #endif // __CHARTABLE_MATRIX_SERIES_INTERFACE_DECLARE__ } // namespace #endif //__CHARTABLE_MATRIX_SERIES_INTERFACE_H__ connectome-workbench-1.4.2/src/Files/ChartableTwoFileBaseChart.cxx000066400000000000000000000274751360521144700251630ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHARTABLE_TWO_FILE_BASE_CHART_DECLARE__ #include "ChartableTwoFileBaseChart.h" #undef __CHARTABLE_TWO_FILE_BASE_CHART_DECLARE__ #include "AnnotationPercentSizeText.h" #include "CaretAssert.h" #include "CaretMappableDataFile.h" #include "CiftiMappableDataFile.h" #include "EventManager.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ChartableTwoFileBaseChart * \brief Base class for File Charting Delegates. * \ingroup Files * * The first version of charting used interfaces for each * charting type. This required some files to subclass * several interfaces and significant modification to any * class that supported charting. * * The reasons for using this 'delegate' are to avoid * extensive modifications to many file classes and to * avoid name clashes with the version one of charting. * Some of the original charting needs to be preserved * to support loading of older scenes. */ /** * Constructor. * * @param chartType * Type of chart provided by this delegate. * @param parentCaretMappableDataFile * Parent caret mappable data file that this delegate supports. */ ChartableTwoFileBaseChart::ChartableTwoFileBaseChart(const ChartTwoDataTypeEnum::Enum chartType, CaretMappableDataFile* parentCaretMappableDataFile) : CaretObjectTracksModification(), m_chartType(chartType), m_parentCaretMappableDataFile(parentCaretMappableDataFile) { CaretAssert(m_chartType != ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID); CaretAssert(m_parentCaretMappableDataFile); /* will be NULL if file is not a cifti mappable file */ m_parentCiftiMappableDataFile = dynamic_cast(m_parentCaretMappableDataFile); setDefaultAxisTitles(); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_bottomAxisTitleText", &m_bottomAxisTitleText); m_sceneAssistant->add("m_leftRightAxisTitleText", &m_leftRightAxisTitleText); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_CHART_LABEL_GET); } /** * Destructor. */ ChartableTwoFileBaseChart::~ChartableTwoFileBaseChart() { EventManager::get()->removeAllEventsFromListener(this); delete m_sceneAssistant; } /** * Set the default titles for the axes. */ void ChartableTwoFileBaseChart::setDefaultAxisTitles() { m_bottomAxisTitleText = setDefaultAxisTitle(ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM); m_leftRightAxisTitleText = setDefaultAxisTitle(ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT); } /** * Set the default axis title. * * @param axisLocation * Location of the axis. */ AString ChartableTwoFileBaseChart::setDefaultAxisTitle(const ChartAxisLocationEnum::Enum axisLocation) { AString title; switch (axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: switch (m_chartType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: title = "Data"; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: title = CaretUnitsTypeEnum::toGuiName(m_compoundChartDataType.getLineChartUnitsAxisX()); switch (m_compoundChartDataType.getLineChartUnitsAxisX()) { case CaretUnitsTypeEnum::NONE: title = "Data"; break; case CaretUnitsTypeEnum::HERTZ: break; case CaretUnitsTypeEnum::METERS: break; case CaretUnitsTypeEnum::PARTS_PER_MILLION: break; case CaretUnitsTypeEnum::RADIANS: break; case CaretUnitsTypeEnum::SECONDS: break; } break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; } break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: { switch (m_chartType) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: title = "Counts"; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: title = "Value"; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; } } break; } return title; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ChartableTwoFileBaseChart::toString() const { return "ChartableTwoFileBaseChart"; } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void ChartableTwoFileBaseChart::receiveEvent(Event* /*event*/) { } /** * @return The CaretMappableDataFile that provided this delegate. */ CaretMappableDataFile* ChartableTwoFileBaseChart::getCaretMappableDataFile() { return m_parentCaretMappableDataFile; } /** * @return The CaretMappableDataFile that provided this delegate. */ const CaretMappableDataFile* ChartableTwoFileBaseChart::getCaretMappableDataFile() const { return m_parentCaretMappableDataFile; } /** * @return The CiftiMappableDataFile that provided this delegate. * NULL is returned if not a CiftiMappableDataFile. */ CiftiMappableDataFile* ChartableTwoFileBaseChart::getCiftiMappableDataFile() { return m_parentCiftiMappableDataFile; } /** * @return The CiftiMappableDataFile that provided this delegate. * NULL is returned if not a CiftiMappableDataFile. */ const CiftiMappableDataFile* ChartableTwoFileBaseChart::getCiftiMappableDataFile() const { return m_parentCiftiMappableDataFile; } /** * @return Chart version two data type */ ChartTwoDataTypeEnum::Enum ChartableTwoFileBaseChart::getChartTwoDataType() const { return m_chartType; } /** * @return Chart compound data type supported by subclass. */ ChartTwoCompoundDataType ChartableTwoFileBaseChart::getChartTwoCompoundDataType() const { CaretAssertMessage((m_compoundChartDataType.getChartTwoDataType() != ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID), "Data type is invalid, was updateChartCompoundDataTypeAfterFileChanges() called by " "implementing class."); return m_compoundChartDataType; } /** * Set the chart compound data type. Subclasses of this base class MUST * call this method whenever the content of the delegatee file changes. * * @param compoundChartDataType * Updated chart compound data type. Its basic data type MUST * match the data type passed to the constructor. */ void ChartableTwoFileBaseChart::updateChartTwoCompoundDataTypeAfterFileChanges(const ChartTwoCompoundDataType compoundChartDataType) { CaretAssert(m_chartType == compoundChartDataType.getChartTwoDataType()); m_compoundChartDataType = compoundChartDataType; setDefaultAxisTitles(); } /** * @return Annotation for the bottom axis title (const method) */ AString ChartableTwoFileBaseChart::getBottomAxisTitle() const { return m_bottomAxisTitleText; } /** * Set the bottom axis title. * * @param title * New bottom axis title. */ void ChartableTwoFileBaseChart::setBottomAxisTitle(const AString& title) { if (title != m_bottomAxisTitleText) { m_bottomAxisTitleText = title; setModified(); } } /** * @return Annotation for the bottom axis title (const method) */ AString ChartableTwoFileBaseChart::getLeftRightAxisTitle() const { return m_leftRightAxisTitleText; } /** * Set the left/right axis title. * * @param title * New left/right axis title. */ void ChartableTwoFileBaseChart::setLeftRightAxisTitle(const AString& title) { if (title != m_leftRightAxisTitleText) { m_leftRightAxisTitleText = title; setModified(); } } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* ChartableTwoFileBaseChart::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ChartableTwoFileBaseChart", 3); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); saveSubClassDataToScene(sceneAttributes, sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ChartableTwoFileBaseChart::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } setDefaultAxisTitles(); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); restoreSubClassDataFromScene(sceneAttributes, sceneClass); if (sceneClass->getVersionNumber() <= 2) { AnnotationPercentSizeText bottomTitle(AnnotationAttributesDefaultTypeEnum::NORMAL, AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); bottomTitle.restoreFromScene(sceneAttributes, sceneClass->getClass("m_bottomAxisTitle")); if ( ! bottomTitle.getText().isEmpty()) { m_bottomAxisTitleText = bottomTitle.getText(); } AnnotationPercentSizeText leftRightTitle(AnnotationAttributesDefaultTypeEnum::NORMAL, AnnotationTextFontSizeTypeEnum::PERCENTAGE_OF_VIEWPORT_HEIGHT); leftRightTitle.restoreFromScene(sceneAttributes, sceneClass->getClass("m_leftRightAxisTitle")); if ( ! leftRightTitle.getText().isEmpty()) { m_leftRightAxisTitleText = leftRightTitle.getText(); } } } connectome-workbench-1.4.2/src/Files/ChartableTwoFileBaseChart.h000066400000000000000000000111661360521144700245760ustar00rootroot00000000000000#ifndef __CHARTABLE_TWO_FILE_BASE_CHART_H__ #define __CHARTABLE_TWO_FILE_BASE_CHART_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "ChartAxisLocationEnum.h" #include "CaretObjectTracksModification.h" #include "ChartTwoCompoundDataType.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" namespace caret { class CaretMappableDataFile; class CiftiMappableDataFile; class SceneClassAssistant; class ChartableTwoFileBaseChart : public CaretObjectTracksModification, public EventListenerInterface, public SceneableInterface { protected: ChartableTwoFileBaseChart(const ChartTwoDataTypeEnum::Enum chartType, CaretMappableDataFile* parentCaretMappableDataFile); public: virtual ~ChartableTwoFileBaseChart(); /** * @return Is this charting valid ? */ virtual bool isValid() const = 0; /** * @return Is this charting empty (no data at this time) */ virtual bool isEmpty() const = 0; CaretMappableDataFile* getCaretMappableDataFile(); const CaretMappableDataFile* getCaretMappableDataFile() const; CiftiMappableDataFile* getCiftiMappableDataFile(); const CiftiMappableDataFile* getCiftiMappableDataFile() const; ChartTwoDataTypeEnum::Enum getChartTwoDataType() const; ChartTwoCompoundDataType getChartTwoCompoundDataType() const; AString getBottomAxisTitle() const; void setBottomAxisTitle(const AString& title); AString getLeftRightAxisTitle() const; void setLeftRightAxisTitle(const AString& title); // ADD_NEW_METHODS_HERE virtual AString toString() const override; virtual void receiveEvent(Event* event) override; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) override; virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) override; protected: void updateChartTwoCompoundDataTypeAfterFileChanges(const ChartTwoCompoundDataType compoundChartDataType); virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) = 0; virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) = 0; private: ChartableTwoFileBaseChart() = delete; ChartableTwoFileBaseChart(const ChartableTwoFileBaseChart&); ChartableTwoFileBaseChart& operator=(const ChartableTwoFileBaseChart&); void setDefaultAxisTitles(); AString setDefaultAxisTitle(const ChartAxisLocationEnum::Enum axisLocation); const ChartTwoDataTypeEnum::Enum m_chartType; CaretMappableDataFile* m_parentCaretMappableDataFile; CiftiMappableDataFile* m_parentCiftiMappableDataFile; SceneClassAssistant* m_sceneAssistant; ChartTwoCompoundDataType m_compoundChartDataType; AString m_bottomAxisTitleText; AString m_leftRightAxisTitleText; static float constexpr s_defaultFontPercentViewportSize = 5.0; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHARTABLE_TWO_FILE_BASE_CHART_DECLARE__ // #endif // __CHARTABLE_TWO_FILE_BASE_CHART_DECLARE__ } // namespace #endif //__CHARTABLE_TWO_FILE_BASE_CHART_H__ connectome-workbench-1.4.2/src/Files/ChartableTwoFileDelegate.cxx000066400000000000000000000520551360521144700250310ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CHARTABLE_TWO_FILE_DELEGATE_DECLARE__ #include "ChartableTwoFileDelegate.h" #undef __CHARTABLE_TWO_INTERFACE_DECLARE__ #include "CaretAssert.h" #include "CaretMappableDataFile.h" #include "ChartableTwoFileHistogramChart.h" #include "ChartableTwoFileLineSeriesChart.h" #include "ChartableTwoFileMatrixChart.h" #include "CiftiConnectivityMatrixParcelFile.h" #include "CiftiMappableDataFile.h" #include "CiftiParcelLabelFile.h" #include "CiftiParcelReordering.h" #include "CiftiParcelScalarFile.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ChartableTwoFileDelegate * \brief Interface for files that are chartable. Contains functionality but no data. * \ingroup Files */ /** * Constructor. * * @param caretMappableDataFile * Caret Mappable Data File this delegate charts. */ ChartableTwoFileDelegate::ChartableTwoFileDelegate(CaretMappableDataFile* caretMappableDataFile) : CaretObjectTracksModification(), SceneableInterface(), m_caretMappableDataFile(caretMappableDataFile) { CaretAssert(m_caretMappableDataFile); m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); clear(); } /** * Destructor. */ ChartableTwoFileDelegate::~ChartableTwoFileDelegate() { } /** * Update after the file has been read or content has changed. */ void ChartableTwoFileDelegate::updateAfterFileChanged() { CaretAssert(m_caretMappableDataFile); ChartTwoHistogramContentTypeEnum::Enum histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_UNSUPPORTED; ChartTwoLineSeriesContentTypeEnum::Enum lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED; ChartTwoMatrixContentTypeEnum::Enum matrixType = ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED; std::vector validMatrixRowColumnSelectionDimensions; switch (m_caretMappableDataFile->getDataFileType()) { case DataFileTypeEnum::CONNECTIVITY_DENSE: histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; matrixType = ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE; validMatrixRowColumnSelectionDimensions.push_back(ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW); validMatrixRowColumnSelectionDimensions.push_back(ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN); break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: matrixType = ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE; validMatrixRowColumnSelectionDimensions.push_back(ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN); break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA; matrixType = ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE; validMatrixRowColumnSelectionDimensions.push_back(ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN); break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA; matrixType = ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE; validMatrixRowColumnSelectionDimensions.push_back(ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN); break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_ROW_SCALAR_DATA; matrixType = ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_SCALARS; validMatrixRowColumnSelectionDimensions.push_back(ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW); break; case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: break; case DataFileTypeEnum::METRIC: histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA; break; case DataFileTypeEnum::METRIC_DYNAMIC: histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: break; case DataFileTypeEnum::VOLUME: if ( ! m_caretMappableDataFile->isMappedWithLabelTable()) { histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; lineSeriesType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA; } break; case DataFileTypeEnum::VOLUME_DYNAMIC: histogramType = ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA; break; } if (m_histogramCharting) { if (histogramType != m_histogramCharting->getHistogramContentType()) { m_histogramCharting.reset(); } } if ( ! m_histogramCharting) { m_histogramCharting = std::unique_ptr(new ChartableTwoFileHistogramChart(histogramType, m_caretMappableDataFile)); } if (m_lineSeriesCharting) { if (lineSeriesType != m_lineSeriesCharting->getLineSeriesContentType()) { m_lineSeriesCharting.reset(); } } if ( ! m_lineSeriesCharting) { m_lineSeriesCharting = std::unique_ptr(new ChartableTwoFileLineSeriesChart(lineSeriesType, m_caretMappableDataFile)); } if (m_matrixCharting) { if (matrixType != m_matrixCharting->getMatrixContentType()) { m_matrixCharting.reset(); } else { /* * Test for change in valid dimensions but do not alter content of * "validMatrixRowColumnSelectionDimensions" since it order is important */ std::vector newDims(validMatrixRowColumnSelectionDimensions); std::sort(newDims.begin(), newDims.end()); std::vector currentDims; m_matrixCharting->getValidRowColumnSelectionDimensions(currentDims); std::sort(currentDims.begin(), currentDims.end()); if ( ! std::equal(currentDims.begin(), currentDims.end(), newDims.begin())) { m_matrixCharting.reset(); } } } if ( ! m_matrixCharting) { m_matrixCharting = std::unique_ptr(new ChartableTwoFileMatrixChart(matrixType, m_caretMappableDataFile, validMatrixRowColumnSelectionDimensions)); } clearModified(); } /** * Clear the content. */ void ChartableTwoFileDelegate::clear() { m_histogramCharting = std::unique_ptr(new ChartableTwoFileHistogramChart(ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_UNSUPPORTED, m_caretMappableDataFile)); m_lineSeriesCharting = std::unique_ptr(new ChartableTwoFileLineSeriesChart(ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED, m_caretMappableDataFile)); std::vector validMatrixRowColumnSelectionDimensions; m_matrixCharting = std::unique_ptr(new ChartableTwoFileMatrixChart(ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED, m_caretMappableDataFile, validMatrixRowColumnSelectionDimensions)); } /** * Clear the modification status of this instance. */ void ChartableTwoFileDelegate::clearModified() { m_histogramCharting->clearModified(); m_lineSeriesCharting->clearModified(); m_matrixCharting->clearModified(); } /** * @return True if this instance is modified, else false. */ bool ChartableTwoFileDelegate::isModified() const { if (m_histogramCharting->isModified()) { return true; } if (m_matrixCharting->isModified()) { return true; } if (m_lineSeriesCharting->isModified()) { return true; } return false; } /** * @return The CaretMappableDataFile that implements this interface. * NULL is returned if not a CaretMappableDataFile. */ CaretMappableDataFile* ChartableTwoFileDelegate::getCaretMappableDataFile() { return m_caretMappableDataFile; } /** * @return The CaretMappableDataFile that implements this interface. * NULL is returned if not a CaretMappableDataFile. */ const CaretMappableDataFile* ChartableTwoFileDelegate::getCaretMappableDataFile() const { return m_caretMappableDataFile; } /** * @return Histogram charting. */ ChartableTwoFileHistogramChart* ChartableTwoFileDelegate::getHistogramCharting() { return m_histogramCharting.get(); } /** * @return Histogram charting. */ const ChartableTwoFileHistogramChart* ChartableTwoFileDelegate::getHistogramCharting() const { return m_histogramCharting.get(); } /** * @return Line series charting. */ ChartableTwoFileLineSeriesChart* ChartableTwoFileDelegate::getLineSeriesCharting() { return m_lineSeriesCharting.get(); } /** * @return Line series charting. */ const ChartableTwoFileLineSeriesChart* ChartableTwoFileDelegate::getLineSeriesCharting() const { return m_lineSeriesCharting.get(); } /** * @return Matrix charting. */ ChartableTwoFileMatrixChart* ChartableTwoFileDelegate::getMatrixCharting() { return m_matrixCharting.get(); } /** * @return Matrix charting. */ const ChartableTwoFileMatrixChart* ChartableTwoFileDelegate::getMatrixCharting() const { return m_matrixCharting.get(); } /** * Does this file support any type of charting? */ bool ChartableTwoFileDelegate::isChartingTwoSupported() const { std::vector chartDataTypes; getSupportedChartTwoDataTypes(chartDataTypes); return ( ! chartDataTypes.empty()); } /** * Test for support of the given chart data type. * * @param chartDataType * Type of chart data. * @return * True if the chart data type is supported, else false. */ bool ChartableTwoFileDelegate::isChartingSupportedForChartTwoDataType(const ChartTwoDataTypeEnum::Enum chartDataType) const { std::vector chartDataTypes; getSupportedChartTwoDataTypes(chartDataTypes); if (std::find(chartDataTypes.begin(), chartDataTypes.end(), chartDataType) != chartDataTypes.end()) { return true; } return false; } /** * Test for support of the given chart compound data type. * * @param chartCompoundDataType * Type of chart compound data. * @return * True if the chart compound data type is supported, else false. */ bool ChartableTwoFileDelegate::isChartingSupportedForChartTwoCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) const { std::vector chartCompoundDataTypes; getSupportedChartTwoCompoundDataTypes(chartCompoundDataTypes); for (auto& ccdt : chartCompoundDataTypes) { if (ccdt == chartCompoundDataType) { return true; } } return false; } /** * Get chart data types supported by this file. * * @param chartDataTypesOut * Output containing all chart data types supported by this data file. */ void ChartableTwoFileDelegate::getSupportedChartTwoDataTypes(std::vector& chartDataTypesOut) const { chartDataTypesOut.clear(); if (m_histogramCharting != NULL) { chartDataTypesOut.push_back(m_histogramCharting->getChartTwoDataType()); } if (m_lineSeriesCharting!= NULL) { chartDataTypesOut.push_back(m_lineSeriesCharting->getChartTwoDataType()); } if (m_matrixCharting != NULL) { chartDataTypesOut.push_back(m_matrixCharting->getChartTwoDataType()); } } /** * Get chart data types supported by this file. * * @param chartDataTypesOut * Output containing all chart data types supported by this data file. */ void ChartableTwoFileDelegate::getSupportedChartTwoCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const { chartCompoundDataTypesOut.clear(); if (m_histogramCharting->getHistogramContentType() != ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_UNSUPPORTED) { chartCompoundDataTypesOut.push_back(m_histogramCharting->getChartTwoCompoundDataType()); } if (m_lineSeriesCharting->getLineSeriesContentType() != ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED) { chartCompoundDataTypesOut.push_back(m_lineSeriesCharting->getChartTwoCompoundDataType()); } if (m_matrixCharting->getMatrixContentType() != ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED) { chartCompoundDataTypesOut.push_back(m_matrixCharting->getChartTwoCompoundDataType()); } } /** * Get the chart compound data type supported by this file that uses the given * chart data type. * * @param chartDataType * The chart data type. * @param chartCompoundDataTypeOut * Output with the chart compound data type. * @return * True if there is output chart compound data type is valid. * False if output chart compound data type is invalid OR if chartDataType is invalid. */ bool ChartableTwoFileDelegate::getChartTwoCompoundDataTypeForChartTwoDataType(const ChartTwoDataTypeEnum::Enum chartDataType, ChartTwoCompoundDataType& chartCompoundDataTypeOut) const { std::vector chartCompoundDataTypes; getSupportedChartTwoCompoundDataTypes(chartCompoundDataTypes); for (auto& cdt : chartCompoundDataTypes) { if (cdt.getChartTwoDataType() == chartDataType) { chartCompoundDataTypeOut = cdt; return true; } } /* default constructor is invalid data type */ chartCompoundDataTypeOut = ChartTwoCompoundDataType(); return false; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* ChartableTwoFileDelegate::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { if ( ! isChartingTwoSupported()) { return NULL; } SceneClass* sceneClass = new SceneClass(instanceName, "ChartableTwoFileDelegate", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); if (m_histogramCharting != NULL) { sceneClass->addClass(m_histogramCharting->saveToScene(sceneAttributes, "m_histogramCharting")); } if (m_lineSeriesCharting != NULL) { sceneClass->addClass(m_lineSeriesCharting->saveToScene(sceneAttributes, "m_lineSeriesCharting")); } if (m_matrixCharting != NULL) { sceneClass->addClass(m_matrixCharting->saveToScene(sceneAttributes, "m_matrixCharting")); } return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ChartableTwoFileDelegate::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); const SceneClass* histogramClass = sceneClass->getClass("m_histogramCharting"); if (histogramClass != NULL) { CaretAssert(m_histogramCharting); m_histogramCharting->restoreFromScene(sceneAttributes, histogramClass); } const SceneClass* lineSeriesClass = sceneClass->getClass("m_lineSeriesCharting"); if (lineSeriesClass != NULL) { CaretAssert(m_lineSeriesCharting); m_lineSeriesCharting->restoreFromScene(sceneAttributes, lineSeriesClass); } const SceneClass* matrixClass = sceneClass->getClass("m_matrixCharting"); if (matrixClass != NULL) { CaretAssert(m_matrixCharting); m_matrixCharting->restoreFromScene(sceneAttributes, matrixClass); } } connectome-workbench-1.4.2/src/Files/ChartableTwoFileDelegate.h000066400000000000000000000105351360521144700244530ustar00rootroot00000000000000#ifndef __CHARTABLE_TWO_FILE_DELEGATE_H__ #define __CHARTABLE_TWO_FILE_DELEGATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObjectTracksModification.h" #include "ChartTwoCompoundDataType.h" #include "ChartTwoDataTypeEnum.h" #include "SceneableInterface.h" namespace caret { class CaretMappableDataFile; class ChartableTwoFileHistogramChart; class ChartableTwoFileLineSeriesChart; class ChartableTwoFileMatrixChart; class ChartableTwoFileDelegate : public CaretObjectTracksModification, public SceneableInterface { public: ChartableTwoFileDelegate(CaretMappableDataFile* caretMappableDataFile); virtual ~ChartableTwoFileDelegate(); void updateAfterFileChanged(); // do not make this virtual since called from constructor void clear(); virtual void clearModified() override; virtual bool isModified() const override; CaretMappableDataFile* getCaretMappableDataFile(); const CaretMappableDataFile* getCaretMappableDataFile() const; ChartableTwoFileHistogramChart* getHistogramCharting(); const ChartableTwoFileHistogramChart* getHistogramCharting() const; ChartableTwoFileLineSeriesChart* getLineSeriesCharting(); const ChartableTwoFileLineSeriesChart* getLineSeriesCharting() const; ChartableTwoFileMatrixChart* getMatrixCharting(); const ChartableTwoFileMatrixChart* getMatrixCharting() const; bool isChartingTwoSupported() const; bool isChartingSupportedForChartTwoDataType(const ChartTwoDataTypeEnum::Enum chartDataType) const; bool isChartingSupportedForChartTwoCompoundDataType(const ChartTwoCompoundDataType& chartCompoundDataType) const; void getSupportedChartTwoDataTypes(std::vector& chartDataTypesOut) const; void getSupportedChartTwoCompoundDataTypes(std::vector& chartCompoundDataTypesOut) const; bool getChartTwoCompoundDataTypeForChartTwoDataType(const ChartTwoDataTypeEnum::Enum chartDataType, ChartTwoCompoundDataType& chartCompoundDataTypeOut) const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) override; virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) override; // ADD_NEW_METHODS_HERE private: ChartableTwoFileDelegate(const ChartableTwoFileDelegate&); ChartableTwoFileDelegate& operator=(const ChartableTwoFileDelegate&); std::unique_ptr m_sceneAssistant; /** points to parent caret mappable data file */ CaretMappableDataFile* m_caretMappableDataFile = NULL; std::unique_ptr m_histogramCharting; std::unique_ptr m_lineSeriesCharting; std::unique_ptr m_matrixCharting; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHARTABLE_TWO_FILE_DELEGATE_DECLARE__ // #endif // __CHARTABLE_TWO_FILE_DELEGATE_DECLARE__ } // namespace #endif //__CHARTABLE_TWO_FILE_DELEGATE_H__ connectome-workbench-1.4.2/src/Files/ChartableTwoFileHistogramChart.cxx000066400000000000000000000627711360521144700262440ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHARTABLE_TWO_FILE_HISTOGRAM_CHART_DECLARE__ #include "ChartableTwoFileHistogramChart.h" #undef __CHARTABLE_TWO_FILE_HISTOGRAM_CHART_DECLARE__ #include "CaretAssert.h" #include "CaretMappableDataFile.h" #include "CaretLogger.h" #include "CaretPreferences.h" #include "EventCaretPreferencesGet.h" #include "EventManager.h" #include "FastStatistics.h" #include "Histogram.h" #include "NodeAndVoxelColoring.h" #include "PaletteColorMapping.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ChartableTwoFileHistogramChart * \brief Implementation of base chart delegate for histogram charts. * \ingroup Files */ /** * Constructor. * * @param histogramContentType * Content of histogram. * @param parentCaretMappableDataFile * Parent caret mappable data file that this delegate supports. */ ChartableTwoFileHistogramChart::ChartableTwoFileHistogramChart(const ChartTwoHistogramContentTypeEnum::Enum histogramContentType, CaretMappableDataFile* parentCaretMappableDataFile) : ChartableTwoFileBaseChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM, parentCaretMappableDataFile), m_histogramContentType(histogramContentType) { m_sceneAssistant = new SceneClassAssistant(); int32_t histogramNumberOfBuckets = 0; switch (m_histogramContentType) { case ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_UNSUPPORTED: break; case ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_MAP_DATA: { CaretMappableDataFile* cmdf = getCaretMappableDataFile(); if (cmdf->getNumberOfMaps() > 0) { const Histogram* histogram = cmdf->getMapHistogram(0); if (histogram != NULL) { histogramNumberOfBuckets = histogram->getNumberOfBuckets(); } } } break; } updateChartTwoCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForHistogram(histogramNumberOfBuckets)); } /** * Destructor. */ ChartableTwoFileHistogramChart::~ChartableTwoFileHistogramChart() { delete m_sceneAssistant; } /** * @return Content type of histogram. */ ChartTwoHistogramContentTypeEnum::Enum ChartableTwoFileHistogramChart::getHistogramContentType() const { return m_histogramContentType; } /** * @return Is this charting valid ? */ bool ChartableTwoFileHistogramChart::isValid() const { return (m_histogramContentType != ChartTwoHistogramContentTypeEnum::HISTOGRAM_CONTENT_TYPE_UNSUPPORTED); } /** * @retrurn Is this charting empty (no data at this time) */ bool ChartableTwoFileHistogramChart::isEmpty() const { if ( ! isValid()) { return true; } return m_mapHistogramPrimitives.empty(); } /** * Invalidate coloring for all histograms. */ void ChartableTwoFileHistogramChart::invalidateAllColoring() { m_mapHistogramPrimitives.clear(); } /** * Get the histogram for drawing histogram as a chart * * @param mapIndex * Index of the map. * @param useDataFromAllMapsFlag * If true, include data from all maps for histogram chart. * @return * Histogram for histogram chart drawing. May be NULL if map is not * mapped with a color palette or the map index is invalid. */ const Histogram* ChartableTwoFileHistogramChart::getHistogramForChartDrawing(const int32_t mapIndex, const bool useDataFromAllMapsFlag) { CaretMappableDataFile* myMapFile = getCaretMappableDataFile(); CaretAssert(myMapFile); const Histogram* histogramOut= NULL; if ( ! myMapFile->isMappedWithPalette()) { return histogramOut; } if ((mapIndex < 0) || (mapIndex >= myMapFile->getNumberOfMaps())) { return histogramOut; } PaletteColorMapping* paletteColorMapping = myMapFile->getMapPaletteColorMapping(mapIndex); CaretAssert(paletteColorMapping); FastStatistics* statistics = NULL; if (useDataFromAllMapsFlag) { statistics = const_cast(myMapFile->getFileFastStatistics()); } else { switch (myMapFile->getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: statistics = const_cast(myMapFile->getFileFastStatistics()); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: statistics = const_cast(myMapFile->getMapFastStatistics(mapIndex)); break; } } /* * Statistics may be NULL for connectivity files (dense, dense dynamic) * that have not yet loaded any data caused by the user clicking * brainordinates. */ if (statistics == NULL) { return histogramOut; } CaretAssert(statistics); float mostPos = 0.0; float leastPos = 0.0; float leastNeg = 0.0; float mostNeg = 0.0; bool matchFlag = false; switch (paletteColorMapping->getHistogramRangeMode()) { case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL: { float dummy; statistics->getNonzeroRanges(mostNeg, dummy, dummy, mostPos); } break; case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE: { matchFlag = true; switch (paletteColorMapping->getScaleMode()) { case PaletteScaleModeEnum::MODE_AUTO_SCALE: mostPos = statistics->getMax(); leastPos = 0.0; leastNeg = 0.0; mostNeg = statistics->getMin(); break; case PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE: mostPos = statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMaximum()); leastPos = statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMinimum()); leastNeg = -statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMinimum()); mostNeg = -statistics->getApproxAbsolutePercentile(paletteColorMapping->getAutoScaleAbsolutePercentageMaximum()); break; case PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE: mostPos = statistics->getApproxPositivePercentile(paletteColorMapping->getAutoScalePercentagePositiveMaximum()); leastPos = statistics->getApproxPositivePercentile(paletteColorMapping->getAutoScalePercentagePositiveMinimum()); leastNeg = statistics->getApproxNegativePercentile(paletteColorMapping->getAutoScalePercentageNegativeMinimum()); mostNeg = statistics->getApproxNegativePercentile(paletteColorMapping->getAutoScalePercentageNegativeMaximum()); break; case PaletteScaleModeEnum::MODE_USER_SCALE: mostPos = paletteColorMapping->getUserScalePositiveMaximum(); leastPos = paletteColorMapping->getUserScalePositiveMinimum(); leastNeg = paletteColorMapping->getUserScaleNegativeMinimum(); mostNeg = paletteColorMapping->getUserScaleNegativeMaximum(); break; } } break; } /* * Remove data that is not displayed */ bool isZeroIncluded = true; if (matchFlag) { isZeroIncluded = paletteColorMapping->isDisplayZeroDataFlag(); if ( ! paletteColorMapping->isDisplayNegativeDataFlag()) { mostNeg = 0.0; leastNeg = 0.0; } if ( ! paletteColorMapping->isDisplayPositiveDataFlag()) { mostPos = 0.0; leastPos = 0.0; } if (useDataFromAllMapsFlag) { histogramOut = myMapFile->getFileHistogram(mostPos, leastPos, leastNeg, mostNeg, isZeroIncluded); } else { histogramOut = myMapFile->getMapHistogram(mapIndex, mostPos, leastPos, leastNeg, mostNeg, isZeroIncluded); } } else { if (useDataFromAllMapsFlag) { histogramOut = myMapFile->getFileHistogram(); } else { histogramOut = myMapFile->getMapHistogram(mapIndex); } } return histogramOut; } /** * Get the graphics primitive for drawing bars for the given map index. * * @param mapIndex * Index of the map. * @return * Primitives for drawing the histogram, bars, and envelope. May be NULL if map is not * mapped with a color palette or the map index is invalid. */ ChartableTwoFileHistogramChart::HistogramPrimitives* ChartableTwoFileHistogramChart::getMapHistogramDrawingPrimitives(const int32_t mapIndex, const bool useDataFromAllMapsFlag) { MapIndexPrimitiveContainer::iterator iter = m_mapHistogramPrimitives.find(mapIndex); if (iter != m_mapHistogramPrimitives.end()) { HistogramPrimitives* histogramPrimitives = iter->second.get(); if (histogramPrimitives != NULL) { return histogramPrimitives; } } CaretMappableDataFile* myMapFile = getCaretMappableDataFile(); CaretAssert(myMapFile); const Histogram* histogram = getHistogramForChartDrawing(mapIndex, useDataFromAllMapsFlag); if (histogram == NULL) { return NULL; } CaretAssert(histogram); FastStatistics* statistics = NULL; if (useDataFromAllMapsFlag) { statistics = const_cast(myMapFile->getFileFastStatistics()); } else { switch (myMapFile->getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: statistics = const_cast(myMapFile->getFileFastStatistics()); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: statistics = const_cast(myMapFile->getMapFastStatistics(mapIndex)); break; } } PaletteColorMapping* paletteColorMapping = myMapFile->getMapPaletteColorMapping(mapIndex); CaretAssert(paletteColorMapping); float minValueX = 0.0; float maxValueX = 0.0; histogram->getRange(minValueX, maxValueX); const float valueRangeX = maxValueX - minValueX; if (valueRangeX <= 0.0) { CaretLogSevere("Range of histogram X-values is zero"); return NULL; } if ((paletteColorMapping != NULL) && (statistics != NULL) && (histogram != NULL)) { std::vector histogramBuckets = histogram->getHistogramDisplay(); const int32_t numBucketValues = static_cast(histogramBuckets.size()); if (numBucketValues < 2) { CaretLogSevere("Histogram must contain two or more values"); return NULL; } const float bucketWidth = valueRangeX / (numBucketValues - 1); std::vector xValuesAtBuckets; xValuesAtBuckets.reserve(numBucketValues); for (int32_t i = 0; i < numBucketValues; i++) { xValuesAtBuckets.push_back(minValueX + (bucketWidth * i)); } CaretAssert(xValuesAtBuckets.size() == histogramBuckets.size()); std::vector histogramRGBA; histogramRGBA.resize(numBucketValues * 4, 0.0f); NodeAndVoxelColoring::colorScalarsWithPalette(statistics, paletteColorMapping, &xValuesAtBuckets[0], paletteColorMapping, &xValuesAtBuckets[0], numBucketValues, &histogramRGBA[0], true); // ignore thresholding const int32_t estimatedNumberOfVerticesForQuads = (numBucketValues * 4); // four vertices per quad const int32_t estimatedNumberOfVerticesForEnvelope = (numBucketValues * 2) + 4; // 2 vertices per line segment plus start/end /* * Use Quads when drawing bars (four vertices quad). * Use Lines when drawing envelope (two vertices per line) * Using quads and lines simplifies identification of individual bars in the histogram */ GraphicsPrimitiveV3fC4f* barsPrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES); barsPrimitive->reserveForNumberOfVertices(estimatedNumberOfVerticesForQuads); GraphicsPrimitiveV3fC4f* envelopePrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN); envelopePrimitive->reserveForNumberOfVertices(estimatedNumberOfVerticesForEnvelope); GraphicsPrimitiveV3fC4f* thresholdPrimitive = NULL; bool setThresholdingFlag = false; switch (paletteColorMapping->getThresholdType()) { case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED: break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED_AVERAGE_AREA: break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_NORMAL: setThresholdingFlag = true; break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_FILE: break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF: break; } if (setThresholdingFlag) { /* * RGBA for thresholding */ EventCaretPreferencesGet preferencesEvent; EventManager::get()->sendEvent(preferencesEvent.getPointer()); CaretPreferences* caretPreferences = preferencesEvent.getCaretPreferences(); float threshRGBA[4] = { 1.0, 0.0, 0.0, 1.0 }; if (caretPreferences != NULL) { uint8_t threshByteRGBA[4]; caretPreferences->getBackgroundAndForegroundColors()->getColorChartHistogramThreshold(threshByteRGBA); threshRGBA[0] = static_cast(threshByteRGBA[0]) / 255.0f; threshRGBA[1] = static_cast(threshByteRGBA[1]) / 255.0f; threshRGBA[2] = static_cast(threshByteRGBA[2]) / 255.0f; threshRGBA[3] = 1.0; } const float minX = -1000000.0f; const float maxX = 1000000.0f; const float minY = 0.0; const float maxY = *std::max_element(histogramBuckets.begin(), histogramBuckets.end()); float threshMinValue = paletteColorMapping->getThresholdNormalMinimum(); float threshMaxValue = paletteColorMapping->getThresholdNormalMaximum(); thresholdPrimitive = new GraphicsPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES); switch (paletteColorMapping->getThresholdTest()) { case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE: { thresholdPrimitive->reserveForNumberOfVertices(12); thresholdPrimitive->addVertex(minX, maxY, threshRGBA); thresholdPrimitive->addVertex(minX, minY, threshRGBA); thresholdPrimitive->addVertex(threshMinValue, minY, threshRGBA); thresholdPrimitive->addVertex(minX, maxY, threshRGBA); thresholdPrimitive->addVertex(threshMinValue, minY, threshRGBA); thresholdPrimitive->addVertex(threshMinValue, maxY, threshRGBA); thresholdPrimitive->addVertex(threshMaxValue, maxY, threshRGBA); thresholdPrimitive->addVertex(threshMaxValue, minY, threshRGBA); thresholdPrimitive->addVertex(maxX, minY, threshRGBA); thresholdPrimitive->addVertex(threshMaxValue, maxY, threshRGBA); thresholdPrimitive->addVertex(maxX, minY, threshRGBA); thresholdPrimitive->addVertex(maxX, maxY, threshRGBA); } break; case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE: { thresholdPrimitive->reserveForNumberOfVertices(6); thresholdPrimitive->addVertex(threshMinValue, maxY, threshRGBA); thresholdPrimitive->addVertex(threshMinValue, minY, threshRGBA); thresholdPrimitive->addVertex(threshMaxValue, minY, threshRGBA); thresholdPrimitive->addVertex(threshMinValue, maxY, threshRGBA); thresholdPrimitive->addVertex(threshMaxValue, minY, threshRGBA); thresholdPrimitive->addVertex(threshMaxValue, maxY, threshRGBA); } break; } } /* * If selected, apply solid color to envelope histogram */ const CaretColorEnum::Enum histogramEnvelopeColor = paletteColorMapping->getHistogramEnvelopeColor(); float envelopeSolidColorRGBA[4] = { 0.0, 0.0, 0.0, 0.0 }; bool envelopeSolidColorFlag = false; if (histogramEnvelopeColor != CaretColorEnum::CUSTOM) { CaretColorEnum::toRGBAFloat(histogramEnvelopeColor, envelopeSolidColorRGBA); envelopeSolidColorFlag = true; } /* * If selected, apply solid color to bars histogram */ const CaretColorEnum::Enum histogramBarsColor = paletteColorMapping->getHistogramBarsColor(); float barsSolidColorRGBA[4] = { 0.0, 0.0, 0.0, 0.0 }; bool barsSolidColorFlag = false; if (histogramBarsColor != CaretColorEnum::CUSTOM) { CaretColorEnum::toRGBAFloat(histogramBarsColor, barsSolidColorRGBA); barsSolidColorFlag = true; } /* * Move start one-half of bucket width so that bar's * X-value is centered within the bar */ const float halfBucketWidth = bucketWidth / 2.0f; const float startX = minValueX - halfBucketWidth; float x = startX; for (int32_t i = 0; i < numBucketValues; i++) { CaretAssertVectorIndex(histogramBuckets, i); const float xMin = x; const float xMax = x + bucketWidth; const float yMin = 0.0f; float yMax = histogramBuckets[i]; CaretAssertVectorIndex(histogramRGBA, i*4+3); const float* rgba = &histogramRGBA[i * 4]; const float alpha = rgba[3]; /* * Use a height of zero when there is no coloring * (apha == 0) for a bar since the bars will be * smoothed to create the envelope. */ if (alpha <= 0.0) { yMax = 0.0; } if (barsSolidColorFlag) { barsSolidColorRGBA[3] = rgba[3]; } const float* cellRGBA = (barsSolidColorFlag ? barsSolidColorRGBA : rgba); /* Triangle One for Cell*/ barsPrimitive->addVertex(xMin, yMax, cellRGBA); barsPrimitive->addVertex(xMin, yMin, cellRGBA); barsPrimitive->addVertex(xMax, yMin, cellRGBA); /* Triangle Two for Cell */ barsPrimitive->addVertex(xMin, yMax, cellRGBA); barsPrimitive->addVertex(xMax, yMin, cellRGBA); barsPrimitive->addVertex(xMax, yMax, cellRGBA); if (envelopeSolidColorFlag) { const float envelopeX = x + halfBucketWidth; if (i == 0) { envelopePrimitive->addVertex(envelopeX, yMin, envelopeSolidColorRGBA); } envelopePrimitive->addVertex(envelopeX, yMax, envelopeSolidColorRGBA); if (i == (numBucketValues - 1)) { envelopePrimitive->addVertex(envelopeX, yMin, envelopeSolidColorRGBA); } } else { const float envelopeX = x + halfBucketWidth; if (i == 0) { envelopePrimitive->addVertex(envelopeX, yMin, rgba); } envelopePrimitive->addVertex(envelopeX, yMax, rgba); if (i == (numBucketValues - 1)) { envelopePrimitive->addVertex(envelopeX, yMin, rgba); } } x += bucketWidth; } HistogramPrimitives* histogramPrimitives = new HistogramPrimitives(thresholdPrimitive, barsPrimitive, envelopePrimitive, paletteColorMapping->getHistogramEnvelopeLineWidthPercentage()); m_mapHistogramPrimitives.insert(std::make_pair(mapIndex, std::unique_ptr(histogramPrimitives))); return histogramPrimitives; } return NULL; } /** * Save subclass data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void ChartableTwoFileHistogramChart::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void ChartableTwoFileHistogramChart::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } /** * Default constructor. */ ChartableTwoFileHistogramChart::HistogramPrimitives::HistogramPrimitives() { } /** * Constructor for primitives * * @param thresholdPrimitive * Graphics Primitive for drawing threshold ranges. * @param barsPrimitive * Graphics Primitive for drawing histogram bars. * @param envelopePrimitive * Graphics Primitive for drawing histogram envelope. * @param envelopeLineWidthPercentage * Line width percentage for drawing envelope. */ ChartableTwoFileHistogramChart::HistogramPrimitives::HistogramPrimitives(GraphicsPrimitiveV3fC4f* thresholdPrimitive, GraphicsPrimitiveV3fC4f* barsPrimitive, GraphicsPrimitiveV3fC4f* envelopePrimitive, const float envelopeLineWidthPercentage) { m_thresholdPrimitive.reset(thresholdPrimitive); m_barsPrimitive.reset(barsPrimitive); m_envelopePrimitive.reset(envelopePrimitive); m_envelopeLineWidthPercentage = envelopeLineWidthPercentage; } /* * Destructor. */ ChartableTwoFileHistogramChart::HistogramPrimitives::~HistogramPrimitives() { } connectome-workbench-1.4.2/src/Files/ChartableTwoFileHistogramChart.h000066400000000000000000000121101360521144700256470ustar00rootroot00000000000000#ifndef __CHARTABLE_TWO_FILE_HISTOGRAM_CHART_H__ #define __CHARTABLE_TWO_FILE_HISTOGRAM_CHART_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "ChartableTwoFileBaseChart.h" #include "ChartTwoHistogramContentTypeEnum.h" #include "GraphicsPrimitiveV3fC4f.h" // forward declaration has problems namespace caret { class Histogram; class ChartableTwoFileHistogramChart : public ChartableTwoFileBaseChart { public: /** * Contains the graphics primitives for drawing * the histogram threshold, bars, and envelope. */ class HistogramPrimitives { public: HistogramPrimitives(); HistogramPrimitives(GraphicsPrimitiveV3fC4f* thresholdPrimitive, GraphicsPrimitiveV3fC4f* barsPrimitive, GraphicsPrimitiveV3fC4f* envelopePrimitive, const float envelopeLineWidthPercentage); ~HistogramPrimitives(); /* * @return Graphics primitive for drawing threshlold. * NULL if invalid. */ GraphicsPrimitiveV3fC4f* getThresholdPrimitive() { return m_thresholdPrimitive.get(); } /* * @return Graphics primitive for drawing histogram bars. * NULL if invalid. */ GraphicsPrimitiveV3fC4f* getBarsPrimitive() { return m_barsPrimitive.get(); } /* * @return Graphics primitive for drawing histogram envelope. * NULL if invalid. */ GraphicsPrimitiveV3fC4f* getEnvelopePrimitive() { return m_envelopePrimitive.get(); } /** * @return Line width percentage for drawing envelope */ float getEnvelopeLineWidthPercentage() const { return m_envelopeLineWidthPercentage; } private: std::unique_ptr m_thresholdPrimitive; std::unique_ptr m_barsPrimitive; std::unique_ptr m_envelopePrimitive; float m_envelopeLineWidthPercentage = 1.0f; }; ChartableTwoFileHistogramChart(const ChartTwoHistogramContentTypeEnum::Enum histogramContentType, CaretMappableDataFile* parentCaretMappableDataFile); virtual ~ChartableTwoFileHistogramChart(); ChartTwoHistogramContentTypeEnum::Enum getHistogramContentType() const; virtual bool isValid() const override; virtual bool isEmpty() const override; const Histogram* getHistogramForChartDrawing(const int32_t mapIndex, const bool useDataFromAllMapsFlag); HistogramPrimitives* getMapHistogramDrawingPrimitives(const int32_t mapIndex, const bool useDataFromAllMapsFlag); void invalidateAllColoring(); // ADD_NEW_METHODS_HERE protected: virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) override; virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) override; private: ChartableTwoFileHistogramChart(const ChartableTwoFileHistogramChart&); ChartableTwoFileHistogramChart& operator=(const ChartableTwoFileHistogramChart&); SceneClassAssistant* m_sceneAssistant; const ChartTwoHistogramContentTypeEnum::Enum m_histogramContentType; typedef std::map> MapIndexPrimitiveContainer; MapIndexPrimitiveContainer m_mapHistogramPrimitives; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHARTABLE_TWO_FILE_HISTOGRAM_CHART_DECLARE__ // #endif // __CHARTABLE_TWO_FILE_HISTOGRAM_CHART_DECLARE__ } // namespace #endif //__CHARTABLE_TWO_FILE_HISTOGRAM_CHART_H__ connectome-workbench-1.4.2/src/Files/ChartableTwoFileLineSeriesChart.cxx000066400000000000000000000410311360521144700263330ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHARTABLE_TWO_FILE_LINE_SERIES_CHART_DECLARE__ #include "ChartableTwoFileLineSeriesChart.h" #undef __CHARTABLE_TWO_FILE_LINE_SERIES_CHART_DECLARE__ #include "CaretAssert.h" #include "ChartTwoDataCartesian.h" #include "ChartTwoLineSeriesHistory.h" #include "CiftiMappableDataFile.h" #include "CiftiScalarDataSeriesFile.h" #include "EventChartTwoLoadLineSeriesData.h" #include "EventManager.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ChartableTwoFileLineSeriesChart * \brief Implementation of base chart delegate for line series charts. * \ingroup Files */ /** * Constructor. * * @param lineSeriesContentType * Content type of the line series data. * @param parentCaretMappableDataFile * Parent caret mappable data file that this delegate supports. */ ChartableTwoFileLineSeriesChart::ChartableTwoFileLineSeriesChart(const ChartTwoLineSeriesContentTypeEnum::Enum lineSeriesContentType, CaretMappableDataFile* parentCaretMappableDataFile) : ChartableTwoFileBaseChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, parentCaretMappableDataFile), m_lineSeriesContentType(lineSeriesContentType) { m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); CaretUnitsTypeEnum::Enum xAxisUnits = CaretUnitsTypeEnum::NONE; int32_t xAxisNumberOfElements = 0; CaretMappableDataFile* cmdf = getCaretMappableDataFile(); CaretAssert(cmdf); switch (lineSeriesContentType) { case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED: break; case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA: if (cmdf->getNumberOfMaps() > 1) { const NiftiTimeUnitsEnum::Enum mapUnits = cmdf->getMapIntervalUnits(); xAxisUnits = CaretUnitsTypeEnum::NONE; switch (mapUnits) { case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: xAxisUnits = CaretUnitsTypeEnum::HERTZ; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: xAxisUnits = CaretUnitsTypeEnum::SECONDS; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: xAxisUnits = CaretUnitsTypeEnum::PARTS_PER_MILLION; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: xAxisUnits = CaretUnitsTypeEnum::SECONDS; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: xAxisUnits = CaretUnitsTypeEnum::SECONDS; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: break; } xAxisNumberOfElements = cmdf->getNumberOfMaps(); } break; case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_ROW_SCALAR_DATA: { const CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); CaretAssert(ciftiMapFile); std::vector dims; ciftiMapFile->getMapDimensions(dims); CaretAssertVectorIndex(dims, 1); const int32_t numCols = dims[0]; const int32_t numRows = dims[1]; if ((numRows > 0) && (numCols > 1)) { const NiftiTimeUnitsEnum::Enum mapUnits = ciftiMapFile->getMapIntervalUnits(); xAxisUnits = CaretUnitsTypeEnum::NONE; switch (mapUnits) { case NiftiTimeUnitsEnum::NIFTI_UNITS_HZ: xAxisUnits = CaretUnitsTypeEnum::HERTZ; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_MSEC: xAxisUnits = CaretUnitsTypeEnum::SECONDS; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_PPM: xAxisUnits = CaretUnitsTypeEnum::PARTS_PER_MILLION; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_SEC: xAxisUnits = CaretUnitsTypeEnum::SECONDS; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_USEC: xAxisUnits = CaretUnitsTypeEnum::SECONDS; break; case NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN: break; } xAxisNumberOfElements = numCols; } } break; } m_lineChartHistory = std::unique_ptr(new ChartTwoLineSeriesHistory(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN)); m_sceneAssistant->add("m_lineChartHistory", "ChartTwoLineSeriesHistory", m_lineChartHistory.get()); /* * Must have two or more elements */ if (xAxisNumberOfElements <= 1) { m_lineSeriesContentType = ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED; } updateChartTwoCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForLineSeries(xAxisUnits, xAxisNumberOfElements)); if (m_lineSeriesContentType != ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED) { EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA); } } /** * Destructor. */ ChartableTwoFileLineSeriesChart::~ChartableTwoFileLineSeriesChart() { EventManager::get()->removeEventFromListener(this, EventTypeEnum::EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA); } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void ChartableTwoFileLineSeriesChart::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_CHART_TWO_LOAD_LINE_SERIES_DATA) { const EventChartTwoLoadLineSeriesData* lineSeriesDataEvent = dynamic_cast(event); CaretAssert(lineSeriesDataEvent); if (m_lineSeriesContentType != ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED) { const std::vector tabIndicesForLoading = getTabIndicesForLoadingData(lineSeriesDataEvent->getValidTabIndices()); if ( ! tabIndicesForLoading.empty()) { loadLineCharts(lineSeriesDataEvent); } } event->setEventProcessed(); } else { ChartableTwoFileBaseChart::receiveEvent(event); } } /** * Load line-series charts. * * @param lineSeriesDataEvent * Event indicating data for loading. */ void ChartableTwoFileLineSeriesChart::loadLineCharts(const EventChartTwoLoadLineSeriesData* lineSeriesDataEvent) { const MapFileDataSelector mapFileDataSelector = lineSeriesDataEvent->getMapFileDataSelector(); int32_t scalarRowIndex = -1; bool loadDataFlag = false; switch (m_lineSeriesContentType) { case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED: return; break; case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_BRAINORDINATE_DATA: switch (mapFileDataSelector.getDataSelectionType()) { case MapFileDataSelector::DataSelectionType::INVALID: break; case MapFileDataSelector::DataSelectionType::COLUMN_DATA: break; case MapFileDataSelector::DataSelectionType::ROW_DATA: break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: loadDataFlag = true; break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTICES_AVERAGE: loadDataFlag = true; break; case MapFileDataSelector::DataSelectionType::VOLUME_XYZ: loadDataFlag = true; break; } break; case ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_ROW_SCALAR_DATA: switch (mapFileDataSelector.getDataSelectionType()) { case MapFileDataSelector::DataSelectionType::INVALID: break; case MapFileDataSelector::DataSelectionType::COLUMN_DATA: { CaretMappableDataFile* mapFile = NULL; AString mapFileName; int32_t columnIndex = -1; mapFileDataSelector.getColumnIndex(mapFile, mapFileName, columnIndex); if (mapFile == getCaretMappableDataFile()) { loadDataFlag = true; } } break; case MapFileDataSelector::DataSelectionType::ROW_DATA: { CaretMappableDataFile* mapFile = NULL; AString mapFileName; int32_t rowIndex = -1; mapFileDataSelector.getRowIndex(mapFile, mapFileName, rowIndex); if (mapFile == getCaretMappableDataFile()) { loadDataFlag = true; } scalarRowIndex = rowIndex; } break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTICES_AVERAGE: break; case MapFileDataSelector::DataSelectionType::VOLUME_XYZ: break; } break; } if (loadDataFlag) { std::vector data; getCaretMappableDataFile()->getDataForSelector(mapFileDataSelector, data); if ( ! data.empty()) { const CaretUnitsTypeEnum::Enum xUnits = getChartTwoCompoundDataType().getLineChartUnitsAxisX(); CaretAssert(getChartTwoCompoundDataType().getLineChartNumberOfElementsAxisX() == static_cast(data.size())); ChartTwoDataCartesian* cartesianData = new ChartTwoDataCartesian(ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES, xUnits, CaretUnitsTypeEnum::NONE, m_lineChartHistory->getDefaultGraphicsPrimitiveType()); cartesianData->setMapFileDataSelector(mapFileDataSelector); float x = 0.0f; float xStep = 0.0f; getCaretMappableDataFile()->getMapIntervalStartAndStep(x, xStep); /* * Note: Start at index one since line segments are used */ const int32_t numData = static_cast(data.size()); for (int32_t i = 1; i < numData; i++) { CaretAssertVectorIndex(data, i - 1); cartesianData->addPoint(x, data[i - 1]); x += xStep; // CaretAssertVectorIndex(data, i); // cartesianData->addPoint(x, data[i]); } m_lineChartHistory->addHistoryItem(cartesianData); if (scalarRowIndex >= 0) { CaretMappableDataFile* mapFile = getCaretMappableDataFile(); CaretAssert(mapFile); CiftiScalarDataSeriesFile* scalarFile = dynamic_cast(mapFile); if (scalarFile != NULL) { for (auto tabIndex : lineSeriesDataEvent->getValidTabIndices()) { scalarFile->setSelectedMapIndex(tabIndex, scalarRowIndex); } } } } } } /** * Load data for the given row or column. * * @param tabIndex * Index of tab. * @param rowOrColumnIndex * Index of row/column for loading. */ void ChartableTwoFileLineSeriesChart::loadDataForRowOrColumn(const int32_t tabIndex, const int32_t rowOrColumnIndex) { std::vector tabIndices; tabIndices.push_back(tabIndex); MapFileDataSelector mapFileSelector; mapFileSelector.setRowIndex(getCaretMappableDataFile(), "", rowOrColumnIndex); EventChartTwoLoadLineSeriesData lineSeriesDataEvent(tabIndices, mapFileSelector); loadLineCharts(&lineSeriesDataEvent); } /** * Find tab indices for which user has loading of data enabled in the given valid tab indices. * * @param validTabIndices * All tabs that are valid. * @return * Tab indices for which data should be loaded. */ std::vector ChartableTwoFileLineSeriesChart::getTabIndicesForLoadingData(const std::vector& validTabIndices) const { std::vector tabIndicesOut; if ( ! validTabIndices.empty()) { if (m_lineChartHistory->isLoadingEnabled()) { tabIndicesOut = validTabIndices; } } return tabIndicesOut; } /** * @return Content type of the line series data. */ ChartTwoLineSeriesContentTypeEnum::Enum ChartableTwoFileLineSeriesChart::getLineSeriesContentType() const { return m_lineSeriesContentType; } /** * @return History of line charts. */ ChartTwoLineSeriesHistory* ChartableTwoFileLineSeriesChart::getHistory() { return m_lineChartHistory.get(); } /** * @return History of line charts (const method) */ const ChartTwoLineSeriesHistory* ChartableTwoFileLineSeriesChart::getHistory() const { return m_lineChartHistory.get(); } /** * @return Is this charting valid ? */ bool ChartableTwoFileLineSeriesChart::isValid() const { return (m_lineSeriesContentType != ChartTwoLineSeriesContentTypeEnum::LINE_SERIES_CONTENT_UNSUPPORTED); } /** * @retrurn Is this charting empty (no data at this time) */ bool ChartableTwoFileLineSeriesChart::isEmpty() const { if ( ! isValid()) { return true; } return (m_lineChartHistory->getHistoryCount() <= 0); } /** * Save subclass data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void ChartableTwoFileLineSeriesChart::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void ChartableTwoFileLineSeriesChart::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } connectome-workbench-1.4.2/src/Files/ChartableTwoFileLineSeriesChart.h000066400000000000000000000065771360521144700260000ustar00rootroot00000000000000#ifndef __CHARTABLE_TWO_FILE_LINE_SERIES_CHART_H__ #define __CHARTABLE_TWO_FILE_LINE_SERIES_CHART_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "BrainConstants.h" #include "ChartableTwoFileBaseChart.h" #include "ChartTwoLineSeriesContentTypeEnum.h" namespace caret { class ChartTwoLineSeriesHistory; class EventChartTwoLoadLineSeriesData; class ChartableTwoFileLineSeriesChart : public ChartableTwoFileBaseChart { public: ChartableTwoFileLineSeriesChart(const ChartTwoLineSeriesContentTypeEnum::Enum lineSeriesContentType, CaretMappableDataFile* parentCaretMappableDataFile); virtual ~ChartableTwoFileLineSeriesChart(); ChartTwoLineSeriesContentTypeEnum::Enum getLineSeriesContentType() const; ChartTwoLineSeriesHistory* getHistory(); const ChartTwoLineSeriesHistory* getHistory() const; virtual bool isValid() const override; virtual bool isEmpty() const override; virtual void receiveEvent(Event* event) override; void loadDataForRowOrColumn(const int32_t tabIndex, const int32_t rowOrColumnIndex); // ADD_NEW_METHODS_HERE protected: virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) override; virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) override; private: void loadLineCharts(const EventChartTwoLoadLineSeriesData* lineSeriesDataEvent); ChartableTwoFileLineSeriesChart(const ChartableTwoFileLineSeriesChart&); ChartableTwoFileLineSeriesChart& operator=(const ChartableTwoFileLineSeriesChart&); std::vector getTabIndicesForLoadingData(const std::vector& validTabIndices) const; std::unique_ptr m_sceneAssistant; ChartTwoLineSeriesContentTypeEnum::Enum m_lineSeriesContentType; std::unique_ptr m_lineChartHistory; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHARTABLE_TWO_FILE_LINE_SERIES_CHART_DECLARE__ // #endif // __CHARTABLE_TWO_FILE_LINE_SERIES_CHART_DECLARE__ } // namespace #endif //__CHARTABLE_TWO_FILE_LINE_SERIES_CHART_H__ connectome-workbench-1.4.2/src/Files/ChartableTwoFileMatrixChart.cxx000066400000000000000000001026441360521144700255450ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHARTABLE_TWO_FILE_MATRIX_CHART_DECLARE__ #include "ChartableTwoFileMatrixChart.h" #undef __CHARTABLE_TWO_FILE_MATRIX_CHART_DECLARE__ #include "CaretAssert.h" #include "CiftiConnectivityMatrixParcelFile.h" #include "CiftiParcelLabelFile.h" #include "CiftiParcelReordering.h" #include "CiftiParcelScalarFile.h" #include "CiftiParcelSeriesFile.h" #include "CiftiXML.h" #include "CiftiScalarDataSeriesFile.h" #include "ConnectivityDataLoaded.h" #include "EventCaretMappableDataFileMapsViewedInOverlays.h" #include "EventManager.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ChartableTwoFileMatrixChart * \brief Implementation of base chart delegate for matrix charts. * \ingroup Files */ /** * Constructor. * * @param matrixContentType * Content type of the matrix. * @param parentCaretMappableDataFile * Parent caret mappable data file that this delegate supports. * @param validRowColumnSelectionDimensions * Valid row/column selection dimensions for loading and selection. */ ChartableTwoFileMatrixChart::ChartableTwoFileMatrixChart(const ChartTwoMatrixContentTypeEnum::Enum matrixContentType, CaretMappableDataFile* parentCaretMappableDataFile, std::vector& validRowColumnSelectionDimensions) : ChartableTwoFileBaseChart(ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX, parentCaretMappableDataFile), m_matrixContentType(matrixContentType), m_validRowColumnSelectionDimensions(validRowColumnSelectionDimensions) { m_sceneAssistant = new SceneClassAssistant(); m_numberOfRows = 0; m_numberOfColumns = 0; for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_parcelLabelFileSelectedColumn[i] = 0; m_parcelScalarFileSelectedColumn[i] = 0; m_parcelSeriesFileSelectedColumn[i] = 0; } m_sceneAssistant->addTabIndexedIntegerArray("m_parcelLabelFileSelectedColumn", m_parcelLabelFileSelectedColumn); m_sceneAssistant->addTabIndexedIntegerArray("m_parcelScalarFileSelectedColumn", m_parcelScalarFileSelectedColumn); m_sceneAssistant->addTabIndexedIntegerArray("m_parcelSeriesFileSelectedColumn", m_parcelSeriesFileSelectedColumn); if (m_matrixContentType != ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED) { CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); CaretAssert(ciftiMapFile); ciftiMapFile->helpMapFileGetMatrixDimensions(m_numberOfRows, m_numberOfColumns); switch (ciftiMapFile->getDataFileType()) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: m_matrixDataFileType = MatrixDataFileType::PARCEL; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: m_matrixDataFileType = MatrixDataFileType::PARCEL_LABEL; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: m_matrixDataFileType = MatrixDataFileType::PARCEL_SCALAR; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: m_matrixDataFileType = MatrixDataFileType::PARCEL_SERIES; break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: m_matrixDataFileType = MatrixDataFileType::SCALAR_DATA_SERIES; break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: break; case DataFileTypeEnum::METRIC: break; case DataFileTypeEnum::METRIC_DYNAMIC: break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: break; } bool hasColumnParcelsFlag = false; bool hasColumnMapNamesFlag = false; bool hasRowParcelsFlag = false; bool hasRowNumbersFlag = false; switch (m_matrixDataFileType) { case MatrixDataFileType::INVALID: CaretAssert(0); return; break; case MatrixDataFileType::PARCEL: m_parcelFile = dynamic_cast(ciftiMapFile); CaretAssert(m_parcelFile); m_hasRowSelectionFlag = true; hasRowParcelsFlag = true; m_hasColumnSelectionFlag = true; hasColumnParcelsFlag = true; break; case MatrixDataFileType::PARCEL_LABEL: m_parcelLabelFile = dynamic_cast(ciftiMapFile); CaretAssert(m_parcelLabelFile); m_hasColumnSelectionFlag = true; hasColumnMapNamesFlag = true; break; case MatrixDataFileType::PARCEL_SCALAR: m_parcelScalarFile = dynamic_cast(ciftiMapFile); CaretAssert(m_parcelScalarFile); m_hasColumnSelectionFlag = true; hasColumnMapNamesFlag = true; break; case MatrixDataFileType::PARCEL_SERIES: m_parcelSeriesFile = dynamic_cast(ciftiMapFile); CaretAssert(m_parcelSeriesFile); m_hasColumnSelectionFlag = true; hasColumnMapNamesFlag = true; break; case MatrixDataFileType::SCALAR_DATA_SERIES: m_scalarDataSeriesFile = dynamic_cast(ciftiMapFile); CaretAssert(m_scalarDataSeriesFile); m_hasRowSelectionFlag = true; break; } if (m_hasRowSelectionFlag) { if (hasRowParcelsFlag) { const CiftiParcelsMap* rowParcelsMap = ciftiMapFile->getCiftiParcelsMapForDirection(CiftiXML::ALONG_COLUMN); if (rowParcelsMap != NULL) { const int32_t numRowParcels = rowParcelsMap->getLength(); CaretAssert(numRowParcels == m_numberOfRows); for (int32_t i = 0; i < numRowParcels; i++) { m_rowNames.push_back(rowParcelsMap->getIndexName(i)); m_rowNumberAndNames.push_back("Row " + AString::number(i + ROW_COLUMN_INDEX_BASE_OFFSET) + ": " + rowParcelsMap->getIndexName(i)); } } else { const CiftiParcelsMap* columnParcelsMap = ciftiMapFile->getCiftiParcelsMapForDirection(CiftiXML::ALONG_ROW); if (columnParcelsMap != NULL) { CaretAssertMessage(0, ("Trying to use row parcels but parcels are in columns. There are " + AString::number(columnParcelsMap->getLength()) + " parcels in the column for the file " + getCaretMappableDataFile()->getFileNameNoPath())); } else { CaretAssertMessage(0, "Trying to use row parcels but there are none for the file " + getCaretMappableDataFile()->getFileNameNoPath()); } } } else if (hasRowNumbersFlag) { for (int32_t i = 0; i < m_numberOfRows; i++) { m_rowNames.push_back(AString::number(i)); m_rowNumberAndNames.push_back("Row " + AString::number(i + ROW_COLUMN_INDEX_BASE_OFFSET) + ": " + AString::number(i + 1)); } } } if (m_hasColumnSelectionFlag) { if (hasColumnParcelsFlag) { const CiftiParcelsMap* colParcelsMap = ciftiMapFile->getCiftiParcelsMapForDirection(CiftiXML::ALONG_ROW); if (colParcelsMap != NULL) { const int32_t numColParcels = colParcelsMap->getLength(); CaretAssert(numColParcels == m_numberOfColumns); for (int32_t i = 0; i < numColParcels; i++) { m_columnNames.push_back(colParcelsMap->getIndexName(i)); m_columnNumberAndNames.push_back("Column " + AString::number(i + ROW_COLUMN_INDEX_BASE_OFFSET) + ": " + colParcelsMap->getIndexName(i)); } } else { const CiftiParcelsMap* rowParcelsMap = ciftiMapFile->getCiftiParcelsMapForDirection(CiftiXML::ALONG_COLUMN); if (rowParcelsMap != NULL) { CaretAssertMessage(0, ("Trying to use column parcels but parcels are in rows. There are " + AString::number(rowParcelsMap->getLength()) + " parcels in the row for the file " + getCaretMappableDataFile()->getFileNameNoPath())); } else { CaretAssertMessage(0, "Trying to use column parcels but there are none for the file " + getCaretMappableDataFile()->getFileNameNoPath()); } } } else if (hasColumnMapNamesFlag) { const int32_t numMaps = ciftiMapFile->getNumberOfMaps(); CaretAssert(m_numberOfColumns == numMaps); for (int32_t i = 0; i < numMaps; i++) { m_columnNames.push_back(ciftiMapFile->getMapName(i)); m_columnNumberAndNames.push_back("Column " + AString::number(i + ROW_COLUMN_INDEX_BASE_OFFSET) + ": " + ciftiMapFile->getMapName(i)); } } // if (hasColumnMapSelectionFlag) { // m_columnNames.clear(); // for (int32_t i = 0; i < m_numberOfColumns; i++) { // m_columnNames.push_back(ciftiMapFile->getMapName(i)); // } // if (m_parcelScalarFile != NULL) { // for (int32_t i = 0; i < m_numberOfColumns; i++) { // m_columnNames.push_back(m_parcelScalarFile->getMapName(i)); // } // } // if (m_parcelSeriesFile != NULL) { // for (int32_t i = 0; i < m_numberOfColumns; i++) { // m_columnNames.push_back(m_parcelSeriesFile->getMapName(i)); // } // } // } } } m_matrixTriangularViewingModeSupportedFlag = false; if ((m_numberOfRows > 0) && (m_numberOfColumns > 0)) { const CiftiConnectivityMatrixParcelFile* matrixFile = dynamic_cast(parentCaretMappableDataFile); if (matrixFile != NULL) { m_matrixTriangularViewingModeSupportedFlag = matrixFile->hasSymetricRowColumnNames(); } } else { m_matrixContentType = ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED; } updateChartTwoCompoundDataTypeAfterFileChanges(ChartTwoCompoundDataType::newInstanceForMatrix(m_numberOfRows, m_numberOfColumns)); } /** * Destructor. */ ChartableTwoFileMatrixChart::~ChartableTwoFileMatrixChart() { delete m_sceneAssistant; } /** * @return Content type of the matrix. */ ChartTwoMatrixContentTypeEnum::Enum ChartableTwoFileMatrixChart::getMatrixContentType() const { return m_matrixContentType; } /** * @return Is this charting valid ? */ bool ChartableTwoFileMatrixChart::isValid() const { return (m_matrixContentType != ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED); } /** * @retrurn Is this charting empty (no data at this time) */ bool ChartableTwoFileMatrixChart::isEmpty() const { if ( ! isValid()) { return true; } int32_t numRows = 0; int32_t numCols = 0; getMatrixDimensions(numRows, numCols); if ((numRows > 0) || (numCols > 0)) { return false; } return true; } /** * @return Is matrix triangular viewing modes supported? */ bool ChartableTwoFileMatrixChart::isMatrixTriangularViewingModeSupported() const { return m_matrixTriangularViewingModeSupportedFlag; } /** * Get the matrix dimensions. * * @param numberOfRowsOut * Number of rows in the matrix. * @param numberOfColumnsOut * Number of rows in the matrix. */ void ChartableTwoFileMatrixChart::getMatrixDimensions(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) const { numberOfRowsOut = 0; numberOfColumnsOut = 0; if (m_matrixContentType == ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED) { return; } const CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); CaretAssert(ciftiMapFile); ciftiMapFile->helpMapFileGetMatrixDimensions(numberOfRowsOut, numberOfColumnsOut); } /** * Get the matrix RGBA coloring for this matrix data creator. * * @param numberOfRowsOut * Number of rows in the coloring matrix. * @param numberOfColumnsOut * Number of rows in the coloring matrix. * @param rgbaOut * RGBA coloring output with number of elements * (numberOfRowsOut * numberOfColumnsOut * 4). * @return * True if data output data is valid, else false. */ bool ChartableTwoFileMatrixChart::getMatrixDataRGBA(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut, std::vector& rgbaOut) const { const CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); CaretAssert(ciftiMapFile); return ciftiMapFile->getMatrixForChartingRGBA(numberOfRowsOut, numberOfColumnsOut, rgbaOut); } /** * @return The graphics primitive containing the matrix representation of the file. * All cells are of dimension 1.0 x 1.0 * * @param matrixViewMode * The matrix visualization mode (upper/lower). * @param gridMode * The grid mode (filled or outline) */ GraphicsPrimitiveV3fC4f* ChartableTwoFileMatrixChart::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode, const CiftiMappableDataFile::MatrixGridMode gridMode) const { const CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); CaretAssert(ciftiMapFile); return ciftiMapFile->getMatrixChartingGraphicsPrimitive(matrixViewMode, gridMode); } /** * @return Identifier for the matrix primitives alternative color used for the grid coloring */ int32_t ChartableTwoFileMatrixChart::getMatrixChartGraphicsPrimitiveGridColorIdentifier() const { const CiftiMappableDataFile* ciftiMapFile = getCiftiMappableDataFile(); CaretAssert(ciftiMapFile); return ciftiMapFile->getMatrixChartGraphicsPrimitiveGridColorIdentifier(); } /** * @return The selected row/column dimension. */ ChartTwoMatrixLoadingDimensionEnum::Enum ChartableTwoFileMatrixChart::getSelectedRowColumnDimension() const { ChartTwoMatrixLoadingDimensionEnum::Enum loadDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; switch (m_matrixDataFileType) { case MatrixDataFileType::INVALID: CaretAssert(0); break; case MatrixDataFileType::PARCEL: CaretAssert(m_parcelFile); switch (m_parcelFile->getMatrixLoadingDimension()) { case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: loadDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; break; case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: loadDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN; break; } break; case MatrixDataFileType::PARCEL_LABEL: CaretAssert(m_parcelLabelFile); loadDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN; break; case MatrixDataFileType::PARCEL_SCALAR: CaretAssert(m_parcelScalarFile); loadDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN; break; case MatrixDataFileType::PARCEL_SERIES: CaretAssert(m_parcelSeriesFile); loadDimension = ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN; break; case MatrixDataFileType::SCALAR_DATA_SERIES: CaretAssert(m_scalarDataSeriesFile); break; } return loadDimension; } /** * Set the selected row/column dimension. * * @param rowColumnDimension * New value for row/column dimension */ void ChartableTwoFileMatrixChart::setSelectedRowColumnDimension(const ChartTwoMatrixLoadingDimensionEnum::Enum rowColumnDimension) { switch (m_matrixDataFileType) { case MatrixDataFileType::INVALID: CaretAssert(0); break; case MatrixDataFileType::PARCEL: { CaretAssert(m_parcelFile); ChartMatrixLoadingDimensionEnum::Enum oldLoadDim = ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; switch (rowColumnDimension) { case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: oldLoadDim = ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; break; case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: oldLoadDim = ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN; break; } m_parcelFile->setMatrixLoadingDimension(oldLoadDim); } break; case MatrixDataFileType::PARCEL_LABEL: CaretAssert(m_parcelLabelFile); break; case MatrixDataFileType::PARCEL_SCALAR: CaretAssert(m_parcelScalarFile); break; case MatrixDataFileType::PARCEL_SERIES: CaretAssert(m_parcelSeriesFile); break; case MatrixDataFileType::SCALAR_DATA_SERIES: CaretAssert(m_scalarDataSeriesFile); break; } } /** * Get the valid row/column dimensions. * * @param validRowColumnSelectionDimensionsOut * Output with valid row/column dimensions for selection. */ void ChartableTwoFileMatrixChart::getValidRowColumnSelectionDimensions(std::vector& validRowColumnSelectionDimensionsOut) const { validRowColumnSelectionDimensionsOut = m_validRowColumnSelectionDimensions; } /** * @param tabIndex * Index of the tab. * @param selectedRowIndicesOut * Indices if indices are for rows or columns. * @param selectedRowIndicesOut * Output with row indices selected. * @param selectedColumnIndicesOut * Output with column indices selected. */ void ChartableTwoFileMatrixChart::getSelectedRowColumnIndices(const int32_t tabIndex, ChartTwoMatrixLoadingDimensionEnum::Enum& rowColumnDimensionOut, std::vector& selectedRowIndicesOut, std::vector& selectedColumnIndicesOut) const { rowColumnDimensionOut = getSelectedRowColumnDimension(); selectedRowIndicesOut.clear(); selectedColumnIndicesOut.clear(); std::set rowIndicesSet; std::set columnIndicesSet; switch (m_matrixDataFileType) { case MatrixDataFileType::INVALID: CaretAssert(0); break; case MatrixDataFileType::PARCEL: { CaretAssert(m_parcelFile); const ConnectivityDataLoaded* connDataLoaded = m_parcelFile->getConnectivityDataLoaded(); if (connDataLoaded != NULL) { int64_t loadedRowIndex = -1; int64_t loadedColumnIndex = -1; connDataLoaded->getRowColumnLoading(loadedRowIndex, loadedColumnIndex); switch (rowColumnDimensionOut) { case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: if (loadedColumnIndex >= 0) { columnIndicesSet.insert(loadedColumnIndex); } break; case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: if (loadedRowIndex >= 0) { rowIndicesSet.insert(loadedRowIndex); } break; } } } break; case MatrixDataFileType::PARCEL_LABEL: { CaretAssertArrayIndex(m_parcelLabelFileSelectedColumn, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); columnIndicesSet.insert(m_parcelLabelFileSelectedColumn[tabIndex]); // CaretAssert(m_parcelLabelFile); // EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(m_parcelLabelFile); // EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); // for (auto indx : mapOverlayEvent.getSelectedMapIndices()) { // columnIndicesSet.insert(indx); // } } break; case MatrixDataFileType::PARCEL_SCALAR: CaretAssertArrayIndex(m_parcelScalarFileSelectedColumn, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); columnIndicesSet.insert(m_parcelScalarFileSelectedColumn[tabIndex]); break; case MatrixDataFileType::PARCEL_SERIES: CaretAssertArrayIndex(m_parcelSeriesFileSelectedColumn, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); columnIndicesSet.insert(m_parcelSeriesFileSelectedColumn[tabIndex]); break; case MatrixDataFileType::SCALAR_DATA_SERIES: { CaretAssert(m_scalarDataSeriesFile); const int32_t scalarDataSeriesMapIndex = m_scalarDataSeriesFile->getSelectedMapIndex(tabIndex); if (scalarDataSeriesMapIndex >= 0) { rowIndicesSet.insert(scalarDataSeriesMapIndex); } } break; } selectedRowIndicesOut.insert(selectedRowIndicesOut.end(), rowIndicesSet.begin(), rowIndicesSet.end()); selectedColumnIndicesOut.insert(selectedColumnIndicesOut.end(), columnIndicesSet.begin(), columnIndicesSet.end()); } /** * Set the row or column index using the currently selected row/column dimension. * * @param tabIndex * Index of tab. * @param rowColumnIndex * New row/column index. */ void ChartableTwoFileMatrixChart::setSelectedRowColumnIndex(const int32_t tabIndex, const int32_t rowColumnIndex) { /* * Ignore an invalid row/column index. It may occur when the chart overlay * is changed. */ if (rowColumnIndex < 0) { return; } switch (m_matrixDataFileType) { case MatrixDataFileType::INVALID: CaretAssert(0); break; case MatrixDataFileType::PARCEL: { CaretAssert(m_parcelFile); int32_t numRows = -1; int32_t numCols = -1; getMatrixDimensions(numRows, numCols); switch (getSelectedRowColumnDimension()) { case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: if ((rowColumnIndex >= 0) && (rowColumnIndex < numCols)) { m_parcelFile->loadDataForColumnIndex(rowColumnIndex); m_parcelFile->invalidateColoringInAllMaps(); } break; case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: if ((rowColumnIndex >= 0) && (rowColumnIndex < numRows)) { m_parcelFile->loadDataForRowIndex(rowColumnIndex); m_parcelFile->invalidateColoringInAllMaps(); } break; } } break; case MatrixDataFileType::PARCEL_LABEL: { CaretAssert(m_parcelLabelFile); CaretAssertArrayIndex(m_parcelLabelFileSelectedColumn, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_parcelLabelFileSelectedColumn[tabIndex] = rowColumnIndex; // EventCaretMappableDataFileMapsViewedInOverlays mapOverlayEvent(m_parcelLabelFile); // EventManager::get()->sendEvent(mapOverlayEvent.getPointer()); // for (auto indx : mapOverlayEvent.getSelectedMapIndices()) { // columnIndicesSet.insert(indx); // } } break; case MatrixDataFileType::PARCEL_SCALAR: { CaretAssert(m_parcelScalarFile); CaretAssertArrayIndex(m_parcelScalarFileSelectedColumn, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_parcelScalarFileSelectedColumn[tabIndex] = rowColumnIndex; } break; case MatrixDataFileType::PARCEL_SERIES: CaretAssert(m_parcelSeriesFile); CaretAssertArrayIndex(m_parcelSeriesFileSelectedColumn, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_parcelSeriesFileSelectedColumn[tabIndex] = rowColumnIndex; break; case MatrixDataFileType::SCALAR_DATA_SERIES: CaretAssert(m_scalarDataSeriesFile); m_scalarDataSeriesFile->setSelectedMapIndex(tabIndex, rowColumnIndex); break; } } /** * Load a row or column if none are loaded. * */ void ChartableTwoFileMatrixChart::loadDefaultRowOrColumn() { if (getChartTwoDataType() != ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX) { return; } if (m_matrixDataFileType == MatrixDataFileType::INVALID) { return; } const int32_t tabIndex = BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS - 1; ChartTwoMatrixLoadingDimensionEnum::Enum rowColumnDimension = getSelectedRowColumnDimension(); std::vector selectedRowIndices; std::vector selectedColumnIndices; getSelectedRowColumnIndices(tabIndex, rowColumnDimension, selectedRowIndices, selectedColumnIndices); if (selectedRowIndices.empty() && selectedRowIndices.empty()) { setSelectedRowColumnIndex(tabIndex, 0); } } /** * @return True if the file supports row selection. */ bool ChartableTwoFileMatrixChart::hasRowSelection() const { return m_hasRowSelectionFlag; } /** * @return True if the file supports column selection. */ bool ChartableTwoFileMatrixChart::hasColumnSelection() const { return m_hasColumnSelectionFlag; } /** * @return Name of row at the given index. * * @param rowIndex * Index of the row. */ AString ChartableTwoFileMatrixChart::getRowName(const int32_t rowIndex) const { if ((rowIndex >= 0) && (rowIndex < m_numberOfRows)) { if (rowIndex < static_cast(m_rowNames.size())) { CaretAssertVectorIndex(m_rowNames, rowIndex); return m_rowNames[rowIndex]; } return ("Row: " + AString::number(rowIndex + ROW_COLUMN_INDEX_BASE_OFFSET)); } return ""; } /** * @return Name of column at the given index. * * @param columnIndex * Index of the row. */ AString ChartableTwoFileMatrixChart::getColumnName(const int32_t columnIndex) const { if ((columnIndex >= 0) && (columnIndex < m_numberOfColumns)) { if (columnIndex < static_cast(m_columnNames.size())) { CaretAssertVectorIndex(m_columnNames, columnIndex); return m_columnNames[columnIndex]; } return ("Column: " + AString::number(columnIndex + ROW_COLUMN_INDEX_BASE_OFFSET)); } return ""; } /** * @return Name of row at the given index. * * @param rowIndex * Index of the row. */ AString ChartableTwoFileMatrixChart::getRowNumberAndName(const int32_t rowIndex) const { if ((rowIndex >= 0) && (rowIndex < m_numberOfRows)) { if (rowIndex < static_cast(m_rowNumberAndNames.size())) { CaretAssertVectorIndex(m_rowNumberAndNames, rowIndex); return m_rowNumberAndNames[rowIndex]; } return ("Row: " + AString::number(rowIndex + ROW_COLUMN_INDEX_BASE_OFFSET)); } return ""; } /** * @return Name of column at the given index. * * @param columnIndex * Index of the row. */ AString ChartableTwoFileMatrixChart::getColumnNumberAndName(const int32_t columnIndex) const { if ((columnIndex >= 0) && (columnIndex < m_numberOfColumns)) { if (columnIndex < static_cast(m_columnNumberAndNames.size())) { CaretAssertVectorIndex(m_columnNumberAndNames, columnIndex); return m_columnNumberAndNames[columnIndex]; } return ("Column: " + AString::number(columnIndex + ROW_COLUMN_INDEX_BASE_OFFSET)); } return ""; } /** * Save subclass data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void ChartableTwoFileMatrixChart::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void ChartableTwoFileMatrixChart::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } connectome-workbench-1.4.2/src/Files/ChartableTwoFileMatrixChart.h000066400000000000000000000150651360521144700251720ustar00rootroot00000000000000#ifndef __CHARTABLE_TWO_FILE_MATRIX_CHART_H__ #define __CHARTABLE_TWO_FILE_MATRIX_CHART_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "ChartTwoMatrixContentTypeEnum.h" #include "ChartTwoMatrixLoadingDimensionEnum.h" #include "ChartTwoMatrixTriangularViewingModeEnum.h" #include "ChartableTwoFileBaseChart.h" #include "CiftiMappableDataFile.h" namespace caret { class CiftiConnectivityMatrixParcelFile; class CiftiParcelLabelFile; class CiftiParcelScalarFile; class CiftiParcelSeriesFile; class CiftiScalarDataSeriesFile; class GraphicsPrimitiveV3fC4f; class ChartableTwoFileMatrixChart : public ChartableTwoFileBaseChart { public: ChartableTwoFileMatrixChart(const ChartTwoMatrixContentTypeEnum::Enum matrixContentType, CaretMappableDataFile* parentCaretMappableDataFile, std::vector& validRowColumnSelectionDimensions); virtual ~ChartableTwoFileMatrixChart(); ChartTwoMatrixContentTypeEnum::Enum getMatrixContentType() const; virtual bool isValid() const override; virtual bool isEmpty() const override; void getMatrixDimensions(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) const; bool getMatrixDataRGBA(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut, std::vector& rgbaOut) const; GraphicsPrimitiveV3fC4f* getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode, const CiftiMappableDataFile::MatrixGridMode gridMode) const; int32_t getMatrixChartGraphicsPrimitiveGridColorIdentifier() const; bool isMatrixTriangularViewingModeSupported() const; // ADD_NEW_METHODS_HERE ChartTwoMatrixLoadingDimensionEnum::Enum getSelectedRowColumnDimension() const; void setSelectedRowColumnDimension(const ChartTwoMatrixLoadingDimensionEnum::Enum rowColumnDimension); void getValidRowColumnSelectionDimensions(std::vector& validRowColumnSelectionDimensionOut) const; void getSelectedRowColumnIndices(const int32_t tabIndex, ChartTwoMatrixLoadingDimensionEnum::Enum& rowColumnDimensionOut, std::vector& selectedRowIndicesOut, std::vector& selectedColumnIndicesOut) const; void setSelectedRowColumnIndex(const int32_t tabIndex, const int32_t rowColumnIndex); bool hasRowSelection() const; bool hasColumnSelection() const; void loadDefaultRowOrColumn(); AString getRowNumberAndName(const int32_t rowIndex) const; AString getColumnNumberAndName(const int32_t columnIndex) const; AString getRowName(const int32_t rowIndex) const; AString getColumnName(const int32_t columnIndex) const; protected: enum class MatrixDataFileType { INVALID, PARCEL, PARCEL_LABEL, PARCEL_SCALAR, PARCEL_SERIES, SCALAR_DATA_SERIES }; virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) override; virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) override; private: ChartableTwoFileMatrixChart(const ChartableTwoFileMatrixChart&); ChartableTwoFileMatrixChart& operator=(const ChartableTwoFileMatrixChart&); SceneClassAssistant* m_sceneAssistant; ChartTwoMatrixContentTypeEnum::Enum m_matrixContentType; const std::vector m_validRowColumnSelectionDimensions; bool m_matrixTriangularViewingModeSupportedFlag = false; int32_t m_numberOfRows = 0; int32_t m_numberOfColumns = 0; std::vector m_rowNames; std::vector m_columnNames; std::vector m_rowNumberAndNames; std::vector m_columnNumberAndNames; bool m_hasRowSelectionFlag = false; bool m_hasColumnSelectionFlag = false; MatrixDataFileType m_matrixDataFileType = MatrixDataFileType::INVALID; CiftiConnectivityMatrixParcelFile *m_parcelFile = NULL; CiftiParcelLabelFile* m_parcelLabelFile = NULL; CiftiParcelScalarFile* m_parcelScalarFile = NULL; CiftiParcelSeriesFile* m_parcelSeriesFile = NULL; CiftiScalarDataSeriesFile* m_scalarDataSeriesFile = NULL; int32_t m_parcelLabelFileSelectedColumn[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; int32_t m_parcelScalarFileSelectedColumn[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; int32_t m_parcelSeriesFileSelectedColumn[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; static const int32_t ROW_COLUMN_INDEX_BASE_OFFSET = 1; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHARTABLE_TWO_FILE_MATRIX_CHART_DECLARE__ // #endif // __CHARTABLE_TWO_FILE_MATRIX_CHART_DECLARE__ } // namespace #endif //__CHARTABLE_TWO_FILE_MATRIX_CHART_H__ connectome-workbench-1.4.2/src/Files/CiftiBrainordinateDataSeriesFile.cxx000066400000000000000000000372531360521144700265270ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CIFTI_BRAINORDINATE_DATA_SERIES_FILE_DECLARE__ #include "CiftiBrainordinateDataSeriesFile.h" #undef __CIFTI_BRAINORDINATE_DATA_SERIES_FILE_DECLARE__ #include #include "CaretLogger.h" #include "ChartDataCartesian.h" #include "CiftiConnectivityMatrixDenseDynamicFile.h" #include "CiftiFile.h" #include "DataFileException.h" #include "ElapsedTimer.h" #include "SceneClass.h" using namespace caret; /** * \class caret::CiftiBrainordinateDataSeriesFile * \brief CIFTI Brainordinate by Data-Series File. * \ingroup Files */ /** * Constructor. */ CiftiBrainordinateDataSeriesFile::CiftiBrainordinateDataSeriesFile() : CiftiMappableDataFile(DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES) { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = false; } m_lazyInitializedDenseDynamicFile = NULL; } /** * Destructor. */ CiftiBrainordinateDataSeriesFile::~CiftiBrainordinateDataSeriesFile() { if (m_lazyInitializedDenseDynamicFile != NULL) { delete m_lazyInitializedDenseDynamicFile; } } /** * Clear the contents of the file. */ void CiftiBrainordinateDataSeriesFile::clear() { CiftiMappableDataFile::clear(); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = false; } if (m_lazyInitializedDenseDynamicFile != NULL) { delete m_lazyInitializedDenseDynamicFile; m_lazyInitializedDenseDynamicFile = NULL; //m_lazyInitializedDenseDynamicFile->clear(); } } /** * Initialize the dense dynamic file. */ void CiftiBrainordinateDataSeriesFile::initializeDenseDynamicFile() { if (m_lazyInitializedDenseDynamicFile != NULL) { return; } m_lazyInitializedDenseDynamicFile = new CiftiConnectivityMatrixDenseDynamicFile(this); try { //ElapsedTimer timer; //timer.start(); m_lazyInitializedDenseDynamicFile->readFile(getFileName()); m_lazyInitializedDenseDynamicFile->updateAfterReading(getCiftiFile()); /* * Palette for dynamic file is in my CIFTI file metadata */ GiftiMetaData* fileMetaData = m_ciftiFile->getCiftiXML().getFileMetaData(); const AString encodedPaletteColorMappingString = fileMetaData->get(s_paletteColorMappingNameInMetaData); if ( ! encodedPaletteColorMappingString.isEmpty()) { if (m_lazyInitializedDenseDynamicFile->getNumberOfMaps() > 0) { PaletteColorMapping* pcm = m_lazyInitializedDenseDynamicFile->getMapPaletteColorMapping(0); CaretAssert(pcm); pcm->decodeFromStringXML(encodedPaletteColorMappingString); } } m_lazyInitializedDenseDynamicFile->clearModified(); // /* // * Remove palette color mapping from metadata so not seen by user // */ // fileMetaData->remove(s_paletteColorMappingNameInMetaData); // clearModified(); /*AString msg = ("Time to setup dense dynamic file " + m_lazyInitializedDenseDynamicFile->getFileNameNoPath() + " was " + AString::number(timer.getElapsedTimeSeconds()) + " seconds."); CaretLogInfo(msg);//*/ } catch (const DataFileException& dfe) { m_lazyInitializedDenseDynamicFile->clear(); CaretLogSevere("ERROR initializing dense dynamic file for " + getFileName() + ": " + dfe.whatString()); } // std::cout << "Initializing dense dynamic file" << std::endl; } /** * Read the file. * * @param ciftiMapFileName * Name of the file to read. * @throw * DataFileException if there is an error reading the file. */ void CiftiBrainordinateDataSeriesFile::readFile(const AString& ciftiMapFileName) { CiftiMappableDataFile::readFile(ciftiMapFileName); } /** * Write the file. * * @param ciftiMapFileName * Name of the file to write. * @throw * DataFileException if there is an error writing the file. */ void CiftiBrainordinateDataSeriesFile::writeFile(const AString& ciftiMapFileName) { /* * Put the child dynamic data-series file's palette in the file's metadata. */ if (m_lazyInitializedDenseDynamicFile != NULL) { GiftiMetaData* fileMetaData = m_ciftiFile->getCiftiXML().getFileMetaData(); CaretAssert(fileMetaData); if (m_lazyInitializedDenseDynamicFile->getNumberOfMaps() > 0) { fileMetaData->set(s_paletteColorMappingNameInMetaData, m_lazyInitializedDenseDynamicFile->getMapPaletteColorMapping(0)->encodeInXML()); } else { fileMetaData->remove(s_paletteColorMappingNameInMetaData); } } CiftiMappableDataFile::writeFile(ciftiMapFileName); clearModified(); if (m_lazyInitializedDenseDynamicFile != NULL) { m_lazyInitializedDenseDynamicFile->clearModified(); } } /** * @return Is charting enabled for this file? */ bool CiftiBrainordinateDataSeriesFile::isLineSeriesChartingEnabled(const int32_t tabIndex) const { CaretAssertArrayIndex(m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_chartingEnabledForTab[tabIndex]; } /** * @return Return true if the file's current state supports * charting data, else false. Typically a brainordinate file * is chartable if it contains more than one map. */ bool CiftiBrainordinateDataSeriesFile::isLineSeriesChartingSupported() const { if (getNumberOfMaps() > 1) { return true; } return false; } /** * Set charting enabled for this file. * * @param enabled * New status for charting enabled. */ void CiftiBrainordinateDataSeriesFile::setLineSeriesChartingEnabled(const int32_t tabIndex, const bool enabled) { CaretAssertArrayIndex(m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_chartingEnabledForTab[tabIndex] = enabled; } /** * Load charting data for the surface with the given structure and node index. * * @param structure * The surface's structure. * @param nodeIndex * Index of the node. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will return true. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* CiftiBrainordinateDataSeriesFile::loadLineSeriesChartDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t nodeIndex) { ChartDataCartesian* chartData = helpLoadChartDataForSurfaceNode(structure, nodeIndex); return chartData; } /** * Load average charting data for the surface with the given structure and node indices. * * @param structure * The surface's structure. * @param nodeIndices * Indices of the node. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* CiftiBrainordinateDataSeriesFile::loadAverageLineSeriesChartDataForSurfaceNodes(const StructureEnum::Enum structure, const std::vector& nodeIndices) { ChartDataCartesian* chartData = helpLoadChartDataForSurfaceNodeAverage(structure, nodeIndices); return chartData; } /** * Load charting data for the voxel enclosing the given coordinate. * * @param xyz * Coordinate of voxel. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* CiftiBrainordinateDataSeriesFile::loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]) { ChartDataCartesian* chartData = helpLoadChartDataForVoxelAtCoordinate(xyz); return chartData; } /** * Get chart data types supported by the file. * * @param chartDataTypesOut * Chart types supported by this file. */ void CiftiBrainordinateDataSeriesFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { helpGetSupportedLineSeriesChartDataTypes(chartDataTypesOut); } /** * Save file data from the scene. For subclasses that need to * save to a scene, this method should be overriden. sceneClass * will be valid and any scene data should be added to it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. */ void CiftiBrainordinateDataSeriesFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { CiftiMappableDataFile::saveFileDataToScene(sceneAttributes, sceneClass); sceneClass->addBooleanArray("m_chartingEnabledForTab", m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); if (m_lazyInitializedDenseDynamicFile != NULL) { sceneClass->addClass(m_lazyInitializedDenseDynamicFile->saveToScene(sceneAttributes, "m_lazyInitializedDenseDynamicFile")); } } /** * Restore file data from the scene. For subclasses that need to * restore from a scene, this method should be overridden. The scene class * will be valid and any scene data may be obtained from it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void CiftiBrainordinateDataSeriesFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { CiftiMappableDataFile::restoreFileDataFromScene(sceneAttributes, sceneClass); const ScenePrimitiveArray* tabArray = sceneClass->getPrimitiveArray("m_chartingEnabledForTab"); if (tabArray != NULL) { sceneClass->getBooleanArrayValue("m_chartingEnabledForTab", m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); } else { /* * Obsolete value when charting was not 'per tab' */ const bool chartingEnabled = sceneClass->getBooleanValue("m_chartingEnabled", false); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = chartingEnabled; } } const SceneClass* dynamicFileSceneClass = sceneClass->getClass("m_lazyInitializedDenseDynamicFile"); if (dynamicFileSceneClass != NULL) { CiftiConnectivityMatrixDenseDynamicFile* denseDynamicFile = getConnectivityMatrixDenseDynamicFile(); denseDynamicFile->restoreFromScene(sceneAttributes, dynamicFileSceneClass); } } /** * @return My matrix dense dynamic file representation. */ CiftiConnectivityMatrixDenseDynamicFile* CiftiBrainordinateDataSeriesFile::getConnectivityMatrixDenseDynamicFile() { if (m_lazyInitializedDenseDynamicFile == NULL) { initializeDenseDynamicFile(); } return m_lazyInitializedDenseDynamicFile; } ///** // * @return My matrix dense dynamic file representation (const method). // */ //const CiftiConnectivityMatrixDenseDynamicFile* //CiftiBrainordinateDataSeriesFile::getConnectivityMatrixDenseDynamicFile() const //{ // CiftiBrainordinateDataSeriesFile* nonConstThis = const_cast(this); // if (m_lazyInitializedDenseDynamicFile == NULL) { // nonConstThis->initializeDenseDynamicFile(); // } // return m_lazyInitializedDenseDynamicFile; //} /** * @return True if any of the maps in this file contain a * color mapping that possesses a modified status. */ bool CiftiBrainordinateDataSeriesFile::isModifiedPaletteColorMapping() const { /* * This method is override because we need to know if the * encapsulated dynamic dense file has a modified palette. * When restoring a scene, a file with any type of modification * must be reloaded to remove any modifications. Note that * when a scene is restored, files that are not modified and * are in the new scene are NOT reloaded to save time. */ if (CiftiMappableDataFile::isModifiedPaletteColorMapping()) { return true; } if (m_lazyInitializedDenseDynamicFile != NULL) { if (m_lazyInitializedDenseDynamicFile->isModifiedPaletteColorMapping()) { return true; } } return false; } /** * @return The modified status for aall palettes in this file. * Note that 'modified' overrides any 'modified by show scene'. */ PaletteModifiedStatusEnum::Enum CiftiBrainordinateDataSeriesFile::getPaletteColorMappingModifiedStatus() const { const std::array fileModStatus = { { CiftiMappableDataFile::getPaletteColorMappingModifiedStatus(), ((m_lazyInitializedDenseDynamicFile != NULL) ? m_lazyInitializedDenseDynamicFile->getPaletteColorMappingModifiedStatus() : PaletteModifiedStatusEnum::UNMODIFIED) } }; PaletteModifiedStatusEnum::Enum modStatus = PaletteModifiedStatusEnum::UNMODIFIED; for (auto status : fileModStatus) { switch (status) { case PaletteModifiedStatusEnum::MODIFIED: modStatus = PaletteModifiedStatusEnum::MODIFIED; break; case PaletteModifiedStatusEnum::MODIFIED_BY_SHOW_SCENE: modStatus = PaletteModifiedStatusEnum::MODIFIED_BY_SHOW_SCENE; break; case PaletteModifiedStatusEnum::UNMODIFIED: break; } if (modStatus == PaletteModifiedStatusEnum::MODIFIED) { /* * 'MODIFIED' overrides 'MODIFIED_BY_SHOW_SCENE' * so no need to continue loop */ break; } } return modStatus; } connectome-workbench-1.4.2/src/Files/CiftiBrainordinateDataSeriesFile.h000066400000000000000000000102751360521144700261470ustar00rootroot00000000000000#ifndef __CIFTI_BRAINORDINATE_DATA_SERIES_FILE_H__ #define __CIFTI_BRAINORDINATE_DATA_SERIES_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "ChartableLineSeriesBrainordinateInterface.h" #include "CiftiMappableDataFile.h" namespace caret { class CiftiConnectivityMatrixDenseDynamicFile; class CiftiBrainordinateDataSeriesFile : public CiftiMappableDataFile, public ChartableLineSeriesBrainordinateInterface { public: CiftiBrainordinateDataSeriesFile(); virtual ~CiftiBrainordinateDataSeriesFile(); virtual bool isLineSeriesChartingEnabled(const int32_t tabIndex) const; virtual void setLineSeriesChartingEnabled(const int32_t tabIndex, const bool enabled); virtual bool isLineSeriesChartingSupported() const; virtual ChartDataCartesian* loadLineSeriesChartDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t nodeIndex); virtual ChartDataCartesian* loadAverageLineSeriesChartDataForSurfaceNodes(const StructureEnum::Enum structure, const std::vector& nodeIndices); virtual ChartDataCartesian* loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]); virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; CiftiConnectivityMatrixDenseDynamicFile* getConnectivityMatrixDenseDynamicFile(); //const CiftiConnectivityMatrixDenseDynamicFile* getConnectivityMatrixDenseDynamicFile() const; virtual void clear(); virtual void readFile(const AString& ciftiMapFileName); virtual void writeFile(const AString& filename); virtual bool isModifiedPaletteColorMapping() const override; virtual PaletteModifiedStatusEnum::Enum getPaletteColorMappingModifiedStatus() const override; private: CiftiBrainordinateDataSeriesFile(const CiftiBrainordinateDataSeriesFile&); CiftiBrainordinateDataSeriesFile& operator=(const CiftiBrainordinateDataSeriesFile&); virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE void initializeDenseDynamicFile(); bool m_chartingEnabledForTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; CiftiConnectivityMatrixDenseDynamicFile* m_lazyInitializedDenseDynamicFile; static const AString s_paletteColorMappingNameInMetaData; }; #ifdef __CIFTI_BRAINORDINATE_DATA_SERIES_FILE_DECLARE__ const AString CiftiBrainordinateDataSeriesFile::s_paletteColorMappingNameInMetaData = "__DYNAMIC_FILE_PALETTE_COLOR_MAPPING__"; // #endif // __CIFTI_BRAINORDINATE_DATA_SERIES_FILE_DECLARE__ } // namespace #endif //__CIFTI_BRAINORDINATE_DATA_SERIES_FILE_H__ connectome-workbench-1.4.2/src/Files/CiftiBrainordinateLabelFile.cxx000066400000000000000000000133261360521144700255150ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CIFTI_BRAINORDINATE_LABEL_FILE_DECLARE__ #include "CiftiBrainordinateLabelFile.h" #undef __CIFTI_BRAINORDINATE_LABEL_FILE_DECLARE__ #include "CiftiFile.h" #include "CiftiLabelsMap.h" using namespace caret; /** * \class caret::CiftiBrainordinateLabelFile * \brief CIFTI Brainordinate by Label File * \ingroup Files */ /** * Constructor. */ CiftiBrainordinateLabelFile::CiftiBrainordinateLabelFile() : CiftiMappableDataFile(DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL) { } /** * Destructor. */ CiftiBrainordinateLabelFile::~CiftiBrainordinateLabelFile() { } /** * For the given structure with the given number of nodes, get indices of all * nodes in the map that have the same label key (node value). * * @param structure * Structure of surface. * @param surfaceNumberOfNodes * Number of nodes in surface. * @param mapIndex * Index of the map. * @param labelKey * Desired label key. */ void CiftiBrainordinateLabelFile::getNodeIndicesWithLabelKey(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const int32_t mapIndex, const int32_t labelKey, std::vector& nodeIndicesOut) const { nodeIndicesOut.clear(); std::vector dataIndices; if (getSurfaceDataIndicesForMappingToBrainordinates(structure, surfaceNumberOfNodes, dataIndices)) { std::vector mapData; getMapData(mapIndex, mapData); for (int32_t i = 0; i < surfaceNumberOfNodes; i++) { const int64_t dataIndex = dataIndices[i]; if (dataIndex >= 0) { CaretAssertVectorIndex(mapData, dataIndex); const int32_t dataKey = static_cast(mapData[dataIndex]); if (dataKey == labelKey) { nodeIndicesOut.push_back(i); } } } } } /** * Get the voxel indices of all voxels in the given map with the given label key. * * @param mapIndex * Index of map. * @param labelKey * Key of the label. * @param voxelIndicesOut * Output containing indices of voxels with the given label key. */ void CiftiBrainordinateLabelFile::getVoxelIndicesWithLabelKey(const int32_t mapIndex, const int32_t labelKey, std::vector& voxelIndicesOut) const { voxelIndicesOut.clear(); const CiftiXML& myXML = m_ciftiFile->getCiftiXML(); if (myXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) { return; } std::vector volumeMaps = myXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN).getFullVolumeMap(); std::vector mapData; getMapData(mapIndex, mapData); for (std::vector::iterator iter = volumeMaps.begin(); iter != volumeMaps.end(); iter++) { const CiftiBrainModelsMap::VolumeMap& vm = *iter; const int64_t dataOffset = vm.m_ciftiIndex; CaretAssertVectorIndex(mapData, dataOffset); const int32_t key = static_cast(mapData[dataOffset]); if (key == labelKey) { voxelIndicesOut.push_back(VoxelIJK(vm.m_ijk)); } } } /** * Get the voxel indices of all voxels in the given map with the given label key. * * @param mapIndex * Index of map. * @param labelKey * Key of the label. * @param voxelXyzOut * Output containing coordinates of voxels with the given label key. */ void CiftiBrainordinateLabelFile::getVoxelCoordinatesWithLabelKey(const int32_t mapIndex, const int32_t labelKey, std::vector& voxelXyzOut) const { voxelXyzOut.clear(); std::vector voxelIJK; getVoxelIndicesWithLabelKey(mapIndex, labelKey, voxelIJK); if (voxelIJK.empty()) { return; } const CiftiXML& myXML = m_ciftiFile->getCiftiXML(); if (myXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) { return; } const VolumeSpace volumeSpace = myXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN).getVolumeSpace(); const int64_t numVoxels = static_cast(voxelIJK.size()); for (int64_t i = 0; i < numVoxels; i++) { float xyz[3]; volumeSpace.indexToSpace(voxelIJK[i].m_ijk, xyz); voxelXyzOut.push_back(xyz[0]); voxelXyzOut.push_back(xyz[1]); voxelXyzOut.push_back(xyz[2]); } } connectome-workbench-1.4.2/src/Files/CiftiBrainordinateLabelFile.h000066400000000000000000000047501360521144700251430ustar00rootroot00000000000000#ifndef __CIFTI_BRAINORDINATE_LABEL_FILE_H__ #define __CIFTI_BRAINORDINATE_LABEL_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiMappableDataFile.h" #include "VoxelIJK.h" namespace caret { class CiftiBrainordinateLabelFile : public CiftiMappableDataFile { public: CiftiBrainordinateLabelFile(); virtual ~CiftiBrainordinateLabelFile(); void getNodeIndicesWithLabelKey(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const int32_t mapIndex, const int32_t labelKey, std::vector& nodeIndicesOut) const; void getVoxelIndicesWithLabelKey(const int32_t mapIndex, const int32_t labelKey, std::vector& voxelIndicesOut) const; void getVoxelCoordinatesWithLabelKey(const int32_t mapIndex, const int32_t labelKey, std::vector& voxelXyzOut) const; private: CiftiBrainordinateLabelFile(const CiftiBrainordinateLabelFile&); CiftiBrainordinateLabelFile& operator=(const CiftiBrainordinateLabelFile&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE }; #ifdef __CIFTI_BRAINORDINATE_LABEL_FILE_DECLARE__ // #endif // __CIFTI_BRAINORDINATE_LABEL_FILE_DECLARE__ } // namespace #endif //__CIFTI_BRAINORDINATE_LABEL_FILE_H__ connectome-workbench-1.4.2/src/Files/CiftiBrainordinateScalarFile.cxx000066400000000000000000000360041360521144700257010ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CIFTI_BRAINORDINATE_SCALAR_FILE_DECLARE__ #include "CiftiBrainordinateScalarFile.h" #undef __CIFTI_BRAINORDINATE_SCALAR_FILE_DECLARE__ #include "CiftiMappableConnectivityMatrixDataFile.h" #include "CiftiConnectivityMatrixDenseFile.h" #include "CiftiConnectivityMatrixDenseDynamicFile.h" #include "CaretLogger.h" #include "ChartDataCartesian.h" #include "CiftiFile.h" #include "CiftiXML.h" #include "DataFileException.h" #include "FileInformation.h" #include "SceneClass.h" #include "SceneClassArray.h" using namespace caret; /** * \class caret::CiftiBrainordinateScalarFile * \brief CIFTI Brainordinate by Scalar File * \ingroup Files * */ /** * Constructor. */ CiftiBrainordinateScalarFile::CiftiBrainordinateScalarFile() : CiftiMappableDataFile(DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR) { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = false; } } /** * Destructor. */ CiftiBrainordinateScalarFile::~CiftiBrainordinateScalarFile() { } /** * Create a Cifti Scalar File using the currently loaded row in a Cifti * connectivity matrix file. * * @param sourceCiftiMatrixFile * Cifti connectivity matrix file. * @param destinationDirectory * Directory in which file is placed if the input matrix file is not * in a valid local (user's file system) directory. * @param errorMessageOut * Will describe problem if there is an error. * @return * Pointer to the newly created Cifti Scalar File. If there is an error, * NULL will be returned and errorMessageOut will describe the problem. */ CiftiBrainordinateScalarFile* CiftiBrainordinateScalarFile::newInstanceFromRowInCiftiConnectivityMatrixFile(const CiftiMappableConnectivityMatrixDataFile* sourceCiftiMatrixFile, const AString& destinationDirectory, AString& errorMessageOut) { errorMessageOut.clear(); const CiftiConnectivityMatrixDenseFile* denseFile = dynamic_cast(sourceCiftiMatrixFile); const CiftiConnectivityMatrixDenseDynamicFile* dynamicDenseFile = dynamic_cast(sourceCiftiMatrixFile); if ((denseFile != NULL) || (dynamicDenseFile != NULL)) { /* ok, acceptable file type */ } else { errorMessageOut = "Only Cifti Dense Matrix Files and Dynamic Data from Data (time) Series Files are supported for conversion to Cifti Scalar Files."; return NULL; } const CiftiFile* sourceCiftiFile = sourceCiftiMatrixFile->m_ciftiFile; if (sourceCiftiMatrixFile->getNumberOfMaps() <= 0) { errorMessageOut = "No data appears to be loaded in the Cifti Matrix File (No Maps)."; return NULL; } std::vector data; sourceCiftiMatrixFile->getMapData(0, data); if (data.empty()) { errorMessageOut = "No data appears to be loaded in the Cifti Matrix File (mapData empty)."; return NULL; } CiftiBrainordinateScalarFile* scalarFile = NULL; try { CiftiFile* ciftiFile = new CiftiFile(); /* * Copy XML from matrix file * and update to be a scalar file. */ const CiftiXML& ciftiMatrixXML = sourceCiftiFile->getCiftiXML(); CiftiXML ciftiScalarXML = ciftiMatrixXML; CiftiBrainModelsMap brainModelsMap; if (denseFile != NULL) { brainModelsMap = ciftiMatrixXML.getBrainModelsMap(CiftiXML::ALONG_ROW); } else if (dynamicDenseFile != NULL) { brainModelsMap = ciftiMatrixXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); } else { const AString msg("Invalid file type for create of CIFTI Scalars File: " + sourceCiftiMatrixFile->getFileName()); CaretAssertMessage(0, msg); CaretLogSevere(msg); delete ciftiFile; return NULL; } CiftiScalarsMap scalarsMap; scalarsMap.setLength(1); scalarsMap.setMapName(0, sourceCiftiMatrixFile->getMapName(0)); ciftiScalarXML.setMap(CiftiXML::ALONG_ROW, scalarsMap); ciftiScalarXML.setMap(CiftiXML::ALONG_COLUMN, brainModelsMap); ciftiFile->setCiftiXML(ciftiScalarXML); /* * Add data to the file */ ciftiFile->setColumn(&data[0], 0); /* * Create a scalar file */ CiftiBrainordinateScalarFile* scalarFile = new CiftiBrainordinateScalarFile(); scalarFile->m_ciftiFile.grabNew(ciftiFile); /* * May need to convert a remote path to a local path */ FileInformation initialFileNameInfo(sourceCiftiMatrixFile->getFileName()); const AString scalarFileName = initialFileNameInfo.getAsLocalAbsoluteFilePath(destinationDirectory, scalarFile->getDataFileType()); /* * Create name of scalar file with row/column information */ FileInformation scalarFileInfo(scalarFileName); AString thePath, theName, theExtension; scalarFileInfo.getFileComponents(thePath, theName, theExtension); theName.append("_" + sourceCiftiMatrixFile->getRowLoadedText()); const AString newFileName = FileInformation::assembleFileComponents(thePath, theName, theExtension); scalarFile->setFileName(newFileName); scalarFile->initializeAfterReading(newFileName); /* * Need to copy color palette since it may be the default */ PaletteColorMapping* scalarPalette = scalarFile->getMapPaletteColorMapping(0); CaretAssert(scalarPalette); const PaletteColorMapping* densePalette = sourceCiftiMatrixFile->getMapPaletteColorMapping(0); CaretAssert(densePalette); scalarPalette->copy(*densePalette, true); scalarFile->updateAfterFileDataChanges(); scalarFile->setModified(); return scalarFile; } catch (const DataFileException& de) { if (scalarFile != NULL) { delete scalarFile; } errorMessageOut = de.whatString(); } return NULL; } /** * @return Is charting enabled for this file? */ bool CiftiBrainordinateScalarFile::isLineSeriesChartingEnabled(const int32_t tabIndex) const { CaretAssertArrayIndex(m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_chartingEnabledForTab[tabIndex]; } /** * @return Return true if the file's current state supports * charting data, else false. Typically a brainordinate file * is chartable if it contains more than one map. */ bool CiftiBrainordinateScalarFile::isLineSeriesChartingSupported() const { if (getNumberOfMaps() > 1) { return true; } return false; } /** * Set charting enabled for this file. * * @param enabled * New status for charting enabled. */ void CiftiBrainordinateScalarFile::setLineSeriesChartingEnabled(const int32_t tabIndex, const bool enabled) { CaretAssertArrayIndex(m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_chartingEnabledForTab[tabIndex] = enabled; } /** * Get chart data types supported by the file. * * @param chartDataTypesOut * Chart types supported by this file. */ void CiftiBrainordinateScalarFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { helpGetSupportedLineSeriesChartDataTypes(chartDataTypesOut); } /** * Load charting data for the surface with the given structure and node index. * * @param structure * The surface's structure. * @param nodeIndex * Index of the node. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will return true. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* CiftiBrainordinateScalarFile::loadLineSeriesChartDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t nodeIndex) { ChartDataCartesian* chartData = helpLoadChartDataForSurfaceNode(structure, nodeIndex); return chartData; // ChartDataCartesian* chartData = NULL; // // try { // std::vector data; // if (getSeriesDataForSurfaceNode(structure, // nodeIndex, // data)) { // const int64_t numData = static_cast(data.size()); // // chartData = new ChartDataCartesian(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES, // ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, // ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); // for (int64_t i = 0; i < numData; i++) { // float xValue = i; // chartData->addPoint(xValue, // data[i]); // } // // const AString description = (getFileNameNoPath() // + " node " // + AString::number(nodeIndex)); // chartData->setDescription(description); // } // } // catch (const DataFileException& dfe) { // if (chartData != NULL) { // delete chartData; // chartData = NULL; // } // // throw dfe; // } // // return chartData; } /** * Load average charting data for the surface with the given structure and node indices. * * @param structure * The surface's structure. * @param nodeIndices * Indices of the node. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* CiftiBrainordinateScalarFile::loadAverageLineSeriesChartDataForSurfaceNodes(const StructureEnum::Enum structure, const std::vector& nodeIndices) { ChartDataCartesian* chartData = helpLoadChartDataForSurfaceNodeAverage(structure, nodeIndices); return chartData; } /** * Load charting data for the voxel enclosing the given coordinate. * * @param xyz * Coordinate of voxel. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* CiftiBrainordinateScalarFile::loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]) { ChartDataCartesian* chartData = helpLoadChartDataForVoxelAtCoordinate(xyz); return chartData; } /** * Save file data from the scene. For subclasses that need to * save to a scene, this method should be overriden. sceneClass * will be valid and any scene data should be added to it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. */ void CiftiBrainordinateScalarFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { CiftiMappableDataFile::saveFileDataToScene(sceneAttributes, sceneClass); sceneClass->addBooleanArray("m_chartingEnabledForTab", m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); } /** * Restore file data from the scene. For subclasses that need to * restore from a scene, this method should be overridden. The scene class * will be valid and any scene data may be obtained from it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void CiftiBrainordinateScalarFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { CiftiMappableDataFile::restoreFileDataFromScene(sceneAttributes, sceneClass); const ScenePrimitiveArray* tabArray = sceneClass->getPrimitiveArray("m_chartingEnabledForTab"); if (tabArray != NULL) { sceneClass->getBooleanArrayValue("m_chartingEnabledForTab", m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); } else { /* * Obsolete value when charting was not 'per tab' */ const bool chartingEnabled = sceneClass->getBooleanValue("m_chartingEnabled", false); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = chartingEnabled; } } } connectome-workbench-1.4.2/src/Files/CiftiBrainordinateScalarFile.h000066400000000000000000000072111360521144700253240ustar00rootroot00000000000000#ifndef __CIFTI_BRAINORDINATE_SCALAR_FILE_H__ #define __CIFTI_BRAINORDINATE_SCALAR_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "ChartableLineSeriesBrainordinateInterface.h" #include "CiftiMappableDataFile.h" namespace caret { class CiftiMappableConnectivityMatrixDataFile; class CiftiBrainordinateScalarFile : public CiftiMappableDataFile, public ChartableLineSeriesBrainordinateInterface { public: CiftiBrainordinateScalarFile(); virtual ~CiftiBrainordinateScalarFile(); static CiftiBrainordinateScalarFile* newInstanceFromRowInCiftiConnectivityMatrixFile(const CiftiMappableConnectivityMatrixDataFile* ciftiMatrixFile, const AString& destinationDirectory, AString& errorMessageOut); virtual bool isLineSeriesChartingEnabled(const int32_t tabIndex) const; virtual void setLineSeriesChartingEnabled(const int32_t tabIndex, const bool enabled); virtual bool isLineSeriesChartingSupported() const; virtual ChartDataCartesian* loadLineSeriesChartDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t nodeIndex); virtual ChartDataCartesian* loadAverageLineSeriesChartDataForSurfaceNodes(const StructureEnum::Enum structure, const std::vector& nodeIndices); virtual ChartDataCartesian* loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]); virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; private: CiftiBrainordinateScalarFile(const CiftiBrainordinateScalarFile&); CiftiBrainordinateScalarFile& operator=(const CiftiBrainordinateScalarFile&); virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); public: // ADD_NEW_METHODS_HERE private: bool m_chartingEnabledForTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; // ADD_NEW_MEMBERS_HERE }; #ifdef __CIFTI_BRAINORDINATE_SCALAR_FILE_DECLARE__ // #endif // __CIFTI_BRAINORDINATE_SCALAR_FILE_DECLARE__ } // namespace #endif //__CIFTI_BRAINORDINATE_SCALAR_FILE_H__ connectome-workbench-1.4.2/src/Files/CiftiConnectivityMatrixDenseDynamicFile.cxx000066400000000000000000000466571360521144700301400ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __CIFTI_CONNECTIVITY_MATRIX_DENSE_DYNAMIC_FILE_DECLARE__ #include "CiftiConnectivityMatrixDenseDynamicFile.h" #undef __CIFTI_CONNECTIVITY_MATRIX_DENSE_DYNAMIC_FILE_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretOMP.h" #include "CiftiBrainordinateDataSeriesFile.h" #include "CiftiFile.h" #include "FileInformation.h" #include "SceneClassAssistant.h" #include "dot_wrapper.h" using namespace caret; /** * \class caret::CiftiConnectivityMatrixDenseDynamicFile * \brief Connectivity Dynamic Dense x Dense File version of data-series * \ingroup Files * * Contains dynamic connectivity from brainordinates to brainordinates. * Internally, the file format is the same as a data series file. When * a row is requested, the row is correlated with all other rows * producing the connectivity from that row to all other rows. */ /** * Constructor. * * @param parentDataSeriesFile * Parent data series file. */ CiftiConnectivityMatrixDenseDynamicFile::CiftiConnectivityMatrixDenseDynamicFile(CiftiBrainordinateDataSeriesFile* parentDataSeriesFile) : CiftiMappableConnectivityMatrixDataFile(DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC), m_parentDataSeriesFile(parentDataSeriesFile), m_parentDataSeriesCiftiFile(NULL), m_numberOfBrainordinates(-1), m_numberOfTimePoints(-1), m_validDataFlag(false), m_enabledAsLayer(true), m_cacheDataFlag(false) { CaretAssert(m_parentDataSeriesFile); m_sceneAssistant.grabNew(new SceneClassAssistant()); m_sceneAssistant->add("m_enabledAsLayer", &m_enabledAsLayer); } /** * Destructor. */ CiftiConnectivityMatrixDenseDynamicFile::~CiftiConnectivityMatrixDenseDynamicFile() { } /** * @return The parent brainordinate data-series file (const method) */ const CiftiBrainordinateDataSeriesFile* CiftiConnectivityMatrixDenseDynamicFile::getParentBrainordinateDataSeriesFile() const { return m_parentDataSeriesFile; } /** * @return The parent brainordinate data-series file. */ CiftiBrainordinateDataSeriesFile* CiftiConnectivityMatrixDenseDynamicFile::getParentBrainordinateDataSeriesFile() { return m_parentDataSeriesFile; } /** * @return True if enabled as a layer. */ bool CiftiConnectivityMatrixDenseDynamicFile::isEnabledAsLayer() const { return m_enabledAsLayer; } /** * Set enabled as a layer. * * @param True if enabled as a layer. */ void CiftiConnectivityMatrixDenseDynamicFile::setEnabledAsLayer(const bool enabled) { m_enabledAsLayer = enabled; } /** * @return True if this file type supports writing, else false. * * Dense files do NOT support writing. */ bool CiftiConnectivityMatrixDenseDynamicFile::supportsWriting() const { return false; } /** * @return Is the data within the file valid? */ bool CiftiConnectivityMatrixDenseDynamicFile::isDataValid() const { return m_validDataFlag; } /** * Update the content of this dense dynamic file after the parent * brainordinate data series file is successfully read. * * @param ciftiFile * Parent's CIFTI file.. */ void CiftiConnectivityMatrixDenseDynamicFile::updateAfterReading(const CiftiFile* ciftiFile) { m_validDataFlag = false; m_parentDataSeriesCiftiFile = const_cast(ciftiFile); AString path, nameNoExt, ext; FileInformation fileInfo(m_parentDataSeriesCiftiFile->getFileName()); fileInfo.getFileComponents(path, nameNoExt, ext); setFileName(FileInformation::assembleFileComponents(path, nameNoExt, DataFileTypeEnum::toFileExtension(DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC))); /* * Need dimensions of data * Note that CIFTI XML in this file is identifical to CIFTI XML in parent data-series file */ const CiftiXML& ciftiXML = getCiftiFile()->getCiftiXML(); m_numberOfBrainordinates = ciftiXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN).getLength(); m_numberOfTimePoints = ciftiXML.getSeriesMap(CiftiXML::ALONG_ROW).getLength(); m_rowData.clear(); if ((m_numberOfBrainordinates > 0) && (m_numberOfTimePoints > 0)) { m_rowData.resize(m_numberOfBrainordinates); if (m_cacheDataFlag) { /* * Read all of the data. Time-series type files are not * too large and by caching the data, it eliminates * numerous calls to read the data when correlation * is performed. * * READ DATA FROM PARENT FILE */ for (int32_t i = 0; i < m_numberOfBrainordinates; i++) { CaretAssertVectorIndex(m_rowData, i); m_rowData[i].m_data.resize(m_numberOfTimePoints); m_parentDataSeriesCiftiFile->getRow(&m_rowData[i].m_data[0], i); } } preComputeRowMeanAndSumSquared(); m_validDataFlag = true; } } /** * Load data for the given column. * * @param dataOut * Output with data. * @param index * Index of the column. */ void CiftiConnectivityMatrixDenseDynamicFile::getDataForColumn(float* /*dataOut*/, const int64_t& /*index*/) const { const AString msg("Should never be called for Dense Dynamic File"); CaretAssertMessage(0, msg); CaretLogSevere(msg); } /** * Load data for the given row. * * @param dataOut * Output with data. * @param index * Index of the row. */ void CiftiConnectivityMatrixDenseDynamicFile::getDataForRow(float* dataOut, const int64_t& index) const { m_parentDataSeriesCiftiFile->getRow(dataOut, index); } /** * Load PROCESSED data for the given column. * * Some file types may have special processing for a column. This method can be * overridden for those types of files. * * @param dataOut * Output with data. * @param index * Index of the column. */ void CiftiConnectivityMatrixDenseDynamicFile::getProcessedDataForColumn(float* /*dataOut*/, const int64_t& /*index*/) const { const AString msg("Should never be called for Dense Dynamic File"); CaretAssertMessage(0, msg); CaretLogSevere(msg); } /** * Load PROCESSED data for the given row. * * Some file types may have special processing for a row. This method can be * overridden for those types of files. * * @param dataOut * Output with data. * @param index * Index of the row. */ void CiftiConnectivityMatrixDenseDynamicFile::getProcessedDataForRow(float* dataOut, const int64_t& index) const { if ((m_numberOfBrainordinates <= 0) || (m_numberOfTimePoints <= 0)) { return; } std::vector rowData(m_numberOfTimePoints); m_parentDataSeriesCiftiFile->getRow(&rowData[0], index); const float mean = m_rowData[index].m_mean; const float ssxx = m_rowData[index].m_sqrt_ssxx; /* * TSC: hyperthreading means some cores end up "faster" than others, so "static" scheduling is generally not as fast * there is almost no overhead to dynamic scheduling */ #pragma omp CARET_PARFOR schedule(dynamic) for (int32_t iRow = 0; iRow < m_numberOfBrainordinates; iRow++) { float coefficient = 1.0; if (iRow != index) { coefficient = correlation(rowData, mean, ssxx, iRow, m_numberOfTimePoints); } dataOut[iRow] = coefficient; } } /** * Some file types may perform additional processing of row average data and * can override this method. * * @param rowAverageDataInOut * The row average data. */ void CiftiConnectivityMatrixDenseDynamicFile::processRowAverageData(std::vector& rowAverageDataInOut) { if ((m_numberOfBrainordinates <= 0) || (m_numberOfTimePoints <= 0)) { return; } const int32_t dataLength = static_cast(rowAverageDataInOut.size()); if (dataLength != m_numberOfTimePoints) { CaretLogWarning("Data length incorrect. Is " + AString::number(dataLength) + " but should be " + AString::number(m_numberOfTimePoints)); return; } if (dataLength <= 0) { return; } float mean = 0.0; float sumSquared = 0.0; computeDataMeanAndSumSquared(&rowAverageDataInOut[0], dataLength, mean, sumSquared); std::vector processedRowAverageData(m_numberOfBrainordinates); /* * TSC: hyperthreading means some cores end up "faster" than others, so "static" scheduling is generally not as fast * there is almost no overhead to dynamic scheduling */ #pragma omp CARET_PARFOR schedule(dynamic) for (int32_t iRow = 0; iRow < m_numberOfBrainordinates; iRow++) { const float coefficient = correlation(rowAverageDataInOut, mean, sumSquared, iRow, dataLength); CaretAssertVectorIndex(processedRowAverageData, iRow); processedRowAverageData[iRow] = coefficient; } rowAverageDataInOut = processedRowAverageData; } /** * Compute the mean and sum-squared for each row so that they * are only calculated once. */ void CiftiConnectivityMatrixDenseDynamicFile::preComputeRowMeanAndSumSquared() { CaretAssert(m_numberOfBrainordinates > 0); CaretAssert(m_numberOfTimePoints > 0); /* * TSC: hyperthreading means some cores end up "faster" than others, so "static" scheduling is generally not as fast * there is almost no overhead to dynamic scheduling */ #pragma omp CARET_PARFOR schedule(dynamic) for (int32_t iRow = 0; iRow < m_numberOfBrainordinates; iRow++) { CaretAssertVectorIndex(m_rowData, iRow); if (m_cacheDataFlag) { CaretAssertVectorIndex(m_rowData[iRow].m_data, (m_numberOfTimePoints - 1)); computeDataMeanAndSumSquared(&m_rowData[iRow].m_data[0], m_numberOfTimePoints, m_rowData[iRow].m_mean, m_rowData[iRow].m_sqrt_ssxx); } else { std::vector data(m_numberOfTimePoints); #pragma omp critical {//TSC: this can do disk access, which is not currently thread-safe m_parentDataSeriesCiftiFile->getRow(&data[0], iRow); } computeDataMeanAndSumSquared(&data[0], m_numberOfTimePoints, m_rowData[iRow].m_mean, m_rowData[iRow].m_sqrt_ssxx); } // double sum = 0.0; // double sumSquared = 0.0; // if (m_cacheDataFlag) { // for (int32_t iPoint = 0; iPoint < m_numberOfTimePoints; iPoint++) { // CaretAssertVectorIndex(m_rowData[iRow].m_data, iPoint); // const float d = m_rowData[iRow].m_data[iPoint]; // sum += d; // sumSquared += (d * d); // } // } // else { // std::vector data(m_numberOfTimePoints); // m_parentDataSeriesCiftiFile->getRow(&data[0], iRow); // for (int32_t iPoint = 0; iPoint < m_numberOfTimePoints; iPoint++) { // CaretAssertVectorIndex(data, iPoint); // const float d = data[iPoint]; // sum += d; // sumSquared += (d * d); // } // } // // const float mean = (sum / numPointsFloat); // const float ssxx = (sumSquared - (numPointsFloat * mean * mean)); // CaretAssert(ssxx >= 0.0); // // const float meanDiff = std::fabs(mean - m_rowData[iRow].m_mean); // const float ssDiff = std::fabs(std::sqrt(ssxx) - m_rowData[iRow].m_sqrt_ssxx); // if ((meanDiff > 0.0001) || (ssDiff > 0.0001)) { // std::cout << "Mean/SS diff" << std::endl; // } // // m_rowData[iRow].m_mean = mean; // m_rowData[iRow].m_sqrt_ssxx = std::sqrt(ssxx); } } /** * Compute data's mean and sum-squared * * @param data * Data on which mean and sum-squared are calculated * @param dataLength * Number of items in data. * @param meanOut * Output with mean of data. * @param sumSquaredOut * Output with sum-squared. */ void CiftiConnectivityMatrixDenseDynamicFile::computeDataMeanAndSumSquared(const float* data, const int32_t dataLength, float& meanOut, float& sumSquaredOut) const { meanOut = 0.0; sumSquaredOut = 0.0; if (dataLength <= 0) { return; } double sum = 0.0; double sumSquared = 0.0; for (int32_t i = 0; i < dataLength; i++) { const float d = data[i]; sum += d; sumSquared += (d * d); } meanOut = (sum / dataLength); const float ssxx = (sumSquared - (dataLength * meanOut * meanOut)); //TSC: do not assert things that depend on input file content (a NaN in the data will trip it), you could print a warning instead //CaretAssert(ssxx >= 0.0); sumSquaredOut = std::sqrt(ssxx); } /** * Correlation from https://en.wikipedia.org/wiki/Pearson_product-moment_correlation_coefficient * * @param data * Data for correlation * @param mean * Mean of data * @param sumSquared * Sum squared of data. * @param otherRowIndex * Index of another row * @param numberOfPoints * Number of points int the two arrays * @return * The correlation coefficient computed on the two arrays. */ float CiftiConnectivityMatrixDenseDynamicFile::correlation(const std::vector& data, const float mean, const float sumSquared, const int32_t otherRowIndex, const int32_t numberOfPoints) const { const double numFloat = numberOfPoints; double xySum = 0.0; CaretAssertVectorIndex(m_rowData, otherRowIndex); const RowData& otherData = m_rowData[otherRowIndex]; if (m_cacheDataFlag) { xySum = dsdot(&data[0], &otherData.m_data[0], numberOfPoints); } else { std::vector otherDataVector(m_numberOfTimePoints); m_parentDataSeriesCiftiFile->getRow(&otherDataVector[0], otherRowIndex); xySum = dsdot(&data[0], &otherDataVector[0], numberOfPoints); } const double ssxy = xySum - (numFloat * mean * otherData.m_mean); float correlationCoefficient = 0.0; if ((sumSquared > 0.0) && (otherData.m_sqrt_ssxx > 0.0)) { correlationCoefficient = (ssxy / (sumSquared * otherData.m_sqrt_ssxx)); } return correlationCoefficient; } /** * Correlation from https://en.wikipedia.org/wiki/Pearson_product-moment_correlation_coefficient * * @param rowIndex * Index of a row * @param otherRowIndex * Index of another row * @param numberOfPoints * Number of points int the two arrays * @return * The correlation coefficient computed on the two arrays. */ float CiftiConnectivityMatrixDenseDynamicFile::correlation(const int32_t rowIndex, const int32_t otherRowIndex, const int32_t numberOfPoints) const { const double numFloat = numberOfPoints; double xySum = 0.0; CaretAssertVectorIndex(m_rowData, rowIndex); CaretAssertVectorIndex(m_rowData, otherRowIndex); const RowData& data = m_rowData[rowIndex]; const RowData& otherData = m_rowData[otherRowIndex]; if (m_cacheDataFlag) { for (int i = 0; i < numberOfPoints; i++) { CaretAssertVectorIndex(data.m_data, i); CaretAssertVectorIndex(otherData.m_data, i); xySum += data.m_data[i] * otherData.m_data[i]; } } else { std::vector dataVector(m_numberOfTimePoints); std::vector otherDataVector(m_numberOfTimePoints); m_parentDataSeriesCiftiFile->getRow(&dataVector[0], rowIndex); m_parentDataSeriesCiftiFile->getRow(&otherDataVector[0], otherRowIndex); for (int i = 0; i < numberOfPoints; i++) { CaretAssertVectorIndex(dataVector, i); CaretAssertVectorIndex(otherDataVector, i); xySum += dataVector[i] * otherDataVector[i]; } } const double ssxy = xySum - (numFloat * data.m_mean * otherData.m_mean); float correlationCoefficient = 0.0; if ((data.m_sqrt_ssxx > 0.0) && (otherData.m_sqrt_ssxx > 0.0)) { correlationCoefficient = (ssxy / (data.m_sqrt_ssxx * otherData.m_sqrt_ssxx)); } return correlationCoefficient; } /** * Save subclass data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void CiftiConnectivityMatrixDenseDynamicFile::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void CiftiConnectivityMatrixDenseDynamicFile::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } connectome-workbench-1.4.2/src/Files/CiftiConnectivityMatrixDenseDynamicFile.h000066400000000000000000000112421360521144700275430ustar00rootroot00000000000000#ifndef __CIFTI_CONNECTIVITY_MATRIX_DENSE_DYNAMIC_FILE_H__ #define __CIFTI_CONNECTIVITY_MATRIX_DENSE_DYNAMIC_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretPointer.h" #include "CiftiMappableConnectivityMatrixDataFile.h" namespace caret { class CiftiBrainordinateDataSeriesFile; class SceneClassAssistant; class CiftiConnectivityMatrixDenseDynamicFile : public CiftiMappableConnectivityMatrixDataFile { public: CiftiConnectivityMatrixDenseDynamicFile(CiftiBrainordinateDataSeriesFile* parentDataSeriesFile); virtual ~CiftiConnectivityMatrixDenseDynamicFile(); bool isDataValid() const; bool isEnabledAsLayer() const; void setEnabledAsLayer(const bool enabled); virtual bool supportsWriting() const; void updateAfterReading(const CiftiFile* ciftiFile); CiftiBrainordinateDataSeriesFile* getParentBrainordinateDataSeriesFile(); const CiftiBrainordinateDataSeriesFile* getParentBrainordinateDataSeriesFile() const; private: CiftiConnectivityMatrixDenseDynamicFile(const CiftiConnectivityMatrixDenseDynamicFile&); CiftiConnectivityMatrixDenseDynamicFile& operator=(const CiftiConnectivityMatrixDenseDynamicFile&); protected: virtual void getDataForColumn(float* dataOut, const int64_t& index) const; virtual void getDataForRow(float* dataOut, const int64_t& index) const; virtual void getProcessedDataForColumn(float* dataOut, const int64_t& index) const; virtual void getProcessedDataForRow(float* dataOut, const int64_t& index) const; virtual void processRowAverageData(std::vector& rowAverageData); virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: class RowData { public: RowData() { } ~RowData() { } std::vector m_data; float m_mean; float m_sqrt_ssxx; }; float correlation(const int32_t rowIndex, const int32_t otherRowIndex, const int32_t numberOfPoints) const; float correlation(const std::vector& data, const float mean, const float sumSquared, const int32_t otherRowIndex, const int32_t numberOfPoints) const; void preComputeRowMeanAndSumSquared(); void computeDataMeanAndSumSquared(const float* data, const int32_t dataLength, float& meanOut, float& sumSquaredOut) const; CiftiBrainordinateDataSeriesFile* m_parentDataSeriesFile; CiftiFile* m_parentDataSeriesCiftiFile; int32_t m_numberOfBrainordinates; int32_t m_numberOfTimePoints; std::vector m_rowData; bool m_validDataFlag; bool m_enabledAsLayer; const bool m_cacheDataFlag; CaretPointer m_sceneAssistant; // ADD_NEW_MEMBERS_HERE }; #ifdef __CIFTI_CONNECTIVITY_MATRIX_DENSE_DYNAMIC_FILE_DECLARE__ // #endif // __CIFTI_CONNECTIVITY_MATRIX_DENSE_DYNAMIC_FILE_DECLARE__ } // namespace #endif //__CIFTI_CONNECTIVITY_MATRIX_DENSE_DYNAMIC_FILE_H__ connectome-workbench-1.4.2/src/Files/CiftiConnectivityMatrixDenseFile.cxx000066400000000000000000000033141360521144700266120ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CIFTI_CONNECTIVITY_MATRIX_DENSE_FILE_DECLARE__ #include "CiftiConnectivityMatrixDenseFile.h" #undef __CIFTI_CONNECTIVITY_MATRIX_DENSE_FILE_DECLARE__ using namespace caret; /** * \class caret::CiftiConnectivityMatrixDenseFile * \brief Connectivity Dense x Dense File * \ingroup Files * * Contains connectivity matrix that measures connectivity from brainordinates * to brainordinates. */ /** * Constructor. */ CiftiConnectivityMatrixDenseFile::CiftiConnectivityMatrixDenseFile() : CiftiMappableConnectivityMatrixDataFile(DataFileTypeEnum::CONNECTIVITY_DENSE) { } /** * Destructor. */ CiftiConnectivityMatrixDenseFile::~CiftiConnectivityMatrixDenseFile() { } /** * @return True if this file type supports writing, else false. * * Dense files do NOT support writing. */ bool CiftiConnectivityMatrixDenseFile::supportsWriting() const { return false; } connectome-workbench-1.4.2/src/Files/CiftiConnectivityMatrixDenseFile.h000066400000000000000000000034601360521144700262410ustar00rootroot00000000000000#ifndef __CIFTI_CONNECTIVITY_MATRIX_DENSE_FILE_H__ #define __CIFTI_CONNECTIVITY_MATRIX_DENSE_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiMappableConnectivityMatrixDataFile.h" namespace caret { class CiftiConnectivityMatrixDenseFile : public CiftiMappableConnectivityMatrixDataFile { public: CiftiConnectivityMatrixDenseFile(); virtual ~CiftiConnectivityMatrixDenseFile(); virtual bool supportsWriting() const; private: CiftiConnectivityMatrixDenseFile(const CiftiConnectivityMatrixDenseFile&); CiftiConnectivityMatrixDenseFile& operator=(const CiftiConnectivityMatrixDenseFile&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE }; #ifdef __CIFTI_CONNECTIVITY_MATRIX_DENSE_FILE_DECLARE__ // #endif // __CIFTI_CONNECTIVITY_MATRIX_DENSE_FILE_DECLARE__ } // namespace #endif //__CIFTI_CONNECTIVITY_MATRIX_DENSE_FILE_H__ connectome-workbench-1.4.2/src/Files/CiftiConnectivityMatrixDenseParcelFile.cxx000066400000000000000000000030661360521144700277450ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CIFTI_CONNECTIVITY_MATRIX_DENSE_PARCEL_FILE_DECLARE__ #include "CiftiConnectivityMatrixDenseParcelFile.h" #undef __CIFTI_CONNECTIVITY_MATRIX_DENSE_PARCEL_FILE_DECLARE__ using namespace caret; /** * \class caret::CiftiConnectivityMatrixDenseParcelFile * \brief Connectivity Dense x Parcel File * \ingroup Files * * Contains connectivity matrix that measures connectivity from brainordinates * to parcels. */ /** * Constructor. */ CiftiConnectivityMatrixDenseParcelFile::CiftiConnectivityMatrixDenseParcelFile() : CiftiMappableConnectivityMatrixDataFile(DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL) { } /** * Destructor. */ CiftiConnectivityMatrixDenseParcelFile::~CiftiConnectivityMatrixDenseParcelFile() { } connectome-workbench-1.4.2/src/Files/CiftiConnectivityMatrixDenseParcelFile.h000066400000000000000000000035061360521144700273710ustar00rootroot00000000000000#ifndef __CIFTI_CONNECTIVITY_MATRIX_DENSE_PARCEL_FILE_H__ #define __CIFTI_CONNECTIVITY_MATRIX_DENSE_PARCEL_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiMappableConnectivityMatrixDataFile.h" namespace caret { class CiftiConnectivityMatrixDenseParcelFile : public CiftiMappableConnectivityMatrixDataFile { public: CiftiConnectivityMatrixDenseParcelFile(); virtual ~CiftiConnectivityMatrixDenseParcelFile(); private: CiftiConnectivityMatrixDenseParcelFile(const CiftiConnectivityMatrixDenseParcelFile&); CiftiConnectivityMatrixDenseParcelFile& operator=(const CiftiConnectivityMatrixDenseParcelFile&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE }; #ifdef __CIFTI_CONNECTIVITY_MATRIX_DENSE_PARCEL_FILE_DECLARE__ // #endif // __CIFTI_CONNECTIVITY_MATRIX_DENSE_PARCEL_FILE_DECLARE__ } // namespace #endif //__CIFTI_CONNECTIVITY_MATRIX_DENSE_PARCEL_FILE_H__ connectome-workbench-1.4.2/src/Files/CiftiConnectivityMatrixParcelDenseFile.cxx000066400000000000000000000030661360521144700277450ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CIFTI_CONNECTIVITY_MATRIX_PARCEL_DENSE_FILE_DECLARE__ #include "CiftiConnectivityMatrixParcelDenseFile.h" #undef __CIFTI_CONNECTIVITY_MATRIX_PARCEL_DENSE_FILE_DECLARE__ using namespace caret; /** * \class caret::CiftiConnectivityMatrixParcelDenseFile * \brief Connectivity Parcel x Dense File * \ingroup Files * * Contains connectivity matrix that measures connectivity from parcels * to brainordinates. */ /** * Constructor. */ CiftiConnectivityMatrixParcelDenseFile::CiftiConnectivityMatrixParcelDenseFile() : CiftiMappableConnectivityMatrixDataFile(DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE) { } /** * Destructor. */ CiftiConnectivityMatrixParcelDenseFile::~CiftiConnectivityMatrixParcelDenseFile() { } connectome-workbench-1.4.2/src/Files/CiftiConnectivityMatrixParcelDenseFile.h000066400000000000000000000035061360521144700273710ustar00rootroot00000000000000#ifndef __CIFTI_CONNECTIVITY_MATRIX_PARCEL_DENSE_FILE_H__ #define __CIFTI_CONNECTIVITY_MATRIX_PARCEL_DENSE_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CiftiMappableConnectivityMatrixDataFile.h" namespace caret { class CiftiConnectivityMatrixParcelDenseFile : public CiftiMappableConnectivityMatrixDataFile { public: CiftiConnectivityMatrixParcelDenseFile(); virtual ~CiftiConnectivityMatrixParcelDenseFile(); private: CiftiConnectivityMatrixParcelDenseFile(const CiftiConnectivityMatrixParcelDenseFile&); CiftiConnectivityMatrixParcelDenseFile& operator=(const CiftiConnectivityMatrixParcelDenseFile&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE }; #ifdef __CIFTI_CONNECTIVITY_MATRIX_PARCEL_DENSE_FILE_DECLARE__ // #endif // __CIFTI_CONNECTIVITY_MATRIX_PARCEL_DENSE_FILE_DECLARE__ } // namespace #endif //__CIFTI_CONNECTIVITY_MATRIX_PARCEL_DENSE_FILE_H__ connectome-workbench-1.4.2/src/Files/CiftiConnectivityMatrixParcelFile.cxx000066400000000000000000000732111360521144700267650ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CIFTI_CONNECTIVITY_MATRIX_PARCEL_FILE_DECLARE__ #include "CiftiConnectivityMatrixParcelFile.h" #undef __CIFTI_CONNECTIVITY_MATRIX_PARCEL_FILE_DECLARE__ #include "CaretLogger.h" #include "ChartMatrixDisplayProperties.h" #include "CiftiFile.h" #include "CiftiParcelReordering.h" #include "CiftiParcelReorderingModel.h" #include "ConnectivityDataLoaded.h" #include "EventChartMatrixParcelYokingValidation.h" #include "EventManager.h" #include "FastStatistics.h" #include "NodeAndVoxelColoring.h" #include "Palette.h" #include "PaletteColorMapping.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::CiftiConnectivityMatrixParcelFile * \brief Connectivity Parcel x Parcel File * \ingroup Files * * Contains connectivity matrix that measures connectivity from parcels * to parcels. */ /** * Constructor. */ CiftiConnectivityMatrixParcelFile::CiftiConnectivityMatrixParcelFile() : CiftiMappableConnectivityMatrixDataFile(DataFileTypeEnum::CONNECTIVITY_PARCEL), ChartableMatrixParcelInterface() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = false; m_chartMatrixDisplayProperties[i] = new ChartMatrixDisplayProperties(); } m_selectedParcelColoringMode = CiftiParcelColoringModeEnum::CIFTI_PARCEL_COLORING_OUTLINE; m_selectedParcelColor = CaretColorEnum::WHITE; m_parcelReorderingModel = new CiftiParcelReorderingModel(this); m_chartLoadingYokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_selectedParcelColoringMode", &m_selectedParcelColoringMode); m_sceneAssistant->add("m_selectedParcelColor", &m_selectedParcelColor); m_sceneAssistant->add("m_parcelReorderingModel", "CiftiParcelReorderingModel", m_parcelReorderingModel); m_sceneAssistant->add("m_chartLoadingYokingGroup", &m_chartLoadingYokingGroup); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CHART_MATRIX_YOKING_VALIDATION); } /** * Destructor. */ CiftiConnectivityMatrixParcelFile::~CiftiConnectivityMatrixParcelFile() { EventManager::get()->removeAllEventsFromListener(this); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { delete m_chartMatrixDisplayProperties[i]; } delete m_parcelReorderingModel; delete m_sceneAssistant; } /** * Receive an event. * * @param event * The event that the receive can respond to. */ void CiftiConnectivityMatrixParcelFile::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_CHART_MATRIX_YOKING_VALIDATION) { EventChartMatrixParcelYokingValidation* yokeEvent = dynamic_cast(event); CaretAssert(yokeEvent); if (yokeEvent->getChartableMatrixParcelInterface() != this) { switch (yokeEvent->getMode()) { case EventChartMatrixParcelYokingValidation::MODE_APPLY_YOKING: { // YokingGroupEnum::Enum yokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; // int32_t rowOrColumnIndex = -1; // yokeEvent->getApplyYokingSelections(yokingGroup, // rowOrColumnIndex); // if ((yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) // && (rowOrColumnIndex >= 0)) { // int32_t numRows = -1; // int32_t numCols = -1; // getMatrixDimensions(numRows, // numCols); // switch (getMatrixLoadingDimension()) { // case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: // if (rowOrColumnIndex < numCols) { // loadDataForColumnIndex(rowOrColumnIndex); // } // else { // } // break; // case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: // if (rowOrColumnIndex < numRows) { // loadDataForRowIndex(rowOrColumnIndex); // } // break; // } // } } break; case EventChartMatrixParcelYokingValidation::MODE_VALIDATE_YOKING: { const ConnectivityDataLoaded* connData = getConnectivityDataLoaded(); int64_t rowIndex = -1; int64_t columnIndex = -1; connData->getRowColumnLoading(rowIndex, columnIndex); int64_t selectedRowColumnIndex = -1; if (rowIndex >= 0) { selectedRowColumnIndex = rowIndex; } else if (columnIndex >= 0) { selectedRowColumnIndex = columnIndex; } yokeEvent->addValidateYokingChartableInterface(this, selectedRowColumnIndex); } break; } } } CiftiMappableConnectivityMatrixDataFile::receiveEvent(event); } /** * Get the matrix dimensions. * * @param numberOfRowsOut * Number of rows in the matrix. * @param numberOfColumnsOut * Number of columns in the matrix. */ void CiftiConnectivityMatrixParcelFile::getMatrixDimensions(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) const { helpMapFileGetMatrixDimensions(numberOfRowsOut, numberOfColumnsOut); } /** * Get the matrix RGBA coloring for this matrix data creator. * * @param numberOfRowsOut * Number of rows in the coloring matrix. * @param numberOfColumnsOut * Number of rows in the coloring matrix. * @param rgbaOut * RGBA coloring output with number of elements * (numberOfRowsOut * numberOfColumnsOut * 4). * @return * True if data output data is valid, else false. */ bool CiftiConnectivityMatrixParcelFile::getMatrixDataRGBA(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut, std::vector& rgbaOut) const { CiftiParcelLabelFile* parcelLabelFile = NULL; int32_t parcelLabelFileMapIndex = -1; bool enabled = false; std::vector parcelLabelFiles; getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, parcelLabelFile, parcelLabelFileMapIndex, enabled); std::vector rowIndices; if (enabled) { const CiftiParcelReordering* parcelReordering = getParcelReordering(parcelLabelFile, parcelLabelFileMapIndex); if (parcelReordering != NULL) { rowIndices = parcelReordering->getReorderedParcelIndices(); } } return helpMatrixFileLoadChartDataMatrixRGBA(numberOfRowsOut, numberOfColumnsOut, rowIndices, rgbaOut); } /** * Get the value, row name, and column name for a cell in the matrix. * * @param rowIndex * The row index. * @param columnIndex * The column index. * @param cellValueOut * Output containing value in the cell. * @param rowNameOut * Name of row corresponding to row index. * @param columnNameOut * Name of column corresponding to column index. * @return * True if the output values are valid (valid row/column indices). */ bool CiftiConnectivityMatrixParcelFile::getMatrixCellAttributes(const int32_t rowIndex, const int32_t columnIndex, AString& cellValueOut, AString& rowNameOut, AString& columnNameOut) const { if ((rowIndex >= 0) && (rowIndex < m_ciftiFile->getNumberOfRows()) && (columnIndex >= 0) && (columnIndex < m_ciftiFile->getNumberOfColumns())) { const CiftiXML& xml = m_ciftiFile->getCiftiXML(); const std::vector& rowsParcelsMap = xml.getParcelsMap(CiftiXML::ALONG_COLUMN).getParcels(); CaretAssertVectorIndex(rowsParcelsMap, rowIndex); rowNameOut = rowsParcelsMap[rowIndex].m_name; const std::vector& columnsParcelsMap = xml.getParcelsMap(CiftiXML::ALONG_ROW).getParcels(); CaretAssertVectorIndex(columnsParcelsMap, columnIndex); columnNameOut = columnsParcelsMap[columnIndex].m_name; const int32_t numberOfElementsInRow = m_ciftiFile->getNumberOfColumns(); std::vector rowData(numberOfElementsInRow); m_ciftiFile->getRow(&rowData[0], rowIndex); CaretAssertVectorIndex(rowData, columnIndex); cellValueOut = AString::number(rowData[columnIndex], 'f', 6); return true; } return false; } /** * @return Is charting enabled for this file? */ bool CiftiConnectivityMatrixParcelFile::isMatrixChartingEnabled(const int32_t tabIndex) const { CaretAssertArrayIndex(m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_chartingEnabledForTab[tabIndex]; } /** * @return Return true if the file's current state supports * charting data, else false. Typically a brainordinate file * is chartable if it contains more than one map. */ bool CiftiConnectivityMatrixParcelFile::isMatrixChartingSupported() const { return true; } /** * Set charting enabled for this file. * * @param enabled * New status for charting enabled. */ void CiftiConnectivityMatrixParcelFile::setMatrixChartingEnabled(const int32_t tabIndex, const bool enabled) { CaretAssertArrayIndex(m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_chartingEnabledForTab[tabIndex] = enabled; } /** * Get chart data types supported by the file. * * @param chartDataTypesOut * Chart types supported by this file. */ void CiftiConnectivityMatrixParcelFile::getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const { chartDataTypesOut.clear(); chartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER); } /** * @return Chart matrix display properties (const method). */ const ChartMatrixDisplayProperties* CiftiConnectivityMatrixParcelFile::getChartMatrixDisplayProperties(const int32_t tabIndex) const { CaretAssertArrayIndex(m_chartMatrixDisplayProperties, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_chartMatrixDisplayProperties[tabIndex]; } /** * @return Chart matrix display properties. */ ChartMatrixDisplayProperties* CiftiConnectivityMatrixParcelFile::getChartMatrixDisplayProperties(const int32_t tabIndex) { CaretAssertArrayIndex(m_chartMatrixDisplayProperties, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_chartMatrixDisplayProperties[tabIndex]; } /** * Save subclass data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void CiftiConnectivityMatrixParcelFile::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); sceneClass->addBooleanArray("m_chartingEnabledForTab", m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); /* * Save chart matrix properties */ SceneObjectMapIntegerKey* chartMatrixPropertiesMap = new SceneObjectMapIntegerKey("m_chartMatrixDisplayPropertiesMap", SceneObjectDataTypeEnum::SCENE_CLASS); const std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); for (std::vector::const_iterator tabIter = tabIndices.begin(); tabIter != tabIndices.end(); tabIter++) { const int32_t tabIndex = *tabIter; chartMatrixPropertiesMap->addClass(tabIndex, m_chartMatrixDisplayProperties[tabIndex]->saveToScene(sceneAttributes, "m_chartMatrixDisplayProperties")); } sceneClass->addChild(chartMatrixPropertiesMap); } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void CiftiConnectivityMatrixParcelFile::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); // CiftiMappableConnectivityMatrixDataFile::restoreFileDataFromScene(sceneAttributes, // sceneClass); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = false; } const ScenePrimitiveArray* tabArray = sceneClass->getPrimitiveArray("m_chartingEnabledForTab"); if (tabArray != NULL) { sceneClass->getBooleanArrayValue("m_chartingEnabledForTab", m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); } else { /* * Obsolete value when charting was not 'per tab' */ const bool chartingEnabled = sceneClass->getBooleanValue("m_chartingEnabled", false); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = chartingEnabled; } } /* * Restore chart matrix properties */ const SceneObjectMapIntegerKey* chartMatrixPropertiesMap = sceneClass->getMapIntegerKey("m_chartMatrixDisplayPropertiesMap"); if (chartMatrixPropertiesMap != NULL) { const std::vector tabIndices = chartMatrixPropertiesMap->getKeys(); for (std::vector::const_iterator tabIter = tabIndices.begin(); tabIter != tabIndices.end(); tabIter++) { const int32_t tabIndex = *tabIter; const SceneClass* sceneClass = chartMatrixPropertiesMap->classValue(tabIndex); m_chartMatrixDisplayProperties[tabIndex]->restoreFromScene(sceneAttributes, sceneClass); } } } ///** // * Save file data from the scene. For subclasses that need to // * save to a scene, this method should be overriden. sceneClass // * will be valid and any scene data should be added to it. // * // * @param sceneAttributes // * Attributes for the scene. Scenes may be of different types // * (full, generic, etc) and the attributes should be checked when // * restoring the scene. // * // * @param sceneClass // * sceneClass to which data members should be added. // */ //void //CiftiConnectivityMatrixParcelFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) //{ // CiftiMappableConnectivityMatrixDataFile::saveFileDataToScene(sceneAttributes, // sceneClass); // // m_sceneAssistant->saveMembers(sceneAttributes, // sceneClass); // // sceneClass->addBooleanArray("m_chartingEnabledForTab", // m_chartingEnabledForTab, // BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); // // /* // * Save chart matrix properties // */ // SceneObjectMapIntegerKey* chartMatrixPropertiesMap = new SceneObjectMapIntegerKey("m_chartMatrixDisplayPropertiesMap", // SceneObjectDataTypeEnum::SCENE_CLASS); // const std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); // for (std::vector::const_iterator tabIter = tabIndices.begin(); // tabIter != tabIndices.end(); // tabIter++) { // const int32_t tabIndex = *tabIter; // // chartMatrixPropertiesMap->addClass(tabIndex, // m_chartMatrixDisplayProperties[tabIndex]->saveToScene(sceneAttributes, // "m_chartMatrixDisplayProperties")); // } // sceneClass->addChild(chartMatrixPropertiesMap); //} // ///** // * Restore file data from the scene. For subclasses that need to // * restore from a scene, this method should be overridden. The scene class // * will be valid and any scene data may be obtained from it. // * // * @param sceneAttributes // * Attributes for the scene. Scenes may be of different types // * (full, generic, etc) and the attributes should be checked when // * restoring the scene. // * // * @param sceneClass // * sceneClass for the instance of a class that implements // * this interface. Will NEVER be NULL. // */ //void //CiftiConnectivityMatrixParcelFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) //{ // CiftiMappableConnectivityMatrixDataFile::restoreFileDataFromScene(sceneAttributes, // sceneClass); // // m_sceneAssistant->restoreMembers(sceneAttributes, // sceneClass); // // /* // * The chart loading type is restored by the scene assistant. // * Swap its value so that calling setMatrixLoadingDimension requires // * the value to change for it to have any affect including // * setting size of data. // */ // switch (m_chartLoadingType) { // case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: // m_chartLoadingType = ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; // break; // case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: // m_chartLoadingType = ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN; // break; // } // setMatrixLoadingDimension(m_chartLoadingType); // //// CiftiMappableConnectivityMatrixDataFile::restoreFileDataFromScene(sceneAttributes, //// sceneClass); // // for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { // m_chartingEnabledForTab[i] = false; // } // // const ScenePrimitiveArray* tabArray = sceneClass->getPrimitiveArray("m_chartingEnabledForTab"); // if (tabArray != NULL) { // sceneClass->getBooleanArrayValue("m_chartingEnabledForTab", // m_chartingEnabledForTab, // BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); // } // else { // /* // * Obsolete value when charting was not 'per tab' // */ // const bool chartingEnabled = sceneClass->getBooleanValue("m_chartingEnabled", // false); // for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { // m_chartingEnabledForTab[i] = chartingEnabled; // } // } // // /* // * Restore chart matrix properties // */ // const SceneObjectMapIntegerKey* chartMatrixPropertiesMap = sceneClass->getMapIntegerKey("m_chartMatrixDisplayPropertiesMap"); // if (chartMatrixPropertiesMap != NULL) { // const std::vector tabIndices = chartMatrixPropertiesMap->getKeys(); // for (std::vector::const_iterator tabIter = tabIndices.begin(); // tabIter != tabIndices.end(); // tabIter++) { // const int32_t tabIndex = *tabIter; // const SceneClass* sceneClass = chartMatrixPropertiesMap->classValue(tabIndex); // m_chartMatrixDisplayProperties[tabIndex]->restoreFromScene(sceneAttributes, // sceneClass); // } // } // //} /** * @return Coloring mode for selected parcel. */ CiftiParcelColoringModeEnum::Enum CiftiConnectivityMatrixParcelFile::getSelectedParcelColoringMode() const { return m_selectedParcelColoringMode; } /** * Set the coloring mode for selected parcel. * * @param coloringMode * New value for coloring mode. */ void CiftiConnectivityMatrixParcelFile::setSelectedParcelColoringMode(const CiftiParcelColoringModeEnum::Enum coloringMode) { m_selectedParcelColoringMode = coloringMode; } /** * @return Color for selected parcel. */ CaretColorEnum::Enum CiftiConnectivityMatrixParcelFile::getSelectedParcelColor() const { return m_selectedParcelColor; } /** * Set color for selected parcel. * * @param color * New color for selected parcel. */ void CiftiConnectivityMatrixParcelFile::setSelectedParcelColor(const CaretColorEnum::Enum color) { m_selectedParcelColor = color; } /** * Get the selected parcel label file used for reordering of parcels. * * @param compatibleParcelLabelFilesOut * All Parcel Label files that are compatible with file implementing * this interface * @param selectedParcelLabelFileOut * The selected parcel label file used for reordering the parcels. * May be NULL! * @param selectedParcelLabelFileMapIndexOut * Map index in the selected parcel label file. * @param enabledStatusOut * Enabled status of reordering. */ void CiftiConnectivityMatrixParcelFile::getSelectedParcelLabelFileAndMapForReordering(std::vector& compatibleParcelLabelFilesOut, CiftiParcelLabelFile* &selectedParcelLabelFileOut, int32_t& selectedParcelLabelFileMapIndexOut, bool& enabledStatusOut) const { m_parcelReorderingModel->getSelectedParcelLabelFileAndMapForReordering(compatibleParcelLabelFilesOut, selectedParcelLabelFileOut, selectedParcelLabelFileMapIndexOut, enabledStatusOut); } /** * Set the selected parcel label file used for reordering of parcels. * * @param selectedParcelLabelFile * The selected parcel label file used for reordering the parcels. * May be NULL! * @param selectedParcelLabelFileMapIndex * Map index in the selected parcel label file. * @param enabledStatus * Enabled status of reordering. */ void CiftiConnectivityMatrixParcelFile::setSelectedParcelLabelFileAndMapForReordering(CiftiParcelLabelFile* selectedParcelLabelFile, const int32_t selectedParcelLabelFileMapIndex, const bool enabledStatus) { m_parcelReorderingModel->setSelectedParcelLabelFileAndMapForReordering(selectedParcelLabelFile, selectedParcelLabelFileMapIndex, enabledStatus); } /** * Get the parcel reordering for the given map index that was created using * the given parcel label file and its map index. * * @param parcelLabelFile * The selected parcel label file used for reordering the parcels. * @param parcelLabelFileMapIndex * Map index in the selected parcel label file. * @return * Pointer to parcel reordering or NULL if not found. */ const CiftiParcelReordering* CiftiConnectivityMatrixParcelFile::getParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex) const { return m_parcelReorderingModel->getParcelReordering(parcelLabelFile, parcelLabelFileMapIndex); } /** * Create the parcel reordering for the given map index using * the given parcel label file and its map index. * * @param parcelLabelFile * The selected parcel label file used for reordering the parcels. * @param parcelLabelFileMapIndex * Map index in the selected parcel label file. * @param ciftiParcelsMap * The CIFTI parcels map that will or has been reordered. * @param errorMessageOut * Error message output. Will only be non-empty if NULL is returned. * @return * Pointer to parcel reordering or NULL if not found. */ bool CiftiConnectivityMatrixParcelFile::createParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex, AString& errorMessageOut) { return m_parcelReorderingModel->createParcelReordering(parcelLabelFile, parcelLabelFileMapIndex, errorMessageOut); } /** * @return True if loading attributes (column/row, yoking) are * supported by this file type. */ bool CiftiConnectivityMatrixParcelFile::isSupportsLoadingAttributes() { return true; } /** * @return The matrix loading type (by row/column). */ ChartMatrixLoadingDimensionEnum::Enum CiftiConnectivityMatrixParcelFile::getMatrixLoadingDimension() const { return getChartMatrixLoadingDimension(); } /** * Set the matrix loading type (by row/column). * * @param matrixLoadingType * New value for matrix loading type. */ void CiftiConnectivityMatrixParcelFile::setMatrixLoadingDimension(const ChartMatrixLoadingDimensionEnum::Enum matrixLoadingType) { /* * Ignore when the loading dimension does not change */ if (matrixLoadingType != getMatrixLoadingDimension()) { setChartMatrixLoadingDimension(matrixLoadingType); } } /** * @return Selected yoking group. */ YokingGroupEnum::Enum CiftiConnectivityMatrixParcelFile::getYokingGroup() const { return m_chartLoadingYokingGroup; } /** * Set the selected yoking group. * * @param yokingGroup * New value for yoking group. */ void CiftiConnectivityMatrixParcelFile::setYokingGroup(const YokingGroupEnum::Enum yokingGroup) { m_chartLoadingYokingGroup = yokingGroup; if (m_chartLoadingYokingGroup == YokingGroupEnum::YOKING_GROUP_OFF) { return; } /* * Updated selected row/column to match yoking. */ } connectome-workbench-1.4.2/src/Files/CiftiConnectivityMatrixParcelFile.h000066400000000000000000000151471360521144700264160ustar00rootroot00000000000000#ifndef __CIFTI_CONNECTIVITY_MATRIX_PARCEL_FILE_H__ #define __CIFTI_CONNECTIVITY_MATRIX_PARCEL_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "ChartableMatrixParcelInterface.h" namespace caret { class ChartMatrixDisplayProperties; class CiftiParcelReorderingModel; class CiftiConnectivityMatrixParcelFile : public CiftiMappableConnectivityMatrixDataFile, public ChartableMatrixParcelInterface { public: CiftiConnectivityMatrixParcelFile(); virtual ~CiftiConnectivityMatrixParcelFile(); private: CiftiConnectivityMatrixParcelFile(const CiftiConnectivityMatrixParcelFile&); CiftiConnectivityMatrixParcelFile& operator=(const CiftiConnectivityMatrixParcelFile&); public: virtual void receiveEvent(Event* event); virtual void getMatrixDimensions(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) const; virtual bool getMatrixDataRGBA(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut, std::vector& rgbaOut) const; virtual bool getMatrixCellAttributes(const int32_t rowIndex, const int32_t columnIndex, AString& cellValueOut, AString& rowNameOut, AString& columnNameOut) const; virtual bool isMatrixChartingEnabled(const int32_t tabIndex) const; virtual bool isMatrixChartingSupported() const; virtual void setMatrixChartingEnabled(const int32_t tabIndex, const bool enabled); virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const; const ChartMatrixDisplayProperties* getChartMatrixDisplayProperties(const int32_t tabIndex) const; ChartMatrixDisplayProperties* getChartMatrixDisplayProperties(const int32_t tabIndex); virtual CiftiParcelColoringModeEnum::Enum getSelectedParcelColoringMode() const; virtual void setSelectedParcelColoringMode(const CiftiParcelColoringModeEnum::Enum coloringMode); virtual CaretColorEnum::Enum getSelectedParcelColor() const; virtual void setSelectedParcelColor(const CaretColorEnum::Enum color); virtual void getSelectedParcelLabelFileAndMapForReordering(std::vector& compatibleParcelLabelFilesOut, CiftiParcelLabelFile* &selectedParcelLabelFileOut, int32_t& selectedParcelLabelFileMapIndexOut, bool& enabledStatusOut) const; virtual void setSelectedParcelLabelFileAndMapForReordering(CiftiParcelLabelFile* selectedParcelLabelFile, const int32_t selectedParcelLabelFileMapIndex, const bool enabledStatus); virtual bool createParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex, AString& errorMessageOut); virtual const CiftiParcelReordering* getParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex) const; virtual bool isSupportsLoadingAttributes(); virtual ChartMatrixLoadingDimensionEnum::Enum getMatrixLoadingDimension() const; virtual void setMatrixLoadingDimension(const ChartMatrixLoadingDimensionEnum::Enum matrixLoadingType); virtual YokingGroupEnum::Enum getYokingGroup() const; virtual void setYokingGroup(const YokingGroupEnum::Enum yokingType); public: // ADD_NEW_METHODS_HERE protected: virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass); // // virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass); private: // ADD_NEW_MEMBERS_HERE SceneClassAssistant* m_sceneAssistant; bool m_chartingEnabledForTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; ChartMatrixDisplayProperties* m_chartMatrixDisplayProperties[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; CiftiParcelColoringModeEnum::Enum m_selectedParcelColoringMode; CaretColorEnum::Enum m_selectedParcelColor; CiftiParcelReorderingModel* m_parcelReorderingModel; YokingGroupEnum::Enum m_chartLoadingYokingGroup; }; #ifdef __CIFTI_CONNECTIVITY_MATRIX_PARCEL_FILE_DECLARE__ // #endif // __CIFTI_CONNECTIVITY_MATRIX_PARCEL_FILE_DECLARE__ } // namespace #endif //__CIFTI_CONNECTIVITY_MATRIX_PARCEL_FILE_H__ connectome-workbench-1.4.2/src/Files/CiftiFiberOrientationFile.cxx000066400000000000000000000403741360521144700252420ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CIFTI_FIBER_ORIENTATION_FILE_DECLARE__ #include "CiftiFiberOrientationFile.h" #undef __CIFTI_FIBER_ORIENTATION_FILE_DECLARE__ #include "CaretAssert.h" #include "CiftiFile.h" #include "CiftiMappableDataFile.h" #include "CaretLogger.h" #include "DataFileException.h" #include "Fiber.h" #include "FiberOrientation.h" #include "GiftiMetaData.h" #include "MathFunctions.h" #include using namespace caret; /** * \class caret::CiftiFiberOrientationFile * \brief Data file for Fiber Orientations * */ /** * Constructor. */ CiftiFiberOrientationFile::CiftiFiberOrientationFile() : CaretDataFile(DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY) { m_metadata = new GiftiMetaData(); m_ciftiXML = NULL; for (int32_t i = 0; i < DisplayGroupEnum::NUMBER_OF_GROUPS; i++) { m_displayStatusInDisplayGroup[i] = true; } for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_displayStatusInTab[i] = true; } } /** * Destructor. */ CiftiFiberOrientationFile::~CiftiFiberOrientationFile() { clearPrivate(); delete m_metadata; } /** * Cleare data in this file. */ void CiftiFiberOrientationFile::clear() { CaretDataFile::clear(); clearPrivate(); } /** * Cleare data in this file but not the parent class. */ void CiftiFiberOrientationFile::clearPrivate() { m_metadata->clear(); if (m_ciftiXML != NULL) { delete m_ciftiXML; m_ciftiXML = NULL; } for (std::vector::iterator iter = m_fiberOrientations.begin(); iter != m_fiberOrientations.end(); iter++) { delete *iter; } m_fiberOrientations.clear(); } /** * @return True if the file is empty. */ bool CiftiFiberOrientationFile::isEmpty() const { return true; } /** * @return The structure for this file. */ StructureEnum::Enum CiftiFiberOrientationFile::getStructure() const { return StructureEnum::ALL; } /** * Set the structure for this file. * @param structure * New structure for this file. */ void CiftiFiberOrientationFile::setStructure(const StructureEnum::Enum /*structure*/) { /* nothing */ } /** * @return Get access to the file's metadata. */ GiftiMetaData* CiftiFiberOrientationFile::getFileMetaData() { return m_metadata; } /** * @return Get access to unmodifiable file's metadata. */ const GiftiMetaData* CiftiFiberOrientationFile::getFileMetaData() const { return m_metadata; } /** * Initialize with test data. */ void CiftiFiberOrientationFile::initializeWithTestData() { const int64_t fiberDataSizeInFloats = (Fiber::NUMBER_OF_ELEMENTS_PER_FIBER_IN_FILE * 3) + 3; { float* fiberData = new float[fiberDataSizeInFloats]; int64_t offset = 0; /* * Coordinate of fiber orientation */ fiberData[offset+0] = 12.8; fiberData[offset+1] = 125.8; fiberData[offset+2] = 2.4; offset += 3; /* * Along Positive X-Axis */ fiberData[offset+0] = 0.3; // meanF fiberData[offset+1] = 2.0; // varF fiberData[offset+2] = MathFunctions::toRadians(90.0); // theta fiberData[offset+3] = 0.0; // phi fiberData[offset+4] = MathFunctions::toRadians(50.0); // k1 fiberData[offset+5] = MathFunctions::toRadians(10.0); // k2 fiberData[offset+6] = 0.0; // psi offset += 7; /* * Along Positive Y-Axis */ fiberData[offset+0] = 0.6; // meanF fiberData[offset+1] = 2.0; // varF fiberData[offset+2] = MathFunctions::toRadians(90.0); // theta fiberData[offset+3] = MathFunctions::toRadians(90.0); // phi fiberData[offset+4] = MathFunctions::toRadians(50.0); // k1 fiberData[offset+5] = MathFunctions::toRadians(10.0); // k2 fiberData[offset+6] = MathFunctions::toRadians(20.0); // psi offset += 7; /* * Along Positive Z-Axis */ fiberData[offset+0] = 1.0; // meanF fiberData[offset+1] = 2.0; // varF fiberData[offset+2] = 0.0; // theta fiberData[offset+3] = 0.0; // phi fiberData[offset+4] = MathFunctions::toRadians(20.0); // k1 fiberData[offset+5] = MathFunctions::toRadians(10.0); // k2 fiberData[offset+6] = MathFunctions::toRadians(70.0); // psi offset += 7; FiberOrientation* fiberOrientation = new FiberOrientation(3, fiberData); m_fiberOrientations.push_back(fiberOrientation); } { float* fiberData = new float[fiberDataSizeInFloats]; int64_t offset = 0; /* * Coordinate of fiber orientation */ fiberData[offset+0] = -60.8; fiberData[offset+1] = -55.8; fiberData[offset+2] = -2.4; offset += 3; /* * Pointing towards forward right and up */ fiberData[offset+0] = 0.3; // meanF fiberData[offset+1] = 2.0; // varF fiberData[offset+2] = MathFunctions::toRadians(45.0); // theta fiberData[offset+3] = MathFunctions::toRadians(45.0); // phi fiberData[offset+4] = MathFunctions::toRadians(40.0); // k1 fiberData[offset+5] = MathFunctions::toRadians(10.0); // k2 fiberData[offset+6] = 0.0; // psi offset += 7; /* * Pointing towards forward left and down */ fiberData[offset+0] = 0.6; // meanF fiberData[offset+1] = 2.0; // varF fiberData[offset+2] = MathFunctions::toRadians(45.0); // theta fiberData[offset+3] = MathFunctions::toRadians(135.0); // phi fiberData[offset+4] = MathFunctions::toRadians(20.0); // k1 fiberData[offset+5] = MathFunctions::toRadians(15.0); // k2 fiberData[offset+6] = 0.0; // psi offset += 7; /* * Pointing towards backward right and up */ fiberData[offset+0] = 1.0; // meanF fiberData[offset+1] = 2.0; // varF fiberData[offset+2] = MathFunctions::toRadians( 45.0); // theta fiberData[offset+3] = MathFunctions::toRadians(-45.0); // phi fiberData[offset+4] = MathFunctions::toRadians(40.0); // k1 fiberData[offset+5] = MathFunctions::toRadians(20.0); // k2 fiberData[offset+6] = MathFunctions::toRadians(25.0); // psi offset += 7; FiberOrientation* fiberOrientation = new FiberOrientation(3, fiberData); m_fiberOrientations.push_back(fiberOrientation); } } /** * @return The number of orientation fiber groups. */ int64_t CiftiFiberOrientationFile::getNumberOfFiberOrientations() const { return m_fiberOrientations.size(); } /** * Get the orientation fiber group at the given index. * @param indx * Index of the desired fiber orientation group. */ FiberOrientation* CiftiFiberOrientationFile::getFiberOrientations(const int64_t indx) { return m_fiberOrientations[indx]; } /** * Get Fiber orientation nearest coordinate and within the maximum * distance. * * @param xyz * The coordinate. * @param maximumDistance * The maximum distance. If negative, any distance is allowed. * * @return Fiber found or NULL if not found. */ FiberOrientation* CiftiFiberOrientationFile::getFiberOrientationNearestCoordinate(const float xyz[3], const float maximumDistance) const { FiberOrientation* nearestFiberOrientation = NULL; float nearestDistance = std::numeric_limits::max(); const int64_t numFiberOrientations = getNumberOfFiberOrientations(); for (int64_t i = 0; i < numFiberOrientations; i++) { const float distance = MathFunctions::distanceSquared3D(xyz, m_fiberOrientations[i]->m_xyz); if (distance < nearestDistance) { if (maximumDistance > 0.0) { if (distance > maximumDistance) { continue; } } nearestDistance = distance; nearestFiberOrientation = m_fiberOrientations[i]; } } return nearestFiberOrientation; } /** * Get the orientation fiber group at the given index. * @param indx * Index of the desired fiber orientation group. */ const FiberOrientation* CiftiFiberOrientationFile::getFiberOrientations(const int64_t indx) const { return m_fiberOrientations[indx]; } /** * @return The display status. */ bool CiftiFiberOrientationFile::isDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { const int32_t displayIndex = (int32_t)displayGroup; CaretAssertArrayIndex(m_displayStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, displayIndex); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_displayStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_displayStatusInTab[tabIndex]; } return m_displayStatusInDisplayGroup[displayIndex]; } /** * Set the display status. * @param displayed * New display status. */ void CiftiFiberOrientationFile::setDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool displayed) { const int32_t displayIndex = (int32_t)displayGroup; CaretAssertArrayIndex(m_displayStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, displayIndex); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_displayStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_displayStatusInTab[tabIndex] = displayed; } else { m_displayStatusInDisplayGroup[displayIndex] = displayed; } } /** * Get the volume spacing. * @param volumeSpacingOut * Will contain volume spacing for (I, J, K) axes upon exit. */ void CiftiFiberOrientationFile::getVolumeSpacing(float volumeSpacingOut[3]) const { volumeSpacingOut[0] = m_volumeSpacing[0]; volumeSpacingOut[1] = m_volumeSpacing[1]; volumeSpacingOut[2] = m_volumeSpacing[2]; } /** * @return a pointer to the CIFTI XML. * May be NULL if a file is not loaded. */ const CiftiXML* CiftiFiberOrientationFile::getCiftiXML() const { return m_ciftiXML; } /** * Read the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully read. */ void CiftiFiberOrientationFile::readFile(const AString& filename) { clear(); checkFileReadability(filename); try { CiftiFile ciftiFile; ciftiFile.openFile(filename); ciftiFile.convertToInMemory(); const int64_t numRows = ciftiFile.getNumberOfRows(); if (numRows <= 0) { throw DataFileException(getFileNameNoPath() + " does not contain any data (no rows)"); } const int64_t numCols = ciftiFile.getNumberOfColumns(); if (numCols <= 0) { throw DataFileException(getFileNameNoPath() + " does not contain any data (no columns)"); } /* * Each set of fibers contains XYZ (3 elements) * plus number of elements per fiber. */ const int64_t numberOfFibers = ((numCols - FiberOrientation::NUMBER_OF_ELEMENTS_IN_FILE) / Fiber::NUMBER_OF_ELEMENTS_PER_FIBER_IN_FILE); const int64_t expectedNumberOfColumns = (numberOfFibers * Fiber::NUMBER_OF_ELEMENTS_PER_FIBER_IN_FILE) + FiberOrientation::NUMBER_OF_ELEMENTS_IN_FILE; if (expectedNumberOfColumns != numCols) { throw DataFileException(filename, "Validation of column count failed: expected " + AString::number(expectedNumberOfColumns) + " but have " + AString::number(numCols) + " columns."); } /* * Create the fiber groups */ std::vector rowData(numCols); float* rowPointer = &rowData[0]; m_fiberOrientations.reserve(numRows); for (int64_t i = 0; i < numRows; i++) { ciftiFile.getRow(rowPointer, i); FiberOrientation* fiberOrient = new FiberOrientation(numberOfFibers, rowPointer); if (fiberOrient->m_valid) { m_fiberOrientations.push_back(fiberOrient); } else { CaretLogSevere("Fiber invalid at row " + QString::number(i) + " is invalid: " + fiberOrient->m_invalidMessage); delete fiberOrient; } } const CiftiXML& ciftiXML = ciftiFile.getCiftiXML(); m_ciftiXML = new CiftiXML(ciftiXML); VolumeSpace::OrientTypes orient[3]; float origin[3]; if (ciftiXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) throw DataFileException(getFileNameNoPath() + " does not have brain models along column"); const CiftiBrainModelsMap& myMap = ciftiXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); if (!myMap.hasVolumeData()) throw DataFileException(getFileNameNoPath() + " has no volume data, cannot be a fiber orientation file"); myMap.getVolumeSpace().getOrientAndSpacingForPlumb(orient, m_volumeSpacing, origin);//NOTE: will assert/throw if not plumb setFileName(filename); clearModified(); } catch (const DataFileException& dfe) { clear(); throw dfe; } } /** * Add information about the file to the data file information. * * @param dataFileInformation * Consolidates information about a data file. */ void CiftiFiberOrientationFile::addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) { CaretDataFile::addToDataFileContentInformation(dataFileInformation); if (m_ciftiXML != NULL) { CiftiMappableDataFile::addCiftiXmlToDataFileContentInformation(dataFileInformation, *m_ciftiXML); } } /** * Write the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully written. */ void CiftiFiberOrientationFile::writeFile(const AString& filename) { throw DataFileException(filename, "Writing of Cifti Orientation Files not supported."); } /** * @return True if this file type supports writing, else false. * * Fiber orientation files do NOT support writing. */ bool CiftiFiberOrientationFile::supportsWriting() const { return false; } connectome-workbench-1.4.2/src/Files/CiftiFiberOrientationFile.h000066400000000000000000000073051360521144700246640ustar00rootroot00000000000000#ifndef __CIFTI_FIBER_ORIENTATION_FILE_H__ #define __CIFTI_FIBER_ORIENTATION_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "CaretDataFile.h" #include "DisplayGroupEnum.h" namespace caret { class CiftiXML; class FiberOrientation; class CiftiFiberOrientationFile : public CaretDataFile { public: CiftiFiberOrientationFile(); virtual ~CiftiFiberOrientationFile(); void initializeWithTestData(); int64_t getNumberOfFiberOrientations() const; FiberOrientation* getFiberOrientations(const int64_t indx); const FiberOrientation* getFiberOrientations(const int64_t indx) const; FiberOrientation* getFiberOrientationNearestCoordinate(const float xyz[3], const float maximumDistance) const; void getVolumeSpacing(float volumeSpacingOut[3]) const; void setDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool displayed); bool isDisplayed(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; virtual void clear(); bool isEmpty() const; const CiftiXML* getCiftiXML() const; virtual StructureEnum::Enum getStructure() const; virtual void setStructure(const StructureEnum::Enum structure); virtual GiftiMetaData* getFileMetaData(); virtual const GiftiMetaData* getFileMetaData() const; virtual void readFile(const AString& filename); virtual void writeFile(const AString& filename); bool supportsWriting() const; void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation); // ADD_NEW_METHODS_HERE private: CiftiFiberOrientationFile(const CiftiFiberOrientationFile&); CiftiFiberOrientationFile& operator=(const CiftiFiberOrientationFile&); private: void clearPrivate(); CiftiXML* m_ciftiXML; GiftiMetaData* m_metadata; std::vector m_fiberOrientations; /** Display status in display group */ bool m_displayStatusInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; /** Display status in tab */ bool m_displayStatusInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; float m_volumeSpacing[3]; // ADD_NEW_MEMBERS_HERE }; #ifdef __CIFTI_FIBER_ORIENTATION_FILE_DECLARE__ // #endif // __CIFTI_FIBER_ORIENTATION_FILE_DECLARE__ } // namespace #endif //__CIFTI_FIBER_ORIENTATION_FILE_H__ connectome-workbench-1.4.2/src/Files/CiftiFiberTrajectoryFile.cxx000066400000000000000000001754411360521144700251010ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #define __CIFTI_FIBER_TRAJECTORY_FILE_DECLARE__ #include "CiftiFiberTrajectoryFile.h" #undef __CIFTI_FIBER_TRAJECTORY_FILE_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretSparseFile.h" #include "CiftiFiberOrientationFile.h" #include "CiftiMappableDataFile.h" #include "ConnectivityDataLoaded.h" #include "DataFileContentInformation.h" #include "EventManager.h" #include "EventProgressUpdate.h" #include "FiberOrientationTrajectory.h" #include "FiberTrajectoryMapProperties.h" #include "FileInformation.h" #include "GiftiMetaData.h" #include "PaletteColorMapping.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::CiftiFiberTrajectoryFile * \brief File that contains trajectories */ /** * Constructor. */ CiftiFiberTrajectoryFile::CiftiFiberTrajectoryFile() : CaretMappableDataFile(DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY) { m_connectivityDataLoaded = new ConnectivityDataLoaded(); m_fiberTrajectoryMapProperties = new FiberTrajectoryMapProperties(); m_metadata = new GiftiMetaData(); m_sparseFile = NULL; m_matchingFiberOrientationFile = NULL; m_matchingFiberOrientationFileName = ""; m_dataLoadingEnabled = true; m_fiberTrajectoryFileType = FIBER_TRAJECTORY_LOAD_BY_BRAINORDINATE; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_dataLoadingEnabled", &m_dataLoadingEnabled); m_sceneAssistant->add("m_matchingFiberOrientationFileName", &m_matchingFiberOrientationFileName); m_sceneAssistant->add("m_fiberTrajectoryMapProperties", "FiberTrajectoryMapProperties", m_fiberTrajectoryMapProperties); m_sceneAssistant->add("m_connectivityDataLoaded", "ConnectivityDataLoaded", m_connectivityDataLoaded); } /** * Destructor. */ CiftiFiberTrajectoryFile::~CiftiFiberTrajectoryFile() { clearPrivate(); delete m_fiberTrajectoryMapProperties; delete m_metadata; // DO NOT DELETE (owned by Brain): m_matchingFiberOrientationFile. delete m_sceneAssistant; delete m_connectivityDataLoaded; } /** * Cleare data in this file. */ void CiftiFiberTrajectoryFile::clear() { CaretMappableDataFile::clear(); clearPrivate(); } /** * Cleare data in this file but not the parent class. */ void CiftiFiberTrajectoryFile::clearPrivate() { m_metadata->clear(); clearLoadedFiberOrientations(); if (m_sparseFile != NULL) { delete m_sparseFile; m_sparseFile = NULL; } m_matchingFiberOrientationFile = NULL; m_matchingFiberOrientationFileName = ""; m_fiberTrajectoryFileType = FIBER_TRAJECTORY_LOAD_BY_BRAINORDINATE; } /** * @return True if the file is empty. */ bool CiftiFiberTrajectoryFile::isEmpty() const { if (m_sparseFile != NULL) { return false; } return true; } /** * @return Is data loading enabled? */ bool CiftiFiberTrajectoryFile::isDataLoadingEnabled() const { return m_dataLoadingEnabled; } /** * Set data loading enabled. * * @param loadingEnabled * New status of data loading. */ void CiftiFiberTrajectoryFile::setDataLoadingEnabled(const bool loadingEnabled) { m_dataLoadingEnabled = loadingEnabled; } /** * @return The selected matching fiber orientation file. May be NULL. */ const CiftiFiberOrientationFile* CiftiFiberTrajectoryFile::getMatchingFiberOrientationFile() const { return m_matchingFiberOrientationFile; } /** * @return The selected matching fiber orientation file. May be NULL. */ CiftiFiberOrientationFile* CiftiFiberTrajectoryFile::getMatchingFiberOrientationFile() { return m_matchingFiberOrientationFile; } /** * Is the given fiber orientation file compatible with this fiber trajectory file * * @param fiberOrientationFile * File tested for compatibilty * @return * True if file is compatible, else false. */ bool CiftiFiberTrajectoryFile::isFiberOrientationFileCombatible(const CiftiFiberOrientationFile* fiberOrientationFile) const { CaretAssert(fiberOrientationFile); const CiftiXML& trajXML = m_sparseFile->getCiftiXML(); const CiftiXML* orientXML = fiberOrientationFile->getCiftiXML(); if (*(trajXML.getMap(CiftiXML::ALONG_ROW)) == *(orientXML->getMap(CiftiXML::ALONG_COLUMN))) { return true; } return false; } /** * Set the selected matching fiber orientation file. No test of compatibility * is made. If this is a "single row" trajectory file, the data for the single * row is loaded. * * @param matchingFiberOrientationFile * New selection for matching fiber orientation file. */ void CiftiFiberTrajectoryFile::setMatchingFiberOrientationFile(CiftiFiberOrientationFile* matchingFiberOrientationFile) { m_matchingFiberOrientationFile = matchingFiberOrientationFile; if (m_matchingFiberOrientationFile != NULL) { // m_matchingFiberOrientationFileName = m_matchingFiberOrientationFile->getFileNameNoPath(); m_matchingFiberOrientationFileName = m_matchingFiberOrientationFile->getFileName(); switch (m_fiberTrajectoryFileType) { case FIBER_TRAJECTORY_LOAD_BY_BRAINORDINATE: break; case FIBER_TRAJECTORY_LOAD_SINGLE_ROW: loadDataForRowIndex(0); const CiftiXML& sparseXML = m_sparseFile->getCiftiXML(); if (sparseXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::SCALARS) { m_loadedDataDescriptionForMapName = sparseXML.getScalarsMap(CiftiXML::ALONG_COLUMN).getMapName(0); } else { m_loadedDataDescriptionForMapName = ""; } break; } } else { m_matchingFiberOrientationFileName = ""; } } /** * Update the matching fiber orientation file from the first compatible file in the list. * If none are found, the matching file will become NULL. If the current matching file * is valid, no action is taken. * * @param matchingFiberOrientationFiles * The fiber orientation files. */ void CiftiFiberTrajectoryFile::updateMatchingFiberOrientationFileFromList(std::vector matchingFiberOrientationFiles) { /* * If a scene has been restored, we want to match to the fiber orientation * file name that was restored from the scene */ if (m_matchingFiberOrientationFileNameFromRestoredScene.isEmpty() == false) { bool matched = false; CiftiFiberOrientationFile* matchedOrientFile = NULL; int64_t matchedOrientFileCount = 0; const FileInformation fileInfo(m_matchingFiberOrientationFileNameFromRestoredScene); const AString matchingFileNameNoPath = fileInfo.getFileName(); for (std::vector::iterator iter = matchingFiberOrientationFiles.begin(); iter != matchingFiberOrientationFiles.end(); iter++) { /* * Try and see if it matches for this file * (1) Verify compatibility * (2) Match name of file without path * (3) Match path starting at end of path */ CiftiFiberOrientationFile* orientationFile = *iter; CaretAssert(orientationFile); if (isFiberOrientationFileCombatible(orientationFile)) { if (matchingFileNameNoPath == orientationFile->getFileNameNoPath()) { const AString orientationFileName = orientationFile->getFileName(); const int64_t endMatchCount = orientationFileName.countMatchingCharactersFromEnd(m_matchingFiberOrientationFileNameFromRestoredScene); if (endMatchCount > matchedOrientFileCount) { matchedOrientFile = orientationFile; matchedOrientFileCount = endMatchCount; } } } // if (orientationFile->getFileNameNoPath() == m_matchingFiberOrientationFileNameFromRestoredScene) { // if (isFiberOrientationFileCombatible(orientationFile)) { // setMatchingFiberOrientationFile(orientationFile); // matched = true; // } // } } if (matchedOrientFileCount > 0) { setMatchingFiberOrientationFile(matchedOrientFile); } /* * Clear name so no attempt to use again */ m_matchingFiberOrientationFileNameFromRestoredScene = ""; if (matched) { return; } } /* * See if selected orientation file is still valid */ for (std::vector::iterator iter = matchingFiberOrientationFiles.begin(); iter != matchingFiberOrientationFiles.end(); iter++) { if (*iter == m_matchingFiberOrientationFile) { return; } } /* * Invalidate matching file */ m_matchingFiberOrientationFile = NULL; m_matchingFiberOrientationFileName = ""; clearLoadedFiberOrientations(); /* * Try to find a matching file */ for (std::vector::iterator iter = matchingFiberOrientationFiles.begin(); iter != matchingFiberOrientationFiles.end(); iter++) { /* * Try and see if it matches for this file */ if (isFiberOrientationFileCombatible(*iter)) { setMatchingFiberOrientationFile(*iter); return; } } } /** * @return The structure for this file. */ StructureEnum::Enum CiftiFiberTrajectoryFile::getStructure() const { return StructureEnum::ALL; } /** * Set the structure for this file. * @param structure * New structure for this file. */ void CiftiFiberTrajectoryFile::setStructure(const StructureEnum::Enum /*structure*/) { /* nothing */ } /** * @return Get access to the file's metadata. */ GiftiMetaData* CiftiFiberTrajectoryFile::getFileMetaData() { return m_metadata; } /** * @return Get access to unmodifiable file's metadata. */ const GiftiMetaData* CiftiFiberTrajectoryFile::getFileMetaData() const { return m_metadata; } /** * @return Is the data mappable to a surface? */ bool CiftiFiberTrajectoryFile::isSurfaceMappable() const { return false; } /** * @return Is the data mappable to a volume? */ bool CiftiFiberTrajectoryFile::isVolumeMappable() const { return true; } /** * @return The number of maps in the file. * Note: Caret5 used the term 'columns'. */ int32_t CiftiFiberTrajectoryFile::getNumberOfMaps() const { /* * Always return 1. * If zero is returned, it will never appear in the overlays because * zero is interpreted as "nothing available". */ return 1; } /** * @return True if the file has map attributes (name and metadata). * For files that do not have map attributes, they should override * this method and return false. If not overriden, this method * returns true. * * Some files (such as CIFTI Connectivity Matrix Files and CIFTI * Data-Series Files) do not have Map Attributes and thus there * is no map name nor map metadata and options to edit these * attributes should not be presented to the user. * * These CIFTI files do contain palette color mapping but it is * associated with the file. To simplify palette color mapping editing * these file will return the file's palette color mapping for any * calls to getMapPaletteColorMapping(). */ bool CiftiFiberTrajectoryFile::hasMapAttributes() const { return false; } /** * Get the name of the map at the given index. * * @param mapIndex * Index of the map. * @return * Name of the map. */ AString CiftiFiberTrajectoryFile::getMapName(const int32_t /*mapIndex*/) const { return m_loadedDataDescriptionForMapName; } /** * Set the name of the map at the given index. * * @param mapIndex * Index of the map. * @param mapName * New name for the map. */ void CiftiFiberTrajectoryFile::setMapName(const int32_t /*mapIndex*/, const AString& /*mapName*/) { } /** * Get the metadata for the map at the given index * * @param mapIndex * Index of the map. * @return * Metadata for the map (const value). */ const GiftiMetaData* CiftiFiberTrajectoryFile::getMapMetaData(const int32_t /*mapIndex*/) const { return getFileMetaData(); } /** * Get the metadata for the map at the given index * * @param mapIndex * Index of the map. * @return * Metadata for the map. */ GiftiMetaData* CiftiFiberTrajectoryFile::getMapMetaData(const int32_t /*mapIndex*/) { return getFileMetaData(); } /** * Get the unique ID (UUID) for the map at the given index. * * @param mapIndex * Index of the map. * @return * String containing UUID for the map. */ AString CiftiFiberTrajectoryFile::getMapUniqueID(const int32_t mapIndex) const { const GiftiMetaData* md = getMapMetaData(mapIndex); const AString uniqueID = md->getUniqueID(); return uniqueID; } /** * @return Is the data in the file mapped to colors using * a palette. */ bool CiftiFiberTrajectoryFile::isMappedWithPalette() const { return false; } /** * Get statistics describing the distribution of data * mapped with a color palette at the given index. * * @param mapIndex * Index of the map. * @return * Fast statistics for data (will be NULL for data * not mapped using a palette). */ const FastStatistics* CiftiFiberTrajectoryFile::getMapFastStatistics(const int32_t /*mapIndex*/) { return NULL; } /** * Get histogram describing the distribution of data * mapped with a color palette at the given index. * * @param mapIndex * Index of the map. * @return * Histogram for data (will be NULL for data * not mapped using a palette). */ const Histogram* CiftiFiberTrajectoryFile::getMapHistogram(const int32_t /*mapIndex*/) { return NULL; } /** * Get histogram describing the distribution of data * mapped with a color palette at the given index for * data within the given ranges. * * @param mapIndex * Index of the map. * @param mostPositiveValueInclusive * Values more positive than this value are excluded. * @param leastPositiveValueInclusive * Values less positive than this value are excluded. * @param leastNegativeValueInclusive * Values less negative than this value are excluded. * @param mostNegativeValueInclusive * Values more negative than this value are excluded. * @param includeZeroValues * If true zero values (very near zero) are included. * @return * Descriptive statistics for data (will be NULL for data * not mapped using a palette). */ const Histogram* CiftiFiberTrajectoryFile::getMapHistogram(const int32_t /*mapIndex*/, const float /*mostPositiveValueInclusive*/, const float /*leastPositiveValueInclusive*/, const float /*leastNegativeValueInclusive*/, const float /*mostNegativeValueInclusive*/, const bool /*includeZeroValues*/) { return NULL; } /** * @return The estimated size of data after it is uncompressed * and loaded into RAM. A negative value indicates that the * file size cannot be computed. */ int64_t CiftiFiberTrajectoryFile::getDataSizeUncompressedInBytes() const { return -1; } /** * Get statistics describing the distribution of data * mapped with a color palette for all data within the file. * * @return * Fast statistics for data (will be NULL for data * not mapped using a palette). */ const FastStatistics* CiftiFiberTrajectoryFile::getFileFastStatistics() { return NULL; } /** * Get histogram describing the distribution of data * mapped with a color palette for all data within * the file. * * @return * Histogram for data (will be NULL for data * not mapped using a palette). */ const Histogram* CiftiFiberTrajectoryFile::getFileHistogram() { return NULL; } /** * Get histogram describing the distribution of data * mapped with a color palette for all data in the file * within the given range of values. * * @param mostPositiveValueInclusive * Values more positive than this value are excluded. * @param leastPositiveValueInclusive * Values less positive than this value are excluded. * @param leastNegativeValueInclusive * Values less negative than this value are excluded. * @param mostNegativeValueInclusive * Values more negative than this value are excluded. * @param includeZeroValues * If true zero values (very near zero) are included. * @return * Descriptive statistics for data (will be NULL for data * not mapped using a palette). */ const Histogram* CiftiFiberTrajectoryFile::getFileHistogram(const float /*mostPositiveValueInclusive*/, const float /*leastPositiveValueInclusive*/, const float /*leastNegativeValueInclusive*/, const float /*mostNegativeValueInclusive*/, const bool /*includeZeroValues*/) { return NULL; } /** * Get the palette color mapping for the map at the given index. * * @param mapIndex * Index of the map. * @return * Palette color mapping for the map (will be NULL for data * not mapped using a palette). */ PaletteColorMapping* CiftiFiberTrajectoryFile::getMapPaletteColorMapping(const int32_t /*mapIndex*/) { return NULL; } /** * Get the palette color mapping for the map at the given index. * * @param mapIndex * Index of the map. * @return * Palette color mapping for the map (constant) (will be NULL for data * not mapped using a palette). */ const PaletteColorMapping* CiftiFiberTrajectoryFile::getMapPaletteColorMapping(const int32_t /*mapIndex*/) const { return NULL; } /** * @return Is the data in the file mapped to colors using * a label table. */ bool CiftiFiberTrajectoryFile::isMappedWithLabelTable() const { return false; } /** * Get the label table for the map at the given index. * * @param mapIndex * Index of the map. * @return * Label table for the map (will be NULL for data * not mapped using a label table). */ GiftiLabelTable* CiftiFiberTrajectoryFile::getMapLabelTable(const int32_t /*mapIndex*/) { return NULL; } /** * Get the label table for the map at the given index. * * @param mapIndex * Index of the map. * @return * Label table for the map (constant) (will be NULL for data * not mapped using a label table). */ const GiftiLabelTable* CiftiFiberTrajectoryFile::getMapLabelTable(const int32_t /*mapIndex*/) const { return NULL; } /** * Get the palette normalization modes that are supported by the file. * * @param modesSupportedOut * Palette normalization modes supported by a file. Will be * empty for files that are not mapped with a palette. If there * is more than one suppported mode, the first mode in the * vector is assumed to be the default mode. */ void CiftiFiberTrajectoryFile::getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) const { modesSupportedOut.clear(); } /** * Update scalar coloring for a map. * * Note that some CIFTI files can be slow to color due to the need to * retrieve data for the map. Use isMapColoringValid() to avoid * unnecessary calls to isMapColoringValid. * * @param mapIndex * Index of map. * @param paletteFile * Palette file containing palettes. */ void CiftiFiberTrajectoryFile::updateScalarColoringForMap(const int32_t /*mapIndex*/) { } /** * @return The fiber trajectory map properties (const method). */ FiberTrajectoryMapProperties* CiftiFiberTrajectoryFile::getFiberTrajectoryMapProperties() { return m_fiberTrajectoryMapProperties; } /** * @return The fiber trajectory map properties. */ const FiberTrajectoryMapProperties* CiftiFiberTrajectoryFile::getFiberTrajectoryMapProperties() const { return m_fiberTrajectoryMapProperties; } /** * Read the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully read. */ void CiftiFiberTrajectoryFile::readFile(const AString& filename) { clear(); checkFileReadability(filename); try { m_sparseFile = new CaretSparseFile(); m_sparseFile->readFile(filename); setFileName(filename); m_fiberTrajectoryFileType = FIBER_TRAJECTORY_LOAD_BY_BRAINORDINATE; const CiftiXML& xml = m_sparseFile->getCiftiXML(); if (xml.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::SCALARS) { m_fiberTrajectoryFileType = FIBER_TRAJECTORY_LOAD_SINGLE_ROW; } clearModified(); } catch (const DataFileException& e) { clear(); throw e; } } /** * Write the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully written. */ void CiftiFiberTrajectoryFile::writeFile(const AString& filename) { switch (m_fiberTrajectoryFileType) { case FIBER_TRAJECTORY_LOAD_BY_BRAINORDINATE: throw DataFileException(filename, "Writing of Cifti Trajectory Files that load by brainordinate is not supported."); break; case FIBER_TRAJECTORY_LOAD_SINGLE_ROW: writeLoadedDataToFile(filename); break; } } class FiberFractionAndIndex { public: FiberFractionAndIndex(const FiberFractions& fiberFraction, const int64_t fiberIndex) { m_fiberFraction = fiberFraction; m_fiberIndex = fiberIndex; } bool operator<(const FiberFractionAndIndex& other) const { return (m_fiberIndex < other.m_fiberIndex); } FiberFractions m_fiberFraction; int64_t m_fiberIndex; }; class FiberTrajectoryComparison { public: bool operator() (const FiberOrientationTrajectory* left, const FiberOrientationTrajectory* right) const { return (left->getFiberOrientationIndex() < right->getFiberOrientationIndex()); } }; /** * Create a new fiber trajectory file from the loaded data of this file. * * @param errorMessageOut * Error message if creation of new fiber trajectory file failed. * @param * Pointer to new file that was created or NULL if creation failed. */ CiftiFiberTrajectoryFile* CiftiFiberTrajectoryFile::newFiberTrajectoryFileFromLoadedRowData(const AString& destinationDirectory, AString& errorMessageOut) const { errorMessageOut = ""; const int64_t numTraj = static_cast(m_fiberOrientationTrajectories.size()); if (numTraj <= 0) { errorMessageOut = "No data is loaded so cannot create file."; return NULL; } CiftiFiberTrajectoryFile* newFile = NULL; try { newFile = new CiftiFiberTrajectoryFile(); AString rowInfo = ""; if (m_loadedDataDescriptionForFileCopy.isEmpty() == false) { rowInfo = ("_" + m_loadedDataDescriptionForFileCopy); } /* * May need to convert a remote path to a local path */ FileInformation initialFileNameInfo(getFileName()); const AString scalarFileName = initialFileNameInfo.getAsLocalAbsoluteFilePath(destinationDirectory, getDataFileType()); /* * Create name of scalar file with row/column information */ FileInformation scalarFileInfo(scalarFileName); AString thePath, theName, theExtension; scalarFileInfo.getFileComponents(thePath, theName, theExtension); theName.append(rowInfo); const AString newFileName = FileInformation::assembleFileComponents(thePath, theName, theExtension); const AString tempFileName = (QDir::tempPath() + "/" + newFile->getFileNameNoPath()); std::cout << "Filename: " << qPrintable(tempFileName) << std::endl; writeLoadedDataToFile(tempFileName); newFile->readFile(tempFileName); newFile->setFileName(newFileName); newFile->setMatchingFiberOrientationFile(const_cast(getMatchingFiberOrientationFile())); newFile->m_fiberTrajectoryMapProperties->copy(*getFiberTrajectoryMapProperties()); newFile->setModified(); return newFile; } catch (const DataFileException& dfe) { if (newFile != NULL) { delete newFile; } errorMessageOut = dfe.whatString(); return NULL; } return NULL; } /** * Write the loaded data to a file. * * @param filename * Name of file to write. * @throw DataFileException * If an error occurs. */ void CiftiFiberTrajectoryFile::writeLoadedDataToFile(const AString& filename) const { CiftiXML xml = m_sparseFile->getCiftiXML(); /* * Copy the pointers to the fiber orientation trajectories and sort * by fiber orientation index. */ std::vector trajectories(m_fiberOrientationTrajectories.begin(), m_fiberOrientationTrajectories.end()); bool isWriteFullRow = false; if (static_cast(trajectories.size()) == xml.getDimensionLength(CiftiXML::ALONG_ROW)) { isWriteFullRow = true; } else { /* * Sort by fiber orientation index. */ std::sort(trajectories.begin(), trajectories.end(), FiberTrajectoryComparison()); } std::vector fiberIndices; std::vector fiberFractions; int ctr = 0; for (std::vector::const_iterator iter = trajectories.begin(); iter != trajectories.end(); iter++) { const FiberOrientationTrajectory* fot = *iter; std::vector proportions = fot->getFiberFractions(); if (proportions.size() < 3) { proportions.resize(3, 0.0); } const float totalCount = fot->getFiberFractionTotalCount(); FiberFractions ff; ff.totalCount = totalCount; //(totalCount + 0.5); ff.distance = fot->getFiberFractionDistance(); ff.fiberFractions = proportions; fiberIndices.push_back(fot->getFiberOrientationIndex()); fiberFractions.push_back(ff); // // for (int64_t i = 0; i < 3; i++) { // if (vec[i] < -0.002f) { // std::cout << "Fiber " << ctr << vec[i] << std::endl; // } // } ctr++; } /* * Write to temp file!!!!! */ CiftiScalarsMap tempMap; tempMap.setLength(1); tempMap.setMapName(0, m_loadedDataDescriptionForMapName); xml.setMap(CiftiXML::ALONG_COLUMN, tempMap); CaretSparseFileWriter sparseWriter(filename, xml); const int64_t rowIndex = 0; if (isWriteFullRow) { sparseWriter.writeFibersRow(rowIndex, &fiberFractions[0]); } else { sparseWriter.writeFibersRowSparse(rowIndex, fiberIndices, fiberFractions); } sparseWriter.finish(); } /** * Clear the loaded fiber orientations. */ void CiftiFiberTrajectoryFile::clearLoadedFiberOrientations() { const int64_t numFibers = static_cast(m_fiberOrientationTrajectories.size()); for (int64_t i = 0; i < numFibers; i++) { delete m_fiberOrientationTrajectories[i]; } m_fiberOrientationTrajectories.clear(); m_loadedDataDescriptionForMapName = ""; m_loadedDataDescriptionForFileCopy = ""; m_connectivityDataLoaded->reset(); } /** * Validate that the assigned matching fiber orientation file is valid * (not NULL and row/column is compatible). * * @throws DataFileException * If fiber orientation file is NULL or incompatible. */ void CiftiFiberTrajectoryFile::validateAssignedMatchingFiberOrientationFile() { if (m_sparseFile == NULL) { throw DataFileException(getFileName(), "No data has been loaded."); } if (m_matchingFiberOrientationFile == NULL) { throw DataFileException(getFileName(), "No fiber orientation file is assigned."); } const CiftiXML& trajXML = m_sparseFile->getCiftiXML(); const CiftiXML* orientXML = m_matchingFiberOrientationFile->getCiftiXML(); if (*(trajXML.getMap(CiftiXML::ALONG_ROW)) != *(orientXML->getMap(CiftiXML::ALONG_COLUMN))) { QString msg = ("Row to Columns do not match: rows=" + QString::number(trajXML.getDimensionLength(CiftiXML::ALONG_COLUMN)) + " cols=" + QString::number(trajXML.getDimensionLength(CiftiXML::ALONG_ROW)) + " " + m_matchingFiberOrientationFile->getFileNameNoPath() + " rows=" + QString::number(orientXML->getDimensionLength(CiftiXML::ALONG_COLUMN)) + " cols=" + QString::number(orientXML->getDimensionLength(CiftiXML::ALONG_ROW))); throw DataFileException(getFileName(), msg); } } /** * Get the brainordinate from the given row. * * @param rowIndex * Index of the row. * @param surfaceStructureOut * Will contain structure of surface if row is a surface node. * @param surfaceNodeIndexOut * Will contain index of surface node if row is a surface node. * @param surfaceNumberOfNodesOut * Will contain surfaces number of nodes if row is a surface node. * @param surfaceNodeValidOut * Will be true upon exit if the row corresponded to a surface node. * @param voxelIJKOut * Will contain the voxel's IJK indices if row is a surface node. * @param voxelXYZOut * Will contain the voxel's XYZ coordinate if row is a surface node. * @param voxelValidOut * Will be true upon exit if the row corresponded to a surface node. * @throw DataFileException * If the rows are not for brainordinates or the row index is invalid. */ void CiftiFiberTrajectoryFile::getBrainordinateFromRowIndex(const int64_t rowIndex, StructureEnum::Enum& surfaceStructureOut, int32_t& surfaceNodeIndexOut, int32_t& surfaceNumberOfNodesOut, bool& surfaceNodeValidOut, int64_t voxelIJKOut[3], float voxelXYZOut[3], bool& voxelValidOut) const { surfaceNodeValidOut = false; voxelValidOut = false; if (m_sparseFile == NULL) { return; } const CiftiXML& ciftiXML = m_sparseFile->getCiftiXML(); if (ciftiXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) { throw DataFileException(getFileName(), "File does not have brainordinate data for rows."); return; } const CiftiBrainModelsMap& brainMap = ciftiXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); const int numRows = ciftiXML.getDimensionLength(CiftiXML::ALONG_COLUMN); if ((rowIndex < 0) || (rowIndex >= numRows)) { throw DataFileException(getFileName(), "Row index " + AString::number(rowIndex) + " is invalid. Number of rows is " + AString::number(numRows)); } const CiftiBrainModelsMap::IndexInfo indexInfo = brainMap.getInfoForIndex(rowIndex); switch (indexInfo.m_type) { case CiftiBrainModelsMap::SURFACE: surfaceStructureOut = indexInfo.m_structure; surfaceNodeIndexOut = indexInfo.m_surfaceNode; surfaceNumberOfNodesOut = brainMap.getSurfaceNumberOfNodes(surfaceStructureOut); surfaceNodeValidOut = true; break; case CiftiBrainModelsMap::VOXELS: { const VolumeSpace& colSpace = brainMap.getVolumeSpace(); voxelIJKOut[0] = indexInfo.m_ijk[0]; voxelIJKOut[1] = indexInfo.m_ijk[1]; voxelIJKOut[2] = indexInfo.m_ijk[2]; colSpace.indexToSpace(voxelIJKOut, voxelXYZOut); voxelValidOut = true; } break; } } /** * Load data for the given surface node. * @param structure * Structure in which surface node is located. * @param surfaceNumberOfNodes * Number of nodes in the surface. * @param nodeIndex * Index of the surface node. * @return * Index of row that was loaded or -1 if no data was found for node. */ int64_t CiftiFiberTrajectoryFile::loadDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const int32_t nodeIndex) { switch (m_fiberTrajectoryFileType) { case FIBER_TRAJECTORY_LOAD_BY_BRAINORDINATE: break; case FIBER_TRAJECTORY_LOAD_SINGLE_ROW: return -1; break; } if (m_dataLoadingEnabled == false) { return -1; } clearLoadedFiberOrientations(); validateAssignedMatchingFiberOrientationFile(); const CiftiXML& trajXML = m_sparseFile->getCiftiXML(); const CiftiBrainModelsMap& colMap = trajXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); if (colMap.hasSurfaceData(structure) == false) { return -1; } if (colMap.getSurfaceNumberOfNodes(structure) != surfaceNumberOfNodes) { return -1; } const int64_t rowIndex = colMap.getIndexForNode(nodeIndex, structure); if (rowIndex < 0) { return -1; } std::vector fiberIndices; std::vector fiberFractions; bool rowTest = false; if (rowTest) { /* * Test loading a full row instead of sparse. */ const int numCols = trajXML.getDimensionLength(CiftiXML::ALONG_ROW); fiberFractions.resize(numCols); m_sparseFile->getFibersRow(rowIndex, &fiberFractions[0]); for (int64_t i = 0; i < numCols; i++) { fiberIndices.push_back(i); } } else { m_sparseFile->getFibersRowSparse(rowIndex, fiberIndices, fiberFractions); } CaretAssert(fiberIndices.size() == fiberFractions.size()); const int64_t numFibers = static_cast(fiberIndices.size()); CaretLogFine("For node " + AString::number(nodeIndex) + " number of rows loaded: " + AString::number(numFibers)); if (numFibers > 0) { m_fiberOrientationTrajectories.reserve(numFibers); for (int64_t iFiber = 0; iFiber < numFibers; iFiber++) { const int64_t numFiberOrientations = m_matchingFiberOrientationFile->getNumberOfFiberOrientations(); const int64_t fiberIndex = fiberIndices[iFiber]; if (fiberIndex < numFiberOrientations) { const FiberOrientation* fiberOrientation = m_matchingFiberOrientationFile->getFiberOrientations(fiberIndex); FiberOrientationTrajectory* fot = new FiberOrientationTrajectory(fiberIndex, fiberOrientation); fot->setFiberFractions(fiberFractions[iFiber]); m_fiberOrientationTrajectories.push_back(fot); } else{ CaretLogSevere("Invalid index=" + QString::number(fiberIndex) + " into fiber orientations"); } } m_loadedDataDescriptionForMapName = ("Row: " + AString::number(rowIndex) + ", Node Index: " + AString::number(nodeIndex) + ", Structure: " + StructureEnum::toName(structure)); m_loadedDataDescriptionForFileCopy = ("Row_" + AString::number(rowIndex)); m_connectivityDataLoaded->setSurfaceNodeLoading(structure, surfaceNumberOfNodes, nodeIndex, rowIndex, -1); } else { m_connectivityDataLoaded->reset(); return -1; } return rowIndex; } void CiftiFiberTrajectoryFile::finishFiberOrientationTrajectoriesAveraging() { for (std::vector::iterator iter = m_fiberOrientationTrajectories.begin(); iter != m_fiberOrientationTrajectories.end(); iter++) { FiberOrientationTrajectory* fot = *iter; fot->finishAveraging(); } } /** * Load average data for the given surface nodes. * * @param structure * Structure in which surface node is located. * @param surfaceNumberOfNodes * Number of nodes in surface. * @param nodeIndices * Indices of the surface nodes. */ void CiftiFiberTrajectoryFile::loadDataAverageForSurfaceNodes(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const std::vector& nodeIndices) { switch (m_fiberTrajectoryFileType) { case FIBER_TRAJECTORY_LOAD_BY_BRAINORDINATE: break; case FIBER_TRAJECTORY_LOAD_SINGLE_ROW: return; break; } if (m_dataLoadingEnabled == false) { return; } clearLoadedFiberOrientations(); if (surfaceNumberOfNodes <= 0) { return; } validateAssignedMatchingFiberOrientationFile(); const CiftiXML& trajXML = m_sparseFile->getCiftiXML(); const CiftiBrainModelsMap& colMap = trajXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); if (colMap.hasSurfaceData(structure) == false) { return; } if (colMap.getSurfaceNumberOfNodes(structure) != surfaceNumberOfNodes) { return; } /* * This map uses the index of a fiber orientation (from the Fiber Orientation File) * to a FiberOrientationTrajectory instance. For averaging, items that have * a matching fiber orientation index are averaged. */ std::map fiberOrientationIndexMapToFiberTrajectory; std::vector rowIndicesToLoad; const int32_t numberOfNodes = static_cast(nodeIndices.size()); for (int32_t i = 0; i < numberOfNodes; i++) { const int32_t nodeIndex = nodeIndices[i]; /* * Get and load row for node */ const int64_t rowIndex = colMap.getIndexForNode(nodeIndex, structure); if (rowIndex >= 0) { rowIndicesToLoad.push_back(rowIndex); } } if (loadRowsForAveraging(rowIndicesToLoad)) { m_connectivityDataLoaded->setSurfaceAverageNodeLoading(structure, surfaceNumberOfNodes, nodeIndices); m_loadedDataDescriptionForMapName = ("Structure: " + StructureEnum::toName(structure) + ", Averaged Node Count: " + AString::number(numberOfNodes)); m_loadedDataDescriptionForFileCopy = ("Averaged_Node_Count_" + AString::number(numberOfNodes)); } } /** * Load the given rows for averaging. * * @param rowIndices * Indices of rows for averaging. * @return * True if data was loaded else false if no data or user cancelled. * @throw * DataFileException if there is an error. */ bool CiftiFiberTrajectoryFile::loadRowsForAveraging(const std::vector& rowIndices) { const CiftiXML& trajXML = m_sparseFile->getCiftiXML(); const int64_t numberOfColumns = trajXML.getDimensionLength(CiftiXML::ALONG_ROW); std::vector fiberFractionsForRowVector(numberOfColumns); FiberFractions* fiberFractionsForRow = &fiberFractionsForRowVector[0]; const int64_t numberOfRowsToLoad = static_cast(rowIndices.size()); if (numberOfRowsToLoad <= 0) { return false; } const int32_t progressUpdateInterval = 1; EventProgressUpdate progressEvent(0, numberOfRowsToLoad, 0, ("Loading data for " + QString::number(numberOfRowsToLoad) + " brainordinates in file ") + getFileNameNoPath()); EventManager::get()->sendEvent(progressEvent.getPointer()); for (int64_t iCol = 0; iCol < numberOfColumns; iCol++) { const FiberOrientation* fiberOrientation = m_matchingFiberOrientationFile->getFiberOrientations(iCol); CaretAssert(fiberOrientation); m_fiberOrientationTrajectories.push_back(new FiberOrientationTrajectory(iCol, fiberOrientation)); } bool userCancelled = false; for (int64_t iRow = 0; iRow < numberOfRowsToLoad; iRow++) { const int64_t rowIndex = rowIndices[iRow]; if ((iRow % progressUpdateInterval) == 0) { progressEvent.setProgress(iRow, ""); EventManager::get()->sendEvent(progressEvent.getPointer()); if (progressEvent.isCancelled()) { userCancelled = true; break; } } m_sparseFile->getFibersRow(rowIndex, fiberFractionsForRow); for (int64_t iCol = 0; iCol < numberOfColumns; iCol++) { FiberOrientationTrajectory* fot = m_fiberOrientationTrajectories[iCol]; fot->addFiberFractionsForAveraging(fiberFractionsForRow[iCol]); } } if (userCancelled) { clearLoadedFiberOrientations(); return false; } finishFiberOrientationTrajectoriesAveraging(); return true; } /** * Load data for a voxel at the given coordinate. * * @param xyz * Coordinate of voxel. * @return * Index of row that was loaded or -1 if no data was found for coordinate. * @throw * DataFileException if there is an error. */ int64_t CiftiFiberTrajectoryFile::loadMapDataForVoxelAtCoordinate(const float xyz[3]) { m_connectivityDataLoaded->reset(); switch (m_fiberTrajectoryFileType) { case FIBER_TRAJECTORY_LOAD_BY_BRAINORDINATE: break; case FIBER_TRAJECTORY_LOAD_SINGLE_ROW: return -1; break; } if (m_dataLoadingEnabled == false) { return -1; } clearLoadedFiberOrientations(); validateAssignedMatchingFiberOrientationFile(); const CiftiXML& trajXML = m_sparseFile->getCiftiXML(); const CiftiBrainModelsMap& colMap = trajXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); if (!colMap.hasVolumeData()) return -1; const VolumeSpace& colSpace = colMap.getVolumeSpace(); int64_t ijk[3]; colSpace.enclosingVoxel(xyz, ijk); const int64_t rowIndex = colMap.getIndexForVoxel(ijk); if (rowIndex < 0) { return -1; } std::vector fiberIndices; std::vector fiberFractions; m_sparseFile->getFibersRowSparse(rowIndex, fiberIndices, fiberFractions); CaretAssert(fiberIndices.size() == fiberFractions.size()); const int64_t numFibers = static_cast(fiberIndices.size()); CaretLogFine("For voxel at coordinate " + AString::fromNumbers(xyz, 3, ",") + " number of rows loaded: " + AString::number(numFibers)); if (numFibers > 0) { m_fiberOrientationTrajectories.reserve(numFibers); for (int64_t iFiber = 0; iFiber < numFibers; iFiber++) { const int64_t numFiberOrientations = m_matchingFiberOrientationFile->getNumberOfFiberOrientations(); const int64_t fiberIndex = fiberIndices[iFiber]; if (fiberIndex < numFiberOrientations) { const FiberOrientation* fiberOrientation = m_matchingFiberOrientationFile->getFiberOrientations(fiberIndex); FiberOrientationTrajectory* fot = new FiberOrientationTrajectory(fiberIndex, fiberOrientation); fot->setFiberFractions(fiberFractions[iFiber]); m_fiberOrientationTrajectories.push_back(fot); } else{ CaretLogSevere("Invalid index=" + QString::number(fiberIndex) + " into fiber orientations"); } } m_loadedDataDescriptionForMapName = ("Row: " + AString::number(rowIndex) + ", Voxel XYZ: " + AString::fromNumbers(xyz, 3, ",") + ", Structure: "); m_loadedDataDescriptionForFileCopy = ("Row_" + AString::number(rowIndex)); m_connectivityDataLoaded->setVolumeXYZLoading(xyz, rowIndex, -1); } else { return -1; } return rowIndex; } /** * Load connectivity data for the voxel indices and then average the data. * * @param volumeDimensionIJK * Dimensions of the volume. * @param voxelIndices * Indices of voxels. * @throw * DataFileException if there is an error. */ void CiftiFiberTrajectoryFile::loadMapAverageDataForVoxelIndices(const int64_t volumeDimensionIJK[3], const std::vector& voxelIndices) { switch (m_fiberTrajectoryFileType) { case FIBER_TRAJECTORY_LOAD_BY_BRAINORDINATE: break; case FIBER_TRAJECTORY_LOAD_SINGLE_ROW: return; break; } if (m_dataLoadingEnabled == false) { return; } clearLoadedFiberOrientations(); validateAssignedMatchingFiberOrientationFile(); const CiftiXML& trajXML = m_sparseFile->getCiftiXML(); const CiftiBrainModelsMap& colMap = trajXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); if (colMap.hasVolumeData() == false) { return; } std::vector rowIndicesToLoad; const int32_t numberOfVoxels = static_cast(voxelIndices.size()); for (int32_t i = 0; i < numberOfVoxels; i++) { /* * Get and load row for voxel */ const int64_t rowIndex = colMap.getIndexForVoxel(voxelIndices[i].m_ijk); if (rowIndex >= 0) { rowIndicesToLoad.push_back(rowIndex); } } if (loadRowsForAveraging(rowIndicesToLoad)) { m_connectivityDataLoaded->setVolumeAverageVoxelLoading(volumeDimensionIJK, voxelIndices); m_loadedDataDescriptionForMapName = ("Averaged Voxel Count: " + AString::number(numberOfVoxels)); m_loadedDataDescriptionForFileCopy = ("Average_Voxel_Count_" + AString::number(numberOfVoxels)); } } /** * Load the given row index from the file even if the file is disabled for data loading * * @param rowIndex * Index of row that is loaded. * @throw DataFileException * If an error occurs. */ void CiftiFiberTrajectoryFile::loadDataForRowIndex(const int64_t rowIndex) { clearLoadedFiberOrientations(); validateAssignedMatchingFiberOrientationFile(); std::vector fiberIndices; std::vector fiberFractions; m_sparseFile->getFibersRowSparse(rowIndex, fiberIndices, fiberFractions); CaretAssert(fiberIndices.size() == fiberFractions.size()); const int64_t numFibers = static_cast(fiberIndices.size()); if (numFibers > 0) { m_fiberOrientationTrajectories.reserve(numFibers); for (int64_t iFiber = 0; iFiber < numFibers; iFiber++) { const int64_t numFiberOrientations = m_matchingFiberOrientationFile->getNumberOfFiberOrientations(); const int64_t fiberIndex = fiberIndices[iFiber]; if (fiberIndex < numFiberOrientations) { const FiberOrientation* fiberOrientation = m_matchingFiberOrientationFile->getFiberOrientations(fiberIndex); FiberOrientationTrajectory* fot = new FiberOrientationTrajectory(fiberIndex, fiberOrientation); fot->setFiberFractions(fiberFractions[iFiber]); m_fiberOrientationTrajectories.push_back(fot); } else{ CaretLogSevere("Invalid index=" + QString::number(fiberIndex) + " into fiber orientations"); } } m_loadedDataDescriptionForMapName = ("Row: " + AString::number(rowIndex)); m_loadedDataDescriptionForFileCopy = ("Row_" + AString::number(rowIndex)); m_connectivityDataLoaded->setRowColumnLoading(rowIndex, -1); } else { throw DataFileException(getFileName(), "Row " + AString::number(rowIndex) + " is invalid or contains no data."); } } /** * Finish restoration of scene. * In this file's circumstances, the fiber orientation files were not * available at the time the scene was restored. * * @throws DataFileException * If there was an error restoring the data. */ void CiftiFiberTrajectoryFile::finishRestorationOfScene() { /* * Loading of data may be disabled in the scene * so temporarily enabled loading and then * restore the status. */ const bool loadingEnabledStatus = isDataLoadingEnabled(); setDataLoadingEnabled(true); switch (m_connectivityDataLoaded->getMode()) { case ConnectivityDataLoaded::MODE_NONE: break; case ConnectivityDataLoaded::MODE_ROW: { int64_t rowIndex; int64_t columnIndex; m_connectivityDataLoaded->getRowColumnLoading(rowIndex, columnIndex); loadDataForRowIndex(rowIndex); } break; case ConnectivityDataLoaded::MODE_COLUMN: { /* * Never load by column !!! */ CaretAssertMessage(0, "Fiber Trajectory never loads by column."); } break; case ConnectivityDataLoaded::MODE_SURFACE_NODE: { StructureEnum::Enum structure; int32_t surfaceNumberOfNodes; int32_t surfaceNodeIndex; int64_t rowIndex; int64_t columnIndex; m_connectivityDataLoaded->getSurfaceNodeLoading(structure, surfaceNumberOfNodes, surfaceNodeIndex, rowIndex, columnIndex); loadDataForSurfaceNode(structure, surfaceNumberOfNodes, surfaceNodeIndex); } break; case ConnectivityDataLoaded::MODE_SURFACE_NODE_AVERAGE: { StructureEnum::Enum structure; int32_t surfaceNumberOfNodes; std::vector surfaceNodeIndices; m_connectivityDataLoaded->getSurfaceAverageNodeLoading(structure, surfaceNumberOfNodes, surfaceNodeIndices); loadDataAverageForSurfaceNodes(structure, surfaceNumberOfNodes, surfaceNodeIndices); } break; case ConnectivityDataLoaded::MODE_VOXEL_XYZ: { float volumeXYZ[3]; int64_t rowIndex; int64_t columnIndex; m_connectivityDataLoaded->getVolumeXYZLoading(volumeXYZ, rowIndex, columnIndex); loadMapDataForVoxelAtCoordinate(volumeXYZ); } break; case ConnectivityDataLoaded::MODE_VOXEL_IJK_AVERAGE: { int64_t volumeDimensionsIJK[3]; std::vector voxelIndicesIJK; m_connectivityDataLoaded->getVolumeAverageVoxelLoading(volumeDimensionsIJK, voxelIndicesIJK); loadMapAverageDataForVoxelIndices(volumeDimensionsIJK, voxelIndicesIJK); } break; } setDataLoadingEnabled(loadingEnabledStatus); } /** * @return a REFERENCE to the fiber fractions that were loaded. */ const std::vector& CiftiFiberTrajectoryFile::getLoadedFiberOrientationTrajectories() const { return m_fiberOrientationTrajectories; } /** * Save file data from the scene. For subclasses that need to * save to a scene, this method should be overriden. sceneClass * will be valid and any scene data should be added to it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. */ void CiftiFiberTrajectoryFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { CaretMappableDataFile::saveFileDataToScene(sceneAttributes, sceneClass); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore file data from the scene. For subclasses that need to * restore from a scene, this method should be overridden. The scene class * will be valid and any scene data may be obtained from it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void CiftiFiberTrajectoryFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { m_connectivityDataLoaded->reset(); m_matchingFiberOrientationFile = NULL; m_matchingFiberOrientationFileName = ""; CaretMappableDataFile::restoreFileDataFromScene(sceneAttributes, sceneClass); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); m_matchingFiberOrientationFileNameFromRestoredScene = m_matchingFiberOrientationFileName; } /** * @return True if this file type supports writing, else false. * * Fiber trajectory files do NOT support writing. */ bool CiftiFiberTrajectoryFile::supportsWriting() const { switch (m_fiberTrajectoryFileType) { case FIBER_TRAJECTORY_LOAD_BY_BRAINORDINATE: break; case FIBER_TRAJECTORY_LOAD_SINGLE_ROW: return true; break; } return false; } /** * Add information about the file to the data file information. * * @param dataFileInformation * Consolidates information about a data file. */ void CiftiFiberTrajectoryFile::addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) { CaretMappableDataFile::addToDataFileContentInformation(dataFileInformation); if (m_sparseFile != NULL) { const CiftiXML& ciftiXML = m_sparseFile->getCiftiXML(); const CiftiBrainModelsMap& colMap = ciftiXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); //ciftiXML.getVoxelInfoInDataFileContentInformation(CiftiXML::ALONG_COLUMN, // dataFileInformation); if (colMap.hasVolumeData()) { VolumeSpace volumeSpace = colMap.getVolumeSpace();//TSC: copied/reimplemented from CiftiXML Old - I don't think it belongs in CiftiXML or CiftiBrainModelsMap const int64_t* dims = volumeSpace.getDims(); dataFileInformation.addNameAndValue("Dimensions", AString::fromNumbers(dims, 3, ",")); VolumeSpace::OrientTypes orientation[3]; float spacing[3]; float origin[3]; volumeSpace.getOrientAndSpacingForPlumb(orientation, spacing, origin); dataFileInformation.addNameAndValue("Spacing", AString::fromNumbers(spacing, 3, ",")); dataFileInformation.addNameAndValue("Origin", AString::fromNumbers(origin, 3, ",")); const std::vector >& sform = volumeSpace.getSform(); for (uint32_t i = 0; i < sform.size(); i++) { dataFileInformation.addNameAndValue(("sform row " + AString::number(i)), AString::fromNumbers(sform[i], ",")); } std::vector volStructs = colMap.getVolumeStructureList(); for (int i = 0; i < (int)volStructs.size(); ++i) { std::vector voxels = colMap.getVolumeStructureMap(volStructs[i]); for (int j = 0; j < (int)voxels.size(); ++j) { float xyz[3]; volumeSpace.indexToSpace(voxels[i].m_ijk, xyz); const AString msg = ("ijk=(" + AString::fromNumbers(voxels[j].m_ijk, 3, ", ") + "), xyz=(" + AString::fromNumbers(xyz, 3, ", ") + "), row=" + AString::number(voxels[j].m_ciftiIndex) + " ");//TSC: huh? dataFileInformation.addNameAndValue(StructureEnum::toGuiName(volStructs[i]), msg);//TSC: huh? } } } CiftiMappableDataFile::addCiftiXmlToDataFileContentInformation(dataFileInformation, ciftiXML); } } bool CiftiFiberTrajectoryFile::hasCiftiXML() const { return true; } const CiftiXML CiftiFiberTrajectoryFile::getCiftiXML() const { if (m_sparseFile != NULL) { return m_sparseFile->getCiftiXML(); } return CiftiXML(); } /** * Get data from the file as requested in the given map file data selector. * * @param mapFileDataSelector * Specifies selection of data. * @param dataOut * Output with data. Will be empty if data does not support the map file data selector. */ void CiftiFiberTrajectoryFile::getDataForSelector(const MapFileDataSelector& /*mapFileDataSelector*/, std::vector& dataOut) const { dataOut.clear(); } /** * Are all brainordinates in this file also in the given file? * That is, the brainordinates are equal to or a subset of the brainordinates * in the given file. * * @param mapFile * The given map file. * @return * True if brainordinates in this file are subset or equal to the given file, else false. */ CaretMappableDataFile::BrainordinateMappingMatch CiftiFiberTrajectoryFile::getBrainordinateMappingMatch(const CaretMappableDataFile* /*mapFile*/) const { return BrainordinateMappingMatch::NO; } connectome-workbench-1.4.2/src/Files/CiftiFiberTrajectoryFile.h000066400000000000000000000241011360521144700245100ustar00rootroot00000000000000#ifndef __CIFTI_FIBER_TRAJECTORY_FILE__H_ #define __CIFTI_FIBER_TRAJECTORY_FILE__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "CaretMappableDataFile.h" #include "CaretSparseFile.h" #include "DisplayGroupEnum.h" #include "SceneClassAssistant.h" #include "VoxelIJK.h" namespace caret { class CiftiFiberOrientationFile; class ConnectivityDataLoaded; class FiberOrientationTrajectory; class FiberTrajectoryMapProperties; class GiftiMetaData; class CiftiFiberTrajectoryFile : public CaretMappableDataFile { public: CiftiFiberTrajectoryFile(); virtual ~CiftiFiberTrajectoryFile(); virtual void clear(); bool isEmpty() const; virtual StructureEnum::Enum getStructure() const; virtual void setStructure(const StructureEnum::Enum structure); virtual GiftiMetaData* getFileMetaData(); virtual const GiftiMetaData* getFileMetaData() const; virtual bool isSurfaceMappable() const; virtual bool isVolumeMappable() const; virtual int32_t getNumberOfMaps() const; virtual bool hasMapAttributes() const; virtual AString getMapName(const int32_t mapIndex) const; virtual void setMapName(const int32_t mapIndex, const AString& mapName); virtual const GiftiMetaData* getMapMetaData(const int32_t mapIndex) const; virtual GiftiMetaData* getMapMetaData(const int32_t mapIndex); virtual AString getMapUniqueID(const int32_t mapIndex) const; virtual bool isMappedWithPalette() const; virtual const FastStatistics* getMapFastStatistics(const int32_t mapIndex); virtual const Histogram* getMapHistogram(const int32_t mapIndex); virtual const Histogram* getMapHistogram(const int32_t mapIndex, const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues); virtual int64_t getDataSizeUncompressedInBytes() const; virtual const FastStatistics* getFileFastStatistics(); virtual const Histogram* getFileHistogram(); virtual const Histogram* getFileHistogram(const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues); virtual PaletteColorMapping* getMapPaletteColorMapping(const int32_t mapIndex); virtual const PaletteColorMapping* getMapPaletteColorMapping(const int32_t mapIndex) const; virtual bool isMappedWithLabelTable() const; virtual GiftiLabelTable* getMapLabelTable(const int32_t mapIndex); virtual const GiftiLabelTable* getMapLabelTable(const int32_t mapIndex) const; virtual void getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) const; virtual void updateScalarColoringForMap(const int32_t mapIndex) override; virtual void readFile(const AString& filename); virtual void writeFile(const AString& filename); void getBrainordinateFromRowIndex(const int64_t rowIndex, StructureEnum::Enum& surfaceStructureOut, int32_t& surfaceNodeIndexOut, int32_t& surfaceNumberOfNodesOut, bool& surfaceNodeValidOut, int64_t voxelIJKOut[3], float voxelXYZOut[3], bool& voxelValidOut) const; int64_t loadDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const int32_t nodeIndex); void loadDataAverageForSurfaceNodes(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const std::vector& nodeIndices); virtual int64_t loadMapDataForVoxelAtCoordinate(const float xyz[3]); virtual void loadMapAverageDataForVoxelIndices(const int64_t volumeDimensionIJK[3], const std::vector& voxelIndices); void loadDataForRowIndex(const int64_t rowIndex); const std::vector& getLoadedFiberOrientationTrajectories() const; void clearLoadedFiberOrientations(); FiberTrajectoryMapProperties* getFiberTrajectoryMapProperties(); const FiberTrajectoryMapProperties* getFiberTrajectoryMapProperties() const; bool isDataLoadingEnabled() const; void setDataLoadingEnabled(const bool loadingEnabled); CiftiFiberOrientationFile* getMatchingFiberOrientationFile(); const CiftiFiberOrientationFile* getMatchingFiberOrientationFile() const; bool isFiberOrientationFileCombatible(const CiftiFiberOrientationFile* fiberOrientationFile) const; void setMatchingFiberOrientationFile(CiftiFiberOrientationFile* matchingFiberOrientationFile); void updateMatchingFiberOrientationFileFromList(std::vector matchingFiberOrientationFiles); void finishRestorationOfScene(); bool supportsWriting() const; CiftiFiberTrajectoryFile* newFiberTrajectoryFileFromLoadedRowData(const AString& destinationDirectory, AString& errorMessageOut) const; void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation); bool hasCiftiXML() const; const CiftiXML getCiftiXML() const; virtual void getDataForSelector(const MapFileDataSelector& mapFileDataSelector, std::vector& dataOut) const override; virtual BrainordinateMappingMatch getBrainordinateMappingMatch(const CaretMappableDataFile* mapFile) const override; // ADD_NEW_METHODS_HERE private: CiftiFiberTrajectoryFile(const CiftiFiberTrajectoryFile&); CiftiFiberTrajectoryFile& operator=(const CiftiFiberTrajectoryFile&); protected: virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: /** * Type of fiber trajectory file */ enum FiberTrajectoryFileType { /** Load data by brainordinate */ FIBER_TRAJECTORY_LOAD_BY_BRAINORDINATE, /** Load single row (does not map to a brainordinate) */ FIBER_TRAJECTORY_LOAD_SINGLE_ROW }; bool loadRowsForAveraging(const std::vector& rowIndices); void clearPrivate(); void validateAssignedMatchingFiberOrientationFile(); void finishFiberOrientationTrajectoriesAveraging(); void writeLoadedDataToFile(const AString& filename) const; /** True if file supports loading of data by row */ FiberTrajectoryFileType m_fiberTrajectoryFileType; CaretSparseFile* m_sparseFile; GiftiMetaData* m_metadata; CiftiFiberOrientationFile* m_matchingFiberOrientationFile; AString m_matchingFiberOrientationFileName; AString m_matchingFiberOrientationFileNameFromRestoredScene; std::vector m_fiberOrientationTrajectories; FiberTrajectoryMapProperties* m_fiberTrajectoryMapProperties; bool m_dataLoadingEnabled; AString m_loadedDataDescriptionForFileCopy; AString m_loadedDataDescriptionForMapName; ConnectivityDataLoaded* m_connectivityDataLoaded; SceneClassAssistant* m_sceneAssistant; // ADD_NEW_MEMBERS_HERE }; #ifdef __CIFTI_FIBER_TRAJECTORY_FILE_DECLARE__ // #endif // __CIFTI_FIBER_TRAJECTORY_FILE_DECLARE__ } // namespace #endif //__CIFTI_FIBER_TRAJECTORY_FILE__H_ connectome-workbench-1.4.2/src/Files/CiftiMappableConnectivityMatrixDataFile.cxx000066400000000000000000001550661360521144700301030ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CIFTI_MAPPABLE_CONNECTIVITY_MATRIX_DATA_FILE_DECLARE__ #include "CiftiMappableConnectivityMatrixDataFile.h" #undef __CIFTI_MAPPABLE_CONNECTIVITY_MATRIX_DATA_FILE_DECLARE__ #include "CaretAssert.h" #include "CiftiFile.h" #include "CaretLogger.h" #include "ChartableMatrixParcelInterface.h" #include "ConnectivityDataLoaded.h" #include "DataFileException.h" #include "ElapsedTimer.h" #include "EventManager.h" #include "EventProgressUpdate.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::CiftiMappableConnectivityMatrixDataFile * \brief Data file for Cifti Connectivity Matrix Files. * \ingroup Files */ /** * Constructor. */ CiftiMappableConnectivityMatrixDataFile::CiftiMappableConnectivityMatrixDataFile(const DataFileTypeEnum::Enum dataFileType) : CiftiMappableDataFile(dataFileType) { m_connectivityDataLoaded = new ConnectivityDataLoaded(); /* * This method initializes some members */ clearPrivate(); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_connectivityDataLoaded", "ConnectivityDataLoaded", m_connectivityDataLoaded); m_sceneAssistant->add("+", &m_dataLoadingEnabled); } /** * Destructor. */ CiftiMappableConnectivityMatrixDataFile::~CiftiMappableConnectivityMatrixDataFile() { clearPrivate(); delete m_connectivityDataLoaded; delete m_sceneAssistant; } /** * Clear the contents of the file. */ void CiftiMappableConnectivityMatrixDataFile::clear() { CiftiMappableDataFile::clear(); clearPrivate(); } /** * Clear the contents of the file. * Note that "clear()" is virtual and cannot be called from destructor. */ void CiftiMappableConnectivityMatrixDataFile::clearPrivate() { m_loadedRowData.clear(); m_rowLoadedTextForMapName = ""; m_rowLoadedText = ""; m_dataLoadingEnabled = true; m_connectivityDataLoaded->reset(); m_chartLoadingDimension = ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW; if (getDataFileType() == DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC) { m_chartLoadingDimension = ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN; } } /** * @return Pointer to the information about last loaded connectivity data. */ const ConnectivityDataLoaded* CiftiMappableConnectivityMatrixDataFile::getConnectivityDataLoaded() const { return m_connectivityDataLoaded; } /** * Get the nodes for the parcel for the given structure that corresponds * to the last selected row. * * @param parcelNodesOut * Ouput containing the node indices. * @param structure * The surface structure. */ bool CiftiMappableConnectivityMatrixDataFile::getParcelNodesElementForSelectedParcel(std::set &parcelNodesOut, const StructureEnum::Enum &structure) const { bool validFlag = false; int64_t rowIndex = -1; int64_t columnIndex = -1; m_connectivityDataLoaded->getRowColumnLoading(rowIndex, columnIndex); if (rowIndex >= 0) { validFlag = CiftiMappableDataFile::getParcelNodesElementForSelectedParcel(parcelNodesOut, structure, rowIndex); } return validFlag; } /** * @return Is this file empty? */ bool CiftiMappableConnectivityMatrixDataFile::isEmpty() const { if (CiftiMappableDataFile::isEmpty()) { return true; } return false; } /** * @return Is loading of data enabled. Note that if * disabled, any previously loaded data is NOT removed * so that it can still be displayed but not updated. */ bool CiftiMappableConnectivityMatrixDataFile::isMapDataLoadingEnabled(const int32_t /*mapIndex*/) const { return m_dataLoadingEnabled; } /** * Set loading of data enabled. Note that if * disabled, any previously loaded data is NOT removed * so that it can still be displayed but not updated. * * @param dataLoadingEnabled * New data loading enabled status. */ void CiftiMappableConnectivityMatrixDataFile::setMapDataLoadingEnabled(const int32_t /*mapIndex*/, const bool dataLoadingEnabled) { m_dataLoadingEnabled = dataLoadingEnabled; } /** * Get the data for the given map index. * * @param mapIndex * Index of the map. * @param dataOut * A vector that will contain the data for the map upon exit. */ void CiftiMappableConnectivityMatrixDataFile::getMapData(const int32_t /*mapIndex*/, std::vector& dataOut) const { if (!isEnabledAsLayer()) {//TSC: HACK to make identification show empty string instead of number when dynconn is used, then set to not load, not layer dataOut.clear(); } else { dataOut = m_loadedRowData; } } /** * Get the index of a row or column when loading data for a surface node. * * @param structure * Structure of the surface. * @param surfaceNumberOfNodes * Number of nodes in the surface. * @param nodeIndex * Index of the node. * @param rowIndexOut * Index of row corresponding to node or -1 if no row in the * matrix corresponds to the node. * @param columnIndexOut * Index of column corresponding to node or -1 if no column in the * matrix corresponds to the node. */ void CiftiMappableConnectivityMatrixDataFile::getRowColumnIndexForNodeWhenLoading(const StructureEnum::Enum structure, const int64_t surfaceNumberOfNodes, const int64_t nodeIndex, int64_t& rowIndexOut, int64_t& columnIndexOut) { rowIndexOut = -1; columnIndexOut = -1; if (m_ciftiFile == NULL) { return; } const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); const int32_t ciftiDirection = getCifitDirectionForLoadingRowOrColumn(); /* * Make sure number of nodes matches. */ switch (ciftiXML.getMappingType(ciftiDirection)) { case CiftiMappingType::BRAIN_MODELS: if (ciftiXML.getBrainModelsMap(ciftiDirection).getSurfaceNumberOfNodes(structure) != surfaceNumberOfNodes) return; break; case CiftiMappingType::PARCELS: if (ciftiXML.getParcelsMap(ciftiDirection).getSurfaceNumberOfNodes(structure) != surfaceNumberOfNodes) return; break; default: return; } /* * Get the mapping type */ const CiftiMappingType::MappingType rowMappingType = ciftiXML.getMappingType(ciftiDirection); int64_t rowOrColumnIndex = -1; /* * Get the row/column index for the node. */ switch (rowMappingType) { case CiftiMappingType::BRAIN_MODELS: rowOrColumnIndex = ciftiXML.getBrainModelsMap(ciftiDirection).getIndexForNode(nodeIndex, structure); break; case CiftiMappingType::PARCELS: rowOrColumnIndex = ciftiXML.getParcelsMap(ciftiDirection).getIndexForNode(nodeIndex, structure); break; case CiftiMappingType::SCALARS: break; case CiftiMappingType::SERIES: break; default: CaretAssert(0); CaretLogSevere("Invalid row mapping type for connectivity file " + DataFileTypeEnum::toName(getDataFileType())); break; } switch (ciftiDirection) { case CiftiXML::ALONG_COLUMN: rowIndexOut = rowOrColumnIndex; break; case CiftiXML::ALONG_ROW: columnIndexOut = rowOrColumnIndex; break; default: CaretAssert(0); break; } } /** * Get the indices for rows or columns when loading data for a surface nodes. * * @param structure * Structure of the surface. * @param surfaceNumberOfNodes * Number of nodes in the surface. * @param nodeIndices * Indices of the node. * @param rowIndicesOut * Indices of row corresponding to node or empty if no data for rows. * @param columnIndicesOut * Index of column corresponding to node or empty if no data for columns */ void CiftiMappableConnectivityMatrixDataFile::getRowColumnIndicesForNodesWhenLoading(const StructureEnum::Enum structure, const int64_t surfaceNumberOfNodes, const std::vector& nodeIndices, std::vector& rowIndicesOut, std::vector& columnIndicesOut) { rowIndicesOut.clear(); columnIndicesOut.clear(); for (std::vector::const_iterator iter = nodeIndices.begin(); iter != nodeIndices.end(); iter++) { int64_t columnIndex = -1; int64_t rowIndex = -1; getRowColumnIndexForNodeWhenLoading(structure, surfaceNumberOfNodes, *iter, rowIndex, columnIndex); if (rowIndex >= 0) { rowIndicesOut.push_back(rowIndex); } else if (columnIndex >= 0) { columnIndicesOut.push_back(columnIndex); } } } /** * Get the average for or column for the given row/column indices. * * @param rowIndices * Indices of the row. * @param columnIndices * Indices of the column. * @param rowAverageOut * Average values for rows. * @param columnAverageOut * Average value for columns. */ void CiftiMappableConnectivityMatrixDataFile::getRowColumnAverageForIndices(const std::vector& rowIndices, const std::vector& columnIndices, std::vector& rowAverageOut, std::vector& columnAverageOut) { columnAverageOut.clear(); rowAverageOut.clear(); int64_t dataLength = 0; std::vector indices; bool doRowsFlag = false; if (! rowIndices.empty()) { dataLength = m_ciftiFile->getNumberOfColumns(); indices = rowIndices; doRowsFlag = true; } else if ( ! columnIndices.empty()) { dataLength = m_ciftiFile->getNumberOfRows(); indices = columnIndices; } const int64_t numIndices = static_cast(indices.size()); if (numIndices > 0) { std::vector sum(dataLength, 0.0); std::vector data(dataLength); for (std::vector::const_iterator iter = indices.begin(); iter != indices.end(); iter++) { if (doRowsFlag) { getDataForRow(&data[0], *iter); } else { getDataForColumn(&data[0], *iter); } for (int64_t i = 0; i < dataLength; i++) { CaretAssertVectorIndex(sum, i); CaretAssertVectorIndex(data, i); sum[i] += data[i]; } } CaretAssert(dataLength > 0); std::vector average(dataLength); const float floatNumIndices = numIndices; //dataLength; for (int64_t i = 0; i < dataLength; i++) { CaretAssertVectorIndex(average, i); CaretAssertVectorIndex(sum, i); average[i] = sum[i] / floatNumIndices; } if (doRowsFlag) { rowAverageOut = average; } else { columnAverageOut = average; } } } /** * @return The CIFTI Direction (ALONG_COLUMN, ALONG_ROW) for loading data. */ int32_t CiftiMappableConnectivityMatrixDataFile::getCifitDirectionForLoadingRowOrColumn() { /* * Default to loading by row (ALONG_COLUMN) which is how the files normally load. */ int32_t ciftiDirection = CiftiXML::ALONG_COLUMN; /** * Parcel File is able to load by either and implements the * ChartableMatrixInterface. */ ChartableMatrixParcelInterface* matrixParcelInterface = dynamic_cast(this); if (matrixParcelInterface != NULL) { switch (matrixParcelInterface->getMatrixLoadingDimension()) { case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: ciftiDirection = CiftiXML::ALONG_ROW; break; case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: ciftiDirection = CiftiXML::ALONG_COLUMN; break; } } return ciftiDirection; } /** * Get the index of a row or column when loading data for a voxel at a coordinate. * @param xyz * Coordinate of the voxel. * @param rowIndexOut * Index of row corresponding to voxel or -1 if no row in the * matrix corresponds to the voxel. * @param columnIndexOut * Index of column corresponding to voxel or -1 if no column in the * matrix corresponds to the voxel. */ void CiftiMappableConnectivityMatrixDataFile::getRowColumnIndexForVoxelAtCoordinateWhenLoading(const float xyz[3], int64_t& rowIndexOut, int64_t& columnIndexOut) { rowIndexOut = -1; columnIndexOut = -1; if (m_ciftiFile == NULL) { return; } int64_t ijk[3]; if (getDataFileType() == DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC) { enclosingVoxel(xyz[0], xyz[1], xyz[2], ijk[0], ijk[1], ijk[2]); } else { enclosingVoxelForDataLoading(xyz[0], xyz[1], xyz[2], ijk[0], ijk[1], ijk[2]); } return getRowColumnIndexForVoxelIndexWhenLoading(ijk, rowIndexOut, columnIndexOut); } /** * Get the index of a row or column when loading data for a voxel index. * @param ijk * Indicies of the voxel. * @param rowIndexOut * Index of row corresponding to voxel or -1 if no row in the * matrix corresponds to the voxel. * @param columnIndexOut * Index of column corresponding to voxel or -1 if no column in the * matrix corresponds to the voxel. */ void CiftiMappableConnectivityMatrixDataFile::getRowColumnIndexForVoxelIndexWhenLoading(const int64_t ijk[3], int64_t& rowIndexOut, int64_t& columnIndexOut) { rowIndexOut = -1; columnIndexOut = -1; if (m_ciftiFile == NULL) { return; } const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); const int32_t ciftiDirection = getCifitDirectionForLoadingRowOrColumn(); const CiftiMappingType::MappingType rowMappingType = ciftiXML.getMappingType(CiftiXML::ALONG_COLUMN); int64_t rowOrColumnIndex = -1; /* * Get the mapping type */ const bool indexValidFlag = ((getDataFileType() == DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC) ? indexValid(ijk[0], ijk[1], ijk[2]) : indexValidForDataLoading(ijk[0], ijk[1], ijk[2])); if (indexValidFlag) { switch (rowMappingType) { case CiftiMappingType::BRAIN_MODELS: rowOrColumnIndex = ciftiXML.getBrainModelsMap(ciftiDirection).getIndexForVoxel(ijk); break; case CiftiMappingType::PARCELS: rowOrColumnIndex = ciftiXML.getParcelsMap(ciftiDirection).getIndexForVoxel(ijk); break; default: CaretAssert(0); CaretLogSevere("Invalid row mapping type for connectivity file " + DataFileTypeEnum::toName(getDataFileType())); break; } } switch (ciftiDirection) { case CiftiXML::ALONG_COLUMN: rowIndexOut = rowOrColumnIndex; break; case CiftiXML::ALONG_ROW: columnIndexOut = rowOrColumnIndex; break; default: CaretAssert(0); break; } } /** * Set the loaded row data to zeros. */ void CiftiMappableConnectivityMatrixDataFile::setLoadedRowDataToAllZeros() { if ( ! m_loadedRowData.empty()){ std::fill(m_loadedRowData.begin(), m_loadedRowData.end(), 0.0); } updateForChangeInMapDataWithMapIndex(0); m_connectivityDataLoaded->reset(); m_rowLoadedText.clear(); m_rowLoadedTextForMapName.clear(); } /** * Reset the loaded row data to empty. * * Resets the loaded row data to zero elements and also * clears loaded data attributes. * * One usage of this method is when a parcel connectivity file has * its loading direction changed between row and parcel loading. */ void CiftiMappableConnectivityMatrixDataFile::resetLoadedRowDataToEmpty() { m_loadedRowData.clear(); setLoadedRowDataToAllZeros(); } /** * Load raw data for the given column. * * @param dataOut * Output with data. * @param index of the column. */ void CiftiMappableConnectivityMatrixDataFile::getDataForColumn(float* dataOut, const int64_t& index) const { m_ciftiFile->getColumn(dataOut, index); } /** * Load data for the given row. * * @param dataOut * Output with data. * @param index of the row. */ void CiftiMappableConnectivityMatrixDataFile::getDataForRow(float* dataOut, const int64_t& index) const { m_ciftiFile->getRow(dataOut, index); } /** * Load PROCESSED data for the given column. * * Some file types may have special processing for a column. This method can be * overridden for those types of files. * * @param dataOut * Output with data. * @param index of the column. */ void CiftiMappableConnectivityMatrixDataFile::getProcessedDataForColumn(float* dataOut, const int64_t& index) const { m_ciftiFile->getColumn(dataOut, index); } /** * Load PROCESSED data for the given row. * * Some file types may have special processing for a row. This method can be * overridden for those types of files. * * @param dataOut * Output with data. * @param index of the row. */ void CiftiMappableConnectivityMatrixDataFile::getProcessedDataForRow(float* dataOut, const int64_t& index) const { m_ciftiFile->getRow(dataOut, index); } /** * Some file types may perform additional processing of row average data and * can override this method. * * @param rowAverageData * The row average data. */ void CiftiMappableConnectivityMatrixDataFile::processRowAverageData(std::vector& /*rowAverageData*/) { /* This method may be overridden by subclasses */ } /** * Load the given row from the file even if the file is disabled. * * NOTE: Afterwards, it will be necessary to update this file's color mapping * with updateScalarColoringForMap(). * * * @param rowIndex * Index of row that is loaded. * @throw DataFileException * If an error occurs. */ void CiftiMappableConnectivityMatrixDataFile::loadDataForRowIndex(const int64_t rowIndex) { setLoadedRowDataToAllZeros(); const int64_t dataCount = m_ciftiFile->getNumberOfColumns(); if (dataCount > 0) { if ((rowIndex >= 0) && (rowIndex < m_ciftiFile->getNumberOfRows())) { m_rowLoadedTextForMapName = ("Row: " + AString::number(rowIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI)); m_rowLoadedText = ("Row_" + AString::number(rowIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI)); CaretAssert((rowIndex >= 0) && (rowIndex < m_ciftiFile->getNumberOfRows())); m_loadedRowData.resize(dataCount); getProcessedDataForRow(&m_loadedRowData[0], rowIndex); CaretLogFine("Read row " + AString::number(rowIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI)); m_connectivityDataLoaded->setRowColumnLoading(rowIndex, -1); } } updateForChangeInMapDataWithMapIndex(0); } /** * Load the given column from the file even if the file is disabled. * * NOTE: Afterwards, it will be necessary to update this file's color mapping * with updateScalarColoringForMap(). * * * @param columnIndex * Index of row that is loaded. * @throw DataFileException * If an error occurs. */ void CiftiMappableConnectivityMatrixDataFile::loadDataForColumnIndex(const int64_t columnIndex) { setLoadedRowDataToAllZeros(); const int64_t dataCount = m_ciftiFile->getNumberOfRows(); if (dataCount > 0) { if ((columnIndex >= 0) && (columnIndex < m_ciftiFile->getNumberOfColumns())) { m_rowLoadedTextForMapName = ("Column: " + AString::number(columnIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI)); m_rowLoadedText = ("Column_" + AString::number(columnIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI)); CaretAssert((columnIndex >= 0) && (columnIndex < m_ciftiFile->getNumberOfColumns())); m_loadedRowData.resize(dataCount); getProcessedDataForColumn(&m_loadedRowData[0], columnIndex); CaretLogFine("Read column " + AString::number(columnIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI)); m_connectivityDataLoaded->setRowColumnLoading(-1, columnIndex); } } updateForChangeInMapDataWithMapIndex(0); } /** * Load connectivity data for the surface's node. * * @param mapIndex * Index of map. * @param surfaceNumberOfNodes * Number of nodes in surface. * @param structure * Surface's structure. * @param nodeIndex * Index of node number. * @param rowIndexOut * Index of row corresponding to node or -1 if no row in the * matrix corresponds to the node. * @param columnIndexOut * Index of column corresponding to node or -1 if no column in the * matrix corresponds to the node. * @throw * DataFileException if there is an error. */ void CiftiMappableConnectivityMatrixDataFile::loadMapDataForSurfaceNode(const int32_t /*mapIndex*/, const int32_t surfaceNumberOfNodes, const StructureEnum::Enum structure, const int32_t nodeIndex, int64_t& rowIndexOut, int64_t& columnIndexOut) { if (!isEnabledAsLayer()) { return;//TSC: HACK to do nothing when dynconn layer is disabled } ElapsedTimer timer; timer.start(); rowIndexOut = -1; columnIndexOut = -1; if (m_ciftiFile == NULL) { setLoadedRowDataToAllZeros(); return; } /* * Loading of data disabled? */ if (m_dataLoadingEnabled == false) { return; } /* * Zero out here so that data only gets cleared when data * is to be loaded. */ setLoadedRowDataToAllZeros(); int64_t rowIndex = -1; int64_t columnIndex = -1; try { bool dataWasLoaded = false; getRowColumnIndexForNodeWhenLoading(structure, surfaceNumberOfNodes, nodeIndex, rowIndex, columnIndex); if (rowIndex >= 0) { int64_t dataCount = m_ciftiFile->getNumberOfColumns(); if (getDataFileType() == DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC) { /* * Dense dynamic is special case where number of rows equals number of brainordinates. * Number of columns is number of time points */ dataCount = m_ciftiFile->getNumberOfRows(); } if (dataCount > 0) { m_rowLoadedTextForMapName = ("Row: " + AString::number(rowIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI) + ", Vertex Index: " + AString::number(nodeIndex) + ", Structure: " + StructureEnum::toName(structure)); m_rowLoadedText = ("Row_" + AString::number(rowIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI) + "_Vertex_Index_" + AString::number(nodeIndex) + "_Structure_" + StructureEnum::toGuiName(structure)); CaretAssert((rowIndex >= 0) && (rowIndex < m_ciftiFile->getNumberOfRows())); m_loadedRowData.resize(dataCount); getProcessedDataForRow(&m_loadedRowData[0], rowIndex); CaretLogFine("Read row for vertex " + AString::number(nodeIndex)); m_connectivityDataLoaded->setSurfaceNodeLoading(structure, surfaceNumberOfNodes, nodeIndex, rowIndex, -1); rowIndexOut = rowIndex; dataWasLoaded = true; } } else if (columnIndex >= 0) { const int64_t dataCount = m_ciftiFile->getNumberOfRows(); if (dataCount > 0) { m_rowLoadedTextForMapName = ("Column: " + AString::number(columnIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI) + ", Vertex Index: " + AString::number(nodeIndex) + ", Structure: " + StructureEnum::toName(structure)); m_rowLoadedText = ("Column_" + AString::number(columnIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI) + "_Vertex_Index_" + AString::number(nodeIndex) + "_Structure_" + StructureEnum::toGuiName(structure)); CaretAssert((columnIndex >= 0) && (columnIndex < m_ciftiFile->getNumberOfColumns())); m_loadedRowData.resize(dataCount); getProcessedDataForColumn(&m_loadedRowData[0], columnIndex); CaretLogFine("Read column for vertex " + AString::number(nodeIndex)); m_connectivityDataLoaded->setSurfaceNodeLoading(structure, surfaceNumberOfNodes, nodeIndex, -1, columnIndex); columnIndexOut = columnIndex; dataWasLoaded = true; } } if (dataWasLoaded == false) { CaretLogFine("FAILED to read data for vertex " + AString::number(nodeIndex)); m_connectivityDataLoaded->reset(); } } catch (DataFileException& e) { m_connectivityDataLoaded->reset(); throw e; } updateForChangeInMapDataWithMapIndex(0); AString msg = ("Time load data for surface vertex in " + getFileNameNoPath() + " was " + AString::number(timer.getElapsedTimeSeconds()) + " seconds."); CaretLogFine(msg); } /** * Load connectivity data for the surface's nodes and then average the data. * * @param mapIndex * Index of map. * @param surfaceFile * Surface file used for structure. * @param surfaceNumberOfNodes * Number of nodes in surface. * @param structure * Surface's structure. * @param nodeIndices * Indices of nodes. * @throw * DataFileException if there is an error. */ void CiftiMappableConnectivityMatrixDataFile::loadMapAverageDataForSurfaceNodes(const int32_t /*mapIndex*/, const int32_t surfaceNumberOfNodes, const StructureEnum::Enum structure, const std::vector& nodeIndices) { if (m_ciftiFile == NULL) { setLoadedRowDataToAllZeros(); return; } /* * Loading of data disabled? */ if (m_dataLoadingEnabled == false) { return; } /* * Zero out here so that data only gets cleared when data * is to be loaded. */ setLoadedRowDataToAllZeros(); const int32_t numberOfNodeIndices = static_cast(nodeIndices.size()); if (numberOfNodeIndices <= 0) { return; } std::vector rowIndices, columnIndices; getRowColumnIndicesForNodesWhenLoading(structure, surfaceNumberOfNodes, nodeIndices, rowIndices, columnIndices); if (rowIndices.empty() && columnIndices.empty()) { return; } std::vector rowAverage, columnAverage; getRowColumnAverageForIndices(rowIndices, columnIndices, rowAverage, columnAverage); /* * Update the viewed data */ bool dataWasLoaded = false; if ( ! rowAverage.empty()) { processRowAverageData(rowAverage); m_loadedRowData = rowAverage; dataWasLoaded = true; } else if ( ! columnAverage.empty()) { m_loadedRowData = columnAverage; dataWasLoaded = true; } if (dataWasLoaded) { m_rowLoadedTextForMapName = ("Structure: " + StructureEnum::toName(structure) + ", Averaged Vertex Count: " + AString::number(numberOfNodeIndices)); m_rowLoadedText = ("Structure_" + StructureEnum::toGuiName(structure) + "_Averaged_Vertex_Count_" + AString::number(numberOfNodeIndices)); } if (dataWasLoaded == false) { CaretLogFine("FAILED to read data for vertex average" + AString::fromNumbers(nodeIndices, ",")); } updateForChangeInMapDataWithMapIndex(0); if (dataWasLoaded) { m_connectivityDataLoaded->setSurfaceAverageNodeLoading(structure, surfaceNumberOfNodes, nodeIndices); } } /** * Load data for a voxel at the given coordinate. * * @param mapIndex * Index of map. * @param xyz * Coordinate of voxel. * @param rowIndexOut * Index of row corresponding to voxel or -1 if no row in the * matrix corresponds to the voxel. * @param columnIndexOut * Index of column corresponding to voxel or -1 if no column in the * matrix corresponds to the voxel. * @throw * DataFileException if there is an error. */ void CiftiMappableConnectivityMatrixDataFile::loadMapDataForVoxelAtCoordinate(const int32_t mapIndex, const float xyz[3], int64_t& rowIndexOut, int64_t& columnIndexOut) { rowIndexOut = -1; columnIndexOut = -1; if (mapIndex != 0) { setLoadedRowDataToAllZeros(); CaretAssertMessage(0, "Map index must be zero."); return; } if (m_ciftiFile == NULL) { setLoadedRowDataToAllZeros(); return; } /* * Loading of data disabled? */ if (m_dataLoadingEnabled == false) { return; } /* * Zero out here so that data only gets cleared when data * is to be loaded. */ setLoadedRowDataToAllZeros(); int64_t rowIndex = -1; int64_t columnIndex = -1; bool dataWasLoaded = false; getRowColumnIndexForVoxelAtCoordinateWhenLoading(xyz, rowIndex, columnIndex); if (rowIndex >= 0) { int64_t dataCount = m_ciftiFile->getNumberOfColumns(); if (getDataFileType() == DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC) { /* * Dense dynamic is special case where number of rows equals number of brainordinates. * Number of columns is number of time points */ dataCount = m_ciftiFile->getNumberOfRows(); } if (dataCount > 0) { m_loadedRowData.resize(dataCount); CaretAssert((rowIndex >= 0) && (rowIndex < m_ciftiFile->getNumberOfRows())); getProcessedDataForRow(&m_loadedRowData[0], rowIndex); m_rowLoadedTextForMapName = ("Row: " + AString::number(rowIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI) + ", Voxel XYZ: (" + AString::fromNumbers(xyz, 3, ",") + ")"); m_rowLoadedText = ("Row_" + AString::number(rowIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI) + "_Voxel_XYZ_" + AString::fromNumbers(xyz, 3, "_").replace('-', 'm')); CaretLogFine("Read row for voxel " + AString::fromNumbers(xyz, 3, ",")); rowIndexOut = rowIndex; dataWasLoaded = true; } } else if (columnIndex >= 0) { const int64_t dataCount = m_ciftiFile->getNumberOfRows(); if (dataCount > 0) { m_loadedRowData.resize(dataCount); CaretAssert((columnIndex >= 0) && (columnIndex < m_ciftiFile->getNumberOfColumns())); getProcessedDataForColumn(&m_loadedRowData[0], columnIndex); m_rowLoadedTextForMapName = ("Column: " + AString::number(columnIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI) + ", Voxel XYZ: (" + AString::fromNumbers(xyz, 3, ",") + ")"); m_rowLoadedText = ("Column_" + AString::number(columnIndex + CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI) + "_Voxel_XYZ_" + AString::fromNumbers(xyz, 3, "_").replace('-', 'm')); CaretLogFine("Read column for voxel " + AString::fromNumbers(xyz, 3, ",")); columnIndexOut = columnIndex; dataWasLoaded = true; } } if (dataWasLoaded == false) { CaretLogFine("FAILED to read row/column for voxel " + AString::fromNumbers(xyz, 3, ",")); } updateForChangeInMapDataWithMapIndex(0); m_connectivityDataLoaded->setVolumeXYZLoading(xyz, rowIndex, columnIndex); } /** * Get row/column indices for the given voxel indices for the loading of data. * * @param volumeDimensionIJK * Dimensions of the volume. * @param voxelIndices * Indices of voxels. * @param rowIndicesOut * Indices of row corresponding to node or empty if no data for rows. * @param columnIndicesOut * Index of column corresponding to node or empty if no data for columns */ void CiftiMappableConnectivityMatrixDataFile::getRowColumnIndicesForVoxelsWhenLoading(const int64_t volumeDimensionIJK[3], const std::vector& voxelIndices, std::vector& rowIndicesOut, std::vector& columnIndicesOut) { rowIndicesOut.clear(); columnIndicesOut.clear(); /* * Match dimensions */ std::vector volumeDimensions; getDimensions(volumeDimensions); if (volumeDimensions.size() < 3) { return; } if ((volumeDimensions[0] != volumeDimensionIJK[0]) || (volumeDimensions[1] != volumeDimensionIJK[1]) || (volumeDimensions[2] != volumeDimensionIJK[2])) { return; } for (std::vector::const_iterator iter = voxelIndices.begin(); iter != voxelIndices.end(); iter++) { const VoxelIJK& voxelIJK = *iter; int64_t rowIndex; int64_t columnIndex; getRowColumnIndexForVoxelIndexWhenLoading(voxelIJK.m_ijk, rowIndex, columnIndex); if (rowIndex >= 0) { rowIndicesOut.push_back(rowIndex); } else if (columnIndex >= 0) { columnIndicesOut.push_back(columnIndex); } } } /** * Load connectivity data for the voxel indices and then average the data. * * @param mapIndex * Index of map. * @param volumeDimensionIJK * Dimensions of the volume. * @param voxelIndices * Indices of voxels. * @throw * DataFileException if there is an error. */ bool CiftiMappableConnectivityMatrixDataFile::loadMapAverageDataForVoxelIndices(const int32_t mapIndex, const int64_t volumeDimensionIJK[3], const std::vector& voxelIndices) { if (mapIndex != 0) { // eliminates compilation warning when compiled for release CaretAssert(mapIndex == 0); setLoadedRowDataToAllZeros(); } if (m_ciftiFile == NULL) { setLoadedRowDataToAllZeros(); return false; } /* * Loading of data disabled? */ if (m_dataLoadingEnabled == false) { return false; } /* * Zero out here so that data only gets cleared when data * is to be loaded. */ setLoadedRowDataToAllZeros(); std::vector rowIndices, columnIndices; getRowColumnIndicesForVoxelsWhenLoading(volumeDimensionIJK, voxelIndices, rowIndices, columnIndices); if (rowIndices.empty() && columnIndices.empty()) { return false; } std::vector rowAverage, columnAverage; getRowColumnAverageForIndices(rowIndices, columnIndices, rowAverage, columnAverage); bool dataWasLoadedFlag = false; if ( ! rowAverage.empty()) { processRowAverageData(rowAverage); m_loadedRowData = rowAverage; dataWasLoadedFlag = true; } else if ( ! columnAverage.empty()) { m_loadedRowData = columnAverage; dataWasLoadedFlag = true; } // if (userCancelled) { // m_loadedRowData.clear(); // m_loadedRowData.resize(dataCount, 0.0); // } if (dataWasLoadedFlag) { // progressEvent.setProgress(numberOfVoxelIndices - 1, // "Averaging voxel data"); // EventManager::get()->sendEvent(progressEvent.getPointer()); const int32_t numberOfVoxelIndices = static_cast(voxelIndices.size()); m_rowLoadedTextForMapName = ("Averaged Voxel Count: " + AString::number(numberOfVoxelIndices)); m_rowLoadedText = ("Averaged_Voxel_Count_" + AString::number(numberOfVoxelIndices)); m_connectivityDataLoaded->setVolumeAverageVoxelLoading(volumeDimensionIJK, voxelIndices); } updateForChangeInMapDataWithMapIndex(0); return dataWasLoadedFlag; } /** * @return Text describing row loaded that uses * underscores as separators. */ AString CiftiMappableConnectivityMatrixDataFile::getRowLoadedText() const { return m_rowLoadedText; } /** * Get the name of the map at the given index. For connectivity matrix * files this always returns a description of the last data row that * was loaded. * * @param mapIndex * Index of the map. * @return * Name of the map. */ AString CiftiMappableConnectivityMatrixDataFile::getMapName(const int32_t /*mapIndex*/) const { return m_rowLoadedTextForMapName; } /** * @return True if the number of rows and columns is identical * and the row and column names are identical for the same index * (row "i" name is same as column "i" name for all rows/columns). */ bool CiftiMappableConnectivityMatrixDataFile::hasSymetricRowColumnNames() const { const CiftiXML& xml = m_ciftiFile->getCiftiXML(); if ((xml.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::PARCELS) && (xml.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::PARCELS)) { const std::vector& rowParcels = xml.getParcelsMap(CiftiXML::ALONG_COLUMN).getParcels(); const std::vector& columnParcels = xml.getParcelsMap(CiftiXML::ALONG_ROW).getParcels(); if (rowParcels.size() == columnParcels.size()) { const int numRowsColumns = static_cast(rowParcels.size()); if (numRowsColumns > 0) { for (int32_t i = 0; i < numRowsColumns; i++) { CaretAssertVectorIndex(rowParcels, i); CaretAssertVectorIndex(columnParcels, i); if (rowParcels[i].m_name != columnParcels[i].m_name) { return false; } } return true; } } } return false; } AString CiftiMappableConnectivityMatrixDataFile::getRowName(const int32_t rowIndex) const { const CiftiXML& xml = m_ciftiFile->getCiftiXML(); if (xml.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::PARCELS) return "";//TSC: this was originally implemented only for parcels, dunno why const std::vector& plist = xml.getParcelsMap(CiftiXML::ALONG_COLUMN).getParcels(); CaretAssertVectorIndex(plist, rowIndex); return plist[rowIndex].m_name; } AString CiftiMappableConnectivityMatrixDataFile::getColumnName(const int32_t columnIndex) const { const CiftiXML& xml = m_ciftiFile->getCiftiXML(); if (xml.getMappingType(CiftiXML::ALONG_ROW) != CiftiMappingType::PARCELS) return "";//ditto const std::vector& plist = xml.getParcelsMap(CiftiXML::ALONG_ROW).getParcels(); CaretAssertVectorIndex(plist, columnIndex); return plist[columnIndex].m_name; } /** * @return The matrix loading type (by row/column). */ ChartMatrixLoadingDimensionEnum::Enum CiftiMappableConnectivityMatrixDataFile::getChartMatrixLoadingDimension() const { return m_chartLoadingDimension; } /** * Set the matrix loading type (by row/column). * * @param matrixLoadingType * New value for matrix loading type. */ void CiftiMappableConnectivityMatrixDataFile::setChartMatrixLoadingDimension(const ChartMatrixLoadingDimensionEnum::Enum matrixLoadingType) { m_chartLoadingDimension = matrixLoadingType; resetDataLoadingMembers(); switch (m_chartLoadingDimension) { case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: m_dataReadingAccessMethod = DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW; m_dataMappingAccessMethod = DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN; break; case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: m_dataReadingAccessMethod = DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN; m_dataMappingAccessMethod = DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW; break; } initializeAfterReading(getFileName()); resetLoadedRowDataToEmpty(); } /** * Save file data from the scene. For subclasses that need to * save to a scene, this method should be overriden. sceneClass * will be valid and any scene data should be added to it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. */ void CiftiMappableConnectivityMatrixDataFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { CiftiMappableDataFile::saveFileDataToScene(sceneAttributes, sceneClass); sceneClass->addEnumeratedType("m_chartLoadingDimension", m_chartLoadingDimension); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); saveSubClassDataToScene(sceneAttributes, sceneClass); } /** * Restore file data from the scene. For subclasses that need to * restore from a scene, this method should be overridden. The scene class * will be valid and any scene data may be obtained from it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void CiftiMappableConnectivityMatrixDataFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { CiftiMappableDataFile::restoreFileDataFromScene(sceneAttributes, sceneClass); m_connectivityDataLoaded->reset(); /* * The chart loading dimension is restored by the scene assistant but * we need to call setChartMatrixLoadingDimension() so that loading * by row or column is properly setup. */ m_chartLoadingDimension = sceneClass->getEnumeratedTypeValue("m_chartLoadingDimension", ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW); setChartMatrixLoadingDimension(m_chartLoadingDimension); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); restoreSubClassDataFromScene(sceneAttributes, sceneClass); /* * Loading of data may be disabled in the scene * so temporarily enabled loading and then * restore the status. */ const int32_t mapIndex = 0; const bool loadingEnabledStatus = isMapDataLoadingEnabled(mapIndex); setMapDataLoadingEnabled(mapIndex, true); switch (m_connectivityDataLoaded->getMode()) { case ConnectivityDataLoaded::MODE_NONE: setLoadedRowDataToAllZeros(); break; case ConnectivityDataLoaded::MODE_ROW: { int64_t rowIndex; int64_t columnIndex; m_connectivityDataLoaded->getRowColumnLoading(rowIndex, columnIndex); loadDataForRowIndex(rowIndex); } break; case ConnectivityDataLoaded::MODE_COLUMN: { int64_t rowIndex; int64_t columnIndex; m_connectivityDataLoaded->getRowColumnLoading(rowIndex, columnIndex); loadDataForColumnIndex(columnIndex); } break; case ConnectivityDataLoaded::MODE_SURFACE_NODE: { StructureEnum::Enum structure; int32_t surfaceNumberOfNodes; int32_t surfaceNodeIndex; int64_t rowIndex; int64_t columnIndex; m_connectivityDataLoaded->getSurfaceNodeLoading(structure, surfaceNumberOfNodes, surfaceNodeIndex, rowIndex, columnIndex); loadMapDataForSurfaceNode(mapIndex, surfaceNumberOfNodes, structure, surfaceNodeIndex, rowIndex, columnIndex); } break; case ConnectivityDataLoaded::MODE_SURFACE_NODE_AVERAGE: { StructureEnum::Enum structure; int32_t surfaceNumberOfNodes; std::vector surfaceNodeIndices; m_connectivityDataLoaded->getSurfaceAverageNodeLoading(structure, surfaceNumberOfNodes, surfaceNodeIndices); loadMapAverageDataForSurfaceNodes(mapIndex, surfaceNumberOfNodes, structure, surfaceNodeIndices); } break; case ConnectivityDataLoaded::MODE_VOXEL_XYZ: { float volumeXYZ[3]; int64_t rowIndex; int64_t columnIndex; m_connectivityDataLoaded->getVolumeXYZLoading(volumeXYZ, rowIndex, columnIndex); loadMapDataForVoxelAtCoordinate(mapIndex, volumeXYZ, rowIndex, columnIndex); } break; case ConnectivityDataLoaded::MODE_VOXEL_IJK_AVERAGE: { int64_t volumeDimensionsIJK[3]; std::vector voxelIndicesIJK; m_connectivityDataLoaded->getVolumeAverageVoxelLoading(volumeDimensionsIJK, voxelIndicesIJK); loadMapAverageDataForVoxelIndices(mapIndex, volumeDimensionsIJK, voxelIndicesIJK); } break; } setMapDataLoadingEnabled(mapIndex, loadingEnabledStatus); } /** * Save subclass data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void CiftiMappableConnectivityMatrixDataFile::saveSubClassDataToScene(const SceneAttributes* /*sceneAttributes*/, SceneClass* /*sceneClass*/) { /* This method is intended only for subclasses to override */ } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void CiftiMappableConnectivityMatrixDataFile::restoreSubClassDataFromScene(const SceneAttributes* /*sceneAttributes*/, const SceneClass* /*sceneClass*/) { /* This method is intended only for subclasses to override */ } connectome-workbench-1.4.2/src/Files/CiftiMappableConnectivityMatrixDataFile.h000066400000000000000000000216211360521144700275150ustar00rootroot00000000000000#ifndef __CIFTI_MAPPABLE_CONNECTIVITY_MATRIX_DATA_FILE_H__ #define __CIFTI_MAPPABLE_CONNECTIVITY_MATRIX_DATA_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "BrainConstants.h" #include "ChartMatrixLoadingDimensionEnum.h" #include "CiftiMappableDataFile.h" #include "VoxelIJK.h" namespace caret { class ConnectivityDataLoaded; class SceneClassAssistant; class CiftiMappableConnectivityMatrixDataFile : public CiftiMappableDataFile { protected: CiftiMappableConnectivityMatrixDataFile(const DataFileTypeEnum::Enum dataFileType); public: virtual ~CiftiMappableConnectivityMatrixDataFile(); bool isMapDataLoadingEnabled(const int32_t mapIndex) const; void setMapDataLoadingEnabled(const int32_t mapIndex, const bool enabled); virtual void loadMapDataForSurfaceNode(const int32_t mapIndex, const int32_t surfaceNumberOfNodes, const StructureEnum::Enum structure, const int32_t nodeIndex, int64_t& rowIndexOut, int64_t& columnIndexOut); virtual void loadMapAverageDataForSurfaceNodes(const int32_t mapIndex, const int32_t surfaceNumberOfNodes, const StructureEnum::Enum structure, const std::vector& nodeIndices); virtual void loadMapDataForVoxelAtCoordinate(const int32_t mapIndex, const float xyz[3], int64_t& rowIndexOut, int64_t& columnIndexOut); virtual bool loadMapAverageDataForVoxelIndices(const int32_t mapIndex, const int64_t volumeDimensionIJK[3], const std::vector& voxelIndices); void loadDataForRowIndex(const int64_t rowIndex); void loadDataForColumnIndex(const int64_t rowIndex); virtual void clear(); virtual bool isEmpty() const; virtual AString getMapName(const int32_t mapIndex) const; bool hasSymetricRowColumnNames() const; AString getRowName(const int32_t rowIndex) const; AString getColumnName(const int32_t rowIndex) const; AString getRowLoadedText() const; virtual void getMapData(const int32_t mapIndex, std::vector& dataOut) const; const ConnectivityDataLoaded* getConnectivityDataLoaded() const; bool getParcelNodesElementForSelectedParcel(std::set &parcelNodesOut, const StructureEnum::Enum &structure) const; ChartMatrixLoadingDimensionEnum::Enum getChartMatrixLoadingDimension() const; //TSC: HACK to expose dynconn enabled as layer status virtual bool isEnabledAsLayer() const { return true; } private: CiftiMappableConnectivityMatrixDataFile(const CiftiMappableConnectivityMatrixDataFile&); CiftiMappableConnectivityMatrixDataFile& operator=(const CiftiMappableConnectivityMatrixDataFile&); public: // ADD_NEW_METHODS_HERE protected: virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); void resetLoadedRowDataToEmpty(); void setChartMatrixLoadingDimension(const ChartMatrixLoadingDimensionEnum::Enum matrixLoadingType); virtual void getProcessedDataForColumn(float* dataOut, const int64_t& index) const; virtual void getProcessedDataForRow(float* dataOut, const int64_t& index) const; virtual void getDataForColumn(float* dataOut, const int64_t& index) const; virtual void getDataForRow(float* dataOut, const int64_t& index) const; virtual void processRowAverageData(std::vector& rowAverageData); private: void setLoadedRowDataToAllZeros(); void clearPrivate(); void getRowColumnIndexForNodeWhenLoading(const StructureEnum::Enum structure, const int64_t surfaceNumberOfNodes, const int64_t nodeIndex, int64_t& rowIndexOut, int64_t& columnIndexOut); void getRowColumnIndicesForNodesWhenLoading(const StructureEnum::Enum structure, const int64_t surfaceNumberOfNodes, const std::vector& nodeIndices, std::vector& rowIndicesOut, std::vector& columnIndicesOut); void getRowColumnAverageForIndices(const std::vector& rowIndices, const std::vector& columnIndices, std::vector& rowAverageOut, std::vector& columnAverageOut); void getRowColumnIndicesForVoxelsWhenLoading(const int64_t volumeDimensionIJK[3], const std::vector& voxelIndices, std::vector& rowIndicesOut, std::vector& columnIndicesOut); void getRowColumnIndexForVoxelAtCoordinateWhenLoading(const float xyz[3], int64_t& rowIndexOut, int64_t& columnIndexOut); void getRowColumnIndexForVoxelIndexWhenLoading(const int64_t ijk[3], int64_t& rowIndexOut, int64_t& columnIndexOut); int32_t getCifitDirectionForLoadingRowOrColumn(); // ADD_NEW_MEMBERS_HERE SceneClassAssistant* m_sceneAssistant; bool m_dataLoadingEnabled; std::vector m_loadedRowData; AString m_rowLoadedTextForMapName; AString m_rowLoadedText; ConnectivityDataLoaded* m_connectivityDataLoaded; /* * This is really a member of parcel file since it the parcel * file is the only file that can load by row or column. * However, because of scenes, the chart loading dimension needs * to be restored in this class. */ ChartMatrixLoadingDimensionEnum::Enum m_chartLoadingDimension; friend class CiftiBrainordinateScalarFile; }; #ifdef __CIFTI_MAPPABLE_CONNECTIVITY_MATRIX_DATA_FILE_DECLARE__ // #endif // __CIFTI_MAPPABLE_CONNECTIVITY_MATRIX_DATA_FILE_DECLARE__ } // namespace #endif //__CIFTI_MAPPABLE_CONNECTIVITY_MATRIX_DATA_FILE_H__ connectome-workbench-1.4.2/src/Files/CiftiMappableDataFile.cxx000066400000000000000000011261321360521144700243100ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CIFTI_MAPPABLE_DATA_FILE_DECLARE__ #include "CiftiMappableDataFile.h" #undef __CIFTI_MAPPABLE_DATA_FILE_DECLARE__ #include "BackgroundAndForegroundColors.h" #include "BoundingBox.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPreferences.h" #include "ChartDataCartesian.h" #include "CiftiBrainordinateLabelFile.h" #include "CiftiBrainordinateScalarFile.h" #include "CiftiConnectivityMatrixParcelFile.h" #include "CiftiFiberTrajectoryFile.h" #include "CiftiFile.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "CaretMappableDataFileAndMapSelectionModel.h" #include "CiftiParcelLabelFile.h" #include "CiftiParcelReordering.h" #include "CiftiParcelScalarFile.h" #include "CiftiParcelSeriesFile.h" #include "CiftiScalarDataSeriesFile.h" #include "CaretTemporaryFile.h" #include "CiftiXML.h" #include "ConnectivityDataLoaded.h" #include "DataFileContentInformation.h" #include "EventManager.h" #include "EventCaretPreferencesGet.h" #include "EventSurfaceColoringInvalidate.h" #include "FastStatistics.h" #include "FileInformation.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "GiftiMetaData.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GroupAndNameHierarchyModel.h" #include "Histogram.h" #include "MapFileDataSelector.h" #include "NodeAndVoxelColoring.h" #include "PaletteColorMapping.h" #include "SparseVolumeIndexer.h" using namespace caret; /** * \class caret::CiftiMappableDataFile * \brief Abstract class for CIFTI files that are mapped to surfaces and volumes * \ingroup Files */ /** * Constructor. * * @param dataFileType * Type of data file. */ CiftiMappableDataFile::CiftiMappableDataFile(const DataFileTypeEnum::Enum dataFileType) : CaretMappableDataFile(dataFileType) { m_ciftiFile.grabNew(NULL); m_voxelIndicesToOffsetForDataReading.grabNew(NULL); m_voxelIndicesToOffsetForDataMapping.grabNew(NULL); m_classNameHierarchy.grabNew(NULL); m_fileDataReadingType = FILE_READ_DATA_ALL; switch (CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI) { case 0: case 1: break; default: CaretAssertMessage(0, "CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI must be zero or one!"); break; } m_containsSurfaceData = false; m_containsVolumeData = false; m_mappingTimeStart = 0.0f; m_mappingTimeStep = 1.0f; m_mappingTimeUnits = NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN; m_dataReadingAccessMethod = DATA_ACCESS_METHOD_INVALID; m_dataMappingAccessMethod = DATA_ACCESS_METHOD_INVALID; m_colorMappingMethod = COLOR_MAPPING_METHOD_INVALID; m_paletteColorMappingSource = PALETTE_COLOR_MAPPING_SOURCE_INVALID; m_fileMapDataType = FILE_MAP_DATA_TYPE_INVALID; m_dataMappingDirectionForCiftiXML = S_CIFTI_XML_ALONG_INVALID; m_dataReadingDirectionForCiftiXML = S_CIFTI_XML_ALONG_INVALID; m_fileFastStatistics.grabNew(NULL); m_fileHistogram.grabNew(NULL); m_fileHistorgramLimitedValues.grabNew(NULL); /* * Note: The first palette normalization mode is assumed to * be the default mode. */ m_paletteNormalizationModesSupported.clear(); /* * Note: Force an update of the class and name hierarchy */ m_forceUpdateOfGroupAndNameHierarchy = true; switch (dataFileType) { case DataFileTypeEnum::CONNECTIVITY_DENSE: m_dataReadingAccessMethod = DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN; m_dataMappingAccessMethod = DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW; m_colorMappingMethod = COLOR_MAPPING_METHOD_PALETTE; m_paletteColorMappingSource = PALETTE_COLOR_MAPPING_SOURCE_FROM_FILE; m_paletteNormalizationModesSupported.push_back(PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA); m_fileMapDataType = FILE_MAP_DATA_TYPE_MATRIX; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: m_dataReadingAccessMethod = DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW; m_dataMappingAccessMethod = DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN; m_colorMappingMethod = COLOR_MAPPING_METHOD_PALETTE; m_paletteColorMappingSource = PALETTE_COLOR_MAPPING_SOURCE_FROM_FILE; m_paletteNormalizationModesSupported.push_back(PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA); m_fileMapDataType = FILE_MAP_DATA_TYPE_MATRIX; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: m_dataReadingAccessMethod = DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW; m_dataMappingAccessMethod = DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN; m_colorMappingMethod = COLOR_MAPPING_METHOD_LABEL_TABLE; m_fileMapDataType = FILE_MAP_DATA_TYPE_MULTI_MAP; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: m_dataReadingAccessMethod = DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN; m_dataMappingAccessMethod = DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW; m_colorMappingMethod = COLOR_MAPPING_METHOD_PALETTE; m_paletteColorMappingSource = PALETTE_COLOR_MAPPING_SOURCE_FROM_FILE; m_paletteNormalizationModesSupported.push_back(PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA); m_fileMapDataType = FILE_MAP_DATA_TYPE_MATRIX; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: m_dataReadingAccessMethod = DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW; m_dataMappingAccessMethod = DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN; m_colorMappingMethod = COLOR_MAPPING_METHOD_PALETTE; m_paletteColorMappingSource = PALETTE_COLOR_MAPPING_SOURCE_FROM_MAP; m_paletteNormalizationModesSupported.push_back(PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA); m_paletteNormalizationModesSupported.push_back(PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA); m_fileMapDataType = FILE_MAP_DATA_TYPE_MULTI_MAP; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: m_dataReadingAccessMethod = DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW; m_dataMappingAccessMethod = DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN; m_colorMappingMethod = COLOR_MAPPING_METHOD_PALETTE; m_paletteColorMappingSource = PALETTE_COLOR_MAPPING_SOURCE_FROM_FILE; m_paletteNormalizationModesSupported.push_back(PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA); m_paletteNormalizationModesSupported.push_back(PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA); m_fileMapDataType = FILE_MAP_DATA_TYPE_MULTI_MAP; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: m_dataReadingAccessMethod = DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN; m_dataMappingAccessMethod = DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW; m_colorMappingMethod = COLOR_MAPPING_METHOD_PALETTE; m_paletteColorMappingSource = PALETTE_COLOR_MAPPING_SOURCE_FROM_FILE; m_paletteNormalizationModesSupported.push_back(PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA); m_fileMapDataType = FILE_MAP_DATA_TYPE_MATRIX; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: m_dataReadingAccessMethod = DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN; m_dataMappingAccessMethod = DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW; m_colorMappingMethod = COLOR_MAPPING_METHOD_PALETTE; m_paletteColorMappingSource = PALETTE_COLOR_MAPPING_SOURCE_FROM_FILE; m_paletteNormalizationModesSupported.push_back(PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA); m_fileMapDataType = FILE_MAP_DATA_TYPE_MATRIX; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: m_dataReadingAccessMethod = DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW; m_dataMappingAccessMethod = DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN; m_colorMappingMethod = COLOR_MAPPING_METHOD_LABEL_TABLE; m_fileMapDataType = FILE_MAP_DATA_TYPE_MULTI_MAP; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: m_dataReadingAccessMethod = DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW; m_dataMappingAccessMethod = DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN; m_colorMappingMethod = COLOR_MAPPING_METHOD_PALETTE; m_paletteColorMappingSource = PALETTE_COLOR_MAPPING_SOURCE_FROM_MAP; m_paletteNormalizationModesSupported.push_back(PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA); m_paletteNormalizationModesSupported.push_back(PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA); m_fileMapDataType = FILE_MAP_DATA_TYPE_MULTI_MAP; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: m_dataReadingAccessMethod = DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW; m_dataMappingAccessMethod = DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN; m_colorMappingMethod = COLOR_MAPPING_METHOD_PALETTE; m_paletteColorMappingSource = PALETTE_COLOR_MAPPING_SOURCE_FROM_FILE; m_paletteNormalizationModesSupported.push_back(PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA); m_paletteNormalizationModesSupported.push_back(PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA); m_fileMapDataType = FILE_MAP_DATA_TYPE_MULTI_MAP; break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: m_dataReadingAccessMethod = DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN; m_dataMappingAccessMethod = DATA_ACCESS_NONE; m_colorMappingMethod = COLOR_MAPPING_METHOD_PALETTE; m_paletteColorMappingSource = PALETTE_COLOR_MAPPING_SOURCE_FROM_FILE; m_paletteNormalizationModesSupported.push_back(PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA); m_fileMapDataType = FILE_MAP_DATA_TYPE_MULTI_MAP; break; case DataFileTypeEnum::ANNOTATION: case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: case DataFileTypeEnum::BORDER: case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: case DataFileTypeEnum::FOCI: case DataFileTypeEnum::IMAGE: case DataFileTypeEnum::LABEL: case DataFileTypeEnum::METRIC: case DataFileTypeEnum::METRIC_DYNAMIC: case DataFileTypeEnum::PALETTE: case DataFileTypeEnum::RGBA: case DataFileTypeEnum::SCENE: case DataFileTypeEnum::SPECIFICATION: case DataFileTypeEnum::SURFACE: case DataFileTypeEnum::UNKNOWN: case DataFileTypeEnum::VOLUME: case DataFileTypeEnum::VOLUME_DYNAMIC: CaretAssertMessage(0, (DataFileTypeEnum::toGuiName(dataFileType) + " is not a CIFTI Mappable Data File.")); break; } /* * Data from matrix files is read as needed since * Dense can be very large */ switch (m_fileMapDataType) { case FILE_MAP_DATA_TYPE_INVALID: break; case FILE_MAP_DATA_TYPE_MATRIX: m_fileDataReadingType = FILE_READ_DATA_AS_NEEDED; break; case FILE_MAP_DATA_TYPE_MULTI_MAP: m_fileDataReadingType = FILE_READ_DATA_ALL; break; } CaretAssert(m_dataReadingAccessMethod != DATA_ACCESS_METHOD_INVALID); CaretAssert(m_dataMappingAccessMethod != DATA_ACCESS_METHOD_INVALID); CaretAssert(m_colorMappingMethod != COLOR_MAPPING_METHOD_INVALID); CaretAssert(m_fileMapDataType != FILE_MAP_DATA_TYPE_INVALID); if (m_colorMappingMethod != COLOR_MAPPING_METHOD_LABEL_TABLE) { CaretAssert(m_paletteColorMappingSource != PALETTE_COLOR_MAPPING_SOURCE_INVALID); } setupCiftiReadingMappingDirection(); m_classNameHierarchy.grabNew(new GroupAndNameHierarchyModel()); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_SURFACE_COLORING_INVALIDATE); } /** * Destructor. */ CiftiMappableDataFile::~CiftiMappableDataFile() { EventManager::get()->removeAllEventsFromListener(this); clearPrivate(); } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void CiftiMappableDataFile::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_SURFACE_COLORING_INVALIDATE) { EventSurfaceColoringInvalidate* colorInvalidateEvent = dynamic_cast(event); CaretAssert(colorInvalidateEvent); colorInvalidateEvent->setEventProcessed(); invalidateColoringInAllMaps(); } } /** * Create a new instance of a CIFTI file from the given CIFTI data file type * for the given surface structure and number of nodes. NOT all CIFTI file * types are supported. * * @param ciftiFileType * Data file type for the returned CIFTI file. * @param structure * The surface structure. * @param numberOfNodes * Number of nodes in the surface. * @param errorMessageOut * Will describe problem if there was an error such as an unsupported * CIFTI file type. * @param * Pointer to the newly created CIFTI file. If there is an * error, NULL will be returned and errorMessageOut will describe the * problem. User will need to 'dynamic_cast' the returned pointer to * the class corresponding to the CIFTI file type. */ CiftiMappableDataFile* CiftiMappableDataFile::newInstanceForCiftiFileTypeAndSurface(const DataFileTypeEnum::Enum ciftiFileType, const StructureEnum::Enum structure, const int32_t numberOfNodes, AString& errorMessageOut) { errorMessageOut.clear(); CiftiFile* ciftiFile = NULL; CiftiMappableDataFile* ciftiMappableFile = NULL; try { bool hasLabelsFlag = false; bool hasScalarsFlag = false; /* * Create the appropriate file type. */ switch (ciftiFileType) { case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: ciftiMappableFile = new CiftiBrainordinateLabelFile(); hasLabelsFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: ciftiMappableFile = new CiftiBrainordinateScalarFile(); hasScalarsFlag = true; break; default: errorMessageOut = ("Creation of " + DataFileTypeEnum::toGuiName(ciftiFileType) + " is not supported."); CaretAssertMessage(0, errorMessageOut); return NULL; break; } /* * Create the XML. */ CiftiXML myXML; myXML.setNumberOfDimensions(2); /* * Add labels or scalars to XML. */ if (hasLabelsFlag) { CiftiLabelsMap labelsMap; labelsMap.setLength(1); myXML.setMap(CiftiXML::ALONG_ROW, labelsMap); } else if (hasScalarsFlag) { CiftiScalarsMap scalarsMap; scalarsMap.setLength(1); myXML.setMap(CiftiXML::ALONG_ROW, scalarsMap); } else { CaretAssert(0); } /* * Add brainordinates to the XML. */ CiftiBrainModelsMap brainModelsMap; brainModelsMap.addSurfaceModel(numberOfNodes, structure); myXML.setMap(CiftiXML::ALONG_COLUMN, brainModelsMap); /* * Add XML to the CIFTI file. */ ciftiFile = new CiftiFile(); ciftiFile->setCiftiXML(myXML); /* * Fill with zeros */ std::vector zeroData(numberOfNodes, 0.0); ciftiFile->setColumn(&zeroData[0], 0); /* * Add the CiftiFile to the Cifti Mappable File */ const AString defaultFileName = ciftiMappableFile->getFileName(); ciftiMappableFile->m_ciftiFile.grabNew(ciftiFile); ciftiMappableFile->setFileName(defaultFileName); ciftiMappableFile->initializeAfterReading(defaultFileName); ciftiMappableFile->setModified(); return ciftiMappableFile; } catch (const DataFileException& de) { errorMessageOut = de.whatString(); } if (ciftiMappableFile != NULL) { delete ciftiMappableFile; ciftiMappableFile = NULL; } if (ciftiFile != NULL) { delete ciftiFile; ciftiFile = NULL; } return NULL; } /** * Clear the contents of the file. */ void CiftiMappableDataFile::clear() { CaretMappableDataFile::clear(); clearPrivate(); } /** * Clear the contents of the file. * Note that "clear()" is virtual and cannot be called from destructor. */ void CiftiMappableDataFile::clearPrivate() { /* * Do not clear this items as they are setup in the constructor. * m_dataReadingAccessMethod * m_dataMappingAccessMethod * m_colorMappingMethod * m_fileMapDataType */ m_ciftiFile.grabNew(NULL); resetDataLoadingMembers(); m_containsSurfaceData = false; m_containsVolumeData = false; m_mappingTimeStart = 0.0f; m_mappingTimeStep = 1.0f; m_mappingTimeUnits = NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN; m_brainordinateMapping.reset(); m_brainordinateMappingCachedFlag = false; } /** * Reset data loading members. * Also used when parcel row/column loading is changed. */ void CiftiMappableDataFile::resetDataLoadingMembers() { const int64_t num = static_cast(m_mapContent.size()); for (int64_t i = 0; i < num; i++) { delete m_mapContent[i]; } m_mapContent.clear(); m_classNameHierarchy->clear(); m_forceUpdateOfGroupAndNameHierarchy = true; } /** * @return Is this file empty? */ bool CiftiMappableDataFile::isEmpty() const { if (getNumberOfMaps() > 0) { return false; } return true; } /** * Set preference for reading. Reading all data from a "matrix" type file * is not supported and if requested, it will be ignored. * * @param prefer * When true, only header is read and no data is read. * When false, both header and all data is read. */ void CiftiMappableDataFile::setPreferOnDiskReading(const bool& prefer) { if (prefer) { m_fileDataReadingType = FILE_READ_DATA_AS_NEEDED; } else { switch (m_fileMapDataType) { case FILE_MAP_DATA_TYPE_INVALID: break; case FILE_MAP_DATA_TYPE_MATRIX: CaretLogSevere("CIFTI Matrix files do not support reading of all data."); break; case FILE_MAP_DATA_TYPE_MULTI_MAP: m_fileDataReadingType = FILE_READ_DATA_ALL; break; } } } /** * @return structure file maps to. */ StructureEnum::Enum CiftiMappableDataFile::getStructure() const { /* * CIFTI files apply to all structures. */ return StructureEnum::ALL; } /** * Set the structure to which file maps. * @param structure * New structure to which file maps. */ void CiftiMappableDataFile::setStructure(const StructureEnum::Enum /*structure*/) { /* CIFTI files may apply to all structures */ } /** * Is this file able to map to the given structure? Some data files, such * as CIFTI files, are able to map to multiple surface structure. The default * implementation of this method simply compares the given structure to * getStructure() and returns true if they are the same value, else false. * * @param structure * Structure for testing mappability status. * @return True if this file is able to map to the given structure, else false. */ bool CiftiMappableDataFile::isMappableToSurfaceStructure(const StructureEnum::Enum structure) const { /* * Validate number of nodes are correct */ int32_t numCiftiNodes = getMappingSurfaceNumberOfNodes(structure); if (numCiftiNodes > 0) { return true; } return false; } /** * @return Metadata for the file. */ GiftiMetaData* CiftiMappableDataFile::getFileMetaData() { CaretAssert(m_ciftiFile); const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); return ciftiXML.getFileMetaData(); } /** * @return Metadata for the file. */ const GiftiMetaData* CiftiMappableDataFile:: getFileMetaData() const { CaretAssert(m_ciftiFile); const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); return ciftiXML.getFileMetaData(); } /** * Read the file. * * @param ciftiMapFileName * Name of the file to read. * @throw * DataFileException if there is an error reading the file. */ void CiftiMappableDataFile::readFile(const AString& ciftiMapFileName) { clear(); try { /* * Is the file on the network (name begins with http, ftp, etc.). */ if (DataFile::isFileOnNetwork(ciftiMapFileName)) { /* * Data in Xnat does not end with a valid file extension * but ends with HTTP search parameters. Thus, if the * filename does not have a valid extension, assume that * the data is in Xnat. */ bool isValidFileExtension = false; DataFileTypeEnum::fromFileExtension(ciftiMapFileName, &isValidFileExtension); if (isValidFileExtension) { switch (m_fileMapDataType) { case FILE_MAP_DATA_TYPE_INVALID: break; case FILE_MAP_DATA_TYPE_MATRIX: throw DataFileException(ciftiMapFileName + " of type " + DataFileTypeEnum::toGuiName(getDataFileType()) + " cannot be read over the network. The file must be" " accessed by reading individual rows and/or columns" " and this cannot be performed over a network."); break; case FILE_MAP_DATA_TYPE_MULTI_MAP: break; } CaretTemporaryFile tempFile; tempFile.readFile(ciftiMapFileName); m_ciftiFile.grabNew(new CiftiFile()); m_ciftiFile->openFile(tempFile.getFileName()); m_ciftiFile->convertToInMemory(); } else { m_ciftiFile.grabNew(new CiftiFile()); AString username = ""; AString password = ""; AString filenameToOpen = ""; /* * Username and password may be embedded in URL, so extract them. */ FileInformation fileInfo(ciftiMapFileName); fileInfo.getRemoteUrlUsernameAndPassword(filenameToOpen, username, password); /* * Always override with a password entered by the user. */ if (CaretDataFile::getFileReadingUsername().isEmpty() == false) { username = CaretDataFile::getFileReadingUsername(); password = CaretDataFile::getFileReadingPassword(); } m_ciftiFile->openURL(filenameToOpen, username, password); } } else { m_ciftiFile.grabNew(new CiftiFile()); switch (m_fileMapDataType) { case FILE_MAP_DATA_TYPE_INVALID: break; case FILE_MAP_DATA_TYPE_MATRIX: m_ciftiFile->openFile(ciftiMapFileName); break; case FILE_MAP_DATA_TYPE_MULTI_MAP: m_ciftiFile->openFile(ciftiMapFileName); switch (m_fileDataReadingType) { case FILE_READ_DATA_ALL: m_ciftiFile->convertToInMemory(); break; case FILE_READ_DATA_AS_NEEDED: break; } break; } } if (m_ciftiFile != NULL) { setFileName(ciftiMapFileName); // need by charting delegate initializeAfterReading(ciftiMapFileName); } } catch (DataFileException& e) { clear(); throw e; } catch (CaretException& e) { clear(); throw DataFileException(ciftiMapFileName, e.whatString()); } updateAfterFileDataChanges(); setFileName(ciftiMapFileName); clearModified(); } /** * Validate the mapping types for each dimension. * * @param filename * Name of file. */ void CiftiMappableDataFile::validateMappingTypes(const AString& filename) { CaretAssert(m_ciftiFile); CiftiMappingType::MappingType expectedAlongColumnMapType = CiftiMappingType::BRAIN_MODELS; CiftiMappingType::MappingType expectedAlongRowMapType = CiftiMappingType::BRAIN_MODELS; const DataFileTypeEnum::Enum dataFileType = getDataFileType(); switch (dataFileType) { case DataFileTypeEnum::CONNECTIVITY_DENSE: expectedAlongColumnMapType = CiftiMappingType::BRAIN_MODELS; expectedAlongRowMapType = CiftiMappingType::BRAIN_MODELS; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: expectedAlongColumnMapType = CiftiMappingType::BRAIN_MODELS; expectedAlongRowMapType = CiftiMappingType::SERIES; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: expectedAlongColumnMapType = CiftiMappingType::BRAIN_MODELS; expectedAlongRowMapType = CiftiMappingType::LABELS; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: expectedAlongColumnMapType = CiftiMappingType::BRAIN_MODELS; expectedAlongRowMapType = CiftiMappingType::PARCELS; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: expectedAlongColumnMapType = CiftiMappingType::BRAIN_MODELS; expectedAlongRowMapType = CiftiMappingType::SCALARS; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: expectedAlongColumnMapType = CiftiMappingType::BRAIN_MODELS; expectedAlongRowMapType = CiftiMappingType::SERIES; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: expectedAlongColumnMapType = CiftiMappingType::PARCELS; expectedAlongRowMapType = CiftiMappingType::PARCELS; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: expectedAlongColumnMapType = CiftiMappingType::PARCELS; expectedAlongRowMapType = CiftiMappingType::BRAIN_MODELS; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: expectedAlongColumnMapType = CiftiMappingType::PARCELS; expectedAlongRowMapType = CiftiMappingType::LABELS; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: expectedAlongColumnMapType = CiftiMappingType::PARCELS; expectedAlongRowMapType = CiftiMappingType::SCALARS; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: expectedAlongColumnMapType = CiftiMappingType::PARCELS; expectedAlongRowMapType = CiftiMappingType::SERIES; break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: expectedAlongColumnMapType = CiftiMappingType::SCALARS; expectedAlongRowMapType = CiftiMappingType::SERIES; break; case DataFileTypeEnum::ANNOTATION: case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: case DataFileTypeEnum::BORDER: case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: case DataFileTypeEnum::FOCI: case DataFileTypeEnum::IMAGE: case DataFileTypeEnum::LABEL: case DataFileTypeEnum::METRIC: case DataFileTypeEnum::METRIC_DYNAMIC: case DataFileTypeEnum::PALETTE: case DataFileTypeEnum::RGBA: case DataFileTypeEnum::SCENE: case DataFileTypeEnum::SPECIFICATION: case DataFileTypeEnum::SURFACE: case DataFileTypeEnum::UNKNOWN: case DataFileTypeEnum::VOLUME: case DataFileTypeEnum::VOLUME_DYNAMIC: throw DataFileException(filename, DataFileTypeEnum::toGuiName(dataFileType) + " is not a CIFTI Mappable Data File."); break; } const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); const CiftiMappingType::MappingType alongColumnMapType = ciftiXML.getMappingType(CiftiXML::ALONG_COLUMN); const CiftiMappingType::MappingType alongRowMapType = ciftiXML.getMappingType(CiftiXML::ALONG_ROW); AString errorMessage; if (alongColumnMapType != expectedAlongColumnMapType) { errorMessage.appendWithNewLine("Along column mapping type is " + CiftiMappableDataFile::mappingTypeToName(alongColumnMapType) + " but should be " + CiftiMappableDataFile::mappingTypeToName(expectedAlongColumnMapType) + " for file type \"" + DataFileTypeEnum::toGuiName(dataFileType) + "\""); } if (alongRowMapType != expectedAlongRowMapType) { errorMessage.appendWithNewLine("Along row mapping type is " + CiftiMappableDataFile::mappingTypeToName(alongRowMapType) + " but should be " + CiftiMappableDataFile::mappingTypeToName(expectedAlongRowMapType) + " for file type \"" + DataFileTypeEnum::toGuiName(dataFileType) + "\""); } if ( ! errorMessage.isEmpty()) { throw DataFileException(filename, errorMessage); } } /** * Setup the CIFTI mapping and reading directions. */ void CiftiMappableDataFile::setupCiftiReadingMappingDirection() { switch (m_dataMappingAccessMethod) { case DATA_ACCESS_METHOD_INVALID: CaretAssert(0); break; case DATA_ACCESS_NONE: break; case DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN: m_dataMappingDirectionForCiftiXML = CiftiXML::ALONG_COLUMN; break; case DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW: m_dataMappingDirectionForCiftiXML = CiftiXML::ALONG_ROW; break; } switch (m_dataReadingAccessMethod) { case DATA_ACCESS_METHOD_INVALID: CaretAssert(0); break; case DATA_ACCESS_NONE: break; case DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN: m_dataReadingDirectionForCiftiXML = CiftiXML::ALONG_COLUMN; break; case DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW: m_dataReadingDirectionForCiftiXML = CiftiXML::ALONG_ROW; break; } } /** * Initialize the CIFTI file. * * @param filename * Name of file. */ void CiftiMappableDataFile::initializeAfterReading(const AString& filename) { CaretAssert(m_ciftiFile); setupCiftiReadingMappingDirection(); validateMappingTypes(filename); const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); if (m_dataMappingDirectionForCiftiXML != S_CIFTI_XML_ALONG_INVALID) { switch (ciftiXML.getMappingType(m_dataMappingDirectionForCiftiXML)) { case CiftiMappingType::BRAIN_MODELS: { const CiftiBrainModelsMap& map = ciftiXML.getBrainModelsMap(m_dataMappingDirectionForCiftiXML); if (! map.getSurfaceStructureList().empty()) { m_containsSurfaceData = true; } if (map.hasVolumeData()) { m_containsVolumeData = true; } } break; case CiftiMappingType::LABELS: CaretAssertMessage(0, "Mapping type should never be LABELS"); throw DataFileException(filename, "Mapping type should never be LABELS"); break; case CiftiMappingType::PARCELS: { const CiftiParcelsMap& map = ciftiXML.getParcelsMap(m_dataMappingDirectionForCiftiXML); if (! map.getParcelSurfaceStructures().empty()) { m_containsSurfaceData = true; } if (map.hasVolumeData()) { m_containsVolumeData = true; } } break; case CiftiMappingType::SCALARS: CaretAssertMessage(0, "Mapping type should never be SCALARS"); throw DataFileException(filename, "Mapping type should never be SCALARS"); break; case CiftiMappingType::SERIES: CaretAssertMessage(0, "Mapping type should never be SERIES"); throw DataFileException(filename, "Mapping type should never be SERIES"); break; } } switch (ciftiXML.getMappingType(m_dataReadingDirectionForCiftiXML)) { case CiftiMappingType::BRAIN_MODELS: break; case CiftiMappingType::LABELS: break; case CiftiMappingType::PARCELS: break; case CiftiMappingType::SCALARS: break; case CiftiMappingType::SERIES: { const CiftiSeriesMap& map = ciftiXML.getSeriesMap(m_dataReadingDirectionForCiftiXML); CiftiSeriesMap::Unit units = map.getUnit(); switch (units) { case CiftiSeriesMap::HERTZ: m_mappingTimeUnits = NiftiTimeUnitsEnum::NIFTI_UNITS_HZ; break; case CiftiSeriesMap::METER: CaretLogWarning("CIFTI Units METER not implemented"); break; case CiftiSeriesMap::RADIAN: CaretLogWarning("CIFTI Units RADIAN not implemented"); break; case CiftiSeriesMap::SECOND: m_mappingTimeUnits = NiftiTimeUnitsEnum::NIFTI_UNITS_SEC; break; } m_mappingTimeStart = map.getStart(); m_mappingTimeStep = map.getStep(); } break; } switch (m_dataMappingAccessMethod) { case DATA_ACCESS_METHOD_INVALID: CaretAssert(0); break; case DATA_ACCESS_NONE: break; case DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN: if (ciftiXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::BRAIN_MODELS) { m_voxelIndicesToOffsetForDataMapping.grabNew(new SparseVolumeIndexer(ciftiXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN))); } else if (ciftiXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::PARCELS) { m_voxelIndicesToOffsetForDataMapping.grabNew(new SparseVolumeIndexer(ciftiXML.getParcelsMap(CiftiXML::ALONG_COLUMN))); } else { CaretAssertMessage(0, "Invalid mapping type for mapping data to brainordinates"); throw DataFileException(filename, "Invalid mapping type for mapping data to brainordinates"); } break; case DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW: if (ciftiXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::BRAIN_MODELS) { m_voxelIndicesToOffsetForDataMapping.grabNew(new SparseVolumeIndexer(ciftiXML.getBrainModelsMap(CiftiXML::ALONG_ROW))); } else if (ciftiXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::PARCELS) { m_voxelIndicesToOffsetForDataMapping.grabNew(new SparseVolumeIndexer(ciftiXML.getParcelsMap(CiftiXML::ALONG_ROW))); } else { CaretAssertMessage(0, "Invalid mapping type for mapping data to brainordinates"); throw DataFileException(filename, "Invalid mapping type for mapping data to brainordinates"); } break; } switch (m_dataReadingAccessMethod) { case DATA_ACCESS_METHOD_INVALID: CaretAssert(0); break; case DATA_ACCESS_NONE: break; case DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN: if (ciftiXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::BRAIN_MODELS) { m_voxelIndicesToOffsetForDataReading.grabNew(new SparseVolumeIndexer(ciftiXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN))); } else if (ciftiXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::PARCELS) { m_voxelIndicesToOffsetForDataReading.grabNew(new SparseVolumeIndexer(ciftiXML.getParcelsMap(CiftiXML::ALONG_COLUMN))); } else { m_voxelIndicesToOffsetForDataReading.grabNew(new SparseVolumeIndexer()); } break; case DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW: if (ciftiXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::BRAIN_MODELS) { m_voxelIndicesToOffsetForDataReading.grabNew(new SparseVolumeIndexer(ciftiXML.getBrainModelsMap(CiftiXML::ALONG_ROW))); } else if (ciftiXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::PARCELS) { m_voxelIndicesToOffsetForDataReading.grabNew(new SparseVolumeIndexer(ciftiXML.getParcelsMap(CiftiXML::ALONG_ROW))); } else { m_voxelIndicesToOffsetForDataReading.grabNew(new SparseVolumeIndexer()); } break; } /* * Special case for scalar data series that does NOT map to brainordinates */ if (getDataFileType() == DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES) { const CiftiSeriesMap& map = ciftiXML.getSeriesMap(CiftiXML::ALONG_ROW); CiftiSeriesMap::Unit units = map.getUnit(); switch (units) { case CiftiSeriesMap::HERTZ: m_mappingTimeUnits = NiftiTimeUnitsEnum::NIFTI_UNITS_HZ; break; case CiftiSeriesMap::METER: CaretLogWarning("CIFTI Units METER not implemented"); break; case CiftiSeriesMap::RADIAN: CaretLogWarning("CIFTI Units RADIAN not implemented"); break; case CiftiSeriesMap::SECOND: m_mappingTimeUnits = NiftiTimeUnitsEnum::NIFTI_UNITS_SEC; break; } m_mappingTimeStart = map.getStart(); m_mappingTimeStep = map.getStep(); } if (m_mappingTimeStep <= 0.0) { m_mappingTimeStep = 1.0f; } /* * May not have mappings to voxels */ if (m_voxelIndicesToOffsetForDataMapping == NULL) { m_voxelIndicesToOffsetForDataMapping.grabNew(new SparseVolumeIndexer()); } if (m_voxelIndicesToOffsetForDataReading == NULL) { m_voxelIndicesToOffsetForDataReading.grabNew(new SparseVolumeIndexer()); } int32_t numberOfMaps = 0; switch (m_fileMapDataType) { case FILE_MAP_DATA_TYPE_INVALID: break; case FILE_MAP_DATA_TYPE_MATRIX: numberOfMaps = 1; break; case FILE_MAP_DATA_TYPE_MULTI_MAP: switch (m_dataReadingAccessMethod) { case DATA_ACCESS_METHOD_INVALID: CaretAssert(0); break; case DATA_ACCESS_NONE: break; case DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW: numberOfMaps = m_ciftiFile->getNumberOfColumns(); break; case DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN: numberOfMaps = m_ciftiFile->getNumberOfRows(); break; } break; } /* * Get data for maps. */ for (int32_t i = 0; i < numberOfMaps; i++) { MapContent* mc = new MapContent(this, m_ciftiFile, m_fileMapDataType, m_dataReadingDirectionForCiftiXML, m_dataMappingDirectionForCiftiXML, i); m_mapContent.push_back(mc); } m_classNameHierarchy->update(this, true); m_forceUpdateOfGroupAndNameHierarchy = false; m_classNameHierarchy->setAllSelected(true); m_fileFastStatistics.grabNew(NULL); m_fileHistogram.grabNew(NULL); m_fileHistorgramLimitedValues.grabNew(NULL); CaretLogFiner("CLASS/NAME Table for : " + this->getFileNameNoPath() + "\n" + m_classNameHierarchy->toString()); validateKeysAndLabels(); validateAfterFileReading(); } /** * This method is intended for overriding by subclasess so that they * can examine and verify the data that was read. This method is * called after successfully reading a file. */ void CiftiMappableDataFile::validateAfterFileReading() { /* nothing - see method comment. */ } /** * Write the file. * * @param ciftiMapFileName * Name of the file to write. * @throw * DataFileException if there is an error writing the file. */ void CiftiMappableDataFile::writeFile(const AString& ciftiMapFileName) { if (m_ciftiFile == NULL) { throw DataFileException(ciftiMapFileName + " cannot be written because no file is loaded"); } if (getDataFileType() == DataFileTypeEnum::CONNECTIVITY_DENSE) { throw DataFileException(ciftiMapFileName + " dense connectivity files cannot be written to files due to their large sizes."); } m_ciftiFile->writeFile(ciftiMapFileName); setFileName(ciftiMapFileName); clearModified(); } /** * @return Is the data mappable to a surface? */ bool CiftiMappableDataFile::isSurfaceMappable() const { return m_containsSurfaceData; } /** * @return Is the data mappable to a volume? */ bool CiftiMappableDataFile::isVolumeMappable() const { return m_containsVolumeData; } /** * @return The number of maps in the file. * Note: Caret5 used the term 'columns'. */ int32_t CiftiMappableDataFile::getNumberOfMaps() const { return m_mapContent.size(); } /** * @return True if the file has map attributes (name and metadata). * For files that do not have map attributes, they should override * this method and return false. If not overriden, this method * returns true. * * Some files (such as CIFTI Connectivity Matrix Files and CIFTI * Data-Series Files) do not have Map Attributes and thus there * is no map name nor map metadata and options to edit these * attributes should not be presented to the user. * * These CIFTI files do contain palette color mapping but it is * associated with the file. To simplify palette color mapping editing * these file will return the file's palette color mapping for any * calls to getMapPaletteColorMapping(). */ bool CiftiMappableDataFile::hasMapAttributes() const { switch (m_fileMapDataType) { case FILE_MAP_DATA_TYPE_INVALID: break; case FILE_MAP_DATA_TYPE_MATRIX: break; case FILE_MAP_DATA_TYPE_MULTI_MAP: return true; break; } return false; } /** * Get the name of the map at the given index. * * @param mapIndex * Index of the map. * @return * Name of the map. */ AString CiftiMappableDataFile::getMapName(const int32_t mapIndex) const { CaretAssertVectorIndex(m_mapContent, mapIndex); return m_mapContent[mapIndex]->getName(); } /** * Set the name of the map at the given index. * * @param mapIndex * Index of the map. * @param mapName * New name for the map. */ void CiftiMappableDataFile::setMapName(const int32_t mapIndex, const AString& mapName) { CaretAssertVectorIndex(m_mapContent, mapIndex); m_mapContent[mapIndex]->setName(mapName); } /** * Get the metadata for the map at the given index * * @param mapIndex * Index of the map. * @return * Metadata for the map (const value). */ const GiftiMetaData* CiftiMappableDataFile::getMapMetaData(const int32_t mapIndex) const { CaretAssertVectorIndex(m_mapContent, mapIndex); return m_mapContent[mapIndex]->m_metadata; } /** * Get the metadata for the map at the given index * * @param mapIndex * Index of the map. * @return * Metadata for the map. */ GiftiMetaData* CiftiMappableDataFile::getMapMetaData(const int32_t mapIndex) { CaretAssertVectorIndex(m_mapContent, mapIndex); return m_mapContent[mapIndex]->m_metadata; } /** * Get the unique ID (UUID) for the map at the given index. * * @param mapIndex * Index of the map. * @return * String containing UUID for the map. */ AString CiftiMappableDataFile::getMapUniqueID(const int32_t mapIndex) const { CaretAssertVectorIndex(m_mapContent, mapIndex); const GiftiMetaData* md = getMapMetaData(mapIndex); const AString uniqueID = md->getUniqueID(); return uniqueID; } /** * @return Is the data in the file mapped to colors using * a palette. */ bool CiftiMappableDataFile::isMappedWithPalette() const { switch (m_colorMappingMethod) { case COLOR_MAPPING_METHOD_INVALID: break; case COLOR_MAPPING_METHOD_LABEL_TABLE: break; case COLOR_MAPPING_METHOD_PALETTE: return true; break; } return false; } /** * @return True if file is mapped with a palette and one * palette is used for all maps. */ bool CiftiMappableDataFile::isOnePaletteUsedForAllMaps() const { bool onePaletteFlag = false; switch (m_colorMappingMethod) { case COLOR_MAPPING_METHOD_INVALID: break; case COLOR_MAPPING_METHOD_LABEL_TABLE: break; case COLOR_MAPPING_METHOD_PALETTE: switch (m_paletteColorMappingSource) { case PALETTE_COLOR_MAPPING_SOURCE_INVALID: break; case PALETTE_COLOR_MAPPING_SOURCE_FROM_FILE: onePaletteFlag = true; break; case PALETTE_COLOR_MAPPING_SOURCE_FROM_MAP: onePaletteFlag = false; break; } break; } return onePaletteFlag; } /** * Get the data for the given map index. * * @param mapIndex * Index of the map. * @param dataOut * A vector that will contain the data for the map upon exit. */ void CiftiMappableDataFile::getMapData(const int32_t mapIndex, std::vector& dataOut) const { CaretAssertVectorIndex(m_mapContent, mapIndex); CaretAssert(m_ciftiFile); CaretAssert(mapIndex >= 0); switch (m_dataReadingAccessMethod) { case DATA_ACCESS_METHOD_INVALID: CaretAssert(0); break; case DATA_ACCESS_NONE: break; case DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW: CaretAssert(mapIndex < m_ciftiFile->getNumberOfColumns()); dataOut.resize(m_ciftiFile->getNumberOfRows()); m_ciftiFile->getColumn(&dataOut[0], mapIndex); break; case DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN: CaretAssert(mapIndex < m_ciftiFile->getNumberOfRows()); dataOut.resize(m_ciftiFile->getNumberOfColumns()); m_ciftiFile->getRow(&dataOut[0], mapIndex); break; } } /** * Set the data for the given map index. * * @param mapIndex * Index of the map. * @param dataOut * A vector that contains the data for the map. */ void CiftiMappableDataFile::setMapData(const int32_t mapIndex, const std::vector& data) { CaretAssertVectorIndex(m_mapContent, mapIndex); CaretAssert(m_ciftiFile); CaretAssert(mapIndex >= 0); switch (m_dataReadingAccessMethod) { case DATA_ACCESS_METHOD_INVALID: CaretAssert(0); break; case DATA_ACCESS_NONE: break; case DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW: CaretAssert(mapIndex < m_ciftiFile->getNumberOfColumns()); m_ciftiFile->setColumn(&data[0], mapIndex); break; case DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN: CaretAssert(mapIndex < m_ciftiFile->getNumberOfRows()); m_ciftiFile->setRow(&data[0], mapIndex); break; } m_forceUpdateOfGroupAndNameHierarchy = true; m_mapContent[mapIndex]->updateForChangeInMapData(); } /** * Update after a change in map data. * * @param mapIndex * Index of map whose data has changed. */ void CiftiMappableDataFile::updateForChangeInMapDataWithMapIndex(const int32_t mapIndex) { CaretAssertVectorIndex(m_mapContent, mapIndex); m_mapContent[mapIndex]->updateForChangeInMapData(); } /** * Invalidate coloring in all maps */ void CiftiMappableDataFile::invalidateColoringInAllMaps() { const int64_t numMaps = static_cast(getNumberOfMaps()); for (int64_t i = 0; i < numMaps; i++) { CaretAssertVectorIndex(m_mapContent, i); m_mapContent[i]->m_rgbaValid = false; /* invalidates histograms */ updateForChangeInMapDataWithMapIndex(i); } /* * Force recreation of matrix so that it receives updates to coloring * and in particular, matrix grid outline coloring */ m_matrixGraphicsPrimitive.reset(); m_matrixGraphicsOutlinePrimitive.reset(); invalidateHistogramChartColoring(); } /** * Get all data within the file. * * @param data * Filled with data and will contain (number-of-rows * number-of-columns) * of data. */ void CiftiMappableDataFile::getFileData(std::vector& data) const { switch (m_fileMapDataType) { case FILE_MAP_DATA_TYPE_INVALID: CaretAssert(0); break; case FILE_MAP_DATA_TYPE_MATRIX: break; case FILE_MAP_DATA_TYPE_MULTI_MAP: break; } CaretAssert(m_ciftiFile); const int64_t numRows = m_ciftiFile->getNumberOfRows(); const int64_t numCols = m_ciftiFile->getNumberOfColumns(); const int64_t dataSize = numRows * numCols; data.resize(dataSize); for (int64_t iRow = 0; iRow < numRows; iRow++) { m_ciftiFile->getRow(&data[iRow * numCols], iRow); } } /** * Get the RGBA mapped version of the file's data matrix. * * @param rgba * RGBA for file's matrix content. */ void CiftiMappableDataFile::getMatrixRGBA(std::vector &rgba) { std::vector data; getFileData(data); const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); PaletteColorMapping *paletteColorMapping = ciftiXML.getFilePalette(); CaretAssert(paletteColorMapping); CaretPointer fastStatistics(new FastStatistics()); if ( ! data.empty()) { fastStatistics->update(&data[0], data.size()); rgba.resize(data.size() * 4); NodeAndVoxelColoring::colorScalarsWithPalette(fastStatistics, paletteColorMapping, &data[0], paletteColorMapping, &data[0], data.size(), &rgba[0]); } else { std::fill(rgba.begin(), rgba.end(), 0.0); } } /** * @return The graphics primitive containing the matrix representation of the file. * All cells are of dimension 1.0 x 1.0 * * @param matrixViewMode * The matrix visualization mode (upper/lower). * @param gridMode * The grid mode (filled or outline) */ GraphicsPrimitiveV3fC4f* CiftiMappableDataFile::getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode, const MatrixGridMode gridMode) const { EventCaretPreferencesGet preferencesEvent; EventManager::get()->sendEvent(preferencesEvent.getPointer()); CaretPreferences* caretPreferences = preferencesEvent.getCaretPreferences(); uint8_t gridByteRGBA[4] = { 0, 0, 0, 0 }; GraphicsPrimitiveV3fC4f* matrixPrimitive = NULL; switch (gridMode) { case MatrixGridMode::FILLED: matrixPrimitive = m_matrixGraphicsPrimitive.get(); break; case MatrixGridMode::OUTLINE: caretPreferences->getBackgroundAndForegroundColors()->getColorChartMatrixGridLines(gridByteRGBA); matrixPrimitive = m_matrixGraphicsOutlinePrimitive.get(); if ((gridByteRGBA[0] != m_previousMatrixGridRGBA[0]) || (gridByteRGBA[1] != m_previousMatrixGridRGBA[1]) || (gridByteRGBA[2] != m_previousMatrixGridRGBA[2]) || (gridByteRGBA[3] != m_previousMatrixGridRGBA[3])) { matrixPrimitive = NULL; m_previousMatrixGridRGBA[0] = gridByteRGBA[0]; m_previousMatrixGridRGBA[1] = gridByteRGBA[1]; m_previousMatrixGridRGBA[2] = gridByteRGBA[2]; m_previousMatrixGridRGBA[3] = gridByteRGBA[3]; } break; } if (matrixPrimitive == NULL) { int32_t numberOfRows = 0; int32_t numberOfColumns = 0; std::vector matrixRGBA; if (getMatrixForChartingRGBA(numberOfRows, numberOfColumns, matrixRGBA)) { const int32_t numberOfCells = numberOfRows * numberOfColumns; if (numberOfCells > 0) { switch (gridMode) { case MatrixGridMode::FILLED: matrixPrimitive = GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES); matrixPrimitive->reserveForNumberOfVertices(numberOfCells * 6); // 2 triangles per cell, 3 vertices per triangle break; case MatrixGridMode::OUTLINE: /* Lines are used around each cell to simplify upper/lower triangular options */ matrixPrimitive = GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_LINES); matrixPrimitive->reserveForNumberOfVertices(numberOfCells * 8); // 4 lines per cell, 2 vertices per line break; } matrixPrimitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); /* * RGBA for grid outline */ float cellOutlineRGBA[4] = { 1.0, 0.0, 0.0, 1.0 }; if (caretPreferences != NULL) { cellOutlineRGBA[0] = static_cast(gridByteRGBA[0]) / 255.0f; cellOutlineRGBA[1] = static_cast(gridByteRGBA[1]) / 255.0f; cellOutlineRGBA[2] = static_cast(gridByteRGBA[2]) / 255.0f; cellOutlineRGBA[3] = 1.0; } /* * Alpha zero for cells that are "not drawn" */ const float cellNotDrawRGBA[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; /* * NOTE: All matrix cells receive coloring, event those that are * not displayed due to the triangular view selection. * The reason is that it greatly simplifies identification as * one can derive the row and column from the primitive index. * Using triangles also simplifies identification. Lastly, since * OpenGL buffers are used, drawing is very fast. */ int32_t rgbaOffset = 0; const float cellHeight = 1.0; const float cellWidth = 1.0; float cellY = (numberOfRows - 1) * cellHeight; for (int32_t rowIndex = 0; rowIndex < numberOfRows; rowIndex++) { float cellX = 0; for (int32_t columnIndex = 0; columnIndex < numberOfColumns; columnIndex++) { CaretAssertVectorIndex(matrixRGBA, rgbaOffset+3); const float* rgba = &matrixRGBA[rgbaOffset]; rgbaOffset += 4; bool drawCellFlag = true; if (matrixViewMode != ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL) { if (numberOfRows == numberOfColumns) { drawCellFlag = false; switch (matrixViewMode) { case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: break; case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: if (rowIndex != columnIndex) { drawCellFlag = true; } break; case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: if (rowIndex > columnIndex) { drawCellFlag = true; } break; case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: if (rowIndex < columnIndex) { drawCellFlag = true; } break; } } else { drawCellFlag = true; /* * Diagonals for non-square matrices not allowed */ const bool allowNonSquareMatrixDiagonalsFlag = false; if (allowNonSquareMatrixDiagonalsFlag) { drawCellFlag = false; const float slope = static_cast(numberOfRows) / static_cast(numberOfColumns); const int32_t diagonalRow = static_cast(slope * columnIndex); switch (matrixViewMode) { case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: drawCellFlag = true; break; case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: if (rowIndex != diagonalRow) { drawCellFlag = true; } break; case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: if (rowIndex > diagonalRow) { drawCellFlag = true; } break; case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: if (rowIndex < diagonalRow) { drawCellFlag = true; } break; } } } } switch (gridMode) { case MatrixGridMode::FILLED: { const float* cellRGBA = (drawCellFlag ? rgba : cellNotDrawRGBA); matrixPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, cellRGBA); matrixPrimitive->addVertex(cellX, cellY, 0.0, cellRGBA); matrixPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, cellRGBA); matrixPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, cellRGBA); matrixPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, cellRGBA); matrixPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, cellRGBA); } break; case MatrixGridMode::OUTLINE: { const float* cellRGBA = (drawCellFlag ? cellOutlineRGBA : cellNotDrawRGBA); matrixPrimitive->addVertex(cellX, cellY, 0.0, cellRGBA); matrixPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, cellRGBA); matrixPrimitive->addVertex(cellX + cellWidth, cellY, 0.0, cellRGBA); matrixPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, cellRGBA); matrixPrimitive->addVertex(cellX + cellWidth, cellY + cellHeight, 0.0, cellRGBA); matrixPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, cellRGBA); matrixPrimitive->addVertex(cellX, cellY + cellHeight, 0.0, cellRGBA); matrixPrimitive->addVertex(cellX, cellY, 0.0, cellRGBA); } break; } cellX += cellWidth; } cellY -= cellHeight; } } } } switch (gridMode) { case MatrixGridMode::FILLED: if (matrixPrimitive != m_matrixGraphicsPrimitive.get()) { m_matrixGraphicsPrimitive.reset(matrixPrimitive); } break; case MatrixGridMode::OUTLINE: if (matrixPrimitive != m_matrixGraphicsOutlinePrimitive.get()) { m_matrixGraphicsOutlinePrimitive.reset(matrixPrimitive); } break; } return matrixPrimitive; } /** * Get the matrix RGBA coloring for this matrix data creator. * * @param numberOfRowsOut * Number of rows in the coloring matrix. * @param numberOfColumnsOut * Number of rows in the coloring matrix. * @param rgbaOut * RGBA coloring output with number of elements * (numberOfRowsOut * numberOfColumnsOut * 4). * @return * True if data output data is valid, else false. */ bool CiftiMappableDataFile::getMatrixForChartingRGBA(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut, std::vector& rgbaOut) const { bool useMapFileHelperFlag = false; bool useMatrixFileHelperFlag = false; std::vector parcelReorderedRowIndices; switch (getDataFileType()) { case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: { useMatrixFileHelperFlag = true; const CiftiConnectivityMatrixParcelFile* parcelConnFile = dynamic_cast(this); CaretAssert(parcelConnFile); if (parcelConnFile != NULL) { CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; int32_t parcelLabelFileMapIndex = -1; bool reorderingEnabledFlag = false; std::vector parcelLabelFiles; parcelConnFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, parcelLabelReorderingFile, parcelLabelFileMapIndex, reorderingEnabledFlag); if (reorderingEnabledFlag) { const CiftiParcelReordering* parcelReordering = parcelConnFile->getParcelReordering(parcelLabelReorderingFile, parcelLabelFileMapIndex); if (parcelReordering != NULL) { parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); } } } } break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: { useMapFileHelperFlag = true; const CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(this); CaretAssert(parcelLabelFile); if (parcelLabelFile != NULL) { CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; int32_t parcelLabelFileMapIndex = -1; bool reorderingEnabledFlag = false; std::vector parcelLabelFiles; parcelLabelFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, parcelLabelReorderingFile, parcelLabelFileMapIndex, reorderingEnabledFlag); if (reorderingEnabledFlag) { const CiftiParcelReordering* parcelReordering = parcelLabelFile->getParcelReordering(parcelLabelReorderingFile, parcelLabelFileMapIndex); if (parcelReordering != NULL) { parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); } } } } break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: { useMapFileHelperFlag = true; const CiftiParcelScalarFile* parcelScalarFile = dynamic_cast(this); CaretAssert(parcelScalarFile); if (parcelScalarFile != NULL) { CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; int32_t parcelLabelFileMapIndex = -1; bool reorderingEnabledFlag = false; std::vector parcelLabelFiles; parcelScalarFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, parcelLabelReorderingFile, parcelLabelFileMapIndex, reorderingEnabledFlag); if (reorderingEnabledFlag) { const CiftiParcelReordering* parcelReordering = parcelScalarFile->getParcelReordering(parcelLabelReorderingFile, parcelLabelFileMapIndex); if (parcelReordering != NULL) { parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); } } } } break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: { useMapFileHelperFlag = true; const CiftiParcelSeriesFile* parcelSeriesFile = dynamic_cast(this); CaretAssert(parcelSeriesFile); if (parcelSeriesFile != NULL) { CiftiParcelLabelFile* parcelLabelReorderingFile = NULL; int32_t parcelLabelFileMapIndex = -1; bool reorderingEnabledFlag = false; std::vector parcelLabelFiles; parcelSeriesFile->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, parcelLabelReorderingFile, parcelLabelFileMapIndex, reorderingEnabledFlag); if (reorderingEnabledFlag) { const CiftiParcelReordering* parcelReordering = parcelSeriesFile->getParcelReordering(parcelLabelReorderingFile, parcelLabelFileMapIndex); if (parcelReordering != NULL) { parcelReorderedRowIndices = parcelReordering->getReorderedParcelIndices(); } } } } break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: useMatrixFileHelperFlag = true; break; case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: break; case DataFileTypeEnum::METRIC: break; case DataFileTypeEnum::METRIC_DYNAMIC: break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: break; } if (( ! useMapFileHelperFlag) && ( ! useMatrixFileHelperFlag)) { CaretAssertMessage(0, "Trying to get matrix from a file that does not support matrix display"); return false; } bool validDataFlag = false; if (useMapFileHelperFlag) { validDataFlag = helpMapFileLoadChartDataMatrixRGBA(numberOfRowsOut, numberOfColumnsOut, parcelReorderedRowIndices, rgbaOut); } else if (useMatrixFileHelperFlag) { validDataFlag = helpMatrixFileLoadChartDataMatrixRGBA(numberOfRowsOut, numberOfColumnsOut, parcelReorderedRowIndices, rgbaOut); } return validDataFlag; } /** * Get the dimensions of the file (rows and columns). * * @param dim * Contains dimensions upon exit. */ void CiftiMappableDataFile::getMapDimensions(std::vector &dim) const { CaretAssert(m_ciftiFile); dim.clear(); dim.push_back(m_ciftiFile->getNumberOfColumns()); dim.push_back(m_ciftiFile->getNumberOfRows()); } /** * Get statistics describing the distribution of data * mapped with a color palette at the given index. * * @param mapIndex * Index of the map. * @return * Fast statistics for data (will be NULL for data * not mapped using a palette). */ const FastStatistics* CiftiMappableDataFile::getMapFastStatistics(const int32_t mapIndex) { FastStatistics* fastStatsOut = NULL; if (isMappedWithPalette()) { CaretAssertVectorIndex(m_mapContent, mapIndex); if ( ! m_mapContent[mapIndex]->isFastStatisticsValid()) { std::vector data; getMapData(mapIndex, data); m_mapContent[mapIndex]->updateFastStatistics(data); } fastStatsOut = m_mapContent[mapIndex]->m_fastStatistics; } return fastStatsOut; } /** * Get histogram describing the distribution of data * mapped with a color palette at the given index. * * @param mapIndex * Index of the map. * @return * Histogram for data (will be NULL for data * not mapped using a palette). */ const Histogram* CiftiMappableDataFile::getMapHistogram(const int32_t mapIndex) { Histogram* histogramOut = NULL; if (isMappedWithPalette()) { CaretAssertVectorIndex(m_mapContent, mapIndex); int32_t numberOfBuckets = 0; switch (getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: numberOfBuckets = getFileHistogramNumberOfBuckets(); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: numberOfBuckets = getMapPaletteColorMapping(mapIndex)->getHistogramNumberOfBuckets(); break; } if ( ! m_mapContent[mapIndex]->isHistogramValid(numberOfBuckets)) { std::vector data; getMapData(mapIndex, data); m_mapContent[mapIndex]->updateHistogram(numberOfBuckets, data); } histogramOut = m_mapContent[mapIndex]->m_histogram; } return histogramOut; } /** * Get histogram describing the distribution of data * mapped with a color palette at the given index for * data within the given ranges. * * @param mapIndex * Index of the map. * @param mostPositiveValueInclusive * Values more positive than this value are excluded. * @param leastPositiveValueInclusive * Values less positive than this value are excluded. * @param leastNegativeValueInclusive * Values less negative than this value are excluded. * @param mostNegativeValueInclusive * Values more negative than this value are excluded. * @param includeZeroValues * If true zero values (very near zero) are included. * @return * Descriptive statistics for data (will be NULL for data * not mapped using a palette). */ const Histogram* CiftiMappableDataFile::getMapHistogram(const int32_t mapIndex, const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) { Histogram* histogramOut = NULL; if (isMappedWithPalette()) { CaretAssertVectorIndex(m_mapContent, mapIndex); int32_t numberOfBuckets = 0; switch (getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: numberOfBuckets = getFileHistogramNumberOfBuckets(); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: numberOfBuckets = getMapPaletteColorMapping(mapIndex)->getHistogramNumberOfBuckets(); break; } if ( ! m_mapContent[mapIndex]->isHistogramLimitedValuesValid(numberOfBuckets, mostPositiveValueInclusive, leastPositiveValueInclusive, leastNegativeValueInclusive, mostNegativeValueInclusive, includeZeroValues)) { std::vector data; getMapData(mapIndex, data); m_mapContent[mapIndex]->updateHistogramLimitedValues(numberOfBuckets, data, mostPositiveValueInclusive, leastPositiveValueInclusive, leastNegativeValueInclusive, mostNegativeValueInclusive, includeZeroValues); } histogramOut = m_mapContent[mapIndex]->m_histogramLimitedValues; } return histogramOut; } /** * @return The estimated size of data after it is uncompressed * and loaded into RAM. A negative value indicates that the * file size cannot be computed. */ int64_t CiftiMappableDataFile::getDataSizeUncompressedInBytes() const { int64_t dataSize = 0; if (m_ciftiFile != NULL) { dataSize = (m_ciftiFile->getNumberOfColumns() * m_ciftiFile->getNumberOfRows() * sizeof(float)); } return dataSize; } /** * Get statistics describing the distribution of data * mapped with a color palette for all data within the file. * * @return * Fast statistics for data (will be NULL for data * not mapped using a palette). */ const FastStatistics* CiftiMappableDataFile::getFileFastStatistics() { if (m_fileFastStatistics == NULL) { std::vector fileData; getFileData(fileData); if ( ! fileData.empty()) { m_fileFastStatistics.grabNew(new FastStatistics()); m_fileFastStatistics->update(&fileData[0], fileData.size()); } } return m_fileFastStatistics; } /** * Get histogram describing the distribution of data * mapped with a color palette for all data within * the file. * * @return * Histogram for data (will be NULL for data * not mapped using a palette). */ const Histogram* CiftiMappableDataFile::getFileHistogram() { bool updateHistogramFlag = false; const int32_t numberOfBuckets = getFileHistogramNumberOfBuckets(); if (m_fileHistogram != NULL) { if (numberOfBuckets != m_fileHistogramNumberOfBuckets) { updateHistogramFlag = true; } } else { updateHistogramFlag = true; } if (updateHistogramFlag) { std::vector fileData; getFileData(fileData); if ( ! fileData.empty()) { if (m_fileHistogram == NULL) { m_fileHistogram.grabNew(new Histogram(numberOfBuckets)); } m_fileHistogram->update(numberOfBuckets, &fileData[0], fileData.size()); m_fileHistogramNumberOfBuckets = numberOfBuckets; } } return m_fileHistogram; } /** * Get histogram describing the distribution of data * mapped with a color palette for all data in the file * within the given range of values. * * @param mostPositiveValueInclusive * Values more positive than this value are excluded. * @param leastPositiveValueInclusive * Values less positive than this value are excluded. * @param leastNegativeValueInclusive * Values less negative than this value are excluded. * @param mostNegativeValueInclusive * Values more negative than this value are excluded. * @param includeZeroValues * If true zero values (very near zero) are included. * @return * Descriptive statistics for data (will be NULL for data * not mapped using a palette). */ const Histogram* CiftiMappableDataFile::getFileHistogram(const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) { bool updateHistogramFlag = false; const int32_t numberOfBuckets = getFileHistogramNumberOfBuckets(); if (m_fileHistorgramLimitedValues != NULL) { if ((numberOfBuckets != m_fileHistogramLimitedValuesNumberOfBuckets) ||(mostPositiveValueInclusive != m_fileHistogramLimitedValuesMostPositiveValueInclusive) || (leastPositiveValueInclusive != m_fileHistogramLimitedValuesLeastPositiveValueInclusive) || (leastNegativeValueInclusive != m_fileHistogramLimitedValuesLeastNegativeValueInclusive) || (mostNegativeValueInclusive != m_fileHistogramLimitedValuesMostNegativeValueInclusive) || (includeZeroValues != m_fileHistogramLimitedValuesIncludeZeroValues)) { updateHistogramFlag = true; } } else { updateHistogramFlag = true; } if (updateHistogramFlag) { std::vector fileData; getFileData(fileData); if ( ! fileData.empty()) { if (m_fileHistorgramLimitedValues == NULL) { m_fileHistorgramLimitedValues.grabNew(new Histogram()); } m_fileHistorgramLimitedValues->update(numberOfBuckets, &fileData[0], fileData.size(), mostPositiveValueInclusive, leastPositiveValueInclusive, leastNegativeValueInclusive, mostNegativeValueInclusive, includeZeroValues); m_fileHistogramLimitedValuesNumberOfBuckets = numberOfBuckets; m_fileHistogramLimitedValuesMostPositiveValueInclusive = mostPositiveValueInclusive; m_fileHistogramLimitedValuesLeastPositiveValueInclusive = leastPositiveValueInclusive; m_fileHistogramLimitedValuesLeastNegativeValueInclusive = leastNegativeValueInclusive; m_fileHistogramLimitedValuesMostNegativeValueInclusive = mostNegativeValueInclusive; m_fileHistogramLimitedValuesIncludeZeroValues = includeZeroValues; } } return m_fileHistorgramLimitedValues; } /** * Get the palette color mapping for the map at the given index. * * @param mapIndex * Index of the map. * @return * Palette color mapping for the map (will be NULL for data * not mapped using a palette). */ PaletteColorMapping* CiftiMappableDataFile::getMapPaletteColorMapping(const int32_t mapIndex) { CaretAssert(m_ciftiFile); const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); PaletteColorMapping* pcm = NULL; switch (m_colorMappingMethod) { case COLOR_MAPPING_METHOD_INVALID: break; case COLOR_MAPPING_METHOD_LABEL_TABLE: break; case COLOR_MAPPING_METHOD_PALETTE: switch (m_paletteColorMappingSource) { case PALETTE_COLOR_MAPPING_SOURCE_INVALID: break; case PALETTE_COLOR_MAPPING_SOURCE_FROM_FILE: pcm = ciftiXML.getFilePalette(); break; case PALETTE_COLOR_MAPPING_SOURCE_FROM_MAP: CaretAssertVectorIndex(m_mapContent, mapIndex); pcm = m_mapContent[mapIndex]->m_paletteColorMapping; break; } break; } return pcm; } /** * Get the palette color mapping for the map at the given index. * * @param mapIndex * Index of the map. * @return * Palette color mapping for the map (constant) (will be NULL for data * not mapped using a palette). */ const PaletteColorMapping* CiftiMappableDataFile::getMapPaletteColorMapping(const int32_t mapIndex) const { CaretAssert(m_ciftiFile); const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); PaletteColorMapping* pcm = NULL; switch (m_colorMappingMethod) { case COLOR_MAPPING_METHOD_INVALID: break; case COLOR_MAPPING_METHOD_LABEL_TABLE: break; case COLOR_MAPPING_METHOD_PALETTE: switch (m_paletteColorMappingSource) { case PALETTE_COLOR_MAPPING_SOURCE_INVALID: break; case PALETTE_COLOR_MAPPING_SOURCE_FROM_FILE: pcm = ciftiXML.getFilePalette(); break; case PALETTE_COLOR_MAPPING_SOURCE_FROM_MAP: CaretAssertVectorIndex(m_mapContent, mapIndex); pcm = m_mapContent[mapIndex]->m_paletteColorMapping; break; } break; } return pcm; } /** * Get the CIFTI parcels map used for brainordinate mapping. * * @return * Pointer to the map's Cifti Parcels Map or NULL if the file is not * mapped using parcels. */ const CiftiParcelsMap* CiftiMappableDataFile::getCiftiParcelsMapForBrainordinateMapping() const { CaretAssert((m_dataMappingDirectionForCiftiXML == CiftiXML::ALONG_ROW) || (m_dataMappingDirectionForCiftiXML == CiftiXML::ALONG_COLUMN)); return getCiftiParcelsMapForDirection(m_dataMappingDirectionForCiftiXML); } /** * Get the CIFTI parcels map used for data loading. * * @return * Pointer to the map's Cifti Parcels Map or NULL if the file is not * loaded using parcels. */ const CiftiParcelsMap* CiftiMappableDataFile::getCiftiParcelsMapForLoading() const { CaretAssert((m_dataReadingDirectionForCiftiXML == CiftiXML::ALONG_ROW) || (m_dataReadingDirectionForCiftiXML == CiftiXML::ALONG_COLUMN)); return getCiftiParcelsMapForDirection(m_dataReadingDirectionForCiftiXML); } /** * Get the CIFTI parcels for the given direction. * * @param direction * Direction of mapping. MUST BE one of CiftiXML::ALONG_ROW or * CiftiXML::ALONG_COLUMN. * @return * Pointer to the map's Cifti Parcels Map or NULL if the file is not * mapped using parcels or NULL if direction is invalid. */ const CiftiParcelsMap* CiftiMappableDataFile::getCiftiParcelsMapForDirection(const int direction) const { if (m_ciftiFile != NULL) { if ((direction != CiftiXML::ALONG_ROW) && (direction != CiftiXML::ALONG_COLUMN)) { CaretAssert(0); return NULL; } const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); const CiftiMappingType* mapping = ciftiXML.getMap(direction); if (mapping->getType() == CiftiMappingType::PARCELS) { const CiftiParcelsMap* cpm = dynamic_cast(mapping); CaretAssert(cpm); return cpm; } } return NULL; } /** * @return Is the data in the file mapped to colors using * a label table. */ bool CiftiMappableDataFile::isMappedWithLabelTable() const { switch (m_colorMappingMethod) { case COLOR_MAPPING_METHOD_INVALID: break; case COLOR_MAPPING_METHOD_LABEL_TABLE: return true; break; case COLOR_MAPPING_METHOD_PALETTE: break; } return false; } /** * Get the label table for the map at the given index. * * @param mapIndex * Index of the map. * @return * Label table for the map (will be NULL for data * not mapped using a label table). */ GiftiLabelTable* CiftiMappableDataFile::getMapLabelTable(const int32_t mapIndex) { CaretAssertVectorIndex(m_mapContent, mapIndex); switch (m_colorMappingMethod) { case COLOR_MAPPING_METHOD_INVALID: break; case COLOR_MAPPING_METHOD_LABEL_TABLE: return m_mapContent[mapIndex]->m_labelTable; break; case COLOR_MAPPING_METHOD_PALETTE: break; } return NULL; } /** * Get the label table for the map at the given index. * * @param mapIndex * Index of the map. * @return * Label table for the map (constant) (will be NULL for data * not mapped using a label table). */ const GiftiLabelTable* CiftiMappableDataFile::getMapLabelTable(const int32_t mapIndex) const { CaretAssertVectorIndex(m_mapContent, mapIndex); switch (m_colorMappingMethod) { case COLOR_MAPPING_METHOD_INVALID: break; case COLOR_MAPPING_METHOD_LABEL_TABLE: return m_mapContent[mapIndex]->m_labelTable; break; case COLOR_MAPPING_METHOD_PALETTE: break; } return NULL; } /** * Get the palette normalization modes that are supported by the file. * * @param modesSupportedOut * Palette normalization modes supported by a file. Will be * empty for files that are not mapped with a palette. If there * is more than one suppported mode, the first mode in the * vector is assumed to be the default mode. */ void CiftiMappableDataFile::getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) const { modesSupportedOut = m_paletteNormalizationModesSupported; } /** * Update coloring for all maps. * * Note: Overridden since Data-Series files have one palette that is * applied to ALL maps. For data-series, just invalidate the coloring * for all maps (data points). */ void CiftiMappableDataFile::updateScalarColoringForAllMaps() { /* * Just need to invalidate coloring. * Updating coloring for all maps would take time. * Coloring update is triggered by code that colors nodes/voxels * when drawing. */ invalidateColoringInAllMaps(); } /** * Update scalar coloring for a map. * * Note that some CIFTI files can be slow to color due to the need to * retrieve data for the map. Use isMapColoringValid() to avoid * unnecessary calls to isMapColoringValid. * * @param mapIndex * Index of map. */ void CiftiMappableDataFile::updateScalarColoringForMap(const int32_t mapIndex) { CaretAssertVectorIndex(m_mapContent, mapIndex); std::vector data; getMapData(mapIndex, data); m_mapContent[mapIndex]->m_rgbaValid = false; if (isMappedWithPalette()) { FastStatistics* statistics = NULL; switch (getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: statistics = const_cast(getFileFastStatistics()); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: statistics = const_cast(getMapFastStatistics(mapIndex)); break; } m_mapContent[mapIndex]->updateColoring(data, statistics); } else if (isMappedWithLabelTable()) { m_mapContent[mapIndex]->updateColoring(data, NULL); } else { CaretAssert(0); } /* * Force recreation of matrix so that it receives updates to coloring. */ invalidateHistogramChartColoring(); m_matrixGraphicsPrimitive.reset(); m_matrixGraphicsOutlinePrimitive.reset(); } /** * Note that some CIFTI files can be slow to color due to the need to * retrieve data for the map. This method can be used to avoid calls * to updateScalarColoringForMap. * * @param mapIndex * Index of the map. * @return * True if the coloring for the given map index is valid. */ bool CiftiMappableDataFile::isMapColoringValid(const int32_t mapIndex) const { CaretAssertVectorIndex(m_mapContent, mapIndex); return m_mapContent[mapIndex]->m_rgbaValid; } /** * Get the node ins the parcel of the given index. * @param parcelNodes * Output containing the node indices. * @param structure * Structure for which the node indices are requested. * @param selectionIndex * Index of the parcel. * @return true if parcel is valid, else false. */ bool CiftiMappableDataFile::getParcelNodesElementForSelectedParcel(std::set &parcelNodesOut, const StructureEnum::Enum &structure, const int64_t &selectionIndex) const { if (m_ciftiFile->getCiftiXML().getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::PARCELS) return false; const std::vector& parcels = m_ciftiFile->getCiftiXML().getParcelsMap(CiftiXML::ALONG_COLUMN).getParcels(); if(selectionIndex >= 0 && selectionIndex < (int64_t)parcels.size()) { const CiftiParcelsMap::Parcel& parcelOut = parcels[selectionIndex]; std::map >::const_iterator findStruct = parcelOut.m_surfaceNodes.find(structure); if (findStruct != parcelOut.m_surfaceNodes.end()) { parcelNodesOut = findStruct->second; return true; } } return false; } /** * Get the dimensions of the volume. * * @param dimOut1 * First dimension (i) out. * @param dimOut2 * Second dimension (j) out. * @param dimOut3 * Third dimension (k) out. * @param dimTimeOut * Time dimensions out (number of maps) * @param numComponentsOut * Number of components per voxel. */ void CiftiMappableDataFile::getDimensions(int64_t& dimOut1, int64_t& dimOut2, int64_t& dimOut3, int64_t& dimTimeOut, int64_t& numComponentsOut) const { CaretAssert(m_ciftiFile); dimOut1 = 0; dimOut2 = 0; dimOut3 = 0; dimTimeOut = 0; numComponentsOut = 0; if (m_dataMappingDirectionForCiftiXML != S_CIFTI_XML_ALONG_INVALID) { switch (m_ciftiFile->getCiftiXML().getMappingType(m_dataMappingDirectionForCiftiXML)) { case CiftiMappingType::BRAIN_MODELS: { const CiftiBrainModelsMap& myDenseMap = m_ciftiFile->getCiftiXML().getBrainModelsMap(m_dataMappingDirectionForCiftiXML); if (!myDenseMap.hasVolumeData()) return; const VolumeSpace& mySpace = myDenseMap.getVolumeSpace(); const int64_t* dims = mySpace.getDims(); dimOut1 = dims[0]; dimOut2 = dims[1]; dimOut3 = dims[2]; dimTimeOut = 1;//??? numComponentsOut = 1; break; } case CiftiMappingType::PARCELS: { const CiftiParcelsMap& myParcelMap = m_ciftiFile->getCiftiXML().getParcelsMap(m_dataMappingDirectionForCiftiXML); if (!myParcelMap.hasVolumeData()) return; const VolumeSpace& mySpace = myParcelMap.getVolumeSpace(); const int64_t* dims = mySpace.getDims(); dimOut1 = dims[0]; dimOut2 = dims[1]; dimOut3 = dims[2]; dimTimeOut = 1;//??? numComponentsOut = 1; break; } default://nothing else has volume dimensions break; } } } /** * Get the dimensions of the volume. * * @param dimsOut * Will contain 5 elements: (0) X-dimension, (1) Y-dimension * (2) Z-dimension, (3) time, (4) components. */ void CiftiMappableDataFile::getDimensions(std::vector& dimsOut) const { dimsOut.resize(5); int64_t dimI, dimJ, dimK, dimTime, dimComp; getDimensions(dimI, dimJ, dimK, dimTime, dimComp); dimsOut[0] = dimI; dimsOut[1] = dimJ; dimsOut[2] = dimK; dimsOut[3] = dimTime; dimsOut[4] = dimComp; } /** * Get the dimensions of the volume for data loading * * @param dimOut1 * First dimension (i) out. * @param dimOut2 * Second dimension (j) out. * @param dimOut3 * Third dimension (k) out. * @param dimTimeOut * Time dimensions out (number of maps) * @param numComponentsOut * Number of components per voxel. */ void CiftiMappableDataFile::getDimensionsForDataLoading(int64_t& dimOut1, int64_t& dimOut2, int64_t& dimOut3, int64_t& dimTimeOut, int64_t& numComponentsOut) const { CaretAssert(m_ciftiFile); dimOut1 = 0; dimOut2 = 0; dimOut3 = 0; dimTimeOut = 0; numComponentsOut = 0; if (m_dataReadingDirectionForCiftiXML != S_CIFTI_XML_ALONG_INVALID) { switch (m_ciftiFile->getCiftiXML().getMappingType(m_dataReadingDirectionForCiftiXML)) { case CiftiMappingType::BRAIN_MODELS: { const CiftiBrainModelsMap& myDenseMap = m_ciftiFile->getCiftiXML().getBrainModelsMap(m_dataReadingDirectionForCiftiXML); if (!myDenseMap.hasVolumeData()) return; const VolumeSpace& mySpace = myDenseMap.getVolumeSpace(); const int64_t* dims = mySpace.getDims(); dimOut1 = dims[0]; dimOut2 = dims[1]; dimOut3 = dims[2]; dimTimeOut = 1;//??? numComponentsOut = 1; break; } case CiftiMappingType::PARCELS: { const CiftiParcelsMap& myParcelMap = m_ciftiFile->getCiftiXML().getParcelsMap(m_dataReadingDirectionForCiftiXML); if (!myParcelMap.hasVolumeData()) return; const VolumeSpace& mySpace = myParcelMap.getVolumeSpace(); const int64_t* dims = mySpace.getDims(); dimOut1 = dims[0]; dimOut2 = dims[1]; dimOut3 = dims[2]; dimTimeOut = 1;//??? numComponentsOut = 1; break; } default://nothing else has volume dimensions break; } } } /** * Get the dimensions of the volume. * * @param dimsOut * Will contain 5 elements: (0) X-dimension, (1) Y-dimension * (2) Z-dimension, (3) time, (4) components. */ void CiftiMappableDataFile::getDimensionsForDataLoading(std::vector& dimsOut) const { dimsOut.resize(5); int64_t dimI, dimJ, dimK, dimTime, dimComp; getDimensionsForDataLoading(dimI, dimJ, dimK, dimTime, dimComp); dimsOut[0] = dimI; dimsOut[1] = dimJ; dimsOut[2] = dimK; dimsOut[3] = dimTime; dimsOut[4] = dimComp; } /** * @return The number of componenents per voxel in the volume data. */ const int64_t& CiftiMappableDataFile::getNumberOfComponents() const { int64_t dimI, dimJ, dimK, dimTime; static int64_t dimComp = 0; getDimensions(dimI, dimJ, dimK, dimTime, dimComp); return dimComp; } /** * Convert an index to space (coordinates). * * @param indexIn1 * First dimension (i). * @param indexIn2 * Second dimension (j). * @param indexIn3 * Third dimension (k). * @param coordOut1 * Output first (x) coordinate. * @param coordOut2 * Output first (y) coordinate. * @param coordOut3 * Output first (z) coordinate. */ void CiftiMappableDataFile::indexToSpace(const float& indexIn1, const float& indexIn2, const float& indexIn3, float& coordOut1, float& coordOut2, float& coordOut3) const { CaretAssert(m_voxelIndicesToOffsetForDataMapping); m_voxelIndicesToOffsetForDataMapping->indicesToCoordinate(indexIn1, indexIn2, indexIn3, coordOut1, coordOut2, coordOut3); } /** * Convert an index to space (coordinates). * * @param indexIn1 * First dimension (i). * @param indexIn2 * Second dimension (j). * @param indexIn3 * Third dimension (k). * @param coordOut * Output XYZ coordinates. */ void CiftiMappableDataFile::indexToSpace(const float& indexIn1, const float& indexIn2, const float& indexIn3, float* coordOut) const { CaretAssert(m_voxelIndicesToOffsetForDataMapping); m_voxelIndicesToOffsetForDataMapping->indicesToCoordinate(indexIn1, indexIn2, indexIn3, coordOut[0], coordOut[1], coordOut[2]); } /** * Convert an index to space (coordinates). * * @param indexIn * IJK indices * @param coordOut * Output XYZ coordinates. */ void CiftiMappableDataFile::indexToSpace(const int64_t* indexIn, float* coordOut) const { CaretAssert(m_voxelIndicesToOffsetForDataMapping); m_voxelIndicesToOffsetForDataMapping->indicesToCoordinate(indexIn[0], indexIn[1], indexIn[2], coordOut[0], coordOut[1], coordOut[2]); } /** * Convert a coordinate to indices. Note that output indices * MAY NOT BE WITHIN THE VALID VOXEL DIMENSIONS. * * @param coordIn1 * First (x) input coordinate. * @param coordIn2 * Second (y) input coordinate. * @param coordIn3 * Third (z) input coordinate. * @param indexOut1 * First output index (i). * @param indexOut2 * First output index (j). * @param indexOut3 * First output index (k). */ void CiftiMappableDataFile::enclosingVoxel(const float& coordIn1, const float& coordIn2, const float& coordIn3, int64_t& indexOut1, int64_t& indexOut2, int64_t& indexOut3) const { CaretAssert(m_voxelIndicesToOffsetForDataMapping); m_voxelIndicesToOffsetForDataMapping->coordinateToIndices(coordIn1, coordIn2, coordIn3, indexOut1, indexOut2, indexOut3); } /** * Use the method when LOADING data * Convert a coordinate to indices. Note that output indices * MAY NOT BE WITHIN THE VALID VOXEL DIMENSIONS. * * @param coordIn1 * First (x) input coordinate. * @param coordIn2 * Second (y) input coordinate. * @param coordIn3 * Third (z) input coordinate. * @param indexOut1 * First output index (i). * @param indexOut2 * First output index (j). * @param indexOut3 * First output index (k). */ void CiftiMappableDataFile::enclosingVoxelForDataLoading(const float& coordIn1, const float& coordIn2, const float& coordIn3, int64_t& indexOut1, int64_t& indexOut2, int64_t& indexOut3) const { CaretAssert(m_voxelIndicesToOffsetForDataReading); m_voxelIndicesToOffsetForDataReading->coordinateToIndices(coordIn1, coordIn2, coordIn3, indexOut1, indexOut2, indexOut3); } /** * Determine in the given voxel indices are valid (within the volume dimensions). * * @param indexIn1 * First dimension (i). * @param indexIn2 * Second dimension (j). * @param indexIn3 * Third dimension (k). * @param coordOut1 * Output first (x) coordinate. * @param brickIndex * Time/map index (default 0). * @param component * Voxel component (default 0). */ bool CiftiMappableDataFile::indexValid(const int64_t& indexIn1, const int64_t& indexIn2, const int64_t& indexIn3, const int64_t /*brickIndex*/, const int64_t /*component*/) const { std::vector volumeDimensions; getDimensions(volumeDimensions); CaretAssertVectorIndex(volumeDimensions, 2); if ((indexIn1 >= 0) && (indexIn1 < volumeDimensions[0]) && (indexIn2 >= 0) && (indexIn2 < volumeDimensions[1]) && (indexIn3 >= 0) && (indexIn3 < volumeDimensions[2])) { return true; } return false; } /** * Determine in the given voxel indices are valid (within the volume dimensions). * * @param indexIn1 * First dimension (i). * @param indexIn2 * Second dimension (j). * @param indexIn3 * Third dimension (k). * @param coordOut1 * Output first (x) coordinate. * @param brickIndex * Time/map index (default 0). * @param component * Voxel component (default 0). */ bool CiftiMappableDataFile::indexValidForDataLoading(const int64_t& indexIn1, const int64_t& indexIn2, const int64_t& indexIn3, const int64_t /*brickIndex*/, const int64_t /*component*/) const { std::vector volumeDimensions; getDimensionsForDataLoading(volumeDimensions); CaretAssertVectorIndex(volumeDimensions, 2); if ((indexIn1 >= 0) && (indexIn1 < volumeDimensions[0]) && (indexIn2 >= 0) && (indexIn2 < volumeDimensions[1]) && (indexIn3 >= 0) && (indexIn3 < volumeDimensions[2])) { return true; } return false; } const VolumeSpace& CiftiMappableDataFile::getVolumeSpace() const { CaretAssert(m_voxelIndicesToOffsetForDataMapping);//because this is where the other space functions get their volume space from, just roll with it for now return m_voxelIndicesToOffsetForDataMapping->getVolumeSpace(); } /** * Get a bounding box for the voxel coordinate ranges. * * @param boundingBoxOut * The output bounding box. */ void CiftiMappableDataFile::getVoxelSpaceBoundingBox(BoundingBox& boundingBoxOut) const { CaretAssert(m_voxelIndicesToOffsetForDataMapping); boundingBoxOut.resetForUpdate(); std::vector volumeDimensions(5, 0); getDimensions(volumeDimensions); CaretAssertVectorIndex(volumeDimensions, 2); if (m_voxelIndicesToOffsetForDataMapping->isValid()) { float xyz[3]; indexToSpace(0, 0, 0, xyz); boundingBoxOut.update(xyz); indexToSpace(volumeDimensions[0] - 1, volumeDimensions[1] - 1, volumeDimensions[2] - 1, xyz); boundingBoxOut.update(xyz); } else { boundingBoxOut.resetZeros(); } } /** * Get the voxel colors for a slice in the map. * * @param mapIndex * Index of the map. * @param slicePlane * The slice plane. * @param sliceIndex * Index of the slice. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbaOut * Output containing the rgba values (must have been allocated * by caller to sufficient count of elements in the slice). * @return * Number of voxels with alpha greater than zero */ int64_t CiftiMappableDataFile::getVoxelColorsForSliceInMap(const int32_t mapIndex, const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const { CaretAssertVectorIndex(m_mapContent, mapIndex); CaretAssertMessage((sliceIndex >= 0), "Slice index is invalid."); if (sliceIndex < 0) { return 0; } if (isMapColoringValid(mapIndex) == false) { CiftiMappableDataFile* nonConstThis = const_cast(this); nonConstThis->updateScalarColoringForMap(mapIndex); } int64_t dimI, dimJ, dimK, dimTime, dimComp; getDimensions(dimI, dimJ, dimK, dimTime, dimComp); int64_t voxelCount = 0; switch (slicePlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: voxelCount = dimI * dimJ; CaretAssert((sliceIndex < dimK)); if (sliceIndex >= dimK) { return 0; } break; case VolumeSliceViewPlaneEnum::CORONAL: voxelCount = dimI * dimK; CaretAssert((sliceIndex < dimJ)); if (sliceIndex >= dimJ) { return 0; } break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: voxelCount = dimJ * dimK; CaretAssert((sliceIndex < dimI)); if (sliceIndex >= dimI) { return 0; } break; } if (voxelCount <= 0) { return 0; } const int64_t componentCount = voxelCount * 4; /* * Clear the slice rgba coloring. */ for (int64_t i = 0; i < componentCount; i++) { rgbaOut[i] = 0; } const int64_t mapRgbaCount = m_mapContent[mapIndex]->m_rgba.size(); /* * RGBA size will be zero if no data has been loaded for a CIFTI * matrix type file (user clicking brainordinate). */ if (mapRgbaCount <= 0) { return 0; } const uint8_t* mapRGBA = &m_mapContent[mapIndex]->m_rgba[0]; CaretAssert(m_voxelIndicesToOffsetForDataMapping); /* * Data values are only needed when a label volume * is being drawn so that we can determine if the * label is displayed. */ std::vector dataValues; const GiftiLabelTable* labelTable = (isMappedWithLabelTable() ? getMapLabelTable(mapIndex) : NULL); if (isMappedWithLabelTable()) { CaretAssert(labelTable); getMapData(mapIndex, dataValues); } int64_t validVoxelCount = 0; /* * Set the rgba components for the slice. */ switch (slicePlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: for (int64_t j = 0; j < dimJ; j++) { for (int64_t i = 0; i < dimI; i++) { const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(i, j, sliceIndex); if (dataOffset >= 0) { const int64_t dataOffset4 = dataOffset * 4; CaretAssert(dataOffset4 < mapRgbaCount); const int64_t rgbaOffset = ((j * dimI) + i) * 4; CaretAssert(rgbaOffset < componentCount); rgbaOut[rgbaOffset] = mapRGBA[dataOffset4]; rgbaOut[rgbaOffset+1] = mapRGBA[dataOffset4+1]; rgbaOut[rgbaOffset+2] = mapRGBA[dataOffset4+2]; uint8_t alpha = mapRGBA[dataOffset4+3]; if (alpha > 0) { if (labelTable != NULL) { /* * For label data, verify that the label is displayed. * If NOT displayed, zero out the alpha value to * prevent display of the data. */ CaretAssertVectorIndex(dataValues, dataOffset); const int32_t dataValue = dataValues[dataOffset]; const GiftiLabel* label = labelTable->getLabel(dataValue); if (label != NULL) { const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); CaretAssert(item); if (item->isSelected(displayGroup, tabIndex) == false) { alpha = 0; } } } } if (alpha > 0) { ++validVoxelCount; } rgbaOut[rgbaOffset+3] = alpha; } } } break; case VolumeSliceViewPlaneEnum::CORONAL: for (int64_t k = 0; k < dimK; k++) { for (int64_t i = 0; i < dimI; i++) { const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(i, sliceIndex, k); if (dataOffset >= 0) { const int64_t dataOffset4 = dataOffset * 4; CaretAssert(dataOffset4 < mapRgbaCount); const int64_t rgbaOffset = ((k * dimI) + i) * 4; CaretAssert(rgbaOffset < componentCount); rgbaOut[rgbaOffset] = mapRGBA[dataOffset4]; rgbaOut[rgbaOffset+1] = mapRGBA[dataOffset4+1]; rgbaOut[rgbaOffset+2] = mapRGBA[dataOffset4+2]; uint8_t alpha = mapRGBA[dataOffset4+3]; if (alpha > 0) { if (labelTable != NULL) { /* * For label data, verify that the label is displayed. * If NOT displayed, zero out the alpha value to * prevent display of the data. */ CaretAssertVectorIndex(dataValues, dataOffset); const int32_t dataValue = dataValues[dataOffset]; const GiftiLabel* label = labelTable->getLabel(dataValue); if (label != NULL) { const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); CaretAssert(item); if (item->isSelected(displayGroup, tabIndex) == false) { alpha = 0; } } } } if (alpha > 0) { ++validVoxelCount; } rgbaOut[rgbaOffset+3] = alpha; } } } break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: for (int64_t k = 0; k < dimK; k++) { for (int64_t j = 0; j < dimJ; j++) { const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(sliceIndex, j, k); if (dataOffset >= 0) { const int64_t dataOffset4 = dataOffset * 4; CaretAssert(dataOffset4 < mapRgbaCount); const int64_t rgbaOffset = ((k * dimJ) + j) * 4; CaretAssert(rgbaOffset < componentCount); rgbaOut[rgbaOffset] = mapRGBA[dataOffset4]; rgbaOut[rgbaOffset+1] = mapRGBA[dataOffset4+1]; rgbaOut[rgbaOffset+2] = mapRGBA[dataOffset4+2]; uint8_t alpha = mapRGBA[dataOffset4+3]; if (alpha > 0) { if (labelTable != NULL) { /* * For label data, verify that the label is displayed. * If NOT displayed, zero out the alpha value to * prevent display of the data. */ CaretAssertVectorIndex(dataValues, dataOffset); const int32_t dataValue = dataValues[dataOffset]; const GiftiLabel* label = labelTable->getLabel(dataValue); if (label != NULL) { const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); CaretAssert(item); if (item->isSelected(displayGroup, tabIndex) == false) { alpha = 0; } } } } if (alpha > 0) { ++validVoxelCount; } rgbaOut[rgbaOffset+3] = alpha; } } } break; } return validVoxelCount; } /** * Get voxel coloring for a set of voxels. * * @param mapIndex * Index of map. * @param firstVoxelIJK * IJK Indices of first voxel * @param rowStepIJK * IJK Step for moving to next row. * @param columnStepIJK * IJK Step for moving to next column. * @param numberOfRows * Number of rows. * @param numberOfColumns * Number of columns. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbaOut * RGBA color components out. * @return * Number of voxels with alpha greater than zero */ int64_t CiftiMappableDataFile::getVoxelColorsForSliceInMap(const int32_t mapIndex, const int64_t firstVoxelIJK[3], const int64_t rowStepIJK[3], const int64_t columnStepIJK[3], const int64_t numberOfRows, const int64_t numberOfColumns, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const { CaretAssertVectorIndex(m_mapContent, mapIndex); if (isMapColoringValid(mapIndex) == false) { CiftiMappableDataFile* nonConstThis = const_cast(this); nonConstThis->updateScalarColoringForMap(mapIndex); } const int64_t mapRgbaCount = m_mapContent[mapIndex]->m_rgba.size(); /* * RGBA size will be zero if no data has been loaded for a CIFTI * matrix type file (user clicking brainordinate). */ if (mapRgbaCount <= 0) { return 0; } const uint8_t* mapRGBA = &m_mapContent[mapIndex]->m_rgba[0]; CaretAssert(m_voxelIndicesToOffsetForDataMapping); /* * Data values are only needed when a label volume * is being drawn so that we can determine if the * label is displayed. */ std::vector dataValues; const GiftiLabelTable* labelTable = (isMappedWithLabelTable() ? getMapLabelTable(mapIndex) : NULL); if (isMappedWithLabelTable()) { CaretAssert(labelTable); getMapData(mapIndex, dataValues); } int64_t rowIJK[3] = { firstVoxelIJK[0], firstVoxelIJK[1], firstVoxelIJK[2] }; uint8_t rgba[4] = { 0, 0, 0, 0 }; int64_t rgbaOutIndex4 = 0; int64_t validVoxelCount = 0; for (int32_t iRow = 0; iRow < numberOfRows; iRow++) { int64_t ijk[3] = { rowIJK[0], rowIJK[1], rowIJK[2] }; for (int32_t iCol = 0; iCol < numberOfColumns; iCol++) { rgba[3] = 0; const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(ijk[0], ijk[1], ijk[2]); if (dataOffset >= 0) { const int64_t dataOffset4 = dataOffset * 4; CaretAssert(dataOffset4 < mapRgbaCount); rgba[0] = mapRGBA[dataOffset4]; rgba[1] = mapRGBA[dataOffset4+1]; rgba[2] = mapRGBA[dataOffset4+2]; uint8_t alpha = mapRGBA[dataOffset4+3]; if (alpha > 0) { if (labelTable != NULL) { /* * For label data, verify that the label is displayed. * If NOT displayed, zero out the alpha value to * prevent display of the data. */ CaretAssertVectorIndex(dataValues, dataOffset); const int32_t dataValue = dataValues[dataOffset]; const GiftiLabel* label = labelTable->getLabel(dataValue); if (label != NULL) { const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); CaretAssert(item); if (item->isSelected(displayGroup, tabIndex) == false) { alpha = 0; } } } } if (alpha > 0) { ++validVoxelCount; } rgba[3] = alpha; } if (rgba[3] > 0) { rgbaOut[rgbaOutIndex4] = rgba[0]; rgbaOut[rgbaOutIndex4+1] = rgba[1]; rgbaOut[rgbaOutIndex4+2] = rgba[2]; rgbaOut[rgbaOutIndex4+3] = rgba[3]; } else { /* Fixes blending */ rgbaOut[rgbaOutIndex4] = 0; rgbaOut[rgbaOutIndex4+1] = 0; rgbaOut[rgbaOutIndex4+2] = 0; rgbaOut[rgbaOutIndex4+3] = 0; } rgbaOutIndex4 += 4; if (rgba[3] > 0) { validVoxelCount++; } ijk[0] += columnStepIJK[0]; ijk[1] += columnStepIJK[1]; ijk[2] += columnStepIJK[2]; } rowIJK[0] += rowStepIJK[0]; rowIJK[1] += rowStepIJK[1]; rowIJK[2] += rowStepIJK[2]; } return validVoxelCount; } /** * Get the voxel colors for a sub slice in the map. * * @param mapIndex * Index of the map. * @param slicePlane * The slice plane. * @param sliceIndex * Index of the slice. * @param firstCornerVoxelIndex * Indices of voxel for first corner of sub-slice (inclusive). * @param lastCornerVoxelIndex * Indices of voxel for last corner of sub-slice (inclusive). * @param voxelCountIJK * Voxel counts for each axis. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbaOut * Output containing the rgba values (must have been allocated * by caller to sufficient count of elements in the slice). * @return * Number of voxels with alpha greater than zero */ int64_t CiftiMappableDataFile::getVoxelColorsForSubSliceInMap(const int32_t mapIndex, const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, const int64_t firstCornerVoxelIndex[3], const int64_t lastCornerVoxelIndex[3], const int64_t voxelCountIJK[3], const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const { CaretAssertVectorIndex(m_mapContent, mapIndex); CaretAssertMessage((sliceIndex >= 0), "Slice index is invalid."); if (sliceIndex < 0) { return 0; } if (isMapColoringValid(mapIndex) == false) { CiftiMappableDataFile* nonConstThis = const_cast(this); nonConstThis->updateScalarColoringForMap(mapIndex); } const int64_t iStart = firstCornerVoxelIndex[0]; const int64_t jStart = firstCornerVoxelIndex[1]; const int64_t kStart = firstCornerVoxelIndex[2]; const int64_t iEnd = lastCornerVoxelIndex[0]; const int64_t jEnd = lastCornerVoxelIndex[1]; const int64_t kEnd = lastCornerVoxelIndex[2]; const int64_t voxelCountI = voxelCountIJK[0]; const int64_t voxelCountJ = voxelCountIJK[1]; const int64_t voxelCountK = voxelCountIJK[2]; int64_t dimI, dimJ, dimK, dimTime, dimComp; getDimensions(dimI, dimJ, dimK, dimTime, dimComp); int64_t voxelCount = 0; switch (slicePlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: voxelCount = voxelCountI * voxelCountJ; CaretAssert((sliceIndex < dimK)); if (sliceIndex >= dimK) { return 0; } break; case VolumeSliceViewPlaneEnum::CORONAL: voxelCount = voxelCountI * voxelCountK; CaretAssert((sliceIndex < dimJ)); if (sliceIndex >= dimJ) { return 0; } break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: voxelCount = voxelCountJ * voxelCountK; CaretAssert((sliceIndex < dimI)); if (sliceIndex >= dimI) { return 0; } break; } if (voxelCount <= 0) { return 0; } const int64_t componentCount = voxelCount * 4; /* * Clear the slice rgba coloring. */ for (int64_t i = 0; i < componentCount; i++) { rgbaOut[i] = 0; } const int64_t mapRgbaCount = m_mapContent[mapIndex]->m_rgba.size(); /* * RGBA size will be zero if no data has been loaded for a CIFTI * matrix type file (user clicking brainordinate). */ if (mapRgbaCount <= 0) { return 0; } const uint8_t* mapRGBA = &m_mapContent[mapIndex]->m_rgba[0]; CaretAssert(m_voxelIndicesToOffsetForDataMapping); /* * Data values are only needed when a label volume * is being drawn so that we can determine if the * label is displayed. */ std::vector dataValues; const GiftiLabelTable* labelTable = (isMappedWithLabelTable() ? getMapLabelTable(mapIndex) : NULL); if (isMappedWithLabelTable()) { CaretAssert(labelTable); getMapData(mapIndex, dataValues); } /* * Note that step indices may be positive or negative */ const int64_t kStep = ((kEnd < kStart) ? -1 : 1); const int64_t jStep = ((jEnd < jStart) ? -1 : 1); const int64_t iStep = ((iEnd < iStart) ? -1 : 1); int64_t validVoxelCount = 0; /* * Set the rgba components for the slice. */ switch (slicePlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: { int64_t rgbaOffset = 0; int64_t j = jStart; bool jLoopFlag = true; while (jLoopFlag) { int64_t i = iStart; bool iLoopFlag = true; while (iLoopFlag) { const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(i, j, sliceIndex); if (dataOffset >= 0) { const int64_t dataOffset4 = dataOffset * 4; CaretAssert(dataOffset4 < mapRgbaCount); CaretAssert(rgbaOffset < componentCount); rgbaOut[rgbaOffset] = mapRGBA[dataOffset4]; rgbaOut[rgbaOffset+1] = mapRGBA[dataOffset4+1]; rgbaOut[rgbaOffset+2] = mapRGBA[dataOffset4+2]; uint8_t alpha = mapRGBA[dataOffset4+3]; if (alpha > 0) { if (labelTable != NULL) { /* * For label data, verify that the label is displayed. * If NOT displayed, zero out the alpha value to * prevent display of the data. */ CaretAssertVectorIndex(dataValues, dataOffset); const int32_t dataValue = dataValues[dataOffset]; const GiftiLabel* label = labelTable->getLabel(dataValue); if (label != NULL) { const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); CaretAssert(item); if (item->isSelected(displayGroup, tabIndex) == false) { alpha = 0; } } } } if (alpha > 0) { ++validVoxelCount; } rgbaOut[rgbaOffset+3] = alpha; } if (i == iEnd) { iLoopFlag = false; } else { i += iStep; } rgbaOffset += 4; } if (j == jEnd) { jLoopFlag = false; } else { j += jStep; } } } break; case VolumeSliceViewPlaneEnum::CORONAL: { int64_t rgbaOffset = 0; int64_t k = kStart; bool kLoopFlag = true; while (kLoopFlag) { int64_t i = iStart; bool iLoopFlag = true; while (iLoopFlag) { const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(i, sliceIndex, k); if (dataOffset >= 0) { const int64_t dataOffset4 = dataOffset * 4; CaretAssert(dataOffset4 < mapRgbaCount); CaretAssert(rgbaOffset < componentCount); rgbaOut[rgbaOffset] = mapRGBA[dataOffset4]; rgbaOut[rgbaOffset+1] = mapRGBA[dataOffset4+1]; rgbaOut[rgbaOffset+2] = mapRGBA[dataOffset4+2]; uint8_t alpha = mapRGBA[dataOffset4+3]; if (alpha > 0) { if (labelTable != NULL) { /* * For label data, verify that the label is displayed. * If NOT displayed, zero out the alpha value to * prevent display of the data. */ CaretAssertVectorIndex(dataValues, dataOffset); const int32_t dataValue = dataValues[dataOffset]; const GiftiLabel* label = labelTable->getLabel(dataValue); if (label != NULL) { const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); CaretAssert(item); if (item->isSelected(displayGroup, tabIndex) == false) { alpha = 0; } } } } if (alpha > 0) { ++validVoxelCount; } rgbaOut[rgbaOffset+3] = alpha; } if (i == iEnd) { iLoopFlag = false; } else { i += iStep; } rgbaOffset += 4; } if (k == kEnd) { kLoopFlag = false; } else { k += kStep; } } } break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: { int64_t rgbaOffset = 0; int64_t k = kStart; bool kLoopFlag = true; while (kLoopFlag) { int64_t j = jStart; bool jLoopFlag = true; while (jLoopFlag) { const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(sliceIndex, j, k); if (dataOffset >= 0) { const int64_t dataOffset4 = dataOffset * 4; CaretAssert(dataOffset4 < mapRgbaCount); CaretAssert(rgbaOffset < componentCount); rgbaOut[rgbaOffset] = mapRGBA[dataOffset4]; rgbaOut[rgbaOffset+1] = mapRGBA[dataOffset4+1]; rgbaOut[rgbaOffset+2] = mapRGBA[dataOffset4+2]; uint8_t alpha = mapRGBA[dataOffset4+3]; if (alpha > 0) { if (labelTable != NULL) { /* * For label data, verify that the label is displayed. * If NOT displayed, zero out the alpha value to * prevent display of the data. */ CaretAssertVectorIndex(dataValues, dataOffset); const int32_t dataValue = dataValues[dataOffset]; const GiftiLabel* label = labelTable->getLabel(dataValue); if (label != NULL) { const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); CaretAssert(item); if (item->isSelected(displayGroup, tabIndex) == false) { alpha = 0; } } } } if (alpha > 0) { ++validVoxelCount; } rgbaOut[rgbaOffset+3] = alpha; } if (j == jEnd) { jLoopFlag = false; } else { j += jStep; } rgbaOffset += 4; } if (k == kEnd) { kLoopFlag = false; } else { k += kStep; } } } break; } return validVoxelCount; } /** * Get the voxel coloring for the voxel at the given indices. * This method is for label data. Accessing the actual voxel values is * needed for coloring labels. But, one can only access the entire set * of values for a map. Since this method is typically called many times * when coloring slices in ALL view, get the map data value before calling * this and then pass them in. * * This will work for non-label data. * * @param dataForMap * Data for the map. * @param indexIn1 * First dimension (i). * @param indexIn2 * Second dimension (j). * @param indexIn3 * Third dimension (k). * @param mapIndex * Time/map index. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbaOut * Output containing RGBA values for voxel at the given indices. */ void CiftiMappableDataFile::getVoxelColorInMapForLabelData(const std::vector& dataForMap, const int64_t indexIn1, const int64_t indexIn2, const int64_t indexIn3, const int64_t mapIndex, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t rgbaOut[4]) const { getVoxelColorInMap(indexIn1, indexIn2, indexIn3, mapIndex, displayGroup, tabIndex, rgbaOut); if (isMappedWithLabelTable()) { if (rgbaOut[3] > 0.0) { const GiftiLabelTable* labelTable = getMapLabelTable(mapIndex); CaretAssert(labelTable); const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(indexIn1, indexIn2, indexIn3); if (dataOffset >= 0) { /* * If the label is NOT selected for the given display * group and tab, inhibit its display by setting the * alpha component to zero. */ CaretAssertVectorIndex(dataForMap, dataOffset); const int32_t labelKey = dataForMap[dataOffset]; const GiftiLabel* label = labelTable->getLabel(labelKey); if (label != NULL) { const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); if (item != NULL) { if (item->isSelected(displayGroup, tabIndex) == false) { rgbaOut[3] = 0; } } } } } } } /** * Get the voxel coloring for the voxel at the given indices. * * @see getVoxelColorInMapForLabelData * * @param indexIn1 * First dimension (i). * @param indexIn2 * Second dimension (j). * @param indexIn3 * Third dimension (k). * @param mapIndex * Time/map index. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbaOut * Output containing RGBA values for voxel at the given indices. */ void CiftiMappableDataFile::getVoxelColorInMap(const int64_t indexIn1, const int64_t indexIn2, const int64_t indexIn3, const int64_t mapIndex, const DisplayGroupEnum::Enum /*displayGroup*/, const int32_t /*tabIndex*/, uint8_t rgbaOut[4]) const { rgbaOut[0] = 0; rgbaOut[1] = 0; rgbaOut[2] = 0; rgbaOut[3] = 0; if ( ! isMapColoringValid(mapIndex)) { CiftiMappableDataFile* nonConstThis = const_cast(this); nonConstThis->updateScalarColoringForMap(mapIndex); } CaretAssert(m_voxelIndicesToOffsetForDataMapping); const int64_t mapRgbaCount = m_mapContent[mapIndex]->m_rgba.size(); if (mapRgbaCount <= 0) { return; } const uint8_t* mapRGBA = &m_mapContent[mapIndex]->m_rgba[0]; const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(indexIn1, indexIn2, indexIn3); if (dataOffset >= 0) { const int64_t dataOffset4 = dataOffset * 4; CaretAssert(dataOffset4 < mapRgbaCount); rgbaOut[0] = mapRGBA[dataOffset4]; rgbaOut[1] = mapRGBA[dataOffset4+1]; rgbaOut[2] = mapRGBA[dataOffset4+2]; rgbaOut[3] = mapRGBA[dataOffset4+3]; } } /** * Get the brainordinate from the given row. * * @param rowIndex * Index of the row. * @param surfaceStructureOut * Will contain structure of surface if row is a surface node. * @param surfaceNodeIndexOut * Will contain index of surface node if row is a surface node. * @param surfaceNumberOfNodesOut * Will contain surfaces number of nodes if row is a surface node. * @param surfaceNodeValidOut * Will be true upon exit if the row corresponded to a surface node. * @param voxelIJKOut * Will contain the voxel's IJK indices if row is a surface node. * @param voxelXYZOut * Will contain the voxel's XYZ coordinate if row is a surface node. * @param voxelValidOut * Will be true upon exit if the row corresponded to a surface node. * @throw DataFileException * If the rows are not for brainordinates or the row index is invalid. */ void CiftiMappableDataFile::getBrainordinateFromRowIndex(const int64_t rowIndex, StructureEnum::Enum& surfaceStructureOut, int32_t& surfaceNodeIndexOut, int32_t& surfaceNumberOfNodesOut, bool& surfaceNodeValidOut, int64_t voxelIJKOut[3], float voxelXYZOut[3], bool& voxelValidOut) const { surfaceNodeValidOut = false; voxelValidOut = false; if (m_ciftiFile == NULL) { return; } const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); if (ciftiXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) { throw DataFileException(getFileName(), "File does not have brainordinate data for rows."); return; } const CiftiBrainModelsMap& brainMap = ciftiXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); if ((rowIndex < 0) || (rowIndex >= m_ciftiFile->getNumberOfRows())) { throw DataFileException(getFileName(), "Row index " + AString::number(rowIndex) + " is out of range [0, " + AString::number(m_ciftiFile->getNumberOfRows() - 1) + "]"); } const CiftiBrainModelsMap::IndexInfo indexInfo = brainMap.getInfoForIndex(rowIndex); switch (indexInfo.m_type) { case CiftiBrainModelsMap::SURFACE: surfaceStructureOut = indexInfo.m_structure; surfaceNodeIndexOut = indexInfo.m_surfaceNode; surfaceNumberOfNodesOut = brainMap.getSurfaceNumberOfNodes(surfaceStructureOut); surfaceNodeValidOut = true; break; case CiftiBrainModelsMap::VOXELS: voxelIJKOut[0] = indexInfo.m_ijk[0]; voxelIJKOut[1] = indexInfo.m_ijk[1]; voxelIJKOut[2] = indexInfo.m_ijk[2]; indexToSpace(voxelIJKOut, voxelXYZOut); voxelValidOut = true; break; } } /** * Get the unique label keys in the given map. * @param mapIndex * Index of the map. * @return * Keys used by the map. */ std::vector CiftiMappableDataFile::getUniqueLabelKeysUsedInMap(const int32_t mapIndex) const { CaretAssertVectorIndex(m_mapContent, mapIndex); std::vector data; getMapData(mapIndex, data); std::set uniqueKeys; const int64_t numItems = static_cast(data.size()); if (numItems > 0) { const float* dataPtr = &data[0]; for (int64_t i = 0; i < numItems; i++) { const int32_t key = static_cast(dataPtr[i]); uniqueKeys.insert(key); } } std::vector keyVector; keyVector.insert(keyVector.end(), uniqueKeys.begin(), uniqueKeys.end()); return keyVector; } /** * @return The class and name hierarchy. */ GroupAndNameHierarchyModel* CiftiMappableDataFile::getGroupAndNameHierarchyModel() { CaretAssert(m_classNameHierarchy); m_classNameHierarchy->update(this, m_forceUpdateOfGroupAndNameHierarchy); m_forceUpdateOfGroupAndNameHierarchy = false; return m_classNameHierarchy; } /** * @return The class and name hierarchy. */ const GroupAndNameHierarchyModel* CiftiMappableDataFile::getGroupAndNameHierarchyModel() const { CaretAssert(m_classNameHierarchy); m_classNameHierarchy->update(const_cast(this), m_forceUpdateOfGroupAndNameHierarchy); m_forceUpdateOfGroupAndNameHierarchy = false; return m_classNameHierarchy; } /** * Validate keys and labels in the file. */ void CiftiMappableDataFile::validateKeysAndLabels() const { /* * Skip if not label file */ if (isMappedWithLabelTable() == false) { return; } /* * Skip if logging is not fine or less. */ if (CaretLogger::getLogger()->isFine() == false) { return; } AString messages; /* * Find the label keys that are in the data */ std::set dataKeys; const int32_t numMaps = getNumberOfMaps(); for (int32_t jMap = 0; jMap < numMaps; jMap++) { AString mapMessage; std::vector data; getMapData(jMap, data); const int64_t numItems = static_cast(data.size()); for (int32_t i = 0; i < numItems; i++) { const int32_t key = static_cast(data[i]); dataKeys.insert(key); } /* * Find any keys that are not in the label table */ const GiftiLabelTable* labelTable = getMapLabelTable(jMap); std::set missingLabelKeys; for (std::set::iterator dataKeyIter = dataKeys.begin(); dataKeyIter != dataKeys.end(); dataKeyIter++) { const int32_t dataKey = *dataKeyIter; const GiftiLabel* label = labelTable->getLabel(dataKey); if (label == NULL) { missingLabelKeys.insert(dataKey); } } if (missingLabelKeys.empty() == false) { for (std::set::iterator missingKeyIter = missingLabelKeys.begin(); missingKeyIter != missingLabelKeys.end(); missingKeyIter++) { const int32_t missingKey = *missingKeyIter; mapMessage.appendWithNewLine(" Missing Label for Key: " + AString::number(missingKey)); } } /* * Find any label table names that are not used */ std::map labelTableKeysAndNames; labelTable->getKeysAndNames(labelTableKeysAndNames); for (std::map::const_iterator ltIter = labelTableKeysAndNames.begin(); ltIter != labelTableKeysAndNames.end(); ltIter++) { const int32_t ltKey = ltIter->first; if (std::find(dataKeys.begin(), dataKeys.end(), ltKey) == dataKeys.end()) { mapMessage.appendWithNewLine(" Label Not Used Key=" + AString::number(ltKey) + ": " + ltIter->second); } } if (mapMessage.isEmpty() == false) { mapMessage = (" Map: " + getMapName(jMap) + ":\n" + mapMessage + "\n" + labelTable->toFormattedString(" ")); messages += mapMessage; } } AString msg = ("File: " + getFileName() + "\n" + messages); CaretLogFine(msg); } /** * Get connectivity value for a surface's node. When the data is mapped * to parcels, the numerical value will not be valid. * * @param mapIndex * Index of the map. * @param structure * Surface's structure. * @param nodeIndex * Index of the node * @param numberOfNodes * Number of nodes in the surface. * @param numericalValueOut * Numerical value out. * @param numericalValueOutValid * Output that indicates the numerical value output is valid. * For label data, this value will be the lable key. * @param textValueOut * Text containing node' value will always be valid if the method * returns true. For parcel data, this will contain the name of the * parcel. For label data, this will contain the name of the label. * For numerical data, this will contain the text representation * of the numerical value. * @return * True if the text value is valid. The numerical value may or may not * also be valid. */ bool CiftiMappableDataFile::getMapSurfaceNodeValue(const int32_t mapIndex, const StructureEnum::Enum structure, const int nodeIndex, const int32_t numberOfNodes, float& numericalValueOut, bool& numericalValueOutValid, AString& textValueOut) const { numericalValueOut = 0.0; numericalValueOutValid = false; CaretAssertVectorIndex(m_mapContent, mapIndex); CaretAssert(m_ciftiFile); const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); CaretAssert((m_dataMappingDirectionForCiftiXML == CiftiXML::ALONG_ROW) || (m_dataMappingDirectionForCiftiXML == CiftiXML::ALONG_COLUMN)); switch (ciftiXML.getMappingType(m_dataMappingDirectionForCiftiXML)) { case CiftiMappingType::BRAIN_MODELS: { const CiftiBrainModelsMap& map = ciftiXML.getBrainModelsMap(m_dataMappingDirectionForCiftiXML); if (map.getSurfaceNumberOfNodes(structure) == numberOfNodes) { const int64_t dataIndex = map.getIndexForNode(nodeIndex, structure); if (dataIndex >= 0) { std::vector mapData; getMapData(mapIndex, mapData); if (dataIndex < static_cast(mapData.size())) { numericalValueOut = mapData[dataIndex]; numericalValueOutValid = true; if (ciftiXML.getMappingType(m_dataReadingDirectionForCiftiXML) == CiftiMappingType::LABELS) { const GiftiLabelTable* glt = getMapLabelTable(mapIndex); const int32_t labelKey = static_cast(numericalValueOut); const GiftiLabel* gl = glt->getLabel(labelKey); if (gl != NULL) { textValueOut += gl->getName(); } else { textValueOut += ("InvalidLabelKey=" + AString::number(labelKey)); } } else { textValueOut = AString::number(numericalValueOut, 'f'); } return true; } } } } break; case CiftiMappingType::LABELS: CaretAssertMessage(0, "Mapping type should never be LABELS"); break; case CiftiMappingType::PARCELS: { int64_t parcelIndex = -1; const CiftiParcelsMap& map = ciftiXML.getParcelsMap(m_dataMappingDirectionForCiftiXML); if (map.getSurfaceNumberOfNodes(structure) == numberOfNodes) { const std::vector& parcels = map.getParcels(); parcelIndex = map.getIndexForNode(nodeIndex, structure); if ((parcelIndex >= 0) && (parcelIndex < static_cast(parcels.size()))) { textValueOut = parcels[parcelIndex].m_name; std::vector mapData; getMapData(mapIndex, mapData); } } if (parcelIndex >= 0) { int64_t itemIndex = -1; switch (ciftiXML.getMappingType(m_dataReadingDirectionForCiftiXML)) { case CiftiMappingType::BRAIN_MODELS: { const CiftiBrainModelsMap& map = ciftiXML.getBrainModelsMap(m_dataReadingDirectionForCiftiXML); if (map.getSurfaceNumberOfNodes(structure) == numberOfNodes) { itemIndex = map.getIndexForNode(nodeIndex, structure); } } break; case CiftiMappingType::LABELS: break; case CiftiMappingType::PARCELS: itemIndex = mapIndex; break; case CiftiMappingType::SCALARS: itemIndex = mapIndex; break; case CiftiMappingType::SERIES: itemIndex = mapIndex; break; } if (itemIndex >= 0) { const int64_t numRows = m_ciftiFile->getNumberOfRows(); const int64_t numCols = m_ciftiFile->getNumberOfColumns(); switch (m_dataReadingDirectionForCiftiXML) { case CiftiXML::ALONG_COLUMN: { std::vector data; data.resize(numRows); CaretAssert(parcelIndex < numCols); m_ciftiFile->getColumn(&data[0], parcelIndex); CaretAssertVectorIndex(data, itemIndex); textValueOut += (" " + AString::number(data[itemIndex])); } break; case CiftiXML::ALONG_ROW: { std::vector data; data.resize(numCols); CaretAssert(parcelIndex < numRows); m_ciftiFile->getRow(&data[0], parcelIndex); CaretAssertVectorIndex(data, itemIndex); textValueOut += (" " + AString::number(data[itemIndex])); } break; } } } } return true; break; case CiftiMappingType::SCALARS: CaretAssertMessage(0, "Mapping type should never be SCALARS"); break; case CiftiMappingType::SERIES: CaretAssertMessage(0, "Mapping type should never be SERIES"); break; } return false; } /** * Get connectivity value for a surface's node. When the data is mapped * to parcels, the numerical value will not be valid. * * @param mapIndices * Index of the map. * @param structure * Surface's structure. * @param nodeIndex * Index of the node * @param numberOfNodes * Number of nodes in the surface. * @param numericalValuesOut * Numerical values out for all map indices * @param numericalValuesOutValid * Output that indicates the numerical value output is valid. * For label data, this value will be the lable key. * @param textValueOut * Text containing node' value will always be valid if the method * returns true. For parcel data, this will contain the name of the * parcel. For label data, this will contain the name of the label. * For numerical data, this will contain the text representation * of the numerical value. * @return * True if the text value is valid. The numerical values may or may not * also be valid. */ bool CiftiMappableDataFile::getMapSurfaceNodeValues(const std::vector& mapIndices, const StructureEnum::Enum structure, const int nodeIndex, const int32_t numberOfNodes, std::vector& numericalValuesOut, std::vector& numericalValuesOutValid, AString& textValueOut) const { numericalValuesOut.clear(); numericalValuesOutValid.clear(); textValueOut.clear(); CaretAssert(m_ciftiFile); const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); CaretAssert((m_dataMappingDirectionForCiftiXML == CiftiXML::ALONG_ROW) || (m_dataMappingDirectionForCiftiXML == CiftiXML::ALONG_COLUMN)); switch (ciftiXML.getMappingType(m_dataMappingDirectionForCiftiXML)) { case CiftiMappingType::BRAIN_MODELS: { const CiftiBrainModelsMap& map = ciftiXML.getBrainModelsMap(m_dataMappingDirectionForCiftiXML); if (map.getSurfaceNumberOfNodes(structure) == numberOfNodes) { const int64_t dataIndex = map.getIndexForNode(nodeIndex, structure); if (dataIndex >= 0) { for (std::vector::const_iterator mapIter = mapIndices.begin(); mapIter != mapIndices.end(); mapIter++) { const int32_t mapIndex = *mapIter; std::vector mapData; CaretAssertVectorIndex(m_mapContent, mapIndex); getMapData(mapIndex, mapData); if (dataIndex < static_cast(mapData.size())) { const float value = mapData[dataIndex]; numericalValuesOut.push_back(mapData[dataIndex]); numericalValuesOutValid.push_back(true); if (ciftiXML.getMappingType(m_dataReadingDirectionForCiftiXML) == CiftiMappingType::LABELS) { const GiftiLabelTable* glt = getMapLabelTable(mapIndex); const int32_t labelKey = static_cast(value); const GiftiLabel* gl = glt->getLabel(labelKey); if (gl != NULL) { textValueOut += (" " + gl->getName()); } else { textValueOut += (" InvalidLabelKey=" + AString::number(labelKey)); } } else { textValueOut += (" " + AString::number(value, 'f')); } } } } } } break; case CiftiMappingType::LABELS: CaretAssertMessage(0, "Mapping type should never be LABELS"); break; case CiftiMappingType::PARCELS: { if (getDataFileType() == DataFileTypeEnum::CONNECTIVITY_PARCEL) { int32_t readingDataParcelIndex = -1; const CiftiParcelsMap dataMap = ciftiXML.getParcelsMap(m_dataReadingDirectionForCiftiXML); if (dataMap.getSurfaceNumberOfNodes(structure) == numberOfNodes) { readingDataParcelIndex = dataMap.getIndexForNode(nodeIndex, structure); } /* * Special case for matrix type files */ const CiftiMappableConnectivityMatrixDataFile* matrixFile = dynamic_cast(this); if (matrixFile != NULL) { const ConnectivityDataLoaded* dataLoaded = matrixFile->getConnectivityDataLoaded(); switch (dataLoaded->getMode()) { case ConnectivityDataLoaded::MODE_NONE: return false; break; case ConnectivityDataLoaded::MODE_COLUMN: case ConnectivityDataLoaded::MODE_ROW: case ConnectivityDataLoaded::MODE_SURFACE_NODE: case ConnectivityDataLoaded::MODE_SURFACE_NODE_AVERAGE: case ConnectivityDataLoaded::MODE_VOXEL_IJK_AVERAGE: case ConnectivityDataLoaded::MODE_VOXEL_XYZ: { int mappingDataParcelIndex(-1); const CiftiParcelsMap& mappingMap = ciftiXML.getParcelsMap(m_dataMappingDirectionForCiftiXML); if (mappingMap.getSurfaceNumberOfNodes(structure) == numberOfNodes) { const std::vector& mappingParcels = mappingMap.getParcels(); mappingDataParcelIndex = mappingMap.getIndexForNode(nodeIndex, structure); if ((mappingDataParcelIndex >= 0) && (mappingDataParcelIndex < static_cast(mappingParcels.size()))) { textValueOut = mappingParcels[mappingDataParcelIndex].m_name; std::vector dataLoaded; matrixFile->getMapData(0, dataLoaded); if ((mappingDataParcelIndex >= 0) && (mappingDataParcelIndex < static_cast(dataLoaded.size()))) { textValueOut += (" " + AString::number(dataLoaded[mappingDataParcelIndex])); return true; } } } } break; } } int64_t mappingDataParcelIndex = -1; if (readingDataParcelIndex >= 0) { /* * Only get parcel name if there is a row for reading */ const CiftiParcelsMap& mappingMap = ciftiXML.getParcelsMap(m_dataMappingDirectionForCiftiXML); if (mappingMap.getSurfaceNumberOfNodes(structure) == numberOfNodes) { const std::vector& mappingParcels = mappingMap.getParcels(); mappingDataParcelIndex = mappingMap.getIndexForNode(nodeIndex, structure); if ((mappingDataParcelIndex >= 0) && (mappingDataParcelIndex < static_cast(mappingParcels.size()))) { textValueOut = mappingParcels[mappingDataParcelIndex].m_name; } } } for (std::vector::const_iterator mapIter = mapIndices.begin(); mapIter != mapIndices.end(); mapIter++) { if ((mappingDataParcelIndex >= 0) && (readingDataParcelIndex >= 0)) { const int64_t numRows = m_ciftiFile->getNumberOfRows(); const int64_t numCols = m_ciftiFile->getNumberOfColumns(); switch (m_dataReadingDirectionForCiftiXML) { case CiftiXML::ALONG_COLUMN: { std::vector data; data.resize(numCols); CaretAssert(readingDataParcelIndex < numRows); m_ciftiFile->getRow(&data[0], readingDataParcelIndex); CaretAssertVectorIndex(data, mappingDataParcelIndex); textValueOut += (" " + AString::number(data[mappingDataParcelIndex])); } break; case CiftiXML::ALONG_ROW: { std::vector data; data.resize(numRows); CaretAssert(readingDataParcelIndex < numCols); m_ciftiFile->getColumn(&data[0], readingDataParcelIndex); CaretAssertVectorIndex(data, mappingDataParcelIndex); textValueOut += (" " + AString::number(data[mappingDataParcelIndex])); } break; } } } } else { /* * This logic is for parcels NOT in a PCONN file */ int64_t parcelIndex = -1; const CiftiParcelsMap& map = ciftiXML.getParcelsMap(m_dataMappingDirectionForCiftiXML); if (map.getSurfaceNumberOfNodes(structure) == numberOfNodes) { const std::vector& parcels = map.getParcels(); parcelIndex = map.getIndexForNode(nodeIndex, structure); if ((parcelIndex >= 0) && (parcelIndex < static_cast(parcels.size()))) { textValueOut = parcels[parcelIndex].m_name; } } for (std::vector::const_iterator mapIter = mapIndices.begin(); mapIter != mapIndices.end(); mapIter++) { const int32_t mapIndex = *mapIter; if (parcelIndex >= 0) { int64_t itemIndex = -1; switch (ciftiXML.getMappingType(m_dataReadingDirectionForCiftiXML)) { case CiftiMappingType::BRAIN_MODELS: { const CiftiBrainModelsMap& map = ciftiXML.getBrainModelsMap(m_dataReadingDirectionForCiftiXML); if (map.getSurfaceNumberOfNodes(structure) == numberOfNodes) { itemIndex = map.getIndexForNode(nodeIndex, structure); } } break; case CiftiMappingType::LABELS: break; case CiftiMappingType::PARCELS: itemIndex = mapIndex; break; case CiftiMappingType::SCALARS: itemIndex = mapIndex; break; case CiftiMappingType::SERIES: itemIndex = mapIndex; break; } if (itemIndex >= 0) { const int64_t numRows = m_ciftiFile->getNumberOfRows(); const int64_t numCols = m_ciftiFile->getNumberOfColumns(); switch (m_dataReadingDirectionForCiftiXML) { case CiftiXML::ALONG_COLUMN: { std::vector data; data.resize(numRows); CaretAssert(parcelIndex < numCols); m_ciftiFile->getColumn(&data[0], parcelIndex); CaretAssertVectorIndex(data, itemIndex); textValueOut += (" " + AString::number(data[itemIndex])); } break; case CiftiXML::ALONG_ROW: { std::vector data; data.resize(numCols); CaretAssert(parcelIndex < numRows); m_ciftiFile->getRow(&data[0], parcelIndex); CaretAssertVectorIndex(data, itemIndex); textValueOut += (" " + AString::number(data[itemIndex])); } break; } } } } } } break; case CiftiMappingType::SCALARS: CaretAssertMessage(0, "Mapping type should never be SCALARS"); break; case CiftiMappingType::SERIES: CaretAssertMessage(0, "Mapping type should never be SERIES"); break; } if (textValueOut.isEmpty()) { return false; } /* * Output text is valid */ return true; } /** * Get Parcel Label File value for a surface's node. When the data is mapped * to parcels, the numerical value will not be valid. * * @param mapIndex * Index of the map. * @param structure * Surface's structure. * @param nodeIndex * Index of the node * @param numberOfNodes * Number of nodes in the surface. * @param numericalValueOut * Numerical value out. * @param numericalValueOutValid * Output that indicates the numerical value output is valid. * For label data, this value will be the lable key. * @param textValueOut * Text containing node' value will always be valid if the method * returns true. For parcel data, this will contain the name of the * parcel. For label data, this will contain the name of the label. * For numerical data, this will contain the text representation * of the numerical value. * @return * True if the text value is valid. The numerical value may or may not * also be valid. */ bool CiftiMappableDataFile::getParcelLabelMapSurfaceNodeValue(const int32_t mapIndex, const StructureEnum::Enum structure, const int nodeIndex, const int32_t numberOfNodes, float& numericalValueOut, bool& numericalValueOutValid, AString& textValueOut) const { numericalValueOut = 0.0; numericalValueOutValid = false; textValueOut = ""; CaretAssertVectorIndex(m_mapContent, mapIndex); CaretAssert(m_ciftiFile); const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); AString areaName = ""; CaretAssert((m_dataMappingDirectionForCiftiXML == CiftiXML::ALONG_ROW) || (m_dataMappingDirectionForCiftiXML == CiftiXML::ALONG_COLUMN)); const CiftiParcelsMap& map = ciftiXML.getParcelsMap(m_dataMappingDirectionForCiftiXML); if (map.getSurfaceNumberOfNodes(structure) == numberOfNodes) { const std::vector& parcels = map.getParcels(); const int64_t parcelIndex = map.getIndexForNode(nodeIndex, structure); if ((parcelIndex >= 0) && (parcelIndex < static_cast(parcels.size()))) { areaName = parcels[parcelIndex].m_name; const AString networkName = getMapName(mapIndex); textValueOut = ("Area: " + areaName + ", Network: " + networkName); return true; } } return false; } /** * Get the identification information for a surface node in the given maps. * * @param mapIndices * Indices of maps for which identification information is requested. * @param structure * Structure of the surface. * @param nodeIndex * Index of the node. * @param numberOfNodes * Number of nodes in the surface. * @param textOut * Output containing identification information. */ bool CiftiMappableDataFile::getSurfaceNodeIdentificationForMaps(const std::vector& mapIndices, const StructureEnum::Enum structure, const int nodeIndex, const int32_t numberOfNodes, AString& textOut) const { CaretAssert(m_ciftiFile); if (mapIndices.empty()) { return false; } bool useMapData = false; bool useParcelLabelMapData = false; bool useSeriesData = false; switch (getDataFileType()) { case DataFileTypeEnum::ANNOTATION: CaretAssert(0); break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: CaretAssert(0); break; case DataFileTypeEnum::BORDER: CaretAssert(0); break; case DataFileTypeEnum::CONNECTIVITY_DENSE: useMapData = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: useMapData = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: useSeriesData = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: useMapData = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: useSeriesData = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: useSeriesData = true; break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: CaretAssert(0); break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: CaretAssert(0); break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: useMapData = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: useMapData = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: useParcelLabelMapData = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: useMapData = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: useMapData = true; break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: CaretAssert(0); break; case DataFileTypeEnum::IMAGE: CaretAssert(0); break; case DataFileTypeEnum::LABEL: CaretAssert(0); break; case DataFileTypeEnum::METRIC: CaretAssert(0); break; case DataFileTypeEnum::METRIC_DYNAMIC: CaretAssert(0); break; case DataFileTypeEnum::PALETTE: CaretAssert(0); break; case DataFileTypeEnum::RGBA: CaretAssert(0); break; case DataFileTypeEnum::SCENE: CaretAssert(0); break; case DataFileTypeEnum::SPECIFICATION: CaretAssert(0); break; case DataFileTypeEnum::SURFACE: CaretAssert(0); break; case DataFileTypeEnum::UNKNOWN: CaretAssert(0); break; case DataFileTypeEnum::VOLUME: CaretAssert(0); break; case DataFileTypeEnum::VOLUME_DYNAMIC: CaretAssert(0); break; } const int32_t numberOfMapIndices = static_cast(mapIndices.size()); textOut = ""; bool validID = false; if (useMapData) { std::vector numericalValues; std::vector numericalValuesValid; AString textValue; if (getMapSurfaceNodeValues(mapIndices, structure, nodeIndex, numberOfNodes, numericalValues, numericalValuesValid, textValue)) { textOut += textValue; textOut += " "; validID = true; } } else if (useSeriesData) { /* * Use series data which contains values for node from all maps. */ std::vector seriesData; if (getSeriesDataForSurfaceNode(structure, nodeIndex, seriesData)) { for (int32_t i = 0; i < numberOfMapIndices; i++) { const int32_t mapIndex = mapIndices[i]; CaretAssertVectorIndex(seriesData, mapIndex); const float value = seriesData[mapIndex]; if (isMappedWithLabelTable()) { const GiftiLabelTable* glt = getMapLabelTable(mapIndex); const int32_t labelKey = static_cast(value); const GiftiLabel* gl = glt->getLabel(labelKey); if (gl != NULL) { textOut += gl->getName(); } else { textOut += ("InvalidLabelKey=" + AString::number(value)); } validID = true; } else if (isMappedWithPalette()) { textOut += AString::number(value); validID = true; } else { CaretAssert(0); } textOut += " "; } } } else if (useParcelLabelMapData) { for (int32_t i = 0; i < numberOfMapIndices; i++) { const int32_t mapIndex = mapIndices[i]; float numericalValue; AString textValue; bool numericalValueValid; if (getParcelLabelMapSurfaceNodeValue(mapIndex, structure, nodeIndex, numberOfNodes, numericalValue, numericalValueValid, textValue)) { textOut += textValue; textOut += " "; validID = true; } } } return validID; } /** * Get the series data (one data value from each map) for a surface node. * * @param structure * Surface's structure. * @param nodeIndex * Index of the node. * @param seriesDataOut * Series data for given node. * @return * True if output data is valid, else false. */ bool CiftiMappableDataFile::getSeriesDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t nodeIndex, std::vector& seriesDataOut) const { CaretAssert(m_ciftiFile); bool valid = false; switch (m_dataMappingAccessMethod) { case DATA_ACCESS_METHOD_INVALID: CaretAssert(0); break; case DATA_ACCESS_NONE: break; case DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW: seriesDataOut.resize(m_ciftiFile->getNumberOfRows()); valid = m_ciftiFile->getColumnFromNode(&seriesDataOut[0], nodeIndex, structure); break; case DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN: seriesDataOut.resize(m_ciftiFile->getNumberOfColumns()); valid = m_ciftiFile->getRowFromNode(&seriesDataOut[0], nodeIndex, structure); break; } return valid; } /** * Get the series data (oone data value for each map) for a voxel at the * given coordinate. * * @param xyz * Coordinate of the voxel. * @param seriesDataOut * Series data for the given voxel. * @return * True if output data is valid, else false. */ bool CiftiMappableDataFile::getSeriesDataForVoxelAtCoordinate(const float xyz[3], std::vector& seriesDataOut) const { CaretAssert(m_ciftiFile); bool valid = false; switch (m_dataMappingAccessMethod) { case DATA_ACCESS_METHOD_INVALID: CaretAssert(0); break; case DATA_ACCESS_NONE: break; case DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW: seriesDataOut.resize(m_ciftiFile->getNumberOfRows()); valid = m_ciftiFile->getColumnFromVoxelCoordinate(&seriesDataOut[0], xyz); break; case DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN: seriesDataOut.resize(m_ciftiFile->getNumberOfColumns()); valid = m_ciftiFile->getRowFromVoxelCoordinate(&seriesDataOut[0], xyz); break; } return valid; } /** * Get the node coloring for the surface. * @param mapIndex * Index of the map. * @param structure * Surface structure nodes are colored. * @param surfaceRGBAOut * Filled with RGBA coloring for the surface's nodes. * Contains numberOfNodes * 4 elements. * @param dataValuesOut * Data values for the nodes (elements are valid when the alpha value in * the RGBA colors is valid (greater than zero). * @param surfaceNumberOfNodes * Number of nodes in the surface. * @return * True if coloring is valid, else false. */ bool CiftiMappableDataFile::getMapSurfaceNodeColoring(const int32_t mapIndex, const StructureEnum::Enum structure, float* surfaceRGBAOut, float* dataValuesOut, const int32_t surfaceNumberOfNodes) { CaretAssert(m_ciftiFile); CaretAssertVectorIndex(m_mapContent, mapIndex); const int32_t numCiftiNodes = getMappingSurfaceNumberOfNodes(structure); if (numCiftiNodes != surfaceNumberOfNodes) { return false; } std::vector mapData; getMapData(mapIndex, mapData); /* * Map data may be empty for connectivity matrix files with no rows loaded. */ if (mapData.empty()) { return false; } std::vector surfaceMap; switch (m_dataMappingAccessMethod) { case DATA_ACCESS_METHOD_INVALID: CaretAssert(0); break; case DATA_ACCESS_NONE: break; case DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW: m_ciftiFile->getSurfaceMapForRows(surfaceMap, structure); break; case DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN: m_ciftiFile->getSurfaceMapForColumns(surfaceMap, structure); break; } const MapContent* mc = m_mapContent[mapIndex]; /* * May need to update map coloring */ if ( ! mc->m_rgbaValid) { updateScalarColoringForMap(mapIndex); } std::vector dataIndicesForNodes; bool validColorsFlag = false; if (getSurfaceDataIndicesForMappingToBrainordinates(structure, surfaceNumberOfNodes, dataIndicesForNodes)) { for (int64_t iNode = 0; iNode < surfaceNumberOfNodes; iNode++) { CaretAssertVectorIndex(dataIndicesForNodes, iNode); const int64_t dataIndex = dataIndicesForNodes[iNode]; const int64_t node4 = iNode * 4; CaretAssertArrayIndex(surfaceRGBA, (surfaceNumberOfNodes * 4), node4); if (dataIndex >= 0) { CaretAssert(dataIndex < mc->m_dataCount); const int64_t data4 = dataIndex * 4; CaretAssertArrayIndex(this->dataRGBA, (mc->m_dataCount * 4), data4); surfaceRGBAOut[node4] = mc->m_rgba[data4] / 255.0; surfaceRGBAOut[node4+1] = mc->m_rgba[data4+1] / 255.0; surfaceRGBAOut[node4+2] = mc->m_rgba[data4+2] / 255.0; surfaceRGBAOut[node4+3] = mc->m_rgba[data4+3] / 255.0; dataValuesOut[iNode] = mapData[dataIndex]; validColorsFlag = true; } else { surfaceRGBAOut[node4] = 0.0; surfaceRGBAOut[node4+1] = 0.0; surfaceRGBAOut[node4+2] = 0.0; surfaceRGBAOut[node4+3] = -1.0; dataValuesOut[iNode] = 0.0; } } } return validColorsFlag; } /** * Get the data indices corresponding to all nodes in the given surface. * * @param structure * Surface's structure. * @param surfaceNumberOfNodes * Number of nodes in the surface. * @param dataIndicesForNodes * Will containg "surfaceNumberOfNodes" element where the values are * indices into the CIFTI data. * @return True if valid, else false. */ bool CiftiMappableDataFile::getSurfaceDataIndicesForMappingToBrainordinates(const StructureEnum::Enum structure, const int64_t surfaceNumberOfNodes, std::vector& dataIndicesForNodes) const { CaretAssert(m_ciftiFile); const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); CaretAssert((m_dataMappingDirectionForCiftiXML == CiftiXML::ALONG_ROW) || (m_dataMappingDirectionForCiftiXML == CiftiXML::ALONG_COLUMN)); switch (ciftiXML.getMappingType(m_dataMappingDirectionForCiftiXML)) { case CiftiMappingType::BRAIN_MODELS: { const CiftiBrainModelsMap& map = ciftiXML.getBrainModelsMap(m_dataMappingDirectionForCiftiXML); if (map.getSurfaceNumberOfNodes(structure) == surfaceNumberOfNodes) { const std::vector surfaceMap = map.getSurfaceMap(structure); dataIndicesForNodes.resize(surfaceNumberOfNodes); std::fill(dataIndicesForNodes.begin(), dataIndicesForNodes.end(), -1); for (std::vector::const_iterator iter = surfaceMap.begin(); iter != surfaceMap.end(); iter++) { const CiftiBrainModelsMap::SurfaceMap& nodeMap = *iter; CaretAssertVectorIndex(dataIndicesForNodes, nodeMap.m_surfaceNode); dataIndicesForNodes[nodeMap.m_surfaceNode] = nodeMap.m_ciftiIndex; } return true; } } break; case CiftiMappingType::LABELS: CaretAssertMessage(0, "Mapping type should never be LABELS"); break; case CiftiMappingType::PARCELS: { const CiftiParcelsMap& map = ciftiXML.getParcelsMap(m_dataMappingDirectionForCiftiXML); if (map.getSurfaceNumberOfNodes(structure) == surfaceNumberOfNodes) { dataIndicesForNodes.resize(surfaceNumberOfNodes); for (int64_t i = 0; i < surfaceNumberOfNodes; i++) { dataIndicesForNodes[i] = map.getIndexForNode(i, structure); } return true; } } break; case CiftiMappingType::SCALARS: CaretAssertMessage(0, "Mapping type should never be SCALARS"); break; case CiftiMappingType::SERIES: CaretAssertMessage(0, "Mapping type should never be SERIES"); break; } return false; } /** * Get connectivity value for a voxel. When the data is mapped * to parcels, the numerical value will not be valid. * * @param mapIndex * Index of the map. * @param xyz * Coordinate of voxel. * @param ijkOut * Voxel indices of value. * @param numericalValueOut * Numerical value out. * @param numericalValueOutValid * Output that indicates the numerical value output is valid. * For label data, this value will be the label key. * @param textValueOut * Text containing node' value will always be valid if the method * returns true. For parcel data, this will contain the name of the * parcel. For label data, this will contain the name of the label. * For numerical data, this will contain the text representation * of the numerical value. * @return * True if the text value is valid. The numerical value may or may not * also be valid. */ bool CiftiMappableDataFile::getMapVolumeVoxelValue(const int32_t mapIndex, const float xyz[3], int64_t ijkOut[3], float& numericalValueOut, bool& numericalValueOutValid, AString& textValueOut) const { textValueOut = ""; numericalValueOutValid = false; CaretAssert(m_ciftiFile); /* * Get content for map. */ CaretAssertVectorIndex(m_mapContent, mapIndex); int64_t ijk[3]; enclosingVoxel(xyz[0], xyz[1], xyz[2], ijk[0], ijk[1], ijk[2]); if (indexValid(ijk[0], ijk[1], ijk[2])) { /* * Only set the IJK if the index is valid. */ ijkOut[0] = ijk[0]; ijkOut[1] = ijk[1]; ijkOut[2] = ijk[2]; const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(ijk[0], ijk[1], ijk[2]); if (dataOffset >= 0) { CaretAssert((m_dataMappingDirectionForCiftiXML == CiftiXML::ALONG_ROW) || (m_dataMappingDirectionForCiftiXML == CiftiXML::ALONG_COLUMN)); const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); const CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(this); if (parcelLabelFile != NULL) { const CiftiParcelsMap& map = ciftiXML.getParcelsMap(m_dataMappingDirectionForCiftiXML); const int64_t parcelMapIndex = map.getIndexForVoxel(ijk); const std::vector& parcels = map.getParcels(); AString areaName = ""; if ((parcelMapIndex >= 0) && (parcelMapIndex < static_cast(parcels.size()))) { CaretAssertVectorIndex(parcels, parcelMapIndex); areaName = parcels[parcelMapIndex].m_name; } const AString networkName = getMapName(mapIndex); textValueOut = ("Area: " + areaName + ", Network: " + networkName); return true; } else { switch (ciftiXML.getMappingType(m_dataMappingDirectionForCiftiXML)) { case CiftiMappingType::BRAIN_MODELS: { /* * Note: For a Dense connectivity file, it may not have * data loaded since data is loaded upon demand. */ std::vector mapData; getMapData(mapIndex, mapData); if ( ! mapData.empty()) { CaretAssertVectorIndex(mapData, dataOffset); numericalValueOut = mapData[dataOffset]; if (isMappedWithLabelTable()) { textValueOut = "Invalid Label Index"; const GiftiLabelTable* glt = getMapLabelTable(mapIndex); const int32_t labelKey = static_cast(numericalValueOut); const GiftiLabel* gl = glt->getLabel(labelKey); if (gl != NULL) { textValueOut = gl->getName(); } else { textValueOut += ("InvalidLabelKey=" + AString::number(labelKey)); } numericalValueOutValid = true; } else if (isMappedWithPalette()) { numericalValueOutValid = true; textValueOut = AString::number(numericalValueOut); } else { CaretAssert(0); } return true; } } break; case CiftiMappingType::LABELS: CaretAssertMessage(0, "Mapping type should never be LABELS"); break; case CiftiMappingType::PARCELS: { const CiftiParcelsMap& map = ciftiXML.getParcelsMap(m_dataMappingDirectionForCiftiXML); const int64_t parcelMapIndex = map.getIndexForVoxel(ijk); const std::vector& parcels = map.getParcels(); if ((parcelMapIndex >= 0) && (parcelMapIndex < static_cast(parcels.size()))) { CaretAssertVectorIndex(parcels, parcelMapIndex); textValueOut = parcels[parcelMapIndex].m_name; } if (parcelMapIndex >= 0) { int64_t itemIndex = -1; switch (ciftiXML.getMappingType(m_dataReadingDirectionForCiftiXML)) { case CiftiMappingType::BRAIN_MODELS: { const CiftiBrainModelsMap& map = ciftiXML.getBrainModelsMap(m_dataReadingDirectionForCiftiXML); itemIndex = map.getIndexForVoxel(ijk); } break; case CiftiMappingType::LABELS: break; case CiftiMappingType::PARCELS: break; case CiftiMappingType::SCALARS: itemIndex = mapIndex; break; case CiftiMappingType::SERIES: itemIndex = mapIndex; break; } if (itemIndex >= 0) { const int64_t numRows = m_ciftiFile->getNumberOfRows(); const int64_t numCols = m_ciftiFile->getNumberOfColumns(); switch (m_dataReadingDirectionForCiftiXML) { case CiftiXML::ALONG_COLUMN: { std::vector data; data.resize(numRows); CaretAssert(parcelMapIndex < numCols); m_ciftiFile->getColumn(&data[0], parcelMapIndex); CaretAssertVectorIndex(data, itemIndex); textValueOut += (" " + AString::number(data[itemIndex])); } break; case CiftiXML::ALONG_ROW: { std::vector data; data.resize(numCols); CaretAssert(parcelMapIndex < numRows); m_ciftiFile->getRow(&data[0], parcelMapIndex); CaretAssertVectorIndex(data, itemIndex); textValueOut += (" " + AString::number(data[itemIndex])); } break; } } } } return true; break; case CiftiMappingType::SCALARS: CaretAssertMessage(0, "Mapping type should never be SCALARS"); break; case CiftiMappingType::SERIES: CaretAssertMessage(0, "Mapping type should never be SERIES"); break; } } } } return false; } /** * Get connectivity value for a voxel. When the data is mapped * to parcels, the numerical value will not be valid. * * @param mapIndices * Indices of the maps. * @param xyz * Coordinate of voxel. * @param ijkOut * Voxel indices of value. * @param numericalValuesOut * Numerical values out. * @param numericalValuesOutValid * Output that indicates the numerical values output is valid. * For label data, this value will be the label key. * @param textValueOut * Text containing node' value will always be valid if the method * returns true. For parcel data, this will contain the name of the * parcel. For label data, this will contain the name of the label. * For numerical data, this will contain the text representation * of the numerical value. * @return * True if the text value is valid. The numerical value may or may not * also be valid. */ bool CiftiMappableDataFile::getMapVolumeVoxelValues(const std::vector mapIndices, const float xyz[3], int64_t ijkOut[3], std::vector& numericalValuesOut, std::vector& numericalValuesOutValid, AString& textValueOut) const { textValueOut = ""; numericalValuesOut.clear(); numericalValuesOutValid.clear(); if (mapIndices.empty()) { return false; } CaretAssert(m_ciftiFile); int64_t ijk[3]; enclosingVoxel(xyz[0], xyz[1], xyz[2], ijk[0], ijk[1], ijk[2]); if (indexValid(ijk[0], ijk[1], ijk[2])) { /* * Only set the IJK if the index is valid. */ ijkOut[0] = ijk[0]; ijkOut[1] = ijk[1]; ijkOut[2] = ijk[2]; const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(ijk[0], ijk[1], ijk[2]); if (dataOffset >= 0) { CaretAssert((m_dataMappingDirectionForCiftiXML == CiftiXML::ALONG_ROW) || (m_dataMappingDirectionForCiftiXML == CiftiXML::ALONG_COLUMN)); const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); const CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(this); if (parcelLabelFile != NULL) { const CiftiParcelsMap& map = ciftiXML.getParcelsMap(m_dataMappingDirectionForCiftiXML); const int64_t parcelMapIndex = map.getIndexForVoxel(ijk); const std::vector& parcels = map.getParcels(); AString areaName = ""; if ((parcelMapIndex >= 0) && (parcelMapIndex < static_cast(parcels.size()))) { CaretAssertVectorIndex(parcels, parcelMapIndex); areaName = parcels[parcelMapIndex].m_name; } textValueOut = ("Area: " + areaName + ", Network(s): "); for (std::vector::const_iterator mapIter = mapIndices.begin(); mapIter != mapIndices.end(); mapIter++) { textValueOut += (getMapName(*mapIter) + " "); } return true; } else { switch (ciftiXML.getMappingType(m_dataMappingDirectionForCiftiXML)) { case CiftiMappingType::BRAIN_MODELS: { for (std::vector::const_iterator mapIter = mapIndices.begin(); mapIter != mapIndices.end(); mapIter++) { const int32_t mapIndex = *mapIter; /* * Note: For a Dense connectivity file, it may not have * data loaded since data is loaded upon demand. */ std::vector mapData; getMapData(mapIndex, mapData); if ( ! mapData.empty()) { CaretAssertVectorIndex(mapData, dataOffset); const float value = mapData[dataOffset]; if (isMappedWithLabelTable()) { textValueOut = "Invalid Label Index"; const GiftiLabelTable* glt = getMapLabelTable(mapIndex); const int32_t labelKey = static_cast(value); const GiftiLabel* gl = glt->getLabel(labelKey); if (gl != NULL) { textValueOut = (gl->getName()); } else { textValueOut += ("InvalidLabelKey=" + AString::number(labelKey) + " "); } numericalValuesOut.push_back(value); numericalValuesOutValid.push_back(false); // NOT VALID ! } else if (isMappedWithPalette()) { numericalValuesOut.push_back(value); numericalValuesOutValid.push_back(true); textValueOut = (AString::number(value) + " "); } else { CaretAssert(0); } return true; } } } break; case CiftiMappingType::LABELS: CaretAssertMessage(0, "Mapping type should never be LABELS"); break; case CiftiMappingType::PARCELS: { const CiftiParcelsMap& map = ciftiXML.getParcelsMap(m_dataMappingDirectionForCiftiXML); const int64_t parcelMapIndex = map.getIndexForVoxel(ijk); const std::vector& parcels = map.getParcels(); if ((parcelMapIndex >= 0) && (parcelMapIndex < static_cast(parcels.size()))) { CaretAssertVectorIndex(parcels, parcelMapIndex); textValueOut = parcels[parcelMapIndex].m_name; } for (std::vector::const_iterator mapIter = mapIndices.begin(); mapIter != mapIndices.end(); mapIter++) { const int32_t mapIndex = *mapIter; if (parcelMapIndex >= 0) { int64_t itemIndex = -1; switch (ciftiXML.getMappingType(m_dataReadingDirectionForCiftiXML)) { case CiftiMappingType::BRAIN_MODELS: { const CiftiBrainModelsMap& map = ciftiXML.getBrainModelsMap(m_dataReadingDirectionForCiftiXML); itemIndex = map.getIndexForVoxel(ijk); } break; case CiftiMappingType::LABELS: break; case CiftiMappingType::PARCELS: break; case CiftiMappingType::SCALARS: itemIndex = mapIndex; break; case CiftiMappingType::SERIES: itemIndex = mapIndex; break; } if (itemIndex >= 0) { const int64_t numRows = m_ciftiFile->getNumberOfRows(); const int64_t numCols = m_ciftiFile->getNumberOfColumns(); switch (m_dataReadingDirectionForCiftiXML) { case CiftiXML::ALONG_COLUMN: { std::vector data; data.resize(numRows); CaretAssert(parcelMapIndex < numCols); m_ciftiFile->getColumn(&data[0], parcelMapIndex); CaretAssertVectorIndex(data, itemIndex); textValueOut += (" " + AString::number(data[itemIndex])); } break; case CiftiXML::ALONG_ROW: { std::vector data; data.resize(numCols); CaretAssert(parcelMapIndex < numRows); m_ciftiFile->getRow(&data[0], parcelMapIndex); CaretAssertVectorIndex(data, itemIndex); textValueOut += (" " + AString::number(data[itemIndex])); } break; } } } } } return true; break; case CiftiMappingType::SCALARS: CaretAssertMessage(0, "Mapping type should never be SCALARS"); break; case CiftiMappingType::SERIES: CaretAssertMessage(0, "Mapping type should never be SERIES"); break; } } } } return false; } /** * Get the value of the voxel containing the given coordinate. * * @param coordinateIn * The 3D coordinate * @param validOut * If not NULL, will indicate if the coordinate (and hence the * returned value) is valid. * @param mapIndex * Index of map. * @param component * Voxel component. * @return * Value of voxel containing the given coordinate. */ float CiftiMappableDataFile::getVoxelValue(const float* coordinateIn, bool* validOut, const int64_t mapIndex, const int64_t component) const { return getVoxelValue(coordinateIn[0], coordinateIn[1], coordinateIn[2], validOut, mapIndex, component); } /** * Get the value of the voxel containing the given coordinate. * * @param coordinateX * The X coordinate * @param coordinateY * The Y coordinate * @param coordinateZ * The Z coordinate * @param validOut * If not NULL, will indicate if the coordinate (and hence the * returned value) is valid. * @param mapIndex * Index of map. * @param component * Voxel component. * @return * Value of voxel containing the given coordinate. */ float CiftiMappableDataFile::getVoxelValue(const float coordinateX, const float coordinateY, const float coordinateZ, bool* validOut, const int64_t mapIndex, const int64_t component) const { if (validOut != NULL) { *validOut = false; } CaretAssert(m_ciftiFile); /* * Get content for map. */ CaretAssertVectorIndex(m_mapContent, mapIndex); int64_t voxelI, voxelJ, voxelK; enclosingVoxel(coordinateX, coordinateY, coordinateZ, voxelI, voxelJ, voxelK); if (indexValid(voxelI, voxelJ, voxelK, mapIndex, component)) { const int64_t dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(voxelI, voxelJ, voxelK); if (dataOffset >= 0) { std::vector mapData; getMapData(mapIndex, mapData); CaretAssertVectorIndex(mapData, dataOffset); const float value = mapData[dataOffset]; if (validOut != NULL) { *validOut = true; } return value; } } return 0.0; } /** * @param coordinate * Coordinate for which enclosing voxel is located. * @param mapIndex * Index of the map. * @return * Offset in map data for enclosing voxel or NULL if not within a voxel. */ int64_t CiftiMappableDataFile::getMapDataOffsetForVoxelAtCoordinate(const float coordinate[3], const int32_t mapIndex) const { int64_t dataOffset = -1; CaretAssert(m_ciftiFile); /* * Get content for map. */ CaretAssertVectorIndex(m_mapContent, mapIndex); int64_t voxelI, voxelJ, voxelK; enclosingVoxel(coordinate[0], coordinate[1], coordinate[2], voxelI, voxelJ, voxelK); if (indexValid(voxelI, voxelJ, voxelK, mapIndex, 0)) { dataOffset = m_voxelIndicesToOffsetForDataMapping->getOffsetForIndices(voxelI, voxelJ, voxelK); } return dataOffset; } /** * Get the identification information for a surface node in the given maps. * * @param mapIndices * Indices of maps for which identification information is requested. * @param xyz * Coordinate of voxel. * @param ijkOut * Voxel indices of value. * @param textOut * Output containing identification information. */ bool CiftiMappableDataFile::getVolumeVoxelIdentificationForMaps(const std::vector& mapIndices, const float xyz[3], int64_t ijkOut[3], AString& textOut) const { CaretAssert(m_ciftiFile); const int32_t numberOfMapIndices = static_cast(mapIndices.size()); if (numberOfMapIndices <= 0) { return false; } textOut = ""; std::vector numericalValues; std::vector numericalValuesValid; AString textValue; if (getMapVolumeVoxelValues(mapIndices, xyz, ijkOut, numericalValues, numericalValuesValid, textValue)) { textOut = textValue; } if (textOut.isEmpty() == false) { return true; } return false; } /** * Set the status to unmodified. */ void CiftiMappableDataFile::clearModified() { CaretMappableDataFile::clearModified(); CaretAssert(m_ciftiFile); const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); ciftiXML.getFileMetaData()->clearModified(); const int32_t numMaps = getNumberOfMaps(); for (int32_t i = 0; i < numMaps; i++) { m_mapContent[i]->clearModified(); } } /** * @return True if the file is modified in any way EXCEPT for * the palette color mapping. Also see isModified(). */ bool CiftiMappableDataFile::isModifiedExcludingPaletteColorMapping() const { if (CaretMappableDataFile::isModifiedExcludingPaletteColorMapping()) { return true; } CaretAssert(m_ciftiFile); const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); if (ciftiXML.getFileMetaData()->isModified()) { return true; } const int32_t numMaps = getNumberOfMaps(); for (int32_t i = 0; i < numMaps; i++) { if (m_mapContent[i]->isModified()) { return true; } } return false; } /** * @return The units for the 'interval' between two consecutive maps. */ NiftiTimeUnitsEnum::Enum CiftiMappableDataFile::getMapIntervalUnits() const { return m_mappingTimeUnits; } /** * Get the units value for the first map and the * quantity of units between consecutive maps. If the * units for the maps is unknown, value of one (1) are * returned for both output values. * * @param firstMapUnitsValueOut * Output containing units value for first map. * @param mapIntervalStepValueOut * Output containing number of units between consecutive maps. */ void CiftiMappableDataFile::getMapIntervalStartAndStep(float& firstMapUnitsValueOut, float& mapIntervalStepValueOut) const { firstMapUnitsValueOut = m_mappingTimeStart; mapIntervalStepValueOut = m_mappingTimeStep; } /** * Get the minimum and maximum values from ALL maps in this file. * Note that not all files (due to size of file) are able to provide * the minimum and maximum values from the file. The return value * indicates success/failure. If the failure (false) is returned * the returned values are likely +/- the maximum float values. * * @param dataRangeMinimumOut * Minimum data value found. * @param dataRangeMaximumOut * Maximum data value found. * @return * True if the values are valid, else false. */ bool CiftiMappableDataFile::getDataRangeFromAllMaps(float& dataRangeMinimumOut, float& dataRangeMaximumOut) const { CaretAssert(m_ciftiFile); /* * Dense is very large but at this time is [-1, 1] */ if (getDataFileType() == DataFileTypeEnum::CONNECTIVITY_DENSE) { dataRangeMaximumOut = 1.0; dataRangeMinimumOut = -1; return true; } else { if (m_ciftiFile->getDataRangeFromAllMaps(dataRangeMinimumOut, dataRangeMaximumOut)) { return true; } } /* * Default */ dataRangeMaximumOut = std::numeric_limits::max(); dataRangeMinimumOut = -dataRangeMaximumOut; return false; } /** * Get the number of nodes for the structure for mapping data. * * @param structure * Structure for which number of nodes is requested. * @return * Number of nodes corresponding to structure. If no matching structure * is found, a negative value is returned. */ int32_t CiftiMappableDataFile::getMappingSurfaceNumberOfNodes(const StructureEnum::Enum structure) const { int32_t numCiftiNodes = -1; if (m_dataMappingAccessMethod == DATA_ACCESS_NONE) { return numCiftiNodes; } CaretAssert((m_dataMappingDirectionForCiftiXML == CiftiXML::ALONG_ROW) || (m_dataMappingDirectionForCiftiXML == CiftiXML::ALONG_COLUMN)); const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); switch (ciftiXML.getMappingType(m_dataMappingDirectionForCiftiXML)) { case CiftiMappingType::BRAIN_MODELS: { const CiftiBrainModelsMap& map = ciftiXML.getBrainModelsMap(m_dataMappingDirectionForCiftiXML); if (map.hasSurfaceData(structure)) { numCiftiNodes = map.getSurfaceNumberOfNodes(structure); } } break; case CiftiMappingType::LABELS: CaretAssertMessage(0, "Mapping type should never be LABELS"); break; case CiftiMappingType::PARCELS: { const CiftiParcelsMap& map = ciftiXML.getParcelsMap(m_dataMappingDirectionForCiftiXML); if (map.hasSurfaceData(structure)) { numCiftiNodes = map.getSurfaceNumberOfNodes(structure); } } break; case CiftiMappingType::SCALARS: CaretAssertMessage(0, "Mapping type should never be SCALARS"); break; case CiftiMappingType::SERIES: CaretAssertMessage(0, "Mapping type should never be SERIES"); break; } return numCiftiNodes; } /** * Save file data from the scene. For subclasses that need to * save to a scene, this method should be overriden. sceneClass * will be valid and any scene data should be added to it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. */ void CiftiMappableDataFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { CaretMappableDataFile::saveFileDataToScene(sceneAttributes, sceneClass); if (isMappedWithLabelTable()) { sceneClass->addClass(m_classNameHierarchy->saveToScene(sceneAttributes, "m_classNameHierarchy")); } } /** * Restore file data from the scene. For subclasses that need to * restore from a scene, this method should be overridden. The scene class * will be valid and any scene data may be obtained from it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void CiftiMappableDataFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { CaretMappableDataFile::restoreFileDataFromScene(sceneAttributes, sceneClass); if (isMappedWithLabelTable()) { m_classNameHierarchy->restoreFromScene(sceneAttributes, sceneClass->getClass("m_classNameHierarchy")); } /* * When a scene is created and there is a modified palette, the user may choose * to save the modified palette to the scene so that the file does not need to * be saved with a changed palette. When scenes are loaded and a file in the * scene is already in memory, the file is NOT reloaded to save time. However, * since the palette may be saved to the scene, the coloring will needd to be * updated. If this is not done, the coloring of the file's data prior to * loading the scene remains and may be incorrect. */ invalidateColoringInAllMaps(); } /** * Add information about the file to the data file information. * * @param dataFileInformation * Consolidates information about a data file. */ void CiftiMappableDataFile::addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) { CaretAssert(m_ciftiFile); CaretMappableDataFile::addToDataFileContentInformation(dataFileInformation); dataFileInformation.addNameAndValue("Number of Rows", m_ciftiFile->getNumberOfRows()); dataFileInformation.addNameAndValue("Number of Columns", m_ciftiFile->getNumberOfColumns()); int64_t dimI, dimJ, dimK, dimTime, dimNumComp; getDimensions(dimI, dimJ, dimK, dimTime, dimNumComp); dataFileInformation.addNameAndValue("Volume Dim[0]", dimI); dataFileInformation.addNameAndValue("Volume Dim[1]", dimJ); dataFileInformation.addNameAndValue("Volume Dim[2]", dimK); AString paletteType; switch (m_paletteColorMappingSource) { case PALETTE_COLOR_MAPPING_SOURCE_INVALID: paletteType = "None"; break; case PALETTE_COLOR_MAPPING_SOURCE_FROM_FILE: paletteType = "File (One for all maps)"; break; case PALETTE_COLOR_MAPPING_SOURCE_FROM_MAP: paletteType = "Map (Unique for each map)"; break; } dataFileInformation.addNameAndValue("Palette Type", paletteType); const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); CiftiMappableDataFile::addCiftiXmlToDataFileContentInformation(dataFileInformation, ciftiXML); } /** * Get a text name for a CIFTI mapping type. * * @param mappingType * The CIFTI mapping type. * @return * String containing text name. */ AString CiftiMappableDataFile::mappingTypeToName(const CiftiMappingType::MappingType mappingType) { AString mapTypeName; switch (mappingType) { case CiftiMappingType::BRAIN_MODELS: mapTypeName = "BRAIN_MODELS"; break; case CiftiMappingType::LABELS: mapTypeName = "LABELS"; break; case CiftiMappingType::PARCELS: mapTypeName = "PARCELS"; break; case CiftiMappingType::SCALARS: mapTypeName = "SCALARS"; break; case CiftiMappingType::SERIES: mapTypeName = "SERIES"; break; } return mapTypeName; } /** * Add information about the file to the data file information. * * @param dataFileInformation * Consolidates information about a data file. * @param ciftiXML * The CIFTI XML. * @param numberOfCiftiDimensions * Number of Dimensions of the CIFTI File. */ void CiftiMappableDataFile::addCiftiXmlToDataFileContentInformation(DataFileContentInformation& dataFileInformation, const CiftiXML& ciftiXML) { std::vector dims = ciftiXML.getDimensions(); const int32_t numDims = static_cast(dims.size()); for (int32_t i = 0; i < numDims; i++) { dataFileInformation.addNameAndValue(("CIFTI Dim[" + AString::number(i) + "]"), dims[i]); } const bool showLabelMappingsFlag = dataFileInformation.isOptionFlag(DataFileContentInformation::OPTION_SHOW_CIFTI_LABEL_MAPPING); for (int32_t alongType = 0; alongType < numDims; alongType++) { AString alongName; CiftiMappingType::MappingType mapType = CiftiMappingType::BRAIN_MODELS; switch (alongType) { case CiftiXML::ALONG_ROW: alongName = "ALONG_ROW"; mapType = ciftiXML.getMappingType(CiftiXML::ALONG_ROW); break; case CiftiXML::ALONG_COLUMN: alongName = "ALONG_COLUMN"; mapType = ciftiXML.getMappingType(CiftiXML::ALONG_COLUMN); break; case CiftiXML::ALONG_STACK: alongName = "ALONG_STACK"; mapType = ciftiXML.getMappingType(CiftiXML::ALONG_STACK); break; } AString mapInfoString; if ( ! alongName.isEmpty()) { AString mapTypeName; switch (mapType) { case CiftiMappingType::BRAIN_MODELS: mapTypeName = "BRAIN_MODELS"; break; case CiftiMappingType::LABELS: mapTypeName = "LABELS"; break; case CiftiMappingType::PARCELS: mapTypeName = "PARCELS"; break; case CiftiMappingType::SCALARS: mapTypeName = "SCALARS"; break; case CiftiMappingType::SERIES: mapTypeName = "SERIES"; break; } dataFileInformation.addNameAndValue((alongName + " map type"), mapTypeName); switch (mapType) { case CiftiMappingType::BRAIN_MODELS: { const CiftiBrainModelsMap& bmm = ciftiXML.getBrainModelsMap(alongType); dataFileInformation.addNameAndValue(" Has Volume Data", bmm.hasVolumeData()); if (bmm.hasVolumeData()) { const VolumeSpace volumeSpace = bmm.getVolumeSpace(); const int64_t* dims = volumeSpace.getDims(); dataFileInformation.addNameAndValue(" Volume Dims", AString::fromNumbers(dims, 3, ",")); const std::vector >& sform = volumeSpace.getSform(); dataFileInformation.addNameAndValue(" Volume Space", AString::fromNumbers(sform[0].data(), 4, ",") + ";" + AString::fromNumbers(sform[1].data(), 4, ",") + ";" + AString::fromNumbers(sform[2].data(), 4, ",")); } std::vector modelInfo = bmm.getModelInfo();//allows us to visit the models in the order they are in the file for (int i = 0; i < (int)modelInfo.size(); ++i) { if (modelInfo[i].m_type == CiftiBrainModelsMap::SURFACE) { dataFileInformation.addNameAndValue((" " + StructureEnum::toGuiName(modelInfo[i].m_structure)), (AString::number(modelInfo[i].m_indexCount) + " out of " + AString::number(bmm.getSurfaceNumberOfNodes(modelInfo[i].m_structure)) + " vertices")); } else { CaretAssert(modelInfo[i].m_type == CiftiBrainModelsMap::VOXELS); dataFileInformation.addNameAndValue((" " + StructureEnum::toGuiName(modelInfo[i].m_structure)), (AString::number(modelInfo[i].m_indexCount) + " voxels")); } } } break; case CiftiMappingType::LABELS: if (showLabelMappingsFlag) { const CiftiLabelsMap& clm = ciftiXML.getLabelsMap(alongType); const int32_t numItems = clm.getLength(); for (int32_t i = 0; i < numItems; i++) { dataFileInformation.addText(" Index=" + AString::number(i) + " Name=" + clm.getMapName(i) + "\n" + clm.getMapLabelTable(i)->toFormattedString(" ") + "\n"); } } break; case CiftiMappingType::PARCELS: { const CiftiParcelsMap& cpm = ciftiXML.getParcelsMap(alongType); dataFileInformation.addNameAndValue(" Has Volume Data", cpm.hasVolumeData()); if (cpm.hasVolumeData()) { const VolumeSpace volumeSpace = cpm.getVolumeSpace(); const int64_t* dims = volumeSpace.getDims(); dataFileInformation.addNameAndValue(" Volume Dims", AString::fromNumbers(dims, 3, ",")); } const std::vector surfaceStructures = cpm.getParcelSurfaceStructures(); for (std::vector::const_iterator surfaceIter = surfaceStructures.begin(); surfaceIter != surfaceStructures.end(); surfaceIter++) { const StructureEnum::Enum structure = *surfaceIter; dataFileInformation.addNameAndValue((" " + StructureEnum::toGuiName(structure)), (AString::number(cpm.getSurfaceNumberOfNodes(structure)) + " vertices")); } const std::vector& parcels = cpm.getParcels(); for (std::vector::const_iterator parcelIter = parcels.begin(); parcelIter != parcels.end(); parcelIter++) { const CiftiParcelsMap::Parcel parcel = *parcelIter; dataFileInformation.addNameAndValue(" Parcel " + AString::number(parcelIter - parcels.begin() + 1), parcel.m_name); for (std::map >::const_iterator surfIter = parcel.m_surfaceNodes.begin(); surfIter != parcel.m_surfaceNodes.end(); surfIter++) { const StructureEnum::Enum structure = surfIter->first; const std::set& nodeIndices = surfIter->second; dataFileInformation.addNameAndValue(" " + StructureEnum::toGuiName(structure), AString::number(nodeIndices.size()) + " vertices"); } if (parcel.m_voxelIndices.size() != 0) { dataFileInformation.addNameAndValue(" ", AString::number(parcel.m_voxelIndices.size()) + " voxels"); } } } break; case CiftiMappingType::SCALARS: break; case CiftiMappingType::SERIES: { const CiftiSeriesMap& csm = ciftiXML.getSeriesMap(alongType); dataFileInformation.addNameAndValue(" Start", csm.getStart()); dataFileInformation.addNameAndValue(" Step", csm.getStep()); QString unitsName = "Unknown"; switch (csm.getUnit()) { case CiftiSeriesMap::HERTZ: unitsName = "Hertz"; break; case CiftiSeriesMap::METER: unitsName = "Meters"; break; case CiftiSeriesMap::RADIAN: unitsName = "Radians"; break; case CiftiSeriesMap::SECOND: unitsName = "Seconds"; break; } dataFileInformation.addNameAndValue(" Units", unitsName); } break; } } } } /** * Get information about the content of a generic CIFTI file that is * not a Workbench supported CIFTI file type. * * @param filename * Name of the file. * @param dataFileInformation * Consolidates information about a data file. */ void CiftiMappableDataFile::getDataFileContentInformationForGenericCiftiFile(const AString& filename, DataFileContentInformation& dataFileInformation) { CiftiFile ciftiFile(filename); const CiftiXML& ciftiXML = ciftiFile.getCiftiXML(); std::vector dims = ciftiXML.getDimensions(); const int32_t numDims = static_cast(dims.size()); int64_t dataSizeInBytes = 1; for (int32_t i = 0; i < numDims; i++) { dataSizeInBytes *= dims[i]; } dataSizeInBytes *= sizeof(float); dataFileInformation.addNameAndValue("Name", filename); dataFileInformation.addNameAndValue("Type", AString("Connectivity Unknown (Could be Unsupported CIFTI File)")); dataFileInformation.addNameAndValue("Data Size", FileInformation::fileSizeToStandardUnits(dataSizeInBytes)); dataFileInformation.setOptionFlag(DataFileContentInformation::OPTION_SHOW_CIFTI_LABEL_MAPPING, true); CiftiMappableDataFile::addCiftiXmlToDataFileContentInformation(dataFileInformation, ciftiXML); } /** * Help load charting data for the surface with the given structure and node average. * * @param structure * The surface's structure. * @param nodeIndices * Indices of nodes for averaging. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will return true. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* CiftiMappableDataFile::helpLoadChartDataForSurfaceNodeAverage(const StructureEnum::Enum structure, const std::vector& nodeIndices) { ChartDataCartesian* chartData = NULL; try { const int32_t numberOfNodes = static_cast(nodeIndices.size()); if (numberOfNodes > 0) { std::vector dataSum; int32_t dataSumSize = 0; int32_t dataAverageCount = 0; std::vector data; bool firstNodeFlag = true; for (int32_t i = 0; i < numberOfNodes; i++) { if (getSeriesDataForSurfaceNode(structure, nodeIndices[i], data)) { if (firstNodeFlag) { firstNodeFlag = false; dataSumSize = static_cast(data.size()); if (dataSumSize > 0) { dataSum.resize(dataSumSize, 0.0); } } CaretAssert(dataSumSize == static_cast(data.size())); for (int32_t j = 0; j < dataSumSize; j++) { dataSum[j] += data[j]; } dataAverageCount++; } } if ((dataAverageCount > 0) && (dataSumSize > 0)) { std::vector dataAverage(dataSumSize); for (int32_t k = 0; k < dataSumSize; k++) { dataAverage[k] = dataSum[k] / dataAverageCount; } chartData = helpCreateCartesianChartData(dataAverage); } } } catch (const DataFileException& dfe) { if (chartData != NULL) { delete chartData; chartData = NULL; } throw dfe; } return chartData; } /** * Help load charting data for the voxel at the given coordinate. * * @param xyz * The voxel coordinate. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will return true. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* CiftiMappableDataFile::helpLoadChartDataForVoxelAtCoordinate(const float xyz[3]) { ChartDataCartesian* chartData = NULL; try { std::vector data; if (getSeriesDataForVoxelAtCoordinate(xyz, data)) { chartData = helpCreateCartesianChartData(data); } } catch (const DataFileException& dfe) { if (chartData != NULL) { delete chartData; chartData = NULL; } throw dfe; } return chartData; } /** * Help load charting data for the surface with the given structure and node index. * * @param structure * The surface's structure. * @param nodeIndex * Index of the node. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will return true. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* CiftiMappableDataFile::helpLoadChartDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t nodeIndex) { ChartDataCartesian* chartData = NULL; try { std::vector data; if (getSeriesDataForSurfaceNode(structure, nodeIndex, data)) { chartData = helpCreateCartesianChartData(data); } } catch (const DataFileException& dfe) { if (chartData != NULL) { delete chartData; chartData = NULL; } throw dfe; } return chartData; } bool CiftiMappableDataFile::getMapDataForSurface(const int32_t mapIndex, const StructureEnum::Enum structure, std::vector& surfaceMapData, std::vector* roiData) const { surfaceMapData.clear();//empty data is secondary hint at failure CaretAssert(m_ciftiFile); CaretAssertVectorIndex(m_mapContent, mapIndex); const int32_t surfaceNumNodes = getMappingSurfaceNumberOfNodes(structure); if (surfaceNumNodes < 1) return false; std::vector mapData; getMapData(mapIndex, mapData); /* * Map data may be empty for connectivity matrix files with no rows loaded. */ if (mapData.empty()) { return false; } std::vector dataIndicesForNodes; if (!getSurfaceDataIndicesForMappingToBrainordinates(structure, surfaceNumNodes, dataIndicesForNodes)) { return false;//currently should never happen, this currently works for parcellated files } CaretAssert((int)dataIndicesForNodes.size() == surfaceNumNodes); surfaceMapData.resize(surfaceNumNodes, 0.0f); if (roiData != NULL) { roiData->clear();//make sure all values get initialized before setting the roi nodes roiData->resize(surfaceNumNodes, 0.0f); } for (int32_t iNode = 0; iNode < surfaceNumNodes; iNode++) { CaretAssertVectorIndex(dataIndicesForNodes, iNode); const int64_t dataIndex = dataIndicesForNodes[iNode]; if (dataIndex >= 0) { surfaceMapData[iNode] = mapData[dataIndex]; if (roiData != NULL) { (*roiData)[iNode] = 1.0f; } } } return true; } /** * Set the map data for the given structure. * * @param mapIndex * Index of the map. * @param structure * The surface structure. * @param surfaceMapData * Data for surface map that must contain same number of elements as * in the brain models map for the surface. * @throw * DataFileException if there is an error. * */ void CiftiMappableDataFile::setMapDataForSurface(const int32_t mapIndex, const StructureEnum::Enum structure, const std::vector surfaceMapData) { CaretAssert(m_ciftiFile); CaretAssertVectorIndex(m_mapContent, mapIndex); const int32_t surfaceNumberOfNodes = static_cast(surfaceMapData.size()); const int32_t numCiftiNodes = getMappingSurfaceNumberOfNodes(structure); if (numCiftiNodes != surfaceNumberOfNodes) { return; } std::vector mapData; getMapData(mapIndex, mapData); /* * Map data may be empty for connectivity matrix files with no rows loaded. */ if (mapData.empty()) { return; } std::vector dataIndicesForNodes; if (getSurfaceDataIndicesForMappingToBrainordinates(structure, surfaceNumberOfNodes, dataIndicesForNodes)) { for (int32_t iNode = 0; iNode < surfaceNumberOfNodes; iNode++) { CaretAssertVectorIndex(dataIndicesForNodes, iNode); const int64_t dataIndex = dataIndicesForNodes[iNode]; if (dataIndex >= 0) { mapData[dataIndex] = surfaceMapData[iNode]; } } setMapData(mapIndex, mapData); } } /** * Get the matrix dimensions. * * @param numberOfRowsOut * Output number of rows in rgba matrix. * @param numberOfColumnsOut * Output number of Columns in rgba matrix. */ void CiftiMappableDataFile::helpMapFileGetMatrixDimensions(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) const { CaretAssert(m_ciftiFile); /* * Dimensions of matrix. */ numberOfRowsOut = m_ciftiFile->getNumberOfRows(); numberOfColumnsOut = m_ciftiFile->getNumberOfColumns(); } /** * Help load matrix chart data and order in the given row indices * for a file with multi-mapped file that uses a unqiue palette * or label table for each column (row) in the file. * * @param numberOfRowsOut * Output number of rows in rgba matrix. * @param numberOfColumnsOut * Output number of Columns in rgba matrix. * @param rowIndicesIn * Indices of rows inserted into matrix. * @param rgbaOut * RGBA matrix (number of elements is rows * columns * 4). * @return * True if output data is valid, else false. */ bool CiftiMappableDataFile::helpMapFileLoadChartDataMatrixRGBA(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut, const std::vector& rowIndicesIn, std::vector& rgbaOut) const { CaretAssert(m_ciftiFile); /* * Dimensions of matrix. */ numberOfRowsOut = m_ciftiFile->getNumberOfRows(); numberOfColumnsOut = m_ciftiFile->getNumberOfColumns(); const int32_t numberOfData = numberOfRowsOut * numberOfColumnsOut; if (numberOfData <= 0) { return false; } const bool useLabelTableFlag = isMappedWithLabelTable(); const bool usePaletteFlag = isMappedWithPalette(); if (( ! useLabelTableFlag) && ( ! usePaletteFlag)) { CaretAssert(0); return false; } const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); const AString badMapTypeMessage("Matrix charts supports only maps in columns at this time for LABEL, SCALAR, and SERIES data"); if (useLabelTableFlag) { if (ciftiXML.getMappingType(CiftiXML::ALONG_ROW) != CiftiMappingType::LABELS) { CaretAssertMessage(0, badMapTypeMessage); CaretLogSevere(badMapTypeMessage); return false; } } if (usePaletteFlag) { if (ciftiXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::SCALARS) { /* ok */ } else if (ciftiXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::SERIES) { /* ok */ } else { CaretAssertMessage(0, badMapTypeMessage); CaretLogSevere(badMapTypeMessage); return false; } } std::vector rowIndices = rowIndicesIn; if (rowIndices.empty()) { rowIndices.resize(numberOfRowsOut); for (int32_t i = 0; i < numberOfRowsOut; i++) { rowIndices[i] = i; } } else { if (static_cast(rowIndices.size()) != numberOfRowsOut) { const AString msg = AString("rowIndices size=%1 is different than " "number of rows in the matrix=%2.").arg(rowIndices.size()).arg(numberOfRowsOut); CaretAssertMessage(0, msg); CaretLogSevere(msg); return false; } } /* * Set up Fast Stats for files that use all data for * statistics and color mapping. */ CiftiMappableDataFile* nonConstMapFile = const_cast(this); /* * Allocate rgba output */ const int32_t numberOfRgba = numberOfData * 4; rgbaOut.resize(numberOfRgba); /* * Get each column, color it using its label table, and then * add the column's coloring into the output coloring. */ std::vector columnData(numberOfRowsOut); std::vector columnRGBA(numberOfRowsOut * 4); for (int32_t iCol = 0; iCol < numberOfColumnsOut; iCol++) { CaretAssertVectorIndex(m_mapContent, iCol); m_ciftiFile->getColumn(&columnData[0], iCol); if (useLabelTableFlag) { const GiftiLabelTable* labelTable = getMapLabelTable(iCol); NodeAndVoxelColoring::colorIndicesWithLabelTable(labelTable, &columnData[0], numberOfRowsOut, &columnRGBA[0]); } else if (usePaletteFlag) { const PaletteColorMapping* pcm = getMapPaletteColorMapping(iCol); CaretAssert(pcm); NodeAndVoxelColoring::colorScalarsWithPalette(nonConstMapFile->getFileFastStatistics(), pcm, &columnData[0], pcm, &columnData[0], numberOfRowsOut, &columnRGBA[0]); } else { CaretAssert(0); } for (int32_t iRow = 0; iRow < numberOfRowsOut; iRow++) { const int32_t rgbaOffset = (((iRow * numberOfColumnsOut) + iCol) * 4); CaretAssertVectorIndex(rgbaOut, rgbaOffset + 3); const int32_t columnRgbaOffset = (iRow * 4); CaretAssertVectorIndex(columnRGBA, columnRgbaOffset + 3); rgbaOut[rgbaOffset] = columnRGBA[columnRgbaOffset]; rgbaOut[rgbaOffset+1] = columnRGBA[columnRgbaOffset+1]; rgbaOut[rgbaOffset+2] = columnRGBA[columnRgbaOffset+2]; rgbaOut[rgbaOffset+3] = columnRGBA[columnRgbaOffset+3]; } } return true; } /** * Help load matrix chart data and order in the given row indices * for a connectivity matrix file where one palette is used * for all data in the file. * * @param numberOfRowsOut * Output number of rows in rgba matrix. * @param numberOfColumnsOut * Output number of Columns in rgba matrix. * @param rowIndicesIn * Indices of rows inserted into matrix. * @param rgbaOut * RGBA matrix (number of elements is rows * columns * 4). * @return * True if output data is valid, else false. */ bool CiftiMappableDataFile::helpMatrixFileLoadChartDataMatrixRGBA(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut, const std::vector& rowIndicesIn, std::vector& rgbaOut) const { CaretAssert(m_ciftiFile); /* * Dimensions of matrix. */ numberOfRowsOut = m_ciftiFile->getNumberOfRows(); numberOfColumnsOut = m_ciftiFile->getNumberOfColumns(); const int32_t numberOfData = numberOfRowsOut * numberOfColumnsOut; if (numberOfData <= 0) { return false; } std::vector rowIndices = rowIndicesIn; if (rowIndices.empty()) { rowIndices.resize(numberOfRowsOut); for (int32_t i = 0; i < numberOfRowsOut; i++) { rowIndices[i] = i; } } else { if (static_cast(rowIndices.size()) != numberOfRowsOut) { const AString msg = AString("rowIndices size=%1 is different than " "number of rows in the matrix=%2.").arg(rowIndices.size()).arg(numberOfRowsOut); CaretAssertMessage(0, msg); CaretLogSevere(msg); return false; } } /* * Get the data. */ std::vector data(numberOfData); for (int32_t iRow = 0; iRow < numberOfRowsOut; iRow++) { CaretAssertVectorIndex(rowIndices, iRow); const int32_t rowIndex = rowIndices[iRow]; const int32_t rowOffset = rowIndex * numberOfColumnsOut; CaretAssertVectorIndex(data, rowOffset + numberOfColumnsOut - 1); m_ciftiFile->getRow(&data[rowOffset], iRow); } /* * Get palette for color mapping. */ if (isMappedWithPalette()) { const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); const PaletteColorMapping* pcm = ciftiXML.getFilePalette(); CaretAssert(pcm); /* * Set up Fast Stats for files that use all data for * statistics and color mapping. * Map "0" will return the file fast statistics */ CiftiMappableDataFile* nonConstMapFile = const_cast(this); const FastStatistics* fileFastStats = nonConstMapFile->getFileFastStatistics(); /* * Color the data. */ const int32_t numRGBA = numberOfData * 4; rgbaOut.resize(numRGBA); NodeAndVoxelColoring::colorScalarsWithPalette(fileFastStats, pcm, &data[0], pcm, &data[0], numberOfData, &rgbaOut[0]); return true; } else { CaretAssertMessage(0, "Only palette mapped files supported at this time."); } return false; } /** * Get data from the file as requested in the given map file data selector. * * @param mapFileDataSelector * Specifies selection of data. * @param dataOut * Output with data. Will be empty if data does not support the map file data selector. */ void CiftiMappableDataFile::getDataForSelector(const MapFileDataSelector& mapFileDataSelector, std::vector& dataOut) const { dataOut.clear(); switch (mapFileDataSelector.getDataSelectionType()) { case MapFileDataSelector::DataSelectionType::INVALID: break; case MapFileDataSelector::DataSelectionType::COLUMN_DATA: { const bool loadColumnDataFlag = false; if (loadColumnDataFlag) { const DataFileTypeEnum::Enum dataFileType = getDataFileType(); if (dataFileType == DataFileTypeEnum::UNKNOWN) { CaretMappableDataFile* mapFile = NULL; AString mapFileName; int32_t columnIndex = -1; mapFileDataSelector.getColumnIndex(mapFile, mapFileName, columnIndex); bool loadDataFlag = false; if (mapFile != NULL) { if (mapFile == dynamic_cast(this)) { loadDataFlag = true; } } else if (mapFileName.endsWith(getFileNameNoPath())) { loadDataFlag = true; } if (loadDataFlag) { if ((columnIndex >= 0) && (columnIndex < m_ciftiFile->getNumberOfColumns())) { const int32_t numberOfElementsInColumn = m_ciftiFile->getNumberOfRows(); if (numberOfElementsInColumn > 0) { dataOut.resize(numberOfElementsInColumn); m_ciftiFile->getColumn(&dataOut[0], columnIndex); } } } } } } break; case MapFileDataSelector::DataSelectionType::ROW_DATA: { const DataFileTypeEnum::Enum dataFileType = getDataFileType(); if (dataFileType == DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES) { CaretMappableDataFile* mapFile = NULL; AString mapFileName; int32_t rowIndex = -1; mapFileDataSelector.getRowIndex(mapFile, mapFileName, rowIndex); bool loadDataFlag = false; if (mapFile != NULL) { if (mapFile == dynamic_cast(this)) { loadDataFlag = true; } } else if (mapFileName.endsWith(getFileNameNoPath())) { loadDataFlag = true; } if (loadDataFlag) { if ((rowIndex >= 0) && (rowIndex < m_ciftiFile->getNumberOfRows())) { const int32_t numberOfElementsInRow = m_ciftiFile->getNumberOfColumns(); if (numberOfElementsInRow > 0) { dataOut.resize(numberOfElementsInRow); m_ciftiFile->getRow(&dataOut[0], rowIndex); } } } } } break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: try { StructureEnum::Enum structure = StructureEnum::INVALID; int32_t numberOfVertices = -1; int32_t vertexIndex = -1; mapFileDataSelector.getSurfaceVertex(structure, numberOfVertices, vertexIndex); if (getMappingSurfaceNumberOfNodes(structure) == numberOfVertices) { if ( ! getSeriesDataForSurfaceNode(structure, vertexIndex, dataOut)) { dataOut.clear(); } } } catch (const DataFileException& dfe) { CaretLogWarning("Exeception: " + dfe.whatString()); dataOut.clear(); } break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTICES_AVERAGE: { try { StructureEnum::Enum structure = StructureEnum::INVALID; int32_t surfaceNumberOfVertices = -1; std::vector vertexIndices; mapFileDataSelector.getSurfaceVertexAverage(structure, surfaceNumberOfVertices, vertexIndices); if (getMappingSurfaceNumberOfNodes(structure) == surfaceNumberOfVertices) { const int32_t numberOfVertices = static_cast(vertexIndices.size()); if (numberOfVertices > 0) { std::vector dataSum; int32_t dataSumSize = 0; int32_t dataAverageCount = 0; std::vector data; bool firstNodeFlag = true; for (int32_t i = 0; i < numberOfVertices; i++) { if (getSeriesDataForSurfaceNode(structure, vertexIndices[i], data)) { if (firstNodeFlag) { firstNodeFlag = false; dataSumSize = static_cast(data.size()); if (dataSumSize > 0) { dataSum.resize(dataSumSize, 0.0); } } CaretAssert(dataSumSize == static_cast(data.size())); for (int32_t j = 0; j < dataSumSize; j++) { dataSum[j] += data[j]; } dataAverageCount++; } } if ((dataAverageCount > 0) && (dataSumSize > 0)) { dataOut.resize(dataSumSize); for (int32_t k = 0; k < dataSumSize; k++) { dataOut[k] = dataSum[k] / dataAverageCount; } } } } } catch (const DataFileException& dfe) { CaretLogWarning("Exeception: " + dfe.whatString()); dataOut.clear(); } } break; case MapFileDataSelector::DataSelectionType::VOLUME_XYZ: { float xyz[3]; mapFileDataSelector.getVolumeVoxelXYZ(xyz); getSeriesDataForVoxelAtCoordinate(xyz, dataOut); } break; } } /** * @return Pointer to mapping of data to brainordinates. * Will be NULL if data does not map to brainordinates. */ const CiftiBrainModelsMap* CiftiMappableDataFile::getBrainordinateMapping() const { if ( ! m_brainordinateMappingCachedFlag) { m_brainordinateMappingCachedFlag = true; switch (m_dataMappingAccessMethod) { case DATA_ACCESS_METHOD_INVALID: CaretAssert(0); break; case DATA_ACCESS_NONE: break; case DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN: case DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW: { const CiftiXML& myXML = m_ciftiFile->getCiftiXML(); if (myXML.getMappingType(m_dataMappingDirectionForCiftiXML) == CiftiMappingType::BRAIN_MODELS) { /* * Cache a COPY of the CiftiBrainModelsMap to avoid calling CiftiFile::getCiftiXML() many times */ m_brainordinateMapping.reset(new CiftiBrainModelsMap(myXML.getBrainModelsMap(m_dataMappingDirectionForCiftiXML))); } } break; } } return m_brainordinateMapping.get(); } /** * Are all brainordinates in this file also in the given file? * That is, the brainordinates are equal to or a subset of the brainordinates * in the given file. * * @param mapFile * The given map file. * @return * Match status. */ CaretMappableDataFile::BrainordinateMappingMatch CiftiMappableDataFile::getBrainordinateMappingMatch(const CaretMappableDataFile* mapFile) const { CaretAssert(mapFile); if (this == mapFile) { return BrainordinateMappingMatch::EQUAL; } const CiftiMappableDataFile* otherCiftiFile = dynamic_cast(mapFile); if (otherCiftiFile == NULL) { return BrainordinateMappingMatch::NO; } const CiftiBrainModelsMap* myBrainMap = getBrainordinateMapping(); if (myBrainMap != NULL) { const CiftiBrainModelsMap* otherBrainMap = otherCiftiFile->getBrainordinateMapping(); if (otherBrainMap != NULL) { switch (myBrainMap->testMatch(*otherBrainMap)) { case CiftiBrainModelsMap::MatchResult::EQUAL: return BrainordinateMappingMatch::EQUAL; break; case CiftiBrainModelsMap::MatchResult::NO: return BrainordinateMappingMatch::NO; break; case CiftiBrainModelsMap::MatchResult::SUBSET: return BrainordinateMappingMatch::SUBSET; break; } } } return BrainordinateMappingMatch::NO; } ///* ========================================================================== */ /** * Constructor. * * @param ciftiMappableDataFile * CIFTI file containing this map * @param ciftiFile * The CIFTI data file * @param fileMapDataType * Type of CIFTI file (matrix or multi-map). * @param readingDirectionForCiftiXML * Reading direction for CIFTI XML access * @param mappingDirectionForCiftiXML * Mapping direction for CIFTI XML access * @param mapIndex * Index of this map. */ CiftiMappableDataFile::MapContent::MapContent(CiftiMappableDataFile* ciftiMappableDataFile, CiftiFile* ciftiFile, const FileMapDataType fileMapDataType, const int32_t readingDirectionForCiftiXML, const int32_t mappingDirectionForCiftiXML, const int32_t mapIndex) : CaretObjectTracksModification(), m_ciftiMappableDataFile(ciftiMappableDataFile), m_ciftiFile(ciftiFile), m_fileMapDataType(fileMapDataType), m_readingDirectionForCiftiXML(readingDirectionForCiftiXML), m_mappingDirectionForCiftiXML(mappingDirectionForCiftiXML), m_mapIndex(mapIndex) { CaretAssert(ciftiFile); CaretAssert(mapIndex >= 0); m_fastStatistics.grabNew(NULL); m_histogram.grabNew(NULL); m_histogramLimitedValues.grabNew(NULL); m_metadata = NULL; m_paletteColorMapping = NULL; m_labelTable = NULL; m_dataCount = 0; m_rgbaValid = false; m_dataIsMappedWithLabelTable = false; const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); switch (m_mappingDirectionForCiftiXML) { case CiftiXML::ALONG_COLUMN: m_dataCount = ciftiFile->getNumberOfRows(); break; case CiftiXML::ALONG_ROW: m_dataCount = ciftiFile->getNumberOfColumns(); break; case CiftiXML::ALONG_STACK: break; } switch (m_fileMapDataType) { case FILE_MAP_DATA_TYPE_INVALID: CaretAssert(0); break; case FILE_MAP_DATA_TYPE_MATRIX: m_metadata = ciftiXML.getFileMetaData(); m_paletteColorMapping = ciftiXML.getFilePalette(); break; case FILE_MAP_DATA_TYPE_MULTI_MAP: switch (ciftiXML.getMappingType(m_readingDirectionForCiftiXML)) { case CiftiMappingType::BRAIN_MODELS: { CaretAssert(0); } break; case CiftiMappingType::LABELS: { const CiftiLabelsMap& map = ciftiXML.getLabelsMap(m_readingDirectionForCiftiXML); m_dataIsMappedWithLabelTable = true; m_metadata = map.getMapMetadata(mapIndex); CaretAssert(m_metadata); m_labelTable = map.getMapLabelTable(mapIndex); CaretAssert(m_labelTable); m_mapName = map.getMapName(m_mapIndex); } break; case CiftiMappingType::PARCELS: { CaretAssert(0); } break; case CiftiMappingType::SCALARS: { const CiftiScalarsMap& map = ciftiXML.getScalarsMap(m_readingDirectionForCiftiXML); m_metadata = map.getMapMetadata(mapIndex); CaretAssert(m_metadata); m_paletteColorMapping = map.getMapPalette(mapIndex); CaretAssert(m_paletteColorMapping); m_mapName = map.getMapName(m_mapIndex); } break; case CiftiMappingType::SERIES: { /* * Series Data has no map metadata but still need valid metadata instance */ m_metadataForMapsWithNoMetaData.grabNew(new GiftiMetaData()); m_metadata = m_metadataForMapsWithNoMetaData; /* * Series data usings the file's palette */ m_paletteColorMapping = ciftiXML.getFilePalette(); CaretAssert(m_paletteColorMapping); /* * Data series do not have map names but the map name is * a function of units and map index. */ const CiftiSeriesMap& map = ciftiXML.getSeriesMap(m_readingDirectionForCiftiXML); AString unitsSuffix; switch (map.getUnit()) { case CiftiSeriesMap::HERTZ: unitsSuffix = " hertz"; break; case CiftiSeriesMap::METER: unitsSuffix = " meters"; break; case CiftiSeriesMap::RADIAN: unitsSuffix = " radians"; break; case CiftiSeriesMap::SECOND: unitsSuffix = " seconds"; break; } if (unitsSuffix.isEmpty()) { m_mapName = ("Map Index: " + AString::number(m_mapIndex + 1)); } else { const float value = (map.getStart() + (m_mapIndex * map.getStep())); m_mapName = (AString::number(value) + unitsSuffix); } } break; } break; } } /** * Destructor. */ CiftiMappableDataFile::MapContent::~MapContent() { /** * Do not delete these as they point to data in CIFTI XML: * m_labelTable * m_paletteColorMapping * m_metadata; */ } /** * Clear the modification status of this map. */ void CiftiMappableDataFile::MapContent::clearModified() { CaretObjectTracksModification::clearModified(); if (m_labelTable != NULL) { m_labelTable->clearModified(); } m_metadata->clearModified(); if (m_paletteColorMapping != NULL) { m_paletteColorMapping->clearModified(); } } /** * @return Modification status. * * DOES NOT include modification status of palette. */ bool CiftiMappableDataFile::MapContent::isModified() const { if (CaretObjectTracksModification::isModified()) { return true; } if (m_labelTable != NULL) { if (m_labelTable->isModified()) { return true; } } if (m_metadata->isModified()) { return true; } /* DO NOT include palette color mapping status ! */ return false; } /** * @return Name of the map. */ AString CiftiMappableDataFile::MapContent::getName() const { return m_mapName; } /** * Set the name of the map. * * @param name * New name for map. */ void CiftiMappableDataFile::MapContent::setName(const AString& name) { if (name == m_mapName) { return; } m_mapName = name; const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); switch (ciftiXML.getMappingType(m_readingDirectionForCiftiXML)) { case CiftiMappingType::BRAIN_MODELS: { CaretAssert(0); } break; case CiftiMappingType::LABELS: { const CiftiLabelsMap& map = ciftiXML.getLabelsMap(m_readingDirectionForCiftiXML); map.setMapName(m_mapIndex, m_mapName); setModified(); } break; case CiftiMappingType::PARCELS: { CaretAssert(0); } break; case CiftiMappingType::SCALARS: { const CiftiScalarsMap& map = ciftiXML.getScalarsMap(m_readingDirectionForCiftiXML); map.setMapName(m_mapIndex, m_mapName); setModified(); } break; case CiftiMappingType::SERIES: /* * Data series do not have map names but the map name is * a function of units and map index. */ break; } } /** * Invalidate the coloring (usually due to palette or data changes). */ void CiftiMappableDataFile::MapContent::updateForChangeInMapData() { m_fastStatistics.grabNew(NULL); m_histogram.grabNew(NULL); m_histogramLimitedValues.grabNew(NULL); m_rgbaValid = false; } /** * @return True if fast statistics is valid, else false. */ bool CiftiMappableDataFile::MapContent::isFastStatisticsValid() const { return (m_fastStatistics != NULL); } /** * Update the Fast Statistics but only when needed. * * @param data * Data for fast statistics. */ void CiftiMappableDataFile::MapContent::updateFastStatistics(const std::vector& data) { if (data.empty()) { m_fastStatistics.grabNew(NULL); } else { if (m_fastStatistics == NULL) { m_fastStatistics.grabNew(new FastStatistics()); m_fastStatistics->update(&data[0], data.size()); } } } /** * @param numberOfBuckets, * Number of buckets in the histogram. * @return True if histogram is valid, else false. */ bool CiftiMappableDataFile::MapContent::isHistogramValid(const int32_t numberOfBuckets) const { return ((m_histogram != NULL) && (m_histogramNumberOfBuckets == numberOfBuckets)); } /** * Update the Histogram but only when needed. * * @param numberOfBuckets, * Number of buckets in the histogram. * @param data * Data for histogram. */ void CiftiMappableDataFile::MapContent::updateHistogram(const int32_t numberOfBuckets, const std::vector& data) { if (data.empty()) { m_histogram.grabNew(NULL); } else { CaretAssert(m_paletteColorMapping); if (m_histogram == NULL) { m_histogram.grabNew(new Histogram(numberOfBuckets)); } m_histogram->update(numberOfBuckets, &data[0], data.size()); m_histogramNumberOfBuckets = numberOfBuckets; } } /** * Is limited values histogram valid? Is is valid when it exists and * the limited value parameters have not changed. * * @param numberOfBuckets, * Number of buckets in the histogram. * @param mostPositiveValueInclusive * Values more positive than this value are excluded. * @param leastPositiveValueInclusive * Values less positive than this value are excluded. * @param leastNegativeValueInclusive * Values less negative than this value are excluded. * @param mostNegativeValueInclusive * Values more negative than this value are excluded. * @param includeZeroValues * If true zero values (very near zero) are included. * * @return true if valid, else false. */ bool CiftiMappableDataFile::MapContent::isHistogramLimitedValuesValid(const int32_t numberOfBuckets, const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) const { if (m_histogramLimitedValues == NULL) { return false; } else if ((numberOfBuckets != m_histogramLimitedValuesNumberOfBuckets) || (mostPositiveValueInclusive != m_histogramLimitedValuesMostPositiveValueInclusive) || (leastPositiveValueInclusive != m_histogramLimitedValuesLeastPositiveValueInclusive) || (leastNegativeValueInclusive != m_histogramLimitedValuesLeastNegativeValueInclusive) || (mostNegativeValueInclusive != m_histogramLimitedValuesMostNegativeValueInclusive) || (includeZeroValues != m_histogramLimitedValuesIncludeZeroValues)) { return false; } return true; } /** * Update the Histogram for limited values. * * @param data * Data for histogram. * @param mostPositiveValueInclusive * Values more positive than this value are excluded. * @param leastPositiveValueInclusive * Values less positive than this value are excluded. * @param leastNegativeValueInclusive * Values less negative than this value are excluded. * @param mostNegativeValueInclusive * Values more negative than this value are excluded. * @param includeZeroValues * If true zero values (very near zero) are included. */ void CiftiMappableDataFile::MapContent::updateHistogramLimitedValues(const int32_t numberOfBuckets, const std::vector& data, const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) { if (data.empty()) { m_histogramLimitedValues.grabNew(NULL); } else { if (m_histogramLimitedValues == NULL) { m_histogramLimitedValues.grabNew(new Histogram()); } m_histogramLimitedValues->update(numberOfBuckets, &data[0], data.size(), mostPositiveValueInclusive, leastPositiveValueInclusive, leastNegativeValueInclusive, mostNegativeValueInclusive, includeZeroValues); m_histogramLimitedValuesNumberOfBuckets = numberOfBuckets; m_histogramLimitedValuesMostPositiveValueInclusive = mostPositiveValueInclusive; m_histogramLimitedValuesLeastPositiveValueInclusive = leastPositiveValueInclusive; m_histogramLimitedValuesLeastNegativeValueInclusive = leastNegativeValueInclusive; m_histogramLimitedValuesMostNegativeValueInclusive = mostNegativeValueInclusive; m_histogramLimitedValuesIncludeZeroValues = includeZeroValues; } } /** * Get the thresholding data from the given thresholding file in a vector that * has the same brainordinate mapping as this file. * * @param threshMapFile * The thresholding file. * @param threshMapIndex * The map index in the thresholding file. * @param thresholdDataOut * Output containing data for thresholding a map in this file. */ bool CiftiMappableDataFile::MapContent::getThresholdData(const CaretMappableDataFile* threshMapFile, const int32_t threshMapIndex, std::vector& thresholdDataOut) { CaretAssert(threshMapFile); CaretAssert(threshMapIndex >= 0); const CiftiMappableDataFile* thresholdCiftiMapFile = dynamic_cast(threshMapFile); CaretAssert(thresholdCiftiMapFile); thresholdDataOut.resize(m_dataCount); switch (m_ciftiMappableDataFile->getBrainordinateMappingMatch(threshMapFile)) { case BrainordinateMappingMatch::EQUAL: thresholdCiftiMapFile->getMapData(threshMapIndex, thresholdDataOut); break; case BrainordinateMappingMatch::NO: CaretAssert(0); /* should never happen */ break; case BrainordinateMappingMatch::SUBSET: { /* * Since this file is a "subset" of the other file, will need to * data using the structures in each file. */ std::vector thresholdingFileMapData; thresholdCiftiMapFile->getMapData(threshMapIndex, thresholdingFileMapData); const CiftiBrainModelsMap* threshBrainMap = thresholdCiftiMapFile->getBrainordinateMapping(); CaretAssert(threshBrainMap); const CiftiBrainModelsMap* dataBrainMap = m_ciftiMappableDataFile->getBrainordinateMapping(); CaretAssert(dataBrainMap); const std::vector& dataModelsMap = dataBrainMap->getModelInfo(); const std::vector& threshModelsMap = threshBrainMap->getModelInfo(); for (const auto& dataModelsInfo : dataModelsMap) { const StructureEnum::Enum structure = dataModelsInfo.m_structure; for (const auto& threshModelsInfo : threshModelsMap) { if (structure == threshModelsInfo.m_structure) { CaretAssert(dataModelsInfo.m_indexCount == threshModelsInfo.m_indexCount); CaretAssertVectorIndex(thresholdingFileMapData, (threshModelsInfo.m_indexStart + threshModelsInfo.m_indexCount) - 1); CaretAssertVectorIndex(thresholdDataOut, (dataModelsInfo.m_indexStart + dataModelsInfo.m_indexCount) - 1); std::copy_n(&thresholdingFileMapData[threshModelsInfo.m_indexStart], threshModelsInfo.m_indexCount, &thresholdDataOut[dataModelsInfo.m_indexStart]); break; } } } } break; } return true; } /** * Update coloring for this map. If the paletteFile is NOT NULL, * color using a palette; otherwise, color with label table. * * @param data * Data contained in the map. * @param fastStatistics * Fast statistics used for palette coloring. While map content contains * a fast statistics member, it is calculated on the data within the map. * However, some files need the statistics calculated on the entire file * so that a particular data value from one map is colored exactly the * same as the particular data value in another map (the user may have * a min/max coloring selected and the two maps may a have different * min/max values). */ void CiftiMappableDataFile::MapContent::updateColoring(const std::vector& data, const FastStatistics* fastStatistics) { if (data.empty()) { return; } if (m_rgbaValid) { return; } if (m_dataCount != static_cast(data.size())) { m_dataCount = static_cast(data.size()); } const uint64_t rgbaCount = m_dataCount * 4; if (m_rgba.size() != rgbaCount) { m_rgba.resize(rgbaCount, 0); } if (m_dataIsMappedWithLabelTable) { NodeAndVoxelColoring::colorIndicesWithLabelTable(m_labelTable, &data[0], data.size(), &m_rgba[0]); } else { CaretAssert(m_paletteColorMapping); if (fastStatistics != NULL) { bool useThreshMapFileFlag = false; switch (m_paletteColorMapping->getThresholdType()) { case PaletteThresholdTypeEnum::THRESHOLD_TYPE_FILE: useThreshMapFileFlag = true; break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED: break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED_AVERAGE_AREA: break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_NORMAL: break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF: break; } if (useThreshMapFileFlag) { CaretAssert(m_ciftiMappableDataFile); const CaretMappableDataFileAndMapSelectionModel* threshFileModel = m_ciftiMappableDataFile->getMapThresholdFileSelectionModel(m_mapIndex); CaretAssert(threshFileModel); const CaretMappableDataFile* threshMapFile = threshFileModel->getSelectedFile(); if (threshMapFile != NULL) { const int32_t threshMapIndex = threshFileModel->getSelectedMapIndex(); std::vector thresholdData; getThresholdData(threshMapFile, threshMapIndex, thresholdData); CaretAssert(threshMapFile); CaretAssert(threshMapIndex >= 0); PaletteColorMapping* thresholdPaletteColorMapping = const_cast(threshMapFile->getMapPaletteColorMapping(threshMapIndex)); CaretAssert(thresholdPaletteColorMapping); CaretAssert(data.size() == thresholdData.size()); NodeAndVoxelColoring::colorScalarsWithPalette(fastStatistics, m_paletteColorMapping, &data[0], thresholdPaletteColorMapping, &thresholdData[0], m_dataCount, &m_rgba[0]); } else { NodeAndVoxelColoring::colorScalarsWithPalette(fastStatistics, m_paletteColorMapping, &data[0], m_paletteColorMapping, &data[0], m_dataCount, &m_rgba[0]); } } else { NodeAndVoxelColoring::colorScalarsWithPalette(fastStatistics, m_paletteColorMapping, &data[0], m_paletteColorMapping, &data[0], m_dataCount, &m_rgba[0]); } } else { std::fill(m_rgba.begin(), m_rgba.end(), 0); } } m_rgbaValid = true; } bool CiftiMappableDataFile::hasCiftiXML() const { return true; } const CiftiXML CiftiMappableDataFile::getCiftiXML() const { if (m_ciftiFile != NULL) { return m_ciftiFile->getCiftiXML(); } return CiftiXML();//this is why the function doesn't return a reference: must return something even when it doesn't have a CiftiXML allocated - could make it a pointer and return NULL } connectome-workbench-1.4.2/src/Files/CiftiMappableDataFile.h000066400000000000000000001125011360521144700237270ustar00rootroot00000000000000#ifndef __CIFTI_MAPPABLE_DATA_FILE_H__ #define __CIFTI_MAPPABLE_DATA_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretMappableDataFile.h" #include "CaretPointer.h" #include "CaretObjectTracksModification.h" #include "ChartTwoMatrixTriangularViewingModeEnum.h" #include "CiftiMappingType.h" #include "CiftiXMLElements.h" #include "DisplayGroupEnum.h" #include "EventListenerInterface.h" #include "VolumeMappableInterface.h" #include #include namespace caret { class ChartData; class ChartDataCartesian; class CiftiFile; class CiftiParcelsMap; class CiftiXML; class FastStatistics; class GraphicsPrimitiveV3fC4f; class GroupAndNameHierarchyModel; class Histogram; class SparseVolumeIndexer; class CiftiMappableDataFile : public CaretMappableDataFile, public EventListenerInterface, public VolumeMappableInterface { protected: /** * Method for accessing data with CIFTI */ enum DataAccessMethod { /** * Invalid data access method. */ DATA_ACCESS_METHOD_INVALID, /** * No access to data */ DATA_ACCESS_NONE, /** * The data is accessed from CiftiFile using ROW Methods * and from the XML using ALONG_COLUMN */ DATA_ACCESS_FILE_ROWS_OR_XML_ALONG_COLUMN, /** * Use ALONG_ROW to access CIFTI data * which means one is accessing COLUMNS of data */ DATA_ACCESS_FILE_COLUMNS_OR_XML_ALONG_ROW }; /** * Method for color mapping a map */ enum ColorMappingMethod { /** * Invalid color mapping method. */ COLOR_MAPPING_METHOD_INVALID, /** * Color data using a label table */ COLOR_MAPPING_METHOD_LABEL_TABLE, /** * Color data using a color palette */ COLOR_MAPPING_METHOD_PALETTE }; /** * Source of palette color mapping. * Some CIFTI files provide one palette color mapping per file. * Others have one palette color mapping for each map in the file. */ enum PaletteColorMappingSourceType { PALETTE_COLOR_MAPPING_SOURCE_INVALID, /** * Use file's palette color mapping. */ PALETTE_COLOR_MAPPING_SOURCE_FROM_FILE, /** * Use map's palette color mapping. */ PALETTE_COLOR_MAPPING_SOURCE_FROM_MAP }; /** * Type of map data in the file. */ enum FileMapDataType { /** * Invalid file map data type */ FILE_MAP_DATA_TYPE_INVALID, /** * The file contains a connectivity matrix. There is only * 'one map' and the data for the map is selectively read * and replaced based upon user actions. */ FILE_MAP_DATA_TYPE_MATRIX, /** * The file contains one or more maps and all maps are loaded * when the file is read. */ FILE_MAP_DATA_TYPE_MULTI_MAP }; /** How to read the file */ enum FileDataReadingType { /** Read all data in the file */ FILE_READ_DATA_ALL, /** Open the file but only read data as needed */ FILE_READ_DATA_AS_NEEDED }; CiftiMappableDataFile(const DataFileTypeEnum::Enum dataFileType); public: virtual ~CiftiMappableDataFile(); static CiftiMappableDataFile* newInstanceForCiftiFileTypeAndSurface(const DataFileTypeEnum::Enum ciftiFileType, const StructureEnum::Enum structure, const int32_t numberOfNodes, AString& errorMessageOut); virtual void receiveEvent(Event* event); virtual void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation); static void addCiftiXmlToDataFileContentInformation(DataFileContentInformation& dataFileInformation, const CiftiXML& ciftiXML); static void getDataFileContentInformationForGenericCiftiFile(const AString& filename, DataFileContentInformation& dataFileInformation); virtual void clear(); virtual bool isEmpty() const; virtual bool isMappableToSurfaceStructure(const StructureEnum::Enum structure) const; virtual StructureEnum::Enum getStructure() const; virtual void setStructure(const StructureEnum::Enum structure); virtual GiftiMetaData* getFileMetaData(); virtual const GiftiMetaData* getFileMetaData() const; virtual void setPreferOnDiskReading(const bool& prefer); virtual void readFile(const AString& ciftiMapFileName); virtual void writeFile(const AString& filename); virtual bool isSurfaceMappable() const; virtual bool isVolumeMappable() const; virtual int32_t getNumberOfMaps() const; virtual bool hasMapAttributes() const; virtual AString getMapName(const int32_t mapIndex) const; virtual void setMapName(const int32_t mapIndex, const AString& mapName); virtual const GiftiMetaData* getMapMetaData(const int32_t mapIndex) const; virtual GiftiMetaData* getMapMetaData(const int32_t mapIndex); virtual AString getMapUniqueID(const int32_t mapIndex) const; virtual bool isMappedWithPalette() const; virtual bool isOnePaletteUsedForAllMaps() const; virtual const FastStatistics* getMapFastStatistics(const int32_t mapIndex); virtual const Histogram* getMapHistogram(const int32_t mapIndex); virtual const Histogram* getMapHistogram(const int32_t mapIndex, const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues); virtual void getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) const; virtual int64_t getDataSizeUncompressedInBytes() const; virtual const FastStatistics* getFileFastStatistics(); virtual const Histogram* getFileHistogram(); virtual const Histogram* getFileHistogram(const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues); virtual PaletteColorMapping* getMapPaletteColorMapping(const int32_t mapIndex); virtual const PaletteColorMapping* getMapPaletteColorMapping(const int32_t mapIndex) const; const CiftiParcelsMap* getCiftiParcelsMapForBrainordinateMapping() const; const CiftiParcelsMap* getCiftiParcelsMapForLoading() const; const CiftiParcelsMap* getCiftiParcelsMapForDirection(const int direction) const; virtual bool isMappedWithLabelTable() const; virtual GiftiLabelTable* getMapLabelTable(const int32_t mapIndex); virtual const GiftiLabelTable* getMapLabelTable(const int32_t mapIndex) const; virtual void updateScalarColoringForAllMaps() override; virtual void updateScalarColoringForMap(const int32_t mapIndex) override; virtual bool isMapColoringValid(const int32_t mapIndex) const; virtual void getDimensions(int64_t& dimOut1, int64_t& dimOut2, int64_t& dimOut3, int64_t& dimTimeOut, int64_t& numComponents) const override; virtual void getDimensions(std::vector& dimsOut) const override; virtual void getDimensionsForDataLoading(int64_t& dimOut1, int64_t& dimOut2, int64_t& dimOut3, int64_t& dimTimeOut, int64_t& numComponents) const; virtual void getDimensionsForDataLoading(std::vector& dimsOut) const; virtual void getMapDimensions(std::vector &dim) const; virtual const int64_t& getNumberOfComponents() const override; virtual void indexToSpace(const float& indexIn1, const float& indexIn2, const float& indexIn3, float& coordOut1, float& coordOut2, float& coordOut3) const override; virtual void indexToSpace(const float& indexIn1, const float& indexIn2, const float& indexIn3, float* coordOut) const override; virtual void indexToSpace(const int64_t* indexIn, float* coordOut) const override; virtual void enclosingVoxel(const float& coordIn1, const float& coordIn2, const float& coordIn3, int64_t& indexOut1, int64_t& indexOut2, int64_t& indexOut3) const override; virtual void enclosingVoxelForDataLoading(const float& coordIn1, const float& coordIn2, const float& coordIn3, int64_t& indexOut1, int64_t& indexOut2, int64_t& indexOut3) const; virtual bool indexValid(const int64_t& indexIn1, const int64_t& indexIn2, const int64_t& indexIn3, const int64_t brickIndex = 0, const int64_t component = 0) const override; virtual bool indexValidForDataLoading(const int64_t& indexIn1, const int64_t& indexIn2, const int64_t& indexIn3, const int64_t brickIndex = 0, const int64_t component = 0) const; virtual const VolumeSpace& getVolumeSpace() const; virtual void getVoxelSpaceBoundingBox(BoundingBox& boundingBoxOut) const override; virtual int64_t getVoxelColorsForSliceInMap(const int32_t mapIndex, const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const override; int64_t getVoxelColorsForSliceInMap(const int32_t mapIndex, const int64_t firstVoxelIJK[3], const int64_t rowStepIJK[3], const int64_t columnStepIJK[3], const int64_t numberOfRows, const int64_t numberOfColumns, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const override; virtual int64_t getVoxelColorsForSubSliceInMap(const int32_t mapIndex, const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, const int64_t firstCornerVoxelIndex[3], const int64_t lastCornerVoxelIndex[3], const int64_t voxelCountIJK[3], const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const override; virtual void getVoxelColorInMap(const int64_t indexIn1, const int64_t indexIn2, const int64_t indexIn3, const int64_t mapIndex, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t rgbaOut[4]) const override; virtual void getVoxelColorInMapForLabelData(const std::vector& dataForMap, const int64_t indexIn1, const int64_t indexIn2, const int64_t indexIn3, const int64_t mapIndex, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t rgbaOut[4]) const; virtual bool getMapVolumeVoxelValue(const int32_t mapIndex, const float xyz[3], int64_t ijkOut[3], float& numericalValueOut, bool& numericalValueOutValid, AString& textValueOut) const; virtual bool getMapVolumeVoxelValues(const std::vector mapIndices, const float xyz[3], int64_t ijkOut[3], std::vector& numericalValuesOut, std::vector& numericalValuesOutValid, AString& textValueOut) const; int64_t getMapDataOffsetForVoxelAtCoordinate(const float coordinate[3], const int32_t mapIndex) const; virtual float getVoxelValue(const float* coordinateIn, bool* validOut = NULL, const int64_t mapIndex = 0, const int64_t component = 0) const override; virtual float getVoxelValue(const float coordinateX, const float coordinateY, const float coordinateZ, bool* validOut = NULL, const int64_t mapIndex = 0, const int64_t component = 0) const override; virtual bool getVolumeVoxelIdentificationForMaps(const std::vector& mapIndices, const float xyz[3], int64_t ijkOut[3], AString& textOut) const; std::vector getUniqueLabelKeysUsedInMap(const int32_t mapIndex) const; GroupAndNameHierarchyModel* getGroupAndNameHierarchyModel(); const GroupAndNameHierarchyModel* getGroupAndNameHierarchyModel() const; virtual bool getMapSurfaceNodeValue(const int32_t mapIndex, const StructureEnum::Enum structure, const int nodeIndex, const int32_t numberOfNodes, float& numericalValueOut, bool& numericalValueOutValid, AString& textValueOut) const; virtual bool getMapSurfaceNodeValues(const std::vector& mapIndices, const StructureEnum::Enum structure, const int nodeIndex, const int32_t numberOfNodes, std::vector& numericalValuesOut, std::vector& numericalValuesOutValid, AString& textValueOut) const; virtual bool getSurfaceNodeIdentificationForMaps(const std::vector& mapIndices, const StructureEnum::Enum structure, const int nodeIndex, const int32_t numberOfNodes, AString& textOut) const override; int32_t getMappingSurfaceNumberOfNodes(const StructureEnum::Enum structure) const; bool getSeriesDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t nodeIndex, std::vector& seriesDataOut) const; bool getSeriesDataForVoxelAtCoordinate(const float xyz[3], std::vector& seriesDataOut) const; virtual bool getMapSurfaceNodeColoring(const int32_t mapIndex, const StructureEnum::Enum structure, float* surfaceRGBAOut, float* dataValuesOut, const int32_t surfaceNumberOfNodes); virtual void clearModified(); virtual bool isModifiedExcludingPaletteColorMapping() const; virtual NiftiTimeUnitsEnum::Enum getMapIntervalUnits() const; virtual void getMapIntervalStartAndStep(float& firstMapUnitsValueOut, float& mapIntervalStepValueOut) const; virtual bool getDataRangeFromAllMaps(float& dataRangeMinimumOut, float& dataRangeMaximumOut) const; bool getMapDataForSurface(const int32_t mapIndex, const StructureEnum::Enum structure, std::vector& surfaceMapData, std::vector* roiData = NULL) const; void setMapDataForSurface(const int32_t mapIndex, const StructureEnum::Enum structure, const std::vector surfaceMapData); bool getParcelNodesElementForSelectedParcel(std::set &parcelNodesOut, const StructureEnum::Enum &structure, const int64_t &selectionIndex) const; void invalidateColoringInAllMaps(); void getBrainordinateFromRowIndex(const int64_t rowIndex, StructureEnum::Enum& surfaceStructureOut, int32_t& surfaceNodeIndexOut, int32_t& surfaceNumberOfNodesOut, bool& surfaceNodeValidOut, int64_t voxelIJKOut[3], float voxelXYZOut[3], bool& voxelValidOut) const; bool hasCiftiXML() const; const CiftiXML getCiftiXML() const; /** * @return The index base (zero or one) for displaying row and column indices in the Graphical User Interface */ static inline int32_t getCiftiFileRowColumnIndexBaseForGUI() { return CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI; } virtual void getDataForSelector(const MapFileDataSelector& mapFileDataSelector, std::vector& dataOut) const override; virtual BrainordinateMappingMatch getBrainordinateMappingMatch(const CaretMappableDataFile* mapFile) const override; private: CiftiMappableDataFile(const CiftiMappableDataFile&); CiftiMappableDataFile& operator=(const CiftiMappableDataFile&); public: enum class MatrixGridMode { FILLED, OUTLINE }; virtual void getMapData(const int32_t mapIndex, std::vector& dataOut) const; virtual void setMapData(const int32_t mapIndex, const std::vector& data); virtual void getMatrixRGBA(std::vector& rgba); bool getMatrixForChartingRGBA(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut, std::vector& rgbaOut) const; GraphicsPrimitiveV3fC4f* getMatrixChartingGraphicsPrimitive(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode, const MatrixGridMode gridMode) const; /** Identifier for the matrix primitives alternative color used for the grid coloring */ int32_t getMatrixChartGraphicsPrimitiveGridColorIdentifier() const { return 1; } virtual void getFileData(std::vector& data) const; const CiftiFile* getCiftiFile() const { return m_ciftiFile; } protected: virtual bool getParcelLabelMapSurfaceNodeValue(const int32_t mapIndex, const StructureEnum::Enum structure, const int nodeIndex, const int32_t numberOfNodes, float& numericalValueOut, bool& numericalValueOutValid, AString& textValueOut) const; void updateForChangeInMapDataWithMapIndex(const int32_t mapIndex); ChartDataCartesian* helpLoadChartDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t nodeIndex); ChartDataCartesian* helpLoadChartDataForSurfaceNodeAverage(const StructureEnum::Enum structure, const std::vector& nodeIndices); ChartDataCartesian* helpLoadChartDataForVoxelAtCoordinate(const float xyz[3]); void helpMapFileGetMatrixDimensions(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) const; bool helpMapFileLoadChartDataMatrixRGBA(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut, const std::vector& rowIndicesIn, std::vector& rgbaOut) const; bool helpMatrixFileLoadChartDataMatrixRGBA(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut, const std::vector& rowIndicesIn, std::vector& rgbaOut) const; private: class MapContent : public CaretObjectTracksModification { public: MapContent(CiftiMappableDataFile* ciftiMappableDataFile, CiftiFile* ciftiFile, const FileMapDataType fileMapDataType, const int32_t readingDirectionForCiftiXML, const int32_t mappingDirectionForCiftiXML, const int32_t mapIndex); ~MapContent(); virtual void clearModified(); virtual bool isModified() const; void updateForChangeInMapData(); void updateColoring(const std::vector& data, const FastStatistics* fastStatistics); bool isFastStatisticsValid() const; void updateFastStatistics(const std::vector& data); bool isHistogramValid(const int32_t numberOfBuckets) const; void updateHistogram(const int32_t numberOfBuckets, const std::vector& data); bool isHistogramLimitedValuesValid(const int32_t numberOfBuckets, const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) const; void updateHistogramLimitedValues(const int32_t numberOfBuckets, const std::vector& data, const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues); AString getName() const; void setName(const AString& name); bool getThresholdData(const CaretMappableDataFile* threshMapFile, const int32_t threshMapIndex, std::vector& thresholdData); /** CIFTI file containing the map */ CiftiMappableDataFile* m_ciftiMappableDataFile; /** The CIFTI file pointer */ CiftiFile *m_ciftiFile; /** Maps or Matrix file */ const FileMapDataType m_fileMapDataType; /** Direction for obtaining reading information (CiftiXML::ALONG_ROW, etc) */ const int32_t m_readingDirectionForCiftiXML; /** Direction for obtaining mapping information (CiftiXML::ALONG_ROW, etc) */ const int32_t m_mappingDirectionForCiftiXML; /** Index of this map */ const int32_t m_mapIndex; /** Name of the map */ AString m_mapName; /** Count of data elements in map. */ int64_t m_dataCount; /** Metadata for the map. Points to data in CiftiFile so DO NOT delete */ GiftiMetaData* m_metadata; /** Palette color mapping for map. Points to data in CiftiFile so DO NOT delete */ PaletteColorMapping* m_paletteColorMapping; /** Label table for map. Points to data in CiftiFile so DO NOT delete */ GiftiLabelTable* m_labelTable; /** Indicates data is mapped with a lable table */ bool m_dataIsMappedWithLabelTable; /** RGBA coloring for map */ std::vector m_rgba; /** RGBA coloring is valid */ bool m_rgbaValid; /** fast statistics for map */ CaretPointer m_fastStatistics; /** histogram for all of map map */ CaretPointer m_histogram; int32_t m_histogramNumberOfBuckets = 100; /** histogram for limited values from map */ CaretPointer m_histogramLimitedValues; int32_t m_histogramLimitedValuesNumberOfBuckets; float m_histogramLimitedValuesMostPositiveValueInclusive; float m_histogramLimitedValuesLeastPositiveValueInclusive; float m_histogramLimitedValuesLeastNegativeValueInclusive; float m_histogramLimitedValuesMostNegativeValueInclusive; bool m_histogramLimitedValuesIncludeZeroValues; private: /** Name of map */ AString m_name; /** * For maps that do not have metadata, a metadata instance * is still needed even though it essentially does nothing. */ CaretPointer m_metadataForMapsWithNoMetaData; }; void clearPrivate(); protected: void initializeAfterReading(const AString& filename); void validateMappingTypes(const AString& filename); void resetDataLoadingMembers(); void validateKeysAndLabels() const; virtual void validateAfterFileReading(); virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); bool getSurfaceDataIndicesForMappingToBrainordinates(const StructureEnum::Enum structure, const int64_t surfaceNumberOfNodes, std::vector& dataIndicesForNodes) const; void setupCiftiReadingMappingDirection(); static AString mappingTypeToName(const CiftiMappingType::MappingType mappingType); const CiftiBrainModelsMap* getBrainordinateMapping() const; /** * Point to the CIFTI file object. */ CaretPointer m_ciftiFile; /** * How to read data from the file */ FileDataReadingType m_fileDataReadingType; /** * Method used when reading data from the file. */ DataAccessMethod m_dataReadingAccessMethod; /** Direction for obtaining mapping information (CiftiXML::ALONG_ROW, etc) */ int32_t m_dataReadingDirectionForCiftiXML; /** * Method used when mapping loaded data to brainordinates. */ DataAccessMethod m_dataMappingAccessMethod; /** Direction for obtaining mapping information (CiftiXML::ALONG_ROW, etc) */ int32_t m_dataMappingDirectionForCiftiXML; /** * Method used when mapping data to colors (LabelTable or Palette). */ ColorMappingMethod m_colorMappingMethod; /** * Source of color palette (file or per map) */ PaletteColorMappingSourceType m_paletteColorMappingSource; /* * Supported palette normalization modes */ std::vector m_paletteNormalizationModesSupported; /** * Type of data in the file's map(s). */ FileMapDataType m_fileMapDataType; /** Contains data related to each map */ std::vector m_mapContent; /** True if the file contains surface data */ bool m_containsSurfaceData; /** True if the file contains surface data */ bool m_containsVolumeData; float m_mappingTimeStart; float m_mappingTimeStep; NiftiTimeUnitsEnum::Enum m_mappingTimeUnits; /** Fast statistics used when statistics computed on all data in file */ CaretPointer m_fileFastStatistics; /** Histogram used when statistics computed on all data in file */ CaretPointer m_fileHistogram; /** Primitive for matrix cells */ mutable std::unique_ptr m_matrixGraphicsPrimitive; /** Primitive for grid outline around matrix cells */ mutable std::unique_ptr m_matrixGraphicsOutlinePrimitive; mutable uint8_t m_previousMatrixGridRGBA[4] = { 0, 1, 2, 3 }; int32_t m_fileHistogramNumberOfBuckets = 100; /** Histogram with limited values used when statistics computed on all data in file */ CaretPointer m_fileHistorgramLimitedValues; int32_t m_fileHistogramLimitedValuesNumberOfBuckets = 100; float m_fileHistogramLimitedValuesMostPositiveValueInclusive; float m_fileHistogramLimitedValuesLeastPositiveValueInclusive; float m_fileHistogramLimitedValuesLeastNegativeValueInclusive; float m_fileHistogramLimitedValuesMostNegativeValueInclusive; bool m_fileHistogramLimitedValuesIncludeZeroValues; /** Fast conversion of IJK to data offset */ CaretPointer m_voxelIndicesToOffsetForDataMapping; CaretPointer m_voxelIndicesToOffsetForDataReading; /** Holds class and name hierarchy used for display selection */ mutable CaretPointer m_classNameHierarchy; /** force an update of the class and name hierarchy */ mutable bool m_forceUpdateOfGroupAndNameHierarchy; static const int32_t S_CIFTI_XML_ALONG_INVALID; protected: /** * This value is used for the "base index" of CIFTI rows/columns * in the user-interface. */ static const int32_t CIFTI_FILE_ROW_COLUMN_INDEX_BASE_FOR_GUI = 1; private: friend class ChartableTwoFileDelegate; friend class ChartableTwoFileMatrixChart; /** Is lazily initialized and caches CiftiBrainModelsMap for comparison with other CIFTI files */ mutable std::unique_ptr m_brainordinateMapping; /** Controls lazy initialization of m_brainordinateMapping */ mutable bool m_brainordinateMappingCachedFlag = false; // ADD_NEW_MEMBERS_HERE }; #ifdef __CIFTI_MAPPABLE_DATA_FILE_DECLARE__ const int32_t CiftiMappableDataFile::S_CIFTI_XML_ALONG_INVALID = -1; #endif // __CIFTI_MAPPABLE_DATA_FILE_DECLARE__ } // namespace #endif //__CIFTI_MAPPABLE_DATA_FILE_H__ connectome-workbench-1.4.2/src/Files/CiftiParcelColoringModeEnum.cxx000066400000000000000000000262071360521144700255330ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CIFTI_PARCEL_COLORING_MODE_ENUM_DECLARE__ #include "CiftiParcelColoringModeEnum.h" #undef __CIFTI_PARCEL_COLORING_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::CiftiParcelColoringModeEnum * \brief Enumerated type for selected parcel coloring. * * Enumerated type for coloring of selected CIFTI parcel * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_ciftiParcelColoringModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void ciftiParcelColoringModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "CiftiParcelColoringModeEnum.h" * * Instatiate: * m_ciftiParcelColoringModeEnumComboBox = new EnumComboBoxTemplate(this); * m_ciftiParcelColoringModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_ciftiParcelColoringModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(ciftiParcelColoringModeEnumComboBoxItemActivated())); * * Update the selection: * m_ciftiParcelColoringModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const CiftiParcelColoringModeEnum::Enum VARIABLE = m_ciftiParcelColoringModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ CiftiParcelColoringModeEnum::CiftiParcelColoringModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ CiftiParcelColoringModeEnum::~CiftiParcelColoringModeEnum() { } /** * Initialize the enumerated metadata. */ void CiftiParcelColoringModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(CiftiParcelColoringModeEnum(CIFTI_PARCEL_COLORING_OFF, "CIFTI_PARCEL_COLORING_OFF", "Off")); enumData.push_back(CiftiParcelColoringModeEnum(CIFTI_PARCEL_COLORING_FILL, "CIFTI_PARCEL_COLORING_FILL", "Fill")); enumData.push_back(CiftiParcelColoringModeEnum(CIFTI_PARCEL_COLORING_OUTLINE, "CIFTI_PARCEL_COLORING_OUTLINE", "Outline")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const CiftiParcelColoringModeEnum* CiftiParcelColoringModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const CiftiParcelColoringModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString CiftiParcelColoringModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const CiftiParcelColoringModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ CiftiParcelColoringModeEnum::Enum CiftiParcelColoringModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = CiftiParcelColoringModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const CiftiParcelColoringModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type CiftiParcelColoringModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString CiftiParcelColoringModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const CiftiParcelColoringModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ CiftiParcelColoringModeEnum::Enum CiftiParcelColoringModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = CiftiParcelColoringModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const CiftiParcelColoringModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type CiftiParcelColoringModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t CiftiParcelColoringModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const CiftiParcelColoringModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ CiftiParcelColoringModeEnum::Enum CiftiParcelColoringModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = CiftiParcelColoringModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const CiftiParcelColoringModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type CiftiParcelColoringModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void CiftiParcelColoringModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void CiftiParcelColoringModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(CiftiParcelColoringModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void CiftiParcelColoringModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(CiftiParcelColoringModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Files/CiftiParcelColoringModeEnum.h000066400000000000000000000065011360521144700251530ustar00rootroot00000000000000#ifndef __CIFTI_PARCEL_COLORING_MODE_ENUM_H__ #define __CIFTI_PARCEL_COLORING_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class CiftiParcelColoringModeEnum { public: /** * Enumerated values. */ enum Enum { /** off (no special coloring) */ CIFTI_PARCEL_COLORING_OFF, /** fill with user defined color */ CIFTI_PARCEL_COLORING_FILL, /** outline with user defined color */ CIFTI_PARCEL_COLORING_OUTLINE }; ~CiftiParcelColoringModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: CiftiParcelColoringModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const CiftiParcelColoringModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __CIFTI_PARCEL_COLORING_MODE_ENUM_DECLARE__ std::vector CiftiParcelColoringModeEnum::enumData; bool CiftiParcelColoringModeEnum::initializedFlag = false; int32_t CiftiParcelColoringModeEnum::integerCodeCounter = 0; #endif // __CIFTI_PARCEL_COLORING_MODE_ENUM_DECLARE__ } // namespace #endif //__CIFTI_PARCEL_COLORING_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Files/CiftiParcelLabelFile.cxx000066400000000000000000000614201360521144700241400ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CIFTI_PARCEL_LABEL_FILE_DECLARE__ #include "CiftiParcelLabelFile.h" #undef __CIFTI_PARCEL_LABEL_FILE_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "ChartMatrixDisplayProperties.h" #include "CiftiFile.h" #include "CiftiParcelReordering.h" #include "CiftiParcelReorderingModel.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "NodeAndVoxelColoring.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::CiftiParcelLabelFile * \brief CIFTI Parcellated Label File * \ingroup Files */ /** * Constructor. */ CiftiParcelLabelFile::CiftiParcelLabelFile() : CiftiMappableDataFile(DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL) { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = false; m_chartMatrixDisplayProperties[i] = new ChartMatrixDisplayProperties(); } m_selectedParcelColoringMode = CiftiParcelColoringModeEnum::CIFTI_PARCEL_COLORING_OUTLINE; m_selectedParcelColor = CaretColorEnum::WHITE; m_parcelReorderingModel = new CiftiParcelReorderingModel(this); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_selectedParcelColoringMode", &m_selectedParcelColoringMode); m_sceneAssistant->add("m_selectedParcelColor", &m_selectedParcelColor); m_sceneAssistant->add("m_parcelReorderingModel", "CiftiParcelReorderingModel", m_parcelReorderingModel); } /** * Destructor. */ CiftiParcelLabelFile::~CiftiParcelLabelFile() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { delete m_chartMatrixDisplayProperties[i]; } delete m_parcelReorderingModel; delete m_sceneAssistant; } /** * Get the matrix dimensions. * * @param numberOfRowsOut * Number of rows in the matrix. * @param numberOfColumnsOut * Number of rows in the matrix. */ void CiftiParcelLabelFile::getMatrixDimensions(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) const { helpMapFileGetMatrixDimensions(numberOfRowsOut, numberOfColumnsOut); } /** * Get the matrix RGBA coloring for this matrix data creator. * * @param numberOfRowsOut * Number of rows in the coloring matrix. * @param numberOfColumnsOut * Number of rows in the coloring matrix. * @param rgbaOut * RGBA coloring output with number of elements * (numberOfRowsOut * numberOfColumnsOut * 4). * @return * True if data output data is valid, else false. */ bool CiftiParcelLabelFile::getMatrixDataRGBA(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut, std::vector& rgbaOut) const { CiftiParcelLabelFile* parcelLabelFile = NULL; int32_t parcelLabelFileMapIndex = -1; bool enabled = false; std::vector parcelLabelFiles; getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, parcelLabelFile, parcelLabelFileMapIndex, enabled); std::vector rowIndices; if (enabled) { const CiftiParcelReordering* parcelReordering = getParcelReordering(parcelLabelFile, parcelLabelFileMapIndex); if (parcelReordering != NULL) { rowIndices = parcelReordering->getReorderedParcelIndices(); } } return helpMapFileLoadChartDataMatrixRGBA(numberOfRowsOut, numberOfColumnsOut, rowIndices, rgbaOut); // CaretAssert(m_ciftiFile); // // /* // * Dimensions of matrix. // */ // numberOfRowsOut = m_ciftiFile->getNumberOfRows(); // numberOfColumnsOut = m_ciftiFile->getNumberOfColumns(); // const int32_t numberOfData = numberOfRowsOut * numberOfColumnsOut; // if (numberOfData <= 0) { // return false; // } // // /* // * Allocate rgba output // */ // const int32_t numberOfRgba = numberOfData * 4; // rgbaOut.resize(numberOfRgba); // // /* // * Get each column, color it using its label table, and then // * add the column's coloring into the output coloring. // */ // std::vector columnData(numberOfRowsOut); // std::vector columnRGBA(numberOfRowsOut * 4); // for (int32_t iCol = 0; iCol < numberOfColumnsOut; iCol++) { // CaretAssertVectorIndex(m_mapContent, iCol); // m_ciftiFile->getColumn(&columnData[0], // iCol); // const GiftiLabelTable* labelTable = getMapLabelTable(iCol); // NodeAndVoxelColoring::colorIndicesWithLabelTable(labelTable, // &columnData[0], // numberOfRowsOut, // &columnRGBA[0]); // // for (int32_t iRow = 0; iRow < numberOfRowsOut; iRow++) { // const int32_t rgbaOffset = (((iRow * numberOfColumnsOut) // + iCol) * 4); // CaretAssertVectorIndex(rgbaOut, rgbaOffset + 3); // const int32_t columnRgbaOffset = (iRow * 4); // CaretAssertVectorIndex(columnRGBA, columnRgbaOffset + 3); // rgbaOut[rgbaOffset] = columnRGBA[columnRgbaOffset]; // rgbaOut[rgbaOffset+1] = columnRGBA[columnRgbaOffset+1]; // rgbaOut[rgbaOffset+2] = columnRGBA[columnRgbaOffset+2]; // rgbaOut[rgbaOffset+3] = columnRGBA[columnRgbaOffset+3]; // } // } // // return true; } /** * Get the value, row name, and column name for a cell in the matrix. * * @param rowIndex * The row index. * @param columnIndex * The column index. * @param cellValueOut * Output containing value in the cell. * @param rowNameOut * Name of row corresponding to row index. * @param columnNameOut * Name of column corresponding to column index. * @return * True if the output values are valid (valid row/column indices). */ bool CiftiParcelLabelFile::getMatrixCellAttributes(const int32_t rowIndex, const int32_t columnIndex, AString& cellValueOut, AString& rowNameOut, AString& columnNameOut) const { if ((rowIndex >= 0) && (rowIndex < m_ciftiFile->getNumberOfRows()) && (columnIndex >= 0) && (columnIndex < m_ciftiFile->getNumberOfColumns())) { const CiftiXML& xml = m_ciftiFile->getCiftiXML(); const std::vector& rowsParcelsMap = xml.getParcelsMap(CiftiXML::ALONG_COLUMN).getParcels(); CaretAssertVectorIndex(rowsParcelsMap, rowIndex); rowNameOut = rowsParcelsMap[rowIndex].m_name; CaretAssertVectorIndex(m_mapContent, columnIndex); columnNameOut = getMapName(columnIndex); const int32_t numberOfElementsInRow = m_ciftiFile->getNumberOfColumns(); std::vector rowData(numberOfElementsInRow); m_ciftiFile->getRow(&rowData[0], rowIndex); CaretAssertVectorIndex(rowData, columnIndex); const int32_t labelKey = rowData[columnIndex]; const GiftiLabel* label = getMapLabelTable(columnIndex)->getLabel(labelKey); if (label != NULL) { cellValueOut = ("(key=" + AString::number(labelKey) + ")" + label->getName()); } else { cellValueOut = ("Invalid Key=" + AString::number(labelKey)); } return true; } return false; } /** * @return Is charting enabled for this file? */ bool CiftiParcelLabelFile::isMatrixChartingEnabled(const int32_t tabIndex) const { CaretAssertArrayIndex(m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_chartingEnabledForTab[tabIndex]; } /** * @return Return true if the file's current state supports * charting data, else false. Typically a brainordinate file * is chartable if it contains more than one map. */ bool CiftiParcelLabelFile::isMatrixChartingSupported() const { return true; } /** * Set charting enabled for this file. * * @param enabled * New status for charting enabled. */ void CiftiParcelLabelFile::setMatrixChartingEnabled(const int32_t tabIndex, const bool enabled) { CaretAssertArrayIndex(m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_chartingEnabledForTab[tabIndex] = enabled; } /** * Get chart data types supported by the file. * * @param chartDataTypesOut * Chart types supported by this file. */ void CiftiParcelLabelFile::getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const { chartDataTypesOut.clear(); chartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER); } /** * @return Chart matrix display properties (const method). */ const ChartMatrixDisplayProperties* CiftiParcelLabelFile::getChartMatrixDisplayProperties(const int32_t tabIndex) const { CaretAssertArrayIndex(m_chartMatrixDisplayProperties, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_chartMatrixDisplayProperties[tabIndex]; } /** * @return Chart matrix display properties. */ ChartMatrixDisplayProperties* CiftiParcelLabelFile::getChartMatrixDisplayProperties(const int32_t tabIndex) { CaretAssertArrayIndex(m_chartMatrixDisplayProperties, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_chartMatrixDisplayProperties[tabIndex]; } /** * Save file data from the scene. For subclasses that need to * save to a scene, this method should be overriden. sceneClass * will be valid and any scene data should be added to it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. */ void CiftiParcelLabelFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { CiftiMappableDataFile::saveFileDataToScene(sceneAttributes, sceneClass); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); sceneClass->addBooleanArray("m_chartingEnabledForTab", m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); /* * Save chart matrix properties */ SceneObjectMapIntegerKey* chartMatrixPropertiesMap = new SceneObjectMapIntegerKey("m_chartMatrixDisplayPropertiesMap", SceneObjectDataTypeEnum::SCENE_CLASS); const std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); for (std::vector::const_iterator tabIter = tabIndices.begin(); tabIter != tabIndices.end(); tabIter++) { const int32_t tabIndex = *tabIter; chartMatrixPropertiesMap->addClass(tabIndex, m_chartMatrixDisplayProperties[tabIndex]->saveToScene(sceneAttributes, "m_chartMatrixDisplayProperties")); } sceneClass->addChild(chartMatrixPropertiesMap); } /** * Restore file data from the scene. For subclasses that need to * restore from a scene, this method should be overridden. The scene class * will be valid and any scene data may be obtained from it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void CiftiParcelLabelFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { CiftiMappableDataFile::restoreFileDataFromScene(sceneAttributes, sceneClass); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = false; } const ScenePrimitiveArray* tabArray = sceneClass->getPrimitiveArray("m_chartingEnabledForTab"); if (tabArray != NULL) { sceneClass->getBooleanArrayValue("m_chartingEnabledForTab", m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); } else { /* * Obsolete value when charting was not 'per tab' */ const bool chartingEnabled = sceneClass->getBooleanValue("m_chartingEnabled", false); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = chartingEnabled; } } /* * Restore chart matrix properties */ const SceneObjectMapIntegerKey* chartMatrixPropertiesMap = sceneClass->getMapIntegerKey("m_chartMatrixDisplayPropertiesMap"); if (chartMatrixPropertiesMap != NULL) { const std::vector tabIndices = chartMatrixPropertiesMap->getKeys(); for (std::vector::const_iterator tabIter = tabIndices.begin(); tabIter != tabIndices.end(); tabIter++) { const int32_t tabIndex = *tabIter; const SceneClass* sceneClass = chartMatrixPropertiesMap->classValue(tabIndex); m_chartMatrixDisplayProperties[tabIndex]->restoreFromScene(sceneAttributes, sceneClass); } } } /** * @return Coloring mode for selected parcel. */ CiftiParcelColoringModeEnum::Enum CiftiParcelLabelFile::getSelectedParcelColoringMode() const { return m_selectedParcelColoringMode; } /** * Set the coloring mode for selected parcel. * * @param coloringMode * New value for coloring mode. */ void CiftiParcelLabelFile::setSelectedParcelColoringMode(const CiftiParcelColoringModeEnum::Enum coloringMode) { m_selectedParcelColoringMode = coloringMode; } /** * @return Color for selected parcel. */ CaretColorEnum::Enum CiftiParcelLabelFile::getSelectedParcelColor() const { return m_selectedParcelColor; } /** * Set color for selected parcel. * * @param color * New color for selected parcel. */ void CiftiParcelLabelFile::setSelectedParcelColor(const CaretColorEnum::Enum color) { m_selectedParcelColor = color; } /** * Get the selected parcel label file used for reordering of parcels. * * @param compatibleParcelLabelFilesOut * All Parcel Label files that are compatible with file implementing * this interface. * @param selectedParcelLabelFileOut * The selected parcel label file used for reordering the parcels. * May be NULL! * @param selectedParcelLabelFileMapIndexOut * Map index in the selected parcel label file. * @param enabledStatusOut * Enabled status of reordering. */ void CiftiParcelLabelFile::getSelectedParcelLabelFileAndMapForReordering(std::vector& compatibleParcelLabelFilesOut, CiftiParcelLabelFile* &selectedParcelLabelFileOut, int32_t& selectedParcelLabelFileMapIndexOut, bool& enabledStatusOut) const { m_parcelReorderingModel->getSelectedParcelLabelFileAndMapForReordering(compatibleParcelLabelFilesOut, selectedParcelLabelFileOut, selectedParcelLabelFileMapIndexOut, enabledStatusOut); } /** * Set the selected parcel label file used for reordering of parcels. * * @param selectedParcelLabelFile * The selected parcel label file used for reordering the parcels. * May be NULL! * @param selectedParcelLabelFileMapIndex * Map index in the selected parcel label file. * @param enabledStatus * Enabled status of reordering. */ void CiftiParcelLabelFile::setSelectedParcelLabelFileAndMapForReordering(CiftiParcelLabelFile* selectedParcelLabelFile, const int32_t selectedParcelLabelFileMapIndex, const bool enabledStatus) { m_parcelReorderingModel->setSelectedParcelLabelFileAndMapForReordering(selectedParcelLabelFile, selectedParcelLabelFileMapIndex, enabledStatus); } /** * Get the parcel reordering for the given map index that was created using * the given parcel label file and its map index. * * @param parcelLabelFile * The selected parcel label file used for reordering the parcels. * @param parcelLabelFileMapIndex * Map index in the selected parcel label file. * @return * Pointer to parcel reordering or NULL if not found. */ const CiftiParcelReordering* CiftiParcelLabelFile::getParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex) const { return m_parcelReorderingModel->getParcelReordering(parcelLabelFile, parcelLabelFileMapIndex); } /** * Create the parcel reordering for the given map index using * the given parcel label file and its map index. * * @param parcelLabelFile * The selected parcel label file used for reordering the parcels. * @param parcelLabelFileMapIndex * Map index in the selected parcel label file. * @param errorMessageOut * Error message output. Will only be non-empty if NULL is returned. * @return * Pointer to parcel reordering or NULL if not found. */ bool CiftiParcelLabelFile::createParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex, AString& errorMessageOut) { return m_parcelReorderingModel->createParcelReordering(parcelLabelFile, parcelLabelFileMapIndex, errorMessageOut); } /** * @return True if loading attributes (column/row, yoking) are * supported by this file type. */ bool CiftiParcelLabelFile::isSupportsLoadingAttributes() { return false; } /** * @return The matrix loading type (by row/column). */ ChartMatrixLoadingDimensionEnum::Enum CiftiParcelLabelFile::getMatrixLoadingDimension() const { /* * This file supports loading by column only ! */ return ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN; } /** * Set the matrix loading type (by row/column). * * @param matrixLoadingType * New value for matrix loading type. */ void CiftiParcelLabelFile::setMatrixLoadingDimension(const ChartMatrixLoadingDimensionEnum::Enum /* matrixLoadingType */) { CaretLogSevere("Attempting to change matrix loading type for a file that only supports loading by column"); } /** * @return Selected yoking group. */ YokingGroupEnum::Enum CiftiParcelLabelFile::getYokingGroup() const { /* not supported in this file */ return YokingGroupEnum::YOKING_GROUP_OFF; } /** * Set the selected yoking group. * * @param yokingGroup * New value for yoking group. */ void CiftiParcelLabelFile::setYokingGroup(const YokingGroupEnum::Enum /* yokingGroup */) { /* not supported in this file */ } /** * Reorder and map and return the matching parcel indices. * * @param mapIndex * Index of the map. * @param reorderedParcelIndicesOut * The parcel indices with reordering applied * @param errorMessageOut * Contains description of error. * @return * True if reordering successful, otherwise, false is returned * and errorMessageOut will contain a descrption of the error. */ bool CiftiParcelLabelFile::getReorderedParcelIndicesFromMap(const int32_t mapIndex, std::vector& reorderedParcelIndicesOut, AString& errorMessageOut) const { reorderedParcelIndicesOut.clear(); errorMessageOut.clear(); if ((mapIndex < 0) || (mapIndex >= getNumberOfMaps())) { errorMessageOut.appendWithNewLine("Invalid map index=" + AString::number(mapIndex)); } const int32_t numberOfRows = m_ciftiFile->getNumberOfRows(); if (numberOfRows <= 0) { errorMessageOut.appendWithNewLine("File contains no rows."); } if ( ! errorMessageOut.isEmpty()) { return false; } std::vector columnData(numberOfRows); m_ciftiFile->getColumn(&columnData[0], mapIndex); CaretLogFine("Column values size=" + AString::number(columnData.size()) + ": " + AString::fromNumbers(columnData, ",")); std::vector indexProcessed(numberOfRows, false); /* * Reorder row indices so that identical values are grouped together */ for (int32_t iRow = 0; iRow < numberOfRows; iRow++) { if ( ! indexProcessed[iRow]) { reorderedParcelIndicesOut.push_back(iRow); indexProcessed[iRow] = true; const int32_t valueI = columnData[iRow]; for (int32_t jRow = (iRow + 1); jRow < numberOfRows; jRow++) { if ( ! indexProcessed[jRow]) { if (valueI == static_cast(columnData[jRow])) { reorderedParcelIndicesOut.push_back(jRow); indexProcessed[jRow] = true; } } } } } if (reorderedParcelIndicesOut.empty()) { errorMessageOut.appendWithNewLine("No parcel indices for reordering."); return false; } CaretLogFine("Reordered parcel indices (not values!) size=" + AString::number(reorderedParcelIndicesOut.size()) + ": " + AString::fromNumbers(reorderedParcelIndicesOut, ",")); return true; } connectome-workbench-1.4.2/src/Files/CiftiParcelLabelFile.h000066400000000000000000000143461360521144700235720ustar00rootroot00000000000000#ifndef __CIFTI_PARCEL_LABEL_FILE_H__ #define __CIFTI_PARCEL_LABEL_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "CiftiMappableDataFile.h" #include "ChartableMatrixParcelInterface.h" namespace caret { class CiftiParcelReorderingModel; class SceneClassAssistant; class CiftiParcelLabelFile : public CiftiMappableDataFile, public ChartableMatrixParcelInterface { public: CiftiParcelLabelFile(); virtual ~CiftiParcelLabelFile(); virtual void getMatrixDimensions(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) const; virtual bool getMatrixDataRGBA(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut, std::vector& rgbaOut) const; virtual bool getMatrixCellAttributes(const int32_t rowIndex, const int32_t columnIndex, AString& cellValueOut, AString& rowNameOut, AString& columnNameOut) const; virtual bool isMatrixChartingEnabled(const int32_t tabIndex) const; virtual bool isMatrixChartingSupported() const; virtual void setMatrixChartingEnabled(const int32_t tabIndex, const bool enabled); virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const; const ChartMatrixDisplayProperties* getChartMatrixDisplayProperties(const int32_t tabIndex) const; ChartMatrixDisplayProperties* getChartMatrixDisplayProperties(const int32_t tabIndex); virtual CiftiParcelColoringModeEnum::Enum getSelectedParcelColoringMode() const; virtual void setSelectedParcelColoringMode(const CiftiParcelColoringModeEnum::Enum coloringMode); virtual CaretColorEnum::Enum getSelectedParcelColor() const; virtual void setSelectedParcelColor(const CaretColorEnum::Enum color); virtual void getSelectedParcelLabelFileAndMapForReordering(std::vector& compatibleParcelLabelFilesOut, CiftiParcelLabelFile* &selectedParcelLabelFileOut, int32_t& selectedParcelLabelFileMapIndexOut, bool& enabledStatusOut) const; virtual void setSelectedParcelLabelFileAndMapForReordering(CiftiParcelLabelFile* selectedParcelLabelFile, const int32_t selectedParcelLabelFileMapIndex, const bool enabledStatus); virtual bool createParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex, AString& errorMessageOut); virtual const CiftiParcelReordering* getParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex) const; virtual bool isSupportsLoadingAttributes(); virtual ChartMatrixLoadingDimensionEnum::Enum getMatrixLoadingDimension() const; virtual void setMatrixLoadingDimension(const ChartMatrixLoadingDimensionEnum::Enum matrixLoadingType); virtual YokingGroupEnum::Enum getYokingGroup() const; virtual void setYokingGroup(const YokingGroupEnum::Enum yokingType); bool getReorderedParcelIndicesFromMap(const int32_t mapIndex, std::vector& reorderedParcelIndicesOut, AString& errorMessageOut) const; // ADD_NEW_METHODS_HERE protected: virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: CiftiParcelLabelFile(const CiftiParcelLabelFile&); CiftiParcelLabelFile& operator=(const CiftiParcelLabelFile&); SceneClassAssistant* m_sceneAssistant; bool m_chartingEnabledForTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; ChartMatrixDisplayProperties* m_chartMatrixDisplayProperties[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; CiftiParcelColoringModeEnum::Enum m_selectedParcelColoringMode; CaretColorEnum::Enum m_selectedParcelColor; CiftiParcelReorderingModel* m_parcelReorderingModel; // ADD_NEW_MEMBERS_HERE }; #ifdef __CIFTI_PARCEL_LABEL_FILE_DECLARE__ // #endif // __CIFTI_PARCEL_LABEL_FILE_DECLARE__ } // namespace #endif //__CIFTI_PARCEL_LABEL_FILE_H__ connectome-workbench-1.4.2/src/Files/CiftiParcelReordering.cxx000066400000000000000000000426111360521144700244220ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CIFTI_PARCEL_REORDERING_DECLARE__ #include "CiftiParcelReordering.h" #undef __CIFTI_PARCEL_REORDERING_DECLARE__ #include "CaretAssert.h" #include "CiftiParcelLabelFile.h" #include "CiftiParcelsMap.h" #include "ElapsedTimer.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "SceneClass.h" #include "ScenePrimitiveArray.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::CiftiParcelReordering * \brief Contains a parcel reordering. * \ingroup Files */ /** * Constructs an invalid instance. */ CiftiParcelReordering::CiftiParcelReordering() : CaretObject() { m_sourceParcelLabelFile = NULL; m_sourceParcelLabelFileMapIndex = -1; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_sourceParcelLabelFileMapIndex", &m_sourceParcelLabelFileMapIndex); } /** * Destructor. */ CiftiParcelReordering::~CiftiParcelReordering() { delete m_sceneAssistant; } /** * Copy constructor. * @param obj * Object that is copied. */ CiftiParcelReordering::CiftiParcelReordering(const CiftiParcelReordering& obj) : CaretObject(obj), SceneableInterface(obj) { this->copyHelperCiftiParcelReordering(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ CiftiParcelReordering& CiftiParcelReordering::operator=(const CiftiParcelReordering& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperCiftiParcelReordering(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void CiftiParcelReordering::copyHelperCiftiParcelReordering(const CiftiParcelReordering& obj) { m_sourceParcelLabelFile = obj.m_sourceParcelLabelFile; m_sourceParcelLabelFileMapIndex = obj.m_sourceParcelLabelFileMapIndex; m_reorderedParcelIndices = obj.m_reorderedParcelIndices; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString CiftiParcelReordering::toString() const { return "CiftiParcelReordering"; } /** * Equality operator that compares this instance to another instance. * * @param parcelReordering * Compared to "this" * @return * True if this instance and the other instance are "equal", else false. */ bool CiftiParcelReordering::operator==(const CiftiParcelReordering& obj) const { if ((m_sourceParcelLabelFile == obj.m_sourceParcelLabelFile) && (m_sourceParcelLabelFileMapIndex == obj.m_sourceParcelLabelFileMapIndex)) { return true; } return false; } /** * Does this parcel reordering key match? * * @param sourceParcelLabelFile * The source parcel label file for the reordering. * @param sourceParcelLabelFileMapIndex * The map index from the source parcel map file. * @return * True if this parcel reordering is for the given file and map indices, * else false. */ bool CiftiParcelReordering::isMatch(const CiftiParcelLabelFile* sourceParcelLabelFile, const int32_t sourceParcelLabelFileMapIndex) const { if ((sourceParcelLabelFile == m_sourceParcelLabelFile) && (sourceParcelLabelFileMapIndex == m_sourceParcelLabelFileMapIndex)) { return true; } return false; } /** * @ Is this parcel reordering valid? */ bool CiftiParcelReordering::isValid() const { if (m_reorderedParcelIndices.empty()) { return false; } return true; } ///** // * Create the parcel reordering. // * // * @param sourceParcelLabelFile // * Parcel label file used to create the reordering // * @param sourceParcelLabelFileMapIndex // * Index of map in parcel label file used to create reordering // * @param targetParcelsMap // * Parcels map for which a reordering is created. // * @param errorMessageOut // * Error message if there was a problem creating the // * reordering. // * @return // * True if the reordering was successfully created, else false. // */ //bool //CiftiParcelReordering::createReordering(const CiftiParcelLabelFile* sourceParcelLabelFile, // const int32_t sourceParcelLabelFileMapIndex, // const CiftiParcelsMap& targetParcelsMap, // AString& errorMessageOut) //{ // m_reorderedParcelIndices.clear(); // // errorMessageOut = ""; // // if (sourceParcelLabelFile != NULL) { // if ((sourceParcelLabelFileMapIndex < 0) // || (sourceParcelLabelFileMapIndex >= sourceParcelLabelFile->getNumberOfMaps())) { // errorMessageOut.appendWithNewLine("Source Parcel Label File map index=" // + AString::number(sourceParcelLabelFileMapIndex) // + " is invalid."); // } // } // else { // errorMessageOut.appendWithNewLine("Source Parcel Label File is invalid."); // } // // /* // * The target parcels are those whose indices will be reordered // */ // const std::vector& allTargetParcels = targetParcelsMap.getParcels(); // const int32_t numTargetParcels = static_cast(allTargetParcels.size()); // if (numTargetParcels <= 0) { // errorMessageOut.appendWithNewLine("Parcels map that is to be reordered is empty."); // } // // /* // * These source parcels are those used to create the reordering // */ // const CiftiParcelsMap* sourceParcelsMap = sourceParcelLabelFile->getCiftiParcelsMapForBrainordinateMapping(); // CaretAssert(sourceParcelsMap); // const std::vector& allSourceParcels = sourceParcelsMap->getParcels(); // const int32_t numSourceParcels = static_cast(allSourceParcels.size()); // if (numSourceParcels <= 0) { // errorMessageOut.appendWithNewLine("Parcels map from that Parcel Label File is used to reorder the parcels is empty."); // } // // if ( ! errorMessageOut.isEmpty()) { // return false; // } // // /* // * Tracks parcels that are in the reordering so that they can be // * skipped and save time by avoiding parcel comparisons // */ // std::vector targetParcelRemapped(numTargetParcels, // false); // // /* // * Loop through the source parcels used to create the reordering // */ // for (int32_t iSource = 0; // iSource < numSourceParcels; // iSource++) { // CaretAssertVectorIndex(allSourceParcels, // iSource); // const CiftiParcelsMap::Parcel& sourceParcel = allSourceParcels[iSource]; // // /* // * Loop through target parcels to find those that // * have the exact same mapping by using the // * parcel equality operator. // */ // for (int32_t iTarget = 0; // iTarget < numTargetParcels; // iTarget++) { // CaretAssertVectorIndex(targetParcelRemapped, iTarget); // if ( ! targetParcelRemapped[iTarget]) { // CaretAssertVectorIndex(allTargetParcels, iTarget); // if (allTargetParcels[iTarget] == sourceParcel) { // m_reorderedParcelIndices.push_back(iTarget); // // targetParcelRemapped[iTarget] = true; // } // } // } // } // // if (m_reorderedParcelIndices.empty()) { // return false; // } // // m_sourceParcelLabelFile = const_cast(sourceParcelLabelFile); // m_sourceParcelLabelFileMapIndex = sourceParcelLabelFileMapIndex; // // std::cout << "New parcel reorder: "; // for (std::vector::iterator iter = m_reorderedParcelIndices.begin(); // iter != m_reorderedParcelIndices.end(); // iter++) { // std::cout << " " << *iter; // } // std::cout << std::endl; // // return true; //} /** * Create the parcel reordering. * * @param sourceParcelLabelFile * Parcel label file used to create the reordering * @param sourceParcelLabelFileMapIndex * Index of map in parcel label file used to create reordering * @param targetParcelsMap * Parcels map for which a reordering is created. * @param errorMessageOut * Error message if there was a problem creating the * reordering. * @return * True if the reordering was successfully created, else false. */ bool CiftiParcelReordering::createReordering(const CiftiParcelLabelFile* sourceParcelLabelFile, const int32_t sourceParcelLabelFileMapIndex, const CiftiParcelsMap& targetParcelsMap, AString& errorMessageOut) { ElapsedTimer timer; timer.start(); m_reorderedParcelIndices.clear(); errorMessageOut = ""; if (sourceParcelLabelFile != NULL) { if ((sourceParcelLabelFileMapIndex < 0) || (sourceParcelLabelFileMapIndex >= sourceParcelLabelFile->getNumberOfMaps())) { errorMessageOut.appendWithNewLine("Source Parcel Label File map index=" + AString::number(sourceParcelLabelFileMapIndex) + " is invalid."); } } else { errorMessageOut.appendWithNewLine("Source Parcel Label File is invalid."); } /* * The target parcels are those whose indices will be reordered */ const std::vector& allTargetParcels = targetParcelsMap.getParcels(); const int32_t numTargetParcels = static_cast(allTargetParcels.size()); if (numTargetParcels <= 0) { errorMessageOut.appendWithNewLine("Parcels map that is to be reordered is empty."); } /* * These source's parcels map. */ const CiftiParcelsMap* sourceParcelsMap = sourceParcelLabelFile->getCiftiParcelsMapForBrainordinateMapping(); if (sourceParcelsMap == NULL) { errorMessageOut.appendWithNewLine("No parcels map in source Parcel Label File."); } if ( ! errorMessageOut.isEmpty()) { return false; } /* * Reorder the indices for the Parcels Map in the selected map * of the Parcel Labels File. */ std::vector reorderedSourceParcelIndices; if ( ! sourceParcelLabelFile->getReorderedParcelIndicesFromMap(sourceParcelLabelFileMapIndex, reorderedSourceParcelIndices, errorMessageOut)) { return false; } const std::vector& allSourceParcels = sourceParcelsMap->getParcels(); const int32_t numberOfSourceParcels = static_cast(allSourceParcels.size()); if (numberOfSourceParcels <= 0) { errorMessageOut.appendWithNewLine("No parcels in source Parcel Label File."); return false; } /* * One a target parcel is remapped, it no never needs to * be tested again. */ std::vector targetParcelRemapped(numTargetParcels, false); /* * Loop through the source parcels used to create the reordering */ const int32_t numReorderedSourceParcelIndices = static_cast(reorderedSourceParcelIndices.size()); for (int32_t iSource = 0; iSource < numReorderedSourceParcelIndices; iSource++) { CaretAssertVectorIndex(reorderedSourceParcelIndices, iSource); const int32_t sourceParcelIndex = reorderedSourceParcelIndices[iSource]; CaretAssertVectorIndex(allSourceParcels, sourceParcelIndex); const CiftiParcelsMap::Parcel& sourceParcel = allSourceParcels[sourceParcelIndex]; /* * Loop through target parcels to find those that * have the exact same mapping by using the * parcel's approximate match method which * compares the brainordinate mapping of the parcels. */ for (int32_t iTarget = 0; iTarget < numTargetParcels; iTarget++) { CaretAssertVectorIndex(targetParcelRemapped, iTarget); if ( ! targetParcelRemapped[iTarget]) { CaretAssertVectorIndex(allTargetParcels, iTarget); if (allTargetParcels[iTarget].approximateMatch(sourceParcel)) { m_reorderedParcelIndices.push_back(iTarget); targetParcelRemapped[iTarget] = true; } } } } const int32_t matchCount = std::count(targetParcelRemapped.begin(), targetParcelRemapped.end(), true); const int32_t notMatchCount = numTargetParcels - matchCount; if (notMatchCount > 0) { errorMessageOut.appendWithNewLine("Failed to match " + AString::number(notMatchCount) + " of " + AString::number(numTargetParcels)); return false; } //std::cout << "Time to match parcels was: " << timer.getElapsedTimeSeconds() << " seconds." << std::endl; m_sourceParcelLabelFile = const_cast(sourceParcelLabelFile); m_sourceParcelLabelFileMapIndex = sourceParcelLabelFileMapIndex; return true; } /** * @return The reordered indices of the parcels. */ std::vector CiftiParcelReordering::getReorderedParcelIndices() const { return m_reorderedParcelIndices; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* CiftiParcelReordering::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "CiftiParcelReordering", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); if (m_sourceParcelLabelFile != NULL) { sceneClass->addPathName("m_sourceParcelLabelFile", m_sourceParcelLabelFile->getFileName()); if ( ! m_reorderedParcelIndices.empty()) { sceneClass->addIntegerArray("m_reorderedParcelIndices", &m_reorderedParcelIndices[0], m_reorderedParcelIndices.size()); } } // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void CiftiParcelReordering::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sourceParcelLabelFile = NULL; m_reorderedParcelIndices.clear(); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); const ScenePathName* parcelLabelPathName = sceneClass->getPathName("m_sourceParcelLabelFile"); if (parcelLabelPathName != NULL) { } const ScenePrimitiveArray* reorderArray = sceneClass->getPrimitiveArray("m_reorderedParcelIndices"); if (reorderArray != NULL) { const int32_t numberOfElements = reorderArray->getNumberOfArrayElements(); if (numberOfElements > 0) { m_reorderedParcelIndices.reserve(numberOfElements); for (int32_t i = 0; i < numberOfElements; i++) { m_reorderedParcelIndices.push_back(reorderArray->integerValue(i)); } } } //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Files/CiftiParcelReordering.h000066400000000000000000000075101360521144700240460ustar00rootroot00000000000000#ifndef __CIFTI_PARCEL_REORDERING_H__ #define __CIFTI_PARCEL_REORDERING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "SceneableInterface.h" namespace caret { class CiftiParcelLabelFile; class CiftiParcelsMap; class SceneClassAssistant; class CiftiParcelReordering : public CaretObject, public SceneableInterface { public: CiftiParcelReordering(); virtual ~CiftiParcelReordering(); CiftiParcelReordering(const CiftiParcelReordering& obj); CiftiParcelReordering& operator=(const CiftiParcelReordering& obj); bool operator==(const CiftiParcelReordering& obj) const; bool isValid() const; bool isMatch(const CiftiParcelLabelFile* sourceParcelLabelFile, const int32_t sourceParcelLabelFileMapIndex) const; bool createReordering(const CiftiParcelLabelFile* sourceParcelLabelFile, const int32_t sourceParcelLabelFileMapIndex, const CiftiParcelsMap& targetParcelsMap, AString& errorMessageOut); std::vector getReorderedParcelIndices() const; // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implemetation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: void copyHelperCiftiParcelReordering(const CiftiParcelReordering& obj); SceneClassAssistant* m_sceneAssistant; /** * Parcel label file used to create the reordering */ CiftiParcelLabelFile* m_sourceParcelLabelFile; /** * Index of map in parcel label file used to create reordering */ int32_t m_sourceParcelLabelFileMapIndex; /** * Reordered parcel indices in data file that has its parcel's * reordered. */ std::vector m_reorderedParcelIndices; // ADD_NEW_MEMBERS_HERE }; #ifdef __CIFTI_PARCEL_REORDERING_DECLARE__ // #endif // __CIFTI_PARCEL_REORDERING_DECLARE__ } // namespace #endif //__CIFTI_PARCEL_REORDERING_H__ connectome-workbench-1.4.2/src/Files/CiftiParcelReorderingModel.cxx000066400000000000000000000471021360521144700254030ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CIFTI_PARCEL_REORDERING_MODEL_DECLARE__ #include "CiftiParcelReorderingModel.h" #undef __CIFTI_PARCEL_REORDERING_MODEL_DECLARE__ #include "CaretAssert.h" #include "CiftiMappableDataFile.h" #include "CiftiParcelLabelFile.h" #include "CiftiParcelReordering.h" #include "CiftiParcelsMap.h" #include "CiftiXML.h" #include "EventCaretMappableDataFilesGet.h" #include "EventManager.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "ScenePathName.h" using namespace caret; /** * \class caret::CiftiParcelReorderingModel * \brief Controls reordering of parcels for a CIFTI data file. * \ingroup Files */ /** * Constructor. */ CiftiParcelReorderingModel::CiftiParcelReorderingModel(const CiftiMappableDataFile* parentCiftiMappableDataFile) : CaretObject(), m_parentCiftiMappableDataFile(parentCiftiMappableDataFile) { CaretAssert(parentCiftiMappableDataFile); switch (parentCiftiMappableDataFile->getDataFileType()) { case DataFileTypeEnum::CONNECTIVITY_PARCEL: case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: break; default: CaretAssert(0); } m_parcelReorderingEnabledStatus = false; m_selectedParcelLabelFile = NULL; m_selectedParcelLabelFileMapIndex = -1; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_selectedParcelLabelFileMapIndex", &m_selectedParcelLabelFileMapIndex); m_sceneAssistant->add("m_parcelReorderingEnabledStatus", &m_parcelReorderingEnabledStatus); } /** * Destructor. */ CiftiParcelReorderingModel::~CiftiParcelReorderingModel() { delete m_sceneAssistant; clearCiftiParcelReordering(); } /** * Clear all parcel reordering. */ void CiftiParcelReorderingModel::clearCiftiParcelReordering() { for (std::vector::iterator iter = m_parcelReordering.begin(); iter != m_parcelReordering.end(); iter++) { delete *iter; } m_parcelReordering.clear(); } /** * Copy constructor. * @param obj * Object that is copied. */ CiftiParcelReorderingModel::CiftiParcelReorderingModel(const CiftiParcelReorderingModel& obj) : CaretObject(obj), SceneableInterface(obj) { this->copyHelperCiftiParcelReorderingModel(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ CiftiParcelReorderingModel& CiftiParcelReorderingModel::operator=(const CiftiParcelReorderingModel& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperCiftiParcelReorderingModel(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void CiftiParcelReorderingModel::copyHelperCiftiParcelReorderingModel(const CiftiParcelReorderingModel& obj) { std::vector compatibleParcelLabelFiles; CiftiParcelLabelFile* selectedParcelLabelFile; int32_t selectedParcelLabelFileMapIndex; bool enabledStatus; obj.getSelectedParcelLabelFileAndMapForReordering(compatibleParcelLabelFiles, selectedParcelLabelFile, selectedParcelLabelFileMapIndex, enabledStatus); setSelectedParcelLabelFileAndMapForReordering(selectedParcelLabelFile, selectedParcelLabelFileMapIndex, enabledStatus); } /** * (1) Since the user may load/unload files at will, any current * selection requests will need to validate against available * parcel label files. * * (2) The parcel label files must test for compatibility by * matching their CiftiParcelMaps. * * @return Parcel label files that contain at least one map and * contain compatible CiftiParcelMaps. */ std::vector CiftiParcelReorderingModel::getParcelLabelFiles() const { EventCaretMappableDataFilesGet parcelLabelFilesEvent(DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL); EventManager::get()->sendEvent(parcelLabelFilesEvent.getPointer()); std::vector mappableFiles; parcelLabelFilesEvent.getAllFiles(mappableFiles); std::vector parcelLabelFiles; for (std::vector::iterator iter = mappableFiles.begin(); iter != mappableFiles.end(); iter++) { CaretMappableDataFile* cmdf = *iter; if (cmdf->getNumberOfMaps() > 0) { CiftiParcelLabelFile* parcelLabelFile = dynamic_cast(*iter); CaretAssert(parcelLabelFile); std::map::iterator fileStatusIter = m_parcelLabelFileCompatibilityStatus.find(parcelLabelFile); if (fileStatusIter != m_parcelLabelFileCompatibilityStatus.end()) { const bool compatibleFlag = fileStatusIter->second; if (compatibleFlag) { /* * File was previously verified for parcel compatibility. */ parcelLabelFiles.push_back(parcelLabelFile); } } else { const CiftiParcelsMap* parcelsMap = parcelLabelFile->getCiftiParcelsMapForDirection(CiftiXML::ALONG_COLUMN); CaretAssert(parcelsMap); bool testAlongRow = false; bool testAlongColumn = false; switch (m_parentCiftiMappableDataFile->getDataFileType()) { case DataFileTypeEnum::CONNECTIVITY_PARCEL: testAlongColumn = true; testAlongRow = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: testAlongColumn = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: testAlongColumn = true; break; default: CaretAssert(0); } int32_t passCount = 0; int32_t failCount = 0; if (testAlongColumn) { if (m_parentCiftiMappableDataFile->getCiftiParcelsMapForDirection(CiftiXML::ALONG_COLUMN)->approximateMatch(*parcelsMap)) { ++passCount; } else { ++failCount; } } if (testAlongRow) { if (m_parentCiftiMappableDataFile->getCiftiParcelsMapForDirection(CiftiXML::ALONG_ROW)->approximateMatch(*parcelsMap)) { ++passCount; } else { ++failCount; } } bool compatibleFlag = false; if ((passCount > 0) && (failCount <= 0)) { parcelLabelFiles.push_back(parcelLabelFile); /* * NOTE: Since file was found to be compatible it will * always be compatible. */ compatibleFlag = true; } /* * NOTE: Compatiblity status will never change so cache it * to avoid retesting. */ m_parcelLabelFileCompatibilityStatus.insert(std::make_pair(parcelLabelFile, compatibleFlag)); } } } return parcelLabelFiles; } /** * Validate the selected parcel label file and map. * * @param optionalParcelLabelFilesOut * If not NULL, the matching parcel labels files are inserted into this. */ void CiftiParcelReorderingModel::validateSelectedParcelLabelFileAndMap(std::vector* optionalParcelLabelFilesOut) const { std::vector parcelLabelFiles = getParcelLabelFiles(); bool foundFile = false; for (std::vector::iterator iter = parcelLabelFiles.begin(); iter != parcelLabelFiles.end(); iter++) { CiftiParcelLabelFile* plf = *iter; if (m_selectedParcelLabelFile != NULL) { if (m_selectedParcelLabelFile == plf) { foundFile = true; break; } } } if (foundFile) { const int32_t numMaps = m_selectedParcelLabelFile->getNumberOfMaps(); if (m_selectedParcelLabelFileMapIndex >= numMaps) { m_selectedParcelLabelFileMapIndex = numMaps - 1; } else if (m_selectedParcelLabelFileMapIndex < 0) { m_selectedParcelLabelFileMapIndex = 0; } } if ( ! foundFile) { if ( ! parcelLabelFiles.empty()) { m_selectedParcelLabelFile = parcelLabelFiles[0]; m_selectedParcelLabelFileMapIndex = 0; } else { m_selectedParcelLabelFile = NULL; m_selectedParcelLabelFileMapIndex = -1; m_parcelReorderingEnabledStatus = false; } } if (optionalParcelLabelFilesOut != NULL) { *optionalParcelLabelFilesOut = parcelLabelFiles; } } /** * Get a description of this object's content. * @return String describing this object's content. */ AString CiftiParcelReorderingModel::toString() const { return "CiftiParcelReorderingModel"; } /** * Get the selected parcel label file used for reordering of parcels. * * @param parcelLabelFilesOut * The compatible parcel label files. * @param selectedParcelLabelFileOut * The selected parcel label file used for reordering the parcels. * May be NULL! * @param selectedParcelLabelFileMapIndexOut * Map index in the selected parcel label file. * @param enabledStatusOut * Enabled status of reordering. */ void CiftiParcelReorderingModel::getSelectedParcelLabelFileAndMapForReordering(std::vector& parcelLabelFilesOut, CiftiParcelLabelFile* &selectedParcelLabelFileOut, int32_t& selectedParcelLabelFileMapIndexOut, bool& enabledStatusOut) const { validateSelectedParcelLabelFileAndMap(&parcelLabelFilesOut); selectedParcelLabelFileOut = m_selectedParcelLabelFile; selectedParcelLabelFileMapIndexOut = m_selectedParcelLabelFileMapIndex; enabledStatusOut = m_parcelReorderingEnabledStatus; } /** * Set the selected parcel label file used for reordering of parcels. * * @param selectedParcelLabelFile * The selected parcel label file used for reordering the parcels. * May be NULL! * @param selectedParcelLabelFileMapIndex * Map index in the selected parcel label file. * @param enabledStatus * Enabled status of reordering. */ void CiftiParcelReorderingModel::setSelectedParcelLabelFileAndMapForReordering(CiftiParcelLabelFile* selectedParcelLabelFile, const int32_t selectedParcelLabelFileMapIndex, const bool enabledStatus) { m_selectedParcelLabelFile = selectedParcelLabelFile; m_selectedParcelLabelFileMapIndex = selectedParcelLabelFileMapIndex; m_parcelReorderingEnabledStatus = enabledStatus; } /** * Get the parcel reordering for the given map index that was created using * the given parcel label file and its map index. * * @param parcelLabelFile * The selected parcel label file used for reordering the parcels. * @param parcelLabelFileMapIndex * Map index in the selected parcel label file. * @return * Pointer to parcel reordering or NULL if not found. */ const CiftiParcelReordering* CiftiParcelReorderingModel::getParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex) const { for (std::vector::const_iterator iter = m_parcelReordering.begin(); iter != m_parcelReordering.end(); iter++) { const CiftiParcelReordering* parcelReordering = *iter; if (parcelReordering->isMatch(parcelLabelFile, parcelLabelFileMapIndex)) { return parcelReordering; } } return NULL; } /** * Get the parcel reordering for the given map index that was created using * the given parcel label file and its map index. * * @param parcelLabelFile * The selected parcel label file used for reordering the parcels. * @param parcelLabelFileMapIndex * Map index in the selected parcel label file. * @return * Pointer to parcel reordering or NULL if not found. */ CiftiParcelReordering* CiftiParcelReorderingModel::getParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex) { for (std::vector::iterator iter = m_parcelReordering.begin(); iter != m_parcelReordering.end(); iter++) { CiftiParcelReordering* parcelReordering = *iter; if (parcelReordering->isMatch(parcelLabelFile, parcelLabelFileMapIndex)) { return parcelReordering; } } return NULL; } /** * Create the parcel reordering for the parent file's parcels map index using * the given parcel label file and its map index. * * @param parcelLabelFile * The selected parcel label file used for reordering the parcels. * @param parcelLabelFileMapIndex * Map index in the selected parcel label file. * @param errorMessageOut * Error message output. Will only be non-empty if NULL is returned. * @return * Pointer to parcel reordering or NULL if not found. */ bool CiftiParcelReorderingModel::createParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex, AString& errorMessageOut) { if (getParcelReordering(parcelLabelFile, parcelLabelFileMapIndex) != NULL) { return true; } const CiftiParcelsMap* ciftiParcelsMap = m_parentCiftiMappableDataFile->getCiftiParcelsMapForBrainordinateMapping(); CaretAssert(ciftiParcelsMap); CiftiParcelReordering* parcelReordering = new CiftiParcelReordering(); if (parcelReordering->createReordering(parcelLabelFile, parcelLabelFileMapIndex, *ciftiParcelsMap, errorMessageOut)) { m_parcelReordering.push_back(parcelReordering); return true; } return false; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* CiftiParcelReorderingModel::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { validateSelectedParcelLabelFileAndMap(NULL); SceneClass* sceneClass = new SceneClass(instanceName, "CiftiParcelReorderingModel", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); if (m_selectedParcelLabelFile != NULL) { sceneClass->addPathName("m_selectedParcelLabelFile", m_selectedParcelLabelFile->getFileName()); } /* * NOTE: the parcel reorderings are not saved to the scene. * When the scene is restored, a parcel reordering is created * for the restored parcel label file and map index. */ // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void CiftiParcelReorderingModel::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); m_selectedParcelLabelFile = NULL; clearCiftiParcelReordering(); const AString parcelLabelFileName = sceneClass->getPathNameValue("m_selectedParcelLabelFile"); if ( ! parcelLabelFileName.isEmpty()) { std::vector parcelLabelFiles = getParcelLabelFiles(); for (std::vector::iterator iter = parcelLabelFiles.begin(); iter != parcelLabelFiles.end(); iter++) { CiftiParcelLabelFile* plf = *iter; if (plf->getFileName() == parcelLabelFileName) { m_selectedParcelLabelFile = plf; break; } } } validateSelectedParcelLabelFileAndMap(NULL); /* * If there is a valid selected parcel label file, * create the reordering for it. */ if (m_selectedParcelLabelFile != NULL) { if (m_selectedParcelLabelFileMapIndex >= 0) { AString errorMessage; if ( ! createParcelReordering(m_selectedParcelLabelFile, m_selectedParcelLabelFileMapIndex, errorMessage)) { sceneAttributes->addToErrorMessage(errorMessage); } } } //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Files/CiftiParcelReorderingModel.h000066400000000000000000000117721360521144700250340ustar00rootroot00000000000000#ifndef __CIFTI_PARCEL_REORDERING_MODEL_H__ #define __CIFTI_PARCEL_REORDERING_MODEL_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "SceneableInterface.h" namespace caret { class CiftiMappableDataFile; class CiftiParcelLabelFile; class CiftiParcelReordering; class CiftiParcelsMap; class SceneClassAssistant; class CiftiParcelReorderingModel : public CaretObject, public SceneableInterface { public: CiftiParcelReorderingModel(const CiftiMappableDataFile* ciftiMappableDataFile); virtual ~CiftiParcelReorderingModel(); CiftiParcelReorderingModel(const CiftiParcelReorderingModel& obj); CiftiParcelReorderingModel& operator=(const CiftiParcelReorderingModel& obj); void getSelectedParcelLabelFileAndMapForReordering(std::vector& parcelLabelFilesOut, CiftiParcelLabelFile* &selectedParcelLabelFileOut, int32_t& selectedParcelLabelFileMapIndexOut, bool& enabledStatusOut) const; void setSelectedParcelLabelFileAndMapForReordering(CiftiParcelLabelFile* selectedParcelLabelFile, const int32_t selectedParcelLabelFileMapIndex, const bool enabledStatus); bool createParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex, AString& errorMessageOut); const CiftiParcelReordering* getParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex) const; CiftiParcelReordering* getParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex); // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implemetation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: void copyHelperCiftiParcelReorderingModel(const CiftiParcelReorderingModel& obj); void validateSelectedParcelLabelFileAndMap(std::vector* optionalParcelLabelFilesOut) const; std::vector getParcelLabelFiles() const; void clearCiftiParcelReordering(); mutable std::map m_parcelLabelFileCompatibilityStatus; const CiftiMappableDataFile* m_parentCiftiMappableDataFile; SceneClassAssistant* m_sceneAssistant; std::vector m_parcelReordering; mutable CiftiParcelLabelFile* m_selectedParcelLabelFile; mutable int32_t m_selectedParcelLabelFileMapIndex; mutable bool m_parcelReorderingEnabledStatus; // ADD_NEW_MEMBERS_HERE }; #ifdef __CIFTI_PARCEL_REORDERING_MODEL_DECLARE__ // #endif // __CIFTI_PARCEL_REORDERING_MODEL_DECLARE__ } // namespace #endif //__CIFTI_PARCEL_REORDERING_MODEL_H__ connectome-workbench-1.4.2/src/Files/CiftiParcelScalarFile.cxx000066400000000000000000000612561360521144700243350ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CIFTI_PARCEL_SCALAR_FILE_DECLARE__ #include "CiftiParcelScalarFile.h" #undef __CIFTI_PARCEL_SCALAR_FILE_DECLARE__ #include "CaretLogger.h" #include "ChartDataCartesian.h" #include "ChartMatrixDisplayProperties.h" #include "CiftiFile.h" #include "CiftiParcelReordering.h" #include "CiftiParcelReorderingModel.h" #include "CiftiXML.h" #include "FastStatistics.h" #include "NodeAndVoxelColoring.h" #include "Palette.h" #include "PaletteColorMapping.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::CiftiParcelScalarFile * \brief CIFTI Parcel by Scalar File * \ingroup Files * */ /** * Constructor. */ CiftiParcelScalarFile::CiftiParcelScalarFile() : CiftiMappableDataFile(DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR) { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_brainordinateChartingEnabledForTab[i] = false; m_matrixChartingEnabledForTab[i] = false; m_chartMatrixDisplayProperties[i] = new ChartMatrixDisplayProperties(); } m_selectedParcelColoringMode = CiftiParcelColoringModeEnum::CIFTI_PARCEL_COLORING_OUTLINE; m_selectedParcelColor = CaretColorEnum::WHITE; m_parcelReorderingModel = new CiftiParcelReorderingModel(this); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_selectedParcelColoringMode", &m_selectedParcelColoringMode); m_sceneAssistant->add("m_selectedParcelColor", &m_selectedParcelColor); m_sceneAssistant->add("m_parcelReorderingModel", "CiftiParcelReorderingModel", m_parcelReorderingModel); } /** * Destructor. */ CiftiParcelScalarFile::~CiftiParcelScalarFile() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { delete m_chartMatrixDisplayProperties[i]; } delete m_parcelReorderingModel; delete m_sceneAssistant; } /** * @return Is charting enabled for this file? */ bool CiftiParcelScalarFile::isLineSeriesChartingEnabled(const int32_t tabIndex) const { CaretAssertArrayIndex(m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_brainordinateChartingEnabledForTab[tabIndex]; } /** * @return Return true if the file's current state supports * charting data, else false. Typically a brainordinate file * is chartable if it contains more than one map. */ bool CiftiParcelScalarFile::isLineSeriesChartingSupported() const { if (getNumberOfMaps() > 1) { return true; } return false; } /** * Get chart data types supported by the file. * * @param chartDataTypesOut * Chart types supported by this file. */ void CiftiParcelScalarFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { helpGetSupportedLineSeriesChartDataTypes(chartDataTypesOut); } /** * Set charting enabled for this file. * * @param enabled * New status for charting enabled. */ void CiftiParcelScalarFile::setLineSeriesChartingEnabled(const int32_t tabIndex, const bool enabled) { CaretAssertArrayIndex(m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_brainordinateChartingEnabledForTab[tabIndex] = enabled; } /** * Load charting data for the surface with the given structure and node index. * * @param structure * The surface's structure. * @param nodeIndex * Index of the node. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will return true. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* CiftiParcelScalarFile::loadLineSeriesChartDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t nodeIndex) { ChartDataCartesian* chartData = helpLoadChartDataForSurfaceNode(structure, nodeIndex); return chartData; } /** * Load average charting data for the surface with the given structure and node indices. * * @param structure * The surface's structure. * @param nodeIndices * Indices of the node. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* CiftiParcelScalarFile::loadAverageLineSeriesChartDataForSurfaceNodes(const StructureEnum::Enum structure, const std::vector& nodeIndices) { ChartDataCartesian* chartData = helpLoadChartDataForSurfaceNodeAverage(structure, nodeIndices); return chartData; } /** * Load charting data for the voxel enclosing the given coordinate. * * @param xyz * Coordinate of voxel. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* CiftiParcelScalarFile::loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]) { ChartDataCartesian* chartData = helpLoadChartDataForVoxelAtCoordinate(xyz); return chartData; } /** * Get the matrix dimensions. * * @param numberOfRowsOut * Number of rows in the matrix. * @param numberOfColumnsOut * Number of rows in the matrix. */ void CiftiParcelScalarFile::getMatrixDimensions(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) const { helpMapFileGetMatrixDimensions(numberOfRowsOut, numberOfColumnsOut); } /** * Get the matrix RGBA coloring for this matrix data creator. * * @param numberOfRowsOut * Number of rows in the coloring matrix. * @param numberOfColumnsOut * Number of rows in the coloring matrix. * @param rgbaOut * RGBA coloring output with number of elements * (numberOfRowsOut * numberOfColumnsOut * 4). * @return * True if data output data is valid, else false. */ bool CiftiParcelScalarFile::getMatrixDataRGBA(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut, std::vector& rgbaOut) const { CiftiParcelLabelFile* parcelLabelFile = NULL; int32_t parcelLabelFileMapIndex = -1; bool enabled = false; std::vector parcelLabelFiles; getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, parcelLabelFile, parcelLabelFileMapIndex, enabled); std::vector rowIndices; if (enabled) { const CiftiParcelReordering* parcelReordering = getParcelReordering(parcelLabelFile, parcelLabelFileMapIndex); if (parcelReordering != NULL) { rowIndices = parcelReordering->getReorderedParcelIndices(); } } return helpMapFileLoadChartDataMatrixRGBA(numberOfRowsOut, numberOfColumnsOut, rowIndices, rgbaOut); } /** * Get the value, row name, and column name for a cell in the matrix. * * @param rowIndex * The row index. * @param columnIndex * The column index. * @param cellValueOut * Output containing value in the cell. * @param rowNameOut * Name of row corresponding to row index. * @param columnNameOut * Name of column corresponding to column index. * @return * True if the output values are valid (valid row/column indices). */ bool CiftiParcelScalarFile::getMatrixCellAttributes(const int32_t rowIndex, const int32_t columnIndex, AString& cellValueOut, AString& rowNameOut, AString& columnNameOut) const { if ((rowIndex >= 0) && (rowIndex < m_ciftiFile->getNumberOfRows()) && (columnIndex >= 0) && (columnIndex < m_ciftiFile->getNumberOfColumns())) { const CiftiXML& xml = m_ciftiFile->getCiftiXML(); const std::vector& rowsParcelsMap = xml.getParcelsMap(CiftiXML::ALONG_COLUMN).getParcels(); CaretAssertVectorIndex(rowsParcelsMap, rowIndex); rowNameOut = rowsParcelsMap[rowIndex].m_name; columnNameOut = ("Map " + AString::number(columnIndex + 1)); const int32_t numberOfElementsInRow = m_ciftiFile->getNumberOfColumns(); std::vector rowData(numberOfElementsInRow); m_ciftiFile->getRow(&rowData[0], rowIndex); CaretAssertVectorIndex(rowData, columnIndex); cellValueOut = AString::number(rowData[columnIndex], 'f', 6); return true; } return false; } /** * @return Is charting enabled for this file? */ bool CiftiParcelScalarFile::isMatrixChartingEnabled(const int32_t tabIndex) const { CaretAssertArrayIndex(m_matrixChartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_matrixChartingEnabledForTab[tabIndex]; } /** * @return Return true if the file's current state supports * charting data, else false. Typically a brainordinate file * is chartable if it contains more than one map. */ bool CiftiParcelScalarFile::isMatrixChartingSupported() const { return true; } /** * Set charting enabled for this file. * * @param enabled * New status for charting enabled. */ void CiftiParcelScalarFile::setMatrixChartingEnabled(const int32_t tabIndex, const bool enabled) { CaretAssertArrayIndex(m_matrixChartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_matrixChartingEnabledForTab[tabIndex] = enabled; } /** * Get chart data types supported by the file. * * @param chartDataTypesOut * Chart types supported by this file. */ void CiftiParcelScalarFile::getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const { chartDataTypesOut.clear(); chartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER); } /** * @return Chart matrix display properties (const method). */ const ChartMatrixDisplayProperties* CiftiParcelScalarFile::getChartMatrixDisplayProperties(const int32_t tabIndex) const { CaretAssertArrayIndex(m_chartMatrixDisplayProperties, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_chartMatrixDisplayProperties[tabIndex]; } /** * @return Chart matrix display properties. */ ChartMatrixDisplayProperties* CiftiParcelScalarFile::getChartMatrixDisplayProperties(const int32_t tabIndex) { CaretAssertArrayIndex(m_chartMatrixDisplayProperties, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_chartMatrixDisplayProperties[tabIndex]; } /** * @return Coloring mode for selected parcel. */ CiftiParcelColoringModeEnum::Enum CiftiParcelScalarFile::getSelectedParcelColoringMode() const { return m_selectedParcelColoringMode; } /** * Set the coloring mode for selected parcel. * * @param coloringMode * New value for coloring mode. */ void CiftiParcelScalarFile::setSelectedParcelColoringMode(const CiftiParcelColoringModeEnum::Enum coloringMode) { m_selectedParcelColoringMode = coloringMode; } /** * @return Color for selected parcel. */ CaretColorEnum::Enum CiftiParcelScalarFile::getSelectedParcelColor() const { return m_selectedParcelColor; } /** * Set color for selected parcel. * * @param color * New color for selected parcel. */ void CiftiParcelScalarFile::setSelectedParcelColor(const CaretColorEnum::Enum color) { m_selectedParcelColor = color; } /** * Save file data from the scene. For subclasses that need to * save to a scene, this method should be overriden. sceneClass * will be valid and any scene data should be added to it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. */ void CiftiParcelScalarFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { CiftiMappableDataFile::saveFileDataToScene(sceneAttributes, sceneClass); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); sceneClass->addBooleanArray("m_brainordinateChartingEnabledForTab", m_brainordinateChartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); sceneClass->addBooleanArray("m_matrixChartingEnabledForTab", m_matrixChartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); /* * Save chart matrix properties */ SceneObjectMapIntegerKey* chartMatrixPropertiesMap = new SceneObjectMapIntegerKey("m_chartMatrixDisplayPropertiesMap", SceneObjectDataTypeEnum::SCENE_CLASS); const std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); for (std::vector::const_iterator tabIter = tabIndices.begin(); tabIter != tabIndices.end(); tabIter++) { const int32_t tabIndex = *tabIter; chartMatrixPropertiesMap->addClass(tabIndex, m_chartMatrixDisplayProperties[tabIndex]->saveToScene(sceneAttributes, "m_chartMatrixDisplayProperties")); } sceneClass->addChild(chartMatrixPropertiesMap); } /** * Restore file data from the scene. For subclasses that need to * restore from a scene, this method should be overridden. The scene class * will be valid and any scene data may be obtained from it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void CiftiParcelScalarFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { CiftiMappableDataFile::restoreFileDataFromScene(sceneAttributes, sceneClass); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); /* * Originally, charting was "per file": m_chartingEnabled * Later, charting became "per tab": m_chartingEnabledForTab * Even Later, it needed to clearly be for brainordinates: m_brainordinateChartingEnabledForTab */ const ScenePrimitiveArray* brainChartingForTab = sceneClass->getPrimitiveArray("m_brainordinateChartingEnabledForTab"); const ScenePrimitiveArray* oldChartingEnabledForTab = sceneClass->getPrimitiveArray("m_chartingEnabledForTab"); if (brainChartingForTab != NULL) { sceneClass->getBooleanArrayValue("brainChartingForTab", m_brainordinateChartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); } else if (oldChartingEnabledForTab != NULL) { sceneClass->getBooleanArrayValue("m_chartingEnabledForTab", m_brainordinateChartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); } else { /* * Obsolete value when charting was not 'per tab' */ const bool chartingEnabled = sceneClass->getBooleanValue("m_chartingEnabled", false); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_brainordinateChartingEnabledForTab[i] = chartingEnabled; } } for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_matrixChartingEnabledForTab[i] = false; m_chartMatrixDisplayProperties[i]->resetPropertiesToDefault(); } sceneClass->getBooleanArrayValue("m_matrixChartingEnabledForTab", m_matrixChartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); /* * Restore chart matrix properties */ const SceneObjectMapIntegerKey* chartMatrixPropertiesMap = sceneClass->getMapIntegerKey("m_chartMatrixDisplayPropertiesMap"); if (chartMatrixPropertiesMap != NULL) { const std::vector tabIndices = chartMatrixPropertiesMap->getKeys(); for (std::vector::const_iterator tabIter = tabIndices.begin(); tabIter != tabIndices.end(); tabIter++) { const int32_t tabIndex = *tabIter; const SceneClass* sceneClass = chartMatrixPropertiesMap->classValue(tabIndex); m_chartMatrixDisplayProperties[tabIndex]->restoreFromScene(sceneAttributes, sceneClass); } } } /** * Get the selected parcel label file used for reordering of parcels. * * @param compatibleParcelLabelFilesOut * All Parcel Label files that are compatible with file implementing * this interface. * @param selectedParcelLabelFileOut * The selected parcel label file used for reordering the parcels. * May be NULL! * @param selectedParcelLabelFileMapIndexOut * Map index in the selected parcel label file. * @param enabledStatusOut * Enabled status of reordering. */ void CiftiParcelScalarFile::getSelectedParcelLabelFileAndMapForReordering(std::vector& compatibleParcelLabelFilesOut, CiftiParcelLabelFile* &selectedParcelLabelFileOut, int32_t& selectedParcelLabelFileMapIndexOut, bool& enabledStatusOut) const { m_parcelReorderingModel->getSelectedParcelLabelFileAndMapForReordering(compatibleParcelLabelFilesOut, selectedParcelLabelFileOut, selectedParcelLabelFileMapIndexOut, enabledStatusOut); } /** * Set the selected parcel label file used for reordering of parcels. * * @param selectedParcelLabelFile * The selected parcel label file used for reordering the parcels. * May be NULL! * @param selectedParcelLabelFileMapIndex * Map index in the selected parcel label file. * @param enabledStatus * Enabled status of reordering. */ void CiftiParcelScalarFile::setSelectedParcelLabelFileAndMapForReordering(CiftiParcelLabelFile* selectedParcelLabelFile, const int32_t selectedParcelLabelFileMapIndex, const bool enabledStatus) { m_parcelReorderingModel->setSelectedParcelLabelFileAndMapForReordering(selectedParcelLabelFile, selectedParcelLabelFileMapIndex, enabledStatus); } /** * Get the parcel reordering for the given map index that was created using * the given parcel label file and its map index. * * @param parcelLabelFile * The selected parcel label file used for reordering the parcels. * @param parcelLabelFileMapIndex * Map index in the selected parcel label file. * @return * Pointer to parcel reordering or NULL if not found. */ const CiftiParcelReordering* CiftiParcelScalarFile::getParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex) const { return m_parcelReorderingModel->getParcelReordering(parcelLabelFile, parcelLabelFileMapIndex); } /** * Create the parcel reordering for the given map index using * the given parcel label file and its map index. * * @param parcelLabelFile * The selected parcel label file used for reordering the parcels. * @param parcelLabelFileMapIndex * Map index in the selected parcel label file. * @param ciftiParcelsMap * The CIFTI parcels map that will or has been reordered. * @param errorMessageOut * Error message output. Will only be non-empty if NULL is returned. * @return * Pointer to parcel reordering or NULL if not found. */ bool CiftiParcelScalarFile::createParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex, AString& errorMessageOut) { return m_parcelReorderingModel->createParcelReordering(parcelLabelFile, parcelLabelFileMapIndex, errorMessageOut); } /** * @return True if loading attributes (column/row, yoking) are * supported by this file type. */ bool CiftiParcelScalarFile::isSupportsLoadingAttributes() { return false; } /** * @return The matrix loading type (by row/column). */ ChartMatrixLoadingDimensionEnum::Enum CiftiParcelScalarFile::getMatrixLoadingDimension() const { /* * This file supports loading by column only ! */ return ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN; } /** * Set the matrix loading type (by row/column). * * @param matrixLoadingType * New value for matrix loading type. */ void CiftiParcelScalarFile::setMatrixLoadingDimension(const ChartMatrixLoadingDimensionEnum::Enum /* matrixLoadingType */) { CaretLogSevere("Attempting to change matrix loading type for a file that only supports loading by column"); } /** * @return Selected yoking group. */ YokingGroupEnum::Enum CiftiParcelScalarFile::getYokingGroup() const { /* not supported in this file */ return YokingGroupEnum::YOKING_GROUP_OFF; } /** * Set the selected yoking group. * * @param yokingGroup * New value for yoking group. */ void CiftiParcelScalarFile::setYokingGroup(const YokingGroupEnum::Enum /* yokingGroup */) { /* not supported in this file */ } connectome-workbench-1.4.2/src/Files/CiftiParcelScalarFile.h000066400000000000000000000162151360521144700237550ustar00rootroot00000000000000#ifndef __CIFTI_PARCEL_SCALAR_FILE_H__ #define __CIFTI_PARCEL_SCALAR_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "ChartableLineSeriesBrainordinateInterface.h" #include "ChartableMatrixParcelInterface.h" #include "CiftiMappableDataFile.h" namespace caret { class CiftiParcelReorderingModel; class SceneClassAssistant; class CiftiParcelScalarFile : public CiftiMappableDataFile, public ChartableLineSeriesBrainordinateInterface, public ChartableMatrixParcelInterface { public: CiftiParcelScalarFile(); virtual ~CiftiParcelScalarFile(); virtual bool isLineSeriesChartingEnabled(const int32_t tabIndex) const; virtual void setLineSeriesChartingEnabled(const int32_t tabIndex, const bool enabled); virtual bool isLineSeriesChartingSupported() const; virtual ChartDataCartesian* loadLineSeriesChartDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t nodeIndex); virtual ChartDataCartesian* loadAverageLineSeriesChartDataForSurfaceNodes(const StructureEnum::Enum structure, const std::vector& nodeIndices); virtual ChartDataCartesian* loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]); virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; virtual void getMatrixDimensions(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) const; virtual bool getMatrixDataRGBA(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut, std::vector& rgbaOut) const; virtual bool getMatrixCellAttributes(const int32_t rowIndex, const int32_t columnIndex, AString& cellValueOut, AString& rowNameOut, AString& columnNameOut) const; virtual bool isMatrixChartingEnabled(const int32_t tabIndex) const; virtual bool isMatrixChartingSupported() const; virtual void setMatrixChartingEnabled(const int32_t tabIndex, const bool enabled); virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const; const ChartMatrixDisplayProperties* getChartMatrixDisplayProperties(const int32_t tabIndex) const; ChartMatrixDisplayProperties* getChartMatrixDisplayProperties(const int32_t tabIndex); virtual CiftiParcelColoringModeEnum::Enum getSelectedParcelColoringMode() const; virtual void setSelectedParcelColoringMode(const CiftiParcelColoringModeEnum::Enum coloringMode); virtual CaretColorEnum::Enum getSelectedParcelColor() const; virtual void setSelectedParcelColor(const CaretColorEnum::Enum color); virtual void getSelectedParcelLabelFileAndMapForReordering(std::vector& compatibleParcelLabelFilesOut, CiftiParcelLabelFile* &selectedParcelLabelFileOut, int32_t& selectedParcelLabelFileMapIndexOut, bool& enabledStatusOut) const; virtual void setSelectedParcelLabelFileAndMapForReordering(CiftiParcelLabelFile* selectedParcelLabelFile, const int32_t selectedParcelLabelFileMapIndex, const bool enabledStatus); virtual bool createParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex, AString& errorMessageOut); virtual const CiftiParcelReordering* getParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex) const; virtual bool isSupportsLoadingAttributes(); virtual ChartMatrixLoadingDimensionEnum::Enum getMatrixLoadingDimension() const; virtual void setMatrixLoadingDimension(const ChartMatrixLoadingDimensionEnum::Enum matrixLoadingType); virtual YokingGroupEnum::Enum getYokingGroup() const; virtual void setYokingGroup(const YokingGroupEnum::Enum yokingType); private: CiftiParcelScalarFile(const CiftiParcelScalarFile&); CiftiParcelScalarFile& operator=(const CiftiParcelScalarFile&); virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); public: // ADD_NEW_METHODS_HERE private: SceneClassAssistant* m_sceneAssistant; bool m_brainordinateChartingEnabledForTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; bool m_matrixChartingEnabledForTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; ChartMatrixDisplayProperties* m_chartMatrixDisplayProperties[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; CiftiParcelColoringModeEnum::Enum m_selectedParcelColoringMode; CaretColorEnum::Enum m_selectedParcelColor; CiftiParcelReorderingModel* m_parcelReorderingModel; // ADD_NEW_MEMBERS_HERE }; #ifdef __CIFTI_PARCEL_SCALAR_FILE_DECLARE__ // #endif // __CIFTI_PARCEL_SCALAR_FILE_DECLARE__ } // namespace #endif //__CIFTI_PARCEL_SCALAR_FILE_H__ connectome-workbench-1.4.2/src/Files/CiftiParcelSeriesFile.cxx000066400000000000000000000305071360521144700243550ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CIFTI_PARCEL_SERIES_FILE_DECLARE__ #include "CiftiParcelSeriesFile.h" #undef __CIFTI_PARCEL_SERIES_FILE_DECLARE__ #include "CaretLogger.h" #include "ChartDataCartesian.h" #include "CiftiParcelReorderingModel.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::CiftiParcelSeriesFile * \brief CIFTI Parcel by Data-Series File. * \ingroup Files */ /** * Constructor. */ CiftiParcelSeriesFile::CiftiParcelSeriesFile() : CiftiMappableDataFile(DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES) { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = false; } m_parcelReorderingModel = std::unique_ptr(new CiftiParcelReorderingModel(this)); m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); m_sceneAssistant->add("m_parcelReorderingModel", "CiftiParcelReorderingModel", m_parcelReorderingModel.get()); } /** * Destructor. */ CiftiParcelSeriesFile::~CiftiParcelSeriesFile() { } /** * @return Is charting enabled for this file? */ bool CiftiParcelSeriesFile::isLineSeriesChartingEnabled(const int32_t tabIndex) const { CaretAssertArrayIndex(m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_chartingEnabledForTab[tabIndex]; } /** * @return Return true if the file's current state supports * charting data, else false. Typically a brainordinate file * is chartable if it contains more than one map. */ bool CiftiParcelSeriesFile::isLineSeriesChartingSupported() const { if (getNumberOfMaps() > 1) { return true; } return false; } /** * Set charting enabled for this file. * * @param enabled * New status for charting enabled. */ void CiftiParcelSeriesFile::setLineSeriesChartingEnabled(const int32_t tabIndex, const bool enabled) { CaretAssertArrayIndex(m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_chartingEnabledForTab[tabIndex] = enabled; } /** * Get chart data types supported by the file. * * @param chartDataTypesOut * Chart types supported by this file. */ void CiftiParcelSeriesFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { helpGetSupportedLineSeriesChartDataTypes(chartDataTypesOut); } /** * Load charting data for the surface with the given structure and node index. * * @param structure * The surface's structure. * @param nodeIndex * Index of the node. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will return true. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* CiftiParcelSeriesFile::loadLineSeriesChartDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t nodeIndex) { ChartDataCartesian* chartData = helpLoadChartDataForSurfaceNode(structure, nodeIndex); return chartData; } /** * Load average charting data for the surface with the given structure and node indices. * * @param structure * The surface's structure. * @param nodeIndices * Indices of the node. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* CiftiParcelSeriesFile::loadAverageLineSeriesChartDataForSurfaceNodes(const StructureEnum::Enum structure, const std::vector& nodeIndices) { ChartDataCartesian* chartData = helpLoadChartDataForSurfaceNodeAverage(structure, nodeIndices); return chartData; } /** * Load charting data for the voxel enclosing the given coordinate. * * @param xyz * Coordinate of voxel. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* CiftiParcelSeriesFile::loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]) { ChartDataCartesian* chartData = helpLoadChartDataForVoxelAtCoordinate(xyz); return chartData; } /** * Save file data from the scene. For subclasses that need to * save to a scene, this method should be overriden. sceneClass * will be valid and any scene data should be added to it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. */ void CiftiParcelSeriesFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { CiftiMappableDataFile::saveFileDataToScene(sceneAttributes, sceneClass); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); sceneClass->addBooleanArray("m_chartingEnabledForTab", m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); } /** * Restore file data from the scene. For subclasses that need to * restore from a scene, this method should be overridden. The scene class * will be valid and any scene data may be obtained from it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void CiftiParcelSeriesFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { CiftiMappableDataFile::restoreFileDataFromScene(sceneAttributes, sceneClass); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); const ScenePrimitiveArray* tabArray = sceneClass->getPrimitiveArray("m_chartingEnabledForTab"); if (tabArray != NULL) { sceneClass->getBooleanArrayValue("m_chartingEnabledForTab", m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); } else { /* * Obsolete value when charting was not 'per tab' */ const bool chartingEnabled = sceneClass->getBooleanValue("m_chartingEnabled", false); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = chartingEnabled; } } } /** * Get the selected parcel label file used for reordering of parcels. * * @param compatibleParcelLabelFilesOut * All Parcel Label files that are compatible with file implementing * this interface. * @param selectedParcelLabelFileOut * The selected parcel label file used for reordering the parcels. * May be NULL! * @param selectedParcelLabelFileMapIndexOut * Map index in the selected parcel label file. * @param enabledStatusOut * Enabled status of reordering. */ void CiftiParcelSeriesFile::getSelectedParcelLabelFileAndMapForReordering(std::vector& compatibleParcelLabelFilesOut, CiftiParcelLabelFile* &selectedParcelLabelFileOut, int32_t& selectedParcelLabelFileMapIndexOut, bool& enabledStatusOut) const { m_parcelReorderingModel->getSelectedParcelLabelFileAndMapForReordering(compatibleParcelLabelFilesOut, selectedParcelLabelFileOut, selectedParcelLabelFileMapIndexOut, enabledStatusOut); } /** * Set the selected parcel label file used for reordering of parcels. * * @param selectedParcelLabelFile * The selected parcel label file used for reordering the parcels. * May be NULL! * @param selectedParcelLabelFileMapIndex * Map index in the selected parcel label file. * @param enabledStatus * Enabled status of reordering. */ void CiftiParcelSeriesFile::setSelectedParcelLabelFileAndMapForReordering(CiftiParcelLabelFile* selectedParcelLabelFile, const int32_t selectedParcelLabelFileMapIndex, const bool enabledStatus) { m_parcelReorderingModel->setSelectedParcelLabelFileAndMapForReordering(selectedParcelLabelFile, selectedParcelLabelFileMapIndex, enabledStatus); } /** * Get the parcel reordering for the given map index that was created using * the given parcel label file and its map index. * * @param parcelLabelFile * The selected parcel label file used for reordering the parcels. * @param parcelLabelFileMapIndex * Map index in the selected parcel label file. * @return * Pointer to parcel reordering or NULL if not found. */ const CiftiParcelReordering* CiftiParcelSeriesFile::getParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex) const { return m_parcelReorderingModel->getParcelReordering(parcelLabelFile, parcelLabelFileMapIndex); } /** * Create the parcel reordering for the given map index using * the given parcel label file and its map index. * * @param parcelLabelFile * The selected parcel label file used for reordering the parcels. * @param parcelLabelFileMapIndex * Map index in the selected parcel label file. * @param ciftiParcelsMap * The CIFTI parcels map that will or has been reordered. * @param errorMessageOut * Error message output. Will only be non-empty if NULL is returned. * @return * Pointer to parcel reordering or NULL if not found. */ bool CiftiParcelSeriesFile::createParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex, AString& errorMessageOut) { return m_parcelReorderingModel->createParcelReordering(parcelLabelFile, parcelLabelFileMapIndex, errorMessageOut); } connectome-workbench-1.4.2/src/Files/CiftiParcelSeriesFile.h000066400000000000000000000112571360521144700240030ustar00rootroot00000000000000#ifndef __CIFTI_PARCEL_SERIES_FILE_H__ #define __CIFTI_PARCEL_SERIES_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "BrainConstants.h" #include "ChartableLineSeriesBrainordinateInterface.h" #include "CiftiMappableDataFile.h" namespace caret { class CiftiParcelLabelFile; class CiftiParcelReordering; class CiftiParcelReorderingModel; class SceneClassAssistant; class CiftiParcelSeriesFile : public CiftiMappableDataFile, public ChartableLineSeriesBrainordinateInterface { public: CiftiParcelSeriesFile(); virtual ~CiftiParcelSeriesFile(); virtual bool isLineSeriesChartingEnabled(const int32_t tabIndex) const; virtual void setLineSeriesChartingEnabled(const int32_t tabIndex, const bool enabled); virtual bool isLineSeriesChartingSupported() const; virtual ChartDataCartesian* loadLineSeriesChartDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t nodeIndex); virtual ChartDataCartesian* loadAverageLineSeriesChartDataForSurfaceNodes(const StructureEnum::Enum structure, const std::vector& nodeIndices); virtual ChartDataCartesian* loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]); virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; virtual void getSelectedParcelLabelFileAndMapForReordering(std::vector& compatibleParcelLabelFilesOut, CiftiParcelLabelFile* &selectedParcelLabelFileOut, int32_t& selectedParcelLabelFileMapIndexOut, bool& enabledStatusOut) const; virtual void setSelectedParcelLabelFileAndMapForReordering(CiftiParcelLabelFile* selectedParcelLabelFile, const int32_t selectedParcelLabelFileMapIndex, const bool enabledStatus); virtual bool createParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex, AString& errorMessageOut); virtual const CiftiParcelReordering* getParcelReordering(const CiftiParcelLabelFile* parcelLabelFile, const int32_t parcelLabelFileMapIndex) const; private: CiftiParcelSeriesFile(const CiftiParcelSeriesFile&); CiftiParcelSeriesFile& operator=(const CiftiParcelSeriesFile&); virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE std::unique_ptr m_sceneAssistant; bool m_chartingEnabledForTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; std::unique_ptr m_parcelReorderingModel; }; #ifdef __CIFTI_PARCEL_SERIES_FILE_DECLARE__ // #endif // __CIFTI_PARCEL_SERIES_FILE_DECLARE__ } // namespace #endif //__CIFTI_PARCEL_SERIES_FILE_H__ connectome-workbench-1.4.2/src/Files/CiftiScalarDataSeriesFile.cxx000066400000000000000000000566671360521144700251650ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CIFTI_SCALAR_DATA_SERIES_FILE_DECLARE__ #include "CiftiScalarDataSeriesFile.h" #undef __CIFTI_SCALAR_DATA_SERIES_FILE_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "ChartDataCartesian.h" #include "ChartMatrixDisplayProperties.h" #include "CiftiFile.h" #include "CiftiSeriesMap.h" #include "CiftiXML.h" #include "DataFileException.h" #include "EventBrowserTabIndicesGetAll.h" #include "EventManager.h" #include "EventMapYokingSelectMap.h" #include "EventMapYokingValidation.h" #include "FastStatistics.h" #include "NodeAndVoxelColoring.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::CiftiScalarDataSeriesFile * \brief CIFTI Scalar Data Series File * \ingroup Files */ /** * Constructor. */ CiftiScalarDataSeriesFile::CiftiScalarDataSeriesFile() : CiftiMappableDataFile(DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES) { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_lineSeriesChartingEnabledForTab[i] = false; m_matrixChartingEnabledForTab[i] = false; m_chartMatrixDisplayPropertiesForTab[i] = new ChartMatrixDisplayProperties(); m_chartMatrixDisplayPropertiesForTab[i]->setGridLinesDisplayed(false); m_yokingGroupForTab[i] = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; m_selectedMapIndices[i] = 0; } m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->addTabIndexedEnumeratedTypeArray("m_yokingGroupForTab", m_yokingGroupForTab); m_sceneAssistant->addTabIndexedBooleanArray("m_lineSeriesChartingEnabledForTab", m_lineSeriesChartingEnabledForTab); m_sceneAssistant->addTabIndexedBooleanArray("m_matrixChartingEnabledForTab", m_matrixChartingEnabledForTab); m_sceneAssistant->addTabIndexedIntegerArray("m_selectedMapIndices", m_selectedMapIndices); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAP_YOKING_VALIDATION); } /** * Destructor. */ CiftiScalarDataSeriesFile::~CiftiScalarDataSeriesFile() { EventManager::get()->removeAllEventsFromListener(this); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { delete m_chartMatrixDisplayPropertiesForTab[i]; } delete m_sceneAssistant; } /** * Receive an event. * * @param event * The event. */ void CiftiScalarDataSeriesFile::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_MAP_YOKING_VALIDATION) { EventMapYokingValidation* yokeMapEvent = dynamic_cast(event); CaretAssert(yokeMapEvent); yokeMapEvent->addMapYokedFileAllTabs(this, m_yokingGroupForTab); yokeMapEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP) { /* * The events intended for overlays are received here so that * only DISPLAYED overlays are updated. */ EventMapYokingSelectMap* selectMapEvent = dynamic_cast(event); CaretAssert(selectMapEvent); const MapYokingGroupEnum::Enum mapYokingGroup = selectMapEvent->getMapYokingGroup(); if (mapYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { const int32_t yokedMapIndex = selectMapEvent->getMapIndex(); EventBrowserTabIndicesGetAll tabIndicesEvent; EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); const std::vector tabIndices = tabIndicesEvent.getAllBrowserTabIndices(); for (std::vector::const_iterator iter = tabIndices.begin(); iter != tabIndices.end(); iter++) { const int32_t tabIndex = *iter; if (getMatrixRowColumnMapYokingGroup(tabIndex) == mapYokingGroup) { setSelectedMapIndex(tabIndex, yokedMapIndex); } } } selectMapEvent->setEventProcessed(); } CiftiMappableDataFile::receiveEvent(event); } /** * @param tabIndex * Index of tab. * @return * Selected yoking group for the given tab. */ MapYokingGroupEnum::Enum CiftiScalarDataSeriesFile::getMatrixRowColumnMapYokingGroup(const int32_t tabIndex) const { CaretAssertArrayIndex(m_yokingGroupForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_yokingGroupForTab[tabIndex]; } /** * Set the selected yoking group for the given tab. * * @param tabIndex * Index of tab. * @param yokingGroup * New value for yoking group. */ void CiftiScalarDataSeriesFile::setMatrixRowColumnMapYokingGroup(const int32_t tabIndex, const MapYokingGroupEnum::Enum yokingGroup) { CaretAssertArrayIndex(m_yokingGroupForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_yokingGroupForTab[tabIndex] = yokingGroup; if (m_yokingGroupForTab[tabIndex] == MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { return; } } /** * @param tabIndex * Index of tab. * @return * Selected map index in the given tab. */ int32_t CiftiScalarDataSeriesFile::getSelectedMapIndex(const int32_t tabIndex) const { CaretAssertArrayIndex(m_selectedMapIndices, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_selectedMapIndices[tabIndex]; } /** * Set the selected map index for the given tab. * * @param tabIndex * Index of tab. * @param mapIndex * New value for selected map index. */ void CiftiScalarDataSeriesFile::setSelectedMapIndex(const int32_t /*tabIndex*/, const int32_t mapIndex) { /* * One map selection for all tabs */ for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { CaretAssertArrayIndex(m_selectedMapIndices, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, i); m_selectedMapIndices[i] = mapIndex; } } /** * Get the matrix dimensions. * * @param numberOfRowsOut * Number of rows in the matrix. * @param numberOfColumnsOut * Number of columns in the matrix. */ void CiftiScalarDataSeriesFile::getMatrixDimensions(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) const { helpMapFileGetMatrixDimensions(numberOfRowsOut, numberOfColumnsOut); } /** * Get the matrix RGBA coloring for this matrix data creator. * * @param numberOfRowsOut * Number of rows in the coloring matrix. * @param numberOfColumnsOut * Number of rows in the coloring matrix. * @param rgbaOut * RGBA coloring output with number of elements * (numberOfRowsOut * numberOfColumnsOut * 4). * @return * True if data output data is valid, else false. */ bool CiftiScalarDataSeriesFile::getMatrixDataRGBA(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut, std::vector& rgbaOut) const { std::vector rowIndices; return helpMatrixFileLoadChartDataMatrixRGBA(numberOfRowsOut, numberOfColumnsOut, rowIndices, rgbaOut); } /** * Get the value, row name, and column name for a cell in the matrix. * * @param rowIndex * The row index. * @param columnIndex * The column index. * @param cellValueOut * Output containing value in the cell. * @param rowNameOut * Name of row corresponding to row index. * @param columnNameOut * Name of column corresponding to column index. * @return * True if the output values are valid (valid row/column indices). */ bool CiftiScalarDataSeriesFile::getMatrixCellAttributes(const int32_t rowIndex, const int32_t columnIndex, AString& cellValueOut, AString& rowNameOut, AString& columnNameOut) const { rowNameOut = " "; columnNameOut = " "; if ((rowIndex >= 0) && (rowIndex < m_ciftiFile->getNumberOfRows()) && (columnIndex >= 0) && (columnIndex < m_ciftiFile->getNumberOfColumns())) { const CiftiXML& xml = m_ciftiFile->getCiftiXML(); const CiftiScalarsMap& scalarsMap = xml.getScalarsMap(CiftiXML::ALONG_COLUMN); CaretAssertArrayIndex(scalarsMap, scalarsMap.getLength(), rowIndex); rowNameOut = scalarsMap.getMapName(rowIndex); const CiftiSeriesMap& seriesMap = xml.getSeriesMap(CiftiXML::ALONG_ROW); CaretAssertArrayIndex(seriesMap, seriesMap.getLength(), columnIndex); const float time = seriesMap.getStart() + seriesMap.getStep() * columnIndex; AString timeUnitsString; switch (seriesMap.getUnit()) { case CiftiSeriesMap::HERTZ: timeUnitsString = NiftiTimeUnitsEnum::toGuiName(NiftiTimeUnitsEnum::NIFTI_UNITS_HZ); break; case CiftiSeriesMap::METER: CaretLogWarning("CIFTI Units METER not implemented"); break; case CiftiSeriesMap::RADIAN: CaretLogWarning("CIFTI Units RADIAN not implemented"); break; case CiftiSeriesMap::SECOND: timeUnitsString = NiftiTimeUnitsEnum::toGuiName(NiftiTimeUnitsEnum::NIFTI_UNITS_SEC); break; } columnNameOut = (AString::number(time, 'f', 3) + " " + timeUnitsString); const int32_t numberOfElementsInRow = m_ciftiFile->getNumberOfColumns(); std::vector rowData(numberOfElementsInRow); m_ciftiFile->getRow(&rowData[0], rowIndex); CaretAssertVectorIndex(rowData, columnIndex); cellValueOut = AString::number(rowData[columnIndex], 'f', 6); return true; } return false; } /** * @return Is charting enabled for this file? */ bool CiftiScalarDataSeriesFile::isMatrixChartingEnabled(const int32_t tabIndex) const { CaretAssertArrayIndex(m_matrixChartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_matrixChartingEnabledForTab[tabIndex]; } /** * @return Return true if the file's current state supports * charting data, else false. Typically a brainordinate file * is chartable if it contains more than one map. */ bool CiftiScalarDataSeriesFile::isMatrixChartingSupported() const { return true; } /** * Set charting enabled for this file. * * @param enabled * New status for charting enabled. */ void CiftiScalarDataSeriesFile::setMatrixChartingEnabled(const int32_t tabIndex, const bool enabled) { CaretAssertArrayIndex(m_matrixChartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_matrixChartingEnabledForTab[tabIndex] = enabled; } /** * Get chart data types supported by the file. * * @param chartDataTypesOut * Chart types supported by this file. */ void CiftiScalarDataSeriesFile::getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const { chartDataTypesOut.clear(); chartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES); } /** * @return Chart matrix display properties (const method). */ const ChartMatrixDisplayProperties* CiftiScalarDataSeriesFile::getChartMatrixDisplayProperties(const int32_t tabIndex) const { CaretAssertArrayIndex(m_chartMatrixDisplayProperties, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_chartMatrixDisplayPropertiesForTab[tabIndex]; } /** * @return Chart matrix display properties. */ ChartMatrixDisplayProperties* CiftiScalarDataSeriesFile::getChartMatrixDisplayProperties(const int32_t tabIndex) { CaretAssertArrayIndex(m_chartMatrixDisplayProperties, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_chartMatrixDisplayPropertiesForTab[tabIndex]; } /** * Load charting data for the given column index. * * @param columnIndex * Index of the column. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* CiftiScalarDataSeriesFile::loadLineSeriesChartDataForColumn(const int32_t /*columnIndex*/) { CaretAssertMessage(0, "Loading of columns is not used at this time"); return NULL; } /** * Load charting data for the given row index. * * @param rowIndex * Index of the row. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* CiftiScalarDataSeriesFile::loadLineSeriesChartDataForRow(const int32_t rowIndex) { ChartDataCartesian* chartData = NULL; try { if ((rowIndex >= 0) && (rowIndex < m_ciftiFile->getNumberOfRows())) { const int32_t numberOfElementsInRow = m_ciftiFile->getNumberOfColumns(); if (numberOfElementsInRow > 0) { std::vector rowData(numberOfElementsInRow); m_ciftiFile->getRow(&rowData[0], rowIndex); const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); const CiftiSeriesMap& seriesMap = ciftiXML.getSeriesMap(CiftiXML::ALONG_ROW); ChartOneDataTypeEnum::Enum chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; AString timeUnitsString; switch (seriesMap.getUnit()) { case CiftiSeriesMap::HERTZ: chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES; break; case CiftiSeriesMap::METER: CaretLogWarning("CIFTI Units METER not implemented"); break; case CiftiSeriesMap::RADIAN: CaretLogWarning("CIFTI Units RADIAN not implemented"); break; case CiftiSeriesMap::SECOND: chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES; break; } if (chartDataType != ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { chartData = new ChartDataCartesian(chartDataType, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE, ChartAxisUnitsEnum::CHART_AXIS_UNITS_NONE); if (chartData != NULL) { float timeStart = seriesMap.getStart(); float timeStep = seriesMap.getStep(); chartData->setTimeStartInSecondsAxisX(timeStart); chartData->setTimeStepInSecondsAxisX(timeStep); for (int64_t i = 0; i < numberOfElementsInRow; i++) { const float xValue = timeStart + (i * timeStep); chartData->addPoint(xValue, rowData[i]); } } } } } } catch (const DataFileException& dfe) { if (chartData != NULL) { delete chartData; chartData = NULL; } throw dfe; } return chartData; } /** * @return Is charting enabled for this file? */ bool CiftiScalarDataSeriesFile::isLineSeriesChartingEnabled(const int32_t tabIndex) const { CaretAssertArrayIndex(m_lineSeriesChartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_lineSeriesChartingEnabledForTab[tabIndex]; } /** * @return Return true if the file's current state supports * charting data, else false. Typically a brainordinate file * is chartable if it contains more than one map. */ bool CiftiScalarDataSeriesFile::isLineSeriesChartingSupported() const { if ((m_ciftiFile->getNumberOfColumns() > 0) && (m_ciftiFile->getNumberOfRows() > 0)) { return true; } return false; } /** * Get chart data types supported by the file. * * @param chartDataTypesOut * Chart types supported by this file. */ void CiftiScalarDataSeriesFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { chartDataTypesOut.clear(); const CiftiXML& ciftiXML = m_ciftiFile->getCiftiXML(); CiftiMappingType::MappingType mapType = ciftiXML.getMappingType(CiftiXML::ALONG_ROW); const AString message("Mapping type should always be SERIES for CIFTI Scalar Data Series File"); CaretAssertMessage(mapType == CiftiMappingType::SERIES, message); if (mapType == CiftiMappingType::SERIES) { const CiftiSeriesMap& seriesMap = ciftiXML.getSeriesMap(CiftiXML::ALONG_ROW); switch (seriesMap.getUnit()) { case CiftiSeriesMap::HERTZ: chartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES); break; case CiftiSeriesMap::METER: CaretLogWarning("CIFTI Units METER not implemented"); break; case CiftiSeriesMap::RADIAN: CaretLogWarning("CIFTI Units RADIAN not implemented"); break; case CiftiSeriesMap::SECOND: chartDataTypesOut.push_back(ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES); break; } } else { CaretLogSevere(message); } } /** * Set charting enabled for this file. * * @param enabled * New status for charting enabled. */ void CiftiScalarDataSeriesFile::setLineSeriesChartingEnabled(const int32_t tabIndex, const bool enabled) { CaretAssertArrayIndex(m_lineSeriesChartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_lineSeriesChartingEnabledForTab[tabIndex] = enabled; } /** * Save file data from the scene. For subclasses that need to * save to a scene, this method should be overriden. sceneClass * will be valid and any scene data should be added to it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. */ void CiftiScalarDataSeriesFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { CiftiMappableDataFile::saveFileDataToScene(sceneAttributes, sceneClass); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); /* * Save chart matrix properties */ SceneObjectMapIntegerKey* chartMatrixPropertiesMap = new SceneObjectMapIntegerKey("m_chartMatrixDisplayPropertiesMap", SceneObjectDataTypeEnum::SCENE_CLASS); const std::vector tabIndices = sceneAttributes->getIndicesOfTabsForSavingToScene(); for (std::vector::const_iterator tabIter = tabIndices.begin(); tabIter != tabIndices.end(); tabIter++) { const int32_t tabIndex = *tabIter; chartMatrixPropertiesMap->addClass(tabIndex, m_chartMatrixDisplayPropertiesForTab[tabIndex]->saveToScene(sceneAttributes, "m_chartMatrixDisplayProperties")); } sceneClass->addChild(chartMatrixPropertiesMap); } /** * Restore file data from the scene. For subclasses that need to * restore from a scene, this method should be overridden. The scene class * will be valid and any scene data may be obtained from it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void CiftiScalarDataSeriesFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { CiftiMappableDataFile::restoreFileDataFromScene(sceneAttributes, sceneClass); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); /* * Restore chart matrix properties */ const SceneObjectMapIntegerKey* chartMatrixPropertiesMap = sceneClass->getMapIntegerKey("m_chartMatrixDisplayPropertiesMap"); if (chartMatrixPropertiesMap != NULL) { const std::vector tabIndices = chartMatrixPropertiesMap->getKeys(); for (std::vector::const_iterator tabIter = tabIndices.begin(); tabIter != tabIndices.end(); tabIter++) { const int32_t tabIndex = *tabIter; const SceneClass* sceneClass = chartMatrixPropertiesMap->classValue(tabIndex); m_chartMatrixDisplayPropertiesForTab[tabIndex]->restoreFromScene(sceneAttributes, sceneClass); } } } connectome-workbench-1.4.2/src/Files/CiftiScalarDataSeriesFile.h000066400000000000000000000125771360521144700246020ustar00rootroot00000000000000#ifndef __CIFTI_SCALAR_DATA_SERIES_FILE_H__ #define __CIFTI_SCALAR_DATA_SERIES_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "ChartableLineSeriesRowColumnInterface.h" #include "ChartableMatrixSeriesInterface.h" #include "CiftiMappableDataFile.h" #include "EventListenerInterface.h" namespace caret { class SceneClassAssistant; class CiftiScalarDataSeriesFile : public CiftiMappableDataFile, public ChartableLineSeriesRowColumnInterface, public ChartableMatrixSeriesInterface { public: CiftiScalarDataSeriesFile(); virtual ~CiftiScalarDataSeriesFile(); virtual MapYokingGroupEnum::Enum getMatrixRowColumnMapYokingGroup(const int32_t tabIndex) const; virtual void setMatrixRowColumnMapYokingGroup(const int32_t tabIndex, const MapYokingGroupEnum::Enum yokingType); virtual int32_t getSelectedMapIndex(const int32_t tabIndex) const override; virtual void setSelectedMapIndex(const int32_t tabIndex, const int32_t mapIndex); virtual void receiveEvent(Event* event); virtual void getMatrixDimensions(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) const; virtual bool getMatrixDataRGBA(int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut, std::vector& rgbaOut) const; virtual bool getMatrixCellAttributes(const int32_t rowIndex, const int32_t columnIndex, AString& cellValueOut, AString& rowNameOut, AString& columnNameOut) const; virtual bool isMatrixChartingEnabled(const int32_t tabIndex) const; virtual bool isMatrixChartingSupported() const; virtual void setMatrixChartingEnabled(const int32_t tabIndex, const bool enabled); virtual void getSupportedMatrixChartDataTypes(std::vector& chartDataTypesOut) const; const ChartMatrixDisplayProperties* getChartMatrixDisplayProperties(const int32_t tabIndex) const; ChartMatrixDisplayProperties* getChartMatrixDisplayProperties(const int32_t tabIndex); virtual bool isLineSeriesChartingEnabled(const int32_t tabIndex) const; virtual void setLineSeriesChartingEnabled(const int32_t tabIndex, const bool enabled); virtual bool isLineSeriesChartingSupported() const; virtual ChartDataCartesian* loadLineSeriesChartDataForColumn(const int32_t columnIndex); virtual ChartDataCartesian* loadLineSeriesChartDataForRow(const int32_t rowIndex); virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; // ADD_NEW_METHODS_HERE protected: virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: CiftiScalarDataSeriesFile(const CiftiScalarDataSeriesFile&); CiftiScalarDataSeriesFile& operator=(const CiftiScalarDataSeriesFile&); SceneClassAssistant* m_sceneAssistant; /** yoking status */ MapYokingGroupEnum::Enum m_yokingGroupForTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; bool m_lineSeriesChartingEnabledForTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; bool m_matrixChartingEnabledForTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; ChartMatrixDisplayProperties* m_chartMatrixDisplayPropertiesForTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; int32_t m_selectedMapIndices[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; // ADD_NEW_MEMBERS_HERE }; #ifdef __CIFTI_SCALAR_DATA_SERIES_FILE_DECLARE__ // #endif // __CIFTI_SCALAR_DATA_SERIES_FILE_DECLARE__ } // namespace #endif //__CIFTI_SCALAR_DATA_SERIES_FILE_H__ connectome-workbench-1.4.2/src/Files/ConnectivityDataLoaded.cxx000066400000000000000000000365711360521144700246050ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CONNECTIVITY_DATA_LOADED_DECLARE__ #include "ConnectivityDataLoaded.h" #undef __CONNECTIVITY_DATA_LOADED_DECLARE__ #include "CaretAssert.h" #include "SceneClassAssistant.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "ScenePrimitiveArray.h" #include "SurfaceFile.h" using namespace caret; /** * \class caret::ConnectivityDataLoaded * \brief Maintains information on loaded brainordinate data. * \ingroup Brain */ /** * Constructor. */ ConnectivityDataLoaded::ConnectivityDataLoaded() : CaretObject() { reset(); m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_rowIndex", &m_rowIndex); m_sceneAssistant->add("m_columnIndex", &m_columnIndex); m_sceneAssistant->add("m_surfaceNumberOfNodes", &m_surfaceNumberOfNodes); m_sceneAssistant->add("m_surfaceStructure", &m_surfaceStructure); m_sceneAssistant->addArray("m_volumeDimensionsIJK", m_volumeDimensionsIJK, 3, -1); m_sceneAssistant->addArray("m_volumeXYZ", m_volumeXYZ, 3, 0.0); reset(); } /** * Destructor. */ ConnectivityDataLoaded::~ConnectivityDataLoaded() { reset(); delete m_sceneAssistant; } /** * Reset the data. */ void ConnectivityDataLoaded::reset() { m_mode = MODE_NONE; m_rowIndex = -1; m_columnIndex = -1; m_surfaceNodeIndices.clear(); m_surfaceNumberOfNodes = 0; m_surfaceStructure = StructureEnum::INVALID; m_volumeDimensionsIJK[0] = -1; m_volumeDimensionsIJK[1] = -1; m_volumeDimensionsIJK[2] = -1; m_volumeXYZ[0] = 0.0; m_volumeXYZ[1] = 0.0; m_volumeXYZ[2] = 0.0; m_voxelIndices.clear(); } /** * @return The mode. */ ConnectivityDataLoaded::Mode ConnectivityDataLoaded::getMode() const { return m_mode; } /** * Get the row that were loaded. * * @param rowIndex * Row that was loaded (may be -1 if none). * @param columnIndex * Column that was loaded (may be -1 if none). */ void ConnectivityDataLoaded::getRowColumnLoading(int64_t& rowIndex, int64_t& columnIndex) const { rowIndex = m_rowIndex; columnIndex = m_columnIndex; } /** * Set the row that were loaded. * * @param rowIndex * Row that was loaded (may be -1 if none). * @param columnIndex * Column that was loaded (may be -1 if none) */ void ConnectivityDataLoaded::setRowColumnLoading(const int64_t rowIndex, const int64_t columnIndex) { reset(); if (rowIndex >= 0) { m_mode = MODE_ROW; m_rowIndex = rowIndex; } else if (columnIndex >= 0) { m_mode = MODE_COLUMN; m_columnIndex = columnIndex; } else { CaretAssertMessage(0, "One or row index or column index should be negative indicating that dimension was not loaded."); } } /** * Get the surface loading information (MODE_SURFACE_NODE) * One of rowIndex or columnIndex will be negative. * * @param structure * The surface structure. * @param surfaceNumberOfNodes * Number of nodes in surface. * @param surfaceNodeIndex * Index of the surface node. * @param rowIndex * Index of row corresponding to the surface node (may be -1 if none). * @param columnIndex * Index of row corresponding to the surface node (may be -1 if none). */ void ConnectivityDataLoaded::getSurfaceNodeLoading(StructureEnum::Enum& structure, int32_t& surfaceNumberOfNodes, int32_t& surfaceNodeIndex, int64_t& rowIndex, int64_t& columnIndex) const { structure = m_surfaceStructure; surfaceNumberOfNodes = m_surfaceNumberOfNodes; if (m_surfaceNodeIndices.empty() == false) { surfaceNodeIndex = m_surfaceNodeIndices[0]; } else { surfaceNodeIndex = -1; } rowIndex = m_rowIndex; columnIndex = m_columnIndex; } /** * Set the surface loading information (MODE_SURFACE_NODE) * One of rowIndex or columnIndex must be negative. * * @param structure * The surface structure. * @param surfaceNumberOfNodes * Number of nodes in surface. * @param surfaceNodeIndex * Index of the surface node. * @param rowIndex * Index of row corresponding to the surface node (may be -1 if none). * @param columnIndex * Index of column corresponding to the surface node (may be -1 if none). */ void ConnectivityDataLoaded::setSurfaceNodeLoading(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const int32_t surfaceNodeIndex, const int64_t rowIndex, const int64_t columnIndex) { reset(); m_mode = MODE_SURFACE_NODE; m_surfaceStructure = structure; m_surfaceNumberOfNodes = surfaceNumberOfNodes; m_surfaceNodeIndices.push_back(surfaceNodeIndex); m_rowIndex = rowIndex; m_columnIndex = columnIndex; if ((rowIndex >= 0) && (columnIndex >= 0)) { CaretAssertMessage(0, "One of row or column index must be negative."); } } /** * Get the surface average node loading information (MODE_SURFACE_NODE_AVERAGE) * * @param structure * The surface structure. * @param surfaceNumberOfNodes * Number of nodes in surface. * @param surfaceNodeIndices * Indices of the surface nodes. */ void ConnectivityDataLoaded::getSurfaceAverageNodeLoading(StructureEnum::Enum& structure, int32_t& surfaceNumberOfNodes, std::vector& surfaceNodeIndices) const { structure = m_surfaceStructure; surfaceNumberOfNodes = m_surfaceNumberOfNodes; surfaceNodeIndices = m_surfaceNodeIndices; } /** * Set the surface average node loading information (MODE_SURFACE_NODE_AVERAGE) * * @param structure * The surface structure. * @param surfaceNumberOfNodes * Number of nodes in surface. * @param surfaceNodeIndices * Indices of the surface nodes. */ void ConnectivityDataLoaded::setSurfaceAverageNodeLoading(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const std::vector& surfaceNodeIndices) { reset(); m_mode = MODE_SURFACE_NODE_AVERAGE; m_surfaceStructure = structure; m_surfaceNumberOfNodes = surfaceNumberOfNodes; m_surfaceNodeIndices = surfaceNodeIndices; m_rowIndex = -1; m_columnIndex = -1; } /** * Get the volume loading XYZ coordinate (MODE_VOXEL_XYZ). * * @param volumeXYZ * Coordinate of location. * @param rowIndex * Index of row corresponding to the voxel (may be -1 if none). * @param columnIndex * Index of column corresponding to the voxel (may be -1 if none). */ void ConnectivityDataLoaded::getVolumeXYZLoading(float volumeXYZ[3], int64_t& rowIndex, int64_t& columnIndex) const { volumeXYZ[0] = m_volumeXYZ[0]; volumeXYZ[1] = m_volumeXYZ[1]; volumeXYZ[2] = m_volumeXYZ[2]; rowIndex = m_rowIndex; columnIndex = m_columnIndex; } /** * Set the volume loading XYZ coordinate (MODE_VOXEL_XYZ). * * @param volumeXYZ * Coordinate of location. * @param rowIndex * Index of row corresponding to the voxel(may be -1 if none). * @param columnIndex * Index of column corresponding to the voxel (may be -1 if none). */ void ConnectivityDataLoaded::setVolumeXYZLoading(const float volumeXYZ[3], const int64_t rowIndex, const int64_t columnIndex) { reset(); m_mode = MODE_VOXEL_XYZ; m_volumeXYZ[0] = volumeXYZ[0]; m_volumeXYZ[1] = volumeXYZ[1]; m_volumeXYZ[2] = volumeXYZ[2]; m_rowIndex = rowIndex; m_columnIndex = columnIndex; } /** * Get the voxel average loading voxel IJK indices (MODE_VOXEL_IJK_AVERAGE) * * @param voxelIndicesIJK * Indices of the voxels. */ void ConnectivityDataLoaded::getVolumeAverageVoxelLoading(int64_t volumeDimensionsIJK[3], std::vector& voxelIndicesIJK) const { volumeDimensionsIJK[0] = m_volumeDimensionsIJK[0]; volumeDimensionsIJK[1] = m_volumeDimensionsIJK[1]; volumeDimensionsIJK[2] = m_volumeDimensionsIJK[2]; voxelIndicesIJK = m_voxelIndices; } /** * Set the voxel average loading voxel IJK indices (MODE_VOXEL_IJK_AVERAGE) * * @param voxelIndicesIJK * Indices of the voxels. */ void ConnectivityDataLoaded::setVolumeAverageVoxelLoading(const int64_t volumeDimensionsIJK[3], const std::vector& voxelIndicesIJK) { reset(); m_volumeDimensionsIJK[0] = volumeDimensionsIJK[0]; m_volumeDimensionsIJK[1] = volumeDimensionsIJK[1]; m_volumeDimensionsIJK[2] = volumeDimensionsIJK[2]; m_mode = MODE_VOXEL_IJK_AVERAGE; m_voxelIndices = voxelIndicesIJK; m_rowIndex = -1; m_columnIndex = -1; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. May be NULL for some types of scenes. */ void ConnectivityDataLoaded::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { reset(); if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); m_mode = MODE_NONE; const AString modeName = sceneClass->getStringValue("m_mode"); if (modeName == "MODE_NONE") { m_mode = MODE_NONE; } else if (modeName == "MODE_ROW") { m_mode = MODE_ROW; } else if (modeName == "MODE_COLUMN") { m_mode = MODE_COLUMN; } else if (modeName == "MODE_SURFACE_NODE_AVERAGE") { m_mode = MODE_SURFACE_NODE_AVERAGE; } else if (modeName == "MODE_SURFACE_NODE") { m_mode = MODE_SURFACE_NODE; } else if (modeName == "MODE_VOXEL_XYZ") { m_mode = MODE_VOXEL_XYZ; } else if (modeName == "MODE_VOXEL_IJK_AVERAGE") { m_mode = MODE_VOXEL_IJK_AVERAGE; } else { sceneAttributes->addToErrorMessage("Unrecognized mode=" + modeName); return; } const ScenePrimitiveArray* surfaceNodeIndicesArray = sceneClass->getPrimitiveArray("m_surfaceNodeIndices"); if (surfaceNodeIndicesArray != NULL) { const int32_t numNodeIndices = surfaceNodeIndicesArray->getNumberOfArrayElements(); m_surfaceNodeIndices.reserve(numNodeIndices); for (int32_t i = 0; i < numNodeIndices; i++) { m_surfaceNodeIndices.push_back(surfaceNodeIndicesArray->integerValue(i)); } } const ScenePrimitiveArray* voxelIndicesArray = sceneClass->getPrimitiveArray("m_voxelIndices"); if (voxelIndicesArray != NULL) { const int64_t numIndices = voxelIndicesArray->getNumberOfArrayElements(); const int64_t numVoxelIndices = numIndices / 3; for (int64_t i = 0; i < numVoxelIndices; i++) { const int64_t i3 = i * 3; VoxelIJK voxelIJK(voxelIndicesArray->integerValue(i3), voxelIndicesArray->integerValue(i3 + 1), voxelIndicesArray->integerValue(i3 + 2)); m_voxelIndices.push_back(voxelIJK); } } } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* ConnectivityDataLoaded::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ConnectivityDataLoaded", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); AString modeName = "MODE_NONE"; switch (m_mode) { case MODE_NONE: modeName = "MODE_NONE"; break; case MODE_ROW: modeName = "MODE_ROW"; break; case MODE_COLUMN: modeName = "MODE_COLUMN"; break; case MODE_SURFACE_NODE: modeName = "MODE_SURFACE_NODE"; break; case MODE_SURFACE_NODE_AVERAGE: modeName = "MODE_SURFACE_NODE_AVERAGE"; break; case MODE_VOXEL_XYZ: modeName = "MODE_VOXEL_XYZ"; break; case MODE_VOXEL_IJK_AVERAGE: modeName = "MODE_VOXEL_IJK_AVERAGE"; break; } sceneClass->addString("m_mode", modeName); if (m_surfaceNodeIndices.empty() == false) { sceneClass->addIntegerArray("m_surfaceNodeIndices", &m_surfaceNodeIndices[0], m_surfaceNodeIndices.size()); } if (m_voxelIndices.empty() == false) { const int32_t numVoxels = m_voxelIndices.size(); std::vector indices; for (int32_t i = 0; i < numVoxels; i++) { indices.push_back(m_voxelIndices[i].m_ijk[0]); indices.push_back(m_voxelIndices[i].m_ijk[1]); indices.push_back(m_voxelIndices[i].m_ijk[2]); } sceneClass->addIntegerArray("m_voxelIndices", &indices[0], indices.size()); } return sceneClass; } connectome-workbench-1.4.2/src/Files/ConnectivityDataLoaded.h000066400000000000000000000115171360521144700242230ustar00rootroot00000000000000#ifndef __CONNECTIVITY_DATA_LOADED_H__ #define __CONNECTIVITY_DATA_LOADED_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "SceneableInterface.h" #include "StructureEnum.h" #include "VoxelIJK.h" namespace caret { class SceneClassAssistant; class SurfaceFile; class ConnectivityDataLoaded : public CaretObject, public SceneableInterface { public: ConnectivityDataLoaded(); virtual ~ConnectivityDataLoaded(); private: ConnectivityDataLoaded(const ConnectivityDataLoaded&); ConnectivityDataLoaded& operator=(const ConnectivityDataLoaded&); public: enum Mode { MODE_NONE, MODE_ROW, MODE_COLUMN, MODE_SURFACE_NODE, MODE_SURFACE_NODE_AVERAGE, MODE_VOXEL_XYZ, MODE_VOXEL_IJK_AVERAGE }; void reset(); Mode getMode() const; void getRowColumnLoading(int64_t& rowIndex, int64_t& columnIndex) const; void setRowColumnLoading(const int64_t rowIndex, const int64_t columnIndex); void getSurfaceNodeLoading(StructureEnum::Enum& structure, int32_t& surfaceNumberOfNodes, int32_t& surfaceNodeIndex, int64_t& rowIndex, int64_t& columnIndex) const; void setSurfaceNodeLoading(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const int32_t surfaceNodeIndex, const int64_t rowIndex, const int64_t columnIndex); void getSurfaceAverageNodeLoading(StructureEnum::Enum& structure, int32_t& surfaceNumberOfNode, std::vector& surfaceNodeIndices) const; void setSurfaceAverageNodeLoading(const StructureEnum::Enum structure, const int32_t surfaceNumberOfNodes, const std::vector& surfaceNodeIndices); void getVolumeXYZLoading(float volumeXYZ[3], int64_t& rowIndex, int64_t& columnIndex) const; void setVolumeXYZLoading(const float volumeXYZ[3], const int64_t rowIndex, const int64_t columnIndex); void getVolumeAverageVoxelLoading(int64_t volumeDimensionsIJK[3], std::vector& voxelIndicesIJK) const; void setVolumeAverageVoxelLoading(const int64_t volumeDimensionsIJK[3], const std::vector& voxelIndicesIJK); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); private: // ADD_NEW_MEMBERS_HERE SceneClassAssistant* m_sceneAssistant; Mode m_mode; int32_t m_rowIndex; int32_t m_columnIndex; StructureEnum::Enum m_surfaceStructure; int32_t m_surfaceNumberOfNodes; std::vector m_surfaceNodeIndices; std::vector m_voxelIndices; int32_t m_volumeDimensionsIJK[3]; float m_volumeXYZ[3]; }; #ifdef __CONNECTIVITY_DATA_LOADED_DECLARE__ // #endif // __CONNECTIVITY_DATA_LOADED_DECLARE__ } // namespace #endif // __CONNECTIVITY_DATA_LOADED_H__ connectome-workbench-1.4.2/src/Files/ControlPointFile.cxx000066400000000000000000000261071360521144700234500ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CONTROL_POINT_FILE_DECLARE__ #include "ControlPointFile.h" #undef __CONTROL_POINT_FILE_DECLARE__ #include "CaretAssert.h" #include "ControlPoint3D.h" #include "DataFileException.h" #include "GiftiMetaData.h" #include "Matrix4x4.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ControlPointFile * \brief File containing control points used for data transformations. * \ingroup Files */ /** * Constructor. */ ControlPointFile::ControlPointFile() : CaretDataFile(DataFileTypeEnum::UNKNOWN) { m_metadata.grabNew(new GiftiMetaData()); m_sceneAssistant.grabNew(new SceneClassAssistant()); m_landmarkTransformationMatrix.grabNew(new Matrix4x4()); // addControlPoint(ControlPoint3D(151, 147, 0, -42, -81, 6)); // addControlPoint(ControlPoint3D(263, 126, 0, -10, -87, 6)); // addControlPoint(ControlPoint3D(250, 491, 0, -13, 20, 6)); // addControlPoint(ControlPoint3D(48, 105, 0, -58, -13, 11)); // addControlPoint(ControlPoint3D(140, 106, 0, -12, -13, 13)); // addControlPoint(ControlPoint3D(133, 196, 0, -17, -13, 58)); } /** * Destructor. */ ControlPointFile::~ControlPointFile() { clearPrivate(); } /** * @return True if this file is empty, else false. */ bool ControlPointFile::isEmpty() const { return m_controlPoints.empty(); } /** * @return The structure for this file. */ StructureEnum::Enum ControlPointFile::getStructure() const { return StructureEnum::ALL; } /** * Set the structure for this file. * @param structure * New structure for this file. */ void ControlPointFile::setStructure(const StructureEnum::Enum /*structure*/) { /* nothing */ } /** * @return Get access to the file's metadata. */ GiftiMetaData* ControlPointFile::getFileMetaData() { return m_metadata.getPointer(); } /** * @return Get access to unmodifiable file's metadata. */ const GiftiMetaData* ControlPointFile::getFileMetaData() const { return m_metadata.getPointer(); } /** * Clear the content of this file. * This method is virtual so do not call from constructor/destructor. */ void ControlPointFile::clear() { const AString nameOfFile = getFileName(); CaretDataFile::clear(); clearPrivate(); } /** * Clear the content of this file. */ void ControlPointFile::clearPrivate() { m_metadata->clear(); removeAllControlPoints(); m_landmarkTransformationMatrix->identity(); } /** * Add information about the content of this file. * * @param dataFileInformation * Will contain information about this file. */ void ControlPointFile::addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) { CaretDataFile::addToDataFileContentInformation(dataFileInformation); } /** * @return true if file is modified, else false. */ bool ControlPointFile::isModified() const { if (CaretDataFile::isModified()) { return true; } if (m_metadata->isModified()) { return true; } for (std::vector::const_iterator iter = m_controlPoints.begin(); iter != m_controlPoints.end(); iter++) { if ((*iter)->isModified()) { return true; } } return false; } /** * Clear the modified status of this file. */ void ControlPointFile::clearModified() { CaretDataFile::clearModified(); m_metadata->clearModified(); for (std::vector::const_iterator iter = m_controlPoints.begin(); iter != m_controlPoints.end(); iter++) { (*iter)->clearModified(); } m_landmarkTransformationMatrix->clearModified(); } /** * @return The number of control points. */ int32_t ControlPointFile::getNumberOfControlPoints() const { return m_controlPoints.size(); } /** * Add a control point. * * @param controlPoint * Control point to add. */ void ControlPointFile::addControlPoint(const ControlPoint3D& controlPoint) { m_controlPoints.push_back(new ControlPoint3D(controlPoint)); setModified(); } /** * @return Control point at the given index (const method). * * @param index * Index of the control point. */ const ControlPoint3D* ControlPointFile::getControlPointAtIndex(const int32_t index) const { CaretAssertVectorIndex(m_controlPoints, index); return m_controlPoints[index]; } /** * @return Control point at the given index. * * @param index * Index of the control point. */ ControlPoint3D* ControlPointFile::getControlPointAtIndex(const int32_t index) { CaretAssertVectorIndex(m_controlPoints, index); return m_controlPoints[index]; } /** * Remove all of the control points. */ void ControlPointFile::removeAllControlPoints() { for (std::vector::iterator iter = m_controlPoints.begin(); iter != m_controlPoints.end(); iter++) { delete *iter; } m_controlPoints.clear(); } /** * Remote the control point at the given index. * * @param index * Index of the control point. */ void ControlPointFile::removeControlPointAtIndex(const int32_t index) { CaretAssertVectorIndex(m_controlPoints, index); delete m_controlPoints[index]; m_controlPoints.erase(m_controlPoints.begin() + index); setModified(); } /** * Update the landmark transformation matrix from the control points. * The transformed position will be set in the control points if the * matrix is successfully created. * * @param errorMessageOutk * Contains error information upon exit. * @return True if landmark transformation matrix was successfully update, * else false. */ bool ControlPointFile::updateLandmarkTransformationMatrix(AString& errorMessageOut) { m_landmarkTransformationMatrix->identity(); errorMessageOut.clear(); bool successFlag = m_landmarkTransformationMatrix->createLandmarkTransformMatrix(m_controlPoints, errorMessageOut); const int32_t numCP = getNumberOfControlPoints(); for (int32_t icp = 0; icp < numCP; icp++) { float transformedXYZ[3] = { 0.0, 0.0, 0.0 }; CaretAssertVectorIndex(m_controlPoints, icp); ControlPoint3D* cp = m_controlPoints[icp]; if (successFlag) { cp->getSourceXYZ(transformedXYZ); m_landmarkTransformationMatrix->multiplyPoint3(transformedXYZ); } cp->setTransformedXYZ(transformedXYZ); } return successFlag; } /** * @return The landmark transformation matrix. */ Matrix4x4* ControlPointFile::getLandmarkTransformationMatrix() { return m_landmarkTransformationMatrix; } /** * @return The landmark transformation matrix (const method). */ const Matrix4x4* ControlPointFile::getLandmarkTransformationMatrix() const { return m_landmarkTransformationMatrix; } /** * Read the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully read. */ void ControlPointFile::readFile(const AString& filename) { clear(); checkFileReadability(filename); throw DataFileException("Reading of Control Point files not implemented"); // AnnotationFileXmlReader reader; // reader.readFile(filename, // this); // // updateUniqueKeysAfterReadingFile(); setFileName(filename); clearModified(); } /** * Write the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully written. */ void ControlPointFile::writeFile(const AString& filename) { checkFileWritability(filename); throw DataFileException("Writing of Control Point files not implemented"); setFileName(filename); // AnnotationFileXmlWriter writer; // writer.writeFile(this); clearModified(); } /** * Save subclass data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void ControlPointFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); std::vector controlPointsVector; const int32_t numCP = getNumberOfControlPoints(); for (int32_t icp = 0; icp < numCP; icp++) { const QString name("ControlPoint" + QString::number(icp)); controlPointsVector.push_back(m_controlPoints[icp]->saveToScene(sceneAttributes, name)); } SceneClassArray* classArray = new SceneClassArray("controlPointsArray", controlPointsVector); sceneClass->addChild(classArray); } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void ControlPointFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); const SceneClassArray* controlPointsArray = sceneClass->getClassArray("controlPointsArray"); if (controlPointsArray != NULL) { const int32_t numElements = controlPointsArray->getNumberOfArrayElements(); for (int32_t i = 0; i < numElements; i++) { const SceneClass* controlPointClass = controlPointsArray->getClassAtIndex(i); ControlPoint3D controlPoint(0, 0, 0, 0, 0, 0); controlPoint.restoreFromScene(sceneAttributes, controlPointClass); addControlPoint(controlPoint); } } } connectome-workbench-1.4.2/src/Files/ControlPointFile.h000066400000000000000000000070411360521144700230710ustar00rootroot00000000000000#ifndef __CONTROL_POINT_FILE_H__ #define __CONTROL_POINT_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretDataFile.h" #include "CaretPointer.h" namespace caret { class ControlPoint3D; class Matrix4x4; class SceneClassAssistant; class ControlPointFile : public CaretDataFile { public: ControlPointFile(); virtual ~ControlPointFile(); bool isEmpty() const; virtual void clear(); virtual StructureEnum::Enum getStructure() const; virtual void setStructure(const StructureEnum::Enum structure); virtual GiftiMetaData* getFileMetaData(); virtual const GiftiMetaData* getFileMetaData() const; virtual void readFile(const AString& filename); virtual void writeFile(const AString& filename); virtual bool isModified() const; virtual void clearModified(); virtual void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation); int32_t getNumberOfControlPoints() const; void addControlPoint(const ControlPoint3D& controlPoint); const ControlPoint3D* getControlPointAtIndex(const int32_t index) const; ControlPoint3D* getControlPointAtIndex(const int32_t index); void removeAllControlPoints(); void removeControlPointAtIndex(const int32_t index); bool updateLandmarkTransformationMatrix(AString& errorMessageOut); Matrix4x4* getLandmarkTransformationMatrix(); const Matrix4x4* getLandmarkTransformationMatrix() const; // ADD_NEW_METHODS_HERE protected: virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: ControlPointFile(const ControlPointFile&); ControlPointFile& operator=(const ControlPointFile&); void clearPrivate(); CaretPointer m_metadata; CaretPointer m_sceneAssistant; std::vector m_controlPoints; CaretPointer m_landmarkTransformationMatrix; // ADD_NEW_MEMBERS_HERE }; #ifdef __CONTROL_POINT_FILE_DECLARE__ // #endif // __CONTROL_POINT_FILE_DECLARE__ } // namespace #endif //__CONTROL_POINT_FILE_H__ connectome-workbench-1.4.2/src/Files/EventCaretDataFilesGet.cxx000066400000000000000000000121331360521144700244650ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_CARET_DATA_FILES_GET_DECLARE__ #include "EventCaretDataFilesGet.h" #undef __EVENT_CARET_DATA_FILES_GET_DECLARE__ #include "CaretAssert.h" #include "CaretDataFile.h" #include "EventManager.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventCaretDataFilesGet * \brief Event to get CaretDataFiles * \ingroup Files */ /** * Constructor. * * @param structure * Structure. * @param dataFileTypes * Type of data files. */ EventCaretDataFilesGet::EventCaretDataFilesGet(const StructureEnum::Enum structure, const std::vector& dataFileTypes) : Event(EventTypeEnum::EVENT_CARET_DATA_FILES_GET) , m_structure(structure), m_dataFileTypes(dataFileTypes) { } /** * Destructor. */ EventCaretDataFilesGet::~EventCaretDataFilesGet() { } std::vector EventCaretDataFilesGet::getAllCaretDataFiles() { std::vector types; std::vector files; run(StructureEnum::ALL, types, files); return files; } /** * @return All data files of the given data file type. * * @param dataFileType * Type of data file. */ std::vector EventCaretDataFilesGet::getCaretDataFilesForType(const DataFileTypeEnum::Enum dataFileType) { std::vector types; types.push_back(dataFileType); std::vector files; run(StructureEnum::ALL, types, files); return files; } /** * @return All data files of the given multiple data file types. * * @param dataFileTypes * Types of data files. */ std::vector EventCaretDataFilesGet::getCaretDataFilesForTypes(const std::vector& dataFileTypes) { std::vector files; run(StructureEnum::ALL, dataFileTypes, files); return files; } /** * @return All data files of the given structure and multiple data file types. * * @param structure * Structure. * @param dataFileTypes * Type of data files. */ std::vector EventCaretDataFilesGet::getCaretDataFilesForStructureAndTypes(const StructureEnum::Enum structure, const std::vector& dataFileTypes) { std::vector files; run(structure, dataFileTypes, files); return files; } /** * Add all caret data files (called by Brain). This method will filter the * data files to meet the selection criteria. * * @param caretDataFiles * All caret data files. */ void EventCaretDataFilesGet::addAllCaretDataFiles(std::vector& caretDataFiles) { m_caretDataFiles = caretDataFiles; } /** * Run the event to get files of the specified criteria. * * @param structure * Structure. * @param dataFileTypes * Type of data files. * @param caretDataFilesOut * Output with caret data files matching selection criteria. */ void EventCaretDataFilesGet::run(const StructureEnum::Enum structure, const std::vector& dataFileTypes, std::vector& caretDataFilesOut) { caretDataFilesOut.clear(); EventCaretDataFilesGet instance(structure, dataFileTypes); EventManager::get()->sendEvent(instance.getPointer()); /* * If data file types is empty it implies ALL file types */ const bool allDataFileTypesFlag = dataFileTypes.empty(); for (auto dataFile : instance.m_caretDataFiles) { /* * Match structure */ if (structure != StructureEnum::ALL) { if (structure != dataFile->getStructure()) { continue; } } /* * Test data file type */ if (allDataFileTypesFlag) { caretDataFilesOut.push_back(dataFile); } else { if (std::find(dataFileTypes.begin(), dataFileTypes.end(), dataFile->getDataFileType()) != dataFileTypes.end()) { caretDataFilesOut.push_back(dataFile); } } } } connectome-workbench-1.4.2/src/Files/EventCaretDataFilesGet.h000066400000000000000000000055461360521144700241240ustar00rootroot00000000000000#ifndef __EVENT_CARET_DATA_FILES_GET_H__ #define __EVENT_CARET_DATA_FILES_GET_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "DataFileTypeEnum.h" #include "Event.h" #include "StructureEnum.h" namespace caret { class BorderFile; class CaretDataFile; class EventCaretDataFilesGet : public Event { public: virtual ~EventCaretDataFilesGet(); static std::vector getAllCaretDataFiles(); static std::vector getCaretDataFilesForType(const DataFileTypeEnum::Enum dataFileType); static std::vector getCaretDataFilesForTypes(const std::vector& dataFileTypes); static std::vector getCaretDataFilesForStructureAndTypes(const StructureEnum::Enum structure, const std::vector& dataFileTypes); void addAllCaretDataFiles(std::vector& caretDataFiles); // ADD_NEW_METHODS_HERE private: EventCaretDataFilesGet(const StructureEnum::Enum structure, const std::vector& dataFileTypes); EventCaretDataFilesGet(const EventCaretDataFilesGet&); EventCaretDataFilesGet& operator=(const EventCaretDataFilesGet&); static void run(const StructureEnum::Enum structure, const std::vector& dataFileTypes, std::vector& caretDataFilesOut); const StructureEnum::Enum m_structure; const std::vector& m_dataFileTypes; std::vector m_caretDataFiles; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_CARET_DATA_FILES_GET_DECLARE__ // #endif // __EVENT_CARET_DATA_FILES_GET_DECLARE__ } // namespace #endif //__EVENT_CARET_DATA_FILES_GET_H__ connectome-workbench-1.4.2/src/Files/EventCaretMappableDataFileMapsViewedInOverlays.cxx000066400000000000000000000046001360521144700313050ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS_DECLARE__ #include "EventCaretMappableDataFileMapsViewedInOverlays.h" #undef __EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventCaretMappableDataFileMapsViewedInOverlays * \brief Get maps viewed as an overlay for the given data file type * \ingroup Brain */ /** * Constructor. */ EventCaretMappableDataFileMapsViewedInOverlays::EventCaretMappableDataFileMapsViewedInOverlays(const CaretMappableDataFile* caretMappableDataFile) : Event(EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS), m_caretMappableDataFile(caretMappableDataFile) { CaretAssert(caretMappableDataFile); } /** * Destructor. */ EventCaretMappableDataFileMapsViewedInOverlays::~EventCaretMappableDataFileMapsViewedInOverlays() { } /** * @return The type of data file for which maps viewed as overlay are desired. */ const CaretMappableDataFile* EventCaretMappableDataFileMapsViewedInOverlays::getCaretMappableDataFile() const { return m_caretMappableDataFile; } /** * Add map index for caret mappable data file. * * @param mapIndex * Selected map index for data file. */ void EventCaretMappableDataFileMapsViewedInOverlays::addMapIndex(const int32_t mapIndex) { m_mapIndices.insert(mapIndex); } /** * @return Displayed as overlay map indices for file. */ std::set EventCaretMappableDataFileMapsViewedInOverlays::getSelectedMapIndices() const { return m_mapIndices; } connectome-workbench-1.4.2/src/Files/EventCaretMappableDataFileMapsViewedInOverlays.h000066400000000000000000000043661360521144700307430ustar00rootroot00000000000000#ifndef __EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS_H__ #define __EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class CaretMappableDataFile; class EventCaretMappableDataFileMapsViewedInOverlays : public Event { public: EventCaretMappableDataFileMapsViewedInOverlays(const CaretMappableDataFile* caretMappableDataFile); virtual ~EventCaretMappableDataFileMapsViewedInOverlays(); const CaretMappableDataFile* getCaretMappableDataFile() const; void addMapIndex(const int32_t mapIndex); std::set getSelectedMapIndices() const; // ADD_NEW_METHODS_HERE private: EventCaretMappableDataFileMapsViewedInOverlays(const EventCaretMappableDataFileMapsViewedInOverlays&); EventCaretMappableDataFileMapsViewedInOverlays& operator=(const EventCaretMappableDataFileMapsViewedInOverlays&); // ADD_NEW_MEMBERS_HERE const CaretMappableDataFile* m_caretMappableDataFile; std::set m_mapIndices; }; #ifdef __EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS_DECLARE__ // #endif // __EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS_DECLARE__ } // namespace #endif //__EVENT_CARET_MAPPABLE_DATA_FILE_MAPS_VIEWED_IN_OVERLAYS_H__ connectome-workbench-1.4.2/src/Files/EventCaretMappableDataFilesGet.cxx000066400000000000000000000054201360521144700261300ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretAssert.h" #include "CaretMappableDataFile.h" #include "EventCaretMappableDataFilesGet.h" using namespace caret; /** * Constructor for ALL map data files. */ EventCaretMappableDataFilesGet::EventCaretMappableDataFilesGet() : Event(EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILES_GET), m_mode(MODE_ANY_DATA_FILE_TYPE), m_oneDataFileType(DataFileTypeEnum::UNKNOWN) { } /** * Constructor for map data files of the given file type. * * @param dataFileType * Type of data files requested. */ EventCaretMappableDataFilesGet::EventCaretMappableDataFilesGet(const DataFileTypeEnum::Enum dataFileType) : Event(EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILES_GET), m_mode(MODE_ONE_DATA_FILE_TYPE), m_oneDataFileType(dataFileType) { } /** * Destructor. */ EventCaretMappableDataFilesGet::~EventCaretMappableDataFilesGet() { } /** * Add a map data file. * @param mapDataFile * Map data file that is added. */ void EventCaretMappableDataFilesGet::addFile(CaretMappableDataFile* mapDataFile) { CaretAssert(mapDataFile); if (mapDataFile->getNumberOfMaps() <= 0) { return; } const DataFileTypeEnum::Enum mapDataFileType = mapDataFile->getDataFileType(); /* * No surface files */ if (mapDataFileType == DataFileTypeEnum::SURFACE) { return; } /* * Based upon mode, perform additional filtering of file data type */ switch (m_mode) { case MODE_ONE_DATA_FILE_TYPE: if (mapDataFileType != m_oneDataFileType) { return; } break; case MODE_ANY_DATA_FILE_TYPE: break; } m_allCaretMappableDataFiles.push_back(mapDataFile); } /** * Get all map data files. * * @param allFilesOut * All map data files output. */ void EventCaretMappableDataFilesGet::getAllFiles(std::vector& allFilesOut) const { allFilesOut = m_allCaretMappableDataFiles; } connectome-workbench-1.4.2/src/Files/EventCaretMappableDataFilesGet.h000066400000000000000000000040431360521144700255550ustar00rootroot00000000000000#ifndef __EVENT_CARET_MAPPABLE_DATA_FILES_GET_H__ #define __EVENT_CARET_MAPPABLE_DATA_FILES_GET_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class CaretMappableDataFile; /// Event that gets all caret mappable data files. class EventCaretMappableDataFilesGet : public Event { public: EventCaretMappableDataFilesGet(); EventCaretMappableDataFilesGet(const DataFileTypeEnum::Enum dataFileType); virtual ~EventCaretMappableDataFilesGet(); void addFile(CaretMappableDataFile* mapDataFile); void getAllFiles(std::vector& allFilesOut) const; private: enum Mode { MODE_ANY_DATA_FILE_TYPE, MODE_ONE_DATA_FILE_TYPE }; EventCaretMappableDataFilesGet(const EventCaretMappableDataFilesGet&); EventCaretMappableDataFilesGet& operator=(const EventCaretMappableDataFilesGet&); const Mode m_mode; const DataFileTypeEnum::Enum m_oneDataFileType; std::vector m_allCaretMappableDataFiles; }; } // namespace #endif // __EVENT_CARET_MAPPABLE_DATA_FILES_GET_H__ connectome-workbench-1.4.2/src/Files/EventChartMatrixParcelYokingValidation.cxx000066400000000000000000000175011360521144700277670ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_CHART_MATRIX_PARCEL_LOADING_YOKING_DECLARE__ #include "EventChartMatrixParcelYokingValidation.h" #undef __EVENT_CHART_MATRIX_PARCEL_LOADING_YOKING_DECLARE__ #include "CaretAssert.h" #include "CaretMappableDataFile.h" #include "ChartableMatrixParcelInterface.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventChartMatrixParcelYokingValidation * \brief Event for coordination of Matrix Chart yoking. * \ingroup Files */ /** * Constructor for validating that the given file is compatible with any * current yoking for the given yoking group. After sending this event, * call isYokingCompatible() to validate the yoking selection. * * @param chartableInterface * The file for which yoking compatibility is verified. * @param yokingGroup * The selected yoking group. */ EventChartMatrixParcelYokingValidation::EventChartMatrixParcelYokingValidation(const ChartableMatrixParcelInterface* chartableInterface, const YokingGroupEnum::Enum yokingGroup) : Event(EventTypeEnum::EVENT_CHART_MATRIX_YOKING_VALIDATION), m_mode(MODE_VALIDATE_YOKING), m_chartableInterface(chartableInterface), m_yokingGroup(yokingGroup) { CaretAssert(chartableInterface); } /** * Destructor. */ EventChartMatrixParcelYokingValidation::~EventChartMatrixParcelYokingValidation() { } /** * @return The mode of this event (apply or validate). */ EventChartMatrixParcelYokingValidation::Mode EventChartMatrixParcelYokingValidation::getMode() const { return m_mode; } /** * Add chartable interface for validating yoking compatibility. * * @param chartableInterface * A file for which yoking compatibility is verified with the file passed * to the constructor. * @param selectedRowOrColumnIndex * Selected row or column index in the file. */ void EventChartMatrixParcelYokingValidation::addValidateYokingChartableInterface(const ChartableMatrixParcelInterface* chartableInterface, const int32_t selectedRowOrColumnIndex) { CaretAssert(chartableInterface); int32_t numberOfRowsColumns = -1; AString loadingDimensionName; int32_t numRows = -1; int32_t numCols = -1; m_chartableInterface->getMatrixDimensions(numRows, numCols); switch (m_chartableInterface->getMatrixLoadingDimension()) { case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: numberOfRowsColumns = numCols; loadingDimensionName = "columns"; break; case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: numberOfRowsColumns = numRows; loadingDimensionName = "rows"; break; } if (chartableInterface != m_chartableInterface) { if ((chartableInterface->getYokingGroup() == m_yokingGroup) && (chartableInterface->getYokingGroup() != YokingGroupEnum::YOKING_GROUP_OFF)) { int32_t chartInterNumRowsColumns = -1; AString chartDimensionsName; int32_t chartRows = -1; int32_t chartCols = -1; chartableInterface->getMatrixDimensions(chartRows, chartCols); switch (chartableInterface->getMatrixLoadingDimension()) { case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: chartInterNumRowsColumns = chartCols; chartDimensionsName = "columns"; break; case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: chartInterNumRowsColumns = chartRows; chartDimensionsName = "rows"; break; } if (numberOfRowsColumns != chartInterNumRowsColumns) { if (m_incompatibilityMessage.isEmpty()) { m_incompatibilityMessage.appendWithNewLine(m_chartableInterface->getMatrixChartCaretMappableDataFile()->getFileNameNoPath() + " is loading from " + AString::number(numberOfRowsColumns) + " " + loadingDimensionName); m_incompatibilityMessage.appendWithNewLine("and is incompatible with: "); } m_incompatibilityMessage.appendWithNewLine(" " + chartableInterface->getMatrixChartCaretMappableDataFile()->getFileNameNoPath() + " is loading from " + AString::number(chartInterNumRowsColumns) + " " + chartDimensionsName); } /* * For the map key is row/column index and value is number of times that * row column index is used. */ std::map::iterator iter = m_compatibleRowColumnIndicesCount.find(selectedRowOrColumnIndex); if (iter != m_compatibleRowColumnIndicesCount.end()) { iter->second++; } else { m_compatibleRowColumnIndicesCount.insert(std::make_pair(selectedRowOrColumnIndex, 1)); } } } } /** * Is the yoking for the file passed to the constructor validated with * other files yoked to the yoking group? * * @param messageOut * Contains information on compatibility. * @param selectedRowOrColumnIndexOut * Row or column index that should be selected if yoking is compatible. * @return * True if compatible, else false. */ bool EventChartMatrixParcelYokingValidation::isValidateYokingCompatible(AString& messageOut, int32_t& selectedRowOrColumnIndexOut) const { selectedRowOrColumnIndexOut = -1; messageOut = m_incompatibilityMessage; /* * For the map key is row/column index and value is number of times that * row column index is used. */ int32_t maxCount = 0; for (std::map::const_iterator iter = m_compatibleRowColumnIndicesCount.begin(); iter != m_compatibleRowColumnIndicesCount.end(); iter++) { if (iter->second > maxCount) { maxCount = iter->second; selectedRowOrColumnIndexOut = iter->first; } } if (messageOut.isEmpty()) { return true; } return false; } /** * @return Chartable interface for which this event was issued. */ const ChartableMatrixParcelInterface* EventChartMatrixParcelYokingValidation::getChartableMatrixParcelInterface() const { return m_chartableInterface; } connectome-workbench-1.4.2/src/Files/EventChartMatrixParcelYokingValidation.h000066400000000000000000000054741360521144700274220ustar00rootroot00000000000000#ifndef __EVENT_CHART_MATRIX_PARCEL_LOADING_YOKING_H__ #define __EVENT_CHART_MATRIX_PARCEL_LOADING_YOKING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" #include "YokingGroupEnum.h" namespace caret { class ChartableMatrixParcelInterface; class EventChartMatrixParcelYokingValidation : public Event { public: enum Mode { MODE_APPLY_YOKING, MODE_VALIDATE_YOKING }; EventChartMatrixParcelYokingValidation(const ChartableMatrixParcelInterface* chartableInterface, const YokingGroupEnum::Enum yokingGroup); virtual ~EventChartMatrixParcelYokingValidation(); Mode getMode() const; void addValidateYokingChartableInterface(const ChartableMatrixParcelInterface* chartableInterface, const int32_t selectedRowOrColumnIndex); bool isValidateYokingCompatible(AString& messageOut, int32_t& selectedRowOrColumnIndexOut) const; const ChartableMatrixParcelInterface* getChartableMatrixParcelInterface() const; // ADD_NEW_METHODS_HERE private: EventChartMatrixParcelYokingValidation(const EventChartMatrixParcelYokingValidation&); EventChartMatrixParcelYokingValidation& operator=(const EventChartMatrixParcelYokingValidation&); const Mode m_mode; const ChartableMatrixParcelInterface* m_chartableInterface; const YokingGroupEnum::Enum m_yokingGroup; AString m_incompatibilityMessage; std::map m_compatibleRowColumnIndicesCount; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_CHART_MATRIX_PARCEL_LOADING_YOKING_DECLARE__ // #endif // __EVENT_CHART_MATRIX_PARCEL_LOADING_YOKING_DECLARE__ } // namespace #endif //__EVENT_CHART_MATRIX_PARCEL_LOADING_YOKING_H__ connectome-workbench-1.4.2/src/Files/EventGetDisplayedDataFiles.cxx000066400000000000000000000137061360521144700253540ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __EVENT_GET_DISPLAYED_DATA_FILES_DECLARE__ #include "EventGetDisplayedDataFiles.h" #undef __EVENT_GET_DISPLAYED_DATA_FILES_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" #include "SurfaceFile.h" using namespace caret; /** * \class caret::EventGetDisplayedDataFiles * \brief Find data files displayed in some or all tabs. * \ingroup Files */ /** * Constructor for finding data files displayed in the given tab indices. * * param windowIndices * Indices of windows for displayed data files. * param tabIndices * Indices of tabs for displayed data files. */ EventGetDisplayedDataFiles::EventGetDisplayedDataFiles(const std::vector& windowIndices, const std::vector& tabIndices) : Event(EventTypeEnum::EVENT_GET_DISPLAYED_DATA_FILES) { m_tabIndices.insert(tabIndices.begin(), tabIndices.end()); m_windowIndices.insert(windowIndices.begin(), windowIndices.end()); } /** * Destructor. */ EventGetDisplayedDataFiles::~EventGetDisplayedDataFiles() { } /** * Is the tab index one for determining displayed data files. * * @param tabIndex * Index for displayed data files. * @return * True if the tab is one determining displayed data files. */ bool EventGetDisplayedDataFiles::isTestForDisplayedDataFileInTabIndex(const int32_t tabIndex) const { if (m_tabIndices.find(tabIndex) != m_tabIndices.end()) { return true; } return false; } /** * Is the window index one for determining displayed data files. * * @param windowIndex * Index for displayed data files. * @return * True if the window is one determining displayed data files. */ bool EventGetDisplayedDataFiles::isTestForDisplayedDataFileInWindowIndex(const int32_t windowIndex) const { if (m_windowIndices.find(windowIndex) != m_windowIndices.end()) { return true; } return false; } /** * Is the given surface structure displayed? * * @param surfaceStructure * The surface structure. * @return * True if the structure is displayed, else false. */ bool EventGetDisplayedDataFiles::isTestForDisplayedSurfaceStructure(const StructureEnum::Enum surfaceStructure) const { setupSurfaceStrucutures(); if (std::find(m_surfaceStructures.begin(), m_surfaceStructures.end(), surfaceStructure) != m_surfaceStructures.end()) { return true; } return false; } /** * Add the given file as a displayed data file. * * @param caretDataFile * Data file that is displayed. */ void EventGetDisplayedDataFiles::addDisplayedDataFile(const CaretDataFile* caretDataFile) { m_displayedDataFiles.insert(caretDataFile); } /* * Is the given data file displayed? * * @param caretDataFile * Caret data file for testing displayed in a tab. * @return * True if the file is displayed, else false. */ bool EventGetDisplayedDataFiles::isDataFileDisplayed(const CaretDataFile* caretDataFile) const { if (m_displayedDataFiles.find(caretDataFile) != m_displayedDataFiles.end()) { return true; } return false; } /** * @return The displayed data files in a set. */ std::set EventGetDisplayedDataFiles::getDisplayedDataFiles() const { return m_displayedDataFiles; } /** * @return The displayed surface structures. Must be called * AFTER event completes. */ std::vector EventGetDisplayedDataFiles::getDisplayedSurfaceStructures() const { setupSurfaceStrucutures(); return m_surfaceStructures; } /** * Setup the surface structures. */ void EventGetDisplayedDataFiles::setupSurfaceStrucutures() const { if ( ! m_surfaceStructuresValid) { std::set structureSet; for (std::set::const_iterator dataFileIter = m_displayedDataFiles.begin(); dataFileIter != m_displayedDataFiles.end(); dataFileIter++) { const CaretDataFile* dataFile = *dataFileIter; CaretAssert(dataFile); if (dataFile->getDataFileType() == DataFileTypeEnum::SURFACE) { const SurfaceFile* surfaceFile = dynamic_cast(dataFile); CaretAssert(surfaceFile); structureSet.insert(surfaceFile->getStructure()); } } m_surfaceStructures.insert(m_surfaceStructures.end(), structureSet.begin(), structureSet.end()); m_surfaceStructuresValid = true; } } /** * @return The tab indices. */ std::vector EventGetDisplayedDataFiles::getTabIndices() const { std::vector tabVector(m_tabIndices.begin(), m_tabIndices.end()); return tabVector; } /** * @return The window indices. */ std::vector EventGetDisplayedDataFiles::getWindowIndices() const { std::vector windowVector(m_windowIndices.begin(), m_windowIndices.end()); return windowVector; } connectome-workbench-1.4.2/src/Files/EventGetDisplayedDataFiles.h000066400000000000000000000055611360521144700250010ustar00rootroot00000000000000#ifndef __EVENT_GET_DISPLAYED_DATA_FILES_H__ #define __EVENT_GET_DISPLAYED_DATA_FILES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" #include "StructureEnum.h" namespace caret { class CaretDataFile; class EventGetDisplayedDataFiles : public Event { public: EventGetDisplayedDataFiles(const std::vector& windowIndices, const std::vector& tabIndices); virtual ~EventGetDisplayedDataFiles(); bool isTestForDisplayedDataFileInTabIndex(const int32_t tabIndex) const; bool isTestForDisplayedDataFileInWindowIndex(const int32_t windowIndex) const; bool isTestForDisplayedSurfaceStructure(const StructureEnum::Enum surfaceStructure) const; void addDisplayedDataFile(const CaretDataFile* caretDataFile); bool isDataFileDisplayed(const CaretDataFile* caretDataFile) const; std::set getDisplayedDataFiles() const; std::vector getTabIndices() const; std::vector getWindowIndices() const; std::vector getDisplayedSurfaceStructures() const; private: EventGetDisplayedDataFiles(const EventGetDisplayedDataFiles&); EventGetDisplayedDataFiles& operator=(const EventGetDisplayedDataFiles&); public: // ADD_NEW_METHODS_HERE private: void setupSurfaceStrucutures() const; // ADD_NEW_MEMBERS_HERE std::set m_windowIndices; std::set m_tabIndices; std::set m_displayedDataFiles; mutable std::vector m_surfaceStructures; mutable bool m_surfaceStructuresValid; }; #ifdef __EVENT_GET_DISPLAYED_DATA_FILES_DECLARE__ // #endif // __EVENT_GET_DISPLAYED_DATA_FILES_DECLARE__ } // namespace #endif //__EVENT_GET_DISPLAYED_DATA_FILES_H__ connectome-workbench-1.4.2/src/Files/EventMapYokingSelectMap.cxx000066400000000000000000000066521360521144700247170ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_MAP_YOKING_SELECT_MAP_DECLARE__ #include "EventMapYokingSelectMap.h" #undef __EVENT_MAP_YOKING_SELECT_MAP_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventMapYokingSelectMap * \brief Event sent when a yoked overlay or file selection changes. * \ingroup Files */ /** * Constructor for change in map yoking. * * @param mapYokingGroup * Map yoking group that has a status change (selected map or enabled status) * @param caretMappableDataFile * Caret mappable file that is causing this event. * @param mapIndex * Index of map selected. * @param selectionStatus * Status of selection. */ EventMapYokingSelectMap::EventMapYokingSelectMap(const MapYokingGroupEnum::Enum mapYokingGroup, const CaretMappableDataFile* caretMappableDataFile, const AnnotationTextSubstitutionFile* annotationTextSubstitutionFile, const int32_t mapIndex, const bool mapOverlaySelectionStatus) : Event(EventTypeEnum::EVENT_MAP_YOKING_SELECT_MAP), m_mapYokingGroup(mapYokingGroup), m_caretMappableDataFile(caretMappableDataFile), m_annotationTextSubstitutionFile(annotationTextSubstitutionFile), m_mapIndex(mapIndex), m_selectionStatus(mapOverlaySelectionStatus) { if (mapYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { MapYokingGroupEnum::setSelectedMapIndex(mapYokingGroup, mapIndex); MapYokingGroupEnum::setEnabled(mapYokingGroup, mapOverlaySelectionStatus); } } /** * Destructor. */ EventMapYokingSelectMap::~EventMapYokingSelectMap() { } /** * @return The map yoking group. */ MapYokingGroupEnum::Enum EventMapYokingSelectMap::getMapYokingGroup() const { return m_mapYokingGroup; } /** * @return Caret Mappable Data File for which event was issued. * Might be NULL. */ const CaretMappableDataFile* EventMapYokingSelectMap::getCaretMappableDataFile() const { return m_caretMappableDataFile; } /** * @return Annotation text substitution file for which event was issued. * Might be NULL. */ const AnnotationTextSubstitutionFile* EventMapYokingSelectMap::getAnnotationTextSubstitutionFile() const { return m_annotationTextSubstitutionFile; } /** * @return Map index selected. */ int32_t EventMapYokingSelectMap::getMapIndex() const { return m_mapIndex; } /** * @return Selection status but ONLY for SAME FILE ! */ bool EventMapYokingSelectMap::getSelectionStatus() const { return m_selectionStatus; } connectome-workbench-1.4.2/src/Files/EventMapYokingSelectMap.h000066400000000000000000000051731360521144700243410ustar00rootroot00000000000000#ifndef __EVENT_MAP_YOKING_SELECT_MAP_H__ #define __EVENT_MAP_YOKING_SELECT_MAP_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" #include "MapYokingGroupEnum.h" namespace caret { class AnnotationTextSubstitutionFile; class CaretMappableDataFile; class EventMapYokingSelectMap : public Event { public: EventMapYokingSelectMap(const MapYokingGroupEnum::Enum mapYokingGroup, const CaretMappableDataFile* caretMappableDataFile, const AnnotationTextSubstitutionFile* annotationTextSubstitutionFile, const int32_t mapIndex, const bool selectionStatus); virtual ~EventMapYokingSelectMap(); MapYokingGroupEnum::Enum getMapYokingGroup() const; const CaretMappableDataFile* getCaretMappableDataFile() const; const AnnotationTextSubstitutionFile* getAnnotationTextSubstitutionFile() const; int32_t getMapIndex() const; bool getSelectionStatus() const; // ADD_NEW_METHODS_HERE private: EventMapYokingSelectMap(const EventMapYokingSelectMap&); EventMapYokingSelectMap& operator=(const EventMapYokingSelectMap&); const MapYokingGroupEnum::Enum m_mapYokingGroup; const CaretMappableDataFile* m_caretMappableDataFile; const AnnotationTextSubstitutionFile* m_annotationTextSubstitutionFile; const int32_t m_mapIndex; const bool m_selectionStatus; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_MAP_YOKING_SELECT_MAP_DECLARE__ // #endif // __EVENT_MAP_YOKING_SELECT_MAP_DECLARE__ } // namespace #endif //__EVENT_MAP_YOKING_SELECT_MAP_H__ connectome-workbench-1.4.2/src/Files/EventMapYokingValidation.cxx000066400000000000000000000215301360521144700251240ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __EVENT_MAP_YOKING_VALIDATION_DECLARE__ #include "EventMapYokingValidation.h" #undef __EVENT_MAP_YOKING_VALIDATION_DECLARE__ #include "AnnotationTextSubstitutionFile.h" #include "BrainConstants.h" #include "CaretAssert.h" #include "CaretMappableDataFile.h" #include "EventBrowserTabIndicesGetAll.h" #include "EventManager.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventMapYokingValidation * \brief Get map files yoked to a mapping group for validation. * \ingroup Files * * When the user selects map yoking for a file, verify that the new * file contains the same number of maps as any other files using * the same yoking group. If not, warn the user. */ /** * Constructor for validation files with map yoked to the given yoking group. * * @param mapYokingGroup * The map yoking group that will be validated for compatibility. */ EventMapYokingValidation::EventMapYokingValidation(const MapYokingGroupEnum::Enum mapYokingGroup) : Event(EventTypeEnum::EVENT_MAP_YOKING_VALIDATION), m_mapYokingGroup(mapYokingGroup) { EventBrowserTabIndicesGetAll allTabsEvent; EventManager::get()->sendEvent(allTabsEvent.getPointer()); m_validTabIndices = allTabsEvent.getAllBrowserTabIndices(); } /** * Destructor. */ EventMapYokingValidation::~EventMapYokingValidation() { } /** * Add a map file, if it is yoked to the same yoking group, so that it * may be used in the compatibility test. * * @param caretMapFile * The map file. * @param mapYokingGroup * Yoking group status of the file * @param tabIndex * Index of tab in which the file is displayed. */ void EventMapYokingValidation::addMapYokedFile(const CaretMappableDataFile* caretMapFile, const MapYokingGroupEnum::Enum mapYokingGroup, const int32_t tabIndex) { CaretAssert(caretMapFile); if (mapYokingGroup == MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { return; } if (mapYokingGroup != m_mapYokingGroup) { return; } if (std::find(m_validTabIndices.begin(), m_validTabIndices.end(), tabIndex) == m_validTabIndices.end()) { return; } m_yokedFileInfo.insert(YokedFileInfo(NULL, caretMapFile, tabIndex)); } /** * Add a annotation text substitution file, if it is yoked to the same yoking group, * so that it may be used in the compatibility test. * * @param annTextSubFile * The annotation text substitution file. * @param mapYokingGroup * Yoking group status of the file */ void EventMapYokingValidation::addAnnotationTextSubstitutionFile(const AnnotationTextSubstitutionFile* annTextSubFile, const MapYokingGroupEnum::Enum mapYokingGroup) { CaretAssert(annTextSubFile); if (mapYokingGroup == MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { return; } if (mapYokingGroup != m_mapYokingGroup) { return; } m_yokedFileInfo.insert(YokedFileInfo(annTextSubFile, NULL, -1)); } /** * Add a map file, if it is yoked to the same yoking group, so that it * may be used in the compatibility test. * * @param caretMapFile * The map file. * @param mapYokingGroupsForAllTabs * Yoking group status of the file for all tabs. Number of elements * MUST BE BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS. */ void EventMapYokingValidation::addMapYokedFileAllTabs(const CaretMappableDataFile* caretMapFile, const MapYokingGroupEnum::Enum* mapYokingGroupsForAllTabs) { CaretAssert(caretMapFile); for (int32_t iTab = 0; iTab < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; iTab++) { if (mapYokingGroupsForAllTabs[iTab] == MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { continue; } if (mapYokingGroupsForAllTabs[iTab] != m_mapYokingGroup) { continue; } if (std::find(m_validTabIndices.begin(), m_validTabIndices.end(), iTab) == m_validTabIndices.end()) { continue; } m_yokedFileInfo.insert(YokedFileInfo(NULL, caretMapFile, iTab)); } } /** * @return The map yoking group. */ MapYokingGroupEnum::Enum EventMapYokingValidation::getMapYokingGroup() const { return m_mapYokingGroup; } /** * Validate the file for compatibility. * * @param annTextSubFile * The annotation text substitution file. * @param caretMapFile * The map file. * @param numberOfYokedFilesOut * Number of files, excluding the given file, currently yoked * to this yoking group. * @param messageOut * Message containing information about any incompatibility. * @return * True if new file is compatible with any existing yoked files, else false. */ bool EventMapYokingValidation::validateCompatibility(const AnnotationTextSubstitutionFile* annTextSubFile, const CaretMappableDataFile* caretMapFile, int32_t& numberOfYokedFilesOut, AString& messageOut) const { numberOfYokedFilesOut = 0; messageOut = ""; AString filename; int32_t numberOfMaps = 0; AString message; if (annTextSubFile != NULL) { filename = annTextSubFile->getFileNameNoPath(); numberOfMaps = annTextSubFile->getNumberOfValues(); message = (AString::number(numberOfMaps) + " substitution values in "); } else if (caretMapFile != NULL) { filename = caretMapFile->getFileNameNoPath(); numberOfMaps = caretMapFile->getNumberOfMaps(); message = (AString::number(numberOfMaps) + " maps in "); } else { CaretAssert(0); } for (std::set::const_iterator iter = m_yokedFileInfo.begin(); iter != m_yokedFileInfo.end(); iter++) { const YokedFileInfo& yfi = *iter; numberOfYokedFilesOut++; if (yfi.m_numberOfMaps != numberOfMaps) { messageOut.appendWithNewLine(" " + yfi.m_infoText); } } if (messageOut.isEmpty()) { return true; } const AString fileInfo("Incompatibilities for yoking:\n" + message + filename + "\n\n"); messageOut.insert(0, fileInfo); return false; } /** * Constructor for yoked file information. * * @param annTextSubFile * The annotation text substitution file. * @param caretMapFile * The map file. * @param tabIndex * Index of tab in which the file is displayed. */ EventMapYokingValidation::YokedFileInfo::YokedFileInfo(const AnnotationTextSubstitutionFile* annTextSubFile, const CaretMappableDataFile* caretMapFile, const int32_t tabIndex) : m_annTextSubFile(annTextSubFile), m_mapFile(caretMapFile), m_tabIndex(tabIndex) { if (m_annTextSubFile != NULL) { m_numberOfMaps = annTextSubFile->getNumberOfValues(); m_infoText = (AString::number(m_numberOfMaps) + " substitution values in " + m_annTextSubFile->getFileNameNoPath()); } else if (m_mapFile != NULL) { m_numberOfMaps = caretMapFile->getNumberOfMaps(); m_infoText = (AString::number(m_numberOfMaps) + " maps in tab " + AString::number(tabIndex + 1) + " file: " + caretMapFile->getFileNameNoPath()); } else { CaretAssert(0); } } connectome-workbench-1.4.2/src/Files/EventMapYokingValidation.h000066400000000000000000000070131360521144700245510ustar00rootroot00000000000000#ifndef __EVENT_MAP_YOKING_VALIDATION_H__ #define __EVENT_MAP_YOKING_VALIDATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" #include "MapYokingGroupEnum.h" namespace caret { class AnnotationTextSubstitutionFile; class CaretMappableDataFile; class EventMapYokingValidation : public Event { public: EventMapYokingValidation(const MapYokingGroupEnum::Enum mapYokingGroup); virtual ~EventMapYokingValidation(); void addMapYokedFile(const CaretMappableDataFile* caretMapFile, const MapYokingGroupEnum::Enum mapYokingGroup, const int32_t tabIndex); void addAnnotationTextSubstitutionFile(const AnnotationTextSubstitutionFile* annTextSubFile, const MapYokingGroupEnum::Enum mapYokingGroup); void addMapYokedFileAllTabs(const CaretMappableDataFile* caretMapFile, const MapYokingGroupEnum::Enum* mapYokingGroupsForAllTabs); MapYokingGroupEnum::Enum getMapYokingGroup() const; bool validateCompatibility(const AnnotationTextSubstitutionFile* annTextSubFile, const CaretMappableDataFile* caretMapFile, int32_t& numberOfYokedFilesOut, AString& messageOut) const; // ADD_NEW_METHODS_HERE private: class YokedFileInfo { public: YokedFileInfo(const AnnotationTextSubstitutionFile* annTextSubFile, const CaretMappableDataFile* caretMapFile, const int32_t tabIndex); const AnnotationTextSubstitutionFile* m_annTextSubFile; const CaretMappableDataFile* m_mapFile; const int32_t m_tabIndex; int32_t m_numberOfMaps; AString m_infoText; bool operator<(const YokedFileInfo& rhs) const { return (m_tabIndex < rhs.m_tabIndex); } }; EventMapYokingValidation(const EventMapYokingValidation&); EventMapYokingValidation& operator=(const EventMapYokingValidation&); std::set m_yokedFileInfo; std::vector m_validTabIndices; const MapYokingGroupEnum::Enum m_mapYokingGroup; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_MAP_YOKING_VALIDATION_DECLARE__ // #endif // __EVENT_MAP_YOKING_VALIDATION_DECLARE__ } // namespace #endif //__EVENT_MAP_YOKING_VALIDATION_H__ connectome-workbench-1.4.2/src/Files/EventSurfaceColoringInvalidate.cxx000066400000000000000000000023371360521144700263050ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretAssert.h" #include "EventSurfaceColoringInvalidate.h" using namespace caret; /** * Construct an event for invalidating surface coloring. */ EventSurfaceColoringInvalidate::EventSurfaceColoringInvalidate() : Event(EventTypeEnum::EVENT_SURFACE_COLORING_INVALIDATE) { } /** * Destructore. */ EventSurfaceColoringInvalidate::~EventSurfaceColoringInvalidate() { } connectome-workbench-1.4.2/src/Files/EventSurfaceColoringInvalidate.h000066400000000000000000000027421360521144700257320ustar00rootroot00000000000000#ifndef __EVENT_SURFACE_COLORING_INVALIDATE_H__ #define __EVENT_SURFACE_COLORING_INVALIDATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class BrainStructure; /// Invalidate all surface coloring class EventSurfaceColoringInvalidate : public Event { public: EventSurfaceColoringInvalidate(); virtual ~EventSurfaceColoringInvalidate(); private: EventSurfaceColoringInvalidate(const EventSurfaceColoringInvalidate&); EventSurfaceColoringInvalidate& operator=(const EventSurfaceColoringInvalidate&); }; } // namespace #endif // __EVENT_SURFACE_COLORING_INVALIDATE_H__ connectome-workbench-1.4.2/src/Files/EventSurfaceStructuresValidGet.cxx000066400000000000000000000060531360521144700263320ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_SURFACE_STRUCTURES_VALID_GET_DECLARE__ #include "EventSurfaceStructuresValidGet.h" #undef __EVENT_SURFACE_STRUCTURES_VALID_GET_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventSurfaceStructuresValidGet * \brief Get valid surface structures and their number of nodes * \ingroup Files */ /** * Constructor. */ EventSurfaceStructuresValidGet::EventSurfaceStructuresValidGet() : Event(EventTypeEnum::EVENT_SURFACE_STRUCTURES_VALID_GET) { } /** * Destructor. */ EventSurfaceStructuresValidGet::~EventSurfaceStructuresValidGet() { } /** * Add a structure and its number of nodes. If the structure already * has been added with the same number of nodes, no action is taken. * If a structure already has been added with a DIFFERENT number of nodes, * a warning will be logged. * * @param structure * The structure. * @param numberOfNodes * Number of nodes associated with the structure. */ void EventSurfaceStructuresValidGet::addStructure(const StructureEnum::Enum structure, const int32_t numberOfNodes) { std::map::iterator iter = m_structureAndNumberOfNodes.find(structure); if (iter != m_structureAndNumberOfNodes.end()) { const int32_t structNumNodes = iter->second; if (structNumNodes != numberOfNodes) { const AString message("Structure " + StructureEnum::toGuiName(structure) + " has different node counts: " + AString::number(numberOfNodes) + " and " + AString::number(structNumNodes)); CaretAssertMessage(0, message); CaretLogSevere(message); } } else { m_structureAndNumberOfNodes.insert(std::make_pair(structure, numberOfNodes)); } } /** * @return A map containing structures and their number of nodes. */ std::map EventSurfaceStructuresValidGet::getStructuresAndNumberOfNodes() const { return m_structureAndNumberOfNodes; } connectome-workbench-1.4.2/src/Files/EventSurfaceStructuresValidGet.h000066400000000000000000000037171360521144700257630ustar00rootroot00000000000000#ifndef __EVENT_SURFACE_STRUCTURES_VALID_GET_H__ #define __EVENT_SURFACE_STRUCTURES_VALID_GET_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" #include "StructureEnum.h" namespace caret { class EventSurfaceStructuresValidGet : public Event { public: EventSurfaceStructuresValidGet(); virtual ~EventSurfaceStructuresValidGet(); void addStructure(const StructureEnum::Enum structure, const int32_t numberOfNodes); std::map getStructuresAndNumberOfNodes() const; // ADD_NEW_METHODS_HERE private: EventSurfaceStructuresValidGet(const EventSurfaceStructuresValidGet&); EventSurfaceStructuresValidGet& operator=(const EventSurfaceStructuresValidGet&); std::map m_structureAndNumberOfNodes; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_SURFACE_STRUCTURES_VALID_GET_DECLARE__ // #endif // __EVENT_SURFACE_STRUCTURES_VALID_GET_DECLARE__ } // namespace #endif //__EVENT_SURFACE_STRUCTURES_VALID_GET_H__ connectome-workbench-1.4.2/src/Files/Fiber.cxx000066400000000000000000000132301360521144700212360ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __FIBER_DECLARE__ #include "Fiber.h" #undef __FIBER_DECLARE__ #include "AString.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "MathFunctions.h" using namespace caret; /** * \class caret::Fiber * \brief Data for a single fiber */ /** * Constructor. */ Fiber::Fiber(const float* pointerToData) { m_opacityForDrawing = 1.0; /* * Retrieve values from the file */ m_meanF = pointerToData[0]; m_varF = pointerToData[1]; m_theta = pointerToData[2]; m_phi = pointerToData[3]; m_k1 = pointerToData[4]; m_k2 = pointerToData[5]; m_psi = pointerToData[6]; /* * Validate inputs */ if (m_meanF != m_meanF) { m_invalidMessage += " meanF=NaN"; } if (m_varF != m_varF) { m_invalidMessage += " varF=NaN"; } if (m_theta != m_theta) { m_invalidMessage += " theta=NaN"; } if (m_phi != m_phi) { m_invalidMessage += " phi=NaN"; } if (m_k1 != m_k1) { m_invalidMessage += " k1=NaN"; } else if (m_k1 < 0.0) { m_invalidMessage += " k1=negative=" + QString::number(m_k1); } if (m_k2 != m_k2) { m_invalidMessage += " k2=NaN"; } else if (m_k1 < 0.0) { m_invalidMessage += " k2=negative=" + QString::number(m_k2); } if (m_psi != m_psi) { m_invalidMessage += " psi=NaN"; } m_valid = m_invalidMessage.isEmpty(); if (m_valid) { /* * Set computed values used for visualization */ m_fanningMajorAxisAngle = fanningEigenvalueToAngle(m_k1); m_fanningMinorAxisAngle = fanningEigenvalueToAngle(m_k2); /* * m_theta is angle from Positive-Z Axis rotated about a line * in the XY-Plane * * m_phi is angle from positive X-Axis rotated about Z-Axis * looking to negative Z. * * NOTE: 'X' is in radiological space (positive X is left) * so flip the sign of the X-coordinate. */ m_directionUnitVector[0] = -std::sin(m_theta) * std::cos(m_phi); m_directionUnitVector[1] = std::sin(m_theta) * std::sin(m_phi); m_directionUnitVector[2] = std::cos(m_theta); /* * Use absolute values of directional unit vector as RGB color components. */ m_directionUnitVectorRGB[0] = std::fabs(m_directionUnitVector[0]); m_directionUnitVectorRGB[1] = std::fabs(m_directionUnitVector[1]); m_directionUnitVectorRGB[2] = std::fabs(m_directionUnitVector[2]); // const float nearZero = 0.0001; // float oppositePhi = 0.0; // if (std::fabs(m_directionUnitVector[0]) > nearZero) { // oppositePhi = M_PI - std::atan2(-m_directionUnitVector[1], // -m_directionUnitVector[0]); // } // else { // oppositePhi = M_PI_2; // } // // float oppositeTheta = std::acos(-m_directionUnitVector[2]); // // const float radiansToDegrees = 180.0 / M_PI; // std::cout << "Vector: " << qPrintable(AString::fromNumbers(m_directionUnitVector, 3, ",")) << std::endl; // std::cout << "Theta/OppTheta/Phi/OppPhi: " // << (m_theta * radiansToDegrees) << " " // << (oppositeTheta * radiansToDegrees) << " " // << (m_phi * radiansToDegrees) << " " // << (oppositePhi * radiansToDegrees) << std::endl << std::endl; } } void vectorToAngles(const float vector[3], float& azimuthOut, float& elevationOut) { const float nearZero = 0.001; azimuthOut = 0.0; if (std::fabs(vector[0]) > nearZero) { azimuthOut = std::atan2(vector[1], vector[0]); } else if (vector[1] > nearZero) { azimuthOut = M_PI_2; } else if (vector[1] < -nearZero) { azimuthOut = -M_PI_2; } if (azimuthOut > M_PI_2) azimuthOut -= M_PI_2; else if (azimuthOut < -M_PI_2) azimuthOut += M_PI_2; elevationOut = std::acos(vector[2]); } /** * Destructor. */ Fiber::~Fiber() { } /** * Convert the fanning eigenvalue to an angle. * @param eigenvalue * The eigenvalue * @return * Angle derived from the eigenvalue. */ float Fiber::fanningEigenvalueToAngle(const float eigenvalue) { float angle = 0.0; if (eigenvalue > 0.0) { float sigma = 1.0 / std::sqrt(2.0 * eigenvalue); if (sigma > 1.0) sigma = 1.0; angle = std::asin(sigma); angle = angle / 2; if (angle < 0.0) { angle = -angle; } } else { CaretLogSevere("Have a negative eigenvalue=" + AString::number(eigenvalue) + " for a fiber."); } return angle; } connectome-workbench-1.4.2/src/Files/Fiber.h000066400000000000000000000100061360521144700206610ustar00rootroot00000000000000#ifndef __FIBER_H__ #define __FIBER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include namespace caret { /** * \struct caret::Fiber * \brief Attributes of a single fiber */ class Fiber { public: Fiber(const float* pointerToData); ~Fiber(); /** * Spatial magnitude of distribution/distance from center * This value is from the fiber orientation file. */ float m_meanF; /** * Spatial variance in magnitude of distribution/distance from center * This value is from the fiber orientation file. */ float m_varF; /** * First spatial angle of distribution. * Angle from Positive Z-Axis rotated about a line * in the XY-Plane * Units is radians. * This value is from the fiber orientation file. */ float m_theta; /** * Second spatial angle of distribution. * Aximuthal angle in X-Y Plane, counter-clockwise * around positive Z-Axis starting at positive X-Axis. * Units is radians. * This value is from the fiber orientation file. */ float m_phi; /** * Major fanning eigenvalue * This value is from the fiber orientation file. */ float m_k1; /** * Minor fanning eigenvalue * This value is from the fiber orientation file. */ float m_k2; /** * Angle of anisotropy in uncertainty/fanning distribution on sphere * Units is radians. * This value is from the fiber orientation file. */ float m_psi; /** * Angle of fanning for the major axis. * Units is radians. * This value is computed and is NOT from the fiber orientation file. */ float m_fanningMajorAxisAngle; /** * Angle of fanning for the minor axis. * Units is radians. * This value is computed and is NOT from the fiber orientation file. */ float m_fanningMinorAxisAngle; /** * Directional unit vector of fiber */ float m_directionUnitVector[3]; /** * RGB Color for directional unit vector of fiber */ float m_directionUnitVectorRGB[3]; /** * True if the fiber is valid, else false. */ bool m_valid; /** * Describes why fiber is invalid. */ QString m_invalidMessage; /** * Opacity of fiber drawing used by drawing code. * This value IS NOT stored in the file. */ float m_opacityForDrawing; /** Number of elements per fiber in a fiber orientation's file */ static const int32_t NUMBER_OF_ELEMENTS_PER_FIBER_IN_FILE; private: float fanningEigenvalueToAngle(const float k); }; #ifdef __FIBER_DECLARE__ const int32_t Fiber::NUMBER_OF_ELEMENTS_PER_FIBER_IN_FILE = 7; #endif // __FIBER_DECLARE__ } // namespace #endif //__FIBER_H__ connectome-workbench-1.4.2/src/Files/FiberOrientation.cxx000066400000000000000000000045621360521144700234620ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __FIBER_ORIENTATION_DECLARE__ #include "FiberOrientation.h" #undef __FIBER_ORIENTATION_DECLARE__ #include "Fiber.h" using namespace caret; /** * \class caret::FiberOrientation * \brief Groups fibers at a particular spatial coordinate */ /** * Constructor. */ FiberOrientation::FiberOrientation(const int32_t numberOfFibers, float* pointerToData) { m_xyz[0] = pointerToData[0]; m_xyz[1] = pointerToData[1]; m_xyz[2] = pointerToData[2]; m_numberOfFibers = numberOfFibers; /* * Point to 1st element after XYZ in CIFTI file row */ float* offset = pointerToData + FiberOrientation::NUMBER_OF_ELEMENTS_IN_FILE; /* * Point to each fiber in the CIFTI file row */ for (int32_t i = 0; i < m_numberOfFibers; i++) { Fiber* fiber = new Fiber(offset); m_fibers.push_back(fiber); offset += Fiber::NUMBER_OF_ELEMENTS_PER_FIBER_IN_FILE; if (fiber->m_valid == false) { if (m_invalidMessage.isEmpty() == false) { m_invalidMessage += "; "; } m_invalidMessage += ("Index=" + AString::number(i) + ": " + fiber->m_invalidMessage); } } m_valid = m_invalidMessage.isEmpty(); } /** * Destructor. */ FiberOrientation::~FiberOrientation() { for (int32_t i = 0; i < m_numberOfFibers; i++) { delete m_fibers[i]; } m_fibers.clear(); } connectome-workbench-1.4.2/src/Files/FiberOrientation.h000066400000000000000000000056001360521144700231010ustar00rootroot00000000000000#ifndef __FIBER_ORIENTATION__H__ #define __FIBER_ORIENTATION__H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" namespace caret { class Fiber; class FiberOrientation /* : public CaretObject */ { public: FiberOrientation(const int32_t numberOfFibers, float* pointerToData); virtual ~FiberOrientation(); /** * XYZ coordinates at spatial center of distribution. * When valid, points to memory in a CIFTI file. */ float m_xyz[3]; /** * Number of fibers in this group. * (number of elements in member 'fibers'). */ int32_t m_numberOfFibers; /** * Pointers to all fibers in this group. * When valid, points to memory in a CIFTI file */ std::vector m_fibers; /** * Fiber orientations are drawn using blending (alpha values). For * blending to work correctly in OpenGL, items must be drawn in * "depth" order from furthest to nearest. */ mutable float m_drawingDepth; /** * True if the fiber is valid, else false. */ bool m_valid; /** * Describes why fiber is invalid. */ QString m_invalidMessage; /** * Number of elements per fiber in a fiber orientation's file * (excluding the Fibers). * * At this time, this is the XYZ. * The value for this constant MUST be updated if elements are * added to a fiber orientation. */ static const int32_t NUMBER_OF_ELEMENTS_IN_FILE; private: FiberOrientation(const FiberOrientation&); FiberOrientation& operator=(const FiberOrientation&); // ADD_NEW_MEMBERS_HERE }; #ifdef __FIBER_ORIENTATION_DECLARE__ const int32_t FiberOrientation::NUMBER_OF_ELEMENTS_IN_FILE = 3; #endif // __FIBER_ORIENTATION_DECLARE__ } // namespace #endif //__FIBER_ORIENTATION__H__ connectome-workbench-1.4.2/src/Files/FiberOrientationColoringTypeEnum.cxx000066400000000000000000000232551360521144700266460ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __FIBER_ORIENTATION_COLORING_TYPE_ENUM_DECLARE__ #include "FiberOrientationColoringTypeEnum.h" #undef __FIBER_ORIENTATION_COLORING_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::FiberOrientationColoringTypeEnum * \brief Coloring type for foci orientations (and trajectory) * \ingroup Brain */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ FiberOrientationColoringTypeEnum::FiberOrientationColoringTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ FiberOrientationColoringTypeEnum::~FiberOrientationColoringTypeEnum() { } /** * Initialize the enumerated metadata. */ void FiberOrientationColoringTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(FiberOrientationColoringTypeEnum(FIBER_COLORING_FIBER_INDEX_AS_RGB, "FIBER_COLORING_FIBER_INDEX_AS_RGB", "Fiber 1,2,3 as RBG")); enumData.push_back(FiberOrientationColoringTypeEnum(FIBER_COLORING_XYZ_AS_RGB, "FIBER_COLORING_XYZ_AS_RGB", "XYZ as RGB")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const FiberOrientationColoringTypeEnum* FiberOrientationColoringTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const FiberOrientationColoringTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString FiberOrientationColoringTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const FiberOrientationColoringTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ FiberOrientationColoringTypeEnum::Enum FiberOrientationColoringTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = FIBER_COLORING_XYZ_AS_RGB; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const FiberOrientationColoringTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type FiberOrientationColoringTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString FiberOrientationColoringTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const FiberOrientationColoringTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ FiberOrientationColoringTypeEnum::Enum FiberOrientationColoringTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = FIBER_COLORING_XYZ_AS_RGB; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const FiberOrientationColoringTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type FiberOrientationColoringTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t FiberOrientationColoringTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const FiberOrientationColoringTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ FiberOrientationColoringTypeEnum::Enum FiberOrientationColoringTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = FIBER_COLORING_XYZ_AS_RGB; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const FiberOrientationColoringTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type FiberOrientationColoringTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void FiberOrientationColoringTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void FiberOrientationColoringTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(FiberOrientationColoringTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void FiberOrientationColoringTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(FiberOrientationColoringTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Files/FiberOrientationColoringTypeEnum.h000066400000000000000000000064021360521144700262660ustar00rootroot00000000000000#ifndef __FIBER_ORIENTATION_COLORING_TYPE_ENUM__H_ #define __FIBER_ORIENTATION_COLORING_TYPE_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class FiberOrientationColoringTypeEnum { public: /** * Enumerated values. */ enum Enum { /** */ FIBER_COLORING_XYZ_AS_RGB, /** */ FIBER_COLORING_FIBER_INDEX_AS_RGB }; ~FiberOrientationColoringTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: FiberOrientationColoringTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const FiberOrientationColoringTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __FIBER_ORIENTATION_COLORING_TYPE_ENUM_DECLARE__ std::vector FiberOrientationColoringTypeEnum::enumData; bool FiberOrientationColoringTypeEnum::initializedFlag = false; int32_t FiberOrientationColoringTypeEnum::integerCodeCounter = 0; #endif // __FIBER_ORIENTATION_COLORING_TYPE_ENUM_DECLARE__ } // namespace #endif //__FIBER_ORIENTATION_COLORING_TYPE_ENUM__H_ connectome-workbench-1.4.2/src/Files/FiberOrientationTrajectory.cxx000066400000000000000000000134421360521144700255260ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __FIBER_ORIENTATION_TRAJECTORY_DECLARE__ #include "FiberOrientationTrajectory.h" #undef __FIBER_ORIENTATION_TRAJECTORY_DECLARE__ #include "CaretAssert.h" #include "CaretSparseFile.h" #include "MathFunctions.h" using namespace caret; /** * \class caret::FiberOrientationTrajectory * \brief Containts fiber trajectory and corresponding fiber orientation. */ /** * Constructor that accepts a fiber orientation. * * @param fiberOrientationIndex * Index of the fiber orientation. * @param fiberOrientation * Fiber orientation that is associated with this fiber trajectory. */ FiberOrientationTrajectory::FiberOrientationTrajectory(const int64_t fiberOrientationIndex, const FiberOrientation* fiberOrientation) : m_fiberOrientationIndex(fiberOrientationIndex), m_fiberOrientation(fiberOrientation) { CaretAssert(fiberOrientation); m_fiberFraction = new FiberFractions(); m_fiberFractionTotalCountFloat = 0.0; m_totalCountSum = 0.0; m_fiberCountsSum.clear(); m_distanceSum = 0.0; m_countForAveraging = 0; } /** * Destructor. */ FiberOrientationTrajectory::~FiberOrientationTrajectory() { delete m_fiberFraction; } /** * Add a fiber fraction for averaging. * * @param fiberFraction * Fiber fraction that is added. */ void FiberOrientationTrajectory::addFiberFractionsForAveraging(const FiberFractions& fiberFraction) { const bool includeZeroTotalCountWhenAveraging = true; const int64_t numFractions = fiberFraction.fiberFractions.size(); if ((fiberFraction.totalCount > 0) && (numFractions > 0)) { // const float len = MathFunctions::vectorLength(&fiberFraction.fiberFractions[0]); // if (len < 1.0) { // std::cout << "Fraction len < 1: " << len << std::endl; // } if (m_fiberCountsSum.empty()) { m_fiberCountsSum.resize(numFractions, 0.0); } else if (static_cast(m_fiberCountsSum.size()) != numFractions) { CaretAssertMessage(0, "Sizes should be the same"); return; } m_totalCountSum += fiberFraction.totalCount; for (int64_t i = 0; i < numFractions; i++) { m_fiberCountsSum[i] += fiberFraction.fiberFractions[i] * fiberFraction.totalCount; } m_distanceSum += fiberFraction.distance; m_countForAveraging += 1; } else if (includeZeroTotalCountWhenAveraging) { m_countForAveraging += 1; } } /** * Set a fiber fraction. * * @param fiberFraction * Fiber fraction that is replaced. */ void FiberOrientationTrajectory::setFiberFractions(const FiberFractions& fiberFraction) { *m_fiberFraction = fiberFraction; if (m_fiberFraction->fiberFractions.empty()) { m_fiberFraction->zero(); } m_fiberFractionTotalCountFloat = m_fiberFraction->totalCount; } /** * Finish, which will update the fiber fraction using the average of all * of the fiber fractions that were added. */ void FiberOrientationTrajectory::finishAveraging() { if (m_countForAveraging > 0) { m_fiberFraction->distance = m_distanceSum / m_countForAveraging; m_fiberFraction->totalCount = m_totalCountSum / m_countForAveraging; m_fiberFractionTotalCountFloat = m_totalCountSum / m_countForAveraging; const int64_t numFiberCounts = static_cast(m_fiberCountsSum.size()); m_fiberFraction->fiberFractions.resize(numFiberCounts); if (numFiberCounts > 0) { for (int64_t i = 0; i < numFiberCounts; i++) { if (m_fiberFractionTotalCountFloat > 0.0) { const float averageCount = m_fiberCountsSum[i] / m_countForAveraging; m_fiberFraction->fiberFractions[i] = (averageCount / m_fiberFractionTotalCountFloat); float sum = (m_fiberFraction->fiberFractions[0] + m_fiberFraction->fiberFractions[1] + m_fiberFraction->fiberFractions[2]); if (sum > 1.0) { const float divisor = 1.0 / sum; m_fiberFraction->fiberFractions[0] *= divisor; m_fiberFraction->fiberFractions[1] *= divisor; m_fiberFraction->fiberFractions[2] *= divisor; // float newSum = (m_fiberFraction->fiberFractions[0] // + m_fiberFraction->fiberFractions[1] // + m_fiberFraction->fiberFractions[2]); // std::cout << "Sum too big: " << sum << " new sum: " << newSum << std::endl; } } else { m_fiberFraction->fiberFractions[i] = 0.0; } } } } else { m_fiberFraction->zero(); } } connectome-workbench-1.4.2/src/Files/FiberOrientationTrajectory.h000066400000000000000000000073341360521144700251560ustar00rootroot00000000000000#ifndef __FIBER_ORIENTATION_TRAJECTORY__H_ #define __FIBER_ORIENTATION_TRAJECTORY__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretAssert.h" #include "CaretSparseFile.h" namespace caret { class FiberOrientation; class FiberOrientationTrajectory { public: FiberOrientationTrajectory(const int64_t fiberOrientationIndex, const FiberOrientation* fiberOrientation); virtual ~FiberOrientationTrajectory(); void addFiberFractionsForAveraging(const FiberFractions& fiberFraction); void setFiberFractions(const FiberFractions& fiberFraction); /** * @return the Fiber Orientation. */ inline const FiberOrientation* getFiberOrientation() const { return m_fiberOrientation; } // /** // * Get the fiber fraction. // * // * @param indx // * Index of the fiber fraction. // * @return // * Fiber fraction at the given index. // */ // inline const FiberFractions* getFiberFraction() const { // return m_fiberFraction; // } /** * @return The fiber orientation index. */ inline int64_t getFiberOrientationIndex() const { return m_fiberOrientationIndex; } /** * @return The total count as a float. */ inline float getFiberFractionTotalCount() const { return m_fiberFractionTotalCountFloat; } /** * @return The fiber fractions (proportions). */ inline const std::vector& getFiberFractions() const { return m_fiberFraction->fiberFractions; } /** * @return The fiber fractions distance. */ inline float getFiberFractionDistance() const { return m_fiberFraction->distance; } void finishAveraging(); private: FiberOrientationTrajectory(const FiberOrientationTrajectory&); FiberOrientationTrajectory& operator=(const FiberOrientationTrajectory&); public: // ADD_NEW_METHODS_HERE private: const int64_t m_fiberOrientationIndex; const FiberOrientation* m_fiberOrientation; FiberFractions* m_fiberFraction; float m_fiberFractionTotalCountFloat; double m_totalCountSum; std::vector m_fiberCountsSum; double m_distanceSum; int64_t m_countForAveraging; // ADD_NEW_MEMBERS_HERE friend class CiftiFiberTrajectoryFile; }; #ifdef __FIBER_ORIENTATION_TRAJECTORY_DECLARE__ // #endif // __FIBER_ORIENTATION_TRAJECTORY_DECLARE__ } // namespace #endif //__FIBER_ORIENTATION_TRAJECTORY__H_ connectome-workbench-1.4.2/src/Files/FiberTrajectoryColorModel.cxx000066400000000000000000000301261360521144700252700ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __FIBER_TRAJECTORY_COLOR_MODEL_DECLARE__ #include "FiberTrajectoryColorModel.h" #undef __FIBER_TRAJECTORY_COLOR_MODEL_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::FiberTrajectoryColorModel * \brief Combines Fiber Coloring Type and Caret Color enumerated types. * \ingroup Files * * Fiber trajectories may be colored using either the fiber coloring * type or a caret color. This model allows these types to be * treated as a single type. */ /** * Constructor. */ FiberTrajectoryColorModel::FiberTrajectoryColorModel() : CaretObject() { m_selectedItem = NULL; Item* item = new Item(); m_allItems.push_back(item); std::vector allColors; CaretColorEnum::getColorEnums(allColors); for (std::vector::iterator iter = allColors.begin(); iter != allColors.end(); iter++) { Item* item = new Item(*iter); m_allItems.push_back(item); } if (m_allItems.empty()) { CaretAssert(0); } else { m_selectedItem = m_allItems[0]; } m_sceneAssistant = new SceneClassAssistant(); } /** * Destructor. */ FiberTrajectoryColorModel::~FiberTrajectoryColorModel() { for (std::vector::iterator iter = m_allItems.begin(); iter != m_allItems.end(); iter++) { Item* item = *iter; delete item; } m_allItems.clear(); delete m_sceneAssistant; } /** * @return All items in this model. */ std::vector FiberTrajectoryColorModel::getValidItems() { std::vector items = m_allItems; return m_allItems; } /** * @return Pointer to selected item. */ FiberTrajectoryColorModel::Item* FiberTrajectoryColorModel::getSelectedItem() { if (m_selectedItem == NULL) { if (m_allItems.empty() == false) { m_selectedItem = m_allItems[0]; } } return m_selectedItem; } /** * @return Pointer to selected item. */ const FiberTrajectoryColorModel::Item* FiberTrajectoryColorModel::getSelectedItem() const { FiberTrajectoryColorModel* nonConstThis = const_cast(this); const Item* item = nonConstThis->getSelectedItem(); return item; } /** * Set the selected item. * @param item * New selected item. */ void FiberTrajectoryColorModel::setSelectedItem(const Item* item) { std::vector allItems = getValidItems(); const int32_t numItems = static_cast(allItems.size()); for (int32_t i = 0; i < numItems; i++) { if (item->equals(*allItems[i])) { m_selectedItem = allItems[i]; break; } } } /** * Set the selection to the given caret color. * @param color * Color that is to be selected. */ void FiberTrajectoryColorModel::setCaretColor(const CaretColorEnum::Enum color) { std::vector allItems = getValidItems(); const int32_t numItems = static_cast(allItems.size()); for (int32_t i = 0; i < numItems; i++) { if (allItems[i]->getItemType() == Item::ITEM_TYPE_CARET_COLOR) { if (allItems[i]->getCaretColor() == color) { setSelectedItem(allItems[i]); break; } } } } /** * @return Is the fiber coloring type selected? */ bool FiberTrajectoryColorModel::isFiberOrientationColoringTypeSelected() const { if (m_selectedItem->getItemType() == Item::ITEM_TYPE_FIBER_ORIENTATION_COLORING_TYPE) { return true; } return false; } /** * Set the selection to the given fiber coloring type.. * @param fiberColorType * Fiber coloring type that is to be selected. */ void FiberTrajectoryColorModel::setFiberOrientationColoringTypeSelected() { std::vector allItems = getValidItems(); const int32_t numItems = static_cast(allItems.size()); for (int32_t i = 0; i < numItems; i++) { if (allItems[i]->getItemType() == Item::ITEM_TYPE_FIBER_ORIENTATION_COLORING_TYPE) { setSelectedItem(allItems[i]); break; } } } /** * Copy the selection from the other model. * * @param other * The other model. */ void FiberTrajectoryColorModel::copy(const FiberTrajectoryColorModel& other) { const Item* otherItem = other.getSelectedItem(); switch (otherItem->getItemType()) { case Item::ITEM_TYPE_CARET_COLOR: setCaretColor(otherItem->getCaretColor()); break; case Item::ITEM_TYPE_FIBER_ORIENTATION_COLORING_TYPE: setFiberOrientationColoringTypeSelected(); break; } } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* FiberTrajectoryColorModel::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "FiberTrajectoryColorModel", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); if (m_selectedItem != NULL) { sceneClass->addChild(m_selectedItem->saveToScene(sceneAttributes, "m_selectedItem")); } return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void FiberTrajectoryColorModel::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); Item item; item.restoreFromScene(sceneAttributes, sceneClass->getClass("m_selectedItem")); setSelectedItem(&item); } /* ========================================================================== */ /** * Constructor for a caret color. * * @param caretColor * The caret color enum. */ FiberTrajectoryColorModel::Item::Item(const CaretColorEnum::Enum caretColor) { m_caretColor = caretColor; m_itemType = ITEM_TYPE_CARET_COLOR; initializeAtEndOfConstruction(); } /** * Constructor for a fiber coloring type. * * @param fiberColoringType * The fiber coloring type. */ FiberTrajectoryColorModel::Item::Item() { m_caretColor = CaretColorEnum::BLACK; m_itemType = ITEM_TYPE_FIBER_ORIENTATION_COLORING_TYPE; initializeAtEndOfConstruction(); } /** * Destructor. */ FiberTrajectoryColorModel::Item::~Item() { delete m_sceneAssistant; } /** * Initialize at the end of construction. */ void FiberTrajectoryColorModel::Item::initializeAtEndOfConstruction() { m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_caretColor", &m_caretColor); } /** * Equality test for Item. * * @param item * Item for comparison. * @return * True if the same, else false. */ bool FiberTrajectoryColorModel::Item::equals(const Item& item) const { if (m_itemType == item.m_itemType) { switch (m_itemType) { case ITEM_TYPE_CARET_COLOR: if (m_caretColor == item.m_caretColor) { return true; } break; case ITEM_TYPE_FIBER_ORIENTATION_COLORING_TYPE: return true; break; } } return false; } /** * @return Name of the item. */ AString FiberTrajectoryColorModel::Item::getName() const { AString name = "PROGRAM_ERROR"; switch (m_itemType) { case ITEM_TYPE_CARET_COLOR: name = CaretColorEnum::toGuiName(m_caretColor); break; case ITEM_TYPE_FIBER_ORIENTATION_COLORING_TYPE: name = "Fiber"; break; } return name; } /** * @return Type of the item. */ FiberTrajectoryColorModel::Item::ItemType FiberTrajectoryColorModel::Item::getItemType() const { return m_itemType; } /** * @return The caret color for this item. */ CaretColorEnum::Enum FiberTrajectoryColorModel::Item::getCaretColor() const { return m_caretColor; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* FiberTrajectoryColorModel::Item::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "FiberTrajectoryColorModel::Item", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); switch (m_itemType) { case ITEM_TYPE_CARET_COLOR: sceneClass->addString("m_itemType", "ITEM_TYPE_CARET_COLOR"); break; case ITEM_TYPE_FIBER_ORIENTATION_COLORING_TYPE: sceneClass->addString("m_itemType", "ITEM_TYPE_FIBER_ORIENTATION_COLORING_TYPE"); break; } return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void FiberTrajectoryColorModel::Item::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); const AString itemTypeName = sceneClass->getStringValue("m_itemType", "ITEM_TYPE_FIBER_ORIENTATION_COLORING_TYPE"); m_itemType = ITEM_TYPE_FIBER_ORIENTATION_COLORING_TYPE; if (itemTypeName == "ITEM_TYPE_CARET_COLOR") { m_itemType = ITEM_TYPE_CARET_COLOR; } else if (itemTypeName == "ITEM_TYPE_FIBER_ORIENTATION_COLORING_TYPE") { m_itemType = ITEM_TYPE_FIBER_ORIENTATION_COLORING_TYPE; } else { CaretLogWarning(("Unrecognized value: " + itemTypeName)); } } connectome-workbench-1.4.2/src/Files/FiberTrajectoryColorModel.h000066400000000000000000000075331360521144700247230ustar00rootroot00000000000000#ifndef __FIBER_TRAJECTORY_COLOR_MODEL_H__ #define __FIBER_TRAJECTORY_COLOR_MODEL_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretColorEnum.h" #include "CaretObject.h" #include "SceneableInterface.h" namespace caret { class SceneClassAssistant; class FiberTrajectoryColorModel : public CaretObject, public SceneableInterface { public: class Item : public SceneableInterface { public: enum ItemType { /** * Type of item */ ITEM_TYPE_FIBER_ORIENTATION_COLORING_TYPE, ITEM_TYPE_CARET_COLOR }; Item(const CaretColorEnum::Enum caretColor); Item(); ~Item(); bool equals(const Item& item) const; AString getName() const; ItemType getItemType() const; CaretColorEnum::Enum getCaretColor() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: void initializeAtEndOfConstruction(); SceneClassAssistant* m_sceneAssistant; CaretColorEnum::Enum m_caretColor; ItemType m_itemType; }; FiberTrajectoryColorModel(); virtual ~FiberTrajectoryColorModel(); std::vector getValidItems(); Item* getSelectedItem(); const Item* getSelectedItem() const; void setSelectedItem(const Item* item); void setCaretColor(const CaretColorEnum::Enum color); bool isFiberOrientationColoringTypeSelected() const; void setFiberOrientationColoringTypeSelected(); void copy(const FiberTrajectoryColorModel& other); private: FiberTrajectoryColorModel(const FiberTrajectoryColorModel&); FiberTrajectoryColorModel& operator=(const FiberTrajectoryColorModel&); public: // ADD_NEW_METHODS_HERE virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: SceneClassAssistant* m_sceneAssistant; std::vector m_allItems; Item* m_selectedItem; // ADD_NEW_MEMBERS_HERE }; #ifdef __FIBER_TRAJECTORY_COLOR_MODEL_DECLARE__ // #endif // __FIBER_TRAJECTORY_COLOR_MODEL_DECLARE__ } // namespace #endif //__FIBER_TRAJECTORY_COLOR_MODEL_H__ connectome-workbench-1.4.2/src/Files/FiberTrajectoryDisplayModeEnum.cxx000066400000000000000000000241341360521144700262720ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __FIBER_TRAJECTORY_DISPLAY_MODE_ENUM_DECLARE__ #include "FiberTrajectoryDisplayModeEnum.h" #undef __FIBER_TRAJECTORY_DISPLAY_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::FiberTrajectoryDisplayModeEnum * \brief Enumerated type for fiber trajectory display mode */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ FiberTrajectoryDisplayModeEnum::FiberTrajectoryDisplayModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ FiberTrajectoryDisplayModeEnum::~FiberTrajectoryDisplayModeEnum() { } /** * Initialize the enumerated metadata. */ void FiberTrajectoryDisplayModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(FiberTrajectoryDisplayModeEnum(FIBER_TRAJECTORY_DISPLAY_ABSOLUTE, "FIBER_TRAJECTORY_DISPLAY_ABSOLUTE", "Absolute")); enumData.push_back(FiberTrajectoryDisplayModeEnum(FIBER_TRAJECTORY_DISPLAY_DISTANCE_WEIGHTED, "FIBER_TRAJECTORY_DISPLAY_DISTANCE_WEIGHTED", "Distance Weighted")); enumData.push_back(FiberTrajectoryDisplayModeEnum(FIBER_TRAJECTORY_DISPLAY_DISTANCE_WEIGHTED_LOG, "FIBER_TRAJECTORY_DISPLAY_DISTANCE_WEIGHTED_LOG", "Distance Weighted (Log)")); enumData.push_back(FiberTrajectoryDisplayModeEnum(FIBER_TRAJECTORY_DISPLAY_PROPORTION, "FIBER_TRAJECTORY_DISPLAY_PROPORTION", "Proportion")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const FiberTrajectoryDisplayModeEnum* FiberTrajectoryDisplayModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const FiberTrajectoryDisplayModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString FiberTrajectoryDisplayModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const FiberTrajectoryDisplayModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ FiberTrajectoryDisplayModeEnum::Enum FiberTrajectoryDisplayModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = FIBER_TRAJECTORY_DISPLAY_PROPORTION; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const FiberTrajectoryDisplayModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type FiberTrajectoryDisplayModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString FiberTrajectoryDisplayModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const FiberTrajectoryDisplayModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ FiberTrajectoryDisplayModeEnum::Enum FiberTrajectoryDisplayModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = FIBER_TRAJECTORY_DISPLAY_PROPORTION; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const FiberTrajectoryDisplayModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type FiberTrajectoryDisplayModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t FiberTrajectoryDisplayModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const FiberTrajectoryDisplayModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ FiberTrajectoryDisplayModeEnum::Enum FiberTrajectoryDisplayModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = FIBER_TRAJECTORY_DISPLAY_PROPORTION; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const FiberTrajectoryDisplayModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type FiberTrajectoryDisplayModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void FiberTrajectoryDisplayModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void FiberTrajectoryDisplayModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(FiberTrajectoryDisplayModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void FiberTrajectoryDisplayModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(FiberTrajectoryDisplayModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Files/FiberTrajectoryDisplayModeEnum.h000066400000000000000000000067511360521144700257240ustar00rootroot00000000000000#ifndef __FIBER_TRAJECTORY_DISPLAY_MODE_ENUM__H_ #define __FIBER_TRAJECTORY_DISPLAY_MODE_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class FiberTrajectoryDisplayModeEnum { public: /** * Enumerated values. */ enum Enum { /** Absolute display mode */ FIBER_TRAJECTORY_DISPLAY_ABSOLUTE, /** Distance weighted display mode */ FIBER_TRAJECTORY_DISPLAY_DISTANCE_WEIGHTED, /** Distance weighted Log display mode */ FIBER_TRAJECTORY_DISPLAY_DISTANCE_WEIGHTED_LOG, /** Proportion display mode*/ FIBER_TRAJECTORY_DISPLAY_PROPORTION }; ~FiberTrajectoryDisplayModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: FiberTrajectoryDisplayModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const FiberTrajectoryDisplayModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __FIBER_TRAJECTORY_DISPLAY_MODE_ENUM_DECLARE__ std::vector FiberTrajectoryDisplayModeEnum::enumData; bool FiberTrajectoryDisplayModeEnum::initializedFlag = false; int32_t FiberTrajectoryDisplayModeEnum::integerCodeCounter = 0; #endif // __FIBER_TRAJECTORY_DISPLAY_MODE_ENUM_DECLARE__ } // namespace #endif //__FIBER_TRAJECTORY_DISPLAY_MODE_ENUM__H_ connectome-workbench-1.4.2/src/Files/FiberTrajectoryMapProperties.cxx000066400000000000000000000270711360521144700260300ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __FIBER_TRAJECTORY_MAP_PROPERTIES_DECLARE__ #include "FiberTrajectoryMapProperties.h" #undef __FIBER_TRAJECTORY_MAP_PROPERTIES_DECLARE__ #include "CaretAssert.h" #include "FiberTrajectoryColorModel.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::FiberTrajectoryMapProperties * \brief Contains display properties for a fiber trajectory file. */ /** * Constructor. */ FiberTrajectoryMapProperties::FiberTrajectoryMapProperties() { m_sceneAssistant = new SceneClassAssistant(); m_fiberTrajectoryColoringModel = new FiberTrajectoryColorModel(); const float thresholdStreamline = 5; const float maximumProportionOpacity = 0.80; const float minimumProportionOpacity = 0.05; const FiberTrajectoryDisplayModeEnum::Enum displayMode = FiberTrajectoryDisplayModeEnum::FIBER_TRAJECTORY_DISPLAY_ABSOLUTE; const float countMaximum = 50; const float countMinimum = 5; m_displayStatus = false; m_displayMode = displayMode; m_proportionStreamline = thresholdStreamline; m_maximumProportionOpacity = maximumProportionOpacity; m_minimumProportionOpacity = minimumProportionOpacity; m_countStreamline = thresholdStreamline; m_countMaximumOpacity = countMaximum; m_countMinimumOpacity = countMinimum; m_distanceStreamline = thresholdStreamline; m_distanceMaximumOpacity = countMaximum; m_distanceMinimumOpacity = countMinimum; m_sceneAssistant->add("m_displayStatus", &m_displayStatus); m_sceneAssistant->add("m_displayMode", &m_displayMode); m_sceneAssistant->add("m_proportionStreamline", &m_proportionStreamline); m_sceneAssistant->add("m_maximumProportionOpacity", &m_maximumProportionOpacity); m_sceneAssistant->add("m_minimumProportionOpacity", &m_minimumProportionOpacity); m_sceneAssistant->add("m_countStreamline", &m_countStreamline); m_sceneAssistant->add("m_countMaximumOpacity", &m_countMaximumOpacity); m_sceneAssistant->add("m_countMinimumOpacity", &m_countMinimumOpacity); m_sceneAssistant->add("m_distanceStreamline", &m_distanceStreamline); m_sceneAssistant->add("m_distanceMaximumOpacity", &m_distanceMaximumOpacity); m_sceneAssistant->add("m_distanceMinimumOpacity", &m_distanceMinimumOpacity); m_sceneAssistant->add("m_fiberTrajectoryColoringModel", "FiberTrajectoryColorModel", m_fiberTrajectoryColoringModel); } /** * Destructor. */ FiberTrajectoryMapProperties::~FiberTrajectoryMapProperties() { delete m_fiberTrajectoryColoringModel; delete m_sceneAssistant; } /** * @return Display status of trajectory. */ bool FiberTrajectoryMapProperties::isDisplayed() const { return m_displayStatus; } /** * Set the display status for trajectory for the given display group. * @param displayStatus * New status. */ void FiberTrajectoryMapProperties::setDisplayed(const bool displayStatus) { m_displayStatus = displayStatus; } /** * @return The display mode. */ FiberTrajectoryDisplayModeEnum::Enum FiberTrajectoryMapProperties::getDisplayMode() const { return m_displayMode; } /** * Set the display mode to the given value. * @param displayMode * New value for display mode. */ void FiberTrajectoryMapProperties::setDisplayMode(const FiberTrajectoryDisplayModeEnum::Enum displayMode) { m_displayMode = displayMode; } /** * @return The proportion streamline count */ float FiberTrajectoryMapProperties::getProportionStreamline() const { return m_proportionStreamline; } /** * Set the proportion streamline count. * @param pointSize * New value for below limit. */ void FiberTrajectoryMapProperties::setProportionStreamline(const float proportionStreamline) { m_proportionStreamline = proportionStreamline; } /** * @return The proporation maximum opacity. */ float FiberTrajectoryMapProperties::getProportionMaximumOpacity() const { return m_maximumProportionOpacity; } /** * Set the proporation maximum opacity. * @param minimumMagnitude * New value for minimum magnitude. */ void FiberTrajectoryMapProperties::setProportionMaximumOpacity(const float maximumMagnitude) { m_maximumProportionOpacity = maximumMagnitude; } /** * @return The proporation minimum opacity. */ float FiberTrajectoryMapProperties::getProportionMinimumOpacity() const { return m_minimumProportionOpacity; } /** * Set the proporation minimum opacity. * @param minimumOpacity * New value for minimum opacity */ void FiberTrajectoryMapProperties::setProportionMinimumOpacity(const float minimumOpacity) { m_minimumProportionOpacity = minimumOpacity; } /** * @return The count streamline threshold. */ float FiberTrajectoryMapProperties::getCountStreamline() const { return m_countStreamline; } /** * Set the count streamline threshold. * @param countStreamline * New value for count streamline threshold */ void FiberTrajectoryMapProperties::setCountStreamline(const float countStreamline) { m_countStreamline = countStreamline; } /** * @return The count value mapped to maximum opacity. */ float FiberTrajectoryMapProperties::getCountMaximumOpacity() const { return m_countMaximumOpacity; } /** * Set the count maximum opacity. * @param countMaximumOpacity * New value for count mapped to maximum opacity */ void FiberTrajectoryMapProperties::setCountMaximumOpacity(const float countMaximumOpacity) { m_countMaximumOpacity = countMaximumOpacity; } /** * @return The count value mapped to minimum opacity. */ float FiberTrajectoryMapProperties::getCountMinimumOpacity() const { return m_countMinimumOpacity; } /** * Set the count minimum opacity. * @param countMinimumOpacity * New value for count mapped to minimum opacity */ void FiberTrajectoryMapProperties::setCountMinimumOpacity(const float countMinimumOpacity) { m_countMinimumOpacity = countMinimumOpacity; } /** * @return The distance streamline threshold. */ float FiberTrajectoryMapProperties::getDistanceStreamline() const { return m_distanceStreamline; } /** * Set the distance streamline threshold. * @param distanceStreamline * New value for distance streamline threshold */ void FiberTrajectoryMapProperties::setDistanceStreamline(const float distanceStreamline) { m_distanceStreamline = distanceStreamline; } /** * @return The distance value mapped to maximum opacity. */ float FiberTrajectoryMapProperties::getDistanceMaximumOpacity() const { return m_distanceMaximumOpacity; } /** * Set the distance maximum opacity. * @param distanceMaximumOpacity * New value for distance mapped to maximum opacity */ void FiberTrajectoryMapProperties::setDistanceMaximumOpacity(const float distanceMaximumOpacity) { m_distanceMaximumOpacity = distanceMaximumOpacity; } /** * @return The distance value mapped to minimum opacity. */ float FiberTrajectoryMapProperties::getDistanceMinimumOpacity() const { return m_distanceMinimumOpacity; } /** * Set the distance minimum opacity. * @param distanceMinimumOpacity * New value for distance mapped to minimum opacity */ void FiberTrajectoryMapProperties::setDistanceMinimumOpacity(const float distanceMinimumOpacity) { m_distanceMinimumOpacity = distanceMinimumOpacity; } /** * @return the fiber trajectory coloring model. */ FiberTrajectoryColorModel* FiberTrajectoryMapProperties::getFiberTrajectoryColorModel() { return m_fiberTrajectoryColoringModel; } /** * @return the fiber trajectory coloring model. */ const FiberTrajectoryColorModel* FiberTrajectoryMapProperties::getFiberTrajectoryColorModel() const { return m_fiberTrajectoryColoringModel; } /** * Copy the other map properties. * * @param other * The map properties that are copied. */ void FiberTrajectoryMapProperties::copy(const FiberTrajectoryMapProperties& other) { m_displayMode = other.m_displayMode; m_displayStatus = other.m_displayStatus; m_proportionStreamline = other.m_proportionStreamline; m_maximumProportionOpacity = other.m_maximumProportionOpacity; m_minimumProportionOpacity = other.m_minimumProportionOpacity; m_countStreamline = other.m_countStreamline; m_countMaximumOpacity = other.m_countMaximumOpacity; m_countMinimumOpacity = other.m_countMinimumOpacity; m_distanceStreamline = other.m_distanceStreamline; m_distanceMaximumOpacity = other.m_distanceMaximumOpacity; m_distanceMinimumOpacity = other.m_distanceMinimumOpacity; m_fiberTrajectoryColoringModel->copy(*other.getFiberTrajectoryColorModel()); } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* FiberTrajectoryMapProperties::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "FiberTrajectoryMapProperties", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void FiberTrajectoryMapProperties::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } } connectome-workbench-1.4.2/src/Files/FiberTrajectoryMapProperties.h000066400000000000000000000105501360521144700254470ustar00rootroot00000000000000#ifndef __FIBER_TRAJECTORY_MAP_PROPERTIES_H__ #define __FIBER_TRAJECTORY_MAP_PROPERTIES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "FiberTrajectoryDisplayModeEnum.h" #include "SceneableInterface.h" namespace caret { class FiberTrajectoryColorModel; class SceneClassAssistant; class FiberTrajectoryMapProperties : public SceneableInterface { public: FiberTrajectoryMapProperties(); virtual ~FiberTrajectoryMapProperties(); bool isDisplayed() const; void setDisplayed(const bool displayStatus); FiberTrajectoryDisplayModeEnum::Enum getDisplayMode() const; void setDisplayMode(const FiberTrajectoryDisplayModeEnum::Enum displayMode); float getProportionStreamline() const; void setProportionStreamline(const float thresholdStreamline); float getProportionMaximumOpacity() const; void setProportionMaximumOpacity(const float maximumProportionOpacity); float getProportionMinimumOpacity() const; void setProportionMinimumOpacity(const float minimumProportionOpacity); float getCountStreamline() const; void setCountStreamline(const float countStreamline); float getCountMaximumOpacity() const; void setCountMaximumOpacity(const float countMaximumOpacity); float getCountMinimumOpacity() const; void setCountMinimumOpacity(const float countMinimumOpacity); float getDistanceStreamline() const; void setDistanceStreamline(const float distanceStreamline); float getDistanceMaximumOpacity() const; void setDistanceMaximumOpacity(const float distanceMaximumOpacity); float getDistanceMinimumOpacity() const; void setDistanceMinimumOpacity(const float distanceMinimumOpacity); FiberTrajectoryColorModel* getFiberTrajectoryColorModel(); const FiberTrajectoryColorModel* getFiberTrajectoryColorModel() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); void copy(const FiberTrajectoryMapProperties& other); private: FiberTrajectoryMapProperties(const FiberTrajectoryMapProperties&); FiberTrajectoryMapProperties& operator=(const FiberTrajectoryMapProperties&); SceneClassAssistant* m_sceneAssistant; FiberTrajectoryDisplayModeEnum::Enum m_displayMode; bool m_displayStatus; float m_proportionStreamline; float m_maximumProportionOpacity; float m_minimumProportionOpacity; float m_countStreamline; float m_countMaximumOpacity; float m_countMinimumOpacity; float m_distanceStreamline; float m_distanceMaximumOpacity; float m_distanceMinimumOpacity; FiberTrajectoryColorModel* m_fiberTrajectoryColoringModel; }; #ifdef __FIBER_TRAJECTORY_MAP_PROPERTIES_DECLARE__ // #endif // __FIBER_TRAJECTORY_MAP_PROPERTIES_DECLARE__ } // namespace #endif //__FIBER_TRAJECTORY_MAP_PROPERTIES_H__ connectome-workbench-1.4.2/src/Files/FilePathNamePrefixCompactor.cxx000066400000000000000000000365261360521144700255470ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __FILE_PATH_NAME_PREFIX_COMPACTOR_DECLARE__ #include "FilePathNamePrefixCompactor.h" #undef __FILE_PATH_NAME_PREFIX_COMPACTOR_DECLARE__ #include #include #include #include "CaretAssert.h" #include "CaretMappableDataFile.h" #include "CiftiBrainordinateDataSeriesFile.h" #include "CiftiConnectivityMatrixDenseDynamicFile.h" #include "FileInformation.h" using namespace caret; /** * \class caret::FilePathNamePrefixCompactor * \brief Remove matching prefixes from a group of file names. * \ingroup Files * * In the graphical user-interface names of files with a full path * are frequently presented to the user. In some instances, these * paths may be very long, too long to display in the user-interface. * One solution is to place the path after the name of the file. * However, there are instance in which there are file with identical * names but different paths and when the paths are long, the user * may not see the entire path and is unable to fully identify * a file. * * The static methods in this class are used to remove the matching * prefixes (first of characters) from the path * of each file. Do so, allows the user to see the name of the file * followed by the unique portion of the file's path. */ /** * Constructor. */ FilePathNamePrefixCompactor::FilePathNamePrefixCompactor() : CaretObject() { } /** * Destructor. */ FilePathNamePrefixCompactor::~FilePathNamePrefixCompactor() { } /** * Create names that show the filename followed by the path BUT remove * any matching prefix from the paths for a group of CaretDataFiles. * * Example Input File Names: * /mnt/myelin/data/subject2/rsfmri/activity.dscalar.nii * /mnt/myelin/data/subject1/rsfmri/activity.dscalar.nii * Output: * actitivity.dscalar.nii (../subject2/rsfmri) * actitivity.dscalar.nii (../subject1/rsfmri) * * @param caretMappableDataFiles * The caret mappable data files from which names are obtained. * @param prefixRemovedNamesOut * Names of files with matching prefixes removed. Number of elements * will match the number of elements in caretDataFiles. */ void FilePathNamePrefixCompactor::removeMatchingPathPrefixFromCaretDataFiles(const std::vector& caretMappableDataFiles, std::vector& prefixRemovedNamesOut) { std::vector caretDataFiles; for (std::vector::const_iterator iter = caretMappableDataFiles.begin(); iter != caretMappableDataFiles.end(); iter++) { caretDataFiles.push_back(*iter); } removeMatchingPathPrefixFromCaretDataFiles(caretDataFiles, prefixRemovedNamesOut); } /** * Create names that show the filename followed by the path BUT remove * any matching prefix from the paths for a group of CaretDataFiles. * * Example Input File Names: * /mnt/myelin/data/subject2/rsfmri/activity.dscalar.nii * /mnt/myelin/data/subject1/rsfmri/activity.dscalar.nii * Output: * actitivity.dscalar.nii (../subject2/rsfmri) * actitivity.dscalar.nii (../subject1/rsfmri) * * @param caretDataFiles * The caret data files from which names are obtained. * @param prefixRemovedNamesOut * Names of files with matching prefixes removed. Number of elements * will match the number of elements in caretDataFiles. */ void FilePathNamePrefixCompactor::removeMatchingPathPrefixFromCaretDataFiles(const std::vector& caretDataFiles, std::vector& prefixRemovedNamesOut) { std::vector filePathNames; std::vector fileNames; std::vector specialPrefixes; for (std::vector::const_iterator iter = caretDataFiles.begin(); iter != caretDataFiles.end(); iter++) { CaretDataFile* cdf = *iter; CaretAssert(cdf); AString fileSpecialPrefix; switch (cdf->getDataFileType()) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: fileSpecialPrefix = "dynconn - "; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: break; case DataFileTypeEnum::METRIC: break; case DataFileTypeEnum::METRIC_DYNAMIC: fileSpecialPrefix = "metricdynconn - "; break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: fileSpecialPrefix = "voldynconn - "; break; } specialPrefixes.push_back(fileSpecialPrefix); filePathNames.push_back(cdf->getFileName()); fileNames.push_back(cdf->getFileNameNoPath()); } CaretAssert(filePathNames.size() == fileNames.size()); CaretAssert(filePathNames.size() == specialPrefixes.size()); const bool onlyFilesWithMatchingFileNamesFlag(true); if (onlyFilesWithMatchingFileNamesFlag) { const int32_t numFiles = static_cast(filePathNames.size()); std::vector cleanedFlag(numFiles, false); /* * Initialize output to just file names (no paths) */ prefixRemovedNamesOut = fileNames; for (int32_t i = 0; i < (numFiles - 1); i++) { CaretAssertVectorIndex(cleanedFlag, i); if (cleanedFlag[i]) { continue; } CaretAssertVectorIndex(fileNames, i); const AString& name = fileNames[i]; std::vector duplicateFileIndices; std::vector duplicateNameFiles; duplicateFileIndices.push_back(i); CaretAssertVectorIndex(filePathNames, i); duplicateNameFiles.push_back(filePathNames[i]); /* * Find files with same name (excluding path) */ for (int32_t j = i + 1; j < numFiles; j++) { CaretAssertVectorIndex(cleanedFlag, j); if (cleanedFlag[j]) { continue; } CaretAssertVectorIndex(fileNames, j); if (name == fileNames[j]) { duplicateFileIndices.push_back(j); CaretAssertVectorIndex(filePathNames, j); duplicateNameFiles.push_back(filePathNames[j]); } } /* * If multiple files with same same, remove the matching paths */ std::vector cleanedFileNames; if (duplicateNameFiles.size() > 1) { removeMatchingPathPrefixFromFileNames(duplicateNameFiles, cleanedFileNames); /* * Update the name with prefix removed for output */ CaretAssert(duplicateFileIndices.size() == cleanedFileNames.size()); const int32_t numCleanedFiles = static_cast(cleanedFileNames.size()); for (int32_t m = 0; m < numCleanedFiles; m++) { CaretAssertVectorIndex(duplicateFileIndices, m); const int32_t indx = duplicateFileIndices[m]; CaretAssertVectorIndex(cleanedFileNames, m); prefixRemovedNamesOut[indx] = cleanedFileNames[m]; CaretAssertVectorIndex(cleanedFlag, indx); cleanedFlag[indx] = true; } } } } else { /* * Running this will operate on all files as if all of the them have the same file name */ removeMatchingPathPrefixFromFileNames(filePathNames, prefixRemovedNamesOut); } const int32_t numFiles = static_cast(prefixRemovedNamesOut.size()); CaretAssert(numFiles == static_cast(specialPrefixes.size())); for (int32_t i = 0; i < numFiles; i++) { prefixRemovedNamesOut[i].insert(0, specialPrefixes[i]); } } /** * Create names that show the filename followed by the path BUT remove * any matching prefix from the paths for a group of file names. * * Example Input File Names: * /mnt/myelin/data/subject2/rsfmri/activity.dscalar.nii * /mnt/myelin/data/subject1/rsfmri/activity.dscalar.nii * Output: * actitivity.dscalar.nii (../subject2/rsfmri) * actitivity.dscalar.nii (../subject1/rsfmri) * * @param caretDataFiles * The caret data files from which names are obtained. * @param prefixRemovedNamesOut * Names of files with matching prefixes removed. Number of elements * will match the number of elements in caretDataFiles. */ void FilePathNamePrefixCompactor::removeMatchingPathPrefixFromFileNames(const std::vector& fileNames, std::vector& prefixRemovedNamesOut) { prefixRemovedNamesOut.clear(); const int32_t numFiles = static_cast(fileNames.size()); if (numFiles == 1) { FileInformation fileInfo(fileNames[0]); prefixRemovedNamesOut.push_back(fileInfo.getFileName()); return; } else if (numFiles < 1){ return; } std::vector > pathComponentEachFile; int32_t mininumComponentCount = std::numeric_limits::max(); /* * For each file, split its path components (parts between '/') and * place them into a vector. Also find the minimum number from * all of the paths as that will be the maximum number of matching * components. */ for (std::vector::const_iterator iter = fileNames.begin(); iter != fileNames.end(); iter++) { FileInformation fileInfo(*iter); const QString path = fileInfo.getPathName(); QStringList pathComponentsList = path.split('/'); mininumComponentCount = std::min(mininumComponentCount, pathComponentsList.size()); std::vector pathComponents; for (int32_t ip = 0; ip < pathComponentsList.size(); ip++) { pathComponents.push_back(pathComponentsList[ip]); } pathComponentEachFile.push_back(pathComponents); } CaretAssert(static_cast(pathComponentEachFile.size()) == numFiles); /* * For each of the file names, examine and compare its path * components to all of the other file path components to * determine the matching prefix. */ int32_t numMatchingLeadingComponents = 0; for (int32_t iComp = 0; iComp < mininumComponentCount; iComp++) { CaretAssertVectorIndex(pathComponentEachFile, 0); const std::vector& firstFileCompontents = pathComponentEachFile[0]; const AString component = firstFileCompontents[iComp]; bool doneFlag = false; for (int32_t jFile = 1; jFile < numFiles; jFile++) { CaretAssertVectorIndex(pathComponentEachFile, jFile); const std::vector& fileComps = pathComponentEachFile[jFile]; CaretAssertVectorIndex(fileComps, iComp); if (fileComps[iComp] != component) { doneFlag = true; break; } } if (doneFlag) { break; } else { numMatchingLeadingComponents++; } } /* * For each of the file names, create a name in the form of: * filename (unique-suffix-of-path). */ for (int32_t iFile = 0; iFile < numFiles; iFile++) { CaretAssertVectorIndex(fileNames, iFile); FileInformation fileInfo(fileNames[iFile]); AString name = fileInfo.getFileName() + " "; CaretAssertVectorIndex(pathComponentEachFile, iFile); const std::vector& fileComps = pathComponentEachFile[iFile]; const int32_t numComps = static_cast(fileComps.size()); bool addedComponentsFlag = false; for (int32_t iComp = numMatchingLeadingComponents; iComp < numComps; iComp++) { if (iComp == numMatchingLeadingComponents) { name.append("(..../"); } CaretAssertVectorIndex(fileComps, iComp); name.append(fileComps[iComp] + "/"); addedComponentsFlag = true; } if (addedComponentsFlag) { name.append(")"); } prefixRemovedNamesOut.push_back(name); } CaretAssert(fileNames.size() == prefixRemovedNamesOut.size()); } connectome-workbench-1.4.2/src/Files/FilePathNamePrefixCompactor.h000066400000000000000000000044341360521144700251650ustar00rootroot00000000000000#ifndef __FILE_PATH_NAME_PREFIX_COMPACTOR_H__ #define __FILE_PATH_NAME_PREFIX_COMPACTOR_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" namespace caret { class CaretDataFile; class CaretMappableDataFile; class FilePathNamePrefixCompactor : public CaretObject { public: static void removeMatchingPathPrefixFromCaretDataFiles(const std::vector& caretMappableDataFiles, std::vector& prefixRemovedNamesOut); static void removeMatchingPathPrefixFromCaretDataFiles(const std::vector& caretDataFiles, std::vector& prefixRemovedNamesOut); private: FilePathNamePrefixCompactor(); virtual ~FilePathNamePrefixCompactor(); FilePathNamePrefixCompactor(const FilePathNamePrefixCompactor&); FilePathNamePrefixCompactor& operator=(const FilePathNamePrefixCompactor&); static void removeMatchingPathPrefixFromFileNames(const std::vector& fileNames, std::vector& prefixRemovedNamesOut); }; #ifdef __FILE_PATH_NAME_PREFIX_COMPACTOR_DECLARE__ // #endif // __FILE_PATH_NAME_PREFIX_COMPACTOR_DECLARE__ } // namespace #endif //__FILE_PATH_NAME_PREFIX_COMPACTOR_H__ connectome-workbench-1.4.2/src/Files/FociFile.cxx000066400000000000000000000424771360521144700217060ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #define __FOCI_FILE_DECLARE__ #include "FociFile.h" #undef __FOCI_FILE_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "DataFileContentInformation.h" #include "DataFileException.h" #include "GroupAndNameHierarchyModel.h" #include "FileAdapter.h" #include "FociFileSaxReader.h" #include "Focus.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "GiftiMetaData.h" #include "SurfaceProjectedItem.h" #include "XmlAttributes.h" #include "XmlSaxParser.h" #include "XmlWriter.h" using namespace caret; /** * \class caret::FociFile * \brief A foci (plural of focus) file. */ /** * Constructor. */ FociFile::FociFile() : CaretDataFile(DataFileTypeEnum::FOCI) { initializeFociFile(); } /** * Destructor. */ FociFile::~FociFile() { delete m_nameColorTable; delete m_classColorTable; delete m_metadata; for (std::vector::iterator iter = m_foci.begin(); iter != m_foci.end(); iter++) { delete *iter; } m_foci.clear(); delete m_classNameHierarchy; } /** * Copy constructor. * @param obj * Object that is copied. */ FociFile::FociFile(const FociFile& obj) : CaretDataFile(obj) { initializeFociFile(); copyHelperFociFile(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ FociFile& FociFile::operator=(const FociFile& obj) { if (this != &obj) { clear(); CaretDataFile::operator=(obj); copyHelperFociFile(obj); } return *this; } void FociFile::initializeFociFile() { m_classColorTable = new GiftiLabelTable(); m_nameColorTable = new GiftiLabelTable(); m_classNameHierarchy = new GroupAndNameHierarchyModel(); m_metadata = new GiftiMetaData(); m_forceUpdateOfGroupAndNameHierarchy = true; } /** * Helps with copying an object of this type. * @param ff * Object that is copied. */ void FociFile::copyHelperFociFile(const FociFile& ff) { *m_classColorTable = *ff.m_classColorTable; *m_nameColorTable = *ff.m_nameColorTable; if (m_classNameHierarchy != NULL) { delete m_classNameHierarchy; } m_classNameHierarchy = new GroupAndNameHierarchyModel(); *m_metadata = *ff.m_metadata; const int32_t numFoci = getNumberOfFoci(); for (int32_t i = 0; i < numFoci; i++) { m_foci.push_back(new Focus(*ff.getFocus(i))); } m_forceUpdateOfGroupAndNameHierarchy = true; setModified(); } /** * @return Is this foci file empty (contains zero focuss)? */ bool FociFile::isEmpty() const { return m_foci.empty(); } /** * @return The structure for this file. */ StructureEnum::Enum FociFile::getStructure() const { return StructureEnum::ALL; } /** * Set the structure for this file. * @param structure * New structure for this file. */ void FociFile::setStructure(const StructureEnum::Enum /*structure*/) { // does nothing since focuss apply to all structures } /** * @return Get access to the file's metadata. */ GiftiMetaData* FociFile::getFileMetaData() { return m_metadata; } /** * @return Get access to unmodifiable file's metadata. */ const GiftiMetaData* FociFile::getFileMetaData() const { return m_metadata; } /** * Clear the focus file. */ void FociFile::clear() { CaretDataFile::clear(); m_classNameHierarchy->clear(); m_classColorTable->clear(); m_nameColorTable->clear(); m_metadata->clear(); const int32_t numFoci = getNumberOfFoci(); for (int32_t i = 0; i < numFoci; i++) { delete m_foci[i]; } m_foci.clear(); } /** * @return the number of foci. */ int32_t FociFile::getNumberOfFoci() const { return m_foci.size(); } /** * Get the focus at the given index. * @param indx * Index of the focus. * @return * focus at the given index. */ Focus* FociFile::getFocus(const int32_t indx) { CaretAssertVectorIndex(m_foci, indx); return m_foci[indx]; } /** * Get the focus at the given index. * @param indx * Index of the focus. * @return * focus at the given index. */ const Focus* FociFile::getFocus(const int32_t indx) const { CaretAssertVectorIndex(m_foci, indx); return m_foci[indx]; } /** * Add a focus. NOTE: This focus file * takes ownership of the 'focus' and * will handle deleting it. After calling * this method, the caller must never * do anything with the focus that was passed * to this method. * * @param focus * Focus added to this focus file. */ void FociFile::addFocus(Focus* focus) { m_foci.push_back(focus); const AString name = focus->getName(); if (name.isEmpty() == false) { const int32_t nameColorKey = m_nameColorTable->getLabelKeyFromName(name); if (nameColorKey < 0) { m_nameColorTable->addLabel(name, 0.0f, 0.0f, 0.0f, 1.0f); } } AString className = focus->getClassName(); if (className.isEmpty() == false) { const int32_t classColorKey = m_classColorTable->getLabelKeyFromName(className); if (classColorKey < 0) { m_classColorTable->addLabel(className, 0.0f, 0.0f, 0.0f, 1.0f); } } m_forceUpdateOfGroupAndNameHierarchy = true; setModified(); } /** * Remove the focus at the given index. * @param indx * Index of focus for removal. */ void FociFile::removeFocus(const int32_t indx) { CaretAssertVectorIndex(m_foci, indx); Focus* focus = getFocus(indx); m_foci.erase(m_foci.begin() + indx); delete focus; m_forceUpdateOfGroupAndNameHierarchy = true; setModified(); } /** * Remove the focus. * @param focus * Focus that will be removed and DELETED. */ void FociFile::removeFocus(Focus* focus) { const int32_t numFoci = getNumberOfFoci(); for (int32_t i = 0;i < numFoci; i++) { if (m_foci[i] == focus) { removeFocus(i); return; } } CaretLogWarning("Attempting to delete focus not in focus file with name: " + focus->getName()); } /** * @return The class and name hierarchy. */ GroupAndNameHierarchyModel* FociFile::getGroupAndNameHierarchyModel() { m_classNameHierarchy->update(this, m_forceUpdateOfGroupAndNameHierarchy); m_forceUpdateOfGroupAndNameHierarchy = false; return m_classNameHierarchy; } /** * @return The class color table. */ GiftiLabelTable* FociFile::getClassColorTable() { return m_classColorTable; } /** * @return The class color table. */ const GiftiLabelTable* FociFile::getClassColorTable() const { return m_classColorTable; } /** * @return The name color table. */ GiftiLabelTable* FociFile::getNameColorTable() { return m_nameColorTable; } /** * @return The name color table. */ const GiftiLabelTable* FociFile::getNameColorTable() const { return m_nameColorTable; } /** * Version 1 foci files contained one color table for both names * and classes. Newer versions of the foci file keep them in * separate tables. * * @param oldColorTable * Old color table that is split into name and class color tables. */ void FociFile::createNameAndClassColorTables(const GiftiLabelTable* oldColorTable) { CaretAssert(oldColorTable); m_classColorTable->clear(); m_nameColorTable->clear(); std::set nameSet; std::set classSet; const int numFoci = getNumberOfFoci(); for (int32_t i = 0; i < numFoci; i++) { const Focus* focus = getFocus(i); nameSet.insert(focus->getName()); classSet.insert(focus->getClassName()); } /* * Create colors for only the "best matching" color. */ for (std::set::iterator iter = nameSet.begin(); iter != nameSet.end(); iter++) { const AString colorName = *iter; const GiftiLabel* oldLabel = oldColorTable->getLabelBestMatching(colorName); if (oldLabel != NULL) { const AString bestMatchingName = oldLabel->getName(); const int32_t labelKey = m_nameColorTable->getLabelKeyFromName(bestMatchingName); if (labelKey < 0) { float rgba[4] = { 0.0, 0.0, 0.0, 1.0 }; oldLabel->getColor(rgba); m_nameColorTable->addLabel(bestMatchingName, rgba[0], rgba[1], rgba[2], rgba[3]); } } } /* * Create a color for each class name using the best matching color */ for (std::set::iterator iter = classSet.begin(); iter != classSet.end(); iter++) { const AString colorName = *iter; const GiftiLabel* label = oldColorTable->getLabelBestMatching(colorName); float rgba[4] = { 0.0, 0.0, 0.0, 1.0 }; if (label != NULL) { label->getColor(rgba); } m_classColorTable->addLabel(colorName, rgba[0], rgba[1], rgba[2], rgba[3]); } } /** * @return A string list containing all foci names * sorted in alphabetical order. */ QStringList FociFile::getAllFociNamesSorted() const { std::set nameSet; const int32_t numFoci = getNumberOfFoci(); for (int32_t i = 0;i < numFoci; i++) { nameSet.insert(m_foci[i]->getName()); } QStringList sl; for (std::set::iterator iter = nameSet.begin(); iter != nameSet.end(); iter++) { sl += *iter; } return sl; } /** * @return The version of the file as a number. */ int32_t FociFile::getFileVersion() { return FociFile::s_fociFileVersion; } /** * @return The version of the file as a string. */ AString FociFile::getFileVersionAsString() { return AString::number(FociFile::getFileVersion()); } /** * Invalidate all assigned colors. */ void FociFile::invalidateAllAssignedColors() { const int32_t numFoci = getNumberOfFoci(); for (int32_t i = 0;i < numFoci; i++) { m_foci[i]->setNameRgbaInvalid(); m_foci[i]->setClassRgbaInvalid(); } m_forceUpdateOfGroupAndNameHierarchy = true; } /** * Read the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully read. */ void FociFile::readFile(const AString& filename) { clear(); checkFileReadability(filename); FociFileSaxReader saxReader(this); std::unique_ptr parser(XmlSaxParser::createXmlParser()); try { parser->parseFile(filename, &saxReader); } catch (const XmlSaxParserException& e) { clear(); setFileName(""); int lineNum = e.getLineNumber(); int colNum = e.getColumnNumber(); AString msg = "Parse Error while reading:"; if ((lineNum >= 0) && (colNum >= 0)) { msg += (" line/col (" + AString::number(e.getLineNumber()) + "/" + AString::number(e.getColumnNumber()) + ")"); } msg += (": " + e.whatString()); DataFileException dfe(filename, msg); CaretLogThrowing(dfe); throw dfe; } setFileName(filename); m_classNameHierarchy->update(this, true); m_forceUpdateOfGroupAndNameHierarchy = false; m_classNameHierarchy->setAllSelected(true); CaretLogFiner("CLASS/NAME Table for : " + getFileNameNoPath() + "\n" + m_classNameHierarchy->toString()); clearModified(); } /** * Write the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully written. */ void FociFile::writeFile(const AString& filename) { if (!(filename.endsWith(".foci") || filename.endsWith(".wb_foci"))) { CaretLogWarning("foci file '" + filename + "'should be saved ending in .foci"); } checkFileWritability(filename); setFileName(filename); try { // // Format the version string so that it ends with at most one zero // const AString versionString = FociFile::getFileVersionAsString(); // // Open the file // FileAdapter file; AString errorMessage; QTextStream* textStream = file.openQTextStreamForWritingFile(getFileName(), errorMessage); if (textStream == NULL) { throw DataFileException(getFileName(), errorMessage); } // // Create the xml writer // XmlWriter xmlWriter(*textStream); // // Write header info // xmlWriter.writeStartDocument("1.0"); // // Write GIFTI root element // XmlAttributes attributes; //attributes.addAttribute("xmlns:xsi", // "http://www.w3.org/2001/XMLSchema-instance"); //attributes.addAttribute("xsi:noNamespaceSchemaLocation", // "http://brainvis.wustl.edu/caret6/xml_schemas/GIFTI_Caret.xsd"); attributes.addAttribute(FociFile::XML_ATTRIBUTE_VERSION, versionString); xmlWriter.writeStartElement(FociFile::XML_TAG_FOCI_FILE, attributes); // // Write Metadata // if (m_metadata != NULL) { m_metadata->writeAsXML(xmlWriter); } // // Write the class color table // xmlWriter.writeStartElement(XML_TAG_CLASS_COLOR_TABLE); m_classColorTable->writeAsXML(xmlWriter); xmlWriter.writeEndElement(); // // Write the name color table // xmlWriter.writeStartElement(XML_TAG_NAME_COLOR_TABLE); m_nameColorTable->writeAsXML(xmlWriter); xmlWriter.writeEndElement(); // // Write foci // const int32_t numFoci = getNumberOfFoci(); for (int32_t i = 0; i < numFoci; i++) { m_foci[i]->writeAsXML(xmlWriter, i); } xmlWriter.writeEndElement(); xmlWriter.writeEndDocument(); file.close(); clearModified(); } catch (const GiftiException& e) { throw DataFileException(e); } catch (const XmlException& e) { throw DataFileException(e); } } /** * @return Is this foci file modified? */ bool FociFile::isModified() const { if (CaretDataFile::isModified()) { return true; } if (m_metadata->isModified()) { return true; } if (m_classColorTable->isModified()) { return true; } if (m_nameColorTable->isModified()) { return true; } /* * Note, these members do not affect modification status: * classNameHierarchy */ const int32_t numFoci = getNumberOfFoci(); for (int32_t i = 0; i < numFoci; i++) { if (m_foci[i]->isModified()) { return true; } } return false; } /** * Clear the modification status of this foci file. */ void FociFile::clearModified() { CaretDataFile::clearModified(); m_metadata->clearModified(); m_classColorTable->clearModified(); m_nameColorTable->clearModified(); const int32_t numFoci = getNumberOfFoci(); for (int32_t i = 0; i < numFoci; i++) { m_foci[i]->clearModified(); } } /** * Add information about the file to the data file information. * * @param dataFileInformation * Consolidates information about a data file. */ void FociFile::addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) { CaretDataFile::addToDataFileContentInformation(dataFileInformation); QStringList fociNames = getAllFociNamesSorted(); const int32_t numNames = fociNames.size(); if (numNames > 0) { AString namesListText = "FOCI NAMES"; for (int32_t i = 0; i < numNames; i++) { namesListText.appendWithNewLine(" " + fociNames.at(i)); } dataFileInformation.addText(namesListText); } } connectome-workbench-1.4.2/src/Files/FociFile.h000066400000000000000000000106301360521144700213150ustar00rootroot00000000000000#ifndef __FOCI_FILE__H_ #define __FOCI_FILE__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretDataFile.h" namespace caret { class GroupAndNameHierarchyModel; class Focus; class GiftiLabelTable; class GiftiMetaData; class FociFile : public CaretDataFile { public: FociFile(); virtual ~FociFile(); FociFile(const FociFile& obj); FociFile& operator=(const FociFile& obj); virtual void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation); GiftiMetaData* getFileMetaData(); const GiftiMetaData* getFileMetaData() const; StructureEnum::Enum getStructure() const; void setStructure(const StructureEnum::Enum structure); void readFile(const AString& filename); void writeFile(const AString& filename); void clear(); bool isEmpty() const; int32_t getNumberOfFoci() const; void addFocus(Focus* focus); Focus* getFocus(const int32_t indx); const Focus* getFocus(const int32_t indx) const; void removeFocus(const int32_t indx); void removeFocus(Focus* focus); GiftiLabelTable* getClassColorTable(); const GiftiLabelTable* getClassColorTable() const; GiftiLabelTable* getNameColorTable(); const GiftiLabelTable* getNameColorTable() const; void createNameAndClassColorTables(const GiftiLabelTable* oldColorTable); GroupAndNameHierarchyModel* getGroupAndNameHierarchyModel(); QStringList getAllFociNamesSorted() const; void invalidateAllAssignedColors(); virtual bool isModified() const; virtual void clearModified(); static int32_t getFileVersion(); static AString getFileVersionAsString(); /** XML Tag for foci file */ static const AString XML_TAG_FOCI_FILE; /** XML Tag for Version attribute */ static const AString XML_ATTRIBUTE_VERSION; /** XML Tag for Name Color Table */ static const AString XML_TAG_NAME_COLOR_TABLE; /** XML Tag for Class Color Table */ static const AString XML_TAG_CLASS_COLOR_TABLE; private: void copyHelperFociFile(const FociFile& obj); void initializeFociFile(); GiftiMetaData* m_metadata; std::vector m_foci; /** Holds colors assigned to classes */ GiftiLabelTable* m_classColorTable; /** Holds colors assigned to names */ GiftiLabelTable* m_nameColorTable; /** Holds class and name hierarchy used for display selection */ mutable GroupAndNameHierarchyModel* m_classNameHierarchy; /** force an update of the class and name hierarchy */ bool m_forceUpdateOfGroupAndNameHierarchy; /** Version of this FociFile */ static const int32_t s_fociFileVersion; }; #ifdef __FOCI_FILE_DECLARE__ const AString FociFile::XML_TAG_FOCI_FILE = "FociFile"; const AString FociFile::XML_ATTRIBUTE_VERSION = "Version"; const AString FociFile::XML_TAG_NAME_COLOR_TABLE = "FociNameColorTable"; const AString FociFile::XML_TAG_CLASS_COLOR_TABLE = "FociClassColorTable"; const int32_t FociFile::s_fociFileVersion = 2; #endif // __FOCI_FILE_DECLARE__ } // namespace #endif //__FOCI_FILE__H_ connectome-workbench-1.4.2/src/Files/FociFileSaxReader.cxx000066400000000000000000000352071360521144700234760ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretAssert.h" #include "GiftiLabelTable.h" #include "CaretLogger.h" #include "GiftiXmlElements.h" #include "FociFile.h" #include "FociFileSaxReader.h" #include "Focus.h" #include "GiftiLabelTableSaxReader.h" #include "GiftiMetaDataSaxReader.h" #include "StudyMetaDataLinkSet.h" #include "StudyMetaDataLinkSetSaxReader.h" #include "SurfaceProjectedItem.h" #include "SurfaceProjectedItemSaxReader.h" #include "XmlAttributes.h" #include "XmlException.h" #include "XmlUtilities.h" using namespace caret; /** * \class caret::FociFileSaxReader * \brief Reads a foci file using a SAX XML Parser. */ /** * constructor. */ FociFileSaxReader::FociFileSaxReader(FociFile* fociFile) { CaretAssert(fociFile); m_fociFile = fociFile; m_state = STATE_NONE; m_stateStack.push(m_state); m_elementText = ""; m_metaDataSaxReader = NULL; m_labelTableSaxReader = NULL; m_surfaceProjectedItemSaxReader = NULL; m_focus = NULL; m_surfaceProjectedItem = NULL; m_studyMetaDataLinkSetSaxReader = NULL; m_projectionCounter = 0; m_versionOneColorTable = NULL; } /** * destructor. */ FociFileSaxReader::~FociFileSaxReader() { /* * If reading fails, allocated items need to be deleted. */ if (m_metaDataSaxReader != NULL) { delete m_metaDataSaxReader; } if (m_labelTableSaxReader != NULL) { delete m_labelTableSaxReader; } if (m_surfaceProjectedItemSaxReader != NULL) { delete m_surfaceProjectedItemSaxReader; } if (m_surfaceProjectedItem != NULL) { delete m_surfaceProjectedItem; } if (m_focus != NULL) { delete m_focus; } if (m_studyMetaDataLinkSetSaxReader != NULL) { delete m_studyMetaDataLinkSetSaxReader; } if (m_versionOneColorTable != NULL) { delete m_versionOneColorTable; } } /** * start an element. */ void FociFileSaxReader::startElement(const AString& namespaceURI, const AString& localName, const AString& qName, const XmlAttributes& attributes) { const STATE previousState = m_state; switch (m_state) { case STATE_NONE: if (qName == FociFile::XML_TAG_FOCI_FILE) { m_state = STATE_FOCI_FILE; /* * At one time version was float, but now integer so if * getting the version fails as integer get as float * and convert to integer. */ int32_t versionBeingRead = 0; try { versionBeingRead = attributes.getValueAsInt(FociFile::XML_ATTRIBUTE_VERSION); } catch (const XmlSaxParserException& /*e*/) { const float floatVersion = attributes.getValueAsFloat(FociFile::XML_ATTRIBUTE_VERSION); versionBeingRead = static_cast(floatVersion); } if (versionBeingRead > FociFile::getFileVersion()) { AString msg = XmlUtilities::createInvalidVersionMessage(FociFile::getFileVersion(), versionBeingRead); XmlSaxParserException e(msg); CaretLogThrowing(e); throw e; } } else { const AString msg = XmlUtilities::createInvalidRootElementMessage(FociFile::XML_TAG_FOCI_FILE, qName); XmlSaxParserException e(msg); CaretLogThrowing(e); throw e; } break; case STATE_FOCUS: if (qName == SurfaceProjectedItem::XML_TAG_SURFACE_PROJECTED_ITEM) { m_state = STATE_SURFACE_PROJECTED_ITEM; m_surfaceProjectedItem = new SurfaceProjectedItem(); m_surfaceProjectedItemSaxReader = new SurfaceProjectedItemSaxReader(m_surfaceProjectedItem); m_surfaceProjectedItemSaxReader->startElement(namespaceURI, localName, qName, attributes); } else if (qName == StudyMetaDataLinkSet::XML_TAG_STUDY_META_DATA_LINK_SET) { m_state = STATE_STUDY_META_DATA_LINK_SET; m_studyMetaDataLinkSetSaxReader = new StudyMetaDataLinkSetSaxReader(m_focus->getStudyMetaDataLinkSet()); m_studyMetaDataLinkSetSaxReader->startElement(namespaceURI, localName, qName, attributes); } break; case STATE_FOCI_FILE: if (qName == FociFile::XML_TAG_CLASS_COLOR_TABLE) { m_state = STATE_CLASS_COLOR_TABLE; } else if (qName == FociFile::XML_TAG_NAME_COLOR_TABLE) { m_state = STATE_NAME_COLOR_TABLE; } else if (qName == GiftiXmlElements::TAG_LABEL_TABLE) { m_state = STATE_VERSION_ONE_COLOR_TABLE; m_versionOneColorTable = new GiftiLabelTable(); m_labelTableSaxReader = new GiftiLabelTableSaxReader(m_versionOneColorTable); m_labelTableSaxReader->startElement(namespaceURI, localName, qName, attributes); } else if (qName == GiftiXmlElements::TAG_METADATA) { m_state = STATE_METADATA; m_metaDataSaxReader = new GiftiMetaDataSaxReader(m_fociFile->getFileMetaData()); m_metaDataSaxReader->startElement(namespaceURI, localName, qName, attributes); } else if (qName == Focus::XML_TAG_FOCUS) { m_state = STATE_FOCUS; m_focus = new Focus(); m_projectionCounter = 0; } else { const AString msg = XmlUtilities::createInvalidChildElementMessage(FociFile::XML_TAG_FOCI_FILE, qName); XmlSaxParserException e(msg); CaretLogThrowing(e); throw e; } break; case STATE_METADATA: m_metaDataSaxReader->startElement(namespaceURI, localName, qName, attributes); break; case STATE_VERSION_ONE_COLOR_TABLE: m_labelTableSaxReader->startElement(namespaceURI, localName, qName, attributes); break; case STATE_CLASS_COLOR_TABLE: if (qName == GiftiXmlElements::TAG_LABEL_TABLE) { m_labelTableSaxReader = new GiftiLabelTableSaxReader(m_fociFile->getClassColorTable()); m_labelTableSaxReader->startElement(namespaceURI, localName, qName, attributes); } else if (qName == GiftiXmlElements::TAG_LABEL) { m_labelTableSaxReader->startElement(namespaceURI, localName, qName, attributes); } else { const AString msg = XmlUtilities::createInvalidChildElementMessage(FociFile::XML_TAG_CLASS_COLOR_TABLE, qName); XmlSaxParserException e(msg); CaretLogThrowing(e); throw e; } break; case STATE_NAME_COLOR_TABLE: if (qName == GiftiXmlElements::TAG_LABEL_TABLE) { m_labelTableSaxReader = new GiftiLabelTableSaxReader(m_fociFile->getNameColorTable()); m_labelTableSaxReader->startElement(namespaceURI, localName, qName, attributes); } else if (qName == GiftiXmlElements::TAG_LABEL) { m_labelTableSaxReader->startElement(namespaceURI, localName, qName, attributes); } else { const AString msg = XmlUtilities::createInvalidChildElementMessage(FociFile::XML_TAG_NAME_COLOR_TABLE, qName); XmlSaxParserException e(msg); CaretLogThrowing(e); throw e; } break; case STATE_SURFACE_PROJECTED_ITEM: m_surfaceProjectedItemSaxReader->startElement(namespaceURI, localName, qName, attributes); break; case STATE_STUDY_META_DATA_LINK_SET: m_studyMetaDataLinkSetSaxReader->startElement(namespaceURI, localName, qName, attributes); break; } // // Save previous state // m_stateStack.push(previousState); m_elementText = ""; } /** * end an element. */ void FociFileSaxReader::endElement(const AString& namespaceURI, const AString& localName, const AString& qName) { switch (m_state) { case STATE_NONE: break; case STATE_FOCUS: CaretAssert(m_focus); if (qName == Focus::XML_TAG_FOCUS) { m_fociFile->addFocus(m_focus); m_focus = NULL; // do not delete since added to foci file m_projectionCounter = 0; } else { m_focus->setElementFromText(qName, m_elementText.trimmed()); } break; case STATE_FOCI_FILE: break; case STATE_METADATA: CaretAssert(m_metaDataSaxReader); m_metaDataSaxReader->endElement(namespaceURI, localName, qName); if (qName == GiftiXmlElements::TAG_METADATA) { delete m_metaDataSaxReader; m_metaDataSaxReader = NULL; } break; case STATE_VERSION_ONE_COLOR_TABLE: CaretAssert(m_labelTableSaxReader); m_labelTableSaxReader->endElement(namespaceURI, localName, qName); if (qName == GiftiXmlElements::TAG_LABEL_TABLE) { delete m_labelTableSaxReader; m_labelTableSaxReader = NULL; } break; case STATE_CLASS_COLOR_TABLE: if (qName != FociFile::XML_TAG_CLASS_COLOR_TABLE) { CaretAssert(m_labelTableSaxReader); m_labelTableSaxReader->endElement(namespaceURI, localName, qName); if (qName == GiftiXmlElements::TAG_LABEL_TABLE) { delete m_labelTableSaxReader; m_labelTableSaxReader = NULL; } } break; case STATE_NAME_COLOR_TABLE: if (qName != FociFile::XML_TAG_NAME_COLOR_TABLE) { CaretAssert(m_labelTableSaxReader); m_labelTableSaxReader->endElement(namespaceURI, localName, qName); if (qName == GiftiXmlElements::TAG_LABEL_TABLE) { delete m_labelTableSaxReader; m_labelTableSaxReader = NULL; } } break; case STATE_SURFACE_PROJECTED_ITEM: CaretAssert(m_surfaceProjectedItemSaxReader); m_surfaceProjectedItemSaxReader->endElement(namespaceURI, localName, qName); if (qName == SurfaceProjectedItem::XML_TAG_SURFACE_PROJECTED_ITEM) { if (m_projectionCounter == 0) { /* * Remove all projections when the first projection * is read so that projections can be added as * they are read. */ m_focus->removeAllProjections(); } m_projectionCounter++; m_focus->addProjection(m_surfaceProjectedItem); m_surfaceProjectedItem = NULL; // do not delete since added to focus delete m_surfaceProjectedItemSaxReader; m_surfaceProjectedItemSaxReader = NULL; } break; case STATE_STUDY_META_DATA_LINK_SET: CaretAssert(m_studyMetaDataLinkSetSaxReader); m_studyMetaDataLinkSetSaxReader->endElement(namespaceURI, localName, qName); if (qName == StudyMetaDataLinkSet::XML_TAG_STUDY_META_DATA_LINK_SET) { delete m_studyMetaDataLinkSetSaxReader; m_studyMetaDataLinkSetSaxReader = NULL; } } // // Clear out for new elements // m_elementText = ""; // // Go to previous state // if (m_stateStack.empty()) { throw XmlSaxParserException("State stack is empty while reading XML NiftDataFile."); } m_state = m_stateStack.top(); m_stateStack.pop(); } /** * get characters in an element. */ void FociFileSaxReader::characters(const char* ch) { if (m_metaDataSaxReader != NULL) { m_metaDataSaxReader->characters(ch); } else if (m_labelTableSaxReader != NULL) { m_labelTableSaxReader->characters(ch); } else if (m_surfaceProjectedItemSaxReader != NULL) { m_surfaceProjectedItemSaxReader->characters(ch); } else { m_elementText += ch; } } /** * a fatal error occurs. */ void FociFileSaxReader::fatalError(const XmlSaxParserException& e) { /* std::ostringstream str; str << "Fatal Error at line number: " << e.getLineNumber() << "\n" << "Column number: " << e.getColumnNumber() << "\n" << "Message: " << e.whatString(); if (errorMessage.isEmpty() == false) { str << "\n" << errorMessage; } errorMessage = str.str(); */ // // Stop parsing // throw e; } // a warning occurs void FociFileSaxReader::warning(const XmlSaxParserException& e) { CaretLogWarning("XML Parser Warning: " + e.whatString()); } // an error occurs void FociFileSaxReader::error(const XmlSaxParserException& e) { CaretLogSevere("XML Parser Error: " + e.whatString()); throw e; } void FociFileSaxReader::startDocument() { } void FociFileSaxReader::endDocument() { if (m_versionOneColorTable != NULL) { m_fociFile->createNameAndClassColorTables(m_versionOneColorTable); } } connectome-workbench-1.4.2/src/Files/FociFileSaxReader.h000066400000000000000000000105231360521144700231150ustar00rootroot00000000000000 #ifndef __FOCI_FILE_SAX_READER_H__ #define __FOCI_FILE_SAX_READER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "XmlSaxParserException.h" #include "XmlSaxParserHandlerInterface.h" namespace caret { class Focus; class FociFile; class GiftiLabelTableSaxReader; class GiftiMetaDataSaxReader; class StudyMetaDataLinkSetSaxReader; class SurfaceProjectedItem; class SurfaceProjectedItemSaxReader; class XmlAttributes; class XmlException; class FociFileSaxReader : public CaretObject, public XmlSaxParserHandlerInterface { public: FociFileSaxReader(FociFile* fociFile); virtual ~FociFileSaxReader(); void startElement(const AString& namespaceURI, const AString& localName, const AString& qName, const XmlAttributes& attributes); void endElement(const AString& namspaceURI, const AString& localName, const AString& qName); void characters(const char* ch); void fatalError(const XmlSaxParserException& e); void warning(const XmlSaxParserException& e); void error(const XmlSaxParserException& e); void startDocument(); void endDocument(); protected: /// file reading states enum STATE { /// no state STATE_NONE, /// processing FociFile tag STATE_FOCI_FILE, /// processing MetaData tag STATE_METADATA, /// processing version one color table tag STATE_VERSION_ONE_COLOR_TABLE, /// processing class color table tag STATE_CLASS_COLOR_TABLE, /// processing name color table tag STATE_NAME_COLOR_TABLE, /// processing focus STATE_FOCUS, /// processing StudyMetaDataLinkSet tag STATE_STUDY_META_DATA_LINK_SET, /// processing SurfaceProjectedItem tag STATE_SURFACE_PROJECTED_ITEM }; /// file reading state STATE m_state; /// the state stack used when reading a file std::stack m_stateStack; /// the error message AString m_errorMessage; /// Foci file that is being read FociFile* m_fociFile; /// Focus that is being read Focus* m_focus; /// Counts projections as they are read int32_t m_projectionCounter; /// surface projected item that is being read SurfaceProjectedItem* m_surfaceProjectedItem; /// Reads a SurfaceProjectedItem SurfaceProjectedItemSaxReader* m_surfaceProjectedItemSaxReader; /// element text AString m_elementText; /// GIFTI meta data sax reader GiftiMetaDataSaxReader* m_metaDataSaxReader; /// GIFTI Label Table SAX Reader; GiftiLabelTableSaxReader* m_labelTableSaxReader; /** * Version 1 had only one color table that contained names and classes * After reading, split into name and class color tables */ GiftiLabelTable* m_versionOneColorTable; /// Study meta data link set reader StudyMetaDataLinkSetSaxReader* m_studyMetaDataLinkSetSaxReader; }; } // namespace #endif // __FOCI_FILE_SAX_READER_H__ connectome-workbench-1.4.2/src/Files/Focus.cxx000066400000000000000000000454461360521144700213040ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __FOCUS_DECLARE__ #include "Focus.h" #undef __FOCUS_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "StudyMetaDataLinkSet.h" #include "SurfaceProjectedItem.h" #include "XmlAttributes.h" #include "XmlWriter.h" using namespace caret; /** * \class caret::Focus * \brief A Focus. */ /** * Constructor. */ Focus::Focus() : CaretObjectTracksModification() { m_studyMetaDataLinkSet = new StudyMetaDataLinkSet(); clear(); } /** * Destructor. */ Focus::~Focus() { clear(); removeAllProjections(); delete m_studyMetaDataLinkSet; } /** * Copy constructor. * @param obj * Object that is copied. */ Focus::Focus(const Focus& obj) : CaretObjectTracksModification(obj) { m_studyMetaDataLinkSet = new StudyMetaDataLinkSet(); clear(); this->copyHelperFocus(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ Focus& Focus::operator=(const Focus& obj) { if (this != &obj) { CaretObjectTracksModification::operator=(obj); this->copyHelperFocus(obj); } return *this; } /** * Clear the focus. */ void Focus::clear() { m_area = ""; m_className = ""; m_comment = ""; m_extent = 0.0; m_geography = ""; m_name = ""; m_regionOfInterest = ""; m_searchXYZ[0] = 0.0; m_searchXYZ[1] = 0.0; m_searchXYZ[2] = 0.0; m_statistic = ""; m_studyMetaDataLinkSet->clear(); m_sumsIdNumber = ""; m_sumsRepeatNumber = ""; m_sumsParentFocusBaseId = ""; m_sumsVersionNumber = ""; m_sumsMSLID = ""; m_attributeID = ""; m_groupNameSelectionItem = NULL; m_nameRgbaColor[0] = 0.0; m_nameRgbaColor[1] = 0.0; m_nameRgbaColor[2] = 0.0; m_nameRgbaColor[3] = 1.0; m_nameRgbaColorValid = false; m_classRgbaColor[0] = 0.0; m_classRgbaColor[1] = 0.0; m_classRgbaColor[2] = 0.0; m_classRgbaColor[3] = 1.0; m_classRgbaColorValid = false; setNameOrClassModified(); // new name/class so modified removeAllProjections(); addProjection(new SurfaceProjectedItem()); } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void Focus::copyHelperFocus(const Focus& focus) { clear(); m_area = focus.m_area; m_className = focus.m_className; m_comment = focus.m_comment; m_extent = focus.m_extent; m_geography = focus.m_geography; m_name = focus.m_name; m_regionOfInterest = focus.m_regionOfInterest; m_searchXYZ[0] = focus.m_searchXYZ[0]; m_searchXYZ[1] = focus.m_searchXYZ[1]; m_searchXYZ[2] = focus.m_searchXYZ[2]; m_statistic = focus.m_statistic; delete m_studyMetaDataLinkSet; m_studyMetaDataLinkSet = new StudyMetaDataLinkSet(*focus.m_studyMetaDataLinkSet); m_sumsIdNumber = focus.m_sumsIdNumber; m_sumsRepeatNumber = focus.m_sumsRepeatNumber; m_sumsParentFocusBaseId = focus.m_sumsParentFocusBaseId; m_sumsVersionNumber = focus.m_sumsVersionNumber; m_sumsMSLID = focus.m_sumsMSLID; m_attributeID = focus.m_attributeID; this->removeAllProjections(); const int numProj = focus.getNumberOfProjections(); for (int32_t i = 0; i < numProj; i++) { SurfaceProjectedItem* spi = new SurfaceProjectedItem(*focus.getProjection(i)); this->addProjection(spi); } if (m_projections.empty()) { this->addProjection(new SurfaceProjectedItem()); } setNameOrClassModified(); // new name/class so modified } /** * @return Class name */ AString Focus::getClassName() const { return m_className; } /** * Set the class name * @param className */ void Focus::setClassName(const AString& className) { if (m_className != className) { m_className = className; setNameOrClassModified(); setModified(); } } /** * @return Area */ AString Focus::getArea() const { return m_area; } /** * Set the area * @param area */ void Focus::setArea(const AString& area) { if (m_area != area) { m_area = area; setModified(); } } /** * @return Comment */ AString Focus::getComment() const { return m_comment; } /** * Set the comment * @param */ void Focus::setComment(const AString& comment) { if (m_comment != comment) { m_comment = comment; setModified(); } } /** * @return Extent */ float Focus::getExtent() const { return m_extent; } /** * Set the extent * @param extent */ void Focus::setExtent(const float extent) { if (m_extent != extent) { m_extent = extent; setModified(); } } /** * @return Geography */ AString Focus::getGeography() const { return m_geography; } /** * Set the geography. * @param geography */ void Focus::setGeography(const AString& geography) { m_geography = geography; } /** * @return Name */ AString Focus::getName() const { return m_name; } /** * Set the name * @param name */ void Focus::setName(const AString& name) { if (m_name != name) { m_name = name; setNameOrClassModified(); setModified(); } } /** * @return Region of interest */ AString Focus::getRegionOfInterest() const { return m_regionOfInterest; } /** * Set the region of interest * @param regionOfInterest */ void Focus::setRegionOfInterest(const AString& regionOfInterest) { if (m_regionOfInterest != regionOfInterest) { m_regionOfInterest = regionOfInterest; setModified(); } } /** * @return Search coordinate */ const float* Focus::getSearchXYZ() const { /* * If not set, return stereotaxic coordinate */ if ((m_searchXYZ[0] == 0.0) && (m_searchXYZ[1] == 0.0) && (m_searchXYZ[2] == 0.0)) { const float* stereoXYZ = m_projections[0]->getStereotaxicXYZ(); return stereoXYZ; } return m_searchXYZ; } /** * Set the search XYZ * @param searchXYZ */ void Focus::setSearchXYZ(const float searchXYZ[3]) { if ((m_searchXYZ[0] != searchXYZ[0]) || (m_searchXYZ[1] != searchXYZ[1]) || (m_searchXYZ[2] != searchXYZ[2])) { m_searchXYZ[0] = searchXYZ[0]; m_searchXYZ[1] = searchXYZ[1]; m_searchXYZ[2] = searchXYZ[2]; setModified(); } } /** * @return statistic */ AString Focus::getStatistic() const { return m_statistic; } /** * Set the statistic * @param statistic */ void Focus::setStatistic(const AString& statistic) { if (m_statistic != statistic) { m_statistic = statistic; setModified(); } } /** * @return Is the class RGBA color valid? */ bool Focus::isClassRgbaValid() const { return m_classRgbaColorValid; } /** * Set then class RGBA color invalid. */ void Focus::setClassRgbaInvalid() { m_classRgbaColorValid = false; } /** * @return The class RGBA color components * ranging zero to one. */ const float* Focus::getClassRgba() const { return m_classRgbaColor; } /** * Get the class RGBA color components * ranging zero to one. */ void Focus::getClassRgba(float rgba[4]) const { rgba[0] = m_classRgbaColor[0]; rgba[1] = m_classRgbaColor[1]; rgba[2] = m_classRgbaColor[2]; rgba[3] = m_classRgbaColor[3]; } /** * Set the RGBA color components assigned to the class. * @param rgba * Red, green, blue, alpha ranging zero to one. */ void Focus::setClassRgba(const float rgba[3]) { m_classRgbaColor[0] = rgba[0]; m_classRgbaColor[1] = rgba[1]; m_classRgbaColor[2] = rgba[2]; m_classRgbaColor[3] = rgba[3]; m_classRgbaColorValid = true; } /** * @return Is the name RGBA color valid? */ bool Focus::isNameRgbaValid() const { return m_nameRgbaColorValid; } /** * Set then name RGBA color invalid. */ void Focus::setNameRgbaInvalid() { m_nameRgbaColorValid = false; } /** * @return The name RGBA color components * ranging zero to one. */ const float* Focus::getNameRgba() const { return m_nameRgbaColor; } /** * Get the name RGBA color components * ranging zero to one. */ void Focus::getNameRgba(float rgba[4]) const { rgba[0] = m_nameRgbaColor[0]; rgba[1] = m_nameRgbaColor[1]; rgba[2] = m_nameRgbaColor[2]; rgba[3] = m_nameRgbaColor[3]; } /** * Set the RGBA color components assigned to the name. * @param rgba * Red, green, blue, alpha ranging zero to one. */ void Focus::setNameRgba(const float rgba[4]) { m_nameRgbaColor[0] = rgba[0]; m_nameRgbaColor[1] = rgba[1]; m_nameRgbaColor[2] = rgba[2]; m_nameRgbaColor[3] = rgba[3]; m_nameRgbaColorValid = true; } /** * Set the selection item for the group/name hierarchy. * * @param item * The selection item from the group/name hierarchy. */ void Focus::setGroupNameSelectionItem(GroupAndNameHierarchyItem* item) { m_groupNameSelectionItem = item; } /** * @return The selection item for the Group/Name selection hierarchy. * May be NULL in some circumstances. */ const GroupAndNameHierarchyItem* Focus::getGroupNameSelectionItem() const { return m_groupNameSelectionItem; } /** * @return Sums ID Number */ AString Focus::getSumsIdNumber() const { return m_sumsIdNumber; } /** * Set the Sums ID Number * @param sumsIdNumber */ void Focus::setSumsIdNumber(const AString& sumsIdNumber) { if (m_sumsIdNumber != sumsIdNumber) { m_sumsIdNumber = sumsIdNumber; setModified(); } } /** * @return Sums Repeat number */ AString Focus::getSumsRepeatNumber() const { return m_sumsRepeatNumber; } /** * Set the Sums Repeat Number * @param sumsRepeatNumber */ void Focus::setSumsRepeatNumber(const AString& sumsRepeatNumber) { if (m_sumsRepeatNumber != sumsRepeatNumber) { m_sumsRepeatNumber = sumsRepeatNumber; setModified(); } } /** * @return Sums parent focus base id */ AString Focus::getSumsParentFocusBaseId() const { return m_sumsParentFocusBaseId; } /** * Set the Sums Parent Focus Base ID * @param sumsParentFocusBaseId */ void Focus::setSumsParentFocusBaseId(const AString& sumsParentFocusBaseId) { if (m_sumsParentFocusBaseId != sumsParentFocusBaseId) { m_sumsParentFocusBaseId = sumsParentFocusBaseId; setModified(); } } /** * @return Sums version number */ AString Focus::getSumsVersionNumber() const { return m_sumsVersionNumber; } /** * Set the Sums version number * @param sumsVersionNumber */ void Focus::setSumsVersionNumber(const AString& sumsVersionNumber) { if (m_sumsVersionNumber != sumsVersionNumber) { m_sumsVersionNumber = sumsVersionNumber; setModified(); } } /** * @return Sums MSLID */ AString Focus::getSumsMSLID() const { return m_sumsMSLID; } /** * Set the Sums MSLID * @param sumsMSLID */ void Focus::setSumsMSLID(const AString& sumsMSLID) { if (m_sumsMSLID != sumsMSLID) { m_sumsMSLID = sumsMSLID; setModified(); } } /** * @return Sums attribute ID */ AString Focus::getSumsAttributeID() const { return m_attributeID; } /** * Set the Atribute ID * @param attributeID */ void Focus::setSumsAttributeID(const AString& attributeID) { if (m_attributeID != attributeID) { m_attributeID = attributeID; setModified(); } } /** * @return Number of projections */ int32_t Focus::getNumberOfProjections() const { return m_projections.size(); } /** * Get the projection at the given index. * Note: Index 0 will ALWAYS return a valid projection. * * @param indx * Index of projection * @return * Projection at given index. */ const SurfaceProjectedItem* Focus::getProjection(const int32_t indx) const { CaretAssertVectorIndex(m_projections, indx); return m_projections[indx]; } /** * Get the projection at the given index. * Note: Index 0 will ALWAYS return a valid projection. * * @param indx * Index of projection * @return * Projection at given index. */ SurfaceProjectedItem* Focus::getProjection(const int32_t indx) { CaretAssertVectorIndex(m_projections, indx); return m_projections[indx]; } /** * Add the projection. Note: the focus * takes ownership of the projection and will * delete it. After calling this method DO NOT * ever use the projection passed to this method. * * @param projection * Projection that is added. */ void Focus::addProjection(SurfaceProjectedItem* projection) { CaretAssert(projection); m_projections.push_back(projection); } /** * Remove all of the projections. A focus always * has one projection but this method removes all * projections so caller will need to to add a * projection. */ void Focus::removeAllProjections() { const int32_t numProj = getNumberOfProjections(); for (int32_t i = 0; i < numProj; i++) { delete m_projections[i]; } m_projections.clear(); } /** * Remove all but the first projection. */ void Focus::removeExtraProjections() { const int32_t numProj = getNumberOfProjections(); for (int32_t i = 1; i < numProj; i++) { delete m_projections[i]; } m_projections.resize(1); } /** * @return The study meta data link set. */ StudyMetaDataLinkSet* Focus::getStudyMetaDataLinkSet() { return m_studyMetaDataLinkSet; } /** * @return The study meta data link set. */ const StudyMetaDataLinkSet* Focus::getStudyMetaDataLinkSet() const { return m_studyMetaDataLinkSet; } /** * Write the focus to XML. * @param xmlWriter * Writer to which focus is written. * @param focusIndex * Index of the focus. */ void Focus::writeAsXML(XmlWriter& xmlWriter, const int32_t focusIndex) { XmlAttributes atts; atts.addAttribute(XML_ATTRIBUTE_FOCUS_INDEX, focusIndex); xmlWriter.writeStartElement(XML_TAG_FOCUS, atts); xmlWriter.writeElementCData(XML_TAG_AREA, m_area); xmlWriter.writeElementCData(XML_TAG_CLASS_NAME, m_className); xmlWriter.writeElementCData(XML_TAG_COMMENT, m_comment); xmlWriter.writeElementCharacters(XML_TAG_EXTENT, m_extent); xmlWriter.writeElementCData(XML_TAG_GEOGRAPHY, m_geography); xmlWriter.writeElementCData(XML_TAG_NAME, m_name); xmlWriter.writeElementCData(XML_TAG_REGION_OF_INTEREST, m_regionOfInterest); xmlWriter.writeElementCharacters(XML_TAG_SEARCH_XYZ, m_searchXYZ, 3); xmlWriter.writeElementCData(XML_TAG_STATISTIC, m_statistic); xmlWriter.writeElementCData(XML_TAG_SUMS_ID_NUMBER, m_sumsIdNumber); xmlWriter.writeElementCData(XML_TAG_SUMS_REPEAT_NUMBER, m_sumsRepeatNumber); xmlWriter.writeElementCData(XML_TAG_SUMS_PARENT_FOCUS_BASE_ID, m_sumsParentFocusBaseId); xmlWriter.writeElementCData(XML_TAG_SUMS_VERSION_NUMBER, m_sumsVersionNumber); xmlWriter.writeElementCData(XML_TAG_SUMS_MSLID, m_sumsMSLID); xmlWriter.writeElementCData(XML_TAG_SUMS_ATTRIBUTE_ID, m_attributeID); m_studyMetaDataLinkSet->writeXML(xmlWriter); const int32_t numProj = getNumberOfProjections(); for (int32_t i = 0; i < numProj; i++) { m_projections[i]->writeAsXML(xmlWriter); } xmlWriter.writeEndElement(); } /** * Set modification status of name/class to modified. * * Name/Class modification status is used * by the selection controls that display * borders based upon selected classes and * names. */ void Focus::setNameOrClassModified() { m_groupNameSelectionItem = NULL; m_nameRgbaColorValid = false; m_classRgbaColorValid = false; } /** * Set an element from its XML tag name * @param elementName * Name of XML element. * @param textValue * Value of element's text. * @return * True if element was valid, else false. */ bool Focus::setElementFromText(const AString& elementName, const AString& textValue) { if (elementName == Focus::XML_TAG_AREA) { m_area = textValue; } else if (elementName == Focus::XML_TAG_CLASS_NAME) { m_className = textValue; } else if (elementName == "Color") { // obsolete element } else if (elementName == Focus::XML_TAG_COMMENT) { m_comment = textValue; } else if (elementName == Focus::XML_TAG_EXTENT) { m_extent = textValue.toFloat(); } else if (elementName == Focus::XML_TAG_GEOGRAPHY) { m_geography = textValue; } else if (elementName == Focus::XML_TAG_NAME) { m_name = textValue; } else if (elementName == Focus::XML_TAG_REGION_OF_INTEREST) { m_regionOfInterest = textValue; } else if (elementName == Focus::XML_TAG_SEARCH_XYZ) { std::vector xyz; AString::toNumbers(textValue, xyz); if (xyz.size() == 3) { m_searchXYZ[0] = xyz[0]; m_searchXYZ[1] = xyz[1]; m_searchXYZ[2] = xyz[2]; } } else if (elementName == Focus::XML_TAG_STATISTIC) { m_statistic = textValue; } else if (elementName == Focus::XML_TAG_SUMS_ID_NUMBER) { m_sumsIdNumber = textValue; } else if (elementName == Focus::XML_TAG_SUMS_REPEAT_NUMBER) { m_sumsRepeatNumber = textValue; } else if (elementName == Focus::XML_TAG_SUMS_PARENT_FOCUS_BASE_ID) { m_sumsParentFocusBaseId = textValue; } else if (elementName == Focus::XML_TAG_SUMS_VERSION_NUMBER) { m_sumsVersionNumber = textValue; } else if (elementName == Focus::XML_TAG_SUMS_MSLID) { m_sumsMSLID = textValue; } else if (elementName == Focus::XML_TAG_SUMS_ATTRIBUTE_ID) { m_attributeID = textValue; } else { return false; } return true; } /** * Clear the modification status of the focus. */ void Focus::clearModified() { CaretObjectTracksModification::clearModified(); const int numProj = getNumberOfProjections(); for (int32_t i = 0; i < numProj; i++) { SurfaceProjectedItem* spi = getProjection(i); spi->clearModified(); } } /** * @return The modification status. */ bool Focus::isModified() const { if (CaretObjectTracksModification::isModified()) { return true; } const int numProj = getNumberOfProjections(); for (int32_t i = 0; i < numProj; i++) { const SurfaceProjectedItem* spi = getProjection(i); if (spi->isModified()) { return true; } } return false; } connectome-workbench-1.4.2/src/Files/Focus.h000066400000000000000000000177771360521144700207370ustar00rootroot00000000000000#ifndef __FOCUS__H_ #define __FOCUS__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObjectTracksModification.h" #include "SurfaceProjectedItem.h" namespace caret { class FociFileSaxReader; class GroupAndNameHierarchyItem; class StudyMetaDataLinkSet; class Focus : public CaretObjectTracksModification { public: Focus(); virtual ~Focus(); Focus(const Focus& obj); Focus& operator=(const Focus& obj); void clear(); AString getClassName() const; void setClassName(const AString& name); AString getArea() const; void setArea(const AString& area); AString getComment() const; void setComment(const AString& area); float getExtent() const; void setExtent(const float extent); AString getGeography() const; void setGeography(const AString& geography); AString getName() const; void setName(const AString& name); AString getRegionOfInterest() const; void setRegionOfInterest(const AString& regionOfInterest); const float* getSearchXYZ() const; void setSearchXYZ(const float searchXYZ[3]); AString getStatistic() const; void setStatistic(const AString& statistic); bool isClassRgbaValid() const; void setClassRgbaInvalid(); const float* getClassRgba() const; void getClassRgba(float rgba[4]) const; void setClassRgba(const float rgba[4]); bool isNameRgbaValid() const; void setNameRgbaInvalid(); const float* getNameRgba() const; void getNameRgba(float rgba[4]) const; void setNameRgba(const float rgba[4]); AString getSumsIdNumber() const; void setSumsIdNumber(const AString& sumsIdNumber); AString getSumsRepeatNumber() const; void setSumsRepeatNumber(const AString& sumsRepeatNumber); AString getSumsParentFocusBaseId() const; void setSumsParentFocusBaseId(const AString& sumsParentFocusBaseId); AString getSumsVersionNumber() const; void setSumsVersionNumber(const AString& sumsVersionNumber); AString getSumsMSLID() const; void setSumsMSLID(const AString& sumsMSLID); AString getSumsAttributeID() const; void setSumsAttributeID(const AString& attributeID); int32_t getNumberOfProjections() const; const SurfaceProjectedItem* getProjection(const int32_t indx) const; SurfaceProjectedItem* getProjection(const int32_t indx); void addProjection(SurfaceProjectedItem* projection); void removeExtraProjections(); StudyMetaDataLinkSet* getStudyMetaDataLinkSet(); const StudyMetaDataLinkSet* getStudyMetaDataLinkSet() const; void setGroupNameSelectionItem(GroupAndNameHierarchyItem* item); const GroupAndNameHierarchyItem* getGroupNameSelectionItem() const; void writeAsXML(XmlWriter& xmlWriter, const int32_t focusIndex); bool setElementFromText(const AString& elementName, const AString& textValue); virtual void clearModified(); virtual bool isModified() const; static const AString XML_ATTRIBUTE_FOCUS_INDEX; static const AString XML_TAG_FOCUS; static const AString XML_TAG_AREA; static const AString XML_TAG_CLASS_NAME; static const AString XML_TAG_COMMENT; static const AString XML_TAG_EXTENT; static const AString XML_TAG_GEOGRAPHY; static const AString XML_TAG_NAME; static const AString XML_TAG_REGION_OF_INTEREST; static const AString XML_TAG_SEARCH_XYZ; static const AString XML_TAG_STATISTIC; static const AString XML_TAG_SUMS_ID_NUMBER; static const AString XML_TAG_SUMS_REPEAT_NUMBER; static const AString XML_TAG_SUMS_PARENT_FOCUS_BASE_ID; static const AString XML_TAG_SUMS_VERSION_NUMBER; static const AString XML_TAG_SUMS_MSLID; static const AString XML_TAG_SUMS_ATTRIBUTE_ID; private: void copyHelperFocus(const Focus& obj); void setNameOrClassModified(); void removeAllProjections(); AString m_area; AString m_className; AString m_comment; float m_extent; AString m_geography; AString m_name; AString m_regionOfInterest; float m_searchXYZ[3]; AString m_statistic; StudyMetaDataLinkSet* m_studyMetaDataLinkSet; AString m_sumsIdNumber; AString m_sumsRepeatNumber; AString m_sumsParentFocusBaseId; AString m_sumsVersionNumber; AString m_sumsMSLID; AString m_attributeID; /** RGBA color components assigned to focus' name */ float m_nameRgbaColor[4]; /** RGBA color components assigned to focus' name validity */ bool m_nameRgbaColorValid; /** RGBA color component assigned to focus' class name */ float m_classRgbaColor[4]; /** RGBA color components assigned to focus' name validity */ bool m_classRgbaColorValid; /** May project to more than one surface */ std::vector m_projections; /** Selection status of this border in the group/name hierarchy */ GroupAndNameHierarchyItem* m_groupNameSelectionItem; /** Allow foci file SAX reader to remove all projections */ friend class FociFileSaxReader; }; #ifdef __FOCUS_DECLARE__ const AString Focus::XML_ATTRIBUTE_FOCUS_INDEX = "Index"; const AString Focus::XML_TAG_FOCUS = "Focus"; const AString Focus::XML_TAG_AREA = "Area"; const AString Focus::XML_TAG_CLASS_NAME = "ClassName"; const AString Focus::XML_TAG_COMMENT = "Comment"; const AString Focus::XML_TAG_EXTENT = "Extent"; const AString Focus::XML_TAG_GEOGRAPHY = "Geography"; const AString Focus::XML_TAG_NAME = "Name"; const AString Focus::XML_TAG_REGION_OF_INTEREST = "RegionOfInterest"; const AString Focus::XML_TAG_SEARCH_XYZ = "SearchXYZ"; const AString Focus::XML_TAG_STATISTIC = "Statistic"; const AString Focus::XML_TAG_SUMS_ID_NUMBER = "SumsIDNumber"; const AString Focus::XML_TAG_SUMS_REPEAT_NUMBER = "SumsRepeatNumber"; const AString Focus::XML_TAG_SUMS_PARENT_FOCUS_BASE_ID = "SumsParentFocusBaseID"; const AString Focus::XML_TAG_SUMS_VERSION_NUMBER = "SumsVersionNumber"; const AString Focus::XML_TAG_SUMS_MSLID = "SumsMSLID"; const AString Focus::XML_TAG_SUMS_ATTRIBUTE_ID = "AttributeID"; #endif // __FOCUS_DECLARE__ } // namespace #endif //__FOCUS__H_ connectome-workbench-1.4.2/src/Files/GeodesicHelper.cxx000066400000000000000000001606421360521144700231030ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "GeodesicHelper.h" #include "CaretAssert.h" #include "CaretHeap.h" #include "CaretMutex.h" #include "FastStatistics.h" #include "SurfaceFile.h" #include "TopologyHelper.h" #include #include using namespace caret; using namespace std; GeodesicHelperBase::GeodesicHelperBase(const SurfaceFile* surfaceIn, const float* correctedAreas) { CaretPointer topoBase(new TopologyHelperBase(surfaceIn)); TopologyHelper topoHelpIn(topoBase);//leave this building one privately, to not introduce even worse dependencies regarding SurfaceFile m_corrAreaSmallestFactor = 1.0f; numNodes = surfaceIn->getNumberOfNodes(); nodeNeighbors.resize(numNodes); distances.resize(numNodes); nodeCoords.resize(numNodes); vector sqrtCorrAreas;//each edge has 2 vertices that influence it - assume that each influences a piece of the edge with a ratio depending on the square roots of the vertex areas vector sqrtVertAreas;//we also assume isometric expansion at each vertex if (correctedAreas != NULL)//this gives an estimated original length of curLength * (sqrt(origA) + sqrt(origB))/(sqrt(curA) + sqrt(curB)) { surfaceIn->computeNodeAreas(sqrtVertAreas); sqrtCorrAreas.resize(numNodes); for (int i = 0; i < numNodes; ++i) { sqrtCorrAreas[i] = sqrt(correctedAreas[i]); sqrtVertAreas[i] = sqrt(sqrtVertAreas[i]); } } Vector3D tempvec; float tempf, abmag, efmag, cdmag; double nodeSpacingAccum = 0.0f;//since we may be using corrected areas, find average node spacing manually int32_t numEdges = 0; bool firstCorrArea = true;//if all corrected vertex areas are significantly larger than 1, we can make A* faster by multiplying all euclidean distances by it, so find the actual smallest for (int32_t i = 0; i < numNodes; ++i) {//get neighbors vector& neighbors = nodeNeighbors[i]; neighbors = topoHelpIn.getNodeNeighbors(i); nodeCoords[i] = surfaceIn->getCoordinate(i); const Vector3D baseCoord = nodeCoords[i]; int numNeigh = (int)neighbors.size(); distances[i].resize(numNeigh); for (int32_t j = 0; j < numNeigh; ++j) { Vector3D neighCoord = surfaceIn->getCoordinate(neighbors[j]); tempvec = baseCoord - neighCoord; distances[i][j] = tempvec.length();//precompute for speed in other calls if (correctedAreas != NULL) { float correctionFactor = (sqrtCorrAreas[i] + sqrtCorrAreas[neighbors[j]]) / (sqrtVertAreas[i] + sqrtVertAreas[neighbors[j]]); if (firstCorrArea || correctionFactor < m_corrAreaSmallestFactor) { m_corrAreaSmallestFactor = correctionFactor;//if this is zero anywhere, it just means that the euclidean part of the heuristic must be ignored (worst case, it does dijkstra) firstCorrArea = false; } distances[i][j] *= correctionFactor; } if (i < neighbors[j]) { nodeSpacingAccum += distances[i][j]; ++numEdges; } }//so few floating point operations, this should turn out symmetric } m_avgNodeSpacing = nodeSpacingAccum / numEdges; std::vector tempneigh2; std::vector tempdist2; nodeNeighbors2.resize(numNodes); distances2.resize(numNodes); neighbors2PathInfo.resize(numNodes); const vector& myEdgeInfo = topoHelpIn.getEdgeInfo(); CaretAssert(numEdges == (int32_t)myEdgeInfo.size());//SurfaceFile checks for triangles with duplicated nodes for (int i = 0; i < numEdges; ++i) { if (myEdgeInfo[i].numTiles < 2) { continue;//skip edges that have only one triangle } int32_t neigh1Node, neigh2Node, baseNode, farNode; neigh1Node = myEdgeInfo[i].node1; neigh2Node = myEdgeInfo[i].node2; baseNode = myEdgeInfo[i].tiles[0].node3; farNode = myEdgeInfo[i].tiles[1].node3; Vector3D neigh1Coord = nodeCoords[neigh1Node]; Vector3D neigh2Coord = nodeCoords[neigh2Node]; Vector3D baseCoord = nodeCoords[baseNode]; Vector3D farCoord = nodeCoords[farNode]; CrawlInfo tempInfo; tempInfo.edgeNodes[0] = neigh1Node; tempInfo.edgeNodes[1] = neigh2Node; const int32_t num_reserve = 8;//uses 8 in case it is used on a mesh with haphazard topology nodeNeighbors2[baseNode].reserve(num_reserve);//reserve should be fast if capacity is already num_reserve, and better than reallocating at 2 and 4, if vector allocation is naive doubling nodeNeighbors2[farNode].reserve(num_reserve);//in the extremely rare case of a node with more than num_reserve neighbors, a second allocation plus copy isn't much of a cost distances2[baseNode].reserve(num_reserve); distances2[farNode].reserve(num_reserve); neighbors2PathInfo[baseNode].reserve(num_reserve); neighbors2PathInfo[farNode].reserve(num_reserve); Vector3D abhat = (neigh2Coord - neigh1Coord).normal(&abmag);//a is neigh1, b is neigh2, b - a = (vector)ab Vector3D ac = farCoord - neigh1Coord;//c is farnode, c - a = (vector)ac Vector3D ad = abhat * abhat.dot(ac);//d is the point on the shared edge that farnode (c) is closest to Vector3D d = neigh1Coord + ad;//this way we can "unfold" the triangles by projecting the distance of cd, from point d, along the unit vector of the base node to closest point on shared edge Vector3D ea = neigh1Coord - baseCoord;//e is the base node, a - e = (vector)ea tempvec = abhat * abhat.dot(ea);//find vector fa, f being the point on shared edge closest to e, the base node Vector3D efhat = (ea - tempvec).normal(&efmag);//and subtract it to obtain only the perpendicular, normalize to get unit vector cdmag = (d - farCoord).length();//get the length from shared edge to far point Vector3D g = d + efhat * cdmag;//get point g, the unfolded position of farnode Vector3D eg = g - baseCoord;//this is the vector from base (e) to far node after unfolding (g), this is our distance, as long as the tetralateral is convex tempf = efmag / (efmag + cdmag);//now we need to check that the path stays inside the tetralateral (ie, that it is convex) Vector3D eh = eg * tempf;//this is a vector from e (base node) to the point on the shared edge that the full path (eg) crosses Vector3D ah = eh - ea;//eh - ea = eh + ae = ae + eh = ah, vector from neigh1 to the point on shared edge the path goes through tempf = ah.dot(abhat);//get the component along ab so we can test that it is positive and less than |ab| if (tempf <= 0.0f || tempf >= abmag) continue;//tetralateral is concave or triangular (degenerate), our path is invalid or not shorter, so consider next edge tempInfo.edgeWeight = 1.0f - tempf / abmag;//if tempf is almost zero, then the weight of point a (neigh1) is almost 1 tempf = eg.length();//this is our path length tempInfo.pieceDists[1] = eh.length();//we currently add things to farNode's neighbor info before baseNode's if (correctedAreas != NULL)//apply area correction approximation { float correctionFactor = (sqrtCorrAreas[baseNode] + sqrtCorrAreas[farNode]) / (sqrtVertAreas[baseNode] + sqrtVertAreas[farNode]); if (correctionFactor < m_corrAreaSmallestFactor) { m_corrAreaSmallestFactor = correctionFactor;//if this is zero anywhere, it just means that the euclidean part of the heuristic must be ignored (worst case, it does dijkstra) } tempf *= correctionFactor; tempInfo.pieceDists[1] *= correctionFactor; }//for now, assume it only depends on the expansion of the endpoints, and affects each part equally tempInfo.pieceDists[0] = tempf - tempInfo.pieceDists[1]; nodeNeighbors2[farNode].push_back(baseNode);//record it at both ends, because we are looping through edges distances2[farNode].push_back(tempf); neighbors2PathInfo[farNode].push_back(tempInfo); float tempf2 = tempInfo.pieceDists[0];//swap the piece distances around for the baseNode info tempInfo.pieceDists[0] = tempInfo.pieceDists[1]; tempInfo.pieceDists[1] = tempf2; nodeNeighbors2[baseNode].push_back(farNode); distances2[baseNode].push_back(tempf); neighbors2PathInfo[baseNode].push_back(tempInfo); } } GeodesicHelper::GeodesicHelper(const CaretPointer& baseIn) { m_myBase = baseIn;//copy the pointer so it doesn't get changed or deleted while we get its members //get references and info from base numNodes = m_myBase->numNodes; m_avgNodeSpacing = m_myBase->m_avgNodeSpacing; m_corrAreaSmallestFactor = m_myBase->m_corrAreaSmallestFactor; distances = m_myBase->distances.data(); distances2 = m_myBase->distances2.data(); nodeNeighbors = m_myBase->nodeNeighbors.data(); nodeNeighbors2 = m_myBase->nodeNeighbors2.data(); nodeCoords = m_myBase->nodeCoords.data(); neighbors2PathInfo = m_myBase->neighbors2PathInfo.data(); //allocate private scratch space marked.resize(numNodes, 0);//initialize once, each internal function (dijkstra methods) tracks elements changed, and resets only those (except in the case of whole surface) m_heapIdent.resize(numNodes);//the idea is to make it faster for the more likely case of small areas of the surface for functions that have limits, by removing the runtime term based solely on surface size outputStore.resize(numNodes); output = outputStore.data();//because we have a function that does a pointer swap to compute distances directly in the output array changed.resize(numNodes); parentStore.resize(numNodes); parent = parentStore.data();//ditto for parents heurVal.resize(numNodes); } void GeodesicHelper::getNodesToGeoDist(const int32_t node, const float maxdist, std::vector& nodesOut, std::vector& distsOut, const bool smoothflag) {//public methods sanity check, private methods process nodesOut.clear(); distsOut.clear(); CaretAssert(node < numNodes && node >= 0); if (node >= numNodes || maxdist < 0.0f || node < 0) return;//check what we asserted so release doesn't do strange things CaretMutexLocker locked(&inUse);//let sanity checks go multithreaded, as if it mattered dijkstra(node, maxdist, nodesOut, distsOut, smoothflag); } void GeodesicHelper::getNodesToGeoDist(const int32_t node, const float maxdist, std::vector& nodesOut, std::vector& distsOut, std::vector& parentsOut, const bool smoothflag) {//public methods sanity check, private methods process nodesOut.clear(); distsOut.clear(); CaretAssert(node < numNodes && node >= 0); if (node >= numNodes || maxdist < 0.0f || node < 0) return; CaretMutexLocker locked(&inUse);//we need the parents array to stay put, so don't scope this dijkstra(node, maxdist, nodesOut, distsOut, smoothflag); int32_t mysize = (int32_t)nodesOut.size(); parentsOut.resize(mysize); for (int32_t i = 0; i < mysize; ++i) { parentsOut[i] = parent[nodesOut[i]]; } } void GeodesicHelper::dijkstra(const int32_t root, const float maxdist, std::vector& nodes, std::vector& dists, bool smooth) { int32_t i, j, whichnode, whichneigh, numNeigh, numChanged = 0; const int32_t* neighbors; float tempf; output[root] = 0.0f; marked[root] |= 4; parent[root] = -1;//idiom for end of path changed[numChanged++] = root; m_active.clear(); m_heapIdent[root] = m_active.push(root, 0.0f); //we keep values greater than maxdist off the heap, so anything pulled from the heap which is unmarked belongs in the list while (!m_active.isEmpty()) { whichnode = m_active.pop(); nodes.push_back(whichnode); dists.push_back(output[whichnode]); marked[whichnode] |= 1;//anything pulled from heap will already be marked as having a valid value (flag 4) neighbors = nodeNeighbors[whichnode].data(); numNeigh = (int32_t)nodeNeighbors[whichnode].size(); for (j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if frozen tempf = output[whichnode] + distances[whichnode][j];//isn't precomputation wonderful if (tempf <= maxdist) {//keep it off the heap if it is too far if (!(marked[whichneigh] & 4)) { marked[whichneigh] |= 4; changed[numChanged++] = whichneigh; output[whichneigh] = tempf; parent[whichneigh] = whichnode; m_heapIdent[whichneigh] = m_active.push(whichneigh, tempf); } else if (tempf < output[whichneigh]) { output[whichneigh] = tempf; parent[whichneigh] = whichnode; m_active.changekey(m_heapIdent[whichneigh], tempf); } } } } if (smooth)//repeat with numNeighbors2, nodeNeighbors2, distance2 { neighbors = nodeNeighbors2[whichnode].data(); numNeigh = (int32_t)nodeNeighbors2[whichnode].size(); for (j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if frozen tempf = output[whichnode] + distances2[whichnode][j]; if (tempf <= maxdist) {//keep it off the heap if it is too far if (!(marked[whichneigh] & 4)) { marked[whichneigh] |= 4; changed[numChanged++] = whichneigh; output[whichneigh] = tempf; parent[whichneigh] = whichnode; m_heapIdent[whichneigh] = m_active.push(whichneigh, tempf); } else if (tempf < output[whichneigh]) { output[whichneigh] = tempf; parent[whichneigh] = whichnode; m_active.changekey(m_heapIdent[whichneigh], tempf); } } } } } } for (i = 0; i < numChanged; ++i) { marked[changed[i]] = 0;//minimize reinitialization of arrays } } void GeodesicHelper::dijkstra(const int32_t root, bool smooth) {//straightforward dijkstra, no cutoffs, full surface int32_t i, j, whichnode, whichneigh, numNeigh; const int32_t* neighbors; float tempf; output[root] = 0.0f; parent[root] = -1;//idiom for end of path m_active.clear(); m_heapIdent[root] = m_active.push(root, 0.0f); while (!m_active.isEmpty()) { whichnode = m_active.pop(); marked[whichnode] |= 1; neighbors = nodeNeighbors[whichnode].data(); numNeigh = (int32_t)nodeNeighbors[whichnode].size(); for (j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if frozen tempf = output[whichnode] + distances[whichnode][j]; if (!(marked[whichneigh] & 4)) { marked[whichneigh] |= 4; output[whichneigh] = tempf; parent[whichneigh] = whichnode; m_heapIdent[whichneigh] = m_active.push(whichneigh, tempf); } else if (tempf < output[whichneigh]) { output[whichneigh] = tempf; parent[whichneigh] = whichnode; m_active.changekey(m_heapIdent[whichneigh], tempf); } } } if (smooth) { neighbors = nodeNeighbors2[whichnode].data(); numNeigh = (int32_t)nodeNeighbors2[whichnode].size(); for (j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if frozen tempf = output[whichnode] + distances2[whichnode][j]; if (!(marked[whichneigh] & 4)) { marked[whichneigh] |= 4; output[whichneigh] = tempf; parent[whichneigh] = whichnode; m_heapIdent[whichneigh] = m_active.push(whichneigh, tempf); } else if (tempf < output[whichneigh]) { output[whichneigh] = tempf; parent[whichneigh] = whichnode; m_active.changekey(m_heapIdent[whichneigh], tempf); } } } } } for (i = 0; i < numNodes; ++i) { marked[i] = 0; } } void GeodesicHelper::getGeoFromNode(const int32_t node, float* valuesOut, const bool smoothflag) { CaretAssert(node >= 0 && node < numNodes && valuesOut != NULL); if (node < 0 || node >= numNodes || !valuesOut) { return; } CaretMutexLocker locked(&inUse);//don't screw with member variables while in use float* temp = output;//swap out the output pointer to avoid allocation output = valuesOut; dijkstra(node, smoothflag); output = temp;//restore the pointer to the original memory } void GeodesicHelper::getGeoFromNode(const int32_t node, float* valuesOut, int32_t* parentsOut, const bool smoothflag) { CaretAssert(node >= 0 && node < numNodes && valuesOut != NULL && parentsOut != NULL); if (node < 0 || node >= numNodes || !valuesOut || !parentsOut) { return; } CaretMutexLocker locked(&inUse);//don't screw with member variables while in use float* temp = output;//swap out the output pointer to avoid allocation int32_t* tempi = parent; output = valuesOut; parent = parentsOut; dijkstra(node, smoothflag); output = temp;//restore the pointers to the original memory parent = tempi; } void GeodesicHelper::getGeoFromNode(const int32_t node, std::vector& valuesOut, const bool smoothflag) { CaretAssert(node >= 0 && node < numNodes); if (node < 0 || node >= numNodes) { valuesOut.clear();//empty array is error condition return; } CaretMutexLocker locked(&inUse); float* temp = output;//swap the output pointer to avoid copy valuesOut.resize(numNodes); output = valuesOut.data(); dijkstra(node, smoothflag); output = temp;//restore } void GeodesicHelper::getGeoFromNode(const int32_t node, std::vector& valuesOut, std::vector& parentsOut, const bool smoothflag) { CaretAssert(node >= 0 && node < numNodes); if (node < 0 || node >= numNodes) { return; } CaretMutexLocker locked(&inUse); float* temp = output;//swap out the output pointer to avoid copying into the vector afterwards int32_t* tempi = parent; valuesOut.resize(numNodes); parentsOut.resize(numNodes); output = valuesOut.data(); parent = parentsOut.data(); dijkstra(node, smoothflag); output = temp;//restore the pointers to the original memory parent = tempi; } void GeodesicHelper::dijkstra(const int32_t root, const std::vector& interested, bool smooth) { int32_t i, j, whichnode, whichneigh, numNeigh, numChanged = 0, remain = 0; const int32_t* neighbors; float tempf; j = interested.size(); for (i = 0; i < j; ++i) { whichnode = interested[i]; if (!marked[whichnode]) { ++remain; marked[whichnode] = 2;//interested, not expanded, no valid value changed[numChanged++] = whichnode; } } output[root] = 0.0f; if (!marked[root]) { changed[numChanged++] = root; } marked[root] |= 4; parent[root] = -1;//idiom for end of path m_active.clear(); m_heapIdent[root] = m_active.push(root, 0.0f); while (remain && !m_active.isEmpty()) { whichnode = m_active.pop(); if (marked[whichnode] & 2) { --remain; } marked[whichnode] |= 1;//anything pulled from heap will already be marked as having a valid value (flag 4), so already in changed list neighbors = nodeNeighbors[whichnode].data(); numNeigh = (int32_t)nodeNeighbors[whichnode].size(); for (j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if frozen tempf = output[whichnode] + distances[whichnode][j];//isn't precomputation wonderful if (!(marked[whichneigh] & 4)) { if (!marked[whichneigh]) { changed[numChanged++] = whichneigh; } marked[whichneigh] |= 4; output[whichneigh] = tempf; parent[whichneigh] = whichnode; m_heapIdent[whichneigh] = m_active.push(whichneigh, tempf); } else if (tempf < output[whichneigh]) { output[whichneigh] = tempf; parent[whichneigh] = whichnode; m_active.changekey(m_heapIdent[whichneigh], tempf); } } } if (smooth)//repeat with numNeighbors2, nodeNeighbors2, distance2 { neighbors = nodeNeighbors2[whichnode].data(); numNeigh = (int32_t)nodeNeighbors2[whichnode].size(); for (j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if frozen tempf = output[whichnode] + distances2[whichnode][j]; if (!(marked[whichneigh] & 4)) { if (!marked[whichneigh]) { changed[numChanged++] = whichneigh; } marked[whichneigh] |= 4; output[whichneigh] = tempf; parent[whichneigh] = whichnode; m_heapIdent[whichneigh] = m_active.push(whichneigh, tempf); } else if (tempf < output[whichneigh]) { output[whichneigh] = tempf; parent[whichneigh] = whichnode; m_active.changekey(m_heapIdent[whichneigh], tempf); } } } } } for (i = 0; i < numChanged; ++i) { marked[changed[i]] = 0;//minimize reinitialization of arrays } } int32_t GeodesicHelper::dijkstra(const vector& startList, const vector& endList, const float& maxDist, bool smooth) { int32_t i, j, whichnode, whichneigh, numNeigh, numChanged = 0, ret = -1; const int32_t* neighbors; float tempf; m_active.clear(); j = (int32_t)startList.size(); for (i = 0; i < j; ++i) { if (marked[startList[i]] == 0) { output[startList[i]] = 0.0f; changed[numChanged++] = startList[i]; marked[startList[i]] = 4;//has valid value parent[startList[i]] = -1;//idiom for end of path m_heapIdent[startList[i]] = m_active.push(startList[i], 0.0f); } } j = (int32_t)endList.size(); for (i = 0; i < j; ++i) { if (marked[endList[i]] == 0) { changed[numChanged++] = endList[i]; marked[endList[i]] = 8;//stopping point } } while (!m_active.isEmpty()) { whichnode = m_active.pop(); if ((marked[whichnode] & 8) != 0)//we have found the closest node in the endList, we are done { ret = whichnode; break; } marked[whichnode] |= 1;//anything pulled from heap will already be marked as having a valid value (flag 4), so already in changed list neighbors = nodeNeighbors[whichnode].data(); numNeigh = (int32_t)nodeNeighbors[whichnode].size(); for (j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if frozen tempf = output[whichnode] + distances[whichnode][j]; if (tempf <= maxDist) { if (!(marked[whichneigh] & 4)) { parent[whichneigh] = whichnode; if (!marked[whichneigh]) { changed[numChanged++] = whichneigh; } marked[whichneigh] |= 4; output[whichneigh] = tempf; m_heapIdent[whichneigh] = m_active.push(whichneigh, tempf); } else if (tempf < output[whichneigh]) { m_active.changekey(m_heapIdent[whichneigh], tempf); output[whichneigh] = tempf; parent[whichneigh] = whichnode; } } } } if (smooth)//repeat with numNeighbors2, nodeNeighbors2, distance2 { neighbors = nodeNeighbors2[whichnode].data(); numNeigh = (int32_t)nodeNeighbors2[whichnode].size(); for (j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if frozen tempf = output[whichnode] + distances2[whichnode][j]; if (tempf <= maxDist) { if (!(marked[whichneigh] & 4)) { parent[whichneigh] = whichnode; if (!marked[whichneigh]) { changed[numChanged++] = whichneigh; } marked[whichneigh] |= 4; output[whichneigh] = tempf; m_heapIdent[whichneigh] = m_active.push(whichneigh, tempf); } else if (tempf < output[whichneigh]) { m_active.changekey(m_heapIdent[whichneigh], tempf); output[whichneigh] = tempf; parent[whichneigh] = whichnode; } } } } } } for (i = 0; i < numChanged; ++i) { marked[changed[i]] = 0;//minimize reinitialization of arrays } return ret; } int32_t GeodesicHelper::closest(const int32_t& root, const char* roi, const float& maxdist, float& distOut, bool smooth) { int32_t i, j, whichnode, whichneigh, numNeigh, numChanged = 0, ret = -1; const int32_t* neighbors; float tempf; output[root] = 0.0f; changed[numChanged++] = root; marked[root] |= 4; parent[root] = -1;//idiom for end of path m_active.clear(); m_heapIdent[root] = m_active.push(root, 0.0f); while (!m_active.isEmpty()) { whichnode = m_active.pop(); if (roi[whichnode] != 0)//we have found the closest node in the roi to the root, we are done { distOut = output[whichnode]; ret = whichnode; break; } marked[whichnode] |= 1;//anything pulled from heap will already be marked as having a valid value (flag 4), so already in changed list neighbors = nodeNeighbors[whichnode].data(); numNeigh = (int32_t)nodeNeighbors[whichnode].size(); for (j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if frozen tempf = output[whichnode] + distances[whichnode][j];//isn't precomputation wonderful if (tempf <= maxdist) { if (!(marked[whichneigh] & 4)) { parent[whichneigh] = whichnode; if (!marked[whichneigh]) { changed[numChanged++] = whichneigh; } marked[whichneigh] |= 4; output[whichneigh] = tempf; m_heapIdent[whichneigh] = m_active.push(whichneigh, tempf); } else if (tempf < output[whichneigh]) { m_active.changekey(m_heapIdent[whichneigh], tempf); output[whichneigh] = tempf; parent[whichneigh] = whichnode; } } } } if (smooth)//repeat with numNeighbors2, nodeNeighbors2, distance2 { neighbors = nodeNeighbors2[whichnode].data(); numNeigh = (int32_t)nodeNeighbors2[whichnode].size(); for (j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if frozen tempf = output[whichnode] + distances2[whichnode][j];//isn't precomputation wonderful if (tempf <= maxdist) { if (!(marked[whichneigh] & 4)) { parent[whichneigh] = whichnode; if (!marked[whichneigh]) { changed[numChanged++] = whichneigh; } marked[whichneigh] |= 4; output[whichneigh] = tempf; m_heapIdent[whichneigh] = m_active.push(whichneigh, tempf); } else if (tempf < output[whichneigh]) { m_active.changekey(m_heapIdent[whichneigh], tempf); output[whichneigh] = tempf; parent[whichneigh] = whichnode; } } } } } } for (i = 0; i < numChanged; ++i) { marked[changed[i]] = 0;//minimize reinitialization of arrays } return ret; } int32_t GeodesicHelper::closest(const int32_t& root, const char* roi, bool smooth) { int32_t i, j, whichnode, whichneigh, numNeigh, numChanged = 0, ret = -1; const int32_t* neighbors; float tempf; output[root] = 0.0f; changed[numChanged++] = root; marked[root] |= 4; parent[root] = -1;//idiom for end of path m_active.clear(); m_heapIdent[root] = m_active.push(root, 0.0f); while (!m_active.isEmpty()) { whichnode = m_active.pop(); if (roi[whichnode] != 0)//we have found the closest node in the roi to the root, we are done { ret = whichnode; break; } marked[whichnode] |= 1;//anything pulled from heap will already be marked as having a valid value (flag 4), so already in changed list neighbors = nodeNeighbors[whichnode].data(); numNeigh = (int32_t)nodeNeighbors[whichnode].size(); for (j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if frozen tempf = output[whichnode] + distances[whichnode][j];//isn't precomputation wonderful if (!(marked[whichneigh] & 4)) { parent[whichneigh] = whichnode; if (!marked[whichneigh]) { changed[numChanged++] = whichneigh; } marked[whichneigh] |= 4; output[whichneigh] = tempf; m_heapIdent[whichneigh] = m_active.push(whichneigh, tempf); } else if (tempf < output[whichneigh]) { m_active.changekey(m_heapIdent[whichneigh], tempf); output[whichneigh] = tempf; parent[whichneigh] = whichnode; } } } if (smooth)//repeat with numNeighbors2, nodeNeighbors2, distance2 { neighbors = nodeNeighbors2[whichnode].data(); numNeigh = (int32_t)nodeNeighbors2[whichnode].size(); for (j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if frozen tempf = output[whichnode] + distances2[whichnode][j];//isn't precomputation wonderful if (!(marked[whichneigh] & 4)) { parent[whichneigh] = whichnode; if (!marked[whichneigh]) { changed[numChanged++] = whichneigh; } marked[whichneigh] |= 4; output[whichneigh] = tempf; m_heapIdent[whichneigh] = m_active.push(whichneigh, tempf); } else if (tempf < output[whichneigh]) { m_active.changekey(m_heapIdent[whichneigh], tempf); output[whichneigh] = tempf; parent[whichneigh] = whichnode; } } } } } for (i = 0; i < numChanged; ++i) { marked[changed[i]] = 0;//minimize reinitialization of arrays } return ret; } void GeodesicHelper::aStar(const int32_t root, const int32_t endpoint, bool smooth) { int32_t whichnode, whichneigh, numNeigh, numChanged = 0; const int32_t* neighbors; float tempf; output[root] = 0.0f; changed[numChanged++] = root; marked[root] |= 4;//has value in output parent[root] = -1;//idiom for end of path m_active.clear(); float remainEucl = (nodeCoords[root] - nodeCoords[endpoint]).length(); heurVal[root] = remainEucl * m_corrAreaSmallestFactor; m_heapIdent[root] = m_active.push(root, heurVal[root]); while (!m_active.isEmpty()) { whichnode = m_active.pop();//we use a modifiable heap, so we don't need to check for duplicates marked[whichnode] |= 1;//frozen - will already be in changed list, due to being in heap if (whichnode == endpoint) break; neighbors = nodeNeighbors[whichnode].data(); numNeigh = (int32_t)nodeNeighbors[whichnode].size(); for (int32_t j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if frozen tempf = output[whichnode] + distances[whichnode][j]; if (!(marked[whichneigh] & 4)) { heurVal[whichneigh] = m_corrAreaSmallestFactor * (nodeCoords[whichneigh] - nodeCoords[endpoint]).length(); output[whichneigh] = tempf; parent[whichneigh] = whichnode; changed[numChanged++] = whichneigh;//having a valid value will be the first marking, so set changed marked[whichneigh] |= 4; m_heapIdent[whichneigh] = m_active.push(whichneigh, tempf + heurVal[whichneigh]); } else if (tempf < output[whichneigh]) { m_active.changekey(m_heapIdent[whichneigh], tempf + heurVal[whichneigh]); output[whichneigh] = tempf; parent[whichneigh] = whichnode; } } } if (smooth)//repeat with numNeighbors2, nodeNeighbors2, distance2 { neighbors = nodeNeighbors2[whichnode].data(); numNeigh = (int32_t)nodeNeighbors2[whichnode].size(); for (int32_t j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if frozen tempf = output[whichnode] + distances2[whichnode][j]; if (!(marked[whichneigh] & 4)) { heurVal[whichneigh] = m_corrAreaSmallestFactor * (nodeCoords[whichneigh] - nodeCoords[endpoint]).length(); output[whichneigh] = tempf; parent[whichneigh] = whichnode; changed[numChanged++] = whichneigh;//having a valid value will be the first marking, so set changed marked[whichneigh] |= 4; m_heapIdent[whichneigh] = m_active.push(whichneigh, tempf + heurVal[whichneigh]); } else if (tempf < output[whichneigh]) { m_active.changekey(m_heapIdent[whichneigh], tempf + heurVal[whichneigh]); output[whichneigh] = tempf; parent[whichneigh] = whichnode; } } } } } for (int32_t i = 0; i < numChanged; ++i) { marked[changed[i]] = 0;//minimize reinitialization of marked array } } float GeodesicHelper::linePenalty(const Vector3D& pos, const Vector3D& linep1, const Vector3D& linep2, const bool& segment) { if (segment) { return pos.distToLineSegment(linep1, linep2); } else { return pos.distToLine(linep1, linep2); } } float GeodesicHelper::lineHeuristic(const Vector3D& pos, const Vector3D& linep1, const Vector3D& linep2, const float& remainEucl, const bool& segment) { float tempf;//to make it consistent, assume it minimizes the line penalty by taking a straight line towards the line (segment), encountering the endpoint en route, or on the line (segment) if (segment)//the distance heuristic assumes a different path to make it consistent versus path length, and the sum of consistent heuristics is consistent for the sum of the penalties { tempf = m_corrAreaSmallestFactor * pos.distToLineSegment(linep1, linep2);//all euclidean distances must be modified by the smallest area correction factor } else { tempf = m_corrAreaSmallestFactor * pos.distToLine(linep1, linep2); } if (remainEucl < tempf) { return m_corrAreaSmallestFactor * remainEucl * (2.0f * tempf - remainEucl);//hits the endpoint en route } else { return tempf * tempf;//reaches the line (segment), then finds the endpoint with no additional penalty } } void GeodesicHelper::aStarLine(const int32_t& root, const int32_t& endpoint, const Vector3D& linep1, const Vector3D& linep2, const bool& segment) { int32_t whichnode, whichneigh, numNeigh, numChanged = 0; float penaltyScale = 0.5f / m_avgNodeSpacing;//to prevent change in scale from changing the optimal path - 0.5f is ostensibly for averaging between endpoints, but is largely arbitrary const int32_t* neighbors; float tempf; output[root] = 0.0f; changed[numChanged++] = root; marked[root] |= 4;//has value in output parent[root] = -1;//idiom for end of path m_active.clear(); float remainEucl = (nodeCoords[root] - nodeCoords[endpoint]).length(); heurVal[root] = m_corrAreaSmallestFactor * remainEucl + penaltyScale * lineHeuristic(nodeCoords[root], linep1, linep2, remainEucl, segment); m_heapIdent[root] = m_active.push(root, heurVal[root]);//to get consistent heuristic, assume it can take straight line to endpoint for total distance, and straight line to target line (segment) at the same time while (!m_active.isEmpty()) { whichnode = m_active.pop();//we use a modifiable heap, so we don't need to check for duplicates marked[whichnode] |= 1;//frozen - will already be in changed list, due to being in heap if (whichnode == endpoint) break; neighbors = nodeNeighbors[whichnode].data(); numNeigh = (int32_t)nodeNeighbors[whichnode].size(); for (int32_t j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if frozen tempf = output[whichnode] + distances[whichnode][j] + penaltyScale * distances[whichnode][j] * (linePenalty(nodeCoords[whichnode], linep1, linep2, segment) + linePenalty(nodeCoords[whichneigh], linep1, linep2, segment)); if (!(marked[whichneigh] & 4)) { remainEucl = (nodeCoords[whichneigh] - nodeCoords[endpoint]).length(); heurVal[whichneigh] = m_corrAreaSmallestFactor * remainEucl + penaltyScale * lineHeuristic(nodeCoords[whichneigh], linep1, linep2, remainEucl, segment); output[whichneigh] = tempf; parent[whichneigh] = whichnode; changed[numChanged++] = whichneigh;//having a valid value will be the first marking, so set changed marked[whichneigh] |= 4; m_heapIdent[whichneigh] = m_active.push(whichneigh, tempf + heurVal[whichneigh]); } else if (tempf < output[whichneigh]) { m_active.changekey(m_heapIdent[whichneigh], tempf + heurVal[whichneigh]); output[whichneigh] = tempf; parent[whichneigh] = whichnode; } } } } for (int32_t i = 0; i < numChanged; ++i) { marked[changed[i]] = 0;//minimize reinitialization of marked array } } void GeodesicHelper::aStarData(const int32_t& root, const int32_t& endpoint, const float* data, const float& followStrength, const float* roiData, const bool& smooth) {//NOTE: for consistent behavior, data must not contain negatives (or anything non-numeric) int32_t whichnode, whichneigh, numNeigh, numChanged = 0; const int32_t* neighbors; float tempf; output[root] = 0.0f; changed[numChanged++] = root; marked[root] |= 4;//has value in output parent[root] = -1;//idiom for end of path m_active.clear(); heurVal[root] = m_corrAreaSmallestFactor * (nodeCoords[root] - nodeCoords[endpoint]).length();//data could be zero all the way along the optimal path, so euclidean distance is the only consistent heuristic m_heapIdent[root] = m_active.push(root, heurVal[root]); while (!m_active.isEmpty()) { whichnode = m_active.pop();//we use a modifiable heap, so we don't need to check for duplicates marked[whichnode] |= 1;//frozen - will already be in changed list, due to being in heap if (whichnode == endpoint) break; neighbors = nodeNeighbors[whichnode].data(); numNeigh = (int32_t)nodeNeighbors[whichnode].size(); for (int32_t j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if ((roiData == NULL || roiData[whichneigh] > 0.0f) && !(marked[whichneigh] & 1)) {//skip floating point math if frozen or outside roi tempf = output[whichnode] + distances[whichnode][j] * (1.0f + followStrength * (data[whichnode] + data[whichneigh]));//integrate 1 + strength * value to get distance plus path-integrated data if (!(marked[whichneigh] & 4)) { heurVal[whichneigh] = m_corrAreaSmallestFactor * (nodeCoords[whichneigh] - nodeCoords[endpoint]).length(); output[whichneigh] = tempf; parent[whichneigh] = whichnode; changed[numChanged++] = whichneigh;//having a valid value will be the first marking, so set changed marked[whichneigh] |= 4; m_heapIdent[whichneigh] = m_active.push(whichneigh, tempf + heurVal[whichneigh]); } else if (tempf < output[whichneigh]) { m_active.changekey(m_heapIdent[whichneigh], tempf + heurVal[whichneigh]); output[whichneigh] = tempf; parent[whichneigh] = whichnode; } } } if (smooth)//repeat with numNeighbors2, nodeNeighbors2, distance2 { neighbors = nodeNeighbors2[whichnode].data(); numNeigh = (int32_t)nodeNeighbors2[whichnode].size(); const GeodesicHelperBase::CrawlInfo* pathInfo = neighbors2PathInfo[whichnode].data(); for (int32_t j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if ((roiData == NULL || roiData[whichneigh] > 0.0f) && !(marked[whichneigh] & 1)) {//skip floating point math if frozen or outside roi tempf = output[whichnode] + distances2[whichnode][j] + followStrength * (data[whichnode] * pathInfo[j].pieceDists[0] + data[whichneigh] * pathInfo[j].pieceDists[1] + distances2[whichnode][j] * (data[pathInfo[j].edgeNodes[0]] * pathInfo[j].edgeWeight + data[pathInfo[j].edgeNodes[1]] * (1.0f - pathInfo[j].edgeWeight))); if (!(marked[whichneigh] & 4)) { heurVal[whichneigh] = m_corrAreaSmallestFactor * (nodeCoords[whichneigh] - nodeCoords[endpoint]).length(); output[whichneigh] = tempf; parent[whichneigh] = whichnode; changed[numChanged++] = whichneigh;//having a valid value will be the first marking, so set changed marked[whichneigh] |= 4; m_heapIdent[whichneigh] = m_active.push(whichneigh, tempf + heurVal[whichneigh]); } else if (tempf < output[whichneigh]) { m_active.changekey(m_heapIdent[whichneigh], tempf + heurVal[whichneigh]); output[whichneigh] = tempf; parent[whichneigh] = whichnode; } } } } } for (int32_t i = 0; i < numChanged; ++i) { marked[changed[i]] = 0;//minimize reinitialization of marked array } } void GeodesicHelper::getGeoToTheseNodes(const int32_t root, const std::vector& ofInterest, std::vector& distsOut, bool smoothflag) { CaretAssert(root >= 0 && root < numNodes); if (root < 0 || root >= numNodes) { distsOut.clear();//empty array is error condition return; } int32_t i, mysize = ofInterest.size(), node; for (i = 0; i < mysize; ++i) {//needs to do a linear scan of this array later anyway, so lets sanity check it node = ofInterest[i]; if (node < 0 || node >= numNodes) { distsOut.clear();//empty array is error condition return; } } CaretMutexLocker locked(&inUse);//let sanity checks fail without locking dijkstra(root, ofInterest, smoothflag); distsOut.resize(mysize); for (i = 0; i < mysize; ++i) { distsOut[i] = output[ofInterest[i]]; } } void GeodesicHelper::getPathToNode(const int32_t root, const int32_t endpoint, vector& pathNodesOut, vector& pathDistsOut, bool smoothflag) { CaretAssert(root >= 0 && root < numNodes && endpoint >= 0 && endpoint < numNodes); pathNodesOut.clear(); pathDistsOut.clear(); if (root < 0 || root >= numNodes || endpoint < 0 || endpoint >= numNodes) { return; } CaretMutexLocker locked(&inUse);//let sanity checks fail without locking parent[endpoint] = -2;//sentinel value that DOESN'T mean end of path aStar(root, endpoint, smoothflag); if (parent[endpoint] == -2)//check for invalid value { return; } vector tempReverse; int32_t next = endpoint; while (next != root) { tempReverse.push_back(next); next = parent[next]; } tempReverse.push_back(next); int32_t tempSize = (int32_t)tempReverse.size(); for (int32_t i = tempSize - 1; i >= 0; --i) { int32_t tempNode = tempReverse[i]; pathNodesOut.push_back(tempNode); pathDistsOut.push_back(output[tempNode]); } } void GeodesicHelper::getPathBetweenNodeLists(const vector& startList, const vector& endList, const float& maxDist, vector& pathNodesOut, vector& pathDistsOut, bool smoothflag) { pathNodesOut.clear(); pathDistsOut.clear(); for (size_t i = 0; i < startList.size(); ++i) { if (startList[i] < 0 || startList[i] >= numNodes) return; } for (size_t i = 0; i < endList.size(); ++i) { if (endList[i] < 0 || endList[i] >= numNodes) return; } CaretMutexLocker locked(&inUse);//let sanity checks fail without locking int32_t pathEnd = dijkstra(startList, endList, maxDist, smoothflag);//not sure if A* with a PointLocator would be any faster, so don't add a dependency if (pathEnd == -1) return;//no path found vector tempReverse; int32_t next = pathEnd; while (next != -1)//-1 is "parent" of start node { tempReverse.push_back(next); next = parent[next]; } tempReverse.push_back(next); int32_t tempSize = (int32_t)tempReverse.size(); for (int32_t i = tempSize - 1; i >= 0; --i) { int32_t tempNode = tempReverse[i]; pathNodesOut.push_back(tempNode); pathDistsOut.push_back(output[tempNode]); } } void GeodesicHelper::getPathAlongLine(const int32_t root, const int32_t endpoint, const Vector3D& linep1, const Vector3D& linep2, vector& pathNodesOut, vector& pathDistsOut) { CaretAssert(root >= 0 && root < numNodes && endpoint >= 0 && endpoint < numNodes); pathNodesOut.clear(); pathDistsOut.clear(); if (root < 0 || root >= numNodes || endpoint < 0 || endpoint >= numNodes) { return; } CaretMutexLocker locked(&inUse);//let sanity checks fail without locking parent[endpoint] = -2;//sentinel value that DOESN'T mean end of path aStarLine(root, endpoint, linep1, linep2, false); if (parent[endpoint] == -2)//check for invalid value { return; } vector tempReverse; int32_t next = endpoint; while (next != root) { tempReverse.push_back(next); next = parent[next]; } tempReverse.push_back(next); int32_t tempSize = (int32_t)tempReverse.size(); for (int32_t i = tempSize - 1; i >= 0; --i) { int32_t tempNode = tempReverse[i]; pathNodesOut.push_back(tempNode); pathDistsOut.push_back(output[tempNode]); } } void GeodesicHelper::getPathAlongLineSegment(const int32_t root, const int32_t endpoint, const Vector3D& linep1, const Vector3D& linep2, vector& pathNodesOut, vector& pathDistsOut) { CaretAssert(root >= 0 && root < numNodes && endpoint >= 0 && endpoint < numNodes); pathNodesOut.clear(); pathDistsOut.clear(); if (root < 0 || root >= numNodes || endpoint < 0 || endpoint >= numNodes) { return; } vector ofInterest(1, endpoint); CaretMutexLocker locked(&inUse);//let sanity checks fail without locking parent[endpoint] = -2;//sentinel value that DOESN'T mean end of path aStarLine(root, endpoint, linep1, linep2, true); if (parent[endpoint] == -2)//check for invalid value { return; } vector tempReverse; int32_t next = endpoint; while (next != root) { tempReverse.push_back(next); next = parent[next]; } tempReverse.push_back(next); int32_t tempSize = (int32_t)tempReverse.size(); for (int32_t i = tempSize - 1; i >= 0; --i) { int32_t tempNode = tempReverse[i]; pathNodesOut.push_back(tempNode); pathDistsOut.push_back(output[tempNode]); } } void GeodesicHelper::getPathFollowingData(const int32_t root, const int32_t endpoint, const float* data, vector& pathNodesOut, vector& pathDistsOut, const float& followStrength, const float* roiData, const bool& followMaximum, const bool& smoothFlag) { CaretAssert(root >= 0 && root < numNodes && endpoint >= 0 && endpoint < numNodes); pathNodesOut.clear(); pathDistsOut.clear(); if (root < 0 || root >= numNodes || endpoint < 0 || endpoint >= numNodes) { return; } if (roiData != NULL && !(roiData[root] > 0.0f && roiData[endpoint] > 0.0f)) { return; } vector rescaledData(numNodes); float minimum = 0.0f, maximum = 0.0f; bool first = true; for (int i = 0; i < numNodes; ++i)//first normalize contrast in the roi, so we are not sensitive to the absolute values of the data { if (roiData == NULL || roiData[i] > 0.0f) { if (first) { first = false; minimum = data[i]; maximum = data[i]; } else { if (data[i] < minimum) minimum = data[i]; if (data[i] > maximum) maximum = data[i]; } } } if (minimum == maximum)//no contrast, will do simple shortest path { maximum = minimum + 1.0f;//so map it all to minimum value to prevent divide by 0 }//doesn't matter what value it is mapped to if there is no contrast, rescaled data is integrated along path length, and path length is always a factor float range = maximum - minimum; for (int i = 0; i < numNodes; ++i) { if (roiData == NULL || roiData[i] > 0.0f) { if (followMaximum)//also deal with follow minimum vs maximum { rescaledData[i] = (maximum - data[i]) / range; } else { rescaledData[i] = (data[i] - minimum) / range; } } } CaretMutexLocker locked(&inUse);//let sanity checks fail without locking parent[endpoint] = -2;//sentinel value that DOESN'T mean end of path aStarData(root, endpoint, rescaledData.data(), followStrength, roiData, smoothFlag); if (parent[endpoint] == -2)//check for invalid value { return; } vector tempReverse; int32_t next = endpoint; while (next != root) { tempReverse.push_back(next); next = parent[next]; } tempReverse.push_back(next); int32_t tempSize = (int32_t)tempReverse.size(); for (int32_t i = tempSize - 1; i >= 0; --i) { int32_t tempNode = tempReverse[i]; pathNodesOut.push_back(tempNode); pathDistsOut.push_back(output[tempNode]); } } int32_t GeodesicHelper::getClosestNodeInRoi(const int32_t& root, const char* roi, const float& maxdist, float& distOut, bool smoothflag) { CaretAssert(root >= 0 && root < numNodes && maxdist >= 0.0f); if (root < 0 || root >= numNodes || maxdist < 0.0f) { return -1; } CaretMutexLocker locked(&inUse);//let sanity checks fail without locking return closest(root, roi, maxdist, distOut, smoothflag); } int32_t GeodesicHelper::getClosestNodeInRoi(const int32_t& root, const char* roi, vector& pathNodesOut, vector& pathDistsOut, bool smoothflag) { CaretAssert(root >= 0 && root < numNodes); pathNodesOut.clear(); pathDistsOut.clear(); if (root < 0 || root >= numNodes) { return -1; } CaretMutexLocker locked(&inUse);//let sanity checks fail without locking int32_t ret = closest(root, roi, smoothflag); if (ret == -1) return ret; vector tempReverse; int32_t next = ret; while (next != root) { tempReverse.push_back(next); next = parent[next]; } tempReverse.push_back(next); int32_t tempSize = (int32_t)tempReverse.size(); for (int32_t i = tempSize - 1; i >= 0; --i) { int32_t tempNode = tempReverse[i]; pathNodesOut.push_back(tempNode); pathDistsOut.push_back(output[tempNode]); } return ret; } connectome-workbench-1.4.2/src/Files/GeodesicHelper.h000066400000000000000000000225441360521144700225260ustar00rootroot00000000000000 #ifndef __GEODESIC_HELPER_H__ #define __GEODESIC_HELPER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretMutex.h" #include "CaretPointer.h" #include "CaretHeap.h" #include "Vector3D.h" namespace caret { class SurfaceFile; //NOTE: this class does NOT stay associated with the coord passed into it, it takes a snapshot of the surface in the constructor //This is because it is designed to be fast on repeated calls on a single surface class GeodesicHelperBase {//This does the neighbor computation, create a GeodesicHelper to contain the temporary arrays and actually do stuff public: struct CrawlInfo { int32_t edgeNodes[2]; float edgeWeight, pieceDists[2]; }; private: GeodesicHelperBase();//can't construct without arguments GeodesicHelperBase& operator=(const GeodesicHelperBase& right);//can't assign GeodesicHelperBase(const GeodesicHelperBase& right);//can't use copy constructor std::vector > distances, distances2; std::vector > nodeNeighbors, nodeNeighbors2; std::vector > neighbors2PathInfo; std::vector nodeCoords;//for line-following and A* int32_t numNodes; float m_avgNodeSpacing;//to use for balancing line following penalty float m_corrAreaSmallestFactor;//so that heuristics can be consistent despite corrected areas public: explicit GeodesicHelperBase(const SurfaceFile* surfaceIn, const float* correctedAreas = NULL);//NOTE: this is only an APPROXIMATE correction, use the real surface whenever possible friend class GeodesicHelper;//let it grab the private variables it needs }; class GeodesicHelper { CaretPointer m_myBase;//mostly just for automatic memory management CaretMutex inUse;//could add a function and a locker pointer to be able to lock to thread once, then call repeatedly without locking, if mutex overhead is actually a factor CaretMinHeap m_active;//save and reuse the allocated space const std::vector* distances, *distances2; const std::vector* nodeNeighbors, *nodeNeighbors2; const std::vector* neighbors2PathInfo; const Vector3D* nodeCoords; float* output; int32_t* parent; std::vector outputStore; std::vector heurVal; std::vector marked, changed, parentStore; std::vector m_heapIdent; int32_t numNodes; float m_avgNodeSpacing; float m_corrAreaSmallestFactor; GeodesicHelper();//Don't allow construction without arguments GeodesicHelper& operator=(const GeodesicHelper& right);//can't assign GeodesicHelper(const GeodesicHelper&);//can't use copy constructor void dijkstra(const int32_t root, const float maxdist, std::vector& nodes, std::vector& dists, bool smooth);//geodesic distance restricted void dijkstra(const int32_t root, bool smooth);//full surface void dijkstra(const int32_t root, const std::vector& interested, bool smooth);//partial surface int32_t dijkstra(const std::vector& startList, const std::vector& endList, const float& maxDist, bool smooth);//one path that connects lists int32_t closest(const int32_t& root, const char* roi, const float& maxdist, float& distOut, bool smooth);//just closest node int32_t closest(const int32_t& root, const char* roi, bool smooth);//just closest node void aStar(const int32_t root, const int32_t endpoint, bool smooth);//faster method for path float linePenalty(const Vector3D& pos, const Vector3D& linep1, const Vector3D& linep2, const bool& segment); float lineHeuristic(const Vector3D& pos, const Vector3D& linep1, const Vector3D& linep2, const float& remainEucl, const bool& segment); void aStarLine(const int32_t& root, const int32_t& endpoint, const Vector3D& linep1, const Vector3D& linep2, const bool& segment);//to single endpoint, following line void aStarData(const int32_t& root, const int32_t& endpoint, const float* data, const float& followStrength, const float* roiData, const bool& smooth);//to single endpoint, following data public: explicit GeodesicHelper(const CaretPointer& baseIn); /// Get distances from root node, up to a geodesic distance cutoff (stops computing when no more nodes are within that distance) void getNodesToGeoDist(const int32_t node, const float maxdist, std::vector& neighborsOut, std::vector& distsOut, const bool smoothflag = true); /// Get distances from root node, up to a geodesic distance cutoff, and also return their parents (root node has -1 as parent) void getNodesToGeoDist(const int32_t node, const float maxdist, std::vector& neighborsOut, std::vector& distsOut, std::vector& parentsOut, const bool smoothflag = true); /// Get distances from root node to entire surface - allocate the array first void getGeoFromNode(const int32_t node, float* valuesOut, const bool smoothflag = true);//MUST be already allocated to number of nodes /// Get distances from root node to entire surface, vector method void getGeoFromNode(const int32_t node, std::vector& valuesOut, const bool smoothflag = true); /// Get distances from root node to entire surface and parents - allocate both arrays first (root node has -1 as parent) void getGeoFromNode(const int32_t node, float* valuesOut, int32_t* parentsOut, const bool smoothflag = true); /// Get distances from root node to entire surface, and their parents, vector method (root node has -1 as parent) void getGeoFromNode(const int32_t node, std::vector& valuesOut, std::vector& parentsOut, const bool smoothflag = true); /// Get distances to a restricted set of nodes - output vector is in the SAME ORDER and same size as the input vector ofInterest void getGeoToTheseNodes(const int32_t root, const std::vector& ofInterest, std::vector& distsOut, bool smoothflag = true); ///get the distances and nodes along the path to a node - NOTE: default is not smooth distances, so that all nodes in the path are connected in the surface void getPathToNode(const int32_t root, const int32_t endpoint, std::vector& pathNodesOut, std::vector& pathDistsOut, bool smoothflag = false); ///shortest path between two sets of nodes (for instance, clusters), with distance limit void getPathBetweenNodeLists(const std::vector& startList, const std::vector& endList, const float& maxDist, std::vector& pathNodesOut, std::vector& pathDistsOut, bool smoothflag); ///get the distances and nodes along the path to a node - NOTE: does not do smooth distances, so that all nodes in the path are connected in the surface void getPathAlongLine(const int32_t root, const int32_t endpoint, const Vector3D& linep1, const Vector3D& linep2, std::vector& pathNodesOut, std::vector& pathDistsOut); ///get the distances and nodes along the path to a node - NOTE: does not do smooth distances, so that all nodes in the path are connected in the surface void getPathAlongLineSegment(const int32_t root, const int32_t endpoint, const Vector3D& linep1, const Vector3D& linep2, std::vector& pathNodesOut, std::vector& pathDistsOut); ///path drawing by peaks or troughs of supplied data, controlled by followMaximum void getPathFollowingData(const int32_t root, const int32_t endpoint, const float* data, std::vector& pathNodesOut, std::vector& pathDistsOut, const float& followStrength = 5.0f, const float* roiData = NULL, const bool& followMaximum = true, const bool& smoothFlag = false); ///get just the closest node in the region and max distance given, returns -1 if no such node found - roi value of 0 means not in region, anything else is in region int32_t getClosestNodeInRoi(const int32_t& root, const char* roi, const float& maxdist, float& distOut, bool smoothflag = true); int32_t getClosestNodeInRoi(const int32_t& root, const char* roi, std::vector& pathNodesOut, std::vector& pathDistsOut, bool smoothflag); }; } //namespace caret #endif connectome-workbench-1.4.2/src/Files/GiftiTypeFile.cxx000066400000000000000000001334601360521144700227230ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretLogger.h" #include "DataFileContentInformation.h" #include "DataFileException.h" #include "FastStatistics.h" #include "GiftiDataArray.h" #include "GiftiFile.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "GiftiMetaData.h" #include "GiftiTypeFile.h" #include "GiftiMetaDataXmlElements.h" #include "Histogram.h" #include "LabelFile.h" #include "MapFileDataSelector.h" #include "MetricFile.h" #include "PaletteColorMapping.h" #include "PaletteColorMappingSaxReader.h" #include "SurfaceFile.h" using namespace caret; /** * Constructor. */ GiftiTypeFile::GiftiTypeFile(const DataFileTypeEnum::Enum dataFileType) : CaretMappableDataFile(dataFileType) { this->initializeMembersGiftiTypeFile(); } /** * Destructor. */ GiftiTypeFile::~GiftiTypeFile() { if (this->giftiFile != NULL) { delete this->giftiFile; this->giftiFile = NULL; } } /** * Copy Constructor. * * @param gtf * File that is copied. */ GiftiTypeFile::GiftiTypeFile(const GiftiTypeFile& gtf) : CaretMappableDataFile(gtf) { this->giftiFile = new GiftiFile(*gtf.giftiFile);//NOTE: while CONSTRUCTING, this has virtual type GiftiTypeFile*, NOT MetricFile*, or whatever }//so, validateDataArraysAfterReading will ABORT due to pure virtual /** * Assignment operator. * * @param gtf * File whose contents are copied to this file. */ GiftiTypeFile& GiftiTypeFile::operator=(const GiftiTypeFile& gtf) { if (this != >f) { CaretMappableDataFile::operator=(gtf); this->copyHelperGiftiTypeFile(gtf); } return *this; } /** * Clear the contents of this file. */ void GiftiTypeFile::clear() { DataFile::clear(); this->giftiFile->clear(); } /** * Clear modified status. */ void GiftiTypeFile::clearModified() { CaretDataFile::clearModified(); this->giftiFile->clearModified(); } /** * @return True if any of the maps in this file contain a * color mapping that possesses a modified status. */ bool GiftiTypeFile::isModifiedExcludingPaletteColorMapping() const { if (CaretMappableDataFile::isModifiedExcludingPaletteColorMapping()) { return true; } if (this->giftiFile->isModified()) { return true; } return false; } /** * Is this file empty? * * @return true if file is empty, else false. */ bool GiftiTypeFile::isEmpty() const { return this->giftiFile->isEmpty(); } /** * Read the file. * * @param filename * Name of file to read. * * @throws DataFileException * If there is an error reading the file. */ void GiftiTypeFile::readFile(const AString& filename) { clear(); checkFileReadability(filename); this->setFileName(filename); this->giftiFile->readFile(filename); this->validateDataArraysAfterReading(); updateAfterFileDataChanges(); this->clearModified(); } /** * Write the file. * * @param filename * Name of file to read. * * @throws DataFileException * If there is an error writing the file. */ void GiftiTypeFile::writeFile(const AString& filename) { checkFileWritability(filename); this->giftiFile->writeFile(filename); this->clearModified(); } /** * Helps with file copying. * * @param gtf * File that is copied. */ void GiftiTypeFile::copyHelperGiftiTypeFile(const GiftiTypeFile& gtf) { if (this->giftiFile != NULL) { delete this->giftiFile; } this->giftiFile = new GiftiFile(*gtf.giftiFile); this->validateDataArraysAfterReading(); } /** * Initialize members of this class. */ void GiftiTypeFile::initializeMembersGiftiTypeFile() { this->giftiFile = new GiftiFile(); } /** * Get information about this file's contents. * @return * Information about the file's contents. */ AString GiftiTypeFile::toString() const { return this->giftiFile->toString(); } StructureEnum::Enum GiftiTypeFile::getStructure() const { AString structurePrimaryName; /* * Surface contains anatomical structure in pointset array. */ const SurfaceFile* surfaceFile = dynamic_cast(this); if (surfaceFile != NULL) { const GiftiDataArray* gda = this->giftiFile->getDataArrayWithIntent(NiftiIntentEnum::NIFTI_INTENT_POINTSET); const GiftiMetaData* metadata = gda->getMetaData(); structurePrimaryName = metadata->get(GiftiMetaDataXmlElements::METADATA_NAME_ANATOMICAL_STRUCTURE_PRIMARY); } else { const GiftiMetaData* metadata = this->giftiFile->getMetaData(); structurePrimaryName = metadata->get(GiftiMetaDataXmlElements::METADATA_NAME_ANATOMICAL_STRUCTURE_PRIMARY); } bool isValid = false; StructureEnum::Enum structure = StructureEnum::fromGuiName(structurePrimaryName, &isValid); return structure; } /** * Set the structure. * @param structure * New value for file's structure. */ void GiftiTypeFile::setStructure(const StructureEnum::Enum structure) { const AString structureName = StructureEnum::toGuiName(structure); /* * Surface contains anatomical structure in pointset array. */ SurfaceFile* surfaceFile = dynamic_cast(this); if (surfaceFile != NULL) { GiftiDataArray* gda = this->giftiFile->getDataArrayWithIntent(NiftiIntentEnum::NIFTI_INTENT_POINTSET); GiftiMetaData* metadata = gda->getMetaData(); metadata->set(GiftiMetaDataXmlElements::METADATA_NAME_ANATOMICAL_STRUCTURE_PRIMARY, structureName); } else { GiftiMetaData* metadata = this->giftiFile->getMetaData(); metadata->set(GiftiMetaDataXmlElements::METADATA_NAME_ANATOMICAL_STRUCTURE_PRIMARY, structureName); } } /** * Add map(s) to this GIFTI file. * @param numberOfNodes * Number of nodes. If file is not empty, this value must * match the number of nodes that are in the file. * @param numberOfMaps * Number of maps to add. */ void GiftiTypeFile::addMaps(const int32_t /*numberOfNodes*/, const int32_t /*numberOfMaps*/) { throw DataFileException(getFileName(), "This file does not support adding additional maps"); } /** * @return Get access to the file's metadata. */ GiftiMetaData* GiftiTypeFile::getFileMetaData() { return this->giftiFile->getMetaData(); } /** * @return Get access to unmodifiable file's metadata. */ const GiftiMetaData* GiftiTypeFile::getFileMetaData() const { return this->giftiFile->getMetaData(); } /** * Verify that all of the data arrays have the same number of rows. * @throws DataFileException * If there are data arrays that have a different number of rows. */ void GiftiTypeFile::verifyDataArraysHaveSameNumberOfRows(const int32_t minimumSecondDimension, const int32_t maximumSecondDimension) const { const int32_t numberOfArrays = this->giftiFile->getNumberOfDataArrays(); if (numberOfArrays > 1) { /* * Verify all arrays contain the same number of rows. */ int64_t numberOfRows = this->giftiFile->getDataArray(0)->getNumberOfRows(); for (int32_t i = 1; i < numberOfArrays; i++) { const int32_t arrayNumberOfRows = this->giftiFile->getDataArray(i)->getNumberOfRows(); if (numberOfRows != arrayNumberOfRows) { AString message = "All data arrays (columns) in the file must have the same number of rows."; message += " The first array (column) contains " + AString::number(numberOfRows) + " rows."; message += " Array " + AString::number(i + 1) + " contains " + AString::number(arrayNumberOfRows) + " rows."; DataFileException e(getFileName(), message); CaretLogThrowing(e); throw e; } } /* * Verify that second dimensions is within valid range. */ for (int32_t i = 0; i < numberOfArrays; i++) { const GiftiDataArray* gda = this->giftiFile->getDataArray(i); const int32_t numberOfDimensions = gda->getNumberOfDimensions(); if (numberOfDimensions > 2) { DataFileException e(getFileName(), "Data array " + AString::number(i + 1) + " contains " + AString::number(numberOfDimensions) + " dimensions. Two is the maximum allowed."); CaretLogThrowing(e); throw e; } int32_t secondDimension = 0; if (numberOfDimensions > 1) { secondDimension = gda->getDimension(1); if (secondDimension == 1) { secondDimension = 0; } } if ((secondDimension < minimumSecondDimension) || (secondDimension > maximumSecondDimension)) { DataFileException e(getFileName(), "Data array " + AString::number(i + 1) + " second dimension is " + AString::number(numberOfDimensions) + ". Minimum allowed is " + AString::number(minimumSecondDimension) + ". Maximum allowed is " + AString::number(maximumSecondDimension)); CaretLogThrowing(e); throw e; } } } } /** * Get the name of a file column. * @param columnIndex * Index of column. * @return * Name of column. */ AString GiftiTypeFile::getColumnName(const int columnIndex) const { return this->giftiFile->getDataArrayName(columnIndex); } /** * Find the first column with the given column name. * @param columnName * Name of column. * @return * Index of column with name or negative if no match. */ int32_t GiftiTypeFile::getColumnIndexFromColumnName(const AString& columnName) const { return this->giftiFile->getDataArrayWithNameIndex(columnName); } /** * Set the name of a column. * @param columnIndex * Index of column. * @param columnName * New name for column. */ void GiftiTypeFile::setColumnName(const int32_t columnIndex, const AString& columnName) { this->giftiFile->setDataArrayName(columnIndex, columnName); } /** * @return The palette color mapping for a data column. */ PaletteColorMapping* GiftiTypeFile::getPaletteColorMapping(const int32_t columnIndex) { GiftiDataArray* gda = this->giftiFile->getDataArray(columnIndex); return gda->getPaletteColorMapping(); } /** * @return The palette color mapping for a data column. */ const PaletteColorMapping* GiftiTypeFile::getPaletteColorMapping(const int32_t columnIndex) const { const GiftiDataArray* gda = this->giftiFile->getDataArray(columnIndex); return gda->getPaletteColorMapping(); } /** * @return Is the data mappable to a surface? */ bool GiftiTypeFile::isSurfaceMappable() const { return true; } /** * @return Is the data mappable to a volume? */ bool GiftiTypeFile::isVolumeMappable() const { return false; } /** * @return The number of maps in the file. * Note: Caret5 used the term 'columns'. */ int32_t GiftiTypeFile::getNumberOfMaps() const { return this->giftiFile->getNumberOfDataArrays(); } /** * Get the name of the map at the given index. * * @param mapIndex * Index of the map. * @return * Name of the map. */ AString GiftiTypeFile::getMapName(const int32_t mapIndex) const { return this->giftiFile->getDataArrayName(mapIndex); } /** * Set the name of the map at the given index. * * @param mapIndex * Index of the map. * @param mapName * New name for the map. */ void GiftiTypeFile::setMapName(const int32_t mapIndex, const AString& mapName) { this->giftiFile->setDataArrayName(mapIndex, mapName); } /** * Get the metadata for the map at the given index * * @param mapIndex * Index of the map. * @return * Metadata for the map (const value). */ const GiftiMetaData* GiftiTypeFile::getMapMetaData(const int32_t mapIndex) const { return this->giftiFile->getDataArray(mapIndex)->getMetaData(); } /** * Get the metadata for the map at the given index * * @param mapIndex * Index of the map. * @return * Metadata for the map. */ GiftiMetaData* GiftiTypeFile::getMapMetaData(const int32_t mapIndex) { return this->giftiFile->getDataArray(mapIndex)->getMetaData(); } const FastStatistics* GiftiTypeFile::getMapFastStatistics(const int32_t mapIndex) { const GiftiDataArray* gda = this->giftiFile->getDataArray(mapIndex); return gda->getFastStatistics(); } const Histogram* GiftiTypeFile::getMapHistogram(const int32_t mapIndex) { int32_t numberOfBuckets = 0; switch (getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: numberOfBuckets = getFileHistogramNumberOfBuckets(); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: numberOfBuckets = getMapPaletteColorMapping(mapIndex)->getHistogramNumberOfBuckets(); break; } const GiftiDataArray* gda = this->giftiFile->getDataArray(mapIndex); return gda->getHistogram(numberOfBuckets); } const Histogram* GiftiTypeFile::getMapHistogram(const int32_t mapIndex, const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) { int32_t numberOfBuckets = 0; switch (getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: numberOfBuckets = getFileHistogramNumberOfBuckets(); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: numberOfBuckets = getMapPaletteColorMapping(mapIndex)->getHistogramNumberOfBuckets(); break; } const GiftiDataArray* gda = this->giftiFile->getDataArray(mapIndex); return gda->getHistogram(numberOfBuckets, mostPositiveValueInclusive, leastPositiveValueInclusive, leastNegativeValueInclusive, mostNegativeValueInclusive, includeZeroValues); } /** * @return The estimated size of data after it is uncompressed * and loaded into RAM. A negative value indicates that the * file size cannot be computed. */ int64_t GiftiTypeFile::getDataSizeUncompressedInBytes() const { const int32_t numDataArrays = getNumberOfMaps(); int64_t dataSizeInBytes = 0; for (int32_t iMap = 0; iMap < numDataArrays; iMap++) { const GiftiDataArray* gda = this->giftiFile->getDataArray(iMap); dataSizeInBytes += gda->getDataSizeInBytes(); } return dataSizeInBytes; } /** * Get all data for a file that contains floats. If the file is very * large this method may take a large amount of time! * * @param dataOut * Output with all data for a float file. Empty if no data in file * or data is not float. */ void GiftiTypeFile::getFileDataFloat(std::vector& dataOut) const { int64_t dataSize = 0; /* * Get the size of the data */ const int64_t numberOfDataArrays = this->giftiFile->getNumberOfDataArrays(); for (int64_t i = 0; i < numberOfDataArrays; i++) { const GiftiDataArray* gda = this->giftiFile->getDataArray(i); if (gda->getDataType() == NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32) { dataSize += gda->getTotalNumberOfElements(); } else { dataOut.clear(); return; } } if (dataSize <= 0) { dataOut.clear(); return; } dataOut.resize(dataSize); int64_t dataOffset = 0; /* * Copy the data. */ for (int64_t i = 0; i < numberOfDataArrays; i++) { const GiftiDataArray* gda = this->giftiFile->getDataArray(i); const int64_t arraySize = gda->getTotalNumberOfElements(); const float* arrayPointer = gda->getDataPointerFloat(); for (int64_t j = 0; j < arraySize; j++) { CaretAssertVectorIndex(dataOut, dataOffset); dataOut[dataOffset] = arrayPointer[j]; ++dataOffset; } } CaretAssert(dataOffset == static_cast(dataOut.size())); } /** * Get statistics describing the distribution of data * mapped with a color palette for all data within the file. * * @return * Fast statistics for data (will be NULL for data * not mapped using a palette). */ const FastStatistics* GiftiTypeFile::getFileFastStatistics() { if (m_fileFastStatistics == NULL) { std::vector fileData; getFileDataFloat(fileData); if ( ! fileData.empty()) { m_fileFastStatistics.grabNew(new FastStatistics()); m_fileFastStatistics->update(&fileData[0], fileData.size()); } } return m_fileFastStatistics; } /** * Get histogram describing the distribution of data * mapped with a color palette for all data within * the file. * * @return * Histogram for data (will be NULL for data * not mapped using a palette). */ const Histogram* GiftiTypeFile::getFileHistogram() { const int32_t numBuckets = getFileHistogramNumberOfBuckets(); bool updateHistogramFlag = false; if (m_fileHistogram != NULL) { if (numBuckets != m_histogramNumberOfBuckets) { updateHistogramFlag = true; } } else { updateHistogramFlag = true; } if (updateHistogramFlag) { std::vector fileData; getFileDataFloat(fileData); if ( ! fileData.empty()) { if (m_fileHistogram == NULL) { m_fileHistogram.grabNew(new Histogram(numBuckets)); } m_fileHistogram->update(numBuckets, &fileData[0], fileData.size()); m_histogramNumberOfBuckets = numBuckets; } } return m_fileHistogram; } /** * Get histogram describing the distribution of data * mapped with a color palette for all data in the file * within the given range of values. * * @param mostPositiveValueInclusive * Values more positive than this value are excluded. * @param leastPositiveValueInclusive * Values less positive than this value are excluded. * @param leastNegativeValueInclusive * Values less negative than this value are excluded. * @param mostNegativeValueInclusive * Values more negative than this value are excluded. * @param includeZeroValues * If true zero values (very near zero) are included. * @return * Descriptive statistics for data (will be NULL for data * not mapped using a palette). */ const Histogram* GiftiTypeFile::getFileHistogram(const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) { const int32_t numberOfBuckets = getFileHistogramNumberOfBuckets(); bool updateHistogramFlag = false; if (m_fileHistorgramLimitedValues != NULL) { if ((numberOfBuckets != m_fileHistogramLimitedValuesNumberOfBuckets) || (mostPositiveValueInclusive != m_fileHistogramLimitedValuesMostPositiveValueInclusive) || (leastPositiveValueInclusive != m_fileHistogramLimitedValuesLeastPositiveValueInclusive) || (leastNegativeValueInclusive != m_fileHistogramLimitedValuesLeastNegativeValueInclusive) || (mostNegativeValueInclusive != m_fileHistogramLimitedValuesMostNegativeValueInclusive) || (includeZeroValues != m_fileHistogramLimitedValuesIncludeZeroValues)) { updateHistogramFlag = true; } } else { updateHistogramFlag = true; } if (updateHistogramFlag) { std::vector fileData; getFileDataFloat(fileData); if ( ! fileData.empty()) { if (m_fileHistorgramLimitedValues == NULL) { m_fileHistorgramLimitedValues.grabNew(new Histogram()); } m_fileHistorgramLimitedValues->update(numberOfBuckets, &fileData[0], fileData.size(), mostPositiveValueInclusive, leastPositiveValueInclusive, leastNegativeValueInclusive, mostNegativeValueInclusive, includeZeroValues); m_fileHistogramLimitedValuesNumberOfBuckets = numberOfBuckets; m_fileHistogramLimitedValuesMostPositiveValueInclusive = mostPositiveValueInclusive; m_fileHistogramLimitedValuesLeastPositiveValueInclusive = leastPositiveValueInclusive; m_fileHistogramLimitedValuesLeastNegativeValueInclusive = leastNegativeValueInclusive; m_fileHistogramLimitedValuesMostNegativeValueInclusive = mostNegativeValueInclusive; m_fileHistogramLimitedValuesIncludeZeroValues = includeZeroValues; } } return m_fileHistorgramLimitedValues; // bool updateHistogramFlag = false; // if (m_fileHistorgramLimitedValues != NULL) { // if ((mostPositiveValueInclusive != m_fileHistogramLimitedValuesMostPositiveValueInclusive) // || (leastPositiveValueInclusive != m_fileHistogramLimitedValuesLeastPositiveValueInclusive) // || (leastNegativeValueInclusive != m_fileHistogramLimitedValuesLeastNegativeValueInclusive) // || (mostNegativeValueInclusive != m_fileHistogramLimitedValuesMostNegativeValueInclusive) // || (includeZeroValues != m_fileHistogramLimitedValuesIncludeZeroValues)) { // updateHistogramFlag = true; // } // } // else { // updateHistogramFlag = true; // } // // if (updateHistogramFlag) { // std::vector fileData; // getFileDataFloat(fileData); // if ( ! fileData.empty()) { // if (m_fileHistorgramLimitedValues == NULL) { // m_fileHistorgramLimitedValues.grabNew(new Histogram()); // } // m_fileHistorgramLimitedValues->update(getFileHistogramNumberOfBuckets(), // &fileData[0], // fileData.size(), // mostPositiveValueInclusive, // leastPositiveValueInclusive, // leastNegativeValueInclusive, // mostNegativeValueInclusive, // includeZeroValues); // // m_fileHistogramLimitedValuesMostPositiveValueInclusive = mostPositiveValueInclusive; // m_fileHistogramLimitedValuesLeastPositiveValueInclusive = leastPositiveValueInclusive; // m_fileHistogramLimitedValuesLeastNegativeValueInclusive = leastNegativeValueInclusive; // m_fileHistogramLimitedValuesMostNegativeValueInclusive = mostNegativeValueInclusive; // m_fileHistogramLimitedValuesIncludeZeroValues = includeZeroValues; // } // } // // return m_fileHistorgramLimitedValues; } /** * @return Is the data in the file mapped to colors using * a palette. */ bool GiftiTypeFile::isMappedWithPalette() const { bool paletteFlag(false); switch (getDataFileType()) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: break; case DataFileTypeEnum::METRIC: paletteFlag = true; break; case DataFileTypeEnum::METRIC_DYNAMIC: paletteFlag = true; break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: break; } return paletteFlag; } /** * Get the palette normalization modes that are supported by the file. * * @param modesSupportedOut * Palette normalization modes supported by a file. Will be * empty for files that are not mapped with a palette. If there * is more than one suppported mode, the first mode in the * vector is assumed to be the default mode. */ void GiftiTypeFile::getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) const { modesSupportedOut.clear(); switch (getDataFileType()) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: break; case DataFileTypeEnum::METRIC: modesSupportedOut.push_back(PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA); modesSupportedOut.push_back(PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA); break; case DataFileTypeEnum::METRIC_DYNAMIC: modesSupportedOut.push_back(PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA); break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: break; } } /** * Get the palette color mapping for the map at the given index. * * @param mapIndex * Index of the map. * @return * Palette color mapping for the map (will be NULL for data * not mapped using a palette). */ PaletteColorMapping* GiftiTypeFile::getMapPaletteColorMapping(const int32_t mapIndex) { GiftiDataArray* gda = this->giftiFile->getDataArray(mapIndex); return gda->getPaletteColorMapping(); } /** * Get the palette color mapping for the map at the given index. * * @param mapIndex * Index of the map. * @return * Palette color mapping for the map (constant) (will be NULL for data * not mapped using a palette). */ const PaletteColorMapping* GiftiTypeFile::getMapPaletteColorMapping(const int32_t mapIndex) const { const GiftiDataArray* gda = this->giftiFile->getDataArray(mapIndex); return gda->getPaletteColorMapping(); } /** * @return Is the data in the file mapped to colors using * a label table. */ bool GiftiTypeFile::isMappedWithLabelTable() const { if (this->getDataFileType() == DataFileTypeEnum::LABEL) { return true; } return false; } /** * Get the label table for the map at the given index. * * @param mapIndex * Index of the map. * @return * Label table for the map (will be NULL for data * not mapped using a label table). */ GiftiLabelTable* GiftiTypeFile::getMapLabelTable(const int32_t /*mapIndex*/) { /* * Use file's label table since GIFTI uses one * label table for all data arrays. */ return this->giftiFile->getLabelTable(); } /** * Get the label table for the map at the given index. * * @param mapIndex * Index of the map. * @return * Label table for the map (constant) (will be NULL for data * not mapped using a label table). */ const GiftiLabelTable* GiftiTypeFile::getMapLabelTable(const int32_t /*mapIndex*/) const { /* * Use file's label table since GIFTI uses one * label table for all data arrays. */ return this->giftiFile->getLabelTable(); } /** * Get the unique ID (UUID) for the map at the given index. * * @param mapIndex * Index of the map. * @return * String containing UUID for the map. */ AString GiftiTypeFile::getMapUniqueID(const int32_t mapIndex) const { const GiftiMetaData* md = this->giftiFile->getDataArray(mapIndex)->getMetaData(); return md->getUniqueID(); } /** * Find the index of the map that uses the given unique ID (UUID). * * @param uniqueID * Unique ID (UUID) of the desired map. * @return * Index of the map using the given UUID. */ int32_t GiftiTypeFile::getMapIndexFromUniqueID(const AString& uniqueID) const { const int32_t numberOfArrays = this->giftiFile->getNumberOfDataArrays(); for (int32_t i = 0; i < numberOfArrays; i++) { if (this->getMapUniqueID(i) == uniqueID) { return i; } } return -1; } /** * Update coloring for a map. * * @param mapIndex * Index of map. * @param paletteFile * Palette file containing palettes. */ void GiftiTypeFile::updateScalarColoringForMap(const int32_t mapIndex) { invalidateHistogramChartColoring(); if ((mapIndex >= 0) && (mapIndex < getNumberOfMaps())) { this->giftiFile->getDataArray(mapIndex)->invalidateHistograms(); } } /** * Add information about the file to the data file information. * * @param dataFileInformation * Consolidates information about a data file. */ void GiftiTypeFile::addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) { CaretMappableDataFile::addToDataFileContentInformation(dataFileInformation); dataFileInformation.addNameAndValue("Number of Vertices", getNumberOfNodes()); } /** * Get data from the file as requested in the given map file data selector. * * @param mapFileDataSelector * Specifies selection of data. * @param dataOut * Output with data. Will be empty if data does not support the map file data selector. */ void GiftiTypeFile::getDataForSelector(const MapFileDataSelector& mapFileDataSelector, std::vector& dataOut) const { dataOut.clear(); switch (mapFileDataSelector.getDataSelectionType()) { case MapFileDataSelector::DataSelectionType::INVALID: case MapFileDataSelector::DataSelectionType::COLUMN_DATA: case MapFileDataSelector::DataSelectionType::ROW_DATA: break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: { StructureEnum::Enum structure = StructureEnum::INVALID; int32_t numberOfNodes(-1); int32_t nodeIndex(-1); mapFileDataSelector.getSurfaceVertex(structure, numberOfNodes, nodeIndex); if ((getStructure() == structure) && (getNumberOfNodes() == numberOfNodes)) { const int32_t numberOfMaps = getNumberOfMaps(); if (isMappedWithLabelTable()) { const LabelFile* lf = dynamic_cast(this); CaretAssert(lf); for (int32_t mapIndex = 0; mapIndex < numberOfMaps; mapIndex++) { const int32_t key = lf->getLabelKey(nodeIndex, mapIndex); dataOut.push_back(key); } } if (isMappedWithPalette()) { const MetricFile* mf = dynamic_cast(this); CaretAssert(mf); for (int32_t mapIndex = 0; mapIndex < numberOfMaps; mapIndex++) { const float value = mf->getValue(nodeIndex, mapIndex); dataOut.push_back(value); } } } } break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTICES_AVERAGE: { StructureEnum::Enum structure = StructureEnum::INVALID; int32_t numberOfNodes(-1); std::vector nodeIndices; mapFileDataSelector.getSurfaceVertexAverage(structure, numberOfNodes, nodeIndices); if ((getStructure() == structure) && (getNumberOfNodes() == numberOfNodes)) { if (isMappedWithPalette()) { const MetricFile* mf = dynamic_cast(this); CaretAssert(mf); const int32_t numberOfNodeIndices = static_cast(nodeIndices.size()); if (numberOfNodeIndices > 0) { const int32_t numberOfMaps = getNumberOfMaps(); if (numberOfMaps > 0) { for (int32_t iNode = 0; iNode < numberOfNodeIndices; iNode++) { CaretAssertVectorIndex(nodeIndices, iNode); const int32_t nodeIndex = nodeIndices[iNode]; float sum(0.0f); for (int32_t mapIndex = 0; mapIndex < numberOfMaps; mapIndex++) { const float value = mf->getValue(nodeIndex, mapIndex); sum += value; } const float value = sum / numberOfMaps; dataOut.push_back(value); } } } } } } break; case MapFileDataSelector::DataSelectionType::VOLUME_XYZ: break; } } /** * Are all brainordinates in this file also in the given file? * That is, the brainordinates are equal to or a subset of the brainordinates * in the given file. * * @param mapFile * The given map file. * @return * Match status. */ CaretMappableDataFile::BrainordinateMappingMatch GiftiTypeFile::getBrainordinateMappingMatch(const CaretMappableDataFile* mapFile) const { bool giftiFlag = false; CaretAssert(mapFile); switch (mapFile->getDataFileType()) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: giftiFlag = true; break; case DataFileTypeEnum::METRIC: giftiFlag = true; break; case DataFileTypeEnum::METRIC_DYNAMIC: giftiFlag = true; break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: giftiFlag = true; break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: giftiFlag = true; break; case DataFileTypeEnum::UNKNOWN: break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: break; } if (giftiFlag) { const GiftiTypeFile* gtf = dynamic_cast(mapFile); CaretAssert(gtf); if ((this->getNumberOfNodes() == gtf->getNumberOfNodes()) && (this->getStructure() == gtf->getStructure())) { return BrainordinateMappingMatch::EQUAL; } } return BrainordinateMappingMatch::NO; } /** * Get the identification information for a surface node in the given maps. * * @param mapIndices * Indices of maps for which identification information is requested. * @param structure * Structure of the surface. * @param nodeIndex * Index of the node. * @param numberOfNodes * Number of nodes in the surface. * @param textOut * Output containing identification information. */ bool GiftiTypeFile::getSurfaceNodeIdentificationForMaps(const std::vector& mapIndices, const StructureEnum::Enum structure, const int nodeIndex, const int32_t numberOfNodes, AString& textOut) const { textOut.clear(); if ((getStructure() == structure) && (getNumberOfNodes() == numberOfNodes)) { switch (getDataFileType()) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: { const LabelFile* lf = dynamic_cast(this); CaretAssert(lf); const GiftiLabelTable* labelTable = lf->getLabelTable(); AString valuesText; for (const auto mapIndex : mapIndices) { const int32_t key = lf->getLabelKey(nodeIndex, mapIndex); if (key >= 0) { if ( ! valuesText.isEmpty()) { valuesText.append(", "); } valuesText.append(labelTable->getLabel(key)->getName()); } } if ( ! valuesText.isEmpty()) { textOut = valuesText; } } break; case DataFileTypeEnum::METRIC: case DataFileTypeEnum::METRIC_DYNAMIC: // subclass of METRIC { const MetricFile* mf = dynamic_cast(this); CaretAssert(mf); AString valuesText; for (const auto mapIndex : mapIndices) { const float value = mf->getValue(nodeIndex, mapIndex); if ( ! valuesText.isEmpty()) { valuesText.append(", "); } valuesText.append(AString::number(value, 'f', 3)); } if ( ! valuesText.isEmpty()) { textOut = valuesText; } } break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: break; } } return ( ! textOut.isEmpty()); } connectome-workbench-1.4.2/src/Files/GiftiTypeFile.h000066400000000000000000000205751360521144700223520ustar00rootroot00000000000000#ifndef __GIFTI_TYPE_FILE_H__ #define __GIFTI_TYPE_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretMappableDataFile.h" #include "StructureEnum.h" namespace caret { class GiftiFile; class PaletteColorMapping; /// Encapsulates a GiftiFile for use by specific types of GIFTI data files. class GiftiTypeFile : public CaretMappableDataFile { protected: GiftiTypeFile(const DataFileTypeEnum::Enum dataFileType); virtual ~GiftiTypeFile(); GiftiTypeFile(const GiftiTypeFile& s); GiftiTypeFile& operator=(const GiftiTypeFile&); virtual void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation); /** * Validate the contents of the file after it * has been read such as correct number of * data arrays and proper data types/dimensions. * * @throws DataFileException * If the file is not valid. */ virtual void validateDataArraysAfterReading() = 0; void verifyDataArraysHaveSameNumberOfRows(const int32_t minimumSecondDimension, const int32_t maximumSecondDimension) const; public: virtual void clear(); virtual void clearModified(); virtual bool isModifiedExcludingPaletteColorMapping() const; virtual bool isEmpty() const; virtual void readFile(const AString& filename); virtual void writeFile(const AString& filename); virtual AString toString() const; virtual GiftiMetaData* getFileMetaData(); virtual const GiftiMetaData* getFileMetaData() const; virtual StructureEnum::Enum getStructure() const; virtual void setStructure(const StructureEnum::Enum structure); virtual void addMaps(const int32_t numberOfNodes, const int32_t numberOfMaps); /** @return Number of nodes in the file. */ virtual int32_t getNumberOfNodes() const = 0; /** @return Number of columns (data arrays) in the file. */ virtual int32_t getNumberOfColumns() const = 0; //virtual void setNumberOfNodesAndColumns(int32_t nodes, int32_t columns) = 0; virtual AString getColumnName(const int32_t columnIndex) const; int32_t getColumnIndexFromColumnName(const AString& columnName) const; virtual void setColumnName(const int32_t columnIndex, const AString& columnName); PaletteColorMapping* getPaletteColorMapping(const int32_t columnIndex); const PaletteColorMapping* getPaletteColorMapping(const int32_t columnIndex) const; virtual bool isSurfaceMappable() const; virtual bool isVolumeMappable() const; virtual int32_t getNumberOfMaps() const; virtual AString getMapName(const int32_t mapIndex) const; virtual void setMapName(const int32_t mapIndex, const AString& mapName); virtual const GiftiMetaData* getMapMetaData(const int32_t mapIndex) const; virtual GiftiMetaData* getMapMetaData(const int32_t mapIndex); void getFileDataFloat(std::vector& dataOut) const; virtual const FastStatistics* getMapFastStatistics(const int32_t mapIndex); virtual const Histogram* getMapHistogram(const int32_t mapIndex); virtual const Histogram* getMapHistogram(const int32_t mapIndex, const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues); virtual int64_t getDataSizeUncompressedInBytes() const; virtual const FastStatistics* getFileFastStatistics(); virtual const Histogram* getFileHistogram(); virtual const Histogram* getFileHistogram(const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues); virtual bool isMappedWithPalette() const; virtual void getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) const; virtual PaletteColorMapping* getMapPaletteColorMapping(const int32_t mapIndex); virtual const PaletteColorMapping* getMapPaletteColorMapping(const int32_t mapIndex) const; virtual bool isMappedWithLabelTable() const; virtual GiftiLabelTable* getMapLabelTable(const int32_t mapIndex); virtual const GiftiLabelTable* getMapLabelTable(const int32_t mapIndex) const; virtual AString getMapUniqueID(const int32_t mapIndex) const; virtual int32_t getMapIndexFromUniqueID(const AString& uniqueID) const; virtual void updateScalarColoringForMap(const int32_t mapIndex) override; virtual void getDataForSelector(const MapFileDataSelector& mapFileDataSelector, std::vector& dataOut) const override; virtual BrainordinateMappingMatch getBrainordinateMappingMatch(const CaretMappableDataFile* mapFile) const override; virtual bool getSurfaceNodeIdentificationForMaps(const std::vector& mapIndices, const StructureEnum::Enum structure, const int nodeIndex, const int32_t numberOfNodes, AString& textOut) const; private: void copyHelperGiftiTypeFile(const GiftiTypeFile& gtf); void initializeMembersGiftiTypeFile(); /** Fast statistics used when statistics computed on all data in file */ CaretPointer m_fileFastStatistics; /** Histogram used when statistics computed on all data in file */ CaretPointer m_fileHistogram; int32_t m_histogramNumberOfBuckets = 100; /** Histogram with limited values used when statistics computed on all data in file */ CaretPointer m_fileHistorgramLimitedValues; int32_t m_fileHistogramLimitedValuesNumberOfBuckets = 100; float m_fileHistogramLimitedValuesMostPositiveValueInclusive; float m_fileHistogramLimitedValuesLeastPositiveValueInclusive; float m_fileHistogramLimitedValuesLeastNegativeValueInclusive; float m_fileHistogramLimitedValuesMostNegativeValueInclusive; bool m_fileHistogramLimitedValuesIncludeZeroValues; protected: GiftiFile* giftiFile; }; } // namespace #endif // __GIFTI_TYPE_FILE_H__ connectome-workbench-1.4.2/src/Files/GroupAndNameCheckStateEnum.cxx000066400000000000000000000235001360521144700253140ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __GROUP_AND_NAME_CHECK_STATE_ENUM_DECLARE__ #include "GroupAndNameCheckStateEnum.h" #undef __GROUP_AND_NAME_CHECK_STATE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::GroupAndNameCheckStateEnum * \brief * * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param integerCode * Integer code for this enumerated value. * * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ GroupAndNameCheckStateEnum::GroupAndNameCheckStateEnum(const Enum enumValue, const int32_t integerCode, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCode; this->name = name; this->guiName = guiName; } /** * Destructor. */ GroupAndNameCheckStateEnum::~GroupAndNameCheckStateEnum() { } /** * Initialize the enumerated metadata. */ void GroupAndNameCheckStateEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(GroupAndNameCheckStateEnum(UNCHECKED, Qt::Unchecked, "UNCHECKED", "Unchecked")); enumData.push_back(GroupAndNameCheckStateEnum(PARTIALLY_CHECKED, Qt::PartiallyChecked, "PARTIALLY_CHECKED", "PartiallyChecked")); enumData.push_back(GroupAndNameCheckStateEnum(CHECKED, Qt::Checked, "CHECKED", "Checked")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const GroupAndNameCheckStateEnum* GroupAndNameCheckStateEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const GroupAndNameCheckStateEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString GroupAndNameCheckStateEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const GroupAndNameCheckStateEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ GroupAndNameCheckStateEnum::Enum GroupAndNameCheckStateEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = UNCHECKED; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const GroupAndNameCheckStateEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type GroupAndNameCheckStateEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString GroupAndNameCheckStateEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const GroupAndNameCheckStateEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ GroupAndNameCheckStateEnum::Enum GroupAndNameCheckStateEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = UNCHECKED; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const GroupAndNameCheckStateEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type GroupAndNameCheckStateEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t GroupAndNameCheckStateEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const GroupAndNameCheckStateEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ GroupAndNameCheckStateEnum::Enum GroupAndNameCheckStateEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = UNCHECKED; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const GroupAndNameCheckStateEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type GroupAndNameCheckStateEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void GroupAndNameCheckStateEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void GroupAndNameCheckStateEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(GroupAndNameCheckStateEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void GroupAndNameCheckStateEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(GroupAndNameCheckStateEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Files/GroupAndNameCheckStateEnum.h000066400000000000000000000063041360521144700247440ustar00rootroot00000000000000#ifndef __GROUP_AND_NAME_CHECK_STATE_ENUM_H__ #define __GROUP_AND_NAME_CHECK_STATE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class GroupAndNameCheckStateEnum { public: /** * Enumerated values. */ enum Enum { /** Not selected */ UNCHECKED, /** Selected and at least one, but not all children selected */ PARTIALLY_CHECKED, /** Selected and all children (if any) are selected*/ CHECKED }; ~GroupAndNameCheckStateEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: GroupAndNameCheckStateEnum(const Enum enumValue, const int32_t integerCode, const AString& name, const AString& guiName); static const GroupAndNameCheckStateEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __GROUP_AND_NAME_CHECK_STATE_ENUM_DECLARE__ std::vector GroupAndNameCheckStateEnum::enumData; bool GroupAndNameCheckStateEnum::initializedFlag = false; #endif // __GROUP_AND_NAME_CHECK_STATE_ENUM_DECLARE__ } // namespace #endif //__GROUP_AND_NAME_CHECK_STATE_ENUM_H__ connectome-workbench-1.4.2/src/Files/GroupAndNameHierarchyGroup.cxx000066400000000000000000000032511360521144700254050ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CLASS_AND_NAME_HIERARCHY_GROUP_DECLARE__ #include "GroupAndNameHierarchyGroup.h" #undef __CLASS_AND_NAME_HIERARCHY_GROUP_DECLARE__ #include "CaretAssert.h" #include "GroupAndNameHierarchyName.h" using namespace caret; /** * \class caret::GroupAndNameHierarchyGroup * \brief Maintains selection of a class and name in each 'DisplayGroupEnum'. */ /** * Constructor. * @param name * The name. * @param idNumber * ID number assigned to the name. */ GroupAndNameHierarchyGroup::GroupAndNameHierarchyGroup(const AString& name, const int32_t idNumber) : GroupAndNameHierarchyItem(GroupAndNameHierarchyItem::ITEM_TYPE_GROUP, name, idNumber) { } /** * Destructor. */ GroupAndNameHierarchyGroup::~GroupAndNameHierarchyGroup() { } connectome-workbench-1.4.2/src/Files/GroupAndNameHierarchyGroup.h000066400000000000000000000033711360521144700250350ustar00rootroot00000000000000#ifndef __CLASS_AND_NAME_HIERARCHY_GROUP__H_ #define __CLASS_AND_NAME_HIERARCHY_GROUP__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "GroupAndNameHierarchyItem.h" namespace caret { class GroupAndNameHierarchyName; class GroupAndNameHierarchyGroup : public GroupAndNameHierarchyItem { public: GroupAndNameHierarchyGroup(const AString& name, const int32_t idNumber); virtual ~GroupAndNameHierarchyGroup(); // ADD_NEW_METHODS_HERE private: GroupAndNameHierarchyGroup(const GroupAndNameHierarchyGroup&); GroupAndNameHierarchyGroup& operator=(const GroupAndNameHierarchyGroup&); // ADD_NEW_MEMBERS_HERE }; #ifdef __CLASS_AND_NAME_HIERARCHY_GROUP_DECLARE__ // #endif // __CLASS_AND_NAME_HIERARCHY_GROUP_DECLARE__ } // namespace #endif //__CLASS_AND_NAME_HIERARCHY_GROUP__H_ connectome-workbench-1.4.2/src/Files/GroupAndNameHierarchyItem.cxx000066400000000000000000000673741360521144700252270ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GROUP_AND_NAME_HIERARCHY_ITEM_DECLARE__ #include "GroupAndNameHierarchyItem.h" #undef __GROUP_AND_NAME_HIERARCHY_ITEM_DECLARE__ #include "AStringNaturalComparison.h" #include "CaretAssert.h" #include "GroupAndNameHierarchyGroup.h" #include "GroupAndNameHierarchyName.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneClassAssistant.h" #include using namespace caret; /** * \class caret::GroupAndNameHierarchyItem * \brief Base class for items in a hierarchy tree. */ /** * Constructor. * * @param itemType * Type of this item. * @param name * Name of the item. * @param idNumber * Id number for the item. */ GroupAndNameHierarchyItem::GroupAndNameHierarchyItem(const ItemType itemType, const AString& name, const int32_t idNumber) : CaretObject(), m_itemType(itemType), m_name(name), m_idNumber(idNumber), m_parent(0) { m_sceneAssistant = new SceneClassAssistant(); m_iconRGBA[0] = 0.0; m_iconRGBA[1] = 0.0; m_iconRGBA[2] = 0.0; m_iconRGBA[3] = 0.0; clearPrivate(); m_sceneAssistant->addTabIndexedBooleanArray("m_selectedInTab", m_selectedInTab); m_sceneAssistant->addTabIndexedBooleanArray("m_expandedStatusInTab", m_expandedStatusInTab); m_sceneAssistant->addArray("m_selectedInDisplayGroup", m_selectedInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, m_selectedInDisplayGroup[0]); m_sceneAssistant->addArray("m_expandedStatusInDisplayGroup", m_expandedStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, m_expandedStatusInDisplayGroup[0]); } /** * Destructor. */ GroupAndNameHierarchyItem::~GroupAndNameHierarchyItem() { delete m_sceneAssistant; clearPrivate(); } /** * Clear the contents of this class selector. */ void GroupAndNameHierarchyItem::clear() { clearPrivate(); } /** * Clear the contents of this class selector. */ void GroupAndNameHierarchyItem::clearPrivate() { for (std::vector::iterator iter = m_children.begin(); iter != m_children.end(); iter++) { GroupAndNameHierarchyItem* item = *iter; item->m_parent = NULL; delete item; } m_children.clear(); m_childrenNameIdMap.clear(); for (int32_t i = 0; i < DisplayGroupEnum::NUMBER_OF_GROUPS; i++) { m_selectedInDisplayGroup[i] = true; } for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_selectedInTab[i] = true; } bool defaultExpandStatus = false; switch (m_itemType) { case ITEM_TYPE_NAME: break; case ITEM_TYPE_GROUP: break; case ITEM_TYPE_MODEL: defaultExpandStatus = true; break; } for (int32_t i = 0; i < DisplayGroupEnum::NUMBER_OF_GROUPS; i++) { m_expandedStatusInDisplayGroup[i] = defaultExpandStatus; } for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_expandedStatusInTab[i] = defaultExpandStatus; } m_counter = 0; } /** * @return The type of the item. */ GroupAndNameHierarchyItem::ItemType GroupAndNameHierarchyItem::getItemType() const { return m_itemType; } /** * @return The name of the item. */ AString GroupAndNameHierarchyItem::getName() const { return m_name; } /** * Set the name of the item. This should only be used * to set the name of an item without a parent as names * are used when creating a hierarchy. * * @param name * Name of item. */ void GroupAndNameHierarchyItem::setName(const AString& name) { m_name = name; } /** * @return The parent of this item. */ GroupAndNameHierarchyItem* GroupAndNameHierarchyItem::getParent() { return m_parent; } /** * @return The parent of this item. */ const GroupAndNameHierarchyItem* GroupAndNameHierarchyItem::getParent() const { return m_parent; } /** * @return The ancestors of this item. */ std::vector GroupAndNameHierarchyItem::getAncestors() const { std::vector ancestors; if (m_parent != NULL) { ancestors.push_back(m_parent); std::vector parentsAncestors = m_parent->getAncestors(); ancestors.insert(ancestors.end(), parentsAncestors.begin(), parentsAncestors.end()); } return ancestors; } /** * @return The descendants of this item. */ std::vector GroupAndNameHierarchyItem::getDescendants() const { std::vector descendants; if (m_parent != NULL) { for (std::vector::const_iterator iter = m_children.begin(); iter != m_children.end(); iter++) { GroupAndNameHierarchyItem* child = *iter; descendants.push_back(child); std::vector childDescendants = child->getDescendants(); descendants.insert(descendants.end(), childDescendants.begin(), childDescendants.end()); } } return descendants; } /** * @return The children of this item. */ std::vector GroupAndNameHierarchyItem::getChildren() const { return m_children; } static bool lessName(const GroupAndNameHierarchyItem* itemOne, const GroupAndNameHierarchyItem* itemTwo) { const int32_t result = AStringNaturalComparison::compare(itemOne->getName(), itemTwo->getName()); if (result < 0) { return true; } return false; // return (itemOne->getName() < itemTwo->getName()); } /** * Sort the descendants by name */ void GroupAndNameHierarchyItem::sortDescendantsByName() { std::sort(m_children.begin(), m_children.end(), lessName); for (std::vector::iterator iter = m_children.begin(); iter != m_children.end(); iter++) { GroupAndNameHierarchyItem* child = *iter; child->sortDescendantsByName(); } } /** * Get the child with the given name and ID number. * * @param name * Name of child. * @return Child with the given name and ID number or NULL if no * child with the name and ID number. */ GroupAndNameHierarchyItem* GroupAndNameHierarchyItem::getChildWithNameAndIdNumber(const AString& name, const int32_t idNumber) { ChildMapKey childMapKey(idNumber, name); std::map::iterator iter; iter = m_childrenNameIdMap.find(childMapKey); if (iter != m_childrenNameIdMap.end()) { GroupAndNameHierarchyItem* item = iter->second; return item; } return NULL; } /** * Add the given child to this item. * * @param child * Child to add. */ void GroupAndNameHierarchyItem::addChild(GroupAndNameHierarchyItem* child) { CaretAssertMessage((getChildWithNameAndIdNumber(child->getName(), child->getIdNumber()) != NULL), ("Child with name=" + child->getName() + ", idNumber=" + AString::number(child->getIdNumber()) + " already is in item named=" + getName())); addChildPrivate(child); } /** * Add the given child to this item. * * @param child * Child to add. */ void GroupAndNameHierarchyItem::addChildPrivate(GroupAndNameHierarchyItem* child) { child->m_parent = this; m_children.push_back(child); ChildMapKey childMapKey(child->getIdNumber(), child->getName()); m_childrenNameIdMap.insert(std::make_pair(childMapKey, child)); } /** * Add a child with the given name and id number. * * @param itemType * Type of the item. * @param name * Name of item. * @param idNumber * ID Number for item. * @return If a child with the given name and id number exists, * it is returned. Otherwise, a new child with the given * name and id number is created and returned. */ GroupAndNameHierarchyItem* GroupAndNameHierarchyItem::addChild(const ItemType itemType, const AString& name, const int32_t idNumber) { GroupAndNameHierarchyItem* child = getChildWithNameAndIdNumber(name, idNumber); if (child != NULL) { child->incrementCounter(); return child; } switch (itemType) { case ITEM_TYPE_GROUP: child = new GroupAndNameHierarchyGroup(name, idNumber); break; case ITEM_TYPE_NAME: child = new GroupAndNameHierarchyName(name, idNumber); break; case ITEM_TYPE_MODEL: CaretAssertMessage(0, "Model should never be a child"); break; } child->incrementCounter(); addChildPrivate(child); return child; } /** * Remove the given child from this item. The child IS NOT deleted. * * @param child * Child to remove. */ void GroupAndNameHierarchyItem::removeChild(GroupAndNameHierarchyItem* child) { std::vector::iterator iter = std::find(m_children.begin(), m_children.end(), child); if (iter != m_children.end()) { child->m_parent = NULL; m_children.erase(iter); } for (std::map::iterator mapIter = m_childrenNameIdMap.begin(); mapIter != m_childrenNameIdMap.end(); mapIter++) { GroupAndNameHierarchyItem* item = mapIter->second; if (item == child) { m_childrenNameIdMap.erase(mapIter); break; } } } /** * Is this item selected? * * @param displayGroup * The display group in which the item is controlled/viewed. * @param tabIndex * Index of browser tab in which item is controlled/viewed. * @return * True if item is selected, else false. */ bool GroupAndNameHierarchyItem::isSelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { const int32_t displayIndex = (int32_t)displayGroup; CaretAssertArrayIndex(m_selectedInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, displayIndex); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_selectedInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_selectedInTab[tabIndex]; } return m_selectedInDisplayGroup[displayIndex]; } /** * Get the "check state" of an item. * * @param displayGroup * The display group in which the item is controlled/viewed. * @param tabIndex * Index of browser tab in which item is controlled/viewed. * @return * CHECKED if this item and ALL of its children are selected. * PARTIALLY_CHECKED if this item is selected and any of its * children, but not all of its children, are selected. * UNCHECKED if this item is not selected. */ GroupAndNameCheckStateEnum::Enum GroupAndNameHierarchyItem::getCheckState(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { if (isSelected(displayGroup, tabIndex)) { int64_t numChildren = 0; int64_t numChildrenChecked = 0; for (std::vector::const_iterator iter = m_children.begin(); iter != m_children.end(); iter++) { numChildren++; GroupAndNameHierarchyItem* child = *iter; const GroupAndNameCheckStateEnum::Enum childStatus = child->getCheckState(displayGroup, tabIndex); switch (childStatus) { case GroupAndNameCheckStateEnum::CHECKED: numChildrenChecked++; break; case GroupAndNameCheckStateEnum::PARTIALLY_CHECKED: return GroupAndNameCheckStateEnum::PARTIALLY_CHECKED; break; case GroupAndNameCheckStateEnum::UNCHECKED: break; } } if (numChildrenChecked == numChildren) { return GroupAndNameCheckStateEnum::CHECKED; } else if (numChildrenChecked > 0) { return GroupAndNameCheckStateEnum::PARTIALLY_CHECKED; } } return GroupAndNameCheckStateEnum::UNCHECKED; } /** * Set the selected status of this item only. It does not alter * the status of ancestors and children. * * @param displayGroup * The display group in which the item is controlled/viewed. * @param tabIndex * Index of browser tab in which item is controlled/viewed. * @param status * True if item is selected, else false. */ void GroupAndNameHierarchyItem::setSelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool status) { const int32_t displayIndex = (int32_t)displayGroup; CaretAssertArrayIndex(m_selectedInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, displayIndex); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_selectedInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_selectedInTab[tabIndex] = status; } else { m_selectedInDisplayGroup[displayIndex] = status; } } /** * Set the selected status for all of this item's descendants. * * @param displayGroup * The display group in which the item is controlled/viewed. * @param tabIndex * Index of browser tab in which item is controlled/viewed. * @param status * True if item is selected, else false. */ void GroupAndNameHierarchyItem::setDescendantsSelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool status) { for (std::vector::const_iterator iter = m_children.begin(); iter != m_children.end(); iter++) { GroupAndNameHierarchyItem* child = *iter; child->setSelected(displayGroup, tabIndex, status); child->setDescendantsSelected(displayGroup, tabIndex, status); } } /** * Set the selected status of this item's ancestor's (parent, * its parent, etc). * * @param displayGroup * The display group in which the item is controlled/viewed. * @param tabIndex * Index of browser tab in which item is controlled/viewed. * @param status * True if item is selected, else false. */ void GroupAndNameHierarchyItem::setAncestorsSelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool status) { if (m_parent != NULL) { m_parent->setSelected(displayGroup, tabIndex, status); m_parent->setAncestorsSelected(displayGroup, tabIndex, status); } } /** * Set the selected status of this item, its ancestors, and all * of its children. * * @param displayGroup * The display group in which the item is controlled/viewed. * @param tabIndex * Index of browser tab in which item is controlled/viewed. * @param status * True if item is selected, else false. */ void GroupAndNameHierarchyItem::setSelfAncestorsAndDescendantsSelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool status) { setSelected(displayGroup, tabIndex, status); setAncestorsSelected(displayGroup, tabIndex, status); setDescendantsSelected(displayGroup, tabIndex, status); } /** * Get the RGBA color for an Icon that is displayed * in the selection control for this item. * * @return * Pointer to the Red, Green, Blue, and Alpha * color components for this item's icon. * If no icon is to be displayed, the alpha component is zero. */ const float* GroupAndNameHierarchyItem::getIconColorRGBA() const { return m_iconRGBA; } /** * Set the RGBA color components for an icon displayed in the * selection control for this item. * * @param rgba * The Red, Green, Blue, and Alpha color components. * If no icon is to be displayed, the alpha component is zero. */ void GroupAndNameHierarchyItem::setIconColorRGBA(const float rgba[4]) { m_iconRGBA[0] = rgba[0]; m_iconRGBA[1] = rgba[1]; m_iconRGBA[2] = rgba[2]; m_iconRGBA[3] = rgba[3]; } /** * Is this item expanded to display its children in the * selection controls? * * @param displayGroup * The display group in which the item is controlled/viewed. * @param tabIndex * Index of browser tab in which item is controlled/viewed. * @return * True if children should be visible, else false. */ bool GroupAndNameHierarchyItem::isExpandedToDisplayChildren(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { const int32_t displayIndex = (int32_t)displayGroup; CaretAssertArrayIndex(m_expandedStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, displayIndex); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_expandedStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_expandedStatusInTab[tabIndex]; } return m_expandedStatusInDisplayGroup[displayIndex]; } /** * Set this item expanded to display its children in the * selection controls. * * @param displayGroup * The display group in which the item is controlled/viewed. * @param tabIndex * Index of browser tab in which item is controlled/viewed. * @param expanded * True if children should be visible, else false. */ void GroupAndNameHierarchyItem::setExpandedToDisplayChildren(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool expanded) { const int32_t displayIndex = (int32_t)displayGroup; CaretAssertArrayIndex(m_expandedStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, displayIndex); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(m_expandedStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_expandedStatusInTab[tabIndex] = expanded; } else { m_expandedStatusInDisplayGroup[displayIndex] = expanded; } } /** * Copy the selections from one tab to another tab. * Also copies selections in all descendants. * * @param sourceTabIndex * Index of source tab (copy "from") * @param targetTabIndex * Index of target tab (copy "to") */ void GroupAndNameHierarchyItem::copySelections(const int32_t sourceTabIndex, const int32_t targetTabIndex) { m_selectedInTab[targetTabIndex] = m_selectedInTab[sourceTabIndex]; m_expandedStatusInTab[targetTabIndex] = m_expandedStatusInTab[sourceTabIndex]; for (std::vector::const_iterator iter = m_children.begin(); iter != m_children.end(); iter++) { GroupAndNameHierarchyItem* child = *iter; child->copySelections(sourceTabIndex, targetTabIndex); } } /** * @return The Id Number. */ int32_t GroupAndNameHierarchyItem::getIdNumber() const { return m_idNumber; } /** * Clear the counter. Also clears counters in descendants. */ void GroupAndNameHierarchyItem::clearCounters() { m_counter = 0; for (std::vector::const_iterator iter = m_children.begin(); iter != m_children.end(); iter++) { GroupAndNameHierarchyItem* child = *iter; child->clearCounters(); } } /** * Increment the counter. */ void GroupAndNameHierarchyItem::incrementCounter() { m_counter++; } /** * @return The value of the counter. */ int32_t GroupAndNameHierarchyItem::getCounter() const { return m_counter; } /** * Remove all descendants with counters equal to zero. */ void GroupAndNameHierarchyItem::removeDescendantsWithCountersEqualToZeros() { /* * Process all descendants. */ for (std::vector::const_iterator iter = m_children.begin(); iter != m_children.end(); iter++) { GroupAndNameHierarchyItem* child = *iter; child->removeDescendantsWithCountersEqualToZeros(); } /* * Find children with zero counters indicating item not used. */ std::vector childrenWithCountGreaterThanZero; std::vector childrenWithCountEqualToZero; for (std::vector::const_iterator iter = m_children.begin(); iter != m_children.end(); iter++) { GroupAndNameHierarchyItem* child = *iter; if (child->getCounter() > 0) { childrenWithCountGreaterThanZero.push_back(child); } else { childrenWithCountEqualToZero.push_back(child); } } /* * If no children with zero counter, return. */ if (childrenWithCountEqualToZero.empty()) { return; } /* * Remove children with zero counters */ for (std::vector::iterator iter = childrenWithCountEqualToZero.begin(); iter != childrenWithCountEqualToZero.end(); iter++) { GroupAndNameHierarchyItem* item = *iter; item->m_parent = NULL; delete item; } /* * Clear children */ m_children.clear(); m_childrenNameIdMap.clear(); /* * Read children so maps properly created. */ for (std::vector::iterator iter = childrenWithCountGreaterThanZero.begin(); iter != childrenWithCountGreaterThanZero.end(); iter++) { addChildPrivate(*iter); } } /** * Get a description of this object's content. * @return String describing this object's content. */ AString GroupAndNameHierarchyItem::toString() const { AString info = (CaretObject::toString() + "\n name=" + m_name + ", type" + AString::number(m_itemType) + ", idNumber=" + AString::number(m_idNumber) + ", counter=" + AString::number(m_counter) + "\n"); AString childInfo; for (std::vector::const_iterator iter = m_children.begin(); iter != m_children.end(); iter++) { GroupAndNameHierarchyItem* child = *iter; childInfo += child->toString(); } if (childInfo.isEmpty() == false) { childInfo = childInfo.replace("\n", "\n "); } info += childInfo; return info; } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of the class' instance. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* GroupAndNameHierarchyItem::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "GroupAndNameHierarchyItem", 1); sceneClass->addString("m_name", m_name); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); for (std::vector::iterator iter = m_children.begin(); iter != m_children.end(); iter++) { GroupAndNameHierarchyItem* child = *iter; sceneClass->addClass(child->saveToScene(sceneAttributes, child->getName())); } return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void GroupAndNameHierarchyItem::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } sceneClass->getStringValue("m_name"); // prevents "failed to restore" m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); for (std::vector::iterator iter = m_children.begin(); iter != m_children.end(); iter++) { GroupAndNameHierarchyItem* child = *iter; child->restoreFromScene(sceneAttributes, sceneClass->getClass(child->getName())); } } connectome-workbench-1.4.2/src/Files/GroupAndNameHierarchyItem.h000066400000000000000000000213431360521144700246360ustar00rootroot00000000000000#ifndef __GROUP_AND_NAME_HIERARCHY_ITEM_H__ #define __GROUP_AND_NAME_HIERARCHY_ITEM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "CaretObject.h" #include "DisplayGroupEnum.h" #include "GroupAndNameCheckStateEnum.h" #include "SceneableInterface.h" namespace caret { class SceneClassAssistant; class GroupAndNameHierarchyItem : public CaretObject, SceneableInterface { public: /** * Type of item. */ enum ItemType { /** Model (eg: file) */ ITEM_TYPE_MODEL, /** Group (eg: class or map) */ ITEM_TYPE_GROUP, /** Name (eg: border, focus, or label) */ ITEM_TYPE_NAME }; protected: GroupAndNameHierarchyItem(const ItemType itemType, const AString& name, const int32_t idNumber); public: virtual ~GroupAndNameHierarchyItem(); virtual void clear(); ItemType getItemType() const; AString getName() const; GroupAndNameHierarchyItem* getParent(); const GroupAndNameHierarchyItem* getParent() const; std::vector getAncestors() const; std::vector getChildren() const; void sortDescendantsByName(); GroupAndNameHierarchyItem* getChildWithNameAndIdNumber(const AString& name, const int32_t idNumber); std::vector getDescendants() const; GroupAndNameHierarchyItem* addChild(const ItemType itemType, const AString& name, const int32_t idNumber); void addChild(GroupAndNameHierarchyItem* child); void removeChild(GroupAndNameHierarchyItem* child); bool isSelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; GroupAndNameCheckStateEnum::Enum getCheckState(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setSelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool status); void setDescendantsSelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool status); void setAncestorsSelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool status); void setSelfAncestorsAndDescendantsSelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool status); const float* getIconColorRGBA() const; void setIconColorRGBA(const float rgba[4]); bool isExpandedToDisplayChildren(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; void setExpandedToDisplayChildren(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool expanded); virtual void copySelections(const int32_t sourceTabIndex, const int32_t targetTabIndex); int32_t getIdNumber() const; void clearCounters(); void incrementCounter(); int32_t getCounter() const; void removeDescendantsWithCountersEqualToZeros(); // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); protected: void setName(const AString& name); private: GroupAndNameHierarchyItem(const GroupAndNameHierarchyItem&); GroupAndNameHierarchyItem& operator=(const GroupAndNameHierarchyItem&); void addChildPrivate(GroupAndNameHierarchyItem* child); void clearPrivate(); class ChildMapKey { public: ChildMapKey(const int32_t idNumber, const AString& name) : m_idNumber(idNumber), m_name(name) { } const int32_t m_idNumber; const AString m_name; bool operator==(const ChildMapKey& childMapKey) const { if (m_idNumber == childMapKey.m_idNumber) { if (m_name == childMapKey.m_name) { return true; } } return false; } bool operator<(const ChildMapKey& childMapKey) const { if (m_idNumber < childMapKey.m_idNumber) { return true; } else if (m_idNumber == childMapKey.m_idNumber) { if (m_name < childMapKey.m_name) { return true; } // else if (m_name == childMapKey.m_name) { // return 0; // } } // return 1; return false; } }; // bool operator<(const ChildMapKey& a, // const ChildMapKey& b) { // if (a.m_idNumber < b.m_idNumber) { // return true; // } // else if (a.m_idNumber == b.m_idNumber) { // if (a.m_name < b.m_name) { // return true; // } // } // return false; // } /** Type of item */ const ItemType m_itemType; /** Name of this item */ AString m_name; /** ID Number */ const int32_t m_idNumber; /** Parent of this item */ GroupAndNameHierarchyItem* m_parent; /** Children of this item */ std::vector m_children; /** For fast access to children by name and id number of child */ std::map m_childrenNameIdMap; /** Selection for each display group */ bool m_selectedInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; /** Selection for each tab */ bool m_selectedInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** Color for icon, valid when (iconRGBA[3] > 0.0) */ float m_iconRGBA[4]; /** Expanded (collapsed) status in display group */ bool m_expandedStatusInDisplayGroup[DisplayGroupEnum::NUMBER_OF_GROUPS]; /** Expanded (collapsed) status in tab */ bool m_expandedStatusInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** Counter for tracking usage of item */ int32_t m_counter; /** Assists with scenes */ SceneClassAssistant* m_sceneAssistant; // ADD_NEW_MEMBERS_HERE }; #ifdef __GROUP_AND_NAME_HIERARCHY_ITEM_DECLARE__ #endif // __GROUP_AND_NAME_HIERARCHY_ITEM_DECLARE__ } // namespace #endif //__GROUP_AND_NAME_HIERARCHY_ITEM_H__ connectome-workbench-1.4.2/src/Files/GroupAndNameHierarchyModel.cxx000066400000000000000000001071111360521144700253510ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CLASS_AND_NAME_HIERARCHY_MODEL_DECLARE__ #include "GroupAndNameHierarchyModel.h" #undef __CLASS_AND_NAME_HIERARCHY_MODEL_DECLARE__ #include "Border.h" #include "BorderFile.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CiftiMappableDataFile.h" #include "GroupAndNameHierarchyGroup.h" #include "GroupAndNameHierarchyName.h" #include "FociFile.h" #include "Focus.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "LabelFile.h" #include "VolumeFile.h" using namespace caret; /** * \class caret::GroupAndNameHierarchySelection * \brief Maintains a 'group' and 'name' hierarchy for selection. * * Each group maps to one or more names. Identical names * may be children of more than one group. However, each * group holds its child names independently from the children * of all other groups. * * Note: Two containers are used to hold the data. One, * a vector, maps group keys to groups and a second, a map * group names to groups. * use 'maps'. A map is typically constructed using a * balanced tree so retrieval can be fast. However, adding * or removing items may be slow due to tree rebalancing. * As a result, unused groups and children names are only * removed when the entire instance is cleared (via clear()) * or by calling removeUnusedNamesAndGroupes(). * * Each group or name supports a 'count'. If the for a group * or name is zero, that indicates that the item is unused. * * Attributes are available for every tab and also a * few 'display groups'. A number of methods in this group accept * both display group and tab index parameters. When the display * group is set to 'Tab', the tab index is used meaning that the * attribute requeted/sent is for use with a specifc tab. For an * other display group value, the attribute is for a display group * and the tab index is ignored. */ /** * Constructor. */ GroupAndNameHierarchyModel::GroupAndNameHierarchyModel() : GroupAndNameHierarchyItem(GroupAndNameHierarchyItem::ITEM_TYPE_MODEL, "", -1) { this->clearModelPrivate(); } /** * Destructor. */ GroupAndNameHierarchyModel::~GroupAndNameHierarchyModel() { this->clearModelPrivate(); } /** * Clear the group/name hierarchy. */ void GroupAndNameHierarchyModel::clear() { GroupAndNameHierarchyItem::clear(); clearModelPrivate(); } /** * Clear the group/name hierarchy. */ void GroupAndNameHierarchyModel::clearModelPrivate() { setUserInterfaceUpdateNeeded(); } /** * Set the selected status for self and all children. * @param status * The selection status. */ void GroupAndNameHierarchyModel::setAllSelected(const bool status) { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { setAllSelected(DisplayGroupEnum::DISPLAY_GROUP_TAB, i, status); } for (int32_t i = 0; i < DisplayGroupEnum::NUMBER_OF_GROUPS; i++) { const DisplayGroupEnum::Enum displayGroup = DisplayGroupEnum::fromIntegerCode(i, NULL); if (displayGroup != DisplayGroupEnum::DISPLAY_GROUP_TAB) { setAllSelected(displayGroup, -1, status); } } } /** * Set the selection status of this hierarchy model for the display group/tab. * @param displayGroup * Display group selected. * @param tabIndex * Index of tab used when displayGroup is DisplayGroupEnum::DISPLAY_GROUP_TAB. * @param selectionStatus * New selection status. */ void GroupAndNameHierarchyModel::setAllSelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool selectionStatus) { setSelfAncestorsAndDescendantsSelected(displayGroup, tabIndex, selectionStatus); } /** * Update this group hierarchy with the border names * and classes. * * @param borderFile * The border file from which classes and names are from. * @parm forceUpdate * If true, force an update. */ void GroupAndNameHierarchyModel::update(BorderFile* borderFile, const bool forceUpdate) { bool needToGenerateKeys = forceUpdate; setName(borderFile->getFileNameNoPath()); const int32_t numBorders = borderFile->getNumberOfBorders(); if (needToGenerateKeys == false) { for (int32_t i = 0; i < numBorders; i++) { const Border* border = borderFile->getBorder(i); if (border->getGroupNameSelectionItem() == NULL) { needToGenerateKeys = true; } } } /* * ID for groups and names is not used */ const int32_t ID_NOT_USED = 0; if (needToGenerateKeys) { /* * Clear the counters */ clearCounters(); /* * Names for missing group names or border names. */ const AString missingGroupName = "NoGroup"; const AString missingBorderName = "NoName"; /* * For icons */ const GiftiLabelTable* classLabelTable = borderFile->getClassColorTable(); const GiftiLabelTable* nameLabelTable = borderFile->getNameColorTable(); const float rgbaBlack[4] = { 0.0, 0.0, 0.0, 1.0 }; /* * Update with all borders. */ for (int32_t i = 0; i < numBorders; i++) { Border* border = borderFile->getBorder(i); /* * Get the group. If it is empty, use the default name. */ AString theGroupName = border->getClassName(); if (theGroupName.isEmpty()) { theGroupName = missingGroupName; } /* * Get the name. */ AString name = border->getName(); if (name.isEmpty()) { name = missingBorderName; } /* * Class */ GroupAndNameHierarchyItem* groupItem = addChild(GroupAndNameHierarchyItem::ITEM_TYPE_GROUP, theGroupName, ID_NOT_USED); CaretAssert(groupItem); const GiftiLabel* groupLabel = classLabelTable->getLabelBestMatching(theGroupName); if (groupLabel != NULL) { float tempcolor[4]; groupLabel->getColor(tempcolor); groupItem->setIconColorRGBA(tempcolor); } else { groupItem->setIconColorRGBA(rgbaBlack); } /* * Name */ GroupAndNameHierarchyItem* nameItem = groupItem->addChild(GroupAndNameHierarchyItem::ITEM_TYPE_NAME, name, ID_NOT_USED); const GiftiLabel* nameLabel = nameLabelTable->getLabelBestMatching(name); if (nameLabel != NULL) { float tempcolor[4]; nameLabel->getColor(tempcolor); nameItem->setIconColorRGBA(tempcolor); } else { nameItem->setIconColorRGBA(rgbaBlack); } /* * Place the name selector into the border. */ border->setGroupNameSelectionItem(nameItem); } removeDescendantsWithCountersEqualToZeros(); sortDescendantsByName(); setUserInterfaceUpdateNeeded(); CaretLogFine("BORDER HIERARCHY:" + toString()); } } /** * Update this group hierarchy with the label names * and maps (as group). Groupes and names are done * differently for LabelFiles. Use the map index as * the group key and the label index as the name key. * * @param labelFile * The label file from which groups (map) and names are from. * @parm forceUpdate * If true, force an update. */ void GroupAndNameHierarchyModel::update(LabelFile* labelFile, const bool forceUpdate) { bool needToGenerateKeys = forceUpdate; setName(labelFile->getFileNameNoPath()); /* * Names for missing group names or foci names. */ const AString missingGroupName = "NoGroup"; const AString missingName = "NoName"; /* * The label table */ GiftiLabelTable* labelTable = labelFile->getLabelTable(); std::map labelKeysAndNames; if (needToGenerateKeys == false) { /* * Check to see if any group (map) names have changed. */ const std::vector groups = getChildren(); const int numGroups = static_cast(groups.size()); if (numGroups != labelFile->getNumberOfMaps()) { needToGenerateKeys = true; } else { for (int32_t i = 0; i < numGroups; i++) { AString mapName = labelFile->getMapName(i); if (mapName.isEmpty()) { mapName = missingGroupName; } if (groups[i]->getName() != mapName) { needToGenerateKeys = true; break; } } if (needToGenerateKeys == false) { labelTable->getKeysAndNames(labelKeysAndNames); if (m_previousLabelFileKeysAndNames.size() != labelKeysAndNames.size()) { needToGenerateKeys = true; } else { std::map::const_iterator prevIter = m_previousLabelFileKeysAndNames.begin(); for (std::map::const_iterator labelIter = labelKeysAndNames.begin(); labelIter != labelKeysAndNames.end(); labelIter++) { if (prevIter->first != labelIter->first) { needToGenerateKeys = true; break; } else if (prevIter->second != labelIter->second) { needToGenerateKeys = true; break; } prevIter++; } // if (std::equal(labelKeysAndNames.begin(), // labelKeysAndNames.end(), // m_previousLabelKeysAndNames) == false) { // needToGenerateKeys = true; // } } // if (labelTable->hasLabelsWithInvalidGroupNameHierarchy()) { // needToGenerateKeys = true; // } } } } if (needToGenerateKeys) { //const int32_t ID_NOT_USED = 0; /* * Save keys and names for comparison in next update test */ m_previousLabelFileKeysAndNames = labelKeysAndNames; if (m_previousLabelFileKeysAndNames.empty()) { labelTable->getKeysAndNames(m_previousLabelFileKeysAndNames); } /* * Clear everything */ this->clear(); /* * Update with labels from maps */ const int32_t numMaps = labelFile->getNumberOfMaps(); for (int32_t iMap = 0; iMap < numMaps; iMap++) { /* * Get the group. If it is empty, use the default name. */ AString theGroupName = labelFile->getMapName(iMap); if (theGroupName.isEmpty()) { theGroupName = missingGroupName; } /* * Find/create group */ GroupAndNameHierarchyItem* groupItem = addChild(GroupAndNameHierarchyItem::ITEM_TYPE_GROUP, theGroupName, iMap); CaretAssert(groupItem); /* * Get indices of labels used in this map */ std::vector labelKeys = labelFile->getUniqueLabelKeysUsedInMap(iMap); const int32_t numLabelKeys = static_cast(labelKeys.size()); for (int32_t iLabel = 0; iLabel < numLabelKeys; iLabel++) { const int32_t labelKey = labelKeys[iLabel]; GiftiLabel* label = labelTable->getLabel(labelKey); if (label == NULL) { continue; } AString labelName = label->getName(); if (labelName.isEmpty()) { labelName = missingName; } float rgba[4]; label->getColor(rgba); /* * Adding focus to class */ GroupAndNameHierarchyItem* nameItem = groupItem->addChild(GroupAndNameHierarchyItem::ITEM_TYPE_NAME, labelName, labelKey); nameItem->setIconColorRGBA(rgba); /* * Place the name selector into the label. */ label->setGroupNameSelectionItem(nameItem); } } /* * Sort names in each group */ std::vector groups = getChildren(); for (std::vector::iterator iter = groups.begin(); iter != groups.end(); iter++) { GroupAndNameHierarchyItem* nameItem = *iter; nameItem->sortDescendantsByName(); } setUserInterfaceUpdateNeeded(); CaretLogFine("LABEL HIERARCHY:" + toString()); } } /** * Update this group hierarchy with the label names * and groups. * * @param ciftiMappableDataFile * The cifti mappable data file from which classes and names are from. * @parm forceUpdate * If true, force an update. */ void GroupAndNameHierarchyModel::update(CiftiMappableDataFile* ciftiMappableDataFile, const bool forceUpdate) { /* * If it is not a label file, there is nothing to do. */ if (ciftiMappableDataFile->isMappedWithLabelTable() == false) { this->clear(); return; } /* * Names for missing group names or foci names. */ const AString missingGroupName = "NoGroup"; const AString missingName = "NoName"; bool needToGenerateKeys = forceUpdate; setName(ciftiMappableDataFile->getFileNameNoPath()); std::vector > labelMapKeysAndNames; if (needToGenerateKeys == false) { /* * Check to see if any group (map) names have changed. */ const std::vector groups = getChildren(); const int numGroups = static_cast(groups.size()); if (numGroups != ciftiMappableDataFile->getNumberOfMaps()) { /* * Number of maps has changed. */ needToGenerateKeys = true; } else { for (int32_t i = 0; i < numGroups; i++) { AString mapName = ciftiMappableDataFile->getMapName(i); if (mapName.isEmpty()) { mapName = missingGroupName; } if (groups[i]->getName() != mapName) { needToGenerateKeys = true; break; } } if (needToGenerateKeys == false) { if (static_cast(m_previousCiftiLabelFileMapKeysAndNames.size()) != ciftiMappableDataFile->getNumberOfMaps()) { needToGenerateKeys = true; } } if (needToGenerateKeys == false) { for (int32_t i = 0; i < numGroups; i++) { const GiftiLabelTable* labelTable = ciftiMappableDataFile->getMapLabelTable(i); std::map labelKeysAndNames; labelTable->getKeysAndNames(labelKeysAndNames); labelMapKeysAndNames.push_back(labelKeysAndNames); } for (int32_t i = 0; i < numGroups; i++) { const std::map& labelKeysAndNames = labelMapKeysAndNames[i]; const std::map& previousLabelKeysAndNames = m_previousCiftiLabelFileMapKeysAndNames[i]; if (previousLabelKeysAndNames.size() != labelKeysAndNames.size()) { needToGenerateKeys = true; break; } else { std::map::const_iterator prevIter = previousLabelKeysAndNames.begin(); for (std::map::const_iterator labelIter = labelKeysAndNames.begin(); labelIter != labelKeysAndNames.end(); labelIter++) { if (prevIter->first != labelIter->first) { needToGenerateKeys = true; break; } else if (prevIter->second != labelIter->second) { needToGenerateKeys = true; break; } prevIter++; } } } } } } if (needToGenerateKeys) { //const int32_t ID_NOT_USED = 0; /* * Save keys and names for comparison in next update test */ const int numMaps = ciftiMappableDataFile->getNumberOfMaps(); m_previousCiftiLabelFileMapKeysAndNames = labelMapKeysAndNames; if (m_previousCiftiLabelFileMapKeysAndNames.empty()) { for (int32_t i = 0; i < numMaps; i++) { const GiftiLabelTable* labelTable = ciftiMappableDataFile->getMapLabelTable(i); std::map labelKeysAndNames; labelTable->getKeysAndNames(labelKeysAndNames); m_previousCiftiLabelFileMapKeysAndNames.push_back(labelKeysAndNames); } } /* * Clear everything */ this->clear(); /* * Update with labels from maps */ for (int32_t iMap = 0; iMap < numMaps; iMap++) { /* * The label table */ GiftiLabelTable* labelTable = ciftiMappableDataFile->getMapLabelTable(iMap); /* * Get the group. If it is empty, use the default name. */ AString theGroupName = ciftiMappableDataFile->getMapName(iMap); if (theGroupName.isEmpty()) { theGroupName = missingGroupName; } /* * Find/create group */ GroupAndNameHierarchyItem* groupItem = addChild(GroupAndNameHierarchyItem::ITEM_TYPE_GROUP, theGroupName, iMap); CaretAssert(groupItem); /* * Get indices of labels used in this map */ std::vector labelKeys = ciftiMappableDataFile->getUniqueLabelKeysUsedInMap(iMap); const int32_t numLabelKeys = static_cast(labelKeys.size()); for (int32_t iLabel = 0; iLabel < numLabelKeys; iLabel++) { const int32_t labelKey = labelKeys[iLabel]; GiftiLabel* label = labelTable->getLabel(labelKey); if (label == NULL) { continue; } AString labelName = label->getName(); if (labelName.isEmpty()) { labelName = missingName; } float rgba[4]; label->getColor(rgba); /* * Adding focus to class */ GroupAndNameHierarchyItem* nameItem = groupItem->addChild(GroupAndNameHierarchyItem::ITEM_TYPE_NAME, labelName, labelKey); nameItem->setIconColorRGBA(rgba); /* * Place the name selector into the label. */ label->setGroupNameSelectionItem(nameItem); } } /* * Sort names in each group */ std::vector groups = getChildren(); for (std::vector::iterator iter = groups.begin(); iter != groups.end(); iter++) { GroupAndNameHierarchyItem* nameItem = *iter; nameItem->sortDescendantsByName(); } setUserInterfaceUpdateNeeded(); CaretLogFine("LABEL HIERARCHY:" + toString()); } } /** * Update this group hierarchy with the label names * and groups. * * @param ciftiMappableDataFile * The volume file from which classes and names are from. * @parm forceUpdate * If true, force an update. */ void GroupAndNameHierarchyModel::update(VolumeFile* volumeFile, const bool forceUpdate) { /* * If it is not a label file, there is nothing to do. */ if (volumeFile->isMappedWithLabelTable() == false) { this->clear(); return; } /* * Names for missing group names or foci names. */ const AString missingGroupName = "NoGroup"; const AString missingName = "NoName"; bool needToGenerateKeys = forceUpdate; setName(volumeFile->getFileNameNoPath()); std::vector > labelMapKeysAndNames; if (needToGenerateKeys == false) { /* * Check to see if any group (map) names have changed. */ const std::vector groups = getChildren(); const int numGroups = static_cast(groups.size()); if (numGroups != volumeFile->getNumberOfMaps()) { /* * Number of maps has changed. */ needToGenerateKeys = true; } else { for (int32_t i = 0; i < numGroups; i++) { AString mapName = volumeFile->getMapName(i); if (mapName.isEmpty()) { mapName = missingGroupName; } if (groups[i]->getName() != mapName) { needToGenerateKeys = true; break; } } if (needToGenerateKeys == false) { if (static_cast(m_previousCiftiLabelFileMapKeysAndNames.size()) != volumeFile->getNumberOfMaps()) { needToGenerateKeys = true; } } if (needToGenerateKeys == false) { for (int32_t i = 0; i < numGroups; i++) { const GiftiLabelTable* labelTable = volumeFile->getMapLabelTable(i); std::map labelKeysAndNames; labelTable->getKeysAndNames(labelKeysAndNames); labelMapKeysAndNames.push_back(labelKeysAndNames); } for (int32_t i = 0; i < numGroups; i++) { const std::map& labelKeysAndNames = labelMapKeysAndNames[i]; const std::map& previousLabelKeysAndNames = m_previousCiftiLabelFileMapKeysAndNames[i]; if (previousLabelKeysAndNames.size() != labelKeysAndNames.size()) { needToGenerateKeys = true; break; } else { std::map::const_iterator prevIter = previousLabelKeysAndNames.begin(); for (std::map::const_iterator labelIter = labelKeysAndNames.begin(); labelIter != labelKeysAndNames.end(); labelIter++) { if (prevIter->first != labelIter->first) { needToGenerateKeys = true; break; } else if (prevIter->second != labelIter->second) { needToGenerateKeys = true; break; } prevIter++; } } } } } } if (needToGenerateKeys) { //const int32_t ID_NOT_USED = 0; /* * Save keys and names for comparison in next update test */ const int numMaps = volumeFile->getNumberOfMaps(); m_previousCiftiLabelFileMapKeysAndNames = labelMapKeysAndNames; if (m_previousCiftiLabelFileMapKeysAndNames.empty()) { for (int32_t i = 0; i < numMaps; i++) { const GiftiLabelTable* labelTable = volumeFile->getMapLabelTable(i); std::map labelKeysAndNames; labelTable->getKeysAndNames(labelKeysAndNames); m_previousCiftiLabelFileMapKeysAndNames.push_back(labelKeysAndNames); } } /* * Clear everything */ this->clear(); /* * Update with labels from maps */ for (int32_t iMap = 0; iMap < numMaps; iMap++) { /* * The label table */ GiftiLabelTable* labelTable = volumeFile->getMapLabelTable(iMap); /* * Get the group. If it is empty, use the default name. */ AString theGroupName = volumeFile->getMapName(iMap); if (theGroupName.isEmpty()) { theGroupName = missingGroupName; } /* * Find/create group */ GroupAndNameHierarchyItem* groupItem = addChild(GroupAndNameHierarchyItem::ITEM_TYPE_GROUP, theGroupName, iMap); CaretAssert(groupItem); /* * Get indices of labels used in this map */ std::vector labelKeys = volumeFile->getUniqueLabelKeysUsedInMap(iMap); const int32_t numLabelKeys = static_cast(labelKeys.size()); for (int32_t iLabel = 0; iLabel < numLabelKeys; iLabel++) { const int32_t labelKey = labelKeys[iLabel]; GiftiLabel* label = labelTable->getLabel(labelKey); if (label == NULL) { continue; } AString labelName = label->getName(); if (labelName.isEmpty()) { labelName = missingName; } float rgba[4]; label->getColor(rgba); /* * Adding focus to class */ GroupAndNameHierarchyItem* nameItem = groupItem->addChild(GroupAndNameHierarchyItem::ITEM_TYPE_NAME, labelName, labelKey); nameItem->setIconColorRGBA(rgba); /* * Place the name selector into the label. */ label->setGroupNameSelectionItem(nameItem); } } /* * Sort names in each group */ std::vector groups = getChildren(); for (std::vector::iterator iter = groups.begin(); iter != groups.end(); iter++) { GroupAndNameHierarchyItem* nameItem = *iter; nameItem->sortDescendantsByName(); } setUserInterfaceUpdateNeeded(); CaretLogFine("LABEL HIERARCHY:" + toString()); } } /** * Update this group hierarchy with the foci names * and groups. * * @param fociFile * The foci file from which classes and names are from. * @parm forceUpdate * If true, force an update. */ void GroupAndNameHierarchyModel::update(FociFile* fociFile, const bool forceUpdate) { bool needToGenerateKeys = forceUpdate; setName(fociFile->getFileNameNoPath()); const int32_t numFoci = fociFile->getNumberOfFoci(); if (needToGenerateKeys == false) { for (int32_t i = 0; i < numFoci; i++) { const Focus* focus = fociFile->getFocus(i); if (focus->getGroupNameSelectionItem() == NULL) { needToGenerateKeys = true; } } } /* * ID for groups and names is not used */ const int32_t ID_NOT_USED = 0; if (needToGenerateKeys) { /* * Names for missing group names or foci names. */ const AString missingGroupName = "NoGroup"; const AString missingName = "NoName"; /* * Reset the counts for all group and children names. */ clearCounters(); /* * For icons */ const GiftiLabelTable* classLabelTable = fociFile->getClassColorTable(); const GiftiLabelTable* nameLabelTable = fociFile->getNameColorTable(); const float rgbaBlack[4] = { 0.0, 0.0, 0.0, 1.0 }; /* * Update with all foci. */ for (int32_t i = 0; i < numFoci; i++) { Focus* focus = fociFile->getFocus(i); /* * Get the group. If it is empty, use the default name. */ AString theGroupName = focus->getClassName(); if (theGroupName.isEmpty()) { theGroupName = missingGroupName; } /* * Get the name. */ AString name = focus->getName(); if (name.isEmpty()) { name = missingName; } /* * Class */ GroupAndNameHierarchyItem* groupItem = addChild(GroupAndNameHierarchyItem::ITEM_TYPE_GROUP, theGroupName, ID_NOT_USED); CaretAssert(groupItem); CaretAssert(groupItem); const GiftiLabel* groupLabel = classLabelTable->getLabelBestMatching(theGroupName); if (groupLabel != NULL) { float rgba[4]; groupLabel->getColor(rgba); groupItem->setIconColorRGBA(rgba); } else { groupItem->setIconColorRGBA(rgbaBlack); } /* * Name */ GroupAndNameHierarchyItem* nameItem = groupItem->addChild(GroupAndNameHierarchyItem::ITEM_TYPE_NAME, name, ID_NOT_USED); const GiftiLabel* nameLabel = nameLabelTable->getLabelBestMatching(name); if (nameLabel != NULL) { float rgba[4]; nameLabel->getColor(rgba); nameItem->setIconColorRGBA(rgba); } else { nameItem->setIconColorRGBA(rgbaBlack); } /* * Place the name selector into the border. */ focus->setGroupNameSelectionItem(nameItem); } removeDescendantsWithCountersEqualToZeros(); sortDescendantsByName(); setUserInterfaceUpdateNeeded(); CaretLogFine("FOCI HIERARCHY:" + toString()); } } /** * Is a User-Interface needed in the given display group and tab? * This occurs when the hierarchy has changed (group and name). * After calling this method, the status for the display group/tab is cleared. * * @param displayGroup * Display group. * @param tabIndex * Index of tab. * @return True if update needed, else false. */ bool GroupAndNameHierarchyModel::needsUserInterfaceUpdate(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const { bool needUpdate = false; const int32_t displayIndex = (int32_t)displayGroup; CaretAssertArrayIndex(this->expandedStatusInDisplayGroup, DisplayGroupEnum::NUMBER_OF_GROUPS, displayIndex); if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssertArrayIndex(this->expandedStatusInTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); needUpdate = m_updateNeededInTab[tabIndex]; m_updateNeededInTab[tabIndex] = false; } else { needUpdate = m_updateNeededInDisplayGroupAndTab[displayIndex][tabIndex]; m_updateNeededInDisplayGroupAndTab[displayIndex][tabIndex] = false; } return needUpdate; } /** * Set user interface updates needed. */ void GroupAndNameHierarchyModel::setUserInterfaceUpdateNeeded() { for (int32_t i = 0; i < DisplayGroupEnum::NUMBER_OF_GROUPS; i++) { for (int32_t j = 0; j < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; j++) { m_updateNeededInDisplayGroupAndTab[i][j] = true; } } for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_updateNeededInTab[i] = true; } } connectome-workbench-1.4.2/src/Files/GroupAndNameHierarchyModel.h000066400000000000000000000073201360521144700247770ustar00rootroot00000000000000#ifndef __CLASS_AND_NAME_HIERARCHY_MODEL_H_ #define __CLASS_AND_NAME_HIERARCHY_MODEL_H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "GroupAndNameHierarchyItem.h" #include "GroupAndNameCheckStateEnum.h" namespace caret { class BorderFile; class CiftiMappableDataFile; class FociFile; class LabelFile; class VolumeFile; class GroupAndNameHierarchyModel : public GroupAndNameHierarchyItem { public: GroupAndNameHierarchyModel(); virtual ~GroupAndNameHierarchyModel(); virtual void clear(); bool isGroupValid(const int32_t groupKey) const; void setAllSelected(const bool status); void setAllSelected(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool status); void update(BorderFile* borderFile, const bool forceUpdate); void update(FociFile* fociFile, const bool forceUpdate); void update(LabelFile* labelFile, const bool forceUpdate); void update(CiftiMappableDataFile* ciftiMappableDataFile, const bool forceUpdate); void update(VolumeFile* volumeFile, const bool forceUpdate); bool needsUserInterfaceUpdate(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) const; private: GroupAndNameHierarchyModel(const GroupAndNameHierarchyModel&); GroupAndNameHierarchyModel& operator=(const GroupAndNameHierarchyModel&); void clearModelPrivate(); void setUserInterfaceUpdateNeeded(); /** * Contains label keys and names from previous update with Label File. */ std::map m_previousLabelFileKeysAndNames; /** * Contains label keys and names from previous update with CIFTI label file. */ std::vector > m_previousCiftiLabelFileMapKeysAndNames; /** * Update needed status of DISPLAY GROUP in EACH TAB. * Used when user has set to a display group. * Indicates that an update is needed for the given display group in the given tab. */ mutable bool m_updateNeededInDisplayGroupAndTab[DisplayGroupEnum::NUMBER_OF_GROUPS][BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** * Update needed in TAB. */ mutable bool m_updateNeededInTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; }; #ifdef __CLASS_AND_NAME_HIERARCHY_MODEL_DECLARE__ // #endif // __CLASS_AND_NAME_HIERARCHY_MODEL_DECLARE__ } // namespace #endif //__CLASS_AND_NAME_HIERARCHY_MODEL_H_ connectome-workbench-1.4.2/src/Files/GroupAndNameHierarchyName.cxx000066400000000000000000000035621360521144700251760ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CLASS_AND_NAME_HIERARCHY_NAME_DECLARE__ #include "GroupAndNameHierarchyName.h" #undef __CLASS_AND_NAME_HIERARCHY_NAME_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::GroupAndNameHierarchyName * \brief Maintains selection of a name in each 'DisplayGroupEnum'. * * Methods that operate on a boolean value are used to query and set * the selected status. A separate method is provided to query * the 'check state'. The 'check state' may be unchecked, checked, or * partially checked (some children checked but not all). */ /** * Constructor. * @param name * The name. * @param idNumber * ID number assigned to the name. */ GroupAndNameHierarchyName::GroupAndNameHierarchyName(const AString& name, const int32_t idNumber) : GroupAndNameHierarchyItem(GroupAndNameHierarchyItem::ITEM_TYPE_NAME, name, idNumber) { } /** * Destructor. */ GroupAndNameHierarchyName::~GroupAndNameHierarchyName() { } connectome-workbench-1.4.2/src/Files/GroupAndNameHierarchyName.h000066400000000000000000000032651360521144700246230ustar00rootroot00000000000000#ifndef __CLASS_AND_NAME_HIERARCHY_NAME__H_ #define __CLASS_AND_NAME_HIERARCHY_NAME__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "GroupAndNameHierarchyItem.h" namespace caret { class GroupAndNameHierarchyName : public GroupAndNameHierarchyItem { public: GroupAndNameHierarchyName(const AString& name, const int32_t idNumber); ~GroupAndNameHierarchyName(); // ADD_NEW_METHODS_HERE private: GroupAndNameHierarchyName(const GroupAndNameHierarchyName&); GroupAndNameHierarchyName& operator=(const GroupAndNameHierarchyName&); // ADD_NEW_MEMBERS_HERE }; #ifdef __CLASS_AND_NAME_HIERARCHY_NAME_DECLARE__ // #endif // __CLASS_AND_NAME_HIERARCHY_NAME_DECLARE__ } // namespace #endif //__CLASS_AND_NAME_HIERARCHY_NAME__H_ connectome-workbench-1.4.2/src/Files/ImageCaptureDimensionsModeEnum.cxx000066400000000000000000000262061360521144700262470ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __IMAGE_CAPTURE_DIMENSIONS_MODE_ENUM_DECLARE__ #include "ImageCaptureDimensionsModeEnum.h" #undef __IMAGE_CAPTURE_DIMENSIONS_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ImageCaptureDimensionsModeEnum * \brief * * * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_imageCaptureDimensionsModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void imageCaptureDimensionsModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ImageCaptureDimensionsModeEnum.h" * * Instatiate: * m_imageCaptureDimensionsModeEnumComboBox = new EnumComboBoxTemplate(this); * m_imageCaptureDimensionsModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_imageCaptureDimensionsModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(imageCaptureDimensionsModeEnumComboBoxItemActivated())); * * Update the selection: * m_imageCaptureDimensionsModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ImageCaptureDimensionsModeEnum::Enum VARIABLE = m_imageCaptureDimensionsModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ImageCaptureDimensionsModeEnum::ImageCaptureDimensionsModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ImageCaptureDimensionsModeEnum::~ImageCaptureDimensionsModeEnum() { } /** * Initialize the enumerated metadata. */ void ImageCaptureDimensionsModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ImageCaptureDimensionsModeEnum(IMAGE_CAPTURE_DIMENSIONS_MODE_CUSTOM, "IMAGE_CAPTURE_DIMENSIONS_MODE_CUSTOM", "")); enumData.push_back(ImageCaptureDimensionsModeEnum(IMAGE_CAPTURE_DIMENSIONS_MODE_WINDOW_SIZE, "IMAGE_CAPTURE_DIMENSIONS_MODE_WINDOW_SIZE", "")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ImageCaptureDimensionsModeEnum* ImageCaptureDimensionsModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ImageCaptureDimensionsModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ImageCaptureDimensionsModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ImageCaptureDimensionsModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ImageCaptureDimensionsModeEnum::Enum ImageCaptureDimensionsModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ImageCaptureDimensionsModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ImageCaptureDimensionsModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ImageCaptureDimensionsModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ImageCaptureDimensionsModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ImageCaptureDimensionsModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ImageCaptureDimensionsModeEnum::Enum ImageCaptureDimensionsModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ImageCaptureDimensionsModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ImageCaptureDimensionsModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ImageCaptureDimensionsModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ImageCaptureDimensionsModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ImageCaptureDimensionsModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ImageCaptureDimensionsModeEnum::Enum ImageCaptureDimensionsModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ImageCaptureDimensionsModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ImageCaptureDimensionsModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ImageCaptureDimensionsModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ImageCaptureDimensionsModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ImageCaptureDimensionsModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ImageCaptureDimensionsModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ImageCaptureDimensionsModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ImageCaptureDimensionsModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Files/ImageCaptureDimensionsModeEnum.h000066400000000000000000000063701360521144700256740ustar00rootroot00000000000000#ifndef __IMAGE_CAPTURE_DIMENSIONS_MODE_ENUM_H__ #define __IMAGE_CAPTURE_DIMENSIONS_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ImageCaptureDimensionsModeEnum { public: /** * Enumerated values. */ enum Enum { /** */ IMAGE_CAPTURE_DIMENSIONS_MODE_CUSTOM, /** */ IMAGE_CAPTURE_DIMENSIONS_MODE_WINDOW_SIZE }; ~ImageCaptureDimensionsModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ImageCaptureDimensionsModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ImageCaptureDimensionsModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __IMAGE_CAPTURE_DIMENSIONS_MODE_ENUM_DECLARE__ std::vector ImageCaptureDimensionsModeEnum::enumData; bool ImageCaptureDimensionsModeEnum::initializedFlag = false; int32_t ImageCaptureDimensionsModeEnum::integerCodeCounter = 0; #endif // __IMAGE_CAPTURE_DIMENSIONS_MODE_ENUM_DECLARE__ } // namespace #endif //__IMAGE_CAPTURE_DIMENSIONS_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Files/ImageCaptureSettings.cxx000066400000000000000000000476661360521144700243220ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __IMAGE_CAPTURE_SETTINGS_DECLARE__ #include "ImageCaptureSettings.h" #undef __IMAGE_CAPTURE_SETTINGS_DECLARE__ #include "CaretAssert.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ImageCaptureSettings * \brief Image capture properties * \ingroup Files * * Allows one to adjust dimensions for both pixels and spatial units. * Internally, spatial processing is in centimeters. */ /** * Constructor. */ ImageCaptureSettings::ImageCaptureSettings() : CaretObject(), SceneableInterface() { m_aspectRatio = 1.0; m_pixelsPerCentimeter = 72.0 / CENTIMETERS_PER_INCH; m_croppingEnabled = false; m_croppingMargin = 10; m_copyToClipboardEnabled = true; m_saveToFileEnabled = false; m_scaleProportionatelyEnabled = true; m_imageFileName = "untitled.png"; m_cropToTabWindowLockAspectRegionEnabled = true; m_dimensionsMode = ImageCaptureDimensionsModeEnum::IMAGE_CAPTURE_DIMENSIONS_MODE_WINDOW_SIZE; m_imageResolutionUnits = ImageResolutionUnitsEnum::PIXELS_PER_INCH; m_spatialUnits = ImageSpatialUnitsEnum::INCHES; setPixelWidthAndHeight(512, 512); /* WB-868 Defautl Custom, 300 DPI, 7.5 inches width, copy to clipboard OFF, save to file ON, no file name*/ m_dimensionsMode = ImageCaptureDimensionsModeEnum::IMAGE_CAPTURE_DIMENSIONS_MODE_CUSTOM; setImageResolutionInSelectedUnits(300.0); setSpatialWidth(7.5); m_saveToFileEnabled = true; m_copyToClipboardEnabled = false; m_imageFileName = ""; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_pixelWidth", &m_pixelWidth); m_sceneAssistant->add("m_pixelHeight", &m_pixelHeight); m_sceneAssistant->add("m_centimetersWidth", &m_centimetersWidth); m_sceneAssistant->add("m_centimetersHeight", &m_centimetersHeight); m_sceneAssistant->add("m_pixelsPerCentimeter", &m_pixelsPerCentimeter); m_sceneAssistant->add("m_aspectRatio", &m_aspectRatio); m_sceneAssistant->add("m_croppingEnabled", &m_croppingEnabled); m_sceneAssistant->add("m_croppingMargin", &m_croppingMargin); m_sceneAssistant->add("m_copyToClipboardEnabled", &m_copyToClipboardEnabled); m_sceneAssistant->add("m_saveToFileEnabled", &m_saveToFileEnabled); m_sceneAssistant->add("m_scaleProportionatelyEnabled", &m_scaleProportionatelyEnabled); m_sceneAssistant->add("m_cropToTabWindowLockAspectRegionEnabled", &m_cropToTabWindowLockAspectRegionEnabled); m_sceneAssistant->add("m_dimensionsMode", &m_dimensionsMode); m_sceneAssistant->add("m_imageResolutionUnits", &m_imageResolutionUnits); m_sceneAssistant->add("m_spatialUnits", &m_spatialUnits); } /** * Destructor. */ ImageCaptureSettings::~ImageCaptureSettings() { delete m_sceneAssistant; } /** * Copy constructor. * @param obj * Object that is copied. */ ImageCaptureSettings::ImageCaptureSettings(const ImageCaptureSettings& obj) : CaretObject(obj), SceneableInterface(obj) { this->copyHelperImageDimensionsModel(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ImageCaptureSettings& ImageCaptureSettings::operator=(const ImageCaptureSettings& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperImageDimensionsModel(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ImageCaptureSettings::copyHelperImageDimensionsModel(const ImageCaptureSettings& obj) { m_pixelWidth = obj.m_pixelWidth; m_pixelHeight = obj.m_pixelHeight; m_centimetersWidth = obj.m_centimetersWidth; m_centimetersHeight = obj.m_centimetersHeight; m_pixelsPerCentimeter = obj.m_pixelsPerCentimeter; m_aspectRatio = obj.m_aspectRatio; m_scaleProportionatelyEnabled = obj.m_scaleProportionatelyEnabled; m_croppingMargin = obj.m_croppingMargin; m_croppingEnabled = obj.m_croppingEnabled; m_copyToClipboardEnabled = obj.m_copyToClipboardEnabled; m_saveToFileEnabled = obj.m_saveToFileEnabled; m_imageFileName = obj.m_imageFileName; m_dimensionsMode = obj.m_dimensionsMode; m_imageResolutionUnits = obj.m_imageResolutionUnits; m_spatialUnits = obj.m_spatialUnits; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString ImageCaptureSettings::toString() const { return "ImageCaptureSettings"; } /** * @return The width in pixels. */ int32_t ImageCaptureSettings::getPixelWidth() const { /* * Internally, pixels are float, so round (by adding 0.5) * and return as integer. */ return static_cast(m_pixelWidth + 0.5); } /** * @return The height in pixels. */ int32_t ImageCaptureSettings::getPixelHeight() const { /* * Internally, pixels are float, so round (by adding 0.5) * and return as integer. */ return static_cast(m_pixelHeight + 0.5); } /** * Get the spatial width. * * @return * Width in spatial units. */ float ImageCaptureSettings::getSpatialWidth() const { float width = 1.0; switch (m_spatialUnits) { case ImageSpatialUnitsEnum::CENTIMETERS: width = m_centimetersWidth; break; case ImageSpatialUnitsEnum::INCHES: width = m_centimetersWidth / CENTIMETERS_PER_INCH; break; case ImageSpatialUnitsEnum::MILLIMETERS: width = m_centimetersWidth * MILLIMETERS_PER_CENTIMETER; break; } return width; } /** * Get the spatial height. * * @return * Height in spatial units. */ float ImageCaptureSettings::getSpatialHeight() const { float height = 1.0; switch (m_spatialUnits) { case ImageSpatialUnitsEnum::CENTIMETERS: height = m_centimetersHeight; break; case ImageSpatialUnitsEnum::INCHES: height = m_centimetersHeight / CENTIMETERS_PER_INCH; break; case ImageSpatialUnitsEnum::MILLIMETERS: height = m_centimetersHeight * MILLIMETERS_PER_CENTIMETER; break; } return height; } /** * Get the image resolution (number of pixels per given spatial unit). * * @return * Number of pixels per spatial unit. */ float ImageCaptureSettings::getImageResolutionInCentimeters() const { return m_pixelsPerCentimeter; } /** * Get the image resolution in the selected units * * @return * Number of pixels per selected resolution unit. */ float ImageCaptureSettings::getImageResolutionInSelectedUnits() const { float pixelsPerUnit = 1.0; switch (m_imageResolutionUnits) { case ImageResolutionUnitsEnum::PIXEL_PER_CENTIMETER: pixelsPerUnit = m_pixelsPerCentimeter; break; case ImageResolutionUnitsEnum::PIXELS_PER_INCH: pixelsPerUnit = m_pixelsPerCentimeter * CENTIMETERS_PER_INCH; break; } return pixelsPerUnit; } /** * Set the width and height of the image in pixels. * * @param pixelWidth * New pixel width. * @param pixelHeight * New pixel height. */ void ImageCaptureSettings::setPixelWidthAndHeight(const int32_t pixelWidth, const int32_t pixelHeight) { CaretAssert(pixelWidth > 0); CaretAssert(pixelHeight > 0); m_pixelWidth = pixelWidth; m_pixelHeight = pixelHeight; updateSpatialWidthAndHeightFromPixelWidthAndHeight(); } /** * Set the pixel width to the given width. * Width may change if proportionate scaling is enabled. * * @param pixelWidth * New pixel width. */ void ImageCaptureSettings::setPixelWidth(const int32_t pixelWidth) { CaretAssert(pixelWidth > 0); const float aspectRatio = getAspectRatio(); m_pixelWidth = pixelWidth; if (m_scaleProportionatelyEnabled) { m_pixelHeight = m_pixelWidth * aspectRatio; } updateSpatialWidthAndHeightFromPixelWidthAndHeight(); } /** * Set the pixel height to the given height. * Width may change if proportionate scaling is enabled. * * @param pixelHeight * New pixel height. */ void ImageCaptureSettings::setPixelHeight(const int32_t pixelHeight) { CaretAssert(pixelHeight > 0); const float aspectRatio = getAspectRatio(); m_pixelHeight = pixelHeight; if (m_scaleProportionatelyEnabled) { m_pixelWidth = m_pixelHeight / aspectRatio; } updateSpatialWidthAndHeightFromPixelWidthAndHeight(); } /** * Set the spatial width to the given width. * Height may change if proportionate scaling is enabled. * * @param spatialWidth * New spatial width. */ void ImageCaptureSettings::setSpatialWidth(const float spatialWidth) { CaretAssert(spatialWidth > 0); const float aspectRatio = getAspectRatio(); switch (m_spatialUnits) { case ImageSpatialUnitsEnum::MILLIMETERS: m_centimetersWidth = spatialWidth / MILLIMETERS_PER_CENTIMETER; break; case ImageSpatialUnitsEnum::INCHES: m_centimetersWidth = spatialWidth * CENTIMETERS_PER_INCH; break; case ImageSpatialUnitsEnum::CENTIMETERS: m_centimetersWidth = spatialWidth; break; } if (m_scaleProportionatelyEnabled) { m_centimetersHeight = m_centimetersWidth * aspectRatio; } updatePixelWidthAndHeightFromSpatialWidthAndHeight(); } /** * Set the spatial height to the given height. * Width may change if proportionate scaling is enabled. * * @param spatialHeight * New spatial height. */ void ImageCaptureSettings::setSpatialHeight(const float spatialHeight) { CaretAssert(spatialHeight > 0); const float aspectRatio = getAspectRatio(); switch (m_spatialUnits) { case ImageSpatialUnitsEnum::MILLIMETERS: m_centimetersHeight = spatialHeight / MILLIMETERS_PER_CENTIMETER; break; case ImageSpatialUnitsEnum::INCHES: m_centimetersHeight = spatialHeight * CENTIMETERS_PER_INCH; break; case ImageSpatialUnitsEnum::CENTIMETERS: m_centimetersHeight = spatialHeight; break; } if (m_scaleProportionatelyEnabled) { m_centimetersWidth = m_centimetersHeight / aspectRatio; } updatePixelWidthAndHeightFromSpatialWidthAndHeight(); } /** * Set the image resolution (number of pixels per spatial unit to the given value). * * @param imageResolutionInSelectedUnits * New value for number of pixels per selected resolution unit */ void ImageCaptureSettings::setImageResolutionInSelectedUnits(const float imageResolutionInSelectedUnits) { CaretAssert(imageResolutionInSelectedUnits > 0); switch (m_imageResolutionUnits) { case ImageResolutionUnitsEnum::PIXELS_PER_INCH: m_pixelsPerCentimeter = imageResolutionInSelectedUnits / CENTIMETERS_PER_INCH; break; case ImageResolutionUnitsEnum::PIXEL_PER_CENTIMETER: m_pixelsPerCentimeter = imageResolutionInSelectedUnits; break; } updatePixelWidthAndHeightFromSpatialWidthAndHeight(); } /** * Update the pixel width and height after a change to the spatial width * and/or height. */ void ImageCaptureSettings::updatePixelWidthAndHeightFromSpatialWidthAndHeight() { m_pixelWidth = m_centimetersWidth * m_pixelsPerCentimeter; m_pixelHeight = m_centimetersHeight * m_pixelsPerCentimeter; } /** * Update the spatial width and height after a change to the pixel width * and/or height. */ void ImageCaptureSettings::updateSpatialWidthAndHeightFromPixelWidthAndHeight() { m_centimetersWidth = m_pixelWidth / m_pixelsPerCentimeter; m_centimetersHeight = m_pixelHeight / m_pixelsPerCentimeter; } /** * @return the aspect ration (height / width). */ float ImageCaptureSettings::getAspectRatio() const { return m_aspectRatio; } /** * Update the pixel and image dimensions for the aspect ratio * determined by the given width and height. Aspect ratio * is (height / width) and the height will be changed using * the aspect ratio. * * @param width * Width used in denominator of aspect ratio. * @param height * Height used in numerator of aspect ratio. */ void ImageCaptureSettings::updateForAspectRatio(const float width, const float height) { if ((width > 0.0) && (height > 0.0)) { m_aspectRatio = height / width; m_pixelHeight = m_aspectRatio * m_pixelWidth; updateSpatialWidthAndHeightFromPixelWidthAndHeight(); } } /** * @return The cropping margin. */ int32_t ImageCaptureSettings::getCroppingMargin() const { return m_croppingMargin; } /** * Set the cropping margin. * * @param croppingMargin * New cropping margin. */ void ImageCaptureSettings::setCroppingMargin(const int32_t croppingMargin) { m_croppingMargin = croppingMargin; } /** * @return Is cropping enabled? */ bool ImageCaptureSettings::isCroppingEnabled() const { return m_croppingEnabled; } /** * Set cropping enabled. * * @param enabled * New enabled status. */ void ImageCaptureSettings::setCroppingEnabled(const bool enabled) { m_croppingEnabled = enabled; } /** * @return Is copy to clipboard enabled? */ bool ImageCaptureSettings::isCopyToClipboardEnabled() const { return m_copyToClipboardEnabled; } /** * Set copy to clipboard enabled. * * @param enabled * New enabled status. */ void ImageCaptureSettings::setCopyToClipboardEnabled(const bool enabled) { m_copyToClipboardEnabled = enabled; } /** * @return Is save to file enabled? */ bool ImageCaptureSettings::isSaveToFileEnabled() const { return m_saveToFileEnabled; } /** * Set save to file enabled. * * @param enabled * New enabled status. */ void ImageCaptureSettings::setSaveToFileEnabled(const bool enabled) { m_saveToFileEnabled = enabled; } /** * @return Image file name */ AString ImageCaptureSettings::getImageFileName() const { return m_imageFileName; } /** * @return Is scale proportionately enabled? */ bool ImageCaptureSettings::isScaleProportionately() const { return m_scaleProportionatelyEnabled; } /** * Set scale proportionately enabled. * * @param enabled * New enabled status. */ void ImageCaptureSettings::setScaleProportionately(const bool enabled) { m_scaleProportionatelyEnabled = enabled; } /** * Set the image file name. * * @param filename * Name for image file. */ void ImageCaptureSettings::setImageFileName(const AString& filename) { m_imageFileName = filename; } /** * @return Image dimensions mode */ ImageCaptureDimensionsModeEnum::Enum ImageCaptureSettings::getImageCaptureDimensionsMode() const { return m_dimensionsMode; } /** * @return Image resolution units */ ImageResolutionUnitsEnum::Enum ImageCaptureSettings::getImageResolutionUnits() const { return m_imageResolutionUnits; } /** * Set the image resolution units * * @param imageResolutionUnits * New value for image resolution units */ void ImageCaptureSettings::setImageResolutionUnits(const ImageResolutionUnitsEnum::Enum imageResolutionUnits) { m_imageResolutionUnits = imageResolutionUnits; updateSpatialWidthAndHeightFromPixelWidthAndHeight(); } /** * @return The spatial units. */ ImageSpatialUnitsEnum::Enum ImageCaptureSettings::getSpatialUnits() const { return m_spatialUnits; } /** * Set the spatial units. * * @param spatialUnits * New value for spatial units. */ void ImageCaptureSettings::setSpatialUnits(const ImageSpatialUnitsEnum::Enum spatialUnits) { m_spatialUnits = spatialUnits; updatePixelWidthAndHeightFromSpatialWidthAndHeight(); } /** * Set the image dimensions mode. * * @param mode * New mode. */ void ImageCaptureSettings::setImageCaptureDimensionsMode(const ImageCaptureDimensionsModeEnum::Enum mode) { m_dimensionsMode = mode; } /** * @param Is crop to tab/window lock aspect ratio enabled? */ bool ImageCaptureSettings::isCropToTabWindowLockAspectRegionEnabled() const { return m_cropToTabWindowLockAspectRegionEnabled; } /** * Set crop to tab/window lock aspect ratio enabled. * * @param enabled * New status. */ void ImageCaptureSettings::setCropToTabWindowLockAspectRegionEnabled(const bool enabled) { m_cropToTabWindowLockAspectRegionEnabled = enabled; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* ImageCaptureSettings::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ImageCaptureSettings", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); sceneClass->addPathName("m_imageFileName", m_imageFileName); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ImageCaptureSettings::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); m_imageFileName = sceneClass->getPathNameValue("m_imageFileName", "untitled.png"); //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Files/ImageCaptureSettings.h000066400000000000000000000145201360521144700237260ustar00rootroot00000000000000#ifndef __IMAGE_CAPTURE_SETTINGS_H__ #define __IMAGE_CAPTURE_SETTINGS_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "ImageCaptureDimensionsModeEnum.h" #include "ImageResolutionUnitsEnum.h" #include "ImageSpatialUnitsEnum.h" #include "SceneableInterface.h" namespace caret { class SceneClassAssistant; class ImageCaptureSettings : public CaretObject, public SceneableInterface { public: ImageCaptureSettings(); virtual ~ImageCaptureSettings(); ImageCaptureSettings(const ImageCaptureSettings& obj); ImageCaptureSettings& operator=(const ImageCaptureSettings& obj); int32_t getPixelWidth() const; int32_t getPixelHeight() const; float getSpatialWidth() const; float getSpatialHeight() const; float getImageResolutionInCentimeters() const; float getImageResolutionInSelectedUnits() const; void setPixelWidthAndHeight(const int32_t pixelWidth, const int32_t pixelHeight); void setPixelWidth(const int32_t pixelWidth); void setPixelHeight(const int32_t pixelHeight); void setSpatialWidth(const float spatialWidth); void setSpatialHeight(const float spatialHeight); void setImageResolutionInSelectedUnits(const float imageResolutionInSelectedUnits); void updateForAspectRatio(const float width, const float height); int32_t getCroppingMargin() const; void setCroppingMargin(const int32_t croppingMargin); bool isCroppingEnabled() const; void setCroppingEnabled(const bool enabled); bool isCopyToClipboardEnabled() const; void setCopyToClipboardEnabled(const bool enabled); bool isSaveToFileEnabled() const; void setSaveToFileEnabled(const bool enabled); AString getImageFileName() const; void setImageFileName(const AString& filename); ImageCaptureDimensionsModeEnum::Enum getImageCaptureDimensionsMode() const; void setImageCaptureDimensionsMode(const ImageCaptureDimensionsModeEnum::Enum mode); ImageResolutionUnitsEnum::Enum getImageResolutionUnits() const; void setImageResolutionUnits(const ImageResolutionUnitsEnum::Enum imageResolutionUnits); ImageSpatialUnitsEnum::Enum getSpatialUnits() const; void setSpatialUnits(const ImageSpatialUnitsEnum::Enum spatialUnits); bool isScaleProportionately() const; void setScaleProportionately(const bool enabled); bool isCropToTabWindowLockAspectRegionEnabled() const; void setCropToTabWindowLockAspectRegionEnabled(const bool enabled); // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implemetation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: void copyHelperImageDimensionsModel(const ImageCaptureSettings& obj); SceneClassAssistant* m_sceneAssistant; void updatePixelWidthAndHeightFromSpatialWidthAndHeight(); void updateSpatialWidthAndHeightFromPixelWidthAndHeight(); float getAspectRatio() const; // ADD_NEW_MEMBERS_HERE /** * Width/height of pixels are float. Otherwise, small changes in * pixel dimensions will get lost (truncated). */ float m_pixelWidth; float m_pixelHeight; float m_centimetersWidth; float m_centimetersHeight; float m_pixelsPerCentimeter; float m_aspectRatio; bool m_scaleProportionatelyEnabled; int32_t m_croppingMargin; bool m_croppingEnabled; bool m_copyToClipboardEnabled; bool m_saveToFileEnabled; AString m_imageFileName; bool m_cropToTabWindowLockAspectRegionEnabled; ImageCaptureDimensionsModeEnum::Enum m_dimensionsMode; ImageResolutionUnitsEnum::Enum m_imageResolutionUnits; ImageSpatialUnitsEnum::Enum m_spatialUnits; static const float CENTIMETERS_PER_INCH; static const float MILLIMETERS_PER_CENTIMETER; }; #ifdef __IMAGE_CAPTURE_SETTINGS_DECLARE__ const float ImageCaptureSettings::CENTIMETERS_PER_INCH = 2.54; const float ImageCaptureSettings::MILLIMETERS_PER_CENTIMETER = 10.0; #endif // __IMAGE_CAPTURE_SETTINGS_DECLARE__ } // namespace #endif //__IMAGE_CAPTURE_SETTINGS_H__ connectome-workbench-1.4.2/src/Files/ImageFile.cxx000066400000000000000000001450021360521144700220340ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "ControlPointFile.h" #include "ControlPoint3D.h" #include "DataFileException.h" #include "FileInformation.h" #include "GiftiMetaData.h" #include "ImageCaptureSettings.h" #include "ImageFile.h" #include "Matrix4x4.h" #include "MathFunctions.h" #include "SceneClass.h" #include "VolumeFile.h" using namespace caret; const float ImageFile::s_defaultWindowDepthPercentage = 990; /** * Constructor. */ ImageFile::ImageFile() : CaretDataFile(DataFileTypeEnum::IMAGE) { m_controlPointFile.grabNew(new ControlPointFile()); m_fileMetaData.grabNew(new GiftiMetaData()); m_image = new QImage(); } /** * Constructor * @param qimage * QImage that is copied to this image file. */ ImageFile::ImageFile(const QImage& qimage) : CaretDataFile(DataFileTypeEnum::IMAGE) { m_controlPointFile.grabNew(new ControlPointFile()); m_fileMetaData.grabNew(new GiftiMetaData()); m_image = new QImage(qimage); } /** * Constructs an image file from image data. * * @param imageDataRGBA * Image data unsigned bytes with one byte for each * red, green, blue, alpha. * @param imageWidth * Width of image. * @param imageHeight * Height of image. * @param imageOrigin * Location of first pixel in the image data. */ ImageFile::ImageFile(const unsigned char* imageDataRGBA, const int imageWidth, const int imageHeight, const IMAGE_DATA_ORIGIN_LOCATION imageOrigin) : CaretDataFile(DataFileTypeEnum::IMAGE) { m_controlPointFile.grabNew(new ControlPointFile()); m_fileMetaData.grabNew(new GiftiMetaData()); m_image = new QImage(imageWidth, imageHeight, QImage::Format_RGB32); bool isOriginAtTop = false; switch (imageOrigin) { case IMAGE_DATA_ORIGIN_AT_BOTTOM: isOriginAtTop = false; break; case IMAGE_DATA_ORIGIN_AT_TOP: isOriginAtTop = true; break; } /* * Documentation for QImage states that setPixel may be very costly * and recommends using the scanLine() method to access pixel data. */ for (int y = 0; y < imageHeight; y++) { const int scanLineIndex = (isOriginAtTop ? y : imageHeight -y - 1); QRgb* rgbScanLine = (QRgb*)m_image->scanLine(scanLineIndex); for (int x = 0; x < imageWidth; x++) { const int32_t contentOffset = (((y * imageWidth) * 4) + (x * 4)); const int red = imageDataRGBA[contentOffset]; const int green = imageDataRGBA[contentOffset+1]; const int blue = imageDataRGBA[contentOffset+2]; const int alpha = imageDataRGBA[contentOffset+3]; QColor color(red, green, blue, alpha); QRgb* pixel = &rgbScanLine[x]; *pixel = color.rgba(); } } } /** * Destructor. */ ImageFile::~ImageFile() { if (m_image != NULL) { delete m_image; m_image = NULL; } } /** * Clears current file data in memory. */ void ImageFile::clear() { if (m_image != NULL) { delete m_image; } m_image = new QImage(); this->clearModified(); } /** * @return The structure for this file. */ StructureEnum::Enum ImageFile::getStructure() const { return StructureEnum::INVALID; } /** * Set the structure for this file. * @param structure * New structure for this file. */ void ImageFile::setStructure(const StructureEnum::Enum /*structure */) { /* File does not support structures */ } /** * @return Get access to the file's metadata. */ GiftiMetaData* ImageFile::getFileMetaData() { return m_fileMetaData; } /** * @return Get access to unmodifiable file's metadata. */ const GiftiMetaData* ImageFile::getFileMetaData() const { return m_fileMetaData; } /** * @return true if the file is is empty (image contains no pixels). */ bool ImageFile::isEmpty() const { return (m_image->width() <= 0); } ///** // * @return A pointer to the QImage in this file. // * Note that manipulating the pointer's data will // * alter the contents of this file. // */ //QImage* //ImageFile::getAsQImage() //{ // return m_image; //} /** * @return A pointer to the QImage in this file. */ const QImage* ImageFile::getAsQImage() const { return m_image; } /** * Set the image in this file from a QImage. * @param qimage * Image that is copied to this file. */ void ImageFile::setFromQImage(const QImage& qimage) { if (m_image != NULL) { delete m_image; } m_image = new QImage(qimage); this->setModified(); } /** * Set the dots per meter. * * @param x * Dots per meter for X dimension. * @param y * Dots per meter for Y dimension. */ void ImageFile::setDotsPerMeter(const int x, const int y) { m_image->setDotsPerMeterX(x); m_image->setDotsPerMeterY(y); } /** * Examines the image to find the rectangular of the object in the image * by examining pixels in the background color. * @param backgroundColor * RGB components range 0-255. * @param objectBoundsOut * 4-dimensional array containing the region that excludes * the backround around the image's object. */ void ImageFile::findImageObject(const uint8_t backgroundColor[3], int objectBoundsOut[4]) const { // // Dimensions of image // const int numX = m_image->width(); const int numY = m_image->height(); // // Initialize output // objectBoundsOut[0] = 0; objectBoundsOut[1] = 0; objectBoundsOut[2] = numX - 1; objectBoundsOut[3] = numY - 1; // // Find left // bool gotPixelFlag = false; for (int i = 0; i < numX; i++) { for (int j = 0; j < numY; j++) { const QRgb pixel = m_image->pixel(i, j); if ((qRed(pixel) != backgroundColor[0]) || (qGreen(pixel) != backgroundColor[1]) || (qBlue(pixel) != backgroundColor[2])) { objectBoundsOut[0] = i; gotPixelFlag = true; break; } } if (gotPixelFlag) { break; } } // // Find right // gotPixelFlag = false; for (int i = (numX - 1); i >= 0; i--) { for (int j = 0; j < numY; j++) { const QRgb pixel = m_image->pixel(i, j); if ((qRed(pixel) != backgroundColor[0]) || (qGreen(pixel) != backgroundColor[1]) || (qBlue(pixel) != backgroundColor[2])) { objectBoundsOut[2] = i; gotPixelFlag = true; break; } } if (gotPixelFlag) { break; } } // // Find top // gotPixelFlag = false; for (int j = 0; j < numY; j++) { for (int i = 0; i < numX; i++) { const QRgb pixel = m_image->pixel(i, j); if ((qRed(pixel) != backgroundColor[0]) || (qGreen(pixel) != backgroundColor[1]) || (qBlue(pixel) != backgroundColor[2])) { objectBoundsOut[1] = j; gotPixelFlag = true; break; } } if (gotPixelFlag) { break; } } // // Find bottom // gotPixelFlag = false; for (int j = (numY - 1); j >= 0; j--) { for (int i = 0; i < numX; i++) { const QRgb pixel = m_image->pixel(i, j); if ((qRed(pixel) != backgroundColor[0]) || (qGreen(pixel) != backgroundColor[1]) || (qBlue(pixel) != backgroundColor[2])) { objectBoundsOut[3] = j; gotPixelFlag = true; break; } } if (gotPixelFlag) { break; } } } /** * Add a margin to this image. * @param marginSize * Number of pixels in the margin. * @param backgroundColor used for the added pixels. * RGB components range 0-255. */ void ImageFile::addMargin(const int marginSize, const uint8_t backgroundColor[3]) { this->addMargin(marginSize, marginSize, backgroundColor); /* if (marginSize <= 0) { return; } // // Add margin // const int width = image.width(); const int height = image.height(); const int newWidth = width + marginSize * 2; const int newHeight = height + marginSize * 2; QRgb backgroundColorRGB = qRgba(backgroundColor[0], backgroundColor[1], backgroundColor[2], 0); // // Insert image // ImageFile imageFile; imageFile.setImage(QImage(newWidth, newHeight, image.format())); imageFile.getImage()->fill(backgroundColorRGB); try { imageFile.insertImage(image, marginSize, marginSize); image = (*imageFile.getImage()); } catch (DataFileException&) { } */ } /** * Add a margin to this image. * @param image * Image to which margin is added. * @param marginSizeX * Number of pixels in the margin along x-axis. * @param marginSizeY * Number of pixels in the margin along y-axis. * @param backgroundColor used for the added pixels. * RGB components range 0-255. */ void ImageFile::addMargin(const int marginSizeX, const int marginSizeY, const uint8_t backgroundColor[3]) { if ((marginSizeX <= 0) && (marginSizeY <= 0)) { return; } // // Add margin // const int width = m_image->width(); const int height = m_image->height(); const int newWidth = width + marginSizeX * 2; const int newHeight = height + marginSizeY * 2; QRgb backgroundColorRGB = qRgba(backgroundColor[0], backgroundColor[1], backgroundColor[2], 0); // // Insert image // ImageFile imageFile; imageFile.setFromQImage(QImage(newWidth, newHeight, m_image->format())); imageFile.m_image->fill(backgroundColorRGB); try { imageFile.insertImage(*m_image, marginSizeX, marginSizeY); this->setFromQImage(*imageFile.getAsQImage()); } catch (DataFileException& e) { CaretLogWarning(e.whatString()); } this->setModified(); } /** * Crop an image by removing the background from the object in the image * but keeping a margin of the given size around the image. * @param marginSize * Number of pixels in the margin around the image's object. * @param backgroundColor * Color of background that ranges 0-255. */ void ImageFile::cropImageRemoveBackground(const int marginSize, const uint8_t backgroundColor[3]) { // // Get cropping bounds // int leftTopRightBottom[4]; this->findImageObject(backgroundColor, leftTopRightBottom); CaretLogFine("cropping: " + AString::fromNumbers(leftTopRightBottom, 4, " ")); const int currentWidth = m_image->width(); const int currentHeight = m_image->height(); // // If cropping is valid // const int width = leftTopRightBottom[2] - leftTopRightBottom[0] + 1; const int height = leftTopRightBottom[3] - leftTopRightBottom[1] + 1; if ((width != currentWidth) || (height != currentHeight)) { if ((width > 1) && (height > 1)) { QImage copyImage = this->getAsQImage()->copy(leftTopRightBottom[0], leftTopRightBottom[1], width, height); if (copyImage.isNull() == false) { if ((copyImage.width() > 0) && (copyImage.height() > 0)) { this->setFromQImage(copyImage); } } this->setModified(); } } // // Process margin // if (marginSize > 0) { this->addMargin(marginSize, backgroundColor); } } /** * Replace the contents of this image by combining the input images and * retaining aspect and stretching and filling if needed. * @param imageFiles * Images that are combined. * @param numImagesPerRow * Number of images in each row. * @param backgroundColor * Color of background that ranges 0-255. */ void ImageFile::combinePreservingAspectAndFillIfNeeded(const std::vector& imageFiles, const int numImagesPerRow, const uint8_t backgroundColor[3]) { const int numImages = static_cast(imageFiles.size()); if (numImages <= 0) { return; } if (numImages == 1) { this->setFromQImage(*imageFiles[0]->m_image); return; } QRgb backgroundColorRGB = qRgba(backgroundColor[0], backgroundColor[1], backgroundColor[2], 0); // // Resize all images but do not stretch // need to retain aspect ratio but all must // be the same size in X & Y // // // Find max width and height of input images // int maxImageWidth = 0; int maxImageHeight = 0; for (int i = 0; i < numImages; i++) { // // Track max width/height // maxImageWidth = std::max(maxImageWidth, imageFiles[i]->m_image->width()); maxImageHeight = std::max(maxImageHeight, imageFiles[i]->m_image->height()); } // // Compute size of output image and create it // const int outputImageSizeX = maxImageWidth * numImagesPerRow; const int numberOfRows = (numImages / numImagesPerRow) + (((numImages % numImagesPerRow) != 0) ? 1 : 0); const int outputImageSizeY = maxImageHeight * numberOfRows; QImage combinedImage(outputImageSizeX, outputImageSizeY, imageFiles[0]->m_image->format()); combinedImage.fill(backgroundColorRGB); // // Loop through the images // int rowCounter = 0; int columnCounter = 0; for (int i = 0; i < numImages; i++) { // // Scale image // const QImage imageScaled = imageFiles[i]->m_image->scaled(maxImageWidth, maxImageHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation); // // Compute position of where image should be inserted // const int marginX = (maxImageWidth - imageScaled.width()) / 2; const int marginY = (maxImageHeight - imageScaled.height()) / 2; const int positionX = columnCounter * maxImageWidth + marginX; const int positionY = rowCounter * maxImageHeight + marginY; // // Insert into output image // try { ImageFile::insertImage(imageScaled, combinedImage, positionX, positionY); } catch (DataFileException& e) { CaretLogWarning("QImageFile::insertImage() error: " + e.whatString()); } // // Update row and column counters // columnCounter++; if (columnCounter >= numImagesPerRow) { columnCounter = 0; rowCounter++; } } this->setFromQImage(combinedImage); } /** * Read the image file. * @param filename * Name of image file. * @throws DataFileException * If error reading image. */ void ImageFile::readFile(const AString& filename) { clear(); checkFileReadability(filename); if (filename.isEmpty()) { throw DataFileException(filename + "Filename for reading is isEmpty"); } this->setFileName(filename); if (m_image->load(filename) == false) { clear(); throw DataFileException(filename + "Unable to load file."); } this->clearModified(); } /** * Append an image file to the bottom of this image file. * @param img * Image that is appended. */ void ImageFile::appendImageAtBottom(const ImageFile& img) { // // Determine size of new image // const QImage* otherImage = img.getAsQImage(); const int newWidth = std::max(m_image->width(), otherImage->width()); const int newHeight = m_image->height() + otherImage->height(); const int oldHeight = m_image->height(); // // Copy the current image // const QImage currentImage = *m_image; // std::cout << "cw: " << currentImage.width() << std::endl; // std::cout << "ch: " << currentImage.height() << std::endl; // // Create the new image and make it "this" image // QImage newImage(newWidth, newHeight, QImage::Format_RGB32); // std::cout << "nw: " << newImage.width() << std::endl; // std::cout << "nh: " << newImage.height() << std::endl; setFromQImage(newImage); // std::cout << "iw2: " << image.width() << std::endl; // std::cout << "ih2: " << image.height() << std::endl; // // Insert current image into new image // insertImage(currentImage, 0, 0); // // Insert other image into new image // insertImage(*otherImage, 0, oldHeight); this->setModified(); } /** * Insert an image into this image which must be large enough for insertion of image. * @param otherImage * Image that is inserted into this image. * @param x * X position of where image is inserted. * @param y * Y position of where image is inserted. * @throws DataFileException * If error inserting image. */ void ImageFile::insertImage(const QImage& otherImage, const int x, const int y) { ImageFile::insertImage(otherImage, *m_image, x, y); this->setModified(); } /** * insert an image into another image. * * Insert an image into another image which must be large enough for insertion of image. * @param insertThisImage * Image that is inserted into other image. * @param intoThisImage * Image that receives insertions of other image. * @param x * X position of where image is inserted. * @param y * Y position of where image is inserted. * @throws DataFileException * If error inserting image. */ void ImageFile::insertImage(const QImage& insertThisImage, QImage& intoThisImage, const int positionX, const int positionY) { if (positionX < 0) { throw DataFileException("X position is less than zero."); } if (positionY < 0) { throw DataFileException("Y position is less than zero."); } const int otherWidth = insertThisImage.width(); const int otherHeight = insertThisImage.height(); const int myWidth = intoThisImage.width(); const int myHeight = intoThisImage.height(); if ((otherWidth + positionX) > myWidth) { throw DataFileException("This image is not large enough to insert other image."); } if ((otherHeight + positionY) > myHeight) { throw DataFileException("This image is not large enough to insert other image."); } for (int i = 0; i < otherWidth; i++) { for (int j = 0; j < otherHeight; j++) { intoThisImage.setPixel(positionX + i, positionY + j, insertThisImage.pixel(i, j)); } } } /** * Scale the given image to the given width and height while preserving * the aspect ratio. If the * * @param image * The image * @param width * Width of the image * @param height * Height of the image * @param fillColor * If not NULL, padded region is this color * @return * Image that will be the requested width and height or * a null image (.isNull()) if error. */ QImage ImageFile::scaleToSizeWithPadding(const QImage& image, const int width, const int height, const QColor* fillColor) { /* * Invalid image tests */ if (image.isNull()) { return image; } if ((image.width() <= 0) || (image.height() <= 0)) { return QImage(); } /* * Nothing to do if image is correct size */ if ((image.width() == width) && (image.height() == height)) { return image; } const QImage scaledImage = image.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation); const int scaledWidth = scaledImage.width(); const int scaledHeight = scaledImage.height(); if ((scaledWidth == width) && (scaledHeight == height)) { return scaledImage; } else if (scaledWidth > width) { CaretLogSevere("Image scale width was made larger=" + QString::number(scaledWidth) + " than requested=" + QString::number(width)); return QImage(); } else if (scaledHeight > height) { CaretLogSevere("Image scale height was made larger=" + QString::number(scaledHeight) + " than requested=" + QString::number(height)); return QImage(); } QImage outputImage(width, height, image.format()); if (fillColor != NULL) { outputImage.fill(*fillColor); } else { outputImage.fill(Qt::black); } const int insertX = (width - scaledWidth) / 2; const int insertY = (height - scaledHeight) / 2; try { ImageFile::insertImage(scaledImage, outputImage, insertX, insertY); } catch (const DataFileException& dfe) { CaretLogSevere(dfe.whatString()); outputImage = QImage(); } return outputImage; } /** * Compare a file for unit testing (tolerance ignored). * * @param dataFile * Data files that is compared to this data file. * @param tolerance * Allowable difference at each pixel. * @param messageOut * Message describing differences. * @return * True if files are within tolerance, else false. */ bool ImageFile::compareFileForUnitTesting(const DataFile* dataFile, const float tolerance, AString& messageOut) const { // // Cast to an image file // const ImageFile* img = dynamic_cast(dataFile); if (img == NULL) { messageOut = ("ERROR: File for comparison (" + dataFile->getFileName() + " does not appear to be an image file."); return false; } // // Get the image from the other file // const QImage* otherImage = img->getAsQImage(); // // Confirm width/height // const int width = m_image->width(); const int height = m_image->height(); if ((width != otherImage->width()) || (height != otherImage->height())) { messageOut = "The images are of different height and/or width."; return false; } // // compare pixels // int pixelCount = 0; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { QColor im1 = m_image->pixel(i, j); QColor im2 = otherImage->pixel(i, j); if ((abs(im1.red() - im2.red()) > tolerance) || (abs(im1.green() - im2.green()) > tolerance) || (abs(im1.blue() - im2.blue()) > tolerance)) { pixelCount++; } } } if (pixelCount > 0) { const float pct = static_cast(pixelCount * 100.0) / static_cast(width * height); messageOut = QString::number(pct, 'f', 2) + "% pixels in the image do not match."; return false; } return true; } /** * Write the image file. * @param filename * Name of image file. * @throws DataFileException * If error writing image. */ void ImageFile::writeFile(const AString& filename) { checkFileWritability(filename); this->setFileName(filename); AString errorMessage; if (m_image->width() <= 0) { errorMessage = "Image width is zero."; } if (m_image->height() <= 0) { if (errorMessage.isEmpty() == false) errorMessage += "\n"; errorMessage = "Image height is zero."; } if (errorMessage.isEmpty() == false) { throw DataFileException(filename + " " + errorMessage); } FileInformation fileInfo(this->getFileName()); AString format = fileInfo.getFileExtension().toUpper(); if (format == "JPG") { format = "JPEG"; } QImageWriter writer(filename, format.toLatin1()); if (writer.supportsOption(QImageIOHandler::Quality)) { if (format.compare("png", Qt::CaseInsensitive) == 0) { const int quality = 1; writer.setQuality(quality); } else { const int quality = 100; writer.setQuality(quality); } } if (writer.supportsOption(QImageIOHandler::CompressionRatio)) { writer.setCompression(1); } if (writer.write(*m_image) == false) { throw DataFileException(writer.errorString()); } this->clearModified(); } /** * Get the image file extensions for the supported image types. * The extensions do not include the leading period. * * @param imageFileExtensions * Output filled with extensions for supported image types. * @param defaultExtension * The default extension (preference is png, jpg, jpeg) */ void ImageFile::getImageFileExtensions(std::vector& imageFileExtensions, AString& defaultExtension) { imageFileExtensions.clear(); defaultExtension = ""; QString firstExtension; QString pngExtension; QString jpegExtension; QString jpgExtension; QString tifExtension; QString tiffExtension; QList imageFormats = QImageWriter::supportedImageFormats(); const int numFormats = imageFormats.count(); for (int i = 0; i < numFormats; i++) { AString extension = QString(imageFormats.at(i)).toLower(); imageFileExtensions.push_back(extension); if (i == 0) { firstExtension = extension; } if (extension == "png") { pngExtension = extension; } else if (extension == "jpg") { jpgExtension = extension; } else if (extension == "jpeg") { jpegExtension = extension; } else if (extension == "tif") { tifExtension = extension; } else if (extension == "tiff") { tiffExtension = extension; } } if (pngExtension.isEmpty() == false) { defaultExtension = pngExtension; } else if (jpgExtension.isEmpty() == false) { defaultExtension = jpgExtension; } else if (jpegExtension.isEmpty() == false) { defaultExtension = jpegExtension; } else if (tifExtension.isEmpty() == false) { defaultExtension = tifExtension; } else if (tiffExtension.isEmpty() == false) { defaultExtension = tiffExtension; } else { defaultExtension = firstExtension; } } /** * Get the image file filters for the supported image types. * * @param imageFileFilters * Output filled with the filters for supported image types. * @param defaultFilter * Filter for the preferred image type. */ void ImageFile::getImageFileFilters(std::vector& imageFileFilters, AString& defaultFilter) { imageFileFilters.clear(); defaultFilter.clear(); std::vector imageFileExtensions; AString defaultExtension; ImageFile::getImageFileExtensions(imageFileExtensions, defaultExtension); const int32_t numExtensions = static_cast(imageFileExtensions.size()); for (int32_t i = 0; i < numExtensions; i++) { const AString ext = imageFileExtensions[i]; const AString filter = (ext.toUpper() + " Image File (*." + ext + ")"); imageFileFilters.push_back(filter); if (ext == defaultExtension) { defaultFilter = filter; } } if (defaultFilter.isEmpty()) { if (imageFileFilters.empty() == false) { defaultFilter = imageFileFilters[0]; } } } /** * Resize the image to the given width while preserving the aspect ratio * of the image. * * @param width * Width for image. */ void ImageFile::resizeToWidth(const int32_t width) { CaretAssert(m_image); *m_image = m_image->scaledToWidth(width, Qt::SmoothTransformation); } /** * Resize the image to the given height while preserving the aspect ratio * of the image. * * @param height * Height for image. */ void ImageFile::resizeToHeight(const int32_t height) { CaretAssert(m_image); *m_image = m_image->scaledToHeight(height, Qt::SmoothTransformation); } /** * Resize the image so that its width is no larger than the given value. * If the image's current width is less than the given value, no * resizing takes place. * * @param maximumWidth * Maximum width for the image. */ void ImageFile::resizeToMaximumWidth(const int32_t maximumWidth) { CaretAssert(m_image); const int32_t width = m_image->width(); if (width > maximumWidth) { *m_image = m_image->scaledToWidth(maximumWidth, Qt::SmoothTransformation); } } /** * Resize the image so that its height is no larger than the given value. * If the image's current height is less than the given value, no * resizing takes place. * * @param maximumHeight * Maximum height for the image. */ void ImageFile::resizeToMaximumHeight(const int32_t maximumHeight) { CaretAssert(m_image); const int32_t height = m_image->height(); if (height > maximumHeight) { *m_image = m_image->scaledToHeight(maximumHeight, Qt::SmoothTransformation); } } /** * Resize the image so that its maximum dimension is the given value * yet preserves the aspect ratio of the image. If the maximum dimension * is less than the given value, no resizing takes place. * * @param maximumWidthOrHeight * Maximum dimension for the image. */ void ImageFile::resizeToMaximumWidthOrHeight(const int32_t maximumWidthOrHeight) { CaretAssert(m_image); const int32_t width = m_image->width(); const int32_t height = m_image->height(); if ((width > 0) && (height > 0)) { if (width > height) { resizeToMaximumWidth(maximumWidthOrHeight); } else { if (height > maximumWidthOrHeight) { resizeToMaximumWidth(maximumWidthOrHeight); } } } } /** * Get the RGBA bytes from the image. * * @param bytesRGBA * The RGBA bytes in the image. * @param widthOut * Width of the image. * @param heightOut * Height of the image. * @param imageOrigin * Location of first pixel in the image data. * @return * True if the bytes, width, and height are valid, else false. */ bool ImageFile::getImageBytesRGBA(const IMAGE_DATA_ORIGIN_LOCATION imageOrigin, std::vector& bytesRGBA, int32_t& widthOut, int32_t& heightOut) const { bytesRGBA.clear(); widthOut = 0; heightOut = 0; if (m_image != NULL) { widthOut = m_image->width(); heightOut = m_image->height(); if ((widthOut > 0) && (heightOut > 0)) { bytesRGBA.resize(widthOut * heightOut * 4); bool isOriginAtTop = false; switch (imageOrigin) { case IMAGE_DATA_ORIGIN_AT_BOTTOM: isOriginAtTop = false; break; case IMAGE_DATA_ORIGIN_AT_TOP: isOriginAtTop = true; break; } /* * Documentation for QImage states that setPixel may be very costly * and recommends using the scanLine() method to access pixel data. */ for (int y = 0; y < heightOut; y++) { const int scanLineIndex = (isOriginAtTop ? y : heightOut -y - 1); const uchar* scanLine = m_image->scanLine(scanLineIndex); QRgb* rgbScanLine = (QRgb*)scanLine; for (int x = 0; x < widthOut; x++) { const int32_t contentOffset = (((y * widthOut) * 4) + (x * 4)); QRgb& rgb = rgbScanLine[x]; bytesRGBA[contentOffset] = static_cast(qRed(rgb)); bytesRGBA[contentOffset+1] = static_cast(qGreen(rgb)); bytesRGBA[contentOffset+2] = static_cast(qBlue(rgb)); bytesRGBA[contentOffset+3] = 255; } } return true; } } return false; } /** * Get the pixel RGBA at the given pixel I and J. * * @param imageOrigin * Location of first pixel in the image data. * @param pixelI * Image I index * @param pixelJ * Image J index * @param pixelRGBAOut * RGBA at Pixel I, J * @return * True if valid, else false. */ bool ImageFile::getImagePixelRGBA(const IMAGE_DATA_ORIGIN_LOCATION imageOrigin, const int32_t pixelI, const int32_t pixelJ, uint8_t pixelRGBAOut[4]) const { if (m_image != NULL) { const int32_t w = m_image->width(); const int32_t h = m_image->height(); if ((pixelI >= 0) && (pixelI < w) && (pixelJ >= 0) && (pixelJ < h)) { int32_t imageJ = pixelJ; switch (imageOrigin) { case IMAGE_DATA_ORIGIN_AT_BOTTOM: imageJ = h - pixelJ - 1; break; case IMAGE_DATA_ORIGIN_AT_TOP: break; } if ((imageJ >= 0) && (imageJ < h)) { const QRgb rgb = m_image->pixel(pixelI, imageJ); pixelRGBAOut[0] = static_cast(qRed(rgb)); pixelRGBAOut[1] = static_cast(qGreen(rgb)); pixelRGBAOut[2] = static_cast(qBlue(rgb)); pixelRGBAOut[3] = 255; return true; } else { CaretLogSevere("Invalid image J"); } } } return false; } /** * Get the RGBA bytes from the image resized into the given width and height. * * @param imageOrigin * Location of first pixel in the image data. * @param resizeToWidth * New width for image. * @param resizeToHeight * New height of the image. * @param bytesRGBAOut * The RGBA bytes in the image. * @return * True if the bytes, width, and height are valid, else false. */ bool ImageFile::getImageResizedBytes(const IMAGE_DATA_ORIGIN_LOCATION imageOrigin, const int32_t resizeToWidth, const int32_t resizeToHeight, std::vector& bytesRGBAOut) const { bytesRGBAOut.clear(); if (m_image == NULL) { return false; } const int32_t numBytes = resizeToWidth * resizeToHeight; if (numBytes <= 0) { return false; } const int32_t colorComponentsPerByte = 4; bytesRGBAOut.resize(numBytes * colorComponentsPerByte); QImage scaledImage = m_image->scaled(resizeToWidth, resizeToHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); /* * QImage::scaled() failed. */ if (scaledImage.isNull()) { return false; } bool isOriginAtTop = false; switch (imageOrigin) { case IMAGE_DATA_ORIGIN_AT_BOTTOM: isOriginAtTop = false; break; case IMAGE_DATA_ORIGIN_AT_TOP: isOriginAtTop = true; break; } /* * Documentation for QImage states that setPixel may be very costly * and recommends using the scanLine() method to access pixel data. */ for (int y = 0; y < resizeToHeight; y++) { const int scanLineIndex = (isOriginAtTop ? y : resizeToHeight -y - 1); const uchar* scanLine = scaledImage.scanLine(scanLineIndex); QRgb* rgbScanLine = (QRgb*)scanLine; for (int x = 0; x < resizeToWidth; x++) { const int32_t contentOffset = (((y * resizeToWidth) * 4) + (x * 4)); QRgb& rgb = rgbScanLine[x]; CaretAssertVectorIndex(bytesRGBAOut, contentOffset + 3); bytesRGBAOut[contentOffset] = static_cast(qRed(rgb)); bytesRGBAOut[contentOffset+1] = static_cast(qGreen(rgb)); bytesRGBAOut[contentOffset+2] = static_cast(qBlue(rgb)); bytesRGBAOut[contentOffset+3] = 255; } } return true; } /** * @return width of image (zero if image is invalid) */ int32_t ImageFile::getWidth() const { int32_t w = 0; if (m_image != NULL) { w = m_image->width(); } return w; } /** * @return height of image (zero if image is invalid) */ int32_t ImageFile::getHeight() const { int32_t h = 0; if (m_image != NULL) { h = m_image->height(); } return h; } /** * Essentially writes the image file to a byte array using the given format. * * @param byteArrayOut * Byte array into which the image is written. * @param format * Format for the image (jpg, ppm, etc.). */ void ImageFile::getImageInByteArray(QByteArray& byteArrayOut, const AString& format) const { byteArrayOut.clear(); if (m_image != NULL) { QBuffer buffer(&byteArrayOut); if ( ! buffer.open(QIODevice::WriteOnly)) { throw DataFileException(getFileName(), "PROGRAM ERROR: Unable to open byte array for output of image."); } bool successFlag = false; if (format.isEmpty()) { successFlag = m_image->save(&buffer); } else { successFlag = m_image->save(&buffer, format.toLatin1().data()); } if ( ! successFlag) { throw DataFileException(getFileName(), "Failed to write image to byte array. " + buffer.errorString()); } } } /** * Essentially reads the image file from a byte array using the given format. * * @param byteArray * Byte array from which the image is read. * @param format * Format for the image (jpg, ppm, etc.) or empty if unknown. */ bool ImageFile::setImageFromByteArray(const QByteArray& byteArray, const AString& format) { bool successFlag = false; if (format.isEmpty()) { successFlag = m_image->loadFromData(byteArray); } else { successFlag = m_image->loadFromData(byteArray, format.toLatin1().data()); } if ( ! successFlag) { CaretLogSevere(getFileName() + " Failed to create image from byte array."); } return successFlag; } /** * Convert this image into a Volume File using the * encapsulated Control Point File whose matrix * must have been updated. * * @param colorMode * Color mode for conversion. * @param errorMessageOut * Contains error message if conversion fails. * @return * Pointer to volume file or NULL if there is an error. * Name of volume file is the name of the image but * the file extension is changed to a volume file extension. * */ VolumeFile* ImageFile::convertToVolumeFile(const CONVERT_TO_VOLUME_COLOR_MODE colorMode, AString& errorMessageOut) const { errorMessageOut.clear(); std::vector rgbaBytes; int32_t width = 0; int32_t height = 0; getImageBytesRGBA(ImageFile::IMAGE_DATA_ORIGIN_AT_BOTTOM, rgbaBytes, width, height); if ((width <= 0) || (height <= 0)) { errorMessageOut = "Image width and/or height is invalid."; return NULL; } const Matrix4x4* transformationMatrix = m_controlPointFile->getLandmarkTransformationMatrix(); float firstPixel[3] = { 0, 0, 0 }; transformationMatrix->multiplyPoint3(firstPixel); std::cout << "First pixel coord: " << AString::fromNumbers(firstPixel, 3, ",") << std::endl; float lastPixel[3] = { (float)(width - 1), (float)(height - 1), 0.0f }; transformationMatrix->multiplyPoint3(lastPixel); std::cout << "Last pixel coord: " << AString::fromNumbers(lastPixel, 3, ",") << std::endl; { float bl[3] = { 0.0, 0.0, 0.0 }; transformationMatrix->multiplyPoint3(bl); ControlPoint3D bottomLeft(0, 0, 0, bl[0], bl[1], bl[2]); float br[3] = { (float)(width - 1.0), 0.0, 0.0 }; transformationMatrix->multiplyPoint3(br); ControlPoint3D bottomRight(width - 1.0, 0.0, 0.0, br[0], br[1], br[2]); float tr[3] = { (float)(width - 1.0), (float)(height - 1.0), 0.0 }; transformationMatrix->multiplyPoint3(tr); ControlPoint3D topRight((float)(width - 1.0), (float)(height - 1.0), 0.0, tr[0], tr[1], tr[2]); ControlPointFile volumeControlPointFile; volumeControlPointFile.addControlPoint(bottomLeft); volumeControlPointFile.addControlPoint(bottomRight); volumeControlPointFile.addControlPoint(topRight); if ( ! volumeControlPointFile.updateLandmarkTransformationMatrix(errorMessageOut)) { errorMessageOut.insert(0, "Volume Matrix: "); return NULL; } } std::vector dimensions; dimensions.push_back(width); // I dimensions.push_back(height); // J dimensions.push_back(1); // K /* * Convert matrix4x4 to volume file vector of vectors. */ std::vector row1; std::vector row2; std::vector row3; std::vector row4; for (int j = 0; j < 4; j++) { row1.push_back(transformationMatrix->getMatrixElement(0, j)); row2.push_back(transformationMatrix->getMatrixElement(1, j)); row3.push_back(transformationMatrix->getMatrixElement(2, j)); row4.push_back(transformationMatrix->getMatrixElement(3, j)); } std::vector > indexToSpace; indexToSpace.push_back(row1); indexToSpace.push_back(row2); indexToSpace.push_back(row3); indexToSpace.push_back(row4); int64_t numComponents = 1; SubvolumeAttributes::VolumeType whatType = SubvolumeAttributes::FUNCTIONAL; switch (colorMode) { case CONVERT_TO_VOLUME_COLOR_GRAYSCALE: break; case CONVERT_TO_VOLUME_COLOR_RGB: numComponents = 3; whatType = SubvolumeAttributes::RGB; break; } VolumeFile* volumeFile = new VolumeFile(dimensions, indexToSpace, numComponents, whatType); FileInformation fileInfo(getFileName()); const AString volumeFileName = FileInformation::assembleFileComponents(fileInfo.getAbsolutePath(), fileInfo.getFileNameNoExtension(), DataFileTypeEnum::toFileExtension(DataFileTypeEnum::VOLUME)); volumeFile->setFileName(volumeFileName); int32_t rgbaIndex = 0; const int64_t k = 0; const int64_t mapIndex = 0; for (int64_t j = 0; j < height; j++) { for (int64_t i = 0; i < width; i++) { switch (colorMode) { case CONVERT_TO_VOLUME_COLOR_GRAYSCALE: { /* * Luminosity conversion from GIMP * http://docs.gimp.org/2.6/en/gimp-tool-desaturate.html */ float intensity = ((rgbaBytes[rgbaIndex] * 0.21) + (rgbaBytes[rgbaIndex + 1] * 0.72) + (rgbaBytes[rgbaIndex + 2] * 0.07)); if (intensity > 255.0) intensity = 255.0; else if (intensity < 0.0) intensity = 0.0; if (rgbaBytes[rgbaIndex + 3] <= 0.0) { intensity = 0.0; } volumeFile->setValue(intensity, i, j, k, mapIndex, 0); rgbaIndex += 4; } break; case CONVERT_TO_VOLUME_COLOR_RGB: { CaretAssertVectorIndex(rgbaBytes, rgbaIndex); volumeFile->setValue(rgbaBytes[rgbaIndex], i, j, k, mapIndex, 0); CaretAssertVectorIndex(rgbaBytes, rgbaIndex); volumeFile->setValue(rgbaBytes[rgbaIndex+1], i, j, k, mapIndex, 1); CaretAssertVectorIndex(rgbaBytes, rgbaIndex); volumeFile->setValue(rgbaBytes[rgbaIndex+2], i, j, k, mapIndex, 2); if (numComponents == 4) { CaretAssertVectorIndex(rgbaBytes, rgbaIndex); volumeFile->setValue(rgbaBytes[rgbaIndex+3], i, j, k, mapIndex, 3); } rgbaIndex += 4; } break; } } } switch (colorMode) { case CONVERT_TO_VOLUME_COLOR_GRAYSCALE: { PaletteColorMapping* pcm = volumeFile->getMapPaletteColorMapping(mapIndex); pcm->setSelectedPaletteToGrayInterpolated(); pcm->setDisplayNegativeDataFlag(false); pcm->setDisplayZeroDataFlag(false); pcm->setDisplayPositiveDataFlag(true); pcm->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE); } break; case CONVERT_TO_VOLUME_COLOR_RGB: break; } volumeFile->clearVoxelColoringForMap(mapIndex); volumeFile->updateScalarColoringForMap(mapIndex); return volumeFile; } /** * @return The control point file. */ ControlPointFile* ImageFile::getControlPointFile() { return m_controlPointFile; } /** * @return The control point file. */ const ControlPointFile* ImageFile::getControlPointFile() const { return m_controlPointFile; } /** * Save file data from the scene. For subclasses that need to * save to a scene, this method should be overriden. sceneClass * will be valid and any scene data should be added to it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. */ void ImageFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { if (m_controlPointFile != NULL) { sceneClass->addClass(m_controlPointFile->saveToScene(sceneAttributes, "m_controlPointFile")); } } /** * Restore file data from the scene. For subclasses that need to * restore from a scene, this method should be overridden. The scene class * will be valid and any scene data may be obtained from it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void ImageFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { m_controlPointFile->restoreFromScene(sceneAttributes, sceneClass->getClass("m_controlPointFile")); } connectome-workbench-1.4.2/src/Files/ImageFile.h000066400000000000000000000174011360521144700214620ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #ifndef __IMAGE_FILE_H__ #define __IMAGE_FILE_H__ #include "CaretDataFile.h" #include "CaretPointer.h" class QColor; class QImage; namespace caret { class ControlPointFile; class ControlPoint3D; class VolumeFile; /// File for images class ImageFile : public CaretDataFile { public: // class ControlPoint { // public: // ControlPoint(const float i, // const float j, // const float k, // const float x, // const float y, // const float z) // : i(i), j(j), k(k), x(x), y(y), z(z) { } // // void getSource(double pt[3]) const { pt[0] = i; pt[1] = j; pt[2] = k; } // // void getTarget(double pt[3]) const { pt[0] = x; pt[1] = y; pt[2] = z; } // // const float i; // const float j; // const float k; // const float x; // const float y; // const float z; // }; /** * Location of origin in image data. */ enum IMAGE_DATA_ORIGIN_LOCATION { /** Origin at bottom (OpenGL has origin at bottom) */ IMAGE_DATA_ORIGIN_AT_BOTTOM, /** Origin at top (most image formats have origin at top) */ IMAGE_DATA_ORIGIN_AT_TOP }; /** * Convert to volume color mode */ enum CONVERT_TO_VOLUME_COLOR_MODE { /** Create single component grayscale volume */ CONVERT_TO_VOLUME_COLOR_GRAYSCALE, /** Create three component RGB volume */ CONVERT_TO_VOLUME_COLOR_RGB }; // enum LANDMARK_MODE { // VTK_LANDMARK_AFFINE, // VTK_LANDMARK_RIGIDBODY, // VTK_LANDMARK_SIMILARITY // }; ImageFile(); ImageFile(const unsigned char* imageDataRGBA, const int imageWidth, const int imageHeight, const IMAGE_DATA_ORIGIN_LOCATION imageOrigin); ImageFile(const QImage& img); ~ImageFile(); void appendImageAtBottom(const ImageFile& img); void clear(); /** * @return The structure for this file. */ virtual StructureEnum::Enum getStructure() const; /** * Set the structure for this file. * @param structure * New structure for this file. */ virtual void setStructure(const StructureEnum::Enum structure); /** * @return Get access to the file's metadata. */ virtual GiftiMetaData* getFileMetaData(); /** * @return Get access to unmodifiable file's metadata. */ virtual const GiftiMetaData* getFileMetaData() const; virtual bool compareFileForUnitTesting(const DataFile* df, const float tolerance, AString& messageOut) const; bool isEmpty() const; //QImage* getAsQImage(); const QImage* getAsQImage() const; void setFromQImage(const QImage& img); bool getImageBytesRGBA(const IMAGE_DATA_ORIGIN_LOCATION imageOrigin, std::vector& bytesRGBA, int32_t& widthOut, int32_t& heightOut) const; bool getImageResizedBytes(const IMAGE_DATA_ORIGIN_LOCATION imageOrigin, const int32_t resizeToWidth, const int32_t resizeToHeight, std::vector& bytesRGBAOut) const; bool getImagePixelRGBA(const IMAGE_DATA_ORIGIN_LOCATION imageOrigin, const int32_t pixelI, const int32_t pixelJ, uint8_t pixelRGBAOut[4]) const; int32_t getWidth() const; int32_t getHeight() const; virtual void readFile(const AString& filename); virtual void writeFile(const AString& filename); void cropImageRemoveBackground(const int marginSize, const uint8_t backgroundColor[3]); void findImageObject(const uint8_t backgroundColor[3], int objectBoundsOut[4]) const; void addMargin(const int marginSize, const uint8_t backgroundColor[3]); void addMargin(const int marginSizeX, const int marginSizeY, const uint8_t backgroundColor[3]); void setDotsPerMeter(const int x, const int y); void resizeToMaximumWidthOrHeight(const int32_t maximumWidthOrHeight); void resizeToMaximumWidth(const int32_t maximumWidth); void resizeToMaximumHeight(const int32_t maximumHeight); void resizeToHeight(const int32_t height); void resizeToWidth(const int32_t width); void getImageInByteArray(QByteArray& byteArrayOut, const AString& format) const; bool setImageFromByteArray(const QByteArray& byteArray, const AString& format); void combinePreservingAspectAndFillIfNeeded(const std::vector& imageFiles, const int numImagesPerRow, const uint8_t backgroundColor[3]); static void getImageFileExtensions(std::vector& imageFileExtensions, AString& defaultExtension); static void getImageFileFilters(std::vector& imageFileFilters, AString& defaultFilter); static QImage scaleToSizeWithPadding(const QImage& image, const int width, const int height, const QColor* fillColor = NULL); VolumeFile* convertToVolumeFile(const CONVERT_TO_VOLUME_COLOR_MODE colorMode, AString& errorMessageOut) const; ControlPointFile* getControlPointFile(); const ControlPointFile* getControlPointFile() const; virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: ImageFile(const ImageFile&); ImageFile& operator=(const ImageFile&); void insertImage(const QImage& otherImage, const int x, const int y); static void insertImage(const QImage& insertThisImage, QImage& intoThisImage, const int positionX, const int positionY); QImage* m_image; CaretPointer m_fileMetaData; CaretPointer m_controlPointFile; static const float s_defaultWindowDepthPercentage; }; } // namespace #endif // __IMAGE_FILE_H__ connectome-workbench-1.4.2/src/Files/ImageResolutionUnitsEnum.cxx000066400000000000000000000253701360521144700251750ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __IMAGE_RESOLUTION_UNITS_ENUM_DECLARE__ #include "ImageResolutionUnitsEnum.h" #undef __IMAGE_RESOLUTION_UNITS_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ImageResolutionUnitsEnum * \brief Pixel per spatial unit (inches, cm) * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_imagePixelsPerSpatialUnitsEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void imagePixelsPerSpatialUnitsEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ImageResolutionUnitsEnum.h" * * Instatiate: * m_imagePixelsPerSpatialUnitsEnumComboBox = new EnumComboBoxTemplate(this); * m_imagePixelsPerSpatialUnitsEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_imagePixelsPerSpatialUnitsEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(imagePixelsPerSpatialUnitsEnumComboBoxItemActivated())); * * Update the selection: * m_imagePixelsPerSpatialUnitsEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ImageResolutionUnitsEnum::Enum VARIABLE = m_imagePixelsPerSpatialUnitsEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ImageResolutionUnitsEnum::ImageResolutionUnitsEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ImageResolutionUnitsEnum::~ImageResolutionUnitsEnum() { } /** * Initialize the enumerated metadata. */ void ImageResolutionUnitsEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ImageResolutionUnitsEnum(PIXELS_PER_INCH, "PIXELS_PER_INCH", "pixels/inch")); enumData.push_back(ImageResolutionUnitsEnum(PIXEL_PER_CENTIMETER, "PIXEL_PER_CENTIMETER", "pixels/cm")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ImageResolutionUnitsEnum* ImageResolutionUnitsEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ImageResolutionUnitsEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ImageResolutionUnitsEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ImageResolutionUnitsEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ImageResolutionUnitsEnum::Enum ImageResolutionUnitsEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ImageResolutionUnitsEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ImageResolutionUnitsEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ImageResolutionUnitsEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ImageResolutionUnitsEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ImageResolutionUnitsEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ImageResolutionUnitsEnum::Enum ImageResolutionUnitsEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ImageResolutionUnitsEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ImageResolutionUnitsEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ImageResolutionUnitsEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ImageResolutionUnitsEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ImageResolutionUnitsEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ImageResolutionUnitsEnum::Enum ImageResolutionUnitsEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ImageResolutionUnitsEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ImageResolutionUnitsEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ImageResolutionUnitsEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ImageResolutionUnitsEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ImageResolutionUnitsEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ImageResolutionUnitsEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ImageResolutionUnitsEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ImageResolutionUnitsEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Files/ImageResolutionUnitsEnum.h000066400000000000000000000062341360521144700246200ustar00rootroot00000000000000#ifndef __IMAGE_RESOLUTION_UNITS_ENUM_H__ #define __IMAGE_RESOLUTION_UNITS_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ImageResolutionUnitsEnum { public: /** * Enumerated values. */ enum Enum { /** Pixels per inch */ PIXELS_PER_INCH, /** Pixels per centimeter */ PIXEL_PER_CENTIMETER }; ~ImageResolutionUnitsEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ImageResolutionUnitsEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ImageResolutionUnitsEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __IMAGE_RESOLUTION_UNITS_ENUM_DECLARE__ std::vector ImageResolutionUnitsEnum::enumData; bool ImageResolutionUnitsEnum::initializedFlag = false; int32_t ImageResolutionUnitsEnum::integerCodeCounter = 0; #endif // __IMAGE_RESOLUTION_UNITS_ENUM_DECLARE__ } // namespace #endif //__IMAGE_RESOLUTION_UNITS_ENUM_H__ connectome-workbench-1.4.2/src/Files/ImageSpatialUnitsEnum.cxx000066400000000000000000000251651360521144700244310ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __IMAGE_SPATIAL_UNITS_ENUM_DECLARE__ #include "ImageSpatialUnitsEnum.h" #undef __IMAGE_SPATIAL_UNITS_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::ImageSpatialUnitsEnum * \brief Units of image resolution * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_imageSpatialUnitsEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void imageSpatialUnitsEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "ImageSpatialUnitsEnum.h" * * Instatiate: * m_imageSpatialUnitsEnumComboBox = new EnumComboBoxTemplate(this); * m_imageSpatialUnitsEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_imageSpatialUnitsEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(imageSpatialUnitsEnumComboBoxItemActivated())); * * Update the selection: * m_imageSpatialUnitsEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const ImageSpatialUnitsEnum::Enum VARIABLE = m_imageSpatialUnitsEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ ImageSpatialUnitsEnum::ImageSpatialUnitsEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ ImageSpatialUnitsEnum::~ImageSpatialUnitsEnum() { } /** * Initialize the enumerated metadata. */ void ImageSpatialUnitsEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ImageSpatialUnitsEnum(INCHES, "INCHES", "inches")); enumData.push_back(ImageSpatialUnitsEnum(CENTIMETERS, "CENTIMETERS", "cm")); enumData.push_back(ImageSpatialUnitsEnum(MILLIMETERS, "MILLIMETERS", "mm")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ImageSpatialUnitsEnum* ImageSpatialUnitsEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ImageSpatialUnitsEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ImageSpatialUnitsEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const ImageSpatialUnitsEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ImageSpatialUnitsEnum::Enum ImageSpatialUnitsEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ImageSpatialUnitsEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ImageSpatialUnitsEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type ImageSpatialUnitsEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString ImageSpatialUnitsEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const ImageSpatialUnitsEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ImageSpatialUnitsEnum::Enum ImageSpatialUnitsEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ImageSpatialUnitsEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ImageSpatialUnitsEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type ImageSpatialUnitsEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ImageSpatialUnitsEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const ImageSpatialUnitsEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ImageSpatialUnitsEnum::Enum ImageSpatialUnitsEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ImageSpatialUnitsEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ImageSpatialUnitsEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type ImageSpatialUnitsEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void ImageSpatialUnitsEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ImageSpatialUnitsEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(ImageSpatialUnitsEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void ImageSpatialUnitsEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(ImageSpatialUnitsEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Files/ImageSpatialUnitsEnum.h000066400000000000000000000061751360521144700240560ustar00rootroot00000000000000#ifndef __IMAGE_SPATIAL_UNITS_ENUM_H__ #define __IMAGE_SPATIAL_UNITS_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class ImageSpatialUnitsEnum { public: /** * Enumerated values. */ enum Enum { /** Inches */ INCHES, /** Centimeters */ CENTIMETERS, /** Millimeters */ MILLIMETERS }; ~ImageSpatialUnitsEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: ImageSpatialUnitsEnum(const Enum enumValue, const AString& name, const AString& guiName); static const ImageSpatialUnitsEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __IMAGE_SPATIAL_UNITS_ENUM_DECLARE__ std::vector ImageSpatialUnitsEnum::enumData; bool ImageSpatialUnitsEnum::initializedFlag = false; int32_t ImageSpatialUnitsEnum::integerCodeCounter = 0; #endif // __IMAGE_SPATIAL_UNITS_ENUM_DECLARE__ } // namespace #endif //__IMAGE_SPATIAL_UNITS_ENUM_H__ connectome-workbench-1.4.2/src/Files/LabelDrawingProperties.cxx000066400000000000000000000137101360521144700246220ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __LABEL_DRAWING_PROPERTIES_DECLARE__ #include "LabelDrawingProperties.h" #undef __LABEL_DRAWING_PROPERTIES_DECLARE__ #include "CaretAssert.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::LabelDrawingProperties * \brief File properties for labels. * \ingroup Files */ /** * Constructor. */ LabelDrawingProperties::LabelDrawingProperties() : CaretObject() { initializeInstance(); } /** * Destructor. */ LabelDrawingProperties::~LabelDrawingProperties() { delete m_sceneAssistant; } /** * Copy constructor. * @param obj * Object that is copied. */ LabelDrawingProperties::LabelDrawingProperties(const LabelDrawingProperties& obj) : CaretObject(obj), SceneableInterface(obj) { initializeInstance(); copyHelper(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ LabelDrawingProperties& LabelDrawingProperties::operator=(const LabelDrawingProperties& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelper(obj); } return *this; } /** * Initialize an instance of this class. */ void LabelDrawingProperties::initializeInstance() { m_drawingType = LabelDrawingTypeEnum::DRAW_FILLED; m_outlineColor = CaretColorEnum::BLACK; m_drawMedialWallFilled = true; m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_drawingType", &m_drawingType); m_sceneAssistant->add("m_outlineColor", &m_outlineColor); m_sceneAssistant->add("m_drawMedialWallFilled", &m_drawMedialWallFilled); } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void LabelDrawingProperties::copyHelper(const LabelDrawingProperties& obj) { m_drawingType = obj.m_drawingType; m_outlineColor = obj.m_outlineColor; m_drawMedialWallFilled = obj.m_drawMedialWallFilled; } /** * @return The drawing type. */ LabelDrawingTypeEnum::Enum LabelDrawingProperties::getDrawingType() const { return m_drawingType; } /** * Set the drawing type to the given value. * @param drawingType * New value for drawing type. */ void LabelDrawingProperties::setDrawingType(const LabelDrawingTypeEnum::Enum drawingType) { m_drawingType = drawingType; } /** * @param displayGroup * Display group. * @return The outline color. */ CaretColorEnum::Enum LabelDrawingProperties::getOutlineColor() const { return m_outlineColor; } /** * Set the outline color to the given value. * @param outlineColor * New value for outline color. */ void LabelDrawingProperties::setOutlineColor(const CaretColorEnum::Enum outlineColor) { m_outlineColor = outlineColor; } /** * @return medial wall is drawn filled */ bool LabelDrawingProperties::isDrawMedialWallFilled() const { return m_drawMedialWallFilled; } /** * Set medial wall is drawn filled * @param drawMedialWallFilled * New value for medial wall is drawn filled */ void LabelDrawingProperties::setDrawMedialWallFilled(const bool drawMedialWallFilled) { m_drawMedialWallFilled = drawMedialWallFilled; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* LabelDrawingProperties::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "LabelDrawingProperties", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void LabelDrawingProperties::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/Files/LabelDrawingProperties.h000066400000000000000000000065421360521144700242540ustar00rootroot00000000000000#ifndef __LABEL_DRAWING_PROPERTIES_H__ #define __LABEL_DRAWING_PROPERTIES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "CaretColorEnum.h" #include "LabelDrawingTypeEnum.h" #include "SceneableInterface.h" namespace caret { class SceneClassAssistant; class LabelDrawingProperties : public CaretObject, public SceneableInterface { public: LabelDrawingProperties(); virtual ~LabelDrawingProperties(); LabelDrawingProperties(const LabelDrawingProperties&); LabelDrawingProperties& operator=(const LabelDrawingProperties&); LabelDrawingTypeEnum::Enum getDrawingType() const; void setDrawingType(const LabelDrawingTypeEnum::Enum drawingType); CaretColorEnum::Enum getOutlineColor() const; void setOutlineColor(const CaretColorEnum::Enum outlineColor); bool isDrawMedialWallFilled() const; void setDrawMedialWallFilled(const bool drawMedialWallFilled); // ADD_NEW_METHODS_HERE virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implemetation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: void initializeInstance(); void copyHelper(const LabelDrawingProperties& obj); SceneClassAssistant* m_sceneAssistant; LabelDrawingTypeEnum::Enum m_drawingType; CaretColorEnum::Enum m_outlineColor; /** medial wall is drawn filled*/ bool m_drawMedialWallFilled; // ADD_NEW_MEMBERS_HERE }; #ifdef __LABEL_DRAWING_PROPERTIES_DECLARE__ // #endif // __LABEL_DRAWING_PROPERTIES_DECLARE__ } // namespace #endif //__LABEL_DRAWING_PROPERTIES_H__ connectome-workbench-1.4.2/src/Files/LabelDrawingTypeEnum.cxx000066400000000000000000000227371360521144700242450ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __LABEL_DRAWING_TYPE_ENUM_DECLARE__ #include "LabelDrawingTypeEnum.h" #undef __LABEL_DRAWING_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::LabelDrawingTypeEnum * \brief Drawing type for labels. * \ingroup Files */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ LabelDrawingTypeEnum::LabelDrawingTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ LabelDrawingTypeEnum::~LabelDrawingTypeEnum() { } /** * Initialize the enumerated metadata. */ void LabelDrawingTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(LabelDrawingTypeEnum(DRAW_FILLED, "DRAW_FILLED", "Filled")); enumData.push_back(LabelDrawingTypeEnum(DRAW_FILLED_WITH_OUTLINE_COLOR, "DRAW_FILLED_WITH_OUTLINE_COLOR", "Filled and Outline Color")); enumData.push_back(LabelDrawingTypeEnum(DRAW_OUTLINE_COLOR, "DRAW_OUTLINE_COLOR", "Outline Color")); enumData.push_back(LabelDrawingTypeEnum(DRAW_OUTLINE_LABEL_COLOR, "DRAW_OUTLINE_LABEL_COLOR", "Outline Label Color")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const LabelDrawingTypeEnum* LabelDrawingTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const LabelDrawingTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString LabelDrawingTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const LabelDrawingTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ LabelDrawingTypeEnum::Enum LabelDrawingTypeEnum::fromName(const AString& nameIn, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = DRAW_FILLED; AString name = nameIn; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const LabelDrawingTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type LabelDrawingTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString LabelDrawingTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const LabelDrawingTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ LabelDrawingTypeEnum::Enum LabelDrawingTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = DRAW_FILLED; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const LabelDrawingTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type LabelDrawingTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t LabelDrawingTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const LabelDrawingTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ LabelDrawingTypeEnum::Enum LabelDrawingTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = DRAW_FILLED; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const LabelDrawingTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type LabelDrawingTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void LabelDrawingTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void LabelDrawingTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(LabelDrawingTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void LabelDrawingTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(LabelDrawingTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Files/LabelDrawingTypeEnum.h000066400000000000000000000064271360521144700236700ustar00rootroot00000000000000#ifndef __LABEL_DRAWING_TYPE_ENUM__H_ #define __LABEL_DRAWING_TYPE_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class LabelDrawingTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Filled in label's color */ DRAW_FILLED, /** Filled in label's color with outline color */ DRAW_FILLED_WITH_OUTLINE_COLOR, /** Outline with Outline Color */ DRAW_OUTLINE_COLOR, /** Outline with label color */ DRAW_OUTLINE_LABEL_COLOR }; ~LabelDrawingTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: LabelDrawingTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const LabelDrawingTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __LABEL_DRAWING_TYPE_ENUM_DECLARE__ std::vector LabelDrawingTypeEnum::enumData; bool LabelDrawingTypeEnum::initializedFlag = false; int32_t LabelDrawingTypeEnum::integerCodeCounter = 0; #endif // __LABEL_DRAWING_TYPE_ENUM_DECLARE__ } // namespace #endif //__LABEL_DRAWING_TYPE_ENUM__H_ connectome-workbench-1.4.2/src/Files/LabelFile.cxx000066400000000000000000000403501360521144700220310ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "CaretLogger.h" #include "GroupAndNameHierarchyModel.h" #include "DataFileException.h" #include "DataFileTypeEnum.h" #include "GiftiFile.h" #include "GiftiLabel.h" #include "MathFunctions.h" #include "LabelFile.h" using namespace caret; /** * Constructor. */ LabelFile::LabelFile() : GiftiTypeFile(DataFileTypeEnum::LABEL) { m_classNameHierarchy = NULL; this->initializeMembersLabelFile(); } /** * Copy constructor. * * @param sf * Surface file that is copied. */ LabelFile::LabelFile(const LabelFile& sf) : GiftiTypeFile(sf) { m_classNameHierarchy = NULL; this->copyHelperLabelFile(sf); } /** * Assignment operator. * * @param sf * Surface file that is copied. * @return * This surface file with content replaced * by the LabelFile parameter. */ LabelFile& LabelFile::operator=(const LabelFile& sf) { if (this != &sf) { GiftiTypeFile::operator=(sf); this->copyHelperLabelFile(sf); } return *this; } /** * Destructor. */ LabelFile::~LabelFile() { this->columnDataPointers.clear(); delete m_classNameHierarchy; } void LabelFile::writeFile(const AString& filename) { if (!filename.endsWith(".label.gii")) { CaretLogWarning("label file '" + filename + "' should be saved ending in .label.gii, see wb_command -gifti-help"); } caret::GiftiTypeFile::writeFile(filename); } /** * Clear the surface file. */ void LabelFile::clear() { GiftiTypeFile::clear(); this->columnDataPointers.clear(); m_classNameHierarchy->clear(); } /** * @return Return the GIFTI Label Table. */ GiftiLabelTable* LabelFile::getLabelTable() { return this->giftiFile->getLabelTable(); } /** * @return Return the GIFTI Label Table. */ const GiftiLabelTable* LabelFile::getLabelTable() const { return this->giftiFile->getLabelTable(); } /** * @return The class and name hierarchy. */ GroupAndNameHierarchyModel* LabelFile::getGroupAndNameHierarchyModel() { m_classNameHierarchy->update(this, m_forceUpdateOfGroupAndNameHierarchy); m_forceUpdateOfGroupAndNameHierarchy = false; return m_classNameHierarchy; } /** * @return The class and name hierarchy. */ const GroupAndNameHierarchyModel* LabelFile::getGroupAndNameHierarchyModel() const { m_classNameHierarchy->update(const_cast(this), m_forceUpdateOfGroupAndNameHierarchy); m_forceUpdateOfGroupAndNameHierarchy = false; return m_classNameHierarchy; } /** * Validate the contents of the file after it * has been read such as correct number of * data arrays and proper data types/dimensions. */ void LabelFile::validateDataArraysAfterReading() { this->columnDataPointers.clear(); this->initializeMembersLabelFile(); this->verifyDataArraysHaveSameNumberOfRows(0, 0); bool haveWarned = false; const int32_t numberOfDataArrays = this->giftiFile->getNumberOfDataArrays(); for (int32_t i = 0; i < numberOfDataArrays; i++) { GiftiDataArray* thisArray = this->giftiFile->getDataArray(i); if (thisArray->getDataType() != NiftiDataTypeEnum::NIFTI_TYPE_INT32) { thisArray->convertToDataType(NiftiDataTypeEnum::NIFTI_TYPE_INT32); if (!haveWarned) { CaretLogWarning("label file '" + getFileName() + "' contains data array with data type other than int32"); haveWarned = true; } } int32_t* tempPointer = thisArray->getDataPointerInt(); CaretAssert(tempPointer != NULL); if (tempPointer == NULL) throw DataFileException(getFileName(), "failed to convert data array to int32.");//shouldn't happen, can probably be removed this->columnDataPointers.push_back(tempPointer); } validateKeysAndLabels(); m_classNameHierarchy->update(this, true); m_forceUpdateOfGroupAndNameHierarchy = false; m_classNameHierarchy->setAllSelected(true); CaretLogFiner("CLASS/NAME Table for : " + this->getFileNameNoPath() + "\n" + m_classNameHierarchy->toString()); } /** * Validate keys and labels in the file. */ void LabelFile::validateKeysAndLabels() const { /* * Skip if logging is not fine or less. */ if (CaretLogger::getLogger()->isFine() == false) { return; } AString message; /* * Find the label keys that are in the data */ std::set dataKeys; const int32_t numNodes = getNumberOfNodes(); const int32_t numMaps = getNumberOfMaps(); for (int32_t iNode = 0; iNode < numNodes; iNode++) { for (int32_t jMap = 0; jMap < numMaps; jMap++) { const int32_t key = getLabelKey(iNode, jMap); dataKeys.insert(key); } } /* * Find any keys that are not in the label table */ const GiftiLabelTable* labelTable = getLabelTable(); std::set missingLabelKeys; for (std::set::iterator dataKeyIter = dataKeys.begin(); dataKeyIter != dataKeys.end(); dataKeyIter++) { const int32_t dataKey = *dataKeyIter; const GiftiLabel* label = labelTable->getLabel(dataKey); if (label == NULL) { missingLabelKeys.insert(dataKey); } } if (missingLabelKeys.empty() == false) { for (std::set::iterator missingKeyIter = missingLabelKeys.begin(); missingKeyIter != missingLabelKeys.end(); missingKeyIter++) { const int32_t missingKey = *missingKeyIter; message.appendWithNewLine(" Missing Label for Key: " + AString::number(missingKey)); } } /* * Find any label table names that are not used */ std::map labelTableKeysAndNames; labelTable->getKeysAndNames(labelTableKeysAndNames); for (std::map::const_iterator ltIter = labelTableKeysAndNames.begin(); ltIter != labelTableKeysAndNames.end(); ltIter++) { const int32_t ltKey = ltIter->first; if (std::find(dataKeys.begin(), dataKeys.end(), ltKey) == dataKeys.end()) { message.appendWithNewLine(" Label Not Used Key=" + AString::number(ltKey) + ": " + ltIter->second); } } AString msg = ("File: " + getFileName() + "\n" + labelTable->toFormattedString(" ") + message); CaretLogFine(msg); } /** * Get the number of nodes. * * @return * The number of nodes. */ int32_t LabelFile::getNumberOfNodes() const { int32_t numNodes = 0; int32_t numDataArrays = this->giftiFile->getNumberOfDataArrays(); if (numDataArrays > 0) { numNodes = this->giftiFile->getDataArray(0)->getNumberOfRows(); } return numNodes; } /** * Get the number of columns. * * @return * The number of columns. */ int32_t LabelFile::getNumberOfColumns() const { const int32_t numCols = this->giftiFile->getNumberOfDataArrays(); return numCols; } /** * Initialize members of this class. */ void LabelFile::initializeMembersLabelFile() { if (m_classNameHierarchy != NULL) { delete m_classNameHierarchy; } m_classNameHierarchy = new GroupAndNameHierarchyModel(); m_forceUpdateOfGroupAndNameHierarchy = true; } /** * Helps copying files. * * @param sf * File that is copied. */ void LabelFile::copyHelperLabelFile(const LabelFile& /*sf*/) { if (m_classNameHierarchy != NULL) { delete m_classNameHierarchy; } m_classNameHierarchy = new GroupAndNameHierarchyModel(); m_forceUpdateOfGroupAndNameHierarchy = true; this->validateDataArraysAfterReading(); } /** * Get label name for a node. * * @param nodeIndex * Node index. * @param columnIndex * Column index. * @return * Label name at the given node and column indices * Empty string if label is not available. */ AString LabelFile::getLabelName(const int32_t nodeIndex, const int32_t columnIndex) const { const int32_t labelKey = this->getLabelKey(nodeIndex, columnIndex); AString label = this->giftiFile->getLabelTable()->getLabelName(labelKey); return label; } /** * Get label key for a node. * * @param nodeIndex * Node index. * @param columnIndex * Column index. * @return * Label key at the given node and column indices. */ int32_t LabelFile::getLabelKey(const int32_t nodeIndex, const int32_t columnIndex) const { CaretAssertVectorIndex(this->columnDataPointers, columnIndex); CaretAssertMessage((nodeIndex >= 0) && (nodeIndex < this->getNumberOfNodes()), "Node Index out of range."); return this->columnDataPointers[columnIndex][nodeIndex]; } /** * set label key for a node. * * @param nodeIndex * Node index. * @param columnIndex * Column index. * param labelKey * Label key inserted at the given node and column indices. */ void LabelFile::setLabelKey(const int32_t nodeIndex, const int32_t columnIndex, const int32_t labelKey) { CaretAssertVectorIndex(this->columnDataPointers, columnIndex); CaretAssertMessage((nodeIndex >= 0) && (nodeIndex < this->getNumberOfNodes()), "Node Index out of range."); this->columnDataPointers[columnIndex][nodeIndex] = labelKey; this->setModified(); m_forceUpdateOfGroupAndNameHierarchy = true; } /** * Get nodes in the given column with the given lable key. * @param columnIndex * Index of column * @param labelKey * Key of label that is desired. * @param nodeIndicesOut * On exit, will contain indices of nodes that have the * given label key in the given column. */ void LabelFile::getNodeIndicesWithLabelKey(const int32_t columnIndex, const int32_t labelKey, std::vector& nodeIndicesOut) const { const int32_t numberOfNodes = this->getNumberOfNodes(); nodeIndicesOut.clear(); nodeIndicesOut.reserve(numberOfNodes); for (int32_t i = 0; i < numberOfNodes; i++) { if (this->getLabelKey(i, columnIndex) == labelKey) { nodeIndicesOut.push_back(i); } } } /** * Get a pointer to the keys for a label file column. * @param columnIndex * Index of the column. * @return * Pointer to keys for the given column. */ const int32_t* LabelFile::getLabelKeyPointerForColumn(const int32_t columnIndex) const { CaretAssertVectorIndex(this->columnDataPointers, columnIndex); return this->columnDataPointers[columnIndex]; } void LabelFile::setNumberOfNodesAndColumns(int32_t nodes, int32_t columns) { giftiFile->clearAndKeepMetadata(); columnDataPointers.clear(); const int32_t unassignedKey = this->getLabelTable()->getUnassignedLabelKey(); std::vector dimensions; dimensions.push_back(nodes); for (int32_t i = 0; i < columns; ++i) { giftiFile->addDataArray(new GiftiDataArray(NiftiIntentEnum::NIFTI_INTENT_LABEL, NiftiDataTypeEnum::NIFTI_TYPE_INT32, dimensions, GiftiEncodingEnum::GZIP_BASE64_BINARY)); columnDataPointers.push_back(giftiFile->getDataArray(i)->getDataPointerInt()); int32_t* ptr = giftiFile->getDataArray(i)->getDataPointerInt(); for (int32_t j = 0; j < nodes; j++) { ptr[j] = unassignedKey; } } setModified(); m_forceUpdateOfGroupAndNameHierarchy = true; } /** * Add map(s) to this GIFTI file. * @param numberOfNodes * Number of nodes. If file is not empty, this value must * match the number of nodes that are in the file. * @param numberOfMaps * Number of maps to add. */ void LabelFile::addMaps(const int32_t numberOfNodes, const int32_t numberOfMaps) { if (numberOfNodes <= 0) { throw DataFileException(getFileName(), "When adding maps the number of nodes must be greater than zero"); } if (this->getNumberOfNodes() > 0) { if (numberOfNodes != this->getNumberOfNodes()) { throw DataFileException(getFileName(), "When adding maps the requested number of nodes is " + AString::number(numberOfNodes) + " but the file contains " + AString::number(this->getNumberOfNodes()) + " nodes."); } } if (numberOfMaps <= 0) { throw DataFileException(getFileName(), "When adding maps, the number of maps must be greater than zero."); } const int32_t unassignedKey = this->getLabelTable()->getUnassignedLabelKey(); if ((this->getNumberOfNodes() > 0) && (this->getNumberOfMaps() > 0)) { std::vector dimensions; dimensions.push_back(numberOfNodes); for (int32_t i = 0; i < numberOfMaps; ++i) { this->giftiFile->addDataArray(new GiftiDataArray(NiftiIntentEnum::NIFTI_INTENT_LABEL, NiftiDataTypeEnum::NIFTI_TYPE_INT32, dimensions, GiftiEncodingEnum::GZIP_BASE64_BINARY)); const int32_t mapIndex = giftiFile->getNumberOfDataArrays() - 1; this->columnDataPointers.push_back(giftiFile->getDataArray(mapIndex)->getDataPointerInt()); int32_t* ptr = giftiFile->getDataArray(mapIndex)->getDataPointerInt(); for (int32_t j = 0; j < numberOfNodes; j++) { ptr[j] = unassignedKey; } } } else { this->setNumberOfNodesAndColumns(numberOfNodes, numberOfMaps); } m_forceUpdateOfGroupAndNameHierarchy = true; this->setModified(); } void LabelFile::setLabelKeysForColumn(const int32_t columnIndex, const int32_t* valuesIn) { CaretAssertVectorIndex(this->columnDataPointers, columnIndex); int32_t* myColumn = columnDataPointers[columnIndex]; int numNodes = (int)getNumberOfNodes(); for (int i = 0; i < numNodes; ++i) { myColumn[i] = valuesIn[i]; } m_forceUpdateOfGroupAndNameHierarchy = true; setModified(); } /** * Return a vector containing the keys used in a map. Each key is listed * once and the keys will be in ascending order. * @param mapIndex * Index of map. * @return * Vector containing the keys. */ std::vector LabelFile::getUniqueLabelKeysUsedInMap(const int32_t mapIndex) const { CaretAssertVectorIndex(this->columnDataPointers, mapIndex); std::set uniqueKeys; const int32_t numNodes = getNumberOfNodes(); for (int32_t i = 0; i < numNodes; i++) { const int32_t key = getLabelKey(i, mapIndex); uniqueKeys.insert(key); } std::vector keyVector; keyVector.insert(keyVector.end(), uniqueKeys.begin(), uniqueKeys.end()); return keyVector; } connectome-workbench-1.4.2/src/Files/LabelFile.h000066400000000000000000000075431360521144700214650ustar00rootroot00000000000000 #ifndef __LABEL_FILE_H__ #define __LABEL_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "GiftiTypeFile.h" namespace caret { class GroupAndNameHierarchyModel; class GiftiDataArray; class GiftiLabelTable; /** * \brief A Label data file. */ class LabelFile : public GiftiTypeFile { public: LabelFile(); LabelFile(const LabelFile& sf); LabelFile& operator=(const LabelFile& sf); virtual ~LabelFile(); void clear(); int32_t getNumberOfNodes() const; int32_t getNumberOfColumns() const; void setNumberOfNodesAndColumns(int32_t nodes, int32_t columns); virtual void addMaps(const int32_t numberOfNodes, const int32_t numberOfMaps); GiftiLabelTable* getLabelTable(); const GiftiLabelTable* getLabelTable() const; int32_t getLabelKey(const int32_t nodeIndex, const int32_t columnIndex) const; AString getLabelName(const int32_t nodeIndex, const int32_t columnIndex) const; void setLabelKey(const int32_t nodeIndex, const int32_t columnIndex, const int32_t labelIndex); void getNodeIndicesWithLabelKey(const int32_t columnIndex, const int32_t labelKey, std::vector& nodeIndicesOut) const; const int32_t* getLabelKeyPointerForColumn(const int32_t columnIndex) const; void setLabelKeysForColumn(const int32_t columnIndex, const int32_t* keysIn); std::vector getUniqueLabelKeysUsedInMap(const int32_t mapIndex) const; GroupAndNameHierarchyModel* getGroupAndNameHierarchyModel(); const GroupAndNameHierarchyModel* getGroupAndNameHierarchyModel() const; //override writeFile in order to check filename against type of file virtual void writeFile(const AString& filename); protected: /** * Validate the contents of the file after it * has been read such as correct number of * data arrays and proper data types/dimensions. */ virtual void validateDataArraysAfterReading(); void copyHelperLabelFile(const LabelFile& sf); void initializeMembersLabelFile(); private: void validateKeysAndLabels() const; /** Points to actual data in each Gifti Data Array */ std::vector columnDataPointers; /** Holds class and name hierarchy used for display selection */ mutable GroupAndNameHierarchyModel* m_classNameHierarchy; /** force an update of the class and name hierarchy */ mutable bool m_forceUpdateOfGroupAndNameHierarchy; }; } // namespace #endif // __LABEL_FILE_H__ connectome-workbench-1.4.2/src/Files/MapYokingGroupEnum.cxx000066400000000000000000000357061360521144700237630ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __MAP_YOKING_GROUP_ENUM_DECLARE__ #include "MapYokingGroupEnum.h" #undef __MAP_YOKING_GROUP_ENUM_DECLARE__ #include "CaretAssert.h" #include "EventManager.h" using namespace caret; /** * \class caret::MapYokingGroupEnum * \brief Enumerated types for map yoking selection. */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ MapYokingGroupEnum::MapYokingGroupEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; this->mapIndex = 0; this->enabledStatus = false; } /** * Destructor. */ MapYokingGroupEnum::~MapYokingGroupEnum() { } /** * Initialize the enumerated metadata. */ void MapYokingGroupEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(MapYokingGroupEnum(MAP_YOKING_GROUP_OFF, "MAP_YOKING_GROUP_OFF", "Off")); enumData.push_back(MapYokingGroupEnum(MAP_YOKING_GROUP_1, "MAP_YOKING_GROUP_1", "I")); enumData.push_back(MapYokingGroupEnum(MAP_YOKING_GROUP_2, "MAP_YOKING_GROUP_2", "II")); enumData.push_back(MapYokingGroupEnum(MAP_YOKING_GROUP_3, "MAP_YOKING_GROUP_3", "III")); enumData.push_back(MapYokingGroupEnum(MAP_YOKING_GROUP_4, "MAP_YOKING_GROUP_4", "IV")); enumData.push_back(MapYokingGroupEnum(MAP_YOKING_GROUP_5, "MAP_YOKING_GROUP_5", "V")); enumData.push_back(MapYokingGroupEnum(MAP_YOKING_GROUP_6, "MAP_YOKING_GROUP_6", "VI")); enumData.push_back(MapYokingGroupEnum(MAP_YOKING_GROUP_7, "MAP_YOKING_GROUP_7", "VII")); enumData.push_back(MapYokingGroupEnum(MAP_YOKING_GROUP_8, "MAP_YOKING_GROUP_8", "VIII")); enumData.push_back(MapYokingGroupEnum(MAP_YOKING_GROUP_9, "MAP_YOKING_GROUP_9", "IX")); enumData.push_back(MapYokingGroupEnum(MAP_YOKING_GROUP_10, "MAP_YOKING_GROUP_10", "X")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ MapYokingGroupEnum* MapYokingGroupEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { MapYokingGroupEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString MapYokingGroupEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const MapYokingGroupEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ MapYokingGroupEnum::Enum MapYokingGroupEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = MAP_YOKING_GROUP_OFF; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const MapYokingGroupEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type MapYokingGroupEnum")); } return enumValue; } /** * Get an enumerated value corresponding to the * obsolete OverlayYokingGroupEnum that has been replaced * with MapYokingGroupEnum. * * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ MapYokingGroupEnum::Enum MapYokingGroupEnum::fromOverlayYokingGroupEnumName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = MAP_YOKING_GROUP_OFF; if (name == "OVERLAY_YOKING_GROUP_OFF") { enumValue = MAP_YOKING_GROUP_OFF; validFlag = true; } else if (name == "OVERLAY_YOKING_GROUP_1") { enumValue = MAP_YOKING_GROUP_1; validFlag = true; } else if (name == "OVERLAY_YOKING_GROUP_2") { enumValue = MAP_YOKING_GROUP_2; validFlag = true; } else if (name == "OVERLAY_YOKING_GROUP_3") { enumValue = MAP_YOKING_GROUP_3; validFlag = true; } else if (name == "OVERLAY_YOKING_GROUP_4") { enumValue = MAP_YOKING_GROUP_4; validFlag = true; } else if (name == "OVERLAY_YOKING_GROUP_5") { enumValue = MAP_YOKING_GROUP_5; validFlag = true; } else if (name == "OVERLAY_YOKING_GROUP_6") { enumValue = MAP_YOKING_GROUP_6; validFlag = true; } else if (name == "OVERLAY_YOKING_GROUP_7") { enumValue = MAP_YOKING_GROUP_7; validFlag = true; } else if (name == "OVERLAY_YOKING_GROUP_8") { enumValue = MAP_YOKING_GROUP_8; validFlag = true; } else if (name == "OVERLAY_YOKING_GROUP_9") { enumValue = MAP_YOKING_GROUP_9; validFlag = true; } else if (name == "OVERLAY_YOKING_GROUP_10") { enumValue = MAP_YOKING_GROUP_10; validFlag = true; } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type MapYokingGroupEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString MapYokingGroupEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const MapYokingGroupEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ MapYokingGroupEnum::Enum MapYokingGroupEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = MAP_YOKING_GROUP_OFF; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const MapYokingGroupEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type MapYokingGroupEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t MapYokingGroupEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const MapYokingGroupEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ MapYokingGroupEnum::Enum MapYokingGroupEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = MAP_YOKING_GROUP_OFF; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const MapYokingGroupEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type MapYokingGroupEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void MapYokingGroupEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void MapYokingGroupEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(MapYokingGroupEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void MapYokingGroupEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(MapYokingGroupEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } /** * @return The selected map index associated with the given value. * * @param enumValue * Value for which map index is requested. */ int32_t MapYokingGroupEnum::getSelectedMapIndex(const Enum enumValue) { CaretAssertMessage(enumValue != MAP_YOKING_GROUP_OFF, "Never should be called with MAP_YOKING_GROUP_OFF"); if (initializedFlag == false) initialize(); MapYokingGroupEnum* enumInstance = findData(enumValue); return enumInstance->mapIndex; } /** * Set the map index for the given enum value. * * @param enumValue * Value for which map index is requested. * @param mapIndex * New value for map index. */ void MapYokingGroupEnum::setSelectedMapIndex(const Enum enumValue, const int32_t mapIndex) { CaretAssertMessage(enumValue != MAP_YOKING_GROUP_OFF, "Never should be called with MAP_YOKING_GROUP_OFF"); if (initializedFlag == false) initialize(); MapYokingGroupEnum* enumInstance = findData(enumValue); enumInstance->mapIndex = mapIndex; } /** * @return The enabled status associated with the given value. * * @param enumValue * Value for which map index is requested. */ bool MapYokingGroupEnum::isEnabled(const Enum enumValue) { CaretAssertMessage(enumValue != MAP_YOKING_GROUP_OFF, "Never should be called with MAP_YOKING_GROUP_OFF"); if (initializedFlag == false) initialize(); MapYokingGroupEnum* enumInstance = findData(enumValue); return enumInstance->enabledStatus; } /** * Set the enabled status for the given enum value. * * @param enumValue * Value for which map index is requested. * @param enabled * New value for enabled status. */ void MapYokingGroupEnum::setEnabled(const Enum enumValue, const bool enabled) { CaretAssertMessage(enumValue != MAP_YOKING_GROUP_OFF, "Never should be called with MAP_YOKING_GROUP_OFF"); if (initializedFlag == false) initialize(); MapYokingGroupEnum* enumInstance = findData(enumValue); enumInstance->enabledStatus = enabled; } connectome-workbench-1.4.2/src/Files/MapYokingGroupEnum.h000066400000000000000000000101421360521144700233730ustar00rootroot00000000000000#ifndef __MAP_YOKING_GROUP_ENUM_H__ #define __MAP_YOKING_GROUP_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class MapYokingGroupEnum { public: /** * Enumerated values. */ enum Enum { /** Off */ MAP_YOKING_GROUP_OFF, /** Group 1 */ MAP_YOKING_GROUP_1, /** Group 2 */ MAP_YOKING_GROUP_2, /** Group 3*/ MAP_YOKING_GROUP_3, /** Group 4 */ MAP_YOKING_GROUP_4, /** Group 5 */ MAP_YOKING_GROUP_5, /** Group 6 */ MAP_YOKING_GROUP_6, /** Group 7 */ MAP_YOKING_GROUP_7, /** Group 8 */ MAP_YOKING_GROUP_8, /** Group 9 */ MAP_YOKING_GROUP_9, /** Group 10 */ MAP_YOKING_GROUP_10 }; ~MapYokingGroupEnum(); static Enum fromOverlayYokingGroupEnumName(const AString& name, bool* isValidOut); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); static int32_t getSelectedMapIndex(const Enum enumValue); static void setSelectedMapIndex( const Enum enumValue, const int32_t mapIndex); static bool isEnabled(const Enum enumValue); static void setEnabled(const Enum enumValue, const bool enabled); private: MapYokingGroupEnum(const Enum enumValue, const AString& name, const AString& guiName); static MapYokingGroupEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; /** Index of the selected map */ int32_t mapIndex; /** Enabled status of the map */ bool enabledStatus; }; #ifdef __MAP_YOKING_GROUP_ENUM_DECLARE__ std::vector MapYokingGroupEnum::enumData; bool MapYokingGroupEnum::initializedFlag = false; int32_t MapYokingGroupEnum::integerCodeCounter = 0; #endif // __MAP_YOKING_GROUP_ENUM_DECLARE__ } // namespace #endif //__MAP_YOKING_GROUP_ENUM_H__ connectome-workbench-1.4.2/src/Files/MetricDynamicConnectivityFile.cxx000066400000000000000000000511341360521144700261430ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __METRIC_DYNAMIC_CONNECTIVITY_FILE_DECLARE__ #include "MetricDynamicConnectivityFile.h" #undef __METRIC_DYNAMIC_CONNECTIVITY_FILE_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "ConnectivityCorrelation.h" #include "ConnectivityDataLoaded.h" #include "DataFileException.h" #include "FileInformation.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::MetricDynamicConnectivityFile * \brief Dynamic connectivity from metric file * \ingroup Files */ /** * Constructor. * @param parentMetricFile * The parent metric file. */ MetricDynamicConnectivityFile::MetricDynamicConnectivityFile(MetricFile* parentMetricFile) : MetricFile(DataFileTypeEnum::METRIC_DYNAMIC), m_parentMetricFile(parentMetricFile) { CaretAssert(m_parentMetricFile); m_connectivityDataLoaded.reset(new ConnectivityDataLoaded()); m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); m_sceneAssistant->add("m_dataLoadingEnabledFlag", &m_dataLoadingEnabledFlag); m_sceneAssistant->add("m_enabledAsLayer", &m_enabledAsLayer); m_sceneAssistant->add("m_connectivityDataLoaded", "ConnectivityDataLoaded", m_connectivityDataLoaded.get()); } /** * Destructor. */ MetricDynamicConnectivityFile::~MetricDynamicConnectivityFile() { } /** * Clear the file. */ void MetricDynamicConnectivityFile::clear() { MetricFile::clear(); clearPrivateData(); } /** * Clear the file. */ void MetricDynamicConnectivityFile::clearPrivateData() { m_numberOfVertices = 0; m_validDataFlag = false; m_enabledAsLayer = false; m_connectivityCorrelation.reset(); m_connectivityDataLoaded->reset(); } /** * @return Pointer to the information about last loaded connectivity data. */ const ConnectivityDataLoaded* MetricDynamicConnectivityFile::getConnectivityDataLoaded() const { return m_connectivityDataLoaded.get(); } /** * @return True if enabled as a layer. */ bool MetricDynamicConnectivityFile::isEnabledAsLayer() const { return m_enabledAsLayer; } /** * Set enabled as a layer. * * @param True if enabled as a layer. */ void MetricDynamicConnectivityFile::setEnabledAsLayer(const bool enabled) { m_enabledAsLayer = enabled; } /** * @return True if data loading enabled. */ bool MetricDynamicConnectivityFile::isDataLoadingEnabled() const { return m_dataLoadingEnabledFlag; } /** * Set data loading enabled. * * @param True if data loading enabled. */ void MetricDynamicConnectivityFile::setDataLoadingEnabled(const bool enabled) { m_dataLoadingEnabledFlag = enabled; } /** * Initialize the file using information from parent volume file */ void MetricDynamicConnectivityFile::initializeFile() { clearPrivateData(); CaretAssert(m_parentMetricFile); m_numberOfVertices = m_parentMetricFile->getNumberOfNodes(); const int32_t numberOfMaps = 1; setNumberOfNodesAndColumns(m_numberOfVertices, numberOfMaps); setStructure(m_parentMetricFile->getStructure()); CaretAssert(getNumberOfNodes() == m_numberOfVertices); CaretAssert(getNumberOfMaps() == numberOfMaps); AString path, nameNoExt, ext; FileInformation fileInfo(m_parentMetricFile->getFileName()); fileInfo.getFileComponents(path, nameNoExt, ext); setFileName(FileInformation::assembleFileComponents(path, nameNoExt, DataFileTypeEnum::toFileExtension(DataFileTypeEnum::METRIC_DYNAMIC))); clearVertexValues(); clearModified(); m_validDataFlag = true; } /** * @return True if this file type supports writing, else false. * * Dense files do NOT support writing. */ bool MetricDynamicConnectivityFile::supportsWriting() const { return false; } /** * @return The parent volume file */ MetricFile* MetricDynamicConnectivityFile::getParentMetricFile() { return const_cast(m_parentMetricFile); } /** * @return The parent metric file (const method) */ const MetricFile* MetricDynamicConnectivityFile::getParentMetricFile() const { return m_parentMetricFile; } /** * @return True if the data is valid */ bool MetricDynamicConnectivityFile::isDataValid() const { return m_validDataFlag; } /** * Add information about the file to the data file information. * * @param dataFileInformation * Consolidates information about a data file. */ void MetricDynamicConnectivityFile::addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) { MetricFile::addToDataFileContentInformation(dataFileInformation); } /** * Read the file with the given name. * * @param filename * Name of file * @throws DataFileException * If error occurs */ void MetricDynamicConnectivityFile::readFile(const AString& /*filename*/) { throw DataFileException("Read of Metric Dynamic Connectivity File is not allowed"); } /** * Read the file with the given name. * * @param filename * Name of file * @throws DataFileException * If error occurs */ void MetricDynamicConnectivityFile::writeFile(const AString& /*filename*/) { throw DataFileException("Writing of Metric Dynamic Connectivity File is not allowed"); } /** * Clear voxels in this volume */ void MetricDynamicConnectivityFile::clearVertexValues() { CaretAssert(getNumberOfMaps() == 1); const int32_t mapIndex(0); const float value(0.0f); initializeColumn(mapIndex, value); m_dataLoadedName = ""; } /** * Load connectivity data for the surface's node. * * @param surfaceNumberOfNodes * Number of nodes in surface. * @param structure * Surface's structure. * @param nodeIndex * Index of node number. * @return * True if data was loaded, else false. */ bool MetricDynamicConnectivityFile::loadDataForSurfaceNode(const int32_t surfaceNumberOfNodes, const StructureEnum::Enum structure, const int32_t nodeIndex) { bool validFlag(false); if ( ! isDataValid()) { return validFlag; } if ( ! m_dataLoadingEnabledFlag) { return validFlag; } if (getStructure() != structure) { return validFlag; } if (getNumberOfNodes() != surfaceNumberOfNodes) { return validFlag; } clearVertexValues(); m_connectivityDataLoaded->reset(); std::vector data; if (getConnectivityForVertexIndex(nodeIndex, data)) { CaretAssert(m_numberOfVertices == static_cast(data.size())); float* dataPointer = const_cast(getValuePointerForColumn(0)); CaretAssert(dataPointer); std::copy(data.begin(), data.end(), dataPointer); validFlag = true; m_connectivityDataLoaded->setSurfaceNodeLoading(getStructure(), getNumberOfNodes(), nodeIndex, -1, - 1); } const int32_t mapIndex(0); const AString mapName("Vertex_Index_" + AString::number(nodeIndex) + "_Structure_" + StructureEnum::toGuiName(structure)); setMapName(mapIndex, mapName); m_dataLoadedName = mapName; updateAfterFileDataChanges(); updateScalarColoringForMap(0); return validFlag; } /** * Load connectivity data for the surface's nodes and then average the data. * * @param surfaceNumberOfNodes * Number of nodes in surface. * @param structure * Surface's structure. * @param nodeIndices * Indices of nodes. * @return * True if data was loaded, else false. */ bool MetricDynamicConnectivityFile::loadAverageDataForSurfaceNodes(const int32_t surfaceNumberOfNodes, const StructureEnum::Enum structure, const std::vector& nodeIndices) { bool validFlag(false); if ( ! isDataValid()) { return validFlag; } if ( ! m_dataLoadingEnabledFlag) { return validFlag; } if (getStructure() != structure) { return validFlag; } if (getNumberOfNodes() != surfaceNumberOfNodes) { return validFlag; } if (nodeIndices.size() < 2) { return validFlag; } ConnectivityCorrelation* connCorrelation = getConnectivityCorrelation(); if (connCorrelation == NULL) { return validFlag; } clearVertexValues(); m_connectivityDataLoaded->reset(); float* dataPointer = const_cast(getValuePointerForColumn(0)); CaretAssert(dataPointer); std::vector nodeIndices64(nodeIndices.begin(), nodeIndices.end()); std::vector data(getNumberOfNodes()); connCorrelation->getCorrelationForBrainordinateROI(nodeIndices64, data); const int64_t numData = static_cast(data.size()); validFlag = (numData == getNumberOfNodes()); if (validFlag) { for (int64_t i = 0; i < numData; i++) { dataPointer[i] = data[i]; } } m_connectivityDataLoaded->setSurfaceAverageNodeLoading(getStructure(), getNumberOfNodes(), nodeIndices); const AString mapName("Average_Vertex_Count_" + AString::number(static_cast(nodeIndices.size()))); m_dataLoadedName = mapName; const int32_t mapIndex(0); setMapName(mapIndex, mapName); updateAfterFileDataChanges(); updateScalarColoringForMap(0); return validFlag; } /** * Get the connectivity for the given vertex index. * If the vertex index is invalid, zeros are loaded into all voxels. * * @param vertexIndex * The vertex index. * @param vertexDataOut * Output containing vertex data * @return * True if data was loaded. */ bool MetricDynamicConnectivityFile::getConnectivityForVertexIndex(const int32_t vertexIndex, std::vector& vertexDataOut) { bool validFlag(false); if ((vertexIndex >= 0) && (vertexIndex < getNumberOfNodes())) { ConnectivityCorrelation* connCorrelation = getConnectivityCorrelation(); if (connCorrelation) { connCorrelation->getCorrelationForBrainordinate(vertexIndex, vertexDataOut); CaretAssert(m_numberOfVertices == static_cast(vertexDataOut.size())); validFlag = true; } } if ( ! validFlag) { vertexDataOut.resize(m_numberOfVertices); std::fill(vertexDataOut.begin(), vertexDataOut.end(), 0.0f); } updateAfterFileDataChanges(); invalidateHistogramChartColoring(); return validFlag; } /** * @return Pointer to connectivity correlation or NULL if not valid */ ConnectivityCorrelation* MetricDynamicConnectivityFile::getConnectivityCorrelation() { if ( ! m_connectivityCorrelationFailedFlag) { if (m_connectivityCorrelation == NULL) { /* * Need data and timepoint count from parent file */ CaretAssert(m_parentMetricFile); const int32_t numberOfTimePoints = m_parentMetricFile->getNumberOfMaps(); CaretAssert(numberOfTimePoints >= 2); std::vector timePointData; for (int32_t i = 0; i < numberOfTimePoints; i++) { const float* dataPtr = m_parentMetricFile->getValuePointerForColumn(i); CaretAssert(dataPtr); timePointData.push_back(dataPtr); } const int64_t brainordinateStride(1); AString errorMessage; ConnectivityCorrelation* cc = ConnectivityCorrelation::newInstanceTimePoints(timePointData, m_numberOfVertices, brainordinateStride, errorMessage); if (cc != NULL) { m_connectivityCorrelation.reset(cc); } else { m_connectivityCorrelationFailedFlag = true; CaretLogSevere("Failed to create connectvity correlation for " + m_parentMetricFile->getFileNameNoPath()); } } } return m_connectivityCorrelation.get(); } /** * @return A metric file using the loaded data (will return NULL if there is an error). * * @param directoryName * Directory for file * @param errorMessageOut * Contains error information */ MetricFile* MetricDynamicConnectivityFile::newMetricFileFromLoadedData(const AString& directoryName, AString& errorMessageOut) { errorMessageOut.clear(); bool validDataFlag(false); switch (m_connectivityDataLoaded->getMode()) { case ConnectivityDataLoaded::MODE_COLUMN: break; case ConnectivityDataLoaded::MODE_NONE: break; case ConnectivityDataLoaded::MODE_ROW: break; case ConnectivityDataLoaded::MODE_SURFACE_NODE: validDataFlag = true; break; case ConnectivityDataLoaded::MODE_SURFACE_NODE_AVERAGE: validDataFlag = true; break; case ConnectivityDataLoaded::MODE_VOXEL_IJK_AVERAGE: break; case ConnectivityDataLoaded::MODE_VOXEL_XYZ: break; } if ( ! validDataFlag) { errorMessageOut = "No metric connectivity data is loaded"; return NULL; } MetricFile* mf(NULL); try { const int32_t numVertices = getNumberOfNodes(); mf = new MetricFile(); mf->setStructure(getStructure()); mf->setNumberOfNodesAndColumns(numVertices, 1); mf->setValuesForColumn(0, this->getValuePointerForColumn(0)); /* * May need to convert a remote path to a local path */ FileInformation fileNameInfo(getFileName()); const AString metricFileName = fileNameInfo.getAsLocalAbsoluteFilePath(directoryName, mf->getDataFileType()); /* * Create name of metric file data loaded information */ FileInformation metricFileInfo(metricFileName); AString thePath, theName, theExtension; metricFileInfo.getFileComponents(thePath, theName, theExtension); theName.append("_" + m_dataLoadedName); AString newFileName = FileInformation::assembleFileComponents(thePath, theName, theExtension); mf->setFileName(newFileName); mf->setMapName(0, m_dataLoadedName); /* * Need to copy color palette since it may be the default */ PaletteColorMapping* metricPalette = mf->getMapPaletteColorMapping(0); CaretAssert(metricPalette); const PaletteColorMapping* myPalette = getMapPaletteColorMapping(0); CaretAssert(myPalette); metricPalette->copy(*myPalette, true); mf->updateAfterFileDataChanges(); mf->updateScalarColoringForMap(0); mf->setModified(); } catch (const DataFileException& dfe) { errorMessageOut = dfe.whatString(); if (mf != NULL) { delete mf; mf = NULL; } } return mf; } /** * Save data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void MetricDynamicConnectivityFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { MetricFile::saveFileDataToScene(sceneAttributes, sceneClass); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void MetricDynamicConnectivityFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { m_connectivityDataLoaded->reset(); MetricFile::restoreFileDataFromScene(sceneAttributes, sceneClass); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); switch (m_connectivityDataLoaded->getMode()) { case ConnectivityDataLoaded::MODE_COLUMN: break; case ConnectivityDataLoaded::MODE_NONE: break; case ConnectivityDataLoaded::MODE_ROW: break; case ConnectivityDataLoaded::MODE_SURFACE_NODE: { StructureEnum::Enum structure = StructureEnum::INVALID; int32_t surfaceNumberOfVertices(-1); int32_t vertexIndex(-1); int64_t rowIndex(-1); int64_t columnIndex(-1); m_connectivityDataLoaded->getSurfaceNodeLoading(structure, surfaceNumberOfVertices, vertexIndex, rowIndex, columnIndex); if (vertexIndex >= 0) { loadDataForSurfaceNode(surfaceNumberOfVertices, structure, vertexIndex); } } break; case ConnectivityDataLoaded::MODE_SURFACE_NODE_AVERAGE: { StructureEnum::Enum structure = StructureEnum::INVALID; int32_t surfaceNumberOfVertices(-1); std::vector vertexIndices; m_connectivityDataLoaded->getSurfaceAverageNodeLoading(structure, surfaceNumberOfVertices, vertexIndices); if ( ! vertexIndices.empty()) { loadAverageDataForSurfaceNodes(surfaceNumberOfVertices, structure, vertexIndices); } } break; case ConnectivityDataLoaded::MODE_VOXEL_IJK_AVERAGE: break; case ConnectivityDataLoaded::MODE_VOXEL_XYZ: break; } } connectome-workbench-1.4.2/src/Files/MetricDynamicConnectivityFile.h000066400000000000000000000113411360521144700255640ustar00rootroot00000000000000#ifndef __METRIC_DYNAMIC_CONNECTIVITY_FILE_H__ #define __METRIC_DYNAMIC_CONNECTIVITY_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "MetricFile.h" namespace caret { class ConnectivityCorrelation; class ConnectivityDataLoaded; class MetricDynamicConnectivityFile : public MetricFile { public: MetricDynamicConnectivityFile(MetricFile* parentMetricFile); virtual ~MetricDynamicConnectivityFile(); MetricDynamicConnectivityFile(const MetricDynamicConnectivityFile&) = delete; MetricDynamicConnectivityFile& operator=(const MetricDynamicConnectivityFile&) = delete; void initializeFile(); virtual void clear() override; virtual void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) override; virtual void readFile(const AString& filename) override; virtual void writeFile(const AString& filename) override; virtual bool supportsWriting() const override; MetricFile* getParentMetricFile(); const MetricFile* getParentMetricFile() const; bool isDataValid() const; bool isEnabledAsLayer() const; void setEnabledAsLayer(const bool enabled); bool loadConnectivityForVoxelXYZ(const float xyz[3]); bool loadMapAverageDataForVoxelIndices(const int64_t volumeDimensionIJK[3], const std::vector& voxelIndices); bool isDataLoadingEnabled() const; void setDataLoadingEnabled(const bool enabled); const ConnectivityDataLoaded* getConnectivityDataLoaded() const; bool loadDataForSurfaceNode(const int32_t surfaceNumberOfNodes, const StructureEnum::Enum structure, const int32_t nodeIndex); bool loadAverageDataForSurfaceNodes(const int32_t surfaceNumberOfNodes, const StructureEnum::Enum structure, const std::vector& nodeIndices); MetricFile* newMetricFileFromLoadedData(const AString& directoryName, AString& errorMessageOut); // ADD_NEW_METHODS_HERE protected: virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) override; virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) override; private: void clearPrivateData(); void clearVertexValues(); bool getConnectivityForVertexIndex(const int32_t vertexIndex, std::vector& vertexDataOut); ConnectivityCorrelation* getConnectivityCorrelation(); const MetricFile* m_parentMetricFile; std::unique_ptr m_sceneAssistant; std::unique_ptr m_connectivityCorrelation; AString m_dataLoadedName; int32_t m_numberOfVertices = 0; bool m_validDataFlag = false; bool m_enabledAsLayer = true; bool m_dataLoadingEnabledFlag = true; std::unique_ptr m_connectivityDataLoaded; bool m_connectivityCorrelationFailedFlag = false; // ADD_NEW_MEMBERS_HERE }; #ifdef __METRIC_DYNAMIC_CONNECTIVITY_FILE_DECLARE__ // #endif // __METRIC_DYNAMIC_CONNECTIVITY_FILE_DECLARE__ } // namespace #endif //__METRIC_DYNAMIC_CONNECTIVITY_FILE_H__ connectome-workbench-1.4.2/src/Files/MetricFile.cxx000066400000000000000000000727461360521144700222530ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "CaretLogger.h" #include "ChartDataCartesian.h" #include "ChartDataSource.h" #include "DataFileException.h" #include "DataFileTypeEnum.h" #include "GiftiFile.h" #include "MapFileDataSelector.h" #include "MathFunctions.h" #include "MetricDynamicConnectivityFile.h" #include "MetricFile.h" #include "NiftiEnums.h" #include "PaletteColorMapping.h" #include "SceneClass.h" #include using namespace caret; const AString MetricFile::s_paletteColorMappingNameInMetaData = "__DYNAMIC_FILE_PALETTE_COLOR_MAPPING__"; /** * Constructor. */ MetricFile::MetricFile() : GiftiTypeFile(DataFileTypeEnum::METRIC) { this->initializeMembersMetricFile(); } /** * Constructor for subclasses * * @param dataFileType * Filetype for subclass */ MetricFile::MetricFile(const DataFileTypeEnum::Enum dataFileType) : GiftiTypeFile(dataFileType) { this->initializeMembersMetricFile(); } /** * Copy constructor. * * @param sf * Surface file that is copied. */ MetricFile::MetricFile(const MetricFile& sf) : GiftiTypeFile(sf), ChartableLineSeriesBrainordinateInterface() { this->copyHelperMetricFile(sf); } /** * Assignment operator. * * @param sf * Surface file that is copied. * @return * This surface file with content replaced * by the MetricFile parameter. */ MetricFile& MetricFile::operator=(const MetricFile& sf) { if (this != &sf) { GiftiTypeFile::operator=(sf); this->copyHelperMetricFile(sf); } return *this; } /** * Destructor. */ MetricFile::~MetricFile() { this->columnDataPointers.clear(); } void MetricFile::writeFile(const AString& filename) { if (!(filename.endsWith(".func.gii") || filename.endsWith(".shape.gii"))) { CaretLogWarning("metric file '" + filename + "' should be saved ending in .func.gii or .shape.gii, see wb_command -gifti-help"); } /* * Put the child dynamic data-series file's palette in the file's metadata. */ if (m_lazyInitializedDynamicConnectivityFile != NULL) { GiftiMetaData* fileMetaData = m_lazyInitializedDynamicConnectivityFile->getCiftiXML().getFileMetaData(); CaretAssert(fileMetaData); if (m_lazyInitializedDynamicConnectivityFile->getNumberOfMaps() > 0) { fileMetaData->set(s_paletteColorMappingNameInMetaData, m_lazyInitializedDynamicConnectivityFile->getMapPaletteColorMapping(0)->encodeInXML()); } else { fileMetaData->remove(s_paletteColorMappingNameInMetaData); } } caret::GiftiTypeFile::writeFile(filename); } /** * Clear the surface file. */ void MetricFile::clear() { GiftiTypeFile::clear(); this->columnDataPointers.clear(); } /** * Validate the contents of the file after it * has been read such as correct number of * data arrays and proper data types/dimensions. */ void MetricFile::validateDataArraysAfterReading() { this->columnDataPointers.clear(); this->initializeMembersMetricFile(); this->verifyDataArraysHaveSameNumberOfRows(0, 0); bool isLabelData = false; const int32_t numberOfDataArrays = this->giftiFile->getNumberOfDataArrays(); for (int32_t i = 0; i < numberOfDataArrays; i++) { GiftiDataArray* gda = this->giftiFile->getDataArray(i); if (gda->getDataType() != NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32) { if (gda->getIntent() == NiftiIntentEnum::NIFTI_INTENT_LABEL) { isLabelData = true; } gda->convertToDataType(NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32); } int numDims = gda->getNumberOfDimensions(); std::vector dims = gda->getDimensions(); if (numDims == 1 || (numDims == 2 && dims[1] == 1)) { this->columnDataPointers.push_back(gda->getDataPointerFloat()); } else { if (numDims != 2) { throw DataFileException(getFileName(), "Invalid number of dimensions in metric file: " + AString::number(numDims)); } if (numberOfDataArrays != 1) { throw DataFileException(getFileName(), "Two dimensional data arrays are not allowed in metric files with multiple data arrays"); } std::vector newdims = dims; newdims[1] = 1; GiftiFile* newFile = new GiftiFile();//convert to multiple 1-d arrays on the fly *(newFile->getMetaData()) = *(giftiFile->getMetaData()); int32_t indices[2], newindices[2] = {0, 0}; for (indices[1] = 0; indices[1] < dims[1]; ++indices[1]) { GiftiDataArray* tempArray = new GiftiDataArray(NiftiIntentEnum::NIFTI_INTENT_NORMAL, NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32, newdims, GiftiEncodingEnum::GZIP_BASE64_BINARY); for (indices[0] = 0; indices[0] < dims[0]; ++indices[0]) { newindices[0] = indices[0]; tempArray->setDataFloat32(newindices, gda->getDataFloat32(indices)); } newFile->addDataArray(tempArray); newFile->setDataArrayName(indices[1], "#" + AString::number(indices[1] + 1)); columnDataPointers.push_back(tempArray->getDataPointerFloat()); } delete giftiFile;//delete old 2D file giftiFile = newFile;//drop new 1D file in } } if (isLabelData) { CaretLogWarning("Metric File: " + this->getFileName() + " contains data array with NIFTI_INTENT_LABEL !!!"); } } /** * Get the number of nodes. * * @return * The number of nodes. */ int32_t MetricFile::getNumberOfNodes() const { int32_t numNodes = 0; int32_t numDataArrays = this->giftiFile->getNumberOfDataArrays(); if (numDataArrays > 0) { numNodes = this->giftiFile->getDataArray(0)->getNumberOfRows(); } return numNodes; } /** * Get the number of columns. * * @return * The number of columns. */ int32_t MetricFile::getNumberOfColumns() const { const int32_t numCols = this->giftiFile->getNumberOfDataArrays(); return numCols; } /** * Initialize members of this class. */ void MetricFile::initializeMembersMetricFile() { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = false; } } /** * Helps copying files. * * @param sf * File that is copied. */ void MetricFile::copyHelperMetricFile(const MetricFile& mf) { this->validateDataArraysAfterReading(); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = mf.m_chartingEnabledForTab[i]; } } /** * Get value for a node. * * @param nodeIndex * Node index. * @param columnIndex * Column index. * @return * Value at the given node and column indices. */ float MetricFile::getValue(const int32_t nodeIndex, const int32_t columnIndex) const { CaretAssertVectorIndex(this->columnDataPointers, columnIndex); CaretAssertMessage((nodeIndex >= 0) && (nodeIndex < this->getNumberOfNodes()), "Node Index out of range."); return this->columnDataPointers[columnIndex][nodeIndex]; } /** * set label key for a node. * * @param nodeIndex * Node index. * @param columnIndex * Column index. * param value * Value inserted at the given node and column indices. */ void MetricFile::setValue(const int32_t nodeIndex, const int32_t columnIndex, const float value) { CaretAssertVectorIndex(this->columnDataPointers, columnIndex); CaretAssertMessage((nodeIndex >= 0) && (nodeIndex < this->getNumberOfNodes()), "Node Index out of range."); this->columnDataPointers[columnIndex][nodeIndex] = value; setModified(); } const float* MetricFile::getValuePointerForColumn(const int32_t columnIndex) const { CaretAssertVectorIndex(this->columnDataPointers, columnIndex); return this->columnDataPointers[columnIndex]; } void MetricFile::setNumberOfNodesAndColumns(int32_t nodes, int32_t columns) { giftiFile->clearAndKeepMetadata(); columnDataPointers.clear(); std::vector dimensions; dimensions.push_back(nodes); for (int32_t i = 0; i < columns; ++i) { giftiFile->addDataArray(new GiftiDataArray(NiftiIntentEnum::NIFTI_INTENT_NORMAL, NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32, dimensions, GiftiEncodingEnum::GZIP_BASE64_BINARY)); columnDataPointers.push_back(giftiFile->getDataArray(i)->getDataPointerFloat()); } setModified(); } /** * Add map(s) to this GIFTI file. * @param numberOfNodes * Number of nodes. If file is not empty, this value must * match the number of nodes that are in the file. * @param numberOfMaps * Number of maps to add. */ void MetricFile::addMaps(const int32_t numberOfNodes, const int32_t numberOfMaps) { if (numberOfNodes <= 0) { throw DataFileException(getFileName(), "When adding maps the number of nodes must be greater than zero"); } if (this->getNumberOfNodes() > 0) { if (numberOfNodes != this->getNumberOfNodes()) { throw DataFileException(getFileName(), "When adding maps the requested number of nodes is " + AString::number(numberOfNodes) + " but the file contains " + AString::number(this->getNumberOfNodes()) + " nodes."); } } if (numberOfMaps <= 0) { throw DataFileException(getFileName(), "When adding maps, the number of maps must be greater than zero."); } if ((this->getNumberOfNodes() > 0) && (this->getNumberOfMaps() > 0)) { std::vector dimensions; dimensions.push_back(numberOfNodes); for (int32_t i = 0; i < numberOfMaps; ++i) { this->giftiFile->addDataArray(new GiftiDataArray(NiftiIntentEnum::NIFTI_INTENT_NORMAL, NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32, dimensions, GiftiEncodingEnum::GZIP_BASE64_BINARY)); const int32_t mapIndex = giftiFile->getNumberOfDataArrays() - 1; this->columnDataPointers.push_back(giftiFile->getDataArray(mapIndex)->getDataPointerFloat()); } } else { this->setNumberOfNodesAndColumns(numberOfNodes, numberOfMaps); } this->setModified(); } void MetricFile::setValuesForColumn(const int32_t columnIndex, const float* valuesIn) { CaretAssertVectorIndex(this->columnDataPointers, columnIndex); float* myColumn = columnDataPointers[columnIndex]; int numNodes = (int)getNumberOfNodes(); for (int i = 0; i < numNodes; ++i) { myColumn[i] = valuesIn[i]; } setModified(); } void MetricFile::initializeColumn(const int32_t columnIndex, const float& value) { CaretAssertVectorIndex(this->columnDataPointers, columnIndex); float* myColumn = columnDataPointers[columnIndex]; int numNodes = (int)getNumberOfNodes(); for (int i = 0; i < numNodes; ++i) { myColumn[i] = value; } setModified(); } /** * Get the minimum and maximum values from ALL maps in this file. * Note that not all files (due to size of file) are able to provide * the minimum and maximum values from the file. The return value * indicates success/failure. If the failure (false) is returned * the returned values are likely +/- the maximum float values. * * @param dataRangeMinimumOut * Minimum data value found. * @param dataRangeMaximumOut * Maximum data value found. * @return * True if the values are valid, else false. */ bool MetricFile::getDataRangeFromAllMaps(float& dataRangeMinimumOut, float& dataRangeMaximumOut) const { const int32_t numberOfMaps = getNumberOfMaps(); if (numberOfMaps > 0) { dataRangeMaximumOut = -std::numeric_limits::max(); dataRangeMinimumOut = std::numeric_limits::max(); for (int32_t i = 0; i < numberOfMaps; ++i) { GiftiDataArray* gda = this->giftiFile->getDataArray(i); float mapMin, mapMax; gda->getMinMaxValuesFloat(mapMin, mapMax); if (mapMin < dataRangeMinimumOut) { dataRangeMinimumOut = mapMin; } if (mapMax > dataRangeMaximumOut) { dataRangeMaximumOut = mapMax; } } } else { dataRangeMaximumOut = std::numeric_limits::max(); dataRangeMinimumOut = -dataRangeMaximumOut; } return true; } /** * @return Is charting enabled for this file? */ bool MetricFile::isLineSeriesChartingEnabled(const int32_t tabIndex) const { CaretAssertArrayIndex(m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_chartingEnabledForTab[tabIndex]; } /** * @return Return true if the file's current state supports * charting data, else false. Typically a brainordinate file * is chartable if it contains more than one map. */ bool MetricFile::isLineSeriesChartingSupported() const { if (getNumberOfMaps() > 1) { return true; } return false; } /** * Set charting enabled for this file. * * @param enabled * New status for charting enabled. */ void MetricFile::setLineSeriesChartingEnabled(const int32_t tabIndex, const bool enabled) { CaretAssertArrayIndex(m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_chartingEnabledForTab[tabIndex] = enabled; } /** * Get chart data types supported by the file. * * @param chartDataTypesOut * Chart types supported by this file. */ void MetricFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { helpGetSupportedLineSeriesChartDataTypes(chartDataTypesOut); } /** * Load charting data for the surface with the given structure and node index. * * @param structure * The surface's structure. * @param nodeIndex * Index of the node. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* MetricFile::loadLineSeriesChartDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t nodeIndex) { ChartDataCartesian* chartData = NULL; if (getStructure() == structure) { try { const int32_t numMaps = getNumberOfMaps(); std::vector data; for (int64_t iMap = 0; iMap < numMaps; iMap++) { data.push_back(getValue(nodeIndex, iMap)); } chartData = helpCreateCartesianChartData(data); ChartDataSource* dataSource = chartData->getChartDataSource(); dataSource->setSurfaceNode(getFileName(), StructureEnum::toName(structure), getNumberOfNodes(), nodeIndex); } catch (const DataFileException& dfe) { if (chartData != NULL) { delete chartData; chartData = NULL; } throw dfe; } } return chartData; } /** * Load average charting data for the surface with the given structure and node indices. * * @param structure * The surface's structure. * @param nodeIndices * Indices of the node. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* MetricFile::loadAverageLineSeriesChartDataForSurfaceNodes(const StructureEnum::Enum structure, const std::vector& nodeIndices) { ChartDataCartesian* chartData = NULL; if (getStructure() == structure) { ChartDataCartesian* chartData = NULL; try { const int32_t numberOfNodeIndices = static_cast(nodeIndices.size()); const int32_t numberOfMaps = getNumberOfMaps(); if ((numberOfNodeIndices > 0) && (numberOfMaps > 0)) { std::vector dataSum(numberOfMaps, 0.0); for (int32_t iMap = 0; iMap < numberOfMaps; iMap++) { CaretAssertVectorIndex(dataSum, iMap); for (int32_t iNode = 0; iNode < numberOfNodeIndices; iNode++) { const int32_t nodeIndex = nodeIndices[iNode]; dataSum[iMap] += getValue(nodeIndex, iMap); } } std::vector data; for (int32_t iMap = 0; iMap < numberOfMaps; iMap++) { CaretAssertVectorIndex(dataSum, iMap); const float mapAverageValue = dataSum[iMap] / numberOfNodeIndices; data.push_back(mapAverageValue); } chartData = helpCreateCartesianChartData(data); ChartDataSource* dataSource = chartData->getChartDataSource(); dataSource->setSurfaceNodeAverage(getFileName(), StructureEnum::toName(structure), numberOfNodeIndices, nodeIndices); } } catch (const DataFileException& dfe) { if (chartData != NULL) { delete chartData; chartData = NULL; } throw dfe; } return chartData; } return chartData; } /** * Load charting data for the voxel enclosing the given coordinate. * * @param xyz * Coordinate of voxel. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* MetricFile::loadLineSeriesChartDataForVoxelAtCoordinate(const float * /*xyz[3]*/) { ChartDataCartesian* chartData = NULL; //helpLoadChartDataForVoxelAtCoordinate(xyz); return chartData; } /** * Get data from the file as requested in the given map file data selector. * * @param mapFileDataSelector * Specifies selection of data. * @param dataOut * Output with data. Will be empty if data does not support the map file data selector. */ void MetricFile::getDataForSelector(const MapFileDataSelector& mapFileDataSelector, std::vector& dataOut) const { dataOut.clear(); switch (mapFileDataSelector.getDataSelectionType()) { case MapFileDataSelector::DataSelectionType::INVALID: break; case MapFileDataSelector::DataSelectionType::COLUMN_DATA: break; case MapFileDataSelector::DataSelectionType::ROW_DATA: break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: try { StructureEnum::Enum structure = StructureEnum::INVALID; int32_t surfaceNumberOfVertices = -1; int32_t vertexIndex = -1; mapFileDataSelector.getSurfaceVertex(structure, surfaceNumberOfVertices, vertexIndex); if ((structure == getStructure()) && (surfaceNumberOfVertices == getNumberOfNodes())) { const int32_t numMaps = getNumberOfMaps(); for (int64_t iMap = 0; iMap < numMaps; iMap++) { dataOut.push_back(getValue(vertexIndex, iMap)); } } } catch (const DataFileException& dfe) { CaretLogWarning("Exeception: " + dfe.whatString()); dataOut.clear(); } break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTICES_AVERAGE: { try { StructureEnum::Enum structure = StructureEnum::INVALID; int32_t surfaceNumberOfVertices = -1; std::vector vertexIndices; mapFileDataSelector.getSurfaceVertexAverage(structure, surfaceNumberOfVertices, vertexIndices); if ((structure == getStructure()) && (surfaceNumberOfVertices == getNumberOfNodes())) { const int32_t numberOfVertexIndices = static_cast(vertexIndices.size()); const int32_t numberOfMaps = getNumberOfMaps(); if ((numberOfVertexIndices > 0) && (numberOfMaps > 0)) { std::vector dataSum(numberOfMaps, 0.0); for (int32_t iMap = 0; iMap < numberOfMaps; iMap++) { CaretAssertVectorIndex(dataSum, iMap); for (int32_t iNode = 0; iNode < numberOfVertexIndices; iNode++) { const int32_t nodeIndex = vertexIndices[iNode]; dataSum[iMap] += getValue(nodeIndex, iMap); } } dataOut.resize(numberOfMaps); for (int32_t iMap = 0; iMap < numberOfMaps; iMap++) { CaretAssertVectorIndex(dataSum, iMap); const float mapAverageValue = dataSum[iMap] / numberOfVertexIndices; dataOut[iMap] = mapAverageValue; } } } } catch (const DataFileException& dfe) { CaretLogWarning("Exeception: " + dfe.whatString()); dataOut.clear(); } } break; case MapFileDataSelector::DataSelectionType::VOLUME_XYZ: break; } } /** * Save file data from the scene. For subclasses that need to * save to a scene, this method should be overriden. sceneClass * will be valid and any scene data should be added to it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. */ void MetricFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { GiftiTypeFile::saveFileDataToScene(sceneAttributes, sceneClass); sceneClass->addBooleanArray("m_chartingEnabledForTab", m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); if (m_lazyInitializedDynamicConnectivityFile != NULL) { sceneClass->addClass(m_lazyInitializedDynamicConnectivityFile->saveToScene(sceneAttributes, "m_lazyInitializedDynamicConnectivityFile")); } } /** * Restore file data from the scene. For subclasses that need to * restore from a scene, this method should be overridden. The scene class * will be valid and any scene data may be obtained from it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void MetricFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { GiftiTypeFile::restoreFileDataFromScene(sceneAttributes, sceneClass); const ScenePrimitiveArray* tabArray = sceneClass->getPrimitiveArray("m_chartingEnabledForTab"); if (tabArray != NULL) { sceneClass->getBooleanArrayValue("m_chartingEnabledForTab", m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); } else { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = false; } } const SceneClass* dynamicFileSceneClass = sceneClass->getClass("m_lazyInitializedDynamicConnectivityFile"); if (dynamicFileSceneClass != NULL) { MetricDynamicConnectivityFile* denseDynamicFile = getMetricDynamicConnectivityFile(); denseDynamicFile->restoreFromScene(sceneAttributes, dynamicFileSceneClass); } } /** * @return The volume dynamic connectivity file for a data-series (functional) file * that contains at least two time points. Note that some files may * have type anatomy but still contain functional data. * Will return NULL for other types. */ const MetricDynamicConnectivityFile* MetricFile::getMetricDynamicConnectivityFile() const { MetricFile* nonConstThis = const_cast(this); return nonConstThis->getMetricDynamicConnectivityFile(); } /** * @return The volume dynamic connectivity file for a data-series (functional) file * that contains at least two time points. Note that some files may * have type anatomy but still contain functional data. * Will return NULL for other types. */ MetricDynamicConnectivityFile* MetricFile::getMetricDynamicConnectivityFile() { if (m_lazyInitializedDynamicConnectivityFile == NULL) { const int32_t minimumNumberOfTimePoints(8); if (getNumberOfMaps() >= minimumNumberOfTimePoints) { m_lazyInitializedDynamicConnectivityFile.reset(new MetricDynamicConnectivityFile(this)); m_lazyInitializedDynamicConnectivityFile->initializeFile(); /* * Palette for dynamic file is in file metadata */ GiftiMetaData* fileMetaData = getFileMetaData(); const AString encodedPaletteColorMappingString = fileMetaData->get(s_paletteColorMappingNameInMetaData); if ( ! encodedPaletteColorMappingString.isEmpty()) { if (m_lazyInitializedDynamicConnectivityFile->getNumberOfMaps() > 0) { PaletteColorMapping* pcm = m_lazyInitializedDynamicConnectivityFile->getMapPaletteColorMapping(0); CaretAssert(pcm); pcm->decodeFromStringXML(encodedPaletteColorMappingString); } } m_lazyInitializedDynamicConnectivityFile->clearModified(); } } return m_lazyInitializedDynamicConnectivityFile.get(); } connectome-workbench-1.4.2/src/Files/MetricFile.h000066400000000000000000000122551360521144700216650ustar00rootroot00000000000000 #ifndef __METRIC_FILE_H__ #define __METRIC_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "ChartableLineSeriesBrainordinateInterface.h" #include "BrainConstants.h" #include "GiftiTypeFile.h" namespace caret { class GiftiDataArray; class MetricDynamicConnectivityFile; /** * \brief A Metric data file. */ class MetricFile : public GiftiTypeFile, public ChartableLineSeriesBrainordinateInterface { public: MetricFile(); MetricFile(const MetricFile& sf); MetricFile& operator=(const MetricFile& sf); virtual ~MetricFile(); virtual void clear(); virtual int32_t getNumberOfNodes() const; virtual int32_t getNumberOfColumns() const; virtual void setNumberOfNodesAndColumns(int32_t nodes, int32_t columns); virtual void addMaps(const int32_t numberOfNodes, const int32_t numberOfMaps); float getValue(const int32_t nodeIndex, const int32_t columnIndex) const; void setValue(const int32_t nodeIndex, const int32_t columnIndex, const float value); const float* getValuePointerForColumn(const int32_t columnIndex) const; void setValuesForColumn(const int32_t columnIndex, const float* valuesIn); void initializeColumn(const int32_t columnIndex, const float& value = 0.0f); virtual bool getDataRangeFromAllMaps(float& dataRangeMinimumOut, float& dataRangeMaximumOut) const; virtual bool isLineSeriesChartingEnabled(const int32_t tabIndex) const; virtual void setLineSeriesChartingEnabled(const int32_t tabIndex, const bool enabled); virtual bool isLineSeriesChartingSupported() const; virtual ChartDataCartesian* loadLineSeriesChartDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t nodeIndex); virtual ChartDataCartesian* loadAverageLineSeriesChartDataForSurfaceNodes(const StructureEnum::Enum structure, const std::vector& nodeIndices); virtual ChartDataCartesian* loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]); virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; void getDataForSelector(const MapFileDataSelector& mapFileDataSelector, std::vector& dataOut) const override; //override writeFile in order to check filename against type of file virtual void writeFile(const AString& filename); MetricDynamicConnectivityFile* getMetricDynamicConnectivityFile(); const MetricDynamicConnectivityFile* getMetricDynamicConnectivityFile() const; protected: MetricFile(const DataFileTypeEnum::Enum dataFileType); /** * Validate the contents of the file after it * has been read such as correct number of * data arrays and proper data types/dimensions. */ virtual void validateDataArraysAfterReading(); void copyHelperMetricFile(const MetricFile& sf); void initializeMembersMetricFile(); virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: /** Points to actual data in each Gifti Data Array */ std::vector columnDataPointers; std::unique_ptr m_lazyInitializedDynamicConnectivityFile; bool m_chartingEnabledForTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; static const AString s_paletteColorMappingNameInMetaData; }; } // namespace #endif // __METRIC_FILE_H__ connectome-workbench-1.4.2/src/Files/MetricSmoothingObject.cxx000066400000000000000000001017361360521144700244620ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "MetricSmoothingObject.h" #include "CaretAssert.h" #include "CaretException.h" #include "SurfaceFile.h" #include "MetricFile.h" #include "GeodesicHelper.h" #include "TopologyHelper.h" #include "CaretOMP.h" #include using namespace std; using namespace caret; MetricSmoothingObject::MetricSmoothingObject(const SurfaceFile* mySurf, const float& kernel, const MetricFile* myRoi, Method myMethod, const float* nodeAreas) { CaretAssert(mySurf != NULL); if (myRoi != NULL && mySurf->getNumberOfNodes() != myRoi->getNumberOfNodes()) { throw CaretException("roi number of nodes doesn't match the surface"); } precomputeWeights(mySurf, kernel, myRoi, myMethod, nodeAreas); } void MetricSmoothingObject::smoothColumn(const MetricFile* metricIn, const int& whichColumn, MetricFile* columnOut, const MetricFile* roi, const bool& fixZeros) const { CaretAssert(metricIn != NULL); CaretAssert(columnOut != NULL); if (metricIn->getNumberOfNodes() != (int32_t)m_weightLists.size()) { throw CaretException("metric does not match surface number of nodes"); } if (whichColumn < -1 || whichColumn >= metricIn->getNumberOfColumns()) { throw CaretException("invalid column number"); } if (columnOut->getNumberOfNodes() != (int32_t)m_weightLists.size() || columnOut->getNumberOfColumns() != 1) { columnOut->setNumberOfNodesAndColumns(m_weightLists.size(), 1); } vector scratch(metricIn->getNumberOfNodes()); if (roi != NULL) { if (roi->getNumberOfNodes() != (int32_t)m_weightLists.size()) { throw CaretException("roi does not match surface number of nodes"); } smoothColumnInternal(scratch.data(), metricIn, whichColumn, columnOut, 0, roi, 0, fixZeros); } else { smoothColumnInternal(scratch.data(), metricIn, whichColumn, columnOut, 0, fixZeros); } } void MetricSmoothingObject::smoothColumn(const MetricFile* metricIn, const int& whichColumn, MetricFile* metricOut, const int& whichOutColumn, const MetricFile* roi, const int& whichRoiColumn, const bool& fixZeros) const { CaretAssert(metricIn != NULL); CaretAssert(metricOut != NULL); if (metricIn->getNumberOfNodes() != (int32_t)m_weightLists.size()) { throw CaretException("metric does not match surface number of nodes"); } if (metricOut->getNumberOfNodes() != (int32_t)m_weightLists.size()) { throw CaretException("output metric does not match surface number of nodes"); } if (roi != NULL && (roi->getNumberOfNodes() != (int32_t)m_weightLists.size())) { throw CaretException("roi does not match surface number of nodes"); } if (whichColumn < -1 || whichColumn >= metricIn->getNumberOfColumns()) { throw CaretException("invalid input column number"); } if (whichOutColumn < -1 || whichOutColumn >= metricOut->getNumberOfColumns()) { throw CaretException("invalid output column number"); } if (roi != NULL && (whichRoiColumn < -1 || whichRoiColumn >= roi->getNumberOfColumns())) { throw CaretException("invalid input column number"); } vector scratch(metricIn->getNumberOfNodes()); if (roi != NULL) { smoothColumnInternal(scratch.data(), metricIn, whichColumn, metricOut, whichOutColumn, roi, whichRoiColumn, fixZeros); } else { smoothColumnInternal(scratch.data(), metricIn, whichColumn, metricOut, whichOutColumn, fixZeros); } } void MetricSmoothingObject::smoothMetric(const MetricFile* metricIn, MetricFile* metricOut, const MetricFile* roi, const bool& fixZeros) const { CaretAssert(metricIn != NULL); CaretAssert(metricOut != NULL); int32_t numCols = metricIn->getNumberOfColumns(); if (metricIn->getNumberOfNodes() != (int32_t)m_weightLists.size()) { throw CaretException("metric does not match surface number of nodes"); } if (metricOut->getNumberOfNodes() != (int32_t)m_weightLists.size() || metricOut->getNumberOfColumns() != numCols) { metricOut->setNumberOfNodesAndColumns(m_weightLists.size(), numCols); } vector scratch(metricIn->getNumberOfNodes()); if (roi != NULL) { if (roi->getNumberOfNodes() != (int32_t)m_weightLists.size()) { throw CaretException("roi does not match surface number of nodes"); } for (int32_t i = 0; i < numCols; ++i) { smoothColumnInternal(scratch.data(), metricIn, i, metricOut, i, roi, 0, fixZeros); } } else { for (int32_t i = 0; i < numCols; ++i) { smoothColumnInternal(scratch.data(), metricIn, i, metricOut, i, fixZeros); } } } void MetricSmoothingObject::smoothColumnInternal(float* scratch, const MetricFile* metricIn, const int& whichColumn, MetricFile* metricOut, const int& whichOutColumn, const bool& fixZeros) const { CaretAssert(metricIn != NULL);//asserts only, and only basic checks, these functions are private CaretAssert(metricOut != NULL); CaretAssert(scratch != NULL); CaretAssert(whichColumn >= 0 && whichColumn < metricIn->getNumberOfColumns()); CaretAssert(whichOutColumn >= 0 && whichOutColumn < metricOut->getNumberOfColumns()); const float* myColumn = metricIn->getValuePointerForColumn(whichColumn); int32_t numNodes = metricIn->getNumberOfNodes(); if (fixZeros)//special case early to keep branching down { #pragma omp CARET_PARFOR schedule(dynamic) for (int32_t i = 0; i < numNodes; ++i) { const WeightList& myWeightRef = m_weightLists[i]; if (myWeightRef.m_weightSum != 0.0f)//skip nodes with no neighbors quickly { float sum = 0.0f, weightsum = 0.0f; int32_t numWeights = myWeightRef.m_nodes.size(); for (int32_t j = 0; j < numWeights; ++j) { float value = myColumn[myWeightRef.m_nodes[j]]; if (value != 0.0f) { float weight = myWeightRef.m_weights[j]; sum += weight * value; weightsum += weight; } } if (weightsum != 0.0f) { scratch[i] = sum / weightsum; } else { scratch[i] = 0.0f; } } else { scratch[i] = 0.0f;//but we do need to zero what we skip, so a list of nodes to check may not help } } } else { #pragma omp CARET_PARFOR schedule(dynamic) for (int32_t i = 0; i < numNodes; ++i) { const WeightList& myWeightRef = m_weightLists[i]; if (myWeightRef.m_weightSum != 0.0f) { float sum = 0.0f; int32_t numWeights = myWeightRef.m_nodes.size(); for (int32_t j = 0; j < numWeights; ++j) { sum += myWeightRef.m_weights[j] * myColumn[myWeightRef.m_nodes[j]]; } scratch[i] = sum / myWeightRef.m_weightSum; } else { scratch[i] = 0.0f; } } } metricOut->setValuesForColumn(whichOutColumn, scratch); } void MetricSmoothingObject::smoothColumnInternal(float* scratch, const MetricFile* metricIn, const int& whichColumn, MetricFile* metricOut, const int& whichOutColumn, const MetricFile* roi, const int& whichRoiColumn, const bool& fixZeros) const { CaretAssert(metricIn != NULL);//asserts only, and only basic checks, these functions are private CaretAssert(metricOut != NULL); CaretAssert(scratch != NULL); CaretAssert(roi != NULL); CaretAssert(whichColumn >= 0 && whichColumn < metricIn->getNumberOfColumns()); CaretAssert(whichOutColumn >= 0 && whichOutColumn < metricOut->getNumberOfColumns()); CaretAssert(whichRoiColumn >= 0 && whichRoiColumn < roi->getNumberOfColumns()); const float* myColumn = metricIn->getValuePointerForColumn(whichColumn); const float* roiColumn = roi->getValuePointerForColumn(whichRoiColumn); int32_t numNodes = metricIn->getNumberOfNodes(); if (fixZeros)//special case early to keep branching down { #pragma omp CARET_PARFOR schedule(dynamic) for (int32_t i = 0; i < numNodes; ++i) { const WeightList& myWeightRef = m_weightLists[i]; if (roiColumn[i] > 0.0f && myWeightRef.m_weightSum != 0.0f)//skip nodes with no neighbors quickly { float sum = 0.0f, weightsum = 0.0f; int32_t numWeights = myWeightRef.m_nodes.size(); for (int32_t j = 0; j < numWeights; ++j) { int32_t neighbor = myWeightRef.m_nodes[j]; float value = myColumn[neighbor]; if (roiColumn[neighbor] > 0.0f && value != 0.0f) { float weight = myWeightRef.m_weights[j]; sum += weight * value; weightsum += weight; } } if (weightsum != 0.0f) { scratch[i] = sum / weightsum; } else { scratch[i] = 0.0f; } } else { scratch[i] = 0.0f;//but we do need to zero what we skip, so a list of nodes to check may not help } } } else { #pragma omp CARET_PARFOR schedule(dynamic) for (int32_t i = 0; i < numNodes; ++i) { const WeightList& myWeightRef = m_weightLists[i]; if (roiColumn[i] > 0.0f && myWeightRef.m_weightSum != 0.0f) { float sum = 0.0f, weightsum = 0.0f; int32_t numWeights = myWeightRef.m_nodes.size(); for (int32_t j = 0; j < numWeights; ++j) { int32_t neighbor = myWeightRef.m_nodes[j]; if (roiColumn[neighbor] > 0.0f) { float weight = myWeightRef.m_weights[j]; sum += weight * myColumn[neighbor]; weightsum += weight; } } if (weightsum != 0.0f) { scratch[i] = sum / weightsum; } else { scratch[i] = 0.0f; } } else { scratch[i] = 0.0f; } } } metricOut->setValuesForColumn(whichOutColumn, scratch); } void MetricSmoothingObject::precomputeWeightsGeoGauss(const SurfaceFile* mySurf, float myKernel, const float* nodeAreas) { int32_t numNodes = mySurf->getNumberOfNodes(); float myGeoDist = myKernel * 3.0f; float gaussianDenom = -0.5f / myKernel / myKernel; m_weightLists.resize(numNodes); CaretPointer myGeoBase(new GeodesicHelperBase(mySurf, nodeAreas));//NOTE: if these are equal to the surface's areas, then it does some extra operations, but gets the same answer #pragma omp CARET_PAR { CaretPointer myTopoHelp = mySurf->getTopologyHelper();//don't really need one per thread here, but good practice in case we want getNeighborsToDepth CaretPointer myGeoHelp(new GeodesicHelper(myGeoBase)); vector distances; #pragma omp CARET_FOR schedule(dynamic) for (int32_t i = 0; i < numNodes; ++i) { myGeoHelp->getNodesToGeoDist(i, myGeoDist, m_weightLists[i].m_nodes, distances, true); if (distances.size() < 7) { m_weightLists[i].m_nodes = myTopoHelp->getNodeNeighbors(i); m_weightLists[i].m_nodes.push_back(i); myGeoHelp->getGeoToTheseNodes(i, m_weightLists[i].m_nodes, distances, true); } int32_t numNeigh = (int32_t)distances.size(); m_weightLists[i].m_weights.resize(numNeigh); m_weightLists[i].m_weightSum = 0.0f; for (int32_t j = 0; j < numNeigh; ++j) { float weight = exp(distances[j] * distances[j] * gaussianDenom);//exp(- dist ^ 2 / (2 * sigma ^ 2)) m_weightLists[i].m_weights[j] = weight; m_weightLists[i].m_weightSum += weight; } } } } void MetricSmoothingObject::precomputeWeightsROIGeoGauss(const SurfaceFile* mySurf, float myKernel, const MetricFile* theRoi, const float* nodeAreas) { int32_t numNodes = mySurf->getNumberOfNodes(); float myGeoDist = myKernel * 3.0f; float gaussianDenom = -0.5f / myKernel / myKernel; m_weightLists.resize(numNodes); const float* myRoiColumn = theRoi->getValuePointerForColumn(0); CaretPointer myGeoBase(new GeodesicHelperBase(mySurf, nodeAreas));//NOTE: if these are equal to the surface's areas, then it does some extra operations, but gets the same answer #pragma omp CARET_PAR { CaretPointer myTopoHelp = mySurf->getTopologyHelper(); CaretPointer myGeoHelp(new GeodesicHelper(myGeoBase)); vector distances; vector nodes; #pragma omp CARET_FOR schedule(dynamic) for (int32_t i = 0; i < numNodes; ++i) { if (myRoiColumn[i] > 0.0f) { myGeoHelp->getNodesToGeoDist(i, myGeoDist, nodes, distances, true); if (distances.size() < 7) { nodes = myTopoHelp->getNodeNeighbors(i); nodes.push_back(i); myGeoHelp->getGeoToTheseNodes(i, nodes, distances, true); } int32_t numNeigh = (int32_t)distances.size(); m_weightLists[i].m_weights.reserve(numNeigh); m_weightLists[i].m_nodes.reserve(numNeigh); m_weightLists[i].m_weightSum = 0.0f; for (int32_t j = 0; j < numNeigh; ++j) { if (myRoiColumn[nodes[j]] > 0.0f) { float weight = exp(distances[j] * distances[j] * gaussianDenom);//exp(- dist ^ 2 / (2 * sigma ^ 2)) m_weightLists[i].m_weights.push_back(weight); m_weightLists[i].m_nodes.push_back(nodes[j]); m_weightLists[i].m_weightSum += weight; } } } } } } void MetricSmoothingObject::precomputeWeightsGeoGaussArea(const SurfaceFile* mySurf, float myKernel, const float* nodeAreas) {//this method is normalized in two ways to provide evenly diffusing smoothing with equivalent sum of areas * values as input int32_t numNodes = mySurf->getNumberOfNodes(); float myGeoDist = myKernel * 3.0f; float gaussianDenom = -0.5f / myKernel / myKernel; vector tempList;//this is used to compute scattering kernels because it is easier to normalize scattering kernels correctly, and then convert to gathering kernels tempList.resize(numNodes); CaretPointer myGeoBase(new GeodesicHelperBase(mySurf, nodeAreas));//NOTE: if these are equal to the surface's areas, then it does some extra operations, but gets the same answer #pragma omp CARET_PAR { CaretPointer myTopoHelp = mySurf->getTopologyHelper();//don't really need one per thread here, but good practice in case we want getNeighborsToDepth CaretPointer myGeoHelp(new GeodesicHelper(myGeoBase)); vector distances; #pragma omp CARET_FOR schedule(dynamic) for (int32_t i = 0; i < numNodes; ++i) { myGeoHelp->getNodesToGeoDist(i, myGeoDist, tempList[i].m_nodes, distances, true); const vector& tempneighbors = myTopoHelp->getNodeNeighbors(i); if (distances.size() <= tempneighbors.size())//because neighbors doesn't include center, so if they are equal, geo is missing a neighbor { tempList[i].m_nodes = tempneighbors; tempList[i].m_nodes.push_back(i); myGeoHelp->getGeoToTheseNodes(i, tempList[i].m_nodes, distances, true); } int32_t numNeigh = (int32_t)distances.size(); tempList[i].m_weights.resize(numNeigh); tempList[i].m_weightSum = 0.0f; for (int32_t j = 0; j < numNeigh; ++j) { float weight = exp(distances[j] * distances[j] * gaussianDenom) * nodeAreas[tempList[i].m_nodes[j]];//exp(- dist ^ 2 / (2 * sigma ^ 2)) * area tempList[i].m_weights[j] = weight;//we multiply by area so that a node scattering to a dense region on one side and a sparse region on the other tempList[i].m_weightSum += weight;//gives similar areal influence to each direction rather than giving a more influence on the dense region (simply because nodes are more numerous) } float myFactor = nodeAreas[i] / tempList[i].m_weightSum;//make each scattering kernel sum to the area of the node it scatters from for (int32_t j = 0; j < numNeigh; ++j) { tempList[i].m_weights[j] *= myFactor; } tempList[i].m_weightSum = nodeAreas[i]; } } m_weightLists.resize(numNodes);//now convert it to gathering kernels for (int32_t i = 0; i < numNodes; ++i)//sadly, this is VERY hard to parallelize in a manner that is efficient, since it needs random access modification { m_weightLists[i].m_weightSum = 0.0f;//memory initialization may not go much faster in parallel size_t neighborCount = tempList[i].m_nodes.size(); m_weightLists[i].m_nodes.reserve(neighborCount);//also preallocate the expected number of nodes (geodesic distance should be symmetric except for rounding errors, so it should usually be exact) m_weightLists[i].m_weights.reserve(neighborCount); } for (int32_t i = 0; i < numNodes; ++i)//and this needs to push onto random vectors in the weight list { int32_t numNeigh = tempList[i].m_nodes.size(); for (int32_t j = 0; j < numNeigh; ++j) { int32_t node = tempList[i].m_nodes[j]; float weight = tempList[i].m_weights[j]; m_weightLists[node].m_nodes.push_back(i); m_weightLists[node].m_weights.push_back(weight); m_weightLists[node].m_weightSum += weight; } } } void MetricSmoothingObject::precomputeWeightsROIGeoGaussArea(const SurfaceFile* mySurf, float myKernel, const MetricFile* theRoi, const float* nodeAreas) { int32_t numNodes = mySurf->getNumberOfNodes(); float myGeoDist = myKernel * 3.0f; float gaussianDenom = -0.5f / myKernel / myKernel; vector tempList;//this is used to compute scattering kernels because it is easier to normalize scattering kernels correctly, and then convert to gathering kernels tempList.resize(numNodes); const float* myRoiColumn = theRoi->getValuePointerForColumn(0); CaretPointer myGeoBase(new GeodesicHelperBase(mySurf, nodeAreas));//NOTE: if these are equal to the surface's areas, then it does some extra operations, but gets the same answer #pragma omp CARET_PAR { CaretPointer myTopoHelp = mySurf->getTopologyHelper(); CaretPointer myGeoHelp(new GeodesicHelper(myGeoBase)); vector distances; vector nodes; #pragma omp CARET_FOR schedule(dynamic) for (int32_t i = 0; i < numNodes; ++i) { if (myRoiColumn[i] > 0.0f)//we don't need to scatter from things outside the ROI { myGeoHelp->getNodesToGeoDist(i, myGeoDist, nodes, distances, true); const vector& tempneighbors = myTopoHelp->getNodeNeighbors(i); if (distances.size() <= tempneighbors.size())//because neighbors doesn't include center, so if they are equal, geo is missing a neighbor { nodes = tempneighbors; nodes.push_back(i); myGeoHelp->getGeoToTheseNodes(i, nodes, distances, true); } int32_t numNeigh = (int32_t)distances.size(); tempList[i].m_weightSum = 0.0f; for (int32_t j = 0; j < numNeigh; ++j) {//but we DO need to compute scattering TO things outside the ROI, so that our normalization doesn't increase the in-ROI influence of edge nodes float weight = exp(distances[j] * distances[j] * gaussianDenom) * nodeAreas[nodes[j]];//exp(- dist ^ 2 / (2 * sigma ^ 2)) * area tempList[i].m_weightSum += weight;//add it to the total weight in order to normalize correctly if (myRoiColumn[nodes[j]] > 0.0f) {//BUT, don't add it to the list if it is outside the ROI tempList[i].m_nodes.push_back(nodes[j]); tempList[i].m_weights.push_back(weight); } } float myFactor = nodeAreas[i] / tempList[i].m_weightSum;//make each scattering kernel sum to the area of the node it scatters from int32_t numUsed = (int32_t)tempList[i].m_nodes.size(); for (int32_t j = 0; j < numUsed; ++j) { tempList[i].m_weights[j] *= myFactor; } tempList[i].m_weightSum = 0.0f;//this is never actually used again, but make sure it is wrong in case anything tries to use it } } } m_weightLists.resize(numNodes);//now convert it to gathering kernels for (int32_t i = 0; i < numNodes; ++i)//sadly, this is VERY hard to parallelize in a manner that is efficient, since it needs random access modification { m_weightLists[i].m_weightSum = 0.0f;//memory initialization may not go much faster in parallel size_t neighborCount = tempList[i].m_nodes.size(); m_weightLists[i].m_nodes.reserve(neighborCount);//also preallocate the expected number of nodes, again, should be exact except for rounding errors in geodesic distance m_weightLists[i].m_weights.reserve(neighborCount); } for (int32_t i = 0; i < numNodes; ++i)//and this needs to push onto random vectors in the weight list { int32_t numNeigh = tempList[i].m_nodes.size(); for (int32_t j = 0; j < numNeigh; ++j) { int32_t node = tempList[i].m_nodes[j]; float weight = tempList[i].m_weights[j]; m_weightLists[node].m_nodes.push_back(i); m_weightLists[node].m_weights.push_back(weight); m_weightLists[node].m_weightSum += weight; } } } void MetricSmoothingObject::precomputeWeightsGeoGaussEqual(const SurfaceFile* mySurf, float myKernel, const float* nodeAreas) {//this method is normalized in two ways to provide evenly diffusing smoothing with equivalent sum of values as input - this special purpose smoothing is for things that should not be integrated across the surface int32_t numNodes = mySurf->getNumberOfNodes(); float myGeoDist = myKernel * 3.0f; float gaussianDenom = -0.5f / myKernel / myKernel; vector tempList;//this is used to compute scattering kernels because it is easier to normalize scattering kernels correctly, and then convert to gathering kernels tempList.resize(numNodes); CaretPointer myGeoBase(new GeodesicHelperBase(mySurf, nodeAreas));//NOTE: if these are equal to the surface's areas, then it does some extra operations, but gets the same answer #pragma omp CARET_PAR { CaretPointer myTopoHelp = mySurf->getTopologyHelper();//don't really need one per thread here, but good practice in case we want getNeighborsToDepth CaretPointer myGeoHelp(new GeodesicHelper(myGeoBase)); vector distances; #pragma omp CARET_FOR schedule(dynamic) for (int32_t i = 0; i < numNodes; ++i) { myGeoHelp->getNodesToGeoDist(i, myGeoDist, tempList[i].m_nodes, distances, true); const vector& tempneighbors = myTopoHelp->getNodeNeighbors(i); if (distances.size() <= tempneighbors.size())//because neighbors doesn't include center, so if they are equal, geo is missing a neighbor { tempList[i].m_nodes = tempneighbors; tempList[i].m_nodes.push_back(i); myGeoHelp->getGeoToTheseNodes(i, tempList[i].m_nodes, distances, true); } int32_t numNeigh = (int32_t)distances.size(); tempList[i].m_weights.resize(numNeigh); tempList[i].m_weightSum = 0.0f; for (int32_t j = 0; j < numNeigh; ++j) { float weight = exp(distances[j] * distances[j] * gaussianDenom);//exp(- dist ^ 2 / (2 * sigma ^ 2)) tempList[i].m_weights[j] = weight;//we multiply by area so that a node scattering to a dense region on one side and a sparse region on the other tempList[i].m_weightSum += weight;//gives similar areal influence to each direction rather than giving a more influence on the dense region (simply because nodes are more numerous) } float myFactor = 1.0f / tempList[i].m_weightSum;//make each scattering kernel sum to 1 for (int32_t j = 0; j < numNeigh; ++j) { tempList[i].m_weights[j] *= myFactor; } tempList[i].m_weightSum = 1.0f; } } m_weightLists.resize(numNodes);//now convert it to gathering kernels for (int32_t i = 0; i < numNodes; ++i)//sadly, this is VERY hard to parallelize in a manner that is efficient, since it needs random access modification { m_weightLists[i].m_weightSum = 0.0f;//memory initialization may not go much faster in parallel size_t neighborCount = tempList[i].m_nodes.size(); m_weightLists[i].m_nodes.reserve(neighborCount);//also preallocate the expected number of nodes (geodesic distance should be symmetric except for rounding errors, so it should usually be exact) m_weightLists[i].m_weights.reserve(neighborCount); } for (int32_t i = 0; i < numNodes; ++i)//and this needs to push onto random vectors in the weight list { int32_t numNeigh = tempList[i].m_nodes.size(); for (int32_t j = 0; j < numNeigh; ++j) { int32_t node = tempList[i].m_nodes[j]; float weight = tempList[i].m_weights[j]; m_weightLists[node].m_nodes.push_back(i); m_weightLists[node].m_weights.push_back(weight); m_weightLists[node].m_weightSum += weight; } } } void MetricSmoothingObject::precomputeWeightsROIGeoGaussEqual(const SurfaceFile* mySurf, float myKernel, const MetricFile* theRoi, const float* nodeAreas) { int32_t numNodes = mySurf->getNumberOfNodes(); float myGeoDist = myKernel * 3.0f; float gaussianDenom = -0.5f / myKernel / myKernel; vector tempList;//this is used to compute scattering kernels because it is easier to normalize scattering kernels correctly, and then convert to gathering kernels tempList.resize(numNodes); const float* myRoiColumn = theRoi->getValuePointerForColumn(0); CaretPointer myGeoBase(new GeodesicHelperBase(mySurf, nodeAreas));//NOTE: if these are equal to the surface's areas, then it does some extra operations, but gets the same answer #pragma omp CARET_PAR { CaretPointer myTopoHelp = mySurf->getTopologyHelper(); CaretPointer myGeoHelp(new GeodesicHelper(myGeoBase)); vector distances; vector nodes; #pragma omp CARET_FOR schedule(dynamic) for (int32_t i = 0; i < numNodes; ++i) { if (myRoiColumn[i] > 0.0f)//we don't need to scatter from things outside the ROI { myGeoHelp->getNodesToGeoDist(i, myGeoDist, nodes, distances, true); const vector& tempneighbors = myTopoHelp->getNodeNeighbors(i); if (distances.size() <= tempneighbors.size())//because neighbors doesn't include center, so if they are equal, geo is missing a neighbor { nodes = tempneighbors; nodes.push_back(i); myGeoHelp->getGeoToTheseNodes(i, nodes, distances, true); } int32_t numNeigh = (int32_t)distances.size(); tempList[i].m_weightSum = 0.0f; for (int32_t j = 0; j < numNeigh; ++j) {//but we DO need to compute scattering TO things outside the ROI, so that our normalization doesn't increase the in-ROI influence of edge nodes float weight = exp(distances[j] * distances[j] * gaussianDenom);//exp(- dist ^ 2 / (2 * sigma ^ 2)) tempList[i].m_weightSum += weight;//add it to the total weight in order to normalize correctly if (myRoiColumn[nodes[j]] > 0.0f) {//BUT, don't add it to the list if it is outside the ROI tempList[i].m_nodes.push_back(nodes[j]); tempList[i].m_weights.push_back(weight); } } float myFactor = 1.0f / tempList[i].m_weightSum;//make each scattering kernel sum to 1 int32_t numUsed = (int32_t)tempList[i].m_nodes.size(); for (int32_t j = 0; j < numUsed; ++j) { tempList[i].m_weights[j] *= myFactor; } tempList[i].m_weightSum = 0.0f;//this is never actually used again, but make sure it is wrong in case anything tries to use it } } } m_weightLists.resize(numNodes);//now convert it to gathering kernels for (int32_t i = 0; i < numNodes; ++i)//sadly, this is VERY hard to parallelize in a manner that is efficient, since it needs random access modification { m_weightLists[i].m_weightSum = 0.0f;//memory initialization may not go much faster in parallel size_t neighborCount = tempList[i].m_nodes.size(); m_weightLists[i].m_nodes.reserve(neighborCount);//also preallocate the expected number of nodes, again, should be exact except for rounding errors in geodesic distance m_weightLists[i].m_weights.reserve(neighborCount); } for (int32_t i = 0; i < numNodes; ++i)//and this needs to push onto random vectors in the weight list { int32_t numNeigh = tempList[i].m_nodes.size(); for (int32_t j = 0; j < numNeigh; ++j) { int32_t node = tempList[i].m_nodes[j]; float weight = tempList[i].m_weights[j]; m_weightLists[node].m_nodes.push_back(i); m_weightLists[node].m_weights.push_back(weight); m_weightLists[node].m_weightSum += weight; } } } void MetricSmoothingObject::precomputeWeights(const SurfaceFile* mySurf, float myKernel, const MetricFile* theRoi, Method myMethod, const float* nodeAreas) { const float* passAreas = nodeAreas; vector areasTemp; if (passAreas == NULL) {//corrected node areas need to be passed into all geodesic smoothings, to generate corrected distances mySurf->computeNodeAreas(areasTemp); passAreas = areasTemp.data(); } if (theRoi != NULL) { switch (myMethod) { case GEO_GAUSS_AREA: precomputeWeightsROIGeoGaussArea(mySurf, myKernel, theRoi, passAreas); break; case GEO_GAUSS_EQUAL: precomputeWeightsROIGeoGaussEqual(mySurf, myKernel, theRoi, passAreas); break; case GEO_GAUSS: precomputeWeightsROIGeoGauss(mySurf, myKernel, theRoi, passAreas); break; default: throw CaretException("unknown smoothing method specified"); }; } else { switch (myMethod) { case GEO_GAUSS_AREA: precomputeWeightsGeoGaussArea(mySurf, myKernel, passAreas); break; case GEO_GAUSS_EQUAL: precomputeWeightsGeoGaussEqual(mySurf, myKernel, passAreas); break; case GEO_GAUSS: precomputeWeightsGeoGauss(mySurf, myKernel, passAreas); break; default: throw CaretException("unknown smoothing method specified"); }; } } connectome-workbench-1.4.2/src/Files/MetricSmoothingObject.h000066400000000000000000000106051360521144700241010ustar00rootroot00000000000000#ifndef __METRIC_SMOOTHING_OBJECT_H__ #define __METRIC_SMOOTHING_OBJECT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ //NOTE: this is largely for special-purpose smoothing by providing greater efficiency and flexibility, since it can be reused with different rois or on different metric objects // after being constructed once (constructor takes a while). If you just want to smooth one metric object with one (or no) ROI, you probably want AlgorithmMetricSmoothing. // //NOTE: this object contains no mutable members, multiple threads can call the same function on the same instance and expect consistent behavior, while running concurrently, // as long as they don't call it with output arguments that overlap (same instance, same row, or one row plus full metric, etc) // //NOTE: for a static ROI, it is (sometimes much) more efficient to use it in the constructor, and provide no ROI (NULL) to the functions, using both an ROI in constructor and in method // will result in the effective ROI being the logical AND of the two (intersection). #include "stdint.h" #include "stddef.h" #include namespace caret { class SurfaceFile; class MetricFile; class MetricSmoothingObject { public: enum Method { GEO_GAUSS_AREA, GEO_GAUSS_EQUAL, GEO_GAUSS }; MetricSmoothingObject(const SurfaceFile* mySurf, const float& kernel, const MetricFile* myRoi = NULL, Method myMethod = GEO_GAUSS_AREA, const float* nodeAreas = NULL); void smoothColumn(const MetricFile* metricIn, const int& whichColumn, MetricFile* columnOut, const MetricFile* roi = NULL, const bool& fixZeros = false) const; void smoothColumn(const MetricFile* metricIn, const int& whichColumn, MetricFile* metricOut, const int& whichOutColumn, const MetricFile* roi = NULL, const int& whichRoiColumn = 0, const bool& fixZeros = false) const; void smoothMetric(const MetricFile* metricIn, MetricFile* metricOut, const MetricFile* roi = NULL, const bool& fixZeros = false) const; private: struct WeightList { std::vector m_nodes; std::vector m_weights; float m_weightSum; }; std::vector m_weightLists; void smoothColumnInternal(float* scratch, const MetricFile* metricIn, const int& whichColumn, MetricFile* metricOut, const int& whichOutColumn, const bool& fixZeros) const; void smoothColumnInternal(float* scratch, const MetricFile* metricIn, const int& whichColumn, MetricFile* metricOut, const int& whichOutColumn, const MetricFile* roi, const int& whichRoiColumn, const bool& fixZeros) const; void precomputeWeights(const SurfaceFile* mySurf, float myKernel, const MetricFile* theRoi, Method myMethod, const float* nodeAreas); void precomputeWeightsGeoGauss(const SurfaceFile* mySurf, float myKernel, const float* nodeAreas); void precomputeWeightsROIGeoGauss(const SurfaceFile* mySurf, float myKernel, const MetricFile* theRoi, const float* nodeAreas); void precomputeWeightsGeoGaussArea(const SurfaceFile* mySurf, float myKernel, const float* nodeAreas); void precomputeWeightsROIGeoGaussArea(const SurfaceFile* mySurf, float myKernel, const MetricFile* theRoi, const float* nodeAreas); void precomputeWeightsGeoGaussEqual(const SurfaceFile* mySurf, float myKernel, const float* nodeAreas); void precomputeWeightsROIGeoGaussEqual(const SurfaceFile* mySurf, float myKernel, const MetricFile* theRoi, const float* nodeAreas); MetricSmoothingObject(); }; } #endif //__METRIC_SMOOTHING_OBJECT_H__ connectome-workbench-1.4.2/src/Files/NodeAndVoxelColoring.cxx000066400000000000000000001223201360521144700242330ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include //#include //#include //#include #define __NODE_AND_VOXEL_COLORING_DECLARE__ #include "NodeAndVoxelColoring.h" #undef __NODE_AND_VOXEL_COLORING_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretOMP.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "GroupAndNameHierarchyItem.h" #include "Palette.h" #include "PaletteColorMapping.h" #include "MathFunctions.h" using namespace caret; static const float positiveThresholdGreenColor[4] = { 115.0f / 255.0f, 255.0f / 255.0f, 180.0f / 255.0f, 255.0f / 255.0f }; static const float negativeThresholdGreenColor[] = { 180.0f / 255.0f, 255.0f / 255.0f, 115.0f / 255.0f, 255.0f / 255.0f }; /** * \class NodeAndVoxelColoring * \brief Static methods for coloring nodes and voxels. * * Provides methods for coloring nodes and voxels. */ /** * Color scalars using a palette that accepts a void* type for the * color array to that multiple data types are supported without * having to allocate memory for conversion to one data type or * the other nor duplicate lots of code for each data type. * * @param statistics * Descriptive statistics for min/max values. * @param paletteColorMapping * Specifies mapping of scalars to palette colors. * @param scalarValues * Scalars that are used to color the values. * Number of elements is 'numberOfScalars'. * @param thresholdPaletteColorMapping * Specifies thresholding for thresholding scalars. * @param thresholdValues * Thresholds for inhibiting coloring. * Number of elements is 'numberOfScalars'. * @param numberOfScalars * Number of scalars and thresholds. * @param colorDataType * Data type of the rgbaOut parameter * @param rgbaOutPointer * RGBA Colors that are output. This is a VOID type and its * true type is provided by the previous parameter colorDataType. * @param ignoreThresholding * If true, skip all threshold testing */ void NodeAndVoxelColoring::colorScalarsWithPalettePrivate(const FastStatistics* statistics, const PaletteColorMapping* paletteColorMapping, const float* scalarValues, const PaletteColorMapping* thresholdPaletteColorMapping, const float* thresholdValues, const int64_t numberOfScalars, const ColorDataType colorDataType, void* rgbaOutPointer, const bool ignoreThresholding) { if (numberOfScalars <= 0) { return; } const Palette* palette = paletteColorMapping->getPalette(); CaretAssert(palette); CaretAssert(statistics); CaretAssert(paletteColorMapping); CaretAssert(scalarValues); CaretAssert(thresholdPaletteColorMapping); CaretAssert(thresholdValues); CaretAssert(rgbaOutPointer); /* * Cast to data type for rgba coloring */ float* rgbaFloat = NULL; uint8_t* rgbaUnsignedByte = NULL; switch (colorDataType) { case COLOR_TYPE_FLOAT: rgbaFloat = (float*)rgbaOutPointer; break; case COLOR_TYPE_UNSIGNED_BTYE: rgbaUnsignedByte = (uint8_t*)rgbaOutPointer; break; } /* * Type of threshold testing */ bool showOutsideFlag = false; const PaletteThresholdTestEnum::Enum thresholdTest = thresholdPaletteColorMapping->getThresholdTest(); switch (thresholdTest) { case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE: showOutsideFlag = true; break; case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE: showOutsideFlag = false; break; } /* * Range of values allowed by thresholding */ const PaletteThresholdTypeEnum::Enum thresholdType = paletteColorMapping->getThresholdType(); const float thresholdMinimum = thresholdPaletteColorMapping->getThresholdMinimum(thresholdType); const float thresholdMaximum = thresholdPaletteColorMapping->getThresholdMaximum(thresholdType); const float thresholdMappedPositive = thresholdPaletteColorMapping->getThresholdMappedMaximum(); const float thresholdMappedPositiveAverageArea = thresholdPaletteColorMapping->getThresholdMappedAverageAreaMaximum(); const float thresholdMappedNegative = thresholdPaletteColorMapping->getThresholdMappedMinimum(); const float thresholdMappedNegativeAverageArea = thresholdPaletteColorMapping->getThresholdMappedAverageAreaMinimum(); const bool showMappedThresholdFailuresInGreen = thresholdPaletteColorMapping->isShowThresholdFailureInGreen(); /* * Skip threshold testing? */ const bool skipThresholdTesting = (ignoreThresholding || (thresholdType == PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF)); /* * Display of negative, zero, and positive values allowed. */ const bool hidePositiveValues = (paletteColorMapping->isDisplayPositiveDataFlag() == false); const bool hideNegativeValues = (paletteColorMapping->isDisplayNegativeDataFlag() == false); const bool hideZeroValues = (paletteColorMapping->isDisplayZeroDataFlag() == false); const bool interpolateFlag = paletteColorMapping->isInterpolatePaletteFlag(); /* * Convert data values to normalized palette values. */ std::vector normalizedValues(numberOfScalars); paletteColorMapping->mapDataToPaletteNormalizedValues(statistics, scalarValues, &normalizedValues[0], numberOfScalars); /* * Get color for normalized values of -1.0 and 1.0. * Since there may be a large number of values that are -1.0 or 1.0 * we can compute the color only once for these values and save time. */ float rgbaPositiveOne[4], rgbaNegativeOne[4]; palette->getPaletteColor(1.0, interpolateFlag, rgbaPositiveOne); const bool rgbaPositiveOneValid = (rgbaPositiveOne[3] > 0.0); palette->getPaletteColor(-1.0, interpolateFlag, rgbaNegativeOne); const bool rgbaNegativeOneValid = (rgbaNegativeOne[3] > 0.0); /* * Color all scalars. */ #pragma omp CARET_PARFOR schedule(dynamic, 4096) for (int64_t i = 0; i < numberOfScalars; i++) { const int64_t i4 = i * 4; /* * Initialize coloring for node since one of the * continue statements below may cause moving * on to next node */ switch (colorDataType) { case COLOR_TYPE_FLOAT: rgbaFloat[i4] = 0.0; rgbaFloat[i4+1] = 0.0; rgbaFloat[i4+2] = 0.0; rgbaFloat[i4+3] = 0.0; break; case COLOR_TYPE_UNSIGNED_BTYE: rgbaUnsignedByte[i4] = 0; rgbaUnsignedByte[i4+1] = 0; rgbaUnsignedByte[i4+2] = 0; rgbaUnsignedByte[i4+3] = 0; break; } float scalar = scalarValues[i]; const float threshold = thresholdValues[i]; /* * Positive/Zero/Negative Test */ if (scalar > PaletteColorMapping::SMALL_POSITIVE) { // JWH 24 April 2015 NodeAndVoxelColoring::SMALL_POSITIVE) { if (hidePositiveValues) { continue; } } else if (scalar < PaletteColorMapping::SMALL_NEGATIVE) { // JWH 24 April 2015 NodeAndVoxelColoring::SMALL_NEGATIVE) { if (hideNegativeValues) { continue; } } else if (MathFunctions::isNaN(scalar)) { continue;//TSC: never color NaN } else { /* * May be very near zero so force to zero. * * TSC: that seems wrong, leave the normalized value alone * if the data value is near zero, that doesn't mean the palette settings aren't also near zero * therefore, normalized value may not be near zero, which is important * */ //normalizedValues[i] = 0.0; if (hideZeroValues) { continue; } } /* * Temporary for rgba coloring now that past possible * continue statements */ float rgbaOut[4] = { 0.0, 0.0, 0.0, 0.0 }; const float normalValue = normalizedValues[i]; /* * RGBA colors have been mapped for extreme values */ if (normalValue >= 1.0) { if (rgbaPositiveOneValid) { rgbaOut[0] = rgbaPositiveOne[0]; rgbaOut[1] = rgbaPositiveOne[1]; rgbaOut[2] = rgbaPositiveOne[2]; rgbaOut[3] = rgbaPositiveOne[3]; } } else if (normalValue <= -1.0) { if (rgbaNegativeOneValid) { rgbaOut[0] = rgbaNegativeOne[0]; rgbaOut[1] = rgbaNegativeOne[1]; rgbaOut[2] = rgbaNegativeOne[2]; rgbaOut[3] = rgbaNegativeOne[3]; } } else { /* * Color scalar using palette */ float rgba[4]; palette->getPaletteColor(normalValue, interpolateFlag, rgba); if (rgba[3] > 0.0f) { rgbaOut[0] = rgba[0]; rgbaOut[1] = rgba[1]; rgbaOut[2] = rgba[2]; rgbaOut[3] = rgba[3]; } } /* * Threshold Test * Threshold is done last so colors are still set * but if threshold test fails, alpha is set invalid. */ bool thresholdPassedFlag = false; if (skipThresholdTesting) { thresholdPassedFlag = true; } else if (showOutsideFlag) { if (threshold > thresholdMaximum) { thresholdPassedFlag = true; } else if (threshold < thresholdMinimum) { thresholdPassedFlag = true; } } else { if ((threshold >= thresholdMinimum) && (threshold <= thresholdMaximum)) { thresholdPassedFlag = true; } } if (thresholdPassedFlag == false) { rgbaOut[3] = 0.0; if (showMappedThresholdFailuresInGreen) { if (thresholdType == PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED) { if (threshold > 0.0f) { if ((threshold < thresholdMappedPositive) && (threshold > thresholdMappedPositiveAverageArea)) { rgbaOut[0] = positiveThresholdGreenColor[0]; rgbaOut[1] = positiveThresholdGreenColor[1]; rgbaOut[2] = positiveThresholdGreenColor[2]; rgbaOut[3] = positiveThresholdGreenColor[3]; } } else if (threshold < 0.0f) { if ((threshold > thresholdMappedNegative) && (threshold < thresholdMappedNegativeAverageArea)) { rgbaOut[0] = negativeThresholdGreenColor[0]; rgbaOut[1] = negativeThresholdGreenColor[1]; rgbaOut[2] = negativeThresholdGreenColor[2]; rgbaOut[3] = negativeThresholdGreenColor[3]; } } } } } switch (colorDataType) { case COLOR_TYPE_FLOAT: CaretAssertArrayIndex(rgbaFloat, numberOfScalars * 4, i*4+3); rgbaFloat[i4] = rgbaOut[0]; rgbaFloat[i4+1] = rgbaOut[1]; rgbaFloat[i4+2] = rgbaOut[2]; rgbaFloat[i4+3] = rgbaOut[3]; break; case COLOR_TYPE_UNSIGNED_BTYE: CaretAssertArrayIndex(rgbaUnsignedByte, numberOfScalars * 4, i*4+3); rgbaUnsignedByte[i4] = rgbaOut[0] * 255.0; rgbaUnsignedByte[i4+1] = rgbaOut[1] * 255.0; rgbaUnsignedByte[i4+2] = rgbaOut[2] * 255.0; if (rgbaOut[3] > 0.0) { rgbaUnsignedByte[i4+3] = rgbaOut[3] * 255.0; } else { rgbaUnsignedByte[i4+3] = 0; } break; } } } /** * Color scalars using a palette. * * @param statistics * Descriptive statistics for min/max values. * @param paletteColorMapping * Specifies mapping of scalars to palette colors. * @param scalarValues * Scalars that are used to color the values. * Number of elements is 'numberOfScalars'. * @param thresholdPaletteColorMapping * Specifies thresholding for thresholding scalars. * @param thresholdValues * Thresholds for inhibiting coloring. * Number of elements is 'numberOfScalars'. * @param numberOfScalars * Number of scalars and thresholds. * @param rgbaOut * RGBA Colors that are output. The alpha * value will be negative if the scalar does * not receive any coloring. * Number of elements is 'numberOfScalars' * 4. * @param ignoreThresholding * If true, skip all threshold testing */ void NodeAndVoxelColoring::colorScalarsWithPalette(const FastStatistics* statistics, const PaletteColorMapping* paletteColorMapping, const float* scalarValues, const PaletteColorMapping* thresholdPaletteColorMapping, const float* thresholdValues, const int64_t numberOfScalars, float* rgbaOut, const bool ignoreThresholding) { colorScalarsWithPalettePrivate(statistics, paletteColorMapping, scalarValues, thresholdPaletteColorMapping, thresholdValues, numberOfScalars, COLOR_TYPE_FLOAT, (void*)rgbaOut, ignoreThresholding); } /** * Color scalars using a palette. * * @param statistics * Descriptive statistics for min/max values. * @param paletteColorMapping * Specifies mapping of scalars to palette colors. * @param scalarValues * Scalars that are used to color the values. * Number of elements is 'numberOfScalars'. * @param thresholdPaletteColorMapping * Specifies thresholding for thresholding scalars. * @param thresholdValues * Thresholds for inhibiting coloring. * Number of elements is 'numberOfScalars'. * @param numberOfScalars * Number of scalars and thresholds. * @param rgbaOut * RGBA Colors that are output. The alpha * value will be negative if the scalar does * not receive any coloring. * Number of elements is 'numberOfScalars' * 4. * @param ignoreThresholding * If true, skip all threshold testing */ void NodeAndVoxelColoring::colorScalarsWithPalette(const FastStatistics* statistics, const PaletteColorMapping* paletteColorMapping, const float* scalarValues, const PaletteColorMapping* thresholdPaletteColorMapping, const float* thresholdValues, const int64_t numberOfScalars, uint8_t* rgbaOut, const bool ignoreThresholding) { colorScalarsWithPalettePrivate(statistics, paletteColorMapping, scalarValues, thresholdPaletteColorMapping, thresholdValues, numberOfScalars, COLOR_TYPE_UNSIGNED_BTYE, (void*)rgbaOut, ignoreThresholding); } /** * Color RGBA data. * * @param redComponents * Values for red components. Range [0, 255]. * @param greenComponents * Values for green components. Range [0, 255]. * @param blueComponents * Values for blue components. Range [0, 255]. * @param alphaComponents * Values for alpha components (NULL if alpha not valid) * @param colorDataType * Data type of the rgbaOut parameter * @param rgbThreshold * Threshold RGB (voxel not drawn if voxel RGB components LESS THAN these values). * Range [0, 255]. * @param rgbaOutPointer * RGBA Colors that are output. The alpha * value will be negative if the scalar does * not receive any coloring. * Number of elements is 'numberOfScalars' * 4. */ void NodeAndVoxelColoring::colorScalarsWithRGBAPrivate(const float* redComponents, const float* greenComponents, const float* blueComponents, const float* alphaComponents, const int64_t numberOfComponents, const ColorDataType colorDataType, const uint8_t* rgbThreshold, uint8_t* rgbaOutPointer) { /* * Cast to data type for rgba coloring */ float* rgbaFloat = NULL; uint8_t* rgbaUnsignedByte = NULL; float thresholdRed = -1.0; float thresholdGreen = -1.0; float thresholdBlue = -1.0; switch (colorDataType) { case COLOR_TYPE_FLOAT: { rgbaFloat = (float*)rgbaOutPointer; const float* threshFloat = (float*)rgbThreshold; thresholdRed = threshFloat[0]; thresholdGreen = threshFloat[1]; thresholdBlue = threshFloat[2]; } break; case COLOR_TYPE_UNSIGNED_BTYE: { rgbaUnsignedByte = (uint8_t*)rgbaOutPointer; const uint8_t* threshByte = (uint8_t*)rgbThreshold; thresholdRed = threshByte[0]; thresholdGreen = threshByte[1]; thresholdBlue = threshByte[2]; } break; } for (int64_t i = 0; i < numberOfComponents; i++) { const float red = redComponents[i]; const float green = greenComponents[i]; const float blue = blueComponents[i]; float alpha = 0.0; if ((red >= thresholdRed) && (green >= thresholdGreen) && (blue >= thresholdBlue)) { alpha = ((alphaComponents == NULL) ? 255.0 : alphaComponents[i]); } const int64_t i4 = i * 4; switch (colorDataType) { case COLOR_TYPE_FLOAT: rgbaFloat[i4] = red / 255.0; rgbaFloat[i4+1] = green / 255.0; rgbaFloat[i4+2] = blue / 255.0; rgbaFloat[i4+3] = alpha / 255.0; break; case COLOR_TYPE_UNSIGNED_BTYE: rgbaUnsignedByte[i4] = static_cast(red); rgbaUnsignedByte[i4+1] = static_cast(green); rgbaUnsignedByte[i4+2] = static_cast(blue); rgbaUnsignedByte[i4+3] = static_cast(alpha); break; } } } /** * Color RGBA data. * * @param redComponents * Values for red components. * @param greenComponents * Values for green components. * @param blueComponents * Values for blue components. * @param alphaComponents * Values for alpha components (NULL if alpha not valid) * @param numberOfComponents * Number of components (each color component contains this number of values). * @param rgbThreshold * Threshold RGB (voxel not drawn if voxel RGB components LESS THAN these values). * Range is [0, 255]. * @param rgbaOut * RGBA Colors that are output. The alpha * value will be negative if the scalar does * not receive any coloring. * Number of elements is 'numberOfComponents' * 4. */ void NodeAndVoxelColoring::colorScalarsWithRGBA(const float* redComponents, const float* greenComponents, const float* blueComponents, const float* alphaComponents, const int64_t numberOfComponents, const uint8_t rgbThreshold[3], uint8_t* rgbaOut) { colorScalarsWithRGBAPrivate(redComponents, greenComponents, blueComponents, alphaComponents, numberOfComponents, COLOR_TYPE_UNSIGNED_BTYE, rgbThreshold, rgbaOut); } /** * Assign colors to label indices using a GIFTI label table. * * @param labelTabl * Label table used for coloring and indexing with label indices. * @param labelIndices * The indices are are used to access colors in the label table. * @param numberOfIndices * Number of indices. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbv * Output with assigned colors. Number of elements is (numberOfIndices * 4). */ void NodeAndVoxelColoring::colorIndicesWithLabelTableForDisplayGroupTab(const GiftiLabelTable* labelTable, const float* labelIndices, const int64_t numberOfIndices, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, float* rgbv) { NodeAndVoxelColoring::colorIndicesWithLabelTableForDisplayGroupTabPrivate(labelTable, labelIndices, numberOfIndices, displayGroup, tabIndex, COLOR_TYPE_FLOAT, (void*)rgbv); } /** * Assign colors to label indices using a GIFTI label table. * * @param labelTabl * Label table used for coloring and indexing with label indices. * @param labelIndices * The indices are are used to access colors in the label table. * @param numberOfIndices * Number of indices. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbv * Output with assigned colors. Number of elements is (numberOfIndices * 4). */ void NodeAndVoxelColoring::colorIndicesWithLabelTableForDisplayGroupTab(const GiftiLabelTable* labelTable, const float* labelIndices, const int64_t numberOfIndices, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbv) { NodeAndVoxelColoring::colorIndicesWithLabelTableForDisplayGroupTabPrivate(labelTable, labelIndices, numberOfIndices, displayGroup, tabIndex, COLOR_TYPE_UNSIGNED_BTYE, (void*)rgbv); } /** * Assign colors to label indices using a GIFTI label table. * * @param labelTabl * Label table used for coloring and indexing with label indices. * @param labelIndices * The indices are are used to access colors in the label table. * @param numberOfIndices * Number of indices. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param colorDataType * Data type of the rgbaOut parameter * @param rgbaOutPointer * RGBA Colors that are output. This is a VOID type and its * true type is provided by the previous parameter colorDataType. * @param rgbv * Output with assigned colors. Number of elements is (numberOfIndices * 4). */ void NodeAndVoxelColoring::colorIndicesWithLabelTableForDisplayGroupTabPrivate(const GiftiLabelTable* labelTable, const float* labelIndices, const int64_t numberOfIndices, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const ColorDataType colorDataType, void* rgbaOutPointer) { /* * Cast to data type for rgba coloring */ float* rgbaFloat = NULL; uint8_t* rgbaUnsignedByte = NULL; switch (colorDataType) { case COLOR_TYPE_FLOAT: rgbaFloat = (float*)rgbaOutPointer; break; case COLOR_TYPE_UNSIGNED_BTYE: rgbaUnsignedByte = (uint8_t*)rgbaOutPointer; break; } /* * Invalidate all coloring. */ switch (colorDataType) { case COLOR_TYPE_FLOAT: for (int64_t i = 0; i < numberOfIndices; i++) { rgbaFloat[i*4+3] = 0.0; } break; case COLOR_TYPE_UNSIGNED_BTYE: for (int64_t i = 0; i < numberOfIndices; i++) { rgbaUnsignedByte[i*4+3] = 0; } break; } /* * Assign colors from labels to nodes */ float labelRGBA[4]; for (int64_t i = 0; i < numberOfIndices; i++) { const int64_t labelKey = static_cast(labelIndices[i]); const GiftiLabel* gl = labelTable->getLabel(labelKey); if (gl != NULL) { const GroupAndNameHierarchyItem* item = gl->getGroupNameSelectionItem(); bool colorDataFlag = false; if (item != NULL) { if (tabIndex == NodeAndVoxelColoring::INVALID_TAB_INDEX) { colorDataFlag = true; } else if (item->isSelected(displayGroup, tabIndex)) { colorDataFlag = true; } } else { colorDataFlag = true; } if (colorDataFlag) { gl->getColor(labelRGBA); if (labelRGBA[3] > 0.0) { const int64_t i4 = i * 4; switch (colorDataType) { case COLOR_TYPE_FLOAT: CaretAssertArrayIndex(rgbaFloat, numberOfIndices * 4, i*4+3); rgbaFloat[i*4] = labelRGBA[0]; rgbaFloat[i*4+1] = labelRGBA[1]; rgbaFloat[i*4+2] = labelRGBA[2]; rgbaFloat[i*4+3] = labelRGBA[3]; break; case COLOR_TYPE_UNSIGNED_BTYE: CaretAssertArrayIndex(rgbaUnsignedByte, numberOfIndices * 4, i*4+3); rgbaUnsignedByte[i4] = labelRGBA[0] * 255.0; rgbaUnsignedByte[i4+1] = labelRGBA[1] * 255.0; rgbaUnsignedByte[i4+2] = labelRGBA[2] * 255.0; if (labelRGBA[3] > 0.0) { rgbaUnsignedByte[i4+3] = labelRGBA[3] * 255.0; } else { rgbaUnsignedByte[i4+3] = 0; } break; } } } } } } /** * Assign colors to label indices using a GIFTI label table. * * @param labelTabl * Label table used for coloring and indexing with label indices. * @param labelIndices * The indices are are used to access colors in the label table. * @param numberOfIndices * Number of indices. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbv * Output with assigned colors. Number of elements is (numberOfIndices * 4). */ void NodeAndVoxelColoring::colorIndicesWithLabelTable(const GiftiLabelTable* labelTable, const float* labelIndices, const int64_t numberOfIndices, float* rgbv) { NodeAndVoxelColoring::colorIndicesWithLabelTableForDisplayGroupTabPrivate(labelTable, labelIndices, numberOfIndices, DisplayGroupEnum::DISPLAY_GROUP_TAB, NodeAndVoxelColoring::INVALID_TAB_INDEX, COLOR_TYPE_FLOAT, (void*)rgbv); } /** * Assign colors to label indices using a GIFTI label table. * * @param labelTabl * Label table used for coloring and indexing with label indices. * @param labelIndices * The indices are are used to access colors in the label table. * @param numberOfIndices * Number of indices. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbv * Output with assigned colors. Number of elements is (numberOfIndices * 4). */ void NodeAndVoxelColoring::colorIndicesWithLabelTable(const GiftiLabelTable* labelTable, const float* labelIndices, const int64_t numberOfIndices, uint8_t* rgbv) { NodeAndVoxelColoring::colorIndicesWithLabelTableForDisplayGroupTabPrivate(labelTable, labelIndices, numberOfIndices, DisplayGroupEnum::DISPLAY_GROUP_TAB, NodeAndVoxelColoring::INVALID_TAB_INDEX, COLOR_TYPE_UNSIGNED_BTYE, (void*)rgbv); } /** * Convert the slice coloring to outline mode. * * @param rgbaInOut * Coloring for the slice (input and output) * @param labelDrawingType * Type of drawing for label filling and outline. * @param labelOutlineColor * Outline color of label. * @param xdim * X-dimension of slice (number of columns) * @param ydim * Y-dimension of slice (number of rows). */ void NodeAndVoxelColoring::convertSliceColoringToOutlineMode(uint8_t* rgbaInOut, const LabelDrawingTypeEnum::Enum labelDrawingType, const CaretColorEnum::Enum labelOutlineColor, const int64_t xdim, const int64_t ydim) { /* * Copy the rgba colors */ const int64_t numRGBA = xdim * ydim * 4; if (numRGBA <= 0) { return; } std::vector sliceCopyVector(numRGBA); uint8_t* rgba = &sliceCopyVector[0]; for (int64_t i = 0; i < numRGBA; i++) { rgba[i] = rgbaInOut[i]; } uint8_t outlineRGBA[4]; CaretColorEnum::toRGBAByte(labelOutlineColor, outlineRGBA); outlineRGBA[3] = 255; /* * Examine coloring for all voxels except those along the edge */ const int64_t lastX = xdim - 1; const int64_t lastY = ydim - 1; for (int64_t i = 1; i < lastX; i++) { for (int64_t j = 1; j < lastY; j++) { const int iStart = i - 1; const int iEnd = i + 1; const int jStart = j - 1; const int jEnd = j + 1; const int64_t myOffset = (i + (xdim * j)) * 4; CaretAssert(myOffset < numRGBA); const uint8_t* myRGBA = &rgba[myOffset]; if (myRGBA[3] <= 0) { continue; } /* * Determine if voxel colors match voxel coloring * of ALL immediate neighbors (8-connected). */ bool isLabelBoundaryVoxel = false; for (int64_t iNeigh = iStart; iNeigh <= iEnd; iNeigh++) { for (int64_t jNeigh = jStart; jNeigh <= jEnd; jNeigh++) { const int64_t neighOffset = (iNeigh + (xdim * jNeigh)) * 4; CaretAssert(neighOffset < numRGBA); const uint8_t* neighRGBA = &rgba[neighOffset]; for (int64_t k = 0; k < 4; k++) { if (myRGBA[k] != neighRGBA[k]) { isLabelBoundaryVoxel = true; break; } } if (isLabelBoundaryVoxel) { break; } } if (isLabelBoundaryVoxel) { break; } } /* * Override the coloring as needed. */ switch (labelDrawingType) { case LabelDrawingTypeEnum::DRAW_FILLED: break; case LabelDrawingTypeEnum::DRAW_FILLED_WITH_OUTLINE_COLOR: if (isLabelBoundaryVoxel) { rgbaInOut[myOffset] = outlineRGBA[0]; rgbaInOut[myOffset + 1] = outlineRGBA[1]; rgbaInOut[myOffset + 2] = outlineRGBA[2]; rgbaInOut[myOffset + 3] = outlineRGBA[3]; } break; case LabelDrawingTypeEnum::DRAW_OUTLINE_COLOR: if (isLabelBoundaryVoxel) { rgbaInOut[myOffset] = outlineRGBA[0]; rgbaInOut[myOffset + 1] = outlineRGBA[1]; rgbaInOut[myOffset + 2] = outlineRGBA[2]; rgbaInOut[myOffset + 3] = outlineRGBA[3]; } else { rgbaInOut[myOffset + 3] = 0; } break; case LabelDrawingTypeEnum::DRAW_OUTLINE_LABEL_COLOR: if ( ! isLabelBoundaryVoxel) { rgbaInOut[myOffset + 3] = 0; } break; } } } } /** * Convert the palette slice coloring to outline mode. * * @param rgbaInOut * Coloring for the slice (input and output) * @param outlineMode * Outline mode * @param outlineColor * Type of drawing for label filling and outline. * @param labelOutlineColor * Outline color of label. * @param xdim * X-dimension of slice (number of columns) * @param ydim * Y-dimension of slice (number of rows). */ void NodeAndVoxelColoring::convertPaletteSliceColoringToOutlineMode(uint8_t* rgbaInOut, const PaletteThresholdOutlineDrawingModeEnum::Enum outlineMode, const CaretColorEnum::Enum outlineColor, const int64_t xdim, const int64_t ydim) { bool hideDataFlag = false; switch (outlineMode) { case PaletteThresholdOutlineDrawingModeEnum::OFF: return; break; case PaletteThresholdOutlineDrawingModeEnum::OUTLINE: hideDataFlag = true; break; case PaletteThresholdOutlineDrawingModeEnum::OUTLINE_AND_DATA: break; } /* * Copy the rgba colors */ const int64_t numRGBA = xdim * ydim * 4; if (numRGBA <= 0) { return; } std::vector sliceCopyVector(numRGBA); uint8_t* rgba = &sliceCopyVector[0]; for (int64_t i = 0; i < numRGBA; i++) { rgba[i] = rgbaInOut[i]; } uint8_t outlineRGBA[4]; CaretColorEnum::toRGBAByte(outlineColor, outlineRGBA); outlineRGBA[3] = 255; /* * Examine coloring for all voxels except those along the edge */ const int64_t lastX = xdim - 1; const int64_t lastY = ydim - 1; for (int64_t i = 1; i < lastX; i++) { for (int64_t j = 1; j < lastY; j++) { const int iStart = i - 1; const int iEnd = i + 1; const int jStart = j - 1; const int jEnd = j + 1; const int64_t myOffset = (i + (xdim * j)) * 4; CaretAssert(myOffset < numRGBA); const uint8_t* myRGBA = &rgba[myOffset]; if (myRGBA[3] <= 0) { continue; } /* * Determine if voxel colors match voxel coloring * of ALL immediate neighbors (8-connected). */ bool isLabelBoundaryVoxel = false; for (int64_t iNeigh = iStart; iNeigh <= iEnd; iNeigh++) { for (int64_t jNeigh = jStart; jNeigh <= jEnd; jNeigh++) { if ((i != iNeigh) || (j != jNeigh)) { const int64_t neighOffset = (iNeigh + (xdim * jNeigh)) * 4; CaretAssert(neighOffset < numRGBA); const uint8_t* neighRGBA = &rgba[neighOffset]; if (neighRGBA[3] <= 0.0) { isLabelBoundaryVoxel = true; } } if (isLabelBoundaryVoxel) { break; } } if (isLabelBoundaryVoxel) { break; } } if (isLabelBoundaryVoxel) { rgbaInOut[myOffset] = outlineRGBA[0]; rgbaInOut[myOffset + 1] = outlineRGBA[1]; rgbaInOut[myOffset + 2] = outlineRGBA[2]; rgbaInOut[myOffset + 3] = outlineRGBA[3]; } else if (hideDataFlag) { rgbaInOut[myOffset + 3] = 0; } } } } connectome-workbench-1.4.2/src/Files/NodeAndVoxelColoring.h000066400000000000000000000204531360521144700236640ustar00rootroot00000000000000#ifndef __NODE_AND_VOXEL_COLORING__H_ #define __NODE_AND_VOXEL_COLORING__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretColorEnum.h" #include "DisplayGroupEnum.h" #include "LabelDrawingTypeEnum.h" #include "PaletteThresholdOutlineDrawingModeEnum.h" namespace caret { class FastStatistics; class GiftiLabelTable; class PaletteColorMapping; class NodeAndVoxelColoring { public: static void colorScalarsWithPalette(const FastStatistics* statistics, const PaletteColorMapping* paletteColorMapping, const float* scalars, const PaletteColorMapping* thresholdPaletteColorMapping, const float* scalarThresholds, const int64_t numberOfScalars, float* rgbaOut, const bool ignoreThresholding = false); static void colorScalarsWithPalette(const FastStatistics* statistics, const PaletteColorMapping* paletteColorMapping, const float* scalars, const PaletteColorMapping* thresholdPaletteColorMapping, const float* scalarThresholds, const int64_t numberOfScalars, uint8_t* rgbaOut, const bool ignoreThresholding = false); static void colorScalarsWithRGBA(const float* redComponents, const float* greenComponents, const float* blueComponents, const float* alphaComponents, const int64_t numberOfComponents, const uint8_t rgbThreshold[3], uint8_t* rgbaOut); // JWH 24 April 2015 static const float SMALL_POSITIVE; // JWH 24 April 2015 static const float SMALL_NEGATIVE; static void colorIndicesWithLabelTableForDisplayGroupTab(const GiftiLabelTable* labelTable, const float* labelIndices, const int64_t numberOfIndices, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, float* rgbv); static void colorIndicesWithLabelTableForDisplayGroupTab(const GiftiLabelTable* labelTable, const float* labelIndices, const int64_t numberOfIndices, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbv); static void colorIndicesWithLabelTable(const GiftiLabelTable* labelTable, const float* labelIndices, const int64_t numberOfIndices, float* rgbv); static void colorIndicesWithLabelTable(const GiftiLabelTable* labelTable, const float* labelIndices, const int64_t numberOfIndices, uint8_t* rgbv); static void convertSliceColoringToOutlineMode(uint8_t* rgbaInOut, const LabelDrawingTypeEnum::Enum labelDrawingType, const CaretColorEnum::Enum labelOutlineColor, const int64_t xdim, const int64_t ydim); static void convertPaletteSliceColoringToOutlineMode(uint8_t* rgbaInOut, const PaletteThresholdOutlineDrawingModeEnum::Enum outlineMode, const CaretColorEnum::Enum outlineColor, const int64_t xdim, const int64_t ydim); private: enum ColorDataType { COLOR_TYPE_FLOAT, COLOR_TYPE_UNSIGNED_BTYE }; static void colorScalarsWithPalettePrivate(const FastStatistics* statistics, const PaletteColorMapping* paletteColorMapping, const float* scalars, const PaletteColorMapping* thresholdPaletteColorMapping, const float* scalarThresholds, const int64_t numberOfScalars, const ColorDataType colorDataType, void* rgbaOutPointer, const bool ignoreThresholding); static void colorIndicesWithLabelTableForDisplayGroupTabPrivate(const GiftiLabelTable* labelTable, const float* labelIndices, const int64_t numberOfIndices, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const ColorDataType colorDataType, void* rgbaOutPointer); static void colorScalarsWithRGBAPrivate(const float* redComponents, const float* greenComponents, const float* blueComponents, const float* alphaComponents, const int64_t numberOfComponents, const ColorDataType colorDataType, const uint8_t* rgbThreshold, uint8_t* rgbaOutPointer); NodeAndVoxelColoring(); virtual ~NodeAndVoxelColoring(); NodeAndVoxelColoring(const NodeAndVoxelColoring&); NodeAndVoxelColoring& operator=(const NodeAndVoxelColoring&); static const int32_t INVALID_TAB_INDEX; }; #ifdef __NODE_AND_VOXEL_COLORING_DECLARE__ // JWH 24 April 2015 const float NodeAndVoxelColoring::SMALL_POSITIVE = 0.00001; // JWH 24 April 2015 const float NodeAndVoxelColoring::SMALL_NEGATIVE = -0.00001; const int32_t NodeAndVoxelColoring::INVALID_TAB_INDEX = -1; #endif // __NODE_AND_VOXEL_COLORING_DECLARE__ } // namespace #endif //__NODE_AND_VOXEL_COLORING__H_ connectome-workbench-1.4.2/src/Files/OxfordSparseThreeFile.cxx000066400000000000000000000161471360521144700244300ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OxfordSparseThreeFile.h" #include "ByteOrderEnum.h" #include "ByteSwapping.h" #include "CaretAssert.h" #include "FileInformation.h" #include using namespace caret; using namespace std; OxfordSparseThreeFile::OxfordSparseThreeFile(const AString& dimFileName, const AString& indexFileName, const AString& valueFileName) { m_valueFile = NULL; fstream dimFile(dimFileName.toLocal8Bit().constData(), fstream::in); if (!dimFile) throw DataFileException("error opening dimensions file"); dimFile >> m_dims[0]; if (!dimFile) throw DataFileException("error reading dimensions from file"); dimFile >> m_dims[1]; if (!dimFile) throw DataFileException("error reading dimensions from file"); if (m_dims[0] < 1 || m_dims[1] < 1) throw DataFileException("both dimensions must be positive"); m_indexArray.resize(m_dims[1] + 1); vector lengthArray(m_dims[1]); FileInformation indexFileInfo(indexFileName); if (!indexFileInfo.exists()) throw DataFileException("index file doesn't exist"); if (indexFileInfo.size() != 8 * m_dims[1]) throw DataFileException("index file is the wrong size"); FILE* indexFile = fopen(indexFileName.toLocal8Bit().constData(), "rb"); if (indexFile == NULL) throw DataFileException("error opening index file"); if (fread(lengthArray.data(), sizeof(int64_t), m_dims[1], indexFile) != (size_t)m_dims[1]) throw DataFileException("error reading index file"); if (ByteOrderEnum::isSystemBigEndian()) { ByteSwapping::swapBytes(lengthArray.data(), m_dims[1]); } m_indexArray[0] = 0; for (int64_t i = 0; i < m_dims[1]; ++i) { if (lengthArray[i] > m_dims[0] || lengthArray[i] < 0) throw DataFileException("impossible value found in length array"); m_indexArray[i + 1] = m_indexArray[i] + lengthArray[i]; } FileInformation valueFileInfo(valueFileName); if (!valueFileInfo.exists()) throw DataFileException("value file doesn't exist"); if (valueFileInfo.size() != (int64_t)(2 * sizeof(uint64_t) * m_indexArray[m_dims[1]])) throw DataFileException("value file is the wrong size"); m_valueFile = fopen(valueFileName.toLocal8Bit().constData(), "rb"); if (m_valueFile == NULL) throw DataFileException("error opening value file"); } OxfordSparseThreeFile::~OxfordSparseThreeFile() { if (m_valueFile != NULL) fclose(m_valueFile); } void OxfordSparseThreeFile::getRow(const int64_t& index, int64_t* rowOut) { CaretAssert(index >= 0 && index < m_dims[1]); int64_t start = m_indexArray[index], end = m_indexArray[index + 1]; int64_t numToRead = (end - start) * 2; m_scratchArray.resize(numToRead); if (fseek(m_valueFile, start * sizeof(int64_t) * 2, SEEK_SET) != 0) throw DataFileException("failed to seek in value file"); if (fread(m_scratchArray.data(), sizeof(int64_t), numToRead, m_valueFile) != (size_t)numToRead) throw DataFileException("error reading from value file"); if (ByteOrderEnum::isSystemBigEndian()) { ByteSwapping::swapBytes(m_scratchArray.data(), numToRead); } int64_t curIndex = 0; for (int64_t i = 0; i < numToRead; i += 2) { int64_t index = m_scratchArray[i]; if (index < curIndex || index >= m_dims[0]) throw DataFileException("impossible index value found in value file"); while (curIndex < index) { rowOut[curIndex] = 0; ++curIndex; } ++curIndex; rowOut[index] = m_scratchArray[i + 1]; } while (curIndex < m_dims[0]) { rowOut[curIndex] = 0; ++curIndex; } } void OxfordSparseThreeFile::getRowSparse(const int64_t& index, vector& indicesOut, vector& valuesOut) { CaretAssert(index >= 0 && index < m_dims[1]); int64_t start = m_indexArray[index], end = m_indexArray[index + 1]; int64_t numToRead = (end - start) * 2, numNonzero = end - start; m_scratchArray.resize(numToRead); if (fseek(m_valueFile, start * sizeof(int64_t) * 2, SEEK_SET) != 0) throw DataFileException("failed to seek in value file"); if (fread(m_scratchArray.data(), sizeof(int64_t), numToRead, m_valueFile) != (size_t)numToRead) throw DataFileException("error reading from value file"); if (ByteOrderEnum::isSystemBigEndian()) { ByteSwapping::swapBytes(m_scratchArray.data(), numToRead); } indicesOut.resize(numNonzero); valuesOut.resize(numNonzero); int64_t lastIndex = -1; for (int64_t i = 0; i < numNonzero; ++i) { indicesOut[i] = m_scratchArray[i * 2]; valuesOut[i] = m_scratchArray[i * 2 + 1]; if (indicesOut[i] <= lastIndex || indicesOut[i] >= m_dims[0]) { throw DataFileException("impossible index value found in file"); } lastIndex = indicesOut[i]; } } void OxfordSparseThreeFile::getFibersRow(const int64_t& index, FiberFractions* rowOut) { if (m_scratchRow.size() != (size_t)m_dims[0]) m_scratchRow.resize(m_dims[0]); getRow(index, (int64_t*)m_scratchRow.data()); for (int64_t i = 0; i < m_dims[0]; ++i) { if (m_scratchRow[i] == 0) { rowOut[i].zero(); } else { decodeFibers(m_scratchRow[i], rowOut[i]); } } } void OxfordSparseThreeFile::getFibersRowSparse(const int64_t& index, vector& indicesOut, vector& valuesOut) { getRowSparse(index, indicesOut, m_scratchSparseRow); size_t numNonzero = m_scratchSparseRow.size(); valuesOut.resize(numNonzero); for (size_t i = 0; i < numNonzero; ++i) { decodeFibers(((uint64_t*)m_scratchSparseRow.data())[i], valuesOut[i]); } } void OxfordSparseThreeFile::decodeFibers(const uint64_t& coded, FiberFractions& decoded) { decoded.fiberFractions.resize(3); decoded.totalCount = coded>>32; uint32_t temp = coded & ((1LL<<32) - 1); decoded.distance = (temp % 1001); temp = temp / 1001; decoded.fiberFractions[1] = (temp % 1001) / 1000.0f; temp = temp / 1001; decoded.fiberFractions[0] = temp / 1000.0f; decoded.fiberFractions[2] = 1.0f - decoded.fiberFractions[0] - decoded.fiberFractions[1]; if (decoded.fiberFractions[2] < -0.002f || temp > 1000) { throw DataFileException("error decoding value '" + AString::number(coded) + "' from oxford 3-file"); } if (decoded.fiberFractions[2] < 0.0f) decoded.fiberFractions[2] = 0.0f; } connectome-workbench-1.4.2/src/Files/OxfordSparseThreeFile.h000066400000000000000000000042041360521144700240440ustar00rootroot00000000000000#ifndef __OXFORD_SPARSE_THREE_FILE_H__ #define __OXFORD_SPARSE_THREE_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretSparseFile.h" //for the Fibers struct namespace caret { class OxfordSparseThreeFile { static void decodeFibers(const uint64_t& coded, FiberFractions& decoded);//takes a uint because right shift on signed is implementation dependent FILE* m_valueFile;//we read the other two into memory, so we only need one handle int64_t m_dims[2]; std::vector m_indexArray, m_scratchRow; std::vector m_scratchArray, m_scratchSparseRow; OxfordSparseThreeFile(); OxfordSparseThreeFile(const OxfordSparseThreeFile& rhs); public: const int64_t* getDimensions() { return m_dims; } OxfordSparseThreeFile(const AString& dimFileName, const AString& indexFileName, const AString& valueFileName); void getRow(const int64_t& index, int64_t* rowOut); void getRowSparse(const int64_t& index, std::vector& indicesOut, std::vector& valuesOut); void getFibersRow(const int64_t& index, FiberFractions* rowOut); void getFibersRowSparse(const int64_t& index, std::vector& indicesOut, std::vector& valuesOut); ~OxfordSparseThreeFile(); }; } #endif //__OXFORD_SPARSE_THREE_FILE_H__ connectome-workbench-1.4.2/src/Files/PaletteFile.cxx000066400000000000000000002205551360521144700224170ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretLogger.h" #include "DataFileException.h" #include "GiftiLabel.h" #include "GiftiMetaData.h" #include "Palette.h" #include "PaletteColorMapping.h" #include "PaletteFile.h" #include "PaletteScalarAndColor.h" #include using namespace caret; /** * Constructor. * */ PaletteFile::PaletteFile() : CaretDataFile(DataFileTypeEnum::PALETTE) { this->metadata = new GiftiMetaData(); this->initializeMembersPaletteFile(); this->addDefaultPalettes(); this->clearModified(); } /** * Destructor */ PaletteFile::~PaletteFile() { this->clearAll(); delete this->metadata; } void PaletteFile::initializeMembersPaletteFile() { } /** * Get the label table used for color storage. * @return LabelTable used for color storage. * */ GiftiLabelTable* PaletteFile::getLabelTable() { return &this->labelTable; } /** * Clear everything. */ void PaletteFile::clearAll() { int64_t numberOfPalettes = this->palettes.size(); for (int64_t i = 0; i < numberOfPalettes; i++) { delete this->palettes[i]; } this->palettes.clear(); this->labelTable.clear(); this->metadata->clear(); } /** * Clear the file but add default palettes. */ void PaletteFile::clear() { this->clearAll(); this->addDefaultPalettes(); } /** * Add a palette color. * * @param pc - color to add. * */ void PaletteFile::addColor(const GiftiLabel& pc) { this->labelTable.addLabel(&pc); } /** * Add a palette color. * * @param name - name of color. * @param red - red component. * @param green - red component. * @param blue - red component. * */ void PaletteFile::addColor( const AString& name, const int32_t red, const int32_t green, const int32_t blue) { this->labelTable.addLabel(name, red, green, blue); } /** * Add a palette color. * * @param name - Name of color. * @param rgb - RGB components of color. * */ void PaletteFile::addColor( const AString& name, const int32_t rgb[]) { this->addColor(name, rgb[0], rgb[1], rgb[2]); } /** * Get a color via its index. * * @param index - index of color. * @return Reference to color at index or the default color * if the index is invalid. * */ const GiftiLabel* PaletteFile::getColor(const int32_t indx) const { return this->labelTable.getLabel(indx); } /** * Get a color via its index. * * @param colorName - Name of color. * @return Reference to color with name or the default color * if the name does not match any colors. * */ const GiftiLabel* PaletteFile::getColorByName(const AString& colorName) const { const GiftiLabel* gl = this->labelTable.getLabel(colorName); return gl; } /** * Get index for a color. * * @param colorName - Name of color. * @return Index to color or -1 if not found. * */ int32_t PaletteFile::getColorIndex(const AString& colorName) const { return this->labelTable.getLabelKeyFromName(colorName); } /** * Get the number of palettes. * * @return The number of palettes. * */ int32_t PaletteFile::getNumberOfPalettes() const { return this->palettes.size(); } /** * Add a palette. * * @param p - palette to add. * */ void PaletteFile::addPalette(const Palette& p) { Palette* pal = new Palette(p); this->assignColorsToPalette(*pal); this->palettes.push_back(pal); this->setModified(); } /** * Get a palette. * * @param index - index of palette. * @return Reference to palette or null if invalid index. * */ Palette* PaletteFile::getPalette(const int32_t indx) const { return this->palettes[indx]; } /** * Find a palette by the specified name. * * @param name Name of palette to search for. * @return Reference to palette with name or null if not found. * */ Palette* PaletteFile::getPaletteByName(const AString& name) const { int64_t numberOfPalettes = this->palettes.size(); for (int64_t i = 0; i < numberOfPalettes; i++) { if (this->palettes[i]->getName() == name) { return this->palettes[i]; } } return NULL; } /** * Remove a palette. * * @param index - index of palette to remove. * */ void PaletteFile::removePalette(const int32_t indx) { this->palettes.erase(this->palettes.begin() + indx); this->setModified(); } /** * Is this file empty? * * @return true if the file is empty, else false. * */ bool PaletteFile::isEmpty() const { return this->palettes.empty(); } /** * String description of this class. */ AString PaletteFile::toString() const { AString s; int64_t numberOfPalettes = this->palettes.size(); for (int64_t i = 0; i < numberOfPalettes; i++) { s += (this->palettes[i]->toString() + "\n"); } return s; } /** * Is this palette modified? * @return * true if modified, else false. */ bool PaletteFile::isModified() const { if (DataFile::isModified()) { return true; } if (this->labelTable.isModified()) { return true; } const int64_t numberOfPalettes = this->getNumberOfPalettes(); for (int i = 0; i < numberOfPalettes; i++) { if (this->palettes[i]->isModified()) { return true; } } return false; } /** * Set this object as not modified. Object should also * clear the modification status of its children. * */ void PaletteFile::clearModified() { DataFile::clearModified(); const int64_t numberOfPalettes = this->getNumberOfPalettes(); for (int i = 0; i < numberOfPalettes; i++) { this->palettes[i]->clearModified(); } this->labelTable.clearModified(); } /** * Assign colors to the palette. * @param * p Palette to which colors are assigned. */ void PaletteFile::assignColorsToPalette(Palette& p) { int64_t numberOfScalars = p.getNumberOfScalarsAndColors(); for (int64_t i = 0; i < numberOfScalars; i++) { PaletteScalarAndColor* psac = p.getScalarAndColor(i); const AString& colorName = psac->getColorName(); const GiftiLabel* gl = this->getColorByName(colorName); if (gl != NULL) { float rgba[4]; gl->getColor(rgba); psac->setColor(rgba); } else { CaretLogSevere(("Missing color \"" + colorName + "\" in palette \"" + p.getName() + "\"")); } } } /** * Read the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully read. */ void PaletteFile::readFile(const AString& filename) { clear(); // checkFileReadability(filename); throw DataFileException(filename, "Reading of PaletteFile not implemented."); } /** * Write the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully written. */ void PaletteFile::writeFile(const AString& filename) { // checkFileWritability(filename); throw DataFileException(filename, "Reading of PaletteFile not implemented."); } /** * Add the default palettes. * */ void PaletteFile::addDefaultPalettes() { bool modifiedStatus = this->isModified(); this->addColor("none", 0xff, 0xff, 0xff ); this->addColor("_yellow", 0xff, 0xff, 0x00 ); this->addColor("_black", 0x00, 0x00, 0x00 ); this->addColor("_orange", 0xff, 0x69, 0x00 ); if (this->getPaletteByName(Palette::ROY_BIG_BL_PALETTE_NAME) == NULL) { this->addColor("_RGB_255_255_0", 255, 255, 0 ); //#ffff00 this->addColor("_RGB_255_200_0", 255, 200, 0 ); //#ffc800 this->addColor("_RGB_255_120_0", 255, 120, 0 ); //#ff7800 this->addColor("_RGB_255_0_0", 255, 0, 0 ); //#ff0000 this->addColor("_RGB_200_0_0", 200, 0, 0 ); //#c80000 this->addColor("_RGB_150_0_0", 150, 0, 0 ); //#960000 this->addColor("_RGB_100_0_0", 100, 0, 0 ); //#640000 this->addColor("_RGB_60_0_0", 60, 0, 0 ); //#3c0000 this->addColor("_RGB_0_0_80", 0, 0, 80 ); //#000050 this->addColor("_RGB_0_0_170", 0, 0, 170 ); //#0000aa this->addColor("_RGB_75_0_125", 75, 0, 125 ); //#4b007d this->addColor("_RGB_125_0_160", 125, 0, 160 ); //#7d00a0 this->addColor("_RGB_75_125_0", 75, 125, 0 ); //#4b7d00 this->addColor("_RGB_0_200_0", 0, 200, 0 ); //#00c800 this->addColor("_RGB_0_255_0", 0, 255, 0 ); //#00ff00 this->addColor("_RGB_0_255_255", 0, 255, 255 ); //#00ffff Palette royBigBL; royBigBL.setName(Palette::ROY_BIG_BL_PALETTE_NAME); royBigBL.addScalarAndColor(1.00f, "_RGB_255_255_0"); royBigBL.addScalarAndColor(0.875f, "_RGB_255_200_0"); royBigBL.addScalarAndColor(0.750f, "_RGB_255_120_0"); royBigBL.addScalarAndColor(0.625f, "_RGB_255_0_0"); royBigBL.addScalarAndColor(0.500f, "_RGB_200_0_0"); royBigBL.addScalarAndColor(0.375f, "_RGB_150_0_0"); royBigBL.addScalarAndColor(0.250f, "_RGB_100_0_0"); royBigBL.addScalarAndColor(0.125f, "_RGB_60_0_0"); royBigBL.addScalarAndColor(0.000f, "_black"); royBigBL.addScalarAndColor(-0.125f, "_RGB_0_0_80"); royBigBL.addScalarAndColor(-0.250f, "_RGB_0_0_170"); royBigBL.addScalarAndColor(-0.375f, "_RGB_75_0_125"); royBigBL.addScalarAndColor(-0.500f, "_RGB_125_0_160"); royBigBL.addScalarAndColor(-0.625f, "_RGB_75_125_0"); royBigBL.addScalarAndColor(-0.750f, "_RGB_0_200_0"); royBigBL.addScalarAndColor(-0.875f, "_RGB_0_255_0"); royBigBL.addScalarAndColor(-0.990f, "_RGB_0_255_255"); royBigBL.addScalarAndColor(-1.00f, "_RGB_0_255_255"); addPalette(royBigBL); } //------------------------------------------------------------------------ // // Palette by David Van Essen // int oran_yell[3] = { 0xff, 0x99, 0x00 }; this->addColor("_oran-yell", oran_yell); int red[3] = { 0xff, 0x00, 0x00 }; this->addColor("_red", red); int cyan[3] = { 0x00, 0xff, 0xff }; this->addColor("_cyan", cyan); int green[3] = { 0x00, 0xff, 0x00 }; this->addColor("_green", green); int limegreen[3] = { 0x10, 0xb0, 0x10 }; this->addColor("_limegreen", limegreen); int violet[3] = { 0xe2, 0x51, 0xe2 }; this->addColor("_violet", violet); int hotpink[3] = { 0xff, 0x38, 0x8d }; this->addColor("_hotpink", hotpink); int white[3] = { 0xff, 0xff, 0xff }; this->addColor("_white", white); int gry_dd[3] = { 0xdd, 0xdd, 0xdd }; this->addColor("_gry-dd", gry_dd ); int gry_bb[3] = { 0xbb, 0xbb, 0xbb }; this->addColor("_gry-bb", gry_bb); int purple2[3] = { 0x66, 0x00, 0x33 }; this->addColor("_purple2", purple2); int blue_videen11[3] = { 0x33, 0x33, 0x4c }; this->addColor("_blue_videen11", blue_videen11); int blue_videen9[3] = { 0x4c, 0x4c, 0x7f }; this->addColor("_blue_videen9", blue_videen9); int blue_videen7[3] = { 0x7f, 0x7f, 0xcc }; this->addColor("_blue_videen7", blue_videen7); if (this->getPaletteByName("videen_style") == NULL) { Palette videenStyle; videenStyle.setName("videen_style"); videenStyle.addScalarAndColor(1.0f, "_red"); videenStyle.addScalarAndColor(0.9f, "_orange"); videenStyle.addScalarAndColor(0.8f, "_oran-yell"); videenStyle.addScalarAndColor(0.7f, "_yellow"); videenStyle.addScalarAndColor(0.6f, "_limegreen"); videenStyle.addScalarAndColor(0.5f, "_green"); videenStyle.addScalarAndColor(0.4f, "_blue_videen7"); videenStyle.addScalarAndColor(0.3f, "_blue_videen9"); videenStyle.addScalarAndColor(0.2f, "_blue_videen11"); videenStyle.addScalarAndColor(0.1f, "_purple2"); videenStyle.addScalarAndColor(0.0f, "_black"); videenStyle.addScalarAndColor(-0.1f, "_cyan"); videenStyle.addScalarAndColor(-0.2f, "_green"); videenStyle.addScalarAndColor(-0.3f, "_limegreen"); videenStyle.addScalarAndColor(-0.4f, "_violet"); videenStyle.addScalarAndColor(-0.5f, "_hotpink"); videenStyle.addScalarAndColor(-0.6f, "_white"); videenStyle.addScalarAndColor(-0.7f, "_gry-dd"); videenStyle.addScalarAndColor(-0.8f, "_gry-bb"); videenStyle.addScalarAndColor(-0.9f, "_black"); addPalette(videenStyle); } // // Create a palette with just white and black designed to be used // with the interpolate option // if (this->getPaletteByName(Palette::GRAY_INTERP_PALETTE_NAME) == NULL) { this->addColor("_white_gray_interp", 255, 255, 255 ); this->addColor("_black_gray_interp", 0, 0, 0 ); Palette palGrayPositiveInterp; palGrayPositiveInterp.setName(Palette::GRAY_INTERP_POSITIVE_PALETTE_NAME); palGrayPositiveInterp.addScalarAndColor( 1.0f, "_white_gray_interp"); palGrayPositiveInterp.addScalarAndColor(0.0f, "_black_gray_interp"); addPalette(palGrayPositiveInterp); Palette palGrayInterp; palGrayInterp.setName(Palette::GRAY_INTERP_PALETTE_NAME); palGrayInterp.addScalarAndColor( 1.0f, "_white_gray_interp"); palGrayInterp.addScalarAndColor(-1.0f, "_black_gray_interp"); addPalette(palGrayInterp); } //---------------------------------------------------------------------- // fixed Psych palette // if (this->getPaletteByName("PSYCH-FIXED") == NULL) { this->addColor("_pyell-oran", 0xff, 0xcc, 0x00 ); this->addColor("_poran-red", 0xff, 0x44, 0x00 ); this->addColor("_pred", 0xff, 0x00, 0x00 ); this->addColor("_pblue", 0x00, 0x44, 0xff ); this->addColor("_pltblue1", 0x00, 0x69, 0xff ); this->addColor("_pltblue2", 0x00, 0x99, 0xff ); this->addColor("_pbluecyan", 0x00, 0xcc, 0xff ); this->addColor("_pcyan", 0x00, 0xff, 0xff ); Palette psychFixed; psychFixed.setName("PSYCH-FIXED"); //psych.setPositiveOnly(false); psychFixed.addScalarAndColor(1.00f, "_yellow"); psychFixed.addScalarAndColor(0.75f, "_pyell-oran"); psychFixed.addScalarAndColor(0.50f, "_orange"); psychFixed.addScalarAndColor(0.25f, "_poran-red"); psychFixed.addScalarAndColor(0.00001f, "_pred");//0.00001f is a special range reserved by data normalization for zero values, see PaletteColorMapping.cxx:1590 psychFixed.addScalarAndColor(0.0000099f, "_black"); psychFixed.addScalarAndColor(-0.0000099f, "_black"); psychFixed.addScalarAndColor(-0.00001f, "_pblue"); psychFixed.addScalarAndColor(-0.25f, "_pltblue1"); psychFixed.addScalarAndColor(-0.50f, "_pltblue2"); psychFixed.addScalarAndColor(-0.75f, "_pbluecyan"); psychFixed.addScalarAndColor(-1.0f, "_pcyan"); addPalette(psychFixed); } //------------------------------------------------------------------------ // // Palette by Jon Wieser @ mcw // int rbgyr20_01[3] = { 0xCC, 0x10, 0x33 }; this->addColor("_rbgyr20_01", rbgyr20_01); int rbgyr20_02[3] = { 0x99, 0x20, 0x66 }; this->addColor("_rbgyr20_02", rbgyr20_02); int rbgyr20_03[3] = { 0x66, 0x31, 0x99 }; this->addColor("_rbgyr20_03", rbgyr20_03); int rbgyr20_04[3] = { 0x34, 0x41, 0xCC }; this->addColor("_rbgyr20_04", rbgyr20_04); int rbgyr20_05[3] = { 0x00, 0x51, 0xFF }; this->addColor("_rbgyr20_05", rbgyr20_05); int rbgyr20_06[3] = { 0x00, 0x74, 0xCC }; this->addColor("_rbgyr20_06", rbgyr20_06); int rbgyr20_07[3] = { 0x00, 0x97, 0x99 }; this->addColor("_rbgyr20_07", rbgyr20_07); int rbgyr20_08[3] = { 0x00, 0xB9, 0x66 }; this->addColor("_rbgyr20_08", rbgyr20_08); int rbgyr20_09[3] = { 0x00, 0xDC, 0x33 }; this->addColor("_rbgyr20_09", rbgyr20_09); int rbgyr20_10[3] = { 0x00, 0xFF, 0x00 }; this->addColor("_rbgyr20_10", rbgyr20_10); int rbgyr20_11[3] = { 0x33, 0xFF, 0x00 }; this->addColor("_rbgyr20_11", rbgyr20_11); int rbgyr20_12[3] = { 0x66, 0xFF, 0x00 }; this->addColor("_rbgyr20_12", rbgyr20_12); int rbgyr20_13[3] = { 0x99, 0xFF, 0x00 }; this->addColor("_rbgyr20_13", rbgyr20_13); int rbgyr20_14[3] = { 0xCC, 0xFF, 0x00 }; this->addColor("_rbgyr20_14", rbgyr20_14); int rbgyr20_15[3] = { 0xFF, 0xFF, 0x00 }; this->addColor("_rbgyr20_15", rbgyr20_15); int rbgyr20_16[3] = { 0xFF, 0xCC, 0x00 }; this->addColor("_rbgyr20_16", rbgyr20_16); int rbgyr20_17[3] = { 0xFF, 0x99, 0x00 }; this->addColor("_rbgyr20_17", rbgyr20_17); int rbgyr20_18[3] = { 0xFF, 0x66, 0x00 }; this->addColor("_rbgyr20_18", rbgyr20_18); int rbgyr20_19[3] = { 0xFF, 0x33, 0x00 }; this->addColor("_rbgyr20_19", rbgyr20_19); int rbgyr20_20[3] = { 0xFF, 0x00, 0x00 }; this->addColor("_rbgyr20_20", rbgyr20_20); if (this->getPaletteByName("RBGYR20") == NULL) { Palette pal2; pal2.setName("RBGYR20"); pal2.addScalarAndColor( 1.0f, "_rbgyr20_01"); pal2.addScalarAndColor( 0.9f, "_rbgyr20_02"); pal2.addScalarAndColor( 0.8f, "_rbgyr20_03"); pal2.addScalarAndColor( 0.7f, "_rbgyr20_04"); pal2.addScalarAndColor( 0.6f, "_rbgyr20_05"); pal2.addScalarAndColor( 0.5f, "_rbgyr20_06"); pal2.addScalarAndColor( 0.4f, "_rbgyr20_07"); pal2.addScalarAndColor( 0.3f, "_rbgyr20_08"); pal2.addScalarAndColor( 0.2f, "_rbgyr20_09"); pal2.addScalarAndColor( 0.1f, "_rbgyr20_10"); pal2.addScalarAndColor( 0.0f, "_rbgyr20_11"); pal2.addScalarAndColor(-0.1f, "_rbgyr20_12"); pal2.addScalarAndColor(-0.2f, "_rbgyr20_13"); pal2.addScalarAndColor(-0.3f, "_rbgyr20_14"); pal2.addScalarAndColor(-0.4f, "_rbgyr20_15"); pal2.addScalarAndColor(-0.5f, "_rbgyr20_16"); pal2.addScalarAndColor(-0.6f, "_rbgyr20_17"); pal2.addScalarAndColor(-0.7f, "_rbgyr20_18"); pal2.addScalarAndColor(-0.8f, "_rbgyr20_19"); pal2.addScalarAndColor(-0.9f, "_rbgyr20_20"); addPalette(pal2); Palette pal3; pal3.setName("RBGYR20P"); pal3.addScalarAndColor(1.00f, "_rbgyr20_01"); pal3.addScalarAndColor(0.95f, "_rbgyr20_02"); pal3.addScalarAndColor(0.90f, "_rbgyr20_03"); pal3.addScalarAndColor(0.85f, "_rbgyr20_04"); pal3.addScalarAndColor(0.80f, "_rbgyr20_05"); pal3.addScalarAndColor(0.75f, "_rbgyr20_06"); pal3.addScalarAndColor(0.70f, "_rbgyr20_07"); pal3.addScalarAndColor(0.65f, "_rbgyr20_08"); pal3.addScalarAndColor(0.60f, "_rbgyr20_09"); pal3.addScalarAndColor(0.55f, "_rbgyr20_10"); pal3.addScalarAndColor(0.50f, "_rbgyr20_11"); pal3.addScalarAndColor(0.45f, "_rbgyr20_12"); pal3.addScalarAndColor(0.40f, "_rbgyr20_13"); pal3.addScalarAndColor(0.35f, "_rbgyr20_14"); pal3.addScalarAndColor(0.30f, "_rbgyr20_15"); pal3.addScalarAndColor(0.25f, "_rbgyr20_16"); pal3.addScalarAndColor(0.20f, "_rbgyr20_17"); pal3.addScalarAndColor(0.15f, "_rbgyr20_18"); pal3.addScalarAndColor(0.10f, "_rbgyr20_19"); pal3.addScalarAndColor(0.05f, "_rbgyr20_20"); pal3.addScalarAndColor(0.0f, "none"); addPalette(pal3); } if (this->getPaletteByName("RYGBR4_positive") == NULL) { this->addColor("rygbr4_0", 255, 0, 0); this->addColor("rygbr4_1", 255, 255, 0); this->addColor("rygbr4_2", 0, 180, 0); this->addColor("rygbr4_3", 0, 0, 255); Palette rygbr4_pos; rygbr4_pos.setName("RYGBR4_positive"); rygbr4_pos.addScalarAndColor(1.0f, "rygbr4_0"); rygbr4_pos.addScalarAndColor(0.75f, "rygbr4_3"); rygbr4_pos.addScalarAndColor(0.5f, "rygbr4_2"); rygbr4_pos.addScalarAndColor(0.25f, "rygbr4_1"); rygbr4_pos.addScalarAndColor(0.0f, "rygbr4_0"); rygbr4_pos.addScalarAndColor(-1.0f, "rygbr4_0");//negatives red, I guess addPalette(rygbr4_pos); } if (this->getPaletteByName("RGRBR_mirror90_pos") == NULL) { this->addColor("rgrbr_m9_p_red", 220, 0, 0); this->addColor("rgrbr_m9_p_yellow", 255, 255, 0); this->addColor("rgrbr_m9_p_green", 0, 180, 0); this->addColor("rgrbr_m9_p_blue", 0, 0, 255); this->addColor("rgrbr_m9_p_purple", 255, 100, 255); Palette rgbgr_m9_p; rgbgr_m9_p.setName("RGRBR_mirror90_pos"); rgbgr_m9_p.addScalarAndColor(1.0f, "rgrbr_m9_p_red"); rgbgr_m9_p.addScalarAndColor(0.875f, "rgrbr_m9_p_purple"); rgbgr_m9_p.addScalarAndColor(0.75f, "rgrbr_m9_p_blue"); rgbgr_m9_p.addScalarAndColor(0.625f, "rgrbr_m9_p_purple"); rgbgr_m9_p.addScalarAndColor(0.5f, "rgrbr_m9_p_red"); rgbgr_m9_p.addScalarAndColor(0.375f, "rgrbr_m9_p_yellow"); rgbgr_m9_p.addScalarAndColor(0.25f, "rgrbr_m9_p_green"); rgbgr_m9_p.addScalarAndColor(0.125f, "rgrbr_m9_p_yellow"); rgbgr_m9_p.addScalarAndColor(0.0f, "rgrbr_m9_p_red"); rgbgr_m9_p.addScalarAndColor(-1.0f, "rgrbr_m9_p_red");//negatives red, I guess addPalette(rgbgr_m9_p); } //---------------------------------------------------------------------- // Orange-Yellow palette // if (this->getPaletteByName("Orange-Yellow") == NULL) { this->addColor("_oy1", 0, 0, 0 ); this->addColor("_oy2", 130, 2, 0 ); this->addColor("_oy3", 254, 130, 2 ); this->addColor("_oy4", 254, 254, 126 ); this->addColor("_oy5", 254, 254, 254 ); Palette orangeYellow; orangeYellow.setName("Orange-Yellow"); orangeYellow.addScalarAndColor( 1.0f, "_oy5"); orangeYellow.addScalarAndColor( 0.5f, "_oy4"); orangeYellow.addScalarAndColor( 0.0f, "_oy3"); orangeYellow.addScalarAndColor(-0.5f, "_oy2"); orangeYellow.addScalarAndColor(-1.0f, "_oy1"); addPalette(orangeYellow); } //---------------------------------------------------------------------- // Positive/Negative/Zero palette // if (this->getPaletteByName("POS_NEG_ZERO") == NULL) { this->addColor("pos_neg_blue", 0x00, 0x00, 0xff ); this->addColor("pos_neg_red", 0xff, 0x00, 0x00 ); Palette posNegZero; posNegZero.setName("POS_NEG_ZERO"); posNegZero.addScalarAndColor(1.0f, "pos_neg_red"); posNegZero.addScalarAndColor(0.00001f, "pos_neg_red"); posNegZero.addScalarAndColor(0.0000099f, "_black"); posNegZero.addScalarAndColor(-0.0000099f, "_black"); posNegZero.addScalarAndColor(-0.00001f, "pos_neg_blue"); posNegZero.addScalarAndColor(-1.0f, "pos_neg_blue"); addPalette(posNegZero); } if (this->getPaletteByName("red-yellow") == NULL) { this->addColor("_red_yellow_interp_red", 255, 0, 0 ); this->addColor("_red_yellow_interp_yellow", 255, 255, 0 ); this->addColor("_blue_lightblue_interp_blue", 0, 0, 255 ); this->addColor("_blue_lightblue_interp_lightblue", 0, 255, 255 ); this->addColor("_fslview_zero", 0, 0, 0); Palette palRedYellowInterp; palRedYellowInterp.setName("red-yellow"); palRedYellowInterp.addScalarAndColor(1.0f, "_red_yellow_interp_yellow"); palRedYellowInterp.addScalarAndColor(0.0f, "_red_yellow_interp_red"); addPalette(palRedYellowInterp); Palette palBlueLightblueInterp; palBlueLightblueInterp.setName("blue-lightblue"); palBlueLightblueInterp.addScalarAndColor(1.0f, "_blue_lightblue_interp_lightblue"); palBlueLightblueInterp.addScalarAndColor(0.0f, "_blue_lightblue_interp_blue"); addPalette(palBlueLightblueInterp); Palette palFSLView; palFSLView.setName("FSL"); palFSLView.addScalarAndColor( 1.0f, "_red_yellow_interp_yellow"); palFSLView.addScalarAndColor( 0.00001f, "_red_yellow_interp_red"); palFSLView.addScalarAndColor( 0.0000099f, "_fslview_zero"); palFSLView.addScalarAndColor(-0.0000099f, "_fslview_zero"); palFSLView.addScalarAndColor(-0.00001f, "_blue_lightblue_interp_blue"); palFSLView.addScalarAndColor(-1.0f, "_blue_lightblue_interp_lightblue"); addPalette(palFSLView); } if (this->getPaletteByName("power_surf") == NULL) { this->addColor("_ps_0", 1.0 *255.0, 0.0 * 255.0, 0.0 * 255.0 ); this->addColor("_ps_059", 0.0 * 255.0, 0.0 * 255.0, 0.6 * 255.0 ); this->addColor("_ps_118", 1.0 * 255.0, 1.0 * 255.0, 0.0 * 255.0 ); this->addColor("_ps_176", 1.0 * 255.0, 0.7 * 255.0, 0.4 * 255.0); this->addColor("_ps_235", 0.0 * 255.0, 0.8 * 255.0, 0.0 * 255.0 ); this->addColor("_ps_294", 1.0 * 255.0, 0.6 * 255.0, 1.0 * 255.0 ); this->addColor("_ps_353", 0.0 * 255.0, 0.6 * 255.0, 0.6 * 255.0 ); this->addColor("_ps_412", 0.0 * 255.0, 0.0 * 255.0, 0.0 * 255.0 ); this->addColor("_ps_471", 0.3 * 255.0, 0.0 * 255.0, 0.6 * 255.0 ); this->addColor("_ps_529", 0.2 * 255.0, 1.0 * 255.0, 1.0 * 255.0 ); this->addColor("_ps_588", 1.0 * 255.0, 0.5 * 255.0, 0.0 * 255.0 ); this->addColor("_ps_647", 0.6 * 255.0, 0.2 * 255.0, 1.0 * 255.0 ); this->addColor("_ps_706", 0.0 * 255.0, 0.2 * 255.0, 0.4 * 255.0 ); this->addColor("_ps_765", 0.2 * 255.0, 1.0 * 255.0, 0.2 * 255.0 ); this->addColor("_ps_824", 0.0 * 255.0, 0.0 * 255.0, 1.0 * 255.0 ); this->addColor("_ps_882", 1.0 * 255.0, 1.0 * 255.0, 0.8 * 255.0 ); this->addColor("_ps_941", 0.0 * 255.0, 0.4 * 255.0, 0.0 * 255.0 ); this->addColor("_ps_1000", 0.25 * 255.0, 0.25 * 255.0, 0.25 * 255.0 ); Palette powerSurf; powerSurf.setName("power_surf"); powerSurf.addScalarAndColor( 1.0, "_ps_1000"); powerSurf.addScalarAndColor( 0.941, "_ps_941"); powerSurf.addScalarAndColor( 0.882, "_ps_882"); powerSurf.addScalarAndColor( 0.824, "_ps_824"); powerSurf.addScalarAndColor( 0.765, "_ps_765"); powerSurf.addScalarAndColor( 0.706, "_ps_706"); powerSurf.addScalarAndColor( 0.647, "_ps_647"); powerSurf.addScalarAndColor( 0.588, "_ps_588"); powerSurf.addScalarAndColor( 0.529, "_ps_529"); powerSurf.addScalarAndColor( 0.471, "_ps_471"); powerSurf.addScalarAndColor( 0.412, "_ps_412"); powerSurf.addScalarAndColor( 0.353, "_ps_353"); powerSurf.addScalarAndColor( 0.294, "_ps_294"); powerSurf.addScalarAndColor( 0.235, "_ps_235"); powerSurf.addScalarAndColor( 0.176, "_ps_176"); powerSurf.addScalarAndColor( 0.118, "_ps_118"); powerSurf.addScalarAndColor( 0.059, "_ps_059"); powerSurf.addScalarAndColor( 0.0, "_ps_0"); addPalette(powerSurf); } /* * FSL Red palette from WB-289 * * float offset = 100.0; * float step = (255.0 - offset) / 255.0; * for(unsigned char i = 0; i < 255; ++i) * { int red = int(((i + 1) * step) + offset); lut->pushValue(red, 0, 0, i); } * * lut->m_lutName = std::string("Red"); */ //TSC: no "lookup tables" for purely interpolated palettes! bad for performance. if (this->getPaletteByName("fsl_red") == NULL) { Palette fslRed; fslRed.setName("fsl_red"); this->addColor("fsl_red_0", 100, 0, 0); this->addColor("fsl_red_1", 255, 0, 0); fslRed.addScalarAndColor(1.0f, "fsl_red_1"); fslRed.addScalarAndColor(0.0f, "fsl_red_0"); addPalette(fslRed); } if (this->getPaletteByName("fsl_green") == NULL) { Palette fslGreen; fslGreen.setName("fsl_green"); this->addColor("fsl_green_0", 0, 100, 0); this->addColor("fsl_green_1", 0, 255, 0); fslGreen.addScalarAndColor(1.0f, "fsl_green_1"); fslGreen.addScalarAndColor(0.0f, "fsl_green_0"); addPalette(fslGreen); } if (this->getPaletteByName("fsl_blue") == NULL) { Palette fslBlue; fslBlue.setName("fsl_blue"); this->addColor("fsl_blue_0", 0, 0, 100); this->addColor("fsl_blue_1", 0, 0, 255); fslBlue.addScalarAndColor(1.0f, "fsl_blue_1"); fslBlue.addScalarAndColor(0.0f, "fsl_blue_0"); addPalette(fslBlue); } if (this->getPaletteByName("fsl_yellow") == NULL) { Palette fslYellow; fslYellow.setName("fsl_yellow"); this->addColor("fsl_yellow_0", 100, 100, 0); this->addColor("fsl_yellow_1", 255, 255, 0); fslYellow.addScalarAndColor(1.0f, "fsl_yellow_1"); fslYellow.addScalarAndColor(0.0f, "fsl_yellow_0"); addPalette(fslYellow); } // // Create a palette with red (positive), white (zero), // and blue (negative) for Alan A. // if (this->getPaletteByName("RedWhiteBlue") == NULL) { Palette redWhiteBlue; redWhiteBlue.setName("RedWhiteBlue"); this->addColor("rwbBlue", 0, 0, 255); this->addColor("rwbBlueMiddle", 127, 127, 255); this->addColor("rwbWhite", 255, 255, 255); this->addColor("rwbRedMiddle", 255, 127, 127); this->addColor("rwbRed", 255, 0, 0); redWhiteBlue.addScalarAndColor( 1.0f, "rwbRed"); redWhiteBlue.addScalarAndColor( 0.5f, "rwbRedMiddle"); redWhiteBlue.addScalarAndColor( 0.0f, "rwbWhite"); redWhiteBlue.addScalarAndColor(-0.5f, "rwbBlueMiddle"); redWhiteBlue.addScalarAndColor(-1.0f, "rwbBlue"); addPalette(redWhiteBlue); } //coolwarm, http://www.kennethmoreland.com/color-maps/ //"Diverging Color Maps for Scientific Visualization." Kenneth Moreland. In Proceedings of the 5th International Symposium on Visual Computing, December 2009. DOI 10.1007/978-3-642-10520-3_9. //this palette was interpolated in CIELAB space, and then translated to sRGB, so we need to keep a substantial number of points //use the 33 csv file if (this->getPaletteByName("cool-warm") == NULL) { Palette coolwarm; coolwarm.setName("cool-warm"); this->addColor("cool-warm-0", 59,76,192); this->addColor("cool-warm-1", 68,90,204); this->addColor("cool-warm-2", 77,104,215); this->addColor("cool-warm-3", 87,117,225); this->addColor("cool-warm-4", 98,130,234); this->addColor("cool-warm-5", 108,142,241); this->addColor("cool-warm-6", 119,154,247); this->addColor("cool-warm-7", 130,165,251); this->addColor("cool-warm-8", 141,176,254); this->addColor("cool-warm-9", 152,185,255); this->addColor("cool-warm-10", 163,194,255); this->addColor("cool-warm-11", 174,201,253); this->addColor("cool-warm-12", 184,208,249); this->addColor("cool-warm-13", 194,213,244); this->addColor("cool-warm-14", 204,217,238); this->addColor("cool-warm-15", 213,219,230); this->addColor("cool-warm-16", 221,221,221); this->addColor("cool-warm-17", 229,216,209); this->addColor("cool-warm-18", 236,211,197); this->addColor("cool-warm-19", 241,204,185); this->addColor("cool-warm-20", 245,196,173); this->addColor("cool-warm-21", 247,187,160); this->addColor("cool-warm-22", 247,177,148); this->addColor("cool-warm-23", 247,166,135); this->addColor("cool-warm-24", 244,154,123); this->addColor("cool-warm-25", 241,141,111); this->addColor("cool-warm-26", 236,127,99); this->addColor("cool-warm-27", 229,112,88); this->addColor("cool-warm-28", 222,96,77); this->addColor("cool-warm-29", 213,80,66); this->addColor("cool-warm-30", 203,62,56); this->addColor("cool-warm-31", 192,40,47); this->addColor("cool-warm-32", 180,4,38); coolwarm.addScalarAndColor(16.0f / 16.0f, "cool-warm-32"); coolwarm.addScalarAndColor(15.0f / 16.0f, "cool-warm-31"); coolwarm.addScalarAndColor(14.0f / 16.0f, "cool-warm-30"); coolwarm.addScalarAndColor(13.0f / 16.0f, "cool-warm-29"); coolwarm.addScalarAndColor(12.0f / 16.0f, "cool-warm-28"); coolwarm.addScalarAndColor(11.0f / 16.0f, "cool-warm-27"); coolwarm.addScalarAndColor(10.0f / 16.0f, "cool-warm-26"); coolwarm.addScalarAndColor(9.0f / 16.0f, "cool-warm-25"); coolwarm.addScalarAndColor(8.0f / 16.0f, "cool-warm-24"); coolwarm.addScalarAndColor(7.0f / 16.0f, "cool-warm-23"); coolwarm.addScalarAndColor(6.0f / 16.0f, "cool-warm-22"); coolwarm.addScalarAndColor(5.0f / 16.0f, "cool-warm-21"); coolwarm.addScalarAndColor(4.0f / 16.0f, "cool-warm-20"); coolwarm.addScalarAndColor(3.0f / 16.0f, "cool-warm-19"); coolwarm.addScalarAndColor(2.0f / 16.0f, "cool-warm-18"); coolwarm.addScalarAndColor(1.0f / 16.0f, "cool-warm-17"); coolwarm.addScalarAndColor(0.0f / 16.0f, "cool-warm-16"); coolwarm.addScalarAndColor(-1.0f / 16.0f, "cool-warm-15"); coolwarm.addScalarAndColor(-2.0f / 16.0f, "cool-warm-14"); coolwarm.addScalarAndColor(-3.0f / 16.0f, "cool-warm-13"); coolwarm.addScalarAndColor(-4.0f / 16.0f, "cool-warm-12"); coolwarm.addScalarAndColor(-5.0f / 16.0f, "cool-warm-11"); coolwarm.addScalarAndColor(-6.0f / 16.0f, "cool-warm-10"); coolwarm.addScalarAndColor(-7.0f / 16.0f, "cool-warm-9"); coolwarm.addScalarAndColor(-8.0f / 16.0f, "cool-warm-8"); coolwarm.addScalarAndColor(-9.0f / 16.0f, "cool-warm-7"); coolwarm.addScalarAndColor(-10.0f / 16.0f, "cool-warm-6"); coolwarm.addScalarAndColor(-11.0f / 16.0f, "cool-warm-5"); coolwarm.addScalarAndColor(-12.0f / 16.0f, "cool-warm-4"); coolwarm.addScalarAndColor(-13.0f / 16.0f, "cool-warm-3"); coolwarm.addScalarAndColor(-14.0f / 16.0f, "cool-warm-2"); coolwarm.addScalarAndColor(-15.0f / 16.0f, "cool-warm-1"); coolwarm.addScalarAndColor(-16.0f / 16.0f, "cool-warm-0"); addPalette(coolwarm); } //matplotlib's spectral is from colorbrewer //Colors from www.ColorBrewer.org by Cynthia A. Brewer, Geography, Pennsylvania State University. //Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and The Pennsylvania State University. if (this->getPaletteByName("spectral") == NULL) { Palette spectral; spectral.setName("spectral"); this->addColor("spectral-0", 158,1,66); this->addColor("spectral-1", 213,62,79); this->addColor("spectral-2", 244,109,67); this->addColor("spectral-3", 253,174,97); this->addColor("spectral-4", 254,224,139); this->addColor("spectral-5", 255,255,191); this->addColor("spectral-6", 230,245,152); this->addColor("spectral-7", 171,221,164); this->addColor("spectral-8", 102,194,165); this->addColor("spectral-9", 50,136,189); this->addColor("spectral-10", 94,79,162); spectral.addScalarAndColor(5.0f / 5.0f, "spectral-0"); spectral.addScalarAndColor(4.0f / 5.0f, "spectral-1"); spectral.addScalarAndColor(3.0f / 5.0f, "spectral-2"); spectral.addScalarAndColor(2.0f / 5.0f, "spectral-3"); spectral.addScalarAndColor(1.0f / 5.0f, "spectral-4"); spectral.addScalarAndColor(0.0f / 5.0f, "spectral-5"); spectral.addScalarAndColor(-1.0f / 5.0f, "spectral-6"); spectral.addScalarAndColor(-2.0f / 5.0f, "spectral-7"); spectral.addScalarAndColor(-3.0f / 5.0f, "spectral-8"); spectral.addScalarAndColor(-4.0f / 5.0f, "spectral-9"); spectral.addScalarAndColor(-5.0f / 5.0f, "spectral-10"); addPalette(spectral); } //palette from Alan Anticevic if (this->getPaletteByName("RY-BC-BL") == NULL) { Palette RY_BC_BL; RY_BC_BL.setName("RY-BC-BL");//named like "ROY-BIG-BL" this->addColor("rybcbl-y", 255, 255, 0); this->addColor("rybcbl-r", 255, 0, 0); this->addColor("rybcbl-bl", 0, 0, 0); this->addColor("rybcbl-b", 0, 0, 255); this->addColor("rybcbl-c", 0, 255, 255); RY_BC_BL.addScalarAndColor(1.0f, "rybcbl-y"); RY_BC_BL.addScalarAndColor(0.5f, "rybcbl-r"); RY_BC_BL.addScalarAndColor(0.0f, "rybcbl-bl"); RY_BC_BL.addScalarAndColor(-0.5f, "rybcbl-b"); RY_BC_BL.addScalarAndColor(-1.0f, "rybcbl-c"); addPalette(RY_BC_BL); } //matplotlib's magma, approximated by reducing their massive 256-entry lookup table to 32 entries //Copyright (c) 2012-2015 Matplotlib Development Team; All Rights Reserved //see https://github.com/matplotlib/matplotlib/blob/master/LICENSE/LICENSE or debian/copyright for the matplotlib license, "All Rights Reserved" is required language by the license, but it is actually open source if (this->getPaletteByName("magma") == NULL) { Palette magma; magma.setName("magma"); this->addColor("magma-black", 0, 0, 0);//negative and zero this->addColor("magma-1", 3, 3, 15); this->addColor("magma-2", 9, 7, 32); this->addColor("magma-3", 18, 13, 49); this->addColor("magma-4", 28, 16, 68); this->addColor("magma-5", 39, 18, 88); this->addColor("magma-6", 52, 16, 105); this->addColor("magma-7", 66, 15, 117); this->addColor("magma-8", 79, 18, 123); this->addColor("magma-9", 92, 22, 127); this->addColor("magma-10", 104, 28, 129); this->addColor("magma-11", 117, 33, 129); this->addColor("magma-12", 129, 37, 129); this->addColor("magma-13", 142, 42, 129); this->addColor("magma-14", 155, 46, 127); this->addColor("magma-15", 168, 50, 125); this->addColor("magma-16", 181, 54, 122); this->addColor("magma-17", 194, 59, 117); this->addColor("magma-18", 207, 64, 112); this->addColor("magma-19", 219, 71, 106); this->addColor("magma-20", 229, 80, 100); this->addColor("magma-21", 238, 91, 94); this->addColor("magma-22", 244, 105, 92); this->addColor("magma-23", 249, 120, 93); this->addColor("magma-24", 251, 135, 97); this->addColor("magma-25", 253, 150, 104); this->addColor("magma-26", 254, 165, 113); this->addColor("magma-27", 254, 180, 123); this->addColor("magma-28", 254, 194, 135); this->addColor("magma-29", 254, 209, 148); this->addColor("magma-30", 253, 224, 161); this->addColor("magma-31", 252, 238, 176); this->addColor("magma-32", 252, 253, 191); magma.addScalarAndColor(32.0f / 32.0f, "magma-32"); magma.addScalarAndColor(31.0f / 32.0f, "magma-31"); magma.addScalarAndColor(30.0f / 32.0f, "magma-30"); magma.addScalarAndColor(29.0f / 32.0f, "magma-29"); magma.addScalarAndColor(28.0f / 32.0f, "magma-28"); magma.addScalarAndColor(27.0f / 32.0f, "magma-27"); magma.addScalarAndColor(26.0f / 32.0f, "magma-26"); magma.addScalarAndColor(25.0f / 32.0f, "magma-25"); magma.addScalarAndColor(24.0f / 32.0f, "magma-24"); magma.addScalarAndColor(23.0f / 32.0f, "magma-23"); magma.addScalarAndColor(22.0f / 32.0f, "magma-22"); magma.addScalarAndColor(21.0f / 32.0f, "magma-21"); magma.addScalarAndColor(20.0f / 32.0f, "magma-20"); magma.addScalarAndColor(19.0f / 32.0f, "magma-19"); magma.addScalarAndColor(18.0f / 32.0f, "magma-18"); magma.addScalarAndColor(17.0f / 32.0f, "magma-17"); magma.addScalarAndColor(16.0f / 32.0f, "magma-16"); magma.addScalarAndColor(15.0f / 32.0f, "magma-15"); magma.addScalarAndColor(14.0f / 32.0f, "magma-14"); magma.addScalarAndColor(13.0f / 32.0f, "magma-13"); magma.addScalarAndColor(12.0f / 32.0f, "magma-12"); magma.addScalarAndColor(11.0f / 32.0f, "magma-11"); magma.addScalarAndColor(10.0f / 32.0f, "magma-10"); magma.addScalarAndColor(9.0f / 32.0f, "magma-9"); magma.addScalarAndColor(8.0f / 32.0f, "magma-8"); magma.addScalarAndColor(7.0f / 32.0f, "magma-7"); magma.addScalarAndColor(6.0f / 32.0f, "magma-6"); magma.addScalarAndColor(5.0f / 32.0f, "magma-5"); magma.addScalarAndColor(4.0f / 32.0f, "magma-4"); magma.addScalarAndColor(3.0f / 32.0f, "magma-3"); magma.addScalarAndColor(2.0f / 32.0f, "magma-2"); magma.addScalarAndColor(1.0f / 32.0f, "magma-1"); magma.addScalarAndColor(0.0f, "magma-black");//technically magma doesn't quite reach black at the minimum end (0 0 4), or ~(0 0 2) if extended by one, as it is a 256 element lookup, but it is close enough magma.addScalarAndColor(-1.0f, "magma-black"); addPalette(magma); } if (this->getPaletteByName("JET256") == NULL) { Palette JET256; JET256.setName("JET256"); //summary of original slow "lookup table" (if closer to previous implementation is desired): //start: 0 -> (0 0 132) //change: 0.121 -> (0 0 255) //change: 0.372 -> (0 255 255) //change: 0.623 -> (255 255 0) //change: 0.874 -> (255 0 0) //end: 1 -> (127 0 0) //alternative round-valued version via https://gist.github.com/bagrow/805122 /*(0 0.0 0.0 0.5, \ 1 0.0 0.0 1.0, \ 2 0.0 0.5 1.0, \ <- redundant 3 0.0 1.0 1.0, \ 4 0.5 1.0 0.5, \ <- redundant 5 1.0 1.0 0.0, \ 6 1.0 0.5 0.0, \ <- redundant 7 1.0 0.0 0.0, \ 8 0.5 0.0 0.0 )*/ this->addColor("_J0", 0, 0, 127);//rounding to probably-intended colors this->addColor("_J1", 0, 0, 255); this->addColor("_J3", 0, 255, 255);//skipping redundant points this->addColor("_J5", 255, 255, 0); this->addColor("_J7", 255, 0, 0); this->addColor("_J8", 127, 0, 0); JET256.addScalarAndColor(1.0f, "_J8"); JET256.addScalarAndColor(0.875f, "_J7");//also rounding to probably-intended control points JET256.addScalarAndColor(0.625f, "_J5"); JET256.addScalarAndColor(0.375f, "_J3"); JET256.addScalarAndColor(0.125f, "_J1"); JET256.addScalarAndColor(0.0f, "_J0"); addPalette(JET256); } //TSC: palettes that use "none" or are broken (psych no none) start here - exception: rbgyr20p, to keep it close to rbgyr20 //---------------------------------------------------------------------- // Psych palette // if (this->getPaletteByName("PSYCH") == NULL) { this->addColor("_pyell-oran", 0xff, 0xcc, 0x00 ); this->addColor("_poran-red", 0xff, 0x44, 0x00 ); this->addColor("_pblue", 0x00, 0x44, 0xff ); this->addColor("_pltblue1", 0x00, 0x69, 0xff ); this->addColor("_pltblue2", 0x00, 0x99, 0xff ); this->addColor("_pbluecyan", 0x00, 0xcc, 0xff ); Palette psych; psych.setName("PSYCH"); //psych.setPositiveOnly(false); psych.addScalarAndColor(1.00f, "_yellow"); psych.addScalarAndColor(0.75f, "_pyell-oran"); psych.addScalarAndColor(0.50f, "_orange"); psych.addScalarAndColor(0.25f, "_poran-red"); psych.addScalarAndColor(0.05f, "none"); psych.addScalarAndColor(-0.05f, "_pblue"); psych.addScalarAndColor(-0.25f, "_pltblue1"); psych.addScalarAndColor(-0.50f, "_pltblue2"); psych.addScalarAndColor(-0.75f, "_pbluecyan"); addPalette(psych); } //---------------------------------------------------------------------- // Psych no-none palette // if (this->getPaletteByName("PSYCH-NO-NONE") == NULL) { this->addColor("_pyell-oran", 0xff, 0xcc, 0x00 ); this->addColor("_poran-red", 0xff, 0x44, 0x00 ); this->addColor("_pblue", 0x00, 0x44, 0xff ); this->addColor("_pltblue1", 0x00, 0x69, 0xff ); this->addColor("_pltblue2", 0x00, 0x99, 0xff ); this->addColor("_pbluecyan", 0x00, 0xcc, 0xff ); Palette psychNoNone; psychNoNone.setName("PSYCH-NO-NONE"); //psychNoNone.setPositiveOnly(false); psychNoNone.addScalarAndColor(1.00f, "_yellow"); psychNoNone.addScalarAndColor(0.75f, "_pyell-oran"); psychNoNone.addScalarAndColor(0.50f, "_orange"); psychNoNone.addScalarAndColor(0.25f, "_poran-red"); psychNoNone.addScalarAndColor(0.0f, "_pblue"); psychNoNone.addScalarAndColor(-0.25f, "_pltblue1"); psychNoNone.addScalarAndColor(-0.50f, "_pltblue2"); psychNoNone.addScalarAndColor(-0.75f, "_pbluecyan"); addPalette(psychNoNone); } //---------------------------------------------------------------------- // ROY-BIG palette // if (this->getPaletteByName("ROY-BIG") == NULL) { Palette royBig; royBig.setName("ROY-BIG"); royBig.addScalarAndColor(1.00f, "_RGB_255_255_0"); royBig.addScalarAndColor(0.875f, "_RGB_255_200_0"); royBig.addScalarAndColor(0.750f, "_RGB_255_120_0"); royBig.addScalarAndColor(0.625f, "_RGB_255_0_0"); royBig.addScalarAndColor(0.500f, "_RGB_200_0_0"); royBig.addScalarAndColor(0.375f, "_RGB_150_0_0"); royBig.addScalarAndColor(0.250f, "_RGB_100_0_0"); royBig.addScalarAndColor(0.125f, "_RGB_60_0_0"); royBig.addScalarAndColor(0.000f, "none"); royBig.addScalarAndColor(-0.125f, "_RGB_0_0_80"); royBig.addScalarAndColor(-0.250f, "_RGB_0_0_170"); royBig.addScalarAndColor(-0.375f, "_RGB_75_0_125"); royBig.addScalarAndColor(-0.500f, "_RGB_125_0_160"); royBig.addScalarAndColor(-0.625f, "_RGB_75_125_0"); royBig.addScalarAndColor(-0.750f, "_RGB_0_200_0"); royBig.addScalarAndColor(-0.875f, "_RGB_0_255_0"); royBig.addScalarAndColor(-0.990f, "_RGB_0_255_255"); royBig.addScalarAndColor(-1.00f, "_RGB_0_255_255"); addPalette(royBig); } if (this->getPaletteByName("clear_brain") == NULL) { Palette clearBrain; clearBrain.setName("clear_brain"); clearBrain.addScalarAndColor(1.0f , "_red"); clearBrain.addScalarAndColor(0.9f , "_orange"); clearBrain.addScalarAndColor(0.8f , "_oran-yell"); clearBrain.addScalarAndColor(0.7f , "_yellow"); clearBrain.addScalarAndColor(0.6f , "_limegreen"); clearBrain.addScalarAndColor(0.5f , "_green"); clearBrain.addScalarAndColor(0.4f , "_blue_videen7"); clearBrain.addScalarAndColor(0.3f , "_blue_videen9"); clearBrain.addScalarAndColor(0.2f , "_blue_videen11"); clearBrain.addScalarAndColor(0.1f , "_purple2"); clearBrain.addScalarAndColor(0.0f , "none"); clearBrain.addScalarAndColor(-0.1f , "_cyan"); clearBrain.addScalarAndColor(-0.2f , "_green"); clearBrain.addScalarAndColor(-0.3f , "_limegreen"); clearBrain.addScalarAndColor(-0.4f , "_violet"); clearBrain.addScalarAndColor(-0.5f , "_hotpink"); clearBrain.addScalarAndColor(-0.6f , "_white"); clearBrain.addScalarAndColor(-0.7f , "_gry-dd"); clearBrain.addScalarAndColor(-0.8f , "_gry-bb"); clearBrain.addScalarAndColor(-0.9f , "_black"); addPalette(clearBrain); } if (this->getPaletteByName("fidl") == NULL) { int Bright_Yellow[3] = { 0xee, 0xee, 0x55 }; this->addColor("_Bright_Yellow", Bright_Yellow); int Mustard[3] = { 0xdd, 0xdd, 0x66 }; this->addColor("_Mustard", Mustard); int Brown_Mustard[3] = { 0xdd, 0x99, 0x00 }; this->addColor("_Brown_Mustard", Brown_Mustard); int Bright_Red[3] = { 0xff, 0x00, 0x00 }; this->addColor("_Bright_Red", Bright_Red); int Fire_Engine_Red[3] = { 0xdd, 0x00, 0x00 }; this->addColor("_Fire_Engine_Red", Fire_Engine_Red); int Brick[3] = { 0xbb, 0x00, 0x00 }; this->addColor("_Brick", Brick); int Beet[3] = { 0x99, 0x00, 0x00 }; this->addColor("_Beet", Beet); int Beaujolais[3] = { 0x77, 0x00, 0x00 }; this->addColor("_Beaujolais", Beaujolais); int Burgundy[3] = { 0x55, 0x00, 0x00 }; this->addColor("_Burgundy", Burgundy); int Thrombin[3] = { 0x11, 0x00, 0x00 }; this->addColor("_Thrombin", Thrombin); int Deep_Green[3] = { 0x00, 0x11, 0x00 }; this->addColor("_Deep_Green", Deep_Green); int British_Racing_Green[3] = { 0x00, 0x55, 0x00 }; this->addColor("_British_Racing_Green", British_Racing_Green); int Kelp[3] = { 0x00, 0x77, 0x00 }; this->addColor("_Kelp", Kelp); int Lime[3] = { 0x00, 0x99, 0x00 }; this->addColor("_Lime", Lime); int Mint[3] = { 0x00, 0xbb, 0x00 }; this->addColor("_Mint", Mint); int Brussell_Sprout[3] = { 0x00, 0xdd, 0x00 }; this->addColor("_Brussell_Sprout", Brussell_Sprout); int Bright_Green[3] = { 0x00, 0xff, 0x00 }; this->addColor("_Bright_Green", Bright_Green); int Periwinkle[3] = { 0x66, 0x66, 0xbb }; this->addColor("_Periwinkle", Periwinkle); int Azure[3] = { 0x88, 0x88, 0xee }; this->addColor("_Azure", Azure); int Turquoise[3] = { 0x00, 0xcc, 0xcc }; this->addColor("_Turquoise", Turquoise); Palette fidl; fidl.setName("fidl"); fidl.addScalarAndColor(1.0f, "_Bright_Yellow"); fidl.addScalarAndColor(0.9f, "_Mustard"); fidl.addScalarAndColor(0.8f, "_Brown_Mustard"); fidl.addScalarAndColor(0.7f, "_Bright_Red"); fidl.addScalarAndColor(0.6f, "_Fire_Engine_Red"); fidl.addScalarAndColor(0.5f, "_Brick"); fidl.addScalarAndColor(0.4f, "_Beet"); fidl.addScalarAndColor(0.3f, "_Beaujolais"); fidl.addScalarAndColor(0.2f, "_Burgundy"); fidl.addScalarAndColor(0.1f, "_Thrombin"); fidl.addScalarAndColor(0.0f, "none"); fidl.addScalarAndColor(-0.1f, "_Deep_Green"); fidl.addScalarAndColor(-0.2f, "_British_Racing_Green"); fidl.addScalarAndColor(-0.3f, "_Kelp"); fidl.addScalarAndColor(-0.4f, "_Lime"); fidl.addScalarAndColor(-0.5f, "_Mint"); fidl.addScalarAndColor(-0.6f, "_Brussell_Sprout"); fidl.addScalarAndColor(-0.7f, "_Bright_Green"); fidl.addScalarAndColor(-0.8f, "_Periwinkle"); fidl.addScalarAndColor(-0.9f, "_Azure"); fidl.addScalarAndColor(-1.0f, "_Turquoise"); addPalette(fidl); } //------------------------------------------------------------------------ // // Colors by Russ H. // int _rbgyr20_10[3] = { 0x00, 0xff, 0x00 }; this->addColor("_rbgyr20_10", _rbgyr20_10); int _rbgyr20_15[3] = { 0xff, 0xff, 0x00 }; this->addColor("_rbgyr20_15", _rbgyr20_15); int _rbgyr20_20[3] = { 0xff, 0x00, 0x00 }; this->addColor("_rbgyr20_20", _rbgyr20_20); int _rbgyr20_21[3] = { 0x9d, 0x22, 0xc1 }; this->addColor("_rbgyr20_21", _rbgyr20_21); int _rbgyr20_22[3] = { 0x81, 0x06, 0xa5 }; this->addColor("_rbgyr20_22", _rbgyr20_22); int _rbgyr20_23[3] = { 0xff, 0xec, 0x00 }; this->addColor("_rbgyr20_23", _rbgyr20_23); int _rbgyr20_24[3] = { 0xff, 0xd6, 0x00 }; this->addColor("_rbgyr20_24", _rbgyr20_24); int _rbgyr20_25[3] = { 0xff, 0xbc, 0x00 }; this->addColor("_rbgyr20_25", _rbgyr20_25); int _rbgyr20_26[3] = { 0xff, 0x9c, 0x00 }; this->addColor("_rbgyr20_26", _rbgyr20_26); int _rbgyr20_27[3] = { 0xff, 0x7c, 0x00 }; this->addColor("_rbgyr20_27", _rbgyr20_27); int _rbgyr20_28[3] = { 0xff, 0x5c, 0x00 }; this->addColor("_rbgyr20_28", _rbgyr20_28); int _rbgyr20_29[3] = { 0xff, 0x3d, 0x00 }; this->addColor("_rbgyr20_29", _rbgyr20_29); int _rbgyr20_30[3] = { 0xff, 0x23, 0x00 }; this->addColor("_rbgyr20_30", _rbgyr20_30); int _rbgyr20_31[3] = { 0x00, 0xed, 0x12 }; this->addColor("_rbgyr20_31", _rbgyr20_31); int _rbgyr20_32[3] = { 0x00, 0xd5, 0x2a }; this->addColor("_rbgyr20_32", _rbgyr20_32); int _rbgyr20_33[3] = { 0x00, 0xb9, 0x46 }; this->addColor("_rbgyr20_33", _rbgyr20_33); int _rbgyr20_34[3] = { 0x00, 0x9b, 0x64 }; this->addColor("_rbgyr20_34", _rbgyr20_34); int _rbgyr20_35[3] = { 0x00, 0x7b, 0x84 }; this->addColor("_rbgyr20_35", _rbgyr20_35); int _rbgyr20_36[3] = { 0x00, 0x5b, 0xa4 }; this->addColor("_rbgyr20_36", _rbgyr20_36); int _rbgyr20_37[3] = { 0x00, 0x44, 0xbb }; this->addColor("_rbgyr20_37", _rbgyr20_37); int _rbgyr20_38[3] = { 0x00, 0x24, 0xdb }; this->addColor("_rbgyr20_38", _rbgyr20_38); int _rbgyr20_39[3] = { 0x00, 0x00, 0xff }; this->addColor("_rbgyr20_39", _rbgyr20_39); int _rbgyr20_40[3] = { 0xff, 0xf1, 0x00 }; this->addColor("_rbgyr20_40", _rbgyr20_40); int _rbgyr20_41[3] = { 0xff, 0xdc, 0x00 }; this->addColor("_rbgyr20_41", _rbgyr20_41); int _rbgyr20_42[3] = { 0xff, 0xcb, 0x00 }; this->addColor("_rbgyr20_42", _rbgyr20_42); int _rbgyr20_43[3] = { 0xff, 0xc2, 0x00 }; this->addColor("_rbgyr20_43", _rbgyr20_43); int _rbgyr20_44[3] = { 0xff, 0xae, 0x00 }; this->addColor("_rbgyr20_44", _rbgyr20_44); int _rbgyr20_45[3] = { 0xff, 0x9f, 0x00 }; this->addColor("_rbgyr20_45", _rbgyr20_45); int _rbgyr20_46[3] = { 0xff, 0x86, 0x00 }; this->addColor("_rbgyr20_46", _rbgyr20_46); int _rbgyr20_47[3] = { 0xff, 0x59, 0x00 }; this->addColor("_rbgyr20_47", _rbgyr20_47); int _rbgyr20_48[3] = { 0x00, 0xff, 0x2d }; this->addColor("_rbgyr20_48", _rbgyr20_48); int _rbgyr20_49[3] = { 0x00, 0xff, 0x65 }; this->addColor("_rbgyr20_49", _rbgyr20_49); int _rbgyr20_50[3] = { 0x00, 0xff, 0xa5 }; this->addColor("_rbgyr20_50", _rbgyr20_50); int _rbgyr20_51[3] = { 0x00, 0xff, 0xdd }; this->addColor("_rbgyr20_51", _rbgyr20_51); int _rbgyr20_52[3] = { 0x00, 0xff, 0xff }; this->addColor("_rbgyr20_52", _rbgyr20_52); int _rbgyr20_53[3] = { 0x00, 0xe9, 0xff }; this->addColor("_rbgyr20_53", _rbgyr20_53); int _rbgyr20_54[3] = { 0x00, 0xad, 0xff }; this->addColor("_rbgyr20_54", _rbgyr20_54); int _rbgyr20_55[3] = { 0x00, 0x69, 0xff }; this->addColor("_rbgyr20_55", _rbgyr20_55); int _rbgyr20_56[3] = { 0xff, 0x00, 0xb9 }; this->addColor("_rbgyr20_56", _rbgyr20_56); int _rbgyr20_57[3] = { 0xff, 0x00, 0x63 }; this->addColor("_rbgyr20_57", _rbgyr20_57); int _rbgyr20_58[3] = { 0xff, 0x05, 0x00 }; this->addColor("_rbgyr20_58", _rbgyr20_58); int _rbgyr20_59[3] = { 0xff, 0x32, 0x00 }; this->addColor("_rbgyr20_59", _rbgyr20_59); int _rbgyr20_60[3] = { 0xff, 0x70, 0x00 }; this->addColor("_rbgyr20_60", _rbgyr20_60); int _rbgyr20_61[3] = { 0xff, 0xa4, 0x00 }; this->addColor("_rbgyr20_61", _rbgyr20_61); int _rbgyr20_62[3] = { 0xff, 0xba, 0x00 }; this->addColor("_rbgyr20_62", _rbgyr20_62); int _rbgyr20_63[3] = { 0xff, 0xd3, 0x00 }; this->addColor("_rbgyr20_63", _rbgyr20_63); int _rbgyr20_64[3] = { 0x42, 0x21, 0xdb }; this->addColor("_rbgyr20_64", _rbgyr20_64); int _rbgyr20_65[3] = { 0x10, 0x08, 0xf6 }; this->addColor("_rbgyr20_65", _rbgyr20_65); int _rbgyr20_66[3] = { 0x00, 0x13, 0xff }; this->addColor("_rbgyr20_66", _rbgyr20_66); int _rbgyr20_67[3] = { 0x00, 0x5b, 0xff }; this->addColor("_rbgyr20_67", _rbgyr20_67); int _rbgyr20_68[3] = { 0x00, 0xb3, 0xff }; this->addColor("_rbgyr20_68", _rbgyr20_68); int _rbgyr20_69[3] = { 0x00, 0xfc, 0xff }; this->addColor("_rbgyr20_69", _rbgyr20_69); int _rbgyr20_70[3] = { 0x00, 0xff, 0xcd }; this->addColor("_rbgyr20_70", _rbgyr20_70); int _rbgyr20_71[3] = { 0x00, 0xff, 0x74 }; this->addColor("_rbgyr20_71", _rbgyr20_71); int _rbgyr20_72[3] = { 0xff, 0x00, 0xf9 }; this->addColor("_rbgyr20_72", _rbgyr20_72); int _rbgyr20_73[3] = { 0x62, 0x31, 0xc9 }; this->addColor("_rbgyr20_73", _rbgyr20_73); //------------------------------------------------------------------------ // // Palette by Russ H. // if (this->getPaletteByName("raich4_clrmid") == NULL) { Palette r4; r4.setName("raich4_clrmid"); r4.addScalarAndColor(1.000000f, "_rbgyr20_20"); r4.addScalarAndColor(0.900000f, "_rbgyr20_30"); r4.addScalarAndColor(0.800000f, "_rbgyr20_29"); r4.addScalarAndColor(0.700000f, "_rbgyr20_28"); r4.addScalarAndColor(0.600000f, "_rbgyr20_27"); r4.addScalarAndColor(0.500000f, "_rbgyr20_26"); r4.addScalarAndColor(0.400000f, "_rbgyr20_25"); r4.addScalarAndColor(0.300000f, "_rbgyr20_24"); r4.addScalarAndColor(0.200000f, "_rbgyr20_23"); r4.addScalarAndColor(0.100000f, "_rbgyr20_15"); r4.addScalarAndColor(0.000000f, "none"); r4.addScalarAndColor(-0.100000f, "_rbgyr20_10"); r4.addScalarAndColor(-0.200000f, "_rbgyr20_31"); r4.addScalarAndColor(-0.300000f, "_rbgyr20_32"); r4.addScalarAndColor(-0.400000f, "_rbgyr20_33"); r4.addScalarAndColor(-0.500000f, "_rbgyr20_34"); r4.addScalarAndColor(-0.600000f, "_rbgyr20_35"); r4.addScalarAndColor(-0.700000f, "_rbgyr20_36"); r4.addScalarAndColor(-0.800000f, "_rbgyr20_37"); r4.addScalarAndColor(-0.900000f, "_rbgyr20_38"); r4.addScalarAndColor(-1.000000f, "_rbgyr20_39"); addPalette(r4); } //------------------------------------------------------------------------ // // Palette by Russ H. // if (this->getPaletteByName("raich6_clrmid") == NULL) { Palette r6; r6.setName("raich6_clrmid"); r6.addScalarAndColor(1.000000f, "_rbgyr20_20"); r6.addScalarAndColor(0.900000f, "_rbgyr20_47"); r6.addScalarAndColor(0.800000f, "_rbgyr20_46"); r6.addScalarAndColor(0.700000f, "_rbgyr20_45"); r6.addScalarAndColor(0.600000f, "_rbgyr20_44"); r6.addScalarAndColor(0.500000f, "_rbgyr20_43"); r6.addScalarAndColor(0.400000f, "_rbgyr20_42"); r6.addScalarAndColor(0.300000f, "_rbgyr20_41"); r6.addScalarAndColor(0.200000f, "_rbgyr20_40"); r6.addScalarAndColor(0.100000f, "_rbgyr20_15"); r6.addScalarAndColor(0.000000f, "none"); r6.addScalarAndColor(-0.100000f, "_rbgyr20_10"); r6.addScalarAndColor(-0.200000f, "_rbgyr20_48"); r6.addScalarAndColor(-0.300000f, "_rbgyr20_49"); r6.addScalarAndColor(-0.400000f, "_rbgyr20_50"); r6.addScalarAndColor(-0.500000f, "_rbgyr20_51"); r6.addScalarAndColor(-0.600000f, "_rbgyr20_52"); r6.addScalarAndColor(-0.700000f, "_rbgyr20_53"); r6.addScalarAndColor(-0.800000f, "_rbgyr20_54"); r6.addScalarAndColor(-0.900000f, "_rbgyr20_55"); r6.addScalarAndColor(-1.000000f, "_rbgyr20_39"); addPalette(r6); } //------------------------------------------------------------------------ // // Palette by Russ H. // if (this->getPaletteByName("HSB8_clrmid") == NULL) { Palette hsb8; hsb8.setName("HSB8_clrmid"); hsb8.addScalarAndColor(1.000000f, "_rbgyr20_15"); hsb8.addScalarAndColor(0.900000f, "_rbgyr20_63"); hsb8.addScalarAndColor(0.800000f, "_rbgyr20_62"); hsb8.addScalarAndColor(0.700000f, "_rbgyr20_61"); hsb8.addScalarAndColor(0.600000f, "_rbgyr20_60"); hsb8.addScalarAndColor(0.500000f, "_rbgyr20_59"); hsb8.addScalarAndColor(0.400000f, "_rbgyr20_58"); hsb8.addScalarAndColor(0.300000f, "_rbgyr20_57"); hsb8.addScalarAndColor(0.200000f, "_rbgyr20_56"); hsb8.addScalarAndColor(0.100000f, "_rbgyr20_72"); hsb8.addScalarAndColor(0.000000f, "none"); hsb8.addScalarAndColor(-0.100000f, "_rbgyr20_73"); hsb8.addScalarAndColor(-0.200000f, "_rbgyr20_64"); hsb8.addScalarAndColor(-0.300000f, "_rbgyr20_65"); hsb8.addScalarAndColor(-0.400000f, "_rbgyr20_66"); hsb8.addScalarAndColor(-0.500000f, "_rbgyr20_67"); hsb8.addScalarAndColor(-0.600000f, "_rbgyr20_68"); hsb8.addScalarAndColor(-0.700000f, "_rbgyr20_69"); hsb8.addScalarAndColor(-0.800000f, "_rbgyr20_70"); hsb8.addScalarAndColor(-0.900000f, "_rbgyr20_71"); hsb8.addScalarAndColor(-1.000000f, "_rbgyr20_10"); addPalette(hsb8); } //---------------------------------------------------------------------- // Positive/Negative palette // if (this->getPaletteByName("POS_NEG") == NULL) { this->addColor("pos_neg_blue", 0x00, 0x00, 0xff ); this->addColor("pos_neg_red", 0xff, 0x00, 0x00 ); Palette posNeg; posNeg.setName("POS_NEG"); posNeg.addScalarAndColor(1.00f, "pos_neg_red"); posNeg.addScalarAndColor(0.0001f, "none"); posNeg.addScalarAndColor(-0.0001f, "pos_neg_blue"); addPalette(posNeg); } if (modifiedStatus == false) { this->clearModified();//this clears modified status on all members, to match our status } static bool printAllPalettesFlag = false; if (printAllPalettesFlag) { printAllPalettesFlag = false; for (const auto p : this->palettes) { std::cout << "----------------------" << std::endl; std::cout << p->toString() << std::endl; std::cout << "INVERTED" << std::endl; std::cout << p->getInvertedPalette()->toString() << std::endl; std::cout << "SEPARATE SIGN" << std::endl; std::cout << p->getSignSeparateInvertedPalette()->toString() << std::endl; std::cout << "SEPARATE NONE"; if (p->getSignSeparateInvertedPalette() == p->getNoneSeparateInvertedPalette()) { std::cout << " same as SEPARATE SIGN" << std::endl; } else { std::cout << std::endl; std::cout << p->getNoneSeparateInvertedPalette()->toString() << std::endl; } } } } /** * @return The structure for this file. */ StructureEnum::Enum PaletteFile::getStructure() const { // palette files do not have structure return StructureEnum::INVALID; } /** * Set the structure for this file. * @param structure * New structure for this file. */ void PaletteFile::setStructure(const StructureEnum::Enum /*structure*/) { // palette files do not have structure } /** * @return Get access to the file's metadata. */ GiftiMetaData* PaletteFile::getFileMetaData() { return this->metadata; } /** * @return Get access to unmodifiable file's metadata. */ const GiftiMetaData* PaletteFile::getFileMetaData() const { return this->metadata; } /** * Set the palette mapping based upon the given file type, * file name, data name, and data. * * @param paletteColorMapping * Palette color mapping that is setup. * @param dataFileType * Type of data file. * @param fileName * Name of file. * @param dataName * Name of data. * @param data * The data. * @param numberOfDataElements * Number of elements in data. */ void PaletteFile::setDefaultPaletteColorMapping(PaletteColorMapping* paletteColorMapping, const DataFileTypeEnum::Enum& dataFileType, const AString& fileNameIn, const AString& dataNameIn, const float* data, const int32_t numberOfDataElements) { bool isShapeCurvatureData = false; bool isShapeDepthData = false; bool isShapeData = false; bool isVolumeAnatomyData = false; const AString fileName = fileNameIn.toLower(); const AString dataName = dataNameIn.toLower(); bool invalid = false; bool checkShapeFile = false; bool checkVolume = false; switch (dataFileType) { case DataFileTypeEnum::ANNOTATION: invalid = true; break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: invalid = true; break; case DataFileTypeEnum::BORDER: invalid = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: invalid = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: checkShapeFile = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: invalid = true; break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: invalid = true; break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: invalid = true; break; case DataFileTypeEnum::IMAGE: invalid = true; break; case DataFileTypeEnum::LABEL: invalid = true; break; case DataFileTypeEnum::METRIC: checkShapeFile = true; break; case DataFileTypeEnum::METRIC_DYNAMIC: break; case DataFileTypeEnum::PALETTE: invalid = true; break; case DataFileTypeEnum::RGBA: invalid = true; break; case DataFileTypeEnum::SCENE: invalid = true; break; case DataFileTypeEnum::SPECIFICATION: invalid = true; break; case DataFileTypeEnum::SURFACE: invalid = true; break; case DataFileTypeEnum::UNKNOWN: invalid = true; break; case DataFileTypeEnum::VOLUME: checkVolume = true; break; case DataFileTypeEnum::VOLUME_DYNAMIC: break; } if (invalid) { return; } if (checkShapeFile) { if (dataName.contains("curv")) { isShapeData = true; isShapeCurvatureData = true; } else if (dataName.contains("depth")) { isShapeData = true; isShapeDepthData = true; } else if (dataName.contains("shape")) { isShapeData = true; } else if (fileName.contains("curv")) { isShapeData = true; isShapeCurvatureData = true; } else if (fileName.contains("depth")) { isShapeData = true; isShapeDepthData = true; } else if (fileName.contains("shape")) { isShapeData = true; } } float minValue = std::numeric_limits::max(); float maxValue = -minValue; for (int32_t i = 0; i < numberOfDataElements; i++) { const float d = data[i]; if (d > maxValue) { maxValue = d; } if (d < minValue) { minValue = d; } } //bool havePositiveData = (maxValue > 0);//unused, commenting out to prevent compiler warning bool haveNegativeData = (minValue < 0); if (checkVolume) { if ((minValue >= 0) && (maxValue <= 255.0)) { isVolumeAnatomyData = true; } } if (isVolumeAnatomyData) { paletteColorMapping->setThresholdType(PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF); paletteColorMapping->setSelectedPaletteName("Gray_Interp_Positive"); paletteColorMapping->setInterpolatePaletteFlag(true); paletteColorMapping->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE); paletteColorMapping->setAutoScalePercentageNegativeMaximum(98.0); paletteColorMapping->setAutoScalePercentageNegativeMinimum(2.0); paletteColorMapping->setAutoScalePercentagePositiveMinimum(2.0); paletteColorMapping->setAutoScalePercentagePositiveMaximum(98.0); } else if (isShapeData) { paletteColorMapping->setThresholdType(PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF); paletteColorMapping->setSelectedPaletteName("Gray_Interp"); paletteColorMapping->setInterpolatePaletteFlag(true); if (isShapeDepthData) { paletteColorMapping->setScaleMode(PaletteScaleModeEnum::MODE_USER_SCALE); paletteColorMapping->setUserScaleNegativeMaximum(-30.0); paletteColorMapping->setUserScaleNegativeMinimum(0.0); paletteColorMapping->setUserScalePositiveMinimum(0.0); paletteColorMapping->setUserScalePositiveMaximum(10.0); } else if (isShapeCurvatureData) { // paletteColorMapping->setScaleMode(PaletteScaleModeEnum::MODE_USER_SCALE); // paletteColorMapping->setUserScaleNegativeMaximum(-1.5); // paletteColorMapping->setUserScaleNegativeMinimum(0.0); // paletteColorMapping->setUserScalePositiveMinimum(0.0); // paletteColorMapping->setUserScalePositiveMaximum(1.5); paletteColorMapping->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE); paletteColorMapping->setAutoScalePercentageNegativeMaximum(98.0); paletteColorMapping->setAutoScalePercentageNegativeMinimum(2.0); paletteColorMapping->setAutoScalePercentagePositiveMinimum(2.0); paletteColorMapping->setAutoScalePercentagePositiveMaximum(98.0); } else { paletteColorMapping->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE); paletteColorMapping->setAutoScalePercentageNegativeMaximum(98.0); paletteColorMapping->setAutoScalePercentageNegativeMinimum(2.0); paletteColorMapping->setAutoScalePercentagePositiveMinimum(2.0); paletteColorMapping->setAutoScalePercentagePositiveMaximum(98.0); } paletteColorMapping->setDisplayNegativeDataFlag(true); paletteColorMapping->setDisplayPositiveDataFlag(true); paletteColorMapping->setDisplayZeroDataFlag(true); } else { if (haveNegativeData) { paletteColorMapping->setThresholdType(PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF); paletteColorMapping->setSelectedPaletteName("videen-style"); paletteColorMapping->setSelectedPaletteName("ROY-BIG-BL"); paletteColorMapping->setInterpolatePaletteFlag(true); paletteColorMapping->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE); paletteColorMapping->setAutoScalePercentageNegativeMaximum(98.0); paletteColorMapping->setAutoScalePercentageNegativeMinimum(2.0); paletteColorMapping->setAutoScalePercentagePositiveMinimum(2.0); paletteColorMapping->setAutoScalePercentagePositiveMaximum(98.0); paletteColorMapping->setDisplayNegativeDataFlag(true); paletteColorMapping->setDisplayPositiveDataFlag(true); paletteColorMapping->setDisplayZeroDataFlag(false); } else { paletteColorMapping->setThresholdType(PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF); paletteColorMapping->setSelectedPaletteName("videen-style"); paletteColorMapping->setSelectedPaletteName("ROY-BIG-BL"); paletteColorMapping->setInterpolatePaletteFlag(true); paletteColorMapping->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE); paletteColorMapping->setAutoScalePercentageNegativeMaximum(98.0); paletteColorMapping->setAutoScalePercentageNegativeMinimum(2.0); paletteColorMapping->setAutoScalePercentagePositiveMinimum(2.0); paletteColorMapping->setAutoScalePercentagePositiveMaximum(98.0); paletteColorMapping->setDisplayNegativeDataFlag(true); paletteColorMapping->setDisplayPositiveDataFlag(true); paletteColorMapping->setDisplayZeroDataFlag(false); } } paletteColorMapping->clearModified(); } connectome-workbench-1.4.2/src/Files/PaletteFile.h000066400000000000000000000100161360521144700220310ustar00rootroot00000000000000#ifndef __PALETTEFILE_H__ #define __PALETTEFILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretDataFile.h" #include #include #include #include "GiftiLabelTable.h" namespace caret { class GiftiLabel; class GiftiLabelTable; class GiftiMetaData; class Palette; class PaletteColorMapping; /** * File for storing color palettes. */ class PaletteFile : public CaretDataFile { public: PaletteFile(); virtual ~PaletteFile(); public: PaletteFile(const PaletteFile& o); PaletteFile& operator=(const PaletteFile& o); private: void initializeMembersPaletteFile(); public: GiftiLabelTable* getLabelTable(); void clear(); void addColor(const GiftiLabel& pc); void addColor( const AString& name, const int32_t red, const int32_t green, const int32_t blue); void addColor( const AString& name, const int32_t rgb[]); const GiftiLabel* getColor(const int32_t index) const; const GiftiLabel* getColorByName(const AString& colorName) const; int32_t getColorIndex(const AString& colorName) const; int32_t getNumberOfPalettes() const; void addPalette(const Palette& p); Palette* getPalette(const int32_t index) const; Palette* getPaletteByName(const AString& name) const; void removePalette(const int32_t index); virtual bool isEmpty() const; AString toString() const; bool isModified() const; void clearModified(); virtual void readFile(const AString& filename); virtual void writeFile(const AString& filename); virtual StructureEnum::Enum getStructure() const; virtual void setStructure(const StructureEnum::Enum structure); DataFileTypeEnum::Enum getDataFileType() const; virtual GiftiMetaData* getFileMetaData(); virtual const GiftiMetaData* getFileMetaData() const; static void setDefaultPaletteColorMapping(PaletteColorMapping* paletteColorMapping, const DataFileTypeEnum::Enum& dataFileType, const AString& fileName, const AString& dataName, const float* data, const int32_t numberOfDataElements); private: void assignColorsToPalette(Palette& p); void addDefaultPalettes(); void clearAll(); private: /**the colors for the palettes */ GiftiLabelTable labelTable; /**the palettes */ std::vector palettes; GiftiMetaData* metadata; }; } // namespace #endif // __PALETTEFILE_H__ connectome-workbench-1.4.2/src/Files/RgbaFile.cxx000066400000000000000000000132471360521144700216720ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "DataFileException.h" #include "DataFileTypeEnum.h" #include "GiftiFile.h" #include "MathFunctions.h" #include "RgbaFile.h" using namespace caret; /** * Constructor. */ RgbaFile::RgbaFile() : GiftiTypeFile(DataFileTypeEnum::RGBA) { this->initializeMembersRgbaFile(); } /** * Copy constructor. * * @param sf * Surface file that is copied. */ RgbaFile::RgbaFile(const RgbaFile& sf) : GiftiTypeFile(sf) { this->copyHelperRgbaFile(sf); } /** * Assignment operator. * * @param sf * Surface file that is copied. * @return * This surface file with content replaced * by the RgbaFile parameter. */ RgbaFile& RgbaFile::operator=(const RgbaFile& sf) { if (this != &sf) { GiftiTypeFile::operator=(sf); this->copyHelperRgbaFile(sf); } return *this; } /** * Destructor. */ RgbaFile::~RgbaFile() { } /** * Clear the surface file. */ void RgbaFile::clear() { GiftiTypeFile::clear(); } /** * Validate the contents of the file after it * has been read such as correct number of * data arrays and proper data types/dimensions. */ void RgbaFile::validateDataArraysAfterReading() { this->initializeMembersRgbaFile(); const int32_t numberOfDataArrays = this->giftiFile->getNumberOfDataArrays(); if (numberOfDataArrays != 1) { throw DataFileException(getFileName(), "GIFTI RGBA files must have one GIFTI Data Array"); } const GiftiDataArray* gda = this->giftiFile->getDataArray(0); if (gda->getNumberOfRows() <= 0) { throw DataFileException(getFileName(), "GIFTI RGBA file is empty (number of rows is zero)"); } m_numberOfComponents = gda->getNumberOfComponents(); if ((m_numberOfComponents < 3) || (m_numberOfComponents > 4)) { throw DataFileException(getFileName(), "GIFTI RGBA file must have four components but contains " + AString::number(m_numberOfComponents) + " components."); } if (gda->getDataType() != NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32) { throw DataFileException("GIFTI RGBA files must be FLOAT data type. " "Type of data array is: " + NiftiDataTypeEnum::toName(gda->getDataType())); } this->verifyDataArraysHaveSameNumberOfRows(3, 4); m_dataArray = this->giftiFile->getDataArray(0); m_numberOfVertices = gda->getNumberOfRows(); bool rescaleZeroToOneFlag = false; const int32_t numValues = m_numberOfComponents * m_numberOfVertices; float* floatData = m_dataArray->getDataPointerFloat(); for (int32_t i = 0; i < numValues; i++) { if (floatData[i] > 1.1f) { rescaleZeroToOneFlag = true; break; } } if (rescaleZeroToOneFlag) { for (int32_t i = 0; i < numValues; i++) { floatData[i] /= 255.0; } } } /** * Get the number of nodes. * * @return * The number of nodes. */ int32_t RgbaFile::getNumberOfNodes() const { return m_numberOfVertices; } /** * Get the number of columns. * * @return * The number of columns. */ int32_t RgbaFile::getNumberOfColumns() const { const int32_t numCols = this->giftiFile->getNumberOfDataArrays(); return numCols; } /** * Initialize members of this class. */ void RgbaFile::initializeMembersRgbaFile() { m_dataArray = 0; m_numberOfVertices = 0; m_numberOfComponents = 0; } /** * Helps copying files. * * @param sf * File that is copied. */ void RgbaFile::copyHelperRgbaFile(const RgbaFile& /*sf*/) { this->validateDataArraysAfterReading(); } /** * Get the RGBA data for the given vertex. * * @param vertexIndex * Index of the vertex. * @param rgbaOut * Output containing RGBA values for vertex. */ void RgbaFile::getVertexRGBA(const int32_t vertexIndex, float* rgbaOut) const { CaretAssert((vertexIndex >= 0) && (vertexIndex < m_numberOfVertices)); const float* floatData = m_dataArray->getDataPointerFloat(); if (m_numberOfComponents == 4) { const int32_t v4 = vertexIndex * 4; CaretAssertArrayIndex(floatData, m_numberOfVertices * m_numberOfComponents, v4 + 3); rgbaOut[0] = floatData[v4]; rgbaOut[1] = floatData[v4+1]; rgbaOut[2] = floatData[v4+2]; rgbaOut[3] = floatData[v4+3]; } else if (m_numberOfComponents == 3) { const int32_t v3 = vertexIndex * 3; CaretAssertArrayIndex(floatData, m_numberOfVertices * m_numberOfComponents, v3 + 2); rgbaOut[0] = floatData[v3]; rgbaOut[1] = floatData[v3+1]; rgbaOut[2] = floatData[v3+2]; rgbaOut[3] = 1.0f; } else { CaretAssert(0); } } connectome-workbench-1.4.2/src/Files/RgbaFile.h000066400000000000000000000041641360521144700213150ustar00rootroot00000000000000 #ifndef __RGBA_FILE_H__ #define __RGBA_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "GiftiTypeFile.h" namespace caret { class GiftiDataArray; /** * \brief An RGBA data file. */ class RgbaFile : public GiftiTypeFile { public: RgbaFile(); RgbaFile(const RgbaFile& sf); RgbaFile& operator=(const RgbaFile& sf); virtual ~RgbaFile(); virtual void clear(); virtual int32_t getNumberOfNodes() const; virtual int32_t getNumberOfColumns() const; void getVertexRGBA(const int32_t vertexIndex, float* rgbaOut) const; protected: /** * Validate the contents of the file after it * has been read such as correct number of * data arrays and proper data types/dimensions. */ virtual void validateDataArraysAfterReading(); void copyHelperRgbaFile(const RgbaFile& sf); void initializeMembersRgbaFile(); private: GiftiDataArray* m_dataArray = 0; int32_t m_numberOfVertices = 0; int32_t m_numberOfComponents = 0; }; } // namespace #endif // __RGBA_FILE_H__ connectome-workbench-1.4.2/src/Files/RibbonMappingHelper.cxx000066400000000000000000000416111360521144700241020ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /* * For the function TriInfi::vertRayHit(): * Original copyright for PNPOLY, though my version is entirely rewritten and modified * Source: http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html */ /* Copyright (c) 1970-2003, Wm. Randolph Franklin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers. 2. Redistributions in binary form must reproduce the above copyright notice in the documentation and/or other materials provided with the distribution. 3. The name of W. Randolph Franklin may not be used to endorse or promote products derived from this Software without specific prior written permission. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "RibbonMappingHelper.h" #include "CaretException.h" #include "FloatMatrix.h" #include "MathFunctions.h" #include "SurfaceFile.h" #include "TopologyHelper.h" #include "VolumeSpace.h" #include using namespace caret; using namespace std; //private namespace for implementation details namespace { struct TriInfo { Vector3D m_xyz[3]; float m_planeEq[3];//x coef, y coef, const : z = [0] * x + [1] * y + [2] bool vertRayHit(const float* xyz);//true if a +z ray from point hits this triangle TriInfo(const float* xyz1, const float* xyz2, const float* xyz3); TriInfo() {}; }; struct QuadInfo { TriInfo m_tris[2][2]; int vertRayHit(const float* xyz);//+z ray intersect: 0 if never, 1 if only 1 of the 2 triangulations, 2 if both QuadInfo(const float* xyz1, const float* xyz2, const float* xyz3, const float* xyz4); QuadInfo() {}; }; struct PolyInfo { std::vector m_tris; std::vector m_quads; PolyInfo(const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const int32_t node, const bool& thinColumn = false);//surfaces MUST be in node correspondence, otherwise SEVERE strangeness, possible crashes PolyInfo() {}; int isInside(const float* xyz);//0 for no, 2 for yes, 1 for if only half the triangulations (between the two triangulations of one of the quad faces) private: void addTri(const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const int32_t* myTri, const int rootIndex, const bool& thinColumn);//adds the tri for each surface, plus the quad }; void PolyInfo::addTri(const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const int32_t* myTri, const int rootIndex, const bool& thinColumn) {//tries to orient normals consistently with respect to inside/outside, but it doesn't currently matter int root = myTri[rootIndex], node2 = myTri[(rootIndex + 1) % 3], node3 = myTri[(rootIndex + 2) % 3]; if (thinColumn) { Vector3D innerRoot = innerSurf->getCoordinate(root), inner2 = innerSurf->getCoordinate(node2), inner3 = innerSurf->getCoordinate(node3); Vector3D outerRoot = outerSurf->getCoordinate(root), outer2 = outerSurf->getCoordinate(node2), outer3 = outerSurf->getCoordinate(node3); //use an ordering trick of the 3 vertices so that the summing order is always 01, 12, or 20 - doesn't actually matter (at least on x86), but hey Vector3D innerEdge2 = (innerRoot + inner2) / 2, innerEdge3 = (inner3 + innerRoot) / 2; Vector3D outerEdge2 = (outerRoot + outer2) / 2, outerEdge3 = (outer3 + outerRoot) / 2; //for consistency in floating point rounding, we need to generate the sum of the 3 coordinates in the same order regardless of rootIndex //so, use the original triangle definition and 0, 1, 2 order //this doesn't matter for edges because there only 2 coordinates are added together Vector3D innerCenter = (Vector3D(innerSurf->getCoordinate(myTri[0])) + Vector3D(innerSurf->getCoordinate(myTri[1])) + Vector3D(innerSurf->getCoordinate(myTri[2]))) / 3; Vector3D outerCenter = (Vector3D(outerSurf->getCoordinate(myTri[0])) + Vector3D(outerSurf->getCoordinate(myTri[1])) + Vector3D(outerSurf->getCoordinate(myTri[2]))) / 3; m_tris.push_back(TriInfo(innerRoot, innerEdge3, innerCenter)); m_tris.push_back(TriInfo(innerRoot, innerCenter, innerEdge2)); m_tris.push_back(TriInfo(outerRoot, outerEdge2, outerCenter)); m_tris.push_back(TriInfo(outerRoot, outerCenter, outerEdge3)); m_quads.push_back(QuadInfo(innerEdge2, innerCenter, outerCenter, outerEdge2)); m_quads.push_back(QuadInfo(innerCenter, innerEdge3, outerEdge3, outerCenter)); } else { m_tris.push_back(TriInfo(innerSurf->getCoordinate(root), innerSurf->getCoordinate(node3), innerSurf->getCoordinate(node2))); m_tris.push_back(TriInfo(outerSurf->getCoordinate(root), outerSurf->getCoordinate(node2), outerSurf->getCoordinate(node3))); m_quads.push_back(QuadInfo(innerSurf->getCoordinate(node2), innerSurf->getCoordinate(node3), outerSurf->getCoordinate(node3), outerSurf->getCoordinate(node2))); } } int PolyInfo::isInside(const float* xyz) { int i, temp, numQuads = (int)m_quads.size(); bool toggle = false; for (i = 0; i < numQuads; ++i) { temp = m_quads[i].vertRayHit(xyz); if (temp == 1) return 1;//means only one of the two triangulations has a hit, therefore, we can return early if (temp) toggle = !toggle;//even/odd winding rule } int numTris = (int)m_tris.size(); for (i = 0; i < numTris; ++i) { if (m_tris[i].vertRayHit(xyz)) toggle = !toggle; } if (toggle) return 2; return 0; } PolyInfo::PolyInfo(const caret::SurfaceFile* innerSurf, const caret::SurfaceFile* outerSurf, const int32_t node, const bool& thinColumn) { CaretPointer myTopoHelp = innerSurf->getTopologyHelper(); int numTiles; const int* myTiles = myTopoHelp->getNodeTiles(node, numTiles); for (int i = 0; i < numTiles; ++i) { const int32_t* myTri = innerSurf->getTriangle(myTiles[i]); if (myTri[0] == node) { addTri(innerSurf, outerSurf, myTri, 0, thinColumn); } else { if (myTri[1] == node) { addTri(innerSurf, outerSurf, myTri, 1, thinColumn); } else { addTri(innerSurf, outerSurf, myTri, 2, thinColumn); } } } } QuadInfo::QuadInfo(const float* xyz1, const float* xyz2, const float* xyz3, const float* xyz4) { m_tris[0][0] = TriInfo(xyz1, xyz2, xyz3); m_tris[0][1] = TriInfo(xyz1, xyz3, xyz4); m_tris[1][0] = TriInfo(xyz1, xyz2, xyz4); m_tris[1][1] = TriInfo(xyz2, xyz3, xyz4); } int QuadInfo::vertRayHit(const float* xyz) { int ret = 0; if (m_tris[0][0].vertRayHit(xyz) != m_tris[0][1].vertRayHit(xyz)) ++ret; if (m_tris[1][0].vertRayHit(xyz) != m_tris[1][1].vertRayHit(xyz)) ++ret; return ret; } TriInfo::TriInfo(const float* xyz1, const float* xyz2, const float* xyz3) { m_xyz[0] = xyz1; m_xyz[1] = xyz2; m_xyz[2] = xyz3; FloatMatrix myRref; myRref.resize(3, 4); for (int i = 0; i < 3; ++i)//ax + by + c = z { myRref[i][0] = m_xyz[i][0];//coefficient of a myRref[i][1] = m_xyz[i][1];//coefficient of b myRref[i][2] = 1;//coefficient of c myRref[i][3] = m_xyz[i][2];//what it equals } FloatMatrix myResult = myRref.reducedRowEchelon(); m_planeEq[0] = myResult[0][3];//a m_planeEq[1] = myResult[1][3];//b m_planeEq[2] = myResult[2][3];//c float sanity = m_planeEq[0] + m_planeEq[1] + m_planeEq[2]; if (!MathFunctions::isNumeric(sanity)) { m_planeEq[0] = sanity;//make sure the first element easily identifies vertical triangles } } bool TriInfo::vertRayHit(const float* xyz) { if (!MathFunctions::isNumeric(m_planeEq[0])) {//plane is vertical, nothing can hit it return false; } float planeZ = xyz[0] * m_planeEq[0] + xyz[1] * m_planeEq[1] + m_planeEq[2];//ax + by + c = z if (xyz[2] >= planeZ) {//point is above the plane return false; }//test if the x, y projection has the point inside the triangle //below logic copied from PNPOLY by Wm. Randolph Franklin, swapped x for y, and slightly rewritten, for the special case of 3 vertices bool inside = false; for (int j = 2, i = 0; i < 3; ++i)//start with the wraparound case { if ((m_xyz[i][0] < xyz[0]) != (m_xyz[j][0] < xyz[0])) {//if one vertex is on one side of the point in the x direction, and the other is on the other side (equal case is treated as greater) int ti, tj; if (m_xyz[i][0] < m_xyz[j][0])//reorient the segment consistently to get a consistent answer { ti = i; tj = j; } else { ti = j; tj = i; } if ((m_xyz[ti][1] - m_xyz[tj][1]) / (m_xyz[ti][0] - m_xyz[tj][0]) * (xyz[0] - m_xyz[tj][0]) + m_xyz[tj][1] > xyz[1]) {//if the point on the line described by the two vertices with the same x coordinate is above (greater y) than the test point inside = !inside;//even/odd winding rule again } } j = i;//consecutive vertices, does 2,0 then 0,1 then 1,2 } return inside; } float computeVoxelFraction(const VolumeSpace& myVolSpace, const int64_t* ijk, PolyInfo& myPoly, const int divisions, const Vector3D& ivec, const Vector3D& jvec, const Vector3D& kvec) { Vector3D myLowCorner; myVolSpace.indexToSpace(ijk[0] - 0.5f, ijk[1] - 0.5f, ijk[2] - 0.5f, myLowCorner); int inside = 0; Vector3D istep = ivec / divisions; Vector3D jstep = jvec / divisions; Vector3D kstep = kvec / divisions; myLowCorner += istep * 0.5f + jstep * 0.5f + kstep * 0.5f; for (int i = 0; i < divisions; ++i) { Vector3D tempVeci = myLowCorner + istep * i; for (int j = 0; j < divisions; ++j) { Vector3D tempVecj = tempVeci + jstep * j; for (int k = 0; k < divisions; ++k) { Vector3D thisPoint = tempVecj + kstep * k; inside += myPoly.isInside(thisPoint); } } } return ((float)inside) / (divisions * divisions * divisions * 2); } } void RibbonMappingHelper::computeWeightsRibbon(vector >& myWeightsOut, const VolumeSpace& myVolSpace, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const float* roiFrame, const int& numDivisions, const bool& thinColumn) { if (!innerSurf->hasNodeCorrespondence(*outerSurf)) { throw CaretException("input surfaces to ribbon mapping do not have vertex correspondence"); } if (numDivisions < 1) { throw CaretException("number of voxel subdivisions must be positive for ribbon mapping"); } int64_t numNodes = outerSurf->getNumberOfNodes(); myWeightsOut.resize(numNodes); Vector3D origin, ivec, jvec, kvec;//these are the spatial projections of the ijk unit vectors (also, the offset that specifies the origin) myVolSpace.getSpacingVectors(ivec, jvec, kvec, origin); const float* outerCoords = outerSurf->getCoordinateData(); const float* innerCoords = innerSurf->getCoordinateData(); const int64_t* myDims = myVolSpace.getDims(); #pragma omp CARET_PAR { int maxVoxelCount = 10;//guess for preallocating vectors CaretPointer myTopoHelp = innerSurf->getTopologyHelper(); #pragma omp CARET_FOR schedule(dynamic) for (int64_t node = 0; node < numNodes; ++node) { myWeightsOut[node].clear(); myWeightsOut[node].reserve(maxVoxelCount); float tempf; int64_t node3 = node * 3; PolyInfo myPoly(innerSurf, outerSurf, node, thinColumn);//build the polygon Vector3D minIndex, maxIndex, tempvec; myVolSpace.spaceToIndex(innerCoords + node3, minIndex);//find the bounding box in VOLUME INDEX SPACE, starting with the center nodes maxIndex = minIndex; myVolSpace.spaceToIndex(outerCoords + node3, tempvec); for (int i = 0; i < 3; ++i) { if (tempvec[i] < minIndex[i]) minIndex[i] = tempvec[i]; if (tempvec[i] > maxIndex[i]) maxIndex[i] = tempvec[i]; } int numNeigh; const int* myNeighList = myTopoHelp->getNodeNeighbors(node, numNeigh);//and now the neighbors for (int j = 0; j < numNeigh; ++j) { int neigh3 = myNeighList[j] * 3; myVolSpace.spaceToIndex(outerCoords + neigh3, tempvec); for (int i = 0; i < 3; ++i) { if (tempvec[i] < minIndex[i]) minIndex[i] = tempvec[i]; if (tempvec[i] > maxIndex[i]) maxIndex[i] = tempvec[i]; } myVolSpace.spaceToIndex(innerCoords + neigh3, tempvec); for (int i = 0; i < 3; ++i) { if (tempvec[i] < minIndex[i]) minIndex[i] = tempvec[i]; if (tempvec[i] > maxIndex[i]) maxIndex[i] = tempvec[i]; } } int startIndex[3], endIndex[3]; for (int i = 0; i < 3; ++i) { startIndex[i] = (int)ceil(minIndex[i] - 0.5f);//give an extra half voxel in order to get anything which could have some polygon in it endIndex[i] = (int)floor(maxIndex[i] + 0.5f) + 1;//ditto, plus the one-after end convention if (startIndex[i] < 0) startIndex[i] = 0;//keep it inside the volume boundaries if (endIndex[i] > myDims[i]) endIndex[i] = myDims[i]; } int64_t ijk[3]; for (ijk[0] = startIndex[0]; ijk[0] < endIndex[0]; ++ijk[0]) { for (ijk[1] = startIndex[1]; ijk[1] < endIndex[1]; ++ijk[1]) { for (ijk[2] = startIndex[2]; ijk[2] < endIndex[2]; ++ijk[2]) { if (roiFrame == NULL || roiFrame[myVolSpace.getIndex(ijk)] > 0.0f) { tempf = computeVoxelFraction(myVolSpace, ijk, myPoly, numDivisions, ivec, jvec, kvec); if (tempf != 0.0f) { myWeightsOut[node].push_back(VoxelWeight(tempf, ijk)); } } } } } if ((int)myWeightsOut[node].size() > maxVoxelCount) {//capacity() would use more memory maxVoxelCount = myWeightsOut[node].size(); } } } } connectome-workbench-1.4.2/src/Files/RibbonMappingHelper.h000066400000000000000000000037351360521144700235340ustar00rootroot00000000000000#ifndef __RIBBON_MAPPING_HELPER_H__ #define __RIBBON_MAPPING_HELPER_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "stdint.h" #include #include namespace caret { class SurfaceFile; class VolumeSpace; struct VoxelWeight {//for precomputation in ribbon/myelin style volume to surface mapping float weight; int64_t ijk[3]; VoxelWeight() { }; VoxelWeight(const float weightIn, const int64_t* ijkIn) { weight = weightIn; ijk[0] = ijkIn[0]; ijk[1] = ijkIn[1]; ijk[2] = ijkIn[2]; } }; class RibbonMappingHelper { public: ///compute per-vertex ribbon mapping weights - surfaces must have vertex correspondence, or an exception is thrown static void computeWeightsRibbon(std::vector >& myWeightsOut, const VolumeSpace& myVolSpace, const SurfaceFile* innerSurf, const SurfaceFile* outerSurf, const float* roiFrame = NULL, const int& numDivisions = 3, const bool& thinColumn = false); }; } #endif //__RIBBON_MAPPING_HELPER_H__ connectome-workbench-1.4.2/src/Files/SceneDataFileInfo.cxx000066400000000000000000000174071360521144700234640ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SCENE_DATA_FILE_INFO_DECLARE__ #include "SceneDataFileInfo.h" #undef __SCENE_DATA_FILE_INFO_DECLARE__ #include "CaretAssert.h" #include "FileInformation.h" using namespace caret; /** * \class caret::SceneDataFileInfo * \brief Information about data files in a scene file * \ingroup Files */ /** * Constructor. * * @param absoluteDataFilePathAndName * Absolute path and file name of the data file * @param absoluteBasePath * The absolute base path * @param absoluteSceneFilePathAndName * Absolute path and name of the scene file * @param sceneIndex * Index of scene using this data file. */ SceneDataFileInfo::SceneDataFileInfo(const AString& absoluteDataFilePathAndName, const AString& absoluteBasePath, const AString& absoluteSceneFilePathAndName, const std::vector& sceneIndices) : CaretObject() { FileInformation fileInfo(absoluteDataFilePathAndName); m_remoteFlag = fileInfo.isRemoteFile(); if ( ! m_remoteFlag) { m_missingFlag = ( ! fileInfo.exists()); } m_absolutePath = fileInfo.getAbsolutePath(); m_dataFileName = fileInfo.getFileName(); FileInformation sceneFileInfo(absoluteSceneFilePathAndName); m_relativePathToSceneFile = SystemUtilities::relativePath(m_absolutePath, sceneFileInfo.getAbsolutePath()); m_relativePathToBasePath = SystemUtilities::relativePath(m_absolutePath, absoluteBasePath); m_sceneIndices.insert(sceneIndices.begin(), sceneIndices.end()); } /** * Destructor. */ SceneDataFileInfo::~SceneDataFileInfo() { } /** * Copy constructor. * @param obj * Object that is copied. */ SceneDataFileInfo::SceneDataFileInfo(const SceneDataFileInfo& obj) : CaretObject(obj) { this->copyHelperSceneDataFileInfo(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ SceneDataFileInfo& SceneDataFileInfo::operator=(const SceneDataFileInfo& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperSceneDataFileInfo(obj); } return *this; } /** * Less-than operator. * * @param rhs * Other instance for comparison * @return * True if this instance is 'less-than' the other instance. */ bool SceneDataFileInfo::operator<(const SceneDataFileInfo& rhs) const { if (m_absolutePath == rhs.m_absolutePath) { return (m_dataFileName < rhs.m_dataFileName); } return (m_absolutePath < rhs.m_absolutePath); } /** * Add a scene index that uses this data file. * * @param sceneIndex * Additional scene index. */ void SceneDataFileInfo::addSceneIndex(const int32_t sceneIndex) const { m_sceneIndices.insert(sceneIndex); } /** * @return The scene indices as a string */ AString SceneDataFileInfo::getSceneIndicesAsString() const { std::vector indicesVector(m_sceneIndices.begin(), m_sceneIndices.end()); return AString::fromNumbers(indicesVector, ","); } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void SceneDataFileInfo::copyHelperSceneDataFileInfo(const SceneDataFileInfo& obj) { m_absolutePath = obj.m_absolutePath; m_dataFileName = obj.m_dataFileName; m_relativePathToBasePath = obj.m_relativePathToBasePath; m_relativePathToSceneFile = obj.m_relativePathToSceneFile; m_sceneIndices = obj.m_sceneIndices; } /** * @return */ AString SceneDataFileInfo::getAbsolutePath() const { return m_absolutePath; } /** * @return */ AString SceneDataFileInfo::getAbsolutePathAndFileName() const { if (m_absolutePath.isEmpty()) { return m_dataFileName; } const AString s(m_absolutePath + "/" + m_dataFileName); return s; } /** * @return */ AString SceneDataFileInfo::getDataFileName() const { return m_dataFileName; } /** * @return */ AString SceneDataFileInfo::getRelativePathToBasePath() const { return m_relativePathToBasePath; } /** * @return */ AString SceneDataFileInfo::getRelativePathToSceneFile() const { return m_relativePathToSceneFile; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString SceneDataFileInfo::toString() const { return "SceneDataFileInfo"; } /** * @return True if the file is remote. */ bool SceneDataFileInfo::isRemote() const { return m_remoteFlag; } /** * @return True if this file is missing. * Note: Remote file is never missing. */ bool SceneDataFileInfo::isMissing() const { if (isRemote()) { return false; } return m_missingFlag; } /** * Sort a vector of SceneDataFileInfo objects using the given sort mode * * @param sceneDataFileInfo * Vector of object that is sorted. * @param sortMode * Mode for sorting. */ void SceneDataFileInfo::sort(std::vector& sceneDataFileInfo, const SortMode sortMode) { switch (sortMode) { case SortMode::AbsolutePath: break; case SortMode::RelativeToBasePath: break; case SortMode::RelativeToSceneFilePath: break; } std::sort(sceneDataFileInfo.begin(), sceneDataFileInfo.end(), [&sortMode] (const SceneDataFileInfo& lhs, const SceneDataFileInfo& rhs) { AString lhsPath; AString rhsPath; switch (sortMode) { case SortMode::AbsolutePath: lhsPath = lhs.m_absolutePath; rhsPath = rhs.m_absolutePath; break; case SortMode::RelativeToBasePath: lhsPath = lhs.m_relativePathToBasePath; rhsPath = rhs.m_relativePathToBasePath; break; case SortMode::RelativeToSceneFilePath: lhsPath = lhs.m_relativePathToSceneFile; rhsPath = rhs.m_relativePathToSceneFile; break; } if (lhsPath == rhsPath) { return (lhs.m_dataFileName < rhs.m_dataFileName); } return (lhsPath < rhsPath); }); /*print (sceneDataFileInfo);*/ } /** * Print the vector of file information. * * @param sceneDataFileInfo * Information that is printed. */ void SceneDataFileInfo::print(const std::vector& sceneDataFileInfo) { for (const auto sdfi : sceneDataFileInfo) { std::cout << sdfi.getAbsolutePathAndFileName() << std::endl; } } connectome-workbench-1.4.2/src/Files/SceneDataFileInfo.h000066400000000000000000000067101360521144700231040ustar00rootroot00000000000000#ifndef __SCENE_DATA_FILE_INFO_H__ #define __SCENE_DATA_FILE_INFO_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "CaretObject.h" namespace caret { class SceneDataFileInfo : public CaretObject { public: /** * Mode for sorting */ enum class SortMode { /* Sort by file's absolute path and then data file name */ AbsolutePath, /* Sort by path relative to base path and then data file name */ RelativeToBasePath, /* Sort by path relative to scene file path and then data file name */ RelativeToSceneFilePath }; SceneDataFileInfo(const AString& absoluteDataFilePathAndName, const AString& absoluteBasePath, const AString& absoluteSceneFilePathAndName, const std::vector& sceneIndices); virtual ~SceneDataFileInfo(); SceneDataFileInfo(const SceneDataFileInfo& obj); SceneDataFileInfo& operator=(const SceneDataFileInfo& obj); bool operator<(const SceneDataFileInfo& rhs) const; void addSceneIndex(const int32_t sceneIndex) const; AString getSceneIndicesAsString() const; AString getAbsolutePath() const; AString getAbsolutePathAndFileName() const; AString getDataFileName() const; AString getRelativePathToBasePath() const; AString getRelativePathToSceneFile() const; bool isRemote() const; bool isMissing() const; // ADD_NEW_METHODS_HERE virtual AString toString() const; static void sort(std::vector& sceneDataFileInfo, const SortMode sortMode); static void print(const std::vector& sceneDataFileInfo); private: void copyHelperSceneDataFileInfo(const SceneDataFileInfo& obj); AString m_absolutePath; AString m_dataFileName; AString m_relativePathToBasePath; AString m_relativePathToSceneFile; bool m_remoteFlag = false; bool m_missingFlag = false; mutable std::set m_sceneIndices; // ADD_NEW_MEMBERS_HERE and DON'T FORGET TO UPDATE COPY COPY METHOD }; #ifdef __SCENE_DATA_FILE_INFO_DECLARE__ // #endif // __SCENE_DATA_FILE_INFO_DECLARE__ } // namespace #endif //__SCENE_DATA_FILE_INFO_H__ connectome-workbench-1.4.2/src/Files/SceneFile.cxx000066400000000000000000001330611360521144700220510ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #define __SCENE_FILE_DECLARE__ #include "SceneFile.h" #undef __SCENE_FILE_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "DataFileContentInformation.h" #include "DataFileException.h" #include "DeveloperFlagsEnum.h" #include "FileAdapter.h" #include "FileInformation.h" #include "GiftiMetaData.h" #include "Scene.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneFileSaxReader.h" #include "SceneInfo.h" #include "ScenePathName.h" #include "SceneXmlElements.h" #include "SceneFileXmlStreamReader.h" #include "SceneFileXmlStreamWriter.h" #include "SceneWriterXml.h" #include "SpecFile.h" #include "SystemUtilities.h" #include "WuQMacroGroup.h" #include "XmlSaxParser.h" #include "XmlUtilities.h" #include "XmlWriter.h" using namespace caret; /** * \class caret::SceneFile * \brief Contains scenes that reproduce Workbench state */ /** * Constructor. */ SceneFile::SceneFile() : CaretDataFile(DataFileTypeEnum::SCENE) { m_balsaStudyID = ""; m_balsaStudyTitle = ""; m_balsaCustomBaseDirectory = ""; m_balsaExtractToDirectoryName = ""; m_basePathType = SceneFileBasePathTypeEnum::AUTOMATIC; m_metadata = new GiftiMetaData(); } /** * Destructor. */ SceneFile::~SceneFile() { delete m_metadata; for (std::vector::iterator iter = m_scenes.begin(); iter != m_scenes.end(); iter++) { delete *iter; } m_scenes.clear(); } /** * Clear the contents of this file. */ void SceneFile::clear() { CaretDataFile::clear(); m_metadata->clear(); m_balsaStudyID = ""; m_balsaStudyTitle = ""; m_balsaCustomBaseDirectory = ""; m_balsaExtractToDirectoryName = ""; m_basePathType = SceneFileBasePathTypeEnum::AUTOMATIC; for (std::vector::iterator iter = m_scenes.begin(); iter != m_scenes.end(); iter++) { delete *iter; } m_scenes.clear(); } /** * @return true if the file is empty (no scenes) else false. */ bool SceneFile::isEmpty() const { return m_scenes.empty(); } /** * Add the given scene to the file. The file then * takes ownership of the scene. * * @param scene * Scene that is added. */ void SceneFile::addScene(Scene* scene) { CaretAssert(scene); m_scenes.push_back(scene); setModified(); } /** * Insert a scene above the given scene. The file then * takes ownership of the scene. * * @param newScene * New scene that is inserted. * @param insertAboveThisScene * The new scene is inserted above (before) this scene. */ void SceneFile::insertScene(Scene* newScene, const Scene* insertAboveThisScene) { CaretAssert(newScene); CaretAssert(insertAboveThisScene); std::vector tempSceneVector; bool newSceneInsertedFlag = false; for (std::vector::iterator iter = m_scenes.begin(); iter != m_scenes.end(); iter++) { Scene* scene = *iter; if (scene == insertAboveThisScene) { newSceneInsertedFlag = true; tempSceneVector.push_back(newScene); } tempSceneVector.push_back(scene); } if ( ! newSceneInsertedFlag) { m_scenes.push_back(newScene); CaretLogSevere("Scene insertion did not find \"insert above scene\""); } m_scenes = tempSceneVector; setModified(); } /** * Replace a scene. * @param newScene * New scene * @param sceneThatIsReplacedAndDeleted * Scene that is replaced and delete so DO NOT * reference this scene after calling this method. */ void SceneFile::replaceScene(Scene* newScene, Scene* sceneThatIsReplacedAndDeleted) { CaretAssert(newScene); CaretAssert(sceneThatIsReplacedAndDeleted); const int32_t numScenes = getNumberOfScenes(); for (int32_t i = 0; i < numScenes; i++) { if (m_scenes[i] == sceneThatIsReplacedAndDeleted) { delete m_scenes[i]; m_scenes[i] = newScene; setModified(); return; } } CaretAssertMessage(0, "Replacing scene failed due to scene not found."); CaretLogSevere("Replacing scene failed due to scene not found."); } /** * @return The number of scenes. */ int32_t SceneFile::getNumberOfScenes() const { return m_scenes.size(); } /** * Get the scene at the given index. * @param indx * Index of the scene. * @return * Scene at the given index. */ Scene* SceneFile::getSceneAtIndex(const int32_t indx) const { CaretAssertVectorIndex(m_scenes, indx); return m_scenes[indx]; } /** * Get the index of the given scene. * * @param scene * Scene for which index is requested. * @return * Index of the scene or negative if scene not found. */ int32_t SceneFile::getIndexOfScene(const Scene* scene) const { const int32_t numScenes = getNumberOfScenes(); for (int32_t i = 0; i < numScenes; i++) { if (scene == getSceneAtIndex(i)) { return i; } } return -1; } /** * Get the scene with the given name. * @param sceneName * Name of scene. * @return * Scene with given name or NULL if no scene with * the given name. */ Scene* SceneFile::getSceneWithName(const AString& sceneName) { const int32_t numScenes = getNumberOfScenes(); for (int32_t i = 0; i < numScenes; i++) { Scene* scene = getSceneAtIndex(i); if (scene->getName() == sceneName) { return scene; } } return NULL; } /** * Remove the given scene. * @param scene * Scene that should be removed. */ void SceneFile::removeScene(Scene* scene) { CaretAssert(scene); std::vector::iterator iter = std::find(m_scenes.begin(), m_scenes.end(), scene); if (iter != m_scenes.end()) { m_scenes.erase(iter); delete scene; setModified(); } } /** * Remove the scene at the given index. * @param indx * Index of the scene. */ void SceneFile::removeSceneAtIndex(const int32_t indx) { CaretAssertVectorIndex(m_scenes, indx); Scene* scene = getSceneAtIndex(indx); removeScene(scene); } /** * Remove the scene at the given index, but return its pointer rather than deleting it. * @param index * Index of the scene. */ Scene* SceneFile::releaseScene(const int32_t& index) { CaretAssertVectorIndex(m_scenes, index); Scene* scene = m_scenes[index]; m_scenes.erase(m_scenes.begin() + index); return scene; } /** * Move the scene in the file by the given change in index. * * @param scene * Scene that is moved. * @param indexDelta * Change of index of scene in the file. */ void SceneFile::moveScene(Scene* scene, const int32_t indexDelta) { if (indexDelta == 0) { return; } const int32_t numberOfScenes = getNumberOfScenes(); if (numberOfScenes == 1) { return; } const int32_t sceneIndex = getIndexOfScene(scene); const int32_t newSceneIndex = sceneIndex + indexDelta; if ((sceneIndex >= 0) && (sceneIndex < numberOfScenes)) { if (newSceneIndex < sceneIndex) { if (newSceneIndex >= 0) { /* * Remove scene from its index * insert scene into its new index */ m_scenes.erase(m_scenes.begin() + sceneIndex); m_scenes.insert(m_scenes.begin() + newSceneIndex, scene); setModified(); } } else { CaretAssert(newSceneIndex > sceneIndex); if (newSceneIndex < numberOfScenes) { /* * Innsert scene into its new index * Remove scene from its index */ m_scenes.insert(m_scenes.begin() + newSceneIndex + 1, scene); m_scenes.erase(m_scenes.begin() + sceneIndex); setModified(); } } } } /** * Reorder the scenes given the newly ordered scenes. * Any existing scenes not in the newly ordered scenes are * removed. * * @param orderedScenes * Newly ordered scenes. */ void SceneFile::reorderScenes(std::vector& orderedScenes) { /* * Make copy of pointers to existing scenes */ std::vector oldSceneVector = m_scenes; /* * Replace scenes with newly ordered scenes */ m_scenes = orderedScenes; /* * If an existing scene is not in the newly ordered scenes, * remove it. */ for (std::vector::iterator iter = oldSceneVector.begin(); iter != oldSceneVector.end(); iter++) { Scene* scene = *iter; if (std::find(m_scenes.begin(), m_scenes.end(), scene) == m_scenes.end()) { delete scene; } } setModified(); } int32_t SceneFile::getSceneIndexFromNumberOrName(const AString& numberOrName) { bool ok = false; int32_t ret = numberOrName.toInt(&ok) - 1;//compensate for 1-indexing that command line parsing uses if (ok) { if (ret < 0 || ret >= getNumberOfScenes()) { return -1; } return ret; } else {//DO NOT search by name if the string was parsed as an integer correctly, or some idiot who names their maps as integers will get confused //when getting map "12" out of a file after the file expands to more than 12 elements suddenly does something different const int32_t numScenes = getNumberOfScenes(); for (int32_t i = 0; i < numScenes; i++) { if (numberOrName == getSceneAtIndex(i)->getName()) { return i; } } } return -1; } /** * @return The structure for this file. */ StructureEnum::Enum SceneFile::getStructure() const { return StructureEnum::ALL; } /** * Set the structure for this file. * @param structure * New structure for this file. */ void SceneFile::setStructure(const StructureEnum::Enum /*structure*/) { /* ignore, not a structure related file */ } /** * @return Get access to the file's metadata. */ GiftiMetaData* SceneFile::getFileMetaData() { return m_metadata; } /** * @return Get access to unmodifiable file's metadata. */ const GiftiMetaData* SceneFile::getFileMetaData() const { return m_metadata; } /** * @return The BALSA Study ID. */ AString SceneFile::getBalsaStudyID() const { return m_balsaStudyID; } /** * Set the BALSA Study ID. * * @param balsaStudyID * New value for BALSA Study ID. */ void SceneFile::setBalsaStudyID(const AString& balsaStudyID) { if (balsaStudyID != m_balsaStudyID) { m_balsaStudyID = balsaStudyID; setModified(); } } /** * @return The BALSA Study Title. */ AString SceneFile::getBalsaStudyTitle() const { return m_balsaStudyTitle; } /** * Set the BALSA Study Title. * * @param balsaStudyTitle * New value for BALSA Study Title. */ void SceneFile::setBalsaStudyTitle(const AString& balsaStudyTitle) { if (balsaStudyTitle != m_balsaStudyTitle) { m_balsaStudyTitle = balsaStudyTitle; setModified(); } } /** * @return The Custom Base Directory */ AString SceneFile::getBalsaCustomBaseDirectory() const { return m_balsaCustomBaseDirectory; } /** * Set the Custom Base Directory. * * @param baseDirectory * New value for Base Directory. */ void SceneFile::setBalsaCustomBaseDirectory(const AString& balsaBaseDirectory) { if (balsaBaseDirectory != m_balsaCustomBaseDirectory) { m_balsaCustomBaseDirectory = balsaBaseDirectory; setModified(); } } /** * @return The base path type. */ SceneFileBasePathTypeEnum::Enum SceneFile::getBasePathType() const { return m_basePathType; } /** * Set the base path type. * * @param basePathType * New type for base path. */ void SceneFile::setBasePathType(const SceneFileBasePathTypeEnum::Enum basePathType) { if (basePathType != m_basePathType) { m_basePathType = basePathType; setModified(); } } /** * Set the name of the file. * * @param filename * New name of file */ void SceneFile::setFileName(const AString& filename) { CaretDataFile::setFileName(filename); } /** * Read the scene file. * @param filenameIn * Name of scene file. * @throws DataFileException * If there is an error reading the file. */ void SceneFile::readFile(const AString& filenameIn) { clear(); AString filename = filenameIn; if (DataFile::isFileOnNetwork(filename) == false) { FileInformation specInfo(filename); filename = specInfo.getAbsoluteFilePath(); } checkFileReadability(filename); this->setFileName(filename); /* * Stream reader is newer and supports macro in scene file. * Stream reader is also faster than sax reader. */ const bool useStreamReaderFlag(true); if (useStreamReaderFlag) { try { SceneFileXmlStreamReader streamReader; streamReader.readFile(filename, this); } catch (const DataFileException& e) { DataFileException dfe(filename, e.whatString()); CaretLogThrowing(dfe); throw dfe; } } else { SceneFileSaxReader saxReader(this, filename); std::unique_ptr parser(XmlSaxParser::createXmlParser()); try { parser->parseFile(filename, &saxReader); } catch (const XmlSaxParserException& e) { clear(); this->setFileName(""); int lineNum = e.getLineNumber(); int colNum = e.getColumnNumber(); AString msg = "Parse Error while reading:"; if ((lineNum >= 0) && (colNum >= 0)) { msg += (" line/col (" + AString::number(e.getLineNumber()) + "/" + AString::number(e.getColumnNumber()) + ")"); } msg += (": " + e.whatString()); DataFileException dfe(filenameIn, msg); CaretLogThrowing(dfe); throw dfe; } } this->setFileName(filename); this->clearModified(); } /** * Read the scene file use the old SAX parser * @param filenameIn * Name of scene file. * @throws DataFileException * If there is an error reading the file. */ void SceneFile::readFileSaxReader(const AString& filenameIn) { clear(); AString filename = filenameIn; if (DataFile::isFileOnNetwork(filename) == false) { FileInformation specInfo(filename); filename = specInfo.getAbsoluteFilePath(); } checkFileReadability(filename); this->setFileName(filename); SceneFileSaxReader saxReader(this, filename); std::unique_ptr parser(XmlSaxParser::createXmlParser()); try { parser->parseFile(filename, &saxReader); } catch (const XmlSaxParserException& e) { clear(); this->setFileName(""); int lineNum = e.getLineNumber(); int colNum = e.getColumnNumber(); AString msg = "Parse Error while reading:"; if ((lineNum >= 0) && (colNum >= 0)) { msg += (" line/col (" + AString::number(e.getLineNumber()) + "/" + AString::number(e.getColumnNumber()) + ")"); } msg += (": " + e.whatString()); DataFileException dfe(filenameIn, msg); CaretLogThrowing(dfe); throw dfe; } this->setFileName(filename); this->clearModified(); } /** * Read the scene file using the new Stream parser * @param filenameIn * Name of scene file. * @throws DataFileException * If there is an error reading the file. */ void SceneFile::readFileStreamReader(const AString& filenameIn) { clear(); AString filename = filenameIn; if (DataFile::isFileOnNetwork(filename) == false) { FileInformation specInfo(filename); filename = specInfo.getAbsoluteFilePath(); } checkFileReadability(filename); this->setFileName(filename); try { SceneFileXmlStreamReader streamReader; streamReader.readFile(filename, this); } catch (const DataFileException& e) { DataFileException dfe(filename, e.whatString()); CaretLogThrowing(dfe); throw dfe; } this->setFileName(filename); this->clearModified(); } /** * Write the scene file. * @param filename * Name of scene file. * @throws DataFileException * If there is an error writing the file. */ void SceneFile::writeFile(const AString& filename) { if (!(filename.endsWith(".scene") || filename.endsWith(".wb_scene"))) { CaretLogWarning("scene file '" + filename + "' should be saved ending in .scene"); } checkFileWritability(filename); this->setFileName(filename); try { /* * Stream Writer is newer and supports macros in scene file */ const bool useStreamWriterFlag(true); if (useStreamWriterFlag) { SceneFileXmlStreamWriter xmlStreamWriter; xmlStreamWriter.writeFile(this); } else { writeFileSaxWriter(filename); } this->clearModified(); } catch (const GiftiException& e) { throw DataFileException(e); } catch (const XmlException& e) { throw DataFileException(e); } } /** * Write the scene file using the (not exactly) sax writer * @param filename * Name of scene file. * @throws DataFileException * If there is an error writing the file. */ void SceneFile::writeFileSaxWriter(const AString& filename) { if (!(filename.endsWith(".scene") || filename.endsWith(".wb_scene"))) { CaretLogWarning("scene file '" + filename + "' should be saved ending in .scene"); } for (const auto s : m_scenes) { if ( ! s->getMacroGroup()->isEmpty()) { throw DataFileException("OLD scene writer does not support scene files containing macros. Use stream writer"); } } checkFileWritability(filename); this->setFileName(filename); try { /* * This writes an old file format that does not support macros */ const AString versionString = AString::number(getSceneFileVersionBeforeMacros()); // // Open the file // FileAdapter file; AString errorMessage; QTextStream* textStream = file.openQTextStreamForWritingFile(this->getFileName(), errorMessage); if (textStream == NULL) { throw DataFileException(filename, errorMessage); } // // Create the xml writer // XmlWriter xmlWriter(*textStream); // // Write header info // xmlWriter.writeStartDocument("1.0"); // // Write root element // XmlAttributes attributes; //attributes.addAttribute("xmlns:xsi", // "http://www.w3.org/2001/XMLSchema-instance"); //attributes.addAttribute("xsi:noNamespaceSchemaLocation", // "http://brainvis.wustl.edu/caret6/xml_schemas/GIFTI_Caret.xsd"); attributes.addAttribute(SceneFile::XML_ATTRIBUTE_VERSION, versionString); xmlWriter.writeStartElement(SceneFile::XML_TAG_SCENE_FILE, attributes); // // Write Metadata // if (m_metadata != NULL) { m_metadata->writeAsXML(xmlWriter); } const int32_t numScenes = this->getNumberOfScenes(); /* * Write the scene info directory */ xmlWriter.writeStartElement(SceneFile::XML_TAG_SCENE_INFO_DIRECTORY_TAG); xmlWriter.writeElementCData(SceneXmlElements::SCENE_INFO_BALSA_STUDY_ID_TAG, getBalsaStudyID()); xmlWriter.writeElementCData(SceneXmlElements::SCENE_INFO_BALSA_STUDY_TITLE_TAG, getBalsaStudyTitle()); switch (getBasePathType()) { case SceneFileBasePathTypeEnum::AUTOMATIC: xmlWriter.writeElementCData(SceneXmlElements::SCENE_INFO_BALSA_BASE_DIRECTORY_TAG, ""); break; case SceneFileBasePathTypeEnum::CUSTOM: { /* * Write base path as a path RELATIVE to the scene file * but only when base path type is CUSTOM * Note: we do not use FileInformation::getCanonicalFilePath() * because it returns an empty string if the file DOES NOT exist * and this may occur since the file may be new and has not * been closed. */ if ( ! getBalsaCustomBaseDirectory().isEmpty()) { const AString baseDirAbsPath = FileInformation(getBalsaCustomBaseDirectory()).getAbsoluteFilePath(); const AString sceneFileAbsPath = FileInformation(filename).getAbsoluteFilePath(); ScenePathName basePathName("basePathName", baseDirAbsPath); const AString relativeBasePath = basePathName.getRelativePathToSceneFile(sceneFileAbsPath); //std::cout << "baseDirAbsPath: " << baseDirAbsPath << std::endl; //std::cout << "sceneFileAbsPath: " << sceneFileAbsPath << std::endl; //std::cout << "relativeTempFileName: " << relativeBasePath << std::endl; xmlWriter.writeElementCData(SceneXmlElements::SCENE_INFO_BALSA_BASE_DIRECTORY_TAG, relativeBasePath); } } break; } xmlWriter.writeElementCData(SceneXmlElements::SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY_TAG, getBalsaExtractToDirectoryName()); xmlWriter.writeElementCData(SceneXmlElements::SCENE_INFO_BASE_PATH_TYPE, SceneFileBasePathTypeEnum::toName(getBasePathType())); for (int32_t i = 0; i < numScenes; i++) { m_scenes[i]->getSceneInfo()->writeSceneInfo(xmlWriter, i); } xmlWriter.writeEndElement(); // // Write scenes // SceneWriterXml sceneWriter(xmlWriter, this->getFileName()); for (int32_t i = 0; i < numScenes; i++) { sceneWriter.writeScene(*m_scenes[i], i); } xmlWriter.writeEndElement(); xmlWriter.writeEndDocument(); file.close(); this->clearModified(); } catch (const GiftiException& e) { throw DataFileException(e); } catch (const XmlException& e) { throw DataFileException(e); } } /** * Write the scene file stream writer * @param filename * Name of scene file. * @throws DataFileException * If there is an error writing the file. */ void SceneFile::writeFileStreamWriter(const AString& filename) { if (!(filename.endsWith(".scene") || filename.endsWith(".wb_scene"))) { CaretLogWarning("scene file '" + filename + "' should be saved ending in .scene"); } checkFileWritability(filename); this->setFileName(filename); try { SceneFileXmlStreamWriter xmlStreamWriter; xmlStreamWriter.writeFile(this); this->clearModified(); } catch (const GiftiException& e) { throw DataFileException(e); } catch (const XmlException& e) { throw DataFileException(e); } } /** * Add information about the file to the data file information. * * @param dataFileInformation * Consolidates information about a data file. */ void SceneFile::addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) { CaretDataFile::addToDataFileContentInformation(dataFileInformation); const int32_t numScenes = getNumberOfScenes(); if (numScenes > 0) { AString sceneNamesText = "Scenes:"; for (int32_t i = 0; i < numScenes; i++) { const Scene* scene = getSceneAtIndex(i); sceneNamesText.appendWithNewLine("#" + AString::number(i + 1) + " " + scene->getName()); if (dataFileInformation.isOptionFlag(DataFileContentInformation::OPTION_SHOW_MAP_INFORMATION)) { sceneNamesText += ":"; const SceneAttributes* myAttrs = scene->getAttributes(); const SceneClass* guiMgrClass = scene->getClassWithName("guiManager"); if (guiMgrClass == NULL) { sceneNamesText.appendWithNewLine("missing guiManager class"); continue; } const SceneClass* sessMgrClass = guiMgrClass->getClass("m_sessionManager"); if (sessMgrClass == NULL) { sceneNamesText.appendWithNewLine("missing m_sessionManager class"); continue; } const SceneClassArray* brainArray = sessMgrClass->getClassArray("m_brains"); if (brainArray == NULL) { sceneNamesText.appendWithNewLine("missing m_brains class array"); continue; } const int numBrainClasses = brainArray->getNumberOfArrayElements(); for (int j = 0; j < numBrainClasses; ++j) { const SceneClass* brainClass = brainArray->getClassAtIndex(j); const SceneClass* specClass = brainClass->getClass("specFile"); if (specClass == NULL) { sceneNamesText.appendWithNewLine("missing specFile class in m_brains element " + AString::number(j)); continue; } SpecFile tempSpec; tempSpec.restoreFromScene(myAttrs, specClass); std::vector tempNames = tempSpec.getAllDataFileNamesSelectedForLoading(); int numNames = (int)tempNames.size(); for (int k = 0; k < numNames; ++k) { sceneNamesText.appendWithNewLine(" " + tempNames[k]); } } } } dataFileInformation.addText(sceneNamesText); } } /** * @return Extract to directory name for zip file */ AString SceneFile::getBalsaExtractToDirectoryName() const { return m_balsaExtractToDirectoryName; } /** * Set Extract to directory name for zip file * * @param extractToDirectoryName * New value for Extract to directory name for zip file */ void SceneFile::setBalsaExtractToDirectoryName(const AString& extractToDirectoryName) { if (extractToDirectoryName != m_balsaExtractToDirectoryName) { setModified(); m_balsaExtractToDirectoryName = extractToDirectoryName; } } /** * Find the base directory that is a directory that is parent to all loaded data files * and also including the scene file. * * @param baseDirectoryOut * Output containing the base directory * @param missingFileNamesOut * Will contain data files that are in scenes but do not exist. * @param errorMessageOut * Error message if finding base directory fails * @return * True if the base directory is valid, else false. */ bool SceneFile::findBaseDirectoryForDataFiles(AString& baseDirectoryOut, std::vector& missingFileNamesOut, AString& errorMessageOut) const { baseDirectoryOut.clear(); missingFileNamesOut.clear(); errorMessageOut.clear(); const AString directorySeparator("/"); std::vector allFileNames; std::set filesFromScenes = getAllDataFileNamesFromAllScenes(); for (const auto& nameInfo : filesFromScenes) { allFileNames.push_back(nameInfo.m_dataFileName); } allFileNames.push_back(getFileName()); /* * Find a unique set of directory names used by the data files and * also verify that all files exist. */ std::set directoryNamesUniqueSet; std::set missingFileNames; for (auto name : allFileNames) { if (DataFile::isFileOnNetwork(name)) { /* assume file on network are valid */ } else { FileInformation fileInfo(name); if (fileInfo.exists()) { AString dirName = fileInfo.getAbsolutePath().trimmed(); if ( ! dirName.isEmpty()) { /* * QDir::cleanPath() removes multiple separators and resolves "." or ".." * QDir::fromNativeSeparators() ensures "/" is used for the directory separator. */ dirName = QDir::cleanPath(dirName); dirName = QDir::fromNativeSeparators(dirName); if ( ! dirName.isEmpty()) { directoryNamesUniqueSet.insert(dirName); } } } else { missingFileNames.insert(name); } } } const FileInformation fileInfo(getFileName()); const AString sceneFilePath = fileInfo.getAbsolutePath().trimmed(); missingFileNamesOut.insert(missingFileNamesOut.end(), missingFileNames.begin(), missingFileNames.end()); const int32_t numDirs = static_cast(directoryNamesUniqueSet.size()); if (numDirs <= 0) { /* * if no valid files in scene, user path of scene file. */ baseDirectoryOut = sceneFilePath; return true; } /* * Compare the first directory with all other directories * to find longest common directory path. * Each directory is split into its path components and they * are compared. */ bool firstFlag = true; std::vector longestPathMatch; for (const auto dirName : directoryNamesUniqueSet) { if (firstFlag) { firstFlag = false; longestPathMatch = AString::stringListToVector(dirName.split(directorySeparator)); } else { const std::vector otherPath = AString::stringListToVector(dirName.split(directorySeparator)); const int32_t matchCount = AString::matchingCount(longestPathMatch, otherPath); longestPathMatch.resize(matchCount); } } baseDirectoryOut = sceneFilePath; if ( ! longestPathMatch.empty()) { /* * Assemble the path components into a directory. */ baseDirectoryOut = AString::join(longestPathMatch, directorySeparator); } /* * If no "longest path", files are on multiple disks */ if (baseDirectoryOut.isEmpty()) { if (SystemUtilities::isWindowsOperatingSystem()) { /* * On Windows, there is no "root directory" */ baseDirectoryOut = ""; errorMessageOut = ("Files appear to be on different disks. On the Windows Operating System, " "there is no directory that is parent to the disks. Files will need to " "be moved so that they are on one disk"); return false; } else { /* * On Unix, user root directory */ baseDirectoryOut = directorySeparator; } } return true; } /** * @return The base directory for all data files and all of * the base directorys ancestors (parent directory * up to root directory). * * @param maximumAncestorCount * Maximum number of ancestor directories for output */ std::vector SceneFile::getBaseDirectoryHierarchyForDataFiles(const int32_t maximumAncestorCount) { std::vector names; AString baseDirectoryName; std::vector missingFileNames; AString errorMessage; if (findBaseDirectoryForDataFiles(baseDirectoryName, missingFileNames, errorMessage)) { QDir dir(baseDirectoryName); for (int32_t i = 0; i < maximumAncestorCount; i++) { names.push_back(dir.absolutePath()); if (dir.isRoot()) { break; } else { if ( ! dir.cdUp()) { break; } } } } return names; } /** * @return A vector containing the names of all data files from all scenes. */ std::set SceneFile::getAllDataFileNamesFromAllScenes() const { const bool includeSpecFileFlag = false; std::set fileInfoOut; /** * Find all 'path name' elements from ALL scenes */ const int32_t numScenes = static_cast(m_scenes.size()); for (int32_t sceneIndex = 0; sceneIndex < numScenes; sceneIndex++) { CaretAssertVectorIndex(m_scenes, sceneIndex); const Scene* scene = m_scenes[sceneIndex]; CaretAssert(scene); std::vector children = scene->getDescendants(); for (SceneObject* sceneObject : children) { CaretAssert(sceneObject); if (sceneObject->getDataType() == SceneObjectDataTypeEnum::SCENE_PATH_NAME) { const ScenePathName* scenePathName = dynamic_cast(sceneObject); /* * Will be NULL for 'path name arrays' which we ignore */ if (scenePathName != NULL) { /* * files in spec file are named "fileName" in the scene * specFile is named "specFileName" * and these names are unique to name of files in the spec file */ bool useNameFlag = false; if (sceneObject->getName() == "fileName") { useNameFlag = true; } else if (sceneObject->getName() == "specFileName") { useNameFlag = includeSpecFileFlag; } if (useNameFlag) { AString pathName = scenePathName->stringValue().trimmed(); if ( ! pathName.isEmpty()) { bool validExtensionFlag = false; const DataFileTypeEnum::Enum dataFileType = DataFileTypeEnum::fromFileExtension(pathName, &validExtensionFlag); bool validDiskFileFlag = true; if (validExtensionFlag) { switch (dataFileType) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: validDiskFileFlag = false; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: break; case DataFileTypeEnum::METRIC: break; case DataFileTypeEnum::METRIC_DYNAMIC: validDiskFileFlag = false; break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: validDiskFileFlag = false; break; case DataFileTypeEnum::UNKNOWN: validDiskFileFlag = false; break; } } if (validDiskFileFlag) { FileInformation fileInfo(pathName); const QString absPathName = fileInfo.getAbsoluteFilePath(); if ( ! absPathName.isEmpty()) { pathName = absPathName; } /* * Test to see if this file is already in the output file info */ bool foundFlag = false; for (auto& dfi : fileInfoOut) { if (dfi.m_dataFileName == pathName) { dfi.addSceneIndex(sceneIndex); foundFlag = true; break; } } if ( ! foundFlag) { fileInfoOut.insert(FileAndSceneIndicesInfo(pathName, sceneIndex)); } } } } } } } } return fileInfoOut; } /** * @return File info for all files in the scene file. */ std::vector SceneFile::getAllDataFileInfoFromAllScenes() const { const std::set allNamesAndIndices = getAllDataFileNamesFromAllScenes(); AString basePath; AString errorMessage; std::vector missingFiles; const bool validFlag = findBaseDirectoryForDataFiles(basePath, missingFiles, errorMessage); if ( ! validFlag) { CaretLogSevere("Failed to find the base path for scene file: " + getFileName()); } std::vector fileInfoOut; for (const auto nameAndIndices : allNamesAndIndices) { fileInfoOut.emplace_back(nameAndIndices.m_dataFileName, basePath, getFileName(), nameAndIndices.m_sceneIndices); } return fileInfoOut; } /** * @return Default name for a ZIP file containing the scene file and its data files. */ AString SceneFile::getDefaultZipFileName() const { return FileInformation::replaceExtension(getFileName(), ".zip"); } /** * @return The default extract to directory name (end of default base directory) */ AString SceneFile::getDefaultExtractToDirectoryName() const { AString directoryName; AString baseDirectoryName; std::vector missingFileNames; AString errorMessage; if (findBaseDirectoryForDataFiles(baseDirectoryName, missingFileNames, errorMessage)) { QDir dir(baseDirectoryName); directoryName = dir.dirName(); } if (directoryName.isEmpty()) { QDir dir(SystemUtilities::systemCurrentDirectory()); directoryName = dir.dirName(); } return directoryName; } /** * @return True if this scene is modified. */ bool SceneFile::isModified() const { if (CaretDataFile::isModified()) { return true; } for (const auto scene : m_scenes) { if (scene->isModified()) { return true; } } return false; } /** * Clear the modified status of this scene. */ void SceneFile::clearModified() { CaretDataFile::clearModified(); for (auto scene : m_scenes) { scene->clearModified(); } } /** * @return The version number to use when writing * an instance of a scene. This number returned * may version depending upon the content of the scene * and may allow older versions of wb_view to read * the scene file when it does not contain new stuff. */ int32_t SceneFile::getSceneFileVersionForWriting() const { int32_t version = s_sceneFileVersionBeforeMacros; for (const auto s : m_scenes) { if ( ! s->getMacroGroup()->isEmpty()) { version = s_sceneFileVersionContainingMacros; break; } } return version; } /** * @return The maximum scene file version supported * by the scene file. */ int32_t SceneFile::getMaxiumSupportedSceneFileVersion() { return s_sceneFileVersionContainingMacros; } /** * @return The scene file version before macros were added. */ int32_t SceneFile::getSceneFileVersionBeforeMacros() { return s_sceneFileVersionBeforeMacros; } connectome-workbench-1.4.2/src/Files/SceneFile.h000066400000000000000000000167561360521144700215110ustar00rootroot00000000000000#ifndef __SCENE_FILE__H_ #define __SCENE_FILE__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretDataFile.h" #include "SceneDataFileInfo.h" #include "SceneFileBasePathTypeEnum.h" namespace caret { class Scene; class SceneFile : public CaretDataFile { public: SceneFile(); virtual ~SceneFile(); private: SceneFile(const SceneFile&); SceneFile& operator=(const SceneFile&); public: virtual void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation); void clear(); virtual void setFileName(const AString& filename) override; void readFile(const AString& filename); void readFileSaxReader(const AString& filename); void readFileStreamReader(const AString& filename); void writeFile(const AString& filename); void writeFileSaxWriter(const AString& filename); void writeFileStreamWriter(const AString& filename); bool isEmpty() const; void addScene(Scene* scene); int32_t getIndexOfScene(const Scene* scene) const; void insertScene(Scene* newScene, const Scene* insertAboveThisScene); void replaceScene(Scene* newScene, Scene* sceneThatIsReplacedAndDeleted); int32_t getNumberOfScenes() const; Scene* getSceneAtIndex(const int32_t indx) const; Scene* getSceneWithName(const AString& sceneName); void moveScene(Scene* scene, const int32_t indexDelta); void removeScene(Scene* scene); void removeSceneAtIndex(const int32_t indx); StructureEnum::Enum getStructure() const; void setStructure(const StructureEnum::Enum structure); GiftiMetaData* getFileMetaData(); const GiftiMetaData* getFileMetaData() const; AString getBalsaStudyID() const; void setBalsaStudyID(const AString& balsaStudyID); AString getBalsaStudyTitle() const; void setBalsaStudyTitle(const AString& balsaStudyTitle); SceneFileBasePathTypeEnum::Enum getBasePathType() const; void setBasePathType(const SceneFileBasePathTypeEnum::Enum basePathType); AString getBalsaCustomBaseDirectory() const; void setBalsaCustomBaseDirectory(const AString& balsaBaseDirectory); bool findBaseDirectoryForDataFiles(AString& baseDirectoryOut, std::vector& missingFileNamesOut, AString& errorMessageOut) const; std::vector getBaseDirectoryHierarchyForDataFiles(const int32_t maximumAncestorCount = 25); class FileAndSceneIndicesInfo { public: FileAndSceneIndicesInfo(const AString& dataFileName, const int32_t sceneIndex) : m_dataFileName(dataFileName) { m_sceneIndices.push_back(sceneIndex + 1); } bool operator<(const FileAndSceneIndicesInfo& rhs) const { return m_dataFileName < rhs.m_dataFileName; } void addSceneIndex(const int32_t sceneIndex) const { m_sceneIndices.push_back(sceneIndex + 1); } AString getSceneIndices() const { return AString::fromNumbers(m_sceneIndices, ","); } const AString m_dataFileName; mutable std::vector m_sceneIndices; }; std::set getAllDataFileNamesFromAllScenes() const; std::vector getAllDataFileInfoFromAllScenes() const; void reorderScenes(std::vector& orderedScenes); int32_t getSceneIndexFromNumberOrName(const AString& numberOrName); Scene* releaseScene(const int32_t& index); AString getDefaultZipFileName() const; AString getBalsaExtractToDirectoryName() const; void setBalsaExtractToDirectoryName(const AString& balsaExtractToDirectoryName); AString getDefaultExtractToDirectoryName() const; virtual bool isModified() const override; virtual void clearModified() override; // ADD_NEW_METHODS_HERE int32_t getSceneFileVersionForWriting() const; static int32_t getSceneFileVersionBeforeMacros(); static int32_t getMaxiumSupportedSceneFileVersion(); /** XML Tag for scene file */ static const AString XML_TAG_SCENE_FILE; /** * XML Tag for Scene Info Directory element. */ static const AString XML_TAG_SCENE_INFO_DIRECTORY_TAG; /** XML Tag for Version attribute */ static const AString XML_ATTRIBUTE_VERSION; private: /** the scenes*/ std::vector m_scenes; /** the metadata */ GiftiMetaData* m_metadata; /** the BALSA Study ID */ AString m_balsaStudyID; /** the BALSA Study Title */ AString m_balsaStudyTitle; /** the Base Path Type */ SceneFileBasePathTypeEnum::Enum m_basePathType; /** the Custom Base Directory */ AString m_balsaCustomBaseDirectory; /** The "extract to" directory name */ AString m_balsaExtractToDirectoryName; // ADD_NEW_MEMBERS_HERE /** Version of this SceneFile before addition of macros */ static const int32_t s_sceneFileVersionBeforeMacros; /** Version of this SceneFile containing macros */ static const int32_t s_sceneFileVersionContainingMacros; }; #ifdef __SCENE_FILE_DECLARE__ const AString SceneFile::XML_TAG_SCENE_FILE = "SceneFile"; const AString SceneFile::XML_ATTRIBUTE_VERSION = "Version"; const AString SceneFile::XML_TAG_SCENE_INFO_DIRECTORY_TAG = "SceneInfoDirectory"; /* * NOTE: If these scene file versions change, getSupportedSceneFileVersion() * will need to be updated with the maximum scene file version that * can be read */ const int32_t SceneFile::s_sceneFileVersionBeforeMacros = 3; const int32_t SceneFile::s_sceneFileVersionContainingMacros = 4; #endif // __SCENE_FILE_DECLARE__ } // namespace #endif //__SCENE_FILE__H_ connectome-workbench-1.4.2/src/Files/SceneFileSaxReader.cxx000066400000000000000000000402531360521144700236500ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretAssert.h" #include "CaretLogger.h" #include "FileInformation.h" #include "GiftiMetaDataSaxReader.h" #include "GiftiXmlElements.h" #include "Scene.h" #include "SceneFile.h" #include "SceneFileSaxReader.h" #include "SceneInfo.h" #include "SceneInfoSaxReader.h" #include "ScenePathName.h" #include "SceneXmlElements.h" #include "XmlAttributes.h" #include "XmlException.h" #include "XmlUtilities.h" using namespace caret; /** * \class caret::SceneFileSaxReader * \brief Reads a scene file using a SAX XML Parser. */ /** * constructor. */ SceneFileSaxReader::SceneFileSaxReader(SceneFile* sceneFile, const AString& sceneFileName) { CaretAssert(sceneFile); m_sceneFile = sceneFile; m_sceneFileName = sceneFileName; m_state = STATE_NONE; m_stateStack.push(m_state); m_elementText = ""; m_metaDataSaxReader = NULL; m_sceneSaxReader = NULL; m_sceneInfoSaxReader = NULL; m_scene = NULL; m_baseBathTypeWasFoundFlag = false; } /** * destructor. */ SceneFileSaxReader::~SceneFileSaxReader() { /* * If reading fails, allocated items need to be deleted. */ if (m_metaDataSaxReader != NULL) { delete m_metaDataSaxReader; } if (m_sceneSaxReader != NULL) { delete m_sceneSaxReader; } if (m_sceneInfoSaxReader != NULL) { delete m_sceneInfoSaxReader; } if (m_scene != NULL) { delete m_scene; } } /** * start an element. */ void SceneFileSaxReader::startElement(const AString& namespaceURI, const AString& localName, const AString& qName, const XmlAttributes& attributes) { const STATE previousState = m_state; switch (m_state) { case STATE_NONE: if (qName == SceneFile::XML_TAG_SCENE_FILE) { m_state = STATE_SCENE_FILE; // // Check version of file being read // const float versionFloat = attributes.getValueAsFloat(SceneFile::XML_ATTRIBUTE_VERSION); const int32_t version = static_cast(versionFloat); if (version > SceneFile::getSceneFileVersionBeforeMacros()) { AString msg = XmlUtilities::createInvalidVersionMessage(SceneFile::getSceneFileVersionBeforeMacros(), version); XmlSaxParserException e(msg); CaretLogThrowing(e); throw e; } } else { const AString msg = XmlUtilities::createInvalidRootElementMessage(SceneFile::XML_TAG_SCENE_FILE, qName); XmlSaxParserException e(msg); CaretLogThrowing(e); throw e; } break; case STATE_SCENE_INFO_DIRECTORY: if (qName == SceneXmlElements::SCENE_INFO_TAG) { m_state = STATE_SCENE_INFO; m_sceneInfoIndex = attributes.getValueAsIntRequired(SceneXmlElements::SCENE_INFO_INDEX_ATTRIBUTE); m_sceneInfo = new SceneInfo(); m_sceneInfoSaxReader = new SceneInfoSaxReader(m_sceneFile->getFileName(), m_sceneInfo); m_sceneInfoSaxReader->startElement(namespaceURI, localName, qName, attributes); } else if (qName == SceneXmlElements::SCENE_INFO_BALSA_STUDY_ID_TAG) { m_state = STATE_SCENE_INFO_BALSA_STUDY_ID; } else if (qName == SceneXmlElements::SCENE_INFO_BALSA_STUDY_TITLE_TAG) { m_state = STATE_SCENE_INFO_BALSA_STUDY_TITLE; } else if ((qName == SceneXmlElements::SCENE_INFO_BALSA_BASE_DIRECTORY_TAG) || (qName == SceneXmlElements::SCENE_INFO_BALSA_BASE_DIRECTORY_TAG_OLD)) { m_state = STATE_SCENE_INFO_BALSA_BASE_DIRECTORY; } else if (qName == SceneXmlElements::SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY_TAG) { m_state = STATE_SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY; } else if (qName == SceneXmlElements::SCENE_INFO_BASE_PATH_TYPE) { m_state = STATE_SCENE_INFO_BASE_PATH_TYPE; } else { const AString msg = XmlUtilities::createInvalidChildElementMessage(SceneXmlElements::SCENE_INFO_TAG, qName); XmlSaxParserException e(msg); warning(e); // CaretLogThrowing(e); // throw e; } break; case STATE_SCENE_INFO_BALSA_STUDY_ID: break; case STATE_SCENE_INFO_BALSA_STUDY_TITLE: break; case STATE_SCENE_INFO_BALSA_BASE_DIRECTORY: break; case STATE_SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY: break; case STATE_SCENE_INFO_BASE_PATH_TYPE: break; case STATE_SCENE_INFO: m_sceneInfoSaxReader->startElement(namespaceURI, localName, qName, attributes); break; case STATE_SCENE: m_sceneSaxReader->startElement(namespaceURI, localName, qName, attributes); break; case STATE_SCENE_FILE: if (qName == GiftiXmlElements::TAG_METADATA) { m_state = STATE_METADATA; m_metaDataSaxReader = new GiftiMetaDataSaxReader(m_sceneFile->getFileMetaData()); m_metaDataSaxReader->startElement(namespaceURI, localName, qName, attributes); } else if (qName == SceneFile::XML_TAG_SCENE_INFO_DIRECTORY_TAG) { m_state = STATE_SCENE_INFO_DIRECTORY; break; } else if (qName == SceneXmlElements::SCENE_TAG) { m_state = STATE_SCENE; const AString sceneTypeName = attributes.getValue(SceneXmlElements::SCENE_TYPE_ATTRIBUTE); bool validName = false; const SceneTypeEnum::Enum sceneType = SceneTypeEnum::fromName(sceneTypeName, &validName); if (validName == false) { const AString msg = XmlUtilities::createInvalidAttributeMessage(SceneXmlElements::SCENE_TAG, SceneXmlElements::SCENE_TYPE_ATTRIBUTE, sceneTypeName); XmlSaxParserException e(msg); CaretLogThrowing(e); throw e; } m_scene = new Scene(sceneType); m_sceneSaxReader = new SceneSaxReader(m_sceneFile->getFileName(), m_scene); m_sceneSaxReader->startElement(namespaceURI, localName, qName, attributes); } else { const AString msg = XmlUtilities::createInvalidChildElementMessage(SceneXmlElements::SCENE_TAG, qName); XmlSaxParserException e(msg); warning(e); // CaretLogThrowing(e); // throw e; } break; case STATE_METADATA: m_metaDataSaxReader->startElement(namespaceURI, localName, qName, attributes); break; } // // Save previous state // m_stateStack.push(previousState); m_elementText = ""; } /** * end an element. */ void SceneFileSaxReader::endElement(const AString& namespaceURI, const AString& localName, const AString& qName) { switch (m_state) { case STATE_NONE: break; case STATE_SCENE: CaretAssert(m_scene); CaretAssert(m_sceneSaxReader); m_sceneSaxReader->endElement(namespaceURI, localName, qName); if (qName == SceneXmlElements::SCENE_TAG) { m_sceneFile->addScene(m_scene); m_scene = NULL; // do not delete since added to border file delete m_sceneSaxReader; m_sceneSaxReader = NULL; } break; case STATE_SCENE_INFO_DIRECTORY: break; case STATE_SCENE_INFO_BALSA_STUDY_ID: m_sceneFile->setBalsaStudyID(m_elementText); break; case STATE_SCENE_INFO_BALSA_STUDY_TITLE: m_sceneFile->setBalsaStudyTitle(m_elementText); break; case STATE_SCENE_INFO_BALSA_BASE_DIRECTORY: m_sceneFile->setBalsaCustomBaseDirectory(m_elementText); break; case STATE_SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY: m_sceneFile->setBalsaExtractToDirectoryName(m_elementText); break; case STATE_SCENE_INFO_BASE_PATH_TYPE: { SceneFileBasePathTypeEnum::Enum basePathType = SceneFileBasePathTypeEnum::AUTOMATIC; bool validFlag = false; basePathType = SceneFileBasePathTypeEnum::fromName(m_elementText, &validFlag); if (validFlag) { m_baseBathTypeWasFoundFlag = true; } else { basePathType = SceneFileBasePathTypeEnum::AUTOMATIC; AString msg("Invalid BasePathType name: " + m_elementText); XmlSaxParserException e(msg); warning(e); } m_sceneFile->setBasePathType(basePathType); } break; case STATE_SCENE_INFO: CaretAssert(m_sceneInfo); CaretAssert(m_sceneInfoSaxReader); m_sceneInfoSaxReader->endElement(namespaceURI, localName, qName); if (qName == SceneXmlElements::SCENE_INFO_TAG) { m_sceneInfoMap.insert(std::make_pair(m_sceneInfoIndex, m_sceneInfo)); delete m_sceneInfoSaxReader; m_sceneInfoSaxReader = NULL; } break; case STATE_SCENE_FILE: { for (std::map::iterator iter = m_sceneInfoMap.begin(); iter != m_sceneInfoMap.end(); iter++) { const int32_t sceneIndex = iter->first; SceneInfo* sceneInfo = iter->second; CaretAssert(sceneInfo); if ((sceneIndex >= 0) && (sceneIndex < m_sceneFile->getNumberOfScenes())) { Scene* scene = m_sceneFile->getSceneAtIndex(sceneIndex); scene->setSceneInfo(sceneInfo); } else { const AString msg = ("SceneInfo has bad index=" + AString::number(sceneIndex) + " in file " + m_sceneFile->getFileName()); CaretAssertMessage(0, msg); CaretLogSevere(msg); } } if (m_baseBathTypeWasFoundFlag) { switch (m_sceneFile->getBasePathType()) { case SceneFileBasePathTypeEnum::AUTOMATIC: m_sceneFile->setBalsaCustomBaseDirectory(""); break; case SceneFileBasePathTypeEnum::CUSTOM: { AString basePath = m_sceneFile->getBalsaCustomBaseDirectory(); if ( ! basePath.isEmpty()) { FileInformation basePathInfo(basePath); if (basePathInfo.isRelative()) { // FileInformation tempBaseFile(basePath, // "temp.txt"); ScenePathName basePathName("basePathName", ""); basePathName.setValueToAbsolutePath(m_sceneFileName, (basePath)); // + "/temp.txt")); basePath = basePathName.stringValue(); } } m_sceneFile->setBalsaCustomBaseDirectory(basePath); } break; } } else { /* * Base path type was added by WB- in Oct 2017. * If it is not found, the file was created prior to adding the * base path type. If there is no base path, the go ahead and * use AUTOMATIC mode. If there is a base path assume it is valid * and use CUSTOM mode. */ if (m_sceneFile->getBalsaCustomBaseDirectory().isEmpty()) { m_sceneFile->setBasePathType(SceneFileBasePathTypeEnum::AUTOMATIC); } else { m_sceneFile->setBasePathType(SceneFileBasePathTypeEnum::CUSTOM); } } } break; case STATE_METADATA: CaretAssert(m_metaDataSaxReader); m_metaDataSaxReader->endElement(namespaceURI, localName, qName); if (qName == GiftiXmlElements::TAG_METADATA) { delete m_metaDataSaxReader; m_metaDataSaxReader = NULL; } break; } // // Clear out for new elements // m_elementText = ""; // // Go to previous state // if (m_stateStack.empty()) { throw XmlSaxParserException("State stack is empty while reading XML NiftDataFile."); } m_state = m_stateStack.top(); m_stateStack.pop(); } /** * get characters in an element. */ void SceneFileSaxReader::characters(const char* ch) { if (m_metaDataSaxReader != NULL) { m_metaDataSaxReader->characters(ch); } else if (m_sceneSaxReader != NULL) { m_sceneSaxReader->characters(ch); } else if (m_sceneInfoSaxReader != NULL) { m_sceneInfoSaxReader->characters(ch); } else { m_elementText += ch; } } /** * a fatal error occurs. */ void SceneFileSaxReader::fatalError(const XmlSaxParserException& e) { /* std::ostringstream str; str << "Fatal Error at line number: " << e.getLineNumber() << "\n" << "Column number: " << e.getColumnNumber() << "\n" << "Message: " << e.whatString(); if (errorMessage.isEmpty() == false) { str << "\n" << errorMessage; } errorMessage = str.str(); */ // // Stop parsing // throw e; } // a warning occurs void SceneFileSaxReader::warning(const XmlSaxParserException& e) { CaretLogWarning("XML Parser Warning: " + e.whatString()); } // an error occurs void SceneFileSaxReader::error(const XmlSaxParserException& e) { CaretLogSevere("XML Parser Error: " + e.whatString()); throw e; } void SceneFileSaxReader::startDocument() { } void SceneFileSaxReader::endDocument() { } connectome-workbench-1.4.2/src/Files/SceneFileSaxReader.h000066400000000000000000000106271360521144700232770ustar00rootroot00000000000000 #ifndef __SCENE_FILE_SAX_READER_H__ #define __SCENE_FILE_SAX_READER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "AString.h" #include "SceneSaxReader.h" #include "XmlSaxParserException.h" #include "XmlSaxParserHandlerInterface.h" namespace caret { class Scene; class SceneFile; class SceneInfo; class SceneInfoSaxReader; class GiftiMetaDataSaxReader; class XmlAttributes; class XmlException; class SceneFileSaxReader : public CaretObject, public XmlSaxParserHandlerInterface { public: SceneFileSaxReader(SceneFile* sceneFile, const AString& sceneFileName); virtual ~SceneFileSaxReader(); void startElement(const AString& namespaceURI, const AString& localName, const AString& qName, const XmlAttributes& attributes); void endElement(const AString& namspaceURI, const AString& localName, const AString& qName); void characters(const char* ch); void fatalError(const XmlSaxParserException& e); void warning(const XmlSaxParserException& e); void error(const XmlSaxParserException& e); void startDocument(); void endDocument(); protected: /// file reading states enum STATE { /// no state STATE_NONE, /// processing SceneFile tag STATE_SCENE_FILE, /// processing MetaData tag STATE_METADATA, /// processing SceneInfoDirectory tag STATE_SCENE_INFO_DIRECTORY, /// processing scene info Balsa Study ID tag STATE_SCENE_INFO_BALSA_STUDY_ID, /// processing scene info Balsa Study Title tag STATE_SCENE_INFO_BALSA_STUDY_TITLE, /// processing scene info Base Directory tag STATE_SCENE_INFO_BALSA_BASE_DIRECTORY, /// processing scene info Balsa Extract to Directory STATE_SCENE_INFO_BALSA_EXTRACT_TO_DIRECTORY, /// processing base path type STATE_SCENE_INFO_BASE_PATH_TYPE, /// processing SceneInfo tag STATE_SCENE_INFO, /// processing Scene tag STATE_SCENE }; /// file reading state STATE m_state; /// the state stack used when reading a file std::stack m_stateStack; /// the error message AString m_errorMessage; /// scene file that is being read SceneFile* m_sceneFile; /// scene that is being read Scene* m_scene; /// name of scene file being read AString m_sceneFileName; /// scene info that is being read SceneInfo* m_sceneInfo; /// index attribute of scene info being read int32_t m_sceneInfoIndex; /// element text AString m_elementText; /// GIFTI meta data sax reader GiftiMetaDataSaxReader* m_metaDataSaxReader; /// Scene sax reader SceneSaxReader* m_sceneSaxReader; /// Scene info sax reader SceneInfoSaxReader* m_sceneInfoSaxReader; /// map that stores scene info by index std::map m_sceneInfoMap; bool m_baseBathTypeWasFoundFlag = false; }; } // namespace #endif // __SCENE_FILE_SAX_READER_H__ connectome-workbench-1.4.2/src/Files/SceneFileXmlStreamBase.cxx000066400000000000000000000027741360521144700245070ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SCENE_FILE_XML_STREAM_BASE_DECLARE__ #include "SceneFileXmlStreamBase.h" #undef __SCENE_FILE_XML_STREAM_BASE_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::SceneFileXmlStreamBase * \brief Base class for Scene File XML Stream Reader and Writer * \ingroup Files */ /** * Constructor. */ SceneFileXmlStreamBase::SceneFileXmlStreamBase() : CaretObject() { } /** * Destructor. */ SceneFileXmlStreamBase::~SceneFileXmlStreamBase() { } /** * Get a description of this object's content. * @return String describing this object's content. */ AString SceneFileXmlStreamBase::toString() const { return "SceneFileXmlStreamBase"; } connectome-workbench-1.4.2/src/Files/SceneFileXmlStreamBase.h000066400000000000000000000057001360521144700241240ustar00rootroot00000000000000#ifndef __SCENE_FILE_XML_STREAM_BASE_H__ #define __SCENE_FILE_XML_STREAM_BASE_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" namespace caret { class SceneFileXmlStreamBase : public CaretObject { public: SceneFileXmlStreamBase(); virtual ~SceneFileXmlStreamBase(); SceneFileXmlStreamBase(const SceneFileXmlStreamBase&) = delete; SceneFileXmlStreamBase& operator=(const SceneFileXmlStreamBase&) = delete; static const QString ELEMENT_SCENE_FILE; static const QString ATTRIBUTE_SCENE_FILE_VERSION; static const QString ELEMENT_SCENE_FILE_INFO_DIRECTORY; static const QString ELEMENT_SCENE_FILE_BALSA_STUDY_ID; static const QString ELEMENT_SCENE_FILE_BALSA_STUDY_TITLE; static const QString ELEMENT_SCENE_FILE_BALSA_BASE_DIRECTORY; static const QString ELEMENT_SCENE_FILE_BALSA_EXTRACT_TO_DIRECTORY; static const QString ELEMENT_SCENE_FILE_BALSA_BASE_PATH_TYPE; // ADD_NEW_METHODS_HERE virtual AString toString() const; private: // ADD_NEW_MEMBERS_HERE }; #ifdef __SCENE_FILE_XML_STREAM_BASE_DECLARE__ const QString SceneFileXmlStreamBase::ELEMENT_SCENE_FILE = "SceneFile"; const QString SceneFileXmlStreamBase::ATTRIBUTE_SCENE_FILE_VERSION = "Version"; const QString SceneFileXmlStreamBase::ELEMENT_SCENE_FILE_INFO_DIRECTORY = "SceneInfoDirectory"; const QString SceneFileXmlStreamBase::ELEMENT_SCENE_FILE_BALSA_STUDY_ID = "BalsaStudyID"; const QString SceneFileXmlStreamBase::ELEMENT_SCENE_FILE_BALSA_STUDY_TITLE = "BalsaStudyTitle"; const QString SceneFileXmlStreamBase::ELEMENT_SCENE_FILE_BALSA_BASE_DIRECTORY = "BalsaBaseDirectory"; const QString SceneFileXmlStreamBase::ELEMENT_SCENE_FILE_BALSA_EXTRACT_TO_DIRECTORY = "BalsaExtractToDirectory"; const QString SceneFileXmlStreamBase::ELEMENT_SCENE_FILE_BALSA_BASE_PATH_TYPE = "BasePathType"; #endif // __SCENE_FILE_XML_STREAM_BASE_DECLARE__ } // namespace #endif //__SCENE_FILE_XML_STREAM_BASE_H__ connectome-workbench-1.4.2/src/Files/SceneFileXmlStreamFormatTester.cxx000066400000000000000000000271161360521144700262510ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __SCENE_FILE_XML_STREAM_FORMAT_TESTER_DECLARE__ #include "SceneFileXmlStreamFormatTester.h" #undef __SCENE_FILE_XML_STREAM_FORMAT_TESTER_DECLARE__ #include "CaretAssert.h" #include "DataFileException.h" #include "DataFileTypeEnum.h" #include "ElapsedTimer.h" #include "FileInformation.h" #include "SceneFile.h" #include "SystemUtilities.h" using namespace caret; /** * \class caret::SceneFileXmlStreamFormatTester * \brief Test new XML Stream Reader and Writer * \ingroup Files */ /** * Constructor. */ SceneFileXmlStreamFormatTester::SceneFileXmlStreamFormatTester() : CaretObject() { } /** * Destructor. */ SceneFileXmlStreamFormatTester::~SceneFileXmlStreamFormatTester() { } bool SceneFileXmlStreamFormatTester::testReadingAndWritingInDirectory(const QString& directoryName, const bool printResultsFlag) { bool allSuccessfulFlag(false); QStringList extensions; for (auto ext : DataFileTypeEnum::getAllFileExtensions(DataFileTypeEnum::SCENE)) { extensions.append("*." + ext); } QDir directory(directoryName); QStringList sceneFileList = directory.entryList(extensions, QDir::Files, QDir::Name); QStringListIterator iter(sceneFileList); while (iter.hasNext()) { const QString filename = iter.next(); const bool passFlag = testReadingAndWriting(filename, printResultsFlag); std::cout << (passFlag ? "OK: " : "FAILED: ") << filename << std::endl; } return allSuccessfulFlag; } bool SceneFileXmlStreamFormatTester::testReadingAndWriting(const QString& filename, const bool printResultsFlag) { const bool readFlag = testReading(filename, printResultsFlag); const bool writeFlag = testWriting(filename, printResultsFlag); const bool successFlag = (readFlag && writeFlag); if (printResultsFlag) { if (successFlag) { std::cout << "Success " << std::endl; } else { if ( ! readFlag) { std::cout << "Read FAILED" << std::endl; } if ( ! writeFlag) { std::cout << "Write FAILED" << std::endl; } } } return successFlag; } /** * Test reading of XML Stream Reader * * @param filename * Name of file */ bool SceneFileXmlStreamFormatTester::testReading(const QString& filename, const bool printResultsFlag) { try { QString originalReWrittenFileName; QString intermediateFileName; QString finalFileName; getTempFileNames(filename, "Read", originalReWrittenFileName, intermediateFileName, finalFileName); /* * Save original format file since some changes to writing * may have been made since original file was last written * (perhaps CDATA added) */ SceneFile sceneFileUpdated; sceneFileUpdated.readFileSaxReader(filename); sceneFileUpdated.writeFileSaxWriter(originalReWrittenFileName); SceneFile sceneFile; sceneFile.readFileStreamReader(originalReWrittenFileName); sceneFile.writeFileSaxWriter(finalFileName); FileInformation origFileInfo(filename); FileInformation origReWrittenFileInfo(originalReWrittenFileName); FileInformation finalFileInfo(finalFileName); const bool successFlag(origReWrittenFileInfo.size() == finalFileInfo.size()); if (printResultsFlag) { const QString resultString(successFlag ? "READING MATCHED" : "FAILED"); std::cout << resultString << std::endl; std::cout << " Original File: " << origFileInfo.getFileName() << std::endl; std::cout << " Original File (rewritten): " << origReWrittenFileInfo.getFileName() << std::endl; std::cout << " Test output file name: " << finalFileInfo.getFileName() << std::endl; std::cout << " Sizes (orig) " << origReWrittenFileInfo.size() << " (output) " << finalFileInfo.size() << std::endl; std::cout << " sdiff -s " << origReWrittenFileInfo.getFileName() << " " << finalFileInfo.getFileName() << std::endl; std::cout << std::endl; } return successFlag; } catch (const DataFileException& dfe) { if (printResultsFlag) { std::cout << "Failed: " << dfe.whatString() << std::endl; } return false; } } bool SceneFileXmlStreamFormatTester::testWriting(const QString& filename, const bool printResultsFlag) { try { QString originalReWrittenFileName; QString intermediateFileName; QString finalFileName; getTempFileNames(filename, "Write", originalReWrittenFileName, intermediateFileName, finalFileName); /* * Read with old reader and write with old reader since * writing may have changed since file was originally written */ SceneFile sceneFileUpdated; sceneFileUpdated.readFileSaxReader(filename); sceneFileUpdated.writeFileSaxWriter(originalReWrittenFileName); /* * Write with new reader */ sceneFileUpdated.writeFileSaxWriter(intermediateFileName); /* * Read file with old reader and write with * old reader. */ SceneFile sceneFile; sceneFile.readFileSaxReader(intermediateFileName); sceneFile.writeFileSaxWriter(finalFileName); FileInformation origFileInfo(filename); FileInformation rewrittenFileInfo(originalReWrittenFileName); FileInformation intermediateFileInfo(intermediateFileName); FileInformation finalFileInfo(finalFileName); /* * If 'original re-written' matches final then * the intermediate writing with new writer was * successful */ const bool successFlag(rewrittenFileInfo.size() == finalFileInfo.size()); if (printResultsFlag) { const QString resultString(successFlag ? "WRITING MATCHED" : "FAILED"); std::cout << resultString << std::endl; std::cout << " Original File: " << origFileInfo.getFileName() << std::endl; std::cout << " Old Reritten File: " << rewrittenFileInfo.getFileName() << std::endl; std::cout << " New Writer File: " << intermediateFileInfo.getFileName() << std::endl; std::cout << " Final file: " << finalFileInfo.getFileName() << std::endl; std::cout << " Sizes (re-written) " << rewrittenFileInfo.size() << " (final) " << finalFileInfo.size() << std::endl; std::cout << " sdiff -s " << rewrittenFileInfo.getFileName() << " " << finalFileInfo.getFileName() << std::endl; std::cout << std::endl; } return successFlag; } catch (const DataFileException& dfe) { if (printResultsFlag) { std::cout << "Failed: " << dfe.whatString() << std::endl; } return false; } } void SceneFileXmlStreamFormatTester::getTempFileNames(const QString& filename, const QString& prefixName, QString& originalFileReWrittenOut, QString& intermediateFileNameOut, QString& finalFileNameOut) { FileInformation fileInfo(filename); AString absPath, nameNoExt, extNoDot; fileInfo.getFileComponents(absPath, nameNoExt, extNoDot); const AString path = fileInfo.getAbsolutePath(); const AString name = fileInfo.getFileName(); originalFileReWrittenOut = FileInformation::assembleFileComponents(absPath, prefixName + "TestOriginalReWritten", extNoDot); intermediateFileNameOut = FileInformation::assembleFileComponents(absPath, prefixName + "TestItermediate", extNoDot); finalFileNameOut = FileInformation::assembleFileComponents(absPath, prefixName + "TestFinal", extNoDot); } bool SceneFileXmlStreamFormatTester::timeReadingAndWriting(const QString& filename) { const bool successFlag(false); AString path, name, ext; FileInformation fileInfo(filename); fileInfo.getFileComponents(path, name, ext); std::cout << "Timing (seconds) for " << fileInfo.getFileName() << std::endl; try { SceneFile sceneFile; ElapsedTimer timer; timer.start(); sceneFile.readFileSaxReader(filename); std::cout << " Read OLD: " << timer.getElapsedTimeSeconds() << std::endl; timer.reset(); QString tempName(FileInformation::assembleFileComponents(QDir::tempPath(), "TestRead", ext)); timer.start(); sceneFile.writeFileSaxWriter(tempName); std::cout << " Write OLD: " << timer.getElapsedTimeSeconds() << std::endl; } catch (const DataFileException& dfe) { std::cout << "Test OLD Failed: " << dfe.whatString() << std::endl; } try { SceneFile sceneFile; ElapsedTimer timer; timer.start(); sceneFile.readFileStreamReader(filename); std::cout << " Read NEW: " << timer.getElapsedTimeSeconds() << std::endl; timer.reset(); QString tempName(FileInformation::assembleFileComponents(QDir::tempPath(), "TestWrite", ext)); timer.start(); sceneFile.writeFileStreamWriter(tempName); std::cout << " Write NEW: " << timer.getElapsedTimeSeconds() << std::endl; } catch (const DataFileException& dfe) { std::cout << "Test New Failed: " << dfe.whatString() << std::endl; } return successFlag; } connectome-workbench-1.4.2/src/Files/SceneFileXmlStreamFormatTester.h000066400000000000000000000052311360521144700256700ustar00rootroot00000000000000#ifndef __SCENE_FILE_XML_STREAM_FORMAT_TESTER_H__ #define __SCENE_FILE_XML_STREAM_FORMAT_TESTER_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" namespace caret { class SceneFileXmlStreamFormatTester : public CaretObject { public: SceneFileXmlStreamFormatTester(); virtual ~SceneFileXmlStreamFormatTester(); SceneFileXmlStreamFormatTester(const SceneFileXmlStreamFormatTester&) = delete; SceneFileXmlStreamFormatTester& operator=(const SceneFileXmlStreamFormatTester&) = delete; static bool testReadingAndWriting(const QString& filename, const bool printResultsFlag); static bool testReading(const QString& filename, const bool printResultsFlag); static bool testWriting(const QString& filename, const bool printResultsFlag); static bool timeReadingAndWriting(const QString& filename); static bool testReadingAndWritingInDirectory(const QString& directoryName, const bool printResultsFlag); // ADD_NEW_METHODS_HERE private: static void getTempFileNames(const QString& filename, const QString& prefixName, QString& originalFileReWrittenOut, QString& intermediateFileNameOut, QString& finalFileNameOut); // ADD_NEW_MEMBERS_HERE }; #ifdef __SCENE_FILE_XML_STREAM_FORMAT_TESTER_DECLARE__ // #endif // __SCENE_FILE_XML_STREAM_FORMAT_TESTER_DECLARE__ } // namespace #endif //__SCENE_FILE_XML_STREAM_FORMAT_TESTER_H__ connectome-workbench-1.4.2/src/Files/SceneFileXmlStreamReader.cxx000066400000000000000000000253641360521144700250370ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #define __SCENE_FILE_XML_STREAM_READER_DECLARE__ #include "SceneFileXmlStreamReader.h" #undef __SCENE_FILE_XML_STREAM_READER_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "DataFileException.h" #include "GiftiMetaData.h" #include "GiftiXmlElements.h" #include "Scene.h" #include "SceneFile.h" #include "SceneInfo.h" #include "SceneInfoXmlStreamReader.h" #include "SceneTypeEnum.h" #include "SceneXmlStreamReader.h" using namespace caret; /** * \class caret::SceneFileXmlStreamReader * \brief XML Stream Writer for Scene File * \ingroup Files */ /** * Constructor. */ SceneFileXmlStreamReader::SceneFileXmlStreamReader() : SceneFileXmlStreamBase() { } /** * Destructor. */ SceneFileXmlStreamReader::~SceneFileXmlStreamReader() { } /** * Read into the given scene file from the file with the given name * * @param filename * Name of the scene file * @param sceneFile * Name of the scene file * @throws * Data file exception */ void SceneFileXmlStreamReader::readFile(const AString& filename, SceneFile* sceneFile) { CaretAssert(sceneFile); if (sceneFile == NULL) { throw DataFileException("Scene file is invalid (NULL)."); } if (filename.isEmpty()) { throw DataFileException("Scene file name is empty"); } m_filename = filename; QFile file(m_filename); if ( ! file.open(QFile::ReadOnly)) { throw DataFileException("Unable to open for reading: " + m_filename + " Reason: " + file.errorString()); } QXmlStreamReader xmlReader(&file); readFileContent(xmlReader, sceneFile); AString errorMessage; if (xmlReader.hasError()) { errorMessage = xmlReader.errorString(); errorMessage.appendWithNewLine("Line " + AString::number(xmlReader.lineNumber()) + " column " + AString::number(xmlReader.columnNumber())); } file.close(); if ( ! errorMessage.isEmpty()) { throw DataFileException(errorMessage); } } /** * Read the file's content * * @param xmlReader * The XML stream reader * @param sceneFile * Into this scene file */ void SceneFileXmlStreamReader::readFileContent(QXmlStreamReader& xmlReader, SceneFile* sceneFile) { CaretAssert(sceneFile); if (xmlReader.atEnd()) { xmlReader.raiseError("At end of file when starting to read. Is file empty?"); return; } xmlReader.readNextStartElement(); if (xmlReader.name() != ELEMENT_SCENE_FILE) { xmlReader.raiseError("First element is \"" + xmlReader.name().toString() + "\" but should be " + ELEMENT_SCENE_FILE); return; } const QXmlStreamAttributes atts = xmlReader.attributes(); const QStringRef versionAtt = atts.value(ATTRIBUTE_SCENE_FILE_VERSION); m_fileVersion = 1; if ( ! versionAtt.isEmpty()) { /* * Note: version was float in previous versions, so get as float and convert to int */ m_fileVersion = static_cast(versionAtt.toFloat()); } /* * Set when ending scene file element is found */ bool endElementFound(false); while ( ( ! xmlReader.atEnd()) && ( ! endElementFound)) { xmlReader.readNext(); switch (xmlReader.tokenType()) { case QXmlStreamReader::StartElement: if (xmlReader.name() == GiftiXmlElements::TAG_METADATA) { GiftiMetaData* metaData = sceneFile->getFileMetaData(); metaData->readSceneFile3(xmlReader); } else if (xmlReader.name() == ELEMENT_SCENE_FILE_INFO_DIRECTORY) { readSceneInfoDirectory(xmlReader, sceneFile); } else if (xmlReader.name() == SceneXmlStreamReader::ELEMENT_SCENE) { const QXmlStreamAttributes attributes = xmlReader.attributes(); const QStringRef typeString = attributes.value(SceneXmlStreamReader::ATTRIBUTE_SCENE_TYPE); bool valid(false); SceneTypeEnum::Enum sceneType = SceneTypeEnum::fromName(typeString.toString(), &valid); const QStringRef indexString = attributes.value(SceneXmlStreamReader::ATTRIBUTE_SCENE_INDEX); const int32_t sceneIndex = indexString.toInt(); Scene* scene = new Scene(sceneType); SceneXmlStreamReader sceneReader; sceneReader.readScene(xmlReader, scene, m_filename); if ( ! xmlReader.hasError()) { auto mapIter = m_sceneInfoMap.find(sceneIndex); SceneInfo* sceneInfo = ((mapIter != m_sceneInfoMap.end()) ? mapIter->second : NULL); scene->setSceneInfo(sceneInfo); sceneFile->addScene(scene); } } else { m_unexpectedXmlElements.insert(xmlReader.name().toString()); xmlReader.skipCurrentElement(); } break; case QXmlStreamReader::EndElement: if (xmlReader.name() == ELEMENT_SCENE_FILE) { endElementFound = true; } break; default: break; } } } /** * Read the scene info directory * * @param xmlReader * The XML stream reader * @param sceneFile * Into this scene file */ void SceneFileXmlStreamReader::readSceneInfoDirectory(QXmlStreamReader& xmlReader, SceneFile* sceneFile) { /* * Gets set when ending scene info directory element is read */ bool endElementFound(false); while ( (! xmlReader.atEnd()) && ( ! endElementFound)) { xmlReader.readNext(); switch (xmlReader.tokenType()) { case QXmlStreamReader::StartElement: // { // std::cout << "Start Element " << xmlReader.name().toString() // << " characters " << xmlReader.readElementText() // << " CDATA" << (xmlReader.isCDATA() ? " Yes" : " No") << std::endl; // // } if (xmlReader.name() == ELEMENT_SCENE_FILE_BALSA_STUDY_ID) { sceneFile->setBalsaStudyID(xmlReader.readElementText()); } else if (xmlReader.name() == ELEMENT_SCENE_FILE_BALSA_STUDY_TITLE) { sceneFile->setBalsaStudyTitle(xmlReader.readElementText()); } else if (xmlReader.name() == ELEMENT_SCENE_FILE_BALSA_BASE_DIRECTORY) { sceneFile->setBalsaCustomBaseDirectory(xmlReader.readElementText()); } else if (xmlReader.name() == ELEMENT_SCENE_FILE_BALSA_EXTRACT_TO_DIRECTORY) { sceneFile->setBalsaExtractToDirectoryName(xmlReader.readElementText()); } else if (xmlReader.name() == ELEMENT_SCENE_FILE_BALSA_BASE_PATH_TYPE) { const AString name = xmlReader.readElementText(); bool valid(false); const SceneFileBasePathTypeEnum::Enum basePathType = SceneFileBasePathTypeEnum::fromName(name, &valid); if (valid) { sceneFile->setBasePathType(basePathType); } else { sceneFile->setBasePathType(SceneFileBasePathTypeEnum::AUTOMATIC); CaretLogWarning(m_filename + "has invalid base path type: " + name); } } else if (xmlReader.name() == SceneInfoXmlStreamReader::ELEMENT_SCENE_INFO) { const QXmlStreamAttributes attributes = xmlReader.attributes(); const QStringRef indexAttribute = attributes.value(SceneInfoXmlStreamReader::ATTRIBUTE_SCENE_INDEX); if ( ! indexAttribute.isEmpty()) { const int32_t sceneIndex = indexAttribute.toInt(); SceneInfoXmlStreamReader infoReader; SceneInfo* sceneInfo = new SceneInfo(); infoReader.readSceneInfo(xmlReader, sceneInfo); if ( ! xmlReader.hasError()) { m_sceneInfoMap.insert(std::make_pair(sceneIndex, sceneInfo)); } } } else { m_unexpectedXmlElements.insert(xmlReader.name().toString()); xmlReader.skipCurrentElement(); } break; case QXmlStreamReader::EndElement: if (xmlReader.name() == ELEMENT_SCENE_FILE_INFO_DIRECTORY) { endElementFound = true; } break; default: break; } } } connectome-workbench-1.4.2/src/Files/SceneFileXmlStreamReader.h000066400000000000000000000043661360521144700244630ustar00rootroot00000000000000#ifndef __SCENE_FILE_XML_STREAM_READER_H__ #define __SCENE_FILE_XML_STREAM_READER_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "SceneFileXmlStreamBase.h" class QXmlStreamReader; namespace caret { class SceneFile; class SceneInfo; class SceneFileXmlStreamReader : public SceneFileXmlStreamBase { public: SceneFileXmlStreamReader(); virtual ~SceneFileXmlStreamReader(); SceneFileXmlStreamReader(const SceneFileXmlStreamReader&) = delete; SceneFileXmlStreamReader& operator=(const SceneFileXmlStreamReader&) = delete; void readFile(const AString& filename, SceneFile* sceneFile); // ADD_NEW_METHODS_HERE private: void readFileContent(QXmlStreamReader& xmlReader, SceneFile* sceneFile); void readSceneInfoDirectory(QXmlStreamReader& xmlReader, SceneFile* sceneFile); AString m_filename; int32_t m_fileVersion = -1; std::set m_unexpectedXmlElements; std::map m_sceneInfoMap; // ADD_NEW_MEMBERS_HERE }; #ifdef __SCENE_FILE_XML_STREAM_READER_DECLARE__ // #endif // __SCENE_FILE_XML_STREAM_READER_DECLARE__ } // namespace #endif //__SCENE_FILE_XML_STREAM_READER_H__ connectome-workbench-1.4.2/src/Files/SceneFileXmlStreamWriter.cxx000066400000000000000000000161471360521144700251100ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SCENE_FILE_XML_STREAM_WRITER_DECLARE__ #include "SceneFileXmlStreamWriter.h" #undef __SCENE_FILE_XML_STREAM_WRITER_DECLARE__ #include #include #include "CaretAssert.h" #include "DataFileException.h" #include "FileInformation.h" #include "GiftiMetaData.h" #include "Scene.h" #include "SceneFile.h" #include "SceneInfoXmlStreamWriter.h" #include "ScenePathName.h" #include "SceneXmlStreamWriter.h" using namespace caret; /** * \class caret::SceneFileXmlStreamWriter * \brief XML Stream reader for Scene File * \ingroup Files */ /** * Constructor. */ SceneFileXmlStreamWriter::SceneFileXmlStreamWriter() : SceneFileXmlStreamBase() { } /** * Destructor. */ SceneFileXmlStreamWriter::~SceneFileXmlStreamWriter() { } /** * Write the given Scene File in XML format. Name of the file * is obtained from the file. * * @param sceneFile * Scene File written in XML format. * @throws * DataFileException if there is an error writing the file. */ void SceneFileXmlStreamWriter::writeFile(const SceneFile* sceneFile) { CaretAssert(sceneFile); const QString filename = sceneFile->getFileName(); if (filename.isEmpty()) { throw DataFileException("Name for writing annotation file is empty."); } QFile file(filename); if ( ! file.open(QFile::WriteOnly)) { throw DataFileException(filename, "Error opening for writing: " + file.errorString()); } QXmlStreamWriter xmlWriter(&file); writeFileContentToXmlStreamWriter(xmlWriter, sceneFile, filename); file.close(); if (xmlWriter.hasError()) { throw DataFileException(filename, ("Unknown error writing file " + sceneFile->getFileNameNoPath())); } } /** * Write the scene files content to the XML stream. * * @param xmlWriter * The XML stream writer * @param sceneFile * The scene file * @param sceneFileName * Name of the file. */ void SceneFileXmlStreamWriter::writeFileContentToXmlStreamWriter(QXmlStreamWriter& xmlWriter, const SceneFile* sceneFile, const AString& sceneFileName) { CaretAssert(sceneFile); const AString versionString = AString::number(sceneFile->getSceneFileVersionForWriting()); xmlWriter.setAutoFormatting(true); xmlWriter.writeStartDocument(); xmlWriter.writeStartElement(ELEMENT_SCENE_FILE); xmlWriter.writeAttribute(ATTRIBUTE_SCENE_FILE_VERSION, versionString); const GiftiMetaData* metaData = sceneFile->getFileMetaData(); if ( ! metaData->isEmpty()) { metaData->writeSceneFile3(xmlWriter); } writeSceneInfoDirectory(xmlWriter, sceneFile, sceneFileName); const int32_t numberOfScenes = sceneFile->getNumberOfScenes(); for (int32_t sceneIndex = 0; sceneIndex < numberOfScenes; sceneIndex++) { SceneXmlStreamWriter sceneXmlWriter; sceneXmlWriter.writeXML(&xmlWriter, sceneFile->getSceneAtIndex(sceneIndex), sceneIndex, sceneFileName); } xmlWriter.writeEndElement(); xmlWriter.writeEndDocument(); } /** * Write the scene info directory to the XML stream * * @param xmlWriter * The XML stream writer * @param sceneFile * The scene file * @param sceneFileName * Name of the file. */ void SceneFileXmlStreamWriter::writeSceneInfoDirectory(QXmlStreamWriter& xmlWriter, const SceneFile* sceneFile, const AString& sceneFileName) { xmlWriter.writeStartElement(ELEMENT_SCENE_FILE_INFO_DIRECTORY); xmlWriter.writeTextElement(ELEMENT_SCENE_FILE_BALSA_STUDY_ID, sceneFile->getBalsaStudyID()); xmlWriter.writeTextElement(ELEMENT_SCENE_FILE_BALSA_STUDY_TITLE, sceneFile->getBalsaStudyTitle()); AString relativeBasePath(""); switch (sceneFile->getBasePathType()) { case SceneFileBasePathTypeEnum::AUTOMATIC: break; case SceneFileBasePathTypeEnum::CUSTOM: { /* * Write base path as a path RELATIVE to the scene file * but only when base path type is CUSTOM * Note: we do not use FileInformation::getCanonicalFilePath() * because it returns an empty string if the file DOES NOT exist * and this may occur since the file may be new and has not * been closed. */ if ( ! sceneFile->getBalsaCustomBaseDirectory().isEmpty()) { const AString baseDirAbsPath = FileInformation(sceneFile->getBalsaCustomBaseDirectory()).getAbsoluteFilePath(); const AString sceneFileAbsPath = FileInformation(sceneFileName).getAbsoluteFilePath(); ScenePathName basePathName("basePathName", baseDirAbsPath); relativeBasePath = basePathName.getRelativePathToSceneFile(sceneFileAbsPath); } } break; } xmlWriter.writeTextElement(ELEMENT_SCENE_FILE_BALSA_BASE_DIRECTORY, relativeBasePath); xmlWriter.writeTextElement(ELEMENT_SCENE_FILE_BALSA_EXTRACT_TO_DIRECTORY, sceneFile->getBalsaExtractToDirectoryName()); xmlWriter.writeTextElement(ELEMENT_SCENE_FILE_BALSA_BASE_PATH_TYPE, SceneFileBasePathTypeEnum::toName(sceneFile->getBasePathType())); const int32_t numberOfScenes = sceneFile->getNumberOfScenes(); for (int32_t sceneIndex = 0; sceneIndex < numberOfScenes; sceneIndex++) { SceneInfoXmlStreamWriter infoXmlWriter; infoXmlWriter.writeXML(&xmlWriter, sceneFile->getSceneAtIndex(sceneIndex)->getSceneInfo(), sceneIndex); } xmlWriter.writeEndElement(); } connectome-workbench-1.4.2/src/Files/SceneFileXmlStreamWriter.h000066400000000000000000000042361360521144700245310ustar00rootroot00000000000000#ifndef __SCENE_FILE_XML_STREAM_WRITER_H__ #define __SCENE_FILE_XML_STREAM_WRITER_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "SceneFileXmlStreamBase.h" class QXmlStreamWriter; namespace caret { class SceneFile; class SceneFileXmlStreamWriter : public SceneFileXmlStreamBase { public: SceneFileXmlStreamWriter(); virtual ~SceneFileXmlStreamWriter(); SceneFileXmlStreamWriter(const SceneFileXmlStreamWriter&) = delete; SceneFileXmlStreamWriter& operator=(const SceneFileXmlStreamWriter&) = delete; void writeFile(const SceneFile* sceneFile); // ADD_NEW_METHODS_HERE private: void writeFileContentToXmlStreamWriter(QXmlStreamWriter& xmlWriter, const SceneFile* sceneFile, const AString& sceneFileName); void writeSceneInfoDirectory(QXmlStreamWriter& xmlWriter, const SceneFile* sceneFile, const AString& sceneFileName); // ADD_NEW_MEMBERS_HERE }; #ifdef __SCENE_FILE_XML_STREAM_WRITER_DECLARE__ // #endif // __SCENE_FILE_XML_STREAM_WRITER_DECLARE__ } // namespace #endif //__SCENE_FILE_XML_STREAM_WRITER_H__ connectome-workbench-1.4.2/src/Files/SignedDistanceHelper.cxx000066400000000000000000001213241360521144700242370ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /* * For the function pointInTri(): * Original copyright for PNPOLY, though my version is entirely rewritten and modified * Source: http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html */ /* Copyright (c) 1970-2003, Wm. Randolph Franklin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers. 2. Redistributions in binary form must reproduce the above copyright notice in the documentation and/or other materials provided with the distribution. 3. The name of W. Randolph Franklin may not be used to endorse or promote products derived from this Software without specific prior written permission. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "BoundingBox.h" #include "CaretHeap.h" #include "SignedDistanceHelper.h" #include "SurfaceFile.h" #include "TopologyHelper.h" #include using namespace std; using namespace caret; float SignedDistanceHelper::dist(const float coord[3], WindingLogic myWinding) { CaretMutexLocker locked(&m_mutex); CaretSimpleMinHeap*, float> myHeap; myHeap.push(m_base->m_indexRoot, m_base->m_indexRoot->distToPoint(coord)); ClosestPointInfo tempInfo, bestInfo; float tempf = -1.0f, bestTriDist = -1.0f; bool first = true; int numChanged = 0; while (!myHeap.isEmpty()) { Oct* curOct = myHeap.pop(&tempf); if (first || tempf < bestTriDist) { if (curOct->m_leaf) { vector& myVecRef = *(curOct->m_data.m_triList); int numTris = (int)myVecRef.size(); for (int i = 0; i < numTris; ++i) { if (m_triMarked[myVecRef[i]] != 1) { m_triMarked[myVecRef[i]] = 1; m_triMarkChanged[numChanged++] = myVecRef[i]; tempf = unsignedDistToTri(coord, myVecRef[i], tempInfo); if (first || tempf < bestTriDist) { bestInfo = tempInfo; bestTriDist = tempf; first = false; } } } } else { for (int ci = 0; ci < 2; ++ci) { for (int cj = 0; cj < 2; ++cj) { for (int ck = 0; ck < 2; ++ck) { tempf = curOct->m_children[ci][cj][ck]->distToPoint(coord); if (first || tempf < bestTriDist) { myHeap.push(curOct->m_children[ci][cj][ck], tempf); } } } } } } } while (numChanged) { m_triMarked[m_triMarkChanged[--numChanged]] = 0;//need to do this before computeSign } return bestTriDist * computeSign(coord, bestInfo, myWinding); } void SignedDistanceHelper::barycentricWeights(const float coord[3], BarycentricInfo& baryInfoOut) { CaretMutexLocker locked(&m_mutex); CaretSimpleMinHeap*, float> myHeap; myHeap.push(m_base->m_indexRoot, m_base->m_indexRoot->distToPoint(coord)); ClosestPointInfo tempInfo, bestInfo; float tempf = -1.0f, bestTriDist = -1.0f; bool first = true; int numChanged = 0; while (!myHeap.isEmpty()) { Oct* curOct = myHeap.pop(&tempf); if (first || tempf < bestTriDist) { if (curOct->m_leaf) { vector& myVecRef = *(curOct->m_data.m_triList); int numTris = (int)myVecRef.size(); for (int i = 0; i < numTris; ++i) { if (m_triMarked[myVecRef[i]] != 1) { m_triMarked[myVecRef[i]] = 1; m_triMarkChanged[numChanged++] = myVecRef[i]; tempf = unsignedDistToTri(coord, myVecRef[i], tempInfo); if (first || tempf < bestTriDist) { bestInfo = tempInfo; bestTriDist = tempf; first = false; } } } } else { for (int ci = 0; ci < 2; ++ci) { for (int cj = 0; cj < 2; ++cj) { for (int ck = 0; ck < 2; ++ck) { tempf = curOct->m_children[ci][cj][ck]->distToPoint(coord); if (first || tempf < bestTriDist) { myHeap.push(curOct->m_children[ci][cj][ck], tempf); } } } } } } } while (numChanged) { m_triMarked[m_triMarkChanged[--numChanged]] = 0;//clean up } baryInfoOut.triangle = bestInfo.triangle; baryInfoOut.point = bestInfo.tempPoint; baryInfoOut.absDistance = bestTriDist; const int32_t* triNodes = m_base->getTriangle(bestInfo.triangle); baryInfoOut.nodes[0] = triNodes[0]; baryInfoOut.nodes[1] = triNodes[1]; baryInfoOut.nodes[2] = triNodes[2]; switch (bestInfo.type) { case 2: { baryInfoOut.type = BarycentricInfo::TRIANGLE; Vector3D vert1 = m_base->getCoordinate(triNodes[0]); Vector3D vert2 = m_base->getCoordinate(triNodes[1]); Vector3D vert3 = m_base->getCoordinate(triNodes[2]); Vector3D vp1 = vert1 - bestInfo.tempPoint; Vector3D vp2 = vert2 - bestInfo.tempPoint; Vector3D vp3 = vert3 - bestInfo.tempPoint; float weight1 = vp2.cross(vp3).length(); float weight2 = vp1.cross(vp3).length(); float weight3 = vp1.cross(vp2).length(); float weightsum = weight1 + weight2 + weight3; baryInfoOut.baryWeights[0] = weight1 / weightsum; baryInfoOut.baryWeights[1] = weight2 / weightsum; baryInfoOut.baryWeights[2] = weight3 / weightsum; } break; case 1: { baryInfoOut.type = BarycentricInfo::EDGE; Vector3D vert1 = m_base->getCoordinate(bestInfo.node1); Vector3D vert2 = m_base->getCoordinate(bestInfo.node2); Vector3D v21hat = vert2 - vert1; float origLength; v21hat = v21hat.normal(&origLength); float tempf = v21hat.dot(bestInfo.tempPoint - vert1); float weight2 = tempf / origLength; float weight1 = 1.0f - weight2; for (int i = 0; i < 3; ++i) { if (triNodes[i] == bestInfo.node1) { baryInfoOut.baryWeights[i] = weight1; } else if (triNodes[i] == bestInfo.node2) { baryInfoOut.baryWeights[i] = weight2; } else { baryInfoOut.baryWeights[i] = 0.0f; } } } break; case 0: baryInfoOut.type = BarycentricInfo::NODE; for (int i = 0; i < 3; ++i) { if (triNodes[i] == bestInfo.node1) { baryInfoOut.baryWeights[i] = 1.0f; } else { baryInfoOut.baryWeights[i] = 0.0f; } } break; }; for (int i = 0; i < 3; ++i) { if (baryInfoOut.baryWeights[i] < 0.0f) { baryInfoOut.baryWeights[i] = 0.0f; } } } int SignedDistanceHelper::computeSign(const float coord[3], SignedDistanceHelper::ClosestPointInfo myInfo, WindingLogic myWinding) { Vector3D point = coord; Vector3D result = point - myInfo.tempPoint; float tempf; switch (myWinding) { case EVEN_ODD: case NEGATIVE: case NONZERO: { int numChanged = 0; float positiveZ[3] = {0, 0, 1}; Vector3D point2 = point + positiveZ; int crossCount = 0; vector*> myStack; myStack.push_back(m_base->m_indexRoot); while (!myStack.empty()) { Oct* curOct = myStack[myStack.size() - 1]; myStack.pop_back(); if (curOct->m_leaf) { vector& myVecRef = *(curOct->m_data.m_triList); int numTris = (int)myVecRef.size(); for (int i = 0; i < numTris; ++i) { if (m_triMarked[myVecRef[i]] != 1) { m_triMarked[myVecRef[i]] = 1; m_triMarkChanged[numChanged++] = myVecRef[i]; const int32_t* myTileNodes = m_base->getTriangle(myVecRef[i]); Vector3D verts[3]; verts[0] = m_base->getCoordinate(myTileNodes[0]); verts[1] = m_base->getCoordinate(myTileNodes[1]); verts[2] = m_base->getCoordinate(myTileNodes[2]); Vector3D triNormal; MathFunctions::normalVector(verts[0], verts[1], verts[2], triNormal); float factor = triNormal[2];//equivalent to dot product with positiveZ if (factor != 0.0f) { if (triNormal.dot(verts[0] - point) / factor > 0.0f && pointInTri(verts, point, 0, 1)) { if (triNormal[2] < 0.0f) { ++crossCount; } else { --crossCount; } } } } } } else { for (int ci = 0; ci < 2; ++ci) { for (int cj = 0; cj < 2; ++cj) { for (int ck = 0; ck < 2; ++ck) { if (curOct->m_children[ci][cj][ck]->rayIntersects(coord, point2)) { myStack.push_back(curOct->m_children[ci][cj][ck]); } } } } } } while (numChanged) { m_triMarked[m_triMarkChanged[--numChanged]] = 0; } switch (myWinding) { case EVEN_ODD: if ((abs(crossCount) & 1) == 1) return -1;//& 1 instead of % 2 return 1; break; case NEGATIVE: if (crossCount < 0) return -1; return 1; break; case NONZERO: if (crossCount != 0) return -1; return 1; break; default: return 1;//because compiler can't handle when a switch doesn't accound for an enum value... } } break; case NORMALS: switch (myInfo.type) { case 0://node { int curSign = 0; int numChanged = 0; const vector& myTiles = m_base->m_topoHelp->getNodeTiles(myInfo.node1); bool first = true; float bestNorm = 0; Vector3D tempvec, tempvec2, bestCent; for (int i = 0; i < (int)myTiles.size(); ++i)//find the tile of the node with the normal most parallel to the line segment between centroid and point {//should be least likely to have an intervening triangle const int32_t* myTileNodes = m_base->getTriangle(myTiles[i]); Vector3D vert1 = m_base->getCoordinate(myTileNodes[0]); Vector3D vert2 = m_base->getCoordinate(myTileNodes[1]); Vector3D vert3 = m_base->getCoordinate(myTileNodes[2]); Vector3D centroid = (vert1 + vert2 + vert3) / 3.0f; if (MathFunctions::normalVector(vert1, vert2, vert3, tempvec))//make sure the triangle has a valid normal { tempvec2 = point - centroid; tempf = tempvec.dot(tempvec2.normal()); if (first || abs(tempf) > abs(bestNorm)) { if (tempf > 0.0f) { curSign = 1; } else { curSign = -1; } first = false; bestNorm = tempf; bestCent = centroid; } } } Vector3D mySeg = point - bestCent; float bestDist = mySeg.length(); Vector3D segNormal = mySeg.normal();//from the surface to the point, to match the convention of triangles with normals oriented outwards int majAxis = 0, midAxis = 1;//find the axes to use for projecting the triangles, discard the one most aligned with the line segment if (abs(mySeg[1]) < abs(mySeg[0])) { majAxis = 1; midAxis = 0; } if (abs(mySeg[2]) < abs(mySeg[midAxis])) { midAxis = 2; } vector*> myStack; myStack.push_back(m_base->m_indexRoot); while (!myStack.empty()) { Oct* curOct = myStack[myStack.size() - 1]; myStack.pop_back(); if (curOct->m_leaf) { vector& myVecRef = *(curOct->m_data.m_triList); int numTris = (int)myVecRef.size(); for (int i = 0; i < numTris; ++i) { if (m_triMarked[myVecRef[i]] != 1) { m_triMarked[myVecRef[i]] = 1; m_triMarkChanged[numChanged++] = myVecRef[i]; const int32_t* myTileNodes = m_base->getTriangle(myVecRef[i]); Vector3D verts[3]; verts[0] = m_base->getCoordinate(myTileNodes[0]); verts[1] = m_base->getCoordinate(myTileNodes[1]); verts[2] = m_base->getCoordinate(myTileNodes[2]); Vector3D triNormal; MathFunctions::normalVector(verts[0], verts[1], verts[2], triNormal); float factor = triNormal.dot(segNormal); if (factor == 0.0f) { continue;//skip triangles parallel to the line segment } float intersectDist = triNormal.dot(point - verts[0]) / factor; if (intersectDist > 0.0f && intersectDist < bestDist) { Vector3D inPlane = point - intersectDist * segNormal; if (pointInTri(verts, inPlane, majAxis, midAxis)) { bestDist = intersectDist; if (triNormal.dot(mySeg) > 0.0f) { curSign = 1; } else { curSign = -1; } } } } } } else { for (int ci = 0; ci < 2; ++ci) { for (int cj = 0; cj < 2; ++cj) { for (int ck = 0; ck < 2; ++ck) { if (curOct->m_children[ci][cj][ck]->lineSegmentIntersects(coord, bestCent)) { myStack.push_back(curOct->m_children[ci][cj][ck]); } } } } } } while (numChanged) { m_triMarked[m_triMarkChanged[--numChanged]] = 0; } return curSign; } break; case 1://edge { const vector& edgeInfo = m_base->m_topoHelp->getEdgeInfo(); const vector& edges = m_base->m_topoHelp->getNodeEdges(myInfo.node1); int whichEdge = -1, numEdges = (int)edges.size(); for (int i = 0; i < numEdges; ++i) { if (edgeInfo[edges[i]].node1 == myInfo.node2 || edgeInfo[edges[i]].node2 == myInfo.node2) { whichEdge = edges[i]; } } CaretAssert(whichEdge != -1); int tile1 = edgeInfo[whichEdge].tiles[0].tile, tile2 = edgeInfo[whichEdge].tiles[1].tile; Vector3D normalaccum, tempvec;//default constructor initializes it to the zero vector if (tile1 > -1) { const int32_t* tile1nodes = m_base->getTriangle(tile1); MathFunctions::normalVector(m_base->getCoordinate(tile1nodes[0]), m_base->getCoordinate(tile1nodes[1]), m_base->getCoordinate(tile1nodes[2]), tempvec); normalaccum += tempvec; } if (tile2 > -1) { const int32_t *tile2nodes = m_base->getTriangle(tile2); MathFunctions::normalVector(m_base->getCoordinate(tile2nodes[0]), m_base->getCoordinate(tile2nodes[1]), m_base->getCoordinate(tile2nodes[2]), tempvec); normalaccum += tempvec; } if (normalaccum.dot(result) < 0.0f) { return -1; } } break; case 2://face { Vector3D triNormal; const int32_t* triNodes = m_base->getTriangle(myInfo.triangle); Vector3D vert1 = m_base->getCoordinate(triNodes[0]); Vector3D vert2 = m_base->getCoordinate(triNodes[1]); Vector3D vert3 = m_base->getCoordinate(triNodes[2]); MathFunctions::normalVector(vert1, vert2, vert3, triNormal); if (triNormal.dot(result) < 0.0f) { return -1; } } break; } break; } return 1; } bool SignedDistanceHelper::pointInTri(Vector3D verts[3], Vector3D inPlane, int majAxis, int midAxis) { bool inside = false; for (int j = 2, i = 0; i < 3; ++i)//start with the wraparound case { if ((verts[i][majAxis] < inPlane[majAxis]) != (verts[j][majAxis] < inPlane[majAxis])) {//if one vertex is on one side of the point in the x direction, and the other is on the other side (equal case is treated as greater) int ti, tj; if (verts[i][majAxis] < verts[j][majAxis])//reorient the segment consistently to get a consistent answer { ti = i; tj = j; } else { ti = j; tj = i; } if ((verts[ti][midAxis] - verts[tj][midAxis]) / (verts[ti][majAxis] - verts[tj][majAxis]) * (inPlane[majAxis] - verts[tj][majAxis]) + verts[tj][midAxis] > inPlane[midAxis]) {//if the point on the line described by the two vertices with the same x coordinate is above (greater y) than the test point inside = !inside;//even/odd winding rule } } j = i;//consecutive vertices, does 2,0 then 0,1 then 1,2 } return inside; } ///"dumb" implementation, projects to plane, test if inside while finding closest point on each edge ///there are faster implementations out there, but this is easier to follow float SignedDistanceHelper::unsignedDistToTri(const float coord[3], int32_t triangle, ClosestPointInfo& myInfo) { const int32_t* triNodes = m_base->getTriangle(triangle); Vector3D point = coord; Vector3D verts[3]; int type = 0;//tracks whether it is closest to a node, an edge, or the face int32_t node1 = -1, node2 = -1;//tracks which nodes are involved Vector3D bestPoint; verts[0] = m_base->getCoordinate(triNodes[0]); verts[1] = m_base->getCoordinate(triNodes[1]); verts[2] = m_base->getCoordinate(triNodes[2]); Vector3D v10 = verts[1] - verts[0]; Vector3D xhat = v10.normal(); Vector3D v20 = verts[2] - verts[0]; float sanity; Vector3D yhat = (v20 - xhat * xhat.dot(v20)).normal(&sanity);//now we have our orthogonal basis vectors for projection if (sanity == 0.0f || abs(xhat.dot(yhat)) > 0.01f)//if our triangle is (mostly) degenerate, find the closest point on its edges instead of trying to project to the NaN plane { bool first = true; float bestLengthSqr = -1.0f;//track best squared length from edge to original point for (int j = 2, i = 0; i < 3; ++i)//start with the wraparound case { float length; Vector3D norm = (verts[j] - verts[i]).normal(&length); Vector3D mypoint; int temptype = 0, tempnode1, tempnode2 = -1; if (length > 0.0f) { Vector3D diff = point - verts[i]; float dot = norm.dot(diff); if (dot <= 0.0f) { mypoint = verts[i]; tempnode1 = triNodes[i]; } else if (dot >= length) { mypoint = verts[j]; tempnode1 = triNodes[j]; } else { mypoint = verts[i] + dot * norm; temptype = 1; tempnode1 = triNodes[i]; tempnode2 = triNodes[j]; } } else { temptype = 0; tempnode1 = triNodes[i]; mypoint = verts[i]; } float tempdistsqr = (point - mypoint).lengthsquared(); if (first || tempdistsqr < bestLengthSqr) { first = false; type = temptype; bestLengthSqr = tempdistsqr; bestPoint = mypoint; node1 = tempnode1; node2 = tempnode2; } j = i;//consecutive vertices, does 2,0 then 0,1 then 1,2 } } else { float vertxy[3][2]; for (int i = 0; i < 3; ++i)//project everything to the new plane with basis vectors xhat, yhat { vertxy[i][0] = xhat.dot(verts[i] - verts[0]); vertxy[i][1] = yhat.dot(verts[i] - verts[0]); } bool inside = true; float p[2] = { xhat.dot(point - verts[0]), yhat.dot(point - verts[0]) }; float bestxy[2]; float bestDist = -1.0f; for (int i = 0, j = 2, k = 1; i < 3; ++i)//start with the wraparound case { float norm[2] = { vertxy[j][0] - vertxy[i][0], vertxy[j][1] - vertxy[i][1] }; float diff[2] = { p[0] - vertxy[i][0], p[1] - vertxy[i][1] }; float direction[2] = { vertxy[k][0] - vertxy[i][0], vertxy[k][1] - vertxy[i][1] }; float edgelen = sqrt(norm[0] * norm[0] + norm[1] * norm[1]); if (edgelen != 0.0f) { norm[0] /= edgelen; norm[1] /= edgelen; float dot = direction[0] * norm[0] + direction[1] * norm[1]; direction[0] -= dot * norm[0];//direction is orthogonal to norm, in the direction of the third vertex direction[1] -= dot * norm[1]; if (diff[0] * direction[0] + diff[1] * direction[1] < 0.0f)//if dot product with (projected point - vert[i]) is negative {//we are outside the triangle, find the projection to this edge and break if it is the second time or otherwise known to be finished if (bestDist < 0.0f) { inside = false; dot = diff[0] * norm[0] + diff[1] * norm[1]; if (dot <= 0.0f)//if closest point on this edge is an endpoint, it is possible for another edge that we count as outside of to have a closer point { type = 0; node1 = triNodes[i]; bestPoint = verts[i]; bestxy[0] = vertxy[i][0]; bestxy[1] = vertxy[i][1]; } else if (dot >= edgelen) { type = 0; node1 = triNodes[j]; bestPoint = verts[j]; bestxy[0] = vertxy[j][0]; bestxy[1] = vertxy[j][1]; } else {//if closest point on the edge is in the middle of the edge, nothing can be closer, break type = 1; node1 = triNodes[i]; node2 = triNodes[j]; bestxy[0] = vertxy[i][0] + dot * norm[0]; bestxy[1] = vertxy[i][1] + dot * norm[1]; break; } diff[0] = p[0] - bestxy[0]; diff[1] = p[1] - bestxy[1]; bestDist = diff[0] * diff[0] + diff[1] * diff[1]; } else { int tempnode1; Vector3D tempbestPoint; float tempxy[2]; inside = false; dot = diff[0] * norm[0] + diff[1] * norm[1]; if (dot <= 0.0f) { tempnode1 = triNodes[i]; tempbestPoint = verts[i]; tempxy[0] = vertxy[i][0]; tempxy[1] = vertxy[i][1]; } else if (dot >= edgelen) { tempnode1 = triNodes[j]; tempbestPoint = verts[j]; tempxy[0] = vertxy[j][0]; tempxy[1] = vertxy[j][1]; } else {//again, middle of edge always wins, don't bother with the extra test type = 1; node1 = triNodes[i]; node2 = triNodes[j]; bestxy[0] = vertxy[i][0] + dot * norm[0]; bestxy[1] = vertxy[i][1] + dot * norm[1]; break; } diff[0] = p[0] - tempxy[0]; diff[1] = p[1] - tempxy[1]; float tempdist = diff[0] * diff[0] + diff[1] * diff[1]; if (tempdist < bestDist) { type = 0;//if it were in the middle of the edge, we wouldn't be here node1 = tempnode1; bestPoint = tempbestPoint; bestxy[0] = tempxy[0]; bestxy[0] = tempxy[0]; } break;//this is our second time outside an edge, we have now covered all 3 possible endpoints, so break } } } else { if (diff[0] * direction[0] + diff[1] * direction[1] < 0.0f)//since we don't have an edge, we don't need to othrogonalize direction, or project to the edge { inside = false; type = 0; node1 = triNodes[i]; bestPoint = verts[i]; break; } } k = j; j = i;//consecutive vertices, does 2,0 then 0,1 then 1,2 } if (inside) { bestxy[0] = p[0]; bestxy[1] = p[1]; type = 2; } if (type != 0) { bestPoint = bestxy[0] * xhat + bestxy[1] * yhat + verts[0]; } } Vector3D result = point - bestPoint; myInfo.type = type; myInfo.node1 = node1; myInfo.node2 = node2; myInfo.triangle = triangle; myInfo.tempPoint = bestPoint; return result.length(); } SignedDistanceHelper::SignedDistanceHelper(CaretPointer myBase) { m_base = myBase; int32_t numTris = m_base->m_numTris; m_triMarked = CaretArray(numTris); m_triMarkChanged = CaretArray(numTris); for (int32_t i = 0; i < numTris; ++i) { m_triMarked[i] = 0; } } SignedDistanceHelperBase::SignedDistanceHelperBase(const SurfaceFile* mySurf) { m_topoHelp = mySurf->getTopologyHelper(); const float* myBB = mySurf->getBoundingBox()->getBounds(); Vector3D minCoord, maxCoord; minCoord[0] = myBB[0]; maxCoord[0] = myBB[1]; minCoord[1] = myBB[2]; maxCoord[1] = myBB[3]; minCoord[2] = myBB[4]; maxCoord[2] = myBB[5]; m_indexRoot.grabNew(new Oct(minCoord, maxCoord)); const float* myCoordData = mySurf->getCoordinateData(); m_numNodes = mySurf->getNumberOfNodes(); int32_t numNodes3 = m_numNodes * 3; m_coordList.resize(numNodes3); for (int32_t i = 0; i < numNodes3; ++i) { m_coordList[i] = myCoordData[i]; } m_numTris = mySurf->getNumberOfTriangles(); m_triangleList.resize(m_numTris * 3); for (int32_t i = 0; i < m_numTris; ++i) { int32_t i3 = i * 3; const int32_t* thisTri = mySurf->getTriangle(i); m_triangleList[i3] = thisTri[0]; m_triangleList[i3 + 1] = thisTri[1]; m_triangleList[i3 + 2] = thisTri[2]; maxCoord = minCoord = myCoordData + thisTri[0] * 3;//set both to the coordinates of the first node in the triangle for (int j = 1; j < 3; ++j) { int32_t thisNode3 = thisTri[j] * 3; if (myCoordData[thisNode3] < minCoord[0]) minCoord[0] = myCoordData[thisNode3]; if (myCoordData[thisNode3 + 1] < minCoord[1]) minCoord[1] = myCoordData[thisNode3 + 1]; if (myCoordData[thisNode3 + 2] < minCoord[2]) minCoord[2] = myCoordData[thisNode3 + 2]; if (myCoordData[thisNode3] > maxCoord[0]) maxCoord[0] = myCoordData[thisNode3]; if (myCoordData[thisNode3 + 1] > maxCoord[1]) maxCoord[1] = myCoordData[thisNode3 + 1]; if (myCoordData[thisNode3 + 2] > maxCoord[2]) maxCoord[2] = myCoordData[thisNode3 + 2]; } addTriangle(m_indexRoot, i, minCoord, maxCoord);//use bounding box for now as an easy test to capture any chance of the triangle intersecting the Oct } } void SignedDistanceHelperBase::addTriangle(Oct* thisOct, int32_t triangle, float minCoord[3], float maxCoord[3]) { if (thisOct->m_leaf) { thisOct->m_data.m_triList->push_back(triangle); int numTris = (int)thisOct->m_data.m_triList->size(); if (numTris >= NUM_TRIS_TO_TEST && numTris % NUM_TRIS_TEST_INCR == NUM_TRIS_TO_TEST % NUM_TRIS_TEST_INCR)//the second modulus should const out { Vector3D tempMinCoord, tempMaxCoord; const float* myCoordData = m_coordList.data(); int totalSize = 0; int numSplit = 0; for (int i = 0; i < numTris; ++i)//gather data on how it would end up splitting { const int32_t* tempTri = getTriangle((*(thisOct->m_data.m_triList))[i]); tempMaxCoord = tempMinCoord = myCoordData + tempTri[0] * 3;//set both to the coordinates of the first node in the triangle for (int j = 1; j < 3; ++j) { int32_t thisNode3 = tempTri[j] * 3; if (myCoordData[thisNode3] < tempMinCoord[0]) tempMinCoord[0] = myCoordData[thisNode3]; if (myCoordData[thisNode3 + 1] < tempMinCoord[1]) tempMinCoord[1] = myCoordData[thisNode3 + 1]; if (myCoordData[thisNode3 + 2] < tempMinCoord[2]) tempMinCoord[2] = myCoordData[thisNode3 + 2]; if (myCoordData[thisNode3] > tempMaxCoord[0]) tempMaxCoord[0] = myCoordData[thisNode3]; if (myCoordData[thisNode3 + 1] > tempMaxCoord[1]) tempMaxCoord[1] = myCoordData[thisNode3 + 1]; if (myCoordData[thisNode3 + 2] > tempMaxCoord[2]) tempMaxCoord[2] = myCoordData[thisNode3 + 2]; } int minOct[3], maxOct[3]; thisOct->containingChild(tempMinCoord, minOct); thisOct->containingChild(tempMaxCoord, maxOct); int splitSize = 8; if (minOct[0] == maxOct[0]) splitSize >>= 1; if (minOct[1] == maxOct[1]) splitSize >>= 1; if (minOct[2] == maxOct[2]) splitSize >>= 1; totalSize += splitSize; if (splitSize != 8) ++numSplit; } if (numSplit > 0 && totalSize < 3.0f * numTris)//don't split if all triangles end up in all child octs, and try to balance speedup with memory usage { thisOct->makeChildren();//do the split for (int i = 0; i < numTris; ++i)//gather data on how it would end up splitting { const int32_t* tempTri = getTriangle((*(thisOct->m_data.m_triList))[i]); tempMaxCoord = tempMinCoord = myCoordData + tempTri[0] * 3;//set both to the coordinates of the first node in the triangle for (int j = 1; j < 3; ++j) { int32_t thisNode3 = tempTri[j] * 3; if (myCoordData[thisNode3] < tempMinCoord[0]) tempMinCoord[0] = myCoordData[thisNode3]; if (myCoordData[thisNode3 + 1] < tempMinCoord[1]) tempMinCoord[1] = myCoordData[thisNode3 + 1]; if (myCoordData[thisNode3 + 2] < tempMinCoord[2]) tempMinCoord[2] = myCoordData[thisNode3 + 2]; if (myCoordData[thisNode3] > tempMaxCoord[0]) tempMaxCoord[0] = myCoordData[thisNode3]; if (myCoordData[thisNode3 + 1] > tempMaxCoord[1]) tempMaxCoord[1] = myCoordData[thisNode3 + 1]; if (myCoordData[thisNode3 + 2] > tempMaxCoord[2]) tempMaxCoord[2] = myCoordData[thisNode3 + 2]; } for (int ci = 0; ci < 2; ++ci) { for (int cj = 0; cj < 2; ++cj) { for (int ck = 0; ck < 2; ++ck) { if (thisOct->m_children[ci][cj][ck]->boundsOverlaps(tempMinCoord, tempMaxCoord)) { addTriangle(thisOct->m_children[ci][cj][ck], (*(thisOct->m_data.m_triList))[i], tempMinCoord, tempMaxCoord); } } } } } thisOct->m_data.freeData();//and free up some memory } } } else { for (int ci = 0; ci < 2; ++ci) { for (int cj = 0; cj < 2; ++cj) { for (int ck = 0; ck < 2; ++ck) { if (thisOct->m_children[ci][cj][ck]->boundsOverlaps(minCoord, maxCoord)) { addTriangle(thisOct->m_children[ci][cj][ck], triangle, minCoord, maxCoord); } } } } } } const float* SignedDistanceHelperBase::getCoordinate(const int32_t nodeIndex) const { CaretAssert(nodeIndex >= 0 && nodeIndex < m_numNodes); return m_coordList.data() + (nodeIndex * 3); } const int32_t* SignedDistanceHelperBase::getTriangle(const int32_t tileIndex) const { CaretAssert(tileIndex >= 0 && tileIndex < m_numTris); return m_triangleList.data() + (tileIndex * 3); } SignedDistanceHelperBase::~SignedDistanceHelperBase() {//so we don't need to put TopologyHelper.h in our header, due to the smart pointer destructor } connectome-workbench-1.4.2/src/Files/SignedDistanceHelper.h000066400000000000000000000105411360521144700236620ustar00rootroot00000000000000#ifndef __SIGNED_DISTANCE_HELPER_H__ #define __SIGNED_DISTANCE_HELPER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Vector3D.h" #include "CaretMutex.h" #include "CaretPointer.h" #include "OctTree.h" #include namespace caret { class SurfaceFile; class TopologyHelper; class SignedDistanceHelperBase { struct TriVector {//specifically so we can cleanly deallocate the vector from non-leaf nodes when they split std::vector* m_triList; TriVector() { m_triList = new std::vector(); } ~TriVector() { freeData(); } void freeData() { if (m_triList != NULL) { delete m_triList; m_triList = NULL; } } }; static const int NUM_TRIS_TO_TEST = 50;//test for whether to split leaf at this number static const int NUM_TRIS_TEST_INCR = 50;//and again at further multiples of this CaretPointer > m_indexRoot; int32_t m_numTris, m_numNodes; std::vector m_coordList;//make a copy of what we need from SurfaceFile so that if the SurfaceFile gets destroyed, we don't crash std::vector m_triangleList; CaretPointer m_topoHelp; SignedDistanceHelperBase(); void addTriangle(Oct* thisOct, int32_t triangle, float minCoord[3], float maxCoord[3]); const float* getCoordinate(const int32_t nodeIndex) const;//make these public? probably don't want them to be widely used, that is what SurfaceFile is for (but we don't want to store a SurfaceFile pointer) const int32_t* getTriangle(const int32_t tileIndex) const; public: ~SignedDistanceHelperBase();//in order to let us not include TopologyHelper SignedDistanceHelperBase(const SurfaceFile* mySurf); friend class SignedDistanceHelper; }; struct BarycentricInfo { enum POINT_TYPE { NODE, EDGE, TRIANGLE }; int32_t triangle; Vector3D point; POINT_TYPE type; float absDistance; int32_t nodes[3]; float baryWeights[3]; }; class SignedDistanceHelper { public: enum WindingLogic { EVEN_ODD, NEGATIVE, NONZERO, NORMALS }; private: CaretMutex m_mutex; CaretPointer m_base; CaretArray m_triMarked; CaretArray m_triMarkChanged; SignedDistanceHelper(); struct ClosestPointInfo { int type; int32_t node1, node2, triangle; Vector3D tempPoint; }; float unsignedDistToTri(const float coord[3], int32_t triangle, ClosestPointInfo& myInfo); int computeSign(const float coord[3], ClosestPointInfo myInfo, WindingLogic myWinding); bool pointInTri(Vector3D verts[3], Vector3D inPlane, int majAxis, int midAxis); public: SignedDistanceHelper(CaretPointer myBase); ///return the signed distance value at the point float dist(const float coord[3], WindingLogic myWinding); ///find the closest point ON the surface, and return information about it ///will never have negative barycentric weights, or a point outside the triangle void barycentricWeights(const float coordIn[3], BarycentricInfo& baryInfoOut); }; } #endif //__SIGNED_DISTANCE_HELPER_H__ connectome-workbench-1.4.2/src/Files/SparseVolumeIndexer.cxx000066400000000000000000000262731360521144700241660ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __SPARSE_VOLUME_INDEXER_DECLARE__ #include "SparseVolumeIndexer.h" #undef __SPARSE_VOLUME_INDEXER_DECLARE__ #include "CaretLogger.h" using namespace caret; /** * \class caret::SparseVolumeIndexer * \brief Maps IJK indices or XYZ coordinates to a sparse volume data * \ingroup Files * * Some data sources (such as CIFTI files) contain data for a subset * (or sparse representation) of volume data. In a CIFTI file, there * is a list of IJK indices that indicate the offset of each voxel * in the data (and note that the data may be for both surface vertices * and volume voxels). Finding a particular voxel by its IJK indices * requires a sequential search through the CIFTI's list of voxels. * This class permits a much faster location of a particular CIFTI file's * voxel by creating what is essentially a lookup table that maps the * full non-sparse volume IJK indices to an offset in the CIFTI data * or a negative value if the voxel is not present in the CIFTI data. */ /** * Default constructor with invalid state. */ SparseVolumeIndexer::SparseVolumeIndexer() : CaretObject() { m_dataValid = false; } /** * Constructs instance with the given CIFTI Brain Models Map. * * @param ciftiBrainModelsMap * The CIFTI brain models map. */ SparseVolumeIndexer::SparseVolumeIndexer(const CiftiBrainModelsMap& ciftiBrainModelsMap) : CaretObject() { m_dataValid = false; if ( ! ciftiBrainModelsMap.hasVolumeData()) { return; } m_volumeSpace = ciftiBrainModelsMap.getVolumeSpace(); std::vector ciftiVoxelMapping = ciftiBrainModelsMap.getFullVolumeMap(); const int32_t numberOfCiftiVolumeVoxels = static_cast(ciftiVoxelMapping.size()); if (numberOfCiftiVolumeVoxels <= 0) { return; } /* * Make sure orthogonal */ if ( ! m_volumeSpace.isPlumb()) { CaretLogWarning("CIFTI Volume is not Plumb!"); return; } const int64_t* dimIJK = m_volumeSpace.getDims(); const int64_t numberOfVoxels = (dimIJK[0] * dimIJK[1] * dimIJK[2]); if (numberOfVoxels <= 0) { return; } for (std::vector::const_iterator iter = ciftiVoxelMapping.begin(); iter != ciftiVoxelMapping.end(); iter++) { const CiftiBrainModelsMap::VolumeMap& vm = *iter; m_voxelIndexLookup.at(vm.m_ijk) = vm.m_ciftiIndex; } bool validateFlag = true; if (validateFlag) { AString validateString; for (std::vector::const_iterator iter = ciftiVoxelMapping.begin(); iter != ciftiVoxelMapping.end(); iter++) { const CiftiBrainModelsMap::VolumeMap& vm = *iter; const int64_t* foundOffset = m_voxelIndexLookup.find(vm.m_ijk); if (foundOffset != NULL) { if (*foundOffset != vm.m_ciftiIndex) { validateString.appendWithNewLine("IJK (" + AString::fromNumbers(vm.m_ijk, 3, ",") + " should have lookup value " + AString::number(vm.m_ciftiIndex) + " but has value " + AString::number(*foundOffset)); } } else { validateString.appendWithNewLine("IJK (" + AString::fromNumbers(vm.m_ijk, 3, ",") + " should have lookup value " + AString::number(vm.m_ciftiIndex) + " but was not found."); } } if (validateString.isEmpty() == false) { CaretLogSevere("Sparse Indexer Errors:\n" + validateString); } } m_dataValid = true; } /** * Constructs instance with the given CIFTI Parcel Map. * * @param parcel * The CIFTI parcel map. */ SparseVolumeIndexer::SparseVolumeIndexer(const CiftiParcelsMap& ciftiParcelsMap) : CaretObject() { m_dataValid = false; if ( ! ciftiParcelsMap.hasVolumeData()) { return; } m_volumeSpace = ciftiParcelsMap.getVolumeSpace(); /* * Make sure orthogonal */ if ( ! m_volumeSpace.isPlumb()) { CaretLogWarning("CIFTI Volume is not Plumb!"); return; } const std::vector allParcels = ciftiParcelsMap.getParcels(); for (std::vector::const_iterator parcelIter = allParcels.begin(); parcelIter != allParcels.end(); parcelIter++) { const CiftiParcelsMap::Parcel& parcel = *parcelIter; // const int32_t numberOfCiftiVolumeVoxels = static_cast(parcel.m_voxelIndices.size()); // if (numberOfCiftiVolumeVoxels <= 0) { // return; // } // // const int64_t* dimIJK = m_volumeSpace.getDims(); // const int64_t numberOfVoxels = (dimIJK[0] * dimIJK[1] * dimIJK[2]); // if (numberOfVoxels <= 0) { // return; // } for (std::set::const_iterator iter = parcel.m_voxelIndices.begin(); iter != parcel.m_voxelIndices.end(); iter++) { const VoxelIJK& vm = *iter; m_voxelIndexLookup.at(vm.m_ijk) = ciftiParcelsMap.getIndexForVoxel(vm.m_ijk); } } // bool validateFlag = true; // if (validateFlag) { // AString validateString; // for (std::set::const_iterator iter = ciftiParcel.m_voxelIndices.begin(); // iter != ciftiParcel.m_voxelIndices.end(); // iter++) { // const VoxelIJK& vm = *iter; // const int64_t* foundOffset = m_voxelIndexLookup.find(vm.m_ijk); // const int64_t voxelOffset = ciftiParcelsMap.getIndexForVoxel(vm.m_ijk); // if (foundOffset != NULL) { // if (*foundOffset != voxelOffset) { // validateString.appendWithNewLine("IJK (" // + AString::fromNumbers(vm.m_ijk, 3, ",") // + " should have lookup value " // + AString::number(voxelOffset) // + " but has value " // + AString::number(*foundOffset)); // } // } // else { // validateString.appendWithNewLine("IJK (" // + AString::fromNumbers(vm.m_ijk, 3, ",") // + " should have lookup value " // + AString::number(voxelOffset) // + " but was not found."); // } // } // if (validateString.isEmpty() == false) { // CaretLogSevere("Sparse Indexer Errors:\n" // + validateString); // } // } m_dataValid = true; } /** * Destructor. */ SparseVolumeIndexer::~SparseVolumeIndexer() { } /** * @return True if this instance is valid. */ bool SparseVolumeIndexer::isValid() const { return m_dataValid; } /** * Get the offset for the given IJK indices. * * @param i * I index. * @param j * J index. * @param k * K index. * @return * Offset for given indices or -1 if no data for the given indices. */ int64_t SparseVolumeIndexer::getOffsetForIndices(const int64_t i, const int64_t j, const int64_t k) const { if (m_dataValid) { const int64_t* offset = m_voxelIndexLookup.find(i, j, k); if (offset != NULL) { return *offset; } } return -1; } /** * Convert the coordinates to volume indices. Any coordinates are accepted * and output indices are not necessarily within the volume. * * @param x * X coordinate. * @param y * y coordinate. * @param z * z coordinate. * @param iOut * I index. * @param jOut * J index. * @param kOut * K index. * @return * True if volume attributes (origin/spacing/dimensions) are valid. */ bool SparseVolumeIndexer::coordinateToIndices(const float x, const float y, const float z, int64_t& iOut, int64_t& jOut, int64_t& kOut) const { if (m_dataValid) { m_volumeSpace.enclosingVoxel(x, y, z, iOut, jOut, kOut); return true; } return false; } /** * Get the offset for the given XYZ coordinates. * * @param x * X coordinate. * @param y * y coordinate. * @param z * z coordinate. * @return * Offset for given coordinates or -1 if no data for the given coordinates. */ int64_t SparseVolumeIndexer::getOffsetForCoordinate(const float x, const float y, const float z) const { if (m_dataValid) { int64_t i, j, k; m_volumeSpace.enclosingVoxel(x, y, z, i, j, k); return getOffsetForIndices(i, j, k); } return -1; } /** * Get the XYZ coordinate for the given indices. * Any indices are accepted. * * @param i * I index. * @param j * J index. * @param k * K index. * @param xOut * X coordinate. * @param yOut * y coordinate. * @param zOut * z coordinate. * @return * True if volume attributes (origin/spacing/dimensions) are valid. */ bool SparseVolumeIndexer::indicesToCoordinate(const int64_t i, const int64_t j, const int64_t k, float& xOut, float& yOut, float& zOut) const { if (m_dataValid) { m_volumeSpace.indexToSpace(i, j, k, xOut, yOut, zOut); return true; } return false; } connectome-workbench-1.4.2/src/Files/SparseVolumeIndexer.h000066400000000000000000000060101360521144700235760ustar00rootroot00000000000000#ifndef __SPARSE_VOLUME_INDEXER_H__ #define __SPARSE_VOLUME_INDEXER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretCompact3DLookup.h" #include "CaretObject.h" #include "CiftiBrainModelsMap.h" #include "CiftiParcelsMap.h" #include "VolumeSpace.h" namespace caret { class SparseVolumeIndexer : public CaretObject { public: SparseVolumeIndexer(); SparseVolumeIndexer(const CiftiBrainModelsMap& ciftiBrainModelsMap); SparseVolumeIndexer(const CiftiParcelsMap& ciftiParcelsMap); virtual ~SparseVolumeIndexer(); bool isValid() const; bool coordinateToIndices(const float x, const float y, const float z, int64_t& iOut, int64_t& jOut, int64_t& kOut) const; bool indicesToCoordinate(const int64_t i, const int64_t j, const int64_t k, float& xOut, float& yOut, float& zOut) const; int64_t getOffsetForIndices(const int64_t i, const int64_t j, const int64_t k) const; int64_t getOffsetForCoordinate(const float x, const float y, const float z) const; inline const VolumeSpace& getVolumeSpace() const { return m_volumeSpace; } private: SparseVolumeIndexer(const SparseVolumeIndexer&); SparseVolumeIndexer& operator=(const SparseVolumeIndexer&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE bool m_dataValid; CaretCompact3DLookup m_voxelIndexLookup; VolumeSpace m_volumeSpace; }; #ifdef __SPARSE_VOLUME_INDEXER_DECLARE__ // #endif // __SPARSE_VOLUME_INDEXER_DECLARE__ } // namespace #endif //__SPARSE_VOLUME_INDEXER_H__ connectome-workbench-1.4.2/src/Files/SpecFile.cxx000066400000000000000000001654611360521144700217170ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPointer.h" #include "DataFileContentInformation.h" #include "DataFileException.h" #include "EventGetDisplayedDataFiles.h" #include "EventManager.h" #include "FileAdapter.h" #include "FileInformation.h" #include "GiftiMetaData.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" #define __SPEC_FILE_DEFINE__ #include "SpecFile.h" #undef __SPEC_FILE_DEFINE__ #include "SpecFileDataFile.h" #include "SpecFileDataFileTypeGroup.h" #include "SpecFileSaxReader.h" #include "StringTableModel.h" #include "SystemUtilities.h" #include "XmlSaxParser.h" #include "XmlWriter.h" using namespace caret; /** * \class caret::SpecFile * \brief A spec file groups caret data files. * \ingroup Files */ /** * Constructor. */ SpecFile::SpecFile() : CaretDataFile(DataFileTypeEnum::SPECIFICATION) { this->initializeSpecFile(); } /** * Destructor. */ SpecFile::~SpecFile() { for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { delete *iter; } this->dataFileTypeGroups.clear(); delete this->metadata; this->metadata = NULL; } /** * Copy constructor. * @param sf * Spec file whose data is copied. */ SpecFile::SpecFile(const SpecFile& sf) : CaretDataFile(sf) { this->initializeSpecFile(); this->copyHelperSpecFile(sf); } /** * Assignment operator. * @param sf * Spec file whose data is copied. * @return * Reference to this file. */ SpecFile& SpecFile::operator=(const SpecFile& sf) { if (this != &sf) { CaretDataFile::operator=(sf); this->copyHelperSpecFile(sf); } return *this; } /** * @return The structure for this file. */ StructureEnum::Enum SpecFile::getStructure() const { return StructureEnum::ALL; } /** * Set the structure for this file. * @param structure * New structure for this file. */ void SpecFile::setStructure(const StructureEnum::Enum /* structure */) { /* nothing since spec file not structure type file */ } /** * @return Get access to the file's metadata. */ GiftiMetaData* SpecFile::getFileMetaData() { return metadata; } /** * @return Get access to unmodifiable file's metadata. */ const GiftiMetaData* SpecFile::getFileMetaData() const { return metadata; } /** * Initialize this spec file. */ void SpecFile::initializeSpecFile() { this->metadata = new GiftiMetaData(); std::vector allEnums; DataFileTypeEnum::getAllEnums(allEnums, DataFileTypeEnum::OPTIONS_NONE); /* * Do surface files first since they need to be loaded before other files */ for (std::vector::iterator iter = allEnums.begin(); iter != allEnums.end(); iter++) { DataFileTypeEnum::Enum dataFileType = *iter; const AString typeName = DataFileTypeEnum::toName(dataFileType); if (typeName.startsWith("SURFACE")) { SpecFileDataFileTypeGroup* dftg = new SpecFileDataFileTypeGroup(dataFileType); this->dataFileTypeGroups.push_back(dftg); } } /* * Do remaining file types excluding surfaces */ for (std::vector::iterator iter = allEnums.begin(); iter != allEnums.end(); iter++) { DataFileTypeEnum::Enum dataFileType = *iter; if (dataFileType == DataFileTypeEnum::UNKNOWN) { // ignore } else { const AString typeName = DataFileTypeEnum::toName(dataFileType); if (typeName.startsWith("SURFACE") == false) { SpecFileDataFileTypeGroup* dftg = new SpecFileDataFileTypeGroup(dataFileType); this->dataFileTypeGroups.push_back(dftg); } } } } /** * Copy helper. * @param sf * Spec file whose data is copied. */ void SpecFile::copyHelperSpecFile(const SpecFile& sf) { this->clearData(); if (this->metadata != NULL) { delete this->metadata; } this->metadata = new GiftiMetaData(*sf.metadata); for (std::vector::const_iterator iter = sf.dataFileTypeGroups.begin(); iter != sf.dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* group = *iter; const int numFiles = group->getNumberOfFiles(); for (int32_t i = 0; i < numFiles; i++) { SpecFileDataFile* file = group->getFileInformation(i); this->addDataFile(group->getDataFileType(), file->getStructure(), file->getFileName(), file->isLoadingSelected(), file->isSavingSelected(), file->isSpecFileMember()); } } this->setFileName(sf.getFileName()); this->clearModified(); } /** * Change the name of a file. The existing SpecFileDataFile remains with * its CaretDataFile removed and a new SpecFileDataFile is created with * the CaretDataFile. * * @param specFileDataFile * The SpecFileDataFile that has its name changed. * @param newFileName * New name for file. * @return New SpecFileDataFile that is created or NULL if filename did not * change of there is an error. */ SpecFileDataFile* SpecFile::changeFileName(SpecFileDataFile* specFileDataFile, const AString& newFileName) { CaretAssert(specFileDataFile); /* * Make sure name changed. */ if (specFileDataFile->getFileName() == newFileName) { return NULL; } /* * Create a new SpecFileDataFile */ SpecFileDataFile* newSpecFileDataFile = new SpecFileDataFile(*specFileDataFile); newSpecFileDataFile->setFileName(newFileName); newSpecFileDataFile->setCaretDataFile(specFileDataFile->getCaretDataFile()); /* * Remove CaretDataFile from previous SpecFileDataFile */ specFileDataFile->setCaretDataFile(NULL); specFileDataFile->setSavingSelected(false); /* * Add new SpecFileDataFile to appropriate group. */ for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* group = *iter; if (group->getDataFileType() == newSpecFileDataFile->getDataFileType()) { group->addFileInformation(newSpecFileDataFile); return newSpecFileDataFile; } } CaretAssert(0); CaretLogSevere("PROGRAM ERROR: Failed to match DataFileType"); return NULL; } /** * Add a Caret Data File. * * @param If there is a a spec file entry with the same name as the Caret * Data File, the caret data file is added to the spec file entry. * Otherwise, a new Spec File Entry is created with the given Caret * Data File. * * @param caretDataFile * Caret data file that is added to, or creates, a spec file entry. */ void SpecFile::addCaretDataFile(CaretDataFile* caretDataFile) { CaretAssert(caretDataFile); if ( ! SpecFile::isDataFileTypeAllowedInSpecFile(caretDataFile->getDataFileType())) { return; } /* * Matches to first file found that has matching name and data file type */ SpecFileDataFile* matchedSpecFileDataFile = NULL; /* * Matches to first file found that has matching name and data file type * AND has its caret data file with a NULL value. */ SpecFileDataFile* matchedSpecFileDataFileWithNULL = NULL; /* * Group that matches data file type */ SpecFileDataFileTypeGroup* matchedDataFileTypeGroup = NULL; /* * Find matches */ for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; if (dataFileTypeGroup->getDataFileType() == caretDataFile->getDataFileType()) { matchedDataFileTypeGroup = dataFileTypeGroup; const int32_t numFiles = dataFileTypeGroup->getNumberOfFiles(); for (int32_t i = 0; i < numFiles; i++) { SpecFileDataFile* sfdf = dataFileTypeGroup->getFileInformation(i); if (sfdf->getCaretDataFile() == caretDataFile) { return; } if (sfdf->getFileName() == caretDataFile->getFileName()) { matchedSpecFileDataFile = sfdf; if (sfdf->getCaretDataFile() == NULL) { matchedSpecFileDataFileWithNULL = sfdf; break; } } } } if (matchedSpecFileDataFileWithNULL != NULL) { break; } } CaretAssert(matchedDataFileTypeGroup); SpecFileDataFile* specFileDataFileToUpdate = NULL; if (matchedSpecFileDataFileWithNULL != NULL) { /* * Found item that matched with a NULL value for caret data file */ specFileDataFileToUpdate = matchedSpecFileDataFileWithNULL; } else if (matchedSpecFileDataFile != NULL) { /* * Found item that matched but had non-NULL value for caret data file. * This means that there is a copy of a file loaded (two files same name) */ specFileDataFileToUpdate = new SpecFileDataFile(*matchedSpecFileDataFile); matchedDataFileTypeGroup->addFileInformation(specFileDataFileToUpdate); } else { /* * No matches found, file is not in spec file */ specFileDataFileToUpdate = new SpecFileDataFile(caretDataFile->getFileName(), caretDataFile->getDataFileType(), caretDataFile->getStructure(), false); matchedDataFileTypeGroup->addFileInformation(specFileDataFileToUpdate); } specFileDataFileToUpdate->setStructure(caretDataFile->getStructure()); specFileDataFileToUpdate->setCaretDataFile(caretDataFile); } /** * Remove a Caret Data File. * * @param If there is a a spec file entry with the given caret data file * remove it. Note: file has likely already been deleted so use only the * the caret data file pointer but to not deference it. * * @param caretDataFile * Caret data file that is removed from a spec file entry. */ void SpecFile::removeCaretDataFile(const CaretDataFile* caretDataFile) { CaretAssert(caretDataFile); /* * Get the entry */ for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; const int32_t numFiles = dataFileTypeGroup->getNumberOfFiles(); for (int32_t i = 0; i < numFiles; i++) { SpecFileDataFile* sfdf = dataFileTypeGroup->getFileInformation(i); if (sfdf->getCaretDataFile() == caretDataFile) { sfdf->setCaretDataFile(NULL); return; } } } CaretLogSevere("Failed to remove CaretDataFile at address " + AString::number((qulonglong)caretDataFile) + " from SpecFile: " + getFileName()); } /** * Add a data file to this spec file. * * @param dataFileType * Type of data file. * @param structure * Structure of data file (not all files use structure). * @param filename * Name of the file. * @param fileLoadingSelectionStatus * Selection status for loading of the file. * @param fileSavingSelectionStatus * Selection status for saving of the file. * @param specFileMemberStatus * True if the file is a member of the spec file and is written * into the spec file. * * @throws DataFileException * If data file type is UNKNOWN. */ void SpecFile::addDataFile(const DataFileTypeEnum::Enum dataFileType, const StructureEnum::Enum structure, const AString& filename, const bool fileLoadingSelectionStatus, const bool fileSavingSelectionStatus, const bool specFileMemberStatus) { addDataFilePrivate(dataFileType, structure, filename, fileLoadingSelectionStatus, fileSavingSelectionStatus, specFileMemberStatus); } /** * Add a data file to this spec file. * * @param dataFileType * Type of data file. * @param structure * Structure of data file (not all files use structure). * @param filename * Name of the file. * @param fileLoadingSelectionStatus * Selection status for loading of the file. * @param fileSavingSelectionStatus * Selection status for saving of the file. * @param specFileMemberStatus * True if the file is a member of the spec file and is written * into the spec file. * @return * SpecFileDataFile that was created or matched. NULL if error or file type not allowed. * * @throws DataFileException * If data file type is UNKNOWN. */ SpecFileDataFile* SpecFile::addDataFilePrivate(const DataFileTypeEnum::Enum dataFileType, const StructureEnum::Enum structure, const AString& filename, const bool fileLoadingSelectionStatus, const bool fileSavingSelectionStatus, const bool specFileMemberStatus) { if ( ! SpecFile::isDataFileTypeAllowedInSpecFile(dataFileType)) { return NULL; } AString name = filename; const bool dataFileOnNetwork = DataFile::isFileOnNetwork(name); //NOTE: the spec file's location is completely irrelevant to this operation! if (!dataFileOnNetwork) { FileInformation fileInfo(name); if (fileInfo.isRelative()) { name = fileInfo.getAbsoluteFilePath(); } }//if it is on the network, don't modify it // const AString message = ("After adding, " // + filename // + " becomes " // + name); // CaretLogFine(message); // if (this->getFileName().isEmpty() == false) { // name = SystemUtilities::relativePath(name, FileInformation(this->getFileName()).getPathName()); // } for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; if (dataFileTypeGroup->getDataFileType() == dataFileType) { /* * If already in file, no need to add it a second time but do update * its selection status if new entry has file selected */ const int32_t numFiles = dataFileTypeGroup->getNumberOfFiles(); for (int32_t i = 0; i < numFiles; i++) { SpecFileDataFile* sfdf = dataFileTypeGroup->getFileInformation(i); if (sfdf->getFileName() == name) { if (fileLoadingSelectionStatus) { sfdf->setLoadingSelected(fileLoadingSelectionStatus); } if (fileSavingSelectionStatus) { sfdf->setSavingSelected(fileSavingSelectionStatus); } return sfdf; } } SpecFileDataFile* sfdf = new SpecFileDataFile(name, dataFileType, structure, specFileMemberStatus); sfdf->setLoadingSelected(fileLoadingSelectionStatus); sfdf->setSavingSelected(fileSavingSelectionStatus); dataFileTypeGroup->addFileInformation(sfdf); return sfdf; } } DataFileException e(getFileName(), "Data File Type: " + DataFileTypeEnum::toName(dataFileType) + " not allowed " + " for file " + filename); CaretLogThrowing(e); throw e; return NULL; // will never get here since exception thrown } ///** // * @return ALL of the connectivity file types (NEVER delete contents of returned vector. // */ //void //SpecFile::getAllConnectivityFileTypes(std::vector& connectivityDataFilesOut) //{ // connectivityDataFilesOut.clear(); // // for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); // iter != dataFileTypeGroups.end(); // iter++) { // SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; // if (DataFileTypeEnum::isConnectivityDataType(dataFileTypeGroup->getDataFileType())) { // const int32_t numFiles = dataFileTypeGroup->getNumberOfFiles(); // for (int32_t i = 0; i < numFiles; i++) { // connectivityDataFilesOut.push_back(dataFileTypeGroup->getFileInformation(i)); // } // } // } //} /** * Set the selection status of a data file. * @param dataFileTypeName * Name of type of data file. * @param structure * Name of Structure of data file (not all files use structure). * @param filename * Name of the file. * @param fileSelectionStatus * Selection status of file. */ void SpecFile::setFileLoadingSelectionStatus(const DataFileTypeEnum::Enum dataFileType, const StructureEnum::Enum structure, const AString& filename, const bool fileSelectionStatus) { for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; if (dataFileTypeGroup->getDataFileType() == dataFileType) { const int32_t numFiles = dataFileTypeGroup->getNumberOfFiles(); for (int32_t i = 0; i < numFiles; i++) { SpecFileDataFile* sfdf = dataFileTypeGroup->getFileInformation(i); if (sfdf->getStructure() == structure) { if (sfdf->getFileName().endsWith(filename)) { sfdf->setLoadingSelected(fileSelectionStatus); } } } } } } /** * Add a data file to this spec file. * @param dataFileTypeName * Name of type of data file. * @param structure * Name of Structure of data file (not all files use structure). * @param filename * Name of the file. * @param fileLoadingSelectionStatus * Selection status for loading of file. * @param fileSavingSelectionStatus * Selection status for saving of file. * @param specFileMemberStatus * True if the file is a member of the spec file and is written * into the spec file. * * @throws DataFileException * If data file type is UNKNOWN. */ void SpecFile::addDataFile(const AString& dataFileTypeName, const AString& structureName, const AString& filename, const bool fileLoadingSelectionStatus, const bool fileSavingSelectionStatus, const bool specFileMemberStatus) { bool validType = false; DataFileTypeEnum::Enum dataFileType = DataFileTypeEnum::fromName(dataFileTypeName, &validType); bool validStructure = false; StructureEnum::Enum structure = StructureEnum::fromGuiName(structureName, &validStructure); this->addDataFilePrivate(dataFileType, structure, filename, fileLoadingSelectionStatus, fileSavingSelectionStatus, specFileMemberStatus); } /** * Clear the file.. */ void SpecFile::clear() { DataFile::clear(); this->clearData(); } /** * Clear the spec file's data as if there were no files loaded. */ void SpecFile::clearData() { this->metadata->clear(); /* * Do not clear the vector, just remove file information from all types */ for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; dataFileTypeGroup->removeAllFileInformation(); } } /** * Is this file empty? * * @return true if file is empty, else false. */ bool SpecFile::isEmpty() const { return (this->getNumberOfFiles() <= 0); } /** * @return The number of files. */ int32_t SpecFile::getNumberOfFiles() const { int count = 0; for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; count += dataFileTypeGroup->getNumberOfFiles(); } return count; } /** * @return The number of files selected for loading. */ int32_t SpecFile::getNumberOfFilesSelectedForLoading() const { int count = 0; for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; count += dataFileTypeGroup->getNumberOfFilesSelectedForLoading(); } return count; } /** * @return The number of files selected for saving. */ int32_t SpecFile::getNumberOfFilesSelectedForSaving() const { int count = 0; for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; count += dataFileTypeGroup->getNumberOfFilesSelectedForSaving(); } return count; } /** * @return True if there is at least one file with a remote path * (http...) AND the file is selected for loading. */ bool SpecFile::hasFilesWithRemotePathSelectedForLoading() const { for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { const SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; const int32_t numFiles = dataFileTypeGroup->getNumberOfFiles(); for (int32_t i = 0; i < numFiles; i++) { const SpecFileDataFile* sfdf = dataFileTypeGroup->getFileInformation(i); if (sfdf->isLoadingSelected()) { if (DataFile::isFileOnNetwork(sfdf->getFileName())) { return true; } } } } return false; } /** * @return A vector containing all file names selected for loading. */ std::vector SpecFile::getAllDataFileNamesSelectedForLoading() const { std::vector allFileNames; for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; const int32_t numFiles = dataFileTypeGroup->getNumberOfFiles(); for (int32_t i = 0; i < numFiles; i++) { if (dataFileTypeGroup->getFileInformation(i)->isLoadingSelected()) { const AString filename = dataFileTypeGroup->getFileInformation(i)->getFileName(); allFileNames.push_back(filename); } } } return allFileNames; } /** * @return A vector containing all file names. */ std::vector SpecFile::getAllDataFileNames() const { std::vector allFileNames; for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; const int32_t numFiles = dataFileTypeGroup->getNumberOfFiles(); for (int32_t i = 0; i < numFiles; i++) { const AString filename = dataFileTypeGroup->getFileInformation(i)->getFileName(); allFileNames.push_back(filename); } } return allFileNames; } /** * @return True if the only files selected for loading are scene files. */ bool SpecFile::areAllFilesSelectedForLoadingSceneFiles() const { int32_t sceneFileCount = 0; int32_t allFilesCount = 0; for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; allFilesCount += dataFileTypeGroup->getNumberOfFilesSelectedForLoading(); if (dataFileTypeGroup->getDataFileType() == DataFileTypeEnum::SCENE) { sceneFileCount += dataFileTypeGroup->getNumberOfFilesSelectedForLoading(); } } if (sceneFileCount > 0) { if (sceneFileCount == allFilesCount) { return true; } } return false; } /** * Remove any files that are not "in spec" and do not have an * associated caret data file. */ void SpecFile::removeAnyFileInformationIfNotInSpecAndNoCaretDataFile() { for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; dataFileTypeGroup->removeFileInformationIfNotInSpecAndNoCaretDataFile(); } setModified(); } /** * Read the file. * * @param filenameIn * Name of file to read. * * @throws DataFileException * If there is an error reading the file. */ void SpecFile::readFile(const AString& filenameIn) { clear(); AString filename = filenameIn; if (DataFile::isFileOnNetwork(filename) == false) { FileInformation specInfo(filename); filename = specInfo.getAbsoluteFilePath(); } this->setFileName(filename); checkFileReadability(filename); SpecFileSaxReader saxReader(this); std::unique_ptr parser(XmlSaxParser::createXmlParser()); try { parser->parseFile(filename, &saxReader); } catch (const XmlSaxParserException& e) { clear(); this->setFileName(""); int lineNum = e.getLineNumber(); int colNum = e.getColumnNumber(); AString msg = "Parse Error while reading:"; if ((lineNum >= 0) && (colNum >= 0)) { msg += (" line/col (" + AString::number(e.getLineNumber()) + "/" + AString::number(e.getColumnNumber()) + ")"); } msg += (": " + e.whatString()); DataFileException dfe(filename, msg); CaretLogThrowing(dfe); throw dfe; } this->setFileName(filename); this->setAllFilesSelectedForLoading(true); this->setAllFilesSelectedForSaving(false); this->clearModified(); } /** * Read the spec file from a string containing the files content. * @param string * String containing the file's content. * @throws DataFileException * If there is an error reading the file from the string. */ void SpecFile::readFileFromString(const AString& string) { SpecFileSaxReader saxReader(this); std::unique_ptr parser(XmlSaxParser::createXmlParser()); try { parser->parseString(string, &saxReader); } catch (const XmlSaxParserException& e) { clear(); this->setFileName(""); int lineNum = e.getLineNumber(); int colNum = e.getColumnNumber(); AString msg = "Parse Error while reading Spec File from string."; if ((lineNum >= 0) && (colNum >= 0)) { msg += (" line/col (" + AString::number(e.getLineNumber()) + "/" + AString::number(e.getColumnNumber()) + ")"); } msg += (": " + e.whatString()); DataFileException dfe(getFileName(), msg); CaretLogThrowing(dfe); throw dfe; } this->clearModified(); } /** * Write the file. * * @param filename * Name of file to read. * * @throws DataFileException * If there is an error writing the file. */ void SpecFile::writeFile(const AString& filename) { if (!(filename.endsWith(".spec") || filename.endsWith(".wb_spec"))) { CaretLogWarning("spec file '" + filename + "' should be saved ending in .spec"); } checkFileWritability(filename); FileInformation specInfo(filename); AString absFileName = specInfo.getAbsoluteFilePath(); this->setFileName(absFileName); try { // // Format the version string so that it ends with at most one zero // const AString versionString = AString::number(1.0); // // Open the file // FileAdapter file; AString errorMessage; QTextStream* textStream = file.openQTextStreamForWritingFile(this->getFileName(), errorMessage); if (textStream == NULL) { throw DataFileException(getFileName(), errorMessage); } // // Create the xml writer // XmlWriter xmlWriter(*textStream); /* * Write the XML and include metadata */ this->writeFileContentToXML(xmlWriter, WRITE_META_DATA_YES, WRITE_IN_SPEC_FILES); file.close(); this->clearModified(); } catch (const GiftiException& e) { throw DataFileException(getFileName(), e.whatString()); } catch (const XmlException& e) { throw DataFileException(getFileName(), e.whatString()); } } /** * Write the file's content to the XML Writer. * @param xmlWriter * XML Writer to which file content is written. * @param writeMetaDataStatus * Yes of no to write metadata. * @throws DataFileException * If there is an error writing to the XML writer. */ void SpecFile::writeFileContentToXML(XmlWriter& xmlWriter, const WriteMetaDataType writeMetaDataStatus, const WriteFilesSelectedType writeFilesSelectedStatus) { // // Write header info // xmlWriter.writeStartDocument("1.0"); // // Write GIFTI root element // XmlAttributes attributes; //attributes.addAttribute("xmlns:xsi", // "http://www.w3.org/2001/XMLSchema-instance"); //attributes.addAttribute("xsi:noNamespaceSchemaLocation", // "http://brainvis.wustl.edu/caret6/xml_schemas/GIFTI_Caret.xsd"); attributes.addAttribute(SpecFile::XML_ATTRIBUTE_VERSION, SpecFile::getFileVersionAsString()); xmlWriter.writeStartElement(SpecFile::XML_TAG_SPEC_FILE, attributes); // // Write Metadata // if (writeMetaDataStatus == WRITE_META_DATA_YES) { if (metadata != NULL) { metadata->writeAsXML(xmlWriter); } } // // Write files // const int32_t numGroups = this->getNumberOfDataFileTypeGroups(); for (int32_t i = 0; i < numGroups; i++) { SpecFileDataFileTypeGroup* group = this->getDataFileTypeGroupByIndex(i); const int32_t numFiles = group->getNumberOfFiles(); for (int32_t j = 0; j < numFiles; j++) { SpecFileDataFile* file = group->getFileInformation(j); bool writeIt = true; switch (writeFilesSelectedStatus) { case WRITE_ALL_FILES: break; case WRITE_IN_SPEC_FILES: writeIt = file->isSpecFileMember(); break; } if (writeIt) { const AString name = updateFileNameAndPathForWriting(file->getFileName()); XmlAttributes atts; atts.addAttribute(SpecFile::XML_ATTRIBUTE_STRUCTURE, StructureEnum::toGuiName(file->getStructure())); atts.addAttribute(SpecFile::XML_ATTRIBUTE_DATA_FILE_TYPE, DataFileTypeEnum::toName(group->getDataFileType())); atts.addAttribute(SpecFile::XML_ATTRIBUTE_SELECTED, file->isLoadingSelected()); xmlWriter.writeStartElement(SpecFile::XML_TAG_DATA_FILE, atts); xmlWriter.writeCharacters(" " + name + "\n"); xmlWriter.writeEndElement(); } } } xmlWriter.writeEndElement(); xmlWriter.writeEndDocument(); } /** * Update the file name for writing to a spec file * (makes file relative to spec file location). */ AString SpecFile::updateFileNameAndPathForWriting(const AString& dataFileNameIn) { AString dataFileName = dataFileNameIn; FileInformation fileInfo(dataFileName); if (fileInfo.isAbsolute()) { const AString specFileName = getFileName(); FileInformation specFileInfo(specFileName); if (specFileInfo.isAbsolute()) { const AString newPath = SystemUtilities::relativePath(fileInfo.getPathName(), specFileInfo.getPathName()); if (newPath.isEmpty()) { dataFileName = fileInfo.getFileName(); } else { dataFileName = (newPath + "/" + fileInfo.getFileName()); } } } AString message = ("When writing, " + dataFileNameIn + " becomes " + dataFileName); CaretLogFine(message); return dataFileName; } /** * Write the file to a XML string. * @param writeMetaDataStatus * Write the metadata to the file. * @return * String containing XML. * @throws DataFileException * If error writing to XML. */ //AString //SpecFile::writeFileToString(const WriteMetaDataType writeMetaDataStatus, // const WriteFilesSelectedType writeFilesSelectedStatus) //{ // /* // * Create a TextStream that writes to a string. // */ // AString xmlString; // QTextStream textStream(&xmlString); // // /* // * Create the xml writer // */ // XmlWriter xmlWriter(textStream); // // /* // * Write file to XML. // */ // this->writeFileContentToXML(xmlWriter, // writeMetaDataStatus, // writeFilesSelectedStatus); // // return xmlString; //} /** * Get information about this file's contents. * @return * Information about the file's contents. */ AString SpecFile::toString() const { AString info = "name=" + this->getFileName() + "\n"; info += this->metadata->toString() + "\n"; for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; info += (dataFileTypeGroup->toString() + "\n"); } return info; } /** * @return The number of data file type groups. */ int32_t SpecFile::getNumberOfDataFileTypeGroups() const { return this->dataFileTypeGroups.size(); } /** * Get the data file type group for the given index. * @param dataFileTypeGroupIndex * Index of data file type group. * @return Data file type group at given index. */ SpecFileDataFileTypeGroup* SpecFile::getDataFileTypeGroupByIndex(const int32_t dataFileTypeGroupIndex) { CaretAssertVectorIndex(this->dataFileTypeGroups, dataFileTypeGroupIndex); return this->dataFileTypeGroups[dataFileTypeGroupIndex]; } /** * Get the data file type group for the given index. * @param dataFileTypeGroupIndex * Index of data file type group. * @return Data file type group at given index. */ const SpecFileDataFileTypeGroup* SpecFile::getDataFileTypeGroupByIndex(const int32_t dataFileTypeGroupIndex) const { CaretAssertVectorIndex(this->dataFileTypeGroups, dataFileTypeGroupIndex); return this->dataFileTypeGroups[dataFileTypeGroupIndex]; } /** * Get the data file type group for the given data file type. * @param dataFileType * Data file type requested. * @return Data file type group for requested data file type or * NULL if no matching item found. */ SpecFileDataFileTypeGroup* SpecFile::getDataFileTypeGroupByType(const DataFileTypeEnum::Enum dataFileType) const { for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; if (dataFileTypeGroup->getDataFileType() == dataFileType) { return dataFileTypeGroup; } } return NULL; } /** * Set all file's selection status for loading. * @param selected * New selection status for loading. */ void SpecFile::setAllFilesSelectedForLoading(bool selectionStatus) { for (std::vector::iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; dataFileTypeGroup->setAllFilesSelectedForLoading(selectionStatus); } } /** * Set all file's selection status for saving. * @param selected * New selection status for saving. */ void SpecFile::setAllFilesSelectedForSaving(bool selectionStatus) { for (std::vector::iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; dataFileTypeGroup->setAllFilesSelectedForSaving(selectionStatus); } } /** * Set all scene files selected and all other files not selected. */ void SpecFile::setAllSceneFilesSelectedForLoadingAndAllOtherFilesNotSelected() { for (std::vector::iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; const bool selectionStatus = (dataFileTypeGroup->getDataFileType() == DataFileTypeEnum::SCENE); dataFileTypeGroup->setAllFilesSelectedForLoading(selectionStatus); } } /** * Set the save status to on for any files that are modified. */ void SpecFile::setModifiedFilesSelectedForSaving() { for (std::vector::iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; dataFileTypeGroup->setModifiedFilesSelectedForSaving(); } } /** * Get the file information for the file with the given name. * * @param fileName * Name of the data file. * @return * File information for the file or NULL if not found. */ const SpecFileDataFile* SpecFile::getFileInfoFromFileName(const AString& fileName) const { for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; const int32_t numFiles = dataFileTypeGroup->getNumberOfFiles(); for (int32_t i = 0; i < numFiles; i++) { SpecFileDataFile* dataFileInfo = dataFileTypeGroup->getFileInformation(i); if (fileName == dataFileInfo->getFileName()) { return dataFileInfo; } } } return NULL; } /** * Transfer the "in spec" status for all data files from the * given spec file to this spec file. Files are matched by * data file type and absolute path file name. * * The spec file names MUST match, else no action is taken. * * @param specFile * Spec file from which in spec statuses are copied. */ void SpecFile::transferDataFilesInSpecStatus(const SpecFile& specFile) { if (getFileName() != specFile.getFileName()) { return; } for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; const int32_t numFiles = dataFileTypeGroup->getNumberOfFiles(); for (int32_t i = 0; i < numFiles; i++) { SpecFileDataFile* dataFileInfo = dataFileTypeGroup->getFileInformation(i); const AString fileName = dataFileInfo->getFileName(); FileInformation fileInfo(fileName); if (fileInfo.exists() && (fileInfo.isAbsolute())) { const SpecFileDataFile* copyFromDataFileInfo = specFile.getFileInfoFromFileName(fileName); if (copyFromDataFileInfo != NULL) { dataFileInfo->setSpecFileMember(copyFromDataFileInfo->isSpecFileMember()); } } } } } /** * @return The version of the file as a number. */ float SpecFile::getFileVersion() { return SpecFile::specFileVersion; } /** * @return The version of the file as a string. */ AString SpecFile::getFileVersionAsString() { return AString::number(SpecFile::specFileVersion, 'f', 1); } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of the class' instance. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* SpecFile::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "SpecFile", 1); AString specFileNameForScene; if (sceneAttributes->isSpecFileNameSavedToScene()) { specFileNameForScene = getFileName(); } const bool allLoadedFilesFlag = sceneAttributes->isAllLoadedFilesSavedToScene(); std::set displayedDataFiles; if ( ! allLoadedFilesFlag) { const std::vector tabIndicesForScene = sceneAttributes->getIndicesOfTabsForSavingToScene(); const std::vector windowIndicesForScene = sceneAttributes->getIndicesOfWindowsForSavingToScene(); EventGetDisplayedDataFiles displayedFilesEvent(windowIndicesForScene, tabIndicesForScene); EventManager::get()->sendEvent(displayedFilesEvent.getPointer()); displayedDataFiles = displayedFilesEvent.getDisplayedDataFiles(); } sceneClass->addPathName("specFileName", specFileNameForScene); std::vector dataFileClasses; // // Write files (except Scene and Palette files) // const int32_t numGroups = this->getNumberOfDataFileTypeGroups(); for (int32_t i = 0; i < numGroups; i++) { SpecFileDataFileTypeGroup* group = this->getDataFileTypeGroupByIndex(i); const DataFileTypeEnum::Enum dataFileType = group->getDataFileType(); if (dataFileType == DataFileTypeEnum::SCENE) { //CaretLogInfo("Note: Scene files not added to scene at this time"); } else if (dataFileType == DataFileTypeEnum::PALETTE) { CaretLogInfo("Note: Palette files not added to scene at this time"); } else { const int32_t numFiles = group->getNumberOfFiles(); for (int32_t j = 0; j < numFiles; j++) { SpecFileDataFile* file = group->getFileInformation(j); /* * Only write files that are loaded (indicated by its * "caretDataFile" not NULL. */ const CaretDataFile* caretDataFile = file->getCaretDataFile(); if (caretDataFile != NULL) { bool addFileToSceneFlag = false; if (allLoadedFilesFlag) { addFileToSceneFlag = true; } else { if (displayedDataFiles.find(caretDataFile) != displayedDataFiles.end()) { addFileToSceneFlag = true; } } if (addFileToSceneFlag) { SceneClass* fileClass = new SceneClass("specFileDataFile", "SpecFileDataFile", 1); fileClass->addEnumeratedType("dataFileType", dataFileType); fileClass->addEnumeratedType("structure", file->getStructure()); const AString name = updateFileNameAndPathForWriting(file->getFileName()); fileClass->addPathName("fileName", file->getFileName()); fileClass->addBoolean("selected", file->isLoadingSelected()); dataFileClasses.push_back(fileClass); } } } } } sceneClass->addChild(new SceneClassArray("dataFilesArray", dataFileClasses)); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void SpecFile::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } this->clear(); const AString specFileName = sceneClass->getPathNameValue("specFileName", ""); this->setFileName(specFileName); /* * If spec file name is path to a valid file, * load the spec file and then deselect all * of the files in the spec file. Since the * scene may contain a subset of the files in * the spec file, not doing this would result * in the spec file missing data file if the * user saves files after loading the scene. */ if (specFileName.isEmpty() == false) { FileInformation specFileInfo(specFileName); if (specFileInfo.exists()) { try { readFile(specFileName); } catch (const DataFileException& e) { sceneAttributes->addToErrorMessage("Error reading spec file " + specFileName + " for displaying scene: " + e.whatString()); } setAllFilesSelectedForLoading(false); setAllFilesSelectedForSaving(false); } } const SceneClassArray* dataFileClassArray = sceneClass->getClassArray("dataFilesArray"); if (dataFileClassArray != NULL) { const int32_t numberOfFiles = dataFileClassArray->getNumberOfArrayElements(); for (int32_t i = 0; i < numberOfFiles; i++) { const SceneClass* dataFileClass = dataFileClassArray->getClassAtIndex(i); const bool selectedForLoading = dataFileClass->getBooleanValue("selected"); const AString dataFileName = dataFileClass->getPathNameValue("fileName"); const DataFileTypeEnum::Enum dataFileType = dataFileClass->getEnumeratedTypeValue("dataFileType", DataFileTypeEnum::UNKNOWN); const StructureEnum::Enum structure = dataFileClass->getEnumeratedTypeValue("structure", StructureEnum::INVALID); this->addDataFile(dataFileType, structure, dataFileName, selectedForLoading, false, // not selected for saving true); } } } /** * Append content of a spec file to this spec file. * @param toAppend * Spec file that is appended. */ void SpecFile::appendSpecFile(const SpecFile& toAppend) { int numOtherGroups = (int)toAppend.dataFileTypeGroups.size(); AString otherDirectory = FileInformation(toAppend.getFileName()).getAbsolutePath();//hopefully the filename is already absolute, if it isn't and we changed directory, we can't recover the correct path if (!otherDirectory.endsWith('/'))//deal with the root directory { otherDirectory += "/"; } for (int i = 0; i < numOtherGroups; ++i) { const SpecFileDataFileTypeGroup* thisGroup = toAppend.dataFileTypeGroups[i]; int numOtherFiles = thisGroup->getNumberOfFiles(); for (int j = 0; j < numOtherFiles; ++j) { const SpecFileDataFile* fileData = thisGroup->getFileInformation(j); AString fileName = fileData->getFileName(); FileInformation fileInfo(fileName);//do not trust exists, we don't have the right working directory, this is ONLY to check whether the path is absolute if (fileInfo.isRelative()) { fileName = otherDirectory + fileName;//don't trust the file to exist from current directory, use string manipulation only } addDataFile(thisGroup->getDataFileType(), fileData->getStructure(), fileName, fileData->isLoadingSelected(), fileData->isSavingSelected(), fileData->isSpecFileMember());//absolute paths should get converted to relative on writing } } } /** * Set this file modified. */ void SpecFile::setModified() { CaretDataFile::setModified(); } /** * @return true if this file has been modified. */ bool SpecFile::isModified() const { if (CaretDataFile::isModified()) { return true; } for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { const SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; if (dataFileTypeGroup->isModified()) { return true; } } return false; } /** * Clear the modification status. */ void SpecFile::clearModified() { CaretDataFile::clearModified(); for (std::vector::iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; dataFileTypeGroup->clearModified(); } } /** * Add information about the file to the data file information. * * @param dataFileInformation * Consolidates information about a data file. */ void SpecFile::addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) { CaretDataFile::addToDataFileContentInformation(dataFileInformation); const int32_t numberOfFiles = getNumberOfFiles(); if (numberOfFiles <= 0) { return; } int32_t columnCounter = 0; const int32_t COL_TYPE = columnCounter++; const int32_t COL_STRUCTURE = columnCounter++; const int32_t COL_NAME = columnCounter++; const int32_t COL_PATH = columnCounter++; StringTableModel table((numberOfFiles + 1), columnCounter); int32_t rowIndex = 0; table.setElement(rowIndex, COL_TYPE, "TYPE"); table.setElement(rowIndex, COL_STRUCTURE, "STRUCTURE"); table.setElement(rowIndex, COL_NAME, "NAME"); table.setElement(rowIndex, COL_PATH, "PATH"); rowIndex++; table.setColumnAlignment(COL_TYPE, StringTableModel::ALIGN_LEFT); table.setColumnAlignment(COL_STRUCTURE, StringTableModel::ALIGN_LEFT); table.setColumnAlignment(COL_NAME, StringTableModel::ALIGN_LEFT); table.setColumnAlignment(COL_PATH, StringTableModel::ALIGN_LEFT); for (std::vector::const_iterator iter = dataFileTypeGroups.begin(); iter != dataFileTypeGroups.end(); iter++) { SpecFileDataFileTypeGroup* dataFileTypeGroup = *iter; const DataFileTypeEnum::Enum dataFileType = dataFileTypeGroup->getDataFileType(); const int32_t numFiles = dataFileTypeGroup->getNumberOfFiles(); for (int32_t i = 0; i < numFiles; i++) { SpecFileDataFile* sfdf = dataFileTypeGroup->getFileInformation(i); FileInformation fileInfo(sfdf->getFileName()); table.setElement(rowIndex, COL_TYPE, DataFileTypeEnum::toGuiName(dataFileType)); table.setElement(rowIndex, COL_STRUCTURE, StructureEnum::toGuiName(sfdf->getStructure())); table.setElement(rowIndex, COL_NAME, fileInfo.getFileName()); table.setElement(rowIndex, COL_PATH, fileInfo.getPathName()); rowIndex++; } } dataFileInformation.addText("\n" + table.getInString()); } /** * Is the given file type allowed in the spec file? * * @param dataFileType * Type of data file. * @return * True if allowed in spec file, else false. */ bool SpecFile::isDataFileTypeAllowedInSpecFile(const DataFileTypeEnum::Enum dataFileType) { bool allowedFlag(true); switch (dataFileType) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: allowedFlag = false; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: break; case DataFileTypeEnum::METRIC: break; case DataFileTypeEnum::METRIC_DYNAMIC: allowedFlag = false; break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: allowedFlag = false; break; } return allowedFlag; } connectome-workbench-1.4.2/src/Files/SpecFile.h000066400000000000000000000206311360521144700213310ustar00rootroot00000000000000#ifndef __SPEC_FILE_H__ #define __SPEC_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretDataFile.h" #include "DataFileTypeEnum.h" #include "StructureEnum.h" namespace caret { class GiftiMetaData; class SpecFileDataFile; class SpecFileDataFileTypeGroup; class XmlWriter; class SpecFile : public CaretDataFile { public: SpecFile(); virtual ~SpecFile(); SpecFile(const SpecFile&); SpecFile& operator=(const SpecFile&); public: virtual void clear(); virtual bool isEmpty() const; virtual StructureEnum::Enum getStructure() const; virtual void setStructure(const StructureEnum::Enum structure); virtual GiftiMetaData* getFileMetaData(); virtual const GiftiMetaData* getFileMetaData() const; virtual void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation); void addCaretDataFile(CaretDataFile* caretDataFile); void removeCaretDataFile(const CaretDataFile* caretDataFile); SpecFileDataFile* changeFileName(SpecFileDataFile* specFileDataFile, const AString& newFileName); void addDataFile(const DataFileTypeEnum::Enum dataFileType, const StructureEnum::Enum structure, const AString& filename, const bool fileLoadingSelectionStatus, const bool fileSavingSelectionStatus, const bool specFileMemberStatus); void addDataFile(const AString& dataFileTypeName, const AString& structureName, const AString& filename, const bool fileLoadingSelectionStatus, const bool fileSavingSelectionStatus, const bool specFileMemberStatus); void setFileLoadingSelectionStatus(const DataFileTypeEnum::Enum dataFileType, const StructureEnum::Enum structure, const AString& filename, const bool fileSelectionStatus); bool hasFilesWithRemotePathSelectedForLoading() const; int32_t getNumberOfFiles() const; int32_t getNumberOfFilesSelectedForLoading() const; int32_t getNumberOfFilesSelectedForSaving() const; std::vector getAllDataFileNames() const; std::vector getAllDataFileNamesSelectedForLoading() const; bool areAllFilesSelectedForLoadingSceneFiles() const; void removeAnyFileInformationIfNotInSpecAndNoCaretDataFile(); virtual void readFile(const AString& filename); virtual void writeFile(const AString& filename); virtual AString toString() const; AString getText() const; void transferDataFilesInSpecStatus(const SpecFile& specFile); int32_t getNumberOfDataFileTypeGroups() const; SpecFileDataFileTypeGroup* getDataFileTypeGroupByIndex(const int32_t dataFileTypeGroupIndex); const SpecFileDataFileTypeGroup* getDataFileTypeGroupByIndex(const int32_t dataFileTypeGroupIndex) const; SpecFileDataFileTypeGroup* getDataFileTypeGroupByType(const DataFileTypeEnum::Enum dataFileType) const; const SpecFileDataFile* getFileInfoFromFileName(const AString& fileName) const; // void getAllConnectivityFileTypes(std::vector& connectivityDataFiles); void setAllFilesSelectedForLoading(bool selectionStatus); void setAllFilesSelectedForSaving(bool selectionStatus); void setAllSceneFilesSelectedForLoadingAndAllOtherFilesNotSelected(); void setModifiedFilesSelectedForSaving(); static float getFileVersion(); static AString getFileVersionAsString(); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); void appendSpecFile(const SpecFile& toAppend); virtual void setModified(); virtual bool isModified() const; virtual void clearModified(); static bool isDataFileTypeAllowedInSpecFile(const DataFileTypeEnum::Enum dataFileType); /** XML Tag for SpecFile element */ static const AString XML_TAG_SPEC_FILE; /** XML Tag for DataFile element */ static const AString XML_TAG_DATA_FILE; /** XML Tag for Structure attribute */ static const AString XML_ATTRIBUTE_STRUCTURE; /** XML Tag for DataFileType attribute */ static const AString XML_ATTRIBUTE_DATA_FILE_TYPE; /** XML Tag for data file selection status */ static const AString XML_ATTRIBUTE_SELECTED; /** XML Tag for Version attribute */ static const AString XML_ATTRIBUTE_VERSION; /** Version of this SpecFile */ static const float specFileVersion; private: enum WriteMetaDataType { WRITE_META_DATA_YES, WRITE_META_DATA_NO }; enum WriteFilesSelectedType { WRITE_ALL_FILES, WRITE_IN_SPEC_FILES }; void copyHelperSpecFile(const SpecFile& sf); void initializeSpecFile(); void clearData(); SpecFileDataFile* addDataFilePrivate(const DataFileTypeEnum::Enum dataFileType, const StructureEnum::Enum structure, const AString& filename, const bool fileLoadingSelectionStatus, const bool fileSavingSelectionStatus, const bool specFileMemberStatus); void readFileFromString(const AString& string); AString updateFileNameAndPathForWriting(const AString& dataFileName); // AString writeFileToString(const WriteMetaDataType writeMetaDataStatus, // const WriteFilesSelectedType writeFilesSelectedStatus); void writeFileContentToXML(XmlWriter& xmlWriter, const WriteMetaDataType writeMetaDataStatus, const WriteFilesSelectedType writeFilesSelectedStatus); std::vector dataFileTypeGroups; GiftiMetaData* metadata; }; #ifdef __SPEC_FILE_DEFINE__ const AString SpecFile::XML_TAG_SPEC_FILE = "CaretSpecFile"; const AString SpecFile::XML_TAG_DATA_FILE = "DataFile"; const AString SpecFile::XML_ATTRIBUTE_STRUCTURE = "Structure"; const AString SpecFile::XML_ATTRIBUTE_DATA_FILE_TYPE = "DataFileType"; const AString SpecFile::XML_ATTRIBUTE_SELECTED = "Selected"; const AString SpecFile::XML_ATTRIBUTE_VERSION = "Version"; const float SpecFile::specFileVersion = 1.0; #endif // __SPEC_FILE_DEFINE__ } // namespace #endif // __SPEC_FILE_H__ connectome-workbench-1.4.2/src/Files/SpecFileDataFile.cxx000066400000000000000000000156021360521144700233000ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SPEC_FILE_GROUP_FILE_DECLARE__ #include "SpecFileDataFile.h" #undef __SPEC_FILE_GROUP_FILE_DECLARE__ #include "FileInformation.h" using namespace caret; /** * \class caret::SpecFileDataFile * \brief Name of file and its attributes including structure. * \ingroup Files * * Contains the name of a file and is attributes including * the file's structure. Note that not all files use a * structure. */ /** * Constructor. * * @param filename * Name of file. * @param dataFileType * Type of data file. * @param structure * Structure file represents (not all files have structure). * @param specFileMember * True if this file is a member of the spec file and is thus * written to the spec file. */ SpecFileDataFile::SpecFileDataFile(const AString& filename, const DataFileTypeEnum::Enum dataFileType, const StructureEnum::Enum structure, const bool specFileMember) : CaretObjectTracksModification() { m_caretDataFile = NULL; m_filename = filename; m_dataFileType = dataFileType; m_structure = structure; m_loadingSelected = true; m_savingSelected = false; m_specFileMember = specFileMember; } /** * Copy constructor. * @param sfdf * Object of this type that is copied. */ SpecFileDataFile::SpecFileDataFile(const SpecFileDataFile& sfdf) : CaretObjectTracksModification(sfdf) { copyHelper(sfdf); } /** * Assignment operator. * @parm sfdf * Object that is assigned to this object. * @return * Reference to this object. */ SpecFileDataFile& SpecFileDataFile::operator=(const SpecFileDataFile& sfdf) { if (this != &sfdf) { CaretObjectTracksModification::operator=(sfdf); copyHelper(sfdf); } return *this; } /** * Copy from the given object to this object. * @param sfdf * Object from which data is copied. */ void SpecFileDataFile::copyHelper(const SpecFileDataFile& sfdf) { m_caretDataFile = sfdf.m_caretDataFile; m_filename = sfdf.m_filename; m_dataFileType = sfdf.m_dataFileType; m_structure = sfdf.m_structure; m_loadingSelected = sfdf.m_loadingSelected; m_savingSelected = sfdf.m_savingSelected; m_specFileMember = sfdf.m_specFileMember; } /** * Destructor. */ SpecFileDataFile::~SpecFileDataFile() { } /** * @return The file's name; */ AString SpecFileDataFile::getFileName() const { if (m_caretDataFile != NULL) { m_filename = m_caretDataFile->getFileName(); } return m_filename; } void SpecFileDataFile::setFileName(const AString& fileName) { m_filename = fileName; if (m_caretDataFile != NULL) { m_caretDataFile->setFileName(fileName); } setModified(); } /** * @return The caret data file that is loaded for this spec file entry. * Will return NULL if the file has not been loaded. */ CaretDataFile* SpecFileDataFile::getCaretDataFile() { return m_caretDataFile; } /** * Set the caret data file for this spec file entry. * @param caretDataFile * The caret data file. */ void SpecFileDataFile::setCaretDataFile(CaretDataFile* caretDataFile) { m_caretDataFile = caretDataFile; } /** * @return The file's structure. */ StructureEnum::Enum SpecFileDataFile::getStructure() const { if (m_caretDataFile != NULL) { m_structure = m_caretDataFile->getStructure(); } return m_structure; } /** * Set the structure. * @param structure * New value for structure. */ void SpecFileDataFile::setStructure(const StructureEnum::Enum structure) { if (m_structure != structure) { m_structure = structure; setModified(); } } /** * @return The data file type for this group. */ DataFileTypeEnum::Enum SpecFileDataFile::getDataFileType() const { return m_dataFileType; } /** * @return The file's saving selection status. */ bool SpecFileDataFile::isSavingSelected() const { return m_savingSelected; } /** * Set the file's saving selection status. * DOES NOT alter modification status. * @param selected * New selection status. */ void SpecFileDataFile::setSavingSelected(const bool selected) { if (m_savingSelected != selected) { m_savingSelected = selected; } } /** * @return The file's loading selection status. */ bool SpecFileDataFile::isLoadingSelected() const { return m_loadingSelected; } /** * Set the file's loading selection status. * @param selected * New selection status. */ void SpecFileDataFile::setLoadingSelected(const bool selected) { // note: does not cause modification status to change m_loadingSelected = selected; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString SpecFileDataFile::toString() const { const AString info = "name=" + m_filename + ", structure=" + StructureEnum::toGuiName(m_structure) + ", dataFileType=" + DataFileTypeEnum::toGuiName(m_dataFileType); //+ ", selected=" + AString::fromBool(m_selected); return info; } /** * @return True if this file is a selected as a member of the spec file. * If true, then the spec file is written, this file will be listed in * the spec file. */ bool SpecFileDataFile::isSpecFileMember() const { return m_specFileMember; } /** * Set this file is a selected as a member of the spec file using the given * status. * * @param status If true, then the spec file is written, this file will * be listed in the spec file. */ void SpecFileDataFile::setSpecFileMember(const bool status) { if (m_specFileMember != status) { m_specFileMember = status; setModified(); } } /** * @return True if the file "exists". * * If the file is on the file system, true is returned if the file exists, * else false. * * If the file is remote (http, ftp, etc), true is ALWAYS returned. */ bool SpecFileDataFile::exists() const { if (DataFile::isFileOnNetwork(getFileName())) { return true; } FileInformation fileInfo(getFileName()); if (fileInfo.exists()) { return true; } return false; } connectome-workbench-1.4.2/src/Files/SpecFileDataFile.h000066400000000000000000000060161360521144700227240ustar00rootroot00000000000000#ifndef __SPEC_FILE_DATA_FILE_H__ #define __SPEC_FILE_DATA_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretDataFile.h" #include "CaretObjectTracksModification.h" #include "DataFileTypeEnum.h" #include "StructureEnum.h" namespace caret { class SpecFileDataFile : public CaretObjectTracksModification { public: SpecFileDataFile(const AString& filename, const DataFileTypeEnum::Enum dataFileType, const StructureEnum::Enum structure, const bool specFileMember); virtual ~SpecFileDataFile(); SpecFileDataFile(const SpecFileDataFile& sfdf); SpecFileDataFile& operator=(const SpecFileDataFile& sfdf); AString getFileName() const; void setFileName(const AString& fileName); CaretDataFile* getCaretDataFile(); void setCaretDataFile(CaretDataFile* caretDataFile); DataFileTypeEnum::Enum getDataFileType() const; StructureEnum::Enum getStructure() const; void setStructure(const StructureEnum::Enum structure); bool isLoadingSelected() const; void setLoadingSelected(const bool selected); bool isSavingSelected() const; void setSavingSelected(const bool selected); bool isSpecFileMember() const; void setSpecFileMember(const bool status); bool exists() const; public: virtual AString toString() const; private: SpecFileDataFile(); // not implemented void copyHelper(const SpecFileDataFile& sfdf); mutable AString m_filename; CaretDataFile* m_caretDataFile; mutable StructureEnum::Enum m_structure; DataFileTypeEnum::Enum m_dataFileType; bool m_loadingSelected; bool m_savingSelected; bool m_specFileMember; }; #ifdef __SPEC_FILE_GROUP_FILE_DECLARE__ // #endif // __SPEC_FILE_GROUP_FILE_DECLARE__ } // namespace #endif // __SPEC_FILE_DATA_FILE_H__ connectome-workbench-1.4.2/src/Files/SpecFileDataFileTypeGroup.cxx000066400000000000000000000207221360521144700251560ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SPEC_FILE_GROUP_DECLARE__ #include "SpecFileDataFileTypeGroup.h" #undef __SPEC_FILE_GROUP_DECLARE__ #include "CaretAssert.h" #include "CaretMappableDataFile.h" #include "SpecFileDataFile.h" using namespace caret; /** * \class caret::SpecFileDataFileTypeGroup * \brief Groups files of the same DataFileType. * * Groups files of the same data type in a SpecFile. */ /** * Constructor. * @param dataFileType * Type of data file. */ SpecFileDataFileTypeGroup::SpecFileDataFileTypeGroup(const DataFileTypeEnum::Enum dataFileType) : CaretObjectTracksModification() { this->dataFileType = dataFileType; } /** * Destructor. */ SpecFileDataFileTypeGroup::~SpecFileDataFileTypeGroup() { this->removeAllFileInformation(); } /** * @return The data file type for this group. */ DataFileTypeEnum::Enum SpecFileDataFileTypeGroup::getDataFileType() const { return this->dataFileType; } /** * @return The number of files. */ int32_t SpecFileDataFileTypeGroup::getNumberOfFiles() const { return this->files.size(); } /** * @return The number of files selected for loading. */ int32_t SpecFileDataFileTypeGroup::getNumberOfFilesSelectedForLoading() const { int count = 0; for (std::vector::const_iterator iter = this->files.begin(); iter != this->files.end(); iter++) { SpecFileDataFile* file = *iter; if (file->isLoadingSelected()) { count++; } } return count; } /** * @return The number of files selected for saving. */ int32_t SpecFileDataFileTypeGroup::getNumberOfFilesSelectedForSaving() const { int count = 0; for (std::vector::const_iterator iter = this->files.begin(); iter != this->files.end(); iter++) { SpecFileDataFile* file = *iter; if (file->isSavingSelected()) { count++; } } return count; } /** * Add a file. * @param fileInformation * New file information. */ void SpecFileDataFileTypeGroup::addFileInformation(SpecFileDataFile* fileInformation) { CaretAssert(fileInformation); this->files.push_back(fileInformation); /* * Do not set the modfication status when a data file is added */ } /** * Remove file at given index. * @param fileIndex * Index of file for removal. */ void SpecFileDataFileTypeGroup::removeFileInformation(const int32_t fileIndex) { CaretAssertVectorIndex(this->files, fileIndex); delete this->files[fileIndex]; this->files.erase(this->files.begin() + fileIndex); setModified(); } /** * Remove any files that are not "in spec" and do not have an * associated caret data file. */ void SpecFileDataFileTypeGroup::removeFileInformationIfNotInSpecAndNoCaretDataFile() { const int32_t numFiles = getNumberOfFiles(); for (int32_t i = (numFiles - 1); i >= 0; i--) { SpecFileDataFile* sfdf = getFileInformation(i); if (sfdf->isSpecFileMember() == false) { if (sfdf->getCaretDataFile() == NULL) { removeFileInformation(i); } } } } /** * Remove all files. */ void SpecFileDataFileTypeGroup::removeAllFileInformation() { for (std::vector::iterator iter = this->files.begin(); iter != this->files.end(); iter++) { delete *iter; } this->files.clear(); setModified(); } /** * Get information for a file. * @param fileIndex * Index of file for which information is requested. * @return * Information for file. */ SpecFileDataFile* SpecFileDataFileTypeGroup::getFileInformation(const int32_t fileIndex) { CaretAssertVectorIndex(this->files, fileIndex); return this->files[fileIndex]; } /** * Get information for a file. * @param fileIndex * Index of file for which information is requested. * @return * Information for file. */ const SpecFileDataFile* SpecFileDataFileTypeGroup::getFileInformation(const int32_t fileIndex) const { CaretAssertVectorIndex(this->files, fileIndex); return this->files[fileIndex]; } /** * Set the loading selection status of all files. * @param selectionStatus * New loading selection status for all files. */ void SpecFileDataFileTypeGroup::setAllFilesSelectedForLoading(bool selectionStatus) { for (std::vector::iterator iter = this->files.begin(); iter != this->files.end(); iter++) { SpecFileDataFile* file = *iter; file->setLoadingSelected(selectionStatus); } } /** * Set the saving selection status of all files. * @param selectionStatus * New saving selection status for all files. */ void SpecFileDataFileTypeGroup::setAllFilesSelectedForSaving(bool selectionStatus) { for (std::vector::iterator iter = this->files.begin(); iter != this->files.end(); iter++) { SpecFileDataFile* file = *iter; file->setSavingSelected(selectionStatus); } } /** * Set the save status to on for any files that are modified. */ void SpecFileDataFileTypeGroup::setModifiedFilesSelectedForSaving() { for (std::vector::iterator iter = this->files.begin(); iter != this->files.end(); iter++) { SpecFileDataFile* file = *iter; CaretDataFile* cdf = file->getCaretDataFile(); if (cdf != NULL) { if (cdf->isModified()) { CaretMappableDataFile* mapFile = dynamic_cast(cdf); if (mapFile != NULL) { /* * For mappable data file, we only default saving to on when the modification * does not involve the color palette. Color palettes can be saved to a * scene so it not necessary to save the file when the palette is modified. * This prevents unintentional saving of the mappable data files, * especially when creating scenes. */ if (mapFile->isModifiedExcludingPaletteColorMapping()) { file->setSavingSelected(true); } } else { file->setSavingSelected(true); } } } } } /** * Get a description of this object's content. * @return String describing this object's content. */ AString SpecFileDataFileTypeGroup::toString() const { AString info = "DataFileType=" + DataFileTypeEnum::toName(this->dataFileType) + "\n"; for (std::vector::const_iterator iter = this->files.begin(); iter != this->files.end(); iter++) { SpecFileDataFile* file = *iter; info += (" " + file->toString() + "\n"); } return info; } /** * Set the status to unmodified. */ void SpecFileDataFileTypeGroup::clearModified() { CaretObjectTracksModification::clearModified(); for (std::vector::iterator iter = this->files.begin(); iter != this->files.end(); iter++) { SpecFileDataFile* sfdf = *iter; sfdf->clearModified(); } } /** * Is the object modified? * @return true if modified, else false. */ bool SpecFileDataFileTypeGroup::isModified() const { if (CaretObjectTracksModification::isModified()) { return true; } for (std::vector::const_iterator iter = this->files.begin(); iter != this->files.end(); iter++) { const SpecFileDataFile* sfdf = *iter; if (sfdf->isModified()) { return true; } } return false; } connectome-workbench-1.4.2/src/Files/SpecFileDataFileTypeGroup.h000066400000000000000000000054631360521144700246100ustar00rootroot00000000000000#ifndef __SPEC_FILE_DATA_FILE_TYPE_GROUP_H__ #define __SPEC_FILE_DATA_FILE_TYPE_GROUP_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObjectTracksModification.h" #include "DataFileTypeEnum.h" namespace caret { class SpecFileDataFile; class SpecFileDataFileTypeGroup : public CaretObjectTracksModification { public: SpecFileDataFileTypeGroup(const DataFileTypeEnum::Enum dataFileType); virtual ~SpecFileDataFileTypeGroup(); DataFileTypeEnum::Enum getDataFileType() const; int32_t getNumberOfFiles() const; int32_t getNumberOfFilesSelectedForLoading() const; int32_t getNumberOfFilesSelectedForSaving() const; void addFileInformation(SpecFileDataFile* fileInformation); void removeFileInformation(const int32_t fileIndex); void removeAllFileInformation(); void removeFileInformationIfNotInSpecAndNoCaretDataFile(); SpecFileDataFile* getFileInformation(const int32_t fileIndex); const SpecFileDataFile* getFileInformation(const int32_t fileIndex) const; void setAllFilesSelectedForLoading(bool selectionStatus); void setAllFilesSelectedForSaving(bool selectionStatus); void setModifiedFilesSelectedForSaving(); virtual void clearModified(); virtual bool isModified() const; private: SpecFileDataFileTypeGroup(const SpecFileDataFileTypeGroup&); SpecFileDataFileTypeGroup& operator=(const SpecFileDataFileTypeGroup&); public: virtual AString toString() const; private: std::vector files; DataFileTypeEnum::Enum dataFileType; }; #ifdef __SPEC_FILE_GROUP_DECLARE__ // #endif // __SPEC_FILE_GROUP_DECLARE__ } // namespace #endif // __SPEC_FILE_DATA_FILE_TYPE_GROUP_H__ connectome-workbench-1.4.2/src/Files/SpecFileSaxReader.cxx000066400000000000000000000223721360521144700235070ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretAssert.h" #include "CaretLogger.h" #include "DataFileException.h" #include "GiftiXmlElements.h" #include "SpecFile.h" #include "SpecFileSaxReader.h" #include "GiftiMetaDataSaxReader.h" #include "FileInformation.h" #include "XmlAttributes.h" #include "XmlException.h" using namespace caret; /** * constructor. */ SpecFileSaxReader::SpecFileSaxReader(SpecFile* specFileIn) { CaretAssert(specFileIn); this->specFile = specFileIn; this->state = STATE_NONE; this->stateStack.push(this->state); this->elementText = ""; this->metaDataSaxReader = NULL; } /** * destructor. */ SpecFileSaxReader::~SpecFileSaxReader() { } /** * start an element. */ void SpecFileSaxReader::startElement(const AString& namespaceURI, const AString& localName, const AString& qName, const XmlAttributes& attributes) { const STATE previousState = this->state; switch (this->state) { case STATE_NONE: if (qName == SpecFile::XML_TAG_SPEC_FILE) { this->state = STATE_SPEC_FILE; // // Check version of file being read // const float version = attributes.getValueAsFloat(SpecFile::XML_ATTRIBUTE_VERSION); if (version > SpecFile::getFileVersion()) { AString msg = "File version is " + AString::number(version) + " but versions newer than " + SpecFile::getFileVersionAsString() + " are not supported. Update your software."; XmlSaxParserException e(msg); CaretLogThrowing(e); throw e; } else if (version < 1.0) { AString msg = "File version is " + AString::number(version) + " but versions before" + SpecFile::getFileVersionAsString() + " are not supported. Update your software."; XmlSaxParserException e(msg); CaretLogThrowing(e); throw e; } } else if (qName == "Spec_File") { const AString msg = ("You are trying to read a Spec File from Caret5 " "that is incompatible with Workbench. Use the " "program wb_import (included in the " "Workbench distribution) to convert files from " "Caret5 formats to Workbench formats"); XmlSaxParserException e(msg); CaretLogThrowing(e); throw e; } else { const AString msg = "Root elements is " + qName + " but should be " + SpecFile::XML_TAG_SPEC_FILE; XmlSaxParserException e(msg); CaretLogThrowing(e); throw e; } break; case STATE_SPEC_FILE: if (qName == GiftiXmlElements::TAG_METADATA) { this->state = STATE_METADATA; this->metaDataSaxReader = new GiftiMetaDataSaxReader(this->specFile->getFileMetaData()); this->metaDataSaxReader->startElement(namespaceURI, localName, qName, attributes); } else if (qName == SpecFile::XML_TAG_DATA_FILE) { this->state = STATE_DATA_FILE; this->fileAttributeStructureName = attributes.getValue(SpecFile::XML_ATTRIBUTE_STRUCTURE); this->fileAttributeTypeName = attributes.getValue(SpecFile::XML_ATTRIBUTE_DATA_FILE_TYPE); this->fileAttributeSelectionStatus = attributes.getValueAsBoolean(SpecFile::XML_ATTRIBUTE_SELECTED, false); } else { const AString msg = "Invalid child of " + SpecFile::XML_TAG_SPEC_FILE + " is " + qName; XmlSaxParserException e(msg); CaretLogThrowing(e); throw e; } break; case STATE_METADATA: this->metaDataSaxReader->startElement(namespaceURI, localName, qName, attributes); break; case STATE_DATA_FILE: break; } // // Save previous state // stateStack.push(previousState); elementText = ""; } /** * end an element. */ void SpecFileSaxReader::endElement(const AString& namespaceURI, const AString& localName, const AString& qName) { switch (this->state) { case STATE_NONE: break; case STATE_SPEC_FILE: break; case STATE_METADATA: this->metaDataSaxReader->endElement(namespaceURI, localName, qName); if (qName == GiftiXmlElements::TAG_METADATA) { delete this->metaDataSaxReader; this->metaDataSaxReader = NULL; } break; case STATE_DATA_FILE: { try { const AString filename = this->elementText.trimmed(); AString fileNameForAdd; if (DataFile::isFileOnNetwork(filename))//keep on-network names as-is { fileNameForAdd = filename; } else {//otherwise, resolve relative to spec file if (DataFile::isFileOnNetwork(specFile->getFileName())) { const int32_t lastSlashIndex = specFile->getFileName().lastIndexOf("/"); if (lastSlashIndex >= 0) { fileNameForAdd = (specFile->getFileName().left(lastSlashIndex) + "/" + filename); } else { CaretAssert(0); } } else { FileInformation resolvePath(FileInformation(specFile->getFileName()).getAbsolutePath(), filename); fileNameForAdd = resolvePath.getAbsoluteFilePath(); } } this->specFile->addDataFile(this->fileAttributeTypeName, this->fileAttributeStructureName, fileNameForAdd, this->fileAttributeSelectionStatus, false, // not selected for saving true); // is a member of spec file since read from spec file this->fileAttributeTypeName = ""; this->fileAttributeStructureName = ""; this->fileAttributeSelectionStatus = false; } catch (const DataFileException& e) { throw XmlSaxParserException(e); } } break; } // // Clear out for new elements // this->elementText = ""; // // Go to previous state // if (this->stateStack.empty()) { throw XmlSaxParserException("State stack is empty while reading XML NiftDataFile."); } this->state = stateStack.top(); this->stateStack.pop(); } /** * get characters in an element. */ void SpecFileSaxReader::characters(const char* ch) { if (this->metaDataSaxReader != NULL) { this->metaDataSaxReader->characters(ch); } else { elementText += ch; } } /** * a fatal error occurs. */ void SpecFileSaxReader::fatalError(const XmlSaxParserException& e) { /* std::ostringstream str; str << "Fatal Error at line number: " << e.getLineNumber() << "\n" << "Column number: " << e.getColumnNumber() << "\n" << "Message: " << e.whatString(); if (errorMessage.isEmpty() == false) { str << "\n" << errorMessage; } errorMessage = str.str(); */ // // Stop parsing // throw e; } // a warning occurs void SpecFileSaxReader::warning(const XmlSaxParserException& e) { CaretLogWarning("XML Parser Warning: " + e.whatString()); } // an error occurs void SpecFileSaxReader::error(const XmlSaxParserException& e) { CaretLogSevere("XML Parser Error: " + e.whatString()); throw e; } void SpecFileSaxReader::startDocument() { } void SpecFileSaxReader::endDocument() { } connectome-workbench-1.4.2/src/Files/SpecFileSaxReader.h000066400000000000000000000064111360521144700231300ustar00rootroot00000000000000 #ifndef __SPEC_FILE_SAX_READER_H__ #define __SPEC_FILE_SAX_READER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "XmlSaxParserException.h" #include "XmlSaxParserHandlerInterface.h" namespace caret { class SpecFile; class SpecFileDataFileTypeGroup; class GiftiMetaDataSaxReader; class XmlAttributes; class XmlException; /// class for reading a Spec File with a SAX Parser class SpecFileSaxReader : public CaretObject, public XmlSaxParserHandlerInterface { public: SpecFileSaxReader(SpecFile* specFileIn); virtual ~SpecFileSaxReader(); void startElement(const AString& namespaceURI, const AString& localName, const AString& qName, const XmlAttributes& attributes); void endElement(const AString& namspaceURI, const AString& localName, const AString& qName); void characters(const char* ch); void fatalError(const XmlSaxParserException& e); void warning(const XmlSaxParserException& e); void error(const XmlSaxParserException& e); void startDocument(); void endDocument(); protected: /// file reading states enum STATE { /// no state STATE_NONE, /// processing SpecFile tag STATE_SPEC_FILE, /// processing MetaData tag STATE_METADATA, /// processing DataFile tag STATE_DATA_FILE }; /// file reading state STATE state; /// the state stack used when reading a file std::stack stateStack; /// the error message AString errorMessage; /// Spec file that is being read SpecFile* specFile; /// element text AString elementText; /// GIFTI meta data sax reader GiftiMetaDataSaxReader* metaDataSaxReader; /** value of File Structure attribute */ AString fileAttributeStructureName; /** value of File type attribute */ AString fileAttributeTypeName; /** value of File selection status */ bool fileAttributeSelectionStatus; }; } // namespace #endif // __SPEC_FILE_SAX_READER_H__ connectome-workbench-1.4.2/src/Files/StudyMetaDataLink.cxx000066400000000000000000000205621360521144700235440ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __STUDY_META_DATA_LINK_MAIN__ #include "StudyMetaDataLink.h" #undef __STUDY_META_DATA_LINK_MAIN__ #include "CaretLogger.h" #include "XmlWriter.h" using namespace caret; /** * \class caret::StudyMetaDataLink * \brief A link to study data. */ /** * constructor. */ StudyMetaDataLink::StudyMetaDataLink() { clear(); } /** * destructor. */ StudyMetaDataLink::~StudyMetaDataLink() { } /** * copy constructor. */ StudyMetaDataLink::StudyMetaDataLink(const StudyMetaDataLink& smdl) : CaretObject(smdl){ copyHelper(smdl); } /** * assignment opertator. */ StudyMetaDataLink& StudyMetaDataLink::operator=(const StudyMetaDataLink& smdl) { if (this != &smdl) { CaretObject::operator=(smdl); copyHelper(smdl); } return *this; } /** * copy helper. */ void StudyMetaDataLink::copyHelper(const StudyMetaDataLink& smdl) { m_pubMedID = smdl.m_pubMedID; m_tableNumber = smdl.m_tableNumber; m_tableSubHeaderNumber = smdl.m_tableSubHeaderNumber; m_figureNumber = smdl.m_figureNumber; m_panelNumberOrLetter = smdl.m_panelNumberOrLetter; m_pageReferencePageNumber = smdl.m_pageReferencePageNumber; m_pageReferenceSubHeaderNumber = smdl.m_pageReferenceSubHeaderNumber; } /** * equality operator. */ bool StudyMetaDataLink::operator==(const StudyMetaDataLink& smdl) const { const bool theSame = ((m_pubMedID == smdl.m_pubMedID) && (m_tableNumber == smdl.m_tableNumber) && (m_tableSubHeaderNumber == smdl.m_tableSubHeaderNumber) && (m_figureNumber == smdl.m_figureNumber) && (m_panelNumberOrLetter == smdl.m_panelNumberOrLetter) && (m_pageReferencePageNumber == smdl.m_pageReferencePageNumber) && (m_pageReferenceSubHeaderNumber == smdl.m_pageReferenceSubHeaderNumber)); return theSame; } /** * clear the link. */ void StudyMetaDataLink::clear() { m_pubMedID = "0"; m_tableNumber = ""; m_tableSubHeaderNumber = ""; m_figureNumber = ""; m_panelNumberOrLetter = ""; m_pageReferencePageNumber = ""; m_pageReferenceSubHeaderNumber = ""; } /** * set the table number (blank if invalid). */ void StudyMetaDataLink::setTableNumber(const AString& tn) { if (tn == "-1") { m_tableNumber = ""; } else { m_tableNumber = tn; } } /** * set the table sub header number (blank if invalid). */ void StudyMetaDataLink::setTableSubHeaderNumber(const AString& tshn) { if (tshn == "-1") { m_tableSubHeaderNumber = ""; } else { m_tableSubHeaderNumber = tshn; } } /** * set the panel letter/number (blank if invalid). */ void StudyMetaDataLink::setFigurePanelNumberOrLetter(const AString& pnl) { if (pnl == "-1") { m_panelNumberOrLetter = ""; } else { m_panelNumberOrLetter = pnl; } } /** * set the figure number (blank if invalid). */ void StudyMetaDataLink::setFigureNumber(const AString& fn) { if (fn == "-1") { m_figureNumber = ""; } else { m_figureNumber = fn; } } /** * set the page reference page number (blank if invalid). */ void StudyMetaDataLink::setPageReferencePageNumber(const AString& prpn) { if (prpn == "-1") { m_pageReferencePageNumber = ""; } else { m_pageReferencePageNumber = prpn; } } /** * set the page reference sub header number (blank if invalid). */ void StudyMetaDataLink::setPageReferenceSubHeaderNumber(const AString& tshn) { if (tshn == "-1") { m_pageReferenceSubHeaderNumber = ""; } else { m_pageReferenceSubHeaderNumber = tshn; } } /** * set element from text (used by SAX XML parser). */ void StudyMetaDataLink::setElementFromText(const AString& elementName, const AString& textValue) { if (elementName == XML_TAG_PUBMED_ID) { setPubMedID(textValue); } else if (elementName == XML_TAG_TABLE_NUMBER) { setTableNumber(textValue); } else if (elementName == XML_TAG_TABLE_SUB_HEADER_NUMBER) { setTableSubHeaderNumber(textValue); } else if (elementName == XML_TAG_FIGURE_NUMBER) { setFigureNumber(textValue); } else if (elementName == XML_TAG_PANEL_NUMBER_OR_LETTER) { setFigurePanelNumberOrLetter(textValue); } else if (elementName == XML_TAG_PAGE_REFERENCE_PAGE_NUMBER) { setPageReferencePageNumber(textValue); } else if (elementName == XML_TAG_PAGE_REFERENCE_SUB_HEADER_NUMBER) { setPageReferenceSubHeaderNumber(textValue); } else { CaretLogWarning("Unrecognized StudyMetaDataLink element ignored: " + elementName); } } /** * called to write XML. */ void StudyMetaDataLink::writeXML(XmlWriter& xmlWriter) const { xmlWriter.writeStartElement(XML_TAG_STUDY_META_DATA_LINK); xmlWriter.writeElementCData(XML_TAG_PUBMED_ID, m_pubMedID); xmlWriter.writeElementCData(XML_TAG_TABLE_NUMBER, m_tableNumber); xmlWriter.writeElementCData(XML_TAG_TABLE_SUB_HEADER_NUMBER, m_tableSubHeaderNumber); xmlWriter.writeElementCData(XML_TAG_FIGURE_NUMBER, m_figureNumber); xmlWriter.writeElementCData(XML_TAG_PANEL_NUMBER_OR_LETTER, m_panelNumberOrLetter); xmlWriter.writeElementCData(XML_TAG_PAGE_REFERENCE_PAGE_NUMBER, m_pageReferencePageNumber); xmlWriter.writeElementCData(XML_TAG_PAGE_REFERENCE_SUB_HEADER_NUMBER, m_pageReferenceSubHeaderNumber); xmlWriter.writeEndElement(); } /** * get the entire link in an "coded" text form. */ AString StudyMetaDataLink::getLinkAsCodedText() const { // // Assemble into one string containing key/value pairs separated by a semi-colon // QStringList sl; sl << ("pubMedID=" + m_pubMedID) << ("tableNumber=" + m_tableNumber) << ("tableSubHeaderNumber=" + m_tableSubHeaderNumber) << ("figureNumber=" + m_figureNumber) << ("panelNumberOrLetter=" + m_panelNumberOrLetter) << ("pageReferencePageNumber=" + m_pageReferencePageNumber) << ("pageReferenceSubHeaderNumber=" + m_pageReferenceSubHeaderNumber); const AString s = sl.join(";"); return s; } /** * set the link from "coded" text form. */ void StudyMetaDataLink::setLinkFromCodedText(const AString& txt) { // // Clear this link // clear(); // // Extract the key/value pairs that are separated by a semi-colon // const QStringList sl = txt.split(";", AString::SkipEmptyParts); for (int i = 0; i < sl.size(); i++) { const AString keyValueString = sl.at(i); // // Split with "=" into key/value pairs // const QStringList keyValueList = keyValueString.split("=", AString::SkipEmptyParts); if (keyValueList.size() == 2) { const AString key = keyValueList.at(0); const AString value = keyValueList.at(1).trimmed(); if (key == "pubMedID") { setPubMedID(value); } else if (key == "tableNumber") { setTableNumber(value); } else if (key == "tableSubHeaderNumber") { setTableSubHeaderNumber(value); } else if (key == "figureNumber") { setFigureNumber(value); } else if (key == "panelNumberOrLetter") { setFigurePanelNumberOrLetter(value); } else if (key == "pageReferencePageNumber") { setPageReferencePageNumber(value); } else if (key == "pageReferenceSubHeaderNumber") { setPageReferenceSubHeaderNumber(value); } else { std::cout << "Unrecognized StudyMetaDataLink key: " << key.toLatin1().constData() << std::endl; } } } } connectome-workbench-1.4.2/src/Files/StudyMetaDataLink.h000066400000000000000000000154621360521144700231740ustar00rootroot00000000000000 #ifndef __STUDY_META_DATA_LINK_H__ #define __STUDY_META_DATA_LINK_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "XmlException.h" namespace caret { class XmlWriter; class StudyMetaDataLink : public CaretObject { public: // constructor StudyMetaDataLink(); // destructor ~StudyMetaDataLink(); // copy constructor StudyMetaDataLink(const StudyMetaDataLink& smdl); // assignment opertator StudyMetaDataLink& operator=(const StudyMetaDataLink& smdl); // equality operator bool operator==(const StudyMetaDataLink& smdl) const; // clear the link void clear(); /// get the PubMed ID (negative if project ID, zero if invalid) AString getPubMedID() const { return m_pubMedID; } /// set the PubMed ID (negative if project ID) void setPubMedID(const AString& pmid) { m_pubMedID = pmid; } /// get the table number (blank if invalid) AString getTableNumber() const { return m_tableNumber; } /// set the table number (blank if invalid) void setTableNumber(const AString& tn); /// get the table sub header number (blank if invalid) AString getTableSubHeaderNumber() const { return m_tableSubHeaderNumber; } /// set the table sub header number (blank if invalid) void setTableSubHeaderNumber(const AString& tshn); /// get the figure number (blank if invalid) AString getFigureNumber() const { return m_figureNumber; } /// set the figure number (blank if invalid) void setFigureNumber(const AString& fn); /// get the panel letter/number (blank if invalid) AString getFigurePanelNumberOrLetter() const { return m_panelNumberOrLetter; } /// set the panel letter/number (blank if invalid) void setFigurePanelNumberOrLetter(const AString& pnl); /// get the page reference page number (blank if invalid) AString getPageReferencePageNumber() const { return m_pageReferencePageNumber; } /// set the page reference page number (blank if invalid) void setPageReferencePageNumber(const AString& prpn); /// get the page reference sub header number (blank if invalid) AString getPageReferenceSubHeaderNumber() const { return m_pageReferenceSubHeaderNumber; } /// set the page reference sub header number (blank if invalid) void setPageReferenceSubHeaderNumber(const AString& tshn); /// get the entire link in an "coded" text form AString getLinkAsCodedText() const; /// set the link from "coded" text form void setLinkFromCodedText(const AString& txt); // called to write XML void writeXML(XmlWriter& xmlWriter) const; /// set element from text (used by SAX XML parser) void setElementFromText(const AString& elementName, const AString& textValue); // //----- tags for reading and writing // /// tag for reading and writing study metadata static const AString XML_TAG_STUDY_META_DATA_LINK; /// tag for reading and writing study metadata static const AString XML_TAG_PUBMED_ID; /// tag for reading and writing study metadata static const AString XML_TAG_TABLE_NUMBER; /// tag for reading and writing study metadata static const AString XML_TAG_TABLE_SUB_HEADER_NUMBER; /// tag for reading and writing study metadata static const AString XML_TAG_FIGURE_NUMBER; /// tag for reading and writing study metadata static const AString XML_TAG_PANEL_NUMBER_OR_LETTER; /// tag for reading and writing study metadata //static const AString tagPageNumber; /// tag for reading and writing study metadata static const AString XML_TAG_PAGE_REFERENCE_PAGE_NUMBER; /// tag for reading and writing study metadata static const AString XML_TAG_PAGE_REFERENCE_SUB_HEADER_NUMBER; protected: /// copy helper void copyHelper(const StudyMetaDataLink& smdl); /// the PubMed ID (negative if project ID, 0 if invalid) AString m_pubMedID; /// the table number (blank if invalid) AString m_tableNumber; /// the table sub header number (blank if invalid) AString m_tableSubHeaderNumber; /// the figure number (blank if invalid) AString m_figureNumber; /// the panel letter/number (blank if invalid) AString m_panelNumberOrLetter; /// page reference page number (blank if invalid) AString m_pageReferencePageNumber; /// page reference sub header number (blank if invalid) AString m_pageReferenceSubHeaderNumber; // NOTE: IF MEMBERS ADDED UPDATE THE COPY HELPER friend class StudyMetaDataLinkSet; }; #ifdef __STUDY_META_DATA_LINK_MAIN__ const AString StudyMetaDataLink::XML_TAG_STUDY_META_DATA_LINK = "StudyMetaDataLink"; const AString StudyMetaDataLink::XML_TAG_PUBMED_ID = "pubMedID"; const AString StudyMetaDataLink::XML_TAG_TABLE_NUMBER = "tableNumber"; const AString StudyMetaDataLink::XML_TAG_TABLE_SUB_HEADER_NUMBER = "tableSubHeaderNumber"; const AString StudyMetaDataLink::XML_TAG_FIGURE_NUMBER = "figureNumber"; const AString StudyMetaDataLink::XML_TAG_PANEL_NUMBER_OR_LETTER = "panelNumberOrLetter"; const AString StudyMetaDataLink::XML_TAG_PAGE_REFERENCE_PAGE_NUMBER = "pageReferencePageNumber"; const AString StudyMetaDataLink::XML_TAG_PAGE_REFERENCE_SUB_HEADER_NUMBER = "pageReferenceSubHeaderNumber"; #endif // __STUDY_META_DATA_LINK_MAIN__ } // namespace caret #endif // __STUDY_META_DATA_LINK_H__ connectome-workbench-1.4.2/src/Files/StudyMetaDataLinkSet.cxx000066400000000000000000000073561360521144700242260ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #define __STUDY_META_DATA_LINK_SET_MAIN__ #include "StudyMetaDataLinkSet.h" #undef __STUDY_META_DATA_LINK_SET_MAIN__ #include "XmlWriter.h" using namespace caret; /** * constructor. */ StudyMetaDataLinkSet::StudyMetaDataLinkSet() { clear(); } /** * destructor. */ StudyMetaDataLinkSet::~StudyMetaDataLinkSet() { clear(); } /** * add a StudyMetaDataLink. */ void StudyMetaDataLinkSet::addStudyMetaDataLink(const StudyMetaDataLink& smdl) { m_links.push_back(smdl); } /** * remove all links. */ void StudyMetaDataLinkSet::clear() { m_links.clear(); } /** * get a StudyMetaDataLink. */ StudyMetaDataLink StudyMetaDataLinkSet::getStudyMetaDataLink(const int indx) const { return m_links[indx]; } /** * get a pointer to a StudyMetaDataLink. */ StudyMetaDataLink* StudyMetaDataLinkSet::getStudyMetaDataLinkPointer(const int indx) { if ((indx >= 0) && (indx < getNumberOfStudyMetaDataLinks())) { return &m_links[indx]; } return NULL; } /** * set a study meta data link. */ void StudyMetaDataLinkSet::setStudyMetaDataLink(const int indx, const StudyMetaDataLink& smdl) { m_links[indx] = smdl; } /** * get all linked PubMed IDs. */ void StudyMetaDataLinkSet::getAllLinkedPubMedIDs(std::vector& pmidsOut) const { std::set pmidSet; const int num = getNumberOfStudyMetaDataLinks(); for (int i = 0; i < num; i++) { const AString pmid = getStudyMetaDataLink(i).getPubMedID(); pmidSet.insert(pmid); } pmidsOut.clear(); pmidsOut.insert(pmidsOut.end(), pmidSet.begin(), pmidSet.end()); } /** * remove a study meta data link. */ void StudyMetaDataLinkSet::removeStudyMetaDataLink(const int indx) { m_links.erase(m_links.begin() + indx); } /** * get the entire link set in an "coded" text form. */ AString StudyMetaDataLinkSet::getLinkSetAsCodedText() const { QStringList sl; const int num = getNumberOfStudyMetaDataLinks(); for (int i = 0; i < num; i++) { sl << getStudyMetaDataLink(i).getLinkAsCodedText(); } const AString s = sl.join(encodedTextLinkSeparator); return s; } /** * set the link set from "coded" text form. */ void StudyMetaDataLinkSet::setLinkSetFromCodedText(const AString& txt) { clear(); const QStringList sl = txt.split(encodedTextLinkSeparator, AString::SkipEmptyParts); for (int i = 0; i < sl.count(); i++) { StudyMetaDataLink smdl; smdl.setLinkFromCodedText(sl.at(i)); m_links.push_back(smdl); } } /** * called to write XML. */ void StudyMetaDataLinkSet::writeXML(XmlWriter& xmlWriter) const { xmlWriter.writeStartElement(XML_TAG_STUDY_META_DATA_LINK_SET); const int num = getNumberOfStudyMetaDataLinks(); for (int i = 0; i < num; i++) { StudyMetaDataLink smdl = getStudyMetaDataLink(i); smdl.writeXML(xmlWriter); } xmlWriter.writeEndElement(); } connectome-workbench-1.4.2/src/Files/StudyMetaDataLinkSet.h000066400000000000000000000064331360521144700236460ustar00rootroot00000000000000 #ifndef __STUDY_META_DATA_LINK_SET_H__ #define __STUDY_META_DATA_LINK_SET_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "StudyMetaDataLink.h" #include "XmlException.h" namespace caret { class XmlWriter; /// class for accessing and storing a group of StudyMetaDataLink class StudyMetaDataLinkSet : public CaretObject { public: // constructor StudyMetaDataLinkSet(); // destructor ~StudyMetaDataLinkSet(); // add a StudyMetaDataLink void addStudyMetaDataLink(const StudyMetaDataLink& smdl); // remove all links void clear(); /// get the number of study meta data links int getNumberOfStudyMetaDataLinks() const { return m_links.size(); } // get a StudyMetaDataLink StudyMetaDataLink getStudyMetaDataLink(const int indx) const; // get a pointer to a StudyMetaDataLink StudyMetaDataLink* getStudyMetaDataLinkPointer(const int indx); // get all linked PubMed IDs void getAllLinkedPubMedIDs(std::vector& pmidsOut) const; // remove a study meta data link void removeStudyMetaDataLink(const int indx); // set a study meta data link void setStudyMetaDataLink(const int indx, const StudyMetaDataLink& smdl); /// get the entire link set in an "coded" text form AString getLinkSetAsCodedText() const; /// set the link set from "coded" text form void setLinkSetFromCodedText(const AString& txt); // called to write XML void writeXML(XmlWriter& xmlWriter) const; // //----- tags for reading and writing // /// tag for reading and writing study metadata static const AString XML_TAG_STUDY_META_DATA_LINK_SET; /// get the link separator for when stored as a string static const AString encodedTextLinkSeparator; protected: /// the StudyMetaDataLink std::vector m_links; friend class CellBase; }; #ifdef __STUDY_META_DATA_LINK_SET_MAIN__ const AString StudyMetaDataLinkSet::XML_TAG_STUDY_META_DATA_LINK_SET = "StudyMetaDataLinkSet"; const AString StudyMetaDataLinkSet::encodedTextLinkSeparator = ":::::"; #endif // __STUDY_META_DATA_LINK_SET_MAIN__ } // namespace #endif // __STUDY_META_DATA_LINK_SET_H__ connectome-workbench-1.4.2/src/Files/StudyMetaDataLinkSetSaxReader.cxx000066400000000000000000000123621360521144700260160ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretLogger.h" #include "StudyMetaDataLink.h" #include "StudyMetaDataLinkSet.h" #include "StudyMetaDataLinkSetSaxReader.h" #include "XmlAttributes.h" #include "XmlException.h" #include "XmlUtilities.h" using namespace caret; /** * constructor. */ StudyMetaDataLinkSetSaxReader::StudyMetaDataLinkSetSaxReader(StudyMetaDataLinkSet* studyMetaDataLinkSet) { m_state = STATE_NONE; m_stateStack.push(this->m_state); m_elementText = ""; m_studyMetaDataLinkSet = studyMetaDataLinkSet; m_studyMetaDataLinkBeingRead = NULL; } /** * destructor. */ StudyMetaDataLinkSetSaxReader::~StudyMetaDataLinkSetSaxReader() { } /** * start an element. */ void StudyMetaDataLinkSetSaxReader::startElement(const AString& /* namespaceURI */, const AString& /* localName */, const AString& qName, const XmlAttributes& /*attributes*/) { const STATE previousState = m_state; switch (m_state) { case STATE_NONE: if (qName == StudyMetaDataLinkSet::XML_TAG_STUDY_META_DATA_LINK_SET) { m_state = STATE_STUDY_META_DATA_LINK_SET; } else { AString txt = XmlUtilities::createInvalidRootElementMessage(StudyMetaDataLinkSet::XML_TAG_STUDY_META_DATA_LINK_SET, qName); XmlSaxParserException e(txt); CaretLogThrowing(e); throw e; } break; case STATE_STUDY_META_DATA_LINK_SET: if (qName == StudyMetaDataLink::XML_TAG_STUDY_META_DATA_LINK) { m_state = STATE_STUDY_META_DATA_LINK; m_studyMetaDataLinkBeingRead = new StudyMetaDataLink(); } else { AString txt = XmlUtilities::createInvalidChildElementMessage(StudyMetaDataLink::XML_TAG_STUDY_META_DATA_LINK, qName); XmlSaxParserException e(txt); CaretLogThrowing(e); throw e; } break; case STATE_STUDY_META_DATA_LINK: break; } // // Save previous state // m_stateStack.push(previousState); m_elementText = ""; } /** * end an element. */ void StudyMetaDataLinkSetSaxReader::endElement(const AString& /* namspaceURI */, const AString& /* localName */, const AString& qName) { const AString text = m_elementText.trimmed(); switch (m_state) { case STATE_NONE: break; case STATE_STUDY_META_DATA_LINK_SET: if (m_studyMetaDataLinkBeingRead != NULL) { this->m_studyMetaDataLinkSet->addStudyMetaDataLink(*m_studyMetaDataLinkBeingRead); delete m_studyMetaDataLinkBeingRead; m_studyMetaDataLinkBeingRead = NULL; } break; case STATE_STUDY_META_DATA_LINK: if (qName != StudyMetaDataLink::XML_TAG_STUDY_META_DATA_LINK) { m_studyMetaDataLinkBeingRead->setElementFromText(qName, text); } break; } // // Clear out for new elements // m_elementText = ""; // // Go to previous state // if (m_stateStack.empty()) { throw XmlSaxParserException("State stack is empty while reading XML MetaData."); } m_state = m_stateStack.top(); m_stateStack.pop(); } /** * get characters in an element. */ void StudyMetaDataLinkSetSaxReader::characters(const char* ch) { m_elementText += ch; } /** * a fatal error occurs. */ void StudyMetaDataLinkSetSaxReader::fatalError(const XmlSaxParserException& e) { // // Stop parsing // CaretLogSevere("XML Parser Fatal Error: " + e.whatString()); throw e; } // a warning occurs void StudyMetaDataLinkSetSaxReader::warning(const XmlSaxParserException& e) { CaretLogWarning("XML Parser Warning: " + e.whatString()); } // an error occurs void StudyMetaDataLinkSetSaxReader::error(const XmlSaxParserException& e) { throw e; } void StudyMetaDataLinkSetSaxReader::startDocument() { } void StudyMetaDataLinkSetSaxReader::endDocument() { } connectome-workbench-1.4.2/src/Files/StudyMetaDataLinkSetSaxReader.h000066400000000000000000000065551360521144700254520ustar00rootroot00000000000000 #ifndef __STUDY_META_DATA_LINK_SET_SAX_READER_H__ #define __STUDY_META_DATA_LINK_SET_SAX_READER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" #include "XmlSaxParserException.h" #include "XmlSaxParserHandlerInterface.h" namespace caret { class StudyMetaDataLink; class StudyMetaDataLinkSet; class XmlAttributes; /** * class for reading StudyMetaDataLinkSet with a SAX Parser */ class StudyMetaDataLinkSetSaxReader : public CaretObject, public XmlSaxParserHandlerInterface { public: StudyMetaDataLinkSetSaxReader(StudyMetaDataLinkSet* studyMetaDataLinKSet); virtual ~StudyMetaDataLinkSetSaxReader(); void startElement(const AString& namespaceURI, const AString& localName, const AString& qName, const XmlAttributes& attributes); void endElement(const AString& namspaceURI, const AString& localName, const AString& qName); void characters(const char* ch); void fatalError(const XmlSaxParserException& e); void warning(const XmlSaxParserException& e); void error(const XmlSaxParserException& e); void startDocument(); void endDocument(); private: StudyMetaDataLinkSetSaxReader(const StudyMetaDataLinkSetSaxReader&); StudyMetaDataLinkSetSaxReader& operator=(const StudyMetaDataLinkSetSaxReader&); protected: /// file reading states enum STATE { /// no state STATE_NONE, /// processing SurfaceProjectedItem tags STATE_STUDY_META_DATA_LINK_SET, /// processing StudyMetaDataLink tags STATE_STUDY_META_DATA_LINK, }; /// file reading state STATE m_state; /// the state stack used when reading a file std::stack m_stateStack; /// the error message AString m_errorMessage; /// meta data name AString m_metaDataName; /// meta data value AString m_metaDataValue; /// element text AString m_elementText; /// GIFTI meta data being read StudyMetaDataLinkSet* m_studyMetaDataLinkSet; StudyMetaDataLink* m_studyMetaDataLinkBeingRead; }; } // namespace #endif // __STUDY_META_DATA_LINK_SET_SAX_READER_H__ connectome-workbench-1.4.2/src/Files/SurfaceFile.cxx000066400000000000000000001714261360521144700224130ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include "BoundingBox.h" #include "DataFileException.h" #include "DataFileTypeEnum.h" #include "SurfaceFile.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretOMP.h" #include "DataFileContentInformation.h" #include "DescriptiveStatistics.h" #include "FastStatistics.h" #include "EventSurfaceColoringInvalidate.h" #include "GiftiFile.h" #include "GiftiMetaDataXmlElements.h" #include "MathFunctions.h" #include "Matrix4x4.h" #include "Vector3D.h" #include "CaretPointLocator.h" #include "GeodesicHelper.h" #include "PlainTextStringBuilder.h" #include "SignedDistanceHelper.h" #include "TopologyHelper.h" using namespace caret; /** * Constructor. */ SurfaceFile::SurfaceFile() : GiftiTypeFile(DataFileTypeEnum::SURFACE) { m_skipSanityCheck = false;//NOTE: this is NOT in the initializeMembersSurfaceFile method, because that method gets used at the top of the validate function, //which is used by setNumberOfNodesAndTriangles, which temporarily puts it the triangles into an invalid state, which is why this flag exists this->initializeMembersSurfaceFile(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_SURFACE_COLORING_INVALIDATE); } /** * Copy constructor. * * @param sf * Surface file that is copied. */ SurfaceFile::SurfaceFile(const SurfaceFile& sf) : GiftiTypeFile(sf), EventListenerInterface() { m_skipSanityCheck = false;//see above this->initializeMembersSurfaceFile(); this->copyHelperSurfaceFile(sf); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_SURFACE_COLORING_INVALIDATE); } /** * Assignment operator. * * @param sf * Surface file that is copied. * @return * This surface file with content replaced * by the SurfaceFile parameter. */ SurfaceFile& SurfaceFile::operator=(const SurfaceFile& sf) { if (this != &sf) { GiftiTypeFile::operator=(sf); this->copyHelperSurfaceFile(sf); } return *this; } /** * Destructor. */ SurfaceFile::~SurfaceFile() { EventManager::get()->removeAllEventsFromListener(this); if (this->boundingBox != NULL) { delete this->boundingBox; this->boundingBox = NULL; } this->invalidateNodeColoringForBrowserTabs(); } void SurfaceFile::writeFile(const AString& filename) { if (!filename.endsWith(".surf.gii")) { CaretLogWarning("surface file '" + filename + "' should be saved ending in .surf.gii, see wb_command -gifti-help"); } caret::GiftiTypeFile::writeFile(filename); } /** * Clear the surface file. */ void SurfaceFile::clear() { if (this->boundingBox != NULL) { delete this->boundingBox; this->boundingBox = NULL; } coordinateDataArray = NULL; coordinatePointer = NULL; triangleDataArray = NULL; trianglePointer = NULL; GiftiTypeFile::clear(); invalidateHelpers(); this->invalidateNodeColoringForBrowserTabs(); } /** * Runs topology helper creation in a thread */ class CreateTopologyHelperThread : public QThread { public: CreateTopologyHelperThread(SurfaceFile* surfaceFile) { this->surfaceFile = surfaceFile; } ~CreateTopologyHelperThread() { std::cout << "Delete topology helper for " << this->surfaceFile->getFileNameNoPath() << std::endl; } void run() { /* * NEED to prevent SurfaceFile destructor from completing until this is done * Perhaps before starting this thread, set a variable in SurfaceFile and * then have this method clear the variable after topology helper is created. */ this->surfaceFile->getTopologyHelper(); this->deleteLater(); } SurfaceFile* surfaceFile; }; /** * Validate the contents of the file after it * has been read such as correct number of * data arrays and proper data types/dimensions. */ void SurfaceFile::validateDataArraysAfterReading() { this->initializeMembersSurfaceFile(); int numDataArrays = this->giftiFile->getNumberOfDataArrays(); if (numDataArrays != 2) { throw DataFileException(getFileName(), "Number of data arrays MUST be two in a SurfaceFile."); } /* * Find the coordinate and topology data arrays. */ for (int i = 0; i < numDataArrays; i++) { GiftiDataArray* gda = this->giftiFile->getDataArray(i); if (gda->getIntent() == NiftiIntentEnum::NIFTI_INTENT_POINTSET) { if (gda->getDataType() == NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32) { if (gda->getNumberOfDimensions() == 2) { int64_t dim0 = gda->getDimension(0); int64_t dim1 = gda->getDimension(1); if ((dim0 > 0) && (dim1 == 3)) { this->coordinateDataArray = gda; this->coordinatePointer = gda->getDataPointerFloat(); } } } } else if (gda->getIntent() == NiftiIntentEnum::NIFTI_INTENT_TRIANGLE) { if (gda->getDataType() == NiftiDataTypeEnum::NIFTI_TYPE_INT32) { if (gda->getNumberOfDimensions() == 2) { int64_t dim0 = gda->getDimension(0); int64_t dim1 = gda->getDimension(1); if ((dim0 > 0) && (dim1 == 3)) { this->triangleDataArray = gda; this->trianglePointer = gda->getDataPointerInt(); } } } } } AString errorMessage; if (this->coordinateDataArray == NULL) { errorMessage += "Unable to find coordinate data array which " " contains data type FLOAT32, Intent POINTSET, and two " " dimensions with the second dimension set to three. "; } if (this->triangleDataArray == NULL) { errorMessage += "Unable to find topology data array which " " contains data type INT32, Intent TRIANGLE, and two " " dimensions with the second dimension set to three."; } const int32_t numNodes = this->getNumberOfNodes(); if (!m_skipSanityCheck) { const int numTris = getNumberOfTriangles();//sanity check the triangle data array for (int i = 0; i < numTris; ++i) { const int32_t* thisTri = getTriangle(i); for (int j = 0; j < 3; ++j) { if (thisTri[j] < 0 || thisTri[j] >= numNodes) { errorMessage += "Invalid vertex in triangle array: triangle " + AString::number(i) + ", vertex " + AString::number(thisTri[j]); break; } for (int k = j + 1; k < 3; ++k) { if (thisTri[j] == thisTri[k]) { errorMessage += "Vertex used twice in one triangle: triangle " + AString::number(i) + ", vertex " + AString::number(thisTri[j]); break; } } } } if (errorMessage.isEmpty() == false) { throw DataFileException(getFileName(), errorMessage); } } this->computeNormals(); /* * Apply the first transformation matrix that transforms to * Talairach space. */ // Disable as FreeSurfer is inserting a matrix that causes issues in // HCP Pipeline // const AString talairachName = NiftiTransformEnum::toName(NiftiTransformEnum::NIFTI_XFORM_TALAIRACH); // for (int32_t im = 0; im < this->coordinateDataArray->getNumberOfMatrices(); im++) { // const Matrix4x4* m = this->coordinateDataArray->getMatrix(im); // if (m->getTransformedSpaceName() == talairachName) { // applyMatrix(*m); // break; // } // } /* * Create the topology helper in a thread so files dont' take * too long to read. */ // (new CreateTopologyHelperThread(this))->start(); } /** * Get the number of nodes. * * @return * The number of nodes. */ int32_t SurfaceFile::getNumberOfNodes() const { if (this->coordinatePointer == NULL) { return 0; } CaretAssert(this->coordinateDataArray); return this->coordinateDataArray->getDimension(0); } /** * Get the number of columns. * * @return * The number of columns. */ int32_t SurfaceFile::getNumberOfColumns() const { if (this->getNumberOfNodes() > 0) { return 1; } return 0; } void SurfaceFile::setNumberOfNodesAndTriangles(const int32_t& nodes, const int32_t& triangles) { if (this->boundingBox != NULL) { delete this->boundingBox; this->boundingBox = NULL; } coordinateDataArray = NULL; coordinatePointer = NULL; triangleDataArray = NULL; trianglePointer = NULL; giftiFile->clearAndKeepMetadata(); invalidateHelpers(); this->invalidateNodeColoringForBrowserTabs(); std::vector dims(2); dims[1] = 3; dims[0] = nodes; giftiFile->addDataArray(new GiftiDataArray(NiftiIntentEnum::NIFTI_INTENT_POINTSET, NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32, dims, GiftiEncodingEnum::GZIP_BASE64_BINARY)); dims[0] = triangles; giftiFile->addDataArray(new GiftiDataArray(NiftiIntentEnum::NIFTI_INTENT_TRIANGLE, NiftiDataTypeEnum::NIFTI_TYPE_INT32, dims, GiftiEncodingEnum::GZIP_BASE64_BINARY)); m_skipSanityCheck = true; validateDataArraysAfterReading(); m_skipSanityCheck = false; setModified(); } /** * Get a coordinate. * * @param * nodeIndex of coordinate. * * @return * Pointer to memory containing the XYZ coordinate. */ const float* SurfaceFile::getCoordinate(const int32_t nodeIndex) const { CaretAssert(this->coordinatePointer); const int32_t offset = nodeIndex * 3; CaretAssert((offset >= 0) && (offset < (this->getNumberOfNodes() * 3))); return &(this->coordinatePointer[offset]); } /** * Get a coordinate. * * @param * nodeIndex of coordinate. * @param xyzOut * Will contain coordinate upon exit. */ void SurfaceFile::getCoordinate(const int32_t nodeIndex, float xyzOut[3]) const { CaretAssert(this->coordinatePointer); const int32_t offset = nodeIndex * 3; CaretAssert((offset >= 0) && (offset < (this->getNumberOfNodes() * 3))); xyzOut[0] = this->coordinatePointer[offset]; xyzOut[1] = this->coordinatePointer[offset+1]; xyzOut[2] = this->coordinatePointer[offset+2]; } const float* SurfaceFile::getCoordinateData() const { CaretAssert(this->coordinatePointer); return this->coordinatePointer; } void SurfaceFile::setCoordinate(const int32_t nodeIndex, const float xyzIn[3]) { setCoordinate(nodeIndex, xyzIn[0], xyzIn[1], xyzIn[2]); } void SurfaceFile::setCoordinate(const int32_t nodeIndex, const float xIn, const float yIn, const float zIn) { CaretAssert(this->coordinatePointer); const int32_t offset = nodeIndex * 3; CaretAssert((offset >= 0) && (offset < (this->getNumberOfNodes() * 3))); this->coordinatePointer[offset] = xIn; this->coordinatePointer[offset+1] = yIn; this->coordinatePointer[offset+2] = zIn; invalidateNormals(); invalidateHelpers(); setModified(); } void SurfaceFile::setCoordinates(const float *coordinates) { CaretAssert(this->coordinatePointer); memcpy(this->coordinatePointer, coordinates, 3 * sizeof(float) * getNumberOfNodes()); invalidateHelpers(); invalidateNormals(); //setModified(); } /** * Get the number of triangles. * * @return * Number of triangles. */ int SurfaceFile::getNumberOfTriangles() const { if (this->trianglePointer == NULL) { return 0; } CaretAssert(this->triangleDataArray); return this->triangleDataArray->getDimension(0); } /** * Get a triangle. * * @param indx * Index of triangle. * * @return * Pointer to memory containing the three nodes * in the triangle. */ const int32_t* SurfaceFile::getTriangle(const int32_t indx) const { CaretAssert(this->trianglePointer != NULL); CaretAssert((indx >= 0) && (indx < this->getNumberOfTriangles())); const int32_t offset = indx * 3; return &(this->trianglePointer[offset]); } void SurfaceFile::setTriangle(const int32_t& index, const int32_t* nodes) { setTriangle(index, nodes[0], nodes[1], nodes[2]); } void SurfaceFile::setTriangle(const int32_t& index, const int32_t& node1, const int32_t& node2, const int32_t& node3) { CaretAssert(trianglePointer != NULL); CaretAssert((index >= 0) && (index < getNumberOfTriangles())); const int32_t offset = index * 3; trianglePointer[offset] = node1; trianglePointer[offset + 1] = node2; trianglePointer[offset + 2] = node3; invalidateHelpers(); invalidateNormals(); setModified(); } /** * Find the triangle that has an edge formed by "n1" and "n2" * but its not "oppositeTriangle". * * @param n1 * First node in the edge. * @param n2 * Second node in the edge. * @param oppositeTriangle * Triangle that on opposite side of the edge. * @return * Index of triangle or -1 if not found. If not * found surface must be open/cut. */ int32_t SurfaceFile::getTriangleThatSharesEdge(const int32_t n1, const int32_t n2, const int32_t oppositeTriangle) const { CaretPointer topoHelp = getTopologyHelper(); /* * Get the triangles used by one of the nodes */ int32_t numTriangles = 0; const int32_t* triangles = topoHelp->getNodeTiles(n1, numTriangles); for (int32_t i = 0; i < numTriangles; i++) { const int32_t t = triangles[i]; if (t != oppositeTriangle) { const int* nodes = this->getTriangle(t); if ((n1 == nodes[0]) || (n1 == nodes[1]) || (n1 == nodes[2])) { if ((n2 == nodes[0]) || (n2 == nodes[1]) || (n2 == nodes[2])) { return t; } } } } return -1; } /** * Initialize members of this class. */ void SurfaceFile::initializeMembersSurfaceFile() { this->coordinateDataArray = NULL; this->coordinatePointer = NULL; this->triangleDataArray = NULL; this->trianglePointer = NULL; this->boundingBox = NULL; m_distHelperIndex = 0; m_geoHelperIndex = 0; m_topoHelperIndex = 0; m_normalsComputed = false; } /** * Helps copying files. * * @param sf * File that is copied. */ void SurfaceFile::copyHelperSurfaceFile(const SurfaceFile& /*sf*/) { this->validateDataArraysAfterReading(); } /** * Get a normal vector for a coordinate. * * @param * Index of coordinate. * * @return * Pointer to memory containing the normal vector. */ const float* SurfaceFile::getNormalVector(const int32_t nodeIndex) const { const int32_t offset = nodeIndex * 3; CaretAssert((offset >= 0) && (offset < static_cast(this->normalVectors.size()))); return &(this->normalVectors[offset]); } /** * Get a normal vector for a coordinate. * * @param nodeIndex * Index of coordinate. * @param normalVectorOut * Output containing the normal vector for the node. */ void SurfaceFile::getNormalVector(const int32_t nodeIndex, float normalVectorOut[3]) const { const int32_t offset = nodeIndex * 3; CaretAssertVectorIndex(this->normalVectors, offset+2); normalVectorOut[0] = this->normalVectors[offset]; normalVectorOut[1] = this->normalVectors[offset+1]; normalVectorOut[2] = this->normalVectors[offset+2]; } const float* SurfaceFile::getNormalData() const { return normalVectors.data(); } void SurfaceFile::invalidateNormals() { m_normalsComputed = false; } /** * Compute surface normals. */ void SurfaceFile::computeNormals() { if (m_normalsComputed)//don't recompute when not needed { return; } m_normalsComputed = true; int32_t numCoords = this->getNumberOfNodes(); if (numCoords > 0) { this->normalVectors.resize(numCoords * 3); } else { this->normalVectors.clear(); } const int32_t numTriangles = this->getNumberOfTriangles(); if ((numCoords > 0) && (numTriangles > 0)) { float* normalPointer = &this->normalVectors[0]; std::vector numContribute(numCoords, 0); float triangleNormal[3]; for (int32_t i = 0; i < numTriangles; i++) { const int32_t it3 = i * 3; const int n1 = this->trianglePointer[it3]; const int n2 = this->trianglePointer[it3 + 1]; const int n3 = this->trianglePointer[it3 + 2]; const int32_t c1 = n1 * 3; const int32_t c2 = n2 * 3; const int32_t c3 = n3 * 3; if ((n1 >= 0) && (n2 >= 0) && (n3 >= 0)) { MathFunctions::normalVector(&this->coordinatePointer[c1], &this->coordinatePointer[c2], &this->coordinatePointer[c3], triangleNormal); normalPointer[c1 + 0] += triangleNormal[0];//+= is not guaranteed to be atomic, do not parallelize normalPointer[c1 + 1] += triangleNormal[1]; normalPointer[c1 + 2] += triangleNormal[2]; numContribute[n1] += 1; normalPointer[c2 + 0] += triangleNormal[0]; normalPointer[c2 + 1] += triangleNormal[1]; normalPointer[c2 + 2] += triangleNormal[2]; numContribute[n2] += 1; normalPointer[c3 + 0] += triangleNormal[0]; normalPointer[c3 + 1] += triangleNormal[1]; normalPointer[c3 + 2] += triangleNormal[2]; numContribute[n3] += 1; } } for (int i = 0; i < numCoords; i++) { const int i3 = i * 3; if (numContribute[i] > 0) { MathFunctions::normalizeVector(normalPointer + i3); } else { normalPointer[i3 + 0] = 0.0f;//zero the normals for unconnected nodes normalPointer[i3 + 1] = 0.0f; normalPointer[i3 + 2] = 0.0f; } } } } std::vector SurfaceFile::computeAverageNormals() { computeNormals(); const float* normalPointer = getNormalData(); int numCoords = getNumberOfNodes(); std::vector ret(numCoords * 3); CaretPointer myTopoHelp = getTopologyHelper();//TODO: make this not circular - separate base that doesn't handle helpers (and is used by helpers) from file that handles helpers and normals? for (int i = 0; i < numCoords; ++i) { int i3 = i * 3; Vector3D accum; const std::vector& neighbors = myTopoHelp->getNodeNeighbors(i); int numNeigh = (int)neighbors.size(); for (int j = 0; j < numNeigh; ++j) { accum += normalPointer + neighbors[j] * 3; } Vector3D outVec = accum.normal(); ret[i3] = outVec[0]; ret[i3 + 1] = outVec[1]; ret[i3 + 2] = outVec[2]; } return ret; } /** * Get the normal vector for a triangle. * @param triangleIndex * Index of the triangle. * @param normalOut * Output containing the normal for the triangle. */ void SurfaceFile::getTriangleNormalVector(const int32_t triangleIndex, float normalOut[3]) const { const int32_t it3 = triangleIndex * 3; const int n1 = this->trianglePointer[it3]; const int n2 = this->trianglePointer[it3 + 1]; const int n3 = this->trianglePointer[it3 + 2]; const int32_t c1 = n1 * 3; const int32_t c2 = n2 * 3; const int32_t c3 = n3 * 3; MathFunctions::normalVector(&this->coordinatePointer[c1], &this->coordinatePointer[c2], &this->coordinatePointer[c3], normalOut); } /** * @return The type of this surface. */ SurfaceTypeEnum::Enum SurfaceFile::getSurfaceType() const { if (this->coordinateDataArray == NULL) { return SurfaceTypeEnum::UNKNOWN; } const AString geometricTypeName = this->coordinateDataArray->getMetaData()->get(GiftiMetaDataXmlElements::METADATA_NAME_GEOMETRIC_TYPE); SurfaceTypeEnum::Enum surfaceType = SurfaceTypeEnum::fromGiftiName(geometricTypeName, NULL); return surfaceType; } /** * Sets the type of this surface. * @param surfaceType * New type for surface. */ void SurfaceFile::setSurfaceType(const SurfaceTypeEnum::Enum surfaceType) { if (this->coordinateDataArray == NULL) { return; } const AString geometricTypeName = SurfaceTypeEnum::toGiftiName(surfaceType); this->coordinateDataArray->getMetaData()->set(GiftiMetaDataXmlElements::METADATA_NAME_GEOMETRIC_TYPE, geometricTypeName); } /** * @return The secondary type of this surface. */ SecondarySurfaceTypeEnum::Enum SurfaceFile::getSecondaryType() const { if (this->coordinateDataArray == NULL) { return SecondarySurfaceTypeEnum::INVALID; } const AString secondaryTypeName = this->coordinateDataArray->getMetaData()->get(GiftiMetaDataXmlElements::METADATA_NAME_ANATOMICAL_STRUCTURE_SECONDARY); SecondarySurfaceTypeEnum::Enum surfaceType = SecondarySurfaceTypeEnum::fromGiftiName(secondaryTypeName, NULL); return surfaceType; } /** * Sets the type of this surface. * @param surfaceType * New type for surface. */ void SurfaceFile::setSecondaryType(const SecondarySurfaceTypeEnum::Enum secondaryType) { if (this->coordinateDataArray == NULL) { return; } const AString secondaryTypeName = SecondarySurfaceTypeEnum::toGiftiName(secondaryType); this->coordinateDataArray->getMetaData()->set(GiftiMetaDataXmlElements::METADATA_NAME_ANATOMICAL_STRUCTURE_SECONDARY, secondaryTypeName); } void SurfaceFile::getGeodesicHelper(CaretPointer& helpOut) const { {//lock before modifying member (base) CaretMutexLocker myLock(&m_geoHelperMutex); if (m_geoBase == NULL) { m_geoHelpers.clear();//just to be sure m_geoHelperIndex = 0; m_geoBase.grabNew(new GeodesicHelperBase(this));//yes, this takes some time, and is single threaded at the moment }//keep locked while searching int32_t& myIndex = m_geoHelperIndex; int32_t myEnd = m_geoHelpers.size(); for (int32_t i = 0; i < myEnd; ++i) { if (myIndex >= myEnd) myIndex = 0; if (m_geoHelpers[myIndex].getReferenceCount() == 1)//1 reference: in this class, so unused elsewhere { helpOut = m_geoHelpers[myIndex]; ++myIndex; return; } ++myIndex; } }//UNLOCK before building a new one, so they can be built in parallel - this actually just involves initializing the marked array CaretPointer ret(new GeodesicHelper(m_geoBase)); CaretMutexLocker myLock(&m_geoHelperMutex);//relock before modifying the array m_geoHelpers.push_back(ret); helpOut = ret; } CaretPointer SurfaceFile::getGeodesicHelper() const {//this convenience function is here because in order to guarantee thread safety, the real function explicitly copies to a reference argument before letting the mutex unlock CaretPointer ret;//the copy of a return should take place before destructors (including the locker for the helper mutex), but just to be safe getGeodesicHelper(ret);//this call is therefore thread safe and guaranteed to modify reference count before it unlocks the mutex for helpers return ret;//so we are already safe by here, at the expense of a second copy constructor/operator= of a CaretPointer } void SurfaceFile::getTopologyHelper(CaretPointer& helpOut, bool infoSorted) const { { CaretMutexLocker myLock(&m_topoHelperMutex);//lock before searching with the shared index int32_t& myIndex = m_topoHelperIndex; int32_t myEnd = m_topoHelpers.size(); for (int32_t i = 0; i < myEnd; ++i) { if (myIndex >= myEnd) myIndex = 0; if (m_topoHelpers[myIndex].getReferenceCount() == 1 && (!infoSorted || m_topoHelpers[myIndex]->isNodeInfoSorted()))//1 reference: in this class, so unused elsewhere { helpOut = m_topoHelpers[myIndex];//NOTE: can give sorted info to something that doesn't ask for sorted, if it already exists ++myIndex; return; } ++myIndex; } if (m_topoBase == NULL || (infoSorted && !m_topoBase->isNodeInfoSorted())) { m_topoBase.grabNew(new TopologyHelperBase(this, infoSorted)); } } CaretPointer ret(new TopologyHelper(m_topoBase)); CaretMutexLocker myLock(&m_topoHelperMutex);//lock before modifying the array m_topoHelpers.push_back(ret); helpOut = ret; } CaretPointer SurfaceFile::getTopologyHelper(bool infoSorted) const {//see convenience function for geo helper for explanation CaretPointer ret; getTopologyHelper(ret, infoSorted); return ret; } void SurfaceFile::getSignedDistanceHelper(CaretPointer& helpOut) const { { CaretMutexLocker myLock(&m_distHelperMutex);//lock before searching with the shared index int32_t& myIndex = m_distHelperIndex; int32_t myEnd = m_distHelpers.size(); for (int32_t i = 0; i < myEnd; ++i) { if (myIndex >= myEnd) myIndex = 0; if (m_distHelpers[myIndex].getReferenceCount() == 1)//1 reference: in this class, so unused elsewhere { helpOut = m_distHelpers[myIndex]; ++myIndex; return; } ++myIndex; } if (m_distBase == NULL) { m_distBase.grabNew(new SignedDistanceHelperBase(this)); } } CaretPointer ret(new SignedDistanceHelper(m_distBase)); CaretMutexLocker myLock(&m_distHelperMutex);//lock before modifying the array m_distHelpers.push_back(ret); helpOut = ret; } CaretPointer SurfaceFile::getSignedDistanceHelper() const {//see convenience function for geo helper for explanation CaretPointer ret; getSignedDistanceHelper(ret); return ret; } void SurfaceFile::invalidateHelpers() { if (m_geoBase != NULL) { CaretMutexLocker myLock(&m_geoHelperMutex);//make this function threadsafe m_geoHelperIndex = 0; m_geoHelpers.clear();//CaretPointers make this nice, if they are still in use elsewhere, they don't vanish, even though this class is supposed to "control" them to some extent m_geoBase.grabNew(NULL); } if (m_topoBase != NULL) { CaretMutexLocker myLock2(&m_topoHelperMutex); m_topoHelperIndex = 0; m_topoHelpers.clear(); m_topoBase.grabNew(NULL); } if (m_distBase != NULL) { CaretMutexLocker myLock4(&m_distHelperMutex); m_distHelperIndex = 0; m_distHelpers.clear(); m_distBase.grabNew(NULL); } if (m_locator != NULL) { CaretMutexLocker myLock3(&m_locatorMutex); m_locator.grabNew(NULL); } } /** * @return A bounding box for this surface. */ const BoundingBox* SurfaceFile::getBoundingBox() const { if (this->boundingBox == NULL) { this->boundingBox = new BoundingBox(); /* * For bounding box, must make sure each node is connected. */ CaretPointer th = this->getTopologyHelper(); const int32_t numberOfNodes = this->getNumberOfNodes(); for (int32_t i = 0; i < numberOfNodes; i++) { if (th->getNodeHasNeighbors(i)) { this->boundingBox->update(&this->coordinatePointer[i*3]); } } } return this->boundingBox; } /** * Match the surface to the given anatomical surface. If this * surface is an anatomical or raw surface, no action is taken. * * @param anatomicalSurfaceFile * Match to this anatomical surface file. * @param matchStatus * The match status */ void SurfaceFile::matchToAnatomicalSurface(const SurfaceFile* anatomicalSurfaceFile, const bool matchStatus) { CaretAssert(anatomicalSurfaceFile); if (anatomicalSurfaceFile == NULL) { return; } if (this == anatomicalSurfaceFile) { return; } if (matchStatus) { bool sphereMatchFlag(false); bool matchFlag(false); switch (getSurfaceType()) { case SurfaceTypeEnum::ANATOMICAL: break; case SurfaceTypeEnum::ELLIPSOID: break; case SurfaceTypeEnum::FLAT: matchFlag = true; break; case SurfaceTypeEnum::HULL: break; case SurfaceTypeEnum::INFLATED: matchFlag = true; break; case SurfaceTypeEnum::RECONSTRUCTION: break; case SurfaceTypeEnum::SEMI_SPHERICAL: break; case SurfaceTypeEnum::SPHERICAL: sphereMatchFlag = true; break; case SurfaceTypeEnum::UNKNOWN: break; case SurfaceTypeEnum::VERY_INFLATED: matchFlag = true; break; } if (matchFlag || sphereMatchFlag) { /* * Save the unmatched coordinates */ const int32_t numXYZ = getNumberOfNodes() * 3; m_unmatchedCoordinates.resize(numXYZ); CaretAssert(this->coordinatePointer); std::copy_n(this->coordinatePointer, numXYZ, m_unmatchedCoordinates.begin()); const bool modStatus(isModified()); if (sphereMatchFlag) { matchSphereToSurface(anatomicalSurfaceFile); if ( ! modStatus) { clearModified(); } } else if (matchFlag) { matchSurfaceBoundingBox(anatomicalSurfaceFile); if ( ! modStatus) { clearModified(); } } } } else { /* * Restore the unmatched coordinates */ const int32_t numXYZ = getNumberOfNodes() * 3; if (static_cast(m_unmatchedCoordinates.size()) == numXYZ) { CaretAssert(this->coordinatePointer); std::copy_n(m_unmatchedCoordinates.begin(), numXYZ, this->coordinatePointer); } m_unmatchedCoordinates.clear(); } } /** * Match a sphere to the given surface while retaining the spherical * shape. The center of gravity of the sphere will be the same as the center of gravity of * the match surface and the radius of the sphere will be the * distance furthest from the origin in the match surface. * * @param matchSurfaceFile * Match to this surface file. */ void SurfaceFile::matchSphereToSurface(const SurfaceFile* matchSurfaceFile) { CaretAssert(matchSurfaceFile); const float oldRadius = getSphericalRadius(); if (oldRadius <= 0.0) { CaretLogWarning("Match sphere has invalid radius"); return; } /* * Find match surface vertex distance furthest from origin (0,0,0) * This value will become the radius of the sphere */ CaretPointer matchTH = matchSurfaceFile->getTopologyHelper(); const int32_t numMatchVertices = matchSurfaceFile->getNumberOfNodes(); float newRadius = 0.0; for (int32_t i = 0; i < numMatchVertices; i++) { if (matchTH->getNodeHasNeighbors(i)) { const float* xyz = matchSurfaceFile->getCoordinate(i); const float dist = ((xyz[0]*xyz[0]) + (xyz[1]*xyz[1]) + (xyz[2]*xyz[2])); if (dist > newRadius) { newRadius = dist; } } } newRadius = std::sqrt(newRadius); float myCOG[3]; getCenterOfGravity(myCOG); float matchCOG[3]; matchSurfaceFile->getCenterOfGravity(matchCOG); Matrix4x4 matrix; /* * Scale to new radius */ const float scale = newRadius / oldRadius; matrix.scale(scale, scale, scale); applyMatrix(matrix); } /** * Get the center of gravity (average coordinate) of the surface. * * param cogOut * Output containing center of gravity. */ void SurfaceFile::getCenterOfGravity(float cogOut[3]) const { cogOut[0] = 0.0; cogOut[1] = 0.0; cogOut[2] = 0.0; const int32_t numberOfNodes = getNumberOfNodes(); CaretPointer th = this->getTopologyHelper(); double numberOfNodesWithNeighbors = 0.0; double cx(0.0), cy(0.0), cz(0.0); for (int32_t i = 0; i < numberOfNodes; i++) { if (th->getNodeHasNeighbors(i)) { const float* xyz = getCoordinate(i); cx += xyz[0]; cy += xyz[1]; cz += xyz[2]; numberOfNodesWithNeighbors += 1.0; } } if (numberOfNodesWithNeighbors > 0.0) { cogOut[0] = cx / numberOfNodesWithNeighbors; cogOut[1] = cy / numberOfNodesWithNeighbors; cogOut[2] = cz / numberOfNodesWithNeighbors; } } /** * Match this surface to the given surface. That is, after this * method is called, this surface and the given surface will * fit within the same bounding box. * @param surfaceFile * Match to this surface file. */ void SurfaceFile::matchSurfaceBoundingBox(const SurfaceFile* surfaceFile) { CaretAssert(surfaceFile); const BoundingBox* targetBoundingBox = surfaceFile->getBoundingBox(); const BoundingBox* myBoundingBox = getBoundingBox(); Matrix4x4 matrix; /* * Translate min x/y/z to origin */ matrix.translate(-myBoundingBox->getMinX(), -myBoundingBox->getMinY(), -myBoundingBox->getMinZ()); /* * Scale to match size of match surface */ float scaleX = (targetBoundingBox->getDifferenceX() / myBoundingBox->getDifferenceX()); float scaleY = (targetBoundingBox->getDifferenceY() / myBoundingBox->getDifferenceY()); float scaleZ = (targetBoundingBox->getDifferenceZ() / myBoundingBox->getDifferenceZ()); if (getSurfaceType() == SurfaceTypeEnum::FLAT) { /* * For a flat surface, need to retain overall shape. * Thus, just one scale factor that matches flat X-range * to 3D Y-range. */ const float scale = (targetBoundingBox->getDifferenceY() / myBoundingBox->getDifferenceX()); scaleX = scale; scaleY = scale; scaleZ = scale; } matrix.scale(scaleX, scaleY, scaleZ); /* * Translate to min x/y/z of match surface so that * the two surfaces are now within the same "shoebox". */ matrix.translate(targetBoundingBox->getMinX(), targetBoundingBox->getMinY(), targetBoundingBox->getMinZ()); applyMatrix(matrix); } /** * Apply the given matrix to the coordinates of this surface. * * @param matrix * Transformation matrix that is used. */ void SurfaceFile::applyMatrix(const Matrix4x4& matrix) { CaretPointer th = this->getTopologyHelper(); const int32_t numberOfNodes = getNumberOfNodes(); for (int32_t i = 0; i < numberOfNodes; i++) { if (th->getNodeHasNeighbors(i)) { matrix.multiplyPoint3(&coordinatePointer[i*3]); } } computeNormals(); setModified(); } /** * Translate to the surface center of mass. */ void SurfaceFile::translateToCenterOfMass() { const int32_t numberOfNodes = getNumberOfNodes(); CaretPointer th = this->getTopologyHelper(); double cx = 0.0; double cy = 0.0; double cz = 0.0; double numberOfNodesWithNeighbors = 0.0; for (int32_t i = 0; i < numberOfNodes; i++) { if (th->getNodeHasNeighbors(i)) { const float* xyz = getCoordinate(i); cx += xyz[0]; cy += xyz[1]; cz += xyz[2]; numberOfNodesWithNeighbors += 1.0; } } if (numberOfNodesWithNeighbors > 0.0) { cx /= numberOfNodesWithNeighbors; cy /= numberOfNodesWithNeighbors; cz /= numberOfNodesWithNeighbors; Matrix4x4 matrix; matrix.setTranslation(-cx, -cy, -cz); applyMatrix(matrix); } } /** * Flip the normal vectors. */ void SurfaceFile::flipNormals() { if (trianglePointer == NULL) return; const int numTiles = getNumberOfTriangles(); int32_t tempvert; for (int i = 0; i < numTiles; ++i)//swap first and second verts of all triangles { int offset = i * 3; tempvert = trianglePointer[offset]; trianglePointer[offset] = trianglePointer[offset + 1]; trianglePointer[offset + 1] = tempvert; } invalidateNormals(); invalidateHelpers();//sorted topology helpers would change, so just for completeness setModified(); } /** * @return True if normal vectors are correct, else false. * * Find the node with the greatest Z-coordinate. If the Z-component * of the this node's normal vector is positive, then the normal vectors * point out of the surface and they are correct. Otherwise, the normal * vectors are pointing into the surface. */ bool SurfaceFile::areNormalVectorsCorrect() const { CaretPointer th = this->getTopologyHelper(); float maxZ = -std::numeric_limits::max(); int32_t indxMaxZ = -1; const int32_t numberOfNodes = getNumberOfNodes(); for (int32_t i = 0; i < numberOfNodes; i++) { if (th->getNodeHasNeighbors(i)) { const float* xyz = getCoordinate(i); if (xyz[2] > maxZ) { maxZ = xyz[2]; indxMaxZ = i; } } } if (indxMaxZ >= 0) { const float* normal = getNormalVector(indxMaxZ); if (normal[2] > 0.0) { return true; } } return false; } /** * @return The radius of the spherical surface. * Surface is assumed spherical. */ float SurfaceFile::getSphericalRadius() const { const BoundingBox* bb = getBoundingBox(); const float radius = bb->getMaxX() - bb->getCenterX(); return radius; } /** * @return Area of the surface. */ float SurfaceFile::getSurfaceArea() const { float areaOut = 0.0; CaretAssert(this->trianglePointer); const int32_t numberOfTriangles = getNumberOfTriangles(); for (int32_t i = 0; i < numberOfTriangles; ++i) { const int32_t* triangleNodeIndices = getTriangle(i); const float* node1 = getCoordinate(triangleNodeIndices[0]); const float* node2 = getCoordinate(triangleNodeIndices[1]); const float* node3 = getCoordinate(triangleNodeIndices[2]); areaOut += MathFunctions::triangleArea(node1, node2, node3); } return areaOut; } void SurfaceFile::computeNodeAreas(std::vector& areasOut) const { CaretAssert(this->trianglePointer); int32_t triEnd = getNumberOfTriangles(); int32_t numNodes = getNumberOfNodes(); areasOut.resize(numNodes); for (int32_t i = 0; i < numNodes; ++i) { areasOut[i] = 0.0f; } for (int32_t i = 0; i < triEnd; ++i) { const int32_t* thisTri = getTriangle(i); const float* node1 = getCoordinate(thisTri[0]); const float* node2 = getCoordinate(thisTri[1]); const float* node3 = getCoordinate(thisTri[2]); float area3 = MathFunctions::triangleArea(node1, node2, node3) / 3.0f; areasOut[thisTri[0]] += area3; areasOut[thisTri[1]] += area3; areasOut[thisTri[2]] += area3; } } /** * Is the object modified? * @return true if modified, else false. */ void SurfaceFile::setModified() { if (this->boundingBox != NULL) { delete this->boundingBox; this->boundingBox = NULL; } GiftiTypeFile::setModified(); } int32_t SurfaceFile::closestNode(const float target[3], const float maxDist) const { if (maxDist > 0.0f) { return getPointLocator()->closestPointLimited(target, maxDist); } else { return getPointLocator()->closestPoint(target); } } CaretPointer SurfaceFile::getPointLocator() const { if (m_locator == NULL)//try to avoid locking even once { CaretMutexLocker myLock(&m_locatorMutex); if (m_locator == NULL)//test again AFTER lock to avoid race conditions { m_locator.grabNew(new CaretPointLocator(getCoordinateData(), getNumberOfNodes())); } } return m_locator; } void SurfaceFile::clearCachedHelpers() const { { CaretMutexLocker locked(&m_topoHelperMutex); m_topoHelperIndex = 0; m_topoHelpers.clear(); m_topoBase.grabNew(NULL); } { CaretMutexLocker locked(&m_geoHelperMutex); m_geoHelperIndex = 0; m_geoHelpers.clear(); m_geoBase.grabNew(NULL); } { CaretMutexLocker locked(&m_distHelperMutex); m_distHelperIndex = 0; m_distHelpers.clear(); m_distBase.grabNew(NULL); } { CaretMutexLocker locked(&m_locatorMutex); m_locator.grabNew(NULL); } } /** * @return Information about the surface. */ AString SurfaceFile::getInformation() const { AString txt; txt += ("Name: " + this->getFileNameNoPath() + "\n"); txt += ("Type: " + SurfaceTypeEnum::toGuiName(this->getSurfaceType()) + "\n"); const int32_t numberOfNodes = this->getNumberOfNodes(); txt += ("Number of Vertices: " + AString::number(numberOfNodes) + "\n"); txt += ("Number of Triangles: " + AString::number(this->getNumberOfTriangles()) + "\n"); txt += ("Bounds: (" + AString::fromNumbers(this->getBoundingBox()->getBounds(), 6, ", ") + ")\n"); if (numberOfNodes > 0) { // std::vector nodeSpacing; // nodeSpacing.reserve(numberOfNodes * 10); // CaretPointer th = this->getTopologyHelper(); // int numberOfNeighbors; // for (int32_t i = 0; i < numberOfNodes; i++) { // const int* neighbors = th->getNodeNeighbors(i, numberOfNeighbors); // for (int32_t j = 0; j < numberOfNeighbors; j++) { // const int n = neighbors[j]; // if (n > i) { // const float dist = MathFunctions::distance3D(this->getCoordinate(i), // this->getCoordinate(n)); // nodeSpacing.push_back(dist); // } // } // } // // DescriptiveStatistics stats; // stats.update(nodeSpacing); DescriptiveStatistics stats; getNodesSpacingStatistics(stats); const float mean = stats.getMean(); const float stdDev = stats.getStandardDeviationSample(); const float minValue = stats.getMinimumValue(); const float maxValue = stats.getMaximumValue(); txt += ("Spacing:\n"); txt += (" Mean: " + AString::number(mean, 'f', 6) + "\n"); txt += (" Std Dev: " + AString::number(stdDev, 'f', 6) + "\n"); txt += (" Minimum: " + AString::number(minValue, 'f', 6) + "\n"); txt += (" Maximum: " + AString::number(maxValue, 'f', 6) + "\n"); } return txt; } /** * Get statistics on node spacing. * @param statsOut * Upon exit, contains node spacing descriptive statistics. */ void SurfaceFile::getNodesSpacingStatistics(DescriptiveStatistics& statsOut) const { const int32_t numberOfNodes = this->getNumberOfNodes(); std::vector nodeSpacing; nodeSpacing.reserve(numberOfNodes * 10); CaretPointer th = this->getTopologyHelper(); int numberOfNeighbors; for (int32_t i = 0; i < numberOfNodes; i++) { const int* neighbors = th->getNodeNeighbors(i, numberOfNeighbors); for (int32_t j = 0; j < numberOfNeighbors; j++) { const int n = neighbors[j]; if (n > i) { const float dist = MathFunctions::distance3D(this->getCoordinate(i), this->getCoordinate(n)); nodeSpacing.push_back(dist); } } } statsOut.update(nodeSpacing); } void SurfaceFile::getNodesSpacingStatistics(FastStatistics& statsOut) const { const int32_t numberOfNodes = this->getNumberOfNodes(); std::vector nodeSpacing; nodeSpacing.reserve(numberOfNodes * 10); CaretPointer th = this->getTopologyHelper(); int numberOfNeighbors; for (int32_t i = 0; i < numberOfNodes; i++) { const int* neighbors = th->getNodeNeighbors(i, numberOfNeighbors); for (int32_t j = 0; j < numberOfNeighbors; j++) { const int n = neighbors[j]; if (n > i) { const float dist = MathFunctions::distance3D(this->getCoordinate(i), this->getCoordinate(n)); nodeSpacing.push_back(dist); } } } statsOut.update(nodeSpacing.data(), nodeSpacing.size()); } /** * Invalidate surface coloring. */ void SurfaceFile::invalidateNodeColoringForBrowserTabs() { /* * Free memory since could have many tabs and many surfaces equals lots of memory */ for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { this->surfaceNodeColoringForBrowserTabs[i].clear(); this->surfaceMontageNodeColoringForBrowserTabs[i].clear(); this->wholeBrainNodeColoringForBrowserTabs[i].clear(); } } /** * Allocate node coloring for a single surface in a browser tab. * @param browserTabIndex * Index of browser tab. * @param zeroizeColorsFlag * If true and memory is allocated for colors, the color components * are set to all zeros, otherwise the memory may be left unitialized. */ void SurfaceFile::allocateSurfaceNodeColoringForBrowserTab(const int32_t browserTabIndex, const bool zeroizeColorsFlag) { CaretAssertArrayIndex(this->surfaceNodeColoringForBrowserTabs, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); const uint64_t numberOfComponentsRGBA = this->getNumberOfNodes() * 4; if (this->surfaceNodeColoringForBrowserTabs[browserTabIndex].size() != numberOfComponentsRGBA) { if (zeroizeColorsFlag) { this->surfaceNodeColoringForBrowserTabs[browserTabIndex].resize(numberOfComponentsRGBA, 0.0); } else { this->surfaceNodeColoringForBrowserTabs[browserTabIndex].resize(numberOfComponentsRGBA); } } } /** * Allocate node coloring for a surface montage in a browser tab. * @param browserTabIndex * Index of browser tab. * @param zeroizeColorsFlag * If true and memory is allocated for colors, the color components * are set to all zeros, otherwise the memory may be left unitialized. */ void SurfaceFile::allocateSurfaceMontageNodeColoringForBrowserTab(const int32_t browserTabIndex, const bool zeroizeColorsFlag) { CaretAssertArrayIndex(this->surfaceMontageNodeColoringForBrowserTabs, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); const uint64_t numberOfComponentsRGBA = this->getNumberOfNodes() * 4; if (this->surfaceMontageNodeColoringForBrowserTabs[browserTabIndex].size() != numberOfComponentsRGBA) { if (zeroizeColorsFlag) { this->surfaceMontageNodeColoringForBrowserTabs[browserTabIndex].resize(numberOfComponentsRGBA, 0.0); } else { this->surfaceMontageNodeColoringForBrowserTabs[browserTabIndex].resize(numberOfComponentsRGBA); } } } /** * Allocate node coloring for a whole brain surface in a browser tab. * @param browserTabIndex * Index of browser tab. * @param zeroizeColorsFlag * If true and memory is allocated for colors, the color components * are set to all zeros, otherwise the memory may be left unitialized. */ void SurfaceFile::allocateWholeBrainNodeColoringForBrowserTab(const int32_t browserTabIndex, const bool zeroizeColorsFlag) { CaretAssertArrayIndex(this->wholeBrainNodeColoringForBrowserTabs, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); const uint64_t numberOfComponentsRGBA = this->getNumberOfNodes() * 4; if (this->wholeBrainNodeColoringForBrowserTabs[browserTabIndex].size() != numberOfComponentsRGBA) { if (zeroizeColorsFlag) { this->wholeBrainNodeColoringForBrowserTabs[browserTabIndex].resize(numberOfComponentsRGBA, 0.0); } else { this->wholeBrainNodeColoringForBrowserTabs[browserTabIndex].resize(numberOfComponentsRGBA); } } } /** * Get the RGBA color components for this single surface in the given tab. * @param browserTabIndex * Index of browser tab. * @return * Coloring for the tab or NULL if coloring is invalid and needs to be * set. */ float* SurfaceFile::getSurfaceNodeColoringRgbaForBrowserTab(const int32_t browserTabIndex) { CaretAssertArrayIndex(this->surfaceNodeColoringForBrowserTabs, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); std::vector& rgba = this->surfaceNodeColoringForBrowserTabs[browserTabIndex]; if (rgba.empty()) { return NULL; } return &rgba[0]; } /** * Set the RGBA color components for this a single surface in the given tab. * @param browserTabIndex * Index of browser tab. * @param rgbaNodeColorComponents * RGBA color components for this surface in the given tab. */ void SurfaceFile::setSurfaceNodeColoringRgbaForBrowserTab(const int32_t browserTabIndex, const float* rgbaNodeColorComponents) { CaretAssertArrayIndex(this->surfaceNodeColoringForBrowserTabs, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); this->allocateSurfaceNodeColoringForBrowserTab(browserTabIndex, false); const int numberOfComponentsRGBA = this->getNumberOfNodes() * 4; std::vector& rgba = this->surfaceNodeColoringForBrowserTabs[browserTabIndex]; for (int32_t i = 0; i < numberOfComponentsRGBA; i++) { rgba[i] = rgbaNodeColorComponents[i]; } } /** * Get the RGBA color components for this surface montage in the given tab. * @param browserTabIndex * Index of browser tab. * @return * Coloring for the tab or NULL if coloring is invalid and needs to be * set. */ float* SurfaceFile::getSurfaceMontageNodeColoringRgbaForBrowserTab(const int32_t browserTabIndex) { CaretAssertArrayIndex(this->surfaceMontageNodeColoringForBrowserTabs, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); std::vector& rgba = this->surfaceMontageNodeColoringForBrowserTabs[browserTabIndex]; if (rgba.empty()) { return NULL; } return &rgba[0]; } /** * Set the RGBA color components for this a surface montage in the given tab. * @param browserTabIndex * Index of browser tab. * @param rgbaNodeColorComponents * RGBA color components for this surface montage in the given tab. */ void SurfaceFile::setSurfaceMontageNodeColoringRgbaForBrowserTab(const int32_t browserTabIndex, const float* rgbaNodeColorComponents) { CaretAssertArrayIndex(this->surfaceMontageNodeColoringForBrowserTabs, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); this->allocateSurfaceMontageNodeColoringForBrowserTab(browserTabIndex, false); const int numberOfComponentsRGBA = this->getNumberOfNodes() * 4; std::vector& rgba = this->surfaceMontageNodeColoringForBrowserTabs[browserTabIndex]; for (int32_t i = 0; i < numberOfComponentsRGBA; i++) { rgba[i] = rgbaNodeColorComponents[i]; } } /** * Get the RGBA color components for this whole brain surface in the given tab. * @param browserTabIndex * Index of browser tab. * @return * Coloring for the tab or NULL if coloring is invalid and needs to be set. */ float* SurfaceFile::getWholeBrainNodeColoringRgbaForBrowserTab(const int32_t browserTabIndex) { CaretAssertArrayIndex(this->wholeBrainNodeColoringForBrowserTabs, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); std::vector& rgba = this->wholeBrainNodeColoringForBrowserTabs[browserTabIndex]; if (rgba.empty()) { return NULL; } return &rgba[0]; } /** * Set the RGBA color components for this a whole brain surface in the given tab. * @param browserTabIndex * Index of browser tab. * @param rgbaNodeColorComponents * RGBA color components for this surface in the given tab. */ void SurfaceFile::setWholeBrainNodeColoringRgbaForBrowserTab(const int32_t browserTabIndex, const float* rgbaNodeColorComponents) { CaretAssertArrayIndex(this->wholeBrainNodeColoringForBrowserTabs, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, browserTabIndex); this->allocateWholeBrainNodeColoringForBrowserTab(browserTabIndex, false); const int numberOfComponentsRGBA = this->getNumberOfNodes() * 4; std::vector& rgba = this->wholeBrainNodeColoringForBrowserTabs[browserTabIndex]; for (int32_t i = 0; i < numberOfComponentsRGBA; i++) { rgba[i] = rgbaNodeColorComponents[i]; } } /** * Receive an event. * * @param event * The event that the receive can respond to. */ void SurfaceFile::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_SURFACE_COLORING_INVALIDATE) { EventSurfaceColoringInvalidate* invalidateEvent = dynamic_cast(event); CaretAssert(invalidateEvent); invalidateEvent->setEventProcessed(); this->invalidateNodeColoringForBrowserTabs(); } } bool SurfaceFile::matchesTopology(const SurfaceFile& rhs) const { if (getNumberOfNodes() != rhs.getNumberOfNodes()) return false; int numTriangles = getNumberOfTriangles(); if (numTriangles != rhs.getNumberOfTriangles()) return false; for (int i = 0; i < numTriangles; ++i) { int i3 = i * 3; if (trianglePointer[i3] != rhs.trianglePointer[i3]) return false;//exactly same order of triangles and nodes, for strictest topology equivalence if (trianglePointer[i3 + 1] != rhs.trianglePointer[i3 + 1]) return false;//also, is a faster test if (trianglePointer[i3 + 2] != rhs.trianglePointer[i3 + 2]) return false; } return true; } bool SurfaceFile::hasNodeCorrespondence(const SurfaceFile& rhs) const { int numNodes = getNumberOfNodes(); if (numNodes != rhs.getNumberOfNodes()) return false; if (getNumberOfTriangles() != rhs.getNumberOfTriangles()) return false; if (matchesTopology(rhs)) return true;//short circuit the common, faster to check case, should fail very early if it fails at all CaretPointer myHelp = getTopologyHelper(), rightHelp = rhs.getTopologyHelper(); for (int i = 0; i < numNodes; ++i) { const std::vector& myNeigh = myHelp->getNodeNeighbors(i); const std::vector& rightNeigh = rightHelp->getNodeNeighbors(i); int mySize = (int)myNeigh.size(); if (mySize != (int)rightNeigh.size()) return false; std::set myUsed; for (int j = 0; j < mySize; ++j) { myUsed.insert(myNeigh[j]); } for (int j = 0; j < mySize; ++j) { if (myUsed.find(rightNeigh[j]) == myUsed.end()) return false; } } return true; } /** * Add information about the file to the data file information. * * @param dataFileInformation * Consolidates information about a data file. */ void SurfaceFile::addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) { GiftiTypeFile::addToDataFileContentInformation(dataFileInformation); dataFileInformation.addNameAndValue("Number of Triangles", getNumberOfTriangles()); dataFileInformation.addNameAndValue("Normal Vectors Correct", areNormalVectorsCorrect()); dataFileInformation.addNameAndValue("Surface Type (Primary)", SurfaceTypeEnum::toGuiName(getSurfaceType())); dataFileInformation.addNameAndValue("Surface Type (Secondary)", SecondarySurfaceTypeEnum::toGuiName(getSecondaryType())); const BoundingBox* boundingBox = getBoundingBox(); dataFileInformation.addNameAndValue("X-minimum", boundingBox->getMinX()); dataFileInformation.addNameAndValue("X-maximum", boundingBox->getMaxX()); dataFileInformation.addNameAndValue("Y-minimum", boundingBox->getMinY()); dataFileInformation.addNameAndValue("Y-maximum", boundingBox->getMaxY()); dataFileInformation.addNameAndValue("Z-minimum", boundingBox->getMinZ()); dataFileInformation.addNameAndValue("Z-maximum", boundingBox->getMaxZ()); if (getSurfaceType() == SurfaceTypeEnum::SPHERICAL) { dataFileInformation.addNameAndValue("Spherical Radius", getSphericalRadius()); } dataFileInformation.addNameAndValue("Surface Area", getSurfaceArea()); DescriptiveStatistics stats; getNodesSpacingStatistics(stats); dataFileInformation.addNameAndValue("Spacing Mean", stats.getMean()); dataFileInformation.addNameAndValue("Spacing Std Dev", stats.getStandardDeviationSample()); dataFileInformation.addNameAndValue("Spacing Minimum", stats.getMinimumValue()); dataFileInformation.addNameAndValue("Spacing Maximum", stats.getMaximumValue()); } /** * @return A String describing the content of this object. */ AString SurfaceFile::toString() const { PlainTextStringBuilder tb; getDescriptionOfContent(tb); return tb.getText(); } /** * Get a text description of the instance's content. * * @param descriptionOut * Description of the instance's content. */ void SurfaceFile::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const { descriptionOut.addLine("Surface: " + getFileNameNoPath()); descriptionOut.addLine(" Structure: " + StructureEnum::toGuiName(getStructure())); descriptionOut.addLine(" Primary Type: " + SurfaceTypeEnum::toGuiName(getSurfaceType())); descriptionOut.addLine(" Secondary Type: " + SecondarySurfaceTypeEnum::toGuiName(getSecondaryType())); } connectome-workbench-1.4.2/src/Files/SurfaceFile.h000066400000000000000000000277251360521144700220420ustar00rootroot00000000000000 #ifndef __SURFACE_FILE_H__ #define __SURFACE_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "BrainConstants.h" #include "CaretMutex.h" #include "CaretPointer.h" #include "EventManager.h" #include "EventListenerInterface.h" #include "GiftiTypeFile.h" #include "SurfaceTypeEnum.h" namespace caret { class BoundingBox; class CaretPointLocator; class DescriptiveStatistics; class FastStatistics; class GeodesicHelper; class GeodesicHelperBase; class GiftiDataArray; class Matrix4x4; class PlainTextStringBuilder; class SignedDistanceHelper; class SignedDistanceHelperBase; class TopologyHelper; class TopologyHelperBase; /** * A surface data file. */ class SurfaceFile : public GiftiTypeFile, EventListenerInterface { public: SurfaceFile(); SurfaceFile(const SurfaceFile& sf); SurfaceFile& operator=(const SurfaceFile& sf); virtual ~SurfaceFile(); virtual void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation); virtual void receiveEvent(Event* event); virtual void clear(); virtual int32_t getNumberOfNodes() const; virtual int32_t getNumberOfColumns() const; void setNumberOfNodesAndTriangles(const int32_t& nodes, const int32_t& triangles); const float* getCoordinate(const int32_t nodeIndex) const; void getCoordinate(const int32_t nodeIndex, float xyzOut[3]) const; void setCoordinate(const int32_t nodeIndex, const float xyzIn[3]); void setCoordinate(const int32_t nodeIndex, const float xIn, const float yIn, const float zIn); void setCoordinates(const float *coordinates); const float* getCoordinateData() const; const float* getNormalVector(const int32_t nodeIndex) const; void getNormalVector(const int32_t nodeIndex, float normalVectorOut[3]) const; const float* getNormalData() const; int getNumberOfTriangles() const; const int32_t* getTriangle(const int32_t index) const; void setTriangle(const int32_t& index, const int32_t* nodes); void setTriangle(const int32_t& index, const int32_t& node1, const int32_t& node2, const int32_t& node3); int32_t getTriangleThatSharesEdge(const int32_t n1, const int32_t n2, const int32_t oppositeTriangle) const; void computeNormals(); std::vector computeAverageNormals(); void getTriangleNormalVector(const int32_t triangleIndex, float normalOut[3]) const; SurfaceTypeEnum::Enum getSurfaceType() const; void setSurfaceType(const SurfaceTypeEnum::Enum surfaceType); SecondarySurfaceTypeEnum::Enum getSecondaryType() const; void setSecondaryType(const SecondarySurfaceTypeEnum::Enum secondaryType); float getSphericalRadius() const; float getSurfaceArea() const; CaretPointer getTopologyHelper(bool infoSorted = false) const; void getTopologyHelper(CaretPointer& helpOut, bool infoSorted = false) const; CaretPointer getGeodesicHelper() const; void getGeodesicHelper(CaretPointer& helpOut) const; CaretPointer getSignedDistanceHelper() const; void getSignedDistanceHelper(CaretPointer& helpOut) const; CaretPointer getPointLocator() const; void clearCachedHelpers() const; const BoundingBox* getBoundingBox() const; void matchSurfaceBoundingBox(const SurfaceFile* surfaceFile); void matchSphereToSurface(const SurfaceFile* surfaceFile); void matchToAnatomicalSurface(const SurfaceFile* anatomicalSurfaceFile, const bool matchStatus); void getCenterOfGravity(float cogOut[3]) const; void applyMatrix(const Matrix4x4& matrix); void getNodesSpacingStatistics(DescriptiveStatistics& statsOut) const; void getNodesSpacingStatistics(FastStatistics& statsOut) const; void computeNodeAreas(std::vector& areasOut) const; ///find the closest node on the surface, within maxDist if maxDist is positive int32_t closestNode(const float target[3], const float maxDist = -1.0f) const; virtual void setModified(); AString getInformation() const; float* getSurfaceNodeColoringRgbaForBrowserTab(const int32_t browserTabIndex); void setSurfaceNodeColoringRgbaForBrowserTab(const int32_t browserTabIndex, const float* rgbaNodeColorComponents); float* getSurfaceMontageNodeColoringRgbaForBrowserTab(const int32_t browserTabIndex); void setSurfaceMontageNodeColoringRgbaForBrowserTab(const int32_t browserTabIndex, const float* rgbaNodeColorComponents); float* getWholeBrainNodeColoringRgbaForBrowserTab(const int32_t browserTabIndex); void setWholeBrainNodeColoringRgbaForBrowserTab(const int32_t browserTabIndex, const float* rgbaNodeColorComponents); void invalidateNormals(); void translateToCenterOfMass(); void flipNormals(); bool areNormalVectorsCorrect() const; ///check that it has EXACTLY the same topology, with no flipped normals or rotated or reordered triangles bool matchesTopology(const SurfaceFile& rhs) const; ///check only that each node is connected to the same set of other nodes, allow any other form of mischief bool hasNodeCorrespondence(const SurfaceFile& rhs) const; virtual AString toString() const; virtual void getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const; //override writeFile in order to check filename against type of file virtual void writeFile(const AString& filename); protected: /** * Validate the contents of the file after it * has been read such as correct number of * data arrays and proper data types/dimensions. */ virtual void validateDataArraysAfterReading(); void copyHelperSurfaceFile(const SurfaceFile& sf); void initializeMembersSurfaceFile(); private: void invalidateNodeColoringForBrowserTabs(); void allocateSurfaceNodeColoringForBrowserTab(const int32_t browserTabIndex, const bool zeroizeColorsFlag); void allocateSurfaceMontageNodeColoringForBrowserTab(const int32_t browserTabIndex, const bool zeroizeColorsFlag); void allocateWholeBrainNodeColoringForBrowserTab(const int32_t browserTabIndex, const bool zeroizeColorsFlag); /** Data array containing the coordinates. */ GiftiDataArray* coordinateDataArray; /** * This coloring is used when a ONE surface is displayed. * Node color components Red, Green, Blue, Alpha for each browser tab. * Each element of the vector points to the coloring * for a browser tab with the corresponding index. */ std::vector surfaceNodeColoringForBrowserTabs[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** * This coloring is used when a surface montage is displayed. * Node color components Red, Green, Blue, Alpha for each browser tab. * Each element of the vector points to the coloring * for a browser tab with the corresponding index. */ std::vector surfaceMontageNodeColoringForBrowserTabs[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** * This coloring is used when a Whole Brain is displayed. * Node color components Red, Green, Blue, Alpha for each browser tab. * Each element of the vector points to the coloring * for a browser tab with the corresponding index. */ std::vector wholeBrainNodeColoringForBrowserTabs[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; /** Points to memory containing the coordinates. */ float* coordinatePointer; /** Data array containing the triangles. */ GiftiDataArray* triangleDataArray; /** Points to memory containing the triangles. */ int32_t* trianglePointer; /** surface normal vectors. */ std::vector normalVectors; /** Coordinates before matching surface to anatomical */ std::vector m_unmatchedCoordinates; bool m_normalsComputed; bool m_skipSanityCheck; ///topology base for surface mutable CaretPointer m_topoBase; ///tracks allocated TopologyHelpers for this class mutable std::vector > m_topoHelpers; ///used to search through topology helpers without starting from 0 every time, wraps around mutable int32_t m_topoHelperIndex; ///the geodesic base for this surface mutable CaretPointer m_geoBase; ///tracks allocated geodesic helpers for this class mutable std::vector > m_geoHelpers; ///used to search through geodesic helpers without starting from 0 every time, wraps around mutable int32_t m_geoHelperIndex; ///the geodesic base for this surface mutable CaretPointer m_distBase; ///tracks allocated geodesic helpers for this class mutable std::vector > m_distHelpers; ///used to search through geodesic helpers without starting from 0 every time, wraps around mutable int32_t m_distHelperIndex; ///used to search for the closest point in the surface mutable CaretPointer m_locator; ///used to track when the surface file gets changed void invalidateHelpers(); mutable BoundingBox* boundingBox; mutable CaretMutex m_topoHelperMutex, m_geoHelperMutex, m_locatorMutex, m_distHelperMutex; }; } // namespace #endif // __SURFACE_FILE_H__ connectome-workbench-1.4.2/src/Files/SurfacePlaneIntersectionToContour.cxx000066400000000000000000000406561360521144700270370ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __SURFACE_PLANE_INTERSECTION_TO_CONTOUR_DECLARE__ #include "SurfacePlaneIntersectionToContour.h" #undef __SURFACE_PLANE_INTERSECTION_TO_CONTOUR_DECLARE__ #include "CaretAssert.h" #include "CaretException.h" #include "CaretLogger.h" #include "CaretOMP.h" #include "ElapsedTimer.h" #include "GraphicsPrimitiveV3fC4f.h" #include "Plane.h" #include "SurfaceFile.h" #include "TopologyHelper.h" using namespace caret; /** * \class caret::SurfacePlaneIntersectionToContour * \brief Create a contour from intersecting the plane with a surface. * \ingroup Files * * This algorithm is model upon these papers: * * Utilizing Topological Information to Increase Scan Vector Generation Efficiency * Stephen J. Rock Michael J. Wozny * Rensselaer Design Research Center Rensselaer Polytechnic Institute Troy, New York 12180 * Appears in Solid Freeform Fabrication Symposium Proceedings, H. L. Marcus, et. al. (eds.), pp. 28-36, The University of Texas at Austin, Austin, TX, 1991. * https://pdfs.semanticscholar.org/1129/b21303dcae34fed2a523f5991f8a1f9b3e32.pdf * * * A Simple Arbitrary Solid Slicer * Jin Yao * B-Division, Lawrence Livermore National Laboratory Livermore, California 94551 * https://e-reports-ext.llnl.gov/pdf/321754.pdf * */ /** * Constructor. * * @param surfaceFile * The surface file. * @param plane * Plane intersected with the surface. * @param caretColor * Solid coloring or, if value is CUSTOM, use the vertex coloring * @param vertexColoringRGBA * The per-vertex coloring if 'caretColor' is CUSTOM * @param contourThicknessPercentOfViewportHeight * Thickness for the contour as a percentage of viewport height. */ SurfacePlaneIntersectionToContour::SurfacePlaneIntersectionToContour(const SurfaceFile* surfaceFile, const Plane& plane, const CaretColorEnum::Enum caretColor, const float* vertexColoringRGBA, const float contourThicknessPercentOfViewportHeight) : CaretObject(), m_surfaceFile(surfaceFile), m_plane(plane), m_caretColor(caretColor), m_vertexColoringRGBA(vertexColoringRGBA), m_contourThicknessPercentOfViewportHeight(contourThicknessPercentOfViewportHeight) { CaretAssert(m_surfaceFile); CaretColorEnum::toRGBAFloat(caretColor, m_solidRGBA.data()); } /** * Destructor. */ SurfacePlaneIntersectionToContour::~SurfacePlaneIntersectionToContour() { } /** * Create the contour(s). * * @param graphicsPrimitivesOut * On exit, contains primitives for drawing the contours. * @param errorMessageOut * Output containing the error message. * @return * True if successful, otherwise false. */ bool SurfacePlaneIntersectionToContour::createContours(std::vector& graphicsPrimitivesOut, AString& errorMessageOut) { graphicsPrimitivesOut.clear(); errorMessageOut.clear(); try { if (m_surfaceFile->getNumberOfNodes() <= 2) { throw CaretException("Surface has an invalid number of vertices."); } if ( ! m_plane.isValidPlane()) { throw CaretException("Plane is invalid."); } m_topologyHelper = m_surfaceFile->getTopologyHelper(true); if (m_topologyHelper->getNumberOfNodes() <= 2) { throw CaretException("Toplogy helper has an invalid number of vertices."); } if (m_surfaceFile->getNumberOfNodes() != m_topologyHelper->getNumberOfNodes()) { throw CaretException("Surface File and its Topology contain a different number of vertices."); } static bool timingFlag = false; ElapsedTimer timer; if (timingFlag) { timer.start(); } prepareVertices(); const float verticesTime = (timingFlag ? timer.getElapsedTimeMilliseconds(): 0.0f); prepareEdges(); const float edgesTime = (timingFlag ? timer.getElapsedTimeMilliseconds() - verticesTime : 0.0f); generateContours(graphicsPrimitivesOut); const float contoursTime = (timingFlag ? timer.getElapsedTimeMilliseconds() - edgesTime : 0.0f); if (timingFlag) { std::cout << "Total Time=" << timer.getElapsedTimeMilliseconds() << std::endl; std::cout << " Vertices=" << verticesTime << std::endl; std::cout << " Edges=" << edgesTime << std::endl; std::cout << " Contours=" << contoursTime << std::endl; } } catch (const CaretException& caretException) { errorMessageOut = caretException.whatString(); return false; } return true; } /** * Prepare the vertices by computing their signed distance from the plane. * If vertex is on of very, very close to the plane, move the vertex * away from the play by a very small amount so that the plane * always intersects edges and never at a vertex. */ void SurfacePlaneIntersectionToContour::prepareVertices() { const float epsilon = 0.0000001f; CaretAssert(m_surfaceFile); float planeNormalVector[3]; m_plane.getNormalVector(planeNormalVector); const float abovePlaneOffset[3] = { planeNormalVector[0] * epsilon, planeNormalVector[1] * epsilon, planeNormalVector[2] * epsilon }; const float* surfaceXYZ = m_surfaceFile->getCoordinateData(); const int32_t numberOfVertices = m_surfaceFile->getNumberOfNodes(); m_vertices.resize(numberOfVertices); #pragma omp CARET_PARFOR for (int32_t i = 0; i < numberOfVertices; i++) { const int32_t i3 = i * 3; std::array xyz = {{ surfaceXYZ[i3], surfaceXYZ[i3 + 1], surfaceXYZ[i3 + 2] }}; const float signedDistanceToPlane = m_plane.signedDistanceToPlane(xyz.data()); if ((signedDistanceToPlane < epsilon) && (signedDistanceToPlane > -epsilon)) { /* * Point is on or nearly on the plane so move it away from the plane */ float projectedXYZ[3]; m_plane.projectPointToPlane(xyz.data(), projectedXYZ); if (signedDistanceToPlane >= 0) { xyz[0] = projectedXYZ[0] + abovePlaneOffset[0]; xyz[1] = projectedXYZ[1] + abovePlaneOffset[1]; xyz[2] = projectedXYZ[2] + abovePlaneOffset[2]; } else { xyz[0] = projectedXYZ[0] - abovePlaneOffset[0]; xyz[1] = projectedXYZ[1] - abovePlaneOffset[1]; xyz[2] = projectedXYZ[2] - abovePlaneOffset[2]; } } m_vertices[i].reset(new Vertex(xyz, signedDistanceToPlane)); } CaretAssert(static_cast(m_vertices.size()) == numberOfVertices); } /** * Find the edges that intersect the plane and save * information about these intersecting edges. */ void SurfacePlaneIntersectionToContour::prepareEdges() { const std::vector& allEdgeInfo = m_topologyHelper->getEdgeInfo(); const int32_t numEdges = static_cast(allEdgeInfo.size()); m_topoHelperEdgeToIntersectingEdgeIndices.reserve(numEdges); for (int32_t i = 0; i < numEdges; i++) { CaretAssertVectorIndex(allEdgeInfo, i); const TopologyEdgeInfo& edgeInfo = allEdgeInfo[i]; const int32_t indexOne = edgeInfo.node1; const int32_t indexTwo = edgeInfo.node2; CaretAssertVectorIndex(m_vertices, indexOne); CaretAssertVectorIndex(m_vertices, indexTwo); int32_t intersectingEdgeIndex = -1; /* * We are only interested in edges that have one vertex below the plane * and one vertex above the plane so the edge MUST intersect the plane. */ if (m_vertices[indexOne]->m_abovePlaneFlag != m_vertices[indexTwo]->m_abovePlaneFlag) { const int32_t abovePlaneVertexIndex = (m_vertices[indexOne]->m_abovePlaneFlag ? indexOne : indexTwo); const int32_t belowPlaneVertexIndex = (m_vertices[indexOne]->m_abovePlaneFlag ? indexTwo : indexOne); std::array intersectionXYZ; const bool validFlag = m_plane.lineSegmentIntersectPlane(m_vertices[belowPlaneVertexIndex]->m_xyz.data(), m_vertices[abovePlaneVertexIndex]->m_xyz.data(), intersectionXYZ.data()); if (validFlag) { /* * Get the edge's triangles */ if (edgeInfo.numTiles <= 0) { const AString msg = ("Edge index=" + AString::number(i) + " contains zero triangles. This should never happend!"); throw CaretException(msg); } int32_t triangleOne(edgeInfo.tiles[0].tile); int32_t triangleTwo(-1); if (edgeInfo.numTiles > 1) { triangleTwo = edgeInfo.tiles[1].tile; } std::unique_ptr edge(new IntersectionEdge(intersectionXYZ, belowPlaneVertexIndex, abovePlaneVertexIndex, triangleOne, triangleTwo)); m_intersectingEdges.push_back(std::move(edge)); intersectingEdgeIndex = m_intersectingEdges.size() - 1; m_numberOfIntersectingEdges++; } } m_topoHelperEdgeToIntersectingEdgeIndices.push_back(intersectingEdgeIndex); } CaretAssert(static_cast(m_topoHelperEdgeToIntersectingEdgeIndices.size()) == numEdges); } /** * Examine edges and find contours by moving from edge to neighboring triangle to edge. * In many instances, there will be more than one contour due to the way the * cortex intersects the plane. * * @param graphicsPrimitivesOut * On exit, contains primitives for drawing the contours. */ void SurfacePlaneIntersectionToContour::generateContours(std::vector& graphicsPrimitivesOut) { if (m_debugFlag) { std::cout << "*********************************************" << std::endl; } for (auto& edge : m_intersectingEdges) { if ( ! edge->m_processedFlag) { GraphicsPrimitive* primitive = generateContourFromEdge(edge.get()); if (primitive != NULL) { graphicsPrimitivesOut.push_back(primitive); } } } } /** * Starting with the given edge, follow the intersecting edges to create a contour. * The contour will end when it returns to the original edge or encounters an * edge that is used by only one triangle. An edge with one triangle indicates * open topology such as a surface without a medial wall. * * @param startingEdge * First edge in the contour. */ GraphicsPrimitive* SurfacePlaneIntersectionToContour::generateContourFromEdge(IntersectionEdge* startingEdge) { static std::array debugRgba = {{ 1.0f, 1.0f, 0.0f, 1.0f }}; static std::array startDebugRgba = {{ 0.0, 1.0, 0.0, 1.0 }}; static std::array endDebugRgba = {{ 1.0, 0.0, 0.0, 1.0 }}; const std::vector& allTileInfo = m_topologyHelper->getTileInfo(); std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN)); primitive->setLineWidth(GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, m_contourThicknessPercentOfViewportHeight); primitive->reserveForNumberOfVertices(m_numberOfIntersectingEdges + 5); IntersectionEdge* edge = startingEdge; if (m_debugFlag) { std::cout << "Start: " << startingEdge->toString() << std::endl; } while (edge != NULL) { edge->m_processedFlag = true; IntersectionEdge* nextEdge = NULL; for (int32_t iTile = 0; iTile < 2; iTile++) { CaretAssert(edge); const int32_t tileIndex = (iTile == 0) ? edge->m_triangleOneIndex : edge->m_triangleTwoIndex; if (tileIndex >= 0) { CaretAssertVectorIndex(allTileInfo, tileIndex); const TopologyTileInfo& tileInfo = allTileInfo[tileIndex]; for (int32_t iEdge = 0; iEdge < 3; iEdge++) { const int32_t tileEdgeIndex = tileInfo.edges[iEdge].edge; const int32_t intersectingEdgeIndex = m_topoHelperEdgeToIntersectingEdgeIndices[tileEdgeIndex]; if (intersectingEdgeIndex >= 0) { CaretAssertVectorIndex(m_intersectingEdges, intersectingEdgeIndex); if ( ! m_intersectingEdges[intersectingEdgeIndex]->m_processedFlag) { nextEdge = m_intersectingEdges[intersectingEdgeIndex].get(); break; } } } if (nextEdge != NULL) { break; } } } std::array colorRGBA = m_solidRGBA; if (m_debugFlag) { colorRGBA = debugRgba; if (primitive->getNumberOfVertices() == 0) { colorRGBA = startDebugRgba; } if (nextEdge == NULL) { colorRGBA = endDebugRgba; if (m_debugFlag) { std::cout << " End: " << edge->toString() << std::endl; } } } else { if (m_caretColor == CaretColorEnum::CUSTOM) { CaretAssert(m_vertexColoringRGBA); const int32_t belowI4 = edge->m_belowPlaneVertexIndex * 4; const int32_t aboveI4 = edge->m_abovePlaneVertexIndex * 4; for (int32_t m = 0; m < 4; m++) { colorRGBA[m] = ((m_vertexColoringRGBA[belowI4+m] + m_vertexColoringRGBA[aboveI4+m]) / 2.0f); } } } primitive->addVertex(edge->m_intersectionXYZ.data(), colorRGBA.data()); if (startingEdge->hasMatchingTriangle(edge)) { if (primitive->getNumberOfVertices() > 3) { if (m_debugFlag) { primitive->addVertex(startingEdge->m_intersectionXYZ.data(), startDebugRgba.data()); std::cout << " Closed contour" << std::endl; } else { primitive->addVertex(startingEdge->m_intersectionXYZ.data(), colorRGBA.data()); } } } edge = nextEdge; } if (m_debugFlag) { std::cout << " Contour vertex count: " << primitive->getNumberOfVertices() << std::endl; } if (primitive->isValid()) { return primitive.release(); } return NULL; } connectome-workbench-1.4.2/src/Files/SurfacePlaneIntersectionToContour.h000066400000000000000000000202731360521144700264550ustar00rootroot00000000000000#ifndef __SURFACE_PLANE_INTERSECTION_TO_CONTOUR_H__ #define __SURFACE_PLANE_INTERSECTION_TO_CONTOUR_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretColorEnum.h" #include "CaretObject.h" #include "CaretPointer.h" #include "TopologyHelper.h" namespace caret { class GraphicsPrimitive; class Plane; class SurfaceFile; class SurfacePlaneIntersectionToContour : public CaretObject { public: SurfacePlaneIntersectionToContour(const SurfaceFile* surfaceFile, const Plane& plane, const CaretColorEnum::Enum caretColor, const float* vertexColoringRGBA, const float contourThicknessMillimeters); virtual ~SurfacePlaneIntersectionToContour(); bool createContours(std::vector& graphicsPrimitivesOut, AString& errorMessageOut); // ADD_NEW_METHODS_HERE private: /** * Contains information about each surface vertex * and its relationship to the plane */ class Vertex { public: /** * Constructor. * * @param xyz * The coordinate of the vertex. * @param signedDistanceAbovePlane * Distance of vertex above the plane. * (negative if below the plane). */ Vertex(const std::array& xyz, const float signedDistanceAbovePlane) : m_xyz(xyz), m_signedDistanceAbovePlane(signedDistanceAbovePlane), m_abovePlaneFlag(signedDistanceAbovePlane > 0.0f) { } ~Vertex() { } /** Coordinate of vertex */ const std::array m_xyz; /** Distance above plane (negative if below plane) */ const float m_signedDistanceAbovePlane; /** True if above plane, else false */ const bool m_abovePlaneFlag; }; /* * Contains information about an edge that intersects the plane */ class IntersectionEdge { public: /** * Constructor. * * @param intersectionXYZ * Location in the edge that intersects the plane * @param belowPlaneVertexIndex * Vertex in the edge that is below the plane. * @param abovePlaneVertexIndex * Vertex in the edge that is above the plane. * @param triangleOneIndex * Index of a triangle that shares edge. This triangle * will always be valid. * @param triangleTwoIndex * Index of a triangle that shares edge. This triangle * may be invalid if the edge is on the boundary * of an open topology. */ IntersectionEdge(const std::array& intersectionXYZ, int32_t belowPlaneVertexIndex, int32_t abovePlaneVertexIndex, int32_t triangleOneIndex, int32_t triangleTwoIndex) : m_intersectionXYZ(intersectionXYZ), m_belowPlaneVertexIndex(belowPlaneVertexIndex), m_abovePlaneVertexIndex(abovePlaneVertexIndex), m_triangleOneIndex(triangleOneIndex), m_triangleTwoIndex(triangleTwoIndex) { } /** * True if this and the other edge are connected to the same triangle. * @param otherEdge * The other edge * @return * True if connected to same triangle, else false. */ bool hasMatchingTriangle(const IntersectionEdge* otherEdge) { if ((m_triangleOneIndex == otherEdge->m_triangleOneIndex) || (m_triangleOneIndex == otherEdge->m_triangleTwoIndex)) { return true; } if (m_triangleTwoIndex >= 0) { if ((m_triangleTwoIndex == otherEdge->m_triangleOneIndex) || (m_triangleTwoIndex == otherEdge->m_triangleTwoIndex)) { return true; } } return false; } AString toString() const { AString msg("Intersection=(" + AString::fromNumbers(m_intersectionXYZ.data(), 3, ",") + ") below=" + AString::number(m_belowPlaneVertexIndex) + " aboveV=" + AString::number(m_abovePlaneVertexIndex) + " T1=" + AString::number(m_triangleOneIndex) + " T2=" + AString::number(m_triangleTwoIndex)); return msg; } /** coordinate of where edge intersects plane */ std::array m_intersectionXYZ; /** vertex below the plane (index for surface vertex, topology helper vertex, and this class' m_vertices */ int32_t m_belowPlaneVertexIndex; /** vertex above the plane */ int32_t m_abovePlaneVertexIndex; /** first triangle used by edge (index for ToplogyHelper's TopologyTileInfo) */ int32_t m_triangleOneIndex; /** second triangle used by edge (index for ToplogyHelper's TopologyTileInfo) */ int32_t m_triangleTwoIndex; bool m_processedFlag = false; }; SurfacePlaneIntersectionToContour(const SurfacePlaneIntersectionToContour&); SurfacePlaneIntersectionToContour& operator=(const SurfacePlaneIntersectionToContour&); void prepareVertices(); void prepareEdges(); void generateContours(std::vector& graphicsPrimitivesOut); GraphicsPrimitive* generateContourFromEdge(IntersectionEdge* edge); const SurfaceFile* m_surfaceFile; const Plane& m_plane; const CaretColorEnum::Enum m_caretColor; const float* m_vertexColoringRGBA; const float m_contourThicknessPercentOfViewportHeight; std::array m_solidRGBA; CaretPointer m_topologyHelper; std::vector> m_vertices; std::vector> m_intersectingEdges; /** index with a topo helper edge index to get its intersecting edge (-1) if edge does not intersect */ std::vector m_topoHelperEdgeToIntersectingEdgeIndices; int32_t m_numberOfIntersectingEdges = 0; bool m_debugFlag = false; // ADD_NEW_MEMBERS_HERE }; #ifdef __SURFACE_PLANE_INTERSECTION_TO_CONTOUR_DECLARE__ // #endif // __SURFACE_PLANE_INTERSECTION_TO_CONTOUR_DECLARE__ } // namespace #endif //__SURFACE_PLANE_INTERSECTION_TO_CONTOUR_H__ connectome-workbench-1.4.2/src/Files/SurfaceProjectedItem.cxx000066400000000000000000000444321360521144700242660ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SURFACE_PROJECTED_ITEM_DEFINE__ #include "SurfaceProjectedItem.h" #undef __SURFACE_PROJECTED_ITEM_DEFINE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "DataFileException.h" #include "SurfaceProjectionBarycentric.h" #include "SurfaceProjectionVanEssen.h" #include "XmlWriter.h" #include using namespace caret; /** * \class caret::SurfaceProjectedItem * \brief Maintains position of an item projected to a surface. * * Multiple projections are supported and may be valid at one time. * (1) Barycentric projects to a surface triangle. (2) VanEssen * projects to an edget of a triangle. (3) Stereotaxic is a * three-dimensional coordinate. A volume coordinate is also * available. */ /** * Constructor. * */ SurfaceProjectedItem::SurfaceProjectedItem() : CaretObjectTracksModification() { this->initializeMembersSurfaceProjectedItem(); } /** * Destructor */ SurfaceProjectedItem::~SurfaceProjectedItem() { delete this->barycentricProjection; delete this->vanEssenProjection; } /** * Copy Constructor * @param Object that is copied. */ SurfaceProjectedItem::SurfaceProjectedItem(const SurfaceProjectedItem& o) : CaretObjectTracksModification(o) { this->initializeMembersSurfaceProjectedItem(); this->copyHelper(o); } /** * Assignment operator. */ SurfaceProjectedItem& SurfaceProjectedItem::operator=(const SurfaceProjectedItem& o) { if (this != &o) { CaretObject::operator=(o); this->copyHelper(o); }; return *this; } bool SurfaceProjectedItem::operator==(const SurfaceProjectedItem& rhs) const { if (structure != rhs.structure) return false; if (stereotaxicXYZValid != rhs.stereotaxicXYZValid) return false; if (volumeXYZValid != rhs.volumeXYZValid) return false; if (stereotaxicXYZValid) { for (int i = 0; i < 3; ++i) { if (stereotaxicXYZ[i] != rhs.stereotaxicXYZ[i]) return false; } } if (volumeXYZValid) { for (int i = 0; i < 3; ++i) { if (volumeXYZ[i] != rhs.volumeXYZ[i]) return false; } } if (*barycentricProjection != *rhs.barycentricProjection) return false; return (*vanEssenProjection == *rhs.vanEssenProjection); } /** * Helps with copy constructor and assignment operator. */ void SurfaceProjectedItem::copyHelper(const SurfaceProjectedItem& spi) { this->setStereotaxicXYZ(spi.getStereotaxicXYZ()); this->stereotaxicXYZValid = spi.stereotaxicXYZValid; this->setVolumeXYZ(spi.getVolumeXYZ()); this->volumeXYZValid = spi.volumeXYZValid; this->structure = spi.structure; *this->barycentricProjection = *spi.barycentricProjection; *this->vanEssenProjection = *spi.vanEssenProjection; } /** * Reset to default values as if no projection of any type. */ void SurfaceProjectedItem::reset() { this->stereotaxicXYZ[0] = 0.0; this->stereotaxicXYZ[1] = 0.0; this->stereotaxicXYZ[2] = 0.0; this->stereotaxicXYZValid = false; this->volumeXYZ[0] = 0.0; this->volumeXYZ[1] = 0.0; this->volumeXYZ[2] = 0.0; this->volumeXYZValid = false; this->structure = StructureEnum::INVALID; this->barycentricProjection->reset(); this->vanEssenProjection->reset(); } void SurfaceProjectedItem::initializeMembersSurfaceProjectedItem() { this->barycentricProjection = new SurfaceProjectionBarycentric(); this->vanEssenProjection = new SurfaceProjectionVanEssen(); this->reset(); } /** * Unproject the item to the stereotaxic XYZ coordinates. * * @param sf - Surface on which unprojection takes place. * @param pasteOntoSurfaceFlag - place item directly on surface. * */ void SurfaceProjectedItem::unprojectToStereotaxicXYZ(const SurfaceFile& sf, const bool isUnprojectedOntoSurface) { float xyz[3]; if (getProjectedPosition(sf, xyz, isUnprojectedOntoSurface)) { this->setStereotaxicXYZ(xyz); } } /** * Unproject the item to the volume XYZ coordinates. * * @param sf - Surface on which unprojection takes place. * @param pasteOntoSurfaceFlag - place item directly on surface. * */ void SurfaceProjectedItem::unprojectToVolumeXYZ(const SurfaceFile& sf, const bool isUnprojectedOntoSurface) { float xyz[3]; if (getProjectedPosition(sf, xyz, isUnprojectedOntoSurface)) { this->setVolumeXYZ(xyz); } } /** * Get the projected position of this item. * The first valid of this positions is used: (1) Barycentric, * (2) VanEssen, (3) Stereotaxic. * * @param surfaceFile * Surface File for positioning. * @param xyzOut * Output containing the projected position. * @param pasteOntoSurfaceFlag * Place directly on the surface. * @return true if the position is valid, else false. * */ bool SurfaceProjectedItem::getProjectedPosition(const SurfaceFile& surfaceFile, float xyzOut[3], const bool isUnprojectedOntoSurface) const { bool valid = false; if (valid == false) { if (this->barycentricProjection->isValid()) { valid = this->barycentricProjection->unprojectToSurface(surfaceFile, xyzOut, 0.0, isUnprojectedOntoSurface); } } if (valid == false) { if (this->vanEssenProjection->isValid()) { valid = this->vanEssenProjection->unprojectToSurface(surfaceFile, xyzOut, 0.0, isUnprojectedOntoSurface); } } if (valid == false) { if (this->stereotaxicXYZValid) { this->getStereotaxicXYZ(xyzOut); valid = true; } } return valid; } /** * Get the projected position of this item. The item is unprojected * to the surface and then it is placed above (below if negative) * the surface by the amount specified by 'distanceAboveSurface'. * * The first valid of this positions is used: (1) Barycentric, * (2) VanEssen, (3) Stereotaxic. * * @param surfaceFile * Surface File for positioning. * @param topologyHelper * The topology helper. This value * @param xyzOut * Output containing the projected position. * @param distanceAboveSurface * Unproje * @return true if the position is valid, else false. * */ bool SurfaceProjectedItem::getProjectedPositionAboveSurface(const SurfaceFile& surfaceFile, const TopologyHelper* topologyHelper, float xyzOut[3], const float distanceAboveSurface) const { bool valid = false; if (valid == false) { if (this->barycentricProjection->isValid()) { valid = this->barycentricProjection->unprojectToSurface(surfaceFile, topologyHelper, xyzOut, distanceAboveSurface, true); } } if (valid == false) { if (this->vanEssenProjection->isValid()) { valid = this->vanEssenProjection->unprojectToSurface(surfaceFile, topologyHelper, xyzOut, distanceAboveSurface, true); } } if (valid == false) { if (this->stereotaxicXYZValid) { this->getStereotaxicXYZ(xyzOut); valid = true; } } return valid; } /** * Get the stereotaxic position. * * @return Stereotaxic position. * */ const float* SurfaceProjectedItem::getStereotaxicXYZ() const { return this->stereotaxicXYZ; } /** * Get the Stereotaxic XYZ position. * @param stereotaxicXYZOut Position placed into here. * */ void SurfaceProjectedItem::getStereotaxicXYZ(float stereotaxicXYZOut[3]) const { stereotaxicXYZOut[0] = this->stereotaxicXYZ[0]; stereotaxicXYZOut[1] = this->stereotaxicXYZ[1]; stereotaxicXYZOut[2] = this->stereotaxicXYZ[2]; } /** * Get the validity of the Stereotaxic XYZ coordinate. * @return Validity of Stereotaxic XYZ coordinate. * */ bool SurfaceProjectedItem::isStereotaxicXYZValid() const { return this->stereotaxicXYZValid; } /** * Set the items stereotaxic coordinates and sets the validity * of the stereotaxic coordinates to true. * * @param stereotaxicXYZ New position. * */ void SurfaceProjectedItem::setStereotaxicXYZ(const float stereotaxicXYZ[3]) { if (this->stereotaxicXYZValid) { } this->stereotaxicXYZ[0] = stereotaxicXYZ[0]; this->stereotaxicXYZ[1] = stereotaxicXYZ[1]; this->stereotaxicXYZ[2] = stereotaxicXYZ[2]; this->stereotaxicXYZValid = true; if (this->volumeXYZValid == false) { this->setVolumeXYZ(stereotaxicXYZ); } this->setModified(); } /** * Get the value of volumeXYZ * * @return the value of volumeXYZ * */ const float* SurfaceProjectedItem::getVolumeXYZ() const { /* * If not set, return stereotaxic coordinate */ if ((volumeXYZ[0] == 0.0) && (volumeXYZ[1] == 0.0) && (volumeXYZ[2] == 0.0)) { const float* stereoXYZ = getStereotaxicXYZ(); return stereoXYZ; } return this->volumeXYZ; } /** * Get the volume XYZ coordinates. * @param xyzOut Volume XYZ coordinates. * */ void SurfaceProjectedItem::getVolumeXYZ(float xyzOut[3]) const { /* * If not set, return stereotaxic coordinate */ if ((volumeXYZ[0] == 0.0) && (volumeXYZ[1] == 0.0) && (volumeXYZ[2] == 0.0)) { getStereotaxicXYZ(xyzOut); return; } xyzOut[0] = this->volumeXYZ[0]; xyzOut[1] = this->volumeXYZ[1]; xyzOut[2] = this->volumeXYZ[2]; } /** * Get the validity of the volume XYZ coordinate. * @return Validity of volume XYZ coordinate. * */ bool SurfaceProjectedItem::isVolumeXYZValid() const { return this->volumeXYZValid; } /** * Set the item's volume coordinates and sets the validity * of the volume coordinates to true. * * @param volumeXYZ new value of volumeXYZ * */ void SurfaceProjectedItem::setVolumeXYZ(const float volumeXYZ[3]) { this->volumeXYZ[0] = volumeXYZ[0]; this->volumeXYZ[1] = volumeXYZ[1]; this->volumeXYZ[2] = volumeXYZ[2]; this->volumeXYZValid = true; this->setModified(); } /** * Get the structure of this projected item. * @return The structure. * */ StructureEnum::Enum SurfaceProjectedItem::getStructure() const { return this->structure; } /** * Set the structure of this projected item. * @param s - new structure. * */ void SurfaceProjectedItem::setStructure(const StructureEnum::Enum structure) { this->structure = structure; this->setModified(); } /** * @return the barycentric projection */ SurfaceProjectionBarycentric* SurfaceProjectedItem::getBarycentricProjection() { return this->barycentricProjection; } /** * @return the barycentric projection */ const SurfaceProjectionBarycentric* SurfaceProjectedItem::getBarycentricProjection() const { return this->barycentricProjection; } /** * @return the Van Essen projection */ SurfaceProjectionVanEssen* SurfaceProjectedItem::getVanEssenProjection() { return this->vanEssenProjection; } /** * @return the Van Essen projection */ const SurfaceProjectionVanEssen* SurfaceProjectedItem::getVanEssenProjection() const { return this->vanEssenProjection; } /** * Write the border to the XML Writer. * @param xmlWriter * Writer for XML output. */ void SurfaceProjectedItem::writeAsXML(XmlWriter& xmlWriter) { xmlWriter.writeStartElement(XML_TAG_SURFACE_PROJECTED_ITEM); xmlWriter.writeElementCharacters(XML_TAG_STRUCTURE, StructureEnum::toName(this->structure)); if (this->stereotaxicXYZValid) { xmlWriter.writeElementCharacters(XML_TAG_STEREOTAXIC_XYZ, this->stereotaxicXYZ, 3); } if (this->volumeXYZValid) { xmlWriter.writeElementCharacters(XML_TAG_VOLUME_XYZ, this->volumeXYZ, 3); } this->barycentricProjection->writeAsXML(xmlWriter); this->vanEssenProjection->writeAsXML(xmlWriter); xmlWriter.writeEndElement(); } void SurfaceProjectedItem::readBorderFileXML1(QXmlStreamReader& xml) { reset(); CaretAssert(xml.isStartElement() && xml.name() == "SurfaceProjectedItem"); bool haveStructure = false, haveVanEssen = false, haveStereo = false, haveVolume = false;//track the barycentric projection for being specified more than once by its valid flag for (xml.readNext(); !xml.atEnd() && !xml.isEndElement(); xml.readNext()) { switch (xml.tokenType()) { case QXmlStreamReader::StartElement: { QStringRef name = xml.name(); if (name == "Structure") { if (haveStructure) throw DataFileException("multiple Structure elements in one SurfaceProjectedItem element"); QString structString = xml.readElementText();//sets error on unexpected child element if (xml.hasError()) throw DataFileException("XML parsing error in Structure: " + xml.errorString()); bool ok = false; structure = StructureEnum::fromName(structString, &ok); if (!ok) CaretLogWarning("unrecognized string in Structure: " + structString);//HACK: this is what the SAX reader did, don't look at me haveStructure = true; } else if (name == "ProjectionBarycentric") { if (barycentricProjection->isValid()) throw DataFileException("multiple ProjectionBarycentric elements in one SurfaceProjectedItem element"); barycentricProjection->readBorderFileXML1(xml); } else if (name == "VanEssenProjection") { if (haveVanEssen) throw DataFileException("multiple VanEssenProjection elements in one SurfaceProjectedItem element"); CaretLogFine("found Van Essen projection in border file, ignoring"); xml.readElementText(QXmlStreamReader::SkipChildElements);//HACK: border files never use this projection type, so don't try to parse it if (xml.hasError()) throw DataFileException("XML parsing error in VanEssenProjection: " + xml.errorString()); haveVanEssen = true; } else if (name == "StereotaxicXYZ") { if (haveStereo) throw DataFileException("multiple StereotaxicXYZ elements in one SurfaceProjectedItem element"); CaretLogFine("found stereotaxic coordinates in border file, ignoring"); xml.readElementText(QXmlStreamReader::SkipChildElements);//HACK: ditto if (xml.hasError()) throw DataFileException("XML parsing error in StereotaxicXYZ: " + xml.errorString()); haveStereo = true; } else if (name == "VolumeXYZ") { if (haveVolume) throw DataFileException("multiple VolumeXYZ elements in one SurfaceProjectedItem element"); CaretLogFine("found volume coordinates in border file, ignoring"); xml.readElementText(QXmlStreamReader::SkipChildElements);//HACK: ditto if (xml.hasError()) throw DataFileException("XML parsing error in VolumeXYZ: " + xml.errorString()); haveVolume = true; } else { throw DataFileException("unexpected element in SurfaceProjectedItem: " + name.toString()); } break; } default: break; } } if (xml.hasError()) throw DataFileException("XML parsing error in SurfaceProjectedItem: " + xml.errorString()); CaretAssert(xml.isEndElement() && xml.name() == "SurfaceProjectedItem"); if (!haveStructure) throw DataFileException("SurfaceProjectedItem is missing Structure element"); } /** * Set the status to unmodified. */ void SurfaceProjectedItem::clearModified() { CaretObjectTracksModification::clearModified(); this->barycentricProjection->clearModified(); this->vanEssenProjection->clearModified(); } /** * Is the object modified? * @return true if modified, else false. */ bool SurfaceProjectedItem::isModified() const { if (CaretObjectTracksModification::isModified()) { return true; } if (this->barycentricProjection->isModified()) { return true; } if (this->vanEssenProjection->isModified()) { return true; } return false; } /** * @return True if a projection (barycentric, vanessen) * is valid. Otherwise, false. */ bool SurfaceProjectedItem::hasValidProjection() const { if (barycentricProjection->isValid()) { return true; } if (vanEssenProjection->isValid()) { return true; } return false; } connectome-workbench-1.4.2/src/Files/SurfaceProjectedItem.h000066400000000000000000000121541360521144700237070ustar00rootroot00000000000000#ifndef __SURFACE_PROJECTED_ITEM_H__ #define __SURFACE_PROJECTED_ITEM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObjectTracksModification.h" #include "StructureEnum.h" #include "XmlException.h" class QXmlStreamReader; namespace caret { class SurfaceFile; class SurfaceProjectionBarycentric; class SurfaceProjectionVanEssen; class TopologyHelper; class XmlWriter; class SurfaceProjectedItem : public CaretObjectTracksModification { public: SurfaceProjectedItem(); SurfaceProjectedItem(const SurfaceProjectedItem& o); SurfaceProjectedItem& operator=(const SurfaceProjectedItem& o); bool operator==(const SurfaceProjectedItem& rhs) const; bool operator!=(const SurfaceProjectedItem& rhs) const { return !(*this == rhs); } virtual ~SurfaceProjectedItem(); private: void copyHelper(const SurfaceProjectedItem& o); void initializeMembersSurfaceProjectedItem(); public: void unprojectToStereotaxicXYZ(const SurfaceFile& sf, const bool isUnprojectedOntoSurface); void unprojectToVolumeXYZ(const SurfaceFile& sf, const bool isUnprojectedOntoSurface); bool getProjectedPosition(const SurfaceFile& sf, float xyzOut[3], const bool isUnprojectedOntoSurface) const; bool getProjectedPositionAboveSurface(const SurfaceFile& sf, const TopologyHelper* th, float xyzOut[3], const float distanceAboveSurface) const; const float* getStereotaxicXYZ() const; void getStereotaxicXYZ(float stereotaxicXYZOut[3]) const; bool isStereotaxicXYZValid() const; void setStereotaxicXYZ(const float stereotaxicXYZ[3]); const float* getVolumeXYZ() const; void getVolumeXYZ(float xyzOut[3]) const; bool isVolumeXYZValid() const; void setVolumeXYZ(const float volumeXYZ[3]); StructureEnum::Enum getStructure() const; void setStructure(const StructureEnum::Enum structure); const SurfaceProjectionBarycentric* getBarycentricProjection() const; SurfaceProjectionBarycentric* getBarycentricProjection(); const SurfaceProjectionVanEssen* getVanEssenProjection() const; SurfaceProjectionVanEssen* getVanEssenProjection(); bool hasValidProjection() const; void reset(); void writeAsXML(XmlWriter& xmlWriter); void readBorderFileXML1(QXmlStreamReader& xml); virtual void clearModified(); virtual bool isModified() const; static AString XML_TAG_SURFACE_PROJECTED_ITEM; static AString XML_TAG_STEREOTAXIC_XYZ; static AString XML_TAG_VOLUME_XYZ; static AString XML_TAG_STRUCTURE; protected: /** stereotaxic position of projected item. */ float stereotaxicXYZ[3]; /** stereotaxic position of projected item valid */ bool stereotaxicXYZValid; /** position in volume */ float volumeXYZ[3]; /** position in volume valid */ bool volumeXYZValid; /** Structure to which projected. */ StructureEnum::Enum structure; /** The barycentric projection */ SurfaceProjectionBarycentric* barycentricProjection; /** The Van Essen projection */ SurfaceProjectionVanEssen* vanEssenProjection; }; #ifdef __SURFACE_PROJECTED_ITEM_DEFINE__ AString SurfaceProjectedItem::XML_TAG_SURFACE_PROJECTED_ITEM = "SurfaceProjectedItem"; AString SurfaceProjectedItem::XML_TAG_STEREOTAXIC_XYZ = "StereotaxicXYZ"; AString SurfaceProjectedItem::XML_TAG_VOLUME_XYZ = "VolumeXYZ"; AString SurfaceProjectedItem::XML_TAG_STRUCTURE = "Structure"; #endif // __SURFACE_PROJECTED_ITEM_DEFINE__ } // namespace #endif // __SURFACE_PROJECTED_ITEM_H__ connectome-workbench-1.4.2/src/Files/SurfaceProjectedItemSaxReader.cxx000066400000000000000000000334151360521144700260640ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretLogger.h" #include "SurfaceProjectedItem.h" #include "SurfaceProjectedItemSaxReader.h" #include "SurfaceProjectionBarycentric.h" #include "SurfaceProjectionVanEssen.h" #include "XmlAttributes.h" #include "XmlException.h" #include "XmlUtilities.h" using namespace caret; /** * constructor. */ SurfaceProjectedItemSaxReader::SurfaceProjectedItemSaxReader(SurfaceProjectedItem* surfaceProjectedItem) { this->state = STATE_NONE; this->stateStack.push(this->state); this->elementText = ""; this->surfaceProjectedItem = surfaceProjectedItem; } /** * destructor. */ SurfaceProjectedItemSaxReader::~SurfaceProjectedItemSaxReader() { } /** * start an element. */ void SurfaceProjectedItemSaxReader::startElement(const AString& /* namespaceURI */, const AString& /* localName */, const AString& qName, const XmlAttributes& /*attributes*/) { const STATE previousState = this->state; switch (state) { case STATE_NONE: if (qName == SurfaceProjectedItem::XML_TAG_SURFACE_PROJECTED_ITEM) { this->state = STATE_SURFACE_PROJECTED_ITEM; } else { AString txt = XmlUtilities::createInvalidRootElementMessage(SurfaceProjectedItem::XML_TAG_SURFACE_PROJECTED_ITEM, qName); XmlSaxParserException e(txt); CaretLogThrowing(e); throw e; } break; case STATE_SURFACE_PROJECTED_ITEM: if (qName == SurfaceProjectionBarycentric::XML_TAG_PROJECTION_BARYCENTRIC) { state = STATE_BARYCENTRIC; } else if (qName == SurfaceProjectionVanEssen::XML_TAG_PROJECTION_VAN_ESSEN) { state = STATE_VAN_ESSEN; } else if ((qName == SurfaceProjectedItem::XML_TAG_STEREOTAXIC_XYZ) || (qName == SurfaceProjectedItem::XML_TAG_STRUCTURE) || (qName == SurfaceProjectedItem::XML_TAG_VOLUME_XYZ)) { // nothing } else { AString txt = XmlUtilities::createInvalidChildElementMessage(SurfaceProjectedItem::XML_TAG_SURFACE_PROJECTED_ITEM, qName); XmlSaxParserException e(txt); CaretLogThrowing(e); throw e; } break; case STATE_BARYCENTRIC: if ((qName == SurfaceProjectionBarycentric::XML_TAG_SIGNED_DISTANCE_ABOVE_SURFACE) || (qName == SurfaceProjectionBarycentric::XML_TAG_TRIANGLE_AREAS) || (qName == SurfaceProjectionBarycentric::XML_TAG_TRIANGLE_NODES)) { // nothing } else { AString txt = XmlUtilities::createInvalidChildElementMessage(SurfaceProjectionBarycentric::XML_TAG_PROJECTION_BARYCENTRIC, qName); XmlSaxParserException e(txt); CaretLogThrowing(e); throw e; } break; case STATE_VAN_ESSEN: if ((qName == SurfaceProjectionVanEssen::XML_TAG_DR) || (qName == SurfaceProjectionVanEssen::XML_TAG_FRAC_RI) || (qName == SurfaceProjectionVanEssen::XML_TAG_FRAC_RJ) || (qName == SurfaceProjectionVanEssen::XML_TAG_PHI_R) || (qName == SurfaceProjectionVanEssen::XML_TAG_POS_ANATOMICAL) || (qName == SurfaceProjectionVanEssen::XML_TAG_PROJECTION_VAN_ESSEN) || (qName == SurfaceProjectionVanEssen::XML_TAG_THETA_R) || (qName == SurfaceProjectionVanEssen::XML_TAG_TRI_ANATOMICAL) || (qName == SurfaceProjectionVanEssen::XML_TAG_TRI_VERTICES) || (qName == SurfaceProjectionVanEssen::XML_TAG_VERTEX) || (qName == SurfaceProjectionVanEssen::XML_TAG_VERTEX_ANATOMICAL)) { // nothing } else { AString txt = XmlUtilities::createInvalidChildElementMessage(SurfaceProjectionVanEssen::XML_TAG_PROJECTION_VAN_ESSEN, qName); XmlSaxParserException e(txt); CaretLogThrowing(e); throw e; } break; } // // Save previous state // this->stateStack.push(previousState); this->elementText = ""; } /** * end an element. */ void SurfaceProjectedItemSaxReader::endElement(const AString& /* namspaceURI */, const AString& /* localName */, const AString& qName) { const AString text = this->elementText.trimmed(); switch (state) { case STATE_NONE: break; case STATE_SURFACE_PROJECTED_ITEM: if (qName == SurfaceProjectedItem::XML_TAG_STEREOTAXIC_XYZ) { std::vector xyz; XmlUtilities::getArrayOfNumbersFromText(qName, text, 3, xyz); this->surfaceProjectedItem->setStereotaxicXYZ(xyz.data()); } else if (qName == SurfaceProjectedItem::XML_TAG_STRUCTURE) { bool isValid = false; this->surfaceProjectedItem->setStructure(StructureEnum::fromName(text, &isValid)); if (isValid == false) { CaretLogWarning("Invalid structure name: " + text); throw XmlSaxParserException("Invalid structure name: " + text); } } else if (qName == SurfaceProjectedItem::XML_TAG_VOLUME_XYZ) { std::vector xyz; XmlUtilities::getArrayOfNumbersFromText(qName, text, 3, xyz); this->surfaceProjectedItem->setVolumeXYZ(xyz.data()); } break; case STATE_BARYCENTRIC: { SurfaceProjectionBarycentric* bp = this->surfaceProjectedItem->getBarycentricProjection(); if (qName == SurfaceProjectionBarycentric::XML_TAG_SIGNED_DISTANCE_ABOVE_SURFACE) { bp->setSignedDistanceAboveSurface(text.toFloat()); } else if (qName == SurfaceProjectionBarycentric::XML_TAG_TRIANGLE_AREAS) { std::vector areas; XmlUtilities::getArrayOfNumbersFromText(qName, text, 3, areas); bp->setTriangleAreas(areas.data()); } else if (qName == SurfaceProjectionBarycentric::XML_TAG_TRIANGLE_NODES) { std::vector nodes; XmlUtilities::getArrayOfNumbersFromText(qName, text, 3, nodes); bp->setTriangleNodes(nodes.data()); } bp->setValid(true); } break; case STATE_VAN_ESSEN: { SurfaceProjectionVanEssen* ve = this->surfaceProjectedItem->getVanEssenProjection(); if (qName == SurfaceProjectionVanEssen::XML_TAG_DR) { ve->setDR(text.toFloat()); } else if (qName == SurfaceProjectionVanEssen::XML_TAG_FRAC_RI) { ve->setFracRI(text.toFloat()); } else if (qName == SurfaceProjectionVanEssen::XML_TAG_FRAC_RJ) { ve->setFracRJ(text.toFloat()); } else if (qName == SurfaceProjectionVanEssen::XML_TAG_PHI_R) { ve->setPhiR(text.toFloat()); } else if (qName == SurfaceProjectionVanEssen::XML_TAG_POS_ANATOMICAL) { std::vector xyz; XmlUtilities::getArrayOfNumbersFromText(qName, text, 3, xyz); ve->setPosAnatomical(xyz.data()); } else if (qName == SurfaceProjectionVanEssen::XML_TAG_THETA_R) { ve->setThetaR(text.toFloat()); } else if (qName == SurfaceProjectionVanEssen::XML_TAG_TRI_ANATOMICAL) { std::vector data; XmlUtilities::getArrayOfNumbersFromText(qName, text, 18, data); float ta[2][3][3]; int32_t ctr = 0; for (int32_t i = 0; i < 2; i++) { for (int32_t j = 0; j < 3; j++) { for (int32_t k = 0; k < 3; k++) { ta[i][j][k] = data[ctr]; ctr++; } } } ve->setTriAnatomical(ta); } else if (qName == SurfaceProjectionVanEssen::XML_TAG_TRI_VERTICES) { std::vector data; XmlUtilities::getArrayOfNumbersFromText(qName, text, 6, data); int32_t tv[2][3]; int32_t ctr = 0; for (int32_t i = 0; i < 2; i++) { for (int32_t j = 0; j < 3; j++) { tv[i][j] = data[ctr]; ctr++; } } ve->setTriVertices(tv); } else if (qName == SurfaceProjectionVanEssen::XML_TAG_VERTEX) { std::vector data; XmlUtilities::getArrayOfNumbersFromText(qName, text, 2, data); int32_t tv[2]; int32_t ctr = 0; for (int32_t i = 0; i < 2; i++) { tv[i] = data[ctr]; ctr++; } ve->setVertex(tv); } else if (qName == SurfaceProjectionVanEssen::XML_TAG_VERTEX_ANATOMICAL) { std::vector data; XmlUtilities::getArrayOfNumbersFromText(qName, text, 6, data); float va[2][3]; int32_t ctr = 0; for (int32_t i = 0; i < 2; i++) { for (int32_t j = 0; j < 3; j++) { va[i][j] = data[ctr]; ctr++; } } ve->setVertexAnatomical(va); } ve->setValid(true); } break; } // // Clear out for new elements // this->elementText = ""; // // Go to previous state // if (this->stateStack.empty()) { throw XmlSaxParserException("State stack is empty while reading XML MetaData."); } this->state = this->stateStack.top(); this->stateStack.pop(); } /** * get characters in an element. */ void SurfaceProjectedItemSaxReader::characters(const char* ch) { this->elementText += ch; } /** * a fatal error occurs. */ void SurfaceProjectedItemSaxReader::fatalError(const XmlSaxParserException& e) { // // Stop parsing // CaretLogSevere("XML Parser Fatal Error: " + e.whatString()); throw e; } // a warning occurs void SurfaceProjectedItemSaxReader::warning(const XmlSaxParserException& e) { CaretLogWarning("XML Parser Warning: " + e.whatString()); } // an error occurs void SurfaceProjectedItemSaxReader::error(const XmlSaxParserException& e) { throw e; } void SurfaceProjectedItemSaxReader::startDocument() { } void SurfaceProjectedItemSaxReader::endDocument() { } connectome-workbench-1.4.2/src/Files/SurfaceProjectedItemSaxReader.h000066400000000000000000000064571360521144700255170ustar00rootroot00000000000000 #ifndef __SURFACE_PROJECTED_ITEM_SAX_READER_H__ #define __SURFACE_PROJECTED_ITEM_SAX_READER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "XmlSaxParserException.h" #include "XmlSaxParserHandlerInterface.h" namespace caret { class SurfaceProjectedItem; class XmlAttributes; /** * class for reading SurfaceProjectedItem with a SAX Parser */ class SurfaceProjectedItemSaxReader : public CaretObject, public XmlSaxParserHandlerInterface { public: SurfaceProjectedItemSaxReader(SurfaceProjectedItem* surfaceProjectedItem); virtual ~SurfaceProjectedItemSaxReader(); void startElement(const AString& namespaceURI, const AString& localName, const AString& qName, const XmlAttributes& attributes); void endElement(const AString& namspaceURI, const AString& localName, const AString& qName); void characters(const char* ch); void fatalError(const XmlSaxParserException& e); void warning(const XmlSaxParserException& e); void error(const XmlSaxParserException& e); void startDocument(); void endDocument(); private: SurfaceProjectedItemSaxReader(const SurfaceProjectedItemSaxReader&); SurfaceProjectedItemSaxReader& operator=(const SurfaceProjectedItemSaxReader&); protected: /// file reading states enum STATE { /// no state STATE_NONE, /// processing SurfaceProjectedItem tags STATE_SURFACE_PROJECTED_ITEM, /// processing Barycentric tags STATE_BARYCENTRIC, /// processing Van Essen tags STATE_VAN_ESSEN }; /// file reading state STATE state; /// the state stack used when reading a file std::stack stateStack; /// the error message AString errorMessage; /// meta data name AString metaDataName; /// meta data value AString metaDataValue; /// element text AString elementText; /// GIFTI meta data being read SurfaceProjectedItem* surfaceProjectedItem; }; } // namespace #endif // __SURFACE_PROJECTED_ITEM_SAX_READER_H__ connectome-workbench-1.4.2/src/Files/SurfaceProjection.cxx000066400000000000000000000054571360521144700236500ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SURFACE_PROJECTION_DECLARE__ #include "SurfaceProjection.h" #undef __SURFACE_PROJECTION_DECLARE__ using namespace caret; /** * \class caret::SurfaceProjection * \brief Abstract class for Surface Projections. */ /** * Constructor. */ SurfaceProjection::SurfaceProjection() : CaretObjectTracksModification() { this->projectionSurfaceNumberOfNodes = 0; } /** * Destructor. */ SurfaceProjection::~SurfaceProjection() { } /** * Copy constructor. * @param obj * Object that is copied. */ SurfaceProjection::SurfaceProjection(const SurfaceProjection& obj) : CaretObjectTracksModification(obj) { this->copyHelperSurfaceProjection(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ SurfaceProjection& SurfaceProjection::operator=(const SurfaceProjection& obj) { if (this != &obj) { CaretObjectTracksModification::operator=(obj); this->copyHelperSurfaceProjection(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void SurfaceProjection::copyHelperSurfaceProjection(const SurfaceProjection& obj) { this->projectionSurfaceNumberOfNodes = obj.projectionSurfaceNumberOfNodes; } /** * @return The number of nodes in the surface to which this projection is made. */ int32_t SurfaceProjection::getProjectionSurfaceNumberOfNodes() const { return this->projectionSurfaceNumberOfNodes; } /** * Set the number of nodes in the surface to which this projection is made. * @param projectionSurfaceNumberOfNodes * Number of nodes in the surface. */ void SurfaceProjection::setProjectionSurfaceNumberOfNodes(const int projectionSurfaceNumberOfNodes) { this->projectionSurfaceNumberOfNodes = projectionSurfaceNumberOfNodes; } /** * @return a string describing the projection */ AString SurfaceProjection::toString() const { return CaretObjectTracksModification::toString(); } connectome-workbench-1.4.2/src/Files/SurfaceProjection.h000066400000000000000000000117421360521144700232670ustar00rootroot00000000000000#ifndef __SURFACE_PROJECTION__H_ #define __SURFACE_PROJECTION__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObjectTracksModification.h" #include "XmlException.h" namespace caret { class SurfaceFile; class TopologyHelper; class XmlWriter; class SurfaceProjection : public CaretObjectTracksModification { public: SurfaceProjection(); virtual ~SurfaceProjection(); SurfaceProjection(const SurfaceProjection& obj); SurfaceProjection& operator=(const SurfaceProjection& obj); /** * @return Is the projection valid? */ virtual bool isValid() const = 0; /** * Set the validity of the projection. * @param valid * New validity status. */ virtual void setValid(const bool valid) = 0; /** * Reset the surface projection to its initial state. */ virtual void reset() = 0; /** * Unproject to the surface using 'this' projection. * * @param surfaceFile * Surface file used for unprojecting. * @param xyzOut * Output containing coordinate created by unprojecting. * @param offsetFromSurface * If 'unprojectWithOffsetFromSurface' is true, unprojected * position will be this distance above (negative=below) * the surface. * @param unprojectWithOffsetFromSurface * If true, ouput coordinate will be offset 'offsetFromSurface' * distance from the surface. * @return * True if unprojection is successful, else false. */ virtual bool unprojectToSurface(const SurfaceFile& surfaceFile, float xyzOut[3], const float offsetFromSurface, const bool unprojectWithOffsetFromSurface) const = 0; /** * Unproject to the surface using 'this' projection. * * @param surfaceFile * Surface file used for unprojecting. * @param topologyHelperIn * Topology helper. If NULL, topology helper from surfaceFile * will be used but frequent calls to get the topology helper * may be slow. * @param xyzOut * Output containing coordinate created by unprojecting. * @param offsetFromSurface * If 'unprojectWithOffsetFromSurface' is true, unprojected * position will be this distance above (negative=below) * the surface. * @param unprojectWithOffsetFromSurface * If true, ouput coordinate will be offset 'offsetFromSurface' * distance from the surface. * @return * True if unprojection is successful, else false. */ virtual bool unprojectToSurface(const SurfaceFile& surfaceFile, const TopologyHelper* topologyHelperIn, float xyzOut[3], const float offsetFromSurface, const bool unprojectWithOffsetFromSurface) const = 0; int32_t getProjectionSurfaceNumberOfNodes() const; void setProjectionSurfaceNumberOfNodes(const int surfaceNumberOfNodes); /** * Write the projection to XML. * @param xmlWriter * The XML Writer. * @throw XmlException * If an error occurs. */ virtual void writeAsXML(XmlWriter& xmlWriter) = 0; /* @return a string describing the projection */ virtual AString toString() const; protected: /** Number of nodes in surface to which item is projected. */ int32_t projectionSurfaceNumberOfNodes; private: void copyHelperSurfaceProjection(const SurfaceProjection& obj); }; #ifdef __SURFACE_PROJECTION_DECLARE__ // #endif // __SURFACE_PROJECTION_DECLARE__ } // namespace #endif //__SURFACE_PROJECTION__H_ connectome-workbench-1.4.2/src/Files/SurfaceProjectionBarycentric.cxx000066400000000000000000000472131360521144700260320ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SURFACE_PROJECTION_BARYCENTRIC_DECLARE__ #include "SurfaceProjectionBarycentric.h" #undef __SURFACE_PROJECTION_BARYCENTRIC_DECLARE__ #include "CaretAssert.h" #include "DataFileException.h" #include "MathFunctions.h" #include "SurfaceFile.h" #include "TopologyHelper.h" #include "XmlWriter.h" #include #include using namespace caret; /** * \class caret::SurfaceProjectionBarycentric * \brief Maintains a barycentric projection. * */ /** * Constructor. */ SurfaceProjectionBarycentric::SurfaceProjectionBarycentric() : SurfaceProjection() { this->resetAllValues(); } /** * Destructor. */ SurfaceProjectionBarycentric::~SurfaceProjectionBarycentric() { } /** * Copy constructor. * @param obj * Object that is copied. */ SurfaceProjectionBarycentric::SurfaceProjectionBarycentric(const SurfaceProjectionBarycentric& obj) : SurfaceProjection(obj) { this->copyHelperSurfaceProjectionBarycentric(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ SurfaceProjectionBarycentric& SurfaceProjectionBarycentric::operator=(const SurfaceProjectionBarycentric& obj) { if (this != &obj) { SurfaceProjection::operator=(obj); this->copyHelperSurfaceProjectionBarycentric(obj); } return *this; } bool SurfaceProjectionBarycentric::operator==(const SurfaceProjectionBarycentric& rhs) { if (projectionValid != rhs.projectionValid) return false; if (projectionValid) { for (int i = 0; i < 3; ++i) { if (triangleAreas[i] != rhs.triangleAreas[i]) return false; if (triangleNodes[i] != rhs.triangleNodes[i]) return false; } if (m_degenerate != rhs.m_degenerate) return false; return (signedDistanceAboveSurface == rhs.signedDistanceAboveSurface); } return true; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void SurfaceProjectionBarycentric::copyHelperSurfaceProjectionBarycentric(const SurfaceProjectionBarycentric& obj) { this->setTriangleAreas(obj.getTriangleAreas()); this->setTriangleNodes(obj.getTriangleNodes()); this->signedDistanceAboveSurface = obj.signedDistanceAboveSurface; this->projectionValid = obj.projectionValid; this->m_degenerate = obj.m_degenerate; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString SurfaceProjectionBarycentric::toString() const { AString txt = SurfaceProjection::toString(); if (txt.isEmpty() == false) { txt += ", "; } txt += ("projectionValid=" + AString::fromBool(projectionValid) + ", triangleAreas=(" + AString::fromNumbers(this->triangleAreas, 3, ",") + "), triangleNodes=(" + AString::fromNumbers(this->triangleNodes, 3, ",") + "), signedDistanceAboveSurface=" + AString::number(this->signedDistanceAboveSurface)); return txt; } /** * @return The signed distance above the surface. */ float SurfaceProjectionBarycentric::getSignedDistanceAboveSurface() const { return this->signedDistanceAboveSurface; } /** * Set the signed distance above the surface. * * @param signedDistanceAboveSurface * New value. */ void SurfaceProjectionBarycentric::setSignedDistanceAboveSurface(const float signedDistanceAboveSurface) { this->signedDistanceAboveSurface = signedDistanceAboveSurface; this->setModified(); } /** * @return The triangle nodes (3 elements). */ const int32_t* SurfaceProjectionBarycentric::getTriangleNodes() const { return this->triangleNodes; } /** * Set the triangle nodes. * * @param triangleNodes * New values for nodes. */ void SurfaceProjectionBarycentric::setTriangleNodes(const int32_t triangleNodes[3]) { this->triangleNodes[0] = triangleNodes[0]; this->triangleNodes[1] = triangleNodes[1]; this->triangleNodes[2] = triangleNodes[2]; this->setModified(); } /** * @return The triangle areas (3 elements). */ const float* SurfaceProjectionBarycentric::getTriangleAreas() const { return this->triangleAreas; } int32_t SurfaceProjectionBarycentric::getNodeWithLargestWeight() const { int32_t ret = -1; float largestWeight = 0.0f;//there must be a positive weight for (int i = 0; i < 3; ++i) { if (triangleAreas[i] > largestWeight) { ret = triangleNodes[i]; largestWeight = triangleAreas[i]; } } return ret; } /** * Set the triangle areas. * * @param triangleAreas * New values for triangle areas. */ void SurfaceProjectionBarycentric::setTriangleAreas(const float triangleAreas[3]) { this->triangleAreas[0] = triangleAreas[0]; this->triangleAreas[1] = triangleAreas[1]; this->triangleAreas[2] = triangleAreas[2]; this->setModified(); } /** * Unproject to the surface using 'this' projection. * * @param surfaceFile * Surface file used for unprojecting. * @param topologyHelperIn * Topology helper. If NULL, topology helper from surfaceFile * will be used but frequent calls to get the topology helper * may be slow. * @param xyzOut * Output containing coordinate created by unprojecting. * @param offsetFromSurface * If 'unprojectWithOffsetFromSurface' is true, unprojected * position will be this distance above (negative=below) * the surface. * @param unprojectWithOffsetFromSurface * If true, ouput coordinate will be offset 'offsetFromSurface' * distance from the surface. * @return * True if unprojection was successful. */ bool SurfaceProjectionBarycentric::unprojectToSurface(const SurfaceFile& surfaceFile, const TopologyHelper* topologyHelperIn, float xyzOut[3], const float offsetFromSurface, const bool unprojectWithOffsetFromSurface) const { /* * Make sure projection surface number of nodes matches surface. */ if (this->projectionSurfaceNumberOfNodes > 0) { if (surfaceFile.getNumberOfNodes() != this->projectionSurfaceNumberOfNodes) { return false; } } const int32_t n1 = this->triangleNodes[0]; const int32_t n2 = this->triangleNodes[1]; const int32_t n3 = this->triangleNodes[2]; CaretAssert(n1 < surfaceFile.getNumberOfNodes()); CaretAssert(n2 < surfaceFile.getNumberOfNodes()); CaretAssert(n3 < surfaceFile.getNumberOfNodes()); /* * All nodes MUST have neighbors (connected) */ const TopologyHelper* topologyHelper = ((topologyHelperIn != NULL) ? topologyHelperIn : surfaceFile.getTopologyHelper().getPointer()); if ((topologyHelper->getNodeHasNeighbors(n1) == false) || (topologyHelper->getNodeHasNeighbors(n2) == false) || (topologyHelper->getNodeHasNeighbors(n3) == false)) { return false; } const float* c1 = surfaceFile.getCoordinate(n1); const float* c2 = surfaceFile.getCoordinate(n2); const float* c3 = surfaceFile.getCoordinate(n3); float barycentricXYZ[3]; float barycentricNormal[3]; /* * If all the nodes are the same (object projects to a single node, not triangle) */ if ((n1 == n2) && (n2 == n3)) { /* * Use node's normal vector and position */ barycentricXYZ[0] = c1[0]; barycentricXYZ[1] = c1[1]; barycentricXYZ[2] = c1[2]; const float* nodeNormal = surfaceFile.getNormalVector(n1); barycentricNormal[0] = nodeNormal[0]; barycentricNormal[1] = nodeNormal[1]; barycentricNormal[2] = nodeNormal[2]; } else { /* * Compute position using barycentric coordinates */ float t1[3]; float t2[3]; float t3[3]; for (int i = 0; i < 3; i++) { t1[i] = triangleAreas[0] * c1[i]; t2[i] = triangleAreas[1] * c2[i]; t3[i] = triangleAreas[2] * c3[i]; } float area = (triangleAreas[0] + triangleAreas[1] + triangleAreas[2]); if (area != 0) { for (int i = 0; i < 3; i++) { barycentricXYZ[i] = (t1[i] + t2[i] + t3[i]) / area; } } else { return false; } if (MathFunctions::normalVector(c1, c2, c3, barycentricNormal) == false) { return false; } } /* * Set output coordinate, possibly offsetting from surface. */ for (int j = 0; j < 3; j++) { if (unprojectWithOffsetFromSurface) { xyzOut[j] = (barycentricXYZ[j] + (barycentricNormal[j] * offsetFromSurface)); } else { xyzOut[j] = (barycentricXYZ[j] + (barycentricNormal[j] * signedDistanceAboveSurface)); } } return true; } /** * Unproject to the surface using 'this' projection. * * @param surfaceFile * Surface file used for unprojecting. * @param xyzOut * Output containing coordinate created by unprojecting. * @param offsetFromSurface * If 'unprojectWithOffsetFromSurface' is true, unprojected * position will be this distance above (negative=below) * the surface. * @param unprojectWithOffsetFromSurface * If true, ouput coordinate will be offset 'offsetFromSurface' * distance from the surface. * @return * True if unprojection was successful. */ bool SurfaceProjectionBarycentric::unprojectToSurface(const SurfaceFile& surfaceFile, float xyzOut[3], const float offsetFromSurface, const bool unprojectWithOffsetFromSurface) const { /* * Make sure projection surface number of nodes matches surface. */ if (this->projectionSurfaceNumberOfNodes > 0) { if (surfaceFile.getNumberOfNodes() != this->projectionSurfaceNumberOfNodes) { return false; } } const int32_t n1 = this->triangleNodes[0]; const int32_t n2 = this->triangleNodes[1]; const int32_t n3 = this->triangleNodes[2]; CaretAssert(n1 < surfaceFile.getNumberOfNodes()); CaretAssert(n2 < surfaceFile.getNumberOfNodes()); CaretAssert(n3 < surfaceFile.getNumberOfNodes()); /* * All nodes MUST have neighbors (connected) */ const TopologyHelper* topologyHelper = surfaceFile.getTopologyHelper().getPointer(); if ((topologyHelper->getNodeHasNeighbors(n1) == false) || (topologyHelper->getNodeHasNeighbors(n2) == false) || (topologyHelper->getNodeHasNeighbors(n3) == false)) { return false; } const float* c1 = surfaceFile.getCoordinate(n1); const float* c2 = surfaceFile.getCoordinate(n2); const float* c3 = surfaceFile.getCoordinate(n3); float barycentricXYZ[3]; float barycentricNormal[3]; /* * If all the nodes are the same (object projects to a single node, not triangle) */ if ((n1 == n2) && (n2 == n3)) { /* * Use node's normal vector and position */ barycentricXYZ[0] = c1[0]; barycentricXYZ[1] = c1[1]; barycentricXYZ[2] = c1[2]; const float* nodeNormal = surfaceFile.getNormalVector(n1); barycentricNormal[0] = nodeNormal[0]; barycentricNormal[1] = nodeNormal[1]; barycentricNormal[2] = nodeNormal[2]; } else { /* * Compute position using barycentric coordinates */ float t1[3]; float t2[3]; float t3[3]; for (int i = 0; i < 3; i++) { t1[i] = triangleAreas[0] * c1[i]; t2[i] = triangleAreas[1] * c2[i]; t3[i] = triangleAreas[2] * c3[i]; } float area = (triangleAreas[0] + triangleAreas[1] + triangleAreas[2]); if (area != 0) { for (int i = 0; i < 3; i++) { barycentricXYZ[i] = (t1[i] + t2[i] + t3[i]) / area; } } else { return false; } if (MathFunctions::normalVector(c1, c2, c3, barycentricNormal) == false) { return false; } } /* * Set output coordinate, possibly offsetting from surface. */ for (int j = 0; j < 3; j++) { if (unprojectWithOffsetFromSurface) { xyzOut[j] = (barycentricXYZ[j] + (barycentricNormal[j] * offsetFromSurface)); } else { xyzOut[j] = (barycentricXYZ[j] + (barycentricNormal[j] * signedDistanceAboveSurface)); } } return true; } /** * Reset the surface projection to its initial state. */ void SurfaceProjectionBarycentric::reset() { this->resetAllValues(); } /** * @return Is the projection valid? */ bool SurfaceProjectionBarycentric::isValid() const { return this->projectionValid; } /** * Set the validity of the projection. * @param valid * New validity status. */ void SurfaceProjectionBarycentric::setValid(const bool valid) { this->projectionValid = valid; } /** * Set the projection is degenerate (on * an edge or just outside the edge). * @param degenerate * New status. */ void SurfaceProjectionBarycentric::setDegenerate(const bool degenerate) { m_degenerate = degenerate; } /** * @return Is the projection degenerate (on * an edge or just outside the edge). */ bool SurfaceProjectionBarycentric::isDegenerate() const { return m_degenerate; } /** * Since reset overrides the 'super' class it should * never be called from a constructor. So, this * method does the actual reset, and since it does * not override a method from the 'super' class, it * may be called from this class' constructor. */ void SurfaceProjectionBarycentric::resetAllValues() { this->projectionValid = false; m_degenerate = false; this->triangleAreas[0] = -1.0; this->triangleAreas[1] = -1.0; this->triangleAreas[2] = -1.0; this->triangleNodes[0] = -1; this->triangleNodes[1] = -1; this->triangleNodes[2] = -1; this->signedDistanceAboveSurface = 0.0; } /** * Write the projection to XML. * @param xmlWriter * The XML Writer. * @throw XmlException * If an error occurs. */ void SurfaceProjectionBarycentric::writeAsXML(XmlWriter& xmlWriter) { /* * Note: Degenerate status is not saved! */ if (this->projectionValid) { xmlWriter.writeStartElement(XML_TAG_PROJECTION_BARYCENTRIC); xmlWriter.writeElementCharacters(XML_TAG_TRIANGLE_AREAS, this->triangleAreas, 3); xmlWriter.writeElementCharacters(XML_TAG_TRIANGLE_NODES, this->triangleNodes, 3); xmlWriter.writeElementCharacters(XML_TAG_SIGNED_DISTANCE_ABOVE_SURFACE, this->signedDistanceAboveSurface); xmlWriter.writeEndElement(); } } void SurfaceProjectionBarycentric::readBorderFileXML1(QXmlStreamReader& xml) { reset(); CaretAssert(xml.isStartElement() && xml.name() == "ProjectionBarycentric"); bool haveAreas = false, haveNodes = false, haveDist = false; for (xml.readNext(); !xml.atEnd() && !xml.isEndElement(); xml.readNext()) { switch (xml.tokenType()) { case QXmlStreamReader::StartElement: { QStringRef name = xml.name(); if (name == "TriangleAreas") { if (haveAreas) throw DataFileException("multiple TriangleAreas elements in one ProjectionBarycentric element"); QString text = xml.readElementText();//errors on unexpected element if (xml.hasError()) throw DataFileException("XML parsing error in TriangleAreas: " + xml.errorString()); QStringList areaStrings = text.split(QRegExp("\\s+"), QString::SkipEmptyParts); if (areaStrings.size() != 3) throw DataFileException("TriangleAreas element must contain 3 numbers separated by whitespace"); bool ok = false; for (int i = 0; i < 3; ++i) { triangleAreas[i] = areaStrings[i].toFloat(&ok); if (!ok) throw DataFileException("found non-numeric string in TriangleAreas: " + areaStrings[i]); } haveAreas = true; } else if (name == "TriangleNodes") { if (haveNodes) throw DataFileException("multiple TriangleNodes elements in one ProjectionBarycentric element"); QString text = xml.readElementText();//errors on unexpected element if (xml.hasError()) throw DataFileException("XML parsing error in TriangleNodes: " + xml.errorString()); QStringList nodeStrings = text.split(QRegExp("\\s+"), QString::SkipEmptyParts); if (nodeStrings.size() != 3) throw DataFileException("TriangleNodes element must contain 3 integers separated by whitespace"); bool ok = false; for (int i = 0; i < 3; ++i) { triangleNodes[i] = nodeStrings[i].toInt(&ok); if (!ok) throw DataFileException("found non-integer string in TriangleNodes: " + nodeStrings[i]); } haveNodes = true; } else if (name == "SignedDistanceAboveSurface") { if (haveDist) throw DataFileException("multiple SignedDistanceAboveSurface elements in one ProjectionBarycentric element"); QString text = xml.readElementText();//errors on unexpected element if (xml.hasError()) throw DataFileException("XML parsing error in SignedDistanceAboveSurface: " + xml.errorString()); bool ok = false; signedDistanceAboveSurface = text.toFloat(&ok); if (!ok) throw DataFileException("found non-numeric string in SignedDistanceAboveSurface: " + text); haveDist = true; } else { throw DataFileException("unexpected element in ProjectionBarycentric: " + name.toString()); } break; } default: break; } } if (xml.hasError()) throw DataFileException("XML parsing error in ProjectionBarycentric: " + xml.errorString()); CaretAssert(xml.isEndElement() && xml.name() == "ProjectionBarycentric"); if (!haveAreas || !haveNodes)//ignore missing distance? should always be zero for BorderFile anyway { throw DataFileException("SurfaceProjectionBarycentric element missing TriangleNodes and/or TriangleAreas"); } projectionValid = true; } connectome-workbench-1.4.2/src/Files/SurfaceProjectionBarycentric.h000066400000000000000000000103031360521144700254450ustar00rootroot00000000000000#ifndef __SURFACE_PROJECTION_BARYCENTRIC__H_ #define __SURFACE_PROJECTION_BARYCENTRIC__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SurfaceProjection.h" class QXmlStreamReader; namespace caret { class TopologyHelper; class SurfaceProjectionBarycentric : public SurfaceProjection { public: SurfaceProjectionBarycentric(); virtual ~SurfaceProjectionBarycentric(); SurfaceProjectionBarycentric(const SurfaceProjectionBarycentric& obj); SurfaceProjectionBarycentric& operator=(const SurfaceProjectionBarycentric& obj); bool operator==(const SurfaceProjectionBarycentric& rhs); bool operator!=(const SurfaceProjectionBarycentric& rhs) { return !(*this == rhs); } virtual AString toString() const; float getSignedDistanceAboveSurface() const; void setSignedDistanceAboveSurface(const float signedDistanceAboveSurface); const int32_t* getTriangleNodes() const; void setTriangleNodes(const int32_t triangleNodes[3]); const float* getTriangleAreas() const; void setTriangleAreas(const float triangleAreas[3]); int32_t getNodeWithLargestWeight() const; bool unprojectToSurface(const SurfaceFile& surfaceFile, float xyzOut[3], const float offsetFromSurface, const bool unprojectWithOffsetFromSurface) const; bool unprojectToSurface(const SurfaceFile& surfaceFile, const TopologyHelper* topologyHelper, float xyzOut[3], const float offsetFromSurface, const bool unprojectWithOffsetFromSurface) const; void reset(); bool isValid() const; void setDegenerate(const bool degenerate); bool isDegenerate() const; void setValid(const bool valid); void writeAsXML(XmlWriter& xmlWriter); void readBorderFileXML1(QXmlStreamReader& xml); static const AString XML_TAG_PROJECTION_BARYCENTRIC; static const AString XML_TAG_TRIANGLE_NODES; static const AString XML_TAG_TRIANGLE_AREAS; static const AString XML_TAG_SIGNED_DISTANCE_ABOVE_SURFACE; private: void copyHelperSurfaceProjectionBarycentric(const SurfaceProjectionBarycentric& obj); void resetAllValues(); int32_t triangleNodes[3]; float triangleAreas[3]; float signedDistanceAboveSurface; bool projectionValid; bool m_degenerate; }; #ifdef __SURFACE_PROJECTION_BARYCENTRIC_DECLARE__ const AString SurfaceProjectionBarycentric::XML_TAG_PROJECTION_BARYCENTRIC = "ProjectionBarycentric"; const AString SurfaceProjectionBarycentric::XML_TAG_TRIANGLE_NODES = "TriangleNodes"; const AString SurfaceProjectionBarycentric::XML_TAG_TRIANGLE_AREAS = "TriangleAreas"; const AString SurfaceProjectionBarycentric::XML_TAG_SIGNED_DISTANCE_ABOVE_SURFACE = "SignedDistanceAboveSurface"; #endif // __SURFACE_PROJECTION_BARYCENTRIC_DECLARE__ } // namespace #endif //__SURFACE_PROJECTION_BARYCENTRIC__H_ connectome-workbench-1.4.2/src/Files/SurfaceProjectionVanEssen.cxx000066400000000000000000000617121360521144700253070ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __SURFACE_PROJECTION_VAN_ESSEN_DECLARE__ #include "SurfaceProjectionVanEssen.h" #undef __SURFACE_PROJECTION_VAN_ESSEN_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "MathFunctions.h" #include "SurfaceFile.h" #include "TopologyHelper.h" #include "XmlWriter.h" using namespace caret; /** * \class caret::SurfaceProjectionVanEssen * \brief Maintains a VanEssen Projection that projects to an edge with offset. * */ /** * Constructor. */ SurfaceProjectionVanEssen::SurfaceProjectionVanEssen() : SurfaceProjection() { this->resetAllValues(); } /** * Destructor. */ SurfaceProjectionVanEssen::~SurfaceProjectionVanEssen() { } /** * Copy constructor. * @param obj * Object that is copied. */ SurfaceProjectionVanEssen::SurfaceProjectionVanEssen(const SurfaceProjectionVanEssen& obj) : SurfaceProjection(obj) { this->copyHelperSurfaceProjectionVanEssen(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ SurfaceProjectionVanEssen& SurfaceProjectionVanEssen::operator=(const SurfaceProjectionVanEssen& obj) { if (this != &obj) { SurfaceProjection::operator=(obj); this->copyHelperSurfaceProjectionVanEssen(obj); } return *this; } bool SurfaceProjectionVanEssen::operator==(const SurfaceProjectionVanEssen& rhs) { if (projectionValid != rhs.projectionValid) return false; if (projectionValid) { for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { for (int k = 0; k < 3; k++) { if (triAnatomical[i][j][k] != rhs.triAnatomical[i][j][k]) return false; } if (triVertices[i][j] != rhs.triVertices[i][j]) return false; if (vertexAnatomical[i][j] != rhs.vertexAnatomical[i][j]) return false; } if (vertex[i] != rhs.vertex[i]) return false; } for (int i = 0; i < 3; ++i) { if (posAnatomical[i] != rhs.posAnatomical[i]) return false; } if (thetaR != rhs.thetaR) return false; if (phiR != rhs.phiR) return false; if (fracRI != rhs.fracRI) return false; if (fracRJ != rhs.fracRJ) return false; } return true; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void SurfaceProjectionVanEssen::copyHelperSurfaceProjectionVanEssen(const SurfaceProjectionVanEssen& obj) { this->dR = obj.dR; for (int32_t i = 0; i < 2; i++) { for (int32_t j = 0; j < 3; j++) { for (int32_t k = 0; k < 3; k++) { this->triAnatomical[i][j][k] = obj.triAnatomical[i][j][k]; } this->triVertices[i][j] = obj.triVertices[i][j]; } this->vertex[i] = obj.vertex[i]; } this->vertexAnatomical[0][0] = this->vertexAnatomical[0][0]; this->vertexAnatomical[0][1] = this->vertexAnatomical[0][1]; this->vertexAnatomical[0][2] = this->vertexAnatomical[0][2]; this->vertexAnatomical[1][0] = this->vertexAnatomical[1][0]; this->vertexAnatomical[1][1] = this->vertexAnatomical[1][1]; this->vertexAnatomical[1][2] = this->vertexAnatomical[1][2]; this->posAnatomical[0] = this->posAnatomical[0]; this->posAnatomical[1] = this->posAnatomical[1]; this->posAnatomical[2] = this->posAnatomical[2]; this->thetaR = obj.thetaR; this->phiR = obj.phiR; this->fracRI = obj.fracRI; this->fracRJ = obj.fracRJ; this->projectionValid = obj.projectionValid; } /** * Unproject to the surface using 'this' projection. * * @param surfaceFile * Surface file used for unprojecting. * @param xyzOut * Output containing coordinate created by unprojecting. * @param offsetFromSurface * If 'unprojectWithOffsetFromSurface' is true, unprojected * position will be this distance above (negative=below) * the surface. * @param unprojectWithOffsetFromSurface * If true, ouput coordinate will be offset 'offsetFromSurface' * distance from the surface. */ bool SurfaceProjectionVanEssen::unprojectToSurface(const SurfaceFile& surfaceFile, float xyzOut[3], const float offsetFromSurface, const bool unprojectWithOffsetFromSurface) const { return unprojectToSurface(surfaceFile, NULL, xyzOut, offsetFromSurface, unprojectWithOffsetFromSurface); } /** * Unproject to the surface using 'this' projection. * * @param surfaceFile * Surface file used for unprojecting. * @param topologyHelperIn * Topology helper. If NULL, topology helper from surfaceFile * will be used but frequent calls to get the topology helper * may be slow. * @param xyzOut * Output containing coordinate created by unprojecting. * @param offsetFromSurface * If 'unprojectWithOffsetFromSurface' is true, unprojected * position will be this distance above (negative=below) * the surface. * @param unprojectWithOffsetFromSurface * If true, ouput coordinate will be offset 'offsetFromSurface' * distance from the surface. */ bool SurfaceProjectionVanEssen::unprojectToSurface(const SurfaceFile& surfaceFile, const TopologyHelper* topologyHelperIn, float xyzOut[3], const float offsetFromSurface, const bool unprojectWithOffsetFromSurface) const { /* * Make sure projection surface number of nodes matches surface. */ if (this->projectionSurfaceNumberOfNodes > 0) { if (surfaceFile.getNumberOfNodes() != this->projectionSurfaceNumberOfNodes) { return false; } } const int is = 0; const int js = 1; const int32_t n1 = this->vertex[is]; const int32_t n2 = this->vertex[js]; CaretAssert(n1 < surfaceFile.getNumberOfNodes()); CaretAssert(n2 < surfaceFile.getNumberOfNodes()); /* * All nodes MUST have neighbors (connected) */ const TopologyHelper* topologyHelper = ((topologyHelperIn != NULL) ? topologyHelperIn : surfaceFile.getTopologyHelper().getPointer()); if ((topologyHelper->getNodeHasNeighbors(n1) == false) || (topologyHelper->getNodeHasNeighbors(n2) == false)) { return false; } float v[3]; float v_t1[3]; MathFunctions::subtractVectors(this->vertexAnatomical[js], this->vertexAnatomical[is], v); MathFunctions::subtractVectors(this->posAnatomical, this->vertexAnatomical[is], v_t1); float s_t2 = MathFunctions::dotProduct(v, v); float s_t3 = MathFunctions::dotProduct(v_t1, v); float QR[3]; for (int j = 0; j < 3; j++) { QR[j] = this->vertexAnatomical[is][j] + ((s_t3/s_t2) * v[j]); } const int pis = this->vertex[0]; const int pjs = this->vertex[1]; const float* posPIS = surfaceFile.getCoordinate(pis); const float* posPJS = surfaceFile.getCoordinate(pjs); if (unprojectWithOffsetFromSurface) { xyzOut[0] = (posPIS[0] + posPJS[0]) / 2.0f; xyzOut[1] = (posPIS[1] + posPJS[1]) / 2.0f; xyzOut[2] = (posPIS[2] + posPJS[2]) / 2.0f; if (offsetFromSurface != 0.0) { const float* normalI = surfaceFile.getNormalVector(pis); const float* normalJ = surfaceFile.getNormalVector(pjs); float avgNormal[3] = { ((normalI[0] + normalJ[0]) / 2.0f), ((normalI[1] + normalJ[1]) / 2.0f), ((normalI[2] + normalJ[2]) / 2.0f), }; MathFunctions::normalizeVector(avgNormal); const float offsetX = avgNormal[0] * offsetFromSurface; const float offsetY = avgNormal[1] * offsetFromSurface; const float offsetZ = avgNormal[2] * offsetFromSurface; xyzOut[0] += offsetX; xyzOut[1] += offsetY; xyzOut[2] += offsetZ; } return true; } MathFunctions::subtractVectors(posPJS, posPIS, v); float QS[3]; if ((this->fracRI <= 1.0) && (this->fracRJ <= 1.0)) { for (int j = 0; j < 3; j++) { QS[j] = posPIS[j] + this->fracRI * v[j]; } } else if ((this->fracRI > 1.0) && (this->fracRI > this->fracRJ)) { MathFunctions::subtractVectors(QR, this->vertexAnatomical[js], v_t1); s_t2 = MathFunctions::vectorLength(v_t1); MathFunctions::subtractVectors(posPJS, posPIS, v); s_t3 = MathFunctions::vectorLength(v); for (int j = 0; j < 3; j++) { QS[j] = posPJS[j] + s_t2 * (v[j]/s_t3); } } else if ((this->fracRJ > 1.0) && (this->fracRJ > this->fracRI)) { MathFunctions::subtractVectors(QR, this->vertexAnatomical[is], v_t1); s_t2 = MathFunctions::vectorLength(v_t1); MathFunctions::subtractVectors(posPIS, posPJS, v); s_t3 = MathFunctions::vectorLength(v); for (int j = 0; j < 3; j++) { QS[j] = posPIS[j] + s_t2 * (v[j]/s_t3); } } else { CaretLogWarning(("VanEssen Projection: Unrecognized case for fracRI and fracRJ: " + AString::number(this->fracRI) + ", " + AString::number(this->fracRJ))); return false; } if ((this->triVertices[0][0] < 0) || (this->triVertices[1][0] < 0)) { return false; } float normalB[3]; MathFunctions::normalVector( surfaceFile.getCoordinate(this->triVertices[1][0]), surfaceFile.getCoordinate(this->triVertices[1][1]), surfaceFile.getCoordinate(this->triVertices[1][2]), normalB); float normalA[3]; MathFunctions::normalVector( surfaceFile.getCoordinate(this->triVertices[0][0]), surfaceFile.getCoordinate(this->triVertices[0][1]), surfaceFile.getCoordinate(this->triVertices[0][2]), normalA); s_t2 = MathFunctions::dotProduct(normalA, normalB); s_t2 = std::min(s_t2, 1.0f); // limit to <= 1.0 float phiS = (float)std::acos(s_t2); float thetaS = 0.0f; if (this->phiR > 0.0f) { thetaS = (this->thetaR / this->phiR) * phiS; } else { thetaS = 0.5f * phiS; } /* * Fixes unprojection when thetaR is zero NOT ALL CASES YET */ if (thetaR == 0.0) { // thetaS = M_PI / 2.0; // if (this->phiR > 0.0) { // thetaS = ((M_PI / 2.0) / this->phiR) * phiS; // } } MathFunctions::subtractVectors(posPJS, posPIS, v); MathFunctions::normalizeVector(v); float projection[3] = { 0.0f, 0.0f, 0.0f }; this->computeProjectionPoint(projection); MathFunctions::subtractVectors(projection, QR, v_t1); MathFunctions::normalizeVector(v_t1); MathFunctions::subtractVectors(this->vertexAnatomical[js], this->vertexAnatomical[is], v); MathFunctions::normalizeVector(v); float normalA_3D[3]; MathFunctions::normalVector(this->triAnatomical[0][0], this->triAnatomical[0][1], this->triAnatomical[0][2], normalA_3D); float v_t2[3]; MathFunctions::crossProduct(normalA_3D, v, v_t2); s_t3 = MathFunctions::dotProduct(v_t1, v_t2); float TS[3]; for (int k = 0; k < 3; k++) { TS[k] = QS[k] + (s_t3 * (this->dR * (float)std::sin(thetaS)) * v_t2[k]); } MathFunctions::subtractVectors(this->posAnatomical, projection, v); MathFunctions::normalizeVector(v); s_t3 = MathFunctions::dotProduct(normalA_3D, v); for (int i = 0; i < 3; i++) { xyzOut[i] = TS[i] + (this->dR * s_t3 * (float)std::cos(thetaS)) * normalA[i]; } return true; } /** * Compute a projection point?? * @param * Projection that is computed and set by this method. */ void SurfaceProjectionVanEssen::computeProjectionPoint(float projection[3]) const { float v[3]; MathFunctions::subtractVectors(this->triAnatomical[0][1], this->triAnatomical[0][0], v); float w[3]; MathFunctions::subtractVectors(this->triAnatomical[0][1], this->triAnatomical[0][2], w); float tnormal[3]; MathFunctions::crossProduct(w, v, tnormal); float a[3][3]; for (int k = 0; k < 3; k++) { a[0][k] = v[k]; a[1][k] = w[k]; a[2][k] = tnormal[k]; } float b[3]; b[0] = MathFunctions::dotProduct(v, this->posAnatomical); b[1] = MathFunctions::dotProduct(w, this->posAnatomical); b[2] = MathFunctions::dotProduct(tnormal, this->triAnatomical[0][2]); MathFunctions::vtkLinearSolve3x3(a, b, projection); } /** * @return dR */ float SurfaceProjectionVanEssen::getDR() const { return this->dR; } /** * Set dR * @param dR * New value. */ void SurfaceProjectionVanEssen::setDR(const float dR) { this->dR = dR; this->setModified(); } /** * @return thetaR */ float SurfaceProjectionVanEssen::getThetaR() const { return this->thetaR; } /** * Set thetaR * @param thetaR * New value. */ void SurfaceProjectionVanEssen::setThetaR(const float thetaR) { this->thetaR = thetaR; this->setModified(); } /** * @return phiR */ float SurfaceProjectionVanEssen::getPhiR() const { return this->phiR; } /** * Set phiR * @param phiR * New value. */ void SurfaceProjectionVanEssen::setPhiR(const float phiR) { this->phiR = phiR; this->setModified(); } /** * @return fracRI */ float SurfaceProjectionVanEssen::getFracRI() const { return this->fracRI; } /** * Set fracRI * @param fracRI * New value. */ void SurfaceProjectionVanEssen::setFracRI(const float fracRI) { this->fracRI = fracRI; this->setModified(); } /** * @return fracRJ */ float SurfaceProjectionVanEssen::getFracRJ() const { return this->fracRJ; } /** * Set fracRJ * @param fracRJ * New value. */ void SurfaceProjectionVanEssen::setFracRJ(const float fracRJ) { this->fracRJ = fracRJ; this->setModified(); } /** * Set triVertices * @param triVertices * New values. */ void SurfaceProjectionVanEssen::setTriVertices(const int32_t triVertices[2][3]) { for (int32_t i = 0; i < 2; i++) { for (int32_t j = 0; j < 3; j++) { this->triVertices[i][j] = triVertices[i][j]; } } this->setModified(); } /** * Set triVertices * @param indx1 * Index of vertices being set. * @param triVertices * New values. */ void SurfaceProjectionVanEssen::setTriVertices(const int32_t indx1, const int32_t vertices[3]) { CaretAssertArrayIndex(this->triVertices, 2, indx1); for (int32_t j = 0; j < 3; j++) { this->triVertices[indx1][j] = vertices[j]; } setModified(); } /** * Get triVertices * @param triVertices * Output values. */ void SurfaceProjectionVanEssen::getTriVertices(int32_t triVertices[2][3]) const { for (int32_t i = 0; i < 2; i++) { for (int32_t j = 0; j < 3; j++) { triVertices[i][j] = this->triVertices[i][j]; } } } /** * Set vertex * @param vertex * New values. */ void SurfaceProjectionVanEssen::setVertex(const int32_t vertex[2]) { this->vertex[0] = vertex[0]; this->vertex[1] = vertex[1]; this->setModified(); } /** * Set vertex * @param vertex * New values. */ void SurfaceProjectionVanEssen::setVertex(const int32_t indx1, const int32_t vertex) { CaretAssertArrayIndex(this->vertex, 2, indx1); this->vertex[indx1] = vertex; this->setModified(); } /** * Get vertex * @param vertex * Output values. */ void SurfaceProjectionVanEssen::getVertex(int32_t vertex[2]) const { vertex[0] = this->vertex[0]; vertex[1] = this->vertex[1]; } /** * Set triAnatomical * @param triAnatomical * New values. */ void SurfaceProjectionVanEssen::setTriAnatomical(const float triAnatomical[2][3][3]) { for (int32_t i = 0; i < 2; i++) { for (int32_t j = 0; j < 3; j++) { for (int32_t k = 0; k < 3; k++) { this->triAnatomical[i][j][k] = triAnatomical[i][j][k]; } } } this->setModified(); } /** * Set triAnatomical * @param triAnatomical * New values. */ void SurfaceProjectionVanEssen::setTriAnatomical(const int32_t indx1, const int32_t indx2, const float triAnatomical[3]) { CaretAssertArrayIndex(this->triAnatomical, 2, indx1); CaretAssertArrayIndex(this->triAnatomical, 3, indx2); for (int32_t k = 0; k < 3; k++) { this->triAnatomical[indx1][indx2][k] = triAnatomical[k]; } this->setModified(); } /** * Get triAnatomical * @param triAnatomical * Output values. */ void SurfaceProjectionVanEssen::getTriAnatomical(float triAnatomical[2][3][3]) const { for (int32_t i = 0; i < 2; i++) { for (int32_t j = 0; j < 3; j++) { for (int32_t k = 0; k < 3; k++) { triAnatomical[i][j][k] = this->triAnatomical[i][j][k]; } } } } /** * Set vertexAnatomical * @param vertexAnatomical * New values. */ void SurfaceProjectionVanEssen::setVertexAnatomical(const float vertexAnatomical[2][3]) { this->vertexAnatomical[0][0] = vertexAnatomical[0][0]; this->vertexAnatomical[0][1] = vertexAnatomical[0][1]; this->vertexAnatomical[0][2] = vertexAnatomical[0][2]; this->vertexAnatomical[1][0] = vertexAnatomical[1][0]; this->vertexAnatomical[1][1] = vertexAnatomical[1][1]; this->vertexAnatomical[1][2] = vertexAnatomical[1][2]; this->setModified(); } /** * Set vertexAnatomical * @param vertexAnatomical * New values. */ void SurfaceProjectionVanEssen::setVertexAnatomical(const int32_t indx1, const float vertexAnatomical[3]) { CaretAssertArrayIndex(this->vertexAnatomical, 2, indx1); this->vertexAnatomical[indx1][0] = vertexAnatomical[0]; this->vertexAnatomical[indx1][1] = vertexAnatomical[1]; this->vertexAnatomical[indx1][2] = vertexAnatomical[2]; this->setModified(); } /** * Get vertexAnatomical * @param vertexAnatomical * Output values. */ void SurfaceProjectionVanEssen::getVertexAnatomical(float vertexAnatomical[2][3]) const { vertexAnatomical[0][0] = this->vertexAnatomical[0][0]; vertexAnatomical[0][1] = this->vertexAnatomical[0][1]; vertexAnatomical[0][2] = this->vertexAnatomical[0][2]; vertexAnatomical[1][0] = this->vertexAnatomical[1][0]; vertexAnatomical[1][1] = this->vertexAnatomical[1][1]; vertexAnatomical[1][2] = this->vertexAnatomical[1][2]; } /** * Get posAnatomical * @param posAnatomical * Output values. */ void SurfaceProjectionVanEssen::getPosAnatomical(float posAnatomical[3]) const { posAnatomical[0] = this->posAnatomical[0]; posAnatomical[1] = this->posAnatomical[1]; posAnatomical[2] = this->posAnatomical[2]; } /** * Set posAnatomical * @param posAnatomical * New values. */ void SurfaceProjectionVanEssen::setPosAnatomical(const float posAnatomical[3]) { this->posAnatomical[0] = posAnatomical[0]; this->posAnatomical[1] = posAnatomical[1]; this->posAnatomical[2] = posAnatomical[2]; this->setModified(); } /** * Reset the surface projection to its initial state. */ void SurfaceProjectionVanEssen::reset() { this->resetAllValues(); } /** * Since reset overrides the 'super' class it should * never be called from a constructor. So, this * method does the actual reset, and since it does * not override a method from the 'super' class, it * may be called from this class' constructor. */ void SurfaceProjectionVanEssen::resetAllValues() { this->projectionValid = false; this->dR = 0.0; for (int32_t i = 0; i < 2; i++) { for (int32_t j = 0; j < 3; j++) { for (int32_t k = 0; k < 3; k++) { this->triAnatomical[i][j][k] = 0; } this->triVertices[i][j] = 0.0; } this->vertex[i] = 0.0; } this->vertexAnatomical[0][0] = 0.0; this->vertexAnatomical[0][1] = 0.0; this->vertexAnatomical[0][2] = 0.0; this->vertexAnatomical[1][0] = 0.0; this->vertexAnatomical[1][1] = 0.0; this->vertexAnatomical[1][2] = 0.0; this->posAnatomical[0] = 0.0; this->posAnatomical[1] = 0.0; this->posAnatomical[2] = 0.0; this->thetaR = 0.0; this->phiR = 0.0; this->fracRI = 0.0; this->fracRJ = 0.0; } /** * @return Is the projection valid? */ bool SurfaceProjectionVanEssen::isValid() const { return this->projectionValid; } /** * Set the validity of the projection. * @param valid * New validity status. */ void SurfaceProjectionVanEssen::setValid(const bool valid) { this->projectionValid = valid; setModified(); } /** * Write the projection to XML. * @param xmlWriter * The XML Writer. * @throw XmlException * If an error occurs. */ void SurfaceProjectionVanEssen::writeAsXML(XmlWriter& xmlWriter) { if (this->projectionValid) { xmlWriter.writeStartElement(XML_TAG_PROJECTION_VAN_ESSEN); xmlWriter.writeElementCharacters(XML_TAG_DR, this->dR); xmlWriter.writeElementCharacters(XML_TAG_TRI_ANATOMICAL, (float*)this->triAnatomical, 18); xmlWriter.writeElementCharacters(XML_TAG_THETA_R, this->thetaR); xmlWriter.writeElementCharacters(XML_TAG_PHI_R, this->phiR); xmlWriter.writeElementCharacters(XML_TAG_TRI_VERTICES, (int32_t*)this->triVertices, 6); xmlWriter.writeElementCharacters(XML_TAG_VERTEX, (int32_t*)this->vertex, 2); xmlWriter.writeElementCharacters(XML_TAG_VERTEX_ANATOMICAL, (float*)this->vertexAnatomical, 6); xmlWriter.writeElementCharacters(XML_TAG_POS_ANATOMICAL, this->posAnatomical, 3); xmlWriter.writeElementCharacters(XML_TAG_FRAC_RI, this->fracRI); xmlWriter.writeElementCharacters(XML_TAG_FRAC_RJ, this->fracRJ); xmlWriter.writeEndElement(); } } /** * Get a description of this object's content. * @return String describing this object's content. */ AString SurfaceProjectionVanEssen::toString() const { AString txt = SurfaceProjection::toString(); if (txt.isEmpty() == false) { txt += ", "; } txt += ("dR=" + AString::number(dR) + ", thetaR=" + AString::number(thetaR) + ", phiR=" + AString::number(phiR) + ", fracRI=" + AString::number(fracRI) + ", fracRJ=" + AString::number(fracRJ) + ", triVertices=" + AString::fromNumbers((int32_t*)triVertices, 6, ",") + ", vertex=" + AString::fromNumbers(vertex, 2, ",") + ", triAnatomical=" + AString::fromNumbers((float*)triAnatomical, 18, ",") + ", vertexAnatomical=" + AString::fromNumbers((float*)vertexAnatomical, 6, ",") + ", posAnatomical=" + AString::fromNumbers(posAnatomical, 3, ",") ); return txt; } connectome-workbench-1.4.2/src/Files/SurfaceProjectionVanEssen.h000066400000000000000000000144331360521144700247320ustar00rootroot00000000000000#ifndef __SURFACE_PROJECTION_VAN_ESSEN__H_ #define __SURFACE_PROJECTION_VAN_ESSEN__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SurfaceProjection.h" namespace caret { class TopologyHelper; class SurfaceProjectionVanEssen : public SurfaceProjection { public: SurfaceProjectionVanEssen(); virtual ~SurfaceProjectionVanEssen(); SurfaceProjectionVanEssen(const SurfaceProjectionVanEssen& obj); SurfaceProjectionVanEssen& operator=(const SurfaceProjectionVanEssen& obj); bool operator==(const SurfaceProjectionVanEssen& rhs); bool operator!=(const SurfaceProjectionVanEssen& rhs) { return !(*this == rhs); } bool unprojectToSurface(const SurfaceFile& surfaceFile, const TopologyHelper* topologyHelper, float xyzOut[3], const float offsetFromSurface, const bool unprojectWithOffsetFromSurface) const; bool unprojectToSurface(const SurfaceFile& surfaceFile, float xyzOut[3], const float offsetFromSurface, const bool unprojectWithOffsetFromSurface) const; float getDR() const; void setDR(const float dR); float getThetaR() const; void setThetaR(const float thetaR); float getPhiR() const; void setPhiR(const float phiR); float getFracRI() const; void setFracRI(const float fracRI); float getFracRJ() const; void setFracRJ(const float fracRJ); void setTriVertices(const int32_t triVertices[2][3]); void setTriVertices(const int32_t indx1, const int32_t vertices[3]); void getTriVertices(int32_t triVertices[2][3]) const; void setVertex(const int32_t vertex[2]); void setVertex(const int32_t indx1, const int32_t vertex); void getVertex(int32_t vertex[2]) const; void setTriAnatomical(const float triAnatomical[2][3][3]); void setTriAnatomical(const int32_t indx1, const int32_t indx2, const float anatomical[3]); void getTriAnatomical(float triAnatomical[2][3][3]) const; void setVertexAnatomical(const float vertexAnatomical[2][3]); void setVertexAnatomical(const int32_t indx1, const float anatomical[3]); void getVertexAnatomical(float vertexAnatomical[2][3]) const; void getPosAnatomical(float posAnatomical[3]) const; void setPosAnatomical(const float posAnatomical[3]); void reset(); bool isValid() const; void setValid(const bool valid); virtual AString toString() const; void writeAsXML(XmlWriter& xmlWriter); static const AString XML_TAG_PROJECTION_VAN_ESSEN; static const AString XML_TAG_DR; static const AString XML_TAG_TRI_ANATOMICAL; static const AString XML_TAG_THETA_R; static const AString XML_TAG_PHI_R; static const AString XML_TAG_TRI_VERTICES; static const AString XML_TAG_VERTEX; static const AString XML_TAG_VERTEX_ANATOMICAL; static const AString XML_TAG_POS_ANATOMICAL; static const AString XML_TAG_FRAC_RI; static const AString XML_TAG_FRAC_RJ; private: void copyHelperSurfaceProjectionVanEssen(const SurfaceProjectionVanEssen& obj); void computeProjectionPoint(float projection[3]) const; void resetAllValues(); float dR; float thetaR; float phiR; float fracRI; float fracRJ; int32_t triVertices[2][3]; int32_t vertex[2]; float triAnatomical[2][3][3]; float vertexAnatomical[2][3]; float posAnatomical[3]; bool projectionValid; }; #ifdef __SURFACE_PROJECTION_VAN_ESSEN_DECLARE__ const AString SurfaceProjectionVanEssen::XML_TAG_PROJECTION_VAN_ESSEN = "VanEssenProjection"; const AString SurfaceProjectionVanEssen::XML_TAG_DR = "DR"; const AString SurfaceProjectionVanEssen::XML_TAG_TRI_ANATOMICAL = "TriAnatomical"; const AString SurfaceProjectionVanEssen::XML_TAG_THETA_R = "ThetaR"; const AString SurfaceProjectionVanEssen::XML_TAG_PHI_R = "PhiR"; const AString SurfaceProjectionVanEssen::XML_TAG_TRI_VERTICES = "TriVertices"; const AString SurfaceProjectionVanEssen::XML_TAG_VERTEX = "Vertex"; const AString SurfaceProjectionVanEssen::XML_TAG_VERTEX_ANATOMICAL = "VertexAnatomical"; const AString SurfaceProjectionVanEssen::XML_TAG_POS_ANATOMICAL = "PosAnatomical"; const AString SurfaceProjectionVanEssen::XML_TAG_FRAC_RI = "FracRI"; const AString SurfaceProjectionVanEssen::XML_TAG_FRAC_RJ = "FracRJ"; #endif // __SURFACE_PROJECTION_VAN_ESSEN_DECLARE__ } // namespace #endif //__SURFACE_PROJECTION_VAN_ESSEN__H_ connectome-workbench-1.4.2/src/Files/SurfaceProjector.cxx000066400000000000000000001642031360521144700234760ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #define __SURFACE_PROJECTOR_DEFINE__ #include "SurfaceProjector.h" #undef __SURFACE_PROJECTOR_DEFINE__ #include "CaretLogger.h" #include "FociFile.h" #include "Focus.h" #include "MathFunctions.h" #include "SignedDistanceHelper.h" #include "SurfaceFile.h" #include "SurfaceProjectedItem.h" #include "SurfaceProjectionBarycentric.h" #include "SurfaceProjectionVanEssen.h" #include "TopologyHelper.h" using namespace caret; /** * \class caret::SurfaceProjector * \brief Project points to a surface. */ /** * Constructor for projection to a given surface. * * @param surfaceFile * Surface to which projection takes place. For proper * projection (particularly flat and spherical) surfaces, it is important * that the surface's type is correctly set. */ SurfaceProjector::SurfaceProjector(const SurfaceFile* surfaceFile) : CaretObject(), m_surfaceFileLeft(NULL), m_surfaceFileRight(NULL), m_surfaceFileCerebellum(NULL), m_mode(MODE_SURFACES) { CaretAssert(surfaceFile); m_surfaceFiles.push_back(surfaceFile); initializeMembersSurfaceProjector(); } /** * Constructor for projection to closest of a group of surfaces. * * @param surfaceFiles * Vector of Surfaces to which projection takes place. For proper * projection (particularly flat and spherical) surfaces, it is important * that the surface's type is correctly set. */ SurfaceProjector::SurfaceProjector(const std::vector& surfaceFiles) : CaretObject(), m_surfaceFileLeft(NULL), m_surfaceFileRight(NULL), m_surfaceFileCerebellum(NULL), m_mode(MODE_SURFACES) { const int32_t numberOfSurfaces = static_cast(surfaceFiles.size()); for (int32_t i = 0; i < numberOfSurfaces; i++) { m_surfaceFiles.push_back(surfaceFiles[i]); } initializeMembersSurfaceProjector(); } /** * Constructor that allows ambiguous projections for items between a cortical * surface and the cerebellum. Items that have a positive X-coordinate * are projected to the right cortex or the cerebellum. Items that have * a negative X-coordinate are projected to the left cortex or the cerebellum. * Some of the surface files may be NULL but at least one must be valid. * * @param leftSurfaceFile * Surface file for left cortex. * @param rightSurfaceFile * Surface file for right cortex. * @param cerebellumSurfaceFile * Surface file for cerebellum cortex. */ SurfaceProjector::SurfaceProjector(const SurfaceFile* leftSurfaceFile, const SurfaceFile* rightSurfaceFile, const SurfaceFile* cerebellumSurfaceFile) : CaretObject(), m_surfaceFileLeft(leftSurfaceFile), m_surfaceFileRight(rightSurfaceFile), m_surfaceFileCerebellum(cerebellumSurfaceFile), m_mode(MODE_LEFT_RIGHT_CEREBELLUM) { } /** * Destructor */ SurfaceProjector::~SurfaceProjector() { } /** * Initialize members of this instance. */ void SurfaceProjector::initializeMembersSurfaceProjector() { m_surfaceOffset = 0.0; m_surfaceOffsetValid = false; /* * Validate when logger is set at a specified level * If the level is changed, all need to change level * where validation message is logged. */ m_validateFlag = CaretLogger::getLogger()->isFine(); m_validateItemName = ""; } /** * Set the desired offset of projected items from the surface-> * * @param surfaceOffset - distance above the surface-> * */ void SurfaceProjector::setSurfaceOffset(const float surfaceOffset) { m_surfaceOffset = surfaceOffset; m_surfaceOffsetValid = true; } /** * Project all foci in a foci file. * @param fociFile * The foci file. * @throws SurfaceProjectorException * If projecting an item failed. */ void SurfaceProjector::projectFociFile(FociFile* fociFile) { CaretAssert(fociFile); const int32_t numberOfFoci = fociFile->getNumberOfFoci(); AString errorMessage = ""; for (int32_t i = 0; i < numberOfFoci; i++) { Focus* focus = fociFile->getFocus(i); try { if (m_validateFlag) { m_validateItemName = ("Focus " + AString::number(i) + ", " + focus->getName()); } projectFocus(i, focus); } catch (const SurfaceProjectorException& spe) { if (errorMessage.isEmpty() == false) { errorMessage += "\n"; } errorMessage += (focus->getName() + ", index=" + AString::number(i) + ": " + spe.whatString()); } } if (errorMessage.isEmpty() == false) { throw SurfaceProjectorException(errorMessage); } } /** * Project a focus. * @param focusIndex * Index of the focus (negative indicates no index) * @param focus * The focus. * @throws SurfaceProjectorException * If projecting an item failed. */ void SurfaceProjector::projectFocus(const int32_t focusIndex, Focus* focus) { const int32_t numberOfProjections = focus->getNumberOfProjections(); CaretAssert(numberOfProjections > 0); if (numberOfProjections < 0) { throw SurfaceProjectorException("Focus has no projections, no stereotaxic coordinate."); } focus->removeExtraProjections(); SurfaceProjectedItem* spi = focus->getProjection(0); SurfaceProjectedItem* spiSecond = NULL; if (m_surfaceFileCerebellum != NULL) { spiSecond = new SurfaceProjectedItem(); } m_allowEdgeProjection = true; projectItem(spi, spiSecond); if (spiSecond != NULL) { if (spiSecond->hasValidProjection()) { focus->addProjection(spiSecond); } else { delete spiSecond; spiSecond = NULL; } } if (m_projectionWarning.isEmpty() == false) { AString msg = ("Focus: Name=" + focus->getName()); if (focusIndex >= 0) { msg += (", Index=" + AString::number(focusIndex)); } msg += (": " + m_projectionWarning); CaretLogWarning(msg);; } } /** * Project to the surface(s) triangles (barycentric projection) * * @param spi * Item that is to be projected. Its contents will be * updated to reflect the projection. This item's stereotaxic coordinate * is used for the projection point. * * @throws SurfaceProjectorException * If projecting an item failed. */ void SurfaceProjector::projectItemToTriangle(SurfaceProjectedItem* spi) { CaretAssert(spi); m_allowEdgeProjection = false; projectItem(spi, NULL); } /** * Project to the surface(s) triangles (barycentric projection) * or edges (van-essen projection). * * @param spi * Item that is to be projected. Its contents will be * updated to reflect the projection. This item's stereotaxic coordinate * is used for the projection point. * * @throws SurfaceProjectorException * If projecting an item failed. */ void SurfaceProjector::projectItemToTriangleOrEdge(SurfaceProjectedItem* spi) { CaretAssert(spi); m_allowEdgeProjection = true; projectItem(spi, NULL); } /** * Project to the appropriate surface(s). * * @param spi * Item that is to be projected. Its contents will be * updated to reflect the projection. This item's stereotaxic coordinate * is used for the projection point. * @param secondSpi * For left/right/cerebellum projections, if there is ambiguity for an * item (between cortex and cerebellum), this projection will be set if * it is not NULL. * @throws SurfaceProjectorException * If projecting an item failed. */ void SurfaceProjector::projectItem(SurfaceProjectedItem* spi, SurfaceProjectedItem* secondSpi) { m_projectionWarning = ""; /* * Get position of item. */ float xyz[3]; if (spi->isStereotaxicXYZValid() == false) { throw SurfaceProjectorException( "Stereotaxic position is invalid, cannot project."); } spi->getStereotaxicXYZ(xyz); if (secondSpi != NULL) { secondSpi->setStereotaxicXYZ(xyz); } switch (m_mode) { case MODE_LEFT_RIGHT_CEREBELLUM: { if (xyz[0] < 0.0) { if (m_surfaceFileLeft != NULL) { if (m_surfaceFileCerebellum != NULL) { const float leftDist = m_surfaceFileLeft->getSignedDistanceHelper()->dist(xyz, SignedDistanceHelper::NORMALS); const float cerebellumDist = m_surfaceFileCerebellum->getSignedDistanceHelper()->dist(xyz, SignedDistanceHelper::NORMALS); float ratio = 1000000.0; if (cerebellumDist != 0.0) { ratio = leftDist / cerebellumDist; } if (ratio > s_cerebellumSurfaceCutoff) { projectItemToSurfaceFile(m_surfaceFileCerebellum, spi); } else if (ratio < s_corticalSurfaceCutoff) { projectItemToSurfaceFile(m_surfaceFileLeft, spi); } else { projectItemToSurfaceFile(m_surfaceFileLeft, spi); if (secondSpi != NULL) { projectItemToSurfaceFile(m_surfaceFileCerebellum, secondSpi); } } } else { projectItemToSurfaceFile(m_surfaceFileLeft, spi); } } else if (m_surfaceFileCerebellum != NULL) { projectItemToSurfaceFile(m_surfaceFileCerebellum, spi); } } else { if (m_surfaceFileRight != NULL) { if (m_surfaceFileCerebellum != NULL) { const float rightDist = m_surfaceFileRight->getSignedDistanceHelper()->dist(xyz, SignedDistanceHelper::NORMALS); const float cerebellumDist = m_surfaceFileCerebellum->getSignedDistanceHelper()->dist(xyz, SignedDistanceHelper::NORMALS); float ratio = 1000000.0; if (cerebellumDist != 0.0) { ratio = rightDist / cerebellumDist; } if (ratio > s_cerebellumSurfaceCutoff) { projectItemToSurfaceFile(m_surfaceFileCerebellum, spi); } else if (ratio < s_corticalSurfaceCutoff) { projectItemToSurfaceFile(m_surfaceFileRight, spi); } else { projectItemToSurfaceFile(m_surfaceFileRight, spi); if (secondSpi != NULL) { projectItemToSurfaceFile(m_surfaceFileCerebellum, secondSpi); } } } else { projectItemToSurfaceFile(m_surfaceFileRight, spi); } } else if (m_surfaceFileCerebellum != NULL) { projectItemToSurfaceFile(m_surfaceFileCerebellum, spi); } } } break; case MODE_SURFACES: { const int32_t numberOfSurfaceFiles = static_cast(m_surfaceFiles.size()); if (numberOfSurfaceFiles <= 0) { throw SurfaceProjectorException("No surface for projection!"); } int32_t nearestSurfaceIndex = -1; if (numberOfSurfaceFiles == 1) { nearestSurfaceIndex = 0; } else { /* * Find surface closest to node. */ float nearestDistance = std::numeric_limits::max(); for (int32_t i = 0; i < numberOfSurfaceFiles; i++) { const SurfaceFile* sf = m_surfaceFiles[i]; CaretPointer sdh = sf->getSignedDistanceHelper(); const float absDist = std::fabs(sdh->dist(xyz, SignedDistanceHelper::NORMALS)); if (absDist < nearestDistance) { nearestDistance = absDist; nearestSurfaceIndex = i; } } } if (nearestSurfaceIndex < 0) { throw SurfaceProjectorException("Failed to find surface for projection."); } const SurfaceFile* projectionSurfaceFile = m_surfaceFiles[nearestSurfaceIndex]; projectItemToSurfaceFile(projectionSurfaceFile, spi); } break; } } /** * Project to the given surface * @param surfaceFile * Surface to which triangle projection is made. * @param spi * Item that is to be projected. Its contents will be * updated to reflect the projection. This items XYZ coordinate * is used for the projection point. * * @throws SurfaceProjectorException If projecting an item * failed. */ void SurfaceProjector::projectItemToSurfaceFile(const SurfaceFile* surfaceFile, SurfaceProjectedItem* spi) { float originalXYZ[3]; spi->getStereotaxicXYZ(originalXYZ); float xyz[3] = { originalXYZ[0], originalXYZ[1], originalXYZ[2] }; float projXYZ[3]; float stereoXYZ[3]; float distanceError = 0.0; bool projectionValid = false; projectToSurface(surfaceFile, xyz, spi); if (spi->getBarycentricProjection()->isValid() || spi->getVanEssenProjection()->isValid()) { spi->getProjectedPosition(*surfaceFile, projXYZ, false); spi->getStereotaxicXYZ(stereoXYZ); distanceError = MathFunctions::distance3D(projXYZ, stereoXYZ); projectionValid = true; } if (distanceError > s_projectionDistanceError) { bool perturbIfError = true; if (perturbIfError) { /* * Initialize with first try */ float bestXYZ[3] = { xyz[0], xyz[1], xyz[2] }; float bestDistance = distanceError; bool bestValid = true; const float originalDistanceError = distanceError; for (int32_t iTry = 0; iTry < 10; iTry++) { const float randomZeroToOne = ((float)std::rand()) / ((float)RAND_MAX); const float randomPlusMinusOneHalf = randomZeroToOne - 0.5; const float moveLittleBit = randomPlusMinusOneHalf * 0.5; xyz[0] = originalXYZ[0] + moveLittleBit; xyz[1] = originalXYZ[1] + moveLittleBit; xyz[2] = originalXYZ[2] + moveLittleBit; SurfaceProjectedItem spiTest; spiTest.setStereotaxicXYZ(originalXYZ); projectToSurface(surfaceFile, xyz, &spiTest); if (spiTest.getBarycentricProjection()->isValid() || spiTest.getVanEssenProjection()->isValid()) { spiTest.getProjectedPosition(*surfaceFile, projXYZ, false); spiTest.getStereotaxicXYZ(stereoXYZ); distanceError = MathFunctions::distance3D(projXYZ, stereoXYZ); projectionValid = true; // std::cout << "Moved from original (" // << AString::fromNumbers(originalXYZ, 3, ",") // << ") to (" // << AString::fromNumbers(xyz, 3, ",") // << ") distance error now=" // << distanceError // << std::endl; if (distanceError < bestDistance) { bestXYZ[0] = xyz[0]; bestXYZ[1] = xyz[1]; bestXYZ[2] = xyz[2]; bestDistance = distanceError; bestValid = true; } } } if (bestValid) { projectToSurface(surfaceFile, bestXYZ, spi); if (spi->getBarycentricProjection()->isValid() || spi->getVanEssenProjection()->isValid()) { spi->getProjectedPosition(*surfaceFile, projXYZ, false); spi->getStereotaxicXYZ(stereoXYZ); distanceError = MathFunctions::distance3D(projXYZ, stereoXYZ); m_projectionWarning += ("Was moved due to projection error from (" + AString::fromNumbers(originalXYZ, 3, ",") + ") to (" + AString::fromNumbers(bestXYZ, 3, ",") + ") with distance error reduced from " + AString::number(originalDistanceError) + " to " + AString::number(distanceError)); } } } } if (m_validateFlag == false) { if (distanceError > s_projectionDistanceError) { m_projectionWarning += ("Projection Warning: Error=" + AString::number(distanceError) + "mm, Stereotaxic=(" + AString::fromNumbers(stereoXYZ, 3, ",") + "), Projected=(" + AString::fromNumbers(projXYZ, 3, ",") + ")"); } } if (m_validateFlag) { bool errorFlag = false; AString validateString; if (projectionValid) { AString projTypeString = "Unprojected"; AString projInfo; if (spi->getBarycentricProjection()->isValid()) { projTypeString = "Triangle"; if (spi->getBarycentricProjection()->isDegenerate()) { projTypeString = "-degenerate"; } projInfo = spi->getBarycentricProjection()->toString(); } else if (spi->getVanEssenProjection()->isValid()) { projTypeString = "Edge"; projInfo = spi->getVanEssenProjection()->toString(); } AString matchString = ""; if (distanceError > 0.001) { matchString = " FAILED *************************"; errorFlag = true; } if (validateString.isEmpty() == false) { validateString += "\n"; } if (spi->getStructure() == StructureEnum::CEREBELLUM) { if (spi->getVanEssenProjection()->isValid()) { //errorFlag = true; } } validateString += (m_validateItemName + ": projType=" + projTypeString + ": structure=" + StructureEnum::toName(spi->getStructure()) + ", stereoPos=(" + AString::fromNumbers(stereoXYZ, 3, ",") + "), projPos=(" + AString::fromNumbers(projXYZ, 3, ",") + "): stereo/proj positions differ by " + AString::number(distanceError, 'f', 3) + matchString + "\n"); if (projInfo.isEmpty() == false) { validateString += (projInfo + "\n"); } } else { validateString += (m_validateItemName + ": failed to project\n"); errorFlag = true; } if (errorFlag && (validateString.isEmpty() == false)) { CaretLogFine(validateString); } } } /** * Project to the surface * @param surfaceFile * Surface to which triangle projection is made. * @param xyz * Coordinate that is being projected. * @param spi * Item that is to be projected. Its contents will be * updated to reflect the projection. This items XYZ coordinate * is used for the projection point. * * @throws SurfaceProjectorException If projecting an item * failed. */ void SurfaceProjector::projectToSurface(const SurfaceFile* surfaceFile, const float xyz[3], SurfaceProjectedItem* spi) { // // If needed, create node locator // if (surfaceFile->getNumberOfNodes() <= 0) { throw SurfaceProjectorException("Surface file contains no nodes: " + surfaceFile->getFileNameNoPath()); } if (surfaceFile->getNumberOfTriangles() <= 0) { throw SurfaceProjectorException("Surface topology contains no triangles: " + surfaceFile->getFileNameNoPath()); } m_sphericalSurfaceRadius = 0.0; m_surfaceTypeHint = SURFACE_HINT_THREE_DIMENSIONAL; switch (surfaceFile->getSurfaceType()) { case SurfaceTypeEnum::FLAT: m_surfaceTypeHint = SURFACE_HINT_FLAT; break; case SurfaceTypeEnum::SPHERICAL: m_surfaceTypeHint = SURFACE_HINT_SPHERE; m_sphericalSurfaceRadius = surfaceFile->getSphericalRadius(); break; default: m_surfaceTypeHint = SURFACE_HINT_THREE_DIMENSIONAL; break; } // // Default to invalid projection // SurfaceProjectionBarycentric* baryProj = spi->getBarycentricProjection(); baryProj->setValid(false); SurfaceProjectionVanEssen* vanEssenProj = spi->getVanEssenProjection(); vanEssenProj->setValid(false); /* * Determine if projected to node/edge/triangle */ ProjectionLocation projectionLocation; getProjectionLocation(surfaceFile, xyz, projectionLocation); if (m_validateFlag) { if (m_validateItemName.isEmpty() == false) { m_validateItemName += "\n"; } m_validateItemName += ("ORIGINAL: " + projectionLocation.toString(surfaceFile)); } /* * If projected to edge and edge projection allowed */ if (m_allowEdgeProjection && (projectionLocation.m_type == ProjectionLocation::EDGE)) { vanEssenProj->setPosAnatomical(xyz); projectWithVanEssenAlgorithm(surfaceFile, projectionLocation, vanEssenProj); if (vanEssenProj->isValid() == false) { throw SurfaceProjectorException("Edge projection failed."); } } else { /* * Convert the projection to a triangle projection. */ if ((projectionLocation.m_type == ProjectionLocation::EDGE) || (projectionLocation.m_type == ProjectionLocation::NODE)) { convertToTriangleProjection(surfaceFile, projectionLocation); if (m_validateFlag) { if (m_validateItemName.isEmpty() == false) { m_validateItemName += "\n"; } m_validateItemName += ("ALTERED: " + projectionLocation.toString(surfaceFile)); } } projectToSurfaceTriangle(surfaceFile, projectionLocation, spi->getBarycentricProjection()); if (baryProj->isValid() == false) { throw SurfaceProjectorException("Triangle projection failed."); } } spi->setStructure(surfaceFile->getStructure()); } /** * Convert an edge or node projection to a triangle projection which * may become a degenerate triangle projection. * @param surfaceFile * Surface to which triangle projection is made. * @param projectionLocation * Contains informaiton about item on the surface file. * * @throws SurfaceProjectorException If projecting an item * failed. */ void SurfaceProjector::convertToTriangleProjection(const SurfaceFile* surfaceFile, ProjectionLocation& projectionLocation) { bool doIt = false; switch (projectionLocation.m_type) { case ProjectionLocation::EDGE: doIt = true; break; case ProjectionLocation::INVALID: break; case ProjectionLocation::NODE: doIt = true; break; case ProjectionLocation::TRIANGLE: break; } if (doIt) { SurfaceProjectionBarycentric baryProj; checkItemInTriangle(surfaceFile, projectionLocation.m_triangleIndices[0], projectionLocation.m_pointXYZ, s_extremeTriangleAreaTolerance, &baryProj); if (baryProj.isValid()) { projectionLocation.m_type = ProjectionLocation::TRIANGLE; const int32_t* nodes = baryProj.getTriangleNodes(); projectionLocation.m_nodes[0] = nodes[0]; projectionLocation.m_nodes[1] = nodes[1]; projectionLocation.m_nodes[2] = nodes[2]; const float* areas = baryProj.getTriangleAreas(); projectionLocation.m_weights[0] = areas[0]; projectionLocation.m_weights[1] = areas[1]; projectionLocation.m_weights[2] = areas[2]; projectionLocation.m_signedDistance = baryProj.getSignedDistanceAboveSurface(); projectionLocation.m_absoluteDistance = std::fabs(projectionLocation.m_signedDistance); } else { throw SurfaceProjectorException("Failed to convert from edge/node projection to triangle projection"); } } } /** * Project a coordinate to the surface using a barycentric projection. * @param surfaceFile * Surface to which triangle projection is made. * @param projectionLocation * Contains informaiton about item on the surface file. * @param baryProj * The barycentric projection that will be updated. * * @throws SurfaceProjectorException If projecting an item * failed. * */ void SurfaceProjector::projectToSurfaceTriangle(const SurfaceFile* surfaceFile, const ProjectionLocation& projectionLocation, SurfaceProjectionBarycentric* baryProj) { /* * At one time, there was a need to 'perturb' (slightly move) the * surface, probably for registration. */ projectToSurfaceTriangleAux(surfaceFile, projectionLocation, baryProj); if (baryProj->isValid()) { if (m_surfaceOffsetValid) { baryProj->setSignedDistanceAboveSurface(m_surfaceOffset); } } } /** * Get the location on the surface nearest the given coordinate. * @param surfaceFile * Surface for location. * @param xyz * The coordinate. * @param projectionLocation * Output containing location on surface information. */ void SurfaceProjector::getProjectionLocation(const SurfaceFile* surfaceFile, const float xyz[3], ProjectionLocation& projectionLocation) const { /* * Find nearest point on the surface */ CaretPointer sdh = surfaceFile->getSignedDistanceHelper(); BarycentricInfo baryInfo; sdh->barycentricWeights(xyz, baryInfo); int32_t nearestNode = -1; float maxWeight = -1; std::vector nodes; std::vector weights; for (int32_t i = 0; i < 3; i++) { if (baryInfo.baryWeights[i] > 0.0) { nodes.push_back(baryInfo.nodes[i]); const float w = baryInfo.baryWeights[i]; weights.push_back(w); if (w > maxWeight) { nearestNode = baryInfo.nodes[i]; maxWeight = w; } } } if (nearestNode < 0) { throw SurfaceProjectorException("ERROR: Nearest node is invalid"); } float signedDistance = 0.0; switch (baryInfo.type) { case BarycentricInfo::NODE: { if (nodes.size() != 1) { throw SurfaceProjectorException("ERROR: project to node number of weights incorrect=" + AString::number(nodes.size())); } else { const float* nodeNormal = surfaceFile->getNormalVector(nodes[0]); const float* c1 = surfaceFile->getCoordinate(nodes[0]); const float aboveBelowPlane = MathFunctions::signedDistanceFromPlane(nodeNormal, c1, xyz); const float signValue = ((aboveBelowPlane > 0.0) ? 1.0 : -1.0); signedDistance = (MathFunctions::distance3D(xyz, c1) * signValue); } } break; case BarycentricInfo::EDGE: { if (nodes.size() != 2) { throw SurfaceProjectorException("ERROR: project to edge number weights incorrect=" + AString::number(nodes.size())); } else { const float* n1 = surfaceFile->getNormalVector(nodes[0]); const float* n2 = surfaceFile->getNormalVector(nodes[1]); float avgNormal[3]; MathFunctions::addVectors(n1, n2, avgNormal); MathFunctions::normalizeVector(avgNormal); const float* c1 = surfaceFile->getCoordinate(nodes[0]); const float* c2 = surfaceFile->getCoordinate(nodes[1]); MathFunctions::distanceToLine3D(c1, c2, xyz); const float aboveBelowPlane = MathFunctions::signedDistanceFromPlane(avgNormal, baryInfo.point, xyz); const float signValue = ((aboveBelowPlane > 0.0) ? 1.0 : -1.0); signedDistance = (MathFunctions::distance3D(xyz, baryInfo.point) * signValue); } } break; case BarycentricInfo::TRIANGLE: { if (nodes.size() != 3) { throw SurfaceProjectorException("ERROR: project to triangle number of weights incorrect=" + AString::number(nodes.size())); } else { float triangleNormal[3]; surfaceFile->getTriangleNormalVector(baryInfo.triangle, triangleNormal); const float* c1 = surfaceFile->getCoordinate(nodes[0]); signedDistance = MathFunctions::signedDistanceFromPlane(triangleNormal, c1, xyz); } } break; } /* * Topology helper */ CaretPointer topologyHelper = surfaceFile->getTopologyHelper(); /* * Triangle(s) near projection point on surface */ std::vector nearbyTriangles; /* * Load up the projection information. */ projectionLocation.m_type = ProjectionLocation::INVALID; switch (baryInfo.type) { case BarycentricInfo::NODE: { projectionLocation.m_type = ProjectionLocation::NODE; int32_t numTriangles = 0; const int32_t* nodesTriangles = topologyHelper->getNodeTiles(nodes[0], numTriangles); /* * Make sure nearest triangle is first and * keep triangles ordering */ int32_t iStart = 0; for (int32_t i = 0; i < numTriangles; i++) { if (nodesTriangles[i] == baryInfo.triangle) { iStart = i; break; } } if (iStart < 0) { throw SurfaceProjectorException("PROGRAM ERROR: Nearest triangle node found to be associated with nearest node"); } for (int32_t i = iStart; i < numTriangles; i++) { nearbyTriangles.push_back(nodesTriangles[i]); } for (int32_t i = 0; i < iStart; i++) { nearbyTriangles.push_back(nodesTriangles[i]); } } break; case BarycentricInfo::EDGE: { projectionLocation.m_type = ProjectionLocation::EDGE; const int32_t oppositeTriangle = surfaceFile->getTriangleThatSharesEdge(nodes[0], nodes[1], baryInfo.triangle); nearbyTriangles.push_back(baryInfo.triangle); nearbyTriangles.push_back(oppositeTriangle); } break; case BarycentricInfo::TRIANGLE: projectionLocation.m_type = ProjectionLocation::TRIANGLE; nearbyTriangles.push_back(baryInfo.triangle); break; } for (int32_t i = 0; i < 3; i++) { projectionLocation.m_pointXYZ[i] = xyz[i]; projectionLocation.m_surfaceXYZ[i] = baryInfo.point[i]; if (i < static_cast(nodes.size())) { projectionLocation.m_nodes[i] = nodes[i]; projectionLocation.m_weights[i] = weights[i]; } else { projectionLocation.m_nodes[i] = -1; projectionLocation.m_weights[i] = 0.0; } } projectionLocation.m_numberOfTriangles = static_cast(nearbyTriangles.size()); projectionLocation.m_triangleIndices = new int32_t[projectionLocation.m_numberOfTriangles]; for (int32_t i = 0; i < projectionLocation.m_numberOfTriangles; i++) { projectionLocation.m_triangleIndices[i] = nearbyTriangles[i]; } projectionLocation.m_absoluteDistance = baryInfo.absDistance; projectionLocation.m_signedDistance = signedDistance; projectionLocation.m_nearestNode = nearestNode; AString distErrorMessage = ""; float distError = std::fabs(signedDistance) - baryInfo.absDistance; if (distError > 0.01) { throw SurfaceProjectorException("ERROR: signed/abs distance mismatch: " + projectionLocation.toString(surfaceFile)); } } /** * Project a coordinate to the surface * @param surfaceFile * Surface file to which item is projected. * @param projectionLocation * Contains informaiton about item on the surface file. * @param baryProj * The barycentric projection that will be set. * @return * The node nearest the coordinate. * @throws SurfaceProjectorException * If projecting an item failed. */ int32_t SurfaceProjector::projectToSurfaceTriangleAux(const SurfaceFile* surfaceFile, const ProjectionLocation& projectionLocation, SurfaceProjectionBarycentric* baryProj) { /* * Set the projection. */ baryProj->setTriangleAreas(projectionLocation.m_weights); baryProj->setTriangleNodes(projectionLocation.m_nodes); baryProj->setProjectionSurfaceNumberOfNodes(surfaceFile->getNumberOfNodes()); if (m_surfaceOffsetValid) { baryProj->setSignedDistanceAboveSurface(m_surfaceOffset); } else { baryProj->setSignedDistanceAboveSurface(projectionLocation.m_signedDistance); } baryProj->setValid(true); return projectionLocation.m_nearestNode; } /** * See if the coordinate is within the triangle. * @param surfaceFile * Surface file to which item is projected. * @param triangleNumber * Triangle to check. * @param xyz * The coordinate * @param degenerateTolerance * If the point is outside the triangle, an output area will be negative. * In most cases use zero or a negative value (-0.01) very near zero. A very * negative value can be used to allow degenerate cases. * @param baryProj * Barycentric projection into triangle. */ void SurfaceProjector::checkItemInTriangle(const SurfaceFile* surfaceFile, const int32_t triangleNumber, const float xyz[3], const float degenerateTolerance, SurfaceProjectionBarycentric* baryProj) { // // Vertices of the triangle // const int32_t* tn = surfaceFile->getTriangle(triangleNumber); const float* v1 = surfaceFile->getCoordinate(tn[0]); const float* v2 = surfaceFile->getCoordinate(tn[1]); const float* v3 = surfaceFile->getCoordinate(tn[2]); // // coordinate that may be pushed to a plane depending upon surfac type // float queryXYZ[3] = { xyz[0], xyz[1], xyz[2] }; // // Initialize normal vector to normal of triangle // float normal[3]; MathFunctions::normalVector(v1, v2, v3, normal); // // Adjust the query coordinate based upon the surface type // switch (m_surfaceTypeHint) { case SURFACE_HINT_FLAT: // // Override normal with flat surface normal // normal[0] = 0.0f; normal[1] = 0.0f; normal[2] = 1.0f; queryXYZ[2] = 0.0f; // place on plane break; case SURFACE_HINT_SPHERE: { if (m_sphericalSurfaceRadius > 0.0) { MathFunctions::normalizeVector(queryXYZ); queryXYZ[0] *= m_sphericalSurfaceRadius; queryXYZ[1] *= m_sphericalSurfaceRadius; queryXYZ[2] *= m_sphericalSurfaceRadius; } float origin[3] = { 0.0f, 0.0f, 0.0f }; float xyzDistance[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; if (MathFunctions::rayIntersectPlane(v1, v2, v3, origin, queryXYZ, xyzDistance) == false) { // // Ray does not intersect, must be parallel to plane // return; } // // Use intersection point // queryXYZ[0] = xyzDistance[0]; queryXYZ[1] = xyzDistance[1]; queryXYZ[2] = xyzDistance[2]; } break; case SURFACE_HINT_THREE_DIMENSIONAL: { // // Project point to the triangle // float xyzOnPlane[3]; MathFunctions::projectPoint(queryXYZ, v1, normal, xyzOnPlane); queryXYZ[0] = xyzOnPlane[0]; queryXYZ[1] = xyzOnPlane[1]; queryXYZ[2] = xyzOnPlane[2]; } break; } // // Note that if tolerance is a small negative number (which is done to handle // degenerate cases - projected point on vertex or edge of triangle) an area may // be negative and we continue searching tiles. If all areas are positive // then there is no need to continue searching. // float areas[3] = { 0.0f, 0.0f, 0.0f }; int result = triangleAreas(v1, v2, v3, normal, queryXYZ, degenerateTolerance, areas); if (result != 0) { baryProj->setValid(true); if (result < 0) { baryProj->setDegenerate(true); } float signedDistanceToTriangle = MathFunctions::signedDistanceFromPlane(normal, v1, xyz); baryProj->setTriangleAreas(areas); baryProj->setTriangleNodes(tn); baryProj->setSignedDistanceAboveSurface(signedDistanceToTriangle); baryProj->setProjectionSurfaceNumberOfNodes(surfaceFile->getNumberOfNodes()); } } /** * Compute the signed areas formed by assuming "xyz" is contained in the triangle formed * by the points "p1, p2, p3". "area2" and "area3" may not be set if "xyz" is not * within the triangle. * * @param p1 * Coordinate of triangle node1. * @param p2 * Coordinate of triangle node2. * @param p3 * Coordinate of triangle node3. * @param normal * Triangle's normal vector. * @param xyz * The coordinate being examined. * @param degenerateTolerance * If the point is outside the triangle, an output area will be negative. * In most cases use zero or a negative value (-0.01) very near zero. A very * negative value can be used to allow degenerate cases. * @param areasOut * Output barycentric areas of xyz in the triangle OUTPUT. * @return * Returns 1 if all areas are positive (point32_t inside the triangle). * Returns -1 if all areas are greater than the tolerance * (point32_t may be on edge or vertex) * Returns 0 if not in the triangle. * */ int32_t SurfaceProjector::triangleAreas( const float p1[3], const float p2[3], const float p3[3], const float normal[3], const float xyz[3], const float degenerateTolerance, float areasOut[3]) { float area1 = 0.0f; float area2 = 0.0f; float area3 = 0.0f; int32_t result = 0; float triangleArea = 0.0f; bool inside = false; switch (m_surfaceTypeHint) { case SURFACE_HINT_FLAT: area1 = MathFunctions::triangleAreaSigned2D(p2, p3, xyz); if (area1 > degenerateTolerance) { area2 = MathFunctions::triangleAreaSigned2D(p3, p1, xyz); if (area2 > degenerateTolerance) { area3 = MathFunctions::triangleAreaSigned2D(p1, p2, xyz); if (area3 > degenerateTolerance) { inside = true; triangleArea = MathFunctions::triangleAreaSigned2D(p1, p2, p3); } } } break; case SURFACE_HINT_SPHERE: case SURFACE_HINT_THREE_DIMENSIONAL: area1 = MathFunctions::triangleAreaSigned3D(normal, p2, p3, xyz); if (area1 >= degenerateTolerance) { area2 = MathFunctions::triangleAreaSigned3D(normal, p3, p1, xyz); if (area2 >= degenerateTolerance) { area3 = MathFunctions::triangleAreaSigned3D(normal, p1,p2,xyz); if (area3 >= degenerateTolerance) { inside = true; triangleArea = MathFunctions::triangleArea(p1, p2, p3); } } } break; } if (inside) { if ((area1 > 0.0) && (area2 > 0.0) && (area3 > 0.0)) { result = 1; } else { result = -1; } // if (area1 < 0.0) area1 = -area1; // if (area2 < 0.0) area2 = -area2; // if (area3 < 0.0) area3 = -area3; if (triangleArea > 0.0) { //area1 /= triangleArea; //area2 /= triangleArea; //area3 /= triangleArea; } else { area1 = 1.0f; area2 = 0.0f; area3 = 0.0f; } } areasOut[0] = area1; areasOut[1] = area2; areasOut[2] = area3; return result; } /** * Perform a VanEssen Projection that projects to the edge of two triangles. * * @param surfaceFile * File to which item is projected. * @param projectionLocation * Contains informaiton about item on the surface file. * @param spve * The Van Essen Projection that is setup. * @throws SurfaceProjectorException If projection failure. * */ void SurfaceProjector::projectWithVanEssenAlgorithm(const SurfaceFile* surfaceFile, const ProjectionLocation& projectionLocation, SurfaceProjectionVanEssen* spve) { float xyz[3] = { projectionLocation.m_pointXYZ[0], projectionLocation.m_pointXYZ[1], projectionLocation.m_pointXYZ[2] }; const bool pointIsUnderSurface = (projectionLocation.m_signedDistance < 0.0); // // Find nearest triangle to coordinate // const int32_t nearestTriangle = projectionLocation.m_triangleIndices[0]; if (nearestTriangle < 0) { throw SurfaceProjectorException( "Unable to find nearest triangle for VanEssen projection."); } // // Get triangle's nodes and their coordinates // const int32_t* tn = surfaceFile->getTriangle(nearestTriangle); int32_t n1 = tn[0]; int32_t n2 = tn[1]; int32_t n3 = tn[2]; const float* p1 = surfaceFile->getCoordinate(n1); const float* p2 = surfaceFile->getCoordinate(n2); const float* p3 = surfaceFile->getCoordinate(n3); // // Project the coordinate to the plane of nearest triangle // float planeNormal[3]; MathFunctions::normalVector(p1, p2, p3, planeNormal); float xyzOnPlane[3]; MathFunctions::projectPoint(xyz, p1, planeNormal, xyzOnPlane); // // Adjust for surface offset // if (m_surfaceOffsetValid) { for (int32_t i = 0; i < 3; i++) { xyz[i] = xyzOnPlane[i] + planeNormal[i] * m_surfaceOffset; } } /* * With the nearest triangle, determine which edge is closest * to the coordinate */ const int32_t closestVertices[2] = { projectionLocation.m_nodes[0], projectionLocation.m_nodes[1] }; /* * Nodes and triangles using the edge */ int32_t iR = closestVertices[0]; int32_t jR = closestVertices[1]; int32_t triA = nearestTriangle; int32_t triB = projectionLocation.m_triangleIndices[1]; const float* coordJR = surfaceFile->getCoordinate(jR); const float* coordIR = surfaceFile->getCoordinate(iR); /* * Normal vector for triangle nearest the coordinate */ float normalA[3]; surfaceFile->getTriangleNormalVector(triA, normalA); /* * When point is under surface, need to flip the normal vector */ if (pointIsUnderSurface) { for (int32_t i = 0; i < 3; i++) { normalA[i] *= -1.0; } } /* * Second triangle might not be found if topology is open or cut. */ float normalB[3] = { 0.0f, 0.0f, 0.0f }; if (triB >= 0) { /* * Normal vector for triangle sharing edge with nearest triangle */ surfaceFile->getTriangleNormalVector(triB, normalB); /* * When point is under surface, need to flip the normal vector */ if (pointIsUnderSurface) { for (int32_t i = 0; i < 3; i++) { normalB[i] *= -1.0; } } } else { float dR = (float)std::sqrt(MathFunctions::distance3D(xyzOnPlane, xyz)); float v[3]; MathFunctions::subtractVectors(coordJR, coordIR, v); float t1[3]; MathFunctions::subtractVectors(xyz, coordIR, t1); float t2 = MathFunctions::dotProduct(v, v); float t3 = MathFunctions::dotProduct(t1, v); float QR[3] = { 0.0f, 0.0f, 0.0f }; for (int32_t j = 0; j < 3; j++) { QR[j] = coordIR[j] + ((t3/t2) * v[j]); } MathFunctions::subtractVectors(coordJR, coordIR, v); t2 = MathFunctions::vectorLength(v); MathFunctions::subtractVectors(QR, coordIR, t1); t3 = MathFunctions::vectorLength(t1); float fracRI = 0.0f; if (t2 > 0.0f) { fracRI = t3/t2; } MathFunctions::subtractVectors(coordIR, coordJR, v); t2 = MathFunctions::vectorLength(v); MathFunctions::subtractVectors(QR, coordJR, t1); t3 = MathFunctions::vectorLength(t1); float fracRJ = 0.0f; if (t2 > 0.0f) { fracRJ = t3/t2; } else { fracRI = 0.0f; // uses fracRI seems wrong but like this in OLD code } if (fracRI > 1.0f) { for (int32_t j = 0; j < 3; j++) { QR[j] = coordJR[j]; } } if (fracRJ > 1.0f) { for (int32_t j = 0; j < 3; j++) { QR[j] = coordIR[j]; } } MathFunctions::subtractVectors(xyz, xyzOnPlane, t1); t2 = MathFunctions::vectorLength(t1); if (t2 > 0.0f) { for (int32_t j = 0; j < 3; j++) { t1[j] = t1[j]/t2; } } t3 = MathFunctions::dotProduct(t1, normalA); for (int32_t j = 0; j < 3; j++) { xyz[j] = QR[j] + (dR * t3 * normalA[j]); } } /* * Vector from "IR" to "JR" */ float v[3]; MathFunctions::subtractVectors(coordJR, coordIR, v); /* * Vector from "IR" to "xyz" */ float t1[3]; MathFunctions::subtractVectors(xyz, coordIR, t1); float t2 = MathFunctions::dotProduct(v, v); float t3 = MathFunctions::dotProduct(t1, v); float QR[3] = { 0.0f, 0.0f, 0.0f }; for (int32_t j = 0; j < 3; j++) { QR[j] = coordIR[j] + ((t3/t2) * v[j]); } if ((triA >= 0) && (triB >= 0)) { /* * t2 is arccos of angle between the normal vectors of the two triangles */ t2 = MathFunctions::dotProduct(normalA, normalB); t2 = std::min(t2, 1.0f); /* * Angle formed by the normal vectors of the two triangles */ spve->setPhiR((float)std::acos(t2)); if (m_validateFlag) { m_validateItemName += (", t2=" + AString::number(t2) + ", angleDegrees=" + AString::number(MathFunctions::toDegrees(spve->getPhiR()))); } } else { spve->setPhiR(0.0f); } /* * Vector from "QR" to "xyz" */ MathFunctions::subtractVectors(xyz, QR, t1); MathFunctions::normalizeVector(t1); /* * t3 is arccos of nearest triangle and "t1" */ t3 = MathFunctions::dotProduct(normalA, t1); if (t3 > 0.0f) { spve->setThetaR((float)std::acos(t3 * (t3/std::fabs(t3)))); if ((spve->getThetaR() > -0.001) && (spve->getThetaR() < 0.001)) { const float oneDegreeRadians = (1.0 * M_PI) / 180.0; if (spve->getPhiR() < oneDegreeRadians) { m_validateItemName += (",t3=" + AString::number(t3) + ",thetaR=" + AString::number(spve->getThetaR(), 'f', 10) + "THETAR=NEAR0,t2=SMALL-POSITIVE***"); } } } else { spve->setThetaR(0.0f); if (m_validateFlag) { if (t2 < 0.0) { m_validateItemName += (" ***THETAR=0,t2=NEG***"); } } } MathFunctions::subtractVectors(coordJR, coordIR, v); t2 = MathFunctions::vectorLength(v); MathFunctions::subtractVectors(QR, coordIR, t1); t3 = MathFunctions::vectorLength(t1); if (t2 > 0.0f) { spve->setFracRI(t3/t2); } else { spve->setFracRI(0.0f); } MathFunctions::subtractVectors(coordIR, coordJR, v); t2 = MathFunctions::vectorLength(v); MathFunctions::subtractVectors(QR, coordJR, t1); t3 = MathFunctions::vectorLength(t1); if (t2 > 0.0f) { spve->setFracRJ(t3/t2); } else { spve->setFracRJ(0.0f); } spve->setDR(MathFunctions::distance3D(QR, xyz)); const int32_t* triANodes = surfaceFile->getTriangle(triA); int32_t nodesA[3] = { triANodes[0], triANodes[1], triANodes[2] }; int32_t swapA = nodesA[0]; nodesA[0] = nodesA[2]; nodesA[2] = swapA; spve->setTriVertices(0, nodesA); spve->setTriAnatomical(0,0,surfaceFile->getCoordinate(nodesA[0])); spve->setTriAnatomical(0,1,surfaceFile->getCoordinate(nodesA[1])); spve->setTriAnatomical(0,2,surfaceFile->getCoordinate(nodesA[2])); if (triB >= 0) { const int32_t* triBNodes = surfaceFile->getTriangle(triB); int32_t nodesB[3] = { triBNodes[0], triBNodes[1], triBNodes[2] }; int32_t swapB = nodesB[0]; nodesB[0] = nodesB[2]; nodesB[2] = swapB; spve->setTriVertices(1, nodesB); spve->setTriAnatomical(1,0,surfaceFile->getCoordinate(nodesB[0])); spve->setTriAnatomical(1,1,surfaceFile->getCoordinate(nodesB[1])); spve->setTriAnatomical(1,2,surfaceFile->getCoordinate(nodesB[2])); } else { int32_t intZeros[3] = { 0, 0, 0 }; spve->setTriVertices(1, intZeros); float zeros[3] = { 0.0f, 0.0f, 0.0f }; spve->setTriAnatomical(1, 0, zeros); spve->setTriAnatomical(1, 1, zeros); spve->setTriAnatomical(1, 2, zeros); } spve->setVertexAnatomical(0, coordIR); spve->setVertexAnatomical(1, coordJR); spve->setVertex(0, iR); spve->setVertex(1, jR); spve->setProjectionSurfaceNumberOfNodes(surfaceFile->getNumberOfNodes()); spve->setValid(true); } /* ========================================================================== */ /** * \class caret::SurfaceProjector::ProjectionLocation * \brief Contains information about nearby point on surface */ /** * Constructor. */ SurfaceProjector::ProjectionLocation::ProjectionLocation() { m_type = INVALID; m_triangleIndices = NULL; m_numberOfTriangles = 0; } /** * Destructor. */ SurfaceProjector::ProjectionLocation::~ProjectionLocation() { if (m_triangleIndices != NULL) { delete[] m_triangleIndices; } } /** * Get String describing content. * @param surfaceFile * Surface file used for projection * @return * Description. */ AString SurfaceProjector::ProjectionLocation::toString(const SurfaceFile* surfaceFile) const { AString typeString; switch (m_type) { case EDGE: typeString = "EDGE"; break; case INVALID: typeString = "INVALID"; break; case NODE: typeString = "NODE"; break; case TRIANGLE: typeString = "TRIANGLE"; break; } AString msg = (" Type=" + typeString + " Pos=(" + AString::fromNumbers(m_pointXYZ, 3, ",") + ") SurfacePos=(" + AString::fromNumbers(m_surfaceXYZ, 3, ",") + ") Triangles=(" + AString::fromNumbers(m_triangleIndices, m_numberOfTriangles, ",") + ") AbsDistance=" + AString::number(m_absoluteDistance) + " SignedDistance=" + AString::number(m_signedDistance) + " Nodes=(" + AString::fromNumbers(m_nodes, 3, ",") + ") Weights=(" + AString::fromNumbers(m_weights, 3, ",") + ") NearestNode=" + AString::number(m_nearestNode) + " Node-XYZ=(" + AString::fromNumbers(surfaceFile->getCoordinate(m_nearestNode), 3,",") + ")"); return msg; } connectome-workbench-1.4.2/src/Files/SurfaceProjector.h000066400000000000000000000200031360521144700231100ustar00rootroot00000000000000#ifndef __SURFACE_PROJECTOR_H__ #define __SURFACE_PROJECTOR_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "SurfaceProjectorException.h" #include #include namespace caret { class FociFile; class Focus; class SurfaceFile; class SurfaceProjectedItem; class SurfaceProjectionBarycentric; class SurfaceProjectionVanEssen; class TopologyHelper; /** * Class for projecting items to the surface. */ class SurfaceProjector : public CaretObject { public: SurfaceProjector(const SurfaceFile* surfaceFile); SurfaceProjector(const std::vector& surfaceFiles); SurfaceProjector(const SurfaceFile* leftSurfaceFile, const SurfaceFile* rightSurfaceFile, const SurfaceFile* cerebellumSurfaceFile); virtual ~SurfaceProjector(); void projectItemToTriangle(SurfaceProjectedItem* spi); void projectItemToTriangleOrEdge(SurfaceProjectedItem* spi); void projectFociFile(FociFile* fociFile); void projectFocus(const int32_t focusIndex, Focus* focus); void setSurfaceOffset(const float surfaceOffset); private: enum SurfaceHintType { SURFACE_HINT_FLAT, SURFACE_HINT_SPHERE, SURFACE_HINT_THREE_DIMENSIONAL }; enum Mode { MODE_LEFT_RIGHT_CEREBELLUM, MODE_SURFACES }; class ProjectionLocation { public: enum Type { EDGE, INVALID, NODE, TRIANGLE }; ProjectionLocation(); ~ProjectionLocation(); AString toString(const SurfaceFile* surfaceFile) const; /** Type of surface item projected to */ Type m_type; /** Coordinate that was projected */ float m_pointXYZ[3]; /** Nearest coordinate on surface */ float m_surfaceXYZ[3]; /** Nearest triangle(s) indices (closest triangle always first) */ int32_t* m_triangleIndices; /** Number of triangles */ int32_t m_numberOfTriangles; /** Absolute distance to the surface */ float m_absoluteDistance; /** Signed distance to surface (positive=>above, negative=>below) */ float m_signedDistance; /** Nodes of node/edge/triangle (node has 1 element, edge 2, triangle 3) */ int32_t m_nodes[3]; /** Weights cooresponding to nodes (node has 1 element, edge 2, triangle 3) */ float m_weights[3]; /** Node nearest to the coordinate that was projected */ int32_t m_nearestNode; }; SurfaceProjector(const SurfaceProjector& o); SurfaceProjector& operator=(const SurfaceProjector& o); void initializeMembersSurfaceProjector(); void getProjectionLocation(const SurfaceFile* surfaceFile, const float xyz[3], ProjectionLocation& projectionLocation) const; void projectItem(SurfaceProjectedItem* spi, SurfaceProjectedItem* secondSpi); void projectItemToSurfaceFile(const SurfaceFile* surfaceFile, SurfaceProjectedItem* spi); void projectToSurface(const SurfaceFile* surfaceFile, const float xyz[3], SurfaceProjectedItem* spi) ; void projectToSurfaceTriangle(const SurfaceFile* surfaceFile, const ProjectionLocation& projectionLocation, SurfaceProjectionBarycentric* baryProj) ; int32_t projectToSurfaceTriangleAux(const SurfaceFile* surfaceFile, const ProjectionLocation& projectionLocation, SurfaceProjectionBarycentric* baryProj) ; void checkItemInTriangle(const SurfaceFile* surfaceFile, const int32_t triangleNumber, const float xyz[3], const float degenerateTolerance, SurfaceProjectionBarycentric* baryProj); int32_t triangleAreas( const float p1[3], const float p2[3], const float p3[3], const float normal[3], const float xyz[3], const float degenerateTolerance, float areasOut[3]); void convertToTriangleProjection(const SurfaceFile* surfaceFile, ProjectionLocation& projectionLocation); void projectWithVanEssenAlgorithm(const SurfaceFile* surfaceFile, const ProjectionLocation& projectionLocation, SurfaceProjectionVanEssen* spve) ; std::vector m_surfaceFiles; const SurfaceFile* m_surfaceFileLeft; const SurfaceFile* m_surfaceFileRight; const SurfaceFile* m_surfaceFileCerebellum; const Mode m_mode; SurfaceHintType m_surfaceTypeHint; float m_sphericalSurfaceRadius; float m_surfaceOffset; bool m_surfaceOffsetValid; bool m_allowEdgeProjection; bool m_validateFlag; AString m_validateItemName; AString m_projectionWarning; /** Point in triangle test tolerance that requires point inside triangle */ static float s_normalTriangleAreaTolerance; /** Point in triangle test tolerance that allows point outside triangle (degenerate case) */ static float s_extremeTriangleAreaTolerance; /** Projection distance error used to compare original and after projection/unprojection */ static float s_projectionDistanceError; /** Cutoff for item that that is projected to cortex and not cerebellum */ static float s_corticalSurfaceCutoff; /** Cutoff for item that that is projected to cerebellum and not cortex */ static float s_cerebellumSurfaceCutoff; }; #ifdef __SURFACE_PROJECTOR_DEFINE__ float SurfaceProjector::s_normalTriangleAreaTolerance = -0.01; float SurfaceProjector::s_extremeTriangleAreaTolerance = -10000000.0; float SurfaceProjector::s_projectionDistanceError = 0.5; float SurfaceProjector::s_corticalSurfaceCutoff = 2.0; float SurfaceProjector::s_cerebellumSurfaceCutoff = 4.0; #endif // __SURFACE_PROJECTOR_DEFINE__ } // namespace #endif // __SURFACE_PROJECTOR_H__ connectome-workbench-1.4.2/src/Files/SurfaceProjectorException.cxx000066400000000000000000000037261360521144700253570ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SurfaceProjectorException.h" #include using namespace caret; /** * Constructor. * */ SurfaceProjectorException::SurfaceProjectorException() : CaretException() { this->initializeMembersSurfaceProjectorException(); } /** * Constructor. * * @param s Description of the exception. * */ SurfaceProjectorException::SurfaceProjectorException( const AString& s) : CaretException(s) { this->initializeMembersSurfaceProjectorException(); } /** * Copy Constructor. * @param e * Exception that is copied. */ SurfaceProjectorException::SurfaceProjectorException(const SurfaceProjectorException& e) : CaretException(e) { } /** * Assignment operator. * @param e * Exception that is copied. * @return * Copy of the exception. */ SurfaceProjectorException& SurfaceProjectorException::operator=(const SurfaceProjectorException& e) { if (this != &e) { CaretException::operator=(e); } return *this; } /** * Destructor */ SurfaceProjectorException::~SurfaceProjectorException() throw() { } void SurfaceProjectorException::initializeMembersSurfaceProjectorException() { } connectome-workbench-1.4.2/src/Files/SurfaceProjectorException.h000066400000000000000000000030541360521144700247760ustar00rootroot00000000000000#ifndef __SURFACE_PROJECTOR_EXCEPTION_H__ #define __SURFACE_PROJECTOR_EXCEPTION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretException.h" namespace caret { /** * An exception thrown during surface projector processing. */ class SurfaceProjectorException : public CaretException { public: SurfaceProjectorException(); SurfaceProjectorException(const AString& s); SurfaceProjectorException(const SurfaceProjectorException& e); SurfaceProjectorException& operator=(const SurfaceProjectorException& e); virtual ~SurfaceProjectorException() throw(); private: void initializeMembersSurfaceProjectorException(); }; } // namespace #endif // __SURFACE_PROJECTOR_EXCEPTION_H__ connectome-workbench-1.4.2/src/Files/SurfaceResamplingHelper.cxx000066400000000000000000000641161360521144700247720ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*LICENSE_END*/ #include "SurfaceResamplingHelper.h" #include "CaretAssert.h" #include "CaretException.h" #include "CaretOMP.h" #include "GeodesicHelper.h" #include "SignedDistanceHelper.h" #include "SurfaceFile.h" #include "TopologyHelper.h" #include "Vector3D.h" #include #include using namespace std; using namespace caret; SurfaceResamplingHelper::SurfaceResamplingHelper(const SurfaceResamplingMethodEnum::Enum& myMethod, const SurfaceFile* currentSphere, const SurfaceFile* newSphere, const float* currentAreas, const float* newAreas, const float* currentRoi) { if (!checkSphere(currentSphere) || !checkSphere(newSphere)) throw CaretException("input surfaces to SurfaceResamplingHelper must be spheres"); SurfaceFile currentSphereMod, newSphereMod; changeRadius(100.0f, currentSphere, ¤tSphereMod); changeRadius(100.0f, newSphere, &newSphereMod); switch (myMethod) { case SurfaceResamplingMethodEnum::ADAP_BARY_AREA: CaretAssert(currentAreas != NULL && newAreas != NULL); if (currentAreas == NULL || newAreas == NULL) throw CaretException("ADAP_BARY_AREA method requires area surfaces"); computeWeightsAdapBaryArea(¤tSphereMod, &newSphereMod, currentAreas, newAreas, currentRoi); break; case SurfaceResamplingMethodEnum::BARYCENTRIC: computeWeightsBarycentric(¤tSphereMod, &newSphereMod, currentRoi); break; } } void SurfaceResamplingHelper::resampleNormal(const float* input, float* output, const float& invalidVal) const { int numNodes = (int)m_weights.size() - 1; #pragma omp CARET_PARFOR schedule(dynamic) for (int i = 0; i < numNodes; ++i) { WeightElem* end = m_weights[i + 1], *elem = m_weights[i]; if (elem != end) { double accum = 0.0; for (; elem != end; ++elem) { accum += input[elem->node] * elem->weight;//don't need to divide afterwards, because the weights already sum to 1 } output[i] = accum; } else { output[i] = invalidVal; } } } void SurfaceResamplingHelper::resample3DCoord(const float* input, float* output) const { int numNodes = (int)m_weights.size() - 1; #pragma omp CARET_PARFOR schedule(dynamic) for (int i = 0; i < numNodes; ++i) { double tempvec[3] = { 0.0, 0.0, 0.0 }; WeightElem* end = m_weights[i + 1]; for (WeightElem* elem = m_weights[i]; elem != end; ++elem) { const float* coord = input + elem->node * 3; tempvec[0] += coord[0] * elem->weight;//don't need to divide afterwards, because the weights already sum to 1 tempvec[1] += coord[1] * elem->weight; tempvec[2] += coord[2] * elem->weight; } int i3 = i * 3; output[i3] = tempvec[0]; output[i3 + 1] = tempvec[1]; output[i3 + 2] = tempvec[2]; } } void SurfaceResamplingHelper::resamplePopular(const int32_t* input, int32_t* output, const int32_t& invalidVal) const { int numNodes = (int)m_weights.size() - 1; #pragma omp CARET_PARFOR schedule(dynamic) for (int i = 0; i < numNodes; ++i) { map accum; float maxweight = -1.0f; int32_t bestlabel = invalidVal; WeightElem* end = m_weights[i + 1]; for (WeightElem* elem = m_weights[i]; elem != end; ++elem) { int32_t label = input[elem->node]; map::iterator iter = accum.find(label); if (iter == accum.end()) { accum[label] = elem->weight; if (elem->weight > maxweight) { maxweight = elem->weight; bestlabel = label; } } else { iter->second += elem->weight; if (iter->second > maxweight) { maxweight = iter->second; bestlabel = label; } } } output[i] = bestlabel; } } void SurfaceResamplingHelper::resampleLargest(const float* input, float* output, const float& invalidVal) const { int numNodes = (int)m_weights.size() - 1; #pragma omp CARET_PARFOR schedule(dynamic) for (int i = 0; i < numNodes; ++i) { WeightElem* end = m_weights[i + 1]; float largest = -1.0f; int largestNode = -1; for (WeightElem* elem = m_weights[i]; elem != end; ++elem) { if (elem->weight > largest) { largest = elem->weight; largestNode = elem->node; } } if (largestNode != -1) { output[i] = input[largestNode]; } else { output[i] = invalidVal; } } } void SurfaceResamplingHelper::resampleLargest(const int32_t* input, int32_t* output, const int32_t& invalidVal) const { int numNodes = (int)m_weights.size() - 1; #pragma omp CARET_PARFOR schedule(dynamic) for (int i = 0; i < numNodes; ++i) { WeightElem* end = m_weights[i + 1]; float largest = -1.0f; int largestNode = -1; for (WeightElem* elem = m_weights[i]; elem != end; ++elem) { if (elem->weight > largest) { largest = elem->weight; largestNode = elem->node; } } if (largestNode != -1) { output[i] = input[largestNode]; } else { output[i] = invalidVal; } } } void SurfaceResamplingHelper::getResampleValidROI(float* output) const { int numNodes = (int)m_weights.size() - 1; for (int i = 0; i < numNodes; ++i) { if (m_weights[i] != m_weights[i + 1]) { output[i] = 1.0f; } else { output[i] = 0.0f; } } } void SurfaceResamplingHelper::resampleCutSurface(const SurfaceFile* cutSurfaceIn, const SurfaceFile* currentSphere, const SurfaceFile* newSphere, SurfaceFile* surfaceOut) { if (cutSurfaceIn->getNumberOfNodes() != currentSphere->getNumberOfNodes()) throw CaretException("input surface has different number of nodes than input sphere"); if (!checkSphere(currentSphere) || !checkSphere(newSphere)) throw CaretException("input surfaces to SurfaceResamplingHelper must be spheres"); SurfaceFile currentSphereMod, newSphereMod; changeRadius(100.0f, currentSphere, ¤tSphereMod); changeRadius(100.0f, newSphere, &newSphereMod); SurfaceFile cutCurSphere = *cutSurfaceIn; cutCurSphere.setCoordinates(currentSphereMod.getCoordinateData()); int newNodes = newSphere->getNumberOfNodes(); vector newInfo(newSphere->getNumberOfNodes()); #pragma omp CARET_PAR { CaretPointer mySignedHelp = cutCurSphere.getSignedDistanceHelper(); #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < newNodes; ++i) { mySignedHelp->barycentricWeights(newSphereMod.getCoordinate(i), newInfo[i]); } } vector isOnEdge(newNodes, 0);//really used as bool, but avoid bitpacking so it can be modified in parallel CaretPointer cutTopoHelp = cutSurfaceIn->getTopologyHelper();//because topology didn't change, and it might have one already - also, don't need separate helpers per thread, not using neighbors to depth CaretPointer closedTopoHelp = currentSphere->getTopologyHelper();//ditto CaretPointer newTopoHelp = newSphere->getTopologyHelper();//tritto? const vector& cutEdgeInfo = cutTopoHelp->getEdgeInfo(); vector largestNode(newNodes, -1); #pragma omp CARET_PARFOR for (int i = 0; i < newNodes; ++i) { float largestWeight = 0.0f, secondWeight = 0.0f;//locate the two nodes with largest barycentric weights largestNode[i] = -1; int secondNode = -1; for (int j = 0; j < 3; ++j) { if (newInfo[i].baryWeights[j] > largestWeight) { secondNode = largestNode[i];//shift largest to second secondWeight = largestWeight; largestWeight = newInfo[i].baryWeights[j];//update largest largestNode[i] = newInfo[i].nodes[j]; } else if (newInfo[i].baryWeights[j] > secondWeight) { secondWeight = newInfo[i].baryWeights[j]; secondNode = newInfo[i].nodes[j]; } } switch (newInfo[i].type) { case BarycentricInfo::NODE: if (cutTopoHelp->getNodeTiles(largestNode[i]).size() != closedTopoHelp->getNodeTiles(largestNode[i]).size()) { isOnEdge[i] = 1; } break; case BarycentricInfo::EDGE: { const vector& cutEdges = cutTopoHelp->getNodeEdges(largestNode[i]); for (int j = 0; j < (int)cutEdges.size(); ++j) { const TopologyEdgeInfo& myInfo = cutEdgeInfo[cutEdges[j]]; if (myInfo.node1 == largestNode[i]) { if (myInfo.node2 == secondNode) { if (myInfo.numTiles == 1)//NOTE: assumes 1 tile means that it is an edge of a cut, could compare to closed instead, but need to search it separately { isOnEdge[i] = 1; } break; } } else { if (myInfo.node1 == secondNode && myInfo.node2 == largestNode[i]) { if (myInfo.numTiles == 1)//ditto { isOnEdge[i] = 1; } break; } } } break; } case BarycentricInfo::TRIANGLE://is never on a cut edge, do nothing break; } } int numNewTris = newSphere->getNumberOfTriangles(); vector triRemove(numNewTris, 0), nodeDisconnect(newNodes, 0);//again, avoid bitpacking #pragma omp CARET_PAR { CaretPointer closedGeoHelp = currentSphereMod.getGeodesicHelper(); CaretPointer cutGeoHelp = cutCurSphere.getGeodesicHelper(); #pragma omp CARET_FOR schedule(dynamic) for (int32_t i = 0; i < newNodes; ++i) { const vector& neighbors = newTopoHelp->getNodeNeighbors(i); if (isOnEdge[i]) { bool hasInteriorNeighbor = false; for (int j = 0; j < (int)neighbors.size(); ++j) { if (!isOnEdge[neighbors[j]]) { hasInteriorNeighbor = true; break; } } if (hasInteriorNeighbor) { for (int j = 0; j < (int)neighbors.size(); ++j) { vector closedPath, cutPath; vector closedPathDists, cutPathDists; closedGeoHelp->getPathToNode(largestNode[i], largestNode[neighbors[j]], closedPath, closedPathDists); cutGeoHelp->getPathToNode(largestNode[i], largestNode[neighbors[j]], cutPath, cutPathDists); if (cutPathDists.size() == 0 || cutPathDists.back() > 2.0f * closedPathDists.back())//maybe this cutoff should be tunable { const vector& myTiles = newTopoHelp->getNodeTiles(i);//find tiles on new mesh that share this edge, remove them for (int k = 0; k < (int)myTiles.size(); ++k) { const int32_t* thisTile = newSphere->getTriangle(myTiles[k]); if (thisTile[0] == neighbors[j] || thisTile[1] == neighbors[j] || thisTile[2] == neighbors[j]) { triRemove[myTiles[k]] = 1; } } } } } else { nodeDisconnect[i] = 1;//disconnect it completely if it has no interior neighbors const vector& nodeTiles = newTopoHelp->getNodeTiles(i); for (int j = 0; j < (int)nodeTiles.size(); ++j) { triRemove[nodeTiles[j]] = 1; } } } else {//interior nodes also have to be checked for crossing the cut, since there may not be a node that falls inside the cut for (int j = 0; j < (int)neighbors.size(); ++j) { vector closedPath, cutPath; vector closedPathDists, cutPathDists; closedGeoHelp->getPathToNode(largestNode[i], largestNode[neighbors[j]], closedPath, closedPathDists); cutGeoHelp->getPathToNode(largestNode[i], largestNode[neighbors[j]], cutPath, cutPathDists);//note: path length of zero means no connection if (cutPathDists.size() == 0 || cutPathDists.back() > 2.0f * closedPathDists.back())//maybe this cutoff should be tunable { const vector& myTiles = newTopoHelp->getNodeTiles(i);//find tiles on new mesh that share this edge, remove them for (int k = 0; k < (int)myTiles.size(); ++k) { const int32_t* thisTile = newSphere->getTriangle(myTiles[k]); if (thisTile[0] == neighbors[j] || thisTile[1] == neighbors[j] || thisTile[2] == neighbors[j]) { triRemove[myTiles[k]] = 1; } } } } } } } int triRemoveCount = 0; for (int i = 0; i < numNewTris; ++i) { if (triRemove[i] != 0) ++triRemoveCount;//parallelizing counting would be silly } surfaceOut->setNumberOfNodesAndTriangles(newNodes, numNewTris - triRemoveCount); surfaceOut->setStructure(cutSurfaceIn->getStructure()); surfaceOut->setSurfaceType(cutSurfaceIn->getSurfaceType()); surfaceOut->setSecondaryType(cutSurfaceIn->getSecondaryType()); int outTri = 0; for (int i = 0; i < numNewTris; ++i) { if (triRemove[i] == 0) { surfaceOut->setTriangle(outTri, newSphere->getTriangle(i)); ++outTri;//means this can't be parallel, but it would also be silly } } CaretAssert(outTri == numNewTris - triRemoveCount); Vector3D origin(0.0f, 0.0f, 0.0f);//where we move disconnected nodes to for (int i = 0; i < newNodes; ++i)//could be parallel, but probably not needed { if (nodeDisconnect[i] != 0) { surfaceOut->setCoordinate(i, origin); } else { Vector3D coord1 = cutSurfaceIn->getCoordinate(newInfo[i].nodes[0]); Vector3D coord2 = cutSurfaceIn->getCoordinate(newInfo[i].nodes[1]); Vector3D coord3 = cutSurfaceIn->getCoordinate(newInfo[i].nodes[2]); Vector3D outCoord = coord1 * newInfo[i].baryWeights[0] + coord2 * newInfo[i].baryWeights[1] + coord3 * newInfo[i].baryWeights[2]; surfaceOut->setCoordinate(i, outCoord); } } } void SurfaceResamplingHelper::computeWeightsAdapBaryArea(const SurfaceFile* currentSphere, const SurfaceFile* newSphere, const float* currentAreas, const float* newAreas, const float* currentRoi) { vector > forward, reverse, reverse_gather; makeBarycentricWeights(currentSphere, newSphere, forward, NULL);//don't use an roi until after we have done area correction, because area correction MUST ignore ROI makeBarycentricWeights(newSphere, currentSphere, reverse, NULL); int numNewNodes = (int)forward.size(), numOldNodes = currentSphere->getNumberOfNodes(); reverse_gather.resize(numNewNodes); for (int oldNode = 0; oldNode < numOldNodes; ++oldNode)//this loop can't be parallelized { for (map::iterator iter = reverse[oldNode].begin(); iter != reverse[oldNode].end(); ++iter)//convert scattering weights to gathering weights { reverse_gather[iter->first][oldNode] = iter->second; } } vector > adap_gather(numNewNodes); #pragma omp CARET_PARFOR schedule(dynamic) for (int newNode = 0; newNode < numNewNodes; ++newNode) { set forwardused;//build set of all nodes used by forward weights (really only 3, but this is a bit cleaner and more generic) for (map::iterator iter = forward[newNode].begin(); iter != forward[newNode].end(); ++iter) { forwardused.insert(iter->first); } bool useforward = true; for (map::iterator iter = reverse_gather[newNode].begin(); iter != reverse_gather[newNode].end(); ++iter) { if (forwardused.find(iter->first) == forwardused.end()) { useforward = false;//if the reverse scatter weights include something the forward gather weights don't, use reverse scatter break; } } if (useforward) { adap_gather[newNode] = forward[newNode]; } else { adap_gather[newNode] = reverse_gather[newNode]; } for (map::iterator iter = adap_gather[newNode].begin(); iter != adap_gather[newNode].end(); ++iter)//begin area correction by multiplying by target node area { iter->second *= newAreas[newNode];//begin the process of area correction by multiplying by gathering node areas } } vector correctionSum(numOldNodes, 0.0f); for (int newNode = 0; newNode < numNewNodes; ++newNode)//this loop is separate because it can't be parallelized { for (map::iterator iter = adap_gather[newNode].begin(); iter != adap_gather[newNode].end(); ++iter) { correctionSum[iter->first] += iter->second;//now, sum the scattering weights to prepare for first normalization } } #pragma omp CARET_PARFOR schedule(dynamic) for (int newNode = 0; newNode < numNewNodes; ++newNode) { double weightsum = 0.0f; vector::iterator> toRemove; for (map::iterator iter = adap_gather[newNode].begin(); iter != adap_gather[newNode].end(); ++iter) { if (currentRoi == NULL || currentRoi[iter->first] > 0.0f) { iter->second *= currentAreas[iter->first] / correctionSum[iter->first];//divide the weights by their scatter sum, then multiply by current areas weightsum += iter->second;//and compute the sum } else { toRemove.push_back(iter); } } int numToRemove = (int)toRemove.size(); for (int i = 0; i < numToRemove; ++i) { adap_gather[newNode].erase(toRemove[i]); } if (weightsum != 0.0f)//this shouldn't happen unless no nodes remain due to roi, or node areas can be zero { for (map::iterator iter = adap_gather[newNode].begin(); iter != adap_gather[newNode].end(); ++iter) { iter->second /= weightsum;//and normalize to a sum of 1 } } } compactWeights(adap_gather);//and compact them into the internal weight storage } void SurfaceResamplingHelper::computeWeightsBarycentric(const SurfaceFile* currentSphere, const SurfaceFile* newSphere, const float* currentRoi) { vector > forward; makeBarycentricWeights(currentSphere, newSphere, forward, currentRoi);//this should ensure they sum to 1, so we are done compactWeights(forward); } bool SurfaceResamplingHelper::checkSphere(const SurfaceFile* surface) { int numNodes = surface->getNumberOfNodes(); CaretAssert(numNodes > 1); int numNodes3 = numNodes * 3; const float* coordData = surface->getCoordinateData(); float mindist = Vector3D(coordData).length(); if (mindist != mindist) throw CaretException("found NaN coordinate in an input sphere"); float maxdist = mindist; const float TOLERANCE = 1.001f; for (int i = 3; i < numNodes3; i += 3) { float tempf = Vector3D(coordData + i).length(); if (tempf != tempf) throw CaretException("found NaN coordinate in an input sphere"); if (tempf < mindist) { mindist = tempf; } if (tempf > maxdist) { maxdist = tempf; } } return (mindist * TOLERANCE > maxdist); } void SurfaceResamplingHelper::changeRadius(const float& radius, const SurfaceFile* input, SurfaceFile* output) { *output = *input; int numNodes = output->getNumberOfNodes(); int numNodes3 = numNodes * 3; vector newCoordData(numNodes3); const float* oldCoordData = output->getCoordinateData(); #pragma omp CARET_PARFOR schedule(dynamic) for (int i = 0; i < numNodes3; i += 3) { Vector3D tempvec1 = oldCoordData + i, tempvec2; tempvec2 = tempvec1 * (radius / tempvec1.length()); newCoordData[i] = tempvec2[0]; newCoordData[i + 1] = tempvec2[1]; newCoordData[i + 2] = tempvec2[2]; } output->setCoordinates(newCoordData.data()); } void SurfaceResamplingHelper::compactWeights(const vector >& weights) { int compactsize = 0; int numNodes = (int)weights.size(); m_weights = CaretArray(numNodes + 1);//include a "one-after" pointer for (int i = 0; i < numNodes; ++i) { compactsize += (int)weights[i].size(); } m_storagechunk = CaretArray(compactsize); int curpos = 0; for (int i = 0; i < numNodes; ++i) { m_weights[i] = m_storagechunk + curpos; for (map::const_iterator iter = weights[i].begin(); iter != weights[i].end(); ++iter) { m_storagechunk[curpos] = WeightElem(iter->first, iter->second); ++curpos; } } CaretAssert(curpos == compactsize); m_weights[numNodes] = m_storagechunk + compactsize; } void SurfaceResamplingHelper::makeBarycentricWeights(const SurfaceFile* from, const SurfaceFile* to, vector >& weights, const float* currentRoi) { int numToNodes = to->getNumberOfNodes(); weights.resize(numToNodes); const float* toCoordData = to->getCoordinateData(); if (currentRoi == NULL) { #pragma omp CARET_PAR { CaretPointer mySignedHelp = from->getSignedDistanceHelper(); #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < numToNodes; ++i) { BarycentricInfo myInfo; mySignedHelp->barycentricWeights(toCoordData + i * 3, myInfo); if (myInfo.baryWeights[0] != 0.0f) weights[i][myInfo.nodes[0]] = myInfo.baryWeights[0]; if (myInfo.baryWeights[1] != 0.0f) weights[i][myInfo.nodes[1]] = myInfo.baryWeights[1]; if (myInfo.baryWeights[2] != 0.0f) weights[i][myInfo.nodes[2]] = myInfo.baryWeights[2]; } } } else { #pragma omp CARET_PAR { CaretPointer mySignedHelp = from->getSignedDistanceHelper(); #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < numToNodes; ++i) { BarycentricInfo myInfo; float weightsum = 0.0f;//there are only 3 weights, so don't bother with double precision mySignedHelp->barycentricWeights(toCoordData + i * 3, myInfo); if (myInfo.baryWeights[0] != 0.0f && currentRoi[myInfo.nodes[0]] > 0.0f) { weights[i][myInfo.nodes[0]] = myInfo.baryWeights[0]; weightsum += myInfo.baryWeights[0]; } if (myInfo.baryWeights[1] != 0.0f && currentRoi[myInfo.nodes[1]] > 0.0f) { weights[i][myInfo.nodes[1]] = myInfo.baryWeights[1]; weightsum += myInfo.baryWeights[1]; } if (myInfo.baryWeights[2] != 0.0f && currentRoi[myInfo.nodes[2]] > 0.0f) { weights[i][myInfo.nodes[2]] = myInfo.baryWeights[2]; weightsum += myInfo.baryWeights[2]; } if (weightsum != 0.0f) { for (map::iterator iter = weights[i].begin(); iter != weights[i].end(); ++iter) { iter->second /= weightsum; } } } } } } connectome-workbench-1.4.2/src/Files/SurfaceResamplingHelper.h000066400000000000000000000072211360521144700244110ustar00rootroot00000000000000#ifndef __SURFACE_RESAMPLING_HELPER_H__ #define __SURFACE_RESAMPLING_HELPER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretPointer.h" #include "SurfaceResamplingMethodEnum.h" #include #include namespace caret { class SurfaceFile; class SurfaceResamplingHelper { struct WeightElem { int node; float weight; WeightElem() { } WeightElem(const int& nodeIn, const float& weightIn) : node(nodeIn), weight(weightIn) { } }; CaretArray m_storagechunk; CaretArray m_weights; static bool checkSphere(const SurfaceFile* surface); static void changeRadius(const float& radius, const SurfaceFile* input, SurfaceFile* output); void computeWeightsAdapBaryArea(const SurfaceFile* currentSphere, const SurfaceFile* newSphere, const float* currentAreas, const float* newAreas, const float* currentRoi); void computeWeightsBarycentric(const SurfaceFile* currentSphere, const SurfaceFile* newSphere, const float* currentRoi); static void makeBarycentricWeights(const SurfaceFile* from, const SurfaceFile* to, std::vector >& weights, const float* currentRoi); void compactWeights(const std::vector >& weights); public: SurfaceResamplingHelper() { } SurfaceResamplingHelper(const SurfaceResamplingMethodEnum::Enum& myMethod, const SurfaceFile* currentSphere, const SurfaceFile* newSphere, const float* currentAreas = NULL, const float* newAreas = NULL, const float* currentRoi = NULL); ///resample real-valued data by means of weights void resampleNormal(const float* input, float* output, const float& invalidVal = 0.0f) const; ///resample 3D coordinate data by means of weights void resample3DCoord(const float* input, float* output) const; ///resample label-like data according to which value gets the largest weight sum void resamplePopular(const int32_t* input, int32_t* output, const int32_t& invalidVal = 0) const; ///resample float data according to what weight is largest void resampleLargest(const float* input, float* output, const float& invalidVal = 0.0f) const; ///resample int data according to what weight is largest void resampleLargest(const int32_t* input, int32_t* output, const int32_t& invalidVal = 0) const; ///get the ROI of nodes that have data within the input ROI void getResampleValidROI(float* output) const; ///resample a cut surface - not something you will apply multiple times, so static method static void resampleCutSurface(const SurfaceFile* cutSurfaceIn, const SurfaceFile* curSphere, const SurfaceFile* newSphere, SurfaceFile* surfaceOut); }; } #endif //__SURFACE_RESAMPLING_HELPER_H__ connectome-workbench-1.4.2/src/Files/SurfaceResamplingMethodEnum.cxx000066400000000000000000000231201360521144700256060ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "SurfaceResamplingMethodEnum.h" #include "CaretAssert.h" using namespace caret; std::vector SurfaceResamplingMethodEnum::enumData; bool SurfaceResamplingMethodEnum::initializedFlag = false; /** * \class caret::SurfaceResamplingMethodEnum * \brief * * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param integerCode * Integer code for this enumerated value. * * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ SurfaceResamplingMethodEnum::SurfaceResamplingMethodEnum(const Enum enumValue, const int32_t integerCode, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCode; this->name = name; this->guiName = guiName; } /** * Destructor. */ SurfaceResamplingMethodEnum::~SurfaceResamplingMethodEnum() { } /** * Initialize the enumerated metadata. */ void SurfaceResamplingMethodEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(SurfaceResamplingMethodEnum(ADAP_BARY_AREA, 0, "ADAP_BARY_AREA", "adaptive barycentric with area correction")); enumData.push_back(SurfaceResamplingMethodEnum(BARYCENTRIC, 1, "BARYCENTRIC", "barycentric")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const SurfaceResamplingMethodEnum* SurfaceResamplingMethodEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const SurfaceResamplingMethodEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString SurfaceResamplingMethodEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const SurfaceResamplingMethodEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ SurfaceResamplingMethodEnum::Enum SurfaceResamplingMethodEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ADAP_BARY_AREA; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SurfaceResamplingMethodEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type SurfaceResamplingMethodEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString SurfaceResamplingMethodEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const SurfaceResamplingMethodEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ SurfaceResamplingMethodEnum::Enum SurfaceResamplingMethodEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ADAP_BARY_AREA; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SurfaceResamplingMethodEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type SurfaceResamplingMethodEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t SurfaceResamplingMethodEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const SurfaceResamplingMethodEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ SurfaceResamplingMethodEnum::Enum SurfaceResamplingMethodEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = ADAP_BARY_AREA; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SurfaceResamplingMethodEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type SurfaceResamplingMethodEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void SurfaceResamplingMethodEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void SurfaceResamplingMethodEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(SurfaceResamplingMethodEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void SurfaceResamplingMethodEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(SurfaceResamplingMethodEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Files/SurfaceResamplingMethodEnum.h000066400000000000000000000054411360521144700252410ustar00rootroot00000000000000#ifndef __SURFACE_RESAMPLING_METHOD_ENUM_H__ #define __SURFACE_RESAMPLING_METHOD_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class SurfaceResamplingMethodEnum { public: /** * Enumerated values. */ enum Enum { ADAP_BARY_AREA, BARYCENTRIC }; ~SurfaceResamplingMethodEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: SurfaceResamplingMethodEnum(const Enum enumValue, const int32_t integerCode, const AString& name, const AString& guiName); static const SurfaceResamplingMethodEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; } // namespace #endif //__SURFACE_RESAMPLING_METHOD_ENUM_H__ connectome-workbench-1.4.2/src/Files/SurfaceTypeEnum.cxx000066400000000000000000000427671360521144700233070ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SURFACE_TYPE_ENUM_DECLARE__ #include "SurfaceTypeEnum.h" #undef __SURFACE_TYPE_ENUM_DECLARE__ using namespace caret; /** * Constructor. * * @param e * An enumerated value. * @param name * Name of enumberated value. */ SurfaceTypeEnum::SurfaceTypeEnum(const Enum e, const AString& name, const AString& guiName, const AString& giftiName) { this->e = e; this->integerCode = SurfaceTypeEnum::integerCodeGenerator++; this->name = name; this->guiName = guiName; this->giftiName = giftiName; } /** * Destructor. */ SurfaceTypeEnum::~SurfaceTypeEnum() { } /** * Initialize the enumerated metadata. */ void SurfaceTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(SurfaceTypeEnum(UNKNOWN, "UNKNOWN", "Unknown", "Unknown")); enumData.push_back(SurfaceTypeEnum(RECONSTRUCTION, "RECONSTRUCTION", "Reconstruction", "Reconstruction")); enumData.push_back(SurfaceTypeEnum(ANATOMICAL, "ANATOMICAL", "Anatomical", "Anatomical")); enumData.push_back(SurfaceTypeEnum(INFLATED, "INFLATED", "Inflated", "Inflated")); enumData.push_back(SurfaceTypeEnum(VERY_INFLATED, "VERY_INFLATED", "VeryInflated", "VeryInflated")); enumData.push_back(SurfaceTypeEnum(SPHERICAL, "SPHERICAL", "Spherical", "Spherical")); enumData.push_back(SurfaceTypeEnum(SEMI_SPHERICAL, "SEMI_SPHERICAL", "SemiSpherical", "SemiSpherical")); enumData.push_back(SurfaceTypeEnum(ELLIPSOID, "ELLIPSOID", "Ellipsoid", "Ellipsoid")); enumData.push_back(SurfaceTypeEnum(FLAT, "FLAT", "Flat", "Flat")); enumData.push_back(SurfaceTypeEnum(HULL, "HULL", "Hull", "Hull")); } /** * Find the data for and enumerated value. * @param e * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const SurfaceTypeEnum* SurfaceTypeEnum::findData(const Enum e) { initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const SurfaceTypeEnum* d = &enumData[i]; if (d->e == e) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString SurfaceTypeEnum::toName(Enum e) { initialize(); const SurfaceTypeEnum* st = findData(e); return st->name; } /** * Get an enumerated value corresponding to its name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ SurfaceTypeEnum::Enum SurfaceTypeEnum::fromName(const AString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = UNKNOWN; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SurfaceTypeEnum& d = *iter; if (d.name == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } /** * Get a GUI string representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString SurfaceTypeEnum::toGuiName(Enum e) { initialize(); const SurfaceTypeEnum* st = findData(e); return st->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ SurfaceTypeEnum::Enum SurfaceTypeEnum::fromGuiName(const AString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = UNKNOWN; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SurfaceTypeEnum& d = *iter; if (d.guiName == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t SurfaceTypeEnum::toIntegerCode(Enum e) { initialize(); const SurfaceTypeEnum* ndt = findData(e); return ndt->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ SurfaceTypeEnum::Enum SurfaceTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = UNKNOWN; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SurfaceTypeEnum& ndt = *iter; if (ndt.integerCode == integerCode) { e = ndt.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } /** * Get a GIFTI Name string representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString SurfaceTypeEnum::toGiftiName(Enum e) { initialize(); const SurfaceTypeEnum* st = findData(e); return st->giftiName; } /** * Get an enumerated value corresponding to its GIFTI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ SurfaceTypeEnum::Enum SurfaceTypeEnum::fromGiftiName(const AString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = UNKNOWN; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SurfaceTypeEnum& d = *iter; if (d.giftiName == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void SurfaceTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->e); } } /** * Get all of the enumerated type values EXCEPT FLAT. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param enumsOut * A vector that is OUTPUT containing all of the enumerated values EXCEPT FLAT */ void SurfaceTypeEnum::getAllEnumsExceptFlat(std::vector& enumsOut) { std::vector allEnums; SurfaceTypeEnum::getAllEnums(allEnums); enumsOut.clear(); for (std::vector::iterator iter = allEnums.begin(); iter != allEnums.end(); iter++) { const SurfaceTypeEnum::Enum st = *iter; if (st != FLAT) { enumsOut.push_back(st); } } } /** * Get the enumerated type values that are three-dimensional in shape * but still have an anatomical-shaped appearance. * * @param anatomicalEnumsOut * A vector that is OUTPUT containing the anatomically shaped enums. */ void SurfaceTypeEnum::getAllAnatomicallyShapedEnums(std::vector& anatomicalEnumsOut) { anatomicalEnumsOut.clear(); anatomicalEnumsOut.push_back(ANATOMICAL); anatomicalEnumsOut.push_back(INFLATED); anatomicalEnumsOut.push_back(VERY_INFLATED); anatomicalEnumsOut.push_back(RECONSTRUCTION); } /** * Constructor. * * @param e * An enumerated value. * @param name * Name of enumberated value. */ SecondarySurfaceTypeEnum::SecondarySurfaceTypeEnum(const Enum e, const AString& name, const AString& guiName, const AString& giftiName) { this->e = e; this->integerCode = SecondarySurfaceTypeEnum::integerCodeGenerator++; this->name = name; this->guiName = guiName; this->giftiName = giftiName; } /** * Initialize the enumerated metadata. */ void SecondarySurfaceTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(SecondarySurfaceTypeEnum(INVALID, "INVALID", "Invalid", "Invalid")); enumData.push_back(SecondarySurfaceTypeEnum(GRAY_WHITE, "GRAY_WHITE", "GrayWhite", "GrayWhite")); enumData.push_back(SecondarySurfaceTypeEnum(MIDTHICKNESS, "MIDTHICKNESS", "Midthickness",//I'm assuming that middle capital T is not desired in the gui "MidThickness"));//but it is used in the data format for caret6 enumData.push_back(SecondarySurfaceTypeEnum(PIAL, "PIAL", "Pial", "Pial")); } /** * Find the data for and enumerated value. * @param e * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const SecondarySurfaceTypeEnum* SecondarySurfaceTypeEnum::findData(const Enum e) { initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const SecondarySurfaceTypeEnum* d = &enumData[i]; if (d->e == e) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString SecondarySurfaceTypeEnum::toName(Enum e) { initialize(); const SecondarySurfaceTypeEnum* st = findData(e); return st->name; } /** * Get an enumerated value corresponding to its name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ SecondarySurfaceTypeEnum::Enum SecondarySurfaceTypeEnum::fromName(const AString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = INVALID; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SecondarySurfaceTypeEnum& d = *iter; if (d.name == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } /** * Get a GUI string representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString SecondarySurfaceTypeEnum::toGuiName(Enum e) { initialize(); const SecondarySurfaceTypeEnum* st = findData(e); return st->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ SecondarySurfaceTypeEnum::Enum SecondarySurfaceTypeEnum::fromGuiName(const AString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = INVALID; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SecondarySurfaceTypeEnum& d = *iter; if (d.guiName == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t SecondarySurfaceTypeEnum::toIntegerCode(Enum e) { initialize(); const SecondarySurfaceTypeEnum* ndt = findData(e); return ndt->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ SecondarySurfaceTypeEnum::Enum SecondarySurfaceTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = INVALID; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SecondarySurfaceTypeEnum& ndt = *iter; if (ndt.integerCode == integerCode) { e = ndt.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } /** * Get a GIFTI Name string representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString SecondarySurfaceTypeEnum::toGiftiName(Enum e) { initialize(); const SecondarySurfaceTypeEnum* st = findData(e); return st->giftiName; } /** * Get an enumerated value corresponding to its GIFTI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ SecondarySurfaceTypeEnum::Enum SecondarySurfaceTypeEnum::fromGiftiName(const AString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = INVALID; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const SecondarySurfaceTypeEnum& d = *iter; if (d.giftiName == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void SecondarySurfaceTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->e); } } connectome-workbench-1.4.2/src/Files/SurfaceTypeEnum.h000066400000000000000000000106141360521144700227160ustar00rootroot00000000000000#ifndef __SURFACE_TYPE_ENUM__H_ #define __SURFACE_TYPE_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { /** * Enumerated type for */ class SurfaceTypeEnum { public: /** * Enumerated values. */ enum Enum { /** UNKNOWN */ UNKNOWN, /** Reconstruction (raw) */ RECONSTRUCTION, /** Anatomical */ ANATOMICAL, /** Inflated */ INFLATED, /** Very Inflated */ VERY_INFLATED, /** Spherical */ SPHERICAL, /** Semi-Spherical (CMW) */ SEMI_SPHERICAL, /** Ellipsoid */ ELLIPSOID, /** Flat */ FLAT, /** Hull */ HULL }; ~SurfaceTypeEnum(); static AString toName(Enum e); static Enum fromName(const AString& s, bool* isValidOut); static AString toGuiName(Enum e); static Enum fromGuiName(const AString& s, bool* isValidOut); static AString toGiftiName(Enum e); static Enum fromGiftiName(const AString& s, bool* isValidOut); static int32_t toIntegerCode(Enum e); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllEnumsExceptFlat(std::vector& enumsOut); static void getAllAnatomicallyShapedEnums(std::vector& threeDimEnums); private: SurfaceTypeEnum(const Enum e, const AString& name, const AString& guiName, const AString& giftiName); static const SurfaceTypeEnum* findData(const Enum e); static std::vector enumData; static void initialize(); static bool initializedFlag; static int32_t integerCodeGenerator; Enum e; int32_t integerCode; AString name; AString guiName; AString giftiName; }; class SecondarySurfaceTypeEnum { public: enum Enum { INVALID, GRAY_WHITE, MIDTHICKNESS, PIAL }; static AString toName(Enum e); static Enum fromName(const AString& s, bool* isValidOut); static AString toGuiName(Enum e); static Enum fromGuiName(const AString& s, bool* isValidOut); static AString toGiftiName(Enum e); static Enum fromGiftiName(const AString& s, bool* isValidOut); static int32_t toIntegerCode(Enum e); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); private: SecondarySurfaceTypeEnum(const Enum e, const AString& name, const AString& guiName, const AString& giftiName); static const SecondarySurfaceTypeEnum* findData(const Enum e); static std::vector enumData; static void initialize(); static bool initializedFlag; static int32_t integerCodeGenerator; Enum e; int32_t integerCode; AString name; AString guiName; AString giftiName; }; #ifdef __SURFACE_TYPE_ENUM_DECLARE__ std::vector SurfaceTypeEnum::enumData; bool SurfaceTypeEnum::initializedFlag = false; int32_t SurfaceTypeEnum::integerCodeGenerator = 0; std::vector SecondarySurfaceTypeEnum::enumData; bool SecondarySurfaceTypeEnum::initializedFlag = false; int32_t SecondarySurfaceTypeEnum::integerCodeGenerator = 0; #endif // __SURFACE_TYPE_ENUM_DECLARE__ } // namespace #endif //__SURFACE_TYPE_ENUM__H_ connectome-workbench-1.4.2/src/Files/TextFile.cxx000066400000000000000000000067431360521144700217460ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretLogger.h" #include "DataFileException.h" #include "TextFile.h" using namespace caret; /** * Constructor. */ TextFile::TextFile() : DataFile() { this->text = ""; } /** * Destructor. */ TextFile::~TextFile() { this->text = ""; } /** * Clear the contents of this file. */ void TextFile::clear() { DataFile::clear(); this->text = ""; } /** * Is this file empty? * * @return true if file is empty, else false. */ bool TextFile::isEmpty() const { return this->text.isEmpty(); } /** * Read the file. * * @param filename * Name of file to read. * * @throws DataFileException * If there is an error reading the file. */ void TextFile::readFile(const AString& filename) { clear(); checkFileReadability(filename); QFile file(filename); if (file.open(QFile::ReadOnly) == false) { throw DataFileException(filename, "Unable to open for reading."); } QTextStream textStream(&file); this->text = textStream.readAll(); file.close(); this->setFileName(filename); this->clearModified(); } /** * Write the file. * * @param filename * Name of file to read. * * @throws DataFileException * If there is an error writing the file. */ void TextFile::writeFile(const AString& filename) { checkFileWritability(filename); QFile file(filename); if (file.open(QFile::WriteOnly) == false) { throw DataFileException(filename, "Unable to open for writing."); } QTextStream textStream(&file); textStream << this->text; file.close(); this->setFileName(filename); this->clearModified(); } /** * Get information about this file's contents. * @return * Information about the file's contents. */ AString TextFile::toString() const { return "TextFile"; } /** * Get the file's text. * * @return The file's text. */ AString TextFile::getText() const { return this->text; } /** * Replace the file's text. * * @param text * Replaces text in the file. */ void TextFile::replaceText(const AString& text) { if (text != this->text) { this->text = text; this->setModified(); } } /** * Add to the file's text. * * @param text * Text added. */ void TextFile::addText(const AString& text) { this->text += text; this->setModified(); } /** * Add to the file's text and then add * a newline character. * * @param text * Text added. */ void TextFile::addLine(const AString& text) { this->text += text; this->text += "\n"; this->setModified(); } connectome-workbench-1.4.2/src/Files/TextFile.h000066400000000000000000000034211360521144700213610ustar00rootroot00000000000000#ifndef __TEXT_FILE_H__ #define __TEXT_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "DataFile.h" namespace caret { /** * A simple text file. */ class TextFile : public DataFile { public: TextFile(); virtual ~TextFile(); private: TextFile(const TextFile&); TextFile& operator=(const TextFile&); public: virtual void clear(); virtual bool isEmpty() const; virtual void readFile(const AString& filename); virtual void writeFile(const AString& filename); virtual AString toString() const; AString getText() const; void replaceText(const AString& text); void addText(const AString& text); void addLine(const AString& text); private: AString text; }; } // namespace #endif // __TEXT_FILE_H__ connectome-workbench-1.4.2/src/Files/TopologyHelper.cxx000066400000000000000000000361671360521144700232010ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "SurfaceFile.h" #include "TopologyHelper.h" #include "CaretAssert.h" #include using namespace caret; using namespace std; TopologyHelperBase::TopologyHelperBase(const SurfaceFile* surfIn, bool sortFlag) { m_numNodes = surfIn->getNumberOfNodes(); m_numTris = surfIn->getNumberOfTriangles(); m_nodeInfo.resize(m_numNodes); m_boundaryCount.resize(m_numNodes); m_tileInfo.resize(m_numTris); vector tempEdgeInfo; tempEdgeInfo.reserve(m_numTris * 3);//worst case, to prevent reallocs, we will copy it over later to the exact right size for (int32_t i = 0; i < m_numNodes; ++i) {//preallocate what should be enough size for most nodes on most surfaces, including freesurfer m_nodeInfo[i].m_edges.reserve(8); m_nodeInfo[i].m_neighbors.reserve(8); m_nodeInfo[i].m_tiles.reserve(8); m_nodeInfo[i].m_whichVertex.reserve(8); } for (int32_t i = 0; i < m_numTris; ++i) { const int32_t* thisTri = surfIn->getTriangle(i); m_nodeInfo[thisTri[0]].addTileInfo(i, 0); m_nodeInfo[thisTri[1]].addTileInfo(i, 1); m_nodeInfo[thisTri[2]].addTileInfo(i, 2); }//node tiles complete, now we can sweep over nodes instead of triangles, making it easier to build node info m_maxNeigh = -1; m_maxTiles = -1; CaretArray scratch(m_numNodes, -1);//mark array for added neighbors for (int32_t i = 0; i < m_numNodes; ++i) { vector& tileList = m_nodeInfo[i].m_tiles; vector& vertexList = m_nodeInfo[i].m_whichVertex; int neighTiles = (int)tileList.size(); if (neighTiles > m_maxTiles) { m_maxTiles = neighTiles; } for (int j = 0; j < neighTiles; ++j) { int32_t myTile = tileList[j]; const int32_t* thisTri = surfIn->getTriangle(myTile); int32_t myVert = vertexList[j]; switch (myVert) { case 0: if (thisTri[1] > i) processTileNeighbor(tempEdgeInfo, scratch, i, thisTri[1], thisTri[2], myTile, 0, false);//boolean signifies if root, neighbor is same ordering as the cycle of tile nodes if (thisTri[2] > i) processTileNeighbor(tempEdgeInfo, scratch, i, thisTri[2], thisTri[1], myTile, 2, true); break;//the if statement is a trick: processTileNeighbor adds neighbor to both nodes, so by checking that root is less, it does every edge exactly once case 1://this allows edge info building in a linear pass if (thisTri[2] > i) processTileNeighbor(tempEdgeInfo, scratch, i, thisTri[2], thisTri[0], myTile, 1, false); if (thisTri[0] > i) processTileNeighbor(tempEdgeInfo, scratch, i, thisTri[0], thisTri[2], myTile, 0, true); break; case 2: if (thisTri[0] > i) processTileNeighbor(tempEdgeInfo, scratch, i, thisTri[0], thisTri[1], myTile, 2, false); if (thisTri[1] > i) processTileNeighbor(tempEdgeInfo, scratch, i, thisTri[1], thisTri[0], myTile, 1, true); } } vector& myNeighList = m_nodeInfo[i].m_neighbors; vector& myEdgeList = m_nodeInfo[i].m_edges; int numNeigh = (int)myNeighList.size(); if (numNeigh > m_maxNeigh) { m_maxNeigh = numNeigh; } m_boundaryCount[i] = 0; for (int j = 0; j < numNeigh; ++j) { if (tempEdgeInfo[myEdgeList[j]].numTiles == 1) ++m_boundaryCount[i]; scratch[myNeighList[j]] = -1;//NOTE: -1 as sentinel because 0 is a valid edge number } }//neighbor, edge and tile info done m_edgeInfo = tempEdgeInfo;//copy edge info into member to get allocation correct CaretArray scratch2(m_numTris, -1); if (sortFlag) { for (int32_t i = 0; i < m_numNodes; ++i) { sortNeighbors(surfIn, i, scratch, scratch2);//not a member function of node info object because I need m_edgeInfo and m_nodeInfo } m_neighborsSorted = true; } else { m_neighborsSorted = false; } } //1) check mark array // a) if marked, find edge, add triangle to edge // b) if unmarked, make edge from triangle, add neighbor, add reverse neighbor void TopologyHelperBase::processTileNeighbor(vector& tempEdgeInfo, CaretArray& scratch, const int32_t& root, const int32_t& neighbor, const int32_t& thirdNode, const int32_t& tile, const int32_t& tileEdge, const bool& reversed) { if (scratch[neighbor] == -1) { TopologyEdgeInfo tempInfo(root, neighbor, thirdNode, tile, tileEdge, reversed); int32_t myEdge = (int32_t)tempEdgeInfo.size(); tempEdgeInfo.push_back(tempInfo); m_nodeInfo[root].addNeighborInfo(neighbor, myEdge); m_nodeInfo[neighbor].addNeighborInfo(root, myEdge); scratch[neighbor] = myEdge;//use mark array both as "have this neighbor" AND "this is this neighbor's edge" m_tileInfo[tile].edges[tileEdge].edge = myEdge; } else { tempEdgeInfo[scratch[neighbor]].addTile(thirdNode, tile, tileEdge, reversed); m_tileInfo[tile].edges[tileEdge].edge = scratch[neighbor]; } m_tileInfo[tile].edges[tileEdge].reversed = reversed; } void TopologyHelperBase::sortNeighbors(const SurfaceFile* mySurf, const int32_t& node, CaretArray& nodeScratch, CaretArray& tileScratch) { TopologyHelperBase::NodeInfo& myNodeInfo = m_nodeInfo[node]; if (myNodeInfo.m_neighbors.size() == 0) return; int firstIndex = 0, numNeigh = (int)myNodeInfo.m_neighbors.size(); for (int i = 0; i < numNeigh; ++i) { int32_t thisEdge = myNodeInfo.m_edges[i]; if (m_edgeInfo[thisEdge].numTiles == 1)//there cannot be edge info with zero tiles, we are looking for the edge of a cut { firstIndex = i; if ((m_edgeInfo[thisEdge].node1 == node) != m_edgeInfo[thisEdge].tiles[0].edgeReversed)//this checks if the edge from center to neighbor is oriented with the tile {//since edge info is always node1 < node2, we have to xor (this center is node1) and (this edge is reversed compared to its only triangle) break;//found one }//the reason the break is in the additional if, is so that if we don't find a correctly oriented edge, we still find an edge if one exists } } vector tempNeigh; vector tempEdges, tempTiles;//why not sort everything? verts get regenerated in place int numTiles = myNodeInfo.m_tiles.size(); tempNeigh.reserve(numNeigh); tempEdges.reserve(numNeigh); tempTiles.reserve(numTiles); int32_t nextNode = myNodeInfo.m_neighbors[firstIndex]; int32_t nextEdge = myNodeInfo.m_edges[firstIndex]; int32_t nextTile; bool foundNext = true; int tileToUse = 0; if (m_edgeInfo[nextEdge].numTiles > 1) { if (m_edgeInfo[nextEdge].tiles[0].edgeReversed != (m_edgeInfo[nextEdge].node1 == nextNode)) { tileToUse = 1; } } do { nextTile = m_edgeInfo[nextEdge].tiles[tileToUse].tile; int32_t node3 = m_edgeInfo[nextEdge].tiles[tileToUse].node3; nextEdge = -1; for (int i = 0; i < 3; ++i) { if (m_edgeInfo[m_tileInfo[nextTile].edges[i].edge].node1 == node) { if (m_edgeInfo[m_tileInfo[nextTile].edges[i].edge].node2 == node3) { nextEdge = m_tileInfo[nextTile].edges[i].edge; break; } } else { if (m_edgeInfo[m_tileInfo[nextTile].edges[i].edge].node1 == node3 && m_edgeInfo[m_tileInfo[nextTile].edges[i].edge].node2 == node) { nextEdge = m_tileInfo[nextTile].edges[i].edge; break; } } } CaretAssert(nextEdge != -1); tempNeigh.push_back(nextNode); tempEdges.push_back(nextEdge); nodeScratch[nextNode] = 0;//remember, -1 is "unused" tempTiles.push_back(nextTile); nextNode = node3;//update the next node we are going to use tileScratch[nextTile] = 0; tileToUse = 0; if (tileScratch[m_edgeInfo[nextEdge].tiles[0].tile] == 0 && m_edgeInfo[nextEdge].numTiles > 1) { tileToUse = 1; } if (tileScratch[m_edgeInfo[nextEdge].tiles[tileToUse].tile] == 0) { foundNext = false; } } while (foundNext); for (int i = 0; i < numNeigh; ++i)//clean up scratch array, find any neighbors that are gap-separated or on third+ tile of an edge { if (nodeScratch[myNodeInfo.m_neighbors[i]] == 0) { nodeScratch[myNodeInfo.m_neighbors[i]] = -1; } else { tempNeigh.push_back(myNodeInfo.m_neighbors[i]); tempEdges.push_back(myNodeInfo.m_edges[i]); } } CaretAssert(tempNeigh.size() == myNodeInfo.m_neighbors.size());//check against original size CaretAssert(tempEdges.size() == myNodeInfo.m_edges.size()); myNodeInfo.m_neighbors = tempNeigh;//copy over myNodeInfo.m_edges = tempEdges; for (int i = 0; i < numTiles; ++i)//and find similar tiles { if (tileScratch[myNodeInfo.m_tiles[i]] == 0) { tileScratch[myNodeInfo.m_tiles[i]] = -1; } else { tempTiles.push_back(myNodeInfo.m_tiles[i]); } } CaretAssert(tempTiles.size() == myNodeInfo.m_tiles.size()); myNodeInfo.m_tiles = tempTiles; for (int i = 0; i < numTiles; ++i)//finally, regenerate verts { const int32_t* myTri = mySurf->getTriangle(myNodeInfo.m_tiles[i]); if (myTri[0] == node) { myNodeInfo.m_whichVertex[i] = 0; } else if (myTri[1] == node) { myNodeInfo.m_whichVertex[i] = 1; } else { myNodeInfo.m_whichVertex[i] = 2; } } } TopologyHelper::TopologyHelper(CaretPointer myBase) : m_base(myBase), m_nodeInfo(myBase->m_nodeInfo), m_edgeInfo(myBase->m_edgeInfo), m_tileInfo(myBase->m_tileInfo), m_boundaryCount(myBase->m_boundaryCount) {//pointer is by-value so that it makes a private copy that can't be pointed elsewhere during this constructor m_maxNeigh = m_base->m_maxNeigh; m_neighborsSorted = m_base->m_neighborsSorted; m_numNodes = m_base->m_numNodes; } const vector& TopologyHelper::getNumberOfBoundaryEdgesForAllNodes() const { return m_boundaryCount; } int32_t TopologyHelper::getMaximumNumberOfNeighbors() const { return m_maxNeigh; } bool TopologyHelper::getNodeHasNeighbors(const int32_t nodeNum) const { CaretAssertVectorIndex(m_nodeInfo, nodeNum); return m_nodeInfo[nodeNum].m_neighbors.size() != 0; } const vector& TopologyHelper::getNodeNeighbors(const int32_t nodeNum) const { CaretAssertVectorIndex(m_nodeInfo, nodeNum); return m_nodeInfo[nodeNum].m_neighbors; } const int32_t* TopologyHelper::getNodeNeighbors(const int32_t nodeNum, int32_t& numNeighborsOut) const { CaretAssertVectorIndex(m_nodeInfo, nodeNum); numNeighborsOut = (int32_t)m_nodeInfo[nodeNum].m_neighbors.size(); return m_nodeInfo[nodeNum].m_neighbors.data(); } int32_t TopologyHelper::getNodeNumberOfNeighbors(const int32_t nodeNum) const { CaretAssertVectorIndex(m_nodeInfo, nodeNum); return m_nodeInfo[nodeNum].m_neighbors.size(); } const vector& TopologyHelper::getNodeTiles(const int32_t nodeNum) const { CaretAssertVectorIndex(m_nodeInfo, nodeNum); return m_nodeInfo[nodeNum].m_tiles; } const int32_t* TopologyHelper::getNodeTiles(const int32_t nodeNum, int32_t& numTilesOut) const { CaretAssertVectorIndex(m_nodeInfo, nodeNum); numTilesOut = (int32_t)m_nodeInfo[nodeNum].m_tiles.size(); return m_nodeInfo[nodeNum].m_tiles.data(); } const vector& TopologyHelper::getNodeEdges(const int32_t nodeNum) const { CaretAssertVectorIndex(m_nodeInfo, nodeNum); return m_nodeInfo[nodeNum].m_edges; } void TopologyHelper::checkArrays() const { if (m_markNodes.size() != m_numNodes) { m_markNodes = CaretArray(m_numNodes, 0); m_nodelist[0] = CaretArray(m_numNodes); m_nodelist[1] = CaretArray(m_numNodes); } } void TopologyHelper::getNodeNeighborsToDepth(const int32_t nodeNum, const int32_t depth, vector& neighborsOut) const { if (depth < 2) { neighborsOut = getNodeNeighbors(nodeNum); return; } int32_t expected = (7 * depth * (depth + 1)) / 2; if (expected > m_numNodes / 2) expected = m_numNodes / 2; neighborsOut.clear(); neighborsOut.reserve(expected); CaretArray* curlist = &(m_nodelist[0]), *nextlist = &(m_nodelist[1]), *templist;//using raw pointers instead of CaretArray::operator= because this is single threaded int32_t curNum = 1, nextNum = 0;//curnum gets initialized to 1 because it starts with the root node CaretMutexLocker locked(&m_usingMarkNodes);//lock before possibly constructing this object's scratch space checkArrays(); m_markNodes[nodeNum] = 1; (*curlist)[0] = nodeNum;//just use iterative, because depth-first recursive does unneeded work, and has very little reason to ever be faster for (int32_t curdepth = 0; curdepth < depth; ++curdepth) { for (int32_t i = 0; i < curNum; ++i) { const vector& nodeNeighbors = m_nodeInfo[(*curlist)[i]].m_neighbors; int numNeigh = (int)nodeNeighbors.size(); for (int j = 0; j < numNeigh; ++j) { int32_t thisNode = nodeNeighbors[j]; if (m_markNodes[thisNode] == 0) { m_markNodes[thisNode] = 1; (*nextlist)[nextNum] = thisNode; ++nextNum; neighborsOut.push_back(thisNode); } } } templist = curlist; curlist = nextlist; nextlist = templist; curNum = nextNum; nextNum = 0;//we restart the list by zeroing the count, and just overwrite the old values } m_markNodes[nodeNum] = 0;//clean up the mark array int32_t numNeigh = (int32_t)neighborsOut.size(); for (int32_t i = 0; i < numNeigh; ++i) { m_markNodes[neighborsOut[i]] = 0; } } connectome-workbench-1.4.2/src/Files/TopologyHelper.h000066400000000000000000000201641360521144700226140ustar00rootroot00000000000000#ifndef __TOPOLOGY_HELPER_H__ #define __TOPOLOGY_HELPER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretPointer.h" namespace caret { class SurfaceFile; struct TopologyEdgeInfo { struct Tile { int32_t tile; int32_t node3; int32_t whichEdge;//whether this is edge 0 (0-1), 1 (1-2), or 2 (2-0) bool edgeReversed;//whether ordering the nodes as 1, 2, 3 results in a flipped tile compared to topology }; int32_t node1, node2; int32_t numTiles; Tile tiles[2];//should be so amazingly rare (and inherently bad) for an edge to have 3 triangles that it isn't worth making this a vector TopologyEdgeInfo()//also, a vector would have poor data locality, each edge would have its tiles list in an unrelated spot to the previous edge { numTiles = 0; } TopologyEdgeInfo(const int32_t& firstNode, const int32_t& secondNode, const int32_t& thirdNode, const int32_t& tile, const int32_t& whichEdge, const bool& reversed) { node1 = firstNode;//always called with firstNode less than secondNode, so don't need to swap node2 = secondNode; tiles[0].tile = tile; tiles[0].node3 = thirdNode; tiles[0].edgeReversed = reversed; tiles[0].whichEdge = whichEdge; numTiles = 1; } void addTile(const int32_t& thirdNode, const int32_t& tile, const int32_t& whichEdge, const bool& reversed) { if (numTiles < 2) { tiles[numTiles].tile = tile; tiles[numTiles].node3 = thirdNode; tiles[numTiles].edgeReversed = reversed; tiles[numTiles].whichEdge = whichEdge; } ++numTiles; } }; struct TopologyTileInfo { struct Edge { int32_t edge; bool reversed; }; Edge edges[3]; }; class TopologyHelperBase { TopologyHelperBase();//prevent default, copy, assign TopologyHelperBase(const TopologyHelperBase&); TopologyHelperBase& operator=(const TopologyHelperBase&); void processTileNeighbor(std::vector& tempEdgeInfo, CaretArray& scratch, const int32_t& root, const int32_t& neighbor, const int32_t& thirdNode, const int32_t& tile, const int32_t& tileEdge, const bool& reversed); void sortNeighbors(const SurfaceFile* mySurf, const int32_t& node, CaretArray& nodeScratch, CaretArray& tileScratch); struct NodeInfo { std::vector m_neighbors; std::vector m_edges;//index into the topology edges vector, matched with neighbors std::vector m_tiles; std::vector m_whichVertex;//stores which tile vertex this node is, matched to m_tiles void addTileInfo(int32_t tile, int32_t vertexNum)//don't take edge info yet because it is built after neighbor info { m_tiles.push_back(tile); m_whichVertex.push_back(vertexNum); } void addNeighborInfo(int32_t neighbor, int32_t edge)//after we have tile info, we then generate neighbor info with the help of a mark array { m_neighbors.push_back(neighbor); m_edges.push_back(edge); } }; std::vector m_nodeInfo; std::vector m_edgeInfo; std::vector m_tileInfo; std::vector m_boundaryCount; int32_t m_maxNeigh, m_maxTiles, m_numNodes, m_numTris; bool m_neighborsSorted; public: TopologyHelperBase(const SurfaceFile* surfIn, bool sortNeighbors = false); bool isNodeInfoSorted() const { return m_neighborsSorted; } friend class TopologyHelper; }; /// This class is used to determine the node neighbors and edges for a Topology File. class TopologyHelper { CaretPointer m_base; mutable CaretArray m_markNodes, m_nodelist[2];//persistent, never cleared, only initialized once, saving bazillions of nanoseconds mutable CaretMutex m_usingMarkNodes; bool m_neighborsSorted; int32_t m_numNodes, m_maxNeigh; const std::vector& m_nodeInfo;//references for convenience instead of using the m_base pointer const std::vector& m_edgeInfo; const std::vector& m_tileInfo; const std::vector& m_boundaryCount; void checkArrays() const;//used to make the thread arrays for neighbors to depth lazy (not allocated until first needed) TopologyHelper();//prevent default, copy, assign, prolly not needed since there are reference members TopologyHelper(const TopologyHelper& right); TopologyHelper& operator=(const TopologyHelper& right); public: /// Constructor for use with a TopologyHelperBase (the only way, for now) TopologyHelper(CaretPointer myBase); /// Get the number of nodes int32_t getNumberOfNodes() const { return m_numNodes; } /// See if a node has neighbors bool getNodeHasNeighbors(const int32_t nodeNum) const; /// Get the number of neighbors for a node int32_t getNodeNumberOfNeighbors(const int32_t nodeNum) const; /// Get the neighbors of a node const std::vector& getNodeNeighbors(const int32_t nodeNum) const; /// Get the neighboring nodes for a node. Returns a pointer to an array /// containing the neighbors. const int32_t* getNodeNeighbors(const int32_t nodeNum, int32_t& numNeighborsOut) const; ///get the edges of a node const std::vector& getNodeEdges(const int32_t nodeNum) const; /// Get the neighbors to a specified depth void getNodeNeighborsToDepth(const int32_t nodeNum, const int32_t depth, std::vector& neighborsOut) const; /// Get the number of boundary edges used by node const std::vector& getNumberOfBoundaryEdgesForAllNodes() const; /// Get the maximum number of neighbors of all nodes int32_t getMaximumNumberOfNeighbors() const; /// Get the tiles used by a node const std::vector& getNodeTiles(const int32_t nodeNum) const; /// Get the tiles for a node. Returns a pointer to an array /// containing the tiles. const int32_t* getNodeTiles(const int32_t nodeNum, int32_t& numTilesOut) const; /// get node sorted info validity bool isNodeInfoSorted() const { return m_neighborsSorted; } /// Get the edge information const std::vector& getEdgeInfo() const { return m_edgeInfo; } /// Get the tile information const std::vector& getTileInfo() const { return m_tileInfo; } /// Get the number of edges int32_t getNumberOfEdges() const { return m_edgeInfo.size(); } }; } #endif //__TOPOLOGY_HELPER_H__ connectome-workbench-1.4.2/src/Files/VolumeDynamicConnectivityFile.cxx000066400000000000000000000555531360521144700262000ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __VOLUME_DYNN_CONN_FILE_DECLARE__ #include "VolumeDynamicConnectivityFile.h" #undef __VOLUME_DYNN_CONN_FILE_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "ConnectivityCorrelation.h" #include "ConnectivityDataLoaded.h" #include "DataFileException.h" #include "FileInformation.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::VolumeDynamicConnectivityFile * \brief Dynamic connectivity volume file * \ingroup Files */ /** * Constructor. */ VolumeDynamicConnectivityFile::VolumeDynamicConnectivityFile(const VolumeFile* parentVolumeFile) : VolumeFile(DataFileTypeEnum::VOLUME_DYNAMIC), m_parentVolumeFile(parentVolumeFile) { CaretAssert(m_parentVolumeFile); m_connectivityDataLoaded.reset(new ConnectivityDataLoaded()); m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); m_sceneAssistant->add("m_dataLoadingEnabledFlag", &m_dataLoadingEnabledFlag); m_sceneAssistant->add("m_enabledAsLayer", &m_enabledAsLayer); m_sceneAssistant->add("m_connectivityDataLoaded", "ConnectivityDataLoaded", m_connectivityDataLoaded.get()); } /** * Destructor. */ VolumeDynamicConnectivityFile::~VolumeDynamicConnectivityFile() { } /** * Clear the file. */ void VolumeDynamicConnectivityFile::clear() { VolumeFile::clear(); clearPrivateData(); } /** * Clear the file. */ void VolumeDynamicConnectivityFile::clearPrivateData() { m_voxelData = NULL; m_numberOfVoxels = 0; m_validDataFlag = false; m_enabledAsLayer = false; m_connectivityCorrelation.reset(); m_connectivityDataLoaded->reset(); } /** * @return Pointer to the information about last loaded connectivity data. */ const ConnectivityDataLoaded* VolumeDynamicConnectivityFile::getConnectivityDataLoaded() const { return m_connectivityDataLoaded.get(); } /** * @return True if enabled as a layer. */ bool VolumeDynamicConnectivityFile::isEnabledAsLayer() const { return m_enabledAsLayer; } /** * Set enabled as a layer. * * @param True if enabled as a layer. */ void VolumeDynamicConnectivityFile::setEnabledAsLayer(const bool enabled) { m_enabledAsLayer = enabled; } /** * @return True if data loading enabled. */ bool VolumeDynamicConnectivityFile::isDataLoadingEnabled() const { return m_dataLoadingEnabledFlag; } /** * Set data loading enabled. * * @param True if data loading enabled. */ void VolumeDynamicConnectivityFile::setDataLoadingEnabled(const bool enabled) { m_dataLoadingEnabledFlag = enabled; } /** * Initialize the file using information from parent volume file */ void VolumeDynamicConnectivityFile::initializeFile() { clearPrivateData(); CaretAssert(m_parentVolumeFile); const int64_t numberOfFrames(1); const int32_t numberOfComponents(1); reinitialize(m_parentVolumeFile->getVolumeSpace(), numberOfFrames, numberOfComponents, SubvolumeAttributes::FUNCTIONAL, m_parentVolumeFile->m_header); AString path, nameNoExt, ext; FileInformation fileInfo(m_parentVolumeFile->getFileName()); fileInfo.getFileComponents(path, nameNoExt, ext); setFileName(FileInformation::assembleFileComponents(path, nameNoExt, DataFileTypeEnum::toFileExtension(DataFileTypeEnum::VOLUME_DYNAMIC))); std::vector dims; getDimensions(dims); m_numberOfVoxels = (dims[0] * dims[1] * dims[2]); m_dimI = dims[0]; m_dimJ = dims[1]; m_dimK = dims[2]; m_dimTime = dims[3]; CaretAssert(m_dimTime == 1); if (m_numberOfVoxels > 0) { m_voxelData = const_cast(getFrame(0)); m_sliceStride = m_dimI * m_dimJ; m_timePointIndexStride = m_numberOfVoxels; } clearVoxels(); m_validDataFlag = true; } /** * @return True if this file type supports writing, else false. * * Dense files do NOT support writing. */ bool VolumeDynamicConnectivityFile::supportsWriting() const { return false; } /** * @return The parent volume file */ VolumeFile* VolumeDynamicConnectivityFile::getParentVolumeFile() { return const_cast(m_parentVolumeFile); } /** * @return The parent volume file (const method) */ const VolumeFile* VolumeDynamicConnectivityFile::getParentVolumeFile() const { return m_parentVolumeFile; } /** * @return True if the data is valid */ bool VolumeDynamicConnectivityFile::isDataValid() const { return m_validDataFlag; } /** * Add information about the file to the data file information. * * @param dataFileInformation * Consolidates information about a data file. */ void VolumeDynamicConnectivityFile::addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) { VolumeFile::addToDataFileContentInformation(dataFileInformation); } /** * Read the file with the given name. * * @param filename * Name of file * @throws DataFileException * If error occurs */ void VolumeDynamicConnectivityFile::readFile(const AString& /*filename*/) { throw DataFileException("Read of Volume Dynamic Connectivity File is not allowed"); } /** * Read the file with the given name. * * @param filename * Name of file * @throws DataFileException * If error occurs */ void VolumeDynamicConnectivityFile::writeFile(const AString& /*filename*/) { throw DataFileException("Writing of Volume Dynamic Connectivity File is not allowed"); } /** * Clear voxels in this volume */ void VolumeDynamicConnectivityFile::clearVoxels() { if (m_voxelData != NULL) { std::fill(m_voxelData, m_voxelData + m_numberOfVoxels, 0.0f); updateScalarColoringForMap(0); m_connectivityDataLoaded->reset(); } m_dataLoadedName = ""; } /** * Get the timepoints for a given voxel * * @param i * index "I" * @param j * index "J" * @param k * index "K" * @param dataOut * Output with time points */ void VolumeDynamicConnectivityFile::getTimePointsForVoxel(const int64_t i, const int64_t j, const int64_t k, std::vector& dataOut) const { CaretAssert(indexValid(i, j, k)); const int64_t ijk[3] { i, j, k }; const int64_t componentIndex(0); dataOut.resize(m_dimTime); for (int64_t iTime = 0; iTime < m_dimTime; iTime++) { dataOut[iTime] = m_parentVolumeFile->getValue(ijk, iTime, componentIndex); } } /** * Load connectivity data for the voxel indices and then average the data. * * @param volumeDimensionIJK * Dimensions of the volume. * @param voxelIndices * Indices of voxels. * @return * True if data was loaded, else false */ bool VolumeDynamicConnectivityFile::loadMapAverageDataForVoxelIndices(const int64_t volumeDimensionIJK[3], const std::vector& voxelIndices) { /* * Loading of data disabled? */ if ( ! isDataValid()) { return false; } if ( ! isDataLoadingEnabled()) { return false; } if ( ! matchesDimensions(volumeDimensionIJK[0], volumeDimensionIJK[1], volumeDimensionIJK[2])) { return false; } ConnectivityCorrelation* connCorrelation = getConnectivityCorrelation(); if (connCorrelation == NULL) { return false; } /* * Zero out here so that data only gets cleared when data * is to be loaded. */ clearVoxels(); std::vector brainordinateIndices; for (auto voxel : voxelIndices) { const int64_t offset = getVoxelOffset(voxel.m_ijk[0], voxel.m_ijk[1], voxel.m_ijk[2], 0); brainordinateIndices.push_back(offset); } std::vector data(m_numberOfVoxels); connCorrelation->getCorrelationForBrainordinateROI(brainordinateIndices, data); if (m_numberOfVoxels == static_cast(data.size())) { for (int64_t i = 0; i < m_numberOfVoxels; i++) { m_voxelData[i] = data[i]; } const int32_t mapIndex(0); const int64_t validDataCount(static_cast(brainordinateIndices.size())); setMapName(mapIndex, ("Average Voxel Count: " + AString::number(validDataCount, 'f', 0))); m_dataLoadedName = ("Average_Voxel_Count_" + AString::number(validDataCount, 'f', 0)); updateScalarColoringForMap(mapIndex); return true; } return false; } /** * Load the connectivity for the voxel at the given coordinate. * The loaded data will be in the voxels inside this volume. * If the voxel index at the coordinate is invalid, zeros are loaded into all voxels. * * @param xyz * The voxel XYZ. * @return * True if data was loaded, else false. */ bool VolumeDynamicConnectivityFile::loadConnectivityForVoxelXYZ(const float xyz[3]) { float indicesFloat[3]; spaceToIndex(xyz, indicesFloat); const int64_t ijk[3] { static_cast(indicesFloat[0]), static_cast(indicesFloat[1]), static_cast(indicesFloat[2]) }; if (loadConnectivityForVoxelIndex(ijk)) { const int32_t invalidRowColumnIndex(-1); m_connectivityDataLoaded->setVolumeXYZLoading(xyz, invalidRowColumnIndex, invalidRowColumnIndex); setMapName(0, ("Voxel XYZ: (" + AString::fromNumbers(xyz, 3, ",") + ")")); m_dataLoadedName = ("Voxel_x" + AString::number(static_cast(xyz[0])) + "_y" + AString::number(static_cast(xyz[1])) + "_z" + AString::number(static_cast(xyz[2]))); return true; } return false; } /** * Load the connectivity for the given voxel. * The loaded data will be in the voxels inside this volume. * If the voxel index is invalid, zeros are loaded into all voxels. * * @param ijk * The voxel index. */ bool VolumeDynamicConnectivityFile::loadConnectivityForVoxelIndex(const int64_t ijk[3]) { bool validFlag(false); if ( ! isDataValid()) { return validFlag; } if ( ! m_dataLoadingEnabledFlag) { return validFlag; } clearVoxels(); std::vector data; if (getConnectivityForVoxelIndex(ijk, data)) { CaretAssert(m_numberOfVoxels == static_cast(data.size())); std::copy(data.begin(), data.end(), m_voxelData); validFlag = true; } const int32_t mapIndex(0); updateScalarColoringForMap(mapIndex); return validFlag; } /** * Get the connectivity for the given voxel. * If the voxel index is invalid, zeros are loaded into all voxels. * * @param ijk * The voxel index. * @param voxelsOut * Output containing voxel data * @return * True if data was loaded. */ bool VolumeDynamicConnectivityFile::getConnectivityForVoxelIndex(const int64_t ijk[3], std::vector& voxelsOut) { bool validFlag(false); ConnectivityCorrelation* connCorrelation = getConnectivityCorrelation(); if (connCorrelation != NULL) { if (indexValid(ijk)) { if (connCorrelation) { const int64_t myTimePointOffset = getVoxelOffset(ijk[0], ijk[1], ijk[2], 0); connCorrelation->getCorrelationForBrainordinate(myTimePointOffset, voxelsOut); CaretAssert(m_dimI * m_dimJ * m_dimK == static_cast(voxelsOut.size())); validFlag = true; } } } if ( ! validFlag) { voxelsOut.resize(m_numberOfVoxels); std::fill(voxelsOut.begin(), voxelsOut.end(), 0.0f); } return validFlag; } /** * @return Pointer to connectivity correlation or NULL if not valid */ ConnectivityCorrelation* VolumeDynamicConnectivityFile::getConnectivityCorrelation() { if ( ! m_connectivityCorrelationFailedFlag) { if (m_voxelData != NULL) { if (m_connectivityCorrelation == NULL) { /* * Need data and timepoint count from parent volume * IJK dimensions are same in this and parent volume */ CaretAssert(m_parentVolumeFile); const float* parentVoxels = m_parentVolumeFile->getFrame(0); CaretAssert(parentVoxels); std::vector parentVolumeDimensions; m_parentVolumeFile->getDimensions(parentVolumeDimensions); CaretAssert(parentVolumeDimensions.size() >= 4); const int64_t timePointCount = parentVolumeDimensions[3]; const int64_t voxelCount(m_dimI * m_dimJ * m_dimK); const int64_t numberOfBrainordinates(voxelCount); // Each IJK voxel is a group const int64_t nextBrainordinateStride(1); // All groups have one element in each 'brick' const int64_t numberOfTimePoints(timePointCount); // Each group contains timepoints const int64_t nextTimePointStride(voxelCount); // Each group element is in separate IJK 'brick' AString errorMessage; ConnectivityCorrelation* cc = ConnectivityCorrelation::newInstance(parentVoxels, numberOfBrainordinates, nextBrainordinateStride, numberOfTimePoints, nextTimePointStride, errorMessage); if (cc != NULL) { m_connectivityCorrelation.reset(cc); } else { m_connectivityCorrelationFailedFlag = true; CaretLogSevere("Failed to create connectvity correlation for " + m_parentVolumeFile->getFileNameNoPath()); } } } } return m_connectivityCorrelation.get(); } /** * @return True if this matches the given dimensions * * @param dimI * I dimension * @param dimJ * J dimension * @param dimK * K dimension */ bool VolumeDynamicConnectivityFile::matchesDimensions(const int64_t dimI, const int64_t dimJ, const int64_t dimK) const { if ((dimI == m_dimI) && (dimJ == m_dimJ) && (dimK == m_dimK)) { return true; } return false; } /** * @return A volume file using the loaded data (will return NULL if there is an error). * * @param directoryName * Directory for file * @param errorMessageOut * Contains error information */ VolumeFile* VolumeDynamicConnectivityFile::newVolumeFileFromLoadedData(const AString& directoryName, AString& errorMessageOut) { errorMessageOut.clear(); bool validDataFlag(false); switch (m_connectivityDataLoaded->getMode()) { case ConnectivityDataLoaded::MODE_COLUMN: break; case ConnectivityDataLoaded::MODE_NONE: break; case ConnectivityDataLoaded::MODE_ROW: break; case ConnectivityDataLoaded::MODE_SURFACE_NODE: break; case ConnectivityDataLoaded::MODE_SURFACE_NODE_AVERAGE: break; case ConnectivityDataLoaded::MODE_VOXEL_IJK_AVERAGE: validDataFlag = true; break; case ConnectivityDataLoaded::MODE_VOXEL_XYZ: validDataFlag = true; break; } if ( ! validDataFlag) { errorMessageOut = "No voxel connectivity data is loaded"; return NULL; } VolumeFile* vf(NULL); try { std::vector dimensions; dimensions.push_back(m_dimI); dimensions.push_back(m_dimJ); dimensions.push_back(m_dimK); dimensions.push_back(1); dimensions.push_back(1); const VolumeSpace vs = getVolumeSpace(); vf = new VolumeFile(dimensions, vs.getSform(), 1, SubvolumeAttributes::FUNCTIONAL, m_header); float* voxelData = const_cast(vf->getFrame(0)); std::copy(m_voxelData, m_voxelData + m_numberOfVoxels, voxelData); /* * May need to convert a remote path to a local path */ FileInformation fileNameInfo(getFileName()); const AString volumeFileName = fileNameInfo.getAsLocalAbsoluteFilePath(directoryName, vf->getDataFileType()); /* * Create name of volume file data loaded information */ FileInformation volumeFileInfo(volumeFileName); AString thePath, theName, theExtension; volumeFileInfo.getFileComponents(thePath, theName, theExtension); theName.append("_" + m_dataLoadedName); AString newFileName = FileInformation::assembleFileComponents(thePath, theName, theExtension); if (newFileName.endsWith(".nii")) { newFileName.append(".gz"); } vf->setFileName(newFileName); /* * Need to copy color palette since it may be the default */ PaletteColorMapping* volumePalette = vf->getMapPaletteColorMapping(0); CaretAssert(volumePalette); const PaletteColorMapping* myPalette = getMapPaletteColorMapping(0); CaretAssert(myPalette); volumePalette->copy(*myPalette, true); vf->updateAfterFileDataChanges(); vf->updateScalarColoringForMap(0); vf->setModified(); } catch (const DataFileException& dfe) { errorMessageOut = dfe.whatString(); if (vf != NULL) { delete vf; vf = NULL; } } return vf; } /** * Save data to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. Will always * be valid (non-NULL). */ void VolumeDynamicConnectivityFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { VolumeFile::saveFileDataToScene(sceneAttributes, sceneClass); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); } /** * Restore file data from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void VolumeDynamicConnectivityFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { m_connectivityDataLoaded->reset(); VolumeFile::restoreFileDataFromScene(sceneAttributes, sceneClass); m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); switch (m_connectivityDataLoaded->getMode()) { case ConnectivityDataLoaded::MODE_COLUMN: break; case ConnectivityDataLoaded::MODE_NONE: break; case ConnectivityDataLoaded::MODE_ROW: break; case ConnectivityDataLoaded::MODE_SURFACE_NODE: break; case ConnectivityDataLoaded::MODE_SURFACE_NODE_AVERAGE: break; case ConnectivityDataLoaded::MODE_VOXEL_IJK_AVERAGE: { int64_t dimIJK[3]; std::vector voxelIJKs; m_connectivityDataLoaded->getVolumeAverageVoxelLoading(dimIJK, voxelIJKs); loadMapAverageDataForVoxelIndices(dimIJK, voxelIJKs); } break; case ConnectivityDataLoaded::MODE_VOXEL_XYZ: { float xyz[3]; int64_t rowIndex(-1); int64_t columnIndex(-1); m_connectivityDataLoaded->getVolumeXYZLoading(xyz, rowIndex, columnIndex); loadConnectivityForVoxelXYZ(xyz); } break; } } connectome-workbench-1.4.2/src/Files/VolumeDynamicConnectivityFile.h000066400000000000000000000127761360521144700256250ustar00rootroot00000000000000#ifndef __VOLUME_DYNN_CONN_FILE_H__ #define __VOLUME_DYNN_CONN_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "VolumeFile.h" namespace caret { class ConnectivityCorrelation; class ConnectivityDataLoaded; class VolumeDynamicConnectivityFile : public VolumeFile { public: VolumeDynamicConnectivityFile(const VolumeFile* parentVolumeFile); virtual ~VolumeDynamicConnectivityFile(); VolumeDynamicConnectivityFile(const VolumeDynamicConnectivityFile&) = delete; VolumeDynamicConnectivityFile& operator=(const VolumeDynamicConnectivityFile&) = delete; void initializeFile(); virtual void clear() override; virtual void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) override; virtual void readFile(const AString& filename) override; virtual void writeFile(const AString& filename) override; virtual bool supportsWriting() const override; VolumeFile* getParentVolumeFile(); const VolumeFile* getParentVolumeFile() const; bool isDataValid() const; bool isEnabledAsLayer() const; void setEnabledAsLayer(const bool enabled); bool loadConnectivityForVoxelXYZ(const float xyz[3]); bool loadMapAverageDataForVoxelIndices(const int64_t volumeDimensionIJK[3], const std::vector& voxelIndices); bool isDataLoadingEnabled() const; void setDataLoadingEnabled(const bool enabled); const ConnectivityDataLoaded* getConnectivityDataLoaded() const; bool matchesDimensions(const int64_t dimI, const int64_t dimJ, const int64_t dimK) const; VolumeFile* newVolumeFileFromLoadedData(const AString& directoryName, AString& errorMessageOut); // ADD_NEW_METHODS_HERE protected: virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) override; virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) override; private: void clearPrivateData(); void clearVoxels(); void getTimePointsForVoxel(const int64_t i, const int64_t j, const int64_t k, std::vector& dataOut) const; inline int64_t getVoxelOffset(const int64_t i, const int64_t j, const int64_t k, const int64_t timePointIndex) const { const int64_t offset = (i + (j * m_dimI) + (k * m_sliceStride) + (timePointIndex * m_timePointIndexStride)); return offset; } bool loadConnectivityForVoxelIndex(const int64_t ijk[3]); bool getConnectivityForVoxelIndex(const int64_t ijk[3], std::vector& voxelsOut) ; ConnectivityCorrelation* getConnectivityCorrelation(); const VolumeFile* m_parentVolumeFile; std::unique_ptr m_sceneAssistant; std::unique_ptr m_connectivityCorrelation; bool m_connectivityCorrelationFailedFlag = false; float* m_voxelData = NULL; int64_t m_numberOfVoxels = 0; int64_t m_sliceStride = 0; int64_t m_timePointIndexStride = 0; int64_t m_dimI = 0; int64_t m_dimJ = 0; int64_t m_dimK = 0; int64_t m_dimTime = 0; AString m_dataLoadedName; bool m_validDataFlag = false; bool m_enabledAsLayer = true; bool m_dataLoadingEnabledFlag = true; std::unique_ptr m_connectivityDataLoaded; // ADD_NEW_MEMBERS_HERE }; #ifdef __VOLUME_DYNN_CONN_FILE_DECLARE__ // #endif // __VOLUME_DYNN_CONN_FILE_DECLARE__ } // namespace #endif //__VOLUME_DYNN_CONN_FILE_H__ connectome-workbench-1.4.2/src/Files/VolumeEditingModeEnum.cxx000066400000000000000000000355771360521144700244360ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __VOLUME_EDITING_MODE_DECLARE__ #include "VolumeEditingModeEnum.h" #undef __VOLUME_EDITING_MODE_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::VolumeEditingModeEnum * \brief Enumerated type for volume editing. * * * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_volumeEditingModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void volumeEditingModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "VolumeEditingModeEnum.h" * * Instatiate: * m_volumeEditingModeEnumComboBox = new EnumComboBoxTemplate(this); * m_volumeEditingModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_volumeEditingModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(volumeEditingModeEnumComboBoxItemActivated())); * * Update the selection: * m_volumeEditingModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const VolumeEditingModeEnum::Enum VARIABLE = m_volumeEditingModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * @param guiName * User-friendly name for use in user-interface. * @param toolTipText * Text for the tooltip. */ VolumeEditingModeEnum::VolumeEditingModeEnum(const Enum enumValue, const AString& name, const AString& guiName, const AString& toolTipText) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; this->toolTipText = toolTipText; } /** * Destructor. */ VolumeEditingModeEnum::~VolumeEditingModeEnum() { } /** * Initialize the enumerated metadata. */ void VolumeEditingModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(VolumeEditingModeEnum(VOLUME_EDITING_MODE_ON, "VOLUME_EDITING_MODE_ON", "On", "Turn voxels on at mouse click. Or move the mouse with the left " "mouse button down while holding down the CTRL (Apple key on Mac) " "and SHIFT keys.")); enumData.push_back(VolumeEditingModeEnum(VOLUME_EDITING_MODE_OFF, "VOLUME_EDITING_MODE_OFF", "Off", "Turn voxels off at mouse click. Or move the mouse with the left " "mouse button down while holding down the CTRL (Apple key on Mac) " "and SHIFT keys.")); enumData.push_back(VolumeEditingModeEnum(VOLUME_EDITING_MODE_DILATE, "VOLUME_EDITING_MODE_DILATE", "Dilate", "Dilate voxels at mouse click")); enumData.push_back(VolumeEditingModeEnum(VOLUME_EDITING_MODE_ERODE, "VOLUME_EDITING_MODE_ERODE", "Erode", "Erode voxels at mouse click")); enumData.push_back(VolumeEditingModeEnum(VOLUME_EDITING_MODE_FLOOD_FILL_2D, "VOLUME_EDITING_MODE_FLOOD_FILL_2D", "Fill 2D", "Fill closed region (2D) at mouse click")); enumData.push_back(VolumeEditingModeEnum(VOLUME_EDITING_MODE_FLOOD_FILL_3D, "VOLUME_EDITING_MODE_FLOOD_FILL_3D", "Fill 3D", "Fill closed region (3D) at mouse click")); enumData.push_back(VolumeEditingModeEnum(VOLUME_EDITING_MODE_REMOVE_CONNECTED_2D, "VOLUME_EDITING_MODE_REMOVE_CONNECTED_2D", "Remove 2D", "Remove connected region (2D) at mouse click")); enumData.push_back(VolumeEditingModeEnum(VOLUME_EDITING_MODE_REMOVE_CONNECTED_3D, "VOLUME_EDITING_MODE_REMOVE_CONNECTED_3D", "Remove 3D", "Remove connected region (3D) at mouse click")); enumData.push_back(VolumeEditingModeEnum(VOLUME_EDITING_MODE_RETAIN_CONNECTED_3D, "VOLUME_EDITING_MODE_RETAIN_CONNECTED_3D", "Retain 3D", "Remove voxel not connected to region (3D) at mouse click")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const VolumeEditingModeEnum* VolumeEditingModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const VolumeEditingModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a tool tip string of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing tooltip. */ AString VolumeEditingModeEnum::toToolTip(Enum enumValue) { if (initializedFlag == false) initialize(); const VolumeEditingModeEnum* enumInstance = findData(enumValue); return enumInstance->toolTipText; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString VolumeEditingModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const VolumeEditingModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ VolumeEditingModeEnum::Enum VolumeEditingModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = VolumeEditingModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const VolumeEditingModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type VolumeEditingModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString VolumeEditingModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const VolumeEditingModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ VolumeEditingModeEnum::Enum VolumeEditingModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = VolumeEditingModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const VolumeEditingModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type VolumeEditingModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t VolumeEditingModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const VolumeEditingModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ VolumeEditingModeEnum::Enum VolumeEditingModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = VolumeEditingModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const VolumeEditingModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type VolumeEditingModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void VolumeEditingModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void VolumeEditingModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(VolumeEditingModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void VolumeEditingModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(VolumeEditingModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } /** * Does the enum value allow oblique editing? * * @param enumValue * The editing mode. * @return * True if the enum value allows oblique slice editing, else false. */ bool VolumeEditingModeEnum::isObliqueEditingAllowed(const Enum enumValue) { bool obliqueEditingSupportedFlag = false; switch (enumValue) { case VolumeEditingModeEnum::VOLUME_EDITING_MODE_ON: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_OFF: obliqueEditingSupportedFlag = true; break; case VolumeEditingModeEnum::VOLUME_EDITING_MODE_DILATE: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_ERODE: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_FLOOD_FILL_2D: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_FLOOD_FILL_3D: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_REMOVE_CONNECTED_2D: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_REMOVE_CONNECTED_3D: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_RETAIN_CONNECTED_3D: break; } return obliqueEditingSupportedFlag; } connectome-workbench-1.4.2/src/Files/VolumeEditingModeEnum.h000066400000000000000000000075271360521144700240550ustar00rootroot00000000000000#ifndef __VOLUME_EDITING_MODE_ENUM_H__ #define __VOLUME_EDITING_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class VolumeEditingModeEnum { public: /** * Enumerated values. */ enum Enum { /** Turn voxels on */ VOLUME_EDITING_MODE_ON, /** Turn voxels off */ VOLUME_EDITING_MODE_OFF, /** Dilate */ VOLUME_EDITING_MODE_DILATE, /** Erode */ VOLUME_EDITING_MODE_ERODE, /** Flood Fill 2D */ VOLUME_EDITING_MODE_FLOOD_FILL_2D, /** Flood Fill 3D */ VOLUME_EDITING_MODE_FLOOD_FILL_3D, /** Remove connected voxels */ VOLUME_EDITING_MODE_REMOVE_CONNECTED_2D, /** Remove connected voxels 3D */ VOLUME_EDITING_MODE_REMOVE_CONNECTED_3D, /** Retain connected voxels 3D */ VOLUME_EDITING_MODE_RETAIN_CONNECTED_3D }; ~VolumeEditingModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static AString toToolTip(Enum enumValue); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); static bool isObliqueEditingAllowed(const Enum enumValue); private: VolumeEditingModeEnum(const Enum enumValue, const AString& name, const AString& guiName, const AString& toolTipText); static const VolumeEditingModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; AString toolTipText; }; #ifdef __VOLUME_EDITING_MODE_DECLARE__ std::vector VolumeEditingModeEnum::enumData; bool VolumeEditingModeEnum::initializedFlag = false; int32_t VolumeEditingModeEnum::integerCodeCounter = 0; #endif // __VOLUME_EDITING_MODE_DECLARE__ } // namespace #endif //__VOLUME_EDITING_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Files/VolumeFile.cxx000066400000000000000000002712771360521144700222770ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include "ApplicationInformation.h" #include "CaretHttpManager.h" #include "CaretLogger.h" #include "CaretTemporaryFile.h" #include "ChartDataCartesian.h" #include "ChartDataSource.h" #include "DataFileContentInformation.h" #include "ElapsedTimer.h" #include "EventManager.h" #include "GiftiLabel.h" #include "GroupAndNameHierarchyModel.h" #include "FastStatistics.h" #include "Histogram.h" #include "MapFileDataSelector.h" #include "MultiDimIterator.h" #include "NiftiIO.h" #include "Palette.h" #include "SceneClass.h" #include "VolumeDynamicConnectivityFile.h" #include "VolumeFile.h" #include "VolumeFileEditorDelegate.h" #include "VolumeFileVoxelColorizer.h" #include "VolumeSpline.h" #include using namespace caret; using namespace std; const float VolumeFile::INVALID_INTERP_VALUE = 0.0f;//we may want NaN or something more obvious bool VolumeFile::s_voxelColoringEnabled = true; const AString VolumeFile::s_paletteColorMappingNameInMetaData = "__DYNAMIC_FILE_PALETTE_COLOR_MAPPING__"; /** * Static method that sets the status of voxel coloring. Coloring may take * time and is almost never needed during command line operations (wb_command). * * DO NOT CHANGE THIS VALUE if there are any instance of VolumeFile since * the coloring object is created when a VolumeFile instance is created. * * @param enabled * New status for coloring. */ void VolumeFile::setVoxelColoringEnabled(const bool enabled) { s_voxelColoringEnabled = enabled; CaretLogConfig(AString(s_voxelColoringEnabled ? "Volume coloring is enabled." : "Volume coloring is disabled.")); } /** protected, used by dynamic volume file */ VolumeFile::VolumeFile(const DataFileTypeEnum::Enum dataFileType) : VolumeBase(), CaretMappableDataFile(dataFileType) {//CaretPointers initialize to NULL, and this isn't an operator= CaretAssert((dataFileType == DataFileTypeEnum::VOLUME) || (dataFileType == DataFileTypeEnum::VOLUME_DYNAMIC)); m_forceUpdateOfGroupAndNameHierarchy = true; for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = false; } validateMembers(); } VolumeFile::VolumeFile() : VolumeBase(), CaretMappableDataFile(DataFileTypeEnum::VOLUME) {//CaretPointers initialize to NULL, and this isn't an operator= m_forceUpdateOfGroupAndNameHierarchy = true; for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = false; } validateMembers(); } VolumeFile::VolumeFile(const vector& dimensionsIn, const vector >& indexToSpace, const int64_t numComponents, SubvolumeAttributes::VolumeType whatType, const AbstractHeader* templateHeader) : VolumeBase(dimensionsIn, indexToSpace, numComponents), CaretMappableDataFile(DataFileTypeEnum::VOLUME) {//CaretPointers initialize to NULL, and this isn't an operator= m_forceUpdateOfGroupAndNameHierarchy = true; for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = false; } if (templateHeader != NULL) m_header.grabNew(templateHeader->clone()); validateMembers(); setType(whatType); } void VolumeFile::reinitialize(const vector& dimensionsIn, const vector >& indexToSpace, const int64_t numComponents, SubvolumeAttributes::VolumeType whatType, const AbstractHeader* templateHeader) { clear(); VolumeBase::reinitialize(dimensionsIn, indexToSpace, numComponents); if (templateHeader != NULL) m_header.grabNew(templateHeader->clone()); validateMembers(); setType(whatType); } void VolumeFile::reinitialize(const VolumeSpace& volSpaceIn, const int64_t numFrames, const int64_t numComponents, SubvolumeAttributes::VolumeType whatType, const AbstractHeader* templateHeader) { CaretAssert(numFrames > 0); const int64_t* dimsPtr = volSpaceIn.getDims(); vector dims(dimsPtr, dimsPtr + 3); if (numFrames > 1) { dims.push_back(numFrames); } reinitialize(dims, volSpaceIn.getSform(), numComponents, whatType, templateHeader); } void VolumeFile::reinitialize(const VolumeFile* headerTemplate, const int64_t numFrames, const int64_t numComponents) {//really just a convenience wrapper reinitialize(headerTemplate->getVolumeSpace(), numFrames, numComponents, headerTemplate->getType(), headerTemplate->m_header); } void VolumeFile::addSubvolumes(const int64_t& numToAdd) { VolumeBase::addSubvolumes(numToAdd); validateMembers(); } SubvolumeAttributes::VolumeType VolumeFile::getType() const { CaretAssertVectorIndex(m_caretVolExt.m_attributes, 0); CaretAssert(m_caretVolExt.m_attributes[0] != NULL); return m_caretVolExt.m_attributes[0]->m_type; } void VolumeFile::setType(SubvolumeAttributes::VolumeType whatType) { int numAttrs = (int)m_caretVolExt.m_attributes.size(); for (int i = 0; i < numAttrs; ++i) { CaretAssert(m_caretVolExt.m_attributes[i] != NULL); if (m_caretVolExt.m_attributes[i]->m_type != whatType) { m_caretVolExt.m_attributes[i]->m_type = whatType; if (whatType == SubvolumeAttributes::LABEL) { m_caretVolExt.m_attributes[i]->m_palette.grabNew(NULL); m_caretVolExt.m_attributes[i]->m_labelTable.grabNew(new GiftiLabelTable()); } else { m_caretVolExt.m_attributes[i]->m_palette.grabNew(new PaletteColorMapping()); m_caretVolExt.m_attributes[i]->m_labelTable.grabNew(NULL); if (whatType == SubvolumeAttributes::ANATOMY) { m_caretVolExt.m_attributes[i]->m_palette->setSelectedPaletteName(Palette::GRAY_INTERP_POSITIVE_PALETTE_NAME); m_caretVolExt.m_attributes[i]->m_palette->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE); } } } } } VolumeFile::~VolumeFile() { clear(); } /** * Clear the file. */ void VolumeFile::clear() { CaretMappableDataFile::clear(); m_voxelColorizer.grabNew(NULL); m_classNameHierarchy.grabNew(NULL); m_forceUpdateOfGroupAndNameHierarchy = true; m_fileFastStatistics.grabNew(NULL); m_fileHistogram.grabNew(NULL); m_fileHistorgramLimitedValues.grabNew(NULL); m_caretVolExt.clear(); m_brickAttributes.clear(); m_brickStatisticsValid = false; m_splinesValid = false; m_frameSplineValid.clear(); m_frameSplines.clear(); m_dataRangeValid = false; VolumeBase::clear(); m_volumeFileEditorDelegate->clear(); m_lazyInitializedDynamicConnectivityFile.reset(); } void VolumeFile::readFile(const AString& filename) { ElapsedTimer timer; timer.start(); clear(); { /* * CaretTemporaryFile must be outside of the "if" statment block of code. * Otherwise, at the end of the "if" statement block, the * CaretTemporaryFile object will go out of scope and the temporary * file will be deleted so there will be no file to read. */ AString fileToRead; CaretTemporaryFile tempFile; if (DataFile::isFileOnNetwork(filename)) { tempFile.readFile(filename); fileToRead = tempFile.getFileName(); setFileName(filename); } else { setFileName(filename); fileToRead = filename; } checkFileReadability(fileToRead); NiftiIO myIO;//begin nifti specific code - should this go somewhere else? myIO.openRead(fileToRead); const NiftiHeader& inHeader = myIO.getHeader(); for (int i = 0; i < (int)inHeader.m_extensions.size(); ++i) {//check for actually being cifti if (inHeader.m_extensions[i]->m_ecode == NIFTI_ECODE_CIFTI) { throw DataFileException(filename, "Cifti files cannot be used as volume files"); } } int numComponents = myIO.getNumComponents(); vector myDims = myIO.getDimensions(); int fullDims = 3;//deal with nifti with less than 3 dimensions if (myDims.size() < 3) fullDims = (int)myDims.size(); vector extraDims;//non-spatial dims if (myDims.size() > 3) { extraDims = vector(myDims.begin() + 3, myDims.end()); } while (myDims.size() < 3) myDims.push_back(1);//pretend we have 3 dimensions in header, always, things that use getOriginalDimensions assume this (because "VolumeFile") if (myDims.size() > 3) {//check for cifti-like dimensions here, so that we have the filename to report in the error int64_t numFrames = myDims[3]; for (int i = 4; i < (int)myDims.size(); ++i) { numFrames *= myDims[i]; } if (myDims[0] == 1 && myDims[1] == 1 && myDims[2] == 1 && numFrames > 10000) { throw DataFileException(filename, "volume FOV is 1x1x1 voxel, with over 10,000 frames, which suggests a broken cifti file (no header extension)"); } }//this check is also done in reinitialize(), but we don't want to call getSForm before this check when reading a file reinitialize(myDims, inHeader.getSForm(), numComponents); setFileName(filename); // must be done after reinitialize() since it calls clear() which clears the name of the file int64_t frameSize = myDims[0] * myDims[1] * myDims[2]; if (numComponents != 1) { vector tempFrame(frameSize), readBuffer(frameSize * numComponents); for (MultiDimIterator myiter(extraDims); !myiter.atEnd(); ++myiter) { myIO.readData(readBuffer.data(), fullDims, *myiter); for (int c = 0; c < numComponents; ++c) { for (int64_t i = 0; i < frameSize; ++i) { tempFrame[i] = readBuffer[i * numComponents + c]; } setFrame(tempFrame.data(), getBrickIndexFromNonSpatialIndexes(*myiter), c); } } } else {//avoid the added allocation for separating components vector tempFrame(frameSize); for (MultiDimIterator myiter(extraDims); !myiter.atEnd(); ++myiter) { myIO.readData(tempFrame.data(), fullDims, *myiter); setFrame(tempFrame.data(), getBrickIndexFromNonSpatialIndexes(*myiter)); } } CaretLogFine("Time to read volume data is " + AString::number(timer.getElapsedTimeSeconds(), 'f', 3) + " seconds."); m_header.grabNew(new NiftiHeader(inHeader));//end nifti-specific code parseExtensions(); updateAfterFileDataChanges(); clearModified(); } m_volumeFileEditorDelegate->updateIfVolumeFileChangedNumberOfMaps(); /* * This will update the map name/label hierarchy */ if (isMappedWithLabelTable()) { m_forceUpdateOfGroupAndNameHierarchy = true; getGroupAndNameHierarchyModel(); } if ( ! hasGoodSpatialInformation()) { addFileReadWarning("No spatial information in file (in NIFTI header, both qform and sform are invalid)."); } CaretLogFine("Total Time to read and process volume is " + AString::number(timer.getElapsedTimeSeconds(), 'f', 3) + " seconds."); } /** * Write the data file. * * @param filename * Name of the data file. * @throws DataFileException * If the file was not successfully written. */ void VolumeFile::writeFile(const AString& filename) { if (!(filename.endsWith(".nii.gz") || filename.endsWith(".nii"))) { CaretLogWarning("volume file '" + filename + "' should be saved ending in .nii.gz or .nii, other formats are not supported"); } checkFileWritability(filename); if (getNumberOfComponents() != 1) { throw DataFileException(filename, "writing multi-component volumes is not currently supported");//its a hassle, and uncommon, and there is only one 3-component type, restricted to 0-255 } /* * Put the child dynamic data-series file's palette in the file's metadata. */ if (m_lazyInitializedDynamicConnectivityFile != NULL) { GiftiMetaData* fileMetaData = m_lazyInitializedDynamicConnectivityFile->getCiftiXML().getFileMetaData(); CaretAssert(fileMetaData); if (m_lazyInitializedDynamicConnectivityFile->getNumberOfMaps() > 0) { fileMetaData->set(s_paletteColorMappingNameInMetaData, m_lazyInitializedDynamicConnectivityFile->getMapPaletteColorMapping(0)->encodeInXML()); } else { fileMetaData->remove(s_paletteColorMappingNameInMetaData); } } updateCaretExtension(); NiftiHeader outHeader;//begin nifti-specific code if (m_header != NULL && (m_header->getType() == AbstractHeader::NIFTI)) { outHeader = *((NiftiHeader*)m_header.getPointer());//also shallow copies extensions } outHeader.clearDataScaling(); outHeader.setDescription(("Connectome Workbench, version " + ApplicationInformation().getVersion()).toLatin1().constData());//30 chars, plus however many chars the version is (generally 5) outHeader.setSForm(getVolumeSpace().getSform()); outHeader.setDimensions(getOriginalDimensions()); outHeader.setDataType(NIFTI_TYPE_FLOAT32);//could set this to an integer when type is label NiftiIO myIO; int outVersion = 1; if (!outHeader.canWriteVersion(1)) outVersion = 2; myIO.writeNew(filename, outHeader, outVersion); const vector& origDims = getOriginalDimensions(); vector extraDims;//non-spatial dims if (origDims.size() > 3) { extraDims = vector(origDims.begin() + 3, origDims.end()); } for (MultiDimIterator myiter(extraDims); !myiter.atEnd(); ++myiter) { myIO.writeData(getFrame(getBrickIndexFromNonSpatialIndexes(*myiter)), 3, *myiter);//NOTE: does not deal with multi-component volumes } myIO.close();//call close explicitly to get a throw rather than a severe log when there is a problem m_header.grabNew(new NiftiHeader(outHeader));//update header to last written version, end nifti-specific code m_volumeFileEditorDelegate->clear(); m_volumeFileEditorDelegate->updateIfVolumeFileChangedNumberOfMaps(); clearModified(); } bool VolumeFile::hasGoodSpatialInformation() const { if (m_header != NULL) { return m_header->hasGoodSpatialInformation(); } return true; } float VolumeFile::interpolateValue(const float* coordIn, InterpType interp, bool* validOut, const int64_t brickIndex, const int64_t component) const { return interpolateValue(coordIn[0], coordIn[1], coordIn[2], interp, validOut, brickIndex, component); } float VolumeFile::interpolateValue(const float coordIn1, const float coordIn2, const float coordIn3, InterpType interp, bool* validOut, const int64_t brickIndex, const int64_t component) const { /* * If the volume is a single slice, CUBIC and TRILINEAR will fail they * require and interpolate between adjacent slices. */ if (m_singleSliceFlag) { interp = ENCLOSING_VOXEL; } const int64_t* dimensions = getDimensionsPtr(); switch (interp) { case CUBIC: { float indexSpace[3]; spaceToIndex(coordIn1, coordIn2, coordIn3, indexSpace); int64_t ind1low = floor(indexSpace[0]); int64_t ind2low = floor(indexSpace[1]); int64_t ind3low = floor(indexSpace[2]); int64_t ind1high = ind1low + 1; int64_t ind2high = ind2low + 1; int64_t ind3high = ind3low + 1; if (!indexValid(ind1low, ind2low, ind3low, brickIndex, component) || !indexValid(ind1high, ind2high, ind3high, brickIndex, component)) { if (validOut != NULL) *validOut = false;//check for valid coord before deconvolving the frame if (getType() == SubvolumeAttributes::LABEL) { return getMapLabelTable(brickIndex)->getUnassignedLabelKey(); } else { return INVALID_INTERP_VALUE; } } int64_t whichFrame = component * dimensions[3] + brickIndex; validateSpline(brickIndex, component); if (validOut != NULL) *validOut = true; return m_frameSplines[whichFrame].sample(indexSpace); } case TRILINEAR: { float index1, index2, index3; spaceToIndex(coordIn1, coordIn2, coordIn3, index1, index2, index3); int64_t ind1low = floor(index1); int64_t ind2low = floor(index2); int64_t ind3low = floor(index3); int64_t ind1high = ind1low + 1; int64_t ind2high = ind2low + 1; int64_t ind3high = ind3low + 1; if (!indexValid(ind1low, ind2low, ind3low, brickIndex, component) || !indexValid(ind1high, ind2high, ind3high, brickIndex, component)) { if (validOut != NULL) *validOut = false; if (getType() == SubvolumeAttributes::LABEL) { return getMapLabelTable(brickIndex)->getUnassignedLabelKey(); } else { return INVALID_INTERP_VALUE; } } float xhighWeight = index1 - ind1low; float xlowWeight = 1.0f - xhighWeight; float xinterp[2][2];//manually unrolled, because loops of 2 seem silly xinterp[0][0] = xlowWeight * getValue(ind1low, ind2low, ind3low, brickIndex, component) + xhighWeight * getValue(ind1high, ind2low, ind3low, brickIndex, component); xinterp[1][0] = xlowWeight * getValue(ind1low, ind2high, ind3low, brickIndex, component) + xhighWeight * getValue(ind1high, ind2high, ind3low, brickIndex, component); xinterp[0][1] = xlowWeight * getValue(ind1low, ind2low, ind3high, brickIndex, component) + xhighWeight * getValue(ind1high, ind2low, ind3high, brickIndex, component); xinterp[1][1] = xlowWeight * getValue(ind1low, ind2high, ind3high, brickIndex, component) + xhighWeight * getValue(ind1high, ind2high, ind3high, brickIndex, component); float yhighWeight = index2 - ind2low; float ylowWeight = 1.0f - yhighWeight; float yinterp[2]; yinterp[0] = ylowWeight * xinterp[0][0] + yhighWeight * xinterp[1][0]; yinterp[1] = ylowWeight * xinterp[0][1] + yhighWeight * xinterp[1][1]; float zhighWeight = index3 - ind3low; float zlowWeight = 1.0f - zhighWeight; float ret = zlowWeight * yinterp[0] + zhighWeight * yinterp[1]; if (validOut != NULL) *validOut = true; return ret; } break; case ENCLOSING_VOXEL: { int64_t index1, index2, index3; enclosingVoxel(coordIn1, coordIn2, coordIn3, index1, index2, index3); if (indexValid(index1, index2, index3, brickIndex, component)) { if (validOut != NULL) *validOut = true; return getValue(index1, index2, index3, brickIndex, component); } else { if (validOut != NULL) *validOut = false; if (getType() == SubvolumeAttributes::LABEL) { return getMapLabelTable(brickIndex)->getUnassignedLabelKey(); } else { return INVALID_INTERP_VALUE; } } } break; } if (validOut != NULL) *validOut = false;//this shouldn't be reached unless the enum value is invalid if (getType() == SubvolumeAttributes::LABEL) { return getMapLabelTable(brickIndex)->getUnassignedLabelKey(); } else { return INVALID_INTERP_VALUE; } } void VolumeFile::validateSpline(const int64_t brickIndex, const int64_t component) const { const int64_t* dimensions = getDimensionsPtr(); CaretAssert(brickIndex >= 0 && brickIndex < dimensions[3]);//function is public, so check inputs CaretAssert(component >= 0 && component < dimensions[4]); int64_t numFrames = dimensions[3] * dimensions[4], whichFrame = component * dimensions[3] + brickIndex; if (!m_splinesValid) { CaretMutexLocker locked(&m_splineMutex);//prevent concurrent modify access to spline state if (!m_splinesValid)//double check { m_frameSplineValid = vector(numFrames, false); m_frameSplines = vector(numFrames);//release the old spline memory m_splinesValid = true;//the only purpose of this flag is for setModified to be fast, don't worry about it becoming false again before the below happens } } CaretAssert((int64_t)m_frameSplineValid.size() == numFrames); CaretAssert((int64_t)m_frameSplines.size() == numFrames); if (!m_frameSplineValid[whichFrame]) { CaretMutexLocker locked(&m_splineMutex);//prevent concurrent modify access to spline state if (!m_frameSplineValid[whichFrame])//double check { m_frameSplines[whichFrame] = VolumeSpline(getFrame(brickIndex, component), dimensions); if (m_frameSplines[whichFrame].ignoredNonNumeric()) { CaretLogWarning("ignored non-numeric input value when calculating cubic splines in volume '" + getFileName() + "', frame #" + AString::number(brickIndex + 1)); } m_frameSplineValid[whichFrame] = true; } } } void VolumeFile::freeSpline(const int64_t brickIndex, const int64_t component) const { const int64_t* dimensions = getDimensionsPtr(); CaretAssert(brickIndex >= 0 && brickIndex < dimensions[3]);//function is public, so check inputs CaretAssert(component >= 0 && component < dimensions[4]); int64_t numFrames = dimensions[3] * dimensions[4], whichFrame = component * dimensions[3] + brickIndex; if (!m_splinesValid) { CaretMutexLocker locked(&m_splineMutex);//prevent concurrent modify access to spline state if (!m_splinesValid)//double check { m_frameSplineValid = vector(numFrames, false); m_frameSplines = vector(numFrames);//release the old spline memory m_splinesValid = true;//the only purpose of this flag is for setModified to be fast } return;//already freed, we are done } CaretAssert((int64_t)m_frameSplineValid.size() == numFrames); CaretAssert((int64_t)m_frameSplines.size() == numFrames); if (m_frameSplineValid[whichFrame]) { CaretMutexLocker locked(&m_splineMutex);//prevent concurrent modify access to spline state if (m_frameSplineValid[whichFrame])//double check { m_frameSplines[whichFrame] = VolumeSpline(); m_frameSplineValid[whichFrame] = false; } } } bool VolumeFile::matchesVolumeSpace(const VolumeFile* right) const { return getVolumeSpace().matches(right->getVolumeSpace()); } bool VolumeFile::matchesVolumeSpace(const VolumeSpace& otherSpace) const { return getVolumeSpace().matches(otherSpace); } bool VolumeFile::matchesVolumeSpace(const int64_t dims[3], const vector >& sform) const { return getVolumeSpace().matches(VolumeSpace(dims, sform)); } void VolumeFile::parseExtensions() { const int NIFTI_ECODE_CARET = 30;//this should probably go in nifti1.h if (m_header != NULL && m_header->getType() == AbstractHeader::NIFTI) { const NiftiHeader& myHeader = *((NiftiHeader*)m_header.getPointer()); int numExtensions = (int)myHeader.m_extensions.size(); int whichExt = -1, whichType = -1;//type will track caret's preference in which extension to read, the greater the type, the more it prefers it for (int i = 0; i < numExtensions; ++i) { const NiftiExtension& myNiftiExtension = *(myHeader.m_extensions[i]); switch (myNiftiExtension.m_ecode) { case NIFTI_ECODE_CARET: if (100 > whichType)//mostly to make it use the first caret extension it finds in the list of extensions { whichExt = i; whichType = 100;//caret extension gets maximum priority } break; default: break; } break; } if (whichExt != -1) { switch (whichType) { case 100://caret extension { QByteArray myByteArray(myHeader.m_extensions[whichExt]->m_bytes.data(), myHeader.m_extensions[whichExt]->m_bytes.size()); AString myString(myByteArray); m_caretVolExt.readFromXmlString(myString); break; } default: break; } } } validateMembers(); } void VolumeFile::updateCaretExtension() { const int NIFTI_ECODE_CARET = 30;//this should probably go in nifti1.h stringstream mystream; XmlWriter myWriter(mystream); m_caretVolExt.writeAsXML(myWriter); string myStr = mystream.str(); if (m_header == NULL) m_header.grabNew(new NiftiHeader()); switch (m_header->getType()) { case AbstractHeader::NIFTI: { NiftiHeader& myHeader = *((NiftiHeader*)m_header.getPointer()); int numExtensions = (int)myHeader.m_extensions.size(); for (int i = 0; i < numExtensions; ++i)//erase all existing caret extensions { NiftiExtension* myNiftiExtension = myHeader.m_extensions[i]; if (myNiftiExtension->m_ecode == NIFTI_ECODE_CARET) { myHeader.m_extensions.erase(myHeader.m_extensions.begin() + i); --i; --numExtensions; } } CaretPointer newExt(new NiftiExtension()); newExt->m_ecode = NIFTI_ECODE_CARET; int length = myStr.length(); newExt->m_bytes.resize(length + 1);//allocate a null byte for safety for (int i = 0; i < length; ++i) { newExt->m_bytes[i] = myStr[i]; } newExt->m_bytes[length] = '\0'; myHeader.m_extensions.push_back(newExt); break; } } } void VolumeFile::validateMembers() { m_dataRangeValid = false; const int64_t* dimensions = getDimensionsPtr(); m_frameSplineValid = vector(dimensions[3] * dimensions[4], false); m_frameSplines = vector(dimensions[3] * dimensions[4]);//release any previous spline memory m_splinesValid = true;//this now indicates only if they need to all be recalculated - the frame vectors will always have the correct length int numMaps = getNumberOfMaps(); m_brickAttributes.resize(numMaps);//only resize, if this was called from reinitialize, it has called clear() beforehand m_brickStatisticsValid = true; int curAttribNum = (int)m_caretVolExt.m_attributes.size(); if (curAttribNum != numMaps) { m_caretVolExt.m_attributes.resize(numMaps); } bool isLabel = false; SubvolumeAttributes::VolumeType theType = SubvolumeAttributes::ANATOMY; if (numMaps > 0 && curAttribNum > 0 && m_caretVolExt.m_attributes[0] != NULL) { theType = m_caretVolExt.m_attributes[0]->m_type; if (theType == SubvolumeAttributes::UNKNOWN) { theType = SubvolumeAttributes::ANATOMY; } if (theType == SubvolumeAttributes::LABEL) { isLabel = true; } } for (int i = 0; i < numMaps; ++i) { if (m_caretVolExt.m_attributes[i] == NULL) { m_caretVolExt.m_attributes[i].grabNew(new SubvolumeAttributes()); } m_caretVolExt.m_attributes[i]->m_type = theType; if (isLabel) { m_caretVolExt.m_attributes[i]->m_palette.grabNew(NULL); if (m_caretVolExt.m_attributes[i]->m_labelTable == NULL) { m_caretVolExt.m_attributes[i]->m_labelTable.grabNew(new GiftiLabelTable());//TODO: populate the label table by means of the frame values? } } else { m_caretVolExt.m_attributes[i]->m_labelTable.grabNew(NULL); if (m_caretVolExt.m_attributes[i]->m_palette == NULL) { m_caretVolExt.m_attributes[i]->m_palette.grabNew(new PaletteColorMapping()); m_caretVolExt.m_attributes[i]->m_palette->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE); if ((theType == SubvolumeAttributes::ANATOMY) && (numMaps == 1)) { m_caretVolExt.m_attributes[i]->m_palette->setSelectedPaletteName(Palette::GRAY_INTERP_POSITIVE_PALETTE_NAME); } else { m_caretVolExt.m_attributes[i]->m_palette->setSelectedPaletteName(Palette::ROY_BIG_BL_PALETTE_NAME); } } } } m_singleSliceFlag = false; if ((dimensions[0] == 1) || (dimensions[1] == 1) || (dimensions[2] == 1)) { m_singleSliceFlag = true; } /* * Will handle colorization of voxel data. */ if (m_voxelColorizer != NULL) { m_voxelColorizer.grabNew(NULL); } if (s_voxelColoringEnabled) { m_voxelColorizer.grabNew(new VolumeFileVoxelColorizer(this)); } if (m_classNameHierarchy == NULL) { m_classNameHierarchy.grabNew(new GroupAndNameHierarchyModel()); } m_classNameHierarchy->clear(); m_forceUpdateOfGroupAndNameHierarchy = true; m_volumeFileEditorDelegate.grabNew(new VolumeFileEditorDelegate(this)); m_volumeFileEditorDelegate->updateIfVolumeFileChangedNumberOfMaps(); } /** * Set this file as modified. */ void VolumeFile::setModified() { DataFile::setModified(); VolumeBase::setModified(); m_brickStatisticsValid = false; m_splinesValid = false; m_fileFastStatistics.grabNew(NULL); m_fileHistogram.grabNew(NULL); m_fileHistorgramLimitedValues.grabNew(NULL); } /** * Clear the modified status of this file. */ void VolumeFile::clearModified() { CaretMappableDataFile::clearModified(); clearModifiedVolumeBase(); getFileMetaData()->clearModified(); const int32_t numMaps = getNumberOfMaps(); if (isMappedWithPalette()) { for (int32_t i = 0; i < numMaps; i++) { PaletteColorMapping* pcm = getMapPaletteColorMapping(i); pcm->clearModified(); } } else if (isMappedWithLabelTable()) { for (int32_t i = 0; i < numMaps; i++) { getMapLabelTable(i)->clearModified(); } } for (int32_t i = 0; i < numMaps; i++) { getMapMetaData(i)->clearModified(); } if (m_lazyInitializedDynamicConnectivityFile != NULL) { m_lazyInitializedDynamicConnectivityFile->clearModified(); } } /** * @eturn The modified status of this file. * * NOTE: DOES NOT include palette color mapping modified status. */ bool VolumeFile::isModifiedExcludingPaletteColorMapping() const { if (CaretMappableDataFile::isModifiedExcludingPaletteColorMapping()) { return true; } if (isModifiedVolumeBase()) { return true; } if (getFileMetaData()->isModified()) { return true; } const int32_t numMaps = getNumberOfMaps(); if (isMappedWithLabelTable()) { for (int32_t i = 0; i < numMaps; i++) { if (getMapLabelTable(i)->isModified()) { return true; } } } for (int32_t i = 0; i < numMaps; i++) { if (getMapMetaData(i)->isModified()) { return true; } } return false; } /** * @return The structure for this file. */ StructureEnum::Enum VolumeFile::getStructure() const { return StructureEnum::INVALID; } /** * Set the structure for this file. * @param structure * New structure for this file. */ void VolumeFile::setStructure(const StructureEnum::Enum /*structure*/) { /* no structure in volulme file */ } /** * Get the name of the map at the given index. * * @param mapIndex * Index of the map. * @return * Name of the map. */ AString VolumeFile::getMapName(const int32_t mapIndex) const { CaretAssertVectorIndex(m_caretVolExt.m_attributes, mapIndex); CaretAssert(m_caretVolExt.m_attributes[mapIndex] != NULL); AString name = m_caretVolExt.m_attributes[mapIndex]->m_guiLabel; return name; } /** * Set the name of the map at the given index. * * @param mapIndex * Index of the map. * @param mapName * New name for the map. */ void VolumeFile::setMapName(const int32_t mapIndex, const AString& mapName) { CaretAssertVectorIndex(m_caretVolExt.m_attributes, mapIndex); CaretAssert(m_caretVolExt.m_attributes[mapIndex] != NULL); m_caretVolExt.m_attributes[mapIndex]->m_guiLabel = mapName; setModified(); } const GiftiMetaData* VolumeFile::getMapMetaData(const int32_t mapIndex) const { CaretAssertVectorIndex(m_caretVolExt.m_attributes, mapIndex); return &m_caretVolExt.m_attributes[mapIndex]->m_metadata; } GiftiMetaData* VolumeFile::getMapMetaData(const int32_t mapIndex) { CaretAssertVectorIndex(m_caretVolExt.m_attributes, mapIndex); return &m_caretVolExt.m_attributes[mapIndex]->m_metadata; } void VolumeFile::checkStatisticsValid() { if (m_brickStatisticsValid == false) { int32_t numMaps = getNumberOfMaps(); for (int i = 0; i < numMaps; ++i) { m_brickAttributes[i].m_fastStatistics.grabNew(NULL); m_brickAttributes[i].m_histogram.grabNew(NULL); m_brickAttributes[i].m_histogramLimitedValues.grabNew(NULL); } m_brickStatisticsValid = true; } } const FastStatistics* VolumeFile::getMapFastStatistics(const int32_t mapIndex) { CaretAssertVectorIndex(m_brickAttributes, mapIndex); checkStatisticsValid(); const int64_t* dimensions = getDimensionsPtr(); if (m_brickAttributes[mapIndex].m_fastStatistics == NULL) { m_brickAttributes[mapIndex].m_fastStatistics.grabNew(new FastStatistics(getFrame(mapIndex), dimensions[0] * dimensions[1] * dimensions[2])); } return m_brickAttributes[mapIndex].m_fastStatistics; } const Histogram* VolumeFile::getMapHistogram(const int32_t mapIndex) { CaretAssertVectorIndex(m_brickAttributes, mapIndex); checkStatisticsValid(); const int64_t* dimensions = getDimensionsPtr(); bool updateHistogramFlag = false; int32_t numberOfBuckets = 0; switch (getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: numberOfBuckets = getFileHistogramNumberOfBuckets(); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: numberOfBuckets = getMapPaletteColorMapping(mapIndex)->getHistogramNumberOfBuckets(); break; } if (m_brickAttributes[mapIndex].m_histogram == NULL) { m_brickAttributes[mapIndex].m_histogram.grabNew(new Histogram(numberOfBuckets)); updateHistogramFlag = true; } else if (numberOfBuckets != m_brickAttributes[mapIndex].m_histogramNumberOfBuckets) { updateHistogramFlag = true; } if (updateHistogramFlag) { m_brickAttributes[mapIndex].m_histogram->update(numberOfBuckets, getFrame(mapIndex), dimensions[0] * dimensions[1] * dimensions[2]); m_brickAttributes[mapIndex].m_histogramNumberOfBuckets = numberOfBuckets; } return m_brickAttributes[mapIndex].m_histogram; } /** * Update the Histogram for limited values. * * @param data * Data for histogram. * @param mostPositiveValueInclusive * Values more positive than this value are excluded. * @param leastPositiveValueInclusive * Values less positive than this value are excluded. * @param leastNegativeValueInclusive * Values less negative than this value are excluded. * @param mostNegativeValueInclusive * Values more negative than this value are excluded. * @param includeZeroValues * If true zero values (very near zero) are included. */ const Histogram* VolumeFile::getMapHistogram(const int32_t mapIndex, const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) { CaretAssertVectorIndex(m_brickAttributes, mapIndex); checkStatisticsValid(); const int64_t* dimensions = getDimensionsPtr(); bool updateHistogramFlag = false; int32_t numberOfBuckets = 0; switch (getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: numberOfBuckets = getFileHistogramNumberOfBuckets(); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: numberOfBuckets = getMapPaletteColorMapping(mapIndex)->getHistogramNumberOfBuckets(); break; } if (m_brickAttributes[mapIndex].m_histogramLimitedValues == NULL) { m_brickAttributes[mapIndex].m_histogramLimitedValues.grabNew(new Histogram(100)); updateHistogramFlag = true; } else if ((numberOfBuckets != m_brickAttributes[mapIndex].m_histogramLimitedValuesNumberOfBuckets) || (mostPositiveValueInclusive != m_brickAttributes[mapIndex].m_histogramLimitedValuesMostPositiveValueInclusive) || (leastPositiveValueInclusive != m_brickAttributes[mapIndex].m_histogramLimitedValuesLeastPositiveValueInclusive) || (leastNegativeValueInclusive != m_brickAttributes[mapIndex].m_histogramLimitedValuesLeastNegativeValueInclusive) || (mostNegativeValueInclusive != m_brickAttributes[mapIndex].m_histogramLimitedValuesMostNegativeValueInclusive) || (includeZeroValues != m_brickAttributes[mapIndex].m_histogramLimitedValuesIncludeZeroValues)) { updateHistogramFlag = true; } if (updateHistogramFlag) { m_brickAttributes[mapIndex].m_histogramLimitedValues->update(numberOfBuckets, getFrame(mapIndex), dimensions[0] * dimensions[1] * dimensions[2], mostPositiveValueInclusive, leastPositiveValueInclusive, leastNegativeValueInclusive, mostNegativeValueInclusive, includeZeroValues); m_brickAttributes[mapIndex].m_histogramLimitedValuesNumberOfBuckets = numberOfBuckets; m_brickAttributes[mapIndex].m_histogramLimitedValuesMostPositiveValueInclusive = mostPositiveValueInclusive; m_brickAttributes[mapIndex].m_histogramLimitedValuesLeastPositiveValueInclusive = leastPositiveValueInclusive; m_brickAttributes[mapIndex].m_histogramLimitedValuesLeastNegativeValueInclusive = leastNegativeValueInclusive; m_brickAttributes[mapIndex].m_histogramLimitedValuesMostNegativeValueInclusive = mostNegativeValueInclusive; m_brickAttributes[mapIndex].m_histogramLimitedValuesIncludeZeroValues = includeZeroValues; } return m_brickAttributes[mapIndex].m_histogramLimitedValues; } /** * @return The estimated size of data after it is uncompressed * and loaded into RAM. A negative value indicates that the * file size cannot be computed. */ int64_t VolumeFile::getDataSizeUncompressedInBytes() const { int64_t dimI, dimJ, dimK, dimTime, dimComp; getDimensions(dimI, dimJ, dimK, dimTime, dimComp); const int64_t numBytes = (dimI * dimJ * dimK * dimTime * dimComp * sizeof(float)); return numBytes; } /** * Get statistics describing the distribution of data * mapped with a color palette for all data within the file. * * @return * Fast statistics for data (will be NULL for data * not mapped using a palette). */ const FastStatistics* VolumeFile::getFileFastStatistics() { if (m_fileFastStatistics == NULL) { std::vector fileData; getFileData(fileData); if ( ! fileData.empty()) { m_fileFastStatistics.grabNew(new FastStatistics()); m_fileFastStatistics->update(&fileData[0], fileData.size()); } } return m_fileFastStatistics; } /** * Get histogram describing the distribution of data * mapped with a color palette for all data within * the file. * * @return * Histogram for data (will be NULL for data * not mapped using a palette). */ const Histogram* VolumeFile::getFileHistogram() { const int32_t numBuckets = getFileHistogramNumberOfBuckets(); bool updateHistogramFlag = false; if (m_fileHistogram != NULL) { if (numBuckets != m_fileHistogramNumberOfBuckets) { updateHistogramFlag = true; } } else { updateHistogramFlag = true; } if (updateHistogramFlag) { std::vector fileData; getFileData(fileData); if ( ! fileData.empty()) { if (m_fileHistogram == NULL) { m_fileHistogram.grabNew(new Histogram(numBuckets)); } m_fileHistogram->update(numBuckets, &fileData[0], fileData.size()); m_fileHistogramNumberOfBuckets = numBuckets; } } return m_fileHistogram; } /** * Get histogram describing the distribution of data * mapped with a color palette for all data in the file * within the given range of values. * * @param mostPositiveValueInclusive * Values more positive than this value are excluded. * @param leastPositiveValueInclusive * Values less positive than this value are excluded. * @param leastNegativeValueInclusive * Values less negative than this value are excluded. * @param mostNegativeValueInclusive * Values more negative than this value are excluded. * @param includeZeroValues * If true zero values (very near zero) are included. * @return * Descriptive statistics for data (will be NULL for data * not mapped using a palette). */ const Histogram* VolumeFile::getFileHistogram(const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) { const int32_t numberOfBuckets = getFileHistogramNumberOfBuckets(); bool updateHistogramFlag = false; if (m_fileHistorgramLimitedValues != NULL) { if ((numberOfBuckets != m_fileHistogramLimitedValuesNumberOfBuckets) || (mostPositiveValueInclusive != m_fileHistogramLimitedValuesMostPositiveValueInclusive) || (leastPositiveValueInclusive != m_fileHistogramLimitedValuesLeastPositiveValueInclusive) || (leastNegativeValueInclusive != m_fileHistogramLimitedValuesLeastNegativeValueInclusive) || (mostNegativeValueInclusive != m_fileHistogramLimitedValuesMostNegativeValueInclusive) || (includeZeroValues != m_fileHistogramLimitedValuesIncludeZeroValues)) { updateHistogramFlag = true; } } else { updateHistogramFlag = true; } if (updateHistogramFlag) { std::vector fileData; getFileData(fileData); if ( ! fileData.empty()) { if (m_fileHistorgramLimitedValues == NULL) { m_fileHistorgramLimitedValues.grabNew(new Histogram()); } m_fileHistorgramLimitedValues->update(numberOfBuckets, &fileData[0], fileData.size(), mostPositiveValueInclusive, leastPositiveValueInclusive, leastNegativeValueInclusive, mostNegativeValueInclusive, includeZeroValues); m_fileHistogramLimitedValuesNumberOfBuckets = numberOfBuckets; m_fileHistogramLimitedValuesMostPositiveValueInclusive = mostPositiveValueInclusive; m_fileHistogramLimitedValuesLeastPositiveValueInclusive = leastPositiveValueInclusive; m_fileHistogramLimitedValuesLeastNegativeValueInclusive = leastNegativeValueInclusive; m_fileHistogramLimitedValuesMostNegativeValueInclusive = mostNegativeValueInclusive; m_fileHistogramLimitedValuesIncludeZeroValues = includeZeroValues; } } return m_fileHistorgramLimitedValues; } /** * @return Pointer to file's metadata. */ GiftiMetaData* VolumeFile::getFileMetaData() { return &m_caretVolExt.m_metadata; } /** * @return Pointer to file's metadata. */ const GiftiMetaData* VolumeFile::getFileMetaData() const { return &m_caretVolExt.m_metadata; } /** * Get all data for a volume file. If the file is very * large this method may take a large amount of time! * * @param dataOut * Output with all data for a file. Empty if no data in file * or data is not float. */ void VolumeFile::getFileData(std::vector& dataOut) const { int64_t dimI, dimJ, dimK, dimTime, dimComp; getDimensions(dimI, dimJ, dimK, dimTime, dimComp); const int64_t mapSize = dimI * dimJ * dimK * dimComp; const int64_t numMaps = dimTime; const int64_t dataSize = mapSize * numMaps; if (dataSize <= 0) { dataOut.clear(); return; } dataOut.resize(dataSize); int64_t dataOffset = 0; for (int iMap = 0; iMap < numMaps; iMap++) { const float* mapData = getFrame(iMap); for (int64_t i = 0; i < mapSize; i++) { CaretAssertVectorIndex(dataOut, dataOffset); dataOut[dataOffset] = mapData[i]; ++dataOffset; } } CaretAssert(dataOffset == static_cast(dataOut.size())); } /** * @return Is the data in the file mapped to colors using * a palette. */ bool VolumeFile::isMappedWithPalette() const { CaretAssertVectorIndex(m_caretVolExt.m_attributes, 0); CaretAssert(m_caretVolExt.m_attributes[0] != NULL); bool mapsWithPaletteFlag = true; switch (m_caretVolExt.m_attributes[0]->m_type) { case SubvolumeAttributes::ANATOMY: break; case SubvolumeAttributes::FUNCTIONAL: break; case SubvolumeAttributes::LABEL: mapsWithPaletteFlag = false; break; case SubvolumeAttributes::RGB: mapsWithPaletteFlag = false; break; case SubvolumeAttributes::SEGMENTATION: break; case SubvolumeAttributes::UNKNOWN: break; case SubvolumeAttributes::VECTOR: break; } return mapsWithPaletteFlag; // return (m_caretVolExt.m_attributes[0]->m_type != SubvolumeAttributes::LABEL); } /** * Get the palette normalization modes that are supported by the file. * * @param modesSupportedOut * Palette normalization modes supported by a file. Will be * empty for files that are not mapped with a palette. If there * is more than one suppported mode, the first mode in the * vector is assumed to be the default mode. */ void VolumeFile::getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) const { modesSupportedOut.clear(); if (getDataFileType() == DataFileTypeEnum::VOLUME) { modesSupportedOut.push_back(PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA); modesSupportedOut.push_back(PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA); } else if (getDataFileType() == DataFileTypeEnum::VOLUME_DYNAMIC) { modesSupportedOut.push_back(PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA); } } /** * Get the palette color mapping for the map at the given index. * * @param mapIndex * Index of the map. * @return * Palette color mapping for the map (will be NULL for data * not mapped using a palette). */ PaletteColorMapping* VolumeFile::getMapPaletteColorMapping(const int32_t mapIndex) { CaretAssertVectorIndex(m_caretVolExt.m_attributes, mapIndex); CaretAssert(m_caretVolExt.m_attributes[mapIndex] != NULL); CaretAssert(m_caretVolExt.m_attributes[mapIndex]->m_palette != NULL); return m_caretVolExt.m_attributes[mapIndex]->m_palette; } /** * Get the palette color mapping for the map at the given index. * * @param mapIndex * Index of the map. * @return * Palette color mapping for the map (constant) (will be NULL for data * not mapped using a palette). */ const PaletteColorMapping* VolumeFile::getMapPaletteColorMapping(const int32_t mapIndex) const { CaretAssertVectorIndex(m_caretVolExt.m_attributes, mapIndex); CaretAssert(m_caretVolExt.m_attributes[mapIndex] != NULL); CaretAssert(m_caretVolExt.m_attributes[mapIndex]->m_palette != NULL); return m_caretVolExt.m_attributes[mapIndex]->m_palette; } /** * @return Is the data in the file mapped to colors using * a label table. */ bool VolumeFile::isMappedWithLabelTable() const { CaretAssertVectorIndex(m_caretVolExt.m_attributes, 0); CaretAssert(m_caretVolExt.m_attributes[0] != NULL); return (m_caretVolExt.m_attributes[0]->m_type == SubvolumeAttributes::LABEL); } /** * Get the label table for the map at the given index. * * @param mapIndex * Index of the map. * @return * Label table for the map (will be NULL for data * not mapped using a label table). */ GiftiLabelTable* VolumeFile::getMapLabelTable(const int32_t mapIndex) { CaretAssertVectorIndex(m_caretVolExt.m_attributes, mapIndex); CaretAssert(m_caretVolExt.m_attributes[mapIndex] != NULL); CaretAssert(m_caretVolExt.m_attributes[mapIndex]->m_labelTable != NULL); return m_caretVolExt.m_attributes[mapIndex]->m_labelTable; } /** * Get the label table for the map at the given index. * * @param mapIndex * Index of the map. * @return * Label table for the map (constant) (will be NULL for data * not mapped using a label table). */ const GiftiLabelTable* VolumeFile::getMapLabelTable(const int32_t mapIndex) const { CaretAssertVectorIndex(m_caretVolExt.m_attributes, mapIndex); CaretAssert(m_caretVolExt.m_attributes[mapIndex] != NULL); CaretAssert(m_caretVolExt.m_attributes[mapIndex]->m_labelTable != NULL); return m_caretVolExt.m_attributes[mapIndex]->m_labelTable; } /** * @return Is the data in the file mapped to colors using * Red, Green, Blue, Alpha values. */ bool VolumeFile::isMappedWithRGBA() const { bool mapsWithRgbaFlag = false; switch (m_caretVolExt.m_attributes[0]->m_type) { case SubvolumeAttributes::ANATOMY: break; case SubvolumeAttributes::FUNCTIONAL: break; case SubvolumeAttributes::LABEL: break; case SubvolumeAttributes::RGB: mapsWithRgbaFlag = true; break; case SubvolumeAttributes::SEGMENTATION: break; case SubvolumeAttributes::UNKNOWN: break; case SubvolumeAttributes::VECTOR: break; } return mapsWithRgbaFlag; } /** * Get the unique ID (UUID) for the map at the given index. * * @param mapIndex * Index of the map. * @return * String containing UUID for the map. */ AString VolumeFile::getMapUniqueID(const int32_t mapIndex) const { CaretAssertVectorIndex(m_caretVolExt.m_attributes, mapIndex); return m_caretVolExt.m_attributes[mapIndex]->m_metadata.getUniqueID(); } /** * @return Bounding box of the volumes spatial coordinates. */ void VolumeFile::getVoxelSpaceBoundingBox(BoundingBox& boundingBoxOut) const { boundingBoxOut.resetForUpdate(); float coordinates[3]; const int64_t* dimensions = getDimensionsPtr(); for (int i = 0; i < 2; ++i)//if the volume isn't plumb, we need to test all corners, so just always test all corners { for (int j = 0; j < 2; ++j) { for (int k = 0; k < 2; ++k) { this->indexToSpace(i * dimensions[0] - 0.5f, j * dimensions[1] - 0.5f, k * dimensions[2] - 0.5f, coordinates);//accounts for extra half voxel on each side of each center boundingBoxOut.update(coordinates); } } } } /** * Update coloring for a map. * Does nothing if coloring is not enabled. * * @param mapIndex * Index of map. */ void VolumeFile::updateScalarColoringForMap(const int32_t mapIndex) { if (s_voxelColoringEnabled == false) { return; } CaretAssertVectorIndex(m_caretVolExt.m_attributes, mapIndex); CaretAssert(m_voxelColorizer); m_voxelColorizer->assignVoxelColorsForMap(mapIndex); invalidateHistogramChartColoring(); } /** * Get the voxel RGBA coloring for a map. * Does nothing if coloring is not enabled and output colors are undefined * in this case. * * @param mapIndex * Index of the map. * @param slicePlane * Plane for which colors are requested. * @param sliceIndex * Index of the slice. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbaOut * Contains colors upon exit. * @return * Number of voxels with alpha greater than zero */ int64_t VolumeFile::getVoxelColorsForSliceInMap(const int32_t mapIndex, const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const { if (s_voxelColoringEnabled == false) { return 0; } CaretAssert(m_voxelColorizer); return m_voxelColorizer->getVoxelColorsForSliceInMap(mapIndex, slicePlane, sliceIndex, displayGroup, tabIndex, rgbaOut); } /** * Get voxel coloring for a set of voxels. * * @param mapIndex * Index of map. * @param firstVoxelIJK * IJK Indices of first voxel * @param rowStepIJK * IJK Step for moving to next row. * @param columnStepIJK * IJK Step for moving to next column. * @param numberOfRows * Number of rows. * @param numberOfColumns * Number of columns. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbaOut * RGBA color components out. * @return * Number of voxels with alpha greater than zero */ int64_t VolumeFile::getVoxelColorsForSliceInMap(const int32_t mapIndex, const int64_t firstVoxelIJK[3], const int64_t rowStepIJK[3], const int64_t columnStepIJK[3], const int64_t numberOfRows, const int64_t numberOfColumns, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const { if (s_voxelColoringEnabled == false) { return 0; } CaretAssert(m_voxelColorizer); return m_voxelColorizer->getVoxelColorsForSliceInMap(mapIndex, firstVoxelIJK, rowStepIJK, columnStepIJK, numberOfRows, numberOfColumns, displayGroup, tabIndex, rgbaOut); } /** * Get the voxel colors for a sub slice in the map. * * @param mapIndex * Index of the map. * @param slicePlane * The slice plane. * @param sliceIndex * Index of the slice. * @param firstCornerVoxelIndex * Indices of voxel for first corner of sub-slice (inclusive). * @param lastCornerVoxelIndex * Indices of voxel for last corner of sub-slice (inclusive). * @param voxelCountIJK * Voxel counts for each axis. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbaOut * Output containing the rgba values (must have been allocated * by caller to sufficient count of elements in the slice). * @return * Number of voxels with alpha greater than zero */ int64_t VolumeFile::getVoxelColorsForSubSliceInMap(const int32_t mapIndex, const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, const int64_t firstCornerVoxelIndex[3], const int64_t lastCornerVoxelIndex[3], const int64_t voxelCountIJK[3], const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const { if (s_voxelColoringEnabled == false) { return 0; } CaretAssert(m_voxelColorizer); return m_voxelColorizer->getVoxelColorsForSubSliceInMap(mapIndex, slicePlane, sliceIndex, firstCornerVoxelIndex, lastCornerVoxelIndex, voxelCountIJK, displayGroup, tabIndex, rgbaOut); } /** * Get the voxel values for a slice in a map. * * @param mapIndex * Index of the map. * @param slicePlane * Plane for which colors are requested. * @param sliceIndex * Index of the slice. * @param sliceValuesOut * Slice values output must be correct number of elements. */ void VolumeFile::getVoxelValuesForSliceInMap(const int32_t mapIndex, const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, float* sliceValuesOut) const { CaretAssert(sliceValuesOut); if (s_voxelColoringEnabled == false) { return; } int64_t dimI, dimJ, dimK, dimTime, dimMaps; getDimensions(dimI, dimJ, dimK, dimTime, dimMaps); switch (slicePlane) { case VolumeSliceViewPlaneEnum::ALL: return; break; case VolumeSliceViewPlaneEnum::AXIAL: { int64_t counter = 0; for (int64_t j = 0; j < dimJ; j++) { for (int64_t i = 0; i < dimI; i++) { sliceValuesOut[counter] = getValue(i, j, sliceIndex, 0, mapIndex); counter++; } } } break; case VolumeSliceViewPlaneEnum::CORONAL: { int64_t counter = 0; for (int64_t k = 0; k < dimK; k++) { for (int64_t i = 0; i < dimI; i++) { sliceValuesOut[counter] = getValue(i, sliceIndex, k, 0, mapIndex); counter++; } } } break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: { int64_t counter = 0; for (int64_t k = 0; k < dimK; k++) { for (int64_t j = 0; j < dimJ; j++) { sliceValuesOut[counter] = getValue(sliceIndex, j, k, 0, mapIndex); counter++; } } } break; } } /** * Get the RGBA color components for voxel. * Does nothing if coloring is not enabled and output colors are undefined * in this case. * * @param i * Parasaggital index * @param j * Coronal index * @param k * Axial index * @param mapIndex * Index of map. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbaOut * Contains voxel coloring on exit. */ void VolumeFile::getVoxelColorInMap(const int64_t i, const int64_t j, const int64_t k, const int64_t mapIndex, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t rgbaOut[4]) const { if (s_voxelColoringEnabled == false) { return; } CaretAssert(m_voxelColorizer); m_voxelColorizer->getVoxelColorInMap(i, j, k, mapIndex, displayGroup, tabIndex, rgbaOut); } /** * Clear the voxel coloring for the given map. * Does nothing if coloring is not enabled. * * @param mapIndex * Index of map. */ void VolumeFile::clearVoxelColoringForMap(const int64_t mapIndex) { if (s_voxelColoringEnabled == false) { return; } CaretAssert(m_voxelColorizer); m_voxelColorizer->clearVoxelColoringForMap(mapIndex); if (isMappedWithLabelTable()) { m_forceUpdateOfGroupAndNameHierarchy = true; } } /** * Get the minimum and maximum values from ALL maps in this file. * Note that not all files (due to size of file) are able to provide * the minimum and maximum values from the file. The return value * indicates success/failure. If the failure (false) is returned * the returned values are likely +/- the maximum float values. * * @param dataRangeMinimumOut * Minimum data value found. * @param dataRangeMaximumOut * Maximum data value found. * @return * True if the values are valid, else false. */ bool VolumeFile::getDataRangeFromAllMaps(float& dataRangeMinimumOut, float& dataRangeMaximumOut) const { /* * No data? */ if (isEmpty()) { dataRangeMaximumOut = std::numeric_limits::max(); dataRangeMinimumOut = -dataRangeMaximumOut; return false; } /* * If valid, no need to update */ if (m_dataRangeValid) { dataRangeMinimumOut = m_dataRangeMinimum; dataRangeMaximumOut = m_dataRangeMaximum; return true; } /* * Update range. */ m_dataRangeMaximum = -std::numeric_limits::max(); m_dataRangeMinimum = std::numeric_limits::max(); const int64_t* dimensions = getDimensionsPtr(); int64_t m_dataSize = dimensions[0] * dimensions[1] * dimensions[2] * dimensions[3] * dimensions[4]; const float* data = getFrame();//HACK: use first frame knowing all data is contiguous after it for (int64_t i = 0; i < m_dataSize; i++) { if (data[i] > m_dataRangeMaximum) { m_dataRangeMaximum = data[i]; } if (data[i] < m_dataRangeMinimum) { m_dataRangeMinimum = data[i]; } } dataRangeMinimumOut = m_dataRangeMinimum; dataRangeMaximumOut = m_dataRangeMaximum; m_dataRangeValid = true; return true; } /** * Get the voxel indices of all voxels in the given map with the given label key. * * @param mapIndex * Index of map. * @param labelKey * Key of the label. * @param voxelIndicesOut * Output containing indices of voxels with the given label key. */ void VolumeFile::getVoxelIndicesWithLabelKey(const int32_t mapIndex, const int32_t labelKey, std::vector& voxelIndicesOut) const { voxelIndicesOut.clear(); std::vector dims; getDimensions(dims); const int64_t dimI = dims[0]; const int64_t dimJ = dims[1]; const int64_t dimK = dims[2]; for (int64_t i = 0; i < dimI; i++) { for (int64_t j = 0; j < dimJ; j++) { for (int64_t k = 0; k < dimK; k++) { const float keyValue = static_cast(getValue(i, j, k, mapIndex)); if (keyValue == labelKey) { voxelIndicesOut.push_back(VoxelIJK(i, j, k)); } } } } } /** * Get the unique label keys in the given map. * @param mapIndex * Index of the map. * @return * Keys used by the map. */ std::vector VolumeFile::getUniqueLabelKeysUsedInMap(const int32_t mapIndex) const { std::vector dims; getDimensions(dims); const int64_t dimI = dims[0]; const int64_t dimJ = dims[1]; const int64_t dimK = dims[2]; std::set uniqueKeys; for (int64_t i = 0; i < dimI; i++) { for (int64_t j = 0; j < dimJ; j++) { for (int64_t k = 0; k < dimK; k++) { const float keyValue = static_cast(getValue(i, j, k, mapIndex)); uniqueKeys.insert(keyValue); } } } std::vector keyVector; keyVector.insert(keyVector.end(), uniqueKeys.begin(), uniqueKeys.end()); return keyVector; } /** * @return The class and name hierarchy. */ GroupAndNameHierarchyModel* VolumeFile::getGroupAndNameHierarchyModel() { m_classNameHierarchy->update(this, m_forceUpdateOfGroupAndNameHierarchy); m_forceUpdateOfGroupAndNameHierarchy = false; return m_classNameHierarchy; } /** * @return The class and name hierarchy. */ const GroupAndNameHierarchyModel* VolumeFile::getGroupAndNameHierarchyModel() const { m_classNameHierarchy->update(const_cast(this), m_forceUpdateOfGroupAndNameHierarchy); m_forceUpdateOfGroupAndNameHierarchy = false; return m_classNameHierarchy; } /** * @return The volume file editor delegate used for interactive * editing of a volume's voxels. */ VolumeFileEditorDelegate* VolumeFile::getVolumeFileEditorDelegate() { CaretAssert(m_volumeFileEditorDelegate); return m_volumeFileEditorDelegate; } /** * Save file data from the scene. For subclasses that need to * save to a scene, this method should be overriden. sceneClass * will be valid and any scene data should be added to it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass to which data members should be added. */ void VolumeFile::saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass) { CaretMappableDataFile::saveFileDataToScene(sceneAttributes, sceneClass); sceneClass->addBooleanArray("m_chartingEnabledForTab", m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); if (isMappedWithLabelTable()) { sceneClass->addClass(m_classNameHierarchy->saveToScene(sceneAttributes, "m_classNameHierarchy")); } if (m_lazyInitializedDynamicConnectivityFile != NULL) { sceneClass->addClass(m_lazyInitializedDynamicConnectivityFile->saveToScene(sceneAttributes, "m_lazyInitializedDynamicConnectivityFile")); } } /** * Restore file data from the scene. For subclasses that need to * restore from a scene, this method should be overridden. The scene class * will be valid and any scene data may be obtained from it. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass for the instance of a class that implements * this interface. Will NEVER be NULL. */ void VolumeFile::restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { CaretMappableDataFile::restoreFileDataFromScene(sceneAttributes, sceneClass); const ScenePrimitiveArray* tabArray = sceneClass->getPrimitiveArray("m_chartingEnabledForTab"); if (tabArray != NULL) { sceneClass->getBooleanArrayValue("m_chartingEnabledForTab", m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS); } else { for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; i++) { m_chartingEnabledForTab[i] = false; } } if (isMappedWithLabelTable()) { const SceneClass* sc = sceneClass->getClass("m_classNameHierarchy"); m_classNameHierarchy->restoreFromScene(sceneAttributes, sc); m_forceUpdateOfGroupAndNameHierarchy = false; } const SceneClass* dynamicFileSceneClass = sceneClass->getClass("m_lazyInitializedDynamicConnectivityFile"); if (dynamicFileSceneClass != NULL) { VolumeDynamicConnectivityFile* denseDynamicFile = getVolumeDynamicConnectivityFile(); denseDynamicFile->restoreFromScene(sceneAttributes, dynamicFileSceneClass); } } /** * Add information about the file to the data file information. * * @param dataFileInformation * Consolidates information about a data file. */ void VolumeFile::addToDataFileContentInformation(DataFileContentInformation& dataFileInformation) { CaretMappableDataFile::addToDataFileContentInformation(dataFileInformation); dataFileInformation.addNameAndValue("Orthogonal", isPlumb()); if (m_header != NULL && m_header->getType() == AbstractHeader::NIFTI) { const NiftiHeader& myHeader = *((NiftiHeader*)m_header.getPointer()); dataFileInformation.addNameAndValue("NIFTI Version", myHeader.version()); bool ok = false; dataFileInformation.addNameAndValue("NIFTI Data Type", NiftiDataTypeEnum::toName(NiftiDataTypeEnum::fromIntegerCode(myHeader.getDataType(), &ok)));//fromIntegerCode basically just ignores invalid values if (!ok) { CaretLogWarning("found invalid NIFTI datatype code while adding file information"); } } AString dimString; vector dims = getOriginalDimensions(); for (int i = 0; i < (int)dims.size(); ++i) { if (i != 0) dimString += ", "; dimString += AString::number(dims[i]); } dataFileInformation.addNameAndValue("Dimensions", dimString); if (dims.size() >= 3) { const int64_t maxI((dims[0] > 1) ? dims[0] - 1 : 0); const int64_t maxJ((dims[1] > 1) ? dims[1] - 1 : 0); const int64_t maxK((dims[2] > 1) ? dims[2] - 1 : 0); int64_t corners[8][3] = { { 0, 0, 0 }, { maxI, 0, 0 }, { maxI, maxJ, 0 }, { 0, maxJ, 0}, { 0, 0, maxK }, { maxI, 0, maxK }, { maxI, maxJ, maxK }, { 0, maxJ, maxK} }; for (int32_t m = 0; m < 8; m++) { const int64_t i(corners[m][0]); const int64_t j(corners[m][1]); const int64_t k(corners[m][2]); if (indexValid(i, j, k)) { float x, y, z; indexToSpace(i, j, k, x, y, z); dataFileInformation.addNameAndValue("IJK = (" + AString::number(i) + "," + AString::number(j) + "," + AString::number(k) + ")", ("XYZ = (" + AString::number(x) + ", " + AString::number(y) + ", " + AString::number(z) + ")")); } } } const std::vector>& sform = getVolumeSpace().getSform(); QString sformName("sform"); for (const auto& row : sform) { AString s; for (const auto element : row) { s.append(AString::number(element, 'f', 6) + " "); } dataFileInformation.addNameAndValue(sformName, s); sformName.clear(); } BoundingBox boundingBox; getVoxelSpaceBoundingBox(boundingBox); dataFileInformation.addNameAndValue("X-minimum", boundingBox.getMinX()); dataFileInformation.addNameAndValue("X-maximum", boundingBox.getMaxX()); dataFileInformation.addNameAndValue("Y-minimum", boundingBox.getMinY()); dataFileInformation.addNameAndValue("Y-maximum", boundingBox.getMaxY()); dataFileInformation.addNameAndValue("Z-minimum", boundingBox.getMinZ()); dataFileInformation.addNameAndValue("Z-maximum", boundingBox.getMaxZ()); VolumeSpace::OrientTypes orientation[3]; getOrientation(orientation); for (int32_t i = 0; i < 3; i++) { AString orientName; switch (orientation[i]) { case VolumeSpace::ANTERIOR_TO_POSTERIOR: orientName = "Anterior to Posterior"; break; case VolumeSpace::INFERIOR_TO_SUPERIOR: orientName = "Inferior to Superior"; break; case VolumeSpace::LEFT_TO_RIGHT: orientName = "Left to Right"; break; case VolumeSpace::POSTERIOR_TO_ANTERIOR: orientName = "Posterior to Anterior"; break; case VolumeSpace::RIGHT_TO_LEFT: orientName = "Right to Left"; break; case VolumeSpace::SUPERIOR_TO_INFERIOR: orientName = "Superior to Inferior"; break; } dataFileInformation.addNameAndValue(("Orientation[" + AString::number(i) + "]"), orientName); } float spacing[3]; getVoxelSpacing(spacing[0], spacing[1], spacing[2]); spacing[0] = std::fabs(spacing[0]); spacing[1] = std::fabs(spacing[1]); spacing[2] = std::fabs(spacing[2]); dataFileInformation.addNameAndValue("Spacing", AString::fromNumbers(spacing, 3, ", ")); } /** * @return Is charting enabled for this file? */ bool VolumeFile::isLineSeriesChartingEnabled(const int32_t tabIndex) const { CaretAssertArrayIndex(m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); return m_chartingEnabledForTab[tabIndex]; } /** * @return Return true if the file's current state supports * charting data, else false. Typically a brainordinate file * is chartable if it contains more than one map. */ bool VolumeFile::isLineSeriesChartingSupported() const { if (getNumberOfMaps() > 1) { return true; } return false; } /** * Set charting enabled for this file. * * @param enabled * New status for charting enabled. */ void VolumeFile::setLineSeriesChartingEnabled(const int32_t tabIndex, const bool enabled) { CaretAssertArrayIndex(m_chartingEnabledForTab, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, tabIndex); m_chartingEnabledForTab[tabIndex] = enabled; } /** * Get chart data types supported by the file. * * @param chartDataTypesOut * Chart types supported by this file. */ void VolumeFile::getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const { helpGetSupportedLineSeriesChartDataTypes(chartDataTypesOut); } /** * Load charting data for the surface with the given structure and node index. * * @param structure * The surface's structure. * @param nodeIndex * Index of the node. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* VolumeFile::loadLineSeriesChartDataForSurfaceNode(const StructureEnum::Enum /*structure*/, const int32_t /*nodeIndex*/) { ChartDataCartesian* chartData = NULL; return chartData; } /** * Load average charting data for the surface with the given structure and node indices. * * @param structure * The surface's structure. * @param nodeIndices * Indices of the node. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* VolumeFile::loadAverageLineSeriesChartDataForSurfaceNodes(const StructureEnum::Enum /*structure*/, const std::vector& /*nodeIndices*/) { ChartDataCartesian* chartData = NULL; return chartData; } /** * Load charting data for the voxel enclosing the given coordinate. * * @param xyz * Coordinate of voxel. * @return * Pointer to the chart data. If the data FAILED to load, * the returned pointer will be NULL. Caller takes ownership * of the pointer and must delete it when no longer needed. */ ChartDataCartesian* VolumeFile::loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]) { ChartDataCartesian* chartData = NULL; if (isMappedWithPalette()) { int64_t ijk[3]; enclosingVoxel(xyz, ijk); if (indexValid(ijk)) { std::vector data; const int32_t numMaps = getNumberOfMaps(); for (int32_t iMap = 0; iMap < numMaps; iMap++) { data.push_back(getValue(ijk, iMap)); } try { chartData = helpCreateCartesianChartData(data); ChartDataSource* dataSource = chartData->getChartDataSource(); dataSource->setVolumeVoxel(getFileName(), xyz); } catch (const DataFileException& dfe) { if (chartData != NULL) { delete chartData; chartData = NULL; } throw dfe; } } } return chartData; } /** * Get data from the file as requested in the given map file data selector. * * @param mapFileDataSelector * Specifies selection of data. * @param dataOut * Output with data. Will be empty if data does not support the map file data selector. */ void VolumeFile::getDataForSelector(const MapFileDataSelector& mapFileDataSelector, std::vector& dataOut) const { dataOut.clear(); switch (mapFileDataSelector.getDataSelectionType()) { case MapFileDataSelector::DataSelectionType::INVALID: break; case MapFileDataSelector::DataSelectionType::COLUMN_DATA: break; case MapFileDataSelector::DataSelectionType::ROW_DATA: break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTEX: break; case MapFileDataSelector::DataSelectionType::SURFACE_VERTICES_AVERAGE: break; case MapFileDataSelector::DataSelectionType::VOLUME_XYZ: { if (isMappedWithPalette()) { float xyz[3]; mapFileDataSelector.getVolumeVoxelXYZ(xyz); int64_t ijk[3]; enclosingVoxel(xyz, ijk); if (indexValid(ijk)) { const int32_t numMaps = getNumberOfMaps(); for (int32_t iMap = 0; iMap < numMaps; iMap++) { dataOut.push_back(getValue(ijk, iMap)); } } } } break; } } /** * Are all brainordinates in this file also in the given file? * That is, the brainordinates are equal to or a subset of the brainordinates * in the given file. * * @param mapFile * The given map file. * @return * Match status. */ CaretMappableDataFile::BrainordinateMappingMatch VolumeFile::getBrainordinateMappingMatch(const CaretMappableDataFile* mapFile) const { CaretAssert(mapFile); if (mapFile->getDataFileType() == DataFileTypeEnum::VOLUME) { const VolumeFile* otherVolumeFile = dynamic_cast(mapFile); CaretAssert(otherVolumeFile); std::vector myDims, otherDims; getDimensions(myDims); otherVolumeFile->getDimensions(otherDims); for (int32_t i = 0; i < 3; i++) { CaretAssertVectorIndex(myDims, i); CaretAssertVectorIndex(otherDims, i); if (myDims[i] != otherDims[i]) { return BrainordinateMappingMatch::NO; } } return BrainordinateMappingMatch::EQUAL; } return BrainordinateMappingMatch::NO; } /** * Get the identification information for a surface node in the given maps. * * @param mapIndices * Indices of maps for which identification information is requested. * @param xyz * Coordinate of voxel. * @param ijkOut * Voxel indices of value. * @param textOut * Output containing identification information. */ bool VolumeFile::getVolumeVoxelIdentificationForMaps(const std::vector& mapIndices, const float xyz[3], int64_t ijkOut[3], AString& textOut) const { float floatIJK[3]; spaceToIndex(xyz, floatIJK); ijkOut[0] = floatIJK[0]; ijkOut[1] = floatIJK[1]; ijkOut[2] = floatIJK[2]; bool anyValidFlag = false; AString valuesText; for (const auto mapIndex : mapIndices) { if ( ! valuesText.isEmpty()) { valuesText.append(", "); } bool validFlag(false); const float value = getVoxelValue(xyz, &validFlag, mapIndex); if (validFlag) { anyValidFlag = true; if (isMappedWithLabelTable()) { const GiftiLabelTable* labelTable = getMapLabelTable(mapIndex); CaretAssert(labelTable); const int32_t key = static_cast(value); const GiftiLabel* label = labelTable->getLabel(key); if (label != NULL) { valuesText.append(label->getName()); } else { valuesText.append("?"); } } else { valuesText.append(AString::number(value, 'f', 3)); } } else { valuesText.append("invalid"); } } if (anyValidFlag) { textOut = valuesText; return true; } return false; } /** * @return The units for the 'interval' between two consecutive maps. */ NiftiTimeUnitsEnum::Enum VolumeFile::getMapIntervalUnits() const { NiftiTimeUnitsEnum::Enum units = NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN; if (m_header != NULL && m_header->getType() == AbstractHeader::NIFTI) { const NiftiHeader& myHeader = *((NiftiHeader*)m_header.getPointer()); std::vector dims; getDimensions(dims); if (dims.size() >= 4) { if (dims[3] > 1) { /* * Timestep from NiftiHeader is always seconds */ const float timeStep = myHeader.getTimeStep(); if (timeStep > 0.0) { units = NiftiTimeUnitsEnum::NIFTI_UNITS_SEC; } } } } return units; } /** * Get the units value for the first map and the * quantity of units between consecutive maps. If the * units for the maps is unknown, value of one (1) are * returned for both output values. * * @param firstMapUnitsValueOut * Output containing units value for first map. * @param mapIntervalStepValueOut * Output containing number of units between consecutive maps. */ void VolumeFile::getMapIntervalStartAndStep(float& firstMapUnitsValueOut, float& mapIntervalStepValueOut) const { firstMapUnitsValueOut = 0.0; mapIntervalStepValueOut = 1.0; if (m_header != NULL && m_header->getType() == AbstractHeader::NIFTI) { const NiftiHeader& myHeader = *((NiftiHeader*)m_header.getPointer()); std::vector dims; getDimensions(dims); if (dims.size() >= 4) { if (dims[3] > 1) { /* * Timestep from NiftiHeader is always seconds */ const float timeStep = myHeader.getTimeStep(); if (timeStep > 0.0) { mapIntervalStepValueOut = timeStep; } } } } } /** * @return The volume dynamic connectivity file for a data-series (functional) file * that contains at least two time points. Note that some files may * have type anatomy but still contain functional data. * Will return NULL for other types. */ const VolumeDynamicConnectivityFile* VolumeFile::getVolumeDynamicConnectivityFile() const { VolumeFile* nonConstThis = const_cast(this); return nonConstThis->getVolumeDynamicConnectivityFile(); } /** * @return The volume dynamic connectivity file for a data-series (functional) file * that contains at least two time points. Note that some files may * have type anatomy but still contain functional data. * Will return NULL for other types. */ VolumeDynamicConnectivityFile* VolumeFile::getVolumeDynamicConnectivityFile() { if (m_lazyInitializedDynamicConnectivityFile == NULL) { if ((getType() == SubvolumeAttributes::ANATOMY) || (getType() == SubvolumeAttributes::FUNCTIONAL)) { std::vector dims; getDimensions(dims); if (dims.size() >= 4) { const int64_t minimumNumberOfTimePoints(8); if (dims[3] > minimumNumberOfTimePoints) { m_lazyInitializedDynamicConnectivityFile.reset(new VolumeDynamicConnectivityFile(this)); m_lazyInitializedDynamicConnectivityFile->initializeFile(); /* * Palette for dynamic file is in file metadata */ GiftiMetaData* fileMetaData = getFileMetaData(); const AString encodedPaletteColorMappingString = fileMetaData->get(s_paletteColorMappingNameInMetaData); if ( ! encodedPaletteColorMappingString.isEmpty()) { if (m_lazyInitializedDynamicConnectivityFile->getNumberOfMaps() > 0) { PaletteColorMapping* pcm = m_lazyInitializedDynamicConnectivityFile->getMapPaletteColorMapping(0); CaretAssert(pcm); pcm->decodeFromStringXML(encodedPaletteColorMappingString); } } m_lazyInitializedDynamicConnectivityFile->clearModified(); } } } } return m_lazyInitializedDynamicConnectivityFile.get(); } /** * @return True if any of the maps in this file contain a * color mapping that possesses a modified status. */ bool VolumeFile::isModifiedPaletteColorMapping() const { /* * This method is override because we need to know if the * encapsulated dynamic dense file has a modified palette. * When restoring a scene, a file with any type of modification * must be reloaded to remove any modifications. Note that * when a scene is restored, files that are not modified and * are in the new scene are NOT reloaded to save time. */ if (CaretMappableDataFile::isModifiedPaletteColorMapping()) { return true; } if (m_lazyInitializedDynamicConnectivityFile != NULL) { if (m_lazyInitializedDynamicConnectivityFile->isModifiedPaletteColorMapping()) { return true; } } return false; } /** * @return The modified status for aall palettes in this file. * Note that 'modified' overrides any 'modified by show scene'. */ PaletteModifiedStatusEnum::Enum VolumeFile::getPaletteColorMappingModifiedStatus() const { const std::array fileModStatus = { { CaretMappableDataFile::getPaletteColorMappingModifiedStatus(), ((m_lazyInitializedDynamicConnectivityFile != NULL) ? m_lazyInitializedDynamicConnectivityFile->getPaletteColorMappingModifiedStatus() : PaletteModifiedStatusEnum::UNMODIFIED) } }; PaletteModifiedStatusEnum::Enum modStatus = PaletteModifiedStatusEnum::UNMODIFIED; for (auto status : fileModStatus) { switch (status) { case PaletteModifiedStatusEnum::MODIFIED: modStatus = PaletteModifiedStatusEnum::MODIFIED; break; case PaletteModifiedStatusEnum::MODIFIED_BY_SHOW_SCENE: modStatus = PaletteModifiedStatusEnum::MODIFIED_BY_SHOW_SCENE; break; case PaletteModifiedStatusEnum::UNMODIFIED: break; } if (modStatus == PaletteModifiedStatusEnum::MODIFIED) { /* * 'MODIFIED' overrides 'MODIFIED_BY_SHOW_SCENE' * so no need to continue loop */ break; } } return modStatus; } connectome-workbench-1.4.2/src/Files/VolumeFile.h000066400000000000000000000446471360521144700217230ustar00rootroot00000000000000 #ifndef __VOLUME_FILE_H__ #define __VOLUME_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "VolumeBase.h" #include "CaretMappableDataFile.h" #include "CaretMutex.h" #include "CaretVolumeExtension.h" #include "ChartableLineSeriesBrainordinateInterface.h" #include "StructureEnum.h" #include "GiftiMetaData.h" #include "BoundingBox.h" #include "VolumeFileVoxelColorizer.h" #include "VoxelIJK.h" namespace caret { class GroupAndNameHierarchyModel; class VolumeDynamicConnectivityFile; class VolumeFileEditorDelegate; class VolumeFileVoxelColorizer; class VolumeSpline; class VolumeFile : public VolumeBase, public CaretMappableDataFile, public ChartableLineSeriesBrainordinateInterface { VolumeFile(const VolumeFile&); VolumeFile& operator=(const VolumeFile&); CaretVolumeExtension m_caretVolExt; void parseExtensions();//called after reading a file, in order to populate m_caretVolExt with best guesses void validateMembers();//called to ensure extension agrees with number of subvolumes void updateCaretExtension();//called before writing a file, erases all existing caret extensions from m_extensions, and rebuilds one from m_caretVolExt void checkStatisticsValid(); struct BrickAttributes//for storing ONLY stuff that doesn't get saved to the caret extension {//TODO: prune this once statistics gets straightened out CaretPointer m_fastStatistics; CaretPointer m_histogram; int32_t m_histogramNumberOfBuckets = 100; CaretPointer m_histogramLimitedValues; int32_t m_histogramLimitedValuesNumberOfBuckets = 100; float m_histogramLimitedValuesMostPositiveValueInclusive; float m_histogramLimitedValuesLeastPositiveValueInclusive; float m_histogramLimitedValuesLeastNegativeValueInclusive; float m_histogramLimitedValuesMostNegativeValueInclusive; bool m_histogramLimitedValuesIncludeZeroValues; }; mutable std::vector m_brickAttributes;//because statistics and metadata construct lazily bool m_brickStatisticsValid;//so that setModified() doesn't do something slow /** Fast statistics used when statistics computed on all data in file */ CaretPointer m_fileFastStatistics; /** Histogram used when statistics computed on all data in file */ CaretPointer m_fileHistogram; int32_t m_fileHistogramNumberOfBuckets = 100; /** Histogram with limited values used when statistics computed on all data in file */ CaretPointer m_fileHistorgramLimitedValues; int32_t m_fileHistogramLimitedValuesNumberOfBuckets; float m_fileHistogramLimitedValuesMostPositiveValueInclusive; float m_fileHistogramLimitedValuesLeastPositiveValueInclusive; float m_fileHistogramLimitedValuesLeastNegativeValueInclusive; float m_fileHistogramLimitedValuesMostNegativeValueInclusive; bool m_fileHistogramLimitedValuesIncludeZeroValues; /** Performs coloring of voxels. Will be NULL if coloring is disabled. */ CaretPointer m_voxelColorizer; std::unique_ptr m_lazyInitializedDynamicConnectivityFile; /** True if the volume is a single slice, needed by interpolateValue() methods */ bool m_singleSliceFlag; mutable CaretMutex m_splineMutex; mutable bool m_splinesValid; mutable std::vector m_frameSplineValid; mutable std::vector m_frameSplines; bool m_chartingEnabledForTab[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; mutable bool m_dataRangeValid; mutable float m_dataRangeMinimum; mutable float m_dataRangeMaximum; /** Holds class and name hierarchy used for display selection */ mutable CaretPointer m_classNameHierarchy; /** force an update of the class and name hierarchy */ mutable bool m_forceUpdateOfGroupAndNameHierarchy; CaretPointer m_volumeFileEditorDelegate; static const AString s_paletteColorMappingNameInMetaData; protected: VolumeFile(const DataFileTypeEnum::Enum dataFileType); virtual void saveFileDataToScene(const SceneAttributes* sceneAttributes, SceneClass* sceneClass); virtual void restoreFileDataFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); public: enum InterpType { ENCLOSING_VOXEL, TRILINEAR, CUBIC }; const static float INVALID_INTERP_VALUE; /** Enables coloring. Coloring is almost always not needed for command line operations */ static bool s_voxelColoringEnabled; static void setVoxelColoringEnabled(const bool enabled); VolumeFile(); VolumeFile(const std::vector& dimensionsIn, const std::vector >& indexToSpace, const int64_t numComponents = 1, SubvolumeAttributes::VolumeType whatType = SubvolumeAttributes::ANATOMY, const AbstractHeader* templateHeader = NULL); ~VolumeFile(); virtual void clear(); virtual void addToDataFileContentInformation(DataFileContentInformation& dataFileInformation); ///recreates the volume file storage with new size and spacing void reinitialize(const std::vector& dimensionsIn, const std::vector >& indexToSpace, const int64_t numComponents = 1, SubvolumeAttributes::VolumeType whatType = SubvolumeAttributes::ANATOMY, const AbstractHeader* templateHeader = NULL); ///convenient version for 3D or 4D from a VolumeSpace void reinitialize(const VolumeSpace& volSpaceIn, const int64_t numFrames = 1, const int64_t numComponents = 1, SubvolumeAttributes::VolumeType whatType = SubvolumeAttributes::ANATOMY, const AbstractHeader* templateHeader = NULL); ///another convenience version for taking spatial dims, spacing, type and header from existing file void reinitialize(const VolumeFile* headerTemplate, const int64_t numFrames = 1, const int64_t numComponents = 1); void addSubvolumes(const int64_t& numToAdd); void setType(SubvolumeAttributes::VolumeType whatType); SubvolumeAttributes::VolumeType getType() const; void validateSpline(const int64_t brickIndex = 0, const int64_t component = 0) const; void freeSpline(const int64_t brickIndex = 0, const int64_t component = 0) const; float interpolateValue(const float* coordIn, InterpType interp = TRILINEAR, bool* validOut = NULL, const int64_t brickIndex = 0, const int64_t component = 0) const; float interpolateValue(const float coordIn1, const float coordIn2, const float coordIn3, InterpType interp = TRILINEAR, bool* validOut = NULL, const int64_t brickIndex = 0, const int64_t component = 0) const; ///returns true if volume space matches in spatial dimensions and sform bool matchesVolumeSpace(const VolumeFile* right) const; ///returns true if volume space matches in spatial dimensions and sform bool matchesVolumeSpace(const VolumeSpace& otherSpace) const; ///returns true if volume space matches in spatial dimensions and sform bool matchesVolumeSpace(const int64_t dims[3], const std::vector >& sform) const; virtual void readFile(const AString& filename); virtual void writeFile(const AString& filename); bool isEmpty() const { return VolumeBase::isEmpty(); } bool hasGoodSpatialInformation() const; virtual void setModified(); virtual void clearModified(); virtual bool isModifiedExcludingPaletteColorMapping() const; void getVoxelSpaceBoundingBox(BoundingBox& boundingBoxOut) const override; /** * @return The structure for this file. */ StructureEnum::Enum getStructure() const; /** * Set the structure for this file. * @param structure * New structure for this file. */ void setStructure(const StructureEnum::Enum structure); /** * @return Get access to the file's metadata. */ GiftiMetaData* getFileMetaData(); /** * @return Get access to unmodifiable file's metadata. */ const GiftiMetaData* getFileMetaData() const; bool isSurfaceMappable() const { return false; } bool isVolumeMappable() const { return true; } int32_t getNumberOfMaps() const { return getDimensionsPtr()[3]; } AString getMapName(const int32_t mapIndex) const; void setMapName(const int32_t mapIndex, const AString& mapName); const GiftiMetaData* getMapMetaData(const int32_t mapIndex) const; GiftiMetaData* getMapMetaData(const int32_t mapIndex); const FastStatistics* getMapFastStatistics(const int32_t mapIndex); const Histogram* getMapHistogram(const int32_t mapIndex); const Histogram* getMapHistogram(const int32_t mapIndex, const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues); virtual int64_t getDataSizeUncompressedInBytes() const; virtual const FastStatistics* getFileFastStatistics(); virtual const Histogram* getFileHistogram(); virtual const Histogram* getFileHistogram(const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues); void getFileData(std::vector& dataOut) const; bool isMappedWithPalette() const; virtual void getPaletteNormalizationModesSupported(std::vector& modesSupportedOut) const; PaletteColorMapping* getMapPaletteColorMapping(const int32_t mapIndex); const PaletteColorMapping* getMapPaletteColorMapping(const int32_t mapIndex) const; bool isMappedWithLabelTable() const; GiftiLabelTable* getMapLabelTable(const int32_t mapIndex); const GiftiLabelTable* getMapLabelTable(const int32_t mapIndex) const; void getVoxelIndicesWithLabelKey(const int32_t mapIndex, const int32_t labelKey, std::vector& voxelIndicesOut) const; std::vector getUniqueLabelKeysUsedInMap(const int32_t mapIndex) const; virtual bool isMappedWithRGBA() const; AString getMapUniqueID(const int32_t mapIndex) const; void updateScalarColoringForMap(const int32_t mapIndex) override; virtual int64_t getVoxelColorsForSliceInMap(const int32_t mapIndex, const int64_t firstVoxelIJK[3], const int64_t rowStepIJK[3], const int64_t columnStepIJK[3], const int64_t numberOfRows, const int64_t numberOfColumns, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const override; virtual int64_t getVoxelColorsForSliceInMap( const int32_t mapIndex, const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const override; virtual int64_t getVoxelColorsForSubSliceInMap( const int32_t mapIndex, const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, const int64_t firstCornerVoxelIndex[3], const int64_t lastCornerVoxelIndex[3], const int64_t voxelCountIJK[3], const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const override; void getVoxelValuesForSliceInMap(const int32_t mapIndex, const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, float* sliceValues) const; void getVoxelColorInMap(const int64_t i, const int64_t j, const int64_t k, const int64_t mapIndex, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t rgbaOut[4]) const override; void clearVoxelColoringForMap(const int64_t mapIndex); virtual bool getDataRangeFromAllMaps(float& dataRangeMinimumOut, float& dataRangeMaximumOut) const; GroupAndNameHierarchyModel* getGroupAndNameHierarchyModel(); const GroupAndNameHierarchyModel* getGroupAndNameHierarchyModel() const; VolumeFileEditorDelegate* getVolumeFileEditorDelegate(); virtual bool isLineSeriesChartingEnabled(const int32_t tabIndex) const; virtual void setLineSeriesChartingEnabled(const int32_t tabIndex, const bool enabled); virtual bool isLineSeriesChartingSupported() const; virtual ChartDataCartesian* loadLineSeriesChartDataForSurfaceNode(const StructureEnum::Enum structure, const int32_t nodeIndex); virtual ChartDataCartesian* loadAverageLineSeriesChartDataForSurfaceNodes(const StructureEnum::Enum structure, const std::vector& nodeIndices); virtual ChartDataCartesian* loadLineSeriesChartDataForVoxelAtCoordinate(const float xyz[3]); virtual void getSupportedLineSeriesChartDataTypes(std::vector& chartDataTypesOut) const; virtual void getDataForSelector(const MapFileDataSelector& mapFileDataSelector, std::vector& dataOut) const override; virtual BrainordinateMappingMatch getBrainordinateMappingMatch(const CaretMappableDataFile* mapFile) const override; virtual bool getVolumeVoxelIdentificationForMaps(const std::vector& mapIndices, const float xyz[3], int64_t ijkOut[3], AString& textOut) const; virtual NiftiTimeUnitsEnum::Enum getMapIntervalUnits() const override; virtual void getMapIntervalStartAndStep(float& firstMapUnitsValueOut, float& mapIntervalStepValueOut) const override; VolumeDynamicConnectivityFile* getVolumeDynamicConnectivityFile(); const VolumeDynamicConnectivityFile* getVolumeDynamicConnectivityFile() const; virtual bool isModifiedPaletteColorMapping() const override; virtual PaletteModifiedStatusEnum::Enum getPaletteColorMappingModifiedStatus() const override; }; } #endif //__VOLUME_FILE_H__ connectome-workbench-1.4.2/src/Files/VolumeFileEditorDelegate.cxx000066400000000000000000001266211360521144700250710ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __VOLUME_FILE_EDITOR_DELEGATE_DECLARE__ #include "VolumeFileEditorDelegate.h" #undef __VOLUME_FILE_EDITOR_DELEGATE_DECLARE__ #include "CaretAssert.h" #include "CaretPointer.h" #include "CaretUndoStack.h" #include "Matrix4x4.h" #include "VolumeFile.h" #include "VolumeMapUndoCommand.h" #include "VoxelIJK.h" using namespace caret; /** * \class caret::VolumeFileEditorDelegate * \brief Delegate for performing editing operations on a volume file's voxels. * \ingroup Files * * Perform interactive editing operations in a GUI on a volume file * including the ability to undo, redo, and reset the editing operations. */ /** * Constructor. * * @param volumeFile * Volume that 'owns' this editor and on which editing is performed. */ VolumeFileEditorDelegate::VolumeFileEditorDelegate(VolumeFile* volumeFile) : CaretObject(), m_volumeFile(volumeFile) { CaretAssert(volumeFile); m_volumeDimensions[0] = 0; m_volumeDimensions[1] = 0; m_volumeDimensions[2] = 0; updateIfVolumeFileChangedNumberOfMaps(); } /** * Destructor. */ VolumeFileEditorDelegate::~VolumeFileEditorDelegate() { clear(); } /** * Clear the instance. */ void VolumeFileEditorDelegate::clear() { /* * The undo stacks are only created when needed so some * entries may be NULL */ for (std::vector::iterator mapIter = m_volumeMapUndoStacks.begin(); mapIter != m_volumeMapUndoStacks.end(); mapIter++) { CaretUndoStack* undoStack = *mapIter; delete undoStack; } m_volumeMapUndoStacks.clear(); m_volumeDimensions[0] = 0; m_volumeDimensions[1] = 0; m_volumeDimensions[2] = 0; m_volumeMapEditingLocked.clear(); } /** * Perform an editing operation. * * @param mapIndex * Index of map (brick) within the volume that is being edited. * @param mode * The editing mode. * @param slicePlane * The selected slice plane. * @param voxelIJK * Indices of voxel selected by the user. * @param brushSize * Size of brush used by some operations. * @param voxelValueOn * Value that is assigned by a "turn on" operation. * @param voxelValueOff * Value that is assigned by a "turn off" operation. * @param errorMessageOut * Will contain error information. * @return * True if successful, else false and errorMessageOut will be set. */ bool VolumeFileEditorDelegate::performEditingOperation(const int64_t mapIndex, const VolumeEditingModeEnum::Enum mode, const VolumeSliceViewPlaneEnum::Enum slicePlane, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const Matrix4x4& obliqueRotationMatrix, const float voxelDiffXYZ[3], const int64_t voxelIJK[3], const int64_t brushSize[3], const float voxelValueOn, const float voxelValueOff, AString& errorMessageOut) { errorMessageOut.clear(); CaretAssert(m_volumeFile); int64_t dimNumComponents = 0; int64_t dimNumMaps = 0; m_volumeFile->getDimensions(m_volumeDimensions[0], m_volumeDimensions[1], m_volumeDimensions[2], dimNumMaps, dimNumComponents); if ((mapIndex < 0) || (mapIndex >= dimNumMaps)) { errorMessageOut = ("Invalid map index=" + AString::number(mapIndex) + ", number of maps=" + AString::number(dimNumMaps)); return false; } if (isLocked(mapIndex)) { errorMessageOut = "Volume must be unlocked (Press \"Lock\" in toolbar) to allow editing."; return false; } switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: if ( ! VolumeEditingModeEnum::isObliqueEditingAllowed(mode)) { errorMessageOut = (VolumeEditingModeEnum::toGuiName(mode) + " does not support editing voxels when the volume " "is in an oblique view."); return false; } break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: break; } int64_t iHalf = brushSize[0] / 2; int64_t jHalf = brushSize[1] / 2; int64_t kHalf = brushSize[2] / 2; int64_t ijkMin[3] = { voxelIJK[0] - iHalf, voxelIJK[1] - jHalf, voxelIJK[2] - kHalf }; clampVoxelIndices(ijkMin); int64_t ijkMax[3] = { voxelIJK[0] + iHalf, voxelIJK[1] + jHalf, voxelIJK[2] + kHalf }; clampVoxelIndices(ijkMax); const EditInfo editInfo(mapIndex, mode, slicePlane, sliceProjectionType, obliqueRotationMatrix, voxelDiffXYZ, voxelIJK, ijkMin, ijkMax, brushSize, voxelValueOn, voxelValueOff); bool result = false; switch (mode) { case VolumeEditingModeEnum::VOLUME_EDITING_MODE_ON: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_OFF: switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: result = performTurnOnOrOffOblique(editInfo, errorMessageOut); break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: result = performTurnOnOrOffOrthogonal(editInfo, errorMessageOut); break; } break; case VolumeEditingModeEnum::VOLUME_EDITING_MODE_DILATE: result = performDilateOrErode(editInfo, errorMessageOut); break; case VolumeEditingModeEnum::VOLUME_EDITING_MODE_ERODE: result = performDilateOrErode(editInfo, errorMessageOut); break; case VolumeEditingModeEnum::VOLUME_EDITING_MODE_FLOOD_FILL_2D: result = performFloodFill2D(editInfo, errorMessageOut); break; case VolumeEditingModeEnum::VOLUME_EDITING_MODE_FLOOD_FILL_3D: result = performFloodFill3D(editInfo, errorMessageOut); break; case VolumeEditingModeEnum::VOLUME_EDITING_MODE_REMOVE_CONNECTED_2D: result = performRemoveConnected2D(editInfo, errorMessageOut); break; case VolumeEditingModeEnum::VOLUME_EDITING_MODE_REMOVE_CONNECTED_3D: result = performRemoveConnected3D(editInfo, errorMessageOut); break; case VolumeEditingModeEnum::VOLUME_EDITING_MODE_RETAIN_CONNECTED_3D: result = performRetainConnected3D(editInfo, errorMessageOut); break; } return result; } /** * @return Is the volume file locked (does not allow editing)? * * @param mapIndex * Index of map that is tested for locked. */ bool VolumeFileEditorDelegate::isLocked(const int64_t mapIndex) const { CaretAssertVectorIndex(m_volumeMapEditingLocked, mapIndex); return m_volumeMapEditingLocked[mapIndex]; } /** * Set the volume file's lock status (does not allow editing). * * If the locked status transitions to 'locked', * then CLEAR THE UNDO STACK since by locking, * the user is satisfied with changes made to the volume. * * * @param mapIndex * Index of map that has lock status set. * @param locked * New locked status. */ void VolumeFileEditorDelegate::setLocked(const int64_t mapIndex, const bool locked) { CaretAssertVectorIndex(m_volumeMapEditingLocked, mapIndex); if (locked != m_volumeMapEditingLocked[mapIndex]) { m_volumeMapEditingLocked[mapIndex] = locked; if (m_volumeMapEditingLocked[mapIndex]) { CaretAssertVectorIndex(m_volumeMapUndoStacks, mapIndex); m_volumeMapUndoStacks[mapIndex]->clear(); } } } /** * Adjust the voxel indices so that they are within the volume. * * @param ijk * Voxel indices that are adjusted to be in the range * 0 to dimension minus one. */ void VolumeFileEditorDelegate::clampVoxelIndices(int64_t ijk[3]) const { for (int32_t i = 0; i < 3; i++) { ijk[i] = clampDimensionIndex(m_volumeDimensions[i], ijk[i]); } } /** * Clamp a voxel dimensions index (zero to dim-1) * * @param maxDim * Maximum dimension value. * @param dimIndex * Value that is clamped. */ int64_t VolumeFileEditorDelegate::clampDimensionIndex(const int64_t maxDim, int64_t dimIndex) const { if (dimIndex < 0) { dimIndex = 0; } else if (dimIndex >= maxDim) { dimIndex = maxDim - 1; } return dimIndex; } /** * Clamp voxel indices. * * @param i * Index for dimension 0. * @param j * Index for dimension 1. * @param k * Index for dimension 2. */ void VolumeFileEditorDelegate::clampVoxelIndices(int64_t& i, int64_t& j, int64_t& k) const { i = clampDimensionIndex(m_volumeDimensions[0], i); j = clampDimensionIndex(m_volumeDimensions[1], j); k = clampDimensionIndex(m_volumeDimensions[2], k); } /** * Add to the modified undo stacks for the given map. * * @param mapIndex * Index of the map that was modified. * @param modifiedVoxels * Voxels that were modified. */ void VolumeFileEditorDelegate::addToMapUndoStacks(const int32_t mapIndex, VolumeMapUndoCommand* modifiedVoxels) { if (modifiedVoxels->count() <= 0) { delete modifiedVoxels; return; } CaretAssertVectorIndex(m_volumeMapUndoStacks, mapIndex); m_volumeMapUndoStacks[mapIndex]->push(modifiedVoxels); } /** * Update in case number of maps in volume file has changed. */ void VolumeFileEditorDelegate::updateIfVolumeFileChangedNumberOfMaps() { const int32_t oldNumMaps = static_cast(m_volumeMapUndoStacks.size()); const int32_t numMaps = m_volumeFile->getNumberOfMaps(); const int32_t numMapsToAdd = numMaps - oldNumMaps; if (numMapsToAdd > 0) { for (int32_t i = 0; i < numMapsToAdd; i++) { m_volumeMapUndoStacks.push_back(new CaretUndoStack()); m_volumeMapEditingLocked.push_back(true); } } CaretAssert(static_cast(m_volumeMapUndoStacks.size()) == numMaps); CaretAssert(static_cast(m_volumeMapEditingLocked.size()) == numMaps); } /** * Undo the last voxel editing operation for the given map index. * * @param mapIndex * Index of map that has last voxel operation 'undone'. * @param errorMessageOut * Output containing error message. * @return * True if the redo executed successfully, else false. */ bool VolumeFileEditorDelegate::undo(const int64_t mapIndex, AString& errorMessageOut) { CaretAssertVectorIndex(m_volumeMapUndoStacks, mapIndex); return m_volumeMapUndoStacks[mapIndex]->undo(errorMessageOut); } /** * Reset all voxel editing since last lock. * * Note that when the lock status transitions to lock, * the undo stack is cleared. * * @param mapIndex * Index of map that has last voxel operation 'undone'. * @param errorMessageOut * Output containing error message. * @return * True if the redo executed successfully, else false. */ bool VolumeFileEditorDelegate::reset(const int64_t mapIndex, AString& errorMessageOut) { CaretAssertVectorIndex(m_volumeMapUndoStacks, mapIndex); return m_volumeMapUndoStacks[mapIndex]->undoAll(errorMessageOut); } /** * Redo the last voxel editing operation for the given map index. * * @param mapIndex * Index of map that has last voxel operation 'redone'. * @param errorMessageOut * Output containing error message. * @return * True if the redo executed successfully, else false. */ bool VolumeFileEditorDelegate::redo(const int64_t mapIndex, AString& errorMessageOut) { CaretAssertVectorIndex(m_volumeMapUndoStacks, mapIndex); return m_volumeMapUndoStacks[mapIndex]->redo(errorMessageOut); } /** * Perform an editing operation that turns voxels on or off * for orthogonal slice viewing. * * @param editInfo * The editing information. * @param errorMessageOut * Will contain error information. * @return * True if there was an error, else false. */ bool VolumeFileEditorDelegate::performTurnOnOrOffOrthogonal(const EditInfo& editInfo, AString& errorMessageOut) { float redoVoxelValue = 0.0; switch (editInfo.m_mode){ case VolumeEditingModeEnum::VOLUME_EDITING_MODE_OFF: redoVoxelValue = editInfo.m_voxelValueOff; break; case VolumeEditingModeEnum::VOLUME_EDITING_MODE_ON: redoVoxelValue = editInfo.m_voxelValueOn; break; case VolumeEditingModeEnum::VOLUME_EDITING_MODE_DILATE: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_ERODE: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_FLOOD_FILL_2D: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_FLOOD_FILL_3D: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_REMOVE_CONNECTED_2D: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_REMOVE_CONNECTED_3D: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_RETAIN_CONNECTED_3D: CaretAssert(0); errorMessageOut = "Program error in performTurnOnOrOff but mode not valid."; return false; break; } CaretPointer modifiedVoxels; modifiedVoxels.grabNew(new VolumeMapUndoCommand(m_volumeFile, editInfo.m_mapIndex)); for (int64_t i = editInfo.m_ijkMin[0]; i <= editInfo.m_ijkMax[0]; i++) { for (int64_t j = editInfo.m_ijkMin[1]; j <= editInfo.m_ijkMax[1]; j++) { for (int64_t k = editInfo.m_ijkMin[2]; k <= editInfo.m_ijkMax[2]; k++) { const int64_t ijk[3] = { i, j, k }; modifiedVoxels->addVoxelRedoUndo(ijk, redoVoxelValue, m_volumeFile->getValue(ijk, editInfo.m_mapIndex)); m_volumeFile->setValue(redoVoxelValue, ijk, editInfo.m_mapIndex); } } } addToMapUndoStacks(editInfo.m_mapIndex, modifiedVoxels.releasePointer()); return true; } /** * Perform an editing operation that turns voxels on or off * for oblique slice viewing. * * @param editInfo * The editing information. * @param errorMessageOut * Will contain error information. * @return * True if there was an error, else false. */ bool VolumeFileEditorDelegate::performTurnOnOrOffOblique(const EditInfo& editInfo, AString& errorMessageOut) { float redoVoxelValue = 0.0; switch (editInfo.m_mode){ case VolumeEditingModeEnum::VOLUME_EDITING_MODE_OFF: redoVoxelValue = editInfo.m_voxelValueOff; break; case VolumeEditingModeEnum::VOLUME_EDITING_MODE_ON: redoVoxelValue = editInfo.m_voxelValueOn; break; case VolumeEditingModeEnum::VOLUME_EDITING_MODE_DILATE: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_ERODE: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_FLOOD_FILL_2D: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_FLOOD_FILL_3D: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_REMOVE_CONNECTED_2D: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_REMOVE_CONNECTED_3D: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_RETAIN_CONNECTED_3D: CaretAssert(0); errorMessageOut = "Program error in performTurnOnOrOff but mode not valid."; return false; break; } // float voxelDiffXYZ[3]; float voxelXYZ[3]; m_volumeFile->indexToSpace(editInfo.m_voxelIJK, voxelXYZ); // const int64_t planeVoxelsDI = (editInfo.m_ijkMax[0] - editInfo.m_ijkMin[0]) / 2 ; // const int64_t planeVoxelsDJ = (editInfo.m_ijkMax[1] - editInfo.m_ijkMin[1]) / 2 ; // const int64_t planeVoxelsDK = (editInfo.m_ijkMax[2] - editInfo.m_ijkMin[2]) / 2 ; CaretPointer modifiedVoxels; modifiedVoxels.grabNew(new VolumeMapUndoCommand(m_volumeFile, editInfo.m_mapIndex)); // const float planeZ = voxelXYZ[2]; // for (int64_t i = -planeVoxelsDI; i <= planeVoxelsDI; i++) { // const float planeX = voxelXYZ[0] + i * editInfo.m_voxelDiffXYZ[0]; // for (int64_t j = -planeVoxelsDJ; j <= planeVoxelsDJ; j++) { // const float planeY = voxelXYZ[1] + j * editInfo.m_voxelDiffXYZ[1]; // const float xyz[3] = { planeX, planeY, planeZ }; // float ijkFloat[3]; // m_volumeFile->spaceToIndex(xyz, ijkFloat); // int64_t ijk[3] = { ijkFloat[0], ijkFloat[1], ijkFloat[2] }; // modifiedVoxels->addVoxelRedoUndo(ijk, // redoVoxelValue, // m_volumeFile->getValue(ijk, editInfo.m_mapIndex)); // m_volumeFile->setValue(redoVoxelValue, // ijk, // editInfo.m_mapIndex); // } // } const int64_t halfBrushI = editInfo.m_brushSize[0] / 2; const int64_t halfBrushJ = editInfo.m_brushSize[1] / 2; const int64_t halfBrushK = editInfo.m_brushSize[2] / 2; VolumeSpace::OrientTypes orient[3]; float spacing[3]; float origin[3]; m_volumeFile->getVolumeSpace().getOrientAndSpacingForPlumb(orient, spacing, origin); for (int64_t k = -halfBrushK; k <= halfBrushK; k++) { for (int64_t i = -halfBrushI; i <= halfBrushI; i++) { for (int64_t j = -halfBrushJ; j <= halfBrushJ; j++) { float localXYZ[3] = { i * spacing[0], j * spacing[1], k * spacing[2] }; editInfo.m_obliqueRotationMatrix.multiplyPoint3(localXYZ); float brushXYZ[3] = { voxelXYZ[0] + localXYZ[0], voxelXYZ[1] + localXYZ[1], voxelXYZ[2] + localXYZ[2] }; float ijkFloat[3]; m_volumeFile->spaceToIndex(brushXYZ, ijkFloat); int64_t ijk[3] = { (int64_t)ijkFloat[0], (int64_t)ijkFloat[1], (int64_t)ijkFloat[2] }; modifiedVoxels->addVoxelRedoUndo(ijk, redoVoxelValue, m_volumeFile->getValue(ijk, editInfo.m_mapIndex)); m_volumeFile->setValue(redoVoxelValue, ijk, editInfo.m_mapIndex); } } } // for (int64_t k = -planeVoxelsDZ; k <= planeVoxelsDZ; ++k) { // // } // CaretPointer modifiedVoxels; // modifiedVoxels.grabNew(new VolumeMapUndoCommand(m_volumeFile, // editInfo.m_mapIndex)); // for (int64_t i = editInfo.m_ijkMin[0]; i <= editInfo.m_ijkMax[0]; i++) { // for (int64_t j = editInfo.m_ijkMin[1]; j <= editInfo.m_ijkMax[1]; j++) { // for (int64_t k = editInfo.m_ijkMin[2]; k <= editInfo.m_ijkMax[2]; k++) { // const int64_t ijk[3] = { i, j, k }; // modifiedVoxels->addVoxelRedoUndo(ijk, // redoVoxelValue, // m_volumeFile->getValue(ijk, editInfo.m_mapIndex)); // m_volumeFile->setValue(redoVoxelValue, // ijk, // editInfo.m_mapIndex); // } // } // } addToMapUndoStacks(editInfo.m_mapIndex, modifiedVoxels.releasePointer()); return true; } /** * Perform an editing operation that dilates voxels * connected to the selected voxel. * * @param editInfo * The editing information. * @param errorMessageOut * Will contain error information. * @return * True if there was an error, else false. */ bool VolumeFileEditorDelegate::performDilateOrErode(const EditInfo& editInfo, AString& errorMessageOut) { bool dilateFlag = false; switch (editInfo.m_mode){ case VolumeEditingModeEnum::VOLUME_EDITING_MODE_DILATE: dilateFlag = true; break; case VolumeEditingModeEnum::VOLUME_EDITING_MODE_ERODE: dilateFlag = false; break; case VolumeEditingModeEnum::VOLUME_EDITING_MODE_FLOOD_FILL_2D: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_FLOOD_FILL_3D: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_OFF: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_ON: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_REMOVE_CONNECTED_2D: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_REMOVE_CONNECTED_3D: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_RETAIN_CONNECTED_3D: CaretAssert(0); errorMessageOut = "Program error in dilate/erode but mode not valid."; return false; break; } const int64_t STRUCTURE_ELEMENT_SIZE = 1; CaretPointer modifiedVoxels; modifiedVoxels.grabNew(new VolumeMapUndoCommand(m_volumeFile, editInfo.m_mapIndex)); /* * Check each voxel in the desired region */ for (int64_t i = editInfo.m_ijkMin[0]; i <= editInfo.m_ijkMax[0]; i++) { for (int64_t j = editInfo.m_ijkMin[1]; j <= editInfo.m_ijkMax[1]; j++) { for (int64_t k = editInfo.m_ijkMin[2]; k <= editInfo.m_ijkMax[2]; k++) { const int64_t ijk[3] = { i, j, k }; /* * Get the value of the voxel */ float value = m_volumeFile->getValue(ijk, editInfo.m_mapIndex); bool voxelMatches = false; /* * If eroding, look for voxels with "turn on" value */ if (! dilateFlag) { if (value == editInfo.m_voxelValueOn) { voxelMatches = true; } } /* * If dilating, look for "OFF" voxels */ if (dilateFlag) { if (value == editInfo.m_voxelValueOff) { voxelMatches = true; } } /* * Should we continue processing this voxel */ if (voxelMatches) { /* * Create Structuring Element based upon the axis */ int64_t iMin = ijk[0]; int64_t iMax = ijk[0]; int64_t jMin = ijk[1]; int64_t jMax = ijk[1]; int64_t kMin = ijk[2]; int64_t kMax = ijk[2]; switch (editInfo.m_slicePlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); errorMessageOut = "Program Error: Cannot edit an ALL slice"; return false; break; case VolumeSliceViewPlaneEnum::AXIAL: iMin -= STRUCTURE_ELEMENT_SIZE; iMax += STRUCTURE_ELEMENT_SIZE; jMin -= STRUCTURE_ELEMENT_SIZE; jMax += STRUCTURE_ELEMENT_SIZE; break; case VolumeSliceViewPlaneEnum::CORONAL: iMin -= STRUCTURE_ELEMENT_SIZE; iMax += STRUCTURE_ELEMENT_SIZE; kMin -= STRUCTURE_ELEMENT_SIZE; kMax += STRUCTURE_ELEMENT_SIZE; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: jMin -= STRUCTURE_ELEMENT_SIZE; jMax += STRUCTURE_ELEMENT_SIZE; kMin -= STRUCTURE_ELEMENT_SIZE; kMax += STRUCTURE_ELEMENT_SIZE; break; } clampVoxelIndices(iMin, jMin, kMin); clampVoxelIndices(iMax, jMax, kMax); /* * Check all voxels "under" the structuring element */ bool foundVoxelFlag = false; for (int64_t ii = iMin; ii <= iMax; ii++) { for (int64_t jj = jMin; jj <= jMax; jj++) { for (int64_t kk = kMin; kk <= kMax; kk++) { /* * Ignore the voxel under the center of the * structuring element */ if ((ii != i) || (jj != j) || (kk != k)) { /* * Make sure voxel is valid since structuring element * may exceed bounds of the volume */ const int64_t iijjkk[3] = { ii, jj, kk }; float value = m_volumeFile->getValue(iijjkk); /* * If dilating, look for voxels that are the * turn on value under the structuring * element. */ if (dilateFlag) { if (value == editInfo.m_voxelValueOn) { foundVoxelFlag = true; break; } } /* * If eroding look for voxels that are "OFF" * under the structuring element */ if ( ! dilateFlag) { if (value != editInfo.m_voxelValueOn) { foundVoxelFlag = true; break; } } } } if (foundVoxelFlag) { break; } } if (foundVoxelFlag) { break; } } if (foundVoxelFlag) { /* * For now, just note which voxels need to be set since * we do not want to modify the volume until after all voxels * under structuring element have been checked. */ if (dilateFlag) { modifiedVoxels->addVoxelRedoUndo(ijk, editInfo.m_voxelValueOn, m_volumeFile->getValue(ijk, editInfo.m_mapIndex)); } else { modifiedVoxels->addVoxelRedoUndo(ijk, editInfo.m_voxelValueOff, m_volumeFile->getValue(ijk, editInfo.m_mapIndex)); } } } } } } /* * Calling 'redo' will apply the changes to the volume file. */ const bool validFlag = modifiedVoxels->redo(errorMessageOut); addToMapUndoStacks(editInfo.m_mapIndex, modifiedVoxels.releasePointer()); return validFlag; } /** * Perform an editing operation that flood fills the region * containing the selected voxel in the selected slice. * * @param editInfo * The editing information. * @param errorMessageOut * Will contain error information. * @return * True if there was an error, else false. */ bool VolumeFileEditorDelegate::performFloodFill2D(const EditInfo& editInfo, AString& errorMessageOut) { return performFloodFillAndRemoveConnected(editInfo, errorMessageOut); } /** * Perform an editing operation that flood fills the region * containing the selected voxel in all dimensions. * * @param editInfo * The editing information. * @param errorMessageOut * Will contain error information. * @return * True if there was an error, else false. */ bool VolumeFileEditorDelegate::performFloodFill3D(const EditInfo& editInfo, AString& errorMessageOut) { return performFloodFillAndRemoveConnected(editInfo, errorMessageOut); } /** * Perform an editing operation that removes all voxels connected * to the selected voxel in the slice. * * @param editInfo * The editing information. * @param errorMessageOut * Will contain error information. * @return * True if there was an error, else false. */ bool VolumeFileEditorDelegate::performRemoveConnected2D(const EditInfo& editInfo, AString& errorMessageOut) { return performFloodFillAndRemoveConnected(editInfo, errorMessageOut); } /** * Perform an editing operation that removes all voxels connected * to the selected voxel in all dimensions. * * @param editInfo * The editing information. * @param errorMessageOut * Will contain error information. * @return * True if there was an error, else false. */ bool VolumeFileEditorDelegate::performRemoveConnected3D(const EditInfo& editInfo, AString& errorMessageOut) { return performFloodFillAndRemoveConnected(editInfo, errorMessageOut); } /** * Perform an editing operation that rmeoves all voxels that * are not connected to the selected voxel. * * @param editInfo * The editing information. * @param errorMessageOut * Will contain error information. * @return * True if there was an error, else false. */ bool VolumeFileEditorDelegate::performRetainConnected3D(const EditInfo& editInfo, AString& errorMessageOut) { if (m_volumeFile->getValue(editInfo.m_voxelIJK, editInfo.m_mapIndex) == editInfo.m_voxelValueOff) { errorMessageOut = "Voxel value is zero or the unassigned label."; return false; } CaretPointer modifiedVoxels; modifiedVoxels.grabNew(new VolumeMapUndoCommand(m_volumeFile, editInfo.m_mapIndex)); /* * Tracks visited voxels */ const int64_t numVoxels = (m_volumeDimensions[0] * m_volumeDimensions[1] * m_volumeDimensions[2]); std::vector visitedVoxelFlags(numVoxels, false); /* * Tracks voxels that are connected */ std::vector connectedVoxelFlags(numVoxels, false); /* * Initialize to the staring voxel */ std::stack st; st.push(VoxelIJK(editInfo.m_voxelIJK)); /* * While there are voxels to process */ while (st.empty() == false) { /* * Get the next voxel to process */ const VoxelIJK v = st.top(); st.pop(); const int64_t visitedFlagsOffset = (v.m_ijk[0] + (v.m_ijk[1] * (m_volumeDimensions[0])) + (v.m_ijk[2] * m_volumeDimensions[0] * m_volumeDimensions[1])); CaretAssertVectorIndex(visitedVoxelFlags, visitedFlagsOffset); if (visitedVoxelFlags[visitedFlagsOffset]) { continue; } visitedVoxelFlags[visitedFlagsOffset] = true; if (m_volumeFile->getValue(v.m_ijk, editInfo.m_mapIndex) == editInfo.m_voxelValueOff) { continue; } connectedVoxelFlags[visitedFlagsOffset] = true; int64_t ijkMin[3] = { v.m_ijk[0] - 1, v.m_ijk[1] - 1, v.m_ijk[2] - 1 }; clampVoxelIndices(ijkMin); int64_t ijkMax[3] = { v.m_ijk[0] + 1, v.m_ijk[1] + 1, v.m_ijk[2] + 1 }; clampVoxelIndices(ijkMax); /* * Add neighbors to search */ for (int64_t i = ijkMin[0]; i <= ijkMax[0]; i++) { for (int64_t j = ijkMin[1]; j <= ijkMax[1]; j++) { for (int64_t k = ijkMin[2]; k <= ijkMax[2]; k++) { const int64_t flagsOffset = (i + (j * (m_volumeDimensions[0])) + (k * m_volumeDimensions[0] * m_volumeDimensions[1])); if (visitedVoxelFlags[flagsOffset]) { continue; } if (m_volumeFile->getValue(i, j, k, editInfo.m_mapIndex) != editInfo.m_voxelValueOff) { st.push(VoxelIJK(i, j, k)); } } } } } /* * Turn off not connected voxels */ for (int64_t i = 0; i < m_volumeDimensions[0]; i++) { for (int64_t j = 0; j < m_volumeDimensions[1]; j++) { for (int64_t k = 0; k < m_volumeDimensions[2]; k++) { const int64_t flagsOffset = (i + (j * (m_volumeDimensions[0])) + (k * m_volumeDimensions[0] * m_volumeDimensions[1])); if ( ! connectedVoxelFlags[flagsOffset]) { modifiedVoxels->addVoxelRedoUndo(i, j, k, editInfo.m_voxelValueOff, m_volumeFile->getValue(i, j, k, editInfo.m_mapIndex)); m_volumeFile->setValue(editInfo.m_voxelValueOff, i, j, k, editInfo.m_mapIndex); } } } } addToMapUndoStacks(editInfo.m_mapIndex, modifiedVoxels.releasePointer()); return true; } /** * Perform an editing operation that rmeoves all voxels that * are not connected to the selected voxel. * * @param editInfo * The editing information. * @param errorMessageOut * Will contain error information. * @return * True if there was an error, else false. */ bool VolumeFileEditorDelegate::performFloodFillAndRemoveConnected(const EditInfo& editInfo, AString& errorMessageOut) { bool fillingFlag = false; bool threeDimensionalFlag = false; switch (editInfo.m_mode){ case VolumeEditingModeEnum::VOLUME_EDITING_MODE_DILATE: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_ERODE: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_OFF: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_ON: case VolumeEditingModeEnum::VOLUME_EDITING_MODE_RETAIN_CONNECTED_3D: CaretAssert(0); errorMessageOut = "Program error in performFloodFillAndRemoveConnected but mode not valid."; return false; break; case VolumeEditingModeEnum::VOLUME_EDITING_MODE_FLOOD_FILL_2D: fillingFlag = true; break; case VolumeEditingModeEnum::VOLUME_EDITING_MODE_FLOOD_FILL_3D: fillingFlag = true; threeDimensionalFlag = true; break; case VolumeEditingModeEnum::VOLUME_EDITING_MODE_REMOVE_CONNECTED_2D: break; case VolumeEditingModeEnum::VOLUME_EDITING_MODE_REMOVE_CONNECTED_3D: threeDimensionalFlag = true; break; } CaretPointer modifiedVoxels; modifiedVoxels.grabNew(new VolumeMapUndoCommand(m_volumeFile, editInfo.m_mapIndex)); float newVoxelValue = editInfo.m_voxelValueOff; if (fillingFlag) { newVoxelValue = editInfo.m_voxelValueOn; } /* * Initialize to the staring voxel */ std::stack st; st.push(VoxelIJK(editInfo.m_voxelIJK)); /* * While there are voxels to process */ while (st.empty() == false) { /* * Get the next voxel to process */ const VoxelIJK v = st.top(); st.pop(); int64_t i = v.m_ijk[0]; int64_t j = v.m_ijk[1]; int64_t k = v.m_ijk[2]; /* * If the voxel has valid indices */ if ((i >= 0) && (i < m_volumeDimensions[0]) && (j >= 0) && (j < m_volumeDimensions[1]) && (k >= 0) && (k < m_volumeDimensions[2])) { const int64_t ijk[3] = { i, j, k }; float currentValue = m_volumeFile->getValue(ijk, editInfo.m_mapIndex); /* * See if voxel has proper value for operation */ bool matchingVoxel = false; if (fillingFlag) { matchingVoxel = (currentValue == editInfo.m_voxelValueOff); } else { matchingVoxel = (currentValue == editInfo.m_voxelValueOn); } /* * If the voxel should be modified */ if (matchingVoxel) { /* * Update the voxels value */ modifiedVoxels->addVoxelRedoUndo(ijk, newVoxelValue, m_volumeFile->getValue(ijk, editInfo.m_mapIndex)); m_volumeFile->setValue(newVoxelValue, ijk, editInfo.m_mapIndex); /* * Determine neighboring voxels */ int64_t iDelta = 0; int64_t jDelta = 0; int64_t kDelta = 0; switch (editInfo.m_slicePlane) { case VolumeSliceViewPlaneEnum::PARASAGITTAL: if (threeDimensionalFlag) { iDelta = 1; } else { iDelta = 0; } jDelta = 1; kDelta = 1; break; case VolumeSliceViewPlaneEnum::CORONAL: iDelta = 1; if (threeDimensionalFlag) { jDelta = 1; } else { jDelta = 0; } kDelta = 1; break; case VolumeSliceViewPlaneEnum::AXIAL: iDelta = 1; jDelta = 1; if (threeDimensionalFlag) { kDelta = 1; } else { kDelta = 0; } break; case VolumeSliceViewPlaneEnum::ALL: break; } /* * Add neighboring voxels for search */ if (iDelta != 0) { st.push(VoxelIJK(i - iDelta, j, k)); st.push(VoxelIJK(i + iDelta, j, k)); } if (jDelta != 0) { st.push(VoxelIJK(i, j - jDelta, k)); st.push(VoxelIJK(i, j + jDelta, k)); } if (kDelta != 0) { st.push(VoxelIJK(i, j, k - kDelta)); st.push(VoxelIJK(i, j, k + kDelta)); } } } } addToMapUndoStacks(editInfo.m_mapIndex, modifiedVoxels.releasePointer()); return true; } connectome-workbench-1.4.2/src/Files/VolumeFileEditorDelegate.h000066400000000000000000000167511360521144700245200ustar00rootroot00000000000000#ifndef __VOLUME_FILE_EDITOR_DELEGATE_H__ #define __VOLUME_FILE_EDITOR_DELEGATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "Matrix4x4.h" #include "VolumeEditingModeEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "VolumeSliceViewPlaneEnum.h" namespace caret { class CaretUndoStack; class VolumeFile; class VolumeMapUndoCommand; class VolumeFileEditorDelegate : public CaretObject { public: VolumeFileEditorDelegate(VolumeFile* volumeFile); virtual ~VolumeFileEditorDelegate(); void clear(); void updateIfVolumeFileChangedNumberOfMaps(); bool performEditingOperation(const int64_t mapIndex, const VolumeEditingModeEnum::Enum mode, const VolumeSliceViewPlaneEnum::Enum slicePlane, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const Matrix4x4& obliqueRotationMatrix, const float voxelDiffXYZ[3], const int64_t voxelIJK[3], const int64_t brushSize[3], const float voxelValueOn, const float voxelValueOff, AString& errorMessageOut); bool undo(const int64_t mapIndex, AString& errorMessageOut); bool reset(const int64_t mapIndex, AString& errorMessageOut); bool redo(const int64_t mapIndex, AString& errorMessageOut); bool isLocked(const int64_t mapIndex) const; void setLocked(const int64_t mapIndex, const bool locked); // ADD_NEW_METHODS_HERE private: class EditInfo { public: EditInfo(const int32_t mapIndex, const VolumeEditingModeEnum::Enum mode, const VolumeSliceViewPlaneEnum::Enum slicePlane, const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType, const Matrix4x4& obliqueRotationMatrix, const float voxelDiffXYZ[3], const int64_t voxelIJK[3], const int64_t ijkMin[3], const int64_t ijkMax[3], const int64_t brushSize[3], const float voxelValueOn, const float voxelValueOff) : m_mapIndex(mapIndex), m_mode(mode), m_slicePlane(slicePlane), m_sliceProjectionType(sliceProjectionType), m_obliqueRotationMatrix(obliqueRotationMatrix), m_voxelValueOn(voxelValueOn), m_voxelValueOff(voxelValueOff) { m_voxelDiffXYZ[0] = voxelDiffXYZ[0]; m_voxelDiffXYZ[1] = voxelDiffXYZ[1]; m_voxelDiffXYZ[2] = voxelDiffXYZ[2]; m_voxelIJK[0] = voxelIJK[0]; m_voxelIJK[1] = voxelIJK[1]; m_voxelIJK[2] = voxelIJK[2]; m_brushSize[0] = brushSize[0]; m_brushSize[1] = brushSize[1]; m_brushSize[2] = brushSize[2]; m_ijkMin[0] = ijkMin[0]; m_ijkMin[1] = ijkMin[1]; m_ijkMin[2] = ijkMin[2]; m_ijkMax[0] = ijkMax[0]; m_ijkMax[1] = ijkMax[1]; m_ijkMax[2] = ijkMax[2]; } const int32_t m_mapIndex; const VolumeEditingModeEnum::Enum m_mode; const VolumeSliceViewPlaneEnum::Enum m_slicePlane; const VolumeSliceProjectionTypeEnum::Enum m_sliceProjectionType; const Matrix4x4 m_obliqueRotationMatrix; float m_voxelDiffXYZ[3]; int64_t m_voxelIJK[3]; int64_t m_ijkMin[3]; int64_t m_ijkMax[3]; int64_t m_brushSize[3]; const float m_voxelValueOn; const float m_voxelValueOff; }; VolumeFileEditorDelegate(const VolumeFileEditorDelegate&); VolumeFileEditorDelegate& operator=(const VolumeFileEditorDelegate&); bool performTurnOnOrOffOblique(const EditInfo& editInfo, AString& errorMessageOut); bool performTurnOnOrOffOrthogonal(const EditInfo& editInfo, AString& errorMessageOut); bool performDilateOrErode(const EditInfo& editInfo, AString& errorMessageOut); bool performFloodFill2D(const EditInfo& editInfo, AString& errorMessageOut); bool performFloodFill3D(const EditInfo& editInfo, AString& errorMessageOut); bool performRemoveConnected2D(const EditInfo& editInfo, AString& errorMessageOut); bool performRemoveConnected3D(const EditInfo& editInfo, AString& errorMessageOut); bool performRetainConnected3D(const EditInfo& editInfo, AString& errorMessageOut); bool performFloodFillAndRemoveConnected(const EditInfo& editInfo, AString& errorMessageOut); int64_t clampDimensionIndex(const int64_t maxDim, int64_t dimIndex) const; void clampVoxelIndices(int64_t ijk[3]) const; void clampVoxelIndices(int64_t& i, int64_t& j, int64_t& k) const; void addToMapUndoStacks(const int32_t mapIndex, VolumeMapUndoCommand* modifiedVoxels); VolumeFile* m_volumeFile; /** * Holds modifications for undo/redo operations. * Index into vector is the map index. */ std::vector m_volumeMapUndoStacks; /** * IJK dimensions of the volume. */ int64_t m_volumeDimensions[3]; /** * A "lock" to prevent editing of a volume's map. */ std::vector m_volumeMapEditingLocked; // ADD_NEW_MEMBERS_HERE }; #ifdef __VOLUME_FILE_EDITOR_DELEGATE_DECLARE__ // #endif // __VOLUME_FILE_EDITOR_DELEGATE_DECLARE__ } // namespace #endif //__VOLUME_FILE_EDITOR_DELEGATE_H__ connectome-workbench-1.4.2/src/Files/VolumeFileVoxelColorizer.cxx000066400000000000000000000667641360521144700252110ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __VOLUME_FILE_VOXEL_COLORIZER_DECLARE__ #include "VolumeFileVoxelColorizer.h" #undef __VOLUME_FILE_VOXEL_COLORIZER_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "ElapsedTimer.h" #include "GiftiLabel.h" #include "GroupAndNameHierarchyItem.h" #include "NodeAndVoxelColoring.h" #include "VolumeFile.h" #include using namespace caret; /** * \class caret::VolumeFileVoxelColorizer * \brief Delegate for coloring a volumes voxels. */ /** * Constructor. * * @param volumeFile * Volume file on which this instance colors voxels. */ VolumeFileVoxelColorizer::VolumeFileVoxelColorizer(VolumeFile* volumeFile) : CaretObject() { CaretAssert(volumeFile); m_volumeFile = volumeFile; int64_t dimNumberOfComponents; m_volumeFile->getDimensions(m_dimI, m_dimJ, m_dimK, m_mapCount, dimNumberOfComponents); m_voxelCountPerMap = m_dimI * m_dimJ * m_dimK; m_mapRGBACount = m_voxelCountPerMap * 4; for (int64_t i = 0; i < m_mapCount; i++) { m_mapRGBA.push_back(new uint8_t[m_mapRGBACount]); m_mapColoringValid.push_back(false); } } /** * Destructor. */ VolumeFileVoxelColorizer::~VolumeFileVoxelColorizer() { for (int64_t i = 0; i < m_mapCount; i++) { delete[] m_mapRGBA[i]; } m_mapRGBA.clear(); } /** * Assign voxel coloring for a map. * * @param mapIndex * Index of map. */ void VolumeFileVoxelColorizer::assignVoxelColorsForMap(const int32_t mapIndex) { CaretAssertVectorIndex(m_mapRGBA, mapIndex); ElapsedTimer timer; timer.start(); /* * Pointer to map's data */ const float* mapDataPointer = m_volumeFile->getFrame(mapIndex); VolumeFile* thresholdVolume = NULL; int32_t thresholdVolumeMapIndex = -1; if (m_volumeFile->isMappedWithPalette()) { switch (m_volumeFile->getMapPaletteColorMapping(mapIndex)->getThresholdType()) { case PaletteThresholdTypeEnum::THRESHOLD_TYPE_FILE: { CaretMappableDataFileAndMapSelectionModel* threshSel = m_volumeFile->getMapThresholdFileSelectionModel(mapIndex); CaretMappableDataFile* mapFile = threshSel->getSelectedFile(); if (mapFile != NULL) { thresholdVolume = dynamic_cast(mapFile); CaretAssert(thresholdVolume); thresholdVolumeMapIndex = threshSel->getSelectedMapIndex(); } } break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED: break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED_AVERAGE_AREA: break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_NORMAL: /* * Thresholding with 'self' */ thresholdVolume = m_volumeFile; thresholdVolumeMapIndex = mapIndex; break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF: break; } } /* * Get access to threshold data */ bool ignoreThresholding = true; if (thresholdVolume != NULL) { int64_t threshI, threshJ, threshK, threshMapCount, threshNumberOfComponents; thresholdVolume->getDimensions(threshI, threshJ, threshK, threshMapCount, threshNumberOfComponents); if ((threshI != m_dimI) || (threshJ != m_dimJ) || (threshK != m_dimK)) { CaretLogSevere("Threshold volume (" + thresholdVolume->getFileNameNoPath() + ") dimensions do not match " + m_volumeFile->getFileNameNoPath()); } else if ((thresholdVolumeMapIndex < 0) || (thresholdVolumeMapIndex >= thresholdVolume->getNumberOfMaps())) { CaretLogSevere("Threshold volume (" + thresholdVolume->getFileNameNoPath() + ") map index=" + AString::number(thresholdVolumeMapIndex) + " is invalid"); } else { ignoreThresholding = false; } } switch (m_volumeFile->getType()) { case SubvolumeAttributes::UNKNOWN: case SubvolumeAttributes::ANATOMY: case SubvolumeAttributes::FUNCTIONAL: { FastStatistics* statistics = NULL; switch (m_volumeFile->getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: statistics = const_cast(m_volumeFile->getFileFastStatistics()); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: statistics = const_cast(m_volumeFile->getMapFastStatistics(mapIndex)); break; } CaretAssert(statistics); const float* thresholdDataPointer = (ignoreThresholding ? mapDataPointer : thresholdVolume->getFrame(thresholdVolumeMapIndex)); const PaletteColorMapping* thresholdPaletteColorMapping = (ignoreThresholding ? m_volumeFile->getMapPaletteColorMapping(mapIndex) : thresholdVolume->getMapPaletteColorMapping(thresholdVolumeMapIndex)); NodeAndVoxelColoring::colorScalarsWithPalette(statistics, m_volumeFile->getMapPaletteColorMapping(mapIndex), mapDataPointer, thresholdPaletteColorMapping, thresholdDataPointer, m_voxelCountPerMap, m_mapRGBA[mapIndex], ignoreThresholding); m_mapColoringValid[mapIndex] = true; } break; case SubvolumeAttributes::LABEL: if (m_voxelCountPerMap > 0) { NodeAndVoxelColoring::colorIndicesWithLabelTable(m_volumeFile->getMapLabelTable(mapIndex), &mapDataPointer[0], m_voxelCountPerMap, m_mapRGBA[mapIndex]); m_mapColoringValid[mapIndex] = true; } break; case SubvolumeAttributes::RGB: { const uint8_t thresholdRGB[3] = { 5, 5, 5 }; const int32_t numberOfComponents = m_volumeFile->getNumberOfComponents(); if ((numberOfComponents == 3) || (numberOfComponents == 4)) { const float* alphaComponents = ((numberOfComponents == 4) ? m_volumeFile->getFrame(mapIndex, 3) : NULL); NodeAndVoxelColoring::colorScalarsWithRGBA(m_volumeFile->getFrame(mapIndex, 0), m_volumeFile->getFrame(mapIndex, 1), m_volumeFile->getFrame(mapIndex, 2), alphaComponents, m_voxelCountPerMap, thresholdRGB, m_mapRGBA[mapIndex]); m_mapColoringValid[mapIndex] = true; } else { CaretLogSevere("An RGB/RGBA volume must contain 3 or 4 components per voxel: " + m_volumeFile->getFileNameNoPath()); } } break; case SubvolumeAttributes::SEGMENTATION: break; case SubvolumeAttributes::VECTOR: break; } CaretLogFine("Time to color map named \"" + m_volumeFile->getMapName(mapIndex) + " in volume file " + m_volumeFile->getFileNameNoPath() + " was " + AString::number(timer.getElapsedTimeMilliseconds()) + " milliseconds"); } /** * Invalidate the RGBA coloring for all maps. */ void VolumeFileVoxelColorizer::invalidateColoring() { std::fill(m_mapColoringValid.begin(), m_mapColoringValid.end(), false); } /** * Get voxel coloring for a slice in a map. If voxel coloring is not ready * (it may be running in a different thread) this method will wait until the * coloring is valid prior to returning the slice's coloring. * * @param mapIndex * Index of map. * @param slicePlane * Plane of the slice. * @param sliceIndex * Index of the slice. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbaOut * RGBA color components out. * @return * Number of voxels with alpha greater than zero */ int64_t VolumeFileVoxelColorizer::getVoxelColorsForSliceInMap(const int32_t mapIndex, const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const { CaretAssertVectorIndex(m_mapRGBA, mapIndex); CaretAssert(sliceIndex >= 0); CaretAssert(rgbaOut); int64_t iStart = 0; int64_t iEnd = m_dimI - 1; int64_t jStart = 0; int64_t jEnd = m_dimJ - 1; int64_t kStart = 0; int64_t kEnd = m_dimK - 1; switch (slicePlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: kStart = sliceIndex; kEnd = sliceIndex; break; case VolumeSliceViewPlaneEnum::CORONAL: jStart = sliceIndex; jEnd = sliceIndex; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: iStart = sliceIndex; iEnd = sliceIndex; break; } /* * Pointer to maps RGBA values */ const uint8_t* mapRGBA = m_mapRGBA[mapIndex]; const GiftiLabelTable* labelTable = (m_volumeFile->isMappedWithLabelTable() ? m_volumeFile->getMapLabelTable(mapIndex) : NULL); if (m_volumeFile->isMappedWithLabelTable()) { CaretAssert(labelTable); } int64_t validVoxelCount = 0; /* * Output RGBA values for slice */ int64_t rgbaOutIndex = 0; for (int64_t k = kStart; k <= kEnd; k++) { for (int64_t j = jStart; j <= jEnd; j++) { for (int64_t i = iStart; i <= iEnd; i++) { const int64_t rgbaOffset = getRgbaOffsetForVoxelIndex(i, j, k); CaretAssertArrayIndex(mapRGBA, m_mapRGBACount, rgbaOffset); rgbaOut[rgbaOutIndex] = mapRGBA[rgbaOffset]; rgbaOut[rgbaOutIndex+1] = mapRGBA[rgbaOffset+1]; rgbaOut[rgbaOutIndex+2] = mapRGBA[rgbaOffset+2]; uint8_t alpha = mapRGBA[rgbaOffset+3]; if (alpha > 0) { if (labelTable != NULL) { /* * For label data, verify that the label is displayed. * If NOT displayed, zero out the alpha value to * prevent display of the data. */ const int32_t dataValue = static_cast(m_volumeFile->getValue(i, j, k, mapIndex)); const GiftiLabel* label = labelTable->getLabel(dataValue); if (label != NULL) { const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); if (item != NULL) { if (item->isSelected(displayGroup, tabIndex) == false) { alpha = 0; } } } } } if (alpha > 0.0) { ++validVoxelCount; } rgbaOut[rgbaOutIndex+3] = alpha; rgbaOutIndex += 4; } } } return validVoxelCount; } /** * Get voxel coloring for a set of voxels. * * @param mapIndex * Index of map. * @param firstVoxelIJK * IJK Indices of first voxel * @param rowStepIJK * IJK Step for moving to next row. * @param columnStepIJK * IJK Step for moving to next column. * @param numberOfRows * Number of rows. * @param numberOfColumns * Number of columns. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbaOut * RGBA color components out. * @return * Number of voxels with alpha greater than zero */ int64_t VolumeFileVoxelColorizer::getVoxelColorsForSliceInMap(const int32_t mapIndex, const int64_t firstVoxelIJK[3], const int64_t rowStepIJK[3], const int64_t columnStepIJK[3], const int64_t numberOfRows, const int64_t numberOfColumns, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const { /* * Pointer to maps RGBA values */ const uint8_t* mapRGBA = m_mapRGBA[mapIndex]; const GiftiLabelTable* labelTable = (m_volumeFile->isMappedWithLabelTable() ? m_volumeFile->getMapLabelTable(mapIndex) : NULL); if (m_volumeFile->isMappedWithLabelTable()) { CaretAssert(labelTable); } int64_t validVoxelCount = 0; int64_t rgbaOutIndex = 0; int64_t rowIJK[3] = { firstVoxelIJK[0], firstVoxelIJK[1], firstVoxelIJK[2] }; for (int64_t iRow = 0; iRow < numberOfRows; iRow++) { int64_t ijk[3] = { rowIJK[0], rowIJK[1], rowIJK[2] }; for (int64_t iCol = 0; iCol < numberOfColumns; iCol++) { const int64_t rgbaOffset = getRgbaOffsetForVoxelIndex(ijk); CaretAssertArrayIndex(mapRGBA, m_mapRGBACount, rgbaOffset); rgbaOut[rgbaOutIndex] = mapRGBA[rgbaOffset]; rgbaOut[rgbaOutIndex+1] = mapRGBA[rgbaOffset+1]; rgbaOut[rgbaOutIndex+2] = mapRGBA[rgbaOffset+2]; uint8_t alpha = mapRGBA[rgbaOffset+3]; if (alpha > 0) { if (labelTable != NULL) { /* * For label data, verify that the label is displayed. * If NOT displayed, zero out the alpha value to * prevent display of the data. */ const int32_t dataValue = static_cast(m_volumeFile->getValue(ijk, mapIndex)); const GiftiLabel* label = labelTable->getLabel(dataValue); if (label != NULL) { const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); if (item != NULL) { if (item->isSelected(displayGroup, tabIndex) == false) { alpha = 0; } } } } } if (alpha > 0.0) { ++validVoxelCount; } rgbaOut[rgbaOutIndex+3] = alpha; rgbaOutIndex += 4; ijk[0] += columnStepIJK[0]; ijk[1] += columnStepIJK[1]; ijk[2] += columnStepIJK[2]; } rowIJK[0] += rowStepIJK[0]; rowIJK[1] += rowStepIJK[1]; rowIJK[2] += rowStepIJK[2]; } return validVoxelCount; } /** * Get voxel coloring for a sub-slice in a map. If voxel coloring is not ready * (it may be running in a different thread) this method will wait until the * coloring is valid prior to returning the slice's coloring. * * @param mapIndex * Index of map. * @param slicePlane * Plane of the slice. * @param sliceIndex * Index of the slice. * @param firstCornerVoxelIndex * Indices of voxel for first corner of sub-slice (inclusive). * @param lastCornerVoxelIndex * Indices of voxel for last corner of sub-slice (inclusive). * @param voxelCountIJK * Voxel counts for each axis. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbaOut * RGBA color components out. * @return * Number of voxels with alpha greater than zero */ int64_t VolumeFileVoxelColorizer::getVoxelColorsForSubSliceInMap(const int32_t mapIndex, const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, const int64_t firstCornerVoxelIndex[3], const int64_t lastCornerVoxelIndex[3], const int64_t* CaretParameterUsedInDebugCompileOnly(voxelCountIJK), const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const { CaretAssertVectorIndex(m_mapRGBA, mapIndex); CaretAssert(sliceIndex >= 0); CaretAssert(rgbaOut); VolumeSpace::OrientTypes orient[3]; m_volumeFile->getOrientation(orient); int orient2dim[3]; int64_t incrementijk[3]; for (int i = 0; i < 3; ++i) { incrementijk[i] = (lastCornerVoxelIndex[i] > firstCornerVoxelIndex[i]) ? 1 : -1; switch (orient[i])//easier to read than indexing by (orient[i] & 3) { case VolumeSpace::LEFT_TO_RIGHT: case VolumeSpace::RIGHT_TO_LEFT: orient2dim[0] = i; break; case VolumeSpace::POSTERIOR_TO_ANTERIOR: case VolumeSpace::ANTERIOR_TO_POSTERIOR: orient2dim[1] = i; break; case VolumeSpace::INFERIOR_TO_SUPERIOR: case VolumeSpace::SUPERIOR_TO_INFERIOR: orient2dim[2] = i; break; } } int outerLoop = -1, innerLoop = -1; int64_t iterijk[3]; switch (slicePlane) { case VolumeSliceViewPlaneEnum::PARASAGITTAL: outerLoop = orient2dim[2]; innerLoop = orient2dim[1]; iterijk[orient2dim[0]] = sliceIndex; break; case VolumeSliceViewPlaneEnum::CORONAL: outerLoop = orient2dim[2]; innerLoop = orient2dim[0]; iterijk[orient2dim[1]] = sliceIndex; break; case VolumeSliceViewPlaneEnum::AXIAL: outerLoop = orient2dim[1]; innerLoop = orient2dim[0]; iterijk[orient2dim[2]] = sliceIndex; break; default: CaretAssert(false); } CaretUsedInDebugCompileOnly(const int64_t voxelCount = (voxelCountIJK[0] * voxelCountIJK[1] * voxelCountIJK[2])); CaretUsedInDebugCompileOnly(const int64_t rgbaCount = voxelCount * 4); /* * Pointer to maps RGBA values */ const uint8_t* mapRGBA = m_mapRGBA[mapIndex]; const GiftiLabelTable* labelTable = (m_volumeFile->isMappedWithLabelTable() ? m_volumeFile->getMapLabelTable(mapIndex) : NULL); if (m_volumeFile->isMappedWithLabelTable()) { CaretAssert(labelTable); } int64_t validVoxelCount = 0; CaretUsedInDebugCompileOnly(int64_t innerCount = std::abs(lastCornerVoxelIndex[innerLoop] - firstCornerVoxelIndex[innerLoop]) + 1);//to check validity of index int64_t rgbaOutIndex = 0; for (iterijk[outerLoop] = firstCornerVoxelIndex[outerLoop]; iterijk[outerLoop] != lastCornerVoxelIndex[outerLoop] + incrementijk[outerLoop]; iterijk[outerLoop] += incrementijk[outerLoop]) { for (iterijk[innerLoop] = firstCornerVoxelIndex[innerLoop]; iterijk[innerLoop] != lastCornerVoxelIndex[innerLoop] + incrementijk[innerLoop]; iterijk[innerLoop] += incrementijk[innerLoop]) { CaretAssert(rgbaOutIndex == 4 * (innerCount * std::abs(iterijk[outerLoop] - firstCornerVoxelIndex[outerLoop]) + std::abs(iterijk[innerLoop] - firstCornerVoxelIndex[innerLoop]))); CaretAssertArrayIndex(rgbaOut, rgbaCount, rgbaOutIndex + 3); const int64_t rgbaOffset = getRgbaOffsetForVoxelIndex(iterijk[0], iterijk[1], iterijk[2]); CaretAssertArrayIndex(mapRGBA, m_mapRGBACount, rgbaOffset); rgbaOut[rgbaOutIndex] = mapRGBA[rgbaOffset]; rgbaOut[rgbaOutIndex+1] = mapRGBA[rgbaOffset+1]; rgbaOut[rgbaOutIndex+2] = mapRGBA[rgbaOffset+2]; uint8_t alpha = mapRGBA[rgbaOffset+3]; if (alpha > 0) { if (labelTable != NULL) { //For label data, verify that the label is displayed. //If NOT displayed, zero out the alpha value to //prevent display of the data. const int32_t dataValue = static_cast(m_volumeFile->getValue(iterijk, mapIndex)); const GiftiLabel* label = labelTable->getLabel(dataValue); if (label != NULL) { const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); if (item != NULL) { if (item->isSelected(displayGroup, tabIndex) == false) { alpha = 0; } } } } } if (alpha > 0.0) { ++validVoxelCount; } rgbaOut[rgbaOutIndex+3] = alpha; rgbaOutIndex += 4; } } return validVoxelCount; } /** * Get the RGBA color components for voxel. * * @param i * Parasaggital index * @param j * Coronal index * @param k * Axial index * @param mapIndex * Index of map. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbaOut * Contains voxel coloring on exit. */ void VolumeFileVoxelColorizer::getVoxelColorInMap(const int64_t i, const int64_t j, const int64_t k, const int64_t mapIndex, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t rgbaOut[4]) const { /* * Pointer to maps RGBA values */ CaretAssertVectorIndex(m_mapRGBA, mapIndex); const uint8_t* mapRGBA = m_mapRGBA[mapIndex]; const int64_t rgbaOffset = getRgbaOffsetForVoxelIndex(i, j, k); CaretAssertArrayIndex(mapRGBA, m_mapRGBACount, rgbaOffset); rgbaOut[0] = mapRGBA[rgbaOffset]; rgbaOut[1] = mapRGBA[rgbaOffset+1]; rgbaOut[2] = mapRGBA[rgbaOffset+2]; uint8_t alpha = mapRGBA[rgbaOffset+3]; if (alpha > 0) { if (m_volumeFile->isMappedWithLabelTable()) { const GiftiLabelTable* labelTable = m_volumeFile->getMapLabelTable(mapIndex); CaretAssert(labelTable); /* * For label data, verify that the label is displayed. * If NOT displayed, zero out the alpha value to * prevent display of the data. */ const int32_t dataValue = static_cast(m_volumeFile->getValue(i, j, k, mapIndex)); const GiftiLabel* label = labelTable->getLabel(dataValue); if (label != NULL) { const GroupAndNameHierarchyItem* item = label->getGroupNameSelectionItem(); if (item != NULL) { if (item->isSelected(displayGroup, tabIndex) == false) { alpha = 0; } } } } } rgbaOut[3] = alpha; } /** * Clear the voxel coloring for the given map. * @param mapIndex * Index of map. */ void VolumeFileVoxelColorizer::clearVoxelColoringForMap(const int64_t mapIndex) { CaretAssertVectorIndex(m_mapRGBA, mapIndex); uint8_t* mapRGBA = m_mapRGBA[mapIndex]; for (int64_t i = 0; i < m_mapRGBACount; i++) { mapRGBA[i] = 0.0; } CaretAssertVectorIndex(m_mapColoringValid, mapIndex); m_mapColoringValid[mapIndex] = false; } connectome-workbench-1.4.2/src/Files/VolumeFileVoxelColorizer.h000066400000000000000000000117751360521144700246260ustar00rootroot00000000000000#ifndef __VOLUME_FILE_VOXEL_COLORIZER_H__ #define __VOLUME_FILE_VOXEL_COLORIZER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "DisplayGroupEnum.h" #include "VolumeSliceViewPlaneEnum.h" namespace caret { class VolumeFile; class VolumeFileVoxelColorizer : public CaretObject { public: VolumeFileVoxelColorizer(VolumeFile* volumeFile); virtual ~VolumeFileVoxelColorizer(); void assignVoxelColorsForMap(const int32_t mapIndex); int64_t getVoxelColorsForSliceInMap(const int32_t mapIndex, const int64_t firstVoxelIJK[3], const int64_t rowStepIJK[3], const int64_t columnStepIJK[3], const int64_t numberOfRows, const int64_t numberOfColumns, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const; int64_t getVoxelColorsForSliceInMap(const int32_t mapIndex, const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const; int64_t getVoxelColorsForSubSliceInMap(const int32_t mapIndex, const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, const int64_t firstCornerVoxelIndex[3], const int64_t lastCornerVoxelIndex[3], const int64_t* voxelCountIJK, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const; void getVoxelColorInMap(const int64_t i, const int64_t j, const int64_t k, const int64_t mapIndex, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t rgbaOut[4]) const; void clearVoxelColoringForMap(const int64_t mapIndex); void invalidateColoring(); private: VolumeFileVoxelColorizer(const VolumeFileVoxelColorizer&); VolumeFileVoxelColorizer& operator=(const VolumeFileVoxelColorizer&); /** * Get theRGBA offset for a voxel index */ inline int64_t getRgbaOffsetForVoxelIndex(const int64_t i, const int64_t j, const int64_t k) const { return (4 * (i + (j * m_dimI) + ((k * m_dimI * m_dimJ)))); } /** * Get theRGBA offset for a voxel index */ inline int64_t getRgbaOffsetForVoxelIndex(const int64_t ijk[3]) const { return (4 * (ijk[0] + (ijk[1] * m_dimI) + ((ijk[2] * m_dimI * m_dimJ)))); } // ADD_NEW_MEMBERS_HERE VolumeFile* m_volumeFile; int64_t m_dimI; int64_t m_dimJ; int64_t m_dimK; int64_t m_voxelCountPerMap; int64_t m_mapCount; int64_t m_mapRGBACount; std::vector m_mapColoringValid; std::vector m_mapRGBA; }; #ifdef __VOLUME_FILE_VOXEL_COLORIZER_DECLARE__ // #endif // __VOLUME_FILE_VOXEL_COLORIZER_DECLARE__ } // namespace #endif //__VOLUME_FILE_VOXEL_COLORIZER_H__ connectome-workbench-1.4.2/src/Files/VolumeMapUndoCommand.cxx000066400000000000000000000115631360521144700242500ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __VOLUME_MAP_UNDO_COMMAND_DECLARE__ #include "VolumeMapUndoCommand.h" #undef __VOLUME_MAP_UNDO_COMMAND_DECLARE__ #include "CaretAssert.h" #include "VolumeFile.h" using namespace caret; /** * \class caret::VolumeMapUndoCommand * \brief Command pattern for volume map modifications that undo and redo. * \ingroup Files */ /** * Constructor. */ VolumeMapUndoCommand::VolumeMapUndoCommand(VolumeFile* volumeFile, const int32_t mapIndex) : CaretUndoCommand(), m_volumeFile(volumeFile), m_mapIndex(mapIndex) { CaretAssert(volumeFile); CaretAssert((mapIndex >= 0) && (mapIndex < volumeFile->getNumberOfMaps())); } /** * Destructor. */ VolumeMapUndoCommand::~VolumeMapUndoCommand() { for (std::vector::iterator iter = m_voxelMementos.begin(); iter != m_voxelMementos.end(); iter++) { delete *iter; } m_voxelMementos.clear(); } /** * Operation that "redoes" the command. * * @param errorMessageOut * Output containing error message. * @return * True if the command executed successfully, else false. */ bool VolumeMapUndoCommand::redo(AString& errorMessageOut) { errorMessageOut.clear(); for (std::vector::iterator iter = m_voxelMementos.begin(); iter != m_voxelMementos.end(); iter++) { const VoxelMemento* voxelMod = *iter; m_volumeFile->setValue(voxelMod->m_redoValue, voxelMod->m_ijk, m_mapIndex); } return true; } /** * Operation that "undoes" the command. */ bool VolumeMapUndoCommand::undo(AString& errorMessageOut) { errorMessageOut.clear(); for (std::vector::iterator iter = m_voxelMementos.begin(); iter != m_voxelMementos.end(); iter++) { const VoxelMemento* voxelMod = *iter; m_volumeFile->setValue(voxelMod->m_undoValue, voxelMod->m_ijk, m_mapIndex); } return true; } /** * @return Number of modified voxels. */ int32_t VolumeMapUndoCommand::count() const { return m_voxelMementos.size(); } /** * Add the redo and undo values for a voxel. * * @param ijk * The voxel's indices. * @param redoValue * Value for redo operation. * @param undoValue * Value for undo operation. */ void VolumeMapUndoCommand::addVoxelRedoUndo(const int64_t ijk[3], const float redoValue, const float undoValue) { m_voxelMementos.push_back(new VoxelMemento(ijk, redoValue, undoValue)); } /** * Add the redo and undo values for a voxel. * * @param i * The voxel's "i" index. * @param j * The voxel's "j" index. * @param k * The voxel's "k" index. * @param redoValue * Value for redo operation. * @param undoValue * Value for undo operation. */ void VolumeMapUndoCommand::addVoxelRedoUndo(const int64_t i, const int64_t j, const int64_t k, const float redoValue, const float undoValue) { const int64_t ijk[3] = { i, j, k }; addVoxelRedoUndo(ijk, redoValue, undoValue); } /* ------------------------------------------------------------------ */ /** * Constructor. * * @param ijk * The voxel's indices. * @param redoValue * Value for redo operation. * @param undoValue * Value for undo operation. */ VolumeMapUndoCommand::VoxelMemento::VoxelMemento(const int64_t ijk[3], const float redoValue, const float undoValue) { m_ijk[0] = ijk[0]; m_ijk[1] = ijk[1]; m_ijk[2] = ijk[2]; m_redoValue = redoValue; m_undoValue = undoValue; } VolumeMapUndoCommand::VoxelMemento::~VoxelMemento() { } connectome-workbench-1.4.2/src/Files/VolumeMapUndoCommand.h000066400000000000000000000053401360521144700236710ustar00rootroot00000000000000#ifndef __VOLUME_MAP_UNDO_COMMAND_H__ #define __VOLUME_MAP_UNDO_COMMAND_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretUndoCommand.h" namespace caret { class VolumeFile; class VolumeMapUndoCommand : public CaretUndoCommand { public: VolumeMapUndoCommand(VolumeFile* volumeFile, const int32_t mapIndex); virtual ~VolumeMapUndoCommand(); virtual bool redo(AString& errorMessageOut); virtual bool undo(AString& errorMessageOut); int32_t count() const; void addVoxelRedoUndo(const int64_t ijk[3], const float redoValue, const float undoValue); void addVoxelRedoUndo(const int64_t i, const int64_t j, const int64_t k, const float redoValue, const float undoValue); // ADD_NEW_METHODS_HERE private: class VoxelMemento { public: VoxelMemento(const int64_t ijk[3], const float redoValue, const float undoValue); ~VoxelMemento(); int64_t m_ijk[3]; float m_redoValue; float m_undoValue; }; VolumeMapUndoCommand(const VolumeMapUndoCommand&); VolumeMapUndoCommand& operator=(const VolumeMapUndoCommand&); VolumeFile* m_volumeFile; const int32_t m_mapIndex; std::vector m_voxelMementos; // ADD_NEW_MEMBERS_HERE }; #ifdef __VOLUME_MAP_UNDO_COMMAND_DECLARE__ // #endif // __VOLUME_MAP_UNDO_COMMAND_DECLARE__ } // namespace #endif //__VOLUME_MAP_UNDO_COMMAND_H__ connectome-workbench-1.4.2/src/Files/VolumePaddingHelper.cxx000066400000000000000000000153321360521144700241120ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "VolumePaddingHelper.h" #include "CaretAssert.h" #include "CaretException.h" #include "FloatMatrix.h" #include "GiftiLabelTable.h" #include "PaletteColorMapping.h" #include "Vector3D.h" #include "VolumeFile.h" #include using namespace caret; using namespace std; VolumePaddingHelper VolumePaddingHelper::padVoxels(const VolumeFile* orig, const int& ipad, const int& jpad, const int& kpad) { VolumePaddingHelper ret; orig->getDimensions(ret.m_origDims); ret.m_ipad = ipad; ret.m_jpad = jpad; ret.m_kpad = kpad; ret.m_origDims.resize(3);//we only care about spatial dimensions ret.m_paddedDims = ret.m_origDims; ret.m_paddedDims[0] += ipad * 2; ret.m_paddedDims[1] += jpad * 2; ret.m_paddedDims[2] += kpad * 2; ret.m_origSform = orig->getSform(); FloatMatrix origSpace(ret.m_origSform); FloatMatrix padSpace = origSpace; for (int i = 0; i < origSpace.getNumberOfRows(); ++i) { padSpace[i][3] -= ipad * origSpace[i][0] + jpad * origSpace[i][1] + kpad * origSpace[i][2]; } ret.m_paddedSform = padSpace.getMatrix(); return ret; } VolumePaddingHelper VolumePaddingHelper::padMM(const VolumeFile* orig, const float& mmpad) { vector > volSpace = orig->getSform(); Vector3D ivec, jvec, kvec, origin, ijorth, jkorth, kiorth; FloatMatrix(volSpace).getAffineVectors(ivec, jvec, kvec, origin); ijorth = ivec.cross(jvec).normal();//conceptually put a sphere on each corner of the volume, find how many voxels are needed to fully enclose them jkorth = jvec.cross(kvec).normal(); kiorth = kvec.cross(ivec).normal(); int ipad = (int)floor(abs(mmpad / ivec.dot(jkorth))) + 1; int jpad = (int)floor(abs(mmpad / jvec.dot(kiorth))) + 1; int kpad = (int)floor(abs(mmpad / kvec.dot(ijorth))) + 1; return padVoxels(orig, ipad, jpad, kpad); } void VolumePaddingHelper::doPadding(const VolumeFile* orig, VolumeFile* padded, const float& padval) const { CaretAssert(padded != orig); bool labelMode = (orig->getType() == SubvolumeAttributes::LABEL); if (!orig->matchesVolumeSpace(m_origDims.data(), m_origSform)) throw CaretException("attempted to pad a volume that doesn't match the one initialized with"); vector newdims = m_paddedDims, curdims = orig->getOriginalDimensions(); while (newdims.size() < curdims.size()) newdims.push_back(curdims[newdims.size()]);//add the nonspatial dimensions from orig padded->reinitialize(newdims, m_paddedSform, orig->getNumberOfComponents(), orig->getType()); vector loopdims; orig->getDimensions(loopdims); for (int c = 0; c < loopdims[4]; ++c) { for (int s = 0; s < loopdims[3]; ++s) { if (c == 0) { if (labelMode) { *(padded->getMapLabelTable(s)) = *(orig->getMapLabelTable(s)); } else { *(padded->getMapPaletteColorMapping(s)) = *(orig->getMapPaletteColorMapping(s)); } padded->setMapName(s, orig->getMapName(s)); } float mypadval = padval; if (labelMode) mypadval = orig->getMapLabelTable(s)->getUnassignedLabelKey(); vector padframe(m_paddedDims[0] * m_paddedDims[1] * m_paddedDims[2], mypadval); int64_t ijk[3], inIndex = 0;//we scan the frame linearly, so we can do this const float* inFrame = orig->getFrame(s, c); for (ijk[2] = 0; ijk[2] < m_origDims[2]; ++ijk[2]) { for (ijk[1] = 0; ijk[1] < m_origDims[1]; ++ijk[1]) { for (ijk[0] = 0; ijk[0] < m_origDims[0]; ++ijk[0]) { int64_t outIndex = padded->getIndex(ijk[0] + m_ipad, ijk[1] + m_jpad, ijk[2] + m_kpad); padframe[outIndex] = inFrame[inIndex];//I could use pointer math instead, but that is needlessly obtuse ++inIndex; } } } padded->setFrame(padframe.data(), s, c); } } } void VolumePaddingHelper::undoPadding(const VolumeFile* padded, VolumeFile* orig) const { CaretAssert(orig != padded); if (!padded->matchesVolumeSpace(m_paddedDims.data(), m_paddedSform)) throw CaretException("attempted to unpad a volume that doesn't match padding"); vector newdims = m_origDims, curdims = padded->getOriginalDimensions(); while (newdims.size() < curdims.size()) newdims.push_back(curdims[newdims.size()]);//add the nonspatial dimensions from padded orig->reinitialize(newdims, m_origSform, padded->getNumberOfComponents(), padded->getType()); vector unpadframe(m_origDims[0] * m_origDims[1] * m_origDims[2]); vector loopdims; padded->getDimensions(loopdims); for (int c = 0; c < loopdims[4]; ++c) { for (int s = 0; s < loopdims[3]; ++s) { if (c == 0) { if (padded->getType() == SubvolumeAttributes::LABEL) { *(orig->getMapLabelTable(s)) = *(padded->getMapLabelTable(s)); } else { *(orig->getMapPaletteColorMapping(s)) = *(padded->getMapPaletteColorMapping(s)); } orig->setMapName(s, padded->getMapName(s)); } int64_t ijk[3], outIndex = 0;//we scan the frame linearly, so we can do this for (ijk[2] = 0; ijk[2] < m_origDims[2]; ++ijk[2]) { for (ijk[1] = 0; ijk[1] < m_origDims[1]; ++ijk[1]) { for (ijk[0] = 0; ijk[0] < m_origDims[0]; ++ijk[0]) { unpadframe[outIndex] = padded->getValue(ijk[0] + m_ipad, ijk[1] + m_jpad, ijk[2] + m_kpad, s, c); ++outIndex; } } } orig->setFrame(unpadframe.data(), s, c); } } } connectome-workbench-1.4.2/src/Files/VolumePaddingHelper.h000066400000000000000000000034431360521144700235370ustar00rootroot00000000000000#ifndef __VOLUME_PADDING_HELPER_H__ #define __VOLUME_PADDING_HELPER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "stdint.h" #include namespace caret { class VolumeFile; class VolumePaddingHelper { std::vector > m_origSform, m_paddedSform; std::vector m_origDims, m_paddedDims; int64_t m_ipad, m_jpad, m_kpad;//hopefully apple doesn't sue us public: VolumePaddingHelper() { } static VolumePaddingHelper padMM(const VolumeFile* orig, const float& mmpad); static VolumePaddingHelper padVoxels(const VolumeFile* orig, const int& ipad, const int& jpad, const int& kpad); void getPadding(int& ipad, int& jpad, int& kpad) const { ipad = m_ipad; jpad = m_jpad; kpad = m_kpad; } void doPadding(const VolumeFile* orig, VolumeFile* padded, const float& padval = 0.0f) const; void undoPadding(const VolumeFile* padded, VolumeFile* orig) const; }; } #endif //__VOLUME_PADDING_HELPER_H__ connectome-workbench-1.4.2/src/Files/VolumeSliceProjectionTypeEnum.cxx000066400000000000000000000261411360521144700261670ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __VOLUME_SLICE_PROJECTION_TYPE_ENUM_DECLARE__ #include "VolumeSliceProjectionTypeEnum.h" #undef __VOLUME_SLICE_PROJECTION_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::VolumeSliceProjectionTypeEnum * \brief Type of projection for drawing a volume slice * * Draw volume slice with an oblique or orthogonal projection * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_volumeSliceProjectionTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void volumeSliceProjectionTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "VolumeSliceProjectionTypeEnum.h" * * Instatiate: * m_volumeSliceProjectionTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_volumeSliceProjectionTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_volumeSliceProjectionTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(volumeSliceProjectionTypeEnumComboBoxItemActivated())); * * Update the selection: * m_volumeSliceProjectionTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const VolumeSliceProjectionTypeEnum::Enum VARIABLE = m_volumeSliceProjectionTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ VolumeSliceProjectionTypeEnum::VolumeSliceProjectionTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ VolumeSliceProjectionTypeEnum::~VolumeSliceProjectionTypeEnum() { } /** * Initialize the enumerated metadata. */ void VolumeSliceProjectionTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(VolumeSliceProjectionTypeEnum(VOLUME_SLICE_PROJECTION_OBLIQUE, "VOLUME_SLICE_PROJECTION_OBLIQUE", "Oblique")); enumData.push_back(VolumeSliceProjectionTypeEnum(VOLUME_SLICE_PROJECTION_ORTHOGONAL, "VOLUME_SLICE_PROJECTION_ORTHOGONAL", "Orthogonal")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const VolumeSliceProjectionTypeEnum* VolumeSliceProjectionTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const VolumeSliceProjectionTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString VolumeSliceProjectionTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const VolumeSliceProjectionTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ VolumeSliceProjectionTypeEnum::Enum VolumeSliceProjectionTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = VolumeSliceProjectionTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const VolumeSliceProjectionTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type VolumeSliceProjectionTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString VolumeSliceProjectionTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const VolumeSliceProjectionTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ VolumeSliceProjectionTypeEnum::Enum VolumeSliceProjectionTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = VolumeSliceProjectionTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const VolumeSliceProjectionTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type VolumeSliceProjectionTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t VolumeSliceProjectionTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const VolumeSliceProjectionTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ VolumeSliceProjectionTypeEnum::Enum VolumeSliceProjectionTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = VolumeSliceProjectionTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const VolumeSliceProjectionTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type VolumeSliceProjectionTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void VolumeSliceProjectionTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void VolumeSliceProjectionTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(VolumeSliceProjectionTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void VolumeSliceProjectionTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(VolumeSliceProjectionTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Files/VolumeSliceProjectionTypeEnum.h000066400000000000000000000064731360521144700256220ustar00rootroot00000000000000#ifndef __VOLUME_SLICE_PROJECTION_TYPE_ENUM_H__ #define __VOLUME_SLICE_PROJECTION_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class VolumeSliceProjectionTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Draw volume slice with an oblique projection */ VOLUME_SLICE_PROJECTION_OBLIQUE, /** Draw volume slice with an orthogonal projection */ VOLUME_SLICE_PROJECTION_ORTHOGONAL }; ~VolumeSliceProjectionTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: VolumeSliceProjectionTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const VolumeSliceProjectionTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __VOLUME_SLICE_PROJECTION_TYPE_ENUM_DECLARE__ std::vector VolumeSliceProjectionTypeEnum::enumData; bool VolumeSliceProjectionTypeEnum::initializedFlag = false; int32_t VolumeSliceProjectionTypeEnum::integerCodeCounter = 0; #endif // __VOLUME_SLICE_PROJECTION_TYPE_ENUM_DECLARE__ } // namespace #endif //__VOLUME_SLICE_PROJECTION_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/Files/VolumeSpline.cxx000066400000000000000000000241611360521144700226360ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretOMP.h" #include "CubicSpline.h" #include "MathFunctions.h" #include "VolumeSpline.h" #include #include #include using namespace std; using namespace caret; VolumeSpline::VolumeSpline() { m_ignoredNonNumeric = false; m_dims[0] = 0; m_dims[1] = 0; m_dims[2] = 0; } VolumeSpline::VolumeSpline(const float* frame, const int64_t framedims[3]) { m_ignoredNonNumeric = false; m_dims[0] = framedims[0]; m_dims[1] = framedims[1]; m_dims[2] = framedims[2]; m_deconv = CaretArray(m_dims[0] * m_dims[1] * m_dims[2]); CaretArray scratchArray(m_dims[0] * max(m_dims[1], m_dims[2])), deconvScratch(max(m_dims[0], max(m_dims[1], m_dims[2])));//allocate as much as we will need, even if we don't use it all yet predeconvolve(deconvScratch, m_dims[0]); for (int k = 0; k < m_dims[2]; ++k) { int64_t index = m_dims[0] * m_dims[1] * k; int64_t index2 = 0; for (int j = 0; j < m_dims[1]; ++j) { for (int i = 0; i < m_dims[0]; ++i) { float tempf = frame[index]; if (MathFunctions::isNumeric(tempf)) { scratchArray[index2] = tempf; } else { scratchArray[index2] = 0.0f; m_ignoredNonNumeric = true; } ++index; ++index2; } } #pragma omp CARET_PARFOR schedule(dynamic) for (int j = 0; j < m_dims[1]; ++j) { int64_t privIndex = j * m_dims[0]; deconvolve(scratchArray.getArray() + privIndex, deconvScratch, m_dims[0]); } index = m_dims[0] * m_dims[1] * k; index2 = 0; for (int j = 0; j < m_dims[1]; ++j) { for (int i = 0; i < m_dims[0]; ++i) { m_deconv[index] = scratchArray[index2]; ++index; ++index2; } } } predeconvolve(deconvScratch, m_dims[1]); for (int k = 0; k < m_dims[2]; ++k) { int64_t indexbase = k * m_dims[1] * m_dims[0]; int64_t index = indexbase; for (int j = 0; j < m_dims[1]; ++j) { int64_t index2 = j; for (int i = 0; i < m_dims[0]; ++i) { scratchArray[index2] = m_deconv[index];//read linearly from frame while writing transposed should be slightly faster, because cache can stay dirty? index2 += m_dims[1]; ++index; } } #pragma omp CARET_PARFOR schedule(dynamic) for (int i = 0; i < m_dims[0]; ++i) { int64_t privindex = i * m_dims[1]; deconvolve(scratchArray.getArray() + privindex, deconvScratch, m_dims[1]); } index = 0; for (int i = 0; i < m_dims[0]; ++i) { int64_t index2 = i + indexbase; for (int j = 0; j < m_dims[1]; ++j) { m_deconv[index2] = scratchArray[index];//even though scratch should be cached now, if writing to frame collides, reading linearly should give better behavior ++index; index2 += m_dims[0]; } } } predeconvolve(deconvScratch, m_dims[2]); for (int j = 0; j < m_dims[1]; ++j)//finally, use a similar strategy to do linear reads instead of widely interleaved reads for k-rows { int64_t indexbase = j * m_dims[0]; int64_t increment = m_dims[1] * m_dims[0]; for (int k = 0; k < m_dims[2]; ++k) { int64_t index = indexbase + k * increment; int64_t index2 = k; for (int i = 0; i < m_dims[0]; ++i) { scratchArray[index2] = m_deconv[index]; index2 += m_dims[2]; ++index; } } #pragma omp CARET_PARFOR schedule(dynamic) for (int i = 0; i < m_dims[0]; ++i) { int64_t privindex = i * m_dims[2]; deconvolve(scratchArray.getArray() + privindex, deconvScratch, m_dims[2]); } for (int i = 0; i < m_dims[0]; ++i) { int64_t index = indexbase + i; int64_t index2 = i * m_dims[2]; for (int k = 0; k < m_dims[2]; ++k) { m_deconv[index] = scratchArray[index2]; index += increment; ++index2; } } } } float VolumeSpline::sample(const float& ifloat, const float& jfloat, const float& kfloat) { if (m_dims[0] < 2 || ifloat < 0.0f || jfloat < 0.0f || kfloat < 0.0f || ifloat > m_dims[0] - 1 || jfloat > m_dims[1] - 1 || kfloat > m_dims[2] - 1) return 0.0f;//yeesh const int64_t zstep = m_dims[0] * m_dims[1]; float iparti, ipartj, ipartk; float fparti = modf(ifloat, &iparti); float fpartj = modf(jfloat, &ipartj); float fpartk = modf(kfloat, &ipartk); int64_t lowi = (int64_t)iparti; int64_t lowj = (int64_t)ipartj; int64_t lowk = (int64_t)ipartk; bool lowedgei = (lowi < 1); bool lowedgej = (lowj < 1); bool lowedgek = (lowk < 1); bool highedgei = (lowi >= m_dims[0] - 2); bool highedgej = (lowj >= m_dims[1] - 2); bool highedgek = (lowk >= m_dims[2] - 2); CubicSpline ispline = CubicSpline::bspline(fparti, lowedgei, highedgei); CubicSpline jspline = CubicSpline::bspline(fpartj, lowedgej, highedgej); CubicSpline kspline = CubicSpline::bspline(fpartk, lowedgek, highedgek); float jtemp[4], ktemp[4];//the weights of the splines are zero for off-the edge values, but zero the data anyway jtemp[0] = 0.0f; jtemp[3] = 0.0f; ktemp[0] = 0.0f; ktemp[3] = 0.0f; if (lowedgei || lowedgej || lowedgek || highedgei || highedgej || highedgek) {//there is an edge nearby, use the generic version with more conditionals int jstart = lowedgej ? 1 : 0; int kstart = lowedgek ? 1 : 0; int jend = highedgej ? 3 : 4; int kend = highedgek ? 3 : 4; for (int k = kstart; k < kend; ++k) { int64_t indexk = (k + lowk - 1) * zstep; for (int j = jstart; j < jend; ++j) { int64_t indexj = indexk + (j + lowj - 1) * m_dims[0] + lowi - 1; if (lowedgei)//have to do these tests for the simple reason that otherwise we might access off the end of the array in two of the 8 corners { if (highedgei) { jtemp[j] = ispline.evalBothEdge(m_deconv[indexj + 1], m_deconv[indexj + 2]); } else { jtemp[j] = ispline.evalLowEdge(m_deconv[indexj + 1], m_deconv[indexj + 2], m_deconv[indexj + 3]); } } else { if (highedgei) { jtemp[j] = ispline.evalHighEdge(m_deconv[indexj], m_deconv[indexj + 1], m_deconv[indexj + 2]); } else { jtemp[j] = ispline.evaluate(m_deconv[indexj], m_deconv[indexj + 1], m_deconv[indexj + 2], m_deconv[indexj + 3]); } } } ktemp[k] = jspline.evaluate(jtemp[0], jtemp[1], jtemp[2], jtemp[3]); } return kspline.evaluate(ktemp[0], ktemp[1], ktemp[2], ktemp[3]); } else {//we are clear of all edges, we can use fewer conditionals int64_t indexbase = lowi - 1 + m_dims[0] * (lowj - 1 + m_dims[1] * (lowk - 1)); const float* basePtr = m_deconv.getArray() + indexbase; int64_t indexk = 0; for (int k = 0; k < 4; ++k) { int64_t indexj = indexk; for (int j = 0; j < 4; ++j) { jtemp[j] = ispline.evaluate(basePtr[indexj], basePtr[indexj + 1], basePtr[indexj + 2], basePtr[indexj + 3]); indexj += m_dims[0]; } ktemp[k] = jspline.evaluate(jtemp[0], jtemp[1], jtemp[2], jtemp[3]); indexk += zstep; } return kspline.evaluate(ktemp[0], ktemp[1], ktemp[2], ktemp[3]); } } void VolumeSpline::deconvolve(float* data, const float* backsubs, const int64_t& length) { if (length < 1) return; const float A = 1.0f / 6.0f, B = 2.0f / 3.0f;//the coefficients of a bspline at center and +/-1 //forward pass simulating gaussian elimination on matrix of bspline kernels and data data[0] /= B + A;//repeat final value for data outside the bounding box, to prevent bright edges for (int i = 1; i < length - 1; ++i)//the first and last rows are handled slightly differently { data[i] = (data[i] - A * data[i - 1]) / (B - A * backsubs[i - 1]); } data[length - 1] = (data[length - 1] - A * data[length - 2]) / (B + A - A * backsubs[length - 2]);//repeat final value for data outside the bounding box, to prevent bright edges //back substitution, making it gauss-jordan for (int i = length - 2; i >= 0; --i)//the last row doesn't need back-substitution { data[i] -= backsubs[i] * data[i + 1]; } } void VolumeSpline::predeconvolve(float* backsubs, const int64_t& length) { if (length < 1) return; const float A = 1.0f / 6.0f, B = 2.0f / 3.0f; backsubs[0] = A / (B + A);//repeat final value for data outside the bounding box, to prevent bright edges for (int i = 1; i < length; ++i) { backsubs[i] = A / (B - A * backsubs[i - 1]); } } connectome-workbench-1.4.2/src/Files/VolumeSpline.h000066400000000000000000000036511360521144700222640ustar00rootroot00000000000000#ifndef __VOLUME_SPLINE_H__ #define __VOLUME_SPLINE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "stdint.h" #include "CaretPointer.h" namespace caret { class VolumeSpline { bool m_ignoredNonNumeric; int64_t m_dims[3]; CaretArray m_deconv;//don't do lazy deconvolution, it doesn't save much time, and takes more memory and slightly longer if you have to do the whole volume anyway void deconvolve(float* data, const float* backsubs, const int64_t& length);//use CaretArray so that it doesn't reallocate like a vector on copy, and the data is static once computed void predeconvolve(float* backsubs, const int64_t& length);//since the back substitution on the same size array uses the same coefficients, precompute them public: VolumeSpline(); VolumeSpline(const float* frame, const int64_t framedims[3]); float sample(const float& i, const float& j, const float& k); float sample(const float ijk[3]) { return sample(ijk[0], ijk[1], ijk[2]); } bool ignoredNonNumeric() const { return m_ignoredNonNumeric; } }; } #endif //__VOLUME_SPLINE_H__ connectome-workbench-1.4.2/src/Files/VtkFileExporter.cxx000066400000000000000000000366741360521144700233250ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __VTK_FILE_EXPORTER_DECLARE__ #include "VtkFileExporter.h" #undef __VTK_FILE_EXPORTER_DECLARE__ #include "AString.h" #include "ByteOrderEnum.h" #include "CaretAssert.h" #include "DataFileException.h" #include "FileAdapter.h" #include "SurfaceFile.h" #include "XmlWriter.h" #include using namespace caret; /** * \class caret::VtkFileExporter * \brief Exports data into VTK file formats. * \ingroup Files */ /** * Write the given surface files using the coloring from the given browser tab. * * File format documented at: http://www.vtk.org/VTK/img/file-formats.pdf * * @param surfaceFile * The surface file. * @param surfaceFilesColoring * RGBA coloring for each of the surfaces. * @param vtkFileName * Name of the VTK file. */ void VtkFileExporter::writeSurfaces(const std::vector& surfaceFiles, const std::vector& surfaceFilesColoring, const AString& vtkFileName) { try { const int32_t numberOfSurfaceFiles = static_cast(surfaceFiles.size()); if (numberOfSurfaceFiles <= 0) { throw DataFileException(vtkFileName, "No surfaces provided for export to VTK."); } CaretAssert(surfaceFiles.size() == surfaceFilesColoring.size()); int32_t totalNodes = 0; int32_t totalTriangles = 0; float coordinateMinimum = std::numeric_limits::max(); float coordinateMaximum = -std::numeric_limits::max(); for (int32_t iSurface = 0; iSurface < numberOfSurfaceFiles; iSurface++) { SurfaceFile* surfaceFile = surfaceFiles[iSurface]; const int32_t numberOfNodes = surfaceFile->getNumberOfNodes(); totalNodes += numberOfNodes; const int32_t numberOfTriangles = surfaceFile->getNumberOfTriangles(); totalTriangles += numberOfTriangles; for (int32_t iNode = 0; iNode < numberOfNodes; iNode++) { const float* xyz = surfaceFile->getCoordinate(iNode); for (int32_t i = 0; i < 3; i++) { if (xyz[i] < coordinateMinimum) coordinateMinimum = xyz[i]; if (xyz[i] > coordinateMaximum) coordinateMaximum = xyz[i]; } } } if (totalNodes <= 0) { throw DataFileException(vtkFileName, "Surfaces contain no nodes"); } if (totalNodes <= 0) { throw DataFileException(vtkFileName, "Surfaces contain no triangles"); } /* * Open a text stream */ FileAdapter fileAdapter; AString errorMessage; QTextStream* textStream = fileAdapter.openQTextStreamForWritingFile(vtkFileName, errorMessage); if (textStream == NULL) { throw DataFileException(vtkFileName, errorMessage); } /* * Create the XML Writer */ XmlWriter xmlWriter(*textStream); xmlWriter.writeStartDocument("1.0"); /* * Write the root element */ XmlAttributes rootAttributes; rootAttributes.addAttribute("type", "PolyData"); rootAttributes.addAttribute("version", "0.1"); switch (ByteOrderEnum::getSystemEndian()) { case ByteOrderEnum::ENDIAN_BIG: rootAttributes.addAttribute("byte_order", "BigEndian"); break; case ByteOrderEnum::ENDIAN_LITTLE: rootAttributes.addAttribute("byte_order", "LittleEndian"); break; } rootAttributes.addAttribute("compressor", "vtkZLibDataCompressor"); xmlWriter.writeStartElement("VTKFile", rootAttributes); /* * Start PolyData element */ xmlWriter.writeStartElement("PolyData"); /* * Start Piece element */ XmlAttributes pieceAttributes; pieceAttributes.addAttribute("NumberOfPoints", totalNodes); pieceAttributes.addAttribute("NumberOfVerts", 0); pieceAttributes.addAttribute("NumberOfLines", 0); pieceAttributes.addAttribute("NumberOfStrips", 0); pieceAttributes.addAttribute("NumberOfPolys", totalTriangles); xmlWriter.writeStartElement("Piece", pieceAttributes); /* * Start PointData */ XmlAttributes pointDataAttributes; pointDataAttributes.addAttribute("Scalars", "Scalars_"); pointDataAttributes.addAttribute("Normals", "Normals"); xmlWriter.writeStartElement("PointData", pointDataAttributes); /* * Start Normal Vectors DataArray element */ XmlAttributes dataArrayNormalsAttributes; dataArrayNormalsAttributes.addAttribute("type", "Float32"); dataArrayNormalsAttributes.addAttribute("Name", "Normals"); dataArrayNormalsAttributes.addAttribute("NumberOfComponents", 3); dataArrayNormalsAttributes.addAttribute("format", "ascii"); dataArrayNormalsAttributes.addAttribute("RangeMin", -1.0); dataArrayNormalsAttributes.addAttribute("RangeMax", 1.0); xmlWriter.writeStartElement("DataArray", dataArrayNormalsAttributes); for (int32_t iSurface = 0; iSurface < numberOfSurfaceFiles; iSurface++) { const SurfaceFile* sf = surfaceFiles[iSurface]; const int32_t numberOfNodes = sf->getNumberOfNodes(); for (int32_t iNode = 0; iNode < numberOfNodes; iNode++) { const float* normalVector = sf->getNormalVector(iNode); xmlWriter.writeCharactersWithIndent(AString::number(normalVector[0])); xmlWriter.writeCharacters(" "); xmlWriter.writeCharacters(AString::number(normalVector[1])); xmlWriter.writeCharacters(" "); xmlWriter.writeCharacters(AString::number(normalVector[2])); xmlWriter.writeCharacters("\n"); } } /* * End DataArray Normals element */ xmlWriter.writeEndElement(); /* * Start Scalars DataArray element * that contains the RGB colors */ XmlAttributes dataArrayScalarsAttributes; dataArrayScalarsAttributes.addAttribute("type", "UInt8"); dataArrayScalarsAttributes.addAttribute("Name", "Scalars_"); dataArrayScalarsAttributes.addAttribute("NumberOfComponents", 3); dataArrayScalarsAttributes.addAttribute("format", "ascii"); dataArrayScalarsAttributes.addAttribute("RangeMin", 0); dataArrayScalarsAttributes.addAttribute("RangeMax", 255); xmlWriter.writeStartElement("DataArray", dataArrayScalarsAttributes); for (int32_t iSurface = 0; iSurface < numberOfSurfaceFiles; iSurface++) { SurfaceFile* sf = surfaceFiles[iSurface]; const float* surfaceRGBA = surfaceFilesColoring[iSurface]; const int32_t numberOfNodes = sf->getNumberOfNodes(); for (int32_t iNode = 0; iNode < numberOfNodes; iNode++) { const float* rgbaFloat = &surfaceRGBA[iNode * 4]; uint8_t rgb[3]; for (int32_t k = 0; k < 3; k++) { float value = rgbaFloat[k] * 255.0; if (value > 255.0) value = 255.0; if (value < 0.0) value = 0.0; const uint8_t byteValue = static_cast(value); rgb[k] = byteValue; } xmlWriter.writeCharactersWithIndent(AString::number(rgb[0])); xmlWriter.writeCharacters(" "); xmlWriter.writeCharacters(AString::number(rgb[1])); xmlWriter.writeCharacters(" "); xmlWriter.writeCharacters(AString::number(rgb[2])); xmlWriter.writeCharacters("\n"); } } /* * End DataArray Scalars element */ xmlWriter.writeEndElement(); /* * End PointData */ xmlWriter.writeEndElement(); /* * No Cell Data */ xmlWriter.writeStartElement("CellData"); xmlWriter.writeEndElement(); /* * Start Points element */ xmlWriter.writeStartElement("Points"); /* * Start Coordinates DataArray element */ XmlAttributes dataArrayPointsAttributes; dataArrayPointsAttributes.addAttribute("type", "Float32"); dataArrayPointsAttributes.addAttribute("Name", "Points"); dataArrayPointsAttributes.addAttribute("NumberOfComponents", 3); dataArrayPointsAttributes.addAttribute("format", "ascii"); dataArrayPointsAttributes.addAttribute("RangeMin", coordinateMinimum); dataArrayPointsAttributes.addAttribute("RangeMax", coordinateMaximum); xmlWriter.writeStartElement("DataArray", dataArrayPointsAttributes); for (int32_t iSurface = 0; iSurface < numberOfSurfaceFiles; iSurface++) { const SurfaceFile* sf = surfaceFiles[iSurface]; const int32_t numberOfNodes = sf->getNumberOfNodes(); for (int32_t iNode = 0; iNode < numberOfNodes; iNode++) { const float* normalVector = sf->getCoordinate(iNode); xmlWriter.writeCharactersWithIndent(AString::number(normalVector[0])); xmlWriter.writeCharacters(" "); xmlWriter.writeCharacters(AString::number(normalVector[1])); xmlWriter.writeCharacters(" "); xmlWriter.writeCharacters(AString::number(normalVector[2])); xmlWriter.writeCharacters("\n"); } } /* * End DataArray Coordinates */ xmlWriter.writeEndElement(); /* * End Points element */ xmlWriter.writeEndElement(); /* * Empty Verts Element */ xmlWriter.writeStartElement("Verts"); xmlWriter.writeEndElement(); /* * Empty Lines Element */ xmlWriter.writeStartElement("Lines"); xmlWriter.writeEndElement(); /* * Empty Strips Element */ xmlWriter.writeStartElement("Strips"); xmlWriter.writeEndElement(); /* * Start Polys Element */ xmlWriter.writeStartElement("Polys"); /* * Start DataArray for nodes in every triangle */ XmlAttributes dataArrayTrianglesAttributes; dataArrayTrianglesAttributes.addAttribute("type", "Int64"); dataArrayTrianglesAttributes.addAttribute("Name", "connectivity"); dataArrayTrianglesAttributes.addAttribute("format", "ascii"); dataArrayTrianglesAttributes.addAttribute("RangeMin", 0); dataArrayTrianglesAttributes.addAttribute("RangeMax", totalNodes - 1); xmlWriter.writeStartElement("DataArray", dataArrayTrianglesAttributes); /* * Write the nodes in every triangle */ int32_t triangleNodeOffset = 0; for (int32_t iSurface = 0; iSurface < numberOfSurfaceFiles; iSurface++) { const SurfaceFile* sf = surfaceFiles[iSurface]; const int32_t numberOfTriangles = sf->getNumberOfTriangles(); for (int32_t iTriangle = 0; iTriangle < numberOfTriangles; iTriangle++) { const int32_t* triangleNodes = sf->getTriangle(iTriangle); xmlWriter.writeCharactersWithIndent(AString::number(triangleNodes[0] + triangleNodeOffset)); xmlWriter.writeCharacters(" "); xmlWriter.writeCharacters(AString::number(triangleNodes[1] + triangleNodeOffset)); xmlWriter.writeCharacters(" "); xmlWriter.writeCharacters(AString::number(triangleNodes[2] + triangleNodeOffset)); xmlWriter.writeCharacters("\n"); } /* * All surface nodes are in one list so offset for additional surfaces */ triangleNodeOffset += sf->getNumberOfNodes(); } /* * End DataArray for nodes in every triangle */ xmlWriter.writeEndElement(); /* * Start DataArray for offset of each triangle */ XmlAttributes dataArrayTriangleOffsetAttributes; dataArrayTriangleOffsetAttributes.addAttribute("type", "Int64"); dataArrayTriangleOffsetAttributes.addAttribute("Name", "offsets"); dataArrayTriangleOffsetAttributes.addAttribute("format", "ascii"); dataArrayTriangleOffsetAttributes.addAttribute("RangeMin", 0); dataArrayTriangleOffsetAttributes.addAttribute("RangeMax", totalTriangles - 1); xmlWriter.writeStartElement("DataArray", dataArrayTriangleOffsetAttributes); /* * Write offset of each triangle */ for (int32_t i = 1; i <= totalTriangles; i++) { if ((i % 6) == 0) { if (i > 0) { xmlWriter.writeCharacters("\n"); } xmlWriter.writeCharactersWithIndent(AString::number(i * 3)); } else { xmlWriter.writeCharacters(AString::number(i * 3)); } xmlWriter.writeCharacters(" "); } xmlWriter.writeCharacters("\n"); /* * End DataArray for offset of each triangle */ xmlWriter.writeEndElement(); /* * End Polys Element */ xmlWriter.writeEndElement(); /* * End Piece element */ xmlWriter.writeEndElement(); /* * End PolyData element */ xmlWriter.writeEndElement(); /* * End root element */ xmlWriter.writeEndElement(); /* * Finish XML and close file */ xmlWriter.writeEndDocument(); fileAdapter.close(); } catch (const XmlException& e) { throw DataFileException(vtkFileName, e.whatString()); } } connectome-workbench-1.4.2/src/Files/VtkFileExporter.h000066400000000000000000000033621360521144700227360ustar00rootroot00000000000000#ifndef __VTK_FILE_EXPORTER_H__ #define __VTK_FILE_EXPORTER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AString.h" #include namespace caret { class SurfaceFile; class VtkFileExporter { public: static void writeSurfaces(const std::vector& surfaceFiles, const std::vector& surfaceFilesColoring, const AString& vtkFileName); private: VtkFileExporter(); virtual ~VtkFileExporter(); VtkFileExporter(const VtkFileExporter&); VtkFileExporter& operator=(const VtkFileExporter&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE }; #ifdef __VTK_FILE_EXPORTER_DECLARE__ // #endif // __VTK_FILE_EXPORTER_DECLARE__ } // namespace #endif //__VTK_FILE_EXPORTER_H__ connectome-workbench-1.4.2/src/Files/WarpfieldFile.cxx000066400000000000000000000244261360521144700227350ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WarpfieldFile.h" #include "CaretAssert.h" #include "CaretOMP.h" #include "FileInformation.h" #include "FloatMatrix.h" #include "NiftiIO.h" using namespace caret; using namespace std; CaretPointer WarpfieldFile::generateAbsolute() const { if (m_warpfield == NULL) { throw DataFileException("generateAbsolute() called on uninitialized WarpfieldFile"); } CaretPointer ret(new VolumeFile()); vector dims = m_warpfield->getDimensions(); CaretAssert(dims[3] == 3);//make sure it looks like a warpfield dims.resize(4);//drop number of components ret->reinitialize(dims, m_warpfield->getSform()); ret->setMapName(0, "x location"); ret->setMapName(1, "y location"); ret->setMapName(2, "z location"); for (int b = 0; b < 3; ++b) { for (int64_t k = 0; k < dims[2]; ++k) { for (int64_t j = 0; j < dims[1]; ++j) { for (int64_t i = 0; i < dims[0]; ++i) { Vector3D voxelCenter; m_warpfield->indexToSpace(i, j, k, voxelCenter); ret->setValue(m_warpfield->getValue(i, j, k, b) + voxelCenter[b], i, j, k, b); } } } } return ret; } namespace { void genericWarpfieldRead(VolumeFile& volOut, const AString& filename) { volOut.readFile(filename); vector dims; volOut.getDimensions(dims); if (dims[3] != 3) { throw DataFileException("volume file '" + filename + "' has the wrong number of subvolumes for a warpfield"); } if (dims[4] != 1) { throw DataFileException("volume file '" + filename + "' has multiple components, which is not allowed in a warpfield"); } volOut.setMapName(0, "x displacement"); volOut.setMapName(1, "y displacement"); volOut.setMapName(2, "z displacement"); } } void WarpfieldFile::readWorld(const AString& warpname) { CaretPointer newFile(new VolumeFile()); genericWarpfieldRead(*newFile, warpname); m_warpfield = newFile;//drop the previous warpfield, and replace with the new one } void WarpfieldFile::readITK(const AString& warpname) { CaretPointer newFile(new VolumeFile()); genericWarpfieldRead(*newFile, warpname); vector dims; newFile->getDimensions(dims); for (int64_t k = 0; k < dims[2]; ++k) { for (int64_t j = 0; j < dims[1]; ++j) { for (int64_t i = 0; i < dims[0]; ++i) { newFile->setValue(-newFile->getValue(i, j, k, 0), i, j, k, 0);//negate x and y to convert LPS displacements to RAS newFile->setValue(-newFile->getValue(i, j, k, 1), i, j, k, 1); } } } m_warpfield = newFile; } void WarpfieldFile::readFnirt(const AString& warpName, const AString& sourceName, const bool& absolute) { FloatMatrix sourceSform, sourceFSL, refSform, refFSL; NiftiIO myIO; myIO.openRead(warpName); refSform = FloatMatrix(myIO.getHeader().getSForm()); refFSL = FloatMatrix(myIO.getHeader().getFSLSpace()); myIO.openRead(sourceName); sourceSform = FloatMatrix(myIO.getHeader().getSForm()); sourceFSL = FloatMatrix(myIO.getHeader().getFSLSpace()); CaretPointer newFile(new VolumeFile()); genericWarpfieldRead(*newFile, warpName); vector dims; newFile->getDimensions(dims); FloatMatrix sourceTransform = sourceSform * sourceFSL.inverse();//goes from FSL source space to real source space Vector3D sourceTransX, sourceTransY, sourceTransZ, sourceTransOff; sourceTransform.getAffineVectors(sourceTransX, sourceTransY, sourceTransZ, sourceTransOff); Vector3D fslX, fslY, fslZ, fslOff; refFSL.getAffineVectors(fslX, fslY, fslZ, fslOff); int64_t numVox = dims[0] * dims[1] * dims[2]; vector> scratchFrames(3, vector(numVox, 0.0f)); #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t k = 0; k < dims[2]; ++k) { for (int64_t j = 0; j < dims[1]; ++j) { for (int64_t i = 0; i < dims[0]; ++i) { Vector3D fslcoord = i * fslX + j * fslY + k * fslZ + fslOff; Vector3D coord, fslwarpval; newFile->indexToSpace(i, j, k, coord); fslwarpval[0] = newFile->getValue(i, j, k, 0); fslwarpval[1] = newFile->getValue(i, j, k, 1); fslwarpval[2] = newFile->getValue(i, j, k, 2); Vector3D fslTransAbsolute; if (absolute) { fslTransAbsolute = fslwarpval; } else { fslTransAbsolute = fslcoord + fslwarpval; } Vector3D transAbsolute = fslTransAbsolute[0] * sourceTransX + fslTransAbsolute[1] * sourceTransY + fslTransAbsolute[2] * sourceTransZ + sourceTransOff; Vector3D transdisplace = transAbsolute - coord;//internal format is always relative scratchFrames[0][newFile->getIndex(i, j, k)] = transdisplace[0]; scratchFrames[1][newFile->getIndex(i, j, k)] = transdisplace[1]; scratchFrames[2][newFile->getIndex(i, j, k)] = transdisplace[2]; } } } newFile->setFrame(scratchFrames[0].data(), 0); newFile->setFrame(scratchFrames[1].data(), 1); newFile->setFrame(scratchFrames[2].data(), 2); m_warpfield = newFile;//drop the previous warpfield, and replace with the new one } void WarpfieldFile::writeWorld(const AString& warpname) const { if (m_warpfield == NULL) throw DataFileException("writeWorld called on uninitialized warpfield"); m_warpfield->writeFile(warpname); } void WarpfieldFile::writeITK(const AString& warpname) const { if (m_warpfield == NULL) throw DataFileException("writeWorld called on uninitialized warpfield"); vector dims; m_warpfield->getDimensions(dims); dims.resize(4);//drop number of components VolumeFile outFile; outFile.reinitialize(dims, m_warpfield->getSform()); outFile.setMapName(0, "x displacement"); outFile.setMapName(1, "y displacement"); outFile.setMapName(2, "z displacement"); for (int64_t k = 0; k < dims[2]; ++k) { for (int64_t j = 0; j < dims[1]; ++j) { for (int64_t i = 0; i < dims[0]; ++i) { outFile.setValue(-m_warpfield->getValue(i, j, k, 0), i, j, k, 0);//negate x and y to convert RAS displacements to LPS outFile.setValue(-m_warpfield->getValue(i, j, k, 1), i, j, k, 1); outFile.setValue(m_warpfield->getValue(i, j, k, 2), i, j, k, 2); } } } outFile.writeFile(warpname); } void WarpfieldFile::writeFnirt(const AString& warpname, const AString& sourceName) const { if (m_warpfield == NULL) throw DataFileException("writeFnirt called on uninitialized warpfield"); FloatMatrix sourceSform, sourceFSL, refSform, refFSL; NiftiHeader myHeader; myHeader.setSForm(m_warpfield->getSform()); myHeader.setDimensions(m_warpfield->getOriginalDimensions()); refSform = FloatMatrix(myHeader.getSForm()); refFSL = FloatMatrix(myHeader.getFSLSpace()); NiftiIO sourceIO; sourceIO.openRead(sourceName); sourceSform = FloatMatrix(sourceIO.getHeader().getSForm()); sourceFSL = FloatMatrix(sourceIO.getHeader().getFSLSpace()); VolumeFile outFile; vector dims; m_warpfield->getDimensions(dims); dims.resize(4);//drop number of components outFile.reinitialize(dims, m_warpfield->getSform()); outFile.setMapName(0, "x displacement"); outFile.setMapName(1, "y displacement"); outFile.setMapName(2, "z displacement"); FloatMatrix FSLTransform = sourceFSL * sourceSform.inverse();//goes from real space to FSL source space Vector3D FSLTransX, FSLTransY, FSLTransZ, FSLTransOff; FSLTransform.getAffineVectors(FSLTransX, FSLTransY, FSLTransZ, FSLTransOff); Vector3D fslX, fslY, fslZ, fslOff; refFSL.getAffineVectors(fslX, fslY, fslZ, fslOff); int64_t numVox = dims[0] * dims[1] * dims[2]; vector> scratchFrames(3, vector(numVox, 0.0f)); #pragma omp CARET_PARFOR schedule(dynamic) for (int64_t k = 0; k < dims[2]; ++k) { for (int64_t j = 0; j < dims[1]; ++j) { for (int64_t i = 0; i < dims[0]; ++i) { Vector3D fslcoord = i * fslX + j * fslY + k * fslZ + fslOff; Vector3D coord, realdisplacement; m_warpfield->indexToSpace(i, j, k, coord); realdisplacement[0] = m_warpfield->getValue(i, j, k, 0); realdisplacement[1] = m_warpfield->getValue(i, j, k, 1); realdisplacement[2] = m_warpfield->getValue(i, j, k, 2); Vector3D realabsolute = coord + realdisplacement; Vector3D fslabsolute = realabsolute[0] * FSLTransX + realabsolute[1] * FSLTransY + realabsolute[2] * FSLTransZ + FSLTransOff; Vector3D fsldisplace = fslabsolute - fslcoord; scratchFrames[0][outFile.getIndex(i, j, k)] = fsldisplace[0]; scratchFrames[1][outFile.getIndex(i, j, k)] = fsldisplace[1]; scratchFrames[2][outFile.getIndex(i, j, k)] = fsldisplace[2]; } } } outFile.setFrame(scratchFrames[0].data(), 0); outFile.setFrame(scratchFrames[1].data(), 1); outFile.setFrame(scratchFrames[2].data(), 2); outFile.writeFile(warpname); } connectome-workbench-1.4.2/src/Files/WarpfieldFile.h000066400000000000000000000032211360521144700223500ustar00rootroot00000000000000#ifndef __WARPFIELD_FILE_H__ #define __WARPFIELD_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AString.h" #include "CaretPointer.h" #include "VolumeFile.h" namespace caret { class WarpfieldFile { CaretPointer m_warpfield; public: const VolumeFile* getWarpfield() const { return m_warpfield.getPointer(); } CaretPointer generateAbsolute() const; void readWorld(const AString& warpname); void readITK(const AString& warpname); void readFnirt(const AString& warpName, const AString& sourceName, const bool& absolute = false); void writeWorld(const AString& warpname) const;//for completeness void writeITK(const AString& warpname) const; void writeFnirt(const AString& warpname, const AString& sourceName) const; }; } #endif //__WARPFIELD_FILE_H__ connectome-workbench-1.4.2/src/Files/XmlStreamReaderHelper.cxx000066400000000000000000000413451360521144700244160ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __XML_STREAM_READER_HELPER_DECLARE__ #include "XmlStreamReaderHelper.h" #undef __XML_STREAM_READER_HELPER_DECLARE__ #include #include #include "CaretAssert.h" #include "DataFileException.h" #include "GiftiMetaData.h" using namespace caret; /** * \class caret::XmlStreamReaderHelper * \brief Helper class for using QXmlStreamReader * \ingroup Files * * Assists with reading a file using QXmlStreamReader. * If there is an error while using any of these methods, * a DataFileException will be thrown containing the * name of the file, a message, and also the line and * column of the error. */ /** * Constructor. * * @param filename * Name of file that is being read using the QXmlStreamReader * @param stream * The QXmlStreamReader */ XmlStreamReaderHelper::XmlStreamReaderHelper(const QString& filename, QXmlStreamReader* stream) : CaretObject(), m_filename(filename), m_stream(stream) { CaretAssert(stream); } /** * Destructor. */ XmlStreamReaderHelper::~XmlStreamReaderHelper() { } /** * Get the string value for the given attribute name from the * given attributes. If the attribute is missing or if the * attributes value is empty text, the defaultValue is * returned. This method WILL NOT throw an exception. * * @param attributes * The XML attributes. * @param elementName * Name of element containing the attributes. * @param attributeName * Name of the attribute. * @param defaultValue * Value that is returned if the attribute is missing or if the value * is empty text. * @return * String value for the attribute. */ QString XmlStreamReaderHelper::getOptionalAttributeStringValue(const QXmlStreamAttributes& attributes, const QString& /*elementName*/, const QString& attributeName, const QString& defaultValue) { QString valueString; if (attributes.hasAttribute(attributeName)) { valueString = attributes.value(attributeName).toString(); if (valueString.isEmpty()) { valueString = defaultValue; } } else { valueString = defaultValue; } return valueString; } /** * Get the string value for the given attribute name from the * given attributes. If the attribute name is not found or * its value is an empty string, a DataFileException is thrown. * * @param attributes * The XML attributes. * @param elementName * Name of element containing the attributes. * @param attributeName * Name of the attribute. * @param alternateAttributeNameOne * Use if attributeName is not found. * @param alternateAttributeNameTwo * Use if neither attributeName nor alternateAttributeNameOne is not found. * @return * String value for the attribute. * @throw * DataFileException if attribute is missing or value is * an empty string. */ QString XmlStreamReaderHelper::getRequiredAttributeStringValue(const QXmlStreamAttributes& attributes, const QString& elementName, const QString& attributeName, const QString& alternateAttributeNameOne, const QString& alternateAttributeNameTwo) { QString valueString; QString foundAttributeName; if (attributes.hasAttribute(attributeName)) { foundAttributeName = attributeName; } else if (( ! alternateAttributeNameOne.isEmpty()) && attributes.hasAttribute(alternateAttributeNameOne)) { foundAttributeName = alternateAttributeNameOne; } else if (( ! alternateAttributeNameTwo.isEmpty()) && attributes.hasAttribute(alternateAttributeNameTwo)) { foundAttributeName = alternateAttributeNameTwo; } if ( ! foundAttributeName.isEmpty()) { valueString = attributes.value(foundAttributeName).toString(); if (valueString.isEmpty()) { throwDataFileException("Value for attribute " + foundAttributeName + " in element " + elementName + " is empty"); } } else { throwDataFileException(attributeName + " is missing from element " + elementName); } return valueString; } /** * Get the bool value for the given attribute name from the * given attributes. If the attribute is missing or if the * attributes value is empty text, the defaultValue is * returned. This method WILL NOT throw an exception. * * @param attributes * The XML attributes. * @param elementName * Name of element containing the attributes. * @param attributeName * Name of the attribute. * @param defaultValue * Value that is returned if the attribute is missing. * @return * Boolean value for the attribute. * @throw * DataFileException if attribute is missing or value is * an empty string. */ bool XmlStreamReaderHelper::getOptionalAttributeBoolValue(const QXmlStreamAttributes& attributes, const QString& elementName, const QString& attributeName, const bool defaultValue) { const AString stringValue = getOptionalAttributeStringValue(attributes, elementName, attributeName, AString::fromBool(defaultValue)); const bool value = stringValue.toBool(); return value; } /** * Get the bool value for the given attribute name from the * given attributes. If the attribute name is not found or * its value is an empty string, a DataFileException is thrown. * * @param attributes * The XML attributes. * @param elementName * Name of element containing the attributes. * @param attributeName * Name of the attribute. * @return * Boolean value for the attribute. * @throw * DataFileException if attribute is missing or value is * an empty string. */ bool XmlStreamReaderHelper::getRequiredAttributeBoolValue(const QXmlStreamAttributes& attributes, const QString& elementName, const QString& attributeName) { const AString stringValue = getRequiredAttributeStringValue(attributes, elementName, attributeName); const bool value = stringValue.toBool(); return value; } /** * Get the int value for the given attribute name from the * given attributes. If the attribute is missing or if the * attributes value is empty text, the defaultValue is * returned. This method WILL NOT throw an exception. * * @param attributes * The XML attributes. * @param elementName * Name of element containing the attributes. * @param attributeName * Name of the attribute. * @param defaultValue * Value that is returned if the attribute is missing. * @return * int value for the attribute. * @throw * DataFileException if attribute is missing or value is * an empty string. */ int XmlStreamReaderHelper::getOptionalAttributeIntValue(const QXmlStreamAttributes& attributes, const QString& elementName, const QString& attributeName, const int defaultValue) { const AString stringValue = getOptionalAttributeStringValue(attributes, elementName, attributeName, AString::number(defaultValue)); const int value = stringValue.toInt(); return value; } /** * Get the int value for the given attribute name from the * given attributes. If the attribute name is not found or * its value is an empty string, a DataFileException is thrown. * * @param attributes * The XML attributes. * @param elementName * Name of element containing the attributes. * @param attributeName * Name of the attribute. * @return * Integer value for the attribute. * @throw * DataFileException if attribute is missing or value is * an empty string. */ int XmlStreamReaderHelper::getRequiredAttributeIntValue(const QXmlStreamAttributes& attributes, const QString& elementName, const QString& attributeName) { const QString stringValue = getRequiredAttributeStringValue(attributes, elementName, attributeName); bool valid; const int value = stringValue.toInt(&valid); if ( ! valid) { throwDataFileException("Value for attribute " + attributeName + " is not a valid integer value " + stringValue); } return value; } /** * Get the float value for the given attribute name from the * given attributes. If the attribute is missing or if the * attributes value is empty text, the defaultValue is * returned. This method WILL NOT throw an exception. * * @param attributes * The XML attributes. * @param elementName * Name of element containing the attributes. * @param attributeName * Name of the attribute. * @param defaultValue * Value that is returned if the attribute is missing. * @return * float value for the attribute. * @throw * DataFileException if attribute is missing or value is * an empty string. */ float XmlStreamReaderHelper::getOptionalAttributeFloatValue(const QXmlStreamAttributes& attributes, const QString& elementName, const QString& attributeName, const float defaultValue) { const AString stringValue = getOptionalAttributeStringValue(attributes, elementName, attributeName, AString::number(defaultValue)); const float value = stringValue.toFloat(); return value; } /** * Get the int value for the given attribute name from the * given attributes. If the attribute name is not found or * its value is an empty string, a DataFileException is thrown. * * @param attributes * The XML attributes. * @param elementName * Name of element containing the attributes. * @param attributeName * Name of the attribute. * @return * Integer value for the attribute. * @throw * DataFileException if attribute is missing or value is * an empty string. */ float XmlStreamReaderHelper::getRequiredAttributeFloatValue(const QXmlStreamAttributes& attributes, const QString& elementName, const QString& attributeName) { const QString stringValue = getRequiredAttributeStringValue(attributes, elementName, attributeName); bool valid; const float value = stringValue.toFloat(&valid); if ( ! valid) { throwDataFileException("Value for attribute " + attributeName + " is not a valid integer value " + stringValue); } return value; } /** * Read the GIFTI metadata (Copied from CiftiXMLReader::parseMetaData). * * @param metadata * GIFTI metadata to which metadata is added. */ void XmlStreamReaderHelper::readMetaData(GiftiMetaData* metadata) { CaretAssert(metadata); metadata->clear(); while (!(m_stream->isEndElement() && (m_stream->name().toString() == "MetaData")) && !m_stream->hasError()) { m_stream->readNext(); if(m_stream->isStartElement()) { QString elementName = m_stream->name().toString(); if(elementName == "MD") { readMetaDataElement(metadata); } else throwDataFileException("unknown element in MetaData: " + elementName); } } //check for end element if(!m_stream->isEndElement() || (m_stream->name().toString() != "MetaData")) throwDataFileException("MetaData end tag not found."); } /** * Read the GIFTI metadata (Copied from CiftiXMLReader::parseMetaDataElement). * * @param metadata * GIFTI metadata to which metadata is added. */ void XmlStreamReaderHelper::readMetaDataElement(GiftiMetaData* metadata) { QString name; QString value; bool haveName = false; bool haveValue = false; while (!(m_stream->isEndElement() && (m_stream->name().toString() == "MD")) && !m_stream->hasError()) { //test = m_stream->name().toString(); m_stream->readNext(); if(m_stream->isStartElement()) { QString elementName = m_stream->name().toString(); if(elementName == "Name") { m_stream->readNext(); if(m_stream->tokenType() != QXmlStreamReader::Characters) { return; } name = m_stream->text().toString(); haveName = true; m_stream->readNext(); if(!m_stream->isEndElement()) { throwDataFileException("End element for meta data name tag not found."); } } else if(elementName == "Value") { m_stream->readNext(); if(m_stream->tokenType() != QXmlStreamReader::Characters) { return; } value = m_stream->text().toString(); haveValue = true; m_stream->readNext(); if(!m_stream->isEndElement()) { throwDataFileException("End element for meta data value tag not found."); } } else { throwDataFileException("unknown element in MD: " + elementName); } } } if (!haveName || !haveValue) { throwDataFileException("MD element is missing name or value"); } metadata->set(name, value); if(!m_stream->isEndElement() || (m_stream->name().toString() != "MD")) { throwDataFileException("End element for MD tag not found"); } } /** * Throw a data file exception with the given message and add * the line and column numbers to the message. * * @param message * Message included in the exception. * @throw * Always throws a DataFileException. */ void XmlStreamReaderHelper::throwDataFileException(const QString message) { throw DataFileException(m_filename, (message + " at line " + QString::number(m_stream->lineNumber()) + ", column " + QString::number(m_stream->columnNumber()))); } connectome-workbench-1.4.2/src/Files/XmlStreamReaderHelper.h000066400000000000000000000104601360521144700240350ustar00rootroot00000000000000#ifndef __XML_STREAM_READER_HELPER_H__ #define __XML_STREAM_READER_HELPER_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" class QXmlStreamAttributes; class QXmlStreamReader; namespace caret { class GiftiMetaData; class XmlStreamReaderHelper : public CaretObject { public: XmlStreamReaderHelper(const QString& filename, QXmlStreamReader* stream); virtual ~XmlStreamReaderHelper(); QString getOptionalAttributeStringValue(const QXmlStreamAttributes& attributes, const QString& elementName, const QString& attributeName, const QString& defaultValue); QString getRequiredAttributeStringValue(const QXmlStreamAttributes& attributes, const QString& elementName, const QString& attributeName, const QString& alternateAttributeNameOne = "", const QString& alternateAttributeNameTwo = ""); int getOptionalAttributeIntValue(const QXmlStreamAttributes& attributes, const QString& elementName, const QString& attributeName, const int defaultValue); int getRequiredAttributeIntValue(const QXmlStreamAttributes& attributes, const QString& elementName, const QString& attributeName); float getOptionalAttributeFloatValue(const QXmlStreamAttributes& attributes, const QString& elementName, const QString& attributeName, const float defaultValue); float getRequiredAttributeFloatValue(const QXmlStreamAttributes& attributes, const QString& elementName, const QString& attributeName); bool getOptionalAttributeBoolValue(const QXmlStreamAttributes& attributes, const QString& elementName, const QString& attributeName, const bool defaultValue); bool getRequiredAttributeBoolValue(const QXmlStreamAttributes& attributes, const QString& elementName, const QString& attributeName); void readMetaData(GiftiMetaData* metadata); void throwDataFileException(const QString message); private: XmlStreamReaderHelper(const XmlStreamReaderHelper&); XmlStreamReaderHelper& operator=(const XmlStreamReaderHelper&); void readMetaDataElement(GiftiMetaData* metadata); const QString m_filename; QXmlStreamReader* m_stream; // ADD_NEW_MEMBERS_HERE }; #ifdef __XML_STREAM_READER_HELPER_DECLARE__ // #endif // __XML_STREAM_READER_HELPER_DECLARE__ } // namespace #endif //__XML_STREAM_READER_HELPER_H__ connectome-workbench-1.4.2/src/Files/XmlStreamWriterHelper.cxx000066400000000000000000000047301360521144700244650ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __XML_STREAM_WRITER_HELPER_DECLARE__ #include "XmlStreamWriterHelper.h" #undef __XML_STREAM_WRITER_HELPER_DECLARE__ #include #include "CaretAssert.h" #include "GiftiMetaData.h" #include "GiftiXmlElements.h" using namespace caret; /** * \class caret::XmlStreamWriterHelper * \brief Helper class for using QXmlStreamWriter * \ingroup Files */ /** * Constructor. * * @param filename * Name of file that is being read using the QXmlStreamWriter * @param stream * The QXmlStreamWriter */ XmlStreamWriterHelper::XmlStreamWriterHelper(const QString& filename, QXmlStreamWriter* stream) : CaretObject(), m_filename(filename), m_stream(stream) { CaretAssert(stream); } /** * Destructor. */ XmlStreamWriterHelper::~XmlStreamWriterHelper() { } /** * Write the given metadata using the XML stream writer. * * @param metadata * Metadata that will be written to the XML stream. */ void XmlStreamWriterHelper::writeMetaData(const GiftiMetaData* metadata) { CaretAssert(metadata); m_stream->writeStartElement(GiftiXmlElements::TAG_METADATA); const std::map mdMap = metadata->getAsMap(); for (std::map::const_iterator iter = mdMap.begin(); iter != mdMap.end(); iter++) { m_stream->writeStartElement(GiftiXmlElements::TAG_METADATA_ENTRY); m_stream->writeTextElement(GiftiXmlElements::TAG_METADATA_NAME, iter->first); m_stream->writeTextElement(GiftiXmlElements::TAG_METADATA_VALUE, iter->second); m_stream->writeEndElement(); } m_stream->writeEndElement(); } connectome-workbench-1.4.2/src/Files/XmlStreamWriterHelper.h000066400000000000000000000035331360521144700241120ustar00rootroot00000000000000#ifndef __XML_STREAM_WRITER_HELPER_H__ #define __XML_STREAM_WRITER_HELPER_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" class QXmlStreamAttributes; class QXmlStreamWriter; namespace caret { class GiftiMetaData; class XmlStreamWriterHelper : public CaretObject { public: XmlStreamWriterHelper(const QString& filename, QXmlStreamWriter* stream); virtual ~XmlStreamWriterHelper(); void writeMetaData(const GiftiMetaData* metadata); // ADD_NEW_METHODS_HERE private: XmlStreamWriterHelper(const XmlStreamWriterHelper&); XmlStreamWriterHelper& operator=(const XmlStreamWriterHelper&); const QString m_filename; QXmlStreamWriter* m_stream; // ADD_NEW_MEMBERS_HERE }; #ifdef __XML_STREAM_WRITER_HELPER_DECLARE__ // #endif // __XML_STREAM_WRITER_HELPER_DECLARE__ } // namespace #endif //__XML_STREAM_WRITER_HELPER_H__ connectome-workbench-1.4.2/src/FilesBase/000077500000000000000000000000001360521144700202575ustar00rootroot00000000000000connectome-workbench-1.4.2/src/FilesBase/CMakeLists.txt000066400000000000000000000016741360521144700230270ustar00rootroot00000000000000# # The FilesBase Project # project (FilesBase) # # Need XML from Qt # SET(QT_DONT_USE_QTGUI) # # Add QT for includes # if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () # # Create the NIFTI library # ADD_LIBRARY(FilesBase GiftiException.h GiftiLabel.h GiftiLabelTable.h GiftiMetaData.h GiftiMetaDataXmlElements.h GiftiXmlElements.h nifti1.h nifti2.h NiftiEnums.h VolumeBase.h VolumeMappableInterface.h VolumeSliceViewPlaneEnum.h VolumeSpace.h GiftiException.cxx GiftiLabel.cxx GiftiLabelTable.cxx GiftiMetaData.cxx GiftiXmlElements.cxx NiftiEnums.cxx VolumeBase.cxx VolumeMappableInterface.cxx VolumeSliceViewPlaneEnum.cxx VolumeSpace.cxx ) TARGET_LINK_LIBRARIES(FilesBase ${CARET_QT5_LINK}) # # Find Headers # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Annotations ${CMAKE_SOURCE_DIR}/FilesBase ${CMAKE_SOURCE_DIR}/Common ${CMAKE_SOURCE_DIR}/Palette ${CMAKE_SOURCE_DIR}/Xml ) connectome-workbench-1.4.2/src/FilesBase/GiftiException.cxx000066400000000000000000000041501360521144700237240ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "GiftiException.h" #include using namespace caret; /** * Constructor. * */ GiftiException::GiftiException() : CaretException() { this->initializeMembersGiftiException(); } /** * Constructor that uses stack trace from the exception * passed in as a parameter. * * @param e Any exception whose stack trace becomes * this exception's stack trace. * */ GiftiException::GiftiException( const CaretException& e) : CaretException(e) { this->initializeMembersGiftiException(); } /** * Constructor. * * @param s Description of the exception. * */ GiftiException::GiftiException( const AString& s) : CaretException(s) { this->initializeMembersGiftiException(); } /** * Copy Constructor. * @param e * Exception that is copied. */ GiftiException::GiftiException(const GiftiException& e) : CaretException(e) { } /** * Assignment operator. * @param e * Exception that is copied. * @return * Copy of the exception. */ GiftiException& GiftiException::operator=(const GiftiException& e) { if (this != &e) { CaretException::operator=(e); } return *this; } /** * Destructor */ GiftiException::~GiftiException() throw() { } void GiftiException::initializeMembersGiftiException() { } connectome-workbench-1.4.2/src/FilesBase/GiftiException.h000066400000000000000000000027111360521144700233520ustar00rootroot00000000000000#ifndef __GIFTIEXCEPTION_H__ #define __GIFTIEXCEPTION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretException.h" namespace caret { /** * An exception thrown during GIFTI file processing. */ class GiftiException : public CaretException { public: GiftiException(); GiftiException(const CaretException& e); GiftiException(const AString& s); GiftiException(const GiftiException& e); GiftiException& operator=(const GiftiException& e); virtual ~GiftiException() throw(); private: void initializeMembersGiftiException(); }; } // namespace #endif // __GIFTIEXCEPTION_H__ connectome-workbench-1.4.2/src/FilesBase/GiftiLabel.cxx000066400000000000000000000407341360521144700230150ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __GIFTI_LABEL_DECLARE__ #include "GiftiLabel.h" #undef __GIFTI_LABEL_DECLARE__ #include "CaretLogger.h" using namespace caret; /** * Constructor. * * @param key - key of the label. * @param name - name of label. * */ GiftiLabel::GiftiLabel( const int32_t key, const AString& name) : CaretObject() { this->initializeMembersGiftiLabel(); this->key = key; setNamePrivate(name); } /** * Constructor. * * @param key - Key of the label. * @param name - name of label. * @param red - red color component, zero to one. * @param green - green color component, zero to one. * @param blue - blue color component, zero to one. * @param alpha - alpha color component, zero to one. * */ GiftiLabel::GiftiLabel( const int32_t key, const AString& name, const float red, const float green, const float blue, const float alpha) : CaretObject() { this->initializeMembersGiftiLabel(); this->key = key; setNamePrivate(name); this->red = colorClamp(red); this->green = colorClamp(green); this->blue = colorClamp(blue); this->alpha = colorClamp(alpha); } /** * Constructor. * * @param key - Key of the label. * @param name - name of label. * @param red - red color component, zero to one. * @param green - green color component, zero to one. * @param blue - blue color component, zero to one. * @param alpha - alpha color component, zero to one. * */ GiftiLabel::GiftiLabel(const int32_t key, const AString& name, const float red, const float green, const float blue, const float alpha, const float x, const float y, const float z) : CaretObject() { this->initializeMembersGiftiLabel(); this->key = key; setNamePrivate(name); this->red = colorClamp(red); this->green = colorClamp(green); this->blue = colorClamp(blue); this->alpha = colorClamp(alpha); this->x = x; this->y = y; this->z = z; } /** * Constructor. * * @param key - Key of the label. * @param name - name of label. * @param red - red color component, zero to one. * @param green - green color component, zero to one. * @param blue - blue color component, zero to one. * @param alpha - alpha color component, zero to one. * */ GiftiLabel::GiftiLabel( const int32_t key, const AString& name, const double red, const double green, const double blue, const double alpha) : CaretObject() { this->initializeMembersGiftiLabel(); this->key = key; setNamePrivate(name); this->red = colorClamp(red); this->green = colorClamp(green); this->blue = colorClamp(blue); this->alpha = colorClamp(alpha); } /** * Constructor. * * @param key - Key of the label. * @param name - name of label. * @param rgba - red, green, blue, alpha color componenents, zero to one. * */ GiftiLabel::GiftiLabel( const int32_t key, const AString& name, const float rgba[]) : CaretObject() { this->initializeMembersGiftiLabel(); this->key = key; setNamePrivate(name); this->red = colorClamp(rgba[0]); this->green = colorClamp(rgba[1]); this->blue = colorClamp(rgba[2]); this->alpha = colorClamp(rgba[3]); } /** * Constructor. * * @param key - Key of the label. * @param name - name of label. * @param red - red color component, zero to two-fifty-five. * @param green - green color component, zero to two-fifty-five. * @param blue - blue color component, zero to two-fifty-five. * @param alpha - alpha color component, zero to two-fifty-five. * */ GiftiLabel::GiftiLabel( const int32_t key, const AString& name, const int32_t red, const int32_t green, const int32_t blue, const int32_t alpha) : CaretObject() { this->initializeMembersGiftiLabel(); this->key = key; setNamePrivate(name); this->red = colorClamp(red / 255.0); this->green = colorClamp(green / 255.0); this->blue = colorClamp(blue / 255.0); this->alpha = colorClamp(alpha / 255.0); } /** * Constructor. * * @param key - Key of the label. * @param name - name of label. * @param rgba - red, green, blue, alpha color componenents, zero to 255. * */ GiftiLabel::GiftiLabel( const int32_t key, const AString& name, const int32_t rgba[]) : CaretObject() { this->initializeMembersGiftiLabel(); this->key = key; setNamePrivate(name); this->red = colorClamp(rgba[0] / 255.0); this->green = colorClamp(rgba[1] / 255.0); this->blue = colorClamp(rgba[2] / 255.0); this->alpha = colorClamp(rgba[3] / 255.0); } /** * Constructor. * * @param key - Key of the label. * */ GiftiLabel::GiftiLabel( const int32_t key) : CaretObject() { this->initializeMembersGiftiLabel(); this->key = key; if (this->key == 0) { setNamePrivate("???"); } else { std::stringstream str; str << "???" << this->key; setNamePrivate(AString::fromStdString(str.str())); } } /** * Destructor */ GiftiLabel::~GiftiLabel() { } float GiftiLabel::colorClamp(const float& in) { if (in < 0.0f) return 0.0f; if (in > 1.0f) return 1.0f; if (in != in) { CaretLogWarning("GiftiLabel was given NaN as a color, changing to 1.0"); return 1.0f; } return in; } /** * Copy Constructor * @param Object that is copied. */ GiftiLabel::GiftiLabel(const GiftiLabel& o) : CaretObject(o), TracksModificationInterface() { this->initializeMembersGiftiLabel(); this->copyHelper(o); } /** * Assignment operator. */ GiftiLabel& GiftiLabel::operator=(const GiftiLabel& o) { if (this != &o) { CaretObject::operator=(o); this->copyHelper(o); }; return *this; } /** * Helps with copy constructor and assignment operator. */ void GiftiLabel::copyHelper(const GiftiLabel& gl) { this->initializeMembersGiftiLabel(); setNamePrivate(gl.name); this->key = gl.key; this->selected = gl.selected; this->red = gl.red; this->green = gl.green; this->blue = gl.blue; this->alpha = gl.alpha; this->x = gl.x; this->y = gl.y; this->z = gl.z; this->count = 0; m_groupNameSelectionItem = gl.m_groupNameSelectionItem; } /** * Initialize data members. */ void GiftiLabel::initializeMembersGiftiLabel() { this->modifiedFlag = false; this->medialWallNameFlag = false; this->name = ""; this->key = s_invalidLabelKey; this->selected = true; this->red = 1.0; this->green = 1.0; this->blue = 1.0; this->alpha = 1.0; this->x = 0.0; this->y = 0.0; this->z = 0.0; this->count = 0; m_groupNameSelectionItem = NULL; } /** * Determine if two objects are equal. Two GiftiLabels are equal if they * have the same "key". * @param obj Object for comparison. * @return true if equal, else false. * */ bool GiftiLabel::equals(const GiftiLabel& gl) { return (this->key == gl.key); } /** * Compare this label to another label using the indices of the labels. * @param gl - Compare to this GiftiLabel. * @return negative if "this" is less, positive if "this" is greater, * else zero. * */ int32_t GiftiLabel::operator<(const GiftiLabel& gl) { return (this->key < gl.key); } /** * Get the key of this label. * @return key of the label. * */ int32_t GiftiLabel::getKey() const { return this->key; } /** * Set the key of this label. DO NOT call this method on a label * retrieved from the label table. * * @param key - New key for this label. * */ void GiftiLabel::setKey(const int32_t key) { this->key = key; this->setModified(); } /** * Get the name. * @return Name of label. * */ AString GiftiLabel::getName() const { return this->name; } /** * Set the name. * @param name - new name for label. * */ void GiftiLabel::setName(const AString& name) { setNamePrivate(name); this->setModified(); } /** * (1) Sets the name of the label. * (2) Examines the name of the label to see if the label * is a "medial wall" name which is defined as a name that * contains substring "medial", followed by zero or more * characters, followed by the substring "wall". * (3) DOES NOT change the modfified * status for this label. * * @param name * New name for label. */ void GiftiLabel::setNamePrivate(const AString& name) { this->name = name; this->medialWallNameFlag = false; const int32_t medialIndex = name.indexOf("medial", 0, Qt::CaseInsensitive); if (medialIndex >= 0) { const int32_t wallIndex = name.indexOf("wall", 6, Qt::CaseInsensitive); if (wallIndex > medialIndex) { this->medialWallNameFlag = true; } } } /** * @return A string that contains both the key and name * for use in the label editor. */ AString GiftiLabel::getNameAndKeyForLabelEditor() const { const AString keyAndNameText(QString::number(this->key).rightJustified(4, ' ', false) + ": " + (this->name)); return keyAndNameText; } /** * Is this label selected (for display)? * * @return true if label selected for display, else false. * */ bool GiftiLabel::isSelected() const { return this->selected; } /** * Set the label selected (for display). * * @param selected - new selection status. * */ void GiftiLabel::setSelected(const bool selected) { this->selected = selected; } /** * Get the color components. * @param rgbaOut four dimensional array into which are loaded, * red, green, blue, and alpha components ranging 0.0. to 1.0. * */ void GiftiLabel::getColor(float rgbaOut[4]) const { rgbaOut[0] = this->red; rgbaOut[1] = this->green; rgbaOut[2] = this->blue; rgbaOut[3] = this->alpha; } /** * Set the color components. * * @param rgba - A four-dimensional array of floats containing the red, * green, blue, and alpha components with values ranging from 0.0 to 1.0. * */ void GiftiLabel::setColor(const float rgba[4]) { this->red = colorClamp(rgba[0]); this->green = colorClamp(rgba[1]); this->blue = colorClamp(rgba[2]); this->alpha = colorClamp(rgba[3]); this->setModified(); } /** * Get the default color. * * @param Output with a four-dimensional array of floats * containing the red, green, blue, and alpha components with values * ranging from 0.0 to 1.0. */ void GiftiLabel::getDefaultColor(float rgbaOut[4]) { rgbaOut[0] = 1.0; rgbaOut[1] = 1.0; rgbaOut[2] = 1.0; rgbaOut[3] = 1.0; } /** * Get the red color component for this label. * @return red color component. * */ float GiftiLabel::getRed() const { return this->red; } /** * Get the green color component for this label. * @return green color component. * */ float GiftiLabel::getGreen() const { return this->green; } /** * Get the blue color component for this label. * @return blue color component. * */ float GiftiLabel::getBlue() const { return this->blue; } /** * Get the alpha color component for this label. * @return alpha color component. * */ float GiftiLabel::getAlpha() const { return this->alpha; } /** * Get the X-Coordinate. * @return * The X-coordinate. */ float GiftiLabel::getX() const { return this->x; } /** * Get the Y-Coordinate. * @return * The Y-coordinate. */ float GiftiLabel::getY() const { return this->y; } /** * Get the Z-Coordinate. * @return * The Z-coordinate. */ float GiftiLabel::getZ() const { return this->z; } /** * Get the XYZ coordiantes. * @param xyz * Array into which coordinates are loaded. */ void GiftiLabel::getXYZ(float xyz[3]) const { xyz[0] = this->x; xyz[1] = this->y; xyz[2] = this->z; } /** * Set the X-coordinate. * @param x * New value for X-coordinate. */ void GiftiLabel::setX(const float x) { this->x = x; this->setModified(); } /** * Set the Y-coordinate. * @param y * New value for Y-coordinate. */ void GiftiLabel::setY(const float y) { this->y = y; this->setModified(); } /** * Set the Z-coordinate. * @param z * New value for Z-coordinate. */ void GiftiLabel::setZ(const float z) { this->z = z; this->setModified(); } /** * Set the XYZ coordinates. * @param xyz * Array containing XYZ coordiantes. */ void GiftiLabel::setXYZ(const float xyz[3]) { this->x = xyz[0]; this->y = xyz[1]; this->z = xyz[2]; this->setModified(); } /** * Set this object has been modified. * */ void GiftiLabel::setModified() { this->modifiedFlag = true; } /** * Set this object as not modified. Object should also * clear the modification status of its children. * */ void GiftiLabel::clearModified() { this->modifiedFlag = false; } /** * Get the modification status. Returns true if this object or * any of its children have been modified. * @return - The modification status. * */ bool GiftiLabel::isModified() const { return this->modifiedFlag; } /** * Get information about this label. * * @return Information about the label. * */ AString GiftiLabel::toString() const { AString s; s += "[GiftiLabel=(key=" + AString::number(this->getKey()) + "," + this->getName() + "," + AString::number(this->getRed()) + "," + AString::number(this->getGreen()) + "," + AString::number(this->getBlue()) + "," + AString::number(this->getAlpha()) + "," + AString::number(this->getX()) + "," + AString::number(this->getY()) + "," + AString::number(this->getZ()) + ") "; return s; } /** * Get the count. * @return Count value. * */ int32_t GiftiLabel::getCount() const { return this->count; } /** * Set the count. * @param count - new value for count. * */ void GiftiLabel::setCount(const int32_t count) { this->count = count; } /** * Increment the count. * */ void GiftiLabel::incrementCount() { this->count++; } bool GiftiLabel::matches(const GiftiLabel& rhs, const bool checkColor, const bool checkCoord) const { if (key != rhs.key) return false; if (name != rhs.name) return false; if (checkColor) { if (red != rhs.red) return false; if (green != rhs.green) return false; if (blue != rhs.blue) return false; if (alpha != rhs.alpha) return false; } if (checkCoord) { if (x != rhs.x) return false; if (y != rhs.y) return false; if (z != rhs.z) return false; } return true; } /** * Set the selection item for the group/name hierarchy. * * @param item * The selection item from the group/name hierarchy. */ void GiftiLabel::setGroupNameSelectionItem(GroupAndNameHierarchyItem* item) { m_groupNameSelectionItem = item; } /** * @return The selection item for the Group/Name selection hierarchy. * May be NULL in some circumstances. */ const GroupAndNameHierarchyItem* GiftiLabel::getGroupNameSelectionItem() const { return m_groupNameSelectionItem; } /** * @return The selection item for the Group/Name selection hierarchy. * May be NULL in some circumstances. */ GroupAndNameHierarchyItem* GiftiLabel::getGroupNameSelectionItem() { return m_groupNameSelectionItem; } connectome-workbench-1.4.2/src/FilesBase/GiftiLabel.h000066400000000000000000000154661360521144700224460ustar00rootroot00000000000000#ifndef __GIFTILABEL_H__ #define __GIFTILABEL_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "TracksModificationInterface.h" #include #include #include namespace caret { class GroupAndNameHierarchyItem; /** * Represents a GIFTI Label. */ class GiftiLabel : public CaretObject, TracksModificationInterface { public: GiftiLabel( const int32_t key, const AString& name); explicit GiftiLabel( const int32_t key, const AString& name, const float red, const float green, const float blue, const float alpha); explicit GiftiLabel( const int32_t key, const AString& name, const float red, const float green, const float blue, const float alpha, const float x, const float y, const float z); explicit GiftiLabel( const int32_t key, const AString& name, const double red, const double green, const double blue, const double alpha); GiftiLabel( const int32_t key, const AString& name, const float rgba[]); explicit GiftiLabel( const int32_t key, const AString& name, const int32_t red, const int32_t green, const int32_t blue, const int32_t alpha); GiftiLabel( const int32_t key, const AString& name, const int32_t rgba[]); GiftiLabel(const int32_t key); GiftiLabel(const GiftiLabel& gl); public: GiftiLabel& operator=(const GiftiLabel& gl); virtual ~GiftiLabel(); private: static float colorClamp(const float& in); void copyHelper(const GiftiLabel& o); void initializeMembersGiftiLabel(); public: int32_t hashCode(); bool equals(const GiftiLabel&); int32_t operator<(const GiftiLabel& gl); int32_t getKey() const; void setKey(const int32_t key); AString getName() const; /** * @return True if the name of the label is detected * to be a "medial wall" name. */ inline bool isMedialWallName() const { return this->medialWallNameFlag; } void setName(const AString& name); AString getNameAndKeyForLabelEditor() const; bool isSelected() const; void setSelected(const bool selected); void getColor(float rgbaOut[4]) const; void setColor(const float rgba[4]); static void getDefaultColor(float rgbaOut[4]); float getRed() const; float getGreen() const; float getBlue() const; float getAlpha() const; float getX() const; float getY() const; float getZ() const; void getXYZ(float xyz[3]) const; void setX(const float x); void setY(const float y); void setZ(const float z); void setXYZ(const float xyz[3]); void setModified(); void clearModified(); bool isModified() const; AString toString() const; int32_t getCount() const; void setCount(const int32_t count); void incrementCount(); bool matches(const GiftiLabel& rhs, const bool checkColor = false, const bool checkCoord = false) const; void setGroupNameSelectionItem(GroupAndNameHierarchyItem* item); const GroupAndNameHierarchyItem* getGroupNameSelectionItem() const; GroupAndNameHierarchyItem* getGroupNameSelectionItem(); /** * @return The invalid label key. */ static inline int32_t getInvalidLabelKey() { return s_invalidLabelKey; } private: void setNamePrivate(const AString& name); /**tracks modification status (DO NOT CLONE) */ bool modifiedFlag; /** * Name of label * DO NOT set directly with assignment operation. * Use setName() or setNamePrivate() so that the * medial wall name flag is updated. */ AString name; int32_t key; bool selected; bool medialWallNameFlag; float red; float green; float blue; float alpha; float x; float y; float z; /**Used to count nodes/voxel using label (not saved in file) */ int32_t count; /** Selection status of this label in the map/label hierarchy */ mutable GroupAndNameHierarchyItem* m_groupNameSelectionItem; /** The invalid label key */ const static int32_t s_invalidLabelKey; }; #ifdef __GIFTI_LABEL_DECLARE__ const int32_t GiftiLabel::s_invalidLabelKey = std::numeric_limits::min(); //const int32_t GiftiLabel::s_invalidLabelKey = -2147483648; #endif // __GIFTI_LABEL_DECLARE__ } // namespace #endif // __GIFTILABEL_H__ connectome-workbench-1.4.2/src/FilesBase/GiftiLabelTable.cxx000066400000000000000000001446671360521144700237770ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "AStringNaturalComparison.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "GiftiXmlElements.h" #include "StringTableModel.h" #include "XmlWriter.h" using namespace caret; /** * Constructor. * */ GiftiLabelTable::GiftiLabelTable() : CaretObject() { this->initializeMembersGiftiLabelTable(); clear();//actually adds the 0: ??? label } /** * Destructor */ GiftiLabelTable::~GiftiLabelTable() { for (LABELS_MAP_CONST_ITERATOR iter = this->labelsMap.begin(); iter != labelsMap.end(); iter++) { delete iter->second; } this->labelsMap.clear(); } /** * Copy Constructor * @param Object that is copied. */ GiftiLabelTable::GiftiLabelTable(const GiftiLabelTable& glt) : CaretObject(glt), TracksModificationInterface() { this->initializeMembersGiftiLabelTable(); this->copyHelper(glt); } /** * Assignment operator. */ GiftiLabelTable& GiftiLabelTable::operator=(const GiftiLabelTable& glt) { if (this != &glt) { CaretObject::operator=(glt); this->copyHelper(glt); }; return *this; } /** * Helps with copy constructor and assignment operator. */ void GiftiLabelTable::copyHelper(const GiftiLabelTable& glt) { this->clear(); for (LABELS_MAP_CONST_ITERATOR iter = glt.labelsMap.begin(); iter != glt.labelsMap.end(); iter++) { GiftiLabel* myLabel = this->getLabel(iter->second->getKey()); if (myLabel != NULL) { *myLabel = *(iter->second); } else { addLabel(iter->second); } } } void GiftiLabelTable::initializeMembersGiftiLabelTable() { this->modifiedFlag = false; m_tableModelColumnCount = 0; m_tableModelColumnIndexKey = m_tableModelColumnCount++; m_tableModelColumnIndexName = m_tableModelColumnCount++; m_tableModelColumnIndexColorSwatch = m_tableModelColumnCount++; m_tableModelColumnIndexRed = m_tableModelColumnCount++; m_tableModelColumnIndexGreen = m_tableModelColumnCount++; m_tableModelColumnIndexBlue = m_tableModelColumnCount++; } /** * Clear the labelTable. * */ void GiftiLabelTable::clear() { for (LABELS_MAP_CONST_ITERATOR iter = this->labelsMap.begin(); iter != labelsMap.end(); iter++) { delete iter->second; } this->labelsMap.clear(); GiftiLabel gl(0, "???", 1.0, 1.0, 1.0, 0.0); this->addLabel(&gl); this->modifiedFlag = false; } /** * Append a label table to this label table. Since labels may be * duplicated, the map returned that converts the keys of * the appended LabelTable to keys for "this" label table. * * @param lt Label table that is to be appended. * * @return A map where the keys are the keys in the label table * that is passed as a parameter and the values are the keys * into "this" label table. * */ std::map GiftiLabelTable::append(const GiftiLabelTable& glt) { std::map keyConverterMap; for (LABELS_MAP_CONST_ITERATOR iter = glt.labelsMap.begin(); iter != glt.labelsMap.end(); iter++) { int32_t key = iter->first; int32_t newKey = this->addLabel(iter->second); keyConverterMap.insert(std::make_pair(key, newKey)); } return keyConverterMap; } /** * Add a label. If a label with the name exists, its colors * are replaced with these color components. * @param labelName Name of label. * @param red Red color component ranging 0.0 to 1.0. * @param green Green color component ranging 0.0 to 1.0. * @param blue Blue color component ranging 0.0 to 1.0. * @param alpha Alpha color component ranging 0.0 to 1.0. * @return Index of the existing label, or, if no label * exists with name, index of new label. * */ int32_t GiftiLabelTable::addLabel( const AString& labelName, const float red, const float green, const float blue, const float alpha) { const GiftiLabel gl(GiftiLabel::getInvalidLabelKey(), labelName, red, green, blue, alpha); return this->addLabel(&gl); } /** * Add a label. If a label with the name exists, its colors * are replaced with these color components. * @param labelName Name of label. * @param red Red color component ranging 0.0 to 1.0. * @param green Green color component ranging 0.0 to 1.0. * @param blue Blue color component ranging 0.0 to 1.0. * @return Index of the existing label, or, if no label * exists with name, index of new label. * */ int32_t GiftiLabelTable::addLabel( const AString& labelName, const float red, const float green, const float blue) { return this->addLabel(labelName, red, green, blue, 1.0f); } /** * Add a label. If a label with the name exists, its colors * are replaced with these color components. * @param labelName Name of label. * @param red Red color component ranging 0 to 255. * @param green Green color component ranging 0 to 255. * @param blue Blue color component ranging 0 to 255. * @param alpha Alpha color component ranging 0 to 255. * @return Index of the existing label, or, if no label * exists with name, index of new label. * */ int32_t GiftiLabelTable::addLabel( const AString& labelName, const int32_t red, const int32_t green, const int32_t blue, const int32_t alpha) { const GiftiLabel gl(GiftiLabel::getInvalidLabelKey(), labelName, red, green, blue, alpha); return this->addLabel(&gl); } /** * Add a label. If a label with the name exists, its colors * are replaced with these color components. * @param labelName Name of label. * @param red Red color component ranging 0 to 255. * @param green Green color component ranging 0 to 255. * @param blue Blue color component ranging 0 to 255. * @return Index of the existing label, or, if no label * exists with name, index of new label. * */ int32_t GiftiLabelTable::addLabel( const AString& labelName, const int32_t red, const int32_t green, const int32_t blue) { return this->addLabel(labelName, red, green, blue, 255); } /** * Add a label to the label table. If the label's key is already in * the label table, a new key is created. If a label of the same * name already exists, the key of the existing label is returned * and its color is overridden. * @param glIn - Label to add. * @return Key of the label, possibly different than its original key. * */ int32_t GiftiLabelTable::addLabel(const GiftiLabel* glIn) { /* * First see if a label with the same name already exists */ int32_t key = this->getLabelKeyFromName(glIn->getName()); /* * If no label with the name exists, get the key * (which may be invalid) from the input label, * and check that nothing uses that key */ if (key == GiftiLabel::getInvalidLabelKey()) { int32_t tempkey = glIn->getKey(); LABELS_MAP_ITERATOR iter = this->labelsMap.find(tempkey); if (iter == labelsMap.end()) { key = tempkey; } } /* * Still need a key, find an unused key */ if (key == GiftiLabel::getInvalidLabelKey()) { key = this->generateUnusedKey(); GiftiLabel* gl = new GiftiLabel(*glIn); gl->setKey(key); this->labelsMap.insert(std::make_pair(key, gl)); return key; } if (key == 0) { issueLabelKeyZeroWarning(glIn->getName()); // if (glIn->getName() != "???") { // CaretLogWarning("Label 0 overridden!"); // } } LABELS_MAP_ITERATOR iter = this->labelsMap.find(key); if (iter != this->labelsMap.end()) { /* * Update existing label */ GiftiLabel* gl = iter->second; gl->setName(glIn->getName()); float rgba[4]; glIn->getColor(rgba); gl->setColor(rgba); key = iter->first; } else { /* * Insert a new label */ this->labelsMap.insert(std::make_pair(key, new GiftiLabel(*glIn))); } return key; } /** * Generate an unused key. * @return An unused key. */ int32_t GiftiLabelTable::generateUnusedKey() const { const int32_t numKeys = labelsMap.size(); LABELS_MAP::const_reverse_iterator rbegin = labelsMap.rbegin();//reverse begin is largest key if (numKeys > 0 && rbegin->first > 0)//there is at least one positive key { if (rbegin->first < numKeys) { CaretAssert(labelsMap.find(rbegin->first + 1) == labelsMap.end()); return rbegin->first + 1;//keys are compact unless negatives exist, in which case consider it "compact enough" if positive holes equal number of negative keys } else { LABELS_MAP::const_iterator begin = labelsMap.begin(); if (begin->first == 1 && rbegin->first == numKeys) { CaretAssert(labelsMap.find(rbegin->first + 1) == labelsMap.end()); return rbegin->first + 1;//keys are compact but missing 0, do not return 0, so return next } else {//there aren't enough negatives to make up for the missing, search for a hole in the positives LABELS_MAP::const_iterator iter = labelsMap.upper_bound(0);//start with first positive int32_t curVal = 0;//if it isn't one, we can stop early while (iter != labelsMap.end() && iter->first == curVal + 1)//it should NEVER hit end(), due to above checks, but if it did, it would return rbegin->first + 1 { curVal = iter->first; ++iter; } CaretAssert(labelsMap.find(curVal + 1) == labelsMap.end()); return curVal + 1; } } } else { CaretAssert(labelsMap.find(1) == labelsMap.end()); return 1;//otherwise, no keys exist or all keys are non-positive, return 1 } /*int32_t numKeys = labelsMap.size(); LABELS_MAP_CONST_ITERATOR myend = labelsMap.end(); if (labelsMap.upper_bound(numKeys - 1) == myend) {//returns a valid iterator only if there is no strictly greater key - zero key is assumed to exist, being the ??? special palette, no negatives exist return numKeys;//keys are therefore compact, return the next one } if (labelsMap.find(0) == myend && labelsMap.upper_bound(numKeys) == myend) {//similar check, but in case label 0 doesn't exist (but don't override it) return numKeys + 1; } std::vector scratch; scratch.resize(numKeys);//guaranteed to have at least one missing spot within this range other than zero, or one of above tests would have returned for (int32_t i = 0; i < numKeys; ++i) { scratch[i] = 0; } for (LABELS_MAP_CONST_ITERATOR iter = labelsMap.begin(); iter != myend; ++iter) { if (iter->first >= 0 && iter->first < numKeys) {//dont try to mark above the range scratch[iter->first] = 1; } } for (int32_t i = 1; i < numKeys; ++i) {//NOTE: start at 1! 0 is reserved (sort of) if (scratch[i] == 0) { return i; } } CaretAssertMessage(false, "generateUnusedKey() failed for unknown reasons"); return 0;//should never happen//*/ /*std::set keys = getKeys(); int32_t newKey = 1; bool found = false; while (found == false) { if (std::find(keys.begin(), keys.end(), newKey) == keys.end()) { found = true; } else { newKey++; } } return newKey;//*/ } /** * Remove the label with the specified key. * @param key - key of label. * */ void GiftiLabelTable::deleteLabel(const int32_t key) { if (key == 0) {//key 0 is reserved (sort of) CaretLogWarning("Label 0 DELETED!"); } LABELS_MAP_ITERATOR iter = this->labelsMap.find(key); if (iter != this->labelsMap.end()) { GiftiLabel* gl = iter->second; this->labelsMap.erase(iter); delete gl; setModified(); } } /** * Remove a label from the label table. * This method WILL DELETE the label passed * in so the caller should never use the parameter * passed after this call. * @param label - label to remove. * */ void GiftiLabelTable::deleteLabel(const GiftiLabel* label) { if (label->getKey() == 0) {//key 0 is reserved (sort of) CaretLogWarning("Label 0 DELETED!"); } for (LABELS_MAP_ITERATOR iter = this->labelsMap.begin(); iter != this->labelsMap.end(); iter++) { if (iter->second == label) { this->labelsMap.erase(iter); setModified(); break; } } delete label; } /** * Remove unused labels from the label table. Note that the unassigned * label is not removed, even if it is unused. * * @param usedLabelKeys - Color keys that are in use. * */ void GiftiLabelTable::deleteUnusedLabels(const std::set& usedLabelKeys) { LABELS_MAP newMap; int32_t unassignedKey = getUnassignedLabelKey(); for (LABELS_MAP_ITERATOR iter = this->labelsMap.begin(); iter != this->labelsMap.end(); iter++) { int32_t key = iter->first; GiftiLabel* gl = iter->second; if (key == unassignedKey || usedLabelKeys.find(key) != usedLabelKeys.end()) {//unassigned key gets a free pass newMap.insert(std::make_pair(key, gl)); } else { delete gl; } } this->labelsMap = newMap; this->setModified(); } /** * Insert the label using the labels key. * @param labelIn - Label to insert (replaces an existing label * with the same key). * */ void GiftiLabelTable::insertLabel(const GiftiLabel* labelIn) { GiftiLabel* label = new GiftiLabel(*labelIn); int32_t key = label->getKey(); if (key == GiftiLabel::getInvalidLabelKey()) { key = this->generateUnusedKey(); label->setKey(key); } if (key == 0) {//key 0 is reserved (sort of) issueLabelKeyZeroWarning(label->getName()); } /* * Note: A map DOES NOT replace an existing key, so it * must be deleted and then added. */ LABELS_MAP_ITERATOR keyPos = this->labelsMap.find(label->getKey()); if (keyPos != this->labelsMap.end()) { GiftiLabel* gl = keyPos->second; this->labelsMap.erase(keyPos); delete gl; } this->labelsMap.insert(std::make_pair(label->getKey(), label)); this->setModified(); } /** * Get the key of a lable from its name. * @param name Name to search for. * @return Key of Name or GiftiLabel::getInvalidLabelKey() if not found. * */ int32_t GiftiLabelTable::getLabelKeyFromName(const AString& name) const { LABELS_MAP newMap; for (LABELS_MAP_CONST_ITERATOR iter = this->labelsMap.begin(); iter != this->labelsMap.end(); iter++) { int32_t key = iter->first; GiftiLabel* gl = iter->second; if (gl->getName() == name) { return key; } } return GiftiLabel::getInvalidLabelKey(); } /** * Get a GIFTI Label from its name. * @param labelName - Name of label that is sought. * @return Reference to label with name or null if no matching label. * */ const GiftiLabel* GiftiLabelTable::getLabel(const AString& labelName) const { LABELS_MAP newMap; for (LABELS_MAP_CONST_ITERATOR iter = this->labelsMap.begin(); iter != this->labelsMap.end(); iter++) { GiftiLabel* gl = iter->second; if (gl->getName() == labelName) { return gl; } } return NULL; } /** * Get a GIFTI Label from its name. * @param labelName - Name of label that is sought. * @return Reference to label with name or null if no matching label. * */ GiftiLabel* GiftiLabelTable::getLabel(const AString& labelName) { LABELS_MAP newMap; for (LABELS_MAP_CONST_ITERATOR iter = this->labelsMap.begin(); iter != this->labelsMap.end(); iter++) { GiftiLabel* gl = iter->second; if (gl->getName() == labelName) { return gl; } } return NULL; } /** * Get the label whose name is the longest substring of "name" beginning * at the first character. * * @param name - name for which best matching label is sought. * @return Reference to best matching label or null if not found. * */ const GiftiLabel* GiftiLabelTable::getLabelBestMatching(const AString& name) const { GiftiLabel* bestMatchingLabel = NULL; int32_t bestMatchLength = -1; LABELS_MAP newMap; for (LABELS_MAP_CONST_ITERATOR iter = this->labelsMap.begin(); iter != this->labelsMap.end(); iter++) { GiftiLabel* gl = iter->second; AString labelName = gl->getName(); if (name.startsWith(labelName)) { const int32_t len = labelName.length(); if (len > bestMatchLength) { bestMatchLength = len; bestMatchingLabel = iter->second; } } } return bestMatchingLabel; } /** * Get the GiftiLabel at the specified key. * * @param key - Key of GiftiLabel entry. * @return The GiftiLabel at the specified key or null if the * there is not a label at the specified key. * */ const GiftiLabel* GiftiLabelTable::getLabel(const int32_t key) const { LABELS_MAP_CONST_ITERATOR iter = this->labelsMap.find(key); if (iter != this->labelsMap.end()) { return iter->second; } return NULL; } /** * Get the GiftiLabel at the specified key. * * @param key - Key of GiftiLabel entry. * @return The GiftiLabel at the specified key or null if the * there is not a label at the specified key. */ GiftiLabel* GiftiLabelTable::getLabel(const int32_t key) { LABELS_MAP_ITERATOR iter = this->labelsMap.find(key); if (iter != this->labelsMap.end()) { return iter->second; } return NULL; } /** * Get the key for the unassigned label. * @return Index of key for unassigned label. * A valid key will always be returned. * */ int32_t GiftiLabelTable::getUnassignedLabelKey() const { const GiftiLabel* gl = this->getLabel("???"); if (gl != NULL) { return gl->getKey(); } /* * Remove 'constness' from this object so that the * label can be added. */ GiftiLabelTable* glt = (GiftiLabelTable*)this; const int32_t key = glt->addLabel("???", 0.0f, 0.0f, 0.0f, 0.0f); return key; } /** * Get the number of labels. This value is one greater than the last * label key. Note that not every key may have a label. If there * are no labels this returns 0. * @return Number of labels. * */ int32_t GiftiLabelTable::getNumberOfLabels() const { return this->labelsMap.size(); } /** * Get the name of the label at the key. If there is no label at the * key an empty string is returned. * @param key - key of label. * @return Name of label at inkeydex. * */ AString GiftiLabelTable::getLabelName(const int32_t key) const { LABELS_MAP_CONST_ITERATOR iter = this->labelsMap.find(key); if (iter != this->labelsMap.end()) { const AString name = iter->second->getName(); return name; } return ""; } /** * Set the name of a label. * @param key - key of label. * @param name - new name of label. * */ void GiftiLabelTable::setLabelName( const int32_t key, const AString& name) { if (key == 0) { if (name != "???") { issueLabelKeyZeroWarning(name); // CaretLogWarning("Label 0 modified!"); } } LABELS_MAP_ITERATOR iter = this->labelsMap.find(key); if (iter != this->labelsMap.end()) { iter->second->setName(name); } } /** * Set a label. If a label with the specified key exists, * it is replaced. * * @param key Key for label. * @param name Name of label. * @param red Red color component. * @param green Green color component. * @param blue Blue color component. * @param alpha Alpha color component. * */ void GiftiLabelTable::setLabel( const int32_t key, const AString& name, const float red, const float green, const float blue, const float alpha) { if (key == 0) { if (name != "???") { issueLabelKeyZeroWarning(name); // CaretLogWarning("Label 0 modified!"); } } LABELS_MAP_ITERATOR iter = this->labelsMap.find(key); if (iter != this->labelsMap.end()) { GiftiLabel* gl = iter->second; gl->setName(name); float rgba[4] = { red, green, blue, alpha }; gl->setColor(rgba); } else { GiftiLabel gl(key, name, red, green, blue, alpha); this->addLabel(&gl); } } /** * Set a label. If a label with the specified key exists, * it is replaced. * * @param key Key for label. * @param name Name of label. * @param red Red color component. * @param green Green color component. * @param blue Blue color component. * @param alpha Alpha color component. * @param x The X-coordinate. * @param y The Y-coordinate. * @param z The Z-coordinate. * */ void GiftiLabelTable::setLabel(const int32_t key, const AString& name, const float red, const float green, const float blue, const float alpha, const float x, const float y, const float z) { if (key == 0) { if (name != "???") { issueLabelKeyZeroWarning(name); //CaretLogWarning("Label 0 modified!"); } } LABELS_MAP_ITERATOR iter = this->labelsMap.find(key); if (iter != this->labelsMap.end()) { GiftiLabel* gl = iter->second; gl->setName(name); float rgba[4] = { red, green, blue, alpha }; gl->setColor(rgba); gl->setX(x); gl->setY(y); gl->setZ(z); } else { GiftiLabel gl(key, name, red, green, blue, alpha, x, y, z); this->addLabel(&gl); } } /** * Get the selection status of the label at the specified key. If there * is no label at the key, false is returned. * @param key - key of label * @return selection status of label. * */ bool GiftiLabelTable::isLabelSelected(const int32_t key) const { LABELS_MAP_CONST_ITERATOR iter = this->labelsMap.find(key); if (iter != this->labelsMap.end()) { return iter->second->isSelected(); } return false; } /** * Set the selection status of a label. * @param key - key of label. * @param sel - new selection status. * */ void GiftiLabelTable::setLabelSelected( const int32_t key, const bool sel) { LABELS_MAP_ITERATOR iter = this->labelsMap.find(key); if (iter != this->labelsMap.end()) { iter->second->setSelected(sel); } } /** * Set the selection status for all labels. * @param newStatus New selection status. * */ void GiftiLabelTable::setSelectionStatusForAllLabels(const bool newStatus) { for (LABELS_MAP_ITERATOR iter = this->labelsMap.begin(); iter != this->labelsMap.end(); iter++) { GiftiLabel* gl = iter->second; gl->setSelected(newStatus); } } /** * Get the alpha color component for a label. If the key is not a * valid label, an alpha of zero is returned. * @param key - Key of label. * @return Alpha for label or zero if invalid key. * */ float GiftiLabelTable::getLabelAlpha(const int32_t key) const { const GiftiLabel* gl = this->getLabel(key); if (gl != NULL) { return gl->getAlpha(); } return 0.0; } /** * Get the color for a label. * @param key - key of label. * @return Its color components or null if it is an invalid key. * */ void GiftiLabelTable::getLabelColor(const int32_t key, float rgbaOut[4]) const { const GiftiLabel* gl = this->getLabel(key); if (gl != NULL) { gl->getColor(rgbaOut); } } /** * Set the color of a label. * @param key - key of label. * @param color - new color of label. * */ void GiftiLabelTable::setLabelColor( const int32_t key, const float color[]) { if (key == 0) { CaretLogFiner("Label 0 color changed"); } LABELS_MAP_ITERATOR iter = this->labelsMap.find(key); if (iter != this->labelsMap.end()) { GiftiLabel* gl = iter->second; gl->setColor(color); } } /** * Get the label keys sorted by label name. * * @return Vector containing label keys sorted by name. * */ std::vector GiftiLabelTable::getLabelKeysSortedByName() const { /* * Use map to sort by name * If AStringNaturalComparison crashes, temporarily remove * as the third template parameter. */ std::map nameToKeyMap; for (LABELS_MAP_CONST_ITERATOR iter = this->labelsMap.begin(); iter != this->labelsMap.end(); iter++) { nameToKeyMap.insert(std::make_pair(iter->second->getName(), iter->first)); } std::vector keysSortedByName; for (std::map::iterator iter = nameToKeyMap.begin(); iter != nameToKeyMap.end(); iter++) { keysSortedByName.push_back(iter->second); } return keysSortedByName; } /** * Reset the label counts to zero. * */ void GiftiLabelTable::resetLabelCounts() { for (LABELS_MAP_ITERATOR iter = this->labelsMap.begin(); iter != this->labelsMap.end(); iter++) { if (iter != this->labelsMap.end()) { GiftiLabel* gl = iter->second; gl->setCount(0); } } } /** * @return True if this label table contains a label with the * name of the medial wall, else false. */ bool GiftiLabelTable::hasMedialWallLabel() const { for (LABELS_MAP_CONST_ITERATOR iter = this->labelsMap.begin(); iter != this->labelsMap.end(); iter++) { const GiftiLabel* label = iter->second; CaretAssert(label); if (label->isMedialWallName()) { return true; } } return false; } ///** // * @return Are there any labels that have an invalid group/name // * hierarchy settings. This can be caused by changing the name // * of a label or its color. // */ //bool //GiftiLabelTable::hasLabelsWithInvalidGroupNameHierarchy() const //{ // for (LABELS_MAP_CONST_ITERATOR iter = this->labelsMap.begin(); // iter != this->labelsMap.end(); // iter++) { // if (iter != this->labelsMap.end()) { // GiftiLabel* gl = iter->second; // if (gl->getGroupNameSelectionItem() == NULL) { // return true; // break; // } // } // } // // return false; //} /** * Remove labels that have the 'count' attribute * set to zero. * Note the ??? label is not removed. */ void GiftiLabelTable::removeLabelsWithZeroCounts() { const int32_t unknownKey = getUnassignedLabelKey(); /** * First, iterate through the map to find * labels that have the 'count' attribute * set to zero. Delete the label and save * the key since one cannot erase the map * element without confusing the iterator * and causing a crash. */ std::vector unusedkeys; for (LABELS_MAP_ITERATOR iter = this->labelsMap.begin(); iter != this->labelsMap.end(); iter++) { const GiftiLabel* gl = iter->second; if (gl->getCount() <= 0) { /* * Get key and save it. */ const int32_t key = iter->first; if (key != unknownKey) { unusedkeys.push_back(key); /* * Delete the label. */ delete gl; iter->second = NULL; } } } /* * Now, remove all of the elements in the * map for the keys that were found in the * previous loop. */ bool isLabelRemoved = false; for (std::vector::iterator iter = unusedkeys.begin(); iter != unusedkeys.end(); iter++) { const int32_t key = *iter; this->labelsMap.erase(key); isLabelRemoved = true; } if (isLabelRemoved) { this->setModified(); } } /** * Create labels for the keys with generated names and colors. * @param newKeys - Keys that need labels. * */ void GiftiLabelTable::createLabelsForKeys(const std::set& newKeys) { AString namePrefix = "Name"; int32_t nameCount = 0; int32_t colorCounter = 0; for (std::set::iterator iter = newKeys.begin(); iter != newKeys.end(); iter++) { int32_t key = *iter; if (this->getLabel(key) == NULL) { bool found = false; AString name; while (! found) { std::stringstream str; str << namePrefix.toStdString() << "_" << nameCount; nameCount++; name = AString::fromStdString(str.str()); if (this->getLabel(name) == NULL) { found = true; } float red = 0.0f; float green = 0.0f; float blue = 0.0f; float alpha = 1.0f; switch (colorCounter) { case 0: red = 1.0f; break; case 1: red = 1.0f; blue = 0.5f; break; case 2: red = 1.0f; blue = 1.0f; break; case 3: red = 1.0f; green = 0.5f; break; case 4: red = 1.0f; green = 0.5f; blue = 0.5f; break; case 5: red = 1.0f; green = 0.5f; blue = 1.0f; break; case 6: blue = 0.5f; break; case 7: blue = 1.0f; break; case 8: red = 0.5f; break; case 9: red = 0.5f; blue = 0.5f; break; case 10: red = 0.5f; blue = 1.0f; break; case 11: red = 0.5f; green = 0.5f; break; case 12: red = 0.5f; green = 0.5f; blue = 0.5f; break; case 13: red = 0.5f; green = 0.5f; blue = 1.0f; break; case 14: red = 0.5f; green = 1.0f; break; case 15: red = 0.5f; green = 1.0f; blue = 0.5f; break; case 16: red = 0.5f; green = 1.0f; blue = 1.0f; colorCounter = 0; // start over break; } colorCounter++; GiftiLabel* gl = new GiftiLabel(key, name, red, green, blue, alpha); this->addLabel(gl); } } } } /** * Write the metadata in GIFTI XML format. * * @param xmlWriter - output stream * @throws GiftiException if an error occurs while writing. * */ void GiftiLabelTable::writeAsXML(XmlWriter& xmlWriter) { try { // // Write the label tag // xmlWriter.writeStartElement(GiftiXmlElements::TAG_LABEL_TABLE); // // Write the labels // std::set keys = this->getKeys(); for (std::set::const_iterator iter = keys.begin(); iter != keys.end(); iter++) { int key = *iter; const GiftiLabel* label = this->getLabel(key); if (label != NULL) { XmlAttributes attributes; attributes.addAttribute(GiftiXmlElements::ATTRIBUTE_LABEL_KEY, key); float rgba[4]; label->getColor(rgba); attributes.addAttribute(GiftiXmlElements::ATTRIBUTE_LABEL_RED, rgba[0]); attributes.addAttribute(GiftiXmlElements::ATTRIBUTE_LABEL_GREEN, rgba[1]); attributes.addAttribute(GiftiXmlElements::ATTRIBUTE_LABEL_BLUE, rgba[2]); attributes.addAttribute(GiftiXmlElements::ATTRIBUTE_LABEL_ALPHA, rgba[3]); xmlWriter.writeElementCData(GiftiXmlElements::TAG_LABEL, attributes, label->getName()); } } // // Write the closing label tag // xmlWriter.writeEndElement(); } catch (XmlException& e) { throw GiftiException(e); } } void GiftiLabelTable::writeAsXML(QXmlStreamWriter& xmlWriter) const { try { // // Write the label tag // xmlWriter.writeStartElement(GiftiXmlElements::TAG_LABEL_TABLE); // // Write the labels // std::set keys = this->getKeys(); for (std::set::const_iterator iter = keys.begin(); iter != keys.end(); iter++) { int key = *iter; const GiftiLabel* label = this->getLabel(key); if (label != NULL) { xmlWriter.writeStartElement(GiftiXmlElements::TAG_LABEL); xmlWriter.writeAttribute(GiftiXmlElements::ATTRIBUTE_LABEL_KEY, AString::number(key)); float rgba[4]; label->getColor(rgba); xmlWriter.writeAttribute(GiftiXmlElements::ATTRIBUTE_LABEL_RED, AString::number(rgba[0])); xmlWriter.writeAttribute(GiftiXmlElements::ATTRIBUTE_LABEL_GREEN, AString::number(rgba[1])); xmlWriter.writeAttribute(GiftiXmlElements::ATTRIBUTE_LABEL_BLUE, AString::number(rgba[2])); xmlWriter.writeAttribute(GiftiXmlElements::ATTRIBUTE_LABEL_ALPHA, AString::number(rgba[3])); xmlWriter.writeCharacters(label->getName()); xmlWriter.writeEndElement(); } } // // Write the closing label tag // xmlWriter.writeEndElement(); } catch (XmlException& e) { throw GiftiException(e); } } /** * Convert to a string. * * @return String representation of labelTable. * */ AString GiftiLabelTable::toString() const { AString s = "GiftiLabelTable=["; for (LABELS_MAP_CONST_ITERATOR iter = this->labelsMap.begin(); iter != this->labelsMap.end(); iter++) { s += "key="; s += AString::number(iter->first); s += iter->second->toString(); s += ","; } s += "]"; return s; } /** * Get a nicely formatted string for printing. * * @param indentation - use as indentation. * @return String containing label information. * */ AString GiftiLabelTable::toFormattedString(const AString& indentation) const { std::set allKeys = getKeys(); const int32_t numberOfKeys = allKeys.size(); if (numberOfKeys <= 0) { return "Empty"; } int32_t columnCounter = 0; const int32_t COL_INDENT = columnCounter++; const int32_t COL_KEY = columnCounter++; const int32_t COL_NAME = columnCounter++; const int32_t COL_RED = columnCounter++; const int32_t COL_GREEN = columnCounter++; const int32_t COL_BLUE = columnCounter++; const int32_t COL_ALPHA = columnCounter++; const int32_t numberOfTableRows = numberOfKeys + 1; StringTableModel table(numberOfTableRows, columnCounter); int32_t rowIndex = 0; table.setElement(rowIndex, COL_INDENT, // accomplishes indentation indentation); table.setElement(rowIndex, COL_KEY, "KEY"); table.setElement(rowIndex, COL_NAME, "NAME"); table.setElement(rowIndex, COL_RED, "RED"); table.setElement(rowIndex, COL_GREEN, "GREEN"); table.setElement(rowIndex, COL_BLUE, "BLUE"); table.setElement(rowIndex, COL_ALPHA, "ALPHA"); rowIndex++; table.setColumnAlignment(COL_KEY, StringTableModel::ALIGN_RIGHT); table.setColumnAlignment(COL_NAME, StringTableModel::ALIGN_LEFT); table.setColumnAlignment(COL_RED, StringTableModel::ALIGN_RIGHT); table.setColumnAlignment(COL_GREEN, StringTableModel::ALIGN_RIGHT); table.setColumnAlignment(COL_BLUE, StringTableModel::ALIGN_RIGHT); table.setColumnAlignment(COL_ALPHA, StringTableModel::ALIGN_RIGHT); for (std::set::iterator iter = allKeys.begin(); iter != allKeys.end(); iter++) { const int32_t key = *iter; const GiftiLabel* label = getLabel(key); CaretAssertArrayIndex("table", numberOfTableRows, rowIndex); table.setElement(rowIndex, COL_KEY, key); if (label != NULL) { table.setElement(rowIndex, COL_NAME, label->getName()); table.setElement(rowIndex, COL_RED, label->getRed()); table.setElement(rowIndex, COL_GREEN, label->getGreen()); table.setElement(rowIndex, COL_BLUE, label->getBlue()); table.setElement(rowIndex, COL_ALPHA, label->getAlpha()); } else { table.setElement(rowIndex, COL_NAME, "Label Missing"); } rowIndex++; } return table.getInString(); } /** * Read the label table from XML DOM structures. * @param rootNode - the LabelTable node. * @throws GiftiException if an error occurs. * * void GiftiLabelTable::readFromXMLDOM(const Node* rootNode) { } */ /** * Read a LabelTable from a String. The beginning and ending tags must * be the label table tag GiftiXmlElements.TAG_LABEL_TABLE. * @param s - string containing the label table. * @throws GiftiException If there is an error processing the table. * */ void GiftiLabelTable::readFromXmlString(const AString& /*s*/) { CaretAssertMessage(0, "Not implemented yet!"); } void GiftiLabelTable::readFromQXmlStreamReader(QXmlStreamReader& xml) { clear(); bool haveUnassigned = false;//because clear() creates the default "???" label if (!xml.isStartElement() || xml.name() != GiftiXmlElements::TAG_LABEL_TABLE) {//TODO: try to recover instead of erroring? xml.raiseError("tried to read GiftiLabelTable when current element is not " + GiftiXmlElements::TAG_LABEL_TABLE); return; } while (xml.readNextStartElement() && !xml.atEnd()) { if (xml.name() != GiftiXmlElements::TAG_LABEL) { xml.raiseError("unexpected element '" + xml.name().toString() + "' encountered in " + GiftiXmlElements::TAG_LABEL_TABLE); } int key; float rgba[4]; QXmlStreamAttributes myAttrs = xml.attributes(); bool ok = false; QString temp = myAttrs.value(GiftiXmlElements::ATTRIBUTE_LABEL_KEY).toString(); key = temp.toInt(&ok); if (!ok) xml.raiseError("Key attribute of Label missing or noninteger"); temp = myAttrs.value(GiftiXmlElements::ATTRIBUTE_LABEL_RED).toString(); rgba[0] = temp.toFloat(&ok); if (!ok) xml.raiseError("Red attribute of Label missing or not a number"); temp = myAttrs.value(GiftiXmlElements::ATTRIBUTE_LABEL_GREEN).toString(); rgba[1] = temp.toFloat(&ok); if (!ok) xml.raiseError("Green attribute of Label missing or not a number"); temp = myAttrs.value(GiftiXmlElements::ATTRIBUTE_LABEL_BLUE).toString(); rgba[2] = temp.toFloat(&ok); if (!ok) xml.raiseError("Blue attribute of Label missing or not a number"); temp = myAttrs.value(GiftiXmlElements::ATTRIBUTE_LABEL_ALPHA).toString(); if (temp == "") { rgba[3] = 1.0f; } else { rgba[3] = temp.toFloat(&ok); if (!ok) xml.raiseError("Alpha attribute of Label not a number"); } temp = xml.readElementText(); if (xml.hasError()) return; if ((temp == "unknown" || temp == "Unknown") && rgba[3] == 0.0f) { if (haveUnassigned) { CaretLogWarning("found multiple label elements that should be interpreted as unlabeled"); } else { CaretLogFiner("Using '" + temp + "' label as unlabeled key"); haveUnassigned = true; temp = "???";//pretend they are actually our internal unlabeled name } } else if (temp == "???") { if (haveUnassigned) { CaretLogWarning("found multiple label elements that should be interpreted as unlabeled"); } haveUnassigned = true; } setLabel(key, temp, rgba[0], rgba[1], rgba[2], rgba[3]); } } /** * Set this object has been modified. * */ void GiftiLabelTable::setModified() { this->modifiedFlag = true; } /** * Set this object as not modified. Object should also * clear the modification status of its children. * */ void GiftiLabelTable::clearModified() { this->modifiedFlag = false; for (LABELS_MAP_CONST_ITERATOR iter = this->labelsMap.begin(); iter != this->labelsMap.end(); iter++) { iter->second->clearModified(); } } /** * Get the modification status. Returns true if this object or * any of its children have been modified. * @return - The modification status. * */ bool GiftiLabelTable::isModified() const { if (this->modifiedFlag) return true; for (LABELS_MAP_CONST_ITERATOR iter = this->labelsMap.begin(); iter != this->labelsMap.end(); iter++) { if (iter->second->isModified()) return true; } return false; } /** * Get an iterator that steps thought the label keys in * ascending order. * @return An iterator for stepping through the keys in * ascending order. * * Iterator GiftiLabelTable::getKeysIterator() const { return this-> } */ /** * Get the valid keys of the labels in ascending order. * @return A Set containing the valid keys of the label in * ascending order. * */ std::set GiftiLabelTable::getKeys() const { std::set keys; for (std::map::const_iterator iter = this->labelsMap.begin(); iter != this->labelsMap.end(); iter++) { keys.insert(iter->first); } return keys; } void GiftiLabelTable::getKeys(std::vector& keysOut) const { keysOut.reserve(labelsMap.size()); for (std::map::const_iterator iter = this->labelsMap.begin(); iter != this->labelsMap.end(); iter++) { keysOut.push_back(iter->first); } } /** * Get all keys and names. * * @parm keysAndNamesOut * Map containing the pairs of corresponding keys and names. */ void GiftiLabelTable::getKeysAndNames(std::map& keysAndNamesOut) const { keysAndNamesOut.clear(); for (std::map::const_iterator iter = this->labelsMap.begin(); iter != this->labelsMap.end(); iter++) { const GiftiLabel* gl = iter->second; keysAndNamesOut.insert(std::make_pair(iter->first, gl->getName())); } } /** * Change the key of a label from 'currentKey' to 'newKey'. * If a label exists with 'newKey', the label with 'newKey' is removed. * * @param currentKey * Key currently used by the label. * @param newKey * New key for the label. */ void GiftiLabelTable::changeLabelKey(const int32_t currentKey, const int32_t newKey) { /* * Remove a label that uses 'newKey'. */ if (this->labelsMap.find(newKey) != this->labelsMap.end()) { deleteLabel(newKey); } /* * Get the label with 'currentKey' and remove it from the map. */ LABELS_MAP_ITERATOR currentLabelIter = this->labelsMap.find(currentKey); if (currentLabelIter == this->labelsMap.end()) { CaretLogSevere("Attempting to change label key for non-existent label with key=" + AString::number(currentKey)); return; } GiftiLabel* label = currentLabelIter->second; this->labelsMap.erase(currentKey); /* * Change the lable's key from 'currentKey' to 'newKey' * and add the label into the label's map. */ label->setKey(newKey); this->labelsMap.insert(std::make_pair(newKey, label)); } bool GiftiLabelTable::matches(const GiftiLabelTable& rhs, const bool checkColors, const bool checkCoords) const { if (labelsMap.size() != rhs.labelsMap.size()) return false; for (LABELS_MAP::const_iterator iter = labelsMap.begin(); iter != labelsMap.end(); ++iter) { LABELS_MAP::const_iterator riter = rhs.labelsMap.find(iter->first); if (riter == rhs.labelsMap.end()) return false; if (!iter->second->matches(*(riter->second), checkColors, checkCoords)) return false; } return true; } /** * Called when label key zero's name is changed. * May result in a logger message is name is not a preferred name * for the label with key zero. * * @param name * New name for label with key zero. */ void GiftiLabelTable::issueLabelKeyZeroWarning(const AString& name) const { if ((name != "???") && (name.toLower() != "unknown")) { CaretLogFine("Label with key=0 overridden with name \"" + name + "\". This label is typically \"???\" or \"unknown\"."); } } /** * Export the content of the GIFTI Label Table to a Caret5 Color File. */ void GiftiLabelTable::exportToCaret5ColorFile(const AString& filename) const { if (filename.isEmpty()) { throw GiftiException("Missing filename for export of label table to caret5 color file format."); } QFile file(filename); if ( ! file.open(QFile::WriteOnly)) { const AString msg = ("Unable to open " + filename + " for export of label table to caret5 color file format.\n" + file.errorString()); throw GiftiException(msg); } QXmlStreamWriter xmlWriter(&file); xmlWriter.setAutoFormatting(true); xmlWriter.writeStartDocument("1.0"); xmlWriter.writeStartElement("Border_Color_File"); xmlWriter.writeStartElement("FileHeader"); xmlWriter.writeStartElement("Element"); xmlWriter.writeTextElement("comment", "Exported from Caret7/Workbench"); xmlWriter.writeEndElement(); xmlWriter.writeEndElement(); std::set keys = this->getKeys(); for (std::set::const_iterator iter = keys.begin(); iter != keys.end(); iter++) { int key = *iter; const GiftiLabel* label = this->getLabel(key); if (label != NULL) { xmlWriter.writeStartElement("Color"); xmlWriter.writeTextElement("name", label->getName()); const int32_t red = static_cast(label->getRed() * 255.0); const int32_t green = static_cast(label->getGreen() * 255.0); const int32_t blue = static_cast(label->getBlue() * 255.0); const int32_t alpha = static_cast(label->getAlpha() * 255.0); xmlWriter.writeTextElement("red", AString::number(red)); xmlWriter.writeTextElement("green", AString::number(green)); xmlWriter.writeTextElement("blue", AString::number(blue)); xmlWriter.writeTextElement("alpha", AString::number(alpha)); xmlWriter.writeTextElement("pointSize", "1.5"); xmlWriter.writeTextElement("lineSize", "1.0"); xmlWriter.writeTextElement("symbol", "POINT"); xmlWriter.writeTextElement("sumscolorid", ""); xmlWriter.writeEndElement(); } } xmlWriter.writeEndElement(); xmlWriter.writeEndDocument(); file.close(); } connectome-workbench-1.4.2/src/FilesBase/GiftiLabelTable.h000066400000000000000000000151311360521144700234030ustar00rootroot00000000000000#ifndef __GIFTILABELTABLE_H__ #define __GIFTILABELTABLE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AString.h" #include "CaretObject.h" #include "TracksModificationInterface.h" #include "GiftiException.h" #include #include #include #include #include #include namespace caret { class GiftiLabel; class XmlWriter; class XmlException; /** * Maintains a GIFTI Label Table using key/value pairs. */ class GiftiLabelTable : public CaretObject, TracksModificationInterface { public: GiftiLabelTable(); GiftiLabelTable(const GiftiLabelTable& glt); GiftiLabelTable& operator=(const GiftiLabelTable& glt); bool matches(const GiftiLabelTable& rhs, const bool checkColors = false, const bool checkCoords = false) const; bool operator==(const GiftiLabelTable& rhs) const { return matches(rhs, true); } bool operator!=(const GiftiLabelTable& rhs) const { return !((*this) == rhs); } virtual ~GiftiLabelTable(); private: void copyHelper(const GiftiLabelTable& glt); void initializeMembersGiftiLabelTable(); public: void clear(); std::map append(const GiftiLabelTable& glt); int32_t addLabel( const AString& labelName, const float red, const float green, const float blue, const float alpha); int32_t addLabel( const AString& labelName, const float red, const float green, const float blue); int32_t addLabel( const AString& labelName, const int32_t red, const int32_t green, const int32_t blue, const int32_t alpha); int32_t addLabel( const AString& labelName, const int32_t red, const int32_t green, const int32_t blue); int32_t addLabel(const GiftiLabel* glt); void deleteLabel(const int32_t key); void deleteLabel(const GiftiLabel* label); void deleteUnusedLabels(const std::set& usedLabelKeys); void insertLabel(const GiftiLabel* label); int32_t getLabelKeyFromName(const AString& name) const; const GiftiLabel* getLabel(const AString& labelName) const; GiftiLabel* getLabel(const AString& labelName); const GiftiLabel* getLabelBestMatching(const AString& name) const; const GiftiLabel* getLabel(const int32_t key) const; GiftiLabel* getLabel(const int32_t key); int32_t getUnassignedLabelKey() const; int32_t getNumberOfLabels() const; AString getLabelName(const int32_t key) const; void setLabelName( const int32_t key, const AString& name); void setLabel(const int32_t key, const AString& name, const float red, const float green, const float blue, const float alpha); void setLabel(const int32_t key, const AString& name, const float red, const float green, const float blue, const float alpha, const float x, const float y, const float z); bool isLabelSelected(const int32_t key) const; void setLabelSelected( const int32_t key, const bool sel); void setSelectionStatusForAllLabels(const bool newStatus); float getLabelAlpha(const int32_t key) const; void getLabelColor(const int32_t key, float rgbaOut[4]) const; void setLabelColor( const int32_t key, const float color[4]); std::vector getLabelKeysSortedByName() const; void resetLabelCounts(); void removeLabelsWithZeroCounts(); void createLabelsForKeys(const std::set& newKeys); bool hasMedialWallLabel() const; void writeAsXML(XmlWriter& xmlWriter); void writeAsXML(QXmlStreamWriter& xmlWriter) const; AString toString() const; AString toFormattedString(const AString& indentation) const; //void readFromXMLDOM(const Node* rootNode) // ; void readFromXmlString(const AString& s); void readFromQXmlStreamReader(QXmlStreamReader& xml); void setModified(); void clearModified(); bool isModified() const; //Iterator getKeysIterator() const; std::set getKeys() const; void getKeys(std::vector& keysOut) const; void getKeysAndNames(std::map& keysAndNamesOut) const; // bool hasLabelsWithInvalidGroupNameHierarchy() const; int32_t generateUnusedKey() const; void changeLabelKey(const int32_t currentKey, const int32_t newKey); void exportToCaret5ColorFile(const AString& filename) const; private: void issueLabelKeyZeroWarning(const AString& name) const; /** The label table storage. Use a TreeMap since label keys may be sparse. */ typedef std::map LABELS_MAP; typedef std::map::iterator LABELS_MAP_ITERATOR; typedef std::map::const_iterator LABELS_MAP_CONST_ITERATOR; LABELS_MAP labelsMap; /**tracks modification status */ bool modifiedFlag; int32_t m_tableModelColumnIndexKey; int32_t m_tableModelColumnIndexName; int32_t m_tableModelColumnIndexColorSwatch; int32_t m_tableModelColumnIndexRed; int32_t m_tableModelColumnIndexGreen; int32_t m_tableModelColumnIndexBlue; int32_t m_tableModelColumnCount; }; } // namespace #endif // __GIFTILABELTABLE_H__ connectome-workbench-1.4.2/src/FilesBase/GiftiMetaData.cxx000066400000000000000000000413461360521144700234560ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "CaretAssert.h" #include "GiftiMetaData.h" #include "GiftiMetaDataXmlElements.h" //#include "NiftiUtilities.h" #include "GiftiXmlElements.h" #include "XmlWriter.h" using namespace caret; /** * Constructor. * */ GiftiMetaData::GiftiMetaData() : CaretObject(), TracksModificationInterface() { this->initializeMembersGiftiMetaData(); } /** * Destructor */ GiftiMetaData::~GiftiMetaData() { } /** * Copy Constructor * @param Object that is copied. */ GiftiMetaData::GiftiMetaData(const GiftiMetaData& o) : CaretObject(o), TracksModificationInterface() { this->initializeMembersGiftiMetaData(); this->copyHelper(o); } /** * Assignment operator. */ GiftiMetaData& GiftiMetaData::operator=(const GiftiMetaData& o) { if (this != &o) { CaretObject::operator=(o); this->copyHelper(o); }; return *this; } bool GiftiMetaData::operator==(const GiftiMetaData& rhs) const { return (metadata == rhs.metadata); } /** * Helps with copy constructor and assignment operator. */ void GiftiMetaData::copyHelper(const GiftiMetaData& o) { /* * Preserve this instance's Unique ID, but only if it already has one. */ if (exists(GiftiMetaDataXmlElements::METADATA_NAME_UNIQUE_ID)) { const AString uid = this->getUniqueID(); this->metadata = o.metadata; this->set(GiftiMetaDataXmlElements::METADATA_NAME_UNIQUE_ID, uid); this->clearModified(); } else { this->metadata = o.metadata; } } void GiftiMetaData::initializeMembersGiftiMetaData() { this->modifiedFlag = false; } /** * Get the Unique ID. If there is not a unique ID, one is created. * @return String containing unique ID. * */ AString GiftiMetaData::getUniqueID() const { AString uid; MetaDataConstIterator iter = this->metadata.find(GiftiMetaDataXmlElements::METADATA_NAME_UNIQUE_ID); if (iter != this->metadata.end()) { uid = iter->second; } else { uid = SystemUtilities::createUniqueID(); this->metadata.insert(std::make_pair(GiftiMetaDataXmlElements::METADATA_NAME_UNIQUE_ID, uid)); } return uid; } /** * Reset the unique identifier. * Do not call this method unless you really need to such * as in the caret when multiple data arrays have the * same unique identifier. */ void GiftiMetaData::resetUniqueIdentifier() { this->set(GiftiMetaDataXmlElements::METADATA_NAME_UNIQUE_ID, SystemUtilities::createUniqueID()); } /** * Remove the UniqueID from this metadata. * * void GiftiMetaData::removeUniqueID() { this->remove(GiftiMetaDataXmlElements::METADATA_NAME_UNIQUE_ID); } */ /** * Clear the metadata. * */ void GiftiMetaData::clear(bool keepUUID) { if (keepUUID && exists(GiftiMetaDataXmlElements::METADATA_NAME_UNIQUE_ID)) { /* * Preserve this instance's Unique ID. */ const AString uid = this->getUniqueID(); this->metadata.clear(); this->set(GiftiMetaDataXmlElements::METADATA_NAME_UNIQUE_ID, uid); this->clearModified(); } else { metadata.clear(); } } /** * Append the metadata to this metadata. A comment is always appended. * Other metadata are added only if the name is not in "this" metadata. * * @param smd Metadata that is to be appended to "this". * */ void GiftiMetaData::append(const GiftiMetaData& smd) { for (MetaDataConstIterator iter = smd.metadata.begin(); iter != smd.metadata.end(); iter++) { if (iter->first != GiftiMetaDataXmlElements::METADATA_NAME_UNIQUE_ID) { this->set(iter->first, iter->second); } } this->setModified(); } /** * Clears this metadata and then copies all metadata from "smd" * with the exception of the Unique ID. * * @param smd Metadata that is to be copied to "this". * */ void GiftiMetaData::replace(const GiftiMetaData& smd) { /* * Preserve UniqueID. */ const AString uid = this->getUniqueID(); this->metadata = smd.metadata; this->set(GiftiMetaDataXmlElements::METADATA_NAME_UNIQUE_ID, uid); this->setModified(); } /** * Sets metadata. If a metadata entry named "name" already * exists, it is replaced. * * @param name Name of metadata entry. * @param value Value for metadata entry. * */ void GiftiMetaData::set(const AString& name, const AString& value) { MetaDataIterator namePos = this->metadata.find(name); if (namePos != this->metadata.end()) { if (namePos->second != value) { namePos->second = value; this->setModified(); } } else { this->metadata.insert(std::make_pair(name, value)); this->setModified(); } } /** * Set metadata with an integer value. * @param name - name of metadata. * @param value - value of metadata. * */ void GiftiMetaData::setInt( const AString& name, const int32_t value) { AString s = AString::number(value); this->set(name, s); } /** * Set metadata with an float value. * @param name - name of metadata. * @param value - value of metadata. * */ void GiftiMetaData::setFloat( const AString& name, const float value) { AString s = AString::number(value); this->set(name, s); } /** * Replace ALL of the metadata with the data in the given map. * * @param map * New metadata that replaces all existing metadata. */ void GiftiMetaData::replaceWithMap(const std::map& map) { /* * Save UniqueID if it has one and use it if no unique ID in given map. */ AString uid; if (exists(GiftiMetaDataXmlElements::METADATA_NAME_UNIQUE_ID)) { uid = this->getUniqueID(); } this->metadata = map; /* * If metadata was not in given map, restore the Unique ID if we had one. */ if (this->metadata.find(GiftiMetaDataXmlElements::METADATA_NAME_UNIQUE_ID) == this->metadata.end() && uid != "") { this->set(GiftiMetaDataXmlElements::METADATA_NAME_UNIQUE_ID, uid); } this->setModified(); } /** * @return ALL of the metadata in map. */ std::map GiftiMetaData::getAsMap() const { return this->metadata; } /** * Remove a metadata entry. * * @param name Name of metadata entry that is to be removed. * */ void GiftiMetaData::remove(const AString& name) { this->metadata.erase(name); } /** * See if a metadata entry "name" exists. * * @param name Name of metadata entry. * @return Returns true if the metadata entry "name" exists, else false. * */ bool GiftiMetaData::exists(const AString& name) const { if (this->metadata.find(name) != this->metadata.end()) { return true; } return false; } /** * Get a value for metadata entry. * * @param name Name of metadata entry. * @return The value of the metadata entry "name". If the * metadata entry "name" does not exist an empty * string is returned. * */ AString GiftiMetaData::get(const AString& name) const { if (this->metadata.empty()) { return ""; } MetaDataConstIterator iter = this->metadata.find(name); if (iter != this->metadata.end()) { return iter->second; } return ""; } /** * Get the metadata as an integer value. If the metadata does not exist * of its string representation is not a number, zero is returned. * @param name - name of metadata. * @return Integer value associated with the metadata. * */ int32_t GiftiMetaData::getInt(const AString& name) const { AString s = this->get(name); if (s.length() > 0) { int32_t i = s.toInt(); return i; } return 0; } /** * Get the metadata as an float value. If the metadata does not exist * of its string representation is not a number, zero is returned. * @param name - name of metadata. * @return Float value associated with the metadata. * */ float GiftiMetaData::getFloat(const AString& name) const { AString s = this->get(name); if (s.length() > 0) { float f = s.toFloat(); return f; } return 0.0f; } /** * Get names of all metadata. * * @return List of all metadata names. * */ std::vector GiftiMetaData::getAllMetaDataNames() const { std::vector names; for (MetaDataConstIterator iter = this->metadata.begin(); iter != this->metadata.end(); iter++) { names.push_back(iter->first); } return names; } /** * Update metanames from caret5. * */ void GiftiMetaData::updateFromCaret5Names() { } /** * Replace a metadata name. * @param oldName - old name of metadata. * @param newName - new name of metadata. * */ void GiftiMetaData::replaceName( const AString& oldName, const AString& newName) { MetaDataIterator iter = this->metadata.find(oldName); if (iter != this->metadata.end()) { AString value = iter->second; this->remove(oldName); this->set(newName, value); this->setModified(); } } /** * Convert to a string. * * @return String representation of metadata. * */ AString GiftiMetaData::toString() const { AString s = "GiftiMetaData=["; for (MetaDataConstIterator iter = this->metadata.begin(); iter != this->metadata.end(); iter++) { const AString& name = iter->first; const AString& value = iter->second; s += ("(" + name + "," + value + ")"); } s += "]"; return s; } /** * Get a nicely formatted string for printing. * * @param indentation - use as indentation. * @return String containing label information. * */ AString GiftiMetaData::toFormattedString(const AString& indentation) { return (indentation + this->toString()); } /** * Write the metadata in GIFTI XML format. * * @param xmlWriter - output stream * @throws GiftiException if an error occurs while writing. */ void GiftiMetaData::writeAsXML(XmlWriter& xmlWriter) { try { // // Write the metadata tag // xmlWriter.writeStartElement(GiftiXmlElements::TAG_METADATA); // // Write the metadata // for (MetaDataConstIterator iter = this->metadata.begin(); iter != this->metadata.end(); iter++) { const AString& key = iter->first; const AString& value = iter->second; // // MD Tag // xmlWriter.writeStartElement(GiftiXmlElements::TAG_METADATA_ENTRY); // // Name and value // xmlWriter.writeElementCData(GiftiXmlElements::TAG_METADATA_NAME, key); xmlWriter.writeElementCData(GiftiXmlElements::TAG_METADATA_VALUE, value); // // Closing tag // xmlWriter.writeEndElement(); } // // Write the closing metadata tag // xmlWriter.writeEndElement(); } catch (XmlException& e) { throw GiftiException(e); } } void GiftiMetaData::writeCiftiXML1(QXmlStreamWriter& xmlWriter) const { if (metadata.empty()) return;//don't write an empty tag if we have no metadata xmlWriter.writeStartElement(GiftiXmlElements::TAG_METADATA); for (MetaDataConstIterator iter = metadata.begin(); iter != metadata.end(); ++iter) { xmlWriter.writeStartElement(GiftiXmlElements::TAG_METADATA_ENTRY); xmlWriter.writeTextElement(GiftiXmlElements::TAG_METADATA_NAME, iter->first); xmlWriter.writeTextElement(GiftiXmlElements::TAG_METADATA_VALUE, iter->second); xmlWriter.writeEndElement(); } xmlWriter.writeEndElement(); } void GiftiMetaData::writeCiftiXML2(QXmlStreamWriter& xmlWriter) const { writeCiftiXML1(xmlWriter); } void GiftiMetaData::writeBorderFileXML3(QXmlStreamWriter& xmlWriter) const { writeCiftiXML1(xmlWriter); } void GiftiMetaData::writeSceneFile3(QXmlStreamWriter& xmlWriter) const { writeCiftiXML1(xmlWriter); } void GiftiMetaData::readCiftiXML1(QXmlStreamReader& xml) { clear(false); while (!xml.atEnd())//don't check the current element's name { xml.readNext(); if (xml.isStartElement()) { QStringRef name = xml.name(); if (name == GiftiXmlElements::TAG_METADATA_ENTRY) { readEntry(xml); } else { xml.raiseError("unexpected tag name in " + GiftiXmlElements::TAG_METADATA + ": " + name.toString()); } } else if (xml.isEndElement()) { break; } } } void GiftiMetaData::readCiftiXML2(QXmlStreamReader& xml) { readCiftiXML1(xml); } void GiftiMetaData::readBorderFileXML1(QXmlStreamReader& xml) { readCiftiXML1(xml); } void GiftiMetaData::readBorderFileXML3(QXmlStreamReader& xml) { readCiftiXML1(xml); } void GiftiMetaData::readSceneFile3(QXmlStreamReader& xml) { readCiftiXML1(xml); } void GiftiMetaData::readEntry(QXmlStreamReader& xml) { AString key, value; bool haveKey = false, haveValue = false; while (!xml.atEnd())//don't check the current element's name { xml.readNext(); if (xml.isStartElement()) { QStringRef name = xml.name(); if (name == GiftiXmlElements::TAG_METADATA_NAME) { if (haveKey) throw GiftiException("MD element has multiple Name elements"); key = xml.readElementText(); haveKey = true; } else if (name == GiftiXmlElements::TAG_METADATA_VALUE) { if (haveValue) throw GiftiException("MD element has multiple Value elements"); value = xml.readElementText(); haveValue = true; } else { xml.raiseError("unexpected tag name in " + GiftiXmlElements::TAG_METADATA_ENTRY + ": " + name.toString()); } } else if (xml.isEndElement()) { if (haveKey && haveValue) { if (exists(key)) { xml.raiseError("key '" + key + "' used more than once in " + GiftiXmlElements::TAG_METADATA); } else { set(key, value); } } else { if (haveKey) { xml.raiseError(GiftiXmlElements::TAG_METADATA_ENTRY + " element has no " + GiftiXmlElements::TAG_METADATA_VALUE + " element"); } else { if (haveValue) { xml.raiseError(GiftiXmlElements::TAG_METADATA_ENTRY + " element has no " + GiftiXmlElements::TAG_METADATA_NAME + " element"); } else { xml.raiseError(GiftiXmlElements::TAG_METADATA_ENTRY + " element has no " + GiftiXmlElements::TAG_METADATA_NAME + " or " + GiftiXmlElements::TAG_METADATA_VALUE + " element"); } } } break; } } CaretAssert(xml.hasError() || (xml.isEndElement() && xml.name() == "MD")); } /** * Set this object has been modified. * */ void GiftiMetaData::setModified() { this->modifiedFlag = true; } /** * Set this object as not modified. Object should also * clear the modification status of its children. * */ void GiftiMetaData::clearModified() { this->modifiedFlag = false; } /** * Get the modification status. Returns true if this object or * any of its children have been modified. * @return - The modification status. * */ bool GiftiMetaData::isModified() const { return this->modifiedFlag; } /** * Is the metadata empty (no metadata)? */ bool GiftiMetaData::isEmpty() const { return this->metadata.empty(); } /** * @return Number of metadata */ int32_t GiftiMetaData::getNumberOfMetaData() const { return this->metadata.size(); } connectome-workbench-1.4.2/src/FilesBase/GiftiMetaData.h000066400000000000000000000102221360521144700230700ustar00rootroot00000000000000#ifndef __GIFTIMETADATA_H__ #define __GIFTIMETADATA_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "GiftiException.h" #include "TracksModificationInterface.h" #include #include #include #include class QXmlStreamReader; class QXmlStreamWriter; namespace caret { class XmlWriter; /** * Maintains GIFTI metadata using name/value pairs. A * metadata object may be associated with the GIFTI * data file and with each GIFTI data array. */ class GiftiMetaData : public CaretObject, TracksModificationInterface { public: GiftiMetaData(); public: GiftiMetaData(const GiftiMetaData& o); GiftiMetaData& operator=(const GiftiMetaData& o); bool operator==(const GiftiMetaData& rhs) const; bool operator!=(const GiftiMetaData& rhs) const { return !((*this) == rhs); } virtual ~GiftiMetaData(); private: void copyHelper(const GiftiMetaData& o); void initializeMembersGiftiMetaData(); public: AString getUniqueID() const; //void removeUniqueID(); void clear(bool keepUUID = true); void append(const GiftiMetaData& smd); void replace(const GiftiMetaData& smd); void set( const AString& name, const AString& value); void setInt( const AString& name, const int32_t value); void setFloat( const AString& name, const float value); void replaceWithMap(const std::map& map); std::map getAsMap() const; void remove(const AString& name); bool exists(const AString& name) const; AString get(const AString& name) const; int32_t getInt(const AString& name) const; float getFloat(const AString& name) const; std::vector getAllMetaDataNames() const; void updateFromCaret5Names(); AString toString() const; AString toFormattedString(const AString& indentation); void writeAsXML(XmlWriter& xmlWriter); void writeCiftiXML1(QXmlStreamWriter& xmlWriter) const; void writeCiftiXML2(QXmlStreamWriter& xmlWriter) const;//extra names for code style, and in case it changes in a future version void writeBorderFileXML3(QXmlStreamWriter& xmlWriter) const; void readCiftiXML1(QXmlStreamReader& xml); void readCiftiXML2(QXmlStreamReader& xml); void readBorderFileXML1(QXmlStreamReader& xml); void readBorderFileXML3(QXmlStreamReader& xml); void readSceneFile3(QXmlStreamReader& xml); void writeSceneFile3(QXmlStreamWriter& xmlWriter) const; void setModified(); void clearModified(); bool isModified() const; void resetUniqueIdentifier(); bool isEmpty() const; int32_t getNumberOfMetaData() const; private: void readEntry(QXmlStreamReader& xml); std::map createTreeMap(); void replaceName( const AString& oldName, const AString& newName); public: private: /**the metadata storage. */ mutable std::map metadata; typedef std::map::iterator MetaDataIterator; typedef std::map::const_iterator MetaDataConstIterator; /**has the metadata been modified */ bool modifiedFlag; }; } // namespace #endif // __GIFTIMETADATA_H__ connectome-workbench-1.4.2/src/FilesBase/GiftiMetaDataXmlElements.h000066400000000000000000000212411360521144700252510ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ namespace caret { namespace GiftiMetaDataXmlElements { /** metadata name for primary anatomical structure found in NIFTI_INTENT_POINTSET data arrays. */ static const AString METADATA_NAME_ANATOMICAL_STRUCTURE_PRIMARY = "AnatomicalStructurePrimary"; /** metadata value for NIFTI_INTENT_POINTSET primary anatomical structure representing the left cerebral cortex. */ static const AString METADATA_NAME_ANATOMICAL_STRUCTURE_PRIMARY_VALUE_CORTEX_LEFT = "CortexLeft"; /** metadata value for NIFTI_INTENT_POINTSET primary anatomical structure representing the right cerebral cortex. */ static const AString METADATA_NAME_ANATOMICAL_STRUCTURE_PRIMARY_VALUE_CORTEX_RIGHT = "CortexRight"; /** metadata value for NIFTI_INTENT_POINTSET primary anatomical structure representing the both left and right cerebral cortex. */ static const AString METADATA_NAME_ANATOMICAL_STRUCTURE_PRIMARY_VALUE_CORTEX_BOTH = "CortexRightAndLeft"; /** metadata value for NIFTI_INTENT_POINTSET primary anatomical structure representing the cerebellum. */ static const AString METADATA_NAME_ANATOMICAL_STRUCTURE_PRIMARY_VALUE_CEREBELLUM = "Cerebellum"; /** metadata value for NIFTI_INTENT_POINTSET primary anatomical structure representing the head. */ static const AString METADATA_NAME_ANATOMICAL_STRUCTURE_PRIMARY_VALUE_HEAD = "Head"; /** metadata value for NIFTI_INTENT_POINTSET primary anatomical structure representing the left hippocampus. */ static const AString METADATA_NAME_ANATOMICAL_STRUCTURE_PRIMARY_VALUE_HIPPOCAMPUS_LEFT = "HippocampusLeft"; /** metadata value for NIFTI_INTENT_POINTSET primary anatomical structure representing the right hippocampus. */ static const AString METADATA_NAME_ANATOMICAL_STRUCTURE_PRIMARY_VALUE_HIPPOCAMPUS_RIGHT = "HippocampusRight"; /** metadata name for for secondary anatomical structure found in NIFTI_INTENT_POINTSET data arrays. */ static const AString METADATA_NAME_ANATOMICAL_STRUCTURE_SECONDARY = "AnatomicalStructureSecondary"; /** metadata value for NIFTI_INTENT_POINTSET secondary anatomical structure representing the gray and white boundary. */ static const AString METADATA_NAME_ANATOMICAL_STRUCTURE_SECONDARY_VALUE_GRAY_WHITE = "GrayWhite"; /** metadata value for NIFTI_INTENT_POINTSET secondary anatomical structure representing the pial (gray/CSF boundary). */ static const AString METADATA_NAME_ANATOMICAL_STRUCTURE_SECONDARY_VALUE_PIAL = "Pial"; /** metadata value for NIFTI_INTENT_POINTSET secondary anatomical structure representing the mid thickness (layer 4). */ static const AString METADATA_NAME_ANATOMICAL_STRUCTURE_SECONDARY_VALUE_ = "MidThickness"; /** metadata name found in the file's metadata and indicates the date and time the file was written. */ static const AString METADATA_NAME_DATE = "Date"; /** metadata name found in any metadata and provides a description of the entity's content. */ static const AString METADATA_NAME_DESCRIPTION = "Description"; static const AString METADATA_NAME_COMMENT = "Comment"; /** metadata name for geometric type found in NIFTI_INTENT_POINTSET data arrays. */ static const AString METADATA_NAME_GEOMETRIC_TYPE = "GeometricType"; /** metadata value for NIFTI_INTENT_POINTSET's Geometric Type Reconstruction with a "blocky" appearance. */ static const AString METADATA_NAME_GEOMETRIC_TYPE_VALUE_RECONSTRUCTION = "Reconstruction"; /** metadata value for NIFTI_INTENT_POINTSET's Geometric Type representing true anatomical structure. */ static const AString METADATA_NAME_GEOMETRIC_TYPE_VALUE_ANATOMICAL = "Anatomical"; /** metadata value for NIFTI_INTENT_POINTSET's Geometric Type for inflated surface. */ static const AString METADATA_NAME_GEOMETRIC_TYPE_VALUE_INFLATED = "Inflated"; /** metadata value for NIFTI_INTENT_POINTSET's Geometric Type for very inflated surface. */ static const AString METADATA_NAME_GEOMETRIC_TYPE_VALUE_VERY_INFLATED = "VeryInflated"; /** metadata value for NIFTI_INTENT_POINTSET's Geometric Type spherical surface. */ static const AString METADATA_NAME_GEOMETRIC_TYPE_VALUE_SPHERICAL = "Spherical"; /** metadata value for NIFTI_INTENT_POINTSET's Geometric Type semi-spherical surface with one half flattened. */ static const AString METADATA_NAME_GEOMETRIC_TYPE_VALUE_SEMI_SPHERICAL = "SemiSpherical"; /** metadata value for NIFTI_INTENT_POINTSET's Geometric Type ellipsoid surface. */ static const AString METADATA_NAME_GEOMETRIC_TYPE_VALUE_ELLIPSOID = "Ellipsoid"; /** metadata value for NIFTI_INTENT_POINTSET's Geometric Type flat surface. */ static const AString METADATA_NAME_GEOMETRIC_TYPE_VALUE_FLAT = "Flat"; /** metadata value for NIFTI_INTENT_POINTSET's Geometric Type hull surface (eg: wrapping around cortex with sulci filled but not necessarily convex). */ static const AString METADATA_NAME_GEOMETRIC_TYPE_VALUE_HULL = "Hull"; /**metadata name for NIFTI Intent label found in functional data arrays. */ static const AString METADATA_NAME_INTENT_CODE = "Intent_code"; /**metadata name for NIFTI Intent parameter one in functional data arrays.*/ static const AString METADATA_NAME_INTENT_P1 = "intent_p1"; /**metadata name for NIFTI Intent parameter two in functional data arrays.*/ static const AString METADATA_NAME_INTENT_P2 = "intent_p2"; /**metadata name for NIFTI Intent parameter three in functional data arrays.*/ static const AString METADATA_NAME_INTENT_P3 = "intent_p3"; /**metadata name for name of data, often displayed in the user-interface. */ static const AString METADATA_NAME_NAME = "Name"; /**metadata name for text that identifies a subjet. */ static const AString METADATA_NAME_SUBJECT_ID = "SubjectID"; /**metadata name for text that uniquely defines a surface. */ static const AString METADATA_NAME_SURFACE_ID = "SurfaceID"; /**metadata name for time step (TR) in NIFTI_INTENT_TIME_SERIES arrays. */ static const AString METADATA_NAME_TIME_STEP = "TimeStep"; /**metadata name for topological type in NIFTI_INTENT_TRIANGLE arrays. */ static const AString METADATA_NAME_TOPOLOGICAL_TYPE = "TopologicalType"; /** metadata value for NIFTI_INTENT_TRIANGLE's Topological Type for closed topology. */ static const AString METADATA_NAME_TOPOLOGICAL_TYPE_VALUE_CLOSED = "Closed"; /** metadata value for NIFTI_INTENT_TRIANGLE's Topological Type for open topology (perhaps medial wall removed). */ static const AString METADATA_NAME_TOPOLOGICAL_TYPE_VALUE_OPEN = "Open"; /** metadata value for NIFTI_INTENT_TRIANGLE's Topological Type for cut topology (typically used with flat surfaces with medial wall removed and cuts made to reduce distortion. */ static const AString METADATA_NAME_TOPOLOGICAL_TYPE_VALUE_CUT = "Cut"; /** metadata name for a unique identifiers for the data array. This ID is best generated using a Universal Unique Identifier function such as Java's java.util.uuid or C's uuid_generate(). @see UUID */ static const AString METADATA_NAME_UNIQUE_ID = "UniqueID"; /**metadata name for username of user that wrote the file in file metadata.*/ static const AString METADATA_NAME_USER_NAME = "UserName"; /**name of study metadata link set metadata */ static const AString METADATA_NAME_STUDY_METADATA_LINK_SET = "StudyMetaDataLinkSet"; /**name of palette color mapping stored in metadata */ static const AString METADATA_NAME_PALETTE_COLOR_MAPPING = "PaletteColorMapping"; /** name of palette normalization mode */ static const AString METADATA_PALETTE_NORMALIZATION_MODE = "PaletteNormalizationMode"; /** name of histogram number of buckets */ static const AString HISTOGRAM_NUMBER_OF_BUCKETS = "HistogramNumberOfBuckets"; } // namespace } // namespace connectome-workbench-1.4.2/src/FilesBase/GiftiXmlElements.cxx000066400000000000000000000023471360521144700242310ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "GiftiXmlElements.h" using namespace caret; /** * Get an attribute dimension (Dim0, Dim1, etc). * @param Index value for dimension. * @return Dim0, Dim1, etc */ AString GiftiXmlElements::getAttributeDimension(int32_t dimIndex) { std::ostringstream str; str << GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_DIM_PREFIX.toStdString() << dimIndex; return AString::fromStdString(str.str()); } connectome-workbench-1.4.2/src/FilesBase/GiftiXmlElements.h000066400000000000000000000165221360521144700236560ustar00rootroot00000000000000#ifndef __GIFTIXMLELEMENTS_H__ #define __GIFTIXMLELEMENTS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include namespace caret { /** * GIFTI XML Element tags */ namespace GiftiXmlElements { /** tag for coordinate transformation matrix element */ static const AString TAG_COORDINATE_TRANSFORMATION_MATRIX = "CoordinateSystemTransformMatrix"; /** tag for data element */ static const AString TAG_DATA = "Data"; /** tag for data array element */ static const AString TAG_DATA_ARRAY = "DataArray"; /** tag for coordinate transformation data space element */ static const AString TAG_MATRIX_DATA_SPACE = "DataSpace"; /** tag for GIFTI element */ static const AString TAG_GIFTI = "GIFTI"; /** tag for label element */ static const AString TAG_LABEL = "Label"; /** tag for label table element */ static const AString TAG_LABEL_TABLE = "LabelTable"; /** tag for a metadata entry */ static const AString TAG_METADATA_ENTRY = "MD"; /** tag for matrix data */ static const AString TAG_MATRIX_DATA = "MatrixData"; /** tag for metadata */ static const AString TAG_METADATA = "MetaData"; /** tag for metadata name */ static const AString TAG_METADATA_NAME = "Name"; /** tag for coordinate transformation space element */ static const AString TAG_MATRIX_TRANSFORMED_SPACE = "TransformedSpace"; /** tag for metadata value element */ static const AString TAG_METADATA_VALUE = "Value"; /** attribute for data array indexing order */ static const AString ATTRIBUTE_DATA_ARRAY_INDEXING_ORDER = "ArrayIndexingOrder"; /** attribute for data array data type */ static const AString ATTRIBUTE_DATA_ARRAY_DATA_TYPE = "DataType"; /** attribute for data array dimensionality */ static const AString ATTRIBUTE_DATA_ARRAY_DIMENSIONALITY = "Dimensionality"; /** attribute for data array dimensionality */ static const AString ATTRIBUTE_DATA_ARRAY_DIM_PREFIX = "Dim"; /** attribute for data array encoding */ static const AString ATTRIBUTE_DATA_ARRAY_ENCODING = "Encoding"; /** attribute for data array ending */ static const AString ATTRIBUTE_DATA_ARRAY_ENDIAN = "Endian"; /** attribute for data array external file name */ static const AString ATTRIBUTE_DATA_ARRAY_EXTERNAL_FILE_NAME = "ExternalFileName"; /** attribute for data array external file offset */ static const AString ATTRIBUTE_DATA_ARRAY_EXTERNAL_FILE_OFFSET = "ExternalFileOffset"; /** attribute for data array label index REPLACED BY KEY*/ static const AString ATTRIBUTE_LABEL_INDEX_obsolete = "Index"; /** attribute for data array label key */ static const AString ATTRIBUTE_LABEL_KEY = "Key"; /** attribute for data array label red color component */ static const AString ATTRIBUTE_LABEL_RED = "Red"; /** attribute for data array label green color component */ static const AString ATTRIBUTE_LABEL_GREEN = "Green"; /** attribute for data array label blue color component */ static const AString ATTRIBUTE_LABEL_BLUE = "Blue"; /** attribute for data array label alpha color component */ static const AString ATTRIBUTE_LABEL_ALPHA = "Alpha"; /** attribute for data array label X-coordinate */ static const AString ATTRIBUTE_LABEL_X = "X"; /** attribute for data array label X-coordinate */ static const AString ATTRIBUTE_LABEL_Y = "Y"; /** attribute for data array label X-coordinate */ static const AString ATTRIBUTE_LABEL_Z = "Z"; /** attribute for data array intent */ static const AString ATTRIBUTE_DATA_ARRAY_INTENT = "Intent"; /** attribute for data array intent parameter 1 */ static const AString ATTRIBUTE_DATA_ARRAY_INTENT_P1 = "intent_p1"; /** attribute for data array intent parameter 2 */ static const AString ATTRIBUTE_DATA_ARRAY_INTENT_P2 = "intent_p2"; /** attribute for data array intent parameter 3 */ static const AString ATTRIBUTE_DATA_ARRAY_INTENT_P3 = "intent_p3"; /** attribute for GIFTI Number of Data Arrays */ static const AString ATTRIBUTE_GIFTI_NUMBER_OF_DATA_ARRAYS = "NumberOfDataArrays"; /** attribute for GIFTI Version */ static const AString ATTRIBUTE_GIFTI_VERSION = "Version"; AString getAttributeDimension(int32_t dimIndex); /** * Get an attribute dimension (Dim0, Dim1, etc). * @param Index value for dimension. * @return Dim0, Dim1, etc * static AString getAttributeDimension(int32_t dimIndex) { std::ostringstream str; str << ATTRIBUTE_DATA_ARRAY_DIM_PREFIX << dimIndex;; return str.str(); } */ /* static const AString tagGIFTI = "GIFTI"; static const AString tagMetaData = "MetaData"; static const AString tagMD = "MD"; static const AString tagName = "Name"; static const AString tagValue = "Value"; static const AString tagDataArray = "DataArray"; static const AString tagData = "Data"; static const AString tagLabelTable = "LabelTable"; static const AString tagLabel = "Labe"; static const AString tagMatrix = "CoordinateSystemTransformMatrix"; static const AString tagMatrixDataSpace = "DataSpace"; static const AString tagMatrixTransformedSpace = "TransformedSpace"; static const AString tagMatrixData = "MatrixData"; static const AString attVersion = "Version"; static const AString attNumberOfDataArrays = "NumberOfDataArrays"; static const AString attArraySubscriptingOrder = "ArrayIndexingOrder"; static const AString attKey = "Key"; static const AString attRed = "Red"; static const AString attGreen = "Green"; static const AString attBlue = "Blue"; static const AString attAlpha = "Alpha"; static const AString attIntent = "Intent"; static const AString attDataType = "DataType"; static const AString attDimensionality = "Dimensionality"; static const AString attDim = "Dim"; static const AString attEncoding = "Encoding"; static const AString attEndian = "Endian"; static const AString attExternalFileName = "ExternalFileName"; static const AString attExternalFileOffset = "ExternalFileOffset"; */ }; // namespace } // namespace #endif // __GIFTIXMLELEMENTS_H__ connectome-workbench-1.4.2/src/FilesBase/NiftiEnums.cxx000066400000000000000000001031011360521144700230600ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __NIFTI_ENUMS_DECLARE__ #include "NiftiEnums.h" #undef __NIFTI_ENUMS_DECLARE__ using namespace caret; ///Nifti Data Type Enum NiftiDataTypeEnum::NiftiDataTypeEnum() { } NiftiDataTypeEnum::NiftiDataTypeEnum(Enum e, const AString& name, const int32_t integerCode) { this->e = e; this->name = name; this->integerCode = integerCode; } NiftiDataTypeEnum::~NiftiDataTypeEnum() { } void NiftiDataTypeEnum::createDataTypes() { if (dataTypesCreatedFlag) { return; } dataTypesCreatedFlag = true; dataTypes.push_back(NiftiDataTypeEnum(NIFTI_TYPE_INVALID, "NIFTI_DATA_TYPE_NONE", 0)); dataTypes.push_back(NiftiDataTypeEnum(NIFTI_TYPE_UINT8, "NIFTI_TYPE_UINT8", 2)); dataTypes.push_back(NiftiDataTypeEnum(NIFTI_TYPE_INT16, "NIFTI_TYPE_INT16", 4)); dataTypes.push_back(NiftiDataTypeEnum(NIFTI_TYPE_INT32, "NIFTI_TYPE_INT32", 8)); dataTypes.push_back(NiftiDataTypeEnum(NIFTI_TYPE_FLOAT32, "NIFTI_TYPE_FLOAT32", 16)); dataTypes.push_back(NiftiDataTypeEnum(NIFTI_TYPE_COMPLEX64, "NIFTI_TYPE_COMPLEX64", 32)); dataTypes.push_back(NiftiDataTypeEnum(NIFTI_TYPE_FLOAT64, "NIFTI_TYPE_FLOAT64", 64)); dataTypes.push_back(NiftiDataTypeEnum(NIFTI_TYPE_RGB24, "NIFTI_TYPE_RGB24", 128)); dataTypes.push_back(NiftiDataTypeEnum(NIFTI_TYPE_INT8, "NIFTI_TYPE_INT8", 256)); dataTypes.push_back(NiftiDataTypeEnum(NIFTI_TYPE_UINT16, "NIFTI_TYPE_UINT16", 512)); dataTypes.push_back(NiftiDataTypeEnum(NIFTI_TYPE_UINT32, "NIFTI_TYPE_UINT32", 768)); dataTypes.push_back(NiftiDataTypeEnum(NIFTI_TYPE_INT64, "NIFTI_TYPE_INT64", 1024)); dataTypes.push_back(NiftiDataTypeEnum(NIFTI_TYPE_UINT64, "NIFTI_TYPE_UINT64", 1280)); dataTypes.push_back(NiftiDataTypeEnum(NIFTI_TYPE_FLOAT128, "NIFTI_TYPE_FLOAT128", 1792)); dataTypes.push_back(NiftiDataTypeEnum(NIFTI_TYPE_COMPLEX128, "NIFTI_TYPE_COMPLEX128", 1792)); dataTypes.push_back(NiftiDataTypeEnum(NIFTI_TYPE_COMPLEX256, "NIFTI_TYPE_COMPLEX256", 2048)); } /** * Get a string representition of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString NiftiDataTypeEnum::toName(Enum e) { createDataTypes(); const NiftiDataTypeEnum* ndt = findData(e); return ndt->name; } /** * Get an enumerated value corresponding to its name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ NiftiDataTypeEnum::Enum NiftiDataTypeEnum::fromName(const AString& s, bool* isValidOut) { createDataTypes(); bool validFlag = false; Enum e = NIFTI_TYPE_FLOAT32; for (std::vector::iterator iter = dataTypes.begin(); iter != dataTypes.end(); iter++) { const NiftiDataTypeEnum& ndt = *iter; if (ndt.name == s) { e = ndt.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } /** * Find the Data Type using the enum. * * @return * Object using enum or NULL if not found. */ const NiftiDataTypeEnum* NiftiDataTypeEnum::findData(Enum e) { createDataTypes(); for (std::vector::iterator iter = dataTypes.begin(); iter != dataTypes.end(); iter++) { const NiftiDataTypeEnum& ndt = *iter; if (ndt.e == e) { return &ndt; } } return NULL; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t NiftiDataTypeEnum::toIntegerCode(Enum e) { createDataTypes(); const NiftiDataTypeEnum* ndt = findData(e); return ndt->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ NiftiDataTypeEnum::Enum NiftiDataTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { createDataTypes(); bool validFlag = false; Enum e = NIFTI_TYPE_INVALID; for (std::vector::iterator iter = dataTypes.begin(); iter != dataTypes.end(); iter++) { const NiftiDataTypeEnum& ndt = *iter; if (ndt.integerCode == integerCode) { e = ndt.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } ///Nifti Intent Enum NiftiIntentEnum::NiftiIntentEnum(Enum e, const AString& enumName, const int32_t integerCode, const AString& name, const AString& p1Name, const AString& p2Name, const AString& p3Name) { this->e = e; this->enumName = enumName; this->integerCode = integerCode; this->name = name; this->p1Name = p1Name; this->p2Name = p2Name; this->p3Name = p3Name; } //NiftiIntentEnum::NiftiIntentEnum() //{ // //} NiftiIntentEnum::~NiftiIntentEnum() { } void NiftiIntentEnum::initializeIntents() { if (intentsCreatedFlag) { return; } intentsCreatedFlag = true; //intents.push_back( // NiftiIntentEnum()); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_NONE,"NIFTI_INTENT_NONE", 0,"None","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_CORREL,"NIFTI_INTENT_CORREL", 2,"Correlation Statistic","DOF","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_TTEST,"NIFTI_INTENT_TTEST", 3,"T-Statistic","DOF","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_FTEST,"NIFTI_INTENT_FTEST", 4,"F-Statistic","Numberator DOF","Denominator DOF","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_ZSCORE,"NIFTI_INTENT_ZSCORE", 5,"Z-Score","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_CHISQ,"NIFTI_INTENT_CHISQ", 6,"Chi-Squared Distribution","DOF","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_BETA,"NIFTI_INTENT_BETA", 7,"Beta Distribution","a","b","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_BINOM,"NIFTI_INTENT_BINOM", 8,"Binomial Distribution", "Number of Trials","Probability per Trial","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_GAMMA,"NIFTI_INTENT_GAMMA", 9,"Gamma Distribution","Shape","Scale","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_POISSON,"NIFTI_INTENT_POISSON", 10,"Poisson Distribution","Mean","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_NORMAL,"NIFTI_INTENT_NORMAL", 11,"Normal Distribution","Mean","Standard Deviation","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_FTEST_NONC,"NIFTI_INTENT_FTEST_NONC", 12,"F-Statistic Non-Central", "Numerator DOF", "Denominator DOF", "Numerator Noncentrality Parameter")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_CHISQ_NONC,"NIFTI_INTENT_CHISQ_NONC", 13,"Chi-Squared Non-Central", "DOF", "Noncentrality Parameter","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_LOGISTIC,"NIFTI_INTENT_LOGISTIC", 14,"Logistic Distribution","Location","Scale","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_LAPLACE,"NIFTI_INTENT_LAPLACE", 15,"Laplace Distribution","Location","Scale","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_UNIFORM,"NIFTI_INTENT_UNIFORM", 16,"Uniform Distribution","Lower End","Upper End","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_TTEST_NONC,"NIFTI_INTENT_TTEST_NONC", 17,"T-Statistic Non-Central", "DOF", "Noncentrality Parameter","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_WEIBULL,"NIFTI_INTENT_WEIBULL", 18,"Weibull Distribution","Location","Scale","Power")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_CHI,"NIFTI_INTENT_CHI", 19,"Chi Distribution", "Half Normal Distribution", "Rayleigh Distribution", "Maxwell-Boltzmann Distribution")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_INVGAUSS,"NIFTI_INTENT_INVGAUSS", 20,"Inverse Gaussian Distribution", "MU", "Lambda","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_EXTVAL,"NIFTI_INTENT_EXTVAL", 21,"Extreme Value Distribution", "Location", "Scale","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_PVAL,"NIFTI_INTENT_PVAL", 22,"P-Value","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_LOGPVAL,"NIFTI_INTENT_LOGPVAL", 23,"Log P-Value","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_LOG10PVAL,"NIFTI_INTENT_LOG10PVAL", 24,"Logn10 P-Value","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_ESTIMATE,"NIFTI_INTENT_ESTIMATE", 1001,"Estimate","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_LABEL,"NIFTI_INTENT_LABEL", 1002,"Label Indices","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_NEURONAME,"NIFTI_INTENT_NEURONAME", 1003,"Neuronames Indices","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_GENMATRIX,"NIFTI_INTENT_GENMATRIX", 1004,"General Matrix","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_SYMMATRIX,"NIFTI_INTENT_SYMMATRIX", 1005,"Symmetric Matrix","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_DISPVECT,"NIFTI_INTENT_DISPVECT", 1006,"Displacement Vector","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_VECTOR,"NIFTI_INTENT_VECTOR", 1007,"Vector","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_POINTSET,"NIFTI_INTENT_POINTSET", 1008,"Point Set","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_TRIANGLE,"NIFTI_INTENT_TRIANGLE", 1009,"Triangle","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_QUATERNION,"NIFTI_INTENT_QUATERNION", 1010,"Quaternion","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_DIMLESS,"NIFTI_INTENT_DIMLESS", 1011,"Dimensionless Number","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_TIME_SERIES,"NIFTI_INTENT_TIME_SERIES", 2001,"Time Series","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_NODE_INDEX,"NIFTI_INTENT_NODE_INDEX", 2002,"Node Index","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_RGB_VECTOR,"NIFTI_INTENT_RGB_VECTOR", 2003,"RGB","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_RGBA_VECTOR,"NIFTI_INTENT_RGBA_VECTOR", 2004,"RGBA","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_SHAPE,"NIFTI_INTENT_SHAPE", 2005,"Shape","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_CARET_DEFORMATION_NODE_INDICES,"NIFTI_INTENT_CARET_DEFORMATION_NODE_INDICES", 25000,"Deformation Node Indices","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_CARET_DEFORMATION_NODE_AREAS,"NIFTI_INTENT_CARET_DEFORMATION_NODE_AREAS", 25001,"Deformation Node Areas","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_CONNECTIVITY_DENSE,"NIFTI_INTENT_CONNECTIVITY_DENSE", 3001,"Connectivity - Dense","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_CONNECTIVITY_DENSE_TIME,"NIFTI_INTENT_CONNECTIVITY_DENSE_TIME", 3002,"Connectivity - Dense Time Series","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_CONNECTIVITY_PARCELLATED,"NIFTI_INTENT_CONNECTIVITY_PARCELLATED", 3003,"Connectivity - Parcellated","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_CONNECTIVITY_PARCELLATED_TIME,"NIFTI_INTENT_CONNECTIVITY_PARCELLATED_TIME", 3004,"Connectivity - Parcellated Time Series","","","")); intents.push_back(NiftiIntentEnum(NIFTI_INTENT_CONNECTIVITY_TRAJECTORY,"NIFTI_INTENT_CONNECTIVITY_TRAJECTORY", 3005,"Connectivity - Trajectory","","","")); } /** * Get a string representition of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString NiftiIntentEnum::toName(Enum e) { initializeIntents(); const NiftiIntentEnum* ni = findData(e); return ni->enumName; } /** * Get an enumerated value corresponding to its name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ NiftiIntentEnum::Enum NiftiIntentEnum::fromName(const AString& s, bool* isValidOut) { initializeIntents(); bool validFlag = false; Enum e = NIFTI_INTENT_NONE; for (std::vector::const_iterator iter = intents.begin(); iter != intents.end(); iter++) { const NiftiIntentEnum& intent = *iter; if (intent.enumName == s) { e = intent.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } /** * Find the Intent object corresponding to the enum. * @param e * The enum * @return * The Intent or NULL if enum does not match an intent. */ const NiftiIntentEnum* NiftiIntentEnum::findData(Enum e) { initializeIntents(); for (std::vector::const_iterator iter = intents.begin(); iter != intents.end(); iter++) { const NiftiIntentEnum& intent = *iter; if (intent.e == e) { return &intent; } } CaretAssertMessage(0, "Intent enum failed to match."); return NULL; } /** * Get the "P1" name associated with an intent. * @param e * The enum. * @return * P1 name associated with intent (may be empty string). */ AString NiftiIntentEnum::toNameP1(Enum e) { initializeIntents(); const NiftiIntentEnum* ni = findData(e); return ni->p1Name; } /** * Get the "P2" name associated with an intent. * @param e * The enum. * @return * P2 name associated with intent (may be empty string). */ AString NiftiIntentEnum::toNameP2(Enum e) { initializeIntents(); const NiftiIntentEnum* ni = findData(e); return ni->p2Name; } /** * Get the "P3" name associated with an intent. * @param e * The enum. * @return * P3 name associated with intent (may be empty string). */ AString NiftiIntentEnum::toNameP3(Enum e) { initializeIntents(); const NiftiIntentEnum* ni = findData(e); return ni->p3Name; } /** * Get the integer code associated with an intent. * @param e * The enum. * @return * Integer code associated with intent. */ int32_t NiftiIntentEnum::toIntegerCode(Enum e) { initializeIntents(); const NiftiIntentEnum* ni = findData(e); return ni->integerCode; } /** * Find enum corresponding to integer code. * @param integerCode * The integer code. * @param isValidOut * If not NULL, on exit it indicates valid integer code. * @return * Enum corresponding to integer code. */ NiftiIntentEnum::Enum NiftiIntentEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { initializeIntents(); bool validFlag = false; Enum e = NIFTI_INTENT_NONE; for (std::vector::const_iterator iter = intents.begin(); iter != intents.end(); iter++) { const NiftiIntentEnum& intent = *iter; if (intent.integerCode == integerCode) { e = intent.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } ///Nifti Spacing Units Enum NiftiSpacingUnitsEnum::NiftiSpacingUnitsEnum(Enum e, const int32_t integerCode, const AString& name) { this->e = e; this->integerCode = integerCode; this->name = name; } NiftiSpacingUnitsEnum::~NiftiSpacingUnitsEnum() { } void NiftiSpacingUnitsEnum::initializeSpacingUnits() { if (initializedFlag) { return; } initializedFlag = true; spacingUnits.push_back(NiftiSpacingUnitsEnum(NIFTI_UNITS_UNKNOWN, 0, "NIFTI_UNITS_UNKNOWN")); spacingUnits.push_back(NiftiSpacingUnitsEnum(NIFTI_UNITS_METER, 1, "NIFTI_UNITS_METER")); spacingUnits.push_back(NiftiSpacingUnitsEnum(NIFTI_UNITS_MM, 2, "NIFTI_UNITS_MM")); spacingUnits.push_back(NiftiSpacingUnitsEnum(NIFTI_UNITS_MICRON, 3, "NIFTI_UNITS_MICRON")); } /** * Get a string representition of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString NiftiSpacingUnitsEnum::toName(Enum e) { initializeSpacingUnits(); const NiftiSpacingUnitsEnum* nsu = findData(e); return nsu->name; } /** * Get an enumerated value corresponding to its name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ NiftiSpacingUnitsEnum::Enum NiftiSpacingUnitsEnum::fromName(const AString& s, bool* isValidOut) { initializeSpacingUnits(); bool validFlag = false; Enum e = NIFTI_UNITS_UNKNOWN; for (std::vector::iterator iter = spacingUnits.begin(); iter != spacingUnits.end(); iter++) { const NiftiSpacingUnitsEnum& ndt = *iter; if (ndt.name == s) { e = ndt.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } /** * Find the Intent object corresponding to the enum. * @param e * The enum * @return * The Intent or NULL if enum does not match an intent. */ const NiftiSpacingUnitsEnum* NiftiSpacingUnitsEnum::findData(Enum e) { initializeSpacingUnits(); for (std::vector::const_iterator iter = spacingUnits.begin(); iter != spacingUnits.end(); iter++) { const NiftiSpacingUnitsEnum& nsu = *iter; if (nsu.e == e) { return &nsu; } return &nsu; } CaretAssertMessage(0, "Spacing Units enum failed to match."); return NULL; } /** * Get the integer code associated with an spacing units. * @param e * The enum. * @return * Integer code associated with spacing units. */ int32_t NiftiSpacingUnitsEnum::toIntegerCode(Enum e) { initializeSpacingUnits(); const NiftiSpacingUnitsEnum* nsu = findData(e); return nsu->integerCode; } /** * Find enum corresponding to integer code. * @param integerCode * The integer code. * @param isValidOut * If not NULL, on exit it indicates valid integer code. * @return * Enum corresponding to integer code. */ NiftiSpacingUnitsEnum::Enum NiftiSpacingUnitsEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { initializeSpacingUnits(); bool validFlag = false; Enum e = NIFTI_UNITS_UNKNOWN; for (std::vector::const_iterator iter = spacingUnits.begin(); iter != spacingUnits.end(); iter++) { const NiftiSpacingUnitsEnum& nsu = *iter; if (nsu.integerCode == integerCode) { e = nsu.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } ///Nifti Time Units Enum /** * Constructor. * * @param e * An enumerated value. * @param name * Name of enumberated value. * @param guiName * Name in GUI of enumberated value. */ NiftiTimeUnitsEnum::NiftiTimeUnitsEnum(const Enum e, const int32_t integerCode, const AString& name, const AString& guiName) { this->e = e; this->integerCode = integerCode; this->name = name; this->guiName = guiName; } /** * Destructor. */ NiftiTimeUnitsEnum::~NiftiTimeUnitsEnum() { } void NiftiTimeUnitsEnum::initializeTimeUnits() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(NiftiTimeUnitsEnum(NIFTI_UNITS_UNKNOWN, 0,"NIFTI_UNITS_UNKNOWN","Unknown")); enumData.push_back(NiftiTimeUnitsEnum(NIFTI_UNITS_SEC, 8,"NIFTI_UNITS_SEC","Seconds")); enumData.push_back(NiftiTimeUnitsEnum(NIFTI_UNITS_MSEC, 16,"NIFTI_UNITS_MSEC","Milliseconds")); enumData.push_back(NiftiTimeUnitsEnum(NIFTI_UNITS_USEC, 24,"NIFTI_UNITS_USEC","Microseconds")); enumData.push_back(NiftiTimeUnitsEnum(NIFTI_UNITS_HZ, 32,"NIFTI_UNITS_HZ","Hertz")); enumData.push_back(NiftiTimeUnitsEnum(NIFTI_UNITS_PPM, 40,"NIFTI_UNITS_PPM","Parts Per Million")); } /** * Find the data for and enumerated value. * @param e * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const NiftiTimeUnitsEnum* NiftiTimeUnitsEnum::findData(const Enum e) { initializeTimeUnits(); int64_t num = enumData.size(); for (int64_t i = 0; i < num; i++) { const NiftiTimeUnitsEnum* d = &enumData[i]; if (d->e == e) { return d; } } CaretAssertMessage(0, "Time Units enum failed to match."); return NULL; } /** * Get a string representation of the enumerated type. * @param e * Enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * label exists for the input enum value. * @return * String representing enumerated value. */ AString NiftiTimeUnitsEnum::toName(Enum e) { initializeTimeUnits(); const NiftiTimeUnitsEnum* ntu = findData(e); return ntu->name; } /** * Get an enumerated value corresponding to its name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ NiftiTimeUnitsEnum::Enum NiftiTimeUnitsEnum::fromName(const AString& s, bool* isValidOut) { initializeTimeUnits(); bool validFlag = false; Enum e = NIFTI_UNITS_UNKNOWN; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const NiftiTimeUnitsEnum& d = *iter; if (d.name == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } /** * Get the integer code associated with an time units. * @param e * The enum. * @return * Integer code associated with time units. */ int32_t NiftiTimeUnitsEnum::toIntegerCode(Enum e) { initializeTimeUnits(); const NiftiTimeUnitsEnum* nsu = findData(e); return nsu->integerCode; } /** * Find enum corresponding to integer code. * @param integerCode * The integer code. * @param isValidOut * If not NULL, on exit it indicates valid integer code. * @return * Enum corresponding to integer code. */ NiftiTimeUnitsEnum::Enum NiftiTimeUnitsEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { initializeTimeUnits(); bool validFlag = false; Enum e = NIFTI_UNITS_UNKNOWN; for (std::vector::const_iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const NiftiTimeUnitsEnum& nsu = *iter; if (nsu.integerCode == integerCode) { e = nsu.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } /** * Get a string representation for GUI of the enumerated type. * @param e * Enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * label exists for the input enum value. * @return * String representing enumerated value for GUI. */ AString NiftiTimeUnitsEnum::toGuiName(Enum e) { initializeTimeUnits(); const NiftiTimeUnitsEnum* ntu = findData(e); return ntu->guiName; } /** * Constructor. * * @param e * An enumerated value. * @param name * Name of enumberated value. */ NiftiTransformEnum::NiftiTransformEnum( const Enum e, const int32_t integerCode, const AString& name) { this->e = e; this->integerCode = integerCode; this->name = name; } /** * Destructor. */ NiftiTransformEnum::~NiftiTransformEnum() { } void NiftiTransformEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(NiftiTransformEnum(NIFTI_XFORM_UNKNOWN, 0,"NIFTI_XFORM_UNKNOWN")); enumData.push_back(NiftiTransformEnum(NIFTI_XFORM_SCANNER_ANAT, 1,"NIFTI_XFORM_SCANNER_ANAT")); enumData.push_back(NiftiTransformEnum(NIFTI_XFORM_ALIGNED_ANAT, 2,"NIFTI_XFORM_ALIGNED_ANAT")); enumData.push_back(NiftiTransformEnum(NIFTI_XFORM_TALAIRACH, 3,"NIFTI_XFORM_TALAIRACH")); enumData.push_back(NiftiTransformEnum(NIFTI_XFORM_MNI_152, 4,"NIFTI_XFORM_MNI_152")); } /** * Find the data for and enumerated value. * @param e * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const NiftiTransformEnum* NiftiTransformEnum::findData(const Enum e) { initialize(); int64_t num = enumData.size(); for (int64_t i = 0; i < num; i++) { const NiftiTransformEnum* d = &enumData[i]; if (d->e == e) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param e * Enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * label exists for the input enum value. * @return * String representing enumerated value. */ AString NiftiTransformEnum::toName(Enum e) { initialize(); const NiftiTransformEnum* nt = findData(e); return nt->name; } /** * Get an enumerated value corresponding to its name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ NiftiTransformEnum::Enum NiftiTransformEnum::fromName(const AString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = NIFTI_XFORM_UNKNOWN; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const NiftiTransformEnum& d = *iter; if (d.name == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } /** * Get the integer code associated with a transform. * @param e * The enum. * @return * Integer code associated with a transform. */ int32_t NiftiTransformEnum::toIntegerCode(Enum e) { initialize(); const NiftiTransformEnum* nsu = findData(e); return nsu->integerCode; } /** * Find enum corresponding to integer code. * @param integerCode * The integer code. * @param isValidOut * If not NULL, on exit it indicates valid integer code. * @return * Enum corresponding to integer code. */ NiftiTransformEnum::Enum NiftiTransformEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = NIFTI_XFORM_UNKNOWN; for (std::vector::const_iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const NiftiTransformEnum& nsu = *iter; if (nsu.integerCode == integerCode) { e = nsu.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } /** * Constructor. * * @param e * An enumerated value. * @param name * Name of enumberated value. */ NiftiVersionEnum::NiftiVersionEnum( const Enum e, const int32_t integerCode, const AString& name) { this->e = e; this->integerCode = integerCode; this->name = name; } /** * Destructor. */ NiftiVersionEnum::~NiftiVersionEnum() { } void NiftiVersionEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(NiftiVersionEnum(NIFTI_VERSION_1, 348, "NIFTI_VERSION_1")); enumData.push_back(NiftiVersionEnum(NIFTI_VERSION_2, 540, "NIFTI_VERSION_2")); } /** * Find the data for and enumerated value. * @param e * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const NiftiVersionEnum* NiftiVersionEnum::findData(const Enum e) { initialize(); int64_t num = enumData.size(); for (int64_t i = 0; i < num; i++) { const NiftiVersionEnum* d = &enumData[i]; if (d->e == e) { return d; } } CaretAssertMessage(0, "NIFTI Version enum failed to match."); return NULL; } /** * Get a string representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString NiftiVersionEnum::toName(Enum e) { initialize(); const NiftiVersionEnum* nv = findData(e); return nv->name; } /** * Get an enumerated value corresponding to its name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ NiftiVersionEnum::Enum NiftiVersionEnum::fromName(const AString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = NIFTI_VERSION_1; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const NiftiVersionEnum& d = *iter; if (d.name == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } /** * Get the integer code associated with a transform. * @param e * The enum. * @return * Integer code associated with a transform. */ int32_t NiftiVersionEnum::toIntegerCode(Enum e) { initialize(); const NiftiVersionEnum* nsu = findData(e); return nsu->integerCode; } /** * Find enum corresponding to integer code. * @param integerCode * The integer code. * @param isValidOut * If not NULL, on exit it indicates valid integer code. * @return * Enum corresponding to integer code. */ NiftiVersionEnum::Enum NiftiVersionEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = NIFTI_VERSION_1; for (std::vector::const_iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const NiftiVersionEnum& nsu = *iter; if (nsu.integerCode == integerCode) { e = nsu.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } connectome-workbench-1.4.2/src/FilesBase/NiftiEnums.h000066400000000000000000000323051360521144700225140ustar00rootroot00000000000000#ifndef __NIFTI_ENUMS_H__ #define __NIFTI_ENUMS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include "nifti2.h" namespace caret { //we specify here whether to write in native byte order, or to honor the original //byte order, we could also get clever and try to determine whether or not we are //a big or little-endian machine, but the key concept to keep track of is whether or //not we want to honor the byte order of the original file (for in place read/write) //not the actual byte order. This should also function portably. enum NIFTI_BYTE_ORDER { NATIVE_BYTE_ORDER, SWAPPED_BYTE_ORDER }; /** * NIFTI Data Types. Note that only a small subset are used * in GIFTI data files. */ class NiftiDataTypeEnum { public: /** NIFTI Data Types. Note that only a small subset are used * in GIFTI data files. */ enum Enum { /** invalid data type. */ NIFTI_TYPE_INVALID = 0, /** unsigned byte. */ NIFTI_TYPE_UINT8 = ::NIFTI_TYPE_UINT8, /** signed short. */ NIFTI_TYPE_INT16 = ::NIFTI_TYPE_INT16, /** signed int. */ NIFTI_TYPE_INT32 = ::NIFTI_TYPE_INT32, /** 32 bit float. */ NIFTI_TYPE_FLOAT32 = ::NIFTI_TYPE_FLOAT32, /** 64 bit complex = 2 32 bit floats. */ NIFTI_TYPE_COMPLEX64 = ::NIFTI_TYPE_COMPLEX64, /** 64 bit float = double. */ NIFTI_TYPE_FLOAT64 = ::NIFTI_TYPE_FLOAT64, /** 3 8 bit bytes. */ NIFTI_TYPE_RGB24 = ::NIFTI_TYPE_RGB24, /** signed char. */ NIFTI_TYPE_INT8 = ::NIFTI_TYPE_INT8, /** unsigned short. */ NIFTI_TYPE_UINT16 = ::NIFTI_TYPE_UINT16, /** unsigned int. */ NIFTI_TYPE_UINT32 = ::NIFTI_TYPE_UINT32, /** signed long long. */ NIFTI_TYPE_INT64 = ::NIFTI_TYPE_INT64, /** unsigned long long. */ NIFTI_TYPE_UINT64 = ::NIFTI_TYPE_UINT64, /** 128 bit float = long double. */ NIFTI_TYPE_FLOAT128 = ::NIFTI_TYPE_FLOAT128, /** 128 bit complex = 2 64 bit floats. */ NIFTI_TYPE_COMPLEX128 = ::NIFTI_TYPE_COMPLEX128, /** 256 bit complex = 2 128 bit floats */ NIFTI_TYPE_COMPLEX256 = ::NIFTI_TYPE_COMPLEX256 }; ~NiftiDataTypeEnum(); private: NiftiDataTypeEnum(); NiftiDataTypeEnum(Enum e, const AString& name, const int32_t integerCode); static const NiftiDataTypeEnum* findData(Enum e); static std::vector dataTypes; static void createDataTypes(); static bool dataTypesCreatedFlag; Enum e; AString name; int32_t integerCode; public: static AString toName(Enum e); static Enum fromName(const AString& s, bool* isValidOut); static int32_t toIntegerCode(Enum e); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); }; /** * NIFTI Intent codes and related parameters. */ class NiftiIntentEnum { public: /** NIFTI Intent codes and related parameters. */ enum Enum { /** */ NIFTI_INTENT_NONE = ::NIFTI_INTENT_NONE, /** */ NIFTI_INTENT_CORREL = ::NIFTI_INTENT_CORREL, /** */ NIFTI_INTENT_TTEST = ::NIFTI_INTENT_FTEST, /** */ NIFTI_INTENT_FTEST = ::NIFTI_INTENT_FTEST, /** */ NIFTI_INTENT_ZSCORE = ::NIFTI_INTENT_ZSCORE, /** */ NIFTI_INTENT_CHISQ = ::NIFTI_INTENT_CHISQ, /** */ NIFTI_INTENT_BETA = ::NIFTI_INTENT_BETA, /** */ NIFTI_INTENT_BINOM = ::NIFTI_INTENT_BINOM, /** */ NIFTI_INTENT_GAMMA = ::NIFTI_INTENT_GAMMA, /** */ NIFTI_INTENT_POISSON = ::NIFTI_INTENT_POISSON, /** */ NIFTI_INTENT_NORMAL = ::NIFTI_INTENT_NORMAL, /** */ NIFTI_INTENT_FTEST_NONC = ::NIFTI_INTENT_FTEST_NONC, /** */ NIFTI_INTENT_CHISQ_NONC = ::NIFTI_INTENT_CHISQ_NONC, /** */ NIFTI_INTENT_LOGISTIC = ::NIFTI_INTENT_LOGISTIC, /** */ NIFTI_INTENT_LAPLACE = ::NIFTI_INTENT_LAPLACE, /** */ NIFTI_INTENT_UNIFORM = ::NIFTI_INTENT_UNIFORM, /** */ NIFTI_INTENT_TTEST_NONC = ::NIFTI_INTENT_TTEST_NONC, /** */ NIFTI_INTENT_WEIBULL = ::NIFTI_INTENT_WEIBULL, /** */ NIFTI_INTENT_CHI = ::NIFTI_INTENT_CHI, /** */ NIFTI_INTENT_INVGAUSS = ::NIFTI_INTENT_INVGAUSS, /** */ NIFTI_INTENT_EXTVAL = ::NIFTI_INTENT_EXTVAL, /** */ NIFTI_INTENT_PVAL = ::NIFTI_INTENT_PVAL, /** */ NIFTI_INTENT_LOGPVAL = ::NIFTI_INTENT_LOGPVAL, /** */ NIFTI_INTENT_LOG10PVAL = ::NIFTI_INTENT_LOG10PVAL, /** */ NIFTI_INTENT_ESTIMATE = ::NIFTI_INTENT_ESTIMATE, /** */ NIFTI_INTENT_LABEL = ::NIFTI_INTENT_LABEL, /** */ NIFTI_INTENT_NEURONAME = ::NIFTI_INTENT_NEURONAME, /** */ NIFTI_INTENT_GENMATRIX = ::NIFTI_INTENT_GENMATRIX, /** */ NIFTI_INTENT_SYMMATRIX = ::NIFTI_INTENT_SYMMATRIX, /** */ NIFTI_INTENT_DISPVECT = ::NIFTI_INTENT_DISPVECT, /** */ NIFTI_INTENT_VECTOR = ::NIFTI_INTENT_VECTOR, /** */ NIFTI_INTENT_POINTSET = ::NIFTI_INTENT_POINTSET, /** */ NIFTI_INTENT_TRIANGLE = ::NIFTI_INTENT_TRIANGLE, /** */ NIFTI_INTENT_QUATERNION = ::NIFTI_INTENT_QUATERNION, /** */ NIFTI_INTENT_DIMLESS = ::NIFTI_INTENT_DIMLESS, /** */ NIFTI_INTENT_TIME_SERIES = 2001, /** */ NIFTI_INTENT_NODE_INDEX = 2002, /** */ NIFTI_INTENT_RGB_VECTOR = 2003, /** */ NIFTI_INTENT_RGBA_VECTOR = 2004, /** */ NIFTI_INTENT_SHAPE = 2005, /** */ NIFTI_INTENT_CARET_DEFORMATION_NODE_INDICES = 25000, /** */ NIFTI_INTENT_CARET_DEFORMATION_NODE_AREAS = 25001, /** */ NIFTI_INTENT_CONNECTIVITY_DENSE = ::NIFTI_INTENT_CONNECTIVITY_DENSE, /** */ NIFTI_INTENT_CONNECTIVITY_DENSE_TIME = ::NIFTI_INTENT_CONNECTIVITY_DENSE_TIME, /** */ NIFTI_INTENT_CONNECTIVITY_PARCELLATED = ::NIFTI_INTENT_CONNECTIVITY_PARCELLATED, /** */ NIFTI_INTENT_CONNECTIVITY_PARCELLATED_TIME = ::NIFTI_INTENT_CONNECTIVITY_PARCELLATED_TIME, /** */ NIFTI_INTENT_CONNECTIVITY_TRAJECTORY = ::NIFTI_INTENT_CONNECTIVITY_DENSE_TRAJECTORY }; ~NiftiIntentEnum(); private: NiftiIntentEnum(const Enum e, const AString& enumName, const int32_t integerCode, const AString& name, const AString& p1Name, const AString& p2Name, const AString& p3Name); //NiftiIntentEnum(); Enum e; AString enumName; int32_t integerCode; AString name; AString p1Name; AString p2Name; AString p3Name; static void initializeIntents(); static const NiftiIntentEnum* findData(Enum e); static std::vector intents; static bool intentsCreatedFlag; public: static AString toName(Enum e); static AString toNameP1(Enum e); static AString toNameP2(Enum e); static AString toNameP3(Enum e); static Enum fromName(const AString& s, bool* isValidOut); static int32_t toIntegerCode(Enum e); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); }; /** * NIFTI Spacing Units */ class NiftiSpacingUnitsEnum { public: /** NIFTI Spacing Units */ enum Enum { /** */ NIFTI_UNITS_UNKNOWN = ::NIFTI_UNITS_UNKNOWN, /** */ NIFTI_UNITS_METER = ::NIFTI_UNITS_METER, /** */ NIFTI_UNITS_MM = ::NIFTI_UNITS_MM, /** */ NIFTI_UNITS_MICRON = ::NIFTI_UNITS_MICRON }; ~NiftiSpacingUnitsEnum(); private: NiftiSpacingUnitsEnum(Enum e, const int32_t integerCode, const AString& name); static const NiftiSpacingUnitsEnum* findData(Enum e); static std::vector spacingUnits; static void initializeSpacingUnits(); static bool initializedFlag; Enum e; int32_t integerCode; AString name; public: static AString toName(Enum e); static Enum fromName(const AString& s, bool* isValidOut); static int32_t toIntegerCode(Enum e); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); }; /** * NIFTI Time Units */ class NiftiTimeUnitsEnum { public: /** NIFTI Time Units */ enum Enum { /** Unknown */ NIFTI_UNITS_UNKNOWN = ::NIFTI_UNITS_UNKNOWN, /** Seconds */ NIFTI_UNITS_SEC = ::NIFTI_UNITS_SEC, /** Milliseconds */ NIFTI_UNITS_MSEC = ::NIFTI_UNITS_MSEC, /** Microseconds */ NIFTI_UNITS_USEC = ::NIFTI_UNITS_USEC, /** Hertz */ NIFTI_UNITS_HZ = ::NIFTI_UNITS_HZ, /** Parts Per Million */ NIFTI_UNITS_PPM = ::NIFTI_UNITS_PPM }; ~NiftiTimeUnitsEnum(); static AString toName(Enum e); static Enum fromName(const AString& s, bool* isValidOut); static int32_t toIntegerCode(Enum e); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static AString toGuiName(Enum e); private: NiftiTimeUnitsEnum(const Enum e, const int32_t integerCode, const AString& name, const AString& guiName); static const NiftiTimeUnitsEnum* findData(const Enum e); static std::vector enumData; static void initializeTimeUnits(); static bool initializedFlag; Enum e; int32_t integerCode; AString name; AString guiName; }; /** * NIFTI Transform. */ class NiftiTransformEnum { public: /** NIFTI Transform. */ enum Enum { /** Arbitrary Coordinates */ NIFTI_XFORM_UNKNOWN = ::NIFTI_XFORM_UNKNOWN, /** Scanner-base anatomical coordinates */ NIFTI_XFORM_SCANNER_ANAT = ::NIFTI_XFORM_SCANNER_ANAT, /** Coordinates aligned to another file's or anatomial "truth" */ NIFTI_XFORM_ALIGNED_ANAT = ::NIFTI_XFORM_ALIGNED_ANAT, /** Coordinates aligned to Talairach-Tournoux Atlas: (0,0,0) = Anterior Commissure */ NIFTI_XFORM_TALAIRACH = ::NIFTI_XFORM_TALAIRACH, /** MNI 152 Normalize Coordinates */ NIFTI_XFORM_MNI_152 = ::NIFTI_XFORM_MNI_152 }; ~NiftiTransformEnum(); static AString toName(Enum e); static Enum fromName(const AString& s, bool* isValidOut); static int32_t toIntegerCode(Enum e); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); private: NiftiTransformEnum(const Enum e, const int32_t integerCode, const AString& name); static std::vector enumData; static const NiftiTransformEnum* findData(const Enum e); static void initialize(); static bool initializedFlag; Enum e; int32_t integerCode; AString name; }; /** * The NIFTI version */ class NiftiVersionEnum { public: /** The NIFTI version */ enum Enum { /** NIFTI-1 */ NIFTI_VERSION_1, /** NIFTI-2 */ NIFTI_VERSION_2 }; ~NiftiVersionEnum(); static AString toName(Enum e); static Enum fromName(const AString& s, bool* isValidOut); static int32_t toIntegerCode(Enum e); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); private: NiftiVersionEnum(const Enum e, const int32_t integerCode, const AString& name); static std::vector enumData; static void initialize(); static bool initializedFlag; Enum e; int32_t integerCode; AString name; static const NiftiVersionEnum* findData(const Enum e); }; #ifdef __NIFTI_ENUMS_DECLARE__ std::vector NiftiDataTypeEnum::dataTypes; bool NiftiDataTypeEnum::dataTypesCreatedFlag = false; std::vector NiftiIntentEnum::intents; bool NiftiIntentEnum::intentsCreatedFlag = false; std::vector NiftiSpacingUnitsEnum::spacingUnits; bool NiftiSpacingUnitsEnum::initializedFlag = false; std::vector NiftiTimeUnitsEnum::enumData; bool NiftiTimeUnitsEnum::initializedFlag = false; std::vector NiftiTransformEnum::enumData; bool NiftiTransformEnum::initializedFlag = false; std::vector NiftiVersionEnum::enumData; bool NiftiVersionEnum::initializedFlag = false; #endif // __NIFTI_ENUMS_DECLARE__ } // namespace #endif // __NIFTI_ENUMS_H connectome-workbench-1.4.2/src/FilesBase/VolumeBase.cxx000066400000000000000000000373061360521144700230560ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "VolumeBase.h" #include "DataFileException.h" #include "FloatMatrix.h" #include "GiftiLabelTable.h" #include "GiftiMetaData.h" #include "GiftiXmlElements.h" #include "Palette.h" #include "PaletteColorMapping.h" #include "Vector3D.h" #include using namespace caret; using namespace std; AbstractHeader::~AbstractHeader() { } void VolumeBase::reinitialize(const vector& dimensionsIn, const vector >& indexToSpace, const int64_t numComponents) { CaretAssert(numComponents > 0); clear(); int numDims = (int)dimensionsIn.size(); if (numDims < 3) { throw DataFileException("volume files must have 3 or more dimensions"); } m_origDims = dimensionsIn;//save the original dimensions int64_t storeDims[5]; storeDims[3] = 1; for (int i = 0; i < numDims; ++i) { if (i > 2) { storeDims[3] *= dimensionsIn[i]; } else { storeDims[i] = dimensionsIn[i]; } } m_volSpace.setSpace(storeDims, indexToSpace); if (storeDims[0] == 1 && storeDims[1] == 1 && storeDims[2] == 1 && storeDims[3] > 10000) {//slight hack, to detect if a cifti file is loaded as a volume file, because many 1x1x1 frames could use a surprisingly large amount of memory (metadata, palette, etc) throw DataFileException("this file doesn't appear to be a volume file"); } storeDims[4] = numComponents; m_storage.reinitialize(storeDims); } void VolumeBase::addSubvolumes(const int64_t& numToAdd) { CaretAssert(numToAdd > 0); vector olddims = getDimensions();//use the already flattened dimensions to start, as the non-spatial dimensions must be flattened to add an arbitrary number of maps CaretAssert(olddims[3] > 0);//can't add volumes when we have no dimensions, stop the debugger here if (olddims[3] < 1) { throw DataFileException("cannot call addSubvolumes on an uninitialized VolumeFile");//release shouldn't allow it either } vector newdims = olddims; newdims[3] += numToAdd;//add to the flattened non-spatial dimensions VolumeStorage newStorage(newdims.data()); newdims.resize(4);//drop the number of components from the dimensions array m_origDims = newdims;//and reset our original dimensions for (int64_t c = 0; c < olddims[4]; ++c) { for (int64_t b = 0; b < olddims[3]; ++b) { newStorage.setFrame(m_storage.getFrame(b, c), b, c); } } m_storage.swap(newStorage); setModified();//NOTE: will invalidate splines, can be made more efficient for certain cases when merging Base and File } void VolumeBase::setVolumeSpace(const vector >& indexToSpace) { m_volSpace.setSpace(getDimensionsPtr(), indexToSpace); setModified(); } VolumeBase::VolumeBase() { m_origDims.push_back(0);//give original dimensions 3 elements, just because m_origDims.push_back(0); m_origDims.push_back(0); m_ModifiedFlag = false; } VolumeBase::VolumeBase(const vector& dimensionsIn, const vector >& indexToSpace, const int64_t numComponents) { reinitialize(dimensionsIn, indexToSpace, numComponents); m_ModifiedFlag = true; } void VolumeBase::getOrientAndSpacingForPlumb(VolumeSpace::OrientTypes* orientOut, float* spacingOut, float* centerOut) const { m_volSpace.getOrientAndSpacingForPlumb(orientOut, spacingOut, centerOut); } void VolumeBase::getOrientation(VolumeSpace::OrientTypes orientOut[3]) const { m_volSpace.getOrientation(orientOut); } void VolumeBase::reorient(const VolumeSpace::OrientTypes newOrient[3]) { VolumeSpace::OrientTypes curOrient[3]; getOrientation(curOrient); int curReverse[3];//for each spatial axis, which index currently goes that direction bool curReverseNeg[3]; int doSomething = false;//check whether newOrient is any different for (int i = 0; i < 3; ++i) { if (curOrient[i] != newOrient[i]) doSomething = true; curReverse[curOrient[i] & 3] = i;//int values of the enum are crafted to make this work curReverseNeg[curOrient[i] & 3] = ((curOrient[i] & 4) != 0); } if (!doSomething) return; bool flip[3]; int fetchFrom[3]; for (int i = 0; i < 3; ++i) { flip[i] = curReverseNeg[newOrient[i] & 3] != ((newOrient[i] & 4) != 0); fetchFrom[i] = curReverse[newOrient[i] & 3]; } const int64_t* dims = getDimensionsPtr(); int64_t rowSize = dims[0]; int64_t sliceSize = rowSize * dims[1]; int64_t frameSize = sliceSize * dims[2]; vector scratchFrame(frameSize); int64_t newDims[5] = {dims[fetchFrom[0]], dims[fetchFrom[1]], dims[fetchFrom[2]], dims[3], dims[4]}; VolumeStorage newStorage(newDims); for (int c = 0; c < dims[4]; ++c) { for (int b = 0; b < dims[3]; ++b) { const float* oldFrame = m_storage.getFrame(b, c); int64_t newIndices[3], oldIndices[3]; for (newIndices[2] = 0; newIndices[2] < newDims[2]; ++newIndices[2]) { if (flip[2]) { oldIndices[fetchFrom[2]] = newDims[2] - newIndices[2] - 1; } else { oldIndices[fetchFrom[2]] = newIndices[2]; } for (newIndices[1] = 0; newIndices[1] < newDims[1]; ++newIndices[1]) { if (flip[1]) { oldIndices[fetchFrom[1]] = newDims[1] - newIndices[1] - 1; } else { oldIndices[fetchFrom[1]] = newIndices[1]; } for (newIndices[0] = 0; newIndices[0] < newDims[0]; ++newIndices[0]) { if (flip[0]) { oldIndices[fetchFrom[0]] = newDims[0] - newIndices[0] - 1; } else { oldIndices[fetchFrom[0]] = newIndices[0]; } scratchFrame[newStorage.getIndex(newIndices, 0, 0)] = oldFrame[getIndex(oldIndices)]; } } } newStorage.setFrame(scratchFrame.data(), b, c); } } const vector >& oldSform = m_volSpace.getSform(); vector > indexToSpace = oldSform;//reorder and flip the sform - this might belong in VolumeSpace for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { if (flip[j]) { indexToSpace[i][j] = -oldSform[i][fetchFrom[j]]; indexToSpace[i][3] += oldSform[i][fetchFrom[j]] * (newDims[j] - 1); } else { indexToSpace[i][j] = oldSform[i][fetchFrom[j]]; } } }//and now generate the inverse for spaceToIndex m_volSpace.setSpace(newDims, indexToSpace); m_origDims[0] = newDims[0];//update m_origDims too m_origDims[1] = newDims[1]; m_origDims[2] = newDims[2]; m_storage.swap(newStorage); setModified(); } void VolumeBase::enclosingVoxel(const float* coordIn, int64_t* indexOut) const { enclosingVoxel(coordIn[0], coordIn[1], coordIn[2], indexOut[0], indexOut[1], indexOut[2]); } void VolumeBase::enclosingVoxel(const float& coordIn1, const float& coordIn2, const float& coordIn3, int64_t* indexOut) const { enclosingVoxel(coordIn1, coordIn2, coordIn3, indexOut[0], indexOut[1], indexOut[2]); } void VolumeBase::enclosingVoxel(const float* coordIn, int64_t& indexOut1, int64_t& indexOut2, int64_t& indexOut3) const { enclosingVoxel(coordIn[0], coordIn[1], coordIn[2], indexOut1, indexOut2, indexOut3); } void VolumeBase::enclosingVoxel(const float& coordIn1, const float& coordIn2, const float& coordIn3, int64_t& indexOut1, int64_t& indexOut2, int64_t& indexOut3) const { float tempInd1, tempInd2, tempInd3; spaceToIndex(coordIn1, coordIn2, coordIn3, tempInd1, tempInd2, tempInd3); indexOut1 = (int64_t)floor(0.5f + tempInd1); indexOut2 = (int64_t)floor(0.5f + tempInd2); indexOut3 = (int64_t)floor(0.5f + tempInd3); } int64_t VolumeBase::getBrickIndexFromNonSpatialIndexes(const vector& extraInds) const { CaretAssert(extraInds.size() == m_origDims.size() - 3); int extraDims = (int)extraInds.size(); if (extraDims == 0) return 0; CaretAssert(extraInds[extraDims - 1] >= 0 && extraInds[extraDims - 1] < m_origDims[extraDims + 2]); int64_t ret = extraInds[extraDims - 1]; for (int i = extraDims - 2; i >= 0; --i)//yes, its supposed to loop starting with the second highest dimension { CaretAssert(extraInds[i] >= 0 && extraInds[i] < m_origDims[i + 3]); ret = ret * m_origDims[i + 3] + extraInds[i];//factored polynomial form } CaretAssert(ret < getDimensionsPtr()[3]);//otherwise, dimensions[3] and m_origDims don't match return ret; } vector VolumeBase::getNonSpatialIndexesFromBrickIndex(const int64_t& brickIndex) const { CaretAssert(brickIndex >= 0 && brickIndex < getDimensionsPtr()[3]); vector ret; int extraDims = (int)m_origDims.size() - 3; if (extraDims <= 0) return ret;//empty vector if there are no extra-spatial dimensions, so we don't call resize(0), even though it should be safe ret.resize(extraDims); int64_t myRemaining = brickIndex, temp; for (int i = 0; i < extraDims; ++i) { temp = myRemaining % m_origDims[i + 3];//modulus myRemaining = (myRemaining - temp) / m_origDims[i + 3];//subtract the remainder even though int divide should truncate correctly, just to make it obvious ret[i] = temp; } CaretAssert(myRemaining == 0);//otherwise, m_dimensions[3] and m_origDims don't match return ret; } void VolumeBase::indexToSpace(const int64_t* indexIn, float* coordOut) const { indexToSpace(indexIn[0], indexIn[1], indexIn[2], coordOut[0], coordOut[1], coordOut[2]); } void VolumeBase::indexToSpace(const int64_t* indexIn, float& coordOut1, float& coordOut2, float& coordOut3) const { indexToSpace(indexIn[0], indexIn[1], indexIn[2], coordOut1, coordOut2, coordOut3); } void VolumeBase::indexToSpace(const float* indexIn, float* coordOut) const { indexToSpace(indexIn[0], indexIn[1], indexIn[2], coordOut[0], coordOut[1], coordOut[2]); } void VolumeBase::indexToSpace(const float& indexIn1, const float& indexIn2, const float& indexIn3, float* coordOut) const { indexToSpace(indexIn1, indexIn2, indexIn3, coordOut[0], coordOut[1], coordOut[2]); } void VolumeBase::indexToSpace(const float* indexIn, float& coordOut1, float& coordOut2, float& coordOut3) const { indexToSpace(indexIn[0], indexIn[1], indexIn[2], coordOut1, coordOut2, coordOut3); } void VolumeBase::indexToSpace(const float& indexIn1, const float& indexIn2, const float& indexIn3, float& coordOut1, float& coordOut2, float& coordOut3) const { m_volSpace.indexToSpace(indexIn1, indexIn2, indexIn3, coordOut1, coordOut2, coordOut3); } bool VolumeBase::isPlumb() const { return m_volSpace.isPlumb(); } void VolumeBase::spaceToIndex(const float* coordIn, float* indexOut) const { spaceToIndex(coordIn[0], coordIn[1], coordIn[2], indexOut[0], indexOut[1], indexOut[2]); } void VolumeBase::spaceToIndex(const float& coordIn1, const float& coordIn2, const float& coordIn3, float* indexOut) const { spaceToIndex(coordIn1, coordIn2, coordIn3, indexOut[0], indexOut[1], indexOut[2]); } void VolumeBase::spaceToIndex(const float* coordIn, float& indexOut1, float& indexOut2, float& indexOut3) const { spaceToIndex(coordIn[0], coordIn[1], coordIn[2], indexOut1, indexOut2, indexOut3); } void VolumeBase::spaceToIndex(const float& coordIn1, const float& coordIn2, const float& coordIn3, float& indexOut1, float& indexOut2, float& indexOut3) const { m_volSpace.spaceToIndex(coordIn1, coordIn2, coordIn3, indexOut1, indexOut2, indexOut3); } void VolumeBase::clear() { m_storage.clear(); m_origDims.clear(); m_origDims.resize(3, 0);//give original dimensions 3 elements, just because m_header.grabNew(NULL); } VolumeBase::~VolumeBase() { } /** * Is the file empty (contains no data)? * * @return * true if the file is empty, else false. */ bool VolumeBase::isEmpty() const { return (getDimensionsPtr()[0] <= 0); } VolumeBase::VolumeStorage::VolumeStorage() { for (int i = 0; i < 5; ++i) { m_dimensions[i] = 0; m_mult[i] = 0; } } void VolumeBase::VolumeStorage::reinitialize(int64_t dims[5]) { for (int i = 0; i < 5; ++i) { CaretAssert(dims[i] > 0);//stop the debugger in the right place if (dims[i] < 1) throw DataFileException("VolumeStorage dimensions must be positive");//release shouldn't allow it either, though m_dimensions[i] = dims[i]; } m_mult[0] = m_dimensions[0]; for (int i = 1; i < 5; ++i) { m_mult[i] = m_mult[i - 1] * m_dimensions[i]; } m_data.resize(m_mult[4]); } VolumeBase::VolumeStorage::VolumeStorage(int64_t dims[5]) { reinitialize(dims); } const float* VolumeBase::VolumeStorage::getFrame(const int64_t brickIndex, const int64_t component) const { return m_data.data() + brickIndex * m_mult[2] + component * m_mult[3];//NOTE: do not use [4] } void VolumeBase::VolumeStorage::setFrame(const float* frameIn, const int64_t brickIndex, const int64_t component) { int64_t start = brickIndex * m_mult[2] + component * m_mult[3]; for (int64_t i = 0; i < m_mult[2]; ++i) { m_data[i + start] = frameIn[i]; } } void VolumeBase::VolumeStorage::setValueAllVoxels(const float value) { for (int64_t i = 0; i < m_mult[4]; ++i) { m_data[i] = value; } } void VolumeBase::VolumeStorage::swap(VolumeStorage& rhs) { m_data.swap(rhs.m_data); for (int i = 0; i < 5; ++i) { std::swap(m_dimensions[i], rhs.m_dimensions[i]); std::swap(m_mult[i], rhs.m_mult[i]); } } void VolumeBase::VolumeStorage::getDimensions(vector& dimOut) const { dimOut.resize(5); for (int i = 0; i < 5; ++i) { dimOut[i] = m_dimensions[i]; } } void VolumeBase::VolumeStorage::getDimensions(int64_t& dimOut1, int64_t& dimOut2, int64_t& dimOut3, int64_t& dimTimeOut, int64_t& numComponents) const { dimOut1 = m_dimensions[0]; dimOut2 = m_dimensions[1]; dimOut3 = m_dimensions[2]; dimTimeOut = m_dimensions[3]; numComponents = m_dimensions[4]; } vector VolumeBase::VolumeStorage::getDimensions() const { vector ret; getDimensions(ret); return ret; } void VolumeBase::VolumeStorage::clear() { m_data.clear(); for (int i = 0; i < 5; ++i) { m_dimensions[i] = 0; m_mult[i] = 0; } } /** * @return Is this instance modified? */ bool VolumeBase::isModifiedVolumeBase() const { if (m_ModifiedFlag) { return true; } return false; } /** * Clear this instance's modified status */ void VolumeBase::clearModifiedVolumeBase() { m_ModifiedFlag = false; } /** * Set this instance's status to modified. */ void VolumeBase::setModified() { m_ModifiedFlag = true; } connectome-workbench-1.4.2/src/FilesBase/VolumeBase.h000066400000000000000000000451571360521144700225060ustar00rootroot00000000000000 #ifndef __VOLUME_BASE_H__ #define __VOLUME_BASE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "stdint.h" #include #include "CaretAssert.h" #include "CaretPointer.h" #include "VolumeMappableInterface.h" #include "VolumeSpace.h" namespace caret { struct AbstractHeader { virtual bool hasGoodSpatialInformation() const = 0; enum HeaderType { NIFTI }; virtual HeaderType getType() const = 0; virtual AbstractHeader* clone() const = 0; virtual ~AbstractHeader(); }; class VolumeBase : public VolumeMappableInterface { class VolumeStorage { std::vector m_data; int64_t m_dimensions[5];//store internally as 4d+component int64_t m_mult[5];//precalculated multipliers for getIndex/getValue/setValue - NOTE: [0] is for index[1], [4] is the entire size of the data VolumeStorage(const VolumeStorage& rhs);//deny copy, assignment for now VolumeStorage& operator=(const VolumeStorage& rhs); public: VolumeStorage(); VolumeStorage(int64_t dims[5]); void reinitialize(int64_t dims[5]); void clear(); virtual void getDimensions(std::vector& dimOut) const;//NOTE: always returns a vector of 5 elements virtual void getDimensions(int64_t& dimOut1, int64_t& dimOut2, int64_t& dimOut3, int64_t& dimTimeOut, int64_t& numComponents) const; std::vector getDimensions() const; const int64_t* getDimensionsPtr() const { return m_dimensions; } inline const int64_t& getNumberOfComponents() const { return m_dimensions[4]; } void swap(VolumeStorage& rhs); ///get a value at three indexes and optionally timepoint inline const float& getValue(const int64_t& indexIn1, const int64_t& indexIn2, const int64_t& indexIn3, const int64_t brickIndex, const int64_t component) const { CaretAssert(indexValid(indexIn1, indexIn2, indexIn3, brickIndex, component));//assert so release version isn't slowed by checking return m_data[getIndex(indexIn1, indexIn2, indexIn3, brickIndex, component)]; } inline const float& getValue(const int64_t indexIn[3], const int64_t brickIndex, const int64_t component) const { return getValue(indexIn[0], indexIn[1], indexIn[2], brickIndex, component); } ///gets index into data array for three indexes plus time index inline int64_t getIndex(const int64_t& indexIn1, const int64_t& indexIn2, const int64_t& indexIn3, const int64_t brickIndex, const int64_t component) const { CaretAssert(indexValid(indexIn1, indexIn2, indexIn3, brickIndex, component)); return indexIn1 + m_mult[0] * indexIn2 + m_mult[1] * indexIn3 + m_mult[2] * brickIndex + m_mult[3] * component; } inline int64_t getIndex(const int64_t indexIn[3], const int64_t brickIndex, const int64_t component) const { return getIndex(indexIn[0], indexIn[1], indexIn[2], brickIndex, component); } ///checks if an index is within array dimensions inline bool indexValid(const int64_t& indexIn1, const int64_t& indexIn2, const int64_t& indexIn3, const int64_t brickIndex, const int64_t component) const {//inlined so that getValue and setValue can get optimized out entirely if (indexIn1 < 0 || indexIn1 >= m_dimensions[0]) return false; if (indexIn2 < 0 || indexIn2 >= m_dimensions[1]) return false; if (indexIn3 < 0 || indexIn3 >= m_dimensions[2]) return false; if (brickIndex < 0 || brickIndex >= m_dimensions[3]) return false; if (component < 0 || component >= m_dimensions[4]) return false; return true; } inline bool indexValid(const int64_t indexIn[3], const int64_t brickIndex, const int64_t component) const { return indexValid(indexIn[0], indexIn[1], indexIn[2], brickIndex, component); } ///set a value at an index triplet and optionally timepoint inline void setValue(const float& valueIn, const int64_t& indexIn1, const int64_t& indexIn2, const int64_t& indexIn3, const int64_t brickIndex, const int64_t component) { CaretAssert(indexValid(indexIn1, indexIn2, indexIn3, brickIndex, component));//assert so release version isn't slowed by checking m_data[getIndex(indexIn1, indexIn2, indexIn3, brickIndex, component)] = valueIn; } inline void setValue(const float& valueIn, const int64_t indexIn[3], const int64_t brickIndex, const int64_t component) { setValue(valueIn, indexIn[0], indexIn[1], indexIn[2], brickIndex, component); } /// set every voxel to the given value void setValueAllVoxels(const float value); ///get a frame (const) const float* getFrame(const int64_t brickIndex = 0, const int64_t component = 0) const; ///set a frame void setFrame(const float* frameIn, const int64_t brickIndex = 0, const int64_t component = 0); }; VolumeStorage m_storage; VolumeSpace m_volSpace; std::vector m_origDims;//keep track of the original dimensions bool m_ModifiedFlag; protected: VolumeBase(); VolumeBase(const std::vector& dimensionsIn, const std::vector >& indexToSpace, const int64_t numComponents = 1); ///recreates the volume file storage with new size and spacing void reinitialize(const std::vector& dimensionsIn, const std::vector >& indexToSpace, const int64_t numComponents = 1); void addSubvolumes(const int64_t& numToAdd); public: void clear(); virtual ~VolumeBase(); ///there isn't much VolumeFile can do to restrict access to the header, so just have it public CaretPointer m_header; ///get the spacing info inline const std::vector >& getSform() const { return m_volSpace.getSform(); } void setVolumeSpace(const std::vector >& indexToSpace); ///get the originally specified dimensions vector inline const std::vector& getOriginalDimensions() const { return m_origDims; } inline const int64_t& getNumberOfComponents() const override { return m_storage.getNumberOfComponents(); } ///translates extraspatial indices into a (flat) brick index int64_t getBrickIndexFromNonSpatialIndexes(const std::vector& extraInds) const; ///translates a (flat) brick index into the original extraspatial indices std::vector getNonSpatialIndexesFromBrickIndex(const int64_t& brickIndex) const; ///returns true if volume space is not skew, and each axis and index is separate bool isPlumb() const; ///returns orientation, spacing, and center (spacing/center can be negative, spacing/center is LPI rearranged to ijk (first dimension uses first element), will assert false if isOblique is true) void getOrientAndSpacingForPlumb(VolumeSpace::OrientTypes* orientOut, float* spacingOut, float* centerOut) const; ///get just orientation, even for non-plumb volumes void getOrientation(VolumeSpace::OrientTypes orientOut[3]) const; ///reorient this volume void reorient(const VolumeSpace::OrientTypes newOrient[3]); //not to worry, simple passthrough convenience functions like these get partially optimized to the main one by even -O1, and completely optimized together by -O2 or -O3 ///returns coordinate triplet of an index triplet void indexToSpace(const int64_t* indexIn, float* coordOut) const override; ///returns three coordinates of an index triplet void indexToSpace(const int64_t* indexIn, float& coordOut1, float& coordOut2, float& coordOut3) const; ///returns coordinate triplet of a floating point index triplet void indexToSpace(const float* indexIn, float* coordOut) const; ///returns coordinate triplet of three floating point indexes void indexToSpace(const float& indexIn1, const float& indexIn2, const float& indexIn3, float* coordOut) const override; ///returns three coordinates of a floating point index triplet void indexToSpace(const float* indexIn, float& coordOut1, float& coordOut2, float& coordOut3) const; ///returns three coordinates of three floating point indexes void indexToSpace(const float& indexIn1, const float& indexIn2, const float& indexIn3, float& coordOut1, float& coordOut2, float& coordOut3) const override; ///returns floating point index triplet of a given coordinate triplet void spaceToIndex(const float* coordIn, float* indexOut) const; ///returns floating point index triplet of three given coordinates void spaceToIndex(const float& coordIn1, const float& coordIn2, const float& coordIn3, float* indexOut) const; ///returns three floating point indexes of a given coordinate triplet void spaceToIndex(const float* coordIn, float& indexOut1, float& indexOut2, float& indexOut3) const; ///returns three floating point indexes of three given coordinates void spaceToIndex(const float& coordIn1, const float& coordIn2, const float& coordIn3, float& indexOut1, float& indexOut2, float& indexOut3) const; ///returns integer index triplet of voxel whose center is closest to the coordinate triplet void enclosingVoxel(const float* coordIn, int64_t* indexOut) const; ///returns integer index triplet of voxel whose center is closest to the three coordinates void enclosingVoxel(const float& coordIn1, const float& coordIn2, const float& coordIn3, int64_t* indexOut) const; ///returns integer indexes of voxel whose center is closest to the coordinate triplet void enclosingVoxel(const float* coordIn, int64_t& indexOut1, int64_t& indexOut2, int64_t& indexOut3) const; ///returns integer indexes of voxel whose center is closest to the three coordinates void enclosingVoxel(const float& coordIn1, const float& coordIn2, const float& coordIn3, int64_t& indexOut1, int64_t& indexOut2, int64_t& indexOut3) const override; inline const VolumeSpace& getVolumeSpace() const { return m_volSpace; } ///get a value at an index triplet and optionally timepoint inline const float& getValue(const int64_t* indexIn, const int64_t brickIndex = 0, const int64_t component = 0) const { return m_storage.getValue(indexIn[0], indexIn[1], indexIn[2], brickIndex, component); } ///get a value at three indexes and optionally timepoint inline const float& getValue(const int64_t& indexIn1, const int64_t& indexIn2, const int64_t& indexIn3, const int64_t brickIndex = 0, const int64_t component = 0) const { return m_storage.getValue(indexIn1, indexIn2, indexIn3, brickIndex, component); } /** * Get the value of the voxel containing the given coordinate. * * @param coordinateIn * The 3D coordinate * @param validOut * If not NULL, will indicate if the coordinate (and hence the * returned value) is valid. * @param mapIndex * Index of map. * @param component * Voxel component. * @return * Value of voxel containing the given coordinate. */ inline float getVoxelValue(const float* coordinateIn, bool* validOut = NULL, const int64_t mapIndex = 0, const int64_t component = 0) const override { return getVoxelValue(coordinateIn[0], coordinateIn[1], coordinateIn[2], validOut, mapIndex, component); } /** * Get the value of the voxel containing the given coordinate. * * @param coordinateX * The X coordinate * @param coordinateY * The Y coordinate * @param coordinateZ * The Z coordinate * @param validOut * If not NULL, will indicate if the coordinate (and hence the * returned value) is valid. * @param mapIndex * Index of map. * @param component * Voxel component. * @return * Value of voxel containing the given coordinate. */ inline float getVoxelValue(const float coordinateX, const float coordinateY, const float coordinateZ, bool* validOut = NULL, const int64_t mapIndex = 0, const int64_t component = 0) const override { if (validOut != NULL) { *validOut = false; } int64_t voxelI, voxelJ, voxelK; enclosingVoxel(coordinateX, coordinateY, coordinateZ, voxelI, voxelJ, voxelK); if (indexValid(voxelI, voxelJ, voxelK, mapIndex, component)) { if (validOut != NULL) { *validOut = true; } return getValue(voxelI, voxelJ, voxelK, mapIndex, component); } return 0.0; } ///get a frame (const) const float* getFrame(const int64_t brickIndex = 0, const int64_t component = 0) const { return m_storage.getFrame(brickIndex, component); } ///set a value at an index triplet and optionally timepoint inline void setValue(const float& valueIn, const int64_t* indexIn, const int64_t brickIndex = 0, const int64_t component = 0) { m_storage.setValue(valueIn, indexIn[0], indexIn[1], indexIn[2], brickIndex, component); setModified(); } ///set a value at an index triplet and optionally timepoint inline void setValue(const float& valueIn, const int64_t& indexIn1, const int64_t& indexIn2, const int64_t& indexIn3, const int64_t brickIndex = 0, const int64_t component = 0) { m_storage.setValue(valueIn, indexIn1, indexIn2, indexIn3, brickIndex, component); setModified(); } /// set every voxel to the given value void setValueAllVoxels(const float value) { m_storage.setValueAllVoxels(value); setModified(); } ///set a frame void setFrame(const float* frameIn, const int64_t brickIndex = 0, const int64_t component = 0) { m_storage.setFrame(frameIn, brickIndex, component); setModified(); } ///gets dimensions as a vector of 5 integers, 3 spatial, time, components void getDimensions(std::vector& dimOut) const override { m_storage.getDimensions(dimOut); } ///gets dimensions void getDimensions(int64_t& dimOut1, int64_t& dimOut2, int64_t& dimOut3, int64_t& dimTimeOut, int64_t& numComponents) const override { m_storage.getDimensions(dimOut1, dimOut2, dimOut3, dimTimeOut, numComponents); } ///gets dimensions std::vector getDimensions() const { return m_storage.getDimensions(); } const int64_t* getDimensionsPtr() const { return m_storage.getDimensionsPtr(); } ///gets index into data array for three indexes plus time index inline int64_t getIndex(const int64_t& indexIn1, const int64_t& indexIn2, const int64_t& indexIn3, const int64_t brickIndex = 0, const int64_t component = 0) const { return m_storage.getIndex(indexIn1, indexIn2, indexIn3, brickIndex, component); } inline int64_t getIndex(const int64_t* indexIn, const int64_t brickIndex = 0, const int64_t component = 0) const { return m_storage.getIndex(indexIn[0], indexIn[1], indexIn[2], brickIndex, component); } inline bool indexValid(const int64_t* indexIn, const int64_t brickIndex = 0, const int64_t component = 0) const { return m_storage.indexValid(indexIn[0], indexIn[1], indexIn[2], brickIndex, component); } ///checks if an index is within array dimensions inline bool indexValid(const int64_t& indexIn1, const int64_t& indexIn2, const int64_t& indexIn3, const int64_t brickIndex = 0, const int64_t component = 0) const {//inlined so that getValue and setValue can get optimized out entirely return m_storage.indexValid(indexIn1, indexIn2, indexIn3, brickIndex, component); } virtual void setModified();//virtual because we need the functions that change voxels in this class to call the setModified in VolumeFile if it really is a VolumeFile (which it always is) void clearModifiedVolumeBase(); bool isModifiedVolumeBase() const; bool isEmpty() const; }; } #endif //__VOLUME_BASE_H__ connectome-workbench-1.4.2/src/FilesBase/VolumeMappableInterface.cxx000066400000000000000000000066011360521144700255400ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __VOLUME_MAPPABLE_INTERFACE_DECLARE__ #include "VolumeMappableInterface.h" #undef __VOLUME_MAPPABLE_INTERFACE_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * Get the voxel spacing for each of the spatial dimensions. * * @param spacingOut1 * Spacing for the first dimension (typically X). * @param spacingOut2 * Spacing for the first dimension (typically Y). * @param spacingOut3 * Spacing for the first dimension (typically Z). */ void VolumeMappableInterface::getVoxelSpacing(float& spacingOut1, float& spacingOut2, float& spacingOut3) const { float originX, originY, originZ; float x1, y1, z1; indexToSpace(0, 0, 0, originX, originY, originZ); indexToSpace(1, 1, 1, x1, y1, z1); spacingOut1 = x1 - originX; spacingOut2 = y1 - originY; spacingOut3 = z1 - originZ; } /** * Does this volume have these spatial dimensions? * * @param dim1 * First dimension. * @param dim2 * Second dimension. * @param dim3 * Third dimension. * @return * True if this volume's spatial dimensions match the * given dimensions, else false. */ bool VolumeMappableInterface::matchesDimensions(const int64_t dim1, const int64_t dim2, const int64_t dim3) const { std::vector dims; getDimensions(dims); if (dims.size() >= 3){ if ((dims[0] == dim1) && (dims[1] == dim2) && (dims[2] == dim3)) { return true; } } return false; } /** * Adjust the given indices so that they are valid * in the range 0 to (volume dimension - 1) * * @param index1 * First index. * @param index2 * Second index. * @param index3 * Third index. */ void VolumeMappableInterface::limitIndicesToValidIndices(int64_t& index1, int64_t& index2, int64_t& index3) const { std::vector dims; getDimensions(dims); if (dims.size() >= 3) { if (index1 >= dims[0]) { index1 = dims[0] - 1; } if (index1 < 0) { index1 = 0; } if (index2 >= dims[1]) { index2 = dims[1] - 1; } if (index2 < 0) { index2 = 0; } if (index3 >= dims[2]) { index3 = dims[2] - 1; } if (index3 < 0) { index3 = 0; } } } connectome-workbench-1.4.2/src/FilesBase/VolumeMappableInterface.h000066400000000000000000000357151360521144700251750ustar00rootroot00000000000000#ifndef __VOLUME_MAPPABLE_INTERFACE_H__ #define __VOLUME_MAPPABLE_INTERFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "DisplayGroupEnum.h" #include "VolumeSliceViewPlaneEnum.h" #include "VolumeSpace.h" namespace caret { class BoundingBox; /** * \class caret::VolumeMappableInterface * \brief Interface for data that is mapped to volumes * \ingroup FilesBase * * Defines an interface for data files that are drawn with voxel data. */ class VolumeMappableInterface { protected: VolumeMappableInterface() { } virtual ~VolumeMappableInterface() { } private: VolumeMappableInterface(const VolumeMappableInterface&); VolumeMappableInterface& operator=(const VolumeMappableInterface&); public: /** * Get the dimensions of the volume. * * @param dimOut1 * First dimension (i) out. * @param dimOut2 * Second dimension (j) out. * @param dimOut3 * Third dimension (k) out. * @param dimTimeOut * Time dimensions out (number of maps) * @param numComponents * Number of components per voxel. */ virtual void getDimensions(int64_t& dimOut1, int64_t& dimOut2, int64_t& dimOut3, int64_t& dimTimeOut, int64_t& numComponents) const = 0; /** * Get the dimensions of the volume. * * @param dimsOut * Will contain 5 elements: (0) X-dimension, (1) Y-dimension * (2) Z-dimension, (3) time, (4) components. */ virtual void getDimensions(std::vector& dimsOut) const = 0; bool matchesDimensions(const int64_t dim1, const int64_t dim2, const int64_t dim3) const; void limitIndicesToValidIndices(int64_t& index1, int64_t& index2, int64_t& index3) const; /** * @return The number of componenents per voxel. */ virtual const int64_t& getNumberOfComponents() const = 0; /** * Get the value of the voxel containing the given coordinate. * * @param coordinateIn * The 3D coordinate * @param validOut * If not NULL, will indicate if the coordinate (and hence the * returned value) is valid. * @param mapIndex * Index of map. * @param component * Voxel component. * @return * Value of voxel containing the given coordinate. */ virtual float getVoxelValue(const float* coordinateIn, bool* validOut = NULL, const int64_t mapIndex = 0, const int64_t component = 0) const = 0; /** * Get the value of the voxel containing the given coordinate. * * @param coordinateX * The X coordinate * @param coordinateY * The Y coordinate * @param coordinateZ * The Z coordinate * @param validOut * If not NULL, will indicate if the coordinate (and hence the * returned value) is valid. * @param mapIndex * Index of map. * @param component * Voxel component. * @return * Value of voxel containing the given coordinate. */ virtual float getVoxelValue(const float coordinateX, const float coordinateY, const float coordinateZ, bool* validOut = NULL, const int64_t mapIndex = 0, const int64_t component = 0) const = 0; /** * Convert an index to space (coordinates). * * @param indexIn1 * First dimension (i). * @param indexIn2 * Second dimension (j). * @param indexIn3 * Third dimension (k). * @param coordOut1 * Output first (x) coordinate. * @param coordOut2 * Output first (y) coordinate. * @param coordOut3 * Output first (z) coordinate. */ virtual void indexToSpace(const float& indexIn1, const float& indexIn2, const float& indexIn3, float& coordOut1, float& coordOut2, float& coordOut3) const = 0; /** * Convert an index to space (coordinates). * * @param indexIn1 * First dimension (i). * @param indexIn2 * Second dimension (j). * @param indexIn3 * Third dimension (k). * @param coordOut * Output XYZ coordinates. */ virtual void indexToSpace(const float& indexIn1, const float& indexIn2, const float& indexIn3, float* coordOut) const = 0; /** * Convert an index to space (coordinates). * * @param indexIn * IJK indices * @param coordOut * Output XYZ coordinates. */ virtual void indexToSpace(const int64_t* indexIn, float* coordOut) const = 0; /** * Convert a coordinate to indices. Note that output indices * MAY NOT BE WITHING THE VALID VOXEL DIMENSIONS. * * @param coordIn1 * First (x) input coordinate. * @param coordIn2 * Second (y) input coordinate. * @param coordIn3 * Third (z) input coordinate. * @param indexOut1 * First output index (i). * @param indexOut2 * First output index (j). * @param indexOut3 * First output index (k). */ virtual void enclosingVoxel(const float& coordIn1, const float& coordIn2, const float& coordIn3, int64_t& indexOut1, int64_t& indexOut2, int64_t& indexOut3) const = 0; /** * Determine in the given voxel indices are valid (within the volume). * * @param indexIn1 * First dimension (i). * @param indexIn2 * Second dimension (j). * @param indexIn3 * Third dimension (k). * @param coordOut1 * Output first (x) coordinate. * @param brickIndex * Time/map index (default 0). * @param component * Voxel component (default 0). */ virtual bool indexValid(const int64_t& indexIn1, const int64_t& indexIn2, const int64_t& indexIn3, const int64_t brickIndex = 0, const int64_t component = 0) const = 0; /** * Get a bounding box for the voxel coordinate ranges. * * @param boundingBoxOut * The output bounding box. */ virtual void getVoxelSpaceBoundingBox(BoundingBox& boundingBoxOut) const = 0; /** * Get the voxel spacing for each of the spatial dimensions. * * @param spacingOut1 * Spacing for the first dimension (typically X). * @param spacingOut2 * Spacing for the first dimension (typically Y). * @param spacingOut3 * Spacing for the first dimension (typically Z). */ void getVoxelSpacing(float& spacingOut1, float& spacingOut2, float& spacingOut3) const; /** * Get the voxel colors for a slice in the map. * * @param mapIndex * Index of the map. * @param slicePlane * The slice plane. * @param sliceIndex * Index of the slice. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbaOut * Output containing the rgba values (must have been allocated * by caller to sufficient count of elements in the slice). * @return * Number of voxels with alpha greater than zero */ virtual int64_t getVoxelColorsForSliceInMap(const int32_t mapIndex, const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const = 0; /** * Get voxel coloring for a set of voxels. * * @param mapIndex * Index of map. * @param firstVoxelIJK * IJK Indices of first voxel * @param rowStepIJK * IJK Step for moving to next row. * @param columnStepIJK * IJK Step for moving to next column. * @param numberOfRows * Number of rows. * @param numberOfColumns * Number of columns. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbaOut * RGBA color components out. * @return * Number of voxels with alpha greater than zero */ virtual int64_t getVoxelColorsForSliceInMap(const int32_t mapIndex, const int64_t firstVoxelIJK[3], const int64_t rowStepIJK[3], const int64_t columnStepIJK[3], const int64_t numberOfRows, const int64_t numberOfColumns, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const = 0; /** * Get the voxel colors for a sub slice in the map. * * @param mapIndex * Index of the map. * @param slicePlane * The slice plane. * @param sliceIndex * Index of the slice. * @param firstCornerVoxelIndex * Indices of voxel for first corner of sub-slice (inclusive). * @param lastCornerVoxelIndex * Indices of voxel for last corner of sub-slice (inclusive). * @param voxelCountIJK * Voxel counts for each axis. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbaOut * Output containing the rgba values (must have been allocated * by caller to sufficient count of elements in the slice). * @return * Number of voxels with alpha greater than zero */ virtual int64_t getVoxelColorsForSubSliceInMap(const int32_t mapIndex, const VolumeSliceViewPlaneEnum::Enum slicePlane, const int64_t sliceIndex, const int64_t firstCornerVoxelIndex[3], const int64_t lastCornerVoxelIndex[3], const int64_t voxelCountIJK[3], const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t* rgbaOut) const = 0; /** * Get the voxel coloring for the voxel at the given indices. * * @param indexIn1 * First dimension (i). * @param indexIn2 * Second dimension (j). * @param indexIn3 * Third dimension (k). * @param brickIndex * Time/map index. * @param displayGroup * The selected display group. * @param tabIndex * Index of selected tab. * @param rgbaOut * Output containing RGBA values for voxel at the given indices. */ virtual void getVoxelColorInMap(const int64_t indexIn1, const int64_t indexIn2, const int64_t indexIn3, const int64_t brickIndex, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, uint8_t rgbaOut[4]) const = 0; /** * Get the volume space object, so we have access to all functions associated with volume spaces */ virtual const VolumeSpace& getVolumeSpace() const = 0; }; #ifdef __VOLUME_MAPPABLE_INTERFACE_DECLARE__ // #endif // __VOLUME_MAPPABLE_INTERFACE_DECLARE__ } // namespace #endif //__VOLUME_MAPPABLE_INTERFACE_H__ connectome-workbench-1.4.2/src/FilesBase/VolumeSliceViewPlaneEnum.cxx000066400000000000000000000270771360521144700257070ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __VOLUME_SLICE_VIEW_AXIS_ENUM_DECLARE__ #include "VolumeSliceViewPlaneEnum.h" #undef __VOLUME_SLICE_VIEW_AXIS_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class VolumeSliceViewPlaneEnum * \brief * * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. * @param guiNameAbbreviation * Abbreviated name for user-interface. */ VolumeSliceViewPlaneEnum::VolumeSliceViewPlaneEnum(const Enum enumValue, const AString& name, const AString& guiName, const AString& guiNameAbbreviation) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; this->guiNameAbbreviation = guiNameAbbreviation; } /** * Destructor. */ VolumeSliceViewPlaneEnum::~VolumeSliceViewPlaneEnum() { } /** * Initialize the enumerated metadata. */ void VolumeSliceViewPlaneEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(VolumeSliceViewPlaneEnum(ALL, "ALL", "All", "All")); enumData.push_back(VolumeSliceViewPlaneEnum(AXIAL, "AXIAL", "Axial", "A")); enumData.push_back(VolumeSliceViewPlaneEnum(CORONAL, "CORONAL", "Coronal", "C")); enumData.push_back(VolumeSliceViewPlaneEnum(PARASAGITTAL, "PARASAGITTAL", "Parasagittal", "P")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const VolumeSliceViewPlaneEnum* VolumeSliceViewPlaneEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const VolumeSliceViewPlaneEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString VolumeSliceViewPlaneEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const VolumeSliceViewPlaneEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ VolumeSliceViewPlaneEnum::Enum VolumeSliceViewPlaneEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AXIAL; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const VolumeSliceViewPlaneEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type VolumeSliceViewPlaneEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString VolumeSliceViewPlaneEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const VolumeSliceViewPlaneEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ VolumeSliceViewPlaneEnum::Enum VolumeSliceViewPlaneEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AXIAL; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const VolumeSliceViewPlaneEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type VolumeSliceViewPlaneEnum")); } return enumValue; } /** * Get a GUI abbreviated string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * Short name representing enumerated value. */ AString VolumeSliceViewPlaneEnum::toGuiNameAbbreviation(Enum enumValue) { if (initializedFlag == false) initialize(); const VolumeSliceViewPlaneEnum* enumInstance = findData(enumValue); return enumInstance->guiNameAbbreviation; } /** * Get an enumerated value corresponding to its abbreviated GUI name. * @param guiNameAbbreviation * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ VolumeSliceViewPlaneEnum::Enum VolumeSliceViewPlaneEnum::fromGuiNameAbbreviation(const AString& guiNameAbbreviation, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AXIAL; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const VolumeSliceViewPlaneEnum& d = *iter; if (d.guiNameAbbreviation == guiNameAbbreviation) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiNameAbbreviation " + guiNameAbbreviation + "failed to match enumerated value for type VolumeSliceViewPlaneEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t VolumeSliceViewPlaneEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const VolumeSliceViewPlaneEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ VolumeSliceViewPlaneEnum::Enum VolumeSliceViewPlaneEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AXIAL; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const VolumeSliceViewPlaneEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type VolumeSliceViewPlaneEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void VolumeSliceViewPlaneEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void VolumeSliceViewPlaneEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(VolumeSliceViewPlaneEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void VolumeSliceViewPlaneEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(VolumeSliceViewPlaneEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/FilesBase/VolumeSliceViewPlaneEnum.h000066400000000000000000000070631360521144700253250ustar00rootroot00000000000000#ifndef __VOLUME_SLICE_VIEW_AXIS_ENUM__H_ #define __VOLUME_SLICE_VIEW_AXIS_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class VolumeSliceViewPlaneEnum { public: /** * Enumerated values. */ enum Enum { /** All Axis */ ALL, /** Axial (Horizontal) */ AXIAL, /** Coronal */ CORONAL, /** Parasagittal */ PARASAGITTAL }; ~VolumeSliceViewPlaneEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiNameAbbreviation(const AString& guiNameAbbreviation, bool* isValidOut); static AString toGuiNameAbbreviation(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: VolumeSliceViewPlaneEnum(const Enum enumValue, const AString& name, const AString& guiName, const AString& guiNameAbbreviation); static const VolumeSliceViewPlaneEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; /** A short user-friendly name that is displayed in the GUI */ AString guiNameAbbreviation; }; #ifdef __VOLUME_SLICE_VIEW_AXIS_ENUM_DECLARE__ std::vector VolumeSliceViewPlaneEnum::enumData; bool VolumeSliceViewPlaneEnum::initializedFlag = false; int32_t VolumeSliceViewPlaneEnum::integerCodeCounter = 0; #endif // __VOLUME_SLICE_VIEW_AXIS_ENUM_DECLARE__ } // namespace #endif //__VOLUME_SLICE_VIEW_AXIS_ENUM__H_ connectome-workbench-1.4.2/src/FilesBase/VolumeSpace.cxx000066400000000000000000000454151360521144700232370ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "VolumeSpace.h" #include "CaretAssert.h" #include "CaretException.h" #include "CaretLogger.h" #include "FloatMatrix.h" #include #include #include #include using namespace std; using namespace caret; VolumeSpace::VolumeSpace() { m_dims[0] = 0; m_dims[1] = 0; m_dims[2] = 0; m_sform = FloatMatrix::identity(4).getMatrix(); computeInverse(); } VolumeSpace::VolumeSpace(const int64_t dims[3], const vector >& sform) { setSpace(dims, sform); } VolumeSpace::VolumeSpace(const int64_t dims[3], const float sform[12]) { setSpace(dims, sform); } void VolumeSpace::setSpace(const int64_t dims[3], const vector >& sform) { if (sform.size() < 2 || sform.size() > 4) { CaretAssert(false); throw CaretException("VolumeSpace initialized with wrong size sform"); } for (int i = 0; i < (int)sform.size(); ++i) { if (sform[i].size() != 4) { CaretAssert(false); throw CaretException("VolumeSpace initialized with wrong size sform"); } } m_dims[0] = dims[0]; m_dims[1] = dims[1]; m_dims[2] = dims[2]; m_sform = sform; m_sform.resize(4);//make sure its 4x4 m_sform[3].resize(4); m_sform[3][0] = 0.0f;//force the fourth row to be correct m_sform[3][1] = 0.0f; m_sform[3][2] = 0.0f; m_sform[3][3] = 1.0f; computeInverse(); } void VolumeSpace::setSpace(const int64_t dims[3], const float sform[12]) { m_sform = FloatMatrix::identity(4).getMatrix(); for (int i = 0; i < 3; ++i) { for (int j = 0; j < 4; ++j) { m_sform[i][j] = sform[i * 4 + j]; } } m_dims[0] = dims[0]; m_dims[1] = dims[1]; m_dims[2] = dims[2]; computeInverse(); } void VolumeSpace::computeInverse() { m_inverse = FloatMatrix(m_sform).inverse().getMatrix(); } void VolumeSpace::spaceToIndex(const float& coordIn1, const float& coordIn2, const float& coordIn3, float& indexOut1, float& indexOut2, float& indexOut3) const { indexOut1 = coordIn1 * m_inverse[0][0] + coordIn2 * m_inverse[0][1] + coordIn3 * m_inverse[0][2] + m_inverse[0][3]; indexOut2 = coordIn1 * m_inverse[1][0] + coordIn2 * m_inverse[1][1] + coordIn3 * m_inverse[1][2] + m_inverse[1][3]; indexOut3 = coordIn1 * m_inverse[2][0] + coordIn2 * m_inverse[2][1] + coordIn3 * m_inverse[2][2] + m_inverse[2][3]; } void VolumeSpace::enclosingVoxel(const float& coordIn1, const float& coordIn2, const float& coordIn3, int64_t& indexOut1, int64_t& indexOut2, int64_t& indexOut3) const { float tempInd1, tempInd2, tempInd3; spaceToIndex(coordIn1, coordIn2, coordIn3, tempInd1, tempInd2, tempInd3); indexOut1 = (int64_t)floor(0.5f + tempInd1); indexOut2 = (int64_t)floor(0.5f + tempInd2); indexOut3 = (int64_t)floor(0.5f + tempInd3); } bool VolumeSpace::matches(const VolumeSpace& right) const { for (int i = 0; i < 3; ++i) { if (m_dims[i] != right.m_dims[i]) { return false; } } const float TOLER_RATIO = 0.999f;//ratio a spacing element can mismatch by for (int i = 0; i < 3; ++i) { for (int j = 0; j < 4; ++j) { float leftelem = m_sform[i][j]; float rightelem = right.m_sform[i][j]; if ((leftelem != rightelem) && (leftelem == 0.0f || rightelem == 0.0f || (leftelem / rightelem < TOLER_RATIO || rightelem / leftelem < TOLER_RATIO))) { return false; } } } return true; } bool VolumeSpace::operator==(const VolumeSpace& right) const { for (int i = 0; i < 3; ++i) { if (m_dims[i] != right.m_dims[i]) { return false; } } for (int i = 0; i < 3; ++i) { for (int j = 0; j < 4; ++j) { if (m_sform[i][j] != right.m_sform[i][j]) { return false; } } } return true; } void VolumeSpace::getSpacingVectors(Vector3D& iStep, Vector3D& jStep, Vector3D& kStep, Vector3D& origin) const { FloatMatrix(m_sform).getAffineVectors(iStep, jStep, kStep, origin); } float VolumeSpace::getVoxelVolume() const { Vector3D spacingVecs[4]; getSpacingVectors(spacingVecs[0], spacingVecs[1], spacingVecs[2], spacingVecs[3]); return abs(spacingVecs[0].dot(spacingVecs[1].cross(spacingVecs[2]))); } void VolumeSpace::getOrientAndSpacingForPlumb(OrientTypes* orientOut, float* spacingOut, float* originOut) const { CaretAssert(isPlumb()); if (!isPlumb()) { throw CaretException("orientation and spacing asked for on non-plumb volume space");//this will fail MISERABLY on non-plumb volumes, so throw otherwise } for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { if (m_sform[i][j] != 0.0f) { spacingOut[j] = m_sform[i][j]; originOut[j] = m_sform[i][3]; bool negative = (m_sform[i][j] < 0.0f); switch (i) { case 0: //left/right orientOut[j] = (negative ? RIGHT_TO_LEFT : LEFT_TO_RIGHT); break; case 1: //forward/back orientOut[j] = (negative ? ANTERIOR_TO_POSTERIOR : POSTERIOR_TO_ANTERIOR); break; case 2: //up/down orientOut[j] = (negative ? SUPERIOR_TO_INFERIOR : INFERIOR_TO_SUPERIOR); break; default: //will never get called break; }; } } } } void VolumeSpace::getOrientation(OrientTypes orientOut[3]) const { Vector3D ivec, jvec, kvec, origin; getSpacingVectors(ivec, jvec, kvec, origin); int next = 1, bestarray[3] = {0, 0, 0}; float bestVal = -1.0f;//make sure at least the first test trips true, if there is a zero spacing vector it will default to report LPI for (int first = 0; first < 3; ++first)//brute force search for best fit - only 6 to try { int third = 3 - first - next; float testVal = abs(ivec[first] * jvec[next] * kvec[third]); if (testVal > bestVal) { bestVal = testVal; bestarray[0] = first; bestarray[1] = next; } testVal = abs(ivec[first] * jvec[third] * kvec[next]); if (testVal > bestVal) { bestVal = testVal; bestarray[0] = first; bestarray[1] = third; } next = 0; } bestarray[2] = 3 - bestarray[0] - bestarray[1]; Vector3D spaceHats[3];//to translate into enums without casting spaceHats[0] = ivec; spaceHats[1] = jvec; spaceHats[2] = kvec; for (int i = 0; i < 3; ++i) { bool neg = (spaceHats[i][bestarray[i]] < 0.0f); switch (bestarray[i]) { case 0: if (neg) { orientOut[i] = RIGHT_TO_LEFT; } else { orientOut[i] = LEFT_TO_RIGHT; } break; case 1: if (neg) { orientOut[i] = ANTERIOR_TO_POSTERIOR; } else { orientOut[i] = POSTERIOR_TO_ANTERIOR; } break; case 2: if (neg) { orientOut[i] = SUPERIOR_TO_INFERIOR; } else { orientOut[i] = INFERIOR_TO_SUPERIOR; } break; default: CaretAssert(0); } } } bool VolumeSpace::isPlumb() const { char axisUsed = 0; char indexUsed = 0; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { if (m_sform[i][j] != 0.0f) { if (axisUsed & (1< #include #include "stdint.h" #include namespace caret { class VolumeSpace { int64_t m_dims[3]; std::vector > m_sform, m_inverse; void computeInverse(); public: enum OrientTypes { LEFT_TO_RIGHT = 0, RIGHT_TO_LEFT = 4, POSTERIOR_TO_ANTERIOR = 1, ANTERIOR_TO_POSTERIOR = 5, INFERIOR_TO_SUPERIOR = 2, SUPERIOR_TO_INFERIOR = 6 }; VolumeSpace(); VolumeSpace(const int64_t dims[3], const std::vector >& sform); VolumeSpace(const int64_t dims[3], const float sform[12]); void setSpace(const int64_t dims[3], const std::vector >& sform); void setSpace(const int64_t dims[3], const float sform[12]); const int64_t* getDims() const { return m_dims; } const std::vector >& getSform() const { return m_sform; } void getSpacingVectors(Vector3D& iStep, Vector3D& jStep, Vector3D& kStep, Vector3D& origin) const; float getVoxelVolume() const; bool matches(const VolumeSpace& right) const;//allows slight mismatches bool operator==(const VolumeSpace& right) const;//requires that it be exact bool operator!=(const VolumeSpace& right) const { return !(*this == right); } ///returns true if volume space is not skew, and each axis and index is separate bool isPlumb() const; ///returns orientation, spacing, and center (spacing/center can be negative, spacing/center is LPI rearranged to ijk (first dimension uses first element), will assert false if isOblique is true) void getOrientAndSpacingForPlumb(OrientTypes* orientOut, float* spacingOut, float* originOut) const; ///get just orientation, even for non-plumb volumes void getOrientation(OrientTypes orientOut[3]) const; ///returns coordinate triplet of an index triplet template inline void indexToSpace(const T* indexIn, float* coordOut) const { indexToSpace(indexIn[0], indexIn[1], indexIn[2], coordOut[0], coordOut[1], coordOut[2]); } ///returns coordinate triplet of three indices template inline void indexToSpace(const T& indexIn1, const T& indexIn2, const T& indexIn3, float* coordOut) const { indexToSpace(indexIn1, indexIn2, indexIn3, coordOut[0], coordOut[1], coordOut[2]); } ///returns three coordinates of an index triplet template inline void indexToSpace(const T* indexIn, float& coordOut1, float& coordOut2, float& coordOut3) const { indexToSpace(indexIn[0], indexIn[1], indexIn[2], coordOut1, coordOut2, coordOut3); } ///output a Vector3D for three indices template inline Vector3D indexToSpace(const T& indexIn1, const T& indexIn2, const T& indexIn3) const { Vector3D coords; indexToSpace(indexIn1, indexIn2, indexIn3, coords); return coords; } ///output a Vector3D for an index triplet template inline Vector3D indexToSpace(const T* indexIn) const { Vector3D coords; indexToSpace(indexIn, coords); return coords; } ///convenience methods to use VoxelIJK without .m_ijk inline Vector3D indexToSpace(const VoxelIJK indexIn) const { return indexToSpace(indexIn.m_ijk); } inline void indexToSpace(const VoxelIJK indexIn, float* coordOut) const { indexToSpace(indexIn.m_ijk, coordOut); } inline void indexToSpace(const VoxelIJK indexIn, float& coordOut1, float& coordOut2, float& coordOut3) const { indexToSpace(indexIn.m_ijk, coordOut1, coordOut2, coordOut3); } ///returns three coordinates of three indices template void indexToSpace(const T& indexIn1, const T& indexIn2, const T& indexIn3, float& coordOut1, float& coordOut2, float& coordOut3) const; ///returns floating point index triplet of a given coordinate triplet inline void spaceToIndex(const float* coordIn, float* indexOut) const { spaceToIndex(coordIn[0], coordIn[1], coordIn[2], indexOut[0], indexOut[1], indexOut[2]); } ///returns floating point index triplet of three given coordinates inline void spaceToIndex(const float& coordIn1, const float& coordIn2, const float& coordIn3, float* indexOut) const { spaceToIndex(coordIn1, coordIn2, coordIn3, indexOut[0], indexOut[1], indexOut[2]); } ///returns three floating point indexes of a given coordinate triplet inline void spaceToIndex(const float* coordIn, float& indexOut1, float& indexOut2, float& indexOut3) const { spaceToIndex(coordIn[0], coordIn[1], coordIn[2], indexOut1, indexOut2, indexOut3); } ///returns three floating point indexes of three given coordinates void spaceToIndex(const float& coordIn1, const float& coordIn2, const float& coordIn3, float& indexOut1, float& indexOut2, float& indexOut3) const; ///returns integer index triplet of voxel whose center is closest to the coordinate triplet inline void enclosingVoxel(const float* coordIn, int64_t* indexOut) const { enclosingVoxel(coordIn[0], coordIn[1], coordIn[2], indexOut[0], indexOut[1], indexOut[2]); } ///returns integer index triplet of voxel whose center is closest to the three coordinates inline void enclosingVoxel(const float& coordIn1, const float& coordIn2, const float& coordIn3, int64_t* indexOut) const { enclosingVoxel(coordIn1, coordIn2, coordIn3, indexOut[0], indexOut[1], indexOut[2]); } ///returns integer indexes of voxel whose center is closest to the coordinate triplet inline void enclosingVoxel(const float* coordIn, int64_t& indexOut1, int64_t& indexOut2, int64_t& indexOut3) const { enclosingVoxel(coordIn[0], coordIn[1], coordIn[2], indexOut1, indexOut2, indexOut3); } ///returns integer indexes of voxel whose center is closest to the three coordinates void enclosingVoxel(const float& coordIn1, const float& coordIn2, const float& coordIn3, int64_t& indexOut1, int64_t& indexOut2, int64_t& indexOut3) const; template inline bool indexValid(const T* indexIn) const { return indexValid(indexIn[0], indexIn[1], indexIn[2]);//implicit cast to int64_t } ///checks if an index is within array dimensions inline bool indexValid(const int64_t& indexIn1, const int64_t& indexIn2, const int64_t& indexIn3) const { if (indexIn1 < 0 || indexIn1 >= m_dims[0]) return false; if (indexIn2 < 0 || indexIn2 >= m_dims[1]) return false; if (indexIn3 < 0 || indexIn3 >= m_dims[2]) return false; return true; } inline int64_t getIndex(const int64_t& indexIn1, const int64_t& indexIn2, const int64_t& indexIn3) const { CaretAssert(indexValid(indexIn1, indexIn2, indexIn3)); return indexIn1 + m_dims[0] * (indexIn2 + m_dims[1] * indexIn3); } template inline int64_t getIndex(const T* indexIn) const { return getIndex(indexIn[0], indexIn[1], indexIn[2]);//implicit cast to int64_t } void readCiftiXML1(QXmlStreamReader& xml);//xml functions void readCiftiXML2(QXmlStreamReader& xml); void writeCiftiXML1(QXmlStreamWriter& xml) const; void writeCiftiXML2(QXmlStreamWriter& xml) const; }; template void VolumeSpace::indexToSpace(const T& indexIn1, const T& indexIn2, const T& indexIn3, float& coordOut1, float& coordOut2, float& coordOut3) const { coordOut1 = indexIn1 * m_sform[0][0] + indexIn2 * m_sform[0][1] + indexIn3 * m_sform[0][2] + m_sform[0][3]; coordOut2 = indexIn1 * m_sform[1][0] + indexIn2 * m_sform[1][1] + indexIn3 * m_sform[1][2] + m_sform[1][3]; coordOut3 = indexIn1 * m_sform[2][0] + indexIn2 * m_sform[2][1] + indexIn3 * m_sform[2][2] + m_sform[2][3]; } } #endif //__VOLUME_SPACE_H__ connectome-workbench-1.4.2/src/FilesBase/nifti1.h000077500000000000000000002054021360521144700216300ustar00rootroot00000000000000#ifndef _NIFTI_HEADER_ #define _NIFTI_HEADER_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /* * NOTE: our version is slightly modified, mainly turning #define into const int32_t */ /***************************************************************************** ** This file defines the "NIFTI-1" header format. ** ** It is derived from 2 meetings at the NIH (31 Mar 2003 and ** ** 02 Sep 2003) of the Data Format Working Group (DFWG), ** ** chartered by the NIfTI (Neuroimaging Informatics Technology ** ** Initiative) at the National Institutes of Health (NIH). ** **--------------------------------------------------------------** ** Neither the National Institutes of Health (NIH), the DFWG, ** ** nor any of the members or employees of these institutions ** ** imply any warranty of usefulness of this material for any ** ** purpose, and do not assume any liability for damages, ** ** incidental or otherwise, caused by any use of this document. ** ** If these conditions are not acceptable, do not use this! ** **--------------------------------------------------------------** ** Author: Robert W Cox (NIMH, Bethesda) ** ** Advisors: John Ashburner (FIL, London), ** ** Stephen Smith (FMRIB, Oxford), ** ** Mark Jenkinson (FMRIB, Oxford) ** ******************************************************************************/ /*---------------------------------------------------------------------------*/ /* Note that the ANALYZE 7.5 file header (dbh.h) is (c) Copyright 1986-1995 Biomedical Imaging Resource Mayo Foundation Incorporation of components of dbh.h are by permission of the Mayo Foundation. Changes from the ANALYZE 7.5 file header in this file are released to the public domain, including the functional comments and any amusing asides. -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /*! INTRODUCTION TO NIFTI-1: ------------------------ The twin (and somewhat conflicting) goals of this modified ANALYZE 7.5 format are: (a) To add information to the header that will be useful for functional neuroimaging data analysis and display. These additions include: - More basic data types. - Two affine transformations to specify voxel coordinates. - "Intent" codes and parameters to describe the meaning of the data. - Affine scaling of the stored data values to their "true" values. - Optional storage of the header and image data in one file (.nii). (b) To maintain compatibility with non-NIFTI-aware ANALYZE 7.5 compatible software (i.e., such a program should be able to do something useful with a NIFTI-1 dataset -- at least, with one stored in a traditional .img/.hdr file pair). Most of the unused fields in the ANALYZE 7.5 header have been taken, and some of the lesser-used fields have been co-opted for other purposes. Notably, most of the data_history substructure has been co-opted for other purposes, since the ANALYZE 7.5 format describes this substructure as "not required". NIFTI-1 FLAG (MAGIC STRINGS): ---------------------------- To flag such a struct as being conformant to the NIFTI-1 spec, the last 4 bytes of the header must be either the C String "ni1" or "n+1"; in hexadecimal, the 4 bytes 6E 69 31 00 or 6E 2B 31 00 (in any future version of this format, the '1' will be upgraded to '2', etc.). Normally, such a "magic number" or flag goes at the start of the file, but trying to avoid clobbering widely-used ANALYZE 7.5 fields led to putting this marker last. However, recall that "the last shall be first" (Matthew 20:16). If a NIFTI-aware program reads a header file that is NOT marked with a NIFTI magic string, then it should treat the header as an ANALYZE 7.5 structure. NIFTI-1 FILE STORAGE: -------------------- "ni1" means that the image data is stored in the ".img" file corresponding to the header file (starting at file offset 0). "n+1" means that the image data is stored in the same file as the header information. We recommend that the combined header+data filename suffix be ".nii". When the dataset is stored in one file, the first byte of image data is stored at byte location (int)vox_offset in this combined file. The minimum allowed value of vox_offset is 352; for compatibility with some software, vox_offset should be an integral multiple of 16. GRACE UNDER FIRE: ---------------- Most NIFTI-aware programs will only be able to handle a subset of the full range of datasets possible with this format. All NIFTI-aware programs should take care to check if an input dataset conforms to the program's needs and expectations (e.g., check datatype, intent_code, etc.). If the input dataset can't be handled by the program, the program should fail gracefully (e.g., print a useful warning; not crash). SAMPLE CODES: ------------ The associated files nifti1_io.h and nifti1_io.c provide a sample implementation in C of a set of functions to read, write, and manipulate NIFTI-1 files. The file nifti1_test.c is a sample program that uses the nifti1_io.c functions. -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* HEADER STRUCT DECLARATION: ------------------------- In the comments below for each field, only NIFTI-1 specific requirements or changes from the ANALYZE 7.5 format are described. For convenience, the 348 byte header is described as a single struct, rather than as the ANALYZE 7.5 group of 3 substructs. Further comments about the interpretation of various elements of this header are after the data type definition itself. Fields that are marked as ++UNUSED++ have no particular interpretation in this standard. (Also see the UNUSED FIELDS comment section, far below.) The presumption below is that the various C types have particular sizes: sizeof(int) = sizeof(float) = 4 ; sizeof(short) = 2 -----------------------------------------------------------------------------*/ /*=================*/ #ifdef __cplusplus extern "C" { #endif /*=================*/ //hopefully cross-platform solution to byte padding added by some compilers #pragma pack(push) #pragma pack(1) /*! \struct nifti_1_header \brief Data structure defining the fields in the nifti1 header. This binary header should be found at the beginning of a valid NIFTI-1 header file. */ /*************************/ /************************/ struct nifti_1_header { /* NIFTI-1 usage */ /* ANALYZE 7.5 field(s) */ /*************************/ /************************/ /*--- was header_key substruct ---*/ int sizeof_hdr; /*!< MUST be 348 */ /* int sizeof_hdr; */ /* 0 */ char data_type[10]; /*!< ++UNUSED++ */ /* char data_type[10]; */ /* 4 */ char db_name[18]; /*!< ++UNUSED++ */ /* char db_name[18]; */ /* 14 */ int extents; /*!< ++UNUSED++ */ /* int extents; */ /* 32 */ short session_error; /*!< ++UNUSED++ */ /* short session_error; */ /* 36 */ char regular; /*!< ++UNUSED++ */ /* char regular; */ /* 38 */ char dim_info; /*!< MRI slice ordering. */ /* char hkey_un0; */ /* 39 */ /*--- was image_dimension substruct ---*/ short dim[8]; /*!< Data array dimensions.*/ /* short dim[8]; */ /* 40 */ float intent_p1 ; /*!< 1st intent parameter. */ /* short unused8; */ /* 56 */ /* short unused9; */ float intent_p2 ; /*!< 2nd intent parameter. */ /* short unused10; */ /* 60 */ /* short unused11; */ float intent_p3 ; /*!< 3rd intent parameter. */ /* short unused12; */ /* 64 */ /* short unused13; */ short intent_code ; /*!< NIFTI_INTENT_* code. */ /* short unused14; */ /* 68 */ short datatype; /*!< Defines data type! */ /* short datatype; */ /* 70 */ short bitpix; /*!< Number bits/voxel. */ /* short bitpix; */ /* 72 */ short slice_start; /*!< First slice index. */ /* short dim_un0; */ /* 74 */ float pixdim[8]; /*!< Grid spacings. */ /* float pixdim[8]; */ /* 76 */ float vox_offset; /*!< Offset into .nii file */ /* float vox_offset; */ /* 108 */ float scl_slope ; /*!< Data scaling: slope. */ /* float funused1; */ /* 112 */ float scl_inter ; /*!< Data scaling: offset. */ /* float funused2; */ /* 116 */ short slice_end; /*!< Last slice index. */ /* float funused3; */ /* 120 */ char slice_code ; /*!< Slice timing order. */ /* 122 */ char xyzt_units ; /*!< Units of pixdim[1..4] */ /* 123 */ float cal_max; /*!< Max display intensity */ /* float cal_max; */ /* 124 */ float cal_min; /*!< Min display intensity */ /* float cal_min; */ /* 128 */ float slice_duration;/*!< Time for 1 slice. */ /* float compressed; */ /* 132 */ float toffset; /*!< Time axis shift. */ /* float verified; */ /* 136 */ int glmax; /*!< ++UNUSED++ */ /* int glmax; */ /* 140 */ int glmin; /*!< ++UNUSED++ */ /* int glmin; */ /* 144 */ /*--- was data_history substruct ---*/ char descrip[80]; /*!< any text you like. */ /* char descrip[80]; */ /* 148 */ char aux_file[24]; /*!< auxiliary filename. */ /* char aux_file[24]; */ /* 228 */ short qform_code ; /*!< NIFTI_XFORM_* code. */ /*-- all ANALYZE 7.5 ---*/ /* 252 */ short sform_code ; /*!< NIFTI_XFORM_* code. */ /* fields below here */ /* 254 */ /* are replaced */ float quatern_b ; /*!< Quaternion b param. */ /* 256 */ float quatern_c ; /*!< Quaternion c param. */ /* 260 */ float quatern_d ; /*!< Quaternion d param. */ /* 264 */ float qoffset_x ; /*!< Quaternion x shift. */ /* 268 */ float qoffset_y ; /*!< Quaternion y shift. */ /* 272 */ float qoffset_z ; /*!< Quaternion z shift. */ /* 276 */ float srow_x[4] ; /*!< 1st row affine transform. */ /* 280 */ float srow_y[4] ; /*!< 2nd row affine transform. */ /* 296 */ float srow_z[4] ; /*!< 3rd row affine transform. */ /* 312 */ char intent_name[16];/*!< 'name' or meaning of data. */ /* 328 */ char magic[4] ; /*!< MUST be "ni1\0" or "n+1\0". */ /* 344 */ } ; /**** 348 bytes total ****/ typedef struct nifti_1_header nifti_1_header ; /*---------------------------------------------------------------------------*/ /* HEADER EXTENSIONS: ----------------- After the end of the 348 byte header (e.g., after the magic field), the next 4 bytes are a char array field named "extension". By default, all 4 bytes of this array should be set to zero. In a .nii file, these 4 bytes will always be present, since the earliest start point for the image data is byte #352. In a separate .hdr file, these bytes may or may not be present. If not present (i.e., if the length of the .hdr file is 348 bytes), then a NIfTI-1 compliant program should use the default value of extension={0,0,0,0}. The first byte (extension[0]) is the only value of this array that is specified at present. The other 3 bytes are reserved for future use. If extension[0] is nonzero, it indicates that extended header information is present in the bytes following the extension array. In a .nii file, this extended header data is before the image data (and vox_offset must be set correctly to allow for this). In a .hdr file, this extended data follows extension and proceeds (potentially) to the end of the file. The format of extended header data is weakly specified. Each extension must be an integer multiple of 16 bytes long. The first 8 bytes of each extension comprise 2 integers: int esize , ecode ; These values may need to be byte-swapped, as indicated by dim[0] for the rest of the header. * esize is the number of bytes that form the extended header data + esize must be a positive integral multiple of 16 + this length includes the 8 bytes of esize and ecode themselves * ecode is a non-negative integer that indicates the format of the extended header data that follows + different ecode values are assigned to different developer groups + at present, the "registered" values for code are = 0 = unknown private format (not recommended!) = 2 = DICOM format (i.e., attribute tags and values) = 4 = AFNI group (i.e., ASCII XML-ish elements) In the interests of interoperability (a primary rationale for NIfTI), groups developing software that uses this extension mechanism are encouraged to document and publicize the format of their extensions. To this end, the NIfTI DFWG will assign even numbered codes upon request to groups submitting at least rudimentary documentation for the format of their extension; at present, the contact is mailto:rwcox@nih.gov. The assigned codes and documentation will be posted on the NIfTI website. All odd values of ecode (and 0) will remain unassigned; at least, until the even ones are used up, when we get to 2,147,483,646. Note that the other contents of the extended header data section are totally unspecified by the NIfTI-1 standard. In particular, if binary data is stored in such a section, its byte order is not necessarily the same as that given by examining dim[0]; it is incumbent on the programs dealing with such data to determine the byte order of binary extended header data. Multiple extended header sections are allowed, each starting with an esize,ecode value pair. The first esize value, as described above, is at bytes #352-355 in the .hdr or .nii file (files start at byte #0). If this value is positive, then the second (esize2) will be found starting at byte #352+esize1 , the third (esize3) at byte #352+esize1+esize2, et cetera. Of course, in a .nii file, the value of vox_offset must be compatible with these extensions. If a malformed file indicates that an extended header data section would run past vox_offset, then the entire extended header section should be ignored. In a .hdr file, if an extended header data section would run past the end-of-file, that extended header data should also be ignored. With the above scheme, a program can successively examine the esize and ecode values, and skip over each extended header section if the program doesn't know how to interpret the data within. Of course, any program can simply ignore all extended header sections simply by jumping straight to the image data using vox_offset. -----------------------------------------------------------------------------*/ /*! \struct nifti1_extender \brief This structure represents a 4-byte string that should follow the binary nifti_1_header data in a NIFTI-1 header file. If the char values are {1,0,0,0}, the file is expected to contain extensions, values of {0,0,0,0} imply the file does not contain extensions. Other sequences of values are not currently defined. */ struct nifti1_extender { char extension[4] ; } ; typedef struct nifti1_extender nifti1_extender ; /*! \struct nifti1_extension \brief Data structure defining the fields of a header extension. */ struct nifti1_extension { int esize ; /*!< size of extension, in bytes (must be multiple of 16) */ int ecode ; /*!< extension code, one of the NIFTI_ECODE_ values */ char * edata ; /*!< raw data, with no byte swapping */ } ; typedef struct nifti1_extension nifti1_extension ; //and restore packing behavior #pragma pack(pop) /*---------------------------------------------------------------------------*/ /* DATA DIMENSIONALITY (as in ANALYZE 7.5): --------------------------------------- dim[0] = number of dimensions; - if dim[0] is outside range 1..7, then the header information needs to be byte swapped appropriately - ANALYZE supports dim[0] up to 7, but NIFTI-1 reserves dimensions 1,2,3 for space (x,y,z), 4 for time (t), and 5,6,7 for anything else needed. dim[i] = length of dimension #i, for i=1..dim[0] (must be positive) - also see the discussion of intent_code, far below pixdim[i] = voxel width along dimension #i, i=1..dim[0] (positive) - cf. ORIENTATION section below for use of pixdim[0] - the units of pixdim can be specified with the xyzt_units field (also described far below). Number of bits per voxel value is in bitpix, which MUST correspond with the datatype field. The total number of bytes in the image data is dim[1] * ... * dim[dim[0]] * bitpix / 8 In NIFTI-1 files, dimensions 1,2,3 are for space, dimension 4 is for time, and dimension 5 is for storing multiple values at each spatiotemporal voxel. Some examples: - A typical whole-brain FMRI experiment's time series: - dim[0] = 4 - dim[1] = 64 pixdim[1] = 3.75 xyzt_units = NIFTI_UNITS_MM - dim[2] = 64 pixdim[2] = 3.75 | NIFTI_UNITS_SEC - dim[3] = 20 pixdim[3] = 5.0 - dim[4] = 120 pixdim[4] = 2.0 - A typical T1-weighted anatomical volume: - dim[0] = 3 - dim[1] = 256 pixdim[1] = 1.0 xyzt_units = NIFTI_UNITS_MM - dim[2] = 256 pixdim[2] = 1.0 - dim[3] = 128 pixdim[3] = 1.1 - A single slice EPI time series: - dim[0] = 4 - dim[1] = 64 pixdim[1] = 3.75 xyzt_units = NIFTI_UNITS_MM - dim[2] = 64 pixdim[2] = 3.75 | NIFTI_UNITS_SEC - dim[3] = 1 pixdim[3] = 5.0 - dim[4] = 1200 pixdim[4] = 0.2 - A 3-vector stored at each point in a 3D volume: - dim[0] = 5 - dim[1] = 256 pixdim[1] = 1.0 xyzt_units = NIFTI_UNITS_MM - dim[2] = 256 pixdim[2] = 1.0 - dim[3] = 128 pixdim[3] = 1.1 - dim[4] = 1 pixdim[4] = 0.0 - dim[5] = 3 intent_code = NIFTI_INTENT_VECTOR - A single time series with a 3x3 matrix at each point: - dim[0] = 5 - dim[1] = 1 xyzt_units = NIFTI_UNITS_SEC - dim[2] = 1 - dim[3] = 1 - dim[4] = 1200 pixdim[4] = 0.2 - dim[5] = 9 intent_code = NIFTI_INTENT_GENMATRIX - intent_p1 = intent_p2 = 3.0 (indicates matrix dimensions) -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* DATA STORAGE: ------------ If the magic field is "n+1", then the voxel data is stored in the same file as the header. In this case, the voxel data starts at offset (int)vox_offset into the header file. Thus, vox_offset=352.0 means that the data starts immediately after the NIFTI-1 header. If vox_offset is greater than 352, the NIFTI-1 format does not say much about the contents of the dataset file between the end of the header and the start of the data. FILES: ----- If the magic field is "ni1", then the voxel data is stored in the associated ".img" file, starting at offset 0 (i.e., vox_offset is not used in this case, and should be set to 0.0). When storing NIFTI-1 datasets in pairs of files, it is customary to name the files in the pattern "name.hdr" and "name.img", as in ANALYZE 7.5. When storing in a single file ("n+1"), the file name should be in the form "name.nii" (the ".nft" and ".nif" suffixes are already taken; cf. http://www.icdatamaster.com/n.html ). BYTE ORDERING: ------------- The byte order of the data arrays is presumed to be the same as the byte order of the header (which is determined by examining dim[0]). Floating point types are presumed to be stored in IEEE-754 format. -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* DETAILS ABOUT vox_offset: ------------------------ In a .nii file, the vox_offset field value is interpreted as the start location of the image data bytes in that file. In a .hdr/.img file pair, the vox_offset field value is the start location of the image data bytes in the .img file. * If vox_offset is less than 352 in a .nii file, it is equivalent to 352 (i.e., image data never starts before byte #352 in a .nii file). * The default value for vox_offset in a .nii file is 352. * In a .hdr file, the default value for vox_offset is 0. * vox_offset should be an integer multiple of 16; otherwise, some programs may not work properly (e.g., SPM). This is to allow memory-mapped input to be properly byte-aligned. Note that since vox_offset is an IEEE-754 32 bit float (for compatibility with the ANALYZE-7.5 format), it effectively has a 24 bit mantissa. All integers from 0 to 2^24 can be represented exactly in this format, but not all larger integers are exactly storable as IEEE-754 32 bit floats. However, unless you plan to have vox_offset be potentially larger than 16 MB, this should not be an issue. (Actually, any integral multiple of 16 up to 2^27 can be represented exactly in this format, which allows for up to 128 MB of random information before the image data. If that isn't enough, then perhaps this format isn't right for you.) In a .img file (i.e., image data stored separately from the NIfTI-1 header), data bytes between #0 and #vox_offset-1 (inclusive) are completely undefined and unregulated by the NIfTI-1 standard. One potential use of having vox_offset > 0 in the .hdr/.img file pair storage method is to make the .img file be a copy of (or link to) a pre-existing image file in some other format, such as DICOM; then vox_offset would be set to the offset of the image data in this file. (It may not be possible to follow the "multiple-of-16 rule" with an arbitrary external file; using the NIfTI-1 format in such a case may lead to a file that is incompatible with software that relies on vox_offset being a multiple of 16.) In a .nii file, data bytes between #348 and #vox_offset-1 (inclusive) may be used to store user-defined extra information; similarly, in a .hdr file, any data bytes after byte #347 are available for user-defined extra information. The (very weak) regulation of this extra header data is described elsewhere. -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* DATA SCALING: ------------ If the scl_slope field is nonzero, then each voxel value in the dataset should be scaled as y = scl_slope * x + scl_inter where x = voxel value stored y = "true" voxel value Normally, we would expect this scaling to be used to store "true" floating values in a smaller integer datatype, but that is not required. That is, it is legal to use scaling even if the datatype is a float type (crazy, perhaps, but legal). - However, the scaling is to be ignored if datatype is DT_RGB24. - If datatype is a complex type, then the scaling is to be applied to both the real and imaginary parts. The cal_min and cal_max fields (if nonzero) are used for mapping (possibly scaled) dataset values to display colors: - Minimum display intensity (black) corresponds to dataset value cal_min. - Maximum display intensity (white) corresponds to dataset value cal_max. - Dataset values below cal_min should display as black also, and values above cal_max as white. - Colors "black" and "white", of course, may refer to any scalar display scheme (e.g., a color lookup table specified via aux_file). - cal_min and cal_max only make sense when applied to scalar-valued datasets (i.e., dim[0] < 5 or dim[5] = 1). -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* TYPE OF DATA (acceptable values for datatype field): --------------------------------------------------- Values of datatype smaller than 256 are ANALYZE 7.5 compatible. Larger values are NIFTI-1 additions. These are all multiples of 256, so that no bits below position 8 are set in datatype. But there is no need to use only powers-of-2, as the original ANALYZE 7.5 datatype codes do. The additional codes are intended to include a complete list of basic scalar types, including signed and unsigned integers from 8 to 64 bits, floats from 32 to 128 bits, and complex (float pairs) from 64 to 256 bits. Note that most programs will support only a few of these datatypes! A NIFTI-1 program should fail gracefully (e.g., print a warning message) when it encounters a dataset with a type it doesn't like. -----------------------------------------------------------------------------*/ #undef DT_UNKNOWN /* defined in dirent.h on some Unix systems */ #include /*! \defgroup NIFTI1_DATATYPES \brief nifti1 datatype codes @{ */ /*--- the original ANALYZE 7.5 type codes ---*/ const int32_t DT_NONE =0; const int32_t DT_UNKNOWN =0; /* what it says, dude */ const int32_t DT_BINARY =1; /* binary (1 bit/voxel) */ const int32_t DT_UNSIGNED_CHAR =2; /* unsigned char (8 bits/voxel) */ const int32_t DT_SIGNED_SHORT =4; /* signed short (16 bits/voxel) */ const int32_t DT_SIGNED_INT =8; /* signed int (32 bits/voxel) */ const int32_t DT_FLOAT =16; /* float (32 bits/voxel) */ const int32_t DT_COMPLEX =32; /* complex (64 bits/voxel) */ const int32_t DT_DOUBLE =64; /* double (64 bits/voxel) */ const int32_t DT_RGB =128; /* RGB triple (24 bits/voxel) */ const int32_t DT_ALL =255; /* not very useful (?) */ /*----- another set of names for the same ---*/ const int32_t DT_UINT8 =2; const int32_t DT_INT16 =4; const int32_t DT_INT32 =8; const int32_t DT_FLOAT32 =16; const int32_t DT_COMPLEX64 =32; const int32_t DT_FLOAT64 =64; const int32_t DT_RGB24 =128; /*------------------- new codes for NIFTI ---*/ const int32_t DT_INT8 =256; /* signed char (8 bits) */ const int32_t DT_UINT16 =512; /* unsigned short (16 bits) */ const int32_t DT_UINT32 =768; /* unsigned int (32 bits) */ const int32_t DT_INT64 =1024; /* long long (64 bits) */ const int32_t DT_UINT64 =1280; /* unsigned long long (64 bits) */ const int32_t DT_FLOAT128 =1536; /* long double (128 bits) */ const int32_t DT_COMPLEX128 =1792; /* double pair (128 bits) */ const int32_t DT_COMPLEX256 =2048; /* long double pair (256 bits) */ /* @} */ /*------- aliases for all the above codes ---*/ /*! \defgroup NIFTI1_DATATYPE_ALIASES \brief aliases for the nifti1 datatype codes @{ */ /*! unsigned char. */ const int32_t NIFTI_TYPE_UINT8 =2; /*! signed short. */ const int32_t NIFTI_TYPE_INT16 =4; /*! signed int. */ const int32_t NIFTI_TYPE_INT32 =8; /*! 32 bit float. */ const int32_t NIFTI_TYPE_FLOAT32 =16; /*! 64 bit complex = 2 32 bit floats. */ const int32_t NIFTI_TYPE_COMPLEX64 =32; /*! 64 bit float = double. */ const int32_t NIFTI_TYPE_FLOAT64 =64; /*! 3 8 bit bytes. */ const int32_t NIFTI_TYPE_RGB24 =128; /*! signed char. */ const int32_t NIFTI_TYPE_INT8 =256; /*! unsigned short. */ const int32_t NIFTI_TYPE_UINT16 =512; /*! unsigned int. */ const int32_t NIFTI_TYPE_UINT32 =768; /*! signed long long. */ const int32_t NIFTI_TYPE_INT64 =1024; /*! unsigned long long. */ const int32_t NIFTI_TYPE_UINT64 =1280; /*! 128 bit float = long double. */ const int32_t NIFTI_TYPE_FLOAT128 =1536; /*! 128 bit complex = 2 64 bit floats. */ const int32_t NIFTI_TYPE_COMPLEX128 =1792; /*! 256 bit complex = 2 128 bit floats */ const int32_t NIFTI_TYPE_COMPLEX256 =2048; /* @} */ /*-------- sample typedefs for complicated types ---*/ #if 0 typedef struct { float r,i; } complex_float ; typedef struct { double r,i; } complex_double ; typedef struct { long double r,i; } complex_longdouble ; typedef struct { unsigned char r,g,b; } rgb_byte ; #endif /*---------------------------------------------------------------------------*/ /* INTERPRETATION OF VOXEL DATA: ---------------------------- The intent_code field can be used to indicate that the voxel data has some particular meaning. In particular, a large number of codes is given to indicate that the the voxel data should be interpreted as being drawn from a given probability distribution. VECTOR-VALUED DATASETS: ---------------------- The 5th dimension of the dataset, if present (i.e., dim[0]=5 and dim[5] > 1), contains multiple values (e.g., a vector) to be stored at each spatiotemporal location. For example, the header values - dim[0] = 5 - dim[1] = 64 - dim[2] = 64 - dim[3] = 20 - dim[4] = 1 (indicates no time axis) - dim[5] = 3 - datatype = DT_FLOAT - intent_code = NIFTI_INTENT_VECTOR mean that this dataset should be interpreted as a 3D volume (64x64x20), with a 3-vector of floats defined at each point in the 3D grid. A program reading a dataset with a 5th dimension may want to reformat the image data to store each voxels' set of values together in a struct or array. This programming detail, however, is beyond the scope of the NIFTI-1 file specification! Uses of dimensions 6 and 7 are also not specified here. STATISTICAL PARAMETRIC DATASETS (i.e., SPMs): -------------------------------------------- Values of intent_code from NIFTI_FIRST_STATCODE to NIFTI_LAST_STATCODE (inclusive) indicate that the numbers in the dataset should be interpreted as being drawn from a given distribution. Most such distributions have auxiliary parameters (e.g., NIFTI_INTENT_TTEST has 1 DOF parameter). If the dataset DOES NOT have a 5th dimension, then the auxiliary parameters are the same for each voxel, and are given in header fields intent_p1, intent_p2, and intent_p3. If the dataset DOES have a 5th dimension, then the auxiliary parameters are different for each voxel. For example, the header values - dim[0] = 5 - dim[1] = 128 - dim[2] = 128 - dim[3] = 1 (indicates a single slice) - dim[4] = 1 (indicates no time axis) - dim[5] = 2 - datatype = DT_FLOAT - intent_code = NIFTI_INTENT_TTEST mean that this is a 2D dataset (128x128) of t-statistics, with the t-statistic being in the first "plane" of data and the degrees-of-freedom parameter being in the second "plane" of data. If the dataset 5th dimension is used to store the voxel-wise statistical parameters, then dim[5] must be 1 plus the number of parameters required by that distribution (e.g., intent_code=NIFTI_INTENT_TTEST implies dim[5] must be 2, as in the example just above). Note: intent_code values 2..10 are compatible with AFNI 1.5x (which is why there is no code with value=1, which is obsolescent in AFNI). OTHER INTENTIONS: ---------------- The purpose of the intent_* fields is to help interpret the values stored in the dataset. Some non-statistical values for intent_code and conventions are provided for storing other complex data types. The intent_name field provides space for a 15 character (plus 0 byte) 'name' string for the type of data stored. Examples: - intent_code = NIFTI_INTENT_ESTIMATE; intent_name = "T1"; could be used to signify that the voxel values are estimates of the NMR parameter T1. - intent_code = NIFTI_INTENT_TTEST; intent_name = "House"; could be used to signify that the voxel values are t-statistics for the significance of 'activation' response to a House stimulus. - intent_code = NIFTI_INTENT_DISPVECT; intent_name = "ToMNI152"; could be used to signify that the voxel values are a displacement vector that transforms each voxel (x,y,z) location to the corresponding location in the MNI152 standard brain. - intent_code = NIFTI_INTENT_SYMMATRIX; intent_name = "DTI"; could be used to signify that the voxel values comprise a diffusion tensor image. If no data name is implied or needed, intent_name[0] should be set to 0. -----------------------------------------------------------------------------*/ /*! default: no intention is indicated in the header. */ const int32_t NIFTI_INTENT_NONE =0; /*-------- These codes are for probability distributions ---------------*/ /* Most distributions have a number of parameters, below denoted by p1, p2, and p3, and stored in - intent_p1, intent_p2, intent_p3 if dataset doesn't have 5th dimension - image data array if dataset does have 5th dimension Functions to compute with many of the distributions below can be found in the CDF library from U Texas. Formulas for and discussions of these distributions can be found in the following books: [U] Univariate Discrete Distributions, NL Johnson, S Kotz, AW Kemp. [C1] Continuous Univariate Distributions, vol. 1, NL Johnson, S Kotz, N Balakrishnan. [C2] Continuous Univariate Distributions, vol. 2, NL Johnson, S Kotz, N Balakrishnan. */ /*----------------------------------------------------------------------*/ /*! [C2, chap 32] Correlation coefficient R (1 param): p1 = degrees of freedom R/sqrt(1-R*R) is t-distributed with p1 DOF. */ /*! \defgroup NIFTI1_INTENT_CODES \brief nifti1 intent codes, to describe intended meaning of dataset contents @{ */ const int32_t NIFTI_INTENT_CORREL =2; /*! [C2, chap 28] Student t statistic (1 param): p1 = DOF. */ const int32_t NIFTI_INTENT_TTEST =3; /*! [C2, chap 27] Fisher F statistic (2 params): p1 = numerator DOF, p2 = denominator DOF. */ const int32_t NIFTI_INTENT_FTEST =4; /*! [C1, chap 13] Standard normal (0 params): Density = N(0,1). */ const int32_t NIFTI_INTENT_ZSCORE =5; /*! [C1, chap 18] Chi-squared (1 param): p1 = DOF. Density(x) proportional to exp(-x/2) * x^(p1/2-1). */ const int32_t NIFTI_INTENT_CHISQ =6; /*! [C2, chap 25] Beta distribution (2 params): p1=a, p2=b. Density(x) proportional to x^(a-1) * (1-x)^(b-1). */ const int32_t NIFTI_INTENT_BETA =7; /*! [U, chap 3] Binomial distribution (2 params): p1 = number of trials, p2 = probability per trial. Prob(x) = (p1 choose x) * p2^x * (1-p2)^(p1-x), for x=0,1,...,p1. */ const int32_t NIFTI_INTENT_BINOM =8; /*! [C1, chap 17] Gamma distribution (2 params): p1 = shape, p2 = scale. Density(x) proportional to x^(p1-1) * exp(-p2*x). */ const int32_t NIFTI_INTENT_GAMMA =9; /*! [U, chap 4] Poisson distribution (1 param): p1 = mean. Prob(x) = exp(-p1) * p1^x / x! , for x=0,1,2,.... */ const int32_t NIFTI_INTENT_POISSON =10; /*! [C1, chap 13] Normal distribution (2 params): p1 = mean, p2 = standard deviation. */ const int32_t NIFTI_INTENT_NORMAL =11; /*! [C2, chap 30] Noncentral F statistic (3 params): p1 = numerator DOF, p2 = denominator DOF, p3 = numerator noncentrality parameter. */ const int32_t NIFTI_INTENT_FTEST_NONC=12; /*! [C2, chap 29] Noncentral chi-squared statistic (2 params): p1 = DOF, p2 = noncentrality parameter. */ const int32_t NIFTI_INTENT_CHISQ_NONC=13; /*! [C2, chap 23] Logistic distribution (2 params): p1 = location, p2 = scale. Density(x) proportional to sech^2((x-p1)/(2*p2)). */ const int32_t NIFTI_INTENT_LOGISTIC =14; /*! [C2, chap 24] Laplace distribution (2 params): p1 = location, p2 = scale. Density(x) proportional to exp(-abs(x-p1)/p2). */ const int32_t NIFTI_INTENT_LAPLACE =15; /*! [C2, chap 26] Uniform distribution: p1 = lower end, p2 = upper end. */ const int32_t NIFTI_INTENT_UNIFORM =16; /*! [C2, chap 31] Noncentral t statistic (2 params): p1 = DOF, p2 = noncentrality parameter. */ const int32_t NIFTI_INTENT_TTEST_NONC=17; /*! [C1, chap 21] Weibull distribution (3 params): p1 = location, p2 = scale, p3 = power. Density(x) proportional to ((x-p1)/p2)^(p3-1) * exp(-((x-p1)/p2)^p3) for x > p1. */ const int32_t NIFTI_INTENT_WEIBULL =18; /*! [C1, chap 18] Chi distribution (1 param): p1 = DOF. Density(x) proportional to x^(p1-1) * exp(-x^2/2) for x > 0. p1 = 1 = 'half normal' distribution p1 = 2 = Rayleigh distribution p1 = 3 = Maxwell-Boltzmann distribution. */ const int32_t NIFTI_INTENT_CHI =19; /*! [C1, chap 15] Inverse Gaussian (2 params): p1 = mu, p2 = lambda Density(x) proportional to exp(-p2*(x-p1)^2/(2*p1^2*x)) / x^3 for x > 0. */ const int32_t NIFTI_INTENT_INVGAUSS =20; /*! [C2, chap 22] Extreme value type I (2 params): p1 = location, p2 = scale cdf(x) = exp(-exp(-(x-p1)/p2)). */ const int32_t NIFTI_INTENT_EXTVAL =21; /*! Data is a 'p-value' (no params). */ const int32_t NIFTI_INTENT_PVAL =22; /*! Data is ln(p-value) (no params). To be safe, a program should compute p = exp(-abs(this_value)). The nifti_stats.c library returns this_value as positive, so that this_value = -log(p). */ const int32_t NIFTI_INTENT_LOGPVAL =23; /*! Data is log10(p-value) (no params). To be safe, a program should compute p = pow(10.,-abs(this_value)). The nifti_stats.c library returns this_value as positive, so that this_value = -log10(p). */ const int32_t NIFTI_INTENT_LOG10PVAL =24; /*! Smallest intent_code that indicates a statistic. */ const int32_t NIFTI_FIRST_STATCODE =2; /*! Largest intent_code that indicates a statistic. */ const int32_t NIFTI_LAST_STATCODE =24; /*---------- these values for intent_code aren't for statistics ----------*/ /*! To signify that the value at each voxel is an estimate of some parameter, set intent_code = NIFTI_INTENT_ESTIMATE. The name of the parameter may be stored in intent_name. */ const int32_t NIFTI_INTENT_ESTIMATE =1001; /*! To signify that the value at each voxel is an index into some set of labels, set intent_code = NIFTI_INTENT_LABEL. The filename with the labels may stored in aux_file. */ const int32_t NIFTI_INTENT_LABEL =1002; /*! To signify that the value at each voxel is an index into the NeuroNames labels set, set intent_code = NIFTI_INTENT_NEURONAME. */ const int32_t NIFTI_INTENT_NEURONAME=1003; /*! To store an M x N matrix at each voxel: - dataset must have a 5th dimension (dim[0]=5 and dim[5]>1) - intent_code must be NIFTI_INTENT_GENMATRIX - dim[5] must be M*N - intent_p1 must be M (in float format) - intent_p2 must be N (ditto) - the matrix values A[i][[j] are stored in row-order: - A[0][0] A[0][1] ... A[0][N-1] - A[1][0] A[1][1] ... A[1][N-1] - etc., until - A[M-1][0] A[M-1][1] ... A[M-1][N-1] */ const int32_t NIFTI_INTENT_GENMATRIX=1004; /*! To store an NxN symmetric matrix at each voxel: - dataset must have a 5th dimension - intent_code must be NIFTI_INTENT_SYMMATRIX - dim[5] must be N*(N+1)/2 - intent_p1 must be N (in float format) - the matrix values A[i][[j] are stored in row-order: - A[0][0] - A[1][0] A[1][1] - A[2][0] A[2][1] A[2][2] - etc.: row-by-row */ const int32_t NIFTI_INTENT_SYMMATRIX=1005; /*! To signify that the vector value at each voxel is to be taken as a displacement field or vector: - dataset must have a 5th dimension - intent_code must be NIFTI_INTENT_DISPVECT - dim[5] must be the dimensionality of the displacment vector (e.g., 3 for spatial displacement, 2 for in-plane) */ const int32_t NIFTI_INTENT_DISPVECT =1006; /* specifically for displacements */ const int32_t NIFTI_INTENT_VECTOR =1007; /* for any other type of vector */ /*! To signify that the vector value at each voxel is really a spatial coordinate (e.g., the vertices or nodes of a surface mesh): - dataset must have a 5th dimension - intent_code must be NIFTI_INTENT_POINTSET - dim[0] = 5 - dim[1] = number of points - dim[2] = dim[3] = dim[4] = 1 - dim[5] must be the dimensionality of space (e.g., 3 => 3D space). - intent_name may describe the object these points come from (e.g., "pial", "gray/white" , "EEG", "MEG"). */ const int32_t NIFTI_INTENT_POINTSET =1008; /*! To signify that the vector value at each voxel is really a triple of indexes (e.g., forming a triangle) from a pointset dataset: - dataset must have a 5th dimension - intent_code must be NIFTI_INTENT_TRIANGLE - dim[0] = 5 - dim[1] = number of triangles - dim[2] = dim[3] = dim[4] = 1 - dim[5] = 3 - datatype should be an integer type (preferably DT_INT32) - the data values are indexes (0,1,...) into a pointset dataset. */ const int32_t NIFTI_INTENT_TRIANGLE =1009; /*! To signify that the vector value at each voxel is a quaternion: - dataset must have a 5th dimension - intent_code must be NIFTI_INTENT_QUATERNION - dim[0] = 5 - dim[5] = 4 - datatype should be a floating point type */ const int32_t NIFTI_INTENT_QUATERNION=1010; /*! Dimensionless value - no params - although, as in _ESTIMATE the name of the parameter may be stored in intent_name. */ const int32_t NIFTI_INTENT_DIMLESS =1011; /* @} */ /*---------------------------------------------------------------------------*/ /* 3D IMAGE (VOLUME) ORIENTATION AND LOCATION IN SPACE: --------------------------------------------------- There are 3 different methods by which continuous coordinates can attached to voxels. The discussion below emphasizes 3D volumes, and the continuous coordinates are referred to as (x,y,z). The voxel index coordinates (i.e., the array indexes) are referred to as (i,j,k), with valid ranges: i = 0 .. dim[1]-1 j = 0 .. dim[2]-1 (if dim[0] >= 2) k = 0 .. dim[3]-1 (if dim[0] >= 3) The (x,y,z) coordinates refer to the CENTER of a voxel. In methods 2 and 3, the (x,y,z) axes refer to a subject-based coordinate system, with +x = Right +y = Anterior +z = Superior. This is a right-handed coordinate system. However, the exact direction these axes point with respect to the subject depends on qform_code (Method 2) and sform_code (Method 3). N.B.: The i index varies most rapidly, j index next, k index slowest. Thus, voxel (i,j,k) is stored starting at location (i + j*dim[1] + k*dim[1]*dim[2]) * (bitpix/8) into the dataset array. N.B.: The ANALYZE 7.5 coordinate system is +x = Left +y = Anterior +z = Superior which is a left-handed coordinate system. This backwardness is too difficult to tolerate, so this NIFTI-1 standard specifies the coordinate order which is most common in functional neuroimaging. N.B.: The 3 methods below all give the locations of the voxel centers in the (x,y,z) coordinate system. In many cases, programs will wish to display image data on some other grid. In such a case, the program will need to convert its desired (x,y,z) values into (i,j,k) values in order to extract (or interpolate) the image data. This operation would be done with the inverse transformation to those described below. N.B.: Method 2 uses a factor 'qfac' which is either -1 or 1; qfac is stored in the otherwise unused pixdim[0]. If pixdim[0]=0.0 (which should not occur), we take qfac=1. Of course, pixdim[0] is only used when reading a NIFTI-1 header, not when reading an ANALYZE 7.5 header. N.B.: The units of (x,y,z) can be specified using the xyzt_units field. METHOD 1 (the "old" way, used only when qform_code = 0): ------------------------------------------------------- The coordinate mapping from (i,j,k) to (x,y,z) is the ANALYZE 7.5 way. This is a simple scaling relationship: x = pixdim[1] * i y = pixdim[2] * j z = pixdim[3] * k No particular spatial orientation is attached to these (x,y,z) coordinates. (NIFTI-1 does not have the ANALYZE 7.5 orient field, which is not general and is often not set properly.) This method is not recommended, and is present mainly for compatibility with ANALYZE 7.5 files. METHOD 2 (used when qform_code > 0, which should be the "normal" case): --------------------------------------------------------------------- The (x,y,z) coordinates are given by the pixdim[] scales, a rotation matrix, and a shift. This method is intended to represent "scanner-anatomical" coordinates, which are often embedded in the image header (e.g., DICOM fields (0020,0032), (0020,0037), (0028,0030), and (0018,0050)), and represent the nominal orientation and location of the data. This method can also be used to represent "aligned" coordinates, which would typically result from some post-acquisition alignment of the volume to a standard orientation (e.g., the same subject on another day, or a rigid rotation to true anatomical orientation from the tilted position of the subject in the scanner). The formula for (x,y,z) in terms of header parameters and (i,j,k) is: [ x ] [ R11 R12 R13 ] [ pixdim[1] * i ] [ qoffset_x ] [ y ] = [ R21 R22 R23 ] [ pixdim[2] * j ] + [ qoffset_y ] [ z ] [ R31 R32 R33 ] [ qfac * pixdim[3] * k ] [ qoffset_z ] The qoffset_* shifts are in the NIFTI-1 header. Note that the center of the (i,j,k)=(0,0,0) voxel (first value in the dataset array) is just (x,y,z)=(qoffset_x,qoffset_y,qoffset_z). The rotation matrix R is calculated from the quatern_* parameters. This calculation is described below. The scaling factor qfac is either 1 or -1. The rotation matrix R defined by the quaternion parameters is "proper" (has determinant 1). This may not fit the needs of the data; for example, if the image grid is i increases from Left-to-Right j increases from Anterior-to-Posterior k increases from Inferior-to-Superior Then (i,j,k) is a left-handed triple. In this example, if qfac=1, the R matrix would have to be [ 1 0 0 ] [ 0 -1 0 ] which is "improper" (determinant = -1). [ 0 0 1 ] If we set qfac=-1, then the R matrix would be [ 1 0 0 ] [ 0 -1 0 ] which is proper. [ 0 0 -1 ] This R matrix is represented by quaternion [a,b,c,d] = [0,1,0,0] (which encodes a 180 degree rotation about the x-axis). METHOD 3 (used when sform_code > 0): ----------------------------------- The (x,y,z) coordinates are given by a general affine transformation of the (i,j,k) indexes: x = srow_x[0] * i + srow_x[1] * j + srow_x[2] * k + srow_x[3] y = srow_y[0] * i + srow_y[1] * j + srow_y[2] * k + srow_y[3] z = srow_z[0] * i + srow_z[1] * j + srow_z[2] * k + srow_z[3] The srow_* vectors are in the NIFTI_1 header. Note that no use is made of pixdim[] in this method. WHY 3 METHODS? -------------- Method 1 is provided only for backwards compatibility. The intention is that Method 2 (qform_code > 0) represents the nominal voxel locations as reported by the scanner, or as rotated to some fiducial orientation and location. Method 3, if present (sform_code > 0), is to be used to give the location of the voxels in some standard space. The sform_code indicates which standard space is present. Both methods 2 and 3 can be present, and be useful in different contexts (method 2 for displaying the data on its original grid; method 3 for displaying it on a standard grid). In this scheme, a dataset would originally be set up so that the Method 2 coordinates represent what the scanner reported. Later, a registration to some standard space can be computed and inserted in the header. Image display software can use either transform, depending on its purposes and needs. In Method 2, the origin of coordinates would generally be whatever the scanner origin is; for example, in MRI, (0,0,0) is the center of the gradient coil. In Method 3, the origin of coordinates would depend on the value of sform_code; for example, for the Talairach coordinate system, (0,0,0) corresponds to the Anterior Commissure. QUATERNION REPRESENTATION OF ROTATION MATRIX (METHOD 2) ------------------------------------------------------- The orientation of the (x,y,z) axes relative to the (i,j,k) axes in 3D space is specified using a unit quaternion [a,b,c,d], where a*a+b*b+c*c+d*d=1. The (b,c,d) values are all that is needed, since we require that a = sqrt(1.0-(b*b+c*c+d*d)) be nonnegative. The (b,c,d) values are stored in the (quatern_b,quatern_c,quatern_d) fields. The quaternion representation is chosen for its compactness in representing rotations. The (proper) 3x3 rotation matrix that corresponds to [a,b,c,d] is [ a*a+b*b-c*c-d*d 2*b*c-2*a*d 2*b*d+2*a*c ] R = [ 2*b*c+2*a*d a*a+c*c-b*b-d*d 2*c*d-2*a*b ] [ 2*b*d-2*a*c 2*c*d+2*a*b a*a+d*d-c*c-b*b ] [ R11 R12 R13 ] = [ R21 R22 R23 ] [ R31 R32 R33 ] If (p,q,r) is a unit 3-vector, then rotation of angle h about that direction is represented by the quaternion [a,b,c,d] = [cos(h/2), p*sin(h/2), q*sin(h/2), r*sin(h/2)]. Requiring a >= 0 is equivalent to requiring -Pi <= h <= Pi. (Note that [-a,-b,-c,-d] represents the same rotation as [a,b,c,d]; there are 2 quaternions that can be used to represent a given rotation matrix R.) To rotate a 3-vector (x,y,z) using quaternions, we compute the quaternion product [0,x',y',z'] = [a,b,c,d] * [0,x,y,z] * [a,-b,-c,-d] which is equivalent to the matrix-vector multiply [ x' ] [ x ] [ y' ] = R [ y ] (equivalence depends on a*a+b*b+c*c+d*d=1) [ z' ] [ z ] Multiplication of 2 quaternions is defined by the following: [a,b,c,d] = a*1 + b*I + c*J + d*K where I*I = J*J = K*K = -1 (I,J,K are square roots of -1) I*J = K J*K = I K*I = J J*I = -K K*J = -I I*K = -J (not commutative!) For example [a,b,0,0] * [0,0,0,1] = [0,0,-b,a] since this expands to (a+b*I)*(K) = (a*K+b*I*K) = (a*K-b*J). The above formula shows how to go from quaternion (b,c,d) to rotation matrix and direction cosines. Conversely, given R, we can compute the fields for the NIFTI-1 header by a = 0.5 * sqrt(1+R11+R22+R33) (not stored) b = 0.25 * (R32-R23) / a => quatern_b c = 0.25 * (R13-R31) / a => quatern_c d = 0.25 * (R21-R12) / a => quatern_d If a=0 (a 180 degree rotation), alternative formulas are needed. See the nifti1_io.c function mat44_to_quatern() for an implementation of the various cases in converting R to [a,b,c,d]. Note that R-transpose (= R-inverse) would lead to the quaternion [a,-b,-c,-d]. The choice to specify the qoffset_x (etc.) values in the final coordinate system is partly to make it easy to convert DICOM images to this format. The DICOM attribute "Image Position (Patient)" (0020,0032) stores the (Xd,Yd,Zd) coordinates of the center of the first voxel. Here, (Xd,Yd,Zd) refer to DICOM coordinates, and Xd=-x, Yd=-y, Zd=z, where (x,y,z) refers to the NIFTI coordinate system discussed above. (i.e., DICOM +Xd is Left, +Yd is Posterior, +Zd is Superior, whereas +x is Right, +y is Anterior , +z is Superior. ) Thus, if the (0020,0032) DICOM attribute is extracted into (px,py,pz), then qoffset_x = -px qoffset_y = -py qoffset_z = pz is a reasonable setting when qform_code=NIFTI_XFORM_SCANNER_ANAT. That is, DICOM's coordinate system is 180 degrees rotated about the z-axis from the neuroscience/NIFTI coordinate system. To transform between DICOM and NIFTI, you just have to negate the x- and y-coordinates. The DICOM attribute (0020,0037) "Image Orientation (Patient)" gives the orientation of the x- and y-axes of the image data in terms of 2 3-vectors. The first vector is a unit vector along the x-axis, and the second is along the y-axis. If the (0020,0037) attribute is extracted into the value (xa,xb,xc,ya,yb,yc), then the first two columns of the R matrix would be [ -xa -ya ] [ -xb -yb ] [ xc yc ] The negations are because DICOM's x- and y-axes are reversed relative to NIFTI's. The third column of the R matrix gives the direction of displacement (relative to the subject) along the slice-wise direction. This orientation is not encoded in the DICOM standard in a simple way; DICOM is mostly concerned with 2D images. The third column of R will be either the cross-product of the first 2 columns or its negative. It is possible to infer the sign of the 3rd column by examining the coordinates in DICOM attribute (0020,0032) "Image Position (Patient)" for successive slices. However, this method occasionally fails for reasons that I (RW Cox) do not understand. -----------------------------------------------------------------------------*/ /* [qs]form_code value: */ /* x,y,z coordinate system refers to: */ /*-----------------------*/ /*---------------------------------------*/ /*! \defgroup NIFTI1_XFORM_CODES \brief nifti1 xform codes to describe the "standard" coordinate system @{ */ /*! Arbitrary coordinates (Method 1). */ const int32_t NIFTI_XFORM_UNKNOWN =0; /*! Scanner-based anatomical coordinates */ const int32_t NIFTI_XFORM_SCANNER_ANAT=1; /*! Coordinates aligned to another file's, or to anatomical "truth". */ const int32_t NIFTI_XFORM_ALIGNED_ANAT=2; /*! Coordinates aligned to Talairach- Tournoux Atlas; (0,0,0)=AC, etc. */ const int32_t NIFTI_XFORM_TALAIRACH =3; /*! MNI 152 normalized coordinates. */ const int32_t NIFTI_XFORM_MNI_152 =4; /* @} */ /*---------------------------------------------------------------------------*/ /* UNITS OF SPATIAL AND TEMPORAL DIMENSIONS: ---------------------------------------- The codes below can be used in xyzt_units to indicate the units of pixdim. As noted earlier, dimensions 1,2,3 are for x,y,z; dimension 4 is for time (t). - If dim[4]=1 or dim[0] < 4, there is no time axis. - A single time series (no space) would be specified with - dim[0] = 4 (for scalar data) or dim[0] = 5 (for vector data) - dim[1] = dim[2] = dim[3] = 1 - dim[4] = number of time points - pixdim[4] = time step - xyzt_units indicates units of pixdim[4] - dim[5] = number of values stored at each time point Bits 0..2 of xyzt_units specify the units of pixdim[1..3] (e.g., spatial units are values 1..7). Bits 3..5 of xyzt_units specify the units of pixdim[4] (e.g., temporal units are multiples of 8). This compression of 2 distinct concepts into 1 byte is due to the limited space available in the 348 byte ANALYZE 7.5 header. The macros XYZT_TO_SPACE and XYZT_TO_TIME can be used to mask off the undesired bits from the xyzt_units fields, leaving "pure" space and time codes. Inversely, the macro SPACE_TIME_TO_XYZT can be used to assemble a space code (0,1,2,...,7) with a time code (0,8,16,32,...,56) into the combined value for xyzt_units. Note that codes are provided to indicate the "time" axis units are actually frequency in Hertz (_HZ), in part-per-million (_PPM) or in radians-per-second (_RADS). The toffset field can be used to indicate a nonzero start point for the time axis. That is, time point #m is at t=toffset+m*pixdim[4] for m=0..dim[4]-1. -----------------------------------------------------------------------------*/ /*! \defgroup NIFTI1_UNITS \brief nifti1 units codes to describe the unit of measurement for each dimension of the dataset @{ */ /*! NIFTI code for unspecified units. */ const int32_t NIFTI_UNITS_UNKNOWN=0; /** Space codes are multiples of 1. **/ /*! NIFTI code for meters. */ const int32_t NIFTI_UNITS_METER =1; /*! NIFTI code for millimeters. */ const int32_t NIFTI_UNITS_MM =2; /*! NIFTI code for micrometers. */ const int32_t NIFTI_UNITS_MICRON =3; /** Time codes are multiples of 8. **/ /*! NIFTI code for seconds. */ const int32_t NIFTI_UNITS_SEC =8; /*! NIFTI code for milliseconds. */ const int32_t NIFTI_UNITS_MSEC =16; /*! NIFTI code for microseconds. */ const int32_t NIFTI_UNITS_USEC =24; /*** These units are for spectral data: ***/ /*! NIFTI code for Hertz. */ const int32_t NIFTI_UNITS_HZ =32; /*! NIFTI code for ppm. */ const int32_t NIFTI_UNITS_PPM =40; /*! NIFTI code for radians per second. */ const int32_t NIFTI_UNITS_RADS =48; /* @} */ #undef XYZT_TO_SPACE #undef XYZT_TO_TIME #define XYZT_TO_SPACE(xyzt) ( (xyzt) & 0x07 ) #define XYZT_TO_TIME(xyzt) ( (xyzt) & 0x38 ) #undef SPACE_TIME_TO_XYZT #define SPACE_TIME_TO_XYZT(ss,tt) ( (((char)(ss)) & 0x07) \ | (((char)(tt)) & 0x38) ) /*---------------------------------------------------------------------------*/ /* MRI-SPECIFIC SPATIAL AND TEMPORAL INFORMATION: --------------------------------------------- A few fields are provided to store some extra information that is sometimes important when storing the image data from an FMRI time series experiment. (After processing such data into statistical images, these fields are not likely to be useful.) { freq_dim } = These fields encode which spatial dimension (1,2, or 3) { phase_dim } = corresponds to which acquisition dimension for MRI data. { slice_dim } = Examples: Rectangular scan multi-slice EPI: freq_dim = 1 phase_dim = 2 slice_dim = 3 (or some permutation) Spiral scan multi-slice EPI: freq_dim = phase_dim = 0 slice_dim = 3 since the concepts of frequency- and phase-encoding directions don't apply to spiral scan slice_duration = If this is positive, AND if slice_dim is nonzero, indicates the amount of time used to acquire 1 slice. slice_duration*dim[slice_dim] can be less than pixdim[4] with a clustered acquisition method, for example. slice_code = If this is nonzero, AND if slice_dim is nonzero, AND if slice_duration is positive, indicates the timing pattern of the slice acquisition. The following codes are defined: NIFTI_SLICE_SEQ_INC == sequential increasing NIFTI_SLICE_SEQ_DEC == sequential decreasing NIFTI_SLICE_ALT_INC == alternating increasing NIFTI_SLICE_ALT_DEC == alternating decreasing NIFTI_SLICE_ALT_INC2 == alternating increasing #2 NIFTI_SLICE_ALT_DEC2 == alternating decreasing #2 { slice_start } = Indicates the start and end of the slice acquisition { slice_end } = pattern, when slice_code is nonzero. These values are present to allow for the possible addition of "padded" slices at either end of the volume, which don't fit into the slice timing pattern. If there are no padding slices, then slice_start=0 and slice_end=dim[slice_dim]-1 are the correct values. For these values to be meaningful, slice_start must be non-negative and slice_end must be greater than slice_start. Otherwise, they should be ignored. The following table indicates the slice timing pattern, relative to time=0 for the first slice acquired, for some sample cases. Here, dim[slice_dim]=7 (there are 7 slices, labeled 0..6), slice_duration=0.1, and slice_start=1, slice_end=5 (1 padded slice on each end). slice index SEQ_INC SEQ_DEC ALT_INC ALT_DEC ALT_INC2 ALT_DEC2 6 : n/a n/a n/a n/a n/a n/a n/a = not applicable 5 : 0.4 0.0 0.2 0.0 0.4 0.2 (slice time offset 4 : 0.3 0.1 0.4 0.3 0.1 0.0 doesn't apply to 3 : 0.2 0.2 0.1 0.1 0.3 0.3 slices outside 2 : 0.1 0.3 0.3 0.4 0.0 0.1 the range 1 : 0.0 0.4 0.0 0.2 0.2 0.4 slice_start .. 0 : n/a n/a n/a n/a n/a n/a slice_end) The SEQ slice_codes are sequential ordering (uncommon but not unknown), either increasing in slice number or decreasing (INC or DEC), as illustrated above. The ALT slice codes are alternating ordering. The 'standard' way for these to operate (without the '2' on the end) is for the slice timing to start at the edge of the slice_start .. slice_end group (at slice_start for INC and at slice_end for DEC). For the 'ALT_*2' slice_codes, the slice timing instead starts at the first slice in from the edge (at slice_start+1 for INC2 and at slice_end-1 for DEC2). This latter acquisition scheme is found on some Siemens scanners. The fields freq_dim, phase_dim, slice_dim are all squished into the single byte field dim_info (2 bits each, since the values for each field are limited to the range 0..3). This unpleasantness is due to lack of space in the 348 byte allowance. The macros DIM_INFO_TO_FREQ_DIM, DIM_INFO_TO_PHASE_DIM, and DIM_INFO_TO_SLICE_DIM can be used to extract these values from the dim_info byte. The macro FPS_INTO_DIM_INFO can be used to put these 3 values into the dim_info byte. -----------------------------------------------------------------------------*/ #undef DIM_INFO_TO_FREQ_DIM #undef DIM_INFO_TO_PHASE_DIM #undef DIM_INFO_TO_SLICE_DIM #define DIM_INFO_TO_FREQ_DIM(di) ( ((di) ) & 0x03 ) #define DIM_INFO_TO_PHASE_DIM(di) ( ((di) >> 2) & 0x03 ) #define DIM_INFO_TO_SLICE_DIM(di) ( ((di) >> 4) & 0x03 ) #undef FPS_INTO_DIM_INFO #define FPS_INTO_DIM_INFO(fd,pd,sd) ( ( ( ((char)(fd)) & 0x03) ) | \ ( ( ((char)(pd)) & 0x03) << 2 ) | \ ( ( ((char)(sd)) & 0x03) << 4 ) ) /*! \defgroup NIFTI1_SLICE_ORDER \brief nifti1 slice order codes, describing the acquisition order of the slices @{ */ const int32_t NIFTI_SLICE_UNKNOWN =0; const int32_t NIFTI_SLICE_SEQ_INC =1; const int32_t NIFTI_SLICE_SEQ_DEC =2; const int32_t NIFTI_SLICE_ALT_INC =3; const int32_t NIFTI_SLICE_ALT_DEC =4; const int32_t NIFTI_SLICE_ALT_INC2 =5; /* 05 May 2005: RWCox */ const int32_t NIFTI_SLICE_ALT_DEC2 =6; /* 05 May 2005: RWCox */ /* @} */ /*---------------------------------------------------------------------------*/ /* UNUSED FIELDS: ------------- Some of the ANALYZE 7.5 fields marked as ++UNUSED++ may need to be set to particular values for compatibility with other programs. The issue of interoperability of ANALYZE 7.5 files is a murky one -- not all programs require exactly the same set of fields. (Unobscuring this murkiness is a principal motivation behind NIFTI-1.) Some of the fields that may need to be set for other (non-NIFTI aware) software to be happy are: extents dbh.h says this should be 16384 regular dbh.h says this should be the character 'r' glmin, } dbh.h says these values should be the min and max voxel glmax } values for the entire dataset It is best to initialize ALL fields in the NIFTI-1 header to 0 (e.g., with calloc()), then fill in what is needed. -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* MISCELLANEOUS C MACROS -----------------------------------------------------------------------------*/ /*.................*/ /*! Given a nifti_1_header struct, check if it has a good magic number. Returns NIFTI version number (1..9) if magic is good, 0 if it is not. */ #define NIFTI_VERSION(h) \ ( ( (h).magic[0]=='n' && (h).magic[3]=='\0' && \ ( (h).magic[1]=='i' || (h).magic[1]=='+' ) && \ ( (h).magic[2]>='1' && (h).magic[2]<='9' ) ) \ ? (h).magic[2]-'0' : 0 ) /*.................*/ /*! Check if a nifti_1_header struct says if the data is stored in the same file or in a separate file. Returns 1 if the data is in the same file as the header, 0 if it is not. */ #define NIFTI_ONEFILE(h) ( (h).magic[1] == '+' ) /*.................*/ /*! Check if a nifti_1_header struct needs to be byte swapped. Returns 1 if it needs to be swapped, 0 if it does not. */ #define NIFTI_NEEDS_SWAP(h) ( (h).dim[0] < 0 || (h).dim[0] > 7 ) /*.................*/ /*! Check if a nifti_1_header struct contains a 5th (vector) dimension. Returns size of 5th dimension if > 1, returns 0 otherwise. */ #define NIFTI_5TH_DIM(h) ( ((h).dim[0]>4 && (h).dim[5]>1) ? (h).dim[5] : 0 ) /*****************************************************************************/ /*=================*/ #ifdef __cplusplus } #endif /*=================*/ #endif /* _NIFTI_HEADER_ */ connectome-workbench-1.4.2/src/FilesBase/nifti2.h000066400000000000000000000152551360521144700216330ustar00rootroot00000000000000#ifndef __NIFTI2_HEADER #define __NIFTI2_HEADER /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "nifti1.h" /*=================*/ #ifdef __cplusplus extern "C" { #endif /*=================*/ #include /*extended nifti intent codes*/ const int32_t NIFTI_INTENT_CONNECTIVITY_UNKNOWN=3000; const int32_t NIFTI_INTENT_CONNECTIVITY_DENSE=3001; const int32_t NIFTI_INTENT_CONNECTIVITY_DENSE_TIME=3002;//CIFTI-1 name const int32_t NIFTI_INTENT_CONNECTIVITY_DENSE_SERIES=3002;//CIFTI-2 name const int32_t NIFTI_INTENT_CONNECTIVITY_PARCELLATED=3003; const int32_t NIFTI_INTENT_CONNECTIVITY_PARCELLATED_TIME=3004;//ditto const int32_t NIFTI_INTENT_CONNECTIVITY_PARCELLATED_SERIES=3004; const int32_t NIFTI_INTENT_CONNECTIVITY_CONNECTIVITY_TRAJECTORY=3005;//ditto const int32_t NIFTI_INTENT_CONNECTIVITY_DENSE_TRAJECTORY=3005; const int32_t NIFTI_INTENT_CONNECTIVITY_DENSE_SCALARS=3006; const int32_t NIFTI_INTENT_CONNECTIVITY_DENSE_LABELS=3007; const int32_t NIFTI_INTENT_CONNECTIVITY_PARCELLATED_SCALAR=3008; const int32_t NIFTI_INTENT_CONNECTIVITY_PARCELLATED_DENSE=3009; const int32_t NIFTI_INTENT_CONNECTIVITY_DENSE_PARCELLATED=3010; const int32_t NIFTI_INTENT_CONNECTIVITY_PARCELLATED_PARCELLATED_SERIES=3011; const int32_t NIFTI_INTENT_CONNECTIVITY_PARCELLATED_PARCELLATED_SCALAR=3012; const int32_t NIFTI_ECODE_CIFTI=32; #define NIFTI2_VERSION(h) \ (h).sizeof_hdr == 348 ? 1 : (\ (h).sizeof_hdr == 1543569408 ? 1 : (\ (h).sizeof_hdr == 540 ? 2 : (\ (h).sizeof_hdr == 469893120 ? 2 : 0))) #define NIFTI2_NEEDS_SWAP(h) \ (h).sizeof_hdr == 469893120 ? 1 : (\ (h).sizeof_hdr == 1543569408 ? 1 : 0) //hopefully cross-platform solution to byte padding added by some compilers #pragma pack(push) #pragma pack(1) /*! \struct nifti_2_header \brief Data structure defining the fields in the nifti2 header. This binary header should be found at the beginning of a valid NIFTI-2 header file. */ /*************************/ /************************/ /************/ struct nifti_2_header { /* NIFTI-2 usage */ /* NIFTI-1 usage */ /* offset */ /*************************/ /************************/ /************/ int32_t sizeof_hdr; /*!< MUST be 540 */ /* int32_t sizeof_hdr; (348) */ /* 0 */ char magic[8] ; /*!< MUST be valid signature. */ /* char magic[4]; */ /* 4 */ int16_t datatype; /*!< Defines data type! */ /* short datatype; */ /* 12 */ int16_t bitpix; /*!< Number bits/voxel. */ /* short bitpix; */ /* 14 */ int64_t dim[8]; /*!< Data array dimensions.*/ /* short dim[8]; */ /* 16 */ double intent_p1 ; /*!< 1st intent parameter. */ /* float intent_p1; */ /* 80 */ double intent_p2 ; /*!< 2nd intent parameter. */ /* float intent_p2; */ /* 88 */ double intent_p3 ; /*!< 3rd intent parameter. */ /* float intent_p3; */ /* 96 */ double pixdim[8]; /*!< Grid spacings. */ /* float pixdim[8]; */ /* 104 */ int64_t vox_offset; /*!< Offset into .nii file */ /* float vox_offset; */ /* 168 */ double scl_slope ; /*!< Data scaling: slope. */ /* float scl_slope; */ /* 176 */ double scl_inter ; /*!< Data scaling: offset. */ /* float scl_inter; */ /* 184 */ double cal_max; /*!< Max display intensity */ /* float cal_max; */ /* 192 */ double cal_min; /*!< Min display intensity */ /* float cal_min; */ /* 200 */ double slice_duration;/*!< Time for 1 slice. */ /* float slice_duration; */ /* 208 */ double toffset; /*!< Time axis shift. */ /* float toffset; */ /* 216 */ int64_t slice_start;/*!< First slice index. */ /* short slice_start; */ /* 224 */ int64_t slice_end; /*!< Last slice index. */ /* short slice_end; */ /* 232 */ char descrip[80]; /*!< any text you like. */ /* char descrip[80]; */ /* 240 */ char aux_file[24]; /*!< auxiliary filename. */ /* char aux_file[24]; */ /* 320 */ int32_t qform_code ; /*!< NIFTI_XFORM_* code. */ /* short qform_code; */ /* 344 */ int32_t sform_code ; /*!< NIFTI_XFORM_* code. */ /* short sform_code; */ /* 348 */ double quatern_b ; /*!< Quaternion b param. */ /* float quatern_b; */ /* 352 */ double quatern_c ; /*!< Quaternion c param. */ /* float quatern_c; */ /* 360 */ double quatern_d ; /*!< Quaternion d param. */ /* float quatern_d; */ /* 368 */ double qoffset_x ; /*!< Quaternion x shift. */ /* float qoffset_x; */ /* 376 */ double qoffset_y ; /*!< Quaternion y shift. */ /* float qoffset_y; */ /* 384 */ double qoffset_z ; /*!< Quaternion z shift. */ /* float qoffset_z; */ /* 392 */ double srow_x[4] ; /*!< 1st row affine transform. */ /* float srow_x[4]; */ /* 400 */ double srow_y[4] ; /*!< 2nd row affine transform. */ /* float srow_y[4]; */ /* 432 */ double srow_z[4] ; /*!< 3rd row affine transform. */ /* float srow_z[4]; */ /* 464 */ int32_t slice_code ; /*!< Slice timing order. */ /* char slice_code; */ /* 496 */ int32_t xyzt_units ; /*!< Units of pixdim[1..4] */ /* char xyzt_units; */ /* 500 */ int32_t intent_code ; /*!< NIFTI_INTENT_* code. */ /* short intent_code; */ /* 504 */ char intent_name[16]; /*!< 'name' or meaning of data. */ /* char intent_name[16]; */ /* 508 */ char dim_info; /*!< MRI slice ordering. */ /* char dim_info; */ /* 524 */ char unused_str[15]; /*!< unused, filled with \0 */ /* 525 */ } ; /**** 540 bytes total ****/ typedef struct nifti_2_header nifti_2_header ; //and restore packing behavior #pragma pack(pop) /*=================*/ #ifdef __cplusplus } #endif /*=================*/ #endif //__NIFTI2_HEADER connectome-workbench-1.4.2/src/FtglFont/000077500000000000000000000000001360521144700201455ustar00rootroot00000000000000connectome-workbench-1.4.2/src/FtglFont/AUTHORS000066400000000000000000000021351360521144700212160ustar00rootroot00000000000000 -*- coding: utf-8 -*- Original author: Henry Maddocks http://homepages.paradise.net.nz/henryj/ Contributors: Jed Soane (Bezier curve code) Gérard Lanois (demo, Linux port, extrusion code, gltt maintainance) Matthias Kretz (Linux port) Andrew Ellerton (Windows port) Max Rheiner (Windows port) Sébastien Barré (containers and optimisations) Marcelo E. Magallon (original autoconf, bug fixes) Robert Bell (pixmap font modifications) Sam Hocevar (build system, new maintainer) Éric Beets (C bindings) Christopher Sean Morrison (bug fixes, new maintainer) Jeff Myers (JeffM2501) (Windows fixes) Daniel Remenak (Windows fixes) Portions derived from ConvertUTF.c Copyright (C) 2001-2004 Unicode, Inc. Bug fixes: Robert Osfield Markku Rontu Mark A. Fox Patrick Rogers Kai Huettemann FTGL was inspired by gltt, Copyright (C) 1998-1999 Stephane Rehel (http://gltt.sourceforge.net) connectome-workbench-1.4.2/src/FtglFont/CMakeLists.txt000066400000000000000000000045721360521144700227150ustar00rootroot00000000000000# # Name of project # PROJECT (Ftgl) # # Add QT for includes # if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) endif() IF (QT4_FOUND) SET(QT_DONT_USE_QTGUI) INCLUDE(${QT_USE_FILE}) ENDIF () # # Create the brain library # ADD_LIBRARY(FtglFont FTCharToGlyphIndexMap.h FTContour.h FTFace.h FTFont/FTBitmapFontImpl.h FTFont/FTBufferFontImpl.h FTFont/FTExtrudeFontImpl.h FTFont/FTFontImpl.h FTFont/FTOutlineFontImpl.h FTFont/FTPixmapFontImpl.h FTFont/FTPolygonFontImpl.h FTFont/FTTextureFontImpl.h FTGL/FTBBox.h FTGL/FTBitmapGlyph.h FTGL/FTBuffer.h FTGL/FTBufferFont.h FTGL/FTBufferGlyph.h FTGL/FTExtrdGlyph.h FTGL/FTFont.h FTGL/ftgl.h FTGL/FTGLBitmapFont.h FTGL/FTGLExtrdFont.h FTGL/FTGLOutlineFont.h FTGL/FTGLPixmapFont.h FTGL/FTGLPolygonFont.h FTGL/FTGLTextureFont.h FTGL/FTGLGlyph.h FTGL/FTLayout.h FTGL/FTOutlineGlyph.h FTGL/FTPixmapGlyph.h FTGL/FTPoint.h FTGL/FTPolyGlyph.h FTGL/FTSimpleLayout.h FTGL/FTTextureGlyph.h FTGlyph/FTBitmapGlyphImpl.h FTGlyph/FTBufferGlyphImpl.h FTGlyph/FTExtrudeGlyphImpl.h FTGlyph/FTGlyphImpl.h FTGlyph/FTOutlineGlyphImpl.h FTGlyph/FTPixmapGlyphImpl.h FTGlyph/FTPolygonGlyphImpl.h FTGlyph/FTTextureGlyphImpl.h FTGlyphContainer.h FTInternals.h FTLayout/FTLayoutImpl.h FTLayout/FTSimpleLayoutImpl.h FTLibrary.h FTList.h FTSize.h FTUnicode.h FTVector.h FTVectoriser.h FtglConfig.h FTBuffer.cpp FTCharmap.cpp FTContour.cpp FTFace.cpp FTFont/FTBitmapFont.cpp FTFont/FTBufferFont.cpp FTFont/FTExtrudeFont.cpp FTFont/FTFont.cpp FTFont/FTFontGlue.cpp FTFont/FTOutlineFont.cpp FTFont/FTPixmapFont.cpp FTFont/FTPolygonFont.cpp FTFont/FTTextureFont.cpp FTGlyph/FTBitmapGlyph.cpp FTGlyph/FTBufferGlyph.cpp FTGlyph/FTExtrudeGlyph.cpp FTGlyph/FTGlyph.cpp FTGlyph/FTGlyphGlue.cpp FTGlyph/FTOutlineGlyph.cpp FTGlyph/FTPixmapGlyph.cpp FTGlyph/FTPolygonGlyph.cpp FTGlyph/FTTextureGlyph.cpp FTGlyphContainer.cpp FTLayout/FTLayout.cpp FTLayout/FTLayoutGlue.cpp FTLayout/FTSimpleLayout.cpp FTLibrary.cpp FTPoint.cpp FTSize.cpp FTVectoriser.cpp ) # # Find Headers # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Common ${CMAKE_SOURCE_DIR}/Graphics ${FREETYPE_INCLUDE_DIR_ft2build} ${FREETYPE_INCLUDE_DIR_freetype2} ${CMAKE_SOURCE_DIR}/FtglFont ${CMAKE_SOURCE_DIR}/FtglFont/FTFont ${CMAKE_SOURCE_DIR}/FtglFont/FTGL ${CMAKE_SOURCE_DIR}/FtglFont/FTGlyph ) SET(FTGL_LIBRARIES FtglFont PARENT_SCOPE) SET(FTGL_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/FTGL PARENT_SCOPE) connectome-workbench-1.4.2/src/FtglFont/COPYING000066400000000000000000000022671360521144700212070ustar00rootroot00000000000000FTGL Herewith is a license. Basically I want you to use this software and if you think this license is preventing you from doing so let me know. Copyright (C) 2001-3 Henry Maddocks Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. connectome-workbench-1.4.2/src/FtglFont/FTBuffer.cpp000066400000000000000000000032461360521144700223210ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTGL/ftgl.h" FTBuffer::FTBuffer() : width(0), height(0), pixels(0), pos(FTPoint()) { } FTBuffer::~FTBuffer() { if(pixels) { delete[] pixels; } } void FTBuffer::Size(int w, int h) { if(w == width && h == height) { return; } if(w * h != width * height) { if(pixels) { delete[] pixels; } pixels = new unsigned char[w * h]; } memset(pixels, 0, w * h); width = w; height = h; } connectome-workbench-1.4.2/src/FtglFont/FTCharToGlyphIndexMap.h000066400000000000000000000115351360521144700243670ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2014 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTCharToGlyphIndexMap__ #define __FTCharToGlyphIndexMap__ #include #include "FTGL/ftgl.h" /** * Provides a non-STL alternative to the STL map * which maps character codes to glyph indices inside FTCharmap. * * Implementation: * - NumberOfBuckets buckets are considered. * - Each bucket has BucketSize entries. * - When the glyph index for the character code C has to be stored, the * bucket this character belongs to is found using 'C div BucketSize'. * If this bucket has not been allocated yet, do it now. * The entry in the bucked is found using 'C mod BucketSize'. * If it is set to IndexNotFound, then the glyph entry has not been set. * - Try to mimic the calls made to the STL map API. * * Caveats: * - The glyph index is now a signed long instead of unsigned long, so * the special value IndexNotFound (= -1) can be used to specify that the * glyph index has not been stored yet. */ class FTCharToGlyphIndexMap { public: typedef unsigned long CharacterCode; typedef signed long GlyphIndex; enum { NumberOfBuckets = 256, BucketSize = 256, IndexNotFound = -1 }; FTCharToGlyphIndexMap() { this->Indices = 0; } virtual ~FTCharToGlyphIndexMap() { if(this->Indices) { // Free all buckets this->clear(); // Free main structure delete [] this->Indices; this->Indices = 0; } } void clear() { if(this->Indices) { for(int i = 0; i < FTCharToGlyphIndexMap::NumberOfBuckets; i++) { if(this->Indices[i]) { delete [] this->Indices[i]; this->Indices[i] = 0; } } } } /*const */GlyphIndex find(CharacterCode c) { if(!this->Indices) { return 0; } // Find position of char code in buckets div_t pos = div(c, FTCharToGlyphIndexMap::BucketSize); if(!this->Indices[pos.quot]) { return 0; } const FTCharToGlyphIndexMap::GlyphIndex *ptr = &this->Indices[pos.quot][pos.rem]; if(*ptr == FTCharToGlyphIndexMap::IndexNotFound) { return 0; } return *ptr; } void insert(CharacterCode c, GlyphIndex g) { if(!this->Indices) { this->Indices = new GlyphIndex* [FTCharToGlyphIndexMap::NumberOfBuckets]; for(int i = 0; i < FTCharToGlyphIndexMap::NumberOfBuckets; i++) { this->Indices[i] = 0; } } // Find position of char code in buckets div_t pos = div(c, FTCharToGlyphIndexMap::BucketSize); // Allocate bucket if does not exist yet if(!this->Indices[pos.quot]) { this->Indices[pos.quot] = new GlyphIndex [FTCharToGlyphIndexMap::BucketSize]; for(int i = 0; i < FTCharToGlyphIndexMap::BucketSize; i++) { this->Indices[pos.quot][i] = FTCharToGlyphIndexMap::IndexNotFound; } } this->Indices[pos.quot][pos.rem] = g; } private: GlyphIndex** Indices; }; #endif // __FTCharToGlyphIndexMap__ connectome-workbench-1.4.2/src/FtglFont/FTCharmap.cpp000066400000000000000000000052771360521144700224710ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTFace.h" #include "FTCharmap.h" FTCharmap::FTCharmap(FTFace* face) : ftFace(*(face->Face())), err(0) { if(!ftFace->charmap) { if(!ftFace->num_charmaps) { // This face doesn't even have one charmap! err = 0x96; // Invalid_CharMap_Format return; } err = FT_Set_Charmap(ftFace, ftFace->charmaps[0]); } ftEncoding = ftFace->charmap->encoding; for(unsigned int i = 0; i < FTCharmap::MAX_PRECOMPUTED; i++) { charIndexCache[i] = FT_Get_Char_Index(ftFace, i); } } FTCharmap::~FTCharmap() { charMap.clear(); } bool FTCharmap::CharMap(FT_Encoding encoding) { if(ftEncoding == encoding) { err = 0; return true; } err = FT_Select_Charmap(ftFace, encoding); if(!err) { ftEncoding = encoding; charMap.clear(); } return !err; } unsigned int FTCharmap::GlyphListIndex(const unsigned int characterCode) { return charMap.find(characterCode); } unsigned int FTCharmap::FontIndex(const unsigned int characterCode) { if(characterCode < FTCharmap::MAX_PRECOMPUTED) { return charIndexCache[characterCode]; } return FT_Get_Char_Index(ftFace, characterCode); } void FTCharmap::InsertIndex(const unsigned int characterCode, const size_t containerIndex) { charMap.insert(characterCode, static_cast(containerIndex)); } connectome-workbench-1.4.2/src/FtglFont/FTCharmap.h000066400000000000000000000122031360521144700221210ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTCharmap__ #define __FTCharmap__ #include #include FT_FREETYPE_H #include FT_GLYPH_H #include "FTGL/ftgl.h" #include "FTCharToGlyphIndexMap.h" /** * FTCharmap takes care of specifying the encoding for a font and mapping * character codes to glyph indices. * * It doesn't preprocess all indices, only on an as needed basis. This may * seem like a performance penalty but it is quicker than using the 'raw' * freetype calls and will save significant amounts of memory when dealing * with unicode encoding * * @see "Freetype 2 Documentation" * */ class FTFace; class FTCharmap { public: /** * Constructor */ FTCharmap(FTFace* face); /** * Destructor */ virtual ~FTCharmap(); /** * Queries for the current character map code. * * @return The current character map code. */ FT_Encoding Encoding() const { return ftEncoding; } /** * Sets the character map for the face. If an error occurs the object is not modified. * Valid encodings as at Freetype 2.0.4 * ft_encoding_none * ft_encoding_symbol * ft_encoding_unicode * ft_encoding_latin_2 * ft_encoding_sjis * ft_encoding_gb2312 * ft_encoding_big5 * ft_encoding_wansung * ft_encoding_johab * ft_encoding_adobe_standard * ft_encoding_adobe_expert * ft_encoding_adobe_custom * ft_encoding_apple_roman * * @param encoding the Freetype encoding symbol. See above. * @return true if charmap was valid and set * correctly. */ bool CharMap(FT_Encoding encoding); /** * Get the FTGlyphContainer index of the input character. * * @param characterCode The character code of the requested glyph in * the current encoding eg apple roman. * @return The FTGlyphContainer index for the character or zero * if it wasn't found */ unsigned int GlyphListIndex(const unsigned int characterCode); /** * Get the font glyph index of the input character. * * @param characterCode The character code of the requested glyph in * the current encoding eg apple roman. * @return The glyph index for the character. */ unsigned int FontIndex(const unsigned int characterCode); /** * Set the FTGlyphContainer index of the character code. * * @param characterCode The character code of the requested glyph in * the current encoding eg apple roman. * @param containerIndex The index into the FTGlyphContainer of the * character code. */ void InsertIndex(const unsigned int characterCode, const size_t containerIndex); /** * Queries for errors. * * @return The current error code. Zero means no error. */ FT_Error Error() const { return err; } private: /** * Current character map code. */ FT_Encoding ftEncoding; /** * The current Freetype face. */ const FT_Face ftFace; /** * A structure that maps glyph indices to character codes * * < character code, face glyph index> */ typedef FTCharToGlyphIndexMap CharacterMap; CharacterMap charMap; /** * Precomputed font indices. */ static const unsigned int MAX_PRECOMPUTED = 128; unsigned int charIndexCache[MAX_PRECOMPUTED]; /** * Current error code. */ FT_Error err; }; #endif // __FTCharmap__ connectome-workbench-1.4.2/src/FtglFont/FTContour.cpp000066400000000000000000000163611360521144700225430ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Éric Beets * Copyright (c) 2014 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTContour.h" #include static const unsigned int BEZIER_STEPS = 5; void FTContour::AddPoint(FTPoint point) { if(pointList.empty() || (point != pointList[pointList.size() - 1] && point != pointList[0])) { pointList.push_back(point); } } void FTContour::AddOutsetPoint(FTPoint point) { outsetPointList.push_back(point); } void FTContour::AddFrontPoint(FTPoint point) { frontPointList.push_back(point); } void FTContour::AddBackPoint(FTPoint point) { backPointList.push_back(point); } void FTContour::evaluateQuadraticCurve(FTPoint A, FTPoint B, FTPoint C) { for(unsigned int i = 1; i < BEZIER_STEPS; i++) { float t = static_cast(i) / BEZIER_STEPS; FTPoint U = (1.0f - t) * A + t * B; FTPoint V = (1.0f - t) * B + t * C; AddPoint((1.0f - t) * U + t * V); } } void FTContour::evaluateCubicCurve(FTPoint A, FTPoint B, FTPoint C, FTPoint D) { for(unsigned int i = 0; i < BEZIER_STEPS; i++) { float t = static_cast(i) / BEZIER_STEPS; FTPoint U = (1.0f - t) * A + t * B; FTPoint V = (1.0f - t) * B + t * C; FTPoint W = (1.0f - t) * C + t * D; FTPoint M = (1.0f - t) * U + t * V; FTPoint N = (1.0f - t) * V + t * W; AddPoint((1.0f - t) * M + t * N); } } // This function is a bit tricky. Given a path ABC, it returns the // coordinates of the outset point facing B on the left at a distance // of 64.0. // M // - - - - - - X // ^ / ' // | 64.0 / ' // X---->-----X ==> X--v-------X ' // A B \ A B \ .>' // \ \<' 64.0 // \ \ . // \ \ . // C X C X // FTPoint FTContour::ComputeOutsetPoint(FTPoint A, FTPoint B, FTPoint C) { /* Build the rotation matrix from 'ba' vector */ FTPoint ba = (A - B).Normalise(); FTPoint bc = C - B; /* Rotate bc to the left */ FTPoint tmp(bc.X() * -ba.X() + bc.Y() * -ba.Y(), bc.X() * ba.Y() + bc.Y() * -ba.X()); /* Compute the vector bisecting 'abc' */ FTGL_DOUBLE norm = sqrt(tmp.X() * tmp.X() + tmp.Y() * tmp.Y()); FTGL_DOUBLE dist = 64.0 * sqrt((norm - tmp.X()) / (norm + tmp.X())); tmp.X(tmp.Y() < 0.0 ? dist : -dist); tmp.Y(64.0); /* Rotate the new bc to the right */ return FTPoint(tmp.X() * -ba.X() + tmp.Y() * ba.Y(), tmp.X() * -ba.Y() + tmp.Y() * -ba.X()); } void FTContour::SetParity(int parity) { size_t size = PointCount(); FTPoint vOutset; if(((parity & 1) && clockwise) || (!(parity & 1) && !clockwise)) { // Contour orientation is wrong! We must reverse all points. // FIXME: could it be worth writing FTVector::reverse() for this? for(size_t i = 0; i < size / 2; i++) { FTPoint tmp = pointList[i]; pointList[i] = pointList[size - 1 - i]; pointList[size - 1 -i] = tmp; } clockwise = !clockwise; } for(size_t i = 0; i < size; i++) { size_t prev, cur, next; prev = (i + size - 1) % size; cur = i; next = (i + size + 1) % size; vOutset = ComputeOutsetPoint(Point(prev), Point(cur), Point(next)); AddOutsetPoint(vOutset); } } FTContour::FTContour(FT_Vector* contour, char* tags, unsigned int n) { FTPoint prev, cur(contour[(n - 1) % n]), next(contour[0]); FTPoint a;//, b = next - cur; double olddir, dir = atan2((next - cur).Y(), (next - cur).X()); double angle = 0.0; // See http://freetype.sourceforge.net/freetype2/docs/glyphs/glyphs-6.html // for a full description of FreeType tags. for(unsigned int i = 0; i < n; i++) { prev = cur; cur = next; next = FTPoint(contour[(i + 1) % n]); olddir = dir; dir = atan2((next - cur).Y(), (next - cur).X()); // Compute our path's new direction. double t = dir - olddir; if(t < -M_PI) t += 2 * M_PI; if(t > M_PI) t -= 2 * M_PI; angle += t; // Only process point tags we know. if(n < 2 || FT_CURVE_TAG(tags[i]) == FT_Curve_Tag_On) { AddPoint(cur); } else if(FT_CURVE_TAG(tags[i]) == FT_Curve_Tag_Conic) { FTPoint prev2 = prev, next2 = next; // Previous point is either the real previous point (an "on" // point), or the midpoint between the current one and the // previous "conic off" point. if(FT_CURVE_TAG(tags[(i - 1 + n) % n]) == FT_Curve_Tag_Conic) { prev2 = (cur + prev) * 0.5; AddPoint(prev2); } // Next point is either the real next point or the midpoint. if(FT_CURVE_TAG(tags[(i + 1) % n]) == FT_Curve_Tag_Conic) { next2 = (cur + next) * 0.5; } evaluateQuadraticCurve(prev2, cur, next2); } else if(FT_CURVE_TAG(tags[i]) == FT_Curve_Tag_Cubic && FT_CURVE_TAG(tags[(i + 1) % n]) == FT_Curve_Tag_Cubic) { evaluateCubicCurve(prev, cur, next, FTPoint(contour[(i + 2) % n])); } } // If final angle is positive (+2PI), it's an anti-clockwise contour, // otherwise (-2PI) it's clockwise. clockwise = (angle < 0.0); } void FTContour::buildFrontOutset(float outset) { for(size_t i = 0; i < PointCount(); ++i) { AddFrontPoint(Point(i) + Outset(i) * outset); } } void FTContour::buildBackOutset(float outset) { for(size_t i = 0; i < PointCount(); ++i) { AddBackPoint(Point(i) + Outset(i) * outset); } } connectome-workbench-1.4.2/src/FtglFont/FTContour.h000066400000000000000000000143151360521144700222050ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTContour__ #define __FTContour__ #include "FTGL/ftgl.h" #include "FTVector.h" /** * FTContour class is a container of points that describe a vector font * outline. It is used as a container for the output of the bezier curve * evaluator in FTVectoriser. * * @see FTOutlineGlyph * @see FTPolygonGlyph * @see FTPoint */ class FTContour { public: /** * Constructor * * @param contour * @param pointTags * @param numberOfPoints */ FTContour(FT_Vector* contour, char* pointTags, unsigned int numberOfPoints); /** * Destructor */ ~FTContour() { pointList.clear(); outsetPointList.clear(); frontPointList.clear(); backPointList.clear(); } /** * Return a point at index. * * @param index of the point in the curve. * @return const point reference */ const FTPoint& Point(size_t index) const { return pointList[index]; } /** * Return a point at index. * * @param index of the point in the outset curve. * @return const point reference */ const FTPoint& Outset(size_t index) const { return outsetPointList[index]; } /** * Return a point at index of the front outset contour. * * @param index of the point in the curve. * @return const point reference */ const FTPoint& FrontPoint(size_t index) const { if(frontPointList.size() == 0) return Point(index); return frontPointList[index]; } /** * Return a point at index of the back outset contour. * * @param index of the point in the curve. * @return const point reference */ const FTPoint& BackPoint(size_t index) const { if(backPointList.size() == 0) return Point(index); return backPointList[index]; } /** * How many points define this contour * * @return the number of points in this contour */ size_t PointCount() const { return pointList.size(); } /** * Make sure the glyph has the proper parity and create the front/back * outset contour. * * @param parity The contour's parity within the glyph. */ void SetParity(int parity); // FIXME: this should probably go away. void buildFrontOutset(float outset); void buildBackOutset(float outset); private: /** * Add a point to this contour. This function tests for duplicate * points. * * @param point The point to be added to the contour. */ inline void AddPoint(FTPoint point); /** * Add a point to this contour. This function tests for duplicate * points. * * @param point The point to be added to the contour. */ inline void AddOutsetPoint(FTPoint point); /* * Add a point to this outset contour. This function tests for duplicate * points. * * @param point The point to be added to the contour outset. */ inline void AddFrontPoint(FTPoint point); inline void AddBackPoint(FTPoint point); /** * De Casteljau (bezier) algorithm contributed by Jed Soane * Evaluates a quadratic or conic (second degree) curve */ inline void evaluateQuadraticCurve(FTPoint, FTPoint, FTPoint); /** * De Casteljau (bezier) algorithm contributed by Jed Soane * Evaluates a cubic (third degree) curve */ inline void evaluateCubicCurve(FTPoint, FTPoint, FTPoint, FTPoint); /** * Compute the vector norm */ inline FTGL_DOUBLE NormVector(const FTPoint &v); /** * Compute a rotation matrix from a vector */ inline void RotationMatrix(const FTPoint &a, const FTPoint &b, FTGL_DOUBLE *matRot, FTGL_DOUBLE *invRot); /** * Matrix and vector multiplication */ inline void MultMatrixVect(FTGL_DOUBLE *mat, FTPoint &v); /** * Compute the vector bisecting from a vector 'v' and a distance 'd' */ inline void ComputeBisec(FTPoint &v); /** * Compute the outset point coordinates */ inline FTPoint ComputeOutsetPoint(FTPoint a, FTPoint b, FTPoint c); /** * The list of points in this contour */ typedef FTVector PointVector; PointVector pointList; PointVector outsetPointList; PointVector frontPointList; PointVector backPointList; /** * Is this contour clockwise or anti-clockwise? */ bool clockwise; }; #endif // __FTContour__ connectome-workbench-1.4.2/src/FtglFont/FTFace.cpp000066400000000000000000000133761360521144700217530ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTFace.h" #include "FTLibrary.h" #include FT_TRUETYPE_TABLES_H FTFace::FTFace(const char* fontFilePath, bool precomputeKerning) : numGlyphs(0), fontEncodingList(0), kerningCache(0), err(0) { const FT_Long DEFAULT_FACE_INDEX = 0; ftFace = new FT_Face; err = FT_New_Face(*FTLibrary::Instance().GetLibrary(), fontFilePath, DEFAULT_FACE_INDEX, ftFace); if(err) { delete ftFace; ftFace = 0; return; } numGlyphs = (*ftFace)->num_glyphs; hasKerningTable = (FT_HAS_KERNING((*ftFace)) != 0); if(hasKerningTable && precomputeKerning) { BuildKerningCache(); } } FTFace::FTFace(const unsigned char *pBufferBytes, size_t bufferSizeInBytes, bool precomputeKerning) : numGlyphs(0), fontEncodingList(0), kerningCache(0), err(0) { const FT_Long DEFAULT_FACE_INDEX = 0; ftFace = new FT_Face; err = FT_New_Memory_Face(*FTLibrary::Instance().GetLibrary(), (FT_Byte const *)pBufferBytes, (FT_Long)bufferSizeInBytes, DEFAULT_FACE_INDEX, ftFace); if(err) { delete ftFace; ftFace = 0; return; } numGlyphs = (*ftFace)->num_glyphs; hasKerningTable = (FT_HAS_KERNING((*ftFace)) != 0); if(hasKerningTable && precomputeKerning) { BuildKerningCache(); } } FTFace::~FTFace() { if(kerningCache) { delete[] kerningCache; } if(ftFace) { FT_Done_Face(*ftFace); delete ftFace; ftFace = 0; } } bool FTFace::Attach(const char* fontFilePath) { err = FT_Attach_File(*ftFace, fontFilePath); return !err; } bool FTFace::Attach(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) { FT_Open_Args open; open.flags = FT_OPEN_MEMORY; open.memory_base = (FT_Byte const *)pBufferBytes; open.memory_size = (FT_Long)bufferSizeInBytes; err = FT_Attach_Stream(*ftFace, &open); return !err; } const FTSize& FTFace::Size(const unsigned int size, const unsigned int res) { charSize.CharSize(ftFace, size, res, res); err = charSize.Error(); return charSize; } unsigned int FTFace::CharMapCount() const { return (*ftFace)->num_charmaps; } FT_Encoding* FTFace::CharMapList() { if(0 == fontEncodingList) { fontEncodingList = new FT_Encoding[CharMapCount()]; for(size_t i = 0; i < CharMapCount(); ++i) { fontEncodingList[i] = (*ftFace)->charmaps[i]->encoding; } } return fontEncodingList; } FTPoint FTFace::KernAdvance(unsigned int index1, unsigned int index2) { float x, y; if(!hasKerningTable || !index1 || !index2) { return FTPoint(0.0f, 0.0f); } if(kerningCache && index1 < FTFace::MAX_PRECOMPUTED && index2 < FTFace::MAX_PRECOMPUTED) { x = kerningCache[2 * (index2 * FTFace::MAX_PRECOMPUTED + index1)]; y = kerningCache[2 * (index2 * FTFace::MAX_PRECOMPUTED + index1) + 1]; return FTPoint(x, y); } FT_Vector kernAdvance; kernAdvance.x = kernAdvance.y = 0; err = FT_Get_Kerning(*ftFace, index1, index2, ft_kerning_unfitted, &kernAdvance); if(err) { return FTPoint(0.0f, 0.0f); } x = static_cast(kernAdvance.x) / 64.0f; y = static_cast(kernAdvance.y) / 64.0f; return FTPoint(x, y); } FT_GlyphSlot FTFace::Glyph(unsigned int index, FT_Int load_flags) { err = FT_Load_Glyph(*ftFace, index, load_flags); if(err) { return NULL; } return (*ftFace)->glyph; } void FTFace::BuildKerningCache() { FT_Vector kernAdvance; kernAdvance.x = 0; kernAdvance.y = 0; kerningCache = new float[FTFace::MAX_PRECOMPUTED * FTFace::MAX_PRECOMPUTED * 2]; for(unsigned int j = 0; j < FTFace::MAX_PRECOMPUTED; j++) { for(unsigned int i = 0; i < FTFace::MAX_PRECOMPUTED; i++) { err = FT_Get_Kerning(*ftFace, i, j, ft_kerning_unfitted, &kernAdvance); if(err) { delete[] kerningCache; kerningCache = NULL; return; } kerningCache[2 * (j * FTFace::MAX_PRECOMPUTED + i)] = static_cast(kernAdvance.x) / 64.0f; kerningCache[2 * (j * FTFace::MAX_PRECOMPUTED + i) + 1] = static_cast(kernAdvance.y) / 64.0f; } } } connectome-workbench-1.4.2/src/FtglFont/FTFace.h000066400000000000000000000122351360521144700214110ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTFace__ #define __FTFace__ #include #include FT_FREETYPE_H #include FT_GLYPH_H #include "FTGL/ftgl.h" #include "FTSize.h" /** * FTFace class provides an abstraction layer for the Freetype Face. * * @see "Freetype 2 Documentation" * */ class FTFace { public: /** * Opens and reads a face file. Error is set. * * @param fontFilePath font file path. */ FTFace(const char* fontFilePath, bool precomputeKerning = true); /** * Read face data from an in-memory buffer. Error is set. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTFace(const unsigned char *pBufferBytes, size_t bufferSizeInBytes, bool precomputeKerning = true); /** * Destructor * * Disposes of the current Freetype Face. */ virtual ~FTFace(); /** * Attach auxilliary file to font (e.g., font metrics). * * @param fontFilePath auxilliary font file path. * @return true if file has opened * successfully. */ bool Attach(const char* fontFilePath); /** * Attach auxilliary data to font (e.g., font metrics) from memory * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes * @return true if file has opened * successfully. */ bool Attach(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Get the freetype face object.. * * @return pointer to an FT_Face. */ FT_Face* Face() const { return ftFace; } /** * Sets the char size for the current face. * * This doesn't guarantee that the size was set correctly. Clients * should check errors. * * @param size the face size in points (1/72 inch) * @param res the resolution of the target device. * @return FTSize object */ const FTSize& Size(const unsigned int size, const unsigned int res); /** * Get the number of character maps in this face. * * @return character map count. */ unsigned int CharMapCount() const; /** * Get a list of character maps in this face. * * @return pointer to the first encoding. */ FT_Encoding* CharMapList(); /** * Gets the kerning vector between two glyphs */ FTPoint KernAdvance(unsigned int index1, unsigned int index2); /** * Loads and creates a Freetype glyph. */ FT_GlyphSlot Glyph(unsigned int index, FT_Int load_flags); /** * Gets the number of glyphs in the current face. */ unsigned int GlyphCount() const { return numGlyphs; } /** * Queries for errors. * * @return The current error code. */ FT_Error Error() const { return err; } private: /** * The Freetype face */ FT_Face* ftFace; /** * The size object associated with this face */ FTSize charSize; /** * The number of glyphs in this face */ int numGlyphs; FT_Encoding* fontEncodingList; /** * This face has kerning tables */ bool hasKerningTable; /** * If this face has kerning tables, we can cache them. */ void BuildKerningCache(); static const unsigned int MAX_PRECOMPUTED = 128; float *kerningCache; /** * Current error code. Zero means no error. */ FT_Error err; }; #endif // __FTFace__ connectome-workbench-1.4.2/src/FtglFont/FTFont/000077500000000000000000000000001360521144700213055ustar00rootroot00000000000000connectome-workbench-1.4.2/src/FtglFont/FTFont/FTBitmapFont.cpp000066400000000000000000000060031360521144700243050ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTBitmapFontImpl.h" // // FTBitmapFont // FTBitmapFont::FTBitmapFont(char const *fontFilePath) : FTFont(new FTBitmapFontImpl(this, fontFilePath)) {} FTBitmapFont::FTBitmapFont(unsigned char const *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTBitmapFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTBitmapFont::~FTBitmapFont() {} FTGlyph* FTBitmapFont::MakeGlyph(FT_GlyphSlot ftGlyph) { return new FTBitmapGlyph(ftGlyph); } // // FTBitmapFontImpl // template inline FTPoint FTBitmapFontImpl::RenderI(const T* string, const int len, FTPoint position, FTPoint spacing, int renderMode) { // Protect GL_BLEND glPushAttrib(GL_COLOR_BUFFER_BIT); // Protect glPixelStorei() calls (also in FTBitmapGlyphImpl::RenderImpl) glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glDisable(GL_BLEND); FTPoint tmp = FTFontImpl::Render(string, len, position, spacing, renderMode); glPopClientAttrib(); glPopAttrib(); return tmp; } FTPoint FTBitmapFontImpl::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } FTPoint FTBitmapFontImpl::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } connectome-workbench-1.4.2/src/FtglFont/FTFont/FTBitmapFontImpl.h000066400000000000000000000044761360521144700246100ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTBitmapFontImpl__ #define __FTBitmapFontImpl__ #include "FTFontImpl.h" class FTGlyph; class FTBitmapFontImpl : public FTFontImpl { friend class FTBitmapFont; protected: FTBitmapFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath) {}; FTBitmapFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes) {}; virtual FTPoint Render(const char *s, const int len, FTPoint position, FTPoint spacing, int renderMode); virtual FTPoint Render(const wchar_t *s, const int len, FTPoint position, FTPoint spacing, int renderMode); private: /* Internal generic Render() implementation */ template inline FTPoint RenderI(const T *s, const int len, FTPoint position, FTPoint spacing, int mode); }; #endif // __FTBitmapFontImpl__ connectome-workbench-1.4.2/src/FtglFont/FTFont/FTBufferFont.cpp000066400000000000000000000226551360521144700243150ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTBufferFontImpl.h" // // FTBufferFont // FTBufferFont::FTBufferFont(char const *fontFilePath) : FTFont(new FTBufferFontImpl(this, fontFilePath)) {} FTBufferFont::FTBufferFont(unsigned char const *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTBufferFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTBufferFont::~FTBufferFont() {} FTGlyph* FTBufferFont::MakeGlyph(FT_GlyphSlot ftGlyph) { FTBufferFontImpl *myimpl = dynamic_cast(impl); if(!myimpl) { return NULL; } return myimpl->MakeGlyphImpl(ftGlyph); } // // FTBufferFontImpl // FTBufferFontImpl::FTBufferFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath), buffer(new FTBuffer()) { load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; glGenTextures(BUFFER_CACHE_SIZE, idCache); for(int i = 0; i < BUFFER_CACHE_SIZE; i++) { stringCache[i] = NULL; glBindTexture(GL_TEXTURE_2D, idCache[i]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } lastString = 0; } FTBufferFontImpl::FTBufferFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes), buffer(new FTBuffer()) { load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; glGenTextures(BUFFER_CACHE_SIZE, idCache); for(int i = 0; i < BUFFER_CACHE_SIZE; i++) { stringCache[i] = NULL; glBindTexture(GL_TEXTURE_2D, idCache[i]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } lastString = 0; } FTBufferFontImpl::~FTBufferFontImpl() { glDeleteTextures(BUFFER_CACHE_SIZE, idCache); for(int i = 0; i < BUFFER_CACHE_SIZE; i++) { if(stringCache[i]) { free(stringCache[i]); } } delete buffer; } FTGlyph* FTBufferFontImpl::MakeGlyphImpl(FT_GlyphSlot ftGlyph) { return new FTBufferGlyph(ftGlyph, buffer); } bool FTBufferFontImpl::FaceSize(const unsigned int size, const unsigned int res) { for(int i = 0; i < BUFFER_CACHE_SIZE; i++) { if(stringCache[i]) { free(stringCache[i]); stringCache[i] = NULL; } } return FTFontImpl::FaceSize(size, res); } static inline GLuint NextPowerOf2(GLuint in) { in -= 1; in |= in >> 16; in |= in >> 8; in |= in >> 4; in |= in >> 2; in |= in >> 1; return in + 1; } inline int StringCompare(void const *a, char const *b, int len) { return len < 0 ? strcmp((char const *)a, b) : strncmp((char const *)a, b, len); } inline int StringCompare(void const *a, wchar_t const *b, int len) { return len < 0 ? wcscmp((wchar_t const *)a, b) : wcsncmp((wchar_t const *)a, b, len); } inline char *StringCopy(char const *s, int len) { if(len < 0) { return strdup(s); } else { #ifdef HAVE_STRNDUP return strndup(s, len); #else char *s2 = (char*)malloc(len + 1); memcpy(s2, s, len); s2[len] = 0; return s2; #endif } } inline wchar_t *StringCopy(wchar_t const *s, int len) { if(len < 0) { #if defined HAVE_WCSDUP return wcsdup(s); #else len = (int)wcslen(s); #endif } wchar_t *s2 = (wchar_t *)malloc((len + 1) * sizeof(wchar_t)); memcpy(s2, s, len * sizeof(wchar_t)); s2[len] = 0; return s2; } template inline FTPoint FTBufferFontImpl::RenderI(const T* string, const int len, FTPoint position, FTPoint spacing, int renderMode) { const float padding = 3.0f; int width, height, texWidth, texHeight; int cacheIndex = -1; bool inCache = false; // Protect blending functions, GL_BLEND and GL_TEXTURE_2D glPushAttrib(GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT); // Protect glPixelStorei() calls glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); glEnable(GL_BLEND); glEnable(GL_TEXTURE_2D); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE // Search whether the string is already in a texture we uploaded for(int n = 0; n < BUFFER_CACHE_SIZE; n++) { int i = (lastString + n + BUFFER_CACHE_SIZE) % BUFFER_CACHE_SIZE; if(stringCache[i] && !StringCompare(stringCache[i], string, len)) { cacheIndex = i; inCache = true; break; } } // If the string was not found, we need to put it in the cache and compute // its new bounding box. if(!inCache) { // FIXME: this cache is not very efficient. We should first expire // strings that are not used very often. cacheIndex = lastString; lastString = (lastString + 1) % BUFFER_CACHE_SIZE; if(stringCache[cacheIndex]) { free(stringCache[cacheIndex]); } // FIXME: only the first N bytes are copied; we want the first N chars. stringCache[cacheIndex] = StringCopy(string, len); bboxCache[cacheIndex] = BBox(string, len, FTPoint(), spacing); } FTBBox bbox = bboxCache[cacheIndex]; width = static_cast(bbox.Upper().X() - bbox.Lower().X() + padding + padding + 0.5); height = static_cast(bbox.Upper().Y() - bbox.Lower().Y() + padding + padding + 0.5); texWidth = NextPowerOf2(width); texHeight = NextPowerOf2(height); glBindTexture(GL_TEXTURE_2D, idCache[cacheIndex]); // If the string was not found, we need to render the text in a new // texture buffer, then upload it to the OpenGL layer. if(!inCache) { buffer->Size(texWidth, texHeight); buffer->Pos(FTPoint(padding, padding) - bbox.Lower()); advanceCache[cacheIndex] = FTFontImpl::Render(string, len, FTPoint(), spacing, renderMode); glBindTexture(GL_TEXTURE_2D, idCache[cacheIndex]); glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); /* TODO: use glTexSubImage2D later? */ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texWidth, texHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, (GLvoid *)buffer->Pixels()); buffer->Size(0, 0); } FTPoint low = position + bbox.Lower(); FTPoint up = position + bbox.Upper(); glBegin(GL_QUADS); glNormal3f(0.0f, 0.0f, 1.0f); glTexCoord2f(padding / texWidth, (texHeight - height + padding) / texHeight); glVertex2f(low.Xf(), up.Yf()); glTexCoord2f(padding / texWidth, (texHeight - padding) / texHeight); glVertex2f(low.Xf(), low.Yf()); glTexCoord2f((width - padding) / texWidth, (texHeight - padding) / texHeight); glVertex2f(up.Xf(), low.Yf()); glTexCoord2f((width - padding) / texWidth, (texHeight - height + padding) / texHeight); glVertex2f(up.Xf(), up.Yf()); glEnd(); glPopClientAttrib(); glPopAttrib(); return position + advanceCache[cacheIndex]; } FTPoint FTBufferFontImpl::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } FTPoint FTBufferFontImpl::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } connectome-workbench-1.4.2/src/FtglFont/FTFont/FTBufferFontImpl.h000066400000000000000000000054121360521144700245740ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTBufferFontImpl__ #define __FTBufferFontImpl__ #include "FTFontImpl.h" class FTGlyph; class FTBuffer; class FTBufferFontImpl : public FTFontImpl { friend class FTBufferFont; protected: FTBufferFontImpl(FTFont *ftFont, const char* fontFilePath); FTBufferFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); virtual ~FTBufferFontImpl(); virtual FTPoint Render(const char *s, const int len, FTPoint position, FTPoint spacing, int renderMode); virtual FTPoint Render(const wchar_t *s, const int len, FTPoint position, FTPoint spacing, int renderMode); virtual bool FaceSize(const unsigned int size, const unsigned int res); private: /** * Create an FTBufferGlyph object for the base class. */ FTGlyph* MakeGlyphImpl(FT_GlyphSlot ftGlyph); /* Internal generic Render() implementation */ template inline FTPoint RenderI(const T *s, const int len, FTPoint position, FTPoint spacing, int mode); /* Pixel buffer */ FTBuffer *buffer; static const int BUFFER_CACHE_SIZE = 16; /* Texture IDs */ GLuint idCache[BUFFER_CACHE_SIZE]; void *stringCache[BUFFER_CACHE_SIZE]; FTBBox bboxCache[BUFFER_CACHE_SIZE]; FTPoint advanceCache[BUFFER_CACHE_SIZE]; int lastString; }; #endif // __FTBufferFontImpl__ connectome-workbench-1.4.2/src/FtglFont/FTFont/FTExtrudeFont.cpp000066400000000000000000000050371360521144700245170ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTExtrudeFontImpl.h" // // FTExtrudeFont // FTExtrudeFont::FTExtrudeFont(char const *fontFilePath) : FTFont(new FTExtrudeFontImpl(this, fontFilePath)) {} FTExtrudeFont::FTExtrudeFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTExtrudeFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTExtrudeFont::~FTExtrudeFont() {} FTGlyph* FTExtrudeFont::MakeGlyph(FT_GlyphSlot ftGlyph) { FTExtrudeFontImpl *myimpl = dynamic_cast(impl); if(!myimpl) { return NULL; } return new FTExtrudeGlyph(ftGlyph, myimpl->depth, myimpl->front, myimpl->back, myimpl->useDisplayLists); } // // FTExtrudeFontImpl // FTExtrudeFontImpl::FTExtrudeFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath), depth(0.0f), front(0.0f), back(0.0f) { load_flags = FT_LOAD_NO_HINTING; } FTExtrudeFontImpl::FTExtrudeFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes), depth(0.0f), front(0.0f), back(0.0f) { load_flags = FT_LOAD_NO_HINTING; } connectome-workbench-1.4.2/src/FtglFont/FTFont/FTExtrudeFontImpl.h000066400000000000000000000051051360521144700250020ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTExtrudeFontImpl__ #define __FTExtrudeFontImpl__ #include "FTFontImpl.h" class FTGlyph; class FTExtrudeFontImpl : public FTFontImpl { friend class FTExtrudeFont; protected: FTExtrudeFontImpl(FTFont *ftFont, const char* fontFilePath); FTExtrudeFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Set the extrusion distance for the font. * * @param d The extrusion distance. */ virtual void Depth(float d) { depth = d; } /** * Set the outset distance for the font. Only implemented by * FTOutlineFont, FTPolygonFont and FTExtrudeFont * * @param o The outset distance. */ virtual void Outset(float o) { front = back = o; } /** * Set the outset distance for the font. Only implemented by * FTExtrudeFont * * @param f The front outset distance. * @param b The back outset distance. */ virtual void Outset(float f, float b) { front = f; back = b; } private: /** * The extrusion distance for the font. */ float depth; /** * The outset distance (front and back) for the font. */ float front, back; }; #endif // __FTExtrudeFontImpl__ connectome-workbench-1.4.2/src/FtglFont/FTFont/FTFont.cpp000066400000000000000000000263721360521144700231630ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2014 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTInternals.h" #include "FTUnicode.h" #include "FTFontImpl.h" #include "FTBitmapFontImpl.h" #include "FTExtrudeFontImpl.h" #include "FTOutlineFontImpl.h" #include "FTPixmapFontImpl.h" #include "FTPolygonFontImpl.h" #include "FTTextureFontImpl.h" #include "FTGlyphContainer.h" #include "FTFace.h" // // FTFont // FTFont::FTFont(char const *fontFilePath) { impl = new FTFontImpl(this, fontFilePath); } FTFont::FTFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) { impl = new FTFontImpl(this, pBufferBytes, bufferSizeInBytes); } FTFont::FTFont(FTFontImpl *pImpl) { impl = pImpl; } FTFont::~FTFont() { delete impl; } bool FTFont::Attach(const char* fontFilePath) { return impl->Attach(fontFilePath); } bool FTFont::Attach(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) { return impl->Attach(pBufferBytes, bufferSizeInBytes); } bool FTFont::FaceSize(const unsigned int size, const unsigned int res) { return impl->FaceSize(size, res); } unsigned int FTFont::FaceSize() const { return impl->FaceSize(); } void FTFont::Depth(float depth) { return impl->Depth(depth); } void FTFont::Outset(float outset) { return impl->Outset(outset); } void FTFont::Outset(float front, float back) { return impl->Outset(front, back); } void FTFont::GlyphLoadFlags(FT_Int flags) { return impl->GlyphLoadFlags(flags); } bool FTFont::CharMap(FT_Encoding encoding) { return impl->CharMap(encoding); } unsigned int FTFont::CharMapCount() const { return impl->CharMapCount(); } FT_Encoding* FTFont::CharMapList() { return impl->CharMapList(); } void FTFont::UseDisplayList(bool useList) { return impl->UseDisplayList(useList); } float FTFont::Ascender() const { return impl->Ascender(); } float FTFont::Descender() const { return impl->Descender(); } float FTFont::LineHeight() const { return impl->LineHeight(); } FTPoint FTFont::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return impl->Render(string, len, position, spacing, renderMode); } FTPoint FTFont::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return impl->Render(string, len, position, spacing, renderMode); } float FTFont::Advance(const char * string, const int len, FTPoint spacing) { return impl->Advance(string, len, spacing); } float FTFont::Advance(const wchar_t * string, const int len, FTPoint spacing) { return impl->Advance(string, len, spacing); } float FTFont::Advance(const wchar_t theChar, const wchar_t theNextChar) { return impl->glyphList->Advance(theChar, theNextChar); } FTBBox FTFont::BBox(const char *string, const int len, FTPoint position, FTPoint spacing) { return impl->BBox(string, len, position, spacing); } FTBBox FTFont::BBox(const wchar_t *string, const int len, FTPoint position, FTPoint spacing) { return impl->BBox(string, len, position, spacing); } FT_Error FTFont::Error() const { return impl->err; } // // FTFontImpl // FTFontImpl::FTFontImpl(FTFont *ftFont, char const *fontFilePath) : face(fontFilePath), useDisplayLists(true), load_flags(FT_LOAD_DEFAULT), intf(ftFont), glyphList(0) { err = face.Error(); if(err == 0) { glyphList = new FTGlyphContainer(&face); } } FTFontImpl::FTFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : face(pBufferBytes, bufferSizeInBytes), useDisplayLists(true), load_flags(FT_LOAD_DEFAULT), intf(ftFont), glyphList(0) { err = face.Error(); if(err == 0) { glyphList = new FTGlyphContainer(&face); } } FTFontImpl::~FTFontImpl() { if(glyphList) { delete glyphList; } } bool FTFontImpl::Attach(const char* fontFilePath) { if(!face.Attach(fontFilePath)) { err = face.Error(); return false; } err = 0; return true; } bool FTFontImpl::Attach(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) { if(!face.Attach(pBufferBytes, bufferSizeInBytes)) { err = face.Error(); return false; } err = 0; return true; } bool FTFontImpl::FaceSize(const unsigned int size, const unsigned int res) { if(glyphList != NULL) { delete glyphList; glyphList = NULL; } charSize = face.Size(size, res); err = face.Error(); if(err != 0) { return false; } glyphList = new FTGlyphContainer(&face); return true; } unsigned int FTFontImpl::FaceSize() const { return charSize.CharSize(); } void FTFontImpl::Depth(float /*depth*/) { ; } void FTFontImpl::Outset(float /*outset*/) { ; } void FTFontImpl::Outset(float /*front*/, float /*back*/) { ; } void FTFontImpl::GlyphLoadFlags(FT_Int flags) { load_flags = flags; } bool FTFontImpl::CharMap(FT_Encoding encoding) { bool result = glyphList->CharMap(encoding); err = glyphList->Error(); return result; } unsigned int FTFontImpl::CharMapCount() const { return face.CharMapCount(); } FT_Encoding* FTFontImpl::CharMapList() { return face.CharMapList(); } void FTFontImpl::UseDisplayList(bool useList) { useDisplayLists = useList; } float FTFontImpl::Ascender() const { return charSize.Ascender(); } float FTFontImpl::Descender() const { return charSize.Descender(); } float FTFontImpl::LineHeight() const { return charSize.Height(); } template inline FTBBox FTFontImpl::BBoxI(const T* string, const int len, FTPoint position, FTPoint spacing) { FTBBox totalBBox; /* Only compute the bounds if string is non-empty. */ if(string && ('\0' != string[0])) { // for multibyte - we can't rely on sizeof(T) == character FTUnicodeStringItr ustr(string); unsigned int thisChar = *ustr++; unsigned int nextChar = *ustr; if(CheckGlyph(thisChar)) { totalBBox = glyphList->BBox(thisChar); totalBBox += position; position += FTPoint(glyphList->Advance(thisChar, nextChar), 0.0); } /* Expand totalBox by each glyph in string */ for(int i = 1; (len < 0 && *ustr) || (len >= 0 && i < len); i++) { thisChar = *ustr++; nextChar = *ustr; if(CheckGlyph(thisChar)) { position += spacing; FTBBox tempBBox = glyphList->BBox(thisChar); tempBBox += position; totalBBox |= tempBBox; position += FTPoint(glyphList->Advance(thisChar, nextChar), 0.0); } } } return totalBBox; } FTBBox FTFontImpl::BBox(const char *string, const int len, FTPoint position, FTPoint spacing) { /* The chars need to be unsigned because they are cast to int later */ return BBoxI((const unsigned char *)string, len, position, spacing); } FTBBox FTFontImpl::BBox(const wchar_t *string, const int len, FTPoint position, FTPoint spacing) { return BBoxI(string, len, position, spacing); } template inline float FTFontImpl::AdvanceI(const T* string, const int len, FTPoint spacing) { float advance = 0.0f; FTUnicodeStringItr ustr(string); for(int i = 0; (len < 0 && *ustr) || (len >= 0 && i < len); i++) { unsigned int thisChar = *ustr++; unsigned int nextChar = *ustr; if(CheckGlyph(thisChar)) { advance += glyphList->Advance(thisChar, nextChar); } if(nextChar) { advance += spacing.Xf(); } } return advance; } float FTFontImpl::Advance(const char* string, const int len, FTPoint spacing) { /* The chars need to be unsigned because they are cast to int later */ return AdvanceI((const unsigned char *)string, len, spacing); } float FTFontImpl::Advance(const wchar_t* string, const int len, FTPoint spacing) { return AdvanceI(string, len, spacing); } template inline FTPoint FTFontImpl::RenderI(const T* string, const int len, FTPoint position, FTPoint spacing, int renderMode) { // for multibyte - we can't rely on sizeof(T) == character FTUnicodeStringItr ustr(string); for(int i = 0; (len < 0 && *ustr) || (len >= 0 && i < len); i++) { unsigned int thisChar = *ustr++; unsigned int nextChar = *ustr; if(CheckGlyph(thisChar)) { position += glyphList->Render(thisChar, nextChar, position, renderMode); } if(nextChar) { position += spacing; } } return position; } FTPoint FTFontImpl::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI((const unsigned char *)string, len, position, spacing, renderMode); } FTPoint FTFontImpl::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } bool FTFontImpl::CheckGlyph(const unsigned int characterCode) { if(glyphList->Glyph(characterCode)) { return true; } unsigned int glyphIndex = glyphList->FontIndex(characterCode); FT_GlyphSlot ftSlot = face.Glyph(glyphIndex, load_flags); if(!ftSlot) { err = face.Error(); return false; } FTGlyph* tempGlyph = intf->MakeGlyph(ftSlot); if(!tempGlyph) { if(0 == err) { err = 0x13; } return false; } glyphList->Add(tempGlyph, characterCode); return true; } connectome-workbench-1.4.2/src/FtglFont/FTFont/FTFontGlue.cpp000066400000000000000000000170141360521144700237710ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTInternals.h" static const FTPoint static_ftpoint; static const FTBBox static_ftbbox; FTGL_BEGIN_C_DECLS #define C_TOR(cname, cargs, cxxname, cxxarg, cxxtype) \ FTGLfont* cname cargs \ { \ cxxname *f = new cxxname cxxarg; \ if(f->Error()) \ { \ delete f; \ return NULL; \ } \ FTGLfont *ftgl = (FTGLfont *)malloc(sizeof(FTGLfont)); \ ftgl->ptr = f; \ ftgl->type = cxxtype; \ return ftgl; \ } // FTBitmapFont::FTBitmapFont(); C_TOR(ftglCreateBitmapFont, (const char *fontname), FTBitmapFont, (fontname), FONT_BITMAP); // FTBufferFont::FTBufferFont(); C_TOR(ftglCreateBufferFont, (const char *fontname), FTBufferFont, (fontname), FONT_BUFFER); // FTExtrudeFont::FTExtrudeFont(); C_TOR(ftglCreateExtrudeFont, (const char *fontname), FTExtrudeFont, (fontname), FONT_EXTRUDE); // FTOutlineFont::FTOutlineFont(); C_TOR(ftglCreateOutlineFont, (const char *fontname), FTOutlineFont, (fontname), FONT_OUTLINE); // FTPixmapFont::FTPixmapFont(); C_TOR(ftglCreatePixmapFont, (const char *fontname), FTPixmapFont, (fontname), FONT_PIXMAP); // FTPolygonFont::FTPolygonFont(); C_TOR(ftglCreatePolygonFont, (const char *fontname), FTPolygonFont, (fontname), FONT_POLYGON); // FTTextureFont::FTTextureFont(); C_TOR(ftglCreateTextureFont, (const char *fontname), FTTextureFont, (fontname), FONT_TEXTURE); // FTCustomFont::FTCustomFont(); class FTCustomFont : public FTFont { public: FTCustomFont(char const *fontFilePath, void *p, FTGLglyph * (*makeglyph) (FT_GlyphSlot, void *)) : FTFont(fontFilePath), data(p), makeglyphCallback(makeglyph) {} ~FTCustomFont() {} FTGlyph* MakeGlyph(FT_GlyphSlot slot) { FTGLglyph *g = makeglyphCallback(slot, data); FTGlyph *glyph = g->ptr; // XXX: we no longer need g, and no one will free it for us. Not // very elegant, and we need to make sure no one else will try to // use it. free(g); return glyph; } private: void *data; FTGLglyph *(*makeglyphCallback) (FT_GlyphSlot, void *); }; C_TOR(ftglCreateCustomFont, (char const *fontFilePath, void *data, FTGLglyph * (*makeglyphCallback) (FT_GlyphSlot, void *)), FTCustomFont, (fontFilePath, data, makeglyphCallback), FONT_CUSTOM); #define C_FUN(cret, cname, cargs, cxxerr, cxxname, cxxarg) \ cret cname cargs \ { \ if(!f || !f->ptr) \ { \ fprintf(stderr, "FTGL warning: NULL pointer in %s\n", #cname); \ cxxerr; \ } \ return f->ptr->cxxname cxxarg; \ } // FTFont::~FTFont(); void ftglDestroyFont(FTGLfont *f) { if(!f || !f->ptr) { fprintf(stderr, "FTGL warning: NULL pointer in %s\n", __FUNCTION__); return; } delete f->ptr; free(f); } // bool FTFont::Attach(const char* fontFilePath); C_FUN(int, ftglAttachFile, (FTGLfont *f, const char* path), return 0, Attach, (path)); // bool FTFont::Attach(const unsigned char *pBufferBytes, // size_t bufferSizeInBytes); C_FUN(int, ftglAttachData, (FTGLfont *f, const unsigned char *p, size_t s), return 0, Attach, (p, s)); // void FTFont::GlyphLoadFlags(FT_Int flags); C_FUN(void, ftglSetFontGlyphLoadFlags, (FTGLfont *f, FT_Int flags), return, GlyphLoadFlags, (flags)); // bool FTFont::CharMap(FT_Encoding encoding); C_FUN(int, ftglSetFontCharMap, (FTGLfont *f, FT_Encoding enc), return 0, CharMap, (enc)); // unsigned int FTFont::CharMapCount(); C_FUN(unsigned int, ftglGetFontCharMapCount, (FTGLfont *f), return 0, CharMapCount, ()); // FT_Encoding* FTFont::CharMapList(); C_FUN(FT_Encoding *, ftglGetFontCharMapList, (FTGLfont* f), return NULL, CharMapList, ()); // virtual bool FTFont::FaceSize(const unsigned int size, // const unsigned int res = 72); C_FUN(int, ftglSetFontFaceSize, (FTGLfont *f, unsigned int s, unsigned int r), return 0, FaceSize, (s, r > 0 ? r : 72)); // unsigned int FTFont::FaceSize() const; // XXX: need to call FaceSize() as FTFont::FaceSize() because of FTGLTexture C_FUN(unsigned int, ftglGetFontFaceSize, (FTGLfont *f), return 0, FTFont::FaceSize, ()); // virtual void FTFont::Depth(float depth); C_FUN(void, ftglSetFontDepth, (FTGLfont *f, float d), return, Depth, (d)); // virtual void FTFont::Outset(float front, float back); C_FUN(void, ftglSetFontOutset, (FTGLfont *f, float front, float back), return, FTFont::Outset, (front, back)); // void FTFont::UseDisplayList(bool useList); C_FUN(void, ftglSetFontDisplayList, (FTGLfont *f, int l), return, UseDisplayList, (l != 0)); // float FTFont::Ascender() const; C_FUN(float, ftglGetFontAscender, (FTGLfont *f), return 0.f, Ascender, ()); // float FTFont::Descender() const; C_FUN(float, ftglGetFontDescender, (FTGLfont *f), return 0.f, Descender, ()); // float FTFont::LineHeight() const; C_FUN(float, ftglGetFontLineHeight, (FTGLfont *f), return 0.f, LineHeight, ()); // void FTFont::BBox(const char* string, float& llx, float& lly, float& llz, // float& urx, float& ury, float& urz); extern "C++" { C_FUN(static FTBBox, _ftglGetFontBBox, (FTGLfont *f, char const *s, int len), return static_ftbbox, BBox, (s, len)); } void ftglGetFontBBox(FTGLfont *f, const char* s, int len, float c[6]) { FTBBox ret = _ftglGetFontBBox(f, s, len); FTPoint lower = ret.Lower(), upper = ret.Upper(); c[0] = lower.Xf(); c[1] = lower.Yf(); c[2] = lower.Zf(); c[3] = upper.Xf(); c[4] = upper.Yf(); c[5] = upper.Zf(); } // float FTFont::Advance(const char* string); C_FUN(float, ftglGetFontAdvance, (FTGLfont *f, char const *s), return 0.0, Advance, (s)); // virtual void Render(const char* string, int renderMode); extern "C++" { C_FUN(static FTPoint, _ftglRenderFont, (FTGLfont *f, char const *s, int len, FTPoint pos, FTPoint spacing, int mode), return static_ftpoint, Render, (s, len, pos, spacing, mode)); } void ftglRenderFont(FTGLfont *f, const char *s, int mode) { _ftglRenderFont(f, s, -1, FTPoint(), FTPoint(), mode); } // FT_Error FTFont::Error() const; C_FUN(FT_Error, ftglGetFontError, (FTGLfont *f), return -1, Error, ()); FTGL_END_C_DECLS connectome-workbench-1.4.2/src/FtglFont/FTFont/FTFontImpl.h000066400000000000000000000113531360521144700234430ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTFontImpl__ #define __FTFontImpl__ #include "FTGL/ftgl.h" #include "FTFace.h" class FTGlyphContainer; class FTGlyph; class FTFontImpl { friend class FTFont; protected: FTFontImpl(FTFont *ftFont, char const *fontFilePath); FTFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); virtual ~FTFontImpl(); virtual bool Attach(const char* fontFilePath); virtual bool Attach(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); virtual void GlyphLoadFlags(FT_Int flags); virtual bool CharMap(FT_Encoding encoding); virtual unsigned int CharMapCount() const; virtual FT_Encoding* CharMapList(); virtual void UseDisplayList(bool useList); virtual float Ascender() const; virtual float Descender() const; virtual float LineHeight() const; virtual bool FaceSize(const unsigned int size, const unsigned int res); virtual unsigned int FaceSize() const; virtual void Depth(float depth); virtual void Outset(float outset); virtual void Outset(float front, float back); virtual FTBBox BBox(const char *s, const int len, FTPoint, FTPoint); virtual FTBBox BBox(const wchar_t *s, const int len, FTPoint, FTPoint); virtual float Advance(const char *s, const int len, FTPoint); virtual float Advance(const wchar_t *s, const int len, FTPoint); virtual FTPoint Render(const char *s, const int len, FTPoint, FTPoint, int); virtual FTPoint Render(const wchar_t *s, const int len, FTPoint, FTPoint, int); /** * Current face object */ FTFace face; /** * Current size object */ FTSize charSize; /** * Flag to enable or disable the use of Display Lists inside FTGL * true turns ON display lists. * false turns OFF display lists. */ bool useDisplayLists; /** * The default glyph loading flags. */ FT_Int load_flags; /** * Current error code. Zero means no error. */ FT_Error err; private: /** * A link back to the interface of which we are the implementation. */ FTFont *intf; /** * Check that the glyph at chr exist. If not load it. * * @param chr character index * @return true if the glyph can be created. */ bool CheckGlyph(const unsigned int chr); /** * An object that holds a list of glyphs */ FTGlyphContainer* glyphList; /** * Current pen or cursor position; */ FTPoint pen; /* Internal generic BBox() implementation */ template inline FTBBox BBoxI(const T *s, const int len, FTPoint position, FTPoint spacing); /* Internal generic Advance() implementation */ template inline float AdvanceI(const T *s, const int len, FTPoint spacing); /* Internal generic Render() implementation */ template inline FTPoint RenderI(const T *s, const int len, FTPoint position, FTPoint spacing, int mode); }; #endif // __FTFontImpl__ connectome-workbench-1.4.2/src/FtglFont/FTFont/FTOutlineFont.cpp000066400000000000000000000073361360521144700245220ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTOutlineFontImpl.h" // // FTOutlineFont // FTOutlineFont::FTOutlineFont(char const *fontFilePath) : FTFont(new FTOutlineFontImpl(this, fontFilePath)) {} FTOutlineFont::FTOutlineFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTOutlineFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTOutlineFont::~FTOutlineFont() {} FTGlyph* FTOutlineFont::MakeGlyph(FT_GlyphSlot ftGlyph) { FTOutlineFontImpl *myimpl = dynamic_cast(impl); if(!myimpl) { return NULL; } return new FTOutlineGlyph(ftGlyph, myimpl->outset, myimpl->useDisplayLists); } // // FTOutlineFontImpl // FTOutlineFontImpl::FTOutlineFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath), outset(0.0f) { load_flags = FT_LOAD_NO_HINTING; } FTOutlineFontImpl::FTOutlineFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes), outset(0.0f) { load_flags = FT_LOAD_NO_HINTING; } template inline FTPoint FTOutlineFontImpl::RenderI(const T* string, const int len, FTPoint position, FTPoint spacing, int renderMode) { // Protect GL_TEXTURE_2D, glHint(), GL_LINE_SMOOTH and blending functions glPushAttrib(GL_ENABLE_BIT | GL_HINT_BIT | GL_LINE_BIT | GL_COLOR_BUFFER_BIT); glDisable(GL_TEXTURE_2D); glEnable(GL_LINE_SMOOTH); glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE FTPoint tmp = FTFontImpl::Render(string, len, position, spacing, renderMode); glPopAttrib(); return tmp; } FTPoint FTOutlineFontImpl::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } FTPoint FTOutlineFontImpl::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } connectome-workbench-1.4.2/src/FtglFont/FTFont/FTOutlineFontImpl.h000066400000000000000000000050601360521144700250010ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTOutlineFontImpl__ #define __FTOutlineFontImpl__ #include "FTFontImpl.h" class FTGlyph; class FTOutlineFontImpl : public FTFontImpl { friend class FTOutlineFont; protected: FTOutlineFontImpl(FTFont *ftFont, const char* fontFilePath); FTOutlineFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Set the outset distance for the font. Only implemented by * FTOutlineFont, FTPolygonFont and FTExtrudeFont * * @param outset The outset distance. */ virtual void Outset(float o) { outset = o; } virtual FTPoint Render(const char *s, const int len, FTPoint position, FTPoint spacing, int renderMode); virtual FTPoint Render(const wchar_t *s, const int len, FTPoint position, FTPoint spacing, int renderMode); private: /** * The outset distance for the font. */ float outset; /* Internal generic Render() implementation */ template inline FTPoint RenderI(const T *s, const int len, FTPoint position, FTPoint spacing, int mode); }; #endif // __FTOutlineFontImpl__ connectome-workbench-1.4.2/src/FtglFont/FTFont/FTPixmapFont.cpp000066400000000000000000000075431360521144700243410ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTPixmapFontImpl.h" // // FTPixmapFont // FTPixmapFont::FTPixmapFont(char const *fontFilePath) : FTFont(new FTPixmapFontImpl(this, fontFilePath)) {} FTPixmapFont::FTPixmapFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTPixmapFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTPixmapFont::~FTPixmapFont() {} FTGlyph* FTPixmapFont::MakeGlyph(FT_GlyphSlot ftGlyph) { return new FTPixmapGlyph(ftGlyph); } // // FTPixmapFontImpl // FTPixmapFontImpl::FTPixmapFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath) { load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; } FTPixmapFontImpl::FTPixmapFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes) { load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; } template inline FTPoint FTPixmapFontImpl::RenderI(const T* string, const int len, FTPoint position, FTPoint spacing, int renderMode) { // Protect GL_TEXTURE_2D and GL_BLEND, glPixelTransferf(), and blending // functions. glPushAttrib(GL_ENABLE_BIT | GL_PIXEL_MODE_BIT | GL_COLOR_BUFFER_BIT); // Protect glPixelStorei() calls (made by FTPixmapGlyphImpl::RenderImpl). glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_TEXTURE_2D); GLfloat ftglColour[4]; glGetFloatv(GL_CURRENT_RASTER_COLOR, ftglColour); glPixelTransferf(GL_RED_SCALE, ftglColour[0]); glPixelTransferf(GL_GREEN_SCALE, ftglColour[1]); glPixelTransferf(GL_BLUE_SCALE, ftglColour[2]); glPixelTransferf(GL_ALPHA_SCALE, ftglColour[3]); FTPoint tmp = FTFontImpl::Render(string, len, position, spacing, renderMode); glPopClientAttrib(); glPopAttrib(); return tmp; } FTPoint FTPixmapFontImpl::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } FTPoint FTPixmapFontImpl::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } connectome-workbench-1.4.2/src/FtglFont/FTFont/FTPixmapFontImpl.h000066400000000000000000000043071360521144700246230ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTPixmapFontImpl__ #define __FTPixmapFontImpl__ #include "FTFontImpl.h" class FTGlyph; class FTPixmapFontImpl : public FTFontImpl { friend class FTPixmapFont; protected: FTPixmapFontImpl(FTFont *ftFont, const char* fontFilePath); FTPixmapFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); virtual FTPoint Render(const char *s, const int len, FTPoint position, FTPoint spacing, int renderMode); virtual FTPoint Render(const wchar_t *s, const int len, FTPoint position, FTPoint spacing, int renderMode); private: /* Internal generic Render() implementation */ template inline FTPoint RenderI(const T *s, const int len, FTPoint position, FTPoint spacing, int mode); }; #endif // __FTPixmapFontImpl__ connectome-workbench-1.4.2/src/FtglFont/FTFont/FTPolygonFont.cpp000066400000000000000000000047231360521144700245270ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTPolygonFontImpl.h" // // FTPolygonFont // FTPolygonFont::FTPolygonFont(char const *fontFilePath) : FTFont(new FTPolygonFontImpl(this, fontFilePath)) {} FTPolygonFont::FTPolygonFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTPolygonFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTPolygonFont::~FTPolygonFont() {} FTGlyph* FTPolygonFont::MakeGlyph(FT_GlyphSlot ftGlyph) { FTPolygonFontImpl *myimpl = dynamic_cast(impl); if(!myimpl) { return NULL; } return new FTPolygonGlyph(ftGlyph, myimpl->outset, myimpl->useDisplayLists); } // // FTPolygonFontImpl // FTPolygonFontImpl::FTPolygonFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath), outset(0.0f) { load_flags = FT_LOAD_NO_HINTING; } FTPolygonFontImpl::FTPolygonFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes), outset(0.0f) { load_flags = FT_LOAD_NO_HINTING; } connectome-workbench-1.4.2/src/FtglFont/FTFont/FTPolygonFontImpl.h000066400000000000000000000040021360521144700250040ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTPolygonFontImpl__ #define __FTPolygonFontImpl__ #include "FTFontImpl.h" class FTGlyph; class FTPolygonFontImpl : public FTFontImpl { friend class FTPolygonFont; protected: FTPolygonFontImpl(FTFont *ftFont, const char* fontFilePath); FTPolygonFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Set the outset distance for the font. Only implemented by * FTOutlineFont, FTPolygonFont and FTExtrudeFont * * @param depth The outset distance. */ virtual void Outset(float o) { outset = o; } private: /** * The outset distance (front and back) for the font. */ float outset; }; #endif // __FTPolygonFontImpl__ connectome-workbench-1.4.2/src/FtglFont/FTFont/FTTextureFont.cpp000066400000000000000000000164531360521144700245430ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include #include // For memset #include "FTGL/ftgl.h" #include "FTInternals.h" #include "../FTGlyph/FTTextureGlyphImpl.h" #include "./FTTextureFontImpl.h" // // FTTextureFont // FTTextureFont::FTTextureFont(char const *fontFilePath) : FTFont(new FTTextureFontImpl(this, fontFilePath)) {} FTTextureFont::FTTextureFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTTextureFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTTextureFont::~FTTextureFont() {} FTGlyph* FTTextureFont::MakeGlyph(FT_GlyphSlot ftGlyph) { FTTextureFontImpl *myimpl = dynamic_cast(impl); if(!myimpl) { return NULL; } return myimpl->MakeGlyphImpl(ftGlyph); } // // FTTextureFontImpl // static inline GLuint NextPowerOf2(GLuint in) { in -= 1; in |= in >> 16; in |= in >> 8; in |= in >> 4; in |= in >> 2; in |= in >> 1; return in + 1; } FTTextureFontImpl::FTTextureFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath), maximumGLTextureSize(0), textureWidth(0), textureHeight(0), glyphHeight(0), glyphWidth(0), padding(3), xOffset(0), yOffset(0) { load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; remGlyphs = numGlyphs = face.GlyphCount(); } FTTextureFontImpl::FTTextureFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes), maximumGLTextureSize(0), textureWidth(0), textureHeight(0), glyphHeight(0), glyphWidth(0), padding(3), xOffset(0), yOffset(0) { load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; remGlyphs = numGlyphs = face.GlyphCount(); } FTTextureFontImpl::~FTTextureFontImpl() { if(textureIDList.size()) { glDeleteTextures((GLsizei)textureIDList.size(), (const GLuint*)&textureIDList[0]); } } FTGlyph* FTTextureFontImpl::MakeGlyphImpl(FT_GlyphSlot ftGlyph) { glyphHeight = static_cast(charSize.Height() + 0.5); glyphWidth = static_cast(charSize.Width() + 0.5); if(glyphHeight < 1) glyphHeight = 1; if(glyphWidth < 1) glyphWidth = 1; if(textureIDList.empty()) { textureIDList.push_back(CreateTexture()); xOffset = yOffset = padding; } if(xOffset > (textureWidth - glyphWidth)) { xOffset = padding; yOffset += glyphHeight; if(yOffset > (textureHeight - glyphHeight)) { textureIDList.push_back(CreateTexture()); yOffset = padding; } } FTTextureGlyph* tempGlyph = new FTTextureGlyph(ftGlyph, textureIDList[textureIDList.size() - 1], xOffset, yOffset, textureWidth, textureHeight); xOffset += static_cast(tempGlyph->BBox().Upper().X() - tempGlyph->BBox().Lower().X() + padding + 0.5); --remGlyphs; return tempGlyph; } void FTTextureFontImpl::CalculateTextureSize() { if(!maximumGLTextureSize) { maximumGLTextureSize = 1024; glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint*)&maximumGLTextureSize); assert(maximumGLTextureSize); // If you hit this then you have an invalid OpenGL context. } textureWidth = NextPowerOf2((remGlyphs * glyphWidth) + (padding * 2)); textureWidth = textureWidth > maximumGLTextureSize ? maximumGLTextureSize : textureWidth; int h = static_cast((textureWidth - (padding * 2)) / glyphWidth + 0.5); textureHeight = NextPowerOf2(((numGlyphs / h) + 1) * glyphHeight); textureHeight = textureHeight > maximumGLTextureSize ? maximumGLTextureSize : textureHeight; } GLuint FTTextureFontImpl::CreateTexture() { CalculateTextureSize(); int totalMemory = textureWidth * textureHeight; unsigned char* textureMemory = new unsigned char[totalMemory]; memset(textureMemory, 0, totalMemory); GLuint textID; glGenTextures(1, (GLuint*)&textID); glBindTexture(GL_TEXTURE_2D, textID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, textureWidth, textureHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, textureMemory); delete [] textureMemory; return textID; } bool FTTextureFontImpl::FaceSize(const unsigned int size, const unsigned int res) { if(!textureIDList.empty()) { glDeleteTextures((GLsizei)textureIDList.size(), (const GLuint*)&textureIDList[0]); textureIDList.clear(); remGlyphs = numGlyphs = face.GlyphCount(); } return FTFontImpl::FaceSize(size, res); } template inline FTPoint FTTextureFontImpl::RenderI(const T* string, const int len, FTPoint position, FTPoint spacing, int renderMode) { // Protect GL_TEXTURE_2D, GL_BLEND and blending functions glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE glEnable(GL_TEXTURE_2D); FTTextureGlyphImpl::ResetActiveTexture(); FTPoint tmp = FTFontImpl::Render(string, len, position, spacing, renderMode); glPopAttrib(); return tmp; } FTPoint FTTextureFontImpl::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } FTPoint FTTextureFontImpl::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } connectome-workbench-1.4.2/src/FtglFont/FTFont/FTTextureFontImpl.h000066400000000000000000000110051360521144700250160ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTTextureFontImpl__ #define __FTTextureFontImpl__ #include "FTFontImpl.h" #include "FTVector.h" class FTTextureGlyph; class FTTextureFontImpl : public FTFontImpl { friend class FTTextureFont; protected: FTTextureFontImpl(FTFont *ftFont, const char* fontFilePath); FTTextureFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); virtual ~FTTextureFontImpl(); /** * Set the char size for the current face. * * @param size the face size in points (1/72 inch) * @param res the resolution of the target device. * @return true if size was set correctly */ virtual bool FaceSize(const unsigned int size, const unsigned int res = 72); virtual FTPoint Render(const char *s, const int len, FTPoint position, FTPoint spacing, int renderMode); virtual FTPoint Render(const wchar_t *s, const int len, FTPoint position, FTPoint spacing, int renderMode); private: /** * Create an FTTextureGlyph object for the base class. */ FTGlyph* MakeGlyphImpl(FT_GlyphSlot ftGlyph); /** * Get the size of a block of memory required to layout the glyphs * * Calculates a width and height based on the glyph sizes and the * number of glyphs. It over estimates. */ inline void CalculateTextureSize(); /** * Creates a 'blank' OpenGL texture object. * * The format is GL_ALPHA and the params are * GL_TEXTURE_WRAP_S = GL_CLAMP * GL_TEXTURE_WRAP_T = GL_CLAMP * GL_TEXTURE_MAG_FILTER = GL_LINEAR * GL_TEXTURE_MIN_FILTER = GL_LINEAR * Note that mipmapping is NOT used */ inline GLuint CreateTexture(); /** * The maximum texture dimension on this OpenGL implemetation */ GLsizei maximumGLTextureSize; /** * The minimum texture width required to hold the glyphs */ GLsizei textureWidth; /** * The minimum texture height required to hold the glyphs */ GLsizei textureHeight; /** *An array of texture ids */ FTVector textureIDList; /** * The max height for glyphs in the current font */ int glyphHeight; /** * The max width for glyphs in the current font */ int glyphWidth; /** * A value to be added to the height and width to ensure that * glyphs don't overlap in the texture */ unsigned int padding; /** * */ unsigned int numGlyphs; /** */ unsigned int remGlyphs; /** */ int xOffset; /** */ int yOffset; /* Internal generic Render() implementation */ template inline FTPoint RenderI(const T *s, const int len, FTPoint position, FTPoint spacing, int mode); }; #endif // __FTTextureFontImpl__ connectome-workbench-1.4.2/src/FtglFont/FTGL/000077500000000000000000000000001360521144700207015ustar00rootroot00000000000000connectome-workbench-1.4.2/src/FtglFont/FTGL/FTBBox.h000066400000000000000000000117771360521144700221530ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTBBox__ #define __FTBBox__ #ifdef __cplusplus /** * FTBBox is a convenience class for handling bounding boxes. */ class FTGL_EXPORT FTBBox { public: /** * Default constructor. Bounding box is set to zero. */ FTBBox() : lower(0.0f, 0.0f, 0.0f), upper(0.0f, 0.0f, 0.0f) {} /** * Constructor. */ FTBBox(float lx, float ly, float lz, float ux, float uy, float uz) : lower(lx, ly, lz), upper(ux, uy, uz) {} /** * Constructor. */ FTBBox(FTPoint l, FTPoint u) : lower(l), upper(u) {} /** * Constructor. Extracts a bounding box from a freetype glyph. Uses * the control box for the glyph. FT_Glyph_Get_CBox() * * @param glyph A freetype glyph */ FTBBox(FT_GlyphSlot glyph) : lower(0.0f, 0.0f, 0.0f), upper(0.0f, 0.0f, 0.0f) { FT_BBox bbox; FT_Outline_Get_CBox(&(glyph->outline), &bbox); lower.X(static_cast(bbox.xMin) / 64.0f); lower.Y(static_cast(bbox.yMin) / 64.0f); lower.Z(0.0f); upper.X(static_cast(bbox.xMax) / 64.0f); upper.Y(static_cast(bbox.yMax) / 64.0f); upper.Z(0.0f); } /** * Destructor */ ~FTBBox() {} /** * Mark the bounds invalid by setting all lower dimensions greater * than the upper dimensions. */ void Invalidate() { lower = FTPoint(1.0f, 1.0f, 1.0f); upper = FTPoint(-1.0f, -1.0f, -1.0f); } /** * Determines if this bounding box is valid. * * @return True if all lower values are <= the corresponding * upper values. */ bool IsValid() { return lower.X() <= upper.X() && lower.Y() <= upper.Y() && lower.Z() <= upper.Z(); } /** * Move the Bounding Box by a vector. * * @param vector The vector to move the bbox in 3D space. */ FTBBox& operator += (const FTPoint vector) { lower += vector; upper += vector; return *this; } /** * Combine two bounding boxes. The result is the smallest bounding * box containing the two original boxes. * * @param bbox The bounding box to merge with the second one. */ FTBBox& operator |= (const FTBBox& bbox) { if(bbox.lower.X() < lower.X()) lower.X(bbox.lower.X()); if(bbox.lower.Y() < lower.Y()) lower.Y(bbox.lower.Y()); if(bbox.lower.Z() < lower.Z()) lower.Z(bbox.lower.Z()); if(bbox.upper.X() > upper.X()) upper.X(bbox.upper.X()); if(bbox.upper.Y() > upper.Y()) upper.Y(bbox.upper.Y()); if(bbox.upper.Z() > upper.Z()) upper.Z(bbox.upper.Z()); return *this; } void SetDepth(float depth) { if(depth > 0) upper.Z(lower.Z() + depth); else lower.Z(upper.Z() + depth); } inline FTPoint const Upper() const { return upper; } inline FTPoint const Lower() const { return lower; } private: /** * The bounds of the box */ FTPoint lower, upper; }; #endif //__cplusplus #endif // __FTBBox__ connectome-workbench-1.4.2/src/FtglFont/FTGL/FTBitmapGlyph.h000066400000000000000000000047251360521144700235340ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTBitmapGlyph__ #define __FTBitmapGlyph__ #ifdef __cplusplus /** * FTBitmapGlyph is a specialisation of FTGlyph for creating bitmaps. */ class FTGL_EXPORT FTBitmapGlyph : public FTGlyph { public: /** * Constructor * * @param glyph The Freetype glyph to be processed */ FTBitmapGlyph(FT_GlyphSlot glyph); /** * Destructor */ virtual ~FTBitmapGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialisation of FTGLglyph for creating bitmaps. * * @param glyph The Freetype glyph to be processed * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreateBitmapGlyph(FT_GlyphSlot glyph); FTGL_END_C_DECLS #endif // __FTBitmapGlyph__ connectome-workbench-1.4.2/src/FtglFont/FTGL/FTBuffer.h000066400000000000000000000063731360521144700225260ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning Please use instead of . # include #endif #ifndef __FTBuffer__ #define __FTBuffer__ #ifdef __cplusplus /** * FTBuffer is a helper class for pixel buffers. * * It provides the interface between FTBufferFont and FTBufferGlyph to * optimise rendering operations. * * @see FTBufferGlyph * @see FTBufferFont */ class FTGL_EXPORT FTBuffer { public: /** * Default constructor. */ FTBuffer(); /** * Destructor */ ~FTBuffer(); /** * Get the pen's position in the buffer. * * @return The pen's position as an FTPoint object. */ inline FTPoint Pos() const { return pos; } /** * Set the pen's position in the buffer. * * @param arg An FTPoint object with the desired pen's position. */ inline void Pos(FTPoint arg) { pos = arg; } /** * Set the buffer's size. * * @param w The buffer's desired width, in pixels. * @param h The buffer's desired height, in pixels. */ void Size(int w, int h); /** * Get the buffer's width. * * @return The buffer's width, in pixels. */ inline int Width() const { return width; } /** * Get the buffer's height. * * @return The buffer's height, in pixels. */ inline int Height() const { return height; } /** * Get the buffer's direct pixel buffer. * * @return A read-write pointer to the buffer's pixels. */ inline unsigned char *Pixels() const { return pixels; } private: /** * Buffer's width and height. */ int width, height; /** * Buffer's pixel buffer. */ unsigned char *pixels; /** * Buffer's internal pen position. */ FTPoint pos; }; #endif //__cplusplus #endif // __FTBuffer__ connectome-workbench-1.4.2/src/FtglFont/FTGL/FTBufferFont.h000066400000000000000000000056341360521144700233540ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning Please use instead of . # include #endif #ifndef __FTBufferFont__ #define __FTBufferFont__ #ifdef __cplusplus /** * FTBufferFont is a specialisation of the FTFont class for handling * memory buffer fonts. * * @see FTFont */ class FTGL_EXPORT FTBufferFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTBufferFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTBufferFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ ~FTBufferFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling memory buffer fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont */ FTGL_EXPORT FTGLfont *ftglCreateBufferFont(const char *file); FTGL_END_C_DECLS #endif // __FTBufferFont__ connectome-workbench-1.4.2/src/FtglFont/FTGL/FTBufferGlyph.h000066400000000000000000000042621360521144700235250ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning Please use instead of . # include #endif #ifndef __FTBufferGlyph__ #define __FTBufferGlyph__ #ifdef __cplusplus /** * FTBufferGlyph is a specialisation of FTGlyph for memory buffer rendering. */ class FTGL_EXPORT FTBufferGlyph : public FTGlyph { public: /** * Constructor * * @param glyph The Freetype glyph to be processed * @param buffer An FTBuffer object in which to render the glyph. */ FTBufferGlyph(FT_GlyphSlot glyph, FTBuffer *buffer); /** * Destructor */ virtual ~FTBufferGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #endif //__cplusplus #endif // __FTBufferGlyph__ connectome-workbench-1.4.2/src/FtglFont/FTGL/FTExtrdGlyph.h000066400000000000000000000072751360521144700234110ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTExtrudeGlyph__ #define __FTExtrudeGlyph__ #ifdef __cplusplus /** * FTExtrudeGlyph is a specialisation of FTGlyph for creating tessellated * extruded polygon glyphs. */ class FTGL_EXPORT FTExtrudeGlyph : public FTGlyph { public: /** * Constructor. Sets the Error to Invalid_Outline if the glyph isn't * an outline. * * @param glyph The Freetype glyph to be processed * @param depth The distance along the z axis to extrude the glyph * @param frontOutset outset contour size * @param backOutset outset contour size * @param useDisplayList Enable or disable the use of Display Lists * for this glyph * true turns ON display lists. * false turns OFF display lists. */ FTExtrudeGlyph(FT_GlyphSlot glyph, float depth, float frontOutset, float backOutset, bool useDisplayList); /** * Destructor */ virtual ~FTExtrudeGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #define FTExtrdGlyph FTExtrudeGlyph #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialisation of FTGLglyph for creating tessellated * extruded polygon glyphs. * * @param glyph The Freetype glyph to be processed * @param depth The distance along the z axis to extrude the glyph * @param frontOutset outset contour size * @param backOutset outset contour size * @param useDisplayList Enable or disable the use of Display Lists * for this glyph * true turns ON display lists. * false turns OFF display lists. * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreateExtrudeGlyph(FT_GlyphSlot glyph, float depth, float frontOutset, float backOutset, int useDisplayList); FTGL_END_C_DECLS #endif // __FTExtrudeGlyph__ connectome-workbench-1.4.2/src/FtglFont/FTGL/FTFont.h000066400000000000000000000500741360521144700222200ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTFont__ #define __FTFont__ #ifdef __cplusplus class FTFontImpl; /** * FTFont is the public interface for the FTGL library. * * Specific font classes are derived from this class. It uses the helper * classes FTFace and FTSize to access the Freetype library. This class * is abstract and deriving classes must implement the protected * MakeGlyph function to create glyphs of the * appropriate type. * * It is good practice after using these functions to test the error * code returned. FT_Error Error(). Check the freetype file * fterrdef.h for error definitions. * * @see FTFace * @see FTSize */ class FTGL_EXPORT FTFont { protected: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTFont(char const *fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); private: /* Allow our internal subclasses to access the private constructor */ friend class FTBitmapFont; friend class FTBufferFont; friend class FTExtrudeFont; friend class FTOutlineFont; friend class FTPixmapFont; friend class FTPolygonFont; friend class FTTextureFont; /** * Internal FTGL FTFont constructor. For private use only. * * @param pImpl Internal implementation object. Will be destroyed * upon FTFont deletion. */ FTFont(FTFontImpl *pImpl); public: virtual ~FTFont(); /** * Attach auxilliary file to font e.g font metrics. * * Note: not all font formats implement this function. * * @param fontFilePath auxilliary font file path. * @return true if file has been attached * successfully. */ virtual bool Attach(const char* fontFilePath); /** * Attach auxilliary data to font e.g font metrics, from memory. * * Note: not all font formats implement this function. * * @param pBufferBytes the in-memory buffer. * @param bufferSizeInBytes the length of the buffer in bytes. * @return true if file has been attached * successfully. */ virtual bool Attach(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Set the glyph loading flags. By default, fonts use the most * sensible flags when loading a font's glyph using FT_Load_Glyph(). * This function allows to override the default flags. * * @param flags The glyph loading flags. */ virtual void GlyphLoadFlags(FT_Int flags); /** * Set the character map for the face. * * @param encoding Freetype enumerate for char map code. * @return true if charmap was valid and * set correctly. */ virtual bool CharMap(FT_Encoding encoding); /** * Get the number of character maps in this face. * * @return character map count. */ virtual unsigned int CharMapCount() const; /** * Get a list of character maps in this face. * * @return pointer to the first encoding. */ virtual FT_Encoding* CharMapList(); /** * Set the char size for the current face. * * @param size the face size in points (1/72 inch) * @param res the resolution of the target device. * @return true if size was set correctly */ virtual bool FaceSize(const unsigned int size, const unsigned int res = 72); /** * Get the current face size in points (1/72 inch). * * @return face size */ virtual unsigned int FaceSize() const; /** * Set the extrusion distance for the font. Only implemented by * FTExtrudeFont * * @param depth The extrusion distance. */ virtual void Depth(float depth); /** * Set the outset distance for the font. Only implemented by * FTOutlineFont, FTPolygonFont and FTExtrudeFont * * @param outset The outset distance. */ virtual void Outset(float outset); /** * Set the front and back outset distances for the font. Only * implemented by FTExtrudeFont * * @param front The front outset distance. * @param back The back outset distance. */ virtual void Outset(float front, float back); /** * Enable or disable the use of Display Lists inside FTGL * * @param useList true turns ON display lists. * false turns OFF display lists. */ virtual void UseDisplayList(bool useList); /** * Get the global ascender height for the face. * * @return Ascender height */ virtual float Ascender() const; /** * Gets the global descender height for the face. * * @return Descender height */ virtual float Descender() const; /** * Gets the line spacing for the font. * * @return Line height */ virtual float LineHeight() const; /** * Get the bounding box for a string. * * @param string A char buffer. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param spacing A displacement vector to add after each character * has been checked (optional). * @return The corresponding bounding box. */ virtual FTBBox BBox(const char *string, const int len = -1, FTPoint position = FTPoint(), FTPoint spacing = FTPoint()); /** * Get the bounding box for a string (deprecated). * * @param string A char buffer. * @param llx Lower left near x coordinate. * @param lly Lower left near y coordinate. * @param llz Lower left near z coordinate. * @param urx Upper right far x coordinate. * @param ury Upper right far y coordinate. * @param urz Upper right far z coordinate. */ void BBox(const char* string, float& llx, float& lly, float& llz, float& urx, float& ury, float& urz) { FTBBox b = BBox(string); llx = b.Lower().Xf(); lly = b.Lower().Yf(); llz = b.Lower().Zf(); urx = b.Upper().Xf(); ury = b.Upper().Yf(); urz = b.Upper().Zf(); } /** * Get the bounding box for a string. * * @param string A wchar_t buffer. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param spacing A displacement vector to add after each character * has been checked (optional). * @return The corresponding bounding box. */ virtual FTBBox BBox(const wchar_t *string, const int len = -1, FTPoint position = FTPoint(), FTPoint spacing = FTPoint()); /** * Get the bounding box for a string (deprecated). * * @param string A wchar_t buffer. * @param llx Lower left near x coordinate. * @param lly Lower left near y coordinate. * @param llz Lower left near z coordinate. * @param urx Upper right far x coordinate. * @param ury Upper right far y coordinate. * @param urz Upper right far z coordinate. */ void BBox(const wchar_t* string, float& llx, float& lly, float& llz, float& urx, float& ury, float& urz) { FTBBox b = BBox(string); llx = b.Lower().Xf(); lly = b.Lower().Yf(); llz = b.Lower().Zf(); urx = b.Upper().Xf(); ury = b.Upper().Yf(); urz = b.Upper().Zf(); } /** * Get the advance from one character to the next. * * Method added by HCP (John Harwell). * * @param theChar 'C' char * @param theNextChar next 'C' char * @return The char's advance width. */ float Advance(const wchar_t theChar, const wchar_t theNextChar); /** * Get the advance for a string. * * @param string 'C' style string to be checked. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param spacing A displacement vector to add after each character * has been checked (optional). * @return The string's advance width. */ virtual float Advance(const char* string, const int len = -1, FTPoint spacing = FTPoint()); /** * Get the advance for a string. * * @param string A wchar_t string * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param spacing A displacement vector to add after each character * has been checked (optional). * @return The string's advance width. */ virtual float Advance(const wchar_t* string, const int len = -1, FTPoint spacing = FTPoint()); /** * Render a string of characters. * * @param string 'C' style string to be output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param spacing A displacement vector to add after each character * has been displayed (optional). * @param renderMode Render mode to use for display (optional). * @return The new pen position after the last character was output. */ virtual FTPoint Render(const char* string, const int len = -1, FTPoint position = FTPoint(), FTPoint spacing = FTPoint(), int renderMode = FTGL::RENDER_ALL); /** * Render a string of characters * * @param string wchar_t string to be output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param spacing A displacement vector to add after each character * has been displayed (optional). * @param renderMode Render mode to use for display (optional). * @return The new pen position after the last character was output. */ virtual FTPoint Render(const wchar_t *string, const int len = -1, FTPoint position = FTPoint(), FTPoint spacing = FTPoint(), int renderMode = FTGL::RENDER_ALL); /** * Queries the Font for errors. * * @return The current error code. */ virtual FT_Error Error() const; protected: /* Allow impl to access MakeGlyph */ friend class FTFontImpl; /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot) = 0; private: /** * Internal FTGL FTFont implementation object. For private use only. */ FTFontImpl *impl; }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * FTGLfont is the public interface for the FTGL library. * * It is good practice after using these functions to test the error * code returned. FT_Error Error(). Check the freetype file * fterrdef.h for error definitions. */ struct _FTGLFont; typedef struct _FTGLfont FTGLfont; /** * Create a custom FTGL font object. * * @param fontFilePath The font file name. * @param data A pointer to private data that will be passed to callbacks. * @param makeglyphCallback A glyph-making callback function. * @return An FTGLfont* object. */ FTGL_EXPORT FTGLfont *ftglCreateCustomFont(char const *fontFilePath, void *data, FTGLglyph * (*makeglyphCallback) (FT_GlyphSlot, void *)); /** * Destroy an FTGL font object. * * @param font An FTGLfont* object. */ FTGL_EXPORT void ftglDestroyFont(FTGLfont* font); /** * Attach auxilliary file to font e.g. font metrics. * * Note: not all font formats implement this function. * * @param font An FTGLfont* object. * @param path Auxilliary font file path. * @return 1 if file has been attached successfully. */ FTGL_EXPORT int ftglAttachFile(FTGLfont* font, const char* path); /** * Attach auxilliary data to font, e.g. font metrics, from memory. * * Note: not all font formats implement this function. * * @param font An FTGLfont* object. * @param data The in-memory buffer. * @param size The length of the buffer in bytes. * @return 1 if file has been attached successfully. */ FTGL_EXPORT int ftglAttachData(FTGLfont* font, const unsigned char * data, size_t size); /** * Set the character map for the face. * * @param font An FTGLfont* object. * @param encoding Freetype enumerate for char map code. * @return 1 if charmap was valid and set correctly. */ FTGL_EXPORT int ftglSetFontCharMap(FTGLfont* font, FT_Encoding encoding); /** * Get the number of character maps in this face. * * @param font An FTGLfont* object. * @return character map count. */ FTGL_EXPORT unsigned int ftglGetFontCharMapCount(FTGLfont* font); /** * Get a list of character maps in this face. * * @param font An FTGLfont* object. * @return pointer to the first encoding. */ FTGL_EXPORT FT_Encoding* ftglGetFontCharMapList(FTGLfont* font); /** * Set the char size for the current face. * * @param font An FTGLfont* object. * @param size The face size in points (1/72 inch). * @param res The resolution of the target device, or 0 to use the default * value of 72. * @return 1 if size was set correctly. */ FTGL_EXPORT int ftglSetFontFaceSize(FTGLfont* font, unsigned int size, unsigned int res); /** * Get the current face size in points (1/72 inch). * * @param font An FTGLfont* object. * @return face size */ FTGL_EXPORT unsigned int ftglGetFontFaceSize(FTGLfont* font); /** * Set the extrusion distance for the font. Only implemented by * FTExtrudeFont. * * @param font An FTGLfont* object. * @param depth The extrusion distance. */ FTGL_EXPORT void ftglSetFontDepth(FTGLfont* font, float depth); /** * Set the outset distance for the font. Only FTOutlineFont, FTPolygonFont * and FTExtrudeFont implement front outset. Only FTExtrudeFont implements * back outset. * * @param font An FTGLfont* object. * @param front The front outset distance. * @param back The back outset distance. */ FTGL_EXPORT void ftglSetFontOutset(FTGLfont* font, float front, float back); /** * Enable or disable the use of Display Lists inside FTGL. * * @param font An FTGLfont* object. * @param useList 1 turns ON display lists. * 0 turns OFF display lists. */ FTGL_EXPORT void ftglSetFontDisplayList(FTGLfont* font, int useList); /** * Get the global ascender height for the face. * * @param font An FTGLfont* object. * @return Ascender height */ FTGL_EXPORT float ftglGetFontAscender(FTGLfont* font); /** * Gets the global descender height for the face. * * @param font An FTGLfont* object. * @return Descender height */ FTGL_EXPORT float ftglGetFontDescender(FTGLfont* font); /** * Gets the line spacing for the font. * * @param font An FTGLfont* object. * @return Line height */ FTGL_EXPORT float ftglGetFontLineHeight(FTGLfont* font); /** * Get the bounding box for a string. * * @param font An FTGLfont* object. * @param string A char buffer * @param len The length of the string. If < 0 then all characters will be * checked until a null character is encountered (optional). * @param bounds An array of 6 float values where the bounding box's lower * left near and upper right far 3D coordinates will be stored. */ FTGL_EXPORT void ftglGetFontBBox(FTGLfont* font, const char *string, int len, float bounds[6]); /** * Get the advance width for a string. * * @param font An FTGLfont* object. * @param string A char string. * @return Advance width */ FTGL_EXPORT float ftglGetFontAdvance(FTGLfont* font, const char *string); /** * Render a string of characters. * * @param font An FTGLfont* object. * @param string Char string to be output. * @param mode Render mode to display. */ FTGL_EXPORT void ftglRenderFont(FTGLfont* font, const char *string, int mode); /** * Query a font for errors. * * @param font An FTGLfont* object. * @return The current error code. */ FTGL_EXPORT FT_Error ftglGetFontError(FTGLfont* font); FTGL_END_C_DECLS #endif // __FTFont__ connectome-workbench-1.4.2/src/FtglFont/FTGL/FTGLBitmapFont.h000066400000000000000000000060631360521144700235770ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTBitmapFont__ #define __FTBitmapFont__ #ifdef __cplusplus /** * FTBitmapFont is a specialisation of the FTFont class for handling * Bitmap fonts * * @see FTFont */ class FTGL_EXPORT FTBitmapFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTBitmapFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTBitmapFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ ~FTBitmapFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #define FTGLBitmapFont FTBitmapFont #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling bitmap fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont */ FTGL_EXPORT FTGLfont *ftglCreateBitmapFont(const char *file); FTGL_END_C_DECLS #endif // __FTBitmapFont__ connectome-workbench-1.4.2/src/FtglFont/FTGL/FTGLExtrdFont.h000066400000000000000000000061771360521144700234570ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTExtrudeFont__ #define __FTExtrudeFont__ #ifdef __cplusplus /** * FTExtrudeFont is a specialisation of the FTFont class for handling * extruded Polygon fonts * * @see FTFont * @see FTPolygonFont */ class FTGL_EXPORT FTExtrudeFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTExtrudeFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTExtrudeFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ ~FTExtrudeFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #define FTGLExtrdFont FTExtrudeFont #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling extruded poygon fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont * @see ftglCreatePolygonFont */ FTGL_EXPORT FTGLfont *ftglCreateExtrudeFont(const char *file); FTGL_END_C_DECLS #endif // __FTExtrudeFont__ connectome-workbench-1.4.2/src/FtglFont/FTGL/FTGLGlyph.h000066400000000000000000000141411360521144700226130ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTGlyph__ #define __FTGlyph__ #ifdef __cplusplus class FTGlyphImpl; /** * FTGlyph is the base class for FTGL glyphs. * * It provides the interface between Freetype glyphs and their openGL * renderable counterparts. This is an abstract class and derived classes * must implement the Render function. * * @see FTBBox * @see FTPoint */ class FTGL_EXPORT FTGlyph { protected: /** * Create a glyph. * * @param glyph The Freetype glyph to be processed */ FTGlyph(FT_GlyphSlot glyph); private: /** * Internal FTGL FTGlyph constructor. For private use only. * * @param pImpl Internal implementation object. Will be destroyed * upon FTGlyph deletion. */ FTGlyph(FTGlyphImpl *pImpl); /* Allow our internal subclasses to access the private constructor */ friend class FTBitmapGlyph; friend class FTBufferGlyph; friend class FTExtrudeGlyph; friend class FTOutlineGlyph; friend class FTPixmapGlyph; friend class FTPolygonGlyph; friend class FTTextureGlyph; public: /** * Destructor */ virtual ~FTGlyph(); /** * Renders this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode) = 0; /** * Return the advance width for this glyph. * * @return advance width. */ virtual float Advance() const; /** * Return the bounding box for this glyph. * * @return bounding box. */ virtual const FTBBox& BBox() const; /** * Queries for errors. * * @return The current error code. */ virtual FT_Error Error() const; private: /** * Internal FTGL FTGlyph implementation object. For private use only. */ FTGlyphImpl *impl; }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * FTGLglyph is the base class for FTGL glyphs. * * It provides the interface between Freetype glyphs and their openGL * renderable counterparts. This is an abstract class and derived classes * must implement the ftglRenderGlyph() function. */ struct _FTGLGlyph; typedef struct _FTGLglyph FTGLglyph; /** * Create a custom FTGL glyph object. * FIXME: maybe get rid of "base" and have advanceCallback etc. functions * * @param base The base FTGLglyph* to subclass. * @param data A pointer to private data that will be passed to callbacks. * @param renderCallback A rendering callback function. * @param destroyCallback A callback function to be called upon destruction. * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreateCustomGlyph(FTGLglyph *base, void *data, void (*renderCallback) (FTGLglyph *, void *, FTGL_DOUBLE, FTGL_DOUBLE, int, FTGL_DOUBLE *, FTGL_DOUBLE *), void (*destroyCallback) (FTGLglyph *, void *)); /** * Destroy an FTGL glyph object. * * @param glyph An FTGLglyph* object. */ FTGL_EXPORT void ftglDestroyGlyph(FTGLglyph *glyph); /** * Render a glyph at the current pen position and compute the corresponding * advance. * * @param glyph An FTGLglyph* object. * @param penx The current pen's X position. * @param peny The current pen's Y position. * @param renderMode Render mode to display * @param advancex A pointer to an FTGL_DOUBLE where to write the advance's X * component. * @param advancey A pointer to an FTGL_DOUBLE where to write the advance's Y * component. */ FTGL_EXPORT void ftglRenderGlyph(FTGLglyph *glyph, FTGL_DOUBLE penx, FTGL_DOUBLE peny, int renderMode, FTGL_DOUBLE *advancex, FTGL_DOUBLE *advancey); /** * Return the advance for a glyph. * * @param glyph An FTGLglyph* object. * @return The advance's X component. */ FTGL_EXPORT float ftglGetGlyphAdvance(FTGLglyph *glyph); /** * Return the bounding box for a glyph. * * @param glyph An FTGLglyph* object. * @param bounds An array of 6 float values where the bounding box's lower * left near and upper right far 3D coordinates will be stored. */ FTGL_EXPORT void ftglGetGlyphBBox(FTGLglyph *glyph, float bounds[6]); /** * Query a glyph for errors. * * @param glyph An FTGLglyph* object. * @return The current error code. */ FTGL_EXPORT FT_Error ftglGetGlyphError(FTGLglyph* glyph); FTGL_END_C_DECLS #endif // __FTGlyph__ connectome-workbench-1.4.2/src/FtglFont/FTGL/FTGLOutlineFont.h000066400000000000000000000061151360521144700240000ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTOutlineFont__ #define __FTOutlineFont__ #ifdef __cplusplus /** * FTOutlineFont is a specialisation of the FTFont class for handling * Vector Outline fonts * * @see FTFont */ class FTGL_EXPORT FTOutlineFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTOutlineFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTOutlineFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ ~FTOutlineFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #define FTGLOutlineFont FTOutlineFont #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling vector outline fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont */ FTGL_EXPORT FTGLfont *ftglCreateOutlineFont(const char *file); FTGL_END_C_DECLS #endif // __FTOutlineFont__ connectome-workbench-1.4.2/src/FtglFont/FTGL/FTGLPixmapFont.h000066400000000000000000000061161360521144700236200ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTPixmapFont__ #define __FTPixmapFont__ #ifdef __cplusplus /** * FTPixmapFont is a specialisation of the FTFont class for handling * Pixmap (Grey Scale) fonts * * @see FTFont */ class FTGL_EXPORT FTPixmapFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTPixmapFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTPixmapFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ ~FTPixmapFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #define FTGLPixmapFont FTPixmapFont #endif // __cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling pixmap (grey scale) fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont */ FTGL_EXPORT FTGLfont *ftglCreatePixmapFont(const char *file); FTGL_END_C_DECLS #endif // __FTPixmapFont__ connectome-workbench-1.4.2/src/FtglFont/FTGL/FTGLPolygonFont.h000066400000000000000000000061441360521144700240120ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTPolygonFont__ #define __FTPolygonFont__ #ifdef __cplusplus /** * FTPolygonFont is a specialisation of the FTFont class for handling * tesselated Polygon Mesh fonts * * @see FTFont */ class FTGL_EXPORT FTPolygonFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTPolygonFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTPolygonFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ ~FTPolygonFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #define FTGLPolygonFont FTPolygonFont #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling tesselated polygon * mesh fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont */ FTGL_EXPORT FTGLfont *ftglCreatePolygonFont(const char *file); FTGL_END_C_DECLS #endif // __FTPolygonFont__ connectome-workbench-1.4.2/src/FtglFont/FTGL/FTGLTextureFont.h000066400000000000000000000061261360521144700240230ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTTextureFont__ #define __FTTextureFont__ #ifdef __cplusplus /** * FTTextureFont is a specialisation of the FTFont class for handling * Texture mapped fonts * * @see FTFont */ class FTGL_EXPORT FTTextureFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTTextureFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTTextureFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ virtual ~FTTextureFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #define FTGLTextureFont FTTextureFont #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling texture-mapped fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont */ FTGL_EXPORT FTGLfont *ftglCreateTextureFont(const char *file); FTGL_END_C_DECLS #endif // __FTTextureFont__ connectome-workbench-1.4.2/src/FtglFont/FTGL/FTLayout.h000066400000000000000000000145451360521144700225720ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTLayout__ #define __FTLayout__ #ifdef __cplusplus class FTLayoutImpl; /** * FTLayout is the interface for layout managers that render text. * * Specific layout manager classes are derived from this class. This class * is abstract and deriving classes must implement the protected * Render methods to render formatted text and * BBox methods to determine the bounding box of output text. * * @see FTFont * @see FTBBox */ class FTGL_EXPORT FTLayout { protected: FTLayout(); private: /** * Internal FTGL FTLayout constructor. For private use only. * * @param pImpl Internal implementation object. Will be destroyed * upon FTLayout deletion. */ FTLayout(FTLayoutImpl *pImpl); /* Allow our internal subclasses to access the private constructor */ friend class FTSimpleLayout; public: /** * Destructor */ virtual ~FTLayout(); /** * Get the bounding box for a formatted string. * * @param string A char string. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @return The corresponding bounding box. */ virtual FTBBox BBox(const char* string, const int len = -1, FTPoint position = FTPoint()) = 0; /** * Get the bounding box for a formatted string. * * @param string A wchar_t string. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @return The corresponding bounding box. */ virtual FTBBox BBox(const wchar_t* string, const int len = -1, FTPoint position = FTPoint()) = 0; /** * Render a string of characters. * * @param string 'C' style string to be output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param renderMode Render mode to display (optional) */ virtual void Render(const char *string, const int len = -1, FTPoint position = FTPoint(), int renderMode = FTGL::RENDER_ALL) = 0; /** * Render a string of characters. * * @param string wchar_t string to be output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param renderMode Render mode to display (optional) */ virtual void Render(const wchar_t *string, const int len = -1, FTPoint position = FTPoint(), int renderMode = FTGL::RENDER_ALL) = 0; /** * Queries the Layout for errors. * * @return The current error code. */ virtual FT_Error Error() const; private: /** * Internal FTGL FTLayout implementation object. For private use only. */ FTLayoutImpl *impl; }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * FTGLlayout is the interface for layout managers that render text. */ struct _FTGLlayout; typedef struct _FTGLlayout FTGLlayout; /** * Destroy an FTGL layout object. * * @param layout An FTGLlayout* object. */ FTGL_EXPORT void ftglDestroyLayout(FTGLlayout* layout); /** * Get the bounding box for a string. * * @param layout An FTGLlayout* object. * @param string A char buffer * @param bounds An array of 6 float values where the bounding box's lower * left near and upper right far 3D coordinates will be stored. */ FTGL_EXPORT void ftglGetLayoutBBox(FTGLlayout *layout, const char* string, float bounds[6]); /** * Render a string of characters. * * @param layout An FTGLlayout* object. * @param string Char string to be output. * @param mode Render mode to display. */ FTGL_EXPORT void ftglRenderLayout(FTGLlayout *layout, const char *string, int mode); /** * Query a layout for errors. * * @param layout An FTGLlayout* object. * @return The current error code. */ FTGL_EXPORT FT_Error ftglGetLayoutError(FTGLlayout* layout); FTGL_END_C_DECLS #endif /* __FTLayout__ */ connectome-workbench-1.4.2/src/FtglFont/FTGL/FTOutlineGlyph.h000066400000000000000000000063511360521144700237340ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTOutlineGlyph__ #define __FTOutlineGlyph__ #ifdef __cplusplus /** * FTOutlineGlyph is a specialisation of FTGlyph for creating outlines. */ class FTGL_EXPORT FTOutlineGlyph : public FTGlyph { public: /** * Constructor. Sets the Error to Invalid_Outline if the glyphs isn't * an outline. * * @param glyph The Freetype glyph to be processed * @param outset outset distance * @param useDisplayList Enable or disable the use of Display Lists * for this glyph * true turns ON display lists. * false turns OFF display lists. */ FTOutlineGlyph(FT_GlyphSlot glyph, float outset, bool useDisplayList); /** * Destructor */ virtual ~FTOutlineGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialisation of FTGLglyph for creating outlines. * * @param glyph The Freetype glyph to be processed * @param outset outset contour size * @param useDisplayList Enable or disable the use of Display Lists * for this glyph * true turns ON display lists. * false turns OFF display lists. * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreateOutlineGlyph(FT_GlyphSlot glyph, float outset, int useDisplayList); FTGL_END_C_DECLS #endif // __FTOutlineGlyph__ connectome-workbench-1.4.2/src/FtglFont/FTGL/FTPixmapGlyph.h000066400000000000000000000047261360521144700235570ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTPixmapGlyph__ #define __FTPixmapGlyph__ #ifdef __cplusplus /** * FTPixmapGlyph is a specialisation of FTGlyph for creating pixmaps. */ class FTGL_EXPORT FTPixmapGlyph : public FTGlyph { public: /** * Constructor * * @param glyph The Freetype glyph to be processed */ FTPixmapGlyph(FT_GlyphSlot glyph); /** * Destructor */ virtual ~FTPixmapGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialisation of FTGLglyph for creating pixmaps. * * @param glyph The Freetype glyph to be processed * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreatePixmapGlyph(FT_GlyphSlot glyph); FTGL_END_C_DECLS #endif // __FTPixmapGlyph__ connectome-workbench-1.4.2/src/FtglFont/FTGL/FTPoint.h000066400000000000000000000170241360521144700224010ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTPoint__ #define __FTPoint__ #ifdef __cplusplus /** * FTPoint class is a basic 3-dimensional point or vector. */ class FTGL_EXPORT FTPoint { public: /** * Default constructor. Point is set to zero. */ inline FTPoint() { values[0] = 0; values[1] = 0; values[2] = 0; } /** * Constructor. Z coordinate is set to zero if unspecified. * * @param x First component * @param y Second component * @param z Third component */ inline FTPoint(const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z = 0) { values[0] = x; values[1] = y; values[2] = z; } /** * Constructor. This converts an FT_Vector to an FTPoint * * @param ft_vector A freetype vector */ inline FTPoint(const FT_Vector& ft_vector) { values[0] = ft_vector.x; values[1] = ft_vector.y; values[2] = 0; } /** * Normalise a point's coordinates. If the coordinates are zero, * the point is left untouched. * * @return A vector of norm one. */ FTPoint Normalise(); /** * Operator += In Place Addition. * * @param point * @return this plus point. */ inline FTPoint& operator += (const FTPoint& point) { values[0] += point.values[0]; values[1] += point.values[1]; values[2] += point.values[2]; return *this; } /** * Operator + * * @param point * @return this plus point. */ inline FTPoint operator + (const FTPoint& point) const { FTPoint temp; temp.values[0] = values[0] + point.values[0]; temp.values[1] = values[1] + point.values[1]; temp.values[2] = values[2] + point.values[2]; return temp; } /** * Operator -= In Place Substraction. * * @param point * @return this minus point. */ inline FTPoint& operator -= (const FTPoint& point) { values[0] -= point.values[0]; values[1] -= point.values[1]; values[2] -= point.values[2]; return *this; } /** * Operator - * * @param point * @return this minus point. */ inline FTPoint operator - (const FTPoint& point) const { FTPoint temp; temp.values[0] = values[0] - point.values[0]; temp.values[1] = values[1] - point.values[1]; temp.values[2] = values[2] - point.values[2]; return temp; } /** * Operator * Scalar multiplication * * @param multiplier * @return this multiplied by multiplier. */ inline FTPoint operator * (double multiplier) const { FTPoint temp; temp.values[0] = values[0] * multiplier; temp.values[1] = values[1] * multiplier; temp.values[2] = values[2] * multiplier; return temp; } /** * Operator * Scalar multiplication * * @param point * @param multiplier * @return multiplier multiplied by point. */ inline friend FTPoint operator * (double multiplier, FTPoint& point) { return point * multiplier; } /** * Operator * Scalar product * * @param a First vector. * @param b Second vector. * @return a.b scalar product. */ inline friend double operator * (FTPoint &a, FTPoint& b) { return a.values[0] * b.values[0] + a.values[1] * b.values[1] + a.values[2] * b.values[2]; } /** * Operator ^ Vector product * * @param point Second point * @return this vector point. */ inline FTPoint operator ^ (const FTPoint& point) { FTPoint temp; temp.values[0] = values[1] * point.values[2] - values[2] * point.values[1]; temp.values[1] = values[2] * point.values[0] - values[0] * point.values[2]; temp.values[2] = values[0] * point.values[1] - values[1] * point.values[0]; return temp; } /** * Operator == Tests for equality * * @param a * @param b * @return true if a & b are equal */ friend bool operator == (const FTPoint &a, const FTPoint &b); /** * Operator != Tests for non equality * * @param a * @param b * @return true if a & b are not equal */ friend bool operator != (const FTPoint &a, const FTPoint &b); /** * Cast to FTGL_DOUBLE* */ inline operator const FTGL_DOUBLE*() const { return values; } /** * Setters */ inline void X(FTGL_DOUBLE x) { values[0] = x; }; inline void Y(FTGL_DOUBLE y) { values[1] = y; }; inline void Z(FTGL_DOUBLE z) { values[2] = z; }; /** * Getters */ inline FTGL_DOUBLE X() const { return values[0]; }; inline FTGL_DOUBLE Y() const { return values[1]; }; inline FTGL_DOUBLE Z() const { return values[2]; }; inline FTGL_FLOAT Xf() const { return static_cast(values[0]); }; inline FTGL_FLOAT Yf() const { return static_cast(values[1]); }; inline FTGL_FLOAT Zf() const { return static_cast(values[2]); }; private: /** * The point data */ FTGL_DOUBLE values[3]; }; #endif //__cplusplus #endif // __FTPoint__ connectome-workbench-1.4.2/src/FtglFont/FTGL/FTPolyGlyph.h000066400000000000000000000065111360521144700232360ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTPolygonGlyph__ #define __FTPolygonGlyph__ #ifdef __cplusplus /** * FTPolygonGlyph is a specialisation of FTGlyph for creating tessellated * polygon glyphs. */ class FTGL_EXPORT FTPolygonGlyph : public FTGlyph { public: /** * Constructor. Sets the Error to Invalid_Outline if the glyphs * isn't an outline. * * @param glyph The Freetype glyph to be processed * @param outset The outset distance * @param useDisplayList Enable or disable the use of Display Lists * for this glyph * true turns ON display lists. * false turns OFF display lists. */ FTPolygonGlyph(FT_GlyphSlot glyph, float outset, bool useDisplayList); /** * Destructor */ virtual ~FTPolygonGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #define FTPolyGlyph FTPolygonGlyph #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialisation of FTGLglyph for creating tessellated * polygon glyphs. * * @param glyph The Freetype glyph to be processed * @param outset outset contour size * @param useDisplayList Enable or disable the use of Display Lists * for this glyph * true turns ON display lists. * false turns OFF display lists. * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreatePolygonGlyph(FT_GlyphSlot glyph, float outset, int useDisplayList); FTGL_END_C_DECLS #endif // __FTPolygonGlyph__ connectome-workbench-1.4.2/src/FtglFont/FTGL/FTSimpleLayout.h000066400000000000000000000147201360521144700237370ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTSimpleLayout__ #define __FTSimpleLayout__ #ifdef __cplusplus class FTFont; /** * FTSimpleLayout is a specialisation of FTLayout for simple text boxes. * * This class has basic support for text wrapping, left, right and centered * alignment, and text justification. * * @see FTLayout */ class FTGL_EXPORT FTSimpleLayout : public FTLayout { public: /** * Initializes line spacing to 1.0, alignment to * ALIGN_LEFT and wrap to 100.0 */ FTSimpleLayout(); /** * Destructor */ ~FTSimpleLayout(); /** * Get the bounding box for a formatted string. * * @param string A char string. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @return The corresponding bounding box. */ virtual FTBBox BBox(const char* string, const int len = -1, FTPoint position = FTPoint()); /** * Get the bounding box for a formatted string. * * @param string A wchar_t string. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @return The corresponding bounding box. */ virtual FTBBox BBox(const wchar_t* string, const int len = -1, FTPoint position = FTPoint()); /** * Render a string of characters. * * @param string 'C' style string to be output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param renderMode Render mode to display (optional) */ virtual void Render(const char *string, const int len = -1, FTPoint position = FTPoint(), int renderMode = FTGL::RENDER_ALL); /** * Render a string of characters. * * @param string wchar_t string to be output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param renderMode Render mode to display (optional) */ virtual void Render(const wchar_t *string, const int len = -1, FTPoint position = FTPoint(), int renderMode = FTGL::RENDER_ALL); /** * Set the font to use for rendering the text. * * @param fontInit A pointer to the new font. The font is * referenced by this but will not be * disposed of when this is deleted. */ void SetFont(FTFont *fontInit); /** * @return The current font. */ FTFont *GetFont(); /** * The maximum line length for formatting text. * * @param LineLength The new line length. */ void SetLineLength(const float LineLength); /** * @return The current line length. */ float GetLineLength() const; /** * The text alignment mode used to distribute * space within a line or rendered text. * * @param Alignment The new alignment mode. */ void SetAlignment(const FTGL::TextAlignment Alignment); /** * @return The text alignment mode. */ FTGL::TextAlignment GetAlignment() const; /** * Sets the line height. * * @param LineSpacing The height of each line of text expressed as * a percentage of the current fonts line height. */ void SetLineSpacing(const float LineSpacing); /** * @return The line spacing. */ float GetLineSpacing() const; }; #endif //__cplusplus FTGL_BEGIN_C_DECLS FTGL_EXPORT FTGLlayout *ftglCreateSimpleLayout(void); FTGL_EXPORT void ftglSetLayoutFont(FTGLlayout *, FTGLfont*); FTGL_EXPORT FTGLfont *ftglGetLayoutFont(FTGLlayout *); FTGL_EXPORT void ftglSetLayoutLineLength(FTGLlayout *, const float); FTGL_EXPORT float ftglGetLayoutLineLength(FTGLlayout *); FTGL_EXPORT void ftglSetLayoutAlignment(FTGLlayout *, const int); FTGL_EXPORT int ftglGetLayoutAlignement(FTGLlayout *); FTGL_EXPORT void ftglSetLayoutLineSpacing(FTGLlayout *, const float); FTGL_EXPORT float ftglGetLayoutLineSpacing(FTGLlayout *); FTGL_END_C_DECLS #endif /* __FTSimpleLayout__ */ connectome-workbench-1.4.2/src/FtglFont/FTGL/FTTextureGlyph.h000066400000000000000000000067771360521144700237710ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTTextureGlyph__ #define __FTTextureGlyph__ #ifdef __cplusplus /** * FTTextureGlyph is a specialisation of FTGlyph for creating texture * glyphs. */ class FTGL_EXPORT FTTextureGlyph : public FTGlyph { public: /** * Constructor * * @param glyph The Freetype glyph to be processed * @param id The id of the texture that this glyph will be * drawn in * @param xOffset The x offset into the parent texture to draw * this glyph * @param yOffset The y offset into the parent texture to draw * this glyph * @param width The width of the parent texture * @param height The height (number of rows) of the parent texture */ FTTextureGlyph(FT_GlyphSlot glyph, int id, int xOffset, int yOffset, int width, int height); /** * Destructor */ virtual ~FTTextureGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialisation of FTGLglyph for creating pixmaps. * * @param glyph The Freetype glyph to be processed. * @param id The id of the texture that this glyph will be drawn in. * @param xOffset The x offset into the parent texture to draw this glyph. * @param yOffset The y offset into the parent texture to draw this glyph. * @param width The width of the parent texture. * @param height The height (number of rows) of the parent texture. * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreateTextureGlyph(FT_GlyphSlot glyph, int id, int xOffset, int yOffset, int width, int height); FTGL_END_C_DECLS #endif // __FTTextureGlyph__ connectome-workbench-1.4.2/src/FtglFont/FTGL/ftgl.h000066400000000000000000000102011360521144700220000ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ #define __ftgl__ /* We need the Freetype headers */ #include #include FT_FREETYPE_H #include FT_GLYPH_H #include FT_OUTLINE_H /* Floating point types used by the library */ typedef double FTGL_DOUBLE; typedef float FTGL_FLOAT; /* Macros used to declare C-linkage types and symbols */ #ifdef __cplusplus # define FTGL_BEGIN_C_DECLS extern "C" { namespace FTGL { # define FTGL_END_C_DECLS } } #else # define FTGL_BEGIN_C_DECLS # define FTGL_END_C_DECLS #endif #ifdef __cplusplus namespace FTGL { typedef enum { RENDER_FRONT = 0x0001, RENDER_BACK = 0x0002, RENDER_SIDE = 0x0004, RENDER_ALL = 0xffff } RenderMode; typedef enum { ALIGN_LEFT = 0, ALIGN_CENTER = 1, ALIGN_RIGHT = 2, ALIGN_JUSTIFY = 3 } TextAlignment; } #else # define FTGL_RENDER_FRONT 0x0001 # define FTGL_RENDER_BACK 0x0002 # define FTGL_RENDER_SIDE 0x0004 # define FTGL_RENDER_ALL 0xffff # define FTGL_ALIGN_LEFT 0 # define FTGL_ALIGN_CENTER 1 # define FTGL_ALIGN_RIGHT 2 # define FTGL_ALIGN_JUSTIFY 3 #endif // Compiler-specific conditional compilation #ifdef _MSC_VER // MS Visual C++ // Disable various warning. // 4786: template name too long #pragma warning(disable : 4251) #pragma warning(disable : 4275) #pragma warning(disable : 4786) // The following definitions control how symbols are exported. // If the target is a static library ensure that FTGL_LIBRARY_STATIC // is defined. If building a dynamic library (ie DLL) ensure the // FTGL_LIBRARY macro is defined, as it will mark symbols for // export. If compiling a project to _use_ the _dynamic_ library // version of the library, no definition is required. #ifdef FTGL_LIBRARY_STATIC // static lib - no special export required # define FTGL_EXPORT #elif FTGL_LIBRARY // dynamic lib - must export/import symbols appropriately. # define FTGL_EXPORT __declspec(dllexport) #else # define FTGL_EXPORT __declspec(dllimport) #endif #else // Compiler that is not MS Visual C++. // Ensure that the export symbol is defined (and blank) #define FTGL_EXPORT #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif // __ftgl__ connectome-workbench-1.4.2/src/FtglFont/FTGlyph/000077500000000000000000000000001360521144700214625ustar00rootroot00000000000000connectome-workbench-1.4.2/src/FtglFont/FTGlyph/FTBitmapGlyph.cpp000066400000000000000000000065141360521144700246460ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2014 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTBitmapGlyphImpl.h" // // FTGLBitmapGlyph // FTBitmapGlyph::FTBitmapGlyph(FT_GlyphSlot glyph) : FTGlyph(new FTBitmapGlyphImpl(glyph)) {} FTBitmapGlyph::~FTBitmapGlyph() {} const FTPoint& FTBitmapGlyph::Render(const FTPoint& pen, int renderMode) { FTBitmapGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLBitmapGlyphImpl // FTBitmapGlyphImpl::FTBitmapGlyphImpl(FT_GlyphSlot glyph) : FTGlyphImpl(glyph), destWidth(0), destHeight(0), data(0) { err = FT_Render_Glyph(glyph, FT_RENDER_MODE_MONO); if(err || ft_glyph_format_bitmap != glyph->format) { return; } FT_Bitmap bitmap = glyph->bitmap; unsigned int srcWidth = bitmap.width; unsigned int srcHeight = bitmap.rows; unsigned int srcPitch = bitmap.pitch; destWidth = srcWidth; destHeight = srcHeight; destPitch = srcPitch; if(destWidth && destHeight) { data = new unsigned char[destPitch * destHeight]; unsigned char* dest = data + ((destHeight - 1) * destPitch); unsigned char* src = bitmap.buffer; for(unsigned int y = 0; y < srcHeight; ++y) { memcpy(dest, src, srcPitch); dest -= destPitch; src += srcPitch; } } pos = FTPoint(glyph->bitmap_left, static_cast(srcHeight) - glyph->bitmap_top, 0.0); } FTBitmapGlyphImpl::~FTBitmapGlyphImpl() { delete [] data; } const FTPoint& FTBitmapGlyphImpl::RenderImpl(const FTPoint& pen, int /*renderMode*/) { if(data) { float dx, dy; dx = pen.Xf() + pos.Xf(); dy = pen.Yf() - pos.Yf(); glBitmap(0, 0, 0.0f, 0.0f, dx, dy, (const GLubyte*)0); glPixelStorei(GL_UNPACK_ROW_LENGTH, destPitch * 8); glBitmap(destWidth, destHeight, 0.0f, 0.0, 0.0, 0.0, (const GLubyte*)data); glBitmap(0, 0, 0.0f, 0.0f, -dx, -dy, (const GLubyte*)0); } return advance; } connectome-workbench-1.4.2/src/FtglFont/FTGlyph/FTBitmapGlyphImpl.h000066400000000000000000000041411360521144700251270ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTBitmapGlyphImpl__ #define __FTBitmapGlyphImpl__ #include "FTGlyphImpl.h" class FTBitmapGlyphImpl : public FTGlyphImpl { friend class FTBitmapGlyph; protected: FTBitmapGlyphImpl(FT_GlyphSlot glyph); virtual ~FTBitmapGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: /** * The width of the glyph 'image' */ unsigned int destWidth; /** * The height of the glyph 'image' */ unsigned int destHeight; /** * The pitch of the glyph 'image' */ unsigned int destPitch; /** * Vector from the pen position to the topleft corner of the bitmap */ FTPoint pos; /** * Pointer to the 'image' data */ unsigned char* data; }; #endif // __FTBitmapGlyphImpl__ connectome-workbench-1.4.2/src/FtglFont/FTGlyph/FTBufferGlyph.cpp000066400000000000000000000064041360521144700246410ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2014 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTBufferGlyphImpl.h" // // FTGLBufferGlyph // FTBufferGlyph::FTBufferGlyph(FT_GlyphSlot glyph, FTBuffer *buffer) : FTGlyph(new FTBufferGlyphImpl(glyph, buffer)) {} FTBufferGlyph::~FTBufferGlyph() {} const FTPoint& FTBufferGlyph::Render(const FTPoint& pen, int renderMode) { FTBufferGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLBufferGlyphImpl // FTBufferGlyphImpl::FTBufferGlyphImpl(FT_GlyphSlot glyph, FTBuffer *p) : FTGlyphImpl(glyph), has_bitmap(false), buffer(p) { err = FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL); if(err || glyph->format != ft_glyph_format_bitmap) { return; } bitmap = glyph->bitmap; pixels = new unsigned char[bitmap.pitch * bitmap.rows]; memcpy(pixels, bitmap.buffer, bitmap.pitch * bitmap.rows); if(bitmap.width && bitmap.rows) { has_bitmap = true; corner = FTPoint(glyph->bitmap_left, glyph->bitmap_top); } } FTBufferGlyphImpl::~FTBufferGlyphImpl() { delete[] pixels; } const FTPoint& FTBufferGlyphImpl::RenderImpl(const FTPoint& pen, int /*renderMode*/) { if(has_bitmap) { FTPoint pos(buffer->Pos() + pen + corner); int dx = (int)(pos.Xf() + 0.5f); int dy = buffer->Height() - (int)(pos.Yf() + 0.5f); unsigned char * dest = buffer->Pixels() + dx + dy * buffer->Width(); for(int y = 0; y < ((int)bitmap.rows); y++) { // FIXME: change the loop bounds instead of doing this test if(y + dy < 0 || y + dy >= buffer->Height()) continue; for(int x = 0; x < ((int)bitmap.width); x++) { if(x + dx < 0 || x + dx >= buffer->Width()) continue; unsigned char p = pixels[y * bitmap.pitch + x]; if(p) { dest[y * buffer->Width() + x] = p; } } } } return advance; } connectome-workbench-1.4.2/src/FtglFont/FTGlyph/FTBufferGlyphImpl.h000066400000000000000000000032621360521144700251270ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTBufferGlyphImpl__ #define __FTBufferGlyphImpl__ #include "FTGlyphImpl.h" class FTBufferGlyphImpl : public FTGlyphImpl { friend class FTBufferGlyph; protected: FTBufferGlyphImpl(FT_GlyphSlot glyph, FTBuffer *p); virtual ~FTBufferGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: bool has_bitmap; FT_Bitmap bitmap; unsigned char *pixels; FTPoint corner; FTBuffer *buffer; }; #endif // __FTBufferGlyphImpl__ connectome-workbench-1.4.2/src/FtglFont/FTGlyph/FTExtrudeGlyph.cpp000066400000000000000000000164201360521144700250470ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2014 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTExtrudeGlyphImpl.h" #include "FTVectoriser.h" // // FTGLExtrudeGlyph // FTExtrudeGlyph::FTExtrudeGlyph(FT_GlyphSlot glyph, float depth, float frontOutset, float backOutset, bool useDisplayList) : FTGlyph(new FTExtrudeGlyphImpl(glyph, depth, frontOutset, backOutset, useDisplayList)) {} FTExtrudeGlyph::~FTExtrudeGlyph() {} const FTPoint& FTExtrudeGlyph::Render(const FTPoint& pen, int renderMode) { FTExtrudeGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLExtrudeGlyphImpl // FTExtrudeGlyphImpl::FTExtrudeGlyphImpl(FT_GlyphSlot glyph, float _depth, float _frontOutset, float _backOutset, bool useDisplayList) : FTGlyphImpl(glyph), vectoriser(0), glList(0) { bBox.SetDepth(-_depth); if(ft_glyph_format_outline != glyph->format) { err = 0x14; // Invalid_Outline return; } vectoriser = new FTVectoriser(glyph); if((vectoriser->ContourCount() < 1) || (vectoriser->PointCount() < 3)) { delete vectoriser; vectoriser = NULL; return; } hscale = glyph->face->size->metrics.x_ppem * 64; vscale = glyph->face->size->metrics.y_ppem * 64; depth = _depth; frontOutset = _frontOutset; backOutset = _backOutset; if(useDisplayList) { glList = glGenLists(3); /* Front face */ glNewList(glList + 0, GL_COMPILE); RenderFront(); glEndList(); /* Back face */ glNewList(glList + 1, GL_COMPILE); RenderBack(); glEndList(); /* Side face */ glNewList(glList + 2, GL_COMPILE); RenderSide(); glEndList(); delete vectoriser; vectoriser = NULL; } } FTExtrudeGlyphImpl::~FTExtrudeGlyphImpl() { if(glList) { glDeleteLists(glList, 3); } else if(vectoriser) { delete vectoriser; } } const FTPoint& FTExtrudeGlyphImpl::RenderImpl(const FTPoint& pen, int renderMode) { glTranslatef(pen.Xf(), pen.Yf(), pen.Zf()); if(glList) { if(renderMode & FTGL::RENDER_FRONT) glCallList(glList + 0); if(renderMode & FTGL::RENDER_BACK) glCallList(glList + 1); if(renderMode & FTGL::RENDER_SIDE) glCallList(glList + 2); } else if(vectoriser) { if(renderMode & FTGL::RENDER_FRONT) RenderFront(); if(renderMode & FTGL::RENDER_BACK) RenderBack(); if(renderMode & FTGL::RENDER_SIDE) RenderSide(); } glTranslatef(-pen.Xf(), -pen.Yf(), -pen.Zf()); return advance; } void FTExtrudeGlyphImpl::RenderFront() { vectoriser->MakeMesh(1.0, 1, frontOutset); glNormal3d(0.0, 0.0, 1.0); const FTMesh *mesh = vectoriser->GetMesh(); for(unsigned int j = 0; j < mesh->TesselationCount(); ++j) { const FTTesselation* subMesh = mesh->Tesselation(j); unsigned int polygonType = subMesh->PolygonType(); glBegin(polygonType); for(unsigned int i = 0; i < subMesh->PointCount(); ++i) { FTPoint pt = subMesh->Point(i); glTexCoord2f(pt.Xf() / hscale, pt.Yf() / vscale); glVertex3f(pt.Xf() / 64.0f, pt.Yf() / 64.0f, 0.0f); } glEnd(); } } void FTExtrudeGlyphImpl::RenderBack() { vectoriser->MakeMesh(-1.0, 2, backOutset); glNormal3d(0.0, 0.0, -1.0); const FTMesh *mesh = vectoriser->GetMesh(); for(unsigned int j = 0; j < mesh->TesselationCount(); ++j) { const FTTesselation* subMesh = mesh->Tesselation(j); unsigned int polygonType = subMesh->PolygonType(); glBegin(polygonType); for(unsigned int i = 0; i < subMesh->PointCount(); ++i) { //FTPoint pt = subMesh->Point(i); glTexCoord2f(subMesh->Point(i).Xf() / hscale, subMesh->Point(i).Yf() / vscale); glVertex3f(subMesh->Point(i).Xf() / 64.0f, subMesh->Point(i).Yf() / 64.0f, -depth); } glEnd(); } } void FTExtrudeGlyphImpl::RenderSide() { int contourFlag = vectoriser->ContourFlag(); for(size_t c = 0; c < vectoriser->ContourCount(); ++c) { const FTContour* contour = vectoriser->Contour(c); size_t n = contour->PointCount(); if(n < 2) { continue; } glBegin(GL_QUAD_STRIP); for(size_t j = 0; j <= n; ++j) { size_t cur = (j == n) ? 0 : j; size_t next = (cur == n - 1) ? 0 : cur + 1; FTPoint frontPt = contour->FrontPoint(cur); FTPoint nextPt = contour->FrontPoint(next); FTPoint backPt = contour->BackPoint(cur); FTPoint normal = FTPoint(0.f, 0.f, 1.f) ^ (frontPt - nextPt); if(normal != FTPoint(0.0f, 0.0f, 0.0f)) { glNormal3dv(static_cast(normal.Normalise())); } glTexCoord2f(frontPt.Xf() / hscale, frontPt.Yf() / vscale); if(contourFlag & ft_outline_reverse_fill) { glVertex3f(backPt.Xf() / 64.0f, backPt.Yf() / 64.0f, 0.0f); glVertex3f(frontPt.Xf() / 64.0f, frontPt.Yf() / 64.0f, -depth); } else { glVertex3f(backPt.Xf() / 64.0f, backPt.Yf() / 64.0f, -depth); glVertex3f(frontPt.Xf() / 64.0f, frontPt.Yf() / 64.0f, 0.0f); } } glEnd(); } } connectome-workbench-1.4.2/src/FtglFont/FTGlyph/FTExtrudeGlyphImpl.h000066400000000000000000000042011360521144700253300ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTExtrudeGlyphImpl__ #define __FTExtrudeGlyphImpl__ #include "FTGlyphImpl.h" class FTVectoriser; class FTExtrudeGlyphImpl : public FTGlyphImpl { friend class FTExtrudeGlyph; protected: FTExtrudeGlyphImpl(FT_GlyphSlot glyph, float depth, float frontOutset, float backOutset, bool useDisplayList); virtual ~FTExtrudeGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: /** * Private rendering methods. */ void RenderFront(); void RenderBack(); void RenderSide(); /** * Private rendering variables. */ unsigned int hscale, vscale; float depth; float frontOutset, backOutset; FTVectoriser *vectoriser; /** * OpenGL display list */ GLuint glList; }; #endif // __FTExtrudeGlyphImpl__ connectome-workbench-1.4.2/src/FtglFont/FTGlyph/FTGlyph.cpp000066400000000000000000000043431360521144700235070ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2014 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTGlyphImpl.h" // // FTGlyph // FTGlyph::FTGlyph(FT_GlyphSlot glyph) { impl = new FTGlyphImpl(glyph); } FTGlyph::FTGlyph(FTGlyphImpl *pImpl) { impl = pImpl; } FTGlyph::~FTGlyph() { delete impl; } float FTGlyph::Advance() const { return impl->Advance(); } const FTBBox& FTGlyph::BBox() const { return impl->BBox(); } FT_Error FTGlyph::Error() const { return impl->Error(); } // // FTGlyphImpl // FTGlyphImpl::FTGlyphImpl(FT_GlyphSlot glyph, bool /*useList*/) : err(0) { if(glyph) { bBox = FTBBox(glyph); advance = FTPoint(glyph->advance.x / 64.0f, glyph->advance.y / 64.0f); } } FTGlyphImpl::~FTGlyphImpl() {} float FTGlyphImpl::Advance() const { return advance.Xf(); } const FTBBox& FTGlyphImpl::BBox() const { return bBox; } FT_Error FTGlyphImpl::Error() const { return err; } connectome-workbench-1.4.2/src/FtglFont/FTGlyph/FTGlyphGlue.cpp000066400000000000000000000147401360521144700243260ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTGL/ftgl.h" #include "FTInternals.h" static const FTPoint static_ftpoint; static const FTBBox static_ftbbox; FTGL_BEGIN_C_DECLS #define C_TOR(cname, cargs, cxxname, cxxarg, cxxtype) \ FTGLglyph* cname cargs \ { \ cxxname *g = new cxxname cxxarg; \ if(g->Error()) \ { \ delete g; \ return NULL; \ } \ FTGLglyph *ftgl = (FTGLglyph *)malloc(sizeof(FTGLglyph)); \ ftgl->ptr = g; \ ftgl->type = cxxtype; \ return ftgl; \ } // FTBitmapGlyph::FTBitmapGlyph(); C_TOR(ftglCreateBitmapGlyph, (FT_GlyphSlot glyph), FTBitmapGlyph, (glyph), GLYPH_BITMAP); // FTBufferGlyph::FTBufferGlyph(); // FIXME: not implemented // FTExtrudeGlyph::FTExtrudeGlyph(); C_TOR(ftglCreateExtrudeGlyph, (FT_GlyphSlot glyph, float depth, float frontOutset, float backOutset, int useDisplayList), FTExtrudeGlyph, (glyph, depth, frontOutset, backOutset, (useDisplayList != 0)), GLYPH_EXTRUDE); // FTOutlineGlyph::FTOutlineGlyph(); C_TOR(ftglCreateOutlineGlyph, (FT_GlyphSlot glyph, float outset, int useDisplayList), FTOutlineGlyph, (glyph, outset, (useDisplayList != 0)), GLYPH_OUTLINE); // FTPixmapGlyph::FTPixmapGlyph(); C_TOR(ftglCreatePixmapGlyph, (FT_GlyphSlot glyph), FTPixmapGlyph, (glyph), GLYPH_PIXMAP); // FTPolygonGlyph::FTPolygonGlyph(); C_TOR(ftglCreatePolygonGlyph, (FT_GlyphSlot glyph, float outset, int useDisplayList), FTPolygonGlyph, (glyph, outset, (useDisplayList != 0)), GLYPH_POLYGON); // FTTextureGlyph::FTTextureGlyph(); C_TOR(ftglCreateTextureGlyph, (FT_GlyphSlot glyph, int id, int xOffset, int yOffset, int width, int height), FTTextureGlyph, (glyph, id, xOffset, yOffset, width, height), GLYPH_TEXTURE); // FTCustomGlyph::FTCustomGlyph(); class FTCustomGlyph : public FTGlyph { public: FTCustomGlyph(FTGLglyph *base, void *p, void (*render) (FTGLglyph *, void *, FTGL_DOUBLE, FTGL_DOUBLE, int, FTGL_DOUBLE *, FTGL_DOUBLE *), void (*destroy) (FTGLglyph *, void *)) : FTGlyph((FT_GlyphSlot)0), baseGlyph(base), data(p), renderCallback(render), destroyCallback(destroy) {} ~FTCustomGlyph() { destroyCallback(baseGlyph, data); } float Advance() const { return baseGlyph->ptr->Advance(); } const FTPoint& Render(const FTPoint& pen, int renderMode) { FTGL_DOUBLE advancex, advancey; renderCallback(baseGlyph, data, pen.X(), pen.Y(), renderMode, &advancex, &advancey); advance = FTPoint(advancex, advancey); return advance; } const FTBBox& BBox() const { return baseGlyph->ptr->BBox(); } FT_Error Error() const { return baseGlyph->ptr->Error(); } private: FTPoint advance; FTGLglyph *baseGlyph; void *data; void (*renderCallback) (FTGLglyph *, void *, FTGL_DOUBLE, FTGL_DOUBLE, int, FTGL_DOUBLE *, FTGL_DOUBLE *); void (*destroyCallback) (FTGLglyph *, void *); }; C_TOR(ftglCreateCustomGlyph, (FTGLglyph *base, void *data, void (*renderCallback) (FTGLglyph *, void *, FTGL_DOUBLE, FTGL_DOUBLE, int, FTGL_DOUBLE *, FTGL_DOUBLE *), void (*destroyCallback) (FTGLglyph *, void *)), FTCustomGlyph, (base, data, renderCallback, destroyCallback), GLYPH_CUSTOM); #define C_FUN(cret, cname, cargs, cxxerr, cxxname, cxxarg) \ cret cname cargs \ { \ if(!g || !g->ptr) \ { \ fprintf(stderr, "FTGL warning: NULL pointer in %s\n", #cname); \ cxxerr; \ } \ return g->ptr->cxxname cxxarg; \ } // FTGlyph::~FTGlyph(); void ftglDestroyGlyph(FTGLglyph *g) { if(!g || !g->ptr) { fprintf(stderr, "FTGL warning: NULL pointer in %s\n", __FUNCTION__); return; } delete g->ptr; free(g); } // const FTPoint& FTGlyph::Render(const FTPoint& pen, int renderMode); extern "C++" { C_FUN(static const FTPoint&, _ftglRenderGlyph, (FTGLglyph *g, const FTPoint& pen, int renderMode), return static_ftpoint, Render, (pen, renderMode)); } void ftglRenderGlyph(FTGLglyph *g, FTGL_DOUBLE penx, FTGL_DOUBLE peny, int renderMode, FTGL_DOUBLE *advancex, FTGL_DOUBLE *advancey) { FTPoint pen(penx, peny); FTPoint ret = _ftglRenderGlyph(g, pen, renderMode); *advancex = ret.X(); *advancey = ret.Y(); } // float FTGlyph::Advance() const; C_FUN(float, ftglGetGlyphAdvance, (FTGLglyph *g), return 0.0, Advance, ()); // const FTBBox& FTGlyph::BBox() const; extern "C++" { C_FUN(static const FTBBox&, _ftglGetGlyphBBox, (FTGLglyph *g), return static_ftbbox, BBox, ()); } void ftglGetGlyphBBox(FTGLglyph *g, float bounds[6]) { FTBBox ret = _ftglGetGlyphBBox(g); FTPoint lower = ret.Lower(), upper = ret.Upper(); bounds[0] = lower.Xf(); bounds[1] = lower.Yf(); bounds[2] = lower.Zf(); bounds[3] = upper.Xf(); bounds[4] = upper.Yf(); bounds[5] = upper.Zf(); } // FT_Error FTGlyph::Error() const; C_FUN(FT_Error, ftglGetGlyphError, (FTGLglyph *g), return -1, Error, ()); FTGL_END_C_DECLS connectome-workbench-1.4.2/src/FtglFont/FTGlyph/FTGlyphImpl.h000066400000000000000000000035401360521144700237740ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTGlyphImpl__ #define __FTGlyphImpl__ #include "FTGL/ftgl.h" class FTGlyphImpl { friend class FTGlyph; protected: FTGlyphImpl(FT_GlyphSlot glyph, bool useDisplayList = true); virtual ~FTGlyphImpl(); float Advance() const; const FTBBox& BBox() const; FT_Error Error() const; /** * The advance distance for this glyph */ FTPoint advance; /** * The bounding box of this glyph. */ FTBBox bBox; /** * Current error code. Zero means no error. */ FT_Error err; }; #endif // __FTGlyphImpl__ connectome-workbench-1.4.2/src/FtglFont/FTGlyph/FTOutlineGlyph.cpp000066400000000000000000000074351360521144700250540ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2014 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTOutlineGlyphImpl.h" #include "FTVectoriser.h" // // FTGLOutlineGlyph // FTOutlineGlyph::FTOutlineGlyph(FT_GlyphSlot glyph, float outset, bool useDisplayList) : FTGlyph(new FTOutlineGlyphImpl(glyph, outset, useDisplayList)) {} FTOutlineGlyph::~FTOutlineGlyph() {} const FTPoint& FTOutlineGlyph::Render(const FTPoint& pen, int renderMode) { FTOutlineGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLOutlineGlyphImpl // FTOutlineGlyphImpl::FTOutlineGlyphImpl(FT_GlyphSlot glyph, float _outset, bool useDisplayList) : FTGlyphImpl(glyph), glList(0) { if(ft_glyph_format_outline != glyph->format) { err = 0x14; // Invalid_Outline return; } vectoriser = new FTVectoriser(glyph); if((vectoriser->ContourCount() < 1) || (vectoriser->PointCount() < 3)) { delete vectoriser; vectoriser = NULL; return; } outset = _outset; if(useDisplayList) { glList = glGenLists(1); glNewList(glList, GL_COMPILE); DoRender(); glEndList(); delete vectoriser; vectoriser = NULL; } } FTOutlineGlyphImpl::~FTOutlineGlyphImpl() { if(glList) { glDeleteLists(glList, 1); } else if(vectoriser) { delete vectoriser; } } const FTPoint& FTOutlineGlyphImpl::RenderImpl(const FTPoint& pen, int /*renderMode*/) { glTranslatef(pen.Xf(), pen.Yf(), pen.Zf()); if(glList) { glCallList(glList); } else if(vectoriser) { DoRender(); } glTranslatef(-pen.Xf(), -pen.Yf(), -pen.Zf()); return advance; } void FTOutlineGlyphImpl::DoRender() { for(unsigned int c = 0; c < vectoriser->ContourCount(); ++c) { const FTContour* contour = vectoriser->Contour(c); glBegin(GL_LINE_LOOP); for(unsigned int i = 0; i < contour->PointCount(); ++i) { FTPoint point = FTPoint(contour->Point(i).X() + contour->Outset(i).X() * outset, contour->Point(i).Y() + contour->Outset(i).Y() * outset, 0); glVertex2f(point.Xf() / 64.0f, point.Yf() / 64.0f); } glEnd(); } } connectome-workbench-1.4.2/src/FtglFont/FTGlyph/FTOutlineGlyphImpl.h000066400000000000000000000040301360521144700253270ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTOutlineGlyphImpl__ #define __FTOutlineGlyphImpl__ #include "FTGlyphImpl.h" class FTVectoriser; class FTOutlineGlyphImpl : public FTGlyphImpl { friend class FTOutlineGlyph; protected: FTOutlineGlyphImpl(FT_GlyphSlot glyph, float outset, bool useDisplayList); virtual ~FTOutlineGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: /** * Private rendering method. */ void DoRender(); /** * Private rendering variables. */ FTVectoriser *vectoriser; /** * Private rendering variables. */ float outset; /** * OpenGL display list */ GLuint glList; }; #endif // __FTOutlineGlyphImpl__ connectome-workbench-1.4.2/src/FtglFont/FTGlyph/FTPixmapGlyph.cpp000066400000000000000000000070761360521144700246740ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2014 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTPixmapGlyphImpl.h" // // FTGLPixmapGlyph // FTPixmapGlyph::FTPixmapGlyph(FT_GlyphSlot glyph) : FTGlyph(new FTPixmapGlyphImpl(glyph)) {} FTPixmapGlyph::~FTPixmapGlyph() {} const FTPoint& FTPixmapGlyph::Render(const FTPoint& pen, int renderMode) { FTPixmapGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLPixmapGlyphImpl // FTPixmapGlyphImpl::FTPixmapGlyphImpl(FT_GlyphSlot glyph) : FTGlyphImpl(glyph), destWidth(0), destHeight(0), data(0) { err = FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL); if(err || ft_glyph_format_bitmap != glyph->format) { return; } FT_Bitmap bitmap = glyph->bitmap; //check the pixel mode //ft_pixel_mode_grays int srcWidth = bitmap.width; int srcHeight = bitmap.rows; destWidth = srcWidth; destHeight = srcHeight; if(destWidth && destHeight) { data = new unsigned char[destWidth * destHeight * 2]; unsigned char* src = bitmap.buffer; unsigned char* dest = data + ((destHeight - 1) * destWidth * 2); size_t destStep = destWidth * 2 * 2; for(int y = 0; y < srcHeight; ++y) { for(int x = 0; x < srcWidth; ++x) { *dest++ = static_cast(255); *dest++ = *src++; } dest -= destStep; } destHeight = srcHeight; } pos.X(glyph->bitmap_left); pos.Y(srcHeight - glyph->bitmap_top); } FTPixmapGlyphImpl::~FTPixmapGlyphImpl() { delete [] data; } const FTPoint& FTPixmapGlyphImpl::RenderImpl(const FTPoint& pen, int /*renderMode*/) { if(data) { float dx, dy; dx = floor(pen.Xf() + pos.Xf()); dy = floor(pen.Yf() - pos.Yf()); glBitmap(0, 0, 0.0f, 0.0f, dx, dy, (const GLubyte*)0); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_ALIGNMENT, 2); glDrawPixels(destWidth, destHeight, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, (const GLvoid*)data); glBitmap(0, 0, 0.0f, 0.0f, -dx, -dy, (const GLubyte*)0); } return advance; } connectome-workbench-1.4.2/src/FtglFont/FTGlyph/FTPixmapGlyphImpl.h000066400000000000000000000037551360521144700251630ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTPixmapGlyphImpl__ #define __FTPixmapGlyphImpl__ #include "FTGlyphImpl.h" class FTPixmapGlyphImpl : public FTGlyphImpl { friend class FTPixmapGlyph; protected: FTPixmapGlyphImpl(FT_GlyphSlot glyph); virtual ~FTPixmapGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: /** * The width of the glyph 'image' */ int destWidth; /** * The height of the glyph 'image' */ int destHeight; /** * Vector from the pen position to the topleft corner of the pixmap */ FTPoint pos; /** * Pointer to the 'image' data */ unsigned char* data; }; #endif // __FTPixmapGlyphImpl__ connectome-workbench-1.4.2/src/FtglFont/FTGlyph/FTPolygonGlyph.cpp000066400000000000000000000076531360521144700250660ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2014 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTPolygonGlyphImpl.h" #include "FTVectoriser.h" // // FTGLPolyGlyph // FTPolygonGlyph::FTPolygonGlyph(FT_GlyphSlot glyph, float outset, bool useDisplayList) : FTGlyph(new FTPolygonGlyphImpl(glyph, outset, useDisplayList)) {} FTPolygonGlyph::~FTPolygonGlyph() {} const FTPoint& FTPolygonGlyph::Render(const FTPoint& pen, int renderMode) { FTPolygonGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLPolyGlyphImpl // FTPolygonGlyphImpl::FTPolygonGlyphImpl(FT_GlyphSlot glyph, float _outset, bool useDisplayList) : FTGlyphImpl(glyph), glList(0) { if(ft_glyph_format_outline != glyph->format) { err = 0x14; // Invalid_Outline return; } vectoriser = new FTVectoriser(glyph); if((vectoriser->ContourCount() < 1) || (vectoriser->PointCount() < 3)) { delete vectoriser; vectoriser = NULL; return; } hscale = glyph->face->size->metrics.x_ppem * 64; vscale = glyph->face->size->metrics.y_ppem * 64; outset = _outset; if(useDisplayList) { glList = glGenLists(1); glNewList(glList, GL_COMPILE); DoRender(); glEndList(); delete vectoriser; vectoriser = NULL; } } FTPolygonGlyphImpl::~FTPolygonGlyphImpl() { if(glList) { glDeleteLists(glList, 1); } else if(vectoriser) { delete vectoriser; } } const FTPoint& FTPolygonGlyphImpl::RenderImpl(const FTPoint& pen, int /*renderMode*/) { glTranslatef(pen.Xf(), pen.Yf(), pen.Zf()); if(glList) { glCallList(glList); } else if(vectoriser) { DoRender(); } glTranslatef(-pen.Xf(), -pen.Yf(), -pen.Zf()); return advance; } void FTPolygonGlyphImpl::DoRender() { vectoriser->MakeMesh(1.0, 1, outset); const FTMesh *mesh = vectoriser->GetMesh(); for(unsigned int t = 0; t < mesh->TesselationCount(); ++t) { const FTTesselation* subMesh = mesh->Tesselation(t); unsigned int polygonType = subMesh->PolygonType(); glBegin(polygonType); for(unsigned int i = 0; i < subMesh->PointCount(); ++i) { FTPoint point = subMesh->Point(i); glTexCoord2f(point.Xf() / hscale, point.Yf() / vscale); glVertex3f(point.Xf() / 64.0f, point.Yf() / 64.0f, 0.0f); } glEnd(); } } connectome-workbench-1.4.2/src/FtglFont/FTGlyph/FTPolygonGlyphImpl.h000066400000000000000000000037721360521144700253530ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTPolygonGlyphImpl__ #define __FTPolygonGlyphImpl__ #include "FTGlyphImpl.h" class FTVectoriser; class FTPolygonGlyphImpl : public FTGlyphImpl { friend class FTPolygonGlyph; public: FTPolygonGlyphImpl(FT_GlyphSlot glyph, float outset, bool useDisplayList); virtual ~FTPolygonGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: /** * Private rendering method. */ void DoRender(); /** * Private rendering variables. */ unsigned int hscale, vscale; FTVectoriser *vectoriser; float outset; /** * OpenGL display list */ GLuint glList; }; #endif // __FTPolygonGlyphImpl__ connectome-workbench-1.4.2/src/FtglFont/FTGlyph/FTTextureGlyph.cpp000066400000000000000000000121721360521144700250670ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2014 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "CaretOpenGLInclude.h" // Must be here to prevent GLEW error on Windows #include "FtglConfig.h" #include #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTTextureGlyphImpl.h" #include "CaretLogger.h" #include "GraphicsOpenGLError.h" #include "GraphicsUtilitiesOpenGL.h" // // FTGLTextureGlyph // FTTextureGlyph::FTTextureGlyph(FT_GlyphSlot glyph, int id, int xOffset, int yOffset, int width, int height) : FTGlyph(new FTTextureGlyphImpl(glyph, id, xOffset, yOffset, width, height)) {} FTTextureGlyph::~FTTextureGlyph() {} const FTPoint& FTTextureGlyph::Render(const FTPoint& pen, int renderMode) { FTTextureGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLTextureGlyphImpl // GLint FTTextureGlyphImpl::activeTextureID = 0; FTTextureGlyphImpl::FTTextureGlyphImpl(FT_GlyphSlot glyph, int id, int xOffset, int yOffset, int width, int height) : FTGlyphImpl(glyph), destWidth(0), destHeight(0), glTextureID(id) { /* FIXME: need to propagate the render mode all the way down to * here in order to get FT_RENDER_MODE_MONO aliased fonts. */ err = FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL); if(err || glyph->format != ft_glyph_format_bitmap) { return; } FT_Bitmap bitmap = glyph->bitmap; destWidth = bitmap.width; destHeight = bitmap.rows; if(destWidth && destHeight) { glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glBindTexture(GL_TEXTURE_2D, glTextureID); /* * Check for an OpenGL error. * We will ignore errors caused by glTexSubImage2D() as it will cause * OpenGL "Invalid Value" errors when some text characters get too small. */ std::unique_ptr openglError = caret::GraphicsUtilitiesOpenGL::getOpenGLError("FTGL before call to glTexSubImage2D()"); if (openglError) { CaretLogWarning(openglError->getVerboseDescription()); } glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, destWidth, destHeight, GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.buffer); /** * Reset and ignore any OpenGL errors generated by glTexSubImage2D. */ caret::GraphicsUtilitiesOpenGL::resetOpenGLError(); glPopClientAttrib(); } // 0 // +----+ // | | // | | // | | // +----+ // 1 uv[0].X(static_cast(xOffset) / static_cast(width)); uv[0].Y(static_cast(yOffset) / static_cast(height)); uv[1].X(static_cast(xOffset + destWidth) / static_cast(width)); uv[1].Y(static_cast(yOffset + destHeight) / static_cast(height)); corner = FTPoint(glyph->bitmap_left, glyph->bitmap_top); } FTTextureGlyphImpl::~FTTextureGlyphImpl() {} const FTPoint& FTTextureGlyphImpl::RenderImpl(const FTPoint& pen, int /*renderMode*/) { float dx, dy; if(activeTextureID != glTextureID) { glBindTexture(GL_TEXTURE_2D, (GLuint)glTextureID); activeTextureID = glTextureID; } dx = floor(pen.Xf() + corner.Xf()); dy = floor(pen.Yf() + corner.Yf()); glBegin(GL_QUADS); glTexCoord2f(uv[0].Xf(), uv[0].Yf()); glVertex2f(dx, dy); glTexCoord2f(uv[0].Xf(), uv[1].Yf()); glVertex2f(dx, dy - destHeight); glTexCoord2f(uv[1].Xf(), uv[1].Yf()); glVertex2f(dx + destWidth, dy - destHeight); glTexCoord2f(uv[1].Xf(), uv[0].Yf()); glVertex2f(dx + destWidth, dy); glEnd(); return advance; } connectome-workbench-1.4.2/src/FtglFont/FTGlyph/FTTextureGlyphImpl.h000066400000000000000000000053771360521144700253670ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTTextureGlyphImpl__ #define __FTTextureGlyphImpl__ #include "FTGlyphImpl.h" class FTTextureGlyphImpl : public FTGlyphImpl { friend class FTTextureGlyph; friend class FTTextureFontImpl; protected: FTTextureGlyphImpl(FT_GlyphSlot glyph, int id, int xOffset, int yOffset, int width, int height); virtual ~FTTextureGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: /** * Reset the currently active texture to zero to get into a known * state before drawing a string. This is to get round possible * threading issues. */ static void ResetActiveTexture() { activeTextureID = 0; } /** * The width of the glyph 'image' */ int destWidth; /** * The height of the glyph 'image' */ int destHeight; /** * Vector from the pen position to the topleft corner of the pixmap */ FTPoint corner; /** * The texture co-ords of this glyph within the texture. */ FTPoint uv[2]; /** * The texture index that this glyph is contained in. */ int glTextureID; /** * The texture index of the currently active texture * * We keep track of the currently active texture to try to reduce the * number of texture bind operations. */ static GLint activeTextureID; }; #endif // __FTTextureGlyphImpl__ connectome-workbench-1.4.2/src/FtglFont/FTGlyphContainer.cpp000066400000000000000000000064611360521144700240400ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2014 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTGL/ftgl.h" #include "FTGlyphContainer.h" #include "FTFace.h" #include "FTCharmap.h" FTGlyphContainer::FTGlyphContainer(FTFace* f) : face(f), err(0) { glyphs.push_back(NULL); charMap = new FTCharmap(face); } FTGlyphContainer::~FTGlyphContainer() { GlyphVector::iterator it; for(it = glyphs.begin(); it != glyphs.end(); ++it) { delete *it; } glyphs.clear(); delete charMap; } bool FTGlyphContainer::CharMap(FT_Encoding encoding) { bool result = charMap->CharMap(encoding); err = charMap->Error(); return result; } unsigned int FTGlyphContainer::FontIndex(const unsigned int charCode) const { return charMap->FontIndex(charCode); } void FTGlyphContainer::Add(FTGlyph* tempGlyph, const unsigned int charCode) { charMap->InsertIndex(charCode, glyphs.size()); glyphs.push_back(tempGlyph); } const FTGlyph* /*const*/ FTGlyphContainer::Glyph(const unsigned int charCode) const { unsigned int index = charMap->GlyphListIndex(charCode); return glyphs[index]; } FTBBox FTGlyphContainer::BBox(const unsigned int charCode) const { return Glyph(charCode)->BBox(); } float FTGlyphContainer::Advance(const unsigned int charCode, const unsigned int nextCharCode) { unsigned int left = charMap->FontIndex(charCode); unsigned int right = charMap->FontIndex(nextCharCode); return face->KernAdvance(left, right).Xf() + Glyph(charCode)->Advance(); } FTPoint FTGlyphContainer::Render(const unsigned int charCode, const unsigned int nextCharCode, FTPoint penPosition, int renderMode) { unsigned int left = charMap->FontIndex(charCode); unsigned int right = charMap->FontIndex(nextCharCode); FTPoint kernAdvance = face->KernAdvance(left, right); if(!face->Error()) { unsigned int index = charMap->GlyphListIndex(charCode); kernAdvance += glyphs[index]->Render(penPosition, renderMode); } return kernAdvance; } connectome-workbench-1.4.2/src/FtglFont/FTGlyphContainer.h000066400000000000000000000116201360521144700234760ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2014 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTGlyphContainer__ #define __FTGlyphContainer__ #include #include FT_FREETYPE_H #include FT_GLYPH_H #include "FTGL/ftgl.h" #include "FTVector.h" class FTFace; class FTGlyph; class FTCharmap; /** * FTGlyphContainer holds the post processed FTGlyph objects. * * @see FTGlyph */ class FTGlyphContainer { typedef FTVector GlyphVector; public: /** * Constructor * * @param face The Freetype face */ FTGlyphContainer(FTFace* face); /** * Destructor */ ~FTGlyphContainer(); /** * Sets the character map for the face. * * @param encoding the Freetype encoding symbol. See above. * @return true if charmap was valid * and set correctly */ bool CharMap(FT_Encoding encoding); /** * Get the font index of the input character. * * @param characterCode The character code of the requested glyph in the * current encoding eg apple roman. * @return The font index for the character. */ unsigned int FontIndex(const unsigned int characterCode) const; /** * Adds a glyph to this glyph list. * * @param glyph The FTGlyph to be inserted into the container * @param characterCode The char code of the glyph NOT the glyph index. */ void Add(FTGlyph* glyph, const unsigned int characterCode); /** * Get a glyph from the glyph list * * @param characterCode The char code of the glyph NOT the glyph index * @return An FTGlyph or null is it hasn't been * loaded. */ const FTGlyph* /*const*/ Glyph(const unsigned int characterCode) const; /** * Get the bounding box for a character. * @param characterCode The char code of the glyph NOT the glyph index */ FTBBox BBox(const unsigned int characterCode) const; /** * Returns the kerned advance width for a glyph. * * @param characterCode glyph index of the character * @param nextCharacterCode the next glyph in a string * @return advance width */ float Advance(const unsigned int characterCode, const unsigned int nextCharacterCode); /** * Renders a character * @param characterCode the glyph to be Rendered * @param nextCharacterCode the next glyph in the string. Used for kerning. * @param penPosition the position to Render the glyph * @param renderMode Render mode to display * @return The distance to advance the pen position after Rendering */ FTPoint Render(const unsigned int characterCode, const unsigned int nextCharacterCode, FTPoint penPosition, int renderMode); /** * Queries the Font for errors. * * @return The current error code. */ FT_Error Error() const { return err; } private: /** * The FTGL face */ FTFace* face; /** * The Character Map object associated with the current face */ FTCharmap* charMap; /** * A structure to hold the glyphs */ GlyphVector glyphs; /** * Current error code. Zero means no error. */ FT_Error err; }; #endif // __FTGlyphContainer__ connectome-workbench-1.4.2/src/FtglFont/FTInternals.h000066400000000000000000000066101360521144700225120ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTINTERNALS_H__ #define __FTINTERNALS_H__ #include "FTGL/ftgl.h" #include #include // Fixes for deprecated identifiers in 2.1.5 #ifndef FT_OPEN_MEMORY #define FT_OPEN_MEMORY (FT_Open_Flags)1 #endif #ifndef FT_RENDER_MODE_MONO #define FT_RENDER_MODE_MONO ft_render_mode_mono #endif #ifndef FT_RENDER_MODE_NORMAL #define FT_RENDER_MODE_NORMAL ft_render_mode_normal #endif #ifdef WIN32 // Under windows avoid including is overrated. // Sure, it can be avoided and "name space pollution" can be // avoided, but why? It really doesn't make that much difference // these days. #define WIN32_LEAN_AND_MEAN #include #ifndef __gl_h_ #include #include #endif #else // Non windows platforms - don't require nonsense as seen above :-) #ifndef __gl_h_ #ifdef SDL_main #include "SDL_opengl.h" #elif __APPLE_CC__ #include #include #else #include #if defined (__sun__) && !defined (__sparc__) #include #else #include #endif #endif #endif // Required for compatibility with glext.h style function definitions of // OpenGL extensions, such as in src/osg/Point.cpp. #ifndef APIENTRY #define APIENTRY #endif #endif FTGL_BEGIN_C_DECLS typedef enum { GLYPH_CUSTOM, GLYPH_BITMAP, GLYPH_BUFFER, GLYPH_PIXMAP, GLYPH_OUTLINE, GLYPH_POLYGON, GLYPH_EXTRUDE, GLYPH_TEXTURE, } GlyphType; struct _FTGLglyph { FTGlyph *ptr; FTGL::GlyphType type; }; typedef enum { FONT_CUSTOM, FONT_BITMAP, FONT_BUFFER, FONT_PIXMAP, FONT_OUTLINE, FONT_POLYGON, FONT_EXTRUDE, FONT_TEXTURE, } FontType; struct _FTGLfont { FTFont *ptr; FTGL::FontType type; }; typedef enum { LAYOUT_SIMPLE, } LayoutType; struct _FTGLlayout { FTLayout *ptr; FTGLfont *font; FTGL::LayoutType type; }; FTGL_END_C_DECLS #endif //__FTINTERNALS_H__ connectome-workbench-1.4.2/src/FtglFont/FTLayout/000077500000000000000000000000001360521144700216545ustar00rootroot00000000000000connectome-workbench-1.4.2/src/FtglFont/FTLayout/FTLayout.cpp000066400000000000000000000032611360521144700240710ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTGL/ftgl.h" #include "../FTFont/FTFontImpl.h" #include "./FTLayoutImpl.h" // // FTLayout // FTLayout::FTLayout() { impl = new FTLayoutImpl(); } FTLayout::FTLayout(FTLayoutImpl *pImpl) { impl = pImpl; } FTLayout::~FTLayout() { delete impl; } FT_Error FTLayout::Error() const { return impl->err; } // // FTLayoutImpl // FTLayoutImpl::FTLayoutImpl() : err(0) { ; } FTLayoutImpl::~FTLayoutImpl() { ; } connectome-workbench-1.4.2/src/FtglFont/FTLayout/FTLayoutGlue.cpp000066400000000000000000000125551360521144700247140ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTInternals.h" static const FTBBox static_ftbbox; FTGL_BEGIN_C_DECLS #define C_TOR(cname, cargs, cxxname, cxxarg, cxxtype) \ FTGLlayout* cname cargs \ { \ cxxname *l = new cxxname cxxarg; \ if(l->Error()) \ { \ delete l; \ return NULL; \ } \ FTGLlayout *ftgl = (FTGLlayout *)malloc(sizeof(FTGLlayout)); \ ftgl->ptr = l; \ ftgl->type = cxxtype; \ return ftgl; \ } // FTSimpleLayout::FTSimpleLayout(); C_TOR(ftglCreateSimpleLayout, (), FTSimpleLayout, (), LAYOUT_SIMPLE); #define C_FUN(cret, cname, cargs, cxxerr, cxxname, cxxarg) \ cret cname cargs \ { \ if(!l || !l->ptr) \ { \ fprintf(stderr, "FTGL warning: NULL pointer in %s\n", #cname); \ cxxerr; \ } \ return l->ptr->cxxname cxxarg; \ } // FTLayout::~FTLayout(); void ftglDestroyLayout(FTGLlayout *l) { if(!l || !l->ptr) { fprintf(stderr, "FTGL warning: NULL pointer in %s\n", __FUNCTION__); return; } delete l->ptr; free(l); } // virtual FTBBox FTLayout::BBox(const char* string) extern "C++" { C_FUN(static FTBBox, _ftgGetlLayoutBBox, (FTGLlayout *l, const char *s), return static_ftbbox, BBox, (s)); } void ftgGetlLayoutBBox(FTGLlayout *l, const char * s, float c[6]) { FTBBox ret = _ftgGetlLayoutBBox(l, s); FTPoint lower = ret.Lower(), upper = ret.Upper(); c[0] = lower.Xf(); c[1] = lower.Yf(); c[2] = lower.Zf(); c[3] = upper.Xf(); c[4] = upper.Yf(); c[5] = upper.Zf(); } // virtual void FTLayout::Render(const char* string, int renderMode); C_FUN(void, ftglRenderLayout, (FTGLlayout *l, const char *s, int r), return, Render, (s, r)); // FT_Error FTLayout::Error() const; C_FUN(FT_Error, ftglGetLayoutError, (FTGLlayout *l), return -1, Error, ()); // void FTSimpleLayout::SetFont(FTFont *fontInit) void ftglSetLayoutFont(FTGLlayout *l, FTGLfont *font) { if(!l || !l->ptr) { fprintf(stderr, "FTGL warning: NULL pointer in %s\n", __FUNCTION__); return; } if(l->type != FTGL::LAYOUT_SIMPLE) { fprintf(stderr, "FTGL warning: %s not implemented for %d\n", __FUNCTION__, l->type); } l->font = font; return dynamic_cast(l->ptr)->SetFont(font->ptr); } // FTFont *FTSimpleLayout::GetFont() FTGLfont *ftglGetLayoutFont(FTGLlayout *l) { if(!l || !l->ptr) { fprintf(stderr, "FTGL warning: NULL pointer in %s\n", __FUNCTION__); return NULL; } if(l->type != FTGL::LAYOUT_SIMPLE) { fprintf(stderr, "FTGL warning: %s not implemented for %d\n", __FUNCTION__, l->type); } return l->font; } #undef C_FUN #define C_FUN(cret, cname, cargs, cxxerr, cxxname, cxxarg) \ cret cname cargs \ { \ if(!l || !l->ptr) \ { \ fprintf(stderr, "FTGL warning: NULL pointer in %s\n", #cname); \ cxxerr; \ } \ if(l->type != FTGL::LAYOUT_SIMPLE) \ { \ fprintf(stderr, "FTGL warning: %s not implemented for %d\n", \ __FUNCTION__, l->type); \ cxxerr; \ } \ return dynamic_cast(l->ptr)->cxxname cxxarg; \ } // void FTSimpleLayout::SetLineLength(const float LineLength); C_FUN(void, ftglSetLayoutLineLength, (FTGLlayout *l, const float length), return, SetLineLength, (length)); // float FTSimpleLayout::GetLineLength() const C_FUN(float, ftglGetLayoutLineLength, (FTGLlayout *l), return 0.0f, GetLineLength, ()); // void FTSimpleLayout::SetAlignment(const TextAlignment Alignment) C_FUN(void, ftglSetLayoutAlignment, (FTGLlayout *l, const int a), return, SetAlignment, ((FTGL::TextAlignment)a)); // TextAlignment FTSimpleLayout::GetAlignment() const C_FUN(int, ftglGetLayoutAlignement, (FTGLlayout *l), return FTGL::ALIGN_LEFT, GetAlignment, ()); // void FTSimpleLayout::SetLineSpacing(const float LineSpacing) C_FUN(void, ftglSetLayoutLineSpacing, (FTGLlayout *l, const float f), return, SetLineSpacing, (f)); FTGL_END_C_DECLS connectome-workbench-1.4.2/src/FtglFont/FTLayout/FTLayoutImpl.h000066400000000000000000000032411360521144700243560ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTLayoutImpl__ #define __FTLayoutImpl__ #include "FTSize.h" #include "FTGlyphContainer.h" class FTLayoutImpl { friend class FTLayout; protected: FTLayoutImpl(); virtual ~FTLayoutImpl(); protected: /** * Current pen or cursor position; */ FTPoint pen; /** * Current error code. Zero means no error. */ FT_Error err; }; #endif // __FTLayoutImpl__ connectome-workbench-1.4.2/src/FtglFont/FTLayout/FTSimpleLayout.cpp000066400000000000000000000342271360521144700252510ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2014 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include #include #include "FTInternals.h" #include "FTUnicode.h" #include "FTGlyphContainer.h" #include "FTSimpleLayoutImpl.h" // // FTSimpleLayout // FTSimpleLayout::FTSimpleLayout() : FTLayout(new FTSimpleLayoutImpl()) {} FTSimpleLayout::~FTSimpleLayout() {} FTBBox FTSimpleLayout::BBox(const char *string, const int len, FTPoint pos) { return dynamic_cast(impl)->BBox(string, len, pos); } FTBBox FTSimpleLayout::BBox(const wchar_t *string, const int len, FTPoint pos) { return dynamic_cast(impl)->BBox(string, len, pos); } void FTSimpleLayout::Render(const char *string, const int len, FTPoint pos, int renderMode) { return dynamic_cast(impl)->Render(string, len, pos, renderMode); } void FTSimpleLayout::Render(const wchar_t* string, const int len, FTPoint pos, int renderMode) { return dynamic_cast(impl)->Render(string, len, pos, renderMode); } void FTSimpleLayout::SetFont(FTFont *fontInit) { dynamic_cast(impl)->currentFont = fontInit; } FTFont *FTSimpleLayout::GetFont() { return dynamic_cast(impl)->currentFont; } void FTSimpleLayout::SetLineLength(const float LineLength) { dynamic_cast(impl)->lineLength = LineLength; } float FTSimpleLayout::GetLineLength() const { return dynamic_cast(impl)->lineLength; } void FTSimpleLayout::SetAlignment(const FTGL::TextAlignment Alignment) { dynamic_cast(impl)->alignment = Alignment; } FTGL::TextAlignment FTSimpleLayout::GetAlignment() const { return dynamic_cast(impl)->alignment; } void FTSimpleLayout::SetLineSpacing(const float LineSpacing) { dynamic_cast(impl)->lineSpacing = LineSpacing; } float FTSimpleLayout::GetLineSpacing() const { return dynamic_cast(impl)->lineSpacing; } // // FTSimpleLayoutImpl // FTSimpleLayoutImpl::FTSimpleLayoutImpl() { currentFont = NULL; lineLength = 100.0f; alignment = FTGL::ALIGN_LEFT; lineSpacing = 1.0f; } template inline FTBBox FTSimpleLayoutImpl::BBoxI(const T* string, const int len, FTPoint position) { FTBBox tmp; WrapText(string, len, position, 0, &tmp); return tmp; } FTBBox FTSimpleLayoutImpl::BBox(const char *string, const int len, FTPoint position) { return BBoxI(string, len, position); } FTBBox FTSimpleLayoutImpl::BBox(const wchar_t *string, const int len, FTPoint position) { return BBoxI(string, len, position); } template inline void FTSimpleLayoutImpl::RenderI(const T *string, const int len, FTPoint position, int renderMode) { pen = FTPoint(0.0f, 0.0f); WrapText(string, len, position, renderMode, NULL); } void FTSimpleLayoutImpl::Render(const char *string, const int len, FTPoint position, int renderMode) { RenderI(string, len, position, renderMode); } void FTSimpleLayoutImpl::Render(const wchar_t* string, const int len, FTPoint position, int renderMode) { RenderI(string, len, position, renderMode); } template inline void FTSimpleLayoutImpl::WrapTextI(const T *buf, const int /*len*/, FTPoint position, int renderMode, FTBBox *bounds) { FTUnicodeStringItr breakItr(buf); // points to the last break character FTUnicodeStringItr lineStart(buf); // points to the line start float nextStart = 0.0; // total width of the current line float breakWidth = 0.0; // width of the line up to the last word break float currentWidth = 0.0; // width of all characters on the current line float prevWidth; // width of all characters but the current glyph float wordLength = 0.0; // length of the block since the last break char int charCount = 0; // number of characters so far on the line int breakCharCount = 0; // number of characters before the breakItr float glyphWidth, advance; FTBBox glyphBounds; // Reset the pen position pen.Y(0); // If we have bounds mark them invalid if(bounds) { bounds->Invalidate(); } // Scan the input for all characters that need output FTUnicodeStringItr prevItr(buf); for (FTUnicodeStringItr itr(buf); *itr; prevItr = itr++, charCount++) { // Find the width of the current glyph glyphBounds = currentFont->BBox(itr.getBufferFromHere(), 1); glyphWidth = glyphBounds.Upper().Xf() - glyphBounds.Lower().Xf(); advance = currentFont->Advance(itr.getBufferFromHere(), 1); prevWidth = currentWidth; // Compute the width of all glyphs up to the end of buf[i] currentWidth = nextStart + glyphWidth; // Compute the position of the next glyph nextStart += advance; // See if the current character is a space, a break or a regular character if((currentWidth > lineLength) || (*itr == '\n')) { // A non whitespace character has exceeded the line length. Or a // newline character has forced a line break. Output the last // line and start a new line after the break character. // If we have not yet found a break, break on the last character if(breakItr == lineStart || (*itr == '\n')) { // Break on the previous character breakItr = prevItr; breakCharCount = charCount - 1; breakWidth = prevWidth; // None of the previous words will be carried to the next line wordLength = 0; // If the current character is a newline discard its advance if(*itr == '\n') advance = 0; } float remainingWidth = lineLength - breakWidth; // Render the current substring FTUnicodeStringItr breakChar = breakItr; // move past the break character and don't count it on the next line either ++breakChar; --charCount; // If the break character is a newline do not render it if(*breakChar == '\n') { ++breakChar; --charCount; } OutputWrapped(lineStart.getBufferFromHere(), breakCharCount, //breakItr.getBufferFromHere() - lineStart.getBufferFromHere(), position, renderMode, remainingWidth, bounds); // Store the start of the next line lineStart = breakChar; // TODO: Is Height() the right value here? pen -= FTPoint(0, currentFont->LineHeight() * lineSpacing); // The current width is the width since the last break nextStart = wordLength + advance; wordLength += advance; currentWidth = wordLength + advance; // Reset the safe break for the next line breakItr = lineStart; charCount -= breakCharCount; } else if(iswspace(*itr)) { // This is the last word break position wordLength = 0; breakItr = itr; breakCharCount = charCount; // Check to see if this is the first whitespace character in a run if(buf == itr.getBufferFromHere() || !iswspace(*prevItr)) { // Record the width of the start of the block breakWidth = currentWidth; } } else { wordLength += advance; } } float remainingWidth = lineLength - currentWidth; // Render any remaining text on the last line // Disable justification for the last row if(alignment == FTGL::ALIGN_JUSTIFY) { alignment = FTGL::ALIGN_LEFT; OutputWrapped(lineStart.getBufferFromHere(), -1, position, renderMode, remainingWidth, bounds); alignment = FTGL::ALIGN_JUSTIFY; } else { OutputWrapped(lineStart.getBufferFromHere(), -1, position, renderMode, remainingWidth, bounds); } } void FTSimpleLayoutImpl::WrapText(const char *buf, const int len, FTPoint position, int renderMode, FTBBox *bounds) { WrapTextI(buf, len, position, renderMode, bounds); } void FTSimpleLayoutImpl::WrapText(const wchar_t* buf, const int len, FTPoint position, int renderMode, FTBBox *bounds) { WrapTextI(buf, len, position, renderMode, bounds); } template inline void FTSimpleLayoutImpl::OutputWrappedI(const T *buf, const int len, FTPoint position, int renderMode, const float remaining, FTBBox *bounds) { float distributeWidth = 0.0; // Align the text according as specified by Alignment switch (alignment) { case FTGL::ALIGN_LEFT: pen.X(0); break; case FTGL::ALIGN_CENTER: pen.X(remaining / 2); break; case FTGL::ALIGN_RIGHT: pen.X(remaining); break; case FTGL::ALIGN_JUSTIFY: pen.X(0); distributeWidth = remaining; break; } // If we have bounds expand them by the line's bounds, otherwise render // the line. if(bounds) { FTBBox temp = currentFont->BBox(buf, len); // Add the extra space to the upper x dimension temp = FTBBox(temp.Lower() + pen, temp.Upper() + pen + FTPoint(distributeWidth, 0)); // See if this is the first area to be added to the bounds if(bounds->IsValid()) { *bounds |= temp; } else { *bounds = temp; } } else { RenderSpace(buf, len, position, renderMode, distributeWidth); } } void FTSimpleLayoutImpl::OutputWrapped(const char *buf, const int len, FTPoint position, int renderMode, const float remaining, FTBBox *bounds) { OutputWrappedI(buf, len, position, renderMode, remaining, bounds); } void FTSimpleLayoutImpl::OutputWrapped(const wchar_t *buf, const int len, FTPoint position, int renderMode, const float remaining, FTBBox *bounds) { OutputWrappedI(buf, len, position, renderMode, remaining, bounds); } template inline void FTSimpleLayoutImpl::RenderSpaceI(const T *string, const int len, FTPoint /*position*/, int renderMode, const float extraSpace) { float space = 0.0; // If there is space to distribute, count the number of spaces if(extraSpace > 0.0) { int numSpaces = 0; // Count the number of space blocks in the input FTUnicodeStringItr prevItr(string), itr(string); for(int i = 0; ((len < 0) && *itr) || ((len >= 0) && (i <= len)); ++i, prevItr = itr++) { // If this is the end of a space block, increment the counter if((i > 0) && !iswspace(*itr) && iswspace(*prevItr)) { numSpaces++; } } space = extraSpace/numSpaces; } // Output all characters of the string FTUnicodeStringItr prevItr(string), itr(string); for(int i = 0; ((len < 0) && *itr) || ((len >= 0) && (i <= len)); ++i, prevItr = itr++) { // If this is the end of a space block, distribute the extra space // inside it if((i > 0) && !iswspace(*itr) && iswspace(*prevItr)) { pen += FTPoint(space, 0); } pen = currentFont->Render(itr.getBufferFromHere(), 1, pen, FTPoint(), renderMode); } } void FTSimpleLayoutImpl::RenderSpace(const char *string, const int len, FTPoint position, int renderMode, const float extraSpace) { RenderSpaceI(string, len, position, renderMode, extraSpace); } void FTSimpleLayoutImpl::RenderSpace(const wchar_t *string, const int len, FTPoint position, int renderMode, const float extraSpace) { RenderSpaceI(string, len, position, renderMode, extraSpace); } connectome-workbench-1.4.2/src/FtglFont/FTLayout/FTSimpleLayoutImpl.h000066400000000000000000000231131360521144700255300ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTSimpleLayoutImpl__ #define __FTSimpleLayoutImpl__ #include "FTLayoutImpl.h" class FTFont; class FTSimpleLayoutImpl : public FTLayoutImpl { friend class FTSimpleLayout; protected: FTSimpleLayoutImpl(); virtual ~FTSimpleLayoutImpl() {}; virtual FTBBox BBox(const char* string, const int len, FTPoint position); virtual FTBBox BBox(const wchar_t* string, const int len, FTPoint position); virtual void Render(const char *string, const int len, FTPoint position, int renderMode); virtual void Render(const wchar_t *string, const int len, FTPoint position, int renderMode); /** * Render a string of characters and distribute extra space amongst * the whitespace regions of the string. * * @param string A buffer of wchar_t characters to output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered. * @param position TODO * @param renderMode Render mode to display * @param extraSpace The amount of extra space to distribute amongst * the characters. */ virtual void RenderSpace(const char *string, const int len, FTPoint position, int renderMode, const float extraSpace); /** * Render a string of characters and distribute extra space amongst * the whitespace regions of the string. * * @param string A buffer of wchar_t characters to output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered. * @param position TODO * @param renderMode Render mode to display * @param extraSpace The amount of extra space to distribute amongst * the characters. */ virtual void RenderSpace(const wchar_t *string, const int len, FTPoint position, int renderMode, const float extraSpace); private: /** * Either render a string of characters and wrap lines * longer than a threshold or compute the bounds * of a string of characters when wrapped. The functionality * of this method is exposed by the BBoxWrapped and * RenderWrapped methods. * * @param buf A char string to output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered. * @param position TODO * @param renderMode Render mode to display * @param bounds A pointer to a bounds object. If non null * the bounds of the text when laid out * will be stored in bounds. If null the * text will be rendered. */ virtual void WrapText(const char *buf, const int len, FTPoint position, int renderMode, FTBBox *bounds); /** * Either render a string of characters and wrap lines * longer than a threshold or compute the bounds * of a string of characters when wrapped. The functionality * of this method is exposed by the BBoxWrapped and * RenderWrapped methods. * * @param buf A wchar_t style string to output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered. * @param position TODO * @param renderMode Render mode to display * @param bounds A pointer to a bounds object. If non null * the bounds of the text when laid out * will be stored in bounds. If null the * text will be rendered. */ virtual void WrapText(const wchar_t *buf, const int len, FTPoint position, int renderMode, FTBBox *bounds); /** * A helper method used by WrapText to either output the text or * compute it's bounds. * * @param buf A pointer to an array of character data. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered. * @param position TODO * @param renderMode Render mode to display * @param RemainingWidth The amount of extra space left on the line. * @param bounds A pointer to a bounds object. If non null the * bounds will be initialized or expanded by the * bounds of the line. If null the text will be * rendered. If the bounds are invalid (lower > upper) * they will be initialized. Otherwise they * will be expanded. */ void OutputWrapped(const char *buf, const int len, FTPoint position, int renderMode, const float RemainingWidth, FTBBox *bounds); /** * A helper method used by WrapText to either output the text or * compute it's bounds. * * @param buf A pointer to an array of character data. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered. * @param position TODO * @param renderMode Render mode to display * @param RemainingWidth The amount of extra space left on the line. * @param bounds A pointer to a bounds object. If non null the * bounds will be initialized or expanded by the * bounds of the line. If null the text will be * rendered. If the bounds are invalid (lower > upper) * they will be initialized. Otherwise they * will be expanded. */ void OutputWrapped(const wchar_t *buf, const int len, FTPoint position, int renderMode, const float RemainingWidth, FTBBox *bounds); /** * The font to use for rendering the text. The font is * referenced by this but will not be disposed of when this * is deleted. */ FTFont *currentFont; /** * The maximum line length for formatting text. */ float lineLength; /** * The text alignment mode used to distribute * space within a line or rendered text. */ FTGL::TextAlignment alignment; /** * The height of each line of text expressed as * a percentage of the font's line height. */ float lineSpacing; /* Internal generic BBox() implementation */ template inline FTBBox BBoxI(const T* string, const int len, FTPoint position); /* Internal generic Render() implementation */ template inline void RenderI(const T* string, const int len, FTPoint position, int renderMode); /* Internal generic RenderSpace() implementation */ template inline void RenderSpaceI(const T* string, const int len, FTPoint position, int renderMode, const float extraSpace); /* Internal generic WrapText() implementation */ template void WrapTextI(const T* buf, const int len, FTPoint position, int renderMode, FTBBox *bounds); /* Internal generic OutputWrapped() implementation */ template void OutputWrappedI(const T* buf, const int len, FTPoint position, int renderMode, const float RemainingWidth, FTBBox *bounds); }; #endif // __FTSimpleLayoutImpl__ connectome-workbench-1.4.2/src/FtglFont/FTLibrary.cpp000066400000000000000000000040501360521144700225060ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTLibrary.h" const FTLibrary& FTLibrary::Instance() { static FTLibrary ftlib; return ftlib; } FTLibrary::~FTLibrary() { if(library != 0) { FT_Done_FreeType(*library); delete library; library= 0; } // if(manager != 0) // { // FTC_Manager_Done(manager); // // delete manager; // manager= 0; // } } FTLibrary::FTLibrary() : library(0), err(0) { Initialise(); } bool FTLibrary::Initialise() { if(library != 0) return true; library = new FT_Library; err = FT_Init_FreeType(library); if(err) { delete library; library = 0; return false; } // FTC_Manager* manager; // // if(FTC_Manager_New(lib, 0, 0, 0, my_face_requester, 0, manager) // { // delete manager; // manager= 0; // return false; // } return true; } connectome-workbench-1.4.2/src/FtglFont/FTLibrary.h000066400000000000000000000076041360521144700221630ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2014 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTLibrary__ #define __FTLibrary__ #include #include FT_FREETYPE_H //#include FT_CACHE_H #include "FTGL/ftgl.h" /** * FTLibrary class is the global accessor for the Freetype library. * * This class encapsulates the Freetype Library. This is a singleton class * and ensures that only one FT_Library is in existence at any one time. * All constructors are private therefore clients cannot create or * instantiate this class themselves and must access it's methods via the * static FTLibrary::Instance() function. * * Just because this class returns a valid FTLibrary object * doesn't mean that the Freetype Library has been successfully initialised. * Clients should check for errors. You can initialse the library AND check * for errors using the following code... * err = FTLibrary::Instance().Error(); * * @see "Freetype 2 Documentation" * */ class FTLibrary { public: /** * Global acces point to the single FTLibrary object. * * @return The global FTLibrary object. */ static const FTLibrary& Instance(); /** * Gets a pointer to the native Freetype library. * * @return A handle to a FreeType library instance. */ const FT_Library* /*const*/ GetLibrary() const { return library; } /** * Queries the library for errors. * * @return The current error code. */ FT_Error Error() const { return err; } /** * Destructor * * Disposes of the Freetype library */ ~FTLibrary(); private: /** * Default constructors. * * Made private to stop clients creating there own FTLibrary * objects. */ FTLibrary(); FTLibrary(const FT_Library&){} FTLibrary& operator=(const FT_Library&) { return *this; } /** * Initialises the Freetype library * * Even though this function indicates success via the return value, * clients can't see this so must check the error codes. This function * is only ever called by the default c_stor * * @return true if the Freetype library was * successfully initialised, false * otherwise. */ bool Initialise(); /** * Freetype library handle. */ FT_Library* library; // FTC_Manager* manager; /** * Current error code. Zero means no error. */ FT_Error err; }; #endif // __FTLibrary__ connectome-workbench-1.4.2/src/FtglFont/FTList.h000066400000000000000000000063021360521144700214640ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTList__ #define __FTList__ #include "FTGL/ftgl.h" /** * Provides a non-STL alternative to the STL list */ template class FTList { public: typedef FT_LIST_ITEM_TYPE value_type; typedef value_type& reference; typedef const value_type& const_reference; typedef size_t size_type; /** * Constructor */ FTList() : listSize(0), tail(0) { tail = NULL; head = new Node; } /** * Destructor */ ~FTList() { Node* next; for(Node *walk = head; walk; walk = next) { next = walk->next; delete walk; } } /** * Get the number of items in the list */ size_type size() const { return listSize; } /** * Add an item to the end of the list */ void push_back(const value_type& item) { Node* node = new Node(item); if(head->next == NULL) { head->next = node; } if(tail) { tail->next = node; } tail = node; ++listSize; } /** * Get the item at the front of the list */ reference front() const { return head->next->payload; } /** * Get the item at the end of the list */ reference back() const { return tail->payload; } private: struct Node { Node() : next(NULL) {} Node(const value_type& item) : next(NULL) { payload = item; } Node* next; value_type payload; }; size_type listSize; Node* head; Node* tail; }; #endif // __FTList__ connectome-workbench-1.4.2/src/FtglFont/FTPoint.cpp000066400000000000000000000036361360521144700222040ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include #include "FTGL/ftgl.h" bool operator == (const FTPoint &a, const FTPoint &b) { return((a.values[0] == b.values[0]) && (a.values[1] == b.values[1]) && (a.values[2] == b.values[2])); } bool operator != (const FTPoint &a, const FTPoint &b) { return((a.values[0] != b.values[0]) || (a.values[1] != b.values[1]) || (a.values[2] != b.values[2])); } FTPoint FTPoint::Normalise() { double norm = sqrt(values[0] * values[0] + values[1] * values[1] + values[2] * values[2]); if(norm == 0.0) { return *this; } FTPoint temp(values[0] / norm, values[1] / norm, values[2] / norm); return temp; } connectome-workbench-1.4.2/src/FtglFont/FTSize.cpp000066400000000000000000000056131360521144700220220ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTSize.h" FTSize::FTSize() : ftFace(0), ftSize(0), size(0), xResolution(0), yResolution(0), err(0) {} FTSize::~FTSize() {} bool FTSize::CharSize(FT_Face* face, unsigned int pointSize, unsigned int xRes, unsigned int yRes) { if(size != pointSize || xResolution != xRes || yResolution != yRes) { err = FT_Set_Char_Size(*face, 0L, pointSize * 64, xResolution, yResolution); if(!err) { ftFace = face; size = pointSize; xResolution = xRes; yResolution = yRes; ftSize = (*ftFace)->size; } } return !err; } unsigned int FTSize::CharSize() const { return size; } float FTSize::Ascender() const { return ftSize == 0 ? 0.0f : static_cast(ftSize->metrics.ascender) / 64.0f; } float FTSize::Descender() const { return ftSize == 0 ? 0.0f : static_cast(ftSize->metrics.descender) / 64.0f; } float FTSize::Height() const { if(0 == ftSize) { return 0.0f; } if(FT_IS_SCALABLE((*ftFace))) { return ((*ftFace)->bbox.yMax - (*ftFace)->bbox.yMin) * ((float)ftSize->metrics.y_ppem / (float)(*ftFace)->units_per_EM); } else { return static_cast(ftSize->metrics.height) / 64.0f; } } float FTSize::Width() const { if(0 == ftSize) { return 0.0f; } if(FT_IS_SCALABLE((*ftFace))) { return ((*ftFace)->bbox.xMax - (*ftFace)->bbox.xMin) * (static_cast(ftSize->metrics.x_ppem) / static_cast((*ftFace)->units_per_EM)); } else { return static_cast(ftSize->metrics.max_advance) / 64.0f; } } float FTSize::Underline() const { return 0.0f; } connectome-workbench-1.4.2/src/FtglFont/FTSize.h000066400000000000000000000112671360521144700214710ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTSize__ #define __FTSize__ #include #include FT_FREETYPE_H #include "FTGL/ftgl.h" /** * FTSize class provides an abstraction layer for the Freetype Size. * * @see "Freetype 2 Documentation" * */ class FTSize { public: /** * Default Constructor */ FTSize(); /** * Destructor */ virtual ~FTSize(); /** * Sets the char size for the current face. * * This doesn't guarantee that the size was set correctly. Clients * should check errors. If an error does occur the size object isn't modified. * * @param face Parent face for this size object * @param point_size the face size in points (1/72 inch) * @param x_resolution the horizontal resolution of the target device. * @param y_resolution the vertical resolution of the target device. * @return true if the size has been set. Clients should check Error() for more information if this function returns false() */ bool CharSize(FT_Face* face, unsigned int point_size, unsigned int x_resolution, unsigned int y_resolution); /** * get the char size for the current face. * * @return The char size in points */ unsigned int CharSize() const; /** * Gets the global ascender height for the face in pixels. * * @return Ascender height */ float Ascender() const; /** * Gets the global descender height for the face in pixels. * * @return Ascender height */ float Descender() const; /** * Gets the global face height for the face. * * If the face is scalable this returns the height of the global * bounding box which ensures that any glyph will be less than or * equal to this height. If the font isn't scalable there is no * guarantee that glyphs will not be taller than this value. * * @return height in pixels. */ float Height() const; /** * Gets the global face width for the face. * * If the face is scalable this returns the width of the global * bounding box which ensures that any glyph will be less than or * equal to this width. If the font isn't scalable this value is * the max_advance for the face. * * @return width in pixels. */ float Width() const; /** * Gets the underline position for the face. * * @return underline position in pixels */ float Underline() const; /** * Queries for errors. * * @return The current error code. */ FT_Error Error() const { return err; } private: /** * The current Freetype face that this FTSize object relates to. */ FT_Face* ftFace; /** * The Freetype size. */ FT_Size ftSize; /** * The size in points. */ unsigned int size; /** * The horizontal resolution. */ unsigned int xResolution; /** * The vertical resolution. */ unsigned int yResolution; /** * Current error code. Zero means no error. */ FT_Error err; }; #endif // __FTSize__ connectome-workbench-1.4.2/src/FtglFont/FTUnicode.h000066400000000000000000000177341360521144700221520ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2008 Daniel Remenak * * Portions derived from ConvertUTF.c Copyright (C) 2001-2004 Unicode, Inc * Unicode, Inc. hereby grants the right to freely use the information * supplied in this file in the creation of products supporting the * Unicode Standard, and to make copies of this file in any form * for internal or external distribution as long as this notice * remains attached. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTUnicode__ #define __FTUnicode__ /** * Provides a way to easily walk multibyte unicode strings in the various * Unicode encodings (UTF-8, UTF-16, UTF-32, UCS-2, and UCS-4). Encodings * with elements larger than one byte must already be in the correct endian * order for the current architecture. */ template class FTUnicodeStringItr { public: /** * Constructor. Also reads the first character and stores it. * * @param string The buffer to iterate. No copy is made. */ FTUnicodeStringItr(const T* string) : curPos(string), nextPos(string) { (*this)++; }; /** * Pre-increment operator. Reads the next unicode character and sets * the state appropriately. * Note - not protected against overruns. */ FTUnicodeStringItr& operator++() { curPos = nextPos; // unicode handling switch (sizeof(T)) { case 1: // UTF-8 // get this character readUTF8(); break; case 2: // UTF-16 readUTF16(); break; case 4: // UTF-32 // fall through default: // error condition really, but give it a shot anyway curChar = *nextPos++; } return *this; } /** * Post-increment operator. Reads the next character and sets * the state appropriately. * Note - not protected against overruns. */ FTUnicodeStringItr operator++(int) { FTUnicodeStringItr temp = *this; ++*this; return temp; } /** * Equality operator. Two FTUnicodeStringItrs are considered equal * if they have the same current buffer and buffer position. */ bool operator==(const FTUnicodeStringItr& right) const { if (curPos == right.getBufferFromHere()) return true; return false; } /** * Dereference operator. * * @return The unicode codepoint of the character currently pointed * to by the FTUnicodeStringItr. */ unsigned int operator*() const { return curChar; } /** * Buffer-fetching getter. You can use this to retreive the buffer * starting at the currently-iterated character for functions which * require a Unicode string as input. */ const T* getBufferFromHere() const { return curPos; } private: /** * Helper function for reading a single UTF8 character from the string. * Updates internal state appropriately. */ void readUTF8(); /** * Helper function for reading a single UTF16 character from the string. * Updates internal state appropriately. */ void readUTF16(); /** * The buffer position of the first element in the current character. */ const T* curPos; /** * The character stored at the current buffer position (prefetched on * increment, so there's no penalty for dereferencing more than once). */ unsigned int curChar; /** * The buffer position of the first element in the next character. */ const T* nextPos; // unicode magic numbers static const char utf8bytes[256]; static const unsigned long offsetsFromUTF8[6]; static const unsigned long highSurrogateStart; static const unsigned long highSurrogateEnd; static const unsigned long lowSurrogateStart; static const unsigned long lowSurrogateEnd; static const unsigned long highSurrogateShift; static const unsigned long lowSurrogateBase; }; /* The first character in a UTF8 sequence indicates how many bytes * to read (among other things) */ template const char FTUnicodeStringItr::utf8bytes[256] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,5,5,5,5,6,6,6,6 }; /* Magic values subtracted from a buffer value during UTF8 conversion. * This table contains as many values as there might be trailing bytes * in a UTF-8 sequence. */ template const unsigned long FTUnicodeStringItr::offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; // get a UTF8 character; leave the tracking pointer at the start of the // next character // not protected against invalid UTF8 template inline void FTUnicodeStringItr::readUTF8() { unsigned int ch = 0; unsigned int extraBytesToRead = utf8bytes[(unsigned char)(*nextPos)]; // falls through switch (extraBytesToRead) { case 6: ch += *nextPos++; ch <<= 6; /* remember, illegal UTF-8 */ case 5: ch += *nextPos++; ch <<= 6; /* remember, illegal UTF-8 */ case 4: ch += *nextPos++; ch <<= 6; case 3: ch += *nextPos++; ch <<= 6; case 2: ch += *nextPos++; ch <<= 6; case 1: ch += *nextPos++; } ch -= offsetsFromUTF8[extraBytesToRead-1]; curChar = ch; } // Magic numbers for UTF-16 conversions template const unsigned long FTUnicodeStringItr::highSurrogateStart = 0xD800; template const unsigned long FTUnicodeStringItr::highSurrogateEnd = 0xDBFF; template const unsigned long FTUnicodeStringItr::lowSurrogateStart = 0xDC00; template const unsigned long FTUnicodeStringItr::lowSurrogateEnd = 0xDFFF; template const unsigned long FTUnicodeStringItr::highSurrogateShift = 10; template const unsigned long FTUnicodeStringItr::lowSurrogateBase = 0x0010000UL; template inline void FTUnicodeStringItr::readUTF16() { unsigned int ch = *nextPos++; // if we have the first half of the surrogate pair if (ch >= highSurrogateStart && ch <= highSurrogateEnd) { unsigned int ch2 = *curPos; // complete the surrogate pair if (ch2 >= lowSurrogateStart && ch2 <= lowSurrogateEnd) { ch = ((ch - highSurrogateStart) << highSurrogateShift) + (ch2 - lowSurrogateStart) + lowSurrogateBase; ++nextPos; } } curChar = ch; } #endif connectome-workbench-1.4.2/src/FtglFont/FTVector.h000066400000000000000000000116371360521144700220220ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTVector__ #define __FTVector__ #include "FTGL/ftgl.h" /** * Provides a non-STL alternative to the STL vector */ template class FTVector { public: typedef FT_VECTOR_ITEM_TYPE value_type; typedef value_type& reference; typedef const value_type& const_reference; typedef value_type* iterator; typedef const value_type* const_iterator; typedef size_t size_type; FTVector() { Capacity = Size = 0; Items = 0; } virtual ~FTVector() { clear(); } FTVector& operator =(const FTVector& v) { reserve(v.capacity()); iterator ptr = begin(); const_iterator vbegin = v.begin(); const_iterator vend = v.end(); while(vbegin != vend) { *ptr++ = *vbegin++; } Size = v.size(); return *this; } size_type size() const { return Size; } size_type capacity() const { return Capacity; } iterator begin() { return Items; } const_iterator begin() const { return Items; } iterator end() { return begin() + size(); } const_iterator end() const { return begin() + size(); } bool empty() const { return size() == 0; } reference operator [](size_type pos) { return(*(begin() + pos)); } const_reference operator [](size_type pos) const { return *(begin() + pos); } void clear() { if(Capacity) { delete [] Items; Capacity = Size = 0; Items = 0; } } void reserve(size_type n) { if(capacity() < n) { expand(n); } } void push_back(const value_type& x) { if(size() == capacity()) { expand(); } (*this)[size()] = x; ++Size; } void resize(size_type n, value_type x) { if(n == size()) { return; } reserve(n); iterator ibegin, iend; if(n >= Size) { ibegin = this->end(); iend = this->begin() + n; } else { ibegin = this->begin() + n; iend = this->end(); } while(ibegin != iend) { *ibegin++ = x; } Size = n; } private: void expand(size_type capacity_hint = 0) { size_type new_capacity = (capacity() == 0) ? 256 : capacity() * 2; if(capacity_hint) { while(new_capacity < capacity_hint) { new_capacity *= 2; } } value_type *new_items = new value_type[new_capacity]; iterator ibegin = this->begin(); iterator iend = this->end(); value_type *ptr = new_items; while(ibegin != iend) { *ptr++ = *ibegin++; } if(Capacity) { delete [] Items; } Items = new_items; Capacity = new_capacity; } size_type Capacity; size_type Size; value_type* Items; }; #endif // __FTVector__ connectome-workbench-1.4.2/src/FtglFont/FTVectoriser.cpp000066400000000000000000000216261360521144700232370ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2014 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "FtglConfig.h" #include "FTInternals.h" #include "FTVectoriser.h" #ifndef CALLBACK #define CALLBACK #endif #define GCC_VERSION (__GNUC__ * 10000 \ + __GNUC_MINOR__ * 100 \ + __GNUC_PATCHLEVEL__) /* Test for GCC > 4.9.0 on Apple JWH */ #if defined __APPLE_CC__ && GCC_VERSION > 4900 typedef GLvoid (*GLUTesselatorFunction) (); #elif defined __APPLE_CC__ && __APPLE_CC__ < 5465 typedef GLvoid (*GLUTesselatorFunction) (...); #elif defined WIN32 && !defined __CYGWIN__ typedef GLvoid (CALLBACK *GLUTesselatorFunction) (); #else typedef GLvoid (*GLUTesselatorFunction) (); #endif void CALLBACK ftglError(GLenum errCode, FTMesh* mesh) { mesh->Error(errCode); } void CALLBACK ftglVertex(void* data, FTMesh* mesh) { FTGL_DOUBLE* vertex = static_cast(data); mesh->AddPoint(vertex[0], vertex[1], vertex[2]); } void CALLBACK ftglCombine(FTGL_DOUBLE coords[3], void** /*vertex_data[4]*/, GLfloat* /*weight[4]*/, void** outData, FTMesh* mesh) { const FTGL_DOUBLE* vertex = static_cast(coords); *outData = const_cast(mesh->Combine(vertex[0], vertex[1], vertex[2])); } void CALLBACK ftglBegin(GLenum type, FTMesh* mesh) { mesh->Begin(type); } void CALLBACK ftglEnd(FTMesh* mesh) { mesh->End(); } FTMesh::FTMesh() : currentTesselation(0), err(0) { tesselationList.reserve(16); } FTMesh::~FTMesh() { for(size_t t = 0; t < tesselationList.size(); ++t) { delete tesselationList[t]; } tesselationList.clear(); } void FTMesh::AddPoint(const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z) { currentTesselation->AddPoint(x, y, z); } const FTGL_DOUBLE* FTMesh::Combine(const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z) { tempPointList.push_back(FTPoint(x, y,z)); return static_cast(tempPointList.back()); } void FTMesh::Begin(GLenum meshType) { currentTesselation = new FTTesselation(meshType); } void FTMesh::End() { tesselationList.push_back(currentTesselation); } const FTTesselation* /*const*/ FTMesh::Tesselation(size_t index) const { return (index < tesselationList.size()) ? tesselationList[index] : NULL; } FTVectoriser::FTVectoriser(const FT_GlyphSlot glyph) : contourList(0), mesh(0), ftContourCount(0), contourFlag(0) { if(glyph) { outline = glyph->outline; ftContourCount = outline.n_contours; contourList = 0; contourFlag = outline.flags; ProcessContours(); } } FTVectoriser::~FTVectoriser() { for(size_t c = 0; c < ContourCount(); ++c) { delete contourList[c]; } delete [] contourList; delete mesh; } void FTVectoriser::ProcessContours() { short contourLength = 0; short startIndex = 0; short endIndex = 0; contourList = new FTContour*[ftContourCount]; for(int i = 0; i < ftContourCount; ++i) { FT_Vector* pointList = &outline.points[startIndex]; char* tagList = &outline.tags[startIndex]; endIndex = outline.contours[i]; contourLength = (endIndex - startIndex) + 1; FTContour* contour = new FTContour(pointList, tagList, contourLength); contourList[i] = contour; startIndex = endIndex + 1; } // Compute each contour's parity. FIXME: see if FT_Outline_Get_Orientation // can do it for us. for(int i = 0; i < ftContourCount; i++) { FTContour *c1 = contourList[i]; // 1. Find the leftmost point. FTPoint leftmost(65536.0, 0.0); for(size_t n = 0; n < c1->PointCount(); n++) { FTPoint p = c1->Point(n); if(p.X() < leftmost.X()) { leftmost = p; } } // 2. Count how many other contours we cross when going further to // the left. int parity = 0; for(int j = 0; j < ftContourCount; j++) { if(j == i) { continue; } FTContour *c2 = contourList[j]; for(size_t n = 0; n < c2->PointCount(); n++) { FTPoint p1 = c2->Point(n); FTPoint p2 = c2->Point((n + 1) % c2->PointCount()); /* FIXME: combinations of >= > <= and < do not seem stable */ if((p1.Y() < leftmost.Y() && p2.Y() < leftmost.Y()) || (p1.Y() >= leftmost.Y() && p2.Y() >= leftmost.Y()) || (p1.X() > leftmost.X() && p2.X() > leftmost.X())) { continue; } else if(p1.X() < leftmost.X() && p2.X() < leftmost.X()) { parity++; } else { FTPoint a = p1 - leftmost; FTPoint b = p2 - leftmost; if(b.X() * a.Y() > b.Y() * a.X()) { parity++; } } } } // 3. Make sure the glyph has the proper parity. c1->SetParity(parity); } } size_t FTVectoriser::PointCount() { size_t s = 0; for(size_t c = 0; c < ContourCount(); ++c) { s += contourList[c]->PointCount(); } return s; } const FTContour* /*const*/ FTVectoriser::Contour(size_t index) const { return (index < ContourCount()) ? contourList[index] : NULL; } void FTVectoriser::MakeMesh(FTGL_DOUBLE zNormal, int outsetType, float outsetSize) { if(mesh) { delete mesh; } mesh = new FTMesh; GLUtesselator* tobj = gluNewTess(); gluTessCallback(tobj, GLU_TESS_BEGIN_DATA, (GLUTesselatorFunction)ftglBegin); gluTessCallback(tobj, GLU_TESS_VERTEX_DATA, (GLUTesselatorFunction)ftglVertex); gluTessCallback(tobj, GLU_TESS_COMBINE_DATA, (GLUTesselatorFunction)ftglCombine); gluTessCallback(tobj, GLU_TESS_END_DATA, (GLUTesselatorFunction)ftglEnd); gluTessCallback(tobj, GLU_TESS_ERROR_DATA, (GLUTesselatorFunction)ftglError); if(contourFlag & ft_outline_even_odd_fill) // ft_outline_reverse_fill { gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); } else { gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO); } gluTessProperty(tobj, GLU_TESS_TOLERANCE, 0); gluTessNormal(tobj, 0.0f, 0.0f, zNormal); gluTessBeginPolygon(tobj, mesh); for(size_t c = 0; c < ContourCount(); ++c) { /* Build the */ switch(outsetType) { case 1 : contourList[c]->buildFrontOutset(outsetSize); break; case 2 : contourList[c]->buildBackOutset(outsetSize); break; } const FTContour* contour = contourList[c]; gluTessBeginContour(tobj); for(size_t p = 0; p < contour->PointCount(); ++p) { const FTGL_DOUBLE* d; switch(outsetType) { case 1: d = contour->FrontPoint(p); break; case 2: d = contour->BackPoint(p); break; case 0: default: d = contour->Point(p); break; } // XXX: gluTessVertex doesn't modify the data but does not // specify "const" in its prototype, so we cannot cast to // a const type. gluTessVertex(tobj, (GLdouble *)d, (GLvoid *)d); } gluTessEndContour(tobj); } gluTessEndPolygon(tobj); gluDeleteTess(tobj); } connectome-workbench-1.4.2/src/FtglFont/FTVectoriser.h000066400000000000000000000173421360521144700227040ustar00rootroot00000000000000/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2014 Washington University School of Medicine * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTVectoriser__ #define __FTVectoriser__ #include "FTGL/ftgl.h" #include "FTContour.h" #include "FTList.h" #include "FTVector.h" #ifndef CALLBACK #define CALLBACK #endif /** * FTTesselation captures points that are output by OpenGL's gluTesselator. */ class FTTesselation { public: /** * Default constructor */ FTTesselation(GLenum m) : meshType(m) { pointList.reserve(128); } /** * Destructor */ ~FTTesselation() { pointList.clear(); } /** * Add a point to the mesh. */ void AddPoint(const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z) { pointList.push_back(FTPoint(x, y, z)); } /** * The number of points in this mesh */ size_t PointCount() const { return pointList.size(); } /** * */ const FTPoint& Point(unsigned int index) const { return pointList[index]; } /** * Return the OpenGL polygon type. */ GLenum PolygonType() const { return meshType; } private: /** * Points generated by gluTesselator. */ typedef FTVector PointVector; PointVector pointList; /** * OpenGL primitive type from gluTesselator. */ GLenum meshType; }; /** * FTMesh is a container of FTTesselation's that make up a polygon glyph */ class FTMesh { typedef FTVector TesselationVector; typedef FTList PointList; public: /** * Default constructor */ FTMesh(); /** * Destructor */ ~FTMesh(); /** * Add a point to the mesh */ void AddPoint(const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z); /** * Create a combine point for the gluTesselator */ const FTGL_DOUBLE* Combine(const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z); /** * Begin a new polygon */ void Begin(GLenum meshType); /** * End a polygon */ void End(); /** * Record a gluTesselation error */ void Error(GLenum e) { err = e; } /** * The number of tesselations in the mesh */ size_t TesselationCount() const { return tesselationList.size(); } /** * Get a tesselation by index */ const FTTesselation* /*const*/ Tesselation(size_t index) const; /** * Return the temporary point list. For testing only. */ const PointList& TempPointList() const { return tempPointList; } /** * Get the GL ERROR returned by the glu tesselator */ GLenum Error() const { return err; } private: /** * The current sub mesh that we are constructing. */ FTTesselation* currentTesselation; /** * Holds each sub mesh that comprises this glyph. */ TesselationVector tesselationList; /** * Holds extra points created by gluTesselator. See ftglCombine. */ PointList tempPointList; /** * GL ERROR returned by the glu tesselator */ GLenum err; }; const FTGL_DOUBLE FTGL_FRONT_FACING = 1.0; const FTGL_DOUBLE FTGL_BACK_FACING = -1.0; /** * FTVectoriser class is a helper class that converts font outlines into * point data. * * @see FTExtrudeGlyph * @see FTOutlineGlyph * @see FTPolygonGlyph * @see FTContour * @see FTPoint * */ class FTVectoriser { public: /** * Constructor * * @param glyph The freetype glyph to be processed */ FTVectoriser(const FT_GlyphSlot glyph); /** * Destructor */ virtual ~FTVectoriser(); /** * Build an FTMesh from the vector outline data. * * @param zNormal The direction of the z axis of the normal * for this mesh * FIXME: change the following for a constant * @param outsetType Specify the outset type contour * 0 : Original * 1 : Front * 2 : Back * @param outsetSize Specify the outset size contour */ void MakeMesh(FTGL_DOUBLE zNormal = FTGL_FRONT_FACING, int outsetType = 0, float outsetSize = 0.0f); /** * Get the current mesh. */ const FTMesh* /*const*/ GetMesh() const { return mesh; } /** * Get the total count of points in this outline * * @return the number of points */ size_t PointCount(); /** * Get the count of contours in this outline * * @return the number of contours */ size_t ContourCount() const { return ftContourCount; } /** * Return a contour at index * * @return the number of contours */ const FTContour* /*const*/ Contour(size_t index) const; /** * Get the number of points in a specific contour in this outline * * @param c The contour index * @return the number of points in contour[c] */ size_t ContourSize(int c) const { return contourList[c]->PointCount(); } /** * Get the flag for the tesselation rule for this outline * * @return The contour flag */ int ContourFlag() const { return contourFlag; } private: /** * Process the freetype outline data into contours of points * * @param front front outset distance * @param back back outset distance */ void ProcessContours(); /** * The list of contours in the glyph */ FTContour** contourList; /** * A Mesh for tesselations */ FTMesh* mesh; /** * The number of contours reported by Freetype */ short ftContourCount; /** * A flag indicating the tesselation rule for the glyph */ int contourFlag; /** * A Freetype outline */ FT_Outline outline; }; #endif // __FTVectoriser__ connectome-workbench-1.4.2/src/FtglFont/FtglConfig.h000066400000000000000000000046301360521144700223430ustar00rootroot00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* Define to the path to a TrueType font */ #define FONT_FILE /usr/X11R6/share/fonts/TTF/VeraSe.ttf /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the header file. */ #undef HAVE_GLUT_GLUT_H /* Define to 1 if you have the header file. */ #undef HAVE_GL_GLUT_H /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strndup' function. */ #define HAVE_STRNDUP 1 /* not on mac (hippocampus) */ #undef HAVE_STRNDUP /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the `wcsdup' function. */ #undef HAVE_WCSDUP /* Define to 1 if your C compiler doesn't accept -c and -o together. */ #undef NO_MINUS_C_MINUS_O /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define to 1 if the X Window System is missing or not being used. */ #define X_DISPLAY_MISSING 1 /* FOR WINDOWS, otherwise __declspec(dllimport) linking errors */ #define FTGL_LIBRARY_STATIC 1 connectome-workbench-1.4.2/src/FtglFont/Makefile.am000066400000000000000000000053401360521144700222030ustar00rootroot00000000000000 lib_LTLIBRARIES = libftgl.la libftgl_la_SOURCES = \ FTBuffer.cpp \ FTCharmap.cpp \ FTCharmap.h \ FTCharToGlyphIndexMap.h \ FTContour.cpp \ FTContour.h \ FTFace.cpp \ FTFace.h \ FTGlyphContainer.cpp \ FTGlyphContainer.h \ FTInternals.h \ FTLibrary.cpp \ FTLibrary.h \ FTList.h \ FTPoint.cpp \ FTSize.cpp \ FTSize.h \ FTVector.h \ FTVectoriser.cpp \ FTVectoriser.h \ FTUnicode.h \ $(ftglyph_sources) \ $(ftfont_sources) \ $(ftlayout_sources) \ $(ftgl_headers) \ $(NULL) libftgl_la_CPPFLAGS = -IFTGlyph -IFTFont -IFTLayout libftgl_la_CXXFLAGS = $(FT2_CFLAGS) $(GL_CFLAGS) libftgl_la_LDFLAGS = \ -no-undefined -version-number $(LT_VERSION) libftgl_la_LIBADD = \ $(FT2_LIBS) $(GL_LIBS) ftgldir = $(includedir)/FTGL ftgl_HEADERS = $(ftgl_headers) ftgl_headers = \ FTGL/ftgl.h \ FTGL/FTBBox.h \ FTGL/FTBuffer.h \ FTGL/FTPoint.h \ FTGL/FTGlyph.h \ FTGL/FTBitmapGlyph.h \ FTGL/FTBufferGlyph.h \ FTGL/FTExtrdGlyph.h \ FTGL/FTOutlineGlyph.h \ FTGL/FTPixmapGlyph.h \ FTGL/FTPolyGlyph.h \ FTGL/FTTextureGlyph.h \ FTGL/FTFont.h \ FTGL/FTGLBitmapFont.h \ FTGL/FTBufferFont.h \ FTGL/FTGLExtrdFont.h \ FTGL/FTGLOutlineFont.h \ FTGL/FTGLPixmapFont.h \ FTGL/FTGLPolygonFont.h \ FTGL/FTGLTextureFont.h \ FTGL/FTLayout.h \ FTGL/FTSimpleLayout.h \ ${NULL} ftglyph_sources = \ FTGlyph/FTGlyph.cpp \ FTGlyph/FTGlyphImpl.h \ FTGlyph/FTGlyphGlue.cpp \ FTGlyph/FTBitmapGlyph.cpp \ FTGlyph/FTBitmapGlyphImpl.h \ FTGlyph/FTBufferGlyph.cpp \ FTGlyph/FTBufferGlyphImpl.h \ FTGlyph/FTExtrudeGlyph.cpp \ FTGlyph/FTExtrudeGlyphImpl.h \ FTGlyph/FTOutlineGlyph.cpp \ FTGlyph/FTOutlineGlyphImpl.h \ FTGlyph/FTPixmapGlyph.cpp \ FTGlyph/FTPixmapGlyphImpl.h \ FTGlyph/FTPolygonGlyph.cpp \ FTGlyph/FTPolygonGlyphImpl.h \ FTGlyph/FTTextureGlyph.cpp \ FTGlyph/FTTextureGlyphImpl.h \ $(NULL) ftfont_sources = \ FTFont/FTFont.cpp \ FTFont/FTFontImpl.h \ FTFont/FTFontGlue.cpp \ FTFont/FTBitmapFont.cpp \ FTFont/FTBitmapFontImpl.h \ FTFont/FTBufferFont.cpp \ FTFont/FTBufferFontImpl.h \ FTFont/FTExtrudeFont.cpp \ FTFont/FTExtrudeFontImpl.h \ FTFont/FTOutlineFont.cpp \ FTFont/FTOutlineFontImpl.h \ FTFont/FTPixmapFont.cpp \ FTFont/FTPixmapFontImpl.h \ FTFont/FTPolygonFont.cpp \ FTFont/FTPolygonFontImpl.h \ FTFont/FTTextureFont.cpp \ FTFont/FTTextureFontImpl.h \ $(NULL) ftlayout_sources = \ FTLayout/FTLayout.cpp \ FTLayout/FTLayoutImpl.h \ FTLayout/FTLayoutGlue.cpp \ FTLayout/FTSimpleLayout.cpp \ FTLayout/FTSimpleLayoutImpl.h \ $(NULL) NULL = connectome-workbench-1.4.2/src/FtglFont/Makefile.in000066400000000000000000001550131360521144700222170ustar00rootroot00000000000000# Makefile.in generated by automake 1.10.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src DIST_COMMON = $(ftgl_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cxx.m4 $(top_srcdir)/m4/font.m4 \ $(top_srcdir)/m4/freetype2.m4 $(top_srcdir)/m4/gl.m4 \ $(top_srcdir)/m4/glut.m4 $(top_srcdir)/m4/pkg.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(ftgldir)" libLTLIBRARIES_INSTALL = $(INSTALL) LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libftgl_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am__objects_1 = am__objects_2 = libftgl_la-FTGlyph.lo libftgl_la-FTGlyphGlue.lo \ libftgl_la-FTBitmapGlyph.lo libftgl_la-FTBufferGlyph.lo \ libftgl_la-FTExtrudeGlyph.lo libftgl_la-FTOutlineGlyph.lo \ libftgl_la-FTPixmapGlyph.lo libftgl_la-FTPolygonGlyph.lo \ libftgl_la-FTTextureGlyph.lo $(am__objects_1) am__objects_3 = libftgl_la-FTFont.lo libftgl_la-FTFontGlue.lo \ libftgl_la-FTBitmapFont.lo libftgl_la-FTBufferFont.lo \ libftgl_la-FTExtrudeFont.lo libftgl_la-FTOutlineFont.lo \ libftgl_la-FTPixmapFont.lo libftgl_la-FTPolygonFont.lo \ libftgl_la-FTTextureFont.lo $(am__objects_1) am__objects_4 = libftgl_la-FTLayout.lo libftgl_la-FTLayoutGlue.lo \ libftgl_la-FTSimpleLayout.lo $(am__objects_1) am__objects_5 = $(am__objects_1) am_libftgl_la_OBJECTS = libftgl_la-FTBuffer.lo libftgl_la-FTCharmap.lo \ libftgl_la-FTContour.lo libftgl_la-FTFace.lo \ libftgl_la-FTGlyphContainer.lo libftgl_la-FTLibrary.lo \ libftgl_la-FTPoint.lo libftgl_la-FTSize.lo \ libftgl_la-FTVectoriser.lo $(am__objects_2) $(am__objects_3) \ $(am__objects_4) $(am__objects_5) $(am__objects_1) libftgl_la_OBJECTS = $(am_libftgl_la_OBJECTS) libftgl_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(libftgl_la_CXXFLAGS) \ $(CXXFLAGS) $(libftgl_la_LDFLAGS) $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/.auto/depcomp am__depfiles_maybe = depfiles CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libftgl_la_SOURCES) DIST_SOURCES = $(libftgl_la_SOURCES) ftglHEADERS_INSTALL = $(INSTALL_HEADER) HEADERS = $(ftgl_HEADERS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONVERT = @CONVERT@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DOXYGEN = @DOXYGEN@ DSYMUTIL = @DSYMUTIL@ DVIPS = @DVIPS@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EPSTOPDF = @EPSTOPDF@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ FRAMEWORK_OPENGL = @FRAMEWORK_OPENGL@ FT2_CFLAGS = @FT2_CFLAGS@ FT2_CONFIG = @FT2_CONFIG@ FT2_LIBS = @FT2_LIBS@ GLUT_CFLAGS = @GLUT_CFLAGS@ GLUT_LIBS = @GLUT_LIBS@ GL_CFLAGS = @GL_CFLAGS@ GL_LIBS = @GL_LIBS@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KPSEWHICH = @KPSEWHICH@ LATEX = @LATEX@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_MAJOR = @LT_MAJOR@ LT_MICRO = @LT_MICRO@ LT_MINOR = @LT_MINOR@ LT_VERSION = @LT_VERSION@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NMEDIT = @NMEDIT@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ lib_LTLIBRARIES = libftgl.la libftgl_la_SOURCES = \ FTBuffer.cpp \ FTCharmap.cpp \ FTCharmap.h \ FTCharToGlyphIndexMap.h \ FTContour.cpp \ FTContour.h \ FTFace.cpp \ FTFace.h \ FTGlyphContainer.cpp \ FTGlyphContainer.h \ FTInternals.h \ FTLibrary.cpp \ FTLibrary.h \ FTList.h \ FTPoint.cpp \ FTSize.cpp \ FTSize.h \ FTVector.h \ FTVectoriser.cpp \ FTVectoriser.h \ FTUnicode.h \ $(ftglyph_sources) \ $(ftfont_sources) \ $(ftlayout_sources) \ $(ftgl_headers) \ $(NULL) libftgl_la_CPPFLAGS = -IFTGlyph -IFTFont -IFTLayout libftgl_la_CXXFLAGS = $(FT2_CFLAGS) $(GL_CFLAGS) libftgl_la_LDFLAGS = \ -no-undefined -version-number $(LT_VERSION) libftgl_la_LIBADD = \ $(FT2_LIBS) $(GL_LIBS) ftgldir = $(includedir)/FTGL ftgl_HEADERS = $(ftgl_headers) ftgl_headers = \ FTGL/ftgl.h \ FTGL/FTBBox.h \ FTGL/FTBuffer.h \ FTGL/FTPoint.h \ FTGL/FTGlyph.h \ FTGL/FTBitmapGlyph.h \ FTGL/FTBufferGlyph.h \ FTGL/FTExtrdGlyph.h \ FTGL/FTOutlineGlyph.h \ FTGL/FTPixmapGlyph.h \ FTGL/FTPolyGlyph.h \ FTGL/FTTextureGlyph.h \ FTGL/FTFont.h \ FTGL/FTGLBitmapFont.h \ FTGL/FTBufferFont.h \ FTGL/FTGLExtrdFont.h \ FTGL/FTGLOutlineFont.h \ FTGL/FTGLPixmapFont.h \ FTGL/FTGLPolygonFont.h \ FTGL/FTGLTextureFont.h \ FTGL/FTLayout.h \ FTGL/FTSimpleLayout.h \ ${NULL} ftglyph_sources = \ FTGlyph/FTGlyph.cpp \ FTGlyph/FTGlyphImpl.h \ FTGlyph/FTGlyphGlue.cpp \ FTGlyph/FTBitmapGlyph.cpp \ FTGlyph/FTBitmapGlyphImpl.h \ FTGlyph/FTBufferGlyph.cpp \ FTGlyph/FTBufferGlyphImpl.h \ FTGlyph/FTExtrudeGlyph.cpp \ FTGlyph/FTExtrudeGlyphImpl.h \ FTGlyph/FTOutlineGlyph.cpp \ FTGlyph/FTOutlineGlyphImpl.h \ FTGlyph/FTPixmapGlyph.cpp \ FTGlyph/FTPixmapGlyphImpl.h \ FTGlyph/FTPolygonGlyph.cpp \ FTGlyph/FTPolygonGlyphImpl.h \ FTGlyph/FTTextureGlyph.cpp \ FTGlyph/FTTextureGlyphImpl.h \ $(NULL) ftfont_sources = \ FTFont/FTFont.cpp \ FTFont/FTFontImpl.h \ FTFont/FTFontGlue.cpp \ FTFont/FTBitmapFont.cpp \ FTFont/FTBitmapFontImpl.h \ FTFont/FTBufferFont.cpp \ FTFont/FTBufferFontImpl.h \ FTFont/FTExtrudeFont.cpp \ FTFont/FTExtrudeFontImpl.h \ FTFont/FTOutlineFont.cpp \ FTFont/FTOutlineFontImpl.h \ FTFont/FTPixmapFont.cpp \ FTFont/FTPixmapFontImpl.h \ FTFont/FTPolygonFont.cpp \ FTFont/FTPolygonFontImpl.h \ FTFont/FTTextureFont.cpp \ FTFont/FTTextureFontImpl.h \ $(NULL) ftlayout_sources = \ FTLayout/FTLayout.cpp \ FTLayout/FTLayoutImpl.h \ FTLayout/FTLayoutGlue.cpp \ FTLayout/FTSimpleLayout.cpp \ FTLayout/FTSimpleLayoutImpl.h \ $(NULL) NULL = all: all-am .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu src/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ if test -f $$p; then \ f=$(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ else :; fi; \ done uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ p=$(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libftgl.la: $(libftgl_la_OBJECTS) $(libftgl_la_DEPENDENCIES) $(libftgl_la_LINK) -rpath $(libdir) $(libftgl_la_OBJECTS) $(libftgl_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTBitmapFont.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTBitmapGlyph.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTBuffer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTBufferFont.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTBufferGlyph.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTCharmap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTContour.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTExtrudeFont.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTExtrudeGlyph.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTFace.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTFont.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTFontGlue.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTGlyph.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTGlyphContainer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTGlyphGlue.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTLayout.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTLayoutGlue.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTLibrary.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTOutlineFont.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTOutlineGlyph.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTPixmapFont.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTPixmapGlyph.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTPoint.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTPolygonFont.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTPolygonGlyph.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTSimpleLayout.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTSize.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTTextureFont.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTTextureGlyph.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libftgl_la-FTVectoriser.Plo@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< libftgl_la-FTBuffer.lo: FTBuffer.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTBuffer.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTBuffer.Tpo -c -o libftgl_la-FTBuffer.lo `test -f 'FTBuffer.cpp' || echo '$(srcdir)/'`FTBuffer.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTBuffer.Tpo $(DEPDIR)/libftgl_la-FTBuffer.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTBuffer.cpp' object='libftgl_la-FTBuffer.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTBuffer.lo `test -f 'FTBuffer.cpp' || echo '$(srcdir)/'`FTBuffer.cpp libftgl_la-FTCharmap.lo: FTCharmap.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTCharmap.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTCharmap.Tpo -c -o libftgl_la-FTCharmap.lo `test -f 'FTCharmap.cpp' || echo '$(srcdir)/'`FTCharmap.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTCharmap.Tpo $(DEPDIR)/libftgl_la-FTCharmap.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTCharmap.cpp' object='libftgl_la-FTCharmap.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTCharmap.lo `test -f 'FTCharmap.cpp' || echo '$(srcdir)/'`FTCharmap.cpp libftgl_la-FTContour.lo: FTContour.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTContour.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTContour.Tpo -c -o libftgl_la-FTContour.lo `test -f 'FTContour.cpp' || echo '$(srcdir)/'`FTContour.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTContour.Tpo $(DEPDIR)/libftgl_la-FTContour.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTContour.cpp' object='libftgl_la-FTContour.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTContour.lo `test -f 'FTContour.cpp' || echo '$(srcdir)/'`FTContour.cpp libftgl_la-FTFace.lo: FTFace.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTFace.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTFace.Tpo -c -o libftgl_la-FTFace.lo `test -f 'FTFace.cpp' || echo '$(srcdir)/'`FTFace.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTFace.Tpo $(DEPDIR)/libftgl_la-FTFace.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTFace.cpp' object='libftgl_la-FTFace.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTFace.lo `test -f 'FTFace.cpp' || echo '$(srcdir)/'`FTFace.cpp libftgl_la-FTGlyphContainer.lo: FTGlyphContainer.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTGlyphContainer.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTGlyphContainer.Tpo -c -o libftgl_la-FTGlyphContainer.lo `test -f 'FTGlyphContainer.cpp' || echo '$(srcdir)/'`FTGlyphContainer.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTGlyphContainer.Tpo $(DEPDIR)/libftgl_la-FTGlyphContainer.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTGlyphContainer.cpp' object='libftgl_la-FTGlyphContainer.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTGlyphContainer.lo `test -f 'FTGlyphContainer.cpp' || echo '$(srcdir)/'`FTGlyphContainer.cpp libftgl_la-FTLibrary.lo: FTLibrary.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTLibrary.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTLibrary.Tpo -c -o libftgl_la-FTLibrary.lo `test -f 'FTLibrary.cpp' || echo '$(srcdir)/'`FTLibrary.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTLibrary.Tpo $(DEPDIR)/libftgl_la-FTLibrary.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTLibrary.cpp' object='libftgl_la-FTLibrary.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTLibrary.lo `test -f 'FTLibrary.cpp' || echo '$(srcdir)/'`FTLibrary.cpp libftgl_la-FTPoint.lo: FTPoint.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTPoint.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTPoint.Tpo -c -o libftgl_la-FTPoint.lo `test -f 'FTPoint.cpp' || echo '$(srcdir)/'`FTPoint.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTPoint.Tpo $(DEPDIR)/libftgl_la-FTPoint.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTPoint.cpp' object='libftgl_la-FTPoint.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTPoint.lo `test -f 'FTPoint.cpp' || echo '$(srcdir)/'`FTPoint.cpp libftgl_la-FTSize.lo: FTSize.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTSize.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTSize.Tpo -c -o libftgl_la-FTSize.lo `test -f 'FTSize.cpp' || echo '$(srcdir)/'`FTSize.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTSize.Tpo $(DEPDIR)/libftgl_la-FTSize.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTSize.cpp' object='libftgl_la-FTSize.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTSize.lo `test -f 'FTSize.cpp' || echo '$(srcdir)/'`FTSize.cpp libftgl_la-FTVectoriser.lo: FTVectoriser.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTVectoriser.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTVectoriser.Tpo -c -o libftgl_la-FTVectoriser.lo `test -f 'FTVectoriser.cpp' || echo '$(srcdir)/'`FTVectoriser.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTVectoriser.Tpo $(DEPDIR)/libftgl_la-FTVectoriser.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTVectoriser.cpp' object='libftgl_la-FTVectoriser.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTVectoriser.lo `test -f 'FTVectoriser.cpp' || echo '$(srcdir)/'`FTVectoriser.cpp libftgl_la-FTGlyph.lo: FTGlyph/FTGlyph.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTGlyph.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTGlyph.Tpo -c -o libftgl_la-FTGlyph.lo `test -f 'FTGlyph/FTGlyph.cpp' || echo '$(srcdir)/'`FTGlyph/FTGlyph.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTGlyph.Tpo $(DEPDIR)/libftgl_la-FTGlyph.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTGlyph/FTGlyph.cpp' object='libftgl_la-FTGlyph.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTGlyph.lo `test -f 'FTGlyph/FTGlyph.cpp' || echo '$(srcdir)/'`FTGlyph/FTGlyph.cpp libftgl_la-FTGlyphGlue.lo: FTGlyph/FTGlyphGlue.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTGlyphGlue.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTGlyphGlue.Tpo -c -o libftgl_la-FTGlyphGlue.lo `test -f 'FTGlyph/FTGlyphGlue.cpp' || echo '$(srcdir)/'`FTGlyph/FTGlyphGlue.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTGlyphGlue.Tpo $(DEPDIR)/libftgl_la-FTGlyphGlue.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTGlyph/FTGlyphGlue.cpp' object='libftgl_la-FTGlyphGlue.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTGlyphGlue.lo `test -f 'FTGlyph/FTGlyphGlue.cpp' || echo '$(srcdir)/'`FTGlyph/FTGlyphGlue.cpp libftgl_la-FTBitmapGlyph.lo: FTGlyph/FTBitmapGlyph.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTBitmapGlyph.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTBitmapGlyph.Tpo -c -o libftgl_la-FTBitmapGlyph.lo `test -f 'FTGlyph/FTBitmapGlyph.cpp' || echo '$(srcdir)/'`FTGlyph/FTBitmapGlyph.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTBitmapGlyph.Tpo $(DEPDIR)/libftgl_la-FTBitmapGlyph.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTGlyph/FTBitmapGlyph.cpp' object='libftgl_la-FTBitmapGlyph.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTBitmapGlyph.lo `test -f 'FTGlyph/FTBitmapGlyph.cpp' || echo '$(srcdir)/'`FTGlyph/FTBitmapGlyph.cpp libftgl_la-FTBufferGlyph.lo: FTGlyph/FTBufferGlyph.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTBufferGlyph.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTBufferGlyph.Tpo -c -o libftgl_la-FTBufferGlyph.lo `test -f 'FTGlyph/FTBufferGlyph.cpp' || echo '$(srcdir)/'`FTGlyph/FTBufferGlyph.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTBufferGlyph.Tpo $(DEPDIR)/libftgl_la-FTBufferGlyph.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTGlyph/FTBufferGlyph.cpp' object='libftgl_la-FTBufferGlyph.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTBufferGlyph.lo `test -f 'FTGlyph/FTBufferGlyph.cpp' || echo '$(srcdir)/'`FTGlyph/FTBufferGlyph.cpp libftgl_la-FTExtrudeGlyph.lo: FTGlyph/FTExtrudeGlyph.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTExtrudeGlyph.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTExtrudeGlyph.Tpo -c -o libftgl_la-FTExtrudeGlyph.lo `test -f 'FTGlyph/FTExtrudeGlyph.cpp' || echo '$(srcdir)/'`FTGlyph/FTExtrudeGlyph.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTExtrudeGlyph.Tpo $(DEPDIR)/libftgl_la-FTExtrudeGlyph.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTGlyph/FTExtrudeGlyph.cpp' object='libftgl_la-FTExtrudeGlyph.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTExtrudeGlyph.lo `test -f 'FTGlyph/FTExtrudeGlyph.cpp' || echo '$(srcdir)/'`FTGlyph/FTExtrudeGlyph.cpp libftgl_la-FTOutlineGlyph.lo: FTGlyph/FTOutlineGlyph.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTOutlineGlyph.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTOutlineGlyph.Tpo -c -o libftgl_la-FTOutlineGlyph.lo `test -f 'FTGlyph/FTOutlineGlyph.cpp' || echo '$(srcdir)/'`FTGlyph/FTOutlineGlyph.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTOutlineGlyph.Tpo $(DEPDIR)/libftgl_la-FTOutlineGlyph.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTGlyph/FTOutlineGlyph.cpp' object='libftgl_la-FTOutlineGlyph.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTOutlineGlyph.lo `test -f 'FTGlyph/FTOutlineGlyph.cpp' || echo '$(srcdir)/'`FTGlyph/FTOutlineGlyph.cpp libftgl_la-FTPixmapGlyph.lo: FTGlyph/FTPixmapGlyph.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTPixmapGlyph.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTPixmapGlyph.Tpo -c -o libftgl_la-FTPixmapGlyph.lo `test -f 'FTGlyph/FTPixmapGlyph.cpp' || echo '$(srcdir)/'`FTGlyph/FTPixmapGlyph.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTPixmapGlyph.Tpo $(DEPDIR)/libftgl_la-FTPixmapGlyph.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTGlyph/FTPixmapGlyph.cpp' object='libftgl_la-FTPixmapGlyph.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTPixmapGlyph.lo `test -f 'FTGlyph/FTPixmapGlyph.cpp' || echo '$(srcdir)/'`FTGlyph/FTPixmapGlyph.cpp libftgl_la-FTPolygonGlyph.lo: FTGlyph/FTPolygonGlyph.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTPolygonGlyph.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTPolygonGlyph.Tpo -c -o libftgl_la-FTPolygonGlyph.lo `test -f 'FTGlyph/FTPolygonGlyph.cpp' || echo '$(srcdir)/'`FTGlyph/FTPolygonGlyph.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTPolygonGlyph.Tpo $(DEPDIR)/libftgl_la-FTPolygonGlyph.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTGlyph/FTPolygonGlyph.cpp' object='libftgl_la-FTPolygonGlyph.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTPolygonGlyph.lo `test -f 'FTGlyph/FTPolygonGlyph.cpp' || echo '$(srcdir)/'`FTGlyph/FTPolygonGlyph.cpp libftgl_la-FTTextureGlyph.lo: FTGlyph/FTTextureGlyph.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTTextureGlyph.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTTextureGlyph.Tpo -c -o libftgl_la-FTTextureGlyph.lo `test -f 'FTGlyph/FTTextureGlyph.cpp' || echo '$(srcdir)/'`FTGlyph/FTTextureGlyph.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTTextureGlyph.Tpo $(DEPDIR)/libftgl_la-FTTextureGlyph.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTGlyph/FTTextureGlyph.cpp' object='libftgl_la-FTTextureGlyph.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTTextureGlyph.lo `test -f 'FTGlyph/FTTextureGlyph.cpp' || echo '$(srcdir)/'`FTGlyph/FTTextureGlyph.cpp libftgl_la-FTFont.lo: FTFont/FTFont.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTFont.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTFont.Tpo -c -o libftgl_la-FTFont.lo `test -f 'FTFont/FTFont.cpp' || echo '$(srcdir)/'`FTFont/FTFont.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTFont.Tpo $(DEPDIR)/libftgl_la-FTFont.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTFont/FTFont.cpp' object='libftgl_la-FTFont.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTFont.lo `test -f 'FTFont/FTFont.cpp' || echo '$(srcdir)/'`FTFont/FTFont.cpp libftgl_la-FTFontGlue.lo: FTFont/FTFontGlue.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTFontGlue.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTFontGlue.Tpo -c -o libftgl_la-FTFontGlue.lo `test -f 'FTFont/FTFontGlue.cpp' || echo '$(srcdir)/'`FTFont/FTFontGlue.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTFontGlue.Tpo $(DEPDIR)/libftgl_la-FTFontGlue.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTFont/FTFontGlue.cpp' object='libftgl_la-FTFontGlue.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTFontGlue.lo `test -f 'FTFont/FTFontGlue.cpp' || echo '$(srcdir)/'`FTFont/FTFontGlue.cpp libftgl_la-FTBitmapFont.lo: FTFont/FTBitmapFont.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTBitmapFont.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTBitmapFont.Tpo -c -o libftgl_la-FTBitmapFont.lo `test -f 'FTFont/FTBitmapFont.cpp' || echo '$(srcdir)/'`FTFont/FTBitmapFont.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTBitmapFont.Tpo $(DEPDIR)/libftgl_la-FTBitmapFont.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTFont/FTBitmapFont.cpp' object='libftgl_la-FTBitmapFont.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTBitmapFont.lo `test -f 'FTFont/FTBitmapFont.cpp' || echo '$(srcdir)/'`FTFont/FTBitmapFont.cpp libftgl_la-FTBufferFont.lo: FTFont/FTBufferFont.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTBufferFont.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTBufferFont.Tpo -c -o libftgl_la-FTBufferFont.lo `test -f 'FTFont/FTBufferFont.cpp' || echo '$(srcdir)/'`FTFont/FTBufferFont.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTBufferFont.Tpo $(DEPDIR)/libftgl_la-FTBufferFont.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTFont/FTBufferFont.cpp' object='libftgl_la-FTBufferFont.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTBufferFont.lo `test -f 'FTFont/FTBufferFont.cpp' || echo '$(srcdir)/'`FTFont/FTBufferFont.cpp libftgl_la-FTExtrudeFont.lo: FTFont/FTExtrudeFont.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTExtrudeFont.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTExtrudeFont.Tpo -c -o libftgl_la-FTExtrudeFont.lo `test -f 'FTFont/FTExtrudeFont.cpp' || echo '$(srcdir)/'`FTFont/FTExtrudeFont.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTExtrudeFont.Tpo $(DEPDIR)/libftgl_la-FTExtrudeFont.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTFont/FTExtrudeFont.cpp' object='libftgl_la-FTExtrudeFont.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTExtrudeFont.lo `test -f 'FTFont/FTExtrudeFont.cpp' || echo '$(srcdir)/'`FTFont/FTExtrudeFont.cpp libftgl_la-FTOutlineFont.lo: FTFont/FTOutlineFont.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTOutlineFont.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTOutlineFont.Tpo -c -o libftgl_la-FTOutlineFont.lo `test -f 'FTFont/FTOutlineFont.cpp' || echo '$(srcdir)/'`FTFont/FTOutlineFont.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTOutlineFont.Tpo $(DEPDIR)/libftgl_la-FTOutlineFont.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTFont/FTOutlineFont.cpp' object='libftgl_la-FTOutlineFont.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTOutlineFont.lo `test -f 'FTFont/FTOutlineFont.cpp' || echo '$(srcdir)/'`FTFont/FTOutlineFont.cpp libftgl_la-FTPixmapFont.lo: FTFont/FTPixmapFont.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTPixmapFont.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTPixmapFont.Tpo -c -o libftgl_la-FTPixmapFont.lo `test -f 'FTFont/FTPixmapFont.cpp' || echo '$(srcdir)/'`FTFont/FTPixmapFont.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTPixmapFont.Tpo $(DEPDIR)/libftgl_la-FTPixmapFont.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTFont/FTPixmapFont.cpp' object='libftgl_la-FTPixmapFont.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTPixmapFont.lo `test -f 'FTFont/FTPixmapFont.cpp' || echo '$(srcdir)/'`FTFont/FTPixmapFont.cpp libftgl_la-FTPolygonFont.lo: FTFont/FTPolygonFont.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTPolygonFont.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTPolygonFont.Tpo -c -o libftgl_la-FTPolygonFont.lo `test -f 'FTFont/FTPolygonFont.cpp' || echo '$(srcdir)/'`FTFont/FTPolygonFont.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTPolygonFont.Tpo $(DEPDIR)/libftgl_la-FTPolygonFont.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTFont/FTPolygonFont.cpp' object='libftgl_la-FTPolygonFont.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTPolygonFont.lo `test -f 'FTFont/FTPolygonFont.cpp' || echo '$(srcdir)/'`FTFont/FTPolygonFont.cpp libftgl_la-FTTextureFont.lo: FTFont/FTTextureFont.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTTextureFont.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTTextureFont.Tpo -c -o libftgl_la-FTTextureFont.lo `test -f 'FTFont/FTTextureFont.cpp' || echo '$(srcdir)/'`FTFont/FTTextureFont.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTTextureFont.Tpo $(DEPDIR)/libftgl_la-FTTextureFont.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTFont/FTTextureFont.cpp' object='libftgl_la-FTTextureFont.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTTextureFont.lo `test -f 'FTFont/FTTextureFont.cpp' || echo '$(srcdir)/'`FTFont/FTTextureFont.cpp libftgl_la-FTLayout.lo: FTLayout/FTLayout.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTLayout.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTLayout.Tpo -c -o libftgl_la-FTLayout.lo `test -f 'FTLayout/FTLayout.cpp' || echo '$(srcdir)/'`FTLayout/FTLayout.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTLayout.Tpo $(DEPDIR)/libftgl_la-FTLayout.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTLayout/FTLayout.cpp' object='libftgl_la-FTLayout.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTLayout.lo `test -f 'FTLayout/FTLayout.cpp' || echo '$(srcdir)/'`FTLayout/FTLayout.cpp libftgl_la-FTLayoutGlue.lo: FTLayout/FTLayoutGlue.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTLayoutGlue.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTLayoutGlue.Tpo -c -o libftgl_la-FTLayoutGlue.lo `test -f 'FTLayout/FTLayoutGlue.cpp' || echo '$(srcdir)/'`FTLayout/FTLayoutGlue.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTLayoutGlue.Tpo $(DEPDIR)/libftgl_la-FTLayoutGlue.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTLayout/FTLayoutGlue.cpp' object='libftgl_la-FTLayoutGlue.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTLayoutGlue.lo `test -f 'FTLayout/FTLayoutGlue.cpp' || echo '$(srcdir)/'`FTLayout/FTLayoutGlue.cpp libftgl_la-FTSimpleLayout.lo: FTLayout/FTSimpleLayout.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -MT libftgl_la-FTSimpleLayout.lo -MD -MP -MF $(DEPDIR)/libftgl_la-FTSimpleLayout.Tpo -c -o libftgl_la-FTSimpleLayout.lo `test -f 'FTLayout/FTSimpleLayout.cpp' || echo '$(srcdir)/'`FTLayout/FTSimpleLayout.cpp @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libftgl_la-FTSimpleLayout.Tpo $(DEPDIR)/libftgl_la-FTSimpleLayout.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='FTLayout/FTSimpleLayout.cpp' object='libftgl_la-FTSimpleLayout.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libftgl_la_CPPFLAGS) $(CPPFLAGS) $(libftgl_la_CXXFLAGS) $(CXXFLAGS) -c -o libftgl_la-FTSimpleLayout.lo `test -f 'FTLayout/FTSimpleLayout.cpp' || echo '$(srcdir)/'`FTLayout/FTSimpleLayout.cpp mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-ftglHEADERS: $(ftgl_HEADERS) @$(NORMAL_INSTALL) test -z "$(ftgldir)" || $(MKDIR_P) "$(DESTDIR)$(ftgldir)" @list='$(ftgl_HEADERS)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(ftglHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(ftgldir)/$$f'"; \ $(ftglHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(ftgldir)/$$f"; \ done uninstall-ftglHEADERS: @$(NORMAL_UNINSTALL) @list='$(ftgl_HEADERS)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(ftgldir)/$$f'"; \ rm -f "$(DESTDIR)$(ftgldir)/$$f"; \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(ftgldir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-ftglHEADERS install-dvi: install-dvi-am install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-info: install-info-am install-man: install-pdf: install-pdf-am install-ps: install-ps-am installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-ftglHEADERS uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am \ install-ftglHEADERS install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-ftglHEADERS \ uninstall-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: connectome-workbench-1.4.2/src/FtglFont/NEWS000066400000000000000000000462531360521144700206560ustar00rootroot00000000000000 -*- coding: utf-8 -*- FTGL ==== Included below are release notes for all versions of FTGL that have been released to date. All versions prior to and including version 2.1.2 were exclusively developed by Henry Maddocks. Subsequent versions have changes attributed per contributor. ---------------------------------------------------------------------- --- 2008-06-12 Release 2.1.3~rc5 --- ---------------------------------------------------------------------- * Stable API. Public headers are now frozen. * Fixed several memory corruption and crash bugs - Sam Hocevar * Fixed several memory leaks - Sam Hocevar * Kerning and glyph performance enhancements - Sean Morrison * The library now also exports a pure C interface - Éric Beets * Inset/outset contour support for fonts - Éric Beets * Fix the FTLayout rendering - Éric Beets * Added new FTLayout and FTSimpleLayout support for layout managers - Sam Hocevar * Fixed the paths in the XCode project - Henry Maddocks * Changed the behaviour of some objects so that if there is an error their state isn't changed - Henry Maddocks * New, fast FTBufferFont texture fonts - Sam Hocevar * UTF-8 support - Daniel Remenak ---------------------------------------------------------------------- --- 2004-12-11 Release 2.1.2 --- ---------------------------------------------------------------------- * Changed the way the colour is specified for Pixmap fonts. It can now be done per string rather than at start up as previous. * Fixed a couple of compilation errors caused by the new FTPoint stuff, mostly... * More const correctness. It's like a virus! ---------------------------------------------------------------------- --- 2004-12-05 Release 2.1.1 --- ---------------------------------------------------------------------- * Added the xCode project properly this time. ---------------------------------------------------------------------- --- 2004-12-05 Release 2.1.0 --- ---------------------------------------------------------------------- * Added texture co-ordinates to the geometry based font types. * Added the ability to turn off (or on) glDisplayList creation inside FTGL. * Removed unnecessary translates in the glyph rendering code. * Moved the Mac project to XCode. * Added a line height function to FTFont. * Got rid of the GL_TEXTURE_2D_BINDING_EXT call and replaced it with a static member. * Fixed a bug where resizing FTGLTextureFont caused a GL error. * Refactored FTPoint quite a bit. * More unit tests. Fixed a heap of bugs. ---------------------------------------------------------------------- --- 2004-08-16 Release 2.0.11 --- ---------------------------------------------------------------------- * Updated FTFont( *pBufferBytes, bufferSizeInBytes) documentation. ---------------------------------------------------------------------- --- 2004-08-16 Release 2.0.10 --- ---------------------------------------------------------------------- * Fixed tab problem in unix Makefile. * Added CYGWIN GLUTesselatorFunction define to FTVectoriser. ---------------------------------------------------------------------- --- 2004-04-21 Release 2.0.9 --- ---------------------------------------------------------------------- * Fixed includes for pre 2.1.7 versions of freetype * Changed unix build to create FTGL subdir for includes ---------------------------------------------------------------------- --- 2004-04-09 Release 2.0.8 --- ---------------------------------------------------------------------- * Fixes for deprecated identifiers in 2.1.5 * Changed the internals to use FTGlyphSlot instead of FTGlyph * Added a unit test for FTBitmapGlyph, FTCharToGlyphIndexMap. * Fixed a memory leak in FTGlyphContainer. * Added the ability to get the list of charmaps in the font. * Changed FTGLTextureFont to use FTVector for texture id list. ---------------------------------------------------------------------- --- 2003-08-31 Release 2.07 --- ---------------------------------------------------------------------- * Minor fix for unix build scripts. * Minor fix for unit tests. ---------------------------------------------------------------------- --- 2003-08-25 Release 2.06 --- ---------------------------------------------------------------------- * Updated the unix build scripts. ---------------------------------------------------------------------- --- 2003-08-25 Release 2.05 --- ---------------------------------------------------------------------- * Refactored FTGlyphContainer & FTCharmap. They now store FTGlyphs sequentially rather than by glyph index. This should save a heap of memory and a bit of time at startup. * Changed the Mac font paths in the demos. * Changed the unit tests for new hinter in Freetype 2.1.4. * Added a test for broken contour tags. ---------------------------------------------------------------------- --- 2003-04-12 Release 2.04 --- ---------------------------------------------------------------------- * Fixed resize behavior in FTGLTextureFont. ---------------------------------------------------------------------- --- 2003-04-09 Release 2.03 --- ---------------------------------------------------------------------- * Fix in FTContour to handle broken contours. ---------------------------------------------------------------------- --- 2003-04-03 Release 2.02 --- ---------------------------------------------------------------------- * Fixed memory leaks ---------------------------------------------------------------------- --- 2003-03-14 Release 2.01 --- ---------------------------------------------------------------------- * Minor changes to autoconf to detect glu ---------------------------------------------------------------------- --- 2003-03-11 Release 2.0 --- ---------------------------------------------------------------------- * Fixed some alignment bugs caused by changes to Freetype ( > 2.0.9). * Minor fixes to float declarations. * Moved FTBBox and FTPoint to their own files and added Move() and operator += to FTBBox * Replaced FT_Vector with FTPoint for kerning. * Fixed the glPushAttrib calls. * Changed gluTess callback def. * Rewriting FTGLDemo. * Minor fixes for irix. * Removed a bunch of redundant members and made them function locals. * Removed the Open() & Close() functions from FTFont because there was no way to handle Close correctly which makes Open redundant. * Removed Open() from FTface. * Improved the robustness of some of the error handling. * Removed the FTCharmap Platform/Encoding function. * Added unit tests. * Removed the precache flag. * Unvirtualised functions in FTLibrary and FTGlyphContainer. * Fixed empty string bug in FTFont::BBox. * Refactored FTContour and moved it to it's own file. * Removed unnecessary memory allocations in vector Glyphs. They now access the vector data directly. * Made vectoriser a local variable in vector glyphs. * Fixed a long standing visual bug in FTVectoriser. * Changed size calculations to use floats instead of ints. This includes FTBBox. * Refactored FTGlyph. Now calculates advance (as a float) and bbox. * Changed contourList from FTVector to an array in FTVectoriser. * Made function and member names more consistant. * Moved header files to include directory. * Mesh now uses a list for glCombine points. * Delete the display lists. * Unix AutoConf support. * Attach 'files' from memory. ---------------------------------------------------------------------- --- 2002-10-23 Release 1.4 --- ---------------------------------------------------------------------- * FTGL now requires 2.0.9 or later. See below for reason. * Merged 1.32 branch with main tree * Glyph loading has been optimised for pixel based glyphs. * Removed mmgr * Added FTFont::Attach * Updated API docs * Removed stl map and vector. Replaced by code supplied by Sebastien Barre * Removed work around for Type1 height and width bug in freetype. It seems to be fixed in 2.0.9 * Added a test target to the Mac OSX project * Inline some private functions. ---------------------------------------------------------------------- --- 2002-04-23 Release 1.32 --- ---------------------------------------------------------------------- * Fixed enable state attribute in FTGLBitmapFont * Wrapped tb.h & trackball.h in EXTERN "C" * Renamed FTGLDemo to .cpp Ellers... * New MSVC projects updated to v1.3 * Removed a lot of unnecessary Windows stuff from ftgl.h * Added functions to load font from memory. * Fixed a couple of Windows 'for' scope problems in FTExtrdGlyph * FTGLDemo. Added #define for windows font ---------------------------------------------------------------------- --- 2002-01-30 Release 1.31 --- ---------------------------------------------------------------------- * Forgot to update readme etc for 1.3 ---------------------------------------------------------------------- --- 2002-01-27 Release 1.3b5 --- ---------------------------------------------------------------------- * FTBbox now uses float rather then int * Fixed some more warnings (size_t) * Removed the contour winding function because it didn't fix the problem!! * Fixed up some state settings in fonts. ---------------------------------------------------------------------- --- 2001-12-11 Release 1.3b4 --- ---------------------------------------------------------------------- * Added MAC OSX project (Project Builder) * Added a function for extruded glyphs that calculates the winding order of the glyph contour. * Added FTGL_DEBUG to include memory debugger. * Added a couple of typedefs to FTGL.h, mainly to aid debugging * Cleaned up the includes. ---------------------------------------------------------------------- --- 2001-11-13 Release 1.3b3 --- ---------------------------------------------------------------------- * Texture fonts now behave the same as the others and can be loaded on demand. This made FTGLTextureFont MUCH simpler!!!! It has also improved the grid fitting so less texture mem is needed. * Refactored FTVectoriser... This now builds contours and meshes internally and then passes the raw point data onto the glyphs. The gluTess data is captured in an internal non static data structure fixing a memory Leak in PolyGlyph (glCombine). This has enabled... * Extruded fonts. FTGLExtrdFont & FTExtrdGlyph. * Reversed the winding for polyglyphs, extruded glyphs and texture glyphs to make them CCW * Bounding box function * Fixed the != and == operators in ftPoint * Un-virtualised some functions in FTFont * Added a demo app to dist. ---------------------------------------------------------------------- --- 2001-11-09 Release 1.21 --- ---------------------------------------------------------------------- * Visual Studio projects updated for .cpp source file extensions. * A couple of windows 'cast' warnings have been fixed. ---------------------------------------------------------------------- --- 2001-11-06 Release 1.2 --- ---------------------------------------------------------------------- * Glyphs can now be loaded on the fly instead of being pre-cached. If FTFont::Open() is called with false, FTGlyphContainer will build a list of null pointers. Then when ever a glyph needs to be access eg by FTFont::advance or FTFont::render, it will be built and slotted into the glyphlist in the correct position. * Removed glext.h from FTGL.h and replaced it with a test for GL_EXT_texture_object. * Added padding to texture size calculations. * Fixed a NASTY bug in FTGLTextureFont. Only came to light after changes to the glyph preprocessing. ---------------------------------------------------------------------- --- 2001-10-31 Release 1.1 --- ---------------------------------------------------------------------- * Renamed the source to .cpp * Removed the static activeTextureID from FTTextureGlyph and replaced it with a call to glGetIntegerv( GL_TEXTURE_2D_BINDING_EXT, &activeTextureID); * Added an include for glext.h in FTGL.h * Tidied up the glbegin/glEnd pairs in FTTextureGlyph & FTGLTextureFont * Fixed the problem with doc filenames. * Tidied up some implicit type conversions. * Fixed FTCharMap to ensure that a valid default charmap is always created by the c_stor. ---------------------------------------------------------------------- --- 2001-10-26 Release 1.01 --- ---------------------------------------------------------------------- * Removed the glEnable( GL_TEXTURE_2D) from FTGLTextureFont * Removed the redundant tempGlyph members in the FTGLXXXXFont classes * Made a change in FTGL.h to include correct headers for MAC OSX * FTGL.h now includes glu.h * Minor fixes to get rid of Project Builder warnings (MAC OSX) * Fixed some of the docs ---------------------------------------------------------------------- --- 2001-10-24 Release 1.0 --- ---------------------------------------------------------------------- * Version 1.0 release ---------------------------------------------------------------------- --- 2001-09-29 Release 1.0b7 --- ---------------------------------------------------------------------- * Tesselation winding rules * Fixed bug in FTContour Add point function * Cleaned up disposal of FTCharmap in FTFace * renamed FTVectorGlyph to FTOutlineGlyph * New distribution structure * Minor changes for windows (VC 6) * Windows and Linux ports. ---------------------------------------------------------------------- --- 2001-09-20 Release 1.0b6 --- ---------------------------------------------------------------------- * Implemented the new FTCharmap class. The performance improvement is dramatic. * Tidied up the way the freetype FT_Face object is disposed of by FTFont and FTFace. This was a potential crash. * FTVectorGlyph and FTPolyGlyph now disposes of the freetype glyph correctly after initialsation. This was a potential crash. * Preliminary support for unicode...wchar_t Tested with non european fonts. * Added function to calc the advance width of a string. * Minor tidy ups. ---------------------------------------------------------------------- --- 2001-08-29 Release 1.0b5 --- ---------------------------------------------------------------------- * Settled on integers for FTSize stuff. NOTE the FTGlyph stuff is still up in the air. * Fixed the positional stuff. * Added Java Doc comments. NOT COMPLETE * Fixes for linux, mainly to clear warnings. * changed the return type for FTFace::Glyph() from a reference to a pointer so it can return NULL on failure. * Related to above...better error handling and reporting in FTGLXXXFont::MakeGlyphList() * Fixed a bug in FTVectoriser that was ignoring non printing characters. This meant that the pen wasn't advanced for spaces etc. It affected polygon and outline font rendering. * Minor tidy ups. ---------------------------------------------------------------------- --- 2001-08-21 Release 1.0b4 --- ---------------------------------------------------------------------- * Changed the mode for FT_Load_Glyph to FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP for outline and polygon fonts & FT_LOAD_NO_HINTING for texture fonts. Seems to produce better looking glyphs. * FTGLTextureFont can now use multiple textures to render glyphs if they don't fit within one GL_MAX_TEXTURE_SIZE texture. * Changed FTSize to use bbox for global width and height. Needs more work (eg float or int?) and need to check inconsistancies in freetype. * Being more strict with types eg integer indices and sizes are now unsigned. ---------------------------------------------------------------------- --- 2001-08-08 Release 1.0b3 --- ---------------------------------------------------------------------- * I've made fundamental change to the way the glyphlist is built. This is to get round the problems I was having with charmaps. At this stage it is a temporary solution. Previously the glyphList was indexed by char code. Now it's indexed by glyph index and the conversion is done by the freetype function FT_Get_Char_Index(). If this proves to be too slow I'll make my own charmap and use it to index into the glyphlist. This has fixed all the charmap related problems/bugs. * Enabled alpha blend in Pixmap font. * Enabled LINE_SMOOTH in Outline font * Fixed bug that prevented the display of chars >127 * Moved pixel store stuff out of BitmapGlyph into BitmapFont. * Minor changes for IRIX (compiles but isn't tested) * Pixmap fonts can now be in colour. It uses the current colour when the font is CREATED. This isn't ideal but is better than the alternatives. * Tidied up the error handling. * Minor code clean ups. ---------------------------------------------------------------------- --- 2001-08-06 BETA Release 1.0b2 --- ---------------------------------------------------------------------- * Minor tidy ups for first public release. ---------------------------------------------------------------------- --- 2001-08-03 First BETA Release 1.0b1 --- ---------------------------------------------------------------------- * All font types are now working, Bitmaps, Pixmaps, Texture, Outline and Polygons. Quality of output and performance varies wildly. :) ---------------------------------------------------------------------- --- 2001-07-22 First ALPHA Release 1.0a1 --- ---------------------------------------------------------------------- * And so it begins. connectome-workbench-1.4.2/src/FtglFont/README000066400000000000000000000016551360521144700210340ustar00rootroot00000000000000FTGL 2.1 5 December 2004 DESCRIPTION: FTGL is a free open source library to enable developers to use arbitrary fonts in their OpenGL (www.opengl.org) applications. Unlike other OpenGL font libraries FTGL uses standard font file formats so doesn't need a preprocessing step to convert the high quality font data into a lesser quality, proprietary format. FTGL uses the Freetype (www.freetype.org) font library to open and 'decode' the fonts. It then takes that output and stores it in a format most efficient for OpenGL rendering. Rendering modes supported are: - Bit maps - Antialiased Pix maps - Outlines - Polygon meshes - Extruded polygon meshes - Texture maps - Buffer maps USAGE: FTGLPixmapFont font("Arial.ttf"); font.FaceSize(72); font.Render("Hello World!"); CONTACT: Please contact us if you have any suggestions, feature requests, or problems. Sam Hocevar Christopher Sean Morrison connectome-workbench-1.4.2/src/FtglFont/README_WORKBENCH.txt000066400000000000000000000015701360521144700232500ustar00rootroot00000000000000 How FtglFont was created. * Download and uncompress an FTGL library. * Copy the source only: cp -r /src ./FtglFont * cd FtglFont * Create the CMakeLists.txt file. ** find . -name '*.h' -print ** find . -name '*.cpp' -print ** Add .h and .cpp files to ADD_LIBRARY ** Add all subdirectories to INCLUDE_DIRECTORIES ** Need 'ft2build.h' from FreeType it is in /Developer/SDKs/MacOSX10.7.sdk/usr/X11/include on mac ** Change the include for "config.h" to "FtglConfig.h" so that it does not conflict with other "config.h" files ** Create the FtglConfig.h file by "cp /config.h.in ./FtglConfig.h" ** Add FtglConfig.h to CMakeLists.txt ** Edit FtglConfig.h and define these items: *** HAVE_INTTYPES_H *** HAVE_MEMORY_H *** HAVE_STDINT_H *** HAVE_STDLIB_H *** HAVE_STRINGS_H *** HAVE_STRING_H *** HAVE_STRNDUP *** HAVE_SYS_TYPES_H *** STDC_HEADERS *** X_DISPLAY_MISSING connectome-workbench-1.4.2/src/GLMath/000077500000000000000000000000001360521144700175365ustar00rootroot00000000000000connectome-workbench-1.4.2/src/GLMath/VersionNote.txt000066400000000000000000000002761360521144700225570ustar00rootroot00000000000000Version is 0.9.9.6 From the download, only need the 'glm' directory and the 'copying.txt' (license file). Docs, Utils, and other stuff not needed. https://glm.g-truc.net/0.9.9/index.html connectome-workbench-1.4.2/src/GLMath/glm/000077500000000000000000000000001360521144700203155ustar00rootroot00000000000000connectome-workbench-1.4.2/src/GLMath/glm/CMakeLists.txt000066400000000000000000000047401360521144700230620ustar00rootroot00000000000000file(GLOB ROOT_SOURCE *.cpp) file(GLOB ROOT_INLINE *.inl) file(GLOB ROOT_HEADER *.hpp) file(GLOB ROOT_TEXT ../*.txt) file(GLOB ROOT_MD ../*.md) file(GLOB ROOT_NAT ../util/glm.natvis) file(GLOB_RECURSE CORE_SOURCE ./detail/*.cpp) file(GLOB_RECURSE CORE_INLINE ./detail/*.inl) file(GLOB_RECURSE CORE_HEADER ./detail/*.hpp) file(GLOB_RECURSE EXT_SOURCE ./ext/*.cpp) file(GLOB_RECURSE EXT_INLINE ./ext/*.inl) file(GLOB_RECURSE EXT_HEADER ./ext/*.hpp) file(GLOB_RECURSE GTC_SOURCE ./gtc/*.cpp) file(GLOB_RECURSE GTC_INLINE ./gtc/*.inl) file(GLOB_RECURSE GTC_HEADER ./gtc/*.hpp) file(GLOB_RECURSE GTX_SOURCE ./gtx/*.cpp) file(GLOB_RECURSE GTX_INLINE ./gtx/*.inl) file(GLOB_RECURSE GTX_HEADER ./gtx/*.hpp) file(GLOB_RECURSE SIMD_SOURCE ./simd/*.cpp) file(GLOB_RECURSE SIMD_INLINE ./simd/*.inl) file(GLOB_RECURSE SIMD_HEADER ./simd/*.h) source_group("Text Files" FILES ${ROOT_TEXT} ${ROOT_MD}) source_group("Core Files" FILES ${CORE_SOURCE}) source_group("Core Files" FILES ${CORE_INLINE}) source_group("Core Files" FILES ${CORE_HEADER}) source_group("EXT Files" FILES ${EXT_SOURCE}) source_group("EXT Files" FILES ${EXT_INLINE}) source_group("EXT Files" FILES ${EXT_HEADER}) source_group("GTC Files" FILES ${GTC_SOURCE}) source_group("GTC Files" FILES ${GTC_INLINE}) source_group("GTC Files" FILES ${GTC_HEADER}) source_group("GTX Files" FILES ${GTX_SOURCE}) source_group("GTX Files" FILES ${GTX_INLINE}) source_group("GTX Files" FILES ${GTX_HEADER}) source_group("SIMD Files" FILES ${SIMD_SOURCE}) source_group("SIMD Files" FILES ${SIMD_INLINE}) source_group("SIMD Files" FILES ${SIMD_HEADER}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) if(BUILD_STATIC_LIBS) add_library(glm_static STATIC ${ROOT_TEXT} ${ROOT_MD} ${ROOT_NAT} ${ROOT_SOURCE} ${ROOT_INLINE} ${ROOT_HEADER} ${CORE_SOURCE} ${CORE_INLINE} ${CORE_HEADER} ${EXT_SOURCE} ${EXT_INLINE} ${EXT_HEADER} ${GTC_SOURCE} ${GTC_INLINE} ${GTC_HEADER} ${GTX_SOURCE} ${GTX_INLINE} ${GTX_HEADER} ${SIMD_SOURCE} ${SIMD_INLINE} ${SIMD_HEADER}) endif() if(BUILD_SHARED_LIBS) add_library(glm_shared SHARED ${ROOT_TEXT} ${ROOT_MD} ${ROOT_NAT} ${ROOT_SOURCE} ${ROOT_INLINE} ${ROOT_HEADER} ${CORE_SOURCE} ${CORE_INLINE} ${CORE_HEADER} ${EXT_SOURCE} ${EXT_INLINE} ${EXT_HEADER} ${GTC_SOURCE} ${GTC_INLINE} ${GTC_HEADER} ${GTX_SOURCE} ${GTX_INLINE} ${GTX_HEADER} ${SIMD_SOURCE} ${SIMD_INLINE} ${SIMD_HEADER}) endif() connectome-workbench-1.4.2/src/GLMath/glm/common.hpp000066400000000000000000000667751360521144700223430ustar00rootroot00000000000000/// @ref core /// @file glm/common.hpp /// /// @see GLSL 4.20.8 specification, section 8.3 Common Functions /// /// @defgroup core_func_common Common functions /// @ingroup core /// /// Provides GLSL common functions /// /// These all operate component-wise. The description is per component. /// /// Include to use these core features. #pragma once #include "detail/qualifier.hpp" #include "detail/_fixes.hpp" namespace glm { /// @addtogroup core_func_common /// @{ /// Returns x if x >= 0; otherwise, it returns -x. /// /// @tparam genType floating-point or signed integer; scalar or vector types. /// /// @see GLSL abs man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL GLM_CONSTEXPR genType abs(genType x); /// Returns x if x >= 0; otherwise, it returns -x. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or signed integer scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL abs man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL GLM_CONSTEXPR vec abs(vec const& x); /// Returns 1.0 if x > 0, 0.0 if x == 0, or -1.0 if x < 0. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL sign man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL vec sign(vec const& x); /// Returns a value equal to the nearest integer that is less then or equal to x. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL floor man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL vec floor(vec const& x); /// Returns a value equal to the nearest integer to x /// whose absolute value is not larger than the absolute value of x. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL trunc man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL vec trunc(vec const& x); /// Returns a value equal to the nearest integer to x. /// The fraction 0.5 will round in a direction chosen by the /// implementation, presumably the direction that is fastest. /// This includes the possibility that round(x) returns the /// same value as roundEven(x) for all values of x. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL round man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL vec round(vec const& x); /// Returns a value equal to the nearest integer to x. /// A fractional part of 0.5 will round toward the nearest even /// integer. (Both 3.5 and 4.5 for x will return 4.0.) /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL roundEven man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions /// @see New round to even technique template GLM_FUNC_DECL vec roundEven(vec const& x); /// Returns a value equal to the nearest integer /// that is greater than or equal to x. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL ceil man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL vec ceil(vec const& x); /// Return x - floor(x). /// /// @tparam genType Floating-point scalar or vector types. /// /// @see GLSL fract man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL genType fract(genType x); /// Return x - floor(x). /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL fract man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL vec fract(vec const& x); template GLM_FUNC_DECL genType mod(genType x, genType y); template GLM_FUNC_DECL vec mod(vec const& x, T y); /// Modulus. Returns x - y * floor(x / y) /// for each component in x using the floating point value y. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types, include glm/gtc/integer for integer scalar types support /// @tparam Q Value from qualifier enum /// /// @see GLSL mod man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL vec mod(vec const& x, vec const& y); /// Returns the fractional part of x and sets i to the integer /// part (as a whole number floating point value). Both the /// return value and the output parameter will have the same /// sign as x. /// /// @tparam genType Floating-point scalar or vector types. /// /// @see GLSL modf man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL genType modf(genType x, genType& i); /// Returns y if y < x; otherwise, it returns x. /// /// @tparam genType Floating-point or integer; scalar or vector types. /// /// @see GLSL min man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL GLM_CONSTEXPR genType min(genType x, genType y); /// Returns y if y < x; otherwise, it returns x. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL min man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL GLM_CONSTEXPR vec min(vec const& x, T y); /// Returns y if y < x; otherwise, it returns x. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL min man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL GLM_CONSTEXPR vec min(vec const& x, vec const& y); /// Returns y if x < y; otherwise, it returns x. /// /// @tparam genType Floating-point or integer; scalar or vector types. /// /// @see GLSL max man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL GLM_CONSTEXPR genType max(genType x, genType y); /// Returns y if x < y; otherwise, it returns x. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL max man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL GLM_CONSTEXPR vec max(vec const& x, T y); /// Returns y if x < y; otherwise, it returns x. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL max man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL GLM_CONSTEXPR vec max(vec const& x, vec const& y); /// Returns min(max(x, minVal), maxVal) for each component in x /// using the floating-point values minVal and maxVal. /// /// @tparam genType Floating-point or integer; scalar or vector types. /// /// @see GLSL clamp man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL GLM_CONSTEXPR genType clamp(genType x, genType minVal, genType maxVal); /// Returns min(max(x, minVal), maxVal) for each component in x /// using the floating-point values minVal and maxVal. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL clamp man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL GLM_CONSTEXPR vec clamp(vec const& x, T minVal, T maxVal); /// Returns min(max(x, minVal), maxVal) for each component in x /// using the floating-point values minVal and maxVal. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL clamp man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL GLM_CONSTEXPR vec clamp(vec const& x, vec const& minVal, vec const& maxVal); /// If genTypeU is a floating scalar or vector: /// Returns x * (1.0 - a) + y * a, i.e., the linear blend of /// x and y using the floating-point value a. /// The value for a is not restricted to the range [0, 1]. /// /// If genTypeU is a boolean scalar or vector: /// Selects which vector each returned component comes /// from. For a component of 'a' that is false, the /// corresponding component of 'x' is returned. For a /// component of 'a' that is true, the corresponding /// component of 'y' is returned. Components of 'x' and 'y' that /// are not selected are allowed to be invalid floating point /// values and will have no effect on the results. Thus, this /// provides different functionality than /// genType mix(genType x, genType y, genType(a)) /// where a is a Boolean vector. /// /// @see GLSL mix man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions /// /// @param[in] x Value to interpolate. /// @param[in] y Value to interpolate. /// @param[in] a Interpolant. /// /// @tparam genTypeT Floating point scalar or vector. /// @tparam genTypeU Floating point or boolean scalar or vector. It can't be a vector if it is the length of genTypeT. /// /// @code /// #include /// ... /// float a; /// bool b; /// glm::dvec3 e; /// glm::dvec3 f; /// glm::vec4 g; /// glm::vec4 h; /// ... /// glm::vec4 r = glm::mix(g, h, a); // Interpolate with a floating-point scalar two vectors. /// glm::vec4 s = glm::mix(g, h, b); // Returns g or h; /// glm::dvec3 t = glm::mix(e, f, a); // Types of the third parameter is not required to match with the first and the second. /// glm::vec4 u = glm::mix(g, h, r); // Interpolations can be perform per component with a vector for the last parameter. /// @endcode template GLM_FUNC_DECL genTypeT mix(genTypeT x, genTypeT y, genTypeU a); template GLM_FUNC_DECL vec mix(vec const& x, vec const& y, vec const& a); template GLM_FUNC_DECL vec mix(vec const& x, vec const& y, U a); /// Returns 0.0 if x < edge, otherwise it returns 1.0 for each component of a genType. /// /// @see GLSL step man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL genType step(genType edge, genType x); /// Returns 0.0 if x < edge, otherwise it returns 1.0. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL step man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL vec step(T edge, vec const& x); /// Returns 0.0 if x < edge, otherwise it returns 1.0. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL step man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL vec step(vec const& edge, vec const& x); /// Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and /// performs smooth Hermite interpolation between 0 and 1 /// when edge0 < x < edge1. This is useful in cases where /// you would want a threshold function with a smooth /// transition. This is equivalent to: /// genType t; /// t = clamp ((x - edge0) / (edge1 - edge0), 0, 1); /// return t * t * (3 - 2 * t); /// Results are undefined if edge0 >= edge1. /// /// @tparam genType Floating-point scalar or vector types. /// /// @see GLSL smoothstep man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL genType smoothstep(genType edge0, genType edge1, genType x); template GLM_FUNC_DECL vec smoothstep(T edge0, T edge1, vec const& x); template GLM_FUNC_DECL vec smoothstep(vec const& edge0, vec const& edge1, vec const& x); /// Returns true if x holds a NaN (not a number) /// representation in the underlying implementation's set of /// floating point representations. Returns false otherwise, /// including for implementations with no NaN /// representations. /// /// /!\ When using compiler fast math, this function may fail. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL isnan man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL vec isnan(vec const& x); /// Returns true if x holds a positive infinity or negative /// infinity representation in the underlying implementation's /// set of floating point representations. Returns false /// otherwise, including for implementations with no infinity /// representations. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL isinf man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL vec isinf(vec const& x); /// Returns a signed integer value representing /// the encoding of a floating-point value. The floating-point /// value's bit-level representation is preserved. /// /// @see GLSL floatBitsToInt man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions GLM_FUNC_DECL int floatBitsToInt(float const& v); /// Returns a signed integer value representing /// the encoding of a floating-point value. The floatingpoint /// value's bit-level representation is preserved. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam Q Value from qualifier enum /// /// @see GLSL floatBitsToInt man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL vec floatBitsToInt(vec const& v); /// Returns a unsigned integer value representing /// the encoding of a floating-point value. The floatingpoint /// value's bit-level representation is preserved. /// /// @see GLSL floatBitsToUint man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions GLM_FUNC_DECL uint floatBitsToUint(float const& v); /// Returns a unsigned integer value representing /// the encoding of a floating-point value. The floatingpoint /// value's bit-level representation is preserved. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam Q Value from qualifier enum /// /// @see GLSL floatBitsToUint man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL vec floatBitsToUint(vec const& v); /// Returns a floating-point value corresponding to a signed /// integer encoding of a floating-point value. /// If an inf or NaN is passed in, it will not signal, and the /// resulting floating point value is unspecified. Otherwise, /// the bit-level representation is preserved. /// /// @see GLSL intBitsToFloat man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions GLM_FUNC_DECL float intBitsToFloat(int const& v); /// Returns a floating-point value corresponding to a signed /// integer encoding of a floating-point value. /// If an inf or NaN is passed in, it will not signal, and the /// resulting floating point value is unspecified. Otherwise, /// the bit-level representation is preserved. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam Q Value from qualifier enum /// /// @see GLSL intBitsToFloat man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL vec intBitsToFloat(vec const& v); /// Returns a floating-point value corresponding to a /// unsigned integer encoding of a floating-point value. /// If an inf or NaN is passed in, it will not signal, and the /// resulting floating point value is unspecified. Otherwise, /// the bit-level representation is preserved. /// /// @see GLSL uintBitsToFloat man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions GLM_FUNC_DECL float uintBitsToFloat(uint const& v); /// Returns a floating-point value corresponding to a /// unsigned integer encoding of a floating-point value. /// If an inf or NaN is passed in, it will not signal, and the /// resulting floating point value is unspecified. Otherwise, /// the bit-level representation is preserved. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam Q Value from qualifier enum /// /// @see GLSL uintBitsToFloat man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL vec uintBitsToFloat(vec const& v); /// Computes and returns a * b + c. /// /// @tparam genType Floating-point scalar or vector types. /// /// @see GLSL fma man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL genType fma(genType const& a, genType const& b, genType const& c); /// Splits x into a floating-point significand in the range /// [0.5, 1.0) and an integral exponent of two, such that: /// x = significand * exp(2, exponent) /// /// The significand is returned by the function and the /// exponent is returned in the parameter exp. For a /// floating-point value of zero, the significant and exponent /// are both zero. For a floating-point value that is an /// infinity or is not a number, the results are undefined. /// /// @tparam genType Floating-point scalar or vector types. /// /// @see GLSL frexp man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL genType frexp(genType x, int& exp); template GLM_FUNC_DECL vec frexp(vec const& v, vec& exp); /// Builds a floating-point number from x and the /// corresponding integral exponent of two in exp, returning: /// significand * exp(2, exponent) /// /// If this product is too large to be represented in the /// floating-point type, the result is undefined. /// /// @tparam genType Floating-point scalar or vector types. /// /// @see GLSL ldexp man page; /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL genType ldexp(genType const& x, int const& exp); template GLM_FUNC_DECL vec ldexp(vec const& v, vec const& exp); /// @} }//namespace glm #include "detail/func_common.inl" connectome-workbench-1.4.2/src/GLMath/glm/copying.txt000066400000000000000000000055621360521144700225360ustar00rootroot00000000000000================================================================================ OpenGL Mathematics (GLM) -------------------------------------------------------------------------------- GLM is licensed under The Happy Bunny License and MIT License ================================================================================ The Happy Bunny License (Modified MIT License) -------------------------------------------------------------------------------- Copyright (c) 2005 - 2014 G-Truc Creation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Restrictions: By making use of the Software for military purposes, you choose to make a Bunny unhappy. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================================================ The MIT License -------------------------------------------------------------------------------- Copyright (c) 2005 - 2014 G-Truc Creation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. connectome-workbench-1.4.2/src/GLMath/glm/detail/000077500000000000000000000000001360521144700215575ustar00rootroot00000000000000connectome-workbench-1.4.2/src/GLMath/glm/detail/_features.hpp000066400000000000000000000267721360521144700242630ustar00rootroot00000000000000#pragma once // #define GLM_CXX98_EXCEPTIONS // #define GLM_CXX98_RTTI // #define GLM_CXX11_RVALUE_REFERENCES // Rvalue references - GCC 4.3 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html // GLM_CXX11_TRAILING_RETURN // Rvalue references for *this - GCC not supported // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2439.htm // GLM_CXX11_NONSTATIC_MEMBER_INIT // Initialization of class objects by rvalues - GCC any // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1610.html // GLM_CXX11_NONSTATIC_MEMBER_INIT // Non-static data member initializers - GCC 4.7 // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2756.htm // #define GLM_CXX11_VARIADIC_TEMPLATE // Variadic templates - GCC 4.3 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdf // // Extending variadic template template parameters - GCC 4.4 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf // #define GLM_CXX11_GENERALIZED_INITIALIZERS // Initializer lists - GCC 4.4 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2672.htm // #define GLM_CXX11_STATIC_ASSERT // Static assertions - GCC 4.3 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html // #define GLM_CXX11_AUTO_TYPE // auto-typed variables - GCC 4.4 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1984.pdf // #define GLM_CXX11_AUTO_TYPE // Multi-declarator auto - GCC 4.4 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1737.pdf // #define GLM_CXX11_AUTO_TYPE // Removal of auto as a storage-class specifier - GCC 4.4 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2546.htm // #define GLM_CXX11_AUTO_TYPE // New function declarator syntax - GCC 4.4 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm // #define GLM_CXX11_LAMBDAS // New wording for C++0x lambdas - GCC 4.5 // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2927.pdf // #define GLM_CXX11_DECLTYPE // Declared type of an expression - GCC 4.3 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2343.pdf // // Right angle brackets - GCC 4.3 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1757.html // // Default template arguments for function templates DR226 GCC 4.3 // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#226 // // Solving the SFINAE problem for expressions DR339 GCC 4.4 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2634.html // #define GLM_CXX11_ALIAS_TEMPLATE // Template aliases N2258 GCC 4.7 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf // // Extern templates N1987 Yes // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1987.htm // #define GLM_CXX11_NULLPTR // Null pointer constant N2431 GCC 4.6 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf // #define GLM_CXX11_STRONG_ENUMS // Strongly-typed enums N2347 GCC 4.4 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf // // Forward declarations for enums N2764 GCC 4.6 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2764.pdf // // Generalized attributes N2761 GCC 4.8 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2761.pdf // // Generalized constant expressions N2235 GCC 4.6 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf // // Alignment support N2341 GCC 4.8 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf // #define GLM_CXX11_DELEGATING_CONSTRUCTORS // Delegating constructors N1986 GCC 4.7 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1986.pdf // // Inheriting constructors N2540 GCC 4.8 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2540.htm // #define GLM_CXX11_EXPLICIT_CONVERSIONS // Explicit conversion operators N2437 GCC 4.5 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf // // New character types N2249 GCC 4.4 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2249.html // // Unicode string literals N2442 GCC 4.5 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm // // Raw string literals N2442 GCC 4.5 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm // // Universal character name literals N2170 GCC 4.5 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2170.html // #define GLM_CXX11_USER_LITERALS // User-defined literals N2765 GCC 4.7 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2765.pdf // // Standard Layout Types N2342 GCC 4.5 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2342.htm // #define GLM_CXX11_DEFAULTED_FUNCTIONS // #define GLM_CXX11_DELETED_FUNCTIONS // Defaulted and deleted functions N2346 GCC 4.4 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm // // Extended friend declarations N1791 GCC 4.7 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1791.pdf // // Extending sizeof N2253 GCC 4.4 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2253.html // #define GLM_CXX11_INLINE_NAMESPACES // Inline namespaces N2535 GCC 4.4 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2535.htm // #define GLM_CXX11_UNRESTRICTED_UNIONS // Unrestricted unions N2544 GCC 4.6 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf // #define GLM_CXX11_LOCAL_TYPE_TEMPLATE_ARGS // Local and unnamed types as template arguments N2657 GCC 4.5 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm // #define GLM_CXX11_RANGE_FOR // Range-based for N2930 GCC 4.6 // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2930.html // #define GLM_CXX11_OVERRIDE_CONTROL // Explicit virtual overrides N2928 N3206 N3272 GCC 4.7 // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2928.htm // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3206.htm // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3272.htm // // Minimal support for garbage collection and reachability-based leak detection N2670 No // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2670.htm // #define GLM_CXX11_NOEXCEPT // Allowing move constructors to throw [noexcept] N3050 GCC 4.6 (core language only) // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3050.html // // Defining move special member functions N3053 GCC 4.6 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3053.html // // Sequence points N2239 Yes // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html // // Atomic operations N2427 GCC 4.4 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html // // Strong Compare and Exchange N2748 GCC 4.5 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2427.html // // Bidirectional Fences N2752 GCC 4.8 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2752.htm // // Memory model N2429 GCC 4.8 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2429.htm // // Data-dependency ordering: atomics and memory model N2664 GCC 4.4 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2664.htm // // Propagating exceptions N2179 GCC 4.4 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2179.html // // Abandoning a process and at_quick_exit N2440 GCC 4.8 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2440.htm // // Allow atomics use in signal handlers N2547 Yes // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2547.htm // // Thread-local storage N2659 GCC 4.8 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2659.htm // // Dynamic initialization and destruction with concurrency N2660 GCC 4.3 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm // // __func__ predefined identifier N2340 GCC 4.3 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2340.htm // // C99 preprocessor N1653 GCC 4.3 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1653.htm // // long long N1811 GCC 4.3 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1811.pdf // // Extended integral types N1988 Yes // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1988.pdf #if(GLM_COMPILER & GLM_COMPILER_GCC) # define GLM_CXX11_STATIC_ASSERT #elif(GLM_COMPILER & GLM_COMPILER_CLANG) # if(__has_feature(cxx_exceptions)) # define GLM_CXX98_EXCEPTIONS # endif # if(__has_feature(cxx_rtti)) # define GLM_CXX98_RTTI # endif # if(__has_feature(cxx_access_control_sfinae)) # define GLM_CXX11_ACCESS_CONTROL_SFINAE # endif # if(__has_feature(cxx_alias_templates)) # define GLM_CXX11_ALIAS_TEMPLATE # endif # if(__has_feature(cxx_alignas)) # define GLM_CXX11_ALIGNAS # endif # if(__has_feature(cxx_attributes)) # define GLM_CXX11_ATTRIBUTES # endif # if(__has_feature(cxx_constexpr)) # define GLM_CXX11_CONSTEXPR # endif # if(__has_feature(cxx_decltype)) # define GLM_CXX11_DECLTYPE # endif # if(__has_feature(cxx_default_function_template_args)) # define GLM_CXX11_DEFAULT_FUNCTION_TEMPLATE_ARGS # endif # if(__has_feature(cxx_defaulted_functions)) # define GLM_CXX11_DEFAULTED_FUNCTIONS # endif # if(__has_feature(cxx_delegating_constructors)) # define GLM_CXX11_DELEGATING_CONSTRUCTORS # endif # if(__has_feature(cxx_deleted_functions)) # define GLM_CXX11_DELETED_FUNCTIONS # endif # if(__has_feature(cxx_explicit_conversions)) # define GLM_CXX11_EXPLICIT_CONVERSIONS # endif # if(__has_feature(cxx_generalized_initializers)) # define GLM_CXX11_GENERALIZED_INITIALIZERS # endif # if(__has_feature(cxx_implicit_moves)) # define GLM_CXX11_IMPLICIT_MOVES # endif # if(__has_feature(cxx_inheriting_constructors)) # define GLM_CXX11_INHERITING_CONSTRUCTORS # endif # if(__has_feature(cxx_inline_namespaces)) # define GLM_CXX11_INLINE_NAMESPACES # endif # if(__has_feature(cxx_lambdas)) # define GLM_CXX11_LAMBDAS # endif # if(__has_feature(cxx_local_type_template_args)) # define GLM_CXX11_LOCAL_TYPE_TEMPLATE_ARGS # endif # if(__has_feature(cxx_noexcept)) # define GLM_CXX11_NOEXCEPT # endif # if(__has_feature(cxx_nonstatic_member_init)) # define GLM_CXX11_NONSTATIC_MEMBER_INIT # endif # if(__has_feature(cxx_nullptr)) # define GLM_CXX11_NULLPTR # endif # if(__has_feature(cxx_override_control)) # define GLM_CXX11_OVERRIDE_CONTROL # endif # if(__has_feature(cxx_reference_qualified_functions)) # define GLM_CXX11_REFERENCE_QUALIFIED_FUNCTIONS # endif # if(__has_feature(cxx_range_for)) # define GLM_CXX11_RANGE_FOR # endif # if(__has_feature(cxx_raw_string_literals)) # define GLM_CXX11_RAW_STRING_LITERALS # endif # if(__has_feature(cxx_rvalue_references)) # define GLM_CXX11_RVALUE_REFERENCES # endif # if(__has_feature(cxx_static_assert)) # define GLM_CXX11_STATIC_ASSERT # endif # if(__has_feature(cxx_auto_type)) # define GLM_CXX11_AUTO_TYPE # endif # if(__has_feature(cxx_strong_enums)) # define GLM_CXX11_STRONG_ENUMS # endif # if(__has_feature(cxx_trailing_return)) # define GLM_CXX11_TRAILING_RETURN # endif # if(__has_feature(cxx_unicode_literals)) # define GLM_CXX11_UNICODE_LITERALS # endif # if(__has_feature(cxx_unrestricted_unions)) # define GLM_CXX11_UNRESTRICTED_UNIONS # endif # if(__has_feature(cxx_user_literals)) # define GLM_CXX11_USER_LITERALS # endif # if(__has_feature(cxx_variadic_templates)) # define GLM_CXX11_VARIADIC_TEMPLATES # endif #endif//(GLM_COMPILER & GLM_COMPILER_CLANG) connectome-workbench-1.4.2/src/GLMath/glm/detail/_fixes.hpp000066400000000000000000000006271360521144700235520ustar00rootroot00000000000000#include //! Workaround for compatibility with other libraries #ifdef max #undef max #endif //! Workaround for compatibility with other libraries #ifdef min #undef min #endif //! Workaround for Android #ifdef isnan #undef isnan #endif //! Workaround for Android #ifdef isinf #undef isinf #endif //! Workaround for Chrone Native Client #ifdef log2 #undef log2 #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/_noise.hpp000066400000000000000000000044701360521144700235510ustar00rootroot00000000000000#pragma once #include "../common.hpp" namespace glm{ namespace detail { template GLM_FUNC_QUALIFIER T mod289(T const& x) { return x - floor(x * (static_cast(1.0) / static_cast(289.0))) * static_cast(289.0); } template GLM_FUNC_QUALIFIER T permute(T const& x) { return mod289(((x * static_cast(34)) + static_cast(1)) * x); } template GLM_FUNC_QUALIFIER vec<2, T, Q> permute(vec<2, T, Q> const& x) { return mod289(((x * static_cast(34)) + static_cast(1)) * x); } template GLM_FUNC_QUALIFIER vec<3, T, Q> permute(vec<3, T, Q> const& x) { return mod289(((x * static_cast(34)) + static_cast(1)) * x); } template GLM_FUNC_QUALIFIER vec<4, T, Q> permute(vec<4, T, Q> const& x) { return mod289(((x * static_cast(34)) + static_cast(1)) * x); } template GLM_FUNC_QUALIFIER T taylorInvSqrt(T const& r) { return static_cast(1.79284291400159) - static_cast(0.85373472095314) * r; } template GLM_FUNC_QUALIFIER vec<2, T, Q> taylorInvSqrt(vec<2, T, Q> const& r) { return static_cast(1.79284291400159) - static_cast(0.85373472095314) * r; } template GLM_FUNC_QUALIFIER vec<3, T, Q> taylorInvSqrt(vec<3, T, Q> const& r) { return static_cast(1.79284291400159) - static_cast(0.85373472095314) * r; } template GLM_FUNC_QUALIFIER vec<4, T, Q> taylorInvSqrt(vec<4, T, Q> const& r) { return static_cast(1.79284291400159) - static_cast(0.85373472095314) * r; } template GLM_FUNC_QUALIFIER vec<2, T, Q> fade(vec<2, T, Q> const& t) { return (t * t * t) * (t * (t * static_cast(6) - static_cast(15)) + static_cast(10)); } template GLM_FUNC_QUALIFIER vec<3, T, Q> fade(vec<3, T, Q> const& t) { return (t * t * t) * (t * (t * static_cast(6) - static_cast(15)) + static_cast(10)); } template GLM_FUNC_QUALIFIER vec<4, T, Q> fade(vec<4, T, Q> const& t) { return (t * t * t) * (t * (t * static_cast(6) - static_cast(15)) + static_cast(10)); } }//namespace detail }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/_swizzle.hpp000066400000000000000000001400751360521144700241450ustar00rootroot00000000000000#pragma once namespace glm{ namespace detail { // Internal class for implementing swizzle operators template struct _swizzle_base0 { protected: GLM_FUNC_QUALIFIER T& elem(size_t i){ return (reinterpret_cast(_buffer))[i]; } GLM_FUNC_QUALIFIER T const& elem(size_t i) const{ return (reinterpret_cast(_buffer))[i]; } // Use an opaque buffer to *ensure* the compiler doesn't call a constructor. // The size 1 buffer is assumed to aligned to the actual members so that the // elem() char _buffer[1]; }; template struct _swizzle_base1 : public _swizzle_base0 { }; template struct _swizzle_base1<2, T, Q, E0,E1,-1,-2, Aligned> : public _swizzle_base0 { GLM_FUNC_QUALIFIER vec<2, T, Q> operator ()() const { return vec<2, T, Q>(this->elem(E0), this->elem(E1)); } }; template struct _swizzle_base1<3, T, Q, E0,E1,E2,-1, Aligned> : public _swizzle_base0 { GLM_FUNC_QUALIFIER vec<3, T, Q> operator ()() const { return vec<3, T, Q>(this->elem(E0), this->elem(E1), this->elem(E2)); } }; template struct _swizzle_base1<4, T, Q, E0,E1,E2,E3, Aligned> : public _swizzle_base0 { GLM_FUNC_QUALIFIER vec<4, T, Q> operator ()() const { return vec<4, T, Q>(this->elem(E0), this->elem(E1), this->elem(E2), this->elem(E3)); } }; // Internal class for implementing swizzle operators /* Template parameters: T = type of scalar values (e.g. float, double) N = number of components in the vector (e.g. 3) E0...3 = what index the n-th element of this swizzle refers to in the unswizzled vec DUPLICATE_ELEMENTS = 1 if there is a repeated element, 0 otherwise (used to specialize swizzles containing duplicate elements so that they cannot be used as r-values). */ template struct _swizzle_base2 : public _swizzle_base1::value> { struct op_equal { GLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e = t; } }; struct op_minus { GLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e -= t; } }; struct op_plus { GLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e += t; } }; struct op_mul { GLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e *= t; } }; struct op_div { GLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e /= t; } }; public: GLM_FUNC_QUALIFIER _swizzle_base2& operator= (const T& t) { for (int i = 0; i < N; ++i) (*this)[i] = t; return *this; } GLM_FUNC_QUALIFIER _swizzle_base2& operator= (vec const& that) { _apply_op(that, op_equal()); return *this; } GLM_FUNC_QUALIFIER void operator -= (vec const& that) { _apply_op(that, op_minus()); } GLM_FUNC_QUALIFIER void operator += (vec const& that) { _apply_op(that, op_plus()); } GLM_FUNC_QUALIFIER void operator *= (vec const& that) { _apply_op(that, op_mul()); } GLM_FUNC_QUALIFIER void operator /= (vec const& that) { _apply_op(that, op_div()); } GLM_FUNC_QUALIFIER T& operator[](size_t i) { const int offset_dst[4] = { E0, E1, E2, E3 }; return this->elem(offset_dst[i]); } GLM_FUNC_QUALIFIER T operator[](size_t i) const { const int offset_dst[4] = { E0, E1, E2, E3 }; return this->elem(offset_dst[i]); } protected: template GLM_FUNC_QUALIFIER void _apply_op(vec const& that, const U& op) { // Make a copy of the data in this == &that. // The copier should optimize out the copy in cases where the function is // properly inlined and the copy is not necessary. T t[N]; for (int i = 0; i < N; ++i) t[i] = that[i]; for (int i = 0; i < N; ++i) op( (*this)[i], t[i] ); } }; // Specialization for swizzles containing duplicate elements. These cannot be modified. template struct _swizzle_base2 : public _swizzle_base1::value> { struct Stub {}; GLM_FUNC_QUALIFIER _swizzle_base2& operator= (Stub const&) { return *this; } GLM_FUNC_QUALIFIER T operator[] (size_t i) const { const int offset_dst[4] = { E0, E1, E2, E3 }; return this->elem(offset_dst[i]); } }; template struct _swizzle : public _swizzle_base2 { typedef _swizzle_base2 base_type; using base_type::operator=; GLM_FUNC_QUALIFIER operator vec () const { return (*this)(); } }; // // To prevent the C++ syntax from getting entirely overwhelming, define some alias macros // #define GLM_SWIZZLE_TEMPLATE1 template #define GLM_SWIZZLE_TEMPLATE2 template #define GLM_SWIZZLE_TYPE1 _swizzle #define GLM_SWIZZLE_TYPE2 _swizzle // // Wrapper for a binary operator (e.g. u.yy + v.zy) // #define GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(OPERAND) \ GLM_SWIZZLE_TEMPLATE2 \ GLM_FUNC_QUALIFIER vec operator OPERAND ( const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE2& b) \ { \ return a() OPERAND b(); \ } \ GLM_SWIZZLE_TEMPLATE1 \ GLM_FUNC_QUALIFIER vec operator OPERAND ( const GLM_SWIZZLE_TYPE1& a, const vec& b) \ { \ return a() OPERAND b; \ } \ GLM_SWIZZLE_TEMPLATE1 \ GLM_FUNC_QUALIFIER vec operator OPERAND ( const vec& a, const GLM_SWIZZLE_TYPE1& b) \ { \ return a OPERAND b(); \ } // // Wrapper for a operand between a swizzle and a binary (e.g. 1.0f - u.xyz) // #define GLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(OPERAND) \ GLM_SWIZZLE_TEMPLATE1 \ GLM_FUNC_QUALIFIER vec operator OPERAND ( const GLM_SWIZZLE_TYPE1& a, const T& b) \ { \ return a() OPERAND b; \ } \ GLM_SWIZZLE_TEMPLATE1 \ GLM_FUNC_QUALIFIER vec operator OPERAND ( const T& a, const GLM_SWIZZLE_TYPE1& b) \ { \ return a OPERAND b(); \ } // // Macro for wrapping a function taking one argument (e.g. abs()) // #define GLM_SWIZZLE_FUNCTION_1_ARGS(RETURN_TYPE,FUNCTION) \ GLM_SWIZZLE_TEMPLATE1 \ GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a) \ { \ return FUNCTION(a()); \ } // // Macro for wrapping a function taking two vector arguments (e.g. dot()). // #define GLM_SWIZZLE_FUNCTION_2_ARGS(RETURN_TYPE,FUNCTION) \ GLM_SWIZZLE_TEMPLATE2 \ GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE2& b) \ { \ return FUNCTION(a(), b()); \ } \ GLM_SWIZZLE_TEMPLATE1 \ GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE1& b) \ { \ return FUNCTION(a(), b()); \ } \ GLM_SWIZZLE_TEMPLATE1 \ GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const typename V& b) \ { \ return FUNCTION(a(), b); \ } \ GLM_SWIZZLE_TEMPLATE1 \ GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const V& a, const GLM_SWIZZLE_TYPE1& b) \ { \ return FUNCTION(a, b()); \ } // // Macro for wrapping a function take 2 vec arguments followed by a scalar (e.g. mix()). // #define GLM_SWIZZLE_FUNCTION_2_ARGS_SCALAR(RETURN_TYPE,FUNCTION) \ GLM_SWIZZLE_TEMPLATE2 \ GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE2& b, const T& c) \ { \ return FUNCTION(a(), b(), c); \ } \ GLM_SWIZZLE_TEMPLATE1 \ GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE1& b, const T& c) \ { \ return FUNCTION(a(), b(), c); \ } \ GLM_SWIZZLE_TEMPLATE1 \ GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const typename S0::vec_type& b, const T& c)\ { \ return FUNCTION(a(), b, c); \ } \ GLM_SWIZZLE_TEMPLATE1 \ GLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const typename V& a, const GLM_SWIZZLE_TYPE1& b, const T& c) \ { \ return FUNCTION(a, b(), c); \ } }//namespace detail }//namespace glm namespace glm { namespace detail { GLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(-) GLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(*) GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(+) GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(-) GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(*) GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(/) } // // Swizzles are distinct types from the unswizzled type. The below macros will // provide template specializations for the swizzle types for the given functions // so that the compiler does not have any ambiguity to choosing how to handle // the function. // // The alternative is to use the operator()() when calling the function in order // to explicitly convert the swizzled type to the unswizzled type. // //GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, abs); //GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, acos); //GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, acosh); //GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, all); //GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type, any); //GLM_SWIZZLE_FUNCTION_2_ARGS(value_type, dot); //GLM_SWIZZLE_FUNCTION_2_ARGS(vec_type, cross); //GLM_SWIZZLE_FUNCTION_2_ARGS(vec_type, step); //GLM_SWIZZLE_FUNCTION_2_ARGS_SCALAR(vec_type, mix); } #define GLM_SWIZZLE2_2_MEMBERS(T, Q, E0,E1) \ struct { detail::_swizzle<2, T, Q, 0,0,-1,-2> E0 ## E0; }; \ struct { detail::_swizzle<2, T, Q, 0,1,-1,-2> E0 ## E1; }; \ struct { detail::_swizzle<2, T, Q, 1,0,-1,-2> E1 ## E0; }; \ struct { detail::_swizzle<2, T, Q, 1,1,-1,-2> E1 ## E1; }; #define GLM_SWIZZLE2_3_MEMBERS(T, Q, E0,E1) \ struct { detail::_swizzle<3,T, Q, 0,0,0,-1> E0 ## E0 ## E0; }; \ struct { detail::_swizzle<3,T, Q, 0,0,1,-1> E0 ## E0 ## E1; }; \ struct { detail::_swizzle<3,T, Q, 0,1,0,-1> E0 ## E1 ## E0; }; \ struct { detail::_swizzle<3,T, Q, 0,1,1,-1> E0 ## E1 ## E1; }; \ struct { detail::_swizzle<3,T, Q, 1,0,0,-1> E1 ## E0 ## E0; }; \ struct { detail::_swizzle<3,T, Q, 1,0,1,-1> E1 ## E0 ## E1; }; \ struct { detail::_swizzle<3,T, Q, 1,1,0,-1> E1 ## E1 ## E0; }; \ struct { detail::_swizzle<3,T, Q, 1,1,1,-1> E1 ## E1 ## E1; }; #define GLM_SWIZZLE2_4_MEMBERS(T, Q, E0,E1) \ struct { detail::_swizzle<4,T, Q, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 1,1,1,1> E1 ## E1 ## E1 ## E1; }; #define GLM_SWIZZLE3_2_MEMBERS(T, Q, E0,E1,E2) \ struct { detail::_swizzle<2,T, Q, 0,0,-1,-2> E0 ## E0; }; \ struct { detail::_swizzle<2,T, Q, 0,1,-1,-2> E0 ## E1; }; \ struct { detail::_swizzle<2,T, Q, 0,2,-1,-2> E0 ## E2; }; \ struct { detail::_swizzle<2,T, Q, 1,0,-1,-2> E1 ## E0; }; \ struct { detail::_swizzle<2,T, Q, 1,1,-1,-2> E1 ## E1; }; \ struct { detail::_swizzle<2,T, Q, 1,2,-1,-2> E1 ## E2; }; \ struct { detail::_swizzle<2,T, Q, 2,0,-1,-2> E2 ## E0; }; \ struct { detail::_swizzle<2,T, Q, 2,1,-1,-2> E2 ## E1; }; \ struct { detail::_swizzle<2,T, Q, 2,2,-1,-2> E2 ## E2; }; #define GLM_SWIZZLE3_3_MEMBERS(T, Q ,E0,E1,E2) \ struct { detail::_swizzle<3, T, Q, 0,0,0,-1> E0 ## E0 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 0,0,1,-1> E0 ## E0 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 0,0,2,-1> E0 ## E0 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 0,1,0,-1> E0 ## E1 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 0,1,1,-1> E0 ## E1 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 0,1,2,-1> E0 ## E1 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 0,2,0,-1> E0 ## E2 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 0,2,1,-1> E0 ## E2 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 0,2,2,-1> E0 ## E2 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 1,0,0,-1> E1 ## E0 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 1,0,1,-1> E1 ## E0 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 1,0,2,-1> E1 ## E0 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 1,1,0,-1> E1 ## E1 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 1,1,1,-1> E1 ## E1 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 1,1,2,-1> E1 ## E1 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 1,2,0,-1> E1 ## E2 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 1,2,1,-1> E1 ## E2 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 1,2,2,-1> E1 ## E2 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 2,0,0,-1> E2 ## E0 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 2,0,1,-1> E2 ## E0 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 2,0,2,-1> E2 ## E0 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 2,1,0,-1> E2 ## E1 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 2,1,1,-1> E2 ## E1 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 2,1,2,-1> E2 ## E1 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 2,2,0,-1> E2 ## E2 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 2,2,1,-1> E2 ## E2 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 2,2,2,-1> E2 ## E2 ## E2; }; #define GLM_SWIZZLE3_4_MEMBERS(T, Q, E0,E1,E2) \ struct { detail::_swizzle<4,T, Q, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 0,0,0,2> E0 ## E0 ## E0 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 0,0,1,2> E0 ## E0 ## E1 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 0,0,2,0> E0 ## E0 ## E2 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 0,0,2,1> E0 ## E0 ## E2 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 0,0,2,2> E0 ## E0 ## E2 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 0,1,0,2> E0 ## E1 ## E0 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 0,1,1,2> E0 ## E1 ## E1 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 0,1,2,0> E0 ## E1 ## E2 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 0,1,2,1> E0 ## E1 ## E2 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 0,1,2,2> E0 ## E1 ## E2 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 0,2,0,0> E0 ## E2 ## E0 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 0,2,0,1> E0 ## E2 ## E0 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 0,2,0,2> E0 ## E2 ## E0 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 0,2,1,0> E0 ## E2 ## E1 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 0,2,1,1> E0 ## E2 ## E1 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 0,2,1,2> E0 ## E2 ## E1 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 0,2,2,0> E0 ## E2 ## E2 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 0,2,2,1> E0 ## E2 ## E2 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 0,2,2,2> E0 ## E2 ## E2 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 1,0,0,2> E1 ## E0 ## E0 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 1,0,1,2> E1 ## E0 ## E1 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 1,0,2,0> E1 ## E0 ## E2 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 1,0,2,1> E1 ## E0 ## E2 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 1,0,2,2> E1 ## E0 ## E2 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 1,1,0,2> E1 ## E1 ## E0 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 1,1,1,1> E1 ## E1 ## E1 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 1,1,1,2> E1 ## E1 ## E1 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 1,1,2,0> E1 ## E1 ## E2 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 1,1,2,1> E1 ## E1 ## E2 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 1,1,2,2> E1 ## E1 ## E2 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 1,2,0,0> E1 ## E2 ## E0 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 1,2,0,1> E1 ## E2 ## E0 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 1,2,0,2> E1 ## E2 ## E0 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 1,2,1,0> E1 ## E2 ## E1 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 1,2,1,1> E1 ## E2 ## E1 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 1,2,1,2> E1 ## E2 ## E1 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 1,2,2,0> E1 ## E2 ## E2 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 1,2,2,1> E1 ## E2 ## E2 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 1,2,2,2> E1 ## E2 ## E2 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 2,0,0,0> E2 ## E0 ## E0 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 2,0,0,1> E2 ## E0 ## E0 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 2,0,0,2> E2 ## E0 ## E0 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 2,0,1,0> E2 ## E0 ## E1 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 2,0,1,1> E2 ## E0 ## E1 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 2,0,1,2> E2 ## E0 ## E1 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 2,0,2,0> E2 ## E0 ## E2 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 2,0,2,1> E2 ## E0 ## E2 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 2,0,2,2> E2 ## E0 ## E2 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 2,1,0,0> E2 ## E1 ## E0 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 2,1,0,1> E2 ## E1 ## E0 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 2,1,0,2> E2 ## E1 ## E0 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 2,1,1,0> E2 ## E1 ## E1 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 2,1,1,1> E2 ## E1 ## E1 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 2,1,1,2> E2 ## E1 ## E1 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 2,1,2,0> E2 ## E1 ## E2 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 2,1,2,1> E2 ## E1 ## E2 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 2,1,2,2> E2 ## E1 ## E2 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 2,2,0,0> E2 ## E2 ## E0 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 2,2,0,1> E2 ## E2 ## E0 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 2,2,0,2> E2 ## E2 ## E0 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 2,2,1,0> E2 ## E2 ## E1 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 2,2,1,1> E2 ## E2 ## E1 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 2,2,1,2> E2 ## E2 ## E1 ## E2; }; \ struct { detail::_swizzle<4,T, Q, 2,2,2,0> E2 ## E2 ## E2 ## E0; }; \ struct { detail::_swizzle<4,T, Q, 2,2,2,1> E2 ## E2 ## E2 ## E1; }; \ struct { detail::_swizzle<4,T, Q, 2,2,2,2> E2 ## E2 ## E2 ## E2; }; #define GLM_SWIZZLE4_2_MEMBERS(T, Q, E0,E1,E2,E3) \ struct { detail::_swizzle<2,T, Q, 0,0,-1,-2> E0 ## E0; }; \ struct { detail::_swizzle<2,T, Q, 0,1,-1,-2> E0 ## E1; }; \ struct { detail::_swizzle<2,T, Q, 0,2,-1,-2> E0 ## E2; }; \ struct { detail::_swizzle<2,T, Q, 0,3,-1,-2> E0 ## E3; }; \ struct { detail::_swizzle<2,T, Q, 1,0,-1,-2> E1 ## E0; }; \ struct { detail::_swizzle<2,T, Q, 1,1,-1,-2> E1 ## E1; }; \ struct { detail::_swizzle<2,T, Q, 1,2,-1,-2> E1 ## E2; }; \ struct { detail::_swizzle<2,T, Q, 1,3,-1,-2> E1 ## E3; }; \ struct { detail::_swizzle<2,T, Q, 2,0,-1,-2> E2 ## E0; }; \ struct { detail::_swizzle<2,T, Q, 2,1,-1,-2> E2 ## E1; }; \ struct { detail::_swizzle<2,T, Q, 2,2,-1,-2> E2 ## E2; }; \ struct { detail::_swizzle<2,T, Q, 2,3,-1,-2> E2 ## E3; }; \ struct { detail::_swizzle<2,T, Q, 3,0,-1,-2> E3 ## E0; }; \ struct { detail::_swizzle<2,T, Q, 3,1,-1,-2> E3 ## E1; }; \ struct { detail::_swizzle<2,T, Q, 3,2,-1,-2> E3 ## E2; }; \ struct { detail::_swizzle<2,T, Q, 3,3,-1,-2> E3 ## E3; }; #define GLM_SWIZZLE4_3_MEMBERS(T, Q, E0,E1,E2,E3) \ struct { detail::_swizzle<3, T, Q, 0,0,0,-1> E0 ## E0 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 0,0,1,-1> E0 ## E0 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 0,0,2,-1> E0 ## E0 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 0,0,3,-1> E0 ## E0 ## E3; }; \ struct { detail::_swizzle<3, T, Q, 0,1,0,-1> E0 ## E1 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 0,1,1,-1> E0 ## E1 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 0,1,2,-1> E0 ## E1 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 0,1,3,-1> E0 ## E1 ## E3; }; \ struct { detail::_swizzle<3, T, Q, 0,2,0,-1> E0 ## E2 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 0,2,1,-1> E0 ## E2 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 0,2,2,-1> E0 ## E2 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 0,2,3,-1> E0 ## E2 ## E3; }; \ struct { detail::_swizzle<3, T, Q, 0,3,0,-1> E0 ## E3 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 0,3,1,-1> E0 ## E3 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 0,3,2,-1> E0 ## E3 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 0,3,3,-1> E0 ## E3 ## E3; }; \ struct { detail::_swizzle<3, T, Q, 1,0,0,-1> E1 ## E0 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 1,0,1,-1> E1 ## E0 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 1,0,2,-1> E1 ## E0 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 1,0,3,-1> E1 ## E0 ## E3; }; \ struct { detail::_swizzle<3, T, Q, 1,1,0,-1> E1 ## E1 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 1,1,1,-1> E1 ## E1 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 1,1,2,-1> E1 ## E1 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 1,1,3,-1> E1 ## E1 ## E3; }; \ struct { detail::_swizzle<3, T, Q, 1,2,0,-1> E1 ## E2 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 1,2,1,-1> E1 ## E2 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 1,2,2,-1> E1 ## E2 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 1,2,3,-1> E1 ## E2 ## E3; }; \ struct { detail::_swizzle<3, T, Q, 1,3,0,-1> E1 ## E3 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 1,3,1,-1> E1 ## E3 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 1,3,2,-1> E1 ## E3 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 1,3,3,-1> E1 ## E3 ## E3; }; \ struct { detail::_swizzle<3, T, Q, 2,0,0,-1> E2 ## E0 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 2,0,1,-1> E2 ## E0 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 2,0,2,-1> E2 ## E0 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 2,0,3,-1> E2 ## E0 ## E3; }; \ struct { detail::_swizzle<3, T, Q, 2,1,0,-1> E2 ## E1 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 2,1,1,-1> E2 ## E1 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 2,1,2,-1> E2 ## E1 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 2,1,3,-1> E2 ## E1 ## E3; }; \ struct { detail::_swizzle<3, T, Q, 2,2,0,-1> E2 ## E2 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 2,2,1,-1> E2 ## E2 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 2,2,2,-1> E2 ## E2 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 2,2,3,-1> E2 ## E2 ## E3; }; \ struct { detail::_swizzle<3, T, Q, 2,3,0,-1> E2 ## E3 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 2,3,1,-1> E2 ## E3 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 2,3,2,-1> E2 ## E3 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 2,3,3,-1> E2 ## E3 ## E3; }; \ struct { detail::_swizzle<3, T, Q, 3,0,0,-1> E3 ## E0 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 3,0,1,-1> E3 ## E0 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 3,0,2,-1> E3 ## E0 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 3,0,3,-1> E3 ## E0 ## E3; }; \ struct { detail::_swizzle<3, T, Q, 3,1,0,-1> E3 ## E1 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 3,1,1,-1> E3 ## E1 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 3,1,2,-1> E3 ## E1 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 3,1,3,-1> E3 ## E1 ## E3; }; \ struct { detail::_swizzle<3, T, Q, 3,2,0,-1> E3 ## E2 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 3,2,1,-1> E3 ## E2 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 3,2,2,-1> E3 ## E2 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 3,2,3,-1> E3 ## E2 ## E3; }; \ struct { detail::_swizzle<3, T, Q, 3,3,0,-1> E3 ## E3 ## E0; }; \ struct { detail::_swizzle<3, T, Q, 3,3,1,-1> E3 ## E3 ## E1; }; \ struct { detail::_swizzle<3, T, Q, 3,3,2,-1> E3 ## E3 ## E2; }; \ struct { detail::_swizzle<3, T, Q, 3,3,3,-1> E3 ## E3 ## E3; }; #define GLM_SWIZZLE4_4_MEMBERS(T, Q, E0,E1,E2,E3) \ struct { detail::_swizzle<4, T, Q, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 0,0,0,2> E0 ## E0 ## E0 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 0,0,0,3> E0 ## E0 ## E0 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 0,0,1,2> E0 ## E0 ## E1 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 0,0,1,3> E0 ## E0 ## E1 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 0,0,2,0> E0 ## E0 ## E2 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 0,0,2,1> E0 ## E0 ## E2 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 0,0,2,2> E0 ## E0 ## E2 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 0,0,2,3> E0 ## E0 ## E2 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 0,0,3,0> E0 ## E0 ## E3 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 0,0,3,1> E0 ## E0 ## E3 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 0,0,3,2> E0 ## E0 ## E3 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 0,0,3,3> E0 ## E0 ## E3 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 0,1,0,2> E0 ## E1 ## E0 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 0,1,0,3> E0 ## E1 ## E0 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 0,1,1,2> E0 ## E1 ## E1 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 0,1,1,3> E0 ## E1 ## E1 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 0,1,2,0> E0 ## E1 ## E2 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 0,1,2,1> E0 ## E1 ## E2 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 0,1,2,2> E0 ## E1 ## E2 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 0,1,2,3> E0 ## E1 ## E2 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 0,1,3,0> E0 ## E1 ## E3 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 0,1,3,1> E0 ## E1 ## E3 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 0,1,3,2> E0 ## E1 ## E3 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 0,1,3,3> E0 ## E1 ## E3 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 0,2,0,0> E0 ## E2 ## E0 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 0,2,0,1> E0 ## E2 ## E0 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 0,2,0,2> E0 ## E2 ## E0 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 0,2,0,3> E0 ## E2 ## E0 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 0,2,1,0> E0 ## E2 ## E1 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 0,2,1,1> E0 ## E2 ## E1 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 0,2,1,2> E0 ## E2 ## E1 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 0,2,1,3> E0 ## E2 ## E1 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 0,2,2,0> E0 ## E2 ## E2 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 0,2,2,1> E0 ## E2 ## E2 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 0,2,2,2> E0 ## E2 ## E2 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 0,2,2,3> E0 ## E2 ## E2 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 0,2,3,0> E0 ## E2 ## E3 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 0,2,3,1> E0 ## E2 ## E3 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 0,2,3,2> E0 ## E2 ## E3 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 0,2,3,3> E0 ## E2 ## E3 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 0,3,0,0> E0 ## E3 ## E0 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 0,3,0,1> E0 ## E3 ## E0 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 0,3,0,2> E0 ## E3 ## E0 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 0,3,0,3> E0 ## E3 ## E0 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 0,3,1,0> E0 ## E3 ## E1 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 0,3,1,1> E0 ## E3 ## E1 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 0,3,1,2> E0 ## E3 ## E1 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 0,3,1,3> E0 ## E3 ## E1 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 0,3,2,0> E0 ## E3 ## E2 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 0,3,2,1> E0 ## E3 ## E2 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 0,3,2,2> E0 ## E3 ## E2 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 0,3,2,3> E0 ## E3 ## E2 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 0,3,3,0> E0 ## E3 ## E3 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 0,3,3,1> E0 ## E3 ## E3 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 0,3,3,2> E0 ## E3 ## E3 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 0,3,3,3> E0 ## E3 ## E3 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 1,0,0,2> E1 ## E0 ## E0 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 1,0,0,3> E1 ## E0 ## E0 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 1,0,1,2> E1 ## E0 ## E1 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 1,0,1,3> E1 ## E0 ## E1 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 1,0,2,0> E1 ## E0 ## E2 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 1,0,2,1> E1 ## E0 ## E2 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 1,0,2,2> E1 ## E0 ## E2 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 1,0,2,3> E1 ## E0 ## E2 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 1,0,3,0> E1 ## E0 ## E3 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 1,0,3,1> E1 ## E0 ## E3 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 1,0,3,2> E1 ## E0 ## E3 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 1,0,3,3> E1 ## E0 ## E3 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 1,1,0,2> E1 ## E1 ## E0 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 1,1,0,3> E1 ## E1 ## E0 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 1,1,1,1> E1 ## E1 ## E1 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 1,1,1,2> E1 ## E1 ## E1 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 1,1,1,3> E1 ## E1 ## E1 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 1,1,2,0> E1 ## E1 ## E2 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 1,1,2,1> E1 ## E1 ## E2 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 1,1,2,2> E1 ## E1 ## E2 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 1,1,2,3> E1 ## E1 ## E2 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 1,1,3,0> E1 ## E1 ## E3 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 1,1,3,1> E1 ## E1 ## E3 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 1,1,3,2> E1 ## E1 ## E3 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 1,1,3,3> E1 ## E1 ## E3 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 1,2,0,0> E1 ## E2 ## E0 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 1,2,0,1> E1 ## E2 ## E0 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 1,2,0,2> E1 ## E2 ## E0 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 1,2,0,3> E1 ## E2 ## E0 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 1,2,1,0> E1 ## E2 ## E1 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 1,2,1,1> E1 ## E2 ## E1 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 1,2,1,2> E1 ## E2 ## E1 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 1,2,1,3> E1 ## E2 ## E1 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 1,2,2,0> E1 ## E2 ## E2 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 1,2,2,1> E1 ## E2 ## E2 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 1,2,2,2> E1 ## E2 ## E2 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 1,2,2,3> E1 ## E2 ## E2 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 1,2,3,0> E1 ## E2 ## E3 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 1,2,3,1> E1 ## E2 ## E3 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 1,2,3,2> E1 ## E2 ## E3 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 1,2,3,3> E1 ## E2 ## E3 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 1,3,0,0> E1 ## E3 ## E0 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 1,3,0,1> E1 ## E3 ## E0 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 1,3,0,2> E1 ## E3 ## E0 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 1,3,0,3> E1 ## E3 ## E0 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 1,3,1,0> E1 ## E3 ## E1 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 1,3,1,1> E1 ## E3 ## E1 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 1,3,1,2> E1 ## E3 ## E1 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 1,3,1,3> E1 ## E3 ## E1 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 1,3,2,0> E1 ## E3 ## E2 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 1,3,2,1> E1 ## E3 ## E2 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 1,3,2,2> E1 ## E3 ## E2 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 1,3,2,3> E1 ## E3 ## E2 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 1,3,3,0> E1 ## E3 ## E3 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 1,3,3,1> E1 ## E3 ## E3 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 1,3,3,2> E1 ## E3 ## E3 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 1,3,3,3> E1 ## E3 ## E3 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 2,0,0,0> E2 ## E0 ## E0 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 2,0,0,1> E2 ## E0 ## E0 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 2,0,0,2> E2 ## E0 ## E0 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 2,0,0,3> E2 ## E0 ## E0 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 2,0,1,0> E2 ## E0 ## E1 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 2,0,1,1> E2 ## E0 ## E1 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 2,0,1,2> E2 ## E0 ## E1 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 2,0,1,3> E2 ## E0 ## E1 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 2,0,2,0> E2 ## E0 ## E2 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 2,0,2,1> E2 ## E0 ## E2 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 2,0,2,2> E2 ## E0 ## E2 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 2,0,2,3> E2 ## E0 ## E2 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 2,0,3,0> E2 ## E0 ## E3 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 2,0,3,1> E2 ## E0 ## E3 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 2,0,3,2> E2 ## E0 ## E3 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 2,0,3,3> E2 ## E0 ## E3 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 2,1,0,0> E2 ## E1 ## E0 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 2,1,0,1> E2 ## E1 ## E0 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 2,1,0,2> E2 ## E1 ## E0 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 2,1,0,3> E2 ## E1 ## E0 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 2,1,1,0> E2 ## E1 ## E1 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 2,1,1,1> E2 ## E1 ## E1 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 2,1,1,2> E2 ## E1 ## E1 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 2,1,1,3> E2 ## E1 ## E1 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 2,1,2,0> E2 ## E1 ## E2 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 2,1,2,1> E2 ## E1 ## E2 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 2,1,2,2> E2 ## E1 ## E2 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 2,1,2,3> E2 ## E1 ## E2 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 2,1,3,0> E2 ## E1 ## E3 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 2,1,3,1> E2 ## E1 ## E3 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 2,1,3,2> E2 ## E1 ## E3 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 2,1,3,3> E2 ## E1 ## E3 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 2,2,0,0> E2 ## E2 ## E0 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 2,2,0,1> E2 ## E2 ## E0 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 2,2,0,2> E2 ## E2 ## E0 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 2,2,0,3> E2 ## E2 ## E0 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 2,2,1,0> E2 ## E2 ## E1 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 2,2,1,1> E2 ## E2 ## E1 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 2,2,1,2> E2 ## E2 ## E1 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 2,2,1,3> E2 ## E2 ## E1 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 2,2,2,0> E2 ## E2 ## E2 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 2,2,2,1> E2 ## E2 ## E2 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 2,2,2,2> E2 ## E2 ## E2 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 2,2,2,3> E2 ## E2 ## E2 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 2,2,3,0> E2 ## E2 ## E3 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 2,2,3,1> E2 ## E2 ## E3 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 2,2,3,2> E2 ## E2 ## E3 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 2,2,3,3> E2 ## E2 ## E3 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 2,3,0,0> E2 ## E3 ## E0 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 2,3,0,1> E2 ## E3 ## E0 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 2,3,0,2> E2 ## E3 ## E0 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 2,3,0,3> E2 ## E3 ## E0 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 2,3,1,0> E2 ## E3 ## E1 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 2,3,1,1> E2 ## E3 ## E1 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 2,3,1,2> E2 ## E3 ## E1 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 2,3,1,3> E2 ## E3 ## E1 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 2,3,2,0> E2 ## E3 ## E2 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 2,3,2,1> E2 ## E3 ## E2 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 2,3,2,2> E2 ## E3 ## E2 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 2,3,2,3> E2 ## E3 ## E2 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 2,3,3,0> E2 ## E3 ## E3 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 2,3,3,1> E2 ## E3 ## E3 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 2,3,3,2> E2 ## E3 ## E3 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 2,3,3,3> E2 ## E3 ## E3 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 3,0,0,0> E3 ## E0 ## E0 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 3,0,0,1> E3 ## E0 ## E0 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 3,0,0,2> E3 ## E0 ## E0 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 3,0,0,3> E3 ## E0 ## E0 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 3,0,1,0> E3 ## E0 ## E1 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 3,0,1,1> E3 ## E0 ## E1 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 3,0,1,2> E3 ## E0 ## E1 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 3,0,1,3> E3 ## E0 ## E1 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 3,0,2,0> E3 ## E0 ## E2 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 3,0,2,1> E3 ## E0 ## E2 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 3,0,2,2> E3 ## E0 ## E2 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 3,0,2,3> E3 ## E0 ## E2 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 3,0,3,0> E3 ## E0 ## E3 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 3,0,3,1> E3 ## E0 ## E3 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 3,0,3,2> E3 ## E0 ## E3 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 3,0,3,3> E3 ## E0 ## E3 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 3,1,0,0> E3 ## E1 ## E0 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 3,1,0,1> E3 ## E1 ## E0 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 3,1,0,2> E3 ## E1 ## E0 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 3,1,0,3> E3 ## E1 ## E0 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 3,1,1,0> E3 ## E1 ## E1 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 3,1,1,1> E3 ## E1 ## E1 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 3,1,1,2> E3 ## E1 ## E1 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 3,1,1,3> E3 ## E1 ## E1 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 3,1,2,0> E3 ## E1 ## E2 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 3,1,2,1> E3 ## E1 ## E2 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 3,1,2,2> E3 ## E1 ## E2 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 3,1,2,3> E3 ## E1 ## E2 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 3,1,3,0> E3 ## E1 ## E3 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 3,1,3,1> E3 ## E1 ## E3 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 3,1,3,2> E3 ## E1 ## E3 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 3,1,3,3> E3 ## E1 ## E3 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 3,2,0,0> E3 ## E2 ## E0 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 3,2,0,1> E3 ## E2 ## E0 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 3,2,0,2> E3 ## E2 ## E0 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 3,2,0,3> E3 ## E2 ## E0 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 3,2,1,0> E3 ## E2 ## E1 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 3,2,1,1> E3 ## E2 ## E1 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 3,2,1,2> E3 ## E2 ## E1 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 3,2,1,3> E3 ## E2 ## E1 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 3,2,2,0> E3 ## E2 ## E2 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 3,2,2,1> E3 ## E2 ## E2 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 3,2,2,2> E3 ## E2 ## E2 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 3,2,2,3> E3 ## E2 ## E2 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 3,2,3,0> E3 ## E2 ## E3 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 3,2,3,1> E3 ## E2 ## E3 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 3,2,3,2> E3 ## E2 ## E3 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 3,2,3,3> E3 ## E2 ## E3 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 3,3,0,0> E3 ## E3 ## E0 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 3,3,0,1> E3 ## E3 ## E0 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 3,3,0,2> E3 ## E3 ## E0 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 3,3,0,3> E3 ## E3 ## E0 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 3,3,1,0> E3 ## E3 ## E1 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 3,3,1,1> E3 ## E3 ## E1 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 3,3,1,2> E3 ## E3 ## E1 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 3,3,1,3> E3 ## E3 ## E1 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 3,3,2,0> E3 ## E3 ## E2 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 3,3,2,1> E3 ## E3 ## E2 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 3,3,2,2> E3 ## E3 ## E2 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 3,3,2,3> E3 ## E3 ## E2 ## E3; }; \ struct { detail::_swizzle<4, T, Q, 3,3,3,0> E3 ## E3 ## E3 ## E0; }; \ struct { detail::_swizzle<4, T, Q, 3,3,3,1> E3 ## E3 ## E3 ## E1; }; \ struct { detail::_swizzle<4, T, Q, 3,3,3,2> E3 ## E3 ## E3 ## E2; }; \ struct { detail::_swizzle<4, T, Q, 3,3,3,3> E3 ## E3 ## E3 ## E3; }; connectome-workbench-1.4.2/src/GLMath/glm/detail/_swizzle_func.hpp000066400000000000000000001043131360521144700251530ustar00rootroot00000000000000#pragma once #define GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, CONST, A, B) \ vec<2, T, Q> A ## B() CONST \ { \ return vec<2, T, Q>(this->A, this->B); \ } #define GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, CONST, A, B, C) \ vec<3, T, Q> A ## B ## C() CONST \ { \ return vec<3, T, Q>(this->A, this->B, this->C); \ } #define GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, CONST, A, B, C, D) \ vec<4, T, Q> A ## B ## C ## D() CONST \ { \ return vec<4, T, Q>(this->A, this->B, this->C, this->D); \ } #define GLM_SWIZZLE_GEN_VEC2_ENTRY_DEF(T, P, L, CONST, A, B) \ template \ vec vec::A ## B() CONST \ { \ return vec<2, T, Q>(this->A, this->B); \ } #define GLM_SWIZZLE_GEN_VEC3_ENTRY_DEF(T, P, L, CONST, A, B, C) \ template \ vec<3, T, Q> vec::A ## B ## C() CONST \ { \ return vec<3, T, Q>(this->A, this->B, this->C); \ } #define GLM_SWIZZLE_GEN_VEC4_ENTRY_DEF(T, P, L, CONST, A, B, C, D) \ template \ vec<4, T, Q> vec::A ## B ## C ## D() CONST \ { \ return vec<4, T, Q>(this->A, this->B, this->C, this->D); \ } #define GLM_MUTABLE #define GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(T, P, A, B) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, 2, GLM_MUTABLE, A, B) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, 2, GLM_MUTABLE, B, A) #define GLM_SWIZZLE_GEN_REF_FROM_VEC2(T, P) \ GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(T, P, x, y) \ GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(T, P, r, g) \ GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(T, P, s, t) #define GLM_SWIZZLE_GEN_REF2_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, B) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, C) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, A) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, C) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, A) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, B) #define GLM_SWIZZLE_GEN_REF3_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, A, B, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, A, C, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, B, A, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, B, C, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, C, A, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, C, B, A) #define GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(T, P, A, B, C) \ GLM_SWIZZLE_GEN_REF3_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ GLM_SWIZZLE_GEN_REF2_FROM_VEC3_SWIZZLE(T, P, A, B, C) #define GLM_SWIZZLE_GEN_REF_FROM_VEC3(T, P) \ GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(T, P, x, y, z) \ GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(T, P, r, g, b) \ GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(T, P, s, t, p) #define GLM_SWIZZLE_GEN_REF2_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, B) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, C) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, D) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, A) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, C) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, D) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, A) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, B) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, D) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, D, A) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, D, B) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, D, C) #define GLM_SWIZZLE_GEN_REF3_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, B, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, B, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, C, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, C, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, D, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, D, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, A, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, A, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, C, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, C, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, D, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, D, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, A, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, A, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, B, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, B, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, D, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, D, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, A, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, A, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, B, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, B, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, C, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, C, B) #define GLM_SWIZZLE_GEN_REF4_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, C, B, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, C, D, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, D, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, D, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, B, D, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, B, C, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, C, A, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, C, D, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, D, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, D, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, A, D, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, A, C, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, B, A, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, B, D, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, D, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, D, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, A, D, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, A, B, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, C, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, C, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, A, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, A, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, B, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, B, C, A) #define GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, P, A, B, C, D) \ GLM_SWIZZLE_GEN_REF2_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ GLM_SWIZZLE_GEN_REF3_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ GLM_SWIZZLE_GEN_REF4_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) #define GLM_SWIZZLE_GEN_REF_FROM_VEC4(T, P) \ GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, P, x, y, z, w) \ GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, P, r, g, b, a) \ GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, P, s, t, p, q) #define GLM_SWIZZLE_GEN_VEC2_FROM_VEC2_SWIZZLE(T, P, A, B) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, A) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, B) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, A) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, B) #define GLM_SWIZZLE_GEN_VEC3_FROM_VEC2_SWIZZLE(T, P, A, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, B) #define GLM_SWIZZLE_GEN_VEC4_FROM_VEC2_SWIZZLE(T, P, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, B) #define GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, P, A, B) \ GLM_SWIZZLE_GEN_VEC2_FROM_VEC2_SWIZZLE(T, P, A, B) \ GLM_SWIZZLE_GEN_VEC3_FROM_VEC2_SWIZZLE(T, P, A, B) \ GLM_SWIZZLE_GEN_VEC4_FROM_VEC2_SWIZZLE(T, P, A, B) #define GLM_SWIZZLE_GEN_VEC_FROM_VEC2(T, P) \ GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, P, x, y) \ GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, P, r, g) \ GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, P, s, t) #define GLM_SWIZZLE_GEN_VEC2_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, A) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, B) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, C) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, A) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, B) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, C) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, A) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, B) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, C) #define GLM_SWIZZLE_GEN_VEC3_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, C) #define GLM_SWIZZLE_GEN_VEC4_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, C) #define GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, P, A, B, C) \ GLM_SWIZZLE_GEN_VEC2_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ GLM_SWIZZLE_GEN_VEC3_FROM_VEC3_SWIZZLE(T, P, A, B, C) \ GLM_SWIZZLE_GEN_VEC4_FROM_VEC3_SWIZZLE(T, P, A, B, C) #define GLM_SWIZZLE_GEN_VEC_FROM_VEC3(T, P) \ GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, P, x, y, z) \ GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, P, r, g, b) \ GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, P, s, t, p) #define GLM_SWIZZLE_GEN_VEC2_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, A) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, B) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, C) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, D) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, A) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, B) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, C) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, D) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, A) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, B) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, C) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, D) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, D, A) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, D, B) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, D, C) \ GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, D, D) #define GLM_SWIZZLE_GEN_VEC3_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, D, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, D, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, D, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, D, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, D, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, D, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, D, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, D, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, D, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, D, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, D, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, D, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, A, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, A, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, A, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, A, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, B, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, B, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, B, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, B, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, C, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, C, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, C, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, C, D) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, D, A) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, D, B) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, D, C) \ GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, D, D) #define GLM_SWIZZLE_GEN_VEC4_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, D, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, D, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, D, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, D, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, D, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, D, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, D, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, D, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, D, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, D, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, D, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, D, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, A, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, B, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, C, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, D, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, D, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, D, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, D, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, D, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, D, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, D, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, D, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, D, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, D, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, D, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, D, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, D, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, D, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, D, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, D, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, A, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, B, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, C, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, D, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, D, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, D, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, D, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, D, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, D, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, D, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, D, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, D, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, D, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, D, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, D, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, D, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, D, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, D, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, D, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, A, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, B, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, C, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, D, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, D, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, D, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, D, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, A, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, B, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, C, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, D, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, D, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, D, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, D, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, A, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, B, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, C, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, D, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, D, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, D, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, D, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, A, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, B, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, C, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, D, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, D, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, D, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, D, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, A, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, A, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, A, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, A, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, B, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, B, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, B, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, B, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, C, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, C, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, C, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, C, D) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, D, A) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, D, B) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, D, C) \ GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, D, D) #define GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, P, A, B, C, D) \ GLM_SWIZZLE_GEN_VEC2_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ GLM_SWIZZLE_GEN_VEC3_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \ GLM_SWIZZLE_GEN_VEC4_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) #define GLM_SWIZZLE_GEN_VEC_FROM_VEC4(T, P) \ GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, P, x, y, z, w) \ GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, P, r, g, b, a) \ GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, P, s, t, p, q) connectome-workbench-1.4.2/src/GLMath/glm/detail/_vectorize.hpp000066400000000000000000000126041360521144700244440ustar00rootroot00000000000000#pragma once namespace glm{ namespace detail { template class vec, length_t L, typename R, typename T, qualifier Q> struct functor1{}; template class vec, typename R, typename T, qualifier Q> struct functor1 { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<1, R, Q> call(R (*Func) (T x), vec<1, T, Q> const& v) { return vec<1, R, Q>(Func(v.x)); } }; template class vec, typename R, typename T, qualifier Q> struct functor1 { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<2, R, Q> call(R (*Func) (T x), vec<2, T, Q> const& v) { return vec<2, R, Q>(Func(v.x), Func(v.y)); } }; template class vec, typename R, typename T, qualifier Q> struct functor1 { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<3, R, Q> call(R (*Func) (T x), vec<3, T, Q> const& v) { return vec<3, R, Q>(Func(v.x), Func(v.y), Func(v.z)); } }; template class vec, typename R, typename T, qualifier Q> struct functor1 { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, R, Q> call(R (*Func) (T x), vec<4, T, Q> const& v) { return vec<4, R, Q>(Func(v.x), Func(v.y), Func(v.z), Func(v.w)); } }; template class vec, length_t L, typename T, qualifier Q> struct functor2{}; template class vec, typename T, qualifier Q> struct functor2 { GLM_FUNC_QUALIFIER static vec<1, T, Q> call(T (*Func) (T x, T y), vec<1, T, Q> const& a, vec<1, T, Q> const& b) { return vec<1, T, Q>(Func(a.x, b.x)); } }; template class vec, typename T, qualifier Q> struct functor2 { GLM_FUNC_QUALIFIER static vec<2, T, Q> call(T (*Func) (T x, T y), vec<2, T, Q> const& a, vec<2, T, Q> const& b) { return vec<2, T, Q>(Func(a.x, b.x), Func(a.y, b.y)); } }; template class vec, typename T, qualifier Q> struct functor2 { GLM_FUNC_QUALIFIER static vec<3, T, Q> call(T (*Func) (T x, T y), vec<3, T, Q> const& a, vec<3, T, Q> const& b) { return vec<3, T, Q>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z)); } }; template class vec, typename T, qualifier Q> struct functor2 { GLM_FUNC_QUALIFIER static vec<4, T, Q> call(T (*Func) (T x, T y), vec<4, T, Q> const& a, vec<4, T, Q> const& b) { return vec<4, T, Q>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z), Func(a.w, b.w)); } }; template class vec, length_t L, typename T, qualifier Q> struct functor2_vec_sca{}; template class vec, typename T, qualifier Q> struct functor2_vec_sca { GLM_FUNC_QUALIFIER static vec<1, T, Q> call(T (*Func) (T x, T y), vec<1, T, Q> const& a, T b) { return vec<1, T, Q>(Func(a.x, b)); } }; template class vec, typename T, qualifier Q> struct functor2_vec_sca { GLM_FUNC_QUALIFIER static vec<2, T, Q> call(T (*Func) (T x, T y), vec<2, T, Q> const& a, T b) { return vec<2, T, Q>(Func(a.x, b), Func(a.y, b)); } }; template class vec, typename T, qualifier Q> struct functor2_vec_sca { GLM_FUNC_QUALIFIER static vec<3, T, Q> call(T (*Func) (T x, T y), vec<3, T, Q> const& a, T b) { return vec<3, T, Q>(Func(a.x, b), Func(a.y, b), Func(a.z, b)); } }; template class vec, typename T, qualifier Q> struct functor2_vec_sca { GLM_FUNC_QUALIFIER static vec<4, T, Q> call(T (*Func) (T x, T y), vec<4, T, Q> const& a, T b) { return vec<4, T, Q>(Func(a.x, b), Func(a.y, b), Func(a.z, b), Func(a.w, b)); } }; template struct functor2_vec_int {}; template struct functor2_vec_int<1, T, Q> { GLM_FUNC_QUALIFIER static vec<1, int, Q> call(int (*Func) (T x, int y), vec<1, T, Q> const& a, vec<1, int, Q> const& b) { return vec<1, int, Q>(Func(a.x, b.x)); } }; template struct functor2_vec_int<2, T, Q> { GLM_FUNC_QUALIFIER static vec<2, int, Q> call(int (*Func) (T x, int y), vec<2, T, Q> const& a, vec<2, int, Q> const& b) { return vec<2, int, Q>(Func(a.x, b.x), Func(a.y, b.y)); } }; template struct functor2_vec_int<3, T, Q> { GLM_FUNC_QUALIFIER static vec<3, int, Q> call(int (*Func) (T x, int y), vec<3, T, Q> const& a, vec<3, int, Q> const& b) { return vec<3, int, Q>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z)); } }; template struct functor2_vec_int<4, T, Q> { GLM_FUNC_QUALIFIER static vec<4, int, Q> call(int (*Func) (T x, int y), vec<4, T, Q> const& a, vec<4, int, Q> const& b) { return vec<4, int, Q>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z), Func(a.w, b.w)); } }; }//namespace detail }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/compute_common.hpp000066400000000000000000000023321360521144700253140ustar00rootroot00000000000000#pragma once #include "setup.hpp" #include namespace glm{ namespace detail { template struct compute_abs {}; template struct compute_abs { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static genFIType call(genFIType x) { GLM_STATIC_ASSERT( std::numeric_limits::is_iec559 || std::numeric_limits::is_signed, "'abs' only accept floating-point and integer scalar or vector inputs"); return x >= genFIType(0) ? x : -x; // TODO, perf comp with: *(((int *) &x) + 1) &= 0x7fffffff; } }; #if GLM_COMPILER & GLM_COMPILER_CUDA template<> struct compute_abs { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static float call(float x) { return fabsf(x); } }; #endif template struct compute_abs { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static genFIType call(genFIType x) { GLM_STATIC_ASSERT( (!std::numeric_limits::is_signed && std::numeric_limits::is_integer), "'abs' only accept floating-point and integer scalar or vector inputs"); return x; } }; }//namespace detail }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/compute_vector_relational.hpp000066400000000000000000000011661360521144700275440ustar00rootroot00000000000000#pragma once //#include "compute_common.hpp" #include "setup.hpp" #include namespace glm{ namespace detail { template struct compute_equal { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static bool call(T a, T b) { return a == b; } }; /* template struct compute_equal { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static bool call(T a, T b) { return detail::compute_abs::is_signed>::call(b - a) <= static_cast(0); //return std::memcmp(&a, &b, sizeof(T)) == 0; } }; */ }//namespace detail }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/func_common.inl000066400000000000000000000612671360521144700246020ustar00rootroot00000000000000/// @ref core /// @file glm/detail/func_common.inl #include "../vector_relational.hpp" #include "compute_common.hpp" #include "type_vec1.hpp" #include "type_vec2.hpp" #include "type_vec3.hpp" #include "type_vec4.hpp" #include "_vectorize.hpp" #include namespace glm { // min template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType min(genType x, genType y) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'min' only accept floating-point or integer inputs"); return (y < x) ? y : x; } // max template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType max(genType x, genType y) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'max' only accept floating-point or integer inputs"); return (x < y) ? y : x; } // abs template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR int abs(int x) { int const y = x >> (sizeof(int) * 8 - 1); return (x ^ y) - y; } // round # if GLM_HAS_CXX11_STL using ::std::round; # else template GLM_FUNC_QUALIFIER genType round(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'round' only accept floating-point inputs"); return x < static_cast(0) ? static_cast(int(x - static_cast(0.5))) : static_cast(int(x + static_cast(0.5))); } # endif // trunc # if GLM_HAS_CXX11_STL using ::std::trunc; # else template GLM_FUNC_QUALIFIER genType trunc(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'trunc' only accept floating-point inputs"); return x < static_cast(0) ? -std::floor(-x) : std::floor(x); } # endif }//namespace glm namespace glm{ namespace detail { template struct compute_abs_vector { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec call(vec const& x) { return detail::functor1::call(abs, x); } }; template struct compute_mix_vector { GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y, vec const& a) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'mix' only accept floating-point inputs for the interpolator a"); return vec(vec(x) * (static_cast(1) - a) + vec(y) * a); } }; template struct compute_mix_vector { GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y, vec const& a) { vec Result; for(length_t i = 0; i < x.length(); ++i) Result[i] = a[i] ? y[i] : x[i]; return Result; } }; template struct compute_mix_scalar { GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y, U const& a) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'mix' only accept floating-point inputs for the interpolator a"); return vec(vec(x) * (static_cast(1) - a) + vec(y) * a); } }; template struct compute_mix_scalar { GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y, bool const& a) { return a ? y : x; } }; template struct compute_mix { GLM_FUNC_QUALIFIER static T call(T const& x, T const& y, U const& a) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'mix' only accept floating-point inputs for the interpolator a"); return static_cast(static_cast(x) * (static_cast(1) - a) + static_cast(y) * a); } }; template struct compute_mix { GLM_FUNC_QUALIFIER static T call(T const& x, T const& y, bool const& a) { return a ? y : x; } }; template struct compute_sign { GLM_FUNC_QUALIFIER static vec call(vec const& x) { return vec(glm::lessThan(vec(0), x)) - vec(glm::lessThan(x, vec(0))); } }; # if GLM_ARCH == GLM_ARCH_X86 template struct compute_sign { GLM_FUNC_QUALIFIER static vec call(vec const& x) { T const Shift(static_cast(sizeof(T) * 8 - 1)); vec const y(vec::type, Q>(-x) >> typename detail::make_unsigned::type(Shift)); return (x >> Shift) | y; } }; # endif template struct compute_floor { GLM_FUNC_QUALIFIER static vec call(vec const& x) { return detail::functor1::call(std::floor, x); } }; template struct compute_ceil { GLM_FUNC_QUALIFIER static vec call(vec const& x) { return detail::functor1::call(std::ceil, x); } }; template struct compute_fract { GLM_FUNC_QUALIFIER static vec call(vec const& x) { return x - floor(x); } }; template struct compute_trunc { GLM_FUNC_QUALIFIER static vec call(vec const& x) { return detail::functor1::call(trunc, x); } }; template struct compute_round { GLM_FUNC_QUALIFIER static vec call(vec const& x) { return detail::functor1::call(round, x); } }; template struct compute_mod { GLM_FUNC_QUALIFIER static vec call(vec const& a, vec const& b) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'mod' only accept floating-point inputs. Include for integer inputs."); return a - b * floor(a / b); } }; template struct compute_min_vector { GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y) { return detail::functor2::call(min, x, y); } }; template struct compute_max_vector { GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& y) { return detail::functor2::call(max, x, y); } }; template struct compute_clamp_vector { GLM_FUNC_QUALIFIER static vec call(vec const& x, vec const& minVal, vec const& maxVal) { return min(max(x, minVal), maxVal); } }; template struct compute_step_vector { GLM_FUNC_QUALIFIER static vec call(vec const& edge, vec const& x) { return mix(vec(1), vec(0), glm::lessThan(x, edge)); } }; template struct compute_smoothstep_vector { GLM_FUNC_QUALIFIER static vec call(vec const& edge0, vec const& edge1, vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'smoothstep' only accept floating-point inputs"); vec const tmp(clamp((x - edge0) / (edge1 - edge0), static_cast(0), static_cast(1))); return tmp * tmp * (static_cast(3) - static_cast(2) * tmp); } }; }//namespace detail template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genFIType abs(genFIType x) { return detail::compute_abs::is_signed>::call(x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec abs(vec const& x) { return detail::compute_abs_vector::value>::call(x); } // sign // fast and works for any type template GLM_FUNC_QUALIFIER genFIType sign(genFIType x) { GLM_STATIC_ASSERT( std::numeric_limits::is_iec559 || (std::numeric_limits::is_signed && std::numeric_limits::is_integer), "'sign' only accept signed inputs"); return detail::compute_sign<1, genFIType, defaultp, std::numeric_limits::is_iec559, highp>::call(vec<1, genFIType>(x)).x; } template GLM_FUNC_QUALIFIER vec sign(vec const& x) { GLM_STATIC_ASSERT( std::numeric_limits::is_iec559 || (std::numeric_limits::is_signed && std::numeric_limits::is_integer), "'sign' only accept signed inputs"); return detail::compute_sign::is_iec559, detail::is_aligned::value>::call(x); } // floor using ::std::floor; template GLM_FUNC_QUALIFIER vec floor(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'floor' only accept floating-point inputs."); return detail::compute_floor::value>::call(x); } template GLM_FUNC_QUALIFIER vec trunc(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'trunc' only accept floating-point inputs"); return detail::compute_trunc::value>::call(x); } template GLM_FUNC_QUALIFIER vec round(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'round' only accept floating-point inputs"); return detail::compute_round::value>::call(x); } /* // roundEven template GLM_FUNC_QUALIFIER genType roundEven(genType const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'roundEven' only accept floating-point inputs"); return genType(int(x + genType(int(x) % 2))); } */ // roundEven template GLM_FUNC_QUALIFIER genType roundEven(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'roundEven' only accept floating-point inputs"); int Integer = static_cast(x); genType IntegerPart = static_cast(Integer); genType FractionalPart = fract(x); if(FractionalPart > static_cast(0.5) || FractionalPart < static_cast(0.5)) { return round(x); } else if((Integer % 2) == 0) { return IntegerPart; } else if(x <= static_cast(0)) // Work around... { return IntegerPart - static_cast(1); } else { return IntegerPart + static_cast(1); } //else // Bug on MinGW 4.5.2 //{ // return mix(IntegerPart + genType(-1), IntegerPart + genType(1), x <= genType(0)); //} } template GLM_FUNC_QUALIFIER vec roundEven(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'roundEven' only accept floating-point inputs"); return detail::functor1::call(roundEven, x); } // ceil using ::std::ceil; template GLM_FUNC_QUALIFIER vec ceil(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'ceil' only accept floating-point inputs"); return detail::compute_ceil::value>::call(x); } // fract template GLM_FUNC_QUALIFIER genType fract(genType x) { return fract(vec<1, genType>(x)).x; } template GLM_FUNC_QUALIFIER vec fract(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fract' only accept floating-point inputs"); return detail::compute_fract::value>::call(x); } // mod template GLM_FUNC_QUALIFIER genType mod(genType x, genType y) { # if GLM_COMPILER & GLM_COMPILER_CUDA // Another Cuda compiler bug https://github.com/g-truc/glm/issues/530 vec<1, genType, defaultp> Result(mod(vec<1, genType, defaultp>(x), y)); return Result.x; # else return mod(vec<1, genType, defaultp>(x), y).x; # endif } template GLM_FUNC_QUALIFIER vec mod(vec const& x, T y) { return detail::compute_mod::value>::call(x, vec(y)); } template GLM_FUNC_QUALIFIER vec mod(vec const& x, vec const& y) { return detail::compute_mod::value>::call(x, y); } // modf template GLM_FUNC_QUALIFIER genType modf(genType x, genType & i) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'modf' only accept floating-point inputs"); return std::modf(x, &i); } template GLM_FUNC_QUALIFIER vec<1, T, Q> modf(vec<1, T, Q> const& x, vec<1, T, Q> & i) { return vec<1, T, Q>( modf(x.x, i.x)); } template GLM_FUNC_QUALIFIER vec<2, T, Q> modf(vec<2, T, Q> const& x, vec<2, T, Q> & i) { return vec<2, T, Q>( modf(x.x, i.x), modf(x.y, i.y)); } template GLM_FUNC_QUALIFIER vec<3, T, Q> modf(vec<3, T, Q> const& x, vec<3, T, Q> & i) { return vec<3, T, Q>( modf(x.x, i.x), modf(x.y, i.y), modf(x.z, i.z)); } template GLM_FUNC_QUALIFIER vec<4, T, Q> modf(vec<4, T, Q> const& x, vec<4, T, Q> & i) { return vec<4, T, Q>( modf(x.x, i.x), modf(x.y, i.y), modf(x.z, i.z), modf(x.w, i.w)); } //// Only valid if (INT_MIN <= x-y <= INT_MAX) //// min(x,y) //r = y + ((x - y) & ((x - y) >> (sizeof(int) * //CHAR_BIT - 1))); //// max(x,y) //r = x - ((x - y) & ((x - y) >> (sizeof(int) * //CHAR_BIT - 1))); // min template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec min(vec const& a, T b) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'min' only accept floating-point or integer inputs"); return detail::compute_min_vector::value>::call(a, vec(b)); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec min(vec const& a, vec const& b) { return detail::compute_min_vector::value>::call(a, b); } // max template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec max(vec const& a, T b) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'max' only accept floating-point or integer inputs"); return detail::compute_max_vector::value>::call(a, vec(b)); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec max(vec const& a, vec const& b) { return detail::compute_max_vector::value>::call(a, b); } // clamp template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType clamp(genType x, genType minVal, genType maxVal) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'clamp' only accept floating-point or integer inputs"); return min(max(x, minVal), maxVal); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec clamp(vec const& x, T minVal, T maxVal) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'clamp' only accept floating-point or integer inputs"); return detail::compute_clamp_vector::value>::call(x, vec(minVal), vec(maxVal)); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec clamp(vec const& x, vec const& minVal, vec const& maxVal) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer, "'clamp' only accept floating-point or integer inputs"); return detail::compute_clamp_vector::value>::call(x, minVal, maxVal); } template GLM_FUNC_QUALIFIER genTypeT mix(genTypeT x, genTypeT y, genTypeU a) { return detail::compute_mix::call(x, y, a); } template GLM_FUNC_QUALIFIER vec mix(vec const& x, vec const& y, U a) { return detail::compute_mix_scalar::value>::call(x, y, a); } template GLM_FUNC_QUALIFIER vec mix(vec const& x, vec const& y, vec const& a) { return detail::compute_mix_vector::value>::call(x, y, a); } // step template GLM_FUNC_QUALIFIER genType step(genType edge, genType x) { return mix(static_cast(1), static_cast(0), x < edge); } template GLM_FUNC_QUALIFIER vec step(T edge, vec const& x) { return detail::compute_step_vector::value>::call(vec(edge), x); } template GLM_FUNC_QUALIFIER vec step(vec const& edge, vec const& x) { return detail::compute_step_vector::value>::call(edge, x); } // smoothstep template GLM_FUNC_QUALIFIER genType smoothstep(genType edge0, genType edge1, genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'smoothstep' only accept floating-point inputs"); genType const tmp(clamp((x - edge0) / (edge1 - edge0), genType(0), genType(1))); return tmp * tmp * (genType(3) - genType(2) * tmp); } template GLM_FUNC_QUALIFIER vec smoothstep(T edge0, T edge1, vec const& x) { return detail::compute_smoothstep_vector::value>::call(vec(edge0), vec(edge1), x); } template GLM_FUNC_QUALIFIER vec smoothstep(vec const& edge0, vec const& edge1, vec const& x) { return detail::compute_smoothstep_vector::value>::call(edge0, edge1, x); } # if GLM_HAS_CXX11_STL using std::isnan; # else template GLM_FUNC_QUALIFIER bool isnan(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isnan' only accept floating-point inputs"); # if GLM_HAS_CXX11_STL return std::isnan(x); # elif GLM_COMPILER & GLM_COMPILER_VC return _isnan(x) != 0; # elif GLM_COMPILER & GLM_COMPILER_INTEL # if GLM_PLATFORM & GLM_PLATFORM_WINDOWS return _isnan(x) != 0; # else return ::isnan(x) != 0; # endif # elif (GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG)) && (GLM_PLATFORM & GLM_PLATFORM_ANDROID) && __cplusplus < 201103L return _isnan(x) != 0; # elif GLM_COMPILER & GLM_COMPILER_CUDA return ::isnan(x) != 0; # else return std::isnan(x); # endif } # endif template GLM_FUNC_QUALIFIER vec isnan(vec const& v) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isnan' only accept floating-point inputs"); vec Result; for (length_t l = 0; l < v.length(); ++l) Result[l] = glm::isnan(v[l]); return Result; } # if GLM_HAS_CXX11_STL using std::isinf; # else template GLM_FUNC_QUALIFIER bool isinf(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isinf' only accept floating-point inputs"); # if GLM_HAS_CXX11_STL return std::isinf(x); # elif GLM_COMPILER & (GLM_COMPILER_INTEL | GLM_COMPILER_VC) # if(GLM_PLATFORM & GLM_PLATFORM_WINDOWS) return _fpclass(x) == _FPCLASS_NINF || _fpclass(x) == _FPCLASS_PINF; # else return ::isinf(x); # endif # elif GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG) # if(GLM_PLATFORM & GLM_PLATFORM_ANDROID && __cplusplus < 201103L) return _isinf(x) != 0; # else return std::isinf(x); # endif # elif GLM_COMPILER & GLM_COMPILER_CUDA // http://developer.download.nvidia.com/compute/cuda/4_2/rel/toolkit/docs/online/group__CUDA__MATH__DOUBLE_g13431dd2b40b51f9139cbb7f50c18fab.html#g13431dd2b40b51f9139cbb7f50c18fab return ::isinf(double(x)) != 0; # else return std::isinf(x); # endif } # endif template GLM_FUNC_QUALIFIER vec isinf(vec const& v) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isinf' only accept floating-point inputs"); vec Result; for (length_t l = 0; l < v.length(); ++l) Result[l] = glm::isinf(v[l]); return Result; } GLM_FUNC_QUALIFIER int floatBitsToInt(float const& v) { union { float in; int out; } u; u.in = v; return u.out; } template GLM_FUNC_QUALIFIER vec floatBitsToInt(vec const& v) { return reinterpret_cast&>(const_cast&>(v)); } GLM_FUNC_QUALIFIER uint floatBitsToUint(float const& v) { union { float in; uint out; } u; u.in = v; return u.out; } template GLM_FUNC_QUALIFIER vec floatBitsToUint(vec const& v) { return reinterpret_cast&>(const_cast&>(v)); } GLM_FUNC_QUALIFIER float intBitsToFloat(int const& v) { union { int in; float out; } u; u.in = v; return u.out; } template GLM_FUNC_QUALIFIER vec intBitsToFloat(vec const& v) { return reinterpret_cast&>(const_cast&>(v)); } GLM_FUNC_QUALIFIER float uintBitsToFloat(uint const& v) { union { uint in; float out; } u; u.in = v; return u.out; } template GLM_FUNC_QUALIFIER vec uintBitsToFloat(vec const& v) { return reinterpret_cast&>(const_cast&>(v)); } template GLM_FUNC_QUALIFIER genType fma(genType const& a, genType const& b, genType const& c) { return a * b + c; } template GLM_FUNC_QUALIFIER genType frexp(genType x, int& exp) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'frexp' only accept floating-point inputs"); return std::frexp(x, &exp); } template GLM_FUNC_QUALIFIER vec frexp(vec const& v, vec& exp) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'frexp' only accept floating-point inputs"); vec Result; for (length_t l = 0; l < v.length(); ++l) Result[l] = std::frexp(v[l], &exp[l]); return Result; } template GLM_FUNC_QUALIFIER genType ldexp(genType const& x, int const& exp) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'ldexp' only accept floating-point inputs"); return std::ldexp(x, exp); } template GLM_FUNC_QUALIFIER vec ldexp(vec const& v, vec const& exp) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'ldexp' only accept floating-point inputs"); vec Result; for (length_t l = 0; l < v.length(); ++l) Result[l] = std::ldexp(v[l], exp[l]); return Result; } }//namespace glm #if GLM_CONFIG_SIMD == GLM_ENABLE # include "func_common_simd.inl" #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/func_common_simd.inl000066400000000000000000000141331360521144700256040ustar00rootroot00000000000000/// @ref core /// @file glm/detail/func_common_simd.inl #if GLM_ARCH & GLM_ARCH_SSE2_BIT #include "../simd/common.h" #include namespace glm{ namespace detail { template struct compute_abs_vector<4, float, Q, true> { GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) { vec<4, float, Q> result; result.data = glm_vec4_abs(v.data); return result; } }; template struct compute_abs_vector<4, int, Q, true> { GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v) { vec<4, int, Q> result; result.data = glm_ivec4_abs(v.data); return result; } }; template struct compute_floor<4, float, Q, true> { GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) { vec<4, float, Q> result; result.data = glm_vec4_floor(v.data); return result; } }; template struct compute_ceil<4, float, Q, true> { GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) { vec<4, float, Q> result; result.data = glm_vec4_ceil(v.data); return result; } }; template struct compute_fract<4, float, Q, true> { GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) { vec<4, float, Q> result; result.data = glm_vec4_fract(v.data); return result; } }; template struct compute_round<4, float, Q, true> { GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) { vec<4, float, Q> result; result.data = glm_vec4_round(v.data); return result; } }; template struct compute_mod<4, float, Q, true> { GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& x, vec<4, float, Q> const& y) { vec<4, float, Q> result; result.data = glm_vec4_mod(x.data, y.data); return result; } }; template struct compute_min_vector<4, float, Q, true> { GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) { vec<4, float, Q> result; result.data = _mm_min_ps(v1.data, v2.data); return result; } }; template struct compute_min_vector<4, int, Q, true> { GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) { vec<4, int, Q> result; result.data = _mm_min_epi32(v1.data, v2.data); return result; } }; template struct compute_min_vector<4, uint, Q, true> { GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v1, vec<4, uint, Q> const& v2) { vec<4, uint, Q> result; result.data = _mm_min_epu32(v1.data, v2.data); return result; } }; template struct compute_max_vector<4, float, Q, true> { GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) { vec<4, float, Q> result; result.data = _mm_max_ps(v1.data, v2.data); return result; } }; template struct compute_max_vector<4, int, Q, true> { GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) { vec<4, int, Q> result; result.data = _mm_max_epi32(v1.data, v2.data); return result; } }; template struct compute_max_vector<4, uint, Q, true> { GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v1, vec<4, uint, Q> const& v2) { vec<4, uint, Q> result; result.data = _mm_max_epu32(v1.data, v2.data); return result; } }; template struct compute_clamp_vector<4, float, Q, true> { GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& x, vec<4, float, Q> const& minVal, vec<4, float, Q> const& maxVal) { vec<4, float, Q> result; result.data = _mm_min_ps(_mm_max_ps(x.data, minVal.data), maxVal.data); return result; } }; template struct compute_clamp_vector<4, int, Q, true> { GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& x, vec<4, int, Q> const& minVal, vec<4, int, Q> const& maxVal) { vec<4, int, Q> result; result.data = _mm_min_epi32(_mm_max_epi32(x.data, minVal.data), maxVal.data); return result; } }; template struct compute_clamp_vector<4, uint, Q, true> { GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& x, vec<4, uint, Q> const& minVal, vec<4, uint, Q> const& maxVal) { vec<4, uint, Q> result; result.data = _mm_min_epu32(_mm_max_epu32(x.data, minVal.data), maxVal.data); return result; } }; template struct compute_mix_vector<4, float, bool, Q, true> { GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& x, vec<4, float, Q> const& y, vec<4, bool, Q> const& a) { __m128i const Load = _mm_set_epi32(-static_cast(a.w), -static_cast(a.z), -static_cast(a.y), -static_cast(a.x)); __m128 const Mask = _mm_castsi128_ps(Load); vec<4, float, Q> Result; # if 0 && GLM_ARCH & GLM_ARCH_AVX Result.data = _mm_blendv_ps(x.data, y.data, Mask); # else Result.data = _mm_or_ps(_mm_and_ps(Mask, y.data), _mm_andnot_ps(Mask, x.data)); # endif return Result; } }; /* FIXME template struct compute_step_vector { GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& edge, vec<4, float, Q> const& x) { vec<4, float, Q> Result; result.data = glm_vec4_step(edge.data, x.data); return result; } }; */ template struct compute_smoothstep_vector<4, float, Q, true> { GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& edge0, vec<4, float, Q> const& edge1, vec<4, float, Q> const& x) { vec<4, float, Q> Result; Result.data = glm_vec4_smoothstep(edge0.data, edge1.data, x.data); return Result; } }; }//namespace detail }//namespace glm #endif//GLM_ARCH & GLM_ARCH_SSE2_BIT connectome-workbench-1.4.2/src/GLMath/glm/detail/func_exponential.inl000066400000000000000000000106241360521144700256270ustar00rootroot00000000000000/// @ref core /// @file glm/detail/func_exponential.inl #include "../vector_relational.hpp" #include "_vectorize.hpp" #include #include #include namespace glm{ namespace detail { # if GLM_HAS_CXX11_STL using std::log2; # else template genType log2(genType Value) { return std::log(Value) * static_cast(1.4426950408889634073599246810019); } # endif template struct compute_log2 { GLM_FUNC_QUALIFIER static vec call(vec const& v) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'log2' only accept floating-point inputs. Include for integer inputs."); return detail::functor1::call(log2, v); } }; template struct compute_sqrt { GLM_FUNC_QUALIFIER static vec call(vec const& x) { return detail::functor1::call(std::sqrt, x); } }; template struct compute_inversesqrt { GLM_FUNC_QUALIFIER static vec call(vec const& x) { return static_cast(1) / sqrt(x); } }; template struct compute_inversesqrt { GLM_FUNC_QUALIFIER static vec call(vec const& x) { vec tmp(x); vec xhalf(tmp * 0.5f); vec* p = reinterpret_cast*>(const_cast*>(&x)); vec i = vec(0x5f375a86) - (*p >> vec(1)); vec* ptmp = reinterpret_cast*>(&i); tmp = *ptmp; tmp = tmp * (1.5f - xhalf * tmp * tmp); return tmp; } }; }//namespace detail // pow using std::pow; template GLM_FUNC_QUALIFIER vec pow(vec const& base, vec const& exponent) { return detail::functor2::call(pow, base, exponent); } // exp using std::exp; template GLM_FUNC_QUALIFIER vec exp(vec const& x) { return detail::functor1::call(exp, x); } // log using std::log; template GLM_FUNC_QUALIFIER vec log(vec const& x) { return detail::functor1::call(log, x); } # if GLM_HAS_CXX11_STL using std::exp2; # else //exp2, ln2 = 0.69314718055994530941723212145818f template GLM_FUNC_QUALIFIER genType exp2(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'exp2' only accept floating-point inputs"); return std::exp(static_cast(0.69314718055994530941723212145818) * x); } # endif template GLM_FUNC_QUALIFIER vec exp2(vec const& x) { return detail::functor1::call(exp2, x); } // log2, ln2 = 0.69314718055994530941723212145818f template GLM_FUNC_QUALIFIER genType log2(genType x) { return log2(vec<1, genType>(x)).x; } template GLM_FUNC_QUALIFIER vec log2(vec const& x) { return detail::compute_log2::is_iec559, detail::is_aligned::value>::call(x); } // sqrt using std::sqrt; template GLM_FUNC_QUALIFIER vec sqrt(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'sqrt' only accept floating-point inputs"); return detail::compute_sqrt::value>::call(x); } // inversesqrt template GLM_FUNC_QUALIFIER genType inversesqrt(genType x) { return static_cast(1) / sqrt(x); } template GLM_FUNC_QUALIFIER vec inversesqrt(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'inversesqrt' only accept floating-point inputs"); return detail::compute_inversesqrt::value>::call(x); } }//namespace glm #if GLM_CONFIG_SIMD == GLM_ENABLE # include "func_exponential_simd.inl" #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/func_exponential_simd.inl000066400000000000000000000015221360521144700266400ustar00rootroot00000000000000/// @ref core /// @file glm/detail/func_exponential_simd.inl #include "../simd/exponential.h" #if GLM_ARCH & GLM_ARCH_SSE2_BIT namespace glm{ namespace detail { template struct compute_sqrt<4, float, Q, true> { GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) { vec<4, float, Q> Result; Result.data = _mm_sqrt_ps(v.data); return Result; } }; # if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE template<> struct compute_sqrt<4, float, aligned_lowp, true> { GLM_FUNC_QUALIFIER static vec<4, float, aligned_lowp> call(vec<4, float, aligned_lowp> const& v) { vec<4, float, aligned_lowp> Result; Result.data = glm_vec4_sqrt_lowp(v.data); return Result; } }; # endif }//namespace detail }//namespace glm #endif//GLM_ARCH & GLM_ARCH_SSE2_BIT connectome-workbench-1.4.2/src/GLMath/glm/detail/func_geometric.inl000066400000000000000000000170161360521144700252610ustar00rootroot00000000000000#include "../exponential.hpp" #include "../common.hpp" namespace glm{ namespace detail { template struct compute_length { GLM_FUNC_QUALIFIER static T call(vec const& v) { return sqrt(dot(v, v)); } }; template struct compute_distance { GLM_FUNC_QUALIFIER static T call(vec const& p0, vec const& p1) { return length(p1 - p0); } }; template struct compute_dot{}; template struct compute_dot, T, Aligned> { GLM_FUNC_QUALIFIER static T call(vec<1, T, Q> const& a, vec<1, T, Q> const& b) { return a.x * b.x; } }; template struct compute_dot, T, Aligned> { GLM_FUNC_QUALIFIER static T call(vec<2, T, Q> const& a, vec<2, T, Q> const& b) { vec<2, T, Q> tmp(a * b); return tmp.x + tmp.y; } }; template struct compute_dot, T, Aligned> { GLM_FUNC_QUALIFIER static T call(vec<3, T, Q> const& a, vec<3, T, Q> const& b) { vec<3, T, Q> tmp(a * b); return tmp.x + tmp.y + tmp.z; } }; template struct compute_dot, T, Aligned> { GLM_FUNC_QUALIFIER static T call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { vec<4, T, Q> tmp(a * b); return (tmp.x + tmp.y) + (tmp.z + tmp.w); } }; template struct compute_cross { GLM_FUNC_QUALIFIER static vec<3, T, Q> call(vec<3, T, Q> const& x, vec<3, T, Q> const& y) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'cross' accepts only floating-point inputs"); return vec<3, T, Q>( x.y * y.z - y.y * x.z, x.z * y.x - y.z * x.x, x.x * y.y - y.x * x.y); } }; template struct compute_normalize { GLM_FUNC_QUALIFIER static vec call(vec const& v) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'normalize' accepts only floating-point inputs"); return v * inversesqrt(dot(v, v)); } }; template struct compute_faceforward { GLM_FUNC_QUALIFIER static vec call(vec const& N, vec const& I, vec const& Nref) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'normalize' accepts only floating-point inputs"); return dot(Nref, I) < static_cast(0) ? N : -N; } }; template struct compute_reflect { GLM_FUNC_QUALIFIER static vec call(vec const& I, vec const& N) { return I - N * dot(N, I) * static_cast(2); } }; template struct compute_refract { GLM_FUNC_QUALIFIER static vec call(vec const& I, vec const& N, T eta) { T const dotValue(dot(N, I)); T const k(static_cast(1) - eta * eta * (static_cast(1) - dotValue * dotValue)); vec const Result = (k >= static_cast(0)) ? (eta * I - (eta * dotValue + std::sqrt(k)) * N) : vec(0); return Result; } }; }//namespace detail // length template GLM_FUNC_QUALIFIER genType length(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'length' accepts only floating-point inputs"); return abs(x); } template GLM_FUNC_QUALIFIER T length(vec const& v) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'length' accepts only floating-point inputs"); return detail::compute_length::value>::call(v); } // distance template GLM_FUNC_QUALIFIER genType distance(genType const& p0, genType const& p1) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'distance' accepts only floating-point inputs"); return length(p1 - p0); } template GLM_FUNC_QUALIFIER T distance(vec const& p0, vec const& p1) { return detail::compute_distance::value>::call(p0, p1); } // dot template GLM_FUNC_QUALIFIER T dot(T x, T y) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'dot' accepts only floating-point inputs"); return x * y; } template GLM_FUNC_QUALIFIER T dot(vec const& x, vec const& y) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'dot' accepts only floating-point inputs"); return detail::compute_dot, T, detail::is_aligned::value>::call(x, y); } // cross template GLM_FUNC_QUALIFIER vec<3, T, Q> cross(vec<3, T, Q> const& x, vec<3, T, Q> const& y) { return detail::compute_cross::value>::call(x, y); } /* // normalize template GLM_FUNC_QUALIFIER genType normalize(genType const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'normalize' accepts only floating-point inputs"); return x < genType(0) ? genType(-1) : genType(1); } */ template GLM_FUNC_QUALIFIER vec normalize(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'normalize' accepts only floating-point inputs"); return detail::compute_normalize::value>::call(x); } // faceforward template GLM_FUNC_QUALIFIER genType faceforward(genType const& N, genType const& I, genType const& Nref) { return dot(Nref, I) < static_cast(0) ? N : -N; } template GLM_FUNC_QUALIFIER vec faceforward(vec const& N, vec const& I, vec const& Nref) { return detail::compute_faceforward::value>::call(N, I, Nref); } // reflect template GLM_FUNC_QUALIFIER genType reflect(genType const& I, genType const& N) { return I - N * dot(N, I) * genType(2); } template GLM_FUNC_QUALIFIER vec reflect(vec const& I, vec const& N) { return detail::compute_reflect::value>::call(I, N); } // refract template GLM_FUNC_QUALIFIER genType refract(genType const& I, genType const& N, genType eta) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'refract' accepts only floating-point inputs"); genType const dotValue(dot(N, I)); genType const k(static_cast(1) - eta * eta * (static_cast(1) - dotValue * dotValue)); return (eta * I - (eta * dotValue + sqrt(k)) * N) * static_cast(k >= static_cast(0)); } template GLM_FUNC_QUALIFIER vec refract(vec const& I, vec const& N, T eta) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'refract' accepts only floating-point inputs"); return detail::compute_refract::value>::call(I, N, eta); } }//namespace glm #if GLM_CONFIG_SIMD == GLM_ENABLE # include "func_geometric_simd.inl" #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/func_geometric_simd.inl000066400000000000000000000050731360521144700262750ustar00rootroot00000000000000/// @ref core /// @file glm/detail/func_geometric_simd.inl #include "../simd/geometric.h" #if GLM_ARCH & GLM_ARCH_SSE2_BIT namespace glm{ namespace detail { template struct compute_length<4, float, Q, true> { GLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& v) { return _mm_cvtss_f32(glm_vec4_length(v.data)); } }; template struct compute_distance<4, float, Q, true> { GLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& p0, vec<4, float, Q> const& p1) { return _mm_cvtss_f32(glm_vec4_distance(p0.data, p1.data)); } }; template struct compute_dot, float, true> { GLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& x, vec<4, float, Q> const& y) { return _mm_cvtss_f32(glm_vec1_dot(x.data, y.data)); } }; template struct compute_cross { GLM_FUNC_QUALIFIER static vec<3, float, Q> call(vec<3, float, Q> const& a, vec<3, float, Q> const& b) { __m128 const set0 = _mm_set_ps(0.0f, a.z, a.y, a.x); __m128 const set1 = _mm_set_ps(0.0f, b.z, b.y, b.x); __m128 const xpd0 = glm_vec4_cross(set0, set1); vec<4, float, Q> Result; Result.data = xpd0; return vec<3, float, Q>(Result); } }; template struct compute_normalize<4, float, Q, true> { GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v) { vec<4, float, Q> Result; Result.data = glm_vec4_normalize(v.data); return Result; } }; template struct compute_faceforward<4, float, Q, true> { GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& N, vec<4, float, Q> const& I, vec<4, float, Q> const& Nref) { vec<4, float, Q> Result; Result.data = glm_vec4_faceforward(N.data, I.data, Nref.data); return Result; } }; template struct compute_reflect<4, float, Q, true> { GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& I, vec<4, float, Q> const& N) { vec<4, float, Q> Result; Result.data = glm_vec4_reflect(I.data, N.data); return Result; } }; template struct compute_refract<4, float, Q, true> { GLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& I, vec<4, float, Q> const& N, float eta) { vec<4, float, Q> Result; Result.data = glm_vec4_refract(I.data, N.data, _mm_set1_ps(eta)); return Result; } }; }//namespace detail }//namespace glm #endif//GLM_ARCH & GLM_ARCH_SSE2_BIT connectome-workbench-1.4.2/src/GLMath/glm/detail/func_integer.inl000066400000000000000000000360061360521144700247400ustar00rootroot00000000000000/// @ref core #include "_vectorize.hpp" #if(GLM_ARCH & GLM_ARCH_X86 && GLM_COMPILER & GLM_COMPILER_VC) # include # pragma intrinsic(_BitScanReverse) #endif//(GLM_ARCH & GLM_ARCH_X86 && GLM_COMPILER & GLM_COMPILER_VC) #include #if !GLM_HAS_EXTENDED_INTEGER_TYPE # if GLM_COMPILER & GLM_COMPILER_GCC # pragma GCC diagnostic ignored "-Wlong-long" # endif # if (GLM_COMPILER & GLM_COMPILER_CLANG) # pragma clang diagnostic ignored "-Wc++11-long-long" # endif #endif namespace glm{ namespace detail { template GLM_FUNC_QUALIFIER T mask(T Bits) { return Bits >= static_cast(sizeof(T) * 8) ? ~static_cast(0) : (static_cast(1) << Bits) - static_cast(1); } template struct compute_bitfieldReverseStep { GLM_FUNC_QUALIFIER static vec call(vec const& v, T, T) { return v; } }; template struct compute_bitfieldReverseStep { GLM_FUNC_QUALIFIER static vec call(vec const& v, T Mask, T Shift) { return (v & Mask) << Shift | (v & (~Mask)) >> Shift; } }; template struct compute_bitfieldBitCountStep { GLM_FUNC_QUALIFIER static vec call(vec const& v, T, T) { return v; } }; template struct compute_bitfieldBitCountStep { GLM_FUNC_QUALIFIER static vec call(vec const& v, T Mask, T Shift) { return (v & Mask) + ((v >> Shift) & Mask); } }; template struct compute_findLSB { GLM_FUNC_QUALIFIER static int call(genIUType Value) { if(Value == 0) return -1; return glm::bitCount(~Value & (Value - static_cast(1))); } }; # if GLM_HAS_BITSCAN_WINDOWS template struct compute_findLSB { GLM_FUNC_QUALIFIER static int call(genIUType Value) { unsigned long Result(0); unsigned char IsNotNull = _BitScanForward(&Result, *reinterpret_cast(&Value)); return IsNotNull ? int(Result) : -1; } }; # if !((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_MODEL == GLM_MODEL_32)) template struct compute_findLSB { GLM_FUNC_QUALIFIER static int call(genIUType Value) { unsigned long Result(0); unsigned char IsNotNull = _BitScanForward64(&Result, *reinterpret_cast(&Value)); return IsNotNull ? int(Result) : -1; } }; # endif # endif//GLM_HAS_BITSCAN_WINDOWS template struct compute_findMSB_step_vec { GLM_FUNC_QUALIFIER static vec call(vec const& x, T Shift) { return x | (x >> Shift); } }; template struct compute_findMSB_step_vec { GLM_FUNC_QUALIFIER static vec call(vec const& x, T) { return x; } }; template struct compute_findMSB_vec { GLM_FUNC_QUALIFIER static vec call(vec const& v) { vec x(v); x = compute_findMSB_step_vec= 8>::call(x, static_cast( 1)); x = compute_findMSB_step_vec= 8>::call(x, static_cast( 2)); x = compute_findMSB_step_vec= 8>::call(x, static_cast( 4)); x = compute_findMSB_step_vec= 16>::call(x, static_cast( 8)); x = compute_findMSB_step_vec= 32>::call(x, static_cast(16)); x = compute_findMSB_step_vec= 64>::call(x, static_cast(32)); return vec(sizeof(T) * 8 - 1) - glm::bitCount(~x); } }; # if GLM_HAS_BITSCAN_WINDOWS template GLM_FUNC_QUALIFIER int compute_findMSB_32(genIUType Value) { unsigned long Result(0); unsigned char IsNotNull = _BitScanReverse(&Result, *reinterpret_cast(&Value)); return IsNotNull ? int(Result) : -1; } template struct compute_findMSB_vec { GLM_FUNC_QUALIFIER static vec call(vec const& x) { return detail::functor1::call(compute_findMSB_32, x); } }; # if !((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_MODEL == GLM_MODEL_32)) template GLM_FUNC_QUALIFIER int compute_findMSB_64(genIUType Value) { unsigned long Result(0); unsigned char IsNotNull = _BitScanReverse64(&Result, *reinterpret_cast(&Value)); return IsNotNull ? int(Result) : -1; } template struct compute_findMSB_vec { GLM_FUNC_QUALIFIER static vec call(vec const& x) { return detail::functor1::call(compute_findMSB_64, x); } }; # endif # endif//GLM_HAS_BITSCAN_WINDOWS }//namespace detail // uaddCarry GLM_FUNC_QUALIFIER uint uaddCarry(uint const& x, uint const& y, uint & Carry) { detail::uint64 const Value64(static_cast(x) + static_cast(y)); detail::uint64 const Max32((static_cast(1) << static_cast(32)) - static_cast(1)); Carry = Value64 > Max32 ? 1u : 0u; return static_cast(Value64 % (Max32 + static_cast(1))); } template GLM_FUNC_QUALIFIER vec uaddCarry(vec const& x, vec const& y, vec& Carry) { vec Value64(vec(x) + vec(y)); vec Max32((static_cast(1) << static_cast(32)) - static_cast(1)); Carry = mix(vec(0), vec(1), greaterThan(Value64, Max32)); return vec(Value64 % (Max32 + static_cast(1))); } // usubBorrow GLM_FUNC_QUALIFIER uint usubBorrow(uint const& x, uint const& y, uint & Borrow) { Borrow = x >= y ? static_cast(0) : static_cast(1); if(y >= x) return y - x; else return static_cast((static_cast(1) << static_cast(32)) + (static_cast(y) - static_cast(x))); } template GLM_FUNC_QUALIFIER vec usubBorrow(vec const& x, vec const& y, vec& Borrow) { Borrow = mix(vec(1), vec(0), greaterThanEqual(x, y)); vec const YgeX(y - x); vec const XgeY(vec((static_cast(1) << static_cast(32)) + (vec(y) - vec(x)))); return mix(XgeY, YgeX, greaterThanEqual(y, x)); } // umulExtended GLM_FUNC_QUALIFIER void umulExtended(uint const& x, uint const& y, uint & msb, uint & lsb) { detail::uint64 Value64 = static_cast(x) * static_cast(y); msb = static_cast(Value64 >> static_cast(32)); lsb = static_cast(Value64); } template GLM_FUNC_QUALIFIER void umulExtended(vec const& x, vec const& y, vec& msb, vec& lsb) { vec Value64(vec(x) * vec(y)); msb = vec(Value64 >> static_cast(32)); lsb = vec(Value64); } // imulExtended GLM_FUNC_QUALIFIER void imulExtended(int x, int y, int& msb, int& lsb) { detail::int64 Value64 = static_cast(x) * static_cast(y); msb = static_cast(Value64 >> static_cast(32)); lsb = static_cast(Value64); } template GLM_FUNC_QUALIFIER void imulExtended(vec const& x, vec const& y, vec& msb, vec& lsb) { vec Value64(vec(x) * vec(y)); lsb = vec(Value64 & static_cast(0xFFFFFFFF)); msb = vec((Value64 >> static_cast(32)) & static_cast(0xFFFFFFFF)); } // bitfieldExtract template GLM_FUNC_QUALIFIER genIUType bitfieldExtract(genIUType Value, int Offset, int Bits) { return bitfieldExtract(vec<1, genIUType>(Value), Offset, Bits).x; } template GLM_FUNC_QUALIFIER vec bitfieldExtract(vec const& Value, int Offset, int Bits) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldExtract' only accept integer inputs"); return (Value >> static_cast(Offset)) & static_cast(detail::mask(Bits)); } // bitfieldInsert template GLM_FUNC_QUALIFIER genIUType bitfieldInsert(genIUType const& Base, genIUType const& Insert, int Offset, int Bits) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldInsert' only accept integer values"); return bitfieldInsert(vec<1, genIUType>(Base), vec<1, genIUType>(Insert), Offset, Bits).x; } template GLM_FUNC_QUALIFIER vec bitfieldInsert(vec const& Base, vec const& Insert, int Offset, int Bits) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldInsert' only accept integer values"); T const Mask = static_cast(detail::mask(Bits) << Offset); return (Base & ~Mask) | ((Insert << static_cast(Offset)) & Mask); } // bitfieldReverse template GLM_FUNC_QUALIFIER genIUType bitfieldReverse(genIUType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldReverse' only accept integer values"); return bitfieldReverse(glm::vec<1, genIUType, glm::defaultp>(x)).x; } template GLM_FUNC_QUALIFIER vec bitfieldReverse(vec const& v) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldReverse' only accept integer values"); vec x(v); x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 2>::call(x, static_cast(0x5555555555555555ull), static_cast( 1)); x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 4>::call(x, static_cast(0x3333333333333333ull), static_cast( 2)); x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 8>::call(x, static_cast(0x0F0F0F0F0F0F0F0Full), static_cast( 4)); x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 16>::call(x, static_cast(0x00FF00FF00FF00FFull), static_cast( 8)); x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 32>::call(x, static_cast(0x0000FFFF0000FFFFull), static_cast(16)); x = detail::compute_bitfieldReverseStep::value, sizeof(T) * 8>= 64>::call(x, static_cast(0x00000000FFFFFFFFull), static_cast(32)); return x; } // bitCount template GLM_FUNC_QUALIFIER int bitCount(genIUType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitCount' only accept integer values"); return bitCount(glm::vec<1, genIUType, glm::defaultp>(x)).x; } template GLM_FUNC_QUALIFIER vec bitCount(vec const& v) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitCount' only accept integer values"); # if GLM_COMPILER & GLM_COMPILER_VC # pragma warning(push) # pragma warning(disable : 4310) //cast truncates constant value # endif vec::type, Q> x(*reinterpret_cast::type, Q> const *>(&v)); x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 2>::call(x, typename detail::make_unsigned::type(0x5555555555555555ull), typename detail::make_unsigned::type( 1)); x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 4>::call(x, typename detail::make_unsigned::type(0x3333333333333333ull), typename detail::make_unsigned::type( 2)); x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 8>::call(x, typename detail::make_unsigned::type(0x0F0F0F0F0F0F0F0Full), typename detail::make_unsigned::type( 4)); x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 16>::call(x, typename detail::make_unsigned::type(0x00FF00FF00FF00FFull), typename detail::make_unsigned::type( 8)); x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 32>::call(x, typename detail::make_unsigned::type(0x0000FFFF0000FFFFull), typename detail::make_unsigned::type(16)); x = detail::compute_bitfieldBitCountStep::type, Q, detail::is_aligned::value, sizeof(T) * 8>= 64>::call(x, typename detail::make_unsigned::type(0x00000000FFFFFFFFull), typename detail::make_unsigned::type(32)); return vec(x); # if GLM_COMPILER & GLM_COMPILER_VC # pragma warning(pop) # endif } // findLSB template GLM_FUNC_QUALIFIER int findLSB(genIUType Value) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findLSB' only accept integer values"); return detail::compute_findLSB::call(Value); } template GLM_FUNC_QUALIFIER vec findLSB(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findLSB' only accept integer values"); return detail::functor1::call(findLSB, x); } // findMSB template GLM_FUNC_QUALIFIER int findMSB(genIUType v) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findMSB' only accept integer values"); return findMSB(vec<1, genIUType>(v)).x; } template GLM_FUNC_QUALIFIER vec findMSB(vec const& v) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findMSB' only accept integer values"); return detail::compute_findMSB_vec::call(v); } }//namespace glm #if GLM_CONFIG_SIMD == GLM_ENABLE # include "func_integer_simd.inl" #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/func_integer_simd.inl000066400000000000000000000032431360521144700257510ustar00rootroot00000000000000#include "../simd/integer.h" #if GLM_ARCH & GLM_ARCH_SSE2_BIT namespace glm{ namespace detail { template struct compute_bitfieldReverseStep<4, uint, Q, true, true> { GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v, uint Mask, uint Shift) { __m128i const set0 = v.data; __m128i const set1 = _mm_set1_epi32(static_cast(Mask)); __m128i const and1 = _mm_and_si128(set0, set1); __m128i const sft1 = _mm_slli_epi32(and1, Shift); __m128i const set2 = _mm_andnot_si128(set0, _mm_set1_epi32(-1)); __m128i const and2 = _mm_and_si128(set0, set2); __m128i const sft2 = _mm_srai_epi32(and2, Shift); __m128i const or0 = _mm_or_si128(sft1, sft2); return or0; } }; template struct compute_bitfieldBitCountStep<4, uint, Q, true, true> { GLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v, uint Mask, uint Shift) { __m128i const set0 = v.data; __m128i const set1 = _mm_set1_epi32(static_cast(Mask)); __m128i const and0 = _mm_and_si128(set0, set1); __m128i const sft0 = _mm_slli_epi32(set0, Shift); __m128i const and1 = _mm_and_si128(sft0, set1); __m128i const add0 = _mm_add_epi32(and0, and1); return add0; } }; }//namespace detail # if GLM_ARCH & GLM_ARCH_AVX_BIT template<> GLM_FUNC_QUALIFIER int bitCount(uint x) { return _mm_popcnt_u32(x); } # if(GLM_MODEL == GLM_MODEL_64) template<> GLM_FUNC_QUALIFIER int bitCount(detail::uint64 x) { return static_cast(_mm_popcnt_u64(x)); } # endif//GLM_MODEL # endif//GLM_ARCH }//namespace glm #endif//GLM_ARCH & GLM_ARCH_SSE2_BIT connectome-workbench-1.4.2/src/GLMath/glm/detail/func_matrix.inl000066400000000000000000000315121360521144700246040ustar00rootroot00000000000000#include "../geometric.hpp" #include namespace glm{ namespace detail { template struct compute_matrixCompMult { GLM_FUNC_QUALIFIER static mat call(mat const& x, mat const& y) { mat Result; for(length_t i = 0; i < Result.length(); ++i) Result[i] = x[i] * y[i]; return Result; } }; template struct compute_transpose{}; template struct compute_transpose<2, 2, T, Q, Aligned> { GLM_FUNC_QUALIFIER static mat<2, 2, T, Q> call(mat<2, 2, T, Q> const& m) { mat<2, 2, T, Q> Result; Result[0][0] = m[0][0]; Result[0][1] = m[1][0]; Result[1][0] = m[0][1]; Result[1][1] = m[1][1]; return Result; } }; template struct compute_transpose<2, 3, T, Q, Aligned> { GLM_FUNC_QUALIFIER static mat<3, 2, T, Q> call(mat<2, 3, T, Q> const& m) { mat<3,2, T, Q> Result; Result[0][0] = m[0][0]; Result[0][1] = m[1][0]; Result[1][0] = m[0][1]; Result[1][1] = m[1][1]; Result[2][0] = m[0][2]; Result[2][1] = m[1][2]; return Result; } }; template struct compute_transpose<2, 4, T, Q, Aligned> { GLM_FUNC_QUALIFIER static mat<4, 2, T, Q> call(mat<2, 4, T, Q> const& m) { mat<4, 2, T, Q> Result; Result[0][0] = m[0][0]; Result[0][1] = m[1][0]; Result[1][0] = m[0][1]; Result[1][1] = m[1][1]; Result[2][0] = m[0][2]; Result[2][1] = m[1][2]; Result[3][0] = m[0][3]; Result[3][1] = m[1][3]; return Result; } }; template struct compute_transpose<3, 2, T, Q, Aligned> { GLM_FUNC_QUALIFIER static mat<2, 3, T, Q> call(mat<3, 2, T, Q> const& m) { mat<2, 3, T, Q> Result; Result[0][0] = m[0][0]; Result[0][1] = m[1][0]; Result[0][2] = m[2][0]; Result[1][0] = m[0][1]; Result[1][1] = m[1][1]; Result[1][2] = m[2][1]; return Result; } }; template struct compute_transpose<3, 3, T, Q, Aligned> { GLM_FUNC_QUALIFIER static mat<3, 3, T, Q> call(mat<3, 3, T, Q> const& m) { mat<3, 3, T, Q> Result; Result[0][0] = m[0][0]; Result[0][1] = m[1][0]; Result[0][2] = m[2][0]; Result[1][0] = m[0][1]; Result[1][1] = m[1][1]; Result[1][2] = m[2][1]; Result[2][0] = m[0][2]; Result[2][1] = m[1][2]; Result[2][2] = m[2][2]; return Result; } }; template struct compute_transpose<3, 4, T, Q, Aligned> { GLM_FUNC_QUALIFIER static mat<4, 3, T, Q> call(mat<3, 4, T, Q> const& m) { mat<4, 3, T, Q> Result; Result[0][0] = m[0][0]; Result[0][1] = m[1][0]; Result[0][2] = m[2][0]; Result[1][0] = m[0][1]; Result[1][1] = m[1][1]; Result[1][2] = m[2][1]; Result[2][0] = m[0][2]; Result[2][1] = m[1][2]; Result[2][2] = m[2][2]; Result[3][0] = m[0][3]; Result[3][1] = m[1][3]; Result[3][2] = m[2][3]; return Result; } }; template struct compute_transpose<4, 2, T, Q, Aligned> { GLM_FUNC_QUALIFIER static mat<2, 4, T, Q> call(mat<4, 2, T, Q> const& m) { mat<2, 4, T, Q> Result; Result[0][0] = m[0][0]; Result[0][1] = m[1][0]; Result[0][2] = m[2][0]; Result[0][3] = m[3][0]; Result[1][0] = m[0][1]; Result[1][1] = m[1][1]; Result[1][2] = m[2][1]; Result[1][3] = m[3][1]; return Result; } }; template struct compute_transpose<4, 3, T, Q, Aligned> { GLM_FUNC_QUALIFIER static mat<3, 4, T, Q> call(mat<4, 3, T, Q> const& m) { mat<3, 4, T, Q> Result; Result[0][0] = m[0][0]; Result[0][1] = m[1][0]; Result[0][2] = m[2][0]; Result[0][3] = m[3][0]; Result[1][0] = m[0][1]; Result[1][1] = m[1][1]; Result[1][2] = m[2][1]; Result[1][3] = m[3][1]; Result[2][0] = m[0][2]; Result[2][1] = m[1][2]; Result[2][2] = m[2][2]; Result[2][3] = m[3][2]; return Result; } }; template struct compute_transpose<4, 4, T, Q, Aligned> { GLM_FUNC_QUALIFIER static mat<4, 4, T, Q> call(mat<4, 4, T, Q> const& m) { mat<4, 4, T, Q> Result; Result[0][0] = m[0][0]; Result[0][1] = m[1][0]; Result[0][2] = m[2][0]; Result[0][3] = m[3][0]; Result[1][0] = m[0][1]; Result[1][1] = m[1][1]; Result[1][2] = m[2][1]; Result[1][3] = m[3][1]; Result[2][0] = m[0][2]; Result[2][1] = m[1][2]; Result[2][2] = m[2][2]; Result[2][3] = m[3][2]; Result[3][0] = m[0][3]; Result[3][1] = m[1][3]; Result[3][2] = m[2][3]; Result[3][3] = m[3][3]; return Result; } }; template struct compute_determinant{}; template struct compute_determinant<2, 2, T, Q, Aligned> { GLM_FUNC_QUALIFIER static T call(mat<2, 2, T, Q> const& m) { return m[0][0] * m[1][1] - m[1][0] * m[0][1]; } }; template struct compute_determinant<3, 3, T, Q, Aligned> { GLM_FUNC_QUALIFIER static T call(mat<3, 3, T, Q> const& m) { return + m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) - m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2]) + m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]); } }; template struct compute_determinant<4, 4, T, Q, Aligned> { GLM_FUNC_QUALIFIER static T call(mat<4, 4, T, Q> const& m) { T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; vec<4, T, Q> DetCof( + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02), - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04), + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05), - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05)); return m[0][0] * DetCof[0] + m[0][1] * DetCof[1] + m[0][2] * DetCof[2] + m[0][3] * DetCof[3]; } }; template struct compute_inverse{}; template struct compute_inverse<2, 2, T, Q, Aligned> { GLM_FUNC_QUALIFIER static mat<2, 2, T, Q> call(mat<2, 2, T, Q> const& m) { T OneOverDeterminant = static_cast(1) / ( + m[0][0] * m[1][1] - m[1][0] * m[0][1]); mat<2, 2, T, Q> Inverse( + m[1][1] * OneOverDeterminant, - m[0][1] * OneOverDeterminant, - m[1][0] * OneOverDeterminant, + m[0][0] * OneOverDeterminant); return Inverse; } }; template struct compute_inverse<3, 3, T, Q, Aligned> { GLM_FUNC_QUALIFIER static mat<3, 3, T, Q> call(mat<3, 3, T, Q> const& m) { T OneOverDeterminant = static_cast(1) / ( + m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) - m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2]) + m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2])); mat<3, 3, T, Q> Inverse; Inverse[0][0] = + (m[1][1] * m[2][2] - m[2][1] * m[1][2]) * OneOverDeterminant; Inverse[1][0] = - (m[1][0] * m[2][2] - m[2][0] * m[1][2]) * OneOverDeterminant; Inverse[2][0] = + (m[1][0] * m[2][1] - m[2][0] * m[1][1]) * OneOverDeterminant; Inverse[0][1] = - (m[0][1] * m[2][2] - m[2][1] * m[0][2]) * OneOverDeterminant; Inverse[1][1] = + (m[0][0] * m[2][2] - m[2][0] * m[0][2]) * OneOverDeterminant; Inverse[2][1] = - (m[0][0] * m[2][1] - m[2][0] * m[0][1]) * OneOverDeterminant; Inverse[0][2] = + (m[0][1] * m[1][2] - m[1][1] * m[0][2]) * OneOverDeterminant; Inverse[1][2] = - (m[0][0] * m[1][2] - m[1][0] * m[0][2]) * OneOverDeterminant; Inverse[2][2] = + (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * OneOverDeterminant; return Inverse; } }; template struct compute_inverse<4, 4, T, Q, Aligned> { GLM_FUNC_QUALIFIER static mat<4, 4, T, Q> call(mat<4, 4, T, Q> const& m) { T Coef00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; T Coef02 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; T Coef03 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; T Coef04 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; T Coef06 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; T Coef07 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; T Coef08 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; T Coef10 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; T Coef11 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; T Coef12 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; T Coef14 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; T Coef15 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; T Coef16 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; T Coef18 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; T Coef19 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; T Coef20 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; T Coef22 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; T Coef23 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; vec<4, T, Q> Fac0(Coef00, Coef00, Coef02, Coef03); vec<4, T, Q> Fac1(Coef04, Coef04, Coef06, Coef07); vec<4, T, Q> Fac2(Coef08, Coef08, Coef10, Coef11); vec<4, T, Q> Fac3(Coef12, Coef12, Coef14, Coef15); vec<4, T, Q> Fac4(Coef16, Coef16, Coef18, Coef19); vec<4, T, Q> Fac5(Coef20, Coef20, Coef22, Coef23); vec<4, T, Q> Vec0(m[1][0], m[0][0], m[0][0], m[0][0]); vec<4, T, Q> Vec1(m[1][1], m[0][1], m[0][1], m[0][1]); vec<4, T, Q> Vec2(m[1][2], m[0][2], m[0][2], m[0][2]); vec<4, T, Q> Vec3(m[1][3], m[0][3], m[0][3], m[0][3]); vec<4, T, Q> Inv0(Vec1 * Fac0 - Vec2 * Fac1 + Vec3 * Fac2); vec<4, T, Q> Inv1(Vec0 * Fac0 - Vec2 * Fac3 + Vec3 * Fac4); vec<4, T, Q> Inv2(Vec0 * Fac1 - Vec1 * Fac3 + Vec3 * Fac5); vec<4, T, Q> Inv3(Vec0 * Fac2 - Vec1 * Fac4 + Vec2 * Fac5); vec<4, T, Q> SignA(+1, -1, +1, -1); vec<4, T, Q> SignB(-1, +1, -1, +1); mat<4, 4, T, Q> Inverse(Inv0 * SignA, Inv1 * SignB, Inv2 * SignA, Inv3 * SignB); vec<4, T, Q> Row0(Inverse[0][0], Inverse[1][0], Inverse[2][0], Inverse[3][0]); vec<4, T, Q> Dot0(m[0] * Row0); T Dot1 = (Dot0.x + Dot0.y) + (Dot0.z + Dot0.w); T OneOverDeterminant = static_cast(1) / Dot1; return Inverse * OneOverDeterminant; } }; }//namespace detail template GLM_FUNC_QUALIFIER mat matrixCompMult(mat const& x, mat const& y) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'matrixCompMult' only accept floating-point inputs"); return detail::compute_matrixCompMult::value>::call(x, y); } template GLM_FUNC_QUALIFIER typename detail::outerProduct_trait::type outerProduct(vec const& c, vec const& r) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'outerProduct' only accept floating-point inputs"); typename detail::outerProduct_trait::type m; for(length_t i = 0; i < m.length(); ++i) m[i] = c * r[i]; return m; } template GLM_FUNC_QUALIFIER typename mat::transpose_type transpose(mat const& m) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'transpose' only accept floating-point inputs"); return detail::compute_transpose::value>::call(m); } template GLM_FUNC_QUALIFIER T determinant(mat const& m) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'determinant' only accept floating-point inputs"); return detail::compute_determinant::value>::call(m); } template GLM_FUNC_QUALIFIER mat inverse(mat const& m) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, "'inverse' only accept floating-point inputs"); return detail::compute_inverse::value>::call(m); } }//namespace glm #if GLM_CONFIG_SIMD == GLM_ENABLE # include "func_matrix_simd.inl" #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/func_matrix_simd.inl000066400000000000000000000054771360521144700256330ustar00rootroot00000000000000#if GLM_ARCH & GLM_ARCH_SSE2_BIT #include "type_mat4x4.hpp" #include "../geometric.hpp" #include "../simd/matrix.h" #include namespace glm{ namespace detail { # if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE template struct compute_matrixCompMult<4, 4, float, Q, true> { GLM_STATIC_ASSERT(detail::is_aligned::value, "Specialization requires aligned"); GLM_FUNC_QUALIFIER static mat<4, 4, float, Q> call(mat<4, 4, float, Q> const& x, mat<4, 4, float, Q> const& y) { mat<4, 4, float, Q> Result; glm_mat4_matrixCompMult( *static_cast(&x[0].data), *static_cast(&y[0].data), *static_cast(&Result[0].data)); return Result; } }; # endif template struct compute_transpose<4, 4, float, Q, true> { GLM_FUNC_QUALIFIER static mat<4, 4, float, Q> call(mat<4, 4, float, Q> const& m) { mat<4, 4, float, Q> Result; glm_mat4_transpose(&m[0].data, &Result[0].data); return Result; } }; template struct compute_determinant<4, 4, float, Q, true> { GLM_FUNC_QUALIFIER static float call(mat<4, 4, float, Q> const& m) { return _mm_cvtss_f32(glm_mat4_determinant(&m[0].data)); } }; template struct compute_inverse<4, 4, float, Q, true> { GLM_FUNC_QUALIFIER static mat<4, 4, float, Q> call(mat<4, 4, float, Q> const& m) { mat<4, 4, float, Q> Result; glm_mat4_inverse(&m[0].data, &Result[0].data); return Result; } }; }//namespace detail # if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE template<> GLM_FUNC_QUALIFIER mat<4, 4, float, aligned_lowp> outerProduct<4, 4, float, aligned_lowp>(vec<4, float, aligned_lowp> const& c, vec<4, float, aligned_lowp> const& r) { __m128 NativeResult[4]; glm_mat4_outerProduct(c.data, r.data, NativeResult); mat<4, 4, float, aligned_lowp> Result; std::memcpy(&Result[0], &NativeResult[0], sizeof(Result)); return Result; } template<> GLM_FUNC_QUALIFIER mat<4, 4, float, aligned_mediump> outerProduct<4, 4, float, aligned_mediump>(vec<4, float, aligned_mediump> const& c, vec<4, float, aligned_mediump> const& r) { __m128 NativeResult[4]; glm_mat4_outerProduct(c.data, r.data, NativeResult); mat<4, 4, float, aligned_mediump> Result; std::memcpy(&Result[0], &NativeResult[0], sizeof(Result)); return Result; } template<> GLM_FUNC_QUALIFIER mat<4, 4, float, aligned_highp> outerProduct<4, 4, float, aligned_highp>(vec<4, float, aligned_highp> const& c, vec<4, float, aligned_highp> const& r) { __m128 NativeResult[4]; glm_mat4_outerProduct(c.data, r.data, NativeResult); mat<4, 4, float, aligned_highp> Result; std::memcpy(&Result[0], &NativeResult[0], sizeof(Result)); return Result; } # endif }//namespace glm #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/func_packing.inl000066400000000000000000000061041360521144700247130ustar00rootroot00000000000000/// @ref core /// @file glm/detail/func_packing.inl #include "../common.hpp" #include "type_half.hpp" namespace glm { GLM_FUNC_QUALIFIER uint packUnorm2x16(vec2 const& v) { union { unsigned short in[2]; uint out; } u; vec<2, unsigned short, defaultp> result(round(clamp(v, 0.0f, 1.0f) * 65535.0f)); u.in[0] = result[0]; u.in[1] = result[1]; return u.out; } GLM_FUNC_QUALIFIER vec2 unpackUnorm2x16(uint p) { union { uint in; unsigned short out[2]; } u; u.in = p; return vec2(u.out[0], u.out[1]) * 1.5259021896696421759365224689097e-5f; } GLM_FUNC_QUALIFIER uint packSnorm2x16(vec2 const& v) { union { signed short in[2]; uint out; } u; vec<2, short, defaultp> result(round(clamp(v, -1.0f, 1.0f) * 32767.0f)); u.in[0] = result[0]; u.in[1] = result[1]; return u.out; } GLM_FUNC_QUALIFIER vec2 unpackSnorm2x16(uint p) { union { uint in; signed short out[2]; } u; u.in = p; return clamp(vec2(u.out[0], u.out[1]) * 3.0518509475997192297128208258309e-5f, -1.0f, 1.0f); } GLM_FUNC_QUALIFIER uint packUnorm4x8(vec4 const& v) { union { unsigned char in[4]; uint out; } u; vec<4, unsigned char, defaultp> result(round(clamp(v, 0.0f, 1.0f) * 255.0f)); u.in[0] = result[0]; u.in[1] = result[1]; u.in[2] = result[2]; u.in[3] = result[3]; return u.out; } GLM_FUNC_QUALIFIER vec4 unpackUnorm4x8(uint p) { union { uint in; unsigned char out[4]; } u; u.in = p; return vec4(u.out[0], u.out[1], u.out[2], u.out[3]) * 0.0039215686274509803921568627451f; } GLM_FUNC_QUALIFIER uint packSnorm4x8(vec4 const& v) { union { signed char in[4]; uint out; } u; vec<4, signed char, defaultp> result(round(clamp(v, -1.0f, 1.0f) * 127.0f)); u.in[0] = result[0]; u.in[1] = result[1]; u.in[2] = result[2]; u.in[3] = result[3]; return u.out; } GLM_FUNC_QUALIFIER glm::vec4 unpackSnorm4x8(uint p) { union { uint in; signed char out[4]; } u; u.in = p; return clamp(vec4(u.out[0], u.out[1], u.out[2], u.out[3]) * 0.0078740157480315f, -1.0f, 1.0f); } GLM_FUNC_QUALIFIER double packDouble2x32(uvec2 const& v) { union { uint in[2]; double out; } u; u.in[0] = v[0]; u.in[1] = v[1]; return u.out; } GLM_FUNC_QUALIFIER uvec2 unpackDouble2x32(double v) { union { double in; uint out[2]; } u; u.in = v; return uvec2(u.out[0], u.out[1]); } GLM_FUNC_QUALIFIER uint packHalf2x16(vec2 const& v) { union { signed short in[2]; uint out; } u; u.in[0] = detail::toFloat16(v.x); u.in[1] = detail::toFloat16(v.y); return u.out; } GLM_FUNC_QUALIFIER vec2 unpackHalf2x16(uint v) { union { uint in; signed short out[2]; } u; u.in = v; return vec2( detail::toFloat32(u.out[0]), detail::toFloat32(u.out[1])); } }//namespace glm #if GLM_CONFIG_SIMD == GLM_ENABLE # include "func_packing_simd.inl" #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/func_packing_simd.inl000066400000000000000000000001161360521144700257240ustar00rootroot00000000000000namespace glm{ namespace detail { }//namespace detail }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/func_trigonometric.inl000066400000000000000000000124451360521144700261710ustar00rootroot00000000000000#include "_vectorize.hpp" #include #include namespace glm { // radians template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType radians(genType degrees) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'radians' only accept floating-point input"); return degrees * static_cast(0.01745329251994329576923690768489); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec radians(vec const& v) { return detail::functor1::call(radians, v); } // degrees template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType degrees(genType radians) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'degrees' only accept floating-point input"); return radians * static_cast(57.295779513082320876798154814105); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec degrees(vec const& v) { return detail::functor1::call(degrees, v); } // sin using ::std::sin; template GLM_FUNC_QUALIFIER vec sin(vec const& v) { return detail::functor1::call(sin, v); } // cos using std::cos; template GLM_FUNC_QUALIFIER vec cos(vec const& v) { return detail::functor1::call(cos, v); } // tan using std::tan; template GLM_FUNC_QUALIFIER vec tan(vec const& v) { return detail::functor1::call(tan, v); } // asin using std::asin; template GLM_FUNC_QUALIFIER vec asin(vec const& v) { return detail::functor1::call(asin, v); } // acos using std::acos; template GLM_FUNC_QUALIFIER vec acos(vec const& v) { return detail::functor1::call(acos, v); } // atan template GLM_FUNC_QUALIFIER genType atan(genType y, genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'atan' only accept floating-point input"); return ::std::atan2(y, x); } template GLM_FUNC_QUALIFIER vec atan(vec const& a, vec const& b) { return detail::functor2::call(::std::atan2, a, b); } using std::atan; template GLM_FUNC_QUALIFIER vec atan(vec const& v) { return detail::functor1::call(atan, v); } // sinh using std::sinh; template GLM_FUNC_QUALIFIER vec sinh(vec const& v) { return detail::functor1::call(sinh, v); } // cosh using std::cosh; template GLM_FUNC_QUALIFIER vec cosh(vec const& v) { return detail::functor1::call(cosh, v); } // tanh using std::tanh; template GLM_FUNC_QUALIFIER vec tanh(vec const& v) { return detail::functor1::call(tanh, v); } // asinh # if GLM_HAS_CXX11_STL using std::asinh; # else template GLM_FUNC_QUALIFIER genType asinh(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'asinh' only accept floating-point input"); return (x < static_cast(0) ? static_cast(-1) : (x > static_cast(0) ? static_cast(1) : static_cast(0))) * log(std::abs(x) + sqrt(static_cast(1) + x * x)); } # endif template GLM_FUNC_QUALIFIER vec asinh(vec const& v) { return detail::functor1::call(asinh, v); } // acosh # if GLM_HAS_CXX11_STL using std::acosh; # else template GLM_FUNC_QUALIFIER genType acosh(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acosh' only accept floating-point input"); if(x < static_cast(1)) return static_cast(0); return log(x + sqrt(x * x - static_cast(1))); } # endif template GLM_FUNC_QUALIFIER vec acosh(vec const& v) { return detail::functor1::call(acosh, v); } // atanh # if GLM_HAS_CXX11_STL using std::atanh; # else template GLM_FUNC_QUALIFIER genType atanh(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'atanh' only accept floating-point input"); if(std::abs(x) >= static_cast(1)) return 0; return static_cast(0.5) * log((static_cast(1) + x) / (static_cast(1) - x)); } # endif template GLM_FUNC_QUALIFIER vec atanh(vec const& v) { return detail::functor1::call(atanh, v); } }//namespace glm #if GLM_CONFIG_SIMD == GLM_ENABLE # include "func_trigonometric_simd.inl" #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/func_trigonometric_simd.inl000066400000000000000000000000001360521144700271650ustar00rootroot00000000000000connectome-workbench-1.4.2/src/GLMath/glm/detail/func_vector_relational.inl000066400000000000000000000046771360521144700270300ustar00rootroot00000000000000namespace glm { template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec lessThan(vec const& x, vec const& y) { vec Result(true); for(length_t i = 0; i < L; ++i) Result[i] = x[i] < y[i]; return Result; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec lessThanEqual(vec const& x, vec const& y) { vec Result(true); for(length_t i = 0; i < L; ++i) Result[i] = x[i] <= y[i]; return Result; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec greaterThan(vec const& x, vec const& y) { vec Result(true); for(length_t i = 0; i < L; ++i) Result[i] = x[i] > y[i]; return Result; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec greaterThanEqual(vec const& x, vec const& y) { vec Result(true); for(length_t i = 0; i < L; ++i) Result[i] = x[i] >= y[i]; return Result; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(vec const& x, vec const& y) { vec Result(true); for(length_t i = 0; i < L; ++i) Result[i] = x[i] == y[i]; return Result; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y) { vec Result(true); for(length_t i = 0; i < L; ++i) Result[i] = x[i] != y[i]; return Result; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool any(vec const& v) { bool Result = false; for(length_t i = 0; i < L; ++i) Result = Result || v[i]; return Result; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool all(vec const& v) { bool Result = true; for(length_t i = 0; i < L; ++i) Result = Result && v[i]; return Result; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec not_(vec const& v) { vec Result(true); for(length_t i = 0; i < L; ++i) Result[i] = !v[i]; return Result; } }//namespace glm #if GLM_CONFIG_SIMD == GLM_ENABLE # include "func_vector_relational_simd.inl" #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/func_vector_relational_simd.inl000066400000000000000000000001161360521144700300240ustar00rootroot00000000000000namespace glm{ namespace detail { }//namespace detail }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/glm.cpp000066400000000000000000000210301360521144700230360ustar00rootroot00000000000000/// @ref core /// @file glm/glm.cpp #ifndef GLM_ENABLE_EXPERIMENTAL #define GLM_ENABLE_EXPERIMENTAL #endif #include #include #include #include #include #include namespace glm { // tvec1 type explicit instantiation template struct vec<1, uint8, lowp>; template struct vec<1, uint16, lowp>; template struct vec<1, uint32, lowp>; template struct vec<1, uint64, lowp>; template struct vec<1, int8, lowp>; template struct vec<1, int16, lowp>; template struct vec<1, int32, lowp>; template struct vec<1, int64, lowp>; template struct vec<1, float32, lowp>; template struct vec<1, float64, lowp>; template struct vec<1, uint8, mediump>; template struct vec<1, uint16, mediump>; template struct vec<1, uint32, mediump>; template struct vec<1, uint64, mediump>; template struct vec<1, int8, mediump>; template struct vec<1, int16, mediump>; template struct vec<1, int32, mediump>; template struct vec<1, int64, mediump>; template struct vec<1, float32, mediump>; template struct vec<1, float64, mediump>; template struct vec<1, uint8, highp>; template struct vec<1, uint16, highp>; template struct vec<1, uint32, highp>; template struct vec<1, uint64, highp>; template struct vec<1, int8, highp>; template struct vec<1, int16, highp>; template struct vec<1, int32, highp>; template struct vec<1, int64, highp>; template struct vec<1, float32, highp>; template struct vec<1, float64, highp>; // tvec2 type explicit instantiation template struct vec<2, uint8, lowp>; template struct vec<2, uint16, lowp>; template struct vec<2, uint32, lowp>; template struct vec<2, uint64, lowp>; template struct vec<2, int8, lowp>; template struct vec<2, int16, lowp>; template struct vec<2, int32, lowp>; template struct vec<2, int64, lowp>; template struct vec<2, float32, lowp>; template struct vec<2, float64, lowp>; template struct vec<2, uint8, mediump>; template struct vec<2, uint16, mediump>; template struct vec<2, uint32, mediump>; template struct vec<2, uint64, mediump>; template struct vec<2, int8, mediump>; template struct vec<2, int16, mediump>; template struct vec<2, int32, mediump>; template struct vec<2, int64, mediump>; template struct vec<2, float32, mediump>; template struct vec<2, float64, mediump>; template struct vec<2, uint8, highp>; template struct vec<2, uint16, highp>; template struct vec<2, uint32, highp>; template struct vec<2, uint64, highp>; template struct vec<2, int8, highp>; template struct vec<2, int16, highp>; template struct vec<2, int32, highp>; template struct vec<2, int64, highp>; template struct vec<2, float32, highp>; template struct vec<2, float64, highp>; // tvec3 type explicit instantiation template struct vec<3, uint8, lowp>; template struct vec<3, uint16, lowp>; template struct vec<3, uint32, lowp>; template struct vec<3, uint64, lowp>; template struct vec<3, int8, lowp>; template struct vec<3, int16, lowp>; template struct vec<3, int32, lowp>; template struct vec<3, int64, lowp>; template struct vec<3, float32, lowp>; template struct vec<3, float64, lowp>; template struct vec<3, uint8, mediump>; template struct vec<3, uint16, mediump>; template struct vec<3, uint32, mediump>; template struct vec<3, uint64, mediump>; template struct vec<3, int8, mediump>; template struct vec<3, int16, mediump>; template struct vec<3, int32, mediump>; template struct vec<3, int64, mediump>; template struct vec<3, float32, mediump>; template struct vec<3, float64, mediump>; template struct vec<3, uint8, highp>; template struct vec<3, uint16, highp>; template struct vec<3, uint32, highp>; template struct vec<3, uint64, highp>; template struct vec<3, int8, highp>; template struct vec<3, int16, highp>; template struct vec<3, int32, highp>; template struct vec<3, int64, highp>; template struct vec<3, float32, highp>; template struct vec<3, float64, highp>; // tvec4 type explicit instantiation template struct vec<4, uint8, lowp>; template struct vec<4, uint16, lowp>; template struct vec<4, uint32, lowp>; template struct vec<4, uint64, lowp>; template struct vec<4, int8, lowp>; template struct vec<4, int16, lowp>; template struct vec<4, int32, lowp>; template struct vec<4, int64, lowp>; template struct vec<4, float32, lowp>; template struct vec<4, float64, lowp>; template struct vec<4, uint8, mediump>; template struct vec<4, uint16, mediump>; template struct vec<4, uint32, mediump>; template struct vec<4, uint64, mediump>; template struct vec<4, int8, mediump>; template struct vec<4, int16, mediump>; template struct vec<4, int32, mediump>; template struct vec<4, int64, mediump>; template struct vec<4, float32, mediump>; template struct vec<4, float64, mediump>; template struct vec<4, uint8, highp>; template struct vec<4, uint16, highp>; template struct vec<4, uint32, highp>; template struct vec<4, uint64, highp>; template struct vec<4, int8, highp>; template struct vec<4, int16, highp>; template struct vec<4, int32, highp>; template struct vec<4, int64, highp>; template struct vec<4, float32, highp>; template struct vec<4, float64, highp>; // tmat2x2 type explicit instantiation template struct mat<2, 2, float32, lowp>; template struct mat<2, 2, float64, lowp>; template struct mat<2, 2, float32, mediump>; template struct mat<2, 2, float64, mediump>; template struct mat<2, 2, float32, highp>; template struct mat<2, 2, float64, highp>; // tmat2x3 type explicit instantiation template struct mat<2, 3, float32, lowp>; template struct mat<2, 3, float64, lowp>; template struct mat<2, 3, float32, mediump>; template struct mat<2, 3, float64, mediump>; template struct mat<2, 3, float32, highp>; template struct mat<2, 3, float64, highp>; // tmat2x4 type explicit instantiation template struct mat<2, 4, float32, lowp>; template struct mat<2, 4, float64, lowp>; template struct mat<2, 4, float32, mediump>; template struct mat<2, 4, float64, mediump>; template struct mat<2, 4, float32, highp>; template struct mat<2, 4, float64, highp>; // tmat3x2 type explicit instantiation template struct mat<3, 2, float32, lowp>; template struct mat<3, 2, float64, lowp>; template struct mat<3, 2, float32, mediump>; template struct mat<3, 2, float64, mediump>; template struct mat<3, 2, float32, highp>; template struct mat<3, 2, float64, highp>; // tmat3x3 type explicit instantiation template struct mat<3, 3, float32, lowp>; template struct mat<3, 3, float64, lowp>; template struct mat<3, 3, float32, mediump>; template struct mat<3, 3, float64, mediump>; template struct mat<3, 3, float32, highp>; template struct mat<3, 3, float64, highp>; // tmat3x4 type explicit instantiation template struct mat<3, 4, float32, lowp>; template struct mat<3, 4, float64, lowp>; template struct mat<3, 4, float32, mediump>; template struct mat<3, 4, float64, mediump>; template struct mat<3, 4, float32, highp>; template struct mat<3, 4, float64, highp>; // tmat4x2 type explicit instantiation template struct mat<4, 2, float32, lowp>; template struct mat<4, 2, float64, lowp>; template struct mat<4, 2, float32, mediump>; template struct mat<4, 2, float64, mediump>; template struct mat<4, 2, float32, highp>; template struct mat<4, 2, float64, highp>; // tmat4x3 type explicit instantiation template struct mat<4, 3, float32, lowp>; template struct mat<4, 3, float64, lowp>; template struct mat<4, 3, float32, mediump>; template struct mat<4, 3, float64, mediump>; template struct mat<4, 3, float32, highp>; template struct mat<4, 3, float64, highp>; // tmat4x4 type explicit instantiation template struct mat<4, 4, float32, lowp>; template struct mat<4, 4, float64, lowp>; template struct mat<4, 4, float32, mediump>; template struct mat<4, 4, float64, mediump>; template struct mat<4, 4, float32, highp>; template struct mat<4, 4, float64, highp>; // tquat type explicit instantiation template struct qua; template struct qua; template struct qua; template struct qua; template struct qua; template struct qua; //tdualquat type explicit instantiation template struct tdualquat; template struct tdualquat; template struct tdualquat; template struct tdualquat; template struct tdualquat; template struct tdualquat; }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/qualifier.hpp000066400000000000000000000137561360521144700242650ustar00rootroot00000000000000#pragma once #include "setup.hpp" namespace glm { /// Qualify GLM types in term of alignment (packed, aligned) and precision in term of ULPs (lowp, mediump, highp) enum qualifier { packed_highp, ///< Typed data is tightly packed in memory and operations are executed with high precision in term of ULPs packed_mediump, ///< Typed data is tightly packed in memory and operations are executed with medium precision in term of ULPs for higher performance packed_lowp, ///< Typed data is tightly packed in memory and operations are executed with low precision in term of ULPs to maximize performance # if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE aligned_highp, ///< Typed data is aligned in memory allowing SIMD optimizations and operations are executed with high precision in term of ULPs aligned_mediump, ///< Typed data is aligned in memory allowing SIMD optimizations and operations are executed with high precision in term of ULPs for higher performance aligned_lowp, // ///< Typed data is aligned in memory allowing SIMD optimizations and operations are executed with high precision in term of ULPs to maximize performance aligned = aligned_highp, ///< By default aligned qualifier is also high precision # endif highp = packed_highp, ///< By default highp qualifier is also packed mediump = packed_mediump, ///< By default mediump qualifier is also packed lowp = packed_lowp, ///< By default lowp qualifier is also packed packed = packed_highp, ///< By default packed qualifier is also high precision # if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE && defined(GLM_FORCE_DEFAULT_ALIGNED_GENTYPES) defaultp = aligned_highp # else defaultp = highp # endif }; typedef qualifier precision; template struct vec; template struct mat; template struct qua; # if GLM_HAS_TEMPLATE_ALIASES template using tvec1 = vec<1, T, Q>; template using tvec2 = vec<2, T, Q>; template using tvec3 = vec<3, T, Q>; template using tvec4 = vec<4, T, Q>; template using tmat2x2 = mat<2, 2, T, Q>; template using tmat2x3 = mat<2, 3, T, Q>; template using tmat2x4 = mat<2, 4, T, Q>; template using tmat3x2 = mat<3, 2, T, Q>; template using tmat3x3 = mat<3, 3, T, Q>; template using tmat3x4 = mat<3, 4, T, Q>; template using tmat4x2 = mat<4, 2, T, Q>; template using tmat4x3 = mat<4, 3, T, Q>; template using tmat4x4 = mat<4, 4, T, Q>; template using tquat = qua; # endif namespace detail { template struct is_aligned { static const bool value = false; }; # if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE template<> struct is_aligned { static const bool value = true; }; template<> struct is_aligned { static const bool value = true; }; template<> struct is_aligned { static const bool value = true; }; # endif template struct storage { typedef struct type { T data[L]; } type; }; # if GLM_HAS_ALIGNOF template struct storage { typedef struct alignas(L * sizeof(T)) type { T data[L]; } type; }; template struct storage<3, T, true> { typedef struct alignas(4 * sizeof(T)) type { T data[4]; } type; }; # endif # if GLM_ARCH & GLM_ARCH_SSE2_BIT template<> struct storage<4, float, true> { typedef glm_f32vec4 type; }; template<> struct storage<4, int, true> { typedef glm_i32vec4 type; }; template<> struct storage<4, unsigned int, true> { typedef glm_u32vec4 type; }; template<> struct storage<2, double, true> { typedef glm_f64vec2 type; }; template<> struct storage<2, detail::int64, true> { typedef glm_i64vec2 type; }; template<> struct storage<2, detail::uint64, true> { typedef glm_u64vec2 type; }; # endif # if (GLM_ARCH & GLM_ARCH_AVX_BIT) template<> struct storage<4, double, true> { typedef glm_f64vec4 type; }; # endif # if (GLM_ARCH & GLM_ARCH_AVX2_BIT) template<> struct storage<4, detail::int64, true> { typedef glm_i64vec4 type; }; template<> struct storage<4, detail::uint64, true> { typedef glm_u64vec4 type; }; # endif # if GLM_ARCH & GLM_ARCH_NEON_BIT template<> struct storage<4, float, true> { typedef glm_f32vec4 type; }; template<> struct storage<4, int, true> { typedef glm_i32vec4 type; }; template<> struct storage<4, unsigned int, true> { typedef glm_u32vec4 type; }; # endif enum genTypeEnum { GENTYPE_VEC, GENTYPE_MAT, GENTYPE_QUAT }; template struct genTypeTrait {}; template struct genTypeTrait > { static const genTypeEnum GENTYPE = GENTYPE_MAT; }; template struct init_gentype { }; template struct init_gentype { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static genType identity() { return genType(1, 0, 0, 0); } }; template struct init_gentype { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static genType identity() { return genType(1); } }; }//namespace detail }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/setup.hpp000066400000000000000000001171451360521144700234410ustar00rootroot00000000000000#ifndef GLM_SETUP_INCLUDED #include #include #define GLM_VERSION_MAJOR 0 #define GLM_VERSION_MINOR 9 #define GLM_VERSION_PATCH 9 #define GLM_VERSION_REVISION 6 #define GLM_VERSION 996 #define GLM_VERSION_MESSAGE "GLM: version 0.9.9.6" #define GLM_SETUP_INCLUDED GLM_VERSION /////////////////////////////////////////////////////////////////////////////////// // Active states #define GLM_DISABLE 0 #define GLM_ENABLE 1 /////////////////////////////////////////////////////////////////////////////////// // Messages #if defined(GLM_FORCE_MESSAGES) # define GLM_MESSAGES GLM_ENABLE #else # define GLM_MESSAGES GLM_DISABLE #endif /////////////////////////////////////////////////////////////////////////////////// // Detect the platform #include "../simd/platform.h" /////////////////////////////////////////////////////////////////////////////////// // Build model #if defined(__arch64__) || defined(__LP64__) || defined(_M_X64) || defined(__ppc64__) || defined(__x86_64__) # define GLM_MODEL GLM_MODEL_64 #elif defined(__i386__) || defined(__ppc__) # define GLM_MODEL GLM_MODEL_32 #else # define GLM_MODEL GLM_MODEL_32 #endif// #if !defined(GLM_MODEL) && GLM_COMPILER != 0 # error "GLM_MODEL undefined, your compiler may not be supported by GLM. Add #define GLM_MODEL 0 to ignore this message." #endif//GLM_MODEL /////////////////////////////////////////////////////////////////////////////////// // C++ Version // User defines: GLM_FORCE_CXX98, GLM_FORCE_CXX03, GLM_FORCE_CXX11, GLM_FORCE_CXX14, GLM_FORCE_CXX17, GLM_FORCE_CXX2A #define GLM_LANG_CXX98_FLAG (1 << 1) #define GLM_LANG_CXX03_FLAG (1 << 2) #define GLM_LANG_CXX0X_FLAG (1 << 3) #define GLM_LANG_CXX11_FLAG (1 << 4) #define GLM_LANG_CXX14_FLAG (1 << 5) #define GLM_LANG_CXX17_FLAG (1 << 6) #define GLM_LANG_CXX2A_FLAG (1 << 7) #define GLM_LANG_CXXMS_FLAG (1 << 8) #define GLM_LANG_CXXGNU_FLAG (1 << 9) #define GLM_LANG_CXX98 GLM_LANG_CXX98_FLAG #define GLM_LANG_CXX03 (GLM_LANG_CXX98 | GLM_LANG_CXX03_FLAG) #define GLM_LANG_CXX0X (GLM_LANG_CXX03 | GLM_LANG_CXX0X_FLAG) #define GLM_LANG_CXX11 (GLM_LANG_CXX0X | GLM_LANG_CXX11_FLAG) #define GLM_LANG_CXX14 (GLM_LANG_CXX11 | GLM_LANG_CXX14_FLAG) #define GLM_LANG_CXX17 (GLM_LANG_CXX14 | GLM_LANG_CXX17_FLAG) #define GLM_LANG_CXX2A (GLM_LANG_CXX17 | GLM_LANG_CXX2A_FLAG) #define GLM_LANG_CXXMS GLM_LANG_CXXMS_FLAG #define GLM_LANG_CXXGNU GLM_LANG_CXXGNU_FLAG #if (defined(_MSC_EXTENSIONS)) # define GLM_LANG_EXT GLM_LANG_CXXMS_FLAG #elif ((GLM_COMPILER & (GLM_COMPILER_CLANG | GLM_COMPILER_GCC)) && (GLM_ARCH & GLM_ARCH_SIMD_BIT)) # define GLM_LANG_EXT GLM_LANG_CXXMS_FLAG #else # define GLM_LANG_EXT 0 #endif #if (defined(GLM_FORCE_CXX_UNKNOWN)) # define GLM_LANG 0 #elif defined(GLM_FORCE_CXX2A) # define GLM_LANG (GLM_LANG_CXX2A | GLM_LANG_EXT) # define GLM_LANG_STL11_FORCED #elif defined(GLM_FORCE_CXX17) # define GLM_LANG (GLM_LANG_CXX17 | GLM_LANG_EXT) # define GLM_LANG_STL11_FORCED #elif defined(GLM_FORCE_CXX14) # define GLM_LANG (GLM_LANG_CXX14 | GLM_LANG_EXT) # define GLM_LANG_STL11_FORCED #elif defined(GLM_FORCE_CXX11) # define GLM_LANG (GLM_LANG_CXX11 | GLM_LANG_EXT) # define GLM_LANG_STL11_FORCED #elif defined(GLM_FORCE_CXX03) # define GLM_LANG (GLM_LANG_CXX03 | GLM_LANG_EXT) #elif defined(GLM_FORCE_CXX98) # define GLM_LANG (GLM_LANG_CXX98 | GLM_LANG_EXT) #else # if GLM_COMPILER & GLM_COMPILER_VC && defined(_MSVC_LANG) # if GLM_COMPILER >= GLM_COMPILER_VC15_7 # define GLM_LANG_PLATFORM _MSVC_LANG # elif GLM_COMPILER >= GLM_COMPILER_VC15 # if _MSVC_LANG > 201402L # define GLM_LANG_PLATFORM 201402L # else # define GLM_LANG_PLATFORM _MSVC_LANG # endif # else # define GLM_LANG_PLATFORM 0 # endif # else # define GLM_LANG_PLATFORM 0 # endif # if __cplusplus > 201703L || GLM_LANG_PLATFORM > 201703L # define GLM_LANG (GLM_LANG_CXX2A | GLM_LANG_EXT) # elif __cplusplus == 201703L || GLM_LANG_PLATFORM == 201703L # define GLM_LANG (GLM_LANG_CXX17 | GLM_LANG_EXT) # elif __cplusplus == 201402L || __cplusplus == 201500L || GLM_LANG_PLATFORM == 201402L # define GLM_LANG (GLM_LANG_CXX14 | GLM_LANG_EXT) # elif __cplusplus == 201103L || GLM_LANG_PLATFORM == 201103L # define GLM_LANG (GLM_LANG_CXX11 | GLM_LANG_EXT) # elif defined(__INTEL_CXX11_MODE__) || defined(_MSC_VER) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define GLM_LANG (GLM_LANG_CXX0X | GLM_LANG_EXT) # elif __cplusplus == 199711L # define GLM_LANG (GLM_LANG_CXX98 | GLM_LANG_EXT) # else # define GLM_LANG (0 | GLM_LANG_EXT) # endif #endif /////////////////////////////////////////////////////////////////////////////////// // Has of C++ features // http://clang.llvm.org/cxx_status.html // http://gcc.gnu.org/projects/cxx0x.html // http://msdn.microsoft.com/en-us/library/vstudio/hh567368(v=vs.120).aspx // Android has multiple STLs but C++11 STL detection doesn't always work #284 #564 #if GLM_PLATFORM == GLM_PLATFORM_ANDROID && !defined(GLM_LANG_STL11_FORCED) # define GLM_HAS_CXX11_STL 0 #elif GLM_COMPILER & GLM_COMPILER_CLANG # if (defined(_LIBCPP_VERSION) || (GLM_LANG & GLM_LANG_CXX11_FLAG) || defined(GLM_LANG_STL11_FORCED)) # define GLM_HAS_CXX11_STL 1 # else # define GLM_HAS_CXX11_STL 0 # endif #elif GLM_LANG & GLM_LANG_CXX11_FLAG # define GLM_HAS_CXX11_STL 1 #else # define GLM_HAS_CXX11_STL ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ ((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC48)) || \ ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \ ((GLM_PLATFORM != GLM_PLATFORM_WINDOWS) && (GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL15)))) #endif // N1720 #if GLM_COMPILER & GLM_COMPILER_CLANG # define GLM_HAS_STATIC_ASSERT __has_feature(cxx_static_assert) #elif GLM_LANG & GLM_LANG_CXX11_FLAG # define GLM_HAS_STATIC_ASSERT 1 #else # define GLM_HAS_STATIC_ASSERT ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ ((GLM_COMPILER & GLM_COMPILER_CUDA)) || \ ((GLM_COMPILER & GLM_COMPILER_VC)))) #endif // N1988 #if GLM_LANG & GLM_LANG_CXX11_FLAG # define GLM_HAS_EXTENDED_INTEGER_TYPE 1 #else # define GLM_HAS_EXTENDED_INTEGER_TYPE (\ ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_COMPILER & GLM_COMPILER_VC)) || \ ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_COMPILER & GLM_COMPILER_CUDA)) || \ ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_COMPILER & GLM_COMPILER_CLANG))) #endif // N2672 Initializer lists http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2672.htm #if GLM_COMPILER & GLM_COMPILER_CLANG # define GLM_HAS_INITIALIZER_LISTS __has_feature(cxx_generalized_initializers) #elif GLM_LANG & GLM_LANG_CXX11_FLAG # define GLM_HAS_INITIALIZER_LISTS 1 #else # define GLM_HAS_INITIALIZER_LISTS ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC15)) || \ ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL14)) || \ ((GLM_COMPILER & GLM_COMPILER_CUDA)))) #endif // N2544 Unrestricted unions http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf #if GLM_COMPILER & GLM_COMPILER_CLANG # define GLM_HAS_UNRESTRICTED_UNIONS __has_feature(cxx_unrestricted_unions) #elif GLM_LANG & GLM_LANG_CXX11_FLAG # define GLM_HAS_UNRESTRICTED_UNIONS 1 #else # define GLM_HAS_UNRESTRICTED_UNIONS (GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ (GLM_COMPILER & GLM_COMPILER_VC) || \ ((GLM_COMPILER & GLM_COMPILER_CUDA))) #endif // N2346 #if GLM_COMPILER & GLM_COMPILER_CLANG # define GLM_HAS_DEFAULTED_FUNCTIONS __has_feature(cxx_defaulted_functions) #elif GLM_LANG & GLM_LANG_CXX11_FLAG # define GLM_HAS_DEFAULTED_FUNCTIONS 1 #else # define GLM_HAS_DEFAULTED_FUNCTIONS ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \ ((GLM_COMPILER & GLM_COMPILER_INTEL)) || \ (GLM_COMPILER & GLM_COMPILER_CUDA))) #endif // N2118 #if GLM_COMPILER & GLM_COMPILER_CLANG # define GLM_HAS_RVALUE_REFERENCES __has_feature(cxx_rvalue_references) #elif GLM_LANG & GLM_LANG_CXX11_FLAG # define GLM_HAS_RVALUE_REFERENCES 1 #else # define GLM_HAS_RVALUE_REFERENCES ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ ((GLM_COMPILER & GLM_COMPILER_VC)) || \ ((GLM_COMPILER & GLM_COMPILER_CUDA)))) #endif // N2437 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf #if GLM_COMPILER & GLM_COMPILER_CLANG # define GLM_HAS_EXPLICIT_CONVERSION_OPERATORS __has_feature(cxx_explicit_conversions) #elif GLM_LANG & GLM_LANG_CXX11_FLAG # define GLM_HAS_EXPLICIT_CONVERSION_OPERATORS 1 #else # define GLM_HAS_EXPLICIT_CONVERSION_OPERATORS ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL14)) || \ ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \ ((GLM_COMPILER & GLM_COMPILER_CUDA)))) #endif // N2258 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf #if GLM_COMPILER & GLM_COMPILER_CLANG # define GLM_HAS_TEMPLATE_ALIASES __has_feature(cxx_alias_templates) #elif GLM_LANG & GLM_LANG_CXX11_FLAG # define GLM_HAS_TEMPLATE_ALIASES 1 #else # define GLM_HAS_TEMPLATE_ALIASES ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ ((GLM_COMPILER & GLM_COMPILER_INTEL)) || \ ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \ ((GLM_COMPILER & GLM_COMPILER_CUDA)))) #endif // N2930 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2930.html #if GLM_COMPILER & GLM_COMPILER_CLANG # define GLM_HAS_RANGE_FOR __has_feature(cxx_range_for) #elif GLM_LANG & GLM_LANG_CXX11_FLAG # define GLM_HAS_RANGE_FOR 1 #else # define GLM_HAS_RANGE_FOR ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ ((GLM_COMPILER & GLM_COMPILER_INTEL)) || \ ((GLM_COMPILER & GLM_COMPILER_VC)) || \ ((GLM_COMPILER & GLM_COMPILER_CUDA)))) #endif // N2341 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf #if GLM_COMPILER & GLM_COMPILER_CLANG # define GLM_HAS_ALIGNOF __has_feature(cxx_alignas) #elif GLM_LANG & GLM_LANG_CXX11_FLAG # define GLM_HAS_ALIGNOF 1 #else # define GLM_HAS_ALIGNOF ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL15)) || \ ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC14)) || \ ((GLM_COMPILER & GLM_COMPILER_CUDA)))) #endif // N2235 Generalized Constant Expressions http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf // N3652 Extended Constant Expressions http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3652.html #if (GLM_ARCH & GLM_ARCH_SIMD_BIT) // Compiler SIMD intrinsics don't support constexpr... # define GLM_HAS_CONSTEXPR 0 #elif (GLM_COMPILER & GLM_COMPILER_CLANG) # define GLM_HAS_CONSTEXPR __has_feature(cxx_relaxed_constexpr) #elif (GLM_LANG & GLM_LANG_CXX14_FLAG) # define GLM_HAS_CONSTEXPR 1 #else # define GLM_HAS_CONSTEXPR ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && GLM_HAS_INITIALIZER_LISTS && (\ ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL17)) || \ ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC15)))) #endif #if GLM_HAS_CONSTEXPR # define GLM_CONSTEXPR constexpr #else # define GLM_CONSTEXPR #endif // #if GLM_HAS_CONSTEXPR # if (GLM_COMPILER & GLM_COMPILER_CLANG) # if __has_feature(cxx_if_constexpr) # define GLM_HAS_IF_CONSTEXPR 1 # else # define GLM_HAS_IF_CONSTEXPR 0 # endif # elif (GLM_LANG & GLM_LANG_CXX17_FLAG) # define GLM_HAS_IF_CONSTEXPR 1 # else # define GLM_HAS_IF_CONSTEXPR 0 # endif #else # define GLM_HAS_IF_CONSTEXPR 0 #endif #if GLM_HAS_IF_CONSTEXPR # define GLM_IF_CONSTEXPR if constexpr #else # define GLM_IF_CONSTEXPR if #endif // #if GLM_LANG & GLM_LANG_CXX11_FLAG # define GLM_HAS_ASSIGNABLE 1 #else # define GLM_HAS_ASSIGNABLE ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC15)) || \ ((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC49)))) #endif // #define GLM_HAS_TRIVIAL_QUERIES 0 // #if GLM_LANG & GLM_LANG_CXX11_FLAG # define GLM_HAS_MAKE_SIGNED 1 #else # define GLM_HAS_MAKE_SIGNED ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\ ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \ ((GLM_COMPILER & GLM_COMPILER_CUDA)))) #endif // #if defined(GLM_FORCE_INTRINSICS) # define GLM_HAS_BITSCAN_WINDOWS ((GLM_PLATFORM & GLM_PLATFORM_WINDOWS) && (\ ((GLM_COMPILER & GLM_COMPILER_INTEL)) || \ ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC14) && (GLM_ARCH & GLM_ARCH_X86_BIT)))) #else # define GLM_HAS_BITSCAN_WINDOWS 0 #endif /////////////////////////////////////////////////////////////////////////////////// // OpenMP #ifdef _OPENMP # if GLM_COMPILER & GLM_COMPILER_GCC # if GLM_COMPILER >= GLM_COMPILER_GCC61 # define GLM_HAS_OPENMP 45 # elif GLM_COMPILER >= GLM_COMPILER_GCC49 # define GLM_HAS_OPENMP 40 # elif GLM_COMPILER >= GLM_COMPILER_GCC47 # define GLM_HAS_OPENMP 31 # else # define GLM_HAS_OPENMP 0 # endif # elif GLM_COMPILER & GLM_COMPILER_CLANG # if GLM_COMPILER >= GLM_COMPILER_CLANG38 # define GLM_HAS_OPENMP 31 # else # define GLM_HAS_OPENMP 0 # endif # elif GLM_COMPILER & GLM_COMPILER_VC # define GLM_HAS_OPENMP 20 # elif GLM_COMPILER & GLM_COMPILER_INTEL # if GLM_COMPILER >= GLM_COMPILER_INTEL16 # define GLM_HAS_OPENMP 40 # else # define GLM_HAS_OPENMP 0 # endif # else # define GLM_HAS_OPENMP 0 # endif #else # define GLM_HAS_OPENMP 0 #endif /////////////////////////////////////////////////////////////////////////////////// // nullptr #if GLM_LANG & GLM_LANG_CXX0X_FLAG # define GLM_CONFIG_NULLPTR GLM_ENABLE #else # define GLM_CONFIG_NULLPTR GLM_DISABLE #endif #if GLM_CONFIG_NULLPTR == GLM_ENABLE # define GLM_NULLPTR nullptr #else # define GLM_NULLPTR 0 #endif /////////////////////////////////////////////////////////////////////////////////// // Static assert #if GLM_HAS_STATIC_ASSERT # define GLM_STATIC_ASSERT(x, message) static_assert(x, message) #elif GLM_COMPILER & GLM_COMPILER_VC # define GLM_STATIC_ASSERT(x, message) typedef char __CASSERT__##__LINE__[(x) ? 1 : -1] #else # define GLM_STATIC_ASSERT(x, message) assert(x) #endif//GLM_LANG /////////////////////////////////////////////////////////////////////////////////// // Qualifiers #if GLM_COMPILER & GLM_COMPILER_CUDA # define GLM_CUDA_FUNC_DEF __device__ __host__ # define GLM_CUDA_FUNC_DECL __device__ __host__ #else # define GLM_CUDA_FUNC_DEF # define GLM_CUDA_FUNC_DECL #endif #if defined(GLM_FORCE_INLINE) # if GLM_COMPILER & GLM_COMPILER_VC # define GLM_INLINE __forceinline # define GLM_NEVER_INLINE __declspec((noinline)) # elif GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG) # define GLM_INLINE inline __attribute__((__always_inline__)) # define GLM_NEVER_INLINE __attribute__((__noinline__)) # elif GLM_COMPILER & GLM_COMPILER_CUDA # define GLM_INLINE __forceinline__ # define GLM_NEVER_INLINE __noinline__ # else # define GLM_INLINE inline # define GLM_NEVER_INLINE # endif//GLM_COMPILER #else # define GLM_INLINE inline # define GLM_NEVER_INLINE #endif//defined(GLM_FORCE_INLINE) #define GLM_FUNC_DECL GLM_CUDA_FUNC_DECL #define GLM_FUNC_QUALIFIER GLM_CUDA_FUNC_DEF GLM_INLINE /////////////////////////////////////////////////////////////////////////////////// // Swizzle operators // User defines: GLM_FORCE_SWIZZLE #define GLM_SWIZZLE_DISABLED 0 #define GLM_SWIZZLE_OPERATOR 1 #define GLM_SWIZZLE_FUNCTION 2 #if defined(GLM_FORCE_XYZW_ONLY) # undef GLM_FORCE_SWIZZLE #endif #if defined(GLM_SWIZZLE) # pragma message("GLM: GLM_SWIZZLE is deprecated, use GLM_FORCE_SWIZZLE instead.") # define GLM_FORCE_SWIZZLE #endif #if defined(GLM_FORCE_SWIZZLE) && (GLM_LANG & GLM_LANG_CXXMS_FLAG) # define GLM_CONFIG_SWIZZLE GLM_SWIZZLE_OPERATOR #elif defined(GLM_FORCE_SWIZZLE) # define GLM_CONFIG_SWIZZLE GLM_SWIZZLE_FUNCTION #else # define GLM_CONFIG_SWIZZLE GLM_SWIZZLE_DISABLED #endif /////////////////////////////////////////////////////////////////////////////////// // Allows using not basic types as genType // #define GLM_FORCE_UNRESTRICTED_GENTYPE #ifdef GLM_FORCE_UNRESTRICTED_GENTYPE # define GLM_CONFIG_UNRESTRICTED_GENTYPE GLM_ENABLE #else # define GLM_CONFIG_UNRESTRICTED_GENTYPE GLM_DISABLE #endif /////////////////////////////////////////////////////////////////////////////////// // Clip control, define GLM_FORCE_DEPTH_ZERO_TO_ONE before including GLM // to use a clip space between 0 to 1. // Coordinate system, define GLM_FORCE_LEFT_HANDED before including GLM // to use left handed coordinate system by default. #define GLM_CLIP_CONTROL_ZO_BIT (1 << 0) // ZERO_TO_ONE #define GLM_CLIP_CONTROL_NO_BIT (1 << 1) // NEGATIVE_ONE_TO_ONE #define GLM_CLIP_CONTROL_LH_BIT (1 << 2) // LEFT_HANDED, For DirectX, Metal, Vulkan #define GLM_CLIP_CONTROL_RH_BIT (1 << 3) // RIGHT_HANDED, For OpenGL, default in GLM #define GLM_CLIP_CONTROL_LH_ZO (GLM_CLIP_CONTROL_LH_BIT | GLM_CLIP_CONTROL_ZO_BIT) #define GLM_CLIP_CONTROL_LH_NO (GLM_CLIP_CONTROL_LH_BIT | GLM_CLIP_CONTROL_NO_BIT) #define GLM_CLIP_CONTROL_RH_ZO (GLM_CLIP_CONTROL_RH_BIT | GLM_CLIP_CONTROL_ZO_BIT) #define GLM_CLIP_CONTROL_RH_NO (GLM_CLIP_CONTROL_RH_BIT | GLM_CLIP_CONTROL_NO_BIT) #ifdef GLM_FORCE_DEPTH_ZERO_TO_ONE # ifdef GLM_FORCE_LEFT_HANDED # define GLM_CONFIG_CLIP_CONTROL GLM_CLIP_CONTROL_LH_ZO # else # define GLM_CONFIG_CLIP_CONTROL GLM_CLIP_CONTROL_RH_ZO # endif #else # ifdef GLM_FORCE_LEFT_HANDED # define GLM_CONFIG_CLIP_CONTROL GLM_CLIP_CONTROL_LH_NO # else # define GLM_CONFIG_CLIP_CONTROL GLM_CLIP_CONTROL_RH_NO # endif #endif /////////////////////////////////////////////////////////////////////////////////// // Qualifiers #if (GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS)) # define GLM_DEPRECATED __declspec(deprecated) # define GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef __declspec(align(alignment)) type name #elif GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG | GLM_COMPILER_INTEL) # define GLM_DEPRECATED __attribute__((__deprecated__)) # define GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef type name __attribute__((aligned(alignment))) #elif GLM_COMPILER & GLM_COMPILER_CUDA # define GLM_DEPRECATED # define GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef type name __align__(x) #else # define GLM_DEPRECATED # define GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef type name #endif /////////////////////////////////////////////////////////////////////////////////// #ifdef GLM_FORCE_EXPLICIT_CTOR # define GLM_EXPLICIT explicit #else # define GLM_EXPLICIT #endif /////////////////////////////////////////////////////////////////////////////////// // SYCL #if GLM_COMPILER==GLM_COMPILER_SYCL #include #include namespace glm { namespace std { // Import SYCL's functions into the namespace glm::std to force their usages. // It's important to use the math built-in function (sin, exp, ...) // of SYCL instead the std ones. using namespace cl::sycl; /////////////////////////////////////////////////////////////////////////////// // Import some "harmless" std's stuffs used by glm into // the new glm::std namespace. template using numeric_limits = ::std::numeric_limits; using ::std::size_t; using ::std::uint8_t; using ::std::uint16_t; using ::std::uint32_t; using ::std::uint64_t; using ::std::int8_t; using ::std::int16_t; using ::std::int32_t; using ::std::int64_t; using ::std::make_unsigned; /////////////////////////////////////////////////////////////////////////////// } //namespace std } //namespace glm #endif /////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// // Length type: all length functions returns a length_t type. // When GLM_FORCE_SIZE_T_LENGTH is defined, length_t is a typedef of size_t otherwise // length_t is a typedef of int like GLSL defines it. #define GLM_LENGTH_INT 1 #define GLM_LENGTH_SIZE_T 2 #ifdef GLM_FORCE_SIZE_T_LENGTH # define GLM_CONFIG_LENGTH_TYPE GLM_LENGTH_SIZE_T #else # define GLM_CONFIG_LENGTH_TYPE GLM_LENGTH_INT #endif namespace glm { using std::size_t; # if GLM_CONFIG_LENGTH_TYPE == GLM_LENGTH_SIZE_T typedef size_t length_t; # else typedef int length_t; # endif }//namespace glm /////////////////////////////////////////////////////////////////////////////////// // constexpr #if GLM_HAS_CONSTEXPR # define GLM_CONFIG_CONSTEXP GLM_ENABLE namespace glm { template constexpr std::size_t countof(T const (&)[N]) { return N; } }//namespace glm # define GLM_COUNTOF(arr) glm::countof(arr) #elif defined(_MSC_VER) # define GLM_CONFIG_CONSTEXP GLM_DISABLE # define GLM_COUNTOF(arr) _countof(arr) #else # define GLM_CONFIG_CONSTEXP GLM_DISABLE # define GLM_COUNTOF(arr) sizeof(arr) / sizeof(arr[0]) #endif /////////////////////////////////////////////////////////////////////////////////// // uint namespace glm{ namespace detail { template struct is_int { enum test {value = 0}; }; template<> struct is_int { enum test {value = ~0}; }; template<> struct is_int { enum test {value = ~0}; }; }//namespace detail typedef unsigned int uint; }//namespace glm /////////////////////////////////////////////////////////////////////////////////// // 64-bit int #if GLM_HAS_EXTENDED_INTEGER_TYPE # include #endif namespace glm{ namespace detail { # if GLM_HAS_EXTENDED_INTEGER_TYPE typedef std::uint64_t uint64; typedef std::int64_t int64; # elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) // C99 detected, 64 bit types available typedef uint64_t uint64; typedef int64_t int64; # elif GLM_COMPILER & GLM_COMPILER_VC typedef unsigned __int64 uint64; typedef signed __int64 int64; # elif GLM_COMPILER & GLM_COMPILER_GCC # pragma GCC diagnostic ignored "-Wlong-long" __extension__ typedef unsigned long long uint64; __extension__ typedef signed long long int64; # elif (GLM_COMPILER & GLM_COMPILER_CLANG) # pragma clang diagnostic ignored "-Wc++11-long-long" typedef unsigned long long uint64; typedef signed long long int64; # else//unknown compiler typedef unsigned long long uint64; typedef signed long long int64; # endif }//namespace detail }//namespace glm /////////////////////////////////////////////////////////////////////////////////// // make_unsigned #if GLM_HAS_MAKE_SIGNED # include namespace glm{ namespace detail { using std::make_unsigned; }//namespace detail }//namespace glm #else namespace glm{ namespace detail { template struct make_unsigned {}; template<> struct make_unsigned { typedef unsigned char type; }; template<> struct make_unsigned { typedef unsigned char type; }; template<> struct make_unsigned { typedef unsigned short type; }; template<> struct make_unsigned { typedef unsigned int type; }; template<> struct make_unsigned { typedef unsigned long type; }; template<> struct make_unsigned { typedef uint64 type; }; template<> struct make_unsigned { typedef unsigned char type; }; template<> struct make_unsigned { typedef unsigned short type; }; template<> struct make_unsigned { typedef unsigned int type; }; template<> struct make_unsigned { typedef unsigned long type; }; template<> struct make_unsigned { typedef uint64 type; }; }//namespace detail }//namespace glm #endif /////////////////////////////////////////////////////////////////////////////////// // Only use x, y, z, w as vector type components #ifdef GLM_FORCE_XYZW_ONLY # define GLM_CONFIG_XYZW_ONLY GLM_ENABLE #else # define GLM_CONFIG_XYZW_ONLY GLM_DISABLE #endif /////////////////////////////////////////////////////////////////////////////////// // Configure the use of defaulted initialized types #define GLM_CTOR_INIT_DISABLE 0 #define GLM_CTOR_INITIALIZER_LIST 1 #define GLM_CTOR_INITIALISATION 2 #if defined(GLM_FORCE_CTOR_INIT) && GLM_HAS_INITIALIZER_LISTS # define GLM_CONFIG_CTOR_INIT GLM_CTOR_INITIALIZER_LIST #elif defined(GLM_FORCE_CTOR_INIT) && !GLM_HAS_INITIALIZER_LISTS # define GLM_CONFIG_CTOR_INIT GLM_CTOR_INITIALISATION #else # define GLM_CONFIG_CTOR_INIT GLM_CTOR_INIT_DISABLE #endif /////////////////////////////////////////////////////////////////////////////////// // Use SIMD instruction sets #if GLM_HAS_ALIGNOF && (GLM_LANG & GLM_LANG_CXXMS_FLAG) && (GLM_ARCH & GLM_ARCH_SIMD_BIT) # define GLM_CONFIG_SIMD GLM_ENABLE #else # define GLM_CONFIG_SIMD GLM_DISABLE #endif /////////////////////////////////////////////////////////////////////////////////// // Configure the use of defaulted function #if GLM_HAS_DEFAULTED_FUNCTIONS && GLM_CONFIG_CTOR_INIT == GLM_CTOR_INIT_DISABLE # define GLM_CONFIG_DEFAULTED_FUNCTIONS GLM_ENABLE # define GLM_DEFAULT = default #else # define GLM_CONFIG_DEFAULTED_FUNCTIONS GLM_DISABLE # define GLM_DEFAULT #endif /////////////////////////////////////////////////////////////////////////////////// // Configure the use of aligned gentypes #ifdef GLM_FORCE_ALIGNED // Legacy define # define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES #endif #ifdef GLM_FORCE_DEFAULT_ALIGNED_GENTYPES # define GLM_FORCE_ALIGNED_GENTYPES #endif #if GLM_HAS_ALIGNOF && (GLM_LANG & GLM_LANG_CXXMS_FLAG) && (defined(GLM_FORCE_ALIGNED_GENTYPES) || (GLM_CONFIG_SIMD == GLM_ENABLE)) # define GLM_CONFIG_ALIGNED_GENTYPES GLM_ENABLE #else # define GLM_CONFIG_ALIGNED_GENTYPES GLM_DISABLE #endif /////////////////////////////////////////////////////////////////////////////////// // Configure the use of anonymous structure as implementation detail #if ((GLM_CONFIG_SIMD == GLM_ENABLE) || (GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR) || (GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE)) # define GLM_CONFIG_ANONYMOUS_STRUCT GLM_ENABLE #else # define GLM_CONFIG_ANONYMOUS_STRUCT GLM_DISABLE #endif /////////////////////////////////////////////////////////////////////////////////// // Silent warnings #ifdef GLM_FORCE_SILENT_WARNINGS # define GLM_SILENT_WARNINGS GLM_ENABLE #else # define GLM_SILENT_WARNINGS GLM_DISABLE #endif /////////////////////////////////////////////////////////////////////////////////// // Precision #define GLM_HIGHP 1 #define GLM_MEDIUMP 2 #define GLM_LOWP 3 #if defined(GLM_FORCE_PRECISION_HIGHP_BOOL) || defined(GLM_PRECISION_HIGHP_BOOL) # define GLM_CONFIG_PRECISION_BOOL GLM_HIGHP #elif defined(GLM_FORCE_PRECISION_MEDIUMP_BOOL) || defined(GLM_PRECISION_MEDIUMP_BOOL) # define GLM_CONFIG_PRECISION_BOOL GLM_MEDIUMP #elif defined(GLM_FORCE_PRECISION_LOWP_BOOL) || defined(GLM_PRECISION_LOWP_BOOL) # define GLM_CONFIG_PRECISION_BOOL GLM_LOWP #else # define GLM_CONFIG_PRECISION_BOOL GLM_HIGHP #endif #if defined(GLM_FORCE_PRECISION_HIGHP_INT) || defined(GLM_PRECISION_HIGHP_INT) # define GLM_CONFIG_PRECISION_INT GLM_HIGHP #elif defined(GLM_FORCE_PRECISION_MEDIUMP_INT) || defined(GLM_PRECISION_MEDIUMP_INT) # define GLM_CONFIG_PRECISION_INT GLM_MEDIUMP #elif defined(GLM_FORCE_PRECISION_LOWP_INT) || defined(GLM_PRECISION_LOWP_INT) # define GLM_CONFIG_PRECISION_INT GLM_LOWP #else # define GLM_CONFIG_PRECISION_INT GLM_HIGHP #endif #if defined(GLM_FORCE_PRECISION_HIGHP_UINT) || defined(GLM_PRECISION_HIGHP_UINT) # define GLM_CONFIG_PRECISION_UINT GLM_HIGHP #elif defined(GLM_FORCE_PRECISION_MEDIUMP_UINT) || defined(GLM_PRECISION_MEDIUMP_UINT) # define GLM_CONFIG_PRECISION_UINT GLM_MEDIUMP #elif defined(GLM_FORCE_PRECISION_LOWP_UINT) || defined(GLM_PRECISION_LOWP_UINT) # define GLM_CONFIG_PRECISION_UINT GLM_LOWP #else # define GLM_CONFIG_PRECISION_UINT GLM_HIGHP #endif #if defined(GLM_FORCE_PRECISION_HIGHP_FLOAT) || defined(GLM_PRECISION_HIGHP_FLOAT) # define GLM_CONFIG_PRECISION_FLOAT GLM_HIGHP #elif defined(GLM_FORCE_PRECISION_MEDIUMP_FLOAT) || defined(GLM_PRECISION_MEDIUMP_FLOAT) # define GLM_CONFIG_PRECISION_FLOAT GLM_MEDIUMP #elif defined(GLM_FORCE_PRECISION_LOWP_FLOAT) || defined(GLM_PRECISION_LOWP_FLOAT) # define GLM_CONFIG_PRECISION_FLOAT GLM_LOWP #else # define GLM_CONFIG_PRECISION_FLOAT GLM_HIGHP #endif #if defined(GLM_FORCE_PRECISION_HIGHP_DOUBLE) || defined(GLM_PRECISION_HIGHP_DOUBLE) # define GLM_CONFIG_PRECISION_DOUBLE GLM_HIGHP #elif defined(GLM_FORCE_PRECISION_MEDIUMP_DOUBLE) || defined(GLM_PRECISION_MEDIUMP_DOUBLE) # define GLM_CONFIG_PRECISION_DOUBLE GLM_MEDIUMP #elif defined(GLM_FORCE_PRECISION_LOWP_DOUBLE) || defined(GLM_PRECISION_LOWP_DOUBLE) # define GLM_CONFIG_PRECISION_DOUBLE GLM_LOWP #else # define GLM_CONFIG_PRECISION_DOUBLE GLM_HIGHP #endif /////////////////////////////////////////////////////////////////////////////////// // Check inclusions of different versions of GLM #elif ((GLM_SETUP_INCLUDED != GLM_VERSION) && !defined(GLM_FORCE_IGNORE_VERSION)) # error "GLM error: A different version of GLM is already included. Define GLM_FORCE_IGNORE_VERSION before including GLM headers to ignore this error." #elif GLM_SETUP_INCLUDED == GLM_VERSION /////////////////////////////////////////////////////////////////////////////////// // Messages #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_MESSAGE_DISPLAYED) # define GLM_MESSAGE_DISPLAYED # define GLM_STR_HELPER(x) #x # define GLM_STR(x) GLM_STR_HELPER(x) // Report GLM version # pragma message (GLM_STR(GLM_VERSION_MESSAGE)) // Report C++ language # if (GLM_LANG & GLM_LANG_CXX2A_FLAG) && (GLM_LANG & GLM_LANG_EXT) # pragma message("GLM: C++ 2A with extensions") # elif (GLM_LANG & GLM_LANG_CXX2A_FLAG) # pragma message("GLM: C++ 2A") # elif (GLM_LANG & GLM_LANG_CXX17_FLAG) && (GLM_LANG & GLM_LANG_EXT) # pragma message("GLM: C++ 17 with extensions") # elif (GLM_LANG & GLM_LANG_CXX17_FLAG) # pragma message("GLM: C++ 17") # elif (GLM_LANG & GLM_LANG_CXX14_FLAG) && (GLM_LANG & GLM_LANG_EXT) # pragma message("GLM: C++ 14 with extensions") # elif (GLM_LANG & GLM_LANG_CXX14_FLAG) # pragma message("GLM: C++ 14") # elif (GLM_LANG & GLM_LANG_CXX11_FLAG) && (GLM_LANG & GLM_LANG_EXT) # pragma message("GLM: C++ 11 with extensions") # elif (GLM_LANG & GLM_LANG_CXX11_FLAG) # pragma message("GLM: C++ 11") # elif (GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_LANG & GLM_LANG_EXT) # pragma message("GLM: C++ 0x with extensions") # elif (GLM_LANG & GLM_LANG_CXX0X_FLAG) # pragma message("GLM: C++ 0x") # elif (GLM_LANG & GLM_LANG_CXX03_FLAG) && (GLM_LANG & GLM_LANG_EXT) # pragma message("GLM: C++ 03 with extensions") # elif (GLM_LANG & GLM_LANG_CXX03_FLAG) # pragma message("GLM: C++ 03") # elif (GLM_LANG & GLM_LANG_CXX98_FLAG) && (GLM_LANG & GLM_LANG_EXT) # pragma message("GLM: C++ 98 with extensions") # elif (GLM_LANG & GLM_LANG_CXX98_FLAG) # pragma message("GLM: C++ 98") # else # pragma message("GLM: C++ language undetected") # endif//GLM_LANG // Report compiler detection # if GLM_COMPILER & GLM_COMPILER_CUDA # pragma message("GLM: CUDA compiler detected") # elif GLM_COMPILER & GLM_COMPILER_VC # pragma message("GLM: Visual C++ compiler detected") # elif GLM_COMPILER & GLM_COMPILER_CLANG # pragma message("GLM: Clang compiler detected") # elif GLM_COMPILER & GLM_COMPILER_INTEL # pragma message("GLM: Intel Compiler detected") # elif GLM_COMPILER & GLM_COMPILER_GCC # pragma message("GLM: GCC compiler detected") # else # pragma message("GLM: Compiler not detected") # endif // Report build target # if (GLM_ARCH & GLM_ARCH_AVX2_BIT) && (GLM_MODEL == GLM_MODEL_64) # pragma message("GLM: x86 64 bits with AVX2 instruction set build target") # elif (GLM_ARCH & GLM_ARCH_AVX2_BIT) && (GLM_MODEL == GLM_MODEL_32) # pragma message("GLM: x86 32 bits with AVX2 instruction set build target") # elif (GLM_ARCH & GLM_ARCH_AVX_BIT) && (GLM_MODEL == GLM_MODEL_64) # pragma message("GLM: x86 64 bits with AVX instruction set build target") # elif (GLM_ARCH & GLM_ARCH_AVX_BIT) && (GLM_MODEL == GLM_MODEL_32) # pragma message("GLM: x86 32 bits with AVX instruction set build target") # elif (GLM_ARCH & GLM_ARCH_SSE42_BIT) && (GLM_MODEL == GLM_MODEL_64) # pragma message("GLM: x86 64 bits with SSE4.2 instruction set build target") # elif (GLM_ARCH & GLM_ARCH_SSE42_BIT) && (GLM_MODEL == GLM_MODEL_32) # pragma message("GLM: x86 32 bits with SSE4.2 instruction set build target") # elif (GLM_ARCH & GLM_ARCH_SSE41_BIT) && (GLM_MODEL == GLM_MODEL_64) # pragma message("GLM: x86 64 bits with SSE4.1 instruction set build target") # elif (GLM_ARCH & GLM_ARCH_SSE41_BIT) && (GLM_MODEL == GLM_MODEL_32) # pragma message("GLM: x86 32 bits with SSE4.1 instruction set build target") # elif (GLM_ARCH & GLM_ARCH_SSSE3_BIT) && (GLM_MODEL == GLM_MODEL_64) # pragma message("GLM: x86 64 bits with SSSE3 instruction set build target") # elif (GLM_ARCH & GLM_ARCH_SSSE3_BIT) && (GLM_MODEL == GLM_MODEL_32) # pragma message("GLM: x86 32 bits with SSSE3 instruction set build target") # elif (GLM_ARCH & GLM_ARCH_SSE3_BIT) && (GLM_MODEL == GLM_MODEL_64) # pragma message("GLM: x86 64 bits with SSE3 instruction set build target") # elif (GLM_ARCH & GLM_ARCH_SSE3_BIT) && (GLM_MODEL == GLM_MODEL_32) # pragma message("GLM: x86 32 bits with SSE3 instruction set build target") # elif (GLM_ARCH & GLM_ARCH_SSE2_BIT) && (GLM_MODEL == GLM_MODEL_64) # pragma message("GLM: x86 64 bits with SSE2 instruction set build target") # elif (GLM_ARCH & GLM_ARCH_SSE2_BIT) && (GLM_MODEL == GLM_MODEL_32) # pragma message("GLM: x86 32 bits with SSE2 instruction set build target") # elif (GLM_ARCH & GLM_ARCH_X86_BIT) && (GLM_MODEL == GLM_MODEL_64) # pragma message("GLM: x86 64 bits build target") # elif (GLM_ARCH & GLM_ARCH_X86_BIT) && (GLM_MODEL == GLM_MODEL_32) # pragma message("GLM: x86 32 bits build target") # elif (GLM_ARCH & GLM_ARCH_NEON_BIT) && (GLM_MODEL == GLM_MODEL_64) # pragma message("GLM: ARM 64 bits with Neon instruction set build target") # elif (GLM_ARCH & GLM_ARCH_NEON_BIT) && (GLM_MODEL == GLM_MODEL_32) # pragma message("GLM: ARM 32 bits with Neon instruction set build target") # elif (GLM_ARCH & GLM_ARCH_ARM_BIT) && (GLM_MODEL == GLM_MODEL_64) # pragma message("GLM: ARM 64 bits build target") # elif (GLM_ARCH & GLM_ARCH_ARM_BIT) && (GLM_MODEL == GLM_MODEL_32) # pragma message("GLM: ARM 32 bits build target") # elif (GLM_ARCH & GLM_ARCH_MIPS_BIT) && (GLM_MODEL == GLM_MODEL_64) # pragma message("GLM: MIPS 64 bits build target") # elif (GLM_ARCH & GLM_ARCH_MIPS_BIT) && (GLM_MODEL == GLM_MODEL_32) # pragma message("GLM: MIPS 32 bits build target") # elif (GLM_ARCH & GLM_ARCH_PPC_BIT) && (GLM_MODEL == GLM_MODEL_64) # pragma message("GLM: PowerPC 64 bits build target") # elif (GLM_ARCH & GLM_ARCH_PPC_BIT) && (GLM_MODEL == GLM_MODEL_32) # pragma message("GLM: PowerPC 32 bits build target") # else # pragma message("GLM: Unknown build target") # endif//GLM_ARCH // Report platform name # if(GLM_PLATFORM & GLM_PLATFORM_QNXNTO) # pragma message("GLM: QNX platform detected") //# elif(GLM_PLATFORM & GLM_PLATFORM_IOS) //# pragma message("GLM: iOS platform detected") # elif(GLM_PLATFORM & GLM_PLATFORM_APPLE) # pragma message("GLM: Apple platform detected") # elif(GLM_PLATFORM & GLM_PLATFORM_WINCE) # pragma message("GLM: WinCE platform detected") # elif(GLM_PLATFORM & GLM_PLATFORM_WINDOWS) # pragma message("GLM: Windows platform detected") # elif(GLM_PLATFORM & GLM_PLATFORM_CHROME_NACL) # pragma message("GLM: Native Client detected") # elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) # pragma message("GLM: Android platform detected") # elif(GLM_PLATFORM & GLM_PLATFORM_LINUX) # pragma message("GLM: Linux platform detected") # elif(GLM_PLATFORM & GLM_PLATFORM_UNIX) # pragma message("GLM: UNIX platform detected") # elif(GLM_PLATFORM & GLM_PLATFORM_UNKNOWN) # pragma message("GLM: platform unknown") # else # pragma message("GLM: platform not detected") # endif // Report whether only xyzw component are used # if defined GLM_FORCE_XYZW_ONLY # pragma message("GLM: GLM_FORCE_XYZW_ONLY is defined. Only x, y, z and w component are available in vector type. This define disables swizzle operators and SIMD instruction sets.") # endif // Report swizzle operator support # if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR # pragma message("GLM: GLM_FORCE_SWIZZLE is defined, swizzling operators enabled.") # elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION # pragma message("GLM: GLM_FORCE_SWIZZLE is defined, swizzling functions enabled. Enable compiler C++ language extensions to enable swizzle operators.") # else # pragma message("GLM: GLM_FORCE_SWIZZLE is undefined. swizzling functions or operators are disabled.") # endif // Report .length() type # if GLM_CONFIG_LENGTH_TYPE == GLM_LENGTH_SIZE_T # pragma message("GLM: GLM_FORCE_SIZE_T_LENGTH is defined. .length() returns a glm::length_t, a typedef of std::size_t.") # else # pragma message("GLM: GLM_FORCE_SIZE_T_LENGTH is undefined. .length() returns a glm::length_t, a typedef of int following GLSL.") # endif # if GLM_CONFIG_UNRESTRICTED_GENTYPE == GLM_ENABLE # pragma message("GLM: GLM_FORCE_UNRESTRICTED_GENTYPE is defined. Removes GLSL restrictions on valid function genTypes.") # else # pragma message("GLM: GLM_FORCE_UNRESTRICTED_GENTYPE is undefined. Follows strictly GLSL on valid function genTypes.") # endif # if GLM_SILENT_WARNINGS == GLM_ENABLE # pragma message("GLM: GLM_FORCE_SILENT_WARNINGS is defined. Ignores C++ warnings from using C++ language extensions.") # else # pragma message("GLM: GLM_FORCE_SILENT_WARNINGS is undefined. Shows C++ warnings from using C++ language extensions.") # endif # ifdef GLM_FORCE_SINGLE_ONLY # pragma message("GLM: GLM_FORCE_SINGLE_ONLY is defined. Using only single precision floating-point types.") # endif # if defined(GLM_FORCE_ALIGNED_GENTYPES) && (GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE) # undef GLM_FORCE_ALIGNED_GENTYPES # pragma message("GLM: GLM_FORCE_ALIGNED_GENTYPES is defined, allowing aligned types. This prevents the use of C++ constexpr.") # elif defined(GLM_FORCE_ALIGNED_GENTYPES) && (GLM_CONFIG_ALIGNED_GENTYPES == GLM_DISABLE) # undef GLM_FORCE_ALIGNED_GENTYPES # pragma message("GLM: GLM_FORCE_ALIGNED_GENTYPES is defined but is disabled. It requires C++11 and language extensions.") # endif # if defined(GLM_FORCE_DEFAULT_ALIGNED_GENTYPES) # if GLM_CONFIG_ALIGNED_GENTYPES == GLM_DISABLE # undef GLM_FORCE_DEFAULT_ALIGNED_GENTYPES # pragma message("GLM: GLM_FORCE_DEFAULT_ALIGNED_GENTYPES is defined but is disabled. It requires C++11 and language extensions.") # elif GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE # pragma message("GLM: GLM_FORCE_DEFAULT_ALIGNED_GENTYPES is defined. All gentypes (e.g. vec3) will be aligned and padded by default.") # endif # endif # if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT # pragma message("GLM: GLM_FORCE_DEPTH_ZERO_TO_ONE is defined. Using zero to one depth clip space.") # else # pragma message("GLM: GLM_FORCE_DEPTH_ZERO_TO_ONE is undefined. Using negative one to one depth clip space.") # endif # if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT # pragma message("GLM: GLM_FORCE_LEFT_HANDED is defined. Using left handed coordinate system.") # else # pragma message("GLM: GLM_FORCE_LEFT_HANDED is undefined. Using right handed coordinate system.") # endif #endif//GLM_MESSAGES #endif//GLM_SETUP_INCLUDED connectome-workbench-1.4.2/src/GLMath/glm/detail/type_float.hpp000066400000000000000000000031521360521144700244370ustar00rootroot00000000000000#pragma once #include "setup.hpp" #if GLM_COMPILER == GLM_COMPILER_VC12 # pragma warning(push) # pragma warning(disable: 4512) // assignment operator could not be generated #endif namespace glm{ namespace detail { template union float_t {}; // https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ template <> union float_t { typedef int int_type; typedef float float_type; GLM_CONSTEXPR float_t(float_type Num = 0.0f) : f(Num) {} GLM_CONSTEXPR float_t& operator=(float_t const& x) { f = x.f; return *this; } // Portable extraction of components. GLM_CONSTEXPR bool negative() const { return i < 0; } GLM_CONSTEXPR int_type mantissa() const { return i & ((1 << 23) - 1); } GLM_CONSTEXPR int_type exponent() const { return (i >> 23) & ((1 << 8) - 1); } int_type i; float_type f; }; template <> union float_t { typedef detail::int64 int_type; typedef double float_type; GLM_CONSTEXPR float_t(float_type Num = static_cast(0)) : f(Num) {} GLM_CONSTEXPR float_t& operator=(float_t const& x) { f = x.f; return *this; } // Portable extraction of components. GLM_CONSTEXPR bool negative() const { return i < 0; } GLM_CONSTEXPR int_type mantissa() const { return i & ((int_type(1) << 52) - 1); } GLM_CONSTEXPR int_type exponent() const { return (i >> 52) & ((int_type(1) << 11) - 1); } int_type i; float_type f; }; }//namespace detail }//namespace glm #if GLM_COMPILER == GLM_COMPILER_VC12 # pragma warning(pop) #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/type_half.hpp000066400000000000000000000004161360521144700242440ustar00rootroot00000000000000#pragma once #include "setup.hpp" namespace glm{ namespace detail { typedef short hdata; GLM_FUNC_DECL float toFloat32(hdata value); GLM_FUNC_DECL hdata toFloat16(float const& value); }//namespace detail }//namespace glm #include "type_half.inl" connectome-workbench-1.4.2/src/GLMath/glm/detail/type_half.inl000066400000000000000000000112221360521144700242340ustar00rootroot00000000000000namespace glm{ namespace detail { GLM_FUNC_QUALIFIER float overflow() { volatile float f = 1e10; for(int i = 0; i < 10; ++i) f *= f; // this will overflow before the for loop terminates return f; } union uif32 { GLM_FUNC_QUALIFIER uif32() : i(0) {} GLM_FUNC_QUALIFIER uif32(float f_) : f(f_) {} GLM_FUNC_QUALIFIER uif32(unsigned int i_) : i(i_) {} float f; unsigned int i; }; GLM_FUNC_QUALIFIER float toFloat32(hdata value) { int s = (value >> 15) & 0x00000001; int e = (value >> 10) & 0x0000001f; int m = value & 0x000003ff; if(e == 0) { if(m == 0) { // // Plus or minus zero // detail::uif32 result; result.i = static_cast(s << 31); return result.f; } else { // // Denormalized number -- renormalize it // while(!(m & 0x00000400)) { m <<= 1; e -= 1; } e += 1; m &= ~0x00000400; } } else if(e == 31) { if(m == 0) { // // Positive or negative infinity // uif32 result; result.i = static_cast((s << 31) | 0x7f800000); return result.f; } else { // // Nan -- preserve sign and significand bits // uif32 result; result.i = static_cast((s << 31) | 0x7f800000 | (m << 13)); return result.f; } } // // Normalized number // e = e + (127 - 15); m = m << 13; // // Assemble s, e and m. // uif32 Result; Result.i = static_cast((s << 31) | (e << 23) | m); return Result.f; } GLM_FUNC_QUALIFIER hdata toFloat16(float const& f) { uif32 Entry; Entry.f = f; int i = static_cast(Entry.i); // // Our floating point number, f, is represented by the bit // pattern in integer i. Disassemble that bit pattern into // the sign, s, the exponent, e, and the significand, m. // Shift s into the position where it will go in the // resulting half number. // Adjust e, accounting for the different exponent bias // of float and half (127 versus 15). // int s = (i >> 16) & 0x00008000; int e = ((i >> 23) & 0x000000ff) - (127 - 15); int m = i & 0x007fffff; // // Now reassemble s, e and m into a half: // if(e <= 0) { if(e < -10) { // // E is less than -10. The absolute value of f is // less than half_MIN (f may be a small normalized // float, a denormalized float or a zero). // // We convert f to a half zero. // return hdata(s); } // // E is between -10 and 0. F is a normalized float, // whose magnitude is less than __half_NRM_MIN. // // We convert f to a denormalized half. // m = (m | 0x00800000) >> (1 - e); // // Round to nearest, round "0.5" up. // // Rounding may cause the significand to overflow and make // our number normalized. Because of the way a half's bits // are laid out, we don't have to treat this case separately; // the code below will handle it correctly. // if(m & 0x00001000) m += 0x00002000; // // Assemble the half from s, e (zero) and m. // return hdata(s | (m >> 13)); } else if(e == 0xff - (127 - 15)) { if(m == 0) { // // F is an infinity; convert f to a half // infinity with the same sign as f. // return hdata(s | 0x7c00); } else { // // F is a NAN; we produce a half NAN that preserves // the sign bit and the 10 leftmost bits of the // significand of f, with one exception: If the 10 // leftmost bits are all zero, the NAN would turn // into an infinity, so we have to set at least one // bit in the significand. // m >>= 13; return hdata(s | 0x7c00 | m | (m == 0)); } } else { // // E is greater than zero. F is a normalized float. // We try to convert f to a normalized half. // // // Round to nearest, round "0.5" up // if(m & 0x00001000) { m += 0x00002000; if(m & 0x00800000) { m = 0; // overflow in significand, e += 1; // adjust exponent } } // // Handle exponent overflow // if (e > 30) { overflow(); // Cause a hardware floating point overflow; return hdata(s | 0x7c00); // if this returns, the half becomes an } // infinity with the same sign as f. // // Assemble the half from s, e and m. // return hdata(s | (e << 10) | (m >> 13)); } } }//namespace detail }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/type_mat2x2.hpp000066400000000000000000000142731360521144700244550ustar00rootroot00000000000000/// @ref core /// @file glm/detail/type_mat2x2.hpp #pragma once #include "type_vec2.hpp" #include #include namespace glm { template struct mat<2, 2, T, Q> { typedef vec<2, T, Q> col_type; typedef vec<2, T, Q> row_type; typedef mat<2, 2, T, Q> type; typedef mat<2, 2, T, Q> transpose_type; typedef T value_type; private: col_type value[2]; public: // -- Accesses -- typedef length_t length_type; GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 2; } GLM_FUNC_DECL col_type & operator[](length_type i); GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; // -- Constructors -- GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT; template GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<2, 2, T, P> const& m); GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); GLM_FUNC_DECL GLM_CONSTEXPR mat( T const& x1, T const& y1, T const& x2, T const& y2); GLM_FUNC_DECL GLM_CONSTEXPR mat( col_type const& v1, col_type const& v2); // -- Conversions -- template GLM_FUNC_DECL GLM_CONSTEXPR mat( U const& x1, V const& y1, M const& x2, N const& y2); template GLM_FUNC_DECL GLM_CONSTEXPR mat( vec<2, U, Q> const& v1, vec<2, V, Q> const& v2); // -- Matrix conversions -- template GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, U, P> const& m); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); // -- Unary arithmetic operators -- template GLM_FUNC_DECL mat<2, 2, T, Q> & operator=(mat<2, 2, U, Q> const& m); template GLM_FUNC_DECL mat<2, 2, T, Q> & operator+=(U s); template GLM_FUNC_DECL mat<2, 2, T, Q> & operator+=(mat<2, 2, U, Q> const& m); template GLM_FUNC_DECL mat<2, 2, T, Q> & operator-=(U s); template GLM_FUNC_DECL mat<2, 2, T, Q> & operator-=(mat<2, 2, U, Q> const& m); template GLM_FUNC_DECL mat<2, 2, T, Q> & operator*=(U s); template GLM_FUNC_DECL mat<2, 2, T, Q> & operator*=(mat<2, 2, U, Q> const& m); template GLM_FUNC_DECL mat<2, 2, T, Q> & operator/=(U s); template GLM_FUNC_DECL mat<2, 2, T, Q> & operator/=(mat<2, 2, U, Q> const& m); // -- Increment and decrement operators -- GLM_FUNC_DECL mat<2, 2, T, Q> & operator++ (); GLM_FUNC_DECL mat<2, 2, T, Q> & operator-- (); GLM_FUNC_DECL mat<2, 2, T, Q> operator++(int); GLM_FUNC_DECL mat<2, 2, T, Q> operator--(int); }; // -- Unary operators -- template GLM_FUNC_DECL mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m); template GLM_FUNC_DECL mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m); // -- Binary operators -- template GLM_FUNC_DECL mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<2, 2, T, Q> operator+(T scalar, mat<2, 2, T, Q> const& m); template GLM_FUNC_DECL mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); template GLM_FUNC_DECL mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<2, 2, T, Q> operator-(T scalar, mat<2, 2, T, Q> const& m); template GLM_FUNC_DECL mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); template GLM_FUNC_DECL mat<2, 2, T, Q> operator*(mat<2, 2, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<2, 2, T, Q> operator*(T scalar, mat<2, 2, T, Q> const& m); template GLM_FUNC_DECL typename mat<2, 2, T, Q>::col_type operator*(mat<2, 2, T, Q> const& m, typename mat<2, 2, T, Q>::row_type const& v); template GLM_FUNC_DECL typename mat<2, 2, T, Q>::row_type operator*(typename mat<2, 2, T, Q>::col_type const& v, mat<2, 2, T, Q> const& m); template GLM_FUNC_DECL mat<2, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); template GLM_FUNC_DECL mat<3, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2); template GLM_FUNC_DECL mat<4, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2); template GLM_FUNC_DECL mat<2, 2, T, Q> operator/(mat<2, 2, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<2, 2, T, Q> operator/(T scalar, mat<2, 2, T, Q> const& m); template GLM_FUNC_DECL typename mat<2, 2, T, Q>::col_type operator/(mat<2, 2, T, Q> const& m, typename mat<2, 2, T, Q>::row_type const& v); template GLM_FUNC_DECL typename mat<2, 2, T, Q>::row_type operator/(typename mat<2, 2, T, Q>::col_type const& v, mat<2, 2, T, Q> const& m); template GLM_FUNC_DECL mat<2, 2, T, Q> operator/(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); // -- Boolean operators -- template GLM_FUNC_DECL bool operator==(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); template GLM_FUNC_DECL bool operator!=(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2); } //namespace glm #ifndef GLM_EXTERNAL_TEMPLATE #include "type_mat2x2.inl" #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/type_mat2x2.inl000066400000000000000000000342471360521144700244530ustar00rootroot00000000000000#include "../matrix.hpp" namespace glm { // -- Constructors -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat() # if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST : value{col_type(1, 0), col_type(0, 1)} # endif { # if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION this->value[0] = col_type(1, 0); this->value[1] = col_type(0, 1); # endif } # endif template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<2, 2, T, P> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{m[0], m[1]} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = m[0]; this->value[1] = m[1]; # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(T scalar) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(scalar, 0), col_type(0, scalar)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(scalar, 0); this->value[1] = col_type(0, scalar); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat ( T const& x0, T const& y0, T const& x1, T const& y1 ) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(x0, y0), col_type(x1, y1)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(x0, y0); this->value[1] = col_type(x1, y1); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(col_type const& v0, col_type const& v1) # if GLM_HAS_INITIALIZER_LISTS : value{v0, v1} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = v0; this->value[1] = v1; # endif } // -- Conversion constructors -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat ( X1 const& x1, Y1 const& y1, X2 const& x2, Y2 const& y2 ) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(static_cast(x1), value_type(y1)), col_type(static_cast(x2), value_type(y2)) } # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(static_cast(x1), value_type(y1)); this->value[1] = col_type(static_cast(x2), value_type(y2)); # endif } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(vec<2, V1, Q> const& v1, vec<2, V2, Q> const& v2) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(v1), col_type(v2)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(v1); this->value[1] = col_type(v2); # endif } // -- mat2x2 matrix conversions -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<2, 2, U, P> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<3, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<4, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<2, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<3, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<2, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<4, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<3, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<4, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); # endif } // -- Accesses -- template GLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::col_type& mat<2, 2, T, Q>::operator[](typename mat<2, 2, T, Q>::length_type i) { assert(i < this->length()); return this->value[i]; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<2, 2, T, Q>::col_type const& mat<2, 2, T, Q>::operator[](typename mat<2, 2, T, Q>::length_type i) const { assert(i < this->length()); return this->value[i]; } // -- Unary updatable operators -- template template GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator=(mat<2, 2, U, Q> const& m) { this->value[0] = m[0]; this->value[1] = m[1]; return *this; } template template GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator+=(U scalar) { this->value[0] += scalar; this->value[1] += scalar; return *this; } template template GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator+=(mat<2, 2, U, Q> const& m) { this->value[0] += m[0]; this->value[1] += m[1]; return *this; } template template GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator-=(U scalar) { this->value[0] -= scalar; this->value[1] -= scalar; return *this; } template template GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator-=(mat<2, 2, U, Q> const& m) { this->value[0] -= m[0]; this->value[1] -= m[1]; return *this; } template template GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator*=(U scalar) { this->value[0] *= scalar; this->value[1] *= scalar; return *this; } template template GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator*=(mat<2, 2, U, Q> const& m) { return (*this = *this * m); } template template GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator/=(U scalar) { this->value[0] /= scalar; this->value[1] /= scalar; return *this; } template template GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator/=(mat<2, 2, U, Q> const& m) { return *this *= inverse(m); } // -- Increment and decrement operators -- template GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator++() { ++this->value[0]; ++this->value[1]; return *this; } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator--() { --this->value[0]; --this->value[1]; return *this; } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> mat<2, 2, T, Q>::operator++(int) { mat<2, 2, T, Q> Result(*this); ++*this; return Result; } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> mat<2, 2, T, Q>::operator--(int) { mat<2, 2, T, Q> Result(*this); --*this; return Result; } // -- Unary arithmetic operators -- template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m) { return m; } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m) { return mat<2, 2, T, Q>( -m[0], -m[1]); } // -- Binary arithmetic operators -- template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m, T scalar) { return mat<2, 2, T, Q>( m[0] + scalar, m[1] + scalar); } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator+(T scalar, mat<2, 2, T, Q> const& m) { return mat<2, 2, T, Q>( m[0] + scalar, m[1] + scalar); } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) { return mat<2, 2, T, Q>( m1[0] + m2[0], m1[1] + m2[1]); } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m, T scalar) { return mat<2, 2, T, Q>( m[0] - scalar, m[1] - scalar); } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator-(T scalar, mat<2, 2, T, Q> const& m) { return mat<2, 2, T, Q>( scalar - m[0], scalar - m[1]); } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) { return mat<2, 2, T, Q>( m1[0] - m2[0], m1[1] - m2[1]); } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(mat<2, 2, T, Q> const& m, T scalar) { return mat<2, 2, T, Q>( m[0] * scalar, m[1] * scalar); } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(T scalar, mat<2, 2, T, Q> const& m) { return mat<2, 2, T, Q>( m[0] * scalar, m[1] * scalar); } template GLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::col_type operator* ( mat<2, 2, T, Q> const& m, typename mat<2, 2, T, Q>::row_type const& v ) { return vec<2, T, Q>( m[0][0] * v.x + m[1][0] * v.y, m[0][1] * v.x + m[1][1] * v.y); } template GLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::row_type operator* ( typename mat<2, 2, T, Q>::col_type const& v, mat<2, 2, T, Q> const& m ) { return vec<2, T, Q>( v.x * m[0][0] + v.y * m[0][1], v.x * m[1][0] + v.y * m[1][1]); } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) { return mat<2, 2, T, Q>( m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1]); } template GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2) { return mat<3, 2, T, Q>( m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1], m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1]); } template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2) { return mat<4, 2, T, Q>( m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1], m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1], m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1], m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1]); } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator/(mat<2, 2, T, Q> const& m, T scalar) { return mat<2, 2, T, Q>( m[0] / scalar, m[1] / scalar); } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator/(T scalar, mat<2, 2, T, Q> const& m) { return mat<2, 2, T, Q>( scalar / m[0], scalar / m[1]); } template GLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::col_type operator/(mat<2, 2, T, Q> const& m, typename mat<2, 2, T, Q>::row_type const& v) { return inverse(m) * v; } template GLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::row_type operator/(typename mat<2, 2, T, Q>::col_type const& v, mat<2, 2, T, Q> const& m) { return v * inverse(m); } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator/(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) { mat<2, 2, T, Q> m1_copy(m1); return m1_copy /= m2; } // -- Boolean operators -- template GLM_FUNC_QUALIFIER bool operator==(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) { return (m1[0] == m2[0]) && (m1[1] == m2[1]); } template GLM_FUNC_QUALIFIER bool operator!=(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2) { return (m1[0] != m2[0]) || (m1[1] != m2[1]); } } //namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/type_mat2x3.hpp000066400000000000000000000125171360521144700244550ustar00rootroot00000000000000/// @ref core /// @file glm/detail/type_mat2x3.hpp #pragma once #include "type_vec2.hpp" #include "type_vec3.hpp" #include #include namespace glm { template struct mat<2, 3, T, Q> { typedef vec<3, T, Q> col_type; typedef vec<2, T, Q> row_type; typedef mat<2, 3, T, Q> type; typedef mat<3, 2, T, Q> transpose_type; typedef T value_type; private: col_type value[2]; public: // -- Accesses -- typedef length_t length_type; GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 2; } GLM_FUNC_DECL col_type & operator[](length_type i); GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; // -- Constructors -- GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT; template GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<2, 3, T, P> const& m); GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); GLM_FUNC_DECL GLM_CONSTEXPR mat( T x0, T y0, T z0, T x1, T y1, T z1); GLM_FUNC_DECL GLM_CONSTEXPR mat( col_type const& v0, col_type const& v1); // -- Conversions -- template GLM_FUNC_DECL GLM_CONSTEXPR mat( X1 x1, Y1 y1, Z1 z1, X2 x2, Y2 y2, Z2 z2); template GLM_FUNC_DECL GLM_CONSTEXPR mat( vec<3, U, Q> const& v1, vec<3, V, Q> const& v2); // -- Matrix conversions -- template GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, U, P> const& m); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); // -- Unary arithmetic operators -- template GLM_FUNC_DECL mat<2, 3, T, Q> & operator=(mat<2, 3, U, Q> const& m); template GLM_FUNC_DECL mat<2, 3, T, Q> & operator+=(U s); template GLM_FUNC_DECL mat<2, 3, T, Q> & operator+=(mat<2, 3, U, Q> const& m); template GLM_FUNC_DECL mat<2, 3, T, Q> & operator-=(U s); template GLM_FUNC_DECL mat<2, 3, T, Q> & operator-=(mat<2, 3, U, Q> const& m); template GLM_FUNC_DECL mat<2, 3, T, Q> & operator*=(U s); template GLM_FUNC_DECL mat<2, 3, T, Q> & operator/=(U s); // -- Increment and decrement operators -- GLM_FUNC_DECL mat<2, 3, T, Q> & operator++ (); GLM_FUNC_DECL mat<2, 3, T, Q> & operator-- (); GLM_FUNC_DECL mat<2, 3, T, Q> operator++(int); GLM_FUNC_DECL mat<2, 3, T, Q> operator--(int); }; // -- Unary operators -- template GLM_FUNC_DECL mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m); template GLM_FUNC_DECL mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m); // -- Binary operators -- template GLM_FUNC_DECL mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2); template GLM_FUNC_DECL mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2); template GLM_FUNC_DECL mat<2, 3, T, Q> operator*(mat<2, 3, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<2, 3, T, Q> operator*(T scalar, mat<2, 3, T, Q> const& m); template GLM_FUNC_DECL typename mat<2, 3, T, Q>::col_type operator*(mat<2, 3, T, Q> const& m, typename mat<2, 3, T, Q>::row_type const& v); template GLM_FUNC_DECL typename mat<2, 3, T, Q>::row_type operator*(typename mat<2, 3, T, Q>::col_type const& v, mat<2, 3, T, Q> const& m); template GLM_FUNC_DECL mat<2, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<2, 2, T, Q> const& m2); template GLM_FUNC_DECL mat<3, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<3, 2, T, Q> const& m2); template GLM_FUNC_DECL mat<4, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<4, 2, T, Q> const& m2); template GLM_FUNC_DECL mat<2, 3, T, Q> operator/(mat<2, 3, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<2, 3, T, Q> operator/(T scalar, mat<2, 3, T, Q> const& m); // -- Boolean operators -- template GLM_FUNC_DECL bool operator==(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2); template GLM_FUNC_DECL bool operator!=(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2); }//namespace glm #ifndef GLM_EXTERNAL_TEMPLATE #include "type_mat2x3.inl" #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/type_mat2x3.inl000066400000000000000000000332011360521144700244410ustar00rootroot00000000000000namespace glm { // -- Constructors -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat() # if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST : value{col_type(1, 0, 0), col_type(0, 1, 0)} # endif { # if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION this->value[0] = col_type(1, 0, 0); this->value[1] = col_type(0, 1, 0); # endif } # endif template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<2, 3, T, P> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{m.value[0], m.value[1]} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = m.value[0]; this->value[1] = m.value[1]; # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(T scalar) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(scalar, 0, 0), col_type(0, scalar, 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(scalar, 0, 0); this->value[1] = col_type(0, scalar, 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat ( T x0, T y0, T z0, T x1, T y1, T z1 ) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(x0, y0, z0), col_type(x1, y1, z1)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(x0, y0, z0); this->value[1] = col_type(x1, y1, z1); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(col_type const& v0, col_type const& v1) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(v0), col_type(v1)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(v0); this->value[1] = col_type(v1); # endif } // -- Conversion constructors -- template template< typename X1, typename Y1, typename Z1, typename X2, typename Y2, typename Z2> GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat ( X1 x1, Y1 y1, Z1 z1, X2 x2, Y2 y2, Z2 z2 ) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(x1, y1, z1), col_type(x2, y2, z2)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(x1, y1, z1); this->value[1] = col_type(x2, y2, z2); # endif } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(vec<3, V1, Q> const& v1, vec<3, V2, Q> const& v2) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(v1), col_type(v2)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(v1); this->value[1] = col_type(v2); # endif } // -- Matrix conversions -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<2, 3, U, P> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<2, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0), col_type(m[1], 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0); this->value[1] = col_type(m[1], 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<3, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<4, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<2, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<3, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0), col_type(m[1], 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0); this->value[1] = col_type(m[1], 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<3, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<4, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0), col_type(m[1], 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0); this->value[1] = col_type(m[1], 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<4, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); # endif } // -- Accesses -- template GLM_FUNC_QUALIFIER typename mat<2, 3, T, Q>::col_type & mat<2, 3, T, Q>::operator[](typename mat<2, 3, T, Q>::length_type i) { assert(i < this->length()); return this->value[i]; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<2, 3, T, Q>::col_type const& mat<2, 3, T, Q>::operator[](typename mat<2, 3, T, Q>::length_type i) const { assert(i < this->length()); return this->value[i]; } // -- Unary updatable operators -- template template GLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator=(mat<2, 3, U, Q> const& m) { this->value[0] = m[0]; this->value[1] = m[1]; return *this; } template template GLM_FUNC_QUALIFIER mat<2, 3, T, Q> & mat<2, 3, T, Q>::operator+=(U s) { this->value[0] += s; this->value[1] += s; return *this; } template template GLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator+=(mat<2, 3, U, Q> const& m) { this->value[0] += m[0]; this->value[1] += m[1]; return *this; } template template GLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator-=(U s) { this->value[0] -= s; this->value[1] -= s; return *this; } template template GLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator-=(mat<2, 3, U, Q> const& m) { this->value[0] -= m[0]; this->value[1] -= m[1]; return *this; } template template GLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator*=(U s) { this->value[0] *= s; this->value[1] *= s; return *this; } template template GLM_FUNC_QUALIFIER mat<2, 3, T, Q> & mat<2, 3, T, Q>::operator/=(U s) { this->value[0] /= s; this->value[1] /= s; return *this; } // -- Increment and decrement operators -- template GLM_FUNC_QUALIFIER mat<2, 3, T, Q> & mat<2, 3, T, Q>::operator++() { ++this->value[0]; ++this->value[1]; return *this; } template GLM_FUNC_QUALIFIER mat<2, 3, T, Q> & mat<2, 3, T, Q>::operator--() { --this->value[0]; --this->value[1]; return *this; } template GLM_FUNC_QUALIFIER mat<2, 3, T, Q> mat<2, 3, T, Q>::operator++(int) { mat<2, 3, T, Q> Result(*this); ++*this; return Result; } template GLM_FUNC_QUALIFIER mat<2, 3, T, Q> mat<2, 3, T, Q>::operator--(int) { mat<2, 3, T, Q> Result(*this); --*this; return Result; } // -- Unary arithmetic operators -- template GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m) { return m; } template GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m) { return mat<2, 3, T, Q>( -m[0], -m[1]); } // -- Binary arithmetic operators -- template GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m, T scalar) { return mat<2, 3, T, Q>( m[0] + scalar, m[1] + scalar); } template GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2) { return mat<2, 3, T, Q>( m1[0] + m2[0], m1[1] + m2[1]); } template GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m, T scalar) { return mat<2, 3, T, Q>( m[0] - scalar, m[1] - scalar); } template GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2) { return mat<2, 3, T, Q>( m1[0] - m2[0], m1[1] - m2[1]); } template GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(mat<2, 3, T, Q> const& m, T scalar) { return mat<2, 3, T, Q>( m[0] * scalar, m[1] * scalar); } template GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(T scalar, mat<2, 3, T, Q> const& m) { return mat<2, 3, T, Q>( m[0] * scalar, m[1] * scalar); } template GLM_FUNC_QUALIFIER typename mat<2, 3, T, Q>::col_type operator* ( mat<2, 3, T, Q> const& m, typename mat<2, 3, T, Q>::row_type const& v) { return typename mat<2, 3, T, Q>::col_type( m[0][0] * v.x + m[1][0] * v.y, m[0][1] * v.x + m[1][1] * v.y, m[0][2] * v.x + m[1][2] * v.y); } template GLM_FUNC_QUALIFIER typename mat<2, 3, T, Q>::row_type operator* ( typename mat<2, 3, T, Q>::col_type const& v, mat<2, 3, T, Q> const& m) { return typename mat<2, 3, T, Q>::row_type( v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2], v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2]); } template GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<2, 2, T, Q> const& m2) { return mat<2, 3, T, Q>( m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1], m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1]); } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<3, 2, T, Q> const& m2) { T SrcA00 = m1[0][0]; T SrcA01 = m1[0][1]; T SrcA02 = m1[0][2]; T SrcA10 = m1[1][0]; T SrcA11 = m1[1][1]; T SrcA12 = m1[1][2]; T SrcB00 = m2[0][0]; T SrcB01 = m2[0][1]; T SrcB10 = m2[1][0]; T SrcB11 = m2[1][1]; T SrcB20 = m2[2][0]; T SrcB21 = m2[2][1]; mat<3, 3, T, Q> Result; Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01; Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01; Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01; Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11; Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11; Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11; Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21; Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21; Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21; return Result; } template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<4, 2, T, Q> const& m2) { return mat<4, 3, T, Q>( m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1], m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1], m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1], m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1], m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1], m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1], m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1], m1[0][2] * m2[3][0] + m1[1][2] * m2[3][1]); } template GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator/(mat<2, 3, T, Q> const& m, T scalar) { return mat<2, 3, T, Q>( m[0] / scalar, m[1] / scalar); } template GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator/(T scalar, mat<2, 3, T, Q> const& m) { return mat<2, 3, T, Q>( scalar / m[0], scalar / m[1]); } // -- Boolean operators -- template GLM_FUNC_QUALIFIER bool operator==(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2) { return (m1[0] == m2[0]) && (m1[1] == m2[1]); } template GLM_FUNC_QUALIFIER bool operator!=(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2) { return (m1[0] != m2[0]) || (m1[1] != m2[1]); } } //namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/type_mat2x4.hpp000066400000000000000000000126141360521144700244540ustar00rootroot00000000000000/// @ref core /// @file glm/detail/type_mat2x4.hpp #pragma once #include "type_vec2.hpp" #include "type_vec4.hpp" #include #include namespace glm { template struct mat<2, 4, T, Q> { typedef vec<4, T, Q> col_type; typedef vec<2, T, Q> row_type; typedef mat<2, 4, T, Q> type; typedef mat<4, 2, T, Q> transpose_type; typedef T value_type; private: col_type value[2]; public: // -- Accesses -- typedef length_t length_type; GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 2; } GLM_FUNC_DECL col_type & operator[](length_type i); GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; // -- Constructors -- GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT; template GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<2, 4, T, P> const& m); GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); GLM_FUNC_DECL GLM_CONSTEXPR mat( T x0, T y0, T z0, T w0, T x1, T y1, T z1, T w1); GLM_FUNC_DECL GLM_CONSTEXPR mat( col_type const& v0, col_type const& v1); // -- Conversions -- template< typename X1, typename Y1, typename Z1, typename W1, typename X2, typename Y2, typename Z2, typename W2> GLM_FUNC_DECL GLM_CONSTEXPR mat( X1 x1, Y1 y1, Z1 z1, W1 w1, X2 x2, Y2 y2, Z2 z2, W2 w2); template GLM_FUNC_DECL GLM_CONSTEXPR mat( vec<4, U, Q> const& v1, vec<4, V, Q> const& v2); // -- Matrix conversions -- template GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, U, P> const& m); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); // -- Unary arithmetic operators -- template GLM_FUNC_DECL mat<2, 4, T, Q> & operator=(mat<2, 4, U, Q> const& m); template GLM_FUNC_DECL mat<2, 4, T, Q> & operator+=(U s); template GLM_FUNC_DECL mat<2, 4, T, Q> & operator+=(mat<2, 4, U, Q> const& m); template GLM_FUNC_DECL mat<2, 4, T, Q> & operator-=(U s); template GLM_FUNC_DECL mat<2, 4, T, Q> & operator-=(mat<2, 4, U, Q> const& m); template GLM_FUNC_DECL mat<2, 4, T, Q> & operator*=(U s); template GLM_FUNC_DECL mat<2, 4, T, Q> & operator/=(U s); // -- Increment and decrement operators -- GLM_FUNC_DECL mat<2, 4, T, Q> & operator++ (); GLM_FUNC_DECL mat<2, 4, T, Q> & operator-- (); GLM_FUNC_DECL mat<2, 4, T, Q> operator++(int); GLM_FUNC_DECL mat<2, 4, T, Q> operator--(int); }; // -- Unary operators -- template GLM_FUNC_DECL mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m); template GLM_FUNC_DECL mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m); // -- Binary operators -- template GLM_FUNC_DECL mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2); template GLM_FUNC_DECL mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2); template GLM_FUNC_DECL mat<2, 4, T, Q> operator*(mat<2, 4, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<2, 4, T, Q> operator*(T scalar, mat<2, 4, T, Q> const& m); template GLM_FUNC_DECL typename mat<2, 4, T, Q>::col_type operator*(mat<2, 4, T, Q> const& m, typename mat<2, 4, T, Q>::row_type const& v); template GLM_FUNC_DECL typename mat<2, 4, T, Q>::row_type operator*(typename mat<2, 4, T, Q>::col_type const& v, mat<2, 4, T, Q> const& m); template GLM_FUNC_DECL mat<4, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<4, 2, T, Q> const& m2); template GLM_FUNC_DECL mat<2, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<2, 2, T, Q> const& m2); template GLM_FUNC_DECL mat<3, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<3, 2, T, Q> const& m2); template GLM_FUNC_DECL mat<2, 4, T, Q> operator/(mat<2, 4, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<2, 4, T, Q> operator/(T scalar, mat<2, 4, T, Q> const& m); // -- Boolean operators -- template GLM_FUNC_DECL bool operator==(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2); template GLM_FUNC_DECL bool operator!=(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2); }//namespace glm #ifndef GLM_EXTERNAL_TEMPLATE #include "type_mat2x4.inl" #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/type_mat2x4.inl000066400000000000000000000345301360521144700244500ustar00rootroot00000000000000namespace glm { // -- Constructors -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat() # if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST : value{col_type(1, 0, 0, 0), col_type(0, 1, 0, 0)} # endif { # if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION this->value[0] = col_type(1, 0, 0, 0); this->value[1] = col_type(0, 1, 0, 0); # endif } # endif template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<2, 4, T, P> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{m[0], m[1]} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = m[0]; this->value[1] = m[1]; # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(T s) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(s, 0, 0, 0), col_type(0, s, 0, 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(s, 0, 0, 0); this->value[1] = col_type(0, s, 0, 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat ( T x0, T y0, T z0, T w0, T x1, T y1, T z1, T w1 ) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(x0, y0, z0, w0), col_type(x1, y1, z1, w1)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(x0, y0, z0, w0); this->value[1] = col_type(x1, y1, z1, w1); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(col_type const& v0, col_type const& v1) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(v0), col_type(v1)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = v0; this->value[1] = v1; # endif } // -- Conversion constructors -- template template< typename X1, typename Y1, typename Z1, typename W1, typename X2, typename Y2, typename Z2, typename W2> GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat ( X1 x1, Y1 y1, Z1 z1, W1 w1, X2 x2, Y2 y2, Z2 z2, W2 w2 ) # if GLM_HAS_INITIALIZER_LISTS : value{ col_type(x1, y1, z1, w1), col_type(x2, y2, z2, w2)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(x1, y1, z1, w1); this->value[1] = col_type(x2, y2, z2, w2); # endif } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(vec<4, V1, Q> const& v1, vec<4, V2, Q> const& v2) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(v1), col_type(v2)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(v1); this->value[1] = col_type(v2); # endif } // -- Matrix conversions -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<2, 4, U, P> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<2, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0, 0); this->value[1] = col_type(m[1], 0, 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<3, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0), col_type(m[1], 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0); this->value[1] = col_type(m[1], 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<4, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<2, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0), col_type(m[1], 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0); this->value[1] = col_type(m[1], 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<3, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0, 0); this->value[1] = col_type(m[1], 0, 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<3, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<4, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0, 0); this->value[1] = col_type(m[1], 0, 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<4, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0), col_type(m[1], 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0); this->value[1] = col_type(m[1], 0); # endif } // -- Accesses -- template GLM_FUNC_QUALIFIER typename mat<2, 4, T, Q>::col_type & mat<2, 4, T, Q>::operator[](typename mat<2, 4, T, Q>::length_type i) { assert(i < this->length()); return this->value[i]; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<2, 4, T, Q>::col_type const& mat<2, 4, T, Q>::operator[](typename mat<2, 4, T, Q>::length_type i) const { assert(i < this->length()); return this->value[i]; } // -- Unary updatable operators -- template template GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator=(mat<2, 4, U, Q> const& m) { this->value[0] = m[0]; this->value[1] = m[1]; return *this; } template template GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator+=(U s) { this->value[0] += s; this->value[1] += s; return *this; } template template GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator+=(mat<2, 4, U, Q> const& m) { this->value[0] += m[0]; this->value[1] += m[1]; return *this; } template template GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator-=(U s) { this->value[0] -= s; this->value[1] -= s; return *this; } template template GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator-=(mat<2, 4, U, Q> const& m) { this->value[0] -= m[0]; this->value[1] -= m[1]; return *this; } template template GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator*=(U s) { this->value[0] *= s; this->value[1] *= s; return *this; } template template GLM_FUNC_QUALIFIER mat<2, 4, T, Q> & mat<2, 4, T, Q>::operator/=(U s) { this->value[0] /= s; this->value[1] /= s; return *this; } // -- Increment and decrement operators -- template GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator++() { ++this->value[0]; ++this->value[1]; return *this; } template GLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator--() { --this->value[0]; --this->value[1]; return *this; } template GLM_FUNC_QUALIFIER mat<2, 4, T, Q> mat<2, 4, T, Q>::operator++(int) { mat<2, 4, T, Q> Result(*this); ++*this; return Result; } template GLM_FUNC_QUALIFIER mat<2, 4, T, Q> mat<2, 4, T, Q>::operator--(int) { mat<2, 4, T, Q> Result(*this); --*this; return Result; } // -- Unary arithmetic operators -- template GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m) { return m; } template GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m) { return mat<2, 4, T, Q>( -m[0], -m[1]); } // -- Binary arithmetic operators -- template GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m, T scalar) { return mat<2, 4, T, Q>( m[0] + scalar, m[1] + scalar); } template GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2) { return mat<2, 4, T, Q>( m1[0] + m2[0], m1[1] + m2[1]); } template GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m, T scalar) { return mat<2, 4, T, Q>( m[0] - scalar, m[1] - scalar); } template GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2) { return mat<2, 4, T, Q>( m1[0] - m2[0], m1[1] - m2[1]); } template GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(mat<2, 4, T, Q> const& m, T scalar) { return mat<2, 4, T, Q>( m[0] * scalar, m[1] * scalar); } template GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(T scalar, mat<2, 4, T, Q> const& m) { return mat<2, 4, T, Q>( m[0] * scalar, m[1] * scalar); } template GLM_FUNC_QUALIFIER typename mat<2, 4, T, Q>::col_type operator*(mat<2, 4, T, Q> const& m, typename mat<2, 4, T, Q>::row_type const& v) { return typename mat<2, 4, T, Q>::col_type( m[0][0] * v.x + m[1][0] * v.y, m[0][1] * v.x + m[1][1] * v.y, m[0][2] * v.x + m[1][2] * v.y, m[0][3] * v.x + m[1][3] * v.y); } template GLM_FUNC_QUALIFIER typename mat<2, 4, T, Q>::row_type operator*(typename mat<2, 4, T, Q>::col_type const& v, mat<2, 4, T, Q> const& m) { return typename mat<2, 4, T, Q>::row_type( v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2] + v.w * m[0][3], v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2] + v.w * m[1][3]); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<4, 2, T, Q> const& m2) { T SrcA00 = m1[0][0]; T SrcA01 = m1[0][1]; T SrcA02 = m1[0][2]; T SrcA03 = m1[0][3]; T SrcA10 = m1[1][0]; T SrcA11 = m1[1][1]; T SrcA12 = m1[1][2]; T SrcA13 = m1[1][3]; T SrcB00 = m2[0][0]; T SrcB01 = m2[0][1]; T SrcB10 = m2[1][0]; T SrcB11 = m2[1][1]; T SrcB20 = m2[2][0]; T SrcB21 = m2[2][1]; T SrcB30 = m2[3][0]; T SrcB31 = m2[3][1]; mat<4, 4, T, Q> Result; Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01; Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01; Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01; Result[0][3] = SrcA03 * SrcB00 + SrcA13 * SrcB01; Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11; Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11; Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11; Result[1][3] = SrcA03 * SrcB10 + SrcA13 * SrcB11; Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21; Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21; Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21; Result[2][3] = SrcA03 * SrcB20 + SrcA13 * SrcB21; Result[3][0] = SrcA00 * SrcB30 + SrcA10 * SrcB31; Result[3][1] = SrcA01 * SrcB30 + SrcA11 * SrcB31; Result[3][2] = SrcA02 * SrcB30 + SrcA12 * SrcB31; Result[3][3] = SrcA03 * SrcB30 + SrcA13 * SrcB31; return Result; } template GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<2, 2, T, Q> const& m2) { return mat<2, 4, T, Q>( m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1], m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1], m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1], m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1]); } template GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<3, 2, T, Q> const& m2) { return mat<3, 4, T, Q>( m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1], m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1], m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1], m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1], m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1], m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1], m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1], m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1], m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1], m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1], m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1], m1[0][3] * m2[2][0] + m1[1][3] * m2[2][1]); } template GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator/(mat<2, 4, T, Q> const& m, T scalar) { return mat<2, 4, T, Q>( m[0] / scalar, m[1] / scalar); } template GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator/(T scalar, mat<2, 4, T, Q> const& m) { return mat<2, 4, T, Q>( scalar / m[0], scalar / m[1]); } // -- Boolean operators -- template GLM_FUNC_QUALIFIER bool operator==(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2) { return (m1[0] == m2[0]) && (m1[1] == m2[1]); } template GLM_FUNC_QUALIFIER bool operator!=(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2) { return (m1[0] != m2[0]) || (m1[1] != m2[1]); } } //namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/type_mat3x2.hpp000066400000000000000000000126541360521144700244570ustar00rootroot00000000000000/// @ref core /// @file glm/detail/type_mat3x2.hpp #pragma once #include "type_vec2.hpp" #include "type_vec3.hpp" #include #include namespace glm { template struct mat<3, 2, T, Q> { typedef vec<2, T, Q> col_type; typedef vec<3, T, Q> row_type; typedef mat<3, 2, T, Q> type; typedef mat<2, 3, T, Q> transpose_type; typedef T value_type; private: col_type value[3]; public: // -- Accesses -- typedef length_t length_type; GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 3; } GLM_FUNC_DECL col_type & operator[](length_type i); GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; // -- Constructors -- GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT; template GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<3, 2, T, P> const& m); GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); GLM_FUNC_DECL GLM_CONSTEXPR mat( T x0, T y0, T x1, T y1, T x2, T y2); GLM_FUNC_DECL GLM_CONSTEXPR mat( col_type const& v0, col_type const& v1, col_type const& v2); // -- Conversions -- template< typename X1, typename Y1, typename X2, typename Y2, typename X3, typename Y3> GLM_FUNC_DECL GLM_CONSTEXPR mat( X1 x1, Y1 y1, X2 x2, Y2 y2, X3 x3, Y3 y3); template GLM_FUNC_DECL GLM_CONSTEXPR mat( vec<2, V1, Q> const& v1, vec<2, V2, Q> const& v2, vec<2, V3, Q> const& v3); // -- Matrix conversions -- template GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, U, P> const& m); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); // -- Unary arithmetic operators -- template GLM_FUNC_DECL mat<3, 2, T, Q> & operator=(mat<3, 2, U, Q> const& m); template GLM_FUNC_DECL mat<3, 2, T, Q> & operator+=(U s); template GLM_FUNC_DECL mat<3, 2, T, Q> & operator+=(mat<3, 2, U, Q> const& m); template GLM_FUNC_DECL mat<3, 2, T, Q> & operator-=(U s); template GLM_FUNC_DECL mat<3, 2, T, Q> & operator-=(mat<3, 2, U, Q> const& m); template GLM_FUNC_DECL mat<3, 2, T, Q> & operator*=(U s); template GLM_FUNC_DECL mat<3, 2, T, Q> & operator/=(U s); // -- Increment and decrement operators -- GLM_FUNC_DECL mat<3, 2, T, Q> & operator++ (); GLM_FUNC_DECL mat<3, 2, T, Q> & operator-- (); GLM_FUNC_DECL mat<3, 2, T, Q> operator++(int); GLM_FUNC_DECL mat<3, 2, T, Q> operator--(int); }; // -- Unary operators -- template GLM_FUNC_DECL mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m); template GLM_FUNC_DECL mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m); // -- Binary operators -- template GLM_FUNC_DECL mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2); template GLM_FUNC_DECL mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2); template GLM_FUNC_DECL mat<3, 2, T, Q> operator*(mat<3, 2, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<3, 2, T, Q> operator*(T scalar, mat<3, 2, T, Q> const& m); template GLM_FUNC_DECL typename mat<3, 2, T, Q>::col_type operator*(mat<3, 2, T, Q> const& m, typename mat<3, 2, T, Q>::row_type const& v); template GLM_FUNC_DECL typename mat<3, 2, T, Q>::row_type operator*(typename mat<3, 2, T, Q>::col_type const& v, mat<3, 2, T, Q> const& m); template GLM_FUNC_DECL mat<2, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<2, 3, T, Q> const& m2); template GLM_FUNC_DECL mat<3, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<3, 3, T, Q> const& m2); template GLM_FUNC_DECL mat<4, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<4, 3, T, Q> const& m2); template GLM_FUNC_DECL mat<3, 2, T, Q> operator/(mat<3, 2, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<3, 2, T, Q> operator/(T scalar, mat<3, 2, T, Q> const& m); // -- Boolean operators -- template GLM_FUNC_DECL bool operator==(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2); template GLM_FUNC_DECL bool operator!=(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2); }//namespace glm #ifndef GLM_EXTERNAL_TEMPLATE #include "type_mat3x2.inl" #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/type_mat3x2.inl000066400000000000000000000352751360521144700244560ustar00rootroot00000000000000namespace glm { // -- Constructors -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat() # if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST : value{col_type(1, 0), col_type(0, 1), col_type(0, 0)} # endif { # if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION this->value[0] = col_type(1, 0); this->value[1] = col_type(0, 1); this->value[2] = col_type(0, 0); # endif } # endif template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<3, 2, T, P> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = m[0]; this->value[1] = m[1]; this->value[2] = m[2]; # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(T s) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(s, 0), col_type(0, s), col_type(0, 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(s, 0); this->value[1] = col_type(0, s); this->value[2] = col_type(0, 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat ( T x0, T y0, T x1, T y1, T x2, T y2 ) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(x0, y0), col_type(x1, y1), col_type(x2, y2)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(x0, y0); this->value[1] = col_type(x1, y1); this->value[2] = col_type(x2, y2); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(v0), col_type(v1), col_type(v2)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = v0; this->value[1] = v1; this->value[2] = v2; # endif } // -- Conversion constructors -- template template< typename X0, typename Y0, typename X1, typename Y1, typename X2, typename Y2> GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat ( X0 x0, Y0 y0, X1 x1, Y1 y1, X2 x2, Y2 y2 ) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(x0, y0), col_type(x1, y1), col_type(x2, y2)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(x0, y0); this->value[1] = col_type(x1, y1); this->value[2] = col_type(x2, y2); # endif } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(vec<2, V0, Q> const& v0, vec<2, V1, Q> const& v1, vec<2, V2, Q> const& v2) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(v0), col_type(v1), col_type(v2)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(v0); this->value[1] = col_type(v1); this->value[2] = col_type(v2); # endif } // -- Matrix conversions -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<3, 2, U, P> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<2, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = m[0]; this->value[1] = m[1]; this->value[2] = col_type(0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<3, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<4, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<2, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<2, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<3, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<4, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = m[0]; this->value[1] = m[1]; this->value[2] = m[2]; # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<4, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); # endif } // -- Accesses -- template GLM_FUNC_QUALIFIER typename mat<3, 2, T, Q>::col_type & mat<3, 2, T, Q>::operator[](typename mat<3, 2, T, Q>::length_type i) { assert(i < this->length()); return this->value[i]; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<3, 2, T, Q>::col_type const& mat<3, 2, T, Q>::operator[](typename mat<3, 2, T, Q>::length_type i) const { assert(i < this->length()); return this->value[i]; } // -- Unary updatable operators -- template template GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator=(mat<3, 2, U, Q> const& m) { this->value[0] = m[0]; this->value[1] = m[1]; this->value[2] = m[2]; return *this; } template template GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator+=(U s) { this->value[0] += s; this->value[1] += s; this->value[2] += s; return *this; } template template GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator+=(mat<3, 2, U, Q> const& m) { this->value[0] += m[0]; this->value[1] += m[1]; this->value[2] += m[2]; return *this; } template template GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator-=(U s) { this->value[0] -= s; this->value[1] -= s; this->value[2] -= s; return *this; } template template GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator-=(mat<3, 2, U, Q> const& m) { this->value[0] -= m[0]; this->value[1] -= m[1]; this->value[2] -= m[2]; return *this; } template template GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator*=(U s) { this->value[0] *= s; this->value[1] *= s; this->value[2] *= s; return *this; } template template GLM_FUNC_QUALIFIER mat<3, 2, T, Q> & mat<3, 2, T, Q>::operator/=(U s) { this->value[0] /= s; this->value[1] /= s; this->value[2] /= s; return *this; } // -- Increment and decrement operators -- template GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator++() { ++this->value[0]; ++this->value[1]; ++this->value[2]; return *this; } template GLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator--() { --this->value[0]; --this->value[1]; --this->value[2]; return *this; } template GLM_FUNC_QUALIFIER mat<3, 2, T, Q> mat<3, 2, T, Q>::operator++(int) { mat<3, 2, T, Q> Result(*this); ++*this; return Result; } template GLM_FUNC_QUALIFIER mat<3, 2, T, Q> mat<3, 2, T, Q>::operator--(int) { mat<3, 2, T, Q> Result(*this); --*this; return Result; } // -- Unary arithmetic operators -- template GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m) { return m; } template GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m) { return mat<3, 2, T, Q>( -m[0], -m[1], -m[2]); } // -- Binary arithmetic operators -- template GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m, T scalar) { return mat<3, 2, T, Q>( m[0] + scalar, m[1] + scalar, m[2] + scalar); } template GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2) { return mat<3, 2, T, Q>( m1[0] + m2[0], m1[1] + m2[1], m1[2] + m2[2]); } template GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m, T scalar) { return mat<3, 2, T, Q>( m[0] - scalar, m[1] - scalar, m[2] - scalar); } template GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2) { return mat<3, 2, T, Q>( m1[0] - m2[0], m1[1] - m2[1], m1[2] - m2[2]); } template GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(mat<3, 2, T, Q> const& m, T scalar) { return mat<3, 2, T, Q>( m[0] * scalar, m[1] * scalar, m[2] * scalar); } template GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(T scalar, mat<3, 2, T, Q> const& m) { return mat<3, 2, T, Q>( m[0] * scalar, m[1] * scalar, m[2] * scalar); } template GLM_FUNC_QUALIFIER typename mat<3, 2, T, Q>::col_type operator*(mat<3, 2, T, Q> const& m, typename mat<3, 2, T, Q>::row_type const& v) { return typename mat<3, 2, T, Q>::col_type( m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z, m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z); } template GLM_FUNC_QUALIFIER typename mat<3, 2, T, Q>::row_type operator*(typename mat<3, 2, T, Q>::col_type const& v, mat<3, 2, T, Q> const& m) { return typename mat<3, 2, T, Q>::row_type( v.x * m[0][0] + v.y * m[0][1], v.x * m[1][0] + v.y * m[1][1], v.x * m[2][0] + v.y * m[2][1]); } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<2, 3, T, Q> const& m2) { const T SrcA00 = m1[0][0]; const T SrcA01 = m1[0][1]; const T SrcA10 = m1[1][0]; const T SrcA11 = m1[1][1]; const T SrcA20 = m1[2][0]; const T SrcA21 = m1[2][1]; const T SrcB00 = m2[0][0]; const T SrcB01 = m2[0][1]; const T SrcB02 = m2[0][2]; const T SrcB10 = m2[1][0]; const T SrcB11 = m2[1][1]; const T SrcB12 = m2[1][2]; mat<2, 2, T, Q> Result; Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02; Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02; Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12; Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12; return Result; } template GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<3, 3, T, Q> const& m2) { return mat<3, 2, T, Q>( m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2], m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2]); } template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<4, 3, T, Q> const& m2) { return mat<4, 2, T, Q>( m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2], m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2], m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2], m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2]); } template GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator/(mat<3, 2, T, Q> const& m, T scalar) { return mat<3, 2, T, Q>( m[0] / scalar, m[1] / scalar, m[2] / scalar); } template GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator/(T scalar, mat<3, 2, T, Q> const& m) { return mat<3, 2, T, Q>( scalar / m[0], scalar / m[1], scalar / m[2]); } // -- Boolean operators -- template GLM_FUNC_QUALIFIER bool operator==(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2) { return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]); } template GLM_FUNC_QUALIFIER bool operator!=(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2) { return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]); } } //namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/type_mat3x3.hpp000066400000000000000000000145631360521144700244610ustar00rootroot00000000000000/// @ref core /// @file glm/detail/type_mat3x3.hpp #pragma once #include "type_vec3.hpp" #include #include namespace glm { template struct mat<3, 3, T, Q> { typedef vec<3, T, Q> col_type; typedef vec<3, T, Q> row_type; typedef mat<3, 3, T, Q> type; typedef mat<3, 3, T, Q> transpose_type; typedef T value_type; private: col_type value[3]; public: // -- Accesses -- typedef length_t length_type; GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 3; } GLM_FUNC_DECL col_type & operator[](length_type i); GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; // -- Constructors -- GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT; template GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<3, 3, T, P> const& m); GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); GLM_FUNC_DECL GLM_CONSTEXPR mat( T x0, T y0, T z0, T x1, T y1, T z1, T x2, T y2, T z2); GLM_FUNC_DECL GLM_CONSTEXPR mat( col_type const& v0, col_type const& v1, col_type const& v2); // -- Conversions -- template< typename X1, typename Y1, typename Z1, typename X2, typename Y2, typename Z2, typename X3, typename Y3, typename Z3> GLM_FUNC_DECL GLM_CONSTEXPR mat( X1 x1, Y1 y1, Z1 z1, X2 x2, Y2 y2, Z2 z2, X3 x3, Y3 y3, Z3 z3); template GLM_FUNC_DECL GLM_CONSTEXPR mat( vec<3, V1, Q> const& v1, vec<3, V2, Q> const& v2, vec<3, V3, Q> const& v3); // -- Matrix conversions -- template GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, U, P> const& m); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); // -- Unary arithmetic operators -- template GLM_FUNC_DECL mat<3, 3, T, Q> & operator=(mat<3, 3, U, Q> const& m); template GLM_FUNC_DECL mat<3, 3, T, Q> & operator+=(U s); template GLM_FUNC_DECL mat<3, 3, T, Q> & operator+=(mat<3, 3, U, Q> const& m); template GLM_FUNC_DECL mat<3, 3, T, Q> & operator-=(U s); template GLM_FUNC_DECL mat<3, 3, T, Q> & operator-=(mat<3, 3, U, Q> const& m); template GLM_FUNC_DECL mat<3, 3, T, Q> & operator*=(U s); template GLM_FUNC_DECL mat<3, 3, T, Q> & operator*=(mat<3, 3, U, Q> const& m); template GLM_FUNC_DECL mat<3, 3, T, Q> & operator/=(U s); template GLM_FUNC_DECL mat<3, 3, T, Q> & operator/=(mat<3, 3, U, Q> const& m); // -- Increment and decrement operators -- GLM_FUNC_DECL mat<3, 3, T, Q> & operator++(); GLM_FUNC_DECL mat<3, 3, T, Q> & operator--(); GLM_FUNC_DECL mat<3, 3, T, Q> operator++(int); GLM_FUNC_DECL mat<3, 3, T, Q> operator--(int); }; // -- Unary operators -- template GLM_FUNC_DECL mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m); template GLM_FUNC_DECL mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m); // -- Binary operators -- template GLM_FUNC_DECL mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<3, 3, T, Q> operator+(T scalar, mat<3, 3, T, Q> const& m); template GLM_FUNC_DECL mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); template GLM_FUNC_DECL mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<3, 3, T, Q> operator-(T scalar, mat<3, 3, T, Q> const& m); template GLM_FUNC_DECL mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); template GLM_FUNC_DECL mat<3, 3, T, Q> operator*(mat<3, 3, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<3, 3, T, Q> operator*(T scalar, mat<3, 3, T, Q> const& m); template GLM_FUNC_DECL typename mat<3, 3, T, Q>::col_type operator*(mat<3, 3, T, Q> const& m, typename mat<3, 3, T, Q>::row_type const& v); template GLM_FUNC_DECL typename mat<3, 3, T, Q>::row_type operator*(typename mat<3, 3, T, Q>::col_type const& v, mat<3, 3, T, Q> const& m); template GLM_FUNC_DECL mat<3, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); template GLM_FUNC_DECL mat<2, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2); template GLM_FUNC_DECL mat<4, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2); template GLM_FUNC_DECL mat<3, 3, T, Q> operator/(mat<3, 3, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<3, 3, T, Q> operator/(T scalar, mat<3, 3, T, Q> const& m); template GLM_FUNC_DECL typename mat<3, 3, T, Q>::col_type operator/(mat<3, 3, T, Q> const& m, typename mat<3, 3, T, Q>::row_type const& v); template GLM_FUNC_DECL typename mat<3, 3, T, Q>::row_type operator/(typename mat<3, 3, T, Q>::col_type const& v, mat<3, 3, T, Q> const& m); template GLM_FUNC_DECL mat<3, 3, T, Q> operator/(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); // -- Boolean operators -- template GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); template GLM_FUNC_DECL bool operator!=(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2); }//namespace glm #ifndef GLM_EXTERNAL_TEMPLATE #include "type_mat3x3.inl" #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/type_mat3x3.inl000066400000000000000000000425751360521144700244600ustar00rootroot00000000000000#include "../matrix.hpp" namespace glm { // -- Constructors -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat() # if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST : value{col_type(1, 0, 0), col_type(0, 1, 0), col_type(0, 0, 1)} # endif { # if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION this->value[0] = col_type(1, 0, 0); this->value[1] = col_type(0, 1, 0); this->value[2] = col_type(0, 0, 1); # endif } # endif template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<3, 3, T, P> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(T s) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(s, 0, 0), col_type(0, s, 0), col_type(0, 0, s)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(s, 0, 0); this->value[1] = col_type(0, s, 0); this->value[2] = col_type(0, 0, s); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat ( T x0, T y0, T z0, T x1, T y1, T z1, T x2, T y2, T z2 ) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(x0, y0, z0), col_type(x1, y1, z1), col_type(x2, y2, z2)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(x0, y0, z0); this->value[1] = col_type(x1, y1, z1); this->value[2] = col_type(x2, y2, z2); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(v0), col_type(v1), col_type(v2)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(v0); this->value[1] = col_type(v1); this->value[2] = col_type(v2); # endif } // -- Conversion constructors -- template template< typename X1, typename Y1, typename Z1, typename X2, typename Y2, typename Z2, typename X3, typename Y3, typename Z3> GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat ( X1 x1, Y1 y1, Z1 z1, X2 x2, Y2 y2, Z2 z2, X3 x3, Y3 y3, Z3 z3 ) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(x1, y1, z1), col_type(x2, y2, z2), col_type(x3, y3, z3)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(x1, y1, z1); this->value[1] = col_type(x2, y2, z2); this->value[2] = col_type(x3, y3, z3); # endif } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(vec<3, V1, Q> const& v1, vec<3, V2, Q> const& v2, vec<3, V3, Q> const& v3) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(v1), col_type(v2), col_type(v3)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(v1); this->value[1] = col_type(v2); this->value[2] = col_type(v3); # endif } // -- Matrix conversions -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<3, 3, U, P> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<2, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0), col_type(m[1], 0), col_type(0, 0, 1)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0); this->value[1] = col_type(m[1], 0); this->value[2] = col_type(0, 0, 1); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<4, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<2, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(0, 0, 1); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<3, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 1)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0); this->value[1] = col_type(m[1], 0); this->value[2] = col_type(m[2], 1); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<2, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(0, 0, 1); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<4, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 1)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0); this->value[1] = col_type(m[1], 0); this->value[2] = col_type(m[2], 1); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<3, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<4, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); # endif } // -- Accesses -- template GLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::col_type & mat<3, 3, T, Q>::operator[](typename mat<3, 3, T, Q>::length_type i) { assert(i < this->length()); return this->value[i]; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<3, 3, T, Q>::col_type const& mat<3, 3, T, Q>::operator[](typename mat<3, 3, T, Q>::length_type i) const { assert(i < this->length()); return this->value[i]; } // -- Unary updatable operators -- template template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator=(mat<3, 3, U, Q> const& m) { this->value[0] = m[0]; this->value[1] = m[1]; this->value[2] = m[2]; return *this; } template template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator+=(U s) { this->value[0] += s; this->value[1] += s; this->value[2] += s; return *this; } template template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator+=(mat<3, 3, U, Q> const& m) { this->value[0] += m[0]; this->value[1] += m[1]; this->value[2] += m[2]; return *this; } template template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator-=(U s) { this->value[0] -= s; this->value[1] -= s; this->value[2] -= s; return *this; } template template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator-=(mat<3, 3, U, Q> const& m) { this->value[0] -= m[0]; this->value[1] -= m[1]; this->value[2] -= m[2]; return *this; } template template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator*=(U s) { this->value[0] *= s; this->value[1] *= s; this->value[2] *= s; return *this; } template template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator*=(mat<3, 3, U, Q> const& m) { return (*this = *this * m); } template template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator/=(U s) { this->value[0] /= s; this->value[1] /= s; this->value[2] /= s; return *this; } template template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator/=(mat<3, 3, U, Q> const& m) { return *this *= inverse(m); } // -- Increment and decrement operators -- template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator++() { ++this->value[0]; ++this->value[1]; ++this->value[2]; return *this; } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator--() { --this->value[0]; --this->value[1]; --this->value[2]; return *this; } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> mat<3, 3, T, Q>::operator++(int) { mat<3, 3, T, Q> Result(*this); ++*this; return Result; } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> mat<3, 3, T, Q>::operator--(int) { mat<3, 3, T, Q> Result(*this); --*this; return Result; } // -- Unary arithmetic operators -- template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m) { return m; } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m) { return mat<3, 3, T, Q>( -m[0], -m[1], -m[2]); } // -- Binary arithmetic operators -- template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m, T scalar) { return mat<3, 3, T, Q>( m[0] + scalar, m[1] + scalar, m[2] + scalar); } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator+(T scalar, mat<3, 3, T, Q> const& m) { return mat<3, 3, T, Q>( m[0] + scalar, m[1] + scalar, m[2] + scalar); } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) { return mat<3, 3, T, Q>( m1[0] + m2[0], m1[1] + m2[1], m1[2] + m2[2]); } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m, T scalar) { return mat<3, 3, T, Q>( m[0] - scalar, m[1] - scalar, m[2] - scalar); } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator-(T scalar, mat<3, 3, T, Q> const& m) { return mat<3, 3, T, Q>( scalar - m[0], scalar - m[1], scalar - m[2]); } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) { return mat<3, 3, T, Q>( m1[0] - m2[0], m1[1] - m2[1], m1[2] - m2[2]); } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(mat<3, 3, T, Q> const& m, T scalar) { return mat<3, 3, T, Q>( m[0] * scalar, m[1] * scalar, m[2] * scalar); } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(T scalar, mat<3, 3, T, Q> const& m) { return mat<3, 3, T, Q>( m[0] * scalar, m[1] * scalar, m[2] * scalar); } template GLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::col_type operator*(mat<3, 3, T, Q> const& m, typename mat<3, 3, T, Q>::row_type const& v) { return typename mat<3, 3, T, Q>::col_type( m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z, m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z, m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z); } template GLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::row_type operator*(typename mat<3, 3, T, Q>::col_type const& v, mat<3, 3, T, Q> const& m) { return typename mat<3, 3, T, Q>::row_type( m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z, m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z, m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z); } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) { T const SrcA00 = m1[0][0]; T const SrcA01 = m1[0][1]; T const SrcA02 = m1[0][2]; T const SrcA10 = m1[1][0]; T const SrcA11 = m1[1][1]; T const SrcA12 = m1[1][2]; T const SrcA20 = m1[2][0]; T const SrcA21 = m1[2][1]; T const SrcA22 = m1[2][2]; T const SrcB00 = m2[0][0]; T const SrcB01 = m2[0][1]; T const SrcB02 = m2[0][2]; T const SrcB10 = m2[1][0]; T const SrcB11 = m2[1][1]; T const SrcB12 = m2[1][2]; T const SrcB20 = m2[2][0]; T const SrcB21 = m2[2][1]; T const SrcB22 = m2[2][2]; mat<3, 3, T, Q> Result; Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02; Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02; Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01 + SrcA22 * SrcB02; Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12; Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12; Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11 + SrcA22 * SrcB12; Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21 + SrcA20 * SrcB22; Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21 + SrcA21 * SrcB22; Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21 + SrcA22 * SrcB22; return Result; } template GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2) { return mat<2, 3, T, Q>( m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2], m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2]); } template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2) { return mat<4, 3, T, Q>( m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2], m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2], m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2], m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2], m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2], m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2], m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2], m1[0][2] * m2[3][0] + m1[1][2] * m2[3][1] + m1[2][2] * m2[3][2]); } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator/(mat<3, 3, T, Q> const& m, T scalar) { return mat<3, 3, T, Q>( m[0] / scalar, m[1] / scalar, m[2] / scalar); } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator/(T scalar, mat<3, 3, T, Q> const& m) { return mat<3, 3, T, Q>( scalar / m[0], scalar / m[1], scalar / m[2]); } template GLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::col_type operator/(mat<3, 3, T, Q> const& m, typename mat<3, 3, T, Q>::row_type const& v) { return inverse(m) * v; } template GLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::row_type operator/(typename mat<3, 3, T, Q>::col_type const& v, mat<3, 3, T, Q> const& m) { return v * inverse(m); } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator/(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) { mat<3, 3, T, Q> m1_copy(m1); return m1_copy /= m2; } // -- Boolean operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) { return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]); } template GLM_FUNC_QUALIFIER bool operator!=(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2) { return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]); } } //namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/type_mat3x4.hpp000066400000000000000000000131041360521144700244500ustar00rootroot00000000000000/// @ref core /// @file glm/detail/type_mat3x4.hpp #pragma once #include "type_vec3.hpp" #include "type_vec4.hpp" #include #include namespace glm { template struct mat<3, 4, T, Q> { typedef vec<4, T, Q> col_type; typedef vec<3, T, Q> row_type; typedef mat<3, 4, T, Q> type; typedef mat<4, 3, T, Q> transpose_type; typedef T value_type; private: col_type value[3]; public: // -- Accesses -- typedef length_t length_type; GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 3; } GLM_FUNC_DECL col_type & operator[](length_type i); GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; // -- Constructors -- GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT; template GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<3, 4, T, P> const& m); GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); GLM_FUNC_DECL GLM_CONSTEXPR mat( T x0, T y0, T z0, T w0, T x1, T y1, T z1, T w1, T x2, T y2, T z2, T w2); GLM_FUNC_DECL GLM_CONSTEXPR mat( col_type const& v0, col_type const& v1, col_type const& v2); // -- Conversions -- template< typename X1, typename Y1, typename Z1, typename W1, typename X2, typename Y2, typename Z2, typename W2, typename X3, typename Y3, typename Z3, typename W3> GLM_FUNC_DECL GLM_CONSTEXPR mat( X1 x1, Y1 y1, Z1 z1, W1 w1, X2 x2, Y2 y2, Z2 z2, W2 w2, X3 x3, Y3 y3, Z3 z3, W3 w3); template GLM_FUNC_DECL GLM_CONSTEXPR mat( vec<4, V1, Q> const& v1, vec<4, V2, Q> const& v2, vec<4, V3, Q> const& v3); // -- Matrix conversions -- template GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, U, P> const& m); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); // -- Unary arithmetic operators -- template GLM_FUNC_DECL mat<3, 4, T, Q> & operator=(mat<3, 4, U, Q> const& m); template GLM_FUNC_DECL mat<3, 4, T, Q> & operator+=(U s); template GLM_FUNC_DECL mat<3, 4, T, Q> & operator+=(mat<3, 4, U, Q> const& m); template GLM_FUNC_DECL mat<3, 4, T, Q> & operator-=(U s); template GLM_FUNC_DECL mat<3, 4, T, Q> & operator-=(mat<3, 4, U, Q> const& m); template GLM_FUNC_DECL mat<3, 4, T, Q> & operator*=(U s); template GLM_FUNC_DECL mat<3, 4, T, Q> & operator/=(U s); // -- Increment and decrement operators -- GLM_FUNC_DECL mat<3, 4, T, Q> & operator++(); GLM_FUNC_DECL mat<3, 4, T, Q> & operator--(); GLM_FUNC_DECL mat<3, 4, T, Q> operator++(int); GLM_FUNC_DECL mat<3, 4, T, Q> operator--(int); }; // -- Unary operators -- template GLM_FUNC_DECL mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m); template GLM_FUNC_DECL mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m); // -- Binary operators -- template GLM_FUNC_DECL mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2); template GLM_FUNC_DECL mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2); template GLM_FUNC_DECL mat<3, 4, T, Q> operator*(mat<3, 4, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<3, 4, T, Q> operator*(T scalar, mat<3, 4, T, Q> const& m); template GLM_FUNC_DECL typename mat<3, 4, T, Q>::col_type operator*(mat<3, 4, T, Q> const& m, typename mat<3, 4, T, Q>::row_type const& v); template GLM_FUNC_DECL typename mat<3, 4, T, Q>::row_type operator*(typename mat<3, 4, T, Q>::col_type const& v, mat<3, 4, T, Q> const& m); template GLM_FUNC_DECL mat<4, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<4, 3, T, Q> const& m2); template GLM_FUNC_DECL mat<2, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<2, 3, T, Q> const& m2); template GLM_FUNC_DECL mat<3, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<3, 3, T, Q> const& m2); template GLM_FUNC_DECL mat<3, 4, T, Q> operator/(mat<3, 4, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<3, 4, T, Q> operator/(T scalar, mat<3, 4, T, Q> const& m); // -- Boolean operators -- template GLM_FUNC_DECL bool operator==(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2); template GLM_FUNC_DECL bool operator!=(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2); }//namespace glm #ifndef GLM_EXTERNAL_TEMPLATE #include "type_mat3x4.inl" #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/type_mat3x4.inl000066400000000000000000000421231360521144700244460ustar00rootroot00000000000000namespace glm { // -- Constructors -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat() # if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST : value{col_type(1, 0, 0, 0), col_type(0, 1, 0, 0), col_type(0, 0, 1, 0)} # endif { # if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION this->value[0] = col_type(1, 0, 0, 0); this->value[1] = col_type(0, 1, 0, 0); this->value[2] = col_type(0, 0, 1, 0); # endif } # endif template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<3, 4, T, P> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = m[0]; this->value[1] = m[1]; this->value[2] = m[2]; # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(T s) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(s, 0, 0, 0), col_type(0, s, 0, 0), col_type(0, 0, s, 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(s, 0, 0, 0); this->value[1] = col_type(0, s, 0, 0); this->value[2] = col_type(0, 0, s, 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat ( T x0, T y0, T z0, T w0, T x1, T y1, T z1, T w1, T x2, T y2, T z2, T w2 ) # if GLM_HAS_INITIALIZER_LISTS : value{ col_type(x0, y0, z0, w0), col_type(x1, y1, z1, w1), col_type(x2, y2, z2, w2)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(x0, y0, z0, w0); this->value[1] = col_type(x1, y1, z1, w1); this->value[2] = col_type(x2, y2, z2, w2); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(v0), col_type(v1), col_type(v2)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = v0; this->value[1] = v1; this->value[2] = v2; # endif } // -- Conversion constructors -- template template< typename X0, typename Y0, typename Z0, typename W0, typename X1, typename Y1, typename Z1, typename W1, typename X2, typename Y2, typename Z2, typename W2> GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat ( X0 x0, Y0 y0, Z0 z0, W0 w0, X1 x1, Y1 y1, Z1 z1, W1 w1, X2 x2, Y2 y2, Z2 z2, W2 w2 ) # if GLM_HAS_INITIALIZER_LISTS : value{ col_type(x0, y0, z0, w0), col_type(x1, y1, z1, w1), col_type(x2, y2, z2, w2)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(x0, y0, z0, w0); this->value[1] = col_type(x1, y1, z1, w1); this->value[2] = col_type(x2, y2, z2, w2); # endif } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(vec<4, V1, Q> const& v0, vec<4, V2, Q> const& v1, vec<4, V3, Q> const& v2) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(v0), col_type(v1), col_type(v2)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(v0); this->value[1] = col_type(v1); this->value[2] = col_type(v2); # endif } // -- Matrix conversions -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<3, 4, U, P> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<2, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(0, 0, 1, 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0, 0); this->value[1] = col_type(m[1], 0, 0); this->value[2] = col_type(0, 0, 1, 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<3, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0); this->value[1] = col_type(m[1], 0); this->value[2] = col_type(m[2], 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<4, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<2, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0), col_type(m[1], 0), col_type(0, 0, 1, 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0); this->value[1] = col_type(m[1], 0); this->value[2] = col_type(0, 0, 1, 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<3, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(m[2], 1, 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0, 0); this->value[1] = col_type(m[1], 0, 0); this->value[2] = col_type(m[2], 1, 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<2, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1, 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(0, 0, 1, 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<4, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(m[2], 1, 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0, 0); this->value[1] = col_type(m[1], 0, 0); this->value[2] = col_type(m[2], 1, 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<4, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0); this->value[1] = col_type(m[1], 0); this->value[2] = col_type(m[2], 0); # endif } // -- Accesses -- template GLM_FUNC_QUALIFIER typename mat<3, 4, T, Q>::col_type & mat<3, 4, T, Q>::operator[](typename mat<3, 4, T, Q>::length_type i) { assert(i < this->length()); return this->value[i]; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<3, 4, T, Q>::col_type const& mat<3, 4, T, Q>::operator[](typename mat<3, 4, T, Q>::length_type i) const { assert(i < this->length()); return this->value[i]; } // -- Unary updatable operators -- template template GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator=(mat<3, 4, U, Q> const& m) { this->value[0] = m[0]; this->value[1] = m[1]; this->value[2] = m[2]; return *this; } template template GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator+=(U s) { this->value[0] += s; this->value[1] += s; this->value[2] += s; return *this; } template template GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator+=(mat<3, 4, U, Q> const& m) { this->value[0] += m[0]; this->value[1] += m[1]; this->value[2] += m[2]; return *this; } template template GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator-=(U s) { this->value[0] -= s; this->value[1] -= s; this->value[2] -= s; return *this; } template template GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator-=(mat<3, 4, U, Q> const& m) { this->value[0] -= m[0]; this->value[1] -= m[1]; this->value[2] -= m[2]; return *this; } template template GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator*=(U s) { this->value[0] *= s; this->value[1] *= s; this->value[2] *= s; return *this; } template template GLM_FUNC_QUALIFIER mat<3, 4, T, Q> & mat<3, 4, T, Q>::operator/=(U s) { this->value[0] /= s; this->value[1] /= s; this->value[2] /= s; return *this; } // -- Increment and decrement operators -- template GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator++() { ++this->value[0]; ++this->value[1]; ++this->value[2]; return *this; } template GLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator--() { --this->value[0]; --this->value[1]; --this->value[2]; return *this; } template GLM_FUNC_QUALIFIER mat<3, 4, T, Q> mat<3, 4, T, Q>::operator++(int) { mat<3, 4, T, Q> Result(*this); ++*this; return Result; } template GLM_FUNC_QUALIFIER mat<3, 4, T, Q> mat<3, 4, T, Q>::operator--(int) { mat<3, 4, T, Q> Result(*this); --*this; return Result; } // -- Unary arithmetic operators -- template GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m) { return m; } template GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m) { return mat<3, 4, T, Q>( -m[0], -m[1], -m[2]); } // -- Binary arithmetic operators -- template GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m, T scalar) { return mat<3, 4, T, Q>( m[0] + scalar, m[1] + scalar, m[2] + scalar); } template GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2) { return mat<3, 4, T, Q>( m1[0] + m2[0], m1[1] + m2[1], m1[2] + m2[2]); } template GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m, T scalar) { return mat<3, 4, T, Q>( m[0] - scalar, m[1] - scalar, m[2] - scalar); } template GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2) { return mat<3, 4, T, Q>( m1[0] - m2[0], m1[1] - m2[1], m1[2] - m2[2]); } template GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(mat<3, 4, T, Q> const& m, T scalar) { return mat<3, 4, T, Q>( m[0] * scalar, m[1] * scalar, m[2] * scalar); } template GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(T scalar, mat<3, 4, T, Q> const& m) { return mat<3, 4, T, Q>( m[0] * scalar, m[1] * scalar, m[2] * scalar); } template GLM_FUNC_QUALIFIER typename mat<3, 4, T, Q>::col_type operator* ( mat<3, 4, T, Q> const& m, typename mat<3, 4, T, Q>::row_type const& v ) { return typename mat<3, 4, T, Q>::col_type( m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z, m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z, m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z, m[0][3] * v.x + m[1][3] * v.y + m[2][3] * v.z); } template GLM_FUNC_QUALIFIER typename mat<3, 4, T, Q>::row_type operator* ( typename mat<3, 4, T, Q>::col_type const& v, mat<3, 4, T, Q> const& m ) { return typename mat<3, 4, T, Q>::row_type( v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2] + v.w * m[0][3], v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2] + v.w * m[1][3], v.x * m[2][0] + v.y * m[2][1] + v.z * m[2][2] + v.w * m[2][3]); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<4, 3, T, Q> const& m2) { const T SrcA00 = m1[0][0]; const T SrcA01 = m1[0][1]; const T SrcA02 = m1[0][2]; const T SrcA03 = m1[0][3]; const T SrcA10 = m1[1][0]; const T SrcA11 = m1[1][1]; const T SrcA12 = m1[1][2]; const T SrcA13 = m1[1][3]; const T SrcA20 = m1[2][0]; const T SrcA21 = m1[2][1]; const T SrcA22 = m1[2][2]; const T SrcA23 = m1[2][3]; const T SrcB00 = m2[0][0]; const T SrcB01 = m2[0][1]; const T SrcB02 = m2[0][2]; const T SrcB10 = m2[1][0]; const T SrcB11 = m2[1][1]; const T SrcB12 = m2[1][2]; const T SrcB20 = m2[2][0]; const T SrcB21 = m2[2][1]; const T SrcB22 = m2[2][2]; const T SrcB30 = m2[3][0]; const T SrcB31 = m2[3][1]; const T SrcB32 = m2[3][2]; mat<4, 4, T, Q> Result; Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02; Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02; Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01 + SrcA22 * SrcB02; Result[0][3] = SrcA03 * SrcB00 + SrcA13 * SrcB01 + SrcA23 * SrcB02; Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12; Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12; Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11 + SrcA22 * SrcB12; Result[1][3] = SrcA03 * SrcB10 + SrcA13 * SrcB11 + SrcA23 * SrcB12; Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21 + SrcA20 * SrcB22; Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21 + SrcA21 * SrcB22; Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21 + SrcA22 * SrcB22; Result[2][3] = SrcA03 * SrcB20 + SrcA13 * SrcB21 + SrcA23 * SrcB22; Result[3][0] = SrcA00 * SrcB30 + SrcA10 * SrcB31 + SrcA20 * SrcB32; Result[3][1] = SrcA01 * SrcB30 + SrcA11 * SrcB31 + SrcA21 * SrcB32; Result[3][2] = SrcA02 * SrcB30 + SrcA12 * SrcB31 + SrcA22 * SrcB32; Result[3][3] = SrcA03 * SrcB30 + SrcA13 * SrcB31 + SrcA23 * SrcB32; return Result; } template GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<2, 3, T, Q> const& m2) { return mat<2, 4, T, Q>( m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2], m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2], m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2], m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2]); } template GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<3, 3, T, Q> const& m2) { return mat<3, 4, T, Q>( m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2], m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2], m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2], m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2], m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2], m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2], m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2], m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2], m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2], m1[0][3] * m2[2][0] + m1[1][3] * m2[2][1] + m1[2][3] * m2[2][2]); } template GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator/(mat<3, 4, T, Q> const& m, T scalar) { return mat<3, 4, T, Q>( m[0] / scalar, m[1] / scalar, m[2] / scalar); } template GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator/(T scalar, mat<3, 4, T, Q> const& m) { return mat<3, 4, T, Q>( scalar / m[0], scalar / m[1], scalar / m[2]); } // -- Boolean operators -- template GLM_FUNC_QUALIFIER bool operator==(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2) { return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]); } template GLM_FUNC_QUALIFIER bool operator!=(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2) { return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]); } } //namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/type_mat4x2.hpp000066400000000000000000000130541360521144700244530ustar00rootroot00000000000000/// @ref core /// @file glm/detail/type_mat4x2.hpp #pragma once #include "type_vec2.hpp" #include "type_vec4.hpp" #include #include namespace glm { template struct mat<4, 2, T, Q> { typedef vec<2, T, Q> col_type; typedef vec<4, T, Q> row_type; typedef mat<4, 2, T, Q> type; typedef mat<2, 4, T, Q> transpose_type; typedef T value_type; private: col_type value[4]; public: // -- Accesses -- typedef length_t length_type; GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 4; } GLM_FUNC_DECL col_type & operator[](length_type i); GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; // -- Constructors -- GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT; template GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<4, 2, T, P> const& m); GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar); GLM_FUNC_DECL GLM_CONSTEXPR mat( T x0, T y0, T x1, T y1, T x2, T y2, T x3, T y3); GLM_FUNC_DECL GLM_CONSTEXPR mat( col_type const& v0, col_type const& v1, col_type const& v2, col_type const& v3); // -- Conversions -- template< typename X0, typename Y0, typename X1, typename Y1, typename X2, typename Y2, typename X3, typename Y3> GLM_FUNC_DECL GLM_CONSTEXPR mat( X0 x0, Y0 y0, X1 x1, Y1 y1, X2 x2, Y2 y2, X3 x3, Y3 y3); template GLM_FUNC_DECL GLM_CONSTEXPR mat( vec<2, V1, Q> const& v1, vec<2, V2, Q> const& v2, vec<2, V3, Q> const& v3, vec<2, V4, Q> const& v4); // -- Matrix conversions -- template GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, U, P> const& m); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); // -- Unary arithmetic operators -- template GLM_FUNC_DECL mat<4, 2, T, Q> & operator=(mat<4, 2, U, Q> const& m); template GLM_FUNC_DECL mat<4, 2, T, Q> & operator+=(U s); template GLM_FUNC_DECL mat<4, 2, T, Q> & operator+=(mat<4, 2, U, Q> const& m); template GLM_FUNC_DECL mat<4, 2, T, Q> & operator-=(U s); template GLM_FUNC_DECL mat<4, 2, T, Q> & operator-=(mat<4, 2, U, Q> const& m); template GLM_FUNC_DECL mat<4, 2, T, Q> & operator*=(U s); template GLM_FUNC_DECL mat<4, 2, T, Q> & operator/=(U s); // -- Increment and decrement operators -- GLM_FUNC_DECL mat<4, 2, T, Q> & operator++ (); GLM_FUNC_DECL mat<4, 2, T, Q> & operator-- (); GLM_FUNC_DECL mat<4, 2, T, Q> operator++(int); GLM_FUNC_DECL mat<4, 2, T, Q> operator--(int); }; // -- Unary operators -- template GLM_FUNC_DECL mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m); template GLM_FUNC_DECL mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m); // -- Binary operators -- template GLM_FUNC_DECL mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2); template GLM_FUNC_DECL mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2); template GLM_FUNC_DECL mat<4, 2, T, Q> operator*(mat<4, 2, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<4, 2, T, Q> operator*(T scalar, mat<4, 2, T, Q> const& m); template GLM_FUNC_DECL typename mat<4, 2, T, Q>::col_type operator*(mat<4, 2, T, Q> const& m, typename mat<4, 2, T, Q>::row_type const& v); template GLM_FUNC_DECL typename mat<4, 2, T, Q>::row_type operator*(typename mat<4, 2, T, Q>::col_type const& v, mat<4, 2, T, Q> const& m); template GLM_FUNC_DECL mat<2, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<2, 4, T, Q> const& m2); template GLM_FUNC_DECL mat<3, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<3, 4, T, Q> const& m2); template GLM_FUNC_DECL mat<4, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<4, 4, T, Q> const& m2); template GLM_FUNC_DECL mat<4, 2, T, Q> operator/(mat<4, 2, T, Q> const& m, T scalar); template GLM_FUNC_DECL mat<4, 2, T, Q> operator/(T scalar, mat<4, 2, T, Q> const& m); // -- Boolean operators -- template GLM_FUNC_DECL bool operator==(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2); template GLM_FUNC_DECL bool operator!=(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2); }//namespace glm #ifndef GLM_EXTERNAL_TEMPLATE #include "type_mat4x2.inl" #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/type_mat4x2.inl000066400000000000000000000411361360521144700244500ustar00rootroot00000000000000namespace glm { // -- Constructors -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat() # if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST : value{col_type(1, 0), col_type(0, 1), col_type(0, 0), col_type(0, 0)} # endif { # if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION this->value[0] = col_type(1, 0); this->value[1] = col_type(0, 1); this->value[2] = col_type(0, 0); this->value[3] = col_type(0, 0); # endif } # endif template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<4, 2, T, P> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = m[0]; this->value[1] = m[1]; this->value[2] = m[2]; this->value[3] = m[3]; # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(T s) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(s, 0), col_type(0, s), col_type(0, 0), col_type(0, 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(s, 0); this->value[1] = col_type(0, s); this->value[2] = col_type(0, 0); this->value[3] = col_type(0, 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat ( T x0, T y0, T x1, T y1, T x2, T y2, T x3, T y3 ) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(x0, y0), col_type(x1, y1), col_type(x2, y2), col_type(x3, y3)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(x0, y0); this->value[1] = col_type(x1, y1); this->value[2] = col_type(x2, y2); this->value[3] = col_type(x3, y3); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2, col_type const& v3) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(v0), col_type(v1), col_type(v2), col_type(v3)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = v0; this->value[1] = v1; this->value[2] = v2; this->value[3] = v3; # endif } // -- Conversion constructors -- template template< typename X0, typename Y0, typename X1, typename Y1, typename X2, typename Y2, typename X3, typename Y3> GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat ( X0 x0, Y0 y0, X1 x1, Y1 y1, X2 x2, Y2 y2, X3 x3, Y3 y3 ) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(x0, y0), col_type(x1, y1), col_type(x2, y2), col_type(x3, y3)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(x0, y0); this->value[1] = col_type(x1, y1); this->value[2] = col_type(x2, y2); this->value[3] = col_type(x3, y3); # endif } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(vec<2, V0, Q> const& v0, vec<2, V1, Q> const& v1, vec<2, V2, Q> const& v2, vec<2, V3, Q> const& v3) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(v0), col_type(v1), col_type(v2), col_type(v3)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(v0); this->value[1] = col_type(v1); this->value[2] = col_type(v2); this->value[3] = col_type(v3); # endif } // -- Conversion -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<4, 2, U, P> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); this->value[3] = col_type(m[3]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<2, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(0), col_type(0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(0); this->value[3] = col_type(0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<3, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); this->value[3] = col_type(0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<4, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); this->value[3] = col_type(m[3]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<2, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(0), col_type(0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(0); this->value[3] = col_type(0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<3, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); this->value[3] = col_type(0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<2, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(0), col_type(0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(0); this->value[3] = col_type(0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<4, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); this->value[3] = col_type(m[3]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<3, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); this->value[3] = col_type(0); # endif } // -- Accesses -- template GLM_FUNC_QUALIFIER typename mat<4, 2, T, Q>::col_type & mat<4, 2, T, Q>::operator[](typename mat<4, 2, T, Q>::length_type i) { assert(i < this->length()); return this->value[i]; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<4, 2, T, Q>::col_type const& mat<4, 2, T, Q>::operator[](typename mat<4, 2, T, Q>::length_type i) const { assert(i < this->length()); return this->value[i]; } // -- Unary updatable operators -- template template GLM_FUNC_QUALIFIER mat<4, 2, T, Q>& mat<4, 2, T, Q>::operator=(mat<4, 2, U, Q> const& m) { this->value[0] = m[0]; this->value[1] = m[1]; this->value[2] = m[2]; this->value[3] = m[3]; return *this; } template template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator+=(U s) { this->value[0] += s; this->value[1] += s; this->value[2] += s; this->value[3] += s; return *this; } template template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator+=(mat<4, 2, U, Q> const& m) { this->value[0] += m[0]; this->value[1] += m[1]; this->value[2] += m[2]; this->value[3] += m[3]; return *this; } template template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator-=(U s) { this->value[0] -= s; this->value[1] -= s; this->value[2] -= s; this->value[3] -= s; return *this; } template template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator-=(mat<4, 2, U, Q> const& m) { this->value[0] -= m[0]; this->value[1] -= m[1]; this->value[2] -= m[2]; this->value[3] -= m[3]; return *this; } template template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator*=(U s) { this->value[0] *= s; this->value[1] *= s; this->value[2] *= s; this->value[3] *= s; return *this; } template template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator/=(U s) { this->value[0] /= s; this->value[1] /= s; this->value[2] /= s; this->value[3] /= s; return *this; } // -- Increment and decrement operators -- template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator++() { ++this->value[0]; ++this->value[1]; ++this->value[2]; ++this->value[3]; return *this; } template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator--() { --this->value[0]; --this->value[1]; --this->value[2]; --this->value[3]; return *this; } template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> mat<4, 2, T, Q>::operator++(int) { mat<4, 2, T, Q> Result(*this); ++*this; return Result; } template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> mat<4, 2, T, Q>::operator--(int) { mat<4, 2, T, Q> Result(*this); --*this; return Result; } // -- Unary arithmetic operators -- template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m) { return m; } template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m) { return mat<4, 2, T, Q>( -m[0], -m[1], -m[2], -m[3]); } // -- Binary arithmetic operators -- template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m, T scalar) { return mat<4, 2, T, Q>( m[0] + scalar, m[1] + scalar, m[2] + scalar, m[3] + scalar); } template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2) { return mat<4, 2, T, Q>( m1[0] + m2[0], m1[1] + m2[1], m1[2] + m2[2], m1[3] + m2[3]); } template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m, T scalar) { return mat<4, 2, T, Q>( m[0] - scalar, m[1] - scalar, m[2] - scalar, m[3] - scalar); } template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2) { return mat<4, 2, T, Q>( m1[0] - m2[0], m1[1] - m2[1], m1[2] - m2[2], m1[3] - m2[3]); } template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(mat<4, 2, T, Q> const& m, T scalar) { return mat<4, 2, T, Q>( m[0] * scalar, m[1] * scalar, m[2] * scalar, m[3] * scalar); } template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(T scalar, mat<4, 2, T, Q> const& m) { return mat<4, 2, T, Q>( m[0] * scalar, m[1] * scalar, m[2] * scalar, m[3] * scalar); } template GLM_FUNC_QUALIFIER typename mat<4, 2, T, Q>::col_type operator*(mat<4, 2, T, Q> const& m, typename mat<4, 2, T, Q>::row_type const& v) { return typename mat<4, 2, T, Q>::col_type( m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * v.w, m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * v.w); } template GLM_FUNC_QUALIFIER typename mat<4, 2, T, Q>::row_type operator*(typename mat<4, 2, T, Q>::col_type const& v, mat<4, 2, T, Q> const& m) { return typename mat<4, 2, T, Q>::row_type( v.x * m[0][0] + v.y * m[0][1], v.x * m[1][0] + v.y * m[1][1], v.x * m[2][0] + v.y * m[2][1], v.x * m[3][0] + v.y * m[3][1]); } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<2, 4, T, Q> const& m2) { T const SrcA00 = m1[0][0]; T const SrcA01 = m1[0][1]; T const SrcA10 = m1[1][0]; T const SrcA11 = m1[1][1]; T const SrcA20 = m1[2][0]; T const SrcA21 = m1[2][1]; T const SrcA30 = m1[3][0]; T const SrcA31 = m1[3][1]; T const SrcB00 = m2[0][0]; T const SrcB01 = m2[0][1]; T const SrcB02 = m2[0][2]; T const SrcB03 = m2[0][3]; T const SrcB10 = m2[1][0]; T const SrcB11 = m2[1][1]; T const SrcB12 = m2[1][2]; T const SrcB13 = m2[1][3]; mat<2, 2, T, Q> Result; Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02 + SrcA30 * SrcB03; Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02 + SrcA31 * SrcB03; Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12 + SrcA30 * SrcB13; Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12 + SrcA31 * SrcB13; return Result; } template GLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<3, 4, T, Q> const& m2) { return mat<3, 2, T, Q>( m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3], m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3]); } template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<4, 4, T, Q> const& m2) { return mat<4, 2, T, Q>( m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3], m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3], m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2] + m1[3][0] * m2[3][3], m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2] + m1[3][1] * m2[3][3]); } template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator/(mat<4, 2, T, Q> const& m, T scalar) { return mat<4, 2, T, Q>( m[0] / scalar, m[1] / scalar, m[2] / scalar, m[3] / scalar); } template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator/(T scalar, mat<4, 2, T, Q> const& m) { return mat<4, 2, T, Q>( scalar / m[0], scalar / m[1], scalar / m[2], scalar / m[3]); } // -- Boolean operators -- template GLM_FUNC_QUALIFIER bool operator==(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2) { return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]) && (m1[3] == m2[3]); } template GLM_FUNC_QUALIFIER bool operator!=(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2) { return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]) || (m1[3] != m2[3]); } } //namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/type_mat4x3.hpp000066400000000000000000000135361360521144700244610ustar00rootroot00000000000000/// @ref core /// @file glm/detail/type_mat4x3.hpp #pragma once #include "type_vec3.hpp" #include "type_vec4.hpp" #include #include namespace glm { template struct mat<4, 3, T, Q> { typedef vec<3, T, Q> col_type; typedef vec<4, T, Q> row_type; typedef mat<4, 3, T, Q> type; typedef mat<3, 4, T, Q> transpose_type; typedef T value_type; private: col_type value[4]; public: // -- Accesses -- typedef length_t length_type; GLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 4; } GLM_FUNC_DECL col_type & operator[](length_type i); GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; // -- Constructors -- GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT; template GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<4, 3, T, P> const& m); GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T const& x); GLM_FUNC_DECL GLM_CONSTEXPR mat( T const& x0, T const& y0, T const& z0, T const& x1, T const& y1, T const& z1, T const& x2, T const& y2, T const& z2, T const& x3, T const& y3, T const& z3); GLM_FUNC_DECL GLM_CONSTEXPR mat( col_type const& v0, col_type const& v1, col_type const& v2, col_type const& v3); // -- Conversions -- template< typename X1, typename Y1, typename Z1, typename X2, typename Y2, typename Z2, typename X3, typename Y3, typename Z3, typename X4, typename Y4, typename Z4> GLM_FUNC_DECL GLM_CONSTEXPR mat( X1 const& x1, Y1 const& y1, Z1 const& z1, X2 const& x2, Y2 const& y2, Z2 const& z2, X3 const& x3, Y3 const& y3, Z3 const& z3, X4 const& x4, Y4 const& y4, Z4 const& z4); template GLM_FUNC_DECL GLM_CONSTEXPR mat( vec<3, V1, Q> const& v1, vec<3, V2, Q> const& v2, vec<3, V3, Q> const& v3, vec<3, V4, Q> const& v4); // -- Matrix conversions -- template GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, U, P> const& m); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); // -- Unary arithmetic operators -- template GLM_FUNC_DECL mat<4, 3, T, Q> & operator=(mat<4, 3, U, Q> const& m); template GLM_FUNC_DECL mat<4, 3, T, Q> & operator+=(U s); template GLM_FUNC_DECL mat<4, 3, T, Q> & operator+=(mat<4, 3, U, Q> const& m); template GLM_FUNC_DECL mat<4, 3, T, Q> & operator-=(U s); template GLM_FUNC_DECL mat<4, 3, T, Q> & operator-=(mat<4, 3, U, Q> const& m); template GLM_FUNC_DECL mat<4, 3, T, Q> & operator*=(U s); template GLM_FUNC_DECL mat<4, 3, T, Q> & operator/=(U s); // -- Increment and decrement operators -- GLM_FUNC_DECL mat<4, 3, T, Q>& operator++(); GLM_FUNC_DECL mat<4, 3, T, Q>& operator--(); GLM_FUNC_DECL mat<4, 3, T, Q> operator++(int); GLM_FUNC_DECL mat<4, 3, T, Q> operator--(int); }; // -- Unary operators -- template GLM_FUNC_DECL mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m); template GLM_FUNC_DECL mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m); // -- Binary operators -- template GLM_FUNC_DECL mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m, T const& s); template GLM_FUNC_DECL mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2); template GLM_FUNC_DECL mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m, T const& s); template GLM_FUNC_DECL mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2); template GLM_FUNC_DECL mat<4, 3, T, Q> operator*(mat<4, 3, T, Q> const& m, T const& s); template GLM_FUNC_DECL mat<4, 3, T, Q> operator*(T const& s, mat<4, 3, T, Q> const& m); template GLM_FUNC_DECL typename mat<4, 3, T, Q>::col_type operator*(mat<4, 3, T, Q> const& m, typename mat<4, 3, T, Q>::row_type const& v); template GLM_FUNC_DECL typename mat<4, 3, T, Q>::row_type operator*(typename mat<4, 3, T, Q>::col_type const& v, mat<4, 3, T, Q> const& m); template GLM_FUNC_DECL mat<2, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<2, 4, T, Q> const& m2); template GLM_FUNC_DECL mat<3, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<3, 4, T, Q> const& m2); template GLM_FUNC_DECL mat<4, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<4, 4, T, Q> const& m2); template GLM_FUNC_DECL mat<4, 3, T, Q> operator/(mat<4, 3, T, Q> const& m, T const& s); template GLM_FUNC_DECL mat<4, 3, T, Q> operator/(T const& s, mat<4, 3, T, Q> const& m); // -- Boolean operators -- template GLM_FUNC_DECL bool operator==(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2); template GLM_FUNC_DECL bool operator!=(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2); }//namespace glm #ifndef GLM_EXTERNAL_TEMPLATE #include "type_mat4x3.inl" #endif //GLM_EXTERNAL_TEMPLATE connectome-workbench-1.4.2/src/GLMath/glm/detail/type_mat4x3.inl000066400000000000000000000442071360521144700244530ustar00rootroot00000000000000namespace glm { // -- Constructors -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat() # if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST : value{col_type(1, 0, 0), col_type(0, 1, 0), col_type(0, 0, 1), col_type(0, 0, 0)} # endif { # if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION this->value[0] = col_type(1, 0, 0); this->value[1] = col_type(0, 1, 0); this->value[2] = col_type(0, 0, 1); this->value[3] = col_type(0, 0, 0); # endif } # endif template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<4, 3, T, P> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = m[0]; this->value[1] = m[1]; this->value[2] = m[2]; this->value[3] = m[3]; # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(T const& s) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(s, 0, 0), col_type(0, s, 0), col_type(0, 0, s), col_type(0, 0, 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(s, 0, 0); this->value[1] = col_type(0, s, 0); this->value[2] = col_type(0, 0, s); this->value[3] = col_type(0, 0, 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat ( T const& x0, T const& y0, T const& z0, T const& x1, T const& y1, T const& z1, T const& x2, T const& y2, T const& z2, T const& x3, T const& y3, T const& z3 ) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(x0, y0, z0), col_type(x1, y1, z1), col_type(x2, y2, z2), col_type(x3, y3, z3)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(x0, y0, z0); this->value[1] = col_type(x1, y1, z1); this->value[2] = col_type(x2, y2, z2); this->value[3] = col_type(x3, y3, z3); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2, col_type const& v3) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(v0), col_type(v1), col_type(v2), col_type(v3)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = v0; this->value[1] = v1; this->value[2] = v2; this->value[3] = v3; # endif } // -- Conversion constructors -- template template< typename X0, typename Y0, typename Z0, typename X1, typename Y1, typename Z1, typename X2, typename Y2, typename Z2, typename X3, typename Y3, typename Z3> GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat ( X0 const& x0, Y0 const& y0, Z0 const& z0, X1 const& x1, Y1 const& y1, Z1 const& z1, X2 const& x2, Y2 const& y2, Z2 const& z2, X3 const& x3, Y3 const& y3, Z3 const& z3 ) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(x0, y0, z0), col_type(x1, y1, z1), col_type(x2, y2, z2), col_type(x3, y3, z3)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(x0, y0, z0); this->value[1] = col_type(x1, y1, z1); this->value[2] = col_type(x2, y2, z2); this->value[3] = col_type(x3, y3, z3); # endif } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(vec<3, V1, Q> const& v1, vec<3, V2, Q> const& v2, vec<3, V3, Q> const& v3, vec<3, V4, Q> const& v4) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(v1), col_type(v2), col_type(v3), col_type(v4)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(v1); this->value[1] = col_type(v2); this->value[2] = col_type(v3); this->value[3] = col_type(v4); # endif } // -- Matrix conversions -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<4, 3, U, P> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); this->value[3] = col_type(m[3]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<2, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0), col_type(m[1], 0), col_type(0, 0, 1), col_type(0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0); this->value[1] = col_type(m[1], 0); this->value[2] = col_type(0, 0, 1); this->value[3] = col_type(0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<3, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); this->value[3] = col_type(0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<4, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); this->value[3] = col_type(m[3]); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<2, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1), col_type(0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(0, 0, 1); this->value[3] = col_type(0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<3, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 1), col_type(0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0); this->value[1] = col_type(m[1], 0); this->value[2] = col_type(m[2], 1); this->value[3] = col_type(0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<2, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1), col_type(0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(0, 0, 1); this->value[3] = col_type(0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<4, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 1), col_type(m[3], 0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0); this->value[1] = col_type(m[1], 0); this->value[2] = col_type(m[2], 1); this->value[3] = col_type(m[3], 0); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<3, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); this->value[3] = col_type(0); # endif } // -- Accesses -- template GLM_FUNC_QUALIFIER typename mat<4, 3, T, Q>::col_type & mat<4, 3, T, Q>::operator[](typename mat<4, 3, T, Q>::length_type i) { assert(i < this->length()); return this->value[i]; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<4, 3, T, Q>::col_type const& mat<4, 3, T, Q>::operator[](typename mat<4, 3, T, Q>::length_type i) const { assert(i < this->length()); return this->value[i]; } // -- Unary updatable operators -- template template GLM_FUNC_QUALIFIER mat<4, 3, T, Q>& mat<4, 3, T, Q>::operator=(mat<4, 3, U, Q> const& m) { this->value[0] = m[0]; this->value[1] = m[1]; this->value[2] = m[2]; this->value[3] = m[3]; return *this; } template template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator+=(U s) { this->value[0] += s; this->value[1] += s; this->value[2] += s; this->value[3] += s; return *this; } template template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator+=(mat<4, 3, U, Q> const& m) { this->value[0] += m[0]; this->value[1] += m[1]; this->value[2] += m[2]; this->value[3] += m[3]; return *this; } template template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator-=(U s) { this->value[0] -= s; this->value[1] -= s; this->value[2] -= s; this->value[3] -= s; return *this; } template template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator-=(mat<4, 3, U, Q> const& m) { this->value[0] -= m[0]; this->value[1] -= m[1]; this->value[2] -= m[2]; this->value[3] -= m[3]; return *this; } template template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator*=(U s) { this->value[0] *= s; this->value[1] *= s; this->value[2] *= s; this->value[3] *= s; return *this; } template template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator/=(U s) { this->value[0] /= s; this->value[1] /= s; this->value[2] /= s; this->value[3] /= s; return *this; } // -- Increment and decrement operators -- template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator++() { ++this->value[0]; ++this->value[1]; ++this->value[2]; ++this->value[3]; return *this; } template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator--() { --this->value[0]; --this->value[1]; --this->value[2]; --this->value[3]; return *this; } template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> mat<4, 3, T, Q>::operator++(int) { mat<4, 3, T, Q> Result(*this); ++*this; return Result; } template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> mat<4, 3, T, Q>::operator--(int) { mat<4, 3, T, Q> Result(*this); --*this; return Result; } // -- Unary arithmetic operators -- template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m) { return m; } template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m) { return mat<4, 3, T, Q>( -m[0], -m[1], -m[2], -m[3]); } // -- Binary arithmetic operators -- template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m, T const& s) { return mat<4, 3, T, Q>( m[0] + s, m[1] + s, m[2] + s, m[3] + s); } template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2) { return mat<4, 3, T, Q>( m1[0] + m2[0], m1[1] + m2[1], m1[2] + m2[2], m1[3] + m2[3]); } template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m, T const& s) { return mat<4, 3, T, Q>( m[0] - s, m[1] - s, m[2] - s, m[3] - s); } template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2) { return mat<4, 3, T, Q>( m1[0] - m2[0], m1[1] - m2[1], m1[2] - m2[2], m1[3] - m2[3]); } template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(mat<4, 3, T, Q> const& m, T const& s) { return mat<4, 3, T, Q>( m[0] * s, m[1] * s, m[2] * s, m[3] * s); } template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(T const& s, mat<4, 3, T, Q> const& m) { return mat<4, 3, T, Q>( m[0] * s, m[1] * s, m[2] * s, m[3] * s); } template GLM_FUNC_QUALIFIER typename mat<4, 3, T, Q>::col_type operator* ( mat<4, 3, T, Q> const& m, typename mat<4, 3, T, Q>::row_type const& v) { return typename mat<4, 3, T, Q>::col_type( m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * v.w, m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * v.w, m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2] * v.w); } template GLM_FUNC_QUALIFIER typename mat<4, 3, T, Q>::row_type operator* ( typename mat<4, 3, T, Q>::col_type const& v, mat<4, 3, T, Q> const& m) { return typename mat<4, 3, T, Q>::row_type( v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2], v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2], v.x * m[2][0] + v.y * m[2][1] + v.z * m[2][2], v.x * m[3][0] + v.y * m[3][1] + v.z * m[3][2]); } template GLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<2, 4, T, Q> const& m2) { return mat<2, 3, T, Q>( m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3], m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3]); } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<3, 4, T, Q> const& m2) { T const SrcA00 = m1[0][0]; T const SrcA01 = m1[0][1]; T const SrcA02 = m1[0][2]; T const SrcA10 = m1[1][0]; T const SrcA11 = m1[1][1]; T const SrcA12 = m1[1][2]; T const SrcA20 = m1[2][0]; T const SrcA21 = m1[2][1]; T const SrcA22 = m1[2][2]; T const SrcA30 = m1[3][0]; T const SrcA31 = m1[3][1]; T const SrcA32 = m1[3][2]; T const SrcB00 = m2[0][0]; T const SrcB01 = m2[0][1]; T const SrcB02 = m2[0][2]; T const SrcB03 = m2[0][3]; T const SrcB10 = m2[1][0]; T const SrcB11 = m2[1][1]; T const SrcB12 = m2[1][2]; T const SrcB13 = m2[1][3]; T const SrcB20 = m2[2][0]; T const SrcB21 = m2[2][1]; T const SrcB22 = m2[2][2]; T const SrcB23 = m2[2][3]; mat<3, 3, T, Q> Result; Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02 + SrcA30 * SrcB03; Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02 + SrcA31 * SrcB03; Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01 + SrcA22 * SrcB02 + SrcA32 * SrcB03; Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12 + SrcA30 * SrcB13; Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12 + SrcA31 * SrcB13; Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11 + SrcA22 * SrcB12 + SrcA32 * SrcB13; Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21 + SrcA20 * SrcB22 + SrcA30 * SrcB23; Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21 + SrcA21 * SrcB22 + SrcA31 * SrcB23; Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21 + SrcA22 * SrcB22 + SrcA32 * SrcB23; return Result; } template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<4, 4, T, Q> const& m2) { return mat<4, 3, T, Q>( m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3], m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3], m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3], m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3], m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2] + m1[3][2] * m2[2][3], m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2] + m1[3][0] * m2[3][3], m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2] + m1[3][1] * m2[3][3], m1[0][2] * m2[3][0] + m1[1][2] * m2[3][1] + m1[2][2] * m2[3][2] + m1[3][2] * m2[3][3]); } template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator/(mat<4, 3, T, Q> const& m, T const& s) { return mat<4, 3, T, Q>( m[0] / s, m[1] / s, m[2] / s, m[3] / s); } template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator/(T const& s, mat<4, 3, T, Q> const& m) { return mat<4, 3, T, Q>( s / m[0], s / m[1], s / m[2], s / m[3]); } // -- Boolean operators -- template GLM_FUNC_QUALIFIER bool operator==(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2) { return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]) && (m1[3] == m2[3]); } template GLM_FUNC_QUALIFIER bool operator!=(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2) { return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]) || (m1[3] != m2[3]); } } //namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/type_mat4x4.hpp000066400000000000000000000155571360521144700244670ustar00rootroot00000000000000/// @ref core /// @file glm/detail/type_mat4x4.hpp #pragma once #include "type_vec4.hpp" #include #include namespace glm { template struct mat<4, 4, T, Q> { typedef vec<4, T, Q> col_type; typedef vec<4, T, Q> row_type; typedef mat<4, 4, T, Q> type; typedef mat<4, 4, T, Q> transpose_type; typedef T value_type; private: col_type value[4]; public: // -- Accesses -- typedef length_t length_type; GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 4;} GLM_FUNC_DECL col_type & operator[](length_type i); GLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const; // -- Constructors -- GLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT; template GLM_FUNC_DECL GLM_CONSTEXPR mat(mat<4, 4, T, P> const& m); GLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T const& x); GLM_FUNC_DECL GLM_CONSTEXPR mat( T const& x0, T const& y0, T const& z0, T const& w0, T const& x1, T const& y1, T const& z1, T const& w1, T const& x2, T const& y2, T const& z2, T const& w2, T const& x3, T const& y3, T const& z3, T const& w3); GLM_FUNC_DECL GLM_CONSTEXPR mat( col_type const& v0, col_type const& v1, col_type const& v2, col_type const& v3); // -- Conversions -- template< typename X1, typename Y1, typename Z1, typename W1, typename X2, typename Y2, typename Z2, typename W2, typename X3, typename Y3, typename Z3, typename W3, typename X4, typename Y4, typename Z4, typename W4> GLM_FUNC_DECL GLM_CONSTEXPR mat( X1 const& x1, Y1 const& y1, Z1 const& z1, W1 const& w1, X2 const& x2, Y2 const& y2, Z2 const& z2, W2 const& w2, X3 const& x3, Y3 const& y3, Z3 const& z3, W3 const& w3, X4 const& x4, Y4 const& y4, Z4 const& z4, W4 const& w4); template GLM_FUNC_DECL GLM_CONSTEXPR mat( vec<4, V1, Q> const& v1, vec<4, V2, Q> const& v2, vec<4, V3, Q> const& v3, vec<4, V4, Q> const& v4); // -- Matrix conversions -- template GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, U, P> const& m); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x); // -- Unary arithmetic operators -- template GLM_FUNC_DECL mat<4, 4, T, Q> & operator=(mat<4, 4, U, Q> const& m); template GLM_FUNC_DECL mat<4, 4, T, Q> & operator+=(U s); template GLM_FUNC_DECL mat<4, 4, T, Q> & operator+=(mat<4, 4, U, Q> const& m); template GLM_FUNC_DECL mat<4, 4, T, Q> & operator-=(U s); template GLM_FUNC_DECL mat<4, 4, T, Q> & operator-=(mat<4, 4, U, Q> const& m); template GLM_FUNC_DECL mat<4, 4, T, Q> & operator*=(U s); template GLM_FUNC_DECL mat<4, 4, T, Q> & operator*=(mat<4, 4, U, Q> const& m); template GLM_FUNC_DECL mat<4, 4, T, Q> & operator/=(U s); template GLM_FUNC_DECL mat<4, 4, T, Q> & operator/=(mat<4, 4, U, Q> const& m); // -- Increment and decrement operators -- GLM_FUNC_DECL mat<4, 4, T, Q> & operator++(); GLM_FUNC_DECL mat<4, 4, T, Q> & operator--(); GLM_FUNC_DECL mat<4, 4, T, Q> operator++(int); GLM_FUNC_DECL mat<4, 4, T, Q> operator--(int); }; // -- Unary operators -- template GLM_FUNC_DECL mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m); template GLM_FUNC_DECL mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m); // -- Binary operators -- template GLM_FUNC_DECL mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m, T const& s); template GLM_FUNC_DECL mat<4, 4, T, Q> operator+(T const& s, mat<4, 4, T, Q> const& m); template GLM_FUNC_DECL mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); template GLM_FUNC_DECL mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m, T const& s); template GLM_FUNC_DECL mat<4, 4, T, Q> operator-(T const& s, mat<4, 4, T, Q> const& m); template GLM_FUNC_DECL mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); template GLM_FUNC_DECL mat<4, 4, T, Q> operator*(mat<4, 4, T, Q> const& m, T const& s); template GLM_FUNC_DECL mat<4, 4, T, Q> operator*(T const& s, mat<4, 4, T, Q> const& m); template GLM_FUNC_DECL typename mat<4, 4, T, Q>::col_type operator*(mat<4, 4, T, Q> const& m, typename mat<4, 4, T, Q>::row_type const& v); template GLM_FUNC_DECL typename mat<4, 4, T, Q>::row_type operator*(typename mat<4, 4, T, Q>::col_type const& v, mat<4, 4, T, Q> const& m); template GLM_FUNC_DECL mat<2, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2); template GLM_FUNC_DECL mat<3, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2); template GLM_FUNC_DECL mat<4, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); template GLM_FUNC_DECL mat<4, 4, T, Q> operator/(mat<4, 4, T, Q> const& m, T const& s); template GLM_FUNC_DECL mat<4, 4, T, Q> operator/(T const& s, mat<4, 4, T, Q> const& m); template GLM_FUNC_DECL typename mat<4, 4, T, Q>::col_type operator/(mat<4, 4, T, Q> const& m, typename mat<4, 4, T, Q>::row_type const& v); template GLM_FUNC_DECL typename mat<4, 4, T, Q>::row_type operator/(typename mat<4, 4, T, Q>::col_type const& v, mat<4, 4, T, Q> const& m); template GLM_FUNC_DECL mat<4, 4, T, Q> operator/(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); // -- Boolean operators -- template GLM_FUNC_DECL bool operator==(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); template GLM_FUNC_DECL bool operator!=(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2); }//namespace glm #ifndef GLM_EXTERNAL_TEMPLATE #include "type_mat4x4.inl" #endif//GLM_EXTERNAL_TEMPLATE connectome-workbench-1.4.2/src/GLMath/glm/detail/type_mat4x4.inl000066400000000000000000000627001360521144700244520ustar00rootroot00000000000000#include "../matrix.hpp" namespace glm { // -- Constructors -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat() # if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST : value{col_type(1, 0, 0, 0), col_type(0, 1, 0, 0), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)} # endif { # if GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION this->value[0] = col_type(1, 0, 0, 0); this->value[1] = col_type(0, 1, 0, 0); this->value[2] = col_type(0, 0, 1, 0); this->value[3] = col_type(0, 0, 0, 1); # endif } # endif template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<4, 4, T, P> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = m[0]; this->value[1] = m[1]; this->value[2] = m[2]; this->value[3] = m[3]; # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(T const& s) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(s, 0, 0, 0), col_type(0, s, 0, 0), col_type(0, 0, s, 0), col_type(0, 0, 0, s)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(s, 0, 0, 0); this->value[1] = col_type(0, s, 0, 0); this->value[2] = col_type(0, 0, s, 0); this->value[3] = col_type(0, 0, 0, s); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat ( T const& x0, T const& y0, T const& z0, T const& w0, T const& x1, T const& y1, T const& z1, T const& w1, T const& x2, T const& y2, T const& z2, T const& w2, T const& x3, T const& y3, T const& z3, T const& w3 ) # if GLM_HAS_INITIALIZER_LISTS : value{ col_type(x0, y0, z0, w0), col_type(x1, y1, z1, w1), col_type(x2, y2, z2, w2), col_type(x3, y3, z3, w3)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(x0, y0, z0, w0); this->value[1] = col_type(x1, y1, z1, w1); this->value[2] = col_type(x2, y2, z2, w2); this->value[3] = col_type(x3, y3, z3, w3); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2, col_type const& v3) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(v0), col_type(v1), col_type(v2), col_type(v3)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = v0; this->value[1] = v1; this->value[2] = v2; this->value[3] = v3; # endif } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<4, 4, U, P> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0]); this->value[1] = col_type(m[1]); this->value[2] = col_type(m[2]); this->value[3] = col_type(m[3]); # endif } // -- Conversions -- template template< typename X1, typename Y1, typename Z1, typename W1, typename X2, typename Y2, typename Z2, typename W2, typename X3, typename Y3, typename Z3, typename W3, typename X4, typename Y4, typename Z4, typename W4> GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat ( X1 const& x1, Y1 const& y1, Z1 const& z1, W1 const& w1, X2 const& x2, Y2 const& y2, Z2 const& z2, W2 const& w2, X3 const& x3, Y3 const& y3, Z3 const& z3, W3 const& w3, X4 const& x4, Y4 const& y4, Z4 const& z4, W4 const& w4 ) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(x1, y1, z1, w1), col_type(x2, y2, z2, w2), col_type(x3, y3, z3, w3), col_type(x4, y4, z4, w4)} # endif { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 1st parameter type invalid."); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 2nd parameter type invalid."); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 3rd parameter type invalid."); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 4th parameter type invalid."); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 5th parameter type invalid."); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 6th parameter type invalid."); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 7th parameter type invalid."); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 8th parameter type invalid."); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 9th parameter type invalid."); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 10th parameter type invalid."); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 11th parameter type invalid."); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 12th parameter type invalid."); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 13th parameter type invalid."); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 14th parameter type invalid."); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 15th parameter type invalid."); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 16th parameter type invalid."); # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(x1, y1, z1, w1); this->value[1] = col_type(x2, y2, z2, w2); this->value[2] = col_type(x3, y3, z3, w3); this->value[3] = col_type(x4, y4, z4, w4); # endif } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(vec<4, V1, Q> const& v1, vec<4, V2, Q> const& v2, vec<4, V3, Q> const& v3, vec<4, V4, Q> const& v4) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(v1), col_type(v2), col_type(v3), col_type(v4)} # endif { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 1st parameter type invalid."); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 2nd parameter type invalid."); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 3rd parameter type invalid."); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559 || std::numeric_limits::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 4th parameter type invalid."); # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(v1); this->value[1] = col_type(v2); this->value[2] = col_type(v3); this->value[3] = col_type(v4); # endif } // -- Matrix conversions -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<2, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0, 0); this->value[1] = col_type(m[1], 0, 0); this->value[2] = col_type(0, 0, 1, 0); this->value[3] = col_type(0, 0, 0, 1); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<3, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 0), col_type(0, 0, 0, 1)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0); this->value[1] = col_type(m[1], 0); this->value[2] = col_type(m[2], 0); this->value[3] = col_type(0, 0, 0, 1); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<2, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0), col_type(m[1], 0), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0); this->value[1] = col_type(m[1], 0); this->value[2] = col_type(0, 0, 1, 0); this->value[3] = col_type(0, 0, 0, 1); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<3, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(m[2], 1, 0), col_type(0, 0, 0, 1)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0, 0); this->value[1] = col_type(m[1], 0, 0); this->value[2] = col_type(m[2], 1, 0); this->value[3] = col_type(0, 0, 0, 1); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<2, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = m[0]; this->value[1] = m[1]; this->value[2] = col_type(0, 0, 1, 0); this->value[3] = col_type(0, 0, 0, 1); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<4, 2, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0, 0); this->value[1] = col_type(m[1], 0, 0); this->value[2] = col_type(0, 0, 1, 0); this->value[3] = col_type(0, 0, 0, 1); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<3, 4, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0, 0, 0, 1)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = m[0]; this->value[1] = m[1]; this->value[2] = m[2]; this->value[3] = col_type(0, 0, 0, 1); # endif } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<4, 3, T, Q> const& m) # if GLM_HAS_INITIALIZER_LISTS : value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 0), col_type(m[3], 1)} # endif { # if !GLM_HAS_INITIALIZER_LISTS this->value[0] = col_type(m[0], 0); this->value[1] = col_type(m[1], 0); this->value[2] = col_type(m[2], 0); this->value[3] = col_type(m[3], 1); # endif } // -- Accesses -- template GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::col_type & mat<4, 4, T, Q>::operator[](typename mat<4, 4, T, Q>::length_type i) { assert(i < this->length()); return this->value[i]; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<4, 4, T, Q>::col_type const& mat<4, 4, T, Q>::operator[](typename mat<4, 4, T, Q>::length_type i) const { assert(i < this->length()); return this->value[i]; } // -- Unary arithmetic operators -- template template GLM_FUNC_QUALIFIER mat<4, 4, T, Q>& mat<4, 4, T, Q>::operator=(mat<4, 4, U, Q> const& m) { //memcpy could be faster //memcpy(&this->value, &m.value, 16 * sizeof(valType)); this->value[0] = m[0]; this->value[1] = m[1]; this->value[2] = m[2]; this->value[3] = m[3]; return *this; } template template GLM_FUNC_QUALIFIER mat<4, 4, T, Q>& mat<4, 4, T, Q>::operator+=(U s) { this->value[0] += s; this->value[1] += s; this->value[2] += s; this->value[3] += s; return *this; } template template GLM_FUNC_QUALIFIER mat<4, 4, T, Q>& mat<4, 4, T, Q>::operator+=(mat<4, 4, U, Q> const& m) { this->value[0] += m[0]; this->value[1] += m[1]; this->value[2] += m[2]; this->value[3] += m[3]; return *this; } template template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator-=(U s) { this->value[0] -= s; this->value[1] -= s; this->value[2] -= s; this->value[3] -= s; return *this; } template template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator-=(mat<4, 4, U, Q> const& m) { this->value[0] -= m[0]; this->value[1] -= m[1]; this->value[2] -= m[2]; this->value[3] -= m[3]; return *this; } template template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator*=(U s) { this->value[0] *= s; this->value[1] *= s; this->value[2] *= s; this->value[3] *= s; return *this; } template template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator*=(mat<4, 4, U, Q> const& m) { return (*this = *this * m); } template template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator/=(U s) { this->value[0] /= s; this->value[1] /= s; this->value[2] /= s; this->value[3] /= s; return *this; } template template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator/=(mat<4, 4, U, Q> const& m) { return *this *= inverse(m); } // -- Increment and decrement operators -- template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator++() { ++this->value[0]; ++this->value[1]; ++this->value[2]; ++this->value[3]; return *this; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator--() { --this->value[0]; --this->value[1]; --this->value[2]; --this->value[3]; return *this; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> mat<4, 4, T, Q>::operator++(int) { mat<4, 4, T, Q> Result(*this); ++*this; return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> mat<4, 4, T, Q>::operator--(int) { mat<4, 4, T, Q> Result(*this); --*this; return Result; } // -- Unary constant operators -- template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m) { return m; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m) { return mat<4, 4, T, Q>( -m[0], -m[1], -m[2], -m[3]); } // -- Binary arithmetic operators -- template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m, T const& s) { return mat<4, 4, T, Q>( m[0] + s, m[1] + s, m[2] + s, m[3] + s); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator+(T const& s, mat<4, 4, T, Q> const& m) { return mat<4, 4, T, Q>( m[0] + s, m[1] + s, m[2] + s, m[3] + s); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) { return mat<4, 4, T, Q>( m1[0] + m2[0], m1[1] + m2[1], m1[2] + m2[2], m1[3] + m2[3]); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m, T const& s) { return mat<4, 4, T, Q>( m[0] - s, m[1] - s, m[2] - s, m[3] - s); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator-(T const& s, mat<4, 4, T, Q> const& m) { return mat<4, 4, T, Q>( s - m[0], s - m[1], s - m[2], s - m[3]); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) { return mat<4, 4, T, Q>( m1[0] - m2[0], m1[1] - m2[1], m1[2] - m2[2], m1[3] - m2[3]); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(mat<4, 4, T, Q> const& m, T const & s) { return mat<4, 4, T, Q>( m[0] * s, m[1] * s, m[2] * s, m[3] * s); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(T const& s, mat<4, 4, T, Q> const& m) { return mat<4, 4, T, Q>( m[0] * s, m[1] * s, m[2] * s, m[3] * s); } template GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::col_type operator* ( mat<4, 4, T, Q> const& m, typename mat<4, 4, T, Q>::row_type const& v ) { /* __m128 v0 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(0, 0, 0, 0)); __m128 v1 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(1, 1, 1, 1)); __m128 v2 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(2, 2, 2, 2)); __m128 v3 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(3, 3, 3, 3)); __m128 m0 = _mm_mul_ps(m[0].data, v0); __m128 m1 = _mm_mul_ps(m[1].data, v1); __m128 a0 = _mm_add_ps(m0, m1); __m128 m2 = _mm_mul_ps(m[2].data, v2); __m128 m3 = _mm_mul_ps(m[3].data, v3); __m128 a1 = _mm_add_ps(m2, m3); __m128 a2 = _mm_add_ps(a0, a1); return typename mat<4, 4, T, Q>::col_type(a2); */ typename mat<4, 4, T, Q>::col_type const Mov0(v[0]); typename mat<4, 4, T, Q>::col_type const Mov1(v[1]); typename mat<4, 4, T, Q>::col_type const Mul0 = m[0] * Mov0; typename mat<4, 4, T, Q>::col_type const Mul1 = m[1] * Mov1; typename mat<4, 4, T, Q>::col_type const Add0 = Mul0 + Mul1; typename mat<4, 4, T, Q>::col_type const Mov2(v[2]); typename mat<4, 4, T, Q>::col_type const Mov3(v[3]); typename mat<4, 4, T, Q>::col_type const Mul2 = m[2] * Mov2; typename mat<4, 4, T, Q>::col_type const Mul3 = m[3] * Mov3; typename mat<4, 4, T, Q>::col_type const Add1 = Mul2 + Mul3; typename mat<4, 4, T, Q>::col_type const Add2 = Add0 + Add1; return Add2; /* return typename mat<4, 4, T, Q>::col_type( m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2] + m[3][0] * v[3], m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2] + m[3][1] * v[3], m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2] * v[3], m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3] * v[3]); */ } template GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::row_type operator* ( typename mat<4, 4, T, Q>::col_type const& v, mat<4, 4, T, Q> const& m ) { return typename mat<4, 4, T, Q>::row_type( m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2] + m[0][3] * v[3], m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2] + m[1][3] * v[3], m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2] + m[2][3] * v[3], m[3][0] * v[0] + m[3][1] * v[1] + m[3][2] * v[2] + m[3][3] * v[3]); } template GLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2) { return mat<2, 4, T, Q>( m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3], m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2] + m1[3][3] * m2[0][3], m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3], m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2] + m1[3][3] * m2[1][3]); } template GLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2) { return mat<3, 4, T, Q>( m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3], m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3], m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3], m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2] + m1[3][3] * m2[0][3], m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3], m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3], m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3], m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2] + m1[3][3] * m2[1][3], m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3], m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3], m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2] + m1[3][2] * m2[2][3], m1[0][3] * m2[2][0] + m1[1][3] * m2[2][1] + m1[2][3] * m2[2][2] + m1[3][3] * m2[2][3]); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) { typename mat<4, 4, T, Q>::col_type const SrcA0 = m1[0]; typename mat<4, 4, T, Q>::col_type const SrcA1 = m1[1]; typename mat<4, 4, T, Q>::col_type const SrcA2 = m1[2]; typename mat<4, 4, T, Q>::col_type const SrcA3 = m1[3]; typename mat<4, 4, T, Q>::col_type const SrcB0 = m2[0]; typename mat<4, 4, T, Q>::col_type const SrcB1 = m2[1]; typename mat<4, 4, T, Q>::col_type const SrcB2 = m2[2]; typename mat<4, 4, T, Q>::col_type const SrcB3 = m2[3]; mat<4, 4, T, Q> Result; Result[0] = SrcA0 * SrcB0[0] + SrcA1 * SrcB0[1] + SrcA2 * SrcB0[2] + SrcA3 * SrcB0[3]; Result[1] = SrcA0 * SrcB1[0] + SrcA1 * SrcB1[1] + SrcA2 * SrcB1[2] + SrcA3 * SrcB1[3]; Result[2] = SrcA0 * SrcB2[0] + SrcA1 * SrcB2[1] + SrcA2 * SrcB2[2] + SrcA3 * SrcB2[3]; Result[3] = SrcA0 * SrcB3[0] + SrcA1 * SrcB3[1] + SrcA2 * SrcB3[2] + SrcA3 * SrcB3[3]; return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator/(mat<4, 4, T, Q> const& m, T const& s) { return mat<4, 4, T, Q>( m[0] / s, m[1] / s, m[2] / s, m[3] / s); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator/(T const& s, mat<4, 4, T, Q> const& m) { return mat<4, 4, T, Q>( s / m[0], s / m[1], s / m[2], s / m[3]); } template GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::col_type operator/(mat<4, 4, T, Q> const& m, typename mat<4, 4, T, Q>::row_type const& v) { return inverse(m) * v; } template GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::row_type operator/(typename mat<4, 4, T, Q>::col_type const& v, mat<4, 4, T, Q> const& m) { return v * inverse(m); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator/(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) { mat<4, 4, T, Q> m1_copy(m1); return m1_copy /= m2; } // -- Boolean operators -- template GLM_FUNC_QUALIFIER bool operator==(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) { return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]) && (m1[3] == m2[3]); } template GLM_FUNC_QUALIFIER bool operator!=(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2) { return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]) || (m1[3] != m2[3]); } }//namespace glm #if GLM_CONFIG_SIMD == GLM_ENABLE # include "type_mat4x4_simd.inl" #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/type_mat4x4_simd.inl000066400000000000000000000000671360521144700254640ustar00rootroot00000000000000/// @ref core namespace glm { }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/type_quat.hpp000066400000000000000000000130771360521144700243130ustar00rootroot00000000000000/// @ref core /// @file glm/detail/type_quat.hpp #pragma once // Dependency: #include "../detail/type_mat3x3.hpp" #include "../detail/type_mat4x4.hpp" #include "../detail/type_vec3.hpp" #include "../detail/type_vec4.hpp" #include "../ext/vector_relational.hpp" #include "../ext/quaternion_relational.hpp" #include "../gtc/constants.hpp" #include "../gtc/matrix_transform.hpp" namespace glm { template struct qua { // -- Implementation detail -- typedef qua type; typedef T value_type; // -- Data -- # if GLM_SILENT_WARNINGS == GLM_ENABLE # if GLM_COMPILER & GLM_COMPILER_GCC # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpedantic" # elif GLM_COMPILER & GLM_COMPILER_CLANG # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wgnu-anonymous-struct" # pragma clang diagnostic ignored "-Wnested-anon-types" # elif GLM_COMPILER & GLM_COMPILER_VC # pragma warning(push) # pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union # endif # endif # if GLM_LANG & GLM_LANG_CXXMS_FLAG union { struct { T x, y, z, w;}; typename detail::storage<4, T, detail::is_aligned::value>::type data; }; # else T x, y, z, w; # endif # if GLM_SILENT_WARNINGS == GLM_ENABLE # if GLM_COMPILER & GLM_COMPILER_CLANG # pragma clang diagnostic pop # elif GLM_COMPILER & GLM_COMPILER_GCC # pragma GCC diagnostic pop # elif GLM_COMPILER & GLM_COMPILER_VC # pragma warning(pop) # endif # endif // -- Component accesses -- typedef length_t length_type; /// Return the count of components of a quaternion GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 4;} GLM_FUNC_DECL GLM_CONSTEXPR T & operator[](length_type i); GLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const; // -- Implicit basic constructors -- GLM_FUNC_DECL GLM_CONSTEXPR qua() GLM_DEFAULT; GLM_FUNC_DECL GLM_CONSTEXPR qua(qua const& q) GLM_DEFAULT; template GLM_FUNC_DECL GLM_CONSTEXPR qua(qua const& q); // -- Explicit basic constructors -- GLM_FUNC_DECL GLM_CONSTEXPR qua(T s, vec<3, T, Q> const& v); GLM_FUNC_DECL GLM_CONSTEXPR qua(T w, T x, T y, T z); // -- Conversion constructors -- template GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT qua(qua const& q); /// Explicit conversion operators # if GLM_HAS_EXPLICIT_CONVERSION_OPERATORS GLM_FUNC_DECL explicit operator mat<3, 3, T, Q>() const; GLM_FUNC_DECL explicit operator mat<4, 4, T, Q>() const; # endif /// Create a quaternion from two normalized axis /// /// @param u A first normalized axis /// @param v A second normalized axis /// @see gtc_quaternion /// @see http://lolengine.net/blog/2013/09/18/beautiful-maths-quaternion-from-vectors GLM_FUNC_DECL qua(vec<3, T, Q> const& u, vec<3, T, Q> const& v); /// Build a quaternion from euler angles (pitch, yaw, roll), in radians. GLM_FUNC_DECL GLM_EXPLICIT qua(vec<3, T, Q> const& eulerAngles); GLM_FUNC_DECL GLM_EXPLICIT qua(mat<3, 3, T, Q> const& q); GLM_FUNC_DECL GLM_EXPLICIT qua(mat<4, 4, T, Q> const& q); // -- Unary arithmetic operators -- GLM_FUNC_DECL qua& operator=(qua const& q) GLM_DEFAULT; template GLM_FUNC_DECL qua& operator=(qua const& q); template GLM_FUNC_DECL qua& operator+=(qua const& q); template GLM_FUNC_DECL qua& operator-=(qua const& q); template GLM_FUNC_DECL qua& operator*=(qua const& q); template GLM_FUNC_DECL qua& operator*=(U s); template GLM_FUNC_DECL qua& operator/=(U s); }; // -- Unary bit operators -- template GLM_FUNC_DECL qua operator+(qua const& q); template GLM_FUNC_DECL qua operator-(qua const& q); // -- Binary operators -- template GLM_FUNC_DECL qua operator+(qua const& q, qua const& p); template GLM_FUNC_DECL qua operator-(qua const& q, qua const& p); template GLM_FUNC_DECL qua operator*(qua const& q, qua const& p); template GLM_FUNC_DECL vec<3, T, Q> operator*(qua const& q, vec<3, T, Q> const& v); template GLM_FUNC_DECL vec<3, T, Q> operator*(vec<3, T, Q> const& v, qua const& q); template GLM_FUNC_DECL vec<4, T, Q> operator*(qua const& q, vec<4, T, Q> const& v); template GLM_FUNC_DECL vec<4, T, Q> operator*(vec<4, T, Q> const& v, qua const& q); template GLM_FUNC_DECL qua operator*(qua const& q, T const& s); template GLM_FUNC_DECL qua operator*(T const& s, qua const& q); template GLM_FUNC_DECL qua operator/(qua const& q, T const& s); // -- Boolean operators -- template GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(qua const& q1, qua const& q2); template GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(qua const& q1, qua const& q2); } //namespace glm #ifndef GLM_EXTERNAL_TEMPLATE #include "type_quat.inl" #endif//GLM_EXTERNAL_TEMPLATE connectome-workbench-1.4.2/src/GLMath/glm/detail/type_quat.inl000066400000000000000000000247031360521144700243040ustar00rootroot00000000000000#include "../trigonometric.hpp" #include "../exponential.hpp" #include "../ext/quaternion_geometric.hpp" #include namespace glm{ namespace detail { template struct genTypeTrait > { static const genTypeEnum GENTYPE = GENTYPE_QUAT; }; template struct compute_dot, T, Aligned> { static GLM_FUNC_QUALIFIER T call(qua const& a, qua const& b) { vec<4, T, Q> tmp(a.w * b.w, a.x * b.x, a.y * b.y, a.z * b.z); return (tmp.x + tmp.y) + (tmp.z + tmp.w); } }; template struct compute_quat_add { static qua call(qua const& q, qua const& p) { return qua(q.w + p.w, q.x + p.x, q.y + p.y, q.z + p.z); } }; template struct compute_quat_sub { static qua call(qua const& q, qua const& p) { return qua(q.w - p.w, q.x - p.x, q.y - p.y, q.z - p.z); } }; template struct compute_quat_mul_scalar { static qua call(qua const& q, T s) { return qua(q.w * s, q.x * s, q.y * s, q.z * s); } }; template struct compute_quat_div_scalar { static qua call(qua const& q, T s) { return qua(q.w / s, q.x / s, q.y / s, q.z / s); } }; template struct compute_quat_mul_vec4 { static vec<4, T, Q> call(qua const& q, vec<4, T, Q> const& v) { return vec<4, T, Q>(q * vec<3, T, Q>(v), v.w); } }; }//namespace detail // -- Component accesses -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR T & qua::operator[](typename qua::length_type i) { assert(i >= 0 && i < this->length()); return (&x)[i]; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& qua::operator[](typename qua::length_type i) const { assert(i >= 0 && i < this->length()); return (&x)[i]; } // -- Implicit basic constructors -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua() # if GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE : x(0), y(0), z(0), w(1) # endif {} template GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(qua const& q) : x(q.x), y(q.y), z(q.z), w(q.w) {} # endif template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(qua const& q) : x(q.x), y(q.y), z(q.z), w(q.w) {} // -- Explicit basic constructors -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(T s, vec<3, T, Q> const& v) : x(v.x), y(v.y), z(v.z), w(s) {} template GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(T _w, T _x, T _y, T _z) : x(_x), y(_y), z(_z), w(_w) {} // -- Conversion constructors -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR qua::qua(qua const& q) : x(static_cast(q.x)) , y(static_cast(q.y)) , z(static_cast(q.z)) , w(static_cast(q.w)) {} //template //GLM_FUNC_QUALIFIER qua::qua //( // valType const& pitch, // valType const& yaw, // valType const& roll //) //{ // vec<3, valType> eulerAngle(pitch * valType(0.5), yaw * valType(0.5), roll * valType(0.5)); // vec<3, valType> c = glm::cos(eulerAngle * valType(0.5)); // vec<3, valType> s = glm::sin(eulerAngle * valType(0.5)); // // this->w = c.x * c.y * c.z + s.x * s.y * s.z; // this->x = s.x * c.y * c.z - c.x * s.y * s.z; // this->y = c.x * s.y * c.z + s.x * c.y * s.z; // this->z = c.x * c.y * s.z - s.x * s.y * c.z; //} template GLM_FUNC_QUALIFIER qua::qua(vec<3, T, Q> const& u, vec<3, T, Q> const& v) { T norm_u_norm_v = sqrt(dot(u, u) * dot(v, v)); T real_part = norm_u_norm_v + dot(u, v); vec<3, T, Q> t; if(real_part < static_cast(1.e-6f) * norm_u_norm_v) { // If u and v are exactly opposite, rotate 180 degrees // around an arbitrary orthogonal axis. Axis normalisation // can happen later, when we normalise the quaternion. real_part = static_cast(0); t = abs(u.x) > abs(u.z) ? vec<3, T, Q>(-u.y, u.x, static_cast(0)) : vec<3, T, Q>(static_cast(0), -u.z, u.y); } else { // Otherwise, build quaternion the standard way. t = cross(u, v); } *this = normalize(qua(real_part, t.x, t.y, t.z)); } template GLM_FUNC_QUALIFIER qua::qua(vec<3, T, Q> const& eulerAngle) { vec<3, T, Q> c = glm::cos(eulerAngle * T(0.5)); vec<3, T, Q> s = glm::sin(eulerAngle * T(0.5)); this->w = c.x * c.y * c.z + s.x * s.y * s.z; this->x = s.x * c.y * c.z - c.x * s.y * s.z; this->y = c.x * s.y * c.z + s.x * c.y * s.z; this->z = c.x * c.y * s.z - s.x * s.y * c.z; } template GLM_FUNC_QUALIFIER qua::qua(mat<3, 3, T, Q> const& m) { *this = quat_cast(m); } template GLM_FUNC_QUALIFIER qua::qua(mat<4, 4, T, Q> const& m) { *this = quat_cast(m); } # if GLM_HAS_EXPLICIT_CONVERSION_OPERATORS template GLM_FUNC_QUALIFIER qua::operator mat<3, 3, T, Q>() const { return mat3_cast(*this); } template GLM_FUNC_QUALIFIER qua::operator mat<4, 4, T, Q>() const { return mat4_cast(*this); } # endif//GLM_HAS_EXPLICIT_CONVERSION_OPERATORS // -- Unary arithmetic operators -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER qua & qua::operator=(qua const& q) { this->w = q.w; this->x = q.x; this->y = q.y; this->z = q.z; return *this; } # endif template template GLM_FUNC_QUALIFIER qua & qua::operator=(qua const& q) { this->w = static_cast(q.w); this->x = static_cast(q.x); this->y = static_cast(q.y); this->z = static_cast(q.z); return *this; } template template GLM_FUNC_QUALIFIER qua & qua::operator+=(qua const& q) { return (*this = detail::compute_quat_add::value>::call(*this, qua(q))); } template template GLM_FUNC_QUALIFIER qua & qua::operator-=(qua const& q) { return (*this = detail::compute_quat_sub::value>::call(*this, qua(q))); } template template GLM_FUNC_QUALIFIER qua & qua::operator*=(qua const& r) { qua const p(*this); qua const q(r); this->w = p.w * q.w - p.x * q.x - p.y * q.y - p.z * q.z; this->x = p.w * q.x + p.x * q.w + p.y * q.z - p.z * q.y; this->y = p.w * q.y + p.y * q.w + p.z * q.x - p.x * q.z; this->z = p.w * q.z + p.z * q.w + p.x * q.y - p.y * q.x; return *this; } template template GLM_FUNC_QUALIFIER qua & qua::operator*=(U s) { return (*this = detail::compute_quat_mul_scalar::value>::call(*this, static_cast(s))); } template template GLM_FUNC_QUALIFIER qua & qua::operator/=(U s) { return (*this = detail::compute_quat_div_scalar::value>::call(*this, static_cast(s))); } // -- Unary bit operators -- template GLM_FUNC_QUALIFIER qua operator+(qua const& q) { return q; } template GLM_FUNC_QUALIFIER qua operator-(qua const& q) { return qua(-q.w, -q.x, -q.y, -q.z); } // -- Binary operators -- template GLM_FUNC_QUALIFIER qua operator+(qua const& q, qua const& p) { return qua(q) += p; } template GLM_FUNC_QUALIFIER qua operator-(qua const& q, qua const& p) { return qua(q) -= p; } template GLM_FUNC_QUALIFIER qua operator*(qua const& q, qua const& p) { return qua(q) *= p; } template GLM_FUNC_QUALIFIER vec<3, T, Q> operator*(qua const& q, vec<3, T, Q> const& v) { vec<3, T, Q> const QuatVector(q.x, q.y, q.z); vec<3, T, Q> const uv(glm::cross(QuatVector, v)); vec<3, T, Q> const uuv(glm::cross(QuatVector, uv)); return v + ((uv * q.w) + uuv) * static_cast(2); } template GLM_FUNC_QUALIFIER vec<3, T, Q> operator*(vec<3, T, Q> const& v, qua const& q) { return glm::inverse(q) * v; } template GLM_FUNC_QUALIFIER vec<4, T, Q> operator*(qua const& q, vec<4, T, Q> const& v) { return detail::compute_quat_mul_vec4::value>::call(q, v); } template GLM_FUNC_QUALIFIER vec<4, T, Q> operator*(vec<4, T, Q> const& v, qua const& q) { return glm::inverse(q) * v; } template GLM_FUNC_QUALIFIER qua operator*(qua const& q, T const& s) { return qua( q.w * s, q.x * s, q.y * s, q.z * s); } template GLM_FUNC_QUALIFIER qua operator*(T const& s, qua const& q) { return q * s; } template GLM_FUNC_QUALIFIER qua operator/(qua const& q, T const& s) { return qua( q.w / s, q.x / s, q.y / s, q.z / s); } // -- Boolean operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(qua const& q1, qua const& q2) { return q1.x == q2.x && q1.y == q2.y && q1.z == q2.z && q1.w == q2.w; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(qua const& q1, qua const& q2) { return q1.x != q2.x || q1.y != q2.y || q1.z != q2.z || q1.w != q2.w; } }//namespace glm #if GLM_CONFIG_SIMD == GLM_ENABLE # include "type_quat_simd.inl" #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/type_quat_simd.inl000066400000000000000000000140241360521144700253130ustar00rootroot00000000000000/// @ref core #if GLM_ARCH & GLM_ARCH_SSE2_BIT namespace glm{ namespace detail { /* template struct compute_quat_mul { static qua call(qua const& q1, qua const& q2) { // SSE2 STATS: 11 shuffle, 8 mul, 8 add // SSE4 STATS: 3 shuffle, 4 mul, 4 dpps __m128 const mul0 = _mm_mul_ps(q1.Data, _mm_shuffle_ps(q2.Data, q2.Data, _MM_SHUFFLE(0, 1, 2, 3))); __m128 const mul1 = _mm_mul_ps(q1.Data, _mm_shuffle_ps(q2.Data, q2.Data, _MM_SHUFFLE(1, 0, 3, 2))); __m128 const mul2 = _mm_mul_ps(q1.Data, _mm_shuffle_ps(q2.Data, q2.Data, _MM_SHUFFLE(2, 3, 0, 1))); __m128 const mul3 = _mm_mul_ps(q1.Data, q2.Data); # if GLM_ARCH & GLM_ARCH_SSE41_BIT __m128 const add0 = _mm_dp_ps(mul0, _mm_set_ps(1.0f, -1.0f, 1.0f, 1.0f), 0xff); __m128 const add1 = _mm_dp_ps(mul1, _mm_set_ps(1.0f, 1.0f, 1.0f, -1.0f), 0xff); __m128 const add2 = _mm_dp_ps(mul2, _mm_set_ps(1.0f, 1.0f, -1.0f, 1.0f), 0xff); __m128 const add3 = _mm_dp_ps(mul3, _mm_set_ps(1.0f, -1.0f, -1.0f, -1.0f), 0xff); # else __m128 const mul4 = _mm_mul_ps(mul0, _mm_set_ps(1.0f, -1.0f, 1.0f, 1.0f)); __m128 const add0 = _mm_add_ps(mul0, _mm_movehl_ps(mul4, mul4)); __m128 const add4 = _mm_add_ss(add0, _mm_shuffle_ps(add0, add0, 1)); __m128 const mul5 = _mm_mul_ps(mul1, _mm_set_ps(1.0f, 1.0f, 1.0f, -1.0f)); __m128 const add1 = _mm_add_ps(mul1, _mm_movehl_ps(mul5, mul5)); __m128 const add5 = _mm_add_ss(add1, _mm_shuffle_ps(add1, add1, 1)); __m128 const mul6 = _mm_mul_ps(mul2, _mm_set_ps(1.0f, 1.0f, -1.0f, 1.0f)); __m128 const add2 = _mm_add_ps(mul6, _mm_movehl_ps(mul6, mul6)); __m128 const add6 = _mm_add_ss(add2, _mm_shuffle_ps(add2, add2, 1)); __m128 const mul7 = _mm_mul_ps(mul3, _mm_set_ps(1.0f, -1.0f, -1.0f, -1.0f)); __m128 const add3 = _mm_add_ps(mul3, _mm_movehl_ps(mul7, mul7)); __m128 const add7 = _mm_add_ss(add3, _mm_shuffle_ps(add3, add3, 1)); #endif // This SIMD code is a politically correct way of doing this, but in every test I've tried it has been slower than // the final code below. I'll keep this here for reference - maybe somebody else can do something better... // //__m128 xxyy = _mm_shuffle_ps(add4, add5, _MM_SHUFFLE(0, 0, 0, 0)); //__m128 zzww = _mm_shuffle_ps(add6, add7, _MM_SHUFFLE(0, 0, 0, 0)); // //return _mm_shuffle_ps(xxyy, zzww, _MM_SHUFFLE(2, 0, 2, 0)); qua Result; _mm_store_ss(&Result.x, add4); _mm_store_ss(&Result.y, add5); _mm_store_ss(&Result.z, add6); _mm_store_ss(&Result.w, add7); return Result; } }; */ template struct compute_quat_add { static qua call(qua const& q, qua const& p) { qua Result; Result.data = _mm_add_ps(q.data, p.data); return Result; } }; # if GLM_ARCH & GLM_ARCH_AVX_BIT template struct compute_quat_add { static qua call(qua const& a, qua const& b) { qua Result; Result.data = _mm256_add_pd(a.data, b.data); return Result; } }; # endif template struct compute_quat_sub { static qua call(qua const& q, qua const& p) { vec<4, float, Q> Result; Result.data = _mm_sub_ps(q.data, p.data); return Result; } }; # if GLM_ARCH & GLM_ARCH_AVX_BIT template struct compute_quat_sub { static qua call(qua const& a, qua const& b) { qua Result; Result.data = _mm256_sub_pd(a.data, b.data); return Result; } }; # endif template struct compute_quat_mul_scalar { static qua call(qua const& q, float s) { vec<4, float, Q> Result; Result.data = _mm_mul_ps(q.data, _mm_set_ps1(s)); return Result; } }; # if GLM_ARCH & GLM_ARCH_AVX_BIT template struct compute_quat_mul_scalar { static qua call(qua const& q, double s) { qua Result; Result.data = _mm256_mul_pd(q.data, _mm_set_ps1(s)); return Result; } }; # endif template struct compute_quat_div_scalar { static qua call(qua const& q, float s) { vec<4, float, Q> Result; Result.data = _mm_div_ps(q.data, _mm_set_ps1(s)); return Result; } }; # if GLM_ARCH & GLM_ARCH_AVX_BIT template struct compute_quat_div_scalar { static qua call(qua const& q, double s) { qua Result; Result.data = _mm256_div_pd(q.data, _mm_set_ps1(s)); return Result; } }; # endif template struct compute_quat_mul_vec4 { static vec<4, float, Q> call(qua const& q, vec<4, float, Q> const& v) { __m128 const q_wwww = _mm_shuffle_ps(q.data, q.data, _MM_SHUFFLE(3, 3, 3, 3)); __m128 const q_swp0 = _mm_shuffle_ps(q.data, q.data, _MM_SHUFFLE(3, 0, 2, 1)); __m128 const q_swp1 = _mm_shuffle_ps(q.data, q.data, _MM_SHUFFLE(3, 1, 0, 2)); __m128 const v_swp0 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(3, 0, 2, 1)); __m128 const v_swp1 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(3, 1, 0, 2)); __m128 uv = _mm_sub_ps(_mm_mul_ps(q_swp0, v_swp1), _mm_mul_ps(q_swp1, v_swp0)); __m128 uv_swp0 = _mm_shuffle_ps(uv, uv, _MM_SHUFFLE(3, 0, 2, 1)); __m128 uv_swp1 = _mm_shuffle_ps(uv, uv, _MM_SHUFFLE(3, 1, 0, 2)); __m128 uuv = _mm_sub_ps(_mm_mul_ps(q_swp0, uv_swp1), _mm_mul_ps(q_swp1, uv_swp0)); __m128 const two = _mm_set1_ps(2.0f); uv = _mm_mul_ps(uv, _mm_mul_ps(q_wwww, two)); uuv = _mm_mul_ps(uuv, two); vec<4, float, Q> Result; Result.data = _mm_add_ps(v.Data, _mm_add_ps(uv, uuv)); return Result; } }; }//namespace detail }//namespace glm #endif//GLM_ARCH & GLM_ARCH_SSE2_BIT connectome-workbench-1.4.2/src/GLMath/glm/detail/type_vec1.hpp000066400000000000000000000264511360521144700241770ustar00rootroot00000000000000/// @ref core /// @file glm/detail/type_vec1.hpp #pragma once #include "qualifier.hpp" #if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR # include "_swizzle.hpp" #elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION # include "_swizzle_func.hpp" #endif #include namespace glm { template struct vec<1, T, Q> { // -- Implementation detail -- typedef T value_type; typedef vec<1, T, Q> type; typedef vec<1, bool, Q> bool_type; // -- Data -- # if GLM_SILENT_WARNINGS == GLM_ENABLE # if GLM_COMPILER & GLM_COMPILER_GCC # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpedantic" # elif GLM_COMPILER & GLM_COMPILER_CLANG # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wgnu-anonymous-struct" # pragma clang diagnostic ignored "-Wnested-anon-types" # elif GLM_COMPILER & GLM_COMPILER_VC # pragma warning(push) # pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union # endif # endif # if GLM_CONFIG_XYZW_ONLY T x; # elif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE union { T x; T r; T s; typename detail::storage<1, T, detail::is_aligned::value>::type data; /* # if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR _GLM_SWIZZLE1_2_MEMBERS(T, Q, x) _GLM_SWIZZLE1_2_MEMBERS(T, Q, r) _GLM_SWIZZLE1_2_MEMBERS(T, Q, s) _GLM_SWIZZLE1_3_MEMBERS(T, Q, x) _GLM_SWIZZLE1_3_MEMBERS(T, Q, r) _GLM_SWIZZLE1_3_MEMBERS(T, Q, s) _GLM_SWIZZLE1_4_MEMBERS(T, Q, x) _GLM_SWIZZLE1_4_MEMBERS(T, Q, r) _GLM_SWIZZLE1_4_MEMBERS(T, Q, s) # endif */ }; # else union {T x, r, s;}; /* # if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION GLM_SWIZZLE_GEN_VEC_FROM_VEC1(T, Q) # endif */ # endif # if GLM_SILENT_WARNINGS == GLM_ENABLE # if GLM_COMPILER & GLM_COMPILER_CLANG # pragma clang diagnostic pop # elif GLM_COMPILER & GLM_COMPILER_GCC # pragma GCC diagnostic pop # elif GLM_COMPILER & GLM_COMPILER_VC # pragma warning(pop) # endif # endif // -- Component accesses -- /// Return the count of components of the vector typedef length_t length_type; GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 1;} GLM_FUNC_DECL GLM_CONSTEXPR T & operator[](length_type i); GLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const; // -- Implicit basic constructors -- GLM_FUNC_DECL GLM_CONSTEXPR vec() GLM_DEFAULT; GLM_FUNC_DECL GLM_CONSTEXPR vec(vec const& v) GLM_DEFAULT; template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, T, P> const& v); // -- Explicit basic constructors -- GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(T scalar); // -- Conversion vector constructors -- /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<2, U, P> const& v); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<3, U, P> const& v); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<4, U, P> const& v); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<1, U, P> const& v); // -- Swizzle constructors -- /* # if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR template GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<1, T, Q, E0, -1,-2,-3> const& that) { *this = that(); } # endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR */ // -- Unary arithmetic operators -- GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator=(vec const& v) GLM_DEFAULT; template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator+=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator+=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator-=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator-=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator*=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator*=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator/=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator/=(vec<1, U, Q> const& v); // -- Increment and decrement operators -- GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator++(); GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator--(); GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator++(int); GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator--(int); // -- Unary bit operators -- template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator%=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator%=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator&=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator&=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator|=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator|=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator^=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator^=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator<<=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator<<=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator>>=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator>>=(vec<1, U, Q> const& v); }; // -- Unary operators -- template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v); // -- Binary operators -- template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator+(T scalar, vec<1, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator-(T scalar, vec<1, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator*(vec<1, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator*(T scalar, vec<1, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator*(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator/(vec<1, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator/(T scalar, vec<1, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator/(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator%(vec<1, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator%(T scalar, vec<1, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator%(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator&(vec<1, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator&(T scalar, vec<1, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator&(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator|(vec<1, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator|(T scalar, vec<1, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator|(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator^(vec<1, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator^(T scalar, vec<1, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator^(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator<<(vec<1, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator<<(T scalar, vec<1, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator<<(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator>>(vec<1, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator>>(T scalar, vec<1, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator>>(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator~(vec<1, T, Q> const& v); // -- Boolean operators -- template GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, bool, Q> operator&&(vec<1, bool, Q> const& v1, vec<1, bool, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<1, bool, Q> operator||(vec<1, bool, Q> const& v1, vec<1, bool, Q> const& v2); }//namespace glm #ifndef GLM_EXTERNAL_TEMPLATE #include "type_vec1.inl" #endif//GLM_EXTERNAL_TEMPLATE connectome-workbench-1.4.2/src/GLMath/glm/detail/type_vec1.inl000066400000000000000000000342131360521144700241650ustar00rootroot00000000000000/// @ref core #include "./compute_vector_relational.hpp" namespace glm { // -- Implicit basic constructors -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec() # if GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE : x(0) # endif {} template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<1, T, Q> const& v) : x(v.x) {} # endif template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<1, T, P> const& v) : x(v.x) {} // -- Explicit basic constructors -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(T scalar) : x(scalar) {} // -- Conversion vector constructors -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<1, U, P> const& v) : x(static_cast(v.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<2, U, P> const& v) : x(static_cast(v.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<3, U, P> const& v) : x(static_cast(v.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<4, U, P> const& v) : x(static_cast(v.x)) {} // -- Component accesses -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR T & vec<1, T, Q>::operator[](typename vec<1, T, Q>::length_type) { return x; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& vec<1, T, Q>::operator[](typename vec<1, T, Q>::length_type) const { return x; } // -- Unary arithmetic operators -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator=(vec<1, T, Q> const& v) { this->x = v.x; return *this; } # endif template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator=(vec<1, U, Q> const& v) { this->x = static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator+=(U scalar) { this->x += static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator+=(vec<1, U, Q> const& v) { this->x += static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator-=(U scalar) { this->x -= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator-=(vec<1, U, Q> const& v) { this->x -= static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator*=(U scalar) { this->x *= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator*=(vec<1, U, Q> const& v) { this->x *= static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator/=(U scalar) { this->x /= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator/=(vec<1, U, Q> const& v) { this->x /= static_cast(v.x); return *this; } // -- Increment and decrement operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator++() { ++this->x; return *this; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator--() { --this->x; return *this; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> vec<1, T, Q>::operator++(int) { vec<1, T, Q> Result(*this); ++*this; return Result; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> vec<1, T, Q>::operator--(int) { vec<1, T, Q> Result(*this); --*this; return Result; } // -- Unary bit operators -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator%=(U scalar) { this->x %= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator%=(vec<1, U, Q> const& v) { this->x %= static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator&=(U scalar) { this->x &= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator&=(vec<1, U, Q> const& v) { this->x &= static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator|=(U scalar) { this->x |= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator|=(vec<1, U, Q> const& v) { this->x |= U(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator^=(U scalar) { this->x ^= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator^=(vec<1, U, Q> const& v) { this->x ^= static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator<<=(U scalar) { this->x <<= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator<<=(vec<1, U, Q> const& v) { this->x <<= static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator>>=(U scalar) { this->x >>= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator>>=(vec<1, U, Q> const& v) { this->x >>= static_cast(v.x); return *this; } // -- Unary constant operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v) { return v; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v) { return vec<1, T, Q>( -v.x); } // -- Binary arithmetic operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v, T scalar) { return vec<1, T, Q>( v.x + scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator+(T scalar, vec<1, T, Q> const& v) { return vec<1, T, Q>( scalar + v.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<1, T, Q>( v1.x + v2.x); } //operator- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v, T scalar) { return vec<1, T, Q>( v.x - scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator-(T scalar, vec<1, T, Q> const& v) { return vec<1, T, Q>( scalar - v.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<1, T, Q>( v1.x - v2.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator*(vec<1, T, Q> const& v, T scalar) { return vec<1, T, Q>( v.x * scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator*(T scalar, vec<1, T, Q> const& v) { return vec<1, T, Q>( scalar * v.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator*(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<1, T, Q>( v1.x * v2.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator/(vec<1, T, Q> const& v, T scalar) { return vec<1, T, Q>( v.x / scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator/(T scalar, vec<1, T, Q> const& v) { return vec<1, T, Q>( scalar / v.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator/(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<1, T, Q>( v1.x / v2.x); } // -- Binary bit operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator%(vec<1, T, Q> const& v, T scalar) { return vec<1, T, Q>( v.x % scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator%(T scalar, vec<1, T, Q> const& v) { return vec<1, T, Q>( scalar % v.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator%(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<1, T, Q>( v1.x % v2.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator&(vec<1, T, Q> const& v, T scalar) { return vec<1, T, Q>( v.x & scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator&(T scalar, vec<1, T, Q> const& v) { return vec<1, T, Q>( scalar & v.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator&(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<1, T, Q>( v1.x & v2.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator|(vec<1, T, Q> const& v, T scalar) { return vec<1, T, Q>( v.x | scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator|(T scalar, vec<1, T, Q> const& v) { return vec<1, T, Q>( scalar | v.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator|(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<1, T, Q>( v1.x | v2.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator^(vec<1, T, Q> const& v, T scalar) { return vec<1, T, Q>( v.x ^ scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator^(T scalar, vec<1, T, Q> const& v) { return vec<1, T, Q>( scalar ^ v.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator^(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<1, T, Q>( v1.x ^ v2.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator<<(vec<1, T, Q> const& v, T scalar) { return vec<1, T, Q>( static_cast(v.x << scalar)); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator<<(T scalar, vec<1, T, Q> const& v) { return vec<1, T, Q>( scalar << v.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator<<(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<1, T, Q>( v1.x << v2.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator>>(vec<1, T, Q> const& v, T scalar) { return vec<1, T, Q>( v.x >> scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator>>(T scalar, vec<1, T, Q> const& v) { return vec<1, T, Q>( scalar >> v.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator>>(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<1, T, Q>( v1.x >> v2.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator~(vec<1, T, Q> const& v) { return vec<1, T, Q>( ~v.x); } // -- Boolean operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) { return detail::compute_equal::is_iec559>::call(v1.x, v2.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2) { return !(v1 == v2); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, bool, Q> operator&&(vec<1, bool, Q> const& v1, vec<1, bool, Q> const& v2) { return vec<1, bool, Q>(v1.x && v2.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, bool, Q> operator||(vec<1, bool, Q> const& v1, vec<1, bool, Q> const& v2) { return vec<1, bool, Q>(v1.x || v2.x); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/type_vec2.hpp000066400000000000000000000371751360521144700242050ustar00rootroot00000000000000/// @ref core /// @file glm/detail/type_vec2.hpp #pragma once #include "qualifier.hpp" #if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR # include "_swizzle.hpp" #elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION # include "_swizzle_func.hpp" #endif #include namespace glm { template struct vec<2, T, Q> { // -- Implementation detail -- typedef T value_type; typedef vec<2, T, Q> type; typedef vec<2, bool, Q> bool_type; // -- Data -- # if GLM_SILENT_WARNINGS == GLM_ENABLE # if GLM_COMPILER & GLM_COMPILER_GCC # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpedantic" # elif GLM_COMPILER & GLM_COMPILER_CLANG # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wgnu-anonymous-struct" # pragma clang diagnostic ignored "-Wnested-anon-types" # elif GLM_COMPILER & GLM_COMPILER_VC # pragma warning(push) # pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union # endif # endif # if GLM_CONFIG_XYZW_ONLY T x, y; # elif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE union { struct{ T x, y; }; struct{ T r, g; }; struct{ T s, t; }; typename detail::storage<2, T, detail::is_aligned::value>::type data; # if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR GLM_SWIZZLE2_2_MEMBERS(T, Q, x, y) GLM_SWIZZLE2_2_MEMBERS(T, Q, r, g) GLM_SWIZZLE2_2_MEMBERS(T, Q, s, t) GLM_SWIZZLE2_3_MEMBERS(T, Q, x, y) GLM_SWIZZLE2_3_MEMBERS(T, Q, r, g) GLM_SWIZZLE2_3_MEMBERS(T, Q, s, t) GLM_SWIZZLE2_4_MEMBERS(T, Q, x, y) GLM_SWIZZLE2_4_MEMBERS(T, Q, r, g) GLM_SWIZZLE2_4_MEMBERS(T, Q, s, t) # endif }; # else union {T x, r, s;}; union {T y, g, t;}; # if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION GLM_SWIZZLE_GEN_VEC_FROM_VEC2(T, Q) # endif//GLM_CONFIG_SWIZZLE # endif # if GLM_SILENT_WARNINGS == GLM_ENABLE # if GLM_COMPILER & GLM_COMPILER_CLANG # pragma clang diagnostic pop # elif GLM_COMPILER & GLM_COMPILER_GCC # pragma GCC diagnostic pop # elif GLM_COMPILER & GLM_COMPILER_VC # pragma warning(pop) # endif # endif // -- Component accesses -- /// Return the count of components of the vector typedef length_t length_type; GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 2;} GLM_FUNC_DECL GLM_CONSTEXPR T& operator[](length_type i); GLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const; // -- Implicit basic constructors -- GLM_FUNC_DECL GLM_CONSTEXPR vec() GLM_DEFAULT; GLM_FUNC_DECL GLM_CONSTEXPR vec(vec const& v) GLM_DEFAULT; template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, T, P> const& v); // -- Explicit basic constructors -- GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(T scalar); GLM_FUNC_DECL GLM_CONSTEXPR vec(T x, T y); // -- Conversion constructors -- template GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(vec<1, U, P> const& v); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(A x, B y); template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, Q> const& x, B y); template GLM_FUNC_DECL GLM_CONSTEXPR vec(A x, vec<1, B, Q> const& y); template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, Q> const& x, vec<1, B, Q> const& y); // -- Conversion vector constructors -- /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<3, U, P> const& v); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<4, U, P> const& v); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<2, U, P> const& v); // -- Swizzle constructors -- # if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR template GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<2, T, Q, E0, E1,-1,-2> const& that) { *this = that(); } # endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR // -- Unary arithmetic operators -- GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator=(vec const& v) GLM_DEFAULT; template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator=(vec<2, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator+=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator+=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator+=(vec<2, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator-=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator-=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator-=(vec<2, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator*=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator*=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator*=(vec<2, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator/=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator/=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator/=(vec<2, U, Q> const& v); // -- Increment and decrement operators -- GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator++(); GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator--(); GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator++(int); GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator--(int); // -- Unary bit operators -- template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator%=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator%=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator%=(vec<2, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator&=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator&=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator&=(vec<2, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator|=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator|=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator|=(vec<2, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator^=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator^=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator^=(vec<2, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator<<=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator<<=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator<<=(vec<2, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator>>=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator>>=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator>>=(vec<2, U, Q> const& v); }; // -- Unary operators -- template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v); // -- Binary operators -- template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(T scalar, vec<2, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(T scalar, vec<2, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(T scalar, vec<2, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(T scalar, vec<2, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(T scalar, vec<2, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(T scalar, vec<2, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(T scalar, vec<2, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(T scalar, vec<2, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(T scalar, vec<2, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(T scalar, vec<2, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator~(vec<2, T, Q> const& v); // -- Boolean operators -- template GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, bool, Q> operator&&(vec<2, bool, Q> const& v1, vec<2, bool, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<2, bool, Q> operator||(vec<2, bool, Q> const& v1, vec<2, bool, Q> const& v2); }//namespace glm #ifndef GLM_EXTERNAL_TEMPLATE #include "type_vec2.inl" #endif//GLM_EXTERNAL_TEMPLATE connectome-workbench-1.4.2/src/GLMath/glm/detail/type_vec2.inl000066400000000000000000000571131360521144700241720ustar00rootroot00000000000000/// @ref core #include "./compute_vector_relational.hpp" namespace glm { // -- Implicit basic constructors -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec() # if GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE : x(0), y(0) # endif {} template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<2, T, Q> const& v) : x(v.x), y(v.y) {} # endif template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<2, T, P> const& v) : x(v.x), y(v.y) {} // -- Explicit basic constructors -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(T scalar) : x(scalar), y(scalar) {} template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(T _x, T _y) : x(_x), y(_y) {} // -- Conversion scalar constructors -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<1, U, P> const& v) : x(static_cast(v.x)) , y(static_cast(v.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(A _x, B _y) : x(static_cast(_x)) , y(static_cast(_y)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<1, A, Q> const& _x, B _y) : x(static_cast(_x.x)) , y(static_cast(_y)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(A _x, vec<1, B, Q> const& _y) : x(static_cast(_x)) , y(static_cast(_y.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<1, A, Q> const& _x, vec<1, B, Q> const& _y) : x(static_cast(_x.x)) , y(static_cast(_y.x)) {} // -- Conversion vector constructors -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<2, U, P> const& v) : x(static_cast(v.x)) , y(static_cast(v.y)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<3, U, P> const& v) : x(static_cast(v.x)) , y(static_cast(v.y)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<4, U, P> const& v) : x(static_cast(v.x)) , y(static_cast(v.y)) {} // -- Component accesses -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR T & vec<2, T, Q>::operator[](typename vec<2, T, Q>::length_type i) { assert(i >= 0 && i < this->length()); switch(i) { default: case 0: return x; case 1: return y; } } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& vec<2, T, Q>::operator[](typename vec<2, T, Q>::length_type i) const { assert(i >= 0 && i < this->length()); switch(i) { default: case 0: return x; case 1: return y; } } // -- Unary arithmetic operators -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator=(vec<2, T, Q> const& v) { this->x = v.x; this->y = v.y; return *this; } # endif template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator=(vec<2, U, Q> const& v) { this->x = static_cast(v.x); this->y = static_cast(v.y); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator+=(U scalar) { this->x += static_cast(scalar); this->y += static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator+=(vec<1, U, Q> const& v) { this->x += static_cast(v.x); this->y += static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator+=(vec<2, U, Q> const& v) { this->x += static_cast(v.x); this->y += static_cast(v.y); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator-=(U scalar) { this->x -= static_cast(scalar); this->y -= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator-=(vec<1, U, Q> const& v) { this->x -= static_cast(v.x); this->y -= static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator-=(vec<2, U, Q> const& v) { this->x -= static_cast(v.x); this->y -= static_cast(v.y); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator*=(U scalar) { this->x *= static_cast(scalar); this->y *= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator*=(vec<1, U, Q> const& v) { this->x *= static_cast(v.x); this->y *= static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator*=(vec<2, U, Q> const& v) { this->x *= static_cast(v.x); this->y *= static_cast(v.y); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator/=(U scalar) { this->x /= static_cast(scalar); this->y /= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator/=(vec<1, U, Q> const& v) { this->x /= static_cast(v.x); this->y /= static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator/=(vec<2, U, Q> const& v) { this->x /= static_cast(v.x); this->y /= static_cast(v.y); return *this; } // -- Increment and decrement operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator++() { ++this->x; ++this->y; return *this; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator--() { --this->x; --this->y; return *this; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> vec<2, T, Q>::operator++(int) { vec<2, T, Q> Result(*this); ++*this; return Result; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> vec<2, T, Q>::operator--(int) { vec<2, T, Q> Result(*this); --*this; return Result; } // -- Unary bit operators -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator%=(U scalar) { this->x %= static_cast(scalar); this->y %= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator%=(vec<1, U, Q> const& v) { this->x %= static_cast(v.x); this->y %= static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator%=(vec<2, U, Q> const& v) { this->x %= static_cast(v.x); this->y %= static_cast(v.y); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator&=(U scalar) { this->x &= static_cast(scalar); this->y &= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator&=(vec<1, U, Q> const& v) { this->x &= static_cast(v.x); this->y &= static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator&=(vec<2, U, Q> const& v) { this->x &= static_cast(v.x); this->y &= static_cast(v.y); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator|=(U scalar) { this->x |= static_cast(scalar); this->y |= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator|=(vec<1, U, Q> const& v) { this->x |= static_cast(v.x); this->y |= static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator|=(vec<2, U, Q> const& v) { this->x |= static_cast(v.x); this->y |= static_cast(v.y); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator^=(U scalar) { this->x ^= static_cast(scalar); this->y ^= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator^=(vec<1, U, Q> const& v) { this->x ^= static_cast(v.x); this->y ^= static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator^=(vec<2, U, Q> const& v) { this->x ^= static_cast(v.x); this->y ^= static_cast(v.y); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator<<=(U scalar) { this->x <<= static_cast(scalar); this->y <<= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator<<=(vec<1, U, Q> const& v) { this->x <<= static_cast(v.x); this->y <<= static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator<<=(vec<2, U, Q> const& v) { this->x <<= static_cast(v.x); this->y <<= static_cast(v.y); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator>>=(U scalar) { this->x >>= static_cast(scalar); this->y >>= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator>>=(vec<1, U, Q> const& v) { this->x >>= static_cast(v.x); this->y >>= static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator>>=(vec<2, U, Q> const& v) { this->x >>= static_cast(v.x); this->y >>= static_cast(v.y); return *this; } // -- Unary arithmetic operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v) { return v; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v) { return vec<2, T, Q>( -v.x, -v.y); } // -- Binary arithmetic operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v, T scalar) { return vec<2, T, Q>( v.x + scalar, v.y + scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<2, T, Q>( v1.x + v2.x, v1.y + v2.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(T scalar, vec<2, T, Q> const& v) { return vec<2, T, Q>( scalar + v.x, scalar + v.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) { return vec<2, T, Q>( v1.x + v2.x, v1.x + v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) { return vec<2, T, Q>( v1.x + v2.x, v1.y + v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v, T scalar) { return vec<2, T, Q>( v.x - scalar, v.y - scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<2, T, Q>( v1.x - v2.x, v1.y - v2.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(T scalar, vec<2, T, Q> const& v) { return vec<2, T, Q>( scalar - v.x, scalar - v.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) { return vec<2, T, Q>( v1.x - v2.x, v1.x - v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) { return vec<2, T, Q>( v1.x - v2.x, v1.y - v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v, T scalar) { return vec<2, T, Q>( v.x * scalar, v.y * scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<2, T, Q>( v1.x * v2.x, v1.y * v2.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(T scalar, vec<2, T, Q> const& v) { return vec<2, T, Q>( scalar * v.x, scalar * v.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) { return vec<2, T, Q>( v1.x * v2.x, v1.x * v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) { return vec<2, T, Q>( v1.x * v2.x, v1.y * v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v, T scalar) { return vec<2, T, Q>( v.x / scalar, v.y / scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<2, T, Q>( v1.x / v2.x, v1.y / v2.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(T scalar, vec<2, T, Q> const& v) { return vec<2, T, Q>( scalar / v.x, scalar / v.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) { return vec<2, T, Q>( v1.x / v2.x, v1.x / v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) { return vec<2, T, Q>( v1.x / v2.x, v1.y / v2.y); } // -- Binary bit operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v, T scalar) { return vec<2, T, Q>( v.x % scalar, v.y % scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<2, T, Q>( v1.x % v2.x, v1.y % v2.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(T scalar, vec<2, T, Q> const& v) { return vec<2, T, Q>( scalar % v.x, scalar % v.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) { return vec<2, T, Q>( v1.x % v2.x, v1.x % v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) { return vec<2, T, Q>( v1.x % v2.x, v1.y % v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v, T scalar) { return vec<2, T, Q>( v.x & scalar, v.y & scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<2, T, Q>( v1.x & v2.x, v1.y & v2.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(T scalar, vec<2, T, Q> const& v) { return vec<2, T, Q>( scalar & v.x, scalar & v.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) { return vec<2, T, Q>( v1.x & v2.x, v1.x & v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) { return vec<2, T, Q>( v1.x & v2.x, v1.y & v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v, T scalar) { return vec<2, T, Q>( v.x | scalar, v.y | scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<2, T, Q>( v1.x | v2.x, v1.y | v2.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(T scalar, vec<2, T, Q> const& v) { return vec<2, T, Q>( scalar | v.x, scalar | v.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) { return vec<2, T, Q>( v1.x | v2.x, v1.x | v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) { return vec<2, T, Q>( v1.x | v2.x, v1.y | v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v, T scalar) { return vec<2, T, Q>( v.x ^ scalar, v.y ^ scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<2, T, Q>( v1.x ^ v2.x, v1.y ^ v2.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(T scalar, vec<2, T, Q> const& v) { return vec<2, T, Q>( scalar ^ v.x, scalar ^ v.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) { return vec<2, T, Q>( v1.x ^ v2.x, v1.x ^ v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) { return vec<2, T, Q>( v1.x ^ v2.x, v1.y ^ v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v, T scalar) { return vec<2, T, Q>( v.x << scalar, v.y << scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<2, T, Q>( v1.x << v2.x, v1.y << v2.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(T scalar, vec<2, T, Q> const& v) { return vec<2, T, Q>( scalar << v.x, scalar << v.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) { return vec<2, T, Q>( v1.x << v2.x, v1.x << v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) { return vec<2, T, Q>( v1.x << v2.x, v1.y << v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v, T scalar) { return vec<2, T, Q>( v.x >> scalar, v.y >> scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<2, T, Q>( v1.x >> v2.x, v1.y >> v2.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(T scalar, vec<2, T, Q> const& v) { return vec<2, T, Q>( scalar >> v.x, scalar >> v.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2) { return vec<2, T, Q>( v1.x >> v2.x, v1.x >> v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) { return vec<2, T, Q>( v1.x >> v2.x, v1.y >> v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator~(vec<2, T, Q> const& v) { return vec<2, T, Q>( ~v.x, ~v.y); } // -- Boolean operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) { return detail::compute_equal::is_iec559>::call(v1.x, v2.x) && detail::compute_equal::is_iec559>::call(v1.y, v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2) { return !(v1 == v2); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, bool, Q> operator&&(vec<2, bool, Q> const& v1, vec<2, bool, Q> const& v2) { return vec<2, bool, Q>(v1.x && v2.x, v1.y && v2.y); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, bool, Q> operator||(vec<2, bool, Q> const& v1, vec<2, bool, Q> const& v2) { return vec<2, bool, Q>(v1.x || v2.x, v1.y || v2.y); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/type_vec3.hpp000066400000000000000000000430771360521144700242040ustar00rootroot00000000000000/// @ref core /// @file glm/detail/type_vec3.hpp #pragma once #include "qualifier.hpp" #if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR # include "_swizzle.hpp" #elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION # include "_swizzle_func.hpp" #endif #include namespace glm { template struct vec<3, T, Q> { // -- Implementation detail -- typedef T value_type; typedef vec<3, T, Q> type; typedef vec<3, bool, Q> bool_type; // -- Data -- # if GLM_SILENT_WARNINGS == GLM_ENABLE # if GLM_COMPILER & GLM_COMPILER_GCC # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpedantic" # elif GLM_COMPILER & GLM_COMPILER_CLANG # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wgnu-anonymous-struct" # pragma clang diagnostic ignored "-Wnested-anon-types" # elif GLM_COMPILER & GLM_COMPILER_VC # pragma warning(push) # pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union # if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE # pragma warning(disable: 4324) // structure was padded due to alignment specifier # endif # endif # endif # if GLM_CONFIG_XYZW_ONLY T x, y, z; # elif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE union { struct{ T x, y, z; }; struct{ T r, g, b; }; struct{ T s, t, p; }; typename detail::storage<3, T, detail::is_aligned::value>::type data; # if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR GLM_SWIZZLE3_2_MEMBERS(T, Q, x, y, z) GLM_SWIZZLE3_2_MEMBERS(T, Q, r, g, b) GLM_SWIZZLE3_2_MEMBERS(T, Q, s, t, p) GLM_SWIZZLE3_3_MEMBERS(T, Q, x, y, z) GLM_SWIZZLE3_3_MEMBERS(T, Q, r, g, b) GLM_SWIZZLE3_3_MEMBERS(T, Q, s, t, p) GLM_SWIZZLE3_4_MEMBERS(T, Q, x, y, z) GLM_SWIZZLE3_4_MEMBERS(T, Q, r, g, b) GLM_SWIZZLE3_4_MEMBERS(T, Q, s, t, p) # endif }; # else union { T x, r, s; }; union { T y, g, t; }; union { T z, b, p; }; # if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION GLM_SWIZZLE_GEN_VEC_FROM_VEC3(T, Q) # endif//GLM_CONFIG_SWIZZLE # endif//GLM_LANG # if GLM_SILENT_WARNINGS == GLM_ENABLE # if GLM_COMPILER & GLM_COMPILER_CLANG # pragma clang diagnostic pop # elif GLM_COMPILER & GLM_COMPILER_GCC # pragma GCC diagnostic pop # elif GLM_COMPILER & GLM_COMPILER_VC # pragma warning(pop) # endif # endif // -- Component accesses -- /// Return the count of components of the vector typedef length_t length_type; GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 3;} GLM_FUNC_DECL GLM_CONSTEXPR T & operator[](length_type i); GLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const; // -- Implicit basic constructors -- GLM_FUNC_DECL GLM_CONSTEXPR vec() GLM_DEFAULT; GLM_FUNC_DECL GLM_CONSTEXPR vec(vec const& v) GLM_DEFAULT; template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<3, T, P> const& v); // -- Explicit basic constructors -- GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(T scalar); GLM_FUNC_DECL GLM_CONSTEXPR vec(T a, T b, T c); // -- Conversion scalar constructors -- template GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(vec<1, U, P> const& v); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(X x, Y y, Z z); template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, Z _z); template GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, Z _z); template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z); template GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, Y _y, vec<1, Z, Q> const& _z); template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z); template GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z); template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z); // -- Conversion vector constructors -- /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, B _z); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<2, B, P> const& _yz); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<4, U, P> const& v); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<3, U, P> const& v); // -- Swizzle constructors -- # if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR template GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<3, T, Q, E0, E1, E2, -1> const& that) { *this = that(); } template GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v, T const& scalar) { *this = vec(v(), scalar); } template GLM_FUNC_DECL GLM_CONSTEXPR vec(T const& scalar, detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v) { *this = vec(scalar, v()); } # endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR // -- Unary arithmetic operators -- GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q>& operator=(vec<3, T, Q> const& v) GLM_DEFAULT; template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator=(vec<3, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator+=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator+=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator+=(vec<3, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator-=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator-=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator-=(vec<3, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator*=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator*=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator*=(vec<3, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator/=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator/=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator/=(vec<3, U, Q> const& v); // -- Increment and decrement operators -- GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator++(); GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator--(); GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator++(int); GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator--(int); // -- Unary bit operators -- template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator%=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator%=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator%=(vec<3, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator&=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator&=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator&=(vec<3, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator|=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator|=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator|=(vec<3, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator^=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator^=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator^=(vec<3, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator<<=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator<<=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator<<=(vec<3, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator>>=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator>>=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator>>=(vec<3, U, Q> const& v); }; // -- Unary operators -- template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v); // -- Binary operators -- template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(T scalar, vec<3, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(T scalar, vec<3, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(T scalar, vec<3, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(T scalar, vec<3, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(T scalar, vec<3, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v1, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(T scalar, vec<3, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(T scalar, vec<3, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(T scalar, vec<3, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(T scalar, vec<3, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(T scalar, vec<3, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator~(vec<3, T, Q> const& v); // -- Boolean operators -- template GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, bool, Q> operator&&(vec<3, bool, Q> const& v1, vec<3, bool, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<3, bool, Q> operator||(vec<3, bool, Q> const& v1, vec<3, bool, Q> const& v2); }//namespace glm #ifndef GLM_EXTERNAL_TEMPLATE #include "type_vec3.inl" #endif//GLM_EXTERNAL_TEMPLATE connectome-workbench-1.4.2/src/GLMath/glm/detail/type_vec3.inl000066400000000000000000000671651360521144700242030ustar00rootroot00000000000000/// @ref core #include "compute_vector_relational.hpp" namespace glm { // -- Implicit basic constructors -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec() # if GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE : x(0), y(0), z(0) # endif {} template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<3, T, Q> const& v) : x(v.x), y(v.y), z(v.z) {} # endif template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<3, T, P> const& v) : x(v.x), y(v.y), z(v.z) {} // -- Explicit basic constructors -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(T scalar) : x(scalar), y(scalar), z(scalar) {} template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(T _x, T _y, T _z) : x(_x), y(_y), z(_z) {} // -- Conversion scalar constructors -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, U, P> const& v) : x(static_cast(v.x)) , y(static_cast(v.x)) , z(static_cast(v.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(X _x, Y _y, Z _z) : x(static_cast(_x)) , y(static_cast(_y)) , z(static_cast(_z)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, Z _z) : x(static_cast(_x.x)) , y(static_cast(_y)) , z(static_cast(_z)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, Z _z) : x(static_cast(_x)) , y(static_cast(_y.x)) , z(static_cast(_z)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z) : x(static_cast(_x.x)) , y(static_cast(_y.x)) , z(static_cast(_z)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(X _x, Y _y, vec<1, Z, Q> const& _z) : x(static_cast(_x)) , y(static_cast(_y)) , z(static_cast(_z.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z) : x(static_cast(_x.x)) , y(static_cast(_y)) , z(static_cast(_z.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z) : x(static_cast(_x)) , y(static_cast(_y.x)) , z(static_cast(_z.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z) : x(static_cast(_x.x)) , y(static_cast(_y.x)) , z(static_cast(_z.x)) {} // -- Conversion vector constructors -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<2, A, P> const& _xy, B _z) : x(static_cast(_xy.x)) , y(static_cast(_xy.y)) , z(static_cast(_z)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z) : x(static_cast(_xy.x)) , y(static_cast(_xy.y)) , z(static_cast(_z.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(A _x, vec<2, B, P> const& _yz) : x(static_cast(_x)) , y(static_cast(_yz.x)) , z(static_cast(_yz.y)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz) : x(static_cast(_x.x)) , y(static_cast(_yz.x)) , z(static_cast(_yz.y)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<3, U, P> const& v) : x(static_cast(v.x)) , y(static_cast(v.y)) , z(static_cast(v.z)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<4, U, P> const& v) : x(static_cast(v.x)) , y(static_cast(v.y)) , z(static_cast(v.z)) {} // -- Component accesses -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR T & vec<3, T, Q>::operator[](typename vec<3, T, Q>::length_type i) { assert(i >= 0 && i < this->length()); switch(i) { default: case 0: return x; case 1: return y; case 2: return z; } } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& vec<3, T, Q>::operator[](typename vec<3, T, Q>::length_type i) const { assert(i >= 0 && i < this->length()); switch(i) { default: case 0: return x; case 1: return y; case 2: return z; } } // -- Unary arithmetic operators -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>& vec<3, T, Q>::operator=(vec<3, T, Q> const& v) { this->x = v.x; this->y = v.y; this->z = v.z; return *this; } # endif template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>& vec<3, T, Q>::operator=(vec<3, U, Q> const& v) { this->x = static_cast(v.x); this->y = static_cast(v.y); this->z = static_cast(v.z); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator+=(U scalar) { this->x += static_cast(scalar); this->y += static_cast(scalar); this->z += static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator+=(vec<1, U, Q> const& v) { this->x += static_cast(v.x); this->y += static_cast(v.x); this->z += static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator+=(vec<3, U, Q> const& v) { this->x += static_cast(v.x); this->y += static_cast(v.y); this->z += static_cast(v.z); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator-=(U scalar) { this->x -= static_cast(scalar); this->y -= static_cast(scalar); this->z -= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator-=(vec<1, U, Q> const& v) { this->x -= static_cast(v.x); this->y -= static_cast(v.x); this->z -= static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator-=(vec<3, U, Q> const& v) { this->x -= static_cast(v.x); this->y -= static_cast(v.y); this->z -= static_cast(v.z); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator*=(U scalar) { this->x *= static_cast(scalar); this->y *= static_cast(scalar); this->z *= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator*=(vec<1, U, Q> const& v) { this->x *= static_cast(v.x); this->y *= static_cast(v.x); this->z *= static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator*=(vec<3, U, Q> const& v) { this->x *= static_cast(v.x); this->y *= static_cast(v.y); this->z *= static_cast(v.z); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator/=(U v) { this->x /= static_cast(v); this->y /= static_cast(v); this->z /= static_cast(v); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator/=(vec<1, U, Q> const& v) { this->x /= static_cast(v.x); this->y /= static_cast(v.x); this->z /= static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator/=(vec<3, U, Q> const& v) { this->x /= static_cast(v.x); this->y /= static_cast(v.y); this->z /= static_cast(v.z); return *this; } // -- Increment and decrement operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator++() { ++this->x; ++this->y; ++this->z; return *this; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator--() { --this->x; --this->y; --this->z; return *this; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> vec<3, T, Q>::operator++(int) { vec<3, T, Q> Result(*this); ++*this; return Result; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> vec<3, T, Q>::operator--(int) { vec<3, T, Q> Result(*this); --*this; return Result; } // -- Unary bit operators -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator%=(U scalar) { this->x %= scalar; this->y %= scalar; this->z %= scalar; return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator%=(vec<1, U, Q> const& v) { this->x %= v.x; this->y %= v.x; this->z %= v.x; return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator%=(vec<3, U, Q> const& v) { this->x %= v.x; this->y %= v.y; this->z %= v.z; return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator&=(U scalar) { this->x &= scalar; this->y &= scalar; this->z &= scalar; return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator&=(vec<1, U, Q> const& v) { this->x &= v.x; this->y &= v.x; this->z &= v.x; return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator&=(vec<3, U, Q> const& v) { this->x &= v.x; this->y &= v.y; this->z &= v.z; return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator|=(U scalar) { this->x |= scalar; this->y |= scalar; this->z |= scalar; return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator|=(vec<1, U, Q> const& v) { this->x |= v.x; this->y |= v.x; this->z |= v.x; return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator|=(vec<3, U, Q> const& v) { this->x |= v.x; this->y |= v.y; this->z |= v.z; return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator^=(U scalar) { this->x ^= scalar; this->y ^= scalar; this->z ^= scalar; return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator^=(vec<1, U, Q> const& v) { this->x ^= v.x; this->y ^= v.x; this->z ^= v.x; return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator^=(vec<3, U, Q> const& v) { this->x ^= v.x; this->y ^= v.y; this->z ^= v.z; return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator<<=(U scalar) { this->x <<= scalar; this->y <<= scalar; this->z <<= scalar; return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator<<=(vec<1, U, Q> const& v) { this->x <<= static_cast(v.x); this->y <<= static_cast(v.x); this->z <<= static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator<<=(vec<3, U, Q> const& v) { this->x <<= static_cast(v.x); this->y <<= static_cast(v.y); this->z <<= static_cast(v.z); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator>>=(U scalar) { this->x >>= static_cast(scalar); this->y >>= static_cast(scalar); this->z >>= static_cast(scalar); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator>>=(vec<1, U, Q> const& v) { this->x >>= static_cast(v.x); this->y >>= static_cast(v.x); this->z >>= static_cast(v.x); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator>>=(vec<3, U, Q> const& v) { this->x >>= static_cast(v.x); this->y >>= static_cast(v.y); this->z >>= static_cast(v.z); return *this; } // -- Unary arithmetic operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v) { return v; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v) { return vec<3, T, Q>( -v.x, -v.y, -v.z); } // -- Binary arithmetic operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v, T scalar) { return vec<3, T, Q>( v.x + scalar, v.y + scalar, v.z + scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) { return vec<3, T, Q>( v.x + scalar.x, v.y + scalar.x, v.z + scalar.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(T scalar, vec<3, T, Q> const& v) { return vec<3, T, Q>( scalar + v.x, scalar + v.y, scalar + v.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) { return vec<3, T, Q>( scalar.x + v.x, scalar.x + v.y, scalar.x + v.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) { return vec<3, T, Q>( v1.x + v2.x, v1.y + v2.y, v1.z + v2.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v, T scalar) { return vec<3, T, Q>( v.x - scalar, v.y - scalar, v.z - scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) { return vec<3, T, Q>( v.x - scalar.x, v.y - scalar.x, v.z - scalar.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(T scalar, vec<3, T, Q> const& v) { return vec<3, T, Q>( scalar - v.x, scalar - v.y, scalar - v.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) { return vec<3, T, Q>( scalar.x - v.x, scalar.x - v.y, scalar.x - v.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) { return vec<3, T, Q>( v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, T scalar) { return vec<3, T, Q>( v.x * scalar, v.y * scalar, v.z * scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) { return vec<3, T, Q>( v.x * scalar.x, v.y * scalar.x, v.z * scalar.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(T scalar, vec<3, T, Q> const& v) { return vec<3, T, Q>( scalar * v.x, scalar * v.y, scalar * v.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) { return vec<3, T, Q>( scalar.x * v.x, scalar.x * v.y, scalar.x * v.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) { return vec<3, T, Q>( v1.x * v2.x, v1.y * v2.y, v1.z * v2.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v, T scalar) { return vec<3, T, Q>( v.x / scalar, v.y / scalar, v.z / scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) { return vec<3, T, Q>( v.x / scalar.x, v.y / scalar.x, v.z / scalar.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(T scalar, vec<3, T, Q> const& v) { return vec<3, T, Q>( scalar / v.x, scalar / v.y, scalar / v.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) { return vec<3, T, Q>( scalar.x / v.x, scalar.x / v.y, scalar.x / v.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) { return vec<3, T, Q>( v1.x / v2.x, v1.y / v2.y, v1.z / v2.z); } // -- Binary bit operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v, T scalar) { return vec<3, T, Q>( v.x % scalar, v.y % scalar, v.z % scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) { return vec<3, T, Q>( v.x % scalar.x, v.y % scalar.x, v.z % scalar.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(T scalar, vec<3, T, Q> const& v) { return vec<3, T, Q>( scalar % v.x, scalar % v.y, scalar % v.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) { return vec<3, T, Q>( scalar.x % v.x, scalar.x % v.y, scalar.x % v.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) { return vec<3, T, Q>( v1.x % v2.x, v1.y % v2.y, v1.z % v2.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v, T scalar) { return vec<3, T, Q>( v.x & scalar, v.y & scalar, v.z & scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) { return vec<3, T, Q>( v.x & scalar.x, v.y & scalar.x, v.z & scalar.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(T scalar, vec<3, T, Q> const& v) { return vec<3, T, Q>( scalar & v.x, scalar & v.y, scalar & v.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) { return vec<3, T, Q>( scalar.x & v.x, scalar.x & v.y, scalar.x & v.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) { return vec<3, T, Q>( v1.x & v2.x, v1.y & v2.y, v1.z & v2.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v, T scalar) { return vec<3, T, Q>( v.x | scalar, v.y | scalar, v.z | scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) { return vec<3, T, Q>( v.x | scalar.x, v.y | scalar.x, v.z | scalar.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(T scalar, vec<3, T, Q> const& v) { return vec<3, T, Q>( scalar | v.x, scalar | v.y, scalar | v.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) { return vec<3, T, Q>( scalar.x | v.x, scalar.x | v.y, scalar.x | v.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) { return vec<3, T, Q>( v1.x | v2.x, v1.y | v2.y, v1.z | v2.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v, T scalar) { return vec<3, T, Q>( v.x ^ scalar, v.y ^ scalar, v.z ^ scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) { return vec<3, T, Q>( v.x ^ scalar.x, v.y ^ scalar.x, v.z ^ scalar.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(T scalar, vec<3, T, Q> const& v) { return vec<3, T, Q>( scalar ^ v.x, scalar ^ v.y, scalar ^ v.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) { return vec<3, T, Q>( scalar.x ^ v.x, scalar.x ^ v.y, scalar.x ^ v.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) { return vec<3, T, Q>( v1.x ^ v2.x, v1.y ^ v2.y, v1.z ^ v2.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v, T scalar) { return vec<3, T, Q>( v.x << scalar, v.y << scalar, v.z << scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) { return vec<3, T, Q>( v.x << scalar.x, v.y << scalar.x, v.z << scalar.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(T scalar, vec<3, T, Q> const& v) { return vec<3, T, Q>( scalar << v.x, scalar << v.y, scalar << v.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) { return vec<3, T, Q>( scalar.x << v.x, scalar.x << v.y, scalar.x << v.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) { return vec<3, T, Q>( v1.x << v2.x, v1.y << v2.y, v1.z << v2.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v, T scalar) { return vec<3, T, Q>( v.x >> scalar, v.y >> scalar, v.z >> scalar); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar) { return vec<3, T, Q>( v.x >> scalar.x, v.y >> scalar.x, v.z >> scalar.x); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(T scalar, vec<3, T, Q> const& v) { return vec<3, T, Q>( scalar >> v.x, scalar >> v.y, scalar >> v.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v) { return vec<3, T, Q>( scalar.x >> v.x, scalar.x >> v.y, scalar.x >> v.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) { return vec<3, T, Q>( v1.x >> v2.x, v1.y >> v2.y, v1.z >> v2.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator~(vec<3, T, Q> const& v) { return vec<3, T, Q>( ~v.x, ~v.y, ~v.z); } // -- Boolean operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) { return detail::compute_equal::is_iec559>::call(v1.x, v2.x) && detail::compute_equal::is_iec559>::call(v1.y, v2.y) && detail::compute_equal::is_iec559>::call(v1.z, v2.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2) { return !(v1 == v2); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, bool, Q> operator&&(vec<3, bool, Q> const& v1, vec<3, bool, Q> const& v2) { return vec<3, bool, Q>(v1.x && v2.x, v1.y && v2.y, v1.z && v2.z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, bool, Q> operator||(vec<3, bool, Q> const& v1, vec<3, bool, Q> const& v2) { return vec<3, bool, Q>(v1.x || v2.x, v1.y || v2.y, v1.z || v2.z); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/detail/type_vec4.hpp000066400000000000000000000554341360521144700242050ustar00rootroot00000000000000/// @ref core /// @file glm/detail/type_vec4.hpp #pragma once #include "qualifier.hpp" #if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR # include "_swizzle.hpp" #elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION # include "_swizzle_func.hpp" #endif #include namespace glm { template struct vec<4, T, Q> { // -- Implementation detail -- typedef T value_type; typedef vec<4, T, Q> type; typedef vec<4, bool, Q> bool_type; // -- Data -- # if GLM_SILENT_WARNINGS == GLM_ENABLE # if GLM_COMPILER & GLM_COMPILER_GCC # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpedantic" # elif GLM_COMPILER & GLM_COMPILER_CLANG # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wgnu-anonymous-struct" # pragma clang diagnostic ignored "-Wnested-anon-types" # elif GLM_COMPILER & GLM_COMPILER_VC # pragma warning(push) # pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union # endif # endif # if GLM_CONFIG_XYZW_ONLY T x, y, z, w; # elif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE union { struct { T x, y, z, w; }; struct { T r, g, b, a; }; struct { T s, t, p, q; }; typename detail::storage<4, T, detail::is_aligned::value>::type data; # if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR GLM_SWIZZLE4_2_MEMBERS(T, Q, x, y, z, w) GLM_SWIZZLE4_2_MEMBERS(T, Q, r, g, b, a) GLM_SWIZZLE4_2_MEMBERS(T, Q, s, t, p, q) GLM_SWIZZLE4_3_MEMBERS(T, Q, x, y, z, w) GLM_SWIZZLE4_3_MEMBERS(T, Q, r, g, b, a) GLM_SWIZZLE4_3_MEMBERS(T, Q, s, t, p, q) GLM_SWIZZLE4_4_MEMBERS(T, Q, x, y, z, w) GLM_SWIZZLE4_4_MEMBERS(T, Q, r, g, b, a) GLM_SWIZZLE4_4_MEMBERS(T, Q, s, t, p, q) # endif }; # else union { T x, r, s; }; union { T y, g, t; }; union { T z, b, p; }; union { T w, a, q; }; # if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION GLM_SWIZZLE_GEN_VEC_FROM_VEC4(T, Q) # endif # endif # if GLM_SILENT_WARNINGS == GLM_ENABLE # if GLM_COMPILER & GLM_COMPILER_CLANG # pragma clang diagnostic pop # elif GLM_COMPILER & GLM_COMPILER_GCC # pragma GCC diagnostic pop # elif GLM_COMPILER & GLM_COMPILER_VC # pragma warning(pop) # endif # endif // -- Component accesses -- typedef length_t length_type; /// Return the count of components of the vector GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 4;} GLM_FUNC_DECL GLM_CONSTEXPR T & operator[](length_type i); GLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const; // -- Implicit basic constructors -- GLM_FUNC_DECL GLM_CONSTEXPR vec() GLM_DEFAULT; GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<4, T, Q> const& v) GLM_DEFAULT; template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<4, T, P> const& v); // -- Explicit basic constructors -- GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(T scalar); GLM_FUNC_DECL GLM_CONSTEXPR vec(T x, T y, T z, T w); // -- Conversion scalar constructors -- template GLM_FUNC_DECL GLM_CONSTEXPR explicit vec(vec<1, U, P> const& v); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, Y _y, Z _z, W _w); template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, Z _z, W _w); template GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, Z _z, W _w); template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z, W _w); template GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, Y _y, vec<1, Z, Q> const& _z, W _w); template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z, W _w); template GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, W _w); template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, W _w); template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, Z _z, vec<1, W, Q> const& _w); template GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, Z _z, vec<1, W, Q> const& _w); template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z, vec<1, W, Q> const& _w); template GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, Y _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w); template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w); template GLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w); template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _Y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w); // -- Conversion vector constructors -- /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, B _z, C _w); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z, C _w); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, B _z, vec<1, C, P> const& _w); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z, vec<1, C, P> const& _w); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<2, B, P> const& _yz, C _w); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz, C _w); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<2, B, P> const& _yz, vec<1, C, P> const& _w); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz, vec<1, C, P> const& _w); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, B _y, vec<2, C, P> const& _zw); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, B _y, vec<2, C, P> const& _zw); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<1, B, P> const& _y, vec<2, C, P> const& _zw); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<1, B, P> const& _y, vec<2, C, P> const& _zw); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<3, A, P> const& _xyz, B _w); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<3, A, P> const& _xyz, vec<1, B, P> const& _w); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<3, B, P> const& _yzw); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<3, B, P> const& _yzw); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, vec<2, B, P> const& _zw); /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification) template GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<4, U, P> const& v); // -- Swizzle constructors -- # if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR template GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<4, T, Q, E0, E1, E2, E3> const& that) { *this = that(); } template GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v, detail::_swizzle<2, T, Q, F0, F1, -1, -2> const& u) { *this = vec<4, T, Q>(v(), u()); } template GLM_FUNC_DECL GLM_CONSTEXPR vec(T const& x, T const& y, detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v) { *this = vec<4, T, Q>(x, y, v()); } template GLM_FUNC_DECL GLM_CONSTEXPR vec(T const& x, detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v, T const& w) { *this = vec<4, T, Q>(x, v(), w); } template GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v, T const& z, T const& w) { *this = vec<4, T, Q>(v(), z, w); } template GLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<3, T, Q, E0, E1, E2, -1> const& v, T const& w) { *this = vec<4, T, Q>(v(), w); } template GLM_FUNC_DECL GLM_CONSTEXPR vec(T const& x, detail::_swizzle<3, T, Q, E0, E1, E2, -1> const& v) { *this = vec<4, T, Q>(x, v()); } # endif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR // -- Unary arithmetic operators -- GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator=(vec<4, T, Q> const& v) GLM_DEFAULT; template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator=(vec<4, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator+=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator+=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator+=(vec<4, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator-=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator-=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator-=(vec<4, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator*=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator*=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator*=(vec<4, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator/=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator/=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator/=(vec<4, U, Q> const& v); // -- Increment and decrement operators -- GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator++(); GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator--(); GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator++(int); GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator--(int); // -- Unary bit operators -- template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator%=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator%=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator%=(vec<4, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator&=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator&=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator&=(vec<4, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator|=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator|=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator|=(vec<4, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator^=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator^=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator^=(vec<4, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator<<=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator<<=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator<<=(vec<4, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator>>=(U scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator>>=(vec<1, U, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator>>=(vec<4, U, Q> const& v); }; // -- Unary operators -- template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v); // -- Binary operators -- template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v, T const & scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(T scalar, vec<4, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v, T const & scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(T scalar, vec<4, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v, T const & scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(T scalar, vec<4, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v, T const & scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(T scalar, vec<4, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(T scalar, vec<4, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(T scalar, vec<4, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(T scalar, vec<4, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(T scalar, vec<4, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(T scalar, vec<4, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v, T scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(T scalar, vec<4, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator~(vec<4, T, Q> const& v); // -- Boolean operators -- template GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, bool, Q> operator&&(vec<4, bool, Q> const& v1, vec<4, bool, Q> const& v2); template GLM_FUNC_DECL GLM_CONSTEXPR vec<4, bool, Q> operator||(vec<4, bool, Q> const& v1, vec<4, bool, Q> const& v2); }//namespace glm #ifndef GLM_EXTERNAL_TEMPLATE #include "type_vec4.inl" #endif//GLM_EXTERNAL_TEMPLATE connectome-workbench-1.4.2/src/GLMath/glm/detail/type_vec4.inl000066400000000000000000001126611360521144700241740ustar00rootroot00000000000000/// @ref core #include "compute_vector_relational.hpp" namespace glm{ namespace detail { template struct compute_vec4_add { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { return vec<4, T, Q>(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); } }; template struct compute_vec4_sub { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { return vec<4, T, Q>(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); } }; template struct compute_vec4_mul { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { return vec<4, T, Q>(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); } }; template struct compute_vec4_div { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { return vec<4, T, Q>(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); } }; template struct compute_vec4_mod { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { return vec<4, T, Q>(a.x % b.x, a.y % b.y, a.z % b.z, a.w % b.w); } }; template struct compute_vec4_and { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { return vec<4, T, Q>(a.x & b.x, a.y & b.y, a.z & b.z, a.w & b.w); } }; template struct compute_vec4_or { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { return vec<4, T, Q>(a.x | b.x, a.y | b.y, a.z | b.z, a.w | b.w); } }; template struct compute_vec4_xor { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { return vec<4, T, Q>(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w); } }; template struct compute_vec4_shift_left { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { return vec<4, T, Q>(a.x << b.x, a.y << b.y, a.z << b.z, a.w << b.w); } }; template struct compute_vec4_shift_right { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { return vec<4, T, Q>(a.x >> b.x, a.y >> b.y, a.z >> b.z, a.w >> b.w); } }; template struct compute_vec4_equal { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static bool call(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) { return detail::compute_equal::is_iec559>::call(v1.x, v2.x) && detail::compute_equal::is_iec559>::call(v1.y, v2.y) && detail::compute_equal::is_iec559>::call(v1.z, v2.z) && detail::compute_equal::is_iec559>::call(v1.w, v2.w); } }; template struct compute_vec4_nequal { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static bool call(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) { return !compute_vec4_equal::value, sizeof(T) * 8, detail::is_aligned::value>::call(v1, v2); } }; template struct compute_vec4_bitwise_not { GLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& v) { return vec<4, T, Q>(~v.x, ~v.y, ~v.z, ~v.w); } }; }//namespace detail // -- Implicit basic constructors -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec() # if GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE : x(0), y(0), z(0), w(0) # endif {} template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<4, T, Q> const& v) : x(v.x), y(v.y), z(v.z), w(v.w) {} # endif template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<4, T, P> const& v) : x(v.x), y(v.y), z(v.z), w(v.w) {} // -- Explicit basic constructors -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(T scalar) : x(scalar), y(scalar), z(scalar), w(scalar) {} template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(T _x, T _y, T _z, T _w) : x(_x), y(_y), z(_z), w(_w) {} // -- Conversion scalar constructors -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, U, P> const& v) : x(static_cast(v.x)) , y(static_cast(v.x)) , z(static_cast(v.x)) , w(static_cast(v.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, Y _y, Z _z, W _w) : x(static_cast(_x)) , y(static_cast(_y)) , z(static_cast(_z)) , w(static_cast(_w)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, Z _z, W _w) : x(static_cast(_x.x)) , y(static_cast(_y)) , z(static_cast(_z)) , w(static_cast(_w)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, Z _z, W _w) : x(static_cast(_x)) , y(static_cast(_y.x)) , z(static_cast(_z)) , w(static_cast(_w)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z, W _w) : x(static_cast(_x.x)) , y(static_cast(_y.x)) , z(static_cast(_z)) , w(static_cast(_w)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, Y _y, vec<1, Z, Q> const& _z, W _w) : x(static_cast(_x)) , y(static_cast(_y)) , z(static_cast(_z.x)) , w(static_cast(_w)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z, W _w) : x(static_cast(_x.x)) , y(static_cast(_y)) , z(static_cast(_z.x)) , w(static_cast(_w)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, W _w) : x(static_cast(_x)) , y(static_cast(_y.x)) , z(static_cast(_z.x)) , w(static_cast(_w)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, W _w) : x(static_cast(_x.x)) , y(static_cast(_y.x)) , z(static_cast(_z.x)) , w(static_cast(_w)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, Z _z, vec<1, W, Q> const& _w) : x(static_cast(_x.x)) , y(static_cast(_y)) , z(static_cast(_z)) , w(static_cast(_w.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, Z _z, vec<1, W, Q> const& _w) : x(static_cast(_x)) , y(static_cast(_y.x)) , z(static_cast(_z)) , w(static_cast(_w.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z, vec<1, W, Q> const& _w) : x(static_cast(_x.x)) , y(static_cast(_y.x)) , z(static_cast(_z)) , w(static_cast(_w.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, Y _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w) : x(static_cast(_x)) , y(static_cast(_y)) , z(static_cast(_z.x)) , w(static_cast(_w.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w) : x(static_cast(_x.x)) , y(static_cast(_y)) , z(static_cast(_z.x)) , w(static_cast(_w.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w) : x(static_cast(_x)) , y(static_cast(_y.x)) , z(static_cast(_z.x)) , w(static_cast(_w.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w) : x(static_cast(_x.x)) , y(static_cast(_y.x)) , z(static_cast(_z.x)) , w(static_cast(_w.x)) {} // -- Conversion vector constructors -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, B _z, C _w) : x(static_cast(_xy.x)) , y(static_cast(_xy.y)) , z(static_cast(_z)) , w(static_cast(_w)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z, C _w) : x(static_cast(_xy.x)) , y(static_cast(_xy.y)) , z(static_cast(_z.x)) , w(static_cast(_w)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, B _z, vec<1, C, P> const& _w) : x(static_cast(_xy.x)) , y(static_cast(_xy.y)) , z(static_cast(_z)) , w(static_cast(_w.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z, vec<1, C, P> const& _w) : x(static_cast(_xy.x)) , y(static_cast(_xy.y)) , z(static_cast(_z.x)) , w(static_cast(_w.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, vec<2, B, P> const& _yz, C _w) : x(static_cast(_x)) , y(static_cast(_yz.x)) , z(static_cast(_yz.y)) , w(static_cast(_w)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz, C _w) : x(static_cast(_x.x)) , y(static_cast(_yz.x)) , z(static_cast(_yz.y)) , w(static_cast(_w)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, vec<2, B, P> const& _yz, vec<1, C, P> const& _w) : x(static_cast(_x)) , y(static_cast(_yz.x)) , z(static_cast(_yz.y)) , w(static_cast(_w.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz, vec<1, C, P> const& _w) : x(static_cast(_x.x)) , y(static_cast(_yz.x)) , z(static_cast(_yz.y)) , w(static_cast(_w.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, B _y, vec<2, C, P> const& _zw) : x(static_cast(_x)) , y(static_cast(_y)) , z(static_cast(_zw.x)) , w(static_cast(_zw.y)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, B _y, vec<2, C, P> const& _zw) : x(static_cast(_x.x)) , y(static_cast(_y)) , z(static_cast(_zw.x)) , w(static_cast(_zw.y)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, vec<1, B, P> const& _y, vec<2, C, P> const& _zw) : x(static_cast(_x)) , y(static_cast(_y.x)) , z(static_cast(_zw.x)) , w(static_cast(_zw.y)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, vec<1, B, P> const& _y, vec<2, C, P> const& _zw) : x(static_cast(_x.x)) , y(static_cast(_y.x)) , z(static_cast(_zw.x)) , w(static_cast(_zw.y)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<3, A, P> const& _xyz, B _w) : x(static_cast(_xyz.x)) , y(static_cast(_xyz.y)) , z(static_cast(_xyz.z)) , w(static_cast(_w)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<3, A, P> const& _xyz, vec<1, B, P> const& _w) : x(static_cast(_xyz.x)) , y(static_cast(_xyz.y)) , z(static_cast(_xyz.z)) , w(static_cast(_w.x)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, vec<3, B, P> const& _yzw) : x(static_cast(_x)) , y(static_cast(_yzw.x)) , z(static_cast(_yzw.y)) , w(static_cast(_yzw.z)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, vec<3, B, P> const& _yzw) : x(static_cast(_x.x)) , y(static_cast(_yzw.x)) , z(static_cast(_yzw.y)) , w(static_cast(_yzw.z)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, vec<2, B, P> const& _zw) : x(static_cast(_xy.x)) , y(static_cast(_xy.y)) , z(static_cast(_zw.x)) , w(static_cast(_zw.y)) {} template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<4, U, P> const& v) : x(static_cast(v.x)) , y(static_cast(v.y)) , z(static_cast(v.z)) , w(static_cast(v.w)) {} // -- Component accesses -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR T& vec<4, T, Q>::operator[](typename vec<4, T, Q>::length_type i) { assert(i >= 0 && i < this->length()); switch(i) { default: case 0: return x; case 1: return y; case 2: return z; case 3: return w; } } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& vec<4, T, Q>::operator[](typename vec<4, T, Q>::length_type i) const { assert(i >= 0 && i < this->length()); switch(i) { default: case 0: return x; case 1: return y; case 2: return z; case 3: return w; } } // -- Unary arithmetic operators -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>& vec<4, T, Q>::operator=(vec<4, T, Q> const& v) { this->x = v.x; this->y = v.y; this->z = v.z; this->w = v.w; return *this; } # endif template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>& vec<4, T, Q>::operator=(vec<4, U, Q> const& v) { this->x = static_cast(v.x); this->y = static_cast(v.y); this->z = static_cast(v.z); this->w = static_cast(v.w); return *this; } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator+=(U scalar) { return (*this = detail::compute_vec4_add::value>::call(*this, vec<4, T, Q>(scalar))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator+=(vec<1, U, Q> const& v) { return (*this = detail::compute_vec4_add::value>::call(*this, vec<4, T, Q>(v.x))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator+=(vec<4, U, Q> const& v) { return (*this = detail::compute_vec4_add::value>::call(*this, vec<4, T, Q>(v))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator-=(U scalar) { return (*this = detail::compute_vec4_sub::value>::call(*this, vec<4, T, Q>(scalar))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator-=(vec<1, U, Q> const& v) { return (*this = detail::compute_vec4_sub::value>::call(*this, vec<4, T, Q>(v.x))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator-=(vec<4, U, Q> const& v) { return (*this = detail::compute_vec4_sub::value>::call(*this, vec<4, T, Q>(v))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator*=(U scalar) { return (*this = detail::compute_vec4_mul::value>::call(*this, vec<4, T, Q>(scalar))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator*=(vec<1, U, Q> const& v) { return (*this = detail::compute_vec4_mul::value>::call(*this, vec<4, T, Q>(v.x))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator*=(vec<4, U, Q> const& v) { return (*this = detail::compute_vec4_mul::value>::call(*this, vec<4, T, Q>(v))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator/=(U scalar) { return (*this = detail::compute_vec4_div::value>::call(*this, vec<4, T, Q>(scalar))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator/=(vec<1, U, Q> const& v) { return (*this = detail::compute_vec4_div::value>::call(*this, vec<4, T, Q>(v.x))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator/=(vec<4, U, Q> const& v) { return (*this = detail::compute_vec4_div::value>::call(*this, vec<4, T, Q>(v))); } // -- Increment and decrement operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator++() { ++this->x; ++this->y; ++this->z; ++this->w; return *this; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator--() { --this->x; --this->y; --this->z; --this->w; return *this; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> vec<4, T, Q>::operator++(int) { vec<4, T, Q> Result(*this); ++*this; return Result; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> vec<4, T, Q>::operator--(int) { vec<4, T, Q> Result(*this); --*this; return Result; } // -- Unary bit operators -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator%=(U scalar) { return (*this = detail::compute_vec4_mod::value>::call(*this, vec<4, T, Q>(scalar))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator%=(vec<1, U, Q> const& v) { return (*this = detail::compute_vec4_mod::value>::call(*this, vec<4, T, Q>(v))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator%=(vec<4, U, Q> const& v) { return (*this = detail::compute_vec4_mod::value>::call(*this, vec<4, T, Q>(v))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator&=(U scalar) { return (*this = detail::compute_vec4_and::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(scalar))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator&=(vec<1, U, Q> const& v) { return (*this = detail::compute_vec4_and::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator&=(vec<4, U, Q> const& v) { return (*this = detail::compute_vec4_and::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator|=(U scalar) { return (*this = detail::compute_vec4_or::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(scalar))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator|=(vec<1, U, Q> const& v) { return (*this = detail::compute_vec4_or::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator|=(vec<4, U, Q> const& v) { return (*this = detail::compute_vec4_or::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator^=(U scalar) { return (*this = detail::compute_vec4_xor::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(scalar))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator^=(vec<1, U, Q> const& v) { return (*this = detail::compute_vec4_xor::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator^=(vec<4, U, Q> const& v) { return (*this = detail::compute_vec4_xor::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator<<=(U scalar) { return (*this = detail::compute_vec4_shift_left::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(scalar))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator<<=(vec<1, U, Q> const& v) { return (*this = detail::compute_vec4_shift_left::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator<<=(vec<4, U, Q> const& v) { return (*this = detail::compute_vec4_shift_left::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator>>=(U scalar) { return (*this = detail::compute_vec4_shift_right::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(scalar))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator>>=(vec<1, U, Q> const& v) { return (*this = detail::compute_vec4_shift_right::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); } template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator>>=(vec<4, U, Q> const& v) { return (*this = detail::compute_vec4_shift_right::value, sizeof(T) * 8, detail::is_aligned::value>::call(*this, vec<4, T, Q>(v))); } // -- Unary constant operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v) { return v; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v) { return vec<4, T, Q>(0) -= v; } // -- Binary arithmetic operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v, T const & scalar) { return vec<4, T, Q>(v) += scalar; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<4, T, Q>(v1) += v2; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(T scalar, vec<4, T, Q> const& v) { return vec<4, T, Q>(v) += scalar; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) { return vec<4, T, Q>(v2) += v1; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) { return vec<4, T, Q>(v1) += v2; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v, T const & scalar) { return vec<4, T, Q>(v) -= scalar; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<4, T, Q>(v1) -= v2; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(T scalar, vec<4, T, Q> const& v) { return vec<4, T, Q>(scalar) -= v; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) { return vec<4, T, Q>(v1.x) -= v2; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) { return vec<4, T, Q>(v1) -= v2; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v, T const & scalar) { return vec<4, T, Q>(v) *= scalar; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<4, T, Q>(v1) *= v2; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(T scalar, vec<4, T, Q> const& v) { return vec<4, T, Q>(v) *= scalar; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) { return vec<4, T, Q>(v2) *= v1; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) { return vec<4, T, Q>(v1) *= v2; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v, T const & scalar) { return vec<4, T, Q>(v) /= scalar; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<4, T, Q>(v1) /= v2; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(T scalar, vec<4, T, Q> const& v) { return vec<4, T, Q>(scalar) /= v; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) { return vec<4, T, Q>(v1.x) /= v2; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) { return vec<4, T, Q>(v1) /= v2; } // -- Binary bit operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v, T scalar) { return vec<4, T, Q>(v) %= scalar; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<4, T, Q>(v1) %= v2.x; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(T scalar, vec<4, T, Q> const& v) { return vec<4, T, Q>(scalar) %= v; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v) { return vec<4, T, Q>(scalar.x) %= v; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) { return vec<4, T, Q>(v1) %= v2; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v, T scalar) { return vec<4, T, Q>(v) &= scalar; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar) { return vec<4, T, Q>(v) &= scalar; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(T scalar, vec<4, T, Q> const& v) { return vec<4, T, Q>(scalar) &= v; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) { return vec<4, T, Q>(v1.x) &= v2; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) { return vec<4, T, Q>(v1) &= v2; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v, T scalar) { return vec<4, T, Q>(v) |= scalar; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<4, T, Q>(v1) |= v2.x; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(T scalar, vec<4, T, Q> const& v) { return vec<4, T, Q>(scalar) |= v; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) { return vec<4, T, Q>(v1.x) |= v2; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) { return vec<4, T, Q>(v1) |= v2; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v, T scalar) { return vec<4, T, Q>(v) ^= scalar; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<4, T, Q>(v1) ^= v2.x; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(T scalar, vec<4, T, Q> const& v) { return vec<4, T, Q>(scalar) ^= v; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) { return vec<4, T, Q>(v1.x) ^= v2; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) { return vec<4, T, Q>(v1) ^= v2; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v, T scalar) { return vec<4, T, Q>(v) <<= scalar; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<4, T, Q>(v1) <<= v2.x; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(T scalar, vec<4, T, Q> const& v) { return vec<4, T, Q>(scalar) <<= v; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) { return vec<4, T, Q>(v1.x) <<= v2; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) { return vec<4, T, Q>(v1) <<= v2; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v, T scalar) { return vec<4, T, Q>(v) >>= scalar; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2) { return vec<4, T, Q>(v1) >>= v2.x; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(T scalar, vec<4, T, Q> const& v) { return vec<4, T, Q>(scalar) >>= v; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2) { return vec<4, T, Q>(v1.x) >>= v2; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) { return vec<4, T, Q>(v1) >>= v2; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator~(vec<4, T, Q> const& v) { return detail::compute_vec4_bitwise_not::value, sizeof(T) * 8, detail::is_aligned::value>::call(v); } // -- Boolean operators -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) { return detail::compute_vec4_equal::value, sizeof(T) * 8, detail::is_aligned::value>::call(v1, v2); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2) { return detail::compute_vec4_nequal::value, sizeof(T) * 8, detail::is_aligned::value>::call(v1, v2); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, bool, Q> operator&&(vec<4, bool, Q> const& v1, vec<4, bool, Q> const& v2) { return vec<4, bool, Q>(v1.x && v2.x, v1.y && v2.y, v1.z && v2.z, v1.w && v2.w); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, bool, Q> operator||(vec<4, bool, Q> const& v1, vec<4, bool, Q> const& v2) { return vec<4, bool, Q>(v1.x || v2.x, v1.y || v2.y, v1.z || v2.z, v1.w || v2.w); } }//namespace glm #if GLM_CONFIG_SIMD == GLM_ENABLE # include "type_vec4_simd.inl" #endif connectome-workbench-1.4.2/src/GLMath/glm/detail/type_vec4_simd.inl000066400000000000000000000506541360521144700252130ustar00rootroot00000000000000#if GLM_ARCH & GLM_ARCH_SSE2_BIT namespace glm{ namespace detail { # if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR template struct _swizzle_base1<4, float, Q, E0,E1,E2,E3, true> : public _swizzle_base0 { GLM_FUNC_QUALIFIER vec<4, float, Q> operator ()() const { __m128 data = *reinterpret_cast<__m128 const*>(&this->_buffer); vec<4, float, Q> Result; # if GLM_ARCH & GLM_ARCH_AVX_BIT Result.data = _mm_permute_ps(data, _MM_SHUFFLE(E3, E2, E1, E0)); # else Result.data = _mm_shuffle_ps(data, data, _MM_SHUFFLE(E3, E2, E1, E0)); # endif return Result; } }; template struct _swizzle_base1<4, int, Q, E0,E1,E2,E3, true> : public _swizzle_base0 { GLM_FUNC_QUALIFIER vec<4, int, Q> operator ()() const { __m128i data = *reinterpret_cast<__m128i const*>(&this->_buffer); vec<4, int, Q> Result; Result.data = _mm_shuffle_epi32(data, _MM_SHUFFLE(E3, E2, E1, E0)); return Result; } }; template struct _swizzle_base1<4, uint, Q, E0,E1,E2,E3, true> : public _swizzle_base0 { GLM_FUNC_QUALIFIER vec<4, uint, Q> operator ()() const { __m128i data = *reinterpret_cast<__m128i const*>(&this->_buffer); vec<4, uint, Q> Result; Result.data = _mm_shuffle_epi32(data, _MM_SHUFFLE(E3, E2, E1, E0)); return Result; } }; # endif// GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR template struct compute_vec4_add { static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) { vec<4, float, Q> Result; Result.data = _mm_add_ps(a.data, b.data); return Result; } }; # if GLM_ARCH & GLM_ARCH_AVX_BIT template struct compute_vec4_add { static vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b) { vec<4, double, Q> Result; Result.data = _mm256_add_pd(a.data, b.data); return Result; } }; # endif template struct compute_vec4_sub { static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) { vec<4, float, Q> Result; Result.data = _mm_sub_ps(a.data, b.data); return Result; } }; # if GLM_ARCH & GLM_ARCH_AVX_BIT template struct compute_vec4_sub { static vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b) { vec<4, double, Q> Result; Result.data = _mm256_sub_pd(a.data, b.data); return Result; } }; # endif template struct compute_vec4_mul { static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) { vec<4, float, Q> Result; Result.data = _mm_mul_ps(a.data, b.data); return Result; } }; # if GLM_ARCH & GLM_ARCH_AVX_BIT template struct compute_vec4_mul { static vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b) { vec<4, double, Q> Result; Result.data = _mm256_mul_pd(a.data, b.data); return Result; } }; # endif template struct compute_vec4_div { static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) { vec<4, float, Q> Result; Result.data = _mm_div_ps(a.data, b.data); return Result; } }; # if GLM_ARCH & GLM_ARCH_AVX_BIT template struct compute_vec4_div { static vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b) { vec<4, double, Q> Result; Result.data = _mm256_div_pd(a.data, b.data); return Result; } }; # endif template<> struct compute_vec4_div { static vec<4, float, aligned_lowp> call(vec<4, float, aligned_lowp> const& a, vec<4, float, aligned_lowp> const& b) { vec<4, float, aligned_lowp> Result; Result.data = _mm_mul_ps(a.data, _mm_rcp_ps(b.data)); return Result; } }; template struct compute_vec4_and { static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { vec<4, T, Q> Result; Result.data = _mm_and_si128(a.data, b.data); return Result; } }; # if GLM_ARCH & GLM_ARCH_AVX2_BIT template struct compute_vec4_and { static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { vec<4, T, Q> Result; Result.data = _mm256_and_si256(a.data, b.data); return Result; } }; # endif template struct compute_vec4_or { static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { vec<4, T, Q> Result; Result.data = _mm_or_si128(a.data, b.data); return Result; } }; # if GLM_ARCH & GLM_ARCH_AVX2_BIT template struct compute_vec4_or { static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { vec<4, T, Q> Result; Result.data = _mm256_or_si256(a.data, b.data); return Result; } }; # endif template struct compute_vec4_xor { static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { vec<4, T, Q> Result; Result.data = _mm_xor_si128(a.data, b.data); return Result; } }; # if GLM_ARCH & GLM_ARCH_AVX2_BIT template struct compute_vec4_xor { static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { vec<4, T, Q> Result; Result.data = _mm256_xor_si256(a.data, b.data); return Result; } }; # endif template struct compute_vec4_shift_left { static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { vec<4, T, Q> Result; Result.data = _mm_sll_epi32(a.data, b.data); return Result; } }; # if GLM_ARCH & GLM_ARCH_AVX2_BIT template struct compute_vec4_shift_left { static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { vec<4, T, Q> Result; Result.data = _mm256_sll_epi64(a.data, b.data); return Result; } }; # endif template struct compute_vec4_shift_right { static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { vec<4, T, Q> Result; Result.data = _mm_srl_epi32(a.data, b.data); return Result; } }; # if GLM_ARCH & GLM_ARCH_AVX2_BIT template struct compute_vec4_shift_right { static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b) { vec<4, T, Q> Result; Result.data = _mm256_srl_epi64(a.data, b.data); return Result; } }; # endif template struct compute_vec4_bitwise_not { static vec<4, T, Q> call(vec<4, T, Q> const& v) { vec<4, T, Q> Result; Result.data = _mm_xor_si128(v.data, _mm_set1_epi32(-1)); return Result; } }; # if GLM_ARCH & GLM_ARCH_AVX2_BIT template struct compute_vec4_bitwise_not { static vec<4, T, Q> call(vec<4, T, Q> const& v) { vec<4, T, Q> Result; Result.data = _mm256_xor_si256(v.data, _mm_set1_epi32(-1)); return Result; } }; # endif template struct compute_vec4_equal { static bool call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) { return _mm_movemask_ps(_mm_cmpeq_ps(v1.data, v2.data)) != 0; } }; # if GLM_ARCH & GLM_ARCH_SSE41_BIT template struct compute_vec4_equal { static bool call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) { //return _mm_movemask_epi8(_mm_cmpeq_epi32(v1.data, v2.data)) != 0; __m128i neq = _mm_xor_si128(v1.data, v2.data); return _mm_test_all_zeros(neq, neq) == 0; } }; # endif template struct compute_vec4_nequal { static bool call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) { return _mm_movemask_ps(_mm_cmpneq_ps(v1.data, v2.data)) != 0; } }; # if GLM_ARCH & GLM_ARCH_SSE41_BIT template struct compute_vec4_nequal { static bool call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) { //return _mm_movemask_epi8(_mm_cmpneq_epi32(v1.data, v2.data)) != 0; __m128i neq = _mm_xor_si128(v1.data, v2.data); return _mm_test_all_zeros(neq, neq) != 0; } }; # endif }//namespace detail template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(float _s) : data(_mm_set1_ps(_s)) {} template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(float _s) : data(_mm_set1_ps(_s)) {} template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(float _s) : data(_mm_set1_ps(_s)) {} # if GLM_ARCH & GLM_ARCH_AVX_BIT template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, double, aligned_lowp>::vec(double _s) : data(_mm256_set1_pd(_s)) {} template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, double, aligned_mediump>::vec(double _s) : data(_mm256_set1_pd(_s)) {} template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, double, aligned_highp>::vec(double _s) : data(_mm256_set1_pd(_s)) {} # endif template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_lowp>::vec(int _s) : data(_mm_set1_epi32(_s)) {} template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_mediump>::vec(int _s) : data(_mm_set1_epi32(_s)) {} template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_highp>::vec(int _s) : data(_mm_set1_epi32(_s)) {} # if GLM_ARCH & GLM_ARCH_AVX2_BIT template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, detail::int64, aligned_lowp>::vec(detail::int64 _s) : data(_mm256_set1_epi64x(_s)) {} template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, detail::int64, aligned_mediump>::vec(detail::int64 _s) : data(_mm256_set1_epi64x(_s)) {} template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, detail::int64, aligned_highp>::vec(detail::int64 _s) : data(_mm256_set1_epi64x(_s)) {} # endif template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(float _x, float _y, float _z, float _w) : data(_mm_set_ps(_w, _z, _y, _x)) {} template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(float _x, float _y, float _z, float _w) : data(_mm_set_ps(_w, _z, _y, _x)) {} template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(float _x, float _y, float _z, float _w) : data(_mm_set_ps(_w, _z, _y, _x)) {} template<> template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_lowp>::vec(int _x, int _y, int _z, int _w) : data(_mm_set_epi32(_w, _z, _y, _x)) {} template<> template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_mediump>::vec(int _x, int _y, int _z, int _w) : data(_mm_set_epi32(_w, _z, _y, _x)) {} template<> template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_highp>::vec(int _x, int _y, int _z, int _w) : data(_mm_set_epi32(_w, _z, _y, _x)) {} template<> template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(int _x, int _y, int _z, int _w) : data(_mm_cvtepi32_ps(_mm_set_epi32(_w, _z, _y, _x))) {} template<> template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(int _x, int _y, int _z, int _w) : data(_mm_cvtepi32_ps(_mm_set_epi32(_w, _z, _y, _x))) {} template<> template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(int _x, int _y, int _z, int _w) : data(_mm_cvtepi32_ps(_mm_set_epi32(_w, _z, _y, _x))) {} }//namespace glm #endif//GLM_ARCH & GLM_ARCH_SSE2_BIT #if GLM_ARCH & GLM_ARCH_NEON_BIT namespace glm { namespace detail { template struct compute_vec4_add { static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) { vec<4, float, Q> Result; Result.data = vaddq_f32(a.data, b.data); return Result; } }; template struct compute_vec4_add { static vec<4, uint, Q> call(vec<4, uint, Q> const& a, vec<4, uint, Q> const& b) { vec<4, uint, Q> Result; Result.data = vaddq_u32(a.data, b.data); return Result; } }; template struct compute_vec4_add { static vec<4, int, Q> call(vec<4, int, Q> const& a, vec<4, int, Q> const& b) { vec<4, uint, Q> Result; Result.data = vaddq_s32(a.data, b.data); return Result; } }; template struct compute_vec4_sub { static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) { vec<4, float, Q> Result; Result.data = vsubq_f32(a.data, b.data); return Result; } }; template struct compute_vec4_sub { static vec<4, uint, Q> call(vec<4, uint, Q> const& a, vec<4, uint, Q> const& b) { vec<4, uint, Q> Result; Result.data = vsubq_u32(a.data, b.data); return Result; } }; template struct compute_vec4_sub { static vec<4, int, Q> call(vec<4, int, Q> const& a, vec<4, int, Q> const& b) { vec<4, int, Q> Result; Result.data = vsubq_s32(a.data, b.data); return Result; } }; template struct compute_vec4_mul { static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) { vec<4, float, Q> Result; Result.data = vmulq_f32(a.data, b.data); return Result; } }; template struct compute_vec4_mul { static vec<4, uint, Q> call(vec<4, uint, Q> const& a, vec<4, uint, Q> const& b) { vec<4, uint, Q> Result; Result.data = vmulq_u32(a.data, b.data); return Result; } }; template struct compute_vec4_mul { static vec<4, int, Q> call(vec<4, int, Q> const& a, vec<4, int, Q> const& b) { vec<4, int, Q> Result; Result.data = vmulq_s32(a.data, b.data); return Result; } }; template struct compute_vec4_div { static vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b) { vec<4, float, Q> Result; Result.data = vdivq_f32(a.data, b.data); return Result; } }; template struct compute_vec4_div { static vec<4, uint, Q> call(vec<4, uint, Q> const& a, vec<4, uint, Q> const& b) { vec<4, uint, Q> Result; Result.data = vdivq_u32(a.data, b.data); return Result; } }; template struct compute_vec4_div { static vec<4, int, Q> call(vec<4, float, Q> const& a, vec<4, int, Q> const& b) { vec<4, int, Q> Result; Result.data = vdivq_s32(a.data, b.data); return Result; } }; template struct compute_vec4_equal { static bool call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) { uint32x4_t cmp = vceqq_f32(v1.data, v2.data); #if GLM_ARCH & GLM_ARCH_ARMV8_BIT cmp = vpminq_u32(cmp, cmp); cmp = vpminq_u32(cmp, cmp); uint32_t r = cmp[0]; #else uint32x2_t cmpx2 = vpmin_u32(vget_low_f32(cmp), vget_high_f32(cmp)); cmpx2 = vpmin_u32(cmpx2, cmpx2); uint32_t r = cmpx2[0]; #endif return r == ~0u; } }; template struct compute_vec4_equal { static bool call(vec<4, uint, Q> const& v1, vec<4, uint, Q> const& v2) { uint32x4_t cmp = vceqq_u32(v1.data, v2.data); #if GLM_ARCH & GLM_ARCH_ARMV8_BIT cmp = vpminq_u32(cmp, cmp); cmp = vpminq_u32(cmp, cmp); uint32_t r = cmp[0]; #else uint32x2_t cmpx2 = vpmin_u32(vget_low_f32(cmp), vget_high_f32(cmp)); cmpx2 = vpmin_u32(cmpx2, cmpx2); uint32_t r = cmpx2[0]; #endif return r == ~0u; } }; template struct compute_vec4_equal { static bool call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) { uint32x4_t cmp = vceqq_s32(v1.data, v2.data); #if GLM_ARCH & GLM_ARCH_ARMV8_BIT cmp = vpminq_u32(cmp, cmp); cmp = vpminq_u32(cmp, cmp); uint32_t r = cmp[0]; #else uint32x2_t cmpx2 = vpmin_u32(vget_low_f32(cmp), vget_high_f32(cmp)); cmpx2 = vpmin_u32(cmpx2, cmpx2); uint32_t r = cmpx2[0]; #endif return r == ~0u; } }; template struct compute_vec4_nequal { static bool call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2) { return !compute_vec4_equal::call(v1, v2); } }; template struct compute_vec4_nequal { static bool call(vec<4, uint, Q> const& v1, vec<4, uint, Q> const& v2) { return !compute_vec4_equal::call(v1, v2); } }; template struct compute_vec4_nequal { static bool call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2) { return !compute_vec4_equal::call(v1, v2); } }; }//namespace detail #if !GLM_CONFIG_XYZW_ONLY template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(float _s) : data(vdupq_n_f32(_s)) {} template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(float _s) : data(vdupq_n_f32(_s)) {} template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(float _s) : data(vdupq_n_f32(_s)) {} template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_lowp>::vec(int _s) : data(vdupq_n_s32(_s)) {} template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_mediump>::vec(int _s) : data(vdupq_n_s32(_s)) {} template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_highp>::vec(int _s) : data(vdupq_n_s32(_s)) {} template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, uint, aligned_lowp>::vec(uint _s) : data(vdupq_n_u32(_s)) {} template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, uint, aligned_mediump>::vec(uint _s) : data(vdupq_n_u32(_s)) {} template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, uint, aligned_highp>::vec(uint _s) : data(vdupq_n_u32(_s)) {} template<> template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(const vec<4, float, aligned_highp>& rhs) : data(rhs.data) {} template<> template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(const vec<4, int, aligned_highp>& rhs) : data(vcvtq_f32_s32(rhs.data)) {} template<> template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(const vec<4, uint, aligned_highp>& rhs) : data(vcvtq_f32_u32(rhs.data)) {} template<> template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(int _x, int _y, int _z, int _w) : data(vcvtq_f32_s32(vec<4, int, aligned_lowp>(_x, _y, _z, _w).data)) {} template<> template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(int _x, int _y, int _z, int _w) : data(vcvtq_f32_s32(vec<4, int, aligned_mediump>(_x, _y, _z, _w).data)) {} template<> template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(int _x, int _y, int _z, int _w) : data(vcvtq_f32_s32(vec<4, int, aligned_highp>(_x, _y, _z, _w).data)) {} template<> template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(uint _x, uint _y, uint _z, uint _w) : data(vcvtq_f32_u32(vec<4, uint, aligned_lowp>(_x, _y, _z, _w).data)) {} template<> template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(uint _x, uint _y, uint _z, uint _w) : data(vcvtq_f32_u32(vec<4, uint, aligned_mediump>(_x, _y, _z, _w).data)) {} template<> template<> GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(uint _x, uint _y, uint _z, uint _w) : data(vcvtq_f32_u32(vec<4, uint, aligned_highp>(_x, _y, _z, _w).data)) {} #endif }//namespace glm #endif connectome-workbench-1.4.2/src/GLMath/glm/exponential.hpp000066400000000000000000000131351360521144700233570ustar00rootroot00000000000000/// @ref core /// @file glm/exponential.hpp /// /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions /// /// @defgroup core_func_exponential Exponential functions /// @ingroup core /// /// Provides GLSL exponential functions /// /// These all operate component-wise. The description is per component. /// /// Include to use these core features. #pragma once #include "detail/type_vec1.hpp" #include "detail/type_vec2.hpp" #include "detail/type_vec3.hpp" #include "detail/type_vec4.hpp" #include namespace glm { /// @addtogroup core_func_exponential /// @{ /// Returns 'base' raised to the power 'exponent'. /// /// @param base Floating point value. pow function is defined for input values of 'base' defined in the range (inf-, inf+) in the limit of the type qualifier. /// @param exponent Floating point value representing the 'exponent'. /// /// @see GLSL pow man page /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions template GLM_FUNC_DECL vec pow(vec const& base, vec const& exponent); /// Returns the natural exponentiation of x, i.e., e^x. /// /// @param v exp function is defined for input values of v defined in the range (inf-, inf+) in the limit of the type qualifier. /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T Floating-point scalar types. /// /// @see GLSL exp man page /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions template GLM_FUNC_DECL vec exp(vec const& v); /// Returns the natural logarithm of v, i.e., /// returns the value y which satisfies the equation x = e^y. /// Results are undefined if v <= 0. /// /// @param v log function is defined for input values of v defined in the range (0, inf+) in the limit of the type qualifier. /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T Floating-point scalar types. /// /// @see GLSL log man page /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions template GLM_FUNC_DECL vec log(vec const& v); /// Returns 2 raised to the v power. /// /// @param v exp2 function is defined for input values of v defined in the range (inf-, inf+) in the limit of the type qualifier. /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T Floating-point scalar types. /// /// @see GLSL exp2 man page /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions template GLM_FUNC_DECL vec exp2(vec const& v); /// Returns the base 2 log of x, i.e., returns the value y, /// which satisfies the equation x = 2 ^ y. /// /// @param v log2 function is defined for input values of v defined in the range (0, inf+) in the limit of the type qualifier. /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T Floating-point scalar types. /// /// @see GLSL log2 man page /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions template GLM_FUNC_DECL vec log2(vec const& v); /// Returns the positive square root of v. /// /// @param v sqrt function is defined for input values of v defined in the range [0, inf+) in the limit of the type qualifier. /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T Floating-point scalar types. /// /// @see GLSL sqrt man page /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions template GLM_FUNC_DECL vec sqrt(vec const& v); /// Returns the reciprocal of the positive square root of v. /// /// @param v inversesqrt function is defined for input values of v defined in the range [0, inf+) in the limit of the type qualifier. /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T Floating-point scalar types. /// /// @see GLSL inversesqrt man page /// @see GLSL 4.20.8 specification, section 8.2 Exponential Functions template GLM_FUNC_DECL vec inversesqrt(vec const& v); /// @} }//namespace glm #include "detail/func_exponential.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext.hpp000066400000000000000000000150221360521144700216260ustar00rootroot00000000000000/// @file glm/ext.hpp /// /// @ref core (Dependence) #include "detail/setup.hpp" #pragma once #include "glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_MESSAGE_EXT_INCLUDED_DISPLAYED) # define GLM_MESSAGE_EXT_INCLUDED_DISPLAYED # pragma message("GLM: All extensions included (not recommended)") #endif//GLM_MESSAGES #include "./ext/matrix_double2x2.hpp" #include "./ext/matrix_double2x2_precision.hpp" #include "./ext/matrix_double2x3.hpp" #include "./ext/matrix_double2x3_precision.hpp" #include "./ext/matrix_double2x4.hpp" #include "./ext/matrix_double2x4_precision.hpp" #include "./ext/matrix_double3x2.hpp" #include "./ext/matrix_double3x2_precision.hpp" #include "./ext/matrix_double3x3.hpp" #include "./ext/matrix_double3x3_precision.hpp" #include "./ext/matrix_double3x4.hpp" #include "./ext/matrix_double3x4_precision.hpp" #include "./ext/matrix_double4x2.hpp" #include "./ext/matrix_double4x2_precision.hpp" #include "./ext/matrix_double4x3.hpp" #include "./ext/matrix_double4x3_precision.hpp" #include "./ext/matrix_double4x4.hpp" #include "./ext/matrix_double4x4_precision.hpp" #include "./ext/matrix_float2x2.hpp" #include "./ext/matrix_float2x2_precision.hpp" #include "./ext/matrix_float2x3.hpp" #include "./ext/matrix_float2x3_precision.hpp" #include "./ext/matrix_float2x4.hpp" #include "./ext/matrix_float2x4_precision.hpp" #include "./ext/matrix_float3x2.hpp" #include "./ext/matrix_float3x2_precision.hpp" #include "./ext/matrix_float3x3.hpp" #include "./ext/matrix_float3x3_precision.hpp" #include "./ext/matrix_float3x4.hpp" #include "./ext/matrix_float3x4_precision.hpp" #include "./ext/matrix_float4x2.hpp" #include "./ext/matrix_float4x2_precision.hpp" #include "./ext/matrix_float4x3.hpp" #include "./ext/matrix_float4x3_precision.hpp" #include "./ext/matrix_float4x4.hpp" #include "./ext/matrix_float4x4_precision.hpp" #include "./ext/matrix_relational.hpp" #include "./ext/quaternion_double.hpp" #include "./ext/quaternion_double_precision.hpp" #include "./ext/quaternion_float.hpp" #include "./ext/quaternion_float_precision.hpp" #include "./ext/quaternion_geometric.hpp" #include "./ext/quaternion_relational.hpp" #include "./ext/scalar_constants.hpp" #include "./ext/scalar_int_sized.hpp" #include "./ext/scalar_relational.hpp" #include "./ext/vector_bool1.hpp" #include "./ext/vector_bool1_precision.hpp" #include "./ext/vector_bool2.hpp" #include "./ext/vector_bool2_precision.hpp" #include "./ext/vector_bool3.hpp" #include "./ext/vector_bool3_precision.hpp" #include "./ext/vector_bool4.hpp" #include "./ext/vector_bool4_precision.hpp" #include "./ext/vector_double1.hpp" #include "./ext/vector_double1_precision.hpp" #include "./ext/vector_double2.hpp" #include "./ext/vector_double2_precision.hpp" #include "./ext/vector_double3.hpp" #include "./ext/vector_double3_precision.hpp" #include "./ext/vector_double4.hpp" #include "./ext/vector_double4_precision.hpp" #include "./ext/vector_float1.hpp" #include "./ext/vector_float1_precision.hpp" #include "./ext/vector_float2.hpp" #include "./ext/vector_float2_precision.hpp" #include "./ext/vector_float3.hpp" #include "./ext/vector_float3_precision.hpp" #include "./ext/vector_float4.hpp" #include "./ext/vector_float4_precision.hpp" #include "./ext/vector_int1.hpp" #include "./ext/vector_int1_precision.hpp" #include "./ext/vector_int2.hpp" #include "./ext/vector_int2_precision.hpp" #include "./ext/vector_int3.hpp" #include "./ext/vector_int3_precision.hpp" #include "./ext/vector_int4.hpp" #include "./ext/vector_int4_precision.hpp" #include "./ext/vector_relational.hpp" #include "./ext/vector_uint1.hpp" #include "./ext/vector_uint1_precision.hpp" #include "./ext/vector_uint2.hpp" #include "./ext/vector_uint2_precision.hpp" #include "./ext/vector_uint3.hpp" #include "./ext/vector_uint3_precision.hpp" #include "./ext/vector_uint4.hpp" #include "./ext/vector_uint4_precision.hpp" #include "./gtc/bitfield.hpp" #include "./gtc/color_space.hpp" #include "./gtc/constants.hpp" #include "./gtc/epsilon.hpp" #include "./gtc/integer.hpp" #include "./gtc/matrix_access.hpp" #include "./gtc/matrix_integer.hpp" #include "./gtc/matrix_inverse.hpp" #include "./gtc/matrix_transform.hpp" #include "./gtc/noise.hpp" #include "./gtc/packing.hpp" #include "./gtc/quaternion.hpp" #include "./gtc/random.hpp" #include "./gtc/reciprocal.hpp" #include "./gtc/round.hpp" #include "./gtc/type_precision.hpp" #include "./gtc/type_ptr.hpp" #include "./gtc/ulp.hpp" #include "./gtc/vec1.hpp" #if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE # include "./gtc/type_aligned.hpp" #endif #ifdef GLM_ENABLE_EXPERIMENTAL #include "./gtx/associated_min_max.hpp" #include "./gtx/bit.hpp" #include "./gtx/closest_point.hpp" #include "./gtx/color_encoding.hpp" #include "./gtx/color_space.hpp" #include "./gtx/color_space_YCoCg.hpp" #include "./gtx/compatibility.hpp" #include "./gtx/component_wise.hpp" #include "./gtx/dual_quaternion.hpp" #include "./gtx/euler_angles.hpp" #include "./gtx/extend.hpp" #include "./gtx/extended_min_max.hpp" #include "./gtx/fast_exponential.hpp" #include "./gtx/fast_square_root.hpp" #include "./gtx/fast_trigonometry.hpp" #include "./gtx/functions.hpp" #include "./gtx/gradient_paint.hpp" #include "./gtx/handed_coordinate_space.hpp" #include "./gtx/integer.hpp" #include "./gtx/intersect.hpp" #include "./gtx/log_base.hpp" #include "./gtx/matrix_cross_product.hpp" #include "./gtx/matrix_interpolation.hpp" #include "./gtx/matrix_major_storage.hpp" #include "./gtx/matrix_operation.hpp" #include "./gtx/matrix_query.hpp" #include "./gtx/mixed_product.hpp" #include "./gtx/norm.hpp" #include "./gtx/normal.hpp" #include "./gtx/normalize_dot.hpp" #include "./gtx/number_precision.hpp" #include "./gtx/optimum_pow.hpp" #include "./gtx/orthonormalize.hpp" #include "./gtx/perpendicular.hpp" #include "./gtx/polar_coordinates.hpp" #include "./gtx/projection.hpp" #include "./gtx/quaternion.hpp" #include "./gtx/raw_data.hpp" #include "./gtx/rotate_vector.hpp" #include "./gtx/spline.hpp" #include "./gtx/std_based_type.hpp" #if !(GLM_COMPILER & GLM_COMPILER_CUDA) # include "./gtx/string_cast.hpp" #endif #include "./gtx/transform.hpp" #include "./gtx/transform2.hpp" #include "./gtx/vec_swizzle.hpp" #include "./gtx/vector_angle.hpp" #include "./gtx/vector_query.hpp" #include "./gtx/wrap.hpp" #if GLM_HAS_TEMPLATE_ALIASES # include "./gtx/scalar_multiplication.hpp" #endif #if GLM_HAS_RANGE_FOR # include "./gtx/range.hpp" #endif #endif//GLM_ENABLE_EXPERIMENTAL connectome-workbench-1.4.2/src/GLMath/glm/ext/000077500000000000000000000000001360521144700211155ustar00rootroot00000000000000connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_clip_space.hpp000066400000000000000000000730471360521144700253270ustar00rootroot00000000000000/// @ref ext_matrix_clip_space /// @file glm/ext/matrix_clip_space.hpp /// /// @defgroup ext_matrix_clip_space GLM_EXT_matrix_clip_space /// @ingroup ext /// /// Defines functions that generate clip space transformation matrices. /// /// The matrices generated by this extension use standard OpenGL fixed-function /// conventions. For example, the lookAt function generates a transform from world /// space into the specific eye space that the projective matrix functions /// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility /// specifications defines the particular layout of this eye space. /// /// Include to use the features of this extension. /// /// @see ext_matrix_transform /// @see ext_matrix_projection #pragma once // Dependencies #include "../ext/scalar_constants.hpp" #include "../geometric.hpp" #include "../trigonometric.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_matrix_clip_space extension included") #endif namespace glm { /// @addtogroup ext_matrix_clip_space /// @{ /// Creates a matrix for projecting two-dimensional coordinates onto the screen. /// /// @tparam T A floating-point scalar type /// /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top, T const& zNear, T const& zFar) /// @see gluOrtho2D man page template GLM_FUNC_DECL mat<4, 4, T, defaultp> ortho( T left, T right, T bottom, T top); /// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates. /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// /// @tparam T A floating-point scalar type /// /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) template GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoLH_ZO( T left, T right, T bottom, T top, T zNear, T zFar); /// Creates a matrix for an orthographic parallel viewing volume using right-handed coordinates. /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @tparam T A floating-point scalar type /// /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) template GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoLH_NO( T left, T right, T bottom, T top, T zNear, T zFar); /// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates. /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// /// @tparam T A floating-point scalar type /// /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) template GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoRH_ZO( T left, T right, T bottom, T top, T zNear, T zFar); /// Creates a matrix for an orthographic parallel viewing volume, using right-handed coordinates. /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @tparam T A floating-point scalar type /// /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) template GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoRH_NO( T left, T right, T bottom, T top, T zNear, T zFar); /// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates. /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// /// @tparam T A floating-point scalar type /// /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) template GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoZO( T left, T right, T bottom, T top, T zNear, T zFar); /// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @tparam T A floating-point scalar type /// /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) template GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoNO( T left, T right, T bottom, T top, T zNear, T zFar); /// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates. /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @tparam T A floating-point scalar type /// /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) template GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoLH( T left, T right, T bottom, T top, T zNear, T zFar); /// Creates a matrix for an orthographic parallel viewing volume, using right-handed coordinates. /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @tparam T A floating-point scalar type /// /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) template GLM_FUNC_DECL mat<4, 4, T, defaultp> orthoRH( T left, T right, T bottom, T top, T zNear, T zFar); /// Creates a matrix for an orthographic parallel viewing volume, using the default handedness and default near and far clip planes definition. /// To change default handedness use GLM_FORCE_LEFT_HANDED. To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. /// /// @tparam T A floating-point scalar type /// /// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top) /// @see glOrtho man page template GLM_FUNC_DECL mat<4, 4, T, defaultp> ortho( T left, T right, T bottom, T top, T zNear, T zFar); /// Creates a left handed frustum matrix. /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumLH_ZO( T left, T right, T bottom, T top, T near, T far); /// Creates a left handed frustum matrix. /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumLH_NO( T left, T right, T bottom, T top, T near, T far); /// Creates a right handed frustum matrix. /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumRH_ZO( T left, T right, T bottom, T top, T near, T far); /// Creates a right handed frustum matrix. /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumRH_NO( T left, T right, T bottom, T top, T near, T far); /// Creates a frustum matrix using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumZO( T left, T right, T bottom, T top, T near, T far); /// Creates a frustum matrix using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumNO( T left, T right, T bottom, T top, T near, T far); /// Creates a left handed frustum matrix. /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumLH( T left, T right, T bottom, T top, T near, T far); /// Creates a right handed frustum matrix. /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> frustumRH( T left, T right, T bottom, T top, T near, T far); /// Creates a frustum matrix with default handedness, using the default handedness and default near and far clip planes definition. /// To change default handedness use GLM_FORCE_LEFT_HANDED. To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. /// /// @tparam T A floating-point scalar type /// @see glFrustum man page template GLM_FUNC_DECL mat<4, 4, T, defaultp> frustum( T left, T right, T bottom, T top, T near, T far); /// Creates a matrix for a right handed, symetric perspective-view frustum. /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveRH_ZO( T fovy, T aspect, T near, T far); /// Creates a matrix for a right handed, symetric perspective-view frustum. /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveRH_NO( T fovy, T aspect, T near, T far); /// Creates a matrix for a left handed, symetric perspective-view frustum. /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveLH_ZO( T fovy, T aspect, T near, T far); /// Creates a matrix for a left handed, symetric perspective-view frustum. /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveLH_NO( T fovy, T aspect, T near, T far); /// Creates a matrix for a symetric perspective-view frustum using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveZO( T fovy, T aspect, T near, T far); /// Creates a matrix for a symetric perspective-view frustum using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveNO( T fovy, T aspect, T near, T far); /// Creates a matrix for a right handed, symetric perspective-view frustum. /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveRH( T fovy, T aspect, T near, T far); /// Creates a matrix for a left handed, symetric perspective-view frustum. /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveLH( T fovy, T aspect, T near, T far); /// Creates a matrix for a symetric perspective-view frustum based on the default handedness and default near and far clip planes definition. /// To change default handedness use GLM_FORCE_LEFT_HANDED. To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. /// /// @param fovy Specifies the field of view angle in the y direction. Expressed in radians. /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). /// /// @tparam T A floating-point scalar type /// @see gluPerspective man page template GLM_FUNC_DECL mat<4, 4, T, defaultp> perspective( T fovy, T aspect, T near, T far); /// Builds a perspective projection matrix based on a field of view using right-handed coordinates. /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// /// @param fov Expressed in radians. /// @param width Width of the viewport /// @param height Height of the viewport /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovRH_ZO( T fov, T width, T height, T near, T far); /// Builds a perspective projection matrix based on a field of view using right-handed coordinates. /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @param fov Expressed in radians. /// @param width Width of the viewport /// @param height Height of the viewport /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovRH_NO( T fov, T width, T height, T near, T far); /// Builds a perspective projection matrix based on a field of view using left-handed coordinates. /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// /// @param fov Expressed in radians. /// @param width Width of the viewport /// @param height Height of the viewport /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovLH_ZO( T fov, T width, T height, T near, T far); /// Builds a perspective projection matrix based on a field of view using left-handed coordinates. /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @param fov Expressed in radians. /// @param width Width of the viewport /// @param height Height of the viewport /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovLH_NO( T fov, T width, T height, T near, T far); /// Builds a perspective projection matrix based on a field of view using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// /// @param fov Expressed in radians. /// @param width Width of the viewport /// @param height Height of the viewport /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovZO( T fov, T width, T height, T near, T far); /// Builds a perspective projection matrix based on a field of view using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise. /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @param fov Expressed in radians. /// @param width Width of the viewport /// @param height Height of the viewport /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovNO( T fov, T width, T height, T near, T far); /// Builds a right handed perspective projection matrix based on a field of view. /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @param fov Expressed in radians. /// @param width Width of the viewport /// @param height Height of the viewport /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovRH( T fov, T width, T height, T near, T far); /// Builds a left handed perspective projection matrix based on a field of view. /// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @param fov Expressed in radians. /// @param width Width of the viewport /// @param height Height of the viewport /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovLH( T fov, T width, T height, T near, T far); /// Builds a perspective projection matrix based on a field of view and the default handedness and default near and far clip planes definition. /// To change default handedness use GLM_FORCE_LEFT_HANDED. To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. /// /// @param fov Expressed in radians. /// @param width Width of the viewport /// @param height Height of the viewport /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// @param far Specifies the distance from the viewer to the far clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFov( T fov, T width, T height, T near, T far); /// Creates a matrix for a left handed, symmetric perspective-view frustum with far plane at infinite. /// /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> infinitePerspectiveLH( T fovy, T aspect, T near); /// Creates a matrix for a right handed, symmetric perspective-view frustum with far plane at infinite. /// /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> infinitePerspectiveRH( T fovy, T aspect, T near); /// Creates a matrix for a symmetric perspective-view frustum with far plane at infinite with default handedness. /// /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> infinitePerspective( T fovy, T aspect, T near); /// Creates a matrix for a symmetric perspective-view frustum with far plane at infinite for graphics hardware that doesn't support depth clamping. /// /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> tweakedInfinitePerspective( T fovy, T aspect, T near); /// Creates a matrix for a symmetric perspective-view frustum with far plane at infinite for graphics hardware that doesn't support depth clamping. /// /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians. /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). /// @param near Specifies the distance from the viewer to the near clipping plane (always positive). /// @param ep Epsilon /// /// @tparam T A floating-point scalar type template GLM_FUNC_DECL mat<4, 4, T, defaultp> tweakedInfinitePerspective( T fovy, T aspect, T near, T ep); /// @} }//namespace glm #include "matrix_clip_space.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_clip_space.inl000066400000000000000000000477131360521144700253230ustar00rootroot00000000000000namespace glm { template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> ortho(T left, T right, T bottom, T top) { mat<4, 4, T, defaultp> Result(static_cast(1)); Result[0][0] = static_cast(2) / (right - left); Result[1][1] = static_cast(2) / (top - bottom); Result[2][2] = - static_cast(1); Result[3][0] = - (right + left) / (right - left); Result[3][1] = - (top + bottom) / (top - bottom); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH_ZO(T left, T right, T bottom, T top, T zNear, T zFar) { mat<4, 4, T, defaultp> Result(1); Result[0][0] = static_cast(2) / (right - left); Result[1][1] = static_cast(2) / (top - bottom); Result[2][2] = static_cast(1) / (zFar - zNear); Result[3][0] = - (right + left) / (right - left); Result[3][1] = - (top + bottom) / (top - bottom); Result[3][2] = - zNear / (zFar - zNear); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH_NO(T left, T right, T bottom, T top, T zNear, T zFar) { mat<4, 4, T, defaultp> Result(1); Result[0][0] = static_cast(2) / (right - left); Result[1][1] = static_cast(2) / (top - bottom); Result[2][2] = static_cast(2) / (zFar - zNear); Result[3][0] = - (right + left) / (right - left); Result[3][1] = - (top + bottom) / (top - bottom); Result[3][2] = - (zFar + zNear) / (zFar - zNear); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH_ZO(T left, T right, T bottom, T top, T zNear, T zFar) { mat<4, 4, T, defaultp> Result(1); Result[0][0] = static_cast(2) / (right - left); Result[1][1] = static_cast(2) / (top - bottom); Result[2][2] = - static_cast(1) / (zFar - zNear); Result[3][0] = - (right + left) / (right - left); Result[3][1] = - (top + bottom) / (top - bottom); Result[3][2] = - zNear / (zFar - zNear); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH_NO(T left, T right, T bottom, T top, T zNear, T zFar) { mat<4, 4, T, defaultp> Result(1); Result[0][0] = static_cast(2) / (right - left); Result[1][1] = static_cast(2) / (top - bottom); Result[2][2] = - static_cast(2) / (zFar - zNear); Result[3][0] = - (right + left) / (right - left); Result[3][1] = - (top + bottom) / (top - bottom); Result[3][2] = - (zFar + zNear) / (zFar - zNear); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoZO(T left, T right, T bottom, T top, T zNear, T zFar) { if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) return orthoLH_ZO(left, right, bottom, top, zNear, zFar); else return orthoRH_ZO(left, right, bottom, top, zNear, zFar); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoNO(T left, T right, T bottom, T top, T zNear, T zFar) { if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) return orthoLH_NO(left, right, bottom, top, zNear, zFar); else return orthoRH_NO(left, right, bottom, top, zNear, zFar); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH(T left, T right, T bottom, T top, T zNear, T zFar) { if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT) return orthoLH_ZO(left, right, bottom, top, zNear, zFar); else return orthoLH_NO(left, right, bottom, top, zNear, zFar); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH(T left, T right, T bottom, T top, T zNear, T zFar) { if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT) return orthoRH_ZO(left, right, bottom, top, zNear, zFar); else return orthoRH_NO(left, right, bottom, top, zNear, zFar); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> ortho(T left, T right, T bottom, T top, T zNear, T zFar) { if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO) return orthoLH_ZO(left, right, bottom, top, zNear, zFar); else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO) return orthoLH_NO(left, right, bottom, top, zNear, zFar); else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO) return orthoRH_ZO(left, right, bottom, top, zNear, zFar); else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO) return orthoRH_NO(left, right, bottom, top, zNear, zFar); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH_ZO(T left, T right, T bottom, T top, T nearVal, T farVal) { mat<4, 4, T, defaultp> Result(0); Result[0][0] = (static_cast(2) * nearVal) / (right - left); Result[1][1] = (static_cast(2) * nearVal) / (top - bottom); Result[2][0] = (right + left) / (right - left); Result[2][1] = (top + bottom) / (top - bottom); Result[2][2] = farVal / (farVal - nearVal); Result[2][3] = static_cast(1); Result[3][2] = -(farVal * nearVal) / (farVal - nearVal); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH_NO(T left, T right, T bottom, T top, T nearVal, T farVal) { mat<4, 4, T, defaultp> Result(0); Result[0][0] = (static_cast(2) * nearVal) / (right - left); Result[1][1] = (static_cast(2) * nearVal) / (top - bottom); Result[2][0] = (right + left) / (right - left); Result[2][1] = (top + bottom) / (top - bottom); Result[2][2] = (farVal + nearVal) / (farVal - nearVal); Result[2][3] = static_cast(1); Result[3][2] = - (static_cast(2) * farVal * nearVal) / (farVal - nearVal); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH_ZO(T left, T right, T bottom, T top, T nearVal, T farVal) { mat<4, 4, T, defaultp> Result(0); Result[0][0] = (static_cast(2) * nearVal) / (right - left); Result[1][1] = (static_cast(2) * nearVal) / (top - bottom); Result[2][0] = (right + left) / (right - left); Result[2][1] = (top + bottom) / (top - bottom); Result[2][2] = farVal / (nearVal - farVal); Result[2][3] = static_cast(-1); Result[3][2] = -(farVal * nearVal) / (farVal - nearVal); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH_NO(T left, T right, T bottom, T top, T nearVal, T farVal) { mat<4, 4, T, defaultp> Result(0); Result[0][0] = (static_cast(2) * nearVal) / (right - left); Result[1][1] = (static_cast(2) * nearVal) / (top - bottom); Result[2][0] = (right + left) / (right - left); Result[2][1] = (top + bottom) / (top - bottom); Result[2][2] = - (farVal + nearVal) / (farVal - nearVal); Result[2][3] = static_cast(-1); Result[3][2] = - (static_cast(2) * farVal * nearVal) / (farVal - nearVal); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumZO(T left, T right, T bottom, T top, T nearVal, T farVal) { if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) return frustumLH_ZO(left, right, bottom, top, nearVal, farVal); else return frustumRH_ZO(left, right, bottom, top, nearVal, farVal); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumNO(T left, T right, T bottom, T top, T nearVal, T farVal) { if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) return frustumLH_NO(left, right, bottom, top, nearVal, farVal); else return frustumRH_NO(left, right, bottom, top, nearVal, farVal); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH(T left, T right, T bottom, T top, T nearVal, T farVal) { if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT) return frustumLH_ZO(left, right, bottom, top, nearVal, farVal); else return frustumLH_NO(left, right, bottom, top, nearVal, farVal); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH(T left, T right, T bottom, T top, T nearVal, T farVal) { if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT) return frustumRH_ZO(left, right, bottom, top, nearVal, farVal); else return frustumRH_NO(left, right, bottom, top, nearVal, farVal); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustum(T left, T right, T bottom, T top, T nearVal, T farVal) { if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO) return frustumLH_ZO(left, right, bottom, top, nearVal, farVal); else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO) return frustumLH_NO(left, right, bottom, top, nearVal, farVal); else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO) return frustumRH_ZO(left, right, bottom, top, nearVal, farVal); else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO) return frustumRH_NO(left, right, bottom, top, nearVal, farVal); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH_ZO(T fovy, T aspect, T zNear, T zFar) { assert(abs(aspect - std::numeric_limits::epsilon()) > static_cast(0)); T const tanHalfFovy = tan(fovy / static_cast(2)); mat<4, 4, T, defaultp> Result(static_cast(0)); Result[0][0] = static_cast(1) / (aspect * tanHalfFovy); Result[1][1] = static_cast(1) / (tanHalfFovy); Result[2][2] = zFar / (zNear - zFar); Result[2][3] = - static_cast(1); Result[3][2] = -(zFar * zNear) / (zFar - zNear); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH_NO(T fovy, T aspect, T zNear, T zFar) { assert(abs(aspect - std::numeric_limits::epsilon()) > static_cast(0)); T const tanHalfFovy = tan(fovy / static_cast(2)); mat<4, 4, T, defaultp> Result(static_cast(0)); Result[0][0] = static_cast(1) / (aspect * tanHalfFovy); Result[1][1] = static_cast(1) / (tanHalfFovy); Result[2][2] = - (zFar + zNear) / (zFar - zNear); Result[2][3] = - static_cast(1); Result[3][2] = - (static_cast(2) * zFar * zNear) / (zFar - zNear); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH_ZO(T fovy, T aspect, T zNear, T zFar) { assert(abs(aspect - std::numeric_limits::epsilon()) > static_cast(0)); T const tanHalfFovy = tan(fovy / static_cast(2)); mat<4, 4, T, defaultp> Result(static_cast(0)); Result[0][0] = static_cast(1) / (aspect * tanHalfFovy); Result[1][1] = static_cast(1) / (tanHalfFovy); Result[2][2] = zFar / (zFar - zNear); Result[2][3] = static_cast(1); Result[3][2] = -(zFar * zNear) / (zFar - zNear); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH_NO(T fovy, T aspect, T zNear, T zFar) { assert(abs(aspect - std::numeric_limits::epsilon()) > static_cast(0)); T const tanHalfFovy = tan(fovy / static_cast(2)); mat<4, 4, T, defaultp> Result(static_cast(0)); Result[0][0] = static_cast(1) / (aspect * tanHalfFovy); Result[1][1] = static_cast(1) / (tanHalfFovy); Result[2][2] = (zFar + zNear) / (zFar - zNear); Result[2][3] = static_cast(1); Result[3][2] = - (static_cast(2) * zFar * zNear) / (zFar - zNear); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveZO(T fovy, T aspect, T zNear, T zFar) { if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) return perspectiveLH_ZO(fovy, aspect, zNear, zFar); else return perspectiveRH_ZO(fovy, aspect, zNear, zFar); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveNO(T fovy, T aspect, T zNear, T zFar) { if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) return perspectiveLH_NO(fovy, aspect, zNear, zFar); else return perspectiveRH_NO(fovy, aspect, zNear, zFar); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH(T fovy, T aspect, T zNear, T zFar) { if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT) return perspectiveLH_ZO(fovy, aspect, zNear, zFar); else return perspectiveLH_NO(fovy, aspect, zNear, zFar); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH(T fovy, T aspect, T zNear, T zFar) { if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT) return perspectiveRH_ZO(fovy, aspect, zNear, zFar); else return perspectiveRH_NO(fovy, aspect, zNear, zFar); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspective(T fovy, T aspect, T zNear, T zFar) { GLM_IF_CONSTEXPR(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO) return perspectiveLH_ZO(fovy, aspect, zNear, zFar); else GLM_IF_CONSTEXPR(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO) return perspectiveLH_NO(fovy, aspect, zNear, zFar); else GLM_IF_CONSTEXPR(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO) return perspectiveRH_ZO(fovy, aspect, zNear, zFar); else GLM_IF_CONSTEXPR(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO) return perspectiveRH_NO(fovy, aspect, zNear, zFar); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH_ZO(T fov, T width, T height, T zNear, T zFar) { assert(width > static_cast(0)); assert(height > static_cast(0)); assert(fov > static_cast(0)); T const rad = fov; T const h = glm::cos(static_cast(0.5) * rad) / glm::sin(static_cast(0.5) * rad); T const w = h * height / width; ///todo max(width , Height) / min(width , Height)? mat<4, 4, T, defaultp> Result(static_cast(0)); Result[0][0] = w; Result[1][1] = h; Result[2][2] = zFar / (zNear - zFar); Result[2][3] = - static_cast(1); Result[3][2] = -(zFar * zNear) / (zFar - zNear); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH_NO(T fov, T width, T height, T zNear, T zFar) { assert(width > static_cast(0)); assert(height > static_cast(0)); assert(fov > static_cast(0)); T const rad = fov; T const h = glm::cos(static_cast(0.5) * rad) / glm::sin(static_cast(0.5) * rad); T const w = h * height / width; ///todo max(width , Height) / min(width , Height)? mat<4, 4, T, defaultp> Result(static_cast(0)); Result[0][0] = w; Result[1][1] = h; Result[2][2] = - (zFar + zNear) / (zFar - zNear); Result[2][3] = - static_cast(1); Result[3][2] = - (static_cast(2) * zFar * zNear) / (zFar - zNear); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH_ZO(T fov, T width, T height, T zNear, T zFar) { assert(width > static_cast(0)); assert(height > static_cast(0)); assert(fov > static_cast(0)); T const rad = fov; T const h = glm::cos(static_cast(0.5) * rad) / glm::sin(static_cast(0.5) * rad); T const w = h * height / width; ///todo max(width , Height) / min(width , Height)? mat<4, 4, T, defaultp> Result(static_cast(0)); Result[0][0] = w; Result[1][1] = h; Result[2][2] = zFar / (zFar - zNear); Result[2][3] = static_cast(1); Result[3][2] = -(zFar * zNear) / (zFar - zNear); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH_NO(T fov, T width, T height, T zNear, T zFar) { assert(width > static_cast(0)); assert(height > static_cast(0)); assert(fov > static_cast(0)); T const rad = fov; T const h = glm::cos(static_cast(0.5) * rad) / glm::sin(static_cast(0.5) * rad); T const w = h * height / width; ///todo max(width , Height) / min(width , Height)? mat<4, 4, T, defaultp> Result(static_cast(0)); Result[0][0] = w; Result[1][1] = h; Result[2][2] = (zFar + zNear) / (zFar - zNear); Result[2][3] = static_cast(1); Result[3][2] = - (static_cast(2) * zFar * zNear) / (zFar - zNear); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovZO(T fov, T width, T height, T zNear, T zFar) { if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) return perspectiveFovLH_ZO(fov, width, height, zNear, zFar); else return perspectiveFovRH_ZO(fov, width, height, zNear, zFar); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovNO(T fov, T width, T height, T zNear, T zFar) { if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) return perspectiveFovLH_NO(fov, width, height, zNear, zFar); else return perspectiveFovRH_NO(fov, width, height, zNear, zFar); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH(T fov, T width, T height, T zNear, T zFar) { if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT) return perspectiveFovLH_ZO(fov, width, height, zNear, zFar); else return perspectiveFovLH_NO(fov, width, height, zNear, zFar); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH(T fov, T width, T height, T zNear, T zFar) { if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT) return perspectiveFovRH_ZO(fov, width, height, zNear, zFar); else return perspectiveFovRH_NO(fov, width, height, zNear, zFar); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFov(T fov, T width, T height, T zNear, T zFar) { if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO) return perspectiveFovLH_ZO(fov, width, height, zNear, zFar); else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO) return perspectiveFovLH_NO(fov, width, height, zNear, zFar); else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO) return perspectiveFovRH_ZO(fov, width, height, zNear, zFar); else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO) return perspectiveFovRH_NO(fov, width, height, zNear, zFar); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspectiveRH(T fovy, T aspect, T zNear) { T const range = tan(fovy / static_cast(2)) * zNear; T const left = -range * aspect; T const right = range * aspect; T const bottom = -range; T const top = range; mat<4, 4, T, defaultp> Result(static_cast(0)); Result[0][0] = (static_cast(2) * zNear) / (right - left); Result[1][1] = (static_cast(2) * zNear) / (top - bottom); Result[2][2] = - static_cast(1); Result[2][3] = - static_cast(1); Result[3][2] = - static_cast(2) * zNear; return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspectiveLH(T fovy, T aspect, T zNear) { T const range = tan(fovy / static_cast(2)) * zNear; T const left = -range * aspect; T const right = range * aspect; T const bottom = -range; T const top = range; mat<4, 4, T, defaultp> Result(T(0)); Result[0][0] = (static_cast(2) * zNear) / (right - left); Result[1][1] = (static_cast(2) * zNear) / (top - bottom); Result[2][2] = static_cast(1); Result[2][3] = static_cast(1); Result[3][2] = - static_cast(2) * zNear; return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspective(T fovy, T aspect, T zNear) { if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) return infinitePerspectiveLH(fovy, aspect, zNear); else return infinitePerspectiveRH(fovy, aspect, zNear); } // Infinite projection matrix: http://www.terathon.com/gdc07_lengyel.pdf template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> tweakedInfinitePerspective(T fovy, T aspect, T zNear, T ep) { T const range = tan(fovy / static_cast(2)) * zNear; T const left = -range * aspect; T const right = range * aspect; T const bottom = -range; T const top = range; mat<4, 4, T, defaultp> Result(static_cast(0)); Result[0][0] = (static_cast(2) * zNear) / (right - left); Result[1][1] = (static_cast(2) * zNear) / (top - bottom); Result[2][2] = ep - static_cast(1); Result[2][3] = static_cast(-1); Result[3][2] = (ep - static_cast(2)) * zNear; return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> tweakedInfinitePerspective(T fovy, T aspect, T zNear) { return tweakedInfinitePerspective(fovy, aspect, zNear, epsilon()); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_common.hpp000066400000000000000000000020071360521144700245010ustar00rootroot00000000000000/// @ref ext_matrix_common /// @file glm/ext/matrix_common.hpp /// /// @defgroup ext_matrix_common GLM_EXT_matrix_common /// @ingroup ext /// /// Defines functions for common matrix operations. /// /// Include to use the features of this extension. /// /// @see ext_matrix_common #pragma once #include "../detail/qualifier.hpp" #include "../detail/_fixes.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_matrix_transform extension included") #endif namespace glm { /// @addtogroup ext_matrix_common /// @{ template GLM_FUNC_DECL mat mix(mat const& x, mat const& y, mat const& a); template GLM_FUNC_DECL mat mix(mat const& x, mat const& y, U a); /// @} }//namespace glm #include "matrix_common.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_common.inl000066400000000000000000000011711360521144700244750ustar00rootroot00000000000000#include "../matrix.hpp" namespace glm { template GLM_FUNC_QUALIFIER mat mix(mat const& x, mat const& y, U a) { return mat(x) * (static_cast(1) - a) + mat(y) * a; } template GLM_FUNC_QUALIFIER mat mix(mat const& x, mat const& y, mat const& a) { return matrixCompMult(mat(x), static_cast(1) - a) + matrixCompMult(mat(y), a); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_double2x2.hpp000066400000000000000000000013431360521144700250210ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_double2x2.hpp #pragma once #include "../detail/type_mat2x2.hpp" namespace glm { /// @addtogroup core_matrix /// @{ /// 2 columns of 2 components matrix of double-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<2, 2, double, defaultp> dmat2x2; /// 2 columns of 2 components matrix of double-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<2, 2, double, defaultp> dmat2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_double2x2_precision.hpp000066400000000000000000000057131360521144700271010ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_double2x2_precision.hpp #pragma once #include "../detail/type_mat2x2.hpp" namespace glm { /// @addtogroup core_matrix_precision /// @{ /// 2 columns of 2 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 2, double, lowp> lowp_dmat2; /// 2 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 2, double, mediump> mediump_dmat2; /// 2 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 2, double, highp> highp_dmat2; /// 2 columns of 2 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 2, double, lowp> lowp_dmat2x2; /// 2 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 2, double, mediump> mediump_dmat2x2; /// 2 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 2, double, highp> highp_dmat2x2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_double2x3.hpp000066400000000000000000000007251360521144700250250ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_double2x3.hpp #pragma once #include "../detail/type_mat2x3.hpp" namespace glm { /// @addtogroup core_matrix /// @{ /// 2 columns of 3 components matrix of double-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<2, 3, double, defaultp> dmat2x3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_double2x3_precision.hpp000066400000000000000000000031251360521144700270750ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_double2x3_precision.hpp #pragma once #include "../detail/type_mat2x3.hpp" namespace glm { /// @addtogroup core_matrix_precision /// @{ /// 2 columns of 3 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 3, double, lowp> lowp_dmat2x3; /// 2 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 3, double, mediump> mediump_dmat2x3; /// 2 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 3, double, highp> highp_dmat2x3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_double2x4.hpp000066400000000000000000000007251360521144700250260ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_double2x4.hpp #pragma once #include "../detail/type_mat2x4.hpp" namespace glm { /// @addtogroup core_matrix /// @{ /// 2 columns of 4 components matrix of double-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<2, 4, double, defaultp> dmat2x4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_double2x4_precision.hpp000066400000000000000000000031251360521144700270760ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_double2x4_precision.hpp #pragma once #include "../detail/type_mat2x4.hpp" namespace glm { /// @addtogroup core_matrix_precision /// @{ /// 2 columns of 4 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 4, double, lowp> lowp_dmat2x4; /// 2 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 4, double, mediump> mediump_dmat2x4; /// 2 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 4, double, highp> highp_dmat2x4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_double3x2.hpp000066400000000000000000000007251360521144700250250ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_double3x2.hpp #pragma once #include "../detail/type_mat3x2.hpp" namespace glm { /// @addtogroup core_matrix /// @{ /// 3 columns of 2 components matrix of double-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<3, 2, double, defaultp> dmat3x2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_double3x2_precision.hpp000066400000000000000000000031251360521144700270750ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_double3x2_precision.hpp #pragma once #include "../detail/type_mat3x2.hpp" namespace glm { /// @addtogroup core_matrix_precision /// @{ /// 3 columns of 2 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 2, double, lowp> lowp_dmat3x2; /// 3 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 2, double, mediump> mediump_dmat3x2; /// 3 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 2, double, highp> highp_dmat3x2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_double3x3.hpp000066400000000000000000000013431360521144700250230ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_double3x3.hpp #pragma once #include "../detail/type_mat3x3.hpp" namespace glm { /// @addtogroup core_matrix /// @{ /// 3 columns of 3 components matrix of double-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<3, 3, double, defaultp> dmat3x3; /// 3 columns of 3 components matrix of double-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<3, 3, double, defaultp> dmat3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_double3x3_precision.hpp000066400000000000000000000057131360521144700271030ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_double3x3_precision.hpp #pragma once #include "../detail/type_mat3x3.hpp" namespace glm { /// @addtogroup core_matrix_precision /// @{ /// 3 columns of 3 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 3, double, lowp> lowp_dmat3; /// 3 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 3, double, mediump> mediump_dmat3; /// 3 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 3, double, highp> highp_dmat3; /// 3 columns of 3 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 3, double, lowp> lowp_dmat3x3; /// 3 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 3, double, mediump> mediump_dmat3x3; /// 3 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 3, double, highp> highp_dmat3x3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_double3x4.hpp000066400000000000000000000007251360521144700250270ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_double3x4.hpp #pragma once #include "../detail/type_mat3x4.hpp" namespace glm { /// @addtogroup core_matrix /// @{ /// 3 columns of 4 components matrix of double-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<3, 4, double, defaultp> dmat3x4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_double3x4_precision.hpp000066400000000000000000000031251360521144700270770ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_double3x4_precision.hpp #pragma once #include "../detail/type_mat3x4.hpp" namespace glm { /// @addtogroup core_matrix_precision /// @{ /// 3 columns of 4 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 4, double, lowp> lowp_dmat3x4; /// 3 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 4, double, mediump> mediump_dmat3x4; /// 3 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 4, double, highp> highp_dmat3x4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_double4x2.hpp000066400000000000000000000007251360521144700250260ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_double4x2.hpp #pragma once #include "../detail/type_mat4x2.hpp" namespace glm { /// @addtogroup core_matrix /// @{ /// 4 columns of 2 components matrix of double-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<4, 2, double, defaultp> dmat4x2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_double4x2_precision.hpp000066400000000000000000000031251360521144700270760ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_double4x2_precision.hpp #pragma once #include "../detail/type_mat4x2.hpp" namespace glm { /// @addtogroup core_matrix_precision /// @{ /// 4 columns of 2 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 2, double, lowp> lowp_dmat4x2; /// 4 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 2, double, mediump> mediump_dmat4x2; /// 4 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 2, double, highp> highp_dmat4x2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_double4x3.hpp000066400000000000000000000007251360521144700250270ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_double4x3.hpp #pragma once #include "../detail/type_mat4x3.hpp" namespace glm { /// @addtogroup core_matrix /// @{ /// 4 columns of 3 components matrix of double-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<4, 3, double, defaultp> dmat4x3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_double4x3_precision.hpp000066400000000000000000000031251360521144700270770ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_double4x3_precision.hpp #pragma once #include "../detail/type_mat4x3.hpp" namespace glm { /// @addtogroup core_matrix_precision /// @{ /// 4 columns of 3 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 3, double, lowp> lowp_dmat4x3; /// 4 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 3, double, mediump> mediump_dmat4x3; /// 4 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 3, double, highp> highp_dmat4x3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_double4x4.hpp000066400000000000000000000013431360521144700250250ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_double4x4.hpp #pragma once #include "../detail/type_mat4x4.hpp" namespace glm { /// @addtogroup core_matrix /// @{ /// 4 columns of 4 components matrix of double-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<4, 4, double, defaultp> dmat4x4; /// 4 columns of 4 components matrix of double-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<4, 4, double, defaultp> dmat4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_double4x4_precision.hpp000066400000000000000000000057131360521144700271050ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_double4x4_precision.hpp #pragma once #include "../detail/type_mat4x4.hpp" namespace glm { /// @addtogroup core_matrix_precision /// @{ /// 4 columns of 4 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 4, double, lowp> lowp_dmat4; /// 4 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 4, double, mediump> mediump_dmat4; /// 4 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 4, double, highp> highp_dmat4; /// 4 columns of 4 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 4, double, lowp> lowp_dmat4x4; /// 4 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 4, double, mediump> mediump_dmat4x4; /// 4 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 4, double, highp> highp_dmat4x4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_float2x2.hpp000066400000000000000000000013361360521144700246560ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_float2x2.hpp #pragma once #include "../detail/type_mat2x2.hpp" namespace glm { /// @addtogroup core_matrix /// @{ /// 2 columns of 2 components matrix of single-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<2, 2, float, defaultp> mat2x2; /// 2 columns of 2 components matrix of single-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<2, 2, float, defaultp> mat2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_float2x2_precision.hpp000066400000000000000000000056741360521144700267420ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_float2x2_precision.hpp #pragma once #include "../detail/type_mat2x2.hpp" namespace glm { /// @addtogroup core_matrix_precision /// @{ /// 2 columns of 2 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 2, float, lowp> lowp_mat2; /// 2 columns of 2 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 2, float, mediump> mediump_mat2; /// 2 columns of 2 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 2, float, highp> highp_mat2; /// 2 columns of 2 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 2, float, lowp> lowp_mat2x2; /// 2 columns of 2 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 2, float, mediump> mediump_mat2x2; /// 2 columns of 2 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 2, float, highp> highp_mat2x2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_float2x3.hpp000066400000000000000000000007221360521144700246550ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_float2x3.hpp #pragma once #include "../detail/type_mat2x3.hpp" namespace glm { /// @addtogroup core_matrix /// @{ /// 2 columns of 3 components matrix of single-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<2, 3, float, defaultp> mat2x3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_float2x3_precision.hpp000066400000000000000000000031151360521144700267270ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_float2x3_precision.hpp #pragma once #include "../detail/type_mat2x3.hpp" namespace glm { /// @addtogroup core_matrix_precision /// @{ /// 2 columns of 3 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 3, float, lowp> lowp_mat2x3; /// 2 columns of 3 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 3, float, mediump> mediump_mat2x3; /// 2 columns of 3 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 3, float, highp> highp_mat2x3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_float2x4.hpp000066400000000000000000000007221360521144700246560ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_float2x4.hpp #pragma once #include "../detail/type_mat2x4.hpp" namespace glm { /// @addtogroup core_matrix /// @{ /// 2 columns of 4 components matrix of single-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<2, 4, float, defaultp> mat2x4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_float2x4_precision.hpp000066400000000000000000000031151360521144700267300ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_float2x4_precision.hpp #pragma once #include "../detail/type_mat2x4.hpp" namespace glm { /// @addtogroup core_matrix_precision /// @{ /// 2 columns of 4 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 4, float, lowp> lowp_mat2x4; /// 2 columns of 4 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 4, float, mediump> mediump_mat2x4; /// 2 columns of 4 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<2, 4, float, highp> highp_mat2x4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_float3x2.hpp000066400000000000000000000007141360521144700246560ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_float3x2.hpp #pragma once #include "../detail/type_mat3x2.hpp" namespace glm { /// @addtogroup core /// @{ /// 3 columns of 2 components matrix of single-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<3, 2, float, defaultp> mat3x2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_float3x2_precision.hpp000066400000000000000000000031151360521144700267270ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_float3x2_precision.hpp #pragma once #include "../detail/type_mat3x2.hpp" namespace glm { /// @addtogroup core_matrix_precision /// @{ /// 3 columns of 2 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 2, float, lowp> lowp_mat3x2; /// 3 columns of 2 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 2, float, mediump> mediump_mat3x2; /// 3 columns of 2 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 2, float, highp> highp_mat3x2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_float3x3.hpp000066400000000000000000000013401360521144700246530ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_float3x3.hpp #pragma once #include "../detail/type_mat3x3.hpp" namespace glm { /// @addtogroup core_matrix /// @{ /// 3 columns of 3 components matrix of single-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<3, 3, float, defaultp> mat3x3; /// 3 columns of 3 components matrix of single-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<3, 3, float, defaultp> mat3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_float3x3_precision.hpp000066400000000000000000000056741360521144700267440ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_float3x3_precision.hpp #pragma once #include "../detail/type_mat3x3.hpp" namespace glm { /// @addtogroup core_matrix_precision /// @{ /// 3 columns of 3 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 3, float, lowp> lowp_mat3; /// 3 columns of 3 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 3, float, mediump> mediump_mat3; /// 3 columns of 3 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 3, float, highp> highp_mat3; /// 3 columns of 3 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 3, float, lowp> lowp_mat3x3; /// 3 columns of 3 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 3, float, mediump> mediump_mat3x3; /// 3 columns of 3 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 3, float, highp> highp_mat3x3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_float3x4.hpp000066400000000000000000000007231360521144700246600ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_float3x4.hpp #pragma once #include "../detail/type_mat3x4.hpp" namespace glm { /// @addtogroup core_matrix /// @{ /// 3 columns of 4 components matrix of single-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<3, 4, float, defaultp> mat3x4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_float3x4_precision.hpp000066400000000000000000000031151360521144700267310ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_float3x4_precision.hpp #pragma once #include "../detail/type_mat3x4.hpp" namespace glm { /// @addtogroup core_matrix_precision /// @{ /// 3 columns of 4 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 4, float, lowp> lowp_mat3x4; /// 3 columns of 4 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 4, float, mediump> mediump_mat3x4; /// 3 columns of 4 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<3, 4, float, highp> highp_mat3x4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_float4x2.hpp000066400000000000000000000007231360521144700246570ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_float4x2.hpp #pragma once #include "../detail/type_mat4x2.hpp" namespace glm { /// @addtogroup core_matrix /// @{ /// 4 columns of 2 components matrix of single-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<4, 2, float, defaultp> mat4x2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_float4x2_precision.hpp000066400000000000000000000031151360521144700267300ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_float2x2_precision.hpp #pragma once #include "../detail/type_mat2x2.hpp" namespace glm { /// @addtogroup core_matrix_precision /// @{ /// 4 columns of 2 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 2, float, lowp> lowp_mat4x2; /// 4 columns of 2 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 2, float, mediump> mediump_mat4x2; /// 4 columns of 2 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 2, float, highp> highp_mat4x2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_float4x3.hpp000066400000000000000000000007231360521144700246600ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_float4x3.hpp #pragma once #include "../detail/type_mat4x3.hpp" namespace glm { /// @addtogroup core_matrix /// @{ /// 4 columns of 3 components matrix of single-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<4, 3, float, defaultp> mat4x3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_float4x3_precision.hpp000066400000000000000000000031151360521144700267310ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_float4x3_precision.hpp #pragma once #include "../detail/type_mat4x3.hpp" namespace glm { /// @addtogroup core_matrix_precision /// @{ /// 4 columns of 3 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 3, float, lowp> lowp_mat4x3; /// 4 columns of 3 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 3, float, mediump> mediump_mat4x3; /// 4 columns of 3 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 3, float, highp> highp_mat4x3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_float4x4.hpp000066400000000000000000000013351360521144700246610ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_float4x4.hpp #pragma once #include "../detail/type_mat4x4.hpp" namespace glm { /// @ingroup core_matrix /// @{ /// 4 columns of 4 components matrix of single-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<4, 4, float, defaultp> mat4x4; /// 4 columns of 4 components matrix of single-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices typedef mat<4, 4, float, defaultp> mat4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_float4x4_precision.hpp000066400000000000000000000056741360521144700267460ustar00rootroot00000000000000/// @ref core /// @file glm/ext/matrix_float4x4_precision.hpp #pragma once #include "../detail/type_mat4x4.hpp" namespace glm { /// @addtogroup core_matrix_precision /// @{ /// 4 columns of 4 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 4, float, lowp> lowp_mat4; /// 4 columns of 4 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 4, float, mediump> mediump_mat4; /// 4 columns of 4 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 4, float, highp> highp_mat4; /// 4 columns of 4 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 4, float, lowp> lowp_mat4x4; /// 4 columns of 4 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 4, float, mediump> mediump_mat4x4; /// 4 columns of 4 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs. /// /// @see GLSL 4.20.8 specification, section 4.1.6 Matrices /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef mat<4, 4, float, highp> highp_mat4x4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_projection.hpp000066400000000000000000000200151360521144700253640ustar00rootroot00000000000000/// @ref ext_matrix_projection /// @file glm/ext/matrix_projection.hpp /// /// @defgroup ext_matrix_projection GLM_EXT_matrix_projection /// @ingroup ext /// /// Functions that generate common projection transformation matrices. /// /// The matrices generated by this extension use standard OpenGL fixed-function /// conventions. For example, the lookAt function generates a transform from world /// space into the specific eye space that the projective matrix functions /// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility /// specifications defines the particular layout of this eye space. /// /// Include to use the features of this extension. /// /// @see ext_matrix_transform /// @see ext_matrix_clip_space #pragma once // Dependencies #include "../gtc/constants.hpp" #include "../geometric.hpp" #include "../trigonometric.hpp" #include "../matrix.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_matrix_projection extension included") #endif namespace glm { /// @addtogroup ext_matrix_projection /// @{ /// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates. /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// /// @param obj Specify the object coordinates. /// @param model Specifies the current modelview matrix /// @param proj Specifies the current projection matrix /// @param viewport Specifies the current viewport /// @return Return the computed window coordinates. /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. /// @tparam U Currently supported: Floating-point types and integer types. /// /// @see gluProject man page template GLM_FUNC_DECL vec<3, T, Q> projectZO( vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); /// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates. /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @param obj Specify the object coordinates. /// @param model Specifies the current modelview matrix /// @param proj Specifies the current projection matrix /// @param viewport Specifies the current viewport /// @return Return the computed window coordinates. /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. /// @tparam U Currently supported: Floating-point types and integer types. /// /// @see gluProject man page template GLM_FUNC_DECL vec<3, T, Q> projectNO( vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); /// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates using default near and far clip planes definition. /// To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. /// /// @param obj Specify the object coordinates. /// @param model Specifies the current modelview matrix /// @param proj Specifies the current projection matrix /// @param viewport Specifies the current viewport /// @return Return the computed window coordinates. /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. /// @tparam U Currently supported: Floating-point types and integer types. /// /// @see gluProject man page template GLM_FUNC_DECL vec<3, T, Q> project( vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); /// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates. /// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition) /// /// @param win Specify the window coordinates to be mapped. /// @param model Specifies the modelview matrix /// @param proj Specifies the projection matrix /// @param viewport Specifies the viewport /// @return Returns the computed object coordinates. /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. /// @tparam U Currently supported: Floating-point types and integer types. /// /// @see gluUnProject man page template GLM_FUNC_DECL vec<3, T, Q> unProjectZO( vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); /// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates. /// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition) /// /// @param win Specify the window coordinates to be mapped. /// @param model Specifies the modelview matrix /// @param proj Specifies the projection matrix /// @param viewport Specifies the viewport /// @return Returns the computed object coordinates. /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. /// @tparam U Currently supported: Floating-point types and integer types. /// /// @see gluUnProject man page template GLM_FUNC_DECL vec<3, T, Q> unProjectNO( vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); /// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates using default near and far clip planes definition. /// To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE. /// /// @param win Specify the window coordinates to be mapped. /// @param model Specifies the modelview matrix /// @param proj Specifies the projection matrix /// @param viewport Specifies the viewport /// @return Returns the computed object coordinates. /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. /// @tparam U Currently supported: Floating-point types and integer types. /// /// @see gluUnProject man page template GLM_FUNC_DECL vec<3, T, Q> unProject( vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport); /// Define a picking region /// /// @param center Specify the center of a picking region in window coordinates. /// @param delta Specify the width and height, respectively, of the picking region in window coordinates. /// @param viewport Rendering viewport /// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double. /// @tparam U Currently supported: Floating-point types and integer types. /// /// @see gluPickMatrix man page template GLM_FUNC_DECL mat<4, 4, T, Q> pickMatrix( vec<2, T, Q> const& center, vec<2, T, Q> const& delta, vec<4, U, Q> const& viewport); /// @} }//namespace glm #include "matrix_projection.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_projection.inl000066400000000000000000000077151360521144700253730ustar00rootroot00000000000000namespace glm { template GLM_FUNC_QUALIFIER vec<3, T, Q> projectZO(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) { vec<4, T, Q> tmp = vec<4, T, Q>(obj, static_cast(1)); tmp = model * tmp; tmp = proj * tmp; tmp /= tmp.w; tmp.x = tmp.x * static_cast(0.5) + static_cast(0.5); tmp.y = tmp.y * static_cast(0.5) + static_cast(0.5); tmp[0] = tmp[0] * T(viewport[2]) + T(viewport[0]); tmp[1] = tmp[1] * T(viewport[3]) + T(viewport[1]); return vec<3, T, Q>(tmp); } template GLM_FUNC_QUALIFIER vec<3, T, Q> projectNO(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) { vec<4, T, Q> tmp = vec<4, T, Q>(obj, static_cast(1)); tmp = model * tmp; tmp = proj * tmp; tmp /= tmp.w; tmp = tmp * static_cast(0.5) + static_cast(0.5); tmp[0] = tmp[0] * T(viewport[2]) + T(viewport[0]); tmp[1] = tmp[1] * T(viewport[3]) + T(viewport[1]); return vec<3, T, Q>(tmp); } template GLM_FUNC_QUALIFIER vec<3, T, Q> project(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) { if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT) return projectZO(obj, model, proj, viewport); else return projectNO(obj, model, proj, viewport); } template GLM_FUNC_QUALIFIER vec<3, T, Q> unProjectZO(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) { mat<4, 4, T, Q> Inverse = inverse(proj * model); vec<4, T, Q> tmp = vec<4, T, Q>(win, T(1)); tmp.x = (tmp.x - T(viewport[0])) / T(viewport[2]); tmp.y = (tmp.y - T(viewport[1])) / T(viewport[3]); tmp.x = tmp.x * static_cast(2) - static_cast(1); tmp.y = tmp.y * static_cast(2) - static_cast(1); vec<4, T, Q> obj = Inverse * tmp; obj /= obj.w; return vec<3, T, Q>(obj); } template GLM_FUNC_QUALIFIER vec<3, T, Q> unProjectNO(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) { mat<4, 4, T, Q> Inverse = inverse(proj * model); vec<4, T, Q> tmp = vec<4, T, Q>(win, T(1)); tmp.x = (tmp.x - T(viewport[0])) / T(viewport[2]); tmp.y = (tmp.y - T(viewport[1])) / T(viewport[3]); tmp = tmp * static_cast(2) - static_cast(1); vec<4, T, Q> obj = Inverse * tmp; obj /= obj.w; return vec<3, T, Q>(obj); } template GLM_FUNC_QUALIFIER vec<3, T, Q> unProject(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport) { if(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT) return unProjectZO(win, model, proj, viewport); else return unProjectNO(win, model, proj, viewport); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> pickMatrix(vec<2, T, Q> const& center, vec<2, T, Q> const& delta, vec<4, U, Q> const& viewport) { assert(delta.x > static_cast(0) && delta.y > static_cast(0)); mat<4, 4, T, Q> Result(static_cast(1)); if(!(delta.x > static_cast(0) && delta.y > static_cast(0))) return Result; // Error vec<3, T, Q> Temp( (static_cast(viewport[2]) - static_cast(2) * (center.x - static_cast(viewport[0]))) / delta.x, (static_cast(viewport[3]) - static_cast(2) * (center.y - static_cast(viewport[1]))) / delta.y, static_cast(0)); // Translate and scale the picked region to the entire window Result = translate(Result, Temp); return scale(Result, vec<3, T, Q>(static_cast(viewport[2]) / delta.x, static_cast(viewport[3]) / delta.y, static_cast(1))); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_relational.hpp000066400000000000000000000152721360521144700253530ustar00rootroot00000000000000/// @ref ext_matrix_relational /// @file glm/ext/matrix_relational.hpp /// /// @defgroup ext_matrix_relational GLM_EXT_matrix_relational /// @ingroup ext /// /// Exposes comparison functions for matrix types that take a user defined epsilon values. /// /// Include to use the features of this extension. /// /// @see ext_vector_relational /// @see ext_scalar_relational /// @see ext_quaternion_relational #pragma once // Dependencies #include "../detail/qualifier.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_matrix_relational extension included") #endif namespace glm { /// @addtogroup ext_matrix_relational /// @{ /// Perform a component-wise equal-to comparison of two matrices. /// Return a boolean vector which components value is True if this expression is satisfied per column of the matrices. /// /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec equal(mat const& x, mat const& y); /// Perform a component-wise not-equal-to comparison of two matrices. /// Return a boolean vector which components value is True if this expression is satisfied per column of the matrices. /// /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y); /// Returns the component-wise comparison of |x - y| < epsilon. /// True if this expression is satisfied. /// /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec equal(mat const& x, mat const& y, T epsilon); /// Returns the component-wise comparison of |x - y| < epsilon. /// True if this expression is satisfied. /// /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec equal(mat const& x, mat const& y, vec const& epsilon); /// Returns the component-wise comparison of |x - y| < epsilon. /// True if this expression is not satisfied. /// /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, T epsilon); /// Returns the component-wise comparison of |x - y| >= epsilon. /// True if this expression is not satisfied. /// /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, vec const& epsilon); /// Returns the component-wise comparison between two vectors in term of ULPs. /// True if this expression is satisfied. /// /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix /// @tparam T Floating-point /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec equal(mat const& x, mat const& y, int ULPs); /// Returns the component-wise comparison between two vectors in term of ULPs. /// True if this expression is satisfied. /// /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix /// @tparam T Floating-point /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec equal(mat const& x, mat const& y, vec const& ULPs); /// Returns the component-wise comparison between two vectors in term of ULPs. /// True if this expression is not satisfied. /// /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix /// @tparam T Floating-point /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, int ULPs); /// Returns the component-wise comparison between two vectors in term of ULPs. /// True if this expression is not satisfied. /// /// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix /// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix /// @tparam T Floating-point /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, vec const& ULPs); /// @} }//namespace glm #include "matrix_relational.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_relational.inl000066400000000000000000000057001360521144700253410ustar00rootroot00000000000000/// @ref ext_vector_relational /// @file glm/ext/vector_relational.inl // Dependency: #include "../ext/vector_relational.hpp" #include "../common.hpp" namespace glm { template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(mat const& a, mat const& b) { return equal(a, b, static_cast(0)); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(mat const& a, mat const& b, T Epsilon) { return equal(a, b, vec(Epsilon)); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(mat const& a, mat const& b, vec const& Epsilon) { vec Result(true); for(length_t i = 0; i < C; ++i) Result[i] = all(equal(a[i], b[i], Epsilon[i])); return Result; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y) { return notEqual(x, y, static_cast(0)); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, T Epsilon) { return notEqual(x, y, vec(Epsilon)); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(mat const& a, mat const& b, vec const& Epsilon) { vec Result(true); for(length_t i = 0; i < C; ++i) Result[i] = any(notEqual(a[i], b[i], Epsilon[i])); return Result; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(mat const& a, mat const& b, int MaxULPs) { return equal(a, b, vec(MaxULPs)); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(mat const& a, mat const& b, vec const& MaxULPs) { vec Result(true); for(length_t i = 0; i < C; ++i) Result[i] = all(equal(a[i], b[i], MaxULPs[i])); return Result; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(mat const& x, mat const& y, int MaxULPs) { return notEqual(x, y, vec(MaxULPs)); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(mat const& a, mat const& b, vec const& MaxULPs) { vec Result(true); for(length_t i = 0; i < C; ++i) Result[i] = any(notEqual(a[i], b[i], MaxULPs[i])); return Result; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_transform.hpp000066400000000000000000000140321360521144700252250ustar00rootroot00000000000000/// @ref ext_matrix_transform /// @file glm/ext/matrix_transform.hpp /// /// @defgroup ext_matrix_transform GLM_EXT_matrix_transform /// @ingroup ext /// /// Defines functions that generate common transformation matrices. /// /// The matrices generated by this extension use standard OpenGL fixed-function /// conventions. For example, the lookAt function generates a transform from world /// space into the specific eye space that the projective matrix functions /// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility /// specifications defines the particular layout of this eye space. /// /// Include to use the features of this extension. /// /// @see ext_matrix_projection /// @see ext_matrix_clip_space #pragma once // Dependencies #include "../gtc/constants.hpp" #include "../geometric.hpp" #include "../trigonometric.hpp" #include "../matrix.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_matrix_transform extension included") #endif namespace glm { /// @addtogroup ext_matrix_transform /// @{ /// Builds an identity matrix. template GLM_FUNC_DECL GLM_CONSTEXPR genType identity(); /// Builds a translation 4 * 4 matrix created from a vector of 3 components. /// /// @param m Input matrix multiplied by this translation matrix. /// @param v Coordinates of a translation vector. /// /// @tparam T A floating-point scalar type /// @tparam Q A value from qualifier enum /// /// @code /// #include /// #include /// ... /// glm::mat4 m = glm::translate(glm::mat4(1.0f), glm::vec3(1.0f)); /// // m[0][0] == 1.0f, m[0][1] == 0.0f, m[0][2] == 0.0f, m[0][3] == 0.0f /// // m[1][0] == 0.0f, m[1][1] == 1.0f, m[1][2] == 0.0f, m[1][3] == 0.0f /// // m[2][0] == 0.0f, m[2][1] == 0.0f, m[2][2] == 1.0f, m[2][3] == 0.0f /// // m[3][0] == 1.0f, m[3][1] == 1.0f, m[3][2] == 1.0f, m[3][3] == 1.0f /// @endcode /// /// @see - translate(mat<4, 4, T, Q> const& m, T x, T y, T z) /// @see - translate(vec<3, T, Q> const& v) /// @see glTranslate man page template GLM_FUNC_DECL mat<4, 4, T, Q> translate( mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v); /// Builds a rotation 4 * 4 matrix created from an axis vector and an angle. /// /// @param m Input matrix multiplied by this rotation matrix. /// @param angle Rotation angle expressed in radians. /// @param axis Rotation axis, recommended to be normalized. /// /// @tparam T A floating-point scalar type /// @tparam Q A value from qualifier enum /// /// @see - rotate(mat<4, 4, T, Q> const& m, T angle, T x, T y, T z) /// @see - rotate(T angle, vec<3, T, Q> const& v) /// @see glRotate man page template GLM_FUNC_DECL mat<4, 4, T, Q> rotate( mat<4, 4, T, Q> const& m, T angle, vec<3, T, Q> const& axis); /// Builds a scale 4 * 4 matrix created from 3 scalars. /// /// @param m Input matrix multiplied by this scale matrix. /// @param v Ratio of scaling for each axis. /// /// @tparam T A floating-point scalar type /// @tparam Q A value from qualifier enum /// /// @see - scale(mat<4, 4, T, Q> const& m, T x, T y, T z) /// @see - scale(vec<3, T, Q> const& v) /// @see glScale man page template GLM_FUNC_DECL mat<4, 4, T, Q> scale( mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v); /// Build a right handed look at view matrix. /// /// @param eye Position of the camera /// @param center Position where the camera is looking at /// @param up Normalized up vector, how the camera is oriented. Typically (0, 0, 1) /// /// @tparam T A floating-point scalar type /// @tparam Q A value from qualifier enum /// /// @see - frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) template GLM_FUNC_DECL mat<4, 4, T, Q> lookAtRH( vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up); /// Build a left handed look at view matrix. /// /// @param eye Position of the camera /// @param center Position where the camera is looking at /// @param up Normalized up vector, how the camera is oriented. Typically (0, 0, 1) /// /// @tparam T A floating-point scalar type /// @tparam Q A value from qualifier enum /// /// @see - frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) template GLM_FUNC_DECL mat<4, 4, T, Q> lookAtLH( vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up); /// Build a look at view matrix based on the default handedness. /// /// @param eye Position of the camera /// @param center Position where the camera is looking at /// @param up Normalized up vector, how the camera is oriented. Typically (0, 0, 1) /// /// @tparam T A floating-point scalar type /// @tparam Q A value from qualifier enum /// /// @see - frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) /// @see gluLookAt man page template GLM_FUNC_DECL mat<4, 4, T, Q> lookAt( vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up); /// @} }//namespace glm #include "matrix_transform.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext/matrix_transform.inl000066400000000000000000000113611360521144700252220ustar00rootroot00000000000000namespace glm { template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType identity() { return detail::init_gentype::GENTYPE>::identity(); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> translate(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v) { mat<4, 4, T, Q> Result(m); Result[3] = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3]; return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotate(mat<4, 4, T, Q> const& m, T angle, vec<3, T, Q> const& v) { T const a = angle; T const c = cos(a); T const s = sin(a); vec<3, T, Q> axis(normalize(v)); vec<3, T, Q> temp((T(1) - c) * axis); mat<4, 4, T, Q> Rotate; Rotate[0][0] = c + temp[0] * axis[0]; Rotate[0][1] = temp[0] * axis[1] + s * axis[2]; Rotate[0][2] = temp[0] * axis[2] - s * axis[1]; Rotate[1][0] = temp[1] * axis[0] - s * axis[2]; Rotate[1][1] = c + temp[1] * axis[1]; Rotate[1][2] = temp[1] * axis[2] + s * axis[0]; Rotate[2][0] = temp[2] * axis[0] + s * axis[1]; Rotate[2][1] = temp[2] * axis[1] - s * axis[0]; Rotate[2][2] = c + temp[2] * axis[2]; mat<4, 4, T, Q> Result; Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2]; Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2]; Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2]; Result[3] = m[3]; return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotate_slow(mat<4, 4, T, Q> const& m, T angle, vec<3, T, Q> const& v) { T const a = angle; T const c = cos(a); T const s = sin(a); mat<4, 4, T, Q> Result; vec<3, T, Q> axis = normalize(v); Result[0][0] = c + (static_cast(1) - c) * axis.x * axis.x; Result[0][1] = (static_cast(1) - c) * axis.x * axis.y + s * axis.z; Result[0][2] = (static_cast(1) - c) * axis.x * axis.z - s * axis.y; Result[0][3] = static_cast(0); Result[1][0] = (static_cast(1) - c) * axis.y * axis.x - s * axis.z; Result[1][1] = c + (static_cast(1) - c) * axis.y * axis.y; Result[1][2] = (static_cast(1) - c) * axis.y * axis.z + s * axis.x; Result[1][3] = static_cast(0); Result[2][0] = (static_cast(1) - c) * axis.z * axis.x + s * axis.y; Result[2][1] = (static_cast(1) - c) * axis.z * axis.y - s * axis.x; Result[2][2] = c + (static_cast(1) - c) * axis.z * axis.z; Result[2][3] = static_cast(0); Result[3] = vec<4, T, Q>(0, 0, 0, 1); return m * Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scale(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v) { mat<4, 4, T, Q> Result; Result[0] = m[0] * v[0]; Result[1] = m[1] * v[1]; Result[2] = m[2] * v[2]; Result[3] = m[3]; return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scale_slow(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v) { mat<4, 4, T, Q> Result(T(1)); Result[0][0] = v.x; Result[1][1] = v.y; Result[2][2] = v.z; return m * Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtRH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up) { vec<3, T, Q> const f(normalize(center - eye)); vec<3, T, Q> const s(normalize(cross(f, up))); vec<3, T, Q> const u(cross(s, f)); mat<4, 4, T, Q> Result(1); Result[0][0] = s.x; Result[1][0] = s.y; Result[2][0] = s.z; Result[0][1] = u.x; Result[1][1] = u.y; Result[2][1] = u.z; Result[0][2] =-f.x; Result[1][2] =-f.y; Result[2][2] =-f.z; Result[3][0] =-dot(s, eye); Result[3][1] =-dot(u, eye); Result[3][2] = dot(f, eye); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtLH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up) { vec<3, T, Q> const f(normalize(center - eye)); vec<3, T, Q> const s(normalize(cross(up, f))); vec<3, T, Q> const u(cross(f, s)); mat<4, 4, T, Q> Result(1); Result[0][0] = s.x; Result[1][0] = s.y; Result[2][0] = s.z; Result[0][1] = u.x; Result[1][1] = u.y; Result[2][1] = u.z; Result[0][2] = f.x; Result[1][2] = f.y; Result[2][2] = f.z; Result[3][0] = -dot(s, eye); Result[3][1] = -dot(u, eye); Result[3][2] = -dot(f, eye); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAt(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up) { GLM_IF_CONSTEXPR(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT) return lookAtLH(eye, center, up); else return lookAtRH(eye, center, up); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/quaternion_common.hpp000066400000000000000000000100701360521144700253610ustar00rootroot00000000000000/// @ref ext_quaternion_common /// @file glm/ext/quaternion_common.hpp /// /// @defgroup ext_quaternion_common GLM_EXT_quaternion_common /// @ingroup ext /// /// Provides common functions for quaternion types /// /// Include to use the features of this extension. /// /// @see ext_scalar_common /// @see ext_vector_common /// @see ext_quaternion_float /// @see ext_quaternion_double /// @see ext_quaternion_exponential /// @see ext_quaternion_geometric /// @see ext_quaternion_relational /// @see ext_quaternion_trigonometric /// @see ext_quaternion_transform #pragma once // Dependency: #include "../ext/scalar_constants.hpp" #include "../ext/quaternion_geometric.hpp" #include "../common.hpp" #include "../trigonometric.hpp" #include "../exponential.hpp" #include #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_quaternion_common extension included") #endif namespace glm { /// @addtogroup ext_quaternion_common /// @{ /// Spherical linear interpolation of two quaternions. /// The interpolation is oriented and the rotation is performed at constant speed. /// For short path spherical linear interpolation, use the slerp function. /// /// @param x A quaternion /// @param y A quaternion /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1]. /// /// @tparam T A floating-point scalar type /// @tparam Q A value from qualifier enum /// /// @see - slerp(qua const& x, qua const& y, T const& a) template GLM_FUNC_DECL qua mix(qua const& x, qua const& y, T a); /// Linear interpolation of two quaternions. /// The interpolation is oriented. /// /// @param x A quaternion /// @param y A quaternion /// @param a Interpolation factor. The interpolation is defined in the range [0, 1]. /// /// @tparam T A floating-point scalar type /// @tparam Q A value from qualifier enum template GLM_FUNC_DECL qua lerp(qua const& x, qua const& y, T a); /// Spherical linear interpolation of two quaternions. /// The interpolation always take the short path and the rotation is performed at constant speed. /// /// @param x A quaternion /// @param y A quaternion /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1]. /// /// @tparam T A floating-point scalar type /// @tparam Q A value from qualifier enum template GLM_FUNC_DECL qua slerp(qua const& x, qua const& y, T a); /// Returns the q conjugate. /// /// @tparam T A floating-point scalar type /// @tparam Q A value from qualifier enum template GLM_FUNC_DECL qua conjugate(qua const& q); /// Returns the q inverse. /// /// @tparam T A floating-point scalar type /// @tparam Q A value from qualifier enum template GLM_FUNC_DECL qua inverse(qua const& q); /// Returns true if x holds a NaN (not a number) /// representation in the underlying implementation's set of /// floating point representations. Returns false otherwise, /// including for implementations with no NaN /// representations. /// /// /!\ When using compiler fast math, this function may fail. /// /// @tparam T A floating-point scalar type /// @tparam Q A value from qualifier enum template GLM_FUNC_DECL vec<4, bool, Q> isnan(qua const& x); /// Returns true if x holds a positive infinity or negative /// infinity representation in the underlying implementation's /// set of floating point representations. Returns false /// otherwise, including for implementations with no infinity /// representations. /// /// @tparam T A floating-point scalar type /// @tparam Q A value from qualifier enum template GLM_FUNC_DECL vec<4, bool, Q> isinf(qua const& x); /// @} } //namespace glm #include "quaternion_common.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext/quaternion_common.inl000066400000000000000000000061211360521144700253560ustar00rootroot00000000000000namespace glm { template GLM_FUNC_QUALIFIER qua mix(qua const& x, qua const& y, T a) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'mix' only accept floating-point inputs"); T const cosTheta = dot(x, y); // Perform a linear interpolation when cosTheta is close to 1 to avoid side effect of sin(angle) becoming a zero denominator if(cosTheta > static_cast(1) - epsilon()) { // Linear interpolation return qua( mix(x.w, y.w, a), mix(x.x, y.x, a), mix(x.y, y.y, a), mix(x.z, y.z, a)); } else { // Essential Mathematics, page 467 T angle = acos(cosTheta); return (sin((static_cast(1) - a) * angle) * x + sin(a * angle) * y) / sin(angle); } } template GLM_FUNC_QUALIFIER qua lerp(qua const& x, qua const& y, T a) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'lerp' only accept floating-point inputs"); // Lerp is only defined in [0, 1] assert(a >= static_cast(0)); assert(a <= static_cast(1)); return x * (static_cast(1) - a) + (y * a); } template GLM_FUNC_QUALIFIER qua slerp(qua const& x, qua const& y, T a) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'slerp' only accept floating-point inputs"); qua z = y; T cosTheta = dot(x, y); // If cosTheta < 0, the interpolation will take the long way around the sphere. // To fix this, one quat must be negated. if(cosTheta < static_cast(0)) { z = -y; cosTheta = -cosTheta; } // Perform a linear interpolation when cosTheta is close to 1 to avoid side effect of sin(angle) becoming a zero denominator if(cosTheta > static_cast(1) - epsilon()) { // Linear interpolation return qua( mix(x.w, z.w, a), mix(x.x, z.x, a), mix(x.y, z.y, a), mix(x.z, z.z, a)); } else { // Essential Mathematics, page 467 T angle = acos(cosTheta); return (sin((static_cast(1) - a) * angle) * x + sin(a * angle) * z) / sin(angle); } } template GLM_FUNC_QUALIFIER qua conjugate(qua const& q) { return qua(q.w, -q.x, -q.y, -q.z); } template GLM_FUNC_QUALIFIER qua inverse(qua const& q) { return conjugate(q) / dot(q, q); } template GLM_FUNC_QUALIFIER vec<4, bool, Q> isnan(qua const& q) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isnan' only accept floating-point inputs"); return vec<4, bool, Q>(isnan(q.x), isnan(q.y), isnan(q.z), isnan(q.w)); } template GLM_FUNC_QUALIFIER vec<4, bool, Q> isinf(qua const& q) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isinf' only accept floating-point inputs"); return vec<4, bool, Q>(isinf(q.x), isinf(q.y), isinf(q.z), isinf(q.w)); } }//namespace glm #if GLM_CONFIG_SIMD == GLM_ENABLE # include "quaternion_common_simd.inl" #endif connectome-workbench-1.4.2/src/GLMath/glm/ext/quaternion_common_simd.inl000066400000000000000000000006061360521144700263740ustar00rootroot00000000000000#if GLM_ARCH & GLM_ARCH_SSE2_BIT namespace glm{ namespace detail { template struct compute_dot, float, true> { static GLM_FUNC_QUALIFIER float call(qua const& x, qua const& y) { return _mm_cvtss_f32(glm_vec1_dot(x.data, y.data)); } }; }//namespace detail }//namespace glm #endif//GLM_ARCH & GLM_ARCH_SSE2_BIT connectome-workbench-1.4.2/src/GLMath/glm/ext/quaternion_double.hpp000066400000000000000000000020001360521144700253350ustar00rootroot00000000000000/// @ref ext_quaternion_double /// @file glm/ext/quaternion_double.hpp /// /// @defgroup ext_quaternion_double GLM_EXT_quaternion_double /// @ingroup ext /// /// Exposes double-precision floating point quaternion type. /// /// Include to use the features of this extension. /// /// @see ext_quaternion_float /// @see ext_quaternion_double_precision /// @see ext_quaternion_common /// @see ext_quaternion_exponential /// @see ext_quaternion_geometric /// @see ext_quaternion_relational /// @see ext_quaternion_transform /// @see ext_quaternion_trigonometric #pragma once // Dependency: #include "../detail/type_quat.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_quaternion_double extension included") #endif namespace glm { /// @addtogroup ext_quaternion_double /// @{ /// Quaternion of double-precision floating-point numbers. typedef qua dquat; /// @} } //namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/quaternion_double_precision.hpp000066400000000000000000000025201360521144700274170ustar00rootroot00000000000000/// @ref ext_quaternion_double_precision /// @file glm/ext/quaternion_double_precision.hpp /// /// @defgroup ext_quaternion_double_precision GLM_EXT_quaternion_double_precision /// @ingroup ext /// /// Exposes double-precision floating point quaternion type with various precision in term of ULPs. /// /// Include to use the features of this extension. #pragma once // Dependency: #include "../detail/type_quat.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_quaternion_double_precision extension included") #endif namespace glm { /// @addtogroup ext_quaternion_double_precision /// @{ /// Quaternion of double-precision floating-point numbers using high precision arithmetic in term of ULPs. /// /// @see ext_quaternion_double_precision typedef qua lowp_dquat; /// Quaternion of medium double-qualifier floating-point numbers using high precision arithmetic in term of ULPs. /// /// @see ext_quaternion_double_precision typedef qua mediump_dquat; /// Quaternion of high double-qualifier floating-point numbers using high precision arithmetic in term of ULPs. /// /// @see ext_quaternion_double_precision typedef qua highp_dquat; /// @} } //namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/quaternion_exponential.hpp000066400000000000000000000034141360521144700264230ustar00rootroot00000000000000/// @ref ext_quaternion_exponential /// @file glm/ext/quaternion_exponential.hpp /// /// @defgroup ext_quaternion_exponential GLM_EXT_quaternion_exponential /// @ingroup ext /// /// Provides exponential functions for quaternion types /// /// Include to use the features of this extension. /// /// @see core_exponential /// @see ext_quaternion_float /// @see ext_quaternion_double #pragma once // Dependency: #include "../common.hpp" #include "../trigonometric.hpp" #include "../geometric.hpp" #include "../ext/scalar_constants.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_quaternion_exponential extension included") #endif namespace glm { /// @addtogroup ext_quaternion_transform /// @{ /// Returns a exponential of a quaternion. /// /// @tparam T A floating-point scalar type /// @tparam Q A value from qualifier enum template GLM_FUNC_DECL qua exp(qua const& q); /// Returns a logarithm of a quaternion /// /// @tparam T A floating-point scalar type /// @tparam Q A value from qualifier enum template GLM_FUNC_DECL qua log(qua const& q); /// Returns a quaternion raised to a power. /// /// @tparam T A floating-point scalar type /// @tparam Q A value from qualifier enum template GLM_FUNC_DECL qua pow(qua const& q, T y); /// Returns the square root of a quaternion /// /// @tparam T A floating-point scalar type /// @tparam Q A value from qualifier enum template GLM_FUNC_DECL qua sqrt(qua const& q); /// @} } //namespace glm #include "quaternion_exponential.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext/quaternion_exponential.inl000066400000000000000000000042671360521144700264250ustar00rootroot00000000000000namespace glm { template GLM_FUNC_QUALIFIER qua exp(qua const& q) { vec<3, T, Q> u(q.x, q.y, q.z); T const Angle = glm::length(u); if (Angle < epsilon()) return qua(); vec<3, T, Q> const v(u / Angle); return qua(cos(Angle), sin(Angle) * v); } template GLM_FUNC_QUALIFIER qua log(qua const& q) { vec<3, T, Q> u(q.x, q.y, q.z); T Vec3Len = length(u); if (Vec3Len < epsilon()) { if(q.w > static_cast(0)) return qua(log(q.w), static_cast(0), static_cast(0), static_cast(0)); else if(q.w < static_cast(0)) return qua(log(-q.w), pi(), static_cast(0), static_cast(0)); else return qua(std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity()); } else { T t = atan(Vec3Len, T(q.w)) / Vec3Len; T QuatLen2 = Vec3Len * Vec3Len + q.w * q.w; return qua(static_cast(0.5) * log(QuatLen2), t * q.x, t * q.y, t * q.z); } } template GLM_FUNC_QUALIFIER qua pow(qua const& x, T y) { //Raising to the power of 0 should yield 1 //Needed to prevent a division by 0 error later on if(y > -epsilon() && y < epsilon()) return qua(1,0,0,0); //To deal with non-unit quaternions T magnitude = sqrt(x.x * x.x + x.y * x.y + x.z * x.z + x.w *x.w); //Equivalent to raising a real number to a power //Needed to prevent a division by 0 error later on if(abs(x.w / magnitude) > static_cast(1) - epsilon() && abs(x.w / magnitude) < static_cast(1) + epsilon()) return qua(pow(x.w, y), 0, 0, 0); T Angle = acos(x.w / magnitude); T NewAngle = Angle * y; T Div = sin(NewAngle) / sin(Angle); T Mag = pow(magnitude, y - static_cast(1)); return qua(cos(NewAngle) * magnitude * Mag, x.x * Div * Mag, x.y * Div * Mag, x.z * Div * Mag); } template GLM_FUNC_QUALIFIER qua sqrt(qua const& x) { return pow(x, static_cast(0.5)); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/quaternion_float.hpp000066400000000000000000000017671360521144700252130ustar00rootroot00000000000000/// @ref ext_quaternion_float /// @file glm/ext/quaternion_float.hpp /// /// @defgroup ext_quaternion_float GLM_EXT_quaternion_float /// @ingroup ext /// /// Exposes single-precision floating point quaternion type. /// /// Include to use the features of this extension. /// /// @see ext_quaternion_double /// @see ext_quaternion_float_precision /// @see ext_quaternion_common /// @see ext_quaternion_exponential /// @see ext_quaternion_geometric /// @see ext_quaternion_relational /// @see ext_quaternion_transform /// @see ext_quaternion_trigonometric #pragma once // Dependency: #include "../detail/type_quat.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_quaternion_float extension included") #endif namespace glm { /// @addtogroup ext_quaternion_float /// @{ /// Quaternion of single-precision floating-point numbers. typedef qua quat; /// @} } //namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/quaternion_float_precision.hpp000066400000000000000000000022451360521144700272560ustar00rootroot00000000000000/// @ref ext_quaternion_float_precision /// @file glm/ext/quaternion_float_precision.hpp /// /// @defgroup ext_quaternion_float_precision GLM_EXT_quaternion_float_precision /// @ingroup ext /// /// Exposes single-precision floating point quaternion type with various precision in term of ULPs. /// /// Include to use the features of this extension. #pragma once // Dependency: #include "../detail/type_quat.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_quaternion_float_precision extension included") #endif namespace glm { /// @addtogroup ext_quaternion_float_precision /// @{ /// Quaternion of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef qua lowp_quat; /// Quaternion of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef qua mediump_quat; /// Quaternion of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef qua highp_quat; /// @} } //namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/quaternion_geometric.hpp000066400000000000000000000036571360521144700260640ustar00rootroot00000000000000/// @ref ext_quaternion_geometric /// @file glm/ext/quaternion_geometric.hpp /// /// @defgroup ext_quaternion_geometric GLM_EXT_quaternion_geometric /// @ingroup ext /// /// Provides geometric functions for quaternion types /// /// Include to use the features of this extension. /// /// @see core_geometric /// @see ext_quaternion_float /// @see ext_quaternion_double #pragma once // Dependency: #include "../geometric.hpp" #include "../exponential.hpp" #include "../ext/vector_relational.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_quaternion_geometric extension included") #endif namespace glm { /// @addtogroup ext_quaternion_geometric /// @{ /// Returns the norm of a quaternions /// /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see ext_quaternion_geometric template GLM_FUNC_DECL T length(qua const& q); /// Returns the normalized quaternion. /// /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see ext_quaternion_geometric template GLM_FUNC_DECL qua normalize(qua const& q); /// Returns dot product of q1 and q2, i.e., q1[0] * q2[0] + q1[1] * q2[1] + ... /// /// @tparam T Floating-point scalar types. /// @tparam Q Value from qualifier enum /// /// @see ext_quaternion_geometric template GLM_FUNC_DECL T dot(qua const& x, qua const& y); /// Compute a cross product. /// /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see ext_quaternion_geometric template GLM_FUNC_QUALIFIER qua cross(qua const& q1, qua const& q2); /// @} } //namespace glm #include "quaternion_geometric.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext/quaternion_geometric.inl000066400000000000000000000023461360521144700260510ustar00rootroot00000000000000namespace glm { template GLM_FUNC_QUALIFIER T dot(qua const& x, qua const& y) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'dot' accepts only floating-point inputs"); return detail::compute_dot, T, detail::is_aligned::value>::call(x, y); } template GLM_FUNC_QUALIFIER T length(qua const& q) { return glm::sqrt(dot(q, q)); } template GLM_FUNC_QUALIFIER qua normalize(qua const& q) { T len = length(q); if(len <= static_cast(0)) // Problem return qua(static_cast(1), static_cast(0), static_cast(0), static_cast(0)); T oneOverLen = static_cast(1) / len; return qua(q.w * oneOverLen, q.x * oneOverLen, q.y * oneOverLen, q.z * oneOverLen); } template GLM_FUNC_QUALIFIER qua cross(qua const& q1, qua const& q2) { return qua( q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z, q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y, q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z, q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/quaternion_relational.hpp000066400000000000000000000037401360521144700262310ustar00rootroot00000000000000/// @ref ext_quaternion_relational /// @file glm/ext/quaternion_relational.hpp /// /// @defgroup ext_quaternion_relational GLM_EXT_quaternion_relational /// @ingroup ext /// /// Exposes comparison functions for quaternion types that take a user defined epsilon values. /// /// Include to use the features of this extension. /// /// @see core_vector_relational /// @see ext_vector_relational /// @see ext_matrix_relational /// @see ext_quaternion_float /// @see ext_quaternion_double #pragma once // Dependency: #include "../vector_relational.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_quaternion_relational extension included") #endif namespace glm { /// @addtogroup ext_quaternion_relational /// @{ /// Returns the component-wise comparison of result x == y. /// /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL vec<4, bool, Q> equal(qua const& x, qua const& y); /// Returns the component-wise comparison of |x - y| < epsilon. /// /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL vec<4, bool, Q> equal(qua const& x, qua const& y, T epsilon); /// Returns the component-wise comparison of result x != y. /// /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL vec<4, bool, Q> notEqual(qua const& x, qua const& y); /// Returns the component-wise comparison of |x - y| >= epsilon. /// /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL vec<4, bool, Q> notEqual(qua const& x, qua const& y, T epsilon); /// @} } //namespace glm #include "quaternion_relational.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext/quaternion_relational.inl000066400000000000000000000020361360521144700262210ustar00rootroot00000000000000namespace glm { template GLM_FUNC_QUALIFIER vec<4, bool, Q> equal(qua const& x, qua const& y) { vec<4, bool, Q> Result; for(length_t i = 0; i < x.length(); ++i) Result[i] = x[i] == y[i]; return Result; } template GLM_FUNC_QUALIFIER vec<4, bool, Q> equal(qua const& x, qua const& y, T epsilon) { vec<4, T, Q> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w); return lessThan(abs(v), vec<4, T, Q>(epsilon)); } template GLM_FUNC_QUALIFIER vec<4, bool, Q> notEqual(qua const& x, qua const& y) { vec<4, bool, Q> Result; for(length_t i = 0; i < x.length(); ++i) Result[i] = x[i] != y[i]; return Result; } template GLM_FUNC_QUALIFIER vec<4, bool, Q> notEqual(qua const& x, qua const& y, T epsilon) { vec<4, T, Q> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w); return greaterThanEqual(abs(v), vec<4, T, Q>(epsilon)); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/quaternion_transform.hpp000066400000000000000000000025421360521144700261110ustar00rootroot00000000000000/// @ref ext_quaternion_transform /// @file glm/ext/quaternion_transform.hpp /// /// @defgroup ext_quaternion_transform GLM_EXT_quaternion_transform /// @ingroup ext /// /// Provides transformation functions for quaternion types /// /// Include to use the features of this extension. /// /// @see ext_quaternion_float /// @see ext_quaternion_double /// @see ext_quaternion_exponential /// @see ext_quaternion_geometric /// @see ext_quaternion_relational /// @see ext_quaternion_trigonometric #pragma once // Dependency: #include "../common.hpp" #include "../trigonometric.hpp" #include "../geometric.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_quaternion_transform extension included") #endif namespace glm { /// @addtogroup ext_quaternion_transform /// @{ /// Rotates a quaternion from a vector of 3 components axis and an angle. /// /// @param q Source orientation /// @param angle Angle expressed in radians. /// @param axis Axis of the rotation /// /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL qua rotate(qua const& q, T const& angle, vec<3, T, Q> const& axis); /// @} } //namespace glm #include "quaternion_transform.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext/quaternion_transform.inl000066400000000000000000000012151360521144700261000ustar00rootroot00000000000000namespace glm { template GLM_FUNC_QUALIFIER qua rotate(qua const& q, T const& angle, vec<3, T, Q> const& v) { vec<3, T, Q> Tmp = v; // Axis of rotation must be normalised T len = glm::length(Tmp); if(abs(len - static_cast(1)) > static_cast(0.001)) { T oneOverLen = static_cast(1) / len; Tmp.x *= oneOverLen; Tmp.y *= oneOverLen; Tmp.z *= oneOverLen; } T const AngleRad(angle); T const Sin = sin(AngleRad * static_cast(0.5)); return q * qua(cos(AngleRad * static_cast(0.5)), Tmp.x * Sin, Tmp.y * Sin, Tmp.z * Sin); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/quaternion_trigonometric.hpp000066400000000000000000000035241360521144700267640ustar00rootroot00000000000000/// @ref ext_quaternion_trigonometric /// @file glm/ext/quaternion_trigonometric.hpp /// /// @defgroup ext_quaternion_trigonometric GLM_EXT_quaternion_trigonometric /// @ingroup ext /// /// Provides trigonometric functions for quaternion types /// /// Include to use the features of this extension. /// /// @see ext_quaternion_float /// @see ext_quaternion_double /// @see ext_quaternion_exponential /// @see ext_quaternion_geometric /// @see ext_quaternion_relational /// @see ext_quaternion_transform #pragma once // Dependency: #include "../trigonometric.hpp" #include "../exponential.hpp" #include "scalar_constants.hpp" #include "vector_relational.hpp" #include #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_quaternion_trigonometric extension included") #endif namespace glm { /// @addtogroup ext_quaternion_trigonometric /// @{ /// Returns the quaternion rotation angle. /// /// @tparam T A floating-point scalar type /// @tparam Q A value from qualifier enum template GLM_FUNC_DECL T angle(qua const& x); /// Returns the q rotation axis. /// /// @tparam T A floating-point scalar type /// @tparam Q A value from qualifier enum template GLM_FUNC_DECL vec<3, T, Q> axis(qua const& x); /// Build a quaternion from an angle and a normalized axis. /// /// @param angle Angle expressed in radians. /// @param axis Axis of the quaternion, must be normalized. /// /// @tparam T A floating-point scalar type /// @tparam Q A value from qualifier enum template GLM_FUNC_DECL qua angleAxis(T const& angle, vec<3, T, Q> const& axis); /// @} } //namespace glm #include "quaternion_trigonometric.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext/quaternion_trigonometric.inl000066400000000000000000000013731360521144700267570ustar00rootroot00000000000000namespace glm { template GLM_FUNC_QUALIFIER T angle(qua const& x) { return acos(x.w) * static_cast(2); } template GLM_FUNC_QUALIFIER vec<3, T, Q> axis(qua const& x) { T const tmp1 = static_cast(1) - x.w * x.w; if(tmp1 <= static_cast(0)) return vec<3, T, Q>(0, 0, 1); T const tmp2 = static_cast(1) / sqrt(tmp1); return vec<3, T, Q>(x.x * tmp2, x.y * tmp2, x.z * tmp2); } template GLM_FUNC_QUALIFIER qua angleAxis(T const& angle, vec<3, T, Q> const& v) { T const a(angle); T const s = glm::sin(a * static_cast(0.5)); return qua(glm::cos(a * static_cast(0.5)), v * s); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/scalar_common.hpp000066400000000000000000000067711360521144700244560ustar00rootroot00000000000000/// @ref ext_scalar_common /// @file glm/ext/scalar_common.hpp /// /// @defgroup ext_scalar_common GLM_EXT_scalar_common /// @ingroup ext /// /// Exposes min and max functions for 3 to 4 scalar parameters. /// /// Include to use the features of this extension. /// /// @see core_func_common /// @see ext_vector_common #pragma once // Dependency: #include "../common.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_scalar_common extension included") #endif namespace glm { /// @addtogroup ext_scalar_common /// @{ /// Returns the minimum component-wise values of 3 inputs /// /// @tparam T A floating-point scalar type. template GLM_FUNC_DECL T min(T a, T b, T c); /// Returns the minimum component-wise values of 4 inputs /// /// @tparam T A floating-point scalar type. template GLM_FUNC_DECL T min(T a, T b, T c, T d); /// Returns the maximum component-wise values of 3 inputs /// /// @tparam T A floating-point scalar type. template GLM_FUNC_DECL T max(T a, T b, T c); /// Returns the maximum component-wise values of 4 inputs /// /// @tparam T A floating-point scalar type. template GLM_FUNC_DECL T max(T a, T b, T c, T d); /// Returns the minimum component-wise values of 2 inputs. If one of the two arguments is NaN, the value of the other argument is returned. /// /// @tparam T A floating-point scalar type. /// /// @see std::fmin documentation template GLM_FUNC_DECL T fmin(T a, T b); /// Returns the minimum component-wise values of 3 inputs. If one of the two arguments is NaN, the value of the other argument is returned. /// /// @tparam T A floating-point scalar type. /// /// @see std::fmin documentation template GLM_FUNC_DECL T fmin(T a, T b, T c); /// Returns the minimum component-wise values of 4 inputs. If one of the two arguments is NaN, the value of the other argument is returned. /// /// @tparam T A floating-point scalar type. /// /// @see std::fmin documentation template GLM_FUNC_DECL T fmin(T a, T b, T c, T d); /// Returns the maximum component-wise values of 2 inputs. If one of the two arguments is NaN, the value of the other argument is returned. /// /// @tparam T A floating-point scalar type. /// /// @see std::fmax documentation template GLM_FUNC_DECL T fmax(T a, T b); /// Returns the maximum component-wise values of 3 inputs. If one of the two arguments is NaN, the value of the other argument is returned. /// /// @tparam T A floating-point scalar type. /// /// @see std::fmax documentation template GLM_FUNC_DECL T fmax(T a, T b, T C); /// Returns the maximum component-wise values of 4 inputs. If one of the two arguments is NaN, the value of the other argument is returned. /// /// @tparam T A floating-point scalar type. /// /// @see std::fmax documentation template GLM_FUNC_DECL T fmax(T a, T b, T C, T D); /// @} }//namespace glm #include "scalar_common.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext/scalar_common.inl000066400000000000000000000047541360521144700244500ustar00rootroot00000000000000namespace glm { template GLM_FUNC_QUALIFIER T min(T a, T b, T c) { return glm::min(glm::min(a, b), c); } template GLM_FUNC_QUALIFIER T min(T a, T b, T c, T d) { return glm::min(glm::min(a, b), glm::min(c, d)); } template GLM_FUNC_QUALIFIER T max(T a, T b, T c) { return glm::max(glm::max(a, b), c); } template GLM_FUNC_QUALIFIER T max(T a, T b, T c, T d) { return glm::max(glm::max(a, b), glm::max(c, d)); } # if GLM_HAS_CXX11_STL using std::fmin; # else template GLM_FUNC_QUALIFIER T fmin(T a, T b) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point input"); if (isnan(a)) return b; return min(a, b); } # endif template GLM_FUNC_QUALIFIER T fmin(T a, T b, T c) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point input"); if (isnan(a)) return fmin(b, c); if (isnan(b)) return fmin(a, c); if (isnan(c)) return min(a, b); return min(a, b, c); } template GLM_FUNC_QUALIFIER T fmin(T a, T b, T c, T d) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point input"); if (isnan(a)) return fmin(b, c, d); if (isnan(b)) return min(a, fmin(c, d)); if (isnan(c)) return fmin(min(a, b), d); if (isnan(d)) return min(a, b, c); return min(a, b, c, d); } # if GLM_HAS_CXX11_STL using std::fmax; # else template GLM_FUNC_QUALIFIER T fmax(T a, T b) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point input"); if (isnan(a)) return b; return max(a, b); } # endif template GLM_FUNC_QUALIFIER T fmax(T a, T b, T c) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point input"); if (isnan(a)) return fmax(b, c); if (isnan(b)) return fmax(a, c); if (isnan(c)) return max(a, b); return max(a, b, c); } template GLM_FUNC_QUALIFIER T fmax(T a, T b, T c, T d) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point input"); if (isnan(a)) return fmax(b, c, d); if (isnan(b)) return max(a, fmax(c, d)); if (isnan(c)) return fmax(max(a, b), d); if (isnan(d)) return max(a, b, c); return max(a, b, c, d); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/scalar_constants.hpp000066400000000000000000000016351360521144700251740ustar00rootroot00000000000000/// @ref ext_scalar_constants /// @file glm/ext/scalar_constants.hpp /// /// @defgroup ext_scalar_constants GLM_EXT_scalar_constants /// @ingroup ext /// /// Provides a list of constants and precomputed useful values. /// /// Include to use the features of this extension. #pragma once // Dependencies #include "../detail/setup.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_scalar_constants extension included") #endif namespace glm { /// @addtogroup ext_scalar_constants /// @{ /// Return the epsilon constant for floating point types. template GLM_FUNC_DECL GLM_CONSTEXPR genType epsilon(); /// Return the pi constant for floating point types. template GLM_FUNC_DECL GLM_CONSTEXPR genType pi(); /// @} } //namespace glm #include "scalar_constants.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext/scalar_constants.inl000066400000000000000000000010761360521144700251660ustar00rootroot00000000000000#include namespace glm { template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType epsilon() { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'epsilon' only accepts floating-point inputs"); return std::numeric_limits::epsilon(); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType pi() { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'pi' only accepts floating-point inputs"); return static_cast(3.14159265358979323846264338327950288); } } //namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/scalar_int_sized.hpp000066400000000000000000000025671360521144700251550ustar00rootroot00000000000000/// @ref ext_scalar_int_sized /// @file glm/ext/scalar_int_sized.hpp /// /// @defgroup ext_scalar_int_sized GLM_EXT_scalar_int_sized /// @ingroup ext /// /// Exposes sized signed integer scalar types. /// /// Include to use the features of this extension. /// /// @see ext_scalar_uint_sized #pragma once #include "../detail/setup.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_scalar_int_sized extension included") #endif namespace glm{ namespace detail { # if GLM_HAS_EXTENDED_INTEGER_TYPE typedef std::int8_t int8; typedef std::int16_t int16; typedef std::int32_t int32; # else typedef signed char int8; typedef signed short int16; typedef signed int int32; #endif// template<> struct is_int { enum test {value = ~0}; }; template<> struct is_int { enum test {value = ~0}; }; template<> struct is_int { enum test {value = ~0}; }; }//namespace detail /// @addtogroup ext_scalar_int_sized /// @{ /// 8 bit signed integer type. typedef detail::int8 int8; /// 16 bit signed integer type. typedef detail::int16 int16; /// 32 bit signed integer type. typedef detail::int32 int32; /// 64 bit signed integer type. typedef detail::int64 int64; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/scalar_integer.hpp000066400000000000000000000053271360521144700246170ustar00rootroot00000000000000/// @ref ext_scalar_integer /// @file glm/ext/scalar_integer.hpp /// /// @see core (dependence) /// /// @defgroup ext_scalar_integer GLM_EXT_scalar_integer /// @ingroup ext /// /// Include to use the features of this extension. #pragma once // Dependencies #include "../detail/setup.hpp" #include "../detail/qualifier.hpp" #include "../detail/_vectorize.hpp" #include "../detail/type_float.hpp" #include "../vector_relational.hpp" #include "../common.hpp" #include #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_scalar_integer extension included") #endif namespace glm { /// @addtogroup ext_scalar_integer /// @{ /// Return true if the value is a power of two number. /// /// @see ext_scalar_integer template GLM_FUNC_DECL bool isPowerOfTwo(genIUType v); /// Return the power of two number which value is just higher the input value, /// round up to a power of two. /// /// @see ext_scalar_integer template GLM_FUNC_DECL genIUType nextPowerOfTwo(genIUType v); /// Return the power of two number which value is just lower the input value, /// round down to a power of two. /// /// @see ext_scalar_integer template GLM_FUNC_DECL genIUType prevPowerOfTwo(genIUType v); /// Return true if the 'Value' is a multiple of 'Multiple'. /// /// @see ext_scalar_integer template GLM_FUNC_DECL bool isMultiple(genIUType v, genIUType Multiple); /// Higher multiple number of Source. /// /// @tparam genIUType Integer scalar or vector types. /// /// @param v Source value to which is applied the function /// @param Multiple Must be a null or positive value /// /// @see ext_scalar_integer template GLM_FUNC_DECL genIUType nextMultiple(genIUType v, genIUType Multiple); /// Lower multiple number of Source. /// /// @tparam genIUType Integer scalar or vector types. /// /// @param v Source value to which is applied the function /// @param Multiple Must be a null or positive value /// /// @see ext_scalar_integer template GLM_FUNC_DECL genIUType prevMultiple(genIUType v, genIUType Multiple); /// Returns the bit number of the Nth significant bit set to /// 1 in the binary representation of value. /// If value bitcount is less than the Nth significant bit, -1 will be returned. /// /// @tparam genIUType Signed or unsigned integer scalar types. /// /// @see ext_scalar_integer template GLM_FUNC_DECL int findNSB(genIUType x, int significantBitCount); /// @} } //namespace glm #include "scalar_integer.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext/scalar_integer.inl000066400000000000000000000160231360521144700246050ustar00rootroot00000000000000#include "../integer.hpp" namespace glm{ namespace detail { template struct compute_ceilShift { GLM_FUNC_QUALIFIER static vec call(vec const& v, T) { return v; } }; template struct compute_ceilShift { GLM_FUNC_QUALIFIER static vec call(vec const& v, T Shift) { return v | (v >> Shift); } }; template struct compute_ceilPowerOfTwo { GLM_FUNC_QUALIFIER static vec call(vec const& x) { GLM_STATIC_ASSERT(!std::numeric_limits::is_iec559, "'ceilPowerOfTwo' only accept integer scalar or vector inputs"); vec const Sign(sign(x)); vec v(abs(x)); v = v - static_cast(1); v = v | (v >> static_cast(1)); v = v | (v >> static_cast(2)); v = v | (v >> static_cast(4)); v = compute_ceilShift= 2>::call(v, 8); v = compute_ceilShift= 4>::call(v, 16); v = compute_ceilShift= 8>::call(v, 32); return (v + static_cast(1)) * Sign; } }; template struct compute_ceilPowerOfTwo { GLM_FUNC_QUALIFIER static vec call(vec const& x) { GLM_STATIC_ASSERT(!std::numeric_limits::is_iec559, "'ceilPowerOfTwo' only accept integer scalar or vector inputs"); vec v(x); v = v - static_cast(1); v = v | (v >> static_cast(1)); v = v | (v >> static_cast(2)); v = v | (v >> static_cast(4)); v = compute_ceilShift= 2>::call(v, 8); v = compute_ceilShift= 4>::call(v, 16); v = compute_ceilShift= 8>::call(v, 32); return v + static_cast(1); } }; template struct compute_ceilMultiple{}; template<> struct compute_ceilMultiple { template GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) { if(Source > genType(0)) return Source + (Multiple - std::fmod(Source, Multiple)); else return Source + std::fmod(-Source, Multiple); } }; template<> struct compute_ceilMultiple { template GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) { genType Tmp = Source - genType(1); return Tmp + (Multiple - (Tmp % Multiple)); } }; template<> struct compute_ceilMultiple { template GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) { assert(Multiple > genType(0)); if(Source > genType(0)) { genType Tmp = Source - genType(1); return Tmp + (Multiple - (Tmp % Multiple)); } else return Source + (-Source % Multiple); } }; template struct compute_floorMultiple{}; template<> struct compute_floorMultiple { template GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) { if(Source >= genType(0)) return Source - std::fmod(Source, Multiple); else return Source - std::fmod(Source, Multiple) - Multiple; } }; template<> struct compute_floorMultiple { template GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) { if(Source >= genType(0)) return Source - Source % Multiple; else { genType Tmp = Source + genType(1); return Tmp - Tmp % Multiple - Multiple; } } }; template<> struct compute_floorMultiple { template GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) { if(Source >= genType(0)) return Source - Source % Multiple; else { genType Tmp = Source + genType(1); return Tmp - Tmp % Multiple - Multiple; } } }; }//namespace detail template GLM_FUNC_QUALIFIER bool isPowerOfTwo(genIUType Value) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'isPowerOfTwo' only accept integer inputs"); genIUType const Result = glm::abs(Value); return !(Result & (Result - 1)); } template GLM_FUNC_QUALIFIER genIUType nextPowerOfTwo(genIUType value) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'nextPowerOfTwo' only accept integer inputs"); return detail::compute_ceilPowerOfTwo<1, genIUType, defaultp, std::numeric_limits::is_signed>::call(vec<1, genIUType, defaultp>(value)).x; } template GLM_FUNC_QUALIFIER genIUType prevPowerOfTwo(genIUType value) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'prevPowerOfTwo' only accept integer inputs"); return isPowerOfTwo(value) ? value : static_cast(static_cast(1) << static_cast(findMSB(value))); } template GLM_FUNC_QUALIFIER bool isMultiple(genIUType Value, genIUType Multiple) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'isMultiple' only accept integer inputs"); return isMultiple(vec<1, genIUType>(Value), vec<1, genIUType>(Multiple)).x; } template GLM_FUNC_QUALIFIER genIUType nextMultiple(genIUType Source, genIUType Multiple) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'nextMultiple' only accept integer inputs"); return detail::compute_ceilMultiple::is_iec559, std::numeric_limits::is_signed>::call(Source, Multiple); } template GLM_FUNC_QUALIFIER genIUType prevMultiple(genIUType Source, genIUType Multiple) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'prevMultiple' only accept integer inputs"); return detail::compute_floorMultiple::is_iec559, std::numeric_limits::is_signed>::call(Source, Multiple); } template GLM_FUNC_QUALIFIER int findNSB(genIUType x, int significantBitCount) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findNSB' only accept integer inputs"); if(bitCount(x) < significantBitCount) return -1; genIUType const One = static_cast(1); int bitPos = 0; genIUType key = x; int nBitCount = significantBitCount; int Step = sizeof(x) * 8 / 2; while (key > One) { genIUType Mask = static_cast((One << Step) - One); genIUType currentKey = key & Mask; int currentBitCount = bitCount(currentKey); if (nBitCount > currentBitCount) { nBitCount -= currentBitCount; bitPos += Step; key >>= static_cast(Step); } else { key = key & Mask; } Step >>= 1; } return static_cast(bitPos); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/scalar_relational.hpp000066400000000000000000000044311360521144700253070ustar00rootroot00000000000000/// @ref ext_scalar_relational /// @file glm/ext/scalar_relational.hpp /// /// @defgroup ext_scalar_relational GLM_EXT_scalar_relational /// @ingroup ext /// /// Exposes comparison functions for scalar types that take a user defined epsilon values. /// /// Include to use the features of this extension. /// /// @see core_vector_relational /// @see ext_vector_relational /// @see ext_matrix_relational #pragma once // Dependencies #include "../detail/qualifier.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_scalar_relational extension included") #endif namespace glm { /// Returns the component-wise comparison of |x - y| < epsilon. /// True if this expression is satisfied. /// /// @tparam genType Floating-point or integer scalar types template GLM_FUNC_DECL GLM_CONSTEXPR bool equal(genType const& x, genType const& y, genType const& epsilon); /// Returns the component-wise comparison of |x - y| >= epsilon. /// True if this expression is not satisfied. /// /// @tparam genType Floating-point or integer scalar types template GLM_FUNC_DECL GLM_CONSTEXPR bool notEqual(genType const& x, genType const& y, genType const& epsilon); /// Returns the component-wise comparison between two scalars in term of ULPs. /// True if this expression is satisfied. /// /// @param x First operand. /// @param y Second operand. /// @param ULPs Maximum difference in ULPs between the two operators to consider them equal. /// /// @tparam genType Floating-point or integer scalar types template GLM_FUNC_DECL GLM_CONSTEXPR bool equal(genType const& x, genType const& y, int ULPs); /// Returns the component-wise comparison between two scalars in term of ULPs. /// True if this expression is not satisfied. /// /// @param x First operand. /// @param y Second operand. /// @param ULPs Maximum difference in ULPs between the two operators to consider them not equal. /// /// @tparam genType Floating-point or integer scalar types template GLM_FUNC_DECL GLM_CONSTEXPR bool notEqual(genType const& x, genType const& y, int ULPs); /// @} }//namespace glm #include "scalar_relational.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext/scalar_relational.inl000066400000000000000000000023761360521144700253100ustar00rootroot00000000000000#include "../common.hpp" #include "../ext/scalar_int_sized.hpp" #include "../ext/scalar_uint_sized.hpp" #include "../detail/type_float.hpp" namespace glm { template GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool equal(genType const& x, genType const& y, genType const& epsilon) { return abs(x - y) <= epsilon; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool notEqual(genType const& x, genType const& y, genType const& epsilon) { return abs(x - y) > epsilon; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool equal(genType const& x, genType const& y, int MaxULPs) { detail::float_t const a(x); detail::float_t const b(y); // Different signs means they do not match. if(a.negative() != b.negative()) { // Check for equality to make sure +0==-0 return a.mantissa() == b.mantissa() && a.exponent() == b.exponent(); } // Find the difference in ULPs. typename detail::float_t::int_type const DiffULPs = abs(a.i - b.i); return DiffULPs <= MaxULPs; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool notEqual(genType const& x, genType const& y, int ULPs) { return !equal(x, y, ULPs); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/scalar_uint_sized.hpp000066400000000000000000000026341360521144700253350ustar00rootroot00000000000000/// @ref ext_scalar_uint_sized /// @file glm/ext/scalar_uint_sized.hpp /// /// @defgroup ext_scalar_uint_sized GLM_EXT_scalar_uint_sized /// @ingroup ext /// /// Exposes sized unsigned integer scalar types. /// /// Include to use the features of this extension. /// /// @see ext_scalar_int_sized #pragma once #include "../detail/setup.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_scalar_uint_sized extension included") #endif namespace glm{ namespace detail { # if GLM_HAS_EXTENDED_INTEGER_TYPE typedef std::uint8_t uint8; typedef std::uint16_t uint16; typedef std::uint32_t uint32; # else typedef unsigned char uint8; typedef unsigned short uint16; typedef unsigned int uint32; #endif template<> struct is_int { enum test {value = ~0}; }; template<> struct is_int { enum test {value = ~0}; }; template<> struct is_int { enum test {value = ~0}; }; }//namespace detail /// @addtogroup ext_scalar_uint_sized /// @{ /// 8 bit unsigned integer type. typedef detail::uint8 uint8; /// 16 bit unsigned integer type. typedef detail::uint16 uint16; /// 32 bit unsigned integer type. typedef detail::uint32 uint32; /// 64 bit unsigned integer type. typedef detail::uint64 uint64; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/scalar_ulp.hpp000066400000000000000000000041141360521144700237530ustar00rootroot00000000000000/// @ref ext_scalar_ulp /// @file glm/ext/scalar_ulp.hpp /// /// @defgroup ext_scalar_ulp GLM_EXT_scalar_ulp /// @ingroup ext /// /// Allow the measurement of the accuracy of a function against a reference /// implementation. This extension works on floating-point data and provide results /// in ULP. /// /// Include to use the features of this extension. /// /// @see ext_vector_ulp /// @see ext_scalar_relational #pragma once // Dependencies #include "../ext/scalar_int_sized.hpp" #include "../common.hpp" #include "../detail/qualifier.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_scalar_ulp extension included") #endif namespace glm { /// Return the next ULP value(s) after the input value(s). /// /// @tparam genType A floating-point scalar type. /// /// @see ext_scalar_ulp template GLM_FUNC_DECL genType nextFloat(genType x); /// Return the previous ULP value(s) before the input value(s). /// /// @tparam genType A floating-point scalar type. /// /// @see ext_scalar_ulp template GLM_FUNC_DECL genType prevFloat(genType x); /// Return the value(s) ULP distance after the input value(s). /// /// @tparam genType A floating-point scalar type. /// /// @see ext_scalar_ulp template GLM_FUNC_DECL genType nextFloat(genType x, int ULPs); /// Return the value(s) ULP distance before the input value(s). /// /// @tparam genType A floating-point scalar type. /// /// @see ext_scalar_ulp template GLM_FUNC_DECL genType prevFloat(genType x, int ULPs); /// Return the distance in the number of ULP between 2 single-precision floating-point scalars. /// /// @see ext_scalar_ulp GLM_FUNC_DECL int floatDistance(float x, float y); /// Return the distance in the number of ULP between 2 double-precision floating-point scalars. /// /// @see ext_scalar_ulp GLM_FUNC_DECL int64 floatDistance(double x, double y); /// @} }//namespace glm #include "scalar_ulp.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext/scalar_ulp.inl000066400000000000000000000162321360521144700237520ustar00rootroot00000000000000/// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. /// /// Developed at SunPro, a Sun Microsystems, Inc. business. /// Permission to use, copy, modify, and distribute this /// software is freely granted, provided that this notice /// is preserved. #include "../detail/type_float.hpp" #include "../ext/scalar_constants.hpp" #include #include #if(GLM_COMPILER & GLM_COMPILER_VC) # pragma warning(push) # pragma warning(disable : 4127) #endif typedef union { float value; /* FIXME: Assumes 32 bit int. */ unsigned int word; } ieee_float_shape_type; typedef union { double value; struct { int lsw; int msw; } parts; } ieee_double_shape_type; #define GLM_EXTRACT_WORDS(ix0,ix1,d) \ do { \ ieee_double_shape_type ew_u; \ ew_u.value = (d); \ (ix0) = ew_u.parts.msw; \ (ix1) = ew_u.parts.lsw; \ } while (0) #define GLM_GET_FLOAT_WORD(i,d) \ do { \ ieee_float_shape_type gf_u; \ gf_u.value = (d); \ (i) = gf_u.word; \ } while (0) #define GLM_SET_FLOAT_WORD(d,i) \ do { \ ieee_float_shape_type sf_u; \ sf_u.word = (i); \ (d) = sf_u.value; \ } while (0) #define GLM_INSERT_WORDS(d,ix0,ix1) \ do { \ ieee_double_shape_type iw_u; \ iw_u.parts.msw = (ix0); \ iw_u.parts.lsw = (ix1); \ (d) = iw_u.value; \ } while (0) namespace glm{ namespace detail { GLM_FUNC_QUALIFIER float nextafterf(float x, float y) { volatile float t; int hx, hy, ix, iy; GLM_GET_FLOAT_WORD(hx, x); GLM_GET_FLOAT_WORD(hy, y); ix = hx & 0x7fffffff; // |x| iy = hy & 0x7fffffff; // |y| if((ix > 0x7f800000) || // x is nan (iy > 0x7f800000)) // y is nan return x + y; if(abs(y - x) <= epsilon()) return y; // x=y, return y if(ix == 0) { // x == 0 GLM_SET_FLOAT_WORD(x, (hy & 0x80000000) | 1);// return +-minsubnormal t = x * x; if(abs(t - x) <= epsilon()) return t; else return x; // raise underflow flag } if(hx >= 0) { // x > 0 if(hx > hy) // x > y, x -= ulp hx -= 1; else // x < y, x += ulp hx += 1; } else { // x < 0 if(hy >= 0 || hx > hy) // x < y, x -= ulp hx -= 1; else // x > y, x += ulp hx += 1; } hy = hx & 0x7f800000; if(hy >= 0x7f800000) return x + x; // overflow if(hy < 0x00800000) // underflow { t = x * x; if(abs(t - x) > epsilon()) { // raise underflow flag GLM_SET_FLOAT_WORD(y, hx); return y; } } GLM_SET_FLOAT_WORD(x, hx); return x; } GLM_FUNC_QUALIFIER double nextafter(double x, double y) { volatile double t; int hx, hy, ix, iy; unsigned int lx, ly; GLM_EXTRACT_WORDS(hx, lx, x); GLM_EXTRACT_WORDS(hy, ly, y); ix = hx & 0x7fffffff; // |x| iy = hy & 0x7fffffff; // |y| if(((ix >= 0x7ff00000) && ((ix - 0x7ff00000) | lx) != 0) || // x is nan ((iy >= 0x7ff00000) && ((iy - 0x7ff00000) | ly) != 0)) // y is nan return x + y; if(abs(y - x) <= epsilon()) return y; // x=y, return y if((ix | lx) == 0) { // x == 0 GLM_INSERT_WORDS(x, hy & 0x80000000, 1); // return +-minsubnormal t = x * x; if(abs(t - x) <= epsilon()) return t; else return x; // raise underflow flag } if(hx >= 0) { // x > 0 if(hx > hy || ((hx == hy) && (lx > ly))) { // x > y, x -= ulp if(lx == 0) hx -= 1; lx -= 1; } else { // x < y, x += ulp lx += 1; if(lx == 0) hx += 1; } } else { // x < 0 if(hy >= 0 || hx > hy || ((hx == hy) && (lx > ly))){// x < y, x -= ulp if(lx == 0) hx -= 1; lx -= 1; } else { // x > y, x += ulp lx += 1; if(lx == 0) hx += 1; } } hy = hx & 0x7ff00000; if(hy >= 0x7ff00000) return x + x; // overflow if(hy < 0x00100000) { // underflow t = x * x; if(abs(t - x) > epsilon()) { // raise underflow flag GLM_INSERT_WORDS(y, hx, lx); return y; } } GLM_INSERT_WORDS(x, hx, lx); return x; } }//namespace detail }//namespace glm #if(GLM_COMPILER & GLM_COMPILER_VC) # pragma warning(pop) #endif namespace glm { template<> GLM_FUNC_QUALIFIER float nextFloat(float x) { # if GLM_HAS_CXX11_STL return std::nextafter(x, std::numeric_limits::max()); # elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) return detail::nextafterf(x, FLT_MAX); # elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) return __builtin_nextafterf(x, FLT_MAX); # else return nextafterf(x, FLT_MAX); # endif } template<> GLM_FUNC_QUALIFIER double nextFloat(double x) { # if GLM_HAS_CXX11_STL return std::nextafter(x, std::numeric_limits::max()); # elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) return detail::nextafter(x, std::numeric_limits::max()); # elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) return __builtin_nextafter(x, DBL_MAX); # else return nextafter(x, DBL_MAX); # endif } template GLM_FUNC_QUALIFIER T nextFloat(T x, int ULPs) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'next_float' only accept floating-point input"); assert(ULPs >= 0); T temp = x; for(int i = 0; i < ULPs; ++i) temp = nextFloat(temp); return temp; } GLM_FUNC_QUALIFIER float prevFloat(float x) { # if GLM_HAS_CXX11_STL return std::nextafter(x, std::numeric_limits::min()); # elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) return detail::nextafterf(x, FLT_MIN); # elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) return __builtin_nextafterf(x, FLT_MIN); # else return nextafterf(x, FLT_MIN); # endif } GLM_FUNC_QUALIFIER double prevFloat(double x) { # if GLM_HAS_CXX11_STL return std::nextafter(x, std::numeric_limits::min()); # elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) return _nextafter(x, DBL_MIN); # elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) return __builtin_nextafter(x, DBL_MIN); # else return nextafter(x, DBL_MIN); # endif } template GLM_FUNC_QUALIFIER T prevFloat(T x, int ULPs) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'prev_float' only accept floating-point input"); assert(ULPs >= 0); T temp = x; for(int i = 0; i < ULPs; ++i) temp = prevFloat(temp); return temp; } GLM_FUNC_QUALIFIER int floatDistance(float x, float y) { detail::float_t const a(x); detail::float_t const b(y); return abs(a.i - b.i); } GLM_FUNC_QUALIFIER int64 floatDistance(double x, double y) { detail::float_t const a(x); detail::float_t const b(y); return abs(a.i - b.i); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_bool1.hpp000066400000000000000000000012471360521144700242300ustar00rootroot00000000000000/// @ref ext_vector_bool1 /// @file glm/ext/vector_bool1.hpp /// /// @defgroup ext_vector_bool1 GLM_EXT_vector_bool1 /// @ingroup ext /// /// Exposes bvec1 vector type. /// /// Include to use the features of this extension. /// /// @see ext_vector_bool1_precision extension. #pragma once #include "../detail/type_vec1.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_vector_bool1 extension included") #endif namespace glm { /// @addtogroup ext_vector_bool1 /// @{ /// 1 components vector of boolean. typedef vec<1, bool, defaultp> bvec1; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_bool1_precision.hpp000066400000000000000000000016161360521144700263030ustar00rootroot00000000000000/// @ref ext_vector_bool1_precision /// @file glm/ext/vector_bool1_precision.hpp /// /// @defgroup ext_vector_bool1_precision GLM_EXT_vector_bool1_precision /// @ingroup ext /// /// Exposes highp_bvec1, mediump_bvec1 and lowp_bvec1 types. /// /// Include to use the features of this extension. #pragma once #include "../detail/type_vec1.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_vector_bool1_precision extension included") #endif namespace glm { /// @addtogroup ext_vector_bool1_precision /// @{ /// 1 component vector of bool values. typedef vec<1, bool, highp> highp_bvec1; /// 1 component vector of bool values. typedef vec<1, bool, mediump> mediump_bvec1; /// 1 component vector of bool values. typedef vec<1, bool, lowp> lowp_bvec1; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_bool2.hpp000066400000000000000000000006321360521144700242260ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_bool2.hpp #pragma once #include "../detail/type_vec2.hpp" namespace glm { /// @addtogroup core_vector /// @{ /// 2 components vector of boolean. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors typedef vec<2, bool, defaultp> bvec2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_bool2_precision.hpp000066400000000000000000000025331360521144700263030ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_bool2_precision.hpp #pragma once #include "../detail/type_vec2.hpp" namespace glm { /// @addtogroup core_vector_precision /// @{ /// 2 components vector of high qualifier bool numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<2, bool, highp> highp_bvec2; /// 2 components vector of medium qualifier bool numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<2, bool, mediump> mediump_bvec2; /// 2 components vector of low qualifier bool numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<2, bool, lowp> lowp_bvec2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_bool3.hpp000066400000000000000000000006321360521144700242270ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_bool3.hpp #pragma once #include "../detail/type_vec3.hpp" namespace glm { /// @addtogroup core_vector /// @{ /// 3 components vector of boolean. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors typedef vec<3, bool, defaultp> bvec3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_bool3_precision.hpp000066400000000000000000000025331360521144700263040ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_bool3_precision.hpp #pragma once #include "../detail/type_vec3.hpp" namespace glm { /// @addtogroup core_vector_precision /// @{ /// 3 components vector of high qualifier bool numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<3, bool, highp> highp_bvec3; /// 3 components vector of medium qualifier bool numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<3, bool, mediump> mediump_bvec3; /// 3 components vector of low qualifier bool numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<3, bool, lowp> lowp_bvec3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_bool4.hpp000066400000000000000000000006321360521144700242300ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_bool4.hpp #pragma once #include "../detail/type_vec4.hpp" namespace glm { /// @addtogroup core_vector /// @{ /// 4 components vector of boolean. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors typedef vec<4, bool, defaultp> bvec4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_bool4_precision.hpp000066400000000000000000000025331360521144700263050ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_bool4_precision.hpp #pragma once #include "../detail/type_vec4.hpp" namespace glm { /// @addtogroup core_vector_precision /// @{ /// 4 components vector of high qualifier bool numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<4, bool, highp> highp_bvec4; /// 4 components vector of medium qualifier bool numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<4, bool, mediump> mediump_bvec4; /// 4 components vector of low qualifier bool numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<4, bool, lowp> lowp_bvec4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_common.hpp000066400000000000000000000154441360521144700245100ustar00rootroot00000000000000/// @ref ext_vector_common /// @file glm/ext/vector_common.hpp /// /// @defgroup ext_vector_common GLM_EXT_vector_common /// @ingroup ext /// /// Exposes min and max functions for 3 to 4 vector parameters. /// /// Include to use the features of this extension. /// /// @see core_common /// @see ext_scalar_common #pragma once // Dependency: #include "../ext/scalar_common.hpp" #include "../common.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_vector_common extension included") #endif namespace glm { /// @addtogroup ext_vector_common /// @{ /// Return the minimum component-wise values of 3 inputs /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec min(vec const& a, vec const& b, vec const& c); /// Return the minimum component-wise values of 4 inputs /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec min(vec const& a, vec const& b, vec const& c, vec const& d); /// Return the maximum component-wise values of 3 inputs /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec max(vec const& x, vec const& y, vec const& z); /// Return the maximum component-wise values of 4 inputs /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec max( vec const& x, vec const& y, vec const& z, vec const& w); /// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see std::fmin documentation template GLM_FUNC_DECL vec fmin(vec const& x, T y); /// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see std::fmin documentation template GLM_FUNC_DECL vec fmin(vec const& x, vec const& y); /// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see std::fmin documentation template GLM_FUNC_DECL vec fmin(vec const& a, vec const& b, vec const& c); /// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see std::fmin documentation template GLM_FUNC_DECL vec fmin(vec const& a, vec const& b, vec const& c, vec const& d); /// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see std::fmax documentation template GLM_FUNC_DECL vec fmax(vec const& a, T b); /// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see std::fmax documentation template GLM_FUNC_DECL vec fmax(vec const& a, vec const& b); /// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see std::fmax documentation template GLM_FUNC_DECL vec fmax(vec const& a, vec const& b, vec const& c); /// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see std::fmax documentation template GLM_FUNC_DECL vec fmax(vec const& a, vec const& b, vec const& c, vec const& d); /// @} }//namespace glm #include "vector_common.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_common.inl000066400000000000000000000075251360521144700245040ustar00rootroot00000000000000#include "../detail/_vectorize.hpp" namespace glm { template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec min(vec const& x, vec const& y, vec const& z) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'min' only accept floating-point or integer inputs"); return glm::min(glm::min(x, y), z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec min(vec const& x, vec const& y, vec const& z, vec const& w) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'min' only accept floating-point or integer inputs"); return glm::min(glm::min(x, y), glm::min(z, w)); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec max(vec const& x, vec const& y, vec const& z) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'max' only accept floating-point or integer inputs"); return glm::max(glm::max(x, y), z); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec max(vec const& x, vec const& y, vec const& z, vec const& w) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'max' only accept floating-point or integer inputs"); return glm::max(glm::max(x, y), glm::max(z, w)); } template GLM_FUNC_QUALIFIER vec fmin(vec const& a, T b) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point inputs"); return detail::functor2::call(fmin, a, vec(b)); } template GLM_FUNC_QUALIFIER vec fmin(vec const& a, vec const& b) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point inputs"); return detail::functor2::call(fmin, a, b); } template GLM_FUNC_QUALIFIER vec fmin(vec const& a, vec const& b, vec const& c) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point inputs"); return fmin(fmin(a, b), c); } template GLM_FUNC_QUALIFIER vec fmin(vec const& a, vec const& b, vec const& c, vec const& d) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point inputs"); return fmin(fmin(a, b), fmin(c, d)); } template GLM_FUNC_QUALIFIER vec fmax(vec const& a, T b) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point inputs"); return detail::functor2::call(fmax, a, vec(b)); } template GLM_FUNC_QUALIFIER vec fmax(vec const& a, vec const& b) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point inputs"); return detail::functor2::call(fmax, a, b); } template GLM_FUNC_QUALIFIER vec fmax(vec const& a, vec const& b, vec const& c) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point inputs"); return fmax(fmax(a, b), c); } template GLM_FUNC_QUALIFIER vec fmax(vec const& a, vec const& b, vec const& c, vec const& d) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point inputs"); return fmax(fmax(a, b), fmax(c, d)); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_double1.hpp000066400000000000000000000014551360521144700245500ustar00rootroot00000000000000/// @ref ext_vector_double1 /// @file glm/ext/vector_double1.hpp /// /// @defgroup ext_vector_double1 GLM_EXT_vector_double1 /// @ingroup ext /// /// Exposes double-precision floating point vector type with one component. /// /// Include to use the features of this extension. /// /// @see ext_vector_double1_precision extension. /// @see ext_vector_float1 extension. #pragma once #include "../detail/type_vec1.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_vector_double1 extension included") #endif namespace glm { /// @addtogroup ext_vector_double1 /// @{ /// 1 components vector of double-precision floating-point numbers. typedef vec<1, double, defaultp> dvec1; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_double1_precision.hpp000066400000000000000000000022471360521144700266230ustar00rootroot00000000000000/// @ref ext_vector_double1_precision /// @file glm/ext/vector_double1_precision.hpp /// /// @defgroup ext_vector_double1_precision GLM_EXT_vector_double1_precision /// @ingroup ext /// /// Exposes highp_dvec1, mediump_dvec1 and lowp_dvec1 types. /// /// Include to use the features of this extension. /// /// @see ext_vector_double1 #pragma once #include "../detail/type_vec1.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_vector_double1_precision extension included") #endif namespace glm { /// @addtogroup ext_vector_double1_precision /// @{ /// 1 component vector of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef vec<1, double, highp> highp_dvec1; /// 1 component vector of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef vec<1, double, mediump> mediump_dvec1; /// 1 component vector of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef vec<1, double, lowp> lowp_dvec1; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_double2.hpp000066400000000000000000000006761360521144700245550ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_double2.hpp #pragma once #include "../detail/type_vec2.hpp" namespace glm { /// @addtogroup core_vector /// @{ /// 2 components vector of double-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors typedef vec<2, double, defaultp> dvec2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_double2_precision.hpp000066400000000000000000000026271360521144700266260ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_double2_precision.hpp #pragma once #include "../detail/type_vec2.hpp" namespace glm { /// @addtogroup core_vector_precision /// @{ /// 2 components vector of high double-qualifier floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<2, double, highp> highp_dvec2; /// 2 components vector of medium double-qualifier floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<2, double, mediump> mediump_dvec2; /// 2 components vector of low double-qualifier floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<2, double, lowp> lowp_dvec2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_double3.hpp000066400000000000000000000006761360521144700245560ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_double3.hpp #pragma once #include "../detail/type_vec3.hpp" namespace glm { /// @addtogroup core_vector /// @{ /// 3 components vector of double-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors typedef vec<3, double, defaultp> dvec3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_double3_precision.hpp000066400000000000000000000030661360521144700266250ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_double3_precision.hpp #pragma once #include "../detail/type_vec3.hpp" namespace glm { /// @addtogroup core_vector_precision /// @{ /// 3 components vector of high double-qualifier floating-point numbers. /// There is no guarantee on the actual qualifier. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<3, double, highp> highp_dvec3; /// 3 components vector of medium double-qualifier floating-point numbers. /// There is no guarantee on the actual qualifier. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<3, double, mediump> mediump_dvec3; /// 3 components vector of low double-qualifier floating-point numbers. /// There is no guarantee on the actual qualifier. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<3, double, lowp> lowp_dvec3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_double4.hpp000066400000000000000000000006761360521144700245570ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_double4.hpp #pragma once #include "../detail/type_vec4.hpp" namespace glm { /// @addtogroup core_vector /// @{ /// 4 components vector of double-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors typedef vec<4, double, defaultp> dvec4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_double4_precision.hpp000066400000000000000000000031261360521144700266230ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_double4_precision.hpp #pragma once #include "../detail/setup.hpp" #include "../detail/type_vec4.hpp" namespace glm { /// @addtogroup core_vector_precision /// @{ /// 4 components vector of high double-qualifier floating-point numbers. /// There is no guarantee on the actual qualifier. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<4, double, highp> highp_dvec4; /// 4 components vector of medium double-qualifier floating-point numbers. /// There is no guarantee on the actual qualifier. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<4, double, mediump> mediump_dvec4; /// 4 components vector of low double-qualifier floating-point numbers. /// There is no guarantee on the actual qualifier. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<4, double, lowp> lowp_dvec4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_float1.hpp000066400000000000000000000014441360521144700244010ustar00rootroot00000000000000/// @ref ext_vector_float1 /// @file glm/ext/vector_float1.hpp /// /// @defgroup ext_vector_float1 GLM_EXT_vector_float1 /// @ingroup ext /// /// Exposes single-precision floating point vector type with one component. /// /// Include to use the features of this extension. /// /// @see ext_vector_float1_precision extension. /// @see ext_vector_double1 extension. #pragma once #include "../detail/type_vec1.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_vector_float1 extension included") #endif namespace glm { /// @addtogroup ext_vector_float1 /// @{ /// 1 components vector of single-precision floating-point numbers. typedef vec<1, float, defaultp> vec1; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_float1_precision.hpp000066400000000000000000000022421360521144700264510ustar00rootroot00000000000000/// @ref ext_vector_float1_precision /// @file glm/ext/vector_float1_precision.hpp /// /// @defgroup ext_vector_float1_precision GLM_EXT_vector_float1_precision /// @ingroup ext /// /// Exposes highp_vec1, mediump_vec1 and lowp_vec1 types. /// /// Include to use the features of this extension. /// /// @see ext_vector_float1 extension. #pragma once #include "../detail/type_vec1.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_vector_float1_precision extension included") #endif namespace glm { /// @addtogroup ext_vector_float1_precision /// @{ /// 1 component vector of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef vec<1, float, highp> highp_vec1; /// 1 component vector of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef vec<1, float, mediump> mediump_vec1; /// 1 component vector of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef vec<1, float, lowp> lowp_vec1; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_float2.hpp000066400000000000000000000006721360521144700244040ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_float2.hpp #pragma once #include "../detail/type_vec2.hpp" namespace glm { /// @addtogroup core_vector /// @{ /// 2 components vector of single-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors typedef vec<2, float, defaultp> vec2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_float2_precision.hpp000066400000000000000000000026211360521144700264530ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_float2_precision.hpp #pragma once #include "../detail/type_vec2.hpp" namespace glm { /// @addtogroup core_vector_precision /// @{ /// 2 components vector of high single-qualifier floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<2, float, highp> highp_vec2; /// 2 components vector of medium single-qualifier floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<2, float, mediump> mediump_vec2; /// 2 components vector of low single-qualifier floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<2, float, lowp> lowp_vec2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_float3.hpp000066400000000000000000000006731360521144700244060ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_float3.hpp #pragma once #include "../detail/type_vec3.hpp" namespace glm { /// @addtogroup core_vector /// @{ /// 3 components vector of single-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors typedef vec<3, float, defaultp> vec3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_float3_precision.hpp000066400000000000000000000026211360521144700264540ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_float3_precision.hpp #pragma once #include "../detail/type_vec3.hpp" namespace glm { /// @addtogroup core_vector_precision /// @{ /// 3 components vector of high single-qualifier floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<3, float, highp> highp_vec3; /// 3 components vector of medium single-qualifier floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<3, float, mediump> mediump_vec3; /// 3 components vector of low single-qualifier floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<3, float, lowp> lowp_vec3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_float4.hpp000066400000000000000000000006731360521144700244070ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_float4.hpp #pragma once #include "../detail/type_vec4.hpp" namespace glm { /// @addtogroup core_vector /// @{ /// 4 components vector of single-precision floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors typedef vec<4, float, defaultp> vec4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_float4_precision.hpp000066400000000000000000000026211360521144700264550ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_float4_precision.hpp #pragma once #include "../detail/type_vec4.hpp" namespace glm { /// @addtogroup core_vector_precision /// @{ /// 4 components vector of high single-qualifier floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<4, float, highp> highp_vec4; /// 4 components vector of medium single-qualifier floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<4, float, mediump> mediump_vec4; /// 4 components vector of low single-qualifier floating-point numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<4, float, lowp> lowp_vec4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_int1.hpp000066400000000000000000000013251360521144700240640ustar00rootroot00000000000000/// @ref ext_vector_int1 /// @file glm/ext/vector_int1.hpp /// /// @defgroup ext_vector_int1 GLM_EXT_vector_int1 /// @ingroup ext /// /// Exposes ivec1 vector type. /// /// Include to use the features of this extension. /// /// @see ext_vector_uint1 extension. /// @see ext_vector_int1_precision extension. #pragma once #include "../detail/type_vec1.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_vector_int1 extension included") #endif namespace glm { /// @addtogroup ext_vector_int1 /// @{ /// 1 component vector of signed integer numbers. typedef vec<1, int, defaultp> ivec1; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_int1_precision.hpp000066400000000000000000000016421360521144700261410ustar00rootroot00000000000000/// @ref ext_vector_int1_precision /// @file glm/ext/vector_int1_precision.hpp /// /// @defgroup ext_vector_int1_precision GLM_EXT_vector_int1_precision /// @ingroup ext /// /// Exposes highp_ivec1, mediump_ivec1 and lowp_ivec1 types. /// /// Include to use the features of this extension. #pragma once #include "../detail/type_vec1.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_vector_int1_precision extension included") #endif namespace glm { /// @addtogroup ext_vector_int1_precision /// @{ /// 1 component vector of signed integer values. typedef vec<1, int, highp> highp_ivec1; /// 1 component vector of signed integer values. typedef vec<1, int, mediump> mediump_ivec1; /// 1 component vector of signed integer values. typedef vec<1, int, lowp> lowp_ivec1; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_int2.hpp000066400000000000000000000006471360521144700240730ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_int2.hpp #pragma once #include "../detail/type_vec2.hpp" namespace glm { /// @addtogroup core_vector /// @{ /// 2 components vector of signed integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors typedef vec<2, int, defaultp> ivec2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_int2_precision.hpp000066400000000000000000000025651360521144700261470ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_int2_precision.hpp #pragma once #include "../detail/type_vec2.hpp" namespace glm { /// @addtogroup core_vector_precision /// @{ /// 2 components vector of high qualifier signed integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<2, int, highp> highp_ivec2; /// 2 components vector of medium qualifier signed integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<2, int, mediump> mediump_ivec2; /// 2 components vector of low qualifier signed integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<2, int, lowp> lowp_ivec2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_int3.hpp000066400000000000000000000006471360521144700240740ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_int3.hpp #pragma once #include "../detail/type_vec3.hpp" namespace glm { /// @addtogroup core_vector /// @{ /// 3 components vector of signed integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors typedef vec<3, int, defaultp> ivec3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_int3_precision.hpp000066400000000000000000000025651360521144700261500ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_int3_precision.hpp #pragma once #include "../detail/type_vec3.hpp" namespace glm { /// @addtogroup core_vector_precision /// @{ /// 3 components vector of high qualifier signed integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<3, int, highp> highp_ivec3; /// 3 components vector of medium qualifier signed integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<3, int, mediump> mediump_ivec3; /// 3 components vector of low qualifier signed integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<3, int, lowp> lowp_ivec3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_int4.hpp000066400000000000000000000006471360521144700240750ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_int4.hpp #pragma once #include "../detail/type_vec4.hpp" namespace glm { /// @addtogroup core_vector /// @{ /// 4 components vector of signed integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors typedef vec<4, int, defaultp> ivec4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_int4_precision.hpp000066400000000000000000000025651360521144700261510ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_int4_precision.hpp #pragma once #include "../detail/type_vec4.hpp" namespace glm { /// @addtogroup core_vector_precision /// @{ /// 4 components vector of high qualifier signed integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<4, int, highp> highp_ivec4; /// 4 components vector of medium qualifier signed integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<4, int, mediump> mediump_ivec4; /// 4 components vector of low qualifier signed integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<4, int, lowp> lowp_ivec4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_integer.hpp000066400000000000000000000130331360521144700246450ustar00rootroot00000000000000/// @ref ext_vector_integer /// @file glm/ext/vector_integer.hpp /// /// @see core (dependence) /// @see ext_vector_integer (dependence) /// /// @defgroup ext_vector_integer GLM_EXT_vector_integer /// @ingroup ext /// /// Include to use the features of this extension. #pragma once // Dependencies #include "../detail/setup.hpp" #include "../detail/qualifier.hpp" #include "../detail/_vectorize.hpp" #include "../vector_relational.hpp" #include "../common.hpp" #include #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_vector_integer extension included") #endif namespace glm { /// @addtogroup ext_vector_integer /// @{ /// Return true if the value is a power of two number. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Signed or unsigned integer scalar types. /// @tparam Q Value from qualifier enum /// /// @see ext_vector_integer template GLM_FUNC_DECL vec isPowerOfTwo(vec const& v); /// Return the power of two number which value is just higher the input value, /// round up to a power of two. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Signed or unsigned integer scalar types. /// @tparam Q Value from qualifier enum /// /// @see ext_vector_integer template GLM_FUNC_DECL vec nextPowerOfTwo(vec const& v); /// Return the power of two number which value is just lower the input value, /// round down to a power of two. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Signed or unsigned integer scalar types. /// @tparam Q Value from qualifier enum /// /// @see ext_vector_integer template GLM_FUNC_DECL vec prevPowerOfTwo(vec const& v); /// Return true if the 'Value' is a multiple of 'Multiple'. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Signed or unsigned integer scalar types. /// @tparam Q Value from qualifier enum /// /// @see ext_vector_integer template GLM_FUNC_DECL vec isMultiple(vec const& v, T Multiple); /// Return true if the 'Value' is a multiple of 'Multiple'. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Signed or unsigned integer scalar types. /// @tparam Q Value from qualifier enum /// /// @see ext_vector_integer template GLM_FUNC_DECL vec isMultiple(vec const& v, vec const& Multiple); /// Higher multiple number of Source. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Signed or unsigned integer scalar types. /// @tparam Q Value from qualifier enum /// /// @param v Source values to which is applied the function /// @param Multiple Must be a null or positive value /// /// @see ext_vector_integer template GLM_FUNC_DECL vec nextMultiple(vec const& v, T Multiple); /// Higher multiple number of Source. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Signed or unsigned integer scalar types. /// @tparam Q Value from qualifier enum /// /// @param v Source values to which is applied the function /// @param Multiple Must be a null or positive value /// /// @see ext_vector_integer template GLM_FUNC_DECL vec nextMultiple(vec const& v, vec const& Multiple); /// Lower multiple number of Source. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Signed or unsigned integer scalar types. /// @tparam Q Value from qualifier enum /// /// @param v Source values to which is applied the function /// @param Multiple Must be a null or positive value /// /// @see ext_vector_integer template GLM_FUNC_DECL vec prevMultiple(vec const& v, T Multiple); /// Lower multiple number of Source. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Signed or unsigned integer scalar types. /// @tparam Q Value from qualifier enum /// /// @param v Source values to which is applied the function /// @param Multiple Must be a null or positive value /// /// @see ext_vector_integer template GLM_FUNC_DECL vec prevMultiple(vec const& v, vec const& Multiple); /// Returns the bit number of the Nth significant bit set to /// 1 in the binary representation of value. /// If value bitcount is less than the Nth significant bit, -1 will be returned. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T Signed or unsigned integer scalar types. /// /// @see ext_vector_integer template GLM_FUNC_DECL vec findNSB(vec const& Source, vec SignificantBitCount); /// @} } //namespace glm #include "vector_integer.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_integer.inl000066400000000000000000000065221360521144700246450ustar00rootroot00000000000000#include "scalar_integer.hpp" namespace glm { template GLM_FUNC_QUALIFIER vec isPowerOfTwo(vec const& Value) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'isPowerOfTwo' only accept integer inputs"); vec const Result(abs(Value)); return equal(Result & (Result - vec(1)), vec(0)); } template GLM_FUNC_QUALIFIER vec nextPowerOfTwo(vec const& v) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'nextPowerOfTwo' only accept integer inputs"); return detail::compute_ceilPowerOfTwo::is_signed>::call(v); } template GLM_FUNC_QUALIFIER vec prevPowerOfTwo(vec const& v) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'prevPowerOfTwo' only accept integer inputs"); return detail::functor1::call(prevPowerOfTwo, v); } template GLM_FUNC_QUALIFIER vec isMultiple(vec const& Value, T Multiple) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'isMultiple' only accept integer inputs"); return (Value % Multiple) == vec(0); } template GLM_FUNC_QUALIFIER vec isMultiple(vec const& Value, vec const& Multiple) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'isMultiple' only accept integer inputs"); return (Value % Multiple) == vec(0); } template GLM_FUNC_QUALIFIER vec nextMultiple(vec const& Source, T Multiple) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'nextMultiple' only accept integer inputs"); return detail::functor2::call(nextMultiple, Source, vec(Multiple)); } template GLM_FUNC_QUALIFIER vec nextMultiple(vec const& Source, vec const& Multiple) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'nextMultiple' only accept integer inputs"); return detail::functor2::call(nextMultiple, Source, Multiple); } template GLM_FUNC_QUALIFIER vec prevMultiple(vec const& Source, T Multiple) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'prevMultiple' only accept integer inputs"); return detail::functor2::call(prevMultiple, Source, vec(Multiple)); } template GLM_FUNC_QUALIFIER vec prevMultiple(vec const& Source, vec const& Multiple) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'prevMultiple' only accept integer inputs"); return detail::functor2::call(prevMultiple, Source, Multiple); } template GLM_FUNC_QUALIFIER vec findNSB(vec const& Source, vec SignificantBitCount) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'findNSB' only accept integer inputs"); return detail::functor2_vec_int::call(findNSB, Source, SignificantBitCount); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_relational.hpp000066400000000000000000000110341360521144700253410ustar00rootroot00000000000000/// @ref ext_vector_relational /// @file glm/ext/vector_relational.hpp /// /// @see core (dependence) /// @see ext_scalar_integer (dependence) /// /// @defgroup ext_vector_relational GLM_EXT_vector_relational /// @ingroup ext /// /// Exposes comparison functions for vector types that take a user defined epsilon values. /// /// Include to use the features of this extension. /// /// @see core_vector_relational /// @see ext_scalar_relational /// @see ext_matrix_relational #pragma once // Dependencies #include "../detail/qualifier.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_vector_relational extension included") #endif namespace glm { /// @addtogroup ext_vector_relational /// @{ /// Returns the component-wise comparison of |x - y| < epsilon. /// True if this expression is satisfied. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec equal(vec const& x, vec const& y, T epsilon); /// Returns the component-wise comparison of |x - y| < epsilon. /// True if this expression is satisfied. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec equal(vec const& x, vec const& y, vec const& epsilon); /// Returns the component-wise comparison of |x - y| >= epsilon. /// True if this expression is not satisfied. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, T epsilon); /// Returns the component-wise comparison of |x - y| >= epsilon. /// True if this expression is not satisfied. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, vec const& epsilon); /// Returns the component-wise comparison between two vectors in term of ULPs. /// True if this expression is satisfied. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec equal(vec const& x, vec const& y, int ULPs); /// Returns the component-wise comparison between two vectors in term of ULPs. /// True if this expression is satisfied. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec equal(vec const& x, vec const& y, vec const& ULPs); /// Returns the component-wise comparison between two vectors in term of ULPs. /// True if this expression is not satisfied. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, int ULPs); /// Returns the component-wise comparison between two vectors in term of ULPs. /// True if this expression is not satisfied. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point /// @tparam Q Value from qualifier enum template GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, vec const& ULPs); /// @} }//namespace glm #include "vector_relational.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_relational.inl000066400000000000000000000047511360521144700253440ustar00rootroot00000000000000#include "../vector_relational.hpp" #include "../common.hpp" #include "../detail/qualifier.hpp" #include "../detail/type_float.hpp" namespace glm { template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(vec const& x, vec const& y, T Epsilon) { return equal(x, y, vec(Epsilon)); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(vec const& x, vec const& y, vec const& Epsilon) { return lessThanEqual(abs(x - y), Epsilon); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, T Epsilon) { return notEqual(x, y, vec(Epsilon)); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, vec const& Epsilon) { return greaterThan(abs(x - y), Epsilon); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(vec const& x, vec const& y, int MaxULPs) { return equal(x, y, vec(MaxULPs)); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec equal(vec const& x, vec const& y, vec const& MaxULPs) { vec Result(false); for(length_t i = 0; i < L; ++i) { detail::float_t const a(x[i]); detail::float_t const b(y[i]); // Different signs means they do not match. if(a.negative() != b.negative()) { // Check for equality to make sure +0==-0 Result[i] = a.mantissa() == b.mantissa() && a.exponent() == b.exponent(); } else { // Find the difference in ULPs. typename detail::float_t::int_type const DiffULPs = abs(a.i - b.i); Result[i] = DiffULPs <= MaxULPs[i]; } } return Result; } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, int MaxULPs) { return notEqual(x, y, vec(MaxULPs)); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y, vec const& MaxULPs) { return not_(equal(x, y, MaxULPs)); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_uint1.hpp000066400000000000000000000013471360521144700242550ustar00rootroot00000000000000/// @ref ext_vector_uint1 /// @file glm/ext/vector_uint1.hpp /// /// @defgroup ext_vector_uint1 GLM_EXT_vector_uint1 /// @ingroup ext /// /// Exposes uvec1 vector type. /// /// Include to use the features of this extension. /// /// @see ext_vector_int1 extension. /// @see ext_vector_uint1_precision extension. #pragma once #include "../detail/type_vec1.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_vector_uint1 extension included") #endif namespace glm { /// @addtogroup ext_vector_uint1 /// @{ /// 1 component vector of unsigned integer numbers. typedef vec<1, unsigned int, defaultp> uvec1; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_uint1_precision.hpp000066400000000000000000000021161360521144700263230ustar00rootroot00000000000000/// @ref ext_vector_uint1_precision /// @file glm/ext/vector_uint1_precision.hpp /// /// @defgroup ext_vector_uint1_precision GLM_EXT_vector_uint1_precision /// @ingroup ext /// /// Exposes highp_uvec1, mediump_uvec1 and lowp_uvec1 types. /// /// Include to use the features of this extension. #pragma once #include "../detail/type_vec1.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_vector_uint1_precision extension included") #endif namespace glm { /// @addtogroup ext_vector_uint1_precision /// @{ /// 1 component vector of unsigned integer values. /// /// @see ext_vector_uint1_precision typedef vec<1, unsigned int, highp> highp_uvec1; /// 1 component vector of unsigned integer values. /// /// @see ext_vector_uint1_precision typedef vec<1, unsigned int, mediump> mediump_uvec1; /// 1 component vector of unsigned integer values. /// /// @see ext_vector_uint1_precision typedef vec<1, unsigned int, lowp> lowp_uvec1; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_uint2.hpp000066400000000000000000000006631360521144700242560ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_uint2.hpp #pragma once #include "../detail/type_vec2.hpp" namespace glm { /// @addtogroup core_vector /// @{ /// 2 components vector of unsigned integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors typedef vec<2, unsigned int, defaultp> uvec2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_uint2_precision.hpp000066400000000000000000000026271360521144700263330ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_uint2_precision.hpp #pragma once #include "../detail/type_vec2.hpp" namespace glm { /// @addtogroup core_vector_precision /// @{ /// 2 components vector of high qualifier unsigned integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<2, unsigned int, highp> highp_uvec2; /// 2 components vector of medium qualifier unsigned integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<2, unsigned int, mediump> mediump_uvec2; /// 2 components vector of low qualifier unsigned integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<2, unsigned int, lowp> lowp_uvec2; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_uint3.hpp000066400000000000000000000006631360521144700242570ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_uint3.hpp #pragma once #include "../detail/type_vec3.hpp" namespace glm { /// @addtogroup core_vector /// @{ /// 3 components vector of unsigned integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors typedef vec<3, unsigned int, defaultp> uvec3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_uint3_precision.hpp000066400000000000000000000026271360521144700263340ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_uint3_precision.hpp #pragma once #include "../detail/type_vec3.hpp" namespace glm { /// @addtogroup core_vector_precision /// @{ /// 3 components vector of high qualifier unsigned integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<3, unsigned int, highp> highp_uvec3; /// 3 components vector of medium qualifier unsigned integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<3, unsigned int, mediump> mediump_uvec3; /// 3 components vector of low qualifier unsigned integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<3, unsigned int, lowp> lowp_uvec3; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_uint4.hpp000066400000000000000000000006631360521144700242600ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_uint4.hpp #pragma once #include "../detail/type_vec4.hpp" namespace glm { /// @addtogroup core_vector /// @{ /// 4 components vector of unsigned integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors typedef vec<4, unsigned int, defaultp> uvec4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_uint4_precision.hpp000066400000000000000000000026271360521144700263350ustar00rootroot00000000000000/// @ref core /// @file glm/ext/vector_uint4_precision.hpp #pragma once #include "../detail/type_vec4.hpp" namespace glm { /// @addtogroup core_vector_precision /// @{ /// 4 components vector of high qualifier unsigned integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<4, unsigned int, highp> highp_uvec4; /// 4 components vector of medium qualifier unsigned integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<4, unsigned int, mediump> mediump_uvec4; /// 4 components vector of low qualifier unsigned integer numbers. /// /// @see GLSL 4.20.8 specification, section 4.1.5 Vectors /// @see GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier typedef vec<4, unsigned int, lowp> lowp_uvec4; /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_ulp.hpp000066400000000000000000000075651360521144700240250ustar00rootroot00000000000000/// @ref ext_vector_ulp /// @file glm/ext/vector_ulp.hpp /// /// @defgroup ext_vector_ulp GLM_EXT_vector_ulp /// @ingroup ext /// /// Allow the measurement of the accuracy of a function against a reference /// implementation. This extension works on floating-point data and provide results /// in ULP. /// /// Include to use the features of this extension. /// /// @see ext_scalar_ulp /// @see ext_scalar_relational /// @see ext_vector_relational #pragma once // Dependencies #include "../ext/scalar_ulp.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_EXT_vector_ulp extension included") #endif namespace glm { /// Return the next ULP value(s) after the input value(s). /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point /// @tparam Q Value from qualifier enum /// /// @see ext_scalar_ulp template GLM_FUNC_DECL vec nextFloat(vec const& x); /// Return the value(s) ULP distance after the input value(s). /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point /// @tparam Q Value from qualifier enum /// /// @see ext_scalar_ulp template GLM_FUNC_DECL vec nextFloat(vec const& x, int ULPs); /// Return the value(s) ULP distance after the input value(s). /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point /// @tparam Q Value from qualifier enum /// /// @see ext_scalar_ulp template GLM_FUNC_DECL vec nextFloat(vec const& x, vec const& ULPs); /// Return the previous ULP value(s) before the input value(s). /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point /// @tparam Q Value from qualifier enum /// /// @see ext_scalar_ulp template GLM_FUNC_DECL vec prevFloat(vec const& x); /// Return the value(s) ULP distance before the input value(s). /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point /// @tparam Q Value from qualifier enum /// /// @see ext_scalar_ulp template GLM_FUNC_DECL vec prevFloat(vec const& x, int ULPs); /// Return the value(s) ULP distance before the input value(s). /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point /// @tparam Q Value from qualifier enum /// /// @see ext_scalar_ulp template GLM_FUNC_DECL vec prevFloat(vec const& x, vec const& ULPs); /// Return the distance in the number of ULP between 2 single-precision floating-point scalars. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam Q Value from qualifier enum /// /// @see ext_scalar_ulp template GLM_FUNC_DECL vec floatDistance(vec const& x, vec const& y); /// Return the distance in the number of ULP between 2 double-precision floating-point scalars. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam Q Value from qualifier enum /// /// @see ext_scalar_ulp template GLM_FUNC_DECL vec floatDistance(vec const& x, vec const& y); /// @} }//namespace glm #include "vector_ulp.inl" connectome-workbench-1.4.2/src/GLMath/glm/ext/vector_ulp.inl000066400000000000000000000043341360521144700240070ustar00rootroot00000000000000namespace glm { template GLM_FUNC_QUALIFIER vec nextFloat(vec const& x) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = nextFloat(x[i]); return Result; } template GLM_FUNC_QUALIFIER vec nextFloat(vec const& x, int ULPs) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = nextFloat(x[i], ULPs); return Result; } template GLM_FUNC_QUALIFIER vec nextFloat(vec const& x, vec const& ULPs) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = nextFloat(x[i], ULPs[i]); return Result; } template GLM_FUNC_QUALIFIER vec prevFloat(vec const& x) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = prevFloat(x[i]); return Result; } template GLM_FUNC_QUALIFIER vec prevFloat(vec const& x, int ULPs) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = prevFloat(x[i], ULPs); return Result; } template GLM_FUNC_QUALIFIER vec prevFloat(vec const& x, vec const& ULPs) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = prevFloat(x[i], ULPs[i]); return Result; } template GLM_FUNC_QUALIFIER vec floatDistance(vec const& x, vec const& y) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = floatDistance(x[i], y[i]); return Result; } template GLM_FUNC_QUALIFIER vec floatDistance(vec const& x, vec const& y) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = floatDistance(x[i], y[i]); return Result; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/fwd.hpp000066400000000000000000000673341360521144700216230ustar00rootroot00000000000000#pragma once #include "detail/qualifier.hpp" namespace glm { #if GLM_HAS_EXTENDED_INTEGER_TYPE typedef std::int8_t int8; typedef std::int16_t int16; typedef std::int32_t int32; typedef std::int64_t int64; typedef std::uint8_t uint8; typedef std::uint16_t uint16; typedef std::uint32_t uint32; typedef std::uint64_t uint64; #else typedef signed char int8; typedef signed short int16; typedef signed int int32; typedef detail::int64 int64; typedef unsigned char uint8; typedef unsigned short uint16; typedef unsigned int uint32; typedef detail::uint64 uint64; #endif // Scalar int typedef int8 lowp_i8; typedef int8 mediump_i8; typedef int8 highp_i8; typedef int8 i8; typedef int8 lowp_int8; typedef int8 mediump_int8; typedef int8 highp_int8; typedef int8 lowp_int8_t; typedef int8 mediump_int8_t; typedef int8 highp_int8_t; typedef int8 int8_t; typedef int16 lowp_i16; typedef int16 mediump_i16; typedef int16 highp_i16; typedef int16 i16; typedef int16 lowp_int16; typedef int16 mediump_int16; typedef int16 highp_int16; typedef int16 lowp_int16_t; typedef int16 mediump_int16_t; typedef int16 highp_int16_t; typedef int16 int16_t; typedef int32 lowp_i32; typedef int32 mediump_i32; typedef int32 highp_i32; typedef int32 i32; typedef int32 lowp_int32; typedef int32 mediump_int32; typedef int32 highp_int32; typedef int32 lowp_int32_t; typedef int32 mediump_int32_t; typedef int32 highp_int32_t; typedef int32 int32_t; typedef int64 lowp_i64; typedef int64 mediump_i64; typedef int64 highp_i64; typedef int64 i64; typedef int64 lowp_int64; typedef int64 mediump_int64; typedef int64 highp_int64; typedef int64 lowp_int64_t; typedef int64 mediump_int64_t; typedef int64 highp_int64_t; typedef int64 int64_t; // Scalar uint typedef uint8 lowp_u8; typedef uint8 mediump_u8; typedef uint8 highp_u8; typedef uint8 u8; typedef uint8 lowp_uint8; typedef uint8 mediump_uint8; typedef uint8 highp_uint8; typedef uint8 lowp_uint8_t; typedef uint8 mediump_uint8_t; typedef uint8 highp_uint8_t; typedef uint8 uint8_t; typedef uint16 lowp_u16; typedef uint16 mediump_u16; typedef uint16 highp_u16; typedef uint16 u16; typedef uint16 lowp_uint16; typedef uint16 mediump_uint16; typedef uint16 highp_uint16; typedef uint16 lowp_uint16_t; typedef uint16 mediump_uint16_t; typedef uint16 highp_uint16_t; typedef uint16 uint16_t; typedef uint32 lowp_u32; typedef uint32 mediump_u32; typedef uint32 highp_u32; typedef uint32 u32; typedef uint32 lowp_uint32; typedef uint32 mediump_uint32; typedef uint32 highp_uint32; typedef uint32 lowp_uint32_t; typedef uint32 mediump_uint32_t; typedef uint32 highp_uint32_t; typedef uint32 uint32_t; typedef uint64 lowp_u64; typedef uint64 mediump_u64; typedef uint64 highp_u64; typedef uint64 u64; typedef uint64 lowp_uint64; typedef uint64 mediump_uint64; typedef uint64 highp_uint64; typedef uint64 lowp_uint64_t; typedef uint64 mediump_uint64_t; typedef uint64 highp_uint64_t; typedef uint64 uint64_t; // Scalar float typedef float lowp_f32; typedef float mediump_f32; typedef float highp_f32; typedef float f32; typedef float lowp_float32; typedef float mediump_float32; typedef float highp_float32; typedef float float32; typedef float lowp_float32_t; typedef float mediump_float32_t; typedef float highp_float32_t; typedef float float32_t; typedef double lowp_f64; typedef double mediump_f64; typedef double highp_f64; typedef double f64; typedef double lowp_float64; typedef double mediump_float64; typedef double highp_float64; typedef double float64; typedef double lowp_float64_t; typedef double mediump_float64_t; typedef double highp_float64_t; typedef double float64_t; // Vector bool typedef vec<1, bool, lowp> lowp_bvec1; typedef vec<2, bool, lowp> lowp_bvec2; typedef vec<3, bool, lowp> lowp_bvec3; typedef vec<4, bool, lowp> lowp_bvec4; typedef vec<1, bool, mediump> mediump_bvec1; typedef vec<2, bool, mediump> mediump_bvec2; typedef vec<3, bool, mediump> mediump_bvec3; typedef vec<4, bool, mediump> mediump_bvec4; typedef vec<1, bool, highp> highp_bvec1; typedef vec<2, bool, highp> highp_bvec2; typedef vec<3, bool, highp> highp_bvec3; typedef vec<4, bool, highp> highp_bvec4; typedef vec<1, bool, defaultp> bvec1; typedef vec<2, bool, defaultp> bvec2; typedef vec<3, bool, defaultp> bvec3; typedef vec<4, bool, defaultp> bvec4; // Vector int typedef vec<1, i32, lowp> lowp_ivec1; typedef vec<2, i32, lowp> lowp_ivec2; typedef vec<3, i32, lowp> lowp_ivec3; typedef vec<4, i32, lowp> lowp_ivec4; typedef vec<1, i32, mediump> mediump_ivec1; typedef vec<2, i32, mediump> mediump_ivec2; typedef vec<3, i32, mediump> mediump_ivec3; typedef vec<4, i32, mediump> mediump_ivec4; typedef vec<1, i32, highp> highp_ivec1; typedef vec<2, i32, highp> highp_ivec2; typedef vec<3, i32, highp> highp_ivec3; typedef vec<4, i32, highp> highp_ivec4; typedef vec<1, i32, defaultp> ivec1; typedef vec<2, i32, defaultp> ivec2; typedef vec<3, i32, defaultp> ivec3; typedef vec<4, i32, defaultp> ivec4; typedef vec<1, i8, lowp> lowp_i8vec1; typedef vec<2, i8, lowp> lowp_i8vec2; typedef vec<3, i8, lowp> lowp_i8vec3; typedef vec<4, i8, lowp> lowp_i8vec4; typedef vec<1, i8, mediump> mediump_i8vec1; typedef vec<2, i8, mediump> mediump_i8vec2; typedef vec<3, i8, mediump> mediump_i8vec3; typedef vec<4, i8, mediump> mediump_i8vec4; typedef vec<1, i8, highp> highp_i8vec1; typedef vec<2, i8, highp> highp_i8vec2; typedef vec<3, i8, highp> highp_i8vec3; typedef vec<4, i8, highp> highp_i8vec4; typedef vec<1, i8, defaultp> i8vec1; typedef vec<2, i8, defaultp> i8vec2; typedef vec<3, i8, defaultp> i8vec3; typedef vec<4, i8, defaultp> i8vec4; typedef vec<1, i16, lowp> lowp_i16vec1; typedef vec<2, i16, lowp> lowp_i16vec2; typedef vec<3, i16, lowp> lowp_i16vec3; typedef vec<4, i16, lowp> lowp_i16vec4; typedef vec<1, i16, mediump> mediump_i16vec1; typedef vec<2, i16, mediump> mediump_i16vec2; typedef vec<3, i16, mediump> mediump_i16vec3; typedef vec<4, i16, mediump> mediump_i16vec4; typedef vec<1, i16, highp> highp_i16vec1; typedef vec<2, i16, highp> highp_i16vec2; typedef vec<3, i16, highp> highp_i16vec3; typedef vec<4, i16, highp> highp_i16vec4; typedef vec<1, i16, defaultp> i16vec1; typedef vec<2, i16, defaultp> i16vec2; typedef vec<3, i16, defaultp> i16vec3; typedef vec<4, i16, defaultp> i16vec4; typedef vec<1, i32, lowp> lowp_i32vec1; typedef vec<2, i32, lowp> lowp_i32vec2; typedef vec<3, i32, lowp> lowp_i32vec3; typedef vec<4, i32, lowp> lowp_i32vec4; typedef vec<1, i32, mediump> mediump_i32vec1; typedef vec<2, i32, mediump> mediump_i32vec2; typedef vec<3, i32, mediump> mediump_i32vec3; typedef vec<4, i32, mediump> mediump_i32vec4; typedef vec<1, i32, highp> highp_i32vec1; typedef vec<2, i32, highp> highp_i32vec2; typedef vec<3, i32, highp> highp_i32vec3; typedef vec<4, i32, highp> highp_i32vec4; typedef vec<1, i32, defaultp> i32vec1; typedef vec<2, i32, defaultp> i32vec2; typedef vec<3, i32, defaultp> i32vec3; typedef vec<4, i32, defaultp> i32vec4; typedef vec<1, i64, lowp> lowp_i64vec1; typedef vec<2, i64, lowp> lowp_i64vec2; typedef vec<3, i64, lowp> lowp_i64vec3; typedef vec<4, i64, lowp> lowp_i64vec4; typedef vec<1, i64, mediump> mediump_i64vec1; typedef vec<2, i64, mediump> mediump_i64vec2; typedef vec<3, i64, mediump> mediump_i64vec3; typedef vec<4, i64, mediump> mediump_i64vec4; typedef vec<1, i64, highp> highp_i64vec1; typedef vec<2, i64, highp> highp_i64vec2; typedef vec<3, i64, highp> highp_i64vec3; typedef vec<4, i64, highp> highp_i64vec4; typedef vec<1, i64, defaultp> i64vec1; typedef vec<2, i64, defaultp> i64vec2; typedef vec<3, i64, defaultp> i64vec3; typedef vec<4, i64, defaultp> i64vec4; // Vector uint typedef vec<1, u32, lowp> lowp_uvec1; typedef vec<2, u32, lowp> lowp_uvec2; typedef vec<3, u32, lowp> lowp_uvec3; typedef vec<4, u32, lowp> lowp_uvec4; typedef vec<1, u32, mediump> mediump_uvec1; typedef vec<2, u32, mediump> mediump_uvec2; typedef vec<3, u32, mediump> mediump_uvec3; typedef vec<4, u32, mediump> mediump_uvec4; typedef vec<1, u32, highp> highp_uvec1; typedef vec<2, u32, highp> highp_uvec2; typedef vec<3, u32, highp> highp_uvec3; typedef vec<4, u32, highp> highp_uvec4; typedef vec<1, u32, defaultp> uvec1; typedef vec<2, u32, defaultp> uvec2; typedef vec<3, u32, defaultp> uvec3; typedef vec<4, u32, defaultp> uvec4; typedef vec<1, u8, lowp> lowp_u8vec1; typedef vec<2, u8, lowp> lowp_u8vec2; typedef vec<3, u8, lowp> lowp_u8vec3; typedef vec<4, u8, lowp> lowp_u8vec4; typedef vec<1, u8, mediump> mediump_u8vec1; typedef vec<2, u8, mediump> mediump_u8vec2; typedef vec<3, u8, mediump> mediump_u8vec3; typedef vec<4, u8, mediump> mediump_u8vec4; typedef vec<1, u8, highp> highp_u8vec1; typedef vec<2, u8, highp> highp_u8vec2; typedef vec<3, u8, highp> highp_u8vec3; typedef vec<4, u8, highp> highp_u8vec4; typedef vec<1, u8, defaultp> u8vec1; typedef vec<2, u8, defaultp> u8vec2; typedef vec<3, u8, defaultp> u8vec3; typedef vec<4, u8, defaultp> u8vec4; typedef vec<1, u16, lowp> lowp_u16vec1; typedef vec<2, u16, lowp> lowp_u16vec2; typedef vec<3, u16, lowp> lowp_u16vec3; typedef vec<4, u16, lowp> lowp_u16vec4; typedef vec<1, u16, mediump> mediump_u16vec1; typedef vec<2, u16, mediump> mediump_u16vec2; typedef vec<3, u16, mediump> mediump_u16vec3; typedef vec<4, u16, mediump> mediump_u16vec4; typedef vec<1, u16, highp> highp_u16vec1; typedef vec<2, u16, highp> highp_u16vec2; typedef vec<3, u16, highp> highp_u16vec3; typedef vec<4, u16, highp> highp_u16vec4; typedef vec<1, u16, defaultp> u16vec1; typedef vec<2, u16, defaultp> u16vec2; typedef vec<3, u16, defaultp> u16vec3; typedef vec<4, u16, defaultp> u16vec4; typedef vec<1, u32, lowp> lowp_u32vec1; typedef vec<2, u32, lowp> lowp_u32vec2; typedef vec<3, u32, lowp> lowp_u32vec3; typedef vec<4, u32, lowp> lowp_u32vec4; typedef vec<1, u32, mediump> mediump_u32vec1; typedef vec<2, u32, mediump> mediump_u32vec2; typedef vec<3, u32, mediump> mediump_u32vec3; typedef vec<4, u32, mediump> mediump_u32vec4; typedef vec<1, u32, highp> highp_u32vec1; typedef vec<2, u32, highp> highp_u32vec2; typedef vec<3, u32, highp> highp_u32vec3; typedef vec<4, u32, highp> highp_u32vec4; typedef vec<1, u32, defaultp> u32vec1; typedef vec<2, u32, defaultp> u32vec2; typedef vec<3, u32, defaultp> u32vec3; typedef vec<4, u32, defaultp> u32vec4; typedef vec<1, u64, lowp> lowp_u64vec1; typedef vec<2, u64, lowp> lowp_u64vec2; typedef vec<3, u64, lowp> lowp_u64vec3; typedef vec<4, u64, lowp> lowp_u64vec4; typedef vec<1, u64, mediump> mediump_u64vec1; typedef vec<2, u64, mediump> mediump_u64vec2; typedef vec<3, u64, mediump> mediump_u64vec3; typedef vec<4, u64, mediump> mediump_u64vec4; typedef vec<1, u64, highp> highp_u64vec1; typedef vec<2, u64, highp> highp_u64vec2; typedef vec<3, u64, highp> highp_u64vec3; typedef vec<4, u64, highp> highp_u64vec4; typedef vec<1, u64, defaultp> u64vec1; typedef vec<2, u64, defaultp> u64vec2; typedef vec<3, u64, defaultp> u64vec3; typedef vec<4, u64, defaultp> u64vec4; // Vector float typedef vec<1, float, lowp> lowp_vec1; typedef vec<2, float, lowp> lowp_vec2; typedef vec<3, float, lowp> lowp_vec3; typedef vec<4, float, lowp> lowp_vec4; typedef vec<1, float, mediump> mediump_vec1; typedef vec<2, float, mediump> mediump_vec2; typedef vec<3, float, mediump> mediump_vec3; typedef vec<4, float, mediump> mediump_vec4; typedef vec<1, float, highp> highp_vec1; typedef vec<2, float, highp> highp_vec2; typedef vec<3, float, highp> highp_vec3; typedef vec<4, float, highp> highp_vec4; typedef vec<1, float, defaultp> vec1; typedef vec<2, float, defaultp> vec2; typedef vec<3, float, defaultp> vec3; typedef vec<4, float, defaultp> vec4; typedef vec<1, float, lowp> lowp_fvec1; typedef vec<2, float, lowp> lowp_fvec2; typedef vec<3, float, lowp> lowp_fvec3; typedef vec<4, float, lowp> lowp_fvec4; typedef vec<1, float, mediump> mediump_fvec1; typedef vec<2, float, mediump> mediump_fvec2; typedef vec<3, float, mediump> mediump_fvec3; typedef vec<4, float, mediump> mediump_fvec4; typedef vec<1, float, highp> highp_fvec1; typedef vec<2, float, highp> highp_fvec2; typedef vec<3, float, highp> highp_fvec3; typedef vec<4, float, highp> highp_fvec4; typedef vec<1, f32, defaultp> fvec1; typedef vec<2, f32, defaultp> fvec2; typedef vec<3, f32, defaultp> fvec3; typedef vec<4, f32, defaultp> fvec4; typedef vec<1, f32, lowp> lowp_f32vec1; typedef vec<2, f32, lowp> lowp_f32vec2; typedef vec<3, f32, lowp> lowp_f32vec3; typedef vec<4, f32, lowp> lowp_f32vec4; typedef vec<1, f32, mediump> mediump_f32vec1; typedef vec<2, f32, mediump> mediump_f32vec2; typedef vec<3, f32, mediump> mediump_f32vec3; typedef vec<4, f32, mediump> mediump_f32vec4; typedef vec<1, f32, highp> highp_f32vec1; typedef vec<2, f32, highp> highp_f32vec2; typedef vec<3, f32, highp> highp_f32vec3; typedef vec<4, f32, highp> highp_f32vec4; typedef vec<1, f32, defaultp> f32vec1; typedef vec<2, f32, defaultp> f32vec2; typedef vec<3, f32, defaultp> f32vec3; typedef vec<4, f32, defaultp> f32vec4; typedef vec<1, f64, lowp> lowp_dvec1; typedef vec<2, f64, lowp> lowp_dvec2; typedef vec<3, f64, lowp> lowp_dvec3; typedef vec<4, f64, lowp> lowp_dvec4; typedef vec<1, f64, mediump> mediump_dvec1; typedef vec<2, f64, mediump> mediump_dvec2; typedef vec<3, f64, mediump> mediump_dvec3; typedef vec<4, f64, mediump> mediump_dvec4; typedef vec<1, f64, highp> highp_dvec1; typedef vec<2, f64, highp> highp_dvec2; typedef vec<3, f64, highp> highp_dvec3; typedef vec<4, f64, highp> highp_dvec4; typedef vec<1, f64, defaultp> dvec1; typedef vec<2, f64, defaultp> dvec2; typedef vec<3, f64, defaultp> dvec3; typedef vec<4, f64, defaultp> dvec4; typedef vec<1, f64, lowp> lowp_f64vec1; typedef vec<2, f64, lowp> lowp_f64vec2; typedef vec<3, f64, lowp> lowp_f64vec3; typedef vec<4, f64, lowp> lowp_f64vec4; typedef vec<1, f64, mediump> mediump_f64vec1; typedef vec<2, f64, mediump> mediump_f64vec2; typedef vec<3, f64, mediump> mediump_f64vec3; typedef vec<4, f64, mediump> mediump_f64vec4; typedef vec<1, f64, highp> highp_f64vec1; typedef vec<2, f64, highp> highp_f64vec2; typedef vec<3, f64, highp> highp_f64vec3; typedef vec<4, f64, highp> highp_f64vec4; typedef vec<1, f64, defaultp> f64vec1; typedef vec<2, f64, defaultp> f64vec2; typedef vec<3, f64, defaultp> f64vec3; typedef vec<4, f64, defaultp> f64vec4; // Matrix NxN typedef mat<2, 2, f32, lowp> lowp_mat2; typedef mat<3, 3, f32, lowp> lowp_mat3; typedef mat<4, 4, f32, lowp> lowp_mat4; typedef mat<2, 2, f32, mediump> mediump_mat2; typedef mat<3, 3, f32, mediump> mediump_mat3; typedef mat<4, 4, f32, mediump> mediump_mat4; typedef mat<2, 2, f32, highp> highp_mat2; typedef mat<3, 3, f32, highp> highp_mat3; typedef mat<4, 4, f32, highp> highp_mat4; typedef mat<2, 2, f32, defaultp> mat2; typedef mat<3, 3, f32, defaultp> mat3; typedef mat<4, 4, f32, defaultp> mat4; typedef mat<2, 2, f32, lowp> lowp_fmat2; typedef mat<3, 3, f32, lowp> lowp_fmat3; typedef mat<4, 4, f32, lowp> lowp_fmat4; typedef mat<2, 2, f32, mediump> mediump_fmat2; typedef mat<3, 3, f32, mediump> mediump_fmat3; typedef mat<4, 4, f32, mediump> mediump_fmat4; typedef mat<2, 2, f32, highp> highp_fmat2; typedef mat<3, 3, f32, highp> highp_fmat3; typedef mat<4, 4, f32, highp> highp_fmat4; typedef mat<2, 2, f32, defaultp> fmat2; typedef mat<3, 3, f32, defaultp> fmat3; typedef mat<4, 4, f32, defaultp> fmat4; typedef mat<2, 2, f32, lowp> lowp_f32mat2; typedef mat<3, 3, f32, lowp> lowp_f32mat3; typedef mat<4, 4, f32, lowp> lowp_f32mat4; typedef mat<2, 2, f32, mediump> mediump_f32mat2; typedef mat<3, 3, f32, mediump> mediump_f32mat3; typedef mat<4, 4, f32, mediump> mediump_f32mat4; typedef mat<2, 2, f32, highp> highp_f32mat2; typedef mat<3, 3, f32, highp> highp_f32mat3; typedef mat<4, 4, f32, highp> highp_f32mat4; typedef mat<2, 2, f32, defaultp> f32mat2; typedef mat<3, 3, f32, defaultp> f32mat3; typedef mat<4, 4, f32, defaultp> f32mat4; typedef mat<2, 2, f64, lowp> lowp_dmat2; typedef mat<3, 3, f64, lowp> lowp_dmat3; typedef mat<4, 4, f64, lowp> lowp_dmat4; typedef mat<2, 2, f64, mediump> mediump_dmat2; typedef mat<3, 3, f64, mediump> mediump_dmat3; typedef mat<4, 4, f64, mediump> mediump_dmat4; typedef mat<2, 2, f64, highp> highp_dmat2; typedef mat<3, 3, f64, highp> highp_dmat3; typedef mat<4, 4, f64, highp> highp_dmat4; typedef mat<2, 2, f64, defaultp> dmat2; typedef mat<3, 3, f64, defaultp> dmat3; typedef mat<4, 4, f64, defaultp> dmat4; typedef mat<2, 2, f64, lowp> lowp_f64mat2; typedef mat<3, 3, f64, lowp> lowp_f64mat3; typedef mat<4, 4, f64, lowp> lowp_f64mat4; typedef mat<2, 2, f64, mediump> mediump_f64mat2; typedef mat<3, 3, f64, mediump> mediump_f64mat3; typedef mat<4, 4, f64, mediump> mediump_f64mat4; typedef mat<2, 2, f64, highp> highp_f64mat2; typedef mat<3, 3, f64, highp> highp_f64mat3; typedef mat<4, 4, f64, highp> highp_f64mat4; typedef mat<2, 2, f64, defaultp> f64mat2; typedef mat<3, 3, f64, defaultp> f64mat3; typedef mat<4, 4, f64, defaultp> f64mat4; // Matrix MxN typedef mat<2, 2, f32, lowp> lowp_mat2x2; typedef mat<2, 3, f32, lowp> lowp_mat2x3; typedef mat<2, 4, f32, lowp> lowp_mat2x4; typedef mat<3, 2, f32, lowp> lowp_mat3x2; typedef mat<3, 3, f32, lowp> lowp_mat3x3; typedef mat<3, 4, f32, lowp> lowp_mat3x4; typedef mat<4, 2, f32, lowp> lowp_mat4x2; typedef mat<4, 3, f32, lowp> lowp_mat4x3; typedef mat<4, 4, f32, lowp> lowp_mat4x4; typedef mat<2, 2, f32, mediump> mediump_mat2x2; typedef mat<2, 3, f32, mediump> mediump_mat2x3; typedef mat<2, 4, f32, mediump> mediump_mat2x4; typedef mat<3, 2, f32, mediump> mediump_mat3x2; typedef mat<3, 3, f32, mediump> mediump_mat3x3; typedef mat<3, 4, f32, mediump> mediump_mat3x4; typedef mat<4, 2, f32, mediump> mediump_mat4x2; typedef mat<4, 3, f32, mediump> mediump_mat4x3; typedef mat<4, 4, f32, mediump> mediump_mat4x4; typedef mat<2, 2, f32, highp> highp_mat2x2; typedef mat<2, 3, f32, highp> highp_mat2x3; typedef mat<2, 4, f32, highp> highp_mat2x4; typedef mat<3, 2, f32, highp> highp_mat3x2; typedef mat<3, 3, f32, highp> highp_mat3x3; typedef mat<3, 4, f32, highp> highp_mat3x4; typedef mat<4, 2, f32, highp> highp_mat4x2; typedef mat<4, 3, f32, highp> highp_mat4x3; typedef mat<4, 4, f32, highp> highp_mat4x4; typedef mat<2, 2, f32, defaultp> mat2x2; typedef mat<3, 2, f32, defaultp> mat3x2; typedef mat<4, 2, f32, defaultp> mat4x2; typedef mat<2, 3, f32, defaultp> mat2x3; typedef mat<3, 3, f32, defaultp> mat3x3; typedef mat<4, 3, f32, defaultp> mat4x3; typedef mat<2, 4, f32, defaultp> mat2x4; typedef mat<3, 4, f32, defaultp> mat3x4; typedef mat<4, 4, f32, defaultp> mat4x4; typedef mat<2, 2, f32, lowp> lowp_fmat2x2; typedef mat<2, 3, f32, lowp> lowp_fmat2x3; typedef mat<2, 4, f32, lowp> lowp_fmat2x4; typedef mat<3, 2, f32, lowp> lowp_fmat3x2; typedef mat<3, 3, f32, lowp> lowp_fmat3x3; typedef mat<3, 4, f32, lowp> lowp_fmat3x4; typedef mat<4, 2, f32, lowp> lowp_fmat4x2; typedef mat<4, 3, f32, lowp> lowp_fmat4x3; typedef mat<4, 4, f32, lowp> lowp_fmat4x4; typedef mat<2, 2, f32, mediump> mediump_fmat2x2; typedef mat<2, 3, f32, mediump> mediump_fmat2x3; typedef mat<2, 4, f32, mediump> mediump_fmat2x4; typedef mat<3, 2, f32, mediump> mediump_fmat3x2; typedef mat<3, 3, f32, mediump> mediump_fmat3x3; typedef mat<3, 4, f32, mediump> mediump_fmat3x4; typedef mat<4, 2, f32, mediump> mediump_fmat4x2; typedef mat<4, 3, f32, mediump> mediump_fmat4x3; typedef mat<4, 4, f32, mediump> mediump_fmat4x4; typedef mat<2, 2, f32, highp> highp_fmat2x2; typedef mat<2, 3, f32, highp> highp_fmat2x3; typedef mat<2, 4, f32, highp> highp_fmat2x4; typedef mat<3, 2, f32, highp> highp_fmat3x2; typedef mat<3, 3, f32, highp> highp_fmat3x3; typedef mat<3, 4, f32, highp> highp_fmat3x4; typedef mat<4, 2, f32, highp> highp_fmat4x2; typedef mat<4, 3, f32, highp> highp_fmat4x3; typedef mat<4, 4, f32, highp> highp_fmat4x4; typedef mat<2, 2, f32, defaultp> fmat2x2; typedef mat<3, 2, f32, defaultp> fmat3x2; typedef mat<4, 2, f32, defaultp> fmat4x2; typedef mat<2, 3, f32, defaultp> fmat2x3; typedef mat<3, 3, f32, defaultp> fmat3x3; typedef mat<4, 3, f32, defaultp> fmat4x3; typedef mat<2, 4, f32, defaultp> fmat2x4; typedef mat<3, 4, f32, defaultp> fmat3x4; typedef mat<4, 4, f32, defaultp> fmat4x4; typedef mat<2, 2, f32, lowp> lowp_f32mat2x2; typedef mat<2, 3, f32, lowp> lowp_f32mat2x3; typedef mat<2, 4, f32, lowp> lowp_f32mat2x4; typedef mat<3, 2, f32, lowp> lowp_f32mat3x2; typedef mat<3, 3, f32, lowp> lowp_f32mat3x3; typedef mat<3, 4, f32, lowp> lowp_f32mat3x4; typedef mat<4, 2, f32, lowp> lowp_f32mat4x2; typedef mat<4, 3, f32, lowp> lowp_f32mat4x3; typedef mat<4, 4, f32, lowp> lowp_f32mat4x4; typedef mat<2, 2, f32, mediump> mediump_f32mat2x2; typedef mat<2, 3, f32, mediump> mediump_f32mat2x3; typedef mat<2, 4, f32, mediump> mediump_f32mat2x4; typedef mat<3, 2, f32, mediump> mediump_f32mat3x2; typedef mat<3, 3, f32, mediump> mediump_f32mat3x3; typedef mat<3, 4, f32, mediump> mediump_f32mat3x4; typedef mat<4, 2, f32, mediump> mediump_f32mat4x2; typedef mat<4, 3, f32, mediump> mediump_f32mat4x3; typedef mat<4, 4, f32, mediump> mediump_f32mat4x4; typedef mat<2, 2, f32, highp> highp_f32mat2x2; typedef mat<2, 3, f32, highp> highp_f32mat2x3; typedef mat<2, 4, f32, highp> highp_f32mat2x4; typedef mat<3, 2, f32, highp> highp_f32mat3x2; typedef mat<3, 3, f32, highp> highp_f32mat3x3; typedef mat<3, 4, f32, highp> highp_f32mat3x4; typedef mat<4, 2, f32, highp> highp_f32mat4x2; typedef mat<4, 3, f32, highp> highp_f32mat4x3; typedef mat<4, 4, f32, highp> highp_f32mat4x4; typedef mat<2, 2, f32, defaultp> f32mat2x2; typedef mat<3, 2, f32, defaultp> f32mat3x2; typedef mat<4, 2, f32, defaultp> f32mat4x2; typedef mat<2, 3, f32, defaultp> f32mat2x3; typedef mat<3, 3, f32, defaultp> f32mat3x3; typedef mat<4, 3, f32, defaultp> f32mat4x3; typedef mat<2, 4, f32, defaultp> f32mat2x4; typedef mat<3, 4, f32, defaultp> f32mat3x4; typedef mat<4, 4, f32, defaultp> f32mat4x4; typedef mat<2, 2, double, lowp> lowp_dmat2x2; typedef mat<2, 3, double, lowp> lowp_dmat2x3; typedef mat<2, 4, double, lowp> lowp_dmat2x4; typedef mat<3, 2, double, lowp> lowp_dmat3x2; typedef mat<3, 3, double, lowp> lowp_dmat3x3; typedef mat<3, 4, double, lowp> lowp_dmat3x4; typedef mat<4, 2, double, lowp> lowp_dmat4x2; typedef mat<4, 3, double, lowp> lowp_dmat4x3; typedef mat<4, 4, double, lowp> lowp_dmat4x4; typedef mat<2, 2, double, mediump> mediump_dmat2x2; typedef mat<2, 3, double, mediump> mediump_dmat2x3; typedef mat<2, 4, double, mediump> mediump_dmat2x4; typedef mat<3, 2, double, mediump> mediump_dmat3x2; typedef mat<3, 3, double, mediump> mediump_dmat3x3; typedef mat<3, 4, double, mediump> mediump_dmat3x4; typedef mat<4, 2, double, mediump> mediump_dmat4x2; typedef mat<4, 3, double, mediump> mediump_dmat4x3; typedef mat<4, 4, double, mediump> mediump_dmat4x4; typedef mat<2, 2, double, highp> highp_dmat2x2; typedef mat<2, 3, double, highp> highp_dmat2x3; typedef mat<2, 4, double, highp> highp_dmat2x4; typedef mat<3, 2, double, highp> highp_dmat3x2; typedef mat<3, 3, double, highp> highp_dmat3x3; typedef mat<3, 4, double, highp> highp_dmat3x4; typedef mat<4, 2, double, highp> highp_dmat4x2; typedef mat<4, 3, double, highp> highp_dmat4x3; typedef mat<4, 4, double, highp> highp_dmat4x4; typedef mat<2, 2, double, defaultp> dmat2x2; typedef mat<3, 2, double, defaultp> dmat3x2; typedef mat<4, 2, double, defaultp> dmat4x2; typedef mat<2, 3, double, defaultp> dmat2x3; typedef mat<3, 3, double, defaultp> dmat3x3; typedef mat<4, 3, double, defaultp> dmat4x3; typedef mat<2, 4, double, defaultp> dmat2x4; typedef mat<3, 4, double, defaultp> dmat3x4; typedef mat<4, 4, double, defaultp> dmat4x4; typedef mat<2, 2, f64, lowp> lowp_f64mat2x2; typedef mat<2, 3, f64, lowp> lowp_f64mat2x3; typedef mat<2, 4, f64, lowp> lowp_f64mat2x4; typedef mat<3, 2, f64, lowp> lowp_f64mat3x2; typedef mat<3, 3, f64, lowp> lowp_f64mat3x3; typedef mat<3, 4, f64, lowp> lowp_f64mat3x4; typedef mat<4, 2, f64, lowp> lowp_f64mat4x2; typedef mat<4, 3, f64, lowp> lowp_f64mat4x3; typedef mat<4, 4, f64, lowp> lowp_f64mat4x4; typedef mat<2, 2, f64, mediump> mediump_f64mat2x2; typedef mat<2, 3, f64, mediump> mediump_f64mat2x3; typedef mat<2, 4, f64, mediump> mediump_f64mat2x4; typedef mat<3, 2, f64, mediump> mediump_f64mat3x2; typedef mat<3, 3, f64, mediump> mediump_f64mat3x3; typedef mat<3, 4, f64, mediump> mediump_f64mat3x4; typedef mat<4, 2, f64, mediump> mediump_f64mat4x2; typedef mat<4, 3, f64, mediump> mediump_f64mat4x3; typedef mat<4, 4, f64, mediump> mediump_f64mat4x4; typedef mat<2, 2, f64, highp> highp_f64mat2x2; typedef mat<2, 3, f64, highp> highp_f64mat2x3; typedef mat<2, 4, f64, highp> highp_f64mat2x4; typedef mat<3, 2, f64, highp> highp_f64mat3x2; typedef mat<3, 3, f64, highp> highp_f64mat3x3; typedef mat<3, 4, f64, highp> highp_f64mat3x4; typedef mat<4, 2, f64, highp> highp_f64mat4x2; typedef mat<4, 3, f64, highp> highp_f64mat4x3; typedef mat<4, 4, f64, highp> highp_f64mat4x4; typedef mat<2, 2, f64, defaultp> f64mat2x2; typedef mat<3, 2, f64, defaultp> f64mat3x2; typedef mat<4, 2, f64, defaultp> f64mat4x2; typedef mat<2, 3, f64, defaultp> f64mat2x3; typedef mat<3, 3, f64, defaultp> f64mat3x3; typedef mat<4, 3, f64, defaultp> f64mat4x3; typedef mat<2, 4, f64, defaultp> f64mat2x4; typedef mat<3, 4, f64, defaultp> f64mat3x4; typedef mat<4, 4, f64, defaultp> f64mat4x4; // Quaternion typedef qua lowp_quat; typedef qua mediump_quat; typedef qua highp_quat; typedef qua quat; typedef qua lowp_fquat; typedef qua mediump_fquat; typedef qua highp_fquat; typedef qua fquat; typedef qua lowp_f32quat; typedef qua mediump_f32quat; typedef qua highp_f32quat; typedef qua f32quat; typedef qua lowp_dquat; typedef qua mediump_dquat; typedef qua highp_dquat; typedef qua dquat; typedef qua lowp_f64quat; typedef qua mediump_f64quat; typedef qua highp_f64quat; typedef qua f64quat; }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/geometric.hpp000066400000000000000000000125331360521144700230100ustar00rootroot00000000000000/// @ref core /// @file glm/geometric.hpp /// /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions /// /// @defgroup core_func_geometric Geometric functions /// @ingroup core /// /// These operate on vectors as vectors, not component-wise. /// /// Include to use these core features. #pragma once #include "detail/type_vec3.hpp" namespace glm { /// @addtogroup core_func_geometric /// @{ /// Returns the length of x, i.e., sqrt(x * x). /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T Floating-point scalar types. /// /// @see GLSL length man page /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions template GLM_FUNC_DECL T length(vec const& x); /// Returns the distance betwwen p0 and p1, i.e., length(p0 - p1). /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T Floating-point scalar types. /// /// @see GLSL distance man page /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions template GLM_FUNC_DECL T distance(vec const& p0, vec const& p1); /// Returns the dot product of x and y, i.e., result = x * y. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T Floating-point scalar types. /// /// @see GLSL dot man page /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions template GLM_FUNC_DECL T dot(vec const& x, vec const& y); /// Returns the cross product of x and y. /// /// @tparam T Floating-point scalar types. /// /// @see GLSL cross man page /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions template GLM_FUNC_DECL vec<3, T, Q> cross(vec<3, T, Q> const& x, vec<3, T, Q> const& y); /// Returns a vector in the same direction as x but with length of 1. /// According to issue 10 GLSL 1.10 specification, if length(x) == 0 then result is undefined and generate an error. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T Floating-point scalar types. /// /// @see GLSL normalize man page /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions template GLM_FUNC_DECL vec normalize(vec const& x); /// If dot(Nref, I) < 0.0, return N, otherwise, return -N. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T Floating-point scalar types. /// /// @see GLSL faceforward man page /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions template GLM_FUNC_DECL vec faceforward( vec const& N, vec const& I, vec const& Nref); /// For the incident vector I and surface orientation N, /// returns the reflection direction : result = I - 2.0 * dot(N, I) * N. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T Floating-point scalar types. /// /// @see GLSL reflect man page /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions template GLM_FUNC_DECL vec reflect( vec const& I, vec const& N); /// For the incident vector I and surface normal N, /// and the ratio of indices of refraction eta, /// return the refraction vector. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T Floating-point scalar types. /// /// @see GLSL refract man page /// @see GLSL 4.20.8 specification, section 8.5 Geometric Functions template GLM_FUNC_DECL vec refract( vec const& I, vec const& N, T eta); /// @} }//namespace glm #include "detail/func_geometric.inl" connectome-workbench-1.4.2/src/GLMath/glm/glm.hpp000066400000000000000000000110331360521144700216030ustar00rootroot00000000000000/// @ref core /// @file glm/glm.hpp /// /// @defgroup core Core features /// /// @brief Features that implement in C++ the GLSL specification as closely as possible. /// /// The GLM core consists of C++ types that mirror GLSL types and /// C++ functions that mirror the GLSL functions. /// /// The best documentation for GLM Core is the current GLSL specification, /// version 4.2 /// (pdf file). /// /// GLM core functionalities require to be included to be used. /// /// /// @defgroup core_vector Vector types /// /// Vector types of two to four components with an exhaustive set of operators. /// /// @ingroup core /// /// /// @defgroup core_vector_precision Vector types with precision qualifiers /// /// @brief Vector types with precision qualifiers which may result in various precision in term of ULPs /// /// GLSL allows defining qualifiers for particular variables. /// With OpenGL's GLSL, these qualifiers have no effect; they are there for compatibility, /// with OpenGL ES's GLSL, these qualifiers do have an effect. /// /// C++ has no language equivalent to qualifier qualifiers. So GLM provides the next-best thing: /// a number of typedefs that use a particular qualifier. /// /// None of these types make any guarantees about the actual qualifier used. /// /// @ingroup core /// /// /// @defgroup core_matrix Matrix types /// /// Matrix types of with C columns and R rows where C and R are values between 2 to 4 included. /// These types have exhaustive sets of operators. /// /// @ingroup core /// /// /// @defgroup core_matrix_precision Matrix types with precision qualifiers /// /// @brief Matrix types with precision qualifiers which may result in various precision in term of ULPs /// /// GLSL allows defining qualifiers for particular variables. /// With OpenGL's GLSL, these qualifiers have no effect; they are there for compatibility, /// with OpenGL ES's GLSL, these qualifiers do have an effect. /// /// C++ has no language equivalent to qualifier qualifiers. So GLM provides the next-best thing: /// a number of typedefs that use a particular qualifier. /// /// None of these types make any guarantees about the actual qualifier used. /// /// @ingroup core /// /// /// @defgroup ext Stable extensions /// /// @brief Additional features not specified by GLSL specification. /// /// EXT extensions are fully tested and documented. /// /// Even if it's highly unrecommended, it's possible to include all the extensions at once by /// including . Otherwise, each extension needs to be included a specific file. /// /// /// @defgroup gtc Recommended extensions /// /// @brief Additional features not specified by GLSL specification. /// /// GTC extensions aim to be stable with tests and documentation. /// /// Even if it's highly unrecommended, it's possible to include all the extensions at once by /// including . Otherwise, each extension needs to be included a specific file. /// /// /// @defgroup gtx Experimental extensions /// /// @brief Experimental features not specified by GLSL specification. /// /// Experimental extensions are useful functions and types, but the development of /// their API and functionality is not necessarily stable. They can change /// substantially between versions. Backwards compatibility is not much of an issue /// for them. /// /// Even if it's highly unrecommended, it's possible to include all the extensions /// at once by including . Otherwise, each extension needs to be /// included a specific file. /// /// @mainpage OpenGL Mathematics (GLM) /// - Website: glm.g-truc.net /// - GLM API documentation /// - GLM Manual #include "detail/_fixes.hpp" #include "detail/setup.hpp" #pragma once #include #include #include #include #include #include "fwd.hpp" #include "vec2.hpp" #include "vec3.hpp" #include "vec4.hpp" #include "mat2x2.hpp" #include "mat2x3.hpp" #include "mat2x4.hpp" #include "mat3x2.hpp" #include "mat3x3.hpp" #include "mat3x4.hpp" #include "mat4x2.hpp" #include "mat4x3.hpp" #include "mat4x4.hpp" #include "trigonometric.hpp" #include "exponential.hpp" #include "common.hpp" #include "packing.hpp" #include "geometric.hpp" #include "matrix.hpp" #include "vector_relational.hpp" #include "integer.hpp" connectome-workbench-1.4.2/src/GLMath/glm/gtc/000077500000000000000000000000001360521144700210725ustar00rootroot00000000000000connectome-workbench-1.4.2/src/GLMath/glm/gtc/bitfield.hpp000066400000000000000000000236401360521144700233720ustar00rootroot00000000000000/// @ref gtc_bitfield /// @file glm/gtc/bitfield.hpp /// /// @see core (dependence) /// @see gtc_bitfield (dependence) /// /// @defgroup gtc_bitfield GLM_GTC_bitfield /// @ingroup gtc /// /// Include to use the features of this extension. /// /// Allow to perform bit operations on integer values #include "../detail/setup.hpp" #pragma once // Dependencies #include "../ext/scalar_int_sized.hpp" #include "../ext/scalar_uint_sized.hpp" #include "../detail/qualifier.hpp" #include "../detail/_vectorize.hpp" #include "type_precision.hpp" #include #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_GTC_bitfield extension included") #endif namespace glm { /// @addtogroup gtc_bitfield /// @{ /// Build a mask of 'count' bits /// /// @see gtc_bitfield template GLM_FUNC_DECL genIUType mask(genIUType Bits); /// Build a mask of 'count' bits /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Signed and unsigned integer scalar types /// @tparam Q Value from qualifier enum /// /// @see gtc_bitfield template GLM_FUNC_DECL vec mask(vec const& v); /// Rotate all bits to the right. All the bits dropped in the right side are inserted back on the left side. /// /// @see gtc_bitfield template GLM_FUNC_DECL genIUType bitfieldRotateRight(genIUType In, int Shift); /// Rotate all bits to the right. All the bits dropped in the right side are inserted back on the left side. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Signed and unsigned integer scalar types /// @tparam Q Value from qualifier enum /// /// @see gtc_bitfield template GLM_FUNC_DECL vec bitfieldRotateRight(vec const& In, int Shift); /// Rotate all bits to the left. All the bits dropped in the left side are inserted back on the right side. /// /// @see gtc_bitfield template GLM_FUNC_DECL genIUType bitfieldRotateLeft(genIUType In, int Shift); /// Rotate all bits to the left. All the bits dropped in the left side are inserted back on the right side. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Signed and unsigned integer scalar types /// @tparam Q Value from qualifier enum /// /// @see gtc_bitfield template GLM_FUNC_DECL vec bitfieldRotateLeft(vec const& In, int Shift); /// Set to 1 a range of bits. /// /// @see gtc_bitfield template GLM_FUNC_DECL genIUType bitfieldFillOne(genIUType Value, int FirstBit, int BitCount); /// Set to 1 a range of bits. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Signed and unsigned integer scalar types /// @tparam Q Value from qualifier enum /// /// @see gtc_bitfield template GLM_FUNC_DECL vec bitfieldFillOne(vec const& Value, int FirstBit, int BitCount); /// Set to 0 a range of bits. /// /// @see gtc_bitfield template GLM_FUNC_DECL genIUType bitfieldFillZero(genIUType Value, int FirstBit, int BitCount); /// Set to 0 a range of bits. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Signed and unsigned integer scalar types /// @tparam Q Value from qualifier enum /// /// @see gtc_bitfield template GLM_FUNC_DECL vec bitfieldFillZero(vec const& Value, int FirstBit, int BitCount); /// Interleaves the bits of x and y. /// The first bit is the first bit of x followed by the first bit of y. /// The other bits are interleaved following the previous sequence. /// /// @see gtc_bitfield GLM_FUNC_DECL int16 bitfieldInterleave(int8 x, int8 y); /// Interleaves the bits of x and y. /// The first bit is the first bit of x followed by the first bit of y. /// The other bits are interleaved following the previous sequence. /// /// @see gtc_bitfield GLM_FUNC_DECL uint16 bitfieldInterleave(uint8 x, uint8 y); /// Interleaves the bits of x and y. /// The first bit is the first bit of v.x followed by the first bit of v.y. /// The other bits are interleaved following the previous sequence. /// /// @see gtc_bitfield GLM_FUNC_DECL uint16 bitfieldInterleave(u8vec2 const& v); /// Deinterleaves the bits of x. /// /// @see gtc_bitfield GLM_FUNC_DECL glm::u8vec2 bitfieldDeinterleave(glm::uint16 x); /// Interleaves the bits of x and y. /// The first bit is the first bit of x followed by the first bit of y. /// The other bits are interleaved following the previous sequence. /// /// @see gtc_bitfield GLM_FUNC_DECL int32 bitfieldInterleave(int16 x, int16 y); /// Interleaves the bits of x and y. /// The first bit is the first bit of x followed by the first bit of y. /// The other bits are interleaved following the previous sequence. /// /// @see gtc_bitfield GLM_FUNC_DECL uint32 bitfieldInterleave(uint16 x, uint16 y); /// Interleaves the bits of x and y. /// The first bit is the first bit of v.x followed by the first bit of v.y. /// The other bits are interleaved following the previous sequence. /// /// @see gtc_bitfield GLM_FUNC_DECL uint32 bitfieldInterleave(u16vec2 const& v); /// Deinterleaves the bits of x. /// /// @see gtc_bitfield GLM_FUNC_DECL glm::u16vec2 bitfieldDeinterleave(glm::uint32 x); /// Interleaves the bits of x and y. /// The first bit is the first bit of x followed by the first bit of y. /// The other bits are interleaved following the previous sequence. /// /// @see gtc_bitfield GLM_FUNC_DECL int64 bitfieldInterleave(int32 x, int32 y); /// Interleaves the bits of x and y. /// The first bit is the first bit of x followed by the first bit of y. /// The other bits are interleaved following the previous sequence. /// /// @see gtc_bitfield GLM_FUNC_DECL uint64 bitfieldInterleave(uint32 x, uint32 y); /// Interleaves the bits of x and y. /// The first bit is the first bit of v.x followed by the first bit of v.y. /// The other bits are interleaved following the previous sequence. /// /// @see gtc_bitfield GLM_FUNC_DECL uint64 bitfieldInterleave(u32vec2 const& v); /// Deinterleaves the bits of x. /// /// @see gtc_bitfield GLM_FUNC_DECL glm::u32vec2 bitfieldDeinterleave(glm::uint64 x); /// Interleaves the bits of x, y and z. /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. /// The other bits are interleaved following the previous sequence. /// /// @see gtc_bitfield GLM_FUNC_DECL int32 bitfieldInterleave(int8 x, int8 y, int8 z); /// Interleaves the bits of x, y and z. /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. /// The other bits are interleaved following the previous sequence. /// /// @see gtc_bitfield GLM_FUNC_DECL uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z); /// Interleaves the bits of x, y and z. /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. /// The other bits are interleaved following the previous sequence. /// /// @see gtc_bitfield GLM_FUNC_DECL int64 bitfieldInterleave(int16 x, int16 y, int16 z); /// Interleaves the bits of x, y and z. /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. /// The other bits are interleaved following the previous sequence. /// /// @see gtc_bitfield GLM_FUNC_DECL uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z); /// Interleaves the bits of x, y and z. /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. /// The other bits are interleaved following the previous sequence. /// /// @see gtc_bitfield GLM_FUNC_DECL int64 bitfieldInterleave(int32 x, int32 y, int32 z); /// Interleaves the bits of x, y and z. /// The first bit is the first bit of x followed by the first bit of y and the first bit of z. /// The other bits are interleaved following the previous sequence. /// /// @see gtc_bitfield GLM_FUNC_DECL uint64 bitfieldInterleave(uint32 x, uint32 y, uint32 z); /// Interleaves the bits of x, y, z and w. /// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w. /// The other bits are interleaved following the previous sequence. /// /// @see gtc_bitfield GLM_FUNC_DECL int32 bitfieldInterleave(int8 x, int8 y, int8 z, int8 w); /// Interleaves the bits of x, y, z and w. /// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w. /// The other bits are interleaved following the previous sequence. /// /// @see gtc_bitfield GLM_FUNC_DECL uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z, uint8 w); /// Interleaves the bits of x, y, z and w. /// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w. /// The other bits are interleaved following the previous sequence. /// /// @see gtc_bitfield GLM_FUNC_DECL int64 bitfieldInterleave(int16 x, int16 y, int16 z, int16 w); /// Interleaves the bits of x, y, z and w. /// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w. /// The other bits are interleaved following the previous sequence. /// /// @see gtc_bitfield GLM_FUNC_DECL uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z, uint16 w); /// @} } //namespace glm #include "bitfield.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtc/bitfield.inl000066400000000000000000000504251360521144700233660ustar00rootroot00000000000000/// @ref gtc_bitfield #include "../simd/integer.h" namespace glm{ namespace detail { template GLM_FUNC_DECL RET bitfieldInterleave(PARAM x, PARAM y); template GLM_FUNC_DECL RET bitfieldInterleave(PARAM x, PARAM y, PARAM z); template GLM_FUNC_DECL RET bitfieldInterleave(PARAM x, PARAM y, PARAM z, PARAM w); template<> GLM_FUNC_QUALIFIER glm::uint16 bitfieldInterleave(glm::uint8 x, glm::uint8 y) { glm::uint16 REG1(x); glm::uint16 REG2(y); REG1 = ((REG1 << 4) | REG1) & static_cast(0x0F0F); REG2 = ((REG2 << 4) | REG2) & static_cast(0x0F0F); REG1 = ((REG1 << 2) | REG1) & static_cast(0x3333); REG2 = ((REG2 << 2) | REG2) & static_cast(0x3333); REG1 = ((REG1 << 1) | REG1) & static_cast(0x5555); REG2 = ((REG2 << 1) | REG2) & static_cast(0x5555); return REG1 | static_cast(REG2 << 1); } template<> GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(glm::uint16 x, glm::uint16 y) { glm::uint32 REG1(x); glm::uint32 REG2(y); REG1 = ((REG1 << 8) | REG1) & static_cast(0x00FF00FF); REG2 = ((REG2 << 8) | REG2) & static_cast(0x00FF00FF); REG1 = ((REG1 << 4) | REG1) & static_cast(0x0F0F0F0F); REG2 = ((REG2 << 4) | REG2) & static_cast(0x0F0F0F0F); REG1 = ((REG1 << 2) | REG1) & static_cast(0x33333333); REG2 = ((REG2 << 2) | REG2) & static_cast(0x33333333); REG1 = ((REG1 << 1) | REG1) & static_cast(0x55555555); REG2 = ((REG2 << 1) | REG2) & static_cast(0x55555555); return REG1 | (REG2 << 1); } template<> GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint32 x, glm::uint32 y) { glm::uint64 REG1(x); glm::uint64 REG2(y); REG1 = ((REG1 << 16) | REG1) & static_cast(0x0000FFFF0000FFFFull); REG2 = ((REG2 << 16) | REG2) & static_cast(0x0000FFFF0000FFFFull); REG1 = ((REG1 << 8) | REG1) & static_cast(0x00FF00FF00FF00FFull); REG2 = ((REG2 << 8) | REG2) & static_cast(0x00FF00FF00FF00FFull); REG1 = ((REG1 << 4) | REG1) & static_cast(0x0F0F0F0F0F0F0F0Full); REG2 = ((REG2 << 4) | REG2) & static_cast(0x0F0F0F0F0F0F0F0Full); REG1 = ((REG1 << 2) | REG1) & static_cast(0x3333333333333333ull); REG2 = ((REG2 << 2) | REG2) & static_cast(0x3333333333333333ull); REG1 = ((REG1 << 1) | REG1) & static_cast(0x5555555555555555ull); REG2 = ((REG2 << 1) | REG2) & static_cast(0x5555555555555555ull); return REG1 | (REG2 << 1); } template<> GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(glm::uint8 x, glm::uint8 y, glm::uint8 z) { glm::uint32 REG1(x); glm::uint32 REG2(y); glm::uint32 REG3(z); REG1 = ((REG1 << 16) | REG1) & static_cast(0xFF0000FFu); REG2 = ((REG2 << 16) | REG2) & static_cast(0xFF0000FFu); REG3 = ((REG3 << 16) | REG3) & static_cast(0xFF0000FFu); REG1 = ((REG1 << 8) | REG1) & static_cast(0x0F00F00Fu); REG2 = ((REG2 << 8) | REG2) & static_cast(0x0F00F00Fu); REG3 = ((REG3 << 8) | REG3) & static_cast(0x0F00F00Fu); REG1 = ((REG1 << 4) | REG1) & static_cast(0xC30C30C3u); REG2 = ((REG2 << 4) | REG2) & static_cast(0xC30C30C3u); REG3 = ((REG3 << 4) | REG3) & static_cast(0xC30C30C3u); REG1 = ((REG1 << 2) | REG1) & static_cast(0x49249249u); REG2 = ((REG2 << 2) | REG2) & static_cast(0x49249249u); REG3 = ((REG3 << 2) | REG3) & static_cast(0x49249249u); return REG1 | (REG2 << 1) | (REG3 << 2); } template<> GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint16 x, glm::uint16 y, glm::uint16 z) { glm::uint64 REG1(x); glm::uint64 REG2(y); glm::uint64 REG3(z); REG1 = ((REG1 << 32) | REG1) & static_cast(0xFFFF00000000FFFFull); REG2 = ((REG2 << 32) | REG2) & static_cast(0xFFFF00000000FFFFull); REG3 = ((REG3 << 32) | REG3) & static_cast(0xFFFF00000000FFFFull); REG1 = ((REG1 << 16) | REG1) & static_cast(0x00FF0000FF0000FFull); REG2 = ((REG2 << 16) | REG2) & static_cast(0x00FF0000FF0000FFull); REG3 = ((REG3 << 16) | REG3) & static_cast(0x00FF0000FF0000FFull); REG1 = ((REG1 << 8) | REG1) & static_cast(0xF00F00F00F00F00Full); REG2 = ((REG2 << 8) | REG2) & static_cast(0xF00F00F00F00F00Full); REG3 = ((REG3 << 8) | REG3) & static_cast(0xF00F00F00F00F00Full); REG1 = ((REG1 << 4) | REG1) & static_cast(0x30C30C30C30C30C3ull); REG2 = ((REG2 << 4) | REG2) & static_cast(0x30C30C30C30C30C3ull); REG3 = ((REG3 << 4) | REG3) & static_cast(0x30C30C30C30C30C3ull); REG1 = ((REG1 << 2) | REG1) & static_cast(0x9249249249249249ull); REG2 = ((REG2 << 2) | REG2) & static_cast(0x9249249249249249ull); REG3 = ((REG3 << 2) | REG3) & static_cast(0x9249249249249249ull); return REG1 | (REG2 << 1) | (REG3 << 2); } template<> GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint32 x, glm::uint32 y, glm::uint32 z) { glm::uint64 REG1(x); glm::uint64 REG2(y); glm::uint64 REG3(z); REG1 = ((REG1 << 32) | REG1) & static_cast(0xFFFF00000000FFFFull); REG2 = ((REG2 << 32) | REG2) & static_cast(0xFFFF00000000FFFFull); REG3 = ((REG3 << 32) | REG3) & static_cast(0xFFFF00000000FFFFull); REG1 = ((REG1 << 16) | REG1) & static_cast(0x00FF0000FF0000FFull); REG2 = ((REG2 << 16) | REG2) & static_cast(0x00FF0000FF0000FFull); REG3 = ((REG3 << 16) | REG3) & static_cast(0x00FF0000FF0000FFull); REG1 = ((REG1 << 8) | REG1) & static_cast(0xF00F00F00F00F00Full); REG2 = ((REG2 << 8) | REG2) & static_cast(0xF00F00F00F00F00Full); REG3 = ((REG3 << 8) | REG3) & static_cast(0xF00F00F00F00F00Full); REG1 = ((REG1 << 4) | REG1) & static_cast(0x30C30C30C30C30C3ull); REG2 = ((REG2 << 4) | REG2) & static_cast(0x30C30C30C30C30C3ull); REG3 = ((REG3 << 4) | REG3) & static_cast(0x30C30C30C30C30C3ull); REG1 = ((REG1 << 2) | REG1) & static_cast(0x9249249249249249ull); REG2 = ((REG2 << 2) | REG2) & static_cast(0x9249249249249249ull); REG3 = ((REG3 << 2) | REG3) & static_cast(0x9249249249249249ull); return REG1 | (REG2 << 1) | (REG3 << 2); } template<> GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(glm::uint8 x, glm::uint8 y, glm::uint8 z, glm::uint8 w) { glm::uint32 REG1(x); glm::uint32 REG2(y); glm::uint32 REG3(z); glm::uint32 REG4(w); REG1 = ((REG1 << 12) | REG1) & static_cast(0x000F000Fu); REG2 = ((REG2 << 12) | REG2) & static_cast(0x000F000Fu); REG3 = ((REG3 << 12) | REG3) & static_cast(0x000F000Fu); REG4 = ((REG4 << 12) | REG4) & static_cast(0x000F000Fu); REG1 = ((REG1 << 6) | REG1) & static_cast(0x03030303u); REG2 = ((REG2 << 6) | REG2) & static_cast(0x03030303u); REG3 = ((REG3 << 6) | REG3) & static_cast(0x03030303u); REG4 = ((REG4 << 6) | REG4) & static_cast(0x03030303u); REG1 = ((REG1 << 3) | REG1) & static_cast(0x11111111u); REG2 = ((REG2 << 3) | REG2) & static_cast(0x11111111u); REG3 = ((REG3 << 3) | REG3) & static_cast(0x11111111u); REG4 = ((REG4 << 3) | REG4) & static_cast(0x11111111u); return REG1 | (REG2 << 1) | (REG3 << 2) | (REG4 << 3); } template<> GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint16 x, glm::uint16 y, glm::uint16 z, glm::uint16 w) { glm::uint64 REG1(x); glm::uint64 REG2(y); glm::uint64 REG3(z); glm::uint64 REG4(w); REG1 = ((REG1 << 24) | REG1) & static_cast(0x000000FF000000FFull); REG2 = ((REG2 << 24) | REG2) & static_cast(0x000000FF000000FFull); REG3 = ((REG3 << 24) | REG3) & static_cast(0x000000FF000000FFull); REG4 = ((REG4 << 24) | REG4) & static_cast(0x000000FF000000FFull); REG1 = ((REG1 << 12) | REG1) & static_cast(0x000F000F000F000Full); REG2 = ((REG2 << 12) | REG2) & static_cast(0x000F000F000F000Full); REG3 = ((REG3 << 12) | REG3) & static_cast(0x000F000F000F000Full); REG4 = ((REG4 << 12) | REG4) & static_cast(0x000F000F000F000Full); REG1 = ((REG1 << 6) | REG1) & static_cast(0x0303030303030303ull); REG2 = ((REG2 << 6) | REG2) & static_cast(0x0303030303030303ull); REG3 = ((REG3 << 6) | REG3) & static_cast(0x0303030303030303ull); REG4 = ((REG4 << 6) | REG4) & static_cast(0x0303030303030303ull); REG1 = ((REG1 << 3) | REG1) & static_cast(0x1111111111111111ull); REG2 = ((REG2 << 3) | REG2) & static_cast(0x1111111111111111ull); REG3 = ((REG3 << 3) | REG3) & static_cast(0x1111111111111111ull); REG4 = ((REG4 << 3) | REG4) & static_cast(0x1111111111111111ull); return REG1 | (REG2 << 1) | (REG3 << 2) | (REG4 << 3); } }//namespace detail template GLM_FUNC_QUALIFIER genIUType mask(genIUType Bits) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'mask' accepts only integer values"); return Bits >= sizeof(genIUType) * 8 ? ~static_cast(0) : (static_cast(1) << Bits) - static_cast(1); } template GLM_FUNC_QUALIFIER vec mask(vec const& v) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'mask' accepts only integer values"); return detail::functor1::call(mask, v); } template GLM_FUNC_QUALIFIER genIType bitfieldRotateRight(genIType In, int Shift) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldRotateRight' accepts only integer values"); int const BitSize = static_cast(sizeof(genIType) * 8); return (In << static_cast(Shift)) | (In >> static_cast(BitSize - Shift)); } template GLM_FUNC_QUALIFIER vec bitfieldRotateRight(vec const& In, int Shift) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldRotateRight' accepts only integer values"); int const BitSize = static_cast(sizeof(T) * 8); return (In << static_cast(Shift)) | (In >> static_cast(BitSize - Shift)); } template GLM_FUNC_QUALIFIER genIType bitfieldRotateLeft(genIType In, int Shift) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldRotateLeft' accepts only integer values"); int const BitSize = static_cast(sizeof(genIType) * 8); return (In >> static_cast(Shift)) | (In << static_cast(BitSize - Shift)); } template GLM_FUNC_QUALIFIER vec bitfieldRotateLeft(vec const& In, int Shift) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "'bitfieldRotateLeft' accepts only integer values"); int const BitSize = static_cast(sizeof(T) * 8); return (In >> static_cast(Shift)) | (In << static_cast(BitSize - Shift)); } template GLM_FUNC_QUALIFIER genIUType bitfieldFillOne(genIUType Value, int FirstBit, int BitCount) { return Value | static_cast(mask(BitCount) << FirstBit); } template GLM_FUNC_QUALIFIER vec bitfieldFillOne(vec const& Value, int FirstBit, int BitCount) { return Value | static_cast(mask(BitCount) << FirstBit); } template GLM_FUNC_QUALIFIER genIUType bitfieldFillZero(genIUType Value, int FirstBit, int BitCount) { return Value & static_cast(~(mask(BitCount) << FirstBit)); } template GLM_FUNC_QUALIFIER vec bitfieldFillZero(vec const& Value, int FirstBit, int BitCount) { return Value & static_cast(~(mask(BitCount) << FirstBit)); } GLM_FUNC_QUALIFIER int16 bitfieldInterleave(int8 x, int8 y) { union sign8 { int8 i; uint8 u; } sign_x, sign_y; union sign16 { int16 i; uint16 u; } result; sign_x.i = x; sign_y.i = y; result.u = bitfieldInterleave(sign_x.u, sign_y.u); return result.i; } GLM_FUNC_QUALIFIER uint16 bitfieldInterleave(uint8 x, uint8 y) { return detail::bitfieldInterleave(x, y); } GLM_FUNC_QUALIFIER uint16 bitfieldInterleave(u8vec2 const& v) { return detail::bitfieldInterleave(v.x, v.y); } GLM_FUNC_QUALIFIER u8vec2 bitfieldDeinterleave(glm::uint16 x) { uint16 REG1(x); uint16 REG2(x >>= 1); REG1 = REG1 & static_cast(0x5555); REG2 = REG2 & static_cast(0x5555); REG1 = ((REG1 >> 1) | REG1) & static_cast(0x3333); REG2 = ((REG2 >> 1) | REG2) & static_cast(0x3333); REG1 = ((REG1 >> 2) | REG1) & static_cast(0x0F0F); REG2 = ((REG2 >> 2) | REG2) & static_cast(0x0F0F); REG1 = ((REG1 >> 4) | REG1) & static_cast(0x00FF); REG2 = ((REG2 >> 4) | REG2) & static_cast(0x00FF); REG1 = ((REG1 >> 8) | REG1) & static_cast(0xFFFF); REG2 = ((REG2 >> 8) | REG2) & static_cast(0xFFFF); return glm::u8vec2(REG1, REG2); } GLM_FUNC_QUALIFIER int32 bitfieldInterleave(int16 x, int16 y) { union sign16 { int16 i; uint16 u; } sign_x, sign_y; union sign32 { int32 i; uint32 u; } result; sign_x.i = x; sign_y.i = y; result.u = bitfieldInterleave(sign_x.u, sign_y.u); return result.i; } GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(uint16 x, uint16 y) { return detail::bitfieldInterleave(x, y); } GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(u16vec2 const& v) { return detail::bitfieldInterleave(v.x, v.y); } GLM_FUNC_QUALIFIER glm::u16vec2 bitfieldDeinterleave(glm::uint32 x) { glm::uint32 REG1(x); glm::uint32 REG2(x >>= 1); REG1 = REG1 & static_cast(0x55555555); REG2 = REG2 & static_cast(0x55555555); REG1 = ((REG1 >> 1) | REG1) & static_cast(0x33333333); REG2 = ((REG2 >> 1) | REG2) & static_cast(0x33333333); REG1 = ((REG1 >> 2) | REG1) & static_cast(0x0F0F0F0F); REG2 = ((REG2 >> 2) | REG2) & static_cast(0x0F0F0F0F); REG1 = ((REG1 >> 4) | REG1) & static_cast(0x00FF00FF); REG2 = ((REG2 >> 4) | REG2) & static_cast(0x00FF00FF); REG1 = ((REG1 >> 8) | REG1) & static_cast(0x0000FFFF); REG2 = ((REG2 >> 8) | REG2) & static_cast(0x0000FFFF); return glm::u16vec2(REG1, REG2); } GLM_FUNC_QUALIFIER int64 bitfieldInterleave(int32 x, int32 y) { union sign32 { int32 i; uint32 u; } sign_x, sign_y; union sign64 { int64 i; uint64 u; } result; sign_x.i = x; sign_y.i = y; result.u = bitfieldInterleave(sign_x.u, sign_y.u); return result.i; } GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint32 x, uint32 y) { return detail::bitfieldInterleave(x, y); } GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(u32vec2 const& v) { return detail::bitfieldInterleave(v.x, v.y); } GLM_FUNC_QUALIFIER glm::u32vec2 bitfieldDeinterleave(glm::uint64 x) { glm::uint64 REG1(x); glm::uint64 REG2(x >>= 1); REG1 = REG1 & static_cast(0x5555555555555555ull); REG2 = REG2 & static_cast(0x5555555555555555ull); REG1 = ((REG1 >> 1) | REG1) & static_cast(0x3333333333333333ull); REG2 = ((REG2 >> 1) | REG2) & static_cast(0x3333333333333333ull); REG1 = ((REG1 >> 2) | REG1) & static_cast(0x0F0F0F0F0F0F0F0Full); REG2 = ((REG2 >> 2) | REG2) & static_cast(0x0F0F0F0F0F0F0F0Full); REG1 = ((REG1 >> 4) | REG1) & static_cast(0x00FF00FF00FF00FFull); REG2 = ((REG2 >> 4) | REG2) & static_cast(0x00FF00FF00FF00FFull); REG1 = ((REG1 >> 8) | REG1) & static_cast(0x0000FFFF0000FFFFull); REG2 = ((REG2 >> 8) | REG2) & static_cast(0x0000FFFF0000FFFFull); REG1 = ((REG1 >> 16) | REG1) & static_cast(0x00000000FFFFFFFFull); REG2 = ((REG2 >> 16) | REG2) & static_cast(0x00000000FFFFFFFFull); return glm::u32vec2(REG1, REG2); } GLM_FUNC_QUALIFIER int32 bitfieldInterleave(int8 x, int8 y, int8 z) { union sign8 { int8 i; uint8 u; } sign_x, sign_y, sign_z; union sign32 { int32 i; uint32 u; } result; sign_x.i = x; sign_y.i = y; sign_z.i = z; result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u); return result.i; } GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z) { return detail::bitfieldInterleave(x, y, z); } GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(u8vec3 const& v) { return detail::bitfieldInterleave(v.x, v.y, v.z); } GLM_FUNC_QUALIFIER int64 bitfieldInterleave(int16 x, int16 y, int16 z) { union sign16 { int16 i; uint16 u; } sign_x, sign_y, sign_z; union sign64 { int64 i; uint64 u; } result; sign_x.i = x; sign_y.i = y; sign_z.i = z; result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u); return result.i; } GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z) { return detail::bitfieldInterleave(x, y, z); } GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(u16vec3 const& v) { return detail::bitfieldInterleave(v.x, v.y, v.z); } GLM_FUNC_QUALIFIER int64 bitfieldInterleave(int32 x, int32 y, int32 z) { union sign16 { int32 i; uint32 u; } sign_x, sign_y, sign_z; union sign64 { int64 i; uint64 u; } result; sign_x.i = x; sign_y.i = y; sign_z.i = z; result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u); return result.i; } GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint32 x, uint32 y, uint32 z) { return detail::bitfieldInterleave(x, y, z); } GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(u32vec3 const& v) { return detail::bitfieldInterleave(v.x, v.y, v.z); } GLM_FUNC_QUALIFIER int32 bitfieldInterleave(int8 x, int8 y, int8 z, int8 w) { union sign8 { int8 i; uint8 u; } sign_x, sign_y, sign_z, sign_w; union sign32 { int32 i; uint32 u; } result; sign_x.i = x; sign_y.i = y; sign_z.i = z; sign_w.i = w; result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u, sign_w.u); return result.i; } GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z, uint8 w) { return detail::bitfieldInterleave(x, y, z, w); } GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(u8vec4 const& v) { return detail::bitfieldInterleave(v.x, v.y, v.z, v.w); } GLM_FUNC_QUALIFIER int64 bitfieldInterleave(int16 x, int16 y, int16 z, int16 w) { union sign16 { int16 i; uint16 u; } sign_x, sign_y, sign_z, sign_w; union sign64 { int64 i; uint64 u; } result; sign_x.i = x; sign_y.i = y; sign_z.i = z; sign_w.i = w; result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u, sign_w.u); return result.i; } GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z, uint16 w) { return detail::bitfieldInterleave(x, y, z, w); } GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(u16vec4 const& v) { return detail::bitfieldInterleave(v.x, v.y, v.z, v.w); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtc/color_space.hpp000066400000000000000000000037441360521144700241040ustar00rootroot00000000000000/// @ref gtc_color_space /// @file glm/gtc/color_space.hpp /// /// @see core (dependence) /// @see gtc_color_space (dependence) /// /// @defgroup gtc_color_space GLM_GTC_color_space /// @ingroup gtc /// /// Include to use the features of this extension. /// /// Allow to perform bit operations on integer values #pragma once // Dependencies #include "../detail/setup.hpp" #include "../detail/qualifier.hpp" #include "../exponential.hpp" #include "../vec3.hpp" #include "../vec4.hpp" #include #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_GTC_color_space extension included") #endif namespace glm { /// @addtogroup gtc_color_space /// @{ /// Convert a linear color to sRGB color using a standard gamma correction. /// IEC 61966-2-1:1999 / Rec. 709 specification https://www.w3.org/Graphics/Color/srgb template GLM_FUNC_DECL vec convertLinearToSRGB(vec const& ColorLinear); /// Convert a linear color to sRGB color using a custom gamma correction. /// IEC 61966-2-1:1999 / Rec. 709 specification https://www.w3.org/Graphics/Color/srgb template GLM_FUNC_DECL vec convertLinearToSRGB(vec const& ColorLinear, T Gamma); /// Convert a sRGB color to linear color using a standard gamma correction. /// IEC 61966-2-1:1999 / Rec. 709 specification https://www.w3.org/Graphics/Color/srgb template GLM_FUNC_DECL vec convertSRGBToLinear(vec const& ColorSRGB); /// Convert a sRGB color to linear color using a custom gamma correction. // IEC 61966-2-1:1999 / Rec. 709 specification https://www.w3.org/Graphics/Color/srgb template GLM_FUNC_DECL vec convertSRGBToLinear(vec const& ColorSRGB, T Gamma); /// @} } //namespace glm #include "color_space.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtc/color_space.inl000066400000000000000000000057361360521144700241020ustar00rootroot00000000000000/// @ref gtc_color_space namespace glm{ namespace detail { template struct compute_rgbToSrgb { GLM_FUNC_QUALIFIER static vec call(vec const& ColorRGB, T GammaCorrection) { vec const ClampedColor(clamp(ColorRGB, static_cast(0), static_cast(1))); return mix( pow(ClampedColor, vec(GammaCorrection)) * static_cast(1.055) - static_cast(0.055), ClampedColor * static_cast(12.92), lessThan(ClampedColor, vec(static_cast(0.0031308)))); } }; template struct compute_rgbToSrgb<4, T, Q> { GLM_FUNC_QUALIFIER static vec<4, T, Q> call(vec<4, T, Q> const& ColorRGB, T GammaCorrection) { return vec<4, T, Q>(compute_rgbToSrgb<3, T, Q>::call(vec<3, T, Q>(ColorRGB), GammaCorrection), ColorRGB.w); } }; template struct compute_srgbToRgb { GLM_FUNC_QUALIFIER static vec call(vec const& ColorSRGB, T Gamma) { return mix( pow((ColorSRGB + static_cast(0.055)) * static_cast(0.94786729857819905213270142180095), vec(Gamma)), ColorSRGB * static_cast(0.07739938080495356037151702786378), lessThanEqual(ColorSRGB, vec(static_cast(0.04045)))); } }; template struct compute_srgbToRgb<4, T, Q> { GLM_FUNC_QUALIFIER static vec<4, T, Q> call(vec<4, T, Q> const& ColorSRGB, T Gamma) { return vec<4, T, Q>(compute_srgbToRgb<3, T, Q>::call(vec<3, T, Q>(ColorSRGB), Gamma), ColorSRGB.w); } }; }//namespace detail template GLM_FUNC_QUALIFIER vec convertLinearToSRGB(vec const& ColorLinear) { return detail::compute_rgbToSrgb::call(ColorLinear, static_cast(0.41666)); } // Based on Ian Taylor http://chilliant.blogspot.fr/2012/08/srgb-approximations-for-hlsl.html template<> GLM_FUNC_QUALIFIER vec<3, float, lowp> convertLinearToSRGB(vec<3, float, lowp> const& ColorLinear) { vec<3, float, lowp> S1 = sqrt(ColorLinear); vec<3, float, lowp> S2 = sqrt(S1); vec<3, float, lowp> S3 = sqrt(S2); return 0.662002687f * S1 + 0.684122060f * S2 - 0.323583601f * S3 - 0.0225411470f * ColorLinear; } template GLM_FUNC_QUALIFIER vec convertLinearToSRGB(vec const& ColorLinear, T Gamma) { return detail::compute_rgbToSrgb::call(ColorLinear, static_cast(1) / Gamma); } template GLM_FUNC_QUALIFIER vec convertSRGBToLinear(vec const& ColorSRGB) { return detail::compute_srgbToRgb::call(ColorSRGB, static_cast(2.4)); } template GLM_FUNC_QUALIFIER vec convertSRGBToLinear(vec const& ColorSRGB, T Gamma) { return detail::compute_srgbToRgb::call(ColorSRGB, Gamma); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtc/constants.hpp000066400000000000000000000101231360521144700236140ustar00rootroot00000000000000/// @ref gtc_constants /// @file glm/gtc/constants.hpp /// /// @see core (dependence) /// /// @defgroup gtc_constants GLM_GTC_constants /// @ingroup gtc /// /// Include to use the features of this extension. /// /// Provide a list of constants and precomputed useful values. #pragma once // Dependencies #include "../ext/scalar_constants.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_GTC_constants extension included") #endif namespace glm { /// @addtogroup gtc_constants /// @{ /// Return 0. /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType zero(); /// Return 1. /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType one(); /// Return pi * 2. /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType two_pi(); /// Return square root of pi. /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType root_pi(); /// Return pi / 2. /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType half_pi(); /// Return pi / 2 * 3. /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType three_over_two_pi(); /// Return pi / 4. /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType quarter_pi(); /// Return 1 / pi. /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType one_over_pi(); /// Return 1 / (pi * 2). /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType one_over_two_pi(); /// Return 2 / pi. /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType two_over_pi(); /// Return 4 / pi. /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType four_over_pi(); /// Return 2 / sqrt(pi). /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType two_over_root_pi(); /// Return 1 / sqrt(2). /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType one_over_root_two(); /// Return sqrt(pi / 2). /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType root_half_pi(); /// Return sqrt(2 * pi). /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType root_two_pi(); /// Return sqrt(ln(4)). /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType root_ln_four(); /// Return e constant. /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType e(); /// Return Euler's constant. /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType euler(); /// Return sqrt(2). /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType root_two(); /// Return sqrt(3). /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType root_three(); /// Return sqrt(5). /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType root_five(); /// Return ln(2). /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType ln_two(); /// Return ln(10). /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType ln_ten(); /// Return ln(ln(2)). /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType ln_ln_two(); /// Return 1 / 3. /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType third(); /// Return 2 / 3. /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType two_thirds(); /// Return the golden ratio constant. /// @see gtc_constants template GLM_FUNC_DECL GLM_CONSTEXPR genType golden_ratio(); /// @} } //namespace glm #include "constants.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtc/constants.inl000066400000000000000000000076421360521144700236230ustar00rootroot00000000000000/// @ref gtc_constants namespace glm { template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType zero() { return genType(0); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one() { return genType(1); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_pi() { return genType(6.28318530717958647692528676655900576); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_pi() { return genType(1.772453850905516027); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType half_pi() { return genType(1.57079632679489661923132169163975144); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType three_over_two_pi() { return genType(4.71238898038468985769396507491925432); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType quarter_pi() { return genType(0.785398163397448309615660845819875721); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one_over_pi() { return genType(0.318309886183790671537767526745028724); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one_over_two_pi() { return genType(0.159154943091895335768883763372514362); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_over_pi() { return genType(0.636619772367581343075535053490057448); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType four_over_pi() { return genType(1.273239544735162686151070106980114898); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_over_root_pi() { return genType(1.12837916709551257389615890312154517); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one_over_root_two() { return genType(0.707106781186547524400844362104849039); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_half_pi() { return genType(1.253314137315500251); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_two_pi() { return genType(2.506628274631000502); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_ln_four() { return genType(1.17741002251547469); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType e() { return genType(2.71828182845904523536); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType euler() { return genType(0.577215664901532860606); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_two() { return genType(1.41421356237309504880168872420969808); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_three() { return genType(1.73205080756887729352744634150587236); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_five() { return genType(2.23606797749978969640917366873127623); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType ln_two() { return genType(0.693147180559945309417232121458176568); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType ln_ten() { return genType(2.30258509299404568401799145468436421); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType ln_ln_two() { return genType(-0.3665129205816643); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType third() { return genType(0.3333333333333333333333333333333333333333); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_thirds() { return genType(0.666666666666666666666666666666666666667); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType golden_ratio() { return genType(1.61803398874989484820458683436563811); } } //namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtc/epsilon.hpp000066400000000000000000000034441360521144700232610ustar00rootroot00000000000000/// @ref gtc_epsilon /// @file glm/gtc/epsilon.hpp /// /// @see core (dependence) /// @see gtc_quaternion (dependence) /// /// @defgroup gtc_epsilon GLM_GTC_epsilon /// @ingroup gtc /// /// Include to use the features of this extension. /// /// Comparison functions for a user defined epsilon values. #pragma once // Dependencies #include "../detail/setup.hpp" #include "../detail/qualifier.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_GTC_epsilon extension included") #endif namespace glm { /// @addtogroup gtc_epsilon /// @{ /// Returns the component-wise comparison of |x - y| < epsilon. /// True if this expression is satisfied. /// /// @see gtc_epsilon template GLM_FUNC_DECL vec epsilonEqual(vec const& x, vec const& y, T const& epsilon); /// Returns the component-wise comparison of |x - y| < epsilon. /// True if this expression is satisfied. /// /// @see gtc_epsilon template GLM_FUNC_DECL bool epsilonEqual(genType const& x, genType const& y, genType const& epsilon); /// Returns the component-wise comparison of |x - y| < epsilon. /// True if this expression is not satisfied. /// /// @see gtc_epsilon template GLM_FUNC_DECL vec epsilonNotEqual(vec const& x, vec const& y, T const& epsilon); /// Returns the component-wise comparison of |x - y| >= epsilon. /// True if this expression is not satisfied. /// /// @see gtc_epsilon template GLM_FUNC_DECL bool epsilonNotEqual(genType const& x, genType const& y, genType const& epsilon); /// @} }//namespace glm #include "epsilon.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtc/epsilon.inl000066400000000000000000000043441360521144700232540ustar00rootroot00000000000000/// @ref gtc_epsilon // Dependency: #include "../vector_relational.hpp" #include "../common.hpp" namespace glm { template<> GLM_FUNC_QUALIFIER bool epsilonEqual ( float const& x, float const& y, float const& epsilon ) { return abs(x - y) < epsilon; } template<> GLM_FUNC_QUALIFIER bool epsilonEqual ( double const& x, double const& y, double const& epsilon ) { return abs(x - y) < epsilon; } template GLM_FUNC_QUALIFIER vec epsilonEqual(vec const& x, vec const& y, T const& epsilon) { return lessThan(abs(x - y), vec(epsilon)); } template GLM_FUNC_QUALIFIER vec epsilonEqual(vec const& x, vec const& y, vec const& epsilon) { return lessThan(abs(x - y), vec(epsilon)); } template<> GLM_FUNC_QUALIFIER bool epsilonNotEqual(float const& x, float const& y, float const& epsilon) { return abs(x - y) >= epsilon; } template<> GLM_FUNC_QUALIFIER bool epsilonNotEqual(double const& x, double const& y, double const& epsilon) { return abs(x - y) >= epsilon; } template GLM_FUNC_QUALIFIER vec epsilonNotEqual(vec const& x, vec const& y, T const& epsilon) { return greaterThanEqual(abs(x - y), vec(epsilon)); } template GLM_FUNC_QUALIFIER vec epsilonNotEqual(vec const& x, vec const& y, vec const& epsilon) { return greaterThanEqual(abs(x - y), vec(epsilon)); } template GLM_FUNC_QUALIFIER vec<4, bool, Q> epsilonEqual(qua const& x, qua const& y, T const& epsilon) { vec<4, T, Q> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w); return lessThan(abs(v), vec<4, T, Q>(epsilon)); } template GLM_FUNC_QUALIFIER vec<4, bool, Q> epsilonNotEqual(qua const& x, qua const& y, T const& epsilon) { vec<4, T, Q> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w); return greaterThanEqual(abs(v), vec<4, T, Q>(epsilon)); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtc/integer.hpp000066400000000000000000000040601360521144700232400ustar00rootroot00000000000000/// @ref gtc_integer /// @file glm/gtc/integer.hpp /// /// @see core (dependence) /// @see gtc_integer (dependence) /// /// @defgroup gtc_integer GLM_GTC_integer /// @ingroup gtc /// /// Include to use the features of this extension. /// /// @brief Allow to perform bit operations on integer values #pragma once // Dependencies #include "../detail/setup.hpp" #include "../detail/qualifier.hpp" #include "../common.hpp" #include "../integer.hpp" #include "../exponential.hpp" #include #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_GTC_integer extension included") #endif namespace glm { /// @addtogroup gtc_integer /// @{ /// Returns the log2 of x for integer values. Usefull to compute mipmap count from the texture size. /// @see gtc_integer template GLM_FUNC_DECL genIUType log2(genIUType x); /// Returns a value equal to the nearest integer to x. /// The fraction 0.5 will round in a direction chosen by the /// implementation, presumably the direction that is fastest. /// /// @param x The values of the argument must be greater or equal to zero. /// @tparam T floating point scalar types. /// /// @see GLSL round man page /// @see gtc_integer template GLM_FUNC_DECL vec iround(vec const& x); /// Returns a value equal to the nearest integer to x. /// The fraction 0.5 will round in a direction chosen by the /// implementation, presumably the direction that is fastest. /// /// @param x The values of the argument must be greater or equal to zero. /// @tparam T floating point scalar types. /// /// @see GLSL round man page /// @see gtc_integer template GLM_FUNC_DECL vec uround(vec const& x); /// @} } //namespace glm #include "integer.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtc/integer.inl000066400000000000000000000044421360521144700232370ustar00rootroot00000000000000/// @ref gtc_integer namespace glm{ namespace detail { template struct compute_log2 { GLM_FUNC_QUALIFIER static vec call(vec const& v) { //Equivalent to return findMSB(vec); but save one function call in ASM with VC //return findMSB(vec); return vec(detail::compute_findMSB_vec::call(v)); } }; # if GLM_HAS_BITSCAN_WINDOWS template struct compute_log2<4, int, Q, false, Aligned> { GLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v) { vec<4, int, Q> Result; _BitScanReverse(reinterpret_cast(&Result.x), v.x); _BitScanReverse(reinterpret_cast(&Result.y), v.y); _BitScanReverse(reinterpret_cast(&Result.z), v.z); _BitScanReverse(reinterpret_cast(&Result.w), v.w); return Result; } }; # endif//GLM_HAS_BITSCAN_WINDOWS }//namespace detail template GLM_FUNC_QUALIFIER int iround(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'iround' only accept floating-point inputs"); assert(static_cast(0.0) <= x); return static_cast(x + static_cast(0.5)); } template GLM_FUNC_QUALIFIER vec iround(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'iround' only accept floating-point inputs"); assert(all(lessThanEqual(vec(0), x))); return vec(x + static_cast(0.5)); } template GLM_FUNC_QUALIFIER uint uround(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'uround' only accept floating-point inputs"); assert(static_cast(0.0) <= x); return static_cast(x + static_cast(0.5)); } template GLM_FUNC_QUALIFIER vec uround(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'uround' only accept floating-point inputs"); assert(all(lessThanEqual(vec(0), x))); return vec(x + static_cast(0.5)); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtc/matrix_access.hpp000066400000000000000000000026741360521144700244410ustar00rootroot00000000000000/// @ref gtc_matrix_access /// @file glm/gtc/matrix_access.hpp /// /// @see core (dependence) /// /// @defgroup gtc_matrix_access GLM_GTC_matrix_access /// @ingroup gtc /// /// Include to use the features of this extension. /// /// Defines functions to access rows or columns of a matrix easily. #pragma once // Dependency: #include "../detail/setup.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_GTC_matrix_access extension included") #endif namespace glm { /// @addtogroup gtc_matrix_access /// @{ /// Get a specific row of a matrix. /// @see gtc_matrix_access template GLM_FUNC_DECL typename genType::row_type row( genType const& m, length_t index); /// Set a specific row to a matrix. /// @see gtc_matrix_access template GLM_FUNC_DECL genType row( genType const& m, length_t index, typename genType::row_type const& x); /// Get a specific column of a matrix. /// @see gtc_matrix_access template GLM_FUNC_DECL typename genType::col_type column( genType const& m, length_t index); /// Set a specific column to a matrix. /// @see gtc_matrix_access template GLM_FUNC_DECL genType column( genType const& m, length_t index, typename genType::col_type const& x); /// @} }//namespace glm #include "matrix_access.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtc/matrix_access.inl000066400000000000000000000022431360521144700244240ustar00rootroot00000000000000/// @ref gtc_matrix_access namespace glm { template GLM_FUNC_QUALIFIER genType row ( genType const& m, length_t index, typename genType::row_type const& x ) { assert(index >= 0 && index < m[0].length()); genType Result = m; for(length_t i = 0; i < m.length(); ++i) Result[i][index] = x[i]; return Result; } template GLM_FUNC_QUALIFIER typename genType::row_type row ( genType const& m, length_t index ) { assert(index >= 0 && index < m[0].length()); typename genType::row_type Result(0); for(length_t i = 0; i < m.length(); ++i) Result[i] = m[i][index]; return Result; } template GLM_FUNC_QUALIFIER genType column ( genType const& m, length_t index, typename genType::col_type const& x ) { assert(index >= 0 && index < m.length()); genType Result = m; Result[index] = x; return Result; } template GLM_FUNC_QUALIFIER typename genType::col_type column ( genType const& m, length_t index ) { assert(index >= 0 && index < m.length()); return m[index]; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtc/matrix_integer.hpp000066400000000000000000000352151360521144700246320ustar00rootroot00000000000000/// @ref gtc_matrix_integer /// @file glm/gtc/matrix_integer.hpp /// /// @see core (dependence) /// /// @defgroup gtc_matrix_integer GLM_GTC_matrix_integer /// @ingroup gtc /// /// Include to use the features of this extension. /// /// Defines a number of matrices with integer types. #pragma once // Dependency: #include "../mat2x2.hpp" #include "../mat2x3.hpp" #include "../mat2x4.hpp" #include "../mat3x2.hpp" #include "../mat3x3.hpp" #include "../mat3x4.hpp" #include "../mat4x2.hpp" #include "../mat4x3.hpp" #include "../mat4x4.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_GTC_matrix_integer extension included") #endif namespace glm { /// @addtogroup gtc_matrix_integer /// @{ /// High-qualifier signed integer 2x2 matrix. /// @see gtc_matrix_integer typedef mat<2, 2, int, highp> highp_imat2; /// High-qualifier signed integer 3x3 matrix. /// @see gtc_matrix_integer typedef mat<3, 3, int, highp> highp_imat3; /// High-qualifier signed integer 4x4 matrix. /// @see gtc_matrix_integer typedef mat<4, 4, int, highp> highp_imat4; /// High-qualifier signed integer 2x2 matrix. /// @see gtc_matrix_integer typedef mat<2, 2, int, highp> highp_imat2x2; /// High-qualifier signed integer 2x3 matrix. /// @see gtc_matrix_integer typedef mat<2, 3, int, highp> highp_imat2x3; /// High-qualifier signed integer 2x4 matrix. /// @see gtc_matrix_integer typedef mat<2, 4, int, highp> highp_imat2x4; /// High-qualifier signed integer 3x2 matrix. /// @see gtc_matrix_integer typedef mat<3, 2, int, highp> highp_imat3x2; /// High-qualifier signed integer 3x3 matrix. /// @see gtc_matrix_integer typedef mat<3, 3, int, highp> highp_imat3x3; /// High-qualifier signed integer 3x4 matrix. /// @see gtc_matrix_integer typedef mat<3, 4, int, highp> highp_imat3x4; /// High-qualifier signed integer 4x2 matrix. /// @see gtc_matrix_integer typedef mat<4, 2, int, highp> highp_imat4x2; /// High-qualifier signed integer 4x3 matrix. /// @see gtc_matrix_integer typedef mat<4, 3, int, highp> highp_imat4x3; /// High-qualifier signed integer 4x4 matrix. /// @see gtc_matrix_integer typedef mat<4, 4, int, highp> highp_imat4x4; /// Medium-qualifier signed integer 2x2 matrix. /// @see gtc_matrix_integer typedef mat<2, 2, int, mediump> mediump_imat2; /// Medium-qualifier signed integer 3x3 matrix. /// @see gtc_matrix_integer typedef mat<3, 3, int, mediump> mediump_imat3; /// Medium-qualifier signed integer 4x4 matrix. /// @see gtc_matrix_integer typedef mat<4, 4, int, mediump> mediump_imat4; /// Medium-qualifier signed integer 2x2 matrix. /// @see gtc_matrix_integer typedef mat<2, 2, int, mediump> mediump_imat2x2; /// Medium-qualifier signed integer 2x3 matrix. /// @see gtc_matrix_integer typedef mat<2, 3, int, mediump> mediump_imat2x3; /// Medium-qualifier signed integer 2x4 matrix. /// @see gtc_matrix_integer typedef mat<2, 4, int, mediump> mediump_imat2x4; /// Medium-qualifier signed integer 3x2 matrix. /// @see gtc_matrix_integer typedef mat<3, 2, int, mediump> mediump_imat3x2; /// Medium-qualifier signed integer 3x3 matrix. /// @see gtc_matrix_integer typedef mat<3, 3, int, mediump> mediump_imat3x3; /// Medium-qualifier signed integer 3x4 matrix. /// @see gtc_matrix_integer typedef mat<3, 4, int, mediump> mediump_imat3x4; /// Medium-qualifier signed integer 4x2 matrix. /// @see gtc_matrix_integer typedef mat<4, 2, int, mediump> mediump_imat4x2; /// Medium-qualifier signed integer 4x3 matrix. /// @see gtc_matrix_integer typedef mat<4, 3, int, mediump> mediump_imat4x3; /// Medium-qualifier signed integer 4x4 matrix. /// @see gtc_matrix_integer typedef mat<4, 4, int, mediump> mediump_imat4x4; /// Low-qualifier signed integer 2x2 matrix. /// @see gtc_matrix_integer typedef mat<2, 2, int, lowp> lowp_imat2; /// Low-qualifier signed integer 3x3 matrix. /// @see gtc_matrix_integer typedef mat<3, 3, int, lowp> lowp_imat3; /// Low-qualifier signed integer 4x4 matrix. /// @see gtc_matrix_integer typedef mat<4, 4, int, lowp> lowp_imat4; /// Low-qualifier signed integer 2x2 matrix. /// @see gtc_matrix_integer typedef mat<2, 2, int, lowp> lowp_imat2x2; /// Low-qualifier signed integer 2x3 matrix. /// @see gtc_matrix_integer typedef mat<2, 3, int, lowp> lowp_imat2x3; /// Low-qualifier signed integer 2x4 matrix. /// @see gtc_matrix_integer typedef mat<2, 4, int, lowp> lowp_imat2x4; /// Low-qualifier signed integer 3x2 matrix. /// @see gtc_matrix_integer typedef mat<3, 2, int, lowp> lowp_imat3x2; /// Low-qualifier signed integer 3x3 matrix. /// @see gtc_matrix_integer typedef mat<3, 3, int, lowp> lowp_imat3x3; /// Low-qualifier signed integer 3x4 matrix. /// @see gtc_matrix_integer typedef mat<3, 4, int, lowp> lowp_imat3x4; /// Low-qualifier signed integer 4x2 matrix. /// @see gtc_matrix_integer typedef mat<4, 2, int, lowp> lowp_imat4x2; /// Low-qualifier signed integer 4x3 matrix. /// @see gtc_matrix_integer typedef mat<4, 3, int, lowp> lowp_imat4x3; /// Low-qualifier signed integer 4x4 matrix. /// @see gtc_matrix_integer typedef mat<4, 4, int, lowp> lowp_imat4x4; /// High-qualifier unsigned integer 2x2 matrix. /// @see gtc_matrix_integer typedef mat<2, 2, uint, highp> highp_umat2; /// High-qualifier unsigned integer 3x3 matrix. /// @see gtc_matrix_integer typedef mat<3, 3, uint, highp> highp_umat3; /// High-qualifier unsigned integer 4x4 matrix. /// @see gtc_matrix_integer typedef mat<4, 4, uint, highp> highp_umat4; /// High-qualifier unsigned integer 2x2 matrix. /// @see gtc_matrix_integer typedef mat<2, 2, uint, highp> highp_umat2x2; /// High-qualifier unsigned integer 2x3 matrix. /// @see gtc_matrix_integer typedef mat<2, 3, uint, highp> highp_umat2x3; /// High-qualifier unsigned integer 2x4 matrix. /// @see gtc_matrix_integer typedef mat<2, 4, uint, highp> highp_umat2x4; /// High-qualifier unsigned integer 3x2 matrix. /// @see gtc_matrix_integer typedef mat<3, 2, uint, highp> highp_umat3x2; /// High-qualifier unsigned integer 3x3 matrix. /// @see gtc_matrix_integer typedef mat<3, 3, uint, highp> highp_umat3x3; /// High-qualifier unsigned integer 3x4 matrix. /// @see gtc_matrix_integer typedef mat<3, 4, uint, highp> highp_umat3x4; /// High-qualifier unsigned integer 4x2 matrix. /// @see gtc_matrix_integer typedef mat<4, 2, uint, highp> highp_umat4x2; /// High-qualifier unsigned integer 4x3 matrix. /// @see gtc_matrix_integer typedef mat<4, 3, uint, highp> highp_umat4x3; /// High-qualifier unsigned integer 4x4 matrix. /// @see gtc_matrix_integer typedef mat<4, 4, uint, highp> highp_umat4x4; /// Medium-qualifier unsigned integer 2x2 matrix. /// @see gtc_matrix_integer typedef mat<2, 2, uint, mediump> mediump_umat2; /// Medium-qualifier unsigned integer 3x3 matrix. /// @see gtc_matrix_integer typedef mat<3, 3, uint, mediump> mediump_umat3; /// Medium-qualifier unsigned integer 4x4 matrix. /// @see gtc_matrix_integer typedef mat<4, 4, uint, mediump> mediump_umat4; /// Medium-qualifier unsigned integer 2x2 matrix. /// @see gtc_matrix_integer typedef mat<2, 2, uint, mediump> mediump_umat2x2; /// Medium-qualifier unsigned integer 2x3 matrix. /// @see gtc_matrix_integer typedef mat<2, 3, uint, mediump> mediump_umat2x3; /// Medium-qualifier unsigned integer 2x4 matrix. /// @see gtc_matrix_integer typedef mat<2, 4, uint, mediump> mediump_umat2x4; /// Medium-qualifier unsigned integer 3x2 matrix. /// @see gtc_matrix_integer typedef mat<3, 2, uint, mediump> mediump_umat3x2; /// Medium-qualifier unsigned integer 3x3 matrix. /// @see gtc_matrix_integer typedef mat<3, 3, uint, mediump> mediump_umat3x3; /// Medium-qualifier unsigned integer 3x4 matrix. /// @see gtc_matrix_integer typedef mat<3, 4, uint, mediump> mediump_umat3x4; /// Medium-qualifier unsigned integer 4x2 matrix. /// @see gtc_matrix_integer typedef mat<4, 2, uint, mediump> mediump_umat4x2; /// Medium-qualifier unsigned integer 4x3 matrix. /// @see gtc_matrix_integer typedef mat<4, 3, uint, mediump> mediump_umat4x3; /// Medium-qualifier unsigned integer 4x4 matrix. /// @see gtc_matrix_integer typedef mat<4, 4, uint, mediump> mediump_umat4x4; /// Low-qualifier unsigned integer 2x2 matrix. /// @see gtc_matrix_integer typedef mat<2, 2, uint, lowp> lowp_umat2; /// Low-qualifier unsigned integer 3x3 matrix. /// @see gtc_matrix_integer typedef mat<3, 3, uint, lowp> lowp_umat3; /// Low-qualifier unsigned integer 4x4 matrix. /// @see gtc_matrix_integer typedef mat<4, 4, uint, lowp> lowp_umat4; /// Low-qualifier unsigned integer 2x2 matrix. /// @see gtc_matrix_integer typedef mat<2, 2, uint, lowp> lowp_umat2x2; /// Low-qualifier unsigned integer 2x3 matrix. /// @see gtc_matrix_integer typedef mat<2, 3, uint, lowp> lowp_umat2x3; /// Low-qualifier unsigned integer 2x4 matrix. /// @see gtc_matrix_integer typedef mat<2, 4, uint, lowp> lowp_umat2x4; /// Low-qualifier unsigned integer 3x2 matrix. /// @see gtc_matrix_integer typedef mat<3, 2, uint, lowp> lowp_umat3x2; /// Low-qualifier unsigned integer 3x3 matrix. /// @see gtc_matrix_integer typedef mat<3, 3, uint, lowp> lowp_umat3x3; /// Low-qualifier unsigned integer 3x4 matrix. /// @see gtc_matrix_integer typedef mat<3, 4, uint, lowp> lowp_umat3x4; /// Low-qualifier unsigned integer 4x2 matrix. /// @see gtc_matrix_integer typedef mat<4, 2, uint, lowp> lowp_umat4x2; /// Low-qualifier unsigned integer 4x3 matrix. /// @see gtc_matrix_integer typedef mat<4, 3, uint, lowp> lowp_umat4x3; /// Low-qualifier unsigned integer 4x4 matrix. /// @see gtc_matrix_integer typedef mat<4, 4, uint, lowp> lowp_umat4x4; #if(defined(GLM_PRECISION_HIGHP_INT)) typedef highp_imat2 imat2; typedef highp_imat3 imat3; typedef highp_imat4 imat4; typedef highp_imat2x2 imat2x2; typedef highp_imat2x3 imat2x3; typedef highp_imat2x4 imat2x4; typedef highp_imat3x2 imat3x2; typedef highp_imat3x3 imat3x3; typedef highp_imat3x4 imat3x4; typedef highp_imat4x2 imat4x2; typedef highp_imat4x3 imat4x3; typedef highp_imat4x4 imat4x4; #elif(defined(GLM_PRECISION_LOWP_INT)) typedef lowp_imat2 imat2; typedef lowp_imat3 imat3; typedef lowp_imat4 imat4; typedef lowp_imat2x2 imat2x2; typedef lowp_imat2x3 imat2x3; typedef lowp_imat2x4 imat2x4; typedef lowp_imat3x2 imat3x2; typedef lowp_imat3x3 imat3x3; typedef lowp_imat3x4 imat3x4; typedef lowp_imat4x2 imat4x2; typedef lowp_imat4x3 imat4x3; typedef lowp_imat4x4 imat4x4; #else //if(defined(GLM_PRECISION_MEDIUMP_INT)) /// Signed integer 2x2 matrix. /// @see gtc_matrix_integer typedef mediump_imat2 imat2; /// Signed integer 3x3 matrix. /// @see gtc_matrix_integer typedef mediump_imat3 imat3; /// Signed integer 4x4 matrix. /// @see gtc_matrix_integer typedef mediump_imat4 imat4; /// Signed integer 2x2 matrix. /// @see gtc_matrix_integer typedef mediump_imat2x2 imat2x2; /// Signed integer 2x3 matrix. /// @see gtc_matrix_integer typedef mediump_imat2x3 imat2x3; /// Signed integer 2x4 matrix. /// @see gtc_matrix_integer typedef mediump_imat2x4 imat2x4; /// Signed integer 3x2 matrix. /// @see gtc_matrix_integer typedef mediump_imat3x2 imat3x2; /// Signed integer 3x3 matrix. /// @see gtc_matrix_integer typedef mediump_imat3x3 imat3x3; /// Signed integer 3x4 matrix. /// @see gtc_matrix_integer typedef mediump_imat3x4 imat3x4; /// Signed integer 4x2 matrix. /// @see gtc_matrix_integer typedef mediump_imat4x2 imat4x2; /// Signed integer 4x3 matrix. /// @see gtc_matrix_integer typedef mediump_imat4x3 imat4x3; /// Signed integer 4x4 matrix. /// @see gtc_matrix_integer typedef mediump_imat4x4 imat4x4; #endif//GLM_PRECISION #if(defined(GLM_PRECISION_HIGHP_UINT)) typedef highp_umat2 umat2; typedef highp_umat3 umat3; typedef highp_umat4 umat4; typedef highp_umat2x2 umat2x2; typedef highp_umat2x3 umat2x3; typedef highp_umat2x4 umat2x4; typedef highp_umat3x2 umat3x2; typedef highp_umat3x3 umat3x3; typedef highp_umat3x4 umat3x4; typedef highp_umat4x2 umat4x2; typedef highp_umat4x3 umat4x3; typedef highp_umat4x4 umat4x4; #elif(defined(GLM_PRECISION_LOWP_UINT)) typedef lowp_umat2 umat2; typedef lowp_umat3 umat3; typedef lowp_umat4 umat4; typedef lowp_umat2x2 umat2x2; typedef lowp_umat2x3 umat2x3; typedef lowp_umat2x4 umat2x4; typedef lowp_umat3x2 umat3x2; typedef lowp_umat3x3 umat3x3; typedef lowp_umat3x4 umat3x4; typedef lowp_umat4x2 umat4x2; typedef lowp_umat4x3 umat4x3; typedef lowp_umat4x4 umat4x4; #else //if(defined(GLM_PRECISION_MEDIUMP_UINT)) /// Unsigned integer 2x2 matrix. /// @see gtc_matrix_integer typedef mediump_umat2 umat2; /// Unsigned integer 3x3 matrix. /// @see gtc_matrix_integer typedef mediump_umat3 umat3; /// Unsigned integer 4x4 matrix. /// @see gtc_matrix_integer typedef mediump_umat4 umat4; /// Unsigned integer 2x2 matrix. /// @see gtc_matrix_integer typedef mediump_umat2x2 umat2x2; /// Unsigned integer 2x3 matrix. /// @see gtc_matrix_integer typedef mediump_umat2x3 umat2x3; /// Unsigned integer 2x4 matrix. /// @see gtc_matrix_integer typedef mediump_umat2x4 umat2x4; /// Unsigned integer 3x2 matrix. /// @see gtc_matrix_integer typedef mediump_umat3x2 umat3x2; /// Unsigned integer 3x3 matrix. /// @see gtc_matrix_integer typedef mediump_umat3x3 umat3x3; /// Unsigned integer 3x4 matrix. /// @see gtc_matrix_integer typedef mediump_umat3x4 umat3x4; /// Unsigned integer 4x2 matrix. /// @see gtc_matrix_integer typedef mediump_umat4x2 umat4x2; /// Unsigned integer 4x3 matrix. /// @see gtc_matrix_integer typedef mediump_umat4x3 umat4x3; /// Unsigned integer 4x4 matrix. /// @see gtc_matrix_integer typedef mediump_umat4x4 umat4x4; #endif//GLM_PRECISION /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtc/matrix_inverse.hpp000066400000000000000000000027551360521144700246530ustar00rootroot00000000000000/// @ref gtc_matrix_inverse /// @file glm/gtc/matrix_inverse.hpp /// /// @see core (dependence) /// /// @defgroup gtc_matrix_inverse GLM_GTC_matrix_inverse /// @ingroup gtc /// /// Include to use the features of this extension. /// /// Defines additional matrix inverting functions. #pragma once // Dependencies #include "../detail/setup.hpp" #include "../matrix.hpp" #include "../mat2x2.hpp" #include "../mat3x3.hpp" #include "../mat4x4.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_GTC_matrix_inverse extension included") #endif namespace glm { /// @addtogroup gtc_matrix_inverse /// @{ /// Fast matrix inverse for affine matrix. /// /// @param m Input matrix to invert. /// @tparam genType Squared floating-point matrix: half, float or double. Inverse of matrix based of half-qualifier floating point value is highly innacurate. /// @see gtc_matrix_inverse template GLM_FUNC_DECL genType affineInverse(genType const& m); /// Compute the inverse transpose of a matrix. /// /// @param m Input matrix to invert transpose. /// @tparam genType Squared floating-point matrix: half, float or double. Inverse of matrix based of half-qualifier floating point value is highly innacurate. /// @see gtc_matrix_inverse template GLM_FUNC_DECL genType inverseTranspose(genType const& m); /// @} }//namespace glm #include "matrix_inverse.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtc/matrix_inverse.inl000066400000000000000000000116661360521144700246470ustar00rootroot00000000000000/// @ref gtc_matrix_inverse namespace glm { template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> affineInverse(mat<3, 3, T, Q> const& m) { mat<2, 2, T, Q> const Inv(inverse(mat<2, 2, T, Q>(m))); return mat<3, 3, T, Q>( vec<3, T, Q>(Inv[0], static_cast(0)), vec<3, T, Q>(Inv[1], static_cast(0)), vec<3, T, Q>(-Inv * vec<2, T, Q>(m[2]), static_cast(1))); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> affineInverse(mat<4, 4, T, Q> const& m) { mat<3, 3, T, Q> const Inv(inverse(mat<3, 3, T, Q>(m))); return mat<4, 4, T, Q>( vec<4, T, Q>(Inv[0], static_cast(0)), vec<4, T, Q>(Inv[1], static_cast(0)), vec<4, T, Q>(Inv[2], static_cast(0)), vec<4, T, Q>(-Inv * vec<3, T, Q>(m[3]), static_cast(1))); } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> inverseTranspose(mat<2, 2, T, Q> const& m) { T Determinant = m[0][0] * m[1][1] - m[1][0] * m[0][1]; mat<2, 2, T, Q> Inverse( + m[1][1] / Determinant, - m[0][1] / Determinant, - m[1][0] / Determinant, + m[0][0] / Determinant); return Inverse; } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> inverseTranspose(mat<3, 3, T, Q> const& m) { T Determinant = + m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]) + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]); mat<3, 3, T, Q> Inverse; Inverse[0][0] = + (m[1][1] * m[2][2] - m[2][1] * m[1][2]); Inverse[0][1] = - (m[1][0] * m[2][2] - m[2][0] * m[1][2]); Inverse[0][2] = + (m[1][0] * m[2][1] - m[2][0] * m[1][1]); Inverse[1][0] = - (m[0][1] * m[2][2] - m[2][1] * m[0][2]); Inverse[1][1] = + (m[0][0] * m[2][2] - m[2][0] * m[0][2]); Inverse[1][2] = - (m[0][0] * m[2][1] - m[2][0] * m[0][1]); Inverse[2][0] = + (m[0][1] * m[1][2] - m[1][1] * m[0][2]); Inverse[2][1] = - (m[0][0] * m[1][2] - m[1][0] * m[0][2]); Inverse[2][2] = + (m[0][0] * m[1][1] - m[1][0] * m[0][1]); Inverse /= Determinant; return Inverse; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> inverseTranspose(mat<4, 4, T, Q> const& m) { T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; T SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; T SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; T SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; T SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; T SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; T SubFactor11 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; T SubFactor12 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; T SubFactor13 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; T SubFactor14 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; T SubFactor15 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; T SubFactor16 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; T SubFactor17 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; mat<4, 4, T, Q> Inverse; Inverse[0][0] = + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02); Inverse[0][1] = - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04); Inverse[0][2] = + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05); Inverse[0][3] = - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05); Inverse[1][0] = - (m[0][1] * SubFactor00 - m[0][2] * SubFactor01 + m[0][3] * SubFactor02); Inverse[1][1] = + (m[0][0] * SubFactor00 - m[0][2] * SubFactor03 + m[0][3] * SubFactor04); Inverse[1][2] = - (m[0][0] * SubFactor01 - m[0][1] * SubFactor03 + m[0][3] * SubFactor05); Inverse[1][3] = + (m[0][0] * SubFactor02 - m[0][1] * SubFactor04 + m[0][2] * SubFactor05); Inverse[2][0] = + (m[0][1] * SubFactor06 - m[0][2] * SubFactor07 + m[0][3] * SubFactor08); Inverse[2][1] = - (m[0][0] * SubFactor06 - m[0][2] * SubFactor09 + m[0][3] * SubFactor10); Inverse[2][2] = + (m[0][0] * SubFactor07 - m[0][1] * SubFactor09 + m[0][3] * SubFactor11); Inverse[2][3] = - (m[0][0] * SubFactor08 - m[0][1] * SubFactor10 + m[0][2] * SubFactor11); Inverse[3][0] = - (m[0][1] * SubFactor12 - m[0][2] * SubFactor13 + m[0][3] * SubFactor14); Inverse[3][1] = + (m[0][0] * SubFactor12 - m[0][2] * SubFactor15 + m[0][3] * SubFactor16); Inverse[3][2] = - (m[0][0] * SubFactor13 - m[0][1] * SubFactor15 + m[0][3] * SubFactor17); Inverse[3][3] = + (m[0][0] * SubFactor14 - m[0][1] * SubFactor16 + m[0][2] * SubFactor17); T Determinant = + m[0][0] * Inverse[0][0] + m[0][1] * Inverse[0][1] + m[0][2] * Inverse[0][2] + m[0][3] * Inverse[0][3]; Inverse /= Determinant; return Inverse; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtc/matrix_transform.hpp000066400000000000000000000023121360521144700252000ustar00rootroot00000000000000/// @ref gtc_matrix_transform /// @file glm/gtc/matrix_transform.hpp /// /// @see core (dependence) /// @see gtx_transform /// @see gtx_transform2 /// /// @defgroup gtc_matrix_transform GLM_GTC_matrix_transform /// @ingroup gtc /// /// Include to use the features of this extension. /// /// Defines functions that generate common transformation matrices. /// /// The matrices generated by this extension use standard OpenGL fixed-function /// conventions. For example, the lookAt function generates a transform from world /// space into the specific eye space that the projective matrix functions /// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility /// specifications defines the particular layout of this eye space. #pragma once // Dependencies #include "../mat4x4.hpp" #include "../vec2.hpp" #include "../vec3.hpp" #include "../vec4.hpp" #include "../ext/matrix_projection.hpp" #include "../ext/matrix_clip_space.hpp" #include "../ext/matrix_transform.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_GTC_matrix_transform extension included") #endif #include "matrix_transform.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtc/matrix_transform.inl000066400000000000000000000001301360521144700251670ustar00rootroot00000000000000#include "../geometric.hpp" #include "../trigonometric.hpp" #include "../matrix.hpp" connectome-workbench-1.4.2/src/GLMath/glm/gtc/noise.hpp000066400000000000000000000030211360521144700227140ustar00rootroot00000000000000/// @ref gtc_noise /// @file glm/gtc/noise.hpp /// /// @see core (dependence) /// /// @defgroup gtc_noise GLM_GTC_noise /// @ingroup gtc /// /// Include to use the features of this extension. /// /// Defines 2D, 3D and 4D procedural noise functions /// Based on the work of Stefan Gustavson and Ashima Arts on "webgl-noise": /// https://github.com/ashima/webgl-noise /// Following Stefan Gustavson's paper "Simplex noise demystified": /// http://www.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf #pragma once // Dependencies #include "../detail/setup.hpp" #include "../detail/qualifier.hpp" #include "../detail/_noise.hpp" #include "../geometric.hpp" #include "../common.hpp" #include "../vector_relational.hpp" #include "../vec2.hpp" #include "../vec3.hpp" #include "../vec4.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_GTC_noise extension included") #endif namespace glm { /// @addtogroup gtc_noise /// @{ /// Classic perlin noise. /// @see gtc_noise template GLM_FUNC_DECL T perlin( vec const& p); /// Periodic perlin noise. /// @see gtc_noise template GLM_FUNC_DECL T perlin( vec const& p, vec const& rep); /// Simplex noise. /// @see gtc_noise template GLM_FUNC_DECL T simplex( vec const& p); /// @} }//namespace glm #include "noise.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtc/noise.inl000066400000000000000000001022731360521144700227200ustar00rootroot00000000000000/// @ref gtc_noise /// // Based on the work of Stefan Gustavson and Ashima Arts on "webgl-noise": // https://github.com/ashima/webgl-noise // Following Stefan Gustavson's paper "Simplex noise demystified": // http://www.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf namespace glm{ namespace gtc { template GLM_FUNC_QUALIFIER vec<4, T, Q> grad4(T const& j, vec<4, T, Q> const& ip) { vec<3, T, Q> pXYZ = floor(fract(vec<3, T, Q>(j) * vec<3, T, Q>(ip)) * T(7)) * ip[2] - T(1); T pW = static_cast(1.5) - dot(abs(pXYZ), vec<3, T, Q>(1)); vec<4, T, Q> s = vec<4, T, Q>(lessThan(vec<4, T, Q>(pXYZ, pW), vec<4, T, Q>(0.0))); pXYZ = pXYZ + (vec<3, T, Q>(s) * T(2) - T(1)) * s.w; return vec<4, T, Q>(pXYZ, pW); } }//namespace gtc // Classic Perlin noise template GLM_FUNC_QUALIFIER T perlin(vec<2, T, Q> const& Position) { vec<4, T, Q> Pi = glm::floor(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) + vec<4, T, Q>(0.0, 0.0, 1.0, 1.0); vec<4, T, Q> Pf = glm::fract(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) - vec<4, T, Q>(0.0, 0.0, 1.0, 1.0); Pi = mod(Pi, vec<4, T, Q>(289)); // To avoid truncation effects in permutation vec<4, T, Q> ix(Pi.x, Pi.z, Pi.x, Pi.z); vec<4, T, Q> iy(Pi.y, Pi.y, Pi.w, Pi.w); vec<4, T, Q> fx(Pf.x, Pf.z, Pf.x, Pf.z); vec<4, T, Q> fy(Pf.y, Pf.y, Pf.w, Pf.w); vec<4, T, Q> i = detail::permute(detail::permute(ix) + iy); vec<4, T, Q> gx = static_cast(2) * glm::fract(i / T(41)) - T(1); vec<4, T, Q> gy = glm::abs(gx) - T(0.5); vec<4, T, Q> tx = glm::floor(gx + T(0.5)); gx = gx - tx; vec<2, T, Q> g00(gx.x, gy.x); vec<2, T, Q> g10(gx.y, gy.y); vec<2, T, Q> g01(gx.z, gy.z); vec<2, T, Q> g11(gx.w, gy.w); vec<4, T, Q> norm = detail::taylorInvSqrt(vec<4, T, Q>(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); g00 *= norm.x; g01 *= norm.y; g10 *= norm.z; g11 *= norm.w; T n00 = dot(g00, vec<2, T, Q>(fx.x, fy.x)); T n10 = dot(g10, vec<2, T, Q>(fx.y, fy.y)); T n01 = dot(g01, vec<2, T, Q>(fx.z, fy.z)); T n11 = dot(g11, vec<2, T, Q>(fx.w, fy.w)); vec<2, T, Q> fade_xy = detail::fade(vec<2, T, Q>(Pf.x, Pf.y)); vec<2, T, Q> n_x = mix(vec<2, T, Q>(n00, n01), vec<2, T, Q>(n10, n11), fade_xy.x); T n_xy = mix(n_x.x, n_x.y, fade_xy.y); return T(2.3) * n_xy; } // Classic Perlin noise template GLM_FUNC_QUALIFIER T perlin(vec<3, T, Q> const& Position) { vec<3, T, Q> Pi0 = floor(Position); // Integer part for indexing vec<3, T, Q> Pi1 = Pi0 + T(1); // Integer part + 1 Pi0 = detail::mod289(Pi0); Pi1 = detail::mod289(Pi1); vec<3, T, Q> Pf0 = fract(Position); // Fractional part for interpolation vec<3, T, Q> Pf1 = Pf0 - T(1); // Fractional part - 1.0 vec<4, T, Q> ix(Pi0.x, Pi1.x, Pi0.x, Pi1.x); vec<4, T, Q> iy = vec<4, T, Q>(vec<2, T, Q>(Pi0.y), vec<2, T, Q>(Pi1.y)); vec<4, T, Q> iz0(Pi0.z); vec<4, T, Q> iz1(Pi1.z); vec<4, T, Q> ixy = detail::permute(detail::permute(ix) + iy); vec<4, T, Q> ixy0 = detail::permute(ixy + iz0); vec<4, T, Q> ixy1 = detail::permute(ixy + iz1); vec<4, T, Q> gx0 = ixy0 * T(1.0 / 7.0); vec<4, T, Q> gy0 = fract(floor(gx0) * T(1.0 / 7.0)) - T(0.5); gx0 = fract(gx0); vec<4, T, Q> gz0 = vec<4, T, Q>(0.5) - abs(gx0) - abs(gy0); vec<4, T, Q> sz0 = step(gz0, vec<4, T, Q>(0.0)); gx0 -= sz0 * (step(T(0), gx0) - T(0.5)); gy0 -= sz0 * (step(T(0), gy0) - T(0.5)); vec<4, T, Q> gx1 = ixy1 * T(1.0 / 7.0); vec<4, T, Q> gy1 = fract(floor(gx1) * T(1.0 / 7.0)) - T(0.5); gx1 = fract(gx1); vec<4, T, Q> gz1 = vec<4, T, Q>(0.5) - abs(gx1) - abs(gy1); vec<4, T, Q> sz1 = step(gz1, vec<4, T, Q>(0.0)); gx1 -= sz1 * (step(T(0), gx1) - T(0.5)); gy1 -= sz1 * (step(T(0), gy1) - T(0.5)); vec<3, T, Q> g000(gx0.x, gy0.x, gz0.x); vec<3, T, Q> g100(gx0.y, gy0.y, gz0.y); vec<3, T, Q> g010(gx0.z, gy0.z, gz0.z); vec<3, T, Q> g110(gx0.w, gy0.w, gz0.w); vec<3, T, Q> g001(gx1.x, gy1.x, gz1.x); vec<3, T, Q> g101(gx1.y, gy1.y, gz1.y); vec<3, T, Q> g011(gx1.z, gy1.z, gz1.z); vec<3, T, Q> g111(gx1.w, gy1.w, gz1.w); vec<4, T, Q> norm0 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); g000 *= norm0.x; g010 *= norm0.y; g100 *= norm0.z; g110 *= norm0.w; vec<4, T, Q> norm1 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); g001 *= norm1.x; g011 *= norm1.y; g101 *= norm1.z; g111 *= norm1.w; T n000 = dot(g000, Pf0); T n100 = dot(g100, vec<3, T, Q>(Pf1.x, Pf0.y, Pf0.z)); T n010 = dot(g010, vec<3, T, Q>(Pf0.x, Pf1.y, Pf0.z)); T n110 = dot(g110, vec<3, T, Q>(Pf1.x, Pf1.y, Pf0.z)); T n001 = dot(g001, vec<3, T, Q>(Pf0.x, Pf0.y, Pf1.z)); T n101 = dot(g101, vec<3, T, Q>(Pf1.x, Pf0.y, Pf1.z)); T n011 = dot(g011, vec<3, T, Q>(Pf0.x, Pf1.y, Pf1.z)); T n111 = dot(g111, Pf1); vec<3, T, Q> fade_xyz = detail::fade(Pf0); vec<4, T, Q> n_z = mix(vec<4, T, Q>(n000, n100, n010, n110), vec<4, T, Q>(n001, n101, n011, n111), fade_xyz.z); vec<2, T, Q> n_yz = mix(vec<2, T, Q>(n_z.x, n_z.y), vec<2, T, Q>(n_z.z, n_z.w), fade_xyz.y); T n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); return T(2.2) * n_xyz; } /* // Classic Perlin noise template GLM_FUNC_QUALIFIER T perlin(vec<3, T, Q> const& P) { vec<3, T, Q> Pi0 = floor(P); // Integer part for indexing vec<3, T, Q> Pi1 = Pi0 + T(1); // Integer part + 1 Pi0 = mod(Pi0, T(289)); Pi1 = mod(Pi1, T(289)); vec<3, T, Q> Pf0 = fract(P); // Fractional part for interpolation vec<3, T, Q> Pf1 = Pf0 - T(1); // Fractional part - 1.0 vec<4, T, Q> ix(Pi0.x, Pi1.x, Pi0.x, Pi1.x); vec<4, T, Q> iy(Pi0.y, Pi0.y, Pi1.y, Pi1.y); vec<4, T, Q> iz0(Pi0.z); vec<4, T, Q> iz1(Pi1.z); vec<4, T, Q> ixy = permute(permute(ix) + iy); vec<4, T, Q> ixy0 = permute(ixy + iz0); vec<4, T, Q> ixy1 = permute(ixy + iz1); vec<4, T, Q> gx0 = ixy0 / T(7); vec<4, T, Q> gy0 = fract(floor(gx0) / T(7)) - T(0.5); gx0 = fract(gx0); vec<4, T, Q> gz0 = vec<4, T, Q>(0.5) - abs(gx0) - abs(gy0); vec<4, T, Q> sz0 = step(gz0, vec<4, T, Q>(0.0)); gx0 -= sz0 * (step(0.0, gx0) - T(0.5)); gy0 -= sz0 * (step(0.0, gy0) - T(0.5)); vec<4, T, Q> gx1 = ixy1 / T(7); vec<4, T, Q> gy1 = fract(floor(gx1) / T(7)) - T(0.5); gx1 = fract(gx1); vec<4, T, Q> gz1 = vec<4, T, Q>(0.5) - abs(gx1) - abs(gy1); vec<4, T, Q> sz1 = step(gz1, vec<4, T, Q>(0.0)); gx1 -= sz1 * (step(T(0), gx1) - T(0.5)); gy1 -= sz1 * (step(T(0), gy1) - T(0.5)); vec<3, T, Q> g000(gx0.x, gy0.x, gz0.x); vec<3, T, Q> g100(gx0.y, gy0.y, gz0.y); vec<3, T, Q> g010(gx0.z, gy0.z, gz0.z); vec<3, T, Q> g110(gx0.w, gy0.w, gz0.w); vec<3, T, Q> g001(gx1.x, gy1.x, gz1.x); vec<3, T, Q> g101(gx1.y, gy1.y, gz1.y); vec<3, T, Q> g011(gx1.z, gy1.z, gz1.z); vec<3, T, Q> g111(gx1.w, gy1.w, gz1.w); vec<4, T, Q> norm0 = taylorInvSqrt(vec<4, T, Q>(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); g000 *= norm0.x; g010 *= norm0.y; g100 *= norm0.z; g110 *= norm0.w; vec<4, T, Q> norm1 = taylorInvSqrt(vec<4, T, Q>(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); g001 *= norm1.x; g011 *= norm1.y; g101 *= norm1.z; g111 *= norm1.w; T n000 = dot(g000, Pf0); T n100 = dot(g100, vec<3, T, Q>(Pf1.x, Pf0.y, Pf0.z)); T n010 = dot(g010, vec<3, T, Q>(Pf0.x, Pf1.y, Pf0.z)); T n110 = dot(g110, vec<3, T, Q>(Pf1.x, Pf1.y, Pf0.z)); T n001 = dot(g001, vec<3, T, Q>(Pf0.x, Pf0.y, Pf1.z)); T n101 = dot(g101, vec<3, T, Q>(Pf1.x, Pf0.y, Pf1.z)); T n011 = dot(g011, vec<3, T, Q>(Pf0.x, Pf1.y, Pf1.z)); T n111 = dot(g111, Pf1); vec<3, T, Q> fade_xyz = fade(Pf0); vec<4, T, Q> n_z = mix(vec<4, T, Q>(n000, n100, n010, n110), vec<4, T, Q>(n001, n101, n011, n111), fade_xyz.z); vec<2, T, Q> n_yz = mix( vec<2, T, Q>(n_z.x, n_z.y), vec<2, T, Q>(n_z.z, n_z.w), fade_xyz.y); T n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); return T(2.2) * n_xyz; } */ // Classic Perlin noise template GLM_FUNC_QUALIFIER T perlin(vec<4, T, Q> const& Position) { vec<4, T, Q> Pi0 = floor(Position); // Integer part for indexing vec<4, T, Q> Pi1 = Pi0 + T(1); // Integer part + 1 Pi0 = mod(Pi0, vec<4, T, Q>(289)); Pi1 = mod(Pi1, vec<4, T, Q>(289)); vec<4, T, Q> Pf0 = fract(Position); // Fractional part for interpolation vec<4, T, Q> Pf1 = Pf0 - T(1); // Fractional part - 1.0 vec<4, T, Q> ix(Pi0.x, Pi1.x, Pi0.x, Pi1.x); vec<4, T, Q> iy(Pi0.y, Pi0.y, Pi1.y, Pi1.y); vec<4, T, Q> iz0(Pi0.z); vec<4, T, Q> iz1(Pi1.z); vec<4, T, Q> iw0(Pi0.w); vec<4, T, Q> iw1(Pi1.w); vec<4, T, Q> ixy = detail::permute(detail::permute(ix) + iy); vec<4, T, Q> ixy0 = detail::permute(ixy + iz0); vec<4, T, Q> ixy1 = detail::permute(ixy + iz1); vec<4, T, Q> ixy00 = detail::permute(ixy0 + iw0); vec<4, T, Q> ixy01 = detail::permute(ixy0 + iw1); vec<4, T, Q> ixy10 = detail::permute(ixy1 + iw0); vec<4, T, Q> ixy11 = detail::permute(ixy1 + iw1); vec<4, T, Q> gx00 = ixy00 / T(7); vec<4, T, Q> gy00 = floor(gx00) / T(7); vec<4, T, Q> gz00 = floor(gy00) / T(6); gx00 = fract(gx00) - T(0.5); gy00 = fract(gy00) - T(0.5); gz00 = fract(gz00) - T(0.5); vec<4, T, Q> gw00 = vec<4, T, Q>(0.75) - abs(gx00) - abs(gy00) - abs(gz00); vec<4, T, Q> sw00 = step(gw00, vec<4, T, Q>(0.0)); gx00 -= sw00 * (step(T(0), gx00) - T(0.5)); gy00 -= sw00 * (step(T(0), gy00) - T(0.5)); vec<4, T, Q> gx01 = ixy01 / T(7); vec<4, T, Q> gy01 = floor(gx01) / T(7); vec<4, T, Q> gz01 = floor(gy01) / T(6); gx01 = fract(gx01) - T(0.5); gy01 = fract(gy01) - T(0.5); gz01 = fract(gz01) - T(0.5); vec<4, T, Q> gw01 = vec<4, T, Q>(0.75) - abs(gx01) - abs(gy01) - abs(gz01); vec<4, T, Q> sw01 = step(gw01, vec<4, T, Q>(0.0)); gx01 -= sw01 * (step(T(0), gx01) - T(0.5)); gy01 -= sw01 * (step(T(0), gy01) - T(0.5)); vec<4, T, Q> gx10 = ixy10 / T(7); vec<4, T, Q> gy10 = floor(gx10) / T(7); vec<4, T, Q> gz10 = floor(gy10) / T(6); gx10 = fract(gx10) - T(0.5); gy10 = fract(gy10) - T(0.5); gz10 = fract(gz10) - T(0.5); vec<4, T, Q> gw10 = vec<4, T, Q>(0.75) - abs(gx10) - abs(gy10) - abs(gz10); vec<4, T, Q> sw10 = step(gw10, vec<4, T, Q>(0)); gx10 -= sw10 * (step(T(0), gx10) - T(0.5)); gy10 -= sw10 * (step(T(0), gy10) - T(0.5)); vec<4, T, Q> gx11 = ixy11 / T(7); vec<4, T, Q> gy11 = floor(gx11) / T(7); vec<4, T, Q> gz11 = floor(gy11) / T(6); gx11 = fract(gx11) - T(0.5); gy11 = fract(gy11) - T(0.5); gz11 = fract(gz11) - T(0.5); vec<4, T, Q> gw11 = vec<4, T, Q>(0.75) - abs(gx11) - abs(gy11) - abs(gz11); vec<4, T, Q> sw11 = step(gw11, vec<4, T, Q>(0.0)); gx11 -= sw11 * (step(T(0), gx11) - T(0.5)); gy11 -= sw11 * (step(T(0), gy11) - T(0.5)); vec<4, T, Q> g0000(gx00.x, gy00.x, gz00.x, gw00.x); vec<4, T, Q> g1000(gx00.y, gy00.y, gz00.y, gw00.y); vec<4, T, Q> g0100(gx00.z, gy00.z, gz00.z, gw00.z); vec<4, T, Q> g1100(gx00.w, gy00.w, gz00.w, gw00.w); vec<4, T, Q> g0010(gx10.x, gy10.x, gz10.x, gw10.x); vec<4, T, Q> g1010(gx10.y, gy10.y, gz10.y, gw10.y); vec<4, T, Q> g0110(gx10.z, gy10.z, gz10.z, gw10.z); vec<4, T, Q> g1110(gx10.w, gy10.w, gz10.w, gw10.w); vec<4, T, Q> g0001(gx01.x, gy01.x, gz01.x, gw01.x); vec<4, T, Q> g1001(gx01.y, gy01.y, gz01.y, gw01.y); vec<4, T, Q> g0101(gx01.z, gy01.z, gz01.z, gw01.z); vec<4, T, Q> g1101(gx01.w, gy01.w, gz01.w, gw01.w); vec<4, T, Q> g0011(gx11.x, gy11.x, gz11.x, gw11.x); vec<4, T, Q> g1011(gx11.y, gy11.y, gz11.y, gw11.y); vec<4, T, Q> g0111(gx11.z, gy11.z, gz11.z, gw11.z); vec<4, T, Q> g1111(gx11.w, gy11.w, gz11.w, gw11.w); vec<4, T, Q> norm00 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0000, g0000), dot(g0100, g0100), dot(g1000, g1000), dot(g1100, g1100))); g0000 *= norm00.x; g0100 *= norm00.y; g1000 *= norm00.z; g1100 *= norm00.w; vec<4, T, Q> norm01 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0001, g0001), dot(g0101, g0101), dot(g1001, g1001), dot(g1101, g1101))); g0001 *= norm01.x; g0101 *= norm01.y; g1001 *= norm01.z; g1101 *= norm01.w; vec<4, T, Q> norm10 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0010, g0010), dot(g0110, g0110), dot(g1010, g1010), dot(g1110, g1110))); g0010 *= norm10.x; g0110 *= norm10.y; g1010 *= norm10.z; g1110 *= norm10.w; vec<4, T, Q> norm11 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0011, g0011), dot(g0111, g0111), dot(g1011, g1011), dot(g1111, g1111))); g0011 *= norm11.x; g0111 *= norm11.y; g1011 *= norm11.z; g1111 *= norm11.w; T n0000 = dot(g0000, Pf0); T n1000 = dot(g1000, vec<4, T, Q>(Pf1.x, Pf0.y, Pf0.z, Pf0.w)); T n0100 = dot(g0100, vec<4, T, Q>(Pf0.x, Pf1.y, Pf0.z, Pf0.w)); T n1100 = dot(g1100, vec<4, T, Q>(Pf1.x, Pf1.y, Pf0.z, Pf0.w)); T n0010 = dot(g0010, vec<4, T, Q>(Pf0.x, Pf0.y, Pf1.z, Pf0.w)); T n1010 = dot(g1010, vec<4, T, Q>(Pf1.x, Pf0.y, Pf1.z, Pf0.w)); T n0110 = dot(g0110, vec<4, T, Q>(Pf0.x, Pf1.y, Pf1.z, Pf0.w)); T n1110 = dot(g1110, vec<4, T, Q>(Pf1.x, Pf1.y, Pf1.z, Pf0.w)); T n0001 = dot(g0001, vec<4, T, Q>(Pf0.x, Pf0.y, Pf0.z, Pf1.w)); T n1001 = dot(g1001, vec<4, T, Q>(Pf1.x, Pf0.y, Pf0.z, Pf1.w)); T n0101 = dot(g0101, vec<4, T, Q>(Pf0.x, Pf1.y, Pf0.z, Pf1.w)); T n1101 = dot(g1101, vec<4, T, Q>(Pf1.x, Pf1.y, Pf0.z, Pf1.w)); T n0011 = dot(g0011, vec<4, T, Q>(Pf0.x, Pf0.y, Pf1.z, Pf1.w)); T n1011 = dot(g1011, vec<4, T, Q>(Pf1.x, Pf0.y, Pf1.z, Pf1.w)); T n0111 = dot(g0111, vec<4, T, Q>(Pf0.x, Pf1.y, Pf1.z, Pf1.w)); T n1111 = dot(g1111, Pf1); vec<4, T, Q> fade_xyzw = detail::fade(Pf0); vec<4, T, Q> n_0w = mix(vec<4, T, Q>(n0000, n1000, n0100, n1100), vec<4, T, Q>(n0001, n1001, n0101, n1101), fade_xyzw.w); vec<4, T, Q> n_1w = mix(vec<4, T, Q>(n0010, n1010, n0110, n1110), vec<4, T, Q>(n0011, n1011, n0111, n1111), fade_xyzw.w); vec<4, T, Q> n_zw = mix(n_0w, n_1w, fade_xyzw.z); vec<2, T, Q> n_yzw = mix(vec<2, T, Q>(n_zw.x, n_zw.y), vec<2, T, Q>(n_zw.z, n_zw.w), fade_xyzw.y); T n_xyzw = mix(n_yzw.x, n_yzw.y, fade_xyzw.x); return T(2.2) * n_xyzw; } // Classic Perlin noise, periodic variant template GLM_FUNC_QUALIFIER T perlin(vec<2, T, Q> const& Position, vec<2, T, Q> const& rep) { vec<4, T, Q> Pi = floor(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) + vec<4, T, Q>(0.0, 0.0, 1.0, 1.0); vec<4, T, Q> Pf = fract(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) - vec<4, T, Q>(0.0, 0.0, 1.0, 1.0); Pi = mod(Pi, vec<4, T, Q>(rep.x, rep.y, rep.x, rep.y)); // To create noise with explicit period Pi = mod(Pi, vec<4, T, Q>(289)); // To avoid truncation effects in permutation vec<4, T, Q> ix(Pi.x, Pi.z, Pi.x, Pi.z); vec<4, T, Q> iy(Pi.y, Pi.y, Pi.w, Pi.w); vec<4, T, Q> fx(Pf.x, Pf.z, Pf.x, Pf.z); vec<4, T, Q> fy(Pf.y, Pf.y, Pf.w, Pf.w); vec<4, T, Q> i = detail::permute(detail::permute(ix) + iy); vec<4, T, Q> gx = static_cast(2) * fract(i / T(41)) - T(1); vec<4, T, Q> gy = abs(gx) - T(0.5); vec<4, T, Q> tx = floor(gx + T(0.5)); gx = gx - tx; vec<2, T, Q> g00(gx.x, gy.x); vec<2, T, Q> g10(gx.y, gy.y); vec<2, T, Q> g01(gx.z, gy.z); vec<2, T, Q> g11(gx.w, gy.w); vec<4, T, Q> norm = detail::taylorInvSqrt(vec<4, T, Q>(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); g00 *= norm.x; g01 *= norm.y; g10 *= norm.z; g11 *= norm.w; T n00 = dot(g00, vec<2, T, Q>(fx.x, fy.x)); T n10 = dot(g10, vec<2, T, Q>(fx.y, fy.y)); T n01 = dot(g01, vec<2, T, Q>(fx.z, fy.z)); T n11 = dot(g11, vec<2, T, Q>(fx.w, fy.w)); vec<2, T, Q> fade_xy = detail::fade(vec<2, T, Q>(Pf.x, Pf.y)); vec<2, T, Q> n_x = mix(vec<2, T, Q>(n00, n01), vec<2, T, Q>(n10, n11), fade_xy.x); T n_xy = mix(n_x.x, n_x.y, fade_xy.y); return T(2.3) * n_xy; } // Classic Perlin noise, periodic variant template GLM_FUNC_QUALIFIER T perlin(vec<3, T, Q> const& Position, vec<3, T, Q> const& rep) { vec<3, T, Q> Pi0 = mod(floor(Position), rep); // Integer part, modulo period vec<3, T, Q> Pi1 = mod(Pi0 + vec<3, T, Q>(T(1)), rep); // Integer part + 1, mod period Pi0 = mod(Pi0, vec<3, T, Q>(289)); Pi1 = mod(Pi1, vec<3, T, Q>(289)); vec<3, T, Q> Pf0 = fract(Position); // Fractional part for interpolation vec<3, T, Q> Pf1 = Pf0 - vec<3, T, Q>(T(1)); // Fractional part - 1.0 vec<4, T, Q> ix = vec<4, T, Q>(Pi0.x, Pi1.x, Pi0.x, Pi1.x); vec<4, T, Q> iy = vec<4, T, Q>(Pi0.y, Pi0.y, Pi1.y, Pi1.y); vec<4, T, Q> iz0(Pi0.z); vec<4, T, Q> iz1(Pi1.z); vec<4, T, Q> ixy = detail::permute(detail::permute(ix) + iy); vec<4, T, Q> ixy0 = detail::permute(ixy + iz0); vec<4, T, Q> ixy1 = detail::permute(ixy + iz1); vec<4, T, Q> gx0 = ixy0 / T(7); vec<4, T, Q> gy0 = fract(floor(gx0) / T(7)) - T(0.5); gx0 = fract(gx0); vec<4, T, Q> gz0 = vec<4, T, Q>(0.5) - abs(gx0) - abs(gy0); vec<4, T, Q> sz0 = step(gz0, vec<4, T, Q>(0)); gx0 -= sz0 * (step(T(0), gx0) - T(0.5)); gy0 -= sz0 * (step(T(0), gy0) - T(0.5)); vec<4, T, Q> gx1 = ixy1 / T(7); vec<4, T, Q> gy1 = fract(floor(gx1) / T(7)) - T(0.5); gx1 = fract(gx1); vec<4, T, Q> gz1 = vec<4, T, Q>(0.5) - abs(gx1) - abs(gy1); vec<4, T, Q> sz1 = step(gz1, vec<4, T, Q>(T(0))); gx1 -= sz1 * (step(T(0), gx1) - T(0.5)); gy1 -= sz1 * (step(T(0), gy1) - T(0.5)); vec<3, T, Q> g000 = vec<3, T, Q>(gx0.x, gy0.x, gz0.x); vec<3, T, Q> g100 = vec<3, T, Q>(gx0.y, gy0.y, gz0.y); vec<3, T, Q> g010 = vec<3, T, Q>(gx0.z, gy0.z, gz0.z); vec<3, T, Q> g110 = vec<3, T, Q>(gx0.w, gy0.w, gz0.w); vec<3, T, Q> g001 = vec<3, T, Q>(gx1.x, gy1.x, gz1.x); vec<3, T, Q> g101 = vec<3, T, Q>(gx1.y, gy1.y, gz1.y); vec<3, T, Q> g011 = vec<3, T, Q>(gx1.z, gy1.z, gz1.z); vec<3, T, Q> g111 = vec<3, T, Q>(gx1.w, gy1.w, gz1.w); vec<4, T, Q> norm0 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); g000 *= norm0.x; g010 *= norm0.y; g100 *= norm0.z; g110 *= norm0.w; vec<4, T, Q> norm1 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); g001 *= norm1.x; g011 *= norm1.y; g101 *= norm1.z; g111 *= norm1.w; T n000 = dot(g000, Pf0); T n100 = dot(g100, vec<3, T, Q>(Pf1.x, Pf0.y, Pf0.z)); T n010 = dot(g010, vec<3, T, Q>(Pf0.x, Pf1.y, Pf0.z)); T n110 = dot(g110, vec<3, T, Q>(Pf1.x, Pf1.y, Pf0.z)); T n001 = dot(g001, vec<3, T, Q>(Pf0.x, Pf0.y, Pf1.z)); T n101 = dot(g101, vec<3, T, Q>(Pf1.x, Pf0.y, Pf1.z)); T n011 = dot(g011, vec<3, T, Q>(Pf0.x, Pf1.y, Pf1.z)); T n111 = dot(g111, Pf1); vec<3, T, Q> fade_xyz = detail::fade(Pf0); vec<4, T, Q> n_z = mix(vec<4, T, Q>(n000, n100, n010, n110), vec<4, T, Q>(n001, n101, n011, n111), fade_xyz.z); vec<2, T, Q> n_yz = mix(vec<2, T, Q>(n_z.x, n_z.y), vec<2, T, Q>(n_z.z, n_z.w), fade_xyz.y); T n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); return T(2.2) * n_xyz; } // Classic Perlin noise, periodic version template GLM_FUNC_QUALIFIER T perlin(vec<4, T, Q> const& Position, vec<4, T, Q> const& rep) { vec<4, T, Q> Pi0 = mod(floor(Position), rep); // Integer part modulo rep vec<4, T, Q> Pi1 = mod(Pi0 + T(1), rep); // Integer part + 1 mod rep vec<4, T, Q> Pf0 = fract(Position); // Fractional part for interpolation vec<4, T, Q> Pf1 = Pf0 - T(1); // Fractional part - 1.0 vec<4, T, Q> ix = vec<4, T, Q>(Pi0.x, Pi1.x, Pi0.x, Pi1.x); vec<4, T, Q> iy = vec<4, T, Q>(Pi0.y, Pi0.y, Pi1.y, Pi1.y); vec<4, T, Q> iz0(Pi0.z); vec<4, T, Q> iz1(Pi1.z); vec<4, T, Q> iw0(Pi0.w); vec<4, T, Q> iw1(Pi1.w); vec<4, T, Q> ixy = detail::permute(detail::permute(ix) + iy); vec<4, T, Q> ixy0 = detail::permute(ixy + iz0); vec<4, T, Q> ixy1 = detail::permute(ixy + iz1); vec<4, T, Q> ixy00 = detail::permute(ixy0 + iw0); vec<4, T, Q> ixy01 = detail::permute(ixy0 + iw1); vec<4, T, Q> ixy10 = detail::permute(ixy1 + iw0); vec<4, T, Q> ixy11 = detail::permute(ixy1 + iw1); vec<4, T, Q> gx00 = ixy00 / T(7); vec<4, T, Q> gy00 = floor(gx00) / T(7); vec<4, T, Q> gz00 = floor(gy00) / T(6); gx00 = fract(gx00) - T(0.5); gy00 = fract(gy00) - T(0.5); gz00 = fract(gz00) - T(0.5); vec<4, T, Q> gw00 = vec<4, T, Q>(0.75) - abs(gx00) - abs(gy00) - abs(gz00); vec<4, T, Q> sw00 = step(gw00, vec<4, T, Q>(0)); gx00 -= sw00 * (step(T(0), gx00) - T(0.5)); gy00 -= sw00 * (step(T(0), gy00) - T(0.5)); vec<4, T, Q> gx01 = ixy01 / T(7); vec<4, T, Q> gy01 = floor(gx01) / T(7); vec<4, T, Q> gz01 = floor(gy01) / T(6); gx01 = fract(gx01) - T(0.5); gy01 = fract(gy01) - T(0.5); gz01 = fract(gz01) - T(0.5); vec<4, T, Q> gw01 = vec<4, T, Q>(0.75) - abs(gx01) - abs(gy01) - abs(gz01); vec<4, T, Q> sw01 = step(gw01, vec<4, T, Q>(0.0)); gx01 -= sw01 * (step(T(0), gx01) - T(0.5)); gy01 -= sw01 * (step(T(0), gy01) - T(0.5)); vec<4, T, Q> gx10 = ixy10 / T(7); vec<4, T, Q> gy10 = floor(gx10) / T(7); vec<4, T, Q> gz10 = floor(gy10) / T(6); gx10 = fract(gx10) - T(0.5); gy10 = fract(gy10) - T(0.5); gz10 = fract(gz10) - T(0.5); vec<4, T, Q> gw10 = vec<4, T, Q>(0.75) - abs(gx10) - abs(gy10) - abs(gz10); vec<4, T, Q> sw10 = step(gw10, vec<4, T, Q>(0.0)); gx10 -= sw10 * (step(T(0), gx10) - T(0.5)); gy10 -= sw10 * (step(T(0), gy10) - T(0.5)); vec<4, T, Q> gx11 = ixy11 / T(7); vec<4, T, Q> gy11 = floor(gx11) / T(7); vec<4, T, Q> gz11 = floor(gy11) / T(6); gx11 = fract(gx11) - T(0.5); gy11 = fract(gy11) - T(0.5); gz11 = fract(gz11) - T(0.5); vec<4, T, Q> gw11 = vec<4, T, Q>(0.75) - abs(gx11) - abs(gy11) - abs(gz11); vec<4, T, Q> sw11 = step(gw11, vec<4, T, Q>(T(0))); gx11 -= sw11 * (step(T(0), gx11) - T(0.5)); gy11 -= sw11 * (step(T(0), gy11) - T(0.5)); vec<4, T, Q> g0000(gx00.x, gy00.x, gz00.x, gw00.x); vec<4, T, Q> g1000(gx00.y, gy00.y, gz00.y, gw00.y); vec<4, T, Q> g0100(gx00.z, gy00.z, gz00.z, gw00.z); vec<4, T, Q> g1100(gx00.w, gy00.w, gz00.w, gw00.w); vec<4, T, Q> g0010(gx10.x, gy10.x, gz10.x, gw10.x); vec<4, T, Q> g1010(gx10.y, gy10.y, gz10.y, gw10.y); vec<4, T, Q> g0110(gx10.z, gy10.z, gz10.z, gw10.z); vec<4, T, Q> g1110(gx10.w, gy10.w, gz10.w, gw10.w); vec<4, T, Q> g0001(gx01.x, gy01.x, gz01.x, gw01.x); vec<4, T, Q> g1001(gx01.y, gy01.y, gz01.y, gw01.y); vec<4, T, Q> g0101(gx01.z, gy01.z, gz01.z, gw01.z); vec<4, T, Q> g1101(gx01.w, gy01.w, gz01.w, gw01.w); vec<4, T, Q> g0011(gx11.x, gy11.x, gz11.x, gw11.x); vec<4, T, Q> g1011(gx11.y, gy11.y, gz11.y, gw11.y); vec<4, T, Q> g0111(gx11.z, gy11.z, gz11.z, gw11.z); vec<4, T, Q> g1111(gx11.w, gy11.w, gz11.w, gw11.w); vec<4, T, Q> norm00 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0000, g0000), dot(g0100, g0100), dot(g1000, g1000), dot(g1100, g1100))); g0000 *= norm00.x; g0100 *= norm00.y; g1000 *= norm00.z; g1100 *= norm00.w; vec<4, T, Q> norm01 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0001, g0001), dot(g0101, g0101), dot(g1001, g1001), dot(g1101, g1101))); g0001 *= norm01.x; g0101 *= norm01.y; g1001 *= norm01.z; g1101 *= norm01.w; vec<4, T, Q> norm10 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0010, g0010), dot(g0110, g0110), dot(g1010, g1010), dot(g1110, g1110))); g0010 *= norm10.x; g0110 *= norm10.y; g1010 *= norm10.z; g1110 *= norm10.w; vec<4, T, Q> norm11 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0011, g0011), dot(g0111, g0111), dot(g1011, g1011), dot(g1111, g1111))); g0011 *= norm11.x; g0111 *= norm11.y; g1011 *= norm11.z; g1111 *= norm11.w; T n0000 = dot(g0000, Pf0); T n1000 = dot(g1000, vec<4, T, Q>(Pf1.x, Pf0.y, Pf0.z, Pf0.w)); T n0100 = dot(g0100, vec<4, T, Q>(Pf0.x, Pf1.y, Pf0.z, Pf0.w)); T n1100 = dot(g1100, vec<4, T, Q>(Pf1.x, Pf1.y, Pf0.z, Pf0.w)); T n0010 = dot(g0010, vec<4, T, Q>(Pf0.x, Pf0.y, Pf1.z, Pf0.w)); T n1010 = dot(g1010, vec<4, T, Q>(Pf1.x, Pf0.y, Pf1.z, Pf0.w)); T n0110 = dot(g0110, vec<4, T, Q>(Pf0.x, Pf1.y, Pf1.z, Pf0.w)); T n1110 = dot(g1110, vec<4, T, Q>(Pf1.x, Pf1.y, Pf1.z, Pf0.w)); T n0001 = dot(g0001, vec<4, T, Q>(Pf0.x, Pf0.y, Pf0.z, Pf1.w)); T n1001 = dot(g1001, vec<4, T, Q>(Pf1.x, Pf0.y, Pf0.z, Pf1.w)); T n0101 = dot(g0101, vec<4, T, Q>(Pf0.x, Pf1.y, Pf0.z, Pf1.w)); T n1101 = dot(g1101, vec<4, T, Q>(Pf1.x, Pf1.y, Pf0.z, Pf1.w)); T n0011 = dot(g0011, vec<4, T, Q>(Pf0.x, Pf0.y, Pf1.z, Pf1.w)); T n1011 = dot(g1011, vec<4, T, Q>(Pf1.x, Pf0.y, Pf1.z, Pf1.w)); T n0111 = dot(g0111, vec<4, T, Q>(Pf0.x, Pf1.y, Pf1.z, Pf1.w)); T n1111 = dot(g1111, Pf1); vec<4, T, Q> fade_xyzw = detail::fade(Pf0); vec<4, T, Q> n_0w = mix(vec<4, T, Q>(n0000, n1000, n0100, n1100), vec<4, T, Q>(n0001, n1001, n0101, n1101), fade_xyzw.w); vec<4, T, Q> n_1w = mix(vec<4, T, Q>(n0010, n1010, n0110, n1110), vec<4, T, Q>(n0011, n1011, n0111, n1111), fade_xyzw.w); vec<4, T, Q> n_zw = mix(n_0w, n_1w, fade_xyzw.z); vec<2, T, Q> n_yzw = mix(vec<2, T, Q>(n_zw.x, n_zw.y), vec<2, T, Q>(n_zw.z, n_zw.w), fade_xyzw.y); T n_xyzw = mix(n_yzw.x, n_yzw.y, fade_xyzw.x); return T(2.2) * n_xyzw; } template GLM_FUNC_QUALIFIER T simplex(glm::vec<2, T, Q> const& v) { vec<4, T, Q> const C = vec<4, T, Q>( T( 0.211324865405187), // (3.0 - sqrt(3.0)) / 6.0 T( 0.366025403784439), // 0.5 * (sqrt(3.0) - 1.0) T(-0.577350269189626), // -1.0 + 2.0 * C.x T( 0.024390243902439)); // 1.0 / 41.0 // First corner vec<2, T, Q> i = floor(v + dot(v, vec<2, T, Q>(C[1]))); vec<2, T, Q> x0 = v - i + dot(i, vec<2, T, Q>(C[0])); // Other corners //i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0 //i1.y = 1.0 - i1.x; vec<2, T, Q> i1 = (x0.x > x0.y) ? vec<2, T, Q>(1, 0) : vec<2, T, Q>(0, 1); // x0 = x0 - 0.0 + 0.0 * C.xx ; // x1 = x0 - i1 + 1.0 * C.xx ; // x2 = x0 - 1.0 + 2.0 * C.xx ; vec<4, T, Q> x12 = vec<4, T, Q>(x0.x, x0.y, x0.x, x0.y) + vec<4, T, Q>(C.x, C.x, C.z, C.z); x12 = vec<4, T, Q>(vec<2, T, Q>(x12) - i1, x12.z, x12.w); // Permutations i = mod(i, vec<2, T, Q>(289)); // Avoid truncation effects in permutation vec<3, T, Q> p = detail::permute( detail::permute(i.y + vec<3, T, Q>(T(0), i1.y, T(1))) + i.x + vec<3, T, Q>(T(0), i1.x, T(1))); vec<3, T, Q> m = max(vec<3, T, Q>(0.5) - vec<3, T, Q>( dot(x0, x0), dot(vec<2, T, Q>(x12.x, x12.y), vec<2, T, Q>(x12.x, x12.y)), dot(vec<2, T, Q>(x12.z, x12.w), vec<2, T, Q>(x12.z, x12.w))), vec<3, T, Q>(0)); m = m * m ; m = m * m ; // Gradients: 41 points uniformly over a line, mapped onto a diamond. // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287) vec<3, T, Q> x = static_cast(2) * fract(p * C.w) - T(1); vec<3, T, Q> h = abs(x) - T(0.5); vec<3, T, Q> ox = floor(x + T(0.5)); vec<3, T, Q> a0 = x - ox; // Normalise gradients implicitly by scaling m // Inlined for speed: m *= taylorInvSqrt( a0*a0 + h*h ); m *= static_cast(1.79284291400159) - T(0.85373472095314) * (a0 * a0 + h * h); // Compute final noise value at P vec<3, T, Q> g; g.x = a0.x * x0.x + h.x * x0.y; //g.yz = a0.yz * x12.xz + h.yz * x12.yw; g.y = a0.y * x12.x + h.y * x12.y; g.z = a0.z * x12.z + h.z * x12.w; return T(130) * dot(m, g); } template GLM_FUNC_QUALIFIER T simplex(vec<3, T, Q> const& v) { vec<2, T, Q> const C(1.0 / 6.0, 1.0 / 3.0); vec<4, T, Q> const D(0.0, 0.5, 1.0, 2.0); // First corner vec<3, T, Q> i(floor(v + dot(v, vec<3, T, Q>(C.y)))); vec<3, T, Q> x0(v - i + dot(i, vec<3, T, Q>(C.x))); // Other corners vec<3, T, Q> g(step(vec<3, T, Q>(x0.y, x0.z, x0.x), x0)); vec<3, T, Q> l(T(1) - g); vec<3, T, Q> i1(min(g, vec<3, T, Q>(l.z, l.x, l.y))); vec<3, T, Q> i2(max(g, vec<3, T, Q>(l.z, l.x, l.y))); // x0 = x0 - 0.0 + 0.0 * C.xxx; // x1 = x0 - i1 + 1.0 * C.xxx; // x2 = x0 - i2 + 2.0 * C.xxx; // x3 = x0 - 1.0 + 3.0 * C.xxx; vec<3, T, Q> x1(x0 - i1 + C.x); vec<3, T, Q> x2(x0 - i2 + C.y); // 2.0*C.x = 1/3 = C.y vec<3, T, Q> x3(x0 - D.y); // -1.0+3.0*C.x = -0.5 = -D.y // Permutations i = detail::mod289(i); vec<4, T, Q> p(detail::permute(detail::permute(detail::permute( i.z + vec<4, T, Q>(T(0), i1.z, i2.z, T(1))) + i.y + vec<4, T, Q>(T(0), i1.y, i2.y, T(1))) + i.x + vec<4, T, Q>(T(0), i1.x, i2.x, T(1)))); // Gradients: 7x7 points over a square, mapped onto an octahedron. // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) T n_ = static_cast(0.142857142857); // 1.0/7.0 vec<3, T, Q> ns(n_ * vec<3, T, Q>(D.w, D.y, D.z) - vec<3, T, Q>(D.x, D.z, D.x)); vec<4, T, Q> j(p - T(49) * floor(p * ns.z * ns.z)); // mod(p,7*7) vec<4, T, Q> x_(floor(j * ns.z)); vec<4, T, Q> y_(floor(j - T(7) * x_)); // mod(j,N) vec<4, T, Q> x(x_ * ns.x + ns.y); vec<4, T, Q> y(y_ * ns.x + ns.y); vec<4, T, Q> h(T(1) - abs(x) - abs(y)); vec<4, T, Q> b0(x.x, x.y, y.x, y.y); vec<4, T, Q> b1(x.z, x.w, y.z, y.w); // vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; // vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; vec<4, T, Q> s0(floor(b0) * T(2) + T(1)); vec<4, T, Q> s1(floor(b1) * T(2) + T(1)); vec<4, T, Q> sh(-step(h, vec<4, T, Q>(0.0))); vec<4, T, Q> a0 = vec<4, T, Q>(b0.x, b0.z, b0.y, b0.w) + vec<4, T, Q>(s0.x, s0.z, s0.y, s0.w) * vec<4, T, Q>(sh.x, sh.x, sh.y, sh.y); vec<4, T, Q> a1 = vec<4, T, Q>(b1.x, b1.z, b1.y, b1.w) + vec<4, T, Q>(s1.x, s1.z, s1.y, s1.w) * vec<4, T, Q>(sh.z, sh.z, sh.w, sh.w); vec<3, T, Q> p0(a0.x, a0.y, h.x); vec<3, T, Q> p1(a0.z, a0.w, h.y); vec<3, T, Q> p2(a1.x, a1.y, h.z); vec<3, T, Q> p3(a1.z, a1.w, h.w); // Normalise gradients vec<4, T, Q> norm = detail::taylorInvSqrt(vec<4, T, Q>(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); p0 *= norm.x; p1 *= norm.y; p2 *= norm.z; p3 *= norm.w; // Mix final noise value vec<4, T, Q> m = max(T(0.6) - vec<4, T, Q>(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), vec<4, T, Q>(0)); m = m * m; return T(42) * dot(m * m, vec<4, T, Q>(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3))); } template GLM_FUNC_QUALIFIER T simplex(vec<4, T, Q> const& v) { vec<4, T, Q> const C( 0.138196601125011, // (5 - sqrt(5))/20 G4 0.276393202250021, // 2 * G4 0.414589803375032, // 3 * G4 -0.447213595499958); // -1 + 4 * G4 // (sqrt(5) - 1)/4 = F4, used once below T const F4 = static_cast(0.309016994374947451); // First corner vec<4, T, Q> i = floor(v + dot(v, vec<4, T, Q>(F4))); vec<4, T, Q> x0 = v - i + dot(i, vec<4, T, Q>(C.x)); // Other corners // Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI) vec<4, T, Q> i0; vec<3, T, Q> isX = step(vec<3, T, Q>(x0.y, x0.z, x0.w), vec<3, T, Q>(x0.x)); vec<3, T, Q> isYZ = step(vec<3, T, Q>(x0.z, x0.w, x0.w), vec<3, T, Q>(x0.y, x0.y, x0.z)); // i0.x = dot(isX, vec3(1.0)); //i0.x = isX.x + isX.y + isX.z; //i0.yzw = static_cast(1) - isX; i0 = vec<4, T, Q>(isX.x + isX.y + isX.z, T(1) - isX); // i0.y += dot(isYZ.xy, vec2(1.0)); i0.y += isYZ.x + isYZ.y; //i0.zw += 1.0 - vec<2, T, Q>(isYZ.x, isYZ.y); i0.z += static_cast(1) - isYZ.x; i0.w += static_cast(1) - isYZ.y; i0.z += isYZ.z; i0.w += static_cast(1) - isYZ.z; // i0 now contains the unique values 0,1,2,3 in each channel vec<4, T, Q> i3 = clamp(i0, T(0), T(1)); vec<4, T, Q> i2 = clamp(i0 - T(1), T(0), T(1)); vec<4, T, Q> i1 = clamp(i0 - T(2), T(0), T(1)); // x0 = x0 - 0.0 + 0.0 * C.xxxx // x1 = x0 - i1 + 0.0 * C.xxxx // x2 = x0 - i2 + 0.0 * C.xxxx // x3 = x0 - i3 + 0.0 * C.xxxx // x4 = x0 - 1.0 + 4.0 * C.xxxx vec<4, T, Q> x1 = x0 - i1 + C.x; vec<4, T, Q> x2 = x0 - i2 + C.y; vec<4, T, Q> x3 = x0 - i3 + C.z; vec<4, T, Q> x4 = x0 + C.w; // Permutations i = mod(i, vec<4, T, Q>(289)); T j0 = detail::permute(detail::permute(detail::permute(detail::permute(i.w) + i.z) + i.y) + i.x); vec<4, T, Q> j1 = detail::permute(detail::permute(detail::permute(detail::permute( i.w + vec<4, T, Q>(i1.w, i2.w, i3.w, T(1))) + i.z + vec<4, T, Q>(i1.z, i2.z, i3.z, T(1))) + i.y + vec<4, T, Q>(i1.y, i2.y, i3.y, T(1))) + i.x + vec<4, T, Q>(i1.x, i2.x, i3.x, T(1))); // Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope // 7*7*6 = 294, which is close to the ring size 17*17 = 289. vec<4, T, Q> ip = vec<4, T, Q>(T(1) / T(294), T(1) / T(49), T(1) / T(7), T(0)); vec<4, T, Q> p0 = gtc::grad4(j0, ip); vec<4, T, Q> p1 = gtc::grad4(j1.x, ip); vec<4, T, Q> p2 = gtc::grad4(j1.y, ip); vec<4, T, Q> p3 = gtc::grad4(j1.z, ip); vec<4, T, Q> p4 = gtc::grad4(j1.w, ip); // Normalise gradients vec<4, T, Q> norm = detail::taylorInvSqrt(vec<4, T, Q>(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); p0 *= norm.x; p1 *= norm.y; p2 *= norm.z; p3 *= norm.w; p4 *= detail::taylorInvSqrt(dot(p4, p4)); // Mix contributions from the five corners vec<3, T, Q> m0 = max(T(0.6) - vec<3, T, Q>(dot(x0, x0), dot(x1, x1), dot(x2, x2)), vec<3, T, Q>(0)); vec<2, T, Q> m1 = max(T(0.6) - vec<2, T, Q>(dot(x3, x3), dot(x4, x4) ), vec<2, T, Q>(0)); m0 = m0 * m0; m1 = m1 * m1; return T(49) * (dot(m0 * m0, vec<3, T, Q>(dot(p0, x0), dot(p1, x1), dot(p2, x2))) + dot(m1 * m1, vec<2, T, Q>(dot(p3, x3), dot(p4, x4)))); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtc/packing.hpp000066400000000000000000001075101360521144700232230ustar00rootroot00000000000000/// @ref gtc_packing /// @file glm/gtc/packing.hpp /// /// @see core (dependence) /// /// @defgroup gtc_packing GLM_GTC_packing /// @ingroup gtc /// /// Include to use the features of this extension. /// /// This extension provides a set of function to convert vertors to packed /// formats. #pragma once // Dependency: #include "type_precision.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_GTC_packing extension included") #endif namespace glm { /// @addtogroup gtc_packing /// @{ /// First, converts the normalized floating-point value v into a 8-bit integer value. /// Then, the results are packed into the returned 8-bit unsigned integer. /// /// The conversion for component c of v to fixed point is done as follows: /// packUnorm1x8: round(clamp(c, 0, +1) * 255.0) /// /// @see gtc_packing /// @see uint16 packUnorm2x8(vec2 const& v) /// @see uint32 packUnorm4x8(vec4 const& v) /// @see GLSL packUnorm4x8 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL uint8 packUnorm1x8(float v); /// Convert a single 8-bit integer to a normalized floating-point value. /// /// The conversion for unpacked fixed-point value f to floating point is done as follows: /// unpackUnorm4x8: f / 255.0 /// /// @see gtc_packing /// @see vec2 unpackUnorm2x8(uint16 p) /// @see vec4 unpackUnorm4x8(uint32 p) /// @see GLSL unpackUnorm4x8 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL float unpackUnorm1x8(uint8 p); /// First, converts each component of the normalized floating-point value v into 8-bit integer values. /// Then, the results are packed into the returned 16-bit unsigned integer. /// /// The conversion for component c of v to fixed point is done as follows: /// packUnorm2x8: round(clamp(c, 0, +1) * 255.0) /// /// The first component of the vector will be written to the least significant bits of the output; /// the last component will be written to the most significant bits. /// /// @see gtc_packing /// @see uint8 packUnorm1x8(float const& v) /// @see uint32 packUnorm4x8(vec4 const& v) /// @see GLSL packUnorm4x8 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL uint16 packUnorm2x8(vec2 const& v); /// First, unpacks a single 16-bit unsigned integer p into a pair of 8-bit unsigned integers. /// Then, each component is converted to a normalized floating-point value to generate the returned two-component vector. /// /// The conversion for unpacked fixed-point value f to floating point is done as follows: /// unpackUnorm4x8: f / 255.0 /// /// The first component of the returned vector will be extracted from the least significant bits of the input; /// the last component will be extracted from the most significant bits. /// /// @see gtc_packing /// @see float unpackUnorm1x8(uint8 v) /// @see vec4 unpackUnorm4x8(uint32 p) /// @see GLSL unpackUnorm4x8 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL vec2 unpackUnorm2x8(uint16 p); /// First, converts the normalized floating-point value v into 8-bit integer value. /// Then, the results are packed into the returned 8-bit unsigned integer. /// /// The conversion to fixed point is done as follows: /// packSnorm1x8: round(clamp(s, -1, +1) * 127.0) /// /// @see gtc_packing /// @see uint16 packSnorm2x8(vec2 const& v) /// @see uint32 packSnorm4x8(vec4 const& v) /// @see GLSL packSnorm4x8 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL uint8 packSnorm1x8(float s); /// First, unpacks a single 8-bit unsigned integer p into a single 8-bit signed integers. /// Then, the value is converted to a normalized floating-point value to generate the returned scalar. /// /// The conversion for unpacked fixed-point value f to floating point is done as follows: /// unpackSnorm1x8: clamp(f / 127.0, -1, +1) /// /// @see gtc_packing /// @see vec2 unpackSnorm2x8(uint16 p) /// @see vec4 unpackSnorm4x8(uint32 p) /// @see GLSL unpackSnorm4x8 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL float unpackSnorm1x8(uint8 p); /// First, converts each component of the normalized floating-point value v into 8-bit integer values. /// Then, the results are packed into the returned 16-bit unsigned integer. /// /// The conversion for component c of v to fixed point is done as follows: /// packSnorm2x8: round(clamp(c, -1, +1) * 127.0) /// /// The first component of the vector will be written to the least significant bits of the output; /// the last component will be written to the most significant bits. /// /// @see gtc_packing /// @see uint8 packSnorm1x8(float const& v) /// @see uint32 packSnorm4x8(vec4 const& v) /// @see GLSL packSnorm4x8 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL uint16 packSnorm2x8(vec2 const& v); /// First, unpacks a single 16-bit unsigned integer p into a pair of 8-bit signed integers. /// Then, each component is converted to a normalized floating-point value to generate the returned two-component vector. /// /// The conversion for unpacked fixed-point value f to floating point is done as follows: /// unpackSnorm2x8: clamp(f / 127.0, -1, +1) /// /// The first component of the returned vector will be extracted from the least significant bits of the input; /// the last component will be extracted from the most significant bits. /// /// @see gtc_packing /// @see float unpackSnorm1x8(uint8 p) /// @see vec4 unpackSnorm4x8(uint32 p) /// @see GLSL unpackSnorm4x8 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL vec2 unpackSnorm2x8(uint16 p); /// First, converts the normalized floating-point value v into a 16-bit integer value. /// Then, the results are packed into the returned 16-bit unsigned integer. /// /// The conversion for component c of v to fixed point is done as follows: /// packUnorm1x16: round(clamp(c, 0, +1) * 65535.0) /// /// @see gtc_packing /// @see uint16 packSnorm1x16(float const& v) /// @see uint64 packSnorm4x16(vec4 const& v) /// @see GLSL packUnorm4x8 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL uint16 packUnorm1x16(float v); /// First, unpacks a single 16-bit unsigned integer p into a of 16-bit unsigned integers. /// Then, the value is converted to a normalized floating-point value to generate the returned scalar. /// /// The conversion for unpacked fixed-point value f to floating point is done as follows: /// unpackUnorm1x16: f / 65535.0 /// /// @see gtc_packing /// @see vec2 unpackUnorm2x16(uint32 p) /// @see vec4 unpackUnorm4x16(uint64 p) /// @see GLSL unpackUnorm2x16 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL float unpackUnorm1x16(uint16 p); /// First, converts each component of the normalized floating-point value v into 16-bit integer values. /// Then, the results are packed into the returned 64-bit unsigned integer. /// /// The conversion for component c of v to fixed point is done as follows: /// packUnorm4x16: round(clamp(c, 0, +1) * 65535.0) /// /// The first component of the vector will be written to the least significant bits of the output; /// the last component will be written to the most significant bits. /// /// @see gtc_packing /// @see uint16 packUnorm1x16(float const& v) /// @see uint32 packUnorm2x16(vec2 const& v) /// @see GLSL packUnorm4x8 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL uint64 packUnorm4x16(vec4 const& v); /// First, unpacks a single 64-bit unsigned integer p into four 16-bit unsigned integers. /// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector. /// /// The conversion for unpacked fixed-point value f to floating point is done as follows: /// unpackUnormx4x16: f / 65535.0 /// /// The first component of the returned vector will be extracted from the least significant bits of the input; /// the last component will be extracted from the most significant bits. /// /// @see gtc_packing /// @see float unpackUnorm1x16(uint16 p) /// @see vec2 unpackUnorm2x16(uint32 p) /// @see GLSL unpackUnorm2x16 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL vec4 unpackUnorm4x16(uint64 p); /// First, converts the normalized floating-point value v into 16-bit integer value. /// Then, the results are packed into the returned 16-bit unsigned integer. /// /// The conversion to fixed point is done as follows: /// packSnorm1x8: round(clamp(s, -1, +1) * 32767.0) /// /// @see gtc_packing /// @see uint32 packSnorm2x16(vec2 const& v) /// @see uint64 packSnorm4x16(vec4 const& v) /// @see GLSL packSnorm4x8 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL uint16 packSnorm1x16(float v); /// First, unpacks a single 16-bit unsigned integer p into a single 16-bit signed integers. /// Then, each component is converted to a normalized floating-point value to generate the returned scalar. /// /// The conversion for unpacked fixed-point value f to floating point is done as follows: /// unpackSnorm1x16: clamp(f / 32767.0, -1, +1) /// /// @see gtc_packing /// @see vec2 unpackSnorm2x16(uint32 p) /// @see vec4 unpackSnorm4x16(uint64 p) /// @see GLSL unpackSnorm4x8 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL float unpackSnorm1x16(uint16 p); /// First, converts each component of the normalized floating-point value v into 16-bit integer values. /// Then, the results are packed into the returned 64-bit unsigned integer. /// /// The conversion for component c of v to fixed point is done as follows: /// packSnorm2x8: round(clamp(c, -1, +1) * 32767.0) /// /// The first component of the vector will be written to the least significant bits of the output; /// the last component will be written to the most significant bits. /// /// @see gtc_packing /// @see uint16 packSnorm1x16(float const& v) /// @see uint32 packSnorm2x16(vec2 const& v) /// @see GLSL packSnorm4x8 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL uint64 packSnorm4x16(vec4 const& v); /// First, unpacks a single 64-bit unsigned integer p into four 16-bit signed integers. /// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector. /// /// The conversion for unpacked fixed-point value f to floating point is done as follows: /// unpackSnorm4x16: clamp(f / 32767.0, -1, +1) /// /// The first component of the returned vector will be extracted from the least significant bits of the input; /// the last component will be extracted from the most significant bits. /// /// @see gtc_packing /// @see float unpackSnorm1x16(uint16 p) /// @see vec2 unpackSnorm2x16(uint32 p) /// @see GLSL unpackSnorm4x8 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL vec4 unpackSnorm4x16(uint64 p); /// Returns an unsigned integer obtained by converting the components of a floating-point scalar /// to the 16-bit floating-point representation found in the OpenGL Specification, /// and then packing this 16-bit value into a 16-bit unsigned integer. /// /// @see gtc_packing /// @see uint32 packHalf2x16(vec2 const& v) /// @see uint64 packHalf4x16(vec4 const& v) /// @see GLSL packHalf2x16 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL uint16 packHalf1x16(float v); /// Returns a floating-point scalar with components obtained by unpacking a 16-bit unsigned integer into a 16-bit value, /// interpreted as a 16-bit floating-point number according to the OpenGL Specification, /// and converting it to 32-bit floating-point values. /// /// @see gtc_packing /// @see vec2 unpackHalf2x16(uint32 const& v) /// @see vec4 unpackHalf4x16(uint64 const& v) /// @see GLSL unpackHalf2x16 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL float unpackHalf1x16(uint16 v); /// Returns an unsigned integer obtained by converting the components of a four-component floating-point vector /// to the 16-bit floating-point representation found in the OpenGL Specification, /// and then packing these four 16-bit values into a 64-bit unsigned integer. /// The first vector component specifies the 16 least-significant bits of the result; /// the forth component specifies the 16 most-significant bits. /// /// @see gtc_packing /// @see uint16 packHalf1x16(float const& v) /// @see uint32 packHalf2x16(vec2 const& v) /// @see GLSL packHalf2x16 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL uint64 packHalf4x16(vec4 const& v); /// Returns a four-component floating-point vector with components obtained by unpacking a 64-bit unsigned integer into four 16-bit values, /// interpreting those values as 16-bit floating-point numbers according to the OpenGL Specification, /// and converting them to 32-bit floating-point values. /// The first component of the vector is obtained from the 16 least-significant bits of v; /// the forth component is obtained from the 16 most-significant bits of v. /// /// @see gtc_packing /// @see float unpackHalf1x16(uint16 const& v) /// @see vec2 unpackHalf2x16(uint32 const& v) /// @see GLSL unpackHalf2x16 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL vec4 unpackHalf4x16(uint64 p); /// Returns an unsigned integer obtained by converting the components of a four-component signed integer vector /// to the 10-10-10-2-bit signed integer representation found in the OpenGL Specification, /// and then packing these four values into a 32-bit unsigned integer. /// The first vector component specifies the 10 least-significant bits of the result; /// the forth component specifies the 2 most-significant bits. /// /// @see gtc_packing /// @see uint32 packI3x10_1x2(uvec4 const& v) /// @see uint32 packSnorm3x10_1x2(vec4 const& v) /// @see uint32 packUnorm3x10_1x2(vec4 const& v) /// @see ivec4 unpackI3x10_1x2(uint32 const& p) GLM_FUNC_DECL uint32 packI3x10_1x2(ivec4 const& v); /// Unpacks a single 32-bit unsigned integer p into three 10-bit and one 2-bit signed integers. /// /// The first component of the returned vector will be extracted from the least significant bits of the input; /// the last component will be extracted from the most significant bits. /// /// @see gtc_packing /// @see uint32 packU3x10_1x2(uvec4 const& v) /// @see vec4 unpackSnorm3x10_1x2(uint32 const& p); /// @see uvec4 unpackI3x10_1x2(uint32 const& p); GLM_FUNC_DECL ivec4 unpackI3x10_1x2(uint32 p); /// Returns an unsigned integer obtained by converting the components of a four-component unsigned integer vector /// to the 10-10-10-2-bit unsigned integer representation found in the OpenGL Specification, /// and then packing these four values into a 32-bit unsigned integer. /// The first vector component specifies the 10 least-significant bits of the result; /// the forth component specifies the 2 most-significant bits. /// /// @see gtc_packing /// @see uint32 packI3x10_1x2(ivec4 const& v) /// @see uint32 packSnorm3x10_1x2(vec4 const& v) /// @see uint32 packUnorm3x10_1x2(vec4 const& v) /// @see ivec4 unpackU3x10_1x2(uint32 const& p) GLM_FUNC_DECL uint32 packU3x10_1x2(uvec4 const& v); /// Unpacks a single 32-bit unsigned integer p into three 10-bit and one 2-bit unsigned integers. /// /// The first component of the returned vector will be extracted from the least significant bits of the input; /// the last component will be extracted from the most significant bits. /// /// @see gtc_packing /// @see uint32 packU3x10_1x2(uvec4 const& v) /// @see vec4 unpackSnorm3x10_1x2(uint32 const& p); /// @see uvec4 unpackI3x10_1x2(uint32 const& p); GLM_FUNC_DECL uvec4 unpackU3x10_1x2(uint32 p); /// First, converts the first three components of the normalized floating-point value v into 10-bit signed integer values. /// Then, converts the forth component of the normalized floating-point value v into 2-bit signed integer values. /// Then, the results are packed into the returned 32-bit unsigned integer. /// /// The conversion for component c of v to fixed point is done as follows: /// packSnorm3x10_1x2(xyz): round(clamp(c, -1, +1) * 511.0) /// packSnorm3x10_1x2(w): round(clamp(c, -1, +1) * 1.0) /// /// The first vector component specifies the 10 least-significant bits of the result; /// the forth component specifies the 2 most-significant bits. /// /// @see gtc_packing /// @see vec4 unpackSnorm3x10_1x2(uint32 const& p) /// @see uint32 packUnorm3x10_1x2(vec4 const& v) /// @see uint32 packU3x10_1x2(uvec4 const& v) /// @see uint32 packI3x10_1x2(ivec4 const& v) GLM_FUNC_DECL uint32 packSnorm3x10_1x2(vec4 const& v); /// First, unpacks a single 32-bit unsigned integer p into four 16-bit signed integers. /// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector. /// /// The conversion for unpacked fixed-point value f to floating point is done as follows: /// unpackSnorm3x10_1x2(xyz): clamp(f / 511.0, -1, +1) /// unpackSnorm3x10_1x2(w): clamp(f / 511.0, -1, +1) /// /// The first component of the returned vector will be extracted from the least significant bits of the input; /// the last component will be extracted from the most significant bits. /// /// @see gtc_packing /// @see uint32 packSnorm3x10_1x2(vec4 const& v) /// @see vec4 unpackUnorm3x10_1x2(uint32 const& p)) /// @see uvec4 unpackI3x10_1x2(uint32 const& p) /// @see uvec4 unpackU3x10_1x2(uint32 const& p) GLM_FUNC_DECL vec4 unpackSnorm3x10_1x2(uint32 p); /// First, converts the first three components of the normalized floating-point value v into 10-bit unsigned integer values. /// Then, converts the forth component of the normalized floating-point value v into 2-bit signed uninteger values. /// Then, the results are packed into the returned 32-bit unsigned integer. /// /// The conversion for component c of v to fixed point is done as follows: /// packUnorm3x10_1x2(xyz): round(clamp(c, 0, +1) * 1023.0) /// packUnorm3x10_1x2(w): round(clamp(c, 0, +1) * 3.0) /// /// The first vector component specifies the 10 least-significant bits of the result; /// the forth component specifies the 2 most-significant bits. /// /// @see gtc_packing /// @see vec4 unpackUnorm3x10_1x2(uint32 const& p) /// @see uint32 packUnorm3x10_1x2(vec4 const& v) /// @see uint32 packU3x10_1x2(uvec4 const& v) /// @see uint32 packI3x10_1x2(ivec4 const& v) GLM_FUNC_DECL uint32 packUnorm3x10_1x2(vec4 const& v); /// First, unpacks a single 32-bit unsigned integer p into four 16-bit signed integers. /// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector. /// /// The conversion for unpacked fixed-point value f to floating point is done as follows: /// unpackSnorm3x10_1x2(xyz): clamp(f / 1023.0, 0, +1) /// unpackSnorm3x10_1x2(w): clamp(f / 3.0, 0, +1) /// /// The first component of the returned vector will be extracted from the least significant bits of the input; /// the last component will be extracted from the most significant bits. /// /// @see gtc_packing /// @see uint32 packSnorm3x10_1x2(vec4 const& v) /// @see vec4 unpackInorm3x10_1x2(uint32 const& p)) /// @see uvec4 unpackI3x10_1x2(uint32 const& p) /// @see uvec4 unpackU3x10_1x2(uint32 const& p) GLM_FUNC_DECL vec4 unpackUnorm3x10_1x2(uint32 p); /// First, converts the first two components of the normalized floating-point value v into 11-bit signless floating-point values. /// Then, converts the third component of the normalized floating-point value v into a 10-bit signless floating-point value. /// Then, the results are packed into the returned 32-bit unsigned integer. /// /// The first vector component specifies the 11 least-significant bits of the result; /// the last component specifies the 10 most-significant bits. /// /// @see gtc_packing /// @see vec3 unpackF2x11_1x10(uint32 const& p) GLM_FUNC_DECL uint32 packF2x11_1x10(vec3 const& v); /// First, unpacks a single 32-bit unsigned integer p into two 11-bit signless floating-point values and one 10-bit signless floating-point value . /// Then, each component is converted to a normalized floating-point value to generate the returned three-component vector. /// /// The first component of the returned vector will be extracted from the least significant bits of the input; /// the last component will be extracted from the most significant bits. /// /// @see gtc_packing /// @see uint32 packF2x11_1x10(vec3 const& v) GLM_FUNC_DECL vec3 unpackF2x11_1x10(uint32 p); /// First, converts the first two components of the normalized floating-point value v into 11-bit signless floating-point values. /// Then, converts the third component of the normalized floating-point value v into a 10-bit signless floating-point value. /// Then, the results are packed into the returned 32-bit unsigned integer. /// /// The first vector component specifies the 11 least-significant bits of the result; /// the last component specifies the 10 most-significant bits. /// /// packF3x9_E1x5 allows encoding into RGBE / RGB9E5 format /// /// @see gtc_packing /// @see vec3 unpackF3x9_E1x5(uint32 const& p) GLM_FUNC_DECL uint32 packF3x9_E1x5(vec3 const& v); /// First, unpacks a single 32-bit unsigned integer p into two 11-bit signless floating-point values and one 10-bit signless floating-point value . /// Then, each component is converted to a normalized floating-point value to generate the returned three-component vector. /// /// The first component of the returned vector will be extracted from the least significant bits of the input; /// the last component will be extracted from the most significant bits. /// /// unpackF3x9_E1x5 allows decoding RGBE / RGB9E5 data /// /// @see gtc_packing /// @see uint32 packF3x9_E1x5(vec3 const& v) GLM_FUNC_DECL vec3 unpackF3x9_E1x5(uint32 p); /// Returns an unsigned integer vector obtained by converting the components of a floating-point vector /// to the 16-bit floating-point representation found in the OpenGL Specification. /// The first vector component specifies the 16 least-significant bits of the result; /// the forth component specifies the 16 most-significant bits. /// /// @see gtc_packing /// @see vec<3, T, Q> unpackRGBM(vec<4, T, Q> const& p) /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions template GLM_FUNC_DECL vec<4, T, Q> packRGBM(vec<3, T, Q> const& rgb); /// Returns a floating-point vector with components obtained by reinterpreting an integer vector as 16-bit floating-point numbers and converting them to 32-bit floating-point values. /// The first component of the vector is obtained from the 16 least-significant bits of v; /// the forth component is obtained from the 16 most-significant bits of v. /// /// @see gtc_packing /// @see vec<4, T, Q> packRGBM(vec<3, float, Q> const& v) /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions template GLM_FUNC_DECL vec<3, T, Q> unpackRGBM(vec<4, T, Q> const& rgbm); /// Returns an unsigned integer vector obtained by converting the components of a floating-point vector /// to the 16-bit floating-point representation found in the OpenGL Specification. /// The first vector component specifies the 16 least-significant bits of the result; /// the forth component specifies the 16 most-significant bits. /// /// @see gtc_packing /// @see vec unpackHalf(vec const& p) /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions template GLM_FUNC_DECL vec packHalf(vec const& v); /// Returns a floating-point vector with components obtained by reinterpreting an integer vector as 16-bit floating-point numbers and converting them to 32-bit floating-point values. /// The first component of the vector is obtained from the 16 least-significant bits of v; /// the forth component is obtained from the 16 most-significant bits of v. /// /// @see gtc_packing /// @see vec packHalf(vec const& v) /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions template GLM_FUNC_DECL vec unpackHalf(vec const& p); /// Convert each component of the normalized floating-point vector into unsigned integer values. /// /// @see gtc_packing /// @see vec unpackUnorm(vec const& p); template GLM_FUNC_DECL vec packUnorm(vec const& v); /// Convert a packed integer to a normalized floating-point vector. /// /// @see gtc_packing /// @see vec packUnorm(vec const& v) template GLM_FUNC_DECL vec unpackUnorm(vec const& v); /// Convert each component of the normalized floating-point vector into signed integer values. /// /// @see gtc_packing /// @see vec unpackSnorm(vec const& p); template GLM_FUNC_DECL vec packSnorm(vec const& v); /// Convert a packed integer to a normalized floating-point vector. /// /// @see gtc_packing /// @see vec packSnorm(vec const& v) template GLM_FUNC_DECL vec unpackSnorm(vec const& v); /// Convert each component of the normalized floating-point vector into unsigned integer values. /// /// @see gtc_packing /// @see vec2 unpackUnorm2x4(uint8 p) GLM_FUNC_DECL uint8 packUnorm2x4(vec2 const& v); /// Convert a packed integer to a normalized floating-point vector. /// /// @see gtc_packing /// @see uint8 packUnorm2x4(vec2 const& v) GLM_FUNC_DECL vec2 unpackUnorm2x4(uint8 p); /// Convert each component of the normalized floating-point vector into unsigned integer values. /// /// @see gtc_packing /// @see vec4 unpackUnorm4x4(uint16 p) GLM_FUNC_DECL uint16 packUnorm4x4(vec4 const& v); /// Convert a packed integer to a normalized floating-point vector. /// /// @see gtc_packing /// @see uint16 packUnorm4x4(vec4 const& v) GLM_FUNC_DECL vec4 unpackUnorm4x4(uint16 p); /// Convert each component of the normalized floating-point vector into unsigned integer values. /// /// @see gtc_packing /// @see vec3 unpackUnorm1x5_1x6_1x5(uint16 p) GLM_FUNC_DECL uint16 packUnorm1x5_1x6_1x5(vec3 const& v); /// Convert a packed integer to a normalized floating-point vector. /// /// @see gtc_packing /// @see uint16 packUnorm1x5_1x6_1x5(vec3 const& v) GLM_FUNC_DECL vec3 unpackUnorm1x5_1x6_1x5(uint16 p); /// Convert each component of the normalized floating-point vector into unsigned integer values. /// /// @see gtc_packing /// @see vec4 unpackUnorm3x5_1x1(uint16 p) GLM_FUNC_DECL uint16 packUnorm3x5_1x1(vec4 const& v); /// Convert a packed integer to a normalized floating-point vector. /// /// @see gtc_packing /// @see uint16 packUnorm3x5_1x1(vec4 const& v) GLM_FUNC_DECL vec4 unpackUnorm3x5_1x1(uint16 p); /// Convert each component of the normalized floating-point vector into unsigned integer values. /// /// @see gtc_packing /// @see vec3 unpackUnorm2x3_1x2(uint8 p) GLM_FUNC_DECL uint8 packUnorm2x3_1x2(vec3 const& v); /// Convert a packed integer to a normalized floating-point vector. /// /// @see gtc_packing /// @see uint8 packUnorm2x3_1x2(vec3 const& v) GLM_FUNC_DECL vec3 unpackUnorm2x3_1x2(uint8 p); /// Convert each component from an integer vector into a packed integer. /// /// @see gtc_packing /// @see i8vec2 unpackInt2x8(int16 p) GLM_FUNC_DECL int16 packInt2x8(i8vec2 const& v); /// Convert a packed integer into an integer vector. /// /// @see gtc_packing /// @see int16 packInt2x8(i8vec2 const& v) GLM_FUNC_DECL i8vec2 unpackInt2x8(int16 p); /// Convert each component from an integer vector into a packed unsigned integer. /// /// @see gtc_packing /// @see u8vec2 unpackInt2x8(uint16 p) GLM_FUNC_DECL uint16 packUint2x8(u8vec2 const& v); /// Convert a packed integer into an integer vector. /// /// @see gtc_packing /// @see uint16 packInt2x8(u8vec2 const& v) GLM_FUNC_DECL u8vec2 unpackUint2x8(uint16 p); /// Convert each component from an integer vector into a packed integer. /// /// @see gtc_packing /// @see i8vec4 unpackInt4x8(int32 p) GLM_FUNC_DECL int32 packInt4x8(i8vec4 const& v); /// Convert a packed integer into an integer vector. /// /// @see gtc_packing /// @see int32 packInt2x8(i8vec4 const& v) GLM_FUNC_DECL i8vec4 unpackInt4x8(int32 p); /// Convert each component from an integer vector into a packed unsigned integer. /// /// @see gtc_packing /// @see u8vec4 unpackUint4x8(uint32 p) GLM_FUNC_DECL uint32 packUint4x8(u8vec4 const& v); /// Convert a packed integer into an integer vector. /// /// @see gtc_packing /// @see uint32 packUint4x8(u8vec2 const& v) GLM_FUNC_DECL u8vec4 unpackUint4x8(uint32 p); /// Convert each component from an integer vector into a packed integer. /// /// @see gtc_packing /// @see i16vec2 unpackInt2x16(int p) GLM_FUNC_DECL int packInt2x16(i16vec2 const& v); /// Convert a packed integer into an integer vector. /// /// @see gtc_packing /// @see int packInt2x16(i16vec2 const& v) GLM_FUNC_DECL i16vec2 unpackInt2x16(int p); /// Convert each component from an integer vector into a packed integer. /// /// @see gtc_packing /// @see i16vec4 unpackInt4x16(int64 p) GLM_FUNC_DECL int64 packInt4x16(i16vec4 const& v); /// Convert a packed integer into an integer vector. /// /// @see gtc_packing /// @see int64 packInt4x16(i16vec4 const& v) GLM_FUNC_DECL i16vec4 unpackInt4x16(int64 p); /// Convert each component from an integer vector into a packed unsigned integer. /// /// @see gtc_packing /// @see u16vec2 unpackUint2x16(uint p) GLM_FUNC_DECL uint packUint2x16(u16vec2 const& v); /// Convert a packed integer into an integer vector. /// /// @see gtc_packing /// @see uint packUint2x16(u16vec2 const& v) GLM_FUNC_DECL u16vec2 unpackUint2x16(uint p); /// Convert each component from an integer vector into a packed unsigned integer. /// /// @see gtc_packing /// @see u16vec4 unpackUint4x16(uint64 p) GLM_FUNC_DECL uint64 packUint4x16(u16vec4 const& v); /// Convert a packed integer into an integer vector. /// /// @see gtc_packing /// @see uint64 packUint4x16(u16vec4 const& v) GLM_FUNC_DECL u16vec4 unpackUint4x16(uint64 p); /// Convert each component from an integer vector into a packed integer. /// /// @see gtc_packing /// @see i32vec2 unpackInt2x32(int p) GLM_FUNC_DECL int64 packInt2x32(i32vec2 const& v); /// Convert a packed integer into an integer vector. /// /// @see gtc_packing /// @see int packInt2x16(i32vec2 const& v) GLM_FUNC_DECL i32vec2 unpackInt2x32(int64 p); /// Convert each component from an integer vector into a packed unsigned integer. /// /// @see gtc_packing /// @see u32vec2 unpackUint2x32(int p) GLM_FUNC_DECL uint64 packUint2x32(u32vec2 const& v); /// Convert a packed integer into an integer vector. /// /// @see gtc_packing /// @see int packUint2x16(u32vec2 const& v) GLM_FUNC_DECL u32vec2 unpackUint2x32(uint64 p); /// @} }// namespace glm #include "packing.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtc/packing.inl000066400000000000000000000622351360521144700232220ustar00rootroot00000000000000/// @ref gtc_packing #include "../ext/scalar_relational.hpp" #include "../ext/vector_relational.hpp" #include "../common.hpp" #include "../vec2.hpp" #include "../vec3.hpp" #include "../vec4.hpp" #include "../detail/type_half.hpp" #include #include namespace glm{ namespace detail { GLM_FUNC_QUALIFIER glm::uint16 float2half(glm::uint32 f) { // 10 bits => EE EEEFFFFF // 11 bits => EEE EEFFFFFF // Half bits => SEEEEEFF FFFFFFFF // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF // 0x00007c00 => 00000000 00000000 01111100 00000000 // 0x000003ff => 00000000 00000000 00000011 11111111 // 0x38000000 => 00111000 00000000 00000000 00000000 // 0x7f800000 => 01111111 10000000 00000000 00000000 // 0x00008000 => 00000000 00000000 10000000 00000000 return ((f >> 16) & 0x8000) | // sign ((((f & 0x7f800000) - 0x38000000) >> 13) & 0x7c00) | // exponential ((f >> 13) & 0x03ff); // Mantissa } GLM_FUNC_QUALIFIER glm::uint32 float2packed11(glm::uint32 f) { // 10 bits => EE EEEFFFFF // 11 bits => EEE EEFFFFFF // Half bits => SEEEEEFF FFFFFFFF // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF // 0x000007c0 => 00000000 00000000 00000111 11000000 // 0x00007c00 => 00000000 00000000 01111100 00000000 // 0x000003ff => 00000000 00000000 00000011 11111111 // 0x38000000 => 00111000 00000000 00000000 00000000 // 0x7f800000 => 01111111 10000000 00000000 00000000 // 0x00008000 => 00000000 00000000 10000000 00000000 return ((((f & 0x7f800000) - 0x38000000) >> 17) & 0x07c0) | // exponential ((f >> 17) & 0x003f); // Mantissa } GLM_FUNC_QUALIFIER glm::uint32 packed11ToFloat(glm::uint32 p) { // 10 bits => EE EEEFFFFF // 11 bits => EEE EEFFFFFF // Half bits => SEEEEEFF FFFFFFFF // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF // 0x000007c0 => 00000000 00000000 00000111 11000000 // 0x00007c00 => 00000000 00000000 01111100 00000000 // 0x000003ff => 00000000 00000000 00000011 11111111 // 0x38000000 => 00111000 00000000 00000000 00000000 // 0x7f800000 => 01111111 10000000 00000000 00000000 // 0x00008000 => 00000000 00000000 10000000 00000000 return ((((p & 0x07c0) << 17) + 0x38000000) & 0x7f800000) | // exponential ((p & 0x003f) << 17); // Mantissa } GLM_FUNC_QUALIFIER glm::uint32 float2packed10(glm::uint32 f) { // 10 bits => EE EEEFFFFF // 11 bits => EEE EEFFFFFF // Half bits => SEEEEEFF FFFFFFFF // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF // 0x0000001F => 00000000 00000000 00000000 00011111 // 0x0000003F => 00000000 00000000 00000000 00111111 // 0x000003E0 => 00000000 00000000 00000011 11100000 // 0x000007C0 => 00000000 00000000 00000111 11000000 // 0x00007C00 => 00000000 00000000 01111100 00000000 // 0x000003FF => 00000000 00000000 00000011 11111111 // 0x38000000 => 00111000 00000000 00000000 00000000 // 0x7f800000 => 01111111 10000000 00000000 00000000 // 0x00008000 => 00000000 00000000 10000000 00000000 return ((((f & 0x7f800000) - 0x38000000) >> 18) & 0x03E0) | // exponential ((f >> 18) & 0x001f); // Mantissa } GLM_FUNC_QUALIFIER glm::uint32 packed10ToFloat(glm::uint32 p) { // 10 bits => EE EEEFFFFF // 11 bits => EEE EEFFFFFF // Half bits => SEEEEEFF FFFFFFFF // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF // 0x0000001F => 00000000 00000000 00000000 00011111 // 0x0000003F => 00000000 00000000 00000000 00111111 // 0x000003E0 => 00000000 00000000 00000011 11100000 // 0x000007C0 => 00000000 00000000 00000111 11000000 // 0x00007C00 => 00000000 00000000 01111100 00000000 // 0x000003FF => 00000000 00000000 00000011 11111111 // 0x38000000 => 00111000 00000000 00000000 00000000 // 0x7f800000 => 01111111 10000000 00000000 00000000 // 0x00008000 => 00000000 00000000 10000000 00000000 return ((((p & 0x03E0) << 18) + 0x38000000) & 0x7f800000) | // exponential ((p & 0x001f) << 18); // Mantissa } GLM_FUNC_QUALIFIER glm::uint half2float(glm::uint h) { return ((h & 0x8000) << 16) | ((( h & 0x7c00) + 0x1C000) << 13) | ((h & 0x03FF) << 13); } GLM_FUNC_QUALIFIER glm::uint floatTo11bit(float x) { if(x == 0.0f) return 0u; else if(glm::isnan(x)) return ~0u; else if(glm::isinf(x)) return 0x1Fu << 6u; uint Pack = 0u; memcpy(&Pack, &x, sizeof(Pack)); return float2packed11(Pack); } GLM_FUNC_QUALIFIER float packed11bitToFloat(glm::uint x) { if(x == 0) return 0.0f; else if(x == ((1 << 11) - 1)) return ~0;//NaN else if(x == (0x1f << 6)) return ~0;//Inf uint Result = packed11ToFloat(x); float Temp = 0; memcpy(&Temp, &Result, sizeof(Temp)); return Temp; } GLM_FUNC_QUALIFIER glm::uint floatTo10bit(float x) { if(x == 0.0f) return 0u; else if(glm::isnan(x)) return ~0u; else if(glm::isinf(x)) return 0x1Fu << 5u; uint Pack = 0; memcpy(&Pack, &x, sizeof(Pack)); return float2packed10(Pack); } GLM_FUNC_QUALIFIER float packed10bitToFloat(glm::uint x) { if(x == 0) return 0.0f; else if(x == ((1 << 10) - 1)) return ~0;//NaN else if(x == (0x1f << 5)) return ~0;//Inf uint Result = packed10ToFloat(x); float Temp = 0; memcpy(&Temp, &Result, sizeof(Temp)); return Temp; } // GLM_FUNC_QUALIFIER glm::uint f11_f11_f10(float x, float y, float z) // { // return ((floatTo11bit(x) & ((1 << 11) - 1)) << 0) | ((floatTo11bit(y) & ((1 << 11) - 1)) << 11) | ((floatTo10bit(z) & ((1 << 10) - 1)) << 22); // } union u3u3u2 { struct { uint x : 3; uint y : 3; uint z : 2; } data; uint8 pack; }; union u4u4 { struct { uint x : 4; uint y : 4; } data; uint8 pack; }; union u4u4u4u4 { struct { uint x : 4; uint y : 4; uint z : 4; uint w : 4; } data; uint16 pack; }; union u5u6u5 { struct { uint x : 5; uint y : 6; uint z : 5; } data; uint16 pack; }; union u5u5u5u1 { struct { uint x : 5; uint y : 5; uint z : 5; uint w : 1; } data; uint16 pack; }; union u10u10u10u2 { struct { uint x : 10; uint y : 10; uint z : 10; uint w : 2; } data; uint32 pack; }; union i10i10i10i2 { struct { int x : 10; int y : 10; int z : 10; int w : 2; } data; uint32 pack; }; union u9u9u9e5 { struct { uint x : 9; uint y : 9; uint z : 9; uint w : 5; } data; uint32 pack; }; template struct compute_half {}; template struct compute_half<1, Q> { GLM_FUNC_QUALIFIER static vec<1, uint16, Q> pack(vec<1, float, Q> const& v) { int16 const Unpack(detail::toFloat16(v.x)); u16vec1 Packed; memcpy(&Packed, &Unpack, sizeof(Packed)); return Packed; } GLM_FUNC_QUALIFIER static vec<1, float, Q> unpack(vec<1, uint16, Q> const& v) { i16vec1 Unpack; memcpy(&Unpack, &v, sizeof(Unpack)); return vec<1, float, Q>(detail::toFloat32(v.x)); } }; template struct compute_half<2, Q> { GLM_FUNC_QUALIFIER static vec<2, uint16, Q> pack(vec<2, float, Q> const& v) { vec<2, int16, Q> const Unpack(detail::toFloat16(v.x), detail::toFloat16(v.y)); u16vec2 Packed; memcpy(&Packed, &Unpack, sizeof(Packed)); return Packed; } GLM_FUNC_QUALIFIER static vec<2, float, Q> unpack(vec<2, uint16, Q> const& v) { i16vec2 Unpack; memcpy(&Unpack, &v, sizeof(Unpack)); return vec<2, float, Q>(detail::toFloat32(v.x), detail::toFloat32(v.y)); } }; template struct compute_half<3, Q> { GLM_FUNC_QUALIFIER static vec<3, uint16, Q> pack(vec<3, float, Q> const& v) { vec<3, int16, Q> const Unpack(detail::toFloat16(v.x), detail::toFloat16(v.y), detail::toFloat16(v.z)); u16vec3 Packed; memcpy(&Packed, &Unpack, sizeof(Packed)); return Packed; } GLM_FUNC_QUALIFIER static vec<3, float, Q> unpack(vec<3, uint16, Q> const& v) { i16vec3 Unpack; memcpy(&Unpack, &v, sizeof(Unpack)); return vec<3, float, Q>(detail::toFloat32(v.x), detail::toFloat32(v.y), detail::toFloat32(v.z)); } }; template struct compute_half<4, Q> { GLM_FUNC_QUALIFIER static vec<4, uint16, Q> pack(vec<4, float, Q> const& v) { vec<4, int16, Q> const Unpack(detail::toFloat16(v.x), detail::toFloat16(v.y), detail::toFloat16(v.z), detail::toFloat16(v.w)); u16vec4 Packed; memcpy(&Packed, &Unpack, sizeof(Packed)); return Packed; } GLM_FUNC_QUALIFIER static vec<4, float, Q> unpack(vec<4, uint16, Q> const& v) { i16vec4 Unpack; memcpy(&Unpack, &v, sizeof(Unpack)); return vec<4, float, Q>(detail::toFloat32(v.x), detail::toFloat32(v.y), detail::toFloat32(v.z), detail::toFloat32(v.w)); } }; }//namespace detail GLM_FUNC_QUALIFIER uint8 packUnorm1x8(float v) { return static_cast(round(clamp(v, 0.0f, 1.0f) * 255.0f)); } GLM_FUNC_QUALIFIER float unpackUnorm1x8(uint8 p) { float const Unpack(p); return Unpack * static_cast(0.0039215686274509803921568627451); // 1 / 255 } GLM_FUNC_QUALIFIER uint16 packUnorm2x8(vec2 const& v) { u8vec2 const Topack(round(clamp(v, 0.0f, 1.0f) * 255.0f)); uint16 Unpack = 0; memcpy(&Unpack, &Topack, sizeof(Unpack)); return Unpack; } GLM_FUNC_QUALIFIER vec2 unpackUnorm2x8(uint16 p) { u8vec2 Unpack; memcpy(&Unpack, &p, sizeof(Unpack)); return vec2(Unpack) * float(0.0039215686274509803921568627451); // 1 / 255 } GLM_FUNC_QUALIFIER uint8 packSnorm1x8(float v) { int8 const Topack(static_cast(round(clamp(v ,-1.0f, 1.0f) * 127.0f))); uint8 Packed = 0; memcpy(&Packed, &Topack, sizeof(Packed)); return Packed; } GLM_FUNC_QUALIFIER float unpackSnorm1x8(uint8 p) { int8 Unpack = 0; memcpy(&Unpack, &p, sizeof(Unpack)); return clamp( static_cast(Unpack) * 0.00787401574803149606299212598425f, // 1.0f / 127.0f -1.0f, 1.0f); } GLM_FUNC_QUALIFIER uint16 packSnorm2x8(vec2 const& v) { i8vec2 const Topack(round(clamp(v, -1.0f, 1.0f) * 127.0f)); uint16 Packed = 0; memcpy(&Packed, &Topack, sizeof(Packed)); return Packed; } GLM_FUNC_QUALIFIER vec2 unpackSnorm2x8(uint16 p) { i8vec2 Unpack; memcpy(&Unpack, &p, sizeof(Unpack)); return clamp( vec2(Unpack) * 0.00787401574803149606299212598425f, // 1.0f / 127.0f -1.0f, 1.0f); } GLM_FUNC_QUALIFIER uint16 packUnorm1x16(float s) { return static_cast(round(clamp(s, 0.0f, 1.0f) * 65535.0f)); } GLM_FUNC_QUALIFIER float unpackUnorm1x16(uint16 p) { float const Unpack(p); return Unpack * 1.5259021896696421759365224689097e-5f; // 1.0 / 65535.0 } GLM_FUNC_QUALIFIER uint64 packUnorm4x16(vec4 const& v) { u16vec4 const Topack(round(clamp(v , 0.0f, 1.0f) * 65535.0f)); uint64 Packed = 0; memcpy(&Packed, &Topack, sizeof(Packed)); return Packed; } GLM_FUNC_QUALIFIER vec4 unpackUnorm4x16(uint64 p) { u16vec4 Unpack; memcpy(&Unpack, &p, sizeof(Unpack)); return vec4(Unpack) * 1.5259021896696421759365224689097e-5f; // 1.0 / 65535.0 } GLM_FUNC_QUALIFIER uint16 packSnorm1x16(float v) { int16 const Topack = static_cast(round(clamp(v ,-1.0f, 1.0f) * 32767.0f)); uint16 Packed = 0; memcpy(&Packed, &Topack, sizeof(Packed)); return Packed; } GLM_FUNC_QUALIFIER float unpackSnorm1x16(uint16 p) { int16 Unpack = 0; memcpy(&Unpack, &p, sizeof(Unpack)); return clamp( static_cast(Unpack) * 3.0518509475997192297128208258309e-5f, //1.0f / 32767.0f, -1.0f, 1.0f); } GLM_FUNC_QUALIFIER uint64 packSnorm4x16(vec4 const& v) { i16vec4 const Topack(round(clamp(v ,-1.0f, 1.0f) * 32767.0f)); uint64 Packed = 0; memcpy(&Packed, &Topack, sizeof(Packed)); return Packed; } GLM_FUNC_QUALIFIER vec4 unpackSnorm4x16(uint64 p) { i16vec4 Unpack; memcpy(&Unpack, &p, sizeof(Unpack)); return clamp( vec4(Unpack) * 3.0518509475997192297128208258309e-5f, //1.0f / 32767.0f, -1.0f, 1.0f); } GLM_FUNC_QUALIFIER uint16 packHalf1x16(float v) { int16 const Topack(detail::toFloat16(v)); uint16 Packed = 0; memcpy(&Packed, &Topack, sizeof(Packed)); return Packed; } GLM_FUNC_QUALIFIER float unpackHalf1x16(uint16 v) { int16 Unpack = 0; memcpy(&Unpack, &v, sizeof(Unpack)); return detail::toFloat32(Unpack); } GLM_FUNC_QUALIFIER uint64 packHalf4x16(glm::vec4 const& v) { i16vec4 const Unpack( detail::toFloat16(v.x), detail::toFloat16(v.y), detail::toFloat16(v.z), detail::toFloat16(v.w)); uint64 Packed = 0; memcpy(&Packed, &Unpack, sizeof(Packed)); return Packed; } GLM_FUNC_QUALIFIER glm::vec4 unpackHalf4x16(uint64 v) { i16vec4 Unpack; memcpy(&Unpack, &v, sizeof(Unpack)); return vec4( detail::toFloat32(Unpack.x), detail::toFloat32(Unpack.y), detail::toFloat32(Unpack.z), detail::toFloat32(Unpack.w)); } GLM_FUNC_QUALIFIER uint32 packI3x10_1x2(ivec4 const& v) { detail::i10i10i10i2 Result; Result.data.x = v.x; Result.data.y = v.y; Result.data.z = v.z; Result.data.w = v.w; return Result.pack; } GLM_FUNC_QUALIFIER ivec4 unpackI3x10_1x2(uint32 v) { detail::i10i10i10i2 Unpack; Unpack.pack = v; return ivec4( Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w); } GLM_FUNC_QUALIFIER uint32 packU3x10_1x2(uvec4 const& v) { detail::u10u10u10u2 Result; Result.data.x = v.x; Result.data.y = v.y; Result.data.z = v.z; Result.data.w = v.w; return Result.pack; } GLM_FUNC_QUALIFIER uvec4 unpackU3x10_1x2(uint32 v) { detail::u10u10u10u2 Unpack; Unpack.pack = v; return uvec4( Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w); } GLM_FUNC_QUALIFIER uint32 packSnorm3x10_1x2(vec4 const& v) { ivec4 const Pack(round(clamp(v,-1.0f, 1.0f) * vec4(511.f, 511.f, 511.f, 1.f))); detail::i10i10i10i2 Result; Result.data.x = Pack.x; Result.data.y = Pack.y; Result.data.z = Pack.z; Result.data.w = Pack.w; return Result.pack; } GLM_FUNC_QUALIFIER vec4 unpackSnorm3x10_1x2(uint32 v) { detail::i10i10i10i2 Unpack; Unpack.pack = v; vec4 const Result(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w); return clamp(Result * vec4(1.f / 511.f, 1.f / 511.f, 1.f / 511.f, 1.f), -1.0f, 1.0f); } GLM_FUNC_QUALIFIER uint32 packUnorm3x10_1x2(vec4 const& v) { uvec4 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec4(1023.f, 1023.f, 1023.f, 3.f))); detail::u10u10u10u2 Result; Result.data.x = Unpack.x; Result.data.y = Unpack.y; Result.data.z = Unpack.z; Result.data.w = Unpack.w; return Result.pack; } GLM_FUNC_QUALIFIER vec4 unpackUnorm3x10_1x2(uint32 v) { vec4 const ScaleFactors(1.0f / 1023.f, 1.0f / 1023.f, 1.0f / 1023.f, 1.0f / 3.f); detail::u10u10u10u2 Unpack; Unpack.pack = v; return vec4(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w) * ScaleFactors; } GLM_FUNC_QUALIFIER uint32 packF2x11_1x10(vec3 const& v) { return ((detail::floatTo11bit(v.x) & ((1 << 11) - 1)) << 0) | ((detail::floatTo11bit(v.y) & ((1 << 11) - 1)) << 11) | ((detail::floatTo10bit(v.z) & ((1 << 10) - 1)) << 22); } GLM_FUNC_QUALIFIER vec3 unpackF2x11_1x10(uint32 v) { return vec3( detail::packed11bitToFloat(v >> 0), detail::packed11bitToFloat(v >> 11), detail::packed10bitToFloat(v >> 22)); } GLM_FUNC_QUALIFIER uint32 packF3x9_E1x5(vec3 const& v) { float const SharedExpMax = (pow(2.0f, 9.0f - 1.0f) / pow(2.0f, 9.0f)) * pow(2.0f, 31.f - 15.f); vec3 const Color = clamp(v, 0.0f, SharedExpMax); float const MaxColor = max(Color.x, max(Color.y, Color.z)); float const ExpSharedP = max(-15.f - 1.f, floor(log2(MaxColor))) + 1.0f + 15.f; float const MaxShared = floor(MaxColor / pow(2.0f, (ExpSharedP - 15.f - 9.f)) + 0.5f); float const ExpShared = equal(MaxShared, pow(2.0f, 9.0f), epsilon()) ? ExpSharedP + 1.0f : ExpSharedP; uvec3 const ColorComp(floor(Color / pow(2.f, (ExpShared - 15.f - 9.f)) + 0.5f)); detail::u9u9u9e5 Unpack; Unpack.data.x = ColorComp.x; Unpack.data.y = ColorComp.y; Unpack.data.z = ColorComp.z; Unpack.data.w = uint(ExpShared); return Unpack.pack; } GLM_FUNC_QUALIFIER vec3 unpackF3x9_E1x5(uint32 v) { detail::u9u9u9e5 Unpack; Unpack.pack = v; return vec3(Unpack.data.x, Unpack.data.y, Unpack.data.z) * pow(2.0f, Unpack.data.w - 15.f - 9.f); } // Based on Brian Karis http://graphicrants.blogspot.fr/2009/04/rgbm-color-encoding.html template GLM_FUNC_QUALIFIER vec<4, T, Q> packRGBM(vec<3, T, Q> const& rgb) { vec<3, T, Q> const Color(rgb * static_cast(1.0 / 6.0)); T Alpha = clamp(max(max(Color.x, Color.y), max(Color.z, static_cast(1e-6))), static_cast(0), static_cast(1)); Alpha = ceil(Alpha * static_cast(255.0)) / static_cast(255.0); return vec<4, T, Q>(Color / Alpha, Alpha); } template GLM_FUNC_QUALIFIER vec<3, T, Q> unpackRGBM(vec<4, T, Q> const& rgbm) { return vec<3, T, Q>(rgbm.x, rgbm.y, rgbm.z) * rgbm.w * static_cast(6); } template GLM_FUNC_QUALIFIER vec packHalf(vec const& v) { return detail::compute_half::pack(v); } template GLM_FUNC_QUALIFIER vec unpackHalf(vec const& v) { return detail::compute_half::unpack(v); } template GLM_FUNC_QUALIFIER vec packUnorm(vec const& v) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "uintType must be an integer type"); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "floatType must be a floating point type"); return vec(round(clamp(v, static_cast(0), static_cast(1)) * static_cast(std::numeric_limits::max()))); } template GLM_FUNC_QUALIFIER vec unpackUnorm(vec const& v) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "uintType must be an integer type"); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "floatType must be a floating point type"); return vec(v) * (static_cast(1) / static_cast(std::numeric_limits::max())); } template GLM_FUNC_QUALIFIER vec packSnorm(vec const& v) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "uintType must be an integer type"); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "floatType must be a floating point type"); return vec(round(clamp(v , static_cast(-1), static_cast(1)) * static_cast(std::numeric_limits::max()))); } template GLM_FUNC_QUALIFIER vec unpackSnorm(vec const& v) { GLM_STATIC_ASSERT(std::numeric_limits::is_integer, "uintType must be an integer type"); GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "floatType must be a floating point type"); return clamp(vec(v) * (static_cast(1) / static_cast(std::numeric_limits::max())), static_cast(-1), static_cast(1)); } GLM_FUNC_QUALIFIER uint8 packUnorm2x4(vec2 const& v) { u32vec2 const Unpack(round(clamp(v, 0.0f, 1.0f) * 15.0f)); detail::u4u4 Result; Result.data.x = Unpack.x; Result.data.y = Unpack.y; return Result.pack; } GLM_FUNC_QUALIFIER vec2 unpackUnorm2x4(uint8 v) { float const ScaleFactor(1.f / 15.f); detail::u4u4 Unpack; Unpack.pack = v; return vec2(Unpack.data.x, Unpack.data.y) * ScaleFactor; } GLM_FUNC_QUALIFIER uint16 packUnorm4x4(vec4 const& v) { u32vec4 const Unpack(round(clamp(v, 0.0f, 1.0f) * 15.0f)); detail::u4u4u4u4 Result; Result.data.x = Unpack.x; Result.data.y = Unpack.y; Result.data.z = Unpack.z; Result.data.w = Unpack.w; return Result.pack; } GLM_FUNC_QUALIFIER vec4 unpackUnorm4x4(uint16 v) { float const ScaleFactor(1.f / 15.f); detail::u4u4u4u4 Unpack; Unpack.pack = v; return vec4(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w) * ScaleFactor; } GLM_FUNC_QUALIFIER uint16 packUnorm1x5_1x6_1x5(vec3 const& v) { u32vec3 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec3(31.f, 63.f, 31.f))); detail::u5u6u5 Result; Result.data.x = Unpack.x; Result.data.y = Unpack.y; Result.data.z = Unpack.z; return Result.pack; } GLM_FUNC_QUALIFIER vec3 unpackUnorm1x5_1x6_1x5(uint16 v) { vec3 const ScaleFactor(1.f / 31.f, 1.f / 63.f, 1.f / 31.f); detail::u5u6u5 Unpack; Unpack.pack = v; return vec3(Unpack.data.x, Unpack.data.y, Unpack.data.z) * ScaleFactor; } GLM_FUNC_QUALIFIER uint16 packUnorm3x5_1x1(vec4 const& v) { u32vec4 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec4(31.f, 31.f, 31.f, 1.f))); detail::u5u5u5u1 Result; Result.data.x = Unpack.x; Result.data.y = Unpack.y; Result.data.z = Unpack.z; Result.data.w = Unpack.w; return Result.pack; } GLM_FUNC_QUALIFIER vec4 unpackUnorm3x5_1x1(uint16 v) { vec4 const ScaleFactor(1.f / 31.f, 1.f / 31.f, 1.f / 31.f, 1.f); detail::u5u5u5u1 Unpack; Unpack.pack = v; return vec4(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w) * ScaleFactor; } GLM_FUNC_QUALIFIER uint8 packUnorm2x3_1x2(vec3 const& v) { u32vec3 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec3(7.f, 7.f, 3.f))); detail::u3u3u2 Result; Result.data.x = Unpack.x; Result.data.y = Unpack.y; Result.data.z = Unpack.z; return Result.pack; } GLM_FUNC_QUALIFIER vec3 unpackUnorm2x3_1x2(uint8 v) { vec3 const ScaleFactor(1.f / 7.f, 1.f / 7.f, 1.f / 3.f); detail::u3u3u2 Unpack; Unpack.pack = v; return vec3(Unpack.data.x, Unpack.data.y, Unpack.data.z) * ScaleFactor; } GLM_FUNC_QUALIFIER int16 packInt2x8(i8vec2 const& v) { int16 Pack = 0; memcpy(&Pack, &v, sizeof(Pack)); return Pack; } GLM_FUNC_QUALIFIER i8vec2 unpackInt2x8(int16 p) { i8vec2 Unpack; memcpy(&Unpack, &p, sizeof(Unpack)); return Unpack; } GLM_FUNC_QUALIFIER uint16 packUint2x8(u8vec2 const& v) { uint16 Pack = 0; memcpy(&Pack, &v, sizeof(Pack)); return Pack; } GLM_FUNC_QUALIFIER u8vec2 unpackUint2x8(uint16 p) { u8vec2 Unpack; memcpy(&Unpack, &p, sizeof(Unpack)); return Unpack; } GLM_FUNC_QUALIFIER int32 packInt4x8(i8vec4 const& v) { int32 Pack = 0; memcpy(&Pack, &v, sizeof(Pack)); return Pack; } GLM_FUNC_QUALIFIER i8vec4 unpackInt4x8(int32 p) { i8vec4 Unpack; memcpy(&Unpack, &p, sizeof(Unpack)); return Unpack; } GLM_FUNC_QUALIFIER uint32 packUint4x8(u8vec4 const& v) { uint32 Pack = 0; memcpy(&Pack, &v, sizeof(Pack)); return Pack; } GLM_FUNC_QUALIFIER u8vec4 unpackUint4x8(uint32 p) { u8vec4 Unpack; memcpy(&Unpack, &p, sizeof(Unpack)); return Unpack; } GLM_FUNC_QUALIFIER int packInt2x16(i16vec2 const& v) { int Pack = 0; memcpy(&Pack, &v, sizeof(Pack)); return Pack; } GLM_FUNC_QUALIFIER i16vec2 unpackInt2x16(int p) { i16vec2 Unpack; memcpy(&Unpack, &p, sizeof(Unpack)); return Unpack; } GLM_FUNC_QUALIFIER int64 packInt4x16(i16vec4 const& v) { int64 Pack = 0; memcpy(&Pack, &v, sizeof(Pack)); return Pack; } GLM_FUNC_QUALIFIER i16vec4 unpackInt4x16(int64 p) { i16vec4 Unpack; memcpy(&Unpack, &p, sizeof(Unpack)); return Unpack; } GLM_FUNC_QUALIFIER uint packUint2x16(u16vec2 const& v) { uint Pack = 0; memcpy(&Pack, &v, sizeof(Pack)); return Pack; } GLM_FUNC_QUALIFIER u16vec2 unpackUint2x16(uint p) { u16vec2 Unpack; memcpy(&Unpack, &p, sizeof(Unpack)); return Unpack; } GLM_FUNC_QUALIFIER uint64 packUint4x16(u16vec4 const& v) { uint64 Pack = 0; memcpy(&Pack, &v, sizeof(Pack)); return Pack; } GLM_FUNC_QUALIFIER u16vec4 unpackUint4x16(uint64 p) { u16vec4 Unpack; memcpy(&Unpack, &p, sizeof(Unpack)); return Unpack; } GLM_FUNC_QUALIFIER int64 packInt2x32(i32vec2 const& v) { int64 Pack = 0; memcpy(&Pack, &v, sizeof(Pack)); return Pack; } GLM_FUNC_QUALIFIER i32vec2 unpackInt2x32(int64 p) { i32vec2 Unpack; memcpy(&Unpack, &p, sizeof(Unpack)); return Unpack; } GLM_FUNC_QUALIFIER uint64 packUint2x32(u32vec2 const& v) { uint64 Pack = 0; memcpy(&Pack, &v, sizeof(Pack)); return Pack; } GLM_FUNC_QUALIFIER u32vec2 unpackUint2x32(uint64 p) { u32vec2 Unpack; memcpy(&Unpack, &p, sizeof(Unpack)); return Unpack; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtc/quaternion.hpp000066400000000000000000000130061360521144700237700ustar00rootroot00000000000000/// @ref gtc_quaternion /// @file glm/gtc/quaternion.hpp /// /// @see core (dependence) /// @see gtc_constants (dependence) /// /// @defgroup gtc_quaternion GLM_GTC_quaternion /// @ingroup gtc /// /// Include to use the features of this extension. /// /// Defines a templated quaternion type and several quaternion operations. #pragma once // Dependency: #include "../gtc/constants.hpp" #include "../gtc/matrix_transform.hpp" #include "../ext/vector_relational.hpp" #include "../ext/quaternion_common.hpp" #include "../ext/quaternion_float.hpp" #include "../ext/quaternion_float_precision.hpp" #include "../ext/quaternion_double.hpp" #include "../ext/quaternion_double_precision.hpp" #include "../ext/quaternion_relational.hpp" #include "../ext/quaternion_geometric.hpp" #include "../ext/quaternion_trigonometric.hpp" #include "../ext/quaternion_transform.hpp" #include "../detail/type_mat3x3.hpp" #include "../detail/type_mat4x4.hpp" #include "../detail/type_vec3.hpp" #include "../detail/type_vec4.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_GTC_quaternion extension included") #endif namespace glm { /// @addtogroup gtc_quaternion /// @{ /// Returns euler angles, pitch as x, yaw as y, roll as z. /// The result is expressed in radians. /// /// @tparam T Floating-point scalar types. /// /// @see gtc_quaternion template GLM_FUNC_DECL vec<3, T, Q> eulerAngles(qua const& x); /// Returns roll value of euler angles expressed in radians. /// /// @tparam T Floating-point scalar types. /// /// @see gtc_quaternion template GLM_FUNC_DECL T roll(qua const& x); /// Returns pitch value of euler angles expressed in radians. /// /// @tparam T Floating-point scalar types. /// /// @see gtc_quaternion template GLM_FUNC_DECL T pitch(qua const& x); /// Returns yaw value of euler angles expressed in radians. /// /// @tparam T Floating-point scalar types. /// /// @see gtc_quaternion template GLM_FUNC_DECL T yaw(qua const& x); /// Converts a quaternion to a 3 * 3 matrix. /// /// @tparam T Floating-point scalar types. /// /// @see gtc_quaternion template GLM_FUNC_DECL mat<3, 3, T, Q> mat3_cast(qua const& x); /// Converts a quaternion to a 4 * 4 matrix. /// /// @tparam T Floating-point scalar types. /// /// @see gtc_quaternion template GLM_FUNC_DECL mat<4, 4, T, Q> mat4_cast(qua const& x); /// Converts a pure rotation 3 * 3 matrix to a quaternion. /// /// @tparam T Floating-point scalar types. /// /// @see gtc_quaternion template GLM_FUNC_DECL qua quat_cast(mat<3, 3, T, Q> const& x); /// Converts a pure rotation 4 * 4 matrix to a quaternion. /// /// @tparam T Floating-point scalar types. /// /// @see gtc_quaternion template GLM_FUNC_DECL qua quat_cast(mat<4, 4, T, Q> const& x); /// Returns the component-wise comparison result of x < y. /// /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see ext_quaternion_relational template GLM_FUNC_DECL vec<4, bool, Q> lessThan(qua const& x, qua const& y); /// Returns the component-wise comparison of result x <= y. /// /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see ext_quaternion_relational template GLM_FUNC_DECL vec<4, bool, Q> lessThanEqual(qua const& x, qua const& y); /// Returns the component-wise comparison of result x > y. /// /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see ext_quaternion_relational template GLM_FUNC_DECL vec<4, bool, Q> greaterThan(qua const& x, qua const& y); /// Returns the component-wise comparison of result x >= y. /// /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see ext_quaternion_relational template GLM_FUNC_DECL vec<4, bool, Q> greaterThanEqual(qua const& x, qua const& y); /// Build a look at quaternion based on the default handedness. /// /// @param direction Desired forward direction. Needs to be normalized. /// @param up Up vector, how the camera is oriented. Typically (0, 1, 0). template GLM_FUNC_DECL qua quatLookAt( vec<3, T, Q> const& direction, vec<3, T, Q> const& up); /// Build a right-handed look at quaternion. /// /// @param direction Desired forward direction onto which the -z-axis gets mapped. Needs to be normalized. /// @param up Up vector, how the camera is oriented. Typically (0, 1, 0). template GLM_FUNC_DECL qua quatLookAtRH( vec<3, T, Q> const& direction, vec<3, T, Q> const& up); /// Build a left-handed look at quaternion. /// /// @param direction Desired forward direction onto which the +z-axis gets mapped. Needs to be normalized. /// @param up Up vector, how the camera is oriented. Typically (0, 1, 0). template GLM_FUNC_DECL qua quatLookAtLH( vec<3, T, Q> const& direction, vec<3, T, Q> const& up); /// @} } //namespace glm #include "quaternion.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtc/quaternion.inl000066400000000000000000000136531360521144700237730ustar00rootroot00000000000000#include "../trigonometric.hpp" #include "../geometric.hpp" #include "../exponential.hpp" #include "epsilon.hpp" #include namespace glm { template GLM_FUNC_QUALIFIER vec<3, T, Q> eulerAngles(qua const& x) { return vec<3, T, Q>(pitch(x), yaw(x), roll(x)); } template GLM_FUNC_QUALIFIER T roll(qua const& q) { return static_cast(atan(static_cast(2) * (q.x * q.y + q.w * q.z), q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z)); } template GLM_FUNC_QUALIFIER T pitch(qua const& q) { //return T(atan(T(2) * (q.y * q.z + q.w * q.x), q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z)); T const y = static_cast(2) * (q.y * q.z + q.w * q.x); T const x = q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z; if(all(equal(vec<2, T, Q>(x, y), vec<2, T, Q>(0), epsilon()))) //avoid atan2(0,0) - handle singularity - Matiis return static_cast(static_cast(2) * atan(q.x, q.w)); return static_cast(atan(y, x)); } template GLM_FUNC_QUALIFIER T yaw(qua const& q) { return asin(clamp(static_cast(-2) * (q.x * q.z - q.w * q.y), static_cast(-1), static_cast(1))); } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> mat3_cast(qua const& q) { mat<3, 3, T, Q> Result(T(1)); T qxx(q.x * q.x); T qyy(q.y * q.y); T qzz(q.z * q.z); T qxz(q.x * q.z); T qxy(q.x * q.y); T qyz(q.y * q.z); T qwx(q.w * q.x); T qwy(q.w * q.y); T qwz(q.w * q.z); Result[0][0] = T(1) - T(2) * (qyy + qzz); Result[0][1] = T(2) * (qxy + qwz); Result[0][2] = T(2) * (qxz - qwy); Result[1][0] = T(2) * (qxy - qwz); Result[1][1] = T(1) - T(2) * (qxx + qzz); Result[1][2] = T(2) * (qyz + qwx); Result[2][0] = T(2) * (qxz + qwy); Result[2][1] = T(2) * (qyz - qwx); Result[2][2] = T(1) - T(2) * (qxx + qyy); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> mat4_cast(qua const& q) { return mat<4, 4, T, Q>(mat3_cast(q)); } template GLM_FUNC_QUALIFIER qua quat_cast(mat<3, 3, T, Q> const& m) { T fourXSquaredMinus1 = m[0][0] - m[1][1] - m[2][2]; T fourYSquaredMinus1 = m[1][1] - m[0][0] - m[2][2]; T fourZSquaredMinus1 = m[2][2] - m[0][0] - m[1][1]; T fourWSquaredMinus1 = m[0][0] + m[1][1] + m[2][2]; int biggestIndex = 0; T fourBiggestSquaredMinus1 = fourWSquaredMinus1; if(fourXSquaredMinus1 > fourBiggestSquaredMinus1) { fourBiggestSquaredMinus1 = fourXSquaredMinus1; biggestIndex = 1; } if(fourYSquaredMinus1 > fourBiggestSquaredMinus1) { fourBiggestSquaredMinus1 = fourYSquaredMinus1; biggestIndex = 2; } if(fourZSquaredMinus1 > fourBiggestSquaredMinus1) { fourBiggestSquaredMinus1 = fourZSquaredMinus1; biggestIndex = 3; } T biggestVal = sqrt(fourBiggestSquaredMinus1 + static_cast(1)) * static_cast(0.5); T mult = static_cast(0.25) / biggestVal; switch(biggestIndex) { case 0: return qua(biggestVal, (m[1][2] - m[2][1]) * mult, (m[2][0] - m[0][2]) * mult, (m[0][1] - m[1][0]) * mult); case 1: return qua((m[1][2] - m[2][1]) * mult, biggestVal, (m[0][1] + m[1][0]) * mult, (m[2][0] + m[0][2]) * mult); case 2: return qua((m[2][0] - m[0][2]) * mult, (m[0][1] + m[1][0]) * mult, biggestVal, (m[1][2] + m[2][1]) * mult); case 3: return qua((m[0][1] - m[1][0]) * mult, (m[2][0] + m[0][2]) * mult, (m[1][2] + m[2][1]) * mult, biggestVal); default: // Silence a -Wswitch-default warning in GCC. Should never actually get here. Assert is just for sanity. assert(false); return qua(1, 0, 0, 0); } } template GLM_FUNC_QUALIFIER qua quat_cast(mat<4, 4, T, Q> const& m4) { return quat_cast(mat<3, 3, T, Q>(m4)); } template GLM_FUNC_QUALIFIER vec<4, bool, Q> lessThan(qua const& x, qua const& y) { vec<4, bool, Q> Result; for(length_t i = 0; i < x.length(); ++i) Result[i] = x[i] < y[i]; return Result; } template GLM_FUNC_QUALIFIER vec<4, bool, Q> lessThanEqual(qua const& x, qua const& y) { vec<4, bool, Q> Result; for(length_t i = 0; i < x.length(); ++i) Result[i] = x[i] <= y[i]; return Result; } template GLM_FUNC_QUALIFIER vec<4, bool, Q> greaterThan(qua const& x, qua const& y) { vec<4, bool, Q> Result; for(length_t i = 0; i < x.length(); ++i) Result[i] = x[i] > y[i]; return Result; } template GLM_FUNC_QUALIFIER vec<4, bool, Q> greaterThanEqual(qua const& x, qua const& y) { vec<4, bool, Q> Result; for(length_t i = 0; i < x.length(); ++i) Result[i] = x[i] >= y[i]; return Result; } template GLM_FUNC_QUALIFIER qua quatLookAt(vec<3, T, Q> const& direction, vec<3, T, Q> const& up) { # if GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT return quatLookAtLH(direction, up); # else return quatLookAtRH(direction, up); # endif } template GLM_FUNC_QUALIFIER qua quatLookAtRH(vec<3, T, Q> const& direction, vec<3, T, Q> const& up) { mat<3, 3, T, Q> Result; Result[2] = -direction; Result[0] = normalize(cross(up, Result[2])); Result[1] = cross(Result[2], Result[0]); return quat_cast(Result); } template GLM_FUNC_QUALIFIER qua quatLookAtLH(vec<3, T, Q> const& direction, vec<3, T, Q> const& up) { mat<3, 3, T, Q> Result; Result[2] = direction; Result[0] = normalize(cross(up, Result[2])); Result[1] = cross(Result[2], Result[0]); return quat_cast(Result); } }//namespace glm #if GLM_CONFIG_SIMD == GLM_ENABLE # include "quaternion_simd.inl" #endif connectome-workbench-1.4.2/src/GLMath/glm/gtc/quaternion_simd.inl000066400000000000000000000000001360521144700247650ustar00rootroot00000000000000connectome-workbench-1.4.2/src/GLMath/glm/gtc/random.hpp000066400000000000000000000052011360521144700230610ustar00rootroot00000000000000/// @ref gtc_random /// @file glm/gtc/random.hpp /// /// @see core (dependence) /// @see gtx_random (extended) /// /// @defgroup gtc_random GLM_GTC_random /// @ingroup gtc /// /// Include to use the features of this extension. /// /// Generate random number from various distribution methods. #pragma once // Dependency: #include "../ext/scalar_int_sized.hpp" #include "../ext/scalar_uint_sized.hpp" #include "../detail/qualifier.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_GTC_random extension included") #endif namespace glm { /// @addtogroup gtc_random /// @{ /// Generate random numbers in the interval [Min, Max], according a linear distribution /// /// @param Min Minimum value included in the sampling /// @param Max Maximum value included in the sampling /// @tparam genType Value type. Currently supported: float or double scalars. /// @see gtc_random template GLM_FUNC_DECL genType linearRand(genType Min, genType Max); /// Generate random numbers in the interval [Min, Max], according a linear distribution /// /// @param Min Minimum value included in the sampling /// @param Max Maximum value included in the sampling /// @tparam T Value type. Currently supported: float or double. /// /// @see gtc_random template GLM_FUNC_DECL vec linearRand(vec const& Min, vec const& Max); /// Generate random numbers in the interval [Min, Max], according a gaussian distribution /// /// @see gtc_random template GLM_FUNC_DECL genType gaussRand(genType Mean, genType Deviation); /// Generate a random 2D vector which coordinates are regulary distributed on a circle of a given radius /// /// @see gtc_random template GLM_FUNC_DECL vec<2, T, defaultp> circularRand(T Radius); /// Generate a random 3D vector which coordinates are regulary distributed on a sphere of a given radius /// /// @see gtc_random template GLM_FUNC_DECL vec<3, T, defaultp> sphericalRand(T Radius); /// Generate a random 2D vector which coordinates are regulary distributed within the area of a disk of a given radius /// /// @see gtc_random template GLM_FUNC_DECL vec<2, T, defaultp> diskRand(T Radius); /// Generate a random 3D vector which coordinates are regulary distributed within the volume of a ball of a given radius /// /// @see gtc_random template GLM_FUNC_DECL vec<3, T, defaultp> ballRand(T Radius); /// @} }//namespace glm #include "random.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtc/random.inl000066400000000000000000000214541360521144700230640ustar00rootroot00000000000000#include "../geometric.hpp" #include "../exponential.hpp" #include "../trigonometric.hpp" #include "../detail/type_vec1.hpp" #include #include #include #include namespace glm{ namespace detail { template struct compute_rand { GLM_FUNC_QUALIFIER static vec call(); }; template struct compute_rand<1, uint8, P> { GLM_FUNC_QUALIFIER static vec<1, uint8, P> call() { return vec<1, uint8, P>( std::rand() % std::numeric_limits::max()); } }; template struct compute_rand<2, uint8, P> { GLM_FUNC_QUALIFIER static vec<2, uint8, P> call() { return vec<2, uint8, P>( std::rand() % std::numeric_limits::max(), std::rand() % std::numeric_limits::max()); } }; template struct compute_rand<3, uint8, P> { GLM_FUNC_QUALIFIER static vec<3, uint8, P> call() { return vec<3, uint8, P>( std::rand() % std::numeric_limits::max(), std::rand() % std::numeric_limits::max(), std::rand() % std::numeric_limits::max()); } }; template struct compute_rand<4, uint8, P> { GLM_FUNC_QUALIFIER static vec<4, uint8, P> call() { return vec<4, uint8, P>( std::rand() % std::numeric_limits::max(), std::rand() % std::numeric_limits::max(), std::rand() % std::numeric_limits::max(), std::rand() % std::numeric_limits::max()); } }; template struct compute_rand { GLM_FUNC_QUALIFIER static vec call() { return (vec(compute_rand::call()) << static_cast(8)) | (vec(compute_rand::call()) << static_cast(0)); } }; template struct compute_rand { GLM_FUNC_QUALIFIER static vec call() { return (vec(compute_rand::call()) << static_cast(16)) | (vec(compute_rand::call()) << static_cast(0)); } }; template struct compute_rand { GLM_FUNC_QUALIFIER static vec call() { return (vec(compute_rand::call()) << static_cast(32)) | (vec(compute_rand::call()) << static_cast(0)); } }; template struct compute_linearRand { GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max); }; template struct compute_linearRand { GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) { return (vec(compute_rand::call() % vec(Max + static_cast(1) - Min))) + Min; } }; template struct compute_linearRand { GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) { return (compute_rand::call() % (Max + static_cast(1) - Min)) + Min; } }; template struct compute_linearRand { GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) { return (vec(compute_rand::call() % vec(Max + static_cast(1) - Min))) + Min; } }; template struct compute_linearRand { GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) { return (compute_rand::call() % (Max + static_cast(1) - Min)) + Min; } }; template struct compute_linearRand { GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) { return (vec(compute_rand::call() % vec(Max + static_cast(1) - Min))) + Min; } }; template struct compute_linearRand { GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) { return (compute_rand::call() % (Max + static_cast(1) - Min)) + Min; } }; template struct compute_linearRand { GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) { return (vec(compute_rand::call() % vec(Max + static_cast(1) - Min))) + Min; } }; template struct compute_linearRand { GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) { return (compute_rand::call() % (Max + static_cast(1) - Min)) + Min; } }; template struct compute_linearRand { GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) { return vec(compute_rand::call()) / static_cast(std::numeric_limits::max()) * (Max - Min) + Min; } }; template struct compute_linearRand { GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) { return vec(compute_rand::call()) / static_cast(std::numeric_limits::max()) * (Max - Min) + Min; } }; template struct compute_linearRand { GLM_FUNC_QUALIFIER static vec call(vec const& Min, vec const& Max) { return vec(compute_rand::call()) / static_cast(std::numeric_limits::max()) * (Max - Min) + Min; } }; }//namespace detail template GLM_FUNC_QUALIFIER genType linearRand(genType Min, genType Max) { return detail::compute_linearRand<1, genType, highp>::call( vec<1, genType, highp>(Min), vec<1, genType, highp>(Max)).x; } template GLM_FUNC_QUALIFIER vec linearRand(vec const& Min, vec const& Max) { return detail::compute_linearRand::call(Min, Max); } template GLM_FUNC_QUALIFIER genType gaussRand(genType Mean, genType Deviation) { genType w, x1, x2; do { x1 = linearRand(genType(-1), genType(1)); x2 = linearRand(genType(-1), genType(1)); w = x1 * x1 + x2 * x2; } while(w > genType(1)); return static_cast(x2 * Deviation * Deviation * sqrt((genType(-2) * log(w)) / w) + Mean); } template GLM_FUNC_QUALIFIER vec gaussRand(vec const& Mean, vec const& Deviation) { return detail::functor2::call(gaussRand, Mean, Deviation); } template GLM_FUNC_QUALIFIER vec<2, T, defaultp> diskRand(T Radius) { assert(Radius > static_cast(0)); vec<2, T, defaultp> Result(T(0)); T LenRadius(T(0)); do { Result = linearRand( vec<2, T, defaultp>(-Radius), vec<2, T, defaultp>(Radius)); LenRadius = length(Result); } while(LenRadius > Radius); return Result; } template GLM_FUNC_QUALIFIER vec<3, T, defaultp> ballRand(T Radius) { assert(Radius > static_cast(0)); vec<3, T, defaultp> Result(T(0)); T LenRadius(T(0)); do { Result = linearRand( vec<3, T, defaultp>(-Radius), vec<3, T, defaultp>(Radius)); LenRadius = length(Result); } while(LenRadius > Radius); return Result; } template GLM_FUNC_QUALIFIER vec<2, T, defaultp> circularRand(T Radius) { assert(Radius > static_cast(0)); T a = linearRand(T(0), static_cast(6.283185307179586476925286766559)); return vec<2, T, defaultp>(glm::cos(a), glm::sin(a)) * Radius; } template GLM_FUNC_QUALIFIER vec<3, T, defaultp> sphericalRand(T Radius) { assert(Radius > static_cast(0)); T theta = linearRand(T(0), T(6.283185307179586476925286766559f)); T phi = std::acos(linearRand(T(-1.0f), T(1.0f))); T x = std::sin(phi) * std::cos(theta); T y = std::sin(phi) * std::sin(theta); T z = std::cos(phi); return vec<3, T, defaultp>(x, y, z) * Radius; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtc/reciprocal.hpp000066400000000000000000000067361360521144700237420ustar00rootroot00000000000000/// @ref gtc_reciprocal /// @file glm/gtc/reciprocal.hpp /// /// @see core (dependence) /// /// @defgroup gtc_reciprocal GLM_GTC_reciprocal /// @ingroup gtc /// /// Include to use the features of this extension. /// /// Define secant, cosecant and cotangent functions. #pragma once // Dependencies #include "../detail/setup.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_GTC_reciprocal extension included") #endif namespace glm { /// @addtogroup gtc_reciprocal /// @{ /// Secant function. /// hypotenuse / adjacent or 1 / cos(x) /// /// @tparam genType Floating-point scalar or vector types. /// /// @see gtc_reciprocal template GLM_FUNC_DECL genType sec(genType angle); /// Cosecant function. /// hypotenuse / opposite or 1 / sin(x) /// /// @tparam genType Floating-point scalar or vector types. /// /// @see gtc_reciprocal template GLM_FUNC_DECL genType csc(genType angle); /// Cotangent function. /// adjacent / opposite or 1 / tan(x) /// /// @tparam genType Floating-point scalar or vector types. /// /// @see gtc_reciprocal template GLM_FUNC_DECL genType cot(genType angle); /// Inverse secant function. /// /// @return Return an angle expressed in radians. /// @tparam genType Floating-point scalar or vector types. /// /// @see gtc_reciprocal template GLM_FUNC_DECL genType asec(genType x); /// Inverse cosecant function. /// /// @return Return an angle expressed in radians. /// @tparam genType Floating-point scalar or vector types. /// /// @see gtc_reciprocal template GLM_FUNC_DECL genType acsc(genType x); /// Inverse cotangent function. /// /// @return Return an angle expressed in radians. /// @tparam genType Floating-point scalar or vector types. /// /// @see gtc_reciprocal template GLM_FUNC_DECL genType acot(genType x); /// Secant hyperbolic function. /// /// @tparam genType Floating-point scalar or vector types. /// /// @see gtc_reciprocal template GLM_FUNC_DECL genType sech(genType angle); /// Cosecant hyperbolic function. /// /// @tparam genType Floating-point scalar or vector types. /// /// @see gtc_reciprocal template GLM_FUNC_DECL genType csch(genType angle); /// Cotangent hyperbolic function. /// /// @tparam genType Floating-point scalar or vector types. /// /// @see gtc_reciprocal template GLM_FUNC_DECL genType coth(genType angle); /// Inverse secant hyperbolic function. /// /// @return Return an angle expressed in radians. /// @tparam genType Floating-point scalar or vector types. /// /// @see gtc_reciprocal template GLM_FUNC_DECL genType asech(genType x); /// Inverse cosecant hyperbolic function. /// /// @return Return an angle expressed in radians. /// @tparam genType Floating-point scalar or vector types. /// /// @see gtc_reciprocal template GLM_FUNC_DECL genType acsch(genType x); /// Inverse cotangent hyperbolic function. /// /// @return Return an angle expressed in radians. /// @tparam genType Floating-point scalar or vector types. /// /// @see gtc_reciprocal template GLM_FUNC_DECL genType acoth(genType x); /// @} }//namespace glm #include "reciprocal.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtc/reciprocal.inl000066400000000000000000000145771360521144700237370ustar00rootroot00000000000000/// @ref gtc_reciprocal #include "../trigonometric.hpp" #include namespace glm { // sec template GLM_FUNC_QUALIFIER genType sec(genType angle) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'sec' only accept floating-point values"); return genType(1) / glm::cos(angle); } template GLM_FUNC_QUALIFIER vec sec(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'sec' only accept floating-point inputs"); return detail::functor1::call(sec, x); } // csc template GLM_FUNC_QUALIFIER genType csc(genType angle) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'csc' only accept floating-point values"); return genType(1) / glm::sin(angle); } template GLM_FUNC_QUALIFIER vec csc(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'csc' only accept floating-point inputs"); return detail::functor1::call(csc, x); } // cot template GLM_FUNC_QUALIFIER genType cot(genType angle) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'cot' only accept floating-point values"); genType const pi_over_2 = genType(3.1415926535897932384626433832795 / 2.0); return glm::tan(pi_over_2 - angle); } template GLM_FUNC_QUALIFIER vec cot(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'cot' only accept floating-point inputs"); return detail::functor1::call(cot, x); } // asec template GLM_FUNC_QUALIFIER genType asec(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'asec' only accept floating-point values"); return acos(genType(1) / x); } template GLM_FUNC_QUALIFIER vec asec(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'asec' only accept floating-point inputs"); return detail::functor1::call(asec, x); } // acsc template GLM_FUNC_QUALIFIER genType acsc(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acsc' only accept floating-point values"); return asin(genType(1) / x); } template GLM_FUNC_QUALIFIER vec acsc(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acsc' only accept floating-point inputs"); return detail::functor1::call(acsc, x); } // acot template GLM_FUNC_QUALIFIER genType acot(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acot' only accept floating-point values"); genType const pi_over_2 = genType(3.1415926535897932384626433832795 / 2.0); return pi_over_2 - atan(x); } template GLM_FUNC_QUALIFIER vec acot(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acot' only accept floating-point inputs"); return detail::functor1::call(acot, x); } // sech template GLM_FUNC_QUALIFIER genType sech(genType angle) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'sech' only accept floating-point values"); return genType(1) / glm::cosh(angle); } template GLM_FUNC_QUALIFIER vec sech(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'sech' only accept floating-point inputs"); return detail::functor1::call(sech, x); } // csch template GLM_FUNC_QUALIFIER genType csch(genType angle) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'csch' only accept floating-point values"); return genType(1) / glm::sinh(angle); } template GLM_FUNC_QUALIFIER vec csch(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'csch' only accept floating-point inputs"); return detail::functor1::call(csch, x); } // coth template GLM_FUNC_QUALIFIER genType coth(genType angle) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'coth' only accept floating-point values"); return glm::cosh(angle) / glm::sinh(angle); } template GLM_FUNC_QUALIFIER vec coth(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'coth' only accept floating-point inputs"); return detail::functor1::call(coth, x); } // asech template GLM_FUNC_QUALIFIER genType asech(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'asech' only accept floating-point values"); return acosh(genType(1) / x); } template GLM_FUNC_QUALIFIER vec asech(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'asech' only accept floating-point inputs"); return detail::functor1::call(asech, x); } // acsch template GLM_FUNC_QUALIFIER genType acsch(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acsch' only accept floating-point values"); return asinh(genType(1) / x); } template GLM_FUNC_QUALIFIER vec acsch(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acsch' only accept floating-point inputs"); return detail::functor1::call(acsch, x); } // acoth template GLM_FUNC_QUALIFIER genType acoth(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acoth' only accept floating-point values"); return atanh(genType(1) / x); } template GLM_FUNC_QUALIFIER vec acoth(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'acoth' only accept floating-point inputs"); return detail::functor1::call(acoth, x); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtc/round.hpp000066400000000000000000000124761360521144700227440ustar00rootroot00000000000000/// @ref gtc_round /// @file glm/gtc/round.hpp /// /// @see core (dependence) /// @see gtc_round (dependence) /// /// @defgroup gtc_round GLM_GTC_round /// @ingroup gtc /// /// Include to use the features of this extension. /// /// Rounding value to specific boundings #pragma once // Dependencies #include "../detail/setup.hpp" #include "../detail/qualifier.hpp" #include "../detail/_vectorize.hpp" #include "../vector_relational.hpp" #include "../common.hpp" #include #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_GTC_round extension included") #endif namespace glm { /// @addtogroup gtc_round /// @{ /// Return the power of two number which value is just higher the input value, /// round up to a power of two. /// /// @see gtc_round template GLM_FUNC_DECL genIUType ceilPowerOfTwo(genIUType v); /// Return the power of two number which value is just higher the input value, /// round up to a power of two. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum /// /// @see gtc_round template GLM_FUNC_DECL vec ceilPowerOfTwo(vec const& v); /// Return the power of two number which value is just lower the input value, /// round down to a power of two. /// /// @see gtc_round template GLM_FUNC_DECL genIUType floorPowerOfTwo(genIUType v); /// Return the power of two number which value is just lower the input value, /// round down to a power of two. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum /// /// @see gtc_round template GLM_FUNC_DECL vec floorPowerOfTwo(vec const& v); /// Return the power of two number which value is the closet to the input value. /// /// @see gtc_round template GLM_FUNC_DECL genIUType roundPowerOfTwo(genIUType v); /// Return the power of two number which value is the closet to the input value. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum /// /// @see gtc_round template GLM_FUNC_DECL vec roundPowerOfTwo(vec const& v); /// Higher multiple number of Source. /// /// @tparam genType Floating-point or integer scalar or vector types. /// /// @param v Source value to which is applied the function /// @param Multiple Must be a null or positive value /// /// @see gtc_round template GLM_FUNC_DECL genType ceilMultiple(genType v, genType Multiple); /// Higher multiple number of Source. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum /// /// @param v Source values to which is applied the function /// @param Multiple Must be a null or positive value /// /// @see gtc_round template GLM_FUNC_DECL vec ceilMultiple(vec const& v, vec const& Multiple); /// Lower multiple number of Source. /// /// @tparam genType Floating-point or integer scalar or vector types. /// /// @param v Source value to which is applied the function /// @param Multiple Must be a null or positive value /// /// @see gtc_round template GLM_FUNC_DECL genType floorMultiple(genType v, genType Multiple); /// Lower multiple number of Source. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum /// /// @param v Source values to which is applied the function /// @param Multiple Must be a null or positive value /// /// @see gtc_round template GLM_FUNC_DECL vec floorMultiple(vec const& v, vec const& Multiple); /// Lower multiple number of Source. /// /// @tparam genType Floating-point or integer scalar or vector types. /// /// @param v Source value to which is applied the function /// @param Multiple Must be a null or positive value /// /// @see gtc_round template GLM_FUNC_DECL genType roundMultiple(genType v, genType Multiple); /// Lower multiple number of Source. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum /// /// @param v Source values to which is applied the function /// @param Multiple Must be a null or positive value /// /// @see gtc_round template GLM_FUNC_DECL vec roundMultiple(vec const& v, vec const& Multiple); /// @} } //namespace glm #include "round.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtc/round.inl000066400000000000000000000106611360521144700227310ustar00rootroot00000000000000/// @ref gtc_round #include "../integer.hpp" #include "../ext/vector_integer.hpp" namespace glm{ namespace detail { template struct compute_roundMultiple {}; template<> struct compute_roundMultiple { template GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) { if (Source >= genType(0)) return Source - std::fmod(Source, Multiple); else { genType Tmp = Source + genType(1); return Tmp - std::fmod(Tmp, Multiple) - Multiple; } } }; template<> struct compute_roundMultiple { template GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) { if (Source >= genType(0)) return Source - Source % Multiple; else { genType Tmp = Source + genType(1); return Tmp - Tmp % Multiple - Multiple; } } }; template<> struct compute_roundMultiple { template GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) { if (Source >= genType(0)) return Source - Source % Multiple; else { genType Tmp = Source + genType(1); return Tmp - Tmp % Multiple - Multiple; } } }; }//namespace detail ////////////////// // ceilPowerOfTwo template GLM_FUNC_QUALIFIER genType ceilPowerOfTwo(genType value) { return detail::compute_ceilPowerOfTwo<1, genType, defaultp, std::numeric_limits::is_signed>::call(vec<1, genType, defaultp>(value)).x; } template GLM_FUNC_QUALIFIER vec ceilPowerOfTwo(vec const& v) { return detail::compute_ceilPowerOfTwo::is_signed>::call(v); } /////////////////// // floorPowerOfTwo template GLM_FUNC_QUALIFIER genType floorPowerOfTwo(genType value) { return isPowerOfTwo(value) ? value : static_cast(1) << findMSB(value); } template GLM_FUNC_QUALIFIER vec floorPowerOfTwo(vec const& v) { return detail::functor1::call(floorPowerOfTwo, v); } /////////////////// // roundPowerOfTwo template GLM_FUNC_QUALIFIER genIUType roundPowerOfTwo(genIUType value) { if(isPowerOfTwo(value)) return value; genIUType const prev = static_cast(1) << findMSB(value); genIUType const next = prev << static_cast(1); return (next - value) < (value - prev) ? next : prev; } template GLM_FUNC_QUALIFIER vec roundPowerOfTwo(vec const& v) { return detail::functor1::call(roundPowerOfTwo, v); } ////////////////////// // ceilMultiple template GLM_FUNC_QUALIFIER genType ceilMultiple(genType Source, genType Multiple) { return detail::compute_ceilMultiple::is_iec559, std::numeric_limits::is_signed>::call(Source, Multiple); } template GLM_FUNC_QUALIFIER vec ceilMultiple(vec const& Source, vec const& Multiple) { return detail::functor2::call(ceilMultiple, Source, Multiple); } ////////////////////// // floorMultiple template GLM_FUNC_QUALIFIER genType floorMultiple(genType Source, genType Multiple) { return detail::compute_floorMultiple::is_iec559, std::numeric_limits::is_signed>::call(Source, Multiple); } template GLM_FUNC_QUALIFIER vec floorMultiple(vec const& Source, vec const& Multiple) { return detail::functor2::call(floorMultiple, Source, Multiple); } ////////////////////// // roundMultiple template GLM_FUNC_QUALIFIER genType roundMultiple(genType Source, genType Multiple) { return detail::compute_roundMultiple::is_iec559, std::numeric_limits::is_signed>::call(Source, Multiple); } template GLM_FUNC_QUALIFIER vec roundMultiple(vec const& Source, vec const& Multiple) { return detail::functor2::call(roundMultiple, Source, Multiple); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtc/type_aligned.hpp000066400000000000000000002072621360521144700242600ustar00rootroot00000000000000/// @ref gtc_type_aligned /// @file glm/gtc/type_aligned.hpp /// /// @see core (dependence) /// /// @defgroup gtc_type_aligned GLM_GTC_type_aligned /// @ingroup gtc /// /// Include to use the features of this extension. /// /// Aligned types allowing SIMD optimizations of vectors and matrices types #pragma once #if (GLM_CONFIG_ALIGNED_GENTYPES == GLM_DISABLE) # error "GLM: Aligned gentypes require to enable C++ language extensions. Define GLM_FORCE_ALIGNED_GENTYPES before including GLM headers to use aligned types." #endif #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_GTC_type_aligned extension included") #endif #include "../mat4x4.hpp" #include "../mat4x3.hpp" #include "../mat4x2.hpp" #include "../mat3x4.hpp" #include "../mat3x3.hpp" #include "../mat3x2.hpp" #include "../mat2x4.hpp" #include "../mat2x3.hpp" #include "../mat2x2.hpp" #include "../gtc/vec1.hpp" #include "../vec2.hpp" #include "../vec3.hpp" #include "../vec4.hpp" namespace glm { /// @addtogroup gtc_type_aligned /// @{ // -- *vec1 -- /// 1 component vector aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef vec<1, float, aligned_highp> aligned_highp_vec1; /// 1 component vector aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef vec<1, float, aligned_mediump> aligned_mediump_vec1; /// 1 component vector aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef vec<1, float, aligned_lowp> aligned_lowp_vec1; /// 1 component vector aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef vec<1, double, aligned_highp> aligned_highp_dvec1; /// 1 component vector aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef vec<1, double, aligned_mediump> aligned_mediump_dvec1; /// 1 component vector aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef vec<1, double, aligned_lowp> aligned_lowp_dvec1; /// 1 component vector aligned in memory of signed integer numbers. typedef vec<1, int, aligned_highp> aligned_highp_ivec1; /// 1 component vector aligned in memory of signed integer numbers. typedef vec<1, int, aligned_mediump> aligned_mediump_ivec1; /// 1 component vector aligned in memory of signed integer numbers. typedef vec<1, int, aligned_lowp> aligned_lowp_ivec1; /// 1 component vector aligned in memory of unsigned integer numbers. typedef vec<1, uint, aligned_highp> aligned_highp_uvec1; /// 1 component vector aligned in memory of unsigned integer numbers. typedef vec<1, uint, aligned_mediump> aligned_mediump_uvec1; /// 1 component vector aligned in memory of unsigned integer numbers. typedef vec<1, uint, aligned_lowp> aligned_lowp_uvec1; /// 1 component vector aligned in memory of bool values. typedef vec<1, bool, aligned_highp> aligned_highp_bvec1; /// 1 component vector aligned in memory of bool values. typedef vec<1, bool, aligned_mediump> aligned_mediump_bvec1; /// 1 component vector aligned in memory of bool values. typedef vec<1, bool, aligned_lowp> aligned_lowp_bvec1; /// 1 component vector tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef vec<1, float, packed_highp> packed_highp_vec1; /// 1 component vector tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef vec<1, float, packed_mediump> packed_mediump_vec1; /// 1 component vector tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef vec<1, float, packed_lowp> packed_lowp_vec1; /// 1 component vector tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef vec<1, double, packed_highp> packed_highp_dvec1; /// 1 component vector tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef vec<1, double, packed_mediump> packed_mediump_dvec1; /// 1 component vector tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef vec<1, double, packed_lowp> packed_lowp_dvec1; /// 1 component vector tightly packed in memory of signed integer numbers. typedef vec<1, int, packed_highp> packed_highp_ivec1; /// 1 component vector tightly packed in memory of signed integer numbers. typedef vec<1, int, packed_mediump> packed_mediump_ivec1; /// 1 component vector tightly packed in memory of signed integer numbers. typedef vec<1, int, packed_lowp> packed_lowp_ivec1; /// 1 component vector tightly packed in memory of unsigned integer numbers. typedef vec<1, uint, packed_highp> packed_highp_uvec1; /// 1 component vector tightly packed in memory of unsigned integer numbers. typedef vec<1, uint, packed_mediump> packed_mediump_uvec1; /// 1 component vector tightly packed in memory of unsigned integer numbers. typedef vec<1, uint, packed_lowp> packed_lowp_uvec1; /// 1 component vector tightly packed in memory of bool values. typedef vec<1, bool, packed_highp> packed_highp_bvec1; /// 1 component vector tightly packed in memory of bool values. typedef vec<1, bool, packed_mediump> packed_mediump_bvec1; /// 1 component vector tightly packed in memory of bool values. typedef vec<1, bool, packed_lowp> packed_lowp_bvec1; // -- *vec2 -- /// 2 components vector aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef vec<2, float, aligned_highp> aligned_highp_vec2; /// 2 components vector aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef vec<2, float, aligned_mediump> aligned_mediump_vec2; /// 2 components vector aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef vec<2, float, aligned_lowp> aligned_lowp_vec2; /// 2 components vector aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef vec<2, double, aligned_highp> aligned_highp_dvec2; /// 2 components vector aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef vec<2, double, aligned_mediump> aligned_mediump_dvec2; /// 2 components vector aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef vec<2, double, aligned_lowp> aligned_lowp_dvec2; /// 2 components vector aligned in memory of signed integer numbers. typedef vec<2, int, aligned_highp> aligned_highp_ivec2; /// 2 components vector aligned in memory of signed integer numbers. typedef vec<2, int, aligned_mediump> aligned_mediump_ivec2; /// 2 components vector aligned in memory of signed integer numbers. typedef vec<2, int, aligned_lowp> aligned_lowp_ivec2; /// 2 components vector aligned in memory of unsigned integer numbers. typedef vec<2, uint, aligned_highp> aligned_highp_uvec2; /// 2 components vector aligned in memory of unsigned integer numbers. typedef vec<2, uint, aligned_mediump> aligned_mediump_uvec2; /// 2 components vector aligned in memory of unsigned integer numbers. typedef vec<2, uint, aligned_lowp> aligned_lowp_uvec2; /// 2 components vector aligned in memory of bool values. typedef vec<2, bool, aligned_highp> aligned_highp_bvec2; /// 2 components vector aligned in memory of bool values. typedef vec<2, bool, aligned_mediump> aligned_mediump_bvec2; /// 2 components vector aligned in memory of bool values. typedef vec<2, bool, aligned_lowp> aligned_lowp_bvec2; /// 2 components vector tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef vec<2, float, packed_highp> packed_highp_vec2; /// 2 components vector tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef vec<2, float, packed_mediump> packed_mediump_vec2; /// 2 components vector tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef vec<2, float, packed_lowp> packed_lowp_vec2; /// 2 components vector tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef vec<2, double, packed_highp> packed_highp_dvec2; /// 2 components vector tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef vec<2, double, packed_mediump> packed_mediump_dvec2; /// 2 components vector tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef vec<2, double, packed_lowp> packed_lowp_dvec2; /// 2 components vector tightly packed in memory of signed integer numbers. typedef vec<2, int, packed_highp> packed_highp_ivec2; /// 2 components vector tightly packed in memory of signed integer numbers. typedef vec<2, int, packed_mediump> packed_mediump_ivec2; /// 2 components vector tightly packed in memory of signed integer numbers. typedef vec<2, int, packed_lowp> packed_lowp_ivec2; /// 2 components vector tightly packed in memory of unsigned integer numbers. typedef vec<2, uint, packed_highp> packed_highp_uvec2; /// 2 components vector tightly packed in memory of unsigned integer numbers. typedef vec<2, uint, packed_mediump> packed_mediump_uvec2; /// 2 components vector tightly packed in memory of unsigned integer numbers. typedef vec<2, uint, packed_lowp> packed_lowp_uvec2; /// 2 components vector tightly packed in memory of bool values. typedef vec<2, bool, packed_highp> packed_highp_bvec2; /// 2 components vector tightly packed in memory of bool values. typedef vec<2, bool, packed_mediump> packed_mediump_bvec2; /// 2 components vector tightly packed in memory of bool values. typedef vec<2, bool, packed_lowp> packed_lowp_bvec2; // -- *vec3 -- /// 3 components vector aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef vec<3, float, aligned_highp> aligned_highp_vec3; /// 3 components vector aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef vec<3, float, aligned_mediump> aligned_mediump_vec3; /// 3 components vector aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef vec<3, float, aligned_lowp> aligned_lowp_vec3; /// 3 components vector aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef vec<3, double, aligned_highp> aligned_highp_dvec3; /// 3 components vector aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef vec<3, double, aligned_mediump> aligned_mediump_dvec3; /// 3 components vector aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef vec<3, double, aligned_lowp> aligned_lowp_dvec3; /// 3 components vector aligned in memory of signed integer numbers. typedef vec<3, int, aligned_highp> aligned_highp_ivec3; /// 3 components vector aligned in memory of signed integer numbers. typedef vec<3, int, aligned_mediump> aligned_mediump_ivec3; /// 3 components vector aligned in memory of signed integer numbers. typedef vec<3, int, aligned_lowp> aligned_lowp_ivec3; /// 3 components vector aligned in memory of unsigned integer numbers. typedef vec<3, uint, aligned_highp> aligned_highp_uvec3; /// 3 components vector aligned in memory of unsigned integer numbers. typedef vec<3, uint, aligned_mediump> aligned_mediump_uvec3; /// 3 components vector aligned in memory of unsigned integer numbers. typedef vec<3, uint, aligned_lowp> aligned_lowp_uvec3; /// 3 components vector aligned in memory of bool values. typedef vec<3, bool, aligned_highp> aligned_highp_bvec3; /// 3 components vector aligned in memory of bool values. typedef vec<3, bool, aligned_mediump> aligned_mediump_bvec3; /// 3 components vector aligned in memory of bool values. typedef vec<3, bool, aligned_lowp> aligned_lowp_bvec3; /// 3 components vector tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef vec<3, float, packed_highp> packed_highp_vec3; /// 3 components vector tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef vec<3, float, packed_mediump> packed_mediump_vec3; /// 3 components vector tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef vec<3, float, packed_lowp> packed_lowp_vec3; /// 3 components vector tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef vec<3, double, packed_highp> packed_highp_dvec3; /// 3 components vector tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef vec<3, double, packed_mediump> packed_mediump_dvec3; /// 3 components vector tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef vec<3, double, packed_lowp> packed_lowp_dvec3; /// 3 components vector tightly packed in memory of signed integer numbers. typedef vec<3, int, packed_highp> packed_highp_ivec3; /// 3 components vector tightly packed in memory of signed integer numbers. typedef vec<3, int, packed_mediump> packed_mediump_ivec3; /// 3 components vector tightly packed in memory of signed integer numbers. typedef vec<3, int, packed_lowp> packed_lowp_ivec3; /// 3 components vector tightly packed in memory of unsigned integer numbers. typedef vec<3, uint, packed_highp> packed_highp_uvec3; /// 3 components vector tightly packed in memory of unsigned integer numbers. typedef vec<3, uint, packed_mediump> packed_mediump_uvec3; /// 3 components vector tightly packed in memory of unsigned integer numbers. typedef vec<3, uint, packed_lowp> packed_lowp_uvec3; /// 3 components vector tightly packed in memory of bool values. typedef vec<3, bool, packed_highp> packed_highp_bvec3; /// 3 components vector tightly packed in memory of bool values. typedef vec<3, bool, packed_mediump> packed_mediump_bvec3; /// 3 components vector tightly packed in memory of bool values. typedef vec<3, bool, packed_lowp> packed_lowp_bvec3; // -- *vec4 -- /// 4 components vector aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef vec<4, float, aligned_highp> aligned_highp_vec4; /// 4 components vector aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef vec<4, float, aligned_mediump> aligned_mediump_vec4; /// 4 components vector aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef vec<4, float, aligned_lowp> aligned_lowp_vec4; /// 4 components vector aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef vec<4, double, aligned_highp> aligned_highp_dvec4; /// 4 components vector aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef vec<4, double, aligned_mediump> aligned_mediump_dvec4; /// 4 components vector aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef vec<4, double, aligned_lowp> aligned_lowp_dvec4; /// 4 components vector aligned in memory of signed integer numbers. typedef vec<4, int, aligned_highp> aligned_highp_ivec4; /// 4 components vector aligned in memory of signed integer numbers. typedef vec<4, int, aligned_mediump> aligned_mediump_ivec4; /// 4 components vector aligned in memory of signed integer numbers. typedef vec<4, int, aligned_lowp> aligned_lowp_ivec4; /// 4 components vector aligned in memory of unsigned integer numbers. typedef vec<4, uint, aligned_highp> aligned_highp_uvec4; /// 4 components vector aligned in memory of unsigned integer numbers. typedef vec<4, uint, aligned_mediump> aligned_mediump_uvec4; /// 4 components vector aligned in memory of unsigned integer numbers. typedef vec<4, uint, aligned_lowp> aligned_lowp_uvec4; /// 4 components vector aligned in memory of bool values. typedef vec<4, bool, aligned_highp> aligned_highp_bvec4; /// 4 components vector aligned in memory of bool values. typedef vec<4, bool, aligned_mediump> aligned_mediump_bvec4; /// 4 components vector aligned in memory of bool values. typedef vec<4, bool, aligned_lowp> aligned_lowp_bvec4; /// 4 components vector tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef vec<4, float, packed_highp> packed_highp_vec4; /// 4 components vector tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef vec<4, float, packed_mediump> packed_mediump_vec4; /// 4 components vector tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef vec<4, float, packed_lowp> packed_lowp_vec4; /// 4 components vector tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef vec<4, double, packed_highp> packed_highp_dvec4; /// 4 components vector tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef vec<4, double, packed_mediump> packed_mediump_dvec4; /// 4 components vector tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef vec<4, double, packed_lowp> packed_lowp_dvec4; /// 4 components vector tightly packed in memory of signed integer numbers. typedef vec<4, int, packed_highp> packed_highp_ivec4; /// 4 components vector tightly packed in memory of signed integer numbers. typedef vec<4, int, packed_mediump> packed_mediump_ivec4; /// 4 components vector tightly packed in memory of signed integer numbers. typedef vec<4, int, packed_lowp> packed_lowp_ivec4; /// 4 components vector tightly packed in memory of unsigned integer numbers. typedef vec<4, uint, packed_highp> packed_highp_uvec4; /// 4 components vector tightly packed in memory of unsigned integer numbers. typedef vec<4, uint, packed_mediump> packed_mediump_uvec4; /// 4 components vector tightly packed in memory of unsigned integer numbers. typedef vec<4, uint, packed_lowp> packed_lowp_uvec4; /// 4 components vector tightly packed in memory of bool values. typedef vec<4, bool, packed_highp> packed_highp_bvec4; /// 4 components vector tightly packed in memory of bool values. typedef vec<4, bool, packed_mediump> packed_mediump_bvec4; /// 4 components vector tightly packed in memory of bool values. typedef vec<4, bool, packed_lowp> packed_lowp_bvec4; // -- *mat2 -- /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<2, 2, float, aligned_highp> aligned_highp_mat2; /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<2, 2, float, aligned_mediump> aligned_mediump_mat2; /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<2, 2, float, aligned_lowp> aligned_lowp_mat2; /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<2, 2, double, aligned_highp> aligned_highp_dmat2; /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<2, 2, double, aligned_mediump> aligned_mediump_dmat2; /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<2, 2, double, aligned_lowp> aligned_lowp_dmat2; /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<2, 2, float, packed_highp> packed_highp_mat2; /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<2, 2, float, packed_mediump> packed_mediump_mat2; /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<2, 2, float, packed_lowp> packed_lowp_mat2; /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<2, 2, double, packed_highp> packed_highp_dmat2; /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<2, 2, double, packed_mediump> packed_mediump_dmat2; /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<2, 2, double, packed_lowp> packed_lowp_dmat2; // -- *mat3 -- /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<3, 3, float, aligned_highp> aligned_highp_mat3; /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<3, 3, float, aligned_mediump> aligned_mediump_mat3; /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<3, 3, float, aligned_lowp> aligned_lowp_mat3; /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<3, 3, double, aligned_highp> aligned_highp_dmat3; /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<3, 3, double, aligned_mediump> aligned_mediump_dmat3; /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<3, 3, double, aligned_lowp> aligned_lowp_dmat3; /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<3, 3, float, packed_highp> packed_highp_mat3; /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<3, 3, float, packed_mediump> packed_mediump_mat3; /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<3, 3, float, packed_lowp> packed_lowp_mat3; /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<3, 3, double, packed_highp> packed_highp_dmat3; /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<3, 3, double, packed_mediump> packed_mediump_dmat3; /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<3, 3, double, packed_lowp> packed_lowp_dmat3; // -- *mat4 -- /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<4, 4, float, aligned_highp> aligned_highp_mat4; /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<4, 4, float, aligned_mediump> aligned_mediump_mat4; /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<4, 4, float, aligned_lowp> aligned_lowp_mat4; /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<4, 4, double, aligned_highp> aligned_highp_dmat4; /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<4, 4, double, aligned_mediump> aligned_mediump_dmat4; /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<4, 4, double, aligned_lowp> aligned_lowp_dmat4; /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<4, 4, float, packed_highp> packed_highp_mat4; /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<4, 4, float, packed_mediump> packed_mediump_mat4; /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<4, 4, float, packed_lowp> packed_lowp_mat4; /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<4, 4, double, packed_highp> packed_highp_dmat4; /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<4, 4, double, packed_mediump> packed_mediump_dmat4; /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<4, 4, double, packed_lowp> packed_lowp_dmat4; // -- *mat2x2 -- /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<2, 2, float, aligned_highp> aligned_highp_mat2x2; /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<2, 2, float, aligned_mediump> aligned_mediump_mat2x2; /// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<2, 2, float, aligned_lowp> aligned_lowp_mat2x2; /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<2, 2, double, aligned_highp> aligned_highp_dmat2x2; /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<2, 2, double, aligned_mediump> aligned_mediump_dmat2x2; /// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<2, 2, double, aligned_lowp> aligned_lowp_dmat2x2; /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<2, 2, float, packed_highp> packed_highp_mat2x2; /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<2, 2, float, packed_mediump> packed_mediump_mat2x2; /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<2, 2, float, packed_lowp> packed_lowp_mat2x2; /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<2, 2, double, packed_highp> packed_highp_dmat2x2; /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<2, 2, double, packed_mediump> packed_mediump_dmat2x2; /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<2, 2, double, packed_lowp> packed_lowp_dmat2x2; // -- *mat2x3 -- /// 2 by 3 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<2, 3, float, aligned_highp> aligned_highp_mat2x3; /// 2 by 3 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<2, 3, float, aligned_mediump> aligned_mediump_mat2x3; /// 2 by 3 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<2, 3, float, aligned_lowp> aligned_lowp_mat2x3; /// 2 by 3 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<2, 3, double, aligned_highp> aligned_highp_dmat2x3; /// 2 by 3 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<2, 3, double, aligned_mediump> aligned_mediump_dmat2x3; /// 2 by 3 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<2, 3, double, aligned_lowp> aligned_lowp_dmat2x3; /// 2 by 3 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<2, 3, float, packed_highp> packed_highp_mat2x3; /// 2 by 3 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<2, 3, float, packed_mediump> packed_mediump_mat2x3; /// 2 by 3 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<2, 3, float, packed_lowp> packed_lowp_mat2x3; /// 2 by 3 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<2, 3, double, packed_highp> packed_highp_dmat2x3; /// 2 by 3 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<2, 3, double, packed_mediump> packed_mediump_dmat2x3; /// 2 by 3 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<2, 3, double, packed_lowp> packed_lowp_dmat2x3; // -- *mat2x4 -- /// 2 by 4 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<2, 4, float, aligned_highp> aligned_highp_mat2x4; /// 2 by 4 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<2, 4, float, aligned_mediump> aligned_mediump_mat2x4; /// 2 by 4 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<2, 4, float, aligned_lowp> aligned_lowp_mat2x4; /// 2 by 4 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<2, 4, double, aligned_highp> aligned_highp_dmat2x4; /// 2 by 4 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<2, 4, double, aligned_mediump> aligned_mediump_dmat2x4; /// 2 by 4 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<2, 4, double, aligned_lowp> aligned_lowp_dmat2x4; /// 2 by 4 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<2, 4, float, packed_highp> packed_highp_mat2x4; /// 2 by 4 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<2, 4, float, packed_mediump> packed_mediump_mat2x4; /// 2 by 4 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<2, 4, float, packed_lowp> packed_lowp_mat2x4; /// 2 by 4 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<2, 4, double, packed_highp> packed_highp_dmat2x4; /// 2 by 4 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<2, 4, double, packed_mediump> packed_mediump_dmat2x4; /// 2 by 4 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<2, 4, double, packed_lowp> packed_lowp_dmat2x4; // -- *mat3x2 -- /// 3 by 2 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<3, 2, float, aligned_highp> aligned_highp_mat3x2; /// 3 by 2 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<3, 2, float, aligned_mediump> aligned_mediump_mat3x2; /// 3 by 2 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<3, 2, float, aligned_lowp> aligned_lowp_mat3x2; /// 3 by 2 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<3, 2, double, aligned_highp> aligned_highp_dmat3x2; /// 3 by 2 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<3, 2, double, aligned_mediump> aligned_mediump_dmat3x2; /// 3 by 2 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<3, 2, double, aligned_lowp> aligned_lowp_dmat3x2; /// 3 by 2 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<3, 2, float, packed_highp> packed_highp_mat3x2; /// 3 by 2 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<3, 2, float, packed_mediump> packed_mediump_mat3x2; /// 3 by 2 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<3, 2, float, packed_lowp> packed_lowp_mat3x2; /// 3 by 2 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<3, 2, double, packed_highp> packed_highp_dmat3x2; /// 3 by 2 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<3, 2, double, packed_mediump> packed_mediump_dmat3x2; /// 3 by 2 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<3, 2, double, packed_lowp> packed_lowp_dmat3x2; // -- *mat3x3 -- /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<3, 3, float, aligned_highp> aligned_highp_mat3x3; /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<3, 3, float, aligned_mediump> aligned_mediump_mat3x3; /// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<3, 3, float, aligned_lowp> aligned_lowp_mat3x3; /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<3, 3, double, aligned_highp> aligned_highp_dmat3x3; /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<3, 3, double, aligned_mediump> aligned_mediump_dmat3x3; /// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<3, 3, double, aligned_lowp> aligned_lowp_dmat3x3; /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<3, 3, float, packed_highp> packed_highp_mat3x3; /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<3, 3, float, packed_mediump> packed_mediump_mat3x3; /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<3, 3, float, packed_lowp> packed_lowp_mat3x3; /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<3, 3, double, packed_highp> packed_highp_dmat3x3; /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<3, 3, double, packed_mediump> packed_mediump_dmat3x3; /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<3, 3, double, packed_lowp> packed_lowp_dmat3x3; // -- *mat3x4 -- /// 3 by 4 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<3, 4, float, aligned_highp> aligned_highp_mat3x4; /// 3 by 4 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<3, 4, float, aligned_mediump> aligned_mediump_mat3x4; /// 3 by 4 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<3, 4, float, aligned_lowp> aligned_lowp_mat3x4; /// 3 by 4 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<3, 4, double, aligned_highp> aligned_highp_dmat3x4; /// 3 by 4 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<3, 4, double, aligned_mediump> aligned_mediump_dmat3x4; /// 3 by 4 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<3, 4, double, aligned_lowp> aligned_lowp_dmat3x4; /// 3 by 4 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<3, 4, float, packed_highp> packed_highp_mat3x4; /// 3 by 4 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<3, 4, float, packed_mediump> packed_mediump_mat3x4; /// 3 by 4 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<3, 4, float, packed_lowp> packed_lowp_mat3x4; /// 3 by 4 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<3, 4, double, packed_highp> packed_highp_dmat3x4; /// 3 by 4 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<3, 4, double, packed_mediump> packed_mediump_dmat3x4; /// 3 by 4 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<3, 4, double, packed_lowp> packed_lowp_dmat3x4; // -- *mat4x2 -- /// 4 by 2 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<4, 2, float, aligned_highp> aligned_highp_mat4x2; /// 4 by 2 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<4, 2, float, aligned_mediump> aligned_mediump_mat4x2; /// 4 by 2 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<4, 2, float, aligned_lowp> aligned_lowp_mat4x2; /// 4 by 2 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<4, 2, double, aligned_highp> aligned_highp_dmat4x2; /// 4 by 2 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<4, 2, double, aligned_mediump> aligned_mediump_dmat4x2; /// 4 by 2 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<4, 2, double, aligned_lowp> aligned_lowp_dmat4x2; /// 4 by 2 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<4, 2, float, packed_highp> packed_highp_mat4x2; /// 4 by 2 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<4, 2, float, packed_mediump> packed_mediump_mat4x2; /// 4 by 2 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<4, 2, float, packed_lowp> packed_lowp_mat4x2; /// 4 by 2 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<4, 2, double, packed_highp> packed_highp_dmat4x2; /// 4 by 2 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<4, 2, double, packed_mediump> packed_mediump_dmat4x2; /// 4 by 2 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<4, 2, double, packed_lowp> packed_lowp_dmat4x2; // -- *mat4x3 -- /// 4 by 3 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<4, 3, float, aligned_highp> aligned_highp_mat4x3; /// 4 by 3 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<4, 3, float, aligned_mediump> aligned_mediump_mat4x3; /// 4 by 3 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<4, 3, float, aligned_lowp> aligned_lowp_mat4x3; /// 4 by 3 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<4, 3, double, aligned_highp> aligned_highp_dmat4x3; /// 4 by 3 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<4, 3, double, aligned_mediump> aligned_mediump_dmat4x3; /// 4 by 3 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<4, 3, double, aligned_lowp> aligned_lowp_dmat4x3; /// 4 by 3 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<4, 3, float, packed_highp> packed_highp_mat4x3; /// 4 by 3 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<4, 3, float, packed_mediump> packed_mediump_mat4x3; /// 4 by 3 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<4, 3, float, packed_lowp> packed_lowp_mat4x3; /// 4 by 3 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<4, 3, double, packed_highp> packed_highp_dmat4x3; /// 4 by 3 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<4, 3, double, packed_mediump> packed_mediump_dmat4x3; /// 4 by 3 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<4, 3, double, packed_lowp> packed_lowp_dmat4x3; // -- *mat4x4 -- /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<4, 4, float, aligned_highp> aligned_highp_mat4x4; /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<4, 4, float, aligned_mediump> aligned_mediump_mat4x4; /// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<4, 4, float, aligned_lowp> aligned_lowp_mat4x4; /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<4, 4, double, aligned_highp> aligned_highp_dmat4x4; /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<4, 4, double, aligned_mediump> aligned_mediump_dmat4x4; /// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<4, 4, double, aligned_lowp> aligned_lowp_dmat4x4; /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<4, 4, float, packed_highp> packed_highp_mat4x4; /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<4, 4, float, packed_mediump> packed_mediump_mat4x4; /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<4, 4, float, packed_lowp> packed_lowp_mat4x4; /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs. typedef mat<4, 4, double, packed_highp> packed_highp_dmat4x4; /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs. typedef mat<4, 4, double, packed_mediump> packed_mediump_dmat4x4; /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs. typedef mat<4, 4, double, packed_lowp> packed_lowp_dmat4x4; // -- default -- #if(defined(GLM_PRECISION_LOWP_FLOAT)) typedef aligned_lowp_vec1 aligned_vec1; typedef aligned_lowp_vec2 aligned_vec2; typedef aligned_lowp_vec3 aligned_vec3; typedef aligned_lowp_vec4 aligned_vec4; typedef packed_lowp_vec1 packed_vec1; typedef packed_lowp_vec2 packed_vec2; typedef packed_lowp_vec3 packed_vec3; typedef packed_lowp_vec4 packed_vec4; typedef aligned_lowp_mat2 aligned_mat2; typedef aligned_lowp_mat3 aligned_mat3; typedef aligned_lowp_mat4 aligned_mat4; typedef packed_lowp_mat2 packed_mat2; typedef packed_lowp_mat3 packed_mat3; typedef packed_lowp_mat4 packed_mat4; typedef aligned_lowp_mat2x2 aligned_mat2x2; typedef aligned_lowp_mat2x3 aligned_mat2x3; typedef aligned_lowp_mat2x4 aligned_mat2x4; typedef aligned_lowp_mat3x2 aligned_mat3x2; typedef aligned_lowp_mat3x3 aligned_mat3x3; typedef aligned_lowp_mat3x4 aligned_mat3x4; typedef aligned_lowp_mat4x2 aligned_mat4x2; typedef aligned_lowp_mat4x3 aligned_mat4x3; typedef aligned_lowp_mat4x4 aligned_mat4x4; typedef packed_lowp_mat2x2 packed_mat2x2; typedef packed_lowp_mat2x3 packed_mat2x3; typedef packed_lowp_mat2x4 packed_mat2x4; typedef packed_lowp_mat3x2 packed_mat3x2; typedef packed_lowp_mat3x3 packed_mat3x3; typedef packed_lowp_mat3x4 packed_mat3x4; typedef packed_lowp_mat4x2 packed_mat4x2; typedef packed_lowp_mat4x3 packed_mat4x3; typedef packed_lowp_mat4x4 packed_mat4x4; #elif(defined(GLM_PRECISION_MEDIUMP_FLOAT)) typedef aligned_mediump_vec1 aligned_vec1; typedef aligned_mediump_vec2 aligned_vec2; typedef aligned_mediump_vec3 aligned_vec3; typedef aligned_mediump_vec4 aligned_vec4; typedef packed_mediump_vec1 packed_vec1; typedef packed_mediump_vec2 packed_vec2; typedef packed_mediump_vec3 packed_vec3; typedef packed_mediump_vec4 packed_vec4; typedef aligned_mediump_mat2 aligned_mat2; typedef aligned_mediump_mat3 aligned_mat3; typedef aligned_mediump_mat4 aligned_mat4; typedef packed_mediump_mat2 packed_mat2; typedef packed_mediump_mat3 packed_mat3; typedef packed_mediump_mat4 packed_mat4; typedef aligned_mediump_mat2x2 aligned_mat2x2; typedef aligned_mediump_mat2x3 aligned_mat2x3; typedef aligned_mediump_mat2x4 aligned_mat2x4; typedef aligned_mediump_mat3x2 aligned_mat3x2; typedef aligned_mediump_mat3x3 aligned_mat3x3; typedef aligned_mediump_mat3x4 aligned_mat3x4; typedef aligned_mediump_mat4x2 aligned_mat4x2; typedef aligned_mediump_mat4x3 aligned_mat4x3; typedef aligned_mediump_mat4x4 aligned_mat4x4; typedef packed_mediump_mat2x2 packed_mat2x2; typedef packed_mediump_mat2x3 packed_mat2x3; typedef packed_mediump_mat2x4 packed_mat2x4; typedef packed_mediump_mat3x2 packed_mat3x2; typedef packed_mediump_mat3x3 packed_mat3x3; typedef packed_mediump_mat3x4 packed_mat3x4; typedef packed_mediump_mat4x2 packed_mat4x2; typedef packed_mediump_mat4x3 packed_mat4x3; typedef packed_mediump_mat4x4 packed_mat4x4; #else //defined(GLM_PRECISION_HIGHP_FLOAT) /// 1 component vector aligned in memory of single-precision floating-point numbers. typedef aligned_highp_vec1 aligned_vec1; /// 2 components vector aligned in memory of single-precision floating-point numbers. typedef aligned_highp_vec2 aligned_vec2; /// 3 components vector aligned in memory of single-precision floating-point numbers. typedef aligned_highp_vec3 aligned_vec3; /// 4 components vector aligned in memory of single-precision floating-point numbers. typedef aligned_highp_vec4 aligned_vec4; /// 1 component vector tightly packed in memory of single-precision floating-point numbers. typedef packed_highp_vec1 packed_vec1; /// 2 components vector tightly packed in memory of single-precision floating-point numbers. typedef packed_highp_vec2 packed_vec2; /// 3 components vector tightly packed in memory of single-precision floating-point numbers. typedef packed_highp_vec3 packed_vec3; /// 4 components vector tightly packed in memory of single-precision floating-point numbers. typedef packed_highp_vec4 packed_vec4; /// 2 by 2 matrix tightly aligned in memory of single-precision floating-point numbers. typedef aligned_highp_mat2 aligned_mat2; /// 3 by 3 matrix tightly aligned in memory of single-precision floating-point numbers. typedef aligned_highp_mat3 aligned_mat3; /// 4 by 4 matrix tightly aligned in memory of single-precision floating-point numbers. typedef aligned_highp_mat4 aligned_mat4; /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers. typedef packed_highp_mat2 packed_mat2; /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers. typedef packed_highp_mat3 packed_mat3; /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers. typedef packed_highp_mat4 packed_mat4; /// 2 by 2 matrix tightly aligned in memory of single-precision floating-point numbers. typedef aligned_highp_mat2x2 aligned_mat2x2; /// 2 by 3 matrix tightly aligned in memory of single-precision floating-point numbers. typedef aligned_highp_mat2x3 aligned_mat2x3; /// 2 by 4 matrix tightly aligned in memory of single-precision floating-point numbers. typedef aligned_highp_mat2x4 aligned_mat2x4; /// 3 by 2 matrix tightly aligned in memory of single-precision floating-point numbers. typedef aligned_highp_mat3x2 aligned_mat3x2; /// 3 by 3 matrix tightly aligned in memory of single-precision floating-point numbers. typedef aligned_highp_mat3x3 aligned_mat3x3; /// 3 by 4 matrix tightly aligned in memory of single-precision floating-point numbers. typedef aligned_highp_mat3x4 aligned_mat3x4; /// 4 by 2 matrix tightly aligned in memory of single-precision floating-point numbers. typedef aligned_highp_mat4x2 aligned_mat4x2; /// 4 by 3 matrix tightly aligned in memory of single-precision floating-point numbers. typedef aligned_highp_mat4x3 aligned_mat4x3; /// 4 by 4 matrix tightly aligned in memory of single-precision floating-point numbers. typedef aligned_highp_mat4x4 aligned_mat4x4; /// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers. typedef packed_highp_mat2x2 packed_mat2x2; /// 2 by 3 matrix tightly packed in memory of single-precision floating-point numbers. typedef packed_highp_mat2x3 packed_mat2x3; /// 2 by 4 matrix tightly packed in memory of single-precision floating-point numbers. typedef packed_highp_mat2x4 packed_mat2x4; /// 3 by 2 matrix tightly packed in memory of single-precision floating-point numbers. typedef packed_highp_mat3x2 packed_mat3x2; /// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers. typedef packed_highp_mat3x3 packed_mat3x3; /// 3 by 4 matrix tightly packed in memory of single-precision floating-point numbers. typedef packed_highp_mat3x4 packed_mat3x4; /// 4 by 2 matrix tightly packed in memory of single-precision floating-point numbers. typedef packed_highp_mat4x2 packed_mat4x2; /// 4 by 3 matrix tightly packed in memory of single-precision floating-point numbers. typedef packed_highp_mat4x3 packed_mat4x3; /// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers. typedef packed_highp_mat4x4 packed_mat4x4; #endif//GLM_PRECISION #if(defined(GLM_PRECISION_LOWP_DOUBLE)) typedef aligned_lowp_dvec1 aligned_dvec1; typedef aligned_lowp_dvec2 aligned_dvec2; typedef aligned_lowp_dvec3 aligned_dvec3; typedef aligned_lowp_dvec4 aligned_dvec4; typedef packed_lowp_dvec1 packed_dvec1; typedef packed_lowp_dvec2 packed_dvec2; typedef packed_lowp_dvec3 packed_dvec3; typedef packed_lowp_dvec4 packed_dvec4; typedef aligned_lowp_dmat2 aligned_dmat2; typedef aligned_lowp_dmat3 aligned_dmat3; typedef aligned_lowp_dmat4 aligned_dmat4; typedef packed_lowp_dmat2 packed_dmat2; typedef packed_lowp_dmat3 packed_dmat3; typedef packed_lowp_dmat4 packed_dmat4; typedef aligned_lowp_dmat2x2 aligned_dmat2x2; typedef aligned_lowp_dmat2x3 aligned_dmat2x3; typedef aligned_lowp_dmat2x4 aligned_dmat2x4; typedef aligned_lowp_dmat3x2 aligned_dmat3x2; typedef aligned_lowp_dmat3x3 aligned_dmat3x3; typedef aligned_lowp_dmat3x4 aligned_dmat3x4; typedef aligned_lowp_dmat4x2 aligned_dmat4x2; typedef aligned_lowp_dmat4x3 aligned_dmat4x3; typedef aligned_lowp_dmat4x4 aligned_dmat4x4; typedef packed_lowp_dmat2x2 packed_dmat2x2; typedef packed_lowp_dmat2x3 packed_dmat2x3; typedef packed_lowp_dmat2x4 packed_dmat2x4; typedef packed_lowp_dmat3x2 packed_dmat3x2; typedef packed_lowp_dmat3x3 packed_dmat3x3; typedef packed_lowp_dmat3x4 packed_dmat3x4; typedef packed_lowp_dmat4x2 packed_dmat4x2; typedef packed_lowp_dmat4x3 packed_dmat4x3; typedef packed_lowp_dmat4x4 packed_dmat4x4; #elif(defined(GLM_PRECISION_MEDIUMP_DOUBLE)) typedef aligned_mediump_dvec1 aligned_dvec1; typedef aligned_mediump_dvec2 aligned_dvec2; typedef aligned_mediump_dvec3 aligned_dvec3; typedef aligned_mediump_dvec4 aligned_dvec4; typedef packed_mediump_dvec1 packed_dvec1; typedef packed_mediump_dvec2 packed_dvec2; typedef packed_mediump_dvec3 packed_dvec3; typedef packed_mediump_dvec4 packed_dvec4; typedef aligned_mediump_dmat2 aligned_dmat2; typedef aligned_mediump_dmat3 aligned_dmat3; typedef aligned_mediump_dmat4 aligned_dmat4; typedef packed_mediump_dmat2 packed_dmat2; typedef packed_mediump_dmat3 packed_dmat3; typedef packed_mediump_dmat4 packed_dmat4; typedef aligned_mediump_dmat2x2 aligned_dmat2x2; typedef aligned_mediump_dmat2x3 aligned_dmat2x3; typedef aligned_mediump_dmat2x4 aligned_dmat2x4; typedef aligned_mediump_dmat3x2 aligned_dmat3x2; typedef aligned_mediump_dmat3x3 aligned_dmat3x3; typedef aligned_mediump_dmat3x4 aligned_dmat3x4; typedef aligned_mediump_dmat4x2 aligned_dmat4x2; typedef aligned_mediump_dmat4x3 aligned_dmat4x3; typedef aligned_mediump_dmat4x4 aligned_dmat4x4; typedef packed_mediump_dmat2x2 packed_dmat2x2; typedef packed_mediump_dmat2x3 packed_dmat2x3; typedef packed_mediump_dmat2x4 packed_dmat2x4; typedef packed_mediump_dmat3x2 packed_dmat3x2; typedef packed_mediump_dmat3x3 packed_dmat3x3; typedef packed_mediump_dmat3x4 packed_dmat3x4; typedef packed_mediump_dmat4x2 packed_dmat4x2; typedef packed_mediump_dmat4x3 packed_dmat4x3; typedef packed_mediump_dmat4x4 packed_dmat4x4; #else //defined(GLM_PRECISION_HIGHP_DOUBLE) /// 1 component vector aligned in memory of double-precision floating-point numbers. typedef aligned_highp_dvec1 aligned_dvec1; /// 2 components vector aligned in memory of double-precision floating-point numbers. typedef aligned_highp_dvec2 aligned_dvec2; /// 3 components vector aligned in memory of double-precision floating-point numbers. typedef aligned_highp_dvec3 aligned_dvec3; /// 4 components vector aligned in memory of double-precision floating-point numbers. typedef aligned_highp_dvec4 aligned_dvec4; /// 1 component vector tightly packed in memory of double-precision floating-point numbers. typedef packed_highp_dvec1 packed_dvec1; /// 2 components vector tightly packed in memory of double-precision floating-point numbers. typedef packed_highp_dvec2 packed_dvec2; /// 3 components vector tightly packed in memory of double-precision floating-point numbers. typedef packed_highp_dvec3 packed_dvec3; /// 4 components vector tightly packed in memory of double-precision floating-point numbers. typedef packed_highp_dvec4 packed_dvec4; /// 2 by 2 matrix tightly aligned in memory of double-precision floating-point numbers. typedef aligned_highp_dmat2 aligned_dmat2; /// 3 by 3 matrix tightly aligned in memory of double-precision floating-point numbers. typedef aligned_highp_dmat3 aligned_dmat3; /// 4 by 4 matrix tightly aligned in memory of double-precision floating-point numbers. typedef aligned_highp_dmat4 aligned_dmat4; /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers. typedef packed_highp_dmat2 packed_dmat2; /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers. typedef packed_highp_dmat3 packed_dmat3; /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers. typedef packed_highp_dmat4 packed_dmat4; /// 2 by 2 matrix tightly aligned in memory of double-precision floating-point numbers. typedef aligned_highp_dmat2x2 aligned_dmat2x2; /// 2 by 3 matrix tightly aligned in memory of double-precision floating-point numbers. typedef aligned_highp_dmat2x3 aligned_dmat2x3; /// 2 by 4 matrix tightly aligned in memory of double-precision floating-point numbers. typedef aligned_highp_dmat2x4 aligned_dmat2x4; /// 3 by 2 matrix tightly aligned in memory of double-precision floating-point numbers. typedef aligned_highp_dmat3x2 aligned_dmat3x2; /// 3 by 3 matrix tightly aligned in memory of double-precision floating-point numbers. typedef aligned_highp_dmat3x3 aligned_dmat3x3; /// 3 by 4 matrix tightly aligned in memory of double-precision floating-point numbers. typedef aligned_highp_dmat3x4 aligned_dmat3x4; /// 4 by 2 matrix tightly aligned in memory of double-precision floating-point numbers. typedef aligned_highp_dmat4x2 aligned_dmat4x2; /// 4 by 3 matrix tightly aligned in memory of double-precision floating-point numbers. typedef aligned_highp_dmat4x3 aligned_dmat4x3; /// 4 by 4 matrix tightly aligned in memory of double-precision floating-point numbers. typedef aligned_highp_dmat4x4 aligned_dmat4x4; /// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers. typedef packed_highp_dmat2x2 packed_dmat2x2; /// 2 by 3 matrix tightly packed in memory of double-precision floating-point numbers. typedef packed_highp_dmat2x3 packed_dmat2x3; /// 2 by 4 matrix tightly packed in memory of double-precision floating-point numbers. typedef packed_highp_dmat2x4 packed_dmat2x4; /// 3 by 2 matrix tightly packed in memory of double-precision floating-point numbers. typedef packed_highp_dmat3x2 packed_dmat3x2; /// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers. typedef packed_highp_dmat3x3 packed_dmat3x3; /// 3 by 4 matrix tightly packed in memory of double-precision floating-point numbers. typedef packed_highp_dmat3x4 packed_dmat3x4; /// 4 by 2 matrix tightly packed in memory of double-precision floating-point numbers. typedef packed_highp_dmat4x2 packed_dmat4x2; /// 4 by 3 matrix tightly packed in memory of double-precision floating-point numbers. typedef packed_highp_dmat4x3 packed_dmat4x3; /// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers. typedef packed_highp_dmat4x4 packed_dmat4x4; #endif//GLM_PRECISION #if(defined(GLM_PRECISION_LOWP_INT)) typedef aligned_lowp_ivec1 aligned_ivec1; typedef aligned_lowp_ivec2 aligned_ivec2; typedef aligned_lowp_ivec3 aligned_ivec3; typedef aligned_lowp_ivec4 aligned_ivec4; #elif(defined(GLM_PRECISION_MEDIUMP_INT)) typedef aligned_mediump_ivec1 aligned_ivec1; typedef aligned_mediump_ivec2 aligned_ivec2; typedef aligned_mediump_ivec3 aligned_ivec3; typedef aligned_mediump_ivec4 aligned_ivec4; #else //defined(GLM_PRECISION_HIGHP_INT) /// 1 component vector aligned in memory of signed integer numbers. typedef aligned_highp_ivec1 aligned_ivec1; /// 2 components vector aligned in memory of signed integer numbers. typedef aligned_highp_ivec2 aligned_ivec2; /// 3 components vector aligned in memory of signed integer numbers. typedef aligned_highp_ivec3 aligned_ivec3; /// 4 components vector aligned in memory of signed integer numbers. typedef aligned_highp_ivec4 aligned_ivec4; /// 1 component vector tightly packed in memory of signed integer numbers. typedef packed_highp_ivec1 packed_ivec1; /// 2 components vector tightly packed in memory of signed integer numbers. typedef packed_highp_ivec2 packed_ivec2; /// 3 components vector tightly packed in memory of signed integer numbers. typedef packed_highp_ivec3 packed_ivec3; /// 4 components vector tightly packed in memory of signed integer numbers. typedef packed_highp_ivec4 packed_ivec4; #endif//GLM_PRECISION // -- Unsigned integer definition -- #if(defined(GLM_PRECISION_LOWP_UINT)) typedef aligned_lowp_uvec1 aligned_uvec1; typedef aligned_lowp_uvec2 aligned_uvec2; typedef aligned_lowp_uvec3 aligned_uvec3; typedef aligned_lowp_uvec4 aligned_uvec4; #elif(defined(GLM_PRECISION_MEDIUMP_UINT)) typedef aligned_mediump_uvec1 aligned_uvec1; typedef aligned_mediump_uvec2 aligned_uvec2; typedef aligned_mediump_uvec3 aligned_uvec3; typedef aligned_mediump_uvec4 aligned_uvec4; #else //defined(GLM_PRECISION_HIGHP_UINT) /// 1 component vector aligned in memory of unsigned integer numbers. typedef aligned_highp_uvec1 aligned_uvec1; /// 2 components vector aligned in memory of unsigned integer numbers. typedef aligned_highp_uvec2 aligned_uvec2; /// 3 components vector aligned in memory of unsigned integer numbers. typedef aligned_highp_uvec3 aligned_uvec3; /// 4 components vector aligned in memory of unsigned integer numbers. typedef aligned_highp_uvec4 aligned_uvec4; /// 1 component vector tightly packed in memory of unsigned integer numbers. typedef packed_highp_uvec1 packed_uvec1; /// 2 components vector tightly packed in memory of unsigned integer numbers. typedef packed_highp_uvec2 packed_uvec2; /// 3 components vector tightly packed in memory of unsigned integer numbers. typedef packed_highp_uvec3 packed_uvec3; /// 4 components vector tightly packed in memory of unsigned integer numbers. typedef packed_highp_uvec4 packed_uvec4; #endif//GLM_PRECISION #if(defined(GLM_PRECISION_LOWP_BOOL)) typedef aligned_lowp_bvec1 aligned_bvec1; typedef aligned_lowp_bvec2 aligned_bvec2; typedef aligned_lowp_bvec3 aligned_bvec3; typedef aligned_lowp_bvec4 aligned_bvec4; #elif(defined(GLM_PRECISION_MEDIUMP_BOOL)) typedef aligned_mediump_bvec1 aligned_bvec1; typedef aligned_mediump_bvec2 aligned_bvec2; typedef aligned_mediump_bvec3 aligned_bvec3; typedef aligned_mediump_bvec4 aligned_bvec4; #else //defined(GLM_PRECISION_HIGHP_BOOL) /// 1 component vector aligned in memory of bool values. typedef aligned_highp_bvec1 aligned_bvec1; /// 2 components vector aligned in memory of bool values. typedef aligned_highp_bvec2 aligned_bvec2; /// 3 components vector aligned in memory of bool values. typedef aligned_highp_bvec3 aligned_bvec3; /// 4 components vector aligned in memory of bool values. typedef aligned_highp_bvec4 aligned_bvec4; /// 1 components vector tightly packed in memory of bool values. typedef packed_highp_bvec1 packed_bvec1; /// 2 components vector tightly packed in memory of bool values. typedef packed_highp_bvec2 packed_bvec2; /// 3 components vector tightly packed in memory of bool values. typedef packed_highp_bvec3 packed_bvec3; /// 4 components vector tightly packed in memory of bool values. typedef packed_highp_bvec4 packed_bvec4; #endif//GLM_PRECISION /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtc/type_precision.hpp000066400000000000000000002023761360521144700246510ustar00rootroot00000000000000/// @ref gtc_type_precision /// @file glm/gtc/type_precision.hpp /// /// @see core (dependence) /// @see gtc_quaternion (dependence) /// /// @defgroup gtc_type_precision GLM_GTC_type_precision /// @ingroup gtc /// /// Include to use the features of this extension. /// /// Defines specific C++-based qualifier types. #pragma once // Dependency: #include "../gtc/quaternion.hpp" #include "../gtc/vec1.hpp" #include "../ext/scalar_int_sized.hpp" #include "../ext/scalar_uint_sized.hpp" #include "../detail/type_vec2.hpp" #include "../detail/type_vec3.hpp" #include "../detail/type_vec4.hpp" #include "../detail/type_mat2x2.hpp" #include "../detail/type_mat2x3.hpp" #include "../detail/type_mat2x4.hpp" #include "../detail/type_mat3x2.hpp" #include "../detail/type_mat3x3.hpp" #include "../detail/type_mat3x4.hpp" #include "../detail/type_mat4x2.hpp" #include "../detail/type_mat4x3.hpp" #include "../detail/type_mat4x4.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_GTC_type_precision extension included") #endif namespace glm { /////////////////////////// // Signed int vector types /// @addtogroup gtc_type_precision /// @{ /// Low qualifier 8 bit signed integer type. /// @see gtc_type_precision typedef detail::int8 lowp_int8; /// Low qualifier 16 bit signed integer type. /// @see gtc_type_precision typedef detail::int16 lowp_int16; /// Low qualifier 32 bit signed integer type. /// @see gtc_type_precision typedef detail::int32 lowp_int32; /// Low qualifier 64 bit signed integer type. /// @see gtc_type_precision typedef detail::int64 lowp_int64; /// Low qualifier 8 bit signed integer type. /// @see gtc_type_precision typedef detail::int8 lowp_int8_t; /// Low qualifier 16 bit signed integer type. /// @see gtc_type_precision typedef detail::int16 lowp_int16_t; /// Low qualifier 32 bit signed integer type. /// @see gtc_type_precision typedef detail::int32 lowp_int32_t; /// Low qualifier 64 bit signed integer type. /// @see gtc_type_precision typedef detail::int64 lowp_int64_t; /// Low qualifier 8 bit signed integer type. /// @see gtc_type_precision typedef detail::int8 lowp_i8; /// Low qualifier 16 bit signed integer type. /// @see gtc_type_precision typedef detail::int16 lowp_i16; /// Low qualifier 32 bit signed integer type. /// @see gtc_type_precision typedef detail::int32 lowp_i32; /// Low qualifier 64 bit signed integer type. /// @see gtc_type_precision typedef detail::int64 lowp_i64; /// Medium qualifier 8 bit signed integer type. /// @see gtc_type_precision typedef detail::int8 mediump_int8; /// Medium qualifier 16 bit signed integer type. /// @see gtc_type_precision typedef detail::int16 mediump_int16; /// Medium qualifier 32 bit signed integer type. /// @see gtc_type_precision typedef detail::int32 mediump_int32; /// Medium qualifier 64 bit signed integer type. /// @see gtc_type_precision typedef detail::int64 mediump_int64; /// Medium qualifier 8 bit signed integer type. /// @see gtc_type_precision typedef detail::int8 mediump_int8_t; /// Medium qualifier 16 bit signed integer type. /// @see gtc_type_precision typedef detail::int16 mediump_int16_t; /// Medium qualifier 32 bit signed integer type. /// @see gtc_type_precision typedef detail::int32 mediump_int32_t; /// Medium qualifier 64 bit signed integer type. /// @see gtc_type_precision typedef detail::int64 mediump_int64_t; /// Medium qualifier 8 bit signed integer type. /// @see gtc_type_precision typedef detail::int8 mediump_i8; /// Medium qualifier 16 bit signed integer type. /// @see gtc_type_precision typedef detail::int16 mediump_i16; /// Medium qualifier 32 bit signed integer type. /// @see gtc_type_precision typedef detail::int32 mediump_i32; /// Medium qualifier 64 bit signed integer type. /// @see gtc_type_precision typedef detail::int64 mediump_i64; /// High qualifier 8 bit signed integer type. /// @see gtc_type_precision typedef detail::int8 highp_int8; /// High qualifier 16 bit signed integer type. /// @see gtc_type_precision typedef detail::int16 highp_int16; /// High qualifier 32 bit signed integer type. /// @see gtc_type_precision typedef detail::int32 highp_int32; /// High qualifier 64 bit signed integer type. /// @see gtc_type_precision typedef detail::int64 highp_int64; /// High qualifier 8 bit signed integer type. /// @see gtc_type_precision typedef detail::int8 highp_int8_t; /// High qualifier 16 bit signed integer type. /// @see gtc_type_precision typedef detail::int16 highp_int16_t; /// 32 bit signed integer type. /// @see gtc_type_precision typedef detail::int32 highp_int32_t; /// High qualifier 64 bit signed integer type. /// @see gtc_type_precision typedef detail::int64 highp_int64_t; /// High qualifier 8 bit signed integer type. /// @see gtc_type_precision typedef detail::int8 highp_i8; /// High qualifier 16 bit signed integer type. /// @see gtc_type_precision typedef detail::int16 highp_i16; /// High qualifier 32 bit signed integer type. /// @see gtc_type_precision typedef detail::int32 highp_i32; /// High qualifier 64 bit signed integer type. /// @see gtc_type_precision typedef detail::int64 highp_i64; #if GLM_HAS_EXTENDED_INTEGER_TYPE using std::int8_t; using std::int16_t; using std::int32_t; using std::int64_t; #else /// 8 bit signed integer type. /// @see gtc_type_precision typedef detail::int8 int8_t; /// 16 bit signed integer type. /// @see gtc_type_precision typedef detail::int16 int16_t; /// 32 bit signed integer type. /// @see gtc_type_precision typedef detail::int32 int32_t; /// 64 bit signed integer type. /// @see gtc_type_precision typedef detail::int64 int64_t; #endif /// 8 bit signed integer type. /// @see gtc_type_precision typedef detail::int8 i8; /// 16 bit signed integer type. /// @see gtc_type_precision typedef detail::int16 i16; /// 32 bit signed integer type. /// @see gtc_type_precision typedef detail::int32 i32; /// 64 bit signed integer type. /// @see gtc_type_precision typedef detail::int64 i64; /// Low qualifier 8 bit signed integer scalar type. /// @see gtc_type_precision typedef vec<1, i8, lowp> lowp_i8vec1; /// Low qualifier 8 bit signed integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, i8, lowp> lowp_i8vec2; /// Low qualifier 8 bit signed integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, i8, lowp> lowp_i8vec3; /// Low qualifier 8 bit signed integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, i8, lowp> lowp_i8vec4; /// Medium qualifier 8 bit signed integer scalar type. /// @see gtc_type_precision typedef vec<1, i8, mediump> mediump_i8vec1; /// Medium qualifier 8 bit signed integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, i8, mediump> mediump_i8vec2; /// Medium qualifier 8 bit signed integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, i8, mediump> mediump_i8vec3; /// Medium qualifier 8 bit signed integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, i8, mediump> mediump_i8vec4; /// High qualifier 8 bit signed integer scalar type. /// @see gtc_type_precision typedef vec<1, i8, highp> highp_i8vec1; /// High qualifier 8 bit signed integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, i8, highp> highp_i8vec2; /// High qualifier 8 bit signed integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, i8, highp> highp_i8vec3; /// High qualifier 8 bit signed integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, i8, highp> highp_i8vec4; /// 8 bit signed integer scalar type. /// @see gtc_type_precision typedef vec<1, i8, defaultp> i8vec1; /// 8 bit signed integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, i8, defaultp> i8vec2; /// 8 bit signed integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, i8, defaultp> i8vec3; /// 8 bit signed integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, i8, defaultp> i8vec4; /// Low qualifier 16 bit signed integer scalar type. /// @see gtc_type_precision typedef vec<1, i16, lowp> lowp_i16vec1; /// Low qualifier 16 bit signed integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, i16, lowp> lowp_i16vec2; /// Low qualifier 16 bit signed integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, i16, lowp> lowp_i16vec3; /// Low qualifier 16 bit signed integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, i16, lowp> lowp_i16vec4; /// Medium qualifier 16 bit signed integer scalar type. /// @see gtc_type_precision typedef vec<1, i16, mediump> mediump_i16vec1; /// Medium qualifier 16 bit signed integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, i16, mediump> mediump_i16vec2; /// Medium qualifier 16 bit signed integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, i16, mediump> mediump_i16vec3; /// Medium qualifier 16 bit signed integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, i16, mediump> mediump_i16vec4; /// High qualifier 16 bit signed integer scalar type. /// @see gtc_type_precision typedef vec<1, i16, highp> highp_i16vec1; /// High qualifier 16 bit signed integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, i16, highp> highp_i16vec2; /// High qualifier 16 bit signed integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, i16, highp> highp_i16vec3; /// High qualifier 16 bit signed integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, i16, highp> highp_i16vec4; /// 16 bit signed integer scalar type. /// @see gtc_type_precision typedef vec<1, i16, defaultp> i16vec1; /// 16 bit signed integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, i16, defaultp> i16vec2; /// 16 bit signed integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, i16, defaultp> i16vec3; /// 16 bit signed integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, i16, defaultp> i16vec4; /// Low qualifier 32 bit signed integer scalar type. /// @see gtc_type_precision typedef vec<1, i32, lowp> lowp_i32vec1; /// Low qualifier 32 bit signed integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, i32, lowp> lowp_i32vec2; /// Low qualifier 32 bit signed integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, i32, lowp> lowp_i32vec3; /// Low qualifier 32 bit signed integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, i32, lowp> lowp_i32vec4; /// Medium qualifier 32 bit signed integer scalar type. /// @see gtc_type_precision typedef vec<1, i32, mediump> mediump_i32vec1; /// Medium qualifier 32 bit signed integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, i32, mediump> mediump_i32vec2; /// Medium qualifier 32 bit signed integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, i32, mediump> mediump_i32vec3; /// Medium qualifier 32 bit signed integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, i32, mediump> mediump_i32vec4; /// High qualifier 32 bit signed integer scalar type. /// @see gtc_type_precision typedef vec<1, i32, highp> highp_i32vec1; /// High qualifier 32 bit signed integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, i32, highp> highp_i32vec2; /// High qualifier 32 bit signed integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, i32, highp> highp_i32vec3; /// High qualifier 32 bit signed integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, i32, highp> highp_i32vec4; /// 32 bit signed integer scalar type. /// @see gtc_type_precision typedef vec<1, i32, defaultp> i32vec1; /// 32 bit signed integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, i32, defaultp> i32vec2; /// 32 bit signed integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, i32, defaultp> i32vec3; /// 32 bit signed integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, i32, defaultp> i32vec4; /// Low qualifier 64 bit signed integer scalar type. /// @see gtc_type_precision typedef vec<1, i64, lowp> lowp_i64vec1; /// Low qualifier 64 bit signed integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, i64, lowp> lowp_i64vec2; /// Low qualifier 64 bit signed integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, i64, lowp> lowp_i64vec3; /// Low qualifier 64 bit signed integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, i64, lowp> lowp_i64vec4; /// Medium qualifier 64 bit signed integer scalar type. /// @see gtc_type_precision typedef vec<1, i64, mediump> mediump_i64vec1; /// Medium qualifier 64 bit signed integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, i64, mediump> mediump_i64vec2; /// Medium qualifier 64 bit signed integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, i64, mediump> mediump_i64vec3; /// Medium qualifier 64 bit signed integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, i64, mediump> mediump_i64vec4; /// High qualifier 64 bit signed integer scalar type. /// @see gtc_type_precision typedef vec<1, i64, highp> highp_i64vec1; /// High qualifier 64 bit signed integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, i64, highp> highp_i64vec2; /// High qualifier 64 bit signed integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, i64, highp> highp_i64vec3; /// High qualifier 64 bit signed integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, i64, highp> highp_i64vec4; /// 64 bit signed integer scalar type. /// @see gtc_type_precision typedef vec<1, i64, defaultp> i64vec1; /// 64 bit signed integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, i64, defaultp> i64vec2; /// 64 bit signed integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, i64, defaultp> i64vec3; /// 64 bit signed integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, i64, defaultp> i64vec4; ///////////////////////////// // Unsigned int vector types /// Low qualifier 8 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint8 lowp_uint8; /// Low qualifier 16 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint16 lowp_uint16; /// Low qualifier 32 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint32 lowp_uint32; /// Low qualifier 64 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint64 lowp_uint64; /// Low qualifier 8 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint8 lowp_uint8_t; /// Low qualifier 16 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint16 lowp_uint16_t; /// Low qualifier 32 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint32 lowp_uint32_t; /// Low qualifier 64 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint64 lowp_uint64_t; /// Low qualifier 8 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint8 lowp_u8; /// Low qualifier 16 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint16 lowp_u16; /// Low qualifier 32 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint32 lowp_u32; /// Low qualifier 64 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint64 lowp_u64; /// Medium qualifier 8 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint8 mediump_uint8; /// Medium qualifier 16 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint16 mediump_uint16; /// Medium qualifier 32 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint32 mediump_uint32; /// Medium qualifier 64 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint64 mediump_uint64; /// Medium qualifier 8 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint8 mediump_uint8_t; /// Medium qualifier 16 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint16 mediump_uint16_t; /// Medium qualifier 32 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint32 mediump_uint32_t; /// Medium qualifier 64 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint64 mediump_uint64_t; /// Medium qualifier 8 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint8 mediump_u8; /// Medium qualifier 16 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint16 mediump_u16; /// Medium qualifier 32 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint32 mediump_u32; /// Medium qualifier 64 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint64 mediump_u64; /// High qualifier 8 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint8 highp_uint8; /// High qualifier 16 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint16 highp_uint16; /// High qualifier 32 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint32 highp_uint32; /// High qualifier 64 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint64 highp_uint64; /// High qualifier 8 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint8 highp_uint8_t; /// High qualifier 16 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint16 highp_uint16_t; /// High qualifier 32 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint32 highp_uint32_t; /// High qualifier 64 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint64 highp_uint64_t; /// High qualifier 8 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint8 highp_u8; /// High qualifier 16 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint16 highp_u16; /// High qualifier 32 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint32 highp_u32; /// High qualifier 64 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint64 highp_u64; #if GLM_HAS_EXTENDED_INTEGER_TYPE using std::uint8_t; using std::uint16_t; using std::uint32_t; using std::uint64_t; #else /// Default qualifier 8 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint8 uint8_t; /// Default qualifier 16 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint16 uint16_t; /// Default qualifier 32 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint32 uint32_t; /// Default qualifier 64 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint64 uint64_t; #endif /// Default qualifier 8 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint8 u8; /// Default qualifier 16 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint16 u16; /// Default qualifier 32 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint32 u32; /// Default qualifier 64 bit unsigned integer type. /// @see gtc_type_precision typedef detail::uint64 u64; ////////////////////// // Float vector types /// Single-qualifier floating-point scalar. /// @see gtc_type_precision typedef float float32; /// Double-qualifier floating-point scalar. /// @see gtc_type_precision typedef double float64; /// Low 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef float32 lowp_float32; /// Low 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef float64 lowp_float64; /// Low 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef float32 lowp_float32_t; /// Low 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef float64 lowp_float64_t; /// Low 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef float32 lowp_f32; /// Low 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef float64 lowp_f64; /// Low 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef float32 lowp_float32; /// Low 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef float64 lowp_float64; /// Low 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef float32 lowp_float32_t; /// Low 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef float64 lowp_float64_t; /// Low 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef float32 lowp_f32; /// Low 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef float64 lowp_f64; /// Low 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef float32 lowp_float32; /// Low 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef float64 lowp_float64; /// Low 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef float32 lowp_float32_t; /// Low 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef float64 lowp_float64_t; /// Low 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef float32 lowp_f32; /// Low 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef float64 lowp_f64; /// Medium 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef float32 mediump_float32; /// Medium 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef float64 mediump_float64; /// Medium 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef float32 mediump_float32_t; /// Medium 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef float64 mediump_float64_t; /// Medium 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef float32 mediump_f32; /// Medium 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef float64 mediump_f64; /// High 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef float32 highp_float32; /// High 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef float64 highp_float64; /// High 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef float32 highp_float32_t; /// High 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef float64 highp_float64_t; /// High 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef float32 highp_f32; /// High 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef float64 highp_f64; #if(defined(GLM_PRECISION_LOWP_FLOAT)) /// Default 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef lowp_float32_t float32_t; /// Default 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef lowp_float64_t float64_t; /// Default 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef lowp_f32 f32; /// Default 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef lowp_f64 f64; #elif(defined(GLM_PRECISION_MEDIUMP_FLOAT)) /// Default 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef mediump_float32 float32_t; /// Default 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef mediump_float64 float64_t; /// Default 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef mediump_float32 f32; /// Default 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef mediump_float64 f64; #else//(defined(GLM_PRECISION_HIGHP_FLOAT)) /// Default 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef highp_float32_t float32_t; /// Default 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef highp_float64_t float64_t; /// Default 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef highp_float32_t f32; /// Default 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef highp_float64_t f64; #endif /// Low single-qualifier floating-point vector of 1 component. /// @see gtc_type_precision typedef vec<1, float, lowp> lowp_fvec1; /// Low single-qualifier floating-point vector of 2 components. /// @see gtc_type_precision typedef vec<2, float, lowp> lowp_fvec2; /// Low single-qualifier floating-point vector of 3 components. /// @see gtc_type_precision typedef vec<3, float, lowp> lowp_fvec3; /// Low single-qualifier floating-point vector of 4 components. /// @see gtc_type_precision typedef vec<4, float, lowp> lowp_fvec4; /// Medium single-qualifier floating-point vector of 1 component. /// @see gtc_type_precision typedef vec<1, float, mediump> mediump_fvec1; /// Medium Single-qualifier floating-point vector of 2 components. /// @see gtc_type_precision typedef vec<2, float, mediump> mediump_fvec2; /// Medium Single-qualifier floating-point vector of 3 components. /// @see gtc_type_precision typedef vec<3, float, mediump> mediump_fvec3; /// Medium Single-qualifier floating-point vector of 4 components. /// @see gtc_type_precision typedef vec<4, float, mediump> mediump_fvec4; /// High single-qualifier floating-point vector of 1 component. /// @see gtc_type_precision typedef vec<1, float, highp> highp_fvec1; /// High Single-qualifier floating-point vector of 2 components. /// @see core_precision typedef vec<2, float, highp> highp_fvec2; /// High Single-qualifier floating-point vector of 3 components. /// @see core_precision typedef vec<3, float, highp> highp_fvec3; /// High Single-qualifier floating-point vector of 4 components. /// @see core_precision typedef vec<4, float, highp> highp_fvec4; /// Low single-qualifier floating-point vector of 1 component. /// @see gtc_type_precision typedef vec<1, f32, lowp> lowp_f32vec1; /// Low single-qualifier floating-point vector of 2 components. /// @see core_precision typedef vec<2, f32, lowp> lowp_f32vec2; /// Low single-qualifier floating-point vector of 3 components. /// @see core_precision typedef vec<3, f32, lowp> lowp_f32vec3; /// Low single-qualifier floating-point vector of 4 components. /// @see core_precision typedef vec<4, f32, lowp> lowp_f32vec4; /// Medium single-qualifier floating-point vector of 1 component. /// @see gtc_type_precision typedef vec<1, f32, mediump> mediump_f32vec1; /// Medium single-qualifier floating-point vector of 2 components. /// @see core_precision typedef vec<2, f32, mediump> mediump_f32vec2; /// Medium single-qualifier floating-point vector of 3 components. /// @see core_precision typedef vec<3, f32, mediump> mediump_f32vec3; /// Medium single-qualifier floating-point vector of 4 components. /// @see core_precision typedef vec<4, f32, mediump> mediump_f32vec4; /// High single-qualifier floating-point vector of 1 component. /// @see gtc_type_precision typedef vec<1, f32, highp> highp_f32vec1; /// High single-qualifier floating-point vector of 2 components. /// @see gtc_type_precision typedef vec<2, f32, highp> highp_f32vec2; /// High single-qualifier floating-point vector of 3 components. /// @see gtc_type_precision typedef vec<3, f32, highp> highp_f32vec3; /// High single-qualifier floating-point vector of 4 components. /// @see gtc_type_precision typedef vec<4, f32, highp> highp_f32vec4; /// Low double-qualifier floating-point vector of 1 component. /// @see gtc_type_precision typedef vec<1, f64, lowp> lowp_f64vec1; /// Low double-qualifier floating-point vector of 2 components. /// @see gtc_type_precision typedef vec<2, f64, lowp> lowp_f64vec2; /// Low double-qualifier floating-point vector of 3 components. /// @see gtc_type_precision typedef vec<3, f64, lowp> lowp_f64vec3; /// Low double-qualifier floating-point vector of 4 components. /// @see gtc_type_precision typedef vec<4, f64, lowp> lowp_f64vec4; /// Medium double-qualifier floating-point vector of 1 component. /// @see gtc_type_precision typedef vec<1, f64, mediump> mediump_f64vec1; /// Medium double-qualifier floating-point vector of 2 components. /// @see gtc_type_precision typedef vec<2, f64, mediump> mediump_f64vec2; /// Medium double-qualifier floating-point vector of 3 components. /// @see gtc_type_precision typedef vec<3, f64, mediump> mediump_f64vec3; /// Medium double-qualifier floating-point vector of 4 components. /// @see gtc_type_precision typedef vec<4, f64, mediump> mediump_f64vec4; /// High double-qualifier floating-point vector of 1 component. /// @see gtc_type_precision typedef vec<1, f64, highp> highp_f64vec1; /// High double-qualifier floating-point vector of 2 components. /// @see gtc_type_precision typedef vec<2, f64, highp> highp_f64vec2; /// High double-qualifier floating-point vector of 3 components. /// @see gtc_type_precision typedef vec<3, f64, highp> highp_f64vec3; /// High double-qualifier floating-point vector of 4 components. /// @see gtc_type_precision typedef vec<4, f64, highp> highp_f64vec4; ////////////////////// // Float matrix types /// Low single-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef lowp_f32 lowp_fmat1x1; /// Low single-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef mat<2, 2, f32, lowp> lowp_fmat2x2; /// Low single-qualifier floating-point 2x3 matrix. /// @see gtc_type_precision typedef mat<2, 3, f32, lowp> lowp_fmat2x3; /// Low single-qualifier floating-point 2x4 matrix. /// @see gtc_type_precision typedef mat<2, 4, f32, lowp> lowp_fmat2x4; /// Low single-qualifier floating-point 3x2 matrix. /// @see gtc_type_precision typedef mat<3, 2, f32, lowp> lowp_fmat3x2; /// Low single-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef mat<3, 3, f32, lowp> lowp_fmat3x3; /// Low single-qualifier floating-point 3x4 matrix. /// @see gtc_type_precision typedef mat<3, 4, f32, lowp> lowp_fmat3x4; /// Low single-qualifier floating-point 4x2 matrix. /// @see gtc_type_precision typedef mat<4, 2, f32, lowp> lowp_fmat4x2; /// Low single-qualifier floating-point 4x3 matrix. /// @see gtc_type_precision typedef mat<4, 3, f32, lowp> lowp_fmat4x3; /// Low single-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef mat<4, 4, f32, lowp> lowp_fmat4x4; /// Low single-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef lowp_fmat1x1 lowp_fmat1; /// Low single-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef lowp_fmat2x2 lowp_fmat2; /// Low single-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef lowp_fmat3x3 lowp_fmat3; /// Low single-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef lowp_fmat4x4 lowp_fmat4; /// Medium single-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef mediump_f32 mediump_fmat1x1; /// Medium single-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef mat<2, 2, f32, mediump> mediump_fmat2x2; /// Medium single-qualifier floating-point 2x3 matrix. /// @see gtc_type_precision typedef mat<2, 3, f32, mediump> mediump_fmat2x3; /// Medium single-qualifier floating-point 2x4 matrix. /// @see gtc_type_precision typedef mat<2, 4, f32, mediump> mediump_fmat2x4; /// Medium single-qualifier floating-point 3x2 matrix. /// @see gtc_type_precision typedef mat<3, 2, f32, mediump> mediump_fmat3x2; /// Medium single-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef mat<3, 3, f32, mediump> mediump_fmat3x3; /// Medium single-qualifier floating-point 3x4 matrix. /// @see gtc_type_precision typedef mat<3, 4, f32, mediump> mediump_fmat3x4; /// Medium single-qualifier floating-point 4x2 matrix. /// @see gtc_type_precision typedef mat<4, 2, f32, mediump> mediump_fmat4x2; /// Medium single-qualifier floating-point 4x3 matrix. /// @see gtc_type_precision typedef mat<4, 3, f32, mediump> mediump_fmat4x3; /// Medium single-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef mat<4, 4, f32, mediump> mediump_fmat4x4; /// Medium single-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef mediump_fmat1x1 mediump_fmat1; /// Medium single-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef mediump_fmat2x2 mediump_fmat2; /// Medium single-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef mediump_fmat3x3 mediump_fmat3; /// Medium single-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef mediump_fmat4x4 mediump_fmat4; /// High single-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef highp_f32 highp_fmat1x1; /// High single-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef mat<2, 2, f32, highp> highp_fmat2x2; /// High single-qualifier floating-point 2x3 matrix. /// @see gtc_type_precision typedef mat<2, 3, f32, highp> highp_fmat2x3; /// High single-qualifier floating-point 2x4 matrix. /// @see gtc_type_precision typedef mat<2, 4, f32, highp> highp_fmat2x4; /// High single-qualifier floating-point 3x2 matrix. /// @see gtc_type_precision typedef mat<3, 2, f32, highp> highp_fmat3x2; /// High single-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef mat<3, 3, f32, highp> highp_fmat3x3; /// High single-qualifier floating-point 3x4 matrix. /// @see gtc_type_precision typedef mat<3, 4, f32, highp> highp_fmat3x4; /// High single-qualifier floating-point 4x2 matrix. /// @see gtc_type_precision typedef mat<4, 2, f32, highp> highp_fmat4x2; /// High single-qualifier floating-point 4x3 matrix. /// @see gtc_type_precision typedef mat<4, 3, f32, highp> highp_fmat4x3; /// High single-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef mat<4, 4, f32, highp> highp_fmat4x4; /// High single-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef highp_fmat1x1 highp_fmat1; /// High single-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef highp_fmat2x2 highp_fmat2; /// High single-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef highp_fmat3x3 highp_fmat3; /// High single-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef highp_fmat4x4 highp_fmat4; /// Low single-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef f32 lowp_f32mat1x1; /// Low single-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef mat<2, 2, f32, lowp> lowp_f32mat2x2; /// Low single-qualifier floating-point 2x3 matrix. /// @see gtc_type_precision typedef mat<2, 3, f32, lowp> lowp_f32mat2x3; /// Low single-qualifier floating-point 2x4 matrix. /// @see gtc_type_precision typedef mat<2, 4, f32, lowp> lowp_f32mat2x4; /// Low single-qualifier floating-point 3x2 matrix. /// @see gtc_type_precision typedef mat<3, 2, f32, lowp> lowp_f32mat3x2; /// Low single-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef mat<3, 3, f32, lowp> lowp_f32mat3x3; /// Low single-qualifier floating-point 3x4 matrix. /// @see gtc_type_precision typedef mat<3, 4, f32, lowp> lowp_f32mat3x4; /// Low single-qualifier floating-point 4x2 matrix. /// @see gtc_type_precision typedef mat<4, 2, f32, lowp> lowp_f32mat4x2; /// Low single-qualifier floating-point 4x3 matrix. /// @see gtc_type_precision typedef mat<4, 3, f32, lowp> lowp_f32mat4x3; /// Low single-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef mat<4, 4, f32, lowp> lowp_f32mat4x4; /// Low single-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef detail::tmat1x1 lowp_f32mat1; /// Low single-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef lowp_f32mat2x2 lowp_f32mat2; /// Low single-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef lowp_f32mat3x3 lowp_f32mat3; /// Low single-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef lowp_f32mat4x4 lowp_f32mat4; /// High single-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef f32 mediump_f32mat1x1; /// Low single-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef mat<2, 2, f32, mediump> mediump_f32mat2x2; /// Medium single-qualifier floating-point 2x3 matrix. /// @see gtc_type_precision typedef mat<2, 3, f32, mediump> mediump_f32mat2x3; /// Medium single-qualifier floating-point 2x4 matrix. /// @see gtc_type_precision typedef mat<2, 4, f32, mediump> mediump_f32mat2x4; /// Medium single-qualifier floating-point 3x2 matrix. /// @see gtc_type_precision typedef mat<3, 2, f32, mediump> mediump_f32mat3x2; /// Medium single-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef mat<3, 3, f32, mediump> mediump_f32mat3x3; /// Medium single-qualifier floating-point 3x4 matrix. /// @see gtc_type_precision typedef mat<3, 4, f32, mediump> mediump_f32mat3x4; /// Medium single-qualifier floating-point 4x2 matrix. /// @see gtc_type_precision typedef mat<4, 2, f32, mediump> mediump_f32mat4x2; /// Medium single-qualifier floating-point 4x3 matrix. /// @see gtc_type_precision typedef mat<4, 3, f32, mediump> mediump_f32mat4x3; /// Medium single-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef mat<4, 4, f32, mediump> mediump_f32mat4x4; /// Medium single-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef detail::tmat1x1 f32mat1; /// Medium single-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef mediump_f32mat2x2 mediump_f32mat2; /// Medium single-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef mediump_f32mat3x3 mediump_f32mat3; /// Medium single-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef mediump_f32mat4x4 mediump_f32mat4; /// High single-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef f32 highp_f32mat1x1; /// High single-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef mat<2, 2, f32, highp> highp_f32mat2x2; /// High single-qualifier floating-point 2x3 matrix. /// @see gtc_type_precision typedef mat<2, 3, f32, highp> highp_f32mat2x3; /// High single-qualifier floating-point 2x4 matrix. /// @see gtc_type_precision typedef mat<2, 4, f32, highp> highp_f32mat2x4; /// High single-qualifier floating-point 3x2 matrix. /// @see gtc_type_precision typedef mat<3, 2, f32, highp> highp_f32mat3x2; /// High single-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef mat<3, 3, f32, highp> highp_f32mat3x3; /// High single-qualifier floating-point 3x4 matrix. /// @see gtc_type_precision typedef mat<3, 4, f32, highp> highp_f32mat3x4; /// High single-qualifier floating-point 4x2 matrix. /// @see gtc_type_precision typedef mat<4, 2, f32, highp> highp_f32mat4x2; /// High single-qualifier floating-point 4x3 matrix. /// @see gtc_type_precision typedef mat<4, 3, f32, highp> highp_f32mat4x3; /// High single-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef mat<4, 4, f32, highp> highp_f32mat4x4; /// High single-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef detail::tmat1x1 f32mat1; /// High single-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef highp_f32mat2x2 highp_f32mat2; /// High single-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef highp_f32mat3x3 highp_f32mat3; /// High single-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef highp_f32mat4x4 highp_f32mat4; /// Low double-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef f64 lowp_f64mat1x1; /// Low double-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef mat<2, 2, f64, lowp> lowp_f64mat2x2; /// Low double-qualifier floating-point 2x3 matrix. /// @see gtc_type_precision typedef mat<2, 3, f64, lowp> lowp_f64mat2x3; /// Low double-qualifier floating-point 2x4 matrix. /// @see gtc_type_precision typedef mat<2, 4, f64, lowp> lowp_f64mat2x4; /// Low double-qualifier floating-point 3x2 matrix. /// @see gtc_type_precision typedef mat<3, 2, f64, lowp> lowp_f64mat3x2; /// Low double-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef mat<3, 3, f64, lowp> lowp_f64mat3x3; /// Low double-qualifier floating-point 3x4 matrix. /// @see gtc_type_precision typedef mat<3, 4, f64, lowp> lowp_f64mat3x4; /// Low double-qualifier floating-point 4x2 matrix. /// @see gtc_type_precision typedef mat<4, 2, f64, lowp> lowp_f64mat4x2; /// Low double-qualifier floating-point 4x3 matrix. /// @see gtc_type_precision typedef mat<4, 3, f64, lowp> lowp_f64mat4x3; /// Low double-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef mat<4, 4, f64, lowp> lowp_f64mat4x4; /// Low double-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef lowp_f64mat1x1 lowp_f64mat1; /// Low double-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef lowp_f64mat2x2 lowp_f64mat2; /// Low double-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef lowp_f64mat3x3 lowp_f64mat3; /// Low double-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef lowp_f64mat4x4 lowp_f64mat4; /// Medium double-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef f64 Highp_f64mat1x1; /// Medium double-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef mat<2, 2, f64, mediump> mediump_f64mat2x2; /// Medium double-qualifier floating-point 2x3 matrix. /// @see gtc_type_precision typedef mat<2, 3, f64, mediump> mediump_f64mat2x3; /// Medium double-qualifier floating-point 2x4 matrix. /// @see gtc_type_precision typedef mat<2, 4, f64, mediump> mediump_f64mat2x4; /// Medium double-qualifier floating-point 3x2 matrix. /// @see gtc_type_precision typedef mat<3, 2, f64, mediump> mediump_f64mat3x2; /// Medium double-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef mat<3, 3, f64, mediump> mediump_f64mat3x3; /// Medium double-qualifier floating-point 3x4 matrix. /// @see gtc_type_precision typedef mat<3, 4, f64, mediump> mediump_f64mat3x4; /// Medium double-qualifier floating-point 4x2 matrix. /// @see gtc_type_precision typedef mat<4, 2, f64, mediump> mediump_f64mat4x2; /// Medium double-qualifier floating-point 4x3 matrix. /// @see gtc_type_precision typedef mat<4, 3, f64, mediump> mediump_f64mat4x3; /// Medium double-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef mat<4, 4, f64, mediump> mediump_f64mat4x4; /// Medium double-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef mediump_f64mat1x1 mediump_f64mat1; /// Medium double-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef mediump_f64mat2x2 mediump_f64mat2; /// Medium double-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef mediump_f64mat3x3 mediump_f64mat3; /// Medium double-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef mediump_f64mat4x4 mediump_f64mat4; /// High double-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef f64 highp_f64mat1x1; /// High double-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef mat<2, 2, f64, highp> highp_f64mat2x2; /// High double-qualifier floating-point 2x3 matrix. /// @see gtc_type_precision typedef mat<2, 3, f64, highp> highp_f64mat2x3; /// High double-qualifier floating-point 2x4 matrix. /// @see gtc_type_precision typedef mat<2, 4, f64, highp> highp_f64mat2x4; /// High double-qualifier floating-point 3x2 matrix. /// @see gtc_type_precision typedef mat<3, 2, f64, highp> highp_f64mat3x2; /// High double-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef mat<3, 3, f64, highp> highp_f64mat3x3; /// High double-qualifier floating-point 3x4 matrix. /// @see gtc_type_precision typedef mat<3, 4, f64, highp> highp_f64mat3x4; /// High double-qualifier floating-point 4x2 matrix. /// @see gtc_type_precision typedef mat<4, 2, f64, highp> highp_f64mat4x2; /// High double-qualifier floating-point 4x3 matrix. /// @see gtc_type_precision typedef mat<4, 3, f64, highp> highp_f64mat4x3; /// High double-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef mat<4, 4, f64, highp> highp_f64mat4x4; /// High double-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef highp_f64mat1x1 highp_f64mat1; /// High double-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef highp_f64mat2x2 highp_f64mat2; /// High double-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef highp_f64mat3x3 highp_f64mat3; /// High double-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef highp_f64mat4x4 highp_f64mat4; /// Low qualifier 8 bit unsigned integer scalar type. /// @see gtc_type_precision typedef vec<1, u8, lowp> lowp_u8vec1; /// Low qualifier 8 bit unsigned integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, u8, lowp> lowp_u8vec2; /// Low qualifier 8 bit unsigned integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, u8, lowp> lowp_u8vec3; /// Low qualifier 8 bit unsigned integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, u8, lowp> lowp_u8vec4; /// Medium qualifier 8 bit unsigned integer scalar type. /// @see gtc_type_precision typedef vec<1, u8, mediump> mediump_u8vec1; /// Medium qualifier 8 bit unsigned integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, u8, mediump> mediump_u8vec2; /// Medium qualifier 8 bit unsigned integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, u8, mediump> mediump_u8vec3; /// Medium qualifier 8 bit unsigned integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, u8, mediump> mediump_u8vec4; /// High qualifier 8 bit unsigned integer scalar type. /// @see gtc_type_precision typedef vec<1, u8, highp> highp_u8vec1; /// High qualifier 8 bit unsigned integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, u8, highp> highp_u8vec2; /// High qualifier 8 bit unsigned integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, u8, highp> highp_u8vec3; /// High qualifier 8 bit unsigned integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, u8, highp> highp_u8vec4; /// Default qualifier 8 bit unsigned integer scalar type. /// @see gtc_type_precision typedef vec<1, u8, defaultp> u8vec1; /// Default qualifier 8 bit unsigned integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, u8, defaultp> u8vec2; /// Default qualifier 8 bit unsigned integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, u8, defaultp> u8vec3; /// Default qualifier 8 bit unsigned integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, u8, defaultp> u8vec4; /// Low qualifier 16 bit unsigned integer scalar type. /// @see gtc_type_precision typedef vec<1, u16, lowp> lowp_u16vec1; /// Low qualifier 16 bit unsigned integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, u16, lowp> lowp_u16vec2; /// Low qualifier 16 bit unsigned integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, u16, lowp> lowp_u16vec3; /// Low qualifier 16 bit unsigned integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, u16, lowp> lowp_u16vec4; /// Medium qualifier 16 bit unsigned integer scalar type. /// @see gtc_type_precision typedef vec<1, u16, mediump> mediump_u16vec1; /// Medium qualifier 16 bit unsigned integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, u16, mediump> mediump_u16vec2; /// Medium qualifier 16 bit unsigned integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, u16, mediump> mediump_u16vec3; /// Medium qualifier 16 bit unsigned integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, u16, mediump> mediump_u16vec4; /// High qualifier 16 bit unsigned integer scalar type. /// @see gtc_type_precision typedef vec<1, u16, highp> highp_u16vec1; /// High qualifier 16 bit unsigned integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, u16, highp> highp_u16vec2; /// High qualifier 16 bit unsigned integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, u16, highp> highp_u16vec3; /// High qualifier 16 bit unsigned integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, u16, highp> highp_u16vec4; /// Default qualifier 16 bit unsigned integer scalar type. /// @see gtc_type_precision typedef vec<1, u16, defaultp> u16vec1; /// Default qualifier 16 bit unsigned integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, u16, defaultp> u16vec2; /// Default qualifier 16 bit unsigned integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, u16, defaultp> u16vec3; /// Default qualifier 16 bit unsigned integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, u16, defaultp> u16vec4; /// Low qualifier 32 bit unsigned integer scalar type. /// @see gtc_type_precision typedef vec<1, u32, lowp> lowp_u32vec1; /// Low qualifier 32 bit unsigned integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, u32, lowp> lowp_u32vec2; /// Low qualifier 32 bit unsigned integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, u32, lowp> lowp_u32vec3; /// Low qualifier 32 bit unsigned integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, u32, lowp> lowp_u32vec4; /// Medium qualifier 32 bit unsigned integer scalar type. /// @see gtc_type_precision typedef vec<1, u32, mediump> mediump_u32vec1; /// Medium qualifier 32 bit unsigned integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, u32, mediump> mediump_u32vec2; /// Medium qualifier 32 bit unsigned integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, u32, mediump> mediump_u32vec3; /// Medium qualifier 32 bit unsigned integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, u32, mediump> mediump_u32vec4; /// High qualifier 32 bit unsigned integer scalar type. /// @see gtc_type_precision typedef vec<1, u32, highp> highp_u32vec1; /// High qualifier 32 bit unsigned integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, u32, highp> highp_u32vec2; /// High qualifier 32 bit unsigned integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, u32, highp> highp_u32vec3; /// High qualifier 32 bit unsigned integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, u32, highp> highp_u32vec4; /// Default qualifier 32 bit unsigned integer scalar type. /// @see gtc_type_precision typedef vec<1, u32, defaultp> u32vec1; /// Default qualifier 32 bit unsigned integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, u32, defaultp> u32vec2; /// Default qualifier 32 bit unsigned integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, u32, defaultp> u32vec3; /// Default qualifier 32 bit unsigned integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, u32, defaultp> u32vec4; /// Low qualifier 64 bit unsigned integer scalar type. /// @see gtc_type_precision typedef vec<1, u64, lowp> lowp_u64vec1; /// Low qualifier 64 bit unsigned integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, u64, lowp> lowp_u64vec2; /// Low qualifier 64 bit unsigned integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, u64, lowp> lowp_u64vec3; /// Low qualifier 64 bit unsigned integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, u64, lowp> lowp_u64vec4; /// Medium qualifier 64 bit unsigned integer scalar type. /// @see gtc_type_precision typedef vec<1, u64, mediump> mediump_u64vec1; /// Medium qualifier 64 bit unsigned integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, u64, mediump> mediump_u64vec2; /// Medium qualifier 64 bit unsigned integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, u64, mediump> mediump_u64vec3; /// Medium qualifier 64 bit unsigned integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, u64, mediump> mediump_u64vec4; /// High qualifier 64 bit unsigned integer scalar type. /// @see gtc_type_precision typedef vec<1, u64, highp> highp_u64vec1; /// High qualifier 64 bit unsigned integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, u64, highp> highp_u64vec2; /// High qualifier 64 bit unsigned integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, u64, highp> highp_u64vec3; /// High qualifier 64 bit unsigned integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, u64, highp> highp_u64vec4; /// Default qualifier 64 bit unsigned integer scalar type. /// @see gtc_type_precision typedef vec<1, u64, defaultp> u64vec1; /// Default qualifier 64 bit unsigned integer vector of 2 components type. /// @see gtc_type_precision typedef vec<2, u64, defaultp> u64vec2; /// Default qualifier 64 bit unsigned integer vector of 3 components type. /// @see gtc_type_precision typedef vec<3, u64, defaultp> u64vec3; /// Default qualifier 64 bit unsigned integer vector of 4 components type. /// @see gtc_type_precision typedef vec<4, u64, defaultp> u64vec4; ////////////////////// // Float vector types /// 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef float32 float32_t; /// 32 bit single-qualifier floating-point scalar. /// @see gtc_type_precision typedef float32 f32; # ifndef GLM_FORCE_SINGLE_ONLY /// 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef float64 float64_t; /// 64 bit double-qualifier floating-point scalar. /// @see gtc_type_precision typedef float64 f64; # endif//GLM_FORCE_SINGLE_ONLY /// Single-qualifier floating-point vector of 1 component. /// @see gtc_type_precision typedef vec<1, float, defaultp> fvec1; /// Single-qualifier floating-point vector of 2 components. /// @see gtc_type_precision typedef vec<2, float, defaultp> fvec2; /// Single-qualifier floating-point vector of 3 components. /// @see gtc_type_precision typedef vec<3, float, defaultp> fvec3; /// Single-qualifier floating-point vector of 4 components. /// @see gtc_type_precision typedef vec<4, float, defaultp> fvec4; /// Single-qualifier floating-point vector of 1 component. /// @see gtc_type_precision typedef vec<1, f32, defaultp> f32vec1; /// Single-qualifier floating-point vector of 2 components. /// @see gtc_type_precision typedef vec<2, f32, defaultp> f32vec2; /// Single-qualifier floating-point vector of 3 components. /// @see gtc_type_precision typedef vec<3, f32, defaultp> f32vec3; /// Single-qualifier floating-point vector of 4 components. /// @see gtc_type_precision typedef vec<4, f32, defaultp> f32vec4; # ifndef GLM_FORCE_SINGLE_ONLY /// Double-qualifier floating-point vector of 1 component. /// @see gtc_type_precision typedef vec<1, f64, defaultp> f64vec1; /// Double-qualifier floating-point vector of 2 components. /// @see gtc_type_precision typedef vec<2, f64, defaultp> f64vec2; /// Double-qualifier floating-point vector of 3 components. /// @see gtc_type_precision typedef vec<3, f64, defaultp> f64vec3; /// Double-qualifier floating-point vector of 4 components. /// @see gtc_type_precision typedef vec<4, f64, defaultp> f64vec4; # endif//GLM_FORCE_SINGLE_ONLY ////////////////////// // Float matrix types /// Single-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef detail::tmat1x1 fmat1; /// Single-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef mat<2, 2, f32, defaultp> fmat2; /// Single-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef mat<3, 3, f32, defaultp> fmat3; /// Single-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef mat<4, 4, f32, defaultp> fmat4; /// Single-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef f32 fmat1x1; /// Single-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef mat<2, 2, f32, defaultp> fmat2x2; /// Single-qualifier floating-point 2x3 matrix. /// @see gtc_type_precision typedef mat<2, 3, f32, defaultp> fmat2x3; /// Single-qualifier floating-point 2x4 matrix. /// @see gtc_type_precision typedef mat<2, 4, f32, defaultp> fmat2x4; /// Single-qualifier floating-point 3x2 matrix. /// @see gtc_type_precision typedef mat<3, 2, f32, defaultp> fmat3x2; /// Single-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef mat<3, 3, f32, defaultp> fmat3x3; /// Single-qualifier floating-point 3x4 matrix. /// @see gtc_type_precision typedef mat<3, 4, f32, defaultp> fmat3x4; /// Single-qualifier floating-point 4x2 matrix. /// @see gtc_type_precision typedef mat<4, 2, f32, defaultp> fmat4x2; /// Single-qualifier floating-point 4x3 matrix. /// @see gtc_type_precision typedef mat<4, 3, f32, defaultp> fmat4x3; /// Single-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef mat<4, 4, f32, defaultp> fmat4x4; /// Single-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef detail::tmat1x1 f32mat1; /// Single-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef mat<2, 2, f32, defaultp> f32mat2; /// Single-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef mat<3, 3, f32, defaultp> f32mat3; /// Single-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef mat<4, 4, f32, defaultp> f32mat4; /// Single-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef f32 f32mat1x1; /// Single-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef mat<2, 2, f32, defaultp> f32mat2x2; /// Single-qualifier floating-point 2x3 matrix. /// @see gtc_type_precision typedef mat<2, 3, f32, defaultp> f32mat2x3; /// Single-qualifier floating-point 2x4 matrix. /// @see gtc_type_precision typedef mat<2, 4, f32, defaultp> f32mat2x4; /// Single-qualifier floating-point 3x2 matrix. /// @see gtc_type_precision typedef mat<3, 2, f32, defaultp> f32mat3x2; /// Single-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef mat<3, 3, f32, defaultp> f32mat3x3; /// Single-qualifier floating-point 3x4 matrix. /// @see gtc_type_precision typedef mat<3, 4, f32, defaultp> f32mat3x4; /// Single-qualifier floating-point 4x2 matrix. /// @see gtc_type_precision typedef mat<4, 2, f32, defaultp> f32mat4x2; /// Single-qualifier floating-point 4x3 matrix. /// @see gtc_type_precision typedef mat<4, 3, f32, defaultp> f32mat4x3; /// Single-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef mat<4, 4, f32, defaultp> f32mat4x4; # ifndef GLM_FORCE_SINGLE_ONLY /// Double-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef detail::tmat1x1 f64mat1; /// Double-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef mat<2, 2, f64, defaultp> f64mat2; /// Double-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef mat<3, 3, f64, defaultp> f64mat3; /// Double-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef mat<4, 4, f64, defaultp> f64mat4; /// Double-qualifier floating-point 1x1 matrix. /// @see gtc_type_precision //typedef f64 f64mat1x1; /// Double-qualifier floating-point 2x2 matrix. /// @see gtc_type_precision typedef mat<2, 2, f64, defaultp> f64mat2x2; /// Double-qualifier floating-point 2x3 matrix. /// @see gtc_type_precision typedef mat<2, 3, f64, defaultp> f64mat2x3; /// Double-qualifier floating-point 2x4 matrix. /// @see gtc_type_precision typedef mat<2, 4, f64, defaultp> f64mat2x4; /// Double-qualifier floating-point 3x2 matrix. /// @see gtc_type_precision typedef mat<3, 2, f64, defaultp> f64mat3x2; /// Double-qualifier floating-point 3x3 matrix. /// @see gtc_type_precision typedef mat<3, 3, f64, defaultp> f64mat3x3; /// Double-qualifier floating-point 3x4 matrix. /// @see gtc_type_precision typedef mat<3, 4, f64, defaultp> f64mat3x4; /// Double-qualifier floating-point 4x2 matrix. /// @see gtc_type_precision typedef mat<4, 2, f64, defaultp> f64mat4x2; /// Double-qualifier floating-point 4x3 matrix. /// @see gtc_type_precision typedef mat<4, 3, f64, defaultp> f64mat4x3; /// Double-qualifier floating-point 4x4 matrix. /// @see gtc_type_precision typedef mat<4, 4, f64, defaultp> f64mat4x4; # endif//GLM_FORCE_SINGLE_ONLY ////////////////////////// // Quaternion types /// Single-qualifier floating-point quaternion. /// @see gtc_type_precision typedef qua f32quat; /// Low single-qualifier floating-point quaternion. /// @see gtc_type_precision typedef qua lowp_f32quat; /// Low double-qualifier floating-point quaternion. /// @see gtc_type_precision typedef qua lowp_f64quat; /// Medium single-qualifier floating-point quaternion. /// @see gtc_type_precision typedef qua mediump_f32quat; # ifndef GLM_FORCE_SINGLE_ONLY /// Medium double-qualifier floating-point quaternion. /// @see gtc_type_precision typedef qua mediump_f64quat; /// High single-qualifier floating-point quaternion. /// @see gtc_type_precision typedef qua highp_f32quat; /// High double-qualifier floating-point quaternion. /// @see gtc_type_precision typedef qua highp_f64quat; /// Double-qualifier floating-point quaternion. /// @see gtc_type_precision typedef qua f64quat; # endif//GLM_FORCE_SINGLE_ONLY /// @} }//namespace glm #include "type_precision.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtc/type_precision.inl000066400000000000000000000000611360521144700246270ustar00rootroot00000000000000/// @ref gtc_precision namespace glm { } connectome-workbench-1.4.2/src/GLMath/glm/gtc/type_ptr.hpp000066400000000000000000000156201360521144700234550ustar00rootroot00000000000000/// @ref gtc_type_ptr /// @file glm/gtc/type_ptr.hpp /// /// @see core (dependence) /// @see gtc_quaternion (dependence) /// /// @defgroup gtc_type_ptr GLM_GTC_type_ptr /// @ingroup gtc /// /// Include to use the features of this extension. /// /// Handles the interaction between pointers and vector, matrix types. /// /// This extension defines an overloaded function, glm::value_ptr. It returns /// a pointer to the memory layout of the object. Matrix types store their values /// in column-major order. /// /// This is useful for uploading data to matrices or copying data to buffer objects. /// /// Example: /// @code /// #include /// #include /// /// glm::vec3 aVector(3); /// glm::mat4 someMatrix(1.0); /// /// glUniform3fv(uniformLoc, 1, glm::value_ptr(aVector)); /// glUniformMatrix4fv(uniformMatrixLoc, 1, GL_FALSE, glm::value_ptr(someMatrix)); /// @endcode /// /// need to be included to use the features of this extension. #pragma once // Dependency: #include "../gtc/quaternion.hpp" #include "../gtc/vec1.hpp" #include "../vec2.hpp" #include "../vec3.hpp" #include "../vec4.hpp" #include "../mat2x2.hpp" #include "../mat2x3.hpp" #include "../mat2x4.hpp" #include "../mat3x2.hpp" #include "../mat3x3.hpp" #include "../mat3x4.hpp" #include "../mat4x2.hpp" #include "../mat4x3.hpp" #include "../mat4x4.hpp" #include #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_GTC_type_ptr extension included") #endif namespace glm { /// @addtogroup gtc_type_ptr /// @{ /// Return the constant address to the data of the input parameter. /// @see gtc_type_ptr template GLM_FUNC_DECL typename genType::value_type const * value_ptr(genType const& v); /// Build a vector from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<1, T, Q> const& v); /// Build a vector from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<2, T, Q> const& v); /// Build a vector from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<3, T, Q> const& v); /// Build a vector from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<4, T, Q> const& v); /// Build a vector from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<1, T, Q> const& v); /// Build a vector from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<2, T, Q> const& v); /// Build a vector from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<3, T, Q> const& v); /// Build a vector from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<4, T, Q> const& v); /// Build a vector from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<1, T, Q> const& v); /// Build a vector from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<2, T, Q> const& v); /// Build a vector from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<3, T, Q> const& v); /// Build a vector from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<4, T, Q> const& v); /// Build a vector from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<1, T, Q> const& v); /// Build a vector from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<2, T, Q> const& v); /// Build a vector from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<3, T, Q> const& v); /// Build a vector from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<4, T, Q> const& v); /// Build a vector from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL vec<2, T, defaultp> make_vec2(T const * const ptr); /// Build a vector from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL vec<3, T, defaultp> make_vec3(T const * const ptr); /// Build a vector from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL vec<4, T, defaultp> make_vec4(T const * const ptr); /// Build a matrix from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL mat<2, 2, T, defaultp> make_mat2x2(T const * const ptr); /// Build a matrix from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL mat<2, 3, T, defaultp> make_mat2x3(T const * const ptr); /// Build a matrix from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL mat<2, 4, T, defaultp> make_mat2x4(T const * const ptr); /// Build a matrix from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL mat<3, 2, T, defaultp> make_mat3x2(T const * const ptr); /// Build a matrix from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL mat<3, 3, T, defaultp> make_mat3x3(T const * const ptr); /// Build a matrix from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL mat<3, 4, T, defaultp> make_mat3x4(T const * const ptr); /// Build a matrix from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL mat<4, 2, T, defaultp> make_mat4x2(T const * const ptr); /// Build a matrix from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL mat<4, 3, T, defaultp> make_mat4x3(T const * const ptr); /// Build a matrix from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL mat<4, 4, T, defaultp> make_mat4x4(T const * const ptr); /// Build a matrix from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL mat<2, 2, T, defaultp> make_mat2(T const * const ptr); /// Build a matrix from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL mat<3, 3, T, defaultp> make_mat3(T const * const ptr); /// Build a matrix from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL mat<4, 4, T, defaultp> make_mat4(T const * const ptr); /// Build a quaternion from a pointer. /// @see gtc_type_ptr template GLM_FUNC_DECL qua make_quat(T const * const ptr); /// @} }//namespace glm #include "type_ptr.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtc/type_ptr.inl000066400000000000000000000213471360521144700234530ustar00rootroot00000000000000/// @ref gtc_type_ptr #include namespace glm { /// @addtogroup gtc_type_ptr /// @{ template GLM_FUNC_QUALIFIER T const* value_ptr(vec<2, T, Q> const& v) { return &(v.x); } template GLM_FUNC_QUALIFIER T* value_ptr(vec<2, T, Q>& v) { return &(v.x); } template GLM_FUNC_QUALIFIER T const * value_ptr(vec<3, T, Q> const& v) { return &(v.x); } template GLM_FUNC_QUALIFIER T* value_ptr(vec<3, T, Q>& v) { return &(v.x); } template GLM_FUNC_QUALIFIER T const* value_ptr(vec<4, T, Q> const& v) { return &(v.x); } template GLM_FUNC_QUALIFIER T* value_ptr(vec<4, T, Q>& v) { return &(v.x); } template GLM_FUNC_QUALIFIER T const* value_ptr(mat<2, 2, T, Q> const& m) { return &(m[0].x); } template GLM_FUNC_QUALIFIER T* value_ptr(mat<2, 2, T, Q>& m) { return &(m[0].x); } template GLM_FUNC_QUALIFIER T const* value_ptr(mat<3, 3, T, Q> const& m) { return &(m[0].x); } template GLM_FUNC_QUALIFIER T* value_ptr(mat<3, 3, T, Q>& m) { return &(m[0].x); } template GLM_FUNC_QUALIFIER T const* value_ptr(mat<4, 4, T, Q> const& m) { return &(m[0].x); } template GLM_FUNC_QUALIFIER T* value_ptr(mat<4, 4, T, Q>& m) { return &(m[0].x); } template GLM_FUNC_QUALIFIER T const* value_ptr(mat<2, 3, T, Q> const& m) { return &(m[0].x); } template GLM_FUNC_QUALIFIER T* value_ptr(mat<2, 3, T, Q>& m) { return &(m[0].x); } template GLM_FUNC_QUALIFIER T const* value_ptr(mat<3, 2, T, Q> const& m) { return &(m[0].x); } template GLM_FUNC_QUALIFIER T* value_ptr(mat<3, 2, T, Q>& m) { return &(m[0].x); } template GLM_FUNC_QUALIFIER T const* value_ptr(mat<2, 4, T, Q> const& m) { return &(m[0].x); } template GLM_FUNC_QUALIFIER T* value_ptr(mat<2, 4, T, Q>& m) { return &(m[0].x); } template GLM_FUNC_QUALIFIER T const* value_ptr(mat<4, 2, T, Q> const& m) { return &(m[0].x); } template GLM_FUNC_QUALIFIER T* value_ptr(mat<4, 2, T, Q>& m) { return &(m[0].x); } template GLM_FUNC_QUALIFIER T const* value_ptr(mat<3, 4, T, Q> const& m) { return &(m[0].x); } template GLM_FUNC_QUALIFIER T* value_ptr(mat<3, 4, T, Q>& m) { return &(m[0].x); } template GLM_FUNC_QUALIFIER T const* value_ptr(mat<4, 3, T, Q> const& m) { return &(m[0].x); } template GLM_FUNC_QUALIFIER T * value_ptr(mat<4, 3, T, Q>& m) { return &(m[0].x); } template GLM_FUNC_QUALIFIER T const * value_ptr(qua const& q) { return &(q[0]); } template GLM_FUNC_QUALIFIER T* value_ptr(qua& q) { return &(q[0]); } template inline vec<1, T, Q> make_vec1(vec<1, T, Q> const& v) { return v; } template inline vec<1, T, Q> make_vec1(vec<2, T, Q> const& v) { return vec<1, T, Q>(v); } template inline vec<1, T, Q> make_vec1(vec<3, T, Q> const& v) { return vec<1, T, Q>(v); } template inline vec<1, T, Q> make_vec1(vec<4, T, Q> const& v) { return vec<1, T, Q>(v); } template inline vec<2, T, Q> make_vec2(vec<1, T, Q> const& v) { return vec<2, T, Q>(v.x, static_cast(0)); } template inline vec<2, T, Q> make_vec2(vec<2, T, Q> const& v) { return v; } template inline vec<2, T, Q> make_vec2(vec<3, T, Q> const& v) { return vec<2, T, Q>(v); } template inline vec<2, T, Q> make_vec2(vec<4, T, Q> const& v) { return vec<2, T, Q>(v); } template inline vec<3, T, Q> make_vec3(vec<1, T, Q> const& v) { return vec<3, T, Q>(v.x, static_cast(0), static_cast(0)); } template inline vec<3, T, Q> make_vec3(vec<2, T, Q> const& v) { return vec<3, T, Q>(v.x, v.y, static_cast(0)); } template inline vec<3, T, Q> make_vec3(vec<3, T, Q> const& v) { return v; } template inline vec<3, T, Q> make_vec3(vec<4, T, Q> const& v) { return vec<3, T, Q>(v); } template inline vec<4, T, Q> make_vec4(vec<1, T, Q> const& v) { return vec<4, T, Q>(v.x, static_cast(0), static_cast(0), static_cast(1)); } template inline vec<4, T, Q> make_vec4(vec<2, T, Q> const& v) { return vec<4, T, Q>(v.x, v.y, static_cast(0), static_cast(1)); } template inline vec<4, T, Q> make_vec4(vec<3, T, Q> const& v) { return vec<4, T, Q>(v.x, v.y, v.z, static_cast(1)); } template inline vec<4, T, Q> make_vec4(vec<4, T, Q> const& v) { return v; } template GLM_FUNC_QUALIFIER vec<2, T, defaultp> make_vec2(T const *const ptr) { vec<2, T, defaultp> Result; memcpy(value_ptr(Result), ptr, sizeof(vec<2, T, defaultp>)); return Result; } template GLM_FUNC_QUALIFIER vec<3, T, defaultp> make_vec3(T const *const ptr) { vec<3, T, defaultp> Result; memcpy(value_ptr(Result), ptr, sizeof(vec<3, T, defaultp>)); return Result; } template GLM_FUNC_QUALIFIER vec<4, T, defaultp> make_vec4(T const *const ptr) { vec<4, T, defaultp> Result; memcpy(value_ptr(Result), ptr, sizeof(vec<4, T, defaultp>)); return Result; } template GLM_FUNC_QUALIFIER mat<2, 2, T, defaultp> make_mat2x2(T const *const ptr) { mat<2, 2, T, defaultp> Result; memcpy(value_ptr(Result), ptr, sizeof(mat<2, 2, T, defaultp>)); return Result; } template GLM_FUNC_QUALIFIER mat<2, 3, T, defaultp> make_mat2x3(T const *const ptr) { mat<2, 3, T, defaultp> Result; memcpy(value_ptr(Result), ptr, sizeof(mat<2, 3, T, defaultp>)); return Result; } template GLM_FUNC_QUALIFIER mat<2, 4, T, defaultp> make_mat2x4(T const *const ptr) { mat<2, 4, T, defaultp> Result; memcpy(value_ptr(Result), ptr, sizeof(mat<2, 4, T, defaultp>)); return Result; } template GLM_FUNC_QUALIFIER mat<3, 2, T, defaultp> make_mat3x2(T const *const ptr) { mat<3, 2, T, defaultp> Result; memcpy(value_ptr(Result), ptr, sizeof(mat<3, 2, T, defaultp>)); return Result; } template GLM_FUNC_QUALIFIER mat<3, 3, T, defaultp> make_mat3x3(T const *const ptr) { mat<3, 3, T, defaultp> Result; memcpy(value_ptr(Result), ptr, sizeof(mat<3, 3, T, defaultp>)); return Result; } template GLM_FUNC_QUALIFIER mat<3, 4, T, defaultp> make_mat3x4(T const *const ptr) { mat<3, 4, T, defaultp> Result; memcpy(value_ptr(Result), ptr, sizeof(mat<3, 4, T, defaultp>)); return Result; } template GLM_FUNC_QUALIFIER mat<4, 2, T, defaultp> make_mat4x2(T const *const ptr) { mat<4, 2, T, defaultp> Result; memcpy(value_ptr(Result), ptr, sizeof(mat<4, 2, T, defaultp>)); return Result; } template GLM_FUNC_QUALIFIER mat<4, 3, T, defaultp> make_mat4x3(T const *const ptr) { mat<4, 3, T, defaultp> Result; memcpy(value_ptr(Result), ptr, sizeof(mat<4, 3, T, defaultp>)); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> make_mat4x4(T const *const ptr) { mat<4, 4, T, defaultp> Result; memcpy(value_ptr(Result), ptr, sizeof(mat<4, 4, T, defaultp>)); return Result; } template GLM_FUNC_QUALIFIER mat<2, 2, T, defaultp> make_mat2(T const *const ptr) { return make_mat2x2(ptr); } template GLM_FUNC_QUALIFIER mat<3, 3, T, defaultp> make_mat3(T const *const ptr) { return make_mat3x3(ptr); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> make_mat4(T const *const ptr) { return make_mat4x4(ptr); } template GLM_FUNC_QUALIFIER qua make_quat(T const *const ptr) { qua Result; memcpy(value_ptr(Result), ptr, sizeof(qua)); return Result; } /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtc/ulp.hpp000066400000000000000000000121121360521144700224000ustar00rootroot00000000000000/// @ref gtc_ulp /// @file glm/gtc/ulp.hpp /// /// @see core (dependence) /// /// @defgroup gtc_ulp GLM_GTC_ulp /// @ingroup gtc /// /// Include to use the features of this extension. /// /// Allow the measurement of the accuracy of a function against a reference /// implementation. This extension works on floating-point data and provide results /// in ULP. #pragma once // Dependencies #include "../detail/setup.hpp" #include "../detail/qualifier.hpp" #include "../detail/_vectorize.hpp" #include "../ext/scalar_int_sized.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_GTC_ulp extension included") #endif namespace glm { /// Return the next ULP value(s) after the input value(s). /// /// @tparam genType A floating-point scalar type. /// /// @see gtc_ulp template GLM_FUNC_DECL genType next_float(genType x); /// Return the previous ULP value(s) before the input value(s). /// /// @tparam genType A floating-point scalar type. /// /// @see gtc_ulp template GLM_FUNC_DECL genType prev_float(genType x); /// Return the value(s) ULP distance after the input value(s). /// /// @tparam genType A floating-point scalar type. /// /// @see gtc_ulp template GLM_FUNC_DECL genType next_float(genType x, int ULPs); /// Return the value(s) ULP distance before the input value(s). /// /// @tparam genType A floating-point scalar type. /// /// @see gtc_ulp template GLM_FUNC_DECL genType prev_float(genType x, int ULPs); /// Return the distance in the number of ULP between 2 single-precision floating-point scalars. /// /// @see gtc_ulp GLM_FUNC_DECL int float_distance(float x, float y); /// Return the distance in the number of ULP between 2 double-precision floating-point scalars. /// /// @see gtc_ulp GLM_FUNC_DECL int64 float_distance(double x, double y); /// Return the next ULP value(s) after the input value(s). /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point /// @tparam Q Value from qualifier enum /// /// @see gtc_ulp template GLM_FUNC_DECL vec next_float(vec const& x); /// Return the value(s) ULP distance after the input value(s). /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point /// @tparam Q Value from qualifier enum /// /// @see gtc_ulp template GLM_FUNC_DECL vec next_float(vec const& x, int ULPs); /// Return the value(s) ULP distance after the input value(s). /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point /// @tparam Q Value from qualifier enum /// /// @see gtc_ulp template GLM_FUNC_DECL vec next_float(vec const& x, vec const& ULPs); /// Return the previous ULP value(s) before the input value(s). /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point /// @tparam Q Value from qualifier enum /// /// @see gtc_ulp template GLM_FUNC_DECL vec prev_float(vec const& x); /// Return the value(s) ULP distance before the input value(s). /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point /// @tparam Q Value from qualifier enum /// /// @see gtc_ulp template GLM_FUNC_DECL vec prev_float(vec const& x, int ULPs); /// Return the value(s) ULP distance before the input value(s). /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point /// @tparam Q Value from qualifier enum /// /// @see gtc_ulp template GLM_FUNC_DECL vec prev_float(vec const& x, vec const& ULPs); /// Return the distance in the number of ULP between 2 single-precision floating-point scalars. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam Q Value from qualifier enum /// /// @see gtc_ulp template GLM_FUNC_DECL vec float_distance(vec const& x, vec const& y); /// Return the distance in the number of ULP between 2 double-precision floating-point scalars. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam Q Value from qualifier enum /// /// @see gtc_ulp template GLM_FUNC_DECL vec float_distance(vec const& x, vec const& y); /// @} }//namespace glm #include "ulp.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtc/ulp.inl000066400000000000000000000120761360521144700224040ustar00rootroot00000000000000/// @ref gtc_ulp #include "../ext/scalar_ulp.hpp" namespace glm { template<> GLM_FUNC_QUALIFIER float next_float(float x) { # if GLM_HAS_CXX11_STL return std::nextafter(x, std::numeric_limits::max()); # elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) return detail::nextafterf(x, FLT_MAX); # elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) return __builtin_nextafterf(x, FLT_MAX); # else return nextafterf(x, FLT_MAX); # endif } template<> GLM_FUNC_QUALIFIER double next_float(double x) { # if GLM_HAS_CXX11_STL return std::nextafter(x, std::numeric_limits::max()); # elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) return detail::nextafter(x, std::numeric_limits::max()); # elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) return __builtin_nextafter(x, DBL_MAX); # else return nextafter(x, DBL_MAX); # endif } template GLM_FUNC_QUALIFIER T next_float(T x, int ULPs) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'next_float' only accept floating-point input"); assert(ULPs >= 0); T temp = x; for (int i = 0; i < ULPs; ++i) temp = next_float(temp); return temp; } GLM_FUNC_QUALIFIER float prev_float(float x) { # if GLM_HAS_CXX11_STL return std::nextafter(x, std::numeric_limits::min()); # elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) return detail::nextafterf(x, FLT_MIN); # elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) return __builtin_nextafterf(x, FLT_MIN); # else return nextafterf(x, FLT_MIN); # endif } GLM_FUNC_QUALIFIER double prev_float(double x) { # if GLM_HAS_CXX11_STL return std::nextafter(x, std::numeric_limits::min()); # elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))) return _nextafter(x, DBL_MIN); # elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID) return __builtin_nextafter(x, DBL_MIN); # else return nextafter(x, DBL_MIN); # endif } template GLM_FUNC_QUALIFIER T prev_float(T x, int ULPs) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'prev_float' only accept floating-point input"); assert(ULPs >= 0); T temp = x; for (int i = 0; i < ULPs; ++i) temp = prev_float(temp); return temp; } GLM_FUNC_QUALIFIER int float_distance(float x, float y) { detail::float_t const a(x); detail::float_t const b(y); return abs(a.i - b.i); } GLM_FUNC_QUALIFIER int64 float_distance(double x, double y) { detail::float_t const a(x); detail::float_t const b(y); return abs(a.i - b.i); } template GLM_FUNC_QUALIFIER vec next_float(vec const& x) { vec Result; for (length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = next_float(x[i]); return Result; } template GLM_FUNC_QUALIFIER vec next_float(vec const& x, int ULPs) { vec Result; for (length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = next_float(x[i], ULPs); return Result; } template GLM_FUNC_QUALIFIER vec next_float(vec const& x, vec const& ULPs) { vec Result; for (length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = next_float(x[i], ULPs[i]); return Result; } template GLM_FUNC_QUALIFIER vec prev_float(vec const& x) { vec Result; for (length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = prev_float(x[i]); return Result; } template GLM_FUNC_QUALIFIER vec prev_float(vec const& x, int ULPs) { vec Result; for (length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = prev_float(x[i], ULPs); return Result; } template GLM_FUNC_QUALIFIER vec prev_float(vec const& x, vec const& ULPs) { vec Result; for (length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = prev_float(x[i], ULPs[i]); return Result; } template GLM_FUNC_QUALIFIER vec float_distance(vec const& x, vec const& y) { vec Result; for (length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = float_distance(x[i], y[i]); return Result; } template GLM_FUNC_QUALIFIER vec float_distance(vec const& x, vec const& y) { vec Result; for (length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = float_distance(x[i], y[i]); return Result; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtc/vec1.hpp000066400000000000000000000015161360521144700224440ustar00rootroot00000000000000/// @ref gtc_vec1 /// @file glm/gtc/vec1.hpp /// /// @see core (dependence) /// /// @defgroup gtc_vec1 GLM_GTC_vec1 /// @ingroup gtc /// /// Include to use the features of this extension. /// /// Add vec1, ivec1, uvec1 and bvec1 types. #pragma once // Dependency: #include "../ext/vector_bool1.hpp" #include "../ext/vector_bool1_precision.hpp" #include "../ext/vector_float1.hpp" #include "../ext/vector_float1_precision.hpp" #include "../ext/vector_double1.hpp" #include "../ext/vector_double1_precision.hpp" #include "../ext/vector_int1.hpp" #include "../ext/vector_int1_precision.hpp" #include "../ext/vector_uint1.hpp" #include "../ext/vector_uint1_precision.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # pragma message("GLM: GLM_GTC_vec1 extension included") #endif connectome-workbench-1.4.2/src/GLMath/glm/gtx/000077500000000000000000000000001360521144700211175ustar00rootroot00000000000000connectome-workbench-1.4.2/src/GLMath/glm/gtx/associated_min_max.hpp000066400000000000000000000172341360521144700254660ustar00rootroot00000000000000/// @ref gtx_associated_min_max /// @file glm/gtx/associated_min_max.hpp /// /// @see core (dependence) /// @see gtx_extented_min_max (dependence) /// /// @defgroup gtx_associated_min_max GLM_GTX_associated_min_max /// @ingroup gtx /// /// Include to use the features of this extension. /// /// @brief Min and max functions that return associated values not the compared onces. #pragma once // Dependency: #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_associated_min_max is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_associated_min_max extension included") # endif #endif namespace glm { /// @addtogroup gtx_associated_min_max /// @{ /// Minimum comparison between 2 variables and returns 2 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL U associatedMin(T x, U a, T y, U b); /// Minimum comparison between 2 variables and returns 2 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL vec<2, U, Q> associatedMin( vec const& x, vec const& a, vec const& y, vec const& b); /// Minimum comparison between 2 variables and returns 2 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL vec associatedMin( T x, const vec& a, T y, const vec& b); /// Minimum comparison between 2 variables and returns 2 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL vec associatedMin( vec const& x, U a, vec const& y, U b); /// Minimum comparison between 3 variables and returns 3 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL U associatedMin( T x, U a, T y, U b, T z, U c); /// Minimum comparison between 3 variables and returns 3 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL vec associatedMin( vec const& x, vec const& a, vec const& y, vec const& b, vec const& z, vec const& c); /// Minimum comparison between 4 variables and returns 4 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL U associatedMin( T x, U a, T y, U b, T z, U c, T w, U d); /// Minimum comparison between 4 variables and returns 4 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL vec associatedMin( vec const& x, vec const& a, vec const& y, vec const& b, vec const& z, vec const& c, vec const& w, vec const& d); /// Minimum comparison between 4 variables and returns 4 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL vec associatedMin( T x, vec const& a, T y, vec const& b, T z, vec const& c, T w, vec const& d); /// Minimum comparison between 4 variables and returns 4 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL vec associatedMin( vec const& x, U a, vec const& y, U b, vec const& z, U c, vec const& w, U d); /// Maximum comparison between 2 variables and returns 2 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL U associatedMax(T x, U a, T y, U b); /// Maximum comparison between 2 variables and returns 2 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL vec<2, U, Q> associatedMax( vec const& x, vec const& a, vec const& y, vec const& b); /// Maximum comparison between 2 variables and returns 2 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL vec associatedMax( T x, vec const& a, T y, vec const& b); /// Maximum comparison between 2 variables and returns 2 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL vec associatedMax( vec const& x, U a, vec const& y, U b); /// Maximum comparison between 3 variables and returns 3 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL U associatedMax( T x, U a, T y, U b, T z, U c); /// Maximum comparison between 3 variables and returns 3 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL vec associatedMax( vec const& x, vec const& a, vec const& y, vec const& b, vec const& z, vec const& c); /// Maximum comparison between 3 variables and returns 3 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL vec associatedMax( T x, vec const& a, T y, vec const& b, T z, vec const& c); /// Maximum comparison between 3 variables and returns 3 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL vec associatedMax( vec const& x, U a, vec const& y, U b, vec const& z, U c); /// Maximum comparison between 4 variables and returns 4 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL U associatedMax( T x, U a, T y, U b, T z, U c, T w, U d); /// Maximum comparison between 4 variables and returns 4 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL vec associatedMax( vec const& x, vec const& a, vec const& y, vec const& b, vec const& z, vec const& c, vec const& w, vec const& d); /// Maximum comparison between 4 variables and returns 4 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL vec associatedMax( T x, vec const& a, T y, vec const& b, T z, vec const& c, T w, vec const& d); /// Maximum comparison between 4 variables and returns 4 associated variable values /// @see gtx_associated_min_max template GLM_FUNC_DECL vec associatedMax( vec const& x, U a, vec const& y, U b, vec const& z, U c, vec const& w, U d); /// @} } //namespace glm #include "associated_min_max.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/associated_min_max.inl000066400000000000000000000212721360521144700254560ustar00rootroot00000000000000/// @ref gtx_associated_min_max namespace glm{ // Min comparison between 2 variables template GLM_FUNC_QUALIFIER U associatedMin(T x, U a, T y, U b) { return x < y ? a : b; } template GLM_FUNC_QUALIFIER vec<2, U, Q> associatedMin ( vec const& x, vec const& a, vec const& y, vec const& b ) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = x[i] < y[i] ? a[i] : b[i]; return Result; } template GLM_FUNC_QUALIFIER vec associatedMin ( T x, const vec& a, T y, const vec& b ) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = x < y ? a[i] : b[i]; return Result; } template GLM_FUNC_QUALIFIER vec associatedMin ( vec const& x, U a, vec const& y, U b ) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = x[i] < y[i] ? a : b; return Result; } // Min comparison between 3 variables template GLM_FUNC_QUALIFIER U associatedMin ( T x, U a, T y, U b, T z, U c ) { U Result = x < y ? (x < z ? a : c) : (y < z ? b : c); return Result; } template GLM_FUNC_QUALIFIER vec associatedMin ( vec const& x, vec const& a, vec const& y, vec const& b, vec const& z, vec const& c ) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = x[i] < y[i] ? (x[i] < z[i] ? a[i] : c[i]) : (y[i] < z[i] ? b[i] : c[i]); return Result; } // Min comparison between 4 variables template GLM_FUNC_QUALIFIER U associatedMin ( T x, U a, T y, U b, T z, U c, T w, U d ) { T Test1 = min(x, y); T Test2 = min(z, w); U Result1 = x < y ? a : b; U Result2 = z < w ? c : d; U Result = Test1 < Test2 ? Result1 : Result2; return Result; } // Min comparison between 4 variables template GLM_FUNC_QUALIFIER vec associatedMin ( vec const& x, vec const& a, vec const& y, vec const& b, vec const& z, vec const& c, vec const& w, vec const& d ) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) { T Test1 = min(x[i], y[i]); T Test2 = min(z[i], w[i]); U Result1 = x[i] < y[i] ? a[i] : b[i]; U Result2 = z[i] < w[i] ? c[i] : d[i]; Result[i] = Test1 < Test2 ? Result1 : Result2; } return Result; } // Min comparison between 4 variables template GLM_FUNC_QUALIFIER vec associatedMin ( T x, vec const& a, T y, vec const& b, T z, vec const& c, T w, vec const& d ) { T Test1 = min(x, y); T Test2 = min(z, w); vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) { U Result1 = x < y ? a[i] : b[i]; U Result2 = z < w ? c[i] : d[i]; Result[i] = Test1 < Test2 ? Result1 : Result2; } return Result; } // Min comparison between 4 variables template GLM_FUNC_QUALIFIER vec associatedMin ( vec const& x, U a, vec const& y, U b, vec const& z, U c, vec const& w, U d ) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) { T Test1 = min(x[i], y[i]); T Test2 = min(z[i], w[i]); U Result1 = x[i] < y[i] ? a : b; U Result2 = z[i] < w[i] ? c : d; Result[i] = Test1 < Test2 ? Result1 : Result2; } return Result; } // Max comparison between 2 variables template GLM_FUNC_QUALIFIER U associatedMax(T x, U a, T y, U b) { return x > y ? a : b; } // Max comparison between 2 variables template GLM_FUNC_QUALIFIER vec<2, U, Q> associatedMax ( vec const& x, vec const& a, vec const& y, vec const& b ) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = x[i] > y[i] ? a[i] : b[i]; return Result; } // Max comparison between 2 variables template GLM_FUNC_QUALIFIER vec associatedMax ( T x, vec const& a, T y, vec const& b ) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = x > y ? a[i] : b[i]; return Result; } // Max comparison between 2 variables template GLM_FUNC_QUALIFIER vec associatedMax ( vec const& x, U a, vec const& y, U b ) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = x[i] > y[i] ? a : b; return Result; } // Max comparison between 3 variables template GLM_FUNC_QUALIFIER U associatedMax ( T x, U a, T y, U b, T z, U c ) { U Result = x > y ? (x > z ? a : c) : (y > z ? b : c); return Result; } // Max comparison between 3 variables template GLM_FUNC_QUALIFIER vec associatedMax ( vec const& x, vec const& a, vec const& y, vec const& b, vec const& z, vec const& c ) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = x[i] > y[i] ? (x[i] > z[i] ? a[i] : c[i]) : (y[i] > z[i] ? b[i] : c[i]); return Result; } // Max comparison between 3 variables template GLM_FUNC_QUALIFIER vec associatedMax ( T x, vec const& a, T y, vec const& b, T z, vec const& c ) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = x > y ? (x > z ? a[i] : c[i]) : (y > z ? b[i] : c[i]); return Result; } // Max comparison between 3 variables template GLM_FUNC_QUALIFIER vec associatedMax ( vec const& x, U a, vec const& y, U b, vec const& z, U c ) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) Result[i] = x[i] > y[i] ? (x[i] > z[i] ? a : c) : (y[i] > z[i] ? b : c); return Result; } // Max comparison between 4 variables template GLM_FUNC_QUALIFIER U associatedMax ( T x, U a, T y, U b, T z, U c, T w, U d ) { T Test1 = max(x, y); T Test2 = max(z, w); U Result1 = x > y ? a : b; U Result2 = z > w ? c : d; U Result = Test1 > Test2 ? Result1 : Result2; return Result; } // Max comparison between 4 variables template GLM_FUNC_QUALIFIER vec associatedMax ( vec const& x, vec const& a, vec const& y, vec const& b, vec const& z, vec const& c, vec const& w, vec const& d ) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) { T Test1 = max(x[i], y[i]); T Test2 = max(z[i], w[i]); U Result1 = x[i] > y[i] ? a[i] : b[i]; U Result2 = z[i] > w[i] ? c[i] : d[i]; Result[i] = Test1 > Test2 ? Result1 : Result2; } return Result; } // Max comparison between 4 variables template GLM_FUNC_QUALIFIER vec associatedMax ( T x, vec const& a, T y, vec const& b, T z, vec const& c, T w, vec const& d ) { T Test1 = max(x, y); T Test2 = max(z, w); vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) { U Result1 = x > y ? a[i] : b[i]; U Result2 = z > w ? c[i] : d[i]; Result[i] = Test1 > Test2 ? Result1 : Result2; } return Result; } // Max comparison between 4 variables template GLM_FUNC_QUALIFIER vec associatedMax ( vec const& x, U a, vec const& y, U b, vec const& z, U c, vec const& w, U d ) { vec Result; for(length_t i = 0, n = Result.length(); i < n; ++i) { T Test1 = max(x[i], y[i]); T Test2 = max(z[i], w[i]); U Result1 = x[i] > y[i] ? a : b; U Result2 = z[i] > w[i] ? c : d; Result[i] = Test1 > Test2 ? Result1 : Result2; } return Result; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/bit.hpp000066400000000000000000000061001360521144700224030ustar00rootroot00000000000000/// @ref gtx_bit /// @file glm/gtx/bit.hpp /// /// @see core (dependence) /// /// @defgroup gtx_bit GLM_GTX_bit /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Allow to perform bit operations on integer values #pragma once // Dependencies #include "../gtc/bitfield.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_bit is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_bit extension included") # endif #endif namespace glm { /// @addtogroup gtx_bit /// @{ /// @see gtx_bit template GLM_FUNC_DECL genIUType highestBitValue(genIUType Value); /// @see gtx_bit template GLM_FUNC_DECL genIUType lowestBitValue(genIUType Value); /// Find the highest bit set to 1 in a integer variable and return its value. /// /// @see gtx_bit template GLM_FUNC_DECL vec highestBitValue(vec const& value); /// Return the power of two number which value is just higher the input value. /// Deprecated, use ceilPowerOfTwo from GTC_round instead /// /// @see gtc_round /// @see gtx_bit template GLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoAbove(genIUType Value); /// Return the power of two number which value is just higher the input value. /// Deprecated, use ceilPowerOfTwo from GTC_round instead /// /// @see gtc_round /// @see gtx_bit template GLM_DEPRECATED GLM_FUNC_DECL vec powerOfTwoAbove(vec const& value); /// Return the power of two number which value is just lower the input value. /// Deprecated, use floorPowerOfTwo from GTC_round instead /// /// @see gtc_round /// @see gtx_bit template GLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoBelow(genIUType Value); /// Return the power of two number which value is just lower the input value. /// Deprecated, use floorPowerOfTwo from GTC_round instead /// /// @see gtc_round /// @see gtx_bit template GLM_DEPRECATED GLM_FUNC_DECL vec powerOfTwoBelow(vec const& value); /// Return the power of two number which value is the closet to the input value. /// Deprecated, use roundPowerOfTwo from GTC_round instead /// /// @see gtc_round /// @see gtx_bit template GLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoNearest(genIUType Value); /// Return the power of two number which value is the closet to the input value. /// Deprecated, use roundPowerOfTwo from GTC_round instead /// /// @see gtc_round /// @see gtx_bit template GLM_DEPRECATED GLM_FUNC_DECL vec powerOfTwoNearest(vec const& value); /// @} } //namespace glm #include "bit.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/bit.inl000066400000000000000000000044621360521144700224070ustar00rootroot00000000000000/// @ref gtx_bit namespace glm { /////////////////// // highestBitValue template GLM_FUNC_QUALIFIER genIUType highestBitValue(genIUType Value) { genIUType tmp = Value; genIUType result = genIUType(0); while(tmp) { result = (tmp & (~tmp + 1)); // grab lowest bit tmp &= ~result; // clear lowest bit } return result; } template GLM_FUNC_QUALIFIER vec highestBitValue(vec const& v) { return detail::functor1::call(highestBitValue, v); } /////////////////// // lowestBitValue template GLM_FUNC_QUALIFIER genIUType lowestBitValue(genIUType Value) { return (Value & (~Value + 1)); } template GLM_FUNC_QUALIFIER vec lowestBitValue(vec const& v) { return detail::functor1::call(lowestBitValue, v); } /////////////////// // powerOfTwoAbove template GLM_FUNC_QUALIFIER genType powerOfTwoAbove(genType value) { return isPowerOfTwo(value) ? value : highestBitValue(value) << 1; } template GLM_FUNC_QUALIFIER vec powerOfTwoAbove(vec const& v) { return detail::functor1::call(powerOfTwoAbove, v); } /////////////////// // powerOfTwoBelow template GLM_FUNC_QUALIFIER genType powerOfTwoBelow(genType value) { return isPowerOfTwo(value) ? value : highestBitValue(value); } template GLM_FUNC_QUALIFIER vec powerOfTwoBelow(vec const& v) { return detail::functor1::call(powerOfTwoBelow, v); } ///////////////////// // powerOfTwoNearest template GLM_FUNC_QUALIFIER genType powerOfTwoNearest(genType value) { if(isPowerOfTwo(value)) return value; genType const prev = highestBitValue(value); genType const next = prev << 1; return (next - value) < (value - prev) ? next : prev; } template GLM_FUNC_QUALIFIER vec powerOfTwoNearest(vec const& v) { return detail::functor1::call(powerOfTwoNearest, v); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/closest_point.hpp000066400000000000000000000025401360521144700245160ustar00rootroot00000000000000/// @ref gtx_closest_point /// @file glm/gtx/closest_point.hpp /// /// @see core (dependence) /// /// @defgroup gtx_closest_point GLM_GTX_closest_point /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Find the point on a straight line which is the closet of a point. #pragma once // Dependency: #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_closest_point is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_closest_point extension included") # endif #endif namespace glm { /// @addtogroup gtx_closest_point /// @{ /// Find the point on a straight line which is the closet of a point. /// @see gtx_closest_point template GLM_FUNC_DECL vec<3, T, Q> closestPointOnLine( vec<3, T, Q> const& point, vec<3, T, Q> const& a, vec<3, T, Q> const& b); /// 2d lines work as well template GLM_FUNC_DECL vec<2, T, Q> closestPointOnLine( vec<2, T, Q> const& point, vec<2, T, Q> const& a, vec<2, T, Q> const& b); /// @} }// namespace glm #include "closest_point.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/closest_point.inl000066400000000000000000000022121360521144700245050ustar00rootroot00000000000000/// @ref gtx_closest_point namespace glm { template GLM_FUNC_QUALIFIER vec<3, T, Q> closestPointOnLine ( vec<3, T, Q> const& point, vec<3, T, Q> const& a, vec<3, T, Q> const& b ) { T LineLength = distance(a, b); vec<3, T, Q> Vector = point - a; vec<3, T, Q> LineDirection = (b - a) / LineLength; // Project Vector to LineDirection to get the distance of point from a T Distance = dot(Vector, LineDirection); if(Distance <= T(0)) return a; if(Distance >= LineLength) return b; return a + LineDirection * Distance; } template GLM_FUNC_QUALIFIER vec<2, T, Q> closestPointOnLine ( vec<2, T, Q> const& point, vec<2, T, Q> const& a, vec<2, T, Q> const& b ) { T LineLength = distance(a, b); vec<2, T, Q> Vector = point - a; vec<2, T, Q> LineDirection = (b - a) / LineLength; // Project Vector to LineDirection to get the distance of point from a T Distance = dot(Vector, LineDirection); if(Distance <= T(0)) return a; if(Distance >= LineLength) return b; return a + LineDirection * Distance; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/color_encoding.hpp000066400000000000000000000033021360521144700246120ustar00rootroot00000000000000/// @ref gtx_color_encoding /// @file glm/gtx/color_encoding.hpp /// /// @see core (dependence) /// @see gtx_color_encoding (dependence) /// /// @defgroup gtx_color_encoding GLM_GTX_color_encoding /// @ingroup gtx /// /// Include to use the features of this extension. /// /// @brief Allow to perform bit operations on integer values #pragma once // Dependencies #include "../detail/setup.hpp" #include "../detail/qualifier.hpp" #include "../vec3.hpp" #include #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTC_color_encoding is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTC_color_encoding extension included") # endif #endif namespace glm { /// @addtogroup gtx_color_encoding /// @{ /// Convert a linear sRGB color to D65 YUV. template GLM_FUNC_DECL vec<3, T, Q> convertLinearSRGBToD65XYZ(vec<3, T, Q> const& ColorLinearSRGB); /// Convert a linear sRGB color to D50 YUV. template GLM_FUNC_DECL vec<3, T, Q> convertLinearSRGBToD50XYZ(vec<3, T, Q> const& ColorLinearSRGB); /// Convert a D65 YUV color to linear sRGB. template GLM_FUNC_DECL vec<3, T, Q> convertD65XYZToLinearSRGB(vec<3, T, Q> const& ColorD65XYZ); /// Convert a D65 YUV color to D50 YUV. template GLM_FUNC_DECL vec<3, T, Q> convertD65XYZToD50XYZ(vec<3, T, Q> const& ColorD65XYZ); /// @} } //namespace glm #include "color_encoding.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/color_encoding.inl000066400000000000000000000034001360521144700246040ustar00rootroot00000000000000/// @ref gtx_color_encoding namespace glm { template GLM_FUNC_QUALIFIER vec<3, T, Q> convertLinearSRGBToD65XYZ(vec<3, T, Q> const& ColorLinearSRGB) { vec<3, T, Q> const M(0.490f, 0.17697f, 0.2f); vec<3, T, Q> const N(0.31f, 0.8124f, 0.01063f); vec<3, T, Q> const O(0.490f, 0.01f, 0.99f); return (M * ColorLinearSRGB + N * ColorLinearSRGB + O * ColorLinearSRGB) * static_cast(5.650675255693055f); } template GLM_FUNC_QUALIFIER vec<3, T, Q> convertLinearSRGBToD50XYZ(vec<3, T, Q> const& ColorLinearSRGB) { vec<3, T, Q> const M(0.436030342570117f, 0.222438466210245f, 0.013897440074263f); vec<3, T, Q> const N(0.385101860087134f, 0.716942745571917f, 0.097076381494207f); vec<3, T, Q> const O(0.143067806654203f, 0.060618777416563f, 0.713926257896652f); return M * ColorLinearSRGB + N * ColorLinearSRGB + O * ColorLinearSRGB; } template GLM_FUNC_QUALIFIER vec<3, T, Q> convertD65XYZToLinearSRGB(vec<3, T, Q> const& ColorD65XYZ) { vec<3, T, Q> const M(0.41847f, -0.091169f, 0.0009209f); vec<3, T, Q> const N(-0.15866f, 0.25243f, 0.015708f); vec<3, T, Q> const O(0.0009209f, -0.0025498f, 0.1786f); return M * ColorD65XYZ + N * ColorD65XYZ + O * ColorD65XYZ; } template GLM_FUNC_QUALIFIER vec<3, T, Q> convertD65XYZToD50XYZ(vec<3, T, Q> const& ColorD65XYZ) { vec<3, T, Q> const M(+1.047844353856414f, +0.029549007606644f, -0.009250984365223f); vec<3, T, Q> const N(+0.022898981050086f, +0.990508028941971f, +0.015072338237051f); vec<3, T, Q> const O(-0.050206647741605f, -0.017074711360960f, +0.751717835079977f); return M * ColorD65XYZ + N * ColorD65XYZ + O * ColorD65XYZ; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/color_space.hpp000066400000000000000000000037751360521144700241350ustar00rootroot00000000000000/// @ref gtx_color_space /// @file glm/gtx/color_space.hpp /// /// @see core (dependence) /// /// @defgroup gtx_color_space GLM_GTX_color_space /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Related to RGB to HSV conversions and operations. #pragma once // Dependency: #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_color_space is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_color_space extension included") # endif #endif namespace glm { /// @addtogroup gtx_color_space /// @{ /// Converts a color from HSV color space to its color in RGB color space. /// @see gtx_color_space template GLM_FUNC_DECL vec<3, T, Q> rgbColor( vec<3, T, Q> const& hsvValue); /// Converts a color from RGB color space to its color in HSV color space. /// @see gtx_color_space template GLM_FUNC_DECL vec<3, T, Q> hsvColor( vec<3, T, Q> const& rgbValue); /// Build a saturation matrix. /// @see gtx_color_space template GLM_FUNC_DECL mat<4, 4, T, defaultp> saturation( T const s); /// Modify the saturation of a color. /// @see gtx_color_space template GLM_FUNC_DECL vec<3, T, Q> saturation( T const s, vec<3, T, Q> const& color); /// Modify the saturation of a color. /// @see gtx_color_space template GLM_FUNC_DECL vec<4, T, Q> saturation( T const s, vec<4, T, Q> const& color); /// Compute color luminosity associating ratios (0.33, 0.59, 0.11) to RGB canals. /// @see gtx_color_space template GLM_FUNC_DECL T luminosity( vec<3, T, Q> const& color); /// @} }//namespace glm #include "color_space.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/color_space.inl000066400000000000000000000064021360521144700241160ustar00rootroot00000000000000/// @ref gtx_color_space namespace glm { template GLM_FUNC_QUALIFIER vec<3, T, Q> rgbColor(const vec<3, T, Q>& hsvColor) { vec<3, T, Q> hsv = hsvColor; vec<3, T, Q> rgbColor; if(hsv.y == static_cast(0)) // achromatic (grey) rgbColor = vec<3, T, Q>(hsv.z); else { T sector = floor(hsv.x * (T(1) / T(60))); T frac = (hsv.x * (T(1) / T(60))) - sector; // factorial part of h T o = hsv.z * (T(1) - hsv.y); T p = hsv.z * (T(1) - hsv.y * frac); T q = hsv.z * (T(1) - hsv.y * (T(1) - frac)); switch(int(sector)) { default: case 0: rgbColor.r = hsv.z; rgbColor.g = q; rgbColor.b = o; break; case 1: rgbColor.r = p; rgbColor.g = hsv.z; rgbColor.b = o; break; case 2: rgbColor.r = o; rgbColor.g = hsv.z; rgbColor.b = q; break; case 3: rgbColor.r = o; rgbColor.g = p; rgbColor.b = hsv.z; break; case 4: rgbColor.r = q; rgbColor.g = o; rgbColor.b = hsv.z; break; case 5: rgbColor.r = hsv.z; rgbColor.g = o; rgbColor.b = p; break; } } return rgbColor; } template GLM_FUNC_QUALIFIER vec<3, T, Q> hsvColor(const vec<3, T, Q>& rgbColor) { vec<3, T, Q> hsv = rgbColor; float Min = min(min(rgbColor.r, rgbColor.g), rgbColor.b); float Max = max(max(rgbColor.r, rgbColor.g), rgbColor.b); float Delta = Max - Min; hsv.z = Max; if(Max != static_cast(0)) { hsv.y = Delta / hsv.z; T h = static_cast(0); if(rgbColor.r == Max) // between yellow & magenta h = static_cast(0) + T(60) * (rgbColor.g - rgbColor.b) / Delta; else if(rgbColor.g == Max) // between cyan & yellow h = static_cast(120) + T(60) * (rgbColor.b - rgbColor.r) / Delta; else // between magenta & cyan h = static_cast(240) + T(60) * (rgbColor.r - rgbColor.g) / Delta; if(h < T(0)) hsv.x = h + T(360); else hsv.x = h; } else { // If r = g = b = 0 then s = 0, h is undefined hsv.y = static_cast(0); hsv.x = static_cast(0); } return hsv; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> saturation(T const s) { vec<3, T, defaultp> rgbw = vec<3, T, defaultp>(T(0.2126), T(0.7152), T(0.0722)); vec<3, T, defaultp> const col((T(1) - s) * rgbw); mat<4, 4, T, defaultp> result(T(1)); result[0][0] = col.x + s; result[0][1] = col.x; result[0][2] = col.x; result[1][0] = col.y; result[1][1] = col.y + s; result[1][2] = col.y; result[2][0] = col.z; result[2][1] = col.z; result[2][2] = col.z + s; return result; } template GLM_FUNC_QUALIFIER vec<3, T, Q> saturation(const T s, const vec<3, T, Q>& color) { return vec<3, T, Q>(saturation(s) * vec<4, T, Q>(color, T(0))); } template GLM_FUNC_QUALIFIER vec<4, T, Q> saturation(const T s, const vec<4, T, Q>& color) { return saturation(s) * color; } template GLM_FUNC_QUALIFIER T luminosity(const vec<3, T, Q>& color) { const vec<3, T, Q> tmp = vec<3, T, Q>(0.33, 0.59, 0.11); return dot(color, tmp); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/color_space_YCoCg.hpp000066400000000000000000000036061360521144700251520ustar00rootroot00000000000000/// @ref gtx_color_space_YCoCg /// @file glm/gtx/color_space_YCoCg.hpp /// /// @see core (dependence) /// /// @defgroup gtx_color_space_YCoCg GLM_GTX_color_space_YCoCg /// @ingroup gtx /// /// Include to use the features of this extension. /// /// RGB to YCoCg conversions and operations #pragma once // Dependency: #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_color_space_YCoCg is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_color_space_YCoCg extension included") # endif #endif namespace glm { /// @addtogroup gtx_color_space_YCoCg /// @{ /// Convert a color from RGB color space to YCoCg color space. /// @see gtx_color_space_YCoCg template GLM_FUNC_DECL vec<3, T, Q> rgb2YCoCg( vec<3, T, Q> const& rgbColor); /// Convert a color from YCoCg color space to RGB color space. /// @see gtx_color_space_YCoCg template GLM_FUNC_DECL vec<3, T, Q> YCoCg2rgb( vec<3, T, Q> const& YCoCgColor); /// Convert a color from RGB color space to YCoCgR color space. /// @see "YCoCg-R: A Color Space with RGB Reversibility and Low Dynamic Range" /// @see gtx_color_space_YCoCg template GLM_FUNC_DECL vec<3, T, Q> rgb2YCoCgR( vec<3, T, Q> const& rgbColor); /// Convert a color from YCoCgR color space to RGB color space. /// @see "YCoCg-R: A Color Space with RGB Reversibility and Low Dynamic Range" /// @see gtx_color_space_YCoCg template GLM_FUNC_DECL vec<3, T, Q> YCoCgR2rgb( vec<3, T, Q> const& YCoCgColor); /// @} }//namespace glm #include "color_space_YCoCg.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/color_space_YCoCg.inl000066400000000000000000000054341360521144700251460ustar00rootroot00000000000000/// @ref gtx_color_space_YCoCg namespace glm { template GLM_FUNC_QUALIFIER vec<3, T, Q> rgb2YCoCg ( vec<3, T, Q> const& rgbColor ) { vec<3, T, Q> result; result.x/*Y */ = rgbColor.r / T(4) + rgbColor.g / T(2) + rgbColor.b / T(4); result.y/*Co*/ = rgbColor.r / T(2) + rgbColor.g * T(0) - rgbColor.b / T(2); result.z/*Cg*/ = - rgbColor.r / T(4) + rgbColor.g / T(2) - rgbColor.b / T(4); return result; } template GLM_FUNC_QUALIFIER vec<3, T, Q> YCoCg2rgb ( vec<3, T, Q> const& YCoCgColor ) { vec<3, T, Q> result; result.r = YCoCgColor.x + YCoCgColor.y - YCoCgColor.z; result.g = YCoCgColor.x + YCoCgColor.z; result.b = YCoCgColor.x - YCoCgColor.y - YCoCgColor.z; return result; } template class compute_YCoCgR { public: static GLM_FUNC_QUALIFIER vec<3, T, Q> rgb2YCoCgR ( vec<3, T, Q> const& rgbColor ) { vec<3, T, Q> result; result.x/*Y */ = rgbColor.g * static_cast(0.5) + (rgbColor.r + rgbColor.b) * static_cast(0.25); result.y/*Co*/ = rgbColor.r - rgbColor.b; result.z/*Cg*/ = rgbColor.g - (rgbColor.r + rgbColor.b) * static_cast(0.5); return result; } static GLM_FUNC_QUALIFIER vec<3, T, Q> YCoCgR2rgb ( vec<3, T, Q> const& YCoCgRColor ) { vec<3, T, Q> result; T tmp = YCoCgRColor.x - (YCoCgRColor.z * static_cast(0.5)); result.g = YCoCgRColor.z + tmp; result.b = tmp - (YCoCgRColor.y * static_cast(0.5)); result.r = result.b + YCoCgRColor.y; return result; } }; template class compute_YCoCgR { public: static GLM_FUNC_QUALIFIER vec<3, T, Q> rgb2YCoCgR ( vec<3, T, Q> const& rgbColor ) { vec<3, T, Q> result; result.y/*Co*/ = rgbColor.r - rgbColor.b; T tmp = rgbColor.b + (result.y >> 1); result.z/*Cg*/ = rgbColor.g - tmp; result.x/*Y */ = tmp + (result.z >> 1); return result; } static GLM_FUNC_QUALIFIER vec<3, T, Q> YCoCgR2rgb ( vec<3, T, Q> const& YCoCgRColor ) { vec<3, T, Q> result; T tmp = YCoCgRColor.x - (YCoCgRColor.z >> 1); result.g = YCoCgRColor.z + tmp; result.b = tmp - (YCoCgRColor.y >> 1); result.r = result.b + YCoCgRColor.y; return result; } }; template GLM_FUNC_QUALIFIER vec<3, T, Q> rgb2YCoCgR ( vec<3, T, Q> const& rgbColor ) { return compute_YCoCgR::is_integer>::rgb2YCoCgR(rgbColor); } template GLM_FUNC_QUALIFIER vec<3, T, Q> YCoCgR2rgb ( vec<3, T, Q> const& YCoCgRColor ) { return compute_YCoCgR::is_integer>::YCoCgR2rgb(YCoCgRColor); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/common.hpp000066400000000000000000000061701360521144700231240ustar00rootroot00000000000000/// @ref gtx_common /// @file glm/gtx/common.hpp /// /// @see core (dependence) /// /// @defgroup gtx_common GLM_GTX_common /// @ingroup gtx /// /// Include to use the features of this extension. /// /// @brief Provide functions to increase the compatibility with Cg and HLSL languages #pragma once // Dependencies: #include "../vec2.hpp" #include "../vec3.hpp" #include "../vec4.hpp" #include "../gtc/vec1.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_common is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_common extension included") # endif #endif namespace glm { /// @addtogroup gtx_common /// @{ /// Returns true if x is a denormalized number /// Numbers whose absolute value is too small to be represented in the normal format are represented in an alternate, denormalized format. /// This format is less precise but can represent values closer to zero. /// /// @tparam genType Floating-point scalar or vector types. /// /// @see GLSL isnan man page /// @see GLSL 4.20.8 specification, section 8.3 Common Functions template GLM_FUNC_DECL typename genType::bool_type isdenormal(genType const& x); /// Similar to 'mod' but with a different rounding and integer support. /// Returns 'x - y * trunc(x/y)' instead of 'x - y * floor(x/y)' /// /// @see GLSL mod vs HLSL fmod /// @see GLSL mod man page template GLM_FUNC_DECL vec fmod(vec const& v); /// Returns whether vector components values are within an interval. A open interval excludes its endpoints, and is denoted with square brackets. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum /// /// @see ext_vector_relational template GLM_FUNC_DECL vec openBounded(vec const& Value, vec const& Min, vec const& Max); /// Returns whether vector components values are within an interval. A closed interval includes its endpoints, and is denoted with square brackets. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or integer scalar types /// @tparam Q Value from qualifier enum /// /// @see ext_vector_relational template GLM_FUNC_DECL vec closeBounded(vec const& Value, vec const& Min, vec const& Max); /// @} }//namespace glm #include "common.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/common.inl000066400000000000000000000067611360521144700231250ustar00rootroot00000000000000/// @ref gtx_common #include #include "../gtc/epsilon.hpp" #include "../gtc/constants.hpp" namespace glm{ namespace detail { template struct compute_fmod { GLM_FUNC_QUALIFIER static vec call(vec const& a, vec const& b) { return detail::functor2::call(std::fmod, a, b); } }; template struct compute_fmod { GLM_FUNC_QUALIFIER static vec call(vec const& a, vec const& b) { return a % b; } }; }//namespace detail template GLM_FUNC_QUALIFIER bool isdenormal(T const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isdenormal' only accept floating-point inputs"); # if GLM_HAS_CXX11_STL return std::fpclassify(x) == FP_SUBNORMAL; # else return epsilonNotEqual(x, static_cast(0), epsilon()) && std::fabs(x) < std::numeric_limits::min(); # endif } template GLM_FUNC_QUALIFIER typename vec<1, T, Q>::bool_type isdenormal ( vec<1, T, Q> const& x ) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isdenormal' only accept floating-point inputs"); return typename vec<1, T, Q>::bool_type( isdenormal(x.x)); } template GLM_FUNC_QUALIFIER typename vec<2, T, Q>::bool_type isdenormal ( vec<2, T, Q> const& x ) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isdenormal' only accept floating-point inputs"); return typename vec<2, T, Q>::bool_type( isdenormal(x.x), isdenormal(x.y)); } template GLM_FUNC_QUALIFIER typename vec<3, T, Q>::bool_type isdenormal ( vec<3, T, Q> const& x ) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isdenormal' only accept floating-point inputs"); return typename vec<3, T, Q>::bool_type( isdenormal(x.x), isdenormal(x.y), isdenormal(x.z)); } template GLM_FUNC_QUALIFIER typename vec<4, T, Q>::bool_type isdenormal ( vec<4, T, Q> const& x ) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isdenormal' only accept floating-point inputs"); return typename vec<4, T, Q>::bool_type( isdenormal(x.x), isdenormal(x.y), isdenormal(x.z), isdenormal(x.w)); } // fmod template GLM_FUNC_QUALIFIER genType fmod(genType x, genType y) { return fmod(vec<1, genType>(x), y).x; } template GLM_FUNC_QUALIFIER vec fmod(vec const& x, T y) { return detail::compute_fmod::is_iec559>::call(x, vec(y)); } template GLM_FUNC_QUALIFIER vec fmod(vec const& x, vec const& y) { return detail::compute_fmod::is_iec559>::call(x, y); } template GLM_FUNC_QUALIFIER vec openBounded(vec const& Value, vec const& Min, vec const& Max) { return greaterThan(Value, Min) && lessThan(Value, Max); } template GLM_FUNC_QUALIFIER vec closeBounded(vec const& Value, vec const& Min, vec const& Max) { return greaterThanEqual(Value, Min) && lessThanEqual(Value, Max); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/compatibility.hpp000066400000000000000000000354221360521144700245070ustar00rootroot00000000000000/// @ref gtx_compatibility /// @file glm/gtx/compatibility.hpp /// /// @see core (dependence) /// /// @defgroup gtx_compatibility GLM_GTX_compatibility /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Provide functions to increase the compatibility with Cg and HLSL languages #pragma once // Dependency: #include "../glm.hpp" #include "../gtc/quaternion.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_compatibility is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_compatibility extension included") # endif #endif #if GLM_COMPILER & GLM_COMPILER_VC # include #elif GLM_COMPILER & GLM_COMPILER_GCC # include # if(GLM_PLATFORM & GLM_PLATFORM_ANDROID) # undef isfinite # endif #endif//GLM_COMPILER namespace glm { /// @addtogroup gtx_compatibility /// @{ template GLM_FUNC_QUALIFIER T lerp(T x, T y, T a){return mix(x, y, a);} //!< \brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) template GLM_FUNC_QUALIFIER vec<2, T, Q> lerp(const vec<2, T, Q>& x, const vec<2, T, Q>& y, T a){return mix(x, y, a);} //!< \brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) template GLM_FUNC_QUALIFIER vec<3, T, Q> lerp(const vec<3, T, Q>& x, const vec<3, T, Q>& y, T a){return mix(x, y, a);} //!< \brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) template GLM_FUNC_QUALIFIER vec<4, T, Q> lerp(const vec<4, T, Q>& x, const vec<4, T, Q>& y, T a){return mix(x, y, a);} //!< \brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) template GLM_FUNC_QUALIFIER vec<2, T, Q> lerp(const vec<2, T, Q>& x, const vec<2, T, Q>& y, const vec<2, T, Q>& a){return mix(x, y, a);} //!< \brief Returns the component-wise result of x * (1.0 - a) + y * a, i.e., the linear blend of x and y using vector a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) template GLM_FUNC_QUALIFIER vec<3, T, Q> lerp(const vec<3, T, Q>& x, const vec<3, T, Q>& y, const vec<3, T, Q>& a){return mix(x, y, a);} //!< \brief Returns the component-wise result of x * (1.0 - a) + y * a, i.e., the linear blend of x and y using vector a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) template GLM_FUNC_QUALIFIER vec<4, T, Q> lerp(const vec<4, T, Q>& x, const vec<4, T, Q>& y, const vec<4, T, Q>& a){return mix(x, y, a);} //!< \brief Returns the component-wise result of x * (1.0 - a) + y * a, i.e., the linear blend of x and y using vector a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility) template GLM_FUNC_QUALIFIER T saturate(T x){return clamp(x, T(0), T(1));} //!< \brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility) template GLM_FUNC_QUALIFIER vec<2, T, Q> saturate(const vec<2, T, Q>& x){return clamp(x, T(0), T(1));} //!< \brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility) template GLM_FUNC_QUALIFIER vec<3, T, Q> saturate(const vec<3, T, Q>& x){return clamp(x, T(0), T(1));} //!< \brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility) template GLM_FUNC_QUALIFIER vec<4, T, Q> saturate(const vec<4, T, Q>& x){return clamp(x, T(0), T(1));} //!< \brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility) template GLM_FUNC_QUALIFIER T atan2(T x, T y){return atan(x, y);} //!< \brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility) template GLM_FUNC_QUALIFIER vec<2, T, Q> atan2(const vec<2, T, Q>& x, const vec<2, T, Q>& y){return atan(x, y);} //!< \brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility) template GLM_FUNC_QUALIFIER vec<3, T, Q> atan2(const vec<3, T, Q>& x, const vec<3, T, Q>& y){return atan(x, y);} //!< \brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility) template GLM_FUNC_QUALIFIER vec<4, T, Q> atan2(const vec<4, T, Q>& x, const vec<4, T, Q>& y){return atan(x, y);} //!< \brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility) template GLM_FUNC_DECL bool isfinite(genType const& x); //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility) template GLM_FUNC_DECL vec<1, bool, Q> isfinite(const vec<1, T, Q>& x); //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility) template GLM_FUNC_DECL vec<2, bool, Q> isfinite(const vec<2, T, Q>& x); //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility) template GLM_FUNC_DECL vec<3, bool, Q> isfinite(const vec<3, T, Q>& x); //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility) template GLM_FUNC_DECL vec<4, bool, Q> isfinite(const vec<4, T, Q>& x); //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility) typedef bool bool1; //!< \brief boolean type with 1 component. (From GLM_GTX_compatibility extension) typedef vec<2, bool, highp> bool2; //!< \brief boolean type with 2 components. (From GLM_GTX_compatibility extension) typedef vec<3, bool, highp> bool3; //!< \brief boolean type with 3 components. (From GLM_GTX_compatibility extension) typedef vec<4, bool, highp> bool4; //!< \brief boolean type with 4 components. (From GLM_GTX_compatibility extension) typedef bool bool1x1; //!< \brief boolean matrix with 1 x 1 component. (From GLM_GTX_compatibility extension) typedef mat<2, 2, bool, highp> bool2x2; //!< \brief boolean matrix with 2 x 2 components. (From GLM_GTX_compatibility extension) typedef mat<2, 3, bool, highp> bool2x3; //!< \brief boolean matrix with 2 x 3 components. (From GLM_GTX_compatibility extension) typedef mat<2, 4, bool, highp> bool2x4; //!< \brief boolean matrix with 2 x 4 components. (From GLM_GTX_compatibility extension) typedef mat<3, 2, bool, highp> bool3x2; //!< \brief boolean matrix with 3 x 2 components. (From GLM_GTX_compatibility extension) typedef mat<3, 3, bool, highp> bool3x3; //!< \brief boolean matrix with 3 x 3 components. (From GLM_GTX_compatibility extension) typedef mat<3, 4, bool, highp> bool3x4; //!< \brief boolean matrix with 3 x 4 components. (From GLM_GTX_compatibility extension) typedef mat<4, 2, bool, highp> bool4x2; //!< \brief boolean matrix with 4 x 2 components. (From GLM_GTX_compatibility extension) typedef mat<4, 3, bool, highp> bool4x3; //!< \brief boolean matrix with 4 x 3 components. (From GLM_GTX_compatibility extension) typedef mat<4, 4, bool, highp> bool4x4; //!< \brief boolean matrix with 4 x 4 components. (From GLM_GTX_compatibility extension) typedef int int1; //!< \brief integer vector with 1 component. (From GLM_GTX_compatibility extension) typedef vec<2, int, highp> int2; //!< \brief integer vector with 2 components. (From GLM_GTX_compatibility extension) typedef vec<3, int, highp> int3; //!< \brief integer vector with 3 components. (From GLM_GTX_compatibility extension) typedef vec<4, int, highp> int4; //!< \brief integer vector with 4 components. (From GLM_GTX_compatibility extension) typedef int int1x1; //!< \brief integer matrix with 1 component. (From GLM_GTX_compatibility extension) typedef mat<2, 2, int, highp> int2x2; //!< \brief integer matrix with 2 x 2 components. (From GLM_GTX_compatibility extension) typedef mat<2, 3, int, highp> int2x3; //!< \brief integer matrix with 2 x 3 components. (From GLM_GTX_compatibility extension) typedef mat<2, 4, int, highp> int2x4; //!< \brief integer matrix with 2 x 4 components. (From GLM_GTX_compatibility extension) typedef mat<3, 2, int, highp> int3x2; //!< \brief integer matrix with 3 x 2 components. (From GLM_GTX_compatibility extension) typedef mat<3, 3, int, highp> int3x3; //!< \brief integer matrix with 3 x 3 components. (From GLM_GTX_compatibility extension) typedef mat<3, 4, int, highp> int3x4; //!< \brief integer matrix with 3 x 4 components. (From GLM_GTX_compatibility extension) typedef mat<4, 2, int, highp> int4x2; //!< \brief integer matrix with 4 x 2 components. (From GLM_GTX_compatibility extension) typedef mat<4, 3, int, highp> int4x3; //!< \brief integer matrix with 4 x 3 components. (From GLM_GTX_compatibility extension) typedef mat<4, 4, int, highp> int4x4; //!< \brief integer matrix with 4 x 4 components. (From GLM_GTX_compatibility extension) typedef float float1; //!< \brief single-qualifier floating-point vector with 1 component. (From GLM_GTX_compatibility extension) typedef vec<2, float, highp> float2; //!< \brief single-qualifier floating-point vector with 2 components. (From GLM_GTX_compatibility extension) typedef vec<3, float, highp> float3; //!< \brief single-qualifier floating-point vector with 3 components. (From GLM_GTX_compatibility extension) typedef vec<4, float, highp> float4; //!< \brief single-qualifier floating-point vector with 4 components. (From GLM_GTX_compatibility extension) typedef float float1x1; //!< \brief single-qualifier floating-point matrix with 1 component. (From GLM_GTX_compatibility extension) typedef mat<2, 2, float, highp> float2x2; //!< \brief single-qualifier floating-point matrix with 2 x 2 components. (From GLM_GTX_compatibility extension) typedef mat<2, 3, float, highp> float2x3; //!< \brief single-qualifier floating-point matrix with 2 x 3 components. (From GLM_GTX_compatibility extension) typedef mat<2, 4, float, highp> float2x4; //!< \brief single-qualifier floating-point matrix with 2 x 4 components. (From GLM_GTX_compatibility extension) typedef mat<3, 2, float, highp> float3x2; //!< \brief single-qualifier floating-point matrix with 3 x 2 components. (From GLM_GTX_compatibility extension) typedef mat<3, 3, float, highp> float3x3; //!< \brief single-qualifier floating-point matrix with 3 x 3 components. (From GLM_GTX_compatibility extension) typedef mat<3, 4, float, highp> float3x4; //!< \brief single-qualifier floating-point matrix with 3 x 4 components. (From GLM_GTX_compatibility extension) typedef mat<4, 2, float, highp> float4x2; //!< \brief single-qualifier floating-point matrix with 4 x 2 components. (From GLM_GTX_compatibility extension) typedef mat<4, 3, float, highp> float4x3; //!< \brief single-qualifier floating-point matrix with 4 x 3 components. (From GLM_GTX_compatibility extension) typedef mat<4, 4, float, highp> float4x4; //!< \brief single-qualifier floating-point matrix with 4 x 4 components. (From GLM_GTX_compatibility extension) typedef double double1; //!< \brief double-qualifier floating-point vector with 1 component. (From GLM_GTX_compatibility extension) typedef vec<2, double, highp> double2; //!< \brief double-qualifier floating-point vector with 2 components. (From GLM_GTX_compatibility extension) typedef vec<3, double, highp> double3; //!< \brief double-qualifier floating-point vector with 3 components. (From GLM_GTX_compatibility extension) typedef vec<4, double, highp> double4; //!< \brief double-qualifier floating-point vector with 4 components. (From GLM_GTX_compatibility extension) typedef double double1x1; //!< \brief double-qualifier floating-point matrix with 1 component. (From GLM_GTX_compatibility extension) typedef mat<2, 2, double, highp> double2x2; //!< \brief double-qualifier floating-point matrix with 2 x 2 components. (From GLM_GTX_compatibility extension) typedef mat<2, 3, double, highp> double2x3; //!< \brief double-qualifier floating-point matrix with 2 x 3 components. (From GLM_GTX_compatibility extension) typedef mat<2, 4, double, highp> double2x4; //!< \brief double-qualifier floating-point matrix with 2 x 4 components. (From GLM_GTX_compatibility extension) typedef mat<3, 2, double, highp> double3x2; //!< \brief double-qualifier floating-point matrix with 3 x 2 components. (From GLM_GTX_compatibility extension) typedef mat<3, 3, double, highp> double3x3; //!< \brief double-qualifier floating-point matrix with 3 x 3 components. (From GLM_GTX_compatibility extension) typedef mat<3, 4, double, highp> double3x4; //!< \brief double-qualifier floating-point matrix with 3 x 4 components. (From GLM_GTX_compatibility extension) typedef mat<4, 2, double, highp> double4x2; //!< \brief double-qualifier floating-point matrix with 4 x 2 components. (From GLM_GTX_compatibility extension) typedef mat<4, 3, double, highp> double4x3; //!< \brief double-qualifier floating-point matrix with 4 x 3 components. (From GLM_GTX_compatibility extension) typedef mat<4, 4, double, highp> double4x4; //!< \brief double-qualifier floating-point matrix with 4 x 4 components. (From GLM_GTX_compatibility extension) /// @} }//namespace glm #include "compatibility.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/compatibility.inl000066400000000000000000000027631360521144700245040ustar00rootroot00000000000000#include namespace glm { // isfinite template GLM_FUNC_QUALIFIER bool isfinite( genType const& x) { # if GLM_HAS_CXX11_STL return std::isfinite(x) != 0; # elif GLM_COMPILER & GLM_COMPILER_VC return _finite(x) != 0; # elif GLM_COMPILER & GLM_COMPILER_GCC && GLM_PLATFORM & GLM_PLATFORM_ANDROID return _isfinite(x) != 0; # else if (std::numeric_limits::is_integer || std::denorm_absent == std::numeric_limits::has_denorm) return std::numeric_limits::min() <= x && std::numeric_limits::max() >= x; else return -std::numeric_limits::max() <= x && std::numeric_limits::max() >= x; # endif } template GLM_FUNC_QUALIFIER vec<1, bool, Q> isfinite( vec<1, T, Q> const& x) { return vec<1, bool, Q>( isfinite(x.x)); } template GLM_FUNC_QUALIFIER vec<2, bool, Q> isfinite( vec<2, T, Q> const& x) { return vec<2, bool, Q>( isfinite(x.x), isfinite(x.y)); } template GLM_FUNC_QUALIFIER vec<3, bool, Q> isfinite( vec<3, T, Q> const& x) { return vec<3, bool, Q>( isfinite(x.x), isfinite(x.y), isfinite(x.z)); } template GLM_FUNC_QUALIFIER vec<4, bool, Q> isfinite( vec<4, T, Q> const& x) { return vec<4, bool, Q>( isfinite(x.x), isfinite(x.y), isfinite(x.z), isfinite(x.w)); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/component_wise.hpp000066400000000000000000000045641360521144700246720ustar00rootroot00000000000000/// @ref gtx_component_wise /// @file glm/gtx/component_wise.hpp /// @date 2007-05-21 / 2011-06-07 /// @author Christophe Riccio /// /// @see core (dependence) /// /// @defgroup gtx_component_wise GLM_GTX_component_wise /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Operations between components of a type #pragma once // Dependencies #include "../detail/setup.hpp" #include "../detail/qualifier.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_component_wise is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_component_wise extension included") # endif #endif namespace glm { /// @addtogroup gtx_component_wise /// @{ /// Convert an integer vector to a normalized float vector. /// If the parameter value type is already a floating qualifier type, the value is passed through. /// @see gtx_component_wise template GLM_FUNC_DECL vec compNormalize(vec const& v); /// Convert a normalized float vector to an integer vector. /// If the parameter value type is already a floating qualifier type, the value is passed through. /// @see gtx_component_wise template GLM_FUNC_DECL vec compScale(vec const& v); /// Add all vector components together. /// @see gtx_component_wise template GLM_FUNC_DECL typename genType::value_type compAdd(genType const& v); /// Multiply all vector components together. /// @see gtx_component_wise template GLM_FUNC_DECL typename genType::value_type compMul(genType const& v); /// Find the minimum value between single vector components. /// @see gtx_component_wise template GLM_FUNC_DECL typename genType::value_type compMin(genType const& v); /// Find the maximum value between single vector components. /// @see gtx_component_wise template GLM_FUNC_DECL typename genType::value_type compMax(genType const& v); /// @} }//namespace glm #include "component_wise.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/component_wise.inl000066400000000000000000000103331360521144700246540ustar00rootroot00000000000000/// @ref gtx_component_wise #include namespace glm{ namespace detail { template struct compute_compNormalize {}; template struct compute_compNormalize { GLM_FUNC_QUALIFIER static vec call(vec const& v) { floatType const Min = static_cast(std::numeric_limits::min()); floatType const Max = static_cast(std::numeric_limits::max()); return (vec(v) - Min) / (Max - Min) * static_cast(2) - static_cast(1); } }; template struct compute_compNormalize { GLM_FUNC_QUALIFIER static vec call(vec const& v) { return vec(v) / static_cast(std::numeric_limits::max()); } }; template struct compute_compNormalize { GLM_FUNC_QUALIFIER static vec call(vec const& v) { return v; } }; template struct compute_compScale {}; template struct compute_compScale { GLM_FUNC_QUALIFIER static vec call(vec const& v) { floatType const Max = static_cast(std::numeric_limits::max()) + static_cast(0.5); vec const Scaled(v * Max); vec const Result(Scaled - static_cast(0.5)); return Result; } }; template struct compute_compScale { GLM_FUNC_QUALIFIER static vec call(vec const& v) { return vec(vec(v) * static_cast(std::numeric_limits::max())); } }; template struct compute_compScale { GLM_FUNC_QUALIFIER static vec call(vec const& v) { return v; } }; }//namespace detail template GLM_FUNC_QUALIFIER vec compNormalize(vec const& v) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'compNormalize' accepts only floating-point types for 'floatType' template parameter"); return detail::compute_compNormalize::is_integer, std::numeric_limits::is_signed>::call(v); } template GLM_FUNC_QUALIFIER vec compScale(vec const& v) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'compScale' accepts only floating-point types for 'floatType' template parameter"); return detail::compute_compScale::is_integer, std::numeric_limits::is_signed>::call(v); } template GLM_FUNC_QUALIFIER T compAdd(vec const& v) { T Result(0); for(length_t i = 0, n = v.length(); i < n; ++i) Result += v[i]; return Result; } template GLM_FUNC_QUALIFIER T compMul(vec const& v) { T Result(1); for(length_t i = 0, n = v.length(); i < n; ++i) Result *= v[i]; return Result; } template GLM_FUNC_QUALIFIER T compMin(vec const& v) { T Result(v[0]); for(length_t i = 1, n = v.length(); i < n; ++i) Result = min(Result, v[i]); return Result; } template GLM_FUNC_QUALIFIER T compMax(vec const& v) { T Result(v[0]); for(length_t i = 1, n = v.length(); i < n; ++i) Result = max(Result, v[i]); return Result; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/dual_quaternion.hpp000066400000000000000000000230111360521144700250170ustar00rootroot00000000000000/// @ref gtx_dual_quaternion /// @file glm/gtx/dual_quaternion.hpp /// @author Maksim Vorobiev (msomeone@gmail.com) /// /// @see core (dependence) /// @see gtc_constants (dependence) /// @see gtc_quaternion (dependence) /// /// @defgroup gtx_dual_quaternion GLM_GTX_dual_quaternion /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Defines a templated dual-quaternion type and several dual-quaternion operations. #pragma once // Dependency: #include "../glm.hpp" #include "../gtc/constants.hpp" #include "../gtc/quaternion.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_dual_quaternion is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_dual_quaternion extension included") # endif #endif namespace glm { /// @addtogroup gtx_dual_quaternion /// @{ template struct tdualquat { // -- Implementation detail -- typedef T value_type; typedef qua part_type; // -- Data -- qua real, dual; // -- Component accesses -- typedef length_t length_type; /// Return the count of components of a dual quaternion GLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 2;} GLM_FUNC_DECL part_type & operator[](length_type i); GLM_FUNC_DECL part_type const& operator[](length_type i) const; // -- Implicit basic constructors -- GLM_FUNC_DECL GLM_CONSTEXPR tdualquat() GLM_DEFAULT; GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(tdualquat const& d) GLM_DEFAULT; template GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(tdualquat const& d); // -- Explicit basic constructors -- GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(qua const& real); GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(qua const& orientation, vec<3, T, Q> const& translation); GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(qua const& real, qua const& dual); // -- Conversion constructors -- template GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT tdualquat(tdualquat const& q); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR tdualquat(mat<2, 4, T, Q> const& holder_mat); GLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR tdualquat(mat<3, 4, T, Q> const& aug_mat); // -- Unary arithmetic operators -- GLM_FUNC_DECL tdualquat & operator=(tdualquat const& m) GLM_DEFAULT; template GLM_FUNC_DECL tdualquat & operator=(tdualquat const& m); template GLM_FUNC_DECL tdualquat & operator*=(U s); template GLM_FUNC_DECL tdualquat & operator/=(U s); }; // -- Unary bit operators -- template GLM_FUNC_DECL tdualquat operator+(tdualquat const& q); template GLM_FUNC_DECL tdualquat operator-(tdualquat const& q); // -- Binary operators -- template GLM_FUNC_DECL tdualquat operator+(tdualquat const& q, tdualquat const& p); template GLM_FUNC_DECL tdualquat operator*(tdualquat const& q, tdualquat const& p); template GLM_FUNC_DECL vec<3, T, Q> operator*(tdualquat const& q, vec<3, T, Q> const& v); template GLM_FUNC_DECL vec<3, T, Q> operator*(vec<3, T, Q> const& v, tdualquat const& q); template GLM_FUNC_DECL vec<4, T, Q> operator*(tdualquat const& q, vec<4, T, Q> const& v); template GLM_FUNC_DECL vec<4, T, Q> operator*(vec<4, T, Q> const& v, tdualquat const& q); template GLM_FUNC_DECL tdualquat operator*(tdualquat const& q, T const& s); template GLM_FUNC_DECL tdualquat operator*(T const& s, tdualquat const& q); template GLM_FUNC_DECL tdualquat operator/(tdualquat const& q, T const& s); // -- Boolean operators -- template GLM_FUNC_DECL bool operator==(tdualquat const& q1, tdualquat const& q2); template GLM_FUNC_DECL bool operator!=(tdualquat const& q1, tdualquat const& q2); /// Creates an identity dual quaternion. /// /// @see gtx_dual_quaternion template GLM_FUNC_DECL tdualquat dual_quat_identity(); /// Returns the normalized quaternion. /// /// @see gtx_dual_quaternion template GLM_FUNC_DECL tdualquat normalize(tdualquat const& q); /// Returns the linear interpolation of two dual quaternion. /// /// @see gtc_dual_quaternion template GLM_FUNC_DECL tdualquat lerp(tdualquat const& x, tdualquat const& y, T const& a); /// Returns the q inverse. /// /// @see gtx_dual_quaternion template GLM_FUNC_DECL tdualquat inverse(tdualquat const& q); /// Converts a quaternion to a 2 * 4 matrix. /// /// @see gtx_dual_quaternion template GLM_FUNC_DECL mat<2, 4, T, Q> mat2x4_cast(tdualquat const& x); /// Converts a quaternion to a 3 * 4 matrix. /// /// @see gtx_dual_quaternion template GLM_FUNC_DECL mat<3, 4, T, Q> mat3x4_cast(tdualquat const& x); /// Converts a 2 * 4 matrix (matrix which holds real and dual parts) to a quaternion. /// /// @see gtx_dual_quaternion template GLM_FUNC_DECL tdualquat dualquat_cast(mat<2, 4, T, Q> const& x); /// Converts a 3 * 4 matrix (augmented matrix rotation + translation) to a quaternion. /// /// @see gtx_dual_quaternion template GLM_FUNC_DECL tdualquat dualquat_cast(mat<3, 4, T, Q> const& x); /// Dual-quaternion of low single-qualifier floating-point numbers. /// /// @see gtx_dual_quaternion typedef tdualquat lowp_dualquat; /// Dual-quaternion of medium single-qualifier floating-point numbers. /// /// @see gtx_dual_quaternion typedef tdualquat mediump_dualquat; /// Dual-quaternion of high single-qualifier floating-point numbers. /// /// @see gtx_dual_quaternion typedef tdualquat highp_dualquat; /// Dual-quaternion of low single-qualifier floating-point numbers. /// /// @see gtx_dual_quaternion typedef tdualquat lowp_fdualquat; /// Dual-quaternion of medium single-qualifier floating-point numbers. /// /// @see gtx_dual_quaternion typedef tdualquat mediump_fdualquat; /// Dual-quaternion of high single-qualifier floating-point numbers. /// /// @see gtx_dual_quaternion typedef tdualquat highp_fdualquat; /// Dual-quaternion of low double-qualifier floating-point numbers. /// /// @see gtx_dual_quaternion typedef tdualquat lowp_ddualquat; /// Dual-quaternion of medium double-qualifier floating-point numbers. /// /// @see gtx_dual_quaternion typedef tdualquat mediump_ddualquat; /// Dual-quaternion of high double-qualifier floating-point numbers. /// /// @see gtx_dual_quaternion typedef tdualquat highp_ddualquat; #if(!defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT)) /// Dual-quaternion of floating-point numbers. /// /// @see gtx_dual_quaternion typedef highp_fdualquat dualquat; /// Dual-quaternion of single-qualifier floating-point numbers. /// /// @see gtx_dual_quaternion typedef highp_fdualquat fdualquat; #elif(defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT)) typedef highp_fdualquat dualquat; typedef highp_fdualquat fdualquat; #elif(!defined(GLM_PRECISION_HIGHP_FLOAT) && defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT)) typedef mediump_fdualquat dualquat; typedef mediump_fdualquat fdualquat; #elif(!defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && defined(GLM_PRECISION_LOWP_FLOAT)) typedef lowp_fdualquat dualquat; typedef lowp_fdualquat fdualquat; #else # error "GLM error: multiple default precision requested for single-precision floating-point types" #endif #if(!defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE)) /// Dual-quaternion of default double-qualifier floating-point numbers. /// /// @see gtx_dual_quaternion typedef highp_ddualquat ddualquat; #elif(defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE)) typedef highp_ddualquat ddualquat; #elif(!defined(GLM_PRECISION_HIGHP_DOUBLE) && defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE)) typedef mediump_ddualquat ddualquat; #elif(!defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && defined(GLM_PRECISION_LOWP_DOUBLE)) typedef lowp_ddualquat ddualquat; #else # error "GLM error: Multiple default precision requested for double-precision floating-point types" #endif /// @} } //namespace glm #include "dual_quaternion.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/dual_quaternion.inl000066400000000000000000000246661360521144700250330ustar00rootroot00000000000000/// @ref gtx_dual_quaternion #include "../geometric.hpp" #include namespace glm { // -- Component accesses -- template GLM_FUNC_QUALIFIER typename tdualquat::part_type & tdualquat::operator[](typename tdualquat::length_type i) { assert(i >= 0 && i < this->length()); return (&real)[i]; } template GLM_FUNC_QUALIFIER typename tdualquat::part_type const& tdualquat::operator[](typename tdualquat::length_type i) const { assert(i >= 0 && i < this->length()); return (&real)[i]; } // -- Implicit basic constructors -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat() # if GLM_CONFIG_DEFAULTED_FUNCTIONS != GLM_DISABLE : real(qua()) , dual(qua(0, 0, 0, 0)) # endif {} template GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(tdualquat const& d) : real(d.real) , dual(d.dual) {} # endif template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(tdualquat const& d) : real(d.real) , dual(d.dual) {} // -- Explicit basic constructors -- template GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(qua const& r) : real(r), dual(qua(0, 0, 0, 0)) {} template GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(qua const& q, vec<3, T, Q> const& p) : real(q), dual( T(-0.5) * ( p.x*q.x + p.y*q.y + p.z*q.z), T(+0.5) * ( p.x*q.w + p.y*q.z - p.z*q.y), T(+0.5) * (-p.x*q.z + p.y*q.w + p.z*q.x), T(+0.5) * ( p.x*q.y - p.y*q.x + p.z*q.w)) {} template GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(qua const& r, qua const& d) : real(r), dual(d) {} // -- Conversion constructors -- template template GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(tdualquat const& q) : real(q.real) , dual(q.dual) {} template GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(mat<2, 4, T, Q> const& m) { *this = dualquat_cast(m); } template GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat::tdualquat(mat<3, 4, T, Q> const& m) { *this = dualquat_cast(m); } // -- Unary arithmetic operators -- # if GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE template GLM_FUNC_QUALIFIER tdualquat & tdualquat::operator=(tdualquat const& q) { this->real = q.real; this->dual = q.dual; return *this; } # endif template template GLM_FUNC_QUALIFIER tdualquat & tdualquat::operator=(tdualquat const& q) { this->real = q.real; this->dual = q.dual; return *this; } template template GLM_FUNC_QUALIFIER tdualquat & tdualquat::operator*=(U s) { this->real *= static_cast(s); this->dual *= static_cast(s); return *this; } template template GLM_FUNC_QUALIFIER tdualquat & tdualquat::operator/=(U s) { this->real /= static_cast(s); this->dual /= static_cast(s); return *this; } // -- Unary bit operators -- template GLM_FUNC_QUALIFIER tdualquat operator+(tdualquat const& q) { return q; } template GLM_FUNC_QUALIFIER tdualquat operator-(tdualquat const& q) { return tdualquat(-q.real, -q.dual); } // -- Binary operators -- template GLM_FUNC_QUALIFIER tdualquat operator+(tdualquat const& q, tdualquat const& p) { return tdualquat(q.real + p.real,q.dual + p.dual); } template GLM_FUNC_QUALIFIER tdualquat operator*(tdualquat const& p, tdualquat const& o) { return tdualquat(p.real * o.real,p.real * o.dual + p.dual * o.real); } template GLM_FUNC_QUALIFIER vec<3, T, Q> operator*(tdualquat const& q, vec<3, T, Q> const& v) { vec<3, T, Q> const real_v3(q.real.x,q.real.y,q.real.z); vec<3, T, Q> const dual_v3(q.dual.x,q.dual.y,q.dual.z); return (cross(real_v3, cross(real_v3,v) + v * q.real.w + dual_v3) + dual_v3 * q.real.w - real_v3 * q.dual.w) * T(2) + v; } template GLM_FUNC_QUALIFIER vec<3, T, Q> operator*(vec<3, T, Q> const& v, tdualquat const& q) { return glm::inverse(q) * v; } template GLM_FUNC_QUALIFIER vec<4, T, Q> operator*(tdualquat const& q, vec<4, T, Q> const& v) { return vec<4, T, Q>(q * vec<3, T, Q>(v), v.w); } template GLM_FUNC_QUALIFIER vec<4, T, Q> operator*(vec<4, T, Q> const& v, tdualquat const& q) { return glm::inverse(q) * v; } template GLM_FUNC_QUALIFIER tdualquat operator*(tdualquat const& q, T const& s) { return tdualquat(q.real * s, q.dual * s); } template GLM_FUNC_QUALIFIER tdualquat operator*(T const& s, tdualquat const& q) { return q * s; } template GLM_FUNC_QUALIFIER tdualquat operator/(tdualquat const& q, T const& s) { return tdualquat(q.real / s, q.dual / s); } // -- Boolean operators -- template GLM_FUNC_QUALIFIER bool operator==(tdualquat const& q1, tdualquat const& q2) { return (q1.real == q2.real) && (q1.dual == q2.dual); } template GLM_FUNC_QUALIFIER bool operator!=(tdualquat const& q1, tdualquat const& q2) { return (q1.real != q2.real) || (q1.dual != q2.dual); } // -- Operations -- template GLM_FUNC_QUALIFIER tdualquat dual_quat_identity() { return tdualquat( qua(static_cast(1), static_cast(0), static_cast(0), static_cast(0)), qua(static_cast(0), static_cast(0), static_cast(0), static_cast(0))); } template GLM_FUNC_QUALIFIER tdualquat normalize(tdualquat const& q) { return q / length(q.real); } template GLM_FUNC_QUALIFIER tdualquat lerp(tdualquat const& x, tdualquat const& y, T const& a) { // Dual Quaternion Linear blend aka DLB: // Lerp is only defined in [0, 1] assert(a >= static_cast(0)); assert(a <= static_cast(1)); T const k = dot(x.real,y.real) < static_cast(0) ? -a : a; T const one(1); return tdualquat(x * (one - a) + y * k); } template GLM_FUNC_QUALIFIER tdualquat inverse(tdualquat const& q) { const glm::qua real = conjugate(q.real); const glm::qua dual = conjugate(q.dual); return tdualquat(real, dual + (real * (-2.0f * dot(real,dual)))); } template GLM_FUNC_QUALIFIER mat<2, 4, T, Q> mat2x4_cast(tdualquat const& x) { return mat<2, 4, T, Q>( x[0].x, x[0].y, x[0].z, x[0].w, x[1].x, x[1].y, x[1].z, x[1].w ); } template GLM_FUNC_QUALIFIER mat<3, 4, T, Q> mat3x4_cast(tdualquat const& x) { qua r = x.real / length2(x.real); qua const rr(r.w * x.real.w, r.x * x.real.x, r.y * x.real.y, r.z * x.real.z); r *= static_cast(2); T const xy = r.x * x.real.y; T const xz = r.x * x.real.z; T const yz = r.y * x.real.z; T const wx = r.w * x.real.x; T const wy = r.w * x.real.y; T const wz = r.w * x.real.z; vec<4, T, Q> const a( rr.w + rr.x - rr.y - rr.z, xy - wz, xz + wy, -(x.dual.w * r.x - x.dual.x * r.w + x.dual.y * r.z - x.dual.z * r.y)); vec<4, T, Q> const b( xy + wz, rr.w + rr.y - rr.x - rr.z, yz - wx, -(x.dual.w * r.y - x.dual.x * r.z - x.dual.y * r.w + x.dual.z * r.x)); vec<4, T, Q> const c( xz - wy, yz + wx, rr.w + rr.z - rr.x - rr.y, -(x.dual.w * r.z + x.dual.x * r.y - x.dual.y * r.x - x.dual.z * r.w)); return mat<3, 4, T, Q>(a, b, c); } template GLM_FUNC_QUALIFIER tdualquat dualquat_cast(mat<2, 4, T, Q> const& x) { return tdualquat( qua( x[0].w, x[0].x, x[0].y, x[0].z ), qua( x[1].w, x[1].x, x[1].y, x[1].z )); } template GLM_FUNC_QUALIFIER tdualquat dualquat_cast(mat<3, 4, T, Q> const& x) { qua real; T const trace = x[0].x + x[1].y + x[2].z; if(trace > static_cast(0)) { T const r = sqrt(T(1) + trace); T const invr = static_cast(0.5) / r; real.w = static_cast(0.5) * r; real.x = (x[2].y - x[1].z) * invr; real.y = (x[0].z - x[2].x) * invr; real.z = (x[1].x - x[0].y) * invr; } else if(x[0].x > x[1].y && x[0].x > x[2].z) { T const r = sqrt(T(1) + x[0].x - x[1].y - x[2].z); T const invr = static_cast(0.5) / r; real.x = static_cast(0.5)*r; real.y = (x[1].x + x[0].y) * invr; real.z = (x[0].z + x[2].x) * invr; real.w = (x[2].y - x[1].z) * invr; } else if(x[1].y > x[2].z) { T const r = sqrt(T(1) + x[1].y - x[0].x - x[2].z); T const invr = static_cast(0.5) / r; real.x = (x[1].x + x[0].y) * invr; real.y = static_cast(0.5) * r; real.z = (x[2].y + x[1].z) * invr; real.w = (x[0].z - x[2].x) * invr; } else { T const r = sqrt(T(1) + x[2].z - x[0].x - x[1].y); T const invr = static_cast(0.5) / r; real.x = (x[0].z + x[2].x) * invr; real.y = (x[2].y + x[1].z) * invr; real.z = static_cast(0.5) * r; real.w = (x[1].x - x[0].y) * invr; } qua dual; dual.x = static_cast(0.5) * ( x[0].w * real.w + x[1].w * real.z - x[2].w * real.y); dual.y = static_cast(0.5) * (-x[0].w * real.z + x[1].w * real.w + x[2].w * real.x); dual.z = static_cast(0.5) * ( x[0].w * real.y - x[1].w * real.x + x[2].w * real.w); dual.w = -static_cast(0.5) * ( x[0].w * real.x + x[1].w * real.y + x[2].w * real.z); return tdualquat(real, dual); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/easing.hpp000066400000000000000000000156641360521144700231120ustar00rootroot00000000000000/// @ref gtx_easing /// @file glm/gtx/easing.hpp /// @author Robert Chisholm /// /// @see core (dependence) /// /// @defgroup gtx_easing GLM_GTX_easing /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Easing functions for animations and transitons /// All functions take a parameter x in the range [0.0,1.0] /// /// Based on the AHEasing project of Warren Moore (https://github.com/warrenm/AHEasing) #pragma once // Dependency: #include "../glm.hpp" #include "../gtc/constants.hpp" #include "../detail/qualifier.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_easing is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_easing extension included") # endif #endif namespace glm{ /// @addtogroup gtx_easing /// @{ /// Modelled after the line y = x /// @see gtx_easing template GLM_FUNC_DECL genType linearInterpolation(genType const & a); /// Modelled after the parabola y = x^2 /// @see gtx_easing template GLM_FUNC_DECL genType quadraticEaseIn(genType const & a); /// Modelled after the parabola y = -x^2 + 2x /// @see gtx_easing template GLM_FUNC_DECL genType quadraticEaseOut(genType const & a); /// Modelled after the piecewise quadratic /// y = (1/2)((2x)^2) ; [0, 0.5) /// y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1] /// @see gtx_easing template GLM_FUNC_DECL genType quadraticEaseInOut(genType const & a); /// Modelled after the cubic y = x^3 template GLM_FUNC_DECL genType cubicEaseIn(genType const & a); /// Modelled after the cubic y = (x - 1)^3 + 1 /// @see gtx_easing template GLM_FUNC_DECL genType cubicEaseOut(genType const & a); /// Modelled after the piecewise cubic /// y = (1/2)((2x)^3) ; [0, 0.5) /// y = (1/2)((2x-2)^3 + 2) ; [0.5, 1] /// @see gtx_easing template GLM_FUNC_DECL genType cubicEaseInOut(genType const & a); /// Modelled after the quartic x^4 /// @see gtx_easing template GLM_FUNC_DECL genType quarticEaseIn(genType const & a); /// Modelled after the quartic y = 1 - (x - 1)^4 /// @see gtx_easing template GLM_FUNC_DECL genType quarticEaseOut(genType const & a); /// Modelled after the piecewise quartic /// y = (1/2)((2x)^4) ; [0, 0.5) /// y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1] /// @see gtx_easing template GLM_FUNC_DECL genType quarticEaseInOut(genType const & a); /// Modelled after the quintic y = x^5 /// @see gtx_easing template GLM_FUNC_DECL genType quinticEaseIn(genType const & a); /// Modelled after the quintic y = (x - 1)^5 + 1 /// @see gtx_easing template GLM_FUNC_DECL genType quinticEaseOut(genType const & a); /// Modelled after the piecewise quintic /// y = (1/2)((2x)^5) ; [0, 0.5) /// y = (1/2)((2x-2)^5 + 2) ; [0.5, 1] /// @see gtx_easing template GLM_FUNC_DECL genType quinticEaseInOut(genType const & a); /// Modelled after quarter-cycle of sine wave /// @see gtx_easing template GLM_FUNC_DECL genType sineEaseIn(genType const & a); /// Modelled after quarter-cycle of sine wave (different phase) /// @see gtx_easing template GLM_FUNC_DECL genType sineEaseOut(genType const & a); /// Modelled after half sine wave /// @see gtx_easing template GLM_FUNC_DECL genType sineEaseInOut(genType const & a); /// Modelled after shifted quadrant IV of unit circle /// @see gtx_easing template GLM_FUNC_DECL genType circularEaseIn(genType const & a); /// Modelled after shifted quadrant II of unit circle /// @see gtx_easing template GLM_FUNC_DECL genType circularEaseOut(genType const & a); /// Modelled after the piecewise circular function /// y = (1/2)(1 - sqrt(1 - 4x^2)) ; [0, 0.5) /// y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1] /// @see gtx_easing template GLM_FUNC_DECL genType circularEaseInOut(genType const & a); /// Modelled after the exponential function y = 2^(10(x - 1)) /// @see gtx_easing template GLM_FUNC_DECL genType exponentialEaseIn(genType const & a); /// Modelled after the exponential function y = -2^(-10x) + 1 /// @see gtx_easing template GLM_FUNC_DECL genType exponentialEaseOut(genType const & a); /// Modelled after the piecewise exponential /// y = (1/2)2^(10(2x - 1)) ; [0,0.5) /// y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1] /// @see gtx_easing template GLM_FUNC_DECL genType exponentialEaseInOut(genType const & a); /// Modelled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1)) /// @see gtx_easing template GLM_FUNC_DECL genType elasticEaseIn(genType const & a); /// Modelled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1 /// @see gtx_easing template GLM_FUNC_DECL genType elasticEaseOut(genType const & a); /// Modelled after the piecewise exponentially-damped sine wave: /// y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5) /// y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1] /// @see gtx_easing template GLM_FUNC_DECL genType elasticEaseInOut(genType const & a); /// @see gtx_easing template GLM_FUNC_DECL genType backEaseIn(genType const& a); /// @see gtx_easing template GLM_FUNC_DECL genType backEaseOut(genType const& a); /// @see gtx_easing template GLM_FUNC_DECL genType backEaseInOut(genType const& a); /// @param a parameter /// @param o Optional overshoot modifier /// @see gtx_easing template GLM_FUNC_DECL genType backEaseIn(genType const& a, genType const& o); /// @param a parameter /// @param o Optional overshoot modifier /// @see gtx_easing template GLM_FUNC_DECL genType backEaseOut(genType const& a, genType const& o); /// @param a parameter /// @param o Optional overshoot modifier /// @see gtx_easing template GLM_FUNC_DECL genType backEaseInOut(genType const& a, genType const& o); /// @see gtx_easing template GLM_FUNC_DECL genType bounceEaseIn(genType const& a); /// @see gtx_easing template GLM_FUNC_DECL genType bounceEaseOut(genType const& a); /// @see gtx_easing template GLM_FUNC_DECL genType bounceEaseInOut(genType const& a); /// @} }//namespace glm #include "easing.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/easing.inl000066400000000000000000000275501360521144700231020ustar00rootroot00000000000000/// @ref gtx_easing #include namespace glm{ template GLM_FUNC_QUALIFIER genType linearInterpolation(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); return a; } template GLM_FUNC_QUALIFIER genType quadraticEaseIn(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); return a * a; } template GLM_FUNC_QUALIFIER genType quadraticEaseOut(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); return -(a * (a - static_cast(2))); } template GLM_FUNC_QUALIFIER genType quadraticEaseInOut(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); if(a < static_cast(0.5)) { return static_cast(2) * a * a; } else { return (-static_cast(2) * a * a) + (4 * a) - one(); } } template GLM_FUNC_QUALIFIER genType cubicEaseIn(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); return a * a * a; } template GLM_FUNC_QUALIFIER genType cubicEaseOut(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); genType const f = a - one(); return f * f * f + one(); } template GLM_FUNC_QUALIFIER genType cubicEaseInOut(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); if (a < static_cast(0.5)) { return static_cast(4) * a * a * a; } else { genType const f = ((static_cast(2) * a) - static_cast(2)); return static_cast(0.5) * f * f * f + one(); } } template GLM_FUNC_QUALIFIER genType quarticEaseIn(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); return a * a * a * a; } template GLM_FUNC_QUALIFIER genType quarticEaseOut(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); genType const f = (a - one()); return f * f * f * (one() - a) + one(); } template GLM_FUNC_QUALIFIER genType quarticEaseInOut(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); if(a < static_cast(0.5)) { return static_cast(8) * a * a * a * a; } else { genType const f = (a - one()); return -static_cast(8) * f * f * f * f + one(); } } template GLM_FUNC_QUALIFIER genType quinticEaseIn(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); return a * a * a * a * a; } template GLM_FUNC_QUALIFIER genType quinticEaseOut(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); genType const f = (a - one()); return f * f * f * f * f + one(); } template GLM_FUNC_QUALIFIER genType quinticEaseInOut(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); if(a < static_cast(0.5)) { return static_cast(16) * a * a * a * a * a; } else { genType const f = ((static_cast(2) * a) - static_cast(2)); return static_cast(0.5) * f * f * f * f * f + one(); } } template GLM_FUNC_QUALIFIER genType sineEaseIn(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); return sin((a - one()) * half_pi()) + one(); } template GLM_FUNC_QUALIFIER genType sineEaseOut(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); return sin(a * half_pi()); } template GLM_FUNC_QUALIFIER genType sineEaseInOut(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); return static_cast(0.5) * (one() - cos(a * pi())); } template GLM_FUNC_QUALIFIER genType circularEaseIn(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); return one() - sqrt(one() - (a * a)); } template GLM_FUNC_QUALIFIER genType circularEaseOut(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); return sqrt((static_cast(2) - a) * a); } template GLM_FUNC_QUALIFIER genType circularEaseInOut(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); if(a < static_cast(0.5)) { return static_cast(0.5) * (one() - std::sqrt(one() - static_cast(4) * (a * a))); } else { return static_cast(0.5) * (std::sqrt(-((static_cast(2) * a) - static_cast(3)) * ((static_cast(2) * a) - one())) + one()); } } template GLM_FUNC_QUALIFIER genType exponentialEaseIn(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); if(a <= zero()) return a; else { genType const Complementary = a - one(); genType const Two = static_cast(2); return glm::pow(Two, Complementary * static_cast(10)); } } template GLM_FUNC_QUALIFIER genType exponentialEaseOut(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); if(a >= one()) return a; else { return one() - glm::pow(static_cast(2), -static_cast(10) * a); } } template GLM_FUNC_QUALIFIER genType exponentialEaseInOut(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); if(a < static_cast(0.5)) return static_cast(0.5) * glm::pow(static_cast(2), (static_cast(20) * a) - static_cast(10)); else return -static_cast(0.5) * glm::pow(static_cast(2), (-static_cast(20) * a) + static_cast(10)) + one(); } template GLM_FUNC_QUALIFIER genType elasticEaseIn(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); return std::sin(static_cast(13) * half_pi() * a) * glm::pow(static_cast(2), static_cast(10) * (a - one())); } template GLM_FUNC_QUALIFIER genType elasticEaseOut(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); return std::sin(-static_cast(13) * half_pi() * (a + one())) * glm::pow(static_cast(2), -static_cast(10) * a) + one(); } template GLM_FUNC_QUALIFIER genType elasticEaseInOut(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); if(a < static_cast(0.5)) return static_cast(0.5) * std::sin(static_cast(13) * half_pi() * (static_cast(2) * a)) * glm::pow(static_cast(2), static_cast(10) * ((static_cast(2) * a) - one())); else return static_cast(0.5) * (std::sin(-static_cast(13) * half_pi() * ((static_cast(2) * a - one()) + one())) * glm::pow(static_cast(2), -static_cast(10) * (static_cast(2) * a - one())) + static_cast(2)); } template GLM_FUNC_QUALIFIER genType backEaseIn(genType const& a, genType const& o) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); genType z = ((o + one()) * a) - o; return (a * a * z); } template GLM_FUNC_QUALIFIER genType backEaseOut(genType const& a, genType const& o) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); genType n = a - one(); genType z = ((o + one()) * n) + o; return (n * n * z) + one(); } template GLM_FUNC_QUALIFIER genType backEaseInOut(genType const& a, genType const& o) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); genType s = o * static_cast(1.525); genType x = static_cast(0.5); genType n = a / static_cast(0.5); if (n < static_cast(1)) { genType z = ((s + static_cast(1)) * n) - s; genType m = n * n * z; return x * m; } else { n -= static_cast(2); genType z = ((s + static_cast(1)) * n) + s; genType m = (n*n*z) + static_cast(2); return x * m; } } template GLM_FUNC_QUALIFIER genType backEaseIn(genType const& a) { return backEaseIn(a, static_cast(1.70158)); } template GLM_FUNC_QUALIFIER genType backEaseOut(genType const& a) { return backEaseOut(a, static_cast(1.70158)); } template GLM_FUNC_QUALIFIER genType backEaseInOut(genType const& a) { return backEaseInOut(a, static_cast(1.70158)); } template GLM_FUNC_QUALIFIER genType bounceEaseOut(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); if(a < static_cast(4.0 / 11.0)) { return (static_cast(121) * a * a) / static_cast(16); } else if(a < static_cast(8.0 / 11.0)) { return (static_cast(363.0 / 40.0) * a * a) - (static_cast(99.0 / 10.0) * a) + static_cast(17.0 / 5.0); } else if(a < static_cast(9.0 / 10.0)) { return (static_cast(4356.0 / 361.0) * a * a) - (static_cast(35442.0 / 1805.0) * a) + static_cast(16061.0 / 1805.0); } else { return (static_cast(54.0 / 5.0) * a * a) - (static_cast(513.0 / 25.0) * a) + static_cast(268.0 / 25.0); } } template GLM_FUNC_QUALIFIER genType bounceEaseIn(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); return one() - bounceEaseOut(one() - a); } template GLM_FUNC_QUALIFIER genType bounceEaseInOut(genType const& a) { // Only defined in [0, 1] assert(a >= zero()); assert(a <= one()); if(a < static_cast(0.5)) { return static_cast(0.5) * (one() - bounceEaseOut(a * static_cast(2))); } else { return static_cast(0.5) * bounceEaseOut(a * static_cast(2) - one()) + static_cast(0.5); } } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/euler_angles.hpp000066400000000000000000000254041360521144700243020ustar00rootroot00000000000000/// @ref gtx_euler_angles /// @file glm/gtx/euler_angles.hpp /// /// @see core (dependence) /// /// @defgroup gtx_euler_angles GLM_GTX_euler_angles /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Build matrices from Euler angles. /// /// Extraction of Euler angles from rotation matrix. /// Based on the original paper 2014 Mike Day - Extracting Euler Angles from a Rotation Matrix. #pragma once // Dependency: #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_euler_angles is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_euler_angles extension included") # endif #endif namespace glm { /// @addtogroup gtx_euler_angles /// @{ /// Creates a 3D 4 * 4 homogeneous rotation matrix from an euler angle X. /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleX( T const& angleX); /// Creates a 3D 4 * 4 homogeneous rotation matrix from an euler angle Y. /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleY( T const& angleY); /// Creates a 3D 4 * 4 homogeneous rotation matrix from an euler angle Z. /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZ( T const& angleZ); /// Creates a 3D 4 * 4 homogeneous derived matrix from the rotation matrix about X-axis. /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> derivedEulerAngleX( T const & angleX, T const & angularVelocityX); /// Creates a 3D 4 * 4 homogeneous derived matrix from the rotation matrix about Y-axis. /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> derivedEulerAngleY( T const & angleY, T const & angularVelocityY); /// Creates a 3D 4 * 4 homogeneous derived matrix from the rotation matrix about Z-axis. /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> derivedEulerAngleZ( T const & angleZ, T const & angularVelocityZ); /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Y). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXY( T const& angleX, T const& angleY); /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYX( T const& angleY, T const& angleX); /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Z). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXZ( T const& angleX, T const& angleZ); /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * X). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZX( T const& angle, T const& angleX); /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * Z). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYZ( T const& angleY, T const& angleZ); /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * Y). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZY( T const& angleZ, T const& angleY); /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Y * Z). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXYZ( T const& t1, T const& t2, T const& t3); /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Z). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYXZ( T const& yaw, T const& pitch, T const& roll); /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Z * X). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXZX( T const & t1, T const & t2, T const & t3); /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Y * X). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXYX( T const & t1, T const & t2, T const & t3); /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Y). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYXY( T const & t1, T const & t2, T const & t3); /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * Z * Y). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYZY( T const & t1, T const & t2, T const & t3); /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * Y * Z). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZYZ( T const & t1, T const & t2, T const & t3); /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * X * Z). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZXZ( T const & t1, T const & t2, T const & t3); /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Z * Y). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXZY( T const & t1, T const & t2, T const & t3); /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * Z * X). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYZX( T const & t1, T const & t2, T const & t3); /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * Y * X). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZYX( T const & t1, T const & t2, T const & t3); /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * X * Y). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZXY( T const & t1, T const & t2, T const & t3); /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Z). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, defaultp> yawPitchRoll( T const& yaw, T const& pitch, T const& roll); /// Creates a 2D 2 * 2 rotation matrix from an euler angle. /// @see gtx_euler_angles template GLM_FUNC_DECL mat<2, 2, T, defaultp> orientate2(T const& angle); /// Creates a 2D 4 * 4 homogeneous rotation matrix from an euler angle. /// @see gtx_euler_angles template GLM_FUNC_DECL mat<3, 3, T, defaultp> orientate3(T const& angle); /// Creates a 3D 3 * 3 rotation matrix from euler angles (Y * X * Z). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<3, 3, T, Q> orientate3(vec<3, T, Q> const& angles); /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Z). /// @see gtx_euler_angles template GLM_FUNC_DECL mat<4, 4, T, Q> orientate4(vec<3, T, Q> const& angles); /// Extracts the (X * Y * Z) Euler angles from the rotation matrix M /// @see gtx_euler_angles template GLM_FUNC_DECL void extractEulerAngleXYZ(mat<4, 4, T, defaultp> const& M, T & t1, T & t2, T & t3); /// Extracts the (Y * X * Z) Euler angles from the rotation matrix M /// @see gtx_euler_angles template GLM_FUNC_DECL void extractEulerAngleYXZ(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3); /// Extracts the (X * Z * X) Euler angles from the rotation matrix M /// @see gtx_euler_angles template GLM_FUNC_DECL void extractEulerAngleXZX(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3); /// Extracts the (X * Y * X) Euler angles from the rotation matrix M /// @see gtx_euler_angles template GLM_FUNC_DECL void extractEulerAngleXYX(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3); /// Extracts the (Y * X * Y) Euler angles from the rotation matrix M /// @see gtx_euler_angles template GLM_FUNC_DECL void extractEulerAngleYXY(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3); /// Extracts the (Y * Z * Y) Euler angles from the rotation matrix M /// @see gtx_euler_angles template GLM_FUNC_DECL void extractEulerAngleYZY(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3); /// Extracts the (Z * Y * Z) Euler angles from the rotation matrix M /// @see gtx_euler_angles template GLM_FUNC_DECL void extractEulerAngleZYZ(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3); /// Extracts the (Z * X * Z) Euler angles from the rotation matrix M /// @see gtx_euler_angles template GLM_FUNC_DECL void extractEulerAngleZXZ(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3); /// Extracts the (X * Z * Y) Euler angles from the rotation matrix M /// @see gtx_euler_angles template GLM_FUNC_DECL void extractEulerAngleXZY(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3); /// Extracts the (Y * Z * X) Euler angles from the rotation matrix M /// @see gtx_euler_angles template GLM_FUNC_DECL void extractEulerAngleYZX(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3); /// Extracts the (Z * Y * X) Euler angles from the rotation matrix M /// @see gtx_euler_angles template GLM_FUNC_DECL void extractEulerAngleZYX(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3); /// Extracts the (Z * X * Y) Euler angles from the rotation matrix M /// @see gtx_euler_angles template GLM_FUNC_DECL void extractEulerAngleZXY(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3); /// @} }//namespace glm #include "euler_angles.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/euler_angles.inl000066400000000000000000000561441360521144700243020ustar00rootroot00000000000000/// @ref gtx_euler_angles #include "compatibility.hpp" // glm::atan2 namespace glm { template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleX ( T const& angleX ) { T cosX = glm::cos(angleX); T sinX = glm::sin(angleX); return mat<4, 4, T, defaultp>( T(1), T(0), T(0), T(0), T(0), cosX, sinX, T(0), T(0),-sinX, cosX, T(0), T(0), T(0), T(0), T(1)); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleY ( T const& angleY ) { T cosY = glm::cos(angleY); T sinY = glm::sin(angleY); return mat<4, 4, T, defaultp>( cosY, T(0), -sinY, T(0), T(0), T(1), T(0), T(0), sinY, T(0), cosY, T(0), T(0), T(0), T(0), T(1)); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZ ( T const& angleZ ) { T cosZ = glm::cos(angleZ); T sinZ = glm::sin(angleZ); return mat<4, 4, T, defaultp>( cosZ, sinZ, T(0), T(0), -sinZ, cosZ, T(0), T(0), T(0), T(0), T(1), T(0), T(0), T(0), T(0), T(1)); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> derivedEulerAngleX ( T const & angleX, T const & angularVelocityX ) { T cosX = glm::cos(angleX) * angularVelocityX; T sinX = glm::sin(angleX) * angularVelocityX; return mat<4, 4, T, defaultp>( T(0), T(0), T(0), T(0), T(0),-sinX, cosX, T(0), T(0),-cosX,-sinX, T(0), T(0), T(0), T(0), T(0)); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> derivedEulerAngleY ( T const & angleY, T const & angularVelocityY ) { T cosY = glm::cos(angleY) * angularVelocityY; T sinY = glm::sin(angleY) * angularVelocityY; return mat<4, 4, T, defaultp>( -sinY, T(0), -cosY, T(0), T(0), T(0), T(0), T(0), cosY, T(0), -sinY, T(0), T(0), T(0), T(0), T(0)); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> derivedEulerAngleZ ( T const & angleZ, T const & angularVelocityZ ) { T cosZ = glm::cos(angleZ) * angularVelocityZ; T sinZ = glm::sin(angleZ) * angularVelocityZ; return mat<4, 4, T, defaultp>( -sinZ, cosZ, T(0), T(0), -cosZ, -sinZ, T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0)); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXY ( T const& angleX, T const& angleY ) { T cosX = glm::cos(angleX); T sinX = glm::sin(angleX); T cosY = glm::cos(angleY); T sinY = glm::sin(angleY); return mat<4, 4, T, defaultp>( cosY, -sinX * -sinY, cosX * -sinY, T(0), T(0), cosX, sinX, T(0), sinY, -sinX * cosY, cosX * cosY, T(0), T(0), T(0), T(0), T(1)); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYX ( T const& angleY, T const& angleX ) { T cosX = glm::cos(angleX); T sinX = glm::sin(angleX); T cosY = glm::cos(angleY); T sinY = glm::sin(angleY); return mat<4, 4, T, defaultp>( cosY, 0, -sinY, T(0), sinY * sinX, cosX, cosY * sinX, T(0), sinY * cosX, -sinX, cosY * cosX, T(0), T(0), T(0), T(0), T(1)); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXZ ( T const& angleX, T const& angleZ ) { return eulerAngleX(angleX) * eulerAngleZ(angleZ); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZX ( T const& angleZ, T const& angleX ) { return eulerAngleZ(angleZ) * eulerAngleX(angleX); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYZ ( T const& angleY, T const& angleZ ) { return eulerAngleY(angleY) * eulerAngleZ(angleZ); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZY ( T const& angleZ, T const& angleY ) { return eulerAngleZ(angleZ) * eulerAngleY(angleY); } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXYZ ( T const& t1, T const& t2, T const& t3 ) { T c1 = glm::cos(-t1); T c2 = glm::cos(-t2); T c3 = glm::cos(-t3); T s1 = glm::sin(-t1); T s2 = glm::sin(-t2); T s3 = glm::sin(-t3); mat<4, 4, T, defaultp> Result; Result[0][0] = c2 * c3; Result[0][1] =-c1 * s3 + s1 * s2 * c3; Result[0][2] = s1 * s3 + c1 * s2 * c3; Result[0][3] = static_cast(0); Result[1][0] = c2 * s3; Result[1][1] = c1 * c3 + s1 * s2 * s3; Result[1][2] =-s1 * c3 + c1 * s2 * s3; Result[1][3] = static_cast(0); Result[2][0] =-s2; Result[2][1] = s1 * c2; Result[2][2] = c1 * c2; Result[2][3] = static_cast(0); Result[3][0] = static_cast(0); Result[3][1] = static_cast(0); Result[3][2] = static_cast(0); Result[3][3] = static_cast(1); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYXZ ( T const& yaw, T const& pitch, T const& roll ) { T tmp_ch = glm::cos(yaw); T tmp_sh = glm::sin(yaw); T tmp_cp = glm::cos(pitch); T tmp_sp = glm::sin(pitch); T tmp_cb = glm::cos(roll); T tmp_sb = glm::sin(roll); mat<4, 4, T, defaultp> Result; Result[0][0] = tmp_ch * tmp_cb + tmp_sh * tmp_sp * tmp_sb; Result[0][1] = tmp_sb * tmp_cp; Result[0][2] = -tmp_sh * tmp_cb + tmp_ch * tmp_sp * tmp_sb; Result[0][3] = static_cast(0); Result[1][0] = -tmp_ch * tmp_sb + tmp_sh * tmp_sp * tmp_cb; Result[1][1] = tmp_cb * tmp_cp; Result[1][2] = tmp_sb * tmp_sh + tmp_ch * tmp_sp * tmp_cb; Result[1][3] = static_cast(0); Result[2][0] = tmp_sh * tmp_cp; Result[2][1] = -tmp_sp; Result[2][2] = tmp_ch * tmp_cp; Result[2][3] = static_cast(0); Result[3][0] = static_cast(0); Result[3][1] = static_cast(0); Result[3][2] = static_cast(0); Result[3][3] = static_cast(1); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXZX ( T const & t1, T const & t2, T const & t3 ) { T c1 = glm::cos(t1); T s1 = glm::sin(t1); T c2 = glm::cos(t2); T s2 = glm::sin(t2); T c3 = glm::cos(t3); T s3 = glm::sin(t3); mat<4, 4, T, defaultp> Result; Result[0][0] = c2; Result[0][1] = c1 * s2; Result[0][2] = s1 * s2; Result[0][3] = static_cast(0); Result[1][0] =-c3 * s2; Result[1][1] = c1 * c2 * c3 - s1 * s3; Result[1][2] = c1 * s3 + c2 * c3 * s1; Result[1][3] = static_cast(0); Result[2][0] = s2 * s3; Result[2][1] =-c3 * s1 - c1 * c2 * s3; Result[2][2] = c1 * c3 - c2 * s1 * s3; Result[2][3] = static_cast(0); Result[3][0] = static_cast(0); Result[3][1] = static_cast(0); Result[3][2] = static_cast(0); Result[3][3] = static_cast(1); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXYX ( T const & t1, T const & t2, T const & t3 ) { T c1 = glm::cos(t1); T s1 = glm::sin(t1); T c2 = glm::cos(t2); T s2 = glm::sin(t2); T c3 = glm::cos(t3); T s3 = glm::sin(t3); mat<4, 4, T, defaultp> Result; Result[0][0] = c2; Result[0][1] = s1 * s2; Result[0][2] =-c1 * s2; Result[0][3] = static_cast(0); Result[1][0] = s2 * s3; Result[1][1] = c1 * c3 - c2 * s1 * s3; Result[1][2] = c3 * s1 + c1 * c2 * s3; Result[1][3] = static_cast(0); Result[2][0] = c3 * s2; Result[2][1] =-c1 * s3 - c2 * c3 * s1; Result[2][2] = c1 * c2 * c3 - s1 * s3; Result[2][3] = static_cast(0); Result[3][0] = static_cast(0); Result[3][1] = static_cast(0); Result[3][2] = static_cast(0); Result[3][3] = static_cast(1); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYXY ( T const & t1, T const & t2, T const & t3 ) { T c1 = glm::cos(t1); T s1 = glm::sin(t1); T c2 = glm::cos(t2); T s2 = glm::sin(t2); T c3 = glm::cos(t3); T s3 = glm::sin(t3); mat<4, 4, T, defaultp> Result; Result[0][0] = c1 * c3 - c2 * s1 * s3; Result[0][1] = s2* s3; Result[0][2] =-c3 * s1 - c1 * c2 * s3; Result[0][3] = static_cast(0); Result[1][0] = s1 * s2; Result[1][1] = c2; Result[1][2] = c1 * s2; Result[1][3] = static_cast(0); Result[2][0] = c1 * s3 + c2 * c3 * s1; Result[2][1] =-c3 * s2; Result[2][2] = c1 * c2 * c3 - s1 * s3; Result[2][3] = static_cast(0); Result[3][0] = static_cast(0); Result[3][1] = static_cast(0); Result[3][2] = static_cast(0); Result[3][3] = static_cast(1); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYZY ( T const & t1, T const & t2, T const & t3 ) { T c1 = glm::cos(t1); T s1 = glm::sin(t1); T c2 = glm::cos(t2); T s2 = glm::sin(t2); T c3 = glm::cos(t3); T s3 = glm::sin(t3); mat<4, 4, T, defaultp> Result; Result[0][0] = c1 * c2 * c3 - s1 * s3; Result[0][1] = c3 * s2; Result[0][2] =-c1 * s3 - c2 * c3 * s1; Result[0][3] = static_cast(0); Result[1][0] =-c1 * s2; Result[1][1] = c2; Result[1][2] = s1 * s2; Result[1][3] = static_cast(0); Result[2][0] = c3 * s1 + c1 * c2 * s3; Result[2][1] = s2 * s3; Result[2][2] = c1 * c3 - c2 * s1 * s3; Result[2][3] = static_cast(0); Result[3][0] = static_cast(0); Result[3][1] = static_cast(0); Result[3][2] = static_cast(0); Result[3][3] = static_cast(1); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZYZ ( T const & t1, T const & t2, T const & t3 ) { T c1 = glm::cos(t1); T s1 = glm::sin(t1); T c2 = glm::cos(t2); T s2 = glm::sin(t2); T c3 = glm::cos(t3); T s3 = glm::sin(t3); mat<4, 4, T, defaultp> Result; Result[0][0] = c1 * c2 * c3 - s1 * s3; Result[0][1] = c1 * s3 + c2 * c3 * s1; Result[0][2] =-c3 * s2; Result[0][3] = static_cast(0); Result[1][0] =-c3 * s1 - c1 * c2 * s3; Result[1][1] = c1 * c3 - c2 * s1 * s3; Result[1][2] = s2 * s3; Result[1][3] = static_cast(0); Result[2][0] = c1 * s2; Result[2][1] = s1 * s2; Result[2][2] = c2; Result[2][3] = static_cast(0); Result[3][0] = static_cast(0); Result[3][1] = static_cast(0); Result[3][2] = static_cast(0); Result[3][3] = static_cast(1); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZXZ ( T const & t1, T const & t2, T const & t3 ) { T c1 = glm::cos(t1); T s1 = glm::sin(t1); T c2 = glm::cos(t2); T s2 = glm::sin(t2); T c3 = glm::cos(t3); T s3 = glm::sin(t3); mat<4, 4, T, defaultp> Result; Result[0][0] = c1 * c3 - c2 * s1 * s3; Result[0][1] = c3 * s1 + c1 * c2 * s3; Result[0][2] = s2 *s3; Result[0][3] = static_cast(0); Result[1][0] =-c1 * s3 - c2 * c3 * s1; Result[1][1] = c1 * c2 * c3 - s1 * s3; Result[1][2] = c3 * s2; Result[1][3] = static_cast(0); Result[2][0] = s1 * s2; Result[2][1] =-c1 * s2; Result[2][2] = c2; Result[2][3] = static_cast(0); Result[3][0] = static_cast(0); Result[3][1] = static_cast(0); Result[3][2] = static_cast(0); Result[3][3] = static_cast(1); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXZY ( T const & t1, T const & t2, T const & t3 ) { T c1 = glm::cos(t1); T s1 = glm::sin(t1); T c2 = glm::cos(t2); T s2 = glm::sin(t2); T c3 = glm::cos(t3); T s3 = glm::sin(t3); mat<4, 4, T, defaultp> Result; Result[0][0] = c2 * c3; Result[0][1] = s1 * s3 + c1 * c3 * s2; Result[0][2] = c3 * s1 * s2 - c1 * s3; Result[0][3] = static_cast(0); Result[1][0] =-s2; Result[1][1] = c1 * c2; Result[1][2] = c2 * s1; Result[1][3] = static_cast(0); Result[2][0] = c2 * s3; Result[2][1] = c1 * s2 * s3 - c3 * s1; Result[2][2] = c1 * c3 + s1 * s2 *s3; Result[2][3] = static_cast(0); Result[3][0] = static_cast(0); Result[3][1] = static_cast(0); Result[3][2] = static_cast(0); Result[3][3] = static_cast(1); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYZX ( T const & t1, T const & t2, T const & t3 ) { T c1 = glm::cos(t1); T s1 = glm::sin(t1); T c2 = glm::cos(t2); T s2 = glm::sin(t2); T c3 = glm::cos(t3); T s3 = glm::sin(t3); mat<4, 4, T, defaultp> Result; Result[0][0] = c1 * c2; Result[0][1] = s2; Result[0][2] =-c2 * s1; Result[0][3] = static_cast(0); Result[1][0] = s1 * s3 - c1 * c3 * s2; Result[1][1] = c2 * c3; Result[1][2] = c1 * s3 + c3 * s1 * s2; Result[1][3] = static_cast(0); Result[2][0] = c3 * s1 + c1 * s2 * s3; Result[2][1] =-c2 * s3; Result[2][2] = c1 * c3 - s1 * s2 * s3; Result[2][3] = static_cast(0); Result[3][0] = static_cast(0); Result[3][1] = static_cast(0); Result[3][2] = static_cast(0); Result[3][3] = static_cast(1); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZYX ( T const & t1, T const & t2, T const & t3 ) { T c1 = glm::cos(t1); T s1 = glm::sin(t1); T c2 = glm::cos(t2); T s2 = glm::sin(t2); T c3 = glm::cos(t3); T s3 = glm::sin(t3); mat<4, 4, T, defaultp> Result; Result[0][0] = c1 * c2; Result[0][1] = c2 * s1; Result[0][2] =-s2; Result[0][3] = static_cast(0); Result[1][0] = c1 * s2 * s3 - c3 * s1; Result[1][1] = c1 * c3 + s1 * s2 * s3; Result[1][2] = c2 * s3; Result[1][3] = static_cast(0); Result[2][0] = s1 * s3 + c1 * c3 * s2; Result[2][1] = c3 * s1 * s2 - c1 * s3; Result[2][2] = c2 * c3; Result[2][3] = static_cast(0); Result[3][0] = static_cast(0); Result[3][1] = static_cast(0); Result[3][2] = static_cast(0); Result[3][3] = static_cast(1); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZXY ( T const & t1, T const & t2, T const & t3 ) { T c1 = glm::cos(t1); T s1 = glm::sin(t1); T c2 = glm::cos(t2); T s2 = glm::sin(t2); T c3 = glm::cos(t3); T s3 = glm::sin(t3); mat<4, 4, T, defaultp> Result; Result[0][0] = c1 * c3 - s1 * s2 * s3; Result[0][1] = c3 * s1 + c1 * s2 * s3; Result[0][2] =-c2 * s3; Result[0][3] = static_cast(0); Result[1][0] =-c2 * s1; Result[1][1] = c1 * c2; Result[1][2] = s2; Result[1][3] = static_cast(0); Result[2][0] = c1 * s3 + c3 * s1 * s2; Result[2][1] = s1 * s3 - c1 * c3 * s2; Result[2][2] = c2 * c3; Result[2][3] = static_cast(0); Result[3][0] = static_cast(0); Result[3][1] = static_cast(0); Result[3][2] = static_cast(0); Result[3][3] = static_cast(1); return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> yawPitchRoll ( T const& yaw, T const& pitch, T const& roll ) { T tmp_ch = glm::cos(yaw); T tmp_sh = glm::sin(yaw); T tmp_cp = glm::cos(pitch); T tmp_sp = glm::sin(pitch); T tmp_cb = glm::cos(roll); T tmp_sb = glm::sin(roll); mat<4, 4, T, defaultp> Result; Result[0][0] = tmp_ch * tmp_cb + tmp_sh * tmp_sp * tmp_sb; Result[0][1] = tmp_sb * tmp_cp; Result[0][2] = -tmp_sh * tmp_cb + tmp_ch * tmp_sp * tmp_sb; Result[0][3] = static_cast(0); Result[1][0] = -tmp_ch * tmp_sb + tmp_sh * tmp_sp * tmp_cb; Result[1][1] = tmp_cb * tmp_cp; Result[1][2] = tmp_sb * tmp_sh + tmp_ch * tmp_sp * tmp_cb; Result[1][3] = static_cast(0); Result[2][0] = tmp_sh * tmp_cp; Result[2][1] = -tmp_sp; Result[2][2] = tmp_ch * tmp_cp; Result[2][3] = static_cast(0); Result[3][0] = static_cast(0); Result[3][1] = static_cast(0); Result[3][2] = static_cast(0); Result[3][3] = static_cast(1); return Result; } template GLM_FUNC_QUALIFIER mat<2, 2, T, defaultp> orientate2 ( T const& angle ) { T c = glm::cos(angle); T s = glm::sin(angle); mat<2, 2, T, defaultp> Result; Result[0][0] = c; Result[0][1] = s; Result[1][0] = -s; Result[1][1] = c; return Result; } template GLM_FUNC_QUALIFIER mat<3, 3, T, defaultp> orientate3 ( T const& angle ) { T c = glm::cos(angle); T s = glm::sin(angle); mat<3, 3, T, defaultp> Result; Result[0][0] = c; Result[0][1] = s; Result[0][2] = 0.0f; Result[1][0] = -s; Result[1][1] = c; Result[1][2] = 0.0f; Result[2][0] = 0.0f; Result[2][1] = 0.0f; Result[2][2] = 1.0f; return Result; } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> orientate3 ( vec<3, T, Q> const& angles ) { return mat<3, 3, T, Q>(yawPitchRoll(angles.z, angles.x, angles.y)); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> orientate4 ( vec<3, T, Q> const& angles ) { return yawPitchRoll(angles.z, angles.x, angles.y); } template GLM_FUNC_DECL void extractEulerAngleXYZ(mat<4, 4, T, defaultp> const& M, T & t1, T & t2, T & t3) { T T1 = glm::atan2(M[2][1], M[2][2]); T C2 = glm::sqrt(M[0][0]*M[0][0] + M[1][0]*M[1][0]); T T2 = glm::atan2(-M[2][0], C2); T S1 = glm::sin(T1); T C1 = glm::cos(T1); T T3 = glm::atan2(S1*M[0][2] - C1*M[0][1], C1*M[1][1] - S1*M[1][2 ]); t1 = -T1; t2 = -T2; t3 = -T3; } template GLM_FUNC_QUALIFIER void extractEulerAngleYXZ(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3) { T T1 = glm::atan2(M[2][0], M[2][2]); T C2 = glm::sqrt(M[0][1]*M[0][1] + M[1][1]*M[1][1]); T T2 = glm::atan2(-M[2][1], C2); T S1 = glm::sin(T1); T C1 = glm::cos(T1); T T3 = glm::atan2(S1*M[1][2] - C1*M[1][0], C1*M[0][0] - S1*M[0][2]); t1 = T1; t2 = T2; t3 = T3; } template GLM_FUNC_QUALIFIER void extractEulerAngleXZX(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3) { T T1 = glm::atan2(M[0][2], M[0][1]); T S2 = glm::sqrt(M[1][0]*M[1][0] + M[2][0]*M[2][0]); T T2 = glm::atan2(S2, M[0][0]); T S1 = glm::sin(T1); T C1 = glm::cos(T1); T T3 = glm::atan2(C1*M[1][2] - S1*M[1][1], C1*M[2][2] - S1*M[2][1]); t1 = T1; t2 = T2; t3 = T3; } template GLM_FUNC_QUALIFIER void extractEulerAngleXYX(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3) { T T1 = glm::atan2(M[0][1], -M[0][2]); T S2 = glm::sqrt(M[1][0]*M[1][0] + M[2][0]*M[2][0]); T T2 = glm::atan2(S2, M[0][0]); T S1 = glm::sin(T1); T C1 = glm::cos(T1); T T3 = glm::atan2(-C1*M[2][1] - S1*M[2][2], C1*M[1][1] + S1*M[1][2]); t1 = T1; t2 = T2; t3 = T3; } template GLM_FUNC_QUALIFIER void extractEulerAngleYXY(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3) { T T1 = glm::atan2(M[1][0], M[1][2]); T S2 = glm::sqrt(M[0][1]*M[0][1] + M[2][1]*M[2][1]); T T2 = glm::atan2(S2, M[1][1]); T S1 = glm::sin(T1); T C1 = glm::cos(T1); T T3 = glm::atan2(C1*M[2][0] - S1*M[2][2], C1*M[0][0] - S1*M[0][2]); t1 = T1; t2 = T2; t3 = T3; } template GLM_FUNC_QUALIFIER void extractEulerAngleYZY(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3) { T T1 = glm::atan2(M[1][2], -M[1][0]); T S2 = glm::sqrt(M[0][1]*M[0][1] + M[2][1]*M[2][1]); T T2 = glm::atan2(S2, M[1][1]); T S1 = glm::sin(T1); T C1 = glm::cos(T1); T T3 = glm::atan2(-S1*M[0][0] - C1*M[0][2], S1*M[2][0] + C1*M[2][2]); t1 = T1; t2 = T2; t3 = T3; } template GLM_FUNC_QUALIFIER void extractEulerAngleZYZ(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3) { T T1 = glm::atan2(M[2][1], M[2][0]); T S2 = glm::sqrt(M[0][2]*M[0][2] + M[1][2]*M[1][2]); T T2 = glm::atan2(S2, M[2][2]); T S1 = glm::sin(T1); T C1 = glm::cos(T1); T T3 = glm::atan2(C1*M[0][1] - S1*M[0][0], C1*M[1][1] - S1*M[1][0]); t1 = T1; t2 = T2; t3 = T3; } template GLM_FUNC_QUALIFIER void extractEulerAngleZXZ(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3) { T T1 = glm::atan2(M[2][0], -M[2][1]); T S2 = glm::sqrt(M[0][2]*M[0][2] + M[1][2]*M[1][2]); T T2 = glm::atan2(S2, M[2][2]); T S1 = glm::sin(T1); T C1 = glm::cos(T1); T T3 = glm::atan2(-C1*M[1][0] - S1*M[1][1], C1*M[0][0] + S1*M[0][1]); t1 = T1; t2 = T2; t3 = T3; } template GLM_FUNC_QUALIFIER void extractEulerAngleXZY(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3) { T T1 = glm::atan2(M[1][2], M[1][1]); T C2 = glm::sqrt(M[0][0]*M[0][0] + M[2][0]*M[2][0]); T T2 = glm::atan2(-M[1][0], C2); T S1 = glm::sin(T1); T C1 = glm::cos(T1); T T3 = glm::atan2(S1*M[0][1] - C1*M[0][2], C1*M[2][2] - S1*M[2][1]); t1 = T1; t2 = T2; t3 = T3; } template GLM_FUNC_QUALIFIER void extractEulerAngleYZX(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3) { T T1 = glm::atan2(-M[0][2], M[0][0]); T C2 = glm::sqrt(M[1][1]*M[1][1] + M[2][1]*M[2][1]); T T2 = glm::atan2(M[0][1], C2); T S1 = glm::sin(T1); T C1 = glm::cos(T1); T T3 = glm::atan2(S1*M[1][0] + C1*M[1][2], S1*M[2][0] + C1*M[2][2]); t1 = T1; t2 = T2; t3 = T3; } template GLM_FUNC_QUALIFIER void extractEulerAngleZYX(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3) { T T1 = glm::atan2(M[0][1], M[0][0]); T C2 = glm::sqrt(M[1][2]*M[1][2] + M[2][2]*M[2][2]); T T2 = glm::atan2(-M[0][2], C2); T S1 = glm::sin(T1); T C1 = glm::cos(T1); T T3 = glm::atan2(S1*M[2][0] - C1*M[2][1], C1*M[1][1] - S1*M[1][0]); t1 = T1; t2 = T2; t3 = T3; } template GLM_FUNC_QUALIFIER void extractEulerAngleZXY(mat<4, 4, T, defaultp> const & M, T & t1, T & t2, T & t3) { T T1 = glm::atan2(-M[1][0], M[1][1]); T C2 = glm::sqrt(M[0][2]*M[0][2] + M[2][2]*M[2][2]); T T2 = glm::atan2(M[1][2], C2); T S1 = glm::sin(T1); T C1 = glm::cos(T1); T T3 = glm::atan2(C1*M[2][0] + S1*M[2][1], C1*M[0][0] + S1*M[0][1]); t1 = T1; t2 = T2; t3 = T3; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/extend.hpp000066400000000000000000000021271360521144700231210ustar00rootroot00000000000000/// @ref gtx_extend /// @file glm/gtx/extend.hpp /// /// @see core (dependence) /// /// @defgroup gtx_extend GLM_GTX_extend /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Extend a position from a source to a position at a defined length. #pragma once // Dependency: #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_extend is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_extend extension included") # endif #endif namespace glm { /// @addtogroup gtx_extend /// @{ /// Extends of Length the Origin position using the (Source - Origin) direction. /// @see gtx_extend template GLM_FUNC_DECL genType extend( genType const& Origin, genType const& Source, typename genType::value_type const Length); /// @} }//namespace glm #include "extend.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/extend.inl000066400000000000000000000016651360521144700231220ustar00rootroot00000000000000/// @ref gtx_extend namespace glm { template GLM_FUNC_QUALIFIER genType extend ( genType const& Origin, genType const& Source, genType const& Distance ) { return Origin + (Source - Origin) * Distance; } template GLM_FUNC_QUALIFIER vec<2, T, Q> extend ( vec<2, T, Q> const& Origin, vec<2, T, Q> const& Source, T const& Distance ) { return Origin + (Source - Origin) * Distance; } template GLM_FUNC_QUALIFIER vec<3, T, Q> extend ( vec<3, T, Q> const& Origin, vec<3, T, Q> const& Source, T const& Distance ) { return Origin + (Source - Origin) * Distance; } template GLM_FUNC_QUALIFIER vec<4, T, Q> extend ( vec<4, T, Q> const& Origin, vec<4, T, Q> const& Source, T const& Distance ) { return Origin + (Source - Origin) * Distance; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/extended_min_max.hpp000066400000000000000000000132741360521144700251470ustar00rootroot00000000000000/// @ref gtx_extended_min_max /// @file glm/gtx/extended_min_max.hpp /// /// @see core (dependence) /// /// @defgroup gtx_extended_min_max GLM_GTX_extented_min_max /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Min and max functions for 3 to 4 parameters. #pragma once // Dependency: #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_extented_min_max is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_extented_min_max extension included") # endif #endif namespace glm { /// @addtogroup gtx_extended_min_max /// @{ /// Return the minimum component-wise values of 3 inputs /// @see gtx_extented_min_max template GLM_FUNC_DECL T min( T const& x, T const& y, T const& z); /// Return the minimum component-wise values of 3 inputs /// @see gtx_extented_min_max template class C> GLM_FUNC_DECL C min( C const& x, typename C::T const& y, typename C::T const& z); /// Return the minimum component-wise values of 3 inputs /// @see gtx_extented_min_max template class C> GLM_FUNC_DECL C min( C const& x, C const& y, C const& z); /// Return the minimum component-wise values of 4 inputs /// @see gtx_extented_min_max template GLM_FUNC_DECL T min( T const& x, T const& y, T const& z, T const& w); /// Return the minimum component-wise values of 4 inputs /// @see gtx_extented_min_max template class C> GLM_FUNC_DECL C min( C const& x, typename C::T const& y, typename C::T const& z, typename C::T const& w); /// Return the minimum component-wise values of 4 inputs /// @see gtx_extented_min_max template class C> GLM_FUNC_DECL C min( C const& x, C const& y, C const& z, C const& w); /// Return the maximum component-wise values of 3 inputs /// @see gtx_extented_min_max template GLM_FUNC_DECL T max( T const& x, T const& y, T const& z); /// Return the maximum component-wise values of 3 inputs /// @see gtx_extented_min_max template class C> GLM_FUNC_DECL C max( C const& x, typename C::T const& y, typename C::T const& z); /// Return the maximum component-wise values of 3 inputs /// @see gtx_extented_min_max template class C> GLM_FUNC_DECL C max( C const& x, C const& y, C const& z); /// Return the maximum component-wise values of 4 inputs /// @see gtx_extented_min_max template GLM_FUNC_DECL T max( T const& x, T const& y, T const& z, T const& w); /// Return the maximum component-wise values of 4 inputs /// @see gtx_extented_min_max template class C> GLM_FUNC_DECL C max( C const& x, typename C::T const& y, typename C::T const& z, typename C::T const& w); /// Return the maximum component-wise values of 4 inputs /// @see gtx_extented_min_max template class C> GLM_FUNC_DECL C max( C const& x, C const& y, C const& z, C const& w); /// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. /// /// @tparam genType Floating-point or integer; scalar or vector types. /// /// @see gtx_extented_min_max template GLM_FUNC_DECL genType fmin(genType x, genType y); /// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned. /// /// @tparam genType Floating-point; scalar or vector types. /// /// @see gtx_extented_min_max /// @see std::fmax documentation template GLM_FUNC_DECL genType fmax(genType x, genType y); /// Returns min(max(x, minVal), maxVal) for each component in x. If one of the two arguments is NaN, the value of the other argument is returned. /// /// @tparam genType Floating-point scalar or vector types. /// /// @see gtx_extented_min_max template GLM_FUNC_DECL genType fclamp(genType x, genType minVal, genType maxVal); /// Returns min(max(x, minVal), maxVal) for each component in x. If one of the two arguments is NaN, the value of the other argument is returned. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see gtx_extented_min_max template GLM_FUNC_DECL vec fclamp(vec const& x, T minVal, T maxVal); /// Returns min(max(x, minVal), maxVal) for each component in x. If one of the two arguments is NaN, the value of the other argument is returned. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see gtx_extented_min_max template GLM_FUNC_DECL vec fclamp(vec const& x, vec const& minVal, vec const& maxVal); /// @} }//namespace glm #include "extended_min_max.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/extended_min_max.inl000066400000000000000000000112161360521144700251340ustar00rootroot00000000000000/// @ref gtx_extended_min_max namespace glm { template GLM_FUNC_QUALIFIER T min( T const& x, T const& y, T const& z) { return glm::min(glm::min(x, y), z); } template class C> GLM_FUNC_QUALIFIER C min ( C const& x, typename C::T const& y, typename C::T const& z ) { return glm::min(glm::min(x, y), z); } template class C> GLM_FUNC_QUALIFIER C min ( C const& x, C const& y, C const& z ) { return glm::min(glm::min(x, y), z); } template GLM_FUNC_QUALIFIER T min ( T const& x, T const& y, T const& z, T const& w ) { return glm::min(glm::min(x, y), glm::min(z, w)); } template class C> GLM_FUNC_QUALIFIER C min ( C const& x, typename C::T const& y, typename C::T const& z, typename C::T const& w ) { return glm::min(glm::min(x, y), glm::min(z, w)); } template class C> GLM_FUNC_QUALIFIER C min ( C const& x, C const& y, C const& z, C const& w ) { return glm::min(glm::min(x, y), glm::min(z, w)); } template GLM_FUNC_QUALIFIER T max( T const& x, T const& y, T const& z) { return glm::max(glm::max(x, y), z); } template class C> GLM_FUNC_QUALIFIER C max ( C const& x, typename C::T const& y, typename C::T const& z ) { return glm::max(glm::max(x, y), z); } template class C> GLM_FUNC_QUALIFIER C max ( C const& x, C const& y, C const& z ) { return glm::max(glm::max(x, y), z); } template GLM_FUNC_QUALIFIER T max ( T const& x, T const& y, T const& z, T const& w ) { return glm::max(glm::max(x, y), glm::max(z, w)); } template class C> GLM_FUNC_QUALIFIER C max ( C const& x, typename C::T const& y, typename C::T const& z, typename C::T const& w ) { return glm::max(glm::max(x, y), glm::max(z, w)); } template class C> GLM_FUNC_QUALIFIER C max ( C const& x, C const& y, C const& z, C const& w ) { return glm::max(glm::max(x, y), glm::max(z, w)); } // fmin # if GLM_HAS_CXX11_STL using std::fmin; # else template GLM_FUNC_QUALIFIER genType fmin(genType x, genType y) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmin' only accept floating-point input"); if (isnan(x)) return y; if (isnan(y)) return x; return min(x, y); } # endif template GLM_FUNC_QUALIFIER vec fmin(vec const& a, T b) { return detail::functor2::call(fmin, a, vec(b)); } template GLM_FUNC_QUALIFIER vec fmin(vec const& a, vec const& b) { return detail::functor2::call(fmin, a, b); } // fmax # if GLM_HAS_CXX11_STL using std::fmax; # else template GLM_FUNC_QUALIFIER genType fmax(genType x, genType y) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fmax' only accept floating-point input"); if (isnan(x)) return y; if (isnan(y)) return x; return max(x, y); } # endif template GLM_FUNC_QUALIFIER vec fmax(vec const& a, T b) { return detail::functor2::call(fmax, a, vec(b)); } template GLM_FUNC_QUALIFIER vec fmax(vec const& a, vec const& b) { return detail::functor2::call(fmax, a, b); } // fclamp template GLM_FUNC_QUALIFIER genType fclamp(genType x, genType minVal, genType maxVal) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fclamp' only accept floating-point or integer inputs"); return fmin(fmax(x, minVal), maxVal); } template GLM_FUNC_QUALIFIER vec fclamp(vec const& x, T minVal, T maxVal) { return fmin(fmax(x, vec(minVal)), vec(maxVal)); } template GLM_FUNC_QUALIFIER vec fclamp(vec const& x, vec const& minVal, vec const& maxVal) { return fmin(fmax(x, minVal), maxVal); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/exterior_product.hpp000066400000000000000000000025451360521144700252370ustar00rootroot00000000000000/// @ref gtx_exterior_product /// @file glm/gtx/exterior_product.hpp /// /// @see core (dependence) /// @see gtx_exterior_product (dependence) /// /// @defgroup gtx_exterior_product GLM_GTX_exterior_product /// @ingroup gtx /// /// Include to use the features of this extension. /// /// @brief Allow to perform bit operations on integer values #pragma once // Dependencies #include "../detail/setup.hpp" #include "../detail/qualifier.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_exterior_product is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_exterior_product extension included") # endif #endif namespace glm { /// @addtogroup gtx_exterior_product /// @{ /// Returns the cross product of x and y. /// /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see Exterior product template GLM_FUNC_DECL T cross(vec<2, T, Q> const& v, vec<2, T, Q> const& u); /// @} } //namespace glm #include "exterior_product.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/exterior_product.inl000066400000000000000000000012231360521144700252220ustar00rootroot00000000000000/// @ref gtx_exterior_product #include namespace glm { namespace detail { template struct compute_cross_vec2 { GLM_FUNC_QUALIFIER static T call(vec<2, T, Q> const& v, vec<2, T, Q> const& u) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'cross' accepts only floating-point inputs"); return v.x * u.y - u.x * v.y; } }; }//namespace detail template GLM_FUNC_QUALIFIER T cross(vec<2, T, Q> const& x, vec<2, T, Q> const& y) { return detail::compute_cross_vec2::value>::call(x, y); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/fast_exponential.hpp000066400000000000000000000062151360521144700251770ustar00rootroot00000000000000/// @ref gtx_fast_exponential /// @file glm/gtx/fast_exponential.hpp /// /// @see core (dependence) /// @see gtx_half_float (dependence) /// /// @defgroup gtx_fast_exponential GLM_GTX_fast_exponential /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Fast but less accurate implementations of exponential based functions. #pragma once // Dependency: #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_fast_exponential is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_fast_exponential extension included") # endif #endif namespace glm { /// @addtogroup gtx_fast_exponential /// @{ /// Faster than the common pow function but less accurate. /// @see gtx_fast_exponential template GLM_FUNC_DECL genType fastPow(genType x, genType y); /// Faster than the common pow function but less accurate. /// @see gtx_fast_exponential template GLM_FUNC_DECL vec fastPow(vec const& x, vec const& y); /// Faster than the common pow function but less accurate. /// @see gtx_fast_exponential template GLM_FUNC_DECL genTypeT fastPow(genTypeT x, genTypeU y); /// Faster than the common pow function but less accurate. /// @see gtx_fast_exponential template GLM_FUNC_DECL vec fastPow(vec const& x); /// Faster than the common exp function but less accurate. /// @see gtx_fast_exponential template GLM_FUNC_DECL T fastExp(T x); /// Faster than the common exp function but less accurate. /// @see gtx_fast_exponential template GLM_FUNC_DECL vec fastExp(vec const& x); /// Faster than the common log function but less accurate. /// @see gtx_fast_exponential template GLM_FUNC_DECL T fastLog(T x); /// Faster than the common exp2 function but less accurate. /// @see gtx_fast_exponential template GLM_FUNC_DECL vec fastLog(vec const& x); /// Faster than the common exp2 function but less accurate. /// @see gtx_fast_exponential template GLM_FUNC_DECL T fastExp2(T x); /// Faster than the common exp2 function but less accurate. /// @see gtx_fast_exponential template GLM_FUNC_DECL vec fastExp2(vec const& x); /// Faster than the common log2 function but less accurate. /// @see gtx_fast_exponential template GLM_FUNC_DECL T fastLog2(T x); /// Faster than the common log2 function but less accurate. /// @see gtx_fast_exponential template GLM_FUNC_DECL vec fastLog2(vec const& x); /// @} }//namespace glm #include "fast_exponential.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/fast_exponential.inl000066400000000000000000000103661360521144700251740ustar00rootroot00000000000000/// @ref gtx_fast_exponential namespace glm { // fastPow: template GLM_FUNC_QUALIFIER genType fastPow(genType x, genType y) { return exp(y * log(x)); } template GLM_FUNC_QUALIFIER vec fastPow(vec const& x, vec const& y) { return exp(y * log(x)); } template GLM_FUNC_QUALIFIER T fastPow(T x, int y) { T f = static_cast(1); for(int i = 0; i < y; ++i) f *= x; return f; } template GLM_FUNC_QUALIFIER vec fastPow(vec const& x, vec const& y) { vec Result; for(length_t i = 0, n = x.length(); i < n; ++i) Result[i] = fastPow(x[i], y[i]); return Result; } // fastExp // Note: This function provides accurate results only for value between -1 and 1, else avoid it. template GLM_FUNC_QUALIFIER T fastExp(T x) { // This has a better looking and same performance in release mode than the following code. However, in debug mode it's slower. // return 1.0f + x * (1.0f + x * 0.5f * (1.0f + x * 0.3333333333f * (1.0f + x * 0.25 * (1.0f + x * 0.2f)))); T x2 = x * x; T x3 = x2 * x; T x4 = x3 * x; T x5 = x4 * x; return T(1) + x + (x2 * T(0.5)) + (x3 * T(0.1666666667)) + (x4 * T(0.041666667)) + (x5 * T(0.008333333333)); } /* // Try to handle all values of float... but often shower than std::exp, glm::floor and the loop kill the performance GLM_FUNC_QUALIFIER float fastExp(float x) { const float e = 2.718281828f; const float IntegerPart = floor(x); const float FloatPart = x - IntegerPart; float z = 1.f; for(int i = 0; i < int(IntegerPart); ++i) z *= e; const float x2 = FloatPart * FloatPart; const float x3 = x2 * FloatPart; const float x4 = x3 * FloatPart; const float x5 = x4 * FloatPart; return z * (1.0f + FloatPart + (x2 * 0.5f) + (x3 * 0.1666666667f) + (x4 * 0.041666667f) + (x5 * 0.008333333333f)); } // Increase accuracy on number bigger that 1 and smaller than -1 but it's not enough for high and negative numbers GLM_FUNC_QUALIFIER float fastExp(float x) { // This has a better looking and same performance in release mode than the following code. However, in debug mode it's slower. // return 1.0f + x * (1.0f + x * 0.5f * (1.0f + x * 0.3333333333f * (1.0f + x * 0.25 * (1.0f + x * 0.2f)))); float x2 = x * x; float x3 = x2 * x; float x4 = x3 * x; float x5 = x4 * x; float x6 = x5 * x; float x7 = x6 * x; float x8 = x7 * x; return 1.0f + x + (x2 * 0.5f) + (x3 * 0.1666666667f) + (x4 * 0.041666667f) + (x5 * 0.008333333333f)+ (x6 * 0.00138888888888f) + (x7 * 0.000198412698f) + (x8 * 0.0000248015873f);; } */ template GLM_FUNC_QUALIFIER vec fastExp(vec const& x) { return detail::functor1::call(fastExp, x); } // fastLog template GLM_FUNC_QUALIFIER genType fastLog(genType x) { return std::log(x); } /* Slower than the VC7.1 function... GLM_FUNC_QUALIFIER float fastLog(float x) { float y1 = (x - 1.0f) / (x + 1.0f); float y2 = y1 * y1; return 2.0f * y1 * (1.0f + y2 * (0.3333333333f + y2 * (0.2f + y2 * 0.1428571429f))); } */ template GLM_FUNC_QUALIFIER vec fastLog(vec const& x) { return detail::functor1::call(fastLog, x); } //fastExp2, ln2 = 0.69314718055994530941723212145818f template GLM_FUNC_QUALIFIER genType fastExp2(genType x) { return fastExp(0.69314718055994530941723212145818f * x); } template GLM_FUNC_QUALIFIER vec fastExp2(vec const& x) { return detail::functor1::call(fastExp2, x); } // fastLog2, ln2 = 0.69314718055994530941723212145818f template GLM_FUNC_QUALIFIER genType fastLog2(genType x) { return fastLog(x) / 0.69314718055994530941723212145818f; } template GLM_FUNC_QUALIFIER vec fastLog2(vec const& x) { return detail::functor1::call(fastLog2, x); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/fast_square_root.hpp000066400000000000000000000057211360521144700252150ustar00rootroot00000000000000/// @ref gtx_fast_square_root /// @file glm/gtx/fast_square_root.hpp /// /// @see core (dependence) /// /// @defgroup gtx_fast_square_root GLM_GTX_fast_square_root /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Fast but less accurate implementations of square root based functions. /// - Sqrt optimisation based on Newton's method, /// www.gamedev.net/community/forums/topic.asp?topic id=139956 #pragma once // Dependency: #include "../common.hpp" #include "../exponential.hpp" #include "../geometric.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_fast_square_root is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_fast_square_root extension included") # endif #endif namespace glm { /// @addtogroup gtx_fast_square_root /// @{ /// Faster than the common sqrt function but less accurate. /// /// @see gtx_fast_square_root extension. template GLM_FUNC_DECL genType fastSqrt(genType x); /// Faster than the common sqrt function but less accurate. /// /// @see gtx_fast_square_root extension. template GLM_FUNC_DECL vec fastSqrt(vec const& x); /// Faster than the common inversesqrt function but less accurate. /// /// @see gtx_fast_square_root extension. template GLM_FUNC_DECL genType fastInverseSqrt(genType x); /// Faster than the common inversesqrt function but less accurate. /// /// @see gtx_fast_square_root extension. template GLM_FUNC_DECL vec fastInverseSqrt(vec const& x); /// Faster than the common length function but less accurate. /// /// @see gtx_fast_square_root extension. template GLM_FUNC_DECL genType fastLength(genType x); /// Faster than the common length function but less accurate. /// /// @see gtx_fast_square_root extension. template GLM_FUNC_DECL T fastLength(vec const& x); /// Faster than the common distance function but less accurate. /// /// @see gtx_fast_square_root extension. template GLM_FUNC_DECL genType fastDistance(genType x, genType y); /// Faster than the common distance function but less accurate. /// /// @see gtx_fast_square_root extension. template GLM_FUNC_DECL T fastDistance(vec const& x, vec const& y); /// Faster than the common normalize function but less accurate. /// /// @see gtx_fast_square_root extension. template GLM_FUNC_DECL genType fastNormalize(genType const& x); /// @} }// namespace glm #include "fast_square_root.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/fast_square_root.inl000066400000000000000000000041071360521144700252050ustar00rootroot00000000000000/// @ref gtx_fast_square_root namespace glm { // fastSqrt template GLM_FUNC_QUALIFIER genType fastSqrt(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fastSqrt' only accept floating-point input"); return genType(1) / fastInverseSqrt(x); } template GLM_FUNC_QUALIFIER vec fastSqrt(vec const& x) { return detail::functor1::call(fastSqrt, x); } // fastInversesqrt template GLM_FUNC_QUALIFIER genType fastInverseSqrt(genType x) { return detail::compute_inversesqrt<1, genType, lowp, detail::is_aligned::value>::call(vec<1, genType, lowp>(x)).x; } template GLM_FUNC_QUALIFIER vec fastInverseSqrt(vec const& x) { return detail::compute_inversesqrt::value>::call(x); } // fastLength template GLM_FUNC_QUALIFIER genType fastLength(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fastLength' only accept floating-point inputs"); return abs(x); } template GLM_FUNC_QUALIFIER T fastLength(vec const& x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'fastLength' only accept floating-point inputs"); return fastSqrt(dot(x, x)); } // fastDistance template GLM_FUNC_QUALIFIER genType fastDistance(genType x, genType y) { return fastLength(y - x); } template GLM_FUNC_QUALIFIER T fastDistance(vec const& x, vec const& y) { return fastLength(y - x); } // fastNormalize template GLM_FUNC_QUALIFIER genType fastNormalize(genType x) { return x > genType(0) ? genType(1) : -genType(1); } template GLM_FUNC_QUALIFIER vec fastNormalize(vec const& x) { return x * fastInverseSqrt(dot(x, x)); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/fast_trigonometry.hpp000066400000000000000000000046521360521144700254160ustar00rootroot00000000000000/// @ref gtx_fast_trigonometry /// @file glm/gtx/fast_trigonometry.hpp /// /// @see core (dependence) /// /// @defgroup gtx_fast_trigonometry GLM_GTX_fast_trigonometry /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Fast but less accurate implementations of trigonometric functions. #pragma once // Dependency: #include "../gtc/constants.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_fast_trigonometry is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_fast_trigonometry extension included") # endif #endif namespace glm { /// @addtogroup gtx_fast_trigonometry /// @{ /// Wrap an angle to [0 2pi[ /// From GLM_GTX_fast_trigonometry extension. template GLM_FUNC_DECL T wrapAngle(T angle); /// Faster than the common sin function but less accurate. /// From GLM_GTX_fast_trigonometry extension. template GLM_FUNC_DECL T fastSin(T angle); /// Faster than the common cos function but less accurate. /// From GLM_GTX_fast_trigonometry extension. template GLM_FUNC_DECL T fastCos(T angle); /// Faster than the common tan function but less accurate. /// Defined between -2pi and 2pi. /// From GLM_GTX_fast_trigonometry extension. template GLM_FUNC_DECL T fastTan(T angle); /// Faster than the common asin function but less accurate. /// Defined between -2pi and 2pi. /// From GLM_GTX_fast_trigonometry extension. template GLM_FUNC_DECL T fastAsin(T angle); /// Faster than the common acos function but less accurate. /// Defined between -2pi and 2pi. /// From GLM_GTX_fast_trigonometry extension. template GLM_FUNC_DECL T fastAcos(T angle); /// Faster than the common atan function but less accurate. /// Defined between -2pi and 2pi. /// From GLM_GTX_fast_trigonometry extension. template GLM_FUNC_DECL T fastAtan(T y, T x); /// Faster than the common atan function but less accurate. /// Defined between -2pi and 2pi. /// From GLM_GTX_fast_trigonometry extension. template GLM_FUNC_DECL T fastAtan(T angle); /// @} }//namespace glm #include "fast_trigonometry.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/fast_trigonometry.inl000066400000000000000000000100741360521144700254040ustar00rootroot00000000000000/// @ref gtx_fast_trigonometry namespace glm{ namespace detail { template GLM_FUNC_QUALIFIER vec taylorCos(vec const& x) { return static_cast(1) - (x * x) * (1.f / 2.f) + ((x * x) * (x * x)) * (1.f / 24.f) - (((x * x) * (x * x)) * (x * x)) * (1.f / 720.f) + (((x * x) * (x * x)) * ((x * x) * (x * x))) * (1.f / 40320.f); } template GLM_FUNC_QUALIFIER T cos_52s(T x) { T const xx(x * x); return (T(0.9999932946) + xx * (T(-0.4999124376) + xx * (T(0.0414877472) + xx * T(-0.0012712095)))); } template GLM_FUNC_QUALIFIER vec cos_52s(vec const& x) { return detail::functor1::call(cos_52s, x); } }//namespace detail // wrapAngle template GLM_FUNC_QUALIFIER T wrapAngle(T angle) { return abs(mod(angle, two_pi())); } template GLM_FUNC_QUALIFIER vec wrapAngle(vec const& x) { return detail::functor1::call(wrapAngle, x); } // cos template GLM_FUNC_QUALIFIER T fastCos(T x) { T const angle(wrapAngle(x)); if(angle < half_pi()) return detail::cos_52s(angle); if(angle < pi()) return -detail::cos_52s(pi() - angle); if(angle < (T(3) * half_pi())) return -detail::cos_52s(angle - pi()); return detail::cos_52s(two_pi() - angle); } template GLM_FUNC_QUALIFIER vec fastCos(vec const& x) { return detail::functor1::call(fastCos, x); } // sin template GLM_FUNC_QUALIFIER T fastSin(T x) { return fastCos(half_pi() - x); } template GLM_FUNC_QUALIFIER vec fastSin(vec const& x) { return detail::functor1::call(fastSin, x); } // tan template GLM_FUNC_QUALIFIER T fastTan(T x) { return x + (x * x * x * T(0.3333333333)) + (x * x * x * x * x * T(0.1333333333333)) + (x * x * x * x * x * x * x * T(0.0539682539)); } template GLM_FUNC_QUALIFIER vec fastTan(vec const& x) { return detail::functor1::call(fastTan, x); } // asin template GLM_FUNC_QUALIFIER T fastAsin(T x) { return x + (x * x * x * T(0.166666667)) + (x * x * x * x * x * T(0.075)) + (x * x * x * x * x * x * x * T(0.0446428571)) + (x * x * x * x * x * x * x * x * x * T(0.0303819444));// + (x * x * x * x * x * x * x * x * x * x * x * T(0.022372159)); } template GLM_FUNC_QUALIFIER vec fastAsin(vec const& x) { return detail::functor1::call(fastAsin, x); } // acos template GLM_FUNC_QUALIFIER T fastAcos(T x) { return T(1.5707963267948966192313216916398) - fastAsin(x); //(PI / 2) } template GLM_FUNC_QUALIFIER vec fastAcos(vec const& x) { return detail::functor1::call(fastAcos, x); } // atan template GLM_FUNC_QUALIFIER T fastAtan(T y, T x) { T sgn = sign(y) * sign(x); return abs(fastAtan(y / x)) * sgn; } template GLM_FUNC_QUALIFIER vec fastAtan(vec const& y, vec const& x) { return detail::functor2::call(fastAtan, y, x); } template GLM_FUNC_QUALIFIER T fastAtan(T x) { return x - (x * x * x * T(0.333333333333)) + (x * x * x * x * x * T(0.2)) - (x * x * x * x * x * x * x * T(0.1428571429)) + (x * x * x * x * x * x * x * x * x * T(0.111111111111)) - (x * x * x * x * x * x * x * x * x * x * x * T(0.0909090909)); } template GLM_FUNC_QUALIFIER vec fastAtan(vec const& x) { return detail::functor1::call(fastAtan, x); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/float_notmalize.inl000066400000000000000000000004621360521144700250140ustar00rootroot00000000000000/// @ref gtx_float_normalize #include namespace glm { template GLM_FUNC_QUALIFIER vec floatNormalize(vec const& v) { return vec(v) / static_cast(std::numeric_limits::max()); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/functions.hpp000066400000000000000000000024761360521144700236510ustar00rootroot00000000000000/// @ref gtx_functions /// @file glm/gtx/functions.hpp /// /// @see core (dependence) /// @see gtc_quaternion (dependence) /// /// @defgroup gtx_functions GLM_GTX_functions /// @ingroup gtx /// /// Include to use the features of this extension. /// /// List of useful common functions. #pragma once // Dependencies #include "../detail/setup.hpp" #include "../detail/qualifier.hpp" #include "../detail/type_vec2.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_functions is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_functions extension included") # endif #endif namespace glm { /// @addtogroup gtx_functions /// @{ /// 1D gauss function /// /// @see gtc_epsilon template GLM_FUNC_DECL T gauss( T x, T ExpectedValue, T StandardDeviation); /// 2D gauss function /// /// @see gtc_epsilon template GLM_FUNC_DECL T gauss( vec<2, T, Q> const& Coord, vec<2, T, Q> const& ExpectedValue, vec<2, T, Q> const& StandardDeviation); /// @} }//namespace glm #include "functions.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/functions.inl000066400000000000000000000014431360521144700236350ustar00rootroot00000000000000/// @ref gtx_functions #include "../exponential.hpp" namespace glm { template GLM_FUNC_QUALIFIER T gauss ( T x, T ExpectedValue, T StandardDeviation ) { return exp(-((x - ExpectedValue) * (x - ExpectedValue)) / (static_cast(2) * StandardDeviation * StandardDeviation)) / (StandardDeviation * sqrt(static_cast(6.28318530717958647692528676655900576))); } template GLM_FUNC_QUALIFIER T gauss ( vec<2, T, Q> const& Coord, vec<2, T, Q> const& ExpectedValue, vec<2, T, Q> const& StandardDeviation ) { vec<2, T, Q> const Squared = ((Coord - ExpectedValue) * (Coord - ExpectedValue)) / (static_cast(2) * StandardDeviation * StandardDeviation); return exp(-(Squared.x + Squared.y)); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/gradient_paint.hpp000066400000000000000000000027521360521144700246260ustar00rootroot00000000000000/// @ref gtx_gradient_paint /// @file glm/gtx/gradient_paint.hpp /// /// @see core (dependence) /// @see gtx_optimum_pow (dependence) /// /// @defgroup gtx_gradient_paint GLM_GTX_gradient_paint /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Functions that return the color of procedural gradient for specific coordinates. #pragma once // Dependency: #include "../glm.hpp" #include "../gtx/optimum_pow.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_gradient_paint is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_gradient_paint extension included") # endif #endif namespace glm { /// @addtogroup gtx_gradient_paint /// @{ /// Return a color from a radial gradient. /// @see - gtx_gradient_paint template GLM_FUNC_DECL T radialGradient( vec<2, T, Q> const& Center, T const& Radius, vec<2, T, Q> const& Focal, vec<2, T, Q> const& Position); /// Return a color from a linear gradient. /// @see - gtx_gradient_paint template GLM_FUNC_DECL T linearGradient( vec<2, T, Q> const& Point0, vec<2, T, Q> const& Point1, vec<2, T, Q> const& Position); /// @} }// namespace glm #include "gradient_paint.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/gradient_paint.inl000066400000000000000000000016541360521144700246210ustar00rootroot00000000000000/// @ref gtx_gradient_paint namespace glm { template GLM_FUNC_QUALIFIER T radialGradient ( vec<2, T, Q> const& Center, T const& Radius, vec<2, T, Q> const& Focal, vec<2, T, Q> const& Position ) { vec<2, T, Q> F = Focal - Center; vec<2, T, Q> D = Position - Focal; T Radius2 = pow2(Radius); T Fx2 = pow2(F.x); T Fy2 = pow2(F.y); T Numerator = (D.x * F.x + D.y * F.y) + sqrt(Radius2 * (pow2(D.x) + pow2(D.y)) - pow2(D.x * F.y - D.y * F.x)); T Denominator = Radius2 - (Fx2 + Fy2); return Numerator / Denominator; } template GLM_FUNC_QUALIFIER T linearGradient ( vec<2, T, Q> const& Point0, vec<2, T, Q> const& Point1, vec<2, T, Q> const& Position ) { vec<2, T, Q> Dist = Point1 - Point0; return (Dist.x * (Position.x - Point0.x) + Dist.y * (Position.y - Point0.y)) / glm::dot(Dist, Dist); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/handed_coordinate_space.hpp000066400000000000000000000030341360521144700264350ustar00rootroot00000000000000/// @ref gtx_handed_coordinate_space /// @file glm/gtx/handed_coordinate_space.hpp /// /// @see core (dependence) /// /// @defgroup gtx_handed_coordinate_space GLM_GTX_handed_coordinate_space /// @ingroup gtx /// /// Include to use the features of this extension. /// /// To know if a set of three basis vectors defines a right or left-handed coordinate system. #pragma once // Dependency: #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_handed_coordinate_space is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_handed_coordinate_space extension included") # endif #endif namespace glm { /// @addtogroup gtx_handed_coordinate_space /// @{ //! Return if a trihedron right handed or not. //! From GLM_GTX_handed_coordinate_space extension. template GLM_FUNC_DECL bool rightHanded( vec<3, T, Q> const& tangent, vec<3, T, Q> const& binormal, vec<3, T, Q> const& normal); //! Return if a trihedron left handed or not. //! From GLM_GTX_handed_coordinate_space extension. template GLM_FUNC_DECL bool leftHanded( vec<3, T, Q> const& tangent, vec<3, T, Q> const& binormal, vec<3, T, Q> const& normal); /// @} }// namespace glm #include "handed_coordinate_space.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/handed_coordinate_space.inl000066400000000000000000000010571360521144700264330ustar00rootroot00000000000000/// @ref gtx_handed_coordinate_space namespace glm { template GLM_FUNC_QUALIFIER bool rightHanded ( vec<3, T, Q> const& tangent, vec<3, T, Q> const& binormal, vec<3, T, Q> const& normal ) { return dot(cross(normal, tangent), binormal) > T(0); } template GLM_FUNC_QUALIFIER bool leftHanded ( vec<3, T, Q> const& tangent, vec<3, T, Q> const& binormal, vec<3, T, Q> const& normal ) { return dot(cross(normal, tangent), binormal) < T(0); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/hash.hpp000066400000000000000000000070371360521144700225620ustar00rootroot00000000000000/// @ref gtx_hash /// @file glm/gtx/hash.hpp /// /// @see core (dependence) /// /// @defgroup gtx_hash GLM_GTX_hash /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Add std::hash support for glm types #pragma once #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_hash is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_hash extension included") # endif #endif #include #include "../vec2.hpp" #include "../vec3.hpp" #include "../vec4.hpp" #include "../gtc/vec1.hpp" #include "../gtc/quaternion.hpp" #include "../gtx/dual_quaternion.hpp" #include "../mat2x2.hpp" #include "../mat2x3.hpp" #include "../mat2x4.hpp" #include "../mat3x2.hpp" #include "../mat3x3.hpp" #include "../mat3x4.hpp" #include "../mat4x2.hpp" #include "../mat4x3.hpp" #include "../mat4x4.hpp" #if !GLM_HAS_CXX11_STL # error "GLM_GTX_hash requires C++11 standard library support" #endif namespace std { template struct hash > { GLM_FUNC_DECL size_t operator()(glm::vec<1, T, Q> const& v) const; }; template struct hash > { GLM_FUNC_DECL size_t operator()(glm::vec<2, T, Q> const& v) const; }; template struct hash > { GLM_FUNC_DECL size_t operator()(glm::vec<3, T, Q> const& v) const; }; template struct hash > { GLM_FUNC_DECL size_t operator()(glm::vec<4, T, Q> const& v) const; }; template struct hash> { GLM_FUNC_DECL size_t operator()(glm::qua const& q) const; }; template struct hash > { GLM_FUNC_DECL size_t operator()(glm::tdualquat const& q) const; }; template struct hash > { GLM_FUNC_DECL size_t operator()(glm::mat<2, 2, T,Q> const& m) const; }; template struct hash > { GLM_FUNC_DECL size_t operator()(glm::mat<2, 3, T,Q> const& m) const; }; template struct hash > { GLM_FUNC_DECL size_t operator()(glm::mat<2, 4, T,Q> const& m) const; }; template struct hash > { GLM_FUNC_DECL size_t operator()(glm::mat<3, 2, T,Q> const& m) const; }; template struct hash > { GLM_FUNC_DECL size_t operator()(glm::mat<3, 3, T,Q> const& m) const; }; template struct hash > { GLM_FUNC_DECL size_t operator()(glm::mat<3, 4, T,Q> const& m) const; }; template struct hash > { GLM_FUNC_DECL size_t operator()(glm::mat<4, 2, T,Q> const& m) const; }; template struct hash > { GLM_FUNC_DECL size_t operator()(glm::mat<4, 3, T,Q> const& m) const; }; template struct hash > { GLM_FUNC_DECL size_t operator()(glm::mat<4, 4, T,Q> const& m) const; }; } // namespace std #include "hash.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/hash.inl000066400000000000000000000132431360521144700225510ustar00rootroot00000000000000/// @ref gtx_hash /// /// @see core (dependence) /// /// @defgroup gtx_hash GLM_GTX_hash /// @ingroup gtx /// /// @brief Add std::hash support for glm types /// /// need to be included to use the features of this extension. namespace glm { namespace detail { GLM_INLINE void hash_combine(size_t &seed, size_t hash) { hash += 0x9e3779b9 + (seed << 6) + (seed >> 2); seed ^= hash; } }} namespace std { template GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::vec<1, T, Q> const& v) const { hash hasher; return hasher(v.x); } template GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::vec<2, T, Q> const& v) const { size_t seed = 0; hash hasher; glm::detail::hash_combine(seed, hasher(v.x)); glm::detail::hash_combine(seed, hasher(v.y)); return seed; } template GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::vec<3, T, Q> const& v) const { size_t seed = 0; hash hasher; glm::detail::hash_combine(seed, hasher(v.x)); glm::detail::hash_combine(seed, hasher(v.y)); glm::detail::hash_combine(seed, hasher(v.z)); return seed; } template GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::vec<4, T, Q> const& v) const { size_t seed = 0; hash hasher; glm::detail::hash_combine(seed, hasher(v.x)); glm::detail::hash_combine(seed, hasher(v.y)); glm::detail::hash_combine(seed, hasher(v.z)); glm::detail::hash_combine(seed, hasher(v.w)); return seed; } template GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::qua const& q) const { size_t seed = 0; hash hasher; glm::detail::hash_combine(seed, hasher(q.x)); glm::detail::hash_combine(seed, hasher(q.y)); glm::detail::hash_combine(seed, hasher(q.z)); glm::detail::hash_combine(seed, hasher(q.w)); return seed; } template GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::tdualquat const& q) const { size_t seed = 0; hash> hasher; glm::detail::hash_combine(seed, hasher(q.real)); glm::detail::hash_combine(seed, hasher(q.dual)); return seed; } template GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<2, 2, T, Q> const& m) const { size_t seed = 0; hash> hasher; glm::detail::hash_combine(seed, hasher(m[0])); glm::detail::hash_combine(seed, hasher(m[1])); return seed; } template GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<2, 3, T, Q> const& m) const { size_t seed = 0; hash> hasher; glm::detail::hash_combine(seed, hasher(m[0])); glm::detail::hash_combine(seed, hasher(m[1])); return seed; } template GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<2, 4, T, Q> const& m) const { size_t seed = 0; hash> hasher; glm::detail::hash_combine(seed, hasher(m[0])); glm::detail::hash_combine(seed, hasher(m[1])); return seed; } template GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<3, 2, T, Q> const& m) const { size_t seed = 0; hash> hasher; glm::detail::hash_combine(seed, hasher(m[0])); glm::detail::hash_combine(seed, hasher(m[1])); glm::detail::hash_combine(seed, hasher(m[2])); return seed; } template GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<3, 3, T, Q> const& m) const { size_t seed = 0; hash> hasher; glm::detail::hash_combine(seed, hasher(m[0])); glm::detail::hash_combine(seed, hasher(m[1])); glm::detail::hash_combine(seed, hasher(m[2])); return seed; } template GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<3, 4, T, Q> const& m) const { size_t seed = 0; hash> hasher; glm::detail::hash_combine(seed, hasher(m[0])); glm::detail::hash_combine(seed, hasher(m[1])); glm::detail::hash_combine(seed, hasher(m[2])); return seed; } template GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<4, 2, T,Q> const& m) const { size_t seed = 0; hash> hasher; glm::detail::hash_combine(seed, hasher(m[0])); glm::detail::hash_combine(seed, hasher(m[1])); glm::detail::hash_combine(seed, hasher(m[2])); glm::detail::hash_combine(seed, hasher(m[3])); return seed; } template GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<4, 3, T,Q> const& m) const { size_t seed = 0; hash> hasher; glm::detail::hash_combine(seed, hasher(m[0])); glm::detail::hash_combine(seed, hasher(m[1])); glm::detail::hash_combine(seed, hasher(m[2])); glm::detail::hash_combine(seed, hasher(m[3])); return seed; } template GLM_FUNC_QUALIFIER size_t hash>::operator()(glm::mat<4, 4, T, Q> const& m) const { size_t seed = 0; hash> hasher; glm::detail::hash_combine(seed, hasher(m[0])); glm::detail::hash_combine(seed, hasher(m[1])); glm::detail::hash_combine(seed, hasher(m[2])); glm::detail::hash_combine(seed, hasher(m[3])); return seed; } } connectome-workbench-1.4.2/src/GLMath/glm/gtx/integer.hpp000066400000000000000000000043021360521144700232640ustar00rootroot00000000000000/// @ref gtx_integer /// @file glm/gtx/integer.hpp /// /// @see core (dependence) /// /// @defgroup gtx_integer GLM_GTX_integer /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Add support for integer for core functions #pragma once // Dependency: #include "../glm.hpp" #include "../gtc/integer.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_integer is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_integer extension included") # endif #endif namespace glm { /// @addtogroup gtx_integer /// @{ //! Returns x raised to the y power. //! From GLM_GTX_integer extension. GLM_FUNC_DECL int pow(int x, uint y); //! Returns the positive square root of x. //! From GLM_GTX_integer extension. GLM_FUNC_DECL int sqrt(int x); //! Returns the floor log2 of x. //! From GLM_GTX_integer extension. GLM_FUNC_DECL unsigned int floor_log2(unsigned int x); //! Modulus. Returns x - y * floor(x / y) for each component in x using the floating point value y. //! From GLM_GTX_integer extension. GLM_FUNC_DECL int mod(int x, int y); //! Return the factorial value of a number (!12 max, integer only) //! From GLM_GTX_integer extension. template GLM_FUNC_DECL genType factorial(genType const& x); //! 32bit signed integer. //! From GLM_GTX_integer extension. typedef signed int sint; //! Returns x raised to the y power. //! From GLM_GTX_integer extension. GLM_FUNC_DECL uint pow(uint x, uint y); //! Returns the positive square root of x. //! From GLM_GTX_integer extension. GLM_FUNC_DECL uint sqrt(uint x); //! Modulus. Returns x - y * floor(x / y) for each component in x using the floating point value y. //! From GLM_GTX_integer extension. GLM_FUNC_DECL uint mod(uint x, uint y); //! Returns the number of leading zeros. //! From GLM_GTX_integer extension. GLM_FUNC_DECL uint nlz(uint x); /// @} }//namespace glm #include "integer.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/integer.inl000066400000000000000000000076511360521144700232710ustar00rootroot00000000000000/// @ref gtx_integer namespace glm { // pow GLM_FUNC_QUALIFIER int pow(int x, uint y) { if(y == 0) return x >= 0 ? 1 : -1; int result = x; for(uint i = 1; i < y; ++i) result *= x; return result; } // sqrt: From Christopher J. Musial, An integer square root, Graphics Gems, 1990, page 387 GLM_FUNC_QUALIFIER int sqrt(int x) { if(x <= 1) return x; int NextTrial = x >> 1; int CurrentAnswer; do { CurrentAnswer = NextTrial; NextTrial = (NextTrial + x / NextTrial) >> 1; } while(NextTrial < CurrentAnswer); return CurrentAnswer; } // Henry Gordon Dietz: http://aggregate.org/MAGIC/ namespace detail { GLM_FUNC_QUALIFIER unsigned int ones32(unsigned int x) { /* 32-bit recursive reduction using SWAR... but first step is mapping 2-bit values into sum of 2 1-bit values in sneaky way */ x -= ((x >> 1) & 0x55555555); x = (((x >> 2) & 0x33333333) + (x & 0x33333333)); x = (((x >> 4) + x) & 0x0f0f0f0f); x += (x >> 8); x += (x >> 16); return(x & 0x0000003f); } }//namespace detail // Henry Gordon Dietz: http://aggregate.org/MAGIC/ /* GLM_FUNC_QUALIFIER unsigned int floor_log2(unsigned int x) { x |= (x >> 1); x |= (x >> 2); x |= (x >> 4); x |= (x >> 8); x |= (x >> 16); return _detail::ones32(x) >> 1; } */ // mod GLM_FUNC_QUALIFIER int mod(int x, int y) { return ((x % y) + y) % y; } // factorial (!12 max, integer only) template GLM_FUNC_QUALIFIER genType factorial(genType const& x) { genType Temp = x; genType Result; for(Result = 1; Temp > 1; --Temp) Result *= Temp; return Result; } template GLM_FUNC_QUALIFIER vec<2, T, Q> factorial( vec<2, T, Q> const& x) { return vec<2, T, Q>( factorial(x.x), factorial(x.y)); } template GLM_FUNC_QUALIFIER vec<3, T, Q> factorial( vec<3, T, Q> const& x) { return vec<3, T, Q>( factorial(x.x), factorial(x.y), factorial(x.z)); } template GLM_FUNC_QUALIFIER vec<4, T, Q> factorial( vec<4, T, Q> const& x) { return vec<4, T, Q>( factorial(x.x), factorial(x.y), factorial(x.z), factorial(x.w)); } GLM_FUNC_QUALIFIER uint pow(uint x, uint y) { if (y == 0) return 1u; uint result = x; for(uint i = 1; i < y; ++i) result *= x; return result; } GLM_FUNC_QUALIFIER uint sqrt(uint x) { if(x <= 1) return x; uint NextTrial = x >> 1; uint CurrentAnswer; do { CurrentAnswer = NextTrial; NextTrial = (NextTrial + x / NextTrial) >> 1; } while(NextTrial < CurrentAnswer); return CurrentAnswer; } GLM_FUNC_QUALIFIER uint mod(uint x, uint y) { return x - y * (x / y); } #if(GLM_COMPILER & (GLM_COMPILER_VC | GLM_COMPILER_GCC)) GLM_FUNC_QUALIFIER unsigned int nlz(unsigned int x) { return 31u - findMSB(x); } #else // Hackers Delight: http://www.hackersdelight.org/HDcode/nlz.c.txt GLM_FUNC_QUALIFIER unsigned int nlz(unsigned int x) { int y, m, n; y = -int(x >> 16); // If left half of x is 0, m = (y >> 16) & 16; // set n = 16. If left half n = 16 - m; // is nonzero, set n = 0 and x = x >> m; // shift x right 16. // Now x is of the form 0000xxxx. y = x - 0x100; // If positions 8-15 are 0, m = (y >> 16) & 8; // add 8 to n and shift x left 8. n = n + m; x = x << m; y = x - 0x1000; // If positions 12-15 are 0, m = (y >> 16) & 4; // add 4 to n and shift x left 4. n = n + m; x = x << m; y = x - 0x4000; // If positions 14-15 are 0, m = (y >> 16) & 2; // add 2 to n and shift x left 2. n = n + m; x = x << m; y = x >> 14; // Set y = 0, 1, 2, or 3. m = y & ~(y >> 1); // Set m = 0, 1, 2, or 2 resp. return unsigned(n + 2 - m); } #endif//(GLM_COMPILER) }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/intersect.hpp000066400000000000000000000065621360521144700236410ustar00rootroot00000000000000/// @ref gtx_intersect /// @file glm/gtx/intersect.hpp /// /// @see core (dependence) /// @see gtx_closest_point (dependence) /// /// @defgroup gtx_intersect GLM_GTX_intersect /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Add intersection functions #pragma once // Dependency: #include #include #include "../glm.hpp" #include "../geometric.hpp" #include "../gtx/closest_point.hpp" #include "../gtx/vector_query.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_closest_point is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_closest_point extension included") # endif #endif namespace glm { /// @addtogroup gtx_intersect /// @{ //! Compute the intersection of a ray and a plane. //! Ray direction and plane normal must be unit length. //! From GLM_GTX_intersect extension. template GLM_FUNC_DECL bool intersectRayPlane( genType const& orig, genType const& dir, genType const& planeOrig, genType const& planeNormal, typename genType::value_type & intersectionDistance); //! Compute the intersection of a ray and a triangle. /// Based om Tomas Möller implementation http://fileadmin.cs.lth.se/cs/Personal/Tomas_Akenine-Moller/raytri/ //! From GLM_GTX_intersect extension. template GLM_FUNC_DECL bool intersectRayTriangle( vec<3, T, Q> const& orig, vec<3, T, Q> const& dir, vec<3, T, Q> const& v0, vec<3, T, Q> const& v1, vec<3, T, Q> const& v2, vec<2, T, Q>& baryPosition, T& distance); //! Compute the intersection of a line and a triangle. //! From GLM_GTX_intersect extension. template GLM_FUNC_DECL bool intersectLineTriangle( genType const& orig, genType const& dir, genType const& vert0, genType const& vert1, genType const& vert2, genType & position); //! Compute the intersection distance of a ray and a sphere. //! The ray direction vector is unit length. //! From GLM_GTX_intersect extension. template GLM_FUNC_DECL bool intersectRaySphere( genType const& rayStarting, genType const& rayNormalizedDirection, genType const& sphereCenter, typename genType::value_type const sphereRadiusSquered, typename genType::value_type & intersectionDistance); //! Compute the intersection of a ray and a sphere. //! From GLM_GTX_intersect extension. template GLM_FUNC_DECL bool intersectRaySphere( genType const& rayStarting, genType const& rayNormalizedDirection, genType const& sphereCenter, const typename genType::value_type sphereRadius, genType & intersectionPosition, genType & intersectionNormal); //! Compute the intersection of a line and a sphere. //! From GLM_GTX_intersect extension template GLM_FUNC_DECL bool intersectLineSphere( genType const& point0, genType const& point1, genType const& sphereCenter, typename genType::value_type sphereRadius, genType & intersectionPosition1, genType & intersectionNormal1, genType & intersectionPosition2 = genType(), genType & intersectionNormal2 = genType()); /// @} }//namespace glm #include "intersect.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/intersect.inl000066400000000000000000000147111360521144700236270ustar00rootroot00000000000000/// @ref gtx_intersect namespace glm { template GLM_FUNC_QUALIFIER bool intersectRayPlane ( genType const& orig, genType const& dir, genType const& planeOrig, genType const& planeNormal, typename genType::value_type & intersectionDistance ) { typename genType::value_type d = glm::dot(dir, planeNormal); typename genType::value_type Epsilon = std::numeric_limits::epsilon(); if(d < -Epsilon) { intersectionDistance = glm::dot(planeOrig - orig, planeNormal) / d; return true; } return false; } template GLM_FUNC_QUALIFIER bool intersectRayTriangle ( vec<3, T, Q> const& orig, vec<3, T, Q> const& dir, vec<3, T, Q> const& vert0, vec<3, T, Q> const& vert1, vec<3, T, Q> const& vert2, vec<2, T, Q>& baryPosition, T& distance ) { // find vectors for two edges sharing vert0 vec<3, T, Q> const edge1 = vert1 - vert0; vec<3, T, Q> const edge2 = vert2 - vert0; // begin calculating determinant - also used to calculate U parameter vec<3, T, Q> const p = glm::cross(dir, edge2); // if determinant is near zero, ray lies in plane of triangle T const det = glm::dot(edge1, p); vec<3, T, Q> Perpendicular(0); if(det > std::numeric_limits::epsilon()) { // calculate distance from vert0 to ray origin vec<3, T, Q> const dist = orig - vert0; // calculate U parameter and test bounds baryPosition.x = glm::dot(dist, p); if(baryPosition.x < static_cast(0) || baryPosition.x > det) return false; // prepare to test V parameter Perpendicular = glm::cross(dist, edge1); // calculate V parameter and test bounds baryPosition.y = glm::dot(dir, Perpendicular); if((baryPosition.y < static_cast(0)) || ((baryPosition.x + baryPosition.y) > det)) return false; } else if(det < -std::numeric_limits::epsilon()) { // calculate distance from vert0 to ray origin vec<3, T, Q> const dist = orig - vert0; // calculate U parameter and test bounds baryPosition.x = glm::dot(dist, p); if((baryPosition.x > static_cast(0)) || (baryPosition.x < det)) return false; // prepare to test V parameter Perpendicular = glm::cross(dist, edge1); // calculate V parameter and test bounds baryPosition.y = glm::dot(dir, Perpendicular); if((baryPosition.y > static_cast(0)) || (baryPosition.x + baryPosition.y < det)) return false; } else return false; // ray is parallel to the plane of the triangle T inv_det = static_cast(1) / det; // calculate distance, ray intersects triangle distance = glm::dot(edge2, Perpendicular) * inv_det; baryPosition *= inv_det; return true; } template GLM_FUNC_QUALIFIER bool intersectLineTriangle ( genType const& orig, genType const& dir, genType const& vert0, genType const& vert1, genType const& vert2, genType & position ) { typename genType::value_type Epsilon = std::numeric_limits::epsilon(); genType edge1 = vert1 - vert0; genType edge2 = vert2 - vert0; genType Perpendicular = cross(dir, edge2); float det = dot(edge1, Perpendicular); if (det > -Epsilon && det < Epsilon) return false; typename genType::value_type inv_det = typename genType::value_type(1) / det; genType Tengant = orig - vert0; position.y = dot(Tengant, Perpendicular) * inv_det; if (position.y < typename genType::value_type(0) || position.y > typename genType::value_type(1)) return false; genType Cotengant = cross(Tengant, edge1); position.z = dot(dir, Cotengant) * inv_det; if (position.z < typename genType::value_type(0) || position.y + position.z > typename genType::value_type(1)) return false; position.x = dot(edge2, Cotengant) * inv_det; return true; } template GLM_FUNC_QUALIFIER bool intersectRaySphere ( genType const& rayStarting, genType const& rayNormalizedDirection, genType const& sphereCenter, const typename genType::value_type sphereRadiusSquered, typename genType::value_type & intersectionDistance ) { typename genType::value_type Epsilon = std::numeric_limits::epsilon(); genType diff = sphereCenter - rayStarting; typename genType::value_type t0 = dot(diff, rayNormalizedDirection); typename genType::value_type dSquared = dot(diff, diff) - t0 * t0; if( dSquared > sphereRadiusSquered ) { return false; } typename genType::value_type t1 = sqrt( sphereRadiusSquered - dSquared ); intersectionDistance = t0 > t1 + Epsilon ? t0 - t1 : t0 + t1; return intersectionDistance > Epsilon; } template GLM_FUNC_QUALIFIER bool intersectRaySphere ( genType const& rayStarting, genType const& rayNormalizedDirection, genType const& sphereCenter, const typename genType::value_type sphereRadius, genType & intersectionPosition, genType & intersectionNormal ) { typename genType::value_type distance; if( intersectRaySphere( rayStarting, rayNormalizedDirection, sphereCenter, sphereRadius * sphereRadius, distance ) ) { intersectionPosition = rayStarting + rayNormalizedDirection * distance; intersectionNormal = (intersectionPosition - sphereCenter) / sphereRadius; return true; } return false; } template GLM_FUNC_QUALIFIER bool intersectLineSphere ( genType const& point0, genType const& point1, genType const& sphereCenter, typename genType::value_type sphereRadius, genType & intersectionPoint1, genType & intersectionNormal1, genType & intersectionPoint2, genType & intersectionNormal2 ) { typename genType::value_type Epsilon = std::numeric_limits::epsilon(); genType dir = normalize(point1 - point0); genType diff = sphereCenter - point0; typename genType::value_type t0 = dot(diff, dir); typename genType::value_type dSquared = dot(diff, diff) - t0 * t0; if( dSquared > sphereRadius * sphereRadius ) { return false; } typename genType::value_type t1 = sqrt( sphereRadius * sphereRadius - dSquared ); if( t0 < t1 + Epsilon ) t1 = -t1; intersectionPoint1 = point0 + dir * (t0 - t1); intersectionNormal1 = (intersectionPoint1 - sphereCenter) / sphereRadius; intersectionPoint2 = point0 + dir * (t0 + t1); intersectionNormal2 = (intersectionPoint2 - sphereCenter) / sphereRadius; return true; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/io.hpp000066400000000000000000000163031360521144700222420ustar00rootroot00000000000000/// @ref gtx_io /// @file glm/gtx/io.hpp /// @author Jan P Springer (regnirpsj@gmail.com) /// /// @see core (dependence) /// @see gtc_matrix_access (dependence) /// @see gtc_quaternion (dependence) /// /// @defgroup gtx_io GLM_GTX_io /// @ingroup gtx /// /// Include to use the features of this extension. /// /// std::[w]ostream support for glm types /// /// std::[w]ostream support for glm types + qualifier/width/etc. manipulators /// based on howard hinnant's std::chrono io proposal /// [http://home.roadrunner.com/~hinnant/bloomington/chrono_io.html] #pragma once // Dependency: #include "../glm.hpp" #include "../gtx/quaternion.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_io is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_io extension included") # endif #endif #include // std::basic_ostream<> (fwd) #include // std::locale, std::locale::facet, std::locale::id #include // std::pair<> namespace glm { /// @addtogroup gtx_io /// @{ namespace io { enum order_type { column_major, row_major}; template class format_punct : public std::locale::facet { typedef CTy char_type; public: static std::locale::id id; bool formatted; unsigned precision; unsigned width; char_type separator; char_type delim_left; char_type delim_right; char_type space; char_type newline; order_type order; GLM_FUNC_DECL explicit format_punct(size_t a = 0); GLM_FUNC_DECL explicit format_punct(format_punct const&); }; template > class basic_state_saver { public: GLM_FUNC_DECL explicit basic_state_saver(std::basic_ios&); GLM_FUNC_DECL ~basic_state_saver(); private: typedef ::std::basic_ios state_type; typedef typename state_type::char_type char_type; typedef ::std::ios_base::fmtflags flags_type; typedef ::std::streamsize streamsize_type; typedef ::std::locale const locale_type; state_type& state_; flags_type flags_; streamsize_type precision_; streamsize_type width_; char_type fill_; locale_type locale_; GLM_FUNC_DECL basic_state_saver& operator=(basic_state_saver const&); }; typedef basic_state_saver state_saver; typedef basic_state_saver wstate_saver; template > class basic_format_saver { public: GLM_FUNC_DECL explicit basic_format_saver(std::basic_ios&); GLM_FUNC_DECL ~basic_format_saver(); private: basic_state_saver const bss_; GLM_FUNC_DECL basic_format_saver& operator=(basic_format_saver const&); }; typedef basic_format_saver format_saver; typedef basic_format_saver wformat_saver; struct precision { unsigned value; GLM_FUNC_DECL explicit precision(unsigned); }; struct width { unsigned value; GLM_FUNC_DECL explicit width(unsigned); }; template struct delimeter { CTy value[3]; GLM_FUNC_DECL explicit delimeter(CTy /* left */, CTy /* right */, CTy /* separator */ = ','); }; struct order { order_type value; GLM_FUNC_DECL explicit order(order_type); }; // functions, inlined (inline) template FTy const& get_facet(std::basic_ios&); template std::basic_ios& formatted(std::basic_ios&); template std::basic_ios& unformattet(std::basic_ios&); template std::basic_ostream& operator<<(std::basic_ostream&, precision const&); template std::basic_ostream& operator<<(std::basic_ostream&, width const&); template std::basic_ostream& operator<<(std::basic_ostream&, delimeter const&); template std::basic_ostream& operator<<(std::basic_ostream&, order const&); }//namespace io template GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, qua const&); template GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, vec<1, T, Q> const&); template GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, vec<2, T, Q> const&); template GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, vec<3, T, Q> const&); template GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, vec<4, T, Q> const&); template GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<2, 2, T, Q> const&); template GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<2, 3, T, Q> const&); template GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<2, 4, T, Q> const&); template GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<3, 2, T, Q> const&); template GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<3, 3, T, Q> const&); template GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<3, 4, T, Q> const&); template GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<4, 2, T, Q> const&); template GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<4, 3, T, Q> const&); template GLM_FUNC_DECL std::basic_ostream& operator<<(std::basic_ostream&, mat<4, 4, T, Q> const&); template GLM_FUNC_DECL std::basic_ostream & operator<<(std::basic_ostream &, std::pair const, mat<4, 4, T, Q> const> const&); /// @} }//namespace glm #include "io.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/io.inl000066400000000000000000000301301360521144700222270ustar00rootroot00000000000000/// @ref gtx_io /// @author Jan P Springer (regnirpsj@gmail.com) #include // std::fixed, std::setfill<>, std::setprecision, std::right, std::setw #include // std::basic_ostream<> #include "../gtc/matrix_access.hpp" // glm::col, glm::row #include "../gtx/type_trait.hpp" // glm::type<> namespace glm{ namespace io { template GLM_FUNC_QUALIFIER format_punct::format_punct(size_t a) : std::locale::facet(a) , formatted(true) , precision(3) , width(1 + 4 + 1 + precision) , separator(',') , delim_left('[') , delim_right(']') , space(' ') , newline('\n') , order(column_major) {} template GLM_FUNC_QUALIFIER format_punct::format_punct(format_punct const& a) : std::locale::facet(0) , formatted(a.formatted) , precision(a.precision) , width(a.width) , separator(a.separator) , delim_left(a.delim_left) , delim_right(a.delim_right) , space(a.space) , newline(a.newline) , order(a.order) {} template std::locale::id format_punct::id; template GLM_FUNC_QUALIFIER basic_state_saver::basic_state_saver(std::basic_ios& a) : state_(a) , flags_(a.flags()) , precision_(a.precision()) , width_(a.width()) , fill_(a.fill()) , locale_(a.getloc()) {} template GLM_FUNC_QUALIFIER basic_state_saver::~basic_state_saver() { state_.imbue(locale_); state_.fill(fill_); state_.width(width_); state_.precision(precision_); state_.flags(flags_); } template GLM_FUNC_QUALIFIER basic_format_saver::basic_format_saver(std::basic_ios& a) : bss_(a) { a.imbue(std::locale(a.getloc(), new format_punct(get_facet >(a)))); } template GLM_FUNC_QUALIFIER basic_format_saver::~basic_format_saver() {} GLM_FUNC_QUALIFIER precision::precision(unsigned a) : value(a) {} GLM_FUNC_QUALIFIER width::width(unsigned a) : value(a) {} template GLM_FUNC_QUALIFIER delimeter::delimeter(CTy a, CTy b, CTy c) : value() { value[0] = a; value[1] = b; value[2] = c; } GLM_FUNC_QUALIFIER order::order(order_type a) : value(a) {} template GLM_FUNC_QUALIFIER FTy const& get_facet(std::basic_ios& ios) { if(!std::has_facet(ios.getloc())) ios.imbue(std::locale(ios.getloc(), new FTy)); return std::use_facet(ios.getloc()); } template GLM_FUNC_QUALIFIER std::basic_ios& formatted(std::basic_ios& ios) { const_cast&>(get_facet >(ios)).formatted = true; return ios; } template GLM_FUNC_QUALIFIER std::basic_ios& unformatted(std::basic_ios& ios) { const_cast&>(get_facet >(ios)).formatted = false; return ios; } template GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, precision const& a) { const_cast&>(get_facet >(os)).precision = a.value; return os; } template GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, width const& a) { const_cast&>(get_facet >(os)).width = a.value; return os; } template GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, delimeter const& a) { format_punct & fmt(const_cast&>(get_facet >(os))); fmt.delim_left = a.value[0]; fmt.delim_right = a.value[1]; fmt.separator = a.value[2]; return os; } template GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, order const& a) { const_cast&>(get_facet >(os)).order = a.value; return os; } } // namespace io namespace detail { template GLM_FUNC_QUALIFIER std::basic_ostream& print_vector_on(std::basic_ostream& os, V const& a) { typename std::basic_ostream::sentry const cerberus(os); if(cerberus) { io::format_punct const& fmt(io::get_facet >(os)); length_t const& components(type::components); if(fmt.formatted) { io::basic_state_saver const bss(os); os << std::fixed << std::right << std::setprecision(fmt.precision) << std::setfill(fmt.space) << fmt.delim_left; for(length_t i(0); i < components; ++i) { os << std::setw(fmt.width) << a[i]; if(components-1 != i) os << fmt.separator; } os << fmt.delim_right; } else { for(length_t i(0); i < components; ++i) { os << a[i]; if(components-1 != i) os << fmt.space; } } } return os; } }//namespace detail template GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, qua const& a) { return detail::print_vector_on(os, a); } template GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, vec<1, T, Q> const& a) { return detail::print_vector_on(os, a); } template GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, vec<2, T, Q> const& a) { return detail::print_vector_on(os, a); } template GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, vec<3, T, Q> const& a) { return detail::print_vector_on(os, a); } template GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, vec<4, T, Q> const& a) { return detail::print_vector_on(os, a); } namespace detail { template class M, length_t C, length_t R, typename T, qualifier Q> GLM_FUNC_QUALIFIER std::basic_ostream& print_matrix_on(std::basic_ostream& os, M const& a) { typename std::basic_ostream::sentry const cerberus(os); if(cerberus) { io::format_punct const& fmt(io::get_facet >(os)); length_t const& cols(type >::cols); length_t const& rows(type >::rows); if(fmt.formatted) { os << fmt.newline << fmt.delim_left; switch(fmt.order) { case io::column_major: { for(length_t i(0); i < rows; ++i) { if (0 != i) os << fmt.space; os << row(a, i); if(rows-1 != i) os << fmt.newline; } } break; case io::row_major: { for(length_t i(0); i < cols; ++i) { if(0 != i) os << fmt.space; os << column(a, i); if(cols-1 != i) os << fmt.newline; } } break; } os << fmt.delim_right; } else { switch (fmt.order) { case io::column_major: { for(length_t i(0); i < cols; ++i) { os << column(a, i); if(cols - 1 != i) os << fmt.space; } } break; case io::row_major: { for (length_t i(0); i < rows; ++i) { os << row(a, i); if (rows-1 != i) os << fmt.space; } } break; } } } return os; } }//namespace detail template GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, mat<2, 2, T, Q> const& a) { return detail::print_matrix_on(os, a); } template GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, mat<2, 3, T, Q> const& a) { return detail::print_matrix_on(os, a); } template GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, mat<2, 4, T, Q> const& a) { return detail::print_matrix_on(os, a); } template GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, mat<3, 2, T, Q> const& a) { return detail::print_matrix_on(os, a); } template GLM_FUNC_QUALIFIER std::basic_ostream& operator<<(std::basic_ostream& os, mat<3, 3, T, Q> const& a) { return detail::print_matrix_on(os, a); } template GLM_FUNC_QUALIFIER std::basic_ostream & operator<<(std::basic_ostream& os, mat<3, 4, T, Q> const& a) { return detail::print_matrix_on(os, a); } template GLM_FUNC_QUALIFIER std::basic_ostream & operator<<(std::basic_ostream& os, mat<4, 2, T, Q> const& a) { return detail::print_matrix_on(os, a); } template GLM_FUNC_QUALIFIER std::basic_ostream & operator<<(std::basic_ostream& os, mat<4, 3, T, Q> const& a) { return detail::print_matrix_on(os, a); } template GLM_FUNC_QUALIFIER std::basic_ostream & operator<<(std::basic_ostream& os, mat<4, 4, T, Q> const& a) { return detail::print_matrix_on(os, a); } namespace detail { template class M, length_t C, length_t R, typename T, qualifier Q> GLM_FUNC_QUALIFIER std::basic_ostream& print_matrix_pair_on(std::basic_ostream& os, std::pair const, M const> const& a) { typename std::basic_ostream::sentry const cerberus(os); if(cerberus) { io::format_punct const& fmt(io::get_facet >(os)); M const& ml(a.first); M const& mr(a.second); length_t const& cols(type >::cols); length_t const& rows(type >::rows); if(fmt.formatted) { os << fmt.newline << fmt.delim_left; switch(fmt.order) { case io::column_major: { for(length_t i(0); i < rows; ++i) { if(0 != i) os << fmt.space; os << row(ml, i) << ((rows-1 != i) ? fmt.space : fmt.delim_right) << fmt.space << ((0 != i) ? fmt.space : fmt.delim_left) << row(mr, i); if(rows-1 != i) os << fmt.newline; } } break; case io::row_major: { for(length_t i(0); i < cols; ++i) { if(0 != i) os << fmt.space; os << column(ml, i) << ((cols-1 != i) ? fmt.space : fmt.delim_right) << fmt.space << ((0 != i) ? fmt.space : fmt.delim_left) << column(mr, i); if(cols-1 != i) os << fmt.newline; } } break; } os << fmt.delim_right; } else { os << ml << fmt.space << mr; } } return os; } }//namespace detail template GLM_FUNC_QUALIFIER std::basic_ostream& operator<<( std::basic_ostream & os, std::pair const, mat<4, 4, T, Q> const> const& a) { return detail::print_matrix_pair_on(os, a); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/log_base.hpp000066400000000000000000000023021360521144700234000ustar00rootroot00000000000000/// @ref gtx_log_base /// @file glm/gtx/log_base.hpp /// /// @see core (dependence) /// /// @defgroup gtx_log_base GLM_GTX_log_base /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Logarithm for any base. base can be a vector or a scalar. #pragma once // Dependency: #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_log_base is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_log_base extension included") # endif #endif namespace glm { /// @addtogroup gtx_log_base /// @{ /// Logarithm for any base. /// From GLM_GTX_log_base. template GLM_FUNC_DECL genType log( genType const& x, genType const& base); /// Logarithm for any base. /// From GLM_GTX_log_base. template GLM_FUNC_DECL vec sign( vec const& x, vec const& base); /// @} }//namespace glm #include "log_base.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/log_base.inl000066400000000000000000000006131360521144700233760ustar00rootroot00000000000000/// @ref gtx_log_base namespace glm { template GLM_FUNC_QUALIFIER genType log(genType const& x, genType const& base) { return glm::log(x) / glm::log(base); } template GLM_FUNC_QUALIFIER vec log(vec const& x, vec const& base) { return glm::log(x) / glm::log(base); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/matrix_cross_product.hpp000066400000000000000000000025341360521144700261110ustar00rootroot00000000000000/// @ref gtx_matrix_cross_product /// @file glm/gtx/matrix_cross_product.hpp /// /// @see core (dependence) /// @see gtx_extented_min_max (dependence) /// /// @defgroup gtx_matrix_cross_product GLM_GTX_matrix_cross_product /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Build cross product matrices #pragma once // Dependency: #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_matrix_cross_product is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_matrix_cross_product extension included") # endif #endif namespace glm { /// @addtogroup gtx_matrix_cross_product /// @{ //! Build a cross product matrix. //! From GLM_GTX_matrix_cross_product extension. template GLM_FUNC_DECL mat<3, 3, T, Q> matrixCross3( vec<3, T, Q> const& x); //! Build a cross product matrix. //! From GLM_GTX_matrix_cross_product extension. template GLM_FUNC_DECL mat<4, 4, T, Q> matrixCross4( vec<3, T, Q> const& x); /// @} }//namespace glm #include "matrix_cross_product.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/matrix_cross_product.inl000066400000000000000000000013131360521144700260760ustar00rootroot00000000000000/// @ref gtx_matrix_cross_product namespace glm { template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> matrixCross3 ( vec<3, T, Q> const& x ) { mat<3, 3, T, Q> Result(T(0)); Result[0][1] = x.z; Result[1][0] = -x.z; Result[0][2] = -x.y; Result[2][0] = x.y; Result[1][2] = x.x; Result[2][1] = -x.x; return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> matrixCross4 ( vec<3, T, Q> const& x ) { mat<4, 4, T, Q> Result(T(0)); Result[0][1] = x.z; Result[1][0] = -x.z; Result[0][2] = -x.y; Result[2][0] = x.y; Result[1][2] = x.x; Result[2][1] = -x.x; return Result; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/matrix_decompose.hpp000066400000000000000000000026431360521144700251770ustar00rootroot00000000000000/// @ref gtx_matrix_decompose /// @file glm/gtx/matrix_decompose.hpp /// /// @see core (dependence) /// /// @defgroup gtx_matrix_decompose GLM_GTX_matrix_decompose /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Decomposes a model matrix to translations, rotation and scale components #pragma once // Dependencies #include "../mat4x4.hpp" #include "../vec3.hpp" #include "../vec4.hpp" #include "../geometric.hpp" #include "../gtc/quaternion.hpp" #include "../gtc/matrix_transform.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_matrix_decompose is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_matrix_decompose extension included") # endif #endif namespace glm { /// @addtogroup gtx_matrix_decompose /// @{ /// Decomposes a model matrix to translations, rotation and scale components /// @see gtx_matrix_decompose template GLM_FUNC_DECL bool decompose( mat<4, 4, T, Q> const& modelMatrix, vec<3, T, Q> & scale, qua & orientation, vec<3, T, Q> & translation, vec<3, T, Q> & skew, vec<4, T, Q> & perspective); /// @} }//namespace glm #include "matrix_decompose.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/matrix_decompose.inl000066400000000000000000000147421360521144700251750ustar00rootroot00000000000000/// @ref gtx_matrix_decompose #include "../gtc/constants.hpp" #include "../gtc/epsilon.hpp" namespace glm{ namespace detail { /// Make a linear combination of two vectors and return the result. // result = (a * ascl) + (b * bscl) template GLM_FUNC_QUALIFIER vec<3, T, Q> combine( vec<3, T, Q> const& a, vec<3, T, Q> const& b, T ascl, T bscl) { return (a * ascl) + (b * bscl); } template GLM_FUNC_QUALIFIER vec<3, T, Q> scale(vec<3, T, Q> const& v, T desiredLength) { return v * desiredLength / length(v); } }//namespace detail // Matrix decompose // http://www.opensource.apple.com/source/WebCore/WebCore-514/platform/graphics/transforms/TransformationMatrix.cpp // Decomposes the mode matrix to translations,rotation scale components template GLM_FUNC_QUALIFIER bool decompose(mat<4, 4, T, Q> const& ModelMatrix, vec<3, T, Q> & Scale, qua & Orientation, vec<3, T, Q> & Translation, vec<3, T, Q> & Skew, vec<4, T, Q> & Perspective) { mat<4, 4, T, Q> LocalMatrix(ModelMatrix); // Normalize the matrix. if(epsilonEqual(LocalMatrix[3][3], static_cast(0), epsilon())) return false; for(length_t i = 0; i < 4; ++i) for(length_t j = 0; j < 4; ++j) LocalMatrix[i][j] /= LocalMatrix[3][3]; // perspectiveMatrix is used to solve for perspective, but it also provides // an easy way to test for singularity of the upper 3x3 component. mat<4, 4, T, Q> PerspectiveMatrix(LocalMatrix); for(length_t i = 0; i < 3; i++) PerspectiveMatrix[i][3] = static_cast(0); PerspectiveMatrix[3][3] = static_cast(1); /// TODO: Fixme! if(epsilonEqual(determinant(PerspectiveMatrix), static_cast(0), epsilon())) return false; // First, isolate perspective. This is the messiest. if( epsilonNotEqual(LocalMatrix[0][3], static_cast(0), epsilon()) || epsilonNotEqual(LocalMatrix[1][3], static_cast(0), epsilon()) || epsilonNotEqual(LocalMatrix[2][3], static_cast(0), epsilon())) { // rightHandSide is the right hand side of the equation. vec<4, T, Q> RightHandSide; RightHandSide[0] = LocalMatrix[0][3]; RightHandSide[1] = LocalMatrix[1][3]; RightHandSide[2] = LocalMatrix[2][3]; RightHandSide[3] = LocalMatrix[3][3]; // Solve the equation by inverting PerspectiveMatrix and multiplying // rightHandSide by the inverse. (This is the easiest way, not // necessarily the best.) mat<4, 4, T, Q> InversePerspectiveMatrix = glm::inverse(PerspectiveMatrix);// inverse(PerspectiveMatrix, inversePerspectiveMatrix); mat<4, 4, T, Q> TransposedInversePerspectiveMatrix = glm::transpose(InversePerspectiveMatrix);// transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveMatrix); Perspective = TransposedInversePerspectiveMatrix * RightHandSide; // v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint); // Clear the perspective partition LocalMatrix[0][3] = LocalMatrix[1][3] = LocalMatrix[2][3] = static_cast(0); LocalMatrix[3][3] = static_cast(1); } else { // No perspective. Perspective = vec<4, T, Q>(0, 0, 0, 1); } // Next take care of translation (easy). Translation = vec<3, T, Q>(LocalMatrix[3]); LocalMatrix[3] = vec<4, T, Q>(0, 0, 0, LocalMatrix[3].w); vec<3, T, Q> Row[3], Pdum3; // Now get scale and shear. for(length_t i = 0; i < 3; ++i) for(length_t j = 0; j < 3; ++j) Row[i][j] = LocalMatrix[i][j]; // Compute X scale factor and normalize first row. Scale.x = length(Row[0]);// v3Length(Row[0]); Row[0] = detail::scale(Row[0], static_cast(1)); // Compute XY shear factor and make 2nd row orthogonal to 1st. Skew.z = dot(Row[0], Row[1]); Row[1] = detail::combine(Row[1], Row[0], static_cast(1), -Skew.z); // Now, compute Y scale and normalize 2nd row. Scale.y = length(Row[1]); Row[1] = detail::scale(Row[1], static_cast(1)); Skew.z /= Scale.y; // Compute XZ and YZ shears, orthogonalize 3rd row. Skew.y = glm::dot(Row[0], Row[2]); Row[2] = detail::combine(Row[2], Row[0], static_cast(1), -Skew.y); Skew.x = glm::dot(Row[1], Row[2]); Row[2] = detail::combine(Row[2], Row[1], static_cast(1), -Skew.x); // Next, get Z scale and normalize 3rd row. Scale.z = length(Row[2]); Row[2] = detail::scale(Row[2], static_cast(1)); Skew.y /= Scale.z; Skew.x /= Scale.z; // At this point, the matrix (in rows[]) is orthonormal. // Check for a coordinate system flip. If the determinant // is -1, then negate the matrix and the scaling factors. Pdum3 = cross(Row[1], Row[2]); // v3Cross(row[1], row[2], Pdum3); if(dot(Row[0], Pdum3) < 0) { for(length_t i = 0; i < 3; i++) { Scale[i] *= static_cast(-1); Row[i] *= static_cast(-1); } } // Now, get the rotations out, as described in the gem. // FIXME - Add the ability to return either quaternions (which are // easier to recompose with) or Euler angles (rx, ry, rz), which // are easier for authors to deal with. The latter will only be useful // when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I // will leave the Euler angle code here for now. // ret.rotateY = asin(-Row[0][2]); // if (cos(ret.rotateY) != 0) { // ret.rotateX = atan2(Row[1][2], Row[2][2]); // ret.rotateZ = atan2(Row[0][1], Row[0][0]); // } else { // ret.rotateX = atan2(-Row[2][0], Row[1][1]); // ret.rotateZ = 0; // } int i, j, k = 0; T root, trace = Row[0].x + Row[1].y + Row[2].z; if(trace > static_cast(0)) { root = sqrt(trace + static_cast(1.0)); Orientation.w = static_cast(0.5) * root; root = static_cast(0.5) / root; Orientation.x = root * (Row[1].z - Row[2].y); Orientation.y = root * (Row[2].x - Row[0].z); Orientation.z = root * (Row[0].y - Row[1].x); } // End if > 0 else { static int Next[3] = {1, 2, 0}; i = 0; if(Row[1].y > Row[0].x) i = 1; if(Row[2].z > Row[i][i]) i = 2; j = Next[i]; k = Next[j]; root = sqrt(Row[i][i] - Row[j][j] - Row[k][k] + static_cast(1.0)); Orientation[i] = static_cast(0.5) * root; root = static_cast(0.5) / root; Orientation[j] = root * (Row[i][j] + Row[j][i]); Orientation[k] = root * (Row[i][k] + Row[k][i]); Orientation.w = root * (Row[j][k] - Row[k][j]); } // End if <= 0 return true; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/matrix_factorisation.hpp000066400000000000000000000056141360521144700260670ustar00rootroot00000000000000/// @ref gtx_matrix_factorisation /// @file glm/gtx/matrix_factorisation.hpp /// /// @see core (dependence) /// /// @defgroup gtx_matrix_factorisation GLM_GTX_matrix_factorisation /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Functions to factor matrices in various forms #pragma once // Dependency: #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_matrix_factorisation is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_matrix_factorisation extension included") # endif #endif /* Suggestions: - Move helper functions flipud and fliplr to another file: They may be helpful in more general circumstances. - Implement other types of matrix factorisation, such as: QL and LQ, L(D)U, eigendecompositions, etc... */ namespace glm { /// @addtogroup gtx_matrix_factorisation /// @{ /// Flips the matrix rows up and down. /// /// From GLM_GTX_matrix_factorisation extension. template GLM_FUNC_DECL mat flipud(mat const& in); /// Flips the matrix columns right and left. /// /// From GLM_GTX_matrix_factorisation extension. template GLM_FUNC_DECL mat fliplr(mat const& in); /// Performs QR factorisation of a matrix. /// Returns 2 matrices, q and r, such that the columns of q are orthonormal and span the same subspace than those of the input matrix, r is an upper triangular matrix, and q*r=in. /// Given an n-by-m input matrix, q has dimensions min(n,m)-by-m, and r has dimensions n-by-min(n,m). /// /// From GLM_GTX_matrix_factorisation extension. template GLM_FUNC_DECL void qr_decompose(mat const& in, mat<(C < R ? C : R), R, T, Q>& q, mat& r); /// Performs RQ factorisation of a matrix. /// Returns 2 matrices, r and q, such that r is an upper triangular matrix, the rows of q are orthonormal and span the same subspace than those of the input matrix, and r*q=in. /// Note that in the context of RQ factorisation, the diagonal is seen as starting in the lower-right corner of the matrix, instead of the usual upper-left. /// Given an n-by-m input matrix, r has dimensions min(n,m)-by-m, and q has dimensions n-by-min(n,m). /// /// From GLM_GTX_matrix_factorisation extension. template GLM_FUNC_DECL void rq_decompose(mat const& in, mat<(C < R ? C : R), R, T, Q>& r, mat& q); /// @} } #include "matrix_factorisation.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/matrix_factorisation.inl000066400000000000000000000054511360521144700260610ustar00rootroot00000000000000/// @ref gtx_matrix_factorisation namespace glm { template GLM_FUNC_QUALIFIER mat flipud(mat const& in) { mat tin = transpose(in); tin = fliplr(tin); mat out = transpose(tin); return out; } template GLM_FUNC_QUALIFIER mat fliplr(mat const& in) { mat out; for (length_t i = 0; i < C; i++) { out[i] = in[(C - i) - 1]; } return out; } template GLM_FUNC_QUALIFIER void qr_decompose(mat const& in, mat<(C < R ? C : R), R, T, Q>& q, mat& r) { // Uses modified Gram-Schmidt method // Source: https://en.wikipedia.org/wiki/GramSchmidt_process // And https://en.wikipedia.org/wiki/QR_decomposition //For all the linearly independs columns of the input... // (there can be no more linearly independents columns than there are rows.) for (length_t i = 0; i < (C < R ? C : R); i++) { //Copy in Q the input's i-th column. q[i] = in[i]; //j = [0,i[ // Make that column orthogonal to all the previous ones by substracting to it the non-orthogonal projection of all the previous columns. // Also: Fill the zero elements of R for (length_t j = 0; j < i; j++) { q[i] -= dot(q[i], q[j])*q[j]; r[j][i] = 0; } //Now, Q i-th column is orthogonal to all the previous columns. Normalize it. q[i] = normalize(q[i]); //j = [i,C[ //Finally, compute the corresponding coefficients of R by computing the projection of the resulting column on the other columns of the input. for (length_t j = i; j < C; j++) { r[j][i] = dot(in[j], q[i]); } } } template GLM_FUNC_QUALIFIER void rq_decompose(mat const& in, mat<(C < R ? C : R), R, T, Q>& r, mat& q) { // From https://en.wikipedia.org/wiki/QR_decomposition: // The RQ decomposition transforms a matrix A into the product of an upper triangular matrix R (also known as right-triangular) and an orthogonal matrix Q. The only difference from QR decomposition is the order of these matrices. // QR decomposition is GramSchmidt orthogonalization of columns of A, started from the first column. // RQ decomposition is GramSchmidt orthogonalization of rows of A, started from the last row. mat tin = transpose(in); tin = fliplr(tin); mat tr; mat<(C < R ? C : R), C, T, Q> tq; qr_decompose(tin, tq, tr); tr = fliplr(tr); r = transpose(tr); r = fliplr(r); tq = fliplr(tq); q = transpose(tq); } } //namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/matrix_interpolation.hpp000066400000000000000000000040121360521144700261000ustar00rootroot00000000000000/// @ref gtx_matrix_interpolation /// @file glm/gtx/matrix_interpolation.hpp /// @author Ghenadii Ursachi (the.asteroth@gmail.com) /// /// @see core (dependence) /// /// @defgroup gtx_matrix_interpolation GLM_GTX_matrix_interpolation /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Allows to directly interpolate two matrices. #pragma once // Dependency: #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_matrix_interpolation is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_matrix_interpolation extension included") # endif #endif namespace glm { /// @addtogroup gtx_matrix_interpolation /// @{ /// Get the axis and angle of the rotation from a matrix. /// From GLM_GTX_matrix_interpolation extension. template GLM_FUNC_DECL void axisAngle( mat<4, 4, T, Q> const& Mat, vec<3, T, Q> & Axis, T & Angle); /// Build a matrix from axis and angle. /// From GLM_GTX_matrix_interpolation extension. template GLM_FUNC_DECL mat<4, 4, T, Q> axisAngleMatrix( vec<3, T, Q> const& Axis, T const Angle); /// Extracts the rotation part of a matrix. /// From GLM_GTX_matrix_interpolation extension. template GLM_FUNC_DECL mat<4, 4, T, Q> extractMatrixRotation( mat<4, 4, T, Q> const& Mat); /// Build a interpolation of 4 * 4 matrixes. /// From GLM_GTX_matrix_interpolation extension. /// Warning! works only with rotation and/or translation matrixes, scale will generate unexpected results. template GLM_FUNC_DECL mat<4, 4, T, Q> interpolate( mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2, T const Delta); /// @} }//namespace glm #include "matrix_interpolation.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/matrix_interpolation.inl000066400000000000000000000104441360521144700261010ustar00rootroot00000000000000/// @ref gtx_matrix_interpolation #include "../gtc/constants.hpp" namespace glm { template GLM_FUNC_QUALIFIER void axisAngle(mat<4, 4, T, Q> const& m, vec<3, T, Q> & axis, T& angle) { T epsilon = static_cast(0.01); T epsilon2 = static_cast(0.1); if((abs(m[1][0] - m[0][1]) < epsilon) && (abs(m[2][0] - m[0][2]) < epsilon) && (abs(m[2][1] - m[1][2]) < epsilon)) { if ((abs(m[1][0] + m[0][1]) < epsilon2) && (abs(m[2][0] + m[0][2]) < epsilon2) && (abs(m[2][1] + m[1][2]) < epsilon2) && (abs(m[0][0] + m[1][1] + m[2][2] - static_cast(3.0)) < epsilon2)) { angle = static_cast(0.0); axis.x = static_cast(1.0); axis.y = static_cast(0.0); axis.z = static_cast(0.0); return; } angle = static_cast(3.1415926535897932384626433832795); T xx = (m[0][0] + static_cast(1.0)) * static_cast(0.5); T yy = (m[1][1] + static_cast(1.0)) * static_cast(0.5); T zz = (m[2][2] + static_cast(1.0)) * static_cast(0.5); T xy = (m[1][0] + m[0][1]) * static_cast(0.25); T xz = (m[2][0] + m[0][2]) * static_cast(0.25); T yz = (m[2][1] + m[1][2]) * static_cast(0.25); if((xx > yy) && (xx > zz)) { if(xx < epsilon) { axis.x = static_cast(0.0); axis.y = static_cast(0.7071); axis.z = static_cast(0.7071); } else { axis.x = sqrt(xx); axis.y = xy / axis.x; axis.z = xz / axis.x; } } else if (yy > zz) { if(yy < epsilon) { axis.x = static_cast(0.7071); axis.y = static_cast(0.0); axis.z = static_cast(0.7071); } else { axis.y = sqrt(yy); axis.x = xy / axis.y; axis.z = yz / axis.y; } } else { if (zz < epsilon) { axis.x = static_cast(0.7071); axis.y = static_cast(0.7071); axis.z = static_cast(0.0); } else { axis.z = sqrt(zz); axis.x = xz / axis.z; axis.y = yz / axis.z; } } return; } T s = sqrt((m[2][1] - m[1][2]) * (m[2][1] - m[1][2]) + (m[2][0] - m[0][2]) * (m[2][0] - m[0][2]) + (m[1][0] - m[0][1]) * (m[1][0] - m[0][1])); if (glm::abs(s) < T(0.001)) s = static_cast(1); T const angleCos = (m[0][0] + m[1][1] + m[2][2] - static_cast(1)) * static_cast(0.5); if(angleCos - static_cast(1) < epsilon) angle = pi() * static_cast(0.25); else angle = acos(angleCos); axis.x = (m[1][2] - m[2][1]) / s; axis.y = (m[2][0] - m[0][2]) / s; axis.z = (m[0][1] - m[1][0]) / s; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> axisAngleMatrix(vec<3, T, Q> const& axis, T const angle) { T c = cos(angle); T s = sin(angle); T t = static_cast(1) - c; vec<3, T, Q> n = normalize(axis); return mat<4, 4, T, Q>( t * n.x * n.x + c, t * n.x * n.y + n.z * s, t * n.x * n.z - n.y * s, static_cast(0.0), t * n.x * n.y - n.z * s, t * n.y * n.y + c, t * n.y * n.z + n.x * s, static_cast(0.0), t * n.x * n.z + n.y * s, t * n.y * n.z - n.x * s, t * n.z * n.z + c, static_cast(0.0), static_cast(0.0), static_cast(0.0), static_cast(0.0), static_cast(1.0)); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> extractMatrixRotation(mat<4, 4, T, Q> const& m) { return mat<4, 4, T, Q>( m[0][0], m[0][1], m[0][2], static_cast(0.0), m[1][0], m[1][1], m[1][2], static_cast(0.0), m[2][0], m[2][1], m[2][2], static_cast(0.0), static_cast(0.0), static_cast(0.0), static_cast(0.0), static_cast(1.0)); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> interpolate(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2, T const delta) { mat<4, 4, T, Q> m1rot = extractMatrixRotation(m1); mat<4, 4, T, Q> dltRotation = m2 * transpose(m1rot); vec<3, T, Q> dltAxis; T dltAngle; axisAngle(dltRotation, dltAxis, dltAngle); mat<4, 4, T, Q> out = axisAngleMatrix(dltAxis, dltAngle * delta) * m1rot; out[3][0] = m1[3][0] + delta * (m2[3][0] - m1[3][0]); out[3][1] = m1[3][1] + delta * (m2[3][1] - m1[3][1]); out[3][2] = m1[3][2] + delta * (m2[3][2] - m1[3][2]); return out; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/matrix_major_storage.hpp000066400000000000000000000074511360521144700260570ustar00rootroot00000000000000/// @ref gtx_matrix_major_storage /// @file glm/gtx/matrix_major_storage.hpp /// /// @see core (dependence) /// @see gtx_extented_min_max (dependence) /// /// @defgroup gtx_matrix_major_storage GLM_GTX_matrix_major_storage /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Build matrices with specific matrix order, row or column #pragma once // Dependency: #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_matrix_major_storage is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_matrix_major_storage extension included") # endif #endif namespace glm { /// @addtogroup gtx_matrix_major_storage /// @{ //! Build a row major matrix from row vectors. //! From GLM_GTX_matrix_major_storage extension. template GLM_FUNC_DECL mat<2, 2, T, Q> rowMajor2( vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); //! Build a row major matrix from other matrix. //! From GLM_GTX_matrix_major_storage extension. template GLM_FUNC_DECL mat<2, 2, T, Q> rowMajor2( mat<2, 2, T, Q> const& m); //! Build a row major matrix from row vectors. //! From GLM_GTX_matrix_major_storage extension. template GLM_FUNC_DECL mat<3, 3, T, Q> rowMajor3( vec<3, T, Q> const& v1, vec<3, T, Q> const& v2, vec<3, T, Q> const& v3); //! Build a row major matrix from other matrix. //! From GLM_GTX_matrix_major_storage extension. template GLM_FUNC_DECL mat<3, 3, T, Q> rowMajor3( mat<3, 3, T, Q> const& m); //! Build a row major matrix from row vectors. //! From GLM_GTX_matrix_major_storage extension. template GLM_FUNC_DECL mat<4, 4, T, Q> rowMajor4( vec<4, T, Q> const& v1, vec<4, T, Q> const& v2, vec<4, T, Q> const& v3, vec<4, T, Q> const& v4); //! Build a row major matrix from other matrix. //! From GLM_GTX_matrix_major_storage extension. template GLM_FUNC_DECL mat<4, 4, T, Q> rowMajor4( mat<4, 4, T, Q> const& m); //! Build a column major matrix from column vectors. //! From GLM_GTX_matrix_major_storage extension. template GLM_FUNC_DECL mat<2, 2, T, Q> colMajor2( vec<2, T, Q> const& v1, vec<2, T, Q> const& v2); //! Build a column major matrix from other matrix. //! From GLM_GTX_matrix_major_storage extension. template GLM_FUNC_DECL mat<2, 2, T, Q> colMajor2( mat<2, 2, T, Q> const& m); //! Build a column major matrix from column vectors. //! From GLM_GTX_matrix_major_storage extension. template GLM_FUNC_DECL mat<3, 3, T, Q> colMajor3( vec<3, T, Q> const& v1, vec<3, T, Q> const& v2, vec<3, T, Q> const& v3); //! Build a column major matrix from other matrix. //! From GLM_GTX_matrix_major_storage extension. template GLM_FUNC_DECL mat<3, 3, T, Q> colMajor3( mat<3, 3, T, Q> const& m); //! Build a column major matrix from column vectors. //! From GLM_GTX_matrix_major_storage extension. template GLM_FUNC_DECL mat<4, 4, T, Q> colMajor4( vec<4, T, Q> const& v1, vec<4, T, Q> const& v2, vec<4, T, Q> const& v3, vec<4, T, Q> const& v4); //! Build a column major matrix from other matrix. //! From GLM_GTX_matrix_major_storage extension. template GLM_FUNC_DECL mat<4, 4, T, Q> colMajor4( mat<4, 4, T, Q> const& m); /// @} }//namespace glm #include "matrix_major_storage.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/matrix_major_storage.inl000066400000000000000000000073551360521144700260550ustar00rootroot00000000000000/// @ref gtx_matrix_major_storage namespace glm { template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> rowMajor2 ( vec<2, T, Q> const& v1, vec<2, T, Q> const& v2 ) { mat<2, 2, T, Q> Result; Result[0][0] = v1.x; Result[1][0] = v1.y; Result[0][1] = v2.x; Result[1][1] = v2.y; return Result; } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> rowMajor2( const mat<2, 2, T, Q>& m) { mat<2, 2, T, Q> Result; Result[0][0] = m[0][0]; Result[0][1] = m[1][0]; Result[1][0] = m[0][1]; Result[1][1] = m[1][1]; return Result; } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> rowMajor3( const vec<3, T, Q>& v1, const vec<3, T, Q>& v2, const vec<3, T, Q>& v3) { mat<3, 3, T, Q> Result; Result[0][0] = v1.x; Result[1][0] = v1.y; Result[2][0] = v1.z; Result[0][1] = v2.x; Result[1][1] = v2.y; Result[2][1] = v2.z; Result[0][2] = v3.x; Result[1][2] = v3.y; Result[2][2] = v3.z; return Result; } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> rowMajor3( const mat<3, 3, T, Q>& m) { mat<3, 3, T, Q> Result; Result[0][0] = m[0][0]; Result[0][1] = m[1][0]; Result[0][2] = m[2][0]; Result[1][0] = m[0][1]; Result[1][1] = m[1][1]; Result[1][2] = m[2][1]; Result[2][0] = m[0][2]; Result[2][1] = m[1][2]; Result[2][2] = m[2][2]; return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rowMajor4( const vec<4, T, Q>& v1, const vec<4, T, Q>& v2, const vec<4, T, Q>& v3, const vec<4, T, Q>& v4) { mat<4, 4, T, Q> Result; Result[0][0] = v1.x; Result[1][0] = v1.y; Result[2][0] = v1.z; Result[3][0] = v1.w; Result[0][1] = v2.x; Result[1][1] = v2.y; Result[2][1] = v2.z; Result[3][1] = v2.w; Result[0][2] = v3.x; Result[1][2] = v3.y; Result[2][2] = v3.z; Result[3][2] = v3.w; Result[0][3] = v4.x; Result[1][3] = v4.y; Result[2][3] = v4.z; Result[3][3] = v4.w; return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rowMajor4( const mat<4, 4, T, Q>& m) { mat<4, 4, T, Q> Result; Result[0][0] = m[0][0]; Result[0][1] = m[1][0]; Result[0][2] = m[2][0]; Result[0][3] = m[3][0]; Result[1][0] = m[0][1]; Result[1][1] = m[1][1]; Result[1][2] = m[2][1]; Result[1][3] = m[3][1]; Result[2][0] = m[0][2]; Result[2][1] = m[1][2]; Result[2][2] = m[2][2]; Result[2][3] = m[3][2]; Result[3][0] = m[0][3]; Result[3][1] = m[1][3]; Result[3][2] = m[2][3]; Result[3][3] = m[3][3]; return Result; } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> colMajor2( const vec<2, T, Q>& v1, const vec<2, T, Q>& v2) { return mat<2, 2, T, Q>(v1, v2); } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> colMajor2( const mat<2, 2, T, Q>& m) { return mat<2, 2, T, Q>(m); } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> colMajor3( const vec<3, T, Q>& v1, const vec<3, T, Q>& v2, const vec<3, T, Q>& v3) { return mat<3, 3, T, Q>(v1, v2, v3); } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> colMajor3( const mat<3, 3, T, Q>& m) { return mat<3, 3, T, Q>(m); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> colMajor4( const vec<4, T, Q>& v1, const vec<4, T, Q>& v2, const vec<4, T, Q>& v3, const vec<4, T, Q>& v4) { return mat<4, 4, T, Q>(v1, v2, v3, v4); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> colMajor4( const mat<4, 4, T, Q>& m) { return mat<4, 4, T, Q>(m); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/matrix_operation.hpp000066400000000000000000000061231360521144700252160ustar00rootroot00000000000000/// @ref gtx_matrix_operation /// @file glm/gtx/matrix_operation.hpp /// /// @see core (dependence) /// /// @defgroup gtx_matrix_operation GLM_GTX_matrix_operation /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Build diagonal matrices from vectors. #pragma once // Dependency: #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_matrix_operation is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_matrix_operation extension included") # endif #endif namespace glm { /// @addtogroup gtx_matrix_operation /// @{ //! Build a diagonal matrix. //! From GLM_GTX_matrix_operation extension. template GLM_FUNC_DECL mat<2, 2, T, Q> diagonal2x2( vec<2, T, Q> const& v); //! Build a diagonal matrix. //! From GLM_GTX_matrix_operation extension. template GLM_FUNC_DECL mat<2, 3, T, Q> diagonal2x3( vec<2, T, Q> const& v); //! Build a diagonal matrix. //! From GLM_GTX_matrix_operation extension. template GLM_FUNC_DECL mat<2, 4, T, Q> diagonal2x4( vec<2, T, Q> const& v); //! Build a diagonal matrix. //! From GLM_GTX_matrix_operation extension. template GLM_FUNC_DECL mat<3, 2, T, Q> diagonal3x2( vec<2, T, Q> const& v); //! Build a diagonal matrix. //! From GLM_GTX_matrix_operation extension. template GLM_FUNC_DECL mat<3, 3, T, Q> diagonal3x3( vec<3, T, Q> const& v); //! Build a diagonal matrix. //! From GLM_GTX_matrix_operation extension. template GLM_FUNC_DECL mat<3, 4, T, Q> diagonal3x4( vec<3, T, Q> const& v); //! Build a diagonal matrix. //! From GLM_GTX_matrix_operation extension. template GLM_FUNC_DECL mat<4, 2, T, Q> diagonal4x2( vec<2, T, Q> const& v); //! Build a diagonal matrix. //! From GLM_GTX_matrix_operation extension. template GLM_FUNC_DECL mat<4, 3, T, Q> diagonal4x3( vec<3, T, Q> const& v); //! Build a diagonal matrix. //! From GLM_GTX_matrix_operation extension. template GLM_FUNC_DECL mat<4, 4, T, Q> diagonal4x4( vec<4, T, Q> const& v); /// Build an adjugate matrix. /// From GLM_GTX_matrix_operation extension. template GLM_FUNC_DECL mat<2, 2, T, Q> adjugate(mat<2, 2, T, Q> const& m); /// Build an adjugate matrix. /// From GLM_GTX_matrix_operation extension. template GLM_FUNC_DECL mat<3, 3, T, Q> adjugate(mat<3, 3, T, Q> const& m); /// Build an adjugate matrix. /// From GLM_GTX_matrix_operation extension. template GLM_FUNC_DECL mat<4, 4, T, Q> adjugate(mat<4, 4, T, Q> const& m); /// @} }//namespace glm #include "matrix_operation.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/matrix_operation.inl000066400000000000000000000132741360521144700252160ustar00rootroot00000000000000/// @ref gtx_matrix_operation namespace glm { template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> diagonal2x2 ( vec<2, T, Q> const& v ) { mat<2, 2, T, Q> Result(static_cast(1)); Result[0][0] = v[0]; Result[1][1] = v[1]; return Result; } template GLM_FUNC_QUALIFIER mat<2, 3, T, Q> diagonal2x3 ( vec<2, T, Q> const& v ) { mat<2, 3, T, Q> Result(static_cast(1)); Result[0][0] = v[0]; Result[1][1] = v[1]; return Result; } template GLM_FUNC_QUALIFIER mat<2, 4, T, Q> diagonal2x4 ( vec<2, T, Q> const& v ) { mat<2, 4, T, Q> Result(static_cast(1)); Result[0][0] = v[0]; Result[1][1] = v[1]; return Result; } template GLM_FUNC_QUALIFIER mat<3, 2, T, Q> diagonal3x2 ( vec<2, T, Q> const& v ) { mat<3, 2, T, Q> Result(static_cast(1)); Result[0][0] = v[0]; Result[1][1] = v[1]; return Result; } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> diagonal3x3 ( vec<3, T, Q> const& v ) { mat<3, 3, T, Q> Result(static_cast(1)); Result[0][0] = v[0]; Result[1][1] = v[1]; Result[2][2] = v[2]; return Result; } template GLM_FUNC_QUALIFIER mat<3, 4, T, Q> diagonal3x4 ( vec<3, T, Q> const& v ) { mat<3, 4, T, Q> Result(static_cast(1)); Result[0][0] = v[0]; Result[1][1] = v[1]; Result[2][2] = v[2]; return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> diagonal4x4 ( vec<4, T, Q> const& v ) { mat<4, 4, T, Q> Result(static_cast(1)); Result[0][0] = v[0]; Result[1][1] = v[1]; Result[2][2] = v[2]; Result[3][3] = v[3]; return Result; } template GLM_FUNC_QUALIFIER mat<4, 3, T, Q> diagonal4x3 ( vec<3, T, Q> const& v ) { mat<4, 3, T, Q> Result(static_cast(1)); Result[0][0] = v[0]; Result[1][1] = v[1]; Result[2][2] = v[2]; return Result; } template GLM_FUNC_QUALIFIER mat<4, 2, T, Q> diagonal4x2 ( vec<2, T, Q> const& v ) { mat<4, 2, T, Q> Result(static_cast(1)); Result[0][0] = v[0]; Result[1][1] = v[1]; return Result; } template GLM_FUNC_QUALIFIER mat<2, 2, T, Q> adjugate(mat<2, 2, T, Q> const& m) { return mat<2, 2, T, Q>( +m[1][1], -m[1][0], -m[0][1], +m[0][0]); } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> adjugate(mat<3, 3, T, Q> const& m) { T const m00 = determinant(mat<2, 2, T, Q>(m[1][1], m[2][1], m[1][2], m[2][2])); T const m01 = determinant(mat<2, 2, T, Q>(m[0][1], m[2][1], m[0][2], m[2][2])); T const m02 = determinant(mat<2, 2, T, Q>(m[0][1], m[1][1], m[0][2], m[1][2])); T const m10 = determinant(mat<2, 2, T, Q>(m[1][0], m[2][0], m[1][2], m[2][2])); T const m11 = determinant(mat<2, 2, T, Q>(m[0][0], m[2][0], m[0][2], m[2][2])); T const m12 = determinant(mat<2, 2, T, Q>(m[0][0], m[1][0], m[0][2], m[1][2])); T const m20 = determinant(mat<2, 2, T, Q>(m[1][0], m[2][0], m[1][1], m[2][1])); T const m21 = determinant(mat<2, 2, T, Q>(m[0][0], m[2][0], m[0][1], m[2][1])); T const m22 = determinant(mat<2, 2, T, Q>(m[0][0], m[1][0], m[0][1], m[1][1])); return mat<3, 3, T, Q>( +m00, -m01, +m02, -m10, +m11, -m12, +m20, -m21, +m22); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> adjugate(mat<4, 4, T, Q> const& m) { T const m00 = determinant(mat<3, 3, T, Q>(m[1][1], m[1][2], m[1][3], m[2][1], m[2][2], m[2][3], m[3][1], m[3][2], m[3][3])); T const m01 = determinant(mat<3, 3, T, Q>(m[1][0], m[1][2], m[1][3], m[2][0], m[2][2], m[2][3], m[3][0], m[3][2], m[3][3])); T const m02 = determinant(mat<3, 3, T, Q>(m[1][0], m[1][1], m[1][3], m[2][0], m[2][2], m[2][3], m[3][0], m[3][1], m[3][3])); T const m03 = determinant(mat<3, 3, T, Q>(m[1][0], m[1][1], m[1][2], m[2][0], m[2][1], m[2][2], m[3][0], m[3][1], m[3][2])); T const m10 = determinant(mat<3, 3, T, Q>(m[0][1], m[0][2], m[0][3], m[2][1], m[2][2], m[2][3], m[3][1], m[3][2], m[3][3])); T const m11 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][2], m[0][3], m[2][0], m[2][2], m[2][3], m[3][0], m[3][2], m[3][3])); T const m12 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][3], m[2][0], m[2][1], m[2][3], m[3][0], m[3][1], m[3][3])); T const m13 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][2], m[2][0], m[2][1], m[2][2], m[3][0], m[3][1], m[3][2])); T const m20 = determinant(mat<3, 3, T, Q>(m[0][1], m[0][2], m[0][3], m[1][1], m[1][2], m[1][3], m[3][1], m[3][2], m[3][3])); T const m21 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][2], m[0][3], m[1][0], m[1][2], m[1][3], m[3][0], m[3][2], m[3][3])); T const m22 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][3], m[1][0], m[1][1], m[1][3], m[3][0], m[3][1], m[3][3])); T const m23 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2], m[3][0], m[3][1], m[3][2])); T const m30 = determinant(mat<3, 3, T, Q>(m[0][1], m[0][2], m[0][3], m[1][1], m[1][2], m[1][3], m[2][1], m[2][2], m[2][3])); T const m31 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][2], m[0][3], m[1][0], m[1][2], m[1][3], m[2][0], m[2][2], m[2][3])); T const m32 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][3], m[1][0], m[1][1], m[1][3], m[2][0], m[2][1], m[2][3])); T const m33 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2], m[2][0], m[2][1], m[2][2])); return mat<4, 4, T, Q>( +m00, -m01, +m02, -m03, -m10, +m11, -m12, +m13, +m20, -m21, +m22, -m23, -m30, +m31, -m32, +m33); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/matrix_query.hpp000066400000000000000000000054051360521144700243650ustar00rootroot00000000000000/// @ref gtx_matrix_query /// @file glm/gtx/matrix_query.hpp /// /// @see core (dependence) /// @see gtx_vector_query (dependence) /// /// @defgroup gtx_matrix_query GLM_GTX_matrix_query /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Query to evaluate matrix properties #pragma once // Dependency: #include "../glm.hpp" #include "../gtx/vector_query.hpp" #include #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_matrix_query is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_matrix_query extension included") # endif #endif namespace glm { /// @addtogroup gtx_matrix_query /// @{ /// Return whether a matrix a null matrix. /// From GLM_GTX_matrix_query extension. template GLM_FUNC_DECL bool isNull(mat<2, 2, T, Q> const& m, T const& epsilon); /// Return whether a matrix a null matrix. /// From GLM_GTX_matrix_query extension. template GLM_FUNC_DECL bool isNull(mat<3, 3, T, Q> const& m, T const& epsilon); /// Return whether a matrix is a null matrix. /// From GLM_GTX_matrix_query extension. template GLM_FUNC_DECL bool isNull(mat<4, 4, T, Q> const& m, T const& epsilon); /// Return whether a matrix is an identity matrix. /// From GLM_GTX_matrix_query extension. template class matType> GLM_FUNC_DECL bool isIdentity(matType const& m, T const& epsilon); /// Return whether a matrix is a normalized matrix. /// From GLM_GTX_matrix_query extension. template GLM_FUNC_DECL bool isNormalized(mat<2, 2, T, Q> const& m, T const& epsilon); /// Return whether a matrix is a normalized matrix. /// From GLM_GTX_matrix_query extension. template GLM_FUNC_DECL bool isNormalized(mat<3, 3, T, Q> const& m, T const& epsilon); /// Return whether a matrix is a normalized matrix. /// From GLM_GTX_matrix_query extension. template GLM_FUNC_DECL bool isNormalized(mat<4, 4, T, Q> const& m, T const& epsilon); /// Return whether a matrix is an orthonormalized matrix. /// From GLM_GTX_matrix_query extension. template class matType> GLM_FUNC_DECL bool isOrthogonal(matType const& m, T const& epsilon); /// @} }//namespace glm #include "matrix_query.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/matrix_query.inl000066400000000000000000000064301360521144700243570ustar00rootroot00000000000000/// @ref gtx_matrix_query namespace glm { template GLM_FUNC_QUALIFIER bool isNull(mat<2, 2, T, Q> const& m, T const& epsilon) { bool result = true; for(length_t i = 0; result && i < m.length() ; ++i) result = isNull(m[i], epsilon); return result; } template GLM_FUNC_QUALIFIER bool isNull(mat<3, 3, T, Q> const& m, T const& epsilon) { bool result = true; for(length_t i = 0; result && i < m.length() ; ++i) result = isNull(m[i], epsilon); return result; } template GLM_FUNC_QUALIFIER bool isNull(mat<4, 4, T, Q> const& m, T const& epsilon) { bool result = true; for(length_t i = 0; result && i < m.length() ; ++i) result = isNull(m[i], epsilon); return result; } template GLM_FUNC_QUALIFIER bool isIdentity(mat const& m, T const& epsilon) { bool result = true; for(length_t i = 0; result && i < m[0].length() ; ++i) { for(length_t j = 0; result && j < i ; ++j) result = abs(m[i][j]) <= epsilon; if(result) result = abs(m[i][i] - 1) <= epsilon; for(length_t j = i + 1; result && j < m.length(); ++j) result = abs(m[i][j]) <= epsilon; } return result; } template GLM_FUNC_QUALIFIER bool isNormalized(mat<2, 2, T, Q> const& m, T const& epsilon) { bool result(true); for(length_t i = 0; result && i < m.length(); ++i) result = isNormalized(m[i], epsilon); for(length_t i = 0; result && i < m.length(); ++i) { typename mat<2, 2, T, Q>::col_type v; for(length_t j = 0; j < m.length(); ++j) v[j] = m[j][i]; result = isNormalized(v, epsilon); } return result; } template GLM_FUNC_QUALIFIER bool isNormalized(mat<3, 3, T, Q> const& m, T const& epsilon) { bool result(true); for(length_t i = 0; result && i < m.length(); ++i) result = isNormalized(m[i], epsilon); for(length_t i = 0; result && i < m.length(); ++i) { typename mat<3, 3, T, Q>::col_type v; for(length_t j = 0; j < m.length(); ++j) v[j] = m[j][i]; result = isNormalized(v, epsilon); } return result; } template GLM_FUNC_QUALIFIER bool isNormalized(mat<4, 4, T, Q> const& m, T const& epsilon) { bool result(true); for(length_t i = 0; result && i < m.length(); ++i) result = isNormalized(m[i], epsilon); for(length_t i = 0; result && i < m.length(); ++i) { typename mat<4, 4, T, Q>::col_type v; for(length_t j = 0; j < m.length(); ++j) v[j] = m[j][i]; result = isNormalized(v, epsilon); } return result; } template GLM_FUNC_QUALIFIER bool isOrthogonal(mat const& m, T const& epsilon) { bool result = true; for(length_t i(0); result && i < m.length() - 1; ++i) for(length_t j(i + 1); result && j < m.length(); ++j) result = areOrthogonal(m[i], m[j], epsilon); if(result) { mat tmp = transpose(m); for(length_t i(0); result && i < m.length() - 1 ; ++i) for(length_t j(i + 1); result && j < m.length(); ++j) result = areOrthogonal(tmp[i], tmp[j], epsilon); } return result; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/matrix_transform_2d.hpp000066400000000000000000000050611360521144700256160ustar00rootroot00000000000000/// @ref gtx_matrix_transform_2d /// @file glm/gtx/matrix_transform_2d.hpp /// @author Miguel Ángel Pérez Martínez /// /// @see core (dependence) /// /// @defgroup gtx_matrix_transform_2d GLM_GTX_matrix_transform_2d /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Defines functions that generate common 2d transformation matrices. #pragma once // Dependency: #include "../mat3x3.hpp" #include "../vec2.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_matrix_transform_2d is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_matrix_transform_2d extension included") # endif #endif namespace glm { /// @addtogroup gtx_matrix_transform_2d /// @{ /// Builds a translation 3 * 3 matrix created from a vector of 2 components. /// /// @param m Input matrix multiplied by this translation matrix. /// @param v Coordinates of a translation vector. template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> translate( mat<3, 3, T, Q> const& m, vec<2, T, Q> const& v); /// Builds a rotation 3 * 3 matrix created from an angle. /// /// @param m Input matrix multiplied by this translation matrix. /// @param angle Rotation angle expressed in radians. template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> rotate( mat<3, 3, T, Q> const& m, T angle); /// Builds a scale 3 * 3 matrix created from a vector of 2 components. /// /// @param m Input matrix multiplied by this translation matrix. /// @param v Coordinates of a scale vector. template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> scale( mat<3, 3, T, Q> const& m, vec<2, T, Q> const& v); /// Builds an horizontal (parallel to the x axis) shear 3 * 3 matrix. /// /// @param m Input matrix multiplied by this translation matrix. /// @param y Shear factor. template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearX( mat<3, 3, T, Q> const& m, T y); /// Builds a vertical (parallel to the y axis) shear 3 * 3 matrix. /// /// @param m Input matrix multiplied by this translation matrix. /// @param x Shear factor. template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearY( mat<3, 3, T, Q> const& m, T x); /// @} }//namespace glm #include "matrix_transform_2d.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/matrix_transform_2d.inl000066400000000000000000000026031360521144700256100ustar00rootroot00000000000000/// @ref gtx_matrix_transform_2d /// @author Miguel Ángel Pérez Martínez #include "../trigonometric.hpp" namespace glm { template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> translate( mat<3, 3, T, Q> const& m, vec<2, T, Q> const& v) { mat<3, 3, T, Q> Result(m); Result[2] = m[0] * v[0] + m[1] * v[1] + m[2]; return Result; } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> rotate( mat<3, 3, T, Q> const& m, T angle) { T const a = angle; T const c = cos(a); T const s = sin(a); mat<3, 3, T, Q> Result; Result[0] = m[0] * c + m[1] * s; Result[1] = m[0] * -s + m[1] * c; Result[2] = m[2]; return Result; } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> scale( mat<3, 3, T, Q> const& m, vec<2, T, Q> const& v) { mat<3, 3, T, Q> Result; Result[0] = m[0] * v[0]; Result[1] = m[1] * v[1]; Result[2] = m[2]; return Result; } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearX( mat<3, 3, T, Q> const& m, T y) { mat<3, 3, T, Q> Result(1); Result[0][1] = y; return m * Result; } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearY( mat<3, 3, T, Q> const& m, T x) { mat<3, 3, T, Q> Result(1); Result[1][0] = x; return m * Result; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/mixed_product.hpp000066400000000000000000000021151360521144700244750ustar00rootroot00000000000000/// @ref gtx_mixed_product /// @file glm/gtx/mixed_product.hpp /// /// @see core (dependence) /// /// @defgroup gtx_mixed_product GLM_GTX_mixed_producte /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Mixed product of 3 vectors. #pragma once // Dependency: #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_mixed_product is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_mixed_product extension included") # endif #endif namespace glm { /// @addtogroup gtx_mixed_product /// @{ /// @brief Mixed product of 3 vectors (from GLM_GTX_mixed_product extension) template GLM_FUNC_DECL T mixedProduct( vec<3, T, Q> const& v1, vec<3, T, Q> const& v2, vec<3, T, Q> const& v3); /// @} }// namespace glm #include "mixed_product.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/mixed_product.inl000066400000000000000000000004141360521144700244700ustar00rootroot00000000000000/// @ref gtx_mixed_product namespace glm { template GLM_FUNC_QUALIFIER T mixedProduct ( vec<3, T, Q> const& v1, vec<3, T, Q> const& v2, vec<3, T, Q> const& v3 ) { return dot(cross(v1, v2), v3); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/norm.hpp000066400000000000000000000053371360521144700226130ustar00rootroot00000000000000/// @ref gtx_norm /// @file glm/gtx/norm.hpp /// /// @see core (dependence) /// @see gtx_quaternion (dependence) /// @see gtx_component_wise (dependence) /// /// @defgroup gtx_norm GLM_GTX_norm /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Various ways to compute vector norms. #pragma once // Dependency: #include "../geometric.hpp" #include "../gtx/quaternion.hpp" #include "../gtx/component_wise.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_norm is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_norm extension included") # endif #endif namespace glm { /// @addtogroup gtx_norm /// @{ /// Returns the squared length of x. /// From GLM_GTX_norm extension. template GLM_FUNC_DECL T length2(vec const& x); /// Returns the squared distance between p0 and p1, i.e., length2(p0 - p1). /// From GLM_GTX_norm extension. template GLM_FUNC_DECL T distance2(vec const& p0, vec const& p1); //! Returns the L1 norm between x and y. //! From GLM_GTX_norm extension. template GLM_FUNC_DECL T l1Norm(vec<3, T, Q> const& x, vec<3, T, Q> const& y); //! Returns the L1 norm of v. //! From GLM_GTX_norm extension. template GLM_FUNC_DECL T l1Norm(vec<3, T, Q> const& v); //! Returns the L2 norm between x and y. //! From GLM_GTX_norm extension. template GLM_FUNC_DECL T l2Norm(vec<3, T, Q> const& x, vec<3, T, Q> const& y); //! Returns the L2 norm of v. //! From GLM_GTX_norm extension. template GLM_FUNC_DECL T l2Norm(vec<3, T, Q> const& x); //! Returns the L norm between x and y. //! From GLM_GTX_norm extension. template GLM_FUNC_DECL T lxNorm(vec<3, T, Q> const& x, vec<3, T, Q> const& y, unsigned int Depth); //! Returns the L norm of v. //! From GLM_GTX_norm extension. template GLM_FUNC_DECL T lxNorm(vec<3, T, Q> const& x, unsigned int Depth); //! Returns the LMax norm between x and y. //! From GLM_GTX_norm extension. template GLM_FUNC_DECL T lMaxNorm(vec<3, T, Q> const& x, vec<3, T, Q> const& y); //! Returns the LMax norm of v. //! From GLM_GTX_norm extension. template GLM_FUNC_DECL T lMaxNorm(vec<3, T, Q> const& x); /// @} }//namespace glm #include "norm.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/norm.inl000066400000000000000000000052131360521144700225770ustar00rootroot00000000000000/// @ref gtx_norm #include "../detail/qualifier.hpp" namespace glm{ namespace detail { template struct compute_length2 { GLM_FUNC_QUALIFIER static T call(vec const& v) { return dot(v, v); } }; }//namespace detail template GLM_FUNC_QUALIFIER genType length2(genType x) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'length2' accepts only floating-point inputs"); return x * x; } template GLM_FUNC_QUALIFIER T length2(vec const& v) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'length2' accepts only floating-point inputs"); return detail::compute_length2::value>::call(v); } template GLM_FUNC_QUALIFIER T distance2(T p0, T p1) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'distance2' accepts only floating-point inputs"); return length2(p1 - p0); } template GLM_FUNC_QUALIFIER T distance2(vec const& p0, vec const& p1) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'distance2' accepts only floating-point inputs"); return length2(p1 - p0); } template GLM_FUNC_QUALIFIER T l1Norm(vec<3, T, Q> const& a, vec<3, T, Q> const& b) { return abs(b.x - a.x) + abs(b.y - a.y) + abs(b.z - a.z); } template GLM_FUNC_QUALIFIER T l1Norm(vec<3, T, Q> const& v) { return abs(v.x) + abs(v.y) + abs(v.z); } template GLM_FUNC_QUALIFIER T l2Norm(vec<3, T, Q> const& a, vec<3, T, Q> const& b ) { return length(b - a); } template GLM_FUNC_QUALIFIER T l2Norm(vec<3, T, Q> const& v) { return length(v); } template GLM_FUNC_QUALIFIER T lxNorm(vec<3, T, Q> const& x, vec<3, T, Q> const& y, unsigned int Depth) { return pow(pow(abs(y.x - x.x), T(Depth)) + pow(abs(y.y - x.y), T(Depth)) + pow(abs(y.z - x.z), T(Depth)), T(1) / T(Depth)); } template GLM_FUNC_QUALIFIER T lxNorm(vec<3, T, Q> const& v, unsigned int Depth) { return pow(pow(abs(v.x), T(Depth)) + pow(abs(v.y), T(Depth)) + pow(abs(v.z), T(Depth)), T(1) / T(Depth)); } template GLM_FUNC_QUALIFIER T lMaxNorm(vec<3, T, Q> const& a, vec<3, T, Q> const& b) { return compMax(abs(b - a)); } template GLM_FUNC_QUALIFIER T lMaxNorm(vec<3, T, Q> const& v) { return compMax(abs(v)); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/normal.hpp000066400000000000000000000021031360521144700231140ustar00rootroot00000000000000/// @ref gtx_normal /// @file glm/gtx/normal.hpp /// /// @see core (dependence) /// @see gtx_extented_min_max (dependence) /// /// @defgroup gtx_normal GLM_GTX_normal /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Compute the normal of a triangle. #pragma once // Dependency: #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_normal is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_normal extension included") # endif #endif namespace glm { /// @addtogroup gtx_normal /// @{ /// Computes triangle normal from triangle points. /// /// @see gtx_normal template GLM_FUNC_DECL vec<3, T, Q> triangleNormal(vec<3, T, Q> const& p1, vec<3, T, Q> const& p2, vec<3, T, Q> const& p3); /// @} }//namespace glm #include "normal.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/normal.inl000066400000000000000000000004361360521144700231160ustar00rootroot00000000000000/// @ref gtx_normal namespace glm { template GLM_FUNC_QUALIFIER vec<3, T, Q> triangleNormal ( vec<3, T, Q> const& p1, vec<3, T, Q> const& p2, vec<3, T, Q> const& p3 ) { return normalize(cross(p1 - p2, p1 - p3)); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/normalize_dot.hpp000066400000000000000000000030531360521144700244770ustar00rootroot00000000000000/// @ref gtx_normalize_dot /// @file glm/gtx/normalize_dot.hpp /// /// @see core (dependence) /// @see gtx_fast_square_root (dependence) /// /// @defgroup gtx_normalize_dot GLM_GTX_normalize_dot /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Dot product of vectors that need to be normalize with a single square root. #pragma once // Dependency: #include "../gtx/fast_square_root.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_normalize_dot is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_normalize_dot extension included") # endif #endif namespace glm { /// @addtogroup gtx_normalize_dot /// @{ /// Normalize parameters and returns the dot product of x and y. /// It's faster that dot(normalize(x), normalize(y)). /// /// @see gtx_normalize_dot extension. template GLM_FUNC_DECL T normalizeDot(vec const& x, vec const& y); /// Normalize parameters and returns the dot product of x and y. /// Faster that dot(fastNormalize(x), fastNormalize(y)). /// /// @see gtx_normalize_dot extension. template GLM_FUNC_DECL T fastNormalizeDot(vec const& x, vec const& y); /// @} }//namespace glm #include "normalize_dot.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/normalize_dot.inl000066400000000000000000000007741360521144700245010ustar00rootroot00000000000000/// @ref gtx_normalize_dot namespace glm { template GLM_FUNC_QUALIFIER T normalizeDot(vec const& x, vec const& y) { return glm::dot(x, y) * glm::inversesqrt(glm::dot(x, x) * glm::dot(y, y)); } template GLM_FUNC_QUALIFIER T fastNormalizeDot(vec const& x, vec const& y) { return glm::dot(x, y) * glm::fastInverseSqrt(glm::dot(x, x) * glm::dot(y, y)); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/number_precision.hpp000066400000000000000000000045171360521144700252020ustar00rootroot00000000000000/// @ref gtx_number_precision /// @file glm/gtx/number_precision.hpp /// /// @see core (dependence) /// @see gtc_type_precision (dependence) /// @see gtc_quaternion (dependence) /// /// @defgroup gtx_number_precision GLM_GTX_number_precision /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Defined size types. #pragma once // Dependency: #include "../glm.hpp" #include "../gtc/type_precision.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_number_precision is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_number_precision extension included") # endif #endif namespace glm{ namespace gtx { ///////////////////////////// // Unsigned int vector types /// @addtogroup gtx_number_precision /// @{ typedef u8 u8vec1; //!< \brief 8bit unsigned integer scalar. (from GLM_GTX_number_precision extension) typedef u16 u16vec1; //!< \brief 16bit unsigned integer scalar. (from GLM_GTX_number_precision extension) typedef u32 u32vec1; //!< \brief 32bit unsigned integer scalar. (from GLM_GTX_number_precision extension) typedef u64 u64vec1; //!< \brief 64bit unsigned integer scalar. (from GLM_GTX_number_precision extension) ////////////////////// // Float vector types typedef f32 f32vec1; //!< \brief Single-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) typedef f64 f64vec1; //!< \brief Single-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) ////////////////////// // Float matrix types typedef f32 f32mat1; //!< \brief Single-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) typedef f32 f32mat1x1; //!< \brief Single-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) typedef f64 f64mat1; //!< \brief Double-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) typedef f64 f64mat1x1; //!< \brief Double-qualifier floating-point scalar. (from GLM_GTX_number_precision extension) /// @} }//namespace gtx }//namespace glm #include "number_precision.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/number_precision.inl000066400000000000000000000000701360521144700251630ustar00rootroot00000000000000/// @ref gtx_number_precision namespace glm { } connectome-workbench-1.4.2/src/GLMath/glm/gtx/optimum_pow.hpp000066400000000000000000000025211360521144700242070ustar00rootroot00000000000000/// @ref gtx_optimum_pow /// @file glm/gtx/optimum_pow.hpp /// /// @see core (dependence) /// /// @defgroup gtx_optimum_pow GLM_GTX_optimum_pow /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Integer exponentiation of power functions. #pragma once // Dependency: #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_optimum_pow is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_optimum_pow extension included") # endif #endif namespace glm{ namespace gtx { /// @addtogroup gtx_optimum_pow /// @{ /// Returns x raised to the power of 2. /// /// @see gtx_optimum_pow template GLM_FUNC_DECL genType pow2(genType const& x); /// Returns x raised to the power of 3. /// /// @see gtx_optimum_pow template GLM_FUNC_DECL genType pow3(genType const& x); /// Returns x raised to the power of 4. /// /// @see gtx_optimum_pow template GLM_FUNC_DECL genType pow4(genType const& x); /// @} }//namespace gtx }//namespace glm #include "optimum_pow.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/optimum_pow.inl000066400000000000000000000006221360521144700242020ustar00rootroot00000000000000/// @ref gtx_optimum_pow namespace glm { template GLM_FUNC_QUALIFIER genType pow2(genType const& x) { return x * x; } template GLM_FUNC_QUALIFIER genType pow3(genType const& x) { return x * x * x; } template GLM_FUNC_QUALIFIER genType pow4(genType const& x) { return (x * x) * (x * x); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/orthonormalize.hpp000066400000000000000000000025331360521144700247070ustar00rootroot00000000000000/// @ref gtx_orthonormalize /// @file glm/gtx/orthonormalize.hpp /// /// @see core (dependence) /// @see gtx_extented_min_max (dependence) /// /// @defgroup gtx_orthonormalize GLM_GTX_orthonormalize /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Orthonormalize matrices. #pragma once // Dependency: #include "../vec3.hpp" #include "../mat3x3.hpp" #include "../geometric.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_orthonormalize is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_orthonormalize extension included") # endif #endif namespace glm { /// @addtogroup gtx_orthonormalize /// @{ /// Returns the orthonormalized matrix of m. /// /// @see gtx_orthonormalize template GLM_FUNC_DECL mat<3, 3, T, Q> orthonormalize(mat<3, 3, T, Q> const& m); /// Orthonormalizes x according y. /// /// @see gtx_orthonormalize template GLM_FUNC_DECL vec<3, T, Q> orthonormalize(vec<3, T, Q> const& x, vec<3, T, Q> const& y); /// @} }//namespace glm #include "orthonormalize.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/orthonormalize.inl000066400000000000000000000011711360521144700246770ustar00rootroot00000000000000/// @ref gtx_orthonormalize namespace glm { template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> orthonormalize(mat<3, 3, T, Q> const& m) { mat<3, 3, T, Q> r = m; r[0] = normalize(r[0]); T d0 = dot(r[0], r[1]); r[1] -= r[0] * d0; r[1] = normalize(r[1]); T d1 = dot(r[1], r[2]); d0 = dot(r[0], r[2]); r[2] -= r[0] * d0 + r[1] * d1; r[2] = normalize(r[2]); return r; } template GLM_FUNC_QUALIFIER vec<3, T, Q> orthonormalize(vec<3, T, Q> const& x, vec<3, T, Q> const& y) { return normalize(x - y * dot(y, x)); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/perpendicular.hpp000066400000000000000000000021741360521144700244710ustar00rootroot00000000000000/// @ref gtx_perpendicular /// @file glm/gtx/perpendicular.hpp /// /// @see core (dependence) /// @see gtx_projection (dependence) /// /// @defgroup gtx_perpendicular GLM_GTX_perpendicular /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Perpendicular of a vector from other one #pragma once // Dependency: #include "../glm.hpp" #include "../gtx/projection.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_perpendicular is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_perpendicular extension included") # endif #endif namespace glm { /// @addtogroup gtx_perpendicular /// @{ //! Projects x a perpendicular axis of Normal. //! From GLM_GTX_perpendicular extension. template GLM_FUNC_DECL genType perp(genType const& x, genType const& Normal); /// @} }//namespace glm #include "perpendicular.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/perpendicular.inl000066400000000000000000000003211360521144700244540ustar00rootroot00000000000000/// @ref gtx_perpendicular namespace glm { template GLM_FUNC_QUALIFIER genType perp(genType const& x, genType const& Normal) { return x - proj(x, Normal); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/polar_coordinates.hpp000066400000000000000000000025461360521144700253460ustar00rootroot00000000000000/// @ref gtx_polar_coordinates /// @file glm/gtx/polar_coordinates.hpp /// /// @see core (dependence) /// /// @defgroup gtx_polar_coordinates GLM_GTX_polar_coordinates /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Conversion from Euclidean space to polar space and revert. #pragma once // Dependency: #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_polar_coordinates is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_polar_coordinates extension included") # endif #endif namespace glm { /// @addtogroup gtx_polar_coordinates /// @{ /// Convert Euclidean to Polar coordinates, x is the xz distance, y, the latitude and z the longitude. /// /// @see gtx_polar_coordinates template GLM_FUNC_DECL vec<3, T, Q> polar( vec<3, T, Q> const& euclidean); /// Convert Polar to Euclidean coordinates. /// /// @see gtx_polar_coordinates template GLM_FUNC_DECL vec<3, T, Q> euclidean( vec<2, T, Q> const& polar); /// @} }//namespace glm #include "polar_coordinates.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/polar_coordinates.inl000066400000000000000000000014021360521144700253270ustar00rootroot00000000000000/// @ref gtx_polar_coordinates namespace glm { template GLM_FUNC_QUALIFIER vec<3, T, Q> polar ( vec<3, T, Q> const& euclidean ) { T const Length(length(euclidean)); vec<3, T, Q> const tmp(euclidean / Length); T const xz_dist(sqrt(tmp.x * tmp.x + tmp.z * tmp.z)); return vec<3, T, Q>( asin(tmp.y), // latitude atan(tmp.x, tmp.z), // longitude xz_dist); // xz distance } template GLM_FUNC_QUALIFIER vec<3, T, Q> euclidean ( vec<2, T, Q> const& polar ) { T const latitude(polar.x); T const longitude(polar.y); return vec<3, T, Q>( cos(latitude) * sin(longitude), sin(latitude), cos(latitude) * cos(longitude)); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/projection.hpp000066400000000000000000000021571360521144700240110ustar00rootroot00000000000000/// @ref gtx_projection /// @file glm/gtx/projection.hpp /// /// @see core (dependence) /// /// @defgroup gtx_projection GLM_GTX_projection /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Projection of a vector to other one #pragma once // Dependency: #include "../geometric.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_projection is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_projection extension included") # endif #endif namespace glm { /// @addtogroup gtx_projection /// @{ /// Projects x on Normal. /// /// @param[in] x A vector to project /// @param[in] Normal A normal that doesn't need to be of unit length. /// /// @see gtx_projection template GLM_FUNC_DECL genType proj(genType const& x, genType const& Normal); /// @} }//namespace glm #include "projection.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/projection.inl000066400000000000000000000003621360521144700240000ustar00rootroot00000000000000/// @ref gtx_projection namespace glm { template GLM_FUNC_QUALIFIER genType proj(genType const& x, genType const& Normal) { return glm::dot(x, Normal) / glm::dot(Normal, Normal) * Normal; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/quaternion.hpp000066400000000000000000000111631360521144700240170ustar00rootroot00000000000000/// @ref gtx_quaternion /// @file glm/gtx/quaternion.hpp /// /// @see core (dependence) /// @see gtx_extented_min_max (dependence) /// /// @defgroup gtx_quaternion GLM_GTX_quaternion /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Extented quaternion types and functions #pragma once // Dependency: #include "../glm.hpp" #include "../gtc/constants.hpp" #include "../gtc/quaternion.hpp" #include "../ext/quaternion_exponential.hpp" #include "../gtx/norm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_quaternion is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_quaternion extension included") # endif #endif namespace glm { /// @addtogroup gtx_quaternion /// @{ /// Create an identity quaternion. /// /// @see gtx_quaternion template GLM_FUNC_DECL qua quat_identity(); /// Compute a cross product between a quaternion and a vector. /// /// @see gtx_quaternion template GLM_FUNC_DECL vec<3, T, Q> cross( qua const& q, vec<3, T, Q> const& v); //! Compute a cross product between a vector and a quaternion. /// /// @see gtx_quaternion template GLM_FUNC_DECL vec<3, T, Q> cross( vec<3, T, Q> const& v, qua const& q); //! Compute a point on a path according squad equation. //! q1 and q2 are control points; s1 and s2 are intermediate control points. /// /// @see gtx_quaternion template GLM_FUNC_DECL qua squad( qua const& q1, qua const& q2, qua const& s1, qua const& s2, T const& h); //! Returns an intermediate control point for squad interpolation. /// /// @see gtx_quaternion template GLM_FUNC_DECL qua intermediate( qua const& prev, qua const& curr, qua const& next); //! Returns quarternion square root. /// /// @see gtx_quaternion //template //qua sqrt( // qua const& q); //! Rotates a 3 components vector by a quaternion. /// /// @see gtx_quaternion template GLM_FUNC_DECL vec<3, T, Q> rotate( qua const& q, vec<3, T, Q> const& v); /// Rotates a 4 components vector by a quaternion. /// /// @see gtx_quaternion template GLM_FUNC_DECL vec<4, T, Q> rotate( qua const& q, vec<4, T, Q> const& v); /// Extract the real component of a quaternion. /// /// @see gtx_quaternion template GLM_FUNC_DECL T extractRealComponent( qua const& q); /// Converts a quaternion to a 3 * 3 matrix. /// /// @see gtx_quaternion template GLM_FUNC_DECL mat<3, 3, T, Q> toMat3( qua const& x){return mat3_cast(x);} /// Converts a quaternion to a 4 * 4 matrix. /// /// @see gtx_quaternion template GLM_FUNC_DECL mat<4, 4, T, Q> toMat4( qua const& x){return mat4_cast(x);} /// Converts a 3 * 3 matrix to a quaternion. /// /// @see gtx_quaternion template GLM_FUNC_DECL qua toQuat( mat<3, 3, T, Q> const& x){return quat_cast(x);} /// Converts a 4 * 4 matrix to a quaternion. /// /// @see gtx_quaternion template GLM_FUNC_DECL qua toQuat( mat<4, 4, T, Q> const& x){return quat_cast(x);} /// Quaternion interpolation using the rotation short path. /// /// @see gtx_quaternion template GLM_FUNC_DECL qua shortMix( qua const& x, qua const& y, T const& a); /// Quaternion normalized linear interpolation. /// /// @see gtx_quaternion template GLM_FUNC_DECL qua fastMix( qua const& x, qua const& y, T const& a); /// Compute the rotation between two vectors. /// @param orig vector, needs to be normalized /// @param dest vector, needs to be normalized /// /// @see gtx_quaternion template GLM_FUNC_DECL qua rotation( vec<3, T, Q> const& orig, vec<3, T, Q> const& dest); /// Returns the squared length of x. /// /// @see gtx_quaternion template GLM_FUNC_DECL T length2(qua const& q); /// @} }//namespace glm #include "quaternion.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/quaternion.inl000066400000000000000000000103641360521144700240140ustar00rootroot00000000000000/// @ref gtx_quaternion #include #include "../gtc/constants.hpp" namespace glm { template GLM_FUNC_QUALIFIER qua quat_identity() { return qua(static_cast(1), static_cast(0), static_cast(0), static_cast(0)); } template GLM_FUNC_QUALIFIER vec<3, T, Q> cross(vec<3, T, Q> const& v, qua const& q) { return inverse(q) * v; } template GLM_FUNC_QUALIFIER vec<3, T, Q> cross(qua const& q, vec<3, T, Q> const& v) { return q * v; } template GLM_FUNC_QUALIFIER qua squad ( qua const& q1, qua const& q2, qua const& s1, qua const& s2, T const& h) { return mix(mix(q1, q2, h), mix(s1, s2, h), static_cast(2) * (static_cast(1) - h) * h); } template GLM_FUNC_QUALIFIER qua intermediate ( qua const& prev, qua const& curr, qua const& next ) { qua invQuat = inverse(curr); return exp((log(next * invQuat) + log(prev * invQuat)) / static_cast(-4)) * curr; } template GLM_FUNC_QUALIFIER vec<3, T, Q> rotate(qua const& q, vec<3, T, Q> const& v) { return q * v; } template GLM_FUNC_QUALIFIER vec<4, T, Q> rotate(qua const& q, vec<4, T, Q> const& v) { return q * v; } template GLM_FUNC_QUALIFIER T extractRealComponent(qua const& q) { T w = static_cast(1) - q.x * q.x - q.y * q.y - q.z * q.z; if(w < T(0)) return T(0); else return -sqrt(w); } template GLM_FUNC_QUALIFIER T length2(qua const& q) { return q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w; } template GLM_FUNC_QUALIFIER qua shortMix(qua const& x, qua const& y, T const& a) { if(a <= static_cast(0)) return x; if(a >= static_cast(1)) return y; T fCos = dot(x, y); qua y2(y); //BUG!!! qua y2; if(fCos < static_cast(0)) { y2 = -y; fCos = -fCos; } //if(fCos > 1.0f) // problem T k0, k1; if(fCos > (static_cast(1) - epsilon())) { k0 = static_cast(1) - a; k1 = static_cast(0) + a; //BUG!!! 1.0f + a; } else { T fSin = sqrt(T(1) - fCos * fCos); T fAngle = atan(fSin, fCos); T fOneOverSin = static_cast(1) / fSin; k0 = sin((static_cast(1) - a) * fAngle) * fOneOverSin; k1 = sin((static_cast(0) + a) * fAngle) * fOneOverSin; } return qua( k0 * x.w + k1 * y2.w, k0 * x.x + k1 * y2.x, k0 * x.y + k1 * y2.y, k0 * x.z + k1 * y2.z); } template GLM_FUNC_QUALIFIER qua fastMix(qua const& x, qua const& y, T const& a) { return glm::normalize(x * (static_cast(1) - a) + (y * a)); } template GLM_FUNC_QUALIFIER qua rotation(vec<3, T, Q> const& orig, vec<3, T, Q> const& dest) { T cosTheta = dot(orig, dest); vec<3, T, Q> rotationAxis; if(cosTheta >= static_cast(1) - epsilon()) { // orig and dest point in the same direction return quat_identity(); } if(cosTheta < static_cast(-1) + epsilon()) { // special case when vectors in opposite directions : // there is no "ideal" rotation axis // So guess one; any will do as long as it's perpendicular to start // This implementation favors a rotation around the Up axis (Y), // since it's often what you want to do. rotationAxis = cross(vec<3, T, Q>(0, 0, 1), orig); if(length2(rotationAxis) < epsilon()) // bad luck, they were parallel, try again! rotationAxis = cross(vec<3, T, Q>(1, 0, 0), orig); rotationAxis = normalize(rotationAxis); return angleAxis(pi(), rotationAxis); } // Implementation from Stan Melax's Game Programming Gems 1 article rotationAxis = cross(orig, dest); T s = sqrt((T(1) + cosTheta) * static_cast(2)); T invs = static_cast(1) / s; return qua( s * static_cast(0.5f), rotationAxis.x * invs, rotationAxis.y * invs, rotationAxis.z * invs); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/range.hpp000066400000000000000000000044401360521144700227260ustar00rootroot00000000000000/// @ref gtx_range /// @file glm/gtx/range.hpp /// @author Joshua Moerman /// /// @defgroup gtx_range GLM_GTX_range /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Defines begin and end for vectors and matrices. Useful for range-based for loop. /// The range is defined over the elements, not over columns or rows (e.g. mat4 has 16 elements). #pragma once // Dependencies #include "../detail/setup.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_range is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_range extension included") # endif #endif #include "../gtc/type_ptr.hpp" #include "../gtc/vec1.hpp" namespace glm { /// @addtogroup gtx_range /// @{ # if GLM_COMPILER & GLM_COMPILER_VC # pragma warning(push) # pragma warning(disable : 4100) // unreferenced formal parameter # endif template inline length_t components(vec<1, T, Q> const& v) { return v.length(); } template inline length_t components(vec<2, T, Q> const& v) { return v.length(); } template inline length_t components(vec<3, T, Q> const& v) { return v.length(); } template inline length_t components(vec<4, T, Q> const& v) { return v.length(); } template inline length_t components(genType const& m) { return m.length() * m[0].length(); } template inline typename genType::value_type const * begin(genType const& v) { return value_ptr(v); } template inline typename genType::value_type const * end(genType const& v) { return begin(v) + components(v); } template inline typename genType::value_type * begin(genType& v) { return value_ptr(v); } template inline typename genType::value_type * end(genType& v) { return begin(v) + components(v); } # if GLM_COMPILER & GLM_COMPILER_VC # pragma warning(pop) # endif /// @} }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/raw_data.hpp000066400000000000000000000024161360521144700234150ustar00rootroot00000000000000/// @ref gtx_raw_data /// @file glm/gtx/raw_data.hpp /// /// @see core (dependence) /// /// @defgroup gtx_raw_data GLM_GTX_raw_data /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Projection of a vector to other one #pragma once // Dependencies #include "../ext/scalar_uint_sized.hpp" #include "../detail/setup.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_raw_data is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_raw_data extension included") # endif #endif namespace glm { /// @addtogroup gtx_raw_data /// @{ //! Type for byte numbers. //! From GLM_GTX_raw_data extension. typedef detail::uint8 byte; //! Type for word numbers. //! From GLM_GTX_raw_data extension. typedef detail::uint16 word; //! Type for dword numbers. //! From GLM_GTX_raw_data extension. typedef detail::uint32 dword; //! Type for qword numbers. //! From GLM_GTX_raw_data extension. typedef detail::uint64 qword; /// @} }// namespace glm #include "raw_data.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/raw_data.inl000066400000000000000000000000311360521144700233770ustar00rootroot00000000000000/// @ref gtx_raw_data connectome-workbench-1.4.2/src/GLMath/glm/gtx/rotate_normalized_axis.hpp000066400000000000000000000044001360521144700263740ustar00rootroot00000000000000/// @ref gtx_rotate_normalized_axis /// @file glm/gtx/rotate_normalized_axis.hpp /// /// @see core (dependence) /// @see gtc_matrix_transform /// @see gtc_quaternion /// /// @defgroup gtx_rotate_normalized_axis GLM_GTX_rotate_normalized_axis /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Quaternions and matrices rotations around normalized axis. #pragma once // Dependency: #include "../glm.hpp" #include "../gtc/epsilon.hpp" #include "../gtc/quaternion.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_rotate_normalized_axis is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_rotate_normalized_axis extension included") # endif #endif namespace glm { /// @addtogroup gtx_rotate_normalized_axis /// @{ /// Builds a rotation 4 * 4 matrix created from a normalized axis and an angle. /// /// @param m Input matrix multiplied by this rotation matrix. /// @param angle Rotation angle expressed in radians. /// @param axis Rotation axis, must be normalized. /// @tparam T Value type used to build the matrix. Currently supported: half (not recommended), float or double. /// /// @see gtx_rotate_normalized_axis /// @see - rotate(T angle, T x, T y, T z) /// @see - rotate(mat<4, 4, T, Q> const& m, T angle, T x, T y, T z) /// @see - rotate(T angle, vec<3, T, Q> const& v) template GLM_FUNC_DECL mat<4, 4, T, Q> rotateNormalizedAxis( mat<4, 4, T, Q> const& m, T const& angle, vec<3, T, Q> const& axis); /// Rotates a quaternion from a vector of 3 components normalized axis and an angle. /// /// @param q Source orientation /// @param angle Angle expressed in radians. /// @param axis Normalized axis of the rotation, must be normalized. /// /// @see gtx_rotate_normalized_axis template GLM_FUNC_DECL qua rotateNormalizedAxis( qua const& q, T const& angle, vec<3, T, Q> const& axis); /// @} }//namespace glm #include "rotate_normalized_axis.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/rotate_normalized_axis.inl000066400000000000000000000032561360521144700263770ustar00rootroot00000000000000/// @ref gtx_rotate_normalized_axis namespace glm { template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotateNormalizedAxis ( mat<4, 4, T, Q> const& m, T const& angle, vec<3, T, Q> const& v ) { T const a = angle; T const c = cos(a); T const s = sin(a); vec<3, T, Q> const axis(v); vec<3, T, Q> const temp((static_cast(1) - c) * axis); mat<4, 4, T, Q> Rotate; Rotate[0][0] = c + temp[0] * axis[0]; Rotate[0][1] = 0 + temp[0] * axis[1] + s * axis[2]; Rotate[0][2] = 0 + temp[0] * axis[2] - s * axis[1]; Rotate[1][0] = 0 + temp[1] * axis[0] - s * axis[2]; Rotate[1][1] = c + temp[1] * axis[1]; Rotate[1][2] = 0 + temp[1] * axis[2] + s * axis[0]; Rotate[2][0] = 0 + temp[2] * axis[0] + s * axis[1]; Rotate[2][1] = 0 + temp[2] * axis[1] - s * axis[0]; Rotate[2][2] = c + temp[2] * axis[2]; mat<4, 4, T, Q> Result; Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2]; Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2]; Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2]; Result[3] = m[3]; return Result; } template GLM_FUNC_QUALIFIER qua rotateNormalizedAxis ( qua const& q, T const& angle, vec<3, T, Q> const& v ) { vec<3, T, Q> const Tmp(v); T const AngleRad(angle); T const Sin = sin(AngleRad * T(0.5)); return q * qua(cos(AngleRad * static_cast(0.5)), Tmp.x * Sin, Tmp.y * Sin, Tmp.z * Sin); //return gtc::quaternion::cross(q, tquat(cos(AngleRad * T(0.5)), Tmp.x * fSin, Tmp.y * fSin, Tmp.z * fSin)); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/rotate_vector.hpp000066400000000000000000000072011360521144700245100ustar00rootroot00000000000000/// @ref gtx_rotate_vector /// @file glm/gtx/rotate_vector.hpp /// /// @see core (dependence) /// @see gtx_transform (dependence) /// /// @defgroup gtx_rotate_vector GLM_GTX_rotate_vector /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Function to directly rotate a vector #pragma once // Dependency: #include "../gtx/transform.hpp" #include "../gtc/epsilon.hpp" #include "../ext/vector_relational.hpp" #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_rotate_vector is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_rotate_vector extension included") # endif #endif namespace glm { /// @addtogroup gtx_rotate_vector /// @{ /// Returns Spherical interpolation between two vectors /// /// @param x A first vector /// @param y A second vector /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1]. /// /// @see gtx_rotate_vector template GLM_FUNC_DECL vec<3, T, Q> slerp( vec<3, T, Q> const& x, vec<3, T, Q> const& y, T const& a); //! Rotate a two dimensional vector. //! From GLM_GTX_rotate_vector extension. template GLM_FUNC_DECL vec<2, T, Q> rotate( vec<2, T, Q> const& v, T const& angle); //! Rotate a three dimensional vector around an axis. //! From GLM_GTX_rotate_vector extension. template GLM_FUNC_DECL vec<3, T, Q> rotate( vec<3, T, Q> const& v, T const& angle, vec<3, T, Q> const& normal); //! Rotate a four dimensional vector around an axis. //! From GLM_GTX_rotate_vector extension. template GLM_FUNC_DECL vec<4, T, Q> rotate( vec<4, T, Q> const& v, T const& angle, vec<3, T, Q> const& normal); //! Rotate a three dimensional vector around the X axis. //! From GLM_GTX_rotate_vector extension. template GLM_FUNC_DECL vec<3, T, Q> rotateX( vec<3, T, Q> const& v, T const& angle); //! Rotate a three dimensional vector around the Y axis. //! From GLM_GTX_rotate_vector extension. template GLM_FUNC_DECL vec<3, T, Q> rotateY( vec<3, T, Q> const& v, T const& angle); //! Rotate a three dimensional vector around the Z axis. //! From GLM_GTX_rotate_vector extension. template GLM_FUNC_DECL vec<3, T, Q> rotateZ( vec<3, T, Q> const& v, T const& angle); //! Rotate a four dimensional vector around the X axis. //! From GLM_GTX_rotate_vector extension. template GLM_FUNC_DECL vec<4, T, Q> rotateX( vec<4, T, Q> const& v, T const& angle); //! Rotate a four dimensional vector around the Y axis. //! From GLM_GTX_rotate_vector extension. template GLM_FUNC_DECL vec<4, T, Q> rotateY( vec<4, T, Q> const& v, T const& angle); //! Rotate a four dimensional vector around the Z axis. //! From GLM_GTX_rotate_vector extension. template GLM_FUNC_DECL vec<4, T, Q> rotateZ( vec<4, T, Q> const& v, T const& angle); //! Build a rotation matrix from a normal and a up vector. //! From GLM_GTX_rotate_vector extension. template GLM_FUNC_DECL mat<4, 4, T, Q> orientation( vec<3, T, Q> const& Normal, vec<3, T, Q> const& Up); /// @} }//namespace glm #include "rotate_vector.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/rotate_vector.inl000066400000000000000000000076641360521144700245200ustar00rootroot00000000000000/// @ref gtx_rotate_vector namespace glm { template GLM_FUNC_QUALIFIER vec<3, T, Q> slerp ( vec<3, T, Q> const& x, vec<3, T, Q> const& y, T const& a ) { // get cosine of angle between vectors (-1 -> 1) T CosAlpha = dot(x, y); // get angle (0 -> pi) T Alpha = acos(CosAlpha); // get sine of angle between vectors (0 -> 1) T SinAlpha = sin(Alpha); // this breaks down when SinAlpha = 0, i.e. Alpha = 0 or pi T t1 = sin((static_cast(1) - a) * Alpha) / SinAlpha; T t2 = sin(a * Alpha) / SinAlpha; // interpolate src vectors return x * t1 + y * t2; } template GLM_FUNC_QUALIFIER vec<2, T, Q> rotate ( vec<2, T, Q> const& v, T const& angle ) { vec<2, T, Q> Result; T const Cos(cos(angle)); T const Sin(sin(angle)); Result.x = v.x * Cos - v.y * Sin; Result.y = v.x * Sin + v.y * Cos; return Result; } template GLM_FUNC_QUALIFIER vec<3, T, Q> rotate ( vec<3, T, Q> const& v, T const& angle, vec<3, T, Q> const& normal ) { return mat<3, 3, T, Q>(glm::rotate(angle, normal)) * v; } /* template GLM_FUNC_QUALIFIER vec<3, T, Q> rotateGTX( const vec<3, T, Q>& x, T angle, const vec<3, T, Q>& normal) { const T Cos = cos(radians(angle)); const T Sin = sin(radians(angle)); return x * Cos + ((x * normal) * (T(1) - Cos)) * normal + cross(x, normal) * Sin; } */ template GLM_FUNC_QUALIFIER vec<4, T, Q> rotate ( vec<4, T, Q> const& v, T const& angle, vec<3, T, Q> const& normal ) { return rotate(angle, normal) * v; } template GLM_FUNC_QUALIFIER vec<3, T, Q> rotateX ( vec<3, T, Q> const& v, T const& angle ) { vec<3, T, Q> Result(v); T const Cos(cos(angle)); T const Sin(sin(angle)); Result.y = v.y * Cos - v.z * Sin; Result.z = v.y * Sin + v.z * Cos; return Result; } template GLM_FUNC_QUALIFIER vec<3, T, Q> rotateY ( vec<3, T, Q> const& v, T const& angle ) { vec<3, T, Q> Result = v; T const Cos(cos(angle)); T const Sin(sin(angle)); Result.x = v.x * Cos + v.z * Sin; Result.z = -v.x * Sin + v.z * Cos; return Result; } template GLM_FUNC_QUALIFIER vec<3, T, Q> rotateZ ( vec<3, T, Q> const& v, T const& angle ) { vec<3, T, Q> Result = v; T const Cos(cos(angle)); T const Sin(sin(angle)); Result.x = v.x * Cos - v.y * Sin; Result.y = v.x * Sin + v.y * Cos; return Result; } template GLM_FUNC_QUALIFIER vec<4, T, Q> rotateX ( vec<4, T, Q> const& v, T const& angle ) { vec<4, T, Q> Result = v; T const Cos(cos(angle)); T const Sin(sin(angle)); Result.y = v.y * Cos - v.z * Sin; Result.z = v.y * Sin + v.z * Cos; return Result; } template GLM_FUNC_QUALIFIER vec<4, T, Q> rotateY ( vec<4, T, Q> const& v, T const& angle ) { vec<4, T, Q> Result = v; T const Cos(cos(angle)); T const Sin(sin(angle)); Result.x = v.x * Cos + v.z * Sin; Result.z = -v.x * Sin + v.z * Cos; return Result; } template GLM_FUNC_QUALIFIER vec<4, T, Q> rotateZ ( vec<4, T, Q> const& v, T const& angle ) { vec<4, T, Q> Result = v; T const Cos(cos(angle)); T const Sin(sin(angle)); Result.x = v.x * Cos - v.y * Sin; Result.y = v.x * Sin + v.y * Cos; return Result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> orientation ( vec<3, T, Q> const& Normal, vec<3, T, Q> const& Up ) { if(all(equal(Normal, Up, epsilon()))) return mat<4, 4, T, Q>(static_cast(1)); vec<3, T, Q> RotationAxis = cross(Up, Normal); T Angle = acos(dot(Normal, Up)); return rotate(Angle, RotationAxis); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/scalar_multiplication.hpp000066400000000000000000000044041360521144700262140ustar00rootroot00000000000000/// @ref gtx /// @file glm/gtx/scalar_multiplication.hpp /// @author Joshua Moerman /// /// Include to use the features of this extension. /// /// Enables scalar multiplication for all types /// /// Since GLSL is very strict about types, the following (often used) combinations do not work: /// double * vec4 /// int * vec4 /// vec4 / int /// So we'll fix that! Of course "float * vec4" should remain the same (hence the enable_if magic) #pragma once #include "../detail/setup.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_scalar_multiplication is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_scalar_multiplication extension included") # endif #endif #include "../vec2.hpp" #include "../vec3.hpp" #include "../vec4.hpp" #include "../mat2x2.hpp" #include namespace glm { template using return_type_scalar_multiplication = typename std::enable_if< !std::is_same::value // T may not be a float && std::is_arithmetic::value, Vec // But it may be an int or double (no vec3 or mat3, ...) >::type; #define GLM_IMPLEMENT_SCAL_MULT(Vec) \ template \ return_type_scalar_multiplication \ operator*(T const& s, Vec rh){ \ return rh *= static_cast(s); \ } \ \ template \ return_type_scalar_multiplication \ operator*(Vec lh, T const& s){ \ return lh *= static_cast(s); \ } \ \ template \ return_type_scalar_multiplication \ operator/(Vec lh, T const& s){ \ return lh *= 1.0f / s; \ } GLM_IMPLEMENT_SCAL_MULT(vec2) GLM_IMPLEMENT_SCAL_MULT(vec3) GLM_IMPLEMENT_SCAL_MULT(vec4) GLM_IMPLEMENT_SCAL_MULT(mat2) GLM_IMPLEMENT_SCAL_MULT(mat2x3) GLM_IMPLEMENT_SCAL_MULT(mat2x4) GLM_IMPLEMENT_SCAL_MULT(mat3x2) GLM_IMPLEMENT_SCAL_MULT(mat3) GLM_IMPLEMENT_SCAL_MULT(mat3x4) GLM_IMPLEMENT_SCAL_MULT(mat4x2) GLM_IMPLEMENT_SCAL_MULT(mat4x3) GLM_IMPLEMENT_SCAL_MULT(mat4) #undef GLM_IMPLEMENT_SCAL_MULT } // namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/scalar_relational.hpp000066400000000000000000000016351360521144700253140ustar00rootroot00000000000000/// @ref gtx_scalar_relational /// @file glm/gtx/scalar_relational.hpp /// /// @see core (dependence) /// /// @defgroup gtx_scalar_relational GLM_GTX_scalar_relational /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Extend a position from a source to a position at a defined length. #pragma once // Dependency: #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_extend is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_extend extension included") # endif #endif namespace glm { /// @addtogroup gtx_scalar_relational /// @{ /// @} }//namespace glm #include "scalar_relational.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/scalar_relational.inl000066400000000000000000000022401360521144700253000ustar00rootroot00000000000000/// @ref gtx_scalar_relational namespace glm { template GLM_FUNC_QUALIFIER bool lessThan ( T const& x, T const& y ) { return x < y; } template GLM_FUNC_QUALIFIER bool lessThanEqual ( T const& x, T const& y ) { return x <= y; } template GLM_FUNC_QUALIFIER bool greaterThan ( T const& x, T const& y ) { return x > y; } template GLM_FUNC_QUALIFIER bool greaterThanEqual ( T const& x, T const& y ) { return x >= y; } template GLM_FUNC_QUALIFIER bool equal ( T const& x, T const& y ) { return detail::compute_equal::is_iec559>::call(x, y); } template GLM_FUNC_QUALIFIER bool notEqual ( T const& x, T const& y ) { return !detail::compute_equal::is_iec559>::call(x, y); } GLM_FUNC_QUALIFIER bool any ( bool const& x ) { return x; } GLM_FUNC_QUALIFIER bool all ( bool const& x ) { return x; } GLM_FUNC_QUALIFIER bool not_ ( bool const& x ) { return !x; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/spline.hpp000066400000000000000000000031551360521144700231260ustar00rootroot00000000000000/// @ref gtx_spline /// @file glm/gtx/spline.hpp /// /// @see core (dependence) /// /// @defgroup gtx_spline GLM_GTX_spline /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Spline functions #pragma once // Dependency: #include "../glm.hpp" #include "../gtx/optimum_pow.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_spline is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_spline extension included") # endif #endif namespace glm { /// @addtogroup gtx_spline /// @{ /// Return a point from a catmull rom curve. /// @see gtx_spline extension. template GLM_FUNC_DECL genType catmullRom( genType const& v1, genType const& v2, genType const& v3, genType const& v4, typename genType::value_type const& s); /// Return a point from a hermite curve. /// @see gtx_spline extension. template GLM_FUNC_DECL genType hermite( genType const& v1, genType const& t1, genType const& v2, genType const& t2, typename genType::value_type const& s); /// Return a point from a cubic curve. /// @see gtx_spline extension. template GLM_FUNC_DECL genType cubic( genType const& v1, genType const& v2, genType const& v3, genType const& v4, typename genType::value_type const& s); /// @} }//namespace glm #include "spline.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/spline.inl000066400000000000000000000035051360521144700231200ustar00rootroot00000000000000/// @ref gtx_spline namespace glm { template GLM_FUNC_QUALIFIER genType catmullRom ( genType const& v1, genType const& v2, genType const& v3, genType const& v4, typename genType::value_type const& s ) { typename genType::value_type s2 = pow2(s); typename genType::value_type s3 = pow3(s); typename genType::value_type f1 = -s3 + typename genType::value_type(2) * s2 - s; typename genType::value_type f2 = typename genType::value_type(3) * s3 - typename genType::value_type(5) * s2 + typename genType::value_type(2); typename genType::value_type f3 = typename genType::value_type(-3) * s3 + typename genType::value_type(4) * s2 + s; typename genType::value_type f4 = s3 - s2; return (f1 * v1 + f2 * v2 + f3 * v3 + f4 * v4) / typename genType::value_type(2); } template GLM_FUNC_QUALIFIER genType hermite ( genType const& v1, genType const& t1, genType const& v2, genType const& t2, typename genType::value_type const& s ) { typename genType::value_type s2 = pow2(s); typename genType::value_type s3 = pow3(s); typename genType::value_type f1 = typename genType::value_type(2) * s3 - typename genType::value_type(3) * s2 + typename genType::value_type(1); typename genType::value_type f2 = typename genType::value_type(-2) * s3 + typename genType::value_type(3) * s2; typename genType::value_type f3 = s3 - typename genType::value_type(2) * s2 + s; typename genType::value_type f4 = s3 - s2; return f1 * v1 + f2 * v2 + f3 * t1 + f4 * t2; } template GLM_FUNC_QUALIFIER genType cubic ( genType const& v1, genType const& v2, genType const& v3, genType const& v4, typename genType::value_type const& s ) { return ((v1 * s + v2) * s + v3) * s + v4; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/std_based_type.hpp000066400000000000000000000040411360521144700246200ustar00rootroot00000000000000/// @ref gtx_std_based_type /// @file glm/gtx/std_based_type.hpp /// /// @see core (dependence) /// @see gtx_extented_min_max (dependence) /// /// @defgroup gtx_std_based_type GLM_GTX_std_based_type /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Adds vector types based on STL value types. #pragma once // Dependency: #include "../glm.hpp" #include #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_std_based_type is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_std_based_type extension included") # endif #endif namespace glm { /// @addtogroup gtx_std_based_type /// @{ /// Vector type based of one std::size_t component. /// @see GLM_GTX_std_based_type typedef vec<1, std::size_t, defaultp> size1; /// Vector type based of two std::size_t components. /// @see GLM_GTX_std_based_type typedef vec<2, std::size_t, defaultp> size2; /// Vector type based of three std::size_t components. /// @see GLM_GTX_std_based_type typedef vec<3, std::size_t, defaultp> size3; /// Vector type based of four std::size_t components. /// @see GLM_GTX_std_based_type typedef vec<4, std::size_t, defaultp> size4; /// Vector type based of one std::size_t component. /// @see GLM_GTX_std_based_type typedef vec<1, std::size_t, defaultp> size1_t; /// Vector type based of two std::size_t components. /// @see GLM_GTX_std_based_type typedef vec<2, std::size_t, defaultp> size2_t; /// Vector type based of three std::size_t components. /// @see GLM_GTX_std_based_type typedef vec<3, std::size_t, defaultp> size3_t; /// Vector type based of four std::size_t components. /// @see GLM_GTX_std_based_type typedef vec<4, std::size_t, defaultp> size4_t; /// @} }//namespace glm #include "std_based_type.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/std_based_type.inl000066400000000000000000000000661360521144700246160ustar00rootroot00000000000000/// @ref gtx_std_based_type namespace glm { } connectome-workbench-1.4.2/src/GLMath/glm/gtx/string_cast.hpp000066400000000000000000000026331360521144700241540ustar00rootroot00000000000000/// @ref gtx_string_cast /// @file glm/gtx/string_cast.hpp /// /// @see core (dependence) /// @see gtx_integer (dependence) /// @see gtx_quaternion (dependence) /// /// @defgroup gtx_string_cast GLM_GTX_string_cast /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Setup strings for GLM type values /// /// This extension is not supported with CUDA #pragma once // Dependency: #include "../glm.hpp" #include "../gtc/type_precision.hpp" #include "../gtc/quaternion.hpp" #include "../gtx/dual_quaternion.hpp" #include #include #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_string_cast is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_string_cast extension included") # endif #endif #if(GLM_COMPILER & GLM_COMPILER_CUDA) # error "GLM_GTX_string_cast is not supported on CUDA compiler" #endif namespace glm { /// @addtogroup gtx_string_cast /// @{ /// Create a string from a GLM vector or matrix typed variable. /// @see gtx_string_cast extension. template GLM_FUNC_DECL std::string to_string(genType const& x); /// @} }//namespace glm #include "string_cast.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/string_cast.inl000066400000000000000000000433441360521144700241530ustar00rootroot00000000000000/// @ref gtx_string_cast #include #include namespace glm{ namespace detail { template struct cast { typedef T value_type; }; template <> struct cast { typedef double value_type; }; GLM_FUNC_QUALIFIER std::string format(const char* msg, ...) { std::size_t const STRING_BUFFER(4096); char text[STRING_BUFFER]; va_list list; if(msg == GLM_NULLPTR) return std::string(); va_start(list, msg); # if (GLM_COMPILER & GLM_COMPILER_VC) vsprintf_s(text, STRING_BUFFER, msg, list); # else// std::vsprintf(text, msg, list); # endif// va_end(list); return std::string(text); } static const char* LabelTrue = "true"; static const char* LabelFalse = "false"; template struct literal { GLM_FUNC_QUALIFIER static char const * value() {return "%d";} }; template struct literal { GLM_FUNC_QUALIFIER static char const * value() {return "%f";} }; # if GLM_MODEL == GLM_MODEL_32 && GLM_COMPILER && GLM_COMPILER_VC template<> struct literal { GLM_FUNC_QUALIFIER static char const * value() {return "%lld";} }; template<> struct literal { GLM_FUNC_QUALIFIER static char const * value() {return "%lld";} }; # endif//GLM_MODEL == GLM_MODEL_32 && GLM_COMPILER && GLM_COMPILER_VC template struct prefix{}; template<> struct prefix { GLM_FUNC_QUALIFIER static char const * value() {return "";} }; template<> struct prefix { GLM_FUNC_QUALIFIER static char const * value() {return "d";} }; template<> struct prefix { GLM_FUNC_QUALIFIER static char const * value() {return "b";} }; template<> struct prefix { GLM_FUNC_QUALIFIER static char const * value() {return "u8";} }; template<> struct prefix { GLM_FUNC_QUALIFIER static char const * value() {return "i8";} }; template<> struct prefix { GLM_FUNC_QUALIFIER static char const * value() {return "u16";} }; template<> struct prefix { GLM_FUNC_QUALIFIER static char const * value() {return "i16";} }; template<> struct prefix { GLM_FUNC_QUALIFIER static char const * value() {return "u";} }; template<> struct prefix { GLM_FUNC_QUALIFIER static char const * value() {return "i";} }; template<> struct prefix { GLM_FUNC_QUALIFIER static char const * value() {return "u64";} }; template<> struct prefix { GLM_FUNC_QUALIFIER static char const * value() {return "i64";} }; template struct compute_to_string {}; template struct compute_to_string > { GLM_FUNC_QUALIFIER static std::string call(vec<1, bool, Q> const& x) { return detail::format("bvec1(%s)", x[0] ? detail::LabelTrue : detail::LabelFalse); } }; template struct compute_to_string > { GLM_FUNC_QUALIFIER static std::string call(vec<2, bool, Q> const& x) { return detail::format("bvec2(%s, %s)", x[0] ? detail::LabelTrue : detail::LabelFalse, x[1] ? detail::LabelTrue : detail::LabelFalse); } }; template struct compute_to_string > { GLM_FUNC_QUALIFIER static std::string call(vec<3, bool, Q> const& x) { return detail::format("bvec3(%s, %s, %s)", x[0] ? detail::LabelTrue : detail::LabelFalse, x[1] ? detail::LabelTrue : detail::LabelFalse, x[2] ? detail::LabelTrue : detail::LabelFalse); } }; template struct compute_to_string > { GLM_FUNC_QUALIFIER static std::string call(vec<4, bool, Q> const& x) { return detail::format("bvec4(%s, %s, %s, %s)", x[0] ? detail::LabelTrue : detail::LabelFalse, x[1] ? detail::LabelTrue : detail::LabelFalse, x[2] ? detail::LabelTrue : detail::LabelFalse, x[3] ? detail::LabelTrue : detail::LabelFalse); } }; template struct compute_to_string > { GLM_FUNC_QUALIFIER static std::string call(vec<1, T, Q> const& x) { char const * PrefixStr = prefix::value(); char const * LiteralStr = literal::is_iec559>::value(); std::string FormatStr(detail::format("%svec1(%s)", PrefixStr, LiteralStr)); return detail::format(FormatStr.c_str(), static_cast::value_type>(x[0])); } }; template struct compute_to_string > { GLM_FUNC_QUALIFIER static std::string call(vec<2, T, Q> const& x) { char const * PrefixStr = prefix::value(); char const * LiteralStr = literal::is_iec559>::value(); std::string FormatStr(detail::format("%svec2(%s, %s)", PrefixStr, LiteralStr, LiteralStr)); return detail::format(FormatStr.c_str(), static_cast::value_type>(x[0]), static_cast::value_type>(x[1])); } }; template struct compute_to_string > { GLM_FUNC_QUALIFIER static std::string call(vec<3, T, Q> const& x) { char const * PrefixStr = prefix::value(); char const * LiteralStr = literal::is_iec559>::value(); std::string FormatStr(detail::format("%svec3(%s, %s, %s)", PrefixStr, LiteralStr, LiteralStr, LiteralStr)); return detail::format(FormatStr.c_str(), static_cast::value_type>(x[0]), static_cast::value_type>(x[1]), static_cast::value_type>(x[2])); } }; template struct compute_to_string > { GLM_FUNC_QUALIFIER static std::string call(vec<4, T, Q> const& x) { char const * PrefixStr = prefix::value(); char const * LiteralStr = literal::is_iec559>::value(); std::string FormatStr(detail::format("%svec4(%s, %s, %s, %s)", PrefixStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr)); return detail::format(FormatStr.c_str(), static_cast::value_type>(x[0]), static_cast::value_type>(x[1]), static_cast::value_type>(x[2]), static_cast::value_type>(x[3])); } }; template struct compute_to_string > { GLM_FUNC_QUALIFIER static std::string call(mat<2, 2, T, Q> const& x) { char const * PrefixStr = prefix::value(); char const * LiteralStr = literal::is_iec559>::value(); std::string FormatStr(detail::format("%smat2x2((%s, %s), (%s, %s))", PrefixStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr)); return detail::format(FormatStr.c_str(), static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1])); } }; template struct compute_to_string > { GLM_FUNC_QUALIFIER static std::string call(mat<2, 3, T, Q> const& x) { char const * PrefixStr = prefix::value(); char const * LiteralStr = literal::is_iec559>::value(); std::string FormatStr(detail::format("%smat2x3((%s, %s, %s), (%s, %s, %s))", PrefixStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr)); return detail::format(FormatStr.c_str(), static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2])); } }; template struct compute_to_string > { GLM_FUNC_QUALIFIER static std::string call(mat<2, 4, T, Q> const& x) { char const * PrefixStr = prefix::value(); char const * LiteralStr = literal::is_iec559>::value(); std::string FormatStr(detail::format("%smat2x4((%s, %s, %s, %s), (%s, %s, %s, %s))", PrefixStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr)); return detail::format(FormatStr.c_str(), static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), static_cast::value_type>(x[0][3]), static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2]), static_cast::value_type>(x[1][3])); } }; template struct compute_to_string > { GLM_FUNC_QUALIFIER static std::string call(mat<3, 2, T, Q> const& x) { char const * PrefixStr = prefix::value(); char const * LiteralStr = literal::is_iec559>::value(); std::string FormatStr(detail::format("%smat3x2((%s, %s), (%s, %s), (%s, %s))", PrefixStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr)); return detail::format(FormatStr.c_str(), static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1])); } }; template struct compute_to_string > { GLM_FUNC_QUALIFIER static std::string call(mat<3, 3, T, Q> const& x) { char const * PrefixStr = prefix::value(); char const * LiteralStr = literal::is_iec559>::value(); std::string FormatStr(detail::format("%smat3x3((%s, %s, %s), (%s, %s, %s), (%s, %s, %s))", PrefixStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr)); return detail::format(FormatStr.c_str(), static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2]), static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1]), static_cast::value_type>(x[2][2])); } }; template struct compute_to_string > { GLM_FUNC_QUALIFIER static std::string call(mat<3, 4, T, Q> const& x) { char const * PrefixStr = prefix::value(); char const * LiteralStr = literal::is_iec559>::value(); std::string FormatStr(detail::format("%smat3x4((%s, %s, %s, %s), (%s, %s, %s, %s), (%s, %s, %s, %s))", PrefixStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr)); return detail::format(FormatStr.c_str(), static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), static_cast::value_type>(x[0][3]), static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2]), static_cast::value_type>(x[1][3]), static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1]), static_cast::value_type>(x[2][2]), static_cast::value_type>(x[2][3])); } }; template struct compute_to_string > { GLM_FUNC_QUALIFIER static std::string call(mat<4, 2, T, Q> const& x) { char const * PrefixStr = prefix::value(); char const * LiteralStr = literal::is_iec559>::value(); std::string FormatStr(detail::format("%smat4x2((%s, %s), (%s, %s), (%s, %s), (%s, %s))", PrefixStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr)); return detail::format(FormatStr.c_str(), static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1]), static_cast::value_type>(x[3][0]), static_cast::value_type>(x[3][1])); } }; template struct compute_to_string > { GLM_FUNC_QUALIFIER static std::string call(mat<4, 3, T, Q> const& x) { char const * PrefixStr = prefix::value(); char const * LiteralStr = literal::is_iec559>::value(); std::string FormatStr(detail::format("%smat4x3((%s, %s, %s), (%s, %s, %s), (%s, %s, %s), (%s, %s, %s))", PrefixStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr)); return detail::format(FormatStr.c_str(), static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2]), static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1]), static_cast::value_type>(x[2][2]), static_cast::value_type>(x[3][0]), static_cast::value_type>(x[3][1]), static_cast::value_type>(x[3][2])); } }; template struct compute_to_string > { GLM_FUNC_QUALIFIER static std::string call(mat<4, 4, T, Q> const& x) { char const * PrefixStr = prefix::value(); char const * LiteralStr = literal::is_iec559>::value(); std::string FormatStr(detail::format("%smat4x4((%s, %s, %s, %s), (%s, %s, %s, %s), (%s, %s, %s, %s), (%s, %s, %s, %s))", PrefixStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr)); return detail::format(FormatStr.c_str(), static_cast::value_type>(x[0][0]), static_cast::value_type>(x[0][1]), static_cast::value_type>(x[0][2]), static_cast::value_type>(x[0][3]), static_cast::value_type>(x[1][0]), static_cast::value_type>(x[1][1]), static_cast::value_type>(x[1][2]), static_cast::value_type>(x[1][3]), static_cast::value_type>(x[2][0]), static_cast::value_type>(x[2][1]), static_cast::value_type>(x[2][2]), static_cast::value_type>(x[2][3]), static_cast::value_type>(x[3][0]), static_cast::value_type>(x[3][1]), static_cast::value_type>(x[3][2]), static_cast::value_type>(x[3][3])); } }; template struct compute_to_string > { GLM_FUNC_QUALIFIER static std::string call(qua const& q) { char const * PrefixStr = prefix::value(); char const * LiteralStr = literal::is_iec559>::value(); std::string FormatStr(detail::format("%squat(%s, {%s, %s, %s})", PrefixStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr)); return detail::format(FormatStr.c_str(), static_cast::value_type>(q.w), static_cast::value_type>(q.x), static_cast::value_type>(q.y), static_cast::value_type>(q.z)); } }; template struct compute_to_string > { GLM_FUNC_QUALIFIER static std::string call(tdualquat const& x) { char const * PrefixStr = prefix::value(); char const * LiteralStr = literal::is_iec559>::value(); std::string FormatStr(detail::format("%sdualquat((%s, {%s, %s, %s}), (%s, {%s, %s, %s}))", PrefixStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr, LiteralStr)); return detail::format(FormatStr.c_str(), static_cast::value_type>(x.real.w), static_cast::value_type>(x.real.x), static_cast::value_type>(x.real.y), static_cast::value_type>(x.real.z), static_cast::value_type>(x.dual.w), static_cast::value_type>(x.dual.x), static_cast::value_type>(x.dual.y), static_cast::value_type>(x.dual.z)); } }; }//namespace detail template GLM_FUNC_QUALIFIER std::string to_string(matType const& x) { return detail::compute_to_string::call(x); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/texture.hpp000066400000000000000000000024701360521144700233330ustar00rootroot00000000000000/// @ref gtx_texture /// @file glm/gtx/texture.hpp /// /// @see core (dependence) /// /// @defgroup gtx_texture GLM_GTX_texture /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Wrapping mode of texture coordinates. #pragma once // Dependency: #include "../glm.hpp" #include "../gtc/integer.hpp" #include "../gtx/component_wise.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_texture is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_texture extension included") # endif #endif namespace glm { /// @addtogroup gtx_texture /// @{ /// Compute the number of mipmaps levels necessary to create a mipmap complete texture /// /// @param Extent Extent of the texture base level mipmap /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point or signed integer scalar types /// @tparam Q Value from qualifier enum template T levels(vec const& Extent); /// @} }// namespace glm #include "texture.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/texture.inl000066400000000000000000000005061360521144700233240ustar00rootroot00000000000000/// @ref gtx_texture namespace glm { template inline T levels(vec const& Extent) { return glm::log2(compMax(Extent)) + static_cast(1); } template inline T levels(T Extent) { return vec<1, T, defaultp>(Extent).x; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/transform.hpp000066400000000000000000000033211360521144700236420ustar00rootroot00000000000000/// @ref gtx_transform /// @file glm/gtx/transform.hpp /// /// @see core (dependence) /// @see gtc_matrix_transform (dependence) /// @see gtx_transform /// @see gtx_transform2 /// /// @defgroup gtx_transform GLM_GTX_transform /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Add transformation matrices #pragma once // Dependency: #include "../glm.hpp" #include "../gtc/matrix_transform.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_transform is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_transform extension included") # endif #endif namespace glm { /// @addtogroup gtx_transform /// @{ /// Transforms a matrix with a translation 4 * 4 matrix created from 3 scalars. /// @see gtc_matrix_transform /// @see gtx_transform template GLM_FUNC_DECL mat<4, 4, T, Q> translate( vec<3, T, Q> const& v); /// Builds a rotation 4 * 4 matrix created from an axis of 3 scalars and an angle expressed in radians. /// @see gtc_matrix_transform /// @see gtx_transform template GLM_FUNC_DECL mat<4, 4, T, Q> rotate( T angle, vec<3, T, Q> const& v); /// Transforms a matrix with a scale 4 * 4 matrix created from a vector of 3 components. /// @see gtc_matrix_transform /// @see gtx_transform template GLM_FUNC_DECL mat<4, 4, T, Q> scale( vec<3, T, Q> const& v); /// @} }// namespace glm #include "transform.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/transform.inl000066400000000000000000000011201360521144700236300ustar00rootroot00000000000000/// @ref gtx_transform namespace glm { template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> translate(vec<3, T, Q> const& v) { return translate(mat<4, 4, T, Q>(static_cast(1)), v); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotate(T angle, vec<3, T, Q> const& v) { return rotate(mat<4, 4, T, Q>(static_cast(1)), angle, v); } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scale(vec<3, T, Q> const& v) { return scale(mat<4, 4, T, Q>(static_cast(1)), v); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/transform2.hpp000066400000000000000000000067061360521144700237360ustar00rootroot00000000000000/// @ref gtx_transform2 /// @file glm/gtx/transform2.hpp /// /// @see core (dependence) /// @see gtx_transform (dependence) /// /// @defgroup gtx_transform2 GLM_GTX_transform2 /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Add extra transformation matrices #pragma once // Dependency: #include "../glm.hpp" #include "../gtx/transform.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_transform2 is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_transform2 extension included") # endif #endif namespace glm { /// @addtogroup gtx_transform2 /// @{ //! Transforms a matrix with a shearing on X axis. //! From GLM_GTX_transform2 extension. template GLM_FUNC_DECL mat<3, 3, T, Q> shearX2D(mat<3, 3, T, Q> const& m, T y); //! Transforms a matrix with a shearing on Y axis. //! From GLM_GTX_transform2 extension. template GLM_FUNC_DECL mat<3, 3, T, Q> shearY2D(mat<3, 3, T, Q> const& m, T x); //! Transforms a matrix with a shearing on X axis //! From GLM_GTX_transform2 extension. template GLM_FUNC_DECL mat<4, 4, T, Q> shearX3D(mat<4, 4, T, Q> const& m, T y, T z); //! Transforms a matrix with a shearing on Y axis. //! From GLM_GTX_transform2 extension. template GLM_FUNC_DECL mat<4, 4, T, Q> shearY3D(mat<4, 4, T, Q> const& m, T x, T z); //! Transforms a matrix with a shearing on Z axis. //! From GLM_GTX_transform2 extension. template GLM_FUNC_DECL mat<4, 4, T, Q> shearZ3D(mat<4, 4, T, Q> const& m, T x, T y); //template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shear(const mat<4, 4, T, Q> & m, shearPlane, planePoint, angle) // Identity + tan(angle) * cross(Normal, OnPlaneVector) 0 // - dot(PointOnPlane, normal) * OnPlaneVector 1 // Reflect functions seem to don't work //template mat<3, 3, T, Q> reflect2D(const mat<3, 3, T, Q> & m, const vec<3, T, Q>& normal){return reflect2DGTX(m, normal);} //!< \brief Build a reflection matrix (from GLM_GTX_transform2 extension) //template mat<4, 4, T, Q> reflect3D(const mat<4, 4, T, Q> & m, const vec<3, T, Q>& normal){return reflect3DGTX(m, normal);} //!< \brief Build a reflection matrix (from GLM_GTX_transform2 extension) //! Build planar projection matrix along normal axis. //! From GLM_GTX_transform2 extension. template GLM_FUNC_DECL mat<3, 3, T, Q> proj2D(mat<3, 3, T, Q> const& m, vec<3, T, Q> const& normal); //! Build planar projection matrix along normal axis. //! From GLM_GTX_transform2 extension. template GLM_FUNC_DECL mat<4, 4, T, Q> proj3D(mat<4, 4, T, Q> const & m, vec<3, T, Q> const& normal); //! Build a scale bias matrix. //! From GLM_GTX_transform2 extension. template GLM_FUNC_DECL mat<4, 4, T, Q> scaleBias(T scale, T bias); //! Build a scale bias matrix. //! From GLM_GTX_transform2 extension. template GLM_FUNC_DECL mat<4, 4, T, Q> scaleBias(mat<4, 4, T, Q> const& m, T scale, T bias); /// @} }// namespace glm #include "transform2.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/transform2.inl000066400000000000000000000071671360521144700237330ustar00rootroot00000000000000/// @ref gtx_transform2 namespace glm { template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearX2D(mat<3, 3, T, Q> const& m, T s) { mat<3, 3, T, Q> r(1); r[1][0] = s; return m * r; } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearY2D(mat<3, 3, T, Q> const& m, T s) { mat<3, 3, T, Q> r(1); r[0][1] = s; return m * r; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shearX3D(mat<4, 4, T, Q> const& m, T s, T t) { mat<4, 4, T, Q> r(1); r[0][1] = s; r[0][2] = t; return m * r; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shearY3D(mat<4, 4, T, Q> const& m, T s, T t) { mat<4, 4, T, Q> r(1); r[1][0] = s; r[1][2] = t; return m * r; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shearZ3D(mat<4, 4, T, Q> const& m, T s, T t) { mat<4, 4, T, Q> r(1); r[2][0] = s; r[2][1] = t; return m * r; } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> reflect2D(mat<3, 3, T, Q> const& m, vec<3, T, Q> const& normal) { mat<3, 3, T, Q> r(static_cast(1)); r[0][0] = static_cast(1) - static_cast(2) * normal.x * normal.x; r[0][1] = -static_cast(2) * normal.x * normal.y; r[1][0] = -static_cast(2) * normal.x * normal.y; r[1][1] = static_cast(1) - static_cast(2) * normal.y * normal.y; return m * r; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> reflect3D(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& normal) { mat<4, 4, T, Q> r(static_cast(1)); r[0][0] = static_cast(1) - static_cast(2) * normal.x * normal.x; r[0][1] = -static_cast(2) * normal.x * normal.y; r[0][2] = -static_cast(2) * normal.x * normal.z; r[1][0] = -static_cast(2) * normal.x * normal.y; r[1][1] = static_cast(1) - static_cast(2) * normal.y * normal.y; r[1][2] = -static_cast(2) * normal.y * normal.z; r[2][0] = -static_cast(2) * normal.x * normal.z; r[2][1] = -static_cast(2) * normal.y * normal.z; r[2][2] = static_cast(1) - static_cast(2) * normal.z * normal.z; return m * r; } template GLM_FUNC_QUALIFIER mat<3, 3, T, Q> proj2D( const mat<3, 3, T, Q>& m, const vec<3, T, Q>& normal) { mat<3, 3, T, Q> r(static_cast(1)); r[0][0] = static_cast(1) - normal.x * normal.x; r[0][1] = - normal.x * normal.y; r[1][0] = - normal.x * normal.y; r[1][1] = static_cast(1) - normal.y * normal.y; return m * r; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> proj3D( const mat<4, 4, T, Q>& m, const vec<3, T, Q>& normal) { mat<4, 4, T, Q> r(static_cast(1)); r[0][0] = static_cast(1) - normal.x * normal.x; r[0][1] = - normal.x * normal.y; r[0][2] = - normal.x * normal.z; r[1][0] = - normal.x * normal.y; r[1][1] = static_cast(1) - normal.y * normal.y; r[1][2] = - normal.y * normal.z; r[2][0] = - normal.x * normal.z; r[2][1] = - normal.y * normal.z; r[2][2] = static_cast(1) - normal.z * normal.z; return m * r; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scaleBias(T scale, T bias) { mat<4, 4, T, Q> result; result[3] = vec<4, T, Q>(vec<3, T, Q>(bias), static_cast(1)); result[0][0] = scale; result[1][1] = scale; result[2][2] = scale; return result; } template GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scaleBias(mat<4, 4, T, Q> const& m, T scale, T bias) { return m * scaleBias(scale, bias); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/type_aligned.hpp000066400000000000000000001027401360521144700243000ustar00rootroot00000000000000/// @ref gtx_type_aligned /// @file glm/gtx/type_aligned.hpp /// /// @see core (dependence) /// @see gtc_quaternion (dependence) /// /// @defgroup gtx_type_aligned GLM_GTX_type_aligned /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Defines aligned types. #pragma once // Dependency: #include "../gtc/type_precision.hpp" #include "../gtc/quaternion.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_type_aligned is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_type_aligned extension included") # endif #endif namespace glm { /////////////////////////// // Signed int vector types /// @addtogroup gtx_type_aligned /// @{ /// Low qualifier 8 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_int8, aligned_lowp_int8, 1); /// Low qualifier 16 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_int16, aligned_lowp_int16, 2); /// Low qualifier 32 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_int32, aligned_lowp_int32, 4); /// Low qualifier 64 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_int64, aligned_lowp_int64, 8); /// Low qualifier 8 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_int8_t, aligned_lowp_int8_t, 1); /// Low qualifier 16 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_int16_t, aligned_lowp_int16_t, 2); /// Low qualifier 32 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_int32_t, aligned_lowp_int32_t, 4); /// Low qualifier 64 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_int64_t, aligned_lowp_int64_t, 8); /// Low qualifier 8 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_i8, aligned_lowp_i8, 1); /// Low qualifier 16 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_i16, aligned_lowp_i16, 2); /// Low qualifier 32 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_i32, aligned_lowp_i32, 4); /// Low qualifier 64 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_i64, aligned_lowp_i64, 8); /// Medium qualifier 8 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_int8, aligned_mediump_int8, 1); /// Medium qualifier 16 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_int16, aligned_mediump_int16, 2); /// Medium qualifier 32 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_int32, aligned_mediump_int32, 4); /// Medium qualifier 64 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_int64, aligned_mediump_int64, 8); /// Medium qualifier 8 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_int8_t, aligned_mediump_int8_t, 1); /// Medium qualifier 16 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_int16_t, aligned_mediump_int16_t, 2); /// Medium qualifier 32 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_int32_t, aligned_mediump_int32_t, 4); /// Medium qualifier 64 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_int64_t, aligned_mediump_int64_t, 8); /// Medium qualifier 8 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_i8, aligned_mediump_i8, 1); /// Medium qualifier 16 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_i16, aligned_mediump_i16, 2); /// Medium qualifier 32 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_i32, aligned_mediump_i32, 4); /// Medium qualifier 64 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_i64, aligned_mediump_i64, 8); /// High qualifier 8 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_int8, aligned_highp_int8, 1); /// High qualifier 16 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_int16, aligned_highp_int16, 2); /// High qualifier 32 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_int32, aligned_highp_int32, 4); /// High qualifier 64 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_int64, aligned_highp_int64, 8); /// High qualifier 8 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_int8_t, aligned_highp_int8_t, 1); /// High qualifier 16 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_int16_t, aligned_highp_int16_t, 2); /// High qualifier 32 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_int32_t, aligned_highp_int32_t, 4); /// High qualifier 64 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_int64_t, aligned_highp_int64_t, 8); /// High qualifier 8 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_i8, aligned_highp_i8, 1); /// High qualifier 16 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_i16, aligned_highp_i16, 2); /// High qualifier 32 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_i32, aligned_highp_i32, 4); /// High qualifier 64 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_i64, aligned_highp_i64, 8); /// Default qualifier 8 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(int8, aligned_int8, 1); /// Default qualifier 16 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(int16, aligned_int16, 2); /// Default qualifier 32 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(int32, aligned_int32, 4); /// Default qualifier 64 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(int64, aligned_int64, 8); /// Default qualifier 8 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(int8_t, aligned_int8_t, 1); /// Default qualifier 16 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(int16_t, aligned_int16_t, 2); /// Default qualifier 32 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(int32_t, aligned_int32_t, 4); /// Default qualifier 64 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(int64_t, aligned_int64_t, 8); /// Default qualifier 8 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(i8, aligned_i8, 1); /// Default qualifier 16 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(i16, aligned_i16, 2); /// Default qualifier 32 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(i32, aligned_i32, 4); /// Default qualifier 64 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(i64, aligned_i64, 8); /// Default qualifier 32 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(ivec1, aligned_ivec1, 4); /// Default qualifier 32 bit signed integer aligned vector of 2 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(ivec2, aligned_ivec2, 8); /// Default qualifier 32 bit signed integer aligned vector of 3 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(ivec3, aligned_ivec3, 16); /// Default qualifier 32 bit signed integer aligned vector of 4 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(ivec4, aligned_ivec4, 16); /// Default qualifier 8 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(i8vec1, aligned_i8vec1, 1); /// Default qualifier 8 bit signed integer aligned vector of 2 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(i8vec2, aligned_i8vec2, 2); /// Default qualifier 8 bit signed integer aligned vector of 3 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(i8vec3, aligned_i8vec3, 4); /// Default qualifier 8 bit signed integer aligned vector of 4 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(i8vec4, aligned_i8vec4, 4); /// Default qualifier 16 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(i16vec1, aligned_i16vec1, 2); /// Default qualifier 16 bit signed integer aligned vector of 2 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(i16vec2, aligned_i16vec2, 4); /// Default qualifier 16 bit signed integer aligned vector of 3 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(i16vec3, aligned_i16vec3, 8); /// Default qualifier 16 bit signed integer aligned vector of 4 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(i16vec4, aligned_i16vec4, 8); /// Default qualifier 32 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(i32vec1, aligned_i32vec1, 4); /// Default qualifier 32 bit signed integer aligned vector of 2 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(i32vec2, aligned_i32vec2, 8); /// Default qualifier 32 bit signed integer aligned vector of 3 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(i32vec3, aligned_i32vec3, 16); /// Default qualifier 32 bit signed integer aligned vector of 4 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(i32vec4, aligned_i32vec4, 16); /// Default qualifier 64 bit signed integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(i64vec1, aligned_i64vec1, 8); /// Default qualifier 64 bit signed integer aligned vector of 2 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(i64vec2, aligned_i64vec2, 16); /// Default qualifier 64 bit signed integer aligned vector of 3 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(i64vec3, aligned_i64vec3, 32); /// Default qualifier 64 bit signed integer aligned vector of 4 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(i64vec4, aligned_i64vec4, 32); ///////////////////////////// // Unsigned int vector types /// Low qualifier 8 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_uint8, aligned_lowp_uint8, 1); /// Low qualifier 16 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_uint16, aligned_lowp_uint16, 2); /// Low qualifier 32 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_uint32, aligned_lowp_uint32, 4); /// Low qualifier 64 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_uint64, aligned_lowp_uint64, 8); /// Low qualifier 8 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_uint8_t, aligned_lowp_uint8_t, 1); /// Low qualifier 16 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_uint16_t, aligned_lowp_uint16_t, 2); /// Low qualifier 32 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_uint32_t, aligned_lowp_uint32_t, 4); /// Low qualifier 64 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_uint64_t, aligned_lowp_uint64_t, 8); /// Low qualifier 8 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_u8, aligned_lowp_u8, 1); /// Low qualifier 16 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_u16, aligned_lowp_u16, 2); /// Low qualifier 32 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_u32, aligned_lowp_u32, 4); /// Low qualifier 64 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(lowp_u64, aligned_lowp_u64, 8); /// Medium qualifier 8 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_uint8, aligned_mediump_uint8, 1); /// Medium qualifier 16 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_uint16, aligned_mediump_uint16, 2); /// Medium qualifier 32 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_uint32, aligned_mediump_uint32, 4); /// Medium qualifier 64 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_uint64, aligned_mediump_uint64, 8); /// Medium qualifier 8 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_uint8_t, aligned_mediump_uint8_t, 1); /// Medium qualifier 16 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_uint16_t, aligned_mediump_uint16_t, 2); /// Medium qualifier 32 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_uint32_t, aligned_mediump_uint32_t, 4); /// Medium qualifier 64 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_uint64_t, aligned_mediump_uint64_t, 8); /// Medium qualifier 8 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_u8, aligned_mediump_u8, 1); /// Medium qualifier 16 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_u16, aligned_mediump_u16, 2); /// Medium qualifier 32 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_u32, aligned_mediump_u32, 4); /// Medium qualifier 64 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mediump_u64, aligned_mediump_u64, 8); /// High qualifier 8 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_uint8, aligned_highp_uint8, 1); /// High qualifier 16 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_uint16, aligned_highp_uint16, 2); /// High qualifier 32 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_uint32, aligned_highp_uint32, 4); /// High qualifier 64 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_uint64, aligned_highp_uint64, 8); /// High qualifier 8 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_uint8_t, aligned_highp_uint8_t, 1); /// High qualifier 16 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_uint16_t, aligned_highp_uint16_t, 2); /// High qualifier 32 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_uint32_t, aligned_highp_uint32_t, 4); /// High qualifier 64 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_uint64_t, aligned_highp_uint64_t, 8); /// High qualifier 8 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_u8, aligned_highp_u8, 1); /// High qualifier 16 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_u16, aligned_highp_u16, 2); /// High qualifier 32 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_u32, aligned_highp_u32, 4); /// High qualifier 64 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(highp_u64, aligned_highp_u64, 8); /// Default qualifier 8 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(uint8, aligned_uint8, 1); /// Default qualifier 16 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(uint16, aligned_uint16, 2); /// Default qualifier 32 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(uint32, aligned_uint32, 4); /// Default qualifier 64 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(uint64, aligned_uint64, 8); /// Default qualifier 8 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(uint8_t, aligned_uint8_t, 1); /// Default qualifier 16 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(uint16_t, aligned_uint16_t, 2); /// Default qualifier 32 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(uint32_t, aligned_uint32_t, 4); /// Default qualifier 64 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(uint64_t, aligned_uint64_t, 8); /// Default qualifier 8 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(u8, aligned_u8, 1); /// Default qualifier 16 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(u16, aligned_u16, 2); /// Default qualifier 32 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(u32, aligned_u32, 4); /// Default qualifier 64 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(u64, aligned_u64, 8); /// Default qualifier 32 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(uvec1, aligned_uvec1, 4); /// Default qualifier 32 bit unsigned integer aligned vector of 2 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(uvec2, aligned_uvec2, 8); /// Default qualifier 32 bit unsigned integer aligned vector of 3 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(uvec3, aligned_uvec3, 16); /// Default qualifier 32 bit unsigned integer aligned vector of 4 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(uvec4, aligned_uvec4, 16); /// Default qualifier 8 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(u8vec1, aligned_u8vec1, 1); /// Default qualifier 8 bit unsigned integer aligned vector of 2 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(u8vec2, aligned_u8vec2, 2); /// Default qualifier 8 bit unsigned integer aligned vector of 3 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(u8vec3, aligned_u8vec3, 4); /// Default qualifier 8 bit unsigned integer aligned vector of 4 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(u8vec4, aligned_u8vec4, 4); /// Default qualifier 16 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(u16vec1, aligned_u16vec1, 2); /// Default qualifier 16 bit unsigned integer aligned vector of 2 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(u16vec2, aligned_u16vec2, 4); /// Default qualifier 16 bit unsigned integer aligned vector of 3 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(u16vec3, aligned_u16vec3, 8); /// Default qualifier 16 bit unsigned integer aligned vector of 4 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(u16vec4, aligned_u16vec4, 8); /// Default qualifier 32 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(u32vec1, aligned_u32vec1, 4); /// Default qualifier 32 bit unsigned integer aligned vector of 2 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(u32vec2, aligned_u32vec2, 8); /// Default qualifier 32 bit unsigned integer aligned vector of 3 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(u32vec3, aligned_u32vec3, 16); /// Default qualifier 32 bit unsigned integer aligned vector of 4 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(u32vec4, aligned_u32vec4, 16); /// Default qualifier 64 bit unsigned integer aligned scalar type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(u64vec1, aligned_u64vec1, 8); /// Default qualifier 64 bit unsigned integer aligned vector of 2 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(u64vec2, aligned_u64vec2, 16); /// Default qualifier 64 bit unsigned integer aligned vector of 3 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(u64vec3, aligned_u64vec3, 32); /// Default qualifier 64 bit unsigned integer aligned vector of 4 components type. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(u64vec4, aligned_u64vec4, 32); ////////////////////// // Float vector types /// 32 bit single-qualifier floating-point aligned scalar. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(float32, aligned_float32, 4); /// 32 bit single-qualifier floating-point aligned scalar. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(float32_t, aligned_float32_t, 4); /// 32 bit single-qualifier floating-point aligned scalar. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(float32, aligned_f32, 4); # ifndef GLM_FORCE_SINGLE_ONLY /// 64 bit double-qualifier floating-point aligned scalar. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(float64, aligned_float64, 8); /// 64 bit double-qualifier floating-point aligned scalar. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(float64_t, aligned_float64_t, 8); /// 64 bit double-qualifier floating-point aligned scalar. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(float64, aligned_f64, 8); # endif//GLM_FORCE_SINGLE_ONLY /// Single-qualifier floating-point aligned vector of 1 component. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(vec1, aligned_vec1, 4); /// Single-qualifier floating-point aligned vector of 2 components. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(vec2, aligned_vec2, 8); /// Single-qualifier floating-point aligned vector of 3 components. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(vec3, aligned_vec3, 16); /// Single-qualifier floating-point aligned vector of 4 components. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(vec4, aligned_vec4, 16); /// Single-qualifier floating-point aligned vector of 1 component. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(fvec1, aligned_fvec1, 4); /// Single-qualifier floating-point aligned vector of 2 components. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(fvec2, aligned_fvec2, 8); /// Single-qualifier floating-point aligned vector of 3 components. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(fvec3, aligned_fvec3, 16); /// Single-qualifier floating-point aligned vector of 4 components. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(fvec4, aligned_fvec4, 16); /// Single-qualifier floating-point aligned vector of 1 component. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f32vec1, aligned_f32vec1, 4); /// Single-qualifier floating-point aligned vector of 2 components. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f32vec2, aligned_f32vec2, 8); /// Single-qualifier floating-point aligned vector of 3 components. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f32vec3, aligned_f32vec3, 16); /// Single-qualifier floating-point aligned vector of 4 components. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f32vec4, aligned_f32vec4, 16); /// Double-qualifier floating-point aligned vector of 1 component. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(dvec1, aligned_dvec1, 8); /// Double-qualifier floating-point aligned vector of 2 components. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(dvec2, aligned_dvec2, 16); /// Double-qualifier floating-point aligned vector of 3 components. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(dvec3, aligned_dvec3, 32); /// Double-qualifier floating-point aligned vector of 4 components. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(dvec4, aligned_dvec4, 32); # ifndef GLM_FORCE_SINGLE_ONLY /// Double-qualifier floating-point aligned vector of 1 component. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f64vec1, aligned_f64vec1, 8); /// Double-qualifier floating-point aligned vector of 2 components. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f64vec2, aligned_f64vec2, 16); /// Double-qualifier floating-point aligned vector of 3 components. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f64vec3, aligned_f64vec3, 32); /// Double-qualifier floating-point aligned vector of 4 components. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f64vec4, aligned_f64vec4, 32); # endif//GLM_FORCE_SINGLE_ONLY ////////////////////// // Float matrix types /// Single-qualifier floating-point aligned 1x1 matrix. /// @see gtx_type_aligned //typedef detail::tmat1 mat1; /// Single-qualifier floating-point aligned 2x2 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mat2, aligned_mat2, 16); /// Single-qualifier floating-point aligned 3x3 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mat3, aligned_mat3, 16); /// Single-qualifier floating-point aligned 4x4 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mat4, aligned_mat4, 16); /// Single-qualifier floating-point aligned 1x1 matrix. /// @see gtx_type_aligned //typedef detail::tmat1x1 mat1; /// Single-qualifier floating-point aligned 2x2 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mat2x2, aligned_mat2x2, 16); /// Single-qualifier floating-point aligned 3x3 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mat3x3, aligned_mat3x3, 16); /// Single-qualifier floating-point aligned 4x4 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(mat4x4, aligned_mat4x4, 16); /// Single-qualifier floating-point aligned 1x1 matrix. /// @see gtx_type_aligned //typedef detail::tmat1x1 fmat1; /// Single-qualifier floating-point aligned 2x2 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(fmat2x2, aligned_fmat2, 16); /// Single-qualifier floating-point aligned 3x3 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(fmat3x3, aligned_fmat3, 16); /// Single-qualifier floating-point aligned 4x4 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(fmat4x4, aligned_fmat4, 16); /// Single-qualifier floating-point aligned 1x1 matrix. /// @see gtx_type_aligned //typedef f32 fmat1x1; /// Single-qualifier floating-point aligned 2x2 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(fmat2x2, aligned_fmat2x2, 16); /// Single-qualifier floating-point aligned 2x3 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(fmat2x3, aligned_fmat2x3, 16); /// Single-qualifier floating-point aligned 2x4 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(fmat2x4, aligned_fmat2x4, 16); /// Single-qualifier floating-point aligned 3x2 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(fmat3x2, aligned_fmat3x2, 16); /// Single-qualifier floating-point aligned 3x3 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(fmat3x3, aligned_fmat3x3, 16); /// Single-qualifier floating-point aligned 3x4 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(fmat3x4, aligned_fmat3x4, 16); /// Single-qualifier floating-point aligned 4x2 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(fmat4x2, aligned_fmat4x2, 16); /// Single-qualifier floating-point aligned 4x3 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(fmat4x3, aligned_fmat4x3, 16); /// Single-qualifier floating-point aligned 4x4 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(fmat4x4, aligned_fmat4x4, 16); /// Single-qualifier floating-point aligned 1x1 matrix. /// @see gtx_type_aligned //typedef detail::tmat1x1 f32mat1; /// Single-qualifier floating-point aligned 2x2 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f32mat2x2, aligned_f32mat2, 16); /// Single-qualifier floating-point aligned 3x3 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f32mat3x3, aligned_f32mat3, 16); /// Single-qualifier floating-point aligned 4x4 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f32mat4x4, aligned_f32mat4, 16); /// Single-qualifier floating-point aligned 1x1 matrix. /// @see gtx_type_aligned //typedef f32 f32mat1x1; /// Single-qualifier floating-point aligned 2x2 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f32mat2x2, aligned_f32mat2x2, 16); /// Single-qualifier floating-point aligned 2x3 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f32mat2x3, aligned_f32mat2x3, 16); /// Single-qualifier floating-point aligned 2x4 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f32mat2x4, aligned_f32mat2x4, 16); /// Single-qualifier floating-point aligned 3x2 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f32mat3x2, aligned_f32mat3x2, 16); /// Single-qualifier floating-point aligned 3x3 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f32mat3x3, aligned_f32mat3x3, 16); /// Single-qualifier floating-point aligned 3x4 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f32mat3x4, aligned_f32mat3x4, 16); /// Single-qualifier floating-point aligned 4x2 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f32mat4x2, aligned_f32mat4x2, 16); /// Single-qualifier floating-point aligned 4x3 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f32mat4x3, aligned_f32mat4x3, 16); /// Single-qualifier floating-point aligned 4x4 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f32mat4x4, aligned_f32mat4x4, 16); # ifndef GLM_FORCE_SINGLE_ONLY /// Double-qualifier floating-point aligned 1x1 matrix. /// @see gtx_type_aligned //typedef detail::tmat1x1 f64mat1; /// Double-qualifier floating-point aligned 2x2 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f64mat2x2, aligned_f64mat2, 32); /// Double-qualifier floating-point aligned 3x3 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f64mat3x3, aligned_f64mat3, 32); /// Double-qualifier floating-point aligned 4x4 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f64mat4x4, aligned_f64mat4, 32); /// Double-qualifier floating-point aligned 1x1 matrix. /// @see gtx_type_aligned //typedef f64 f64mat1x1; /// Double-qualifier floating-point aligned 2x2 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f64mat2x2, aligned_f64mat2x2, 32); /// Double-qualifier floating-point aligned 2x3 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f64mat2x3, aligned_f64mat2x3, 32); /// Double-qualifier floating-point aligned 2x4 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f64mat2x4, aligned_f64mat2x4, 32); /// Double-qualifier floating-point aligned 3x2 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f64mat3x2, aligned_f64mat3x2, 32); /// Double-qualifier floating-point aligned 3x3 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f64mat3x3, aligned_f64mat3x3, 32); /// Double-qualifier floating-point aligned 3x4 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f64mat3x4, aligned_f64mat3x4, 32); /// Double-qualifier floating-point aligned 4x2 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f64mat4x2, aligned_f64mat4x2, 32); /// Double-qualifier floating-point aligned 4x3 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f64mat4x3, aligned_f64mat4x3, 32); /// Double-qualifier floating-point aligned 4x4 matrix. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f64mat4x4, aligned_f64mat4x4, 32); # endif//GLM_FORCE_SINGLE_ONLY ////////////////////////// // Quaternion types /// Single-qualifier floating-point aligned quaternion. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(quat, aligned_quat, 16); /// Single-qualifier floating-point aligned quaternion. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(quat, aligned_fquat, 16); /// Double-qualifier floating-point aligned quaternion. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(dquat, aligned_dquat, 32); /// Single-qualifier floating-point aligned quaternion. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f32quat, aligned_f32quat, 16); # ifndef GLM_FORCE_SINGLE_ONLY /// Double-qualifier floating-point aligned quaternion. /// @see gtx_type_aligned GLM_ALIGNED_TYPEDEF(f64quat, aligned_f64quat, 32); # endif//GLM_FORCE_SINGLE_ONLY /// @} }//namespace glm #include "type_aligned.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/type_aligned.inl000066400000000000000000000000641360521144700242670ustar00rootroot00000000000000/// @ref gtc_type_aligned namespace glm { } connectome-workbench-1.4.2/src/GLMath/glm/gtx/type_trait.hpp000066400000000000000000000042551360521144700240220ustar00rootroot00000000000000/// @ref gtx_type_trait /// @file glm/gtx/type_trait.hpp /// /// @see core (dependence) /// /// @defgroup gtx_type_trait GLM_GTX_type_trait /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Defines traits for each type. #pragma once #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_type_trait is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_type_trait extension included") # endif #endif // Dependency: #include "../detail/qualifier.hpp" #include "../gtc/quaternion.hpp" #include "../gtx/dual_quaternion.hpp" namespace glm { /// @addtogroup gtx_type_trait /// @{ template struct type { static bool const is_vec = false; static bool const is_mat = false; static bool const is_quat = false; static length_t const components = 0; static length_t const cols = 0; static length_t const rows = 0; }; template struct type > { static bool const is_vec = true; static bool const is_mat = false; static bool const is_quat = false; static length_t const components = L; }; template struct type > { static bool const is_vec = false; static bool const is_mat = true; static bool const is_quat = false; static length_t const components = C; static length_t const cols = C; static length_t const rows = R; }; template struct type > { static bool const is_vec = false; static bool const is_mat = false; static bool const is_quat = true; static length_t const components = 4; }; template struct type > { static bool const is_vec = false; static bool const is_mat = false; static bool const is_quat = true; static length_t const components = 8; }; /// @} }//namespace glm #include "type_trait.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/type_trait.inl000066400000000000000000000040641360521144700240130ustar00rootroot00000000000000/// @ref gtx_type_trait namespace glm { template bool const type::is_vec; template bool const type::is_mat; template bool const type::is_quat; template length_t const type::components; template length_t const type::cols; template length_t const type::rows; // vec template bool const type >::is_vec; template bool const type >::is_mat; template bool const type >::is_quat; template length_t const type >::components; // mat template bool const type >::is_vec; template bool const type >::is_mat; template bool const type >::is_quat; template length_t const type >::components; template length_t const type >::cols; template length_t const type >::rows; // tquat template bool const type >::is_vec; template bool const type >::is_mat; template bool const type >::is_quat; template length_t const type >::components; // tdualquat template bool const type >::is_vec; template bool const type >::is_mat; template bool const type >::is_quat; template length_t const type >::components; }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/vec_swizzle.hpp000066400000000000000000002322761360521144700242100ustar00rootroot00000000000000/// @ref gtx_vec_swizzle /// @file glm/gtx/vec_swizzle.hpp /// /// @see core (dependence) /// /// @defgroup gtx_vec_swizzle GLM_GTX_vec_swizzle /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Functions to perform swizzle operation. #pragma once #include "../glm.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_vec_swizzle is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_vec_swizzle extension included") # endif #endif namespace glm { // xx template GLM_INLINE glm::vec<2, T, Q> xx(const glm::vec<1, T, Q> &v) { return glm::vec<2, T, Q>(v.x, v.x); } template GLM_INLINE glm::vec<2, T, Q> xx(const glm::vec<2, T, Q> &v) { return glm::vec<2, T, Q>(v.x, v.x); } template GLM_INLINE glm::vec<2, T, Q> xx(const glm::vec<3, T, Q> &v) { return glm::vec<2, T, Q>(v.x, v.x); } template GLM_INLINE glm::vec<2, T, Q> xx(const glm::vec<4, T, Q> &v) { return glm::vec<2, T, Q>(v.x, v.x); } // xy template GLM_INLINE glm::vec<2, T, Q> xy(const glm::vec<2, T, Q> &v) { return glm::vec<2, T, Q>(v.x, v.y); } template GLM_INLINE glm::vec<2, T, Q> xy(const glm::vec<3, T, Q> &v) { return glm::vec<2, T, Q>(v.x, v.y); } template GLM_INLINE glm::vec<2, T, Q> xy(const glm::vec<4, T, Q> &v) { return glm::vec<2, T, Q>(v.x, v.y); } // xz template GLM_INLINE glm::vec<2, T, Q> xz(const glm::vec<3, T, Q> &v) { return glm::vec<2, T, Q>(v.x, v.z); } template GLM_INLINE glm::vec<2, T, Q> xz(const glm::vec<4, T, Q> &v) { return glm::vec<2, T, Q>(v.x, v.z); } // xw template GLM_INLINE glm::vec<2, T, Q> xw(const glm::vec<4, T, Q> &v) { return glm::vec<2, T, Q>(v.x, v.w); } // yx template GLM_INLINE glm::vec<2, T, Q> yx(const glm::vec<2, T, Q> &v) { return glm::vec<2, T, Q>(v.y, v.x); } template GLM_INLINE glm::vec<2, T, Q> yx(const glm::vec<3, T, Q> &v) { return glm::vec<2, T, Q>(v.y, v.x); } template GLM_INLINE glm::vec<2, T, Q> yx(const glm::vec<4, T, Q> &v) { return glm::vec<2, T, Q>(v.y, v.x); } // yy template GLM_INLINE glm::vec<2, T, Q> yy(const glm::vec<2, T, Q> &v) { return glm::vec<2, T, Q>(v.y, v.y); } template GLM_INLINE glm::vec<2, T, Q> yy(const glm::vec<3, T, Q> &v) { return glm::vec<2, T, Q>(v.y, v.y); } template GLM_INLINE glm::vec<2, T, Q> yy(const glm::vec<4, T, Q> &v) { return glm::vec<2, T, Q>(v.y, v.y); } // yz template GLM_INLINE glm::vec<2, T, Q> yz(const glm::vec<3, T, Q> &v) { return glm::vec<2, T, Q>(v.y, v.z); } template GLM_INLINE glm::vec<2, T, Q> yz(const glm::vec<4, T, Q> &v) { return glm::vec<2, T, Q>(v.y, v.z); } // yw template GLM_INLINE glm::vec<2, T, Q> yw(const glm::vec<4, T, Q> &v) { return glm::vec<2, T, Q>(v.y, v.w); } // zx template GLM_INLINE glm::vec<2, T, Q> zx(const glm::vec<3, T, Q> &v) { return glm::vec<2, T, Q>(v.z, v.x); } template GLM_INLINE glm::vec<2, T, Q> zx(const glm::vec<4, T, Q> &v) { return glm::vec<2, T, Q>(v.z, v.x); } // zy template GLM_INLINE glm::vec<2, T, Q> zy(const glm::vec<3, T, Q> &v) { return glm::vec<2, T, Q>(v.z, v.y); } template GLM_INLINE glm::vec<2, T, Q> zy(const glm::vec<4, T, Q> &v) { return glm::vec<2, T, Q>(v.z, v.y); } // zz template GLM_INLINE glm::vec<2, T, Q> zz(const glm::vec<3, T, Q> &v) { return glm::vec<2, T, Q>(v.z, v.z); } template GLM_INLINE glm::vec<2, T, Q> zz(const glm::vec<4, T, Q> &v) { return glm::vec<2, T, Q>(v.z, v.z); } // zw template GLM_INLINE glm::vec<2, T, Q> zw(const glm::vec<4, T, Q> &v) { return glm::vec<2, T, Q>(v.z, v.w); } // wx template GLM_INLINE glm::vec<2, T, Q> wx(const glm::vec<4, T, Q> &v) { return glm::vec<2, T, Q>(v.w, v.x); } // wy template GLM_INLINE glm::vec<2, T, Q> wy(const glm::vec<4, T, Q> &v) { return glm::vec<2, T, Q>(v.w, v.y); } // wz template GLM_INLINE glm::vec<2, T, Q> wz(const glm::vec<4, T, Q> &v) { return glm::vec<2, T, Q>(v.w, v.z); } // ww template GLM_INLINE glm::vec<2, T, Q> ww(const glm::vec<4, T, Q> &v) { return glm::vec<2, T, Q>(v.w, v.w); } // xxx template GLM_INLINE glm::vec<3, T, Q> xxx(const glm::vec<1, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.x, v.x); } template GLM_INLINE glm::vec<3, T, Q> xxx(const glm::vec<2, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.x, v.x); } template GLM_INLINE glm::vec<3, T, Q> xxx(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.x, v.x); } template GLM_INLINE glm::vec<3, T, Q> xxx(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.x, v.x); } // xxy template GLM_INLINE glm::vec<3, T, Q> xxy(const glm::vec<2, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.x, v.y); } template GLM_INLINE glm::vec<3, T, Q> xxy(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.x, v.y); } template GLM_INLINE glm::vec<3, T, Q> xxy(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.x, v.y); } // xxz template GLM_INLINE glm::vec<3, T, Q> xxz(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.x, v.z); } template GLM_INLINE glm::vec<3, T, Q> xxz(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.x, v.z); } // xxw template GLM_INLINE glm::vec<3, T, Q> xxw(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.x, v.w); } // xyx template GLM_INLINE glm::vec<3, T, Q> xyx(const glm::vec<2, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.y, v.x); } template GLM_INLINE glm::vec<3, T, Q> xyx(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.y, v.x); } template GLM_INLINE glm::vec<3, T, Q> xyx(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.y, v.x); } // xyy template GLM_INLINE glm::vec<3, T, Q> xyy(const glm::vec<2, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.y, v.y); } template GLM_INLINE glm::vec<3, T, Q> xyy(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.y, v.y); } template GLM_INLINE glm::vec<3, T, Q> xyy(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.y, v.y); } // xyz template GLM_INLINE glm::vec<3, T, Q> xyz(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.y, v.z); } template GLM_INLINE glm::vec<3, T, Q> xyz(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.y, v.z); } // xyw template GLM_INLINE glm::vec<3, T, Q> xyw(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.y, v.w); } // xzx template GLM_INLINE glm::vec<3, T, Q> xzx(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.z, v.x); } template GLM_INLINE glm::vec<3, T, Q> xzx(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.z, v.x); } // xzy template GLM_INLINE glm::vec<3, T, Q> xzy(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.z, v.y); } template GLM_INLINE glm::vec<3, T, Q> xzy(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.z, v.y); } // xzz template GLM_INLINE glm::vec<3, T, Q> xzz(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.z, v.z); } template GLM_INLINE glm::vec<3, T, Q> xzz(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.z, v.z); } // xzw template GLM_INLINE glm::vec<3, T, Q> xzw(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.z, v.w); } // xwx template GLM_INLINE glm::vec<3, T, Q> xwx(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.w, v.x); } // xwy template GLM_INLINE glm::vec<3, T, Q> xwy(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.w, v.y); } // xwz template GLM_INLINE glm::vec<3, T, Q> xwz(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.w, v.z); } // xww template GLM_INLINE glm::vec<3, T, Q> xww(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.x, v.w, v.w); } // yxx template GLM_INLINE glm::vec<3, T, Q> yxx(const glm::vec<2, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.x, v.x); } template GLM_INLINE glm::vec<3, T, Q> yxx(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.x, v.x); } template GLM_INLINE glm::vec<3, T, Q> yxx(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.x, v.x); } // yxy template GLM_INLINE glm::vec<3, T, Q> yxy(const glm::vec<2, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.x, v.y); } template GLM_INLINE glm::vec<3, T, Q> yxy(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.x, v.y); } template GLM_INLINE glm::vec<3, T, Q> yxy(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.x, v.y); } // yxz template GLM_INLINE glm::vec<3, T, Q> yxz(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.x, v.z); } template GLM_INLINE glm::vec<3, T, Q> yxz(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.x, v.z); } // yxw template GLM_INLINE glm::vec<3, T, Q> yxw(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.x, v.w); } // yyx template GLM_INLINE glm::vec<3, T, Q> yyx(const glm::vec<2, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.y, v.x); } template GLM_INLINE glm::vec<3, T, Q> yyx(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.y, v.x); } template GLM_INLINE glm::vec<3, T, Q> yyx(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.y, v.x); } // yyy template GLM_INLINE glm::vec<3, T, Q> yyy(const glm::vec<2, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.y, v.y); } template GLM_INLINE glm::vec<3, T, Q> yyy(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.y, v.y); } template GLM_INLINE glm::vec<3, T, Q> yyy(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.y, v.y); } // yyz template GLM_INLINE glm::vec<3, T, Q> yyz(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.y, v.z); } template GLM_INLINE glm::vec<3, T, Q> yyz(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.y, v.z); } // yyw template GLM_INLINE glm::vec<3, T, Q> yyw(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.y, v.w); } // yzx template GLM_INLINE glm::vec<3, T, Q> yzx(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.z, v.x); } template GLM_INLINE glm::vec<3, T, Q> yzx(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.z, v.x); } // yzy template GLM_INLINE glm::vec<3, T, Q> yzy(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.z, v.y); } template GLM_INLINE glm::vec<3, T, Q> yzy(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.z, v.y); } // yzz template GLM_INLINE glm::vec<3, T, Q> yzz(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.z, v.z); } template GLM_INLINE glm::vec<3, T, Q> yzz(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.z, v.z); } // yzw template GLM_INLINE glm::vec<3, T, Q> yzw(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.z, v.w); } // ywx template GLM_INLINE glm::vec<3, T, Q> ywx(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.w, v.x); } // ywy template GLM_INLINE glm::vec<3, T, Q> ywy(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.w, v.y); } // ywz template GLM_INLINE glm::vec<3, T, Q> ywz(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.w, v.z); } // yww template GLM_INLINE glm::vec<3, T, Q> yww(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.y, v.w, v.w); } // zxx template GLM_INLINE glm::vec<3, T, Q> zxx(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.x, v.x); } template GLM_INLINE glm::vec<3, T, Q> zxx(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.x, v.x); } // zxy template GLM_INLINE glm::vec<3, T, Q> zxy(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.x, v.y); } template GLM_INLINE glm::vec<3, T, Q> zxy(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.x, v.y); } // zxz template GLM_INLINE glm::vec<3, T, Q> zxz(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.x, v.z); } template GLM_INLINE glm::vec<3, T, Q> zxz(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.x, v.z); } // zxw template GLM_INLINE glm::vec<3, T, Q> zxw(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.x, v.w); } // zyx template GLM_INLINE glm::vec<3, T, Q> zyx(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.y, v.x); } template GLM_INLINE glm::vec<3, T, Q> zyx(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.y, v.x); } // zyy template GLM_INLINE glm::vec<3, T, Q> zyy(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.y, v.y); } template GLM_INLINE glm::vec<3, T, Q> zyy(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.y, v.y); } // zyz template GLM_INLINE glm::vec<3, T, Q> zyz(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.y, v.z); } template GLM_INLINE glm::vec<3, T, Q> zyz(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.y, v.z); } // zyw template GLM_INLINE glm::vec<3, T, Q> zyw(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.y, v.w); } // zzx template GLM_INLINE glm::vec<3, T, Q> zzx(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.z, v.x); } template GLM_INLINE glm::vec<3, T, Q> zzx(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.z, v.x); } // zzy template GLM_INLINE glm::vec<3, T, Q> zzy(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.z, v.y); } template GLM_INLINE glm::vec<3, T, Q> zzy(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.z, v.y); } // zzz template GLM_INLINE glm::vec<3, T, Q> zzz(const glm::vec<3, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.z, v.z); } template GLM_INLINE glm::vec<3, T, Q> zzz(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.z, v.z); } // zzw template GLM_INLINE glm::vec<3, T, Q> zzw(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.z, v.w); } // zwx template GLM_INLINE glm::vec<3, T, Q> zwx(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.w, v.x); } // zwy template GLM_INLINE glm::vec<3, T, Q> zwy(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.w, v.y); } // zwz template GLM_INLINE glm::vec<3, T, Q> zwz(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.w, v.z); } // zww template GLM_INLINE glm::vec<3, T, Q> zww(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.z, v.w, v.w); } // wxx template GLM_INLINE glm::vec<3, T, Q> wxx(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.w, v.x, v.x); } // wxy template GLM_INLINE glm::vec<3, T, Q> wxy(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.w, v.x, v.y); } // wxz template GLM_INLINE glm::vec<3, T, Q> wxz(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.w, v.x, v.z); } // wxw template GLM_INLINE glm::vec<3, T, Q> wxw(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.w, v.x, v.w); } // wyx template GLM_INLINE glm::vec<3, T, Q> wyx(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.w, v.y, v.x); } // wyy template GLM_INLINE glm::vec<3, T, Q> wyy(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.w, v.y, v.y); } // wyz template GLM_INLINE glm::vec<3, T, Q> wyz(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.w, v.y, v.z); } // wyw template GLM_INLINE glm::vec<3, T, Q> wyw(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.w, v.y, v.w); } // wzx template GLM_INLINE glm::vec<3, T, Q> wzx(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.w, v.z, v.x); } // wzy template GLM_INLINE glm::vec<3, T, Q> wzy(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.w, v.z, v.y); } // wzz template GLM_INLINE glm::vec<3, T, Q> wzz(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.w, v.z, v.z); } // wzw template GLM_INLINE glm::vec<3, T, Q> wzw(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.w, v.z, v.w); } // wwx template GLM_INLINE glm::vec<3, T, Q> wwx(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.w, v.w, v.x); } // wwy template GLM_INLINE glm::vec<3, T, Q> wwy(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.w, v.w, v.y); } // wwz template GLM_INLINE glm::vec<3, T, Q> wwz(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.w, v.w, v.z); } // www template GLM_INLINE glm::vec<3, T, Q> www(const glm::vec<4, T, Q> &v) { return glm::vec<3, T, Q>(v.w, v.w, v.w); } // xxxx template GLM_INLINE glm::vec<4, T, Q> xxxx(const glm::vec<1, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.x, v.x); } template GLM_INLINE glm::vec<4, T, Q> xxxx(const glm::vec<2, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.x, v.x); } template GLM_INLINE glm::vec<4, T, Q> xxxx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.x, v.x); } template GLM_INLINE glm::vec<4, T, Q> xxxx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.x, v.x); } // xxxy template GLM_INLINE glm::vec<4, T, Q> xxxy(const glm::vec<2, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.x, v.y); } template GLM_INLINE glm::vec<4, T, Q> xxxy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.x, v.y); } template GLM_INLINE glm::vec<4, T, Q> xxxy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.x, v.y); } // xxxz template GLM_INLINE glm::vec<4, T, Q> xxxz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.x, v.z); } template GLM_INLINE glm::vec<4, T, Q> xxxz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.x, v.z); } // xxxw template GLM_INLINE glm::vec<4, T, Q> xxxw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.x, v.w); } // xxyx template GLM_INLINE glm::vec<4, T, Q> xxyx(const glm::vec<2, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.y, v.x); } template GLM_INLINE glm::vec<4, T, Q> xxyx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.y, v.x); } template GLM_INLINE glm::vec<4, T, Q> xxyx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.y, v.x); } // xxyy template GLM_INLINE glm::vec<4, T, Q> xxyy(const glm::vec<2, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.y, v.y); } template GLM_INLINE glm::vec<4, T, Q> xxyy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.y, v.y); } template GLM_INLINE glm::vec<4, T, Q> xxyy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.y, v.y); } // xxyz template GLM_INLINE glm::vec<4, T, Q> xxyz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.y, v.z); } template GLM_INLINE glm::vec<4, T, Q> xxyz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.y, v.z); } // xxyw template GLM_INLINE glm::vec<4, T, Q> xxyw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.y, v.w); } // xxzx template GLM_INLINE glm::vec<4, T, Q> xxzx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.z, v.x); } template GLM_INLINE glm::vec<4, T, Q> xxzx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.z, v.x); } // xxzy template GLM_INLINE glm::vec<4, T, Q> xxzy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.z, v.y); } template GLM_INLINE glm::vec<4, T, Q> xxzy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.z, v.y); } // xxzz template GLM_INLINE glm::vec<4, T, Q> xxzz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.z, v.z); } template GLM_INLINE glm::vec<4, T, Q> xxzz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.z, v.z); } // xxzw template GLM_INLINE glm::vec<4, T, Q> xxzw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.z, v.w); } // xxwx template GLM_INLINE glm::vec<4, T, Q> xxwx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.w, v.x); } // xxwy template GLM_INLINE glm::vec<4, T, Q> xxwy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.w, v.y); } // xxwz template GLM_INLINE glm::vec<4, T, Q> xxwz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.w, v.z); } // xxww template GLM_INLINE glm::vec<4, T, Q> xxww(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.x, v.w, v.w); } // xyxx template GLM_INLINE glm::vec<4, T, Q> xyxx(const glm::vec<2, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.x, v.x); } template GLM_INLINE glm::vec<4, T, Q> xyxx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.x, v.x); } template GLM_INLINE glm::vec<4, T, Q> xyxx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.x, v.x); } // xyxy template GLM_INLINE glm::vec<4, T, Q> xyxy(const glm::vec<2, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.x, v.y); } template GLM_INLINE glm::vec<4, T, Q> xyxy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.x, v.y); } template GLM_INLINE glm::vec<4, T, Q> xyxy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.x, v.y); } // xyxz template GLM_INLINE glm::vec<4, T, Q> xyxz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.x, v.z); } template GLM_INLINE glm::vec<4, T, Q> xyxz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.x, v.z); } // xyxw template GLM_INLINE glm::vec<4, T, Q> xyxw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.x, v.w); } // xyyx template GLM_INLINE glm::vec<4, T, Q> xyyx(const glm::vec<2, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.y, v.x); } template GLM_INLINE glm::vec<4, T, Q> xyyx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.y, v.x); } template GLM_INLINE glm::vec<4, T, Q> xyyx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.y, v.x); } // xyyy template GLM_INLINE glm::vec<4, T, Q> xyyy(const glm::vec<2, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.y, v.y); } template GLM_INLINE glm::vec<4, T, Q> xyyy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.y, v.y); } template GLM_INLINE glm::vec<4, T, Q> xyyy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.y, v.y); } // xyyz template GLM_INLINE glm::vec<4, T, Q> xyyz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.y, v.z); } template GLM_INLINE glm::vec<4, T, Q> xyyz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.y, v.z); } // xyyw template GLM_INLINE glm::vec<4, T, Q> xyyw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.y, v.w); } // xyzx template GLM_INLINE glm::vec<4, T, Q> xyzx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.z, v.x); } template GLM_INLINE glm::vec<4, T, Q> xyzx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.z, v.x); } // xyzy template GLM_INLINE glm::vec<4, T, Q> xyzy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.z, v.y); } template GLM_INLINE glm::vec<4, T, Q> xyzy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.z, v.y); } // xyzz template GLM_INLINE glm::vec<4, T, Q> xyzz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.z, v.z); } template GLM_INLINE glm::vec<4, T, Q> xyzz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.z, v.z); } // xyzw template GLM_INLINE glm::vec<4, T, Q> xyzw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.z, v.w); } // xywx template GLM_INLINE glm::vec<4, T, Q> xywx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.w, v.x); } // xywy template GLM_INLINE glm::vec<4, T, Q> xywy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.w, v.y); } // xywz template GLM_INLINE glm::vec<4, T, Q> xywz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.w, v.z); } // xyww template GLM_INLINE glm::vec<4, T, Q> xyww(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.y, v.w, v.w); } // xzxx template GLM_INLINE glm::vec<4, T, Q> xzxx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.x, v.x); } template GLM_INLINE glm::vec<4, T, Q> xzxx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.x, v.x); } // xzxy template GLM_INLINE glm::vec<4, T, Q> xzxy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.x, v.y); } template GLM_INLINE glm::vec<4, T, Q> xzxy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.x, v.y); } // xzxz template GLM_INLINE glm::vec<4, T, Q> xzxz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.x, v.z); } template GLM_INLINE glm::vec<4, T, Q> xzxz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.x, v.z); } // xzxw template GLM_INLINE glm::vec<4, T, Q> xzxw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.x, v.w); } // xzyx template GLM_INLINE glm::vec<4, T, Q> xzyx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.y, v.x); } template GLM_INLINE glm::vec<4, T, Q> xzyx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.y, v.x); } // xzyy template GLM_INLINE glm::vec<4, T, Q> xzyy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.y, v.y); } template GLM_INLINE glm::vec<4, T, Q> xzyy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.y, v.y); } // xzyz template GLM_INLINE glm::vec<4, T, Q> xzyz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.y, v.z); } template GLM_INLINE glm::vec<4, T, Q> xzyz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.y, v.z); } // xzyw template GLM_INLINE glm::vec<4, T, Q> xzyw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.y, v.w); } // xzzx template GLM_INLINE glm::vec<4, T, Q> xzzx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.z, v.x); } template GLM_INLINE glm::vec<4, T, Q> xzzx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.z, v.x); } // xzzy template GLM_INLINE glm::vec<4, T, Q> xzzy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.z, v.y); } template GLM_INLINE glm::vec<4, T, Q> xzzy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.z, v.y); } // xzzz template GLM_INLINE glm::vec<4, T, Q> xzzz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.z, v.z); } template GLM_INLINE glm::vec<4, T, Q> xzzz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.z, v.z); } // xzzw template GLM_INLINE glm::vec<4, T, Q> xzzw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.z, v.w); } // xzwx template GLM_INLINE glm::vec<4, T, Q> xzwx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.w, v.x); } // xzwy template GLM_INLINE glm::vec<4, T, Q> xzwy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.w, v.y); } // xzwz template GLM_INLINE glm::vec<4, T, Q> xzwz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.w, v.z); } // xzww template GLM_INLINE glm::vec<4, T, Q> xzww(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.z, v.w, v.w); } // xwxx template GLM_INLINE glm::vec<4, T, Q> xwxx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.w, v.x, v.x); } // xwxy template GLM_INLINE glm::vec<4, T, Q> xwxy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.w, v.x, v.y); } // xwxz template GLM_INLINE glm::vec<4, T, Q> xwxz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.w, v.x, v.z); } // xwxw template GLM_INLINE glm::vec<4, T, Q> xwxw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.w, v.x, v.w); } // xwyx template GLM_INLINE glm::vec<4, T, Q> xwyx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.w, v.y, v.x); } // xwyy template GLM_INLINE glm::vec<4, T, Q> xwyy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.w, v.y, v.y); } // xwyz template GLM_INLINE glm::vec<4, T, Q> xwyz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.w, v.y, v.z); } // xwyw template GLM_INLINE glm::vec<4, T, Q> xwyw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.w, v.y, v.w); } // xwzx template GLM_INLINE glm::vec<4, T, Q> xwzx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.w, v.z, v.x); } // xwzy template GLM_INLINE glm::vec<4, T, Q> xwzy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.w, v.z, v.y); } // xwzz template GLM_INLINE glm::vec<4, T, Q> xwzz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.w, v.z, v.z); } // xwzw template GLM_INLINE glm::vec<4, T, Q> xwzw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.w, v.z, v.w); } // xwwx template GLM_INLINE glm::vec<4, T, Q> xwwx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.w, v.w, v.x); } // xwwy template GLM_INLINE glm::vec<4, T, Q> xwwy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.w, v.w, v.y); } // xwwz template GLM_INLINE glm::vec<4, T, Q> xwwz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.w, v.w, v.z); } // xwww template GLM_INLINE glm::vec<4, T, Q> xwww(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.x, v.w, v.w, v.w); } // yxxx template GLM_INLINE glm::vec<4, T, Q> yxxx(const glm::vec<2, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.x, v.x); } template GLM_INLINE glm::vec<4, T, Q> yxxx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.x, v.x); } template GLM_INLINE glm::vec<4, T, Q> yxxx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.x, v.x); } // yxxy template GLM_INLINE glm::vec<4, T, Q> yxxy(const glm::vec<2, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.x, v.y); } template GLM_INLINE glm::vec<4, T, Q> yxxy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.x, v.y); } template GLM_INLINE glm::vec<4, T, Q> yxxy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.x, v.y); } // yxxz template GLM_INLINE glm::vec<4, T, Q> yxxz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.x, v.z); } template GLM_INLINE glm::vec<4, T, Q> yxxz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.x, v.z); } // yxxw template GLM_INLINE glm::vec<4, T, Q> yxxw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.x, v.w); } // yxyx template GLM_INLINE glm::vec<4, T, Q> yxyx(const glm::vec<2, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.y, v.x); } template GLM_INLINE glm::vec<4, T, Q> yxyx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.y, v.x); } template GLM_INLINE glm::vec<4, T, Q> yxyx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.y, v.x); } // yxyy template GLM_INLINE glm::vec<4, T, Q> yxyy(const glm::vec<2, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.y, v.y); } template GLM_INLINE glm::vec<4, T, Q> yxyy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.y, v.y); } template GLM_INLINE glm::vec<4, T, Q> yxyy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.y, v.y); } // yxyz template GLM_INLINE glm::vec<4, T, Q> yxyz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.y, v.z); } template GLM_INLINE glm::vec<4, T, Q> yxyz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.y, v.z); } // yxyw template GLM_INLINE glm::vec<4, T, Q> yxyw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.y, v.w); } // yxzx template GLM_INLINE glm::vec<4, T, Q> yxzx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.z, v.x); } template GLM_INLINE glm::vec<4, T, Q> yxzx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.z, v.x); } // yxzy template GLM_INLINE glm::vec<4, T, Q> yxzy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.z, v.y); } template GLM_INLINE glm::vec<4, T, Q> yxzy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.z, v.y); } // yxzz template GLM_INLINE glm::vec<4, T, Q> yxzz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.z, v.z); } template GLM_INLINE glm::vec<4, T, Q> yxzz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.z, v.z); } // yxzw template GLM_INLINE glm::vec<4, T, Q> yxzw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.z, v.w); } // yxwx template GLM_INLINE glm::vec<4, T, Q> yxwx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.w, v.x); } // yxwy template GLM_INLINE glm::vec<4, T, Q> yxwy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.w, v.y); } // yxwz template GLM_INLINE glm::vec<4, T, Q> yxwz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.w, v.z); } // yxww template GLM_INLINE glm::vec<4, T, Q> yxww(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.x, v.w, v.w); } // yyxx template GLM_INLINE glm::vec<4, T, Q> yyxx(const glm::vec<2, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.x, v.x); } template GLM_INLINE glm::vec<4, T, Q> yyxx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.x, v.x); } template GLM_INLINE glm::vec<4, T, Q> yyxx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.x, v.x); } // yyxy template GLM_INLINE glm::vec<4, T, Q> yyxy(const glm::vec<2, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.x, v.y); } template GLM_INLINE glm::vec<4, T, Q> yyxy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.x, v.y); } template GLM_INLINE glm::vec<4, T, Q> yyxy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.x, v.y); } // yyxz template GLM_INLINE glm::vec<4, T, Q> yyxz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.x, v.z); } template GLM_INLINE glm::vec<4, T, Q> yyxz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.x, v.z); } // yyxw template GLM_INLINE glm::vec<4, T, Q> yyxw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.x, v.w); } // yyyx template GLM_INLINE glm::vec<4, T, Q> yyyx(const glm::vec<2, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.y, v.x); } template GLM_INLINE glm::vec<4, T, Q> yyyx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.y, v.x); } template GLM_INLINE glm::vec<4, T, Q> yyyx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.y, v.x); } // yyyy template GLM_INLINE glm::vec<4, T, Q> yyyy(const glm::vec<2, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.y, v.y); } template GLM_INLINE glm::vec<4, T, Q> yyyy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.y, v.y); } template GLM_INLINE glm::vec<4, T, Q> yyyy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.y, v.y); } // yyyz template GLM_INLINE glm::vec<4, T, Q> yyyz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.y, v.z); } template GLM_INLINE glm::vec<4, T, Q> yyyz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.y, v.z); } // yyyw template GLM_INLINE glm::vec<4, T, Q> yyyw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.y, v.w); } // yyzx template GLM_INLINE glm::vec<4, T, Q> yyzx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.z, v.x); } template GLM_INLINE glm::vec<4, T, Q> yyzx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.z, v.x); } // yyzy template GLM_INLINE glm::vec<4, T, Q> yyzy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.z, v.y); } template GLM_INLINE glm::vec<4, T, Q> yyzy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.z, v.y); } // yyzz template GLM_INLINE glm::vec<4, T, Q> yyzz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.z, v.z); } template GLM_INLINE glm::vec<4, T, Q> yyzz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.z, v.z); } // yyzw template GLM_INLINE glm::vec<4, T, Q> yyzw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.z, v.w); } // yywx template GLM_INLINE glm::vec<4, T, Q> yywx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.w, v.x); } // yywy template GLM_INLINE glm::vec<4, T, Q> yywy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.w, v.y); } // yywz template GLM_INLINE glm::vec<4, T, Q> yywz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.w, v.z); } // yyww template GLM_INLINE glm::vec<4, T, Q> yyww(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.y, v.w, v.w); } // yzxx template GLM_INLINE glm::vec<4, T, Q> yzxx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.x, v.x); } template GLM_INLINE glm::vec<4, T, Q> yzxx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.x, v.x); } // yzxy template GLM_INLINE glm::vec<4, T, Q> yzxy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.x, v.y); } template GLM_INLINE glm::vec<4, T, Q> yzxy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.x, v.y); } // yzxz template GLM_INLINE glm::vec<4, T, Q> yzxz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.x, v.z); } template GLM_INLINE glm::vec<4, T, Q> yzxz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.x, v.z); } // yzxw template GLM_INLINE glm::vec<4, T, Q> yzxw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.x, v.w); } // yzyx template GLM_INLINE glm::vec<4, T, Q> yzyx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.y, v.x); } template GLM_INLINE glm::vec<4, T, Q> yzyx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.y, v.x); } // yzyy template GLM_INLINE glm::vec<4, T, Q> yzyy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.y, v.y); } template GLM_INLINE glm::vec<4, T, Q> yzyy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.y, v.y); } // yzyz template GLM_INLINE glm::vec<4, T, Q> yzyz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.y, v.z); } template GLM_INLINE glm::vec<4, T, Q> yzyz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.y, v.z); } // yzyw template GLM_INLINE glm::vec<4, T, Q> yzyw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.y, v.w); } // yzzx template GLM_INLINE glm::vec<4, T, Q> yzzx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.z, v.x); } template GLM_INLINE glm::vec<4, T, Q> yzzx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.z, v.x); } // yzzy template GLM_INLINE glm::vec<4, T, Q> yzzy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.z, v.y); } template GLM_INLINE glm::vec<4, T, Q> yzzy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.z, v.y); } // yzzz template GLM_INLINE glm::vec<4, T, Q> yzzz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.z, v.z); } template GLM_INLINE glm::vec<4, T, Q> yzzz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.z, v.z); } // yzzw template GLM_INLINE glm::vec<4, T, Q> yzzw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.z, v.w); } // yzwx template GLM_INLINE glm::vec<4, T, Q> yzwx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.w, v.x); } // yzwy template GLM_INLINE glm::vec<4, T, Q> yzwy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.w, v.y); } // yzwz template GLM_INLINE glm::vec<4, T, Q> yzwz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.w, v.z); } // yzww template GLM_INLINE glm::vec<4, T, Q> yzww(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.z, v.w, v.w); } // ywxx template GLM_INLINE glm::vec<4, T, Q> ywxx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.w, v.x, v.x); } // ywxy template GLM_INLINE glm::vec<4, T, Q> ywxy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.w, v.x, v.y); } // ywxz template GLM_INLINE glm::vec<4, T, Q> ywxz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.w, v.x, v.z); } // ywxw template GLM_INLINE glm::vec<4, T, Q> ywxw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.w, v.x, v.w); } // ywyx template GLM_INLINE glm::vec<4, T, Q> ywyx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.w, v.y, v.x); } // ywyy template GLM_INLINE glm::vec<4, T, Q> ywyy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.w, v.y, v.y); } // ywyz template GLM_INLINE glm::vec<4, T, Q> ywyz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.w, v.y, v.z); } // ywyw template GLM_INLINE glm::vec<4, T, Q> ywyw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.w, v.y, v.w); } // ywzx template GLM_INLINE glm::vec<4, T, Q> ywzx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.w, v.z, v.x); } // ywzy template GLM_INLINE glm::vec<4, T, Q> ywzy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.w, v.z, v.y); } // ywzz template GLM_INLINE glm::vec<4, T, Q> ywzz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.w, v.z, v.z); } // ywzw template GLM_INLINE glm::vec<4, T, Q> ywzw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.w, v.z, v.w); } // ywwx template GLM_INLINE glm::vec<4, T, Q> ywwx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.w, v.w, v.x); } // ywwy template GLM_INLINE glm::vec<4, T, Q> ywwy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.w, v.w, v.y); } // ywwz template GLM_INLINE glm::vec<4, T, Q> ywwz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.w, v.w, v.z); } // ywww template GLM_INLINE glm::vec<4, T, Q> ywww(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.y, v.w, v.w, v.w); } // zxxx template GLM_INLINE glm::vec<4, T, Q> zxxx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.x, v.x); } template GLM_INLINE glm::vec<4, T, Q> zxxx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.x, v.x); } // zxxy template GLM_INLINE glm::vec<4, T, Q> zxxy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.x, v.y); } template GLM_INLINE glm::vec<4, T, Q> zxxy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.x, v.y); } // zxxz template GLM_INLINE glm::vec<4, T, Q> zxxz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.x, v.z); } template GLM_INLINE glm::vec<4, T, Q> zxxz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.x, v.z); } // zxxw template GLM_INLINE glm::vec<4, T, Q> zxxw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.x, v.w); } // zxyx template GLM_INLINE glm::vec<4, T, Q> zxyx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.y, v.x); } template GLM_INLINE glm::vec<4, T, Q> zxyx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.y, v.x); } // zxyy template GLM_INLINE glm::vec<4, T, Q> zxyy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.y, v.y); } template GLM_INLINE glm::vec<4, T, Q> zxyy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.y, v.y); } // zxyz template GLM_INLINE glm::vec<4, T, Q> zxyz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.y, v.z); } template GLM_INLINE glm::vec<4, T, Q> zxyz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.y, v.z); } // zxyw template GLM_INLINE glm::vec<4, T, Q> zxyw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.y, v.w); } // zxzx template GLM_INLINE glm::vec<4, T, Q> zxzx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.z, v.x); } template GLM_INLINE glm::vec<4, T, Q> zxzx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.z, v.x); } // zxzy template GLM_INLINE glm::vec<4, T, Q> zxzy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.z, v.y); } template GLM_INLINE glm::vec<4, T, Q> zxzy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.z, v.y); } // zxzz template GLM_INLINE glm::vec<4, T, Q> zxzz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.z, v.z); } template GLM_INLINE glm::vec<4, T, Q> zxzz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.z, v.z); } // zxzw template GLM_INLINE glm::vec<4, T, Q> zxzw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.z, v.w); } // zxwx template GLM_INLINE glm::vec<4, T, Q> zxwx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.w, v.x); } // zxwy template GLM_INLINE glm::vec<4, T, Q> zxwy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.w, v.y); } // zxwz template GLM_INLINE glm::vec<4, T, Q> zxwz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.w, v.z); } // zxww template GLM_INLINE glm::vec<4, T, Q> zxww(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.x, v.w, v.w); } // zyxx template GLM_INLINE glm::vec<4, T, Q> zyxx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.x, v.x); } template GLM_INLINE glm::vec<4, T, Q> zyxx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.x, v.x); } // zyxy template GLM_INLINE glm::vec<4, T, Q> zyxy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.x, v.y); } template GLM_INLINE glm::vec<4, T, Q> zyxy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.x, v.y); } // zyxz template GLM_INLINE glm::vec<4, T, Q> zyxz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.x, v.z); } template GLM_INLINE glm::vec<4, T, Q> zyxz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.x, v.z); } // zyxw template GLM_INLINE glm::vec<4, T, Q> zyxw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.x, v.w); } // zyyx template GLM_INLINE glm::vec<4, T, Q> zyyx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.y, v.x); } template GLM_INLINE glm::vec<4, T, Q> zyyx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.y, v.x); } // zyyy template GLM_INLINE glm::vec<4, T, Q> zyyy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.y, v.y); } template GLM_INLINE glm::vec<4, T, Q> zyyy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.y, v.y); } // zyyz template GLM_INLINE glm::vec<4, T, Q> zyyz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.y, v.z); } template GLM_INLINE glm::vec<4, T, Q> zyyz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.y, v.z); } // zyyw template GLM_INLINE glm::vec<4, T, Q> zyyw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.y, v.w); } // zyzx template GLM_INLINE glm::vec<4, T, Q> zyzx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.z, v.x); } template GLM_INLINE glm::vec<4, T, Q> zyzx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.z, v.x); } // zyzy template GLM_INLINE glm::vec<4, T, Q> zyzy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.z, v.y); } template GLM_INLINE glm::vec<4, T, Q> zyzy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.z, v.y); } // zyzz template GLM_INLINE glm::vec<4, T, Q> zyzz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.z, v.z); } template GLM_INLINE glm::vec<4, T, Q> zyzz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.z, v.z); } // zyzw template GLM_INLINE glm::vec<4, T, Q> zyzw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.z, v.w); } // zywx template GLM_INLINE glm::vec<4, T, Q> zywx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.w, v.x); } // zywy template GLM_INLINE glm::vec<4, T, Q> zywy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.w, v.y); } // zywz template GLM_INLINE glm::vec<4, T, Q> zywz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.w, v.z); } // zyww template GLM_INLINE glm::vec<4, T, Q> zyww(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.y, v.w, v.w); } // zzxx template GLM_INLINE glm::vec<4, T, Q> zzxx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.x, v.x); } template GLM_INLINE glm::vec<4, T, Q> zzxx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.x, v.x); } // zzxy template GLM_INLINE glm::vec<4, T, Q> zzxy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.x, v.y); } template GLM_INLINE glm::vec<4, T, Q> zzxy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.x, v.y); } // zzxz template GLM_INLINE glm::vec<4, T, Q> zzxz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.x, v.z); } template GLM_INLINE glm::vec<4, T, Q> zzxz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.x, v.z); } // zzxw template GLM_INLINE glm::vec<4, T, Q> zzxw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.x, v.w); } // zzyx template GLM_INLINE glm::vec<4, T, Q> zzyx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.y, v.x); } template GLM_INLINE glm::vec<4, T, Q> zzyx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.y, v.x); } // zzyy template GLM_INLINE glm::vec<4, T, Q> zzyy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.y, v.y); } template GLM_INLINE glm::vec<4, T, Q> zzyy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.y, v.y); } // zzyz template GLM_INLINE glm::vec<4, T, Q> zzyz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.y, v.z); } template GLM_INLINE glm::vec<4, T, Q> zzyz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.y, v.z); } // zzyw template GLM_INLINE glm::vec<4, T, Q> zzyw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.y, v.w); } // zzzx template GLM_INLINE glm::vec<4, T, Q> zzzx(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.z, v.x); } template GLM_INLINE glm::vec<4, T, Q> zzzx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.z, v.x); } // zzzy template GLM_INLINE glm::vec<4, T, Q> zzzy(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.z, v.y); } template GLM_INLINE glm::vec<4, T, Q> zzzy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.z, v.y); } // zzzz template GLM_INLINE glm::vec<4, T, Q> zzzz(const glm::vec<3, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.z, v.z); } template GLM_INLINE glm::vec<4, T, Q> zzzz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.z, v.z); } // zzzw template GLM_INLINE glm::vec<4, T, Q> zzzw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.z, v.w); } // zzwx template GLM_INLINE glm::vec<4, T, Q> zzwx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.w, v.x); } // zzwy template GLM_INLINE glm::vec<4, T, Q> zzwy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.w, v.y); } // zzwz template GLM_INLINE glm::vec<4, T, Q> zzwz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.w, v.z); } // zzww template GLM_INLINE glm::vec<4, T, Q> zzww(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.z, v.w, v.w); } // zwxx template GLM_INLINE glm::vec<4, T, Q> zwxx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.w, v.x, v.x); } // zwxy template GLM_INLINE glm::vec<4, T, Q> zwxy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.w, v.x, v.y); } // zwxz template GLM_INLINE glm::vec<4, T, Q> zwxz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.w, v.x, v.z); } // zwxw template GLM_INLINE glm::vec<4, T, Q> zwxw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.w, v.x, v.w); } // zwyx template GLM_INLINE glm::vec<4, T, Q> zwyx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.w, v.y, v.x); } // zwyy template GLM_INLINE glm::vec<4, T, Q> zwyy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.w, v.y, v.y); } // zwyz template GLM_INLINE glm::vec<4, T, Q> zwyz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.w, v.y, v.z); } // zwyw template GLM_INLINE glm::vec<4, T, Q> zwyw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.w, v.y, v.w); } // zwzx template GLM_INLINE glm::vec<4, T, Q> zwzx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.w, v.z, v.x); } // zwzy template GLM_INLINE glm::vec<4, T, Q> zwzy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.w, v.z, v.y); } // zwzz template GLM_INLINE glm::vec<4, T, Q> zwzz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.w, v.z, v.z); } // zwzw template GLM_INLINE glm::vec<4, T, Q> zwzw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.w, v.z, v.w); } // zwwx template GLM_INLINE glm::vec<4, T, Q> zwwx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.w, v.w, v.x); } // zwwy template GLM_INLINE glm::vec<4, T, Q> zwwy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.w, v.w, v.y); } // zwwz template GLM_INLINE glm::vec<4, T, Q> zwwz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.w, v.w, v.z); } // zwww template GLM_INLINE glm::vec<4, T, Q> zwww(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.z, v.w, v.w, v.w); } // wxxx template GLM_INLINE glm::vec<4, T, Q> wxxx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.x, v.x, v.x); } // wxxy template GLM_INLINE glm::vec<4, T, Q> wxxy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.x, v.x, v.y); } // wxxz template GLM_INLINE glm::vec<4, T, Q> wxxz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.x, v.x, v.z); } // wxxw template GLM_INLINE glm::vec<4, T, Q> wxxw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.x, v.x, v.w); } // wxyx template GLM_INLINE glm::vec<4, T, Q> wxyx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.x, v.y, v.x); } // wxyy template GLM_INLINE glm::vec<4, T, Q> wxyy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.x, v.y, v.y); } // wxyz template GLM_INLINE glm::vec<4, T, Q> wxyz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.x, v.y, v.z); } // wxyw template GLM_INLINE glm::vec<4, T, Q> wxyw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.x, v.y, v.w); } // wxzx template GLM_INLINE glm::vec<4, T, Q> wxzx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.x, v.z, v.x); } // wxzy template GLM_INLINE glm::vec<4, T, Q> wxzy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.x, v.z, v.y); } // wxzz template GLM_INLINE glm::vec<4, T, Q> wxzz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.x, v.z, v.z); } // wxzw template GLM_INLINE glm::vec<4, T, Q> wxzw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.x, v.z, v.w); } // wxwx template GLM_INLINE glm::vec<4, T, Q> wxwx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.x, v.w, v.x); } // wxwy template GLM_INLINE glm::vec<4, T, Q> wxwy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.x, v.w, v.y); } // wxwz template GLM_INLINE glm::vec<4, T, Q> wxwz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.x, v.w, v.z); } // wxww template GLM_INLINE glm::vec<4, T, Q> wxww(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.x, v.w, v.w); } // wyxx template GLM_INLINE glm::vec<4, T, Q> wyxx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.y, v.x, v.x); } // wyxy template GLM_INLINE glm::vec<4, T, Q> wyxy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.y, v.x, v.y); } // wyxz template GLM_INLINE glm::vec<4, T, Q> wyxz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.y, v.x, v.z); } // wyxw template GLM_INLINE glm::vec<4, T, Q> wyxw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.y, v.x, v.w); } // wyyx template GLM_INLINE glm::vec<4, T, Q> wyyx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.y, v.y, v.x); } // wyyy template GLM_INLINE glm::vec<4, T, Q> wyyy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.y, v.y, v.y); } // wyyz template GLM_INLINE glm::vec<4, T, Q> wyyz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.y, v.y, v.z); } // wyyw template GLM_INLINE glm::vec<4, T, Q> wyyw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.y, v.y, v.w); } // wyzx template GLM_INLINE glm::vec<4, T, Q> wyzx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.y, v.z, v.x); } // wyzy template GLM_INLINE glm::vec<4, T, Q> wyzy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.y, v.z, v.y); } // wyzz template GLM_INLINE glm::vec<4, T, Q> wyzz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.y, v.z, v.z); } // wyzw template GLM_INLINE glm::vec<4, T, Q> wyzw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.y, v.z, v.w); } // wywx template GLM_INLINE glm::vec<4, T, Q> wywx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.y, v.w, v.x); } // wywy template GLM_INLINE glm::vec<4, T, Q> wywy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.y, v.w, v.y); } // wywz template GLM_INLINE glm::vec<4, T, Q> wywz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.y, v.w, v.z); } // wyww template GLM_INLINE glm::vec<4, T, Q> wyww(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.y, v.w, v.w); } // wzxx template GLM_INLINE glm::vec<4, T, Q> wzxx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.z, v.x, v.x); } // wzxy template GLM_INLINE glm::vec<4, T, Q> wzxy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.z, v.x, v.y); } // wzxz template GLM_INLINE glm::vec<4, T, Q> wzxz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.z, v.x, v.z); } // wzxw template GLM_INLINE glm::vec<4, T, Q> wzxw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.z, v.x, v.w); } // wzyx template GLM_INLINE glm::vec<4, T, Q> wzyx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.z, v.y, v.x); } // wzyy template GLM_INLINE glm::vec<4, T, Q> wzyy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.z, v.y, v.y); } // wzyz template GLM_INLINE glm::vec<4, T, Q> wzyz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.z, v.y, v.z); } // wzyw template GLM_INLINE glm::vec<4, T, Q> wzyw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.z, v.y, v.w); } // wzzx template GLM_INLINE glm::vec<4, T, Q> wzzx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.z, v.z, v.x); } // wzzy template GLM_INLINE glm::vec<4, T, Q> wzzy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.z, v.z, v.y); } // wzzz template GLM_INLINE glm::vec<4, T, Q> wzzz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.z, v.z, v.z); } // wzzw template GLM_INLINE glm::vec<4, T, Q> wzzw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.z, v.z, v.w); } // wzwx template GLM_INLINE glm::vec<4, T, Q> wzwx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.z, v.w, v.x); } // wzwy template GLM_INLINE glm::vec<4, T, Q> wzwy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.z, v.w, v.y); } // wzwz template GLM_INLINE glm::vec<4, T, Q> wzwz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.z, v.w, v.z); } // wzww template GLM_INLINE glm::vec<4, T, Q> wzww(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.z, v.w, v.w); } // wwxx template GLM_INLINE glm::vec<4, T, Q> wwxx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.w, v.x, v.x); } // wwxy template GLM_INLINE glm::vec<4, T, Q> wwxy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.w, v.x, v.y); } // wwxz template GLM_INLINE glm::vec<4, T, Q> wwxz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.w, v.x, v.z); } // wwxw template GLM_INLINE glm::vec<4, T, Q> wwxw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.w, v.x, v.w); } // wwyx template GLM_INLINE glm::vec<4, T, Q> wwyx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.w, v.y, v.x); } // wwyy template GLM_INLINE glm::vec<4, T, Q> wwyy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.w, v.y, v.y); } // wwyz template GLM_INLINE glm::vec<4, T, Q> wwyz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.w, v.y, v.z); } // wwyw template GLM_INLINE glm::vec<4, T, Q> wwyw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.w, v.y, v.w); } // wwzx template GLM_INLINE glm::vec<4, T, Q> wwzx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.w, v.z, v.x); } // wwzy template GLM_INLINE glm::vec<4, T, Q> wwzy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.w, v.z, v.y); } // wwzz template GLM_INLINE glm::vec<4, T, Q> wwzz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.w, v.z, v.z); } // wwzw template GLM_INLINE glm::vec<4, T, Q> wwzw(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.w, v.z, v.w); } // wwwx template GLM_INLINE glm::vec<4, T, Q> wwwx(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.w, v.w, v.x); } // wwwy template GLM_INLINE glm::vec<4, T, Q> wwwy(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.w, v.w, v.y); } // wwwz template GLM_INLINE glm::vec<4, T, Q> wwwz(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.w, v.w, v.z); } // wwww template GLM_INLINE glm::vec<4, T, Q> wwww(const glm::vec<4, T, Q> &v) { return glm::vec<4, T, Q>(v.w, v.w, v.w, v.w); } } connectome-workbench-1.4.2/src/GLMath/glm/gtx/vector_angle.hpp000066400000000000000000000034721360521144700243060ustar00rootroot00000000000000/// @ref gtx_vector_angle /// @file glm/gtx/vector_angle.hpp /// /// @see core (dependence) /// @see gtx_quaternion (dependence) /// @see gtx_epsilon (dependence) /// /// @defgroup gtx_vector_angle GLM_GTX_vector_angle /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Compute angle between vectors #pragma once // Dependency: #include "../glm.hpp" #include "../gtc/epsilon.hpp" #include "../gtx/quaternion.hpp" #include "../gtx/rotate_vector.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_vector_angle is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_vector_angle extension included") # endif #endif namespace glm { /// @addtogroup gtx_vector_angle /// @{ //! Returns the absolute angle between two vectors. //! Parameters need to be normalized. /// @see gtx_vector_angle extension. template GLM_FUNC_DECL T angle(vec const& x, vec const& y); //! Returns the oriented angle between two 2d vectors. //! Parameters need to be normalized. /// @see gtx_vector_angle extension. template GLM_FUNC_DECL T orientedAngle(vec<2, T, Q> const& x, vec<2, T, Q> const& y); //! Returns the oriented angle between two 3d vectors based from a reference axis. //! Parameters need to be normalized. /// @see gtx_vector_angle extension. template GLM_FUNC_DECL T orientedAngle(vec<3, T, Q> const& x, vec<3, T, Q> const& y, vec<3, T, Q> const& ref); /// @} }// namespace glm #include "vector_angle.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/vector_angle.inl000066400000000000000000000026651360521144700243040ustar00rootroot00000000000000/// @ref gtx_vector_angle namespace glm { template GLM_FUNC_QUALIFIER genType angle ( genType const& x, genType const& y ) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'angle' only accept floating-point inputs"); return acos(clamp(dot(x, y), genType(-1), genType(1))); } template GLM_FUNC_QUALIFIER T angle(vec const& x, vec const& y) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'angle' only accept floating-point inputs"); return acos(clamp(dot(x, y), T(-1), T(1))); } //! \todo epsilon is hard coded to 0.01 template GLM_FUNC_QUALIFIER T orientedAngle(vec<2, T, Q> const& x, vec<2, T, Q> const& y) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'orientedAngle' only accept floating-point inputs"); T const Angle(acos(clamp(dot(x, y), T(-1), T(1)))); if(all(epsilonEqual(y, glm::rotate(x, Angle), T(0.0001)))) return Angle; else return -Angle; } template GLM_FUNC_QUALIFIER T orientedAngle(vec<3, T, Q> const& x, vec<3, T, Q> const& y, vec<3, T, Q> const& ref) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'orientedAngle' only accept floating-point inputs"); T const Angle(acos(clamp(dot(x, y), T(-1), T(1)))); return mix(Angle, -Angle, dot(ref, cross(x, y)) < T(0)); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/vector_query.hpp000066400000000000000000000043341360521144700243630ustar00rootroot00000000000000/// @ref gtx_vector_query /// @file glm/gtx/vector_query.hpp /// /// @see core (dependence) /// /// @defgroup gtx_vector_query GLM_GTX_vector_query /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Query informations of vector types #pragma once // Dependency: #include "../glm.hpp" #include #include #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_vector_query is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_vector_query extension included") # endif #endif namespace glm { /// @addtogroup gtx_vector_query /// @{ //! Check whether two vectors are collinears. /// @see gtx_vector_query extensions. template GLM_FUNC_DECL bool areCollinear(vec const& v0, vec const& v1, T const& epsilon); //! Check whether two vectors are orthogonals. /// @see gtx_vector_query extensions. template GLM_FUNC_DECL bool areOrthogonal(vec const& v0, vec const& v1, T const& epsilon); //! Check whether a vector is normalized. /// @see gtx_vector_query extensions. template GLM_FUNC_DECL bool isNormalized(vec const& v, T const& epsilon); //! Check whether a vector is null. /// @see gtx_vector_query extensions. template GLM_FUNC_DECL bool isNull(vec const& v, T const& epsilon); //! Check whether a each component of a vector is null. /// @see gtx_vector_query extensions. template GLM_FUNC_DECL vec isCompNull(vec const& v, T const& epsilon); //! Check whether two vectors are orthonormal. /// @see gtx_vector_query extensions. template GLM_FUNC_DECL bool areOrthonormal(vec const& v0, vec const& v1, T const& epsilon); /// @} }// namespace glm #include "vector_query.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/vector_query.inl000066400000000000000000000110341360521144700243510ustar00rootroot00000000000000/// @ref gtx_vector_query #include namespace glm{ namespace detail { template struct compute_areCollinear{}; template struct compute_areCollinear<2, T, Q> { GLM_FUNC_QUALIFIER static bool call(vec<2, T, Q> const& v0, vec<2, T, Q> const& v1, T const& epsilon) { return length(cross(vec<3, T, Q>(v0, static_cast(0)), vec<3, T, Q>(v1, static_cast(0)))) < epsilon; } }; template struct compute_areCollinear<3, T, Q> { GLM_FUNC_QUALIFIER static bool call(vec<3, T, Q> const& v0, vec<3, T, Q> const& v1, T const& epsilon) { return length(cross(v0, v1)) < epsilon; } }; template struct compute_areCollinear<4, T, Q> { GLM_FUNC_QUALIFIER static bool call(vec<4, T, Q> const& v0, vec<4, T, Q> const& v1, T const& epsilon) { return length(cross(vec<3, T, Q>(v0), vec<3, T, Q>(v1))) < epsilon; } }; template struct compute_isCompNull{}; template struct compute_isCompNull<2, T, Q> { GLM_FUNC_QUALIFIER static vec<2, bool, Q> call(vec<2, T, Q> const& v, T const& epsilon) { return vec<2, bool, Q>( (abs(v.x) < epsilon), (abs(v.y) < epsilon)); } }; template struct compute_isCompNull<3, T, Q> { GLM_FUNC_QUALIFIER static vec<3, bool, Q> call(vec<3, T, Q> const& v, T const& epsilon) { return vec<3, bool, Q>( (abs(v.x) < epsilon), (abs(v.y) < epsilon), (abs(v.z) < epsilon)); } }; template struct compute_isCompNull<4, T, Q> { GLM_FUNC_QUALIFIER static vec<4, bool, Q> call(vec<4, T, Q> const& v, T const& epsilon) { return vec<4, bool, Q>( (abs(v.x) < epsilon), (abs(v.y) < epsilon), (abs(v.z) < epsilon), (abs(v.w) < epsilon)); } }; }//namespace detail template GLM_FUNC_QUALIFIER bool areCollinear(vec const& v0, vec const& v1, T const& epsilon) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'areCollinear' only accept floating-point inputs"); return detail::compute_areCollinear::call(v0, v1, epsilon); } template GLM_FUNC_QUALIFIER bool areOrthogonal(vec const& v0, vec const& v1, T const& epsilon) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'areOrthogonal' only accept floating-point inputs"); return abs(dot(v0, v1)) <= max( static_cast(1), length(v0)) * max(static_cast(1), length(v1)) * epsilon; } template GLM_FUNC_QUALIFIER bool isNormalized(vec const& v, T const& epsilon) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isNormalized' only accept floating-point inputs"); return abs(length(v) - static_cast(1)) <= static_cast(2) * epsilon; } template GLM_FUNC_QUALIFIER bool isNull(vec const& v, T const& epsilon) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isNull' only accept floating-point inputs"); return length(v) <= epsilon; } template GLM_FUNC_QUALIFIER vec isCompNull(vec const& v, T const& epsilon) { GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'isCompNull' only accept floating-point inputs"); return detail::compute_isCompNull::call(v, epsilon); } template GLM_FUNC_QUALIFIER vec<2, bool, Q> isCompNull(vec<2, T, Q> const& v, T const& epsilon) { return vec<2, bool, Q>( abs(v.x) < epsilon, abs(v.y) < epsilon); } template GLM_FUNC_QUALIFIER vec<3, bool, Q> isCompNull(vec<3, T, Q> const& v, T const& epsilon) { return vec<3, bool, Q>( abs(v.x) < epsilon, abs(v.y) < epsilon, abs(v.z) < epsilon); } template GLM_FUNC_QUALIFIER vec<4, bool, Q> isCompNull(vec<4, T, Q> const& v, T const& epsilon) { return vec<4, bool, Q>( abs(v.x) < epsilon, abs(v.y) < epsilon, abs(v.z) < epsilon, abs(v.w) < epsilon); } template GLM_FUNC_QUALIFIER bool areOrthonormal(vec const& v0, vec const& v1, T const& epsilon) { return isNormalized(v0, epsilon) && isNormalized(v1, epsilon) && (abs(dot(v0, v1)) <= epsilon); } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/gtx/wrap.hpp000066400000000000000000000027271360521144700226110ustar00rootroot00000000000000/// @ref gtx_wrap /// @file glm/gtx/wrap.hpp /// /// @see core (dependence) /// /// @defgroup gtx_wrap GLM_GTX_wrap /// @ingroup gtx /// /// Include to use the features of this extension. /// /// Wrapping mode of texture coordinates. #pragma once // Dependency: #include "../glm.hpp" #include "../gtc/vec1.hpp" #if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED) # ifndef GLM_ENABLE_EXPERIMENTAL # pragma message("GLM: GLM_GTX_wrap is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.") # else # pragma message("GLM: GLM_GTX_wrap extension included") # endif #endif namespace glm { /// @addtogroup gtx_wrap /// @{ /// Simulate GL_CLAMP OpenGL wrap mode /// @see gtx_wrap extension. template GLM_FUNC_DECL genType clamp(genType const& Texcoord); /// Simulate GL_REPEAT OpenGL wrap mode /// @see gtx_wrap extension. template GLM_FUNC_DECL genType repeat(genType const& Texcoord); /// Simulate GL_MIRRORED_REPEAT OpenGL wrap mode /// @see gtx_wrap extension. template GLM_FUNC_DECL genType mirrorClamp(genType const& Texcoord); /// Simulate GL_MIRROR_REPEAT OpenGL wrap mode /// @see gtx_wrap extension. template GLM_FUNC_DECL genType mirrorRepeat(genType const& Texcoord); /// @} }// namespace glm #include "wrap.inl" connectome-workbench-1.4.2/src/GLMath/glm/gtx/wrap.inl000066400000000000000000000032661360521144700226030ustar00rootroot00000000000000/// @ref gtx_wrap namespace glm { template GLM_FUNC_QUALIFIER vec clamp(vec const& Texcoord) { return glm::clamp(Texcoord, vec(0), vec(1)); } template GLM_FUNC_QUALIFIER genType clamp(genType const& Texcoord) { return clamp(vec<1, genType, defaultp>(Texcoord)).x; } template GLM_FUNC_QUALIFIER vec repeat(vec const& Texcoord) { return glm::fract(Texcoord); } template GLM_FUNC_QUALIFIER genType repeat(genType const& Texcoord) { return repeat(vec<1, genType, defaultp>(Texcoord)).x; } template GLM_FUNC_QUALIFIER vec mirrorClamp(vec const& Texcoord) { return glm::fract(glm::abs(Texcoord)); } template GLM_FUNC_QUALIFIER genType mirrorClamp(genType const& Texcoord) { return mirrorClamp(vec<1, genType, defaultp>(Texcoord)).x; } template GLM_FUNC_QUALIFIER vec mirrorRepeat(vec const& Texcoord) { vec const Abs = glm::abs(Texcoord); vec const Clamp = glm::mod(glm::floor(Abs), vec(2)); vec const Floor = glm::floor(Abs); vec const Rest = Abs - Floor; vec const Mirror = Clamp + Rest; return mix(Rest, vec(1) - Rest, glm::greaterThanEqual(Mirror, vec(1))); } template GLM_FUNC_QUALIFIER genType mirrorRepeat(genType const& Texcoord) { return mirrorRepeat(vec<1, genType, defaultp>(Texcoord)).x; } }//namespace glm connectome-workbench-1.4.2/src/GLMath/glm/integer.hpp000066400000000000000000000247001360521144700224660ustar00rootroot00000000000000/// @ref core /// @file glm/integer.hpp /// /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions /// /// @defgroup core_func_integer Integer functions /// @ingroup core /// /// Provides GLSL functions on integer types /// /// These all operate component-wise. The description is per component. /// The notation [a, b] means the set of bits from bit-number a through bit-number /// b, inclusive. The lowest-order bit is bit 0. /// /// Include to use these core features. #pragma once #include "detail/qualifier.hpp" #include "common.hpp" #include "vector_relational.hpp" namespace glm { /// @addtogroup core_func_integer /// @{ /// Adds 32-bit unsigned integer x and y, returning the sum /// modulo pow(2, 32). The value carry is set to 0 if the sum was /// less than pow(2, 32), or to 1 otherwise. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// /// @see GLSL uaddCarry man page /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions template GLM_FUNC_DECL vec uaddCarry( vec const& x, vec const& y, vec & carry); /// Subtracts the 32-bit unsigned integer y from x, returning /// the difference if non-negative, or pow(2, 32) plus the difference /// otherwise. The value borrow is set to 0 if x >= y, or to 1 otherwise. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// /// @see GLSL usubBorrow man page /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions template GLM_FUNC_DECL vec usubBorrow( vec const& x, vec const& y, vec & borrow); /// Multiplies 32-bit integers x and y, producing a 64-bit /// result. The 32 least-significant bits are returned in lsb. /// The 32 most-significant bits are returned in msb. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// /// @see GLSL umulExtended man page /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions template GLM_FUNC_DECL void umulExtended( vec const& x, vec const& y, vec & msb, vec & lsb); /// Multiplies 32-bit integers x and y, producing a 64-bit /// result. The 32 least-significant bits are returned in lsb. /// The 32 most-significant bits are returned in msb. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// /// @see GLSL imulExtended man page /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions template GLM_FUNC_DECL void imulExtended( vec const& x, vec const& y, vec & msb, vec & lsb); /// Extracts bits [offset, offset + bits - 1] from value, /// returning them in the least significant bits of the result. /// For unsigned data types, the most significant bits of the /// result will be set to zero. For signed data types, the /// most significant bits will be set to the value of bit offset + base - 1. /// /// If bits is zero, the result will be zero. The result will be /// undefined if offset or bits is negative, or if the sum of /// offset and bits is greater than the number of bits used /// to store the operand. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T Signed or unsigned integer scalar types. /// /// @see GLSL bitfieldExtract man page /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions template GLM_FUNC_DECL vec bitfieldExtract( vec const& Value, int Offset, int Bits); /// Returns the insertion the bits least-significant bits of insert into base. /// /// The result will have bits [offset, offset + bits - 1] taken /// from bits [0, bits - 1] of insert, and all other bits taken /// directly from the corresponding bits of base. If bits is /// zero, the result will simply be base. The result will be /// undefined if offset or bits is negative, or if the sum of /// offset and bits is greater than the number of bits used to /// store the operand. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T Signed or unsigned integer scalar or vector types. /// /// @see GLSL bitfieldInsert man page /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions template GLM_FUNC_DECL vec bitfieldInsert( vec const& Base, vec const& Insert, int Offset, int Bits); /// Returns the reversal of the bits of value. /// The bit numbered n of the result will be taken from bit (bits - 1) - n of value, /// where bits is the total number of bits used to represent value. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T Signed or unsigned integer scalar or vector types. /// /// @see GLSL bitfieldReverse man page /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions template GLM_FUNC_DECL vec bitfieldReverse(vec const& v); /// Returns the number of bits set to 1 in the binary representation of value. /// /// @tparam genType Signed or unsigned integer scalar or vector types. /// /// @see GLSL bitCount man page /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions template GLM_FUNC_DECL int bitCount(genType v); /// Returns the number of bits set to 1 in the binary representation of value. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T Signed or unsigned integer scalar or vector types. /// /// @see GLSL bitCount man page /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions template GLM_FUNC_DECL vec bitCount(vec const& v); /// Returns the bit number of the least significant bit set to /// 1 in the binary representation of value. /// If value is zero, -1 will be returned. /// /// @tparam genIUType Signed or unsigned integer scalar types. /// /// @see GLSL findLSB man page /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions template GLM_FUNC_DECL int findLSB(genIUType x); /// Returns the bit number of the least significant bit set to /// 1 in the binary representation of value. /// If value is zero, -1 will be returned. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T Signed or unsigned integer scalar types. /// /// @see GLSL findLSB man page /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions template GLM_FUNC_DECL vec findLSB(vec const& v); /// Returns the bit number of the most significant bit in the binary representation of value. /// For positive integers, the result will be the bit number of the most significant bit set to 1. /// For negative integers, the result will be the bit number of the most significant /// bit set to 0. For a value of zero or negative one, -1 will be returned. /// /// @tparam genIUType Signed or unsigned integer scalar types. /// /// @see GLSL findMSB man page /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions template GLM_FUNC_DECL int findMSB(genIUType x); /// Returns the bit number of the most significant bit in the binary representation of value. /// For positive integers, the result will be the bit number of the most significant bit set to 1. /// For negative integers, the result will be the bit number of the most significant /// bit set to 0. For a value of zero or negative one, -1 will be returned. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T Signed or unsigned integer scalar types. /// /// @see GLSL findMSB man page /// @see GLSL 4.20.8 specification, section 8.8 Integer Functions template GLM_FUNC_DECL vec findMSB(vec const& v); /// @} }//namespace glm #include "detail/func_integer.inl" connectome-workbench-1.4.2/src/GLMath/glm/mat2x2.hpp000066400000000000000000000003511360521144700221420ustar00rootroot00000000000000/// @ref core /// @file glm/mat2x2.hpp #pragma once #include "./ext/matrix_double2x2.hpp" #include "./ext/matrix_double2x2_precision.hpp" #include "./ext/matrix_float2x2.hpp" #include "./ext/matrix_float2x2_precision.hpp" connectome-workbench-1.4.2/src/GLMath/glm/mat2x3.hpp000066400000000000000000000003511360521144700221430ustar00rootroot00000000000000/// @ref core /// @file glm/mat2x3.hpp #pragma once #include "./ext/matrix_double2x3.hpp" #include "./ext/matrix_double2x3_precision.hpp" #include "./ext/matrix_float2x3.hpp" #include "./ext/matrix_float2x3_precision.hpp" connectome-workbench-1.4.2/src/GLMath/glm/mat2x4.hpp000066400000000000000000000003511360521144700221440ustar00rootroot00000000000000/// @ref core /// @file glm/mat2x4.hpp #pragma once #include "./ext/matrix_double2x4.hpp" #include "./ext/matrix_double2x4_precision.hpp" #include "./ext/matrix_float2x4.hpp" #include "./ext/matrix_float2x4_precision.hpp" connectome-workbench-1.4.2/src/GLMath/glm/mat3x2.hpp000066400000000000000000000003511360521144700221430ustar00rootroot00000000000000/// @ref core /// @file glm/mat3x2.hpp #pragma once #include "./ext/matrix_double3x2.hpp" #include "./ext/matrix_double3x2_precision.hpp" #include "./ext/matrix_float3x2.hpp" #include "./ext/matrix_float3x2_precision.hpp" connectome-workbench-1.4.2/src/GLMath/glm/mat3x3.hpp000066400000000000000000000003471360521144700221510ustar00rootroot00000000000000/// @ref core /// @file glm/mat3x3.hpp #pragma once #include "./ext/matrix_double3x3.hpp" #include "./ext/matrix_double3x3_precision.hpp" #include "./ext/matrix_float3x3.hpp" #include "./ext/matrix_float3x3_precision.hpp" connectome-workbench-1.4.2/src/GLMath/glm/mat3x4.hpp000066400000000000000000000003471360521144700221520ustar00rootroot00000000000000/// @ref core /// @file glm/mat3x4.hpp #pragma once #include "./ext/matrix_double3x4.hpp" #include "./ext/matrix_double3x4_precision.hpp" #include "./ext/matrix_float3x4.hpp" #include "./ext/matrix_float3x4_precision.hpp" connectome-workbench-1.4.2/src/GLMath/glm/mat4x2.hpp000066400000000000000000000003511360521144700221440ustar00rootroot00000000000000/// @ref core /// @file glm/mat4x2.hpp #pragma once #include "./ext/matrix_double4x2.hpp" #include "./ext/matrix_double4x2_precision.hpp" #include "./ext/matrix_float4x2.hpp" #include "./ext/matrix_float4x2_precision.hpp" connectome-workbench-1.4.2/src/GLMath/glm/mat4x3.hpp000066400000000000000000000003471360521144700221520ustar00rootroot00000000000000/// @ref core /// @file glm/mat4x3.hpp #pragma once #include "./ext/matrix_double4x3.hpp" #include "./ext/matrix_double4x3_precision.hpp" #include "./ext/matrix_float4x3.hpp" #include "./ext/matrix_float4x3_precision.hpp" connectome-workbench-1.4.2/src/GLMath/glm/mat4x4.hpp000066400000000000000000000003511360521144700221460ustar00rootroot00000000000000/// @ref core /// @file glm/mat4x4.hpp #pragma once #include "./ext/matrix_double4x4.hpp" #include "./ext/matrix_double4x4_precision.hpp" #include "./ext/matrix_float4x4.hpp" #include "./ext/matrix_float4x4_precision.hpp" connectome-workbench-1.4.2/src/GLMath/glm/matrix.hpp000066400000000000000000000134131360521144700223340ustar00rootroot00000000000000/// @ref core /// @file glm/matrix.hpp /// /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions /// /// @defgroup core_func_matrix Matrix functions /// @ingroup core /// /// Provides GLSL matrix functions. /// /// Include to use these core features. #pragma once // Dependencies #include "detail/qualifier.hpp" #include "detail/setup.hpp" #include "vec2.hpp" #include "vec3.hpp" #include "vec4.hpp" #include "mat2x2.hpp" #include "mat2x3.hpp" #include "mat2x4.hpp" #include "mat3x2.hpp" #include "mat3x3.hpp" #include "mat3x4.hpp" #include "mat4x2.hpp" #include "mat4x3.hpp" #include "mat4x4.hpp" namespace glm { namespace detail { template struct outerProduct_trait{}; template struct outerProduct_trait<2, 2, T, Q> { typedef mat<2, 2, T, Q> type; }; template struct outerProduct_trait<2, 3, T, Q> { typedef mat<3, 2, T, Q> type; }; template struct outerProduct_trait<2, 4, T, Q> { typedef mat<4, 2, T, Q> type; }; template struct outerProduct_trait<3, 2, T, Q> { typedef mat<2, 3, T, Q> type; }; template struct outerProduct_trait<3, 3, T, Q> { typedef mat<3, 3, T, Q> type; }; template struct outerProduct_trait<3, 4, T, Q> { typedef mat<4, 3, T, Q> type; }; template struct outerProduct_trait<4, 2, T, Q> { typedef mat<2, 4, T, Q> type; }; template struct outerProduct_trait<4, 3, T, Q> { typedef mat<3, 4, T, Q> type; }; template struct outerProduct_trait<4, 4, T, Q> { typedef mat<4, 4, T, Q> type; }; }//namespace detail /// @addtogroup core_func_matrix /// @{ /// Multiply matrix x by matrix y component-wise, i.e., /// result[i][j] is the scalar product of x[i][j] and y[i][j]. /// /// @tparam C Integer between 1 and 4 included that qualify the number a column /// @tparam R Integer between 1 and 4 included that qualify the number a row /// @tparam T Floating-point or signed integer scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL matrixCompMult man page /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions template GLM_FUNC_DECL mat matrixCompMult(mat const& x, mat const& y); /// Treats the first parameter c as a column vector /// and the second parameter r as a row vector /// and does a linear algebraic matrix multiply c * r. /// /// @tparam C Integer between 1 and 4 included that qualify the number a column /// @tparam R Integer between 1 and 4 included that qualify the number a row /// @tparam T Floating-point or signed integer scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL outerProduct man page /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions template GLM_FUNC_DECL typename detail::outerProduct_trait::type outerProduct(vec const& c, vec const& r); /// Returns the transposed matrix of x /// /// @tparam C Integer between 1 and 4 included that qualify the number a column /// @tparam R Integer between 1 and 4 included that qualify the number a row /// @tparam T Floating-point or signed integer scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL transpose man page /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions template GLM_FUNC_DECL typename mat::transpose_type transpose(mat const& x); /// Return the determinant of a squared matrix. /// /// @tparam C Integer between 1 and 4 included that qualify the number a column /// @tparam R Integer between 1 and 4 included that qualify the number a row /// @tparam T Floating-point or signed integer scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL determinant man page /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions template GLM_FUNC_DECL T determinant(mat const& m); /// Return the inverse of a squared matrix. /// /// @tparam C Integer between 1 and 4 included that qualify the number a column /// @tparam R Integer between 1 and 4 included that qualify the number a row /// @tparam T Floating-point or signed integer scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL inverse man page /// @see GLSL 4.20.8 specification, section 8.6 Matrix Functions template GLM_FUNC_DECL mat inverse(mat const& m); /// @} }//namespace glm #include "detail/func_matrix.inl" connectome-workbench-1.4.2/src/GLMath/glm/packing.hpp000066400000000000000000000254761360521144700224600ustar00rootroot00000000000000/// @ref core /// @file glm/packing.hpp /// /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions /// @see gtc_packing /// /// @defgroup core_func_packing Floating-Point Pack and Unpack Functions /// @ingroup core /// /// Provides GLSL functions to pack and unpack half, single and double-precision floating point values into more compact integer types. /// /// These functions do not operate component-wise, rather as described in each case. /// /// Include to use these core features. #pragma once #include "./ext/vector_uint2.hpp" #include "./ext/vector_float2.hpp" #include "./ext/vector_float4.hpp" namespace glm { /// @addtogroup core_func_packing /// @{ /// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values. /// Then, the results are packed into the returned 32-bit unsigned integer. /// /// The conversion for component c of v to fixed point is done as follows: /// packUnorm2x16: round(clamp(c, 0, +1) * 65535.0) /// /// The first component of the vector will be written to the least significant bits of the output; /// the last component will be written to the most significant bits. /// /// @see GLSL packUnorm2x16 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL uint packUnorm2x16(vec2 const& v); /// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values. /// Then, the results are packed into the returned 32-bit unsigned integer. /// /// The conversion for component c of v to fixed point is done as follows: /// packSnorm2x16: round(clamp(v, -1, +1) * 32767.0) /// /// The first component of the vector will be written to the least significant bits of the output; /// the last component will be written to the most significant bits. /// /// @see GLSL packSnorm2x16 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL uint packSnorm2x16(vec2 const& v); /// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values. /// Then, the results are packed into the returned 32-bit unsigned integer. /// /// The conversion for component c of v to fixed point is done as follows: /// packUnorm4x8: round(clamp(c, 0, +1) * 255.0) /// /// The first component of the vector will be written to the least significant bits of the output; /// the last component will be written to the most significant bits. /// /// @see GLSL packUnorm4x8 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL uint packUnorm4x8(vec4 const& v); /// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values. /// Then, the results are packed into the returned 32-bit unsigned integer. /// /// The conversion for component c of v to fixed point is done as follows: /// packSnorm4x8: round(clamp(c, -1, +1) * 127.0) /// /// The first component of the vector will be written to the least significant bits of the output; /// the last component will be written to the most significant bits. /// /// @see GLSL packSnorm4x8 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL uint packSnorm4x8(vec4 const& v); /// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers. /// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector. /// /// The conversion for unpacked fixed-point value f to floating point is done as follows: /// unpackUnorm2x16: f / 65535.0 /// /// The first component of the returned vector will be extracted from the least significant bits of the input; /// the last component will be extracted from the most significant bits. /// /// @see GLSL unpackUnorm2x16 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL vec2 unpackUnorm2x16(uint p); /// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers. /// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector. /// /// The conversion for unpacked fixed-point value f to floating point is done as follows: /// unpackSnorm2x16: clamp(f / 32767.0, -1, +1) /// /// The first component of the returned vector will be extracted from the least significant bits of the input; /// the last component will be extracted from the most significant bits. /// /// @see GLSL unpackSnorm2x16 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL vec2 unpackSnorm2x16(uint p); /// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers. /// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector. /// /// The conversion for unpacked fixed-point value f to floating point is done as follows: /// unpackUnorm4x8: f / 255.0 /// /// The first component of the returned vector will be extracted from the least significant bits of the input; /// the last component will be extracted from the most significant bits. /// /// @see GLSL unpackUnorm4x8 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL vec4 unpackUnorm4x8(uint p); /// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers. /// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector. /// /// The conversion for unpacked fixed-point value f to floating point is done as follows: /// unpackSnorm4x8: clamp(f / 127.0, -1, +1) /// /// The first component of the returned vector will be extracted from the least significant bits of the input; /// the last component will be extracted from the most significant bits. /// /// @see GLSL unpackSnorm4x8 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL vec4 unpackSnorm4x8(uint p); /// Returns a double-qualifier value obtained by packing the components of v into a 64-bit value. /// If an IEEE 754 Inf or NaN is created, it will not signal, and the resulting floating point value is unspecified. /// Otherwise, the bit- level representation of v is preserved. /// The first vector component specifies the 32 least significant bits; /// the second component specifies the 32 most significant bits. /// /// @see GLSL packDouble2x32 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL double packDouble2x32(uvec2 const& v); /// Returns a two-component unsigned integer vector representation of v. /// The bit-level representation of v is preserved. /// The first component of the vector contains the 32 least significant bits of the double; /// the second component consists the 32 most significant bits. /// /// @see GLSL unpackDouble2x32 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL uvec2 unpackDouble2x32(double v); /// Returns an unsigned integer obtained by converting the components of a two-component floating-point vector /// to the 16-bit floating-point representation found in the OpenGL Specification, /// and then packing these two 16- bit integers into a 32-bit unsigned integer. /// The first vector component specifies the 16 least-significant bits of the result; /// the second component specifies the 16 most-significant bits. /// /// @see GLSL packHalf2x16 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL uint packHalf2x16(vec2 const& v); /// Returns a two-component floating-point vector with components obtained by unpacking a 32-bit unsigned integer into a pair of 16-bit values, /// interpreting those values as 16-bit floating-point numbers according to the OpenGL Specification, /// and converting them to 32-bit floating-point values. /// The first component of the vector is obtained from the 16 least-significant bits of v; /// the second component is obtained from the 16 most-significant bits of v. /// /// @see GLSL unpackHalf2x16 man page /// @see GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions GLM_FUNC_DECL vec2 unpackHalf2x16(uint v); /// @} }//namespace glm #include "detail/func_packing.inl" connectome-workbench-1.4.2/src/GLMath/glm/simd/000077500000000000000000000000001360521144700212515ustar00rootroot00000000000000connectome-workbench-1.4.2/src/GLMath/glm/simd/common.h000066400000000000000000000161121360521144700227130ustar00rootroot00000000000000/// @ref simd /// @file glm/simd/common.h #pragma once #include "platform.h" #if GLM_ARCH & GLM_ARCH_SSE2_BIT GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_add(glm_f32vec4 a, glm_f32vec4 b) { return _mm_add_ps(a, b); } GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_add(glm_f32vec4 a, glm_f32vec4 b) { return _mm_add_ss(a, b); } GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_sub(glm_f32vec4 a, glm_f32vec4 b) { return _mm_sub_ps(a, b); } GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_sub(glm_f32vec4 a, glm_f32vec4 b) { return _mm_sub_ss(a, b); } GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_mul(glm_f32vec4 a, glm_f32vec4 b) { return _mm_mul_ps(a, b); } GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_mul(glm_f32vec4 a, glm_f32vec4 b) { return _mm_mul_ss(a, b); } GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_div(glm_f32vec4 a, glm_f32vec4 b) { return _mm_div_ps(a, b); } GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_div(glm_f32vec4 a, glm_f32vec4 b) { return _mm_div_ss(a, b); } GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_div_lowp(glm_f32vec4 a, glm_f32vec4 b) { return glm_vec4_mul(a, _mm_rcp_ps(b)); } GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_swizzle_xyzw(glm_f32vec4 a) { # if GLM_ARCH & GLM_ARCH_AVX2_BIT return _mm_permute_ps(a, _MM_SHUFFLE(3, 2, 1, 0)); # else return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 2, 1, 0)); # endif } GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_fma(glm_f32vec4 a, glm_f32vec4 b, glm_f32vec4 c) { # if (GLM_ARCH & GLM_ARCH_AVX2_BIT) && !(GLM_COMPILER & GLM_COMPILER_CLANG) return _mm_fmadd_ss(a, b, c); # else return _mm_add_ss(_mm_mul_ss(a, b), c); # endif } GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_fma(glm_f32vec4 a, glm_f32vec4 b, glm_f32vec4 c) { # if (GLM_ARCH & GLM_ARCH_AVX2_BIT) && !(GLM_COMPILER & GLM_COMPILER_CLANG) return _mm_fmadd_ps(a, b, c); # else return glm_vec4_add(glm_vec4_mul(a, b), c); # endif } GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_abs(glm_f32vec4 x) { return _mm_and_ps(x, _mm_castsi128_ps(_mm_set1_epi32(0x7FFFFFFF))); } GLM_FUNC_QUALIFIER glm_ivec4 glm_ivec4_abs(glm_ivec4 x) { # if GLM_ARCH & GLM_ARCH_SSSE3_BIT return _mm_sign_epi32(x, x); # else glm_ivec4 const sgn0 = _mm_srai_epi32(x, 31); glm_ivec4 const inv0 = _mm_xor_si128(x, sgn0); glm_ivec4 const sub0 = _mm_sub_epi32(inv0, sgn0); return sub0; # endif } GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_sign(glm_vec4 x) { glm_vec4 const zro0 = _mm_setzero_ps(); glm_vec4 const cmp0 = _mm_cmplt_ps(x, zro0); glm_vec4 const cmp1 = _mm_cmpgt_ps(x, zro0); glm_vec4 const and0 = _mm_and_ps(cmp0, _mm_set1_ps(-1.0f)); glm_vec4 const and1 = _mm_and_ps(cmp1, _mm_set1_ps(1.0f)); glm_vec4 const or0 = _mm_or_ps(and0, and1); return or0; } GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_round(glm_vec4 x) { # if GLM_ARCH & GLM_ARCH_SSE41_BIT return _mm_round_ps(x, _MM_FROUND_TO_NEAREST_INT); # else glm_vec4 const sgn0 = _mm_castsi128_ps(_mm_set1_epi32(int(0x80000000))); glm_vec4 const and0 = _mm_and_ps(sgn0, x); glm_vec4 const or0 = _mm_or_ps(and0, _mm_set_ps1(8388608.0f)); glm_vec4 const add0 = glm_vec4_add(x, or0); glm_vec4 const sub0 = glm_vec4_sub(add0, or0); return sub0; # endif } GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_floor(glm_vec4 x) { # if GLM_ARCH & GLM_ARCH_SSE41_BIT return _mm_floor_ps(x); # else glm_vec4 const rnd0 = glm_vec4_round(x); glm_vec4 const cmp0 = _mm_cmplt_ps(x, rnd0); glm_vec4 const and0 = _mm_and_ps(cmp0, _mm_set1_ps(1.0f)); glm_vec4 const sub0 = glm_vec4_sub(rnd0, and0); return sub0; # endif } /* trunc TODO GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_trunc(glm_vec4 x) { return glm_vec4(); } */ //roundEven GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_roundEven(glm_vec4 x) { glm_vec4 const sgn0 = _mm_castsi128_ps(_mm_set1_epi32(int(0x80000000))); glm_vec4 const and0 = _mm_and_ps(sgn0, x); glm_vec4 const or0 = _mm_or_ps(and0, _mm_set_ps1(8388608.0f)); glm_vec4 const add0 = glm_vec4_add(x, or0); glm_vec4 const sub0 = glm_vec4_sub(add0, or0); return sub0; } GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_ceil(glm_vec4 x) { # if GLM_ARCH & GLM_ARCH_SSE41_BIT return _mm_ceil_ps(x); # else glm_vec4 const rnd0 = glm_vec4_round(x); glm_vec4 const cmp0 = _mm_cmpgt_ps(x, rnd0); glm_vec4 const and0 = _mm_and_ps(cmp0, _mm_set1_ps(1.0f)); glm_vec4 const add0 = glm_vec4_add(rnd0, and0); return add0; # endif } GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_fract(glm_vec4 x) { glm_vec4 const flr0 = glm_vec4_floor(x); glm_vec4 const sub0 = glm_vec4_sub(x, flr0); return sub0; } GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_mod(glm_vec4 x, glm_vec4 y) { glm_vec4 const div0 = glm_vec4_div(x, y); glm_vec4 const flr0 = glm_vec4_floor(div0); glm_vec4 const mul0 = glm_vec4_mul(y, flr0); glm_vec4 const sub0 = glm_vec4_sub(x, mul0); return sub0; } GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_clamp(glm_vec4 v, glm_vec4 minVal, glm_vec4 maxVal) { glm_vec4 const min0 = _mm_min_ps(v, maxVal); glm_vec4 const max0 = _mm_max_ps(min0, minVal); return max0; } GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_mix(glm_vec4 v1, glm_vec4 v2, glm_vec4 a) { glm_vec4 const sub0 = glm_vec4_sub(_mm_set1_ps(1.0f), a); glm_vec4 const mul0 = glm_vec4_mul(v1, sub0); glm_vec4 const mad0 = glm_vec4_fma(v2, a, mul0); return mad0; } GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_step(glm_vec4 edge, glm_vec4 x) { glm_vec4 const cmp = _mm_cmple_ps(x, edge); return _mm_movemask_ps(cmp) == 0 ? _mm_set1_ps(1.0f) : _mm_setzero_ps(); } GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_smoothstep(glm_vec4 edge0, glm_vec4 edge1, glm_vec4 x) { glm_vec4 const sub0 = glm_vec4_sub(x, edge0); glm_vec4 const sub1 = glm_vec4_sub(edge1, edge0); glm_vec4 const div0 = glm_vec4_sub(sub0, sub1); glm_vec4 const clp0 = glm_vec4_clamp(div0, _mm_setzero_ps(), _mm_set1_ps(1.0f)); glm_vec4 const mul0 = glm_vec4_mul(_mm_set1_ps(2.0f), clp0); glm_vec4 const sub2 = glm_vec4_sub(_mm_set1_ps(3.0f), mul0); glm_vec4 const mul1 = glm_vec4_mul(clp0, clp0); glm_vec4 const mul2 = glm_vec4_mul(mul1, sub2); return mul2; } // Agner Fog method GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_nan(glm_vec4 x) { glm_ivec4 const t1 = _mm_castps_si128(x); // reinterpret as 32-bit integer glm_ivec4 const t2 = _mm_sll_epi32(t1, _mm_cvtsi32_si128(1)); // shift out sign bit glm_ivec4 const t3 = _mm_set1_epi32(int(0xFF000000)); // exponent mask glm_ivec4 const t4 = _mm_and_si128(t2, t3); // exponent glm_ivec4 const t5 = _mm_andnot_si128(t3, t2); // fraction glm_ivec4 const Equal = _mm_cmpeq_epi32(t3, t4); glm_ivec4 const Nequal = _mm_cmpeq_epi32(t5, _mm_setzero_si128()); glm_ivec4 const And = _mm_and_si128(Equal, Nequal); return _mm_castsi128_ps(And); // exponent = all 1s and fraction != 0 } // Agner Fog method GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_inf(glm_vec4 x) { glm_ivec4 const t1 = _mm_castps_si128(x); // reinterpret as 32-bit integer glm_ivec4 const t2 = _mm_sll_epi32(t1, _mm_cvtsi32_si128(1)); // shift out sign bit return _mm_castsi128_ps(_mm_cmpeq_epi32(t2, _mm_set1_epi32(int(0xFF000000)))); // exponent is all 1s, fraction is 0 } #endif//GLM_ARCH & GLM_ARCH_SSE2_BIT connectome-workbench-1.4.2/src/GLMath/glm/simd/exponential.h000066400000000000000000000006151360521144700237520ustar00rootroot00000000000000/// @ref simd /// @file glm/simd/experimental.h #pragma once #include "platform.h" #if GLM_ARCH & GLM_ARCH_SSE2_BIT GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_sqrt_lowp(glm_f32vec4 x) { return _mm_mul_ss(_mm_rsqrt_ss(x), x); } GLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_sqrt_lowp(glm_f32vec4 x) { return _mm_mul_ps(_mm_rsqrt_ps(x), x); } #endif//GLM_ARCH & GLM_ARCH_SSE2_BIT connectome-workbench-1.4.2/src/GLMath/glm/simd/geometric.h000066400000000000000000000077161360521144700234130ustar00rootroot00000000000000/// @ref simd /// @file glm/simd/geometric.h #pragma once #include "common.h" #if GLM_ARCH & GLM_ARCH_SSE2_BIT GLM_FUNC_DECL glm_vec4 glm_vec4_dot(glm_vec4 v1, glm_vec4 v2); GLM_FUNC_DECL glm_vec4 glm_vec1_dot(glm_vec4 v1, glm_vec4 v2); GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_length(glm_vec4 x) { glm_vec4 const dot0 = glm_vec4_dot(x, x); glm_vec4 const sqt0 = _mm_sqrt_ps(dot0); return sqt0; } GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_distance(glm_vec4 p0, glm_vec4 p1) { glm_vec4 const sub0 = _mm_sub_ps(p0, p1); glm_vec4 const len0 = glm_vec4_length(sub0); return len0; } GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_dot(glm_vec4 v1, glm_vec4 v2) { # if GLM_ARCH & GLM_ARCH_AVX_BIT return _mm_dp_ps(v1, v2, 0xff); # elif GLM_ARCH & GLM_ARCH_SSE3_BIT glm_vec4 const mul0 = _mm_mul_ps(v1, v2); glm_vec4 const hadd0 = _mm_hadd_ps(mul0, mul0); glm_vec4 const hadd1 = _mm_hadd_ps(hadd0, hadd0); return hadd1; # else glm_vec4 const mul0 = _mm_mul_ps(v1, v2); glm_vec4 const swp0 = _mm_shuffle_ps(mul0, mul0, _MM_SHUFFLE(2, 3, 0, 1)); glm_vec4 const add0 = _mm_add_ps(mul0, swp0); glm_vec4 const swp1 = _mm_shuffle_ps(add0, add0, _MM_SHUFFLE(0, 1, 2, 3)); glm_vec4 const add1 = _mm_add_ps(add0, swp1); return add1; # endif } GLM_FUNC_QUALIFIER glm_vec4 glm_vec1_dot(glm_vec4 v1, glm_vec4 v2) { # if GLM_ARCH & GLM_ARCH_AVX_BIT return _mm_dp_ps(v1, v2, 0xff); # elif GLM_ARCH & GLM_ARCH_SSE3_BIT glm_vec4 const mul0 = _mm_mul_ps(v1, v2); glm_vec4 const had0 = _mm_hadd_ps(mul0, mul0); glm_vec4 const had1 = _mm_hadd_ps(had0, had0); return had1; # else glm_vec4 const mul0 = _mm_mul_ps(v1, v2); glm_vec4 const mov0 = _mm_movehl_ps(mul0, mul0); glm_vec4 const add0 = _mm_add_ps(mov0, mul0); glm_vec4 const swp1 = _mm_shuffle_ps(add0, add0, 1); glm_vec4 const add1 = _mm_add_ss(add0, swp1); return add1; # endif } GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_cross(glm_vec4 v1, glm_vec4 v2) { glm_vec4 const swp0 = _mm_shuffle_ps(v1, v1, _MM_SHUFFLE(3, 0, 2, 1)); glm_vec4 const swp1 = _mm_shuffle_ps(v1, v1, _MM_SHUFFLE(3, 1, 0, 2)); glm_vec4 const swp2 = _mm_shuffle_ps(v2, v2, _MM_SHUFFLE(3, 0, 2, 1)); glm_vec4 const swp3 = _mm_shuffle_ps(v2, v2, _MM_SHUFFLE(3, 1, 0, 2)); glm_vec4 const mul0 = _mm_mul_ps(swp0, swp3); glm_vec4 const mul1 = _mm_mul_ps(swp1, swp2); glm_vec4 const sub0 = _mm_sub_ps(mul0, mul1); return sub0; } GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_normalize(glm_vec4 v) { glm_vec4 const dot0 = glm_vec4_dot(v, v); glm_vec4 const isr0 = _mm_rsqrt_ps(dot0); glm_vec4 const mul0 = _mm_mul_ps(v, isr0); return mul0; } GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_faceforward(glm_vec4 N, glm_vec4 I, glm_vec4 Nref) { glm_vec4 const dot0 = glm_vec4_dot(Nref, I); glm_vec4 const sgn0 = glm_vec4_sign(dot0); glm_vec4 const mul0 = _mm_mul_ps(sgn0, _mm_set1_ps(-1.0f)); glm_vec4 const mul1 = _mm_mul_ps(N, mul0); return mul1; } GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_reflect(glm_vec4 I, glm_vec4 N) { glm_vec4 const dot0 = glm_vec4_dot(N, I); glm_vec4 const mul0 = _mm_mul_ps(N, dot0); glm_vec4 const mul1 = _mm_mul_ps(mul0, _mm_set1_ps(2.0f)); glm_vec4 const sub0 = _mm_sub_ps(I, mul1); return sub0; } GLM_FUNC_QUALIFIER __m128 glm_vec4_refract(glm_vec4 I, glm_vec4 N, glm_vec4 eta) { glm_vec4 const dot0 = glm_vec4_dot(N, I); glm_vec4 const mul0 = _mm_mul_ps(eta, eta); glm_vec4 const mul1 = _mm_mul_ps(dot0, dot0); glm_vec4 const sub0 = _mm_sub_ps(_mm_set1_ps(1.0f), mul0); glm_vec4 const sub1 = _mm_sub_ps(_mm_set1_ps(1.0f), mul1); glm_vec4 const mul2 = _mm_mul_ps(sub0, sub1); if(_mm_movemask_ps(_mm_cmplt_ss(mul2, _mm_set1_ps(0.0f))) == 0) return _mm_set1_ps(0.0f); glm_vec4 const sqt0 = _mm_sqrt_ps(mul2); glm_vec4 const mad0 = glm_vec4_fma(eta, dot0, sqt0); glm_vec4 const mul4 = _mm_mul_ps(mad0, N); glm_vec4 const mul5 = _mm_mul_ps(eta, I); glm_vec4 const sub2 = _mm_sub_ps(mul5, mul4); return sub2; } #endif//GLM_ARCH & GLM_ARCH_SSE2_BIT connectome-workbench-1.4.2/src/GLMath/glm/simd/integer.h000066400000000000000000000073331360521144700230650ustar00rootroot00000000000000/// @ref simd /// @file glm/simd/integer.h #pragma once #if GLM_ARCH & GLM_ARCH_SSE2_BIT GLM_FUNC_QUALIFIER glm_uvec4 glm_i128_interleave(glm_uvec4 x) { glm_uvec4 const Mask4 = _mm_set1_epi32(0x0000FFFF); glm_uvec4 const Mask3 = _mm_set1_epi32(0x00FF00FF); glm_uvec4 const Mask2 = _mm_set1_epi32(0x0F0F0F0F); glm_uvec4 const Mask1 = _mm_set1_epi32(0x33333333); glm_uvec4 const Mask0 = _mm_set1_epi32(0x55555555); glm_uvec4 Reg1; glm_uvec4 Reg2; // REG1 = x; // REG2 = y; //Reg1 = _mm_unpacklo_epi64(x, y); Reg1 = x; //REG1 = ((REG1 << 16) | REG1) & glm::uint64(0x0000FFFF0000FFFF); //REG2 = ((REG2 << 16) | REG2) & glm::uint64(0x0000FFFF0000FFFF); Reg2 = _mm_slli_si128(Reg1, 2); Reg1 = _mm_or_si128(Reg2, Reg1); Reg1 = _mm_and_si128(Reg1, Mask4); //REG1 = ((REG1 << 8) | REG1) & glm::uint64(0x00FF00FF00FF00FF); //REG2 = ((REG2 << 8) | REG2) & glm::uint64(0x00FF00FF00FF00FF); Reg2 = _mm_slli_si128(Reg1, 1); Reg1 = _mm_or_si128(Reg2, Reg1); Reg1 = _mm_and_si128(Reg1, Mask3); //REG1 = ((REG1 << 4) | REG1) & glm::uint64(0x0F0F0F0F0F0F0F0F); //REG2 = ((REG2 << 4) | REG2) & glm::uint64(0x0F0F0F0F0F0F0F0F); Reg2 = _mm_slli_epi32(Reg1, 4); Reg1 = _mm_or_si128(Reg2, Reg1); Reg1 = _mm_and_si128(Reg1, Mask2); //REG1 = ((REG1 << 2) | REG1) & glm::uint64(0x3333333333333333); //REG2 = ((REG2 << 2) | REG2) & glm::uint64(0x3333333333333333); Reg2 = _mm_slli_epi32(Reg1, 2); Reg1 = _mm_or_si128(Reg2, Reg1); Reg1 = _mm_and_si128(Reg1, Mask1); //REG1 = ((REG1 << 1) | REG1) & glm::uint64(0x5555555555555555); //REG2 = ((REG2 << 1) | REG2) & glm::uint64(0x5555555555555555); Reg2 = _mm_slli_epi32(Reg1, 1); Reg1 = _mm_or_si128(Reg2, Reg1); Reg1 = _mm_and_si128(Reg1, Mask0); //return REG1 | (REG2 << 1); Reg2 = _mm_slli_epi32(Reg1, 1); Reg2 = _mm_srli_si128(Reg2, 8); Reg1 = _mm_or_si128(Reg1, Reg2); return Reg1; } GLM_FUNC_QUALIFIER glm_uvec4 glm_i128_interleave2(glm_uvec4 x, glm_uvec4 y) { glm_uvec4 const Mask4 = _mm_set1_epi32(0x0000FFFF); glm_uvec4 const Mask3 = _mm_set1_epi32(0x00FF00FF); glm_uvec4 const Mask2 = _mm_set1_epi32(0x0F0F0F0F); glm_uvec4 const Mask1 = _mm_set1_epi32(0x33333333); glm_uvec4 const Mask0 = _mm_set1_epi32(0x55555555); glm_uvec4 Reg1; glm_uvec4 Reg2; // REG1 = x; // REG2 = y; Reg1 = _mm_unpacklo_epi64(x, y); //REG1 = ((REG1 << 16) | REG1) & glm::uint64(0x0000FFFF0000FFFF); //REG2 = ((REG2 << 16) | REG2) & glm::uint64(0x0000FFFF0000FFFF); Reg2 = _mm_slli_si128(Reg1, 2); Reg1 = _mm_or_si128(Reg2, Reg1); Reg1 = _mm_and_si128(Reg1, Mask4); //REG1 = ((REG1 << 8) | REG1) & glm::uint64(0x00FF00FF00FF00FF); //REG2 = ((REG2 << 8) | REG2) & glm::uint64(0x00FF00FF00FF00FF); Reg2 = _mm_slli_si128(Reg1, 1); Reg1 = _mm_or_si128(Reg2, Reg1); Reg1 = _mm_and_si128(Reg1, Mask3); //REG1 = ((REG1 << 4) | REG1) & glm::uint64(0x0F0F0F0F0F0F0F0F); //REG2 = ((REG2 << 4) | REG2) & glm::uint64(0x0F0F0F0F0F0F0F0F); Reg2 = _mm_slli_epi32(Reg1, 4); Reg1 = _mm_or_si128(Reg2, Reg1); Reg1 = _mm_and_si128(Reg1, Mask2); //REG1 = ((REG1 << 2) | REG1) & glm::uint64(0x3333333333333333); //REG2 = ((REG2 << 2) | REG2) & glm::uint64(0x3333333333333333); Reg2 = _mm_slli_epi32(Reg1, 2); Reg1 = _mm_or_si128(Reg2, Reg1); Reg1 = _mm_and_si128(Reg1, Mask1); //REG1 = ((REG1 << 1) | REG1) & glm::uint64(0x5555555555555555); //REG2 = ((REG2 << 1) | REG2) & glm::uint64(0x5555555555555555); Reg2 = _mm_slli_epi32(Reg1, 1); Reg1 = _mm_or_si128(Reg2, Reg1); Reg1 = _mm_and_si128(Reg1, Mask0); //return REG1 | (REG2 << 1); Reg2 = _mm_slli_epi32(Reg1, 1); Reg2 = _mm_srli_si128(Reg2, 8); Reg1 = _mm_or_si128(Reg1, Reg2); return Reg1; } #endif//GLM_ARCH & GLM_ARCH_SSE2_BIT connectome-workbench-1.4.2/src/GLMath/glm/simd/matrix.h000066400000000000000000001200231360521144700227240ustar00rootroot00000000000000/// @ref simd /// @file glm/simd/matrix.h #pragma once #include "geometric.h" #if GLM_ARCH & GLM_ARCH_SSE2_BIT GLM_FUNC_QUALIFIER void glm_mat4_matrixCompMult(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4]) { out[0] = _mm_mul_ps(in1[0], in2[0]); out[1] = _mm_mul_ps(in1[1], in2[1]); out[2] = _mm_mul_ps(in1[2], in2[2]); out[3] = _mm_mul_ps(in1[3], in2[3]); } GLM_FUNC_QUALIFIER void glm_mat4_add(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4]) { out[0] = _mm_add_ps(in1[0], in2[0]); out[1] = _mm_add_ps(in1[1], in2[1]); out[2] = _mm_add_ps(in1[2], in2[2]); out[3] = _mm_add_ps(in1[3], in2[3]); } GLM_FUNC_QUALIFIER void glm_mat4_sub(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4]) { out[0] = _mm_sub_ps(in1[0], in2[0]); out[1] = _mm_sub_ps(in1[1], in2[1]); out[2] = _mm_sub_ps(in1[2], in2[2]); out[3] = _mm_sub_ps(in1[3], in2[3]); } GLM_FUNC_QUALIFIER glm_vec4 glm_mat4_mul_vec4(glm_vec4 const m[4], glm_vec4 v) { __m128 v0 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0)); __m128 v1 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1)); __m128 v2 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2)); __m128 v3 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(3, 3, 3, 3)); __m128 m0 = _mm_mul_ps(m[0], v0); __m128 m1 = _mm_mul_ps(m[1], v1); __m128 m2 = _mm_mul_ps(m[2], v2); __m128 m3 = _mm_mul_ps(m[3], v3); __m128 a0 = _mm_add_ps(m0, m1); __m128 a1 = _mm_add_ps(m2, m3); __m128 a2 = _mm_add_ps(a0, a1); return a2; } GLM_FUNC_QUALIFIER __m128 glm_vec4_mul_mat4(glm_vec4 v, glm_vec4 const m[4]) { __m128 i0 = m[0]; __m128 i1 = m[1]; __m128 i2 = m[2]; __m128 i3 = m[3]; __m128 m0 = _mm_mul_ps(v, i0); __m128 m1 = _mm_mul_ps(v, i1); __m128 m2 = _mm_mul_ps(v, i2); __m128 m3 = _mm_mul_ps(v, i3); __m128 u0 = _mm_unpacklo_ps(m0, m1); __m128 u1 = _mm_unpackhi_ps(m0, m1); __m128 a0 = _mm_add_ps(u0, u1); __m128 u2 = _mm_unpacklo_ps(m2, m3); __m128 u3 = _mm_unpackhi_ps(m2, m3); __m128 a1 = _mm_add_ps(u2, u3); __m128 f0 = _mm_movelh_ps(a0, a1); __m128 f1 = _mm_movehl_ps(a1, a0); __m128 f2 = _mm_add_ps(f0, f1); return f2; } GLM_FUNC_QUALIFIER void glm_mat4_mul(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4]) { { __m128 e0 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(0, 0, 0, 0)); __m128 e1 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(1, 1, 1, 1)); __m128 e2 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(2, 2, 2, 2)); __m128 e3 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(3, 3, 3, 3)); __m128 m0 = _mm_mul_ps(in1[0], e0); __m128 m1 = _mm_mul_ps(in1[1], e1); __m128 m2 = _mm_mul_ps(in1[2], e2); __m128 m3 = _mm_mul_ps(in1[3], e3); __m128 a0 = _mm_add_ps(m0, m1); __m128 a1 = _mm_add_ps(m2, m3); __m128 a2 = _mm_add_ps(a0, a1); out[0] = a2; } { __m128 e0 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(0, 0, 0, 0)); __m128 e1 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(1, 1, 1, 1)); __m128 e2 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(2, 2, 2, 2)); __m128 e3 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(3, 3, 3, 3)); __m128 m0 = _mm_mul_ps(in1[0], e0); __m128 m1 = _mm_mul_ps(in1[1], e1); __m128 m2 = _mm_mul_ps(in1[2], e2); __m128 m3 = _mm_mul_ps(in1[3], e3); __m128 a0 = _mm_add_ps(m0, m1); __m128 a1 = _mm_add_ps(m2, m3); __m128 a2 = _mm_add_ps(a0, a1); out[1] = a2; } { __m128 e0 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(0, 0, 0, 0)); __m128 e1 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(1, 1, 1, 1)); __m128 e2 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(2, 2, 2, 2)); __m128 e3 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(3, 3, 3, 3)); __m128 m0 = _mm_mul_ps(in1[0], e0); __m128 m1 = _mm_mul_ps(in1[1], e1); __m128 m2 = _mm_mul_ps(in1[2], e2); __m128 m3 = _mm_mul_ps(in1[3], e3); __m128 a0 = _mm_add_ps(m0, m1); __m128 a1 = _mm_add_ps(m2, m3); __m128 a2 = _mm_add_ps(a0, a1); out[2] = a2; } { //(__m128&)_mm_shuffle_epi32(__m128i&)in2[0], _MM_SHUFFLE(3, 3, 3, 3)) __m128 e0 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(0, 0, 0, 0)); __m128 e1 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(1, 1, 1, 1)); __m128 e2 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(2, 2, 2, 2)); __m128 e3 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(3, 3, 3, 3)); __m128 m0 = _mm_mul_ps(in1[0], e0); __m128 m1 = _mm_mul_ps(in1[1], e1); __m128 m2 = _mm_mul_ps(in1[2], e2); __m128 m3 = _mm_mul_ps(in1[3], e3); __m128 a0 = _mm_add_ps(m0, m1); __m128 a1 = _mm_add_ps(m2, m3); __m128 a2 = _mm_add_ps(a0, a1); out[3] = a2; } } GLM_FUNC_QUALIFIER void glm_mat4_transpose(glm_vec4 const in[4], glm_vec4 out[4]) { __m128 tmp0 = _mm_shuffle_ps(in[0], in[1], 0x44); __m128 tmp2 = _mm_shuffle_ps(in[0], in[1], 0xEE); __m128 tmp1 = _mm_shuffle_ps(in[2], in[3], 0x44); __m128 tmp3 = _mm_shuffle_ps(in[2], in[3], 0xEE); out[0] = _mm_shuffle_ps(tmp0, tmp1, 0x88); out[1] = _mm_shuffle_ps(tmp0, tmp1, 0xDD); out[2] = _mm_shuffle_ps(tmp2, tmp3, 0x88); out[3] = _mm_shuffle_ps(tmp2, tmp3, 0xDD); } GLM_FUNC_QUALIFIER glm_vec4 glm_mat4_determinant_highp(glm_vec4 const in[4]) { __m128 Fac0; { // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; // valType SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; // valType SubFactor13 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); Fac0 = _mm_sub_ps(Mul00, Mul01); } __m128 Fac1; { // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; // valType SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; // valType SubFactor14 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); Fac1 = _mm_sub_ps(Mul00, Mul01); } __m128 Fac2; { // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; // valType SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; // valType SubFactor15 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); Fac2 = _mm_sub_ps(Mul00, Mul01); } __m128 Fac3; { // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; // valType SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; // valType SubFactor16 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); Fac3 = _mm_sub_ps(Mul00, Mul01); } __m128 Fac4; { // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; // valType SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; // valType SubFactor17 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); Fac4 = _mm_sub_ps(Mul00, Mul01); } __m128 Fac5; { // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; // valType SubFactor12 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; // valType SubFactor18 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); Fac5 = _mm_sub_ps(Mul00, Mul01); } __m128 SignA = _mm_set_ps( 1.0f,-1.0f, 1.0f,-1.0f); __m128 SignB = _mm_set_ps(-1.0f, 1.0f,-1.0f, 1.0f); // m[1][0] // m[0][0] // m[0][0] // m[0][0] __m128 Temp0 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Vec0 = _mm_shuffle_ps(Temp0, Temp0, _MM_SHUFFLE(2, 2, 2, 0)); // m[1][1] // m[0][1] // m[0][1] // m[0][1] __m128 Temp1 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Vec1 = _mm_shuffle_ps(Temp1, Temp1, _MM_SHUFFLE(2, 2, 2, 0)); // m[1][2] // m[0][2] // m[0][2] // m[0][2] __m128 Temp2 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Vec2 = _mm_shuffle_ps(Temp2, Temp2, _MM_SHUFFLE(2, 2, 2, 0)); // m[1][3] // m[0][3] // m[0][3] // m[0][3] __m128 Temp3 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Vec3 = _mm_shuffle_ps(Temp3, Temp3, _MM_SHUFFLE(2, 2, 2, 0)); // col0 // + (Vec1[0] * Fac0[0] - Vec2[0] * Fac1[0] + Vec3[0] * Fac2[0]), // - (Vec1[1] * Fac0[1] - Vec2[1] * Fac1[1] + Vec3[1] * Fac2[1]), // + (Vec1[2] * Fac0[2] - Vec2[2] * Fac1[2] + Vec3[2] * Fac2[2]), // - (Vec1[3] * Fac0[3] - Vec2[3] * Fac1[3] + Vec3[3] * Fac2[3]), __m128 Mul00 = _mm_mul_ps(Vec1, Fac0); __m128 Mul01 = _mm_mul_ps(Vec2, Fac1); __m128 Mul02 = _mm_mul_ps(Vec3, Fac2); __m128 Sub00 = _mm_sub_ps(Mul00, Mul01); __m128 Add00 = _mm_add_ps(Sub00, Mul02); __m128 Inv0 = _mm_mul_ps(SignB, Add00); // col1 // - (Vec0[0] * Fac0[0] - Vec2[0] * Fac3[0] + Vec3[0] * Fac4[0]), // + (Vec0[0] * Fac0[1] - Vec2[1] * Fac3[1] + Vec3[1] * Fac4[1]), // - (Vec0[0] * Fac0[2] - Vec2[2] * Fac3[2] + Vec3[2] * Fac4[2]), // + (Vec0[0] * Fac0[3] - Vec2[3] * Fac3[3] + Vec3[3] * Fac4[3]), __m128 Mul03 = _mm_mul_ps(Vec0, Fac0); __m128 Mul04 = _mm_mul_ps(Vec2, Fac3); __m128 Mul05 = _mm_mul_ps(Vec3, Fac4); __m128 Sub01 = _mm_sub_ps(Mul03, Mul04); __m128 Add01 = _mm_add_ps(Sub01, Mul05); __m128 Inv1 = _mm_mul_ps(SignA, Add01); // col2 // + (Vec0[0] * Fac1[0] - Vec1[0] * Fac3[0] + Vec3[0] * Fac5[0]), // - (Vec0[0] * Fac1[1] - Vec1[1] * Fac3[1] + Vec3[1] * Fac5[1]), // + (Vec0[0] * Fac1[2] - Vec1[2] * Fac3[2] + Vec3[2] * Fac5[2]), // - (Vec0[0] * Fac1[3] - Vec1[3] * Fac3[3] + Vec3[3] * Fac5[3]), __m128 Mul06 = _mm_mul_ps(Vec0, Fac1); __m128 Mul07 = _mm_mul_ps(Vec1, Fac3); __m128 Mul08 = _mm_mul_ps(Vec3, Fac5); __m128 Sub02 = _mm_sub_ps(Mul06, Mul07); __m128 Add02 = _mm_add_ps(Sub02, Mul08); __m128 Inv2 = _mm_mul_ps(SignB, Add02); // col3 // - (Vec1[0] * Fac2[0] - Vec1[0] * Fac4[0] + Vec2[0] * Fac5[0]), // + (Vec1[0] * Fac2[1] - Vec1[1] * Fac4[1] + Vec2[1] * Fac5[1]), // - (Vec1[0] * Fac2[2] - Vec1[2] * Fac4[2] + Vec2[2] * Fac5[2]), // + (Vec1[0] * Fac2[3] - Vec1[3] * Fac4[3] + Vec2[3] * Fac5[3])); __m128 Mul09 = _mm_mul_ps(Vec0, Fac2); __m128 Mul10 = _mm_mul_ps(Vec1, Fac4); __m128 Mul11 = _mm_mul_ps(Vec2, Fac5); __m128 Sub03 = _mm_sub_ps(Mul09, Mul10); __m128 Add03 = _mm_add_ps(Sub03, Mul11); __m128 Inv3 = _mm_mul_ps(SignA, Add03); __m128 Row0 = _mm_shuffle_ps(Inv0, Inv1, _MM_SHUFFLE(0, 0, 0, 0)); __m128 Row1 = _mm_shuffle_ps(Inv2, Inv3, _MM_SHUFFLE(0, 0, 0, 0)); __m128 Row2 = _mm_shuffle_ps(Row0, Row1, _MM_SHUFFLE(2, 0, 2, 0)); // valType Determinant = m[0][0] * Inverse[0][0] // + m[0][1] * Inverse[1][0] // + m[0][2] * Inverse[2][0] // + m[0][3] * Inverse[3][0]; __m128 Det0 = glm_vec4_dot(in[0], Row2); return Det0; } GLM_FUNC_QUALIFIER glm_vec4 glm_mat4_determinant_lowp(glm_vec4 const m[4]) { // _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128( //T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; //T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; //T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; //T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; //T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; //T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; // First 2 columns __m128 Swp2A = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[2]), _MM_SHUFFLE(0, 1, 1, 2))); __m128 Swp3A = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[3]), _MM_SHUFFLE(3, 2, 3, 3))); __m128 MulA = _mm_mul_ps(Swp2A, Swp3A); // Second 2 columns __m128 Swp2B = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[2]), _MM_SHUFFLE(3, 2, 3, 3))); __m128 Swp3B = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[3]), _MM_SHUFFLE(0, 1, 1, 2))); __m128 MulB = _mm_mul_ps(Swp2B, Swp3B); // Columns subtraction __m128 SubE = _mm_sub_ps(MulA, MulB); // Last 2 rows __m128 Swp2C = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[2]), _MM_SHUFFLE(0, 0, 1, 2))); __m128 Swp3C = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[3]), _MM_SHUFFLE(1, 2, 0, 0))); __m128 MulC = _mm_mul_ps(Swp2C, Swp3C); __m128 SubF = _mm_sub_ps(_mm_movehl_ps(MulC, MulC), MulC); //vec<4, T, Q> DetCof( // + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02), // - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04), // + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05), // - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05)); __m128 SubFacA = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(SubE), _MM_SHUFFLE(2, 1, 0, 0))); __m128 SwpFacA = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[1]), _MM_SHUFFLE(0, 0, 0, 1))); __m128 MulFacA = _mm_mul_ps(SwpFacA, SubFacA); __m128 SubTmpB = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(0, 0, 3, 1)); __m128 SubFacB = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(SubTmpB), _MM_SHUFFLE(3, 1, 1, 0)));//SubF[0], SubE[3], SubE[3], SubE[1]; __m128 SwpFacB = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[1]), _MM_SHUFFLE(1, 1, 2, 2))); __m128 MulFacB = _mm_mul_ps(SwpFacB, SubFacB); __m128 SubRes = _mm_sub_ps(MulFacA, MulFacB); __m128 SubTmpC = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(1, 0, 2, 2)); __m128 SubFacC = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(SubTmpC), _MM_SHUFFLE(3, 3, 2, 0))); __m128 SwpFacC = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[1]), _MM_SHUFFLE(2, 3, 3, 3))); __m128 MulFacC = _mm_mul_ps(SwpFacC, SubFacC); __m128 AddRes = _mm_add_ps(SubRes, MulFacC); __m128 DetCof = _mm_mul_ps(AddRes, _mm_setr_ps( 1.0f,-1.0f, 1.0f,-1.0f)); //return m[0][0] * DetCof[0] // + m[0][1] * DetCof[1] // + m[0][2] * DetCof[2] // + m[0][3] * DetCof[3]; return glm_vec4_dot(m[0], DetCof); } GLM_FUNC_QUALIFIER glm_vec4 glm_mat4_determinant(glm_vec4 const m[4]) { // _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(add) //T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; //T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; //T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; //T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; //T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; //T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; // First 2 columns __m128 Swp2A = _mm_shuffle_ps(m[2], m[2], _MM_SHUFFLE(0, 1, 1, 2)); __m128 Swp3A = _mm_shuffle_ps(m[3], m[3], _MM_SHUFFLE(3, 2, 3, 3)); __m128 MulA = _mm_mul_ps(Swp2A, Swp3A); // Second 2 columns __m128 Swp2B = _mm_shuffle_ps(m[2], m[2], _MM_SHUFFLE(3, 2, 3, 3)); __m128 Swp3B = _mm_shuffle_ps(m[3], m[3], _MM_SHUFFLE(0, 1, 1, 2)); __m128 MulB = _mm_mul_ps(Swp2B, Swp3B); // Columns subtraction __m128 SubE = _mm_sub_ps(MulA, MulB); // Last 2 rows __m128 Swp2C = _mm_shuffle_ps(m[2], m[2], _MM_SHUFFLE(0, 0, 1, 2)); __m128 Swp3C = _mm_shuffle_ps(m[3], m[3], _MM_SHUFFLE(1, 2, 0, 0)); __m128 MulC = _mm_mul_ps(Swp2C, Swp3C); __m128 SubF = _mm_sub_ps(_mm_movehl_ps(MulC, MulC), MulC); //vec<4, T, Q> DetCof( // + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02), // - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04), // + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05), // - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05)); __m128 SubFacA = _mm_shuffle_ps(SubE, SubE, _MM_SHUFFLE(2, 1, 0, 0)); __m128 SwpFacA = _mm_shuffle_ps(m[1], m[1], _MM_SHUFFLE(0, 0, 0, 1)); __m128 MulFacA = _mm_mul_ps(SwpFacA, SubFacA); __m128 SubTmpB = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(0, 0, 3, 1)); __m128 SubFacB = _mm_shuffle_ps(SubTmpB, SubTmpB, _MM_SHUFFLE(3, 1, 1, 0));//SubF[0], SubE[3], SubE[3], SubE[1]; __m128 SwpFacB = _mm_shuffle_ps(m[1], m[1], _MM_SHUFFLE(1, 1, 2, 2)); __m128 MulFacB = _mm_mul_ps(SwpFacB, SubFacB); __m128 SubRes = _mm_sub_ps(MulFacA, MulFacB); __m128 SubTmpC = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(1, 0, 2, 2)); __m128 SubFacC = _mm_shuffle_ps(SubTmpC, SubTmpC, _MM_SHUFFLE(3, 3, 2, 0)); __m128 SwpFacC = _mm_shuffle_ps(m[1], m[1], _MM_SHUFFLE(2, 3, 3, 3)); __m128 MulFacC = _mm_mul_ps(SwpFacC, SubFacC); __m128 AddRes = _mm_add_ps(SubRes, MulFacC); __m128 DetCof = _mm_mul_ps(AddRes, _mm_setr_ps( 1.0f,-1.0f, 1.0f,-1.0f)); //return m[0][0] * DetCof[0] // + m[0][1] * DetCof[1] // + m[0][2] * DetCof[2] // + m[0][3] * DetCof[3]; return glm_vec4_dot(m[0], DetCof); } GLM_FUNC_QUALIFIER void glm_mat4_inverse(glm_vec4 const in[4], glm_vec4 out[4]) { __m128 Fac0; { // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; // valType SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; // valType SubFactor13 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); Fac0 = _mm_sub_ps(Mul00, Mul01); } __m128 Fac1; { // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; // valType SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; // valType SubFactor14 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); Fac1 = _mm_sub_ps(Mul00, Mul01); } __m128 Fac2; { // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; // valType SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; // valType SubFactor15 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); Fac2 = _mm_sub_ps(Mul00, Mul01); } __m128 Fac3; { // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; // valType SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; // valType SubFactor16 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); Fac3 = _mm_sub_ps(Mul00, Mul01); } __m128 Fac4; { // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; // valType SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; // valType SubFactor17 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); Fac4 = _mm_sub_ps(Mul00, Mul01); } __m128 Fac5; { // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; // valType SubFactor12 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; // valType SubFactor18 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); Fac5 = _mm_sub_ps(Mul00, Mul01); } __m128 SignA = _mm_set_ps( 1.0f,-1.0f, 1.0f,-1.0f); __m128 SignB = _mm_set_ps(-1.0f, 1.0f,-1.0f, 1.0f); // m[1][0] // m[0][0] // m[0][0] // m[0][0] __m128 Temp0 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Vec0 = _mm_shuffle_ps(Temp0, Temp0, _MM_SHUFFLE(2, 2, 2, 0)); // m[1][1] // m[0][1] // m[0][1] // m[0][1] __m128 Temp1 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Vec1 = _mm_shuffle_ps(Temp1, Temp1, _MM_SHUFFLE(2, 2, 2, 0)); // m[1][2] // m[0][2] // m[0][2] // m[0][2] __m128 Temp2 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Vec2 = _mm_shuffle_ps(Temp2, Temp2, _MM_SHUFFLE(2, 2, 2, 0)); // m[1][3] // m[0][3] // m[0][3] // m[0][3] __m128 Temp3 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Vec3 = _mm_shuffle_ps(Temp3, Temp3, _MM_SHUFFLE(2, 2, 2, 0)); // col0 // + (Vec1[0] * Fac0[0] - Vec2[0] * Fac1[0] + Vec3[0] * Fac2[0]), // - (Vec1[1] * Fac0[1] - Vec2[1] * Fac1[1] + Vec3[1] * Fac2[1]), // + (Vec1[2] * Fac0[2] - Vec2[2] * Fac1[2] + Vec3[2] * Fac2[2]), // - (Vec1[3] * Fac0[3] - Vec2[3] * Fac1[3] + Vec3[3] * Fac2[3]), __m128 Mul00 = _mm_mul_ps(Vec1, Fac0); __m128 Mul01 = _mm_mul_ps(Vec2, Fac1); __m128 Mul02 = _mm_mul_ps(Vec3, Fac2); __m128 Sub00 = _mm_sub_ps(Mul00, Mul01); __m128 Add00 = _mm_add_ps(Sub00, Mul02); __m128 Inv0 = _mm_mul_ps(SignB, Add00); // col1 // - (Vec0[0] * Fac0[0] - Vec2[0] * Fac3[0] + Vec3[0] * Fac4[0]), // + (Vec0[0] * Fac0[1] - Vec2[1] * Fac3[1] + Vec3[1] * Fac4[1]), // - (Vec0[0] * Fac0[2] - Vec2[2] * Fac3[2] + Vec3[2] * Fac4[2]), // + (Vec0[0] * Fac0[3] - Vec2[3] * Fac3[3] + Vec3[3] * Fac4[3]), __m128 Mul03 = _mm_mul_ps(Vec0, Fac0); __m128 Mul04 = _mm_mul_ps(Vec2, Fac3); __m128 Mul05 = _mm_mul_ps(Vec3, Fac4); __m128 Sub01 = _mm_sub_ps(Mul03, Mul04); __m128 Add01 = _mm_add_ps(Sub01, Mul05); __m128 Inv1 = _mm_mul_ps(SignA, Add01); // col2 // + (Vec0[0] * Fac1[0] - Vec1[0] * Fac3[0] + Vec3[0] * Fac5[0]), // - (Vec0[0] * Fac1[1] - Vec1[1] * Fac3[1] + Vec3[1] * Fac5[1]), // + (Vec0[0] * Fac1[2] - Vec1[2] * Fac3[2] + Vec3[2] * Fac5[2]), // - (Vec0[0] * Fac1[3] - Vec1[3] * Fac3[3] + Vec3[3] * Fac5[3]), __m128 Mul06 = _mm_mul_ps(Vec0, Fac1); __m128 Mul07 = _mm_mul_ps(Vec1, Fac3); __m128 Mul08 = _mm_mul_ps(Vec3, Fac5); __m128 Sub02 = _mm_sub_ps(Mul06, Mul07); __m128 Add02 = _mm_add_ps(Sub02, Mul08); __m128 Inv2 = _mm_mul_ps(SignB, Add02); // col3 // - (Vec1[0] * Fac2[0] - Vec1[0] * Fac4[0] + Vec2[0] * Fac5[0]), // + (Vec1[0] * Fac2[1] - Vec1[1] * Fac4[1] + Vec2[1] * Fac5[1]), // - (Vec1[0] * Fac2[2] - Vec1[2] * Fac4[2] + Vec2[2] * Fac5[2]), // + (Vec1[0] * Fac2[3] - Vec1[3] * Fac4[3] + Vec2[3] * Fac5[3])); __m128 Mul09 = _mm_mul_ps(Vec0, Fac2); __m128 Mul10 = _mm_mul_ps(Vec1, Fac4); __m128 Mul11 = _mm_mul_ps(Vec2, Fac5); __m128 Sub03 = _mm_sub_ps(Mul09, Mul10); __m128 Add03 = _mm_add_ps(Sub03, Mul11); __m128 Inv3 = _mm_mul_ps(SignA, Add03); __m128 Row0 = _mm_shuffle_ps(Inv0, Inv1, _MM_SHUFFLE(0, 0, 0, 0)); __m128 Row1 = _mm_shuffle_ps(Inv2, Inv3, _MM_SHUFFLE(0, 0, 0, 0)); __m128 Row2 = _mm_shuffle_ps(Row0, Row1, _MM_SHUFFLE(2, 0, 2, 0)); // valType Determinant = m[0][0] * Inverse[0][0] // + m[0][1] * Inverse[1][0] // + m[0][2] * Inverse[2][0] // + m[0][3] * Inverse[3][0]; __m128 Det0 = glm_vec4_dot(in[0], Row2); __m128 Rcp0 = _mm_div_ps(_mm_set1_ps(1.0f), Det0); //__m128 Rcp0 = _mm_rcp_ps(Det0); // Inverse /= Determinant; out[0] = _mm_mul_ps(Inv0, Rcp0); out[1] = _mm_mul_ps(Inv1, Rcp0); out[2] = _mm_mul_ps(Inv2, Rcp0); out[3] = _mm_mul_ps(Inv3, Rcp0); } GLM_FUNC_QUALIFIER void glm_mat4_inverse_lowp(glm_vec4 const in[4], glm_vec4 out[4]) { __m128 Fac0; { // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; // valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; // valType SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; // valType SubFactor13 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); Fac0 = _mm_sub_ps(Mul00, Mul01); } __m128 Fac1; { // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; // valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; // valType SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; // valType SubFactor14 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); Fac1 = _mm_sub_ps(Mul00, Mul01); } __m128 Fac2; { // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; // valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; // valType SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; // valType SubFactor15 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); Fac2 = _mm_sub_ps(Mul00, Mul01); } __m128 Fac3; { // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; // valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; // valType SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; // valType SubFactor16 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); Fac3 = _mm_sub_ps(Mul00, Mul01); } __m128 Fac4; { // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; // valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; // valType SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; // valType SubFactor17 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); Fac4 = _mm_sub_ps(Mul00, Mul01); } __m128 Fac5; { // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; // valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; // valType SubFactor12 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; // valType SubFactor18 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Mul00 = _mm_mul_ps(Swp00, Swp01); __m128 Mul01 = _mm_mul_ps(Swp02, Swp03); Fac5 = _mm_sub_ps(Mul00, Mul01); } __m128 SignA = _mm_set_ps( 1.0f,-1.0f, 1.0f,-1.0f); __m128 SignB = _mm_set_ps(-1.0f, 1.0f,-1.0f, 1.0f); // m[1][0] // m[0][0] // m[0][0] // m[0][0] __m128 Temp0 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(0, 0, 0, 0)); __m128 Vec0 = _mm_shuffle_ps(Temp0, Temp0, _MM_SHUFFLE(2, 2, 2, 0)); // m[1][1] // m[0][1] // m[0][1] // m[0][1] __m128 Temp1 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(1, 1, 1, 1)); __m128 Vec1 = _mm_shuffle_ps(Temp1, Temp1, _MM_SHUFFLE(2, 2, 2, 0)); // m[1][2] // m[0][2] // m[0][2] // m[0][2] __m128 Temp2 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(2, 2, 2, 2)); __m128 Vec2 = _mm_shuffle_ps(Temp2, Temp2, _MM_SHUFFLE(2, 2, 2, 0)); // m[1][3] // m[0][3] // m[0][3] // m[0][3] __m128 Temp3 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(3, 3, 3, 3)); __m128 Vec3 = _mm_shuffle_ps(Temp3, Temp3, _MM_SHUFFLE(2, 2, 2, 0)); // col0 // + (Vec1[0] * Fac0[0] - Vec2[0] * Fac1[0] + Vec3[0] * Fac2[0]), // - (Vec1[1] * Fac0[1] - Vec2[1] * Fac1[1] + Vec3[1] * Fac2[1]), // + (Vec1[2] * Fac0[2] - Vec2[2] * Fac1[2] + Vec3[2] * Fac2[2]), // - (Vec1[3] * Fac0[3] - Vec2[3] * Fac1[3] + Vec3[3] * Fac2[3]), __m128 Mul00 = _mm_mul_ps(Vec1, Fac0); __m128 Mul01 = _mm_mul_ps(Vec2, Fac1); __m128 Mul02 = _mm_mul_ps(Vec3, Fac2); __m128 Sub00 = _mm_sub_ps(Mul00, Mul01); __m128 Add00 = _mm_add_ps(Sub00, Mul02); __m128 Inv0 = _mm_mul_ps(SignB, Add00); // col1 // - (Vec0[0] * Fac0[0] - Vec2[0] * Fac3[0] + Vec3[0] * Fac4[0]), // + (Vec0[0] * Fac0[1] - Vec2[1] * Fac3[1] + Vec3[1] * Fac4[1]), // - (Vec0[0] * Fac0[2] - Vec2[2] * Fac3[2] + Vec3[2] * Fac4[2]), // + (Vec0[0] * Fac0[3] - Vec2[3] * Fac3[3] + Vec3[3] * Fac4[3]), __m128 Mul03 = _mm_mul_ps(Vec0, Fac0); __m128 Mul04 = _mm_mul_ps(Vec2, Fac3); __m128 Mul05 = _mm_mul_ps(Vec3, Fac4); __m128 Sub01 = _mm_sub_ps(Mul03, Mul04); __m128 Add01 = _mm_add_ps(Sub01, Mul05); __m128 Inv1 = _mm_mul_ps(SignA, Add01); // col2 // + (Vec0[0] * Fac1[0] - Vec1[0] * Fac3[0] + Vec3[0] * Fac5[0]), // - (Vec0[0] * Fac1[1] - Vec1[1] * Fac3[1] + Vec3[1] * Fac5[1]), // + (Vec0[0] * Fac1[2] - Vec1[2] * Fac3[2] + Vec3[2] * Fac5[2]), // - (Vec0[0] * Fac1[3] - Vec1[3] * Fac3[3] + Vec3[3] * Fac5[3]), __m128 Mul06 = _mm_mul_ps(Vec0, Fac1); __m128 Mul07 = _mm_mul_ps(Vec1, Fac3); __m128 Mul08 = _mm_mul_ps(Vec3, Fac5); __m128 Sub02 = _mm_sub_ps(Mul06, Mul07); __m128 Add02 = _mm_add_ps(Sub02, Mul08); __m128 Inv2 = _mm_mul_ps(SignB, Add02); // col3 // - (Vec1[0] * Fac2[0] - Vec1[0] * Fac4[0] + Vec2[0] * Fac5[0]), // + (Vec1[0] * Fac2[1] - Vec1[1] * Fac4[1] + Vec2[1] * Fac5[1]), // - (Vec1[0] * Fac2[2] - Vec1[2] * Fac4[2] + Vec2[2] * Fac5[2]), // + (Vec1[0] * Fac2[3] - Vec1[3] * Fac4[3] + Vec2[3] * Fac5[3])); __m128 Mul09 = _mm_mul_ps(Vec0, Fac2); __m128 Mul10 = _mm_mul_ps(Vec1, Fac4); __m128 Mul11 = _mm_mul_ps(Vec2, Fac5); __m128 Sub03 = _mm_sub_ps(Mul09, Mul10); __m128 Add03 = _mm_add_ps(Sub03, Mul11); __m128 Inv3 = _mm_mul_ps(SignA, Add03); __m128 Row0 = _mm_shuffle_ps(Inv0, Inv1, _MM_SHUFFLE(0, 0, 0, 0)); __m128 Row1 = _mm_shuffle_ps(Inv2, Inv3, _MM_SHUFFLE(0, 0, 0, 0)); __m128 Row2 = _mm_shuffle_ps(Row0, Row1, _MM_SHUFFLE(2, 0, 2, 0)); // valType Determinant = m[0][0] * Inverse[0][0] // + m[0][1] * Inverse[1][0] // + m[0][2] * Inverse[2][0] // + m[0][3] * Inverse[3][0]; __m128 Det0 = glm_vec4_dot(in[0], Row2); __m128 Rcp0 = _mm_rcp_ps(Det0); //__m128 Rcp0 = _mm_div_ps(one, Det0); // Inverse /= Determinant; out[0] = _mm_mul_ps(Inv0, Rcp0); out[1] = _mm_mul_ps(Inv1, Rcp0); out[2] = _mm_mul_ps(Inv2, Rcp0); out[3] = _mm_mul_ps(Inv3, Rcp0); } /* GLM_FUNC_QUALIFIER void glm_mat4_rotate(__m128 const in[4], float Angle, float const v[3], __m128 out[4]) { float a = glm::radians(Angle); float c = cos(a); float s = sin(a); glm::vec4 AxisA(v[0], v[1], v[2], float(0)); __m128 AxisB = _mm_set_ps(AxisA.w, AxisA.z, AxisA.y, AxisA.x); __m128 AxisC = detail::sse_nrm_ps(AxisB); __m128 Cos0 = _mm_set_ss(c); __m128 CosA = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(0, 0, 0, 0)); __m128 Sin0 = _mm_set_ss(s); __m128 SinA = _mm_shuffle_ps(Sin0, Sin0, _MM_SHUFFLE(0, 0, 0, 0)); // vec<3, T, Q> temp = (valType(1) - c) * axis; __m128 Temp0 = _mm_sub_ps(one, CosA); __m128 Temp1 = _mm_mul_ps(Temp0, AxisC); //Rotate[0][0] = c + temp[0] * axis[0]; //Rotate[0][1] = 0 + temp[0] * axis[1] + s * axis[2]; //Rotate[0][2] = 0 + temp[0] * axis[2] - s * axis[1]; __m128 Axis0 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(0, 0, 0, 0)); __m128 TmpA0 = _mm_mul_ps(Axis0, AxisC); __m128 CosA0 = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(1, 1, 1, 0)); __m128 TmpA1 = _mm_add_ps(CosA0, TmpA0); __m128 SinA0 = SinA;//_mm_set_ps(0.0f, s, -s, 0.0f); __m128 TmpA2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(3, 1, 2, 3)); __m128 TmpA3 = _mm_mul_ps(SinA0, TmpA2); __m128 TmpA4 = _mm_add_ps(TmpA1, TmpA3); //Rotate[1][0] = 0 + temp[1] * axis[0] - s * axis[2]; //Rotate[1][1] = c + temp[1] * axis[1]; //Rotate[1][2] = 0 + temp[1] * axis[2] + s * axis[0]; __m128 Axis1 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(1, 1, 1, 1)); __m128 TmpB0 = _mm_mul_ps(Axis1, AxisC); __m128 CosA1 = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(1, 1, 0, 1)); __m128 TmpB1 = _mm_add_ps(CosA1, TmpB0); __m128 SinB0 = SinA;//_mm_set_ps(-s, 0.0f, s, 0.0f); __m128 TmpB2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(3, 0, 3, 2)); __m128 TmpB3 = _mm_mul_ps(SinA0, TmpB2); __m128 TmpB4 = _mm_add_ps(TmpB1, TmpB3); //Rotate[2][0] = 0 + temp[2] * axis[0] + s * axis[1]; //Rotate[2][1] = 0 + temp[2] * axis[1] - s * axis[0]; //Rotate[2][2] = c + temp[2] * axis[2]; __m128 Axis2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(2, 2, 2, 2)); __m128 TmpC0 = _mm_mul_ps(Axis2, AxisC); __m128 CosA2 = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(1, 0, 1, 1)); __m128 TmpC1 = _mm_add_ps(CosA2, TmpC0); __m128 SinC0 = SinA;//_mm_set_ps(s, -s, 0.0f, 0.0f); __m128 TmpC2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(3, 3, 0, 1)); __m128 TmpC3 = _mm_mul_ps(SinA0, TmpC2); __m128 TmpC4 = _mm_add_ps(TmpC1, TmpC3); __m128 Result[4]; Result[0] = TmpA4; Result[1] = TmpB4; Result[2] = TmpC4; Result[3] = _mm_set_ps(1, 0, 0, 0); //mat<4, 4, valType> Result; //Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2]; //Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2]; //Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2]; //Result[3] = m[3]; //return Result; sse_mul_ps(in, Result, out); } */ GLM_FUNC_QUALIFIER void glm_mat4_outerProduct(__m128 const& c, __m128 const& r, __m128 out[4]) { out[0] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(0, 0, 0, 0))); out[1] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(1, 1, 1, 1))); out[2] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(2, 2, 2, 2))); out[3] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(3, 3, 3, 3))); } #endif//GLM_ARCH & GLM_ARCH_SSE2_BIT connectome-workbench-1.4.2/src/GLMath/glm/simd/packing.h000066400000000000000000000002111360521144700230300ustar00rootroot00000000000000/// @ref simd /// @file glm/simd/packing.h #pragma once #if GLM_ARCH & GLM_ARCH_SSE2_BIT #endif//GLM_ARCH & GLM_ARCH_SSE2_BIT connectome-workbench-1.4.2/src/GLMath/glm/simd/platform.h000066400000000000000000000322631360521144700232540ustar00rootroot00000000000000#pragma once /////////////////////////////////////////////////////////////////////////////////// // Platform #define GLM_PLATFORM_UNKNOWN 0x00000000 #define GLM_PLATFORM_WINDOWS 0x00010000 #define GLM_PLATFORM_LINUX 0x00020000 #define GLM_PLATFORM_APPLE 0x00040000 //#define GLM_PLATFORM_IOS 0x00080000 #define GLM_PLATFORM_ANDROID 0x00100000 #define GLM_PLATFORM_CHROME_NACL 0x00200000 #define GLM_PLATFORM_UNIX 0x00400000 #define GLM_PLATFORM_QNXNTO 0x00800000 #define GLM_PLATFORM_WINCE 0x01000000 #define GLM_PLATFORM_CYGWIN 0x02000000 #ifdef GLM_FORCE_PLATFORM_UNKNOWN # define GLM_PLATFORM GLM_PLATFORM_UNKNOWN #elif defined(__CYGWIN__) # define GLM_PLATFORM GLM_PLATFORM_CYGWIN #elif defined(__QNXNTO__) # define GLM_PLATFORM GLM_PLATFORM_QNXNTO #elif defined(__APPLE__) # define GLM_PLATFORM GLM_PLATFORM_APPLE #elif defined(WINCE) # define GLM_PLATFORM GLM_PLATFORM_WINCE #elif defined(_WIN32) # define GLM_PLATFORM GLM_PLATFORM_WINDOWS #elif defined(__native_client__) # define GLM_PLATFORM GLM_PLATFORM_CHROME_NACL #elif defined(__ANDROID__) # define GLM_PLATFORM GLM_PLATFORM_ANDROID #elif defined(__linux) # define GLM_PLATFORM GLM_PLATFORM_LINUX #elif defined(__unix) # define GLM_PLATFORM GLM_PLATFORM_UNIX #else # define GLM_PLATFORM GLM_PLATFORM_UNKNOWN #endif// /////////////////////////////////////////////////////////////////////////////////// // Compiler #define GLM_COMPILER_UNKNOWN 0x00000000 // Intel #define GLM_COMPILER_INTEL 0x00100000 #define GLM_COMPILER_INTEL14 0x00100040 #define GLM_COMPILER_INTEL15 0x00100050 #define GLM_COMPILER_INTEL16 0x00100060 #define GLM_COMPILER_INTEL17 0x00100070 // Visual C++ defines #define GLM_COMPILER_VC 0x01000000 #define GLM_COMPILER_VC12 0x01000001 #define GLM_COMPILER_VC14 0x01000002 #define GLM_COMPILER_VC15 0x01000003 #define GLM_COMPILER_VC15_3 0x01000004 #define GLM_COMPILER_VC15_5 0x01000005 #define GLM_COMPILER_VC15_6 0x01000006 #define GLM_COMPILER_VC15_7 0x01000007 #define GLM_COMPILER_VC15_8 0x01000008 #define GLM_COMPILER_VC15_9 0x01000009 #define GLM_COMPILER_VC16 0x0100000A // GCC defines #define GLM_COMPILER_GCC 0x02000000 #define GLM_COMPILER_GCC46 0x020000D0 #define GLM_COMPILER_GCC47 0x020000E0 #define GLM_COMPILER_GCC48 0x020000F0 #define GLM_COMPILER_GCC49 0x02000100 #define GLM_COMPILER_GCC5 0x02000200 #define GLM_COMPILER_GCC6 0x02000300 #define GLM_COMPILER_GCC7 0x02000400 #define GLM_COMPILER_GCC8 0x02000500 // CUDA #define GLM_COMPILER_CUDA 0x10000000 #define GLM_COMPILER_CUDA75 0x10000001 #define GLM_COMPILER_CUDA80 0x10000002 #define GLM_COMPILER_CUDA90 0x10000004 // SYCL #define GLM_COMPILER_SYCL 0x00300000 // Clang #define GLM_COMPILER_CLANG 0x20000000 #define GLM_COMPILER_CLANG34 0x20000050 #define GLM_COMPILER_CLANG35 0x20000060 #define GLM_COMPILER_CLANG36 0x20000070 #define GLM_COMPILER_CLANG37 0x20000080 #define GLM_COMPILER_CLANG38 0x20000090 #define GLM_COMPILER_CLANG39 0x200000A0 #define GLM_COMPILER_CLANG40 0x200000B0 #define GLM_COMPILER_CLANG41 0x200000C0 #define GLM_COMPILER_CLANG42 0x200000D0 // Build model #define GLM_MODEL_32 0x00000010 #define GLM_MODEL_64 0x00000020 // Force generic C++ compiler #ifdef GLM_FORCE_COMPILER_UNKNOWN # define GLM_COMPILER GLM_COMPILER_UNKNOWN #elif defined(__INTEL_COMPILER) # if __INTEL_COMPILER >= 1700 # define GLM_COMPILER GLM_COMPILER_INTEL17 # elif __INTEL_COMPILER >= 1600 # define GLM_COMPILER GLM_COMPILER_INTEL16 # elif __INTEL_COMPILER >= 1500 # define GLM_COMPILER GLM_COMPILER_INTEL15 # elif __INTEL_COMPILER >= 1400 # define GLM_COMPILER GLM_COMPILER_INTEL14 # elif __INTEL_COMPILER < 1400 # error "GLM requires ICC 2013 SP1 or newer" # endif // CUDA #elif defined(__CUDACC__) # if !defined(CUDA_VERSION) && !defined(GLM_FORCE_CUDA) # include // make sure version is defined since nvcc does not define it itself! # endif # if CUDA_VERSION >= 8000 # define GLM_COMPILER GLM_COMPILER_CUDA80 # elif CUDA_VERSION >= 7500 # define GLM_COMPILER GLM_COMPILER_CUDA75 # elif CUDA_VERSION >= 7000 # define GLM_COMPILER GLM_COMPILER_CUDA70 # elif CUDA_VERSION < 7000 # error "GLM requires CUDA 7.0 or higher" # endif // SYCL #elif defined(__SYCL_DEVICE_ONLY__) # define GLM_COMPILER GLM_COMPILER_SYCL // Clang #elif defined(__clang__) # if defined(__apple_build_version__) # if (__clang_major__ < 6) # error "GLM requires Clang 3.4 / Apple Clang 6.0 or higher" # elif __clang_major__ == 6 && __clang_minor__ == 0 # define GLM_COMPILER GLM_COMPILER_CLANG35 # elif __clang_major__ == 6 && __clang_minor__ >= 1 # define GLM_COMPILER GLM_COMPILER_CLANG36 # elif __clang_major__ >= 7 # define GLM_COMPILER GLM_COMPILER_CLANG37 # endif # else # if ((__clang_major__ == 3) && (__clang_minor__ < 4)) || (__clang_major__ < 3) # error "GLM requires Clang 3.4 or higher" # elif __clang_major__ == 3 && __clang_minor__ == 4 # define GLM_COMPILER GLM_COMPILER_CLANG34 # elif __clang_major__ == 3 && __clang_minor__ == 5 # define GLM_COMPILER GLM_COMPILER_CLANG35 # elif __clang_major__ == 3 && __clang_minor__ == 6 # define GLM_COMPILER GLM_COMPILER_CLANG36 # elif __clang_major__ == 3 && __clang_minor__ == 7 # define GLM_COMPILER GLM_COMPILER_CLANG37 # elif __clang_major__ == 3 && __clang_minor__ == 8 # define GLM_COMPILER GLM_COMPILER_CLANG38 # elif __clang_major__ == 3 && __clang_minor__ >= 9 # define GLM_COMPILER GLM_COMPILER_CLANG39 # elif __clang_major__ == 4 && __clang_minor__ == 0 # define GLM_COMPILER GLM_COMPILER_CLANG40 # elif __clang_major__ == 4 && __clang_minor__ == 1 # define GLM_COMPILER GLM_COMPILER_CLANG41 # elif __clang_major__ == 4 && __clang_minor__ >= 2 # define GLM_COMPILER GLM_COMPILER_CLANG42 # elif __clang_major__ >= 4 # define GLM_COMPILER GLM_COMPILER_CLANG42 # endif # endif // Visual C++ #elif defined(_MSC_VER) # if _MSC_VER >= 1920 # define GLM_COMPILER GLM_COMPILER_VC16 # elif _MSC_VER >= 1916 # define GLM_COMPILER GLM_COMPILER_VC15_9 # elif _MSC_VER >= 1915 # define GLM_COMPILER GLM_COMPILER_VC15_8 # elif _MSC_VER >= 1914 # define GLM_COMPILER GLM_COMPILER_VC15_7 # elif _MSC_VER >= 1913 # define GLM_COMPILER GLM_COMPILER_VC15_6 # elif _MSC_VER >= 1912 # define GLM_COMPILER GLM_COMPILER_VC15_5 # elif _MSC_VER >= 1911 # define GLM_COMPILER GLM_COMPILER_VC15_3 # elif _MSC_VER >= 1910 # define GLM_COMPILER GLM_COMPILER_VC15 # elif _MSC_VER >= 1900 # define GLM_COMPILER GLM_COMPILER_VC14 # elif _MSC_VER >= 1800 # define GLM_COMPILER GLM_COMPILER_VC12 # elif _MSC_VER < 1800 # error "GLM requires Visual C++ 12 - 2013 or higher" # endif//_MSC_VER // G++ #elif defined(__GNUC__) || defined(__MINGW32__) # if __GNUC__ >= 8 # define GLM_COMPILER GLM_COMPILER_GCC8 # elif __GNUC__ >= 7 # define GLM_COMPILER GLM_COMPILER_GCC7 # elif __GNUC__ >= 6 # define GLM_COMPILER GLM_COMPILER_GCC6 # elif __GNUC__ >= 5 # define GLM_COMPILER GLM_COMPILER_GCC5 # elif __GNUC__ == 4 && __GNUC_MINOR__ >= 9 # define GLM_COMPILER GLM_COMPILER_GCC49 # elif __GNUC__ == 4 && __GNUC_MINOR__ >= 8 # define GLM_COMPILER GLM_COMPILER_GCC48 # elif __GNUC__ == 4 && __GNUC_MINOR__ >= 7 # define GLM_COMPILER GLM_COMPILER_GCC47 # elif __GNUC__ == 4 && __GNUC_MINOR__ >= 6 # define GLM_COMPILER GLM_COMPILER_GCC46 # elif ((__GNUC__ == 4) && (__GNUC_MINOR__ < 6)) || (__GNUC__ < 4) # error "GLM requires GCC 4.6 or higher" # endif #else # define GLM_COMPILER GLM_COMPILER_UNKNOWN #endif #ifndef GLM_COMPILER # error "GLM_COMPILER undefined, your compiler may not be supported by GLM. Add #define GLM_COMPILER 0 to ignore this message." #endif//GLM_COMPILER /////////////////////////////////////////////////////////////////////////////////// // Instruction sets // User defines: GLM_FORCE_PURE GLM_FORCE_INTRINSICS GLM_FORCE_SSE2 GLM_FORCE_SSE3 GLM_FORCE_AVX GLM_FORCE_AVX2 GLM_FORCE_AVX2 #define GLM_ARCH_MIPS_BIT (0x10000000) #define GLM_ARCH_PPC_BIT (0x20000000) #define GLM_ARCH_ARM_BIT (0x40000000) #define GLM_ARCH_ARMV8_BIT (0x01000000) #define GLM_ARCH_X86_BIT (0x80000000) #define GLM_ARCH_SIMD_BIT (0x00001000) #define GLM_ARCH_NEON_BIT (0x00000001) #define GLM_ARCH_SSE_BIT (0x00000002) #define GLM_ARCH_SSE2_BIT (0x00000004) #define GLM_ARCH_SSE3_BIT (0x00000008) #define GLM_ARCH_SSSE3_BIT (0x00000010) #define GLM_ARCH_SSE41_BIT (0x00000020) #define GLM_ARCH_SSE42_BIT (0x00000040) #define GLM_ARCH_AVX_BIT (0x00000080) #define GLM_ARCH_AVX2_BIT (0x00000100) #define GLM_ARCH_UNKNOWN (0) #define GLM_ARCH_X86 (GLM_ARCH_X86_BIT) #define GLM_ARCH_SSE (GLM_ARCH_SSE_BIT | GLM_ARCH_SIMD_BIT | GLM_ARCH_X86) #define GLM_ARCH_SSE2 (GLM_ARCH_SSE2_BIT | GLM_ARCH_SSE) #define GLM_ARCH_SSE3 (GLM_ARCH_SSE3_BIT | GLM_ARCH_SSE2) #define GLM_ARCH_SSSE3 (GLM_ARCH_SSSE3_BIT | GLM_ARCH_SSE3) #define GLM_ARCH_SSE41 (GLM_ARCH_SSE41_BIT | GLM_ARCH_SSSE3) #define GLM_ARCH_SSE42 (GLM_ARCH_SSE42_BIT | GLM_ARCH_SSE41) #define GLM_ARCH_AVX (GLM_ARCH_AVX_BIT | GLM_ARCH_SSE42) #define GLM_ARCH_AVX2 (GLM_ARCH_AVX2_BIT | GLM_ARCH_AVX) #define GLM_ARCH_ARM (GLM_ARCH_ARM_BIT) #define GLM_ARCH_ARMV8 (GLM_ARCH_NEON_BIT | GLM_ARCH_SIMD_BIT | GLM_ARCH_ARM | GLM_ARCH_ARMV8_BIT) #define GLM_ARCH_NEON (GLM_ARCH_NEON_BIT | GLM_ARCH_SIMD_BIT | GLM_ARCH_ARM) #define GLM_ARCH_MIPS (GLM_ARCH_MIPS_BIT) #define GLM_ARCH_PPC (GLM_ARCH_PPC_BIT) #if defined(GLM_FORCE_ARCH_UNKNOWN) || defined(GLM_FORCE_PURE) # define GLM_ARCH GLM_ARCH_UNKNOWN #elif defined(GLM_FORCE_NEON) # if __ARM_ARCH >= 8 # define GLM_ARCH (GLM_ARCH_ARMV8) # else # define GLM_ARCH (GLM_ARCH_NEON) # endif # define GLM_FORCE_INTRINSICS #elif defined(GLM_FORCE_AVX2) # define GLM_ARCH (GLM_ARCH_AVX2) # define GLM_FORCE_INTRINSICS #elif defined(GLM_FORCE_AVX) # define GLM_ARCH (GLM_ARCH_AVX) # define GLM_FORCE_INTRINSICS #elif defined(GLM_FORCE_SSE42) # define GLM_ARCH (GLM_ARCH_SSE42) # define GLM_FORCE_INTRINSICS #elif defined(GLM_FORCE_SSE41) # define GLM_ARCH (GLM_ARCH_SSE41) # define GLM_FORCE_INTRINSICS #elif defined(GLM_FORCE_SSSE3) # define GLM_ARCH (GLM_ARCH_SSSE3) # define GLM_FORCE_INTRINSICS #elif defined(GLM_FORCE_SSE3) # define GLM_ARCH (GLM_ARCH_SSE3) # define GLM_FORCE_INTRINSICS #elif defined(GLM_FORCE_SSE2) # define GLM_ARCH (GLM_ARCH_SSE2) # define GLM_FORCE_INTRINSICS #elif defined(GLM_FORCE_SSE) # define GLM_ARCH (GLM_ARCH_SSE) # define GLM_FORCE_INTRINSICS #elif defined(GLM_FORCE_INTRINSICS) && !defined(GLM_FORCE_XYZW_ONLY) # if defined(__AVX2__) # define GLM_ARCH (GLM_ARCH_AVX2) # elif defined(__AVX__) # define GLM_ARCH (GLM_ARCH_AVX) # elif defined(__SSE4_2__) # define GLM_ARCH (GLM_ARCH_SSE42) # elif defined(__SSE4_1__) # define GLM_ARCH (GLM_ARCH_SSE41) # elif defined(__SSSE3__) # define GLM_ARCH (GLM_ARCH_SSSE3) # elif defined(__SSE3__) # define GLM_ARCH (GLM_ARCH_SSE3) # elif defined(__SSE2__) || defined(__x86_64__) || defined(_M_X64) || defined(_M_IX86_FP) # define GLM_ARCH (GLM_ARCH_SSE2) # elif defined(__i386__) # define GLM_ARCH (GLM_ARCH_X86) # elif defined(__ARM_ARCH) && (__ARM_ARCH >= 8) # define GLM_ARCH (GLM_ARCH_ARMV8) # elif defined(__ARM_NEON) # define GLM_ARCH (GLM_ARCH_ARM | GLM_ARCH_NEON) # elif defined(__arm__ ) || defined(_M_ARM) # define GLM_ARCH (GLM_ARCH_ARM) # elif defined(__mips__ ) # define GLM_ARCH (GLM_ARCH_MIPS) # elif defined(__powerpc__ ) || defined(_M_PPC) # define GLM_ARCH (GLM_ARCH_PPC) # else # define GLM_ARCH (GLM_ARCH_UNKNOWN) # endif #else # if defined(__x86_64__) || defined(_M_X64) || defined(_M_IX86) || defined(__i386__) # define GLM_ARCH (GLM_ARCH_X86) # elif defined(__arm__) || defined(_M_ARM) # define GLM_ARCH (GLM_ARCH_ARM) # elif defined(__powerpc__) || defined(_M_PPC) # define GLM_ARCH (GLM_ARCH_PPC) # elif defined(__mips__) # define GLM_ARCH (GLM_ARCH_MIPS) # else # define GLM_ARCH (GLM_ARCH_UNKNOWN) # endif #endif #if GLM_ARCH & GLM_ARCH_AVX2_BIT # include #elif GLM_ARCH & GLM_ARCH_AVX_BIT # include #elif GLM_ARCH & GLM_ARCH_SSE42_BIT # if GLM_COMPILER & GLM_COMPILER_CLANG # include # endif # include #elif GLM_ARCH & GLM_ARCH_SSE41_BIT # include #elif GLM_ARCH & GLM_ARCH_SSSE3_BIT # include #elif GLM_ARCH & GLM_ARCH_SSE3_BIT # include #elif GLM_ARCH & GLM_ARCH_SSE2_BIT # include #elif GLM_ARCH & GLM_ARCH_NEON_BIT # include #endif//GLM_ARCH #if GLM_ARCH & GLM_ARCH_SSE2_BIT typedef __m128 glm_f32vec4; typedef __m128i glm_i32vec4; typedef __m128i glm_u32vec4; typedef __m128d glm_f64vec2; typedef __m128i glm_i64vec2; typedef __m128i glm_u64vec2; typedef glm_f32vec4 glm_vec4; typedef glm_i32vec4 glm_ivec4; typedef glm_u32vec4 glm_uvec4; typedef glm_f64vec2 glm_dvec2; #endif #if GLM_ARCH & GLM_ARCH_AVX_BIT typedef __m256d glm_f64vec4; typedef glm_f64vec4 glm_dvec4; #endif #if GLM_ARCH & GLM_ARCH_AVX2_BIT typedef __m256i glm_i64vec4; typedef __m256i glm_u64vec4; #endif #if GLM_ARCH & GLM_ARCH_NEON_BIT typedef float32x4_t glm_f32vec4; typedef int32x4_t glm_i32vec4; typedef uint32x4_t glm_u32vec4; #endif connectome-workbench-1.4.2/src/GLMath/glm/simd/trigonometric.h000066400000000000000000000002211360521144700243020ustar00rootroot00000000000000/// @ref simd /// @file glm/simd/trigonometric.h #pragma once #if GLM_ARCH & GLM_ARCH_SSE2_BIT #endif//GLM_ARCH & GLM_ARCH_SSE2_BIT connectome-workbench-1.4.2/src/GLMath/glm/simd/vector_relational.h000066400000000000000000000002231360521144700251330ustar00rootroot00000000000000/// @ref simd /// @file glm/simd/vector_relational.h #pragma once #if GLM_ARCH & GLM_ARCH_SSE2_BIT #endif//GLM_ARCH & GLM_ARCH_SSE2_BIT connectome-workbench-1.4.2/src/GLMath/glm/trigonometric.hpp000066400000000000000000000252051360521144700237170ustar00rootroot00000000000000/// @ref core /// @file glm/trigonometric.hpp /// /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions /// /// @defgroup core_func_trigonometric Angle and Trigonometry Functions /// @ingroup core /// /// Function parameters specified as angle are assumed to be in units of radians. /// In no case will any of these functions result in a divide by zero error. If /// the divisor of a ratio is 0, then results will be undefined. /// /// These all operate component-wise. The description is per component. /// /// Include to use these core features. /// /// @see ext_vector_trigonometric #pragma once #include "detail/setup.hpp" #include "detail/qualifier.hpp" namespace glm { /// @addtogroup core_func_trigonometric /// @{ /// Converts degrees to radians and returns the result. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL radians man page /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions template GLM_FUNC_DECL GLM_CONSTEXPR vec radians(vec const& degrees); /// Converts radians to degrees and returns the result. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL degrees man page /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions template GLM_FUNC_DECL GLM_CONSTEXPR vec degrees(vec const& radians); /// The standard trigonometric sine function. /// The values returned by this function will range from [-1, 1]. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL sin man page /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions template GLM_FUNC_DECL vec sin(vec const& angle); /// The standard trigonometric cosine function. /// The values returned by this function will range from [-1, 1]. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL cos man page /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions template GLM_FUNC_DECL vec cos(vec const& angle); /// The standard trigonometric tangent function. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL tan man page /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions template GLM_FUNC_DECL vec tan(vec const& angle); /// Arc sine. Returns an angle whose sine is x. /// The range of values returned by this function is [-PI/2, PI/2]. /// Results are undefined if |x| > 1. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL asin man page /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions template GLM_FUNC_DECL vec asin(vec const& x); /// Arc cosine. Returns an angle whose sine is x. /// The range of values returned by this function is [0, PI]. /// Results are undefined if |x| > 1. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL acos man page /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions template GLM_FUNC_DECL vec acos(vec const& x); /// Arc tangent. Returns an angle whose tangent is y/x. /// The signs of x and y are used to determine what /// quadrant the angle is in. The range of values returned /// by this function is [-PI, PI]. Results are undefined /// if x and y are both 0. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL atan man page /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions template GLM_FUNC_DECL vec atan(vec const& y, vec const& x); /// Arc tangent. Returns an angle whose tangent is y_over_x. /// The range of values returned by this function is [-PI/2, PI/2]. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL atan man page /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions template GLM_FUNC_DECL vec atan(vec const& y_over_x); /// Returns the hyperbolic sine function, (exp(x) - exp(-x)) / 2 /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL sinh man page /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions template GLM_FUNC_DECL vec sinh(vec const& angle); /// Returns the hyperbolic cosine function, (exp(x) + exp(-x)) / 2 /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL cosh man page /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions template GLM_FUNC_DECL vec cosh(vec const& angle); /// Returns the hyperbolic tangent function, sinh(angle) / cosh(angle) /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL tanh man page /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions template GLM_FUNC_DECL vec tanh(vec const& angle); /// Arc hyperbolic sine; returns the inverse of sinh. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL asinh man page /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions template GLM_FUNC_DECL vec asinh(vec const& x); /// Arc hyperbolic cosine; returns the non-negative inverse /// of cosh. Results are undefined if x < 1. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL acosh man page /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions template GLM_FUNC_DECL vec acosh(vec const& x); /// Arc hyperbolic tangent; returns the inverse of tanh. /// Results are undefined if abs(x) >= 1. /// /// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector /// @tparam T Floating-point scalar types /// @tparam Q Value from qualifier enum /// /// @see GLSL atanh man page /// @see GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions template GLM_FUNC_DECL vec atanh(vec const& x); /// @} }//namespace glm #include "detail/func_trigonometric.inl" connectome-workbench-1.4.2/src/GLMath/glm/vec2.hpp000066400000000000000000000007131360521144700216660ustar00rootroot00000000000000/// @ref core /// @file glm/vec2.hpp #pragma once #include "./ext/vector_bool2.hpp" #include "./ext/vector_bool2_precision.hpp" #include "./ext/vector_float2.hpp" #include "./ext/vector_float2_precision.hpp" #include "./ext/vector_double2.hpp" #include "./ext/vector_double2_precision.hpp" #include "./ext/vector_int2.hpp" #include "./ext/vector_int2_precision.hpp" #include "./ext/vector_uint2.hpp" #include "./ext/vector_uint2_precision.hpp" connectome-workbench-1.4.2/src/GLMath/glm/vec3.hpp000066400000000000000000000007131360521144700216670ustar00rootroot00000000000000/// @ref core /// @file glm/vec3.hpp #pragma once #include "./ext/vector_bool3.hpp" #include "./ext/vector_bool3_precision.hpp" #include "./ext/vector_float3.hpp" #include "./ext/vector_float3_precision.hpp" #include "./ext/vector_double3.hpp" #include "./ext/vector_double3_precision.hpp" #include "./ext/vector_int3.hpp" #include "./ext/vector_int3_precision.hpp" #include "./ext/vector_uint3.hpp" #include "./ext/vector_uint3_precision.hpp" connectome-workbench-1.4.2/src/GLMath/glm/vec4.hpp000066400000000000000000000007151360521144700216720ustar00rootroot00000000000000/// @ref core /// @file glm/vec4.hpp #pragma once #include "./ext/vector_bool4.hpp" #include "./ext/vector_bool4_precision.hpp" #include "./ext/vector_float4.hpp" #include "./ext/vector_float4_precision.hpp" #include "./ext/vector_double4.hpp" #include "./ext/vector_double4_precision.hpp" #include "./ext/vector_int4.hpp" #include "./ext/vector_int4_precision.hpp" #include "./ext/vector_uint4.hpp" #include "./ext/vector_uint4_precision.hpp" connectome-workbench-1.4.2/src/GLMath/glm/vector_relational.hpp000066400000000000000000000145001360521144700245420ustar00rootroot00000000000000/// @ref core /// @file glm/vector_relational.hpp /// /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions /// /// @defgroup core_func_vector_relational Vector Relational Functions /// @ingroup core /// /// Relational and equality operators (<, <=, >, >=, ==, !=) are defined to /// operate on scalars and produce scalar Boolean results. For vector results, /// use the following built-in functions. /// /// In all cases, the sizes of all the input and return vectors for any particular /// call must match. /// /// Include to use these core features. /// /// @see ext_vector_relational #pragma once #include "detail/qualifier.hpp" #include "detail/setup.hpp" namespace glm { /// @addtogroup core_func_vector_relational /// @{ /// Returns the component-wise comparison result of x < y. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T A floating-point or integer scalar type. /// /// @see GLSL lessThan man page /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions template GLM_FUNC_DECL GLM_CONSTEXPR vec lessThan(vec const& x, vec const& y); /// Returns the component-wise comparison of result x <= y. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T A floating-point or integer scalar type. /// /// @see GLSL lessThanEqual man page /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions template GLM_FUNC_DECL GLM_CONSTEXPR vec lessThanEqual(vec const& x, vec const& y); /// Returns the component-wise comparison of result x > y. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T A floating-point or integer scalar type. /// /// @see GLSL greaterThan man page /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions template GLM_FUNC_DECL GLM_CONSTEXPR vec greaterThan(vec const& x, vec const& y); /// Returns the component-wise comparison of result x >= y. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T A floating-point or integer scalar type. /// /// @see GLSL greaterThanEqual man page /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions template GLM_FUNC_DECL GLM_CONSTEXPR vec greaterThanEqual(vec const& x, vec const& y); /// Returns the component-wise comparison of result x == y. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T A floating-point, integer or bool scalar type. /// /// @see GLSL equal man page /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions template GLM_FUNC_DECL GLM_CONSTEXPR vec equal(vec const& x, vec const& y); /// Returns the component-wise comparison of result x != y. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// @tparam T A floating-point, integer or bool scalar type. /// /// @see GLSL notEqual man page /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions template GLM_FUNC_DECL GLM_CONSTEXPR vec notEqual(vec const& x, vec const& y); /// Returns true if any component of x is true. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// /// @see GLSL any man page /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions template GLM_FUNC_DECL GLM_CONSTEXPR bool any(vec const& v); /// Returns true if all components of x are true. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// /// @see GLSL all man page /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions template GLM_FUNC_DECL GLM_CONSTEXPR bool all(vec const& v); /// Returns the component-wise logical complement of x. /// /!\ Because of language incompatibilities between C++ and GLSL, GLM defines the function not but not_ instead. /// /// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector. /// /// @see GLSL not man page /// @see GLSL 4.20.8 specification, section 8.7 Vector Relational Functions template GLM_FUNC_DECL GLM_CONSTEXPR vec not_(vec const& v); /// @} }//namespace glm #include "detail/func_vector_relational.inl" connectome-workbench-1.4.2/src/Gifti/000077500000000000000000000000001360521144700174645ustar00rootroot00000000000000connectome-workbench-1.4.2/src/Gifti/CMakeLists.txt000066400000000000000000000016571360521144700222350ustar00rootroot00000000000000 # # Name of Project # PROJECT (Gifti) # # Add QT for includes # if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) endif() IF (QT4_FOUND) SET(QT_DONT_USE_QTGUI) INCLUDE(${QT_USE_FILE}) ENDIF () # # Create GIFTI Library # ADD_LIBRARY(Gifti GiftiArrayIndexingOrderEnum.h GiftiDataArray.h GiftiEncodingEnum.h GiftiEndianEnum.h GiftiFile.h GiftiFileSaxReader.h GiftiFileWriter.h GiftiLabelTableSaxReader.h GiftiMetaDataSaxReader.h GiftiArrayIndexingOrderEnum.cxx GiftiDataArray.cxx GiftiEncodingEnum.cxx GiftiEndianEnum.cxx GiftiFile.cxx GiftiFileSaxReader.cxx GiftiFileWriter.cxx GiftiLabelTableSaxReader.cxx GiftiMetaDataSaxReader.cxx ) TARGET_LINK_LIBRARIES(Gifti ${CARET_QT5_LINK}) # # Find Headers # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Annotations ${CMAKE_SOURCE_DIR}/Palette ${CMAKE_SOURCE_DIR}/FilesBase ${CMAKE_SOURCE_DIR}/Gifti ${CMAKE_SOURCE_DIR}/Nifti ${CMAKE_SOURCE_DIR}/Xml ${CMAKE_SOURCE_DIR}/Common ) connectome-workbench-1.4.2/src/Gifti/GiftiArrayIndexingOrderEnum.cxx000066400000000000000000000117031360521144700255620ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GIFTIARRAYINDEXINGORDER_DECLARE__ #include "GiftiArrayIndexingOrderEnum.h" #undef __GIFTIARRAYINDEXINGORDER_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * Constructor. * * @param e * An enumerated value. * @param name * Name of enumberated value. */ GiftiArrayIndexingOrderEnum::GiftiArrayIndexingOrderEnum( const Enum e, const AString& name, const AString& giftiName) { this->e = e; this->name = name; this->giftiName = giftiName; } /** * Destructor. */ GiftiArrayIndexingOrderEnum::~GiftiArrayIndexingOrderEnum() { } void GiftiArrayIndexingOrderEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(GiftiArrayIndexingOrderEnum(COLUMN_MAJOR_ORDER, "COLUMN_MAJOR_ORDER", "ColumnMajorOrder")); enumData.push_back(GiftiArrayIndexingOrderEnum(ROW_MAJOR_ORDER, "ROW_MAJOR_ORDER", "RowMajorOrder")); } /** * Find the data for and enumerated value. * @param e * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const GiftiArrayIndexingOrderEnum* GiftiArrayIndexingOrderEnum::findData(const Enum e) { initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const GiftiArrayIndexingOrderEnum* d = &enumData[i]; if (d->e == e) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString GiftiArrayIndexingOrderEnum::toName(Enum e) { initialize(); const GiftiArrayIndexingOrderEnum* gaio = findData(e); return gaio->name; } /** * Get an enumerated value corresponding to its name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ GiftiArrayIndexingOrderEnum::Enum GiftiArrayIndexingOrderEnum::fromName(const AString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = ROW_MAJOR_ORDER; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const GiftiArrayIndexingOrderEnum& d = *iter; if (d.name == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("name \"" + s + " \"failed to match enumerated value for type GiftiArrayIndexingOrderEnum")); } return e; } /** * Get a string representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString GiftiArrayIndexingOrderEnum::toGiftiName(Enum e) { initialize(); const GiftiArrayIndexingOrderEnum* gaio = findData(e); return gaio->giftiName; } /** * Get an enumerated value corresponding to its name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ GiftiArrayIndexingOrderEnum::Enum GiftiArrayIndexingOrderEnum::fromGiftiName(const AString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = ROW_MAJOR_ORDER; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const GiftiArrayIndexingOrderEnum& d = *iter; if (d.giftiName == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("giftiName \"" + s + " \"failed to match enumerated value for type GiftiArrayIndexingOrderEnum")); } return e; } connectome-workbench-1.4.2/src/Gifti/GiftiArrayIndexingOrderEnum.h000066400000000000000000000044601360521144700252110ustar00rootroot00000000000000#ifndef __GIFTIARRAYINDEXINGORDER_H__ #define __GIFTIARRAYINDEXINGORDER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "GiftiException.h" #include #include #include namespace caret { /** * Type for GIFTI Data Array ArrayIndexingOrder Attribute. */ class GiftiArrayIndexingOrderEnum { public: /** Type for GIFTI Data Array ArrayIndexingOrder Attribute. */ enum Enum { /** Column-Major Order (Fortran/Matlab) */ COLUMN_MAJOR_ORDER, /** Row-Major Order (C/C++/Java) */ ROW_MAJOR_ORDER }; ~GiftiArrayIndexingOrderEnum(); static AString toName(Enum e); static Enum fromName(const AString& s, bool* isValidOut); static AString toGiftiName(Enum e); static Enum fromGiftiName(const AString& s, bool* isValidOut); private: GiftiArrayIndexingOrderEnum(const Enum e, const AString& name, const AString& giftiName); static const GiftiArrayIndexingOrderEnum* findData(const Enum e); static std::vector enumData; static void initialize(); static bool initializedFlag; Enum e; AString name; AString giftiName; }; #ifdef __GIFTIARRAYINDEXINGORDER_DECLARE__ std::vector GiftiArrayIndexingOrderEnum::enumData; bool GiftiArrayIndexingOrderEnum::initializedFlag = false; #endif // __GIFTIARRAYINDEXINGORDER_DECLARE__ } // namespace #endif // __GIFTIARRAYINDEXINGORDER_H__ connectome-workbench-1.4.2/src/Gifti/GiftiDataArray.cxx000066400000000000000000001765721360521144700230650ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include "Base64.h" #include "ByteOrderEnum.h" #include "ByteSwapping.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "DataCompressZLib.h" //#include "FileUtilities.h" #include "FastStatistics.h" #include "GiftiDataArray.h" #include "GiftiFile.h" #include "GiftiMetaDataXmlElements.h" #include "GiftiXmlElements.h" #include "Histogram.h" #include "NiftiEnums.h" #include "PaletteColorMapping.h" #include "SystemUtilities.h" #include "XmlWriter.h" using namespace caret; /** * constructor. */ GiftiDataArray::GiftiDataArray(const NiftiIntentEnum::Enum intentIn, const NiftiDataTypeEnum::Enum dataTypeIn, const std::vector& dimensionsIn, const GiftiEncodingEnum::Enum encodingIn) { intent = intentIn; dataTypeSize = 0; dataPointerFloat = NULL; dataPointerInt = NULL; dataPointerUByte = NULL; this->paletteColorMapping = NULL; this->descriptiveStatistics = NULL; this->descriptiveStatisticsLimitedValues = NULL; clear(); dataType = dataTypeIn; setDimensions(dimensionsIn); encoding = encodingIn; endian = getSystemEndian(); arraySubscriptingOrder = GiftiArrayIndexingOrderEnum::ROW_MAJOR_ORDER; externalFileName = ""; externalFileOffset = 0; if (intent == NiftiIntentEnum::NIFTI_INTENT_POINTSET) { Matrix4x4 gm; matrices.push_back(gm); } } /** * constructor. */ GiftiDataArray::GiftiDataArray(const NiftiIntentEnum::Enum intentIn) { intent = intentIn; dataTypeSize = 0; dataPointerFloat = NULL; dataPointerInt = NULL; dataPointerUByte = NULL; this->paletteColorMapping = NULL; this->descriptiveStatistics = NULL; this->descriptiveStatisticsLimitedValues = NULL; clear(); dimensions.clear(); encoding = GiftiEncodingEnum::ASCII; endian = getSystemEndian(); arraySubscriptingOrder = GiftiArrayIndexingOrderEnum::ROW_MAJOR_ORDER; externalFileName = ""; externalFileOffset = 0; /*if (intent == NiftiIntentEnum::NIFTI_INTENT_POINTSET) { Matrix4x4 gm; matrices.push_back(gm); }//*///TSC: do not add a fake matrix with no data or transformed space BEFORE knowing if one already exists, instead add one in validate, after reading, if none exists dataType = NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32; getDataTypeAppropriateForIntent(intent, dataType); } /** * destructor. */ GiftiDataArray::~GiftiDataArray() { clear(); } /** * copy constructor. */ GiftiDataArray::GiftiDataArray(const GiftiDataArray& nda) : CaretObject(), TracksModificationInterface() { dataTypeSize = 0; dataPointerFloat = NULL; dataPointerInt = NULL; dataPointerUByte = NULL; this->paletteColorMapping = NULL; this->descriptiveStatistics = NULL; this->descriptiveStatisticsLimitedValues = NULL; copyHelperGiftiDataArray(nda); } /** * assignment operator. */ GiftiDataArray& GiftiDataArray::operator=(const GiftiDataArray& nda) { if (this != &nda) { copyHelperGiftiDataArray(nda); } return *this; } /** * the copy helper (used by copy constructor and assignment operator). */ void GiftiDataArray::copyHelperGiftiDataArray(const GiftiDataArray& nda) { this->paletteColorMapping = NULL; if (nda.paletteColorMapping != NULL) { this->paletteColorMapping = new PaletteColorMapping(*nda.paletteColorMapping); } if (this->descriptiveStatistics != NULL) { delete this->descriptiveStatistics; this->descriptiveStatistics = NULL; } if (this->descriptiveStatisticsLimitedValues != NULL) { delete this->descriptiveStatisticsLimitedValues; this->descriptiveStatisticsLimitedValues = NULL; } intent = nda.intent; encoding = nda.encoding; arraySubscriptingOrder = nda.arraySubscriptingOrder; dataType = nda.dataType; //dataLocation = nda.dataLocation; dataTypeSize = nda.dataTypeSize; endian = nda.endian; dimensions = nda.dimensions; allocateData(); data = nda.data; metaData = nda.metaData; nonWrittenMetaData = nda.nonWrittenMetaData; externalFileName = nda.externalFileName; externalFileOffset = nda.externalFileOffset; minMaxFloatValuesValid = nda.minMaxFloatValuesValid; minValueFloat = nda.minValueFloat; maxValueFloat = nda.maxValueFloat; minMaxFloatValuesValid = nda.minMaxFloatValuesValid; minValueInt = nda.minValueInt; maxValueInt = nda.maxValueInt; minMaxIntValuesValid = nda.minMaxIntValuesValid; minMaxPercentageValuesValid = nda.minMaxPercentageValuesValid; negMaxPct = nda.negMaxPct; negMinPct = nda.negMinPct; posMinPct = nda.posMinPct; posMaxPct = nda.posMaxPct; negMaxPctValue = nda.negMaxPctValue; negMinPctValue = nda.negMinPctValue; posMinPctValue = nda.posMinPctValue; posMaxPctValue = nda.posMaxPctValue; matrices = nda.matrices; setModified(); } /** * get the data type appropriate for the intent (returns true if intent is valid). */ bool GiftiDataArray::getDataTypeAppropriateForIntent(const NiftiIntentEnum::Enum intent, NiftiDataTypeEnum::Enum& dataTypeOut) { // // Default to float // dataTypeOut = NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32; if (intent == NiftiIntentEnum::NIFTI_INTENT_POINTSET) { dataTypeOut = NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32; } else if (intent == NiftiIntentEnum::NIFTI_INTENT_TIME_SERIES) { dataTypeOut = NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32; } else if (intent == NiftiIntentEnum::NIFTI_INTENT_NORMAL) { dataTypeOut = NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32; } else if (intent == NiftiIntentEnum::NIFTI_INTENT_LABEL) { dataTypeOut = NiftiDataTypeEnum::NIFTI_TYPE_INT32; } else if ((intent == NiftiIntentEnum::NIFTI_INTENT_RGB_VECTOR) || (intent == NiftiIntentEnum::NIFTI_INTENT_RGBA_VECTOR)) { dataTypeOut = NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32; } else if (intent == NiftiIntentEnum::NIFTI_INTENT_SHAPE) { dataTypeOut = NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32; } else if (intent == NiftiIntentEnum::NIFTI_INTENT_SYMMATRIX) { dataTypeOut = NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32; } else if (intent == NiftiIntentEnum::NIFTI_INTENT_TRIANGLE) { dataTypeOut = NiftiDataTypeEnum::NIFTI_TYPE_INT32; } // else { // CaretLogFine("Unrecogized NIFTI intent \"" // + NiftiIntentEnum::toName(intent) // + "\" in GiftiDataArray::getDataTypeAppropriateForIntent()."); // return false; // } return true; } /** * add nodes. */ void GiftiDataArray::addRows(const int32_t numRowsToAdd) { dimensions[0] += numRowsToAdd; allocateData(); } /** * delete rows. */ void GiftiDataArray::deleteRows(const std::vector& rowsToDeleteIn) { if (rowsToDeleteIn.empty()) { return; } // // Sort rows in reverse order // std::vector rowsToDelete = rowsToDeleteIn; std::sort(rowsToDelete.begin(), rowsToDelete.end()); std::unique(rowsToDelete.begin(), rowsToDelete.end()); std::reverse(rowsToDelete.begin(), rowsToDelete.end()); // // size of row in bytes // int64_t numBytesInRow = 1; for (uint32_t i = 1; i < dimensions.size(); i++) { numBytesInRow = dimensions[i]; } numBytesInRow *= dataTypeSize; // // Remove the unneeded rows // for (uint32_t i = 0; i < rowsToDelete.size(); i++) { const int32_t offset = rowsToDelete[i] * numBytesInRow; data.erase(data.begin() + offset, data.begin() + offset + numBytesInRow); } // // Update the dimensions // dimensions[0] -= rowsToDelete.size(); setModified(); } /** * set number of nodes which causes reallocation of data. */ void GiftiDataArray::setDimensions(const std::vector dimensionsIn) { dimensions = dimensionsIn; if (dimensions.size() == 1) { dimensions.push_back(1); } else if (dimensions.empty()) { dimensions.push_back(0); dimensions.push_back(0); } allocateData(); } /** * allocate data for this array. */ void GiftiDataArray::allocateData() { // // Determine the number of items to allocate // int64_t dataSizeInBytes = 1; for (uint32_t i = 0; i < dimensions.size(); i++) { dataSizeInBytes *= dimensions[i]; } // // Bytes required by each data type // dataTypeSize = 0; switch (dataType) { case NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32: dataTypeSize = sizeof(float); break; case NiftiDataTypeEnum::NIFTI_TYPE_INT32: dataTypeSize = sizeof(int32_t); break; case NiftiDataTypeEnum::NIFTI_TYPE_UINT8: dataTypeSize = sizeof(uint8_t); break; default: CaretAssertMessage(0, "Unsupported GIFTI data type."); break; } dataSizeInBytes *= dataTypeSize; // // Does data need to be allocated // if (dataSizeInBytes > 0) { // // Allocate the needed memory // data.resize(dataSizeInBytes); } else { data.clear(); } // // Update the data pointers // updateDataPointers(); setModified(); } /** * update the data pointers. */ void GiftiDataArray::updateDataPointers() { dataPointerFloat = NULL; dataPointerInt = NULL; dataPointerUByte = NULL; if (data.empty() == false) { switch (dataType) { case NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32: dataPointerFloat = (float*)&data[0]; break; case NiftiDataTypeEnum::NIFTI_TYPE_INT32: dataPointerInt = (int32_t*)&data[0]; break; case NiftiDataTypeEnum::NIFTI_TYPE_UINT8: dataPointerUByte = (uint8_t*)&data[0]; break; default: CaretAssertMessage(0, "Unsupported GIFTI Data Type"); break; } } } /** * reset column. */ void GiftiDataArray::clear() { arraySubscriptingOrder = GiftiArrayIndexingOrderEnum::ROW_MAJOR_ORDER; encoding = GiftiEncodingEnum::ASCII; dataType = NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32; endian = getSystemEndian(); dataTypeSize = sizeof(float); metaData.clear(); nonWrittenMetaData.clear(); dimensions.clear(); setDimensions(dimensions); externalFileName = ""; externalFileOffset = 0; minMaxFloatValuesValid = false; minMaxPercentageValuesValid = false; if (this->paletteColorMapping != NULL) { delete this->paletteColorMapping; this->paletteColorMapping = NULL; } if (this->descriptiveStatistics != NULL) { delete this->descriptiveStatistics; this->descriptiveStatistics = NULL; } if (this->descriptiveStatisticsLimitedValues != NULL) { delete this->descriptiveStatisticsLimitedValues; this->descriptiveStatisticsLimitedValues = NULL; } // do not clear // parentGiftiDataFile; // arrayType; // setDimensions will call allocateData() which will set // dataPointer // dataPointerFloat // dataPointerInt // dataPointerUByte; } /** * get the number of nodes (1st dimension). */ int64_t GiftiDataArray::getNumberOfRows() const { if (dimensions.empty() == false) { return dimensions[0]; } return 0; } /** * get the total number of elements. */ int64_t GiftiDataArray::getTotalNumberOfElements() const { if (dimensions.empty()) { return 0; } int64_t num = 1; for (uint32_t i = 0; i < dimensions.size(); i++) { num *= dimensions[i]; } return num; } /** * get number of components per node (2nd dimension). */ int64_t GiftiDataArray::getNumberOfComponents() const { if (dimensions.size() > 1) { return dimensions[1]; } else if (dimensions.size() == 1) { return 1; } return 0; } /** * get data offset. */ /*int64_t GiftiDataArray::getDataOffset(const int64_t nodeNum, const int64_t componentNum) const { const int64_t off = nodeNum * dimensions[1] + componentNum;//TSC: this is WRONG! (assumes 2 dimensions, assumes a particular index order) fix it before uncommenting return off; }//*/ /** * get the system's endian. */ GiftiEndianEnum::Enum GiftiDataArray::getSystemEndian() { GiftiEndianEnum::Enum endian = GiftiEndianEnum::ENDIAN_BIG; if (ByteOrderEnum::isSystemLittleEndian()) { endian = GiftiEndianEnum::ENDIAN_LITTLE; } //if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { // return ENDIAN_BIG; //} return endian; } /** * get external file information. */ void GiftiDataArray::getExternalFileInformation(AString& nameOut, int64_t & offsetOut) const { nameOut = externalFileName; offsetOut = externalFileOffset; } /** * set external file information. */ void GiftiDataArray::setExternalFileInformation(const AString& nameIn, const int64_t offsetIn) { externalFileName = nameIn; externalFileOffset = offsetIn; } /** * remap integer values that are indices to a table. * void GiftiDataArray::remapIntValues(const std::vector& remappingTable) { if (remappingTable.isEmpty()) { return; } if (dataType != NiftiDataType::NIFTI_TYPE_INT32) { return; } const int64_t num = getTotalNumberOfElements(); for (int64_t i = 0; i < num; i++) { dataPointerInt[i] = remappingTable[dataPointerInt[i]]; } } */ /** * Update label indices using the index converter array. Typically, * this is done when appending one label file to another. * * @param indexConverter Converts the label indices to new values. */ void GiftiDataArray::transferLabelIndices(const std::map& indexConverter) { if (this->getDataType() == NiftiDataTypeEnum::NIFTI_TYPE_INT32) { int64_t num = this->getTotalNumberOfElements(); for (int i = 0; i < num; i++) { int oldIndex = this->dataPointerInt[i]; std::map::const_iterator iter = indexConverter.find(oldIndex); if (iter != indexConverter.end()) { this->dataPointerInt[i] = iter->second; //indexConverter.get(newIndex); } else { this->dataPointerInt[i] = 0; } this->setModified(); } } } /** * read a GIFTI data array from text. * Data array should already be initialized and allocated. */ void GiftiDataArray::readFromText(const AString text, const GiftiEndianEnum::Enum dataEndianForReading, const GiftiArrayIndexingOrderEnum::Enum arraySubscriptingOrderForReading, const NiftiDataTypeEnum::Enum dataTypeForReading, const std::vector& dimensionsForReading, const GiftiEncodingEnum::Enum encodingForReading, const AString& externalFileNameForReading, const int64_t externalFileOffsetForReading, const bool isReadOnlyMetaData) { const NiftiDataTypeEnum::Enum requiredDataType = dataType; dataType = dataTypeForReading; encoding = encodingForReading; endian = dataEndianForReading; arraySubscriptingOrder = arraySubscriptingOrderForReading; setDimensions(dimensionsForReading); if (dimensionsForReading.size() == 0) { throw GiftiException("Data array has no dimensions."); } //setExternalFileInformation(externalFileNameForReading, // externalFileOffsetForReading);//TSC: don't set the external filename on the array, because that is what it uses when writing the array // // If NOT metadata only // if (isReadOnlyMetaData == false) { // // Total number of elements in Data Array // const int64_t numElements = getTotalNumberOfElements(); switch (encoding) { case GiftiEncodingEnum::ASCII: { std::istringstream stream(text.toStdString()); switch (dataType) { case NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32: { float* ptr = dataPointerFloat; for (int64_t i = 0; i < numElements; i++) { stream >> *ptr; ptr++; } } break; case NiftiDataTypeEnum::NIFTI_TYPE_INT32: { int32_t* ptr = dataPointerInt; for (int64_t i = 0; i < numElements; i++) { stream >> *ptr; ptr++; } } break; case NiftiDataTypeEnum::NIFTI_TYPE_UINT8: { uint8_t* ptr = dataPointerUByte; int32_t c; for (int64_t i = 0; i < numElements; i++) { stream >> c; *ptr = static_cast(c); ptr++; } } break; default: throw GiftiException("DataType " + NiftiDataTypeEnum::toName(dataType) + " not supported in GIFTI"); } } break; case GiftiEncodingEnum::BASE64_BINARY: { // // Decode the Base64 data using VTK's algorithm // const uint64_t numDecoded = Base64::decode((const unsigned char*)(text.toStdString().c_str()), data.size(), &data[0]); if (numDecoded != data.size()) { std::ostringstream str; str << "Decoding of Base64 Binary data failed.\n" << "Decoded " << AString::number(numDecoded).toStdString() << " bytes but should be " << AString::number(static_cast(data.size())).toStdString() << " bytes."; throw GiftiException(AString::fromStdString(str.str())); } // // Is byte swapping needed ? // if (endian != getSystemEndian()) { byteSwapData(getSystemEndian()); } } break; case GiftiEncodingEnum::GZIP_BASE64_BINARY: { // // Decode the Base64 data using VTK's algorithm // unsigned char* dataBuffer = new unsigned char[data.size()]; //const char* textChars = text.toLatin1().constData(); const uint64_t numDecoded = Base64::decode((unsigned char*)text.toStdString().c_str(), data.size(), dataBuffer); if (numDecoded == 0) { std::ostringstream str; str << "Decoding of GZip Base64 Binary data failed." << "Decoded " << AString::number(numDecoded).toStdString() << " bytes but should be " << AString::number(static_cast(data.size())).toStdString() << " bytes."; throw GiftiException(AString::fromStdString(str.str())); } // // Uncompress the data using VTK's algorithm // DataCompressZLib compressor; const uint64_t uncompressedDataLength = compressor.uncompressData(dataBuffer, numDecoded, (unsigned char*)&data[0], data.size()); if (uncompressedDataLength != data.size()) { std::ostringstream str; str << "Decompression of Binary data failed.\n" << "Uncompressed " << AString::number(uncompressedDataLength).toStdString() << " bytes but should be " << AString::number(static_cast(data.size())).toStdString() << " bytes."; throw GiftiException(AString::fromStdString(str.str())); } // // Free memory // delete[] dataBuffer; // // Is byte swapping needed ? // if (endian != getSystemEndian()) { byteSwapData(getSystemEndian()); } } break; case GiftiEncodingEnum::EXTERNAL_FILE_BINARY: { if (externalFileNameForReading.length() <= 0) { throw GiftiException("External file name is empty."); } std::ifstream extBinFile(externalFileNameForReading.toStdString().c_str(), std::ifstream::in | std::ifstream::binary); if (extBinFile.good() == false) { throw GiftiException("Error opening \"" + externalFileNameForReading + "\""); } else { // // Move to the offset of the data // extBinFile.seekg(externalFileOffsetForReading, std::ios::beg); if (extBinFile.good() == false) { throw GiftiException("Error seeking to \"" + AString::number(externalFileOffsetForReading) + "\" in \"" + externalFileNameForReading + "\""); } // // Set the number of bytes that must be read // std::streamsize numberOfBytesToRead = 0; char* pointerToForReadingData = NULL; switch (dataType) { case NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32: numberOfBytesToRead = numElements * sizeof(float); pointerToForReadingData = (char*)dataPointerFloat; break; case NiftiDataTypeEnum::NIFTI_TYPE_INT32: numberOfBytesToRead = numElements * sizeof(int32_t); pointerToForReadingData = (char*)dataPointerInt; break; case NiftiDataTypeEnum::NIFTI_TYPE_UINT8: numberOfBytesToRead = numElements * sizeof(uint8_t); pointerToForReadingData = (char*)dataPointerUByte; break; default: throw GiftiException("DataType " + NiftiDataTypeEnum::toName(dataType) + " not supported in GIFTI"); } // // Read the data // extBinFile.read((char*)pointerToForReadingData, numberOfBytesToRead); if(extBinFile.good() == false) { throw GiftiException("Tried to read " + AString::number((int64_t)numberOfBytesToRead) + " from " + externalFileOffsetForReading + " but failed"); } // // Is byte swapping needed ? // if (endian != getSystemEndian()) { byteSwapData(getSystemEndian()); } } } break; } // // Check if data type needs to be converted // if (requiredDataType != dataType) { if (intent != NiftiIntentEnum::NIFTI_INTENT_POINTSET) { convertToDataType(requiredDataType); } } // // Are array indices in opposite order // if (arraySubscriptingOrderForReading == GiftiArrayIndexingOrderEnum::COLUMN_MAJOR_ORDER) { convertArrayIndexingOrder(); } } // If NOT metadata only setModified(); } /** * convert array indexing order of data. */ void GiftiDataArray::convertArrayIndexingOrder() { const int32_t numDim = static_cast(dimensions.size()); if (numDim > 2) { throw GiftiException("Row/Column Major order conversion unavailable for arrays " "with dimensions greater than two."); } // // Swap data // if (numDim == 2) { int32_t dimI = dimensions[0]; int32_t dimJ = dimensions[1]; /* * If a dimensions is "1", the data does not need to be transposed. */ if ((dimI != 1) && (dimJ != 1)) { // // Is matrix square? // if (dimI == dimJ) { switch (dataType) { case NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32: { for (int64_t i = 1; i < dimI; i++) { for (int64_t j = 0; j < i; j++) { const int64_t indexLowerLeft = (i * dimJ) + j; const int64_t indexUpperRight = (j * dimI) + i; float temp = dataPointerFloat[indexLowerLeft]; dataPointerFloat[indexLowerLeft] = dataPointerFloat[indexUpperRight]; dataPointerFloat[indexUpperRight] = temp; } } } break; case NiftiDataTypeEnum::NIFTI_TYPE_INT32: { for (int64_t i = 1; i < dimI; i++) { for (int64_t j = 0; j < i; j++) { const int64_t indexLowerLeft = (i * dimJ) + j; const int64_t indexUpperRight = (j * dimI) + i; const int32_t temp = dataPointerInt[indexLowerLeft]; dataPointerInt[indexLowerLeft] = dataPointerInt[indexUpperRight]; dataPointerInt[indexUpperRight] = temp; } } } break; case NiftiDataTypeEnum::NIFTI_TYPE_UINT8: { for (int64_t i = 1; i < dimI; i++) { for (int64_t j = 0; j < i; j++) { const int64_t indexLowerLeft = (i * dimJ) + j; const int64_t indexUpperRight = (j * dimI) + i; const uint8_t temp = dataPointerUByte[indexLowerLeft]; dataPointerUByte[indexLowerLeft] = dataPointerUByte[indexUpperRight]; dataPointerUByte[indexUpperRight] = temp; } } } break; default: throw GiftiException("DataType " + NiftiDataTypeEnum::toName(dataType) + " not supported in GIFTI"); break; } } else { // // Copy the data // std::vector dataCopy = data; switch (arraySubscriptingOrder) { case GiftiArrayIndexingOrderEnum::ROW_MAJOR_ORDER: switch (dataType) { case NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32: { float* ptr = (float*)&(dataCopy[0]); for (int64_t i = 0; i < dimI; i++) { for (int64_t j = 0; j < dimJ; j++) { const int64_t indx = (j * dimI) + i; const int64_t ptrIndex = (i * dimJ) + j; dataPointerFloat[indx] = ptr[ptrIndex]; } } } break; case NiftiDataTypeEnum::NIFTI_TYPE_INT32: { uint32_t* ptr = (uint32_t*)&(dataCopy[0]); for (int64_t i = 0; i < dimI; i++) { for (int64_t j = 0; j < dimJ; j++) { const int64_t indx = (j * dimI) + i; const int64_t ptrIndex = (i * dimJ) + j; dataPointerInt[indx] = ptr[ptrIndex]; } } } break; case NiftiDataTypeEnum::NIFTI_TYPE_UINT8: { uint8_t* ptr = (uint8_t*)&(dataCopy[0]); for (int64_t i = 0; i < dimI; i++) { for (int64_t j = 0; j < dimJ; j++) { const int64_t indx = (j * dimI) + i; const int64_t ptrIndex = (i * dimJ) + j; dataPointerUByte[indx] = ptr[ptrIndex]; } } } break; default: throw GiftiException("DataType " + NiftiDataTypeEnum::toName(dataType) + " not supported in GIFTI"); break; } break; case GiftiArrayIndexingOrderEnum::COLUMN_MAJOR_ORDER: switch (dataType) { case NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32: { float* ptr = (float*)&(dataCopy[0]); for (int64_t i = 0; i < dimI; i++) { for (int64_t j = 0; j < dimJ; j++) { const int64_t indx = (i * dimJ) + j; const int64_t ptrIndex = (j * dimI) + i; dataPointerFloat[indx] = ptr[ptrIndex]; } } } break; case NiftiDataTypeEnum::NIFTI_TYPE_INT32: { uint32_t* ptr = (uint32_t*)&(dataCopy[0]); for (int64_t i = 0; i < dimI; i++) { for (int64_t j = 0; j < dimJ; j++) { const int64_t indx = (i * dimJ) + j; const int64_t ptrIndex = (j * dimI) + i; dataPointerInt[indx] = ptr[ptrIndex]; } } } break; case NiftiDataTypeEnum::NIFTI_TYPE_UINT8: { uint8_t* ptr = (uint8_t*)&(dataCopy[0]); for (int64_t i = 0; i < dimI; i++) { for (int64_t j = 0; j < dimJ; j++) { const int64_t indx = (i * dimJ) + j; const int64_t ptrIndex = (j * dimI) + i; dataPointerUByte[indx] = ptr[ptrIndex]; } } } break; default: throw GiftiException("DataType " + NiftiDataTypeEnum::toName(dataType) + " not supported in GIFTI"); break; } break; } } } } switch (arraySubscriptingOrder) { case GiftiArrayIndexingOrderEnum::COLUMN_MAJOR_ORDER: arraySubscriptingOrder = GiftiArrayIndexingOrderEnum::ROW_MAJOR_ORDER; break; case GiftiArrayIndexingOrderEnum::ROW_MAJOR_ORDER: arraySubscriptingOrder = GiftiArrayIndexingOrderEnum::COLUMN_MAJOR_ORDER; break; } } /** * write the data as XML. * @param stream * Stream for XML. * @param externalBinaryOutputStream * Stream for external binary file. * @param encodingForWriting * GIFTI encoding used when writing the data. */ void GiftiDataArray::writeAsXML(std::ostream& stream, std::ostream* externalBinaryOutputStream, GiftiEncodingEnum::Enum encodingForWriting) { this->encoding = encodingForWriting; // // Do not write if data array is isEmpty() // const int64_t numRows = this->dimensions[0]; if (numRows <= 0) { return; } XmlWriter xmlWriter(stream); // // Clean up the dimensions by removing any "last" dimensions that // are one with the exception of the first dimension // e.g.: dimension = [73730, 1] becomes [73730] // int64_t dimensionality = static_cast(dimensions.size()); for (int64_t i = (dimensionality - 1); i >= 1; i--) { if (dimensions[i] <= 1) { dimensions.resize(i); } } dimensionality = static_cast(dimensions.size()); /* * Push the palette color mapping into the metadata. */ if (this->paletteColorMapping != NULL) { const AString paletteXML = this->paletteColorMapping->encodeInXML(); this->getMetaData()->set(GiftiMetaDataXmlElements::METADATA_NAME_PALETTE_COLOR_MAPPING, paletteXML); } // // External file not supported // //const AString externalFileName = ""; //const AString externalFileOffset = "0"; // // Write the opening tag // XmlAttributes dataAtt; dataAtt.addAttribute(GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_INTENT, NiftiIntentEnum::toName(this->intent)); dataAtt.addAttribute(GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_DATA_TYPE, NiftiDataTypeEnum::toName(this->dataType)); dataAtt.addAttribute(GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_INDEXING_ORDER, GiftiArrayIndexingOrderEnum::toGiftiName(this->arraySubscriptingOrder)); dataAtt.addAttribute(GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_DIMENSIONALITY, dimensionality); for (int64_t i = 0; i < dimensionality; i++) { const AString dimName = GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_DIM_PREFIX + AString::number(i); dataAtt.addAttribute(dimName, this->dimensions[i]); } dataAtt.addAttribute(GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_ENCODING, GiftiEncodingEnum::toGiftiName(this->encoding)); dataAtt.addAttribute(GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_ENDIAN, GiftiEndianEnum::toGiftiName(this->endian)); dataAtt.addAttribute(GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_EXTERNAL_FILE_NAME, externalFileName); dataAtt.addAttribute(GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_EXTERNAL_FILE_OFFSET, externalFileOffset); xmlWriter.writeStartElement(GiftiXmlElements::TAG_DATA_ARRAY, dataAtt); // // Write the metadata // this->metaData.writeAsXML(xmlWriter); /* * Write one identity matrix for the transformation matrix. * * We do not want to write the transformation matrices that * were read from the file as the first matrix was applied to * the coordinates when the file was read. To do so would require * applying an inverse of the matrix. However, the user may have * modified the coordinates so the matrix is no longer valid for * the file's coordinates. */ if (getIntent() == NiftiIntentEnum::NIFTI_INTENT_POINTSET) { Matrix4x4 identityMatrix; identityMatrix.identity(); identityMatrix.setDataSpaceName(NiftiTransformEnum::toName(NiftiTransformEnum::NIFTI_XFORM_TALAIRACH)); identityMatrix.setTransformedSpaceName(NiftiTransformEnum::toName(NiftiTransformEnum::NIFTI_XFORM_TALAIRACH)); identityMatrix.writeAsGiftiXML(xmlWriter, GiftiXmlElements::TAG_COORDINATE_TRANSFORMATION_MATRIX, GiftiXmlElements::TAG_MATRIX_DATA_SPACE, GiftiXmlElements::TAG_MATRIX_TRANSFORMED_SPACE, GiftiXmlElements::TAG_MATRIX_DATA); } // // NOTE: for the base64 and ZLIB-Base64 data, it is important that there are // no spaces between the and tags. // switch (encoding) { case GiftiEncodingEnum::ASCII: { // // Write the start element. // xmlWriter.writeStartElement(GiftiXmlElements::TAG_DATA); // // Newline after tag (only do this for ASCII !!!) // //stream << "\n"; // // determine the number of items per row (node) // int64_t numItemsPerRow = 1; for (uint32_t i = 1; i < dimensions.size(); i++) { numItemsPerRow *= dimensions[i]; } // // Write the rows // int32_t offset = 0; for (int32_t i = 0; i < numRows; i++) { xmlWriter.writeCharacters(" "); switch (dataType) { case NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32: for (int64_t j = 0; j < numItemsPerRow; j++) { xmlWriter.writeCharacters(AString::number(this->dataPointerFloat[offset + j])); xmlWriter.writeCharacters(" "); } break; case NiftiDataTypeEnum::NIFTI_TYPE_INT32: for (int64_t j = 0; j < numItemsPerRow; j++) { xmlWriter.writeCharacters(AString::number(this->dataPointerInt[offset + j])); xmlWriter.writeCharacters(" "); } break; case NiftiDataTypeEnum::NIFTI_TYPE_UINT8: for (int64_t j = 0; j < numItemsPerRow; j++) { xmlWriter.writeCharacters(AString::number(this->dataPointerUByte[offset + j])); xmlWriter.writeCharacters(" "); } break; default: throw GiftiException("DataType " + NiftiDataTypeEnum::toName(dataType) + " not supported in GIFTI"); break; } xmlWriter.writeCharacters("\n"); offset += numItemsPerRow; } // // Write the closing Data tag // xmlWriter.writeEndElement(); } break; case GiftiEncodingEnum::BASE64_BINARY: { // // Encode the data with VTK's Base64 algorithm // const uint64_t bufferLength = static_cast(data.size() * 1.5); char* buffer = new char[bufferLength]; const uint64_t compressedLength = Base64::encode(&data[0], data.size(), (unsigned char*)buffer); if (compressedLength >= bufferLength) { throw GiftiException( "Base64 encoding buffer length (" + AString::number(bufferLength) + ") is too small but needs to be " + AString::number(compressedLength)); } buffer[compressedLength] = '\0'; // // Write the data MUST BE NO space around data // xmlWriter.writeElementNoSpace(GiftiXmlElements::TAG_DATA, buffer); // // Free memory // delete[] buffer; } break; case GiftiEncodingEnum::GZIP_BASE64_BINARY: { // // Compress the data with VTK's ZLIB algorithm // DataCompressZLib compressor; unsigned long compressedDataBufferLength = compressor.getMaximumCompressionSpace(data.size()); unsigned char* compressedDataBuffer = new unsigned char[compressedDataBufferLength]; unsigned long compressedDataLength = compressor.compressData(&data[0], data.size(), compressedDataBuffer, compressedDataBufferLength); // // Encode the data with VTK's Base64 algorithm // char* buffer = new char[static_cast(compressedDataLength * 1.5)]; const uint64_t compressedLength = Base64::encode(compressedDataBuffer, compressedDataLength, (unsigned char*)buffer); buffer[compressedLength] = '\0'; // // Write the data MUST BE NO space around data // xmlWriter.writeElementNoSpace(GiftiXmlElements::TAG_DATA, buffer); // // Free memory // delete[] buffer; delete[] compressedDataBuffer; } break; case GiftiEncodingEnum::EXTERNAL_FILE_BINARY: { const int64_t dataLength = data.size(); externalBinaryOutputStream->write((const char*)&data[0], dataLength); if (externalBinaryOutputStream->bad()) { throw GiftiException("Output stream for external file reports its status as bad."); } // // Write the empty data // xmlWriter.writeElementNoSpace(GiftiXmlElements::TAG_DATA, ""); } break; } // // write the closing data array tag // xmlWriter.writeEndElement(); } /** * convert to data type. */ void GiftiDataArray::convertToDataType(const NiftiDataTypeEnum::Enum newDataType) { if (newDataType != dataType) { // // make a copy of myself // GiftiDataArray copyOfMe(*this); // // Set my new data type and reallocate memory // const NiftiDataTypeEnum::Enum oldDataType = dataType; dataType = newDataType; allocateData(); if (data.empty() == false) { // // Get total number of elements // int64_t numElements = 1; for (uint32_t i = 0; i < dimensions.size(); i++) { numElements *= dimensions[i]; } // // copy the data // for (int64_t i = 0; i < numElements; i++) { switch (dataType) { case NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32: switch (oldDataType) { case NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32: dataPointerFloat[i] = static_cast(copyOfMe.dataPointerFloat[i]); break; case NiftiDataTypeEnum::NIFTI_TYPE_INT32: dataPointerFloat[i] = static_cast(copyOfMe.dataPointerInt[i]); break; case NiftiDataTypeEnum::NIFTI_TYPE_UINT8: dataPointerFloat[i] = static_cast(copyOfMe.dataPointerUByte[i]); break; default: throw GiftiException("DataType " + NiftiDataTypeEnum::toName(oldDataType) + " not supported in GIFTI"); break; } break; case NiftiDataTypeEnum::NIFTI_TYPE_INT32: switch (oldDataType) { case NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32: dataPointerInt[i] = static_cast(copyOfMe.dataPointerFloat[i]); break; case NiftiDataTypeEnum::NIFTI_TYPE_INT32: dataPointerInt[i] = static_cast(copyOfMe.dataPointerInt[i]); break; case NiftiDataTypeEnum::NIFTI_TYPE_UINT8: dataPointerInt[i] = static_cast(copyOfMe.dataPointerUByte[i]); break; default: throw GiftiException("DataType " + NiftiDataTypeEnum::toName(oldDataType) + " not supported in GIFTI"); break; } break; case NiftiDataTypeEnum::NIFTI_TYPE_UINT8: switch (oldDataType) { case NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32: dataPointerUByte[i] = static_cast(copyOfMe.dataPointerFloat[i]); break; case NiftiDataTypeEnum::NIFTI_TYPE_INT32: dataPointerUByte[i] = static_cast(copyOfMe.dataPointerInt[i]); break; case NiftiDataTypeEnum::NIFTI_TYPE_UINT8: dataPointerUByte[i] = static_cast(copyOfMe.dataPointerUByte[i]); break; default: throw GiftiException("DataType " + NiftiDataTypeEnum::toName(oldDataType) + " not supported in GIFTI"); break; } break; default: throw GiftiException("DataType " + NiftiDataTypeEnum::toName(dataType) + " not supported in GIFTI"); break; } } } } setModified(); } /** * byte swap the data (data read is different endian than this system). */ void GiftiDataArray::byteSwapData(const GiftiEndianEnum::Enum newEndian) { endian = newEndian; switch (dataType) { case NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32: ByteSwapping::swapBytes(dataPointerFloat, getTotalNumberOfElements()); break; case NiftiDataTypeEnum::NIFTI_TYPE_INT32: ByteSwapping::swapBytes(dataPointerInt, getTotalNumberOfElements()); break; case NiftiDataTypeEnum::NIFTI_TYPE_UINT8: // should not need to swap ?? break; default: CaretAssertMessage(0, "Unsupported GIFTI data Type"); break; } } /** * Set this object has been modified. * */ void GiftiDataArray::setModified() { this->modifiedFlag = true; if (this->descriptiveStatistics != NULL) { delete this->descriptiveStatistics; this->descriptiveStatistics = NULL; } if (this->descriptiveStatisticsLimitedValues != NULL) { delete this->descriptiveStatisticsLimitedValues; this->descriptiveStatisticsLimitedValues = NULL; } } /** * Set this object as not modified. Object should also * clear the modification status of its children. * */ void GiftiDataArray::clearModified() { this->modifiedFlag = false; if (this->paletteColorMapping != NULL) { this->paletteColorMapping->clearModified(); } } /** * Get the modification status. Returns true if this object or * any of its children have been modified. * * DOES NOT include palette color mapping modification status. * * @return - The modification status. * */ bool GiftiDataArray::isModified() const { // if (this->paletteColorMapping != NULL) { // if (this->paletteColorMapping->isModified()) { // return true; // } // } return this->modifiedFlag; } /** * get minimum and maximum values (valid for int data only). */ void GiftiDataArray::getMinMaxValues(int& minValue, int& maxValue) const { if (minMaxIntValuesValid == false) { minValueInt = std::numeric_limits::max(); minValueInt = std::numeric_limits::min(); int64_t numItems = getTotalNumberOfElements(); for (int64_t i = 0; i < numItems; i++) { minValueInt = std::min(minValueInt, dataPointerInt[i]); maxValueInt = std::max(maxValueInt, dataPointerInt[i]); } minMaxIntValuesValid = true; } minValue = minValueInt; maxValue = maxValueInt; } /** * Get the minimum and maximum values for float data. * * @param minValue * Output minimum value. * @param maxValue * Output maximum value. */ void GiftiDataArray::getMinMaxValuesFloat(float& minValue, float& maxValue) const { if (minMaxFloatValuesValid == false) { minValueFloat = std::numeric_limits::max(); maxValueFloat = -std::numeric_limits::max(); int64_t numItems = getTotalNumberOfElements(); for (int64_t i = 0; i < numItems; i++) { minValueFloat = std::min(minValueFloat, dataPointerFloat[i]); maxValueFloat = std::max(maxValueFloat, dataPointerFloat[i]); } minMaxFloatValuesValid = true; } minValue = minValueFloat; maxValue = maxValueFloat; } /** * set all elements of array to zero. */ void GiftiDataArray::zeroize() { if (data.empty() == false) { std::fill(data.begin(), data.end(), 0); } metaData.clear(); nonWrittenMetaData.clear(); } /** * get an offset for indices into data (dimensionality of indices must be same as data). */ int64_t GiftiDataArray::getDataOffset(const int32_t indices[]) const { const int32_t numDim = static_cast(dimensions.size()); int64_t offset = 0; int64_t dimProduct = 1; switch (this->arraySubscriptingOrder) { case GiftiArrayIndexingOrderEnum::ROW_MAJOR_ORDER: for (int32_t d = (numDim - 1); d >= 0; d--) { offset += indices[d] * dimProduct; dimProduct *= dimensions[d]; } break; case GiftiArrayIndexingOrderEnum::COLUMN_MAJOR_ORDER: // correct??? for (int32_t d = 0; d <= (numDim - 1); d++) { offset += indices[d] * dimProduct; dimProduct *= dimensions[d]; } break; } return offset; } /** * get a float value (data type must be float and dimensionality of indices must be same as data). */ float GiftiDataArray::getDataFloat32(const int32_t indices[]) const { const int64_t offset = getDataOffset(indices); return dataPointerFloat[offset]; } /** * get a float value pointer(data type must be float and dimensionality of indices must be same as data). */ const float* GiftiDataArray::getDataFloat32Pointer(const int32_t indices[]) const { const int64_t offset = getDataOffset(indices); return &dataPointerFloat[offset]; } /** * get an int value (data type must be int and dimensionality of indices must be same as data). */ int32_t GiftiDataArray::getDataInt32(const int32_t indices[]) const { const int64_t offset = getDataOffset(indices); return dataPointerInt[offset]; } /** * get an int value pointer (data type must be int and dimensionality of indices must be same as data). */ const int32_t* GiftiDataArray::getDataInt32Pointer(const int32_t indices[]) const { const int64_t offset = getDataOffset(indices); return &dataPointerInt[offset]; } /** * get a byte value (data type must be unsigned char and dimensionality of indices must be same as data). */ uint8_t GiftiDataArray::getDataUInt8(const int32_t indices[]) const { const int64_t offset = getDataOffset(indices); return dataPointerUByte[offset]; } /** * get a byte value pointer(data type must be unsigned char and dimensionality of indices must be same as data). */ const uint8_t* GiftiDataArray::getDataUInt8Pointer(const int32_t indices[]) const { const int64_t offset = getDataOffset(indices); return &dataPointerUByte[offset]; } /** * set a float value (data type must be float and dimensionality of indices must be same as data). */ void GiftiDataArray::setDataFloat32(const int32_t indices[], const float dataValue) const { const int64_t offset = getDataOffset(indices); dataPointerFloat[offset] = dataValue; } /** * set an int value (data type must be int and dimensionality of indices must be same as data). */ void GiftiDataArray::setDataInt32(const int32_t indices[], const int32_t dataValue) const { const int64_t offset = getDataOffset(indices); dataPointerInt[offset] = dataValue; } /** * set a byte value (data type must be unsigned char and dimensionality of indices must be same as data). */ void GiftiDataArray::setDataUInt8(const int32_t indices[], const uint8_t dataValue) const { const int64_t offset = getDataOffset(indices); dataPointerUByte[offset] = dataValue; } /** * valid intent name. */ bool GiftiDataArray::intentNameValid(const AString& intentNameIn) { bool valid = false; NiftiIntentEnum::fromName(intentNameIn, &valid); return valid; } /** * remove all matrices. */ void GiftiDataArray::removeAllMatrices() { matrices.clear(); setModified(); } /** * remove a matrix. */ void GiftiDataArray::removeMatrix(const int32_t indx) { matrices.erase(matrices.begin() + indx); setModified(); } /** * Get the color palette mapping. * * @return * The palette color mapping. */; PaletteColorMapping* GiftiDataArray::getPaletteColorMapping() { if (this->paletteColorMapping == NULL) { this->paletteColorMapping = new PaletteColorMapping(); const AString paletteString = this->getMetaData()->get(GiftiMetaDataXmlElements::METADATA_NAME_PALETTE_COLOR_MAPPING); if (paletteString.isEmpty() == false) { try { this->paletteColorMapping->decodeFromStringXML(paletteString); } catch (const XmlException& e) { this->paletteColorMapping = new PaletteColorMapping(); CaretLogSevere("Failed to parse Palette XML: " + e.whatString()); } } this->paletteColorMapping->clearModified(); } return this->paletteColorMapping; } /** * Get the color palette mapping. * * @return * The palette color mapping. */; const PaletteColorMapping* GiftiDataArray::getPaletteColorMapping() const { if (this->paletteColorMapping == NULL) { this->paletteColorMapping = new PaletteColorMapping(); const AString paletteString = this->getMetaData()->get(GiftiMetaDataXmlElements::METADATA_NAME_PALETTE_COLOR_MAPPING); if (paletteString.isEmpty() == false) { try { this->paletteColorMapping->decodeFromStringXML(paletteString); } catch (const XmlException& e) { this->paletteColorMapping = new PaletteColorMapping(); CaretLogSevere("Failed to parse Palette XML: " + e.whatString()); } } this->paletteColorMapping->clearModified(); } return this->paletteColorMapping; } /** * Get the descriptive statistics for this data array. * * @return Descriptive statistics. */ const DescriptiveStatistics* GiftiDataArray::getDescriptiveStatistics() const { if (this->getDataType() == NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32) { if (this->descriptiveStatistics == NULL) { this->descriptiveStatistics = new DescriptiveStatistics(); } this->descriptiveStatistics->update(this->dataPointerFloat, this->getTotalNumberOfElements()); } return this->descriptiveStatistics; } const FastStatistics* GiftiDataArray::getFastStatistics() const { if (this->getDataType() == NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32) { if (m_fastStatistics == NULL) { m_fastStatistics.grabNew(new FastStatistics()); } m_fastStatistics->update(dataPointerFloat, getTotalNumberOfElements()); } return m_fastStatistics; } /** * Invalidate the histograms */ void GiftiDataArray::invalidateHistograms() { m_histogramNeedsUpdateFlag = true; m_histogramLimitedValuesNeedsUpdateFlag = true; } const Histogram* GiftiDataArray::getHistogram(const int32_t numberOfBuckets) const { if (this->getDataType() == NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32) { bool updateHistogramFlag = m_histogramNeedsUpdateFlag; m_histogramNeedsUpdateFlag = false; if (m_histogram == NULL) { m_histogram.grabNew(new Histogram(numberOfBuckets)); updateHistogramFlag = true; } else if (numberOfBuckets != m_histogramNumberOfBuckets) { updateHistogramFlag = true; } if (updateHistogramFlag) { m_histogram->update(numberOfBuckets, dataPointerFloat, getTotalNumberOfElements()); m_histogramNumberOfBuckets = numberOfBuckets; } } return m_histogram; } /** * Get the descriptive statistics for this data array limited * to values within the given ranges. * * @param mostPositiveValueInclusive * Values more positive than this value are excluded. * @param leastPositiveValueInclusive * Values less positive than this value are excluded. * @param leastNegativeValueInclusive * Values less negative than this value are excluded. * @param mostNegativeValueInclusive * Values more negative than this value are excluded. * @param includeZeroValues * If true zero values (very near zero) are included. * @return Descriptive statistics. */ const DescriptiveStatistics* GiftiDataArray::getDescriptiveStatistics(const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) const { if (this->getDataType() == NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32) { if (this->descriptiveStatisticsLimitedValues == NULL) { this->descriptiveStatisticsLimitedValues = new DescriptiveStatistics(); } this->descriptiveStatisticsLimitedValues->update(this->dataPointerFloat, this->getTotalNumberOfElements(), mostPositiveValueInclusive, leastPositiveValueInclusive, leastNegativeValueInclusive, mostNegativeValueInclusive, includeZeroValues); } return this->descriptiveStatisticsLimitedValues; } const Histogram* GiftiDataArray::getHistogram(const int32_t numberOfBuckets, const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) const { if (this->getDataType() == NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32) { bool updateHistogramFlag = m_histogramLimitedValuesNeedsUpdateFlag; m_histogramLimitedValuesNeedsUpdateFlag = false; if (m_histogramLimitedValues == NULL) { m_histogramLimitedValues.grabNew(new Histogram(numberOfBuckets)); updateHistogramFlag = true; } else if ((numberOfBuckets != m_histogramLimitedValuesNumberOfBuckets) || (mostPositiveValueInclusive != m_histogramLimitedValuesMostPositiveValueInclusive) || (leastPositiveValueInclusive != m_histogramLimitedValuesLeastPositiveValueInclusive) || (leastNegativeValueInclusive != m_histogramLimitedValuesLeastNegativeValueInclusive) || (mostNegativeValueInclusive != m_histogramLimitedValuesMostNegativeValueInclusive) || (includeZeroValues != m_histogramLimitedValuesIncludeZeroValues)) { updateHistogramFlag = true; } if (updateHistogramFlag) { m_histogramLimitedValues->update(numberOfBuckets, dataPointerFloat, getTotalNumberOfElements(), mostPositiveValueInclusive, leastPositiveValueInclusive, leastNegativeValueInclusive, mostNegativeValueInclusive, includeZeroValues); m_histogramLimitedValuesNumberOfBuckets = numberOfBuckets; m_histogramLimitedValuesMostPositiveValueInclusive = mostPositiveValueInclusive; m_histogramLimitedValuesLeastPositiveValueInclusive = leastPositiveValueInclusive; m_histogramLimitedValuesLeastNegativeValueInclusive = leastNegativeValueInclusive; m_histogramLimitedValuesMostNegativeValueInclusive = mostNegativeValueInclusive; m_histogramLimitedValuesIncludeZeroValues = includeZeroValues; } } return m_histogramLimitedValues; } AString GiftiDataArray::toString() const { std::ostringstream str; str << "Data Array" << std::endl; str << " DataType=" << NiftiDataTypeEnum::toName(this->dataType).toStdString() << std::endl; str << " Intent=" << NiftiIntentEnum::toName(this->intent).toStdString() << std::endl; str << " Dimensions=" << AString::fromNumbers(this->dimensions, ",").toStdString(); str << " MetaData=" << this->metaData.toString().toStdString() << std::endl; return AString::fromStdString(str.str()); } void GiftiDataArray::validateArrayAfterReading() { //pointset arrays are mandated to have at least one tranfsormation matrix, for some unknown reason if (intent == NiftiIntentEnum::NIFTI_INTENT_POINTSET && matrices.size() == 0) { CaretLogWarning("pointset gifti array did not include a transformation matrix, adding identity transform"); Matrix4x4 gm; gm.setDataSpaceName("NIFTI_XFORM_TALAIRACH"); gm.setTransformedSpaceName("NIFTI_XFORM_TALAIRACH"); matrices.push_back(gm); } } connectome-workbench-1.4.2/src/Gifti/GiftiDataArray.h000066400000000000000000000425501360521144700224760ustar00rootroot00000000000000 #ifndef __GIFTI_DATA_ARRAY_H__ #define __GIFTI_DATA_ARRAY_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include "CaretObject.h" #include "CaretPointer.h" #include "DescriptiveStatistics.h" #include "FastStatistics.h" #include "GiftiArrayIndexingOrderEnum.h" #include "GiftiEncodingEnum.h" #include "GiftiEndianEnum.h" #include "GiftiLabelTable.h" #include "GiftiMetaData.h" #include "Histogram.h" #include "Matrix4x4.h" #include "NiftiEnums.h" #include "TracksModificationInterface.h" namespace caret { class GiftiFile; class GiftiException; class PaletteColorMapping; /// class GiftiDataArray. class GiftiDataArray : public CaretObject, TracksModificationInterface { public: // constructor GiftiDataArray(const NiftiIntentEnum::Enum intentIn, const NiftiDataTypeEnum::Enum dataTypeIn, const std::vector& dimensionsIn, const GiftiEncodingEnum::Enum encodingIn = GiftiEncodingEnum::ASCII); // constructor used when reading data GiftiDataArray(const NiftiIntentEnum::Enum intentIn); // copy constructor GiftiDataArray(const GiftiDataArray& nda); // assignment operator GiftiDataArray& operator=(const GiftiDataArray& nda); // destructor virtual ~GiftiDataArray(); // add rows (increase 1st dimension) void addRows(const int32_t numRowsToAdd); // delete rows void deleteRows(const std::vector& rowsToDelete); // convert all data arrays to data type void convertToDataType(const NiftiDataTypeEnum::Enum newDataType) ; // set the dimensions void setDimensions(const std::vector dimensionsIn); // reset column virtual void clear(); /// get the number of dimensions int32_t getNumberOfDimensions() const { return dimensions.size(); } /// get the dimensions std::vector getDimensions() const { return dimensions; } /// current size of the data (in bytes) int64_t getDataSizeInBytes() const { return data.size(); } /// get a dimension int32_t getDimension(const int32_t dimIndex) const { return dimensions[dimIndex]; } // get the number of rows (1st dimension) int64_t getNumberOfRows() const; // get number of components per node (2nd dimension) int64_t getNumberOfComponents() const; // get the total number of elements int64_t getTotalNumberOfElements() const; // get data offset //int64_t getDataOffset(const int64_t nodeNum, const int64_t componentNum) const;//TSC: implementation was wrong, commenting out for now // read a data array from text void readFromText(const AString text, const GiftiEndianEnum::Enum dataEndianForReading, const GiftiArrayIndexingOrderEnum::Enum arraySubscriptingOrderForReading, const NiftiDataTypeEnum::Enum dataTypeForReading, const std::vector& dimensionsForReading, const GiftiEncodingEnum::Enum encodingForReading, const AString& externalFileNameForReading, const int64_t externalFileOffsetForReading, const bool isReadOnlyMetaData); // write the data as XML void writeAsXML(std::ostream& stream, std::ostream* externalBinaryOutputStream, GiftiEncodingEnum::Enum encodingForWriting); /// get endian GiftiEndianEnum::Enum getEndian() const { return endian; } // set endian void setEndian(const GiftiEndianEnum::Enum e) { endian = e; } /// get the system's endian static GiftiEndianEnum::Enum getSystemEndian(); // get external file information void getExternalFileInformation(AString& nameOut, int64_t& offsetOut) const; // set external file information void setExternalFileInformation(const AString& nameIn, const int64_t offsetIn); /// get the metadata GiftiMetaData* getMetaData() { return &metaData; } /// get the metadata (const method) const GiftiMetaData* getMetaData() const { return &metaData; } /// set the metadata void setMetaData(const GiftiMetaData* gmd) { metaData = *gmd; setModified(); } /// get the number of matrices int32_t getNumberOfMatrices() const { return matrices.size(); } /// add a matrix void addMatrix(const Matrix4x4& gm) { matrices.push_back(gm); } /// get a matrix Matrix4x4* getMatrix(const int32_t indx) { return &matrices[indx]; } /// remove all matrices void removeAllMatrices(); /// remove a matrix void removeMatrix(const int32_t indx); /// get the matrix (const method) const Matrix4x4* getMatrix(const int32_t indx) const { return &matrices[indx]; } /// get the non-written metadata for values not saved to file //GiftiMetaData* getNonWrittenMetaData() { return &nonWrittenMetaData; } /// get the non-written metadata for values not save to file (const method) //const GiftiMetaData* getNonWrittenMetaData() const { return &nonWrittenMetaData; } /// get the data type NiftiDataTypeEnum::Enum getDataType() const { return dataType; } /// set the data type void setDataType(const NiftiDataTypeEnum::Enum dt) { dataType = dt; setModified(); } /// get the encoding GiftiEncodingEnum::Enum getEncoding() const { return encoding; } /// set the encoding void setEncoding(const GiftiEncodingEnum::Enum e) { encoding = e; setModified(); } /// get the data intent NiftiIntentEnum::Enum getIntent() const { return intent; } /// set the data intent void setIntent(const NiftiIntentEnum::Enum cat) { intent = cat; setModified(); } /// valid intent name static bool intentNameValid(const AString& intentNameIn); /// get array subscripting order GiftiArrayIndexingOrderEnum::Enum getArraySubscriptingOrder() const { return arraySubscriptingOrder; } /// set array subscripting order void setArraySubscriptingOrder(const GiftiArrayIndexingOrderEnum::Enum aso) { arraySubscriptingOrder = aso; } /// get pointer for floating point data (valid only if data type is FLOAT) float* getDataPointerFloat() { return dataPointerFloat; } /// get pointer for floating point data (const method) (valid only if data type is FLOAT) const float* getDataPointerFloat() const { return dataPointerFloat; } /// get pointer for integer data (valid only if data type is INT) int32_t* getDataPointerInt() { return dataPointerInt; } /// get pointer for integer data (const method) (valid only if data type is INT) const int32_t* getDataPointerInt() const { return dataPointerInt; } /// get pointer for unsigned byte data (valid only if data type is UBYTE) uint8_t* getDataPointerUByte() { return dataPointerUByte; } /// get pointer for unsigned byte data (const method) (valid only if data type is UBYTE) const uint8_t* getDataPointerUByte() const { return dataPointerUByte; } // set all elements of array to zero void zeroize(); // get minimum and maximum values (valid for int data only) void getMinMaxValues(int& minValue, int& maxValue) const; void getMinMaxValuesFloat(float& minValue, float& maxValue) const; // remap integer values that are indices to a table //void remapIntValues(const std::vector& remappingTable); void transferLabelIndices(const std::map& indexConverter); // get the data type appropriate for the intent (returns true if valid intent) static bool getDataTypeAppropriateForIntent(const NiftiIntentEnum::Enum intentIn, NiftiDataTypeEnum::Enum& dataTypeOut); // get an offset for indices into data (dimensionality of indices must be same as data) int64_t getDataOffset(const int32_t indices[]) const; // get a float value (data type must be float and dimensionality of indices must be same as data) float getDataFloat32(const int32_t indices[]) const; // get a float value pointer (data type must be float and dimensionality of indices must be same as data) const float* getDataFloat32Pointer(const int32_t indices[]) const; // get an int value (data type must be int and dimensionality of indices must be same as data) int32_t getDataInt32(const int32_t indices[]) const; // get an int value pointer(data type must be int and dimensionality of indices must be same as data) const int32_t* getDataInt32Pointer(const int32_t indices[]) const; // get a byte value (data type must be unsigned char and dimensionality of indices must be same as data) uint8_t getDataUInt8(const int32_t indices[]) const; // get a byte value pointer (data type must be unsigned char and dimensionality of indices must be same as data) const uint8_t* getDataUInt8Pointer(const int32_t indices[]) const; // set a float value (data type must be float and dimensionality of indices must be same as data) void setDataFloat32(const int32_t indices[], const float dataValue) const; // set an int value (data type must be int and dimensionality of indices must be same as data) void setDataInt32(const int32_t indices[], const int32_t dataValue) const; // set a byte value (data type must be unsigned char and dimensionality of indices must be same as data) void setDataUInt8(const int32_t indices[], const uint8_t dataValue) const; void setModified(); void clearModified(); bool isModified() const; virtual AString toString() const; PaletteColorMapping* getPaletteColorMapping(); const PaletteColorMapping* getPaletteColorMapping() const; const DescriptiveStatistics* getDescriptiveStatistics() const; const FastStatistics* getFastStatistics() const; const Histogram* getHistogram(const int32_t numberOfBuckets) const; const DescriptiveStatistics* getDescriptiveStatistics(const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) const; const Histogram* getHistogram(const int32_t numberOfBuckets, const float mostPositiveValueInclusive, const float leastPositiveValueInclusive, const float leastNegativeValueInclusive, const float mostNegativeValueInclusive, const bool includeZeroValues) const; void invalidateHistograms(); protected: //validate the array void validateArrayAfterReading(); // allocate data for this column virtual void allocateData(); // the copy helper (used by copy constructor and assignment operator) void copyHelperGiftiDataArray(const GiftiDataArray& nda); // update the data pointers void updateDataPointers(); // byte swap the data (data read is different endian than this system) void byteSwapData(const GiftiEndianEnum::Enum newEndian); /// convert array indexing order of data void convertArrayIndexingOrder(); /// the data std::vector data; /// size of one data type element uint32_t dataTypeSize; /// pointer for floating point data float* dataPointerFloat; /// pointer for integer data int32_t* dataPointerInt; /// pointer for unsigned byte data uint8_t* dataPointerUByte; /// the matrix (typically only used by coordinates) std::vector matrices; /// the metadata GiftiMetaData metaData; /// the metadata not written to file (mainly for file specific data array meta data) GiftiMetaData nonWrittenMetaData; /// dimensions of the data std::vector dimensions; /// data type NiftiDataTypeEnum::Enum dataType; /// encoding of data GiftiEncodingEnum::Enum encoding; // endian of data GiftiEndianEnum::Enum endian; /// intent name NiftiIntentEnum::Enum intent; /// array subscripting order GiftiArrayIndexingOrderEnum::Enum arraySubscriptingOrder; /// external file name AString externalFileName; /// external file offset int64_t externalFileOffset; /// the palette color mapping mutable PaletteColorMapping* paletteColorMapping; /// minimum float value mutable float minValueFloat; /// maximum float value mutable float maxValueFloat; /// min/max float values valid (child class must set this false when an array value is changed) mutable bool minMaxFloatValuesValid; /// minimum int value mutable int32_t minValueInt; /// maximum int value mutable int32_t maxValueInt; /// min/max int values valid (child class must set this false when an array value is changed) mutable bool minMaxIntValuesValid; mutable float negMaxPct; mutable float negMinPct; mutable float posMinPct; mutable float posMaxPct; mutable float negMaxPctValue; mutable float negMinPctValue; mutable float posMinPctValue; mutable float posMaxPctValue; /// min/max percentage values valid mutable bool minMaxPercentageValuesValid; /// statistics about data (DO NOT COPY) mutable DescriptiveStatistics* descriptiveStatistics; mutable CaretPointer m_fastStatistics; mutable CaretPointer m_histogram; mutable int32_t m_histogramNumberOfBuckets = 100; mutable bool m_histogramNeedsUpdateFlag = false; mutable CaretPointer m_histogramLimitedValues; mutable int32_t m_histogramLimitedValuesNumberOfBuckets = 100; mutable float m_histogramLimitedValuesMostPositiveValueInclusive; mutable float m_histogramLimitedValuesLeastPositiveValueInclusive; mutable float m_histogramLimitedValuesLeastNegativeValueInclusive; mutable float m_histogramLimitedValuesMostNegativeValueInclusive; mutable bool m_histogramLimitedValuesIncludeZeroValues; mutable bool m_histogramLimitedValuesNeedsUpdateFlag = false; /// statistics about data (DO NOT COPY) mutable DescriptiveStatistics* descriptiveStatisticsLimitedValues; bool modifiedFlag; // DO NOT COPY // ***** BE SURE TO UPDATE copyHelper() if elements are added ****** /// allow NodeDataFile access to protected elements friend class GiftiFile; }; } // namespace #endif // __GIFTI_DATA_ARRAY_H__ connectome-workbench-1.4.2/src/Gifti/GiftiEncodingEnum.cxx000066400000000000000000000116621360521144700235540ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GIFTIENCODING_DECLARE__ #include "GiftiEncodingEnum.h" #undef __GIFTIENCODING_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * Constructor. * * @param e * An enumerated value. * @param name * Name of enumberated value. */ GiftiEncodingEnum::GiftiEncodingEnum( const Enum e, const int32_t integerCode, const AString& name, const AString& giftiName) { this->e = e; this->integerCode = integerCode; this->name = name; this->giftiName = giftiName; } /** * Destructor. */ GiftiEncodingEnum::~GiftiEncodingEnum() { } void GiftiEncodingEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(GiftiEncodingEnum(ASCII, -1, "ASCII", "ASCII")); enumData.push_back(GiftiEncodingEnum(BASE64_BINARY, -1, "BASE64_BINARY", "Base64Binary")); enumData.push_back(GiftiEncodingEnum(GZIP_BASE64_BINARY, -1, "GZIP_BASE64_BINARY", "GZipBase64Binary")); enumData.push_back(GiftiEncodingEnum(EXTERNAL_FILE_BINARY, -1, "EXTERNAL_FILE_BINARY", "ExternalFileBinary")); } /** * Find the data for and enumerated value. * @param e * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const GiftiEncodingEnum* GiftiEncodingEnum::findData(const Enum e) { initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const GiftiEncodingEnum* d = &enumData[i]; if (d->e == e) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString GiftiEncodingEnum::toName(Enum e) { initialize(); const GiftiEncodingEnum* gaio = findData(e); return gaio->name; } /** * Get an enumerated value corresponding to its name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ GiftiEncodingEnum::Enum GiftiEncodingEnum::fromName(const AString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = ASCII; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const GiftiEncodingEnum& d = *iter; if (d.name == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("name \"" + s + " \"failed to match enumerated value for type GiftiEncodingEnum")); } return e; } /** * Get a string representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString GiftiEncodingEnum::toGiftiName(Enum e) { initialize(); const GiftiEncodingEnum* gaio = findData(e); return gaio->giftiName; } /** * Get an enumerated value corresponding to its name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ GiftiEncodingEnum::Enum GiftiEncodingEnum::fromGiftiName(const AString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = ASCII; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const GiftiEncodingEnum& d = *iter; if (d.giftiName == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("giftiName \"" + s + " \"failed to match enumerated value for type GiftiEncodingEnum")); } return e; } connectome-workbench-1.4.2/src/Gifti/GiftiEncodingEnum.h000066400000000000000000000045031360521144700231750ustar00rootroot00000000000000#ifndef __GIFTIENCODING_H__ #define __GIFTIENCODING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include namespace caret { /** * GIFTI Encoding Types. */ class GiftiEncodingEnum { public: /** GIFTI Encoding Types. */ enum Enum { /** The data is ASCII Text */ ASCII, /** THe data is binary data that is encoded as text using the Base64 Algorithm */ BASE64_BINARY, /** The data is binary compressed using the GZIP algorithm and then encoded as Base64 */ GZIP_BASE64_BINARY, /** The data is stored in a separate, uncompressed, binary data file */ EXTERNAL_FILE_BINARY }; ~GiftiEncodingEnum(); static AString toName(Enum e); static Enum fromName(const AString& s, bool* isValidOut); static AString toGiftiName(Enum e); static Enum fromGiftiName(const AString& s, bool* isValidOut); private: GiftiEncodingEnum(const Enum e, const int32_t integerCode, const AString& name, const AString& giftiName); static const GiftiEncodingEnum* findData(const Enum e); static std::vector enumData; static void initialize(); static bool initializedFlag; Enum e; int32_t integerCode; AString name; AString giftiName; }; #ifdef __GIFTIENCODING_DECLARE__ std::vector GiftiEncodingEnum::enumData; bool GiftiEncodingEnum::initializedFlag = false; #endif // __GIFTIENCODING_DECLARE__ } // namespace #endif // __GIFTIENCODING_H__ connectome-workbench-1.4.2/src/Gifti/GiftiEndianEnum.cxx000066400000000000000000000112701360521144700232170ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GIFTIENDIAN_DECLARE__ #include "GiftiEndianEnum.h" #undef __GIFTIENDIAN_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * Constructor. * * @param e * An enumerated value. * @param name * Name of enumberated value. */ GiftiEndianEnum::GiftiEndianEnum( const Enum e, const int32_t integerCode, const AString& name, const AString& giftiName) { this->e = e; this->integerCode = integerCode; this->name = name; this->giftiName = giftiName; } /** * Destructor. */ GiftiEndianEnum::~GiftiEndianEnum() { } void GiftiEndianEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(GiftiEndianEnum(ENDIAN_BIG, 0, "ENDIAN_BIG", "BigEndian")); enumData.push_back(GiftiEndianEnum(ENDIAN_LITTLE, 1, "ENDIAN_LITTLE", "LittleEndian")); } /** * Find the data for and enumerated value. * @param e * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const GiftiEndianEnum* GiftiEndianEnum::findData(const Enum e) { initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const GiftiEndianEnum* d = &enumData[i]; if (d->e == e) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString GiftiEndianEnum::toName(Enum e) { initialize(); const GiftiEndianEnum* gaio = findData(e); return gaio->name; } /** * Get an enumerated value corresponding to its name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ GiftiEndianEnum::Enum GiftiEndianEnum::fromName(const AString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = ENDIAN_LITTLE; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const GiftiEndianEnum& d = *iter; if (d.name == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("name \"" + s + " \"failed to match enumerated value for type GiftiEndianEnum")); } return e; } /** * Get a string representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString GiftiEndianEnum::toGiftiName(Enum e) { initialize(); const GiftiEndianEnum* gaio = findData(e); return gaio->giftiName; } /** * Get an enumerated value corresponding to its name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ GiftiEndianEnum::Enum GiftiEndianEnum::fromGiftiName(const AString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = ENDIAN_LITTLE; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const GiftiEndianEnum& d = *iter; if (d.giftiName == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("giftiName \"" + s + " \"failed to match enumerated value for type GiftiEndianEnum")); } return e; } connectome-workbench-1.4.2/src/Gifti/GiftiEndianEnum.h000066400000000000000000000040761360521144700226520ustar00rootroot00000000000000#ifndef __GIFTIENDIAN_H__ #define __GIFTIENDIAN_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "GiftiException.h" #include #include #include namespace caret { /** * GIFTI Endian Types. */ class GiftiEndianEnum { public: /** GIFTI Endian Types. */ enum Enum { /** Data is in Big Endian byte order */ ENDIAN_BIG, /** Data is in Little Endian byte order */ ENDIAN_LITTLE }; ~GiftiEndianEnum(); static AString toName(Enum e); static Enum fromName(const AString& s, bool* isValidOut); static AString toGiftiName(Enum e); static Enum fromGiftiName(const AString& s, bool* isValidOut); private: GiftiEndianEnum(const Enum e, const int32_t integerCode, const AString& name, const AString& giftiName); static const GiftiEndianEnum* findData(const Enum e); static std::vector enumData; static void initialize(); static bool initializedFlag; Enum e; int32_t integerCode; AString name; AString giftiName; }; #ifdef __GIFTIENDIAN_DECLARE__ std::vector GiftiEndianEnum::enumData; bool GiftiEndianEnum::initializedFlag = false; #endif // __GIFTIENDIAN_DECLARE__ } // namespace #endif // __GIFTIENDIAN_H__ connectome-workbench-1.4.2/src/Gifti/GiftiFile.cxx000066400000000000000000001113151360521144700220540ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "DataFileException.h" #include "FileInformation.h" #include "GiftiEncodingEnum.h" #define __GIFTI_FILE_MAIN__ #include "GiftiFile.h" #undef __GIFTI_FILE_MAIN__ #include "GiftiFileSaxReader.h" #include "GiftiMetaDataXmlElements.h" #include "GiftiFileWriter.h" #include "GiftiXmlElements.h" #include "XmlSaxParser.h" #include using namespace caret; /** * Constructor */ GiftiFile::GiftiFile(const AString& descriptiveName, const NiftiIntentEnum::Enum defaultDataArrayIntentIn, const NiftiDataTypeEnum::Enum defaultDataTypeIn, const AString& defaultExtension, const bool dataAreIndicesIntoLabelTableIn) : DataFile() { this->descriptiveName = descriptiveName; defaultDataArrayIntent = defaultDataArrayIntentIn; defaultDataType = defaultDataTypeIn; dataAreIndicesIntoLabelTable = dataAreIndicesIntoLabelTableIn; this->defaultExtension = defaultExtension; numberOfNodesForSparseNodeIndexFile = 0; this->encodingForWriting = GiftiFile::defaultEncodingForWriting; } /** * Constructor for generic gifti data array file */ GiftiFile::GiftiFile() : DataFile() { this->descriptiveName = "GIFTI"; defaultDataArrayIntent = NiftiIntentEnum::NIFTI_INTENT_NONE; defaultDataType = NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32; dataAreIndicesIntoLabelTable = false; numberOfNodesForSparseNodeIndexFile = 0; this->defaultExtension = ".gii"; this->encodingForWriting = GiftiFile::defaultEncodingForWriting; } /** * copy constructor. */ GiftiFile::GiftiFile(const GiftiFile& nndf) : DataFile(nndf) { copyHelperGiftiFile(nndf); } /** * assignment operator. */ GiftiFile& GiftiFile::operator=(const GiftiFile& nndf) { if (this != &nndf) { DataFile::operator=(nndf); this->copyHelperGiftiFile(nndf); } return *this; } /** * copy helper. */ void GiftiFile::copyHelperGiftiFile(const GiftiFile& nndf) { labelTable = nndf.labelTable; metaData = nndf.metaData; defaultDataType = nndf.defaultDataType; defaultDataArrayIntent = nndf.defaultDataArrayIntent; dataAreIndicesIntoLabelTable = nndf.dataAreIndicesIntoLabelTable; numberOfNodesForSparseNodeIndexFile = nndf.numberOfNodesForSparseNodeIndexFile; this->descriptiveName = nndf.descriptiveName; this->defaultExtension = nndf.defaultExtension; int32_t numArrays = this->getNumberOfDataArrays(); for (int32_t i = (numArrays - 1); i >= 0; i--) { this->removeDataArray(i); } for (std::size_t i = 0; i < nndf.dataArrays.size(); i++) { addDataArray(new GiftiDataArray(*nndf.dataArrays[i])); } this->encodingForWriting = nndf.encodingForWriting; } /** * Destructor */ GiftiFile::~GiftiFile() { for (uint64_t i = 0; i < this->dataArrays.size(); i++) { delete this->dataArrays[i]; } } /** * compare a file for unit testing (returns true if "within tolerance"). */ bool GiftiFile::compareFileForUnitTesting(const GiftiFile* gf, const float tolerance, AString& messageOut) const { messageOut = ""; if (gf == NULL) { messageOut += "ERROR: File for comparison is not a GiftiFile or subtype.\n"; return false; } const int32_t numLabels = labelTable.getNumberOfLabels(); if (numLabels != gf->labelTable.getNumberOfLabels()) { messageOut += "ERROR: The files contain a different number of labels.\n"; } else { int32_t labelCount = 0; for (int32_t k = 0; k < numLabels; k++) { if (labelTable.getLabel(k) != gf->getLabelTable()->getLabel(k)) { labelCount++; } } if (labelCount > 0) { messageOut += "ERROR: The files have " + AString::number(labelCount) + " different labels.\n"; } } const int32_t numArrays = getNumberOfDataArrays(); if (numArrays != gf->getNumberOfDataArrays()) { messageOut += "ERROR: The files contain a different number of data arrays (data columns)"; } else { for (int32_t i = 0; i < numArrays; i++) { const GiftiDataArray* gdf1 = getDataArray(i); const GiftiDataArray* gdf2 = gf->getDataArray(i); const std::vector dim1 = gdf1->getDimensions(); const std::vector dim2 = gdf2->getDimensions(); if (dim1 != dim2) { messageOut += "ERROR: Data Array " + AString::number(i) + " have a different number of dimensions.\n"; } else { if (gdf1->getDataType() != gdf2->getDataType()) { messageOut += "ERROR: Data Array " + AString::number(i) + " are different data types.\n"; } else if (gdf1->getTotalNumberOfElements() != gdf2->getTotalNumberOfElements()) { messageOut += "ERROR: Data Array " + AString::number(i) + " have a different number of total elements.\n"; } else { const int32_t numElem = gdf1->getTotalNumberOfElements(); int32_t diffCount = 0; switch (gdf1->getDataType()) { case NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32: { const float* p1 = gdf1->getDataPointerFloat(); const float* p2 = gdf2->getDataPointerFloat(); for (int64_t m = 0; m < numElem; m++) { float diff = p1[m] - p2[m]; if (diff < 0.0) diff = -diff; if (diff > tolerance) { diffCount++; } } } break; case NiftiDataTypeEnum::NIFTI_TYPE_INT32: { const int32_t tol = static_cast(tolerance); const int32_t* p1 = gdf1->getDataPointerInt(); const int32_t* p2 = gdf2->getDataPointerInt(); for (int64_t m = 0; m < numElem; m++) { float diff = p1[m] - p2[m]; if (diff < 0.0) diff = -diff; if (diff > tol) { diffCount++; } } } break; case NiftiDataTypeEnum::NIFTI_TYPE_UINT8: { const uint8_t tol = static_cast(tolerance); const uint8_t* p1 = gdf1->getDataPointerUByte(); const uint8_t* p2 = gdf2->getDataPointerUByte(); for (int64_t m = 0; m < numElem; m++) { float diff = p1[m] - p2[m]; if (diff < 0.0) diff = -diff; if (diff > tol) { diffCount++; } } } break; default: CaretAssertMessage(0, "Invalid Data Type"); break; } if (diffCount > 0) { messageOut += "ERROR: There are " + AString::number(diffCount) + " elements with a difference that are greater than " + AString::number(tolerance) + " in data array " + AString::number(i) + ".\n"; } } } } } return (messageOut.isEmpty()); } /** * Set the name of a data array. */ void GiftiFile::setDataArrayName(const int32_t arrayIndex, const AString& name) { CaretAssertVectorIndex(this->dataArrays, arrayIndex); dataArrays[arrayIndex]->getMetaData()->set(GiftiXmlElements::TAG_METADATA_NAME, name); setModified(); } /** * returns true if the file is isEmpty() (contains no data). */ bool GiftiFile::isEmpty() const { return dataArrays.empty(); } /** * get the data array with the specified name. */ GiftiDataArray* GiftiFile::getDataArrayWithName(const AString& n) { for (int32_t i = 0; i < getNumberOfDataArrays(); i++) { if (getDataArrayName(i) == n) { return getDataArray(i); } } return NULL; } /** * get the data array with the specified name. */ const GiftiDataArray* GiftiFile::getDataArrayWithName(const AString& n) const { for (int32_t i = 0; i < getNumberOfDataArrays(); i++) { if (getDataArrayName(i) == n) { return getDataArray(i); } } return NULL; } /** * Get the data array index for an array with the specified name. If the * name is not found a negative number is returned. */ int GiftiFile::getDataArrayWithNameIndex(const AString& n) const { for (int32_t i = 0; i < getNumberOfDataArrays(); i++) { if (getDataArrayName(i) == n) { return i; } } return -1; } /** * get the data array of the specified intent. */ GiftiDataArray* GiftiFile::getDataArrayWithIntent(const NiftiIntentEnum::Enum intent) { for (int32_t i = 0; i < getNumberOfDataArrays(); i++) { GiftiDataArray* gda = getDataArray(i); if (gda->getIntent() == intent) { return gda; } } return NULL; } /** * get the data array of the specified intent (const method). */ const GiftiDataArray* GiftiFile::getDataArrayWithIntent(const NiftiIntentEnum::Enum intent) const { for (int32_t i = 0; i < getNumberOfDataArrays(); i++) { const GiftiDataArray* gda = getDataArray(i); if (gda->getIntent() == intent) { return gda; } } return NULL; } /** * get the index of the data array of the specified intent. */ int32_t GiftiFile::getDataArrayWithIntentIndex(const NiftiIntentEnum::Enum intent) const { for (int32_t i = 0; i < getNumberOfDataArrays(); i++) { const GiftiDataArray* gda = getDataArray(i); if (gda->getIntent() == intent) { return i; } } return -1; } /** * Get the name for a data array. */ AString GiftiFile::getDataArrayName(const int32_t arrayIndex) const { CaretAssertVectorIndex(this->dataArrays, arrayIndex); AString s = dataArrays[arrayIndex]->getMetaData()->get(GiftiXmlElements::TAG_METADATA_NAME); return s; } /** * Set the comment for a data array. */ void GiftiFile::setDataArrayComment(const int32_t arrayIndex, const AString& comm) { CaretAssertVectorIndex(this->dataArrays, arrayIndex); dataArrays[arrayIndex]->getMetaData()->set(GiftiMetaDataXmlElements::METADATA_NAME_COMMENT, comm); setModified(); } /** * Append to the comment for a data array. */ void GiftiFile::appendToDataArrayComment(const int32_t arrayIndex, const AString& comm) { CaretAssertVectorIndex(this->dataArrays, arrayIndex); if (comm.isEmpty() == false) { AString s(getDataArrayComment(arrayIndex)); s.append(comm); setDataArrayComment(arrayIndex, s); setModified(); } } /** * Prepend to the comment for a data array. */ void GiftiFile::prependToDataArrayComment(const int32_t arrayIndex, const AString& comm) { CaretAssertVectorIndex(this->dataArrays, arrayIndex); if (comm.isEmpty() == false) { AString s(comm); s.append(getDataArrayComment(arrayIndex)); setDataArrayComment(arrayIndex, s); setModified(); } } /** * Get the comment for a data array. */ AString GiftiFile::getDataArrayComment(const int32_t arrayIndex) const { CaretAssertVectorIndex(this->dataArrays, arrayIndex); AString s; (void)dataArrays[arrayIndex]->getMetaData()->get(GiftiMetaDataXmlElements::METADATA_NAME_COMMENT); return s; } /** * get the default data array intent. */ void GiftiFile::setDefaultDataArrayIntent(const NiftiIntentEnum::Enum newIntent) { defaultDataArrayIntent = newIntent; setModified(); } /** * */ void GiftiFile::clear() { DataFile::clear(); for (std::size_t i = 0; i < dataArrays.size(); i++) { if (dataArrays[i] != NULL) { delete dataArrays[i]; dataArrays[i] = NULL; } } dataArrays.clear(); labelTable.clear(); metaData.clear(); // do not clear // giftiElementName // requiredArrayTypeDataTypes } void GiftiFile::clearAndKeepMetadata() {//same as above, minus metaData.clear() DataFile::clear(); for (std::size_t i = 0; i < dataArrays.size(); i++) { if (dataArrays[i] != NULL) { delete dataArrays[i]; dataArrays[i] = NULL; } } dataArrays.clear(); labelTable.clear(); } /** * get all of the data array names. */ void GiftiFile::getAllArrayNames(std::vector& names) const { names.clear(); for (int32_t i = 0; i < getNumberOfDataArrays(); i++) { names.push_back(getDataArrayName(i)); } } /** * check for data arrays with the same name (returns true if there are any). */ bool GiftiFile::checkForDataArraysWithSameName(std::vector& multipleArrayNames) const { multipleArrayNames.clear(); const int32_t numArrays = getNumberOfDataArrays(); if (numArrays > 0) { std::set badNames; for (int32_t i = 0; i < (numArrays - 1); i++) { for (int32_t j = i + 1; j < numArrays; j++) { if (getDataArrayName(i) == getDataArrayName(j)) { badNames.insert(getDataArrayName(i)); } } } if (badNames.empty() == false) { multipleArrayNames.insert(multipleArrayNames.begin(), badNames.begin(), badNames.end()); } } return (multipleArrayNames.size() > 0); } /** * add a data array. */ void GiftiFile::addDataArray(GiftiDataArray* gda) { CaretAssert(gda); // const AString uuid = gda->getMetaData()->getUniqueID(); // const int32_t numDataArrays = this->getNumberOfDataArrays(); // for (int32_t i = 0; i < numDataArrays; i++) { // const AString daUuid = this->getDataArray(i)->getMetaData()->getUniqueID(); // if (daUuid == uuid) { // CaretLogWarning("File " // + this->getFileNameNoPath() // + " contains multiple data arrays with the same unique identifier. " // "Unique ID has been modified to ensure uniqueness within file."); // const bool modStatus = gda->isModified(); // gda->getMetaData()->resetUniqueIdentifier(); // if (modStatus == false) { // gda->clearModified(); // } // } // } dataArrays.push_back(gda); setModified(); } /** * append a gifti array data file to this one. */ void GiftiFile::append(const GiftiFile& gf) { const bool copyDataArrayFlag = true; const int32_t numArrays = gf.getNumberOfDataArrays(); if (numArrays <= 0) { return; } // // Replace filename if "this" file is isEmpty() // if (getNumberOfDataArrays() == 0) { setFileName(gf.getFileName()); } /* * Append metadata. */ this->metaData.append(*gf.getMetaData()); /* * Updates for label table. */ std::map labelIndexConverter = this->labelTable.append(*gf.getLabelTable()); // // Append the data arrays // for (int32_t i = 0; i < gf.getNumberOfDataArrays(); i++) { GiftiDataArray* gda = gf.dataArrays[i]; if (copyDataArrayFlag) { gda = new GiftiDataArray(*(gf.dataArrays[i])); } if (gda->getIntent() == NiftiIntentEnum::NIFTI_INTENT_LABEL) { gda->transferLabelIndices(labelIndexConverter); } this->addDataArray(gda); } setModified(); } /** * append array data file to this one but selectively load/overwrite arrays * indexDestination is where naf's data arrays should be (-1=new, -2=do not load). * "indexDestination" will be updated with the columns actually used. * @param gf * GIFTI file that is appended. * @param indexDestination * How arrays are added/replaced. */ void GiftiFile::append(const GiftiFile& gf, std::vector& indexDestination) { const bool copyDataArrayFlag = true; const int32_t numArrays = gf.getNumberOfDataArrays(); if (numArrays <= 0) { return; } /* * Append metadata. */ this->metaData.append(*gf.getMetaData()); /* * Updates for label table. */ std::map labelIndexConverter = this->labelTable.append(*gf.getLabelTable()); // // Replace file name if this file is isEmpty() // if (getNumberOfDataArrays() == 0) { setFileName(gf.getFileName()); } // // append the data arrays // for (int32_t i = 0; i < numArrays; i++) { const int32_t arrayIndex = indexDestination[i]; if (arrayIndex != 0) { GiftiDataArray* gda = gf.dataArrays[i]; if (copyDataArrayFlag) { gda = new GiftiDataArray(*gda); if (gda->getIntent() == NiftiIntentEnum::NIFTI_INTENT_LABEL) { gda->transferLabelIndices(labelIndexConverter); } this->addDataArray(gda); } // // Replacing existing array ? // if (arrayIndex >= 0) { delete dataArrays[arrayIndex]; dataArrays[arrayIndex] = gda; } // // create new array // else if (arrayIndex == -1) { dataArrays.push_back(gda); // // Lets others know where the array was placed // indexDestination[i] = getNumberOfDataArrays() - 1; } } // // Ignore array // else { // nothing } } this->appendToFileComment(gf.getFileComment()); setModified(); } AString GiftiFile::getFileComment() const { return this->metaData.get(GiftiMetaDataXmlElements::METADATA_NAME_COMMENT); } void GiftiFile::setFileComment(const AString& comment) { if (comment.isEmpty() == false) { AString s = this->getFileName(); s += "\n" + comment; this->setFileComment(s); } } void GiftiFile::appendToFileComment(const AString& comment) { this->metaData.set(GiftiMetaDataXmlElements::METADATA_NAME_COMMENT, comment); } /** * append helper for files where data are label indices. * The table "oldIndicesToNewIndicesTable" maps label indices from * "naf" label indices to the proper indices for "this" file. * void GiftiFile::appendLabelDataHelper(const GiftiFile& naf, const std::vector& arrayWillBeAppended, std::vector& oldIndicesToNewIndicesTable) { oldIndicesToNewIndicesTable.clear(); if ((dataAreIndicesIntoLabelTable == false) || (naf.dataAreIndicesIntoLabelTable == false)) { return; } const int32_t numArrays = naf.getNumberOfDataArrays(); if (numArrays != static_cast(arrayWillBeAppended.size())) { return; } const GiftiLabelTable* nltNew = naf.getLabelTable(); const int32_t numLabelsNew = nltNew->getNumberOfLabels(); if (numLabelsNew <= 0) { return; } oldIndicesToNewIndicesTable.resize(numLabelsNew, -1); // // Determine which labels will be appended // for (int32_t i = 0; i < numArrays; i++) { GiftiDataArray* nda = naf.dataArrays[i]; if (nda->getDataType() == NiftiDataType::NIFTI_TYPE_INT32) { const int32_t numElem = nda->getTotalNumberOfElements(); if (numElem >= 0) { int32_t* dataPtr = nda->getDataPointerInt(); for (int32_t i = 0; i < numElem; i++) { const int32_t indx = dataPtr[i]; if ((indx >= 0) && (indx < numLabelsNew)) { oldIndicesToNewIndicesTable[indx] = -2; } else { std::cout << "WARNING Invalid label index set to zero: " << indx << " of " << numLabelsNew << " labels." << std::endl; dataPtr[i] = 0; } } } } } // // remap the label indices // GiftiLabelTable* myLabelTable = getLabelTable(); for (int32_t i = 0; i < numLabelsNew; i++) { if (oldIndicesToNewIndicesTable[i] == -2) { int32_t indx = myLabelTable->addLabel(nltNew->getLabel(i)); oldIndicesToNewIndicesTable[i] = indx; nltNew->g unsigned char r, g, b, a; nltNew->getColor(i, r, g, b, a); myLabelTable->setColor(indx, r, g, b, a); } } } */ /** * add rows to this file. */ void GiftiFile::addRows(const int32_t numberOfRowsToAdd) { for (int32_t i = 0; i < getNumberOfDataArrays(); i++) { dataArrays[i]->addRows(numberOfRowsToAdd); } setModified(); } /** * reset a data array. */ void GiftiFile::resetDataArray(const int32_t arrayIndex) { CaretAssertVectorIndex(this->dataArrays, arrayIndex); dataArrays[arrayIndex]->zeroize(); } /** * remove a data array. */ void GiftiFile::removeDataArray(const int32_t arrayIndex) { CaretAssertVectorIndex(this->dataArrays, arrayIndex); int32_t numArrays = getNumberOfDataArrays(); if ((arrayIndex >= 0) && (arrayIndex < numArrays)) { delete dataArrays[arrayIndex]; for (int32_t i = arrayIndex; i < (numArrays - 1); i++) { dataArrays[i] = dataArrays[i + 1]; } dataArrays.resize(numArrays - 1); } } /** * remove a data array. */ void GiftiFile::removeDataArray(const GiftiDataArray* arrayPointer) { CaretAssert(arrayPointer); for (int32_t i = 0; i < getNumberOfDataArrays(); i++) { if (getDataArray(i) == arrayPointer) { removeDataArray(i); break; } } } /** * read the file. */ void GiftiFile::readFile(const AString& filename) { this->clear(); this->setFileName(filename); GiftiFileSaxReader saxReader(this); std::unique_ptr parser(XmlSaxParser::createXmlParser()); try { parser->parseFile(filename, &saxReader); } catch (const XmlSaxParserException& e) { clear(); this->setFileName(""); int lineNum = e.getLineNumber(); int colNum = e.getColumnNumber(); std::ostringstream str; str << "File is not a valid GIFTI file"; if ((lineNum >= 0) && (colNum >= 0)) { str << ", error parsing at line/col (" << e.getLineNumber() << "/" << e.getColumnNumber() << ")"; } str << ": " << e.whatString().toStdString(); throw DataFileException(filename, AString::fromStdString(str.str())); } /* * If any maps are missing names, give them default names. */ const int32_t numArrays = getNumberOfDataArrays(); for (int32_t i = 0; i < numArrays; i++) { AString arrayName = getDataArrayName(i); if (arrayName.isEmpty()) { arrayName = ("#" + AString::number(i + 1)); setDataArrayName(i, arrayName); } } } /** * write the file. */ void GiftiFile::writeFile(const AString& filename) { try { this->setFileName(filename); QFile::remove(filename); /*FileInformation fileInfo(filename); if (fileInfo.exists()) { //if (GiftiDataArrayFile.isFileOverwriteAllowed() == false) { // throw new GiftiException( // "Overwriting of existing files is currently prohibited"); //} }//*/ // // Create a GIFTI Data Array File Writer // GiftiFileWriter giftiFileWriter(filename, this->encodingForWriting); // // Start writing the file // int numberOfDataArrays = this->getNumberOfDataArrays(); giftiFileWriter.start(numberOfDataArrays, &this->metaData, &this->labelTable); // // Write the data arrays // for (int i = 0; i < numberOfDataArrays; i++) { giftiFileWriter.writeDataArray(this->getDataArray(i)); } // // Finish writing the file // giftiFileWriter.finish(); } catch (const GiftiException& e) { throw DataFileException(filename, e.whatString()); } this->clearModified(); /* // // Get how the array data should be encoded // GiftiDataArray::ENCODING encoding = GiftiDataArray::ENCODING_INTERNAL_ASCII; switch (getFileWriteType()) { case FILE_FORMAT_ASCII: break; case FILE_FORMAT_BINARY: break; case FILE_FORMAT_XML: encoding = GiftiDataArray::ENCODING_INTERNAL_ASCII; break; case FILE_FORMAT_XML_BASE64: encoding = GiftiDataArray::ENCODING_INTERNAL_BASE64_BINARY; break; case FILE_FORMAT_XML_GZIP_BASE64: encoding = GiftiDataArray::ENCODING_INTERNAL_COMPRESSED_BASE64_BINARY; break; case FILE_FORMAT_XML_EXTERNAL_BINARY: encoding = GiftiDataArray::ENCODING_EXTERNAL_FILE_BINARY; break; case FILE_FORMAT_OTHER: break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: break; } AString giftiFileVersionString = AString::number(GiftiFile::getCurrentFileVersion(), 'f', 6); while (giftiFileVersionString.endsWith("00")) { giftiFileVersionString.resize(giftiFileVersionString.size() - 1); } stream << "" << "\n"; stream << "" << "\n"; stream << "<" << GiftiCommon::tagGIFTI << "\n" << " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" << " xsi:noNamespaceSchemaLocation=\"http://brainvis.wustl.edu/caret6/xml_schemas/GIFTI_Caret.xsd\"\n" << " " << GiftiCommon::attVersion << "=\"" << giftiFileVersionString << "\"\n" << " " << GiftiCommon::attNumberOfDataArrays << "=\"" << getNumberOfDataArrays() << "\"" << ">" << "\n"; int32_t indent = 0; // // External binary file. // AString externalBinaryFileName; int64_t externalBinaryFileDataOffset = 0; std::ofstream* externalBinaryOutputStream = NULL; if (encoding == GiftiDataArray::ENCODING_EXTERNAL_FILE_BINARY) { externalBinaryFileName = getFileNameNoPath() + ".data"; externalBinaryOutputStream = new std::ofstream(externalBinaryFileName.toLatin1().constData(), std::ofstream::binary); if (externalBinaryOutputStream == NULL) { throw GiftiException("Unable to open " + externalBinaryFileName + " for output."); } } #ifdef CARET_FLAG // // copy the Abstract File header into this file's metadata // metaData.clear(); AbstractFileHeaderContainer::iterator iter; for (iter = header.begin(); iter != header.end(); iter++) { // // Get the tag and its value // const AString tag(iter->first); const AString value(iter->second); metaData.set(tag,value); } #endif // CARET_FLAG indent++; metaData.writeAsXML(stream, indent); indent--; // // Write the labels // indent++; labelTable.writeAsXML(stream, indent); indent--; indent++; for (unsigned int32_t i = 0; i < dataArrays.size(); i++) { #ifdef CARET_FLAG dataArrays[i]->setEncoding(encoding); #endif // CARET_FLAG if (externalBinaryOutputStream != NULL) { externalBinaryFileDataOffset = externalBinaryOutputStream->tellp(); } dataArrays[i]->setExternalFileInformation(externalBinaryFileName, externalBinaryFileDataOffset); dataArrays[i]->writeAsXML(stream, indent, externalBinaryOutputStream); } indent--; stream << "" << "\n"; if (externalBinaryOutputStream != NULL) { externalBinaryOutputStream->close(); } */ } /** * set the number of nodes for sparse node index files (NIFTI_INTENT_NODE_INDEX). */ void GiftiFile::setNumberOfNodesForSparseNodeIndexFiles(const int32_t numNodes) { numberOfNodesForSparseNodeIndexFile = numNodes; } /** * process NIFTI_INTENT_NODE_INDEX arrays. */ void GiftiFile::procesNiftiIntentNodeIndexArrays() { // // See if there is a node index array // GiftiDataArray* nodeIndexArray = getDataArrayWithIntent(NiftiIntentEnum::NIFTI_INTENT_NODE_INDEX); if (nodeIndexArray != NULL) { // // Make sure node index array is integer type and one dimensional // if (nodeIndexArray->getDataType() != NiftiDataTypeEnum::NIFTI_TYPE_INT32) { throw GiftiException("Data type other than \"int\" not supported for data intent node index."); } if (nodeIndexArray->getNumberOfDimensions() < 1) { throw GiftiException("Dimensions other than one not supported for data intent node index."); } // // Make node index array integer // nodeIndexArray->convertToDataType(NiftiDataTypeEnum::NIFTI_TYPE_INT32); // // Get the node indices // const int32_t numNodeIndices = nodeIndexArray->getDimension(0); if (numNodeIndices <= 0) { throw GiftiException("Dimension is zero for data intent: " + NiftiIntentEnum::toName(NiftiIntentEnum::NIFTI_INTENT_NODE_INDEX)); } const int32_t zeroIndex[2] = { 0, 0 }; const int32_t* indexData = nodeIndexArray->getDataInt32Pointer(zeroIndex); // // Find the true number of nodes // int32_t numNodes = numberOfNodesForSparseNodeIndexFile; if (numNodes <= 0) { int32_t minNodeIndex = 0; nodeIndexArray->getMinMaxValues(minNodeIndex, numNodes); } // // Check each data array // const int32_t numArrays = getNumberOfDataArrays(); for (int32_t i = 0; i < numArrays; i++) { GiftiDataArray* dataArray = getDataArray(i); if (dataArray->getIntent() != NiftiIntentEnum::NIFTI_INTENT_NODE_INDEX) { if (dataArray->getNumberOfDimensions() < 1) { throw GiftiException("Data Array with intent \"" + NiftiIntentEnum::toName(dataArray->getIntent()) + " is not one-dimensional in sparse node file."); } if (dataArray->getDimension(0) != numNodeIndices) { throw GiftiException("Data Array with intent \"" + NiftiIntentEnum::toName(dataArray->getIntent()) + " has a different number of nodes than the NIFTI_INTENT_NODE_INDEX array in the file."); } switch (dataArray->getDataType()) { case NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32: { std::vector dataFloat(numNodes, 0.0); const float* readPtr = dataArray->getDataFloat32Pointer(zeroIndex); for (int32_t m = 0; m < numNodeIndices; m++) { dataFloat[indexData[m]] = readPtr[m]; } std::vector newDim(1, numNodes); dataArray->setDimensions(newDim); for (int32_t n = 0; n < numNodes; n++) { const int32_t indxs[2] = { n, 0 }; dataArray->setDataFloat32(indxs, dataFloat[n]); } } break; case NiftiDataTypeEnum::NIFTI_TYPE_INT32: { std::vector dataInt(numNodes, 0); const int32_t* readPtr = dataArray->getDataInt32Pointer(zeroIndex); for (int32_t m = 0; m < numNodeIndices; m++) { dataInt[indexData[m]] = readPtr[m]; } std::vector newDim(1, numNodes); dataArray->setDimensions(newDim); for (int32_t n = 0; n < numNodes; n++) { const int32_t indxs[2] = { n, 0 }; dataArray->setDataInt32(indxs, dataInt[n]); } } break; case NiftiDataTypeEnum::NIFTI_TYPE_UINT8: { std::vector dataByte(numNodes, 0); const uint8_t* readPtr = dataArray->getDataUInt8Pointer(zeroIndex); for (int32_t m = 0; m < numNodeIndices; m++) { dataByte[indexData[m]] = readPtr[m]; } std::vector newDim(1, numNodes); dataArray->setDimensions(newDim); for (int32_t n = 0; n < numNodes; n++) { const int32_t indxs[2] = { n, 0 }; dataArray->setDataUInt8(indxs, dataByte[n]); } } break; default: CaretAssertMessage(0, "Invalid Data Type"); break; } } } // // Remove the node index array // removeDataArray(nodeIndexArray); } } /** * Set this object as not modified. Object should also * clear the modification status of its children. * */ void GiftiFile::clearModified() { DataFile::clearModified(); metaData.clearModified(); labelTable.clearModified(); for (int i = 0; i < this->getNumberOfDataArrays(); i++) { this->getDataArray(i)->clearModified(); } } /** * Get the modification status. Returns true if this object or * any of its children have been modified. * @return - The modification status. * */ bool GiftiFile::isModified() const { if (DataFile::isModified()) { return true; } if (metaData.isModified()) { return true; } if (labelTable.isModified()) { return true; } for (int i = 0; i < this->getNumberOfDataArrays(); i++) { if (this->getDataArray(i)->isModified()) { return true; } } return false; } /** * Set the encoding for writing the file. * @param encoding * New encoding. */ void GiftiFile::setEncodingForWriting(const GiftiEncodingEnum::Enum encoding) { this->encodingForWriting = encoding; } /** * Validate the data arrays (optional for subclasses). */ void GiftiFile::validateDataArrays() { // nothing } AString GiftiFile::toString() const { std::ostringstream str; str << "Gifti File: " << this->getFileName().toStdString() << std::endl; str << this->metaData.toString().toStdString() << std::endl; str << this->labelTable.toString().toStdString() << std::endl; for (int32_t i = 0; i < this->getNumberOfDataArrays(); i++) { const GiftiDataArray* gda = this->getDataArray(i); str << gda->toString().toStdString() << std::endl; } return AString::fromStdString(str.str()); } connectome-workbench-1.4.2/src/Gifti/GiftiFile.h000066400000000000000000000224331360521144700215030ustar00rootroot00000000000000#ifndef __GIFTI_FILE_H__ #define __GIFTI_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretAssert.h" #include "DataFile.h" #include "GiftiDataArray.h" #include "GiftiEncodingEnum.h" #include "GiftiLabelTable.h" #include "NiftiEnums.h" #include "TracksModificationInterface.h" namespace caret { /// This abstract class defines some variables and methods used for gifti data array files. /// While this class may be instantiated, it is best subclassed. class GiftiFile : public DataFile { public: /// append array index values enum APPEND_ARRAY_INDEX { APPEND_ARRAY_NEW = -1, APPEND_ARRAY_DO_NOT_LOAD = -2 }; /// constructor GiftiFile(const AString& descriptiveName, const NiftiIntentEnum::Enum defaultDataArrayIntentIn, const NiftiDataTypeEnum::Enum defaultDataTypeIn, const AString& defaultExt, const bool dataAreIndicesIntoLabelTableIn); /// constructor for generic gifti data array file GiftiFile(); // copy constructor GiftiFile(const GiftiFile& nndf); // destructor virtual ~GiftiFile(); // assignment operator GiftiFile& operator=(const GiftiFile& nndf); // add a data array virtual void addDataArray(GiftiDataArray* nda); // add rows to this file. void addRows(const int32_t numberOfRowsToAdd); // append a data array file to this one virtual void append(const GiftiFile& naf); // append a data array file to this one but selectively load/overwrite arraysumns // arrayDestination is where naf's arrays should be (-1=new, -2=do not load) virtual void append(const GiftiFile& naf, std::vector& indexDestinationg); /// compare a file for unit testing (returns true if "within tolerance") virtual bool compareFileForUnitTesting(const GiftiFile* gf, const float tolerance, AString& messageOut) const; // Clear the gifti array data file. virtual void clear(); virtual void clearAndKeepMetadata(); // returns true if the file is isEmpty() (contains no data) virtual bool isEmpty() const; AString getFileComment() const; void setFileComment(const AString& comment); void appendToFileComment(const AString& comment); /// get the number of data arrays int32_t getNumberOfDataArrays() const { return dataArrays.size() ; } /// get a data array GiftiDataArray* getDataArray(const int32_t arrayNumber) { CaretAssertVectorIndex(dataArrays, arrayNumber); return dataArrays[arrayNumber]; } /// get a data array (const method) const GiftiDataArray* getDataArray(const int32_t arrayNumber) const { CaretAssertVectorIndex(dataArrays, arrayNumber); return dataArrays[arrayNumber]; } /// reset a data array virtual void resetDataArray(const int32_t arrayIndex); /// remove a data array virtual void removeDataArray(const GiftiDataArray* arrayPointer); /// remove a data array virtual void removeDataArray(const int32_t arrayIndex); // get all of the data array names void getAllArrayNames(std::vector& names) const; // get the specified data array's name AString getDataArrayName(const int32_t arrayIndex) const; // get the index of the data array with the specified name int32_t getDataArrayWithNameIndex(const AString& n) const; // get the data array with the specified name GiftiDataArray* getDataArrayWithName(const AString& n); // get the data array with the specified name const GiftiDataArray* getDataArrayWithName(const AString& n) const; // get the index of the data array of the specified intent int32_t getDataArrayWithIntentIndex(const NiftiIntentEnum::Enum intent) const; // get the data array of the specified intent GiftiDataArray* getDataArrayWithIntent(const NiftiIntentEnum::Enum intent); // get the data array of the specified intent (const method) const GiftiDataArray* getDataArrayWithIntent(const NiftiIntentEnum::Enum intent) const; // get the comment for a data array AString getDataArrayComment(const int32_t arrayIndex) const; // set the name of a data array void setDataArrayName(const int32_t arrayIndex, const AString& name); // set the comment for a data array void setDataArrayComment(const int32_t arrayIndex, const AString& comm); // append to the comment for a data array void appendToDataArrayComment(const int32_t arrayIndex, const AString& comm); // prepend to the comment for a data array void prependToDataArrayComment(const int32_t arrayIndex, const AString& comm); // check for data arrays with the same name (returns true if there are any) bool checkForDataArraysWithSameName(std::vector& multipleDataArrayNames) const; // get the metadata GiftiMetaData* getMetaData() { return &metaData; } // get the metadata (const method) const GiftiMetaData* getMetaData() const { return &metaData; } /// get the label table GiftiLabelTable* getLabelTable() { return &labelTable; } /// get the label table const GiftiLabelTable* getLabelTable() const { return &labelTable; } /// get the current version for GiftiFiles static float getCurrentFileVersion() { return 1.0; } /// get the default data array intent NiftiIntentEnum::Enum getDefaultDataArrayIntent() const { return defaultDataArrayIntent; } /// get the default data array intent void setDefaultDataArrayIntent(const NiftiIntentEnum::Enum newIntent); /// set the number of nodes for sparse node index files (NIFTI_INTENT_NODE_INDEX) void setNumberOfNodesForSparseNodeIndexFiles(const int32_t numNodes); // read the XML file virtual void readFile(const AString& filename); // write the XML file virtual void writeFile(const AString& filename); bool getReadMetaDataOnlyFlag() const { return false; } /** @return The encoding used to write the file. */ GiftiEncodingEnum::Enum getEncodingForWriting() const { return this->encodingForWriting; } void setEncodingForWriting(const GiftiEncodingEnum::Enum encoding); virtual void clearModified(); virtual bool isModified() const; virtual AString toString() const; protected: // append helper for files where data are label indices //void appendLabelDataHelper(const GiftiFile& naf, // const std::vector& arrayWillBeAppended, // std::vector& oldIndicesToNewIndicesTable); // copy helper void copyHelperGiftiFile(const GiftiFile& nndf); // process NIFTI_INTENT_NODE_INDEX arrays void procesNiftiIntentNodeIndexArrays(); // validate the data arrays (optional for subclasses) virtual void validateDataArrays(); /// the data arrays std::vector dataArrays; /// the label table GiftiLabelTable labelTable; /// the file's metadata GiftiMetaData metaData; GiftiEncodingEnum::Enum encodingForWriting; /// the default data type NiftiDataTypeEnum::Enum defaultDataType; /// default data array intent for this file NiftiIntentEnum::Enum defaultDataArrayIntent; /// data arrays contain indices into label table bool dataAreIndicesIntoLabelTable; AString descriptiveName; AString defaultExtension; /// number of nodes in sparse node index files (NIFTI_INTENT_NODE_INDEX array) int32_t numberOfNodesForSparseNodeIndexFile; /** The default encoding for writing a GIFTI file. */ static GiftiEncodingEnum::Enum defaultEncodingForWriting; /*!!!! be sure to update copyHelperGiftiFile if new member added !!!!*/ // // friends // }; #ifdef __GIFTI_FILE_MAIN__ GiftiEncodingEnum::Enum GiftiFile::defaultEncodingForWriting = GiftiEncodingEnum::GZIP_BASE64_BINARY; #endif // __GIFTI_FILE_MAIN__ } // namespace #endif // __GIFTI_FILE_H__ connectome-workbench-1.4.2/src/Gifti/GiftiFileSaxReader.cxx000066400000000000000000000515721360521144700236630ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretLogger.h" #include "FileInformation.h" #include "GiftiEndianEnum.h" #include "GiftiLabel.h" #include "GiftiFile.h" #include "GiftiFileSaxReader.h" #include "GiftiLabelTableSaxReader.h" #include "GiftiMetaDataSaxReader.h" #include "GiftiXmlElements.h" #include "NiftiEnums.h" #include "XmlAttributes.h" #include "XmlException.h" using namespace caret; /** * constructor. */ GiftiFileSaxReader::GiftiFileSaxReader(GiftiFile* giftiFileIn) { this->giftiFile = giftiFileIn; this->state = STATE_NONE; this->stateStack.push(this->state); this->elementText = ""; this->dataArray.grabNew(NULL); this->labelTable = NULL; this->labelTableSaxReader = NULL; this->metaDataSaxReader = NULL; this->dataArrayDataHasBeenRead = false; } /** * destructor. */ GiftiFileSaxReader::~GiftiFileSaxReader() { } /** * start an element. */ void GiftiFileSaxReader::startElement(const AString& namespaceURI, const AString& localName, const AString& qName, const XmlAttributes& attributes) { const STATE previousState = this->state; switch (this->state) { case STATE_NONE: if (qName == GiftiXmlElements::TAG_GIFTI) { this->state = STATE_GIFTI; // // Check version of file being read // const float version = attributes.getValueAsFloat(GiftiXmlElements::ATTRIBUTE_GIFTI_VERSION); if (version > GiftiFile::getCurrentFileVersion()) { std::ostringstream str; str << "File version is " << version << " but this Caret" << " does not support versions newer than " << GiftiFile::getCurrentFileVersion() << ".\n" << "You may need a newer version of Caret."; throw XmlSaxParserException(AString::fromStdString(str.str())); } else if (version < 1.0) { throw XmlSaxParserException( "File version is " + AString::number(version) + " but this Caret" " does not support versions before 1.0"); } } else { std::ostringstream str; str << "Root element is \"" << qName << "\" but should be " << GiftiXmlElements::TAG_GIFTI; throw XmlSaxParserException(AString::fromStdString(str.str())); } break; case STATE_GIFTI: if (qName == GiftiXmlElements::TAG_METADATA) { this->state = STATE_METADATA; this->metaDataSaxReader = new GiftiMetaDataSaxReader(giftiFile->getMetaData()); this->metaDataSaxReader->startElement(namespaceURI, localName, qName, attributes); } else if (qName == GiftiXmlElements::TAG_DATA_ARRAY) { this->state = STATE_DATA_ARRAY; this->createDataArray(attributes); } else if (qName == GiftiXmlElements::TAG_LABEL_TABLE) { this->state = STATE_LABEL_TABLE; this->labelTableSaxReader = new GiftiLabelTableSaxReader(giftiFile->getLabelTable()); this->labelTableSaxReader->startElement(namespaceURI, localName, qName, attributes); } else { std::ostringstream str; str << "Child of " << GiftiXmlElements::TAG_GIFTI << " is \"" << qName << "\" but should be one of \n" << " " << GiftiXmlElements::TAG_METADATA << "\n" << " " << GiftiXmlElements::TAG_DATA_ARRAY << "\n" << " " << GiftiXmlElements::TAG_LABEL_TABLE; throw XmlSaxParserException(AString::fromStdString(str.str())); } break; case STATE_METADATA: this->metaDataSaxReader->startElement(namespaceURI, localName, qName, attributes); break; case STATE_LABEL_TABLE: this->labelTableSaxReader->startElement(namespaceURI, localName, qName, attributes); break; case STATE_DATA_ARRAY: if (qName == GiftiXmlElements::TAG_METADATA) { this->state = STATE_METADATA; this->metaDataSaxReader = new GiftiMetaDataSaxReader(dataArray->getMetaData()); this->metaDataSaxReader->startElement(namespaceURI, localName, qName, attributes); } else if (qName == GiftiXmlElements::TAG_DATA) { this->state = STATE_DATA_ARRAY_DATA; } else if (qName == GiftiXmlElements::TAG_COORDINATE_TRANSFORMATION_MATRIX) { this->state = STATE_DATA_ARRAY_MATRIX; this->dataArray->addMatrix(Matrix4x4()); this->matrix = dataArray->getMatrix(dataArray->getNumberOfMatrices() - 1); } else { std::ostringstream str; str << "Child of " << GiftiXmlElements::TAG_DATA_ARRAY << " is \"" << qName << "\" but should be one of \n" << " " << GiftiXmlElements::TAG_METADATA << "\n" << " " << GiftiXmlElements::TAG_COORDINATE_TRANSFORMATION_MATRIX << "\n" << " " << GiftiXmlElements::TAG_DATA; throw XmlSaxParserException(AString::fromStdString(str.str())); } break; case STATE_DATA_ARRAY_DATA: { std::ostringstream str; str << GiftiXmlElements::TAG_DATA << " has child \"" << qName << "\" but should not have any child nodes"; throw XmlSaxParserException(AString::fromStdString(str.str())); } break; case STATE_DATA_ARRAY_MATRIX: if (qName == GiftiXmlElements::TAG_MATRIX_DATA_SPACE) { this->state = STATE_DATA_ARRAY_MATRIX_DATA_SPACE; } else if (qName == GiftiXmlElements::TAG_MATRIX_TRANSFORMED_SPACE) { this->state = STATE_DATA_ARRAY_MATRIX_TRANSFORMED_SPACE; } else if (qName == GiftiXmlElements::TAG_MATRIX_DATA) { this->state = STATE_DATA_ARRAY_MATRIX_DATA; } else { std::ostringstream str; str << "Child of " << GiftiXmlElements::TAG_COORDINATE_TRANSFORMATION_MATRIX << " is \"" << qName << "\" but should be one of \n" << " " << GiftiXmlElements::TAG_MATRIX_DATA_SPACE << "\n" << " " << GiftiXmlElements::TAG_MATRIX_TRANSFORMED_SPACE << "\n" << " " << GiftiXmlElements::TAG_MATRIX_DATA; throw XmlSaxParserException(AString::fromStdString(str.str())); } break; case STATE_DATA_ARRAY_MATRIX_DATA_SPACE: { std::ostringstream str; str << GiftiXmlElements::TAG_MATRIX_DATA_SPACE << " has child \"" << qName << "\" but should not have any child nodes"; throw XmlSaxParserException(AString::fromStdString(str.str())); } break; case STATE_DATA_ARRAY_MATRIX_TRANSFORMED_SPACE: { std::ostringstream str; str << GiftiXmlElements::TAG_MATRIX_TRANSFORMED_SPACE << " has child \"" << qName << "\" but should not have any child nodes"; throw XmlSaxParserException(AString::fromStdString(str.str())); } break; case STATE_DATA_ARRAY_MATRIX_DATA: { std::ostringstream str; str << GiftiXmlElements::TAG_MATRIX_DATA << " has child \"" << qName << "\" but should not have any child nodes"; throw XmlSaxParserException(AString::fromStdString(str.str())); } break; } // // Save previous state // stateStack.push(previousState); elementText = ""; } /** * end an element. */ void GiftiFileSaxReader::endElement(const AString& namespaceURI, const AString& localName, const AString& qName) { switch (this->state) { case STATE_NONE: break; case STATE_GIFTI: break; case STATE_METADATA: this->metaDataSaxReader->endElement(namespaceURI, localName, qName); if (qName == GiftiXmlElements::TAG_METADATA) { delete this->metaDataSaxReader; this->metaDataSaxReader = NULL; } break; case STATE_LABEL_TABLE: this->labelTableSaxReader->endElement(namespaceURI, localName, qName); if (qName == GiftiXmlElements::TAG_LABEL_TABLE) { delete this->labelTableSaxReader; this->labelTableSaxReader = NULL; } break; case STATE_DATA_ARRAY: if (this->dataArray != NULL) { /* * An external binary file may not have a DATA tag * so this will handle reading in that case. */ if (this->encodingForReadingArrayData == GiftiEncodingEnum::EXTERNAL_FILE_BINARY) { if (this->dataArrayDataHasBeenRead == false) { this->processArrayData(); } } this->giftiFile->addDataArray(this->dataArray.releasePointer()); } else { } break; case STATE_DATA_ARRAY_DATA: this->processArrayData(); break; case STATE_DATA_ARRAY_MATRIX: this->matrix = NULL; break; case STATE_DATA_ARRAY_MATRIX_DATA_SPACE: this->matrix->setDataSpaceName(elementText); break; case STATE_DATA_ARRAY_MATRIX_TRANSFORMED_SPACE: this->matrix->setTransformedSpaceName(elementText); break; case STATE_DATA_ARRAY_MATRIX_DATA: { std::istringstream istr(elementText.toStdString()); double m[4][4]; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { istr >> m[i][j]; } } matrix->setMatrix(m); /* * In GIFTI file, matrix is row-major order * but Matrix4x4 is column-major order. */ matrix->transpose(); } break; } // // Clear out for new elements // this->elementText = ""; // // Go to previous state // if (this->stateStack.empty()) { throw XmlSaxParserException("State stack is empty while reading XML NiftDataFile."); } this->state = stateStack.top(); this->stateStack.pop(); } /** * create a data array. */ void GiftiFileSaxReader::createDataArray(const XmlAttributes& attributes) { // // Intent // AString intentName = attributes.getValue(GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_INTENT); if (intentName.isEmpty()) { intentName = attributes.getValue("Intent"); } if (intentName.isEmpty()) { throw XmlSaxParserException( "Required attribute " + GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_INTENT + " not found for DataArray"); } bool intentValid = false; NiftiIntentEnum::Enum intent = NiftiIntentEnum::fromName(intentName, &intentValid); if (intentValid == false) { throw XmlSaxParserException("Intent name invalid: " + intentName); } // // Data type name // const AString dataTypeName = attributes.getValue(GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_DATA_TYPE); if (dataTypeName.isEmpty()) { throw XmlSaxParserException("Required attribute " + GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_DATA_TYPE + " not found for DataArray"); } bool dataTypeNameValid = false; this->dataTypeForReadingArrayData = NiftiDataTypeEnum::fromName(dataTypeName, &dataTypeNameValid); if (dataTypeNameValid == false) { throw XmlSaxParserException("Attribute " + GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_DATA_TYPE + "is invalid: " + dataTypeName); } // // Encoding // const AString encodingName = attributes.getValue(GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_ENCODING); if (encodingName.isEmpty()) { throw XmlSaxParserException("Required attribute " + GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_ENCODING + " not found for DataArray"); } bool validEncoding = false; encodingForReadingArrayData = GiftiEncodingEnum::fromGiftiName(encodingName, &validEncoding); if (validEncoding == false) { throw XmlSaxParserException("Attribute " + GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_ENCODING + "is invalid: " + encodingName); } // // External File Name // this->externalFileNameForReadingData = attributes.getValue(GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_EXTERNAL_FILE_NAME); /* * Update external file with path to XML file */ FileInformation extBinInfo(this->externalFileNameForReadingData); if (extBinInfo.isAbsolute() == false) { FileInformation xmlInfo(this->giftiFile->getFileName()); AString path = xmlInfo.getPathName(); if (path.isEmpty() == false) { FileInformation fi(path, this->externalFileNameForReadingData); AString newName = fi.getAbsoluteFilePath(); if (newName.isEmpty() == false) { this->externalFileNameForReadingData = newName; } } } // // External File Offset // this->externalFileOffsetForReadingData = 0; if (encodingForReadingArrayData == GiftiEncodingEnum::EXTERNAL_FILE_BINARY) { const AString offsetString = attributes.getValue(GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_EXTERNAL_FILE_OFFSET); //if (offsetString.isEmpty() == false) { bool validOffsetFlag = false; this->externalFileOffsetForReadingData = offsetString.toLong(&validOffsetFlag); if (validOffsetFlag == false) { XmlSaxParserException e("File Offset is not an integer (" + offsetString + ")"); CaretLogThrowing(e); throw e; } //} } // // Endian // AString endianAttributeNameForReadingArrayData = attributes.getValue(GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_ENDIAN); if (endianAttributeNameForReadingArrayData.isEmpty()) { throw XmlSaxParserException("Required attribute " + GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_ENDIAN + " not found for DataArray"); } bool endianValid = false; this->endianForReadingArrayData = GiftiEndianEnum::fromGiftiName(endianAttributeNameForReadingArrayData, &endianValid); if (endianValid == false) { throw XmlSaxParserException("Attribute " + GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_ENDIAN + "is invalid: " + endianAttributeNameForReadingArrayData); } // // Dimensions // const AString dimString = attributes.getValue(GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_DIMENSIONALITY); if (dimString.isEmpty()) { throw XmlSaxParserException("Required attribute " + GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_DIMENSIONALITY + " not found for DataArray"); } this->dimensionsForReadingArrayData.clear(); const int numDimensions = dimString.toInt(); for (int i = 0; i < numDimensions; i++) { const AString dimNumString = attributes.getValue(GiftiXmlElements::getAttributeDimension(i)); if (dimNumString.isEmpty()) { throw XmlSaxParserException("Required dimension " + GiftiXmlElements::getAttributeDimension(i) + " not found for DataArray"); } const int dim = dimNumString.toInt(); this->dimensionsForReadingArrayData.push_back(dim); } // // Data Location // /* const AString dataLocationString = attributes.getValue(GiftiXmlElements::attDataLocation); if (dataLocationString.isEmpty()) { errorMessage = "Required attribute " + GiftiXmlElements::attDataLocation + " not found for DataArray"; return false; } bool validDataLocation = false; dataLocationForReadingArrayData = GiftiDataArray::getDataLocationFromName(dataLocationString, &validDataLocation); if (validDataLocation == false) { errorMessage = "Attribute " + GiftiXmlElements::attDataLocation + "is invalid: " + dataLocationString; return false; } if (dataLocationForReadingArrayData == GiftiDataArray::DATA_LOCATION_EXTERNAL) { errorMessage = "External data storage not supported."; return false; } */ // // Subscript order // const AString subscriptOrderString = attributes.getValue(GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_INDEXING_ORDER); if (subscriptOrderString.isEmpty()) { throw XmlSaxParserException("Required attribute " + GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_INDEXING_ORDER + " not found for DataArray"); } bool validArraySubscriptingOrder = false; this->arraySubscriptingOrderForReadingArrayData = GiftiArrayIndexingOrderEnum::fromGiftiName( subscriptOrderString, &validArraySubscriptingOrder); if (validArraySubscriptingOrder == false) { throw XmlSaxParserException("Attribute " + GiftiXmlElements::ATTRIBUTE_DATA_ARRAY_INDEXING_ORDER + "is invalid: " + subscriptOrderString); } this->dataArray.grabNew(new GiftiDataArray(intent)); /* * Indicate that data has not been read. */ dataArrayDataHasBeenRead = false; } /** * process the array data into numbers. */ void GiftiFileSaxReader::processArrayData() { this->dataArrayDataHasBeenRead = true; CaretAssert(dataArray); try { dataArray->readFromText(elementText, this->endianForReadingArrayData, arraySubscriptingOrderForReadingArrayData, dataTypeForReadingArrayData, dimensionsForReadingArrayData, encodingForReadingArrayData, externalFileNameForReadingData, externalFileOffsetForReadingData, this->giftiFile->getReadMetaDataOnlyFlag()); } catch (const GiftiException& e) { throw XmlSaxParserException(e.whatString()); } } /** * get characters in an element. */ void GiftiFileSaxReader::characters(const char* ch) { if (this->metaDataSaxReader != NULL) { this->metaDataSaxReader->characters(ch); } else if (this->labelTableSaxReader != NULL) { this->labelTableSaxReader->characters(ch); } else { elementText += ch; } } /** * a fatal error occurs. */ void GiftiFileSaxReader::fatalError(const XmlSaxParserException& e) { /* std::ostringstream str; str << "Fatal Error at line number: " << e.getLineNumber() << "\n" << "Column number: " << e.getColumnNumber() << "\n" << "Message: " << e.whatString(); if (errorMessage.isEmpty() == false) { str << "\n" << errorMessage; } errorMessage = str.str(); */ // // Stop parsing // throw e; } // a warning occurs void GiftiFileSaxReader::warning(const XmlSaxParserException& e) { CaretLogWarning("XML Parser Warning: " + e.whatString()); } // an error occurs void GiftiFileSaxReader::error(const XmlSaxParserException& e) { CaretLogSevere("XML Parser Error: " + e.whatString()); throw e; } void GiftiFileSaxReader::startDocument() { } void GiftiFileSaxReader::endDocument() { } connectome-workbench-1.4.2/src/Gifti/GiftiFileSaxReader.h000066400000000000000000000124131360521144700232770ustar00rootroot00000000000000 #ifndef __GIFTI_FILE_SAX_READER_H__ #define __GIFTI_FILE_SAX_READER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "CaretPointer.h" #include "GiftiArrayIndexingOrderEnum.h" #include "GiftiEndianEnum.h" #include "GiftiEncodingEnum.h" #include "NiftiEnums.h" #include "XmlSaxParserException.h" #include "XmlSaxParserHandlerInterface.h" namespace caret { class GiftiDataArray; class GiftiFile; class GiftiLabelTableSaxReader; class GiftiMetaDataSaxReader; class GiftiFile; class Matrix4x4; class XmlAttributes; class XmlException; /// class for reading a GIFTI Node Data File with a SAX Parser class GiftiFileSaxReader : public CaretObject, public XmlSaxParserHandlerInterface { public: GiftiFileSaxReader(GiftiFile* giftiFileIn); virtual ~GiftiFileSaxReader(); void startElement(const AString& namespaceURI, const AString& localName, const AString& qName, const XmlAttributes& attributes); void endElement(const AString& namspaceURI, const AString& localName, const AString& qName); void characters(const char* ch); void fatalError(const XmlSaxParserException& e); void warning(const XmlSaxParserException& e); void error(const XmlSaxParserException& e); void startDocument(); void endDocument(); protected: /// file reading states enum STATE { /// no state STATE_NONE, /// processing GIFTI tag STATE_GIFTI, /// processing MetaData tag STATE_METADATA, /// processing LabelTable tag STATE_LABEL_TABLE, /// processing DataArray tag STATE_DATA_ARRAY, /// processing DataArray Data tag STATE_DATA_ARRAY_DATA, /// processing DataArray Matrix Tag STATE_DATA_ARRAY_MATRIX, /// processing DataArray Matrix Data Space Tag STATE_DATA_ARRAY_MATRIX_DATA_SPACE, /// processing DataArray Matrix Transformed Space Tag STATE_DATA_ARRAY_MATRIX_TRANSFORMED_SPACE, /// processing DataArray Matrix Data Tag STATE_DATA_ARRAY_MATRIX_DATA }; // process the array data into numbers void processArrayData(); // create a data array void createDataArray(const XmlAttributes& attributes); /// file reading state STATE state; /// the state stack used when reading a file std::stack stateStack; /// the error message AString errorMessage; /// GIFTI file that is being read GiftiFile* giftiFile; /// element text AString elementText; /// GIFTI data array being read CaretPointer dataArray; /// GIFTI label table being read GiftiLabelTable* labelTable; /// GIFTI label table sax reader GiftiLabelTableSaxReader* labelTableSaxReader; /// GIFTI meta data sax reader GiftiMetaDataSaxReader* metaDataSaxReader; /// GIFTI matrix data being read Matrix4x4* matrix; /// endian attribute data GiftiEndianEnum::Enum endianForReadingArrayData; /// array subscripting order for reading GiftiArrayIndexingOrderEnum::Enum arraySubscriptingOrderForReadingArrayData; /// data type for reading NiftiDataTypeEnum::Enum dataTypeForReadingArrayData; /// dimension for reading std::vector dimensionsForReadingArrayData; /// encoding for reading GiftiEncodingEnum::Enum encodingForReadingArrayData; /// data location for reading //GiftiDataArray::DATA_LOCATION dataLocationForReadingArrayData; /// external file name AString externalFileNameForReadingData; /// external file offset int64_t externalFileOffsetForReadingData; /// tracks if data has been read since external binary may not have DATA tag bool dataArrayDataHasBeenRead; }; } // namespace #endif // __GIFTI_FILE_SAX_READER_H__ connectome-workbench-1.4.2/src/Gifti/GiftiFileWriter.cxx000066400000000000000000000274321360521144700232570ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __GIFTI_FILE_WRITER_DECLARE__ #include "GiftiFileWriter.h" #undef __GIFTI_FILE_WRITER_DECLARE__ #include "FileInformation.h" #include "GiftiDataArray.h" #include "GiftiXmlElements.h" #include "XmlWriter.h" using namespace caret; /** * \class GiftiFileWriter * \brief Writes GIFTI files. * * Writes a GIFTI data array file. In most cases, using the * GiftiDataArrayFile's writeFile() method should be used for writing a file. * This class can be used to incrementally write a file. After constructing * an object of this class, call start(), call writeDataArray() for each * data array, and lastly call finish(). */ /** * Constructor. * * @param filename - name of the file. * @param encoding - encoding of the file. */ GiftiFileWriter::GiftiFileWriter(const AString& filename, const GiftiEncodingEnum::Enum encoding) : CaretObject() { this->xmlFileOutputStream = NULL; this->externalFileOutputStream = NULL; this->maximumExternalFileSize = 1024 * 1024 * 1024; this->filename = filename; this->encoding = encoding; this->xmlWriter = NULL; this->dataArraysWrittenCounter = 0; } /** * Destructor. */ GiftiFileWriter::~GiftiFileWriter() { this->closeFiles(); if (this->xmlWriter != NULL) { delete this->xmlWriter; this->xmlWriter = NULL; } } /** * Start writing the file. * * @param numberOfDataArrays - The number of data arrays that for file * that is being written. * @param metadata - The file's metadata or null if no metadata. * @param labelTable - The file's label table or null if no labels. * @throws GiftiException - If an error occurs. */ void GiftiFileWriter::start(const int numberOfDataArrays, GiftiMetaData* metadata, GiftiLabelTable* labelTable) { this->numberOfDataArrays = numberOfDataArrays; // // Does the file need to be opened? // if (this->xmlFileOutputStream == NULL) { // // Open the file // char* name = this->filename.toCharArray(); this->xmlFileOutputStream = new std::ofstream(name); delete[] name; if (! this->xmlFileOutputStream->good()) { delete this->xmlFileOutputStream; this->xmlFileOutputStream = NULL; AString msg = "Unable to open " + this->filename + " for writing."; throw GiftiException(msg); } // // Remove any existing external files. // this->removeExternalFiles(); } try { // // Format the version string so that it ends with at most one zero // const AString versionString = AString::number(GiftiFile::getCurrentFileVersion()); // // Create the xml writer // this->xmlWriter = new XmlWriter(*this->xmlFileOutputStream); // // Write header info // this->xmlWriter->writeStartDocument("1.0"); //this->xmlWriter.writeDTD(GiftiXmlElements.TAG_GIFTI, // "http://www.nitrc.org/frs/download.php/115/gifti.dtd"); // // Write GIFTI root element // XmlAttributes attributes; attributes.addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); attributes.addAttribute("xsi:noNamespaceSchemaLocation", "http://brainvis.wustl.edu/caret6/xml_schemas/GIFTI_Caret.xsd"); attributes.addAttribute(GiftiXmlElements::ATTRIBUTE_GIFTI_VERSION, versionString); attributes.addAttribute(GiftiXmlElements::ATTRIBUTE_GIFTI_NUMBER_OF_DATA_ARRAYS, this->numberOfDataArrays); this->xmlWriter->writeStartElement(GiftiXmlElements::TAG_GIFTI, attributes); // // Write Metadata // if (metadata != NULL) { metadata->writeAsXML(*this->xmlWriter); } // // Write Labels // if (labelTable != NULL) { labelTable->writeAsXML(*this->xmlWriter); } } catch (const GiftiException& e) { this->closeFiles(); throw e; } } /** * Write a GIFTI Data Array. * * @param gda - The data array. * @throws GiftiException - If an error occurs. */ void GiftiFileWriter::writeDataArray(GiftiDataArray* gda) { this->verifyOpened(); if (this->dataArraysWrittenCounter >= this->numberOfDataArrays) { this->closeFiles(); throw GiftiException("PROGRAMMER ERROR: the number of data arrays " "written exceeds the number of data arrays in the file " "passed to start."); } try { // // // // Get the external file name. // // // String externalFileName = ""; // if (this.encoding == GiftiEncoding.EXTERNAL_FILE_BINARY) { // externalFileName = this.getExternalFileNameForWriting(); // } // // Writing to an external binary data file? // if (this->encoding == GiftiEncodingEnum::EXTERNAL_FILE_BINARY) { if (this->externalFileOutputStream == NULL) { char* name = this->getExternalFileNameForWriting().toCharArray(); this->externalFileOutputStream = new std::ofstream(name,std::fstream::binary); delete[] name; if (! *this->externalFileOutputStream) { this->closeFiles(); const AString msg = ("Unable to open " + this->getExternalFileNameForWriting() + " for writing."); throw GiftiException(msg); } } const int64_t fileOffset = this->externalFileOutputStream->tellp(); FileInformation myInfo(this->getExternalFileNameForWriting());//TODO: get filename only without doing a stat? gda->setExternalFileInformation(myInfo.getFileName(), fileOffset); } // // Write data array // gda->writeAsXML(*this->xmlFileOutputStream, this->externalFileOutputStream, this->encoding); // // Increment counter of data arrays written // this->dataArraysWrittenCounter++; } catch (const GiftiException& e) { this->closeFiles(); throw e; } catch (const XmlException& e) { this->closeFiles(); throw GiftiException(e); } } /** * Finish writing the file. Closes any open files. * @throws GiftiException If file error or number of data arrays written * does not match number of data arrays passed to start() method. */ void GiftiFileWriter::finish() { this->verifyOpened(); try { // // Write GIFTI root end element // this->xmlWriter->writeEndElement(); this->xmlWriter->writeEndDocument(); } catch (const XmlException& e) { this->closeFiles(); throw GiftiException(e); } // // Close the file // this->closeFiles(); } /** * Get the maximum external file size. * * @return The size. */ long GiftiFileWriter::getMaximumExternalFileSize() const { return this->maximumExternalFileSize; } /** * Set the maximum external file size. Starts a new external file when * this size is reached or exceeded. * * @param size Desired maximum size. */ void GiftiFileWriter::setMaximumExternalFileSize(const long size) { this->maximumExternalFileSize = size; } /** * Close any open files. */ void GiftiFileWriter::closeFiles() { if (this->xmlFileOutputStream != NULL) { if (this->xmlFileOutputStream->is_open()) { this->xmlFileOutputStream->close(); } delete this->xmlFileOutputStream; this->xmlFileOutputStream = NULL; } if (this->externalFileOutputStream != NULL) { if (this->externalFileOutputStream->is_open()) { this->externalFileOutputStream->close(); } delete this->externalFileOutputStream; this->externalFileOutputStream = NULL; } } /** * Verify the file is properly opened. * * @throws GiftiException If file was not opened properly. */ void GiftiFileWriter::verifyOpened() { if (this->xmlWriter == NULL) { throw GiftiException("Trying to write to file named \"" + this->filename + "\" but the file was not properly opened " "by calling start() or opening the file " "failed."); } } /** * Remove any existing external data files. * * @throws GiftiException - If unable to delete a file. */ void GiftiFileWriter::removeExternalFiles() { int maxFiles = 50; // more than enough for (int counter = -1; counter <= maxFiles; counter++) { AString name = this->getExternalFileNamePrefix() + AString::number(counter); if (counter < 0) { name = this->getExternalFileNamePrefix(); // old version of ext file } FileInformation fileInfo(name); if (fileInfo.exists()) { if (fileInfo.remove() == false) { throw GiftiException("Unable to delete an existing external " " file named \"" + name + "\"."); } } } } /** * Get the name of the external file prefix. * * @return The XML file name + ".data" */ AString GiftiFileWriter::getExternalFileNamePrefix() const { return this->filename + ".data"; } /** * Get the name of the external file that should be used for writing. * * @return Name of external file. */ AString GiftiFileWriter::getExternalFileNameForWriting() const { return this->getExternalFileNamePrefix(); // COULD use multiple files for external data when large. // boolean done = false; // int counter = 1; // String name = this.getExternalFileNamePrefix() + counter; // while (done == false) { // File file = new File(name); // if (file.exists()) { // if (file.length() > this.maximumExternalFileSize) { // counter++; // name = this.getExternalFileNamePrefix() + counter; // } // else { // done = true; // } // } // else { // done = true; // } // } // // return name; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString GiftiFileWriter::toString() const { return "GiftiFileWriter"; } connectome-workbench-1.4.2/src/Gifti/GiftiFileWriter.h000066400000000000000000000061571360521144700227050ustar00rootroot00000000000000#ifndef __GIFTI_FILE_WRITER__H_ #define __GIFTI_FILE_WRITER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "GiftiFile.h" #include "GiftiEncodingEnum.h" namespace caret { class GiftiDataArray; class GiftiMetaData; class GiftiLabelTable; class XmlWriter; class GiftiFileWriter : public CaretObject { public: GiftiFileWriter(const AString& filename, const GiftiEncodingEnum::Enum encoding); virtual ~GiftiFileWriter(); void start(const int numberOfDataArrays, GiftiMetaData* metadata, GiftiLabelTable* labelTable); void writeDataArray(GiftiDataArray* gda); void finish(); long getMaximumExternalFileSize() const; void setMaximumExternalFileSize(const long size); private: GiftiFileWriter(const GiftiFileWriter&); GiftiFileWriter& operator=(const GiftiFileWriter&); void closeFiles(); void verifyOpened(); void removeExternalFiles(); AString getExternalFileNamePrefix() const; AString getExternalFileNameForWriting() const; public: virtual AString toString() const; private: /** The file output stream for the XML file. */ std::ofstream* xmlFileOutputStream; /** The file output stream for the external data file. */ std::ofstream* externalFileOutputStream; /** The number of data arrays in the file being written. */ int numberOfDataArrays; /** Start a new external file when the external file reaches this size. */ long maximumExternalFileSize; /** name of file to write. */ AString filename; /** encoding of file. */ GiftiEncodingEnum::Enum encoding; /** The XML writer. */ XmlWriter* xmlWriter; /** Counts the number of data arrays that have been written. */ int dataArraysWrittenCounter; }; #ifdef __GIFTI_FILE_WRITER_DECLARE__ // #endif // __GIFTI_FILE_WRITER_DECLARE__ } // namespace #endif //__GIFTI_FILE_WRITER__H_ connectome-workbench-1.4.2/src/Gifti/GiftiLabelTableSaxReader.cxx000066400000000000000000000200151360521144700247570ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretLogger.h" #include "GiftiEndianEnum.h" #include "GiftiLabel.h" #include "GiftiFile.h" #include "GiftiLabelTableSaxReader.h" #include "GiftiXmlElements.h" #include "NiftiEnums.h" #include "XmlAttributes.h" #include "XmlException.h" using namespace caret; /** * constructor. */ GiftiLabelTableSaxReader::GiftiLabelTableSaxReader(GiftiLabelTable* labelTable) { this->state = STATE_NONE; this->stateStack.push(state); this->elementText = ""; this->labelTable = labelTable; m_haveUnlabeled = false; } /** * destructor. */ GiftiLabelTableSaxReader::~GiftiLabelTableSaxReader() { } /** * start an element. */ void GiftiLabelTableSaxReader::startElement(const AString& /* namespaceURI */, const AString& /* localName */, const AString& qName, const XmlAttributes& attributes) { const STATE previousState = this->state; switch (this->state) { case STATE_NONE: if (qName == GiftiXmlElements::TAG_LABEL_TABLE) { this->state = STATE_LABEL_TABLE; } else { std::ostringstream str; str << "Root element is \"" << qName.toStdString() << "\" but should be " << GiftiXmlElements::TAG_LABEL_TABLE.toStdString(); throw XmlSaxParserException(AString::fromStdString(str.str())); } break; case STATE_LABEL_TABLE: if (qName == GiftiXmlElements::TAG_LABEL) { this->state = STATE_LABEL_TABLE_LABEL; AString s = attributes.getValue(GiftiXmlElements::ATTRIBUTE_LABEL_KEY); if (s == "") { s = attributes.getValue("Index"); } if (s.isEmpty()) { std::ostringstream str; str << "Tag " << GiftiXmlElements::TAG_LABEL.toStdString() << " is missing its " << GiftiXmlElements::ATTRIBUTE_LABEL_KEY.toStdString(); throw XmlSaxParserException(AString::fromStdString(str.str())); } this->labelIndex = s.toInt(); float defaultRGBA[4]; GiftiLabel::getDefaultColor(defaultRGBA); this->labelRed = defaultRGBA[0]; this->labelGreen = defaultRGBA[1]; this->labelBlue = defaultRGBA[2]; this->labelAlpha = defaultRGBA[3]; const AString redString = attributes.getValue(GiftiXmlElements::ATTRIBUTE_LABEL_RED); if (redString.isEmpty() == false) { this->labelRed = redString.toFloat(); } const AString greenString = attributes.getValue(GiftiXmlElements::ATTRIBUTE_LABEL_GREEN); if (greenString.isEmpty() == false) { this->labelGreen = greenString.toFloat(); } const AString blueString = attributes.getValue(GiftiXmlElements::ATTRIBUTE_LABEL_BLUE); if (blueString.isEmpty() == false) { this->labelBlue = blueString.toFloat(); } const AString alphaString = attributes.getValue(GiftiXmlElements::ATTRIBUTE_LABEL_ALPHA); if (alphaString.isEmpty() == false) { this->labelAlpha = alphaString.toFloat(); } this->labelX = attributes.getValueAsFloat(GiftiXmlElements::ATTRIBUTE_LABEL_X); this->labelY = attributes.getValueAsFloat(GiftiXmlElements::ATTRIBUTE_LABEL_Y); this->labelZ = attributes.getValueAsFloat(GiftiXmlElements::ATTRIBUTE_LABEL_Z); } else { std::ostringstream str; str << "Child of " << GiftiXmlElements::TAG_LABEL_TABLE.toStdString() << " is \"" << qName.toStdString() << "\" but should be " << GiftiXmlElements::TAG_LABEL.toStdString(); throw XmlSaxParserException(AString::fromStdString(str.str())); } break; case STATE_LABEL_TABLE_LABEL: { std::ostringstream str; str << GiftiXmlElements::TAG_LABEL.toStdString() << " has child \"" << qName.toStdString() << "\" but should not have any child nodes"; throw XmlSaxParserException(AString::fromStdString(str.str())); } break; } // // Save previous state // this->stateStack.push(previousState); this->elementText = ""; } /** * end an element. */ void GiftiLabelTableSaxReader::endElement(const AString& /* namspaceURI */, const AString& /* localName */, const AString& /*qName*/) { switch (state) { case STATE_NONE: break; case STATE_LABEL_TABLE: break; case STATE_LABEL_TABLE_LABEL: if ((elementText == "unknown" || elementText == "Unknown") && labelAlpha == 0.0f) { if (!m_haveUnlabeled)//if we already have an unlabeled key, don't change things, and warn { m_haveUnlabeled = true; CaretLogFiner("Using '" + elementText + "' label as unlabeled key"); elementText = "???";//pretend these strings are actually "???" when alpha is 0, as that means it is unlabeled } else { CaretLogWarning("found multiple label elements that should be interpreted as unlabeled"); } } else if (elementText == "???") { if (m_haveUnlabeled) { CaretLogWarning("found multiple label elements that should be interpreted as unlabeled"); } m_haveUnlabeled = true;//that identifier always means unlabeled to us, don't let it slip by without setting m_haveUnlabeled } this->labelTable->setLabel(this->labelIndex, this->elementText, this->labelRed, this->labelGreen, this->labelBlue, this->labelAlpha, this->labelX, this->labelY, this->labelZ); break; } // // Clear out for new elements // this->elementText = ""; // // Go to previous state // if (this->stateStack.empty()) { throw XmlSaxParserException("State stack is empty while reading GiftiLabelTable."); } this->state = stateStack.top(); this->stateStack.pop(); } /** * get characters in an element. */ void GiftiLabelTableSaxReader::characters(const char* ch) { this->elementText += ch; } /** * a fatal error occurs. */ void GiftiLabelTableSaxReader::fatalError(const XmlSaxParserException& e) { throw e; } /** * A warning occurs */ void GiftiLabelTableSaxReader::warning(const XmlSaxParserException& e) { CaretLogWarning("XML Parser Warning: " + e.whatString()); } // an error occurs void GiftiLabelTableSaxReader::error(const XmlSaxParserException& e) { throw e; } void GiftiLabelTableSaxReader::startDocument() { } void GiftiLabelTableSaxReader::endDocument() { } connectome-workbench-1.4.2/src/Gifti/GiftiLabelTableSaxReader.h000066400000000000000000000070031360521144700244060ustar00rootroot00000000000000 #ifndef __GIFTI_LABEL_TABLE_SAX_READER_H__ #define __GIFTI_LABEL_TABLE_SAX_READER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "XmlSaxParserException.h" #include "XmlSaxParserHandlerInterface.h" namespace caret { class GiftiLabelTable; class XmlAttributes; /** * class for reading a GiftiLabelTable with a SAX Parser */ class GiftiLabelTableSaxReader : public CaretObject, public XmlSaxParserHandlerInterface { public: GiftiLabelTableSaxReader(GiftiLabelTable* labelTable); virtual ~GiftiLabelTableSaxReader(); void startElement(const AString& namespaceURI, const AString& localName, const AString& qName, const XmlAttributes& attributes); void endElement(const AString& namspaceURI, const AString& localName, const AString& qName); void characters(const char* ch); void fatalError(const XmlSaxParserException& e); void warning(const XmlSaxParserException& e); void error(const XmlSaxParserException& e); void startDocument(); void endDocument(); protected: /// file reading states enum STATE { /// no state STATE_NONE, /// processing LabelTable tag STATE_LABEL_TABLE, /// processing LabelTable Label STATE_LABEL_TABLE_LABEL }; /// file reading state STATE state; /// the state stack used when reading a file std::stack stateStack; /// the error message AString errorMessage; /// element text AString elementText; /// GIFTI label table being read GiftiLabelTable* labelTable; /// label index int labelIndex; /// label color component float labelRed; /// label color component float labelGreen; /// label color component float labelBlue; /// label color component float labelAlpha; /// label's X-coordinate float labelX; /// label's Y-coordinate float labelY; /// label's Z-coordinate float labelZ; /// tracks whether we have read an "unused" label, because the GiftiLabelTable constructor and clear() add "???" whether we want it or not bool m_haveUnlabeled; }; } // namespace #endif // __GIFTI_LABEL_TABLE_SAX_READER_H__ connectome-workbench-1.4.2/src/Gifti/GiftiMetaDataSaxReader.cxx000066400000000000000000000144641360521144700244630ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretLogger.h" #include "GiftiMetaData.h" #include "GiftiMetaDataSaxReader.h" #include "GiftiXmlElements.h" #include "XmlAttributes.h" #include "XmlException.h" using namespace caret; /** * constructor. */ GiftiMetaDataSaxReader::GiftiMetaDataSaxReader(GiftiMetaData* metaData) { this->state = STATE_NONE; this->stateStack.push(this->state); this->metaDataName = ""; this->metaDataValue = ""; this->elementText = ""; this->metaData = metaData; } /** * destructor. */ GiftiMetaDataSaxReader::~GiftiMetaDataSaxReader() { } /** * start an element. */ void GiftiMetaDataSaxReader::startElement(const AString& /* namespaceURI */, const AString& /* localName */, const AString& qName, const XmlAttributes& /*attributes*/) { const STATE previousState = this->state; switch (this->state) { case STATE_NONE: if (qName == GiftiXmlElements::TAG_METADATA) { this->state = STATE_METADATA; } else { std::ostringstream str; str << "Root element is \"" << qName.toStdString() << "\" but should be " << GiftiXmlElements::TAG_METADATA.toStdString(); throw XmlSaxParserException(AString::fromStdString(str.str())); } break; case STATE_METADATA: if (qName == GiftiXmlElements::TAG_METADATA_ENTRY) { this->state = STATE_METADATA_MD; } else { std::ostringstream str; str << "Child of " << GiftiXmlElements::TAG_METADATA.toStdString() << " is \"" << qName.toStdString() << "\" but should be " << GiftiXmlElements::TAG_METADATA_ENTRY.toStdString(); throw XmlSaxParserException(AString::fromStdString(str.str())); } break; case STATE_METADATA_MD: if (qName == GiftiXmlElements::TAG_METADATA_NAME) { this->state = STATE_METADATA_MD_NAME; } else if (qName == GiftiXmlElements::TAG_METADATA_VALUE) { this->state = STATE_METADATA_MD_VALUE; } else { std::ostringstream str; str << "Child of " << GiftiXmlElements::TAG_METADATA_ENTRY.toStdString() << " is \"" << qName.toStdString() << "\" but should be one of \n" << " " << GiftiXmlElements::TAG_METADATA_NAME.toStdString() << "\n" << " " << GiftiXmlElements::TAG_METADATA_VALUE.toStdString(); throw XmlSaxParserException(AString::fromStdString(str.str())); } break; case STATE_METADATA_MD_NAME: { std::ostringstream str; str << GiftiXmlElements::TAG_METADATA_NAME.toStdString() << " has child \"" << qName.toStdString() << "\" but should not have any child nodes"; throw XmlSaxParserException(AString::fromStdString(str.str())); } break; case STATE_METADATA_MD_VALUE: { std::ostringstream str; str << GiftiXmlElements::TAG_METADATA_VALUE.toStdString() << " has child \"" << qName.toStdString() << "\" but should not have any child nodes"; throw XmlSaxParserException(AString::fromStdString(str.str())); } break; } // // Save previous state // this->stateStack.push(previousState); this->elementText = ""; } /** * end an element. */ void GiftiMetaDataSaxReader::endElement(const AString& /* namspaceURI */, const AString& /* localName */, const AString& /*qName*/) { switch (state) { case STATE_NONE: break; case STATE_METADATA: break; case STATE_METADATA_MD: if ((this->metaDataName.isEmpty() == false) && (this->metaDataValue.isEmpty() == false)) { if (this->metaData != NULL) { this->metaData->set(metaDataName, metaDataValue); } else { throw XmlSaxParserException("ERROR: Have metadata name/value but no MetaDeta."); } this->metaDataName = ""; this->metaDataValue = ""; } break; case STATE_METADATA_MD_NAME: this->metaDataName = elementText; break; case STATE_METADATA_MD_VALUE: this->metaDataValue = elementText; break; } // // Clear out for new elements // this->elementText = ""; // // Go to previous state // if (this->stateStack.empty()) { throw XmlSaxParserException("State stack is empty while reading XML MetaData."); } this->state = this->stateStack.top(); this->stateStack.pop(); } /** * get characters in an element. */ void GiftiMetaDataSaxReader::characters(const char* ch) { this->elementText += ch; } /** * a fatal error occurs. */ void GiftiMetaDataSaxReader::fatalError(const XmlSaxParserException& e) { // // Stop parsing // CaretLogSevere("XML Parser Fatal Error: " + e.whatString()); throw e; } // a warning occurs void GiftiMetaDataSaxReader::warning(const XmlSaxParserException& e) { CaretLogWarning("XML Parser Warning: " + e.whatString()); } // an error occurs void GiftiMetaDataSaxReader::error(const XmlSaxParserException& e) { throw e; } void GiftiMetaDataSaxReader::startDocument() { } void GiftiMetaDataSaxReader::endDocument() { } connectome-workbench-1.4.2/src/Gifti/GiftiMetaDataSaxReader.h000066400000000000000000000064031360521144700241020ustar00rootroot00000000000000 #ifndef __GIFTI_META_DATA_SAX_READER_H__ #define __GIFTI_META_DATA_SAX_READER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "XmlSaxParserException.h" #include "XmlSaxParserHandlerInterface.h" namespace caret { class GiftiMetaData; class XmlAttributes; /** * class for reading Gifti Metadata with a SAX Parser */ class GiftiMetaDataSaxReader : public CaretObject, public XmlSaxParserHandlerInterface { public: GiftiMetaDataSaxReader(GiftiMetaData* metaData); virtual ~GiftiMetaDataSaxReader(); void startElement(const AString& namespaceURI, const AString& localName, const AString& qName, const XmlAttributes& attributes); void endElement(const AString& namspaceURI, const AString& localName, const AString& qName); void characters(const char* ch); void fatalError(const XmlSaxParserException& e); void warning(const XmlSaxParserException& e); void error(const XmlSaxParserException& e); void startDocument(); void endDocument(); private: GiftiMetaDataSaxReader(const GiftiMetaDataSaxReader&); GiftiMetaDataSaxReader& operator=(const GiftiMetaDataSaxReader&); protected: /// file reading states enum STATE { /// no state STATE_NONE, /// processing MetaData tag STATE_METADATA, /// processing MetaData MD child tag STATE_METADATA_MD, /// processing MetaData MD Name tag STATE_METADATA_MD_NAME, /// processing MetaData MD Value tag STATE_METADATA_MD_VALUE }; /// file reading state STATE state; /// the state stack used when reading a file std::stack stateStack; /// the error message AString errorMessage; /// meta data name AString metaDataName; /// meta data value AString metaDataValue; /// element text AString elementText; /// GIFTI meta data being read GiftiMetaData* metaData; }; } // namespace #endif // __GIFTI_META_DATA_SAX_READER_H__ connectome-workbench-1.4.2/src/Graphics/000077500000000000000000000000001360521144700201625ustar00rootroot00000000000000connectome-workbench-1.4.2/src/Graphics/CMakeLists.txt000066400000000000000000000027211360521144700227240ustar00rootroot00000000000000# # Name of Project # PROJECT (Graphics) # # Create a Library # ADD_LIBRARY(Graphics CaretOpenGLInclude.h EventGraphicsOpenGLCreateBufferObject.h EventGraphicsOpenGLCreateTextureName.h EventGraphicsOpenGLDeleteBufferObject.h EventGraphicsOpenGLDeleteTextureName.h EventOpenGLObjectToWindowTransform.h GraphicsEngineData.h GraphicsEngineDataOpenGL.h GraphicsOpenGLBufferObject.h GraphicsOpenGLError.h GraphicsOpenGLPolylineTriangles.h GraphicsOpenGLTextureName.h GraphicsPrimitive.h GraphicsPrimitiveSelectionHelper.h GraphicsPrimitiveV3f.h GraphicsPrimitiveV3fC4f.h GraphicsPrimitiveV3fC4ub.h GraphicsPrimitiveV3fN3f.h GraphicsPrimitiveV3fT3f.h GraphicsShape.h GraphicsUtilitiesOpenGL.h EventGraphicsOpenGLCreateBufferObject.cxx EventGraphicsOpenGLCreateTextureName.cxx EventGraphicsOpenGLDeleteBufferObject.cxx EventGraphicsOpenGLDeleteTextureName.cxx EventOpenGLObjectToWindowTransform.cxx GraphicsEngineData.cxx GraphicsEngineDataOpenGL.cxx GraphicsOpenGLBufferObject.cxx GraphicsOpenGLError.cxx GraphicsOpenGLPolylineTriangles.cxx GraphicsOpenGLTextureName.cxx GraphicsPrimitive.cxx GraphicsPrimitiveSelectionHelper.cxx GraphicsPrimitiveV3f.cxx GraphicsPrimitiveV3fC4f.cxx GraphicsPrimitiveV3fC4ub.cxx GraphicsPrimitiveV3fN3f.cxx GraphicsPrimitiveV3fT3f.cxx GraphicsShape.cxx GraphicsUtilitiesOpenGL.cxx ) # # Find headers # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Common ${CMAKE_SOURCE_DIR}/Graphics ${CMAKE_SOURCE_DIR}/Nifti ) TARGET_LINK_LIBRARIES(Graphics ${CARET_QT5_LINK}) connectome-workbench-1.4.2/src/Graphics/CaretOpenGLInclude.h000066400000000000000000000035711360521144700237500ustar00rootroot00000000000000#ifndef __CARET_OPEN_GL_INCLUDE_H__ #define __CARET_OPEN_GL_INCLUDE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /** * \file CaretOpenGLInclude.h * \brief Contains OpenGL include declarations that work for all operating systems. * \ingroup Common */ /* * When using GLEW, GL/glew.h MUST be included before Gl/gl.h. * Note: Windows.h includes Gl/gl.h. * * Must define GLEW_STATIC when GLEW is in a static library * or linking errors will occur with GLEW functions */ #ifdef HAVE_GLEW #ifdef HAVE_GLEW_STATIC_LIB #define GLEW_STATIC #endif #include #endif #ifdef CARET_OS_WINDOWS #include #endif #ifdef CARET_OS_MACOSX #include #include #else #ifndef HAVE_GLEW #ifdef CARET_OS_LINUX /* * On linux, adds support for newer OpenGL * as described at https://www.khronos.org/registry/OpenGL/ABI/ */ #define GL_GLEXT_PROTOTYPES #endif #endif #include #include #endif #endif //__CARET_OPEN_GL_INCLUDE_H__ connectome-workbench-1.4.2/src/Graphics/EventGraphicsOpenGLCreateBufferObject.cxx000066400000000000000000000063431360521144700301300ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_GRAPHICS_OPEN_G_L_CREATE_BUFFER_OBJECT_DECLARE__ #include "EventGraphicsOpenGLCreateBufferObject.h" #undef __EVENT_GRAPHICS_OPEN_G_L_CREATE_BUFFER_OBJECT_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "EventGraphicsOpenGLDeleteBufferObject.h" #include "EventManager.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventGraphicsOpenGLCreateBufferObject * \brief Create an OpenGL Buffer Object * \ingroup Graphics * * Creates an OpenGL Buffer Object for the current context. * There MUST BE an active OpenGL context when this event * is processed. Otherwise, a buffer object cannot be * created and a program failure will likely occur. */ /** * Constructor. */ EventGraphicsOpenGLCreateBufferObject::EventGraphicsOpenGLCreateBufferObject() : Event(EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_BUFFER_OBJECT) { } /** * Destructor. */ EventGraphicsOpenGLCreateBufferObject::~EventGraphicsOpenGLCreateBufferObject() { if (m_openglBufferObject != NULL) { /* * If the caller did not get the buffer object we need to delete it. */ CaretLogSevere("Create OpenGL Buffer Object Event never had buffer object retrieved. Will attempt to delete it."); EventGraphicsOpenGLDeleteBufferObject deleteEvent(m_openglBufferObject); EventManager::get()->sendEvent(deleteEvent.getPointer()); } } /** * Set the OpenGL Buffer Object. * * @param openglBufferObject * The OpenGL Buffer Object. This instance will take ownership of the buffer so the caller * MUST NOT ever reference the buffer object after calling this method. */ void EventGraphicsOpenGLCreateBufferObject::setOpenGLBufferObject(GraphicsOpenGLBufferObject* openglBufferObject) { m_openglBufferObject = openglBufferObject; } /** * @return OpenGL Buffer Object that was created or NULL if * unable to create buffer object due to no valid context. * Caller takes ownership of the buffer object. If this method * is called more than once for an instance, NULL will be * returned the second and all subsequent times. */ GraphicsOpenGLBufferObject* EventGraphicsOpenGLCreateBufferObject::getOpenGLBufferObject() const { /* * Do not let buffer object be retrieved more than once. */ GraphicsOpenGLBufferObject* bufferObjectPointer = m_openglBufferObject; m_openglBufferObject = NULL; return bufferObjectPointer; } connectome-workbench-1.4.2/src/Graphics/EventGraphicsOpenGLCreateBufferObject.h000066400000000000000000000041041360521144700275460ustar00rootroot00000000000000#ifndef __EVENT_GRAPHICS_OPEN_G_L_CREATE_BUFFER_OBJECT_H__ #define __EVENT_GRAPHICS_OPEN_G_L_CREATE_BUFFER_OBJECT_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class GraphicsOpenGLBufferObject; class EventGraphicsOpenGLCreateBufferObject : public Event { public: EventGraphicsOpenGLCreateBufferObject(); virtual ~EventGraphicsOpenGLCreateBufferObject(); void setOpenGLBufferObject(GraphicsOpenGLBufferObject* openglBufferObject); GraphicsOpenGLBufferObject* getOpenGLBufferObject() const; // ADD_NEW_METHODS_HERE private: EventGraphicsOpenGLCreateBufferObject(const EventGraphicsOpenGLCreateBufferObject&); EventGraphicsOpenGLCreateBufferObject& operator=(const EventGraphicsOpenGLCreateBufferObject&); mutable GraphicsOpenGLBufferObject* m_openglBufferObject = NULL; mutable bool m_openglBufferObjectWasTakenFlag = false; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_GRAPHICS_OPEN_G_L_CREATE_BUFFER_OBJECT_DECLARE__ // #endif // __EVENT_GRAPHICS_OPEN_G_L_CREATE_BUFFER_OBJECT_DECLARE__ } // namespace #endif //__EVENT_GRAPHICS_OPEN_G_L_CREATE_BUFFER_OBJECT_H__ connectome-workbench-1.4.2/src/Graphics/EventGraphicsOpenGLCreateTextureName.cxx000066400000000000000000000062711360521144700300310ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_GRAPHICS_OPEN_G_L_CREATE_TEXTURE_NAME_DECLARE__ #include "EventGraphicsOpenGLCreateTextureName.h" #undef __EVENT_GRAPHICS_OPEN_G_L_CREATE_TEXTURE_NAME_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "EventGraphicsOpenGLDeleteTextureName.h" #include "EventManager.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventGraphicsOpenGLCreateTextureName * \brief Create an OpenGL Texture Name * \ingroup Graphics * * Creates an OpenGL Texture Name for the current context. * There MUST BE an active OpenGL context when this event * is processed. Otherwise, a texture name cannot be * created and a program failure will likely occur. */ /** * Constructor. */ EventGraphicsOpenGLCreateTextureName::EventGraphicsOpenGLCreateTextureName() : Event(EventTypeEnum::EVENT_GRAPHICS_OPENGL_CREATE_TEXTURE_NAME) { } /** * Destructor. */ EventGraphicsOpenGLCreateTextureName::~EventGraphicsOpenGLCreateTextureName() { if (m_openglTextureName != NULL) { /* * If the caller did not get the texture name we need to delete it. */ CaretLogSevere("Create OpenGL Texture Name Event never had texture name retrieved. Will attempt to delete it."); EventGraphicsOpenGLDeleteTextureName deleteEvent(m_openglTextureName); EventManager::get()->sendEvent(deleteEvent.getPointer()); } } /** * Set the OpenGL Texture Name * * @param openglTextureName * The OpenGL Texture Name. This instance will take ownership of the texture so the caller * MUST NOT ever reference the texture name after calling this method. */ void EventGraphicsOpenGLCreateTextureName::setOpenGLTextureName(GraphicsOpenGLTextureName* openglTextureName) { m_openglTextureName = openglTextureName; } /** * @return OpenGL Texture Name that was created or NULL if * unable to create texture name due to no valid context. * Caller takes ownership of the texture name. If this method * is called more than once for an instance, NULL will be * returned the second and all subsequent times. */ GraphicsOpenGLTextureName* EventGraphicsOpenGLCreateTextureName::getOpenGLTextureName() const { /* * Do not let texture name be retrieved more than once. */ GraphicsOpenGLTextureName* textureNamePointer = m_openglTextureName; m_openglTextureName = NULL; return textureNamePointer; } connectome-workbench-1.4.2/src/Graphics/EventGraphicsOpenGLCreateTextureName.h000066400000000000000000000040571360521144700274560ustar00rootroot00000000000000#ifndef __EVENT_GRAPHICS_OPEN_G_L_CREATE_TEXTURE_NAME_H__ #define __EVENT_GRAPHICS_OPEN_G_L_CREATE_TEXTURE_NAME_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class GraphicsOpenGLTextureName; class EventGraphicsOpenGLCreateTextureName : public Event { public: EventGraphicsOpenGLCreateTextureName(); virtual ~EventGraphicsOpenGLCreateTextureName(); void setOpenGLTextureName(GraphicsOpenGLTextureName* openglTextureName); GraphicsOpenGLTextureName* getOpenGLTextureName() const; // ADD_NEW_METHODS_HERE private: EventGraphicsOpenGLCreateTextureName(const EventGraphicsOpenGLCreateTextureName&); EventGraphicsOpenGLCreateTextureName& operator=(const EventGraphicsOpenGLCreateTextureName&); mutable GraphicsOpenGLTextureName* m_openglTextureName = NULL; mutable bool m_openglTextureNameWasTakenFlag = false; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_GRAPHICS_OPEN_G_L_CREATE_TEXTURE_NAME_DECLARE__ // #endif // __EVENT_GRAPHICS_OPEN_G_L_CREATE_TEXTURE_NAME_DECLARE__ } // namespace #endif //__EVENT_GRAPHICS_OPEN_G_L_CREATE_TEXTURE_NAME_H__ connectome-workbench-1.4.2/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.cxx000066400000000000000000000067101360521144700301250ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_GRAPHICS_OPEN_G_L_DELETE_BUFFER_OBJECT_DECLARE__ #include "EventGraphicsOpenGLDeleteBufferObject.h" #undef __EVENT_GRAPHICS_OPEN_G_L_DELETE_BUFFER_OBJECT_DECLARE__ #include "ApplicationInformation.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "EventTypeEnum.h" #include "GraphicsOpenGLBufferObject.h" using namespace caret; /** * \class caret::EventGraphicsOpenGLDeleteBufferObject * \brief Delete an OpenGL Buffer Object * \ingroup Graphics * * Deletes an OpenGL Buffer Object for the current context. */ /** * Constructor. * * @param openglBufferObject * The OpenGL Buffer Object whose buffer name is deleted. * After this event the openglBufferObject should be deleted by the caller. */ EventGraphicsOpenGLDeleteBufferObject::EventGraphicsOpenGLDeleteBufferObject(const GraphicsOpenGLBufferObject* openglBufferObject) : Event(EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_BUFFER_OBJECT), m_openglBufferObject(openglBufferObject) { } /** * Destructor. */ EventGraphicsOpenGLDeleteBufferObject::~EventGraphicsOpenGLDeleteBufferObject() { switch (ApplicationInformation::getApplicationType()) { case ApplicationTypeEnum::APPLICATION_TYPE_COMMAND_LINE: /* * Do not test for deletion of OpenGL buffers with * the command line program as will require redesign * of the -show-scene command and would likely require * loading of the scene for each window. */ break; case ApplicationTypeEnum::APPLICATION_TYPE_GRAPHICAL_USER_INTERFACE: /* * Only perform this test for the GUI application. */ if (this->getEventProcessCount() <= 0) { CaretLogSevere("Deletion of OpenGL Buffer Object Name=" + AString::number(m_openglBufferObject->getBufferObjectName()) + ", context pointer=" + AString::number((qulonglong)m_openglBufferObject->getOpenGLContextPointer()) + " appears to have failed. The events processed count is zero and that " "indicates that the event was not received in any listener or the " "listener failed to set the event as processed."); } break; case ApplicationTypeEnum::APPLICATION_TYPE_INVALID: break; } } /** * @return OpenGL Buffer Object that was deleted */ const GraphicsOpenGLBufferObject* EventGraphicsOpenGLDeleteBufferObject::getOpenGLBufferObject() const { return m_openglBufferObject; } connectome-workbench-1.4.2/src/Graphics/EventGraphicsOpenGLDeleteBufferObject.h000066400000000000000000000037571360521144700275620ustar00rootroot00000000000000#ifndef __EVENT_GRAPHICS_OPEN_G_L_DELETE_BUFFER_OBJECT_H__ #define __EVENT_GRAPHICS_OPEN_G_L_DELETE_BUFFER_OBJECT_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class GraphicsOpenGLBufferObject; class EventGraphicsOpenGLDeleteBufferObject : public Event { public: EventGraphicsOpenGLDeleteBufferObject(const GraphicsOpenGLBufferObject* openglBufferObject); virtual ~EventGraphicsOpenGLDeleteBufferObject(); const GraphicsOpenGLBufferObject* getOpenGLBufferObject() const; // ADD_NEW_METHODS_HERE private: EventGraphicsOpenGLDeleteBufferObject(const EventGraphicsOpenGLDeleteBufferObject&); EventGraphicsOpenGLDeleteBufferObject& operator=(const EventGraphicsOpenGLDeleteBufferObject&); const GraphicsOpenGLBufferObject* m_openglBufferObject = NULL; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_GRAPHICS_OPEN_G_L_DELETE_BUFFER_OBJECT_DECLARE__ // #endif // __EVENT_GRAPHICS_OPEN_G_L_DELETE_BUFFER_OBJECT_DECLARE__ } // namespace #endif //__EVENT_GRAPHICS_OPEN_G_L_DELETE_BUFFER_OBJECT_H__ connectome-workbench-1.4.2/src/Graphics/EventGraphicsOpenGLDeleteTextureName.cxx000066400000000000000000000051761360521144700300330ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_GRAPHICS_OPEN_G_L_DELETE_TEXTURE_NAME_DECLARE__ #include "EventGraphicsOpenGLDeleteTextureName.h" #undef __EVENT_GRAPHICS_OPEN_G_L_DELETE_TEXTURE_NAME_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "EventTypeEnum.h" #include "GraphicsOpenGLTextureName.h" using namespace caret; /** * \class caret::EventGraphicsOpenGLDeleteTextureName * \brief Delete an OpenGL Texture Name * \ingroup Graphics * * Deletes an OpenGL Texture Name for the current context. */ /** * Constructor. * * @param openglTextureName * The OpenGL Texture Name whose texture name is deleted. * After this event the openglTextureName should be deleted by the caller. */ EventGraphicsOpenGLDeleteTextureName::EventGraphicsOpenGLDeleteTextureName(const GraphicsOpenGLTextureName* openglTextureName) : Event(EventTypeEnum::EVENT_GRAPHICS_OPENGL_DELETE_TEXTURE_NAME), m_openglTextureName(openglTextureName) { } /** * Destructor. */ EventGraphicsOpenGLDeleteTextureName::~EventGraphicsOpenGLDeleteTextureName() { if (this->getEventProcessCount() <= 0) { CaretLogSevere("Deletion of OpenGL Texture Name=" + AString::number(m_openglTextureName->getTextureName()) + ", context pointer=" + AString::number((qulonglong)m_openglTextureName->getOpenGLContextPointer()) + " appears to have failed. The events processed count is zero and that " "indicates that the event was not received in any listener or the " "listener failed to set the event as processed."); } } /** * @return OpenGL Texture Name that was deleted */ const GraphicsOpenGLTextureName* EventGraphicsOpenGLDeleteTextureName::getOpenGLTextureName() const { return m_openglTextureName; } connectome-workbench-1.4.2/src/Graphics/EventGraphicsOpenGLDeleteTextureName.h000066400000000000000000000037341360521144700274560ustar00rootroot00000000000000#ifndef __EVENT_GRAPHICS_OPEN_G_L_DELETE_TEXTURE_NAME_H__ #define __EVENT_GRAPHICS_OPEN_G_L_DELETE_TEXTURE_NAME_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class GraphicsOpenGLTextureName; class EventGraphicsOpenGLDeleteTextureName : public Event { public: EventGraphicsOpenGLDeleteTextureName(const GraphicsOpenGLTextureName* openglTextureName); virtual ~EventGraphicsOpenGLDeleteTextureName(); const GraphicsOpenGLTextureName* getOpenGLTextureName() const; // ADD_NEW_METHODS_HERE private: EventGraphicsOpenGLDeleteTextureName(const EventGraphicsOpenGLDeleteTextureName&); EventGraphicsOpenGLDeleteTextureName& operator=(const EventGraphicsOpenGLDeleteTextureName&); const GraphicsOpenGLTextureName* m_openglTextureName = NULL; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_GRAPHICS_OPEN_G_L_DELETE_TEXTURE_NAME_DECLARE__ // #endif // __EVENT_GRAPHICS_OPEN_G_L_DELETE_TEXTURE_NAME_DECLARE__ } // namespace #endif //__EVENT_GRAPHICS_OPEN_G_L_DELETE_TEXTURE_NAME_H__ connectome-workbench-1.4.2/src/Graphics/EventOpenGLObjectToWindowTransform.cxx000066400000000000000000000221731360521144700275570ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_OPEN_G_L_OBJECT_TO_WINDOW_TRANSFORM_DECLARE__ #include "EventOpenGLObjectToWindowTransform.h" #undef __EVENT_OPEN_G_L_OBJECT_TO_WINDOW_TRANSFORM_DECLARE__ #include #include "CaretAssert.h" #include "CaretLogger.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventOpenGLObjectToWindowTransform * \brief Get a transform for converting OpenGL Object to Window Coordinates * \ingroup Graphics * * Creates a transform (matrix) that is used to convert * object coordinates to window coordinates. * There must be a valid OpenGL context that is "current". */ /** * Constructor. * * @param spaceType * Type of space of objects being transformed */ EventOpenGLObjectToWindowTransform::EventOpenGLObjectToWindowTransform(const SpaceType spaceType) : Event(EventTypeEnum::EVENT_OPENGL_OBJECT_TO_WINDOW_TRANSFORM), m_spaceType(spaceType) { } /** * Destructor. */ EventOpenGLObjectToWindowTransform::~EventOpenGLObjectToWindowTransform() { } /** * @return The object to window matrix. */ Matrix4x4 EventOpenGLObjectToWindowTransform::getMatrix() const { return m_transformMatrix; } /** * @return Is the data for performing transformations valid? */ bool EventOpenGLObjectToWindowTransform::isValid() const { return m_validFlag; } /** * Transform a window coordinate to an object coordinate. * * @param windowXYZ * The window coordinate. * @param objectXYZOut * Output containing the computed object coordinate. * @return * True if output coordinate is valid, else false. */ bool EventOpenGLObjectToWindowTransform::inverseTransformPoint(const float windowXYZ[3], float objectXYZOut[3]) const { if ( ! m_validFlag) { CaretAssert(0); CaretLogSevere("Program Error: EventOpenGLObjectToWindowTransform is not valid"); return false; } /* * If needed, create the inverse matrix */ if ( ! m_inverseTransformMatrix) { m_inverseTransformMatrix.reset(new Matrix4x4(m_transformMatrix)); if ( ! m_inverseTransformMatrix->invert()) { CaretAssert(0); CaretLogSevere("Program Error: EventOpenGLObjectToWindowTransform unable to invert matrix"); return false; } } float xyzw[4] { (2.0f * (windowXYZ[0] - m_viewport[0]) / m_viewport[2]) - 1.0f, (2.0f * (windowXYZ[1] - m_viewport[1]) / m_viewport[3]) - 1.0f, (2.0f * windowXYZ[2]) - 1.0f, 1.0f }; m_inverseTransformMatrix->multiplyPoint4(xyzw); objectXYZOut[0] = xyzw[0]; objectXYZOut[1] = xyzw[1]; objectXYZOut[2] = xyzw[2]; return true; } /** * Transform an object coordinate to a window coordinate. * * @param objectXYZ * The object's coordinate. * @param windowXYZOut * Output containing the computed window coordinate. * @return * True if output coordinate is valid, else false. */ bool EventOpenGLObjectToWindowTransform::transformPoint(const float objectXYZ[3], float windowXYZOut[3]) const { if ( ! m_validFlag) { CaretAssert(0); CaretLogSevere("Program Error: EventOpenGLObjectToWindowTransform is not valid"); return false; } float xyzw[4] = { objectXYZ[0], objectXYZ[1], objectXYZ[2], 1.0f }; m_transformMatrix.multiplyPoint4(xyzw); windowXYZOut[0] = m_viewport[0] + (m_viewport[2] * ((xyzw[0] + 1.0f) / 2.0f)); windowXYZOut[1] = m_viewport[1] + (m_viewport[3] * ((xyzw[1] + 1.0f) / 2.0f)); windowXYZOut[2] = (xyzw[2] + 1.0f) / 2.0f; /* * From OpenGL Programming Guide 3rd Ed, p 133: * * If the near value is 1.0 and the far value is 3.0, * objects must have z-coordinates between -1.0 and -3.0 in order to be visible. * So, negate the Z-value to be negative. */ const float windowZ = windowXYZOut[2]; windowXYZOut[2] = -windowXYZOut[2]; bool modelSpaceFlag = false; bool volumeSpaceFlag = false; switch (m_spaceType) { case SpaceType::MODEL: modelSpaceFlag = true; break; case SpaceType::VOLUME_SLICE_MODEL: modelSpaceFlag = true; volumeSpaceFlag = true; break; case SpaceType::WINDOW: break; } /* * If window space, we DO NOT need to offset for the 'eye' location * Even when we do, the offset for the eye is very small */ if (modelSpaceFlag) { if ((m_projectionMatrixArray[0] != 0.0) && (m_projectionMatrixArray[5] != 0.0) && (m_projectionMatrixArray[10] != 0.0)) { /* * From http://lektiondestages.blogspot.com/2013/11/decompose-opengl-projection-matrix.html */ float nearValue = (1.0f + m_projectionMatrixArray[14]) / m_projectionMatrixArray[10]; float farValue = -(1.0f - m_projectionMatrixArray[14]) / m_projectionMatrixArray[10]; float left = -(1.0f + m_projectionMatrixArray[12]) / m_projectionMatrixArray[0]; float right = (1.0f - m_projectionMatrixArray[12]) / m_projectionMatrixArray[0]; /* * Depending upon view, near may be positive and far negative */ const float farNearRange = std::fabs(farValue - nearValue); if ((m_centerToEyeDistance > 0.0) && (farNearRange > 0.0)) { /* * Using gluLookAt moves the eye away from the center which * causes the window Z to also move. Thus, we need to remove * this amount from the window's Z-coordinate. */ const float eyeAdjustment = (m_centerToEyeDistance / farNearRange); if (volumeSpaceFlag) { windowXYZOut[2] = -(windowZ - eyeAdjustment); } else if (left > right) { windowXYZOut[2] = -(windowZ - eyeAdjustment); } else { windowXYZOut[2] = -(windowZ + eyeAdjustment); } } } } return true; } /** * Setup the transformation's data. * * @param modelviewMatrixArray * The OpenGL modelview matrix as an array. * @param projectionMatrixArray * The OpenGL projection matrix as an array. * @param viewport * The OpenGL Viewport (x, y, w, h) * @param depthRange * The depth range (near, far) * @param centerToEyeDistance * Distance from object space center to the viewer's eye along Z-axis. */ void EventOpenGLObjectToWindowTransform::setup(const std::array& modelviewMatrixArray, const std::array& projectionMatrixArray, const std::array& viewport, const std::array& depthRange, const double centerToEyeDistance) { m_projectionMatrixArray = projectionMatrixArray; m_viewport = viewport; m_depthRange = depthRange; m_centerToEyeDistance = centerToEyeDistance; Matrix4x4 modelviewMatrix; modelviewMatrix.setMatrixFromOpenGL(modelviewMatrixArray.data()); m_transformMatrix.setMatrixFromOpenGL(m_projectionMatrixArray.data()); //m_projectionMatrix.postmultiply(modelviewMatrix); m_transformMatrix.premultiply(modelviewMatrix); const bool autoDetectWindowSpaceFlag = false; if (autoDetectWindowSpaceFlag) { /* * Far/near from http://lektiondestages.blogspot.com/2013/11/decompose-opengl-projection-matrix.html */ const float nearValue = (1.0f + m_projectionMatrixArray[14]) / m_projectionMatrixArray[10]; const float farValue = -(1.0f - m_projectionMatrixArray[14]) / m_projectionMatrixArray[10]; /* * Window space when near is zero, far is one */ const float smallValue = 0.005; if ((std::fabs(nearValue) < smallValue) && (std::fabs(farValue - 1.0) < smallValue)) { //m_windowDepthFlag = true; } } m_validFlag = true; } /** * @return The viewport. */ std::array EventOpenGLObjectToWindowTransform::getViewport() const { return m_viewport; } connectome-workbench-1.4.2/src/Graphics/EventOpenGLObjectToWindowTransform.h000066400000000000000000000064671360521144700272140ustar00rootroot00000000000000#ifndef __EVENT_OPEN_G_L_OBJECT_TO_WINDOW_TRANSFORM_H__ #define __EVENT_OPEN_G_L_OBJECT_TO_WINDOW_TRANSFORM_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "Event.h" #include "Matrix4x4.h" namespace caret { class EventOpenGLObjectToWindowTransform : public Event { public: /** * Space in which data is drawn */ enum class SpaceType { /** Transformation data that is being drawn in model space (except volume)*/ MODEL, /** Transformation data that is being drawn in VOLUME model space*/ VOLUME_SLICE_MODEL, /** Transformation data that is being drawn in window space*/ WINDOW }; EventOpenGLObjectToWindowTransform(const SpaceType spaceType); virtual ~EventOpenGLObjectToWindowTransform(); Matrix4x4 getMatrix() const; bool isValid() const; bool inverseTransformPoint(const float windowXYZ[3], float objectXYZOut[3]) const; bool transformPoint(const float objectXYZ[3], float windowXYZOut[3]) const; void setup(const std::array& modelviewMatrixArray, const std::array& projectionMatrixArray, const std::array& viewport, const std::array& depthRange, const double centerToEyeDistance); std::array getViewport() const; // ADD_NEW_METHODS_HERE private: EventOpenGLObjectToWindowTransform(const EventOpenGLObjectToWindowTransform&); EventOpenGLObjectToWindowTransform& operator=(const EventOpenGLObjectToWindowTransform&); const SpaceType m_spaceType; Matrix4x4 m_transformMatrix; mutable std::unique_ptr m_inverseTransformMatrix; std::array m_projectionMatrixArray; std::array m_viewport; std::array m_depthRange; double m_centerToEyeDistance; bool m_validFlag = false; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_OPEN_G_L_OBJECT_TO_WINDOW_TRANSFORM_DECLARE__ // #endif // __EVENT_OPEN_G_L_OBJECT_TO_WINDOW_TRANSFORM_DECLARE__ } // namespace #endif //__EVENT_OPEN_G_L_OBJECT_TO_WINDOW_TRANSFORM_H__ connectome-workbench-1.4.2/src/Graphics/GraphicsEngineData.cxx000066400000000000000000000037741360521144700244010ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GRAPHICS_ENGINE_DATA_DECLARE__ #include "GraphicsEngineData.h" #undef __GRAPHICS_ENGINE_DATA_DECLARE__ #include "CaretAssert.h" #include "EventManager.h" using namespace caret; /** * \class caret::GraphicsEngineData * \brief Base class for data a graphics engine may associate with primitive data. * \ingroup Graphics */ /** * Constructor. */ GraphicsEngineData::GraphicsEngineData() : CaretObject() { // EventManager::get()->addEventListener(this, EventTypeEnum::); } /** * Destructor. */ GraphicsEngineData::~GraphicsEngineData() { EventManager::get()->removeAllEventsFromListener(this); } /** * Get a description of this object's content. * @return String describing this object's content. */ AString GraphicsEngineData::toString() const { return "GraphicsEngineData"; } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void GraphicsEngineData::receiveEvent(Event* /*event*/) { // if (event->getEventType() == EventTypeEnum::) { // eventName = dynamic_cast(event); // CaretAssert(eventName); // // event->setEventProcessed(); // } } connectome-workbench-1.4.2/src/Graphics/GraphicsEngineData.h000066400000000000000000000032621360521144700240160ustar00rootroot00000000000000#ifndef __GRAPHICS_ENGINE_DATA_H__ #define __GRAPHICS_ENGINE_DATA_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "EventListenerInterface.h" namespace caret { class GraphicsEngineData : public CaretObject, public EventListenerInterface { public: GraphicsEngineData(); virtual ~GraphicsEngineData(); // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual void receiveEvent(Event* event); private: GraphicsEngineData(const GraphicsEngineData&); GraphicsEngineData& operator=(const GraphicsEngineData&); // ADD_NEW_MEMBERS_HERE }; #ifdef __GRAPHICS_ENGINE_DATA_DECLARE__ // #endif // __GRAPHICS_ENGINE_DATA_DECLARE__ } // namespace #endif //__GRAPHICS_ENGINE_DATA_H__ connectome-workbench-1.4.2/src/Graphics/GraphicsEngineDataOpenGL.cxx000066400000000000000000001316621360521144700254440ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GRAPHICS_ENGINE_DATA_OPEN_G_L_DECLARE__ #include "GraphicsEngineDataOpenGL.h" #undef __GRAPHICS_ENGINE_DATA_OPEN_G_L_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "DeveloperFlagsEnum.h" #include "EventGraphicsOpenGLCreateBufferObject.h" #include "EventGraphicsOpenGLCreateTextureName.h" #include "EventOpenGLObjectToWindowTransform.h" #include "EventManager.h" #include "GraphicsOpenGLBufferObject.h" #include "GraphicsOpenGLPolylineTriangles.h" #include "GraphicsOpenGLTextureName.h" #include "GraphicsPrimitive.h" #include "GraphicsPrimitiveSelectionHelper.h" #include "GraphicsShape.h" #include "Matrix4x4.h" using namespace caret; /** * \class caret::GraphicsEngineDataOpenGL * \brief Contains data the OpenGL Graphics Engine may associate with primtive data. * \ingroup Graphics */ /** * Constructor. */ GraphicsEngineDataOpenGL::GraphicsEngineDataOpenGL() : GraphicsEngineData() { } /** * Destructor. */ GraphicsEngineDataOpenGL::~GraphicsEngineDataOpenGL() { deleteBuffers(); } /** * Delete the OpenGL buffer objects. */ void GraphicsEngineDataOpenGL::deleteBuffers() { if (m_textureImageDataName != NULL) { delete m_textureImageDataName; m_textureImageDataName = NULL; } } /** * Invalidate the coordinates after they have * changed in the graphics primitive. */ void GraphicsEngineDataOpenGL::invalidateCoordinates() { m_reloadCoordinatesFlag = true; } /** * Invalidate the colors after they have * changed in the graphics primitive. */ void GraphicsEngineDataOpenGL::invalidateColors() { m_reloadColorsFlag = true; } /** * Get the OpenGL Buffer Usage Hint from the primitive. * * @param primitiveUsageType * The graphics primitive usage type * @return * The OpenGL Buffer Usage Hint. */ GLenum GraphicsEngineDataOpenGL::getOpenGLBufferUsageHint(const GraphicsPrimitive::UsageType primitiveUsageType) const { GLenum usageHint = GL_STREAM_DRAW; switch (primitiveUsageType) { case GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES: usageHint = GL_STREAM_DRAW; break; case GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES: usageHint = GL_STATIC_DRAW; break; case GraphicsPrimitive::UsageType::MODIFIED_MANY_DRAWN_MANY_TIMES: usageHint = GL_DYNAMIC_DRAW; break; } return usageHint; } /** * Load the coordinate buffer. * * @param primitive * The graphics primitive that will be drawn. */ void GraphicsEngineDataOpenGL::loadCoordinateBuffer(GraphicsPrimitive* primitive) { CaretAssert(primitive); GLenum usageHint = getOpenGLBufferUsageHint(primitive->getUsageTypeCoordinates()); GLsizei coordinateCount = 0; switch (primitive->m_vertexDataType) { case GraphicsPrimitive::VertexDataType::FLOAT_XYZ: m_coordinateDataType = GL_FLOAT; m_coordinatesPerVertex = 3; // X, Y, Z coordinateCount = primitive->m_xyz.size(); const GLuint xyzSizeBytes = coordinateCount * sizeof(float); CaretAssert(xyzSizeBytes > 0); const GLvoid* xyzDataPointer = (const GLvoid*)&primitive->m_xyz[0]; /* * Coordinate buffer may have been created. * Coordinates may change but the number of coordinates does not change. */ if (m_coordinateBufferObject == NULL) { EventGraphicsOpenGLCreateBufferObject createEvent; EventManager::get()->sendEvent(createEvent.getPointer()); m_coordinateBufferObject.reset(createEvent.getOpenGLBufferObject()); CaretAssert(m_coordinateBufferObject); } CaretAssert(m_coordinateBufferObject->getBufferObjectName()); glBindBuffer(GL_ARRAY_BUFFER, m_coordinateBufferObject->getBufferObjectName()); glBufferData(GL_ARRAY_BUFFER, xyzSizeBytes, xyzDataPointer, usageHint); break; } if (m_coordinatesPerVertex > 0) { m_arrayIndicesCount = coordinateCount / m_coordinatesPerVertex; } else { m_arrayIndicesCount = 0; } m_reloadCoordinatesFlag = false; } /** * Load the normal vector buffer. * * @param primitive * The graphics primitive that will be drawn. */ void GraphicsEngineDataOpenGL::loadNormalVectorBuffer(GraphicsPrimitive* primitive) { CaretAssert(primitive); GLenum usageHint = getOpenGLBufferUsageHint(primitive->getUsageTypeNormals()); switch (primitive->m_normalVectorDataType) { case GraphicsPrimitive::NormalVectorDataType::NONE: break; case GraphicsPrimitive::NormalVectorDataType::FLOAT_XYZ: { m_normalVectorDataType = GL_FLOAT; const GLuint normalSizeBytes = primitive->m_floatNormalVectorXYZ.size() * sizeof(float); CaretAssert(normalSizeBytes > 0); const GLvoid* normalDataPointer = (const GLvoid*)&primitive->m_floatNormalVectorXYZ[0]; EventGraphicsOpenGLCreateBufferObject createEvent; EventManager::get()->sendEvent(createEvent.getPointer()); m_normalVectorBufferObject.reset(createEvent.getOpenGLBufferObject()); CaretAssert(m_normalVectorBufferObject->getBufferObjectName()); glBindBuffer(GL_ARRAY_BUFFER, m_normalVectorBufferObject->getBufferObjectName()); glBufferData(GL_ARRAY_BUFFER, normalSizeBytes, normalDataPointer, usageHint); } break; } } /** * Load the color buffer. * @param primitive * The graphics primitive that will be drawn. */ void GraphicsEngineDataOpenGL::loadColorBuffer(GraphicsPrimitive* primitive) { CaretAssert(primitive); GLenum usageHint = getOpenGLBufferUsageHint(primitive->getUsageTypeColors()); switch (primitive->m_colorDataType) { case GraphicsPrimitive::ColorDataType::NONE: break; case GraphicsPrimitive::ColorDataType::FLOAT_RGBA: { EventGraphicsOpenGLCreateBufferObject createEvent; EventManager::get()->sendEvent(createEvent.getPointer()); m_colorBufferObject.reset(createEvent.getOpenGLBufferObject()); CaretAssert(m_colorBufferObject->getBufferObjectName()); m_componentsPerColor = 4; m_colorDataType = GL_FLOAT; const GLuint colorSizeBytes = primitive->m_floatRGBA.size() * sizeof(float); CaretAssert(colorSizeBytes > 0); const GLvoid* colorDataPointer = (const GLvoid*)&primitive->m_floatRGBA[0]; glBindBuffer(GL_ARRAY_BUFFER, m_colorBufferObject->getBufferObjectName()); glBufferData(GL_ARRAY_BUFFER, colorSizeBytes, colorDataPointer, usageHint); } break; case GraphicsPrimitive::ColorDataType::UNSIGNED_BYTE_RGBA: { EventGraphicsOpenGLCreateBufferObject createEvent; EventManager::get()->sendEvent(createEvent.getPointer()); m_colorBufferObject.reset(createEvent.getOpenGLBufferObject()); CaretAssert(m_colorBufferObject->getBufferObjectName()); m_componentsPerColor = 4; m_colorDataType = GL_UNSIGNED_BYTE; const GLuint colorSizeBytes = primitive->m_unsignedByteRGBA.size() * sizeof(uint8_t); CaretAssert(colorSizeBytes > 0); const GLvoid* colorDataPointer = (const GLvoid*)&primitive->m_unsignedByteRGBA[0]; glBindBuffer(GL_ARRAY_BUFFER, m_colorBufferObject->getBufferObjectName()); glBufferData(GL_ARRAY_BUFFER, colorSizeBytes, colorDataPointer, usageHint); } break; } m_reloadColorsFlag = false; } /** * Load the texture coordinate buffer. * @param primitive * The graphics primitive that will be drawn. */ void GraphicsEngineDataOpenGL::loadTextureCoordinateBuffer(GraphicsPrimitive* primitive) { CaretAssert(primitive); GLenum usageHint = getOpenGLBufferUsageHint(primitive->getUsageTypeTextureCoordinates()); switch (primitive->m_textureDataType) { case GraphicsPrimitive::TextureDataType::FLOAT_STR: { EventGraphicsOpenGLCreateBufferObject createEvent; EventManager::get()->sendEvent(createEvent.getPointer()); m_textureCoordinatesBufferObject.reset(createEvent.getOpenGLBufferObject()); CaretAssert(m_textureCoordinatesBufferObject->getBufferObjectName()); m_textureCoordinatesDataType = GL_FLOAT; const GLuint textureSizeBytes = primitive->m_floatTextureSTR.size() * sizeof(float); CaretAssert(textureSizeBytes > 0); const GLvoid* textureDataPointer = (const GLvoid*)&primitive->m_floatTextureSTR[0]; glBindBuffer(GL_ARRAY_BUFFER, m_textureCoordinatesBufferObject->getBufferObjectName()); glBufferData(GL_ARRAY_BUFFER, textureSizeBytes, textureDataPointer, usageHint); } break; case GraphicsPrimitive::TextureDataType::NONE: break; } } /** * Load the buffers with data from the grpahics primitive. * * @param primitive * The graphics primitive that will be drawn. */ void GraphicsEngineDataOpenGL::loadAllBuffers(GraphicsPrimitive* primitive) { loadCoordinateBuffer(primitive); loadNormalVectorBuffer(primitive); loadColorBuffer(primitive); loadTextureCoordinateBuffer(primitive); } /** * If needed, load the texture buffer. * Note that the texture buffer may be invalidated when * an image is captures as the image capture wipes out all * textures. * * @param primitive * The graphics primitive that will be drawn. */ void GraphicsEngineDataOpenGL::loadTextureImageDataBuffer(GraphicsPrimitive* primitive) { if (m_textureImageDataName != NULL) { return; } switch (primitive->m_textureDataType) { case GraphicsPrimitive::TextureDataType::FLOAT_STR: { const int32_t imageWidth = primitive->m_textureImageWidth; const int32_t imageHeight = primitive->m_textureImageHeight; const int32_t imageNumberOfBytes = imageWidth * imageHeight * 4; if (imageNumberOfBytes <= 0) { CaretLogWarning("Invalid texture (empty data) for drawing primitive with texture"); return; } if (imageNumberOfBytes != static_cast(primitive->m_textureImageBytesRGBA.size())) { CaretLogWarning("Image bytes size incorrect for image width/height"); return; } glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); const GLubyte* imageBytesRGBA = &primitive->m_textureImageBytesRGBA[0]; EventGraphicsOpenGLCreateTextureName createEvent; EventManager::get()->sendEvent(createEvent.getPointer()); m_textureImageDataName = createEvent.getOpenGLTextureName(); CaretAssert(m_textureImageDataName); const GLuint openGLTextureName = m_textureImageDataName->getTextureName(); glBindTexture(GL_TEXTURE_2D, openGLTextureName); bool useMipMapFlag = true; if (useMipMapFlag) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); /* * This code seems to work if OpenGL 3.0 or later and * replaces gluBuild2DMipmaps() * * glTexImage2D(GL_TEXTURE_2D, // MUST BE GL_TEXTURE_2D * 0, // level of detail 0=base, n is nth mipmap reduction * GL_RGBA, // number of components * imageWidth, // width of image * imageHeight, // height of image * 0, // border * GL_RGBA, // format of the pixel data * GL_UNSIGNED_BYTE, // data type of pixel data * imageBytesRGBA); // pointer to image data * glGenerateMipmap(GL_TEXTURE_2D); */ const int errorCode = gluBuild2DMipmaps(GL_TEXTURE_2D, // MUST BE GL_TEXTURE_2D GL_RGBA, // number of components imageWidth, // width of image imageHeight, // height of image GL_RGBA, // format of the pixel data GL_UNSIGNED_BYTE, // data type of pixel data imageBytesRGBA); // pointer to image data if (errorCode != 0) { useMipMapFlag = false; const GLubyte* errorChars = gluErrorString(errorCode); if (errorChars != NULL) { const QString errorText = ("ERROR building mipmaps for annotation image: " + AString((char*)errorChars)); CaretLogSevere(errorText); } } } if ( ! useMipMapFlag) { CaretAssert(0); // image must be 2^N by 2^M glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, // MUST BE GL_TEXTURE_2D 0, // level of detail 0=base, n is nth mipmap reduction GL_RGBA, // number of components imageWidth, // width of image imageHeight, // height of image 0, // border GL_RGBA, // format of the pixel data GL_UNSIGNED_BYTE, // data type of pixel data imageBytesRGBA); // pointer to image data } glBindTexture(GL_TEXTURE_2D, 0); glPopClientAttrib(); } break; case GraphicsPrimitive::TextureDataType::NONE: break; } } /** * Draw the given graphics primitive. * * @param primitive * Primitive that is drawn. */ void GraphicsEngineDataOpenGL::draw(GraphicsPrimitive* primitive) { CaretAssert(primitive); if (primitive->getNumberOfVertices() <= 0) { return; } if ( ! primitive->isValid()) { CaretLogWarning("Attempting to draw invalid Graphics Primitive"); } GraphicsPrimitive* primitiveToDraw = primitive; /* Conversion to window space creates a new primitive that must be deleted */ std::unique_ptr lineConversionPrimitive; bool modelSpaceLineFlag = false; bool windowSpaceLineFlag = false; bool millimeterPointsFlag = false; bool spheresFlag = false; switch (primitive->m_primitiveType) { case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: break; case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: switch (primitive->m_pointSizeType) { case GraphicsPrimitive::PointSizeType::MILLIMETERS: millimeterPointsFlag = true; break; case GraphicsPrimitive::PointSizeType::PERCENTAGE_VIEWPORT_HEIGHT: break; case GraphicsPrimitive::PointSizeType::PIXELS: break; } break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: break; case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN: case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN: case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINES: modelSpaceLineFlag = true; break; case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: windowSpaceLineFlag = true; break; case GraphicsPrimitive::PrimitiveType::SPHERES: spheresFlag = true; break; } if (millimeterPointsFlag) { /* * Special case for points in millimeters */ drawPointsPrimitiveMillimeters(primitive); } else if (spheresFlag) { drawSpheresPrimitive(primitive); } else if (modelSpaceLineFlag || windowSpaceLineFlag) { AString errorMessage; primitiveToDraw = GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(primitive, errorMessage); if (primitiveToDraw == NULL) { const AString msg("For developer: " + errorMessage); #ifdef NDEBUG CaretLogFine(msg); #else CaretLogSevere(msg); #endif return; } SpaceMode spaceMode = SpaceMode::WINDOW; if (modelSpaceLineFlag) { spaceMode = SpaceMode::MODEL; } else if (windowSpaceLineFlag) { spaceMode = SpaceMode::WINDOW; } else { CaretAssert(0); } lineConversionPrimitive.reset(primitiveToDraw); drawModelOrWindowSpace(spaceMode, PrivateDrawMode::DRAW_NORMAL, primitiveToDraw, NULL); } else { drawPrivate(PrivateDrawMode::DRAW_NORMAL, primitiveToDraw, NULL); } } /** * Draw the graphics primitive in model space. * * @param spaceMode * Space mode: model or window * @param drawMode * Mode for drawing. * @param primitive * Primitive that is drawn. * @param primitiveSelectionHelper * Selection helper when draw mode is selection. */ void GraphicsEngineDataOpenGL::drawModelOrWindowSpace(const SpaceMode spaceMode, const PrivateDrawMode drawMode, GraphicsPrimitive* primitive, GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper) { bool windowSpaceFlag = false; switch (spaceMode) { case MODEL: break; case WINDOW: windowSpaceFlag = true; break; } int32_t polygonMode[2]; int32_t viewport[4]; saveOpenGLStateForWindowSpaceDrawing(polygonMode, viewport); if (windowSpaceFlag) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(viewport[0], viewport[0] + viewport[2], viewport[1], viewport[1] + viewport[3], 0, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } glPolygonMode(GL_FRONT, GL_FILL); drawPrivate(drawMode, primitive, primitiveSelectionHelper); restoreOpenGLStateForWindowSpaceDrawing(polygonMode, viewport); } /** * Draw a point primitive type in millimeters (same as model space). * * @param primitive * The points primitive type. */ void GraphicsEngineDataOpenGL::drawPointsPrimitiveMillimeters(const GraphicsPrimitive* primitive) { CaretAssert(primitive); CaretAssert(primitive->getPrimitiveType() == GraphicsPrimitive::PrimitiveType::OPENGL_POINTS); CaretAssert(primitive->m_pointSizeType == GraphicsPrimitive::PointSizeType::MILLIMETERS); GraphicsPrimitive::PointSizeType sizeType; float sizeValue = 0.0f; primitive->getPointDiameter(sizeType, sizeValue); const int32_t numberOfVertices = primitive->getNumberOfVertices(); switch (primitive->m_pointSizeType) { case GraphicsPrimitive::PointSizeType::MILLIMETERS: { switch (primitive->m_vertexColorType) { case GraphicsPrimitive::VertexColorType::NONE: CaretAssert(0); CaretLogSevere("NONE vertex color type, should never occur when drawing points in millimeters"); return; break; case GraphicsPrimitive::VertexColorType::PER_VERTEX_RGBA: { for (int32_t i = 0; i < numberOfVertices; i++) { const int32_t i3 = i * 3; CaretAssertVectorIndex(primitive->m_xyz, i3 + 2); const float* xyz = &primitive->m_xyz[i3]; const int32_t i4 = i * 4; uint8_t* rgba = NULL; switch (primitive->m_colorDataType) { case GraphicsPrimitive::ColorDataType::FLOAT_RGBA: CaretAssert(0); break; case GraphicsPrimitive::ColorDataType::UNSIGNED_BYTE_RGBA: CaretAssertVectorIndex(primitive->m_unsignedByteRGBA, i4 + 3); rgba = const_cast(&primitive->m_unsignedByteRGBA[i4]); break; case GraphicsPrimitive::ColorDataType::NONE: CaretAssert(0); break; } GraphicsShape::drawSquare(xyz, rgba, sizeValue); } } break; case GraphicsPrimitive::VertexColorType::SOLID_RGBA: { const int32_t numberOfVertices = primitive->getNumberOfVertices(); CaretAssertVectorIndex(primitive->m_xyz, (numberOfVertices - 1) * 3 + 1); GraphicsShape::drawSquares(&primitive->m_xyz[0], numberOfVertices, &primitive->m_unsignedByteRGBA[0], sizeValue); } break; } } break; case GraphicsPrimitive::PointSizeType::PERCENTAGE_VIEWPORT_HEIGHT: case GraphicsPrimitive::PointSizeType::PIXELS: CaretAssert(0); break; } } /** * Draw a sphere primitive type. * * @param primitive * The spheres primitive type. */ void GraphicsEngineDataOpenGL::drawSpheresPrimitive(const GraphicsPrimitive* primitive) { CaretAssert(primitive); CaretAssert(primitive->getPrimitiveType() == GraphicsPrimitive::PrimitiveType::SPHERES); GraphicsPrimitive::SphereSizeType sizeType; float sizeValue = 0.0f; primitive->getSphereDiameter(sizeType, sizeValue); switch (primitive->m_vertexColorType) { case GraphicsPrimitive::VertexColorType::NONE: CaretAssert(0); CaretLogSevere("NONE vertex color type, should never occur when drawing spheres"); return; break; case GraphicsPrimitive::VertexColorType::PER_VERTEX_RGBA: { const int32_t numberOfVertices = primitive->getNumberOfVertices(); for (int32_t i = 0; i < numberOfVertices; i++) { const int32_t i3 = i * 3; CaretAssertVectorIndex(primitive->m_xyz, i3 + 2); const int32_t i4 = i * 4; switch (primitive->m_colorDataType) { case GraphicsPrimitive::ColorDataType::FLOAT_RGBA: CaretAssert(0); break; case GraphicsPrimitive::ColorDataType::UNSIGNED_BYTE_RGBA: CaretAssertVectorIndex(primitive->m_unsignedByteRGBA, i4 + 3); GraphicsShape::drawSphereByteColor(&primitive->m_xyz[i3], &primitive->m_unsignedByteRGBA[i4], sizeValue); break; case GraphicsPrimitive::ColorDataType::NONE: CaretAssert(0); break; } } } break; case GraphicsPrimitive::VertexColorType::SOLID_RGBA: { const int32_t numberOfVertices = primitive->getNumberOfVertices(); CaretAssertVectorIndex(primitive->m_xyz, (numberOfVertices - 1) * 3 + 1); GraphicsShape::drawSpheresByteColor(&primitive->m_xyz[0], numberOfVertices, &primitive->m_unsignedByteRGBA[0], sizeValue); } break; } } /** * Save the OpenGL State for drawing in window space. * * @param polygonMode * Output with the polygon mode. * @param viewport * Output with viewport. */ void GraphicsEngineDataOpenGL::saveOpenGLStateForWindowSpaceDrawing(int32_t polygonMode[2], int32_t viewport[4]) { glPushAttrib(GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT | GL_HINT_BIT | GL_LIGHTING_BIT | GL_POLYGON_BIT); /* * For anti-aliasing requires sorting polygons * and turning of depth testing */ const bool drawWithAntiAliasingFlag = false; if (drawWithAntiAliasingFlag) { glBlendFunc (GL_SRC_ALPHA_SATURATE, GL_ONE); glEnable(GL_BLEND); glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); glEnable(GL_POLYGON_SMOOTH); } glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); glGetIntegerv(GL_POLYGON_MODE, polygonMode); glGetIntegerv(GL_VIEWPORT, viewport); glMatrixMode(GL_PROJECTION); glPushMatrix(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); } /** * Restore the OpenGL State from drawing in window space. * @param polygonMode * Polygon mode. * @param viewport * Viewport. */ void GraphicsEngineDataOpenGL::restoreOpenGLStateForWindowSpaceDrawing(int32_t polygonMode[2], int32_t viewport[4]) { glPolygonMode(GL_FRONT, polygonMode[0]); glPolygonMode(GL_BACK, polygonMode[1]); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); glPopAttrib(); } /** * Draw to determine the index of primitive at the given (X, Y) location * * @param primitive * Primitive that is drawn. * @param pixelX * X location for selection. * @param pixelY * Y location for selection. * @param selectedPrimitiveIndexOut * Output with the index of the primitive (invalid no primitve at location * @param selectedPrimitiveDepthOut * Output with depth at the location. */ void GraphicsEngineDataOpenGL::drawWithSelection(GraphicsPrimitive* primitive, const int32_t pixelX, const int32_t pixelY, int32_t& selectedPrimitiveIndexOut, float& selectedPrimitiveDepthOut) { CaretAssert(primitive); switch (primitive->m_primitiveType) { case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: break; case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: break; case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN: case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN: case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINES: break; case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: break; case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: break; case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: break; case GraphicsPrimitive::PrimitiveType::SPHERES: CaretAssertMessage(0, "Not yet implemented"); break; } selectedPrimitiveIndexOut = -1; selectedPrimitiveDepthOut = 0.0; GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); if ((pixelX >= viewport[0]) && (pixelX < (viewport[0] + viewport[2])) && (pixelY >= viewport[1]) && (pixelY < (viewport[1] + viewport[3]))) { /* * Saves glPixelStore parameters */ glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); glPushAttrib(GL_LIGHTING_BIT); glShadeModel(GL_FLAT); glDisable(GL_LIGHTING); GraphicsPrimitiveSelectionHelper selectionHelper(primitive); selectionHelper.setupSelectionBeforeDrawing(); drawPrivate(PrivateDrawMode::DRAW_SELECTION, primitive, &selectionHelper); /* * QOpenGLWidget Note: The QOpenGLWidget always renders in a * frame buffer object (see its documentation). This is * probably why calls to glReadBuffer() always cause an * OpenGL error. */ #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET /* do not call glReadBuffer() */ #else glReadBuffer(GL_BACK); #endif uint8_t pixelRGBA[4]; glPixelStorei(GL_PACK_SKIP_ROWS, 0); glPixelStorei(GL_PACK_SKIP_PIXELS, 0); glPixelStorei(GL_PACK_ALIGNMENT, 1); // bytes glReadPixels(pixelX, pixelY, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixelRGBA); /* * Get depth from depth buffer */ glPixelStorei(GL_PACK_ALIGNMENT, 4); // float glReadPixels(pixelX, pixelY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &selectedPrimitiveDepthOut); glPopAttrib(); glPopClientAttrib(); selectedPrimitiveIndexOut = selectionHelper.getPrimitiveIndexFromEncodedRGBA(pixelRGBA); } } /** * Draw the graphics primitive. * * @param drawMode * Mode for drawing. * @param primitive * Primitive that is drawn. * @param primitiveSelectionHelper * Selection helper when draw mode is selection. */ void GraphicsEngineDataOpenGL::drawPrivate(const PrivateDrawMode drawMode, GraphicsPrimitive* primitive, GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper) { CaretAssert(primitive); if ( ! primitive->isValid()) { return; } switch (drawMode) { case PrivateDrawMode::DRAW_NORMAL: break; case PrivateDrawMode::DRAW_SELECTION: break; } GraphicsEngineDataOpenGL* openglData = primitive->getGraphicsEngineDataForOpenGL(); if (openglData == NULL) { openglData = new GraphicsEngineDataOpenGL(); primitive->setGraphicsEngineDataForOpenGL(openglData); openglData->loadAllBuffers(primitive); } else { /* * Coordinates may get updated. */ if (openglData->m_reloadCoordinatesFlag) { openglData->loadCoordinateBuffer(primitive); } /* * Colors may get updated */ if (openglData->m_reloadColorsFlag) { openglData->loadColorBuffer(primitive); } } openglData->loadTextureImageDataBuffer(primitive); const GLuint coordBufferID = openglData->m_coordinateBufferObject->getBufferObjectName(); CaretAssert(coordBufferID); if ( ! glIsBuffer(coordBufferID)) { CaretAssertMessage(0, "Coordinate buffer is INVALID"); CaretLogSevere("Coordinate buffer is INVALID"); return; } switch (drawMode) { case PrivateDrawMode::DRAW_NORMAL: break; case PrivateDrawMode::DRAW_SELECTION: break; } /* * Setup vertices for drawing */ glEnableClientState(GL_VERTEX_ARRAY); CaretAssert(glIsBuffer(coordBufferID)); glBindBuffer(GL_ARRAY_BUFFER, coordBufferID); glVertexPointer(openglData->m_coordinatesPerVertex, openglData->m_coordinateDataType, 0, (GLvoid*)0); /* * Setup normals for drawing */ if (openglData->m_normalVectorBufferObject != NULL) { glEnableClientState(GL_NORMAL_ARRAY); CaretAssert(glIsBuffer(openglData->m_normalVectorBufferObject->getBufferObjectName())); glBindBuffer(GL_ARRAY_BUFFER, openglData->m_normalVectorBufferObject->getBufferObjectName()); glNormalPointer(openglData->m_normalVectorDataType, 0, (GLvoid*)0); } else { glDisableClientState(GL_NORMAL_ARRAY); } bool hasColorFlag = false; switch (primitive->getColorDataType()) { case GraphicsPrimitive::ColorDataType::NONE: break; case GraphicsPrimitive::ColorDataType::FLOAT_RGBA: hasColorFlag = true; break; case GraphicsPrimitive::ColorDataType::UNSIGNED_BYTE_RGBA: hasColorFlag = true; break; } /* * Setup colors for drawing */ GLuint localColorBufferName = 0; if (hasColorFlag) { switch (drawMode) { case PrivateDrawMode::DRAW_NORMAL: { glEnableClientState(GL_COLOR_ARRAY); CaretAssert(glIsBuffer(openglData->m_colorBufferObject->getBufferObjectName())); glBindBuffer(GL_ARRAY_BUFFER, openglData->m_colorBufferObject->getBufferObjectName()); glColorPointer(openglData->m_componentsPerColor, openglData->m_colorDataType, 0, (GLvoid*)0); } break; case PrivateDrawMode::DRAW_SELECTION: { const int32_t numberOfVertices = primitive->m_xyz.size() / 3; if (numberOfVertices > 0) { glGenBuffers(1, &localColorBufferName); CaretAssert(localColorBufferName > 0); const GLint componentsPerColor = 4; const GLenum colorDataType = GL_UNSIGNED_BYTE; const std::vector selectionRGBA = primitiveSelectionHelper->getSelectionEncodedRGBA(); CaretAssert((selectionRGBA.size() / 4) == numberOfVertices); const GLuint colorSizeBytes = selectionRGBA.size() * sizeof(GLubyte); const GLvoid* colorDataPointer = (const GLvoid*)&selectionRGBA[0]; glBindBuffer(GL_ARRAY_BUFFER, localColorBufferName); glBufferData(GL_ARRAY_BUFFER, colorSizeBytes, colorDataPointer, GL_STREAM_DRAW); glEnableClientState(GL_COLOR_ARRAY); glColorPointer(componentsPerColor, colorDataType, 0, (GLvoid*)0); } } break; } } bool hasTextureFlag = false; switch (primitive->getTextureDataType()) { case GraphicsPrimitive::TextureDataType::NONE: break; case GraphicsPrimitive::TextureDataType::FLOAT_STR: hasTextureFlag = true; break; } /* * Setup textures for drawing */ if (hasTextureFlag && (drawMode == PrivateDrawMode::DRAW_NORMAL) && (openglData->m_textureImageDataName->getTextureName() > 0)) { glEnable(GL_TEXTURE_2D); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glBindTexture(GL_TEXTURE_2D, openglData->m_textureImageDataName->getTextureName()); glEnableClientState(GL_TEXTURE_COORD_ARRAY); CaretAssert(glIsBuffer(openglData->m_textureCoordinatesBufferObject->getBufferObjectName())); glBindBuffer(GL_ARRAY_BUFFER, openglData->m_textureCoordinatesBufferObject->getBufferObjectName()); glTexCoordPointer(3, openglData->m_textureCoordinatesDataType, 0, (GLvoid*)0); } /* * Unbind buffers */ glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); /* * Draw the primitive */ GLenum openGLPrimitiveType = GL_INVALID_ENUM; switch (primitive->m_primitiveType) { case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: openGLPrimitiveType = GL_LINE_LOOP; glLineWidth(getLineWidthForDrawingInPixels(primitive)); break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: openGLPrimitiveType = GL_LINE_STRIP; glLineWidth(getLineWidthForDrawingInPixels(primitive)); break; case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINES: case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: openGLPrimitiveType = GL_LINES; glLineWidth(getLineWidthForDrawingInPixels(primitive)); break; case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: openGLPrimitiveType = GL_POINTS; glPointSize(getPointDiameterForDrawingInPixels(primitive)); break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: openGLPrimitiveType = GL_TRIANGLE_FAN; break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: openGLPrimitiveType = GL_TRIANGLE_STRIP; break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: openGLPrimitiveType = GL_TRIANGLES; break; case GraphicsPrimitive::PrimitiveType::SPHERES: CaretAssertMessage(0, "SPHERES are not drawn with this method"); break; } CaretAssert(openGLPrimitiveType != GL_INVALID_ENUM); glDrawArrays(openGLPrimitiveType, 0, openglData->m_arrayIndicesCount); /* * Disable drawing */ glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); if (localColorBufferName > 0) { glDeleteBuffers(1, &localColorBufferName); } glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); } /** * Get the line width in pixels for drawing lines. * If the primitive's line width type is a percentage * of viewport height, convert it to pixels. * * @param primtive * The graphics primitive. * @return * Width of line in pixels. */ float GraphicsEngineDataOpenGL::getLineWidthForDrawingInPixels(const GraphicsPrimitive* primitive) { CaretAssert(primitive); float width = primitive->m_lineWidthValue; switch (primitive->m_lineWidthType) { case GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT: { GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); width = (viewport[3] * (width / 100.0f)); } break; case GraphicsPrimitive::LineWidthType::PIXELS: break; } return width; } /** * Get the point diameter in pixels for drawing points. * If the primitive's point diameter type is a percentage * of viewport height, convert it to pixels. * * @param primtive * The graphics primitive. * @return * Diameter of point in pixels. */ float GraphicsEngineDataOpenGL::getPointDiameterForDrawingInPixels(const GraphicsPrimitive* primitive) { CaretAssert(primitive); float pointSize = primitive->m_pointDiameterValue; switch (primitive->m_pointSizeType) { case GraphicsPrimitive::PointSizeType::MILLIMETERS: CaretAssert(0); /* millimeters not convertible to pixels */ break; case GraphicsPrimitive::PointSizeType::PERCENTAGE_VIEWPORT_HEIGHT: { GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); pointSize = (viewport[3] * (pointSize / 100.0f)); } break; case GraphicsPrimitive::PointSizeType::PIXELS: break; } return pointSize; } connectome-workbench-1.4.2/src/Graphics/GraphicsEngineDataOpenGL.h000066400000000000000000000126701360521144700250660ustar00rootroot00000000000000#ifndef __GRAPHICS_ENGINE_DATA_OPEN_G_L_H__ #define __GRAPHICS_ENGINE_DATA_OPEN_G_L_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretOpenGLInclude.h" #include "GraphicsEngineData.h" #include "GraphicsPrimitive.h" namespace caret { class GraphicsOpenGLBufferObject; class GraphicsOpenGLTextureName; class GraphicsPrimitive; class GraphicsPrimitiveSelectionHelper; class GraphicsEngineDataOpenGL : public GraphicsEngineData { public: GraphicsEngineDataOpenGL(); virtual ~GraphicsEngineDataOpenGL(); void deleteBuffers(); static void draw(GraphicsPrimitive* primitive); static void drawWithSelection(GraphicsPrimitive* primitive, const int32_t pixelX, const int32_t pixelY, int32_t& selectedPrimitiveIndexOut, float& selectedPrimitiveDepthOut); void invalidateCoordinates(); void invalidateColors(); // ADD_NEW_METHODS_HERE private: enum class PrivateDrawMode { DRAW_NORMAL, DRAW_SELECTION, }; enum SpaceMode { MODEL, WINDOW, }; GraphicsEngineDataOpenGL(const GraphicsEngineDataOpenGL&); GraphicsEngineDataOpenGL& operator=(const GraphicsEngineDataOpenGL&); void loadAllBuffers(GraphicsPrimitive* primitive); void loadCoordinateBuffer(GraphicsPrimitive* primitive); void loadNormalVectorBuffer(GraphicsPrimitive* primitive); void loadColorBuffer(GraphicsPrimitive* primitive); void loadTextureCoordinateBuffer(GraphicsPrimitive* primitive); void loadTextureImageDataBuffer(GraphicsPrimitive* primitive); static void drawPrivate(const PrivateDrawMode drawMode, GraphicsPrimitive* primitive, GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper); static void drawModelOrWindowSpace(const SpaceMode spaceMode, const PrivateDrawMode drawMode, GraphicsPrimitive* primitive, GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper); // static void drawWindowSpace(const PrivateDrawMode drawMode, // GraphicsPrimitive* primitive, // GraphicsPrimitiveSelectionHelper* primitiveSelectionHelper); static void drawPointsPrimitiveMillimeters(const GraphicsPrimitive* primitive); static void drawSpheresPrimitive(const GraphicsPrimitive* primitive); GLenum getOpenGLBufferUsageHint(const GraphicsPrimitive::UsageType primitiveUsageType) const; static float getLineWidthForDrawingInPixels(const GraphicsPrimitive* primitive); static float getPointDiameterForDrawingInPixels(const GraphicsPrimitive* primitive); static void saveOpenGLStateForWindowSpaceDrawing(int32_t polygonMode[2], int32_t viewport[4]); static void restoreOpenGLStateForWindowSpaceDrawing(int32_t polygonMode[2], int32_t viewport[4]); GLsizei m_arrayIndicesCount = 0; std::unique_ptr m_coordinateBufferObject; GLenum m_coordinateDataType = GL_FLOAT; GLint m_coordinatesPerVertex = 0; bool m_reloadCoordinatesFlag = false; bool m_reloadColorsFlag = false; std::unique_ptr m_normalVectorBufferObject; GLenum m_normalVectorDataType = GL_FLOAT; std::unique_ptr m_colorBufferObject; GLenum m_colorDataType = GL_FLOAT; GLint m_componentsPerColor = 0; std::unique_ptr m_textureCoordinatesBufferObject; GLenum m_textureCoordinatesDataType = GL_FLOAT; GraphicsOpenGLTextureName* m_textureImageDataName = NULL; // ADD_NEW_MEMBERS_HERE }; #ifdef __GRAPHICS_ENGINE_DATA_OPEN_G_L_DECLARE__ // #endif // __GRAPHICS_ENGINE_DATA_OPEN_G_L_DECLARE__ } // namespace #endif //__GRAPHICS_ENGINE_DATA_OPEN_G_L_H__ connectome-workbench-1.4.2/src/Graphics/GraphicsOpenGLBufferObject.cxx000066400000000000000000000042431360521144700257770ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GRAPHICS_OPEN_G_L_BUFFER_OBJECT_DECLARE__ #include "GraphicsOpenGLBufferObject.h" #undef __GRAPHICS_OPEN_G_L_BUFFER_OBJECT_DECLARE__ #include "CaretAssert.h" #include "EventGraphicsOpenGLDeleteBufferObject.h" #include "EventManager.h" using namespace caret; /** * \class caret::GraphicsOpenGLBufferObject * \brief Contains the OpenGL Buffer ID and the context in which it was created. * \ingroup Graphics */ /** * Constructor. * * @param openglContextPointer * Pointer to OpenGL context in which buffer object name was created. * @param bufferObjectName * The OpenGL buffer object name. */ GraphicsOpenGLBufferObject::GraphicsOpenGLBufferObject(void* openglContextPointer, const GLuint bufferObjectName) : CaretObject(), m_openglContextPointer(openglContextPointer), m_bufferObjectName(bufferObjectName) { } /** * Destructor. */ GraphicsOpenGLBufferObject::~GraphicsOpenGLBufferObject() { if (m_bufferObjectName > 0) { EventGraphicsOpenGLDeleteBufferObject deleteEvent(this); EventManager::get()->sendEvent(deleteEvent.getPointer()); } } /** * Get a description of this object's content. * @return String describing this object's content. */ AString GraphicsOpenGLBufferObject::toString() const { return "GraphicsOpenGLBufferObject"; } connectome-workbench-1.4.2/src/Graphics/GraphicsOpenGLBufferObject.h000066400000000000000000000045621360521144700254300ustar00rootroot00000000000000#ifndef __GRAPHICS_OPEN_G_L_BUFFER_OBJECT_H__ #define __GRAPHICS_OPEN_G_L_BUFFER_OBJECT_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretOpenGLInclude.h" #include "CaretObject.h" namespace caret { class GraphicsOpenGLBufferObject : public CaretObject { private: GraphicsOpenGLBufferObject(void* openglContextPointer, const GLuint bufferObjectName); public: virtual ~GraphicsOpenGLBufferObject(); /** * @return Pointer to OpenGL context in which buffer object was created. */ inline void* getOpenGLContextPointer() const { return m_openglContextPointer; } /** * @return The OpenGL Buffer Object Name. * While it is an unsigned interger, OpenGL refers to it as a "name". */ inline GLuint getBufferObjectName() const { return m_bufferObjectName; } // ADD_NEW_METHODS_HERE virtual AString toString() const; private: GraphicsOpenGLBufferObject(const GraphicsOpenGLBufferObject&); GraphicsOpenGLBufferObject& operator=(const GraphicsOpenGLBufferObject&); void* m_openglContextPointer = NULL; const GLuint m_bufferObjectName = 0; friend class BrainOpenGL; // ADD_NEW_MEMBERS_HERE }; #ifdef __GRAPHICS_OPEN_G_L_BUFFER_OBJECT_DECLARE__ // #endif // __GRAPHICS_OPEN_G_L_BUFFER_OBJECT_DECLARE__ } // namespace #endif //__GRAPHICS_OPEN_G_L_BUFFER_OBJECT_H__ connectome-workbench-1.4.2/src/Graphics/GraphicsOpenGLError.cxx000066400000000000000000000111011360521144700245170ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GRAPHICS_OPEN_G_L_ERROR_DECLARE__ #include "GraphicsOpenGLError.h" #undef __GRAPHICS_OPEN_G_L_ERROR_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::GraphicsOpenGLError * \brief Contains information about OpenGL Errors. * \ingroup Graphics */ /** * Constructor. */ GraphicsOpenGLError::GraphicsOpenGLError(const AString& userMessage) : CaretObject(), m_userMessage(userMessage) { glGetIntegerv(GL_PROJECTION_STACK_DEPTH, &m_projectionStackDepth); glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &m_modelviewStackDepth); glGetIntegerv(GL_NAME_STACK_DEPTH, &m_nameStackDepth); SystemUtilities::getBackTrace(m_backtrace); } /** * Destructor. */ GraphicsOpenGLError::~GraphicsOpenGLError() { } /** * Add an error code. * * @param errorCode */ void GraphicsOpenGLError::addError(const GLenum errorCode) { m_errorCodes.push_back(errorCode); } /** * @return Number of errors. OpenGL may have more than one error * available. Set the man page for glGetError(). */ int32_t GraphicsOpenGLError::getNumberOfErrors() const { return m_errorCodes.size(); } /** * @return Error code for the given error index. * * @param errorIndex * Error index. */ GLenum GraphicsOpenGLError::getErrorCode(const int32_t errorIndex) const { CaretAssertVectorIndex(m_errorCodes, errorIndex); return m_errorCodes[errorIndex]; } /** * @return Description for the given error index. * * @param errorIndex * Error index. */ AString GraphicsOpenGLError::getErrorDescription(const int32_t errorIndex) const { CaretAssertVectorIndex(m_errorCodes, errorIndex); AString description((char*)gluErrorString(m_errorCodes[errorIndex])); return description; } /** * @return String with verbose description of error information. * An empty string is returned if there are no errors. */ AString GraphicsOpenGLError::getVerboseDescription() const { if (m_errorCodes.empty()) { return ""; } AString msg; if ( ! m_userMessage.isEmpty()) { msg.appendWithNewLine(m_userMessage); } for (auto errorCode : m_errorCodes) { msg.appendWithNewLine("OpenGL Error: " + AString((char*)gluErrorString(errorCode)) + " (" + AString::number(static_cast(errorCode)) + ")"); } msg.appendWithNewLine("OpenGL Version: " + AString((char*)glGetString(GL_VERSION))); msg.appendWithNewLine("OpenGL Vendor: " + AString((char*)glGetString(GL_VENDOR))); GLint maxNameStackDepth, maxModelStackDepth, maxProjStackDepth; glGetIntegerv(GL_MAX_PROJECTION_STACK_DEPTH, &maxProjStackDepth); glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, &maxModelStackDepth); glGetIntegerv(GL_MAX_NAME_STACK_DEPTH, &maxNameStackDepth); msg.appendWithNewLine("Projection Matrix Stack Depth " + AString::number(m_projectionStackDepth) + " Max Depth " + AString::number(maxProjStackDepth)); msg.appendWithNewLine("Model Matrix Stack Depth " + AString::number(m_modelviewStackDepth) + " Max Depth " + AString::number(maxModelStackDepth)); msg.appendWithNewLine("Name Matrix Stack Depth " + AString::number(m_nameStackDepth) + " Max Depth " + AString::number(maxNameStackDepth)); msg.appendWithNewLine("Backtrace: " + m_backtrace.toSymbolString()); return msg; } connectome-workbench-1.4.2/src/Graphics/GraphicsOpenGLError.h000066400000000000000000000051621360521144700241560ustar00rootroot00000000000000#ifndef __GRAPHICS_OPEN_G_L_ERROR_H__ #define __GRAPHICS_OPEN_G_L_ERROR_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "CaretOpenGLInclude.h" namespace caret { class GraphicsOpenGLError : public CaretObject { public: GraphicsOpenGLError(const AString& userMessage); virtual ~GraphicsOpenGLError(); int32_t getNumberOfErrors() const; GLenum getErrorCode(const int32_t errorIndex) const; AString getErrorDescription(const int32_t errorIndex) const; // ADD_NEW_METHODS_HERE AString getVerboseDescription() const; private: // class ErrorInfo { // public: // ErrorInfo(const GLenum errorCode, // const AString errorDescription) // : m_errorCode(errorCode), // m_errorDescription(errorDescription) { } // // const GLenum m_errorCode; // // const AString m_errorDescription; // }; GraphicsOpenGLError(const GraphicsOpenGLError& obj); GraphicsOpenGLError& operator=(const GraphicsOpenGLError& obj); const AString m_userMessage; void addError(const GLenum errorCode); std::vector m_errorCodes; SystemBacktrace m_backtrace; int32_t m_projectionStackDepth = 0; int32_t m_modelviewStackDepth = 0; int32_t m_nameStackDepth = 0; // ADD_NEW_MEMBERS_HERE friend class GraphicsUtilitiesOpenGL; }; #ifdef __GRAPHICS_OPEN_G_L_ERROR_DECLARE__ // #endif // __GRAPHICS_OPEN_G_L_ERROR_DECLARE__ } // namespace #endif //__GRAPHICS_OPEN_G_L_ERROR_H__ connectome-workbench-1.4.2/src/Graphics/GraphicsOpenGLPolylineTriangles.cxx000066400000000000000000001520371360521144700271100ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __GRAPHICS_OPENGL_POLYLINE_TRIANGLES_DECLARE__ #include "GraphicsOpenGLPolylineTriangles.h" #undef __GRAPHICS_OPENGL_POLYLINE_TRIANGLES_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "GraphicsEngineDataOpenGL.h" #include "CaretOpenGLInclude.h" #include "GraphicsPrimitive.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GraphicsPrimitiveV3fC4ub.h" #include "EventManager.h" #include "EventOpenGLObjectToWindowTransform.h" #include "MathFunctions.h" using namespace caret; /** * \class caret::GraphicsOpenGLPolylineTriangles * \brief Converts lines to rectangles * \ingroup Graphics * * Convert lines to polygons. * OpenGL lines have a limited width whose maximum is often exceeded. * Convert the lines to rectangles. All drawing is done in * two dimensional windows coordinates. */ /** * Constructor. * * @param xyz * The XYZ vertices. * @param floatRGBA * The Float RGBA coloring. * @param byteRGBA * The Byte RGBA coloring. * @param vertexPrimitiveRestartIndices * Contains indices at which the primitive should restart. * The primitive will stop at the index and not connect to the next index. * @param lineThickness * Thickness of lines in (pixels when drawingSpace is WINDOW) * @param colorType * Type of color (solid or per-vertex) * @param drawingSpace * Drawing space * @param lineType * Type of lines drawn. * @param joinType * Type of joining for line loop and line strip */ GraphicsOpenGLPolylineTriangles::GraphicsOpenGLPolylineTriangles(const std::vector& xyz, const std::vector& floatRGBA, const std::vector& byteRGBA, const std::set& vertexPrimitiveRestartIndices, const float lineThickness, const ColorType colorType, const DrawingSpace drawingSpace, const LineType lineType, const JoinType joinType) : m_inputXYZ(xyz), m_inputFloatRGBA(floatRGBA), m_inputByteRGBA(byteRGBA), m_vertexPrimitiveRestartIndices(vertexPrimitiveRestartIndices), m_lineThickness(lineThickness), m_colorType(colorType), m_drawingSpace(drawingSpace), m_lineType(lineType), m_joinType(joinType) { } /** * Destructor. */ GraphicsOpenGLPolylineTriangles::~GraphicsOpenGLPolylineTriangles() { } /** * Convert a Workbench Line Primitive to an OpenGL primitive. * OpenGL has limits on the width of the lines that it draws. This method will * convert the lines into polygons so that any line width may be drawn. * * @param primitive * A graphics primitive with a primitive type that is one of the * WORKBENCH_LINE* types. * @param errorMessageOut * Upon exit contains an error message if conversion failed. * @return * A graphics primitive with an OPENGL_TRIANGLES type that draws the lines * using triangles. NULL if error. */ GraphicsPrimitive* GraphicsOpenGLPolylineTriangles::convertWorkbenchLinePrimitiveTypeToOpenGL(const GraphicsPrimitive* primitive, AString& errorMessageOut) { CaretAssert(primitive); errorMessageOut.clear(); if ( ! primitive->isValid()) { errorMessageOut = "Primitive is not valid."; return NULL; } float lineWidthPixels = primitive->m_lineWidthValue; switch (primitive->m_lineWidthType) { case GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT: { GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); lineWidthPixels = (lineWidthPixels / 100.0) * viewport[3]; } break; case GraphicsPrimitive::LineWidthType::PIXELS: break; } /* enforce a minimum line width */ const float minimumLineWidthPixels = 0.001f; if (lineWidthPixels < minimumLineWidthPixels) { lineWidthPixels = minimumLineWidthPixels; } ColorType colorType = ColorType::FLOAT_RGBA_PER_VERTEX; switch (primitive->m_colorDataType) { case GraphicsPrimitive::ColorDataType::NONE: errorMessageOut = "INVALID color type NONE for graphics primitive"; return NULL; break; case GraphicsPrimitive::ColorDataType::FLOAT_RGBA: colorType = ColorType::FLOAT_RGBA_PER_VERTEX; break; case GraphicsPrimitive::ColorDataType::UNSIGNED_BYTE_RGBA: colorType = ColorType::BYTE_RGBA_PER_VERTEX; break; } DrawingSpace drawingSpace = DrawingSpace::WINDOW; LineType lineType = LineType::LINES; JoinType joinType = JoinType::NONE; switch (primitive->m_primitiveType) { case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: errorMessageOut = "Input type is OPENGL_LINE_LOOP but must be one of the POLYGONAL_LINE* types"; break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: errorMessageOut = "Input type is OPENGL_LINE_STRIP but must be one of the POLYGONAL_LINE* types"; break; case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: errorMessageOut = "Input type is OPENGL_LINES but must be one of the POLYGONAL_LINE* types"; break; case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: errorMessageOut = "Input type is OPENGL_POINTS but must be one of the POLYGONAL_LINE* types"; break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: errorMessageOut = "Input type is OPENGL_TRIANGLE_FAN but must be one of the POLYGONAL_LINE* types"; break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: errorMessageOut = "Input type is OPENGL_TRIANGLE_STRIP but must be one of the POLYGONAL_LINE* types"; break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: errorMessageOut = "Input type is OPENGL_TRIANGLES but must be one of the POLYGONAL_LINE* types"; break; case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN: drawingSpace = DrawingSpace::MODEL_XY; lineType = LineType::LINE_LOOP; joinType = JoinType::BEVEL; break; case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN: drawingSpace = DrawingSpace::MODEL_XY; lineType = LineType::LINE_LOOP; joinType = JoinType::MITER; break; case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN: drawingSpace = DrawingSpace::MODEL_XY; lineType = LineType::LINE_STRIP; joinType = JoinType::BEVEL; break; case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN: drawingSpace = DrawingSpace::MODEL_XY; lineType = LineType::LINE_STRIP; joinType = JoinType::MITER; break; case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINES: drawingSpace = DrawingSpace::MODEL_XY; lineType = LineType::LINES; break; case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: lineType = LineType::LINE_LOOP; joinType = JoinType::BEVEL; break; case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: lineType = LineType::LINE_LOOP; joinType = JoinType::MITER; break; case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: lineType = LineType::LINE_STRIP; joinType = JoinType::BEVEL; break; case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: lineType = LineType::LINE_STRIP; joinType = JoinType::MITER; break; case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: lineType = LineType::LINES; break; case GraphicsPrimitive::PrimitiveType::SPHERES: errorMessageOut = "Input type is OPENGL_TRIANGLES but must be one of the POLYGONAL_LINE* types"; break; } if ( ! errorMessageOut.isEmpty()) { return NULL; } GraphicsOpenGLPolylineTriangles lineConversion(primitive->m_xyz, primitive->m_floatRGBA, primitive->m_unsignedByteRGBA, primitive->m_polygonalLinePrimitiveRestartIndices, lineWidthPixels, colorType, drawingSpace, lineType, joinType); GraphicsPrimitive* primitiveOut = lineConversion.convertLinesToPolygons(errorMessageOut); return primitiveOut; } /** * Convert the content of this instance to a new graphics primitive * that draws the lines as polygons. * * @param errorMessageOut * Contains error message if conversion failed. * @return * Pointer to new primitive or NULL if there is an error. * Caller must destroy the primitive. */ GraphicsPrimitive* GraphicsOpenGLPolylineTriangles::convertLinesToPolygons(AString& errorMessageOut) { errorMessageOut.clear(); const int32_t numVertices = static_cast(m_inputXYZ.size() / 3); if (numVertices < 2) { errorMessageOut = ("Invalid number of vertices=" + AString::number(numVertices) + " for line drawing. Must be at least 2."); return NULL; } const int32_t numFloatRGBA = static_cast(m_inputFloatRGBA.size()); const int32_t numByteRGBA = static_cast(m_inputByteRGBA.size()); switch (m_colorType) { case ColorType::BYTE_RGBA_PER_VERTEX: { const int32_t numRgbaVertices = numByteRGBA / 4; if (numVertices != numRgbaVertices) { errorMessageOut = ("Mismatch in vertices and coloring. There are " + AString::number(numVertices) + " vertices but have byte coloring for " + AString::number(numRgbaVertices) + " vertices"); return NULL; } } break; case ColorType::BYTE_RGBA_SOLID: if (numByteRGBA < 4) { errorMessageOut = ("Must have at last 4 color components for solid color line drawing" "Number of color components is " + AString::number(numByteRGBA)); return NULL; } break; case ColorType::FLOAT_RGBA_PER_VERTEX: { const int32_t numRgbaVertices = numFloatRGBA / 4; if (numVertices != numRgbaVertices) { errorMessageOut = ("Mismatch in vertices and coloring. There are " + AString::number(numVertices) + " vertices but have float coloring for " + AString::number(numRgbaVertices) + " vertices"); return NULL; } } break; case ColorType::FLOAT_RGBA_SOLID: if (numFloatRGBA < 4) { errorMessageOut = ("Must have at last 4 color components for solid color line drawing" "Number of color components is " + AString::number(numFloatRGBA)); return NULL; } break; } saveOpenGLState(); createTransform(); createWindowCoordinatesFromVertices(); const int32_t numWindowPoints = static_cast(m_vertexWindowXYZ.size() / 3); if (numWindowPoints >= 2) { convertLineSegmentsToTriangles(); } restoreOpenGLState(); GraphicsPrimitive* primitiveOut = NULL; if (m_primitive != NULL) { if (m_primitive->isValid()) { if (m_primitiveByteColor.get() != NULL) { primitiveOut = m_primitiveByteColor.release(); } else if (m_primitiveFloatColor.get() != NULL) { primitiveOut = m_primitiveFloatColor.release(); } else { CaretAssert(0); errorMessageOut = "Both Byte and Float Primitives are invalid, should never happen"; } } else { errorMessageOut = "Converted primitive is invalid."; } } else { errorMessageOut = "Primitive invalid, all points may be coincident"; } return primitiveOut; } /** * Save the OpenGL State. */ void GraphicsOpenGLPolylineTriangles::saveOpenGLState() { glPushAttrib(GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT | GL_HINT_BIT | GL_LIGHTING_BIT | GL_POLYGON_BIT); /* * For anti-aliasing requires sorting polygons * and turning of depth testing */ const bool drawWithAntiAliasingFlag = false; if (drawWithAntiAliasingFlag) { glBlendFunc (GL_SRC_ALPHA_SATURATE, GL_ONE); glEnable(GL_BLEND); glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); glEnable(GL_POLYGON_SMOOTH); } glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); glGetIntegerv(GL_POLYGON_MODE, m_savedPolygonMode); glGetIntegerv(GL_VIEWPORT, m_savedViewport); glMatrixMode(GL_PROJECTION); glPushMatrix(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); } /** * Restore the OpenGL State. */ void GraphicsOpenGLPolylineTriangles::restoreOpenGLState() { glPolygonMode(GL_FRONT, m_savedPolygonMode[0]); glPolygonMode(GL_BACK, m_savedPolygonMode[1]); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glViewport(m_savedViewport[0], m_savedViewport[1], m_savedViewport[2], m_savedViewport[3]); glPopAttrib(); } /** * Create the transform matrix. */ void GraphicsOpenGLPolylineTriangles::createTransform() { m_transformEvent.reset(new EventOpenGLObjectToWindowTransform(EventOpenGLObjectToWindowTransform::SpaceType::WINDOW)); EventManager::get()->sendEvent(m_transformEvent.get()->getPointer()); if ( ! m_transformEvent->isValid()) { CaretLogSevere("Getting OpenGL Transform Failed"); return; } } /** * Create window coordinates from the input vertices. */ void GraphicsOpenGLPolylineTriangles::createWindowCoordinatesFromVertices() { const float coincidentMaxDistSQ = (0.01f * 0.01f); GLdouble depthRange[2]; glGetDoublev(GL_DEPTH_RANGE, depthRange); GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); bool closeLoopFlag = false; int32_t numInputPoints = static_cast(m_inputXYZ.size() / 3); int32_t iStep = 1; switch (m_lineType) { case LineType::LINES: iStep = 2; if (MathFunctions::isOddNumber(numInputPoints)) { CaretLogWarning("Odd number of points for drawing line segment pairs, should be even number."); --numInputPoints; } break; case LineType::LINE_LOOP: closeLoopFlag = true; iStep = 1; if (numInputPoints > 3) { /* * For a loop, ignore the last point if it is the * same as the first point */ const int32_t lastOffset = (numInputPoints - 1) * 3; CaretAssertVectorIndex(m_inputXYZ, lastOffset + 2); const float distance = MathFunctions::distance3D(&m_inputXYZ[0], &m_inputXYZ[lastOffset]); if (distance < 0.0001f) { --numInputPoints; } } break; case LineType::LINE_STRIP: iStep = 1; break; } m_vertexWindowXYZ.reserve(numInputPoints * 3); m_vertexWindowInputIndices.reserve(numInputPoints); /* * Coincident points that result in zero length * line segments are filtered out */ for (int32_t i = 0; i < numInputPoints; i += iStep) { const int32_t i3 = i * 3; /* * Convert model coordinate to a window coordinate * as described by the documentation from gluProject(). */ float windowXYZ[3]; CaretAssertVectorIndex(m_inputXYZ, i3 + 1); convertFromModelToWindowCoordinate(&m_inputXYZ[i3], windowXYZ); if (iStep == 1) { if (i > 0) { const float previousPointOffset = (m_vertexWindowXYZ.size() - 3); CaretAssertVectorIndex(m_vertexWindowXYZ, previousPointOffset + 2); const float distSQ = MathFunctions::distanceSquared3D(windowXYZ, &m_vertexWindowXYZ[previousPointOffset]); if (distSQ < coincidentMaxDistSQ) { CaretLogFine("Filtered out connected segment conincident point index=" + AString::number(i) + " after conversion to window coordinates. " + AString::fromNumbers(windowXYZ, 3, ",") + " " + AString::fromNumbers(&m_vertexWindowXYZ[previousPointOffset], 3, ",")); continue; } } m_vertexWindowXYZ.push_back(windowXYZ[0]); m_vertexWindowXYZ.push_back(windowXYZ[1]); m_vertexWindowXYZ.push_back(windowXYZ[2]); m_vertexWindowInputIndices.push_back(i); } else if (iStep == 2) { const int32_t iNext3 = (i + 1) * 3; float windowNextXYZ[3]; CaretAssertVectorIndex(m_inputXYZ, iNext3 + 2); convertFromModelToWindowCoordinate(&m_inputXYZ[iNext3], windowNextXYZ); const float distSQ = MathFunctions::distanceSquared3D(windowXYZ, windowNextXYZ); if (distSQ < coincidentMaxDistSQ) { CaretLogFine("Filtered out line pairs conincident points " + AString::number(i) + " and " + AString::number(i + 1)); continue; } m_vertexWindowXYZ.push_back(windowXYZ[0]); m_vertexWindowXYZ.push_back(windowXYZ[1]); m_vertexWindowXYZ.push_back(windowXYZ[2]); m_vertexWindowInputIndices.push_back(i); m_vertexWindowXYZ.push_back(windowNextXYZ[0]); m_vertexWindowXYZ.push_back(windowNextXYZ[1]); m_vertexWindowXYZ.push_back(windowNextXYZ[2]); m_vertexWindowInputIndices.push_back(i + 1); } else { CaretAssertMessage(0, "Invalid step value"); } if (m_debugFlag) { GLdouble modelviewArray[16]; glGetDoublev(GL_MODELVIEW_MATRIX, modelviewArray); GLdouble projectionArray[16]; glGetDoublev(GL_PROJECTION_MATRIX, projectionArray); GLdouble winX, winY, winZ; gluProject(m_inputXYZ[i3], m_inputXYZ[i3+1], m_inputXYZ[i3+2], modelviewArray, projectionArray, viewport, &winX, &winY, &winZ); std::cout << "Input: " << m_inputXYZ[i3] << ", " << m_inputXYZ[i3+1] << ", " << m_inputXYZ[i3+2] << std::endl; std::cout << " Pt " << i << ": " << winX << ", " << winY << ", " << winZ << std::endl; std::cout << " gluProject " << winX << ", " << winY << ", " << winZ << std::endl; } } if (closeLoopFlag) { /* * Close by adding first two points to end (duplicates them). * Two points are necessary for the joins so that there is * not a gap where the last and first points connect. */ const int32_t numXYZ = (m_vertexWindowXYZ.size() / 3); if (numXYZ > 3) { const int32_t closeCount = 2; for (int32_t i = 0; i < (closeCount * 3); i++) { m_vertexWindowXYZ.push_back(m_vertexWindowXYZ[i]); } for (int32_t i = 0; i < closeCount; i++) { m_vertexWindowInputIndices.push_back(m_vertexWindowInputIndices[i]); } } } CaretAssert(m_vertexWindowXYZ.size() == (m_vertexWindowInputIndices.size() * 3)); } /** * Convert from a model coordinate to a window coordinate. * * @param modelXYZ * The coordinate in model space. * @param windowXYZOut * Output with coordinate in window space. */ void GraphicsOpenGLPolylineTriangles::convertFromModelToWindowCoordinate(const float modelXYZ[3], float windowXYZOut[3]) const { switch (m_drawingSpace) { case DrawingSpace::MODEL_XY: windowXYZOut[0] = modelXYZ[0]; windowXYZOut[1] = modelXYZ[1]; windowXYZOut[2] = modelXYZ[2]; break; case DrawingSpace::WINDOW: CaretAssert(m_transformEvent); m_transformEvent->transformPoint(modelXYZ, windowXYZOut); break; } } /** * Create two triangles from the two window vertices * * @param windowVertexOneIndex * Index of first window vertex at start of line * @param windowVertexTwoIndex * Index of second window vertex at end of line */ void GraphicsOpenGLPolylineTriangles::createTrianglesFromWindowVertices(const int32_t windowVertexOneIndex, const int32_t windowVertexTwoIndex) { const int32_t iOne3 = windowVertexOneIndex * 3; CaretAssertVectorIndex(m_vertexWindowXYZ, iOne3 + 2); const int32_t iTwo3 = windowVertexTwoIndex * 3; CaretAssertVectorIndex(m_vertexWindowXYZ, iTwo3 + 2); float x1 = m_vertexWindowXYZ[iOne3]; float y1 = m_vertexWindowXYZ[iOne3 + 1]; float z1 = m_vertexWindowXYZ[iOne3 + 2]; float x2 = m_vertexWindowXYZ[iTwo3]; float y2 = m_vertexWindowXYZ[iTwo3 + 1]; float z2 = m_vertexWindowXYZ[iTwo3 + 2]; /* * Normalized vector from start to end on line segment in 2D coordinates */ float startToEndVector[3] = { x2 - x1, y2 - y1, 0.0f }; const float lineLength = MathFunctions::normalizeVector(startToEndVector); if (lineLength < 0.001f) { const AString msg("This should not happen: Failure to filter coincident points with indices=" + AString::number(windowVertexOneIndex) + ", " + AString::number(windowVertexTwoIndex) + " Coordinates: " + AString::fromNumbers(&m_vertexWindowXYZ[iOne3], 3, ",") + " " + AString::fromNumbers(&m_vertexWindowXYZ[iTwo3], 3, ",")); #ifdef NDEBUG CaretLogFine(msg); #else CaretLogSevere(msg); #endif } /* * Create a perpendicualar vector to the line segment */ float perpendicularVector[3] = { startToEndVector[1], -startToEndVector[0], 0.0f }; /* * "Width" of rectangle */ const float halfWidth = m_lineThickness / 2.0f; const float halfWidthX = perpendicularVector[0] * halfWidth; const float halfWidthY = perpendicularVector[1] * halfWidth; /* * Points of the rectangle * They should be counter-clockwise oriented */ float p1[3] = { x1 - halfWidthX, y1 - halfWidthY, z1 }; float p2[3] = { x1 + halfWidthX, y1 + halfWidthY, z1 }; float p3[3] = { x2 + halfWidthX, y2 + halfWidthY, z2 }; float p4[3] = { x2 - halfWidthX, y2 - halfWidthY, z2 }; /* * Indices to input coloring. * Note that coincident points may be removed */ CaretAssertVectorIndex(m_vertexWindowInputIndices, windowVertexOneIndex); const int32_t indexOneRgba = m_vertexWindowInputIndices[windowVertexOneIndex]; CaretAssertVectorIndex(m_vertexWindowInputIndices, windowVertexTwoIndex); const int32_t indexTwoRgba = m_vertexWindowInputIndices[windowVertexTwoIndex]; /* * RGBA for the points P1, P2, P3, P4 */ int32_t rgbaOffsetP1P2 = 0; int32_t rgbaOffsetP3P4 = 0; switch (m_colorType) { case ColorType::BYTE_RGBA_PER_VERTEX: rgbaOffsetP1P2 = indexOneRgba * 4; rgbaOffsetP3P4 = indexTwoRgba * 4; break; case ColorType::BYTE_RGBA_SOLID: break; case ColorType::FLOAT_RGBA_PER_VERTEX: rgbaOffsetP1P2 = indexOneRgba * 4; rgbaOffsetP3P4 = indexTwoRgba * 4; break; case ColorType::FLOAT_RGBA_SOLID: break; } float crossProduct[3]; MathFunctions::crossProduct(startToEndVector, perpendicularVector, crossProduct); if (crossProduct[2] == 0.0f) { /* This should get caught by vector length check above */ } switch (m_colorType) { case ColorType::BYTE_RGBA_PER_VERTEX: case ColorType::BYTE_RGBA_SOLID: { CaretAssertVectorIndex(m_inputByteRGBA, rgbaOffsetP1P2 + 3); const uint8_t* rgbaP12 = &m_inputByteRGBA[rgbaOffsetP1P2]; CaretAssertVectorIndex(m_inputByteRGBA, rgbaOffsetP3P4 + 3); const uint8_t* rgbaP34 = &m_inputByteRGBA[rgbaOffsetP3P4]; CaretAssert(m_primitiveByteColor.get()); if (crossProduct[2] <= 0.0f) { m_primitiveByteColor->addVertex(p1, rgbaP12); m_primitiveByteColor->addVertex(p2, rgbaP12); m_primitiveByteColor->addVertex(p4, rgbaP34); m_primitiveByteColor->addVertex(p2, rgbaP12); m_primitiveByteColor->addVertex(p3, rgbaP34); m_primitiveByteColor->addVertex(p4, rgbaP34); } else { if (m_debugFlag) std::cout << "Flipped Quad" << std::endl; m_primitiveByteColor->addVertex(p2, rgbaP12); m_primitiveByteColor->addVertex(p1, rgbaP12); m_primitiveByteColor->addVertex(p3, rgbaP34); m_primitiveByteColor->addVertex(p1, rgbaP12); m_primitiveByteColor->addVertex(p4, rgbaP34); m_primitiveByteColor->addVertex(p3, rgbaP34); } } break; case ColorType::FLOAT_RGBA_PER_VERTEX: case ColorType::FLOAT_RGBA_SOLID: { CaretAssertVectorIndex(m_inputFloatRGBA, rgbaOffsetP1P2 + 3); const float* rgbaP12 = &m_inputFloatRGBA[rgbaOffsetP1P2]; CaretAssertVectorIndex(m_inputFloatRGBA, rgbaOffsetP3P4 + 3); const float* rgbaP34 = &m_inputFloatRGBA[rgbaOffsetP3P4]; CaretAssert(m_primitiveFloatColor.get()); if (crossProduct[2] <= 0.0f) { m_primitiveFloatColor->addVertex(p1, rgbaP12); m_primitiveFloatColor->addVertex(p2, rgbaP12); m_primitiveFloatColor->addVertex(p4, rgbaP34); m_primitiveFloatColor->addVertex(p2, rgbaP12); m_primitiveFloatColor->addVertex(p3, rgbaP34); m_primitiveFloatColor->addVertex(p4, rgbaP34); } else { if (m_debugFlag) std::cout << "Flipped Quad" << std::endl; m_primitiveFloatColor->addVertex(p2, rgbaP12); m_primitiveFloatColor->addVertex(p1, rgbaP12); m_primitiveFloatColor->addVertex(p3, rgbaP34); m_primitiveFloatColor->addVertex(p1, rgbaP12); m_primitiveFloatColor->addVertex(p4, rgbaP34); m_primitiveFloatColor->addVertex(p3, rgbaP34); } } break; } const int32_t numVertices = m_primitive->getNumberOfVertices(); const int32_t triangleOneIndices[3] = { numVertices - 6, numVertices - 5, numVertices - 4 }; const int32_t triangleTwoIndices[3] = { numVertices - 3, numVertices - 2, numVertices - 1 }; PolylineInfo polyLine(windowVertexOneIndex, windowVertexTwoIndex, triangleOneIndices, triangleTwoIndices); if (m_lastPolyLineInfo.m_valid) { joinTwoPolyLines(m_lastPolyLineInfo, polyLine); } m_lastPolyLineInfo = polyLine; } /** * Join two polylines by filling in the gaps where the * polylines meet. * * @param polyOne * The first polyline. * @param polyTwo * The two polyline. */ void GraphicsOpenGLPolylineTriangles::joinTwoPolyLines(const PolylineInfo& polyOne, const PolylineInfo& polyTwo) { CaretAssert(m_primitive); switch (m_joinType) { case JoinType::BEVEL: break; case JoinType::MITER: break; case JoinType::NONE: return; break; } switch (m_lineType) { case LineType::LINES: return; break; case LineType::LINE_LOOP: break; case LineType::LINE_STRIP: break; } /* * Does triangle "i" connect to triangle "i+1" ? */ if (polyOne.m_windowVertexTwoIndex == polyTwo.m_windowVertexOneIndex) { switch (m_joinType) { case JoinType::BEVEL: performBevelJoin(polyOne, polyTwo); break; case JoinType::MITER: performMiterJoin(polyOne, polyTwo); break; case JoinType::NONE: break; } } addJoinTriangles(); } /** * Determine the turn direction at the connection point of two line segments. * * @param polyOne * Info about first polyline * @param polyTwo * Info about second polyline * @return * The turn direction. */ GraphicsOpenGLPolylineTriangles::TurnDirection GraphicsOpenGLPolylineTriangles::getTurnDirection(const PolylineInfo& polyOne, const PolylineInfo& polyTwo) const { TurnDirection turnDirection = TurnDirection::PARALLEL; const int32_t windowVertexIndexOne = polyOne.m_windowVertexOneIndex; const int32_t windowVertexIndexTwo = polyOne.m_windowVertexTwoIndex; const int32_t windowVertexIndexThree = polyTwo.m_windowVertexTwoIndex; if (m_debugFlag) std::cout << "Turn Direction: " << windowVertexIndexOne << ", " << windowVertexIndexTwo << ", " << windowVertexIndexThree << std::endl; CaretAssert(m_primitive); /* * Determine if the junction of the two consecutive * line segments in window coordinates makes a left * or right turn */ CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexOne * 3) + 2); CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexTwo * 3) + 2); CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexThree * 3) + 2); const float signedArea = MathFunctions::triangleAreaSigned2D(&m_vertexWindowXYZ[windowVertexIndexOne * 3], &m_vertexWindowXYZ[windowVertexIndexTwo * 3], &m_vertexWindowXYZ[windowVertexIndexThree * 3]); const float smallNumber = 0.0f; if (signedArea > smallNumber) { turnDirection = TurnDirection::LEFT; } else if (signedArea < -smallNumber) { turnDirection = TurnDirection::RIGHT; } else { turnDirection = TurnDirection::PARALLEL; } return turnDirection; } /** * Join the second triangle in poly one to poly two with a bevel join. * A triangle is added that connects the outside corners of the * two polylines. * * @param polyOne * Info about triangles in first polyline * @param polyTwo * Info about triangles in second polyline */ void GraphicsOpenGLPolylineTriangles::performBevelJoin(const PolylineInfo& polyOne, const PolylineInfo& polyTwo) { const TurnDirection turnDirection = getTurnDirection(polyOne, polyTwo); const int32_t windowVertexIndexTwo = polyOne.m_windowVertexTwoIndex; if (m_debugFlag) { const int32_t windowVertexIndexOne = polyOne.m_windowVertexOneIndex; const int32_t windowVertexIndexThree = polyTwo.m_windowVertexTwoIndex; std::cout << "Join: " << windowVertexIndexOne << ", " << windowVertexIndexTwo << ", " << windowVertexIndexThree << std::endl; } CaretAssert(m_primitive); /* * Determine if the junction of the two consecutive * line segments in window coordinates makes a left * or right turn */ CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexTwo * 3) + 2); int32_t quadOneSideEndVertexIndex = -1; int32_t quadTwoSideBeginVertexIndex = -1; switch (turnDirection) { case TurnDirection::LEFT: if (m_debugFlag) std::cout << " Left Turn" << std::endl; /* * Join the right side that is first two vertices in triangle two */ quadOneSideEndVertexIndex = polyOne.m_triangleTwoPrimitiveIndices[1]; quadTwoSideBeginVertexIndex = polyTwo.m_triangleTwoPrimitiveIndices[0]; break; case TurnDirection::PARALLEL: if (m_debugFlag) std::cout << " Parallel" << std::endl; return; break; case TurnDirection::RIGHT: if (m_debugFlag) std::cout << " Right Turn" << std::endl; /* * Join left side that is first and third vertices in triangle one */ quadOneSideEndVertexIndex = polyOne.m_triangleOnePrimitiveIndices[2]; quadTwoSideBeginVertexIndex = polyTwo.m_triangleOnePrimitiveIndices[0]; break; } /* * Add a triangle to fill in the gap */ m_triangleJoins.push_back(TriangleJoin(windowVertexIndexTwo, quadOneSideEndVertexIndex, quadTwoSideBeginVertexIndex)); } /** * Join the second triangle in poly one to poly two with a miter join. * A miter join extends the 'outside' edges of the turn to their intersection. * If the angle is sharp (very small) this intersection may be long way * from the original vertex. The miter limit keeps this from happening by * extending the intersection just a little bit and adding essentially a * bevel-like join. * * @param polyOne * Info about triangles in first polyline * @param polyTwo * Info about triangles in second polyline */ void GraphicsOpenGLPolylineTriangles::performMiterJoin(const PolylineInfo& polyOne, const PolylineInfo& polyTwo) { const TurnDirection turnDirection = getTurnDirection(polyOne, polyTwo); const int32_t windowVertexIndexTwo = polyOne.m_windowVertexTwoIndex; if (m_debugFlag) { const int32_t windowVertexIndexOne = polyOne.m_windowVertexOneIndex; const int32_t windowVertexIndexThree = polyTwo.m_windowVertexTwoIndex; std::cout << "Miter Join: " << windowVertexIndexOne << ", " << windowVertexIndexTwo << ", " << windowVertexIndexThree << std::endl; } CaretAssert(m_primitive); /* * Determine if the junction of the two consecutive * line segments in window coordinates makes a left * or right turn */ CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexTwo * 3) + 2); int32_t quadOneSideBeginVertexIndex = -1; int32_t quadOneSideEndVertexIndex = -1; int32_t quadTwoSideBeginVertexIndex = -1; int32_t quadTwoSideEndVertexIndex = -1; bool leftTurnFlag = false; switch (turnDirection) { case TurnDirection::LEFT: leftTurnFlag = true; if (m_debugFlag) std::cout << " Miter Left Turn" << std::endl; /* * Join the right side that is first two vertices in triangle two */ quadOneSideBeginVertexIndex = polyOne.m_triangleTwoPrimitiveIndices[0]; quadOneSideEndVertexIndex = polyOne.m_triangleTwoPrimitiveIndices[1]; quadTwoSideBeginVertexIndex = polyTwo.m_triangleTwoPrimitiveIndices[0]; quadTwoSideEndVertexIndex = polyTwo.m_triangleTwoPrimitiveIndices[1]; break; case TurnDirection::PARALLEL: if (m_debugFlag) std::cout << " Miter Parallel" << std::endl; return; break; case TurnDirection::RIGHT: leftTurnFlag = false; if (m_debugFlag) std::cout << " Miter Right Turn" << std::endl; /* * Join left side that is first and third vertices in triangle one */ quadOneSideBeginVertexIndex = polyOne.m_triangleOnePrimitiveIndices[0]; quadOneSideEndVertexIndex = polyOne.m_triangleOnePrimitiveIndices[2]; quadTwoSideBeginVertexIndex = polyTwo.m_triangleOnePrimitiveIndices[0]; quadTwoSideEndVertexIndex = polyTwo.m_triangleOnePrimitiveIndices[2]; break; } const std::vector& xyz = m_primitive->getFloatXYZ(); CaretAssertVectorIndex(xyz, (quadOneSideBeginVertexIndex * 3) + 2); CaretAssertVectorIndex(xyz, (quadOneSideEndVertexIndex * 3) + 2); CaretAssertVectorIndex(xyz, (quadTwoSideBeginVertexIndex * 3) + 2); CaretAssertVectorIndex(xyz, (quadTwoSideEndVertexIndex * 3) + 2); const float* q1v1 = &xyz[quadOneSideBeginVertexIndex * 3]; const float* q1v2 = &xyz[quadOneSideEndVertexIndex * 3]; const float* q2v1 = &xyz[quadTwoSideBeginVertexIndex * 3]; const float* q2v2 = &xyz[quadTwoSideEndVertexIndex * 3]; /* * Miter limit is a multiple of the line thickness */ const float miterLimit = m_lineThickness; const float miterLimitSquared = miterLimit * miterLimit; /* * Find location of where the edges in the quads intersect */ float intersectionXYZ[3]; if (MathFunctions::vectorIntersection2D(q1v1, q1v2, q2v1, q2v2, 0.0f, intersectionXYZ)) { intersectionXYZ[2] = q1v1[2]; if (m_debugFlag) std::cout << " Miter Intersection: " << AString::fromNumbers(intersectionXYZ, 3, ",") << std::endl; /* * When the angle is very sharp, the miter point can be very long and pointy * so limit to a multiplier of the line thickness */ CaretAssertVectorIndex(m_vertexWindowXYZ, (windowVertexIndexTwo * 3) + 2); const float* joinPointXYZ = &m_vertexWindowXYZ[(windowVertexIndexTwo * 3)]; const float distanceSquared = MathFunctions::distanceSquared3D(joinPointXYZ, intersectionXYZ); if (distanceSquared > miterLimitSquared) { /* * Extend lines by the miter limit to create a new quad */ float newV1[3]; createMiterJoinVertex(q1v1, q1v2, miterLimit, newV1); float newV2[3]; createMiterJoinVertex(q2v2, q2v1, miterLimit, newV2); /* * Extend vertices to the new miter limit */ int32_t primitiveIndexV1 = -1; int32_t primitiveIndexV2 = -1; if (leftTurnFlag) { m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleTwoPrimitiveIndices[1], newV1); primitiveIndexV1 = polyOne.m_triangleTwoPrimitiveIndices[1]; m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleOnePrimitiveIndices[1], newV2); primitiveIndexV2 = polyTwo.m_triangleOnePrimitiveIndices[1]; m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleTwoPrimitiveIndices[0], newV2); } else { m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleTwoPrimitiveIndices[2], newV1); primitiveIndexV1 = polyOne.m_triangleTwoPrimitiveIndices[2]; m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleOnePrimitiveIndices[2], newV1); m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleOnePrimitiveIndices[0], newV2); primitiveIndexV2 = polyTwo.m_triangleOnePrimitiveIndices[0]; } /* * Add a triangle to fill in the gap */ m_triangleJoins.push_back(TriangleJoin(windowVertexIndexTwo, primitiveIndexV1, primitiveIndexV2)); } else { /* * Move the existing quad vertices to their intersection point */ if (leftTurnFlag) { m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleTwoPrimitiveIndices[1], intersectionXYZ); m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleOnePrimitiveIndices[1], intersectionXYZ); m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleTwoPrimitiveIndices[0], intersectionXYZ); } else { m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleTwoPrimitiveIndices[2], intersectionXYZ); m_primitive->replaceVertexFloatXYZ(polyOne.m_triangleOnePrimitiveIndices[2], intersectionXYZ); m_primitive->replaceVertexFloatXYZ(polyTwo.m_triangleOnePrimitiveIndices[0], intersectionXYZ); } } } } /** * Create a vertex for a miter join when the length limit is exceeded * * @param v1 * First vertex * @param v2 * Second vertex that is connected to the miter join vertex. * @param miterLength * Length of output vertex from v2 * @param xyzOut * Output with vertex used for miter join. */ void GraphicsOpenGLPolylineTriangles::createMiterJoinVertex(const float v1[3], const float v2[3], const float miterLength, float xyzOut[3]) { float n2[3]; MathFunctions::subtractVectors(v2, v1, n2); MathFunctions::normalizeVector(n2); n2[0] *= miterLength; n2[1] *= miterLength; n2[2] *= miterLength; xyzOut[0] = v2[0] + n2[0]; xyzOut[1] = v2[1] + n2[1]; xyzOut[2] = v2[2] + n2[2]; } /** * Get the average color from two vertices. * * @param primitiveVertexOneIndex * The first primitive vertex index. * @param primitiveVertexTwoIndex * The second primitive vertex index. * @param rgbaOut * Output with average RGBA. */ void GraphicsOpenGLPolylineTriangles::getAverageColorRGBA(const int32_t primitiveVertexOneIndex, const int32_t primitiveVertexTwoIndex, float rgbaOut[4]) const { CaretAssert(m_primitiveFloatColor); float rgbaOne[4]; m_primitiveFloatColor->getVertexFloatRGBA(primitiveVertexOneIndex, rgbaOne); float rgbaTwo[4]; m_primitiveFloatColor->getVertexFloatRGBA(primitiveVertexTwoIndex, rgbaTwo); rgbaOut[0] = (rgbaOne[0] + rgbaTwo[0]) / 2.0f; rgbaOut[1] = (rgbaOne[1] + rgbaTwo[1]) / 2.0f; rgbaOut[2] = (rgbaOne[2] + rgbaTwo[2]) / 2.0f; rgbaOut[3] = (rgbaOne[3] + rgbaTwo[3]) / 2.0f; } /** * Get the average color from two vertices. * * @param primitiveVertexOneIndex * The first primitive vertex index. * @param primitiveVertexTwoIndex * The second primitive vertex index. * @param rgbaOut * Output with average RGBA. */ void GraphicsOpenGLPolylineTriangles::getAverageColorRGBA(const int32_t primitiveVertexOneIndex, const int32_t primitiveVertexTwoIndex, uint8_t rgbaOut[4]) const { CaretAssert(m_primitiveByteColor); /* * Since byte colors range [0, 255], adding two bytes could * cause an overflow of the byte. So average using floats * and then assign to the byte output. */ uint8_t rgbaOneByte[4]; m_primitiveByteColor->getVertexByteRGBA(primitiveVertexOneIndex, rgbaOneByte); float rgbaOne[4] = { (float)rgbaOneByte[0], (float)rgbaOneByte[1], (float)rgbaOneByte[2], (float)rgbaOneByte[3] }; uint8_t rgbaTwoByte[4]; m_primitiveByteColor->getVertexByteRGBA(primitiveVertexTwoIndex, rgbaTwoByte); float rgbaTwo[4] = { (float)rgbaTwoByte[0], (float)rgbaTwoByte[1], (float)rgbaTwoByte[2], (float)rgbaTwoByte[3] }; rgbaOut[0] = static_cast((rgbaOne[0] + rgbaTwo[0]) / 2.0f); rgbaOut[1] = static_cast((rgbaOne[1] + rgbaTwo[1]) / 2.0f); rgbaOut[2] = static_cast((rgbaOne[2] + rgbaTwo[2]) / 2.0f); rgbaOut[3] = static_cast((rgbaOne[3] + rgbaTwo[3]) / 2.0f); } /** * Add triangles creating by joins to fill gaps * at the junctions of the line segments */ void GraphicsOpenGLPolylineTriangles::addJoinTriangles() { for (const auto tj : m_triangleJoins) { CaretAssertVectorIndex(m_vertexWindowXYZ, tj.m_windowVertexIndex * 3 + 2); const float* v1 = &m_vertexWindowXYZ[tj.m_windowVertexIndex*3]; const std::vector& xyz = m_primitive->getFloatXYZ(); CaretAssertVectorIndex(xyz, tj.m_primitiveVertexOneIndex * 3 + 2); CaretAssertVectorIndex(xyz, tj.m_primitiveVertexTwoIndex * 3 + 2); const float* v2 = &xyz[tj.m_primitiveVertexOneIndex * 3]; const float* v3 = &xyz[tj.m_primitiveVertexTwoIndex * 3]; /* * If signed area is positive, the triangle is correctly oriented; * otherwise, flip the vertices */ const float signedArea = MathFunctions::triangleAreaSigned2D(v1, v2, v3); const float smallNumber = 0.0f; const bool normalOutFlag = (signedArea > smallNumber); const float* tv2 = (normalOutFlag ? v2 : v3); const float* tv3 = (normalOutFlag ? v3 : v2); switch (m_primitive->getColorDataType()) { case GraphicsPrimitive::ColorDataType::NONE: CaretAssert(0); break; case GraphicsPrimitive::ColorDataType::FLOAT_RGBA: { float rgba[4]; getAverageColorRGBA(tj.m_primitiveVertexOneIndex, tj.m_primitiveVertexTwoIndex, rgba); m_primitiveFloatColor->addVertex(v1, rgba); m_primitiveFloatColor->addVertex(tv2, rgba); m_primitiveFloatColor->addVertex(tv3, rgba); } break; case GraphicsPrimitive::ColorDataType::UNSIGNED_BYTE_RGBA: { uint8_t rgba[4]; getAverageColorRGBA(tj.m_primitiveVertexOneIndex, tj.m_primitiveVertexTwoIndex, rgba); m_primitiveByteColor->addVertex(v1, rgba); m_primitiveByteColor->addVertex(tv2, rgba); m_primitiveByteColor->addVertex(tv3, rgba); } break; } } m_triangleJoins.clear(); } /** * Convert each line segment into two triangles * using the line width. "Length" of the * two triangles is the length of the line segment * and "width" of the two triangles is the line width. */ void GraphicsOpenGLPolylineTriangles::convertLineSegmentsToTriangles() { const int32_t numVertices = static_cast(m_vertexWindowXYZ.size() / 3); /* * When estimating number of triangles, * include both the triangles formed by the vertices * and possible triangles added for joining end points */ int32_t estimatedNumberOfQuads = 0; int32_t maximumNumberOfJoinTriangles = 0; switch (m_lineType) { case LineType::LINES: estimatedNumberOfQuads = numVertices / 2; maximumNumberOfJoinTriangles = 0; break; case LineType::LINE_LOOP: estimatedNumberOfQuads = numVertices * 2; maximumNumberOfJoinTriangles = numVertices; break; case LineType::LINE_STRIP: estimatedNumberOfQuads = (numVertices - 1) * 2; maximumNumberOfJoinTriangles = numVertices - 1; break; } int32_t estimatedNumberOfTriangles = ((estimatedNumberOfQuads * 2) + maximumNumberOfJoinTriangles); const int32_t estimatedNumberOfVertices = estimatedNumberOfTriangles * 3; m_primitive = NULL; switch (m_colorType) { case ColorType::BYTE_RGBA_PER_VERTEX: case ColorType::BYTE_RGBA_SOLID: m_primitiveByteColor.reset(GraphicsPrimitive::newPrimitiveV3fC4ub(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES)); m_primitiveByteColor->reserveForNumberOfVertices(estimatedNumberOfVertices); m_primitive = m_primitiveByteColor.get(); break; case ColorType::FLOAT_RGBA_PER_VERTEX: case ColorType::FLOAT_RGBA_SOLID: m_primitiveFloatColor.reset(GraphicsPrimitive::newPrimitiveV3fC4f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES)); m_primitiveFloatColor->reserveForNumberOfVertices(estimatedNumberOfVertices); m_primitive = m_primitiveFloatColor.get(); break; } CaretAssert(m_primitive); m_primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); const int32_t numVerticesMinusOne = numVertices - 1; std::vector restartVertexFlags(numVertices, false); for (auto index : m_vertexPrimitiveRestartIndices) { /* * The caller may add a primtive restart at the last vertex * which may be equal to numVertices. */ if (index < numVertices) { CaretAssertVectorIndex(restartVertexFlags, index); restartVertexFlags[index] = true; } } const bool restartEnabledFlag = true; switch (m_lineType) { case LineType::LINES: { const int32_t numLineSegments = (numVertices / 2); for (int32_t i = 0; i < numLineSegments; i++) { const int32_t i2 = i * 2; createTrianglesFromWindowVertices(i2, i2 + 1); } } break; case LineType::LINE_LOOP: for (int32_t i = 0; i < numVerticesMinusOne; i++) { CaretAssertVectorIndex(restartVertexFlags, i + 1); if (restartVertexFlags[i + 1]) { if (restartEnabledFlag) continue; } createTrianglesFromWindowVertices(i, i + 1); } createTrianglesFromWindowVertices(numVerticesMinusOne, 0); break; case LineType::LINE_STRIP: for (int32_t i = 0; i < numVerticesMinusOne; i++) { CaretAssertVectorIndex(restartVertexFlags, i + 1); if (restartVertexFlags[i + 1]) { if (restartEnabledFlag) continue; } createTrianglesFromWindowVertices(i, i + 1); } break; } } /** * Get a description of this object's content. * @return String describing this object's content. */ AString GraphicsOpenGLPolylineTriangles::toString() const { return "GraphicsOpenGLPolylineTriangles"; } connectome-workbench-1.4.2/src/Graphics/GraphicsOpenGLPolylineTriangles.h000066400000000000000000000241201360521144700265240ustar00rootroot00000000000000#ifndef __GRAPHICS_OPENGL_POLYLINE_TRIANGLES_H__ #define __GRAPHICS_OPENGL_POLYLINE_TRIANGLES_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretObject.h" namespace caret { class EventOpenGLObjectToWindowTransform; class GraphicsPrimitive; class GraphicsPrimitiveV3fC4f; class GraphicsPrimitiveV3fC4ub; class GraphicsOpenGLPolylineTriangles : public CaretObject { public: virtual ~GraphicsOpenGLPolylineTriangles(); static GraphicsPrimitive* convertWorkbenchLinePrimitiveTypeToOpenGL(const GraphicsPrimitive* primitive, AString& errorMessageOut); // ADD_NEW_METHODS_HERE virtual AString toString() const; private: /** * Type of line coloring */ enum class ColorType { /** Byte RGBA color at each vertex */ BYTE_RGBA_PER_VERTEX, /** One Byte RGBA color for all vertices */ BYTE_RGBA_SOLID, /** Float RGBA color at each vertex */ FLOAT_RGBA_PER_VERTEX, /** One Float RGBA color for all vertices */ FLOAT_RGBA_SOLID }; /** * Drawing space */ enum class DrawingSpace { /** * Lines are drawn using the current modeling transformations in * the XY plane. Z-coordinates should all be the same. */ MODEL_XY, /** * Coordinates of the lines are converted into window (pixel) coordinates * and the lines are drawn in 'window space'. The lines always * face the user even with rotations. */ WINDOW }; /** * Join tyupe of how connected lines are drawn to remove gaps between segments */ enum class JoinType { /** None */ NONE, /** Bevel fills the gap by adding a triangle */ BEVEL, /** Miter extends 'outsides' of lines to meet forming a pointed shape */ MITER }; /** * Type of line drawing */ enum class LineType { /** Each pair of vertices is an independent line segment (GL_LINES) */ LINES, /** A connected set of lines forming a loop (last is automatically connected to first) */ LINE_LOOP, /** A connected set of lines (last is not connected to first) */ LINE_STRIP }; /** * Turn direction add joint vertex of two lines */ enum class TurnDirection { /** Turns left */ LEFT, /** Does not turn (straight) or coincident */ PARALLEL, /** Turns right */ RIGHT, }; /** * Indices into input vertices of line * that formed the polyline */ class PolylineInfo { public: PolylineInfo() { } PolylineInfo(const int32_t windowVertexOneIndex, const int32_t windowVertexTwoIndex, const int32_t triangleOnePrimitiveIndices[3], const int32_t triangleTwoPrimitiveIndices[3]) : m_windowVertexOneIndex(windowVertexOneIndex), m_windowVertexTwoIndex(windowVertexTwoIndex) { m_triangleOnePrimitiveIndices[0] = triangleOnePrimitiveIndices[0]; m_triangleOnePrimitiveIndices[1] = triangleOnePrimitiveIndices[1]; m_triangleOnePrimitiveIndices[2] = triangleOnePrimitiveIndices[2]; m_triangleTwoPrimitiveIndices[0] = triangleTwoPrimitiveIndices[0]; m_triangleTwoPrimitiveIndices[1] = triangleTwoPrimitiveIndices[1]; m_triangleTwoPrimitiveIndices[2] = triangleTwoPrimitiveIndices[2]; m_valid = true; } int32_t m_windowVertexOneIndex; int32_t m_windowVertexTwoIndex; int32_t m_triangleOnePrimitiveIndices[3]; int32_t m_triangleTwoPrimitiveIndices[3]; bool m_valid = false; }; /** * Triangles created by joining of polylines */ class TriangleJoin { public: TriangleJoin(const int32_t windowVertexIndex, const int32_t primitiveVertexOneIndex, const int32_t primitiveVertexTwoIndex) : m_windowVertexIndex(windowVertexIndex), m_primitiveVertexOneIndex(primitiveVertexOneIndex), m_primitiveVertexTwoIndex(primitiveVertexTwoIndex) { } const int32_t m_windowVertexIndex; const int32_t m_primitiveVertexOneIndex; const int32_t m_primitiveVertexTwoIndex; }; GraphicsOpenGLPolylineTriangles(const std::vector& xyz, const std::vector& floatRGBA, const std::vector& byteRGBA, const std::set& vertexPrimitiveRestartIndices, const float lineThickness, const ColorType colorType, const DrawingSpace drawingSpace, const LineType lineType, const JoinType joinType); GraphicsOpenGLPolylineTriangles(const GraphicsOpenGLPolylineTriangles& obj); GraphicsOpenGLPolylineTriangles& operator=(const GraphicsOpenGLPolylineTriangles& obj) const; GraphicsPrimitive* convertLinesToPolygons(AString& errorMessageOut); void saveOpenGLState(); void restoreOpenGLState(); void createTransform(); void convertFromModelToWindowCoordinate(const float modelXYZ[3], float windowXYZOut[3]) const; void createWindowCoordinatesFromVertices(); void convertLineSegmentsToTriangles(); void createTrianglesFromWindowVertices(const int32_t windowVertexOneIndex, const int32_t windowVertexTwoIndex); void performBevelJoin(const PolylineInfo& polyOne, const PolylineInfo& polyTwo); void performMiterJoin(const PolylineInfo& polyOne, const PolylineInfo& polyTwo); void joinTwoPolyLines(const PolylineInfo& polyOne, const PolylineInfo& polyTwo); void addJoinTriangles(); void createMiterJoinVertex(const float v1[3], const float v2[3], const float miterLength, float xyzOut[3]); TurnDirection getTurnDirection(const PolylineInfo& polyOne, const PolylineInfo& polyTwo) const; void getAverageColorRGBA(const int32_t primitiveVertexOneIndex, const int32_t primitiveVertexTwoIndex, float rgbaOut[4]) const; void getAverageColorRGBA(const int32_t primitiveVertexOneIndex, const int32_t primitiveVertexTwoIndex, uint8_t rgbaOut[4]) const; const std::vector& m_inputXYZ; const std::vector& m_inputFloatRGBA; const std::vector& m_inputByteRGBA; std::set m_vertexPrimitiveRestartIndices; const float m_lineThickness; const ColorType m_colorType; const DrawingSpace m_drawingSpace; const LineType m_lineType; const JoinType m_joinType; std::vector m_vertexWindowXYZ; std::vector m_vertexWindowInputIndices; bool m_debugFlag = false; int m_savedPolygonMode[2]; int m_savedViewport[4]; std::unique_ptr m_transformEvent; /* * The base class graphics primitive that points to * either the Float or Byte Color primitive and can * be used for non-color operations. NEVER delete * this as it points to one the color primitive */ GraphicsPrimitive* m_primitive = NULL; std::unique_ptr m_primitiveFloatColor; std::unique_ptr m_primitiveByteColor; PolylineInfo m_lastPolyLineInfo; std::vector m_triangleJoins; // ADD_NEW_MEMBERS_HERE }; #ifdef __GRAPHICS_OPENGL_POLYLINE_TRIANGLES_DECLARE__ // #endif // __GRAPHICS_OPENGL_POLYLINE_TRIANGLES_DECLARE__ } // namespace #endif //__GRAPHICS_OPENGL_POLYLINE_TRIANGLES_H__ connectome-workbench-1.4.2/src/Graphics/GraphicsOpenGLTextureName.cxx000066400000000000000000000041651360521144700257030ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GRAPHICS_OPEN_G_L_TEXTURE_NAME_DECLARE__ #include "GraphicsOpenGLTextureName.h" #undef __GRAPHICS_OPEN_G_L_TEXTURE_NAME_DECLARE__ #include "CaretAssert.h" #include "EventGraphicsOpenGLDeleteTextureName.h" #include "EventManager.h" using namespace caret; /** * \class caret::GraphicsOpenGLTextureName * \brief Contains the OpenGL Texture Name and the context in which it was created. * \ingroup Graphics */ /** * Constructor. * * @param openglContextPointer * Pointer to OpenGL context in which texture name was created. * @param textureName * The OpenGL texture name. */ GraphicsOpenGLTextureName::GraphicsOpenGLTextureName(void* openglContextPointer, const GLuint textureName) : CaretObject(), m_openglContextPointer(openglContextPointer), m_textureName(textureName) { } /** * Destructor. */ GraphicsOpenGLTextureName::~GraphicsOpenGLTextureName() { if (m_textureName > 0) { EventGraphicsOpenGLDeleteTextureName deleteEvent(this); EventManager::get()->sendEvent(deleteEvent.getPointer()); } } /** * Get a description of this object's content. * @return String describing this object's content. */ AString GraphicsOpenGLTextureName::toString() const { return "GraphicsOpenGLTextureName"; } connectome-workbench-1.4.2/src/Graphics/GraphicsOpenGLTextureName.h000066400000000000000000000045201360521144700253230ustar00rootroot00000000000000#ifndef __GRAPHICS_OPEN_G_L_TEXTURE_NAME_H__ #define __GRAPHICS_OPEN_G_L_TEXTURE_NAME_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretOpenGLInclude.h" #include "CaretObject.h" namespace caret { class GraphicsOpenGLTextureName : public CaretObject { private: GraphicsOpenGLTextureName(void* openglContextPointer, const GLuint textureName); public: virtual ~GraphicsOpenGLTextureName(); /** * @return Pointer to OpenGL context in which texture name was created. */ inline void* getOpenGLContextPointer() const { return m_openglContextPointer; } /** * @return The OpenGL Texture Name Name. * While it is an unsigned interger, OpenGL refers to it as a "name". */ inline GLuint getTextureName() const { return m_textureName; } // ADD_NEW_METHODS_HERE virtual AString toString() const; private: GraphicsOpenGLTextureName(const GraphicsOpenGLTextureName&); GraphicsOpenGLTextureName& operator=(const GraphicsOpenGLTextureName&); void* m_openglContextPointer = NULL; const GLuint m_textureName = 0; friend class BrainOpenGL; // ADD_NEW_MEMBERS_HERE }; #ifdef __GRAPHICS_OPEN_G_L_TEXTURE_NAME_DECLARE__ // #endif // __GRAPHICS_OPEN_G_L_TEXTURE_NAME_DECLARE__ } // namespace #endif //__GRAPHICS_OPEN_G_L_TEXTURE_NAME_H__ connectome-workbench-1.4.2/src/Graphics/GraphicsPrimitive.cxx000066400000000000000000001614601360521144700243470ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GRAPHICS_PRIMITIVE_DECLARE__ #include "GraphicsPrimitive.h" #undef __GRAPHICS_PRIMITIVE_DECLARE__ #include "BoundingBox.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "EventManager.h" #include "GraphicsEngineDataOpenGL.h" #include "GraphicsPrimitiveV3f.h" #include "GraphicsPrimitiveV3fC4f.h" #include "GraphicsPrimitiveV3fC4ub.h" #include "GraphicsPrimitiveV3fN3f.h" #include "GraphicsPrimitiveV3fT3f.h" using namespace caret; /** * \class caret::GraphicsPrimitive * \brief Abstract class for a graphics primitive. * \ingroup Graphics * */ /** * Constructs an instance with the given vertex, normal vector, and color type. * * @param vertexDataType * Data type of the vertices. * @param normalVectorDataType * Data type of the normal vectors. * @param colorDataType * Data type of the colors. * @param vertexColorType * Type of vertex coloring * @param textureDataType * Data type of texture coordinates. * @param primitiveType * Type of primitive drawn (triangles, lines, etc.) */ GraphicsPrimitive::GraphicsPrimitive(const VertexDataType vertexDataType, const NormalVectorDataType normalVectorDataType, const ColorDataType colorDataType, const VertexColorType vertexColorType, const TextureDataType textureDataType, const PrimitiveType primitiveType) : CaretObject(), EventListenerInterface(), m_vertexDataType(vertexDataType), m_normalVectorDataType(normalVectorDataType), m_colorDataType(colorDataType), m_vertexColorType(vertexColorType), m_textureDataType(textureDataType), m_primitiveType(primitiveType), m_boundingBoxValid(false) { } /** * Destructor. */ GraphicsPrimitive::~GraphicsPrimitive() { EventManager::get()->removeAllEventsFromListener(this); } /** * Copy constructor for graphics primitive. * @param obj * Object that is copied. */ GraphicsPrimitive::GraphicsPrimitive(const GraphicsPrimitive& obj) : CaretObject(obj), EventListenerInterface(), m_vertexDataType(obj.m_vertexDataType), m_normalVectorDataType(obj.m_normalVectorDataType), m_colorDataType(obj.m_colorDataType), m_vertexColorType(obj.m_vertexColorType), m_textureDataType(obj.m_textureDataType), m_primitiveType(obj.m_primitiveType), m_boundingBoxValid(false) { this->copyHelperGraphicsPrimitive(obj); } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void GraphicsPrimitive::copyHelperGraphicsPrimitive(const GraphicsPrimitive& obj) { m_boundingBoxValid = false; m_xyz = obj.m_xyz; m_floatNormalVectorXYZ = obj.m_floatNormalVectorXYZ; m_floatRGBA = obj.m_floatRGBA; m_unsignedByteRGBA = obj.m_unsignedByteRGBA; m_floatTextureSTR = obj.m_floatTextureSTR; m_lineWidthType = obj.m_lineWidthType; m_lineWidthValue = obj.m_lineWidthValue; m_pointSizeType = obj.m_pointSizeType; m_pointDiameterValue = obj.m_pointDiameterValue; m_polygonalLinePrimitiveRestartIndices = obj.m_polygonalLinePrimitiveRestartIndices; m_sphereSizeType = obj.m_sphereSizeType; m_sphereDiameterValue = obj.m_sphereDiameterValue; m_textureImageBytesRGBA = obj.m_textureImageBytesRGBA; m_textureImageWidth = obj.m_textureImageWidth; m_textureImageHeight = obj.m_textureImageHeight; m_graphicsEngineDataForOpenGL.reset(); } /** * Request the capacity of the primitive for the given number of vertices. * Using this method can help reduce reallocations as data is added * to the primitive. Note: the primitive data is stored in * std::vector's and this method functions identically to * std::vector::reserve(). * * @param numberOfVertices * Number of vertices */ void GraphicsPrimitive::reserveForNumberOfVertices(const int32_t numberOfVertices) { switch (m_vertexDataType) { case VertexDataType::FLOAT_XYZ: m_xyz.reserve(numberOfVertices * 3); break; } switch (m_normalVectorDataType) { case NormalVectorDataType::FLOAT_XYZ: m_floatNormalVectorXYZ.reserve(numberOfVertices * 3); break; case NormalVectorDataType::NONE: break; } switch (m_colorDataType) { case ColorDataType::NONE: break; case ColorDataType::FLOAT_RGBA: m_floatRGBA.reserve(numberOfVertices * 4); break; case ColorDataType::UNSIGNED_BYTE_RGBA: m_unsignedByteRGBA.reserve(numberOfVertices * 4); break; } switch (m_textureDataType) { case GraphicsPrimitive::TextureDataType::NONE: break; case GraphicsPrimitive::TextureDataType::FLOAT_STR: m_floatTextureSTR.reserve(numberOfVertices * 3); break; } m_boundingBoxValid = false; } /** * @return The coordinates usage type hint for graphics system. */ GraphicsPrimitive::UsageType GraphicsPrimitive::getUsageTypeCoordinates() const { return m_usageTypeCoordinates; } /** * @return The normals usage type hint for graphics system. */ GraphicsPrimitive::UsageType GraphicsPrimitive::getUsageTypeNormals() const { return m_usageTypeNormals; } /** * @return The colors usage type hint for graphics system. */ GraphicsPrimitive::UsageType GraphicsPrimitive::getUsageTypeColors() const { return m_usageTypeColors; } /** * @return The texture coordinates usage type hint for graphics system. */ GraphicsPrimitive::UsageType GraphicsPrimitive::getUsageTypeTextureCoordinates() const { return m_usageTypeTextureCoordinates; } /** * Set the usage type hint for all data types for graphics system. * This will override any of the individual (vertex, normal, etc) * usage types so they should be called after calling this method. * * @param usageType * New value for usage type. */ void GraphicsPrimitive::setUsageTypeAll(const UsageType usageType) { m_usageTypeCoordinates = usageType; m_usageTypeNormals = usageType; m_usageTypeColors = usageType; m_usageTypeTextureCoordinates = usageType; } /** * Set the coordinates usage type hint for graphics system. * * @param usageType * New value for usage type. */ void GraphicsPrimitive::setUsageTypeCoordinates(const UsageType usageType) { m_usageTypeCoordinates = usageType; } /** * Set the normals usage type hint for graphics system. * * @param usageType * New value for usage type. */ void GraphicsPrimitive::setUsageTypeNormals(const UsageType usageType) { m_usageTypeNormals = usageType; } /** * Set the colors usage type hint for graphics system. * * @param usageType * New value for usage type. */ void GraphicsPrimitive::setUsageTypeColors(const UsageType usageType) { m_usageTypeColors = usageType; } /** * Set the texture coordinates usage type hint for graphics system. * * @param usageType * New value for usage type. */ void GraphicsPrimitive::setUsageTypeTextureCoordinates(const UsageType usageType) { m_usageTypeTextureCoordinates = usageType; } /** * @return Is this graphics primitive valid. * Primitive is valid if all of these conditions are met * (A) ((count(xyz) * 3) == (count(rgba) * 4)) * (B) (count(xyz) > 0) * (C) ((count(xyz) == count(normals)) OR (count(normals) == 0) */ bool GraphicsPrimitive::isValid() const { switch (m_vertexDataType) { case VertexDataType::FLOAT_XYZ: break; } const uint32_t numXYZ = m_xyz.size(); if (numXYZ > 0) { switch (m_normalVectorDataType) { case NormalVectorDataType::NONE: break; case NormalVectorDataType::FLOAT_XYZ: { const uint32_t numNormalXYZ = m_floatNormalVectorXYZ.size(); if (numNormalXYZ > 0) { if (numNormalXYZ != numXYZ) { CaretLogWarning("ERROR: GraphicsPrimitive XYZ size not matching surface normal size."); return false; } } } break; } bool haveRgbaFlag = false; uint32_t numColorRGBA = 0; switch (m_colorDataType) { case ColorDataType::NONE: haveRgbaFlag = false; break; case ColorDataType::FLOAT_RGBA: numColorRGBA = m_floatRGBA.size(); haveRgbaFlag = true; break; case ColorDataType::UNSIGNED_BYTE_RGBA: numColorRGBA = m_unsignedByteRGBA.size(); haveRgbaFlag = true; break; } if (haveRgbaFlag) { if ((numXYZ / 3) != (numColorRGBA / 4)) { CaretLogWarning("ERROR: GraphicsPrimitive XYZ size does not match RGBA size"); return false; } } switch (m_vertexColorType) { case VertexColorType::NONE: if (haveRgbaFlag) { CaretLogWarning("ERROR: GraphicsPrimitive VertexColorType is NONE but have RGBA ColorDataType"); } break; case VertexColorType::PER_VERTEX_RGBA: case VertexColorType::SOLID_RGBA: if ( ! haveRgbaFlag) { CaretLogWarning("ERROR: GraphicsPrimitive VertexColorType is RGBA but have NONE ColorDataType"); } break; } bool haveTextureFlag = false; uint32_t numTextureSTR = 0; switch (m_textureDataType) { case TextureDataType::NONE: break; case TextureDataType::FLOAT_STR: numTextureSTR = m_floatTextureSTR.size(); haveTextureFlag = true; break; } if (haveTextureFlag) { if (numXYZ != numTextureSTR) { CaretLogWarning("ERROR: GraphicsPrimitive XYZ size does not match Texture STR size"); return false; } if (m_textureImageBytesRGBA.empty()) { CaretLogWarning("ERROR: GraphicsPrimitive has invalid texture data"); } } switch (m_primitiveType) { case PrimitiveType::OPENGL_LINE_LOOP: case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN: case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN: case PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: case PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: if (numXYZ < 3) { CaretLogWarning("Line loop must have at least 3 vertices."); } break; case PrimitiveType::OPENGL_LINE_STRIP: case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN: case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN: case PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: case PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: if (numXYZ < 2) { CaretLogWarning("Line strip must have at least 2 vertices."); } break; case PrimitiveType::MODEL_SPACE_POLYGONAL_LINES: case PrimitiveType::OPENGL_LINES: case PrimitiveType::POLYGONAL_LINES: if (numXYZ < 2) { CaretLogWarning("Lines must have at least 2 vertices."); } else { const uint32_t extraVertices = numXYZ % 2; if (extraVertices > 0) { CaretLogWarning("Extra vertices for drawing lines ignored."); } } break; case PrimitiveType::OPENGL_POINTS: break; case PrimitiveType::OPENGL_TRIANGLE_FAN: if (numXYZ < 3) { CaretLogWarning("Triangle fan must have at least 3 vertices."); } break; case PrimitiveType::OPENGL_TRIANGLE_STRIP: if (numXYZ < 3) { CaretLogWarning("Triangle strip must have at least 3 vertices."); } break; case PrimitiveType::OPENGL_TRIANGLES: if (numXYZ < 3) { CaretLogWarning("Triangles must have at least 3 vertices."); } else { const uint32_t extraVertices = numXYZ % 3; if (extraVertices > 0) { CaretLogWarning("Extra vertices for drawing triangles ignored."); } } break; case PrimitiveType::SPHERES: if (numXYZ < 1) { CaretLogWarning("Spheres must have at least 1 vertices."); } break; } return true; } return false; } /** * Print the primitive's data, data may be long! */ void GraphicsPrimitive::print() const { std::cout << toStringPrivate(true) << std::endl; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString GraphicsPrimitive::toString() const { return toStringPrivate(false); } /** * @return Type of primitive as text. */ AString GraphicsPrimitive::getPrimitiveTypeAsText() const { AString s; switch (m_primitiveType) { case PrimitiveType::OPENGL_LINE_LOOP: s = "OpenGL Line Loop"; break; case PrimitiveType::OPENGL_LINE_STRIP: s = "OpenGL Line Strip"; break; case PrimitiveType::OPENGL_LINES: s = "OpenGL Lines"; break; case PrimitiveType::OPENGL_POINTS: s = "OpenGL Points"; break; case PrimitiveType::OPENGL_TRIANGLE_FAN: s = "OpenGL Triangle Fan"; break; case PrimitiveType::OPENGL_TRIANGLE_STRIP: s = "OpenGL Triangle Strip"; break; case PrimitiveType::OPENGL_TRIANGLES: s = "OpenGL Triangles"; break; case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN: s = "Model Space Polygonal Line Loop Bevel Join"; break; case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN: s = "Model Space Polygonal Line Loop Meter Join"; break; case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN: s = "Model Space Polygonal Line Strip Bevel Join"; break; case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN: s = "Model Space Polygonal Line Strip Miter Join"; break; case PrimitiveType::MODEL_SPACE_POLYGONAL_LINES: s = "Model Space Polygonal Lines"; break; case PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: s = "Polygonal Line Loop Bevel Join"; break; case PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: s = "Polygonal Line Loop Miter Join"; break; case PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: s = "Polygonal Line Strip Bevel Join"; break; case PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: s = "Polygonal Line Strip Miter Join"; break; case PrimitiveType::POLYGONAL_LINES: s = "Polygonal Lines"; break; case PrimitiveType::SPHERES: s = "Spheres"; break; } return s; } /** * @return Sphere size type as text for the given size type. * * @param sizeType * The size type. */ AString GraphicsPrimitive::getSphereSizeTypeAsText(const SphereSizeType sizeType) const { AString s; switch (sizeType) { case SphereSizeType::MILLIMETERS: s = "Millimeters"; break; } return s; } /** * @return Vertex color type as text for the given vertex color type. * * @param vertexColorType * The vertex color type. */ AString GraphicsPrimitive::getVertexColorTypeAsText(const VertexColorType vertexColorType) const { AString s; switch (vertexColorType) { case VertexColorType::NONE: s = "None"; break; case VertexColorType::PER_VERTEX_RGBA: s = "Per Vertex RGBA"; break; case VertexColorType::SOLID_RGBA: s = "Solid RGBA"; break; } return s; } /** * @return Point size type as text for the given size type. * * @param sizeType * The size type. */ AString GraphicsPrimitive::getPointSizeTypeAsText(const PointSizeType sizeType) const { AString s; switch (sizeType) { case PointSizeType::MILLIMETERS: s = "Millimeters"; break; case PointSizeType::PERCENTAGE_VIEWPORT_HEIGHT: s = "Percentage Viewport Height"; break; case PointSizeType::PIXELS: s = "Pixels"; break; } return s; } /** * @return Line width type as text for the given line width type. * * @param lineWidthType * The line width type. */ AString GraphicsPrimitive::getLineWidthTypeAsText(const LineWidthType lineWidthType) const { AString s; switch (lineWidthType) { case LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT: s = "Percentage Viewport Height"; break; case LineWidthType::PIXELS: s = "Pixels"; break; } return s; } /** * Convert to string. * * @param includeAllDataFlag * If true, numerical values are included. Else, only type of data. */ AString GraphicsPrimitive::toStringPrivate(const bool includeAllDataFlag) const { AString s("Primitive: " + getPrimitiveTypeAsText()); const int32_t numVertices = getNumberOfVertices(); s.appendWithNewLine("Number of Vertices: " + AString::number(numVertices) + "\n"); switch (m_textureDataType) { case TextureDataType::NONE: break; case TextureDataType::FLOAT_STR: s.appendWithNewLine("Texture: " + AString::number(m_floatTextureSTR.size()) + " Float Texture 0.0 to 1.0. "); s.appendWithNewLine(" Width: " + AString::number(m_textureImageWidth) + " Height: " + AString::number(m_textureImageHeight)); break; } bool addLineWidthFlag = false; bool addPointSizeFlag = false; bool addSphereSizeFlag = false; switch (m_primitiveType) { case PrimitiveType::OPENGL_LINE_LOOP: addLineWidthFlag = true; break; case PrimitiveType::OPENGL_LINE_STRIP: addLineWidthFlag = true; break; case PrimitiveType::OPENGL_LINES: addLineWidthFlag = true; break; case PrimitiveType::OPENGL_POINTS: addPointSizeFlag = true; break; case PrimitiveType::OPENGL_TRIANGLE_FAN: break; case PrimitiveType::OPENGL_TRIANGLE_STRIP: break; case PrimitiveType::OPENGL_TRIANGLES: break; case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN: case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN: addLineWidthFlag = true; break; case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN: case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN: addLineWidthFlag = true; break; case PrimitiveType::MODEL_SPACE_POLYGONAL_LINES: addLineWidthFlag = true; break; case PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: case PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: addLineWidthFlag = true; break; case PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: case PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: addLineWidthFlag = true; break; case PrimitiveType::POLYGONAL_LINES: addLineWidthFlag = true; break; case PrimitiveType::SPHERES: addSphereSizeFlag = true; break; } if ( ! m_polygonalLinePrimitiveRestartIndices.empty()) { s.appendWithNewLine("Polygonal Line Primitive Restart Indices Count: " + AString::number(m_polygonalLinePrimitiveRestartIndices.size())); if (includeAllDataFlag) { std::vector temp(m_polygonalLinePrimitiveRestartIndices.begin(), m_polygonalLinePrimitiveRestartIndices.end()); s.appendWithNewLine(" " + AString::fromNumbers(temp, ", ")); } } if (addLineWidthFlag) { s.appendWithNewLine("Line Width Type: " + getLineWidthTypeAsText(m_lineWidthType) + "; Value: " + AString::number(m_lineWidthValue, 'f', 3)); } if (addPointSizeFlag) { s.appendWithNewLine("Point Diameter Type: " + getPointSizeTypeAsText(m_pointSizeType) + "; Value: " + AString::number(m_pointDiameterValue, 'f', 3)); } if (addSphereSizeFlag) { s.appendWithNewLine("Sphere Diameter Type: " + getSphereSizeTypeAsText(m_sphereSizeType) + "; Value: " + AString::number(m_sphereDiameterValue, 'f', 3)); } s.appendWithNewLine("Vertex Color Type: " + getVertexColorTypeAsText(m_vertexColorType)); s.append("\n"); if (includeAllDataFlag) { for (int32_t i = 0; i < numVertices; i++) { s.append(AString("%1: ").arg(i, 5)); switch (m_vertexDataType) { case VertexDataType::FLOAT_XYZ: { CaretAssertVectorIndex(m_xyz, i*3 + 2); const float* xyz = &m_xyz[i * 3]; s.append(AString("%1, %2, %3").arg(xyz[0], 10, 'f', 3).arg(xyz[1], 10, 'f', 3).arg(xyz[2], 10, 'f', 3)); } break; } switch (m_normalVectorDataType) { case NormalVectorDataType::FLOAT_XYZ: { CaretAssertVectorIndex(m_floatNormalVectorXYZ, i*3 + 2); const float* xyz = &m_floatNormalVectorXYZ[i * 3]; s.append(AString(" N:%1, %2, %3").arg(xyz[0], 7, 'f', 5).arg(xyz[1], 7, 'f', 5).arg(xyz[2], 7, 'f', 5)); } break; case NormalVectorDataType::NONE: break; } switch (m_colorDataType) { case ColorDataType::NONE: break; case ColorDataType::FLOAT_RGBA: { CaretAssertVectorIndex(m_floatRGBA, i*4 + 3); const float* rgba = &m_floatRGBA[i * 4]; s.append(AString(" RGBAf: %1, %2, %3, %4").arg(rgba[0], 5, 'f', 3).arg(rgba[1], 5, 'f', 3).arg(rgba[2], 5, 'f', 3).arg(rgba[3], 5, 'f', 3)); } break; case ColorDataType::UNSIGNED_BYTE_RGBA: { CaretAssertVectorIndex(m_unsignedByteRGBA, i*4 + 3); const uint8_t* rgba = &m_unsignedByteRGBA[i * 4]; s.append(AString(" RGBAb: %1, %2, %3, %4").arg(rgba[0], 3).arg(rgba[1], 3).arg(rgba[2], 3).arg(rgba[3], 3)); } } switch (m_textureDataType) { case TextureDataType::NONE: break; case TextureDataType::FLOAT_STR: { CaretAssertVectorIndex(m_floatTextureSTR, i*3 + 2); const float* str = &m_floatTextureSTR[i * 3]; s.append(AString(" T:%1, %2, %3").arg(str[0], 7, 'f', 5).arg(str[1], 7, 'f', 5).arg(str[2], 7, 'f', 5)); } break; } s.append("\n"); } } return s; } /** * Add a vertex and its normal vector * * @param xyz * Coordinate of vertex. * @param normalVector * Normal vector for the vertex. * @param rgbaFloat * Float RGBA color components. * @param rgbaByte * Byte RGBA color components. */ void GraphicsPrimitive::addVertexProtected(const float xyz[3], const float normalVector[3], const float rgbaFloat[4], const uint8_t rgbaByte[4], const float textureSTR[3]) { m_xyz.insert(m_xyz.end(), xyz, xyz + 3); switch (m_normalVectorDataType) { case NormalVectorDataType::FLOAT_XYZ: CaretAssert(normalVector); m_floatNormalVectorXYZ.insert(m_floatNormalVectorXYZ.end(), normalVector, normalVector + 3); break; case NormalVectorDataType::NONE: break; } switch (m_colorDataType) { case ColorDataType::NONE: break; case ColorDataType::FLOAT_RGBA: CaretAssert(rgbaFloat); m_floatRGBA.insert(m_floatRGBA.end(), rgbaFloat, rgbaFloat + 4); break; case ColorDataType::UNSIGNED_BYTE_RGBA: CaretAssert(rgbaByte); m_unsignedByteRGBA.insert(m_unsignedByteRGBA.end(), rgbaByte, rgbaByte + 4); break; } switch (m_textureDataType) { case TextureDataType::NONE: break; case TextureDataType::FLOAT_STR: CaretAssert(textureSTR); m_floatTextureSTR.insert(m_floatTextureSTR.end(), textureSTR, textureSTR + 3); break; } m_boundingBoxValid = false; /* * The triangle strip primitve vertces are filled after two * vertices are added after requesting a restart */ if (m_triangleStripPrimitiveRestartIndex == getNumberOfVertices()) { m_triangleStripPrimitiveRestartIndex = -1; fillTriangleStripPrimitiveRestartVertices(); } } /** * Get the XYZ coordinate from the given vertex. * * @param vertexIndex * Index of the vertex. * @param xyzOut * Output containing the XYZ coordinat. */ void GraphicsPrimitive::getVertexFloatXYZ(const int32_t vertexIndex, float xyzOut[3]) const { const int32_t i3 = vertexIndex * 3; CaretAssertVectorIndex(m_xyz, i3 + 2); xyzOut[0] = m_xyz[i3]; xyzOut[1] = m_xyz[i3+1]; xyzOut[2] = m_xyz[i3+2]; } /** * Replace the existing XYZ coordinates with the given * XYZ coordinates. The existing and new coordinates * MUST BE the same size. * * @param xyz * The new XYZ coordinates. */ void GraphicsPrimitive::replaceFloatXYZ(const std::vector& xyz) { if (xyz.size() == m_xyz.size()) { m_xyz = xyz; if (m_graphicsEngineDataForOpenGL != NULL) { m_graphicsEngineDataForOpenGL->invalidateCoordinates(); } } else { const AString msg("Replacement XYZ must be same size as existing xyz"); CaretLogWarning(msg); CaretAssertMessage(0, msg); } m_boundingBoxValid = false; } /** * Replace the XYZ coordinate at the given index * * @param vertexIndex * Index of the vertex * @param xyz * The new XYZ coordinate */ void GraphicsPrimitive::replaceVertexFloatXYZ(const int32_t vertexIndex, const float xyz[3]) { const int32_t offset = vertexIndex * 3; CaretAssertVectorIndex(m_xyz, offset + 2); m_xyz[offset] = xyz[0]; m_xyz[offset + 1] = xyz[1]; m_xyz[offset + 2] = xyz[2]; if (m_graphicsEngineDataForOpenGL != NULL) { m_graphicsEngineDataForOpenGL->invalidateCoordinates(); } } /** * Get the float RGBA coloring for a vertex. * * @param vertexIndex * Index of the vertex. * @param rgbaOut * Output with RGBA. */ void GraphicsPrimitive::getVertexFloatRGBA(const int32_t vertexIndex, float rgbaOut[4]) const { const int32_t i4 = vertexIndex * 4; switch (m_colorDataType) { case ColorDataType::NONE: CaretAssert(0); break; case ColorDataType::FLOAT_RGBA: CaretAssertVectorIndex(m_floatRGBA, i4 + 3); rgbaOut[0] = m_floatRGBA[i4]; rgbaOut[1] = m_floatRGBA[i4 + 1]; rgbaOut[2] = m_floatRGBA[i4 + 2]; rgbaOut[3] = m_floatRGBA[i4 + 3]; break; case ColorDataType::UNSIGNED_BYTE_RGBA: CaretAssertMessage(0, "Getting float RGBA from primitive but coloring type is Byte"); CaretLogWarning("Getting float RGBA from primitive but coloring type is Byte"); break; } } /** * Replace the float RGBA coloring for a vertex. * * @param vertexIndex * Index of the vertex. * @param rgba * New RGBA for vertex. */ void GraphicsPrimitive::replaceVertexFloatRGBA(const int32_t vertexIndex, const float rgba[4]) { const int32_t i4 = vertexIndex * 4; switch (m_colorDataType) { case ColorDataType::NONE: CaretAssert(0); break; case ColorDataType::FLOAT_RGBA: CaretAssertVectorIndex(m_floatRGBA, i4 + 3); m_floatRGBA[i4] = rgba[0]; m_floatRGBA[i4 + 1] = rgba[1]; m_floatRGBA[i4 + 2] = rgba[2]; m_floatRGBA[i4 + 3] = rgba[3]; break; case ColorDataType::UNSIGNED_BYTE_RGBA: CaretAssertMessage(0, "Replacing float RGBA in primitive but coloring type is Byte"); CaretLogWarning("Replacing float RGBA in primitive but coloring type is Byte"); break; } if (m_graphicsEngineDataForOpenGL != NULL) { m_graphicsEngineDataForOpenGL->invalidateColors(); } } /** * Get the byte RGBA coloring for a vertex. * * @param vertexIndex * Index of the vertex. * @param rgbaOut * Output with RGBA. */ void GraphicsPrimitive::getVertexByteRGBA(const int32_t vertexIndex, uint8_t rgbaOut[4]) const { const int32_t i4 = vertexIndex * 4; switch (m_colorDataType) { case ColorDataType::NONE: CaretAssert(0); break; case ColorDataType::FLOAT_RGBA: CaretAssertMessage(0, "Getting Byte RGBA in primitive but coloring type is Float"); CaretLogWarning("Getting Byte RGBA in primitive but coloring type is Float"); break; case ColorDataType::UNSIGNED_BYTE_RGBA: CaretAssertVectorIndex(m_unsignedByteRGBA, i4 + 3); rgbaOut[0] = m_unsignedByteRGBA[i4]; rgbaOut[1] = m_unsignedByteRGBA[i4 + 1]; rgbaOut[2] = m_unsignedByteRGBA[i4 + 2]; rgbaOut[3] = m_unsignedByteRGBA[i4 + 3]; break; } } /** * Replace the float RGBA coloring for a vertex. * * @param vertexIndex * Index of the vertex. * @param rgba * New RGBA for vertex. */ void GraphicsPrimitive::replaceVertexByteRGBA(const int32_t vertexIndex, const uint8_t rgba[4]) { const int32_t i4 = vertexIndex * 4; switch (m_colorDataType) { case ColorDataType::NONE: CaretAssert(0); break; case ColorDataType::FLOAT_RGBA: CaretAssertMessage(0, "Replacing Byte RGBA in primitive but coloring type is Float"); CaretLogWarning("Replacing Byte RGBA in primitive but coloring type is Float"); break; case ColorDataType::UNSIGNED_BYTE_RGBA: CaretAssertVectorIndex(m_unsignedByteRGBA, i4 + 3); m_unsignedByteRGBA[i4] = rgba[0]; m_unsignedByteRGBA[i4 + 1] = rgba[1]; m_unsignedByteRGBA[i4 + 2] = rgba[2]; m_unsignedByteRGBA[i4 + 3] = rgba[3]; break; } if (m_graphicsEngineDataForOpenGL != NULL) { m_graphicsEngineDataForOpenGL->invalidateColors(); } } /** * Replace all vertex RGBA with the given solid color RGBA. * * @param rgba * RGBA values for all vertices */ void GraphicsPrimitive::replaceAllVertexSolidByteRGBA(const uint8_t rgba[4]) { switch (m_colorDataType) { case ColorDataType::NONE: CaretAssert(0); break; case ColorDataType::FLOAT_RGBA: CaretAssertMessage(0, "Replacing Byte RGBA in primitive but coloring type is Float"); CaretLogWarning("Replacing Byte RGBA in primitive but coloring type is Float"); break; case ColorDataType::UNSIGNED_BYTE_RGBA: { const int32_t numRGBA = static_cast(m_unsignedByteRGBA.size() / 4); for (int32_t i = 0; i < numRGBA; i++) { const int32_t i4 = i * 4; CaretAssertVectorIndex(m_unsignedByteRGBA, i4 + 3); m_unsignedByteRGBA[i4] = rgba[0]; m_unsignedByteRGBA[i4 + 1] = rgba[1]; m_unsignedByteRGBA[i4 + 2] = rgba[2]; m_unsignedByteRGBA[i4 + 3] = rgba[3]; } } } if (m_graphicsEngineDataForOpenGL != NULL) { m_graphicsEngineDataForOpenGL->invalidateColors(); } } /** * Replace all vertex RGBA with the given solid color RGBA. * * @param rgba * RGBA values for all vertices */ void GraphicsPrimitive::replaceAllVertexSolidFloatRGBA(const float rgba[4]) { switch (m_colorDataType) { case ColorDataType::NONE: CaretAssert(0); break; case ColorDataType::FLOAT_RGBA: { const int32_t numRGBA = static_cast(m_floatRGBA.size() / 4); for (int32_t i = 0; i < numRGBA; i++) { const int32_t i4 = i * 4; CaretAssertVectorIndex(m_floatRGBA, i4 + 3); m_floatRGBA[i4] = rgba[0]; m_floatRGBA[i4 + 1] = rgba[1]; m_floatRGBA[i4 + 2] = rgba[2]; m_floatRGBA[i4 + 3] = rgba[3]; } } break; case ColorDataType::UNSIGNED_BYTE_RGBA: CaretAssertMessage(0, "Replacing Byte RGBA in primitive but coloring type is Float"); CaretLogWarning("Replacing Byte RGBA in primitive but coloring type is Float"); break; } if (m_graphicsEngineDataForOpenGL != NULL) { m_graphicsEngineDataForOpenGL->invalidateColors(); } } /** * Get a bounds box for the vertex coordinates. * * @param boundingBoxOut * Output bounding box. * @return * True if bounding box is valid, else false. */ bool GraphicsPrimitive::getVertexBounds(BoundingBox& boundingBoxOut) const { if ( ! m_boundingBoxValid) { if (m_boundingBox == NULL) { m_boundingBox.reset(new BoundingBox()); } m_boundingBox->resetForUpdate(); const int32_t numberOfVertices = static_cast(m_xyz.size() / 3); for (int32_t i = 0; i < numberOfVertices; i++) { const int32_t i3 = i * 3; CaretAssertVectorIndex(m_xyz, i3 + 2); m_boundingBox->update(&m_xyz[i3]); } m_boundingBoxValid = true; } boundingBoxOut = *m_boundingBox; return m_boundingBoxValid; } /** * There may be instances where a primitive should stop and restart at * non-consecutive vertices (such as a gap in connected line segment). * Typically, this requires creating separate primitives around * the gap. * * When this method is called, it indicates that any previously * added points will not connect to any points after this method * is called. * * This functionality is similar to that of glPrimitiveRestartIndex() * that is not available in versions of OpenGL prior to 3.1. * * At this time, this functionality if available only for * line strip and line loop. */ void GraphicsPrimitive::addPrimitiveRestart() { bool polygonalLineFlag = false; bool triangleStripFlag = false; switch (m_primitiveType) { case PrimitiveType::OPENGL_LINE_LOOP: break; case PrimitiveType::OPENGL_LINE_STRIP: break; case PrimitiveType::OPENGL_LINES: break; case PrimitiveType::OPENGL_POINTS: break; case PrimitiveType::OPENGL_TRIANGLE_FAN: break; case PrimitiveType::OPENGL_TRIANGLE_STRIP: triangleStripFlag = true; break; case PrimitiveType::OPENGL_TRIANGLES: break; case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN: case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN: polygonalLineFlag = true; break; case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN: case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN: polygonalLineFlag = true; break; case PrimitiveType::MODEL_SPACE_POLYGONAL_LINES: break; case PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: case PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: polygonalLineFlag = true; break; case PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: case PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: polygonalLineFlag = true; break; case PrimitiveType::POLYGONAL_LINES: break; case PrimitiveType::SPHERES: break; } if (polygonalLineFlag) { /* * A set is used because a vertex could be added more than one time */ m_polygonalLinePrimitiveRestartIndices.insert(getNumberOfVertices()); } else if (triangleStripFlag) { const int32_t numVertices = getNumberOfVertices(); if (numVertices > 3) { /* * Add 18 dummy vertices that will be used for the * 6 degenerate triangles at a later time */ float float4[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; uint8_t byte4[4] = { 0, 0, 0, 0 }; for (int32_t i = 0; i < 18; i++) { addVertexProtected(float4, float4, float4, byte4, float4); } /* * When the number of vertices becomes the index below, * the degenerate triangles will be added. */ m_triangleStripPrimitiveRestartIndex = getNumberOfVertices() + 2; } else { CaretLogSevere("Must have at least three vertices before requesting a triangle strip primitive restart."); } } else { CaretLogSevere("Requested primitive restart on not yet supported primitive type: " + getPrimitiveTypeAsText()); } } /** * Copy a vertex to another vertex. * * @param copyFromIndex * Index of the 'copied' vertex. * @param copyToIndex */ void GraphicsPrimitive::copyVertex(const int32_t copyFromIndex, const int32_t copyToIndex) { const int32_t from3 = copyFromIndex * 3; const int32_t to3 = copyToIndex * 3; for (int32_t i = 0; i < 3; i++) { CaretAssertVectorIndex(m_xyz, from3 + i); CaretAssertVectorIndex(m_xyz, to3 + i); m_xyz[to3 + i] = m_xyz[from3 + i]; switch (m_normalVectorDataType) { case NormalVectorDataType::FLOAT_XYZ: CaretAssertVectorIndex(m_floatNormalVectorXYZ, from3 + i); CaretAssertVectorIndex(m_floatNormalVectorXYZ, to3 + i); m_floatNormalVectorXYZ[to3 + i] = m_floatNormalVectorXYZ[from3 + i]; break; case NormalVectorDataType::NONE: break; } switch (m_textureDataType) { case TextureDataType::NONE: break; case TextureDataType::FLOAT_STR: CaretAssertVectorIndex(m_floatTextureSTR, from3 + i); CaretAssertVectorIndex(m_floatTextureSTR, to3 + i); m_floatTextureSTR[to3 + i] = m_floatTextureSTR[from3 + i]; break; } } const int32_t from4 = copyFromIndex * 4; const int32_t to4 = copyToIndex * 4; for (int32_t i = 0; i < 4; i++) { switch (m_colorDataType) { case ColorDataType::NONE: break; case ColorDataType::FLOAT_RGBA: CaretAssertVectorIndex(m_floatRGBA, from4 + i); CaretAssertVectorIndex(m_floatRGBA, to4 + i); m_floatRGBA[to4 + i] = m_floatRGBA[from4 + i]; break; case ColorDataType::UNSIGNED_BYTE_RGBA: CaretAssertVectorIndex(m_unsignedByteRGBA, from4 + i); CaretAssertVectorIndex(m_unsignedByteRGBA, to4 + i); m_unsignedByteRGBA[to4 + i] = m_unsignedByteRGBA[from4 + i]; break; } } m_boundingBoxValid = false; } /** * Fill the degenerate vertices for the triangle strip. * Since OpenGL's primitive restart (glPrimitiveRestartIndices()) * function is not available prior to OpenGL 3.1, add * degenerate triangles as explained in the following links. * * @param newStripVertexOneXYZ * First vertex in new strip that will be added after calling this method. * @param newStripVertexTwoXYZ * Second vertex in new strip that will be added after calling this method. * * @see http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/concatenating-triangle-strips-r1871 * @see http://en.wikipedia.org/wiki/Triangle_strip */ void GraphicsPrimitive::fillTriangleStripPrimitiveRestartVertices() { const int32_t numVertices = getNumberOfVertices(); /* * Vertices "F" and "F" were added just before the call to addPrimitiveRestart() * Vertices "G" and "H" were added after the call to addPrimitiveRestart() and * this method was called immediately after "H" was added * addPrimitiveRestart() added 18 vertices: * DEF + EFF + FFG + FGG + GGH + GHG + GGH + GHI * * From: https://www.gamedev.net/articles/programming/graphics/concatenating-triangle-strips-r1871 */ const int32_t vertexH = numVertices - 1; const int32_t vertexG = numVertices - 2; const int32_t vertexF = numVertices - 21; const int32_t vertexE = numVertices - 22; int32_t copyToIndex = vertexF + 1; copyVertex(vertexE, copyToIndex++); copyVertex(vertexF, copyToIndex++); copyVertex(vertexF, copyToIndex++); copyVertex(vertexF, copyToIndex++); copyVertex(vertexF, copyToIndex++); copyVertex(vertexG, copyToIndex++); copyVertex(vertexF, copyToIndex++); copyVertex(vertexG, copyToIndex++); copyVertex(vertexG, copyToIndex++); copyVertex(vertexG, copyToIndex++); copyVertex(vertexG, copyToIndex++); copyVertex(vertexH, copyToIndex++); copyVertex(vertexG, copyToIndex++); copyVertex(vertexH, copyToIndex++); copyVertex(vertexG, copyToIndex++); copyVertex(vertexG, copyToIndex++); copyVertex(vertexG, copyToIndex++); copyVertex(vertexH, copyToIndex++); CaretAssert(copyToIndex == vertexG); } /** * Get the point diameter. * * @param sizeTypeOut * Type of sizing. * @param pointDiameterOut * Diameter of point. */ void GraphicsPrimitive::getPointDiameter(PointSizeType& sizeTypeOut, float& pointDiameterOut) const { sizeTypeOut = m_pointSizeType; pointDiameterOut = m_pointDiameterValue; } /** * Set the point diameter. * * @param sizeType * Type of sizing. * @param pointDiameter * Diameter of point. */ void GraphicsPrimitive::setPointDiameter(const PointSizeType sizeType, const float pointDiameter) const { m_pointSizeType = sizeType; m_pointDiameterValue = pointDiameter; } /** * Get the line width. * * @param lineWidthTypeOut * Type of width. * @param lineWidthOut * Width of line. */ void GraphicsPrimitive::getLineWidth(LineWidthType& widthTypeOut, float& lineWidthOut) const { widthTypeOut = m_lineWidthType; lineWidthOut = m_lineWidthValue; } /** * Set the line width. * * @param lineWidthType * Type of width. * @param lineWidth * Width of line. */ void GraphicsPrimitive::setLineWidth(const LineWidthType lineWidthType, const float lineWidth) const { m_lineWidthType = lineWidthType; m_lineWidthValue = lineWidth; } /** * Get the sphere diameter. * * @param sizeTypeOut * Type of sizing. * @param pointDiameterOut * Diameter of sphere. */ void GraphicsPrimitive::getSphereDiameter(SphereSizeType& sizeTypeOut, float& sphereDiameterOut) const { sizeTypeOut = m_sphereSizeType; sphereDiameterOut = m_sphereDiameterValue; } /** * Set the sphere diameter. * * @param sizeType * Type of sizing. * @param pointDiameter * Diameter of sphere. */ void GraphicsPrimitive::setSphereDiameter(const SphereSizeType sizeType, const float sphereDiameter) const { m_sphereSizeType = sizeType; m_sphereDiameterValue = sphereDiameter; } /** * Set the image for the texture. * * @param imageBytesRGBA * Bytes containing the image data. 4 bytes per pixel. * @param imageWidth * Width of the actual image. * @param imageHeight * Height of the image. */ void GraphicsPrimitive::setTextureImage(const uint8_t* imageBytesRGBA, const int32_t imageWidth, const int32_t imageHeight) { m_textureImageBytesRGBA.clear(); m_textureImageWidth = -1; m_textureImageHeight = -1; const int32_t numBytes = imageWidth * imageHeight * 4; if (numBytes > 0) { m_textureImageBytesRGBA.reserve(numBytes); m_textureImageWidth = imageWidth; m_textureImageHeight = imageHeight; m_textureImageBytesRGBA.insert(m_textureImageBytesRGBA.end(), imageBytesRGBA, imageBytesRGBA + numBytes); } } /** * Simplify line types by removing every 'skipVertexCount' vertex. * When 'skipVertexCount' is 2, every other point in the line is removed. * Nothing is done when 'skipVertexCount' is less than 2 or primitive * type is not a line. * First and last point are alwyas preserved. * * @param skipVertexCount * Number of vertices to skip. */ void GraphicsPrimitive::simplfyLines(const int32_t skipVertexCount) { if (skipVertexCount < 2) { return; } bool lineTypeFlag(false); switch (m_primitiveType) { case PrimitiveType::OPENGL_LINE_LOOP: lineTypeFlag = true; break; case PrimitiveType::OPENGL_LINE_STRIP: lineTypeFlag = true; break; case PrimitiveType::OPENGL_LINES: break; case PrimitiveType::OPENGL_POINTS: break; case PrimitiveType::OPENGL_TRIANGLE_FAN: break; case PrimitiveType::OPENGL_TRIANGLE_STRIP: break; case PrimitiveType::OPENGL_TRIANGLES: break; case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN: case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN: lineTypeFlag = true; break; case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN: case PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN: lineTypeFlag = true; break; case PrimitiveType::MODEL_SPACE_POLYGONAL_LINES: lineTypeFlag = true; break; case PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: case PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: lineTypeFlag = true; break; case PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: case PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: lineTypeFlag = true; break; case PrimitiveType::POLYGONAL_LINES: lineTypeFlag = true; break; case PrimitiveType::SPHERES: break; } if ( ! lineTypeFlag) { return; } std::vector xyz; std::vector normals; std::vector rgbaFloat; std::vector rgbaByte; std::vector textureSTR; const int32_t numVertices = getNumberOfVertices(); xyz.reserve(m_xyz.size()); normals.reserve(m_floatNormalVectorXYZ.size()); rgbaFloat.reserve(m_floatRGBA.size()); rgbaByte.reserve(m_unsignedByteRGBA.size()); textureSTR.reserve(m_floatTextureSTR.size()); const int32_t lastIndex = numVertices - 1; for (int32_t i = 0; i < numVertices; i++) { bool addFlag(false); if (i == 0) { addFlag = true; } else if (i == lastIndex) { addFlag = true; } else { const int remainder = i % skipVertexCount; if (remainder == 0) { addFlag = true; } } if (addFlag) { std::cout << "Adding vertex: " << i << std::endl; const int32_t i3 = i * 3; const int32_t i4 = i * 4; switch (m_vertexDataType) { case VertexDataType::FLOAT_XYZ: xyz.push_back(m_xyz[i3]); xyz.push_back(m_xyz[i3+1]); xyz.push_back(m_xyz[i3+2]); break; } switch (m_normalVectorDataType) { case NormalVectorDataType::FLOAT_XYZ: normals.push_back(m_floatNormalVectorXYZ[i3]); normals.push_back(m_floatNormalVectorXYZ[i3+1]); normals.push_back(m_floatNormalVectorXYZ[i3+2]); break; case NormalVectorDataType::NONE: break; } switch (m_colorDataType) { case ColorDataType::FLOAT_RGBA: rgbaFloat.push_back(m_floatRGBA[i4]); rgbaFloat.push_back(m_floatRGBA[i4+1]); rgbaFloat.push_back(m_floatRGBA[i4+2]); rgbaFloat.push_back(m_floatRGBA[i4+3]); break; case ColorDataType::UNSIGNED_BYTE_RGBA: rgbaByte.push_back(m_unsignedByteRGBA[i4]); rgbaByte.push_back(m_unsignedByteRGBA[i4+1]); rgbaByte.push_back(m_unsignedByteRGBA[i4+2]); rgbaByte.push_back(m_unsignedByteRGBA[i4+3]); break; case ColorDataType::NONE: break; } switch (m_textureDataType) { case TextureDataType::FLOAT_STR: textureSTR.push_back(m_floatTextureSTR[i3]); textureSTR.push_back(m_floatTextureSTR[i3+1]); textureSTR.push_back(m_floatTextureSTR[i3+2]); break; case TextureDataType::NONE: break; } } } m_xyz = std::move(xyz); m_floatNormalVectorXYZ = normals; m_floatRGBA = rgbaFloat; m_unsignedByteRGBA = rgbaByte; m_floatTextureSTR = textureSTR; } /** * Get the OpenGL graphics engine data in this instance. * * @return * OpenGL graphics engine data or NULL if not found. */ GraphicsEngineDataOpenGL* GraphicsPrimitive::getGraphicsEngineDataForOpenGL() { return m_graphicsEngineDataForOpenGL.get(); } /** * Set the OpenGL graphics engine data in this instance. * * @param graphicsEngineForOpenGL * OpenGLgraphics engine for which graphics engine data is desired. This value may * NULL to remove graphics engine data for the given graphics engine. * This instance will take ownership of this data and handle deletion of it. */ void GraphicsPrimitive::setGraphicsEngineDataForOpenGL(GraphicsEngineDataOpenGL* graphicsEngineDataForOpenGL) { m_graphicsEngineDataForOpenGL.reset(graphicsEngineDataForOpenGL); } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void GraphicsPrimitive::receiveEvent(Event* /*event*/) { // if (event->getEventType() == EventTypeEnum::) { // eventName = dynamic_cast(event); // CaretAssert(eventName); // // event->setEventProcessed(); // } } /** * @return A new primitive for XYZ with solid color float RGBA. Caller is responsible * for deleting the returned pointer. * * @param primitiveType * Type of primitive drawn (triangles, lines, etc.) */ GraphicsPrimitiveV3f* GraphicsPrimitive::newPrimitiveV3f(const GraphicsPrimitive::PrimitiveType primitiveType, const float floatRGBA[4]) { GraphicsPrimitiveV3f* primitive = new GraphicsPrimitiveV3f(primitiveType, floatRGBA); return primitive; } /** * @return A new primitive for XYZ with solid color float RGBA. Caller is responsible * for deleting the returned pointer. * * @param primitiveType * Type of primitive drawn (triangles, lines, etc.) */ GraphicsPrimitiveV3fN3f* GraphicsPrimitive::newPrimitiveV3fN3f(const GraphicsPrimitive::PrimitiveType primitiveType, const uint8_t unsignedByteRGBA[4]) { GraphicsPrimitiveV3fN3f* primitive = new GraphicsPrimitiveV3fN3f(primitiveType, unsignedByteRGBA); return primitive; } /** * @return A new primitive for XYZ with solid color unsigned byte RGBA. Caller is responsible * for deleting the returned pointer. * * @param primitiveType * Type of primitive drawn (triangles, lines, etc.) */ GraphicsPrimitiveV3f* GraphicsPrimitive::newPrimitiveV3f(const GraphicsPrimitive::PrimitiveType primitiveType, const uint8_t unsignedByteRGBA[4]) { GraphicsPrimitiveV3f* primitive = new GraphicsPrimitiveV3f(primitiveType, unsignedByteRGBA); return primitive; } /** * @return A new primitive for XYZ with float RGBA. Caller is responsible * for deleting the returned pointer. * * @param primitiveType * Type of primitive drawn (triangles, lines, etc.) */ GraphicsPrimitiveV3fC4f* GraphicsPrimitive::newPrimitiveV3fC4f(const GraphicsPrimitive::PrimitiveType primitiveType) { GraphicsPrimitiveV3fC4f* primitive = new GraphicsPrimitiveV3fC4f(primitiveType); return primitive; } /** * @return A new primitive for XYZ with unsigned byte RGBA. Caller is responsible * for deleting the returned pointer. * * @param primitiveType * Type of primitive drawn (triangles, lines, etc.) */ GraphicsPrimitiveV3fC4ub* GraphicsPrimitive::newPrimitiveV3fC4ub(const GraphicsPrimitive::PrimitiveType primitiveType) { GraphicsPrimitiveV3fC4ub* primitive = new GraphicsPrimitiveV3fC4ub(primitiveType); return primitive; } GraphicsPrimitiveV3fT3f* GraphicsPrimitive::newPrimitiveV3fT3f(const GraphicsPrimitive::PrimitiveType primitiveType, const uint8_t* imageBytesRGBA, const int32_t imageWidth, const int32_t imageHeight) { GraphicsPrimitiveV3fT3f* primitive = new GraphicsPrimitiveV3fT3f(primitiveType, imageBytesRGBA, imageWidth, imageHeight); return primitive; } connectome-workbench-1.4.2/src/Graphics/GraphicsPrimitive.h000066400000000000000000000503161360521144700237710ustar00rootroot00000000000000#ifndef __GRAPHICS_PRIMITIVE_H__ #define __GRAPHICS_PRIMITIVE_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "CaretObject.h" #include "EventListenerInterface.h" namespace caret { class BoundingBox; class GraphicsEngineDataOpenGL; class GraphicsPrimitiveV3f; class GraphicsPrimitiveV3fC4f; class GraphicsPrimitiveV3fC4ub; class GraphicsPrimitiveV3fN3f; class GraphicsPrimitiveV3fT3f; class GraphicsPrimitive : public CaretObject, public EventListenerInterface { public: /** * Data type of vertices */ enum class VertexDataType { /** Vertices are three float values per vertex containing X, Y, Z */ FLOAT_XYZ }; /** * Data type of normal vectors */ enum class NormalVectorDataType { /** No normal vectors */ NONE, /** Normal vectors are three float values per vertex contain X, Y, Z ranging 0.0 to 1.0 */ FLOAT_XYZ }; /** * Data type of colors */ enum class ColorDataType { /** No color components */ NONE, /** Four float values per vertex containing Red, Green, Blue, Alpha ranging 0.0 to 1.0 */ FLOAT_RGBA, /** Four unsigned byte values per vertex containing Red, Green, Blue, Alpha ranging 0 to 255 */ UNSIGNED_BYTE_RGBA }; /** * Coloring for each vertex thype */ enum class VertexColorType { /** No color components */ NONE, /** One RGBA for all vertices */ SOLID_RGBA, /** Unique RGBA for each vertex */ PER_VERTEX_RGBA }; /** * Data type of texture components */ enum class TextureDataType { /** No texture coordinates */ NONE, /** Three float values per vertex contains S, T, and R texture coordinates */ FLOAT_STR }; /** * Type of primitives for drawing. There are NO primitives equivalent to * OpenGL's GL_QUAD_STRIP and GL_POLYGON. The reason is that these * primitive types are removed in 3.x (probably 3.2). * * Descriptions are copied from the glVertex man page. */ enum class PrimitiveType { /** * Draws a connected group of line segments from the first vertex to the last. * Vertices n and n+1 define line n. n-1 lines are drawn. * Note: OpenGL supports a limited range of line widths, usually [0.5, 10] pixels */ OPENGL_LINE_LOOP, /** * Treats each pair of vertices as an independent line segment. * Vertices 2n-1 and 2n define line n. n/2 lines are drawn. * Note: OpenGL supports a limited range of line widths, usually [0.5, 10] pixels */ OPENGL_LINE_STRIP, /** * Draws a connected group of line segments from the first vertex to the last, then back * to the first. Vertices n and n+1 define line n. The last line, however, is defined by * vertices n and 1. n lines are drawn. * Note: OpenGL supports a limited range of line widths, usually [0.5, 10] pixels */ OPENGL_LINES, /** * Treats each vertex as a single point. Vertex n defines point n. n points are drawn. */ OPENGL_POINTS, /** * Draws a connected group of triangles. One triangle is defined for each vertex * presented after the first two vertices. Vertices 1, n+1, and n+2 define triangle n. n-2 * triangles are drawn. */ OPENGL_TRIANGLE_FAN, /** * Draws a connected group of triangles. One triangle is defined for each vertex * presented after the first two vertices. For odd n, vertices n, n+1, and n+2 define * triangle n. For even n, vertices n+1, n, and n+2 define triangle n. n-2 triangles are * drawn. */ OPENGL_TRIANGLE_STRIP, /** * Treats each triplet of vertices as an independent triangle. Vertices 3n-2, 3n-1, and * 3n define triangle n. n/3 triangles are drawn. */ OPENGL_TRIANGLES, /** * Like OPENGL_LINE_LOOP but there is no limit on line width as it draws the lines using polygons * and polygons that form the line use a BEVEL join at vertices. * Draws in MODEL space so lines are affected by model transformations */ MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN, /** * Like OPENGL_LINE_LOOP but there is no limit on line width as it draws the lines using polygons * and polygons that form the line use a MITER join at vertices * Draws in MODEL space so lines are affected by model transformations */ MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN, /** * Like OPENGL_LINE_STRIP but there is no limit on line width as it draws the lines using polygons * and polygons that form the line use a BEVEL join at vertices * Draws in MODEL space so lines are affected by model transformations */ MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN, /** * Like OPENGL_LINE_STRIP but there is no limit on line width as it draws the lines using polygons * and polygons that form the line use a MITER join at vertices * Draws in MODEL space so lines are affected by model transformations */ MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN, /** * Like OPENGL_LINES but there is no limit on line width as it draws the lines using polygons. * Draws in MODEL space so lines are affected by model transformations */ MODEL_SPACE_POLYGONAL_LINES, /** * Like OPENGL_LINE_LOOP but there is no limit on line width as it draws the lines using polygons * and polygons that form the line use a BEVEL join at vertices. * Lines drawn in window space so that lines always face user */ POLYGONAL_LINE_LOOP_BEVEL_JOIN, /** * Like OPENGL_LINE_LOOP but there is no limit on line width as it draws the lines using polygons * and polygons that form the line use a MITER join at vertices * Lines drawn in window space so that lines always face user */ POLYGONAL_LINE_LOOP_MITER_JOIN, /** * Like OPENGL_LINE_STRIP but there is no limit on line width as it draws the lines using polygons * and polygons that form the line use a BEVEL join at vertices * Lines drawn in window space so that lines always face user */ POLYGONAL_LINE_STRIP_BEVEL_JOIN, /** * Like OPENGL_LINE_STRIP but there is no limit on line width as it draws the lines using polygons * and polygons that form the line use a MITER join at vertices * Lines drawn in window space so that lines always face user */ POLYGONAL_LINE_STRIP_MITER_JOIN, /** * Like OPENGL_LINES but there is no limit on line width as it draws the lines using polygons. * Lines drawn in window space so that lines always face user */ POLYGONAL_LINES, /* * Draws sphere at each vertex */ SPHERES }; /** * Type for point size */ enum class PointSizeType { /** * Millimeters (all models surface, volume, etc. are drawn * in millimeters). */ MILLIMETERS, /** * Size of point or width of line is a percentage of viewport height. * Ranges [0.0, 100.0] */ PERCENTAGE_VIEWPORT_HEIGHT, /** * Size of point or width of line is in pixels */ PIXELS }; /** * Type for line width */ enum class LineWidthType { /** * Size of point or width of line is a percentage of viewport height. * Ranges [0.0, 100.0] */ PERCENTAGE_VIEWPORT_HEIGHT, /** * Size of point or width of line is in pixels */ PIXELS }; /** * Type for sphere size */ enum class SphereSizeType { /** * Millimeters (all models surface, volume, etc. are drawn * in millimeters). */ MILLIMETERS }; /** * Hint to graphics engine on how the primitive is used. * The hint must be set prior to loading of buffers. */ enum class UsageType { /** * Buffer is modified once and used a few times * Like OpenGL STREAM_DRAW */ MODIFIED_ONCE_DRAWN_FEW_TIMES, /** * Buffer is modified once and used many times * Like OpenGL STATIC_DRAW */ MODIFIED_ONCE_DRAWN_MANY_TIMES, /** * Buffer is modified many times and used many times * Like OpenGL DYNAMIC_DRAW */ MODIFIED_MANY_DRAWN_MANY_TIMES }; protected: GraphicsPrimitive(const VertexDataType vertexDataType, const NormalVectorDataType normalVectorDataType, const ColorDataType colorDataType, const VertexColorType vertexColorType, const TextureDataType textureDataType, const PrimitiveType primitiveType); GraphicsPrimitive(const GraphicsPrimitive& obj); private: GraphicsPrimitive& operator=(const GraphicsPrimitive& obj); public: static GraphicsPrimitiveV3f* newPrimitiveV3f(const GraphicsPrimitive::PrimitiveType primitiveType, const float floatRGBA[4]); static GraphicsPrimitiveV3f* newPrimitiveV3f(const GraphicsPrimitive::PrimitiveType primitiveType, const uint8_t unsignedByteRGBA[4]); static GraphicsPrimitiveV3fN3f* newPrimitiveV3fN3f(const GraphicsPrimitive::PrimitiveType primitiveType, const uint8_t unsignedByteRGBA[4]); static GraphicsPrimitiveV3fC4f* newPrimitiveV3fC4f(const GraphicsPrimitive::PrimitiveType primitiveType); static GraphicsPrimitiveV3fC4ub* newPrimitiveV3fC4ub(const GraphicsPrimitive::PrimitiveType primitiveType); static GraphicsPrimitiveV3fT3f* newPrimitiveV3fT3f(const GraphicsPrimitive::PrimitiveType primitiveType, const uint8_t* imageBytesRGBA, const int32_t imageWidth, const int32_t imageHeight); virtual ~GraphicsPrimitive(); void reserveForNumberOfVertices(const int32_t numberOfVertices); UsageType getUsageTypeCoordinates() const; UsageType getUsageTypeNormals() const; UsageType getUsageTypeColors() const; UsageType getUsageTypeTextureCoordinates() const; void setUsageTypeAll(const UsageType usage); void setUsageTypeCoordinates(const UsageType usage); void setUsageTypeNormals(const UsageType usage); void setUsageTypeColors(const UsageType usage); void setUsageTypeTextureCoordinates(const UsageType usage); virtual void receiveEvent(Event* event); bool isValid() const; /** * @return Data type of the vertices. */ inline VertexDataType getVertexDataType() const { return m_vertexDataType; } /** * @return Data type of the normal vectors. */ inline NormalVectorDataType getNormalVectorDataType () const { return m_normalVectorDataType; } /** * @return Data type of the colors. */ inline ColorDataType getColorDataType() const { return m_colorDataType; } /** * @return Type of vertex colors */ inline VertexColorType getVertexColorType() const { return m_vertexColorType; } /** * @return Type of primitive. */ inline PrimitiveType getPrimitiveType() const { return m_primitiveType; } /** * @return Data type of texture. */ inline TextureDataType getTextureDataType() const { return m_textureDataType; } /** * @return The float coordinates. */ const std::vector& getFloatXYZ() const { return m_xyz; } void getVertexFloatXYZ(const int32_t vertexIndex, float xyzOut[3]) const; void replaceFloatXYZ(const std::vector& xyz); /** * @return The number of vertices */ inline int32_t getNumberOfVertices() const { return (m_xyz.size() / 3); } void replaceVertexFloatXYZ(const int32_t vertexIndex, const float xyz[3]); void getVertexFloatRGBA(const int32_t vertexIndex, float rgbaOut[4]) const; void replaceVertexFloatRGBA(const int32_t vertexIndex, const float rgba[4]); void getVertexByteRGBA(const int32_t vertexIndex, uint8_t rgbaOut[4]) const; void replaceVertexByteRGBA(const int32_t vertexIndex, const uint8_t rgba[4]); void replaceAllVertexSolidByteRGBA(const uint8_t rgba[4]); void replaceAllVertexSolidFloatRGBA(const float rgba[4]); bool getVertexBounds(BoundingBox& boundingBoxOut) const; void addPrimitiveRestart(); void getPointDiameter(PointSizeType& sizeTypeOut, float& pointDiameterOut) const; void setPointDiameter(const PointSizeType sizeType, const float pointDiameter) const; void getLineWidth(LineWidthType& widthTypeOut, float& lineWidthOut) const; void setLineWidth(const LineWidthType widthType, const float lineWidth) const; void getSphereDiameter(SphereSizeType& sizeTypeOut, float& sphereDiameterOut) const; void setSphereDiameter(const SphereSizeType sizeType, const float sphereDiameter) const; GraphicsEngineDataOpenGL* getGraphicsEngineDataForOpenGL(); void setGraphicsEngineDataForOpenGL(GraphicsEngineDataOpenGL* graphicsEngineDataForOpenGL); virtual AString toString() const override; virtual void print() const; /** * Clone this primitive. */ virtual GraphicsPrimitive* clone() const = 0; void simplfyLines(const int32_t skipVertexCount); protected: AString toStringPrivate(const bool includeAllDataFlag) const; void setTextureImage(const uint8_t* imageBytesRGBA, const int32_t imageWidth, const int32_t imageHeight); void addVertexProtected(const float xyz[3], const float normalVector[3], const float rgbaFloat[4], const uint8_t rgbaByte[4], const float textureSTR[3]); AString getPrimitiveTypeAsText() const; AString getLineWidthTypeAsText(const LineWidthType lineWidthType) const; AString getPointSizeTypeAsText(const PointSizeType sizeType) const; AString getSphereSizeTypeAsText(const SphereSizeType sizeType) const; AString getVertexColorTypeAsText(const VertexColorType vertexColorType) const; const VertexDataType m_vertexDataType; const NormalVectorDataType m_normalVectorDataType; const ColorDataType m_colorDataType; const VertexColorType m_vertexColorType; const TextureDataType m_textureDataType; const PrimitiveType m_primitiveType; mutable bool m_boundingBoxValid = false; UsageType m_usageTypeCoordinates = UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES; UsageType m_usageTypeNormals = UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES; UsageType m_usageTypeColors = UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES; UsageType m_usageTypeTextureCoordinates = UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES; std::unique_ptr m_graphicsEngineDataForOpenGL; int32_t m_textureImageWidth = -1; int32_t m_textureImageHeight = -1; mutable PointSizeType m_pointSizeType = PointSizeType::PIXELS; mutable float m_pointDiameterValue = 1.0f; mutable LineWidthType m_lineWidthType = LineWidthType::PIXELS; mutable float m_lineWidthValue = 1.0f; mutable SphereSizeType m_sphereSizeType = SphereSizeType::MILLIMETERS; mutable float m_sphereDiameterValue = 1.0f; mutable std::unique_ptr m_boundingBox; std::set m_polygonalLinePrimitiveRestartIndices; int32_t m_triangleStripPrimitiveRestartIndex = -1; private: void copyHelperGraphicsPrimitive(const GraphicsPrimitive& obj); void copyVertex(const int32_t copyFromIndex, const int32_t copyToIndex); void fillTriangleStripPrimitiveRestartVertices(); std::vector m_xyz; std::vector m_floatNormalVectorXYZ; std::vector m_floatRGBA; std::vector m_unsignedByteRGBA; std::vector m_floatTextureSTR; std::vector m_textureImageBytesRGBA; friend class GraphicsEngineDataOpenGL; friend class GraphicsOpenGLPolylineTriangles; friend class GraphicsPrimitiveSelectionHelper; // ADD_NEW_MEMBERS_HERE }; #ifdef __GRAPHICS_PRIMITIVE_DECLARE__ // #endif // __GRAPHICS_PRIMITIVE_DECLARE__ } // namespace #endif //__GRAPHICS_PRIMITIVE_H__ connectome-workbench-1.4.2/src/Graphics/GraphicsPrimitiveSelectionHelper.cxx000066400000000000000000000254701360521144700273550ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GRAPHICS_PRIMITIVE_SELECTION_HELPER_DECLARE__ #include "GraphicsPrimitiveSelectionHelper.h" #undef __GRAPHICS_PRIMITIVE_SELECTION_HELPER_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "GraphicsPrimitive.h" using namespace caret; /** * \class caret::GraphicsPrimitiveSelectionHelper * \brief Helps with identification of graphics primitives * \ingroup Graphics */ /** * Constructor. */ GraphicsPrimitiveSelectionHelper::GraphicsPrimitiveSelectionHelper(GraphicsPrimitive* parentGraphicsPrimitive) : CaretObject(), m_parentGraphicsPrimitive(parentGraphicsPrimitive) { CaretAssert(m_parentGraphicsPrimitive); } /** * Destructor. */ GraphicsPrimitiveSelectionHelper::~GraphicsPrimitiveSelectionHelper() { } /** * Setup selection data just before drawing. */ void GraphicsPrimitiveSelectionHelper::setupSelectionBeforeDrawing() { int32_t numberOfVertices = 0; switch (m_parentGraphicsPrimitive->getVertexDataType()) { case GraphicsPrimitive::VertexDataType::FLOAT_XYZ: numberOfVertices = m_parentGraphicsPrimitive->getFloatXYZ().size() / 3; break; } m_numberOfVerticesPerPrimitive = 0; m_vertexOffsetForPrimitive = 0; switch (m_parentGraphicsPrimitive->getPrimitiveType()) { case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_LOOP: case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN: m_numberOfVerticesPerPrimitive = 1; //numberOfVertices; break; case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_STRIP_MITER_JOIN: case GraphicsPrimitive::PrimitiveType::OPENGL_LINE_STRIP: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN: m_numberOfVerticesPerPrimitive = 1; //numberOfVertices; break; case GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINES: case GraphicsPrimitive::PrimitiveType::OPENGL_LINES: case GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES: m_numberOfVerticesPerPrimitive = 2; break; case GraphicsPrimitive::PrimitiveType::OPENGL_POINTS: m_numberOfVerticesPerPrimitive = 1; break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN: /* * Assuming vertices start at ZERO * Color is at vertex (i + 2): * Vertex[2] is color for first triangle, * Vertex[3] is color for second triangle... */ m_numberOfVerticesPerPrimitive = 1; m_vertexOffsetForPrimitive = 2; break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP: /* * Assuming vertices start at ZERO * Color is at vertex (i + 2): * Vertex[2] is color for first triangle, * Vertex[3] is color for second triangle... */ m_numberOfVerticesPerPrimitive = 1; m_vertexOffsetForPrimitive = 2; break; case GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES: m_numberOfVerticesPerPrimitive = 3; break; case GraphicsPrimitive::PrimitiveType::SPHERES: m_numberOfVerticesPerPrimitive = numberOfVertices; break; } if (numberOfVertices > 0) { const int32_t numberOfPrimitives = (numberOfVertices / m_numberOfVerticesPerPrimitive) - m_vertexOffsetForPrimitive; const int32_t maxPrimitivesSupported = 255 * 255 * 255; if (numberOfPrimitives > maxPrimitivesSupported) { const AString msg("Number of primitives for selection=" + AString::number(numberOfPrimitives) + " exceeds maximum allowed=" + AString::number(maxPrimitivesSupported)); CaretAssertMessage(0, msg); CaretLogSevere(msg); } else { const int32_t selectionRgbaSize = numberOfVertices * 4; if (selectionRgbaSize != static_cast(m_selectionEncodedRGBA.size())) { const GraphicsPrimitive::ColorDataType colorType = m_parentGraphicsPrimitive->getColorDataType(); m_selectionEncodedRGBA.resize(selectionRgbaSize); /* * Encode the primitive index into the RGBA selection data. */ int32_t indexRGBA = 0; const int32_t startIndex = m_vertexOffsetForPrimitive; const int32_t endIndex = m_vertexOffsetForPrimitive + numberOfPrimitives; for (int32_t primitiveIndex = startIndex; primitiveIndex < endIndex; primitiveIndex++) { uint8_t blue = (uint8_t)(primitiveIndex & 0xff); uint8_t green = (uint8_t)((primitiveIndex >> 8) & 0xff); uint8_t red = (uint8_t)((primitiveIndex >> 16) & 0xff); /* * Same ID color at all vertices of a primitive */ for (int32_t j = 0; j < m_numberOfVerticesPerPrimitive; j++) { CaretAssertVectorIndex(m_selectionEncodedRGBA, indexRGBA+3); m_selectionEncodedRGBA[indexRGBA] = red; m_selectionEncodedRGBA[indexRGBA+1] = green; m_selectionEncodedRGBA[indexRGBA+2] = blue; uint8_t vertexAlpha = 0; const int32_t vertexAlphaIndex = indexRGBA + 3; switch (colorType) { case GraphicsPrimitive::ColorDataType::NONE: vertexAlpha = 255; break; case GraphicsPrimitive::ColorDataType::FLOAT_RGBA: CaretAssertVectorIndex(m_parentGraphicsPrimitive->m_floatRGBA, vertexAlphaIndex); vertexAlpha = static_cast(m_parentGraphicsPrimitive->m_floatRGBA[vertexAlphaIndex] * 255); break; case GraphicsPrimitive::ColorDataType::UNSIGNED_BYTE_RGBA: CaretAssertVectorIndex(m_parentGraphicsPrimitive->m_unsignedByteRGBA, vertexAlphaIndex); vertexAlpha = m_parentGraphicsPrimitive->m_unsignedByteRGBA[vertexAlphaIndex]; break; } m_selectionEncodedRGBA[indexRGBA+3] = vertexAlpha; if (primitiveIndex == startIndex) { if (startIndex > 0) { /* * For THE FIRST triangle in a triangle strip or fan, * its color is at vertex 2 (assuming first index is ZERO). * Here we copy the color from vertex 2 to vertices * 0 and 1. This is not absolutely necessary but it * ensures correct color values and avoid a possible * NaN from unintialized values. */ for (int32_t m = 0; m < startIndex; m++) { const int32_t m4 = m * 4; for (int32_t n = 0; n < 4; n++) { m_selectionEncodedRGBA[m4 + n] = m_selectionEncodedRGBA[indexRGBA + n]; } } } } indexRGBA += 4; } } } } } else { m_selectionEncodedRGBA.clear(); } } /** * Get the index of the primitive that was selected using the encoded RGBA. * * @param rgba * RGBA with encoded selection information. * @return * Index of selected primitive or -1 if none selected. */ int32_t GraphicsPrimitiveSelectionHelper::getPrimitiveIndexFromEncodedRGBA(const uint8_t rgba[4]) const { int32_t primitiveIndex(-1); const int32_t numberOfVertices = static_cast(m_selectionEncodedRGBA.size() / 4); if (numberOfVertices > 0) { CaretAssert(m_numberOfVerticesPerPrimitive > 0); for (int32_t i = 0; i < numberOfVertices; i++) { const int32_t i4 = i * 4; CaretAssertVectorIndex(m_selectionEncodedRGBA, i4+3); if ((rgba[0] == m_selectionEncodedRGBA[i4]) && (rgba[1] == m_selectionEncodedRGBA[i4+1]) && (rgba[2] == m_selectionEncodedRGBA[i4+2])) { if (m_selectionEncodedRGBA[i4+3] > 0) { primitiveIndex = (i / m_numberOfVerticesPerPrimitive) + m_vertexOffsetForPrimitive; } break; } } } return primitiveIndex; } /** * @return The RGBA data in which identification information is encoded. */ const std::vector& GraphicsPrimitiveSelectionHelper::getSelectionEncodedRGBA() const { return m_selectionEncodedRGBA; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString GraphicsPrimitiveSelectionHelper::toString() const { return "GraphicsPrimitiveSelectionHelper"; } connectome-workbench-1.4.2/src/Graphics/GraphicsPrimitiveSelectionHelper.h000066400000000000000000000043531360521144700267770ustar00rootroot00000000000000#ifndef __GRAPHICS_PRIMITIVE_SELECTION_HELPER_H__ #define __GRAPHICS_PRIMITIVE_SELECTION_HELPER_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" namespace caret { class GraphicsPrimitive; class GraphicsPrimitiveSelectionHelper : public CaretObject { public: GraphicsPrimitiveSelectionHelper(GraphicsPrimitive* parentGraphicsPrimitive); virtual ~GraphicsPrimitiveSelectionHelper(); void setupSelectionBeforeDrawing(); const std::vector& getSelectionEncodedRGBA() const; int32_t getPrimitiveIndexFromEncodedRGBA(const uint8_t rgba[4]) const; // ADD_NEW_METHODS_HERE virtual AString toString() const; private: GraphicsPrimitiveSelectionHelper(const GraphicsPrimitiveSelectionHelper&); GraphicsPrimitiveSelectionHelper& operator=(const GraphicsPrimitiveSelectionHelper&); GraphicsPrimitive* m_parentGraphicsPrimitive; int32_t m_numberOfVerticesPerPrimitive = 0; int32_t m_vertexOffsetForPrimitive = 0; std::vector m_selectionEncodedRGBA; // ADD_NEW_MEMBERS_HERE }; #ifdef __GRAPHICS_PRIMITIVE_SELECTION_HELPER_DECLARE__ // #endif // __GRAPHICS_PRIMITIVE_SELECTION_HELPER_DECLARE__ } // namespace #endif //__GRAPHICS_PRIMITIVE_SELECTION_HELPER_H__ connectome-workbench-1.4.2/src/Graphics/GraphicsPrimitiveV3f.cxx000066400000000000000000000126431360521144700247240ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GRAPHICS_PRIMITIVE_V3F_DECLARE__ #include "GraphicsPrimitiveV3f.h" #undef __GRAPHICS_PRIMITIVE_V3F_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "GraphicsEngineDataOpenGL.h" using namespace caret; /** * \class caret::GraphicsPrimitiveV3f * \brief Primitive containing XYZ with one color (float, unsigned byte) applied to all vertices. * \ingroup Graphics * * When we move to using the programmable pipeline OpenGL, the color components * can be passed to the shader to avoid adding the color to each vertex. */ /** * Constructor for solid color float RGBA. * * @param primitiveType * Type of primitive drawn (triangles, lines, etc.) * @param rgba * RGBA color components ranging 0.0 to 1.0. */ GraphicsPrimitiveV3f::GraphicsPrimitiveV3f(const PrimitiveType primitiveType, const float rgba[4]) : GraphicsPrimitive(VertexDataType::FLOAT_XYZ, NormalVectorDataType::NONE, ColorDataType::FLOAT_RGBA, VertexColorType::SOLID_RGBA, TextureDataType::NONE, primitiveType) { m_floatSolidRGBA[0] = rgba[0]; m_floatSolidRGBA[1] = rgba[1]; m_floatSolidRGBA[2] = rgba[2]; m_floatSolidRGBA[3] = rgba[3]; } /** * Constructor for solid color unsigned byte RGBA. * * @param primitiveType * Type of primitive drawn (triangles, lines, etc.) * @param rgba * RGBA color components ranging 0.0 to 1.0. */ GraphicsPrimitiveV3f::GraphicsPrimitiveV3f(const PrimitiveType primitiveType, const uint8_t rgba[4]) : GraphicsPrimitive(VertexDataType::FLOAT_XYZ, NormalVectorDataType::NONE, ColorDataType::UNSIGNED_BYTE_RGBA, VertexColorType::SOLID_RGBA, TextureDataType::NONE, primitiveType) { m_unsignedByteSolidRGBA[0] = rgba[0]; m_unsignedByteSolidRGBA[1] = rgba[1]; m_unsignedByteSolidRGBA[2] = rgba[2]; m_unsignedByteSolidRGBA[3] = rgba[3]; } /** * Destructor. */ GraphicsPrimitiveV3f::~GraphicsPrimitiveV3f() { } /** * Copy constructor. * @param obj * Object that is copied. */ GraphicsPrimitiveV3f::GraphicsPrimitiveV3f(const GraphicsPrimitiveV3f& obj) : GraphicsPrimitive(obj) { this->copyHelperGraphicsPrimitiveV3f(obj); } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void GraphicsPrimitiveV3f::copyHelperGraphicsPrimitiveV3f(const GraphicsPrimitiveV3f& obj) { for (int32_t i = 0; i < 4; i++) { m_floatSolidRGBA[i] = obj.m_floatSolidRGBA[i]; m_unsignedByteSolidRGBA[i] = obj.m_unsignedByteSolidRGBA[i]; } } /** * Add a vertex. * * @param xyz * Coordinate of vertex. */ void GraphicsPrimitiveV3f::addVertex(const double xyz[3]) { addVertex(xyz[0], xyz[1], xyz[2]); } /** * Add a vertex. * * @param xyz * Coordinate of vertex. */ void GraphicsPrimitiveV3f::addVertex(const float xyz[3]) { addVertexProtected(xyz, NULL, m_floatSolidRGBA, m_unsignedByteSolidRGBA, NULL); } /** * Add a vertex. * * @param x * X-coordinate of vertex. * @param y * Y-coordinate of vertex. * @param z * Z-coordinate of vertex. */ void GraphicsPrimitiveV3f::addVertex(const float x, const float y, const float z) { const float xyz[3] = { x, y, z }; addVertexProtected(xyz, NULL, m_floatSolidRGBA, m_unsignedByteSolidRGBA, NULL); } /** * Add a 2D vertex. Z will be zero. * * @param x * X-coordinate of vertex. * @param y * Y-coordinate of vertex. * @param rgba * RGBA color components ranging 0.0 to 1.0. */ void GraphicsPrimitiveV3f::addVertex(const float x, const float y) { addVertex(x, y, 0.0f); } /** * Add XYZ vertices from an array. * * @param xyzArray * Array containing XYZ vertex data. * @param numberOfVertices * Number of vertices (xyz triplets) to add */ void GraphicsPrimitiveV3f::addVertices(const float xyzArray[], const int32_t numberOfVertices) { for (int32_t i = 0; i < numberOfVertices; i++) { addVertex(&xyzArray[i*3]); } } /** * Clone this primitive. */ GraphicsPrimitive* GraphicsPrimitiveV3f::clone() const { GraphicsPrimitiveV3f* obj = new GraphicsPrimitiveV3f(*this); return obj; } connectome-workbench-1.4.2/src/Graphics/GraphicsPrimitiveV3f.h000066400000000000000000000046301360521144700243460ustar00rootroot00000000000000#ifndef __GRAPHICS_PRIMITIVE_V3F_H__ #define __GRAPHICS_PRIMITIVE_V3F_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "GraphicsPrimitive.h" namespace caret { class GraphicsPrimitiveV3f : public GraphicsPrimitive { public: GraphicsPrimitiveV3f(const PrimitiveType primitiveType, const float rgba[4]); GraphicsPrimitiveV3f(const PrimitiveType primitiveType, const uint8_t rgba[4]); virtual ~GraphicsPrimitiveV3f(); GraphicsPrimitiveV3f(const GraphicsPrimitiveV3f& obj); void addVertex(const float xyz[3]); void addVertex(const double xyz[3]); void addVertex(const float x, const float y, const float z); void addVertex(const float x, const float y); void addVertices(const float xyzArray[], const int32_t numberOfVertices); virtual GraphicsPrimitive* clone() const; // ADD_NEW_METHODS_HERE private: GraphicsPrimitiveV3f& operator=(const GraphicsPrimitiveV3f& obj); void copyHelperGraphicsPrimitiveV3f(const GraphicsPrimitiveV3f& obj); float m_floatSolidRGBA[4]; uint8_t m_unsignedByteSolidRGBA[4]; // ADD_NEW_MEMBERS_HERE }; #ifdef __GRAPHICS_PRIMITIVE_V3F_DECLARE__ // #endif // __GRAPHICS_PRIMITIVE_V3F_DECLARE__ } // namespace #endif //__GRAPHICS_PRIMITIVE_V3F_H__ connectome-workbench-1.4.2/src/Graphics/GraphicsPrimitiveV3fC4f.cxx000066400000000000000000000071171360521144700252610ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GRAPHICS_PRIMITIVE_V3F_C4F_DECLARE__ #include "GraphicsPrimitiveV3fC4f.h" #undef __GRAPHICS_PRIMITIVE_V3F_C4F_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::GraphicsPrimitiveV3fC4f * \brief Primitive containing XYZ and Float RGBA. * \ingroup Graphics */ /** * Constructor. * * @param primitiveType * Type of primitive drawn (triangles, lines, etc.) */ GraphicsPrimitiveV3fC4f::GraphicsPrimitiveV3fC4f(const PrimitiveType primitiveType) : GraphicsPrimitive(VertexDataType::FLOAT_XYZ, NormalVectorDataType::NONE, ColorDataType::FLOAT_RGBA, VertexColorType::PER_VERTEX_RGBA, TextureDataType::NONE, primitiveType) { } /** * Destructor. */ GraphicsPrimitiveV3fC4f::~GraphicsPrimitiveV3fC4f() { } /** * Copy constructor. * @param obj * Object that is copied. */ GraphicsPrimitiveV3fC4f::GraphicsPrimitiveV3fC4f(const GraphicsPrimitiveV3fC4f& obj) : GraphicsPrimitive(obj) { this->copyHelperGraphicsPrimitiveV3fC4f(obj); } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void GraphicsPrimitiveV3fC4f::copyHelperGraphicsPrimitiveV3fC4f(const GraphicsPrimitiveV3fC4f& /*obj*/) { } /** * Add a vertex. * * @param xyz * Coordinate of vertex. * @param rgba * RGBA color components ranging 0.0 to 1.0. */ void GraphicsPrimitiveV3fC4f::addVertex(const float xyz[3], const float rgba[4]) { addVertexProtected(xyz, NULL, rgba, NULL, NULL); } /** * Add a vertex. * * @param x * X-coordinate of vertex. * @param y * Y-coordinate of vertex. * @param z * Z-coordinate of vertex. * @param rgba * RGBA color components ranging 0.0 to 1.0. */ void GraphicsPrimitiveV3fC4f::addVertex(const float x, const float y, const float z, const float rgba[4]) { const float xyz[] { x, y, z }; addVertex(xyz, rgba); } /** * Add a 2D vertex. Z will be zero. * * @param x * X-coordinate of vertex. * @param y * Y-coordinate of vertex. * @param rgba * RGBA color components ranging 0.0 to 1.0. */ void GraphicsPrimitiveV3fC4f::addVertex(const float x, const float y, const float rgba[4]) { const float xyz[] { x, y, 0.0f }; addVertex(xyz, rgba); } /** * Clone this primitive. */ GraphicsPrimitive* GraphicsPrimitiveV3fC4f::clone() const { GraphicsPrimitiveV3fC4f* obj = new GraphicsPrimitiveV3fC4f(*this); return obj; } connectome-workbench-1.4.2/src/Graphics/GraphicsPrimitiveV3fC4f.h000066400000000000000000000042221360521144700247000ustar00rootroot00000000000000#ifndef __GRAPHICS_PRIMITIVE_V3F_C4F_H__ #define __GRAPHICS_PRIMITIVE_V3F_C4F_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "GraphicsPrimitive.h" namespace caret { class GraphicsPrimitiveV3fC4f : public GraphicsPrimitive { public: GraphicsPrimitiveV3fC4f(const PrimitiveType primitiveType); virtual ~GraphicsPrimitiveV3fC4f(); GraphicsPrimitiveV3fC4f(const GraphicsPrimitiveV3fC4f& obj); void addVertex(const float xyz[3], const float rgba[4]); void addVertex(const float x, const float y, const float z, const float rgba[4]); void addVertex(const float x, const float y, const float rgba[4]); virtual GraphicsPrimitive* clone() const; // ADD_NEW_METHODS_HERE private: GraphicsPrimitiveV3fC4f& operator=(const GraphicsPrimitiveV3fC4f& obj); void copyHelperGraphicsPrimitiveV3fC4f(const GraphicsPrimitiveV3fC4f& obj); // ADD_NEW_MEMBERS_HERE }; #ifdef __GRAPHICS_PRIMITIVE_V3F_C4F_DECLARE__ // #endif // __GRAPHICS_PRIMITIVE_V3F_C4F_DECLARE__ } // namespace #endif //__GRAPHICS_PRIMITIVE_V3F_C4F_H__ connectome-workbench-1.4.2/src/Graphics/GraphicsPrimitiveV3fC4ub.cxx000066400000000000000000000063211360521144700254360ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GRAPHICS_PRIMITIVE_V3F_C4UB_DECLARE__ #include "GraphicsPrimitiveV3fC4ub.h" #undef __GRAPHICS_PRIMITIVE_V3F_C4UB_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::GraphicsPrimitiveV3fC4ub * \brief Primitive containing XYZ and Float RGBA. * \ingroup Graphics */ /** * Constructor. * * @param primitiveType * Type of primitive drawn (triangles, lines, etc.) */ GraphicsPrimitiveV3fC4ub::GraphicsPrimitiveV3fC4ub(const PrimitiveType primitiveType) : GraphicsPrimitive(VertexDataType::FLOAT_XYZ, NormalVectorDataType::NONE, ColorDataType::UNSIGNED_BYTE_RGBA, VertexColorType::PER_VERTEX_RGBA, TextureDataType::NONE, primitiveType) { } /** * Destructor. */ GraphicsPrimitiveV3fC4ub::~GraphicsPrimitiveV3fC4ub() { } /** * Copy constructor. * @param obj * Object that is copied. */ GraphicsPrimitiveV3fC4ub::GraphicsPrimitiveV3fC4ub(const GraphicsPrimitiveV3fC4ub& obj) : GraphicsPrimitive(obj) { this->copyHelperGraphicsPrimitiveV3fC4ub(obj); } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void GraphicsPrimitiveV3fC4ub::copyHelperGraphicsPrimitiveV3fC4ub(const GraphicsPrimitiveV3fC4ub& /*obj*/) { } /** * Add a vertex. * * @param xyz * Coordinate of vertex. * @param rgba * RGBA color components ranging 0.0 to 1.0. */ void GraphicsPrimitiveV3fC4ub::addVertex(const float xyz[3], const uint8_t rgba[4]) { addVertexProtected(xyz, NULL, NULL, rgba, NULL); } /** * Add a vertex. * * @param x * X-coordinate of vertex. * @param y * Y-coordinate of vertex. * @param z * Z-coordinate of vertex. * @param rgba * RGBA color components ranging 0.0 to 1.0. */ void GraphicsPrimitiveV3fC4ub::addVertex(const float x, const float y, const float z, const uint8_t rgba[4]) { const float xyz[] { x, y, z }; addVertex(xyz, rgba); } /** * Clone this primitive. */ GraphicsPrimitive* GraphicsPrimitiveV3fC4ub::clone() const { GraphicsPrimitiveV3fC4ub* obj = new GraphicsPrimitiveV3fC4ub(*this); return obj; } connectome-workbench-1.4.2/src/Graphics/GraphicsPrimitiveV3fC4ub.h000066400000000000000000000040401360521144700250570ustar00rootroot00000000000000#ifndef __GRAPHICS_PRIMITIVE_V3F_C4UB_H__ #define __GRAPHICS_PRIMITIVE_V3F_C4UB_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "GraphicsPrimitive.h" namespace caret { class GraphicsPrimitiveV3fC4ub : public GraphicsPrimitive { public: GraphicsPrimitiveV3fC4ub(const PrimitiveType primitiveType); virtual ~GraphicsPrimitiveV3fC4ub(); GraphicsPrimitiveV3fC4ub(const GraphicsPrimitiveV3fC4ub& obj); void addVertex(const float xyz[3], const uint8_t rgba[4]); void addVertex(const float x, const float y, const float z, const uint8_t rgba[4]); virtual GraphicsPrimitive* clone() const; // ADD_NEW_METHODS_HERE private: GraphicsPrimitiveV3fC4ub& operator=(const GraphicsPrimitiveV3fC4ub& obj); void copyHelperGraphicsPrimitiveV3fC4ub(const GraphicsPrimitiveV3fC4ub& obj); // ADD_NEW_MEMBERS_HERE }; #ifdef __GRAPHICS_PRIMITIVE_V3F_C4UB_DECLARE__ // #endif // __GRAPHICS_PRIMITIVE_V3F_C4UB_DECLARE__ } // namespace #endif //__GRAPHICS_PRIMITIVE_V3F_C4UB_H__ connectome-workbench-1.4.2/src/Graphics/GraphicsPrimitiveV3fN3f.cxx000066400000000000000000000162101360521144700252650ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GRAPHICS_PRIMITIVE_V3F_N3F_DECLARE__ #include "GraphicsPrimitiveV3fN3f.h" #undef __GRAPHICS_PRIMITIVE_V3F_N3F_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "GraphicsEngineDataOpenGL.h" using namespace caret; /** * \class caret::GraphicsPrimitiveV3fN3f * \brief Primitive containing vertices, normals, and with one color (float, unsigned byte) applied to all vertices. * \ingroup Graphics * * When we move to using the programmable pipeline OpenGL, the color components * can be passed to the shader to avoid adding the color to each vertex. */ /** * Constructor for solid color float RGBA. * * @param primitiveType * Type of primitive drawn (triangles, lines, etc.) * @param rgba * RGBA color components ranging 0.0 to 1.0. */ GraphicsPrimitiveV3fN3f::GraphicsPrimitiveV3fN3f(const PrimitiveType primitiveType, const float rgba[4]) : GraphicsPrimitive(VertexDataType::FLOAT_XYZ, NormalVectorDataType::FLOAT_XYZ, ColorDataType::FLOAT_RGBA, VertexColorType::SOLID_RGBA, TextureDataType::NONE, primitiveType) { m_floatSolidRGBA[0] = rgba[0]; m_floatSolidRGBA[1] = rgba[1]; m_floatSolidRGBA[2] = rgba[2]; m_floatSolidRGBA[3] = rgba[3]; } /** * Constructor for solid color unsigned byte RGBA. * * @param primitiveType * Type of primitive drawn (triangles, lines, etc.) * @param rgba * RGBA color components ranging 0.0 to 1.0. */ GraphicsPrimitiveV3fN3f::GraphicsPrimitiveV3fN3f(const PrimitiveType primitiveType, const uint8_t rgba[4]) : GraphicsPrimitive(VertexDataType::FLOAT_XYZ, NormalVectorDataType::FLOAT_XYZ, ColorDataType::UNSIGNED_BYTE_RGBA, VertexColorType::SOLID_RGBA, TextureDataType::NONE, primitiveType) { m_unsignedByteSolidRGBA[0] = rgba[0]; m_unsignedByteSolidRGBA[1] = rgba[1]; m_unsignedByteSolidRGBA[2] = rgba[2]; m_unsignedByteSolidRGBA[3] = rgba[3]; } /** * Destructor. */ GraphicsPrimitiveV3fN3f::~GraphicsPrimitiveV3fN3f() { } /** * Copy constructor. * @param obj * Object that is copied. */ GraphicsPrimitiveV3fN3f::GraphicsPrimitiveV3fN3f(const GraphicsPrimitiveV3fN3f& obj) : GraphicsPrimitive(obj) { this->copyHelperGraphicsPrimitiveV3fN3f(obj); } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void GraphicsPrimitiveV3fN3f::copyHelperGraphicsPrimitiveV3fN3f(const GraphicsPrimitiveV3fN3f& obj) { for (int32_t i = 0; i < 4; i++) { m_floatSolidRGBA[i] = obj.m_floatSolidRGBA[i]; m_unsignedByteSolidRGBA[i] = obj.m_unsignedByteSolidRGBA[i]; } } /** * Add a vertex. * * @param xyz * Coordinate of vertex. * @param normalXYZ * Normal vector */ void GraphicsPrimitiveV3fN3f::addVertex(const float xyz[3], const float normalXYZ[3]) { addVertexProtected(xyz, normalXYZ, m_floatSolidRGBA, m_unsignedByteSolidRGBA, NULL); } /** * Add a vertex. * * @param xyz * Coordinate of vertex. * @param normalXYZ * Normal vector */ void GraphicsPrimitiveV3fN3f::addVertex(const double xyz[3], const double normalXYZ[3]) { const float floatXYZ[] { static_cast(xyz[0]), static_cast(xyz[1]), static_cast(xyz[2]) }; const float floatNormalXYZ[3] { static_cast(normalXYZ[0]), static_cast(normalXYZ[1]), static_cast(normalXYZ[2]) }; addVertexProtected(floatXYZ, floatNormalXYZ, m_floatSolidRGBA, m_unsignedByteSolidRGBA, NULL); } /** * Add a vertex. * * @param x * X-coordinate of vertex. * @param y * Y-coordinate of vertex. * @param z * Z-coordinate of vertex. * @param normalX * X component of normal vector * @param normalY * Y component of normal vector * @param normalZ * Z component of normal vector */ void GraphicsPrimitiveV3fN3f::addVertex(const float x, const float y, const float z, const float normalX, const float normalY, const float normalZ) { const float xyz[] { x, y, z }; const float normalXYZ[] { normalX, normalY, normalZ }; addVertexProtected(xyz, normalXYZ, m_floatSolidRGBA, m_unsignedByteSolidRGBA, NULL); } /** * Add a 2D vertex. Z will be zero. * * @param x * X-coordinate of vertex. * @param y * Y-coordinate of vertex. * @param normalX * X component of normal vector * @param normalY * Y component of normal vector */ void GraphicsPrimitiveV3fN3f::addVertex(const float x, const float y, const float normalX, const float normalY) { const float xyz[] { x, y, 0.0f }; const float normalXYZ[] { normalX, normalY, 1.0f }; addVertexProtected(xyz, normalXYZ, m_floatSolidRGBA, m_unsignedByteSolidRGBA, NULL); } /** * Add XYZ vertices from an array. * * @param xyzArray * Array containing XYZ vertex data. * @param normalXyzArray * Array containing XYZ normal vector data. * @param numberOfVertices * Number of vertices (xyz triplets) to add */ void GraphicsPrimitiveV3fN3f::addVertices(const float xyzArray[], const float normalXyzArray[], const int32_t numberOfVertices) { for (int32_t i = 0; i < numberOfVertices; i++) { addVertex(&xyzArray[i*3], &normalXyzArray[i*3]); } } /** * Clone this primitive. */ GraphicsPrimitive* GraphicsPrimitiveV3fN3f::clone() const { GraphicsPrimitiveV3fN3f* obj = new GraphicsPrimitiveV3fN3f(*this); return obj; } connectome-workbench-1.4.2/src/Graphics/GraphicsPrimitiveV3fN3f.h000066400000000000000000000055001360521144700247120ustar00rootroot00000000000000#ifndef __GRAPHICS_PRIMITIVE_V3F_N3F_H__ #define __GRAPHICS_PRIMITIVE_V3F_N3F_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "GraphicsPrimitive.h" namespace caret { class GraphicsPrimitiveV3fN3f : public GraphicsPrimitive { public: GraphicsPrimitiveV3fN3f(const PrimitiveType primitiveType, const float rgba[4]); GraphicsPrimitiveV3fN3f(const PrimitiveType primitiveType, const uint8_t rgba[4]); virtual ~GraphicsPrimitiveV3fN3f(); GraphicsPrimitiveV3fN3f(const GraphicsPrimitiveV3fN3f& obj); void addVertex(const float xyz[3], const float normalXYZ[3]); void addVertex(const double xyz[3], const double normalXYZ[3]); void addVertex(const float x, const float y, const float z, const float normalX, const float normalY, const float normalZ); void addVertex(const float x, const float y, const float normalX, const float normalY); void addVertices(const float xyzArray[], const float normalXyzArray[], const int32_t numberOfVertices); virtual GraphicsPrimitive* clone() const; // ADD_NEW_METHODS_HERE private: GraphicsPrimitiveV3fN3f& operator=(const GraphicsPrimitiveV3fN3f& obj); void copyHelperGraphicsPrimitiveV3fN3f(const GraphicsPrimitiveV3fN3f& obj); float m_floatSolidRGBA[4]; uint8_t m_unsignedByteSolidRGBA[4]; // ADD_NEW_MEMBERS_HERE }; #ifdef __GRAPHICS_PRIMITIVE_V3F_N3F_DECLARE__ // #endif // __GRAPHICS_PRIMITIVE_V3F_N3F_DECLARE__ } // namespace #endif //__GRAPHICS_PRIMITIVE_V3F_N3F_H__ connectome-workbench-1.4.2/src/Graphics/GraphicsPrimitiveV3fT3f.cxx000066400000000000000000000104421360521144700252740ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GRAPHICS_PRIMITIVE_V3F_T3F_DECLARE__ #include "GraphicsPrimitiveV3fT3f.h" #undef __GRAPHICS_PRIMITIVE_V3F_T3F_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::GraphicsPrimitiveV3fT3f * \brief Primitive containing XYZ with and texture coordinates applied to all vertices. * \ingroup Graphics */ /** * Constructor for solid color float RGBA. * * @param primitiveType * Type of primitive drawn (triangles, lines, etc.) * @param imageBytesRGBA * Bytes containing the image data. * @param imageWidth * Width of the actual image. * @param imageHeight * Height of the image. */ GraphicsPrimitiveV3fT3f::GraphicsPrimitiveV3fT3f(const PrimitiveType primitiveType, const uint8_t* imageBytesRGBA, const int32_t imageWidth, const int32_t imageHeight) : GraphicsPrimitive(VertexDataType::FLOAT_XYZ, NormalVectorDataType::NONE, ColorDataType::NONE, VertexColorType::NONE, TextureDataType::FLOAT_STR, primitiveType) { setTextureImage(imageBytesRGBA, imageWidth, imageHeight); } /** * Destructor. */ GraphicsPrimitiveV3fT3f::~GraphicsPrimitiveV3fT3f() { } /** * Copy constructor. * @param obj * Object that is copied. */ GraphicsPrimitiveV3fT3f::GraphicsPrimitiveV3fT3f(const GraphicsPrimitiveV3fT3f& obj) : GraphicsPrimitive(obj) { this->copyHelperGraphicsPrimitiveV3fT3f(obj); } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void GraphicsPrimitiveV3fT3f::copyHelperGraphicsPrimitiveV3fT3f(const GraphicsPrimitiveV3fT3f& /*obj*/) { } /** * Add a vertex. * * @param xyz * Coordinate of vertex. * @parma st * Texture coordinates */ void GraphicsPrimitiveV3fT3f::addVertex(const float xyz[3], const float st[2]) { const float str[] { st[0], st[1], 0.0f } ; addVertexProtected(xyz, NULL, NULL, NULL, str); } /** * Add a vertex. * * @param x * X-coordinate of vertex. * @param y * Y-coordinate of vertex. * @param z * Z-coordinate of vertex. * @param s * S-coordinate of texture * @param t * T-coordinate of texture */ void GraphicsPrimitiveV3fT3f::addVertex(const float x, const float y, const float z, const float s, const float t) { const float xyz[] { x, y, z }; const float str[] { s, t, 0.0f }; addVertex(xyz, str); } /** * Add a 2D vertex. Z will be zero. * * @param x * X-coordinate of vertex. * @param y * Y-coordinate of vertex. * @param s * S-coordinate of texture * @param t * T-coordinate of texture */ void GraphicsPrimitiveV3fT3f::addVertex(const float x, const float y, const float s, const float t) { addVertex(x, y, 0.0f, s, t); } /** * Clone this primitive. */ GraphicsPrimitive* GraphicsPrimitiveV3fT3f::clone() const { GraphicsPrimitiveV3fT3f* obj = new GraphicsPrimitiveV3fT3f(*this); return obj; } connectome-workbench-1.4.2/src/Graphics/GraphicsPrimitiveV3fT3f.h000066400000000000000000000045741360521144700247320ustar00rootroot00000000000000#ifndef __GRAPHICS_PRIMITIVE_V3F_T3F_H__ #define __GRAPHICS_PRIMITIVE_V3F_T3F_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "GraphicsPrimitive.h" namespace caret { class GraphicsPrimitiveV3fT3f : public GraphicsPrimitive { public: GraphicsPrimitiveV3fT3f(const PrimitiveType primitiveType, const uint8_t* imageBytesRGBA, const int32_t imageWidth, const int32_t imageHeight); virtual ~GraphicsPrimitiveV3fT3f(); GraphicsPrimitiveV3fT3f(const GraphicsPrimitiveV3fT3f& obj); void addVertex(const float xyz[3], const float st[2]); void addVertex(const float x, const float y, const float z, const float s, const float t); void addVertex(const float x, const float y, const float s, const float t); virtual GraphicsPrimitive* clone() const; // ADD_NEW_METHODS_HERE private: GraphicsPrimitiveV3fT3f& operator=(const GraphicsPrimitiveV3fT3f& obj); void copyHelperGraphicsPrimitiveV3fT3f(const GraphicsPrimitiveV3fT3f& obj); // ADD_NEW_MEMBERS_HERE }; #ifdef __GRAPHICS_PRIMITIVE_V3F_T3F_DECLARE__ // #endif // __GRAPHICS_PRIMITIVE_V3F_T3F_DECLARE__ } // namespace #endif //__GRAPHICS_PRIMITIVE_V3F_T3F_H__ connectome-workbench-1.4.2/src/Graphics/GraphicsShape.cxx000066400000000000000000001473771360521144700234520ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GRAPHICS_SHAPE_DECLARE__ #include "GraphicsShape.h" #undef __GRAPHICS_SHAPE_DECLARE__ #include #include "CaretAssert.h" #include "CaretLogger.h" #include "GraphicsEngineDataOpenGL.h" #include "GraphicsPrimitive.h" #include "GraphicsPrimitiveV3f.h" #include "GraphicsPrimitiveV3fC4ub.h" #include "GraphicsPrimitiveV3fN3f.h" #include "MathFunctions.h" #include "Matrix4x4.h" using namespace caret; /** * \class caret::GraphicsShape * \brief Methods for drawing shapes. * \ingroup Graphics */ /** * Constructor. */ GraphicsShape::GraphicsShape() : CaretObject() { } /** * Destructor. */ GraphicsShape::~GraphicsShape() { } /** * Delete all primitives. */ void GraphicsShape::deleteAllPrimitives() { for (auto iter : s_byteSpherePrimitives) { delete iter.second; } s_byteSpherePrimitives.clear(); for (auto iter : s_byteCirclePrimitives) { delete iter.second; } s_byteCirclePrimitives.clear(); for (auto iter : s_byteRingPrimitives) { delete iter.second; } s_byteRingPrimitives.clear(); /* * Need to delete here or it will cause a crash * as there is no EventManager when static data * is deleted. */ s_byteSquarePrimitive.reset(); } /** * Draw an outline box. * * @param v1 * First vertex. * @param v2 * Second vertex. * @param v3 * Third vertex. * @param v4 * Fourth vertex. * @param rgba * Color for drawing. * @param lineThicknessType * Type of line thickness. * @param lineThickness * Thickness of the line. */ void GraphicsShape::drawBoxOutlineByteColor(const float v1[3], const float v2[3], const float v3[3], const float v4[3], const uint8_t rgba[4], const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness) { std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN, rgba)); primitive->reserveForNumberOfVertices(4); primitive->addVertex(v1); primitive->addVertex(v2); primitive->addVertex(v3); primitive->addVertex(v4); primitive->setLineWidth(lineThicknessType, lineThickness); primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); GraphicsEngineDataOpenGL::draw(primitive.get()); } /** * Draw an outline box. * * @param v1 * First vertex. * @param v2 * Second vertex. * @param v3 * Third vertex. * @param v4 * Fourth vertex. * @param rgba * Color for drawing. * @param lineThicknessType * Type of line thickness. * @param lineThickness * Thickness of the line. */ void GraphicsShape::drawBoxOutlineFloatColor(const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float rgba[4], const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness) { std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN, rgba)); primitive->reserveForNumberOfVertices(4); primitive->addVertex(v1); primitive->addVertex(v2); primitive->addVertex(v3); primitive->addVertex(v4); primitive->setLineWidth(lineThicknessType, lineThickness); primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); GraphicsEngineDataOpenGL::draw(primitive.get()); } /** * Draw a filled box. Vertices must be in a counter-clockwise order. * * @param v1 * First vertex. * @param v2 * Second vertex. * @param v3 * Third vertex. * @param v4 * Fourth vertex. * @param rgba * Color for drawing. */ void GraphicsShape::drawBoxFilledByteColor(const float v1[3], const float v2[3], const float v3[3], const float v4[3], const uint8_t rgba[4]) { std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES, rgba)); primitive->reserveForNumberOfVertices(6); primitive->addVertex(v1); primitive->addVertex(v2); primitive->addVertex(v3); primitive->addVertex(v3); primitive->addVertex(v4); primitive->addVertex(v1); primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); GraphicsEngineDataOpenGL::draw(primitive.get()); } /** * Draw a filled box. Vertices must be in a counter-clockwise order. * * @param v1 * First vertex. * @param v2 * Second vertex. * @param v3 * Third vertex. * @param v4 * Fourth vertex. * @param rgba * Color for drawing. */ void GraphicsShape::drawBoxFilledFloatColor(const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float rgba[4]) { std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES, rgba)); primitive->reserveForNumberOfVertices(6); primitive->addVertex(v1); primitive->addVertex(v2); primitive->addVertex(v3); primitive->addVertex(v3); primitive->addVertex(v4); primitive->addVertex(v1); primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); GraphicsEngineDataOpenGL::draw(primitive.get()); } /** * Draw an outline ellipse. * * @param majorAxis * Diameter of the major axis. * @param minorAxis * Diameter of the minor axis. * @param rgba * Color for drawing. * @param lineThicknessType * Type of line thickness. * @param lineThickness * Thickness of the line. */ void GraphicsShape::drawEllipseOutlineByteColor(const double majorAxis, const double minorAxis, const uint8_t rgba[4], const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness) { std::vector ellipseXYZ; createEllipseVertices(majorAxis, minorAxis, ellipseXYZ); std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_LOOP_MITER_JOIN, rgba)); const int32_t numVertices = static_cast(ellipseXYZ.size() / 3); primitive->reserveForNumberOfVertices(numVertices); for (int32_t i = 0; i < numVertices; i++) { primitive->addVertex(&ellipseXYZ[i * 3]); } primitive->setLineWidth(lineThicknessType, lineThickness); primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); GraphicsEngineDataOpenGL::draw(primitive.get()); } /** * Draw an outline ellipse in the XY plane (all Z-coordinates will be zero). * * @param majorAxis * Diameter of the major axis. * @param minorAxis * Diameter of the minor axis. * @param rgba * Color for drawing. * @param lineThickness * Thickness of the line. */ void GraphicsShape::drawEllipseOutlineModelSpaceByteColor(const double majorAxis, const double minorAxis, const uint8_t rgba[4], const double lineThickness) { std::vector ellipseXYZ; createEllipseVertices(majorAxis, minorAxis, ellipseXYZ); std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::MODEL_SPACE_POLYGONAL_LINE_LOOP_MITER_JOIN, rgba)); const int32_t numVertices = static_cast(ellipseXYZ.size() / 3); primitive->reserveForNumberOfVertices(numVertices); for (int32_t i = 0; i < numVertices; i++) { primitive->addVertex(&ellipseXYZ[i * 3]); } primitive->setLineWidth(GraphicsPrimitive::LineWidthType::PIXELS, lineThickness); primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); GraphicsEngineDataOpenGL::draw(primitive.get()); } /** * Draw a filled ellipse. * * @param majorAxis * Diameter of the major axis. * @param minorAxis * Diameter of the minor axis. * @param rgba * Color for drawing. */ void GraphicsShape::drawEllipseFilledByteColor(const double majorAxis, const double minorAxis, const uint8_t rgba[4]) { std::vector ellipseXYZ; createEllipseVertices(majorAxis, minorAxis, ellipseXYZ); const int32_t numVertices = static_cast(ellipseXYZ.size() / 3); std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN, rgba)); primitive->reserveForNumberOfVertices(numVertices + 1); const float center[3] = { 0.0f, 0.0f, 0.0f }; primitive->addVertex(center); for (int32_t i = 0; i < numVertices; i++) { primitive->addVertex(&ellipseXYZ[i * 3]); } primitive->addVertex(&ellipseXYZ[0]); primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); GraphicsEngineDataOpenGL::draw(primitive.get()); } /** * Draw lines: Each pair of vertices is a separate line segment * similar to OpenGL's GL_LINES * * @param xyz * Coordinates of the line end points. * @param rgba * Color for drawing. * @param lineThicknessType * Type of line thickness. * @param lineThickness * Thickness of the line. */ void GraphicsShape::drawLinesByteColor(const std::vector& xyz, const uint8_t rgba[4], const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness) { std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINES, rgba)); const int32_t numVertices = static_cast(xyz.size() / 3); primitive->reserveForNumberOfVertices(numVertices); for (int32_t i = 0; i < numVertices; i++) { primitive->addVertex(&xyz[i * 3]); } primitive->setLineWidth(lineThicknessType, lineThickness); primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); GraphicsEngineDataOpenGL::draw(primitive.get()); } /** * Draw line strip similar to OpenGL's GL_LINE_STRIP * and use Bevel Joins at connected vertices * * @param xyz * Coordinates of the line end points. * @param rgba * Color for drawing. * @param lineThicknessType * Type of line thickness. * @param lineThickness * Thickness of the line. */ void GraphicsShape::drawLineStripBevelJoinByteColor(const std::vector& xyz, const uint8_t rgba[4], const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness) { std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_BEVEL_JOIN, rgba)); const int32_t numVertices = static_cast(xyz.size() / 3); primitive->reserveForNumberOfVertices(numVertices); for (int32_t i = 0; i < numVertices; i++) { primitive->addVertex(&xyz[i * 3]); } primitive->setLineWidth(lineThicknessType, lineThickness); primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); GraphicsEngineDataOpenGL::draw(primitive.get()); } /** * Draw line strip similar to OpenGL's GL_LINE_STRIP * and use Bevel Joins at connected vertices * * @param xyz * Coordinates of the line end points. * @param rgba * Color for drawing. * @param lineThicknessType * Type of line thickness. * @param lineThickness * Thickness of the line. */ void GraphicsShape::drawLineStripMiterJoinByteColor(const std::vector& xyz, const uint8_t rgba[4], const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness) { std::unique_ptr primitive(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::POLYGONAL_LINE_STRIP_MITER_JOIN, rgba)); const int32_t numVertices = static_cast(xyz.size() / 3); primitive->reserveForNumberOfVertices(numVertices); for (int32_t i = 0; i < numVertices; i++) { primitive->addVertex(&xyz[i * 3]); } primitive->setLineWidth(lineThicknessType, lineThickness); primitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_FEW_TIMES); GraphicsEngineDataOpenGL::draw(primitive.get()); } /** * Draw one sphere at the given XYZ coordinate. * NOTE: if you have multiple spheres to draw * with the same color and diameter the method * "drawSpheresByteColor() is much more efficient. * * @param xyz * XYZ-coordinate of sphere * @param rgba * Color for drawing. * @param diameter * Diameter of the sphere. */ void GraphicsShape::drawSphereByteColor(const float xyz[3], const uint8_t rgba[4], const float diameter) { drawSpheresByteColor(xyz, 1, rgba, diameter); // const int32_t numLatLonDivisions = 10; // // GraphicsPrimitive* spherePrimitive = NULL; // for (const auto iter : s_byteSpherePrimitives) { // const auto& key = iter.first; // if ((key == numLatLonDivisions)) { // spherePrimitive = iter.second; // CaretAssert(spherePrimitive); // break; // } // } // // if (spherePrimitive == NULL) { // const bool useStripsFlag = true; // if (useStripsFlag) { // spherePrimitive = createSpherePrimitiveTriangleStrips(numLatLonDivisions); // } // else { // spherePrimitive = createSpherePrimitiveTriangles(numLatLonDivisions); // } // /* colors may change but not coordinates/normals */ // spherePrimitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); // spherePrimitive->setUsageTypeColors(GraphicsPrimitive::UsageType::MODIFIED_MANY_DRAWN_MANY_TIMES); // s_byteSpherePrimitives.insert(std::make_pair(numLatLonDivisions, // spherePrimitive)); // } // // CaretAssert(spherePrimitive); // // spherePrimitive->replaceAllVertexSolidByteRGBA(rgba); // // glPushMatrix(); // glTranslatef(xyz[0], xyz[1], xyz[2]); // glScalef(diameter, diameter, diameter); // GraphicsEngineDataOpenGL::draw(spherePrimitive); // glPopMatrix(); } /** * Draw a spheres at the given XYZ coordinates * * @param xyz * XYZ-coordinates of spheres (must be allocated for * "numberOfSpheres" * @param numberOfSpheres * Number of spheres * @param rgba * Color for drawing. * @param diameter * Diameter of the spheres. */ void GraphicsShape::drawSpheresByteColor(const float xyz[], const int32_t numberOfSpheres, const uint8_t rgba[4], const float diameter) { const int32_t numLatLonDivisions = 10; GraphicsPrimitive* spherePrimitive = NULL; for (const auto iter : s_byteSpherePrimitives) { const auto& key = iter.first; if ((key == numLatLonDivisions)) { spherePrimitive = iter.second; CaretAssert(spherePrimitive); break; } } if (spherePrimitive == NULL) { const bool useStripsFlag = true; if (useStripsFlag) { spherePrimitive = createSpherePrimitiveTriangleStrips(numLatLonDivisions); } else { spherePrimitive = createSpherePrimitiveTriangles(numLatLonDivisions); } /* colors may change but not coordinates/normals */ spherePrimitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); spherePrimitive->setUsageTypeColors(GraphicsPrimitive::UsageType::MODIFIED_MANY_DRAWN_MANY_TIMES); s_byteSpherePrimitives.insert(std::make_pair(numLatLonDivisions, spherePrimitive)); } CaretAssert(spherePrimitive); spherePrimitive->replaceAllVertexSolidByteRGBA(rgba); for (int32_t i = 0; i < numberOfSpheres; i++) { const int32_t i3 = i * 3; glPushMatrix(); glTranslatef(xyz[i3], xyz[i3+1], xyz[i3+2]); glScalef(diameter, diameter, diameter); GraphicsEngineDataOpenGL::draw(spherePrimitive); glPopMatrix(); } } /** * Draw a filled circle at the given XYZ coordinate * * @param xyz * XYZ-coordinate of circle * @param rgba * Color for drawing. * @param diameter * Diameter of the circle. */ void GraphicsShape::drawCircleFilled(const float xyz[3], const uint8_t rgba[4], const float diameter) { const int32_t numberOfDivisions = 20; GraphicsPrimitive* circlePrimitive = NULL; for (const auto keyPrim : s_byteCirclePrimitives) { if (keyPrim.first == numberOfDivisions) { circlePrimitive = keyPrim.second; break; } } if (circlePrimitive == NULL) { const float radius = 0.5f; circlePrimitive = createCirclePrimitive(numberOfDivisions, radius); circlePrimitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); circlePrimitive->setUsageTypeColors(GraphicsPrimitive::UsageType::MODIFIED_MANY_DRAWN_MANY_TIMES); s_byteCirclePrimitives.insert(std::make_pair(numberOfDivisions, circlePrimitive)); } CaretAssert(circlePrimitive); circlePrimitive->replaceAllVertexSolidByteRGBA(rgba); glPushMatrix(); if (xyz != NULL) { glTranslatef(xyz[0], xyz[1], xyz[2]); } glScalef(diameter, diameter, 1.0f); GraphicsEngineDataOpenGL::draw(circlePrimitive); glPopMatrix(); } /** * Draw a squares at the given XYZ coordinates * * @param xyz * XYZ-coordinates of squares * @param numberOfSquares * Number of squares to draw * @param rgba * Color for drawing. * @param diameter * Diameter of the squares. */ void GraphicsShape::drawSquares(const float xyz[], const int32_t numberOfSquares, const uint8_t rgba[4], const float diameter) { if (numberOfSquares <= 0) { return; } CaretAssert(xyz); if ( ! s_byteSquarePrimitive) { s_byteSquarePrimitive.reset(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES, rgba)); /* * The square is made up of four triangles * with two triangles for the 'front' and * two triangles for the 'back' so that it is * never culled. */ const float radius = 0.5f; /* counter clockwise triangle */ s_byteSquarePrimitive->addVertex(-radius, -radius); s_byteSquarePrimitive->addVertex( radius, -radius); s_byteSquarePrimitive->addVertex( radius, radius); /* counter clockwise triangle */ s_byteSquarePrimitive->addVertex(-radius, -radius); s_byteSquarePrimitive->addVertex( radius, radius); s_byteSquarePrimitive->addVertex(-radius, radius); /* clockwise triangle */ s_byteSquarePrimitive->addVertex(-radius, -radius); s_byteSquarePrimitive->addVertex(-radius, radius); s_byteSquarePrimitive->addVertex( radius, radius); /* clockwise triangle */ s_byteSquarePrimitive->addVertex(-radius, -radius); s_byteSquarePrimitive->addVertex( radius, radius); s_byteSquarePrimitive->addVertex( radius, -radius); } CaretAssert(s_byteSquarePrimitive.get()); s_byteSquarePrimitive->replaceAllVertexSolidByteRGBA(rgba); for (int32_t i = 0; i < numberOfSquares; i++) { const int32_t i3 = i * 3; glPushMatrix(); glTranslatef(xyz[i3], xyz[i3+1], xyz[i3+2]); updateModelMatrixToFaceViewer(); glScalef(diameter, diameter, 1.0f); GraphicsEngineDataOpenGL::draw(s_byteSquarePrimitive.get()); glPopMatrix(); } } /** * Draw a square at the given XYZ coordinate * * @param xyz * XYZ-coordinate of square * @param rgba * Color for drawing. * @param diameter * Diameter of the square. */ void GraphicsShape::drawSquare(const float xyz[3], const uint8_t rgba[4], const float diameter) { if ( ! s_byteSquarePrimitive) { s_byteSquarePrimitive.reset(GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES, rgba)); /* * The square is made up of four triangles * with two triangles for the 'front' and * two triangles for the 'back' so that it is * never culled. */ const float radius = 0.5f; /* counter clockwise triangle */ s_byteSquarePrimitive->addVertex(-radius, -radius); s_byteSquarePrimitive->addVertex( radius, -radius); s_byteSquarePrimitive->addVertex( radius, radius); /* counter clockwise triangle */ s_byteSquarePrimitive->addVertex(-radius, -radius); s_byteSquarePrimitive->addVertex( radius, radius); s_byteSquarePrimitive->addVertex(-radius, radius); /* clockwise triangle */ s_byteSquarePrimitive->addVertex(-radius, -radius); s_byteSquarePrimitive->addVertex(-radius, radius); s_byteSquarePrimitive->addVertex( radius, radius); /* clockwise triangle */ s_byteSquarePrimitive->addVertex(-radius, -radius); s_byteSquarePrimitive->addVertex( radius, radius); s_byteSquarePrimitive->addVertex( radius, -radius); } CaretAssert(s_byteSquarePrimitive.get()); s_byteSquarePrimitive->replaceAllVertexSolidByteRGBA(rgba); glPushMatrix(); if (xyz != NULL) { glTranslatef(xyz[0], xyz[1], xyz[2]); updateModelMatrixToFaceViewer(); glScalef(diameter, diameter, 1.0f); } GraphicsEngineDataOpenGL::draw(s_byteSquarePrimitive.get()); glPopMatrix(); } /** * Draw a ring at the given XYZ coordinate * * @param xyz * XYZ-coordinate of ring * @param rgba * Color for drawing. * @param innerRadius * Inner adius of the ring. * @param outerRadius * Outer adius of the ring. */ void GraphicsShape::drawRing(const float xyz[3], const uint8_t rgba[4], const double innerRadius, const double outerRadius) { const int32_t numberOfDivisions = 20; GraphicsPrimitive* ringPrimitive = NULL; for (const auto keyPrim : s_byteRingPrimitives) { if (keyPrim.first.matches(numberOfDivisions, innerRadius, outerRadius)) { ringPrimitive = keyPrim.second; break; } } if (ringPrimitive == NULL) { RingKey ringKey(numberOfDivisions, innerRadius, outerRadius); ringPrimitive = createRingPrimitive(ringKey); ringPrimitive->setUsageTypeAll(GraphicsPrimitive::UsageType::MODIFIED_ONCE_DRAWN_MANY_TIMES); ringPrimitive->setUsageTypeColors(GraphicsPrimitive::UsageType::MODIFIED_MANY_DRAWN_MANY_TIMES); s_byteRingPrimitives.insert(std::make_pair(RingKey(numberOfDivisions, innerRadius, outerRadius), ringPrimitive)); } CaretAssert(ringPrimitive); ringPrimitive->replaceAllVertexSolidByteRGBA(rgba); glPushMatrix(); if (xyz != NULL) { glTranslatef(xyz[0], xyz[1], xyz[2]); } GraphicsEngineDataOpenGL::draw(ringPrimitive); glPopMatrix(); } /** * Create the primitive for a circle. * * @param numberOfDivisions * Number of divisions * @param radius * Radius of the circle. */ GraphicsPrimitive* GraphicsShape::createCirclePrimitive(const int32_t numberOfDivisions, const double radius) { /* * Setup step size based upon number of points around circle */ // const int32_t numberOfPoints = 8; const float step = (2.0 * M_PI) / numberOfDivisions; const uint8_t rgba[] { 255, 255, 255, 255 }; GraphicsPrimitiveV3f* primitive = GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_FAN, rgba); primitive->reserveForNumberOfVertices(numberOfDivisions + 2); /* * Generate points around ring */ const float z = 0.0; primitive->addVertex(0.0f, 0.0f, z); for (int32_t i = 0; i <= numberOfDivisions; i++) { const float t = step * i; const float x = radius * std::cos(t); const float y = radius * std::sin(t); primitive->addVertex(x, y, z); } return primitive; } /** * Create the vertices for a ring. * * @param numberOfDivisions * Number of divisions * @param innerRadius * Inner radius of the ring. * @param outerRadius * Outer radius of the ring. * @return * Primitive containing vertices of ring. */ GraphicsPrimitive* GraphicsShape::createRingPrimitive(const RingKey& ringKey) { /* * Setup step size based upon number of points around circle */ const float step = (2.0 * M_PI) / ringKey.m_numberOfDivisions; const uint8_t rgba[] { 255, 255, 255, 255 }; GraphicsPrimitiveV3f* primitive = GraphicsPrimitive::newPrimitiveV3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP, rgba); primitive->reserveForNumberOfVertices((ringKey.m_numberOfDivisions + 1) * 2); /* * Generate points around ring */ const float z = 0.0; for (int32_t i = 0; i <= ringKey.m_numberOfDivisions; i++) { const float t = step * i; const float xin = ringKey.m_innerRadius * std::cos(t); const float yin = ringKey.m_innerRadius * std::sin(t); const float xout = ringKey.m_outerRadius * std::cos(t); const float yout = ringKey.m_outerRadius * std::sin(t); primitive->addVertex(xin, yin, z); primitive->addVertex(xout, yout, z); } return primitive; } /** * Create the vertices for the ellipse * * @param majorAxis * Diameter of the major axis. * @param minorAxis * Diameter of the minor axis. * @param elliposeXYZOut * Contains vertices upon exit. */ void GraphicsShape::createEllipseVertices(const double majorAxis, const double minorAxis, std::vector& ellipseXYZOut) { const float a = majorAxis / 2.0f; const float b = minorAxis / 2.0f; const float z = 0.0f; const int32_t numSlices = 10; const float totalPoints = numSlices * 4; ellipseXYZOut.resize(totalPoints * 3); /* * Computation of the points on the ellipse is performed * using the parametric equation (a * cos(t), b*sin(t)). * Using this parametric equation provides an equal length * between points on the ellipse. * The symmetry of the four quadrants is used to that * we only need to compute points in the first quadrant. */ const float angleStep = ((M_PI / 2.0f) / numSlices); for (int32_t i = 0; i <= numSlices; i++) { const float x = a * std::cos(i * angleStep); const float y = b * std::sin(i * angleStep); const int32_t quadOneIndex = i * 3; CaretAssertVectorIndex(ellipseXYZOut, quadOneIndex + 2); ellipseXYZOut[quadOneIndex] = x; ellipseXYZOut[quadOneIndex + 1] = y; ellipseXYZOut[quadOneIndex + 2] = z; if (i < numSlices) { const int32_t quadTwoIndex = ((numSlices * 2) - i) * 3; CaretAssertVectorIndex(ellipseXYZOut, quadTwoIndex + 2); ellipseXYZOut[quadTwoIndex] = -x; ellipseXYZOut[quadTwoIndex + 1] = y; ellipseXYZOut[quadTwoIndex + 2] = z; } if (i > 0) { const int32_t quadThreeIndex = ((numSlices * 2) + i) * 3; CaretAssertVectorIndex(ellipseXYZOut, quadThreeIndex + 2); ellipseXYZOut[quadThreeIndex] = -x; ellipseXYZOut[quadThreeIndex + 1] = -y; ellipseXYZOut[quadThreeIndex + 2] = z; } if ((i > 0) && (i < numSlices)) { const int32_t quadFourIndex = ((numSlices * 4) - i) * 3; CaretAssertVectorIndex(ellipseXYZOut, quadFourIndex + 2); ellipseXYZOut[quadFourIndex] = x; ellipseXYZOut[quadFourIndex + 1] = -y; ellipseXYZOut[quadFourIndex + 2] = z; } } } /** * Create an XYZ coordinate on a sphere. * * @param radius * Radius of the sphere * @param latDegrees * Latitude on sphere in degrees * @param lonDegrees * Longitude on sphere in degrees * @param latIndex * Index of the latitude sections * @param numLat * Number of latitude sections * @param xyzOut * Output with XYZ coordinate * @param normalXyzOut * Output with Normal vector */ void GraphicsShape::createSphereXYZ(const float radius, const float latDegrees, const float lonDegrees, const int32_t latIndex, const int32_t numLat, float xyzOut[3], float normalXyzOut[3]) { constexpr float degToRad = M_PI / 180.0f; const float lonRad = lonDegrees * degToRad; const float latRad = latDegrees * degToRad; const float z = radius * std::sin(latRad); xyzOut[0] = radius * std::cos(latRad) * std::cos(lonRad); xyzOut[1] = radius * std::cos(latRad) * std::sin(lonRad); xyzOut[2] = z; if (latIndex == 0) { xyzOut[0] = 0.0f; xyzOut[1] = 0.0f; xyzOut[2] = -radius; } else if (latIndex == (numLat - 1)) { xyzOut[0] = 0.0f; xyzOut[1] = 0.0f; xyzOut[2] = radius; } normalXyzOut[0] = xyzOut[0]; normalXyzOut[1] = xyzOut[1]; normalXyzOut[2] = xyzOut[2]; MathFunctions::normalizeVector(normalXyzOut); } /** * Create a sphere with radius of 0.5 and with the given number * of latitude and longitude divisions. * * @param numberOfLatLon * Number of latitude/longitude divisions * @return * Graphics primitive containing the sphere. */ GraphicsPrimitiveV3fN3f* GraphicsShape::createSpherePrimitiveTriangles(const int32_t numberOfLatLon) { if (numberOfLatLon < 3) { CaretAssertMessage(0, "For sphere, must have at least 3 lat/lon divisions"); CaretLogSevere("For sphere, must have at least 3 lat/lon divisions"); return NULL; } bool debugFlag = false; if (debugFlag) { std::cout << std::endl; std::cout << "TRIANGLE START" << std::endl; } const float radius = 0.5f; const int numLat = numberOfLatLon; const int numLon = numberOfLatLon; uint8_t rgba[4] = { 255, 255, 255, 255 }; GraphicsPrimitiveV3fN3f* primitive = GraphicsPrimitive::newPrimitiveV3fN3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLES, rgba); const float dLat = 180.0 / numLat; for (int iLat = 0; iLat < numLat; iLat++) { const float latDeg = -90.0f + (iLat * dLat); const float latDeg2 = -90.0f + ((iLat + 1) * dLat); const float dLon = 360.0f / numLon; for (int iLon = 0; iLon < numLon; iLon++) { const float lonDeg = iLon * dLon; float xyz1[3]; float normal1[3]; createSphereXYZ(radius, latDeg, lonDeg, iLat, numLat, xyz1, normal1); float xyz2[3]; float normal2[3]; createSphereXYZ(radius, latDeg2, lonDeg, iLat + 1, numLat, xyz2, normal2); float xyz3[3]; float normal3[3]; createSphereXYZ(radius, latDeg, (lonDeg + dLon), iLat, numLat, xyz3, normal3); float xyz4[3]; float normal4[3]; createSphereXYZ(radius, latDeg2, (lonDeg + dLon), iLat + 1, numLat, xyz4, normal4); primitive->addVertex(xyz1, normal1); primitive->addVertex(xyz3, normal3); primitive->addVertex(xyz2, normal2); primitive->addVertex(xyz2, normal2); primitive->addVertex(xyz3, normal3); primitive->addVertex(xyz4, normal4); if (debugFlag) { const int32_t indx1 = (primitive->getNumberOfVertices() - 2); const int32_t indx2 = (primitive->getNumberOfVertices() - 1); std::cout << " " << iLat << ", " << iLon << std::endl; std::cout << " " << indx1 << ":" << latDeg << ", " << lonDeg << ", " << AString::fromNumbers(xyz1, 3, ",") << std::endl; std::cout << " " << indx2 << ":" << latDeg2 << ", " << lonDeg << ", " << AString::fromNumbers(xyz2, 3, ",") << std::endl; std::cout << " " << AString::fromNumbers(xyz3, 3, ",") << std::endl; std::cout << " " << AString::fromNumbers(xyz4, 3, ",") << std::endl; } } if (debugFlag) std::cout << std::endl; } return primitive; } /** * Create a sphere with radius of 0.5 and with the given number * of latitude and longitude divisions. * * @param numberOfLatLon * Number of latitude/longitude divisions * @return * Graphics primitive containing the sphere. */ GraphicsPrimitiveV3fN3f* GraphicsShape::createSpherePrimitiveTriangleStrips(const int32_t numberOfLatLon) { if (numberOfLatLon < 3) { CaretAssertMessage(0, "For sphere, must have at least 3 lat/lon divisions"); CaretLogSevere("For sphere, must have at least 3 lat/lon divisions"); return NULL; } bool debugFlag = false; if (debugFlag) { std::cout << std::endl; std::cout << "TRIANGLE START" << std::endl; } const float radius = 0.5f; const int numLat = numberOfLatLon; const int numLon = numberOfLatLon; uint8_t rgba[4] = { 255, 255, 255, 255 }; GraphicsPrimitiveV3fN3f* primitive = GraphicsPrimitive::newPrimitiveV3fN3f(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP, rgba); const float dLat = 180.0 / numLat; for (int iLat = 0; iLat < numLat; iLat++) { const float latDeg = -90.0f + (iLat * dLat); const float latDeg2 = -90.0f + ((iLat + 1) * dLat); const float dLon = 360.0f / numLon; for (int iLon = 0; iLon <= numLon; iLon++) { const float lonDeg = iLon * dLon; float xyz1[3]; float normal1[3]; createSphereXYZ(radius, latDeg, lonDeg, iLat, numLat, xyz1, normal1); float xyz2[3]; float normal2[3]; createSphereXYZ(radius, latDeg2, lonDeg, iLat + 1, numLat, xyz2, normal2); primitive->addVertex(xyz2, normal2); primitive->addVertex(xyz1, normal1); if (debugFlag) { const int32_t indx1 = (primitive->getNumberOfVertices() - 2); const int32_t indx2 = (primitive->getNumberOfVertices() - 1); std::cout << " " << iLat << ", " << iLon << std::endl; std::cout << " " << indx1 << ":" << latDeg << ", " << lonDeg << ", " << AString::fromNumbers(xyz1, 3, ",") << std::endl; std::cout << " " << indx2 << ":" << latDeg2 << ", " << lonDeg << ", " << AString::fromNumbers(xyz2, 3, ",") << std::endl; } } if (iLat < (numLat - 1)) { primitive->addPrimitiveRestart(); } if (debugFlag) std::cout << std::endl; } return primitive; } /** * Update the model matrix to face the viewer by applying a * technique known as "billboarding". Callers need to * push/pop the modelview matrix before/after calling * this method. * * The result is that the X-Y plane faces the user. */ void GraphicsShape::updateModelMatrixToFaceViewer() { /* * Get the translation and rotation from the * current modelview matrix. */ double modelMatrixArray[16]; glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrixArray); Matrix4x4 matrix; matrix.setMatrixFromOpenGL(modelMatrixArray); float txyz[3]; matrix.getTranslation(txyz); double sx, sy, sz; matrix.getScale(sx, sy, sz); /* * Replace modelview matrix with * just translation and scaling. */ glLoadIdentity(); glTranslatef(txyz[0], txyz[1], txyz[2]); glScalef(sx, sy, sz); } /** * Draw an rectangle outline. * The normal vector is computed from three consecutive vertices in the rectangle. * * @param bottomLeft * Bottom left vertex of the rectangle. * @param bottomRight * Bottom right vertex of the rectangle. * @param topRight * Top right vertex of the rectangle. * @param topLeft * Top left vertex of the rectangle. * @param thickness * Thickness of the outline * @param rgba * RGBA color for the outline. * @param verticesInMiddleFlag * If true, the lines are centered around the vertices. Otherwise, * the inner sides of the lines are tangent to the vertices. */ void GraphicsShape::drawOutlineRectanglePrivate(const float bottomLeft[3], const float bottomRight[3], const float topRight[3], const float topLeft[3], const float thicknessIn, const uint8_t rgba[4], bool verticesInMiddleFlag) { const double bl[3] { bottomLeft[0], bottomLeft[1], bottomLeft[2] }; const double br[3] { bottomRight[0], bottomRight[1], bottomRight[2] }; const double tr[3] { topRight[0], topRight[1], topRight[2] }; const double tl[3] { topLeft[0], topLeft[1], topLeft[2] }; drawOutlineRectanglePrivate(bl, br, tr, tl, thicknessIn, rgba, verticesInMiddleFlag); } /** * Draw an rectangle outline. * The normal vector is computed from three consecutive vertices in the rectangle. * * @param bottomLeft * Bottom left vertex of the rectangle. * @param bottomRight * Bottom right vertex of the rectangle. * @param topRight * Top right vertex of the rectangle. * @param topLeft * Top left vertex of the rectangle. * @param thickness * Thickness of the outline * @param rgba * RGBA color for the outline. * @param verticesInMiddleFlag * If true, the lines are centered around the vertices. Otherwise, * the inner sides of the lines are tangent to the vertices. */ void GraphicsShape::drawOutlineRectanglePrivate(const double bottomLeft[3], const double bottomRight[3], const double topRight[3], const double topLeft[3], const double thicknessIn, const uint8_t rgba[4], bool verticesInMiddleFlag) { double bottomLeftInner[3] = { bottomLeft[0], bottomLeft[1], bottomLeft[2] }; double bottomLeftOuter[3] = { bottomLeft[0], bottomLeft[1], bottomLeft[2] }; double bottomRightInner[3] = { bottomRight[0], bottomRight[1], bottomRight[2] }; double bottomRightOuter[3] = { bottomRight[0], bottomRight[1], bottomRight[2] }; double topRightInner[3] = { topRight[0], topRight[1], topRight[2] }; double topRightOuter[3] = { topRight[0], topRight[1], topRight[2] }; double topLeftInner[3] = { topLeft[0], topLeft[1], topLeft[2] }; double topLeftOuter[3] = { topLeft[0], topLeft[1], topLeft[2] }; /* * Limit thickness of the outline to half of width or height * when points in middle */ const double boxHeight = MathFunctions::distance3D(bottomLeft, topLeft); const double boxWidth = MathFunctions::distance3D(bottomLeft, bottomRight); double thickness = thicknessIn; if (verticesInMiddleFlag) { thickness /= 2.0; thickness = std::min(thickness, boxWidth / 2.0); thickness = std::min(thickness, boxHeight / 2.0); } /* * Horizontal contraction/expansion of vertices */ double horizVector[3]; MathFunctions::subtractVectors(bottomRight, bottomLeft, horizVector); MathFunctions::normalizeVector(horizVector); horizVector[0] *= thickness; horizVector[1] *= thickness; horizVector[2] *= thickness; MathFunctions::subtractOffsetFromVector(bottomLeftOuter, horizVector); MathFunctions::subtractOffsetFromVector(topLeftOuter, horizVector); MathFunctions::addOffsetToVector(bottomRightOuter, horizVector); MathFunctions::addOffsetToVector(topRightOuter, horizVector); if (verticesInMiddleFlag) { MathFunctions::subtractOffsetFromVector(bottomRightInner, horizVector); MathFunctions::subtractOffsetFromVector(topRightInner, horizVector); MathFunctions::addOffsetToVector(bottomLeftInner, horizVector); MathFunctions::addOffsetToVector(topLeftInner, horizVector); } /* * Vertical contraction/expansion of vertices */ double vertVector[3]; MathFunctions::subtractVectors(topLeft, bottomLeft, vertVector); MathFunctions::normalizeVector(vertVector); vertVector[0] *= thickness; vertVector[1] *= thickness; vertVector[2] *= thickness; MathFunctions::subtractOffsetFromVector(bottomRightOuter, vertVector); MathFunctions::subtractOffsetFromVector(bottomLeftOuter, vertVector); MathFunctions::addOffsetToVector(topLeftOuter, vertVector); MathFunctions::addOffsetToVector(topRightOuter, vertVector); if (verticesInMiddleFlag) { MathFunctions::subtractOffsetFromVector(topLeftInner, vertVector); MathFunctions::subtractOffsetFromVector(topRightInner, vertVector); MathFunctions::addOffsetToVector(bottomRightInner, vertVector); MathFunctions::addOffsetToVector(bottomLeftInner, vertVector); } /* * Use three consecutive vertices to calculate normal vector */ double normalVector[3]; MathFunctions::normalVector(bottomRight, topRight, topLeft, normalVector); /* * Draw the outline as triangles using a triangle strip */ GraphicsPrimitiveV3fN3f primitive(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP, rgba); primitive.addVertex(bottomRightInner, normalVector); primitive.addVertex(bottomRightOuter, normalVector); primitive.addVertex(topRightInner, normalVector); primitive.addVertex(topRightOuter, normalVector); primitive.addVertex(topLeftInner, normalVector); primitive.addVertex(topLeftOuter, normalVector); primitive.addVertex(bottomLeftInner, normalVector); primitive.addVertex(bottomLeftOuter, normalVector); primitive.addVertex(bottomRightInner, normalVector); primitive.addVertex(bottomRightOuter, normalVector); GraphicsEngineDataOpenGL::draw(&primitive); } /** * Draw an rectangle outline. * The given points are in the middle of outline. * The normal vector is computed from three consecutive vertices in the rectangle. * * @param bottomLeft * Bottom left vertex of the rectangle. * @param bottomRight * Bottom right vertex of the rectangle. * @param topRight * Top right vertex of the rectangle. * @param topLeft * Top left vertex of the rectangle. * @param thickness * Thickness of the outline * @param rgba * RGBA color for the outline. */ void GraphicsShape::drawOutlineRectangleVerticesInMiddle(const double bottomLeft[3], const double bottomRight[3], const double topRight[3], const double topLeft[3], const double thickness, const uint8_t rgba[4]) { drawOutlineRectanglePrivate(bottomLeft, bottomRight, topRight, topLeft, thickness, rgba, true); } /** * Draw an rectangle outline. * The given points are in the middle of outline. * The normal vector is computed from three consecutive vertices in the rectangle. * * @param bottomLeft * Bottom left vertex of the rectangle. * @param bottomRight * Bottom right vertex of the rectangle. * @param topRight * Top right vertex of the rectangle. * @param topLeft * Top left vertex of the rectangle. * @param thickness * Thickness of the outline * @param rgba * RGBA color for the outline. */ void GraphicsShape::drawOutlineRectangleVerticesInMiddle(const float bottomLeft[3], const float bottomRight[3], const float topRight[3], const float topLeft[3], const float thickness, const uint8_t rgba[4]) { drawOutlineRectanglePrivate(bottomLeft, bottomRight, topRight, topLeft, thickness, rgba, true); } /** * Draw an rectangle outline. * The given points are at the inside of outline. * The normal vector is computed from three consecutive vertices in the rectangle. * * @param bottomLeft * Bottom left vertex of the rectangle. * @param bottomRight * Bottom right vertex of the rectangle. * @param topRight * Top right vertex of the rectangle. * @param topLeft * Top left vertex of the rectangle. * @param thickness * Thickness of the outline * @param rgba * RGBA color for the outline. */ void GraphicsShape::drawOutlineRectangleVerticesAtInside(const float bottomLeft[3], const float bottomRight[3], const float topRight[3], const float topLeft[3], const float thickness, const uint8_t rgba[4]) { drawOutlineRectanglePrivate(bottomLeft, bottomRight, topRight, topLeft, thickness, rgba, false); } /** * Draw an rectangle outline. * The given points are at the inside of outline. * The normal vector is computed from three consecutive vertices in the rectangle. * * @param bottomLeft * Bottom left vertex of the rectangle. * @param bottomRight * Bottom right vertex of the rectangle. * @param topRight * Top right vertex of the rectangle. * @param topLeft * Top left vertex of the rectangle. * @param thickness * Thickness of the outline * @param rgba * RGBA color for the outline. */ void GraphicsShape::drawOutlineRectangleVerticesAtInside(const double bottomLeft[3], const double bottomRight[3], const double topRight[3], const double topLeft[3], const double thickness, const uint8_t rgba[4]) { drawOutlineRectanglePrivate(bottomLeft, bottomRight, topRight, topLeft, thickness, rgba, false); } /** * Get a description of this object's content. * @return String describing this object's content. */ AString GraphicsShape::toString() const { return "GraphicsShape"; } connectome-workbench-1.4.2/src/Graphics/GraphicsShape.h000066400000000000000000000311271360521144700230600ustar00rootroot00000000000000#ifndef __GRAPHICS_SHAPE_H__ #define __GRAPHICS_SHAPE_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretObject.h" #include "GraphicsPrimitive.h" namespace caret { class GraphicsPrimitiveV3f; class GraphicsPrimitiveV3fN3f; class GraphicsShape : public CaretObject { public: virtual ~GraphicsShape(); static void drawBoxOutlineByteColor(const float v1[3], const float v2[3], const float v3[3], const float v4[3], const uint8_t rgba[4], const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness); static void drawBoxOutlineFloatColor(const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float rgba[4], const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness); static void drawBoxFilledByteColor(const float v1[3], const float v2[3], const float v3[3], const float v4[3], const uint8_t rgba[4]); static void drawBoxFilledFloatColor(const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float rgba[4]); static void drawEllipseOutlineByteColor(const double majorAxis, const double minorAxis, const uint8_t rgba[4], const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness); static void drawEllipseFilledByteColor(const double majorAxis, const double minorAxis, const uint8_t rgba[4]); static void drawEllipseOutlineModelSpaceByteColor(const double majorAxis, const double minorAxis, const uint8_t rgba[4], const double lineThickness); static void drawLinesByteColor(const std::vector& xyz, const uint8_t rgba[4], const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness); static void drawLineStripBevelJoinByteColor(const std::vector& xyz, const uint8_t rgba[4], const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness); static void drawLineStripMiterJoinByteColor(const std::vector& xyz, const uint8_t rgba[4], const GraphicsPrimitive::LineWidthType lineThicknessType, const double lineThickness); static void drawSphereByteColor(const float xyz[3], const uint8_t rgba[4], const float diameter); static void drawSpheresByteColor(const float xyz[], const int32_t numberOfSpheres, const uint8_t rgba[4], const float diameter); static void drawCircleFilled(const float xyz[3], const uint8_t rgba[4], const float diameter); static void drawSquare(const float xyz[3], const uint8_t rgba[4], const float diameter); static void drawSquares(const float xyz[], const int32_t numberOfSquares, const uint8_t rgba[4], const float diameter); static void drawRing(const float xyz[3], const uint8_t rgba[4], const double innerRadius, const double outerRadius); static void deleteAllPrimitives(); static void drawOutlineRectangleVerticesInMiddle(const double bottomLeft[3], const double bottomRight[3], const double topRight[3], const double topLeft[3], const double thickness, const uint8_t rgba[4]); static void drawOutlineRectangleVerticesInMiddle(const float bottomLeft[3], const float bottomRight[3], const float topRight[3], const float topLeft[3], const float thickness, const uint8_t rgba[4]); static void drawOutlineRectangleVerticesAtInside(const double bottomLeft[3], const double bottomRight[3], const double topRight[3], const double topLeft[3], const double thickness, const uint8_t rgba[4]); static void drawOutlineRectangleVerticesAtInside(const float bottomLeft[3], const float bottomRight[3], const float topRight[3], const float topLeft[3], const float thickness, const uint8_t rgba[4]); // ADD_NEW_METHODS_HERE virtual AString toString() const; private: class RingKey { public: RingKey(const int32_t numberOfDivisions, const float innerRadius, const float outerRadius) : m_numberOfDivisions(numberOfDivisions), m_innerRadius(innerRadius), m_outerRadius(outerRadius) { } bool matches(const int32_t numberOfDivisions, const float innerRadius, const float outerRadius) const { if ((m_numberOfDivisions == numberOfDivisions) && (m_innerRadius == innerRadius) && (m_outerRadius == outerRadius)) { return true; } return false; } bool operator<(const RingKey& rhs) const { if (m_numberOfDivisions < rhs.m_numberOfDivisions) { return true; } if (m_innerRadius < rhs.m_innerRadius) { return true; } if (m_outerRadius < rhs.m_outerRadius) { return true; } return false; } int32_t m_numberOfDivisions; float m_innerRadius; float m_outerRadius; }; GraphicsShape(); GraphicsShape(const GraphicsShape&); GraphicsShape& operator=(const GraphicsShape&); static void updateModelMatrixToFaceViewer(); static GraphicsPrimitive* createCirclePrimitive(const int32_t numberOfDivisions, const double radius); static GraphicsPrimitive* createRingPrimitive(const RingKey& ringKey); static void createEllipseVertices(const double majorAxis, const double minorAxis, std::vector& ellipseXYZOut); static GraphicsPrimitiveV3fN3f* createSpherePrimitiveTriangles(const int32_t numberOfLatLon); static GraphicsPrimitiveV3fN3f* createSpherePrimitiveTriangleStrips(const int32_t numberOfLatLon); static void createSphereXYZ(const float radius, const float latDegrees, const float lonDegrees, const int32_t latIndex, const int32_t numLat, float xyzOut[3], float normalXyzOut[3]); static void drawOutlineRectanglePrivate(const double bottomLeft[3], const double bottomRight[3], const double topRight[3], const double topLeft[3], const double thicknessIn, const uint8_t rgba[4], bool verticesInMiddleFlag); static void drawOutlineRectanglePrivate(const float bottomLeft[3], const float bottomRight[3], const float topRight[3], const float topLeft[3], const float thicknessIn, const uint8_t rgba[4], bool verticesInMiddleFlag); static std::unique_ptr s_byteSquarePrimitive; static std::map s_byteSpherePrimitives; static std::map s_byteCirclePrimitives; static std::map s_byteRingPrimitives; // ADD_NEW_MEMBERS_HERE }; #ifdef __GRAPHICS_SHAPE_DECLARE__ std::map GraphicsShape::s_byteSpherePrimitives; std::map GraphicsShape::s_byteCirclePrimitives; std::map GraphicsShape::s_byteRingPrimitives; std::unique_ptr GraphicsShape::s_byteSquarePrimitive; #endif // __GRAPHICS_SHAPE_DECLARE__ } // namespace #endif //__GRAPHICS_SHAPE_H__ connectome-workbench-1.4.2/src/Graphics/GraphicsUtilitiesOpenGL.cxx000066400000000000000000000221621360521144700254120ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GRAPHICS_UTILITIES_OPEN_G_L_DECLARE__ #include "GraphicsUtilitiesOpenGL.h" #undef __GRAPHICS_UTILITIES_OPEN_G_L_DECLARE__ #include #include #include "CaretAssert.h" #include "CaretOpenGLInclude.h" #include "GraphicsOpenGLError.h" #include "EventManager.h" #include "EventOpenGLObjectToWindowTransform.h" #include "MathFunctions.h" using namespace caret; /** * \class caret::GraphicsUtilitiesOpenGL * \brief Utility functions for use with OpenGL. * \ingroup Graphics */ /** * Constructor. */ GraphicsUtilitiesOpenGL::GraphicsUtilitiesOpenGL() : CaretObject() { } /** * Destructor. */ GraphicsUtilitiesOpenGL::~GraphicsUtilitiesOpenGL() { } /** * Converts pixels to a percentage of the viewport height. * * @param pixels * The value in pixels. * @return The percentage of height [0.0, 100.0] for the given number of millimeters. */ float GraphicsUtilitiesOpenGL::convertPixelsToPercentageOfViewportHeight(const float pixels) { float percentageOfViewportHeight = 1.0f; EventOpenGLObjectToWindowTransform xform(EventOpenGLObjectToWindowTransform::SpaceType::VOLUME_SLICE_MODEL); EventManager::get()->sendEvent(xform.getPointer()); if (xform.isValid()) { const std::array viewport = xform.getViewport(); const float rangePixels = viewport[3]; if ((rangePixels > 0) && (pixels > 0)) { percentageOfViewportHeight = (pixels / rangePixels) * 100.0f; } } return percentageOfViewportHeight ; } /** * Converts percentage of viewport height to millimeters. * The current transformations must be for drawing in millimeters. * * @param percentOfViewportHeight * The value in percentage of viewport height. * @return * Millimeters */ float GraphicsUtilitiesOpenGL::convertPercentageOfViewportHeightToMillimeters(const float percentOfViewportHeight) { float millimeters = -1.0f; EventOpenGLObjectToWindowTransform xform(EventOpenGLObjectToWindowTransform::SpaceType::VOLUME_SLICE_MODEL); EventManager::get()->sendEvent(xform.getPointer()); if (xform.isValid()) { const std::array viewport = xform.getViewport(); const float windowZ = 0.0f; float bottomWindowXYZ[3] = { (float)viewport[0], (float)viewport[1], (float)windowZ }; float topWindowXYZ[3] = { (float)viewport[0], (float)(viewport[1] + viewport[3]), (float)windowZ }; float bottomModelXYZ[3]; float topModelXYZ[3]; xform.inverseTransformPoint(bottomWindowXYZ, bottomModelXYZ); xform.inverseTransformPoint(topWindowXYZ, topModelXYZ); const float rangeMillimeters = MathFunctions::distance3D(bottomModelXYZ, topModelXYZ); const float rangePixels = viewport[3]; if ((rangePixels > 0) && (rangeMillimeters > 0)) { millimeters = (percentOfViewportHeight / 100.0) * rangeMillimeters; } } return millimeters ; } /** * Converts millimeters to a percentage of the viewport height. * The current transformations must be for drawing in millimeters. * * @param millimeters * The value in millimeters. * @return The percentage of height [0.0, 100.0] for the given number of millimeters. */ float GraphicsUtilitiesOpenGL::convertMillimetersToPercentageOfViewportHeight(const float millimeters) { float percentageOfViewportHeight = -1.0f; EventOpenGLObjectToWindowTransform xform(EventOpenGLObjectToWindowTransform::SpaceType::VOLUME_SLICE_MODEL); EventManager::get()->sendEvent(xform.getPointer()); if (xform.isValid()) { const std::array viewport = xform.getViewport(); const float windowZ = 0.0f; float bottomWindowXYZ[3] = { (float)viewport[0], (float)viewport[1], (float)windowZ }; float topWindowXYZ[3] = { (float)viewport[0], (float)(viewport[1] + viewport[3]), (float)windowZ }; float bottomModelXYZ[3]; float topModelXYZ[3]; xform.inverseTransformPoint(bottomWindowXYZ, bottomModelXYZ); xform.inverseTransformPoint(topWindowXYZ, topModelXYZ); const float rangeMillimeters = MathFunctions::distance3D(bottomModelXYZ, topModelXYZ); const float rangePixels = viewport[3]; if ((rangePixels > 0) && (rangeMillimeters > 0)) { percentageOfViewportHeight = (millimeters / rangeMillimeters) * 100.0f; } } return percentageOfViewportHeight ; } /** * Convert pixels to millimeters. * The current transformations must be for drawing in millimeters. * * @param pixels * The pixels size * @return * Millimeters value. */ float GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(const float pixels) { float mm = 1.0f; EventOpenGLObjectToWindowTransform xform(EventOpenGLObjectToWindowTransform::SpaceType::VOLUME_SLICE_MODEL); EventManager::get()->sendEvent(xform.getPointer()); if (xform.isValid()) { const std::array viewport = xform.getViewport(); const float windowZ = 0.0f; float bottomWindowXYZ[3] = { (float)viewport[0], (float)viewport[1], (float)windowZ }; float topWindowXYZ[3] = { (float)viewport[0], (float)(viewport[1] + viewport[3]), (float)windowZ }; float bottomModelXYZ[3]; float topModelXYZ[3]; xform.inverseTransformPoint(bottomWindowXYZ, bottomModelXYZ); xform.inverseTransformPoint(topWindowXYZ, topModelXYZ); const float rangeMillimeters = MathFunctions::distance3D(bottomModelXYZ, topModelXYZ); const float rangePixels = viewport[3]; if ((rangePixels > 0) && (rangeMillimeters > 0)) { const float ratio = rangeMillimeters / rangePixels; mm = pixels * ratio; } } return mm; } /** * Convert millimeters to pixels. * The current transformations must be for drawing in millimeters. * * @param millimeters * The millimeters size * @return * Pixels value. */ float GraphicsUtilitiesOpenGL::convertMillimetersToPixels(const float millimeters) { float pixels = 1.0f; EventOpenGLObjectToWindowTransform xform(EventOpenGLObjectToWindowTransform::SpaceType::VOLUME_SLICE_MODEL); EventManager::get()->sendEvent(xform.getPointer()); if (xform.isValid()) { const std::array viewport = xform.getViewport(); const float windowZ = 0.0f; float bottomWindowXYZ[3] = { (float)viewport[0], (float)viewport[1], (float)windowZ }; float topWindowXYZ[3] = { (float)viewport[0], (float)(viewport[1] + viewport[3]), (float)windowZ }; float bottomModelXYZ[3]; float topModelXYZ[3]; xform.inverseTransformPoint(bottomWindowXYZ, bottomModelXYZ); xform.inverseTransformPoint(topWindowXYZ, topModelXYZ); const float rangeMillimeters = MathFunctions::distance3D(bottomModelXYZ, topModelXYZ); const float rangePixels = viewport[3]; if ((rangePixels > 0) && (rangeMillimeters > 0)) { const float ratio = rangePixels / rangeMillimeters; pixels = millimeters * ratio; } } return pixels; } /** * Reset and ignore any OpenGL errors. */ void GraphicsUtilitiesOpenGL::resetOpenGLError() { GLenum errorCode = glGetError(); while (errorCode != GL_NO_ERROR) { errorCode = glGetError(); } } /** * @return Pointer to OpenGL Error Information. * If the pointer is not valid, there is no error. * * @param message * Optional message added to the OpenGL error */ std::unique_ptr GraphicsUtilitiesOpenGL::getOpenGLError(const AString& message) { std::unique_ptr errorInfo; GLenum errorCode = glGetError(); while (errorCode != GL_NO_ERROR) { if ( ! errorInfo) { errorInfo.reset(new GraphicsOpenGLError(message)); } errorInfo->addError(errorCode); errorCode = glGetError(); } return errorInfo; } connectome-workbench-1.4.2/src/Graphics/GraphicsUtilitiesOpenGL.h000066400000000000000000000042431360521144700250370ustar00rootroot00000000000000#ifndef __GRAPHICS_UTILITIES_OPEN_G_L_H__ #define __GRAPHICS_UTILITIES_OPEN_G_L_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" namespace caret { class GraphicsOpenGLError; class GraphicsUtilitiesOpenGL : public CaretObject { public: static float convertMillimetersToPercentageOfViewportHeight(const float millimeters); static float convertPercentageOfViewportHeightToMillimeters(const float percentOfViewportHeight); static float convertMillimetersToPixels(const float millimeters); static float convertPixelsToPercentageOfViewportHeight(const float pixels); static float convertPixelsToMillimeters(const float pixels); static void resetOpenGLError(); static std::unique_ptr getOpenGLError(const AString& message = ""); private: GraphicsUtilitiesOpenGL(); virtual ~GraphicsUtilitiesOpenGL(); GraphicsUtilitiesOpenGL(const GraphicsUtilitiesOpenGL&); GraphicsUtilitiesOpenGL& operator=(const GraphicsUtilitiesOpenGL&); }; #ifdef __GRAPHICS_UTILITIES_OPEN_G_L_DECLARE__ // #endif // __GRAPHICS_UTILITIES_OPEN_G_L_DECLARE__ } // namespace #endif //__GRAPHICS_UTILITIES_OPEN_G_L_H__ connectome-workbench-1.4.2/src/GuiQt/000077500000000000000000000000001360521144700174535ustar00rootroot00000000000000connectome-workbench-1.4.2/src/GuiQt/AboutWorkbenchDialog.cxx000066400000000000000000000141151360521144700242360ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ABOUT_WORKBENCH_DIALOG_DECLARE__ #include "AboutWorkbenchDialog.h" #undef __ABOUT_WORKBENCH_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include "ApplicationInformation.h" #include "BrainOpenGLWidget.h" #include "CaretAssert.h" #include "WuQDataEntryDialog.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AboutWorkbenchDialog * \brief Dialog that displays information about workbench. */ /** * Constructor. * * @param openGLParentWidget * The parent OpenGL Widget for which information is provided. */ AboutWorkbenchDialog::AboutWorkbenchDialog(BrainOpenGLWidget* openGLParentWidget) : WuQDialogModal("About Workbench", openGLParentWidget) { m_openGLParentWidget = openGLParentWidget; this->setCancelButtonText(""); ApplicationInformation appInfo; QLabel* imageLabel = NULL; QPixmap pixmap; if (WuQtUtilities::loadPixmap(":/About/hcp-logo.png", pixmap)) { imageLabel = new QLabel(); imageLabel->setPixmap(pixmap); imageLabel->setAlignment(Qt::AlignCenter); } QLabel* workbenchLabel = new QLabel(appInfo.getNameForGuiLabel()); QFont workbenchFont = workbenchLabel->font(); workbenchFont.setBold(true); workbenchFont.setPointSize(32); workbenchLabel->setFont(workbenchFont); const QString labelStyle = ("QLabel { " " font: 20px bold " "}"); QLabel* hcpWebsiteLabel = new QLabel("" "Visit the Human Connectome Project" ""); hcpWebsiteLabel->setStyleSheet(labelStyle); hcpWebsiteLabel->setAlignment(Qt::AlignCenter); QObject::connect(hcpWebsiteLabel, SIGNAL(linkActivated(const QString&)), this, SLOT(websiteLinkActivated(const QString&))); QLabel* versionLabel = new QLabel("Version " + appInfo.getVersion()); QLabel* copyrightLabel = new QLabel("Copyright " + QString::number(QDate::currentDate().year()) + " Washington University"); m_morePushButton = addUserPushButton("More...", QDialogButtonBox::NoRole); m_openGLPushButton = addUserPushButton("OpenGL...", QDialogButtonBox::NoRole); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 2); if (imageLabel != NULL) { layout->addWidget(imageLabel, 0, Qt::AlignHCenter); layout->addSpacing(15); } layout->addWidget(workbenchLabel, 0, Qt::AlignHCenter); layout->addSpacing(15); layout->addWidget(hcpWebsiteLabel, 0, Qt::AlignHCenter); layout->addSpacing(15); layout->addWidget(versionLabel, 0, Qt::AlignHCenter); layout->addSpacing(15); layout->addWidget(copyrightLabel, 0, Qt::AlignHCenter); layout->addSpacing(15); this->setCentralWidget(widget, WuQDialog::SCROLL_AREA_NEVER); } /** * Destructor. */ AboutWorkbenchDialog::~AboutWorkbenchDialog() { } AboutWorkbenchDialog::DialogUserButtonResult AboutWorkbenchDialog::userButtonPressed(QPushButton* userPushButton) { if (userPushButton == m_openGLPushButton) { displayOpenGLInformation(); } else if (userPushButton == m_morePushButton) { displayMoreInformation(); } else { CaretAssert(0); } return AboutWorkbenchDialog::RESULT_NONE; } void AboutWorkbenchDialog::displayOpenGLInformation() { WuQDataEntryDialog ded("OpenGL Information", this, true); ded.addTextEdit("", m_openGLParentWidget->getOpenGLInformation(), true); ded.resize(600, 600); ded.setCancelButtonText(""); ded.exec(); } void AboutWorkbenchDialog::displayMoreInformation() { ApplicationInformation appInfo; std::vector informationData; appInfo.getAllInformation(informationData); QString styleName("Undefined"); QStyle* appStyle = QApplication::style(); if (appStyle != NULL) { styleName = appStyle->objectName(); } informationData.push_back(QString("Style Name: " + styleName)); WuQDataEntryDialog ded("More " + appInfo.getName() + " Information", this, true); const int32_t numInfo = static_cast(informationData.size()); for (int32_t i = 0; i < numInfo; i++) { ded.addWidget("", new QLabel(informationData[i])); } ded.setCancelButtonText(""); ded.exec(); } /** * Called when a label's hyperlink is selected. * @param link * The URL. */ void AboutWorkbenchDialog::websiteLinkActivated(const QString& link) { if (link.isEmpty() == false) { QDesktopServices::openUrl(QUrl(link)); } } connectome-workbench-1.4.2/src/GuiQt/AboutWorkbenchDialog.h000066400000000000000000000037641360521144700236730ustar00rootroot00000000000000#ifndef __ABOUT_WORKBENCH_DIALOG__H_ #define __ABOUT_WORKBENCH_DIALOG__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WuQDialogModal.h" class QPushButton; namespace caret { class BrainOpenGLWidget; class AboutWorkbenchDialog : public WuQDialogModal { Q_OBJECT public: AboutWorkbenchDialog(BrainOpenGLWidget* openGLParentWidget); virtual ~AboutWorkbenchDialog(); protected: virtual DialogUserButtonResult userButtonPressed(QPushButton* userPushButton); private slots: void websiteLinkActivated(const QString& link); private: AboutWorkbenchDialog(const AboutWorkbenchDialog&); AboutWorkbenchDialog& operator=(const AboutWorkbenchDialog&); void displayMoreInformation(); void displayOpenGLInformation(); QPushButton* m_morePushButton; QPushButton* m_openGLPushButton; BrainOpenGLWidget* m_openGLParentWidget; }; #ifdef __ABOUT_WORKBENCH_DIALOG_DECLARE__ // #endif // __ABOUT_WORKBENCH_DIALOG_DECLARE__ } // namespace #endif //__ABOUT_WORKBENCH_DIALOG__H_ connectome-workbench-1.4.2/src/GuiQt/AnnotationChangeCoordinateDialog.cxx000066400000000000000000000162121360521144700265510ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_CHANGE_COORDINATE_DIALOG_DECLARE__ #include "AnnotationChangeCoordinateDialog.h" #undef __ANNOTATION_CHANGE_COORDINATE_DIALOG_DECLARE__ #include #include #include #include #include "Annotation.h" #include "AnnotationCoordinate.h" #include "AnnotationCoordinateSelectionWidget.h" #include "CaretAssert.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AnnotationChangeCoordinateDialog * \brief Dialog for changing an annotation coordinate. * \ingroup GuiQt * * When the user changes a coordinate it may be desirable to * change the coordinate space such as moving from one tab * to another tab. */ /** * Constructor. */ AnnotationChangeCoordinateDialog::AnnotationChangeCoordinateDialog(const AnnotationCoordinateInformation& coordInfo, Annotation* annotation, AnnotationCoordinate* coordinate, AnnotationCoordinate* secondCoordinate, QWidget* parent) : WuQDialogModal("Change Coordinate", parent), m_coordInfo(coordInfo), m_annotation(annotation), m_coordinate(coordinate), m_secondCoordinate(secondCoordinate) { CaretAssert(annotation); CaretAssert(coordinate); QWidget* currentCoordinateWidget = createCurrentCoordinateWidget(); QWidget* newCoordinateWidget = createNewCoordinateWidget(); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(currentCoordinateWidget); layout->addWidget(newCoordinateWidget); setCentralWidget(widget, SCROLL_AREA_NEVER); } /** * Destructor. */ AnnotationChangeCoordinateDialog::~AnnotationChangeCoordinateDialog() { } /** * @return Widget containing new coordinate selection */ QWidget* AnnotationChangeCoordinateDialog::createNewCoordinateWidget() { m_coordinateSelectionWidget = new AnnotationCoordinateSelectionWidget(m_annotation->getType(), m_coordInfo, NULL); m_coordinateSelectionWidget->selectCoordinateSpace(m_annotation->getCoordinateSpace()); QGroupBox* newCoordGroupBox = new QGroupBox("New Coordinate"); QVBoxLayout* newCoordGroupLayout = new QVBoxLayout(newCoordGroupBox); newCoordGroupLayout->setMargin(0); newCoordGroupLayout->addWidget(m_coordinateSelectionWidget); return newCoordGroupBox; } /** * @return Widget containing current coordinate. */ QWidget* AnnotationChangeCoordinateDialog::createCurrentCoordinateWidget() { QString spaceText(AnnotationCoordinateSpaceEnum::toGuiName(m_annotation->getCoordinateSpace()) + " "); bool useXyzFlag = true; switch (m_annotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: spaceText += m_annotation->getSpacerTabIndex().getRowColumnGuiText(); break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: { useXyzFlag = false; StructureEnum::Enum structure = StructureEnum::INVALID; int32_t numberOfNodes = -1; int32_t nodeIndex = -1; m_coordinate->getSurfaceSpace(structure, numberOfNodes, nodeIndex); spaceText += ("Structure: " + StructureEnum::toGuiName(structure) + " Node Index=" + QString::number(nodeIndex)); } break; case AnnotationCoordinateSpaceEnum::TAB: spaceText += (AString::number(m_annotation->getTabIndex() + 1) + " "); break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: spaceText += (AString::number(m_annotation->getWindowIndex() + 1) + " "); break; } QGroupBox* groupBox = new QGroupBox("Coordinate"); if (useXyzFlag) { float xyz[3]; m_coordinate->getXYZ(xyz); QGridLayout* gridLayout = new QGridLayout(groupBox); int row = gridLayout->rowCount(); gridLayout->addWidget(new QLabel("Space"), row, 0, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("X"), row, 1, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Y"), row, 2, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Z"), row, 3, Qt::AlignHCenter); row++; gridLayout->addWidget(new QLabel(spaceText), row, 0); gridLayout->addWidget(new QLabel(QString::number(xyz[0], 'f', 1)), row, 1, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(xyz[1], 'f', 1)), row, 2, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(xyz[2], 'f', 1)), row, 3, Qt::AlignRight); } else { QLabel* spaceLabel = new QLabel(spaceText); QVBoxLayout* layout = new QVBoxLayout(groupBox); layout->addWidget(spaceLabel); } return groupBox; } /** * Called when the OK button is clicked. */ void AnnotationChangeCoordinateDialog::okButtonClicked() { QString errorMessage; if ( ! m_coordinateSelectionWidget->changeAnnotationCoordinate(m_annotation, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); return; } WuQDialogModal::okButtonClicked(); } connectome-workbench-1.4.2/src/GuiQt/AnnotationChangeCoordinateDialog.h000066400000000000000000000051261360521144700262000ustar00rootroot00000000000000#ifndef __ANNOTATION_CHANGE_COORDINATE_DIALOG_H__ #define __ANNOTATION_CHANGE_COORDINATE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "UserInputModeAnnotations.h" #include "WuQDialogModal.h" namespace caret { class Annotation; class AnnotationCoordinate; class AnnotationCoordinateSelectionWidget; class AnnotationChangeCoordinateDialog : public WuQDialogModal { Q_OBJECT public: AnnotationChangeCoordinateDialog(const AnnotationCoordinateInformation& coordInfo, Annotation* annotation, AnnotationCoordinate* coordinate, AnnotationCoordinate* secondCoordinate, QWidget* parent); virtual ~AnnotationChangeCoordinateDialog(); virtual void okButtonClicked(); // ADD_NEW_METHODS_HERE private: AnnotationChangeCoordinateDialog(const AnnotationChangeCoordinateDialog&); AnnotationChangeCoordinateDialog& operator=(const AnnotationChangeCoordinateDialog&); QWidget* createCurrentCoordinateWidget(); QWidget* createNewCoordinateWidget(); const AnnotationCoordinateInformation& m_coordInfo; Annotation* m_annotation; AnnotationCoordinate* m_coordinate; AnnotationCoordinate* m_secondCoordinate; AnnotationCoordinateSelectionWidget* m_coordinateSelectionWidget; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_CHANGE_COORDINATE_DIALOG_DECLARE__ // #endif // __ANNOTATION_CHANGE_COORDINATE_DIALOG_DECLARE__ } // namespace #endif //__ANNOTATION_CHANGE_COORDINATE_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationColorWidget.cxx000066400000000000000000000644571360521144700244740ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_COLOR_WIDGET_DECLARE__ #include "AnnotationColorWidget.h" #undef __ANNOTATION_COLOR_WIDGET_DECLARE__ #include #include #include #include #include #include #include #include "AnnotationManager.h" #include "AnnotationOneDimensionalShape.h" #include "AnnotationTwoDimensionalShape.h" #include "AnnotationRedoUndoCommand.h" #include "Brain.h" #include "BrainOpenGL.h" #include "CaretAssert.h" #include "CaretColorEnumMenu.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "GuiManager.h" #include "WuQFactory.h" #include "WuQMessageBox.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AnnotationColorWidget * \brief Widget for annotation color selection. * \ingroup GuiQt */ /** * Constructor. * * @param parent * Parent for this widget. */ AnnotationColorWidget::AnnotationColorWidget(const AnnotationWidgetParentEnum::Enum parentWidgetType, const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), m_parentWidgetType(parentWidgetType), m_browserWindowIndex(browserWindowIndex) { QLabel* backFillLabel = new QLabel("Fill"); QLabel* backFillColorLabel = new QLabel("Color"); QLabel* foreLineLabel = new QLabel("Line"); QLabel* foreLineColorLabel = new QLabel("Color"); QLabel* lineLabel = new QLabel("Line"); QLabel* lineWidthLabel = new QLabel("Width"); const QSize toolButtonSize(16, 16); /* * Background color menu */ m_backgroundColorMenu = new CaretColorEnumMenu((CaretColorEnum::OPTION_INCLUDE_CUSTOM_COLOR | CaretColorEnum::OPTION_INCLUDE_NONE_COLOR)); QObject::connect(m_backgroundColorMenu, SIGNAL(colorSelected(const CaretColorEnum::Enum)), this, SLOT(backgroundColorSelected(const CaretColorEnum::Enum))); /* * Background action and tool button */ m_backgroundColorAction = new QAction("B", this); m_backgroundColorAction->setToolTip("Adjust the fill color"); m_backgroundColorAction->setMenu(m_backgroundColorMenu); m_backgroundToolButton = new QToolButton(); m_backgroundToolButton->setDefaultAction(m_backgroundColorAction); m_backgroundToolButton->setIconSize(toolButtonSize); WuQtUtilities::setToolButtonStyleForQt5Mac(m_backgroundToolButton); /* * Widget/object group for background widgets */ m_backgroundColorWidgetGroup = new WuQWidgetObjectGroup(this); m_backgroundColorWidgetGroup->add(backFillLabel); m_backgroundColorWidgetGroup->add(backFillColorLabel); m_backgroundColorWidgetGroup->add(m_backgroundToolButton); /* * Line color menu */ m_lineColorMenu = new CaretColorEnumMenu((CaretColorEnum::OPTION_INCLUDE_CUSTOM_COLOR | CaretColorEnum::OPTION_INCLUDE_NONE_COLOR)); QObject::connect(m_lineColorMenu, SIGNAL(colorSelected(const CaretColorEnum::Enum)), this, SLOT(lineColorSelected(const CaretColorEnum::Enum))); /* * Line color action and toolbutton */ m_lineColorAction = new QAction("F", this); m_lineColorAction->setToolTip("Adjust the line color"); m_lineColorAction->setMenu(m_lineColorMenu); m_lineToolButton = new QToolButton(); m_lineToolButton->setDefaultAction(m_lineColorAction); m_lineToolButton->setIconSize(toolButtonSize); WuQtUtilities::setToolButtonStyleForQt5Mac(m_lineToolButton); m_lineColorWidgetGroup = new WuQWidgetObjectGroup(this); m_lineColorWidgetGroup->add(foreLineLabel); m_lineColorWidgetGroup->add(foreLineColorLabel); m_lineColorWidgetGroup->add(m_lineColorMenu); m_lineColorWidgetGroup->add(m_lineToolButton); /* * Line thickness */ float minimumLineWidthPercentage = 0.1; float maximumLineWidthPercentage = 100.0; float lineWidthStep = 0.1; m_lineThicknessWidgetGroup = new WuQWidgetObjectGroup(this); m_lineThicknessSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(minimumLineWidthPercentage, maximumLineWidthPercentage, lineWidthStep, 1, this, SLOT(lineThicknessSpinBoxValueChanged(double))); WuQtUtilities::setWordWrappedToolTip(m_lineThicknessSpinBox, "Adjust the line thickness as percentage of tab/window height"); m_lineThicknessSpinBox->setSuffix("%"); m_lineThicknessWidgetGroup->add(lineLabel); m_lineThicknessWidgetGroup->add(lineWidthLabel); m_lineThicknessWidgetGroup->add(m_lineThicknessSpinBox); /* * Layout */ QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 0); switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: { CaretAssert(lineWidthLabel); gridLayout->addWidget(lineLabel, 0, 0, Qt::AlignHCenter); gridLayout->addWidget(lineWidthLabel, 1, 0, Qt::AlignHCenter); gridLayout->addWidget(foreLineLabel, 0, 1, Qt::AlignHCenter); gridLayout->addWidget(foreLineColorLabel, 1, 1, Qt::AlignHCenter); gridLayout->addWidget(m_lineThicknessSpinBox, 2, 0, Qt::AlignHCenter); gridLayout->addWidget(m_lineToolButton, 2, 1, Qt::AlignHCenter); gridLayout->addWidget(backFillLabel, 0, 2, Qt::AlignHCenter); gridLayout->addWidget(backFillColorLabel, 1, 2, Qt::AlignHCenter); gridLayout->addWidget(m_backgroundToolButton, 2, 2, Qt::AlignHCenter); } break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } /* * Layout widgets */ backgroundColorSelected(CaretColorEnum::WHITE); lineColorSelected(CaretColorEnum::BLACK); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } /** * Destructor. */ AnnotationColorWidget::~AnnotationColorWidget() { } /** * Update with the given annotation. * * @param annotations */ void AnnotationColorWidget::updateContent(std::vector& annotations) { m_lineColorAnnotations.clear(); m_lineColorAnnotations.reserve(annotations.size()); m_lineThicknessAnnotations.clear(); m_lineThicknessAnnotations.reserve(annotations.size()); m_backgroundColorAnnotations.clear(); m_backgroundColorAnnotations.reserve(annotations.size()); bool haveAnnotationsFlag = false; for (auto a : annotations) { if (a->testProperty(Annotation::Property::FILL_COLOR)) { m_backgroundColorAnnotations.push_back(a); } if (a->testProperty(Annotation::Property::LINE_COLOR)) { m_lineColorAnnotations.push_back(a); } if (a->testProperty(Annotation::Property::LINE_THICKNESS)) { m_lineThicknessAnnotations.push_back(a); } haveAnnotationsFlag = true; } setEnabled(haveAnnotationsFlag); updateBackgroundColorButton(); updateLineColorButton(); updateLineThicknessSpinBox(); } /** * Gets called when the background color is changed. * * @param caretColor * Color that was selected. */ void AnnotationColorWidget::backgroundColorSelected(const CaretColorEnum::Enum caretColor) { if (! m_backgroundColorAnnotations.empty()) { float rgba[4]; m_backgroundColorAnnotations[0]->getCustomBackgroundColor(rgba); if (caretColor == CaretColorEnum::CUSTOM) { QColor color; color.setRgbF(rgba[0], rgba[1], rgba[2]); QColor newColor = QColorDialog::getColor(color, m_backgroundToolButton, "Background Color"); if (newColor.isValid()) { rgba[0] = newColor.redF(); rgba[1] = newColor.greenF(); rgba[2] = newColor.blueF(); switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: Annotation::setUserDefaultCustomBackgroundColor(rgba); break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } } } if ( ! isBothColorsSetToNoneAllowed(this, caretColor, m_lineColorMenu->getSelectedColor(), m_backgroundColorAnnotations)) { return; } AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeColorBackground(caretColor, rgba, m_backgroundColorAnnotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } Annotation::setUserDefaultBackgroundColor(caretColor); EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); } updateBackgroundColorButton(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Update the background color. */ void AnnotationColorWidget::updateBackgroundColorButton() { CaretColorEnum::Enum colorEnum = CaretColorEnum::NONE; float rgba[4]; CaretColorEnum::toRGBAFloat(colorEnum, rgba); rgba[3] = 1.0; bool enableBackgroundFlag = false; const int32_t numAnnotations = static_cast(m_backgroundColorAnnotations.size()); if (numAnnotations > 0) { bool firstColorSupportFlag = true; bool allSameColorFlag = true; for (int32_t i = 0; i < numAnnotations; i++) { if (firstColorSupportFlag) { m_backgroundColorAnnotations[i]->getBackgroundColorRGBA(rgba); firstColorSupportFlag = false; enableBackgroundFlag = true; } else { float colorRGBA[4]; m_backgroundColorAnnotations[i]->getBackgroundColorRGBA(colorRGBA); for (int32_t iColor = 0; iColor < 4; iColor++) { if (rgba[iColor] != colorRGBA[iColor]) { allSameColorFlag = false; break; } } if ( ! allSameColorFlag) { break; } } } if (allSameColorFlag) { colorEnum = m_backgroundColorAnnotations[0]->getBackgroundColor(); m_backgroundColorAnnotations[0]->getBackgroundColorRGBA(rgba); float customRGBA[4]; m_backgroundColorAnnotations[0]->getCustomBackgroundColor(customRGBA); m_backgroundColorMenu->setCustomIconColor(customRGBA); switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: Annotation::setUserDefaultBackgroundColor(colorEnum); Annotation::setUserDefaultCustomBackgroundColor(customRGBA); break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } } } m_backgroundColorWidgetGroup->setEnabled(enableBackgroundFlag); if ( ! enableBackgroundFlag) { colorEnum = CaretColorEnum::NONE; } QPixmap pm = WuQtUtilities::createCaretColorEnumPixmap(m_backgroundToolButton, 24, 24, colorEnum, rgba, false); QIcon icon(pm); m_backgroundColorAction->setIcon(icon); m_backgroundColorMenu->setSelectedColor(colorEnum); } /** * Update the line color. */ void AnnotationColorWidget::updateLineColorButton() { CaretColorEnum::Enum colorEnum = CaretColorEnum::NONE; float rgba[4]; CaretColorEnum::toRGBAFloat(colorEnum, rgba); rgba[3] = 1.0; const int32_t numAnnotations = static_cast(m_lineColorAnnotations.size()); bool enableLineFlag = false; if (numAnnotations > 0) { bool firstColorSupportFlag = true; bool allSameColorFlag = true; for (int32_t i = 0; i < numAnnotations; i++) { if (firstColorSupportFlag) { m_lineColorAnnotations[i]->getLineColorRGBA(rgba); firstColorSupportFlag = false; enableLineFlag = true; } else { float colorRGBA[4]; m_lineColorAnnotations[i]->getLineColorRGBA(colorRGBA); for (int32_t iColor = 0; iColor < 4; iColor++) { if (rgba[iColor] != colorRGBA[iColor]) { allSameColorFlag = false; break; } } if ( ! allSameColorFlag) { break; } } } if (allSameColorFlag) { colorEnum = m_lineColorAnnotations[0]->getLineColor(); m_lineColorAnnotations[0]->getLineColorRGBA(rgba); float customRGBA[4]; m_lineColorAnnotations[0]->getCustomLineColor(customRGBA); m_lineColorMenu->setCustomIconColor(customRGBA); switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: setUserDefaultLineColor(colorEnum, customRGBA); break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } } } m_lineColorWidgetGroup->setEnabled(enableLineFlag); if ( ! enableLineFlag) { colorEnum = CaretColorEnum::NONE; } QPixmap pm = WuQtUtilities::createCaretColorEnumPixmap(m_lineToolButton, 24, 24, colorEnum, rgba, true); m_lineColorAction->setIcon(QIcon(pm)); m_lineColorMenu->setSelectedColor(colorEnum); } /** * Tests for both background and line colors both set to none. This is allowed * for some annotations types such as text, which uses a text color, or images. * * @param widget * Widget on which error dialog is displayed. * @param colorOne * One of the background or line colors. * @param colorTwo * The other one of the background or line colors. * @param annotations * The selected annotations. * @return * True if the colors are acceptable, else false (and a an error * message dialog is displayed). */ bool AnnotationColorWidget::isBothColorsSetToNoneAllowed(QWidget* widget, const CaretColorEnum::Enum colorOne, const CaretColorEnum::Enum colorTwo, const std::vector& annotations) { if ((colorOne == CaretColorEnum::NONE) && (colorTwo == CaretColorEnum::NONE)) { bool allowBothColorsNoneFlag = true; for (std::vector::const_iterator iter = annotations.begin(); iter != annotations.end(); iter++) { const Annotation* ann = *iter; CaretAssert(ann); switch (ann->getType()) { case AnnotationTypeEnum::BOX: allowBothColorsNoneFlag = false; break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: break; case AnnotationTypeEnum::LINE: allowBothColorsNoneFlag = false; break; case AnnotationTypeEnum::OVAL: allowBothColorsNoneFlag = false; break; case AnnotationTypeEnum::TEXT: break; } } if ( ! allowBothColorsNoneFlag) { const AString message("Setting both Line and Fill colors to NONE is not allowed for the selected annotation(s)."); WuQMessageBox::errorOk(widget, message); return false; } } return true; } /** * Gets called when the line color is changed. * * @param caretColor * Color that was selected. */ void AnnotationColorWidget::lineColorSelected(const CaretColorEnum::Enum caretColor) { if ( ! m_lineColorAnnotations.empty()) { CaretAssertVectorIndex(m_lineColorAnnotations, 0); float rgba[4]; m_lineColorAnnotations[0]->getCustomLineColor(rgba); if (caretColor == CaretColorEnum::CUSTOM) { QColor color; color.setRgbF(rgba[0], rgba[1], rgba[2]); QColor newColor = QColorDialog::getColor(color, m_backgroundToolButton, "Line Color"); if (newColor.isValid()) { rgba[0] = newColor.redF(); rgba[1] = newColor.greenF(); rgba[2] = newColor.blueF(); } } if ( ! isBothColorsSetToNoneAllowed(this, caretColor, m_backgroundColorMenu->getSelectedColor(), m_lineColorAnnotations)) { return; } AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeColorLine(caretColor, rgba, m_lineColorAnnotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } setUserDefaultLineColor(caretColor, rgba); } updateLineColorButton(); switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: break; } EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Set the user default line color. * * @param caretColor * The line color. * @param customRGBA * The custom line color RGBA components. */ void AnnotationColorWidget::setUserDefaultLineColor(const CaretColorEnum::Enum caretColor, const float customRGBA[4]) { if ( ! m_lineColorAnnotations.empty()) { bool allTextFlag = true; bool someTextFlag = false; for (std::vector::iterator iter = m_lineColorAnnotations.begin(); iter != m_lineColorAnnotations.end(); iter++) { const Annotation* ann = *iter; if (ann->getType() == AnnotationTypeEnum::TEXT) { someTextFlag = true; } else { allTextFlag = false; } } /* * Note: Text has its own default line color. Without it, if the * user creates a text annotation it will get a box around it since * other annotations frequently use a line color. */ if (allTextFlag || someTextFlag) { Annotation::setUserDefaultForTextLineColor(caretColor); if (caretColor == CaretColorEnum::CUSTOM) { Annotation::setUserDefaultForTextCustomLineColor(customRGBA); } } if (! allTextFlag) { Annotation::setUserDefaultLineColor(caretColor); if (caretColor == CaretColorEnum::CUSTOM) { Annotation::setUserDefaultCustomLineColor(customRGBA); } } } } /** * Gets called when the line thickness value changes. * * @param value * New value for line thickness. */ void AnnotationColorWidget::lineThicknessSpinBoxValueChanged(double value) { if ( ! m_lineThicknessSpinBox->specialValueText().isEmpty()) { if (m_lineThicknessSpinBox->specialValueText() == m_lineThicknessSpinBox->text()) { /* * Ignore special text which is available when * there are multiple annotations with different * line thicknesses. */ std::cout << "Ignoring special text " << std::endl; return; } } AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeLineWidth(value, m_lineThicknessAnnotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); Annotation::setUserDefaultLineWidthPercentage(value); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Update the line thickness spin box. */ void AnnotationColorWidget::updateLineThicknessSpinBox() { if (m_lineThicknessSpinBox == NULL) { return; } float lineWidthValue = 1.0; bool lineWidthValid = false; bool haveMultipleLineWidthValues = false; const int32_t numAnnotations = static_cast(m_lineThicknessAnnotations.size()); if (numAnnotations > 0) { for (int32_t i = 0; i < numAnnotations; i++) { const float annLineWidth = m_lineThicknessAnnotations[i]->getLineWidthPercentage(); if (lineWidthValid) { if (annLineWidth != lineWidthValue) { haveMultipleLineWidthValues = true; } lineWidthValue = std::min(lineWidthValue, annLineWidth); } else { lineWidthValue = annLineWidth; lineWidthValid = true; } } if (lineWidthValid) { switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: Annotation::setUserDefaultLineWidthPercentage(lineWidthValue); break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } } } /* * When the selected annotations have different line * widths, the valid displayed is the minimum line * width with a suffix consisting of a plus symbol. */ m_lineThicknessSpinBox->blockSignals(true); m_lineThicknessSpinBox->setValue(lineWidthValue); m_lineThicknessSpinBox->setEnabled(lineWidthValid); if (haveMultipleLineWidthValues) { m_lineThicknessSpinBox->setSuffix("%+"); } else { m_lineThicknessSpinBox->setSuffix("%"); } m_lineThicknessSpinBox->blockSignals(false); m_lineThicknessWidgetGroup->setEnabled(numAnnotations > 0); } connectome-workbench-1.4.2/src/GuiQt/AnnotationColorWidget.h000066400000000000000000000073561360521144700241140ustar00rootroot00000000000000#ifndef __ANNOTATION_COLOR_WIDGET_H__ #define __ANNOTATION_COLOR_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AnnotationWidgetParentEnum.h" #include "CaretColorEnum.h" class QAction; class QDoubleSpinBox; class QToolButton; namespace caret { class Annotation; class CaretColorEnumMenu; class WuQWidgetObjectGroup; class AnnotationColorWidget : public QWidget { Q_OBJECT public: AnnotationColorWidget(const AnnotationWidgetParentEnum::Enum parentWidgetType, const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~AnnotationColorWidget(); void updateContent(std::vector& annotations); // ADD_NEW_METHODS_HERE private slots: void backgroundColorSelected(const CaretColorEnum::Enum); void lineColorSelected(const CaretColorEnum::Enum); private slots: void lineThicknessSpinBoxValueChanged(double value); private: AnnotationColorWidget(const AnnotationColorWidget&); AnnotationColorWidget& operator=(const AnnotationColorWidget&); void setUserDefaultLineColor(const CaretColorEnum::Enum caretColor, const float customRGBA[4]); void updateBackgroundColorButton(); void updateLineColorButton(); void updateLineThicknessSpinBox(); static bool isBothColorsSetToNoneAllowed(QWidget* widget, const CaretColorEnum::Enum colorOne, const CaretColorEnum::Enum colorTwo, const std::vector& annotations); const AnnotationWidgetParentEnum::Enum m_parentWidgetType; const int32_t m_browserWindowIndex; QToolButton* m_backgroundToolButton; QToolButton* m_lineToolButton; QAction* m_lineColorAction; QAction* m_backgroundColorAction; CaretColorEnumMenu* m_lineColorMenu; CaretColorEnumMenu* m_backgroundColorMenu; QDoubleSpinBox* m_lineThicknessSpinBox; WuQWidgetObjectGroup* m_backgroundColorWidgetGroup; WuQWidgetObjectGroup* m_lineColorWidgetGroup; WuQWidgetObjectGroup* m_lineThicknessWidgetGroup; std::vector m_lineColorAnnotations; std::vector m_lineThicknessAnnotations; std::vector m_backgroundColorAnnotations; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_COLOR_WIDGET_DECLARE__ // #endif // __ANNOTATION_COLOR_WIDGET_DECLARE__ } // namespace #endif //__ANNOTATION_COLOR_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationCoordinateInformation.cxx000066400000000000000000001230551360521144700265350ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_COORDINATE_INFORMATION_DECLARE__ #include "AnnotationCoordinateInformation.h" #undef __ANNOTATION_COORDINATE_INFORMATION_DECLARE__ #include "Annotation.h" #include "AnnotationCoordinate.h" #include "AnnotationOneDimensionalShape.h" #include "AnnotationTwoDimensionalShape.h" #include "BrainOpenGLWidget.h" #include "BrainOpenGLViewportContent.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "EventIdentificationRequest.h" #include "EventManager.h" #include "MouseEvent.h" #include "SelectionItemSurfaceNode.h" #include "SelectionItemVoxel.h" #include "SelectionManager.h" #include "SpacerTabContent.h" #include "Surface.h" using namespace caret; /** * \class caret::AnnotationCoordinateInformation * \brief Contains annotation coordinate types valid for a window coordinate * \ingroup GuiQt * * Annotations support several different coordinate systems. This class * contains validity for each these different coordinate systems. */ /** * Constructor. */ AnnotationCoordinateInformation::AnnotationCoordinateInformation() { reset(); } /** * Destructor. */ AnnotationCoordinateInformation::~AnnotationCoordinateInformation() { } /** * Reset all coordinate information to invalid. */ void AnnotationCoordinateInformation::reset() { m_modelSpaceInfo = ModelSpaceInfo(); m_tabSpaceInfo = TabWindowSpaceInfo(); m_windowSpaceInfo = TabWindowSpaceInfo(); m_chartSpaceInfo = ChartSpaceInfo(); m_surfaceSpaceInfo = SurfaceSpaceInfo(); m_spacerTabSpaceInfo = SpacerTabSpaceInfo(); } bool AnnotationCoordinateInformation::isCoordinateSpaceValid(const AnnotationCoordinateSpaceEnum::Enum space) const { bool validSpaceFlag = false; switch (space) { case AnnotationCoordinateSpaceEnum::CHART: validSpaceFlag = m_chartSpaceInfo.m_validFlag; break; case AnnotationCoordinateSpaceEnum::SPACER: validSpaceFlag = m_spacerTabSpaceInfo.m_spacerTabIndex.isValid(); break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: validSpaceFlag = m_modelSpaceInfo.m_validFlag; break; case AnnotationCoordinateSpaceEnum::SURFACE: validSpaceFlag = m_surfaceSpaceInfo.m_validFlag; break; case AnnotationCoordinateSpaceEnum::TAB: validSpaceFlag = (m_tabSpaceInfo.m_index >= 0); break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssertMessage(0, "Should not create/move viewport annotations"); break; case AnnotationCoordinateSpaceEnum::WINDOW: validSpaceFlag = (m_windowSpaceInfo.m_index >= 0); break; } return validSpaceFlag; } /** * Get the valid coordinate spaces for the two annotation coordinate information. * If both coordinates are valid, the space must be valid for both coordinates, AND, if tab or window * space the tab or window indices must also be the same. * * @param coordInfoOne * First coordinate information. * @param coordInfoTwo * Second coordinate information (optional, NULL if not valid). * @param spacesOut * Output containing spaces valid for both. */ void AnnotationCoordinateInformation::getValidCoordinateSpaces(const AnnotationCoordinateInformation* coordInfoOne, const AnnotationCoordinateInformation* coordInfoTwo, std::vector& spacesOut) { CaretAssert(coordInfoOne); spacesOut.clear(); std::vector allSpaces; AnnotationCoordinateSpaceEnum::getAllEnums(allSpaces); for (std::vector::iterator spaceIter = allSpaces.begin(); spaceIter != allSpaces.end(); spaceIter++) { const AnnotationCoordinateSpaceEnum::Enum space = *spaceIter; switch (space) { case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::CHART: case AnnotationCoordinateSpaceEnum::SPACER: case AnnotationCoordinateSpaceEnum::STEREOTAXIC: case AnnotationCoordinateSpaceEnum::SURFACE: case AnnotationCoordinateSpaceEnum::TAB: case AnnotationCoordinateSpaceEnum::WINDOW: /* * See if space for first coord info is valid */ if (coordInfoOne->isCoordinateSpaceValid(space)) { bool addItFlag = true; if (coordInfoTwo != NULL) { /* * See if same space is valid for second coord info */ addItFlag = coordInfoTwo->isCoordinateSpaceValid(space); switch (space) { case AnnotationCoordinateSpaceEnum::CHART: /* * Both coord info's must be in the SAME TAB */ if (coordInfoOne->m_tabSpaceInfo.m_index != coordInfoTwo->m_tabSpaceInfo.m_index) { addItFlag = false; } break; case AnnotationCoordinateSpaceEnum::SPACER: if (coordInfoOne->m_spacerTabSpaceInfo.m_spacerTabIndex != coordInfoTwo->m_spacerTabSpaceInfo.m_spacerTabIndex) { addItFlag = false; } break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: /* * Both coord info's must be in the SAME TAB */ if (coordInfoOne->m_tabSpaceInfo.m_index != coordInfoTwo->m_tabSpaceInfo.m_index) { addItFlag = false; } break; case AnnotationCoordinateSpaceEnum::SURFACE: /* * Both coord info's must be on same surface and * in the SAME TAB */ if ((coordInfoOne->m_tabSpaceInfo.m_index != coordInfoTwo->m_tabSpaceInfo.m_index) || (coordInfoOne->m_surfaceSpaceInfo.m_numberOfNodes != coordInfoTwo->m_surfaceSpaceInfo.m_numberOfNodes) || (coordInfoOne->m_surfaceSpaceInfo.m_structure != coordInfoTwo->m_surfaceSpaceInfo.m_structure)) { addItFlag = false; } break; case AnnotationCoordinateSpaceEnum::TAB: if (coordInfoOne->m_tabSpaceInfo.m_index != coordInfoTwo->m_tabSpaceInfo.m_index) { addItFlag = false; } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: //if (coordInfoOne->m_windowIndex != coordInfoTwo->m_windowIndex) { // addItFlag = false; //} break; case AnnotationCoordinateSpaceEnum::WINDOW: if (coordInfoOne->m_windowSpaceInfo.m_index != coordInfoTwo->m_windowSpaceInfo.m_index) { addItFlag = false; } break; } } if (addItFlag) { spacesOut.push_back(space); } } break; } } } /** * Get the different types of coordinates at the given mouse location. * * @param mouseEvent * Mouse event containing mouse location information. * @param coordInfoOut * Output containing coordinate information. */ void AnnotationCoordinateInformation::createCoordinateInformationFromXY(const MouseEvent& mouseEvent, AnnotationCoordinateInformation& coordInfoOut) { createCoordinateInformationFromXY(mouseEvent.getOpenGLWidget(), mouseEvent.getViewportContent(), mouseEvent.getX(), mouseEvent.getY(), coordInfoOut); } /** * Get the different types of coordinates at the given mouse location. * * @param mouseEvent * Mouse event containing mouse location information. * @param windowX * X-coordinate in the window. * @param windowY * Y-coordinate in the window. * @param coordInfoOut * Output containing coordinate information. */ void AnnotationCoordinateInformation::createCoordinateInformationFromXY(const MouseEvent& mouseEvent, const int32_t windowX, const int32_t windowY, AnnotationCoordinateInformation& coordInfoOut) { createCoordinateInformationFromXY(mouseEvent.getOpenGLWidget(), mouseEvent.getViewportContent(), windowX, windowY, coordInfoOut); } /** * Get the different types of coordinates at the given mouse location. * * @param openGLWidget * The OpenGL Widget. * @param viewportContent * The content of the viewport. * @param windowX * X-coordinate in the window. * @param windowY * Y-coordinate in the window. * @param coordInfoOut * Output containing coordinate information. */ void AnnotationCoordinateInformation::createCoordinateInformationFromXY(BrainOpenGLWidget* openGLWidget, BrainOpenGLViewportContent* viewportContent, const int32_t windowX, const int32_t windowY, AnnotationCoordinateInformation& coordInfoOut) { coordInfoOut.reset(); SelectionManager* idManager = openGLWidget->performIdentification(windowX, windowY, false); SelectionItemVoxel* voxelID = idManager->getVoxelIdentification(); SelectionItemSurfaceNode* surfaceNodeIdentification = idManager->getSurfaceNodeIdentification(); if (surfaceNodeIdentification->isValid()) { surfaceNodeIdentification->getModelXYZ(coordInfoOut.m_modelSpaceInfo.m_xyz); coordInfoOut.m_modelSpaceInfo.m_validFlag = true; const Surface* surface = surfaceNodeIdentification->getSurface(); CaretAssert(surface); coordInfoOut.m_surfaceSpaceInfo.m_numberOfNodes = surface->getNumberOfNodes(); coordInfoOut.m_surfaceSpaceInfo.m_structure = surface->getStructure(); coordInfoOut.m_surfaceSpaceInfo.m_nodeIndex = surfaceNodeIdentification->getNodeNumber(); coordInfoOut.m_surfaceSpaceInfo.m_nodeOffsetLength = AnnotationCoordinate::getDefaultSurfaceOffsetLength(); coordInfoOut.m_surfaceSpaceInfo.m_nodeVectorOffsetType = AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX; surface->getNormalVector(surfaceNodeIdentification->getNodeNumber(), coordInfoOut.m_surfaceSpaceInfo.m_nodeNormalVector); coordInfoOut.m_surfaceSpaceInfo.m_validFlag = true; } else if (voxelID->isValid()) { voxelID->getModelXYZ(coordInfoOut.m_modelSpaceInfo.m_xyz); coordInfoOut.m_modelSpaceInfo.m_validFlag = true; } /* * In tile tabs, some regions may not contain a tab such * as three tabs in a two-by-two configuration * or if the user has clicked in a margin */ BrowserTabContent* tabContent = viewportContent->getBrowserTabContent(); if (tabContent != NULL) { int tabViewport[4]; viewportContent->getModelViewport(tabViewport); const float tabX = 100.0 * (windowX - tabViewport[0]) / static_cast(tabViewport[2]); const float tabY = 100.0 * (windowY - tabViewport[1]) / static_cast(tabViewport[3]); if ((tabX >= 0.0) && (tabX < 100.0) && (tabY >= 0.0) && (tabY <= 100.0)) { coordInfoOut.m_tabSpaceInfo.m_xyz[0] = tabX; coordInfoOut.m_tabSpaceInfo.m_xyz[1] = tabY; coordInfoOut.m_tabSpaceInfo.m_xyz[2] = 0.0; coordInfoOut.m_tabSpaceInfo.m_pixelXYZ[0] = (windowX - tabViewport[0]); coordInfoOut.m_tabSpaceInfo.m_pixelXYZ[1] = (windowY - tabViewport[1]); coordInfoOut.m_tabSpaceInfo.m_pixelXYZ[2] = 0.0; coordInfoOut.m_tabSpaceInfo.m_index = tabContent->getTabNumber(); coordInfoOut.m_tabSpaceInfo.m_width = tabViewport[2]; coordInfoOut.m_tabSpaceInfo.m_height = tabViewport[3]; } } if (tabContent != NULL) { Matrix4x4 projectionMatrix; Matrix4x4 modelviewMatrix; int viewport[4]; if (viewportContent->getChartDataMatricesAndViewport(projectionMatrix, modelviewMatrix, viewport)) { if ((windowX >= viewport[0]) && (windowX < (viewport[0] + viewport[2])) && (windowY >= viewport[1]) && (windowY < (viewport[1] + viewport[3]))) { double projectionArray[16]; projectionMatrix.getMatrixForOpenGL(projectionArray); double modelviewArray[16]; modelviewMatrix.getMatrixForOpenGL(modelviewArray); double chartX = 0.0; double chartY = 0.0; double chartZ = 0.0; if (gluUnProject(windowX, windowY, 0.0, modelviewArray, projectionArray, viewport, &chartX, &chartY, &chartZ) == GL_TRUE) { coordInfoOut.m_chartSpaceInfo.m_xyz[0] = static_cast(chartX); coordInfoOut.m_chartSpaceInfo.m_xyz[1] = static_cast(chartY); coordInfoOut.m_chartSpaceInfo.m_xyz[2] = static_cast(chartZ); coordInfoOut.m_chartSpaceInfo.m_validFlag = true; } } } } SpacerTabContent* spacerTabContent = viewportContent->getSpacerTabContent(); if (spacerTabContent != NULL) { int tabViewport[4]; viewportContent->getModelViewport(tabViewport); const float tabX = 100.0 * (windowX - tabViewport[0]) / static_cast(tabViewport[2]); const float tabY = 100.0 * (windowY - tabViewport[1]) / static_cast(tabViewport[3]); if ((tabX >= 0.0) && (tabX < 100.0) && (tabY >= 0.0) && (tabY <= 100.0)) { coordInfoOut.m_spacerTabSpaceInfo.m_xyz[0] = tabX; coordInfoOut.m_spacerTabSpaceInfo.m_xyz[1] = tabY; coordInfoOut.m_spacerTabSpaceInfo.m_xyz[2] = 0.0; coordInfoOut.m_spacerTabSpaceInfo.m_pixelXYZ[0] = (windowX - tabViewport[0]); coordInfoOut.m_spacerTabSpaceInfo.m_pixelXYZ[1] = (windowY - tabViewport[1]); coordInfoOut.m_spacerTabSpaceInfo.m_pixelXYZ[2] = 0.0; coordInfoOut.m_spacerTabSpaceInfo.m_spacerTabIndex = spacerTabContent->getSpacerTabIndex(); coordInfoOut.m_spacerTabSpaceInfo.m_validFlag = spacerTabContent->getSpacerTabIndex().isValid(); coordInfoOut.m_spacerTabSpaceInfo.m_width = tabViewport[2]; coordInfoOut.m_spacerTabSpaceInfo.m_height = tabViewport[3]; } } int windowViewport[4]; viewportContent->getWindowViewport(windowViewport); coordInfoOut.m_windowSpaceInfo.m_pixelXYZ[0] = windowX - windowViewport[0]; coordInfoOut.m_windowSpaceInfo.m_pixelXYZ[1] = windowY - windowViewport[1]; coordInfoOut.m_windowSpaceInfo.m_pixelXYZ[2] = 0.0; coordInfoOut.m_windowSpaceInfo.m_index = viewportContent->getWindowIndex(); coordInfoOut.m_windowSpaceInfo.m_width = windowViewport[2]; coordInfoOut.m_windowSpaceInfo.m_height = windowViewport[3]; /* * Normalize window coordinates (width and height range [0, 100] */ coordInfoOut.m_windowSpaceInfo.m_xyz[0] = 100.0 * (coordInfoOut.m_windowSpaceInfo.m_pixelXYZ[0] / windowViewport[2]); coordInfoOut.m_windowSpaceInfo.m_xyz[1] = 100.0 * (coordInfoOut.m_windowSpaceInfo.m_pixelXYZ[1] / windowViewport[3]); coordInfoOut.m_windowSpaceInfo.m_xyz[2] = 0.0; } /** * Set the coordinates for the annotation. * * @param annotation * The annotation. * @param coordinateSpace * The coordinate space. * @parm coordInfoOne * Data for the first coordinate. * @parm coordInfoTwo * Data for the second coordinate. */ bool AnnotationCoordinateInformation::setAnnotationCoordinatesForSpace(Annotation* annotation, const AnnotationCoordinateSpaceEnum::Enum coordinateSpace, const AnnotationCoordinateInformation* coordInfoOne, const AnnotationCoordinateInformation* coordInfoTwo) { CaretAssert(annotation); bool validCoordinateFlag = false; AnnotationOneDimensionalShape* oneDimAnn = dynamic_cast(annotation); AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(annotation); if (oneDimAnn != NULL) { validCoordinateFlag = setOneDimAnnotationCoordinatesForSpace(oneDimAnn, coordinateSpace, coordInfoOne, coordInfoTwo); } else if (twoDimAnn != NULL) { validCoordinateFlag = setTwoDimAnnotationCoordinatesForSpace(twoDimAnn, coordinateSpace, coordInfoOne, coordInfoTwo); } return validCoordinateFlag; } /** * Set the coordinates for the one-dimensional annotation. * * @param annotation * The annotation. * @param coordinateSpace * The coordinate space. * @parm coordInfoOne * Data for the first coordinate. * @parm coordInfoTwo * Data for the second coordinate. */ bool AnnotationCoordinateInformation::setOneDimAnnotationCoordinatesForSpace(AnnotationOneDimensionalShape* annotation, const AnnotationCoordinateSpaceEnum::Enum coordinateSpace, const AnnotationCoordinateInformation* coordInfoOne, const AnnotationCoordinateInformation* coordInfoTwo) { bool validCoordinateFlag = false; CaretAssert(annotation); CaretAssert(coordInfoOne); AnnotationCoordinate* startCoordinate = annotation->getStartCoordinate(); CaretAssert(startCoordinate); AnnotationCoordinate* endCoordinate = annotation->getEndCoordinate(); CaretAssert(endCoordinate); switch (coordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: if (coordInfoOne->m_chartSpaceInfo.m_validFlag) { startCoordinate->setXYZ(coordInfoOne->m_chartSpaceInfo.m_xyz); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::CHART); validCoordinateFlag = true; if (coordInfoTwo != NULL) { if (coordInfoTwo->m_chartSpaceInfo.m_validFlag) { if (endCoordinate != NULL) { endCoordinate->setXYZ(coordInfoTwo->m_chartSpaceInfo.m_xyz); } } } } break; case AnnotationCoordinateSpaceEnum::SPACER: if (coordInfoOne->m_spacerTabSpaceInfo.m_spacerTabIndex.isValid()) { startCoordinate->setXYZ(coordInfoOne->m_spacerTabSpaceInfo.m_xyz); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::SPACER); annotation->setSpacerTabIndex(coordInfoOne->m_spacerTabSpaceInfo.m_spacerTabIndex); validCoordinateFlag = true; if (coordInfoTwo != NULL) { if (coordInfoTwo->m_spacerTabSpaceInfo.m_spacerTabIndex.isValid()) { if (endCoordinate != NULL) { endCoordinate->setXYZ(coordInfoTwo->m_spacerTabSpaceInfo.m_xyz); } } } else if (endCoordinate != NULL) { double xyz[3] = { coordInfoOne->m_spacerTabSpaceInfo.m_xyz[0], coordInfoOne->m_spacerTabSpaceInfo.m_xyz[1], coordInfoOne->m_spacerTabSpaceInfo.m_xyz[2] }; if (xyz[1] > 50.0) { xyz[1] -= 25.0; endCoordinate->setXYZ(xyz); } else { xyz[1] += 25.0; endCoordinate->setXYZ(coordInfoOne->m_spacerTabSpaceInfo.m_xyz); startCoordinate->setXYZ(xyz); } } } break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: if (coordInfoOne->m_modelSpaceInfo.m_validFlag) { startCoordinate->setXYZ(coordInfoOne->m_modelSpaceInfo.m_xyz); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::STEREOTAXIC); validCoordinateFlag = true; if (coordInfoTwo != NULL) { if (coordInfoTwo->m_modelSpaceInfo.m_validFlag) { if (endCoordinate != NULL) { endCoordinate->setXYZ(coordInfoTwo->m_modelSpaceInfo.m_xyz); } } } } break; case AnnotationCoordinateSpaceEnum::SURFACE: if (coordInfoOne->m_surfaceSpaceInfo.m_validFlag) { const float surfaceOffsetLength = startCoordinate->getSurfaceOffsetLength(); const AnnotationSurfaceOffsetVectorTypeEnum::Enum surfaceOffsetVector = startCoordinate->getSurfaceOffsetVectorType(); startCoordinate->setSurfaceSpace(coordInfoOne->m_surfaceSpaceInfo.m_structure, coordInfoOne->m_surfaceSpaceInfo.m_numberOfNodes, coordInfoOne->m_surfaceSpaceInfo.m_nodeIndex, surfaceOffsetLength, surfaceOffsetVector); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::SURFACE); validCoordinateFlag = true; if (coordInfoTwo != NULL) { if (coordInfoTwo->m_surfaceSpaceInfo.m_validFlag) { if (endCoordinate != NULL) { endCoordinate->setSurfaceSpace(coordInfoTwo->m_surfaceSpaceInfo.m_structure, coordInfoTwo->m_surfaceSpaceInfo.m_numberOfNodes, coordInfoTwo->m_surfaceSpaceInfo.m_nodeIndex, surfaceOffsetLength, surfaceOffsetVector); } } } } break; case AnnotationCoordinateSpaceEnum::TAB: if (coordInfoOne->m_tabSpaceInfo.m_index >= 0) { startCoordinate->setXYZ(coordInfoOne->m_tabSpaceInfo.m_xyz); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); annotation->setTabIndex(coordInfoOne->m_tabSpaceInfo.m_index); validCoordinateFlag = true; if (coordInfoTwo != NULL) { if (coordInfoTwo->m_tabSpaceInfo.m_index >= 0) { if (endCoordinate != NULL) { endCoordinate->setXYZ(coordInfoTwo->m_tabSpaceInfo.m_xyz); } } } else if (endCoordinate != NULL) { double xyz[3] = { coordInfoOne->m_tabSpaceInfo.m_xyz[0], coordInfoOne->m_tabSpaceInfo.m_xyz[1], coordInfoOne->m_tabSpaceInfo.m_xyz[2] }; if (xyz[1] > 50.0) { xyz[1] -= 25.0; endCoordinate->setXYZ(xyz); } else { xyz[1] += 25.0; endCoordinate->setXYZ(coordInfoOne->m_tabSpaceInfo.m_xyz); startCoordinate->setXYZ(xyz); } } } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: if (coordInfoOne->m_windowSpaceInfo.m_index >= 0) { startCoordinate->setXYZ(coordInfoOne->m_windowSpaceInfo.m_xyz); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::WINDOW); annotation->setWindowIndex(coordInfoOne->m_windowSpaceInfo.m_index); validCoordinateFlag = true; if (coordInfoTwo != NULL) { if (coordInfoTwo->m_windowSpaceInfo.m_index >= 0) { if (endCoordinate != NULL) { endCoordinate->setXYZ(coordInfoTwo->m_windowSpaceInfo.m_xyz); } } } else if (endCoordinate != NULL) { double xyz[3] = { coordInfoOne->m_windowSpaceInfo.m_xyz[0], coordInfoOne->m_windowSpaceInfo.m_xyz[1], coordInfoOne->m_windowSpaceInfo.m_xyz[2] }; if (xyz[1] > 50.0) { xyz[1] -= 25.0; endCoordinate->setXYZ(xyz); } else { xyz[1] += 25.0; endCoordinate->setXYZ(coordInfoOne->m_windowSpaceInfo.m_xyz); startCoordinate->setXYZ(xyz); } } } break; } return validCoordinateFlag; } /** * Set the coordinates for the two-dimensional annotation. * If both coordinates are valid (not NULL), the annotation is * placed at the average of the two coordinates. Otherwise, * the annotation is placed at the first coordinate. * * @param annotation * The annotation. * @param coordinateSpace * The coordinate space. * @parm coordInfoOne * Data for the first coordinate. * @parm optionalCoordInfoTwo * Data for the optional second coordinate. */ bool AnnotationCoordinateInformation::setTwoDimAnnotationCoordinatesForSpace(AnnotationTwoDimensionalShape* annotation, const AnnotationCoordinateSpaceEnum::Enum coordinateSpace, const AnnotationCoordinateInformation* coordInfoOne, const AnnotationCoordinateInformation* optionalCoordInfoTwo) { bool validCoordinateFlag = false; CaretAssert(annotation); CaretAssert(coordInfoOne); bool setWidthHeightWithTabCoordsFlag = false; bool setWidthHeightWithWindowCoordsFlag = false; AnnotationCoordinate* coordinate = annotation->getCoordinate(); switch (coordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: if (coordInfoOne->m_chartSpaceInfo.m_validFlag) { coordinate->setXYZ(coordInfoOne->m_chartSpaceInfo.m_xyz); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::CHART); validCoordinateFlag = true; if (optionalCoordInfoTwo != NULL) { if (optionalCoordInfoTwo->m_chartSpaceInfo.m_validFlag) { float centerXYZ[3] = { (float)(coordInfoOne->m_chartSpaceInfo.m_xyz[0] + optionalCoordInfoTwo->m_chartSpaceInfo.m_xyz[0]) / 2.0f, (float)(coordInfoOne->m_chartSpaceInfo.m_xyz[1] + optionalCoordInfoTwo->m_chartSpaceInfo.m_xyz[1]) / 2.0f, (float)(coordInfoOne->m_chartSpaceInfo.m_xyz[2] + optionalCoordInfoTwo->m_chartSpaceInfo.m_xyz[2]) / 2.0f }; coordinate->setXYZ(centerXYZ); setWidthHeightWithTabCoordsFlag = true; } } } break; case AnnotationCoordinateSpaceEnum::SPACER: if (coordInfoOne->m_spacerTabSpaceInfo.m_spacerTabIndex.isValid()) { coordinate->setXYZ(coordInfoOne->m_spacerTabSpaceInfo.m_xyz); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::SPACER); annotation->setSpacerTabIndex(coordInfoOne->m_spacerTabSpaceInfo.m_spacerTabIndex); validCoordinateFlag = true; if (optionalCoordInfoTwo != NULL) { if (optionalCoordInfoTwo->m_spacerTabSpaceInfo.m_spacerTabIndex.isValid() == coordInfoOne->m_spacerTabSpaceInfo.m_spacerTabIndex.isValid()) { float centerXYZ[3] = { (coordInfoOne->m_spacerTabSpaceInfo.m_xyz[0] + optionalCoordInfoTwo->m_spacerTabSpaceInfo.m_xyz[0]) / 2.0f, (coordInfoOne->m_spacerTabSpaceInfo.m_xyz[1] + optionalCoordInfoTwo->m_spacerTabSpaceInfo.m_xyz[1]) / 2.0f, (coordInfoOne->m_spacerTabSpaceInfo.m_xyz[2] + optionalCoordInfoTwo->m_spacerTabSpaceInfo.m_xyz[2]) / 2.0f }; coordinate->setXYZ(centerXYZ); setWidthHeightWithTabCoordsFlag = true; } } } break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: if (coordInfoOne->m_modelSpaceInfo.m_validFlag) { coordinate->setXYZ(coordInfoOne->m_modelSpaceInfo.m_xyz); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::STEREOTAXIC); validCoordinateFlag = true; if (optionalCoordInfoTwo != NULL) { if (optionalCoordInfoTwo->m_modelSpaceInfo.m_validFlag) { float centerXYZ[3] = { (float)(coordInfoOne->m_modelSpaceInfo.m_xyz[0] + optionalCoordInfoTwo->m_modelSpaceInfo.m_xyz[0]) / 2.0f, (float)(coordInfoOne->m_modelSpaceInfo.m_xyz[1] + optionalCoordInfoTwo->m_modelSpaceInfo.m_xyz[1]) / 2.0f, (float)(coordInfoOne->m_modelSpaceInfo.m_xyz[2] + optionalCoordInfoTwo->m_modelSpaceInfo.m_xyz[2]) / 2.0f }; coordinate->setXYZ(centerXYZ); setWidthHeightWithTabCoordsFlag = true; } } } break; case AnnotationCoordinateSpaceEnum::SURFACE: if (coordInfoOne->m_surfaceSpaceInfo.m_validFlag) { coordinate->setSurfaceSpace(coordInfoOne->m_surfaceSpaceInfo.m_structure, coordInfoOne->m_surfaceSpaceInfo.m_numberOfNodes, coordInfoOne->m_surfaceSpaceInfo.m_nodeIndex); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::SURFACE); annotation->initializeSurfaceSpaceWithTangentOffsetRotation(coordInfoOne->m_surfaceSpaceInfo.m_structure, coordInfoOne->m_surfaceSpaceInfo.m_nodeNormalVector); validCoordinateFlag = true; if (optionalCoordInfoTwo != NULL) { if ((optionalCoordInfoTwo->m_surfaceSpaceInfo.m_validFlag) && (optionalCoordInfoTwo->m_surfaceSpaceInfo.m_structure == coordInfoOne->m_surfaceSpaceInfo.m_structure )) { if ((optionalCoordInfoTwo->m_windowSpaceInfo.m_index == coordInfoOne->m_windowSpaceInfo.m_index) && (coordInfoOne->m_windowSpaceInfo.m_index >= 0)) { const float windowWidth = coordInfoOne->m_windowSpaceInfo.m_width; const float windowHeight = coordInfoOne->m_windowSpaceInfo.m_height; const float x1 = coordInfoOne->m_windowSpaceInfo.m_xyz[0] * windowWidth; const float y1 = coordInfoOne->m_windowSpaceInfo.m_xyz[1] * windowHeight; const float x2 = optionalCoordInfoTwo->m_windowSpaceInfo.m_xyz[0] * windowWidth; const float y2 = optionalCoordInfoTwo->m_windowSpaceInfo.m_xyz[1] * windowHeight; const int32_t windowX = static_cast((x1 + x2)) / 2.0; const int32_t windowY = static_cast((y1 + y2)) / 2.0; EventIdentificationRequest idRequest(coordInfoOne->m_windowSpaceInfo.m_index, static_cast(windowX), static_cast(windowY)); EventManager::get()->sendEvent(idRequest.getPointer()); SelectionManager* sm = idRequest.getSelectionManager(); if (sm != NULL) { const SelectionItemSurfaceNode* nodeID = sm->getSurfaceNodeIdentification(); CaretAssert(nodeID); if (nodeID->isValid()) { if (nodeID->getSurface()->getStructure() == coordInfoOne->m_surfaceSpaceInfo.m_structure) { coordinate->setSurfaceSpace(coordInfoOne->m_surfaceSpaceInfo.m_structure, coordInfoOne->m_surfaceSpaceInfo.m_numberOfNodes, nodeID->getNodeNumber()); setWidthHeightWithTabCoordsFlag = true; } } } } } } } break; case AnnotationCoordinateSpaceEnum::TAB: if (coordInfoOne->m_tabSpaceInfo.m_index >= 0) { coordinate->setXYZ(coordInfoOne->m_tabSpaceInfo.m_xyz); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); annotation->setTabIndex(coordInfoOne->m_tabSpaceInfo.m_index); validCoordinateFlag = true; if (optionalCoordInfoTwo != NULL) { if (optionalCoordInfoTwo->m_tabSpaceInfo.m_index == coordInfoOne->m_tabSpaceInfo.m_index) { float centerXYZ[3] = { (coordInfoOne->m_tabSpaceInfo.m_xyz[0] + optionalCoordInfoTwo->m_tabSpaceInfo.m_xyz[0]) / 2.0f, (coordInfoOne->m_tabSpaceInfo.m_xyz[1] + optionalCoordInfoTwo->m_tabSpaceInfo.m_xyz[1]) / 2.0f, (coordInfoOne->m_tabSpaceInfo.m_xyz[2] + optionalCoordInfoTwo->m_tabSpaceInfo.m_xyz[2]) / 2.0f }; coordinate->setXYZ(centerXYZ); setWidthHeightWithTabCoordsFlag = true; } } } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: if (coordInfoOne->m_windowSpaceInfo.m_index >= 0) { coordinate->setXYZ(coordInfoOne->m_windowSpaceInfo.m_xyz); annotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::WINDOW); annotation->setWindowIndex(coordInfoOne->m_windowSpaceInfo.m_index); validCoordinateFlag = true; if (optionalCoordInfoTwo != NULL) { if (optionalCoordInfoTwo->m_windowSpaceInfo.m_index == coordInfoOne->m_windowSpaceInfo.m_index) { float centerXYZ[3] = { (coordInfoOne->m_windowSpaceInfo.m_xyz[0] + optionalCoordInfoTwo->m_windowSpaceInfo.m_xyz[0]) / 2.0f, (coordInfoOne->m_windowSpaceInfo.m_xyz[1] + optionalCoordInfoTwo->m_windowSpaceInfo.m_xyz[1]) / 2.0f, (coordInfoOne->m_windowSpaceInfo.m_xyz[2] + optionalCoordInfoTwo->m_windowSpaceInfo.m_xyz[2]) / 2.0f }; coordinate->setXYZ(centerXYZ); setWidthHeightWithWindowCoordsFlag = true; } } } break; } if (setWidthHeightWithTabCoordsFlag) { if (coordInfoOne->m_tabSpaceInfo.m_index >= 0) { if (optionalCoordInfoTwo != NULL) { if (coordInfoOne->m_tabSpaceInfo.m_index == optionalCoordInfoTwo->m_tabSpaceInfo.m_index) { annotation->setWidthAndHeightFromBounds(coordInfoOne->m_tabSpaceInfo.m_xyz, optionalCoordInfoTwo->m_tabSpaceInfo.m_xyz, coordInfoOne->m_tabSpaceInfo.m_width, coordInfoOne->m_tabSpaceInfo.m_height); } } } } else if (setWidthHeightWithWindowCoordsFlag) { if (coordInfoOne->m_windowSpaceInfo.m_index >= 0) { if (optionalCoordInfoTwo != NULL) { if (coordInfoOne->m_windowSpaceInfo.m_index == optionalCoordInfoTwo->m_windowSpaceInfo.m_index) { const float windowWidth = coordInfoOne->m_windowSpaceInfo.m_width; const float windowHeight = coordInfoOne->m_windowSpaceInfo.m_height; const float oneXYZ[3] = { coordInfoOne->m_windowSpaceInfo.m_xyz[0], coordInfoOne->m_windowSpaceInfo.m_xyz[1], coordInfoOne->m_windowSpaceInfo.m_xyz[2] }; const float twoXYZ[3] = { optionalCoordInfoTwo->m_windowSpaceInfo.m_xyz[0], optionalCoordInfoTwo->m_windowSpaceInfo.m_xyz[1], optionalCoordInfoTwo->m_windowSpaceInfo.m_xyz[2] }; annotation->setWidthAndHeightFromBounds(oneXYZ, twoXYZ, windowWidth, windowHeight); } } } } return validCoordinateFlag; } connectome-workbench-1.4.2/src/GuiQt/AnnotationCoordinateInformation.h000066400000000000000000000144721360521144700261640ustar00rootroot00000000000000#ifndef __ANNOTATION_COORDINATE_INFORMATION_H__ #define __ANNOTATION_COORDINATE_INFORMATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationCoordinateSpaceEnum.h" #include "AnnotationSurfaceOffsetVectorTypeEnum.h" #include "SpacerTabIndex.h" #include "StructureEnum.h" class QLabel; namespace caret { class Annotation; class AnnotationOneDimensionalShape; class AnnotationTwoDimensionalShape; class BrainOpenGLWidget; class BrainOpenGLViewportContent; class MouseEvent; class AnnotationCoordinateInformation { public: AnnotationCoordinateInformation(); virtual ~AnnotationCoordinateInformation(); bool isCoordinateSpaceValid(const AnnotationCoordinateSpaceEnum::Enum space) const; void reset(); static void getValidCoordinateSpaces(const AnnotationCoordinateInformation* coordInfoOne, const AnnotationCoordinateInformation* coordInfoTwo, std::vector& spacesOut); static void createCoordinateInformationFromXY(const MouseEvent& mouseEvent, AnnotationCoordinateInformation& coordInfoOut); static void createCoordinateInformationFromXY(const MouseEvent& mouseEvent, const int32_t windowX, const int32_t windowY, AnnotationCoordinateInformation& coordInfoOut); static void createCoordinateInformationFromXY(BrainOpenGLWidget* openGLWidget, BrainOpenGLViewportContent* viewportContent, const int32_t windowX, const int32_t windowY, AnnotationCoordinateInformation& coordInfoOut); static bool setAnnotationCoordinatesForSpace(Annotation* annotation, const AnnotationCoordinateSpaceEnum::Enum space, const AnnotationCoordinateInformation* coordInfoOne, const AnnotationCoordinateInformation* coordInfoTwo); class SpaceInfo { public: bool m_validFlag = false; }; class ModelSpaceInfo : public SpaceInfo { public: double m_xyz[3] = { 0.0, 0.0, 0.0 }; }; class TabWindowSpaceInfo : public SpaceInfo { public: float m_width = 0.0f; float m_height = 0.0f; float m_xyz[3] = { 0.0f, 0.0f, 0.0f }; float m_pixelXYZ[3] = { 0.0f, 0.0f, 0.0f }; int32_t m_index = -1; }; class SpacerTabSpaceInfo : public SpaceInfo { public: float m_width = 0.0f; float m_height = 0.0f; float m_xyz[3] = { 0.0f, 0.0f, 0.0f }; float m_pixelXYZ[3] = { 0.0f, 0.0f, 0.0f }; SpacerTabIndex m_spacerTabIndex; }; class ChartSpaceInfo : public SpaceInfo { public: float m_xyz[3] = { 0.0f, 0.0f, 0.0f }; }; class SurfaceSpaceInfo : public SpaceInfo { public: StructureEnum::Enum m_structure = StructureEnum::INVALID; int32_t m_numberOfNodes = 0; int32_t m_nodeIndex = -1; float m_nodeOffsetLength = 0.0f; float m_nodeNormalVector[3] = { 0.0f, 0.0f, 1.0f }; AnnotationSurfaceOffsetVectorTypeEnum::Enum m_nodeVectorOffsetType = AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX; }; ModelSpaceInfo m_modelSpaceInfo; TabWindowSpaceInfo m_tabSpaceInfo; TabWindowSpaceInfo m_windowSpaceInfo; SpacerTabSpaceInfo m_spacerTabSpaceInfo; ChartSpaceInfo m_chartSpaceInfo; SurfaceSpaceInfo m_surfaceSpaceInfo; private: AnnotationCoordinateInformation(const AnnotationCoordinateInformation&); AnnotationCoordinateInformation& operator=(const AnnotationCoordinateInformation&); static bool setOneDimAnnotationCoordinatesForSpace(AnnotationOneDimensionalShape* annotation, const AnnotationCoordinateSpaceEnum::Enum space, const AnnotationCoordinateInformation* coordInfoOne, const AnnotationCoordinateInformation* coordInfoTwo); static bool setTwoDimAnnotationCoordinatesForSpace(AnnotationTwoDimensionalShape* annotation, const AnnotationCoordinateSpaceEnum::Enum space, const AnnotationCoordinateInformation* coordInfoOne, const AnnotationCoordinateInformation* coordInfoTwo); // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_COORDINATE_INFORMATION_DECLARE__ // #endif // __ANNOTATION_COORDINATE_INFORMATION_DECLARE__ } // namespace #endif //__ANNOTATION_COORDINATE_INFORMATION_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx000066400000000000000000001132101360521144700273310ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_COORDINATE_SELECTION_WIDGET_DECLARE__ #include "AnnotationCoordinateSelectionWidget.h" #undef __ANNOTATION_COORDINATE_SELECTION_WIDGET_DECLARE__ #include #include #include #include #include #include #include "Annotation.h" #include "AnnotationCoordinate.h" #include "AnnotationCoordinateInformation.h" #include "AnnotationImage.h" #include "AnnotationManager.h" #include "AnnotationOneDimensionalShape.h" #include "AnnotationPercentSizeText.h" #include "AnnotationRedoUndoCommand.h" #include "AnnotationTwoDimensionalShape.h" #include "Brain.h" #include "BrainStructure.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "DisplayPropertiesAnnotation.h" #include "EventIdentificationRequest.h" #include "GuiManager.h" #include "MathFunctions.h" #include "SelectionItemSurfaceNode.h" #include "SelectionManager.h" #include "Surface.h" #include "WuQMessageBox.h" using namespace caret; /** * \class caret::AnnotationCoordinateSelectionWidget * \brief Widget for selection of an annotation coordinate. * \ingroup GuiQt */ /** * Constructor. * * @param annotationType * Type of annotation that is being created. * @param coordInfo * Coordinate information. * @param optionalSecondCoordInfo * Optional second coordinate information (valid if not NULL) * @param parent * The parent widget. */ AnnotationCoordinateSelectionWidget::AnnotationCoordinateSelectionWidget(const AnnotationTypeEnum::Enum annotationType, const AnnotationCoordinateInformation& coordInfo, const AnnotationCoordinateInformation* optionalSecondCoordInfo, QWidget* parent) : QWidget(parent), m_annotationType(annotationType), m_coordInfo(coordInfo), m_optionalSecondCoordInfo(optionalSecondCoordInfo) { bool enableChartSpaceFlag = false; bool enableModelSpaceFlag = false; bool enableSurfaceSpaceFlag = false; bool enableTabSpaceFlag = true; bool enableWindowSpaceFlag = true; switch (m_annotationType) { case AnnotationTypeEnum::BOX: enableChartSpaceFlag = true; enableModelSpaceFlag = true; enableSurfaceSpaceFlag = true; break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: enableChartSpaceFlag = true; enableModelSpaceFlag = true; enableSurfaceSpaceFlag = true; break; case AnnotationTypeEnum::LINE: enableChartSpaceFlag = true; enableModelSpaceFlag = true; enableSurfaceSpaceFlag = true; break; case AnnotationTypeEnum::OVAL: enableChartSpaceFlag = true; enableModelSpaceFlag = true; enableSurfaceSpaceFlag = true; break; case AnnotationTypeEnum::TEXT: enableChartSpaceFlag = true; enableModelSpaceFlag = true; enableSurfaceSpaceFlag = true; break; } m_spaceButtonGroup = new QButtonGroup(this); int columnIndex = 0; const int COLUMN_RADIO_BUTTON = columnIndex++; const int COLUMN_COORD_X = columnIndex++; const int COLUMN_COORD_Y = columnIndex++; const int COLUMN_COORD_Z = columnIndex++; const int COLUMN_COORD_TWO_X = columnIndex++; const int COLUMN_COORD_TWO_Y = columnIndex++; const int COLUMN_COORD_TWO_Z = columnIndex++; const int COLUMN_EXTRA = columnIndex++; QGridLayout* gridLayout = new QGridLayout(this); gridLayout->setColumnStretch(COLUMN_RADIO_BUTTON, 0); gridLayout->setColumnStretch(COLUMN_COORD_X, 0); gridLayout->setColumnStretch(COLUMN_COORD_Y, 0); gridLayout->setColumnStretch(COLUMN_COORD_Z, 0); gridLayout->setColumnStretch(COLUMN_EXTRA, 100); const int titleRow = gridLayout->rowCount(); gridLayout->addWidget(new QLabel("Space"), titleRow, COLUMN_RADIO_BUTTON, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("X"), titleRow, COLUMN_COORD_X, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Y"), titleRow, COLUMN_COORD_Y, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Z"), titleRow, COLUMN_COORD_Z, Qt::AlignHCenter); if (m_optionalSecondCoordInfo != NULL) { gridLayout->addWidget(new QLabel("X2"), titleRow, COLUMN_COORD_TWO_X, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Y2"), titleRow, COLUMN_COORD_TWO_Y, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Z2"), titleRow, COLUMN_COORD_TWO_Z, Qt::AlignHCenter); } if (enableTabSpaceFlag) { if (m_coordInfo.m_tabSpaceInfo.m_index < 0) { enableTabSpaceFlag = false; } if (m_optionalSecondCoordInfo != NULL) { if (m_optionalSecondCoordInfo->m_tabSpaceInfo.m_index < 0) { enableTabSpaceFlag = false; } } } if (enableChartSpaceFlag) { if ( ! m_coordInfo.m_chartSpaceInfo.m_validFlag) { enableChartSpaceFlag = false; } if (m_optionalSecondCoordInfo != NULL) { if ( ! m_optionalSecondCoordInfo->m_chartSpaceInfo.m_validFlag) { enableChartSpaceFlag = false; } /* * Only allow chart space for two coordinates in the SAME tab. * If tab space is not enabled, then the two chart coordinates are * in different tabs. */ if ( ! enableTabSpaceFlag) { enableChartSpaceFlag = false; } } } if (enableChartSpaceFlag) { QRadioButton* rb = createRadioButtonForSpace(AnnotationCoordinateSpaceEnum::CHART); m_spaceButtonGroup->addButton(rb, AnnotationCoordinateSpaceEnum::toIntegerCode(AnnotationCoordinateSpaceEnum::CHART)); const int rowNum = gridLayout->rowCount(); gridLayout->addWidget(rb, rowNum, COLUMN_RADIO_BUTTON); gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_chartSpaceInfo.m_xyz[0], 'f', 1)), rowNum, COLUMN_COORD_X, Qt::AlignRight); gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_chartSpaceInfo.m_xyz[1], 'f', 1)), rowNum, COLUMN_COORD_Y, Qt::AlignRight); gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_chartSpaceInfo.m_xyz[2], 'f', 1)), rowNum, COLUMN_COORD_Z, Qt::AlignRight); if (m_optionalSecondCoordInfo != NULL) { gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_chartSpaceInfo.m_xyz[0], 'f', 1)), rowNum, COLUMN_COORD_TWO_X, Qt::AlignRight); gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_chartSpaceInfo.m_xyz[1], 'f', 1)), rowNum, COLUMN_COORD_TWO_Y, Qt::AlignRight); gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_chartSpaceInfo.m_xyz[2], 'f', 1)), rowNum, COLUMN_COORD_TWO_Z, Qt::AlignRight); } } if (enableModelSpaceFlag) { if ( ! m_coordInfo.m_modelSpaceInfo.m_validFlag) { enableModelSpaceFlag = false; } if (m_optionalSecondCoordInfo != NULL) { if ( ! m_optionalSecondCoordInfo->m_modelSpaceInfo.m_validFlag) { enableModelSpaceFlag = false; } /* * Only allow model space for two coordinates in the SAME tab. * If tab space is not enabled, then the two model coordinates are * in different tabs. */ if ( ! enableTabSpaceFlag) { enableModelSpaceFlag = false; } } } if (enableModelSpaceFlag) { QRadioButton* rb = createRadioButtonForSpace(AnnotationCoordinateSpaceEnum::STEREOTAXIC); m_spaceButtonGroup->addButton(rb, AnnotationCoordinateSpaceEnum::toIntegerCode(AnnotationCoordinateSpaceEnum::STEREOTAXIC)); const int rowNum = gridLayout->rowCount(); gridLayout->addWidget(rb, rowNum, COLUMN_RADIO_BUTTON); gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_modelSpaceInfo.m_xyz[0], 'f', 1)), rowNum, COLUMN_COORD_X, Qt::AlignRight); gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_modelSpaceInfo.m_xyz[1], 'f', 1)), rowNum, COLUMN_COORD_Y, Qt::AlignRight); gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_modelSpaceInfo.m_xyz[2], 'f', 1)), rowNum, COLUMN_COORD_Z, Qt::AlignRight); if (m_optionalSecondCoordInfo != NULL) { gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_modelSpaceInfo.m_xyz[0], 'f', 1)), rowNum, COLUMN_COORD_TWO_X, Qt::AlignRight); gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_modelSpaceInfo.m_xyz[1], 'f', 1)), rowNum, COLUMN_COORD_TWO_Y, Qt::AlignRight); gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_modelSpaceInfo.m_xyz[2], 'f', 1)), rowNum, COLUMN_COORD_TWO_Z, Qt::AlignRight); } } if (enableTabSpaceFlag) { QRadioButton* rb = createRadioButtonForSpace(AnnotationCoordinateSpaceEnum::TAB); rb->setText(rb->text() + " " + AString::number(m_coordInfo.m_tabSpaceInfo.m_index + 1)); m_spaceButtonGroup->addButton(rb, AnnotationCoordinateSpaceEnum::toIntegerCode(AnnotationCoordinateSpaceEnum::TAB)); const int rowNum = gridLayout->rowCount(); gridLayout->addWidget(rb, rowNum, COLUMN_RADIO_BUTTON); gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_tabSpaceInfo.m_xyz[0], 'f', 1)), rowNum, COLUMN_COORD_X, Qt::AlignRight); gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_tabSpaceInfo.m_xyz[1], 'f', 1)), rowNum, COLUMN_COORD_Y, Qt::AlignRight); gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_tabSpaceInfo.m_xyz[2], 'f', 1)), rowNum, COLUMN_COORD_Z, Qt::AlignRight); if (m_optionalSecondCoordInfo != NULL) { gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_tabSpaceInfo.m_xyz[0], 'f', 1)), rowNum, COLUMN_COORD_TWO_X, Qt::AlignRight); gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_tabSpaceInfo.m_xyz[1], 'f', 1)), rowNum, COLUMN_COORD_TWO_Y, Qt::AlignRight); gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_tabSpaceInfo.m_xyz[2], 'f', 1)), rowNum, COLUMN_COORD_TWO_Z, Qt::AlignRight); } } if (enableWindowSpaceFlag) { if (m_coordInfo.m_windowSpaceInfo.m_index < 0) { enableWindowSpaceFlag = false; } if (m_optionalSecondCoordInfo != NULL) { if (m_optionalSecondCoordInfo->m_windowSpaceInfo.m_index < 0) { enableWindowSpaceFlag = false; } } } if (enableWindowSpaceFlag) { QRadioButton* rb = createRadioButtonForSpace(AnnotationCoordinateSpaceEnum::WINDOW); rb->setText(rb->text() + " " + AString::number(m_coordInfo.m_windowSpaceInfo.m_index + 1)); m_spaceButtonGroup->addButton(rb, AnnotationCoordinateSpaceEnum::toIntegerCode(AnnotationCoordinateSpaceEnum::WINDOW)); const int rowNum = gridLayout->rowCount(); gridLayout->addWidget(rb, rowNum, COLUMN_RADIO_BUTTON); gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_windowSpaceInfo.m_xyz[0], 'f', 1)), rowNum, COLUMN_COORD_X, Qt::AlignRight); gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_windowSpaceInfo.m_xyz[1], 'f', 1)), rowNum, COLUMN_COORD_Y, Qt::AlignRight); gridLayout->addWidget(new QLabel(AString::number(m_coordInfo.m_windowSpaceInfo.m_xyz[2], 'f', 1)), rowNum, COLUMN_COORD_Z, Qt::AlignRight); if (m_optionalSecondCoordInfo != NULL) { gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_windowSpaceInfo.m_xyz[0], 'f', 1)), rowNum, COLUMN_COORD_TWO_X, Qt::AlignRight); gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_windowSpaceInfo.m_xyz[1], 'f', 1)), rowNum, COLUMN_COORD_TWO_Y, Qt::AlignRight); gridLayout->addWidget(new QLabel(AString::number(m_optionalSecondCoordInfo->m_windowSpaceInfo.m_xyz[2], 'f', 1)), rowNum, COLUMN_COORD_TWO_Z, Qt::AlignRight); } } if (enableSurfaceSpaceFlag) { if ( ! m_coordInfo.m_surfaceSpaceInfo.m_validFlag) { enableSurfaceSpaceFlag = false; } if (m_optionalSecondCoordInfo != NULL) { if ( ! m_optionalSecondCoordInfo->m_surfaceSpaceInfo.m_validFlag) { enableSurfaceSpaceFlag = false; } } /* * Only allow surface space for two coordinates in the SAME tab. * If tab space is not enabled, then the two surface coordinates are * in different tabs. */ if ( ! enableTabSpaceFlag) { enableSurfaceSpaceFlag = false; } } if (enableSurfaceSpaceFlag) { QRadioButton* rb = createRadioButtonForSpace(AnnotationCoordinateSpaceEnum::SURFACE); m_spaceButtonGroup->addButton(rb, AnnotationCoordinateSpaceEnum::toIntegerCode(AnnotationCoordinateSpaceEnum::SURFACE)); const int rowNum = gridLayout->rowCount(); gridLayout->addWidget(rb, rowNum, COLUMN_RADIO_BUTTON); const AString infoText(StructureEnum::toGuiName(m_coordInfo.m_surfaceSpaceInfo.m_structure) + " Vertex: " +AString::number(m_coordInfo.m_surfaceSpaceInfo.m_nodeIndex)); gridLayout->addWidget(new QLabel(infoText), rowNum, COLUMN_COORD_X, 1, 4); if (m_optionalSecondCoordInfo != NULL) { const int rowNum = gridLayout->rowCount(); const AString infoText(StructureEnum::toGuiName(m_optionalSecondCoordInfo->m_surfaceSpaceInfo.m_structure) + " Vertex 2: " +AString::number(m_optionalSecondCoordInfo->m_surfaceSpaceInfo.m_nodeIndex)); gridLayout->addWidget(new QLabel(infoText), rowNum, COLUMN_COORD_X, 1, 4); } } /* * This switch statment does nothing. But, if a new space is added * the missing enumerated value in the switch statement will cause a * compilation error which may indicate the code in this method * needs to be updated. */ AnnotationCoordinateSpaceEnum::Enum space = AnnotationCoordinateSpaceEnum::TAB; switch (space) { case AnnotationCoordinateSpaceEnum::CHART: case AnnotationCoordinateSpaceEnum::SPACER: case AnnotationCoordinateSpaceEnum::STEREOTAXIC: case AnnotationCoordinateSpaceEnum::SURFACE: case AnnotationCoordinateSpaceEnum::TAB: case AnnotationCoordinateSpaceEnum::WINDOW: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; } setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } /** * Destructor. */ AnnotationCoordinateSelectionWidget::~AnnotationCoordinateSelectionWidget() { } /** * Create a radio button that displays the text for and contains the * enumerated value in a property. * * @param space * Coordinate space for button. */ QRadioButton* AnnotationCoordinateSelectionWidget::createRadioButtonForSpace(const AnnotationCoordinateSpaceEnum::Enum space) { const QString spaceGuiName = AnnotationCoordinateSpaceEnum::toGuiName(space); const QString spaceEnumName = AnnotationCoordinateSpaceEnum::toName(space); QRadioButton* rb = new QRadioButton(spaceGuiName); rb->setProperty(s_SPACE_PROPERTY_NAME.toLatin1().constData(), spaceEnumName); return rb; } /** * Select the given coordinate space. * * @param coordSpace * The coordinate space. */ void AnnotationCoordinateSelectionWidget::selectCoordinateSpace(const AnnotationCoordinateSpaceEnum::Enum coordSpace) { QList buttons = m_spaceButtonGroup->buttons(); QListIterator buttList(buttons); while (buttList.hasNext()) { QAbstractButton* button = buttList.next(); CaretAssert(button); const int32_t buttonID = m_spaceButtonGroup->id(button); bool valid = false; const AnnotationCoordinateSpaceEnum::Enum buttSpace = AnnotationCoordinateSpaceEnum::fromIntegerCode(buttonID, &valid); if (valid) { if (buttSpace == coordSpace) { button->setChecked(true); break; } } else { CaretLogSevere("Invalid integer code for annotation coordinate space=" + QString::number(buttonID)); } } } /** * Get the selected annotation coordinate space. * * @param validOut * True if user has selected a coordinate space, else false. * @return * Coordinate space selected by the user (valid if validOut is true). */ AnnotationCoordinateSpaceEnum::Enum AnnotationCoordinateSelectionWidget::getSelectedCoordinateSpace(bool& validOut) const { validOut = false; AnnotationCoordinateSpaceEnum::Enum space = AnnotationCoordinateSpaceEnum::VIEWPORT; QAbstractButton* button = m_spaceButtonGroup->checkedButton(); if (button == NULL) { return space; } CaretAssert(button); const int32_t buttonID = m_spaceButtonGroup->id(button); space = AnnotationCoordinateSpaceEnum::fromIntegerCode(buttonID, &validOut); return space; } /** * Set the coordinate with the current space selection. * * @param annotation * Annotation whose coordinates are changed. * @param errorMessageOut * Contains error information. * @return * True if successful, else false. */ bool AnnotationCoordinateSelectionWidget::changeAnnotationCoordinate(Annotation* annotation, QString& errorMessageOut) { CaretAssert(annotation); errorMessageOut.clear(); bool valid = false; const AnnotationCoordinateSpaceEnum::Enum newSpace = getSelectedCoordinateSpace(valid); if ( ! valid) { errorMessageOut = ("A coordinate space has not been selected."); return false; } CaretPointer redoAnnotation(annotation->clone()); AnnotationOneDimensionalShape* oneDimShape = dynamic_cast(redoAnnotation.getPointer()); AnnotationTwoDimensionalShape* twoDimShape = dynamic_cast(redoAnnotation.getPointer()); AnnotationCoordinate* coordinate = NULL; AnnotationCoordinate* otherCoordinate = NULL; if (oneDimShape != NULL) { coordinate = oneDimShape->getStartCoordinate(); otherCoordinate = oneDimShape->getEndCoordinate(); } else { coordinate = twoDimShape->getCoordinate(); } const AnnotationCoordinateSpaceEnum::Enum oldSpace = redoAnnotation->getCoordinateSpace(); float oldViewportHeight = 0.0; switch (oldSpace) { case AnnotationCoordinateSpaceEnum::CHART: oldViewportHeight = m_coordInfo.m_tabSpaceInfo.m_height; break; case AnnotationCoordinateSpaceEnum::SPACER: oldViewportHeight = m_coordInfo.m_spacerTabSpaceInfo.m_height; break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: oldViewportHeight = m_coordInfo.m_tabSpaceInfo.m_height; break; case AnnotationCoordinateSpaceEnum::SURFACE: oldViewportHeight = m_coordInfo.m_tabSpaceInfo.m_height; break; case AnnotationCoordinateSpaceEnum::TAB: oldViewportHeight = m_coordInfo.m_tabSpaceInfo.m_height; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: oldViewportHeight = m_coordInfo.m_windowSpaceInfo.m_height; break; } /* * If annotation has two coordinates, get the difference of the two coordinates * that will be used if the user changes the coordinate space. This results * in the annotation retaining its relative locations in the new space */ float diffXyz[3] = { 0.0, 0.0, 0.0 }; bool diffXyzValid = false; if ((oneDimShape != NULL) && (otherCoordinate != NULL)) { float xyz[3]; coordinate->getXYZ(xyz); float otherXyz[3]; otherCoordinate->getXYZ(otherXyz); switch (oldSpace) { case AnnotationCoordinateSpaceEnum::CHART: diffXyzValid = true; break; case AnnotationCoordinateSpaceEnum::SPACER: diffXyzValid = true; break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: diffXyzValid = true; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: diffXyzValid = true; break; } if (diffXyzValid) { diffXyz[0] = otherXyz[0] - xyz[0]; diffXyz[1] = otherXyz[1] - xyz[1]; diffXyz[2] = otherXyz[2] - xyz[2]; } } float newViewportHeight = 0.0; bool setOtherCoordinateFlag = false; switch (newSpace) { case AnnotationCoordinateSpaceEnum::CHART: if (m_coordInfo.m_chartSpaceInfo.m_validFlag) { coordinate->setXYZ(m_coordInfo.m_chartSpaceInfo.m_xyz); redoAnnotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::CHART); newViewportHeight = m_coordInfo.m_tabSpaceInfo.m_height; } break; case AnnotationCoordinateSpaceEnum::SPACER: if (m_coordInfo.m_spacerTabSpaceInfo.m_spacerTabIndex.isValid()) { coordinate->setXYZ(m_coordInfo.m_spacerTabSpaceInfo.m_xyz); redoAnnotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::SPACER); newViewportHeight = m_coordInfo.m_spacerTabSpaceInfo.m_height; } break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: if (m_coordInfo.m_modelSpaceInfo.m_validFlag) { coordinate->setXYZ(m_coordInfo.m_modelSpaceInfo.m_xyz); redoAnnotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::STEREOTAXIC); newViewportHeight = m_coordInfo.m_tabSpaceInfo.m_height; } break; case AnnotationCoordinateSpaceEnum::SURFACE: if (m_coordInfo.m_surfaceSpaceInfo.m_validFlag) { coordinate->setSurfaceSpace(m_coordInfo.m_surfaceSpaceInfo.m_structure, m_coordInfo.m_surfaceSpaceInfo.m_numberOfNodes, m_coordInfo.m_surfaceSpaceInfo.m_nodeIndex); redoAnnotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::SURFACE); newViewportHeight = m_coordInfo.m_tabSpaceInfo.m_height; } break; case AnnotationCoordinateSpaceEnum::TAB: if (m_coordInfo.m_tabSpaceInfo.m_index >= 0) { const int32_t oldTabIndex = redoAnnotation->getTabIndex(); const int32_t newTabIndex = m_coordInfo.m_tabSpaceInfo.m_index; coordinate->setXYZ(m_coordInfo.m_tabSpaceInfo.m_xyz); redoAnnotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::TAB); redoAnnotation->setTabIndex(newTabIndex); /* * Will need to move 'other' coordinate since it may not * be within the new tab's region. */ if (otherCoordinate != NULL) { if ((newSpace != oldSpace) || (newTabIndex != oldTabIndex)) { setOtherCoordinateFlag = true; } } newViewportHeight = m_coordInfo.m_tabSpaceInfo.m_height; } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: if (m_coordInfo.m_windowSpaceInfo.m_index >= 0) { const int32_t oldWindowIndex = redoAnnotation->getWindowIndex(); const int32_t newWindowIndex = m_coordInfo.m_windowSpaceInfo.m_index; coordinate->setXYZ(m_coordInfo.m_windowSpaceInfo.m_xyz); redoAnnotation->setCoordinateSpace(AnnotationCoordinateSpaceEnum::WINDOW); redoAnnotation->setWindowIndex(newWindowIndex); /* * VERIFY * Will need to move 'other' coordinate since it may not * be within the new windows's region. */ if (otherCoordinate != NULL) { if ((newSpace != oldSpace) || (newWindowIndex != oldWindowIndex)) { setOtherCoordinateFlag = true; } } newViewportHeight = m_coordInfo.m_windowSpaceInfo.m_height; } break; } /* * If the space changes, the 'other' coordinate will need to be moved. * For example, if the */ if (setOtherCoordinateFlag) { float xyz[3]; coordinate->getXYZ(xyz); if (diffXyzValid) { xyz[0] += diffXyz[0]; xyz[1] += diffXyz[1]; xyz[2] += diffXyz[2]; xyz[0] = MathFunctions::clamp(xyz[0], 1.0, 99.0); xyz[1] = MathFunctions::clamp(xyz[1], 1.0, 99.0); xyz[2] = MathFunctions::clamp(xyz[2], 1.0, 99.0); } else { if (xyz[1] > 50.0) { xyz[1] -= 25.0; } else { xyz[1] += 25.0; } } otherCoordinate->setXYZ(xyz); } /* * Height of text is based upon viewport height. If the viewport changes, * scale the text so that it maintains the same physical (pixel) height. */ if ((newViewportHeight > 0.0) && (oldViewportHeight > 0.0)) { const float scale = oldViewportHeight / newViewportHeight; std::cout << "Scale is: " << scale << std::endl; AnnotationPercentSizeText* textAnn = dynamic_cast(redoAnnotation.getPointer()); if (textAnn != NULL) { float percentSize = textAnn->getFontPercentViewportSize(); percentSize *= scale; textAnn->setFontPercentViewportSize(percentSize); } } std::vector annotationsBeforeMoveAndResize; annotationsBeforeMoveAndResize.push_back(annotation); std::vector annotationsAfterMoveAndResize; annotationsAfterMoveAndResize.push_back(redoAnnotation); AnnotationRedoUndoCommand* command = new AnnotationRedoUndoCommand(); command->setModeLocationAndSize(annotationsBeforeMoveAndResize, annotationsAfterMoveAndResize); command->setDescription("Change Coordinate"); AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annotationManager->applyCommand(command, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } updateAnnotationDisplayProperties(redoAnnotation); return true; } /** * Set the coordinate with the current space selection. * * @param coordinate * Coordinate that is set. * @param errorMessageOut * Contains error information. * @return * True if successful, else false. */ bool AnnotationCoordinateSelectionWidget::setCoordinateForNewAnnotation(Annotation* annotation, QString& errorMessageOut) { errorMessageOut.clear(); bool valid = false; const AnnotationCoordinateSpaceEnum::Enum coordinateSpace = getSelectedCoordinateSpace(valid); if ( ! valid) { errorMessageOut = ("A coordinate space has not been selected."); return false; } AnnotationOneDimensionalShape* oneDimAnn = dynamic_cast(annotation); AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(annotation); bool validCoordsFlag = false; if (oneDimAnn != NULL) { validCoordsFlag = AnnotationCoordinateInformation::setAnnotationCoordinatesForSpace(oneDimAnn, coordinateSpace, &m_coordInfo, m_optionalSecondCoordInfo); } else if (twoDimAnn != NULL) { validCoordsFlag = AnnotationCoordinateInformation::setAnnotationCoordinatesForSpace(twoDimAnn, coordinateSpace, &m_coordInfo, m_optionalSecondCoordInfo); } else { const QString msg("PROGRAM ERROR: Annotation is neither one nor two dimensional"); CaretAssertMessage(0, msg); CaretLogSevere(msg); errorMessageOut = msg; return false; } if ( ! validCoordsFlag) { errorMessageOut = "Failed to set coordinates for annotatin."; } updateAnnotationDisplayProperties(annotation); AnnotationImage* imageAnn = dynamic_cast(twoDimAnn); if (imageAnn != NULL) { setWidthAndHeightForImage(imageAnn); } return validCoordsFlag; } /** * Set the width and height of the annotation using the viewport. * * @param imageAnn * The annotation image. */ void AnnotationCoordinateSelectionWidget::setWidthAndHeightForImage(AnnotationImage* imageAnn) { CaretAssert(imageAnn); float vpWidth = 0.0; float vpHeight = 0.0; switch (imageAnn->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: vpWidth = m_coordInfo.m_tabSpaceInfo.m_width; vpHeight = m_coordInfo.m_tabSpaceInfo.m_height; break; case AnnotationCoordinateSpaceEnum::SPACER: vpWidth = m_coordInfo.m_spacerTabSpaceInfo.m_width; vpHeight = m_coordInfo.m_spacerTabSpaceInfo.m_height; break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: vpWidth = m_coordInfo.m_tabSpaceInfo.m_width; vpHeight = m_coordInfo.m_tabSpaceInfo.m_height; break; case AnnotationCoordinateSpaceEnum::SURFACE: vpWidth = m_coordInfo.m_tabSpaceInfo.m_width; vpHeight = m_coordInfo.m_tabSpaceInfo.m_height; break; case AnnotationCoordinateSpaceEnum::TAB: vpWidth = m_coordInfo.m_tabSpaceInfo.m_width; vpHeight = m_coordInfo.m_tabSpaceInfo.m_height; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: vpWidth = m_coordInfo.m_windowSpaceInfo.m_width; vpHeight = m_coordInfo.m_windowSpaceInfo.m_height; break; } if ((vpWidth > 0.0) && (vpHeight > 0.0)) { const float imageWidth = imageAnn->getImageWidth(); const float imageHeight = imageAnn->getImageHeight(); float percentWidth = (imageWidth / vpWidth) * 100.0; float percentHeight = (imageHeight / vpHeight) * 100.0; const float maxPercentageSize = 90.0; if (percentWidth > percentHeight) { if (percentWidth > maxPercentageSize) { const float scaleValue = maxPercentageSize / percentWidth; percentWidth = maxPercentageSize; percentHeight = percentHeight * scaleValue; } } else { if (percentHeight > maxPercentageSize) { const float scaleValue = maxPercentageSize / percentHeight; percentHeight = maxPercentageSize; percentWidth = percentWidth * scaleValue; } } imageAnn->setWidth(percentWidth); imageAnn->setHeight(percentHeight); } } /** * Update the annotation display properties after creating/updating an annotation. * It is possible that the user will create an annotation in a space (tab 4) and tab 4 * anotations are not enabled for display. So, ensure the display property is enabled * for the annotation. Otherwise, the user could create an annotation and not see * the annotation if the display property is disabled. * * @param annotation * Annotation that has been created or updated. */ void AnnotationCoordinateSelectionWidget::updateAnnotationDisplayProperties(const Annotation* annotation) { DisplayPropertiesAnnotation* dpa = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotation(); CaretAssert(annotation); switch (annotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: if (m_coordInfo.m_tabSpaceInfo.m_index >= 0) { } break; case AnnotationCoordinateSpaceEnum::SURFACE: if (m_coordInfo.m_tabSpaceInfo.m_index >= 0) { } break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: dpa->setDisplayWindowAnnotationsInSingleTabViews(annotation->getWindowIndex(), true); break; } } connectome-workbench-1.4.2/src/GuiQt/AnnotationCoordinateSelectionWidget.h000066400000000000000000000071521360521144700267650ustar00rootroot00000000000000#ifndef __ANNOTATION_COORDINATE_SELECTION_WIDGET_H__ #define __ANNOTATION_COORDINATE_SELECTION_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AnnotationCoordinateSpaceEnum.h" #include "AnnotationTypeEnum.h" #include "UserInputModeAnnotations.h" class QButtonGroup; class QRadioButton; namespace caret { class Annotation; class AnnotationCoordinate; class AnnotationImage; class AnnotationOneDimensionalShape; class AnnotationTwoDimensionalShape; class AnnotationCoordinateSelectionWidget : public QWidget { Q_OBJECT public: AnnotationCoordinateSelectionWidget(const AnnotationTypeEnum::Enum annotationType, const AnnotationCoordinateInformation& coordInfo, const AnnotationCoordinateInformation* optionalSecondCoordInfo, QWidget* parent = 0); virtual ~AnnotationCoordinateSelectionWidget(); void selectCoordinateSpace(const AnnotationCoordinateSpaceEnum::Enum coordSpace); AnnotationCoordinateSpaceEnum::Enum getSelectedCoordinateSpace(bool& validOut) const; bool changeAnnotationCoordinate(Annotation* annotation, QString& errorMessageOut); bool setCoordinateForNewAnnotation(Annotation* annotation, QString& errorMessageOut); // ADD_NEW_METHODS_HERE private: AnnotationCoordinateSelectionWidget(const AnnotationCoordinateSelectionWidget&); AnnotationCoordinateSelectionWidget& operator=(const AnnotationCoordinateSelectionWidget&); void updateAnnotationDisplayProperties(const Annotation* annotation); void setWidthAndHeightForImage(AnnotationImage* imageAnn); QRadioButton* createRadioButtonForSpace(const AnnotationCoordinateSpaceEnum::Enum space); // void setOneDimAnnotationCoordinates(AnnotationOneDimensionalShape* annotation); // // void setTwoDimAnnotationCoordinates(AnnotationTwoDimensionalShape* annotation); QButtonGroup* m_spaceButtonGroup; const AnnotationTypeEnum::Enum m_annotationType; const AnnotationCoordinateInformation& m_coordInfo; const AnnotationCoordinateInformation* m_optionalSecondCoordInfo; static const QString s_SPACE_PROPERTY_NAME; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_COORDINATE_SELECTION_WIDGET_DECLARE__ const QString AnnotationCoordinateSelectionWidget::s_SPACE_PROPERTY_NAME = "SPACE_NAME"; #endif // __ANNOTATION_COORDINATE_SELECTION_WIDGET_DECLARE__ } // namespace #endif //__ANNOTATION_COORDINATE_SELECTION_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationCoordinateSpaceWidget.cxx000066400000000000000000000127641360521144700264530ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_COORDINATE_SPACE_WIDGET_DECLARE__ #include "AnnotationCoordinateSpaceWidget.h" #undef __ANNOTATION_COORDINATE_SPACE_WIDGET_DECLARE__ #include #include #include "Annotation.h" #include "CaretAssert.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AnnotationCoordinateSpaceWidget * \brief Widget that displays the coordinate space of selected annotations * \ingroup GuiQt */ /** * Constructor. * * @param browserWindowIndex * Index of window in which this instance is displayed * @param parent * Parent for this widget. */ AnnotationCoordinateSpaceWidget::AnnotationCoordinateSpaceWidget(const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { m_spaceLabel = new QLabel(" "); m_spaceLabel->setToolTip("Selection annotation(s) space.\n" "Mouse dragging to move/resize\n" "annotations allowed in Tab or \n" "Window space only.\n" " Ch : Chart\n" " St : Stereotaxic\n" " Sf : Surface\n" " T : Tab\n" " W : Window\n" " + : Multiple Spaces"); QHBoxLayout* layout = new QHBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 0); layout->addWidget(m_spaceLabel); } /** * Destructor. */ AnnotationCoordinateSpaceWidget::~AnnotationCoordinateSpaceWidget() { } /** * Update the content of this widget with the given text annotation. * * @param annotationTexts * Text annotations for display (may be NULL). */ void AnnotationCoordinateSpaceWidget::updateContent(std::vector annotations) { QString text; if ( ! annotations.empty()) { CaretAssertVectorIndex(annotations, 0); CaretAssert(annotations[0]); AnnotationCoordinateSpaceEnum::Enum space = annotations[0]->getCoordinateSpace(); std::set tabIndices; bool haveMultipleSpacesFlag = false; for (int32_t i = 0; i < static_cast(annotations.size()); i++) { CaretAssertVectorIndex(annotations, i); CaretAssert(annotations[i]); const Annotation* ann = annotations[i]; const AnnotationCoordinateSpaceEnum::Enum annSpace = ann->getCoordinateSpace(); if (annSpace!= space) { haveMultipleSpacesFlag = true; } if (annotations[i]->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::TAB) { tabIndices.insert(AString::number(ann->getTabIndex() + 1)); } if (annotations[i]->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::SPACER) { const SpacerTabIndex sti = ann->getSpacerTabIndex(); tabIndices.insert(AString::number(sti.getRowIndex() + 1) + "," + AString::number(sti.getColumnIndex() + 1)); } } AString indicesString; for (const auto s : tabIndices) { if (indicesString.isEmpty()) { indicesString.append(":"); } else { indicesString.append(";"); } indicesString.append(s); } if (haveMultipleSpacesFlag) { text = "+"; } else { text = AnnotationCoordinateSpaceEnum::toGuiAbbreviatedName(space); switch (space) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: { text = AnnotationCoordinateSpaceEnum::toGuiAbbreviatedName(AnnotationCoordinateSpaceEnum::TAB); text.append(indicesString); } break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: text.append(indicesString); break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } } } m_spaceLabel->setText(text); } connectome-workbench-1.4.2/src/GuiQt/AnnotationCoordinateSpaceWidget.h000066400000000000000000000037501360521144700260730ustar00rootroot00000000000000#ifndef __ANNOTATION_COORDINATE_SPACE_WIDGET_H__ #define __ANNOTATION_COORDINATE_SPACE_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include namespace caret { class Annotation; class AnnotationCoordinateSpaceWidget : public QWidget { Q_OBJECT public: AnnotationCoordinateSpaceWidget(const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~AnnotationCoordinateSpaceWidget(); void updateContent(std::vector annotations); // ADD_NEW_METHODS_HERE private: AnnotationCoordinateSpaceWidget(const AnnotationCoordinateSpaceWidget&); AnnotationCoordinateSpaceWidget& operator=(const AnnotationCoordinateSpaceWidget&); const int32_t m_browserWindowIndex; QLabel* m_spaceLabel; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_COORDINATE_SPACE_WIDGET_DECLARE__ // #endif // __ANNOTATION_COORDINATE_SPACE_WIDGET_DECLARE__ } // namespace #endif //__ANNOTATION_COORDINATE_SPACE_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationCoordinateWidget.cxx000066400000000000000000000735671360521144700255070ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_COORDINATE_WIDGET_DECLARE__ #include "AnnotationCoordinateWidget.h" #undef __ANNOTATION_COORDINATE_WIDGET_DECLARE__ #include #include #include #include #include #include #include #include #include #include "AnnotationColorBar.h" #include "AnnotationManager.h" #include "AnnotationCoordinate.h" #include "AnnotationOneDimensionalShape.h" #include "AnnotationRedoUndoCommand.h" #include "AnnotationTwoDimensionalShape.h" #include "Brain.h" #include "BrainBrowserWindow.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "ChartTwoCartesianAxis.h" #include "ChartTwoOverlaySet.h" #include "EnumComboBoxTemplate.h" #include "EventBrowserWindowContent.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventOverlaySettingsEditorDialogRequest.h" #include "GuiManager.h" #include "MathFunctions.h" #include "ModelChartTwo.h" #include "StructureEnumComboBox.h" #include "WuQFactory.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AnnotationCoordinateWidget * \brief Widget for editing annotation coordinate * \ingroup GuiQt */ /** * Constructor. * * @param * @param whichCoordinate * Which coordinate, one (or only), or two * @param browserWindowIndex * Index of browser window * @param parent * Parent widget */ AnnotationCoordinateWidget::AnnotationCoordinateWidget(const AnnotationWidgetParentEnum::Enum parentWidgetType, const WhichCoordinate whichCoordinate, const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), m_parentWidgetType(parentWidgetType), m_whichCoordinate(whichCoordinate), m_browserWindowIndex(browserWindowIndex) { m_annotation = NULL; QString colonString; switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: colonString = ":"; break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } QLabel* surfaceVertexLabel = new QLabel("Vertex:"); m_surfaceStructureComboBox = new StructureEnumComboBox(this); m_surfaceStructureComboBox->listOnlyValidStructures(); m_surfaceStructureComboBox->getWidget()->setToolTip("Select surface structure"); QObject::connect(m_surfaceStructureComboBox, SIGNAL(structureSelected(const StructureEnum::Enum)), this, SLOT(valueChanged())); m_surfaceNodeIndexSpinBox = new QSpinBox(); m_surfaceNodeIndexSpinBox->setRange(0, 1000000); m_surfaceNodeIndexSpinBox->setSingleStep(1); m_surfaceNodeIndexSpinBox->setToolTip("Select surface vertex"); QObject::connect(m_surfaceNodeIndexSpinBox, SIGNAL(valueChanged(int)), this, SLOT(valueChanged())); m_surfaceOffsetLengthSpinBox = new QDoubleSpinBox(); m_surfaceOffsetLengthSpinBox->setRange(0.0, 999.0); m_surfaceOffsetLengthSpinBox->setSingleStep(0.1); m_surfaceOffsetLengthSpinBox->setToolTip("Offset of annotation from surface vertex"); QObject::connect(m_surfaceOffsetLengthSpinBox, SIGNAL(valueChanged(double)), this, SLOT(surfaceOffsetLengthValueChanged(double))); const int digitsRightOfDecimal = 1; QLabel* xCoordLabel = new QLabel(" X" + colonString); m_xCoordSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 100.0, 0.1, digitsRightOfDecimal, this, SLOT(valueChanged())); WuQtUtilities::setWordWrappedToolTip(m_xCoordSpinBox, "X-coordinate of annotation\n" " STEREOTAXIC: Stereotaxic X-Coordinate\n" " TAB and WINDOW X-Range: [0.0%, 100.0%]\n" " 0.0% => Left side of tab/window\n" " 100.0% => Right side of tab/window\n"); QLabel* yCoordLabel = new QLabel(" Y" + colonString); m_yCoordSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 100.0, 0.1, digitsRightOfDecimal, this, SLOT(valueChanged())); WuQtUtilities::setWordWrappedToolTip(m_yCoordSpinBox, "Y-coordinate of annotation\n" " STEREOTAXIC: Stereotaxic Y-Coordinate\n" " TAB and WINDOW Y-Range: [0.0%, 100.0%]\n" " 0.0% => Bottom of tab/window\n" " 100.0% => Top of tab/window\n"); QLabel* zCoordLabel = new QLabel(" Z" + colonString); m_zCoordSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(-100.0, 100.0, 0.1, digitsRightOfDecimal, this, SLOT(valueChanged())); WuQtUtilities::setWordWrappedToolTip(m_zCoordSpinBox, "Z-coordinate of annotation\n" " STEREOTAXIC: Stereotaxic Z-Coordinate\n" " TAB and WINDOW DEPTH Range: [0.0%, 100.0%]\n" " 0.0% => Toward's viewer\n" " 100.0% => Away from viewer\n"); const float spinBoxMaximumWidth = 80.0f; m_xCoordSpinBox->setMaximumWidth(spinBoxMaximumWidth); m_yCoordSpinBox->setMaximumWidth(spinBoxMaximumWidth); m_zCoordSpinBox->setMaximumWidth(spinBoxMaximumWidth); m_surfaceOffsetVectorTypeComboBox = NULL; switch (m_whichCoordinate) { case COORDINATE_ONE: m_surfaceOffsetVectorTypeComboBox = new EnumComboBoxTemplate(this); m_surfaceOffsetVectorTypeComboBox->setup(); QObject::connect(m_surfaceOffsetVectorTypeComboBox, SIGNAL(itemActivated()), this, SLOT(surfaceOffsetVectorTypeChanged())); m_surfaceOffsetVectorTypeComboBox->getWidget()->setFixedWidth(45); m_surfaceOffsetVectorTypeComboBox->getWidget()->setToolTip("Vector for surface offset:\n" " C - Centroid thru Vertex, Faces Viewer\n" " N - Vertex Normal, Faces Viewer\n" " T - Tangent, Rotates with Surface"); break; case COORDINATE_TWO: break; } m_plusButtonToolTipText = ("Click the mouse to set the new location for the coordinate.\n" "After clicking the mouse, a dialog allows selection of the\n" "coordinate space."); QToolButton* setCoordinateToolButton = NULL; switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: /** disabled as change space cause grouping problems. setCoordinateToolButton = new QToolButton(); */ break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } if (setCoordinateToolButton != NULL) { QAction* setCoordinateAction = WuQtUtilities::createAction("+", ("After pressing this button: \n" + m_plusButtonToolTipText), this, this, SLOT(setCoordinateActionTriggered())); setCoordinateToolButton->setDefaultAction(setCoordinateAction); WuQtUtilities::setToolButtonStyleForQt5Mac(setCoordinateToolButton); } m_surfaceWidget = new QWidget(); QHBoxLayout* surfaceLayout = new QHBoxLayout(m_surfaceWidget); WuQtUtilities::setLayoutSpacingAndMargins(surfaceLayout, 2, 0); surfaceLayout->addWidget(surfaceVertexLabel); surfaceLayout->addWidget(m_surfaceStructureComboBox->getWidget()); surfaceLayout->addWidget(m_surfaceNodeIndexSpinBox); if (m_surfaceOffsetVectorTypeComboBox != NULL) { surfaceLayout->addWidget(m_surfaceOffsetVectorTypeComboBox->getWidget()); } surfaceLayout->addWidget(m_surfaceOffsetLengthSpinBox); m_coordinateWidget = new QWidget(); QHBoxLayout* coordinateLayout = new QHBoxLayout(m_coordinateWidget); WuQtUtilities::setLayoutSpacingAndMargins(coordinateLayout, 2, 0); coordinateLayout->addWidget(xCoordLabel); coordinateLayout->addWidget(m_xCoordSpinBox); coordinateLayout->addWidget(yCoordLabel); coordinateLayout->addWidget(m_yCoordSpinBox); coordinateLayout->addWidget(zCoordLabel); coordinateLayout->addWidget(m_zCoordSpinBox); QHBoxLayout* layout = new QHBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); layout->addWidget(m_surfaceWidget); layout->addWidget(m_coordinateWidget); if (setCoordinateToolButton != NULL) { layout->addWidget(setCoordinateToolButton); } setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } /** * Destructor. */ AnnotationCoordinateWidget::~AnnotationCoordinateWidget() { } AnnotationCoordinate* AnnotationCoordinateWidget::getCoordinate() { AnnotationCoordinate* ac = NULL; if (m_annotation != NULL) { AnnotationOneDimensionalShape* oneDimShape = dynamic_cast(m_annotation); AnnotationTwoDimensionalShape* twoDimShape = dynamic_cast(m_annotation); switch (m_whichCoordinate) { case COORDINATE_ONE: if (oneDimShape != NULL) { ac = oneDimShape->getStartCoordinate(); } else if (twoDimShape != NULL) { ac = twoDimShape->getCoordinate(); } break; case COORDINATE_TWO: if (oneDimShape != NULL) { ac = oneDimShape->getEndCoordinate(); } break; } } return ac; } /** * Update with the given annotation coordinate. * * @param coordinate. */ void AnnotationCoordinateWidget::updateContent(Annotation* annotation) { m_annotation = NULL; if (annotation != NULL) { if (annotation->testProperty(Annotation::Property::COORDINATE)) { m_annotation = annotation; } } m_surfaceStructureComboBox->listOnlyValidStructures(); const AnnotationCoordinate* coordinate = getCoordinate(); bool surfaceFlag = false; if (coordinate != NULL) { float xyz[3]; coordinate->getXYZ(xyz); bool viewportSpaceFlag = false; const double percentageMinimum = 0.0; const double percentageMaximum = 100.0; const double zDepthMinimum = 0.0; const double zDepthMaximum = 100.0; const double coordinateMinimum = -std::numeric_limits::max(); const double coordinateMaximum = std::numeric_limits::max(); double xMin = 0.0; double xMax = 0.0; double yMin = 0.0; double yMax = 0.0; double zMin = 0.0; double zMax = 0.0; double xStep = 0.1; double yStep = 0.1; double zStep = 0.1; QString suffix; int32_t digitsRightOfDecimalX = 2; int32_t digitsRightOfDecimalY = 2; int32_t digitsRightOfDecimalZ = 2; switch (m_annotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: { xMin = coordinateMinimum; xMax = coordinateMaximum; yMin = coordinateMinimum; yMax = coordinateMaximum; zMin = coordinateMinimum; zMax = coordinateMaximum; digitsRightOfDecimalX = 3; digitsRightOfDecimalX = 3; xStep = 1.0; yStep = 1.0; BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(m_browserWindowIndex); CaretAssert(bbw); BrowserTabContent* browserTabContent = bbw->getBrowserTabContent(); if (browserTabContent != NULL) { ModelChartTwo* modelChartTwo = browserTabContent->getDisplayedChartTwoModel(); const int32_t tabIndex = browserTabContent->getTabNumber(); if (modelChartTwo != NULL) { ChartTwoOverlaySet* chartOverlaySet = NULL; switch (modelChartTwo->getSelectedChartTwoDataType(tabIndex)) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: chartOverlaySet = modelChartTwo->getChartTwoOverlaySet(tabIndex); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: chartOverlaySet = modelChartTwo->getChartTwoOverlaySet(tabIndex); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; } if (chartOverlaySet != NULL) { float xAxisMin = std::numeric_limits::max(); float xAxisMax = -std::numeric_limits::max(); float yAxisMin = std::numeric_limits::max(); float yAxisMax = -std::numeric_limits::max(); std::vector axes; chartOverlaySet->getDisplayedChartAxes(axes); const int32_t numAxes = static_cast(axes.size()); for (int32_t i = 0; i < numAxes; i++) { float rangeMin(0), rangeMax(0); axes[i]->getDataRange(rangeMin, rangeMax); if (rangeMax > rangeMin) { const ChartAxisLocationEnum::Enum axisLocation = axes[i]->getAxisLocation(); switch (axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: xAxisMin = std::min(xAxisMin, rangeMin); xAxisMax = std::max(xAxisMax, rangeMax); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: yAxisMin = std::min(yAxisMin, rangeMin); yAxisMax = std::max(yAxisMax, rangeMax); break; } } } if (xAxisMax > xAxisMin) { const float range(xAxisMax - xAxisMin); int32_t digits = 6 - static_cast(std::round(std::log10(range))); digitsRightOfDecimalX = MathFunctions::clamp(digits, 3, 6); xStep = range * 0.001f; } if (yAxisMax > yAxisMin) { const float range(yAxisMax - yAxisMin); int32_t digits = 6 - static_cast(std::round(std::log10(range))); digitsRightOfDecimalY = MathFunctions::clamp(digits, 3, 6); yStep = range * 0.001f; } } } } } break; case AnnotationCoordinateSpaceEnum::SPACER: xMin = percentageMinimum; xMax = percentageMaximum; yMin = percentageMinimum; yMax = percentageMaximum; zMin = zDepthMinimum; zMax = zDepthMaximum; suffix = "%"; break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: xMin = coordinateMinimum; xMax = coordinateMaximum; yMin = coordinateMinimum; yMax = coordinateMaximum; zMin = coordinateMinimum; zMax = coordinateMaximum; xStep = 1.0; yStep = 1.0; break; case AnnotationCoordinateSpaceEnum::SURFACE: surfaceFlag = true; break; case AnnotationCoordinateSpaceEnum::TAB: xMin = percentageMinimum; xMax = percentageMaximum; yMin = percentageMinimum; yMax = percentageMaximum; zMin = zDepthMinimum; zMax = zDepthMaximum; suffix = "%"; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: /* * Cannot move */ xMin = xyz[0]; xMax = xyz[0]; yMin = xyz[1]; yMax = xyz[1]; zMin = xyz[2]; zMax = xyz[2]; viewportSpaceFlag = true; break; case AnnotationCoordinateSpaceEnum::WINDOW: xMin = percentageMinimum; xMax = percentageMaximum; yMin = percentageMinimum; yMax = percentageMaximum; zMin = zDepthMinimum; zMax = zDepthMaximum; suffix = "%"; break; } m_xCoordSpinBox->blockSignals(true); m_xCoordSpinBox->setRange(xMin, xMax); m_xCoordSpinBox->setSingleStep(xStep); m_xCoordSpinBox->setSuffix(suffix); m_xCoordSpinBox->setValue(xyz[0]); m_xCoordSpinBox->setDecimals(digitsRightOfDecimalX); m_xCoordSpinBox->blockSignals(false); m_yCoordSpinBox->blockSignals(true); m_yCoordSpinBox->setRange(yMin, yMax); m_yCoordSpinBox->setSingleStep(yStep); m_yCoordSpinBox->setSuffix(suffix); m_yCoordSpinBox->setValue(xyz[1]); m_yCoordSpinBox->setDecimals(digitsRightOfDecimalY); m_yCoordSpinBox->blockSignals(false); m_zCoordSpinBox->blockSignals(true); m_zCoordSpinBox->setRange(zMin, zMax); m_zCoordSpinBox->setSingleStep(zStep); m_zCoordSpinBox->setSuffix(suffix); m_zCoordSpinBox->setValue(xyz[2]); m_zCoordSpinBox->setDecimals(digitsRightOfDecimalZ); m_zCoordSpinBox->blockSignals(false); if (surfaceFlag) { StructureEnum::Enum structure = StructureEnum::INVALID; int32_t surfaceNumberOfNodes = -1; int32_t surfaceNodeIndex = -1; float surfaceOffsetLength = AnnotationCoordinate::getDefaultSurfaceOffsetLength(); AnnotationSurfaceOffsetVectorTypeEnum::Enum surfaceOffsetVector = AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX; coordinate->getSurfaceSpace(structure, surfaceNumberOfNodes, surfaceNodeIndex, surfaceOffsetLength, surfaceOffsetVector); m_surfaceStructureComboBox->setSelectedStructure(structure); m_surfaceNodeIndexSpinBox->blockSignals(true); m_surfaceNodeIndexSpinBox->setValue(surfaceNodeIndex); m_surfaceNodeIndexSpinBox->blockSignals(false); if (m_surfaceOffsetVectorTypeComboBox != NULL) { m_surfaceOffsetVectorTypeComboBox->setSelectedItem(surfaceOffsetVector); } m_surfaceOffsetLengthSpinBox->blockSignals(true); m_surfaceOffsetLengthSpinBox->setValue(surfaceOffsetLength); m_surfaceOffsetLengthSpinBox->blockSignals(false); AnnotationCoordinate::setUserDefautlSurfaceOffsetVectorType(surfaceOffsetVector); AnnotationCoordinate::setUserDefaultSurfaceOffsetLength(surfaceOffsetLength); } if (viewportSpaceFlag) { setEnabled(false); } else { setEnabled(true); } } else { setEnabled(false); } m_surfaceWidget->setVisible(surfaceFlag); m_coordinateWidget->setVisible( ! surfaceFlag); } /** * Called when surface offset value changed. * * @param value * New value. */ void AnnotationCoordinateWidget::surfaceOffsetLengthValueChanged(double value) { const AnnotationCoordinate* coordinate = getCoordinate(); if ((m_annotation != NULL) && (coordinate != NULL)) { AnnotationCoordinate::setUserDefaultSurfaceOffsetLength(value); valueChanged(); } } /** * Called when surface offset vector type is changed. */ void AnnotationCoordinateWidget::surfaceOffsetVectorTypeChanged() { const AnnotationCoordinate* coordinate = getCoordinate(); if ((m_annotation != NULL) && (coordinate != NULL)) { CaretAssert(m_surfaceOffsetVectorTypeComboBox); AnnotationCoordinate::setUserDefautlSurfaceOffsetVectorType(m_surfaceOffsetVectorTypeComboBox->getSelectedItem()); valueChanged(); } } /** * Gets called when a coordinate value is changed. */ void AnnotationCoordinateWidget::valueChanged() { const AnnotationCoordinate* coordinate = getCoordinate(); if ((m_annotation != NULL) && (coordinate != NULL)) { bool surfaceFlag = false; switch (m_annotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: surfaceFlag = true; break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: { AnnotationCoordinate coordinateCopy(*coordinate); if (surfaceFlag) { StructureEnum::Enum structure = StructureEnum::INVALID; int32_t surfaceNumberOfNodes = -1; int32_t surfaceNodeIndex = -1; float surfaceOffsetLength = AnnotationCoordinate::getDefaultSurfaceOffsetLength(); AnnotationSurfaceOffsetVectorTypeEnum::Enum surfaceOffsetVector = AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX; coordinate->getSurfaceSpace(structure, surfaceNumberOfNodes, surfaceNodeIndex, surfaceOffsetLength, surfaceOffsetVector); structure = m_surfaceStructureComboBox->getSelectedStructure(); surfaceNodeIndex = m_surfaceNodeIndexSpinBox->value(); surfaceOffsetLength = m_surfaceOffsetLengthSpinBox->value(); if (m_surfaceOffsetVectorTypeComboBox != NULL) { surfaceOffsetVector = m_surfaceOffsetVectorTypeComboBox->getSelectedItem(); } coordinateCopy.setSurfaceSpace(structure, surfaceNumberOfNodes, surfaceNodeIndex, surfaceOffsetLength, surfaceOffsetVector); } else { float xyz[3] = { (float)m_xCoordSpinBox->value(), (float)m_yCoordSpinBox->value(), (float)m_zCoordSpinBox->value() }; coordinateCopy.setXYZ(xyz); } std::vector selectedAnnotations; selectedAnnotations.push_back(m_annotation); bool updateUserInterfaceFlag = false; for (std::vector::iterator annIter = selectedAnnotations.begin(); annIter != selectedAnnotations.end(); annIter++) { Annotation* ann = *annIter; if (ann->getType() == AnnotationTypeEnum::COLOR_BAR) { AnnotationColorBar* colorBar = dynamic_cast(ann); CaretAssert(colorBar); colorBar->setPositionMode(AnnotationColorBarPositionModeEnum::MANUAL); updateUserInterfaceFlag = true; } } AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); switch (m_whichCoordinate) { case COORDINATE_ONE: undoCommand->setModeCoordinateOne(coordinateCopy, selectedAnnotations); break; case COORDINATE_TWO: undoCommand->setModeCoordinateTwo(coordinateCopy, selectedAnnotations); break; } AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); if (updateUserInterfaceFlag) { EventManager::get()->sendEvent(EventOverlaySettingsEditorDialogRequest(EventOverlaySettingsEditorDialogRequest::MODE_UPDATE_ALL, m_browserWindowIndex, NULL, (CaretMappableDataFile*)NULL, -1).getPointer()); } } break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } /** * Called when the set coordinate button is clicked. */ void AnnotationCoordinateWidget::setCoordinateActionTriggered() { QPoint middlePos(width() / 2, height() / 2); QToolTip::showText(mapToGlobal(middlePos), m_plusButtonToolTipText, this); signalSelectCoordinateWithMouse(); } connectome-workbench-1.4.2/src/GuiQt/AnnotationCoordinateWidget.h000066400000000000000000000065361360521144700251240ustar00rootroot00000000000000#ifndef __ANNOTATION_COORDINATE_WIDGET_H__ #define __ANNOTATION_COORDINATE_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AnnotationCoordinateSpaceEnum.h" #include "AnnotationWidgetParentEnum.h" class QDoubleSpinBox; class QSpinBox; namespace caret { class Annotation; class AnnotationCoordinate; class EnumComboBoxTemplate; class StructureEnumComboBox; class AnnotationCoordinateWidget : public QWidget { Q_OBJECT public: enum WhichCoordinate { COORDINATE_ONE, COORDINATE_TWO }; AnnotationCoordinateWidget(const AnnotationWidgetParentEnum::Enum parentWidgetType, const WhichCoordinate whichCoordinate, const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~AnnotationCoordinateWidget(); // ADD_NEW_METHODS_HERE void updateContent(Annotation* annotation); signals: void signalSelectCoordinateWithMouse(); private slots: void valueChanged(); void setCoordinateActionTriggered(); void surfaceOffsetLengthValueChanged(double); void surfaceOffsetVectorTypeChanged(); private: AnnotationCoordinateWidget(const AnnotationCoordinateWidget&); AnnotationCoordinateWidget& operator=(const AnnotationCoordinateWidget&); AnnotationCoordinate* getCoordinate(); // ADD_NEW_MEMBERS_HERE const AnnotationWidgetParentEnum::Enum m_parentWidgetType; const WhichCoordinate m_whichCoordinate; const int32_t m_browserWindowIndex; QWidget* m_surfaceWidget; QWidget* m_coordinateWidget; StructureEnumComboBox* m_surfaceStructureComboBox; QSpinBox* m_surfaceNodeIndexSpinBox; EnumComboBoxTemplate* m_surfaceOffsetVectorTypeComboBox; QDoubleSpinBox* m_surfaceOffsetLengthSpinBox; QDoubleSpinBox* m_xCoordSpinBox; QDoubleSpinBox* m_yCoordSpinBox; QDoubleSpinBox* m_zCoordSpinBox; Annotation* m_annotation; AString m_plusButtonToolTipText; }; #ifdef __ANNOTATION_COORDINATE_WIDGET_DECLARE__ // #endif // __ANNOTATION_COORDINATE_WIDGET_DECLARE__ } // namespace #endif //__ANNOTATION_COORDINATE_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationCreateDialog.cxx000066400000000000000000001343161360521144700245650ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_CREATE_DIALOG_DECLARE__ #include "AnnotationCreateDialog.h" #undef __ANNOTATION_CREATE_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include "AnnotationBox.h" #include "AnnotationFile.h" #include "AnnotationImage.h" #include "AnnotationManager.h" #include "AnnotationPercentSizeText.h" #include "AnnotationRedoUndoCommand.h" #include "Brain.h" #include "BrainBrowserWindow.h" #include "BrainOpenGLWidget.h" #include "BrainOpenGLViewportContent.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretFileDialog.h" #include "CaretLogger.h" #include "CaretPointer.h" #include "DataFileException.h" #include "DisplayPropertiesAnnotation.h" #include "EnumComboBoxTemplate.h" #include "EventDataFileAdd.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "ImageFile.h" #include "ModelSurfaceMontage.h" #include "MouseEvent.h" #include "WuQtUtilities.h" #include "WuQMessageBox.h" using namespace caret; /** * \class caret::AnnotationCreateDialog * \brief Dialog used for creating new annotations. * \ingroup GuiQt */ /** * Creating a new annotation using an annotation space and type. * A dialog may be displayed when the coordinate space is not valid * for the window location or for text and image annotations. * * @param mouseEvent * The mouse event indicating where user clicked in the window * @param annotationSpace * Space of annotation being created. * @param annotationType * Type of annotation that is being created. * @param annotationFile * File to which new annotation is added. * @return * Pointer to annotation that was created or NULL * if annotation not created (user cancelled). */ Annotation* AnnotationCreateDialog::newAnnotationFromSpaceAndType(const MouseEvent& mouseEvent, const AnnotationCoordinateSpaceEnum::Enum annotationSpace, const AnnotationTypeEnum::Enum annotationType, AnnotationFile* annotationFile) { Annotation* newAnnotation = newAnnotationFromSpaceTypeAndCoords(MODE_NEW_ANNOTATION_TYPE_CLICK, mouseEvent, annotationSpace, annotationType, annotationFile); return newAnnotation; } /** * Creating a new annotation using an annotation space and type. * A dialog may be displayed when the coordinate space is not valid * for the window location or for text and image annotations. * * @param mouseEvent * The mouse event indicating where user clicked in the window * @param annotationSpace * Space of annotation being created. * @param annotationType * Type of annotation that is being created. * @param annotationFile * File to which new annotation is added. * @return * Pointer to annotation that was created or NULL * if annotation not created (user cancelled). */ Annotation* AnnotationCreateDialog::newAnnotationFromSpaceTypeAndBounds(const MouseEvent& mouseEvent, const AnnotationCoordinateSpaceEnum::Enum annotationSpace, const AnnotationTypeEnum::Enum annotationType, AnnotationFile* annotationFile) { Annotation* newAnnotation = newAnnotationFromSpaceTypeAndCoords(MODE_NEW_ANNOTATION_TYPE_FROM_BOUNDS, mouseEvent, annotationSpace, annotationType, annotationFile); return newAnnotation; } /** * Creating a new annotation using an annotation space and type. * A dialog may be displayed when the coordinate space is not valid * for the window location or for text and image annotations. * * @param mode * The mode. * @param mouseEvent * The mouse event indicating where user clicked in the window * @param annotationSpace * Space of annotation being created. * @param annotationType * Type of annotation that is being created. * @param coordOne * The first coordinate MUST BE VALID (NOT NULL). * @param coordTwo * Optional second coordinate (NULL if invalid). * @param annotationFile * File to which new annotation is added. * @return * Pointer to annotation that was created or NULL * if annotation not created (user cancelled). */ Annotation* AnnotationCreateDialog::newAnnotationFromSpaceTypeAndCoords(const Mode mode, const MouseEvent& mouseEvent, const AnnotationCoordinateSpaceEnum::Enum annotationSpaceIn, const AnnotationTypeEnum::Enum annotationType, AnnotationFile* annotationFile) { bool useBothFlag = false; switch (mode) { case MODE_NEW_ANNOTATION_TYPE_CLICK: break; case MODE_NEW_ANNOTATION_TYPE_FROM_BOUNDS: useBothFlag = true; break; } NewAnnotationInfo newInfo(mouseEvent, annotationSpaceIn, annotationType, useBothFlag, annotationFile); if ( ! newInfo.isValid()) { CaretAssert(0); WuQMessageBox::errorOk(mouseEvent.getOpenGLWidget(), "PROGRAM ERROR: Failed to create coordinate information."); return NULL; } bool needImageOrTextFlag = false; switch (annotationType) { case AnnotationTypeEnum::BOX: break; case AnnotationTypeEnum::COLOR_BAR: CaretAssertMessage(0, "Colorbars do not get created !!!"); break; case AnnotationTypeEnum::IMAGE: needImageOrTextFlag = true; break; case AnnotationTypeEnum::LINE: break; case AnnotationTypeEnum::OVAL: break; case AnnotationTypeEnum::TEXT: needImageOrTextFlag = true; break; } bool needToLaunchDialogFlag = false; if (newInfo.isSelectedSpaceValid()) { if (needImageOrTextFlag) { needToLaunchDialogFlag = true; } else { AString errorMessage; Annotation* newAnn = createAnnotation(newInfo, newInfo.m_selectedSpace, /*annotationSpace,*/ errorMessage); if (newAnn != NULL) { DisplayPropertiesAnnotation* dpa = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotation(); dpa->updateForNewAnnotation(newAnn); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); return newAnn; } if ( ! errorMessage.isEmpty()) { WuQMessageBox::errorOk(mouseEvent.getOpenGLWidget(), errorMessage); return NULL; } needToLaunchDialogFlag = true; } } else { needToLaunchDialogFlag = true; } if (needToLaunchDialogFlag) { AnnotationCreateDialog annDialog(mode, newInfo, newInfo.m_selectedSpace, newInfo.isSelectedSpaceValid(), mouseEvent.getOpenGLWidget()); if (annDialog.exec() == AnnotationCreateDialog::Accepted) { return annDialog.getAnnotationThatWasCreated(); } } return NULL; } /** * Create a new annotation. * * @param newAnnotationInfo * Information about the new annotation. * @param annotationSpace * Coordinate space for new annotaiton. * @param errorMessageOut * Output with error message. * @return * Pointer to new annotation or NULL if creating annotation failed. */ Annotation* AnnotationCreateDialog::createAnnotation(NewAnnotationInfo& newAnnotationInfo, const AnnotationCoordinateSpaceEnum::Enum annotationSpace, AString& errorMessageOut) { errorMessageOut.clear(); Annotation* newAnnotation = NULL; if (newAnnotationInfo.m_annotationType == AnnotationTypeEnum::TEXT) { newAnnotation = new AnnotationPercentSizeText(AnnotationAttributesDefaultTypeEnum::USER); /* * In surface montage, percentage size text may need alteration */ bool adjustTextPctSizeFlag = false; switch (annotationSpace) { case AnnotationCoordinateSpaceEnum::CHART: adjustTextPctSizeFlag = true; break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: adjustTextPctSizeFlag = true; break; case AnnotationCoordinateSpaceEnum::SURFACE: adjustTextPctSizeFlag = true; break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } if (adjustTextPctSizeFlag) { AnnotationPercentSizeText* pctText = dynamic_cast(newAnnotation); if (pctText != NULL) { const int32_t browserWindowIndex = newAnnotationInfo.m_mouseEvent.getBrowserWindowIndex(); BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(browserWindowIndex, false); if (browserTabContent != NULL) { ModelSurfaceMontage* msm = browserTabContent->getDisplayedSurfaceMontageModel(); if (msm != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); int32_t rowCount = 1; int32_t columnCount = 1; msm->getSurfaceMontageNumberOfRowsAndColumns(tabIndex, rowCount, columnCount); if (rowCount > 0) { float pctSize = pctText->getFontPercentViewportSize(); pctSize *= static_cast(rowCount); pctText->setFontPercentViewportSize(pctSize); } } } } } } else { newAnnotation = Annotation::newAnnotationOfType(newAnnotationInfo.m_annotationType, AnnotationAttributesDefaultTypeEnum::USER); } AnnotationCoordinateInformation* coordTwo = NULL; if (newAnnotationInfo.m_coordTwoInfoValid) { coordTwo = &newAnnotationInfo.m_coordTwoInfo; } else { bool threeDimSpaceFlag = false; switch (annotationSpace) { case AnnotationCoordinateSpaceEnum::CHART: threeDimSpaceFlag = true; break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: threeDimSpaceFlag = true; break; case AnnotationCoordinateSpaceEnum::SURFACE: threeDimSpaceFlag = true; break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } if (threeDimSpaceFlag) { switch (newAnnotationInfo.m_annotationType) { case AnnotationTypeEnum::BOX: break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: break; case AnnotationTypeEnum::LINE: delete newAnnotation; newAnnotation = NULL; errorMessageOut = ("A line annotation cannot be created from a mouse click in " + AnnotationCoordinateSpaceEnum::toGuiName(annotationSpace) + " coordinate space. Hold the mouse down, drag the mouse, and then release the mouse."); return NULL; break; case AnnotationTypeEnum::OVAL: break; case AnnotationTypeEnum::TEXT: break; } } } const bool validFlag = AnnotationCoordinateInformation::setAnnotationCoordinatesForSpace(newAnnotation, annotationSpace, &newAnnotationInfo.m_coordOneInfo, coordTwo); if (validFlag) { if ((newAnnotationInfo.m_percentageWidth > 0) && (newAnnotationInfo.m_percentageHeight > 0)) { AnnotationTwoDimensionalShape* twoDimShape = dynamic_cast(newAnnotation); if (twoDimShape != NULL) { twoDimShape->setWidth(newAnnotationInfo.m_percentageWidth); twoDimShape->setHeight(newAnnotationInfo.m_percentageHeight); } } finishAnnotationCreation(newAnnotationInfo.m_annotationFile, newAnnotation, newAnnotationInfo.m_mouseEvent.getBrowserWindowIndex(), newAnnotationInfo.m_coordOneInfo.m_tabSpaceInfo.m_index); return newAnnotation; } else { CaretAssertMessage(0, "Space should have been valid, we should never get here."); delete newAnnotation; return NULL; } } /** * Dialog constructor. * * @param mode * The dialog's mode. * @param newAnnotationInfo * Information for creating new annotation. * @param annotationSpace * Space of annotation that is being created. * @param annotationSpaceValidFlag * True if annotation space is valid (do not need space selection). * @param parent * Optional parent for this dialog. */ AnnotationCreateDialog::AnnotationCreateDialog(const Mode mode, NewAnnotationInfo& newAnnotationInfo, const AnnotationCoordinateSpaceEnum::Enum annotationSpace, const bool annotationSpaceValidFlag, QWidget* parent) : WuQDialogModal("New Annotation", parent), m_mode(mode), m_newAnnotationInfo(newAnnotationInfo), m_annotationSpace(annotationSpace), m_annotationThatWasCreated(NULL), m_imageWidth(0), m_imageHeight(0) { m_annotationSpaceButtonGroup = NULL; m_textEdit = NULL; QGroupBox* coordGroupBox = NULL; if ( ! annotationSpaceValidFlag) { coordGroupBox = new QGroupBox("Coordinate Space"); QVBoxLayout* coordGroupLayout = new QVBoxLayout(coordGroupBox); coordGroupLayout->setMargin(0); m_annotationSpaceButtonGroup = new QButtonGroup(this); for (std::vector::iterator iter = m_newAnnotationInfo.m_validSpaces.begin(); iter != m_newAnnotationInfo.m_validSpaces.end(); iter++) { const AnnotationCoordinateSpaceEnum::Enum space = *iter; QRadioButton* rb = new QRadioButton(AnnotationCoordinateSpaceEnum::toGuiName(space)); if (space == AnnotationCoordinateSpaceEnum::SPACER) { /* * Spacer and Tab are presented as 'TAB' to the user. So show 'TAB' but * use the integer code for 'SPACER'. */ rb->setText(AnnotationCoordinateSpaceEnum::toGuiName(AnnotationCoordinateSpaceEnum::TAB)); } m_annotationSpaceButtonGroup->addButton(rb, AnnotationCoordinateSpaceEnum::toIntegerCode(space)); coordGroupLayout->addWidget(rb); } } QWidget* textWidget = ((m_newAnnotationInfo.m_annotationType == AnnotationTypeEnum::TEXT) ? createTextWidget() : NULL); QWidget* imageWidget = ((m_newAnnotationInfo.m_annotationType == AnnotationTypeEnum::IMAGE) ? createImageWidget() : NULL); QWidget* dialogWidget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(dialogWidget); if (coordGroupBox != NULL) { const QString message("The location for the new annotation is incompatible with the " "coordinate space selected in the toolbar. " "Choose one of the coordinate " "spaces below to create the annotation or press Cancel to cancel creation " "of the annotation."); QLabel* messageLabel = new QLabel(message); messageLabel->setWordWrap(true); QLabel* spaceLabel = new QLabel("Space selected in Toolbar: " + AnnotationCoordinateSpaceEnum::toGuiName(annotationSpace)); spaceLabel->setWordWrap(false); layout->addWidget(spaceLabel); layout->addSpacing(10); layout->addWidget(messageLabel); layout->addSpacing(10); layout->addWidget(coordGroupBox); } if (textWidget != NULL) { layout->addWidget(textWidget); } if (imageWidget != NULL) { layout->addWidget(imageWidget); } dialogWidget->setSizePolicy(dialogWidget->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); setCentralWidget(dialogWidget, SCROLL_AREA_NEVER); if (m_newAnnotationInfo.m_annotationType == AnnotationTypeEnum::TEXT) { CaretAssert(m_textEdit); m_textEdit->setFocus(); } } /** * Destructor. */ AnnotationCreateDialog::~AnnotationCreateDialog() { } /** * @return Annotation that was created by dialog (NULL if annotation NOT created). */ Annotation* AnnotationCreateDialog::getAnnotationThatWasCreated() { return m_annotationThatWasCreated; } /** * @return New instance of text widget. */ QWidget* AnnotationCreateDialog::createTextWidget() { m_textEdit = new QTextEdit(); m_textEdit->setText(""); m_textEdit->selectAll(); QGroupBox* groupBox = new QGroupBox("Text"); QHBoxLayout* layout = new QHBoxLayout(groupBox); layout->addWidget(m_textEdit, 100); return groupBox; } /** * @return New instance of image widget. */ QWidget* AnnotationCreateDialog::createImageWidget() { QAction* newFileAction = WuQtUtilities::createAction("Choose Image File...", "Choose image file using file selection dialog", this, this, SLOT(selectImageButtonClicked())); QToolButton* newFileToolButton = new QToolButton(); newFileToolButton->setDefaultAction(newFileAction); m_imageFileNameLabel = new QLabel(); m_imageThumbnailLabel = new QLabel(); m_imageThumbnailLabel->setFixedSize(s_MAXIMUM_THUMB_NAIL_SIZE, s_MAXIMUM_THUMB_NAIL_SIZE); QHBoxLayout* nameLayout = new QHBoxLayout(); nameLayout->addWidget(newFileToolButton); nameLayout->addWidget(m_imageFileNameLabel); QGroupBox* groupBox = new QGroupBox("Image File"); QVBoxLayout* layout = new QVBoxLayout(groupBox); layout->addLayout(nameLayout); layout->addWidget(WuQtUtilities::createHorizontalLineWidget()); layout->addWidget(m_imageThumbnailLabel); return groupBox; } /** * Invalidate the image. */ void AnnotationCreateDialog::invalidateImage() { m_imageRgbaBytes.clear(); m_imageWidth = 0; m_imageHeight = 0; m_imageFileNameLabel->setText(""); m_imageThumbnailLabel->setPixmap(QPixmap()); } /** * Called when the select image button is clicked. */ void AnnotationCreateDialog::selectImageButtonClicked() { const AString fileDialogSettingsName("AnnotImageDialog"); /* * Setup file selection dialog. */ CaretFileDialog fd(this); fd.setAcceptMode(CaretFileDialog::AcceptOpen); fd.setNameFilter(DataFileTypeEnum::toQFileDialogFilter(DataFileTypeEnum::IMAGE)); fd.setFileMode(CaretFileDialog::ExistingFile); fd.setViewMode(CaretFileDialog::List); fd.setLabelText(CaretFileDialog::Accept, "Choose"); // OK button shows Insert fd.restoreDialogSettings(fileDialogSettingsName); AString errorMessages; if (fd.exec() == CaretFileDialog::Accepted) { invalidateImage(); fd.saveDialogSettings(fileDialogSettingsName); QStringList selectedFiles = fd.selectedFiles(); if ( ! selectedFiles.empty()) { const AString imageFileName = selectedFiles.at(0); ImageFile imageFile; try { imageFile.readFile(imageFileName); } catch (const DataFileException& dfe) { WuQMessageBox::errorOk(this, dfe.whatString()); return; } imageFile.getImageBytesRGBA(ImageFile::IMAGE_DATA_ORIGIN_AT_BOTTOM, m_imageRgbaBytes, m_imageWidth, m_imageHeight); if ((m_imageWidth <= 0) || (m_imageHeight <= 0)) { WuQMessageBox::errorOk(this, ("Image Width=" + QString::number(m_imageWidth) + " or Height=" + QString::number(m_imageHeight) + " is invalid.")); invalidateImage(); return; } const int32_t expectedNumberOfBytes = (m_imageWidth * m_imageHeight * 4); if (static_cast(m_imageRgbaBytes.size()) != expectedNumberOfBytes) { WuQMessageBox::errorOk(this, "Image bytes size should be " + QString::number(expectedNumberOfBytes) + " but is " + QString::number(m_imageRgbaBytes.size())); invalidateImage(); return; } m_imageFileNameLabel->setText(imageFile.getFileNameNoPath()); imageFile.resizeToMaximumWidthOrHeight(s_MAXIMUM_THUMB_NAIL_SIZE); const QImage* qImage = imageFile.getAsQImage(); m_imageThumbnailLabel->setPixmap(QPixmap::fromImage(*qImage)); } } } /** * Gets called when the OK button is clicked. */ void AnnotationCreateDialog::okButtonClicked() { AString errorMessage; QString userText; if (m_newAnnotationInfo.m_annotationType == AnnotationTypeEnum::TEXT) { userText = m_textEdit->toPlainText(); if (userText.isEmpty()) { errorMessage.appendWithNewLine("Text is missing."); } } if (m_newAnnotationInfo.m_annotationType == AnnotationTypeEnum::IMAGE) { if ((m_imageWidth <= 0) || (m_imageHeight <= 0) || (m_imageRgbaBytes.empty())) { errorMessage = "Image File is invalid. Choose Image File."; } } if ( ! errorMessage.isEmpty()) { WuQMessageBox::errorOk(this, errorMessage); return; } AnnotationCoordinateSpaceEnum::Enum space = m_newAnnotationInfo.m_selectedSpace; if (m_annotationSpaceButtonGroup != NULL) { const int id = m_annotationSpaceButtonGroup->checkedId(); bool validFlag = false; space = AnnotationCoordinateSpaceEnum::fromIntegerCode(id, &validFlag); if ( ! validFlag) { WuQMessageBox::errorOk(this, "No Space is selected."); return; } } CaretAssert(m_newAnnotationInfo.m_annotationFile); CaretPointer annotation; annotation.grabNew(NULL); annotation.grabNew(createAnnotation(m_newAnnotationInfo, space, errorMessage)); if (annotation == NULL) { if (errorMessage.isEmpty()) { WuQMessageBox::errorOk(this, "Failed to create annotation in space: " + AnnotationCoordinateSpaceEnum::toGuiName(space)); } else { WuQMessageBox::errorOk(this, errorMessage); } return; } if (m_newAnnotationInfo.m_annotationType == AnnotationTypeEnum::TEXT) { AnnotationText* text = dynamic_cast(annotation.getPointer()); CaretAssert(text); text->setText(userText); } AnnotationImage* annImage = dynamic_cast(annotation.getPointer()); if (annImage != NULL) { annImage->setImageBytesRGBA(&m_imageRgbaBytes[0], m_imageWidth, m_imageHeight); } /* * Need to release annotation from its CaretPointer since the * annotation file will take ownership of the annotation. */ Annotation* annotationPointer = annotation.releasePointer(); m_annotationThatWasCreated = annotationPointer; DisplayPropertiesAnnotation* dpa = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotation(); dpa->updateForNewAnnotation(m_annotationThatWasCreated); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); WuQDialog::okButtonClicked(); } /** * Finish the creation of an annotation. * * @param annotationFile * File to which annotation is added. * @param annotation * Annotation that was created. * @param browserWindowIndex * Index of window in which annotation was created. * @param tabIndex * Index of tab in which annotation was created. */ void AnnotationCreateDialog::finishAnnotationCreation(AnnotationFile* annotationFile, Annotation* annotation, const int32_t browswerWindowIndex, const int32_t tabIndex) { AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); /* * Add annotation to its file */ AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeCreateAnnotation(annotationFile, annotation); AString errorMessage; if ( ! annotationManager->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(GuiManager::get()->getBrowserWindowByWindowIndex(browswerWindowIndex), errorMessage); } annotationManager->selectAnnotationForEditing(browswerWindowIndex, AnnotationManager::SELECTION_MODE_SINGLE, false, annotation); /* * A new chart annotation is displayed only in the tab in which it was created */ if (annotation->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::CHART) { annotation->setItemDisplaySelectedInOneTab(tabIndex); annotation->setItemDisplaySelected(DisplayGroupEnum::DISPLAY_GROUP_TAB, tabIndex, TriStateSelectionStatusEnum::SELECTED); } } /** * Constructor for information used to create a new annotation. * * @param mouseEvent * The mouse event. * @param selectedSpace * The space selected by the user. * @param annotationType * The annotation type. * @param useBothCoordinatesFromMouseFlag * Use both coords (X/Y and pressed X/Y) * @param annotationFile * File to which annotation is added. */ AnnotationCreateDialog::NewAnnotationInfo::NewAnnotationInfo(const MouseEvent& mouseEvent, const AnnotationCoordinateSpaceEnum::Enum selectedSpace, const AnnotationTypeEnum::Enum annotationType, const bool useBothCoordinatesFromMouseFlag, AnnotationFile* annotationFile) : m_mouseEvent(mouseEvent), m_selectedSpace(selectedSpace), m_annotationType(annotationType), m_annotationFile(annotationFile) { CaretAssert(annotationFile); m_validSpaces.clear(); m_coordOneInfo.reset(); m_coordTwoInfo.reset(); m_coordTwoInfoValid = false; m_percentageWidth = -1; m_percentageHeight = -1; if (useBothCoordinatesFromMouseFlag) { AnnotationCoordinateInformation::createCoordinateInformationFromXY(mouseEvent, mouseEvent.getX(), mouseEvent.getY(), m_coordTwoInfo); AnnotationCoordinateInformation::createCoordinateInformationFromXY(mouseEvent, mouseEvent.getPressedX(), mouseEvent.getPressedY(), m_coordOneInfo); AnnotationCoordinateInformation::getValidCoordinateSpaces(&m_coordOneInfo, &m_coordTwoInfo, m_validSpaces); if (isValid()) { m_coordTwoInfoValid = true; processTwoCoordInfo(); } } else { AnnotationCoordinateInformation::createCoordinateInformationFromXY(mouseEvent, mouseEvent.getX(), mouseEvent.getY(), m_coordOneInfo); /* * For one-dimensional annotations (line), we need a second coordinate */ bool addSecondCoordFlag = true; switch (annotationType) { case AnnotationTypeEnum::BOX: break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: break; case AnnotationTypeEnum::LINE: addSecondCoordFlag = true; break; case AnnotationTypeEnum::OVAL: break; case AnnotationTypeEnum::TEXT: break; } if (addSecondCoordFlag) { } AnnotationCoordinateInformation::getValidCoordinateSpaces(&m_coordOneInfo, NULL, m_validSpaces); } /* * There is not a selection in the GUI for the user to choose 'SPACER' coordinate space. * Instead the user uses 'TAB' space in the GUI. So, if TAB space is NOT valid, but * SPACER space is valid, change the requested space to 'SPACER' */ if (m_selectedSpace == AnnotationCoordinateSpaceEnum::TAB) { const bool haveTabFlag = (std::find(m_validSpaces.begin(), m_validSpaces.end(), AnnotationCoordinateSpaceEnum::TAB) != m_validSpaces.end()); const bool haveSpacerFlag = (std::find(m_validSpaces.begin(), m_validSpaces.end(), AnnotationCoordinateSpaceEnum::SPACER) != m_validSpaces.end()); if (haveSpacerFlag) { if ( ! haveTabFlag) { m_selectedSpace = AnnotationCoordinateSpaceEnum::SPACER; } } } } /** * When the user drags to create an annotation, two points are * used at opposite corners. For non-linear annotations, we * need a center, width, and height. So for these types, * convert the two points to one point with center, width, * and height. */ void AnnotationCreateDialog::NewAnnotationInfo::processTwoCoordInfo() { if ((m_coordOneInfo.m_windowSpaceInfo.m_index >= 0) && (m_coordTwoInfo.m_windowSpaceInfo.m_index >= 0)) { bool useAverageFlag = false; bool useTextAligmentFlag = false; switch (m_annotationType) { case AnnotationTypeEnum::BOX: useAverageFlag = true; break; case AnnotationTypeEnum::COLOR_BAR: useAverageFlag = true; break; case AnnotationTypeEnum::IMAGE: useAverageFlag = true; break; case AnnotationTypeEnum::OVAL: useAverageFlag = true; break; case AnnotationTypeEnum::LINE: useAverageFlag = false; break; case AnnotationTypeEnum::TEXT: useTextAligmentFlag = true; break; } if (useAverageFlag || useTextAligmentFlag) { int32_t windowPixelX = m_coordOneInfo.m_windowSpaceInfo.m_pixelXYZ[0]; int32_t windowPixelY = m_coordOneInfo.m_windowSpaceInfo.m_pixelXYZ[1]; int32_t windowTwoPixelX = m_coordTwoInfo.m_windowSpaceInfo.m_pixelXYZ[0]; int32_t windowTwoPixelY = m_coordTwoInfo.m_windowSpaceInfo.m_pixelXYZ[1]; if ((windowPixelX >= 0) && (windowPixelY >= 0) && (windowTwoPixelX >= 0) && (windowTwoPixelY >= 0)) { const float minX = std::min(windowPixelX, windowTwoPixelX); const float minY = std::min(windowPixelY, windowTwoPixelY); const float maxX = std::max(windowPixelX, windowTwoPixelX); const float maxY = std::max(windowPixelY, windowTwoPixelY); const float centerX = (windowPixelX + windowTwoPixelX) / 2.0; const float centerY = (windowPixelY + windowTwoPixelY) / 2.0; if (useAverageFlag) { /* * Width and height in pixels */ const float pixelWidth = maxX - minX; const float pixelHeight = maxY - minY; float viewportWidth = 0.0; float viewportHeight = 0.0; switch (m_selectedSpace) { case AnnotationCoordinateSpaceEnum::CHART: case AnnotationCoordinateSpaceEnum::STEREOTAXIC: case AnnotationCoordinateSpaceEnum::SURFACE: { int viewport[4]; m_mouseEvent.getViewportContent()->getModelViewport(viewport); viewportWidth = viewport[2]; viewportHeight = viewport[3]; float subWidth = 0.0; float subHeight = 0.0; if (adjustViewportForSurfaceMontage(m_mouseEvent.getViewportContent()->getBrowserTabContent(), viewport, subWidth, subHeight)) { viewportWidth = subWidth; viewportHeight = subHeight; } break; } case AnnotationCoordinateSpaceEnum::SPACER: { int viewport[4]; m_mouseEvent.getViewportContent()->getModelViewport(viewport); viewportWidth = viewport[2]; viewportHeight = viewport[3]; } break; case AnnotationCoordinateSpaceEnum::TAB: { int viewport[4]; m_mouseEvent.getViewportContent()->getModelViewport(viewport); viewportWidth = viewport[2]; viewportHeight = viewport[3]; } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: { int viewport[4]; m_mouseEvent.getViewportContent()->getWindowViewport(viewport); viewportWidth = viewport[2]; viewportHeight = viewport[3]; } break; } if ((viewportWidth > 0.0) && (viewportHeight > 0.0)) { m_percentageWidth = (pixelWidth / viewportWidth) * 100.0; m_percentageHeight = (pixelHeight / viewportHeight) * 100.0; } windowPixelX = centerX; windowPixelY = centerY; windowTwoPixelX = -1; windowTwoPixelY = -1; /* 25 Mar 2016 * Note: windowPixelX,Y has origin in locked viewport * but we need X,Y in window as if there was no locked * viewport. */ int wvp[4]; m_mouseEvent.getViewportContent()->getWindowViewport(wvp); windowPixelX = centerX + wvp[0]; windowPixelY = centerY + wvp[1]; } else if (useTextAligmentFlag) { float textX = windowPixelX; float textY = windowPixelY; AnnotationPercentSizeText textAnn(AnnotationAttributesDefaultTypeEnum::USER); switch (textAnn.getHorizontalAlignment()) { case AnnotationTextAlignHorizontalEnum::CENTER: textX = centerX; break; case AnnotationTextAlignHorizontalEnum::LEFT: textX = minX; break; case AnnotationTextAlignHorizontalEnum::RIGHT: textX = maxX; break; } switch (textAnn.getVerticalAlignment()) { case AnnotationTextAlignVerticalEnum::BOTTOM: textY = minY; break; case AnnotationTextAlignVerticalEnum::MIDDLE: textY = centerY; break; case AnnotationTextAlignVerticalEnum::TOP: textY = maxY; break; } windowPixelX = textX; windowPixelY = textY; windowTwoPixelX = -1; windowTwoPixelY = -1; /* 25 Mar 2016 * Note: windowPixelX,Y has origin in locked viewport * but we need X,Y in window as if there was no locked * viewport. */ int wvp[4]; m_mouseEvent.getViewportContent()->getWindowViewport(wvp); windowPixelX = textX + wvp[0]; windowPixelY = textY + wvp[1]; } AnnotationCoordinateInformation::createCoordinateInformationFromXY(m_mouseEvent, windowPixelX, windowPixelY, m_coordOneInfo); m_coordTwoInfo.reset(); m_coordTwoInfoValid = false; AnnotationCoordinateInformation::getValidCoordinateSpaces(&m_coordOneInfo, NULL, m_validSpaces); } } } } /** * Adjust the viewport for surface montage. A surface montage is a composite of multiple * smaller viewports. For proper annotation sizing in stereotaxic or surface space, * we need to find the with of the model area in the viewport. * * @param browserTabContent * Content of browser tab. * @param viewport * The tab's viewport. * @param widthOut * Output with width. * @param heightOut * Output with height. * @return * True if the width and height are valid, else false. */ bool AnnotationCreateDialog::NewAnnotationInfo::adjustViewportForSurfaceMontage(BrowserTabContent* browserTabContent, const int viewport[4], float& widthOut, float& heightOut) { if (browserTabContent == NULL) { return false; } ModelSurfaceMontage* msm = browserTabContent->getDisplayedSurfaceMontageModel(); if (msm == NULL) { return false; } int32_t numRows = -1; int32_t numCols = -1; msm->getSurfaceMontageNumberOfRowsAndColumns(browserTabContent->getTabNumber(), numRows, numCols); if ((numRows > 0) && (numCols > 0)) { /* * All viewports within a surface montage are same dimensions */ const float viewportWidth = viewport[2]; const float viewportHeight = viewport[3]; widthOut = viewportWidth / static_cast(numCols); heightOut = viewportHeight / static_cast(numRows); if ((widthOut > 0.0) && (heightOut > 0.0)) { return true; } } return false; } /** * @return Is the new annotation information valid (has at least one valid space)? */ bool AnnotationCreateDialog::NewAnnotationInfo::isValid() const { return ( ! m_validSpaces.empty()); } /** * @return Is the selected space valid? */ bool AnnotationCreateDialog::NewAnnotationInfo::isSelectedSpaceValid() const { if (std::find(m_validSpaces.begin(), m_validSpaces.end(), m_selectedSpace) != m_validSpaces.end()) { return true; } return false; } connectome-workbench-1.4.2/src/GuiQt/AnnotationCreateDialog.h000066400000000000000000000156721360521144700242150ustar00rootroot00000000000000#ifndef __ANNOTATION_CREATE_DIALOG_H__ #define __ANNOTATION_CREATE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationCoordinateInformation.h" #include "AnnotationCoordinateSpaceEnum.h" #include "AnnotationTypeEnum.h" #include "WuQDialogModal.h" class QButtonGroup; class QTextEdit; namespace caret { class Annotation; class AnnotationFile; class BrowserTabContent; class MouseEvent; class AnnotationCreateDialog : public WuQDialogModal { Q_OBJECT public: static Annotation* newAnnotationFromSpaceAndType(const MouseEvent& mouseEvent, const AnnotationCoordinateSpaceEnum::Enum annotationSpace, const AnnotationTypeEnum::Enum annotationType, AnnotationFile* annotationFile); static Annotation* newAnnotationFromSpaceTypeAndBounds(const MouseEvent& mouseEvent, const AnnotationCoordinateSpaceEnum::Enum annotationSpace, const AnnotationTypeEnum::Enum annotationType, AnnotationFile* annotationFile); virtual ~AnnotationCreateDialog(); virtual void okButtonClicked(); Annotation* getAnnotationThatWasCreated(); // ADD_NEW_METHODS_HERE private slots: void selectImageButtonClicked(); private: /** Dialogs mode */ enum Mode { /** New annotation from annotation type at mouse click */ MODE_NEW_ANNOTATION_TYPE_CLICK, /** New annotation from annotation type at mouse press and release */ MODE_NEW_ANNOTATION_TYPE_FROM_BOUNDS }; class NewAnnotationInfo { public: NewAnnotationInfo(const MouseEvent& mouseEvent, const AnnotationCoordinateSpaceEnum::Enum selectedSpace, const AnnotationTypeEnum::Enum annotationType, const bool useBothCoordinatesFromMouseFlag, AnnotationFile* annotationFile); bool isValid() const; bool isSelectedSpaceValid() const; void processTwoCoordInfo(); bool adjustViewportForSurfaceMontage(BrowserTabContent* browserTabContent, const int viewport[4], float& widthOut, float& heightOut); const MouseEvent& m_mouseEvent; AnnotationCoordinateSpaceEnum::Enum m_selectedSpace; const AnnotationTypeEnum::Enum m_annotationType; AnnotationFile* m_annotationFile; std::vector m_validSpaces; AnnotationCoordinateInformation m_coordOneInfo; AnnotationCoordinateInformation m_coordTwoInfo; bool m_coordTwoInfoValid; float m_percentageWidth; float m_percentageHeight; }; static Annotation* newAnnotationFromSpaceTypeAndCoords(const Mode mode, const MouseEvent& mouseEvent, const AnnotationCoordinateSpaceEnum::Enum annotationSpace, const AnnotationTypeEnum::Enum annotationType, AnnotationFile* annotationFile); AnnotationCreateDialog(const Mode mode, NewAnnotationInfo& newAnnotationInfo, const AnnotationCoordinateSpaceEnum::Enum annotationSpace, const bool annotationSpaceValidFlag, QWidget* parent = 0); AnnotationCreateDialog(const AnnotationCreateDialog&); AnnotationCreateDialog& operator=(const AnnotationCreateDialog&); QWidget* createTextWidget(); QWidget* createImageWidget(); void invalidateImage(); static Annotation* createAnnotation(NewAnnotationInfo& newAnnotationInfo, const AnnotationCoordinateSpaceEnum::Enum annotationSpace, AString& errorMessageOut); static void finishAnnotationCreation(AnnotationFile* annotationFile, Annotation* annotation, const int32_t browswerWindowIndex, const int32_t tabIndex); const Mode m_mode; NewAnnotationInfo& m_newAnnotationInfo; const AnnotationCoordinateSpaceEnum::Enum m_annotationSpace; Annotation* m_annotationThatWasCreated; // float m_annotationFromBoundsWidth; // // float m_annotationFromBoundsHeight; QButtonGroup* m_annotationSpaceButtonGroup; QTextEdit* m_textEdit; QLabel* m_imageFileNameLabel; QLabel* m_imageThumbnailLabel; std::vector m_imageRgbaBytes; int32_t m_imageWidth; int32_t m_imageHeight; // AnnotationCoordinateInformation m_coordInfo; // // AnnotationCoordinateInformation m_coordTwoInfo; static const int s_MAXIMUM_THUMB_NAIL_SIZE; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_CREATE_DIALOG_DECLARE__ const int AnnotationCreateDialog::s_MAXIMUM_THUMB_NAIL_SIZE = 128; #endif // __ANNOTATION_CREATE_DIALOG_DECLARE__; } // namespace #endif //__ANNOTATION_CREATE_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationDeleteWidget.cxx000066400000000000000000000132761360521144700246110ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_DELETE_WIDGET_DECLARE__ #include "AnnotationDeleteWidget.h" #undef __ANNOTATION_DELETE_WIDGET_DECLARE__ #include #include #include #include #include #include #include "AnnotationManager.h" #include "AnnotationRedoUndoCommand.h" #include "Brain.h" #include "CaretAssert.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "GuiManager.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AnnotationDeleteWidget * \brief Widget for deleting annotations. * \ingroup GuiQt */ /** * Constructor. */ AnnotationDeleteWidget::AnnotationDeleteWidget(const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { QLabel* deleteLabel = new QLabel("Delete"); m_deleteToolButton = createDeleteToolButton(); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); layout->addWidget(deleteLabel); layout->addWidget(m_deleteToolButton); layout->addStretch(); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } /** * Destructor. */ AnnotationDeleteWidget::~AnnotationDeleteWidget() { } /** * Update the content. */ void AnnotationDeleteWidget::updateContent() { AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); m_deleteToolButtonAction->setEnabled(annotationManager->isAnnotationSelectedForEditingDeletable(m_browserWindowIndex)); } /** * @return The delete tool button. */ QToolButton* AnnotationDeleteWidget::createDeleteToolButton() { m_deleteToolButtonAction = WuQtUtilities::createAction("", ("Delete the selected annotation\n" "\n" "Pressing the Delete key while an annotation\n" "is selected will also delete an annotation\n" "\n" "Pressing the arrow will show a menu for\n" "undeleting annotations"), this, this, SLOT(deleteActionTriggered())); QToolButton* toolButton = new QToolButton(); const float width = 24.0; const float height = 24.0; QPixmap pixmap(static_cast(width), static_cast(height)); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainter(toolButton, pixmap); /* trash can */ painter->drawLine(4, 6, 4, 22); painter->drawLine(4, 22, 20, 22); painter->drawLine(20, 22, 20, 6); /* trash can lines */ painter->drawLine(12, 8, 12, 20); painter->drawLine(8, 8, 8, 20); painter->drawLine(16, 8, 16, 20); /* trash can lid and handle */ painter->drawLine(2, 6, 22, 6); painter->drawLine(8, 6, 8, 2); painter->drawLine(8, 2, 16, 2); painter->drawLine(16, 2, 16, 6); m_deleteToolButtonAction->setIcon(QIcon(pixmap)); toolButton->setIconSize(pixmap.size()); toolButton->setDefaultAction(m_deleteToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(toolButton); return toolButton; } /** * Gets called when the delete action is triggered. */ void AnnotationDeleteWidget::deleteActionTriggered() { AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); std::vector selectedAnnotations = annotationManager->getAnnotationsSelectedForEditing(m_browserWindowIndex); std::vector deleteAnnotations; for (auto a : selectedAnnotations) { if (a->testProperty(Annotation::Property::DELETION)) { deleteAnnotations.push_back(a); } } if ( ! deleteAnnotations.empty()) { AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeDeleteAnnotations(deleteAnnotations); AString errorMessage; if ( ! annotationManager->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } connectome-workbench-1.4.2/src/GuiQt/AnnotationDeleteWidget.h000066400000000000000000000037671360521144700242420ustar00rootroot00000000000000#ifndef __ANNOTATION_DELETE_WIDGET_H__ #define __ANNOTATION_DELETE_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include class QAction; class QToolButton; namespace caret { class AnnotationDeleteWidget : public QWidget { Q_OBJECT public: AnnotationDeleteWidget(const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~AnnotationDeleteWidget(); // ADD_NEW_METHODS_HERE void updateContent(); private slots: void deleteActionTriggered(); private: AnnotationDeleteWidget(const AnnotationDeleteWidget&); AnnotationDeleteWidget& operator=(const AnnotationDeleteWidget&); QToolButton* createDeleteToolButton(); const int32_t m_browserWindowIndex; QToolButton* m_deleteToolButton; QAction* m_deleteToolButtonAction; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_DELETE_WIDGET_DECLARE__ // #endif // __ANNOTATION_DELETE_WIDGET_DECLARE__ } // namespace #endif //__ANNOTATION_DELETE_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationFontWidget.cxx000066400000000000000000001033431360521144700243100ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #define __ANNOTATION_FONT_WIDGET_DECLARE__ #include "AnnotationFontWidget.h" #undef __ANNOTATION_FONT_WIDGET_DECLARE__ #include "AnnotationFontAttributesInterface.h" #include "AnnotationManager.h" #include "AnnotationRedoUndoCommand.h" #include "AnnotationTextFontNameEnum.h" #include "AnnotationTextFontPointSizeEnum.h" #include "AnnotationPercentSizeText.h" #include "Brain.h" #include "BrainBrowserWindow.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretColorEnumMenu.h" #include "EnumComboBoxTemplate.h" #include "EventBrowserWindowGraphicsRedrawn.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "GuiManager.h" #include "ModelSurfaceMontage.h" #include "WuQDoubleSpinBox.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AnnotationFontWidget * \brief Widget for annotation font selection * \ingroup GuiQt */ /** * Constructor. * * @param browserWindowIndex * Index of window in which this instance is displayed * @param parent * Parent for this widget. */ AnnotationFontWidget::AnnotationFontWidget(const AnnotationWidgetParentEnum::Enum parentWidgetType, const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), m_parentWidgetType(parentWidgetType), m_browserWindowIndex(browserWindowIndex) { /* * "Font" label */ QLabel* fontLabel = new QLabel("Font "); /* * Combo box for font name selection */ m_fontNameComboBox = new EnumComboBoxTemplate(this); m_fontNameComboBox->setup(); QObject::connect(m_fontNameComboBox, SIGNAL(itemActivated()), this, SLOT(fontNameChanged())); WuQtUtilities::setToolTipAndStatusTip(m_fontNameComboBox->getWidget(), "Change font"); /* * Combo box for font size */ const AString fontSizeToolTop("" "Adjusts font height (size), as a percentage of the viewport height, that is " "converted to a pixel height when the text is drawn. " "

" "The numeric value in this control will be RED " "when the pixel height is estimated to be too small and some or all " "characters may not be drawn. " "Reducing the height of the text and/or the height of the window may cause " "too small text. " ""); m_fontSizeSpinBox = new WuQDoubleSpinBox(this); m_fontSizeSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_fontSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(fontSizeChanged())); WuQtUtilities::setToolTipAndStatusTip(m_fontSizeSpinBox->getWidget(), fontSizeToolTop); /* * Default palette for size spin box */ m_fontSizeSpinBoxDefaultPalette = m_fontSizeSpinBox->getWidget()->palette(); /* * Palette for spin box that colors text in red when the font height is "too small" */ m_fontSizeSpinBoxRedTextPalette = m_fontSizeSpinBoxDefaultPalette; QBrush brush = m_fontSizeSpinBoxRedTextPalette.brush(QPalette::Active, QPalette::Text); brush.setColor(Qt::red); m_fontSizeSpinBoxRedTextPalette.setBrush(QPalette::Active, QPalette::Text, brush); m_fontSizeSpinBoxRedTextPalette.setBrush(QPalette::Active, QPalette::WindowText, brush); m_fontSizeSpinBoxRedTextPalette.setBrush(QPalette::Active, QPalette::HighlightedText, brush); /* * Text color menu */ m_textColorMenu = new CaretColorEnumMenu((CaretColorEnum::OPTION_INCLUDE_CUSTOM_COLOR)); QObject::connect(m_textColorMenu, SIGNAL(colorSelected(const CaretColorEnum::Enum)), this, SLOT(textColorSelected(const CaretColorEnum::Enum))); /* * Text color action and toolbutton */ QLabel* textColorLabel = new QLabel("Color"); const QSize toolButtonSize(16, 16); m_textColorAction = new QAction("C", this); m_textColorAction->setToolTip("Adjust the text color"); m_textColorAction->setMenu(m_textColorMenu); m_textColorToolButton = new QToolButton(); m_textColorToolButton->setDefaultAction(m_textColorAction); m_textColorToolButton->setIconSize(toolButtonSize); WuQtUtilities::setToolButtonStyleForQt5Mac(m_textColorToolButton); QToolButton* boldFontToolButton = NULL; QToolButton* italicFontToolButton = NULL; QToolButton* underlineFontToolButton = NULL; m_boldFontAction = NULL; m_italicFontAction = NULL; m_underlineFontAction = NULL; switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: { /* * Bold Font */ m_boldFontAction = WuQtUtilities::createAction("B", "Enable/disable bold styling", this, this, SLOT(fontBoldChanged())); m_boldFontAction->setCheckable(true); boldFontToolButton = new QToolButton(); boldFontToolButton->setDefaultAction(m_boldFontAction); WuQtUtilities::setToolButtonStyleForQt5Mac(boldFontToolButton); /* * Change the bold toolbutton's font to bold. */ QFont boldFont = boldFontToolButton->font(); boldFont.setBold(true); boldFontToolButton->setFont(boldFont); /* * Italic font toolbutton */ m_italicFontAction = WuQtUtilities::createAction("i", "Enable/disable italic styling", this, this, SLOT(fontItalicChanged())); m_italicFontAction->setCheckable(true); italicFontToolButton = new QToolButton(); italicFontToolButton->setDefaultAction(m_italicFontAction); WuQtUtilities::setToolButtonStyleForQt5Mac(italicFontToolButton); /* * Change the italic toolbutton's font to italic. */ QFont italicFont = italicFontToolButton->font(); italicFont.setItalic(true); italicFontToolButton->setFont(italicFont); /* * Underline font toolbutton */ m_underlineFontAction = WuQtUtilities::createAction("U", "Enable/disable font underlining", this, this, SLOT(fontUnderlineChanged())); m_underlineFontAction->setCheckable(true); underlineFontToolButton = new QToolButton(); underlineFontToolButton->setDefaultAction(m_underlineFontAction); WuQtUtilities::setToolButtonStyleForQt5Mac(underlineFontToolButton); /* * Change the underline toolbutton's font to underline. */ QFont underlineFont = underlineFontToolButton->font(); underlineFont.setUnderline(true); underlineFontToolButton->setFont(underlineFont); } break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } /* * Layout the widgets */ switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: { QLabel* sizeLabel = new QLabel("Size"); QLabel* styleLabel = new QLabel("Style"); QHBoxLayout* stylesLayout = new QHBoxLayout(); WuQtUtilities::setLayoutSpacingAndMargins(stylesLayout, 0, 0); stylesLayout->addWidget(boldFontToolButton); stylesLayout->addWidget(italicFontToolButton); stylesLayout->addWidget(underlineFontToolButton); stylesLayout->addStretch(); QGridLayout* fontNameSizeLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(fontNameSizeLayout, 2, 0); fontNameSizeLayout->setColumnStretch(0, 0); fontNameSizeLayout->setColumnStretch(1, 0); fontNameSizeLayout->setColumnStretch(2, 0); fontNameSizeLayout->setColumnStretch(3, 100); fontNameSizeLayout->addWidget(fontLabel, 0, 0); fontNameSizeLayout->addWidget(m_fontNameComboBox->getWidget(), 0, 1, 1, 3); fontNameSizeLayout->addWidget(sizeLabel, 1, 0); fontNameSizeLayout->addWidget(m_fontSizeSpinBox->getWidget(), 1, 1); fontNameSizeLayout->addWidget(styleLabel, 2, 0); fontNameSizeLayout->addLayout(stylesLayout, 2, 1); fontNameSizeLayout->addWidget(textColorLabel, 1, 2); fontNameSizeLayout->addWidget(m_textColorToolButton, 2, 2); } break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN); } /** * Destructor. */ AnnotationFontWidget::~AnnotationFontWidget() { EventManager::get()->removeAllEventsFromListener(this); } /** * Receive an event. * * @param event * The event that the receive can respond to. */ void AnnotationFontWidget::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN) { EventBrowserWindowGraphicsRedrawn* redrawEvent = dynamic_cast(event); CaretAssert(redrawEvent); if (m_browserWindowIndex == redrawEvent->getBrowserWindowIndex()) { if (isVisible()) { AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); std::vector selectedAnnotations = annotationManager->getAnnotationsSelectedForEditing(m_browserWindowIndex); if (selectedAnnotations.empty()) { return; } std::vector textAnnotations; for (auto ann : selectedAnnotations) { AnnotationFontAttributesInterface* textAnn = dynamic_cast(ann); if (textAnn != NULL) { textAnnotations.push_back(textAnn); } } updateContent(textAnnotations); } } } } /** * Update the content of this widget with the given annotations. * * @param annotations * The selected annotations. */ void AnnotationFontWidget::updateContent(std::vector& annotations) { m_annotationsFontColor.clear(); m_annotationsFontColor.reserve(annotations.size()); m_annotationsFontName.clear(); m_annotationsFontName.reserve(annotations.size()); m_annotationsFontSize.clear(); m_annotationsFontSize.reserve(annotations.size()); m_annotationsFontStyle.clear(); m_annotationsFontStyle.reserve(annotations.size()); for (auto a : annotations) { Annotation* ann = dynamic_cast(a); if (ann->testProperty(Annotation::Property::TEXT_FONT_NAME)) { m_annotationsFontName.push_back(a); } if (ann->testProperty(Annotation::Property::TEXT_FONT_SIZE)) { m_annotationsFontSize.push_back(a); } if (ann->testProperty(Annotation::Property::TEXT_FONT_STYLE)) { m_annotationsFontStyle.push_back(a); } if (ann->testProperty(Annotation::Property::TEXT_COLOR)) { m_annotationsFontColor.push_back(a); } } updateFontNameControls(); updateFontSizeControls(); updateFontStyleControls(); updateTextColorButton(); setEnabled((m_annotationsFontColor.size() + m_annotationsFontName.size() + m_annotationsFontSize.size() + m_annotationsFontStyle.size()) > 0); } /** * Update the font name controls. */ void AnnotationFontWidget::updateFontNameControls() { if ( ! m_annotationsFontName.empty()) { AnnotationTextFontNameEnum::Enum fontName = AnnotationTextFontNameEnum::VERA; //bool fontNameValid = true; const int32_t numAnn = static_cast(m_annotationsFontName.size()); for (int32_t i = 0; i < numAnn; i++) { CaretAssertVectorIndex(m_annotationsFontName, i); AnnotationFontAttributesInterface* annText = m_annotationsFontName[i]; CaretAssert(annText); if (i == 0) { fontName = annText->getFont(); } else { if (annText->getFont() != fontName) { //fontNameValid = false; } } } m_fontNameComboBox->setSelectedItem(fontName); AnnotationText::setUserDefaultFont(fontName); } } /** * Update the font size controls. */ void AnnotationFontWidget::updateFontSizeControls() { if ( ! m_annotationsFontSize.empty()) { float fontSizeValue = 5.0; bool haveMultipleFontSizeValues = false; const float surfaceMontageRowCount = getSurfaceMontageRowCount(); bool tooSmallFlag = false; const int32_t numAnn = static_cast(m_annotationsFontSize.size()); for (int32_t i = 0; i < numAnn; i++) { CaretAssertVectorIndex(m_annotationsFontSize, i); AnnotationFontAttributesInterface* annText = m_annotationsFontSize[i]; CaretAssert(annText); float sizeValue = annText->getFontPercentViewportSize(); Annotation* ann = dynamic_cast(annText); CaretAssert(ann); switch (ann->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: sizeValue /= surfaceMontageRowCount; break; case AnnotationCoordinateSpaceEnum::SURFACE: sizeValue /= surfaceMontageRowCount; break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } if (i == 0) { fontSizeValue = sizeValue; } else { if (fontSizeValue != sizeValue) { haveMultipleFontSizeValues = true; fontSizeValue = std::min(fontSizeValue, sizeValue); } } if (annText->isFontTooSmallWhenLastDrawn()) { tooSmallFlag = true; } // const AnnotationText* textAnnotation = dynamic_cast(annText); // if (textAnnotation != NULL) { // if (textAnnotation->isFontTooSmallWhenLastDrawn()) { // tooSmallFlag = true; // } // } } updateFontSizeSpinBox(fontSizeValue, haveMultipleFontSizeValues, tooSmallFlag); AnnotationText::setUserDefaultFontPercentViewportSize(fontSizeValue); } } /** * Update the font style controls. */ void AnnotationFontWidget::updateFontStyleControls() { m_boldFontAction->setEnabled(false); m_italicFontAction->setEnabled(false); m_underlineFontAction->setEnabled(false); if ( ! m_annotationsFontStyle.empty()) { bool boldOnFlag = true; bool italicOnFlag = true; bool underlineOnFlag = true; int32_t stylesEnabledCount = 0; const int32_t numAnn = static_cast(m_annotationsFontStyle.size()); for (int32_t i = 0; i < numAnn; i++) { CaretAssertVectorIndex(m_annotationsFontStyle, i); AnnotationFontAttributesInterface* annText = m_annotationsFontStyle[i]; CaretAssert(annText); Annotation* annotation = dynamic_cast(annText); CaretAssert(annotation); if (annotation->testProperty(Annotation::Property::TEXT_FONT_STYLE)) { if ( ! annText->isBoldStyleEnabled()) { boldOnFlag = false; } if ( ! annText->isItalicStyleEnabled()) { italicOnFlag = false; } if ( ! annText->isUnderlineStyleEnabled()) { underlineOnFlag = false; } ++stylesEnabledCount; } } /* * Font styles are ON only if all selected * text annotations have the style enabled */ const bool stylesEnabledFlag = (stylesEnabledCount > 0); m_boldFontAction->setEnabled(stylesEnabledFlag); m_boldFontAction->setChecked(boldOnFlag && stylesEnabledFlag); m_italicFontAction->setEnabled(stylesEnabledFlag); m_italicFontAction->setChecked(italicOnFlag && stylesEnabledFlag); m_underlineFontAction->setEnabled(stylesEnabledFlag); m_underlineFontAction->setChecked(underlineOnFlag && stylesEnabledFlag); if (stylesEnabledFlag) { AnnotationText::setUserDefaultBoldEnabled(boldOnFlag); AnnotationText::setUserDefaultItalicEnabled(italicOnFlag); AnnotationText::setUserDefaultUnderlineEnabled(underlineOnFlag); } } } /** * Update the font size spin box. * * @param value * New value for font size spin box. * @param haveMultipleValuesFlag * If true, there are multiple font size values so indicate * this with a '+' sign as a suffix * @param tooSmallFontFlag * If true, the font may be too small as detected by the * graphics drawing code. */ void AnnotationFontWidget::updateFontSizeSpinBox(const float value, const bool haveMultipleValuesFlag, const bool tooSmallFontFlag) { QSignalBlocker blocker(m_fontSizeSpinBox->getWidget()); m_fontSizeSpinBox->setValue(value); if (tooSmallFontFlag) { m_fontSizeSpinBox->getWidget()->setPalette(m_fontSizeSpinBoxRedTextPalette); } else { m_fontSizeSpinBox->getWidget()->setPalette(m_fontSizeSpinBoxDefaultPalette); } QString fontSizeSuffix("%"); if (haveMultipleValuesFlag) { fontSizeSuffix = "%+"; } m_fontSizeSpinBox->setValue(value); m_fontSizeSpinBox->setSuffix(fontSizeSuffix); // if (tooSmallFontFlag) { // m_fontSizeSpinBox->getWidget()->setPalette(m_fontSizeSpinBoxRedTextPalette); // } // else { // m_fontSizeSpinBox->getWidget()->setPalette(m_fontSizeSpinBoxDefaultPalette); // } // m_fontSizeSpinBox->setValue(value); } /** * Gets called when the text color is changed. * * @param caretColor * Color that was selected. */ void AnnotationFontWidget::textColorSelected(const CaretColorEnum::Enum caretColor) { if ( ! m_annotationsFontColor.empty()) { float rgba[4]; m_annotationsFontColor[0]->getTextColorRGBA(rgba); if (caretColor == CaretColorEnum::CUSTOM) { QColor color; color.setRgbF(rgba[0], rgba[1], rgba[2]); QColor newColor = QColorDialog::getColor(color, m_textColorToolButton, "Text Color"); if (newColor.isValid()) { rgba[0] = newColor.redF(); rgba[1] = newColor.greenF(); rgba[2] = newColor.blueF(); switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: AnnotationText::setUserDefaultCustomTextColor(rgba); break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } } } switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: { AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeTextColor(caretColor, rgba, convertToAnnotations(m_annotationsFontColor)); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } AnnotationText::setUserDefaultTextColor(caretColor); } break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } } updateTextColorButton(); switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Update the text color button. */ void AnnotationFontWidget::updateTextColorButton() { CaretColorEnum::Enum colorEnum = CaretColorEnum::NONE; float rgba[4]; CaretColorEnum::toRGBAFloat(colorEnum, rgba); rgba[3] = 1.0; bool colorButtonValidFlag = false; switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: { const int32_t numAnnotations = static_cast(m_annotationsFontColor.size()); if (numAnnotations > 0) { bool firstColorSupportFlag = true; bool allSameColorFlag = true; for (int32_t i = 0; i < numAnnotations; i++) { if (firstColorSupportFlag) { m_annotationsFontColor[i]->getTextColorRGBA(rgba); firstColorSupportFlag = false; colorButtonValidFlag = true; } else { float colorRGBA[4]; m_annotationsFontColor[i]->getTextColorRGBA(colorRGBA); for (int32_t iColor = 0; iColor < 4; iColor++) { if (rgba[iColor] != colorRGBA[iColor]) { allSameColorFlag = false; break; } } if ( ! allSameColorFlag) { break; } } } if (allSameColorFlag) { colorEnum = m_annotationsFontColor[0]->getTextColor(); m_annotationsFontColor[0]->getTextColorRGBA(rgba); float customRGBA[4]; m_annotationsFontColor[0]->getCustomTextColor(customRGBA); m_textColorMenu->setCustomIconColor(customRGBA); switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: AnnotationText::setUserDefaultTextColor(colorEnum); AnnotationText::setUserDefaultCustomTextColor(customRGBA); break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } } } } break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } QPixmap pm = WuQtUtilities::createCaretColorEnumPixmap(m_textColorToolButton, 24, 24, colorEnum, rgba, true); m_textColorAction->setIcon(QIcon(pm)); m_textColorMenu->setSelectedColor(colorEnum); m_textColorToolButton->setEnabled(colorButtonValidFlag); if (colorButtonValidFlag) { } } /** * Gets called when font bold changed. */ void AnnotationFontWidget::fontBoldChanged() { AnnotationRedoUndoCommand* command = new AnnotationRedoUndoCommand(); command->setModeTextFontBold(m_boldFontAction->isChecked(), convertToAnnotations(m_annotationsFontStyle)); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(command, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: AnnotationText::setUserDefaultBoldEnabled(m_boldFontAction->isChecked()); break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: break; } } /** * Gets called when font italic changed. */ void AnnotationFontWidget::fontItalicChanged() { AnnotationRedoUndoCommand* command = new AnnotationRedoUndoCommand(); command->setModeTextFontItalic(m_italicFontAction->isChecked(), convertToAnnotations(m_annotationsFontStyle)); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(command, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: AnnotationText::setUserDefaultItalicEnabled(m_italicFontAction->isChecked()); break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: break; } } /** * Gets called when font name changed. */ void AnnotationFontWidget::fontNameChanged() { const AnnotationTextFontNameEnum::Enum fontName = m_fontNameComboBox->getSelectedItem(); AnnotationRedoUndoCommand* command = new AnnotationRedoUndoCommand(); command->setModeTextFontName(fontName, convertToAnnotations(m_annotationsFontName)); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(command, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: AnnotationText::setUserDefaultFont(fontName); break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: break; } EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Gets called when font size changed. */ void AnnotationFontWidget::fontSizeChanged() { const float fontPercentSize = m_fontSizeSpinBox->value(); AnnotationRedoUndoCommand* command = new AnnotationRedoUndoCommand(); command->setModeTextFontPercentSize(fontPercentSize, convertToAnnotations(m_annotationsFontSize), getSurfaceMontageRowCount()); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(command, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: AnnotationText::setUserDefaultFontPercentViewportSize(fontPercentSize); break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); /* * "Font too small" status is set while drawing so need * to update the size spin box AFTER the graphics update */ updateFontSizeControls(); } /** * @return Number of rows in a surface montage. * If a surface montage is not displayed, one is returned. */ float AnnotationFontWidget::getSurfaceMontageRowCount() const { const BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(m_browserWindowIndex); CaretAssert(bbw); int32_t surfaceMontageRowCount = 1; const BrowserTabContent* btc = bbw->getBrowserTabContent(); if (btc != NULL) { const ModelSurfaceMontage* msm = btc->getDisplayedSurfaceMontageModel(); if (msm != NULL) { int32_t columnCount = 1; msm->getSurfaceMontageNumberOfRowsAndColumns(btc->getTabNumber(), surfaceMontageRowCount, columnCount); } } return surfaceMontageRowCount; } /** * Gets called when font underline changed. */ void AnnotationFontWidget::fontUnderlineChanged() { AnnotationRedoUndoCommand* command = new AnnotationRedoUndoCommand(); command->setModeTextFontUnderline(m_underlineFontAction->isChecked(), convertToAnnotations(m_annotationsFontStyle)); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(command, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: AnnotationText::setUserDefaultUnderlineEnabled(m_underlineFontAction->isChecked()); break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } } /** * Convert the font style interfade annotations to annotations * * @param fontInterfaces * Input font interface annotations. * @return * Vector with input converted to Annotation class. */ std::vector AnnotationFontWidget::convertToAnnotations(const std::vector& fontInterfaces) { std::vector annotationsOut; for (auto f : fontInterfaces) { Annotation* a = dynamic_cast(f); CaretAssert(a); annotationsOut.push_back(a); } return annotationsOut; } connectome-workbench-1.4.2/src/GuiQt/AnnotationFontWidget.h000066400000000000000000000104251360521144700237330ustar00rootroot00000000000000#ifndef __ANNOTATION_FONT_WIDGET_H__ #define __ANNOTATION_FONT_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "AnnotationWidgetParentEnum.h" #include "CaretColorEnum.h" #include "EventListenerInterface.h" class QToolButton; namespace caret { class Annotation; class AnnotationFontAttributesInterface; class AnnotationText; class CaretColorEnumMenu; class EnumComboBoxTemplate; class WuQDoubleSpinBox; class AnnotationFontWidget : public QWidget, public EventListenerInterface { Q_OBJECT public: AnnotationFontWidget(const AnnotationWidgetParentEnum::Enum parentWidgetType, const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~AnnotationFontWidget(); void updateContent(std::vector& annotations); virtual void receiveEvent(Event* event) override; // ADD_NEW_METHODS_HERE private slots: void textColorSelected(const CaretColorEnum::Enum); void fontBoldChanged(); void fontItalicChanged(); void fontNameChanged(); void fontSizeChanged(); void fontUnderlineChanged(); private: AnnotationFontWidget(const AnnotationFontWidget&); AnnotationFontWidget& operator=(const AnnotationFontWidget&); void updateFontSizeSpinBox(const float value, const bool haveMultipleValuesFlag, const bool tooSmallFontFlag); void updateTextColorButton(); void updateFontNameControls(); void updateFontSizeControls(); void updateFontStyleControls(); float getSurfaceMontageRowCount() const; static std::vector convertToAnnotations(const std::vector& fontInterfaces); const AnnotationWidgetParentEnum::Enum m_parentWidgetType; const int32_t m_browserWindowIndex; EnumComboBoxTemplate* m_fontNameComboBox; WuQDoubleSpinBox* m_fontSizeSpinBox; QPalette m_fontSizeSpinBoxDefaultPalette; QPalette m_fontSizeSpinBoxRedTextPalette; QToolButton* m_textColorToolButton; QAction* m_textColorAction; CaretColorEnumMenu* m_textColorMenu; QAction* m_boldFontAction; QAction* m_italicFontAction; QAction* m_underlineFontAction; /** Contains annotations supporting font name */ std::vector m_annotationsFontName; /** Contains annotations supporting font style */ std::vector m_annotationsFontSize; /** Contains annotations supporting font style */ std::vector m_annotationsFontStyle; /** Contains annotations supporting font color */ std::vector m_annotationsFontColor; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_FONT_WIDGET_DECLARE__ // #endif // __ANNOTATION_FONT_WIDGET_DECLARE__ } // namespace #endif //__ANNOTATION_FONT_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationFormatWidget.cxx000066400000000000000000000054761360521144700246420ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_FORMAT_WIDGET_DECLARE__ #include "AnnotationFormatWidget.h" #undef __ANNOTATION_FORMAT_WIDGET_DECLARE__ #include #include #include #include "AnnotationMenuArrange.h" #include "CaretAssert.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AnnotationFormatWidget * \brief Widget for formatting annotations. * \ingroup GuiQt */ /** * Constructor. * * @param browserWindowIndex * Index of the browser window. * @param parent * Parent of this widget. */ AnnotationFormatWidget::AnnotationFormatWidget(const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { QLabel* formatLabel = new QLabel("Format"); QWidget* arrangeButton = createArrangeMenuToolButton(); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); layout->addWidget(formatLabel); layout->addWidget(arrangeButton); layout->addStretch(); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } /** * Destructor. */ AnnotationFormatWidget::~AnnotationFormatWidget() { } /** * Update with the given annotation. * * @param annotation. */ void AnnotationFormatWidget::updateContent(Annotation* /*annotation*/) { } /** * @return The arrange tool button. */ QWidget* AnnotationFormatWidget::createArrangeMenuToolButton() { AnnotationMenuArrange* arrangeMenu = new AnnotationMenuArrange(m_browserWindowIndex); QAction* arrangeAction = new QAction("Arrange", this); arrangeAction->setToolTip("Arrange (align) and group annotations"); arrangeAction->setMenu(arrangeMenu); QToolButton* arrangeToolButton = new QToolButton(); arrangeToolButton->setDefaultAction(arrangeAction); WuQtUtilities::setToolButtonStyleForQt5Mac(arrangeToolButton); return arrangeToolButton; } connectome-workbench-1.4.2/src/GuiQt/AnnotationFormatWidget.h000066400000000000000000000035331360521144700242570ustar00rootroot00000000000000#ifndef __ANNOTATION_FORMAT_WIDGET_H__ #define __ANNOTATION_FORMAT_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include namespace caret { class Annotation; class AnnotationFormatWidget : public QWidget { Q_OBJECT public: AnnotationFormatWidget(const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~AnnotationFormatWidget(); // ADD_NEW_METHODS_HERE void updateContent(Annotation* annotation); private: AnnotationFormatWidget(const AnnotationFormatWidget&); AnnotationFormatWidget& operator=(const AnnotationFormatWidget&); QWidget* createArrangeMenuToolButton(); const int32_t m_browserWindowIndex; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_FORMAT_WIDGET_DECLARE__ // #endif // __ANNOTATION_FORMAT_WIDGET_DECLARE__ } // namespace #endif //__ANNOTATION_FORMAT_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationInsertNewWidget.cxx000066400000000000000000000660601360521144700253240ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_INSERT_NEW_WIDGET_DECLARE__ #include "AnnotationInsertNewWidget.h" #undef __ANNOTATION_INSERT_NEW_WIDGET_DECLARE__ #include #include #include #include #include #include #include #include #include #include "Annotation.h" #include "AnnotationFile.h" #include "AnnotationManager.h" #include "AnnotationMenuFileSelection.h" #include "AnnotationRedoUndoCommand.h" #include "Brain.h" #include "BrainBrowserWindow.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretUndoStack.h" #include "DisplayPropertiesAnnotation.h" #include "EventAnnotationCreateNewType.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventUserInterfaceUpdate.h" #include "EventManager.h" #include "GuiManager.h" #include "Model.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AnnotationInsertNewWidget * \brief Widget for creating new annotations. * \ingroup GuiQt */ /** * Constructor. * * @param browserWindowIndex * Index of the browser window. * @param parent * Parent of this widget. */ AnnotationInsertNewWidget::AnnotationInsertNewWidget(const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { /* * Shape buttons */ m_shapeActionGroup = new QActionGroup(this); QToolButton* shapeBoxToolButton = createShapeToolButton(AnnotationTypeEnum::BOX, m_shapeActionGroup); QToolButton* shapeImageToolButton = createShapeToolButton(AnnotationTypeEnum::IMAGE, m_shapeActionGroup); QToolButton* shapeLineToolButton = createShapeToolButton(AnnotationTypeEnum::LINE, m_shapeActionGroup); QToolButton* shapeOvalToolButton = createShapeToolButton(AnnotationTypeEnum::OVAL, m_shapeActionGroup); QToolButton* shapeTextToolButton = createShapeToolButton(AnnotationTypeEnum::TEXT, m_shapeActionGroup); QObject::connect(m_shapeActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(spaceOrShapeActionTriggered())); /* * Space buttons */ m_spaceActionGroup = new QActionGroup(this); QToolButton* chartSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::CHART, m_spaceActionGroup); QToolButton* tabSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::TAB, m_spaceActionGroup); const bool showSpacerToolButtonFlag(false); QToolButton* spacerSpaceToolButton(NULL); if (showSpacerToolButtonFlag) { spacerSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::SPACER, m_spaceActionGroup); } QToolButton* stereotaxicSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::STEREOTAXIC, m_spaceActionGroup); QToolButton* surfaceSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::SURFACE, m_spaceActionGroup); QToolButton* windowSpaceToolButton = createSpaceToolButton(AnnotationCoordinateSpaceEnum::WINDOW, m_spaceActionGroup); QObject::connect(m_spaceActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(spaceOrShapeActionTriggered())); const bool smallButtonsFlag = false; if (smallButtonsFlag) { const int mw = 24; const int mh = 24; shapeBoxToolButton->setMaximumSize(mw, mh); shapeImageToolButton->setMaximumSize(mw, mh); shapeLineToolButton->setMaximumSize(mw, mh); shapeOvalToolButton->setMaximumSize(mw, mh); shapeTextToolButton->setMaximumSize(mw, mh); chartSpaceToolButton->setMaximumSize(mw, mh); if (spacerSpaceToolButton != NULL) { spacerSpaceToolButton->setMaximumSize(mw, mh); } tabSpaceToolButton->setMaximumSize(mw, mh); stereotaxicSpaceToolButton->setMaximumSize(mw, mh); surfaceSpaceToolButton->setMaximumSize(mw, mh); windowSpaceToolButton->setMaximumSize(mw, mh); } QToolButton* fileSelectionToolButton = createFileSelectionToolButton(); QLabel* fileLabel = new QLabel("File"); QLabel* spaceLabel = new QLabel("Space"); QLabel* typeLabel = new QLabel("Type"); QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 2); const bool rowsLayoutFlag = true; if (rowsLayoutFlag) { QVBoxLayout* fileLayout = new QVBoxLayout(); fileLayout->addWidget(fileLabel, 0, Qt::AlignHCenter); fileLayout->addWidget(fileSelectionToolButton, 0, Qt::AlignHCenter); fileLayout->addStretch(); QLabel* insertLabel = new QLabel("Insert New"); const int32_t topColumnCount((spacerSpaceToolButton != NULL) ? 9 : 8); gridLayout->addWidget(insertLabel, 0, 0, 1, topColumnCount, Qt::AlignHCenter); gridLayout->addLayout(fileLayout, 1, 0, 3, 1, (Qt::AlignTop | Qt::AlignHCenter)); gridLayout->setColumnMinimumWidth(1, 5); int32_t topColumn(2); gridLayout->addWidget(spaceLabel, 1, topColumn++, Qt::AlignLeft); gridLayout->addWidget(chartSpaceToolButton, 1, topColumn++); if (spacerSpaceToolButton != NULL) { gridLayout->addWidget(spacerSpaceToolButton, 1, topColumn++); } gridLayout->addWidget(stereotaxicSpaceToolButton, 1, topColumn++); gridLayout->addWidget(surfaceSpaceToolButton, 1, topColumn++); gridLayout->addWidget(tabSpaceToolButton, 1, topColumn++); gridLayout->addWidget(windowSpaceToolButton, 1, topColumn++); gridLayout->setRowMinimumHeight(2, 2); gridLayout->addWidget(typeLabel, 3, 2, Qt::AlignLeft); gridLayout->addWidget(shapeBoxToolButton, 3, 3); gridLayout->addWidget(shapeImageToolButton, 3, 4); gridLayout->addWidget(shapeLineToolButton, 3, 5); gridLayout->addWidget(shapeOvalToolButton, 3, 6); gridLayout->addWidget(shapeTextToolButton, 3, 7); } else { QLabel* insertLabel = new QLabel("Insert New"); gridLayout->addWidget(insertLabel, 0, 0, 1, 8, Qt::AlignHCenter); gridLayout->addWidget(fileLabel, 1, 0, Qt::AlignHCenter); gridLayout->addWidget(fileSelectionToolButton, 2, 0, 2, 1, (Qt::AlignTop | Qt::AlignHCenter)); gridLayout->setColumnMinimumWidth(1, 15); gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 1, 1, 3, 1, Qt::AlignHCenter); gridLayout->addWidget(spaceLabel, 1, 2, Qt::AlignLeft); gridLayout->addWidget(chartSpaceToolButton, 1, 3); gridLayout->addWidget(spacerSpaceToolButton, 1, 4); gridLayout->addWidget(stereotaxicSpaceToolButton, 1, 5); gridLayout->addWidget(surfaceSpaceToolButton, 1, 6); gridLayout->addWidget(tabSpaceToolButton, 1, 7); gridLayout->addWidget(windowSpaceToolButton, 1, 8); QSpacerItem* rowSpaceItem = new QSpacerItem(5, 5, QSizePolicy::Fixed, QSizePolicy::Fixed); gridLayout->addItem(rowSpaceItem, 2, 3, 1, 7); gridLayout->addWidget(typeLabel, 3, 2, Qt::AlignLeft); gridLayout->addWidget(shapeBoxToolButton, 3, 3); gridLayout->addWidget(shapeImageToolButton, 3, 4); gridLayout->addWidget(shapeLineToolButton, 3, 5); gridLayout->addWidget(shapeOvalToolButton, 3, 6); gridLayout->addWidget(shapeTextToolButton, 3, 7); } setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); /* * Default Space to Tab * Default Shape to Text * Do this before creating action groups to avoid * triggering signals. */ m_spaceActionGroup->blockSignals(true); tabSpaceToolButton->defaultAction()->setChecked(true); m_spaceActionGroup->blockSignals(false); m_shapeActionGroup->blockSignals(true); shapeTextToolButton->defaultAction()->setChecked(true); m_shapeActionGroup->blockSignals(false); } /** * Destructor. */ AnnotationInsertNewWidget::~AnnotationInsertNewWidget() { } /** * Update the content. */ void AnnotationInsertNewWidget::updateContent() { enableDisableSpaceActions(); itemSelectedFromFileSelectionMenu(); } /** * Gets called when an item is selected from the file selection menu. */ void AnnotationInsertNewWidget::itemSelectedFromFileSelectionMenu() { /* * Add a space so that the arrow is not */ m_fileSelectionToolButtonAction->setText(m_fileSelectionMenu->getSelectedNameForToolButton()); } /** * Enable/disable space action based upon model in window. */ void AnnotationInsertNewWidget::enableDisableSpaceActions() { QSignalBlocker signalBlocker(m_spaceActionGroup); /* * Window will be invalid when this widget is being created as part of window being created */ BrainBrowserWindow* window = GuiManager::get()->getBrowserWindowByWindowIndex(m_browserWindowIndex); if (window == NULL) { return; } std::vector allTabContent; if (window->isTileTabsSelected()) { window->getAllTabContent(allTabContent); } else { BrowserTabContent* tabContent = window->getBrowserTabContent(); if (tabContent != NULL) { allTabContent.push_back(tabContent); } } const bool spacerSpaceValidFlag = window->isTileTabsSelected(); const bool tabSpaceValidFlag = ( ! allTabContent.empty()); const bool windowSpaceValidFlag = ( ! allTabContent.empty()); bool chartSpaceValidFlag = false; bool surfaceSpaceValidFlag = false; bool stereotaxicSpaceValidFlag = false; for (auto tabContent : allTabContent) { Model* model = tabContent->getModelForDisplay(); if (model == NULL) { return; } const ModelTypeEnum::Enum modelType = model->getModelType(); switch (modelType) { case ModelTypeEnum::MODEL_TYPE_CHART: break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: chartSpaceValidFlag = true; break; case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: stereotaxicSpaceValidFlag = true; surfaceSpaceValidFlag = true; break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: stereotaxicSpaceValidFlag = true; surfaceSpaceValidFlag = true; break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: stereotaxicSpaceValidFlag = true; break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: stereotaxicSpaceValidFlag = true; surfaceSpaceValidFlag = true; break; } } QAction* selectedAction = m_spaceActionGroup->checkedAction(); QAction* tabSpaceAction = NULL; QListIterator actionsIterator(m_spaceActionGroup->actions()); while (actionsIterator.hasNext()) { QAction* action = actionsIterator.next(); const int spaceInt = action->data().toInt(); bool spaceValidFlag = false; AnnotationCoordinateSpaceEnum::Enum annSpace = AnnotationCoordinateSpaceEnum::fromIntegerCode(spaceInt, &spaceValidFlag); CaretAssert(spaceValidFlag); bool enableSpaceFlag = false; switch (annSpace) { case AnnotationCoordinateSpaceEnum::CHART: enableSpaceFlag = chartSpaceValidFlag; break; case AnnotationCoordinateSpaceEnum::SPACER: enableSpaceFlag = spacerSpaceValidFlag; break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: enableSpaceFlag = stereotaxicSpaceValidFlag; break; case AnnotationCoordinateSpaceEnum::SURFACE: enableSpaceFlag = surfaceSpaceValidFlag; break; case AnnotationCoordinateSpaceEnum::TAB: tabSpaceAction = action; enableSpaceFlag = tabSpaceValidFlag; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: enableSpaceFlag = windowSpaceValidFlag; break; } action->setEnabled(enableSpaceFlag); if (action == selectedAction) { if ( ! action->isEnabled()) { selectedAction = NULL; } } } if (selectedAction == NULL) { CaretAssert(tabSpaceAction); tabSpaceAction->setChecked(true); } } /** * @return Create a file selection/menu toolbutton. */ QToolButton* AnnotationInsertNewWidget::createFileSelectionToolButton() { m_fileSelectionMenu = new AnnotationMenuFileSelection(); QObject::connect(m_fileSelectionMenu, SIGNAL(menuItemSelected()), this, SLOT(itemSelectedFromFileSelectionMenu())); m_fileSelectionToolButtonAction = new QAction(m_fileSelectionMenu->getSelectedNameForToolButton(), this); m_fileSelectionToolButtonAction->setToolTip("Choose file for new annotation"); m_fileSelectionToolButtonAction->setMenu(m_fileSelectionMenu); QToolButton* fileSelectionToolButton = new QToolButton(); fileSelectionToolButton->setDefaultAction(m_fileSelectionToolButtonAction); fileSelectionToolButton->setFixedWidth(fileSelectionToolButton->sizeHint().width()); WuQtUtilities::setToolButtonStyleForQt5Mac(fileSelectionToolButton); return fileSelectionToolButton; } /** * @return Create the shape tool button for the given annotation type. * * @param annotationType * The annotation type. * @param actionGroup * Action group to which button is added to make button exclusive. */ QToolButton* AnnotationInsertNewWidget::createShapeToolButton(const AnnotationTypeEnum::Enum annotationType, QActionGroup* actionGroup) { const QString typeGuiName = AnnotationTypeEnum::toGuiName(annotationType); QToolButton* toolButton = new QToolButton(); QAction* action = new QAction(createShapePixmap(toolButton, annotationType), typeGuiName, this); action->setData(AnnotationTypeEnum::toIntegerCode(annotationType)); action->setToolTip(typeGuiName + " annotation"); action->setCheckable(true); action->setChecked(false); toolButton->setDefaultAction(action); /* * Must set style AFTER button is added to action group * so that checked property is enabled for button */ actionGroup->addAction(action); WuQtUtilities::setToolButtonStyleForQt5Mac(toolButton); return toolButton; } /** * Called when a space or shape action triggered. */ void AnnotationInsertNewWidget::spaceOrShapeActionTriggered() { const QAction* spaceAction = m_spaceActionGroup->checkedAction(); if (spaceAction == NULL) { WuQMessageBox::errorOk(this, "No space is selected. Select a space."); return; } const QAction* shapeAction = m_shapeActionGroup->checkedAction(); if (shapeAction == NULL) { WuQMessageBox::errorOk(this, "No shape is selected. Select a shape."); return; } AnnotationFile* annotationFile = m_fileSelectionMenu->getSelectedAnnotationFile(); CaretAssert(annotationFile); CaretAssert(spaceAction); const int spaceInt = spaceAction->data().toInt(); bool spaceValidFlag = false; AnnotationCoordinateSpaceEnum::Enum annSpace = AnnotationCoordinateSpaceEnum::fromIntegerCode(spaceInt, &spaceValidFlag); CaretAssert(spaceValidFlag); CaretAssert(shapeAction); const int shapeInt = shapeAction->data().toInt(); bool shapeValidFlag = false; AnnotationTypeEnum::Enum annShape = AnnotationTypeEnum::fromIntegerCode(shapeInt, &shapeValidFlag); CaretAssert(shapeValidFlag); DisplayPropertiesAnnotation* dpa = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotation(); dpa->setDisplayAnnotations(true); EventManager::get()->sendEvent(EventAnnotationCreateNewType(annotationFile, annSpace, annShape).getPointer()); } /** * Create a pixmap for the given annotation shape type. * * @param widget * To color the pixmap with backround and foreground, * the palette from the given widget is used. * @param annotationType * The annotation type. * @return * Pixmap with icon for the given annotation type. */ QPixmap AnnotationInsertNewWidget::createShapePixmap(const QWidget* widget, const AnnotationTypeEnum::Enum annotationType) { CaretAssert(widget); /* * Create a small, square pixmap that will contain * the foreground color around the pixmap's perimeter. */ const float width = 24.0; const float height = 24.0; QPixmap pixmap(static_cast(width), static_cast(height)); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainter(widget, pixmap); /** * NOTE: ORIGIN is in TOP LEFT corner of pixmap. */ switch (annotationType) { case AnnotationTypeEnum::BOX: painter->drawRect(1, 1, width - 2, height - 2); break; case AnnotationTypeEnum::COLOR_BAR: CaretAssertMessage(0, "No pixmap for colorbar as user does not create them like other annotations"); break; case AnnotationTypeEnum::IMAGE: { const int blueAsGray = qGray(25,25,255); QColor skyColor(blueAsGray, blueAsGray, blueAsGray); /* * Background (sky) */ painter->fillRect(pixmap.rect(), skyColor); const int greenAsGray = qGray(0, 255, 0); QColor terrainColor(greenAsGray, greenAsGray, greenAsGray); /* * Terrain */ painter->setBrush(terrainColor); painter->setPen(terrainColor); const int w14 = width * 0.25; const int h23 = height * 0.667; const int h34 = height * 0.75; QPolygon terrain; terrain.push_back(QPoint(1, height - 1)); terrain.push_back(QPoint(width - 1, height - 1)); terrain.push_back(QPoint(width - 1, h23)); terrain.push_back(QPoint(w14 * 3, h34)); terrain.push_back(QPoint(w14 * 2, h23)); terrain.push_back(QPoint(w14, h34)); terrain.push_back(QPoint(1, h23)); terrain.push_back(QPoint(1, height - 1)); painter->drawPolygon(terrain); const int yellowAsGray = qGray(255, 255, 0); QColor sunColor(yellowAsGray, yellowAsGray, yellowAsGray); /* * Sun */ painter->setBrush(sunColor); painter->setPen(sunColor); const int radius = width * 0.25; painter->drawEllipse(width * 0.33, height * 0.33, radius, radius); } break; case AnnotationTypeEnum::LINE: painter->drawLine(1, height - 1, width - 1, 1); break; case AnnotationTypeEnum::OVAL: painter->drawEllipse(1, 1, width - 1, height - 1); break; case AnnotationTypeEnum::TEXT: { QFont font = painter->font(); font.setPixelSize(20); painter->setFont(font); painter->drawText(pixmap.rect(), (Qt::AlignCenter), "A"); } break; } return pixmap; } /** * @return Create the space tool button for the given annotation space. * * @param annotationSpace * The annotation space * @param actionGroup * Action group to which button is added to make button exclusive. */ QToolButton* AnnotationInsertNewWidget::createSpaceToolButton(const AnnotationCoordinateSpaceEnum::Enum annotationSpace, QActionGroup* actionGroup) { switch (annotationSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssertMessage(0, "Annotations in viewport space not supported."); break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } const bool useIconFlag = true; QToolButton* toolButton = new QToolButton(); QAction* action = NULL; if (useIconFlag) { action = new QAction(createSpacePixmap(toolButton, annotationSpace), AnnotationCoordinateSpaceEnum::toGuiAbbreviatedName(annotationSpace), this); } else { action = new QAction(AnnotationCoordinateSpaceEnum::toGuiAbbreviatedName(annotationSpace), this); } action->setData((int)AnnotationCoordinateSpaceEnum::toIntegerCode(annotationSpace)); action->setToolTip(AnnotationCoordinateSpaceEnum::toToolTip(annotationSpace)); action->setCheckable(true); action->setChecked(false); toolButton->setDefaultAction(action); /* * Must set style AFTER button is added to action group * so that checked property is enabled for button */ actionGroup->addAction(action); WuQtUtilities::setToolButtonStyleForQt5Mac(toolButton); return toolButton; } /** * Create a pixmap for the given annotation coordinate space * * @param widget * To color the pixmap with backround and foreground, * the palette from the given widget is used. * @param annotationSpace * The annotation coordinate space. * @return * Pixmap with icon for the given annotation coordinate space. */ QPixmap AnnotationInsertNewWidget::createSpacePixmap(const QWidget* widget, const AnnotationCoordinateSpaceEnum::Enum annotationSpace) { CaretAssert(widget); /* * Create a small, square pixmap that will contain * the foreground color around the pixmap's perimeter. */ const float width = 24.0; const float height = 24.0; QPixmap pixmap(static_cast(width), static_cast(height)); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainter(widget, pixmap); /** * NOTE: ORIGIN is in TOP LEFT corner of pixmap. */ switch (annotationSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssertMessage(0, "Annotations in viewport space not supported."); break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } const QString letter = AnnotationCoordinateSpaceEnum::toGuiAbbreviatedName(annotationSpace); QFont font = painter->font(); font.setPixelSize(20); painter->setFont(font); painter->drawText(pixmap.rect(), (Qt::AlignCenter), letter); return pixmap; } connectome-workbench-1.4.2/src/GuiQt/AnnotationInsertNewWidget.h000066400000000000000000000061441360521144700247460ustar00rootroot00000000000000#ifndef __ANNOTATION_INSERT_NEW_WIDGET_H__ #define __ANNOTATION_INSERT_NEW_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AnnotationCoordinateSpaceEnum.h" #include "AnnotationTypeEnum.h" class QActionGroup; class QToolButton; namespace caret { class AnnotationMenuFileSelection; class AnnotationInsertNewWidget : public QWidget { Q_OBJECT public: AnnotationInsertNewWidget(const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~AnnotationInsertNewWidget(); // ADD_NEW_METHODS_HERE void updateContent(); private slots: void itemSelectedFromFileSelectionMenu(); void spaceOrShapeActionTriggered(); private: AnnotationInsertNewWidget(const AnnotationInsertNewWidget&); AnnotationInsertNewWidget& operator=(const AnnotationInsertNewWidget&); QToolButton* createShapeToolButton(const AnnotationTypeEnum::Enum annotationType, QActionGroup* actionGroup); QToolButton* createSpaceToolButton(const AnnotationCoordinateSpaceEnum::Enum annotationSpace, QActionGroup* actionGroup); QPixmap createShapePixmap(const QWidget* widget, const AnnotationTypeEnum::Enum annotationType); QPixmap createSpacePixmap(const QWidget* widget, const AnnotationCoordinateSpaceEnum::Enum annotationSpace); QToolButton* createFileSelectionToolButton(); void enableDisableSpaceActions(); const int32_t m_browserWindowIndex; QActionGroup* m_spaceActionGroup; QActionGroup* m_shapeActionGroup; QAction* m_fileSelectionToolButtonAction; AnnotationMenuFileSelection* m_fileSelectionMenu; static AString s_previousImageFileDirectory; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_INSERT_NEW_WIDGET_DECLARE__ AString AnnotationInsertNewWidget::s_previousImageFileDirectory; #endif // __ANNOTATION_INSERT_NEW_WIDGET_DECLARE__ } // namespace #endif //__ANNOTATION_INSERT_NEW_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationLineArrowTipsWidget.cxx000066400000000000000000000210651360521144700261440ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_LINE_ARROW_TIPS_WIDGET_DECLARE__ #include "AnnotationLineArrowTipsWidget.h" #undef __ANNOTATION_LINE_ARROW_TIPS_WIDGET_DECLARE__ #include #include #include #include #include #include "AnnotationLine.h" #include "AnnotationManager.h" #include "AnnotationRedoUndoCommand.h" #include "Brain.h" #include "CaretAssert.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "GuiManager.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AnnotationLineArrowTipsWidget * \brief Widget for enabling/disabling line arrow tips * \ingroup GuiQt */ /** * Constructor. */ AnnotationLineArrowTipsWidget::AnnotationLineArrowTipsWidget(const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { QLabel* label = new QLabel("Line"); QToolButton* endArrowToolButton = new QToolButton(); m_endArrowAction = new QAction(this); m_endArrowAction->setCheckable(true); m_endArrowAction->setToolTip("Show arrow at line's end coordinate"); m_endArrowAction->setIcon(QIcon(createArrowPixmap(endArrowToolButton, ArrowType::DOWN))); QObject::connect(m_endArrowAction, &QAction::triggered, this, &AnnotationLineArrowTipsWidget::endArrowTipActionToggled); endArrowToolButton->setDefaultAction(m_endArrowAction); WuQtUtilities::setToolButtonStyleForQt5Mac(endArrowToolButton); QToolButton* startArrowToolButton = new QToolButton(); m_startArrowAction = new QAction(this); m_startArrowAction->setCheckable(true); m_startArrowAction->setToolTip("Show arrow at line's start coordinate"); m_startArrowAction->setIcon(QIcon(createArrowPixmap(startArrowToolButton, ArrowType::UP))); QObject::connect(m_startArrowAction, &QAction::triggered, this, &AnnotationLineArrowTipsWidget::startArrowTipActionToggled); startArrowToolButton->setDefaultAction(m_startArrowAction); WuQtUtilities::setToolButtonStyleForQt5Mac(startArrowToolButton); QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 0); gridLayout->addWidget(label, 0, 0, Qt::AlignHCenter); gridLayout->addWidget(startArrowToolButton, 1, 0, Qt::AlignHCenter); gridLayout->addWidget(endArrowToolButton, 2, 0, Qt::AlignHCenter); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } /** * Destructor. */ AnnotationLineArrowTipsWidget::~AnnotationLineArrowTipsWidget() { } /** * Update with the given line annotation. * * @param annotationLines */ void AnnotationLineArrowTipsWidget::updateContent(std::vector& annotationLines) { m_annotations.clear(); m_annotations.reserve(annotationLines.size()); for (auto a : annotationLines) { if (a->testProperty(Annotation::Property::LINE_ARROWS)) { m_annotations.push_back(a); } } bool allStartOnFlag = true; bool allEndOnFlag = true; const int32_t numLines = static_cast(annotationLines.size()); for (int32_t i = 0; i < numLines; i++) { CaretAssertVectorIndex(annotationLines, i); if ( ! annotationLines[i]->isDisplayStartArrow()) { allStartOnFlag = false; } if ( ! annotationLines[i]->isDisplayEndArrow()) { allEndOnFlag = false; } } if (numLines <= 0) { allStartOnFlag = false; allEndOnFlag = false; } m_startArrowAction->setChecked(allStartOnFlag); m_endArrowAction->setChecked(allEndOnFlag); if (numLines > 0) { setEnabled(true); AnnotationLine::setUserDefaultDisplayStartArrow(m_startArrowAction->isChecked()); AnnotationLine::setUserDefaultDisplayEndArrow(m_endArrowAction->isChecked()); } else { setEnabled(false); } } /** * Gets called when the line arrow start buttons is toggled. */ void AnnotationLineArrowTipsWidget::startArrowTipActionToggled() { AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeLineArrowStart(m_startArrowAction->isChecked(), m_annotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); AnnotationLine::setUserDefaultDisplayStartArrow(m_startArrowAction->isChecked()); } /** * Gets called when the line arrow end buttons is toggled. */ void AnnotationLineArrowTipsWidget::endArrowTipActionToggled() { AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeLineArrowEnd(m_endArrowAction->isChecked(), m_annotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); AnnotationLine::setUserDefaultDisplayEndArrow(m_endArrowAction->isChecked()); } /** * Create a pixmap for the given arrow type type. * * @param widget * To color the pixmap with backround and foreground, * the palette from the given widget is used. * @param arrowType * The arrow type. * @return * Pixmap with icon for the given arrow type. */ QPixmap AnnotationLineArrowTipsWidget::createArrowPixmap(const QWidget* widget, const ArrowType arrowType) { CaretAssert(widget); /* * Create a small, square pixmap that will contain * the foreground color around the pixmap's perimeter. */ const float width = 24.0; const float height = 24.0; QPixmap pixmap(static_cast(width), static_cast(height)); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginBottomLeft(widget, pixmap); const bool fillShapeFlag = false; if (fillShapeFlag) { QBrush brush = painter->brush(); brush.setColor(painter->pen().color()); brush.setStyle(Qt::SolidPattern); painter->setBrush(brush); } const float percentage = 0.10f; const float left = width * percentage; const float right = width * (1.0 - percentage); const float bottom = height * percentage; const float top = height * (1.0 - percentage); const float centerX = width * 0.5; QPolygonF triangle; switch (arrowType) { case ArrowType::DOWN: triangle.push_back(QPointF(right, top)); triangle.push_back(QPointF(left, top)); triangle.push_back(QPointF(centerX, bottom)); break; case ArrowType::UP: triangle.push_back(QPointF(left, bottom)); triangle.push_back(QPointF(right, bottom)); triangle.push_back(QPointF(centerX, top)); break; } painter->drawPolygon(triangle); return pixmap; } connectome-workbench-1.4.2/src/GuiQt/AnnotationLineArrowTipsWidget.h000066400000000000000000000046311360521144700255710ustar00rootroot00000000000000#ifndef __ANNOTATION_LINE_ARROW_TIPS_WIDGET_H__ #define __ANNOTATION_LINE_ARROW_TIPS_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include namespace caret { class Annotation; class AnnotationLine; class AnnotationLineArrowTipsWidget : public QWidget { Q_OBJECT public: AnnotationLineArrowTipsWidget(const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~AnnotationLineArrowTipsWidget(); void updateContent(std::vector& annotationLines); private slots: void startArrowTipActionToggled(); void endArrowTipActionToggled(); // ADD_NEW_METHODS_HERE private: enum class ArrowType { DOWN, UP }; AnnotationLineArrowTipsWidget(const AnnotationLineArrowTipsWidget&); AnnotationLineArrowTipsWidget& operator=(const AnnotationLineArrowTipsWidget&); QPixmap createArrowPixmap(const QWidget* widget, const ArrowType arrowType); const int32_t m_browserWindowIndex; QAction* m_startArrowAction; QAction* m_endArrowAction; std::vector m_annotations; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_LINE_ARROW_TIPS_WIDGET_DECLARE__ // #endif // __ANNOTATION_LINE_ARROW_TIPS_WIDGET_DECLARE__ } // namespace #endif //__ANNOTATION_LINE_ARROW_TIPS_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationMenuArrange.cxx000066400000000000000000000606741360521144700244530ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_MENU_ARRANGE_DECLARE__ #include "AnnotationMenuArrange.h" #undef __ANNOTATION_MENU_ARRANGE_DECLARE__ #include #include "Annotation.h" #include "AnnotationArrangerInputs.h" #include "AnnotationManager.h" #include "Brain.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "DisplayPropertiesAnnotationTextSubstitution.h" #include "EventAnnotationGrouping.h" #include "EventGetBrainOpenGLTextRenderer.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "GuiManager.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AnnotationMenuArrange * \brief Menu for arranging annotations. * \ingroup GuiQt */ /** * Constructor. * * @param parent * The parent widget. * @param browserWindowIndex * Index of the browser window. */ AnnotationMenuArrange::AnnotationMenuArrange(const int32_t browserWindowIndex, QWidget* parent) : QMenu(parent), m_browserWindowIndex(browserWindowIndex) { addAlignmentSelections(); addSeparator(); addDistributeSelections(); addSeparator(); addGroupingSelections(); QObject::connect(this, SIGNAL(aboutToShow()), this, SLOT(menuAboutToShow())); QObject::connect(this, SIGNAL(triggered(QAction*)), this, SLOT(menuActionTriggered(QAction*))); } /** * Destructor. */ AnnotationMenuArrange::~AnnotationMenuArrange() { } /** * Add alignment options to the menu. */ void AnnotationMenuArrange::addAlignmentSelections() { std::vector alignments; AnnotationAlignmentEnum::getAllEnums(alignments); for (std::vector::iterator iter = alignments.begin(); iter != alignments.end(); iter++) { const AnnotationAlignmentEnum::Enum annAlign = *iter; const QString enumText = AnnotationAlignmentEnum::toGuiName(annAlign); const QString enumName = AnnotationAlignmentEnum::toName(annAlign); QPixmap pixmap = createAlignmentPixmap(this, annAlign); QAction* action = addAction(enumText); action->setIcon(pixmap); action->setData(enumName); } } /** * Add distribution items to the menu. */ void AnnotationMenuArrange::addDistributeSelections() { std::vector distributes; AnnotationDistributeEnum::getAllEnums(distributes); for (std::vector::iterator iter = distributes.begin(); iter != distributes.end(); iter++) { const AnnotationDistributeEnum::Enum annDist = *iter; const QString enumText = AnnotationDistributeEnum::toGuiName(annDist); const QString enumName = AnnotationDistributeEnum::toName(annDist); QPixmap pixmap = createDistributePixmap(this, annDist); QAction* action = addAction(enumText); action->setIcon(pixmap); action->setData(enumName); } } /** * Add distribution items to the menu. */ void AnnotationMenuArrange::addGroupingSelections() { m_groupAction = NULL; m_regroupAction = NULL; m_ungroupAction = NULL; std::vector groupings; AnnotationGroupingModeEnum::getAllEnums(groupings); for (std::vector::iterator iter = groupings.begin(); iter != groupings.end(); iter++) { const AnnotationGroupingModeEnum::Enum groupingMode = *iter; const QString enumText = AnnotationGroupingModeEnum::toGuiName(groupingMode); const QString enumName = AnnotationGroupingModeEnum::toName(groupingMode); QPixmap pixmap = createGroupingPixmap(this, groupingMode); QAction* action = addAction(enumText); action->setIcon(pixmap); action->setData(enumName); switch (groupingMode) { case AnnotationGroupingModeEnum::GROUP: m_groupAction = action; break; case AnnotationGroupingModeEnum::REGROUP: m_regroupAction = action; break; case AnnotationGroupingModeEnum::UNGROUP: m_ungroupAction = action; break; } } CaretAssert(m_groupAction); CaretAssert(m_regroupAction); CaretAssert(m_ungroupAction); } /* * Gets called when the menu is about to show * so that its menu items can be enabled/disabled. */ void AnnotationMenuArrange::menuAboutToShow() { AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); m_groupAction->setEnabled(annMan->isGroupingModeValid(m_browserWindowIndex, AnnotationGroupingModeEnum::GROUP)); m_regroupAction->setEnabled(annMan->isGroupingModeValid(m_browserWindowIndex, AnnotationGroupingModeEnum::REGROUP)); m_ungroupAction->setEnabled(annMan->isGroupingModeValid(m_browserWindowIndex, AnnotationGroupingModeEnum::UNGROUP)); } /** * Gets called when the user selects a menu item. */ void AnnotationMenuArrange::menuActionTriggered(QAction* action) { CaretAssert(action); const QString enumName = action->data().toString(); bool validAlignmentFlag = false; const AnnotationAlignmentEnum::Enum annAlign = AnnotationAlignmentEnum::fromName(enumName, &validAlignmentFlag); bool validDistributeFlag = false; const AnnotationDistributeEnum::Enum annDist = AnnotationDistributeEnum::fromName(enumName, &validDistributeFlag); bool validGroupingFlag = false; const AnnotationGroupingModeEnum::Enum annGroup = AnnotationGroupingModeEnum::fromName(enumName, &validGroupingFlag); if (validAlignmentFlag) { applyAlignment(annAlign); } else if (validDistributeFlag) { applyDistribute(annDist); } else if (validGroupingFlag) { applyGrouping(annGroup); } else { const AString msg("Unrecognized Enum name in Annotation Align Menu \"" + enumName + "\""); CaretAssertMessage(0, msg); CaretLogSevere(msg); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Apply alignment selection. * * @param alignment * Selected alignment. */ void AnnotationMenuArrange::applyAlignment(const AnnotationAlignmentEnum::Enum alignment) { EventGetBrainOpenGLTextRenderer textRendererEvent; EventManager::get()->sendEvent(textRendererEvent.getPointer()); BrainOpenGLTextRenderInterface* textRenderer = textRendererEvent.getTextRenderer(); if (textRenderer == NULL) { WuQMessageBox::errorOk(this, "Failed to get text renderer for window " + QString::number(m_browserWindowIndex)); return; } DisplayPropertiesAnnotationTextSubstitution* dpats = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotationTextSubstitution(); BrainOpenGLTextRenderInterface::DrawingFlags drawingFlags; drawingFlags.setDrawSubstitutedText(dpats->isEnableSubstitutions()); AnnotationArrangerInputs alignMod(textRenderer, drawingFlags, m_browserWindowIndex); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->alignAnnotations(alignMod, alignment, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Apply distribute selection. * * @param distribute * Selected distribute. */ void AnnotationMenuArrange::applyDistribute(const AnnotationDistributeEnum::Enum distribute) { EventGetBrainOpenGLTextRenderer textRendererEvent; EventManager::get()->sendEvent(textRendererEvent.getPointer()); BrainOpenGLTextRenderInterface* textRenderer = textRendererEvent.getTextRenderer(); if (textRenderer == NULL) { WuQMessageBox::errorOk(this, "Failed to get text renderer for window " + QString::number(m_browserWindowIndex)); return; } DisplayPropertiesAnnotationTextSubstitution* dpats = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotationTextSubstitution(); BrainOpenGLTextRenderInterface::DrawingFlags drawingFlags; drawingFlags.setDrawSubstitutedText(dpats->isEnableSubstitutions()); AnnotationArrangerInputs distributeMod(textRenderer, drawingFlags, m_browserWindowIndex); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->distributeAnnotations(distributeMod, distribute, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Apply grouping selection. * * @param grouping * Selected grouping. */ void AnnotationMenuArrange::applyGrouping(const AnnotationGroupingModeEnum::Enum grouping) { AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyGroupingMode(m_browserWindowIndex, grouping, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Create an alignment pixmap. * * @param widget * To color the pixmap with backround and foreground, * the palette from the given widget is used. * @param alignment * The alignment. * @return * Pixmap with icon for the given alignment. */ QPixmap AnnotationMenuArrange::createAlignmentPixmap(const QWidget* widget, const AnnotationAlignmentEnum::Enum alignment) { CaretAssert(widget); const float pixmapSize = 24.0; const float halfPixmapSize = pixmapSize / 2.0; QPixmap pixmap(static_cast(pixmapSize), static_cast(pixmapSize)); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginBottomLeft(widget, pixmap); const qreal minInset = 2; const qreal minInset2 = minInset * 2; const qreal minInset3 = minInset * 3; const qreal maxInset = pixmapSize - minInset; const QLineF horizontalLine(minInset, 0.0, maxInset, 0.0); const QLineF verticalLine(0.0, minInset, 0.0, maxInset); const qreal rectangleThickness = pixmapSize * 0.25; const qreal longRectangleLength = pixmapSize - (minInset * 4); const qreal shortRectangleLength = longRectangleLength * 0.60; const QRectF longVerticalRectangle(QPointF(0.0, 0.0), QPointF(rectangleThickness, longRectangleLength)); const QRectF shortVerticalRectangle(QPointF(0.0, 0.0), QPointF(rectangleThickness, shortRectangleLength)); const qreal shortVerticalRectangleOffset = pixmapSize - minInset2 - rectangleThickness; const QRectF longHorizontalRectangle(QPointF(0.0, 0.0), QPointF(longRectangleLength, rectangleThickness)); const QRectF shortHorizontalRectangle(QPointF(0.0, 0.0), QPointF(shortRectangleLength, rectangleThickness)); const qreal longRectangleSpace = pixmapSize - longRectangleLength; const qreal shortRectangleSpace = pixmapSize - shortRectangleLength; QBrush foregroundBrush = widget->palette().brush(widget->foregroundRole()); QPen foregroundPen = painter->pen(); QColor foregroundColor = widget->palette().brush(widget->foregroundRole()).color(); switch (alignment) { case AnnotationAlignmentEnum::ALIGN_BOTTOM: drawLine(painter, horizontalLine, 0.0, minInset); drawRect(painter, foregroundColor, longVerticalRectangle, minInset2, minInset3); drawRect(painter, foregroundColor, shortVerticalRectangle, shortVerticalRectangleOffset, minInset3); break; case AnnotationAlignmentEnum::ALIGN_CENTER: drawLine(painter, verticalLine, halfPixmapSize, 0.0); drawRect(painter, foregroundColor, longHorizontalRectangle, (longRectangleSpace / 2.0), minInset2); drawRect(painter, foregroundColor, shortHorizontalRectangle, (shortRectangleSpace / 2.0), shortVerticalRectangleOffset); break; case AnnotationAlignmentEnum::ALIGN_LEFT: drawLine(painter, verticalLine, minInset, 0.0); drawRect(painter, foregroundColor, longHorizontalRectangle, minInset3, minInset2); drawRect(painter, foregroundColor, shortHorizontalRectangle, minInset3, shortVerticalRectangleOffset); break; case AnnotationAlignmentEnum::ALIGN_MIDDLE: drawLine(painter, horizontalLine, 0.0, halfPixmapSize); drawRect(painter, foregroundColor, longVerticalRectangle, minInset2, (longRectangleSpace / 2.0)); drawRect(painter, foregroundColor, shortVerticalRectangle, shortVerticalRectangleOffset, (shortRectangleSpace / 2.0)); break; case AnnotationAlignmentEnum::ALIGN_RIGHT: drawLine(painter, verticalLine, maxInset, 0.0); drawRect(painter, foregroundColor, longHorizontalRectangle, (longRectangleSpace - minInset3), minInset2); drawRect(painter, foregroundColor, shortHorizontalRectangle, (shortRectangleSpace - minInset3), shortVerticalRectangleOffset); break; case AnnotationAlignmentEnum::ALIGN_TOP: drawLine(painter, horizontalLine, 0.0, maxInset); drawRect(painter, foregroundColor, longVerticalRectangle, minInset2, (longRectangleSpace - minInset3)); drawRect(painter, foregroundColor, shortVerticalRectangle, shortVerticalRectangleOffset, (shortRectangleSpace - minInset3)); break; } return pixmap; } /** * Create a distribute pixmap. * * @param widget * To color the pixmap with backround and foreground, * the palette from the given widget is used. * @param distribute * The distribute type. * @return * Pixmap with icon for the given distribute. */ QPixmap AnnotationMenuArrange::createDistributePixmap(const QWidget* widget, const AnnotationDistributeEnum::Enum distribute) { CaretAssert(widget); const float pixmapSize = 24.0; const float halfPixmapSize = pixmapSize / 2.0; QPixmap pixmap(static_cast(pixmapSize), static_cast(pixmapSize)); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginBottomLeft(widget, pixmap); const qreal minInset = 2; const qreal minInset2 = minInset * 2; const qreal minInset3 = minInset * 3; const qreal maxInset = pixmapSize - minInset; const QLineF horizontalLine(minInset, 0.0, maxInset, 0.0); const QLineF verticalLine(0.0, minInset, 0.0, maxInset); const qreal rectangleThickness = pixmapSize * 0.15; const qreal longRectangleLength = pixmapSize - (minInset3 * 2); const qreal shortRectangleLength = longRectangleLength * 0.50; const qreal midSizeRectangleLength = longRectangleLength * 0.75; const QRectF longVerticalRectangle(QPointF(0.0, 0.0), QPointF(rectangleThickness, longRectangleLength)); const QRectF midSizeVerticalRectangle(QPointF(0.0, 0.0), QPointF(rectangleThickness, midSizeRectangleLength)); const QRectF shortVerticalRectangle(QPointF(0.0, 0.0), QPointF(rectangleThickness, shortRectangleLength)); const qreal shortVerticalRectangleOffset = halfPixmapSize - (rectangleThickness / 2.0); const qreal midSizeVerticalRectangleOffset = pixmapSize - minInset2 - rectangleThickness; const QRectF longHorizontalRectangle(QPointF(0.0, 0.0), QPointF(longRectangleLength, rectangleThickness)); const QRectF midSizeHorizontalRectangle(QPointF(0.0, 0.0), QPointF(midSizeRectangleLength, rectangleThickness)); const QRectF shortHorizontalRectangle(QPointF(0.0, 0.0), QPointF(shortRectangleLength, rectangleThickness)); const qreal shortRectangleSpace = pixmapSize - shortRectangleLength; const qreal midSizeRectangleSpace = pixmapSize - midSizeRectangleLength; QBrush foregroundBrush = widget->palette().brush(widget->foregroundRole()); QPen foregroundPen = painter->pen(); QColor foregroundColor = widget->palette().brush(widget->foregroundRole()).color(); switch (distribute) { case AnnotationDistributeEnum::HORIZONTALLY: drawLine(painter, horizontalLine, 0.0, maxInset); drawLine(painter, horizontalLine, 0.0, minInset); drawRect(painter, foregroundColor, longVerticalRectangle, minInset2, minInset3); drawRect(painter, foregroundColor, shortVerticalRectangle, shortVerticalRectangleOffset, (shortRectangleSpace / 2.0)); drawRect(painter, foregroundColor, midSizeVerticalRectangle, midSizeVerticalRectangleOffset, (midSizeRectangleSpace / 2.0)); break; case AnnotationDistributeEnum::VERTICALLY: drawLine(painter, verticalLine, minInset, 0.0); drawLine(painter, verticalLine, maxInset, 0.0); drawRect(painter, foregroundColor, longHorizontalRectangle, minInset3, minInset2); drawRect(painter, foregroundColor, shortHorizontalRectangle, (shortRectangleSpace / 2.0), shortVerticalRectangleOffset); drawRect(painter, foregroundColor, midSizeHorizontalRectangle, (midSizeRectangleSpace / 2.0), midSizeVerticalRectangleOffset); break; } return pixmap; } /** * Create a grouping pixmap. * * @param widget * To color the pixmap with backround and foreground, * the palette from the given widget is used. * @param grouping * The grouping type. * @return * Pixmap with icon for the given grouping. */ QPixmap AnnotationMenuArrange::createGroupingPixmap(const QWidget* widget, const AnnotationGroupingModeEnum::Enum grouping) { CaretAssert(widget); const float pixmapSize = 24.0; QPixmap pixmap(static_cast(pixmapSize), static_cast(pixmapSize)); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginCenter100x100(widget, pixmap); const float xyOne = 75.0; const float xyTwo = 25.0; const float boxSize = 100.0; painter->drawRect(-xyOne, -xyTwo, boxSize, boxSize); painter->drawRect(-xyTwo, -xyOne, boxSize, boxSize); QColor foregroundColor = widget->palette().brush(widget->foregroundRole()).color(); painter->setBrush(foregroundColor); const float dotSize = 20.0; switch (grouping) { case AnnotationGroupingModeEnum::GROUP: painter->drawEllipse(QPointF(-xyOne, -xyOne), dotSize, dotSize); painter->drawEllipse(QPointF( xyOne, -xyOne), dotSize, dotSize); painter->drawEllipse(QPointF( xyOne, xyOne), dotSize, dotSize); painter->drawEllipse(QPointF(-xyOne, xyOne), dotSize, dotSize); break; case AnnotationGroupingModeEnum::REGROUP: painter->drawEllipse(QPointF(-xyOne, -xyOne), dotSize, dotSize); painter->drawEllipse(QPointF( xyOne, -xyOne), dotSize, dotSize); painter->drawEllipse(QPointF( xyOne, xyOne), dotSize, dotSize); painter->drawEllipse(QPointF(-xyOne, xyOne), dotSize, dotSize); if (grouping == AnnotationGroupingModeEnum::REGROUP) { QVector points; points.push_back(QPoint(-100, -10)); points.push_back(QPoint( 10, -10)); points.push_back(QPoint( 10, -50)); points.push_back(QPoint( 80, 0)); points.push_back(QPoint( 10, 50)); points.push_back(QPoint( 10, 10)); points.push_back(QPoint(-100, 10)); points.push_back(QPoint(-100, -10)); painter->drawPolygon(QPolygon(points)); } break; case AnnotationGroupingModeEnum::UNGROUP: painter->drawEllipse(QPointF(-xyTwo, -xyOne), dotSize, dotSize); painter->drawEllipse(QPointF(-xyTwo + boxSize, -xyOne), dotSize, dotSize); painter->drawEllipse(QPointF(-xyTwo + boxSize, -xyOne + boxSize), dotSize, dotSize); painter->drawEllipse(QPointF(-xyTwo, -xyOne + boxSize), dotSize, dotSize); painter->drawEllipse(QPointF(-xyOne, -xyTwo), dotSize, dotSize); painter->drawEllipse(QPointF(-xyOne + boxSize, -xyTwo), dotSize, dotSize); painter->drawEllipse(QPointF(-xyOne + boxSize, -xyTwo + boxSize), dotSize, dotSize); painter->drawEllipse(QPointF(-xyOne, -xyTwo + boxSize), dotSize, dotSize); break; } return pixmap; } /** * Draw a line at the given X,Y using the painter. * * @param painter * The painter. * @param line * The line * @param x * Translate to X. * @param y * Translate to Y. */ void AnnotationMenuArrange::drawLine(QSharedPointer& painter, const QLineF& line, const qreal x, const qreal y) { painter->save(); painter->translate(x, y); painter->drawLine(line); painter->restore(); } /** * Draw a filled rectangle at the given X,Y using the painter and in the given color. * * @param painter * The painter. * @param color * Color of filled rectangle. * @param rectangle * The rectangle * @param x * Translate to X. * @param y * Translate to Y. */ void AnnotationMenuArrange::drawRect(QSharedPointer& painter, const QColor& color, const QRectF& rectangle, const qreal x, const qreal y) { painter->save(); painter->translate(x, y); painter->fillRect(rectangle, color); painter->restore(); } connectome-workbench-1.4.2/src/GuiQt/AnnotationMenuArrange.h000066400000000000000000000064561360521144700240760ustar00rootroot00000000000000#ifndef __ANNOTATION_MENU_ARRANGE_H__ #define __ANNOTATION_MENU_ARRANGE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AnnotationAlignmentEnum.h" #include "AnnotationDistributeEnum.h" #include "AnnotationGroupingModeEnum.h" namespace caret { class AnnotationMenuArrange : public QMenu { Q_OBJECT public: AnnotationMenuArrange(const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~AnnotationMenuArrange(); // ADD_NEW_METHODS_HERE private slots: void menuActionTriggered(QAction* action); void menuAboutToShow(); private: void addAlignmentSelections(); void addDistributeSelections(); void addGroupingSelections(); void applyAlignment(const AnnotationAlignmentEnum::Enum alignment); void applyDistribute(const AnnotationDistributeEnum::Enum distribute); void applyGrouping(const AnnotationGroupingModeEnum::Enum grouping); AnnotationMenuArrange(const AnnotationMenuArrange&); AnnotationMenuArrange& operator=(const AnnotationMenuArrange&); QPixmap createAlignmentPixmap(const QWidget* widget, const AnnotationAlignmentEnum::Enum alignment); QPixmap createDistributePixmap(const QWidget* widget, const AnnotationDistributeEnum::Enum distribute); QPixmap createGroupingPixmap(const QWidget* widget, const AnnotationGroupingModeEnum::Enum grouping); void drawLine(QSharedPointer& painter, const QLineF& line, const qreal x, const qreal y); void drawRect(QSharedPointer& painter, const QColor& color, const QRectF& rectangle, const qreal x, const qreal y); const int32_t m_browserWindowIndex; QAction* m_groupAction; QAction* m_regroupAction; QAction* m_ungroupAction; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_MENU_ARRANGE_DECLARE__ // #endif // __ANNOTATION_MENU_ARRANGE_DECLARE__ } // namespace #endif //__ANNOTATION_MENU_ARRANGE_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationMenuFileSelection.cxx000066400000000000000000000144431360521144700256120ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_MENU_FILE_SELECTION_DECLARE__ #include "AnnotationMenuFileSelection.h" #undef __ANNOTATION_MENU_FILE_SELECTION_DECLARE__ #include "AnnotationFile.h" #include "Brain.h" #include "CaretAssert.h" #include "CaretFileDialog.h" #include "EventDataFileAdd.h" #include "EventManager.h" #include "GuiManager.h" using namespace caret; /** * \class caret::AnnotationMenuFileSelection * \brief Menu for selecting an annotation file. * \ingroup GuiQt */ /** * Constructor. * * @param parent * The parent widget. */ AnnotationMenuFileSelection::AnnotationMenuFileSelection(QWidget* parent) : QMenu(parent) { m_selectedAnnotationFile = NULL; QObject::connect(this, SIGNAL(aboutToShow()), this, SLOT(updateMenuContents())); QObject::connect(this, SIGNAL(triggered(QAction*)), this, SLOT(menuActionSelected(QAction*))); } /** * Destructor. */ AnnotationMenuFileSelection::~AnnotationMenuFileSelection() { } /** * @return The selected annotation file or NULL if no * annotation file is selected. */ AnnotationFile* AnnotationMenuFileSelection::getSelectedAnnotationFile() { /* * Ensures selected file is valid */ updateMenuContents(); return m_selectedAnnotationFile; } /** * @return The selected annotation file or NULL if no * annotation file is selected. */ AString AnnotationMenuFileSelection::getSelectedNameForToolButton() { AString name("Scene"); AnnotationFile* annFile = getSelectedAnnotationFile(); if (annFile != NULL) { if (annFile == GuiManager::get()->getBrain()->getSceneAnnotationFile()) { name = "Scene"; } else { name = "Disk "; } } return name; } /** * Called to create a new disk file. */ void AnnotationMenuFileSelection::chooseDiskFile() { const AString fileDialogSettingsName("AnnotDiskFileDialog"); /* * Setup file selection dialog. */ CaretFileDialog fd(this); fd.setAcceptMode(CaretFileDialog::AcceptSave); fd.setNameFilter(DataFileTypeEnum::toQFileDialogFilter(DataFileTypeEnum::ANNOTATION)); fd.setFileMode(CaretFileDialog::AnyFile); fd.setViewMode(CaretFileDialog::List); fd.setLabelText(CaretFileDialog::Accept, "Choose"); // OK button shows Insert fd.restoreDialogSettings(fileDialogSettingsName); fd.selectFile(AnnotationFile().getFileNameNoPath()); AString errorMessages; if (fd.exec() == CaretFileDialog::Accepted) { fd.saveDialogSettings(fileDialogSettingsName); QStringList selectedFiles = fd.selectedFiles(); if ( ! selectedFiles.empty()) { const AString annotationFileName = selectedFiles.at(0); AnnotationFile* newFile = new AnnotationFile(); newFile->setFileName(annotationFileName); EventManager::get()->sendEvent(EventDataFileAdd(newFile).getPointer()); m_selectedAnnotationFile = newFile; } } } /** * Called when a menu action is selected. * * @param action * The action that was selected. */ void AnnotationMenuFileSelection::menuActionSelected(QAction* action) { CaretAssert(action); const int actionID = action->data().toInt(); if (actionID == ACTION_ID_SCENE) { m_selectedAnnotationFile = GuiManager::get()->getBrain()->getSceneAnnotationFile(); } else if (actionID == ACTION_ID_NEW_DISK_FILE) { chooseDiskFile(); } else if (actionID >= ACTION_ID_FIRST_DISK_FILE) { if ((actionID >= 0) && (actionID < static_cast(m_annotationDiskFiles.size()))) { CaretAssertVectorIndex(m_annotationDiskFiles, actionID); m_selectedAnnotationFile = m_annotationDiskFiles[actionID]; } } emit menuItemSelected(); } /** * Update the contents of the menu. */ void AnnotationMenuFileSelection::updateMenuContents() { blockSignals(true); clear(); bool foundSelectedFileFlag = false; Brain* brain = GuiManager::get()->getBrain(); AnnotationFile* sceneAnnotationFile = brain->getSceneAnnotationFile(); QAction* sceneAction = addAction("Scene Annotations"); sceneAction->setData((int)ACTION_ID_SCENE); sceneAction->setCheckable(true); if (sceneAnnotationFile == m_selectedAnnotationFile) { sceneAction->setChecked(true); foundSelectedFileFlag = true; } addSeparator(); QAction* newDiskFileAction = addAction("New Disk File..."); newDiskFileAction->setData((int)ACTION_ID_NEW_DISK_FILE); addSeparator(); m_annotationDiskFiles.clear(); brain->getAllAnnotationFilesExcludingSceneAnnotationFile(m_annotationDiskFiles); const int32_t numDiskFiles = static_cast(m_annotationDiskFiles.size()); for (int32_t i = 0; i < numDiskFiles; i++) { CaretAssertVectorIndex(m_annotationDiskFiles, i); AnnotationFile* annFile = m_annotationDiskFiles[i]; CaretAssert(annFile); QAction* fileAction = addAction(annFile->getFileNameNoPath()); fileAction->setData((int)ACTION_ID_FIRST_DISK_FILE + i); fileAction->setCheckable(true); if (m_selectedAnnotationFile == annFile) { fileAction->setChecked(true); foundSelectedFileFlag = true; } } if ( ! foundSelectedFileFlag) { sceneAction->setChecked(true); m_selectedAnnotationFile = sceneAnnotationFile; } blockSignals(false); } connectome-workbench-1.4.2/src/GuiQt/AnnotationMenuFileSelection.h000066400000000000000000000044251360521144700252360ustar00rootroot00000000000000#ifndef __ANNOTATION_MENU_FILE_SELECTION_H__ #define __ANNOTATION_MENU_FILE_SELECTION_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AString.h" namespace caret { class AnnotationFile; class AnnotationMenuFileSelection : public QMenu { Q_OBJECT public: AnnotationMenuFileSelection(QWidget* parent = 0); virtual ~AnnotationMenuFileSelection(); AnnotationFile* getSelectedAnnotationFile(); AString getSelectedNameForToolButton(); // ADD_NEW_METHODS_HERE signals: void menuItemSelected(); private slots: void updateMenuContents(); void menuActionSelected(QAction* action); private: enum { ACTION_ID_SCENE = -2, ACTION_ID_NEW_DISK_FILE = -1, ACTION_ID_FIRST_DISK_FILE = 0 }; AnnotationMenuFileSelection(const AnnotationMenuFileSelection&); AnnotationMenuFileSelection& operator=(const AnnotationMenuFileSelection&); void chooseDiskFile(); std::vector m_annotationDiskFiles; AnnotationFile* m_selectedAnnotationFile; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_MENU_FILE_SELECTION_DECLARE__ // #endif // __ANNOTATION_MENU_FILE_SELECTION_DECLARE__ } // namespace #endif //__ANNOTATION_MENU_FILE_SELECTION_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationPasteDialog.cxx000066400000000000000000000505661360521144700244420ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_PASTE_DIALOG_DECLARE__ #include "AnnotationPasteDialog.h" #undef __ANNOTATION_PASTE_DIALOG_DECLARE__ #include #include #include #include #include "Annotation.h" #include "AnnotationCoordinateSelectionWidget.h" #include "AnnotationFile.h" #include "AnnotationManager.h" #include "AnnotationOneDimensionalShape.h" #include "AnnotationPercentSizeText.h" #include "AnnotationRedoUndoCommand.h" #include "Brain.h" #include "BrainBrowserWindow.h" #include "BrainOpenGLViewportContent.h" #include "BrainOpenGLWidget.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventUserInterfaceUpdate.h" #include "EventManager.h" #include "GuiManager.h" #include "ModelSurfaceMontage.h" #include "MouseEvent.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AnnotationPasteDialog * \brief Dialog for pasting annotations. * \ingroup GuiQt */ /** * Paste the annotation on the clipboard using the mouse information. * * @param mouseEvent * Information about where to paste the annotation. * @param windowIndex * Window in which annotation is pasted. * @return * Pointer to annotation that was pasted or NULL if the annotation * on the clipboard was not pasted. */ Annotation* AnnotationPasteDialog::pasteAnnotationOnClipboard(const MouseEvent& mouseEvent, const int32_t windowIndex) { Annotation* newPastedAnnotation = NULL; AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); if (annotationManager->isAnnotationOnClipboardValid()) { AnnotationFile* annotationFile = annotationManager->getAnnotationFileOnClipboard(); Annotation* annotation = annotationManager->getAnnotationOnClipboard()->clone(); BrainOpenGLViewportContent* viewportContent = mouseEvent.getViewportContent(); AnnotationCoordinateInformation coordInfo; AnnotationCoordinateInformation::createCoordinateInformationFromXY(mouseEvent.getOpenGLWidget(), viewportContent, mouseEvent.getX(), mouseEvent.getY(), coordInfo); bool validCoordsFlag = false; AnnotationOneDimensionalShape* oneDimShape = dynamic_cast(annotation); if (oneDimShape != NULL) { /* * Pasting line while preserving its orientation only * works for tab and window spaces. */ validCoordsFlag = pasteOneDimensionalShape(oneDimShape, coordInfo); } if (! validCoordsFlag) { validCoordsFlag = AnnotationCoordinateInformation::setAnnotationCoordinatesForSpace(annotation, annotation->getCoordinateSpace(), &coordInfo, NULL); } if (validCoordsFlag) { AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModePasteAnnotation(annotationFile, annotation); AString errorMessage; if ( ! annotationManager->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(mouseEvent.getOpenGLWidget(), errorMessage); } newPastedAnnotation = annotation; annotationManager->selectAnnotationForEditing(windowIndex, AnnotationManager::SELECTION_MODE_SINGLE, false, annotation); } else { /* * Pasting annotation in its coordinate failed (user may have tried to paste * an annotation in surface space where there is no surface). */ delete annotation; annotation = NULL; const QString message("The location for pasting the annotation is incompatible with the " "coordinate space " "used by the annotation on the clipboard. Choose one of the coordinate " "spaces below to paste the annotation or press Cancel to cancel pasting " "of the annotation."); /* * The annotation dialog will create a new annotation for pasting */ AnnotationPasteDialog pasteDialog(mouseEvent, annotationFile, annotationManager->getAnnotationOnClipboard(), message, mouseEvent.getOpenGLWidget()); if (pasteDialog.exec() == AnnotationPasteDialog::Accepted) { newPastedAnnotation = pasteDialog.getAnnotationThatWasCreated(); } } } return newPastedAnnotation; } /** * Paste the annotation on the clipboard using the mouse information * and allow the user to change the coordinate space. * * @param mouseEvent * Information about where to paste the annotation. * @return * Pointer to annotation that was pasted or NULL if the annotation * on the clipboard was not pasted. */ Annotation* AnnotationPasteDialog::pasteAnnotationOnClipboardChangeSpace(const MouseEvent& mouseEvent) { Annotation* newPastedAnnotation = NULL; AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); if (annotationManager->isAnnotationOnClipboardValid()) { AnnotationFile* annotationFile = annotationManager->getAnnotationFileOnClipboard(); AString message("Choose one of the coordinate " "spaces below to paste the annotation or press Cancel to cancel pasting " "of the annotation."); AnnotationPasteDialog pasteDialog(mouseEvent, annotationFile, annotationManager->getAnnotationOnClipboard(), message, mouseEvent.getOpenGLWidget()); if (pasteDialog.exec() == AnnotationPasteDialog::Accepted) { newPastedAnnotation = pasteDialog.getAnnotationThatWasCreated(); } } return newPastedAnnotation; } /** * Constructor. * * @param mouseEvent * Information about where mouse was clicked. * @param annotationFile * File that contains the annotation. * @param annotation * Annotation that is copied and pasted. * @param informationMessage * Message shown on dialog. * @param parent * Parent widget of dialog. */ AnnotationPasteDialog::AnnotationPasteDialog(const MouseEvent& mouseEvent, AnnotationFile* annotationFile, const Annotation* annotation, const AString& informationMessage, QWidget* parent) : WuQDialogModal("Paste Annotation", parent), m_mouseEvent(mouseEvent), m_annotationFile(annotationFile), m_annotation(annotation), m_annotationThatWasCreated(NULL) { CaretAssert(m_annotationFile); CaretAssert(m_annotation); /* * Get coordinates at the mouse location. */ AnnotationCoordinateInformation::createCoordinateInformationFromXY(mouseEvent, m_coordInfo); m_coordinateSelectionWidget = new AnnotationCoordinateSelectionWidget(m_annotation->getType(), m_coordInfo, NULL); m_coordinateSelectionWidget->selectCoordinateSpace(m_annotation->getCoordinateSpace()); QLabel* messageLabel = new QLabel(informationMessage); messageLabel->setWordWrap(true); QLabel* spaceLabel = new QLabel("Space of Annotation on Clipboard: " + AnnotationCoordinateSpaceEnum::toGuiName(m_annotation->getCoordinateSpace())); spaceLabel->setWordWrap(false); QGroupBox* coordGroupBox = new QGroupBox("Coordinate Space"); QVBoxLayout* coordGroupLayout = new QVBoxLayout(coordGroupBox); coordGroupLayout->setMargin(0); coordGroupLayout->addWidget(m_coordinateSelectionWidget); QWidget* dialogWidget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(dialogWidget); layout->addWidget(spaceLabel); layout->addSpacing(10); layout->addWidget(messageLabel); layout->addSpacing(10); layout->addWidget(coordGroupBox); setCentralWidget(dialogWidget, SCROLL_AREA_NEVER); } /** * Destructor. */ AnnotationPasteDialog::~AnnotationPasteDialog() { } /** * @return Get the annotation that was created. */ Annotation* AnnotationPasteDialog::getAnnotationThatWasCreated() { return m_annotationThatWasCreated; } /** * Paste a one-dimensional shape (line) keeping its start to end * coordinate orientation. The start coordinate is pasted at * the coordinate in 'coordInfo'. * * @param oneDimShape * One dimensional shape that will be pasted. * @param coordInfo * Coordinate information that will be used for the shape's 'start' coordinate. * @return * True if the shape's coordinate was updated for pasting, else false. */ bool AnnotationPasteDialog::pasteOneDimensionalShape(AnnotationOneDimensionalShape* oneDimShape, AnnotationCoordinateInformation& coordInfo) { bool tabFlag = false; bool windowFlag = false; switch (oneDimShape->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: tabFlag = true; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: windowFlag = true; break; } bool validCoordsFlag = false; if (tabFlag || windowFlag) { float startXYZ[3]; float endXYZ[3]; oneDimShape->getStartCoordinate()->getXYZ(startXYZ); oneDimShape->getEndCoordinate()->getXYZ(endXYZ); const float diffXYZ[3] = { endXYZ[0] - startXYZ[0], endXYZ[1] - startXYZ[1], endXYZ[2] - startXYZ[2] }; if (tabFlag && (coordInfo.m_tabSpaceInfo.m_index >= 0)) { startXYZ[0] = coordInfo.m_tabSpaceInfo.m_xyz[0]; startXYZ[1] = coordInfo.m_tabSpaceInfo.m_xyz[1]; startXYZ[2] = coordInfo.m_tabSpaceInfo.m_xyz[2]; oneDimShape->setTabIndex(coordInfo.m_tabSpaceInfo.m_index); validCoordsFlag = true; } else if (windowFlag && (coordInfo.m_windowSpaceInfo.m_index >= 0)) { startXYZ[0] = coordInfo.m_windowSpaceInfo.m_xyz[0]; startXYZ[1] = coordInfo.m_windowSpaceInfo.m_xyz[1]; startXYZ[2] = coordInfo.m_windowSpaceInfo.m_xyz[2]; oneDimShape->setWindowIndex(coordInfo.m_windowSpaceInfo.m_index); validCoordsFlag = true; } if (validCoordsFlag) { endXYZ[0] = startXYZ[0] + diffXYZ[0]; endXYZ[1] = startXYZ[1] + diffXYZ[1]; endXYZ[2] = startXYZ[2] + diffXYZ[2]; /* * Tab/Window coordinates are percentage ranging [0.0, 100.0] * Need to "clip" lines if they exceed the viewport's edges */ const float minCoord = 1.0; const float maxCoord = 99.0; if (endXYZ[0] < minCoord) { if (diffXYZ[0] != 0.0) { const float xDist = minCoord - startXYZ[0]; const float scaledDistance = std::fabs(xDist / diffXYZ[0]); endXYZ[0] = minCoord; endXYZ[1] = startXYZ[1] + (scaledDistance * diffXYZ[1]); } } else if (endXYZ[0] >= maxCoord) { if (diffXYZ[0] != 0.0) { const float xDist = maxCoord - startXYZ[0]; const float scaledDistance = std::fabs(xDist / diffXYZ[0]); endXYZ[0] = maxCoord; endXYZ[1] = startXYZ[1] + (scaledDistance * diffXYZ[1]); } } if (endXYZ[1] < minCoord) { if (diffXYZ[1] != 0.0) { const float yDist = minCoord - startXYZ[1]; const float scaledDistance = std::fabs(yDist / diffXYZ[1]); endXYZ[1] = minCoord; endXYZ[0] = startXYZ[0] + (scaledDistance * diffXYZ[0]); } } else if (endXYZ[1] > maxCoord) { if (diffXYZ[1] != 0.0) { const float yDist = maxCoord - startXYZ[1]; const float scaledDistance = std::fabs(yDist / diffXYZ[1]); endXYZ[1] = maxCoord; endXYZ[0] = startXYZ[0] + (scaledDistance * diffXYZ[0]); } } oneDimShape->getStartCoordinate()->setXYZ(startXYZ); oneDimShape->getEndCoordinate()->setXYZ(endXYZ); } } return validCoordsFlag; } /** * Gets called when the OK button is clicked. */ void AnnotationPasteDialog::okButtonClicked() { AString errorMessage; bool valid = false; m_coordinateSelectionWidget->getSelectedCoordinateSpace(valid); if ( ! valid) { const QString msg("A coordinate space has not been selected."); WuQMessageBox::errorOk(this, msg); return; } CaretPointer newAnnotation(m_annotation->clone()); const AnnotationCoordinateSpaceEnum::Enum previousSpace = m_annotation->getCoordinateSpace(); if ( ! m_coordinateSelectionWidget->setCoordinateForNewAnnotation(newAnnotation, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); return; } /* * Need to release annotation from its CaretPointer since the * annotation file will take ownership of the annotation. */ Annotation* annotationPointer = newAnnotation.releasePointer(); adjustTextAnnotationFontHeight(previousSpace, annotationPointer); AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModePasteAnnotation(m_annotationFile, annotationPointer); if ( ! annotationManager->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } annotationManager->selectAnnotationForEditing(m_mouseEvent.getBrowserWindowIndex(), AnnotationManager::SELECTION_MODE_SINGLE, false, annotationPointer); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); m_annotationThatWasCreated = annotationPointer; WuQDialog::okButtonClicked(); } /** * If the given annotation is a text annotation and the space is changed to * surface, we may need to adjust the height if in surface montage. This * results in the surface space pixel height being the same as the tab * space text pixel height when in surface montage. * * Inverse logic is need when converting text annotation from surface * space to another space. * * @param previousSpace * Space of annotation that was on the clipboard. * @param annotation * Annotation that is being pasted. */ void AnnotationPasteDialog::adjustTextAnnotationFontHeight(const AnnotationCoordinateSpaceEnum::Enum previousSpace, Annotation* annotation) { CaretAssert(annotation); BrainOpenGLViewportContent* vpContent = m_mouseEvent.getViewportContent(); CaretAssert(vpContent); BrowserTabContent* btc = vpContent->getBrowserTabContent(); CaretAssert(btc); int32_t surfaceMontageRowCount = 1; const ModelSurfaceMontage* msm = btc->getDisplayedSurfaceMontageModel(); if (msm != NULL) { int32_t columnCount = 1; msm->getSurfaceMontageNumberOfRowsAndColumns(btc->getTabNumber(), surfaceMontageRowCount, columnCount); } const AnnotationCoordinateSpaceEnum::Enum newSpace = annotation->getCoordinateSpace(); const bool previousSpaceStereoOrSurfaceFlag = ((previousSpace == AnnotationCoordinateSpaceEnum::STEREOTAXIC) || (previousSpace == AnnotationCoordinateSpaceEnum::SURFACE)); const bool newSpaceStereoOrSurfaceFlag = ((newSpace == AnnotationCoordinateSpaceEnum::STEREOTAXIC) || (newSpace == AnnotationCoordinateSpaceEnum::SURFACE)); if (surfaceMontageRowCount > 1) { if (annotation->getType() == AnnotationTypeEnum::TEXT) { float heightMultiplier = 0.0; if ( ! previousSpaceStereoOrSurfaceFlag) { if (newSpaceStereoOrSurfaceFlag) { /* * Converting to surface */ heightMultiplier = surfaceMontageRowCount; } } else { if ( ! newSpaceStereoOrSurfaceFlag) { /* * Converting from surface */ heightMultiplier = 1.0 / surfaceMontageRowCount; } } if (heightMultiplier != 0.0) { AnnotationPercentSizeText* textAnn = dynamic_cast(annotation); if (textAnn != NULL) { float percentHeight = textAnn->getFontPercentViewportSize(); percentHeight *= heightMultiplier; textAnn->setFontPercentViewportSize(percentHeight); } } } } } connectome-workbench-1.4.2/src/GuiQt/AnnotationPasteDialog.h000066400000000000000000000062001360521144700240510ustar00rootroot00000000000000#ifndef __ANNOTATION_PASTE_DIALOG_H__ #define __ANNOTATION_PASTE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationCoordinateInformation.h" #include "WuQDialogModal.h" namespace caret { class Annotation; class AnnotationCoordinateInformation; class AnnotationCoordinateSelectionWidget; class AnnotationFile; class AnnotationOneDimensionalShape; class MouseEvent; class AnnotationPasteDialog : public WuQDialogModal { Q_OBJECT public: static Annotation* pasteAnnotationOnClipboard(const MouseEvent& mouseEvent, const int32_t windowIndex); static Annotation* pasteAnnotationOnClipboardChangeSpace(const MouseEvent& mouseEvent); virtual ~AnnotationPasteDialog(); Annotation* getAnnotationThatWasCreated(); // ADD_NEW_METHODS_HERE private: AnnotationPasteDialog(const MouseEvent& mouseEvent, AnnotationFile* annotationFile, const Annotation* annotation, const AString& informationMessage, QWidget* parent = 0); AnnotationPasteDialog(const AnnotationPasteDialog&); AnnotationPasteDialog& operator=(const AnnotationPasteDialog&); static bool pasteOneDimensionalShape(AnnotationOneDimensionalShape* oneDimShape, AnnotationCoordinateInformation& coordInfo); virtual void okButtonClicked(); void adjustTextAnnotationFontHeight(const AnnotationCoordinateSpaceEnum::Enum previousSpace, Annotation* annotation); const MouseEvent& m_mouseEvent; AnnotationFile* m_annotationFile; const Annotation* m_annotation; AnnotationCoordinateSelectionWidget* m_coordinateSelectionWidget; AnnotationCoordinateInformation m_coordInfo; Annotation* m_annotationThatWasCreated; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_PASTE_DIALOG_DECLARE__ // #endif // __ANNOTATION_PASTE_DIALOG_DECLARE__ } // namespace #endif //__ANNOTATION_PASTE_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationRedoUndoWidget.cxx000066400000000000000000000117671360521144700251310ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_REDO_UNDO_WIDGET_DECLARE__ #include "AnnotationRedoUndoWidget.h" #undef __ANNOTATION_REDO_UNDO_WIDGET_DECLARE__ #include #include #include #include #include "AnnotationManager.h" #include "Brain.h" #include "CaretAssert.h" #include "CaretUndoStack.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "GuiManager.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AnnotationRedoUndoWidget * \brief Widget for redo and undo buttons * \ingroup GuiQt */ /** * Constructor. */ AnnotationRedoUndoWidget::AnnotationRedoUndoWidget(const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { QLabel* titleLabel = new QLabel("Edit"); m_redoAction = WuQtUtilities::createAction("Redo", "Redo ToolTip", this, this, SLOT(redoActionTriggered())); QToolButton* redoToolButton = new QToolButton(); redoToolButton->setDefaultAction(m_redoAction); WuQtUtilities::setToolButtonStyleForQt5Mac(redoToolButton); m_undoAction = WuQtUtilities::createAction("Undo", "Undo ToolTip", this, this, SLOT(undoActionTriggered())); QToolButton* undoToolButton = new QToolButton(); undoToolButton->setDefaultAction(m_undoAction); WuQtUtilities::setToolButtonStyleForQt5Mac(undoToolButton); QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 0); gridLayout->addWidget(titleLabel, 0, 0, 1, 1, Qt::AlignHCenter); gridLayout->addWidget(redoToolButton, 1, 0, Qt::AlignHCenter); gridLayout->addWidget(undoToolButton, 2, 0, Qt::AlignHCenter); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } /** * Destructor. */ AnnotationRedoUndoWidget::~AnnotationRedoUndoWidget() { } /** * Update with the given line annotation. * * @param annotationLine */ void AnnotationRedoUndoWidget::updateContent() { AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); CaretUndoStack* undoStack = annMan->getCommandRedoUndoStack(); m_redoAction->setEnabled(undoStack->canRedo()); m_redoAction->setToolTip(undoStack->redoText()); m_undoAction->setEnabled(undoStack->canUndo()); m_undoAction->setToolTip(undoStack->undoText()); } /** * Gets called when the redo action is triggered */ void AnnotationRedoUndoWidget::redoActionTriggered() { AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); CaretUndoStack* undoStack = annMan->getCommandRedoUndoStack(); AString errorMessage; if ( ! undoStack->redoInWindow(m_browserWindowIndex, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Gets called when the undo action is triggered */ void AnnotationRedoUndoWidget::undoActionTriggered() { AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); CaretUndoStack* undoStack = annMan->getCommandRedoUndoStack(); AString errorMessage; if ( ! undoStack->undoInWindow(m_browserWindowIndex, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } connectome-workbench-1.4.2/src/GuiQt/AnnotationRedoUndoWidget.h000066400000000000000000000037171360521144700245520ustar00rootroot00000000000000#ifndef __ANNOTATION_REDO_UNDO_WIDGET_H__ #define __ANNOTATION_REDO_UNDO_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include namespace caret { class AnnotationRedoUndoWidget : public QWidget { Q_OBJECT public: AnnotationRedoUndoWidget(const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~AnnotationRedoUndoWidget(); void updateContent(); private slots: void redoActionTriggered(); void undoActionTriggered(); // ADD_NEW_METHODS_HERE private: AnnotationRedoUndoWidget(const AnnotationRedoUndoWidget&); AnnotationRedoUndoWidget& operator=(const AnnotationRedoUndoWidget&); const int32_t m_browserWindowIndex; QAction* m_redoAction; QAction* m_undoAction; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_REDO_UNDO_WIDGET_DECLARE__ // #endif // __ANNOTATION_REDO_UNDO_WIDGET_DECLARE__ } // namespace #endif //__ANNOTATION_REDO_UNDO_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationRotationWidget.cxx000066400000000000000000000243531360521144700252040ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __ANNOTATION_ROTATION_WIDGET_DECLARE__ #include "AnnotationRotationWidget.h" #undef __ANNOTATION_ROTATION_WIDGET_DECLARE__ #include #include #include #include "AnnotationManager.h" #include "AnnotationOneDimensionalShape.h" #include "AnnotationRedoUndoCommand.h" #include "AnnotationTwoDimensionalShape.h" #include "Brain.h" #include "CaretAssert.h" #include "EventGetViewportSize.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "GuiManager.h" #include "MathFunctions.h" #include "WuQFactory.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AnnotationRotationWidget * \brief Widget for adjusting annotation's rotation angle. * \ingroup GuiQt */ /** * Constructor. * * @param browserWindowIndex * Index of browser window. * @param parent * Parent of this widget. */ AnnotationRotationWidget::AnnotationRotationWidget(const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { QLabel* rotationLabel = new QLabel(" R:"); m_rotationSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 359, 1.0, 0, this, SLOT(rotationValueChanged(double))); m_rotationSpinBox->setWrapping(true); WuQtUtilities::setWordWrappedToolTip(m_rotationSpinBox, "Rotation, clockwise in degrees"); QHBoxLayout* layout = new QHBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); layout->addWidget(rotationLabel); layout->addWidget(m_rotationSpinBox); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } /** * Destructor. */ AnnotationRotationWidget::~AnnotationRotationWidget() { } /** * Convert the given annotation to a one-dimensional annotation. * * @param annotation * The annotation. * @return * Non-null if it is a one-dimensional annotation in a compatible * stereotaxic space for rotation angle. * */ AnnotationOneDimensionalShape* AnnotationRotationWidget::getValidOneDimAnnotation(Annotation* annotation) { AnnotationOneDimensionalShape* oneDimAnn = dynamic_cast(annotation); if (oneDimAnn != NULL) { bool validSpaceFlag = false; switch (oneDimAnn->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: validSpaceFlag = true; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: validSpaceFlag = true; break; } if ( ! validSpaceFlag) { oneDimAnn = NULL; } } return oneDimAnn; } /** * Update with the given annotation. * * @param annotations. * The annotation. */ void AnnotationRotationWidget::updateContent(std::vector& annotations) { m_annotations.clear(); if ( ! annotations.empty()) { float rotationAngle = 0.0; bool rotationAngleValid = false; bool haveMultipleRotationAnglesFlag = false; const int32_t numAnns = static_cast(annotations.size()); for (int32_t i = 0; i < numAnns; i++) { CaretAssertVectorIndex(annotations, i); Annotation* ann = annotations[i]; if (ann->testProperty(Annotation::Property::ROTATION)) { if (ann->isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION)) { AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(ann); AnnotationOneDimensionalShape* oneDimAnn = getValidOneDimAnnotation(ann); float angle = 0.0; float angleValid = false; if (twoDimAnn != NULL) { angle = twoDimAnn->getRotationAngle(); angleValid = true; } else if (oneDimAnn != NULL) { int32_t viewport[4] = { 0, 0, 0, 0 }; bool viewportValidFlag = false; switch (oneDimAnn->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: { const int tabIndex = oneDimAnn->getTabIndex(); EventGetViewportSize vpSizeEvent(EventGetViewportSize::MODE_TAB_AFTER_MARGINS_INDEX, tabIndex); EventManager::get()->sendEvent(vpSizeEvent.getPointer()); if (vpSizeEvent.isViewportSizeValid()) { vpSizeEvent.getViewportSize(viewport); viewportValidFlag = true; } } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: { const int windowIndex = oneDimAnn->getWindowIndex(); EventGetViewportSize vpSizeEvent(EventGetViewportSize::MODE_WINDOW_INDEX, windowIndex); EventManager::get()->sendEvent(vpSizeEvent.getPointer()); if (vpSizeEvent.isViewportSizeValid()) { vpSizeEvent.getViewportSize(viewport); viewportValidFlag = true; } } break; } if (viewportValidFlag) { angle = oneDimAnn->getRotationAngle(viewport[2], viewport[3]); angleValid = true; } } if (angleValid) { if (angle < 0.0) { angle += 360.0; } else if (angle > 360.0) { angle -= 360.0; } if (rotationAngleValid) { if (rotationAngle != angle) { haveMultipleRotationAnglesFlag = true; } rotationAngle = std::min(rotationAngle, angle); } else { rotationAngle = angle; rotationAngleValid = true; } m_annotations.push_back(ann); } } } } if (rotationAngleValid) { m_rotationSpinBox->blockSignals(true); m_rotationSpinBox->setValue(rotationAngle); if (haveMultipleRotationAnglesFlag) { m_rotationSpinBox->setSuffix("+"); } else { m_rotationSpinBox->setSuffix(""); } m_rotationSpinBox->blockSignals(false); } setEnabled(rotationAngleValid); } else { setEnabled(false); } } /** * Gets called when rotation value is changed. * * @param value * */ void AnnotationRotationWidget::rotationValueChanged(double value) { if ( ! m_annotations.empty()) { AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeRotationAngle(value, m_annotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } connectome-workbench-1.4.2/src/GuiQt/AnnotationRotationWidget.h000066400000000000000000000042441360521144700246260ustar00rootroot00000000000000#ifndef __ANNOTATION_ROTATION_WIDGET_H__ #define __ANNOTATION_ROTATION_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include class QDoubleSpinBox; namespace caret { class Annotation; class AnnotationOneDimensionalShape; class AnnotationRotationWidget : public QWidget { Q_OBJECT public: AnnotationRotationWidget(const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~AnnotationRotationWidget(); // ADD_NEW_METHODS_HERE void updateContent(std::vector& annotations); private slots: void rotationValueChanged(double value); private: AnnotationRotationWidget(const AnnotationRotationWidget&); AnnotationRotationWidget& operator=(const AnnotationRotationWidget&); AnnotationOneDimensionalShape* getValidOneDimAnnotation(Annotation* annotation); std::vector m_annotations; const int32_t m_browserWindowIndex; QDoubleSpinBox* m_rotationSpinBox; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_ROTATION_WIDGET_DECLARE__ // #endif // __ANNOTATION_ROTATION_WIDGET_DECLARE__ } // namespace #endif //__ANNOTATION_ROTATION_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationSelectionViewController.cxx000066400000000000000000000323171360521144700270640ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_SELECTION_VIEW_CONTROLLER_DECLARE__ #include "AnnotationSelectionViewController.h" #undef __ANNOTATION_SELECTION_VIEW_CONTROLLER_DECLARE__ #include #include #include #include "AnnotationFile.h" #include "Brain.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "DisplayGroupAndTabItemViewController.h" #include "DisplayGroupEnumComboBox.h" #include "DisplayPropertiesAnnotation.h" #include "EventGetOrSetUserInputModeProcessor.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventUserInterfaceUpdate.h" #include "EventManager.h" #include "GuiManager.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AnnotationSelectionViewController * \brief View controller for display of annotations. * \ingroup GuiQt */ /** * Constructor. * * @param browserWindowIndex * Index of the browser window. * @param parentObjectName * Name of parent object * @param parent * The parent widget. */ AnnotationSelectionViewController::AnnotationSelectionViewController(const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { const QString objectNamePrefix(parentObjectName + ":AnnotationSelection"); WuQMacroManager* macroManager = WuQMacroManager::instance(); QLabel* groupLabel = new QLabel("Group"); m_displayGroupComboBox = new DisplayGroupEnumComboBox(this, (objectNamePrefix + ":DisplayGroup"), "annotations"); QObject::connect(m_displayGroupComboBox, SIGNAL(displayGroupSelected(const DisplayGroupEnum::Enum)), this, SLOT(displayGroupSelected(const DisplayGroupEnum::Enum))); QHBoxLayout* groupSelectionLayout = new QHBoxLayout(); groupSelectionLayout->addWidget(groupLabel); groupSelectionLayout->addWidget(m_displayGroupComboBox->getWidget()); groupSelectionLayout->addStretch(); QMargins groupLayoutMargins = groupSelectionLayout->contentsMargins(); groupLayoutMargins.setBottom(0); groupLayoutMargins.setTop(0); m_displayAnnotationsCheckBox = new QCheckBox("Display Annotations"); m_displayAnnotationsCheckBox->setToolTip("Disables/enables display of annotations in all windows"); QObject::connect(m_displayAnnotationsCheckBox, SIGNAL(clicked(bool)), this, SLOT(checkBoxToggled())); m_displayAnnotationsCheckBox->setObjectName(objectNamePrefix + "DisplayAnnotatons"); macroManager->addMacroSupportToObject(m_displayAnnotationsCheckBox, "Enable display of annotations"); m_displayTextAnnotationsCheckBox = new QCheckBox("Display Text Annotations"); m_displayTextAnnotationsCheckBox->setToolTip("Disables/enables display of text annotations in all windows"); QObject::connect(m_displayTextAnnotationsCheckBox, SIGNAL(clicked(bool)), this, SLOT(checkBoxToggled())); m_displayTextAnnotationsCheckBox->setObjectName(objectNamePrefix + "DisplayTextAnnotatons"); macroManager->addMacroSupportToObject(m_displayTextAnnotationsCheckBox, "Enable display of text annotations"); m_displayWindowAnnotationInSingleTabViewsCheckBox = new QCheckBox("Show Window " + QString::number(m_browserWindowIndex + 1) + " Annotations in Single Tab View"); const QString singTT(WuQtUtilities::createWordWrappedToolTipText("When checked, window annotations are always displayed.\n" "When unchecked, window annotations are only displayed when tile tabs is enabled.")); m_displayWindowAnnotationInSingleTabViewsCheckBox->setToolTip(singTT); QObject::connect(m_displayWindowAnnotationInSingleTabViewsCheckBox, SIGNAL(clicked(bool)), this, SLOT(checkBoxToggled())); m_displayWindowAnnotationInSingleTabViewsCheckBox->setObjectName(objectNamePrefix + "DisplayWindowAnnotatonsInSingleTabView"); macroManager->addMacroSupportToObject(m_displayWindowAnnotationInSingleTabViewsCheckBox, "Enable display window annotations in single tab view"); m_sceneAssistant = new SceneClassAssistant(); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(m_displayAnnotationsCheckBox); layout->addWidget(m_displayTextAnnotationsCheckBox); layout->addWidget(m_displayWindowAnnotationInSingleTabViewsCheckBox); layout->addWidget(WuQtUtilities::createHorizontalLineWidget()); layout->addLayout(groupSelectionLayout); layout->addWidget(createSelectionWidget(), 100); layout->addStretch(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); s_allAnnotationSelectionViewControllers.insert(this); } /** * Destructor. */ AnnotationSelectionViewController::~AnnotationSelectionViewController() { EventManager::get()->removeAllEventsFromListener(this); delete m_sceneAssistant; s_allAnnotationSelectionViewControllers.erase(this); } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void AnnotationSelectionViewController::receiveEvent(Event* event) { bool doUpdateFlag = false; if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE) { doUpdateFlag = true; } else if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* eventUI = dynamic_cast(event); CaretAssert(eventUI); doUpdateFlag = true; eventUI->setEventProcessed(); } if (doUpdateFlag) { updateAnnotationSelections(); } } /** * Update other selection annotation selector since they may share properties */ void AnnotationSelectionViewController::updateOtherAnnotationViewControllers() { for (std::set::iterator iter = s_allAnnotationSelectionViewControllers.begin(); iter != s_allAnnotationSelectionViewControllers.end(); iter++) { AnnotationSelectionViewController* avc = *iter; if (avc != this) { avc->updateAnnotationSelections(); } } } /** * Update the annotation selections. */ void AnnotationSelectionViewController::updateAnnotationSelections() { const DisplayPropertiesAnnotation* dpa = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotation(); BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); m_displayAnnotationsCheckBox->setChecked(dpa->isDisplayAnnotations()); m_displayTextAnnotationsCheckBox->setChecked(dpa->isDisplayTextAnnotations()); m_displayWindowAnnotationInSingleTabViewsCheckBox->setChecked(dpa->isDisplayWindowAnnotationsInSingleTabViews(m_browserWindowIndex)); Brain* brain = GuiManager::get()->getBrain(); std::vector annotationFiles; brain->getAllAnnotationFilesIncludingSceneAnnotationFile(annotationFiles); std::vector fileItems; for (std::vector::iterator fileIter = annotationFiles.begin(); fileIter != annotationFiles.end(); fileIter++) { AnnotationFile* annFile = *fileIter; fileItems.push_back(annFile); } const DisplayGroupEnum::Enum displayGroup = dpa->getDisplayGroupForTab(browserTabIndex); m_displayGroupComboBox->setSelectedDisplayGroup(displayGroup); const bool allowAnnotationSelectionFlag(true); m_selectionViewController->updateContent(fileItems, displayGroup, browserTabIndex, allowAnnotationSelectionFlag); } QWidget* AnnotationSelectionViewController::createSelectionWidget() { m_selectionViewController = new DisplayGroupAndTabItemViewController(DataFileTypeEnum::ANNOTATION, m_browserWindowIndex); return m_selectionViewController; } /** * Called when one of the checkboxes is clicked. */ void AnnotationSelectionViewController::checkBoxToggled() { DisplayPropertiesAnnotation* dpa = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotation(); BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } dpa->setDisplayAnnotations(m_displayAnnotationsCheckBox->isChecked()); dpa->setDisplayTextAnnotations(m_displayTextAnnotationsCheckBox->isChecked()); dpa->setDisplayWindowAnnotationsInSingleTabViews(m_browserWindowIndex, m_displayWindowAnnotationInSingleTabViewsCheckBox->isChecked()); updateOtherAnnotationViewControllers(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called when the display group combo box is changed. */ void AnnotationSelectionViewController::displayGroupSelected(const DisplayGroupEnum::Enum displayGroup) { DisplayPropertiesAnnotation* dpa = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotation(); BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); dpa->setDisplayGroupForTab(browserTabIndex, displayGroup); updateAnnotationSelections(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* AnnotationSelectionViewController::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "AnnotationSelectionViewController", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void AnnotationSelectionViewController::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/GuiQt/AnnotationSelectionViewController.h000066400000000000000000000077371360521144700265210ustar00rootroot00000000000000#ifndef __ANNOTATION_SELECTION_VIEW_CONTROLLER_H__ #define __ANNOTATION_SELECTION_VIEW_CONTROLLER_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "DisplayGroupEnum.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" class QCheckBox; namespace caret { class DisplayGroupAndTabItemViewController; class DisplayGroupEnumComboBox; class SceneClassAssistant; class AnnotationSelectionViewController : public QWidget, public EventListenerInterface, public SceneableInterface { Q_OBJECT public: AnnotationSelectionViewController(const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent); virtual ~AnnotationSelectionViewController(); // ADD_NEW_METHODS_HERE virtual void receiveEvent(Event* event); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implemetation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private slots: void checkBoxToggled(); void displayGroupSelected(const DisplayGroupEnum::Enum); private: AnnotationSelectionViewController(const AnnotationSelectionViewController&); AnnotationSelectionViewController& operator=(const AnnotationSelectionViewController&); QWidget* createSelectionWidget(); void updateAnnotationSelections(); void updateOtherAnnotationViewControllers(); SceneClassAssistant* m_sceneAssistant; int32_t m_browserWindowIndex; DisplayGroupEnumComboBox* m_displayGroupComboBox; DisplayGroupAndTabItemViewController* m_selectionViewController; QCheckBox* m_displayAnnotationsCheckBox; QCheckBox* m_displayTextAnnotationsCheckBox; QCheckBox* m_displayWindowAnnotationInSingleTabViewsCheckBox; static std::set s_allAnnotationSelectionViewControllers; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_SELECTION_VIEW_CONTROLLER_DECLARE__ std::set AnnotationSelectionViewController::s_allAnnotationSelectionViewControllers; #endif // __ANNOTATION_SELECTION_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__ANNOTATION_SELECTION_VIEW_CONTROLLER_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationTextAlignmentWidget.cxx000066400000000000000000000540111360521144700261620ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_TEXT_ALIGNMENT_WIDGET_DECLARE__ #include "AnnotationTextAlignmentWidget.h" #undef __ANNOTATION_TEXT_ALIGNMENT_WIDGET_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include "AnnotationManager.h" #include "AnnotationRedoUndoCommand.h" #include "AnnotationText.h" #include "Brain.h" #include "CaretAssert.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "GuiManager.h" #include "MathFunctions.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AnnotationTextAlignmentWidget * \brief Widget for adjusting annotation alignment. * \ingroup GuiQt */ /** * Constructor. * * @param browserWindowIndex * Index of browser window. * @param parent * The parent widget. */ AnnotationTextAlignmentWidget::AnnotationTextAlignmentWidget(const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { m_smallLayoutFlag = true; QToolButton* leftAlignToolButton = createHorizontalAlignmentToolButton(AnnotationTextAlignHorizontalEnum::LEFT); QToolButton* centerAlignToolButton = createHorizontalAlignmentToolButton(AnnotationTextAlignHorizontalEnum::CENTER); QToolButton* rightAlignToolButton = createHorizontalAlignmentToolButton(AnnotationTextAlignHorizontalEnum::RIGHT); m_horizontalAlignActionGroup = new QActionGroup(this); m_horizontalAlignActionGroup->setExclusive(false); /** not exclusive as may need to turn all off */ m_horizontalAlignActionGroup->addAction(leftAlignToolButton->defaultAction()); m_horizontalAlignActionGroup->addAction(centerAlignToolButton->defaultAction()); m_horizontalAlignActionGroup->addAction(rightAlignToolButton->defaultAction()); QObject::connect(m_horizontalAlignActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(horizontalAlignmentActionSelected(QAction*))); QToolButton* topAlignToolButton = createVerticalAlignmentToolButton(AnnotationTextAlignVerticalEnum::TOP); QToolButton* middleAlignToolButton = createVerticalAlignmentToolButton(AnnotationTextAlignVerticalEnum::MIDDLE); QToolButton* bottomAlignToolButton = createVerticalAlignmentToolButton(AnnotationTextAlignVerticalEnum::BOTTOM); m_verticalAlignActionGroup = new QActionGroup(this); m_verticalAlignActionGroup->setExclusive(false); /** not exclusive as may need to turn all off */ m_verticalAlignActionGroup->addAction(topAlignToolButton->defaultAction()); m_verticalAlignActionGroup->addAction(middleAlignToolButton->defaultAction()); m_verticalAlignActionGroup->addAction(bottomAlignToolButton->defaultAction()); QObject::connect(m_verticalAlignActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(verticalAlignmentActionSelected(QAction*))); QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 0); if (m_smallLayoutFlag) { QLabel* alignmentLabel = new QLabel("Alignment"); int row = gridLayout->rowCount(); gridLayout->addWidget(alignmentLabel, row, 0, 1, 3, Qt::AlignHCenter); row++; gridLayout->addWidget(leftAlignToolButton, row, 0); gridLayout->addWidget(centerAlignToolButton, row, 1); gridLayout->addWidget(rightAlignToolButton, row, 2); row++; gridLayout->addWidget(topAlignToolButton, row, 0); gridLayout->addWidget(middleAlignToolButton, row, 1); gridLayout->addWidget(bottomAlignToolButton, row, 2); } else { QLabel* horizontalLabel = new QLabel("Text Horizontal"); QHBoxLayout* horizontalAlignLayout = new QHBoxLayout(); WuQtUtilities::setLayoutSpacingAndMargins(horizontalAlignLayout, 2, 0); horizontalAlignLayout->addWidget(leftAlignToolButton); horizontalAlignLayout->addWidget(centerAlignToolButton); horizontalAlignLayout->addWidget(rightAlignToolButton); QLabel* verticalLabel = new QLabel("Text Vertical"); QHBoxLayout* verticalAlignLayout = new QHBoxLayout(); WuQtUtilities::setLayoutSpacingAndMargins(verticalAlignLayout, 2, 0); verticalAlignLayout->addWidget(topAlignToolButton); verticalAlignLayout->addWidget(middleAlignToolButton); verticalAlignLayout->addWidget(bottomAlignToolButton); gridLayout->addWidget(horizontalLabel, 0, 0, Qt::AlignHCenter); gridLayout->addLayout(horizontalAlignLayout, 1, 0); gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 0, 1, 2, 1); gridLayout->addWidget(verticalLabel, 0, 2, Qt::AlignHCenter); gridLayout->addLayout(verticalAlignLayout, 1, 2); } } /** * Destructor. */ AnnotationTextAlignmentWidget::~AnnotationTextAlignmentWidget() { } /** * Update with the given annotation. * * @param annotationTexts. */ void AnnotationTextAlignmentWidget::updateContent(std::vector& annotationTexts) { m_annotations.clear(); m_annotations.reserve(annotationTexts.size()); for (auto a : annotationTexts) { if (a->testProperty(Annotation::Property::TEXT_ORIENTATION)) { m_annotations.push_back(a); } } { /* * Update horizontal alignment */ m_horizontalAlignActionGroup->blockSignals(true); /* * If multiple annotations are selected, the may have different alignments. */ std::set selectedAlignments; for (std::vector::iterator iter = m_annotations.begin(); iter != m_annotations.end(); iter++) { const AnnotationText* annText = *iter; CaretAssert(annText); selectedAlignments.insert(annText->getHorizontalAlignment()); } AnnotationTextAlignHorizontalEnum::Enum alignment = AnnotationTextAlignHorizontalEnum::LEFT; bool alignmentValid = false; if (selectedAlignments.size() == 1) { alignment = *(selectedAlignments.begin()); alignmentValid = true; } /* * Update the status of each action * * An action is "checked" if an only if all selected annotations * have the same alignment. */ QList allActions = m_horizontalAlignActionGroup->actions(); QListIterator iter(allActions); while (iter.hasNext()) { QAction* action = iter.next(); const int intValue = action->data().toInt(); bool valid = false; AnnotationTextAlignHorizontalEnum::Enum actionAlign = AnnotationTextAlignHorizontalEnum::fromIntegerCode(intValue, &valid); bool actionChecked = false; if (valid) { if (alignmentValid) { if (actionAlign == alignment) { actionChecked = true; } } } action->setChecked(actionChecked); } if (alignmentValid) { AnnotationText::setUserDefaultHorizontalAlignment(alignment); } m_horizontalAlignActionGroup->blockSignals(false); } { /* * Update vertical alignment */ m_verticalAlignActionGroup->blockSignals(true); /* * If multiple annotations are selected, the may have different alignments. */ std::set selectedAlignments; for (std::vector::iterator iter = m_annotations.begin(); iter != m_annotations.end(); iter++) { const AnnotationText* annText = *iter; CaretAssert(annText); selectedAlignments.insert(annText->getVerticalAlignment()); } AnnotationTextAlignVerticalEnum::Enum alignment = AnnotationTextAlignVerticalEnum::TOP; bool alignmentValid = false; if (selectedAlignments.size() == 1) { alignment = *(selectedAlignments.begin()); alignmentValid = true; } /* * Update the status of each action * * An action is "checked" if an only if all selected annotations * have the same alignment. */ QList allActions = m_verticalAlignActionGroup->actions(); QListIterator iter(allActions); while (iter.hasNext()) { QAction* action = iter.next(); const int intValue = action->data().toInt(); bool valid = false; AnnotationTextAlignVerticalEnum::Enum actionAlign = AnnotationTextAlignVerticalEnum::fromIntegerCode(intValue, &valid); bool actionChecked = false; if (valid) { if (alignmentValid) { if (actionAlign == alignment) { actionChecked = true; } } } action->setChecked(actionChecked); } if (alignmentValid) { AnnotationText::setUserDefaultVerticalAlignment(alignment); } m_verticalAlignActionGroup->blockSignals(false); } setEnabled( ! m_annotations.empty()); } /** * Gets called when a horizontal alignment selection is made. * * @param action * Action that was selected. */ void AnnotationTextAlignmentWidget::horizontalAlignmentActionSelected(QAction* action) { CaretAssert(action); const int intValue = action->data().toInt(); bool valid = false; AnnotationTextAlignHorizontalEnum::Enum actionAlign = AnnotationTextAlignHorizontalEnum::fromIntegerCode(intValue, &valid); if (valid) { AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); std::vector annotations(m_annotations.begin(), m_annotations.end()); undoCommand->setModeTextAlignmentHorizontal(actionAlign, annotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); AnnotationText::setUserDefaultHorizontalAlignment(actionAlign); } } /** * Gets called when a vertical alignment selection is made. * * @param action * Action that was selected. */ void AnnotationTextAlignmentWidget::verticalAlignmentActionSelected(QAction* action) { CaretAssert(action); const int intValue = action->data().toInt(); bool valid = false; AnnotationTextAlignVerticalEnum::Enum actionAlign = AnnotationTextAlignVerticalEnum::fromIntegerCode(intValue, &valid); if (valid) { AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); std::vector annotations(m_annotations.begin(), m_annotations.end()); undoCommand->setModeTextAlignmentVertical(actionAlign, annotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); AnnotationText::setUserDefaultVerticalAlignment(actionAlign); } } /** * Create a tool button for the given horizontal alignment. * The tool button will contain an action with the appropriate * icon and tooltip. * * @param horizontalAlignment * The horizontal alignment. */ QToolButton* AnnotationTextAlignmentWidget::createHorizontalAlignmentToolButton(const AnnotationTextAlignHorizontalEnum::Enum horizontalAlignment) { QString toolTipText; switch (horizontalAlignment) { case AnnotationTextAlignHorizontalEnum::CENTER: toolTipText = "Align Text Center"; break; case AnnotationTextAlignHorizontalEnum::LEFT: toolTipText = "Align Text Left"; break; case AnnotationTextAlignHorizontalEnum::RIGHT: toolTipText = "Align Text Right"; break; } QToolButton* toolButton = new QToolButton(); QPixmap pixmap = createHorizontalAlignmentPixmap(toolButton, horizontalAlignment); QAction* action = new QAction(this); action->setCheckable(true); action->setData((int)AnnotationTextAlignHorizontalEnum::toIntegerCode(horizontalAlignment)); action->setToolTip(toolTipText); action->setIcon(QIcon(pixmap)); toolButton->setDefaultAction(action); toolButton->setIconSize(pixmap.size()); WuQtUtilities::setToolButtonStyleForQt5Mac(toolButton); return toolButton; } /** * Create a tool button for the given vertical alignment. * The tool button will contain an action with the appropriate * icon and tooltip. * * @param verticalAlignment * The vertical alignment. */ QToolButton* AnnotationTextAlignmentWidget::createVerticalAlignmentToolButton(const AnnotationTextAlignVerticalEnum::Enum verticalAlignment) { QString toolTipText; switch (verticalAlignment) { case AnnotationTextAlignVerticalEnum::BOTTOM: toolTipText = "Align Text Bottom"; break; case AnnotationTextAlignVerticalEnum::MIDDLE: toolTipText = "Align Text Middle"; break; case AnnotationTextAlignVerticalEnum::TOP: toolTipText = "Align Text Top"; break; } QToolButton* toolButton = new QToolButton(); QPixmap pixmap = createVerticalAlignmentPixmap(toolButton, verticalAlignment); QAction* action = new QAction(this); action->setCheckable(true); action->setData((int)AnnotationTextAlignVerticalEnum::toIntegerCode(verticalAlignment)); action->setToolTip(toolTipText); action->setIcon(QIcon(pixmap)); toolButton->setDefaultAction(action); toolButton->setIconSize(pixmap.size()); WuQtUtilities::setToolButtonStyleForQt5Mac(toolButton); return toolButton; } /** * Create a horizontal alignment pixmap. * * @param widget * To color the pixmap with backround and foreground, * the palette from the given widget is used. * @param horizontalAlignment * The horizontal alignment. * @return * Pixmap with icon for the given horizontal alignment. */ QPixmap AnnotationTextAlignmentWidget::createHorizontalAlignmentPixmap(const QWidget* widget, const AnnotationTextAlignHorizontalEnum::Enum horizontalAlignment) { CaretAssert(widget); /* * Create a small, square pixmap that will contain * the foreground color around the pixmap's perimeter. */ float width = 24.0; float height = 24.0; int32_t numLines = 5; if (m_smallLayoutFlag) { width = 12.0; height = 12.0; numLines = 3; } QPixmap pixmap(static_cast(width), static_cast(height)); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainter(widget, pixmap); const qreal margin = width * 0.05; const qreal longLineLength = width - (margin * 2.0); const qreal shortLineLength = width / 2.0; const qreal yStep = MathFunctions::round(height / (numLines + 1)); for (int32_t i = 1; i <= numLines; i++) { const qreal lineLength = (((i % 2) == 0) ? shortLineLength : longLineLength); const qreal y = yStep * i; qreal xStart = 0.0; qreal xEnd = width; switch (horizontalAlignment) { case AnnotationTextAlignHorizontalEnum::CENTER: xStart = (width - lineLength) / 2.0; xEnd = xStart + lineLength; break; case AnnotationTextAlignHorizontalEnum::LEFT: xStart = margin; xEnd = xStart + lineLength; break; case AnnotationTextAlignHorizontalEnum::RIGHT: xEnd = width - margin; xStart = xEnd - lineLength; break; } painter->drawLine(QLineF(xStart, y, xEnd, y)); } return pixmap; } /** * Create a vertical alignment pixmap. * * @param widget * To color the pixmap with backround and foreground, * the palette from the given widget is used. * @param verticalAlignment * The vertical alignment. * @return * Pixmap with icon for the given vertical alignment. */ QPixmap AnnotationTextAlignmentWidget::createVerticalAlignmentPixmap(const QWidget* widget, const AnnotationTextAlignVerticalEnum::Enum verticalAlignment) { CaretAssert(widget); /* * Create a small, square pixmap that will contain * the foreground color around the pixmap's perimeter. */ float width = 24.0; float height = 24.0; int32_t numLines = 5; if (m_smallLayoutFlag) { width = 12.0; height = 12.0; numLines = 3; } QPixmap pixmap(static_cast(width), static_cast(height)); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainter(widget, pixmap); const qreal margin = width * 0.05; if (m_smallLayoutFlag) { float yStep = 3.0; float y1 = 0.0; float y2 = 0.0; switch (verticalAlignment) { case AnnotationTextAlignVerticalEnum::BOTTOM: y1 = (height - 1 - yStep); y2 = y1 + yStep; break; case AnnotationTextAlignVerticalEnum::MIDDLE: y1 = MathFunctions::round((height / 2.0) - (yStep / 2.0)); y2 = y1 + yStep; break; case AnnotationTextAlignVerticalEnum::TOP: y1 = yStep; y2 = y1 + yStep; break; } const float xStart = margin; const float xEnd = width - (margin * 2.0); painter->drawLine(QLineF(xStart, y1, xEnd, y1)); painter->drawLine(QLineF(xStart, y2, xEnd, y2)); } else { const qreal longLineLength = width - (margin * 2.0); const qreal shortLineLength = width / 2.0; const qreal yStep = MathFunctions::round(height / 6.0); for (int32_t i = 1; i <= numLines; i++) { const qreal lineLength = (((i % 2) == 0) ? shortLineLength : longLineLength); int32_t iOffset = i; switch (verticalAlignment) { case AnnotationTextAlignVerticalEnum::BOTTOM: iOffset += 2; break; case AnnotationTextAlignVerticalEnum::MIDDLE: iOffset += 1; break; case AnnotationTextAlignVerticalEnum::TOP: break; } const qreal y = yStep * iOffset; const qreal xStart = margin; const qreal xEnd = xStart + lineLength; painter->drawLine(QLineF(xStart, y, xEnd, y)); } } return pixmap; } connectome-workbench-1.4.2/src/GuiQt/AnnotationTextAlignmentWidget.h000066400000000000000000000060361360521144700256130ustar00rootroot00000000000000#ifndef __ANNOTATION_TEXT_ALIGNMENT_WIDGET_H__ #define __ANNOTATION_TEXT_ALIGNMENT_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AnnotationTextAlignHorizontalEnum.h" #include "AnnotationTextAlignVerticalEnum.h" class QActionGroup; class QToolButton; namespace caret { class Annotation; class AnnotationText; class AnnotationTextAlignmentWidget : public QWidget { Q_OBJECT public: AnnotationTextAlignmentWidget(const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~AnnotationTextAlignmentWidget(); // ADD_NEW_METHODS_HERE void updateContent(std::vector& annotationTexts); private slots: void horizontalAlignmentActionSelected(QAction* action); void verticalAlignmentActionSelected(QAction* action); private: AnnotationTextAlignmentWidget(const AnnotationTextAlignmentWidget&); AnnotationTextAlignmentWidget& operator=(const AnnotationTextAlignmentWidget&); QToolButton* createHorizontalAlignmentToolButton(const AnnotationTextAlignHorizontalEnum::Enum horizontalAlignment); QToolButton* createVerticalAlignmentToolButton(const AnnotationTextAlignVerticalEnum::Enum verticalAlignment); QPixmap createHorizontalAlignmentPixmap(const QWidget* widget, const AnnotationTextAlignHorizontalEnum::Enum horizontalAlignment); QPixmap createVerticalAlignmentPixmap(const QWidget* widget, const AnnotationTextAlignVerticalEnum::Enum verticalAlignment); const int32_t m_browserWindowIndex; QActionGroup* m_horizontalAlignActionGroup; QActionGroup* m_verticalAlignActionGroup; std::vector m_annotations; bool m_smallLayoutFlag; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_TEXT_ALIGNMENT_WIDGET_DECLARE__ // #endif // __ANNOTATION_TEXT_ALIGNMENT_WIDGET_DECLARE__ } // namespace #endif //__ANNOTATION_TEXT_ALIGNMENT_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationTextEditorDialog.cxx000066400000000000000000000104041360521144700254440ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_TEXT_EDITOR_DIALOG_DECLARE__ #include "AnnotationTextEditorDialog.h" #undef __ANNOTATION_TEXT_EDITOR_DIALOG_DECLARE__ #include #include #include #include "AnnotationManager.h" #include "AnnotationRedoUndoCommand.h" #include "AnnotationText.h" #include "Brain.h" #include "CaretAssert.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "GuiManager.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AnnotationTextEditorDialog * \brief Dialog for editing annotation text. * \ingroup GuiQt */ /** * Constructor. * * @param textAnnotation * Text annotation that will be edited. * @param parent * Parent of this dialog. */ AnnotationTextEditorDialog::AnnotationTextEditorDialog(AnnotationText* textAnnotation, QWidget* parent) : QDialog(parent), m_textAnnotation(textAnnotation) { CaretAssert(textAnnotation); Qt::WindowFlags flags = windowFlags(); flags |= (Qt::CustomizeWindowHint); // disables min/max buttons setWindowFlags(flags); setWindowTitle("Edit Annotation Text"); m_uneditedText = textAnnotation->getText(); m_textEdit = new QTextEdit(); m_textEdit->setText(textAnnotation->getText()); m_textEdit->selectAll(); m_textEdit->setToolTip("Press OK to save text changes and close dialog\n" "Press CANCEL to revert changes and close dialog"); QObject::connect(m_textEdit, SIGNAL(textChanged()), this, SLOT(textWasEdited())); QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QObject::connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 2); layout->addWidget(m_textEdit); layout->addWidget(buttonBox); } /** * Destructor. */ AnnotationTextEditorDialog::~AnnotationTextEditorDialog() { } /** * Closes the dialog. * * @param resultCode */ void AnnotationTextEditorDialog::done(int resultCode) { if (resultCode == QDialog::Accepted) { } else { m_textEdit->setText(m_uneditedText); } textWasEdited(); QDialog::done(resultCode); } /** * Called when the user edits text. * * @param text * Text entered by user. */ void AnnotationTextEditorDialog::textWasEdited() { const QString text = m_textEdit->toPlainText(); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); std::vector annotationVector; annotationVector.push_back(m_textAnnotation); undoCommand->setModeTextCharacters(text, annotationVector); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } connectome-workbench-1.4.2/src/GuiQt/AnnotationTextEditorDialog.h000066400000000000000000000040341360521144700250730ustar00rootroot00000000000000#ifndef __ANNOTATION_TEXT_EDITOR_DIALOG_H__ #define __ANNOTATION_TEXT_EDITOR_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include class QTextEdit; namespace caret { class AnnotationText; class AnnotationTextEditorDialog : public QDialog { Q_OBJECT public: AnnotationTextEditorDialog(AnnotationText* textAnnotation, QWidget* parent); virtual ~AnnotationTextEditorDialog(); virtual void done(int resultCode); signals: void textHasBeenChanged(const QString&); private slots: void textWasEdited(); // ADD_NEW_METHODS_HERE private: AnnotationTextEditorDialog(const AnnotationTextEditorDialog&); AnnotationTextEditorDialog& operator=(const AnnotationTextEditorDialog&); AnnotationText* m_textAnnotation; QString m_uneditedText; QTextEdit* m_textEdit; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_TEXT_EDITOR_DIALOG_DECLARE__ // #endif // __ANNOTATION_TEXT_EDITOR_DIALOG_DECLARE__ } // namespace #endif //__ANNOTATION_TEXT_EDITOR_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationTextEditorWidget.cxx000066400000000000000000000203541360521144700254750ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_TEXT_EDITOR_WIDGET_DECLARE__ #include "AnnotationTextEditorWidget.h" #undef __ANNOTATION_TEXT_EDITOR_WIDGET_DECLARE__ #include #include #include #include #include "AnnotationManager.h" #include "AnnotationRedoUndoCommand.h" #include "AnnotationText.h" #include "AnnotationTextEditorDialog.h" #include "Brain.h" #include "CaretAssert.h" #include "EnumComboBoxTemplate.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "GuiManager.h" #include "WuQDataEntryDialog.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AnnotationTextEditorWidget * \brief Widget for editing annotation text. * \ingroup GuiQt */ /** * Constructor. * * @param browserWindowIndex * Index of browser window. * @param parent * The parent widget. */ AnnotationTextEditorWidget::AnnotationTextEditorWidget(const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { m_annotationText = NULL; QLabel* textLabel = new QLabel("Text"); m_textLineEdit = new AnnotationLineEdit(); QObject::connect(m_textLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(annotationTextChanged())); QObject::connect(m_textLineEdit, SIGNAL(doubleClickInLineEdit()), this, SLOT(displayTextEditor())); m_textLineEdit->setToolTip("Insert lines breaks with '\\n' \n" "Double-click text to edit text in a multi-line text dialog"); const QString textConnectToolTip("Connect text to brainordinate with arrow or line"); m_annotationTextConnectTypeEnumComboBox = new EnumComboBoxTemplate(this); m_annotationTextConnectTypeEnumComboBox->getWidget()->setToolTip(textConnectToolTip); m_annotationTextConnectTypeEnumComboBox->setup(); QObject::connect(m_annotationTextConnectTypeEnumComboBox, SIGNAL(itemActivated()), this, SLOT(annotationTextConnectTypeEnumComboBoxItemActivated())); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); layout->addWidget(textLabel, 0, Qt::AlignHCenter); layout->addWidget(m_textLineEdit); //, 0, Qt::AlignHCenter); layout->addWidget(m_annotationTextConnectTypeEnumComboBox->getWidget(), 0, Qt::AlignHCenter); setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); setMaximumWidth(200); } /** * Destructor. */ AnnotationTextEditorWidget::~AnnotationTextEditorWidget() { } /** * Update with the given annotation. * * @param annotation. */ void AnnotationTextEditorWidget::updateContent(std::vector& annotationTexts) { m_annotationText = NULL; for (auto a : annotationTexts) { if (a->testProperty(Annotation::Property::TEXT_EDIT)) { m_annotationText = a; break; } } AnnotationTextConnectTypeEnum::Enum connectValue = AnnotationTextConnectTypeEnum::ANNOTATION_TEXT_CONNECT_NONE; if (m_annotationText != NULL) { connectValue = m_annotationText->getConnectToBrainordinate(); AnnotationText::setUserDefaultConnectToBrainordinate(connectValue); } m_annotationTextConnectTypeEnumComboBox->setSelectedItem(connectValue); QString text; m_annotationTextConnectTypeEnumComboBox->getComboBox()->setEnabled(false); if (m_annotationText != NULL) { setEnabled(true); if (m_annotationText->isConnectToBrainordinateValid()) { m_annotationTextConnectTypeEnumComboBox->getComboBox()->setEnabled(true); } text = m_annotationText->getText(); } else { setEnabled(false); } updateLineEditText(text); } /** * Gets called when the edit button is clicked. */ void AnnotationTextEditorWidget::displayTextEditor() { if (m_annotationText != NULL) { AnnotationTextEditorDialog ted(m_annotationText, this); QObject::connect(&ted, SIGNAL(textHasBeenChanged(const QString&)), this, SLOT(textEditorDialogTextChanged(const QString&))); ted.exec(); } } /** * Gets called when text is edited in the text editor dialog. */ void AnnotationTextEditorWidget::textEditorDialogTextChanged(const QString& text) { updateLineEditText(text); annotationTextChanged(); } /** * Gets called when the annotation text is changed. */ void AnnotationTextEditorWidget::annotationTextChanged() { if (m_annotationText == NULL) { return; } /* * The update event will cause the text to be reloaded * into the line edit and that will cause the cursor * position to change so save and later restore the * cursor position. */ const int cursorPos = m_textLineEdit->cursorPosition(); QString s(m_textLineEdit->text()); s.replace("\\n", "\n"); std::vector selectedAnnotations; selectedAnnotations.push_back(m_annotationText); AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeTextCharacters(s, selectedAnnotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); m_textLineEdit->setCursorPosition(cursorPos); } /** * Update the text in the line edit including * replacing newline characters with "\n" * * @param text * Text for the line edit. */ void AnnotationTextEditorWidget::updateLineEditText(const QString& text) { QString s(text); s.replace("\n", "\\n"); m_textLineEdit->setText(s); } /** * Gets called when the annotation connect to brainordinate is changed. */ void AnnotationTextEditorWidget::annotationTextConnectTypeEnumComboBoxItemActivated() { if (m_annotationText == NULL) { return; } std::vector selectedAnnotations; selectedAnnotations.push_back(m_annotationText); const AnnotationTextConnectTypeEnum::Enum connectType = m_annotationTextConnectTypeEnumComboBox->getSelectedItem(); AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeTextConnectToBrainordinate(connectType, selectedAnnotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } AnnotationText::setUserDefaultConnectToBrainordinate(connectType); EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } connectome-workbench-1.4.2/src/GuiQt/AnnotationTextEditorWidget.h000066400000000000000000000056651360521144700251320ustar00rootroot00000000000000#ifndef __ANNOTATION_TEXT_EDITOR_WIDGET_H__ #define __ANNOTATION_TEXT_EDITOR_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include namespace caret { class AnnotationLineEdit; class AnnotationText; class EnumComboBoxTemplate; class AnnotationTextEditorWidget : public QWidget { Q_OBJECT public: AnnotationTextEditorWidget(const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~AnnotationTextEditorWidget(); // ADD_NEW_METHODS_HERE void updateContent(std::vector& annotationTexts); private slots: void annotationTextChanged(); void displayTextEditor(); void textEditorDialogTextChanged(const QString&); void annotationTextConnectTypeEnumComboBoxItemActivated(); private: AnnotationTextEditorWidget(const AnnotationTextEditorWidget&); AnnotationTextEditorWidget& operator=(const AnnotationTextEditorWidget&); void updateLineEditText(const QString& text); const int32_t m_browserWindowIndex; AnnotationText* m_annotationText; AnnotationLineEdit* m_textLineEdit; EnumComboBoxTemplate* m_annotationTextConnectTypeEnumComboBox; // ADD_NEW_MEMBERS_HERE }; /** * A line edit that emits a signal if the user double-clicks * in the line edit. */ class AnnotationLineEdit : public QLineEdit { Q_OBJECT public: AnnotationLineEdit(QWidget* parent = 0) : QLineEdit(parent) { } virtual ~AnnotationLineEdit() { } signals: void doubleClickInLineEdit(); protected: void mouseDoubleClickEvent(QMouseEvent*) { emit doubleClickInLineEdit(); } }; #ifdef __ANNOTATION_TEXT_EDITOR_WIDGET_DECLARE__ // #endif // __ANNOTATION_TEXT_EDITOR_WIDGET_DECLARE__ } // namespace #endif //__ANNOTATION_TEXT_EDITOR_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationTextOrientationWidget.cxx000066400000000000000000000235721360521144700265470ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_TEXT_ORIENTATION_WIDGET_DECLARE__ #include "AnnotationTextOrientationWidget.h" #undef __ANNOTATION_TEXT_ORIENTATION_WIDGET_DECLARE__ #include #include #include #include #include #include #include #include #include "AnnotationManager.h" #include "AnnotationRedoUndoCommand.h" #include "AnnotationText.h" #include "Brain.h" #include "CaretAssert.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "GuiManager.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AnnotationTextOrientationWidget * \brief Widget for selection of text orientation. * \ingroup GuiQt */ /** * Constructor. */ AnnotationTextOrientationWidget::AnnotationTextOrientationWidget(const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { QLabel* orientationLabel = new QLabel("Orientation"); QToolButton* horizontalOrientationToolButton = createOrientationToolButton(AnnotationTextOrientationEnum::HORIZONTAL); QToolButton* verticalOrientationToolButton = createOrientationToolButton(AnnotationTextOrientationEnum::STACKED); m_orientationActionGroup = new QActionGroup(this); m_orientationActionGroup->setExclusive(false); m_orientationActionGroup->addAction(horizontalOrientationToolButton->defaultAction()); m_orientationActionGroup->addAction(verticalOrientationToolButton->defaultAction()); QObject::connect(m_orientationActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(orientationActionSelected(QAction*))); QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 0); int row = gridLayout->rowCount(); gridLayout->addWidget(orientationLabel, row, 0, 1, 2, Qt::AlignHCenter); row++; gridLayout->addWidget(horizontalOrientationToolButton, row, 0); gridLayout->addWidget(verticalOrientationToolButton, row, 1); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } /** * Destructor. */ AnnotationTextOrientationWidget::~AnnotationTextOrientationWidget() { } /** * Update with the given annotation. * * @param annotationTextsIn. */ void AnnotationTextOrientationWidget::updateContent(std::vector& annotationTextsIn) { m_annotations.clear(); m_annotations.reserve(annotationTextsIn.size()); for (auto a : annotationTextsIn) { if (a->testProperty(Annotation::Property::TEXT_ORIENTATION)) { m_annotations.push_back(a); } } { /* * Update orientation */ m_orientationActionGroup->blockSignals(true); /* * If multiple annotations are selected, the may have different orientation. */ std::set selectedOrientations; for (std::vector::iterator iter = m_annotations.begin(); iter != m_annotations.end(); iter++) { const AnnotationText* annText = *iter; CaretAssert(annText); selectedOrientations.insert(annText->getOrientation()); } AnnotationTextOrientationEnum::Enum orientation = AnnotationTextOrientationEnum::HORIZONTAL; bool orientationValid = false; if (selectedOrientations.size() == 1) { orientation = *(selectedOrientations.begin()); orientationValid = true; } /* * Update the status of each action * * An action is "checked" if an only if all selected annotations * have the same orientation. */ QList allActions = m_orientationActionGroup->actions(); QListIterator iter(allActions); while (iter.hasNext()) { QAction* action = iter.next(); const int intValue = action->data().toInt(); bool valid = false; AnnotationTextOrientationEnum::Enum actionOrient = AnnotationTextOrientationEnum::fromIntegerCode(intValue, &valid); bool actionChecked = false; if (valid) { if (orientationValid) { if (actionOrient == orientation) { actionChecked = true; } } } action->setChecked(actionChecked); } if (orientationValid) { AnnotationText::setUserDefaultOrientation(orientation); } m_orientationActionGroup->blockSignals(false); } setEnabled( ! m_annotations.empty()); } /** * Gets called when a orientation selection is made. * * @param action * Action that was selected. */ void AnnotationTextOrientationWidget::orientationActionSelected(QAction* action) { CaretAssert(action); const int intValue = action->data().toInt(); bool valid = false; AnnotationTextOrientationEnum::Enum actionOrientation = AnnotationTextOrientationEnum::fromIntegerCode(intValue, &valid); if (valid) { AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); std::vector annotations(m_annotations.begin(), m_annotations.end()); undoCommand->setModeTextOrientation(actionOrientation, annotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); AnnotationText::setUserDefaultOrientation(actionOrientation); } } /** * Create a tool button for the given horizontal alignment. * The tool button will contain an action with the appropriate * icon and tooltip. * * @param orientation * The horizontal alignment. */ QToolButton* AnnotationTextOrientationWidget::createOrientationToolButton(const AnnotationTextOrientationEnum::Enum orientation) { QString toolTipText; switch (orientation) { case AnnotationTextOrientationEnum::HORIZONTAL: toolTipText = "Horizontal (left-to-right) text"; break; case AnnotationTextOrientationEnum::STACKED: toolTipText = "Stacked (top-to-bottom) text"; break; } QToolButton* toolButton = new QToolButton(); QPixmap pixmap = createHorizontalAlignmentPixmap(toolButton, orientation); QAction* action = new QAction(this); action->setCheckable(true); action->setData((int)AnnotationTextOrientationEnum::toIntegerCode(orientation)); action->setToolTip(toolTipText); action->setIcon(QIcon(pixmap)); toolButton->setDefaultAction(action); toolButton->setIconSize(pixmap.size()); WuQtUtilities::setToolButtonStyleForQt5Mac(toolButton); return toolButton; } /** * Create a horizontal alignment pixmap. * * @param widget * To color the pixmap with backround and foreground, * the palette from the given widget is used. * @param orientation * The horizontal alignment. * @return * Pixmap with icon for the given horizontal alignment. */ QPixmap AnnotationTextOrientationWidget::createHorizontalAlignmentPixmap(const QWidget* widget, const AnnotationTextOrientationEnum::Enum orientation) { CaretAssert(widget); /* * Create a small, square pixmap that will contain * the foreground color around the pixmap's perimeter. */ float width = 24.0; float height = 30.0; QPixmap pixmap(static_cast(width), static_cast(height)); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainter(widget, pixmap); switch (orientation) { case AnnotationTextOrientationEnum::HORIZONTAL: painter->drawText(pixmap.rect(), (Qt::AlignCenter), "ab"); break; case AnnotationTextOrientationEnum::STACKED: painter->drawText(pixmap.rect(), (Qt::AlignCenter), "a\nb"); break; } return pixmap; } connectome-workbench-1.4.2/src/GuiQt/AnnotationTextOrientationWidget.h000066400000000000000000000047651360521144700261770ustar00rootroot00000000000000#ifndef __ANNOTATION_TEXT_ORIENTATION_WIDGET_H__ #define __ANNOTATION_TEXT_ORIENTATION_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AnnotationTextOrientationEnum.h" class QActionGroup; class QToolButton; namespace caret { class Annotation; class AnnotationText; class AnnotationTextOrientationWidget : public QWidget { Q_OBJECT public: AnnotationTextOrientationWidget(const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~AnnotationTextOrientationWidget(); // ADD_NEW_METHODS_HERE void updateContent(std::vector& annotationTexts); private slots: void orientationActionSelected(QAction* action); private: AnnotationTextOrientationWidget(const AnnotationTextOrientationWidget&); AnnotationTextOrientationWidget& operator=(const AnnotationTextOrientationWidget&); QToolButton* createOrientationToolButton(const AnnotationTextOrientationEnum::Enum orientation); QPixmap createHorizontalAlignmentPixmap(const QWidget* widget, const AnnotationTextOrientationEnum::Enum orientation); const int32_t m_browserWindowIndex; std::vector m_annotations; QActionGroup* m_orientationActionGroup; // ADD_NEW_MEMBERS_HERE }; #ifdef __ANNOTATION_TEXT_ORIENTATION_WIDGET_DECLARE__ // #endif // __ANNOTATION_TEXT_ORIENTATION_WIDGET_DECLARE__ } // namespace #endif //__ANNOTATION_TEXT_ORIENTATION_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationTextSubstitutionViewController.cxx000066400000000000000000000420701360521144700305150ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_TEXT_SUBSTITUTION_VIEW_CONTROLLER_DECLARE__ #include "AnnotationTextSubstitutionViewController.h" #undef __ANNOTATION_TEXT_SUBSTITUTION_VIEW_CONTROLLER_DECLARE__ #include #include #include #include #include #include #include #include #include #include "AnnotationTextSubstitutionFile.h" #include "Brain.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "DisplayPropertiesAnnotationTextSubstitution.h" #include "EventGetOrSetUserInputModeProcessor.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventMapYokingSelectMap.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUserInterfaceUpdate.h" #include "EventManager.h" #include "GuiManager.h" #include "MapYokingGroupComboBox.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AnnotationTextSubstitutionViewController * \brief View controller for display of annotations. * \ingroup GuiQt */ /** * Constructor. * * @param browserWindowIndex * Index of the browser window. * @param parentObjectName * Name of parent object for macros * @param parent * The parent widget. */ AnnotationTextSubstitutionViewController::AnnotationTextSubstitutionViewController(const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { m_sceneAssistant = new SceneClassAssistant(); m_enableSubstitutionsCheckBox = new QCheckBox("Enable Substitutions"); QObject::connect(m_enableSubstitutionsCheckBox, &QCheckBox::clicked, this, &AnnotationTextSubstitutionViewController::enableCheckBoxClicked); m_enableSubstitutionsCheckBox->setObjectName(parentObjectName + ":Substitutions:Enable"); m_enableSubstitutionsCheckBox->setToolTip("Enable Text Annotation Substitutions"); WuQMacroManager::instance()->addMacroSupportToObject(m_enableSubstitutionsCheckBox, "Enable annotation subsitutions"); QButtonGroup* buttonGroup = new QButtonGroup(); QWidget* fileWidget = new QWidget(); fileWidget->setSizePolicy(fileWidget->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); QGridLayout* fileGridLayout = new QGridLayout(fileWidget); for (int32_t i = 0; i < MAXIMUM_NUMBER_OF_FILES; i++) { QRadioButton* rb = new QRadioButton(" "); QObject::connect(rb, &QCheckBox::clicked, [=] { fileRadioButtonClicked(i); } ); buttonGroup->addButton(rb); MapYokingGroupComboBox* ycb = new MapYokingGroupComboBox(this); QObject::connect(ycb, &MapYokingGroupComboBox::itemActivated, [=] { fileMapYokingGroupComboBoxChanged(i); } ); QSpinBox* sb = new QSpinBox(); sb->setRange(1, 100); #if QT_VERSION >= 0x050700 QObject::connect(sb, QOverload::of(&QSpinBox::valueChanged), [=] { valueIndexSpinBoxChanged(i); } ); #else QObject::connect(sb, static_cast(&QSpinBox::valueChanged), [=] { valueIndexSpinBoxChanged(i); } ); #endif QLabel* fl = new QLabel(); if (i == 0) { const int row = fileGridLayout->rowCount(); int32_t column = 0; fileGridLayout->setColumnStretch(column, 0); fileGridLayout->addWidget(new QLabel("On"), row, column++, Qt::AlignHCenter); fileGridLayout->setColumnStretch(column, 0); fileGridLayout->addWidget(new QLabel("Yoke"), row, column++, Qt::AlignHCenter); fileGridLayout->setColumnStretch(column, 0); fileGridLayout->addWidget(new QLabel("Index"), row, column++, Qt::AlignHCenter); fileGridLayout->setColumnStretch(column, 100); fileGridLayout->addWidget(new QLabel("File"), row, column++, Qt::AlignHCenter); } const int row = fileGridLayout->rowCount(); int32_t column = 0; fileGridLayout->addWidget(rb, row, column++); fileGridLayout->addWidget(ycb->getWidget(), row, column++); fileGridLayout->addWidget(sb, row, column++); fileGridLayout->addWidget(fl, row, column++); FileGuiControls* fgc = new FileGuiControls(rb, sb, ycb, fl); m_fileGuiControls.push_back(fgc); } QScrollArea* fileScrollArea = new QScrollArea(); fileScrollArea->setWidget(fileWidget); fileScrollArea->setWidgetResizable(true); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(m_enableSubstitutionsCheckBox, 0); layout->addWidget(fileScrollArea, 0); layout->addStretch(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); s_allAnnotationTextSubstitutionViewControllers.insert(this); updateSelections(); } /** * Destructor. */ AnnotationTextSubstitutionViewController::~AnnotationTextSubstitutionViewController() { EventManager::get()->removeAllEventsFromListener(this); delete m_sceneAssistant; s_allAnnotationTextSubstitutionViewControllers.erase(this); } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void AnnotationTextSubstitutionViewController::receiveEvent(Event* event) { bool doUpdateFlag = false; if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE) { doUpdateFlag = true; } else if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* eventUI = dynamic_cast(event); CaretAssert(eventUI); doUpdateFlag = true; eventUI->setEventProcessed(); } if (doUpdateFlag) { updateSelections(); } } /** * Called when enable checkbox is clicked. * * @param clicked * New checked status */ void AnnotationTextSubstitutionViewController::enableCheckBoxClicked(bool clicked) { DisplayPropertiesAnnotationTextSubstitution* dpats = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotationTextSubstitution(); dpats->setEnableSubstitutions(clicked); updateOtherViewControllersAndGraphics(-1); } /** * Called when a file radio button is clicked. * * @param index * Index of radio button that was clicked. */ void AnnotationTextSubstitutionViewController::fileRadioButtonClicked(int32_t fileIndex) { if (fileIndex >= 0) { CaretAssertVectorIndex(m_fileGuiControls, fileIndex); DisplayPropertiesAnnotationTextSubstitution* dpats = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotationTextSubstitution(); dpats->setSelectedFile(m_fileGuiControls[fileIndex]->m_dataFile); updateOtherViewControllersAndGraphics(fileIndex); } } /** * Called when a file value index spin box is changed. * * @param fileIndex * Index of file value index spin box that was changed. */ void AnnotationTextSubstitutionViewController::valueIndexSpinBoxChanged(int32_t fileIndex) { if (fileIndex >= 0) { CaretAssertVectorIndex(m_fileGuiControls, fileIndex); AnnotationTextSubstitutionFile* textSubFile = m_fileGuiControls[fileIndex]->m_dataFile; CaretAssert(textSubFile); QSpinBox* spinBox = m_fileGuiControls[fileIndex]->m_valueIndexSpinBox; CaretAssert(spinBox); const int32_t valueIndex = (spinBox->value() - spinBox->minimum()); MapYokingGroupEnum::Enum mapYoking = textSubFile->getMapYokingGroup(); if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { EventMapYokingSelectMap selectMapEvent(mapYoking, NULL, textSubFile, valueIndex, true); EventManager::get()->sendEvent(selectMapEvent.getPointer()); } else { textSubFile->setSelectedValueIndex(valueIndex); } updateOtherViewControllersAndGraphics(fileIndex); } } /** * Called when a file map yoking group combo box is changed. * * @param fileIndex * Index of file map yoking group combo box that was changed. */ void AnnotationTextSubstitutionViewController::fileMapYokingGroupComboBoxChanged(int32_t fileIndex) { if (fileIndex >= 0) { CaretAssertVectorIndex(m_fileGuiControls, fileIndex); AnnotationTextSubstitutionFile* textSubFile = m_fileGuiControls[fileIndex]->m_dataFile; CaretAssert(textSubFile); MapYokingGroupComboBox* mapComboBox = m_fileGuiControls[fileIndex]->m_mapYokingGroupComboBox; mapComboBox->validateYokingChange(textSubFile); updateOtherViewControllersAndGraphics(fileIndex); } } /** * Update other selection annotation selectors since they may share properties * and also update graphics. * * @param fileIndex * Index of file. */ void AnnotationTextSubstitutionViewController::updateOtherViewControllersAndGraphics(const int32_t fileIndex) { for (auto avc : s_allAnnotationTextSubstitutionViewControllers) { if (avc != this) { avc->updateSelections(); } } bool updateAllFlag = false; if (fileIndex >= 0) { CaretAssertVectorIndex(m_fileGuiControls, fileIndex); if (m_fileGuiControls[fileIndex]->m_mapYokingGroupComboBox->getMapYokingGroup() != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { updateAllFlag = true; } } if (updateAllFlag) { EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Update the annotation selections. */ void AnnotationTextSubstitutionViewController::updateSelections() { Brain* brain = GuiManager::get()->getBrain(); CaretAssert(brain); DisplayPropertiesAnnotationTextSubstitution* dpats = brain->getDisplayPropertiesAnnotationTextSubstitution(); m_enableSubstitutionsCheckBox->setChecked(dpats->isEnableSubstitutions()); AnnotationTextSubstitutionFile* selectedFile = dpats->getSelectedFile(); std::vector allFiles; brain->getAnnotationTextSubstitutionFiles(allFiles); const int32_t numFiles = static_cast(allFiles.size()); const int32_t numItems = static_cast(m_fileGuiControls.size()); for (int32_t i = 0; i < numItems; i++) { CaretAssertVectorIndex(m_fileGuiControls, i); FileGuiControls* fgc = m_fileGuiControls[i]; CaretAssert(fgc); /* * Spin boxes always emit signals when value changed */ QSignalBlocker spinBoxBlocker(fgc->m_valueIndexSpinBox); bool visibleFlag = false; if (i < numFiles) { visibleFlag = true; CaretAssertVectorIndex(allFiles, i); AnnotationTextSubstitutionFile* file = allFiles[i]; CaretAssert(file); fgc->m_selectionRadioButton->setChecked(file == selectedFile); fgc->m_mapYokingGroupComboBox->setMapYokingGroup(file->getMapYokingGroup()); const int32_t maxValue = std::max(1, file->getNumberOfValues()); fgc->m_valueIndexSpinBox->setRange(1, maxValue); fgc->m_valueIndexSpinBox->setValue(file->getSelectedValueIndex() + fgc->m_valueIndexSpinBox->minimum()); fgc->m_fileNameLabel->setText(file->getFileNameNoPath()); fgc->m_fileNameLabel->setToolTip(file->getFileName()); fgc->m_dataFile = file; } else { fgc->m_dataFile = NULL; } fgc->m_selectionRadioButton->setVisible(visibleFlag); fgc->m_mapYokingGroupComboBox->getWidget()->setVisible(visibleFlag); fgc->m_valueIndexSpinBox->setVisible(visibleFlag); fgc->m_fileNameLabel->setVisible(visibleFlag); } // const DisplayPropertiesAnnotation* dpa = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotation(); // // BrowserTabContent* browserTabContent = // GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); // if (browserTabContent == NULL) { // return; // } // const int32_t browserTabIndex = browserTabContent->getTabNumber(); // // m_displayAnnotationsCheckBox->setChecked(dpa->isDisplayAnnotations()); // m_displayTextAnnotationsCheckBox->setChecked(dpa->isDisplayTextAnnotations()); // m_displayWindowAnnotationInSingleTabViewsCheckBox->setChecked(dpa->isDisplayWindowAnnotationsInSingleTabViews(m_browserWindowIndex)); // // Brain* brain = GuiManager::get()->getBrain(); // std::vector annotationFiles; // brain->getAllAnnotationFilesIncludingSceneAnnotationFile(annotationFiles); // // std::vector fileItems; // for (std::vector::iterator fileIter = annotationFiles.begin(); // fileIter != annotationFiles.end(); // fileIter++) { // AnnotationFile* annFile = *fileIter; // fileItems.push_back(annFile); // } // // const DisplayGroupEnum::Enum displayGroup = dpa->getDisplayGroupForTab(browserTabIndex); // m_displayGroupComboBox->setSelectedDisplayGroup(displayGroup); // // EventGetOrSetUserInputModeProcessor inputModeEvent(m_browserWindowIndex); // EventManager::get()->sendEvent(inputModeEvent.getPointer()); // UserInputModeAbstract::UserInputMode mode = inputModeEvent.getUserInputMode(); // const bool annotationsValidFlag = (mode == UserInputModeAbstract::ANNOTATIONS); // // m_selectionViewController->updateContent(fileItems, // displayGroup, // browserTabIndex, // annotationsValidFlag); } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* AnnotationTextSubstitutionViewController::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "AnnotationTextSubstitutionViewController", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void AnnotationTextSubstitutionViewController::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/GuiQt/AnnotationTextSubstitutionViewController.h000066400000000000000000000120101360521144700301310ustar00rootroot00000000000000#ifndef __ANNOTATION_TEXT_SUBSTITUTION_VIEW_CONTROLLER_H__ #define __ANNOTATION_TEXT_SUBSTITUTION_VIEW_CONTROLLER_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "DisplayGroupEnum.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" class QCheckBox; class QLabel; class QRadioButton; class QSpinBox; namespace caret { class AnnotationTextSubstitutionFile; class MapYokingGroupComboBox; class SceneClassAssistant; class AnnotationTextSubstitutionViewController : public QWidget, public EventListenerInterface, public SceneableInterface { Q_OBJECT public: AnnotationTextSubstitutionViewController(const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent); virtual ~AnnotationTextSubstitutionViewController(); // ADD_NEW_METHODS_HERE virtual void receiveEvent(Event* event); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implemetation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private slots: void enableCheckBoxClicked(bool); void fileRadioButtonClicked(int32_t fileIndex); void valueIndexSpinBoxChanged(int32_t fileIndex); void fileMapYokingGroupComboBoxChanged(int32_t fileIndex); private: class FileGuiControls { public: FileGuiControls(const int32_t index); FileGuiControls(QRadioButton* selectionRadioButton, QSpinBox* valueIndexSpinBox, MapYokingGroupComboBox* mapYokingGroupSpinBox, QLabel* fileNameLabel) : m_selectionRadioButton(selectionRadioButton), m_valueIndexSpinBox(valueIndexSpinBox), m_mapYokingGroupComboBox(mapYokingGroupSpinBox), m_fileNameLabel(fileNameLabel), m_dataFile(NULL) { } QRadioButton* m_selectionRadioButton; QSpinBox* m_valueIndexSpinBox; MapYokingGroupComboBox* m_mapYokingGroupComboBox; QLabel* m_fileNameLabel; AnnotationTextSubstitutionFile* m_dataFile; }; AnnotationTextSubstitutionViewController(const AnnotationTextSubstitutionViewController&); AnnotationTextSubstitutionViewController& operator=(const AnnotationTextSubstitutionViewController&); void updateSelections(); void updateOtherViewControllersAndGraphics(const int32_t fileIndex); SceneClassAssistant* m_sceneAssistant; QCheckBox* m_enableSubstitutionsCheckBox; int32_t m_browserWindowIndex; std::vector m_fileGuiControls; static std::set s_allAnnotationTextSubstitutionViewControllers; // ADD_NEW_MEMBERS_HERE static const int32_t MAXIMUM_NUMBER_OF_FILES = 25; }; #ifdef __ANNOTATION_TEXT_SUBSTITUTION_VIEW_CONTROLLER_DECLARE__ std::set AnnotationTextSubstitutionViewController::s_allAnnotationTextSubstitutionViewControllers; #endif // __ANNOTATION_TEXT_SUBSTITUTION_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__ANNOTATION_TEXT_SUBSTITUTION_VIEW_CONTROLLER_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationWidgetParentEnum.cxx000066400000000000000000000255741360521144700254710ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __ANNOTATION_WIDGET_PARENT_ENUM_DECLARE__ #include "AnnotationWidgetParentEnum.h" #undef __ANNOTATION_WIDGET_PARENT_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::AnnotationWidgetParentEnum * \brief * * * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_annotationWidgetParentEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void annotationWidgetParentEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "AnnotationWidgetParentEnum.h" * * Instatiate: * m_annotationWidgetParentEnumComboBox = new EnumComboBoxTemplate(this); * m_annotationWidgetParentEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_annotationWidgetParentEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(annotationWidgetParentEnumComboBoxItemActivated())); * * Update the selection: * m_annotationWidgetParentEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const AnnotationWidgetParentEnum::Enum VARIABLE = m_annotationWidgetParentEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ AnnotationWidgetParentEnum::AnnotationWidgetParentEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ AnnotationWidgetParentEnum::~AnnotationWidgetParentEnum() { } /** * Initialize the enumerated metadata. */ void AnnotationWidgetParentEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(AnnotationWidgetParentEnum(ANNOTATION_TOOL_BAR_WIDGET, "ANNOTATION_TOOL_BAR_WIDGET", "Annotation Tool Bar Widget")); enumData.push_back(AnnotationWidgetParentEnum(PARENT_ENUM_FOR_LATER_USE, "PARENT_ENUM_FOR_LATER_USE", "For future usage")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const AnnotationWidgetParentEnum* AnnotationWidgetParentEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const AnnotationWidgetParentEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationWidgetParentEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationWidgetParentEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationWidgetParentEnum::Enum AnnotationWidgetParentEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationWidgetParentEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationWidgetParentEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type AnnotationWidgetParentEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString AnnotationWidgetParentEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationWidgetParentEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ AnnotationWidgetParentEnum::Enum AnnotationWidgetParentEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationWidgetParentEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationWidgetParentEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type AnnotationWidgetParentEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t AnnotationWidgetParentEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const AnnotationWidgetParentEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ AnnotationWidgetParentEnum::Enum AnnotationWidgetParentEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = AnnotationWidgetParentEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const AnnotationWidgetParentEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type AnnotationWidgetParentEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void AnnotationWidgetParentEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationWidgetParentEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(AnnotationWidgetParentEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void AnnotationWidgetParentEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(AnnotationWidgetParentEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/GuiQt/AnnotationWidgetParentEnum.h000066400000000000000000000071451360521144700251100ustar00rootroot00000000000000#ifndef __ANNOTATION_WIDGET_PARENT_ENUM_H__ #define __ANNOTATION_WIDGET_PARENT_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class AnnotationWidgetParentEnum { public: /** * Enumerated values. */ enum Enum { /** Parent is the annotation toolbar */ ANNOTATION_TOOL_BAR_WIDGET, /* * There is only one enum at this time. * There was a second enum for use when the color bar was edited * on the Map and Overlay Settings dialog prior to color bar * becoming an annotation. * * This enumerated type is being preserved in the event there * are other parents for editing annotations such as a * right-click pop-up dialog. */ PARENT_ENUM_FOR_LATER_USE }; ~AnnotationWidgetParentEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: AnnotationWidgetParentEnum(const Enum enumValue, const AString& name, const AString& guiName); static const AnnotationWidgetParentEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __ANNOTATION_WIDGET_PARENT_ENUM_DECLARE__ std::vector AnnotationWidgetParentEnum::enumData; bool AnnotationWidgetParentEnum::initializedFlag = false; int32_t AnnotationWidgetParentEnum::integerCodeCounter = 0; #endif // __ANNOTATION_WIDGET_PARENT_ENUM_DECLARE__ } // namespace #endif //__ANNOTATION_WIDGET_PARENT_ENUM_H__ connectome-workbench-1.4.2/src/GuiQt/AnnotationWidthHeightWidget.cxx000066400000000000000000000224371360521144700256160ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ANNOTATION_WIDTH_HEIGHT_WIDGET_DECLARE__ #include "AnnotationWidthHeightWidget.h" #undef __ANNOTATION_WIDTH_HEIGHT_WIDGET_DECLARE__ #include #include #include #include "AnnotationBox.h" #include "AnnotationManager.h" #include "AnnotationRedoUndoCommand.h" #include "AnnotationTwoDimensionalShape.h" #include "Brain.h" #include "CaretAssert.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "GuiManager.h" #include "WuQFactory.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::AnnotationWidthHeightWidget * \brief Widget for editing annotation coordinate, size, and rotation. * \ingroup GuiQt */ /** * Constructor. * * @param parentWidgetType * Type of parent widget * @param browserWindowIndex * Index of browser window. * @param parent * Parent of this widget. */ AnnotationWidthHeightWidget::AnnotationWidthHeightWidget(const AnnotationWidgetParentEnum::Enum parentWidgetType, const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), m_parentWidgetType(parentWidgetType), m_browserWindowIndex(browserWindowIndex) { QString widthLabelText; QString heightLabelText; switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: widthLabelText = " W:"; heightLabelText = " H:"; break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } QLabel* widthLabel = new QLabel(widthLabelText); m_widthSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 1000.0, 0.1, 1, this, SLOT(widthValueChanged(double))); m_widthSpinBox->setSuffix("%"); WuQtUtilities::setWordWrappedToolTip(m_widthSpinBox, "Percentage width of 2D Shapes (Box, Image, Oval)"); QLabel* heightLabel = new QLabel(heightLabelText); m_heightSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 1000.0, 0.1, 1, this, SLOT(heightValueChanged(double))); m_heightSpinBox->setSuffix("%"); WuQtUtilities::setWordWrappedToolTip(m_heightSpinBox, "Percentage height of 2D Shapes (Box, Image, Oval)"); QHBoxLayout* layout = new QHBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); layout->addWidget(widthLabel); layout->addWidget(m_widthSpinBox); layout->addWidget(heightLabel); layout->addWidget(m_heightSpinBox); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } /** * Destructor. */ AnnotationWidthHeightWidget::~AnnotationWidthHeightWidget() { } /** * Update with the given annotation. * * @param annotations2D. * Two dimensional annotation. */ void AnnotationWidthHeightWidget::updateContent(std::vector& annotations2D) { m_annotations2D = annotations2D; if ( ! m_annotations2D.empty()) { float widthValue = 0.0; bool haveMultipleWidthValuesFlag = false; float heightValue = 0.0; bool haveMultipleHeightValuesFlag = false; bool firstFlag = true; bool haveValuesFlag = false; const int32_t numAnns = static_cast(m_annotations2D.size()); for (int32_t i = 0; i < numAnns; i++) { CaretAssertVectorIndex(m_annotations2D, i); if (m_annotations2D[i]->getType() == AnnotationTypeEnum::TEXT) { continue; } haveValuesFlag = true; const float width = m_annotations2D[i]->getWidth(); const float height = m_annotations2D[i]->getHeight(); if (firstFlag) { widthValue = width; heightValue = height; firstFlag = false; } else { if (width != widthValue) { haveMultipleWidthValuesFlag = true; } if (height != heightValue) { haveMultipleHeightValuesFlag = true; } widthValue = std::min(widthValue, width); heightValue = std::min(heightValue, height); } } if (haveValuesFlag) { m_widthSpinBox->blockSignals(true); m_widthSpinBox->setValue(widthValue); if (haveMultipleWidthValuesFlag) { m_widthSpinBox->setSuffix("%+"); } else { m_widthSpinBox->setSuffix("%"); } m_widthSpinBox->blockSignals(false); m_heightSpinBox->blockSignals(true); m_heightSpinBox->setValue(heightValue); if (haveMultipleHeightValuesFlag) { m_heightSpinBox->setSuffix("%+"); } else { m_heightSpinBox->setSuffix("%"); } m_heightSpinBox->blockSignals(false); switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: AnnotationTwoDimensionalShape::setUserDefaultWidth(widthValue); AnnotationTwoDimensionalShape::setUserDefaultHeight(heightValue); break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } setEnabled(true); } else { setEnabled(false); } } else { setEnabled(false); } } /** * Gets called when height value is changed. * * @param value * */ void AnnotationWidthHeightWidget::heightValueChanged(double value) { std::vector annotations(m_annotations2D.begin(), m_annotations2D.end()); AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeTwoDimHeight(value, annotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: AnnotationTwoDimensionalShape::setUserDefaultHeight(value); break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Gets called when width value is changed. * * @param value * */ void AnnotationWidthHeightWidget::widthValueChanged(double value) { std::vector annotations(m_annotations2D.begin(), m_annotations2D.end()); AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeTwoDimWidth(value, annotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: AnnotationTwoDimensionalShape::setUserDefaultWidth(value); break; case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: CaretAssert(0); break; } EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } connectome-workbench-1.4.2/src/GuiQt/AnnotationWidthHeightWidget.h000066400000000000000000000047041360521144700252400ustar00rootroot00000000000000#ifndef __ANNOTATION_WIDTH_HEIGHT_WIDGET_H__ #define __ANNOTATION_WIDTH_HEIGHT_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "AnnotationWidgetParentEnum.h" class QDoubleSpinBox; namespace caret { class AnnotationTwoDimensionalShape; class AnnotationWidthHeightWidget : public QWidget { Q_OBJECT public: AnnotationWidthHeightWidget(const AnnotationWidgetParentEnum::Enum parentWidgetType, const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~AnnotationWidthHeightWidget(); // ADD_NEW_METHODS_HERE void updateContent(std::vector& annotations2D); private slots: void widthValueChanged(double value); void heightValueChanged(double value); private: AnnotationWidthHeightWidget(const AnnotationWidthHeightWidget&); AnnotationWidthHeightWidget& operator=(const AnnotationWidthHeightWidget&); // ADD_NEW_MEMBERS_HERE const AnnotationWidgetParentEnum::Enum m_parentWidgetType; const int32_t m_browserWindowIndex; QDoubleSpinBox* m_widthSpinBox; QDoubleSpinBox* m_heightSpinBox; std::vector m_annotations2D; }; #ifdef __ANNOTATION_WIDTH_HEIGHT_WIDGET_DECLARE__ // #endif // __ANNOTATION_WIDTH_HEIGHT_WIDGET_DECLARE__ } // namespace #endif //__ANNOTATION_WIDTH_HEIGHT_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/BalsaDatabaseManager.cxx000066400000000000000000001743321360521144700241530ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __BALSA_DATABASE_MANAGER_DECLARE__ #include "BalsaDatabaseManager.h" #undef __BALSA_DATABASE_MANAGER_DECLARE__ #include #include "BalsaUserRoles.h" #include "CaretAssert.h" #include "CaretHttpManager.h" #include "CaretLogger.h" #include "CommandOperationManager.h" #include "EventManager.h" #include "EventProgressUpdate.h" #include "FileInformation.h" #include "JsonHelper.h" #include "OperationZipSceneFile.h" #include "ProgramParameters.h" #include "Scene.h" #include "SceneFile.h" using namespace caret; /** * \class caret::BalsaDatabaseManager * \brief Manages connection with BALSA Database. * \ingroup GuiQt */ /** * Constructor. */ BalsaDatabaseManager::BalsaDatabaseManager() : CaretObject() { m_debugFlag = false; logout(); //EventManager::get()->addEventListener(this, EventTypeEnum::); } /** * Destructor. */ BalsaDatabaseManager::~BalsaDatabaseManager() { EventManager::get()->removeAllEventsFromListener(this); } /** * Get a description of this object's content. * @return String describing this object's content. */ AString BalsaDatabaseManager::toString() const { return "BalsaDatabaseManager"; } /** * Login to the BALSA Database. * * @param databaseURL * URL of the database for login * @param username * Name for login. * @param password * Password for login. * @param errorMessageOut * Contains error information if login failed. * @return * True if login is successful, else false. */ bool BalsaDatabaseManager::login(const AString& databaseURL, const AString& username, const AString& password, AString& errorMessageOut) { errorMessageOut.clear(); m_databaseURL = databaseURL; m_username = username.trimmed(); m_password = password.trimmed(); m_jSessionIdCookie = ""; const AString loginURL(databaseURL + "/j_spring_security_check"); CaretHttpRequest loginRequest; loginRequest.m_method = CaretHttpManager::POST_ARGUMENTS; loginRequest.m_url = loginURL; loginRequest.m_arguments.push_back(std::make_pair("j_username", m_username)); loginRequest.m_arguments.push_back(std::make_pair("j_password", m_password)); CaretHttpResponse loginResponse; CaretHttpManager::httpRequest(loginRequest, loginResponse); if (m_debugFlag) { std::cout << "Response Code: " << loginResponse.m_responseCode << std::endl; } for (std::map::iterator mapIter = loginResponse.m_headers.begin(); mapIter != loginResponse.m_headers.end(); mapIter++) { if (mapIter->first == "Set-Cookie") { const AString value = mapIter->second; const int equalPos = value.indexOf("="); const int semiPos = value.indexOf(";"); if ((equalPos >= 0) && (semiPos > (equalPos + 1))) { const int offset = equalPos + 1; const int length = semiPos - offset; m_jSessionIdCookie = value.mid(offset, length); } } if (m_debugFlag) { std::cout << " Response Header: " << qPrintable(mapIter->first) << " -> " << qPrintable(mapIter->second) << std::endl; } } if (m_debugFlag) { std::cout << "SessionID: " << qPrintable(m_jSessionIdCookie) << std::endl; } if (loginResponse.m_responseCode == 200) { if (m_jSessionIdCookie.isEmpty()) { errorMessageOut = ("Login was successful but BALSA failed to provide a Session ID."); logout(); return false; } return true; } else if (loginResponse.m_responseCode == 302) { errorMessageOut = ("Login failed.

" "If you are unable to login, helpful links are located on the right side of the username and password boxes:" "

    " "
  • Register: Click to create a BALSA account" "
  • Forgot Username: Click to get your username by entering your email address" "
  • Forgot Password: Click to reset your password by entering your username" "
"); logout(); return false; } loginResponse.m_body.push_back('\0'); const AString responseContent(&loginResponse.m_body[0]); errorMessageOut = ("Login has failed.\n" "HTTP Code: " + AString::number(loginResponse.m_responseCode) + " Content: " + responseContent); if (loginResponse.m_responseCode < 0) { errorMessageOut.appendWithNewLine(loginResponse.m_errorMessage); } logout(); return false; } /** * Logout of the database */ void BalsaDatabaseManager::logout() { m_databaseURL.clear(); m_username.clear(); m_password.clear(); m_jSessionIdCookie.clear(); } /** * Upload file to the BALSA Database. * * @param uploadURL * URL for uploading file. * @param fileName * Name of file. * @param httpContentTypeName * Type of content for upload (eg: application/zip, see http://www.freeformatter.com/mime-types-list.html) * @param responseContentOut * If successful, contains the response content received after successful upload. * @param errorMessageOut * Contains error information if upload failed. * @return * True if upload is successful, else false. */ bool BalsaDatabaseManager::uploadFile(const AString& uploadURL, const AString& fileName, const AString& httpContentTypeName, AString& responseContentOut, AString& errorMessageOut) { responseContentOut.clear(); errorMessageOut.clear(); const bool successFlag = uploadFileWithCaretHttpManager(uploadURL, fileName, httpContentTypeName, responseContentOut, errorMessageOut); return successFlag; } /** * Upload file to the BALSA Database. * * @param uploadURL * URL for uploading file. * @param fileName * Name of file. * @param httpContentTypeName * Type of content for upload (eg: application/zip, see http://www.freeformatter.com/mime-types-list.html) * @param responseContentOut * If successful, contains the response content received after successful upload. * @param errorMessageOut * Contains error information if upload failed. * @return * True if upload is successful, else false. */ bool BalsaDatabaseManager::uploadFileWithCaretHttpManager(const AString& uploadURL, const AString& fileName, const AString& httpContentTypeName, AString& responseContentOut, AString& errorMessageOut) { responseContentOut.clear(); errorMessageOut.clear(); if (httpContentTypeName.isEmpty()) { errorMessageOut = ("Content Type Name is empty. " "See http://www.freeformatter.com/mime-types-list.html for examples."); return false; } FileInformation fileInfo(fileName); if ( ! fileInfo.exists()) { errorMessageOut = (fileName + " does not exist."); return false; } const int64_t fileSize = fileInfo.size(); if (fileSize <= 0) { errorMessageOut = (fileName + " does not contain any data (size=0)"); return false; } /* * Upload file name must be name of file without path */ const AString uploadFileName(fileInfo.getFileName()); const AString fileSizeString(AString::number(fileSize)); CaretHttpRequest uploadRequest; uploadRequest.m_method = CaretHttpManager::POST_FILE; uploadRequest.m_url = uploadURL; uploadRequest.m_uploadFileName = fileName; uploadRequest.m_headers.insert(std::make_pair("Content-Type", httpContentTypeName)); uploadRequest.m_headers.insert(std::make_pair("Cookie", getJSessionIdCookie())); uploadRequest.m_headers.insert(std::make_pair("X-File-Name", uploadFileName)); uploadRequest.m_headers.insert(std::make_pair("X-File-Size", fileSizeString)); CaretHttpResponse uploadResponse; CaretHttpManager::httpRequest(uploadRequest, uploadResponse); uploadResponse.m_body.push_back('\0'); responseContentOut.append(&uploadResponse.m_body[0]); return verifyUploadFileResponse(uploadResponse.m_headers, responseContentOut, uploadResponse.m_responseCode, uploadResponse.m_errorMessage, errorMessageOut); } /** * Process the response from file upload. Content should be JSON. * * @param responseHeaders * Headers from the response. * @param responseContent * Content from the response. * @param responseHttpCode * HTTP code from response. * @param responseErrorMessage * * @param errorMessageOut * Contains description of error. * @return * True if response shows upload was successful, else false. */ bool BalsaDatabaseManager::verifyUploadFileResponse(const std::map& responseHeaders, const AString& responseContent, const int32_t responseHttpCode, const AString& responseErrorMessage, AString& errorMessageOut) const { if (responseHttpCode != 200) { if (responseHttpCode == 403) { errorMessageOut = ("Upload failed. (Http Code=" + AString::number(responseHttpCode) + ").\n\n" "Either you do now have ownership/permission to edit the study or " "the study has been submitted for curation.\n\n" "Use your web browser to login to BALSA to view the study and " "check its permissions. If the the study has been submitted for " "curation, there will be a 'return for revision' option on the study. " "Selection of 'return for 'revision' will allow you to upload your data."); } else { errorMessageOut = ("Upload failed. Http Code=" + AString::number(responseHttpCode) + ".\n" + responseErrorMessage); // if (responseHttpCode < 0) { // const QString s(responseContent.isEmpty() // ? "Response content is empty !!!" // : ("Response content:\n" // + responseContent)); // CaretLogSevere("Invalid http response=" // + AString::number(responseHttpCode) // + "\n" // + s // + "\n"); // } } return false; } if (responseHeaders.empty()) { if (m_debugFlag) std::cout << "Response headers from upload are empty." << std::endl; } bool haveContentTypeFlag = false; AString contentTypeString; for (std::map::const_iterator iter = responseHeaders.begin(); iter != responseHeaders.end(); iter++) { if (m_debugFlag) std::cout << "Response Header: " << iter->first << " -> " << iter->second << std::endl; if (iter->first == "Content-Type") { haveContentTypeFlag = true; contentTypeString = iter->second; } } AString contentErrorMessage; bool haveJsonResponseContentFlag = false; if (haveContentTypeFlag) { if (contentTypeString.startsWith("application/json;")) { haveJsonResponseContentFlag = true; } else { contentErrorMessage = ("Content-Type received from file upload is not JSON but is " + contentTypeString + "\n"); } } else { contentErrorMessage = "No Content-Type header received from file upload.\n"; } if (m_debugFlag) { std::cout << std::endl << "RESPONSE CONTENT: " << responseContent << std::endl << std::endl; } AString statusText; if (haveJsonResponseContentFlag) { if (responseContent.isEmpty()) { errorMessageOut = "Process upload response content is empty."; return false; } QJsonParseError jsonError; QJsonDocument jsonDocument = QJsonDocument::fromJson(responseContent.toUtf8(), &jsonError); if (jsonDocument.isNull()) { errorMessageOut = ("Process upload response failed. Failed to parse JSON, error:" + jsonError.errorString() + " Offset=" + AString::number(jsonError.offset) + "\n\n" "Response Content: " + responseContent); return false; } QByteArray json = jsonDocument.toJson(); if (m_debugFlag) { std::cout << "Array?: " << jsonDocument.isArray() << std::endl; std::cout << "Empty?: " << jsonDocument.isEmpty() << std::endl; std::cout << "NULL?: " << jsonDocument.isNull() << std::endl; std::cout << "Object?: " << jsonDocument.isObject() << std::endl; std::cout << "JSON length: " << json.size() << std::endl; AString str(json); std::cout << ("Formatted JSON:\n" + str) << std::endl; } if ( ! jsonDocument.isObject()) { errorMessageOut = ("Process upload response failed. JSON content is not an object." "JSON is displayed in terminal if logging level is warning or higher."); CaretLogWarning("Study ID JSON is not Object\n" + AString(jsonDocument.toJson())); return false; } QJsonObject responseObject = jsonDocument.object(); const QJsonValue statusValue = responseObject.value("statusText"); if (statusValue.type() == QJsonValue::String) { statusText = statusValue.toString(); } if (m_debugFlag) { std::cout << "Status Text: " << statusText << std::endl; } } else { errorMessageOut = contentErrorMessage; return false; } return true; } /** * Zip a scene file and its data files. * * @param sceneFile * Scene file that is zipped. * @param extractDirectory * Directory into which files are extracted. * @param zipFileName * Name for the ZIP file. * @param errorMessageOut * Contains error information if zipping failed. * @return * True if zipping is successful, else false. */ bool BalsaDatabaseManager::zipSceneAndDataFiles(const SceneFile* sceneFile, const AString& extractDirectory, const AString& zipFileName, AString& errorMessageOut) { errorMessageOut.clear(); if (sceneFile == NULL) { errorMessageOut = "Scene file is invalid."; return false; } const QString sceneFileName = sceneFile->getFileName(); if (sceneFileName.isEmpty()) { errorMessageOut = "Scene File does not have a name."; return false; } const AString extractToDirectoryName = extractDirectory; if (extractToDirectoryName.isEmpty()) { errorMessageOut = "Extract to directory is empty."; return false; } if (zipFileName.isEmpty()) { errorMessageOut = "Zip File name is empty"; return false; } AString basePathName; switch (sceneFile->getBasePathType()) { case SceneFileBasePathTypeEnum::AUTOMATIC: { std::vector missingFileNames; AString errorMessage; const bool validBasePathFlag = sceneFile->findBaseDirectoryForDataFiles(basePathName, missingFileNames, errorMessage); if ( ! validBasePathFlag) { errorMessageOut.appendWithNewLine("Automatic Base Path Failed: " + errorMessage); return false; } if ( ! FileInformation(basePathName).exists()) { errorMessageOut = ("AUTOMATIC base path mode produced an invalid base path (directory does not exist). " ". \"" + basePathName + "\"."); return false; } } break; case SceneFileBasePathTypeEnum::CUSTOM: basePathName = sceneFile->getBalsaCustomBaseDirectory(); if (basePathName.isEmpty()) { errorMessageOut = ("CUSTOM base path is empty"); return false; } if ( ! FileInformation(basePathName).exists()) { errorMessageOut = ("CUSTOM base path is invalid (directory does not exist): \"" + basePathName + "\""); return false; } break; } bool successFlag = false; try { OperationZipSceneFile::createZipFile(NULL, sceneFileName, extractToDirectoryName, zipFileName, basePathName, OperationZipSceneFile::PROGRESS_GUI_EVENT); successFlag = true; } catch (const CaretException& e) { AString moreInfo("If there was an error opening or writing to the ZIP file, " "it may caused by incorrect permissions or insufficient space in the " "temporary directory used for creating the ZIP file. Use the ZIP File Directory Custom option " "in the Advanced Tab to choose an alternative directory."); errorMessageOut = ("Error: " + e.whatString() + "\n\n" + moreInfo); } return successFlag; } /** * @return The JSESSIONID Cookie value (empty if not valid). */ AString BalsaDatabaseManager::getJSessionIdCookie() const { return m_jSessionIdCookie; } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void BalsaDatabaseManager::receiveEvent(Event* /*event*/) { // if (event->getEventType() == EventTypeEnum::) { // eventName = dynamic_cast(event); // CaretAssert(eventName); // // event->setEventProcessed(); // } } /** * Request BALSA database process the file that was uploaded. * * @param sceneFile * Scene file that was uploaded. * @param processUploadURL * URL for uploading file. * @param httpContentTypeName * Type of content for upload (eg: application/zip, see http://www.freeformatter.com/mime-types-list.html) * @param updateSceneIDsFromResponseFlag * If true, update the Scene IDs using those in the response content. * @param errorMessageOut * Contains error information if upload failed. * @return * True if upload is successful, else false. */ bool BalsaDatabaseManager::processUploadedFile(SceneFile* sceneFile, const AString& processUploadURL, const AString& httpContentTypeName, const bool updateSceneIDsFromResponseFlag, AString& errorMessageOut) { errorMessageOut.clear(); if (httpContentTypeName.isEmpty()) { errorMessageOut = ("Content Type Name is empty. " "See http://www.freeformatter.com/mime-types-list.html for examples."); return false; } CaretHttpRequest uploadRequest; uploadRequest.m_method = CaretHttpManager::POST_ARGUMENTS; uploadRequest.m_url = processUploadURL; uploadRequest.m_headers.insert(std::make_pair("Content-Type", httpContentTypeName)); uploadRequest.m_headers.insert(std::make_pair("Cookie", getJSessionIdCookie())); uploadRequest.m_arguments.push_back(std::make_pair("type", "json")); CaretHttpResponse uploadResponse; CaretHttpManager::httpRequest(uploadRequest, uploadResponse); if (m_debugFlag) { std::cout << "Process upload response Code: " << uploadResponse.m_responseCode << std::endl; } if (uploadResponse.m_responseCode != 200) { errorMessageOut = ("Process Upload failed code: " + QString::number(uploadResponse.m_responseCode) + ". "); errorMessageOut.appendWithNewLine(uploadResponse.m_errorMessage); uploadResponse.m_body.push_back('\0'); AString responseContent(&uploadResponse.m_body[0]); if (m_debugFlag) { std::cout << errorMessageOut << std::endl; std::cout << "Process Upload FAILED to BALSA reply body: " << responseContent << std::endl; } else { CaretLogFine("Process Upload FAILED to BALSA reply error message in GUI: " + errorMessageOut + "Process Upload FAILED to BALSA reply body: " + responseContent); } return false; } /* * As of 24 Oct 2017, Scene IDs are updated prior to uploading scene fiel */ if (updateSceneIDsFromResponseFlag) { for (std::map::iterator mapIter = uploadResponse.m_headers.begin(); mapIter != uploadResponse.m_headers.end(); mapIter++) { if (m_debugFlag) { std::cout << " Process Upload Response Header: " << qPrintable(mapIter->first) << " -> " << qPrintable(mapIter->second) << std::endl; } } uploadResponse.m_body.push_back('\0'); AString responseContent(&uploadResponse.m_body[0]); if (m_debugFlag) { std::cout << "Process Upload to BALSA reply body: " << responseContent << std::endl; } else { CaretLogFine("Process Upload to BALSA reply body: " + responseContent); } AString contentType = getHeaderValue(uploadResponse, "Content-Type"); if (contentType.isNull()) { errorMessageOut = ("Process Upload Content type returned by BALSA is unknown"); return false; } if ( ! contentType.toLower().startsWith("application/json")) { errorMessageOut = ("Process Upload Content type return by BALSA should be JSON format but is " + contentType + "Scene File was uploaded but Scene IDs will not be updated"); return false; } if ( ! updateSceneIdsFromProcessUploadResponse(sceneFile, responseContent, errorMessageOut)) { return false; } } return true; } /** * Get the Scene IDs from the JSON content returned by * the process upload command and update the scene file. * * @param sceneFile * Scene file that was uploaded. * @param jsonContent * The JSON content. * @param errorMessage * Contains error information if there is a problem. * @return * true if successful, else false. */ bool BalsaDatabaseManager::updateSceneIdsFromProcessUploadResponse(SceneFile* sceneFile, const AString& jsonContent, AString& errorMessageOut) { QJsonParseError jsonError; QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonContent.toUtf8(), &jsonError); if (jsonDocument.isNull()) { errorMessageOut = ("Failed to parse JSON response from procssess upload, error:" + jsonError.errorString()); return false; } if ( ! jsonDocument.isArray()) { errorMessageOut = ("Unrecognized format of JSON response from process upload (not an array)"); return false; } const AString mySceneFileName = sceneFile->getFileNameNoPath(); QJsonArray jsonArray = jsonDocument.array(); const int32_t numFileAndSceneIds = jsonArray.count(); if (numFileAndSceneIds <= 0) { errorMessageOut = ("No Scene IDs were returned by BALSA. Content returned \"" + JsonHelper::jsonArrayToString(jsonArray) + "\""); return false; } for (int32_t j = 0; j < numFileAndSceneIds; j++) { SceneFileIdentifiers sceneFileIDs(m_debugFlag, jsonArray.at(j)); if ( ! sceneFileIDs.isValid()) { errorMessageOut = ("Scene File IDs error: " + sceneFileIDs.getErrorMessage()); return false; } if (sceneFileIDs.m_sceneFileName == mySceneFileName) { for (const auto& indexAndID : sceneFileIDs.m_sceneIndexAndIDsMap) { const int32_t sceneIndex = indexAndID.first; const AString sceneID = indexAndID.second; if ((sceneIndex >= 0) && (sceneIndex < sceneFile->getNumberOfScenes())) { Scene* scene = sceneFile->getSceneAtIndex(sceneIndex); CaretAssert(scene); scene->setBalsaSceneID(sceneID); } else { errorMessageOut = ("Invalid Scene Index from BALSA Scene IDs: " + AString::number(sceneIndex)); return false; } } } } return true; } /** * Get the value for the given header name using * a case-insensitive string comparison. * * @param httpResponse * The HTTP response. * @param headerName * The header name. * @return * Value for header name. If the header name is * not found the returned string will be NULL * (test with .isNull()). */ AString BalsaDatabaseManager::getHeaderValue(const CaretHttpResponse& httpResponse, const AString& headerName) const { /* * NULL string */ AString value; CaretAssert(value.isNull()); const QString headerNameLower(headerName.toLower()); for (auto iter : httpResponse.m_headers) { if (iter.first.toLower() == headerNameLower) { value = iter.second; break; } } return value; } /** * Add Scene IDs to scenes in the given scene file that are missing Scene IDs * * @param sceneFile * The scene file. * @param errorMessageOut * Output with error message * @return * True if success, else false. */ bool BalsaDatabaseManager::updateSceneIDs(SceneFile* sceneFile, AString& errorMessageOut) { CaretAssert(sceneFile); std::vector scenesMissingID; const int32_t numScenes = sceneFile->getNumberOfScenes(); for (int32_t i = 0; i < numScenes; i++) { Scene* scene = sceneFile->getSceneAtIndex(i); CaretAssert(scene); if (scene->getBalsaSceneID().trimmed().isEmpty()) { scenesMissingID.push_back(scene); } } const int32_t numberOfIDs = static_cast(scenesMissingID.size()); if (numberOfIDs > 0) { std::vector sceneIDs; if ( ! getSceneIDs(numberOfIDs, sceneIDs, errorMessageOut)) { return false; } CaretAssert(scenesMissingID.size() == sceneIDs.size()); for (int32_t i = 0; i < numberOfIDs; i++) { scenesMissingID[i]->setBalsaSceneID(sceneIDs[i]); } } return true; } /** * Request the given number of scene IDs * * @param numberOfSceneIDs * Number of scene IDs requested * @param sceneIDsOut * Output with requested number of Scene IDs * @param errorMessageOut * Output with error message * @return * True if success, else false. */ bool BalsaDatabaseManager::getSceneIDs(const int32_t numberOfSceneIDs, std::vector& sceneIDsOut, AString& errorMessageOut) { errorMessageOut.clear(); sceneIDsOut.clear(); if (numberOfSceneIDs <= 0) { errorMessageOut = "Zero or fewer Study IDs requested"; return false; } const AString studyIdURL(m_databaseURL + "/scene/newIds/" + AString::number(numberOfSceneIDs)); errorMessageOut.clear(); CaretHttpRequest caretRequest; caretRequest.m_method = CaretHttpManager::POST_ARGUMENTS; caretRequest.m_url = studyIdURL; caretRequest.m_headers.insert(std::make_pair("Content-Type", "application/x-www-form-urlencoded")); caretRequest.m_headers.insert(std::make_pair("Cookie", getJSessionIdCookie())); caretRequest.m_arguments.push_back(std::make_pair("type", "json")); CaretHttpResponse response; CaretHttpManager::httpRequest(caretRequest, response); if (m_debugFlag) { std::cout << "Request Scene IDs response Code: " << response.m_responseCode << std::endl; } if (response.m_responseCode != 200) { errorMessageOut = ("Requesting Scene IDs failed with HTTP code=" + AString::number(response.m_responseCode) + ". This error may be caused by failure to agree to data use terms. "); errorMessageOut.appendWithNewLine(response.m_errorMessage); return false; } response.m_body.push_back('\0'); AString responseContent(&response.m_body[0]); if (m_debugFlag) { std::cout << "Request Scene IDs body:\n" << responseContent << std::endl << std::endl; } AString contentType = getHeaderValue(response, "Content-Type"); if (contentType.isNull()) { errorMessageOut = ("Requesting Scene IDs failed. Content type returned by BALSA is unknown"); return false; } if (contentType.toLower().startsWith("text/html")) { /* * Response from BALSA has Scene IDs separated by '
' * Example: vp5B
Z02A
*/ QStringList sl = responseContent.split("
", QString::SkipEmptyParts, Qt::CaseInsensitive); const int32_t receivedCount = sl.count(); if (receivedCount != numberOfSceneIDs) { errorMessageOut = ("Requested " + AString::number(numberOfSceneIDs) + " but received " + receivedCount + " IDs"); return false; } for (int32_t i = 0; i < receivedCount; i++) { sceneIDsOut.push_back(sl.at(i)); } } else if (contentType.toLower().startsWith("application/json")) { errorMessageOut = ("Requesting Scene IDS failed. Content type returned by BALSA is JSON but support for JSON has not been implemented in Workbench"); return false; } else { errorMessageOut = ("Requesting Scene IDS failed. Content type returned by BALSA should be either text/html or JSON format but is " + contentType); return false; } return true; } /** * Get the study ID from a study Title * * @param databaseURL * URL for database * @param studyTitle * Title of the study * @param studyIDOut * Output with the study ID * @param errorMessageOut * Output with error message * @return * True if success, else false. */ bool BalsaDatabaseManager::requestStudyID(const AString& databaseURL, const AString& studyTitle, AString& studyIDOut, AString& errorMessageOut) { const AString studyIdURL(databaseURL + "/study/save"); errorMessageOut.clear(); CaretHttpRequest caretRequest; caretRequest.m_method = CaretHttpManager::POST_ARGUMENTS; caretRequest.m_url = studyIdURL; caretRequest.m_headers.insert(std::make_pair("Content-Type", "application/x-www-form-urlencoded")); caretRequest.m_headers.insert(std::make_pair("Cookie", getJSessionIdCookie())); caretRequest.m_arguments.push_back(std::make_pair("title", studyTitle)); caretRequest.m_arguments.push_back(std::make_pair("type", "json")); CaretHttpResponse studyResponse; CaretHttpManager::httpRequest(caretRequest, studyResponse); if (m_debugFlag) { std::cout << "Request study ID response Code: " << studyResponse.m_responseCode << std::endl; } if (studyResponse.m_responseCode != 200) { errorMessageOut = ("Requesting study ID failed with HTTP code=" + AString::number(studyResponse.m_responseCode) + ". This error may be caused by failure to agree to data use terms. "); errorMessageOut.appendWithNewLine(studyResponse.m_errorMessage); return false; } AString contentType = getHeaderValue(studyResponse, "Content-Type"); if (contentType.isNull()) { errorMessageOut = ("Requesting study ID failed. Content type returned by BALSA is unknown"); return false; } if ( ! contentType.toLower().startsWith("application/json")) { errorMessageOut = ("Requesting study ID failed. Content type return by BALSA should be JSON format but is " + contentType); return false; } studyResponse.m_body.push_back('\0'); AString responseContent(&studyResponse.m_body[0]); if (m_debugFlag) { std::cout << "Request study ID body:\n" << responseContent << std::endl << std::endl; } QJsonParseError jsonError; QJsonDocument jsonDocument = QJsonDocument::fromJson(responseContent.toUtf8(), &jsonError); if (jsonDocument.isNull()) { errorMessageOut = ("Requesting study ID failed. Failed to parse JSON, error:" + jsonError.errorString() + " Offset=" + AString::number(jsonError.offset)); return false; } QByteArray json = jsonDocument.toJson(); if (m_debugFlag) { std::cout << "Array?: " << jsonDocument.isArray() << std::endl; std::cout << "Empty?: " << jsonDocument.isEmpty() << std::endl; std::cout << "NULL?: " << jsonDocument.isNull() << std::endl; std::cout << "Object?: " << jsonDocument.isObject() << std::endl; std::cout << "JSON length: " << json.size() << std::endl; AString str(json); std::cout << ("Formatted JSON:\n" + str) << std::endl; } if ( ! jsonDocument.isObject()) { errorMessageOut = ("Requesting study ID failed. JSON content is not an object." "JSON is displayed in terminal if logging level is warning or higher."); CaretLogWarning("Study ID JSON is not Object\n" + AString(jsonDocument.toJson())); return false; } BalsaStudyInformation bsi(jsonDocument.object()); if ( ! bsi.getStudyID().isEmpty()) { studyIDOut = bsi.getStudyID(); return true; } return false; } /** * Login to BALSA and request a study ID from a study title. * * @param studyTitle * The study's titlee. * @param studyIdOut * Output containing the study ID. * @param errorMessageOut * Contains description of any error(s). * @return * True if processing was successful, else false. */ bool BalsaDatabaseManager::getStudyIDFromStudyTitle(const AString& studyTitle, AString& studyIdOut, AString& errorMessageOut) { if (studyTitle.isEmpty()) { errorMessageOut = "The study title is empty."; return false; } if ( ! requestStudyID(m_databaseURL, studyTitle, studyIdOut, errorMessageOut)) { return false; } return true; } /** * Get the User's Roles. * * @param userRolesOut * Output with user's roles. * @param errorMessageOut * Contains description of any error(s). * @return * True if processing was successful, else false. */ bool BalsaDatabaseManager::getUserRoles(BalsaUserRoles& userRolesOut, AString& errorMessageOut) { userRolesOut.resetToAllInvalid(); const AString studyIdURL(m_databaseURL + "/user/roles"); errorMessageOut.clear(); CaretHttpRequest caretRequest; caretRequest.m_method = CaretHttpManager::POST_ARGUMENTS; caretRequest.m_url = studyIdURL; caretRequest.m_headers.insert(std::make_pair("Content-Type", "application/x-www-form-urlencoded")); caretRequest.m_headers.insert(std::make_pair("Cookie", getJSessionIdCookie())); caretRequest.m_arguments.push_back(std::make_pair("type", "json")); CaretHttpResponse studyResponse; CaretHttpManager::httpRequest(caretRequest, studyResponse); if (m_debugFlag) { std::cout << "Request roles response Code: " << studyResponse.m_responseCode << std::endl; } if (studyResponse.m_responseCode != 200) { errorMessageOut = ("Requesting roles failed with HTTP code=" + AString::number(studyResponse.m_responseCode) + ". "); errorMessageOut.appendWithNewLine(studyResponse.m_errorMessage); return false; } AString contentType = getHeaderValue(studyResponse, "Content-Type"); if (contentType.isNull()) { errorMessageOut = ("Requesting roles failed. Content type returned by BALSA is unknown"); return false; } if ( ! contentType.toLower().startsWith("application/json")) { errorMessageOut = ("Requesting rolesfailed. Content type return by BALSA should be JSON format but is " + contentType); return false; } studyResponse.m_body.push_back('\0'); AString responseContent(&studyResponse.m_body[0]); if (m_debugFlag) { std::cout << "Request roles body:\n" << responseContent << std::endl << std::endl; } QJsonParseError jsonError; QJsonDocument jsonDocument = QJsonDocument::fromJson(responseContent.toUtf8(), &jsonError); if (jsonDocument.isNull()) { errorMessageOut = ("Requesting roles failed. Failed to parse JSON, error:" + jsonError.errorString() + " Offset=" + AString::number(jsonError.offset)); return false; } QByteArray json = jsonDocument.toJson(); if (m_debugFlag) { std::cout << "Array?: " << jsonDocument.isArray() << std::endl; std::cout << "Empty?: " << jsonDocument.isEmpty() << std::endl; std::cout << "NULL?: " << jsonDocument.isNull() << std::endl; std::cout << "Object?: " << jsonDocument.isObject() << std::endl; std::cout << "JSON length: " << json.size() << std::endl; AString str(json); std::cout << ("Formatted JSON:\n" + str) << std::endl; } if ( ! jsonDocument.isArray()) { errorMessageOut = ("Requesting roles failed. JSON content is not an array." "JSON is displayed in terminal if logging level is warning or higher."); CaretLogWarning("Roles JSON is not Array\n" + AString(jsonDocument.toJson())); return false; } userRolesOut.parseJson(jsonDocument.array()); if (m_debugFlag) { std::cout << "**** Roles: " << userRolesOut.toString() << std::endl; } return userRolesOut.isValid(); } /** * Get the Extract Directory Prefix for the given study. * * @param studyID * The Study ID. * @param extractDirectoryPrefixOut * Output containing the directory prefix from BALSA. * @param errorMessageOut * Contains description of any error(s). * @return * True if processing was successful, else false. */ bool BalsaDatabaseManager::getStudyExtractDirectoryPrefix(const AString& studyID, AString& extractDirectoryPrefixOut, AString& errorMessageOut) { const AString studyIdURL(m_databaseURL + "/study/extractdir/" + studyID.trimmed()); extractDirectoryPrefixOut.clear(); errorMessageOut.clear(); CaretHttpRequest caretRequest; caretRequest.m_method = CaretHttpManager::POST_ARGUMENTS; caretRequest.m_url = studyIdURL; caretRequest.m_headers.insert(std::make_pair("Content-Type", "application/x-www-form-urlencoded")); caretRequest.m_headers.insert(std::make_pair("Cookie", getJSessionIdCookie())); caretRequest.m_arguments.push_back(std::make_pair("type", "utf-8")); CaretHttpResponse studyResponse; CaretHttpManager::httpRequest(caretRequest, studyResponse); if (m_debugFlag) { std::cout << "Request extract directory response Code: " << studyResponse.m_responseCode << std::endl; } if (studyResponse.m_responseCode != 200) { errorMessageOut = ("Requesting extract directory failed with HTTP code=" + AString::number(studyResponse.m_responseCode) + ". "); errorMessageOut.appendWithNewLine(studyResponse.m_errorMessage); return false; } AString contentType = getHeaderValue(studyResponse, "Content-Type"); if (contentType.isNull()) { errorMessageOut = ("Requesting extract directory failed. Content type returned by BALSA is unknown"); return false; } studyResponse.m_body.push_back('\0'); AString responseContent(&studyResponse.m_body[0]); if (m_debugFlag) { std::cout << "Request extract directory body:\n" << responseContent << std::endl << std::endl; } if ( ! contentType.toLower().startsWith("text/html;charset=utf-8")) { errorMessageOut = ("Requesting exxtract directory failed. Content type return by BALSA should be text/html;charset=utf-8 format but is " + contentType); return false; } extractDirectoryPrefixOut = responseContent; /* * "null" is returned by BALSA when the directory is empty */ if (extractDirectoryPrefixOut == "null") { extractDirectoryPrefixOut.clear(); } return true; } /** * Request study information. * * @param studyInformationOut * Output containing information for all of the user's studies. * @param errorMessageOut * Contains description of any error(s). * @return * True if processing was successful, else false. */ bool BalsaDatabaseManager::getAllStudyInformation(std::vector& studyInformationOut, AString& errorMessageOut) { studyInformationOut.clear(); errorMessageOut = ""; const AString studyIdURL(m_databaseURL + "/study/mine"); errorMessageOut.clear(); CaretHttpRequest caretRequest; caretRequest.m_method = CaretHttpManager::POST_ARGUMENTS; caretRequest.m_url = studyIdURL; caretRequest.m_headers.insert(std::make_pair("Content-Type", "application/x-www-form-urlencoded")); caretRequest.m_headers.insert(std::make_pair("Cookie", getJSessionIdCookie())); caretRequest.m_arguments.push_back(std::make_pair("type", "json")); CaretHttpResponse idResponse; CaretHttpManager::httpRequest(caretRequest, idResponse); idResponse.m_body.push_back('\0'); AString responseContent(&idResponse.m_body[0]); CaretLogFine("Get All Study Information Response from " + studyIdURL + ", Response Code=" + AString::number(idResponse.m_responseCode) + "\nContent:\n" + responseContent); if (m_debugFlag) { std::cout << "Request all studies response Code: " << idResponse.m_responseCode << std::endl; } if (idResponse.m_responseCode != 200) { errorMessageOut = ("Requesting all study information failed with HTTP code=" + AString::number(idResponse.m_responseCode) + ". This error may be caused by failure to agree to data use terms. "); errorMessageOut.appendWithNewLine(idResponse.m_errorMessage); return false; } AString contentType = getHeaderValue(idResponse, "Content-Type"); if (contentType.isNull()) { errorMessageOut = ("Requesting all study information failed. Content type returned by BALSA is unknown"); return false; } if ( ! contentType.toLower().startsWith("application/json")) { errorMessageOut = ("Requesting all study information failed. Content type return by BALSA should be JSON format but is " + contentType); return false; } if (m_debugFlag) { std::cout << "Request all studies reply body:\n" << responseContent << std::endl << std::endl; } QJsonParseError jsonError; QJsonDocument jsonDocument = QJsonDocument::fromJson(responseContent.toUtf8(), &jsonError); if (jsonDocument.isNull()) { errorMessageOut = ("Requesting all study information failed. Failed to parse JSON, error:" + jsonError.errorString() + " Offset=" + AString::number(jsonError.offset)); return false; } QByteArray json = jsonDocument.toJson(); if (m_debugFlag) { std::cout << "Array?: " << jsonDocument.isArray() << std::endl; std::cout << "Empty?: " << jsonDocument.isEmpty() << std::endl; std::cout << "NULL?: " << jsonDocument.isNull() << std::endl; std::cout << "Object?: " << jsonDocument.isObject() << std::endl; std::cout << "JSON length: " << json.size() << std::endl; AString str(json); std::cout << ("Formatted JSON:\n" + str) << std::endl; } if ( ! jsonDocument.isArray()) { errorMessageOut = ("Requesting all study information failed. JSON content is not an array." "JSON is displayed in terminal if logging level is warning or higher."); CaretLogWarning("Study Information JSON is not Array\n" + AString(jsonDocument.toJson())); return false; } QJsonArray jsonArray = jsonDocument.array(); for (QJsonArray::iterator iter = jsonArray.begin(); iter != jsonArray.end(); iter++) { QJsonValue jsonValue = *iter; if ( ! jsonValue.isNull()) { if (jsonValue.isObject()) { QJsonObject studyInfo = jsonValue.toObject(); BalsaStudyInformation bsi(studyInfo); if ( ! bsi.isEmpty()) { studyInformationOut.push_back(bsi); } } } } if ( ! studyInformationOut.empty()) { std::sort(studyInformationOut.begin(), studyInformationOut.end()); } return true; } /** * @return Is the given Study ID valid (in BALSA)? * * @param studyID * The study ID. */ bool BalsaDatabaseManager::isStudyIDValid(const AString& studyID) { std::vector studyInformation; AString errorMessage; if (getAllStudyInformation(studyInformation, errorMessage)) { for (const auto info : studyInformation) { if (info.getStudyID() == studyID) { return true; } } } return false; } /** * @return Is the study editable by the user? * * @param studyID * The study ID. * @param errorMessageOut * Description of error if false is returned. */ bool BalsaDatabaseManager::isStudyEditableByUser(const AString& studyID, AString& errorMessageOut) { errorMessageOut.clear(); std::vector studyInformation; AString errorMessage; if (getAllStudyInformation(studyInformation, errorMessage)) { for (const auto& info : studyInformation) { if (info.getStudyID() == studyID) { if (info.isEditable()) { return true; } else { errorMessageOut = ("The study (ID=" + studyID + ") is not editable."); return false; } } } errorMessageOut = ("You are not the owner of the study (ID=" + studyID + ")."); return false; } else { errorMessageOut = errorMessage; } return false; } /** * Login to BALSA, zip the scene and data files, and upload the * ZIP file to BALSA. * * @param sceneFile * Name of scene file. * @param zipFileName * Name for ZIP file. * @param extractToDirectoryName * Directory for extraction of ZIP file. * @param errorMessageOut * Contains description of any error(s). * @return * True if processing was successful, else false. */ bool BalsaDatabaseManager::uploadZippedSceneFile(SceneFile* sceneFile, const AString& zipFileName, const AString& extractToDirectoryName, AString& errorMessageOut) { errorMessageOut.clear(); /* * Check for errors */ if (sceneFile == NULL) { errorMessageOut = "Scene file is invalid."; return false; } const AString sceneFileName = sceneFile->getFileName(); if (sceneFileName.isEmpty()) { errorMessageOut = "Scene file does not have a name."; return false; } if (sceneFile->getNumberOfScenes() <= 0) { errorMessageOut = "Scene file does not contain any scenes."; return false; } if (zipFileName.isEmpty()) { errorMessageOut = "Zip file does not have a name."; return false; } if ( ! zipFileName.endsWith(".zip")) { errorMessageOut = "Zip file name must end with \".zip\""; return false; } if (extractToDirectoryName.isEmpty()) { errorMessageOut = "The extract directory name is empty."; return false; } enum ProgressEnum { PROGRESS_NONE, PROGRESS_LOGIN, PROGRESS_ZIPPING, PROGRESS_UPLOAD, PROGRESS_PROCESS_UPLOAD, PROGRESS_DONE }; EventProgressUpdate progressUpdate(PROGRESS_NONE, PROGRESS_DONE, PROGRESS_LOGIN, "Logging in..."); EventManager::get()->sendEvent(progressUpdate.getPointer()); progressUpdate.setProgress(PROGRESS_ZIPPING, "Zipping Scene and Data Files"); EventManager::get()->sendEvent(progressUpdate.getPointer()); /* * Zip the scene file and its data files */ if ( ! zipSceneAndDataFiles(sceneFile, extractToDirectoryName, zipFileName, errorMessageOut)) { return false; } if (m_debugFlag) std::cout << "Zip file " << zipFileName << " has been created " << std::endl; progressUpdate.setProgress(PROGRESS_UPLOAD, "Uploading zip file"); EventManager::get()->sendEvent(progressUpdate.getPointer()); /* * Upload the ZIP file */ AString uploadResultText; const AString uploadURL(m_databaseURL + "/study/handleUpload/" + sceneFile->getBalsaStudyID()); const bool uploadSuccessFlag = uploadFile(uploadURL, zipFileName, "application/zip", uploadResultText, errorMessageOut); if (m_debugFlag) std::cout << "Output of uploading zip file: " << uploadResultText << std::endl; if ( ! uploadSuccessFlag) { return false; } const bool doProcessUploadFlag = true; if (doProcessUploadFlag) { /* * Process the uploaded file */ progressUpdate.setProgress(PROGRESS_PROCESS_UPLOAD, "Processing uploaded zip file (this step may take a long time)"); EventManager::get()->sendEvent(progressUpdate.getPointer()); const AString processUploadURL(m_databaseURL + "/study/processUpload/" + sceneFile->getBalsaStudyID()); const bool processUploadSuccessFlag = processUploadedFile(sceneFile, processUploadURL, "application/x-www-form-urlencoded", false, // do not look for Scene IDs in response content errorMessageOut); if (m_debugFlag) std::cout << "Result of processing the uploaded ZIP file" << AString::fromBool(processUploadSuccessFlag) << std::endl; if ( ! processUploadSuccessFlag) { return false; } } else { CaretLogSevere("PROCESSING OF FILE UPLOADED TO BALSA IS DISABLED"); } if (QFile::exists(zipFileName)) { if ( ! QFile::remove(zipFileName)) { CaretLogWarning("Unable to delete Zip file after uploading: " + zipFileName); } } progressUpdate.setProgress(PROGRESS_DONE, "Finished."); EventManager::get()->sendEvent(progressUpdate.getPointer()); return true; } /** * Constructor that parses JSON containing scene file name and identifiers. * * Example: ["FileName.scene",[[1,"55XX"],[0,"n51z"]]] * * @param debugFlag * Debugging flag * @param jsonValue * The JSON value containing the array. */ BalsaDatabaseManager::SceneFileIdentifiers::SceneFileIdentifiers(const bool debugFlag, const QJsonValue& jsonValue) : m_debugFlag(debugFlag) { if ( ! jsonValue.isArray()) { m_errorMessage = ("Scene File Name/Identifier is not JSON array \"" + JsonHelper::jsonValueToString(jsonValue) + "\""); return; } if (m_debugFlag) { std::cout << "Scene IDs Content: " << JsonHelper::jsonValueToString(jsonValue) << std::endl; } const QJsonArray jsonArray = jsonValue.toArray(); if (jsonArray.count() != 2) { m_errorMessage = ("Scene File Name/Identifier array should have two elements \"" + JsonHelper::jsonValueToString(jsonValue) + "\""); return; } const QJsonValue sceneFileNameJsonValue = jsonArray.at(0); if ( ! sceneFileNameJsonValue.isString()) { m_errorMessage = ("Scene File Name is not a string \"" + JsonHelper::jsonValueToString(sceneFileNameJsonValue) + "\""); return; } m_sceneFileName = sceneFileNameJsonValue.toString(); const QJsonValue sceneIDsJsonValue = jsonArray.at(1); if ( ! sceneIDsJsonValue.isArray()) { m_errorMessage = ("Scene IDs is not an array \"" + JsonHelper::jsonValueToString(sceneFileNameJsonValue) + "\""); return; } const QJsonArray sceneIDsArray = sceneIDsJsonValue.toArray(); const int numSceneIDs = sceneIDsArray.count(); for (int32_t i = 0; i < numSceneIDs; i++) { const QJsonValue sceneIDJsonElementValue = sceneIDsArray.at(i); if (m_debugFlag) { std::cout << "Scene Index/ID: " << i << " " << JsonHelper::jsonValueToString(sceneIDJsonElementValue) << std::endl; } if ( ! sceneIDJsonElementValue.isArray()) { m_errorMessage = ("Scene Index/ID is not an array \"" + JsonHelper::jsonValueToString(sceneIDJsonElementValue) + "\""); return; } const QJsonArray sceneIDJsonArray = sceneIDJsonElementValue.toArray(); if (sceneIDJsonArray.count() != 2) { m_errorMessage = ("Scene Index/ID array should have two elements \"" + JsonHelper::jsonValueToString(sceneIDJsonArray) + "\""); return; } const QJsonValue sceneIndexValue = sceneIDJsonArray.at(0); if ( ! sceneIndexValue.isDouble()) { m_errorMessage = ("Scene Index (first element) is not a number \"" + JsonHelper::jsonValueToString(sceneIndexValue) + "\""); return; } const QJsonValue sceneIDValue = sceneIDJsonArray.at(1); if ( ! sceneIDValue.isString()) { m_errorMessage = ("Scene ID (second element) is not a string \"" + JsonHelper::jsonValueToString(sceneIDJsonArray) + "\""); return; } const int32_t invalidIndex = -1; const int32_t sceneIndex = sceneIndexValue.toInt(invalidIndex); if (sceneIndex == invalidIndex) { m_errorMessage = ("Scene Index (first element) is not an integer \"" + JsonHelper::jsonValueToString(sceneIndexValue) + "\""); return; } const AString sceneID = sceneIDValue.toString(); m_sceneIndexAndIDsMap.insert(std::make_pair(sceneIndex, sceneID)); } } /** * @return True if parsing was valid. */ bool BalsaDatabaseManager::SceneFileIdentifiers::isValid() const { return (m_errorMessage.isEmpty()); } /** * @return Error message describing parsing problem. */ AString BalsaDatabaseManager::SceneFileIdentifiers::getErrorMessage() const { return m_errorMessage; } connectome-workbench-1.4.2/src/GuiQt/BalsaDatabaseManager.h000066400000000000000000000145521360521144700235750ustar00rootroot00000000000000#ifndef __BALSA_DATABASE_MANAGER_H__ #define __BALSA_DATABASE_MANAGER_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "BalsaStudyInformation.h" #include "CaretObject.h" #include "EventListenerInterface.h" class QJsonValue; namespace caret { class BalsaUserRoles; struct CaretHttpResponse; class SceneFile; class BalsaDatabaseManager : public CaretObject, public EventListenerInterface { public: BalsaDatabaseManager(); virtual ~BalsaDatabaseManager(); bool login(const AString& databaseURL, const AString& username, const AString& password, AString& errorMessageOut); void logout(); bool isStudyIDValid(const AString& studyID); bool getAllStudyInformation(std::vector& studyInformationOut, AString& errorMessageOut); bool getUserRoles(BalsaUserRoles& userRolesOut, AString& errorMessageOut); bool getStudyExtractDirectoryPrefix(const AString& studyID, AString& extractDirectoryPrefixOut, AString& errorMessageOut); bool getStudyIDFromStudyTitle(const AString& studyTitle, AString& studyIdOut, AString& errorMessageOut); bool getSceneIDs(const int32_t numberOfSceneIDs, std::vector& sceneIDsOut, AString& errorMessageOut); bool updateSceneIDs(SceneFile* sceneFile, AString& errorMessageOut); bool uploadZippedSceneFile(SceneFile* sceneFile, const AString& zipFileName, const AString& extractToDirectoryName, AString& errorMessageOut); static bool zipSceneAndDataFiles(const SceneFile* sceneFile, const AString& extractDirectory, const AString& zipFileName, AString& errorMessageOut); bool isStudyEditableByUser(const AString& studyID, AString& errorMessageOut); // ADD_NEW_METHODS_HERE virtual AString toString() const; virtual void receiveEvent(Event* event); private: class SceneFileIdentifiers { public: SceneFileIdentifiers(const bool debugFlag, const QJsonValue& jsonValue); bool isValid() const; AString getErrorMessage() const; const bool m_debugFlag; AString m_errorMessage; AString m_sceneFileName; std::map m_sceneIndexAndIDsMap; }; BalsaDatabaseManager(const BalsaDatabaseManager&); BalsaDatabaseManager& operator=(const BalsaDatabaseManager&); AString getJSessionIdCookie() const; bool uploadFile(const AString& uploadURL, const AString& fileName, const AString& httpContentTypeName, AString& responseContentOut, AString& errorMessageOut); bool processUploadedFile(SceneFile* sceneFile, const AString& processUploadURL, const AString& httpContentTypeName, const bool updateSceneIDsFromResponseFlag, AString& errorMessageOut); bool requestStudyID(const AString& databaseURL, const AString& studyTitle, AString& studyIDOut, AString& errorMessageOut); bool uploadFileWithCaretHttpManager(const AString& uploadURL, const AString& fileName, const AString& httpContentTypeName, AString& responseContentOut, AString& errorMessageOut); bool verifyUploadFileResponse(const std::map& responseHeaders, const AString& responseContent, const int32_t responseHttpCode, const AString& responseErrorMessage, AString& errorMessageOut) const; AString getHeaderValue(const CaretHttpResponse& httpResponse, const AString& headerName) const; bool updateSceneIdsFromProcessUploadResponse(SceneFile* sceneFile, const AString& jsonContent, AString& errorMessageOut); AString m_databaseURL; AString m_username; AString m_password; AString m_jSessionIdCookie; bool m_debugFlag; // ADD_NEW_MEMBERS_HERE }; #ifdef __BALSA_DATABASE_MANAGER_DECLARE__ // #endif // __BALSA_DATABASE_MANAGER_DECLARE__ } // namespace #endif //__BALSA_DATABASE_MANAGER_H__ connectome-workbench-1.4.2/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.cxx000066400000000000000000001414671360521144700267260ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BALSA_DATABASE_UPLOAD_SCENE_FILE_DIALOG_DECLARE__ #include "BalsaDatabaseUploadSceneFileDialog.h" #undef __BALSA_DATABASE_UPLOAD_SCENE_FILE_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "BalsaDatabaseManager.h" #include "BalsaStudySelectionDialog.h" #include "BalsaUserRoles.h" #include "Brain.h" #include "CaretAssert.h" #include "CaretFileDialog.h" #include "CaretLogger.h" #include "CaretPointer.h" #include "CaretPreferences.h" #include "CursorDisplayScoped.h" #include "DataFileException.h" #include "FileInformation.h" #include "GuiManager.h" #include "ProgressReportingDialog.h" #include "SceneBasePathWidget.h" #include "SceneFile.h" #include "SessionManager.h" #include "SystemUtilities.h" #include "WuQDataEntryDialog.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" #include "WuQWidgetDisabler.h" using namespace caret; /** * \class caret::BalsaDatabaseUploadSceneFileDialog * \brief Dialog for uploading a scene file to the BALSA Database. * \ingroup GuiQt */ /** * Constructor. * * @param sceneFile * Scene file that will be uploaded. * @param parent * Parent of this dialog. */ BalsaDatabaseUploadSceneFileDialog::BalsaDatabaseUploadSceneFileDialog(SceneFile* sceneFile, QWidget* parent) : WuQDialogModal("Upload Scene File to BALSA", parent), m_sceneFile(sceneFile) { CaretAssert(m_sceneFile); if (s_username.isEmpty()) { s_username = SessionManager::get()->getCaretPreferences()->getBalsaUserName(); } m_userRoles.reset(new BalsaUserRoles); QWidget* loginWidget = createLoginWidget(); m_uploadWidget = createTabWidget(); QWidget* dialogWidget = new QWidget(); QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); dialogLayout->addWidget(loginWidget); dialogLayout->addWidget(m_uploadWidget); setCentralWidget(dialogWidget, WuQDialogModal::SCROLL_AREA_NEVER); loginInformationChanged(); setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); setOkButtonText("Upload"); setCancelButtonText("Close"); m_basePathWidget->updateWithSceneFile(m_sceneFile); updateUserRolesLabel(); disableAutoDefaultForAllPushButtons(); m_loginPushButton->setAutoDefault(true); m_loginPushButton->setDefault(true); showPasswordActionTriggered(m_showPasswordAction->isChecked()); } /** * Destructor. */ BalsaDatabaseUploadSceneFileDialog::~BalsaDatabaseUploadSceneFileDialog() { } /** * Called when the Cancel button (we have changed text * to Close) is clicked. */ void BalsaDatabaseUploadSceneFileDialog::cancelButtonClicked() { s_username = m_usernameLineEdit->text(); s_password = m_passwordLineEdit->text(); /* * Will logout of database and disable part of dialog */ loginInformationChanged(); WuQDialogModal::cancelButtonClicked(); } /** * @return The login widget */ QWidget* BalsaDatabaseUploadSceneFileDialog::createLoginWidget() { /* * Create the BALSA database manager */ m_balsaDatabaseManager = std::unique_ptr(new BalsaDatabaseManager()); const int minimumLineEditWidth = 250; /* * Username */ m_usernameLabel = new QLabel(""); m_usernameLineEdit = new QLineEdit(); m_usernameLineEdit->setMinimumWidth(minimumLineEditWidth); m_usernameLineEdit->setText(s_username); m_usernameLineEdit->setValidator(createValidator(LabelName::LABEL_USERNAME)); QObject::connect(m_usernameLineEdit, &QLineEdit::textEdited, this, [=] { this->loginInformationChanged(); }); QObject::connect(m_usernameLineEdit, &QLineEdit::returnPressed, this, &BalsaDatabaseUploadSceneFileDialog::returnPressedUsernameOrPassword); /* * Password */ m_passwordLabel = new QLabel(""); m_passwordLineEdit = new QLineEdit(); m_passwordLineEdit->setMinimumWidth(minimumLineEditWidth); m_passwordLineEdit->setEchoMode(QLineEdit::Password); if (s_password.isEmpty()) { const bool allowEnvPasswordFlag(false); if (allowEnvPasswordFlag) { QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); m_passwordLineEdit->setText(environment.value("WORKBENCH_BALSA_PD")); } } else { m_passwordLineEdit->setText(s_password); } m_passwordLineEdit->setValidator(createValidator(LabelName::LABEL_PASSWORD)); QObject::connect(m_passwordLineEdit, &QLineEdit::textEdited, this, [=] { this->loginInformationChanged(); }); QObject::connect(m_passwordLineEdit, &QLineEdit::returnPressed, this, &BalsaDatabaseUploadSceneFileDialog::returnPressedUsernameOrPassword); /* * Forgot username label/link */ QLabel* forgotUsernameLabel = new QLabel("" "Forgot Username" ""); QObject::connect(forgotUsernameLabel, SIGNAL(linkActivated(const QString&)), this, SLOT(labelHtmlLinkClicked(const QString&))); /* * Show password tool button */ m_showPasswordAction = new QAction("Show", this); m_showPasswordAction->setCheckable(true); m_showPasswordAction->setChecked(false); QObject::connect(m_showPasswordAction, &QAction::triggered, this, &BalsaDatabaseUploadSceneFileDialog::showPasswordActionTriggered); QToolButton* showPasswordToolButton = new QToolButton(); showPasswordToolButton->setDefaultAction(m_showPasswordAction); /* * Forgot password label/link */ QLabel* forgotPasswordLabel = new QLabel("" "Forgot Password" ""); QObject::connect(forgotPasswordLabel, SIGNAL(linkActivated(const QString&)), this, SLOT(labelHtmlLinkClicked(const QString&))); /* * Register label/link */ QLabel* registerLabel = new QLabel("" "Register" ""); QObject::connect(registerLabel, SIGNAL(linkActivated(const QString&)), this, SLOT(labelHtmlLinkClicked(const QString&))); /* * Login push button */ m_loginPushButton = new QPushButton("Login"); QObject::connect(m_loginPushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::loginButtonClicked); /* * Label for User Roles */ m_userRolesLabel = new QLabel(" "); int columnCounter = 0; const int COLUMN_LABEL = columnCounter++; const int COLUMN_DATA_WIDGET_ONE = columnCounter++; const int COLUMN_DATA_WIDGET_TWO = columnCounter++; const int COLUMN_BUTTON_ONE = columnCounter++; const int COLUMN_BUTTON_TWO = columnCounter++; QGroupBox* groupBox = new QGroupBox("BALSA Login"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->setSpacing(5); gridLayout->setColumnStretch(COLUMN_LABEL, 0); gridLayout->setColumnStretch(COLUMN_DATA_WIDGET_ONE, 0); gridLayout->setColumnStretch(COLUMN_DATA_WIDGET_TWO, 100); gridLayout->setColumnStretch(COLUMN_BUTTON_ONE, 0); int row = 0; gridLayout->addWidget(m_usernameLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_usernameLineEdit, row, COLUMN_DATA_WIDGET_ONE, 1, 2); gridLayout->addWidget(registerLabel, row, COLUMN_BUTTON_ONE); gridLayout->addWidget(forgotUsernameLabel, row, COLUMN_BUTTON_TWO); row++; gridLayout->addWidget(m_passwordLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_passwordLineEdit, row, COLUMN_DATA_WIDGET_ONE, 1, 2); gridLayout->addWidget(showPasswordToolButton, row, COLUMN_BUTTON_ONE); gridLayout->addWidget(forgotPasswordLabel, row, COLUMN_BUTTON_TWO); row++; gridLayout->setRowMinimumHeight(row, 10); // empty row row++; gridLayout->addWidget(m_loginPushButton, row, COLUMN_DATA_WIDGET_ONE); gridLayout->addWidget(m_userRolesLabel, row, COLUMN_DATA_WIDGET_TWO, 1, Qt::AlignLeft); return groupBox; } /** * Called when login information (database, username, password) is changed */ void BalsaDatabaseUploadSceneFileDialog::loginInformationChanged() { m_balsaDatabaseManager->logout(); setOkButtonEnabled(false); m_selectStudyTitlePushButton->setEnabled(false); m_userRoles->resetToAllInvalid(); updateAllLabels(); } /** * Called when show password action is triggered. * * @param checked * New status. */ void BalsaDatabaseUploadSceneFileDialog::showPasswordActionTriggered(bool checked) { if (checked) { m_passwordLineEdit->setEchoMode(QLineEdit::Normal); } else { m_passwordLineEdit->setEchoMode(QLineEdit::Password); } } /** * @return The upload widget */ QWidget* BalsaDatabaseUploadSceneFileDialog::createTabWidget() { QTabWidget* tabWidget = new QTabWidget(); tabWidget->addTab(createUploadTab(), "Upload"); tabWidget->addTab(createAdvancedTab(), "Advanced"); return tabWidget; } /** * @return New instance of the upload tab. */ QWidget* BalsaDatabaseUploadSceneFileDialog::createUploadTab() { /* * Extract to directory */ const AString defaultExtractDirectoryName = m_sceneFile->getDefaultExtractToDirectoryName(); m_extractDirectoryNameLabel = new QLabel(""); m_extractDirectoryNameLineEdit = new QLineEdit(); m_extractDirectoryNameLineEdit->setText("ExtDir"); m_extractDirectoryNameLineEdit->setValidator(createValidator(LabelName::LABEL_EXTRACT_DIRECTORY)); m_extractDirectoryNameLineEdit->setToolTip("Directory created when data files are extracted from ZIP archive"); m_extractDirectoryNameLineEdit->setText(defaultExtractDirectoryName); QObject::connect(m_extractDirectoryNameLineEdit, &QLineEdit::textEdited, this, [=] { this->validateUploadData(); }); /* * Scene BALSA Study ID */ m_balsaStudyIDLabel = new QLabel(""); m_balsaStudyIDLineEdit = new QLineEdit(); m_balsaStudyIDLineEdit->setReadOnly(true); m_balsaStudyIDLineEdit->setToolTip("The Study ID is available from the BALSA Database; click the Get button to get a Study ID"); m_balsaStudyIDLineEdit->setValidator(createValidator(LabelName::LABEL_STUDY_ID)); m_balsaStudyIDLineEdit->setReadOnly(true); QObject::connect(m_balsaStudyIDLineEdit, &QLineEdit::textEdited, this, [=] { this->validateUploadData(); }); /* * Scene BALSA Study Title */ m_balsaStudyTitleLabel = new QLabel(""); m_balsaStudyTitleLineEdit = new QLineEdit(); m_balsaStudyTitleLineEdit->setToolTip("Title for the study"); m_balsaStudyTitleLineEdit->setValidator(createValidator(LabelName::LABEL_STUDY_TITLE)); m_balsaStudyTitleLineEdit->setReadOnly(true); QObject::connect(m_balsaStudyTitleLineEdit, &QLineEdit::textEdited, this, [=] { this->validateUploadData(); }); /** * Select Study Push Button */ m_selectStudyTitlePushButton = new QPushButton("Create/Select/Rename..."); m_selectStudyTitlePushButton->setToolTip("Add new study, choose a study, or edit a study's title in BALSA Database"); QObject::connect(m_selectStudyTitlePushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::selectStudyTitleButtonClicked); /* * Test button */ QPushButton* testPushButton = new QPushButton("Test..."); testPushButton->setToolTip("Test some functionality"); QObject::connect(testPushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::testButtonClicked); testPushButton->setVisible(false); /* * Auto-save checkbox */ m_autoSaveSceneFileCheckBox = new QCheckBox("Auto-Save Scene File"); m_autoSaveSceneFileCheckBox->setChecked(true); QObject::connect(m_autoSaveSceneFileCheckBox, &QCheckBox::clicked, this, &BalsaDatabaseUploadSceneFileDialog::autoSaveCheckBoxClicked); int columnCounter = 0; const int COLUMN_LABEL = columnCounter++; const int COLUMN_DATA_WIDGET = columnCounter++; const int COLUMN_BUTTON_ONE = columnCounter++; const int COLUMN_BUTTON_TWO = columnCounter++; QGridLayout* gridLayout = new QGridLayout(); gridLayout->setSpacing(5); gridLayout->setColumnMinimumWidth(COLUMN_DATA_WIDGET, 300); gridLayout->setColumnStretch(COLUMN_LABEL, 0); gridLayout->setColumnStretch(COLUMN_DATA_WIDGET, 100); gridLayout->setColumnStretch(COLUMN_BUTTON_ONE, 0); gridLayout->setColumnStretch(COLUMN_BUTTON_TWO, 0); int row = 0; gridLayout->addWidget(m_balsaStudyTitleLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_balsaStudyTitleLineEdit, row, COLUMN_DATA_WIDGET); gridLayout->addWidget(m_selectStudyTitlePushButton, row, COLUMN_BUTTON_ONE, 1, 2); row++; gridLayout->addWidget(m_balsaStudyIDLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_balsaStudyIDLineEdit, row, COLUMN_DATA_WIDGET); gridLayout->addWidget(testPushButton, row, COLUMN_BUTTON_ONE, 1, 2); row++; gridLayout->addWidget(m_extractDirectoryNameLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_extractDirectoryNameLineEdit, row, COLUMN_DATA_WIDGET); row++; gridLayout->addWidget(m_autoSaveSceneFileCheckBox, row, COLUMN_DATA_WIDGET, 1, 3, Qt::AlignLeft); row++; gridLayout->setRowMinimumHeight(row, 15); // empty row row++; m_balsaStudyIDLineEdit->setText(m_sceneFile->getBalsaStudyID()); m_balsaStudyTitleLineEdit->setText(m_sceneFile->getBalsaStudyTitle()); m_extractDirectoryNameLineEdit->setText(m_sceneFile->getBalsaExtractToDirectoryName()); if (m_extractDirectoryNameLineEdit->text().trimmed().isEmpty()) { m_extractDirectoryNameLineEdit->setText(m_sceneFile->getDefaultExtractToDirectoryName()); } QWidget* widget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(widget); layout->addLayout(gridLayout); layout->addStretch(); return widget; } /** * @return A new BALSA Database selection widget */ QWidget* BalsaDatabaseUploadSceneFileDialog::createBalsaDatabaseSelectionWidget() { bool isWustlDomainFlag = false; /* DOES NOT WORK ON MACOS 10.14, See note in: SystemUtilities::getLocalHostName() QString hostName = SystemUtilities::getLocalHostName(); bool isWustlDomainFlag = hostName.endsWith(".wustl.edu"); */ #ifndef NDEBUG isWustlDomainFlag = true; #endif /* * Database selection */ m_databaseLabel = new QLabel(""); m_databaseComboBox = new QComboBox(); m_databaseComboBox->setEditable(true); m_databaseComboBox->addItem("https://balsa.wustl.edu"); if (isWustlDomainFlag) { m_databaseComboBox->addItem("http://johnsdev.wustl.edu:8080"); m_databaseComboBox->addItem("https://johnsdev.wustl.edu:8080"); } QObject::connect(m_databaseComboBox, static_cast(&QComboBox::activated), this, [=] { this->loginInformationChanged(); }); QObject::connect(m_databaseComboBox, &QComboBox::editTextChanged, this, [=] { this->loginInformationChanged(); }); QPushButton* whatsThisPushButton = new QPushButton("What's this?"); whatsThisPushButton->setSizePolicy(QSizePolicy::Fixed, whatsThisPushButton->sizePolicy().verticalPolicy()); QObject::connect(whatsThisPushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::whatsThisDatabase); int columnCounter = 0; const int COLUMN_LABEL = columnCounter++; const int COLUMN_WIDGET = columnCounter++; QGroupBox* groupBox = new QGroupBox("BALSA Database"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->setSpacing(5); gridLayout->setColumnStretch(COLUMN_LABEL, 0); gridLayout->setColumnStretch(COLUMN_WIDGET, 100); int row = 0; gridLayout->addWidget(whatsThisPushButton, row, COLUMN_LABEL, 1, 2, Qt::AlignLeft); row++; gridLayout->addWidget(m_databaseLabel, row, COLUMN_LABEL, Qt::AlignRight); gridLayout->addWidget(m_databaseComboBox, row, COLUMN_WIDGET); row++; return groupBox; } /** * @return A new ZIP file directory widget */ QWidget* BalsaDatabaseUploadSceneFileDialog::creatZipFileDirectoryWidget() { m_zipFileTemporaryDirectoryRadioButton = new QRadioButton("System Temporary"); m_zipFileCustomDirectoryRadioButton = new QRadioButton("Custom: "); QButtonGroup* buttGroup = new QButtonGroup(this); buttGroup->addButton(m_zipFileTemporaryDirectoryRadioButton); buttGroup->addButton(m_zipFileCustomDirectoryRadioButton); m_zipFileTemporaryDirectoryRadioButton->setChecked(true); // do before signal QObject::connect(buttGroup, static_cast(&QButtonGroup::buttonClicked), [=](int id){ this->zipFileDirectoryRadioButtonClicked(id); }); m_zipFileAutomaticDirectoryLineEdit = new QLineEdit(); m_zipFileAutomaticDirectoryLineEdit->setReadOnly(true); m_zipFileAutomaticDirectoryLineEdit->setText(SystemUtilities::getTempDirectory()); m_zipFileCustomDirectoryLineEdit = new QLineEdit(); QPushButton* copyAutomaticDirectoryPushButton = new QPushButton("Copy"); QObject::connect(copyAutomaticDirectoryPushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::copyAutomaticDirectoryPushButtonClicked); copyAutomaticDirectoryPushButton->setToolTip("Copy system temporary directory to clipboard"); QPushButton* browseCustomDirectoryPushButton = new QPushButton("Browse..."); QObject::connect(browseCustomDirectoryPushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::browseZipFileCustomDirectoryPushButtonClicked); QPushButton* whatsThisPushButton = new QPushButton("What's this?"); whatsThisPushButton->setSizePolicy(QSizePolicy::Fixed, whatsThisPushButton->sizePolicy().verticalPolicy()); QObject::connect(whatsThisPushButton, &QPushButton::clicked, this, &BalsaDatabaseUploadSceneFileDialog::whatsThisZipFileDirectory); QGroupBox* zipDirectoryGroupBox = new QGroupBox("Zip File Directory"); QGridLayout* gridLayout = new QGridLayout(zipDirectoryGroupBox); gridLayout->setSpacing(2); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); gridLayout->setColumnStretch(2, 0); int row = 0; gridLayout->addWidget(whatsThisPushButton, row, 0, 1, 3, Qt::AlignLeft); row++; gridLayout->addWidget(m_zipFileTemporaryDirectoryRadioButton, row, 0); gridLayout->addWidget(m_zipFileAutomaticDirectoryLineEdit, row, 1); gridLayout->addWidget(copyAutomaticDirectoryPushButton, row, 2); row++; gridLayout->addWidget(m_zipFileCustomDirectoryRadioButton, row, 0); gridLayout->addWidget(m_zipFileCustomDirectoryLineEdit, row, 1); gridLayout->addWidget(browseCustomDirectoryPushButton, row, 2); row++; return zipDirectoryGroupBox; } /** * @return New instance of the advanced tab */ QWidget* BalsaDatabaseUploadSceneFileDialog::createAdvancedTab() { QWidget* databaseSelectionWidget = createBalsaDatabaseSelectionWidget(); QWidget* zipDirectoryWidget = creatZipFileDirectoryWidget(); m_basePathWidget = new SceneBasePathWidget(); QLabel* infoLabel = new QLabel("NOTE: In most instances, the default selections should be used."); infoLabel->setWordWrap(true); QWidget* widget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(infoLabel); layout->addWidget(m_basePathWidget); layout->addWidget(zipDirectoryWidget); layout->addWidget(databaseSelectionWidget); layout->addStretch(); return widget; } /** * @return Name of selected database. */ AString BalsaDatabaseUploadSceneFileDialog::getDataBaseURL() const { return m_databaseComboBox->currentText().trimmed(); } /** * Gets called when the user clicks a link in the forgot username * or password label. * * @param linkPath * Path relative to database. */ void BalsaDatabaseUploadSceneFileDialog::labelHtmlLinkClicked(const QString& linkPath) { if (linkPath.isEmpty() == false) { const QString dbURL = getDataBaseURL(); const AString linkURL = (getDataBaseURL() + (linkPath.startsWith("/") ? "" : "/") + linkPath); QDesktopServices::openUrl(QUrl(linkURL)); } } /** * Called when a Zip File Directory radio button is clicked */ void BalsaDatabaseUploadSceneFileDialog::zipFileDirectoryRadioButtonClicked(int) { validateUploadData(); } /** * Get the ZIP file name. * * @param errorMessageOut * Output if failure to create zip file name. * * @return * Name of ZIP file. If empty, check errorMessageOut for explanation. */ AString BalsaDatabaseUploadSceneFileDialog::getZipFileNameWithPath(AString& errorMessageOut) const { errorMessageOut = ""; AString directoryName; if (m_zipFileTemporaryDirectoryRadioButton->isChecked()) { directoryName = SystemUtilities::getTempDirectory(); if ( ! FileInformation(directoryName).exists()) { errorMessageOut = "Default temporary directory is invalid. Please choose a Custom Zip File Directory on Advanced tab"; return ""; } } else if (m_zipFileCustomDirectoryRadioButton->isChecked()) { directoryName = m_zipFileCustomDirectoryLineEdit->text().trimmed(); if (directoryName.isEmpty()) { errorMessageOut = "Zip File Custom directory is selected but is empty (see Advanced tab)."; return ""; } if ( ! FileInformation(directoryName).exists()) { errorMessageOut = "Zip File Custom directory is invalid. Please choose a Custom Zip File Directory on Advanced tab"; return ""; } } else { CaretAssert(0); } FileInformation zipFileName(directoryName, "BalsaUpload_" + QString::number(QDateTime::currentMSecsSinceEpoch())+ ".zip"); return zipFileName.getAbsoluteFilePath(); } /** * Gets called when the login button is clicked. */ void BalsaDatabaseUploadSceneFileDialog::loginButtonClicked() { const AString username = m_usernameLineEdit->text().trimmed(); if (username.isEmpty()) { WuQMessageBox::errorOk(this, "Username is empty"); return; } const AString password = m_passwordLineEdit->text().trimmed(); if (password.isEmpty()) { WuQMessageBox::errorOk(this, "Password is empty"); return; } setOkButtonEnabled(false); m_selectStudyTitlePushButton->setEnabled(false); m_userRoles->resetToAllInvalid(); updateUserRolesLabel(); CursorDisplayScoped cursor; cursor.showWaitCursor(); /* * If operation takes a while */ WuQWidgetDisabler blocker(m_loginPushButton); AString errorMessage; if ( ! m_balsaDatabaseManager->login(getDataBaseURL(), username, password, errorMessage)) { cursor.restoreCursor(); WuQMessageBox::errorOk(this, errorMessage); return; } if (m_balsaDatabaseManager->getUserRoles(*m_userRoles, errorMessage)) { if ( ! m_userRoles->isSubmitter()) { cursor.restoreCursor(); const AString msg("Login to BALSA was successful. However, your have not agreed " "to the BALSA Submission Terms and Conditions that are required " "to upload data to BALSA. You will need to login to BALSA " "using your web browser and complete this agreement."); const bool okPressedFlag = WuQMessageBox::warningAcceptReject(this, msg, "OK", "OK, Go to BALSA in Web Browser"); if ( ! okPressedFlag) { labelHtmlLinkClicked("about/submission"); } return; } } else { m_userRoles->resetToAllInvalid(); cursor.restoreCursor(); const AString msg("Unable to verify that you have agreed to the BALSA " "Submission Terms and Conditions. If you have not " "agreed to terms and conditions, uploading will fail.\n\n" + errorMessage); WuQMessageBox::warningOk(this, msg); } updateUserRolesLabel(); setOkButtonEnabled(true); m_selectStudyTitlePushButton->setEnabled(true); SessionManager::get()->getCaretPreferences()->setBalsaUserName(username); } /** * Check the BALSA database to see if the "Extraction Directory Prefix" in the database * is different than the value in the dialog. If so, warn user. * * @return * True if uploading should continue, otherwise false. */ bool BalsaDatabaseUploadSceneFileDialog::checkBalsaExtractionDirectoryPrefix() { bool validFlag = true; const AString studyID = m_balsaStudyIDLineEdit->text().trimmed(); if ( ! studyID.isEmpty()) { if (m_balsaDatabaseManager->isStudyIDValid(studyID)) { AString balsaDirectoryName; AString errorMessage; if (m_balsaDatabaseManager->getStudyExtractDirectoryPrefix(studyID, balsaDirectoryName, errorMessage)) { if ( ! balsaDirectoryName.isEmpty()) { const AString currentDirName = m_extractDirectoryNameLineEdit->text().trimmed(); if (balsaDirectoryName != currentDirName) { AString msg("" "The Extraction Directory Prefix in this dialog differs from the " "Extraction Directory Prefix for this study in the BALSA Database." "

" "This may be caused by:" "

    " "
  • A scene file containing a different base directory in the " "same study was uploaded to BALSA" "
  • The Extraction Directory Prefix has been edited in this scene file" "
  • The Extraction Directory Prefix has been edited through the " "BALSA Database web interface (Edit Study: Study Details)" "
" "

" "For the Extraction Directory Prefix:" ""); WuQDataEntryDialog ded("Warning, Extraction Directory Prefix", this); ded.setTextAtTop(msg, true); QRadioButton* balsaDirRadioButton = ded.addRadioButton("Change to \"" + balsaDirectoryName + "\""); QRadioButton* dialogDirRadioButton = ded.addRadioButton("No change, use \"" + currentDirName + "\" from this dialog"); balsaDirRadioButton->setChecked(true); ded.setOkButtonText("Continue"); if (ded.exec() == WuQDataEntryDialog::Accepted) { AString dirName; if (balsaDirRadioButton->isChecked()){ dirName = balsaDirectoryName; } else if (dialogDirRadioButton->isChecked()) { dirName = currentDirName; } else { CaretAssert(0); } m_extractDirectoryNameLineEdit->setText(dirName); m_sceneFile->setBalsaExtractToDirectoryName(dirName); } else { validFlag = false; } } } } else { AString msg("BALSA was unable to provide an updated \"Extraction Directory Prefix\" for Study ID \"" + studyID + "\". You may continue uploading."); WuQMessageBox::warningOk(this, msg); } } } return validFlag; } /** * Update roles label with user's valid roles */ void BalsaDatabaseUploadSceneFileDialog::updateUserRolesLabel() { m_userRolesLabel->setText(""); const bool showRolesFlag = false; if (showRolesFlag) { const AString rolesText = m_userRoles->getRolesForDisplayInGUI(); if ( ! rolesText.isEmpty()) { m_userRolesLabel->setText(" BALSA Roles: " + rolesText); } } } /** * Gets called when return is pressed in either username * or password. If both contain text, try to login. */ void BalsaDatabaseUploadSceneFileDialog::returnPressedUsernameOrPassword() { if (m_usernameLineEdit->text().trimmed().isEmpty()) { return; } if (m_passwordLineEdit->text().trimmed().isEmpty()) { return; } loginButtonClicked(); } /** * Gets called when the Upload button is clicked. */ void BalsaDatabaseUploadSceneFileDialog::okButtonClicked() { CaretAssert(m_sceneFile); m_sceneFile->setBalsaStudyID(m_balsaStudyIDLineEdit->text().trimmed()); m_sceneFile->setBalsaStudyTitle(m_balsaStudyTitleLineEdit->text().trimmed()); AString zipFileErrorMessage; const AString zipFileName = getZipFileNameWithPath(zipFileErrorMessage); m_sceneFile->setBalsaExtractToDirectoryName(m_extractDirectoryNameLineEdit->text().trimmed()); s_username = m_usernameLineEdit->text(); s_password = m_passwordLineEdit->text(); AString msg; if ( ! m_usernameLineEdit->hasAcceptableInput()) { msg.appendWithNewLine("Username is missing. If you do not have an account, press the \"Register\" link. " "If you have forgotten your username, press the \"Forgot Username\" link.

"); } if ( ! m_passwordLineEdit->hasAcceptableInput()) { msg.appendWithNewLine("Password is missing. If you do not remember your password, press the \"Forgot Password\" link.

"); } if (zipFileName.isEmpty()) { msg.appendWithNewLine(zipFileErrorMessage + "

"); } if ( ! m_extractDirectoryNameLineEdit->hasAcceptableInput()) { msg.appendWithNewLine("Extraction Directory Prefix is invalid.

"); } AString basePathErrorMessage; if ( ! m_basePathWidget->isValid(basePathErrorMessage)) { msg.appendWithNewLine(basePathErrorMessage); } else { switch (m_sceneFile->getBasePathType()) { case SceneFileBasePathTypeEnum::AUTOMATIC: break; case SceneFileBasePathTypeEnum::CUSTOM: { if (m_sceneFile->getBalsaCustomBaseDirectory().isEmpty()) { msg.appendWithNewLine("CUSTOM Base Path (on Advanced Tab) is invalid. " "Select Base Path or use AUTOMATIC.

"); } else { if ( ! FileInformation(m_sceneFile->getBalsaCustomBaseDirectory()).exists()) { msg.appendWithNewLine("CUSTOM Base Directory (on Advanced Tab) is not a valid directory on this computer. " "Select a valid Base Path or use AUTOMATIC.

"); } } } break; } } bool invalidStudyFlag = false; if ( ! m_balsaStudyTitleLineEdit->hasAcceptableInput()) { invalidStudyFlag = true; } if ( ! m_balsaStudyIDLineEdit->hasAcceptableInput()) { invalidStudyFlag = true; } if (invalidStudyFlag) { msg.appendWithNewLine("Study ID and/or Title is invalid. Press the \"" + m_selectStudyTitlePushButton->text() + "\" button to choose or create a BALSA Study ID and Title."); } else { /* * Note: Test of study ID for editable status will move * into BALSA Database so disabled until that time. */ const bool testStudyIdEditableFlag(false); if (testStudyIdEditableFlag) { if (m_extractDirectoryNameLineEdit->hasAcceptableInput()) { const AString studyID = m_balsaStudyIDLineEdit->text().trimmed(); AString errorMessage; if ( ! m_balsaDatabaseManager->isStudyEditableByUser(studyID, errorMessage)) { msg.appendWithNewLine(errorMessage); } } } } if ( ! msg.isEmpty()) { msg.insert(0, ""); msg.append(""); WuQMessageBox::errorOk(this, msg); return; } if ( ! checkBalsaExtractionDirectoryPrefix()) { return; } const AString username = m_usernameLineEdit->text().trimmed(); const AString password = m_passwordLineEdit->text().trimmed(); const AString extractToDirectoryName = m_extractDirectoryNameLineEdit->text().trimmed(); AString saveMessage("The scene file is modified and must be saved before continuing."); AString errorMessage; bool sceneFileModStatus = m_sceneFile->isModified(); if (m_balsaDatabaseManager->updateSceneIDs(m_sceneFile, errorMessage)) { if ( ! sceneFileModStatus) { if (m_sceneFile->isModified()) { saveMessage = "The scene file was modified to add BALSA Scene Identifiers and must be saved before continuing."; } } } else { return; } if ( ! saveSceneFile(saveMessage)) { return; } CursorDisplayScoped cursor; cursor.showWaitCursor(); ProgressReportingDialog progressDialog("Upload Scene File to BALSA", "", this); progressDialog.setCancelButton((QPushButton*)0); // no cancel button const bool successFlag = m_balsaDatabaseManager->uploadZippedSceneFile(m_sceneFile, zipFileName, extractToDirectoryName, errorMessage); cursor.restoreCursor(); progressDialog.setValue(progressDialog.maximum()); if (successFlag) { WuQMessageBox::informationOk(this, "Upload was successful"); } else { WuQMessageBox::errorOk(this, errorMessage); return; } WuQDialogModal::okButtonClicked(); } /** * Save the scene file if it is modified. If auto-save is OFF, the user is * prompted to confirm saving. * * @param message * Message containing reason for saving scene file. If empty, the * default "file has been modified and must be saved" message is displayed. * @return * True if the scene file was saved successfully, else false. */ bool BalsaDatabaseUploadSceneFileDialog::saveSceneFile(const AString& saveMessage) { if (m_sceneFile->isModified()) { if ( ! m_autoSaveSceneFileCheckBox->isChecked()) { AString msg(saveMessage + " Would you like to save the scene file using its current name and continue?"); if ( ! WuQMessageBox::warningOkCancel(this, msg)) { return false; } } try { Brain* brain = GuiManager::get()->getBrain(); brain->writeDataFile(m_sceneFile); } catch (const DataFileException& e) { WuQMessageBox::errorOk(this, e.whatString()); return false; } } return true; } /** * Gets called when auto save checkbox is checked. * * @param checked * Check status */ void BalsaDatabaseUploadSceneFileDialog::autoSaveCheckBoxClicked(bool /*checked*/) { } void BalsaDatabaseUploadSceneFileDialog::testButtonClicked() { const int32_t buttonIndex = WuQMessageBox::informationTwoButtons(this, "You have not agreed to Submitter Terms", "OK", "OK, View Terms in Web Browser"); switch (buttonIndex) { case 1: break; case 2: labelHtmlLinkClicked("about/submission"); break; default: CaretAssert(0); } return; bool testRolesFlag = false; bool testNewIDsFlag = true; if (testRolesFlag) { const AString username = m_usernameLineEdit->text().trimmed(); const AString password = m_passwordLineEdit->text().trimmed(); AString roleNames; AString errorMessage; BalsaUserRoles balsaUserRoles; if ( ! m_balsaDatabaseManager->getUserRoles(balsaUserRoles, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); return; } std::cout << "*** Role Names: " << balsaUserRoles.toString() << std::endl; } if (testNewIDsFlag) { int32_t numberOfSceneIDs = 2; std::vector sceneIDs; AString errorMessage; if ( ! m_balsaDatabaseManager->getSceneIDs(numberOfSceneIDs, sceneIDs, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); return; } for (auto id : sceneIDs) { std::cout << "Scene ID " << id << std::endl; } } } /** * Select a Study Title from those user has in BALSA Database */ void BalsaDatabaseUploadSceneFileDialog::selectStudyTitleButtonClicked() { const AString username = m_usernameLineEdit->text().trimmed(); const AString password = m_passwordLineEdit->text().trimmed(); std::vector studyInfo; CursorDisplayScoped cursor; cursor.showWaitCursor(); AString errorMessage; if ( ! m_balsaDatabaseManager->getAllStudyInformation(studyInfo, errorMessage)) { cursor.restoreCursor(); WuQMessageBox::errorOk(this, errorMessage); return; } cursor.restoreCursor(); const AString selectedStudyName = m_balsaStudyTitleLineEdit->text().trimmed(); BalsaStudySelectionDialog dialog(studyInfo, selectedStudyName, m_balsaDatabaseManager.get(), getDataBaseURL(), username, password, this); if (dialog.exec() == BalsaStudySelectionDialog::Accepted) { BalsaStudyInformation bsi = dialog.getSelectedStudyInformation(); if ( ! bsi.isEmpty()) { m_balsaStudyIDLineEdit->setText(bsi.getStudyID()); m_balsaStudyTitleLineEdit->setText(bsi.getStudyTitle()); } validateUploadData(); } } /** * Copy automatic directory to clipboard */ void BalsaDatabaseUploadSceneFileDialog::copyAutomaticDirectoryPushButtonClicked() { const QString txt = m_zipFileAutomaticDirectoryLineEdit->text().trimmed(); if ( ! txt.isEmpty()) { QApplication::clipboard()->setText(txt, QClipboard::Clipboard); } } /** * Choose the custom directory */ void BalsaDatabaseUploadSceneFileDialog::browseZipFileCustomDirectoryPushButtonClicked() { CaretAssert(m_sceneFile); /* * Let user choose directory path */ QString directoryName; FileInformation fileInfo(m_zipFileCustomDirectoryLineEdit->text().trimmed()); if (fileInfo.exists()) { if (fileInfo.isDirectory()) { directoryName = fileInfo.getAbsoluteFilePath(); } } AString newDirectoryName = CaretFileDialog::getExistingDirectoryDialog(m_zipFileCustomDirectoryRadioButton, "Choose Custom Zip File Directory", directoryName); /* * If user cancels, return */ if (newDirectoryName.isEmpty()) { return; } /* * Set name of new scene file and add to brain */ m_zipFileCustomDirectoryLineEdit->setText(newDirectoryName); FileInformation newFileInfo(newDirectoryName); if (newFileInfo.exists() && newFileInfo.isDirectory()) { m_zipFileCustomDirectoryRadioButton->setChecked(true); } validateUploadData(); } /** * Create a regular expression validatory for the give label/data. * * @param labelName * 'Name' of label. */ QRegularExpressionValidator* BalsaDatabaseUploadSceneFileDialog::createValidator(const LabelName labelName) { QRegularExpression regEx; switch (labelName) { case LabelName::LABEL_DATABASE: regEx.setPattern(".+"); break; case LabelName::LABEL_EXTRACT_DIRECTORY: regEx.setPattern(".+"); break; case LabelName::LABEL_PASSWORD: regEx.setPattern(".+"); break; case LabelName::LABEL_STUDY_ID: { const AString lowerCaseNoVowels("bcdfghjklmnpqrstvwxyz"); const AString upperCaseNoVowels(lowerCaseNoVowels.toUpper()); regEx.setPattern("[0-9" + lowerCaseNoVowels + upperCaseNoVowels + "]+"); } break; case LabelName::LABEL_STUDY_TITLE: regEx.setPattern(".+"); break; case LabelName::LABEL_USERNAME: regEx.setPattern(".+"); break; } CaretAssert(regEx.isValid()); QRegularExpressionValidator* validator = new QRegularExpressionValidator(regEx, this); return validator; } /** * Called by validators. */ void BalsaDatabaseUploadSceneFileDialog::validateUploadData() { updateAllLabels(); } /** * Update all of the labels. */ void BalsaDatabaseUploadSceneFileDialog::updateAllLabels() { setLabelText(LabelName::LABEL_DATABASE); setLabelText(LabelName::LABEL_EXTRACT_DIRECTORY); setLabelText(LabelName::LABEL_PASSWORD); setLabelText(LabelName::LABEL_STUDY_ID); setLabelText(LabelName::LABEL_STUDY_TITLE); setLabelText(LabelName::LABEL_USERNAME); } /** * Set the label's text. * * @param label * The label * @param labelName * 'Name' of the label */ void BalsaDatabaseUploadSceneFileDialog::setLabelText(const LabelName labelName) { QLabel* label = NULL; AString labelText; bool validFlag = false; switch (labelName) { case LabelName::LABEL_DATABASE: label = m_databaseLabel; labelText = "Database"; validFlag = true; break; case LabelName::LABEL_EXTRACT_DIRECTORY: label = m_extractDirectoryNameLabel; labelText = "Extraction Directory Prefix"; validFlag = m_extractDirectoryNameLineEdit->hasAcceptableInput(); break; case LabelName::LABEL_PASSWORD: label = m_passwordLabel; labelText = "Password"; validFlag = m_passwordLineEdit->hasAcceptableInput(); break; case LabelName::LABEL_STUDY_ID: label = m_balsaStudyIDLabel; labelText = "Study ID"; validFlag = m_balsaStudyIDLineEdit->hasAcceptableInput(); break; case LabelName::LABEL_STUDY_TITLE: label = m_balsaStudyTitleLabel; labelText = "Study Title"; validFlag = m_balsaStudyTitleLineEdit->hasAcceptableInput(); break; case LabelName::LABEL_USERNAME: label = m_usernameLabel; labelText = "Username"; validFlag = m_usernameLineEdit->hasAcceptableInput(); break; } const bool textRedIfInvalid = true; AString coloredText; if (validFlag) { if (textRedIfInvalid) { coloredText = (labelText + ": "); } else { coloredText = (" " + labelText + ": "); } } else { if (textRedIfInvalid) { coloredText = ("" + labelText + ": "); } else { coloredText = ("" + labelText + "*" ": "); } } CaretAssert(label); label->setText(coloredText); } /** * Displays a dialog explaining the ZIP file directory options */ void BalsaDatabaseUploadSceneFileDialog::whatsThisZipFileDirectory() { const AString text("When a Scene File is uploaded to BALSA, the Scene File and all data files that it " "references are placed into a ZIP file and the ZIP file is then uploaded to BALSA. " "While unlikely, creation of the ZIP file in the system temporary directory could fail " "if there is insufficient space. If this should happen, set a CUSTOM directory on a disk " "with adequate space."); WuQMessageBox::informationOk(this, text); } /** * Displays a dialog explaining the database selection option */ void BalsaDatabaseUploadSceneFileDialog::whatsThisDatabase() { const AString text("This option is provided for developers of " "Workbench (wb_view and wb_command) and BALSA Database software. " "It allows the selection of develpment versions of the BALSA Database. " "To add a database, type the new name into the combo box."); WuQMessageBox::informationOk(this, text); } connectome-workbench-1.4.2/src/GuiQt/BalsaDatabaseUploadSceneFileDialog.h000066400000000000000000000126521360521144700263440ustar00rootroot00000000000000#ifndef __BALSA_DATABASE_UPLOAD_SCENE_FILE_DIALOG_H__ #define __BALSA_DATABASE_UPLOAD_SCENE_FILE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "WuQDialogModal.h" class QAction; class QCheckBox; class QComboBox; class QLabel; class QLineEdit; class QPushButton; class QRadioButton; class QRegularExpressionValidator; namespace caret { class BalsaDatabaseManager; class BalsaUserRoles; class SceneBasePathWidget; class SceneFile; class BalsaDatabaseUploadSceneFileDialog : public WuQDialogModal { Q_OBJECT public: BalsaDatabaseUploadSceneFileDialog(SceneFile* sceneFile, QWidget* parent); virtual ~BalsaDatabaseUploadSceneFileDialog(); // ADD_NEW_METHODS_HERE private slots: void loginInformationChanged(); void loginButtonClicked(); void returnPressedUsernameOrPassword(); void showPasswordActionTriggered(bool checked); void labelHtmlLinkClicked(const QString&); void validateUploadData(); void selectStudyTitleButtonClicked(); void zipFileDirectoryRadioButtonClicked(int); void copyAutomaticDirectoryPushButtonClicked(); void browseZipFileCustomDirectoryPushButtonClicked(); void testButtonClicked(); void autoSaveCheckBoxClicked(bool checked); virtual void cancelButtonClicked(); void whatsThisZipFileDirectory(); void whatsThisDatabase(); protected: virtual void okButtonClicked(); private: enum class LabelName { LABEL_DATABASE, LABEL_EXTRACT_DIRECTORY, LABEL_PASSWORD, LABEL_STUDY_ID, LABEL_STUDY_TITLE, LABEL_USERNAME }; BalsaDatabaseUploadSceneFileDialog(const BalsaDatabaseUploadSceneFileDialog&); BalsaDatabaseUploadSceneFileDialog& operator=(const BalsaDatabaseUploadSceneFileDialog&); QWidget* createLoginWidget(); QWidget* createTabWidget(); QWidget* createUploadTab(); QWidget* createAdvancedTab(); QWidget* createBalsaDatabaseSelectionWidget(); QWidget* creatZipFileDirectoryWidget(); void loadSceneFileMetaDataWidgets(); AString getDataBaseURL() const; QRegularExpressionValidator* createValidator(const LabelName labelName); AString getZipFileNameWithPath(AString& errorMessageOut) const; void updateAllLabels(); void setLabelText(const LabelName labelName); bool saveSceneFile(const AString& saveMesage); void updateUserRolesLabel(); bool checkBalsaExtractionDirectoryPrefix(); SceneFile* m_sceneFile; std::unique_ptr m_balsaDatabaseManager; QWidget* m_uploadWidget; QLabel* m_databaseLabel; QComboBox* m_databaseComboBox; QLabel* m_usernameLabel; QLineEdit* m_usernameLineEdit; QLabel* m_passwordLabel; QLineEdit* m_passwordLineEdit; QAction* m_showPasswordAction; QPushButton* m_loginPushButton; QLabel* m_userRolesLabel; std::unique_ptr m_userRoles; QRadioButton* m_zipFileTemporaryDirectoryRadioButton; QRadioButton* m_zipFileCustomDirectoryRadioButton; QLineEdit* m_zipFileAutomaticDirectoryLineEdit; QLineEdit* m_zipFileCustomDirectoryLineEdit; QLabel* m_extractDirectoryNameLabel; QLineEdit* m_extractDirectoryNameLineEdit; QLabel* m_balsaStudyIDLabel; QLineEdit* m_balsaStudyIDLineEdit; QLabel* m_balsaStudyTitleLabel; QLineEdit* m_balsaStudyTitleLineEdit; QPushButton* m_selectStudyTitlePushButton; QCheckBox* m_autoSaveSceneFileCheckBox; SceneBasePathWidget* m_basePathWidget; static AString s_username; static AString s_password; // ADD_NEW_MEMBERS_HERE }; #ifdef __BALSA_DATABASE_UPLOAD_SCENE_FILE_DIALOG_DECLARE__ AString BalsaDatabaseUploadSceneFileDialog::s_username; AString BalsaDatabaseUploadSceneFileDialog::s_password; #endif // __BALSA_DATABASE_UPLOAD_SCENE_FILE_DIALOG_DECLARE__ } // namespace #endif //__BALSA_DATABASE_UPLOAD_SCENE_FILE_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/BalsaStudyInformation.cxx000066400000000000000000000116331360521144700244640ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BALSA_STUDY_INFORMATION_DECLARE__ #include "BalsaStudyInformation.h" #undef __BALSA_STUDY_INFORMATION_DECLARE__ #include #include "CaretAssert.h" using namespace caret; /** * \class caret::BalsaStudyInformation * \brief Information about a BALSA Study * \ingroup GuiQt */ /** * Constructor with invalid ID and title. */ BalsaStudyInformation::BalsaStudyInformation() : CaretObject() { } /** * Constructor with ID and title. * * @param studyID * The Study Identifier * @param studyTitle * The Study Title */ BalsaStudyInformation::BalsaStudyInformation(const AString& studyID, const AString& studyTitle) : CaretObject(), m_studyID(studyID), m_studyTitle(studyTitle), m_editableStatus(false) { } /** * Constructor that creates BALSA study information from a JSON object. * * @param jsonObject * The JSON object. */ BalsaStudyInformation::BalsaStudyInformation(const QJsonObject& jsonObject) { QJsonObject::const_iterator idIter = jsonObject.find("id"); QJsonObject::const_iterator titleIter = jsonObject.find("title"); if ((idIter != jsonObject.end()) && (titleIter != jsonObject.end())) { m_studyID = (*idIter).toString(); m_studyTitle = (*titleIter).toString(); QJsonObject::const_iterator statusIter = jsonObject.find("status"); if (statusIter != jsonObject.end()) { QJsonObject statusObject = (*statusIter).toObject(); QJsonObject::const_iterator nameIter = statusObject.find("name"); if (nameIter != jsonObject.end()) { AString editText = (*nameIter).toString().toUpper().trimmed(); m_editableStatus = (editText == "EDITABLE"); } } } } /** * Destructor. */ BalsaStudyInformation::~BalsaStudyInformation() { } /** * Copy constructor. * @param obj * Object that is copied. */ BalsaStudyInformation::BalsaStudyInformation(const BalsaStudyInformation& obj) : CaretObject(obj) { this->copyHelperBalsaStudyInformation(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ BalsaStudyInformation& BalsaStudyInformation::operator=(const BalsaStudyInformation& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperBalsaStudyInformation(obj); } return *this; } /** * Comparison operator using study title. * * @param obj * Other study information. * @return * True if "this" is less than obj. */ bool BalsaStudyInformation::operator<(const BalsaStudyInformation& obj) const { return m_studyTitle < obj.m_studyTitle; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void BalsaStudyInformation::copyHelperBalsaStudyInformation(const BalsaStudyInformation& obj) { m_studyID = obj.m_studyID; m_studyTitle = obj.m_studyTitle; m_editableStatus = obj.m_editableStatus; } /** * @return True if ID is not empty (title may be empty). */ bool BalsaStudyInformation::isEmpty() const { return m_studyID.isEmpty(); } /** * @return study identifier generated by BALSA */ AString BalsaStudyInformation::getStudyID() const { return m_studyID; } /** * Set study identifier generated by BALSA * @param studyID * New value for study identifier generated by BALSA */ void BalsaStudyInformation::setStudyID(const AString& studyID) { m_studyID = studyID; } /** * @return study title */ AString BalsaStudyInformation::getStudyTitle() const { return m_studyTitle; } /** * Set study title * @param studyTitle * New value for study title */ void BalsaStudyInformation::setStudyTitle(const AString& studyTitle) { m_studyTitle = studyTitle; } /** * @return True is the study is editable. */ bool BalsaStudyInformation::isEditable() const { return m_editableStatus; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString BalsaStudyInformation::toString() const { return "BalsaStudyInformation"; } connectome-workbench-1.4.2/src/GuiQt/BalsaStudyInformation.h000066400000000000000000000047241360521144700241140ustar00rootroot00000000000000#ifndef __BALSA_STUDY_INFORMATION_H__ #define __BALSA_STUDY_INFORMATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" class QJsonObject; namespace caret { class BalsaStudyInformation : public CaretObject { public: BalsaStudyInformation(const QJsonObject& jsonObject); BalsaStudyInformation(); BalsaStudyInformation(const AString& studyID, const AString& studyTitle); virtual ~BalsaStudyInformation(); BalsaStudyInformation(const BalsaStudyInformation& obj); BalsaStudyInformation& operator=(const BalsaStudyInformation& obj); bool operator<(const BalsaStudyInformation& obj) const; bool isEmpty() const; AString getStudyID() const; void setStudyID(const AString& studyID); AString getStudyTitle() const; void setStudyTitle(const AString& studyTitle); bool isEditable() const; // ADD_NEW_METHODS_HERE virtual AString toString() const; private: void copyHelperBalsaStudyInformation(const BalsaStudyInformation& obj); /** study identifier generated by BALSA*/ AString m_studyID; /** study title*/ AString m_studyTitle; /** editable status (true is YES) */ bool m_editableStatus = false; // ADD_NEW_MEMBERS_HERE }; #ifdef __BALSA_STUDY_INFORMATION_DECLARE__ // #endif // __BALSA_STUDY_INFORMATION_DECLARE__ } // namespace #endif //__BALSA_STUDY_INFORMATION_H__ connectome-workbench-1.4.2/src/GuiQt/BalsaStudySelectionDialog.cxx000066400000000000000000000246621360521144700252520ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BALSA_STUDY_SELECTION_DIALOG_DECLARE__ #include "BalsaStudySelectionDialog.h" #undef __BALSA_STUDY_SELECTION_DIALOG_DECLARE__ #include #include #include #include #include #include #include "BalsaDatabaseManager.h" #include "CaretAssert.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::BalsaStudySelectionDialog * \brief Dialog for selection and getting study titles with BALSA Database * \ingroup GuiQt */ /** * Constructor. * * @param studyInformation * The study information. * @param selectedStudyName * Name of study information that is selected. * @param balsaDatabaseManager * Database manager. * @param databaseURL * URL for database requests. * @param balsaUsername * Username for BALSA Database * @param balsaPassword * Password for BALSA Database * @param parent * Parent dialog */ BalsaStudySelectionDialog::BalsaStudySelectionDialog(const std::vector& studyInformation, const AString selectedStudyName, BalsaDatabaseManager* balsaDatabaseManager, const AString& databaseURL, const AString& balsaUsername, const AString& balsaPassword, QWidget* parent) : WuQDialogModal("BALSA Studies", parent), m_studyInformation(studyInformation), m_balsaDatabaseManager(balsaDatabaseManager), m_databaseURL(databaseURL), m_balsaUsername(balsaUsername), m_balsaPassword(balsaPassword) { m_studyTableWidget = new QTableWidget(); QPushButton* newStudyTitlePushButton = new QPushButton("Create New Study..."); newStudyTitlePushButton->setSizePolicy(QSizePolicy::Fixed, newStudyTitlePushButton->sizePolicy().verticalPolicy()); QObject::connect(newStudyTitlePushButton, &QPushButton::clicked, this, &BalsaStudySelectionDialog::newStudyButtonClicked); m_editSelectedStudyPushButton = new QPushButton("Edit Selected Study Title..."); m_editSelectedStudyPushButton->setSizePolicy(QSizePolicy::Fixed, m_editSelectedStudyPushButton->sizePolicy().verticalPolicy()); QObject::connect(m_editSelectedStudyPushButton, &QPushButton::clicked, this, &BalsaStudySelectionDialog::editSelectedStudyButtonClicked); QHBoxLayout* studyButtonLayout = new QHBoxLayout(); studyButtonLayout->addWidget(newStudyTitlePushButton); studyButtonLayout->addStretch(); studyButtonLayout->addWidget(m_editSelectedStudyPushButton); QWidget* dialogWidget = new QWidget; QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); dialogLayout->addWidget(m_studyTableWidget, 100); dialogLayout->addLayout(studyButtonLayout, 0); setCentralWidget(dialogWidget, SCROLL_AREA_NEVER); loadStudyTitleTableWidget(selectedStudyName); const QSize tableSize = WuQtUtilities::estimateTableWidgetSize(m_studyTableWidget); WuQtUtilities::resizeWindow(this, std::min(tableSize.width() + 40, 600), std::min(tableSize.height() + 40, 600)); } /** * Destructor. */ BalsaStudySelectionDialog::~BalsaStudySelectionDialog() { } /** * Load the list widget for the studies. * * @param selectedStudyName * Name of study information that is selected. */ void BalsaStudySelectionDialog::loadStudyTitleTableWidget(const AString selectedStudyNameIn) { AString selectedStudyName = selectedStudyNameIn; const int numRows = static_cast(m_studyInformation.size()); if (selectedStudyName.isEmpty()) { const int32_t selectedRow = m_studyTableWidget->currentRow(); if ((selectedRow >= 0) && (selectedRow < numRows)) { selectedStudyName = m_studyTableWidget->item(selectedRow, COLUMN_TITLE)->text(); } } m_studyTableWidget->clear(); m_studyTableWidget->setSelectionMode(QTableWidget::SingleSelection); m_studyTableWidget->setSelectionBehavior(QTableWidget::SelectRows); m_studyTableWidget->setRowCount(numRows); m_studyTableWidget->setColumnCount(COLUMN_COUNT); m_studyTableWidget->setHorizontalHeaderItem(COLUMN_ID, new QTableWidgetItem("ID")); m_studyTableWidget->setHorizontalHeaderItem(COLUMN_TITLE, new QTableWidgetItem("Title")); m_studyTableWidget->setShowGrid(false); std::sort(m_studyInformation.begin(), m_studyInformation.end()); int32_t selectedRow = 0; for (int32_t iRow = 0; iRow < numRows; iRow++) { const AString studyTitle = m_studyInformation[iRow].getStudyTitle(); if ( ! selectedStudyName.isEmpty()) { if (selectedStudyName.toLower() == studyTitle.toLower()) { selectedRow = iRow; } } CaretAssertVectorIndex(m_studyInformation, iRow); QTableWidgetItem* idItem = new QTableWidgetItem(m_studyInformation[iRow].getStudyID()); idItem->setFlags(idItem->flags() &= (~Qt::ItemIsEditable)); m_studyTableWidget->setItem(iRow, COLUMN_ID, idItem); QTableWidgetItem* titleItem = new QTableWidgetItem(studyTitle); titleItem->setFlags(idItem->flags() &= (~Qt::ItemIsEditable)); m_studyTableWidget->setItem(iRow, COLUMN_TITLE, titleItem); } if (numRows > 0) { if (selectedRow >= 0) { m_studyTableWidget->selectRow(selectedRow); } else { m_studyTableWidget->selectRow(0); } const int32_t rowIndex = m_studyTableWidget->currentRow(); if (rowIndex >= 0) { QTableWidgetItem* item = m_studyTableWidget->item(rowIndex, 0); if (item != NULL) { m_studyTableWidget->scrollToItem(item); } } QHeaderView* horizontalHeader = m_studyTableWidget->horizontalHeader(); for (int32_t i = 0; i < COLUMN_COUNT; i++) { const int logicalIndex = horizontalHeader->logicalIndex(i); horizontalHeader->setSectionResizeMode(logicalIndex, QHeaderView::ResizeToContents); } } } /** * @return The selected study information. Will return * and empty instance (test with isEmpty()) if no study information was selected. */ BalsaStudyInformation BalsaStudySelectionDialog::getSelectedStudyInformation() const { const int32_t selectedRow = m_studyTableWidget->currentRow(); if (selectedRow < 0) { return BalsaStudyInformation(); } CaretAssertVectorIndex(m_studyInformation, selectedRow); return m_studyInformation[selectedRow]; } /** * Called when the new study button is clicked. */ void BalsaStudySelectionDialog::newStudyButtonClicked() { AString title = QInputDialog::getText(this, "Create New Study", "Title of New Study"); if ( ! title.isNull()) { title = title.trimmed(); AString studyID; AString errorMessage; const bool successFlag = m_balsaDatabaseManager->getStudyIDFromStudyTitle(title, studyID, errorMessage); if (successFlag) { const AString titleLower = title.toLower(); for (auto infoIter : m_studyInformation) { if (infoIter.getStudyTitle().toLower() == titleLower) { WuQMessageBox::errorOk(this, ("Duplicate study names are not allowed: \"" + title + "\" ")); return; } } m_studyInformation.emplace_back(studyID, title); loadStudyTitleTableWidget(title); } else { WuQMessageBox::errorOk(this, errorMessage); } } } /** * Called when edit selected study title button is clicked */ void BalsaStudySelectionDialog::editSelectedStudyButtonClicked() { const int32_t selectedRow = m_studyTableWidget->currentRow(); if (selectedRow < 0) { WuQMessageBox::errorOk(this, "No Study Title is selected"); return; } CaretAssertVectorIndex(m_studyInformation, selectedRow); AString title = m_studyInformation[selectedRow].getStudyTitle(); title = QInputDialog::getText(this, "Edit study title", "Title", QLineEdit::Normal, title); if ( ! title.isNull()) { m_studyInformation[selectedRow].setStudyTitle(title); loadStudyTitleTableWidget(title); } } /** * Called when the OK button is clicked. */ void BalsaStudySelectionDialog::okButtonClicked() { if ( m_studyTableWidget->currentItem() == NULL) { WuQMessageBox::errorOk(this, "No Study Title is selected"); return; } WuQDialogModal::okButtonClicked(); } connectome-workbench-1.4.2/src/GuiQt/BalsaStudySelectionDialog.h000066400000000000000000000057761360521144700247040ustar00rootroot00000000000000#ifndef __BALSA_STUDY_SELECTION_DIALOG_H__ #define __BALSA_STUDY_SELECTION_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "BalsaStudyInformation.h" #include "WuQDialogModal.h" class QPushButton; class QTableWidget; namespace caret { class BalsaDatabaseManager; class BalsaStudySelectionDialog : public WuQDialogModal { Q_OBJECT public: BalsaStudySelectionDialog(const std::vector& studyInformation, const AString selectedStudyName, BalsaDatabaseManager* balsaDatabaseManager, const AString& databaseURL, const AString& balsaUsername, const AString& balsaPassword, QWidget* parent); virtual ~BalsaStudySelectionDialog(); virtual void okButtonClicked() override; BalsaStudyInformation getSelectedStudyInformation() const; // ADD_NEW_METHODS_HERE private slots: void newStudyButtonClicked(); void editSelectedStudyButtonClicked(); private: const int32_t COLUMN_TITLE = 0; const int32_t COLUMN_ID = 1; const int32_t COLUMN_COUNT = 2; BalsaStudySelectionDialog(const BalsaStudySelectionDialog&); BalsaStudySelectionDialog& operator=(const BalsaStudySelectionDialog&); void loadStudyTitleTableWidget(const AString selectedStudyName); std::vector m_studyInformation; BalsaDatabaseManager* m_balsaDatabaseManager; const AString& m_databaseURL; const AString& m_balsaUsername; const AString& m_balsaPassword; QTableWidget* m_studyTableWidget; QPushButton* m_editSelectedStudyPushButton; // ADD_NEW_MEMBERS_HERE }; #ifdef __BALSA_STUDY_SELECTION_DIALOG_DECLARE__ // #endif // __BALSA_STUDY_SELECTION_DIALOG_DECLARE__ } // namespace #endif //__BALSA_STUDY_SELECTION_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/BalsaUserRoles.cxx000066400000000000000000000127151360521144700230730ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BALSA_USER_ROLES_DECLARE__ #include "BalsaUserRoles.h" #undef __BALSA_USER_ROLES_DECLARE__ #include #include "CaretAssert.h" #include "CaretLogger.h" using namespace caret; /** * \class caret::BalsaUserRoles * \brief Information about a BALSA User's Roles * \ingroup GuiQt */ /** * Constructor with all roles invalid; */ BalsaUserRoles::BalsaUserRoles() : CaretObject() { resetToAllInvalid(); } /** * Constructor that creates BALSA user roles from a JSON array. * * @param jsonArray * The JSON array. */ BalsaUserRoles::BalsaUserRoles(const QJsonArray& jsonArray) { resetToAllInvalid(); parseJson(jsonArray); } /** * Destructor. */ BalsaUserRoles::~BalsaUserRoles() { } /** * Copy constructor. * @param obj * Object that is copied. */ BalsaUserRoles::BalsaUserRoles(const BalsaUserRoles& obj) : CaretObject(obj) { this->copyHelperBalsaUserRoles(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ BalsaUserRoles& BalsaUserRoles::operator=(const BalsaUserRoles& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperBalsaUserRoles(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void BalsaUserRoles::copyHelperBalsaUserRoles(const BalsaUserRoles& obj) { m_validFlag = obj.m_validFlag; m_adminFlag = obj.m_adminFlag; m_curatorFlag = obj.m_curatorFlag; m_submitterFlag = obj.m_submitterFlag; m_userFlag = obj.m_userFlag; } /** * Reset the instance to all invalid roles. */ void BalsaUserRoles::resetToAllInvalid() { m_validFlag = false; m_adminFlag = false; m_curatorFlag = false; m_submitterFlag = false; m_userFlag = false; } /** * Parse JSON to find roles. * * @param jsonArray * JSON array with roles. * @return * True if data was parsed, else false. */ bool BalsaUserRoles::parseJson(const QJsonArray& jsonArray) { resetToAllInvalid(); for (QJsonArray::const_iterator roleIter = jsonArray.begin(); roleIter != jsonArray.end(); roleIter++) { QJsonValue value = *roleIter; if (value.isString()) { const QString roleName = value.toString().trimmed(); if (roleName == "ROLE_ADMIN") { m_adminFlag = true; } else if (roleName == "ROLE_CURATOR") { m_curatorFlag = true; } else if (roleName == "ROLE_SUBMITTER") { m_submitterFlag = true; } else if (roleName == "ROLE_USER") { m_userFlag = true; } else { CaretLogInfo("Unrecognized BALSA role found \"" + roleName + "\""); } } m_validFlag = true; } /* * Some roles imply other roles */ if (m_curatorFlag) { m_submitterFlag = true; } return isValid(); } /** * @return True if has admin role */ bool BalsaUserRoles::isAdmin() const { return m_adminFlag; } /** * @return True if has admin role */ bool BalsaUserRoles::isCurator() const { return m_curatorFlag; } /** * @return True if has submitter role */ bool BalsaUserRoles::isSubmitter() const { return m_submitterFlag; } /** * @return True if has user role */ bool BalsaUserRoles::isUser() const { return m_userFlag; } /** * Is the data valid (has parsed successfully) */ bool BalsaUserRoles::isValid() const { return m_validFlag; } /** * @return Roles formatted for display in GUI. */ AString BalsaUserRoles::getRolesForDisplayInGUI() const { AString s; if (m_validFlag) { if (m_adminFlag) s.append("Admin; "); if (m_curatorFlag) s.append("Curator; "); if (m_submitterFlag) s.append("Submitter; "); if (m_userFlag) s.append("User; "); } return s; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString BalsaUserRoles::toString() const { AString msg("BalsaUserRoles: " + AString("Data Valid - " + AString(m_validFlag ? "YES: " : "NO: ")) + AString("Admin - " + AString(m_adminFlag ? "YES: " : "NO: ")) + AString("Curator - " + AString(m_curatorFlag ? "YES: " : "NO: ")) + AString("Submitter - " + AString(m_submitterFlag ? "YES: " : "NO: ")) + AString("User - " + AString(m_userFlag ? "YES: " : "NO: "))); return msg; } connectome-workbench-1.4.2/src/GuiQt/BalsaUserRoles.h000066400000000000000000000044001360521144700225100ustar00rootroot00000000000000#ifndef __BALSA_USER_ROLES_H__ #define __BALSA_USER_ROLES_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" class QJsonArray; namespace caret { class BalsaUserRoles : public CaretObject { public: BalsaUserRoles(const QJsonArray& jsonArray); BalsaUserRoles(); virtual ~BalsaUserRoles(); BalsaUserRoles(const BalsaUserRoles& obj); BalsaUserRoles& operator=(const BalsaUserRoles& obj); void resetToAllInvalid(); bool parseJson(const QJsonArray& jsonArray); bool isEmpty() const; bool isAdmin() const; bool isCurator() const; bool isSubmitter() const; bool isUser() const; bool isValid() const; // ADD_NEW_METHODS_HERE AString getRolesForDisplayInGUI() const; virtual AString toString() const; private: void copyHelperBalsaUserRoles(const BalsaUserRoles& obj); bool m_adminFlag = false; bool m_curatorFlag = false; bool m_submitterFlag = false; bool m_userFlag = false; bool m_validFlag = false; // ADD_NEW_MEMBERS_HERE }; #ifdef __BALSA_USER_ROLES_DECLARE__ // #endif // __BALSA_USER_ROLES_DECLARE__ } // namespace #endif //__BALSA_USER_ROLES_H__ connectome-workbench-1.4.2/src/GuiQt/BorderEditingSelectionDialog.cxx000066400000000000000000000117751360521144700257210ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BORDER_EDITING_SELECTION_DIALOG_DECLARE__ #include "BorderEditingSelectionDialog.h" #undef __BORDER_EDITING_SELECTION_DIALOG_DECLARE__ #include #include #include #include #include #include "CaretAssert.h" using namespace caret; /** * \class caret::BorderEditingSelectionDialog * \brief Dialog for selecting border when borders are editing. * \ingroup GuiQt */ /** * Constructor. * * @param modeDescription * Description of the mode. * @param borderNames * Names of the borders for selection. * @param parent * Parent of the dialog. */ BorderEditingSelectionDialog::BorderEditingSelectionDialog(const AString& modeDescription, const std::vector& borderNames, QWidget* parent) : WuQDialogModal("Border Editing", parent) { AString modeText(modeDescription + ((borderNames.size() > 1) ? " these borders (ordered by distance): " : " this border: ")); const QString toolTipText = ("ERASE AND REPLACE - Distance is the average of:\n" " * Distance from first segment point to nearest point in border.\n" " * Distance from last segment point to nearest point in border.\n" "\n" "EXTEND - Distance is from first segment point to any point\n" "in border.\n"); QLabel* modeLabel = new QLabel(modeText); QPushButton* allOnPushButton = new QPushButton("All On"); QObject::connect(allOnPushButton, SIGNAL(clicked()), this, SLOT(allOnPushButtonClicked())); QPushButton* allOffPushButton = new QPushButton("All Off"); QObject::connect(allOffPushButton, SIGNAL(clicked()), this, SLOT(allOffPushButtonClicked())); QWidget* allOnOffWidget = new QWidget(); QHBoxLayout* allOnOffLayout = new QHBoxLayout(allOnOffWidget); allOnOffLayout->addWidget(allOnPushButton); allOnOffLayout->addStrut(10); allOnOffLayout->addWidget(allOffPushButton); allOnOffLayout->addStretch(); QWidget* widget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(modeLabel); for (std::vector::const_iterator iter = borderNames.begin(); iter != borderNames.end(); iter++) { QCheckBox* cb = new QCheckBox(*iter); cb->setChecked(true); cb->setToolTip(toolTipText); m_borderNameCheckBoxes.push_back(cb); layout->addWidget(cb); } setTopBottomAndCentralWidgets(allOnOffWidget, widget, NULL, WuQDialog::SCROLL_AREA_AS_NEEDED); disableAutoDefaultForAllPushButtons(); } /** * Destructor. */ BorderEditingSelectionDialog::~BorderEditingSelectionDialog() { } /** * Called when ALL ON push button is clicked. */ void BorderEditingSelectionDialog::allOnPushButtonClicked() { setAllCheckBoxesChecked(true); } /** * Called when ALL OFF push button is clicked. */ void BorderEditingSelectionDialog::allOffPushButtonClicked() { setAllCheckBoxesChecked(false); } /** * Set all checkbox check status. * * @param status * New checked status. */ void BorderEditingSelectionDialog::setAllCheckBoxesChecked(const bool status) { for (std::vector::iterator iter = m_borderNameCheckBoxes.begin(); iter != m_borderNameCheckBoxes.end(); iter++) { QCheckBox* cb = *iter; cb->setChecked(status); } } /** * Is the border name with the given index selected ? * * @param borderNameIndex * Index of the border name. * @return * Selection status. */ bool BorderEditingSelectionDialog::isBorderNameSelected(const int32_t borderNameIndex) const { CaretAssertVectorIndex(m_borderNameCheckBoxes, borderNameIndex); return m_borderNameCheckBoxes[borderNameIndex]->isChecked(); } connectome-workbench-1.4.2/src/GuiQt/BorderEditingSelectionDialog.h000066400000000000000000000042151360521144700253350ustar00rootroot00000000000000#ifndef __BORDER_EDITING_SELECTION_DIALOG_H__ #define __BORDER_EDITING_SELECTION_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WuQDialogModal.h" class QCheckBox; namespace caret { class BorderEditingSelectionDialog : public WuQDialogModal { Q_OBJECT public: BorderEditingSelectionDialog(const AString& modeDescription, const std::vector& borderNames, QWidget* parent); virtual ~BorderEditingSelectionDialog(); // ADD_NEW_METHODS_HERE bool isBorderNameSelected(const int32_t borderNameIndex) const; private slots: void allOnPushButtonClicked(); void allOffPushButtonClicked(); private: BorderEditingSelectionDialog(const BorderEditingSelectionDialog&); BorderEditingSelectionDialog& operator=(const BorderEditingSelectionDialog&); void setAllCheckBoxesChecked(const bool status); std::vector m_borderNameCheckBoxes; // ADD_NEW_MEMBERS_HERE }; #ifdef __BORDER_EDITING_SELECTION_DIALOG_DECLARE__ // #endif // __BORDER_EDITING_SELECTION_DIALOG_DECLARE__ } // namespace #endif //__BORDER_EDITING_SELECTION_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/BorderFileSplitDialog.cxx000066400000000000000000000255221360521144700243560ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BORDER_FILE_SPLIT_DIALOG_DECLARE__ #include "BorderFileSplitDialog.h" #undef __BORDER_FILE_SPLIT_DIALOG_DECLARE__ #include #include #include #include #include #include #include "BorderFile.h" #include "Brain.h" #include "BrainStructure.h" #include "CaretAssert.h" #include "CaretDataFileSelectionComboBox.h" #include "CaretDataFileSelectionModel.h" #include "CaretFileDialog.h" #include "EventDataFileAdd.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "FileInformation.h" #include "GuiManager.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::BorderFileSplitDialog * \brief Dialog for splitting multi-structure border file. * \ingroup GuiQt * * Some older border files contained borders for multiple structures * which will not work with wb_command operations. This dialog is * used to split up a multi-structure border file into multiple border * files each containing a single structure. */ /** * Constructor. */ BorderFileSplitDialog::BorderFileSplitDialog(QWidget* parent) : WuQDialogModal("Split Multi-Structure Border File", parent) { m_dialogIsBeingCreatedFlag = true; m_fileNameToolButtonSignalMapper = new QSignalMapper(this); QObject::connect(m_fileNameToolButtonSignalMapper, SIGNAL(mapped(int)), this, SLOT(fileNameToolButtonClicked(int))); m_fileSelectionModel.grabNew(CaretDataFileSelectionModel::newInstanceForMultiStructureBorderFiles()); QLabel* fileSelectionLabel = new QLabel("Multi Structure Border File: "); m_fileSelectionComboBox = new CaretDataFileSelectionComboBox(this); m_fileSelectionComboBox->updateComboBox(m_fileSelectionModel); QObject::connect(m_fileSelectionComboBox, SIGNAL(fileSelected(CaretDataFile*)), this, SLOT(borderMultiStructureFileSelected(CaretDataFile*))); QHBoxLayout* multiLayout = new QHBoxLayout(); multiLayout->addWidget(fileSelectionLabel); multiLayout->addWidget(m_fileSelectionComboBox->getWidget()); multiLayout->addStretch(); m_gridLayout = new QGridLayout(); WuQtUtilities::setLayoutSpacingAndMargins(m_gridLayout, 3, 3); m_gridLayout->setColumnStretch(0, 0); m_gridLayout->setColumnStretch(1, 100); int rowIndex = 0; m_gridLayout->addWidget(new QLabel("Structures"), rowIndex, 0, Qt::AlignHCenter); m_gridLayout->addWidget(new QLabel("New Single-Structure Border Files"), rowIndex, 1, Qt::AlignHCenter); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addLayout(multiLayout); layout->addWidget(WuQtUtilities::createHorizontalLineWidget()); layout->addLayout(m_gridLayout); layout->addStretch(); setCentralWidget(widget, WuQDialog::SCROLL_AREA_AS_NEEDED); m_dialogIsBeingCreatedFlag = false; CaretDataFile* firstFile = m_fileSelectionModel->getSelectedFile(); if (firstFile != NULL) { borderMultiStructureFileSelected(firstFile); } } /** * Destructor. */ BorderFileSplitDialog::~BorderFileSplitDialog() { } /** * Called when a multi-structure border file is selected. */ void BorderFileSplitDialog::borderMultiStructureFileSelected(CaretDataFile* caretDataFile) { if (m_dialogIsBeingCreatedFlag) { return; } AString pathName; AString fileNameNoExt; AString fileExtension; std::vector structures; if (caretDataFile != NULL) { BorderFile* borderFile = dynamic_cast(caretDataFile); CaretAssert(borderFile); structures = borderFile->getAllBorderStructures(); FileInformation fileInfo(caretDataFile->getFileName()); fileInfo.getFileComponents(pathName, fileNameNoExt, fileExtension); } const int32_t numStructures = static_cast(structures.size()); for (int32_t i = 0; i < numStructures; i++) { QPushButton* pushButton = NULL; QLineEdit* lineEdit = NULL; if (i < static_cast(m_structureRows.size())) { CaretAssertVectorIndex(m_structureRows, i); pushButton = m_structureRows[i].m_fileNamePushButton; lineEdit = m_structureRows[i].m_fileNameLineEdit; if (m_structureRows[i].m_fileNamePushButton->isHidden()) { pushButton->setVisible(true); lineEdit->setVisible(true); } } else { const int MINIMUM_LINE_EDIT_WIDTH = 400; pushButton = new QPushButton(); QObject::connect(pushButton, SIGNAL(clicked()), m_fileNameToolButtonSignalMapper, SLOT(map())); m_fileNameToolButtonSignalMapper->setMapping(pushButton, i); lineEdit = new QLineEdit(); lineEdit->setMinimumWidth(MINIMUM_LINE_EDIT_WIDTH); const int rowIndex = m_gridLayout->rowCount(); m_gridLayout->addWidget(pushButton, rowIndex, 0); m_gridLayout->addWidget(lineEdit, rowIndex, 1); StructureRow structureRow; structureRow.m_fileNamePushButton = pushButton; structureRow.m_fileNameLineEdit = lineEdit; m_structureRows.push_back(structureRow); } CaretAssertVectorIndex(m_structureRows, i); CaretAssert(pushButton); CaretAssert(lineEdit); CaretAssertVectorIndex(structures, i); m_structureRows[i].m_structure = structures[i]; pushButton->setText(StructureEnum::toGuiName(structures[i]) + "..."); AString singleStructureFileName; if ( ! pathName.isEmpty()) { singleStructureFileName += (pathName + "/"); } singleStructureFileName += fileNameNoExt; singleStructureFileName += ("_" + StructureEnum::toGuiName(structures[i])); singleStructureFileName += ("." + fileExtension); lineEdit->setText(singleStructureFileName); lineEdit->end(false); } const int32_t numRows = static_cast(m_structureRows.size()); for (int32_t i = numStructures; i < numRows; i++) { m_structureRows[i].m_fileNamePushButton->hide(); m_structureRows[i].m_fileNameLineEdit->hide(); } } /** * Called when a file name tool button is clicked. Allows user to set * name of new border file with file selection dialog. * * @param buttonIndex * Index of button that was clicked. */ void BorderFileSplitDialog::fileNameToolButtonClicked(int buttonIndex) { CaretAssertVectorIndex(m_structureRows, buttonIndex); QLineEdit* lineEdit = m_structureRows[buttonIndex].m_fileNameLineEdit; AString newBorderFileName = CaretFileDialog::getSaveFileNameDialog(DataFileTypeEnum::BORDER, this, "Choose Border File Name", lineEdit->text().trimmed()); if ( ! newBorderFileName.isEmpty()) { lineEdit->setText(newBorderFileName); lineEdit->end(false); } } /** * Called when the OK button is clicked. */ void BorderFileSplitDialog::okButtonClicked() { const BorderFile* borderFile = m_fileSelectionComboBox->getSelectionModel()->getSelectedFileOfType(); if (borderFile == NULL) { WuQMessageBox::errorOk(this, "No border file is selected."); return; } std::map singleStructureFileNames; const int32_t numSingleStructureFiles = static_cast(m_structureRows.size()); for (int32_t i = 0; i < numSingleStructureFiles; i++) { if (m_structureRows[i].m_fileNameLineEdit->isVisible()) { singleStructureFileNames.insert(std::make_pair(m_structureRows[i].m_structure, m_structureRows[i].m_fileNameLineEdit->text().trimmed())); } } if (singleStructureFileNames.empty()) { WuQMessageBox::errorOk(this, "Border file contains no structures."); return; } std::map structureNumberOfNodes; Brain* brain = GuiManager::get()->getBrain(); const int32_t numStructures = brain->getNumberOfBrainStructures(); for (int32_t iStruct = 0; iStruct < numStructures; iStruct++) { const BrainStructure* bs = brain->getBrainStructure(iStruct); structureNumberOfNodes.insert(std::make_pair(bs->getStructure(), bs->getNumberOfNodes())); } std::vector singleStructureBorderFiles; AString errorMessage; if (borderFile->splitIntoSingleStructureFiles(singleStructureFileNames, structureNumberOfNodes, singleStructureBorderFiles, errorMessage)) { for (std::vector::iterator iter = singleStructureBorderFiles.begin(); iter != singleStructureBorderFiles.end(); iter++) { EventManager::get()->sendEvent(EventDataFileAdd(*iter).getPointer()); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); WuQMessageBox::informationOk(this, ("New border file(s) were created but not saved. " "Use File Menu->Save/Manage Files to save these new files.")); } else { WuQMessageBox::errorOk(this, errorMessage); return; } WuQDialog::okButtonClicked(); } connectome-workbench-1.4.2/src/GuiQt/BorderFileSplitDialog.h000066400000000000000000000052301360521144700237750ustar00rootroot00000000000000#ifndef __BORDER_FILE_SPLIT_DIALOG_H__ #define __BORDER_FILE_SPLIT_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretPointer.h" #include "StructureEnum.h" #include "WuQDialogModal.h" class QGridLayout; class QLineEdit; class QPushButton; class QSignalMapper; namespace caret { class CaretDataFile; class CaretDataFileSelectionComboBox; class CaretDataFileSelectionModel; class BorderFileSplitDialog : public WuQDialogModal { Q_OBJECT public: BorderFileSplitDialog(QWidget* parent = 0); virtual ~BorderFileSplitDialog(); // ADD_NEW_METHODS_HERE protected: virtual void okButtonClicked(); private slots: void fileNameToolButtonClicked(int); void borderMultiStructureFileSelected(CaretDataFile* caretDataFile); private: BorderFileSplitDialog(const BorderFileSplitDialog&); BorderFileSplitDialog& operator=(const BorderFileSplitDialog&); QGridLayout* m_gridLayout; /* Use CaretPointer so that the file selection model gets destroyed */ CaretPointer m_fileSelectionModel; CaretDataFileSelectionComboBox* m_fileSelectionComboBox; struct StructureRow { QPushButton* m_fileNamePushButton; QLineEdit* m_fileNameLineEdit; StructureEnum::Enum m_structure; }; std::vector m_structureRows; QSignalMapper* m_fileNameToolButtonSignalMapper; bool m_dialogIsBeingCreatedFlag; // ADD_NEW_MEMBERS_HERE }; #ifdef __BORDER_FILE_SPLIT_DIALOG_DECLARE__ // #endif // __BORDER_FILE_SPLIT_DIALOG_DECLARE__ } // namespace #endif //__BORDER_FILE_SPLIT_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/BorderOptimizeDialog.cxx000066400000000000000000001511611360521144700242620ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __BORDER_OPTIMIZE_DIALOG_DECLARE__ #include "BorderOptimizeDialog.h" #undef __BORDER_OPTIMIZE_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include #include "Border.h" #include "BorderFile.h" #include "Brain.h" #include "BrainStructure.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretDataFileSelectionComboBox.h" #include "CaretDataFileSelectionModel.h" #include "CaretFileDialog.h" #include "CaretMappableDataFile.h" #include "CaretMappableDataFileAndMapSelectionModel.h" #include "CaretMappableDataFileAndMapSelectorObject.h" #include "CursorDisplayScoped.h" #include "EventBrowserTabGet.h" #include "EventDataFileAdd.h" #include "EventManager.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUpdateInformationWindows.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "MetricFile.h" #include "OverlaySet.h" #include "ProgressReportingDialog.h" #include "Surface.h" #include "SurfaceSelectionModel.h" #include "SurfaceSelectionViewController.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::BorderOptimizeDialog * \brief Border Optimize Dialog. * \ingroup GuiQt */ static const int STRETCH_NONE = 0; static const int STRETCH_MAX = 100; static const bool DATA_FILES_IN_SCROLL_BARS = false; /** * Constructor. * * @param parent * Parent of the dialog. */ BorderOptimizeDialog::BorderOptimizeDialog(QWidget* parent) : WuQDialogModal("Border Optimize", parent), m_surface(NULL), m_borderEnclosingROI(NULL), m_borderPairFileSelectionModel(NULL), m_surfaceSelectionStructure(StructureEnum::INVALID), m_surfaceSelectionModel(NULL), m_vertexAreasMetricFileSelectionModel(NULL), m_browserTabIndex(-1), m_upsamplingSurfaceSelectionModel(NULL), m_upsamplingSurfaceStructure(StructureEnum::INVALID) { m_objectNamePrefix + "BorderOptimizeDialog"; m_optimizeDataFileTypes.push_back(DataFileTypeEnum::CONNECTIVITY_DENSE); m_optimizeDataFileTypes.push_back(DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR); m_optimizeDataFileTypes.push_back(DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES); m_optimizeDataFileTypes.push_back(DataFileTypeEnum::METRIC); QWidget* dialogWidget = new QWidget(); QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); dialogLayout->addWidget(createBorderSelectionWidget(), STRETCH_NONE); if (DATA_FILES_IN_SCROLL_BARS) { dialogLayout->addWidget(createDataFilesWidget(), STRETCH_MAX); } else { dialogLayout->addWidget(createDataFilesWidget(), STRETCH_MAX); } dialogLayout->addWidget(createSurfaceSelectionWidget(), STRETCH_NONE); dialogLayout->addWidget(createVertexAreasMetricWidget(), STRETCH_NONE); dialogLayout->addWidget(createSphericalUpsamplingWidget(), STRETCH_NONE); dialogLayout->addWidget(createSavingWidget(), STRETCH_NONE); QWidget* optionsWidget = createOptionsWidget(); if (optionsWidget != NULL) { dialogLayout->addWidget(optionsWidget, STRETCH_NONE); } if (DATA_FILES_IN_SCROLL_BARS) { dialogLayout->addStretch(); setCentralWidget(dialogWidget, SCROLL_AREA_NEVER); } else { setCentralWidget(dialogWidget, SCROLL_AREA_AS_NEEDED_VERT_NO_HORIZ); } if (DATA_FILES_IN_SCROLL_BARS) { if (m_defaultDataFilesWidgetSize.width() > 300) { QSize defaultSize = sizeHint(); defaultSize.setWidth(m_defaultDataFilesWidgetSize.width() + 100); setSizeOfDialogWhenDisplayed(defaultSize); } } m_dialogWidget = dialogWidget; // if ( ! DATA_FILES_IN_SCROLL_BARS) { // setSizePolicy(sizePolicy().horizontalPolicy(), // QSizePolicy::Fixed); // } } /** * Destructor. */ BorderOptimizeDialog::~BorderOptimizeDialog() { if (m_surfaceSelectionModel != NULL) { delete m_surfaceSelectionModel; } if (m_vertexAreasMetricFileSelectionModel != NULL) { delete m_vertexAreasMetricFileSelectionModel; } if (m_borderPairFileSelectionModel != NULL) { delete m_borderPairFileSelectionModel; } if (m_upsamplingSurfaceSelectionModel != NULL) { delete m_upsamplingSurfaceSelectionModel; } } /** * Update the content of the dialog. * * @param browserTabIndex * Index of browser tab in which borders are drawn. * @param surface * Surface on which borders are drawn. * @param bordersInsideROI * Map where value is border and key is number of border * points inside the ROI * @param borderEnclosingROI * Border that encloses the region of interest * @param nodesInsideROI * Nodes inside the region of interest. */ void BorderOptimizeDialog::updateDialog(const int32_t browserTabIndex, Surface* surface, std::vector >& bordersInsideROI, Border* borderEnclosingROI, std::vector& nodesInsideROI) { CaretAssert(surface); CaretAssert(borderEnclosingROI); m_browserTabIndex = browserTabIndex; m_surface = surface; m_borderEnclosingROI = borderEnclosingROI; m_nodesInsideROI = nodesInsideROI; m_borderPointsInsideROICount.clear(); m_bordersInsideROI.clear(); for (std::vector >::reverse_iterator bi = bordersInsideROI.rbegin(); bi != bordersInsideROI.rend(); bi++) { m_borderPointsInsideROICount.push_back(bi->first); m_bordersInsideROI.push_back(bi->second); } /* * Update surface selection. * Will need to recreate model if the structure has changed. */ const StructureEnum::Enum structure = m_surface->getStructure(); if (m_surfaceSelectionModel != NULL) { if (structure != m_surfaceSelectionStructure) { delete m_surfaceSelectionModel; m_surfaceSelectionModel = NULL; m_surfaceSelectionStructure = StructureEnum::INVALID; } } if (m_surfaceSelectionModel == NULL) { m_surfaceSelectionStructure = structure; std::vector allSurfaceTypes; SurfaceTypeEnum::getAllEnums(allSurfaceTypes); m_surfaceSelectionModel = new SurfaceSelectionModel(m_surfaceSelectionStructure, allSurfaceTypes); BrainStructure* bs = GuiManager::get()->getBrain()->getBrainStructure(m_surfaceSelectionStructure, false); if (bs != NULL) { Surface* surface = bs->getPrimaryAnatomicalSurface(); if (surface != NULL) { m_surfaceSelectionModel->updateModel(); m_surfaceSelectionModel->setSurface(const_cast(surface)); } } } else { m_surfaceSelectionModel->updateModel(); } if (m_surfaceSelectionModel != NULL) { m_surfaceSelectionControl->updateControl(m_surfaceSelectionModel); m_surfaceSelectionControl->getWidget()->setEnabled(true); } else { m_surfaceSelectionControl->getWidget()->setEnabled(false); } Surface* defaultSphericalSurface = NULL; if (m_upsamplingSurfaceSelectionModel != NULL) { defaultSphericalSurface = m_upsamplingSurfaceSelectionModel->getSurface(); if (structure != m_upsamplingSurfaceStructure) { delete m_upsamplingSurfaceSelectionModel; m_upsamplingSurfaceSelectionModel = NULL; m_upsamplingSurfaceStructure = StructureEnum::INVALID; } } if (m_upsamplingSurfaceSelectionModel == NULL) { m_upsamplingSurfaceStructure = structure; std::vector sphericalSurfaceTypes; sphericalSurfaceTypes.push_back(SurfaceTypeEnum::SPHERICAL); m_upsamplingSurfaceSelectionModel = new SurfaceSelectionModel(m_upsamplingSurfaceStructure, sphericalSurfaceTypes); m_upsamplingResolutionSpinBox->setValue(0); } if (defaultSphericalSurface != NULL) { m_upsamplingSurfaceSelectionModel->setSurface(defaultSphericalSurface); } m_upsamplingSurfaceSelectionModel->updateModel(); m_upsamplingSurfaceSelectionControl->updateControl(m_upsamplingSurfaceSelectionModel); if (m_upsamplingResolutionSpinBox->value() <= 0) { Surface* surface = m_upsamplingSurfaceSelectionModel->getSurface(); if (surface != NULL) { m_upsamplingResolutionSpinBox->setValue(surface->getNumberOfNodes() * 4); } } /* * Update metric selection model * Will need to recreate if the structure has changed. */ if (m_vertexAreasMetricFileSelectionModel != NULL) { if (structure != m_vertexAreasMetricFileSelectionModel->getStructure()) { delete m_vertexAreasMetricFileSelectionModel; m_vertexAreasMetricFileSelectionModel = NULL; } } if (m_vertexAreasMetricFileSelectionModel == NULL) { std::vector metricDataTypes; metricDataTypes.push_back(DataFileTypeEnum::METRIC); m_vertexAreasMetricFileSelectionModel = CaretDataFileSelectionModel::newInstanceForCaretDataFileTypesInStructure(m_surfaceSelectionStructure, metricDataTypes); m_vertexAreasMetricFileComboBox->updateComboBox(m_vertexAreasMetricFileSelectionModel); } if (m_vertexAreasMetricFileSelectionModel != NULL) { m_vertexAreasMetricFileComboBox->updateComboBox(m_vertexAreasMetricFileSelectionModel); } /* * Update border file selection but limit to border files that are the same structure * as the surface */ m_borderPairFileSelectionModel->setStructure(structure); m_borderPairFileSelectionComboBox->updateComboBox(m_borderPairFileSelectionModel); QString initialBaseName = ""; /* * Update borders inside ROI selections */ CaretAssert(m_bordersInsideROI.size() == m_borderPointsInsideROICount.size()); const int32_t NUM_ROWS = 2; const int32_t numberOfBorders = static_cast(m_bordersInsideROI.size()); for (int32_t i = 0; i < numberOfBorders; i++) { if (i >= static_cast(m_borderCheckBoxes.size())) { QCheckBox* cb = new QCheckBox(""); m_borderCheckBoxes.push_back(cb); /* * Use two rows and then wrap additional columns on right */ const int32_t row = (i % NUM_ROWS); const int32_t col = (i / NUM_ROWS); m_bordersInsideROIGridLayout->addWidget(cb, row, col); } CaretAssertVectorIndex(m_borderCheckBoxes, i); CaretAssertVectorIndex(m_bordersInsideROI, i); CaretAssertVectorIndex(m_borderPointsInsideROICount, i); if (m_borderCheckBoxes[i]->text() != m_bordersInsideROI[i]->getName()) { m_borderCheckBoxes[i]->blockSignals(true); m_borderCheckBoxes[i]->setChecked(true); m_borderCheckBoxes[i]->blockSignals(false); } // m_borderCheckBoxes[i]->setText(m_bordersInsideROI[i]->getName()); m_borderCheckBoxes[i]->setText(m_bordersInsideROI[i]->getName() + " (" + QString::number(m_borderPointsInsideROICount[i]) + ")"); m_borderCheckBoxes[i]->setVisible(true); if (i < 2) { if (initialBaseName != "") initialBaseName += "_"; initialBaseName += m_bordersInsideROI[i]->getName(); } } m_savingBaseNameLineEdit->setText(initialBaseName); /* * Remove border selections not needed. */ for (int32_t i = numberOfBorders; i < static_cast(m_borderCheckBoxes.size()); i++) { m_borderCheckBoxes[i]->setVisible(false); } /* * Update the data file selectors. */ for (std::vector::iterator fileIter = m_optimizeDataFileSelectors.begin(); fileIter != m_optimizeDataFileSelectors.end(); fileIter++) { BorderOptimizeDataFileSelector* selector = *fileIter; selector->updateFileData(); } m_dialogWidget->adjustSize(); } /** * Called when OK button is clicked. */ void BorderOptimizeDialog::okButtonClicked() { preserveDialogSizeAndPositionWhenReOpened(); AString errorMessage; m_selectedBorders.clear(); Surface* gradientComputationSurface = m_surfaceSelectionModel->getSurface(); if (gradientComputationSurface == NULL) { errorMessage.appendWithNewLine("Gradient Computation Surface is not valid."); } if (m_borderEnclosingROI != NULL) { if (m_borderEnclosingROI->getNumberOfPoints() < 3) { errorMessage.appendWithNewLine("Border named " + m_borderEnclosingROI->getName() + " enclosing region is invalid must contain at least three points"); } } else { errorMessage.appendWithNewLine("Border enclosing region is invalid."); } std::vector dataFileSelections; for (std::vector::iterator fileIter = m_optimizeDataFileSelectors.begin(); fileIter != m_optimizeDataFileSelectors.end(); fileIter++) { BorderOptimizeDataFileSelector* selector = *fileIter; CaretPointer fileInfo = selector->getSelections(); if (fileInfo != NULL) { dataFileSelections.push_back(*fileInfo); } } if (dataFileSelections.empty()) { errorMessage.appendWithNewLine("No optimization data files are selected."); } /* * "Pair" border file */ const BorderFile* pairBorderFile = m_borderPairFileSelectionModel->getSelectedFileOfType(); std::vector pairedBorders; /* * Get borders selected by the user. */ AString metricFileMapName; CaretAssert(m_bordersInsideROI.size() <= m_borderCheckBoxes.size()); const int32_t numBorderFileSelections = static_cast(m_bordersInsideROI.size()); for (int32_t iBorder = 0; iBorder < numBorderFileSelections; iBorder++) { if (m_borderCheckBoxes[iBorder]->isVisible()) { if (m_borderCheckBoxes[iBorder]->isChecked()) { CaretAssertVectorIndex(m_bordersInsideROI, iBorder); Border* border = m_bordersInsideROI[iBorder]; m_selectedBorders.push_back(border); metricFileMapName.append(border->getName() + " "); if (pairBorderFile != NULL) { if (pairBorderFile->containsBorder(border)) { pairedBorders.push_back(border); } } } } } const int32_t numPairedBorders = static_cast(pairedBorders.size()); if (m_selectedBorders.empty()) { errorMessage.appendWithNewLine("No optimization border files are selected."); } else if (m_borderPairCheckBox->isChecked()) { if (pairBorderFile == NULL) { errorMessage.appendWithNewLine("Border pair file selection is invalid."); } else if (numPairedBorders != 2) { errorMessage.appendWithNewLine("Two of the selected borders must be in the border pair file."); if (pairedBorders.empty()) { errorMessage.appendWithNewLine("None of the selected borders are in the border pair file."); } else { errorMessage.appendWithNewLine("There are " + AString::number(numPairedBorders) + " selected borders in the border pair file."); for (int32_t i = 0; i < numPairedBorders; i++) { CaretAssertVectorIndex(pairedBorders, i); errorMessage.appendWithNewLine(" " + pairedBorders[i]->getName()); } } } } Surface* upsamplingSphericalSurface = NULL; int32_t upsamplingResolution = 0; if (m_upsamplingGroupBox->isChecked()) { upsamplingSphericalSurface = m_upsamplingSurfaceSelectionModel->getSurface(); if (upsamplingSphericalSurface == NULL) { errorMessage.appendWithNewLine("Upsampling is selected but no spherical surface is available."); } upsamplingResolution = m_upsamplingResolutionSpinBox->value(); if (upsamplingResolution <= 0) { errorMessage.appendWithNewLine("Upsampling resolution is invalid."); } } const QString savingBaseName = m_savingBaseNameLineEdit->text().trimmed(); const QString savingDirectoryName = m_savingDirectoryLineEdit->text().trimmed(); if (m_savingGroupBox->isChecked()) { if (savingDirectoryName.isEmpty()) { errorMessage.appendWithNewLine("Save Results is selected and Saving Directory is empty."); } if (savingBaseName.isEmpty()) { errorMessage.appendWithNewLine("Save Results is selected and Saving Base Filename is empty."); } } if ( ! errorMessage.isEmpty()) { WuQMessageBox::errorOk(this, errorMessage); return; } if (m_borderPairCheckBox->isChecked()) { CaretAssertMessage((pairedBorders.size() == 2), "Must be exactly two borders in the border pair vector"); } else { pairedBorders.clear(); } ProgressReportingDialog progressDialog("Border Optimization", "", this); progressDialog.setMinimum(0); progressDialog.setValue(0); MetricFile* vertexAreasMetricFile = NULL; CaretDataFile* vertexAreaFile = m_vertexAreasMetricFileSelectionModel->getSelectedFile(); if (vertexAreaFile != NULL) { vertexAreasMetricFile = dynamic_cast(vertexAreaFile); } const float gradientFollowingStrength = m_gradientFollowingStrengthSpinBox->value(); CaretPointer resultsMetricFile; resultsMetricFile.grabNew(new MetricFile()); BorderOptimizeExecutor::InputData algInput(m_selectedBorders, pairedBorders, m_borderEnclosingROI, m_nodesInsideROI, gradientComputationSurface, dataFileSelections, vertexAreasMetricFile, gradientFollowingStrength, upsamplingSphericalSurface, upsamplingResolution, resultsMetricFile, m_savingGroupBox->isChecked(), savingDirectoryName, savingBaseName); /* * Run border optimization. */ AString statisticsInformation; const bool algSuccessFlag = BorderOptimizeExecutor::run(algInput, statisticsInformation, errorMessage); /* * The progress dialog normally closes on its own but * may fail to close if the algorithm fails due to * the 'progress value' not reaching 'progress maximum'. * This prevent the error dialog from being shown behind * the progress dialog. */ progressDialog.close(); if (algSuccessFlag) { AString infoMsg; if (m_outputGradientMapCheckBox->isChecked() && ! resultsMetricFile->isEmpty()) { resultsMetricFile->setStructure(gradientComputationSurface->getStructure()); resultsMetricFile->setMapName(0, metricFileMapName); PaletteColorMapping* pcm = resultsMetricFile->getMapPaletteColorMapping(0); pcm->setAutoScalePercentageNegativeMaximum(96.0); pcm->setAutoScalePercentageNegativeMinimum(4.0); pcm->setAutoScalePercentagePositiveMinimum(4.0); pcm->setAutoScalePercentagePositiveMaximum(96.0); pcm->setSelectedPaletteName("videen_style"); pcm->setDisplayNegativeDataFlag(false); pcm->setDisplayZeroDataFlag(false); pcm->setDisplayPositiveDataFlag(true); pcm->setInterpolatePaletteFlag(true); EventDataFileAdd addDataFile(resultsMetricFile.releasePointer()); EventManager::get()->sendEvent(addDataFile.getPointer()); infoMsg.appendWithNewLine("Border Optimization Gradient results in file " + resultsMetricFile->getFileNameNoPath() + " Map Name: " + metricFileMapName); if (m_browserTabIndex >= 0) { /* * Updating user interface will update content of overlay * so that metric file gets added. */ EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventBrowserTabGet browserTabEvent(m_browserTabIndex); EventManager::get()->sendEvent(browserTabEvent.getPointer()); BrowserTabContent* tabContent = browserTabEvent.getBrowserTab(); if (tabContent != NULL) { /* * Create a new overlay at the top */ OverlaySet* overlaySet = tabContent->getOverlaySet(); CaretAssert(overlaySet); overlaySet->insertOverlayAbove(0); /* * Load the gradient metric file into the top-most * (should be the new) overlay. */ Overlay* overlay = overlaySet->getPrimaryOverlay(); CaretAssert(overlay); overlay->setSelectionData(resultsMetricFile, 0); overlay->setEnabled(true); overlay->setMapYokingGroup(MapYokingGroupEnum::MAP_YOKING_GROUP_OFF); overlay->setOpacity(1.0); EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); } } } /* * Display the statistics information. */ if ( ! statisticsInformation.isEmpty()) { infoMsg.appendWithNewLine(""); infoMsg.appendWithNewLine(statisticsInformation); } infoMsg = infoMsg.replaceHtmlSpecialCharactersWithEscapeCharacters(); EventManager::get()->sendEvent(EventUpdateInformationWindows(infoMsg).getPointer()); /* * Success, allow dialog to close. */ WuQDialogModal::okButtonClicked(); return; } WuQMessageBox::errorOk(this, errorMessage); } /** * Called when cancel button clicked. */ void BorderOptimizeDialog::cancelButtonClicked() { preserveDialogSizeAndPositionWhenReOpened(); /* * Allow dialog to close. */ WuQDialogModal::cancelButtonClicked(); } /** * Make dialog appear in same place and size when repopened. */ void BorderOptimizeDialog::preserveDialogSizeAndPositionWhenReOpened() { setSaveWindowPositionForNextTime("BorderOptimizeDialog"); setSizeOfDialogWhenDisplayed(size()); } /** * Get borders that were selected by the user. * * @param selectedBordersOut * Output containing borders selected by the user. */ void BorderOptimizeDialog::getModifiedBorders(std::vector& modifiedBordersOut) const { modifiedBordersOut = m_selectedBorders; } /** * @return The border selection widget. */ QWidget* BorderOptimizeDialog::createBorderSelectionWidget() { m_borderPairCheckBox = new QCheckBox("Border Pair File"); m_borderPairCheckBox->setChecked(true); m_borderPairFileSelectionModel = CaretDataFileSelectionModel::newInstanceForCaretDataFileType(DataFileTypeEnum::BORDER); m_borderPairFileSelectionComboBox = new CaretDataFileSelectionComboBox(this); QHBoxLayout* borderPairLayout = new QHBoxLayout(); borderPairLayout->addWidget(m_borderPairCheckBox, 0); borderPairLayout->addWidget(m_borderPairFileSelectionComboBox->getWidget(), 100); QObject::connect(m_borderPairCheckBox, SIGNAL(clicked(bool)), m_borderPairFileSelectionComboBox->getWidget(), SLOT(setEnabled(bool))); m_borderPairFileSelectionComboBox->getWidget()->setEnabled(m_borderPairCheckBox->isChecked()); m_bordersInsideROIGridLayout = new QGridLayout(); m_bordersInsideROIGridLayout->setMargin(2); m_bordersInsideROIGridLayout->setHorizontalSpacing(25); m_bordersInsideROIGridLayout->setColumnStretch(100, 1000); // force widgets to left QAction* diableAllAction = new QAction("Disable All", this); QObject::connect(diableAllAction, SIGNAL(triggered(bool)), this, SLOT(bordersDisableAllSelected())); QToolButton* disableAllToolButton = new QToolButton(); disableAllToolButton->setDefaultAction(diableAllAction); QAction* enableAllAction = new QAction("Enable All", this); QObject::connect(enableAllAction, SIGNAL(triggered(bool)), this, SLOT(bordersEnableAllSelected())); QToolButton* enableAllToolButton = new QToolButton(); enableAllToolButton->setDefaultAction(enableAllAction); QHBoxLayout* buttonsLayout = new QHBoxLayout(); buttonsLayout->setMargin(2); buttonsLayout->addWidget(enableAllToolButton); buttonsLayout->addWidget(disableAllToolButton); buttonsLayout->addStretch(); QGroupBox* widget = new QGroupBox("Borders"); widget->setSizePolicy(widget->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); QVBoxLayout* layout = new QVBoxLayout(widget); layout->setMargin(2); layout->addLayout(borderPairLayout); layout->addLayout(m_bordersInsideROIGridLayout, STRETCH_NONE); layout->addLayout(buttonsLayout, STRETCH_NONE); return widget; } /** * Disable all borders. */ void BorderOptimizeDialog::bordersDisableAllSelected() { setAllBorderEnabledSelections(false); } /** * Enable all borders. */ void BorderOptimizeDialog::bordersEnableAllSelected() { setAllBorderEnabledSelections(true); } /** * Set the enable status of all borders to the given value. * * @param status * New status. */ void BorderOptimizeDialog::setAllBorderEnabledSelections(const bool status) { for (std::vector::iterator iter = m_borderCheckBoxes.begin(); iter != m_borderCheckBoxes.end(); iter++) { QCheckBox* cb = *iter; cb->setChecked(status); } } /** * @return The data files widget. */ QWidget* BorderOptimizeDialog::createDataFilesWidget() { QWidget* gridWidget = new QWidget(); if (DATA_FILES_IN_SCROLL_BARS) { gridWidget->setSizePolicy(gridWidget->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); } else { // gridWidget->setSizePolicy(gridWidget->sizePolicy().horizontalPolicy(), // QSizePolicy::Fixed); } m_borderOptimizeDataFileGridLayout = new QGridLayout(gridWidget); m_borderOptimizeDataFileGridLayout->setMargin(2); std::vector optimizeMapFiles; GuiManager::get()->getBrain()->getAllMappableDataFileWithDataFileTypes(m_optimizeDataFileTypes, optimizeMapFiles); const int32_t numberOfMapFiles = static_cast(optimizeMapFiles.size()); // const int32_t minimumDataFilesToShow = 10; // const int32_t numberOfFilesToShow = std::max(minimumDataFilesToShow, // numberOfMapFiles); const int32_t numberOfFilesToShow = 3; for (int32_t i = 0; i < numberOfFilesToShow; i++) { CaretMappableDataFile* mapFile = NULL; if (i < numberOfMapFiles) { CaretAssertVectorIndex(optimizeMapFiles, i); mapFile = optimizeMapFiles[i]; } addDataFileRow(mapFile); } QWidget* widget = gridWidget; if (DATA_FILES_IN_SCROLL_BARS) { QScrollArea* scrollArea = new QScrollArea(); scrollArea->setWidget(gridWidget); scrollArea->setWidgetResizable(true); scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); scrollArea->setSizePolicy(gridWidget->sizePolicy().horizontalPolicy(), QSizePolicy::Preferred); widget = scrollArea; } else { widget->setSizePolicy(widget->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); } QAction* addRowAction = new QAction("Add New Data File Row", this); QObject::connect(addRowAction, SIGNAL(triggered(bool)), this, SLOT(addDataFileRowToolButtonClicked())); QToolButton* addRowToolButton = new QToolButton(); addRowToolButton->setDefaultAction(addRowAction); QAction* diableAllAction = new QAction("Disable All", this); QObject::connect(diableAllAction, SIGNAL(triggered(bool)), this, SLOT(dataFilesDisableAllSelected())); QToolButton* disableAllToolButton = new QToolButton(); disableAllToolButton->setDefaultAction(diableAllAction); QAction* enableAllAction = new QAction("Enable All", this); QObject::connect(enableAllAction, SIGNAL(triggered(bool)), this, SLOT(dataFilesEnableAllSelected())); QToolButton* enableAllToolButton = new QToolButton(); enableAllToolButton->setDefaultAction(enableAllAction); QHBoxLayout* buttonsLayout = new QHBoxLayout(); buttonsLayout->setMargin(2); buttonsLayout->addWidget(addRowToolButton); buttonsLayout->addWidget(enableAllToolButton); buttonsLayout->addWidget(disableAllToolButton); buttonsLayout->addStretch(); QGroupBox* groupBox = new QGroupBox("Data Files"); if ( ! DATA_FILES_IN_SCROLL_BARS) { // groupBox->setSizePolicy(groupBox->sizePolicy().horizontalPolicy(), // QSizePolicy::Minimum); } QVBoxLayout* groupBoxLayout = new QVBoxLayout(groupBox); groupBoxLayout->setMargin(2); if (DATA_FILES_IN_SCROLL_BARS) { groupBox->setMinimumHeight(300); groupBoxLayout->addWidget(widget, STRETCH_NONE); } else { groupBoxLayout->addWidget(widget, STRETCH_NONE); // STRETCH_MAX); } groupBoxLayout->addLayout(buttonsLayout, STRETCH_NONE); m_defaultDataFilesWidgetSize = gridWidget->sizeHint(); if ( ! DATA_FILES_IN_SCROLL_BARS) { groupBox->setSizePolicy(groupBox->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); //groupBoxLayout->addStretch(); } return groupBox; } /** * Add a data file row * * @param mapFile * If not NULL, the file selector is set to this file. */ void BorderOptimizeDialog::addDataFileRow(CaretMappableDataFile* mapFile) { const int32_t index = static_cast(m_optimizeDataFileSelectors.size()); BorderOptimizeDataFileSelector* selector = new BorderOptimizeDataFileSelector(index, m_optimizeDataFileTypes, mapFile, m_borderOptimizeDataFileGridLayout, this); selector->setSelected(true); m_optimizeDataFileSelectors.push_back(selector); } /** * Called when data file's Add Row button is clicked. */ void BorderOptimizeDialog::addDataFileRowToolButtonClicked() { addDataFileRow(NULL); } /** * Disable all borders. */ void BorderOptimizeDialog::dataFilesDisableAllSelected() { setAllDataFileEnabledSelections(false); } /** * Enable all borders. */ void BorderOptimizeDialog::dataFilesEnableAllSelected() { setAllDataFileEnabledSelections(true); } void BorderOptimizeDialog::saveBrowseButtonClicked() { QString path = CaretFileDialog::getExistingDirectoryDialog(); if (path != "") m_savingDirectoryLineEdit->setText(path); } /** * Set the enable status of all borders to the given value. * * @param status * New status. */ void BorderOptimizeDialog::setAllDataFileEnabledSelections(const bool status) { for (std::vector::iterator iter = m_optimizeDataFileSelectors.begin(); iter != m_optimizeDataFileSelectors.end(); iter++) { BorderOptimizeDataFileSelector* dfs = *iter; dfs->m_selectionCheckBox->setChecked(status); } } /** * @return The metric vertex areas widget. */ QWidget* BorderOptimizeDialog::createVertexAreasMetricWidget() { m_vertexAreasMetricFileComboBox = new CaretDataFileSelectionComboBox(this); QGroupBox* widget = new QGroupBox("Vertex Areas Metric File"); widget->setSizePolicy(widget->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); QVBoxLayout* layout = new QVBoxLayout(widget); layout->setMargin(2); layout->addWidget(m_vertexAreasMetricFileComboBox->getWidget()); return widget; } /** * @return The options widget. */ QWidget* BorderOptimizeDialog::createOptionsWidget() { m_keepRegionBorderCheckBox = new QCheckBox("Keep Boundary Border"); m_keepRegionBorderCheckBox->setChecked(true); m_outputGradientMapCheckBox = new QCheckBox("Output Gradient as Map"); m_outputGradientMapCheckBox->setChecked(true); QLabel* gradientLabel = new QLabel("Graident Following Strength"); m_gradientFollowingStrengthSpinBox = new QDoubleSpinBox(); m_gradientFollowingStrengthSpinBox->setRange(0.0, 1.0e6); m_gradientFollowingStrengthSpinBox->setDecimals(2); m_gradientFollowingStrengthSpinBox->setSingleStep(1.0); m_gradientFollowingStrengthSpinBox->setValue(5); QHBoxLayout* gradientLayout = new QHBoxLayout(); gradientLayout->addWidget(gradientLabel); gradientLayout->addWidget(m_gradientFollowingStrengthSpinBox); gradientLayout->addStretch(); QGroupBox* widget = new QGroupBox("Options"); widget->setSizePolicy(widget->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); QVBoxLayout* layout = new QVBoxLayout(widget); layout->setMargin(2); layout->addWidget(m_keepRegionBorderCheckBox); layout->addWidget(m_outputGradientMapCheckBox); layout->addLayout(gradientLayout); return widget; } /** * @return Return keep boundary border selection status. */ bool BorderOptimizeDialog::isKeepBoundaryBorderSelected() const { return m_keepRegionBorderCheckBox->isChecked(); } /** * @return The options widget. */ QWidget* BorderOptimizeDialog::createSurfaceSelectionWidget() { m_surfaceSelectionControl = new SurfaceSelectionViewController(this, (m_objectNamePrefix + ":SurfaceSelectionComboBox"), "border sampling"); QObject::connect(m_surfaceSelectionControl, SIGNAL(surfaceSelected(Surface*)), this, SLOT(gradientComputatonSurfaceSelected(Surface*))); QGroupBox* widget = new QGroupBox("Gradient Computation Surface"); widget->setSizePolicy(widget->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); QVBoxLayout* layout = new QVBoxLayout(widget); layout->setMargin(2); layout->addWidget(m_surfaceSelectionControl->getWidget()); return widget; } /** * @return The spherical upsampling widget. */ QWidget* BorderOptimizeDialog::createSphericalUpsamplingWidget() { QLabel* surfaceLabel = new QLabel("Current Sphere"); m_upsamplingSurfaceSelectionControl = new SurfaceSelectionViewController(this, (m_objectNamePrefix + ":UpSamplingSurfaceSelection"), "border upsampling"); QLabel* resolutionLabel = new QLabel("Upsampling Resolution"); m_upsamplingResolutionSpinBox = new QSpinBox(); m_upsamplingResolutionSpinBox->setRange(0, std::numeric_limits::max()); m_upsamplingResolutionSpinBox->setSingleStep(1); m_upsamplingResolutionSpinBox->setToolTip("Number of vertices to use when making the upsampling sphere"); m_upsamplingGroupBox = new QGroupBox(" Upsampling"); m_upsamplingGroupBox->setSizePolicy(m_upsamplingGroupBox->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); m_upsamplingGroupBox->setCheckable(true); m_upsamplingGroupBox->setChecked(true); QGridLayout* layout = new QGridLayout(m_upsamplingGroupBox); layout->setMargin(2); layout->setColumnStretch(0, 0); layout->setColumnStretch(1, 100); int row = 0; layout->addWidget(surfaceLabel, row, 0); layout->addWidget(m_upsamplingSurfaceSelectionControl->getWidget(), row, 1); row++; layout->addWidget(resolutionLabel, row, 0); layout->addWidget(m_upsamplingResolutionSpinBox, row, 1, Qt::AlignLeft); return m_upsamplingGroupBox; } QWidget* BorderOptimizeDialog::createSavingWidget() { m_savingGroupBox = new QGroupBox(" Save results"); m_savingGroupBox->setSizePolicy(m_savingGroupBox->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); m_savingGroupBox->setCheckable(true); m_savingGroupBox->setChecked(true); QGridLayout* layout = new QGridLayout(m_savingGroupBox); layout->setMargin(2); layout->setColumnStretch(0, 0);//label layout->setColumnStretch(1, 100);//line edit layout->setColumnStretch(2, 0);//button or extended line edit layout->addWidget(new QLabel("Base Filename"), 0, 0); m_savingBaseNameLineEdit = new QLineEdit(); layout->addWidget(m_savingBaseNameLineEdit, 0, 1, 1, -1);//extend to end of row layout->addWidget(new QLabel("Path"), 1, 0); m_savingDirectoryLineEdit = new QLineEdit(); layout->addWidget(m_savingDirectoryLineEdit, 1, 1); QPushButton* browseButton = new QPushButton("Browse..."); QObject::connect(browseButton, SIGNAL(clicked()), this, SLOT(saveBrowseButtonClicked())); layout->addWidget(browseButton, 1, 2); return m_savingGroupBox; } /** * Called when gradient computational surface is selected * * @param surface * Surface that was selected. */ void BorderOptimizeDialog::gradientComputatonSurfaceSelected(Surface* surface) { if (m_surfaceSelectionModel != NULL) { m_surfaceSelectionModel->setSurface(surface); } } /** * Constructor. * * @param optimizeDataFileTypes * File types for selection * @param defaultFile * The default file (may be NULL) * @param gridLayout * Layout for the widgets. * @param parent * Parent of the selector. */ BorderOptimizeDataFileSelector::BorderOptimizeDataFileSelector(const int32_t itemIndex, const std::vector& optimizeDataFileTypes, CaretMappableDataFile* defaultFile, QGridLayout* gridLayout, QObject* parent) : QObject(parent) { m_mapFileAndIndexSelectorObject = new CaretMappableDataFileAndMapSelectorObject(optimizeDataFileTypes, CaretMappableDataFileAndMapSelectorObject::OPTION_SHOW_MAP_INDEX_SPIN_BOX, this); QObject::connect(m_mapFileAndIndexSelectorObject, SIGNAL(selectionWasPerformed()), this, SLOT(mapFileSelectionChanged())); QWidget* mapFileComboBox; QWidget* mapIndexSpinBox; QWidget* mapNameComboBox; m_mapFileAndIndexSelectorObject->getWidgetsForAddingToLayout(mapFileComboBox, mapIndexSpinBox, mapNameComboBox); CaretAssert(mapFileComboBox); CaretAssert(mapIndexSpinBox); CaretAssert(mapNameComboBox); mapIndexSpinBox->setFixedWidth(80); m_allMapsCheckBox = new QCheckBox(""); QObject::connect(m_allMapsCheckBox, SIGNAL(toggled(bool)), this, SLOT(allMapsCheckBoxToggled(bool))); m_invertGradientCheckBox = new QCheckBox(""); m_skipGradientCheckBox = new QCheckBox(""); m_selectionCheckBox = new QCheckBox(""); m_selectionCheckBox->setChecked(true); QObject::connect(m_selectionCheckBox, SIGNAL(toggled(bool)), this, SLOT(selectionCheckBoxToggled(bool))); m_exclusionDistanceSpinBox = new QDoubleSpinBox(); m_exclusionDistanceSpinBox->setRange(0, 1.0e6); m_exclusionDistanceSpinBox->setDecimals(2); m_exclusionDistanceSpinBox->setSingleStep(1.0); m_exclusionDistanceSpinBox->setValue(2); m_smoothingSpinBox = new QDoubleSpinBox(); m_smoothingSpinBox->setRange(0.0, 1.0e6); m_smoothingSpinBox->setDecimals(2); m_smoothingSpinBox->setSingleStep(1.0); m_smoothingSpinBox->setValue(1.0); m_weightSpinBox = new QDoubleSpinBox(); m_weightSpinBox->setRange(0.0, 1.0); m_weightSpinBox->setDecimals(2); m_weightSpinBox->setSingleStep(0.01); m_weightSpinBox->setValue(0.7); int32_t columnCount = 0; const int32_t COLUMN_SELECT = columnCount++; const int32_t COLUMN_EXCLUDE = columnCount++; const int32_t COLUMN_SMOOTH = columnCount++; const int32_t COLUMN_WEIGHT = columnCount++; const int32_t COLUMN_INVERT = columnCount++; const int32_t COLUMN_SKIP = columnCount++; const int32_t COLUMN_ALL_MAP = columnCount++; const int32_t COLUMN_MAP_INDEX = columnCount++; const int32_t COLUMN_MAP_NAME = columnCount++; if (itemIndex == 0) { const int32_t row = gridLayout->rowCount(); gridLayout->addWidget(new QLabel("Enable"), row, COLUMN_SELECT, 2, 1, Qt::AlignCenter); gridLayout->addWidget(new QLabel("Exclusion"), row, COLUMN_EXCLUDE, Qt::AlignCenter); gridLayout->addWidget(new QLabel("Radius (mm)"), row+1, COLUMN_EXCLUDE, Qt::AlignCenter); gridLayout->addWidget(new QLabel("Smoothing"), row, COLUMN_SMOOTH, Qt::AlignCenter); gridLayout->addWidget(new QLabel("Sigma (mm)"), row+1, COLUMN_SMOOTH, Qt::AlignCenter); gridLayout->addWidget(new QLabel("Weight"), row, COLUMN_WEIGHT, 2, 1, Qt::AlignCenter); gridLayout->addWidget(new QLabel("Invert"), row, COLUMN_INVERT, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Gradient"), row + 1, COLUMN_INVERT, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Skip"), row, COLUMN_SKIP, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Gradient"), row + 1, COLUMN_SKIP, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("All"), row, COLUMN_ALL_MAP, Qt::AlignCenter); gridLayout->addWidget(new QLabel("Maps"), row + 1, COLUMN_ALL_MAP, Qt::AlignCenter); gridLayout->addWidget(new QLabel("File/Map"), row, COLUMN_MAP_INDEX, 2, 2, Qt::AlignCenter); gridLayout->setVerticalSpacing(2); gridLayout->setColumnStretch(COLUMN_SELECT, 0); gridLayout->setColumnStretch(COLUMN_EXCLUDE, 0); gridLayout->setColumnStretch(COLUMN_SMOOTH, 0); gridLayout->setColumnStretch(COLUMN_WEIGHT, 0); gridLayout->setColumnStretch(COLUMN_INVERT, 0); gridLayout->setColumnStretch(COLUMN_SKIP, 0); gridLayout->setColumnStretch(COLUMN_ALL_MAP, 0); gridLayout->setColumnStretch(COLUMN_MAP_INDEX, 0); gridLayout->setColumnStretch(COLUMN_MAP_NAME, 100); } int row = gridLayout->rowCount(); gridLayout->addWidget(m_selectionCheckBox, row, COLUMN_SELECT, 2, 1, Qt::AlignCenter); gridLayout->addWidget(m_exclusionDistanceSpinBox, row, COLUMN_EXCLUDE, 2, 1, Qt::AlignCenter); gridLayout->addWidget(m_smoothingSpinBox, row, COLUMN_SMOOTH, 2, 1, Qt::AlignCenter); gridLayout->addWidget(m_weightSpinBox, row, COLUMN_WEIGHT, 2, 1, Qt::AlignCenter); gridLayout->addWidget(m_invertGradientCheckBox, row, COLUMN_INVERT, 2, 1, Qt::AlignCenter); gridLayout->addWidget(m_skipGradientCheckBox, row, COLUMN_SKIP, 2, 1, Qt::AlignCenter); gridLayout->addWidget(m_allMapsCheckBox, row, COLUMN_ALL_MAP, 2, 1, Qt::AlignCenter); gridLayout->addWidget(mapFileComboBox, row, COLUMN_MAP_INDEX, 1, 2); row++; gridLayout->addWidget(mapIndexSpinBox, row, COLUMN_MAP_INDEX); gridLayout->addWidget(mapNameComboBox, row, COLUMN_MAP_NAME); CaretMappableDataFileAndMapSelectionModel* model = m_mapFileAndIndexSelectorObject->getModel(); if (defaultFile != NULL) { model->setSelectedFile(defaultFile); } else { m_selectionCheckBox->blockSignals(true); m_selectionCheckBox->setChecked(false); m_selectionCheckBox->blockSignals(false); } m_mapFileAndIndexSelectorObject->updateFileAndMapSelector(model); updateFileData(); } /* * Destructor. */ BorderOptimizeDataFileSelector::~BorderOptimizeDataFileSelector() { } /** * Update the file data. */ void BorderOptimizeDataFileSelector::updateFileData() { const bool widgetsEnabled = m_selectionCheckBox->isChecked(); m_allMapsCheckBox->setEnabled(widgetsEnabled); m_exclusionDistanceSpinBox->setEnabled(widgetsEnabled); m_invertGradientCheckBox->setEnabled(widgetsEnabled); m_skipGradientCheckBox->setEnabled(widgetsEnabled); m_smoothingSpinBox->setEnabled(widgetsEnabled); m_weightSpinBox->setEnabled(widgetsEnabled); CaretMappableDataFileAndMapSelectionModel* model = m_mapFileAndIndexSelectorObject->getModel(); m_mapFileAndIndexSelectorObject->updateFileAndMapSelector(model); m_mapFileAndIndexSelectorObject->setEnabled(widgetsEnabled); if (widgetsEnabled) { const CaretMappableDataFile* mapFile = model->getSelectedFile(); const bool denseFileFlag = ((mapFile != NULL) ? (mapFile->getDataFileType() == DataFileTypeEnum::CONNECTIVITY_DENSE) : false); if (denseFileFlag) { m_allMapsCheckBox->setChecked(false); m_allMapsCheckBox->setEnabled(false); m_exclusionDistanceSpinBox->setEnabled(true); m_skipGradientCheckBox->setChecked(false); m_skipGradientCheckBox->setEnabled(false); } else { m_exclusionDistanceSpinBox->setEnabled(false); } m_allMapsCheckBox->setEnabled( ! denseFileFlag); } } /** * Set the selection status. * * @param selectedStatus * New selection status. */ void BorderOptimizeDataFileSelector::setSelected(const bool selectedStatus) { m_selectionCheckBox->setChecked(selectedStatus); } /** * Gets called when the map file selection changes. */ void BorderOptimizeDataFileSelector::mapFileSelectionChanged() { updateFileData(); } /** * @return Selections made for data file. */ CaretPointer BorderOptimizeDataFileSelector::getSelections() const { CaretMappableDataFileAndMapSelectionModel* model = m_mapFileAndIndexSelectorObject->getModel(); CaretMappableDataFile* mapFile = model->getSelectedFile(); const int32_t mapIndex = model->getSelectedMapIndex(); CaretPointer dataOut(NULL); if (mapFile != NULL) { if ((mapIndex >= 0) && (mapIndex < mapFile->getNumberOfMaps())) { if (m_selectionCheckBox->isChecked()) { dataOut.grabNew(new BorderOptimizeExecutor::DataFileInfo(mapFile, mapIndex, m_allMapsCheckBox->isChecked(), m_smoothingSpinBox->value(), m_weightSpinBox->value(), m_invertGradientCheckBox->isChecked(), m_skipGradientCheckBox->isChecked(), m_exclusionDistanceSpinBox->value())); } } } return dataOut; } /* * Called when selection checkbox changes. * @param checked * New status for selection check box. */ void BorderOptimizeDataFileSelector::selectionCheckBoxToggled(bool /*checked*/) { updateFileData(); } /* * Called when all maps check box is toggled. * * @param checked * New status for selection check box. */ void BorderOptimizeDataFileSelector::allMapsCheckBoxToggled(bool /*checked*/) { updateFileData(); } connectome-workbench-1.4.2/src/GuiQt/BorderOptimizeDialog.h000066400000000000000000000157001360521144700237050ustar00rootroot00000000000000#ifndef __BORDER_OPTIMIZE_DIALOG_H__ #define __BORDER_OPTIMIZE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "BorderOptimizeExecutor.h" #include "DataFileTypeEnum.h" #include "StructureEnum.h" #include "WuQDialogModal.h" class QCheckBox; class QDoubleSpinBox; class QGridLayout; class QGroupBox; class QLineEdit; class QSpinBox; class QVBoxLayout; namespace caret { class Border; class BorderOptimizeDataFileSelector; class CaretDataFileSelectionComboBox; class CaretDataFileSelectionModel; class CaretMappableDataFile; class CaretMappableDataFileAndMapSelectorObject; class Surface; class SurfaceSelectionModel; class SurfaceSelectionViewController; class BorderOptimizeDialog : public WuQDialogModal { Q_OBJECT public: BorderOptimizeDialog(QWidget* parent); virtual ~BorderOptimizeDialog(); void getModifiedBorders(std::vector& modifiedBordersOut) const; bool isKeepBoundaryBorderSelected() const; void updateDialog(const int32_t browserTabIndex, Surface* surface, std::vector >& bordersInsideROI, Border* borderEnclosingROI, std::vector& nodesInsideROI); protected: virtual void okButtonClicked(); virtual void cancelButtonClicked(); private slots: void addDataFileRowToolButtonClicked(); void gradientComputatonSurfaceSelected(Surface* surface); void bordersDisableAllSelected(); void bordersEnableAllSelected(); void dataFilesDisableAllSelected(); void dataFilesEnableAllSelected(); void saveBrowseButtonClicked(); private: BorderOptimizeDialog(const BorderOptimizeDialog&); BorderOptimizeDialog& operator=(const BorderOptimizeDialog&); QWidget* createBorderSelectionWidget(); QWidget* createDataFilesWidget(); QWidget* createVertexAreasMetricWidget(); QWidget* createOptionsWidget(); QWidget* createSurfaceSelectionWidget(); QWidget* createSphericalUpsamplingWidget(); QWidget* createSavingWidget(); void addDataFileRow(CaretMappableDataFile* mapFile); void setAllBorderEnabledSelections(const bool status); void setAllDataFileEnabledSelections(const bool status); void preserveDialogSizeAndPositionWhenReOpened(); QString m_objectNamePrefix; QWidget* m_dialogWidget; Surface* m_surface; std::vector m_bordersInsideROI; std::vector m_borderPointsInsideROICount; std::vector m_selectedBorders; QGridLayout* m_bordersInsideROIGridLayout; Border* m_borderEnclosingROI; std::vector m_nodesInsideROI; std::vector m_optimizeDataFileSelectors; CaretDataFileSelectionComboBox* m_borderPairFileSelectionComboBox; CaretDataFileSelectionModel* m_borderPairFileSelectionModel; QCheckBox* m_borderPairCheckBox; std::vector m_borderCheckBoxes; std::vector m_optimizeDataFileTypes; QGridLayout* m_borderOptimizeDataFileGridLayout; StructureEnum::Enum m_surfaceSelectionStructure; SurfaceSelectionModel* m_surfaceSelectionModel; SurfaceSelectionViewController* m_surfaceSelectionControl; CaretDataFileSelectionComboBox* m_vertexAreasMetricFileComboBox; CaretDataFileSelectionModel* m_vertexAreasMetricFileSelectionModel; QDoubleSpinBox* m_gradientFollowingStrengthSpinBox; int32_t m_browserTabIndex; QCheckBox* m_keepRegionBorderCheckBox; QCheckBox* m_outputGradientMapCheckBox; QSize m_defaultDataFilesWidgetSize; QGroupBox* m_upsamplingGroupBox; SurfaceSelectionModel* m_upsamplingSurfaceSelectionModel; StructureEnum::Enum m_upsamplingSurfaceStructure; SurfaceSelectionViewController* m_upsamplingSurfaceSelectionControl; QSpinBox* m_upsamplingResolutionSpinBox; QGroupBox* m_savingGroupBox; QLineEdit* m_savingBaseNameLineEdit; QLineEdit* m_savingDirectoryLineEdit; }; class BorderOptimizeDataFileSelector : public QObject { Q_OBJECT public: BorderOptimizeDataFileSelector(const int32_t itemIndex, const std::vector& optimizeDataFileTypes, CaretMappableDataFile* defaultFile, QGridLayout* gridLayout, QObject* parent); ~BorderOptimizeDataFileSelector(); void updateFileData(); CaretPointer getSelections() const; void setSelected(const bool selectedStatus); private slots: void selectionCheckBoxToggled(bool checked); void allMapsCheckBoxToggled(bool checked); void mapFileSelectionChanged(); public: CaretMappableDataFileAndMapSelectorObject* m_mapFileAndIndexSelectorObject; QCheckBox* m_allMapsCheckBox; QDoubleSpinBox* m_exclusionDistanceSpinBox; QCheckBox* m_invertGradientCheckBox; QCheckBox* m_skipGradientCheckBox; QCheckBox* m_selectionCheckBox; QDoubleSpinBox* m_smoothingSpinBox; QDoubleSpinBox* m_weightSpinBox; }; #ifdef __BORDER_OPTIMIZE_DIALOG_DECLARE__ #endif // __BORDER_OPTIMIZE_DIALOG_DECLARE__ } // namespace #endif //__BORDER_OPTIMIZE_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/BorderOptimizeExecutor.cxx000066400000000000000000001614651360521144700246710ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BORDER_OPTIMIZE_EXECUTOR_DECLARE__ #include "BorderOptimizeExecutor.h" #undef __BORDER_OPTIMIZE_EXECUTOR_DECLARE__ #include "Border.h" #include "CaretAssert.h" #include "Surface.h" #include "AlgorithmBorderResample.h" #include "AlgorithmBorderToVertices.h" #include "AlgorithmCiftiCorrelationGradient.h" #include "AlgorithmCiftiRestrictDenseMap.h" #include "AlgorithmCiftiSeparate.h" #include "AlgorithmMetricDilate.h" #include "AlgorithmMetricGradient.h" #include "AlgorithmMetricFindClusters.h" #include "AlgorithmNodesInsideBorder.h" #include "AlgorithmSurfaceCreateSphere.h" #include "AlgorithmSurfaceResample.h" #include "BorderFile.h" #include "CaretLogger.h" #include "CaretOMP.h" #include "CiftiFile.h" #include "CiftiMappableDataFile.h" #include "EventProgressUpdate.h" #include "FileInformation.h" #include "GeodesicHelper.h" #include "MathFunctions.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "SurfaceProjectedItem.h" #include "SurfaceProjectionBarycentric.h" #include "SurfaceResamplingHelper.h" #include "TextFile.h" #include "TopologyHelper.h" #include using namespace caret; using namespace std; /** * \class caret::BorderOptimizeExecutor * \brief * \ingroup GuiQt * * */ /** * Constructor. */ BorderOptimizeExecutor::BorderOptimizeExecutor() : CaretObject() { } /** * Destructor. */ BorderOptimizeExecutor::~BorderOptimizeExecutor() { } namespace { void doCombination(const MetricFile& gradient, const vector& roiNodes, const bool& invert, const float& mapStrength, vector& combinedGradData) { const float* gradVals = gradient.getValuePointerForColumn(0); float myMin = 0.0f, myMax = 0.0f; bool first = true; int numSelected = (int)roiNodes.size(); for (int i = 0; i < numSelected; ++i)//for normalizing, gather min/max { float tempVal = gradVals[roiNodes[i]]; if (MathFunctions::isNumeric(tempVal)) { if (first) { first = false; myMin = tempVal; myMax = tempVal; } else { if (tempVal < myMin) myMin = tempVal; if (tempVal > myMax) myMax = tempVal; } } } if (myMin == myMax)//if no contrast, map it all to (post-inversion) minimum - also trips if no numeric data { if (invert) { myMin -= 1.0f; } else { myMax += 1.0f; } } float myRange = myMax - myMin; for (int i = 0; i < numSelected; ++i)//for normalizing, gather min/max { float tempVal = gradVals[roiNodes[i]]; if (MathFunctions::isNumeric(tempVal)) { float toCombine; if (invert) { toCombine = (myMax - tempVal) / myRange; } else { toCombine = (tempVal - myMin) / myRange; } combinedGradData[roiNodes[i]] *= 1.0f + mapStrength * (toCombine - 1.0f);//equals toCombine * mapStrength + 1.0f - mapStrength } else { combinedGradData[roiNodes[i]] *= 1.0f - mapStrength; } } } bool extractGradientData(const CaretMappableDataFile* dataFile, const int32_t& mapIndex, SurfaceFile* surface, const MetricFile* gradRoi, const float& smoothing, const MetricFile* correctedAreasMetric, MetricFile& gradientOut, const bool& skipGradient, const float& excludeDist) { int numNodes = surface->getNumberOfNodes(); MetricFile tempData, tempRoi; const MetricFile* useData = &tempData, *useRoi = gradRoi; switch (dataFile->getDataFileType()) { case DataFileTypeEnum::METRIC: { const MetricFile* metricFile = dynamic_cast(dataFile); CaretAssert(metricFile != NULL); CaretAssert(metricFile->getNumberOfNodes() == numNodes); useData = metricFile; break; } case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: { tempData.setNumberOfNodesAndColumns(numNodes, 1); tempData.setStructure(surface->getStructure()); tempRoi.setNumberOfNodesAndColumns(numNodes, 1); const CiftiMappableDataFile* ciftiMappableFile = dynamic_cast(dataFile); CaretAssert(ciftiMappableFile != NULL); CaretAssert(ciftiMappableFile->getMappingSurfaceNumberOfNodes(surface->getStructure()) == numNodes); vector surfData, ciftiRoi; bool result = ciftiMappableFile->getMapDataForSurface(mapIndex, surface->getStructure(), surfData, &ciftiRoi); CaretAssert(result); if (!result) { CaretLogSevere("failed to get map data for map " + AString::number(mapIndex) + " of data file of type " + DataFileTypeEnum::toName(dataFile->getDataFileType())); return false; } tempData.setValuesForColumn(0, surfData.data()); vector maskedROI(numNodes); const float* gradRoiData = gradRoi->getValuePointerForColumn(0); for (int i = 0; i < numNodes; ++i) { if (gradRoiData[i] > 0.0f) { maskedROI[i] = ciftiRoi[i]; } else { maskedROI[i] = 0.0f; } } tempRoi.setValuesForColumn(0, maskedROI.data()); useRoi = &tempRoi; break; } case DataFileTypeEnum::CONNECTIVITY_DENSE: { const CiftiMappableDataFile* ciftiMappableFile = dynamic_cast(dataFile); CaretAssert(ciftiMappableFile != NULL); CaretAssert(ciftiMappableFile->getMappingSurfaceNumberOfNodes(surface->getStructure()) == numNodes); const CiftiFile* dataCifti = ciftiMappableFile->getCiftiFile(); const MetricFile* leftRoi = NULL, *rightRoi = NULL, *cerebRoi = NULL; const MetricFile* leftCorrAreas = NULL, *rightCorrAreas = NULL, *cerebCorrAreas = NULL; SurfaceFile* leftSurf = NULL, *rightSurf = NULL, *cerebSurf = NULL; switch (surface->getStructure()) { case StructureEnum::CORTEX_LEFT: leftRoi = gradRoi; leftCorrAreas = correctedAreasMetric; leftSurf = surface; break; case StructureEnum::CORTEX_RIGHT: rightRoi = gradRoi; rightCorrAreas = correctedAreasMetric; rightSurf = surface; break; case StructureEnum::CEREBELLUM: cerebRoi = gradRoi; cerebCorrAreas = correctedAreasMetric; cerebSurf = surface; break; default: CaretAssert(false); break; } CiftiFile restrictCifti, corrGradCifti; AlgorithmCiftiRestrictDenseMap(NULL, dataCifti, CiftiXML::ALONG_COLUMN, &restrictCifti, leftRoi, rightRoi, cerebRoi, NULL); AlgorithmCiftiCorrelationGradient(NULL, &restrictCifti, &corrGradCifti, leftSurf, rightSurf, cerebSurf, leftCorrAreas, rightCorrAreas, cerebCorrAreas, smoothing, 0.0f, false, false, excludeDist, -1.0f); AlgorithmCiftiSeparate(NULL, &corrGradCifti, CiftiXML::ALONG_COLUMN, surface->getStructure(), &gradientOut); return true; } default: CaretLogWarning("ignoring map " + AString::number(mapIndex) + " of data file of type " + DataFileTypeEnum::toName(dataFile->getDataFileType())); return false; } if (skipGradient) { gradientOut.setNumberOfNodesAndColumns(numNodes, 1); gradientOut.setStructure(surface->getStructure()); gradientOut.setValuesForColumn(0, useData->getValuePointerForColumn(0)); } else { AlgorithmMetricGradient(NULL, surface, useData, &gradientOut, NULL, smoothing, useRoi, false, 0, correctedAreasMetric); } return true; } bool getStatisticsString(const CaretMappableDataFile* dataFile, const int32_t& mapIndex, const vector nodeLists[2], const SurfaceFile& surface, const MetricFile* correctedAreasMetric, const float& excludeDist, AString& statsOut) { vector tempStatsStore, roiData; StructureEnum::Enum structure = surface.getStructure(); int numNodes = surface.getNumberOfNodes(); const float* statsData = NULL; switch (dataFile->getDataFileType()) { case DataFileTypeEnum::METRIC: { const MetricFile* metricFile = dynamic_cast(dataFile); CaretAssert(metricFile != NULL); statsData = metricFile->getValuePointerForColumn(mapIndex); break; } case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: { const CiftiMappableDataFile* ciftiMappableFile = dynamic_cast(dataFile); CaretAssert(ciftiMappableFile != NULL); bool result = ciftiMappableFile->getMapDataForSurface(mapIndex, structure, tempStatsStore, &roiData); CaretAssert(result); if (!result) { CaretLogSevere("failed to get map data for map " + AString::number(mapIndex) + " of data file of type " + DataFileTypeEnum::toName(dataFile->getDataFileType())); return false; } statsData = tempStatsStore.data(); break; } case DataFileTypeEnum::CONNECTIVITY_DENSE: { const CiftiMappableDataFile* ciftiMappableFile = dynamic_cast(dataFile); CaretAssert(ciftiMappableFile != NULL); const CiftiFile* dataCifti = ciftiMappableFile->getCiftiFile(); const CiftiXML& myXML = dataCifti->getCiftiXML(); const CiftiBrainModelsMap& myDenseMap = myXML.getBrainModelsMap(CiftiXML::ALONG_ROW); CaretAssert(myDenseMap.hasSurfaceData(structure));//the GUI should filter by structure, right? int64_t rowLength = myXML.getDimensionLength(CiftiXML::ALONG_ROW); vector > data[2]; for (int i = 0; i < 2; ++i) { data[i].resize(nodeLists[i].size()); for (int j = 0; j < (int)nodeLists[i].size(); ++j) { int64_t index = myDenseMap.getIndexForNode(nodeLists[i][j], structure); if (index != -1)//roi can go outside the cifti ROI, ignore such vertices { data[i][j].resize(rowLength);//only allocate the ones inside the cifti ROI dataCifti->getRow(data[i][j].data(), index); } } } vector samples[2][2]; CaretPointer myGeoBase; if (correctedAreasMetric != NULL) { myGeoBase.grabNew(new GeodesicHelperBase(&surface, correctedAreasMetric->getValuePointerForColumn(0))); } for (int posSide = 0; posSide < 2; ++posSide) { int listSize = (int)nodeLists[posSide].size(); #pragma omp CARET_PAR { CaretPointer myGeoHelp; if (correctedAreasMetric != NULL) { myGeoHelp.grabNew(new GeodesicHelper(myGeoBase)); } else { myGeoHelp = surface.getGeodesicHelper(); } #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < listSize; ++i) { if (!data[posSide][i].empty()) { vector excludeNodes; vector excludeDists; myGeoHelp->getNodesToGeoDist(nodeLists[posSide][i], excludeDist, excludeNodes, excludeDists); vector excludeLookup(numNodes, 0); for (int j = 0; j < (int)excludeNodes.size(); ++j) { excludeLookup[excludeNodes[j]] = 1; } for (int side = 0; side < 2; ++side) { vector averagerow(rowLength, 0.0); int count = 0; for (int j = 0; j < (int)nodeLists[side].size(); ++j) { if (excludeLookup[nodeLists[side][j]] == 0 && !data[side][j].empty()) { ++count; float* dataRef = data[side][j].data(); for (int k = 0; k < rowLength; ++k) { averagerow[k] += dataRef[k]; } } } if (count != 0) { double accum1 = 0.0, accum2 = 0.0; for (int k = 0; k < rowLength; ++k) { averagerow[k] /= count; accum1 += averagerow[k]; accum2 += data[posSide][i][k]; } float mean1 = accum1 / rowLength, mean2 = accum2 / rowLength; accum1 = 0.0, accum2 = 0.0; double accum3 = 0.0; for (int k = 0; k < rowLength; ++k) { float val1 = averagerow[k] - mean1, val2 = data[posSide][i][k] - mean2; accum1 += val1 * val2; accum2 += val1 * val1; accum3 += val2 * val2; } double corrval = accum1 / sqrt(accum2 * accum3); if (corrval >= 0.999999) corrval = 0.999999;//prevent inf if (corrval <= -0.999999) corrval = -0.999999;//prevent -inf #pragma omp critical { samples[posSide][side].push_back(0.5f * log((1 + corrval)/(1 - corrval)));//fisher z transform } } } } } } } float tstats[2], cohen_ds[2], pvals[2]; for (int piece = 0; piece < 2; ++piece) { int count[2]; float mean[2], variance[2]; for (int posSide = 0; posSide < 2; ++posSide) { count[posSide] = (int)samples[posSide][piece].size(); if (count[posSide] < 2) return false; double accum = 0.0; for (int i = 0; i < count[posSide]; ++i) { accum += samples[posSide][piece][i]; } mean[posSide] = accum / count[posSide]; accum = 0.0; for (int i = 0; i < count[posSide]; ++i) { float tempf = samples[posSide][piece][i] - mean[posSide]; accum += tempf * tempf; } variance[posSide] = accum / (count[posSide] - 1); } tstats[piece] = (mean[0] - mean[1]) / sqrt(variance[0] / count[0] + variance[1] / count[1]);//welch's t-test cohen_ds[piece] = (mean[0] - mean[1]) / sqrt(((count[0] - 1) * variance[0] + (count[1] - 1) * variance[1]) / (count[0] + count[1] - 2)); pvals[piece] = 2.0f * MathFunctions::q_func(abs(tstats[piece]));//treat as 2-tailed z-stat, this isn't meant to be rigorous, and the t-test cdf is a pain } statsOut = "p1=" + AString::number(pvals[0], 'g', 3) + ", p2=" + AString::number(pvals[1], 'g', 3) + ", t1=" + AString::number(tstats[0], 'g', 3) + ", t2=" + AString::number(tstats[1], 'g', 3) + ", d1=" + AString::number(cohen_ds[0], 'g', 3) + ", d2=" + AString::number(cohen_ds[1], 'g', 3); return true; } default: CaretLogWarning("statistics: ignoring data file of type " + DataFileTypeEnum::toName(dataFile->getDataFileType())); return false; } float mean[2], variance[2]; int count[2] = {0, 0}; for (int piece = 0; piece < 2; ++piece) { double accum = 0.0; for (int i = 0; i < (int)nodeLists[piece].size(); ++i) { if (roiData.empty() || roiData[nodeLists[piece][i]] > 0.0f) { accum += statsData[nodeLists[piece][i]];//weight by vertex area? weighted welch's t-test, oh joy ++count[piece]; } } mean[piece] = accum / count[piece]; accum = 0.0; for (int i = 0; i < (int)nodeLists[piece].size(); ++i) { if (roiData.empty() || roiData[nodeLists[piece][i]] > 0.0f) { float tempf = (statsData[nodeLists[piece][i]] - mean[piece]); accum += tempf * tempf; } } variance[piece] = accum / (count[piece] - 1); } float tstat = (mean[0] - mean[1]) / sqrt(variance[0] / count[0] + variance[1] / count[1]);//welch's t-test float cohen_d = (mean[0] - mean[1]) / sqrt(((count[0] - 1) * variance[0] + (count[1] - 1) * variance[1]) / (count[0] + count[1] - 2)); float pval = 2.0f * MathFunctions::q_func(abs(tstat));//treat as 2-tailed z-stat, this isn't meant to be rigorous, and the t-test cdf is a pain statsOut = "p=" + AString::number(pval, 'g', 3) + ", t=" + AString::number(tstat, 'g', 3) + ", d=" + AString::number(cohen_d, 'g', 3); return true; } int getBorderPointNode(const Border* theBorder, const int& index) { CaretAssert(index >= 0 && index < theBorder->getNumberOfPoints()); const SurfaceProjectionBarycentric* thisBary = theBorder->getPoint(index)->getBarycentricProjection(); CaretAssert(thisBary != NULL && thisBary->isValid()); int thisNode = thisBary->getNodeWithLargestWeight(); CaretAssert(thisNode >= 0); return thisNode; } struct BorderRedrawInfo { int startpoint, endpoint; }; } /** * Run the border optimization algorithm. * * @param inputData * Input data for the algorithm. * @param statisticsInformationOut * Output containing statistics information. * @param errorMessageOut * Output containing error information when false returned. * @return * True if successful, else false. */ bool BorderOptimizeExecutor::run(const InputData& inputData, AString& statisticsInformationOut, AString& errorMessageOut) { AString stageString = "initializing"; try { statisticsInformationOut.clear(); errorMessageOut.clear(); printInputs(inputData); SurfaceFile* computeSurf = inputData.m_surface; const MetricFile* correctedAreasMetric = inputData.m_vertexAreasMetricFile; int32_t numNodes = computeSurf->getNumberOfNodes(); int numSelected = (int)inputData.m_nodesInsideROI.size(); if (numSelected < 1) { errorMessageOut = "no nodes selected"; return false; } vector roiData(numNodes, 0.0f); vector combinedGradData(numNodes, 0.0f); for (int i = 0; i < numSelected; ++i) { roiData[inputData.m_nodesInsideROI[i]] = 1.0f; combinedGradData[inputData.m_nodesInsideROI[i]] = 1.0f;//also initialize only the inside-roi parts of the gradient combining function, leaving the outside 0 } int numBorders = (int)inputData.m_borders.size(); vector myRedrawInfo(numBorders); const int PROGRESS_MAX = 100; const int SEGMENT_PROGRESS = 10; const int COMPUTE_PROGRESS = 55; const int HELPER_PROGRESS = 5; const int DRAW_PROGRESS = 10; const int STATISTICS_PROGRESS = 20; CaretAssert(SEGMENT_PROGRESS + COMPUTE_PROGRESS + HELPER_PROGRESS + DRAW_PROGRESS + STATISTICS_PROGRESS == PROGRESS_MAX); stageString = "border segment locating"; for (int i = 0; i < numBorders; ++i) {//find pieces of border to redraw, before doing gradient, so it can error early Border* thisBorder = inputData.m_borders[i]; EventProgressUpdate tempEvent(0, PROGRESS_MAX, (SEGMENT_PROGRESS * i) / numBorders, "finding in-roi segment of border '" + thisBorder->getName() + "'"); EventManager::get()->sendEvent(&tempEvent); if (tempEvent.isCancelled()) { errorMessageOut = "cancelled by user"; return false; } int numPoints = thisBorder->getNumberOfPoints(); int start, end; if (thisBorder->isClosed()) { if (numPoints < 3)//one outside, two inside will work { errorMessageOut = "Border '" + thisBorder->getName() + "' has too few points to adjust"; return false; } for (start = numPoints - 1; start >= 0; --start)//search backwards for a point outside the roi { if (!(roiData[getBorderPointNode(thisBorder, start)] > 0.0f)) break; } if (start == -1)//no points outside ROI { errorMessageOut = "Border '" + thisBorder->getName() + "' has no points outside the ROI"; return false; } int added; for (added = 1; added < numPoints; ++added)//search forward from it to find the point inside the roi - if the above loop had to loop, this will end on the first iteration { int pointIndex = (start + added) % numPoints;//closed border requires mod arithmetic if (roiData[getBorderPointNode(thisBorder, pointIndex)] > 0.0f) break; } if (added == numPoints)//no points inside ROI {//NOTE: if multipart borders are used, and passed borders don't check the parts for being in/out, then this name is not unique errorMessageOut = "Border '" + thisBorder->getName() + "' has no points inside the ROI"; return false; } start = (start + added) % numPoints; for (added = 1; added < numPoints; ++added) { int pointIndex = (start + added) % numPoints; if (!(roiData[getBorderPointNode(thisBorder, pointIndex)] > 0.0f)) break; } CaretAssert(added != numPoints);//we have points inside and outside roi, this search should have stopped end = (start + added - 1) % numPoints;//we will check this for being equal to start later, first check for multiple sections for (; added < numPoints; ++added) { int pointIndex = (start + added) % numPoints; if (roiData[getBorderPointNode(thisBorder, pointIndex)] > 0.0f) { errorMessageOut = "Border '" + thisBorder->getName() + "' has multiple sections inside the ROI"; return false; } } if (end == start) { errorMessageOut = "Border '" + thisBorder->getName() + "' has only one point inside the ROI"; return false; } if (getBorderPointNode(thisBorder, start) == getBorderPointNode(thisBorder, end)) { errorMessageOut = "Border '" + thisBorder->getName() + "' enters and exits the ROI too close to the same vertex"; return false; } } else {//open border if (numPoints < 2)//two, both inside, will work { errorMessageOut = "Border '" + thisBorder->getName() + "' has too few points to adjust"; return false; } for (start = 0; start < numPoints; ++start)//search for first point inside { if (roiData[getBorderPointNode(thisBorder, start)] > 0.0f) break; } if (start == numPoints) {//NOTE: if multipart borders are used, and passed borders don't check the parts for being in/out, then this name is not unique errorMessageOut = "Border '" + thisBorder->getName() + "' has no points inside the ROI"; return false; } for (end = start + 1; end < numPoints; ++end)//search for first point outside { if (!(roiData[getBorderPointNode(thisBorder, end)] > 0.0f)) break; } --end;//and subtract one to get inclusive range, also deals with == numPoints for (int check = end + 2; check < numPoints; ++check)//look for a second piece inside { if (roiData[getBorderPointNode(thisBorder, check)] > 0.0f) { errorMessageOut = "Border '" + thisBorder->getName() + "' has multiple sections inside the ROI"; return false; } } } myRedrawInfo[i].startpoint = start; myRedrawInfo[i].endpoint = end; } stageString = "data processing"; int numInputs = (int)inputData.m_dataFileInfo.size(); vector inputRoiData(numNodes, 0.0f); for (int i = 0; i < (int)inputData.m_nodesInsideROI.size(); ++i) { inputRoiData[inputData.m_nodesInsideROI[i]] = 1.0f; } MetricFile inputRoi, dilatedRoi; inputRoi.setNumberOfNodesAndColumns(numNodes, 1); inputRoi.setValuesForColumn(0, inputRoiData.data()); AlgorithmMetricDilate(NULL, &inputRoi, computeSurf, 0.0001f, &dilatedRoi);//dilate roi by 1 neighbor for (int i = 0; i < numInputs; ++i) { EventProgressUpdate tempEvent(0, PROGRESS_MAX, SEGMENT_PROGRESS + (COMPUTE_PROGRESS * i) / numInputs, "processing data file '" + inputData.m_dataFileInfo[i].m_mapFile->getFileNameNoPath() + "'"); EventManager::get()->sendEvent(&tempEvent); if (tempEvent.isCancelled()) { errorMessageOut = "cancelled by user"; return false; } MetricFile tempGradient; if (inputData.m_dataFileInfo[i].m_allMapsFlag) { for (int j = 0; j < inputData.m_dataFileInfo[i].m_mapFile->getNumberOfMaps(); ++j) { if (extractGradientData(inputData.m_dataFileInfo[i].m_mapFile, j, computeSurf, &dilatedRoi, inputData.m_dataFileInfo[i].m_smoothing, correctedAreasMetric, tempGradient, inputData.m_dataFileInfo[i].m_skipGradient, inputData.m_dataFileInfo[i].m_corrGradExcludeDist)) { doCombination(tempGradient, inputData.m_nodesInsideROI, inputData.m_dataFileInfo[i].m_invertGradientFlag, inputData.m_dataFileInfo[i].m_weight, combinedGradData); } } } else { if (extractGradientData(inputData.m_dataFileInfo[i].m_mapFile, inputData.m_dataFileInfo[i].m_mapIndex, computeSurf, &dilatedRoi, inputData.m_dataFileInfo[i].m_smoothing, correctedAreasMetric, tempGradient, inputData.m_dataFileInfo[i].m_skipGradient, inputData.m_dataFileInfo[i].m_corrGradExcludeDist)) { doCombination(tempGradient, inputData.m_nodesInsideROI, inputData.m_dataFileInfo[i].m_invertGradientFlag, inputData.m_dataFileInfo[i].m_weight, combinedGradData); } } } stageString = "border drawing"; if (inputData.m_combinedGradientDataOut != NULL) { inputData.m_combinedGradientDataOut->setNumberOfNodesAndColumns(numNodes, 1); inputData.m_combinedGradientDataOut->setStructure(computeSurf->getStructure()); inputData.m_combinedGradientDataOut->setValuesForColumn(0, combinedGradData.data()); } SurfaceFile* drawSurf = computeSurf, *origSphere = inputData.m_upsamplingSphericalSurface, highresSphere, highresMidthick; vector drawGrad = combinedGradData, drawRoi = roiData; vector origAreasStore, highresAreasStore; const float* origAreas = NULL; if (correctedAreasMetric != NULL) { origAreas = correctedAreasMetric->getValuePointerForColumn(0); } const float* drawAreas = origAreas; if (origSphere != NULL) { if (inputData.m_upsamplingSphericalSurface->getNumberOfNodes() >= inputData.m_upsamplingResolution) { errorMessageOut = "upsampling number of vertices must be greater than current vertex count"; return false; } AlgorithmSurfaceCreateSphere(NULL, inputData.m_upsamplingResolution, &highresSphere); int highresNumNodes = highresSphere.getNumberOfNodes(); highresSphere.setStructure(origSphere->getStructure()); AlgorithmSurfaceResample(NULL, computeSurf, origSphere, &highresSphere, SurfaceResamplingMethodEnum::BARYCENTRIC, &highresMidthick); if (origAreas == NULL) { computeSurf->computeNodeAreas(origAreasStore); origAreas = origAreasStore.data(); highresMidthick.computeNodeAreas(highresAreasStore); } else { vector origRatioStore(origAreas, origAreas + numNodes), highresRatioStore(highresNumNodes), wrongAreas, highresWrongAreas; computeSurf->computeNodeAreas(wrongAreas);//to get high res corrected areas, convert to expansion ratio, highresMidthick.computeNodeAreas(highresWrongAreas);//then resample and multiply by the high res surface areas for (int i = 0; i < numNodes; ++i) { origRatioStore[i] /= wrongAreas[i]; }//we don't have anything high res but the wrong areas yet, so use like area measures - expansion ratio should be fairly smooth anyway, so not as important SurfaceResamplingHelper initialUpsampler(SurfaceResamplingMethodEnum::ADAP_BARY_AREA, origSphere, &highresSphere, wrongAreas.data(), highresWrongAreas.data()); initialUpsampler.resampleNormal(origRatioStore.data(), highresRatioStore.data()); highresAreasStore.resize(highresNumNodes); for (int i = 0; i < highresNumNodes; ++i) { highresAreasStore[i] = highresRatioStore[i] * highresWrongAreas[i]; } } drawSurf = &highresMidthick; drawAreas = highresAreasStore.data(); drawGrad.resize(highresNumNodes); drawRoi.resize(highresNumNodes); SurfaceResamplingHelper finalUpsampler(SurfaceResamplingMethodEnum::ADAP_BARY_AREA, origSphere, &highresSphere, origAreas, highresAreasStore.data(), roiData.data()); finalUpsampler.resampleNormal(combinedGradData.data(), drawGrad.data()); finalUpsampler.getResampleValidROI(drawRoi.data()); } { EventProgressUpdate tempEvent(0, PROGRESS_MAX, SEGMENT_PROGRESS + COMPUTE_PROGRESS, "generating geodesic helper"); EventManager::get()->sendEvent(&tempEvent); if (tempEvent.isCancelled()) { errorMessageOut = "cancelled by user"; return false; } } CaretPointer myGeoHelp; CaretPointer myGeoBase; if (correctedAreasMetric != NULL) { myGeoBase.grabNew(new GeodesicHelperBase(drawSurf, drawAreas)); myGeoHelp.grabNew(new GeodesicHelper(myGeoBase)); } else { myGeoHelp = drawSurf->getGeodesicHelper(); } CaretPointer myTopoHelp = drawSurf->getTopologyHelper(); vector drawOrigBorders = inputData.m_borders; BorderFile highresOrigBorders; if (origSphere != NULL) {//first, copy all borders and resample to get endpoint positions on high res mesh, then draw new segments as borders and downsample just the segments BorderFile origBorders; for (int i = 0; i < numBorders; ++i) { origBorders.addBorder(new Border(*(inputData.m_borders[i]))); } AlgorithmBorderResample(NULL, &origBorders, origSphere, &highresSphere, &highresOrigBorders);//NOTE: this must keep each border and point intact and in the same order, just on the new sphere for (int i = 0; i < numBorders; ++i) { drawOrigBorders[i] = highresOrigBorders.getBorder(i); } } vector roiMinusTracesData = drawRoi; BorderFile redrawnSegments; for (int i = 0; i < numBorders; ++i) { EventProgressUpdate tempEvent(0, PROGRESS_MAX, SEGMENT_PROGRESS + COMPUTE_PROGRESS + HELPER_PROGRESS + (DRAW_PROGRESS * i) / numBorders, "redrawing segment of border '" + inputData.m_borders[i]->getName() + "'");//use non-resampled borders for name, just in case EventManager::get()->sendEvent(&tempEvent); if (tempEvent.isCancelled()) { errorMessageOut = "cancelled by user"; return false; } vector nodes; vector dists; myGeoHelp->getPathFollowingData(getBorderPointNode(drawOrigBorders[i], myRedrawInfo[i].startpoint), getBorderPointNode(drawOrigBorders[i], myRedrawInfo[i].endpoint), drawGrad.data(), nodes, dists, inputData.m_gradientFollowingStrength, drawRoi.data(), true, true); if (nodes.size() < 3)//require at least 1 surviving point after removing endpoints { errorMessageOut = "Unable to redraw border segment for border '" + inputData.m_borders[i]->getName() + "'"; return false; } CaretPointer redrawnSegment(new Border()); for (int j = 1; j < (int)nodes.size() - 1; ++j)//drop the closest node to the start and end points from the redrawn segment { const vector& nodeTiles = myTopoHelp->getNodeTiles(nodes[j]); CaretAssert(!nodeTiles.empty()); const int32_t* tileNodes = drawSurf->getTriangle(nodeTiles[0]); int whichNode; for (whichNode = 0; whichNode < 3; ++whichNode) { if (tileNodes[whichNode] == nodes[j]) break; } CaretAssert(whichNode < 3);//it should always find it float weights[3] = { 0.0f, 0.0f, 0.0f }; weights[whichNode] = 1.0f; SurfaceProjectedItem* myItem = new SurfaceProjectedItem(); myItem->getBarycentricProjection()->setTriangleNodes(tileNodes);//none of these should throw myItem->getBarycentricProjection()->setTriangleAreas(weights); myItem->getBarycentricProjection()->setValid(true); myItem->setStructure(computeSurf->getStructure()); redrawnSegment->addPoint(myItem); } redrawnSegments.addBorder(redrawnSegment.releasePointer()); int numOrigPoints = inputData.m_borders[i]->getNumberOfPoints(); Border fullRedrawn = *(drawOrigBorders[i]);//use the potentially upsampled version for the ROI splitting, but don't re-downsample it as the modified border on the current mesh fullRedrawn.removeAllPoints(); if (!(inputData.m_borders[i]->isClosed()))//if it is a closed border, start with the newly drawn section, for simplicity { for (int j = 0; j <= myRedrawInfo[i].startpoint; ++j)//include the original startpoint { fullRedrawn.addPoint(new SurfaceProjectedItem(*(drawOrigBorders[i]->getPoint(j)))); } } fullRedrawn.addPoints(redrawnSegment); if (inputData.m_borders[i]->isClosed()) {//mod arithmetic for closed borders int numKeep = ((numOrigPoints + myRedrawInfo[i].startpoint - myRedrawInfo[i].endpoint) % numOrigPoints) + 1;//inclusive for (int j = 0; j < numKeep; ++j) { fullRedrawn.addPoint(new SurfaceProjectedItem(*(drawOrigBorders[i]->getPoint((j + myRedrawInfo[i].endpoint) % numOrigPoints)))); } } else { for (int j = myRedrawInfo[i].endpoint; j < numOrigPoints; ++j)//include original endpoint { fullRedrawn.addPoint(new SurfaceProjectedItem(*(drawOrigBorders[i]->getPoint(j)))); } } MetricFile borderTrace; BorderFile tempBorderFile; tempBorderFile.addBorder(new Border(fullRedrawn));//because it takes ownership of a pointer AlgorithmBorderToVertices(NULL, drawSurf, &tempBorderFile, &borderTrace); const float* traceData = borderTrace.getValuePointerForColumn(0); int drawNumNodes = drawSurf->getNumberOfNodes(); for (int j = 0; j < drawNumNodes; ++j) { if (traceData[j] > 0.0f) { roiMinusTracesData[j] = 0.0f; } } } BorderFile* segmentsToUse = &redrawnSegments; BorderFile downsampledSegments; if (origSphere != NULL) { AlgorithmBorderResample(NULL, &redrawnSegments, &highresSphere, origSphere, &downsampledSegments); segmentsToUse = &downsampledSegments; } vector modifiedBorders(numBorders);//modify all without replacing so we can error before changing any for (int i = 0; i < numBorders; ++i) { Border& modifiedBorder = modifiedBorders[i]; modifiedBorder = *(inputData.m_borders[i]); int numOrigPoints = inputData.m_borders[i]->getNumberOfPoints(); modifiedBorder.removeAllPoints();//keep name, color, class, etc if (!(inputData.m_borders[i]->isClosed()))//if it is a closed border, start with the newly drawn section, for simplicity { for (int j = 0; j <= myRedrawInfo[i].startpoint; ++j)//include the original startpoint { modifiedBorder.addPoint(new SurfaceProjectedItem(*(inputData.m_borders[i]->getPoint(j)))); } } modifiedBorder.addPoints(segmentsToUse->getBorder(i)); if (inputData.m_borders[i]->isClosed()) {//mod arithmetic for closed borders int numKeep = ((numOrigPoints + myRedrawInfo[i].startpoint - myRedrawInfo[i].endpoint) % numOrigPoints) + 1;//inclusive for (int j = 0; j < numKeep; ++j) { modifiedBorder.addPoint(new SurfaceProjectedItem(*(inputData.m_borders[i]->getPoint((j + myRedrawInfo[i].endpoint) % numOrigPoints)))); } } else { for (int j = myRedrawInfo[i].endpoint; j < numOrigPoints; ++j)//include original endpoint { modifiedBorder.addPoint(new SurfaceProjectedItem(*(inputData.m_borders[i]->getPoint(j)))); } } } stageString = "roi splitting"; MetricFile roiMinusBorderTraces, roiMetric, drawAreasMetric; roiMinusBorderTraces.setNumberOfNodesAndColumns(roiMinusTracesData.size(), 1); roiMinusBorderTraces.setValuesForColumn(0, roiMinusTracesData.data()); roiMetric.setNumberOfNodesAndColumns(drawRoi.size(), 1); roiMetric.setValuesForColumn(0, drawRoi.data()); drawAreasMetric.setNumberOfNodesAndColumns(drawSurf->getNumberOfNodes(), 1); drawAreasMetric.setValuesForColumn(0, drawAreas); MetricFile clustersMetric; int endVal = 0; AlgorithmMetricFindClusters(NULL, drawSurf, &roiMinusBorderTraces, 0.5f, 10.0f, &clustersMetric, false, &roiMetric, &drawAreasMetric, 0, 1, &endVal); if (endVal != 3) { statisticsInformationOut = AString::number(endVal - 1) + " cluster(s) found after splitting the roi with the redrawn borders, skipping statistics"; } else { const float* clusterData = clustersMetric.getValuePointerForColumn(0); vector downsampledClusters; if (origSphere != NULL) { SurfaceResamplingHelper downsampler(SurfaceResamplingMethodEnum::ADAP_BARY_AREA, &highresSphere, origSphere, highresAreasStore.data(), origAreas, drawRoi.data()); vector highresData(highresSphere.getNumberOfNodes()), downsamledData(numNodes); const float* highresClusters = clustersMetric.getValuePointerForColumn(0); for (int i = 0; i < (int)highresData.size(); ++i) { highresData[i] = floor(highresClusters[i] + 0.5f); } downsampler.resamplePopular(highresData.data(), downsamledData.data()); downsampledClusters.resize(numNodes); for (int i = 0; i < (int)downsamledData.size(); ++i) { downsampledClusters[i] = downsamledData[i]; } clusterData = downsampledClusters.data(); } stageString = "statistics"; vector nodeLists[2]; for (int i = 0; i < numNodes; ++i) { int label = (int)floor(clusterData[i] + 0.5f); CaretAssert(label < 3); if (label > 0) nodeLists[label - 1].push_back(i); } vector orderedNodeLists[2]; if (nodeLists[0].size() >= nodeLists[1].size()) { orderedNodeLists[0] = nodeLists[0]; orderedNodeLists[1] = nodeLists[1]; } else { orderedNodeLists[0] = nodeLists[1]; orderedNodeLists[1] = nodeLists[0]; } if (inputData.m_borderPair.size() == 2) { vector insideBorderNodes; AlgorithmNodesInsideBorder(NULL, computeSurf, inputData.m_borderPair[0], false, insideBorderNodes); vector insideLookup(numNodes, 0); for (int i = 0; i < (int)insideBorderNodes.size(); ++i) { insideLookup[insideBorderNodes[i]] = 1; } int counts[2] = {0, 0}; for (int whichList = 0; whichList < 2; ++whichList) { for (int i = 0; i < (int)orderedNodeLists[whichList].size(); ++i) { if (insideLookup[orderedNodeLists[whichList][i]] != 0) { ++counts[whichList]; } } } if (counts[0] >= counts[1]) { statisticsInformationOut += inputData.m_borderPair[0]->getName() + " n=" + AString::number(orderedNodeLists[0].size()) + ", " + inputData.m_borderPair[1]->getName() + " n=" + AString::number(orderedNodeLists[1].size()) + "\n\n"; } else { statisticsInformationOut += inputData.m_borderPair[1]->getName() + " n=" + AString::number(orderedNodeLists[0].size()) + ", " + inputData.m_borderPair[0]->getName() + " n=" + AString::number(orderedNodeLists[1].size()) + "\n\n"; } if (orderedNodeLists[0].size() < 2 || orderedNodeLists[1].size() < 2) { statisticsInformationOut += "roi pieces are too small for statistics"; } else { for (int i = 0; i < numInputs; ++i) { EventProgressUpdate tempEvent(0, PROGRESS_MAX, SEGMENT_PROGRESS + COMPUTE_PROGRESS + HELPER_PROGRESS + DRAW_PROGRESS + (STATISTICS_PROGRESS * i) / numInputs, "computing statistics on file '" + inputData.m_dataFileInfo[i].m_mapFile->getFileNameNoPath() + "'"); EventManager::get()->sendEvent(&tempEvent); if (tempEvent.isCancelled()) { errorMessageOut = "cancelled by user"; return false; } if (inputData.m_dataFileInfo[i].m_allMapsFlag) { for (int j = 0; j < inputData.m_dataFileInfo[i].m_mapFile->getNumberOfMaps(); ++j) { AString statsOut; if(getStatisticsString(inputData.m_dataFileInfo[i].m_mapFile, j, orderedNodeLists, *computeSurf, correctedAreasMetric, inputData.m_dataFileInfo[i].m_corrGradExcludeDist, statsOut)) { statisticsInformationOut += statsOut + ": " + inputData.m_dataFileInfo[i].m_mapFile->getMapName(inputData.m_dataFileInfo[i].m_mapIndex) + ", " + inputData.m_dataFileInfo[i].m_mapFile->getFileNameNoPath() + ", " + FileInformation(inputData.m_dataFileInfo[i].m_mapFile->getFileName()).getLastDirectory() + "\n"; } } statisticsInformationOut += "\n"; } else { AString statsOut; if(getStatisticsString(inputData.m_dataFileInfo[i].m_mapFile, inputData.m_dataFileInfo[i].m_mapIndex, orderedNodeLists, *computeSurf, correctedAreasMetric, inputData.m_dataFileInfo[i].m_corrGradExcludeDist, statsOut)) { statisticsInformationOut += statsOut + ": " + inputData.m_dataFileInfo[i].m_mapFile->getMapName(inputData.m_dataFileInfo[i].m_mapIndex) + ", " + inputData.m_dataFileInfo[i].m_mapFile->getFileNameNoPath() + ", " + FileInformation(inputData.m_dataFileInfo[i].m_mapFile->getFileName()).getLastDirectory() + "\n\n"; } } } } } } stageString = "border replacing"; for (int i = 0; i < numBorders; ++i)//now replace the borders with the modified ones { inputData.m_borders[i]->replacePointsWithUndoSaving(&modifiedBorders[i]); } if (inputData.m_saveResults) { saveResults(inputData, statisticsInformationOut); } /* * Modifying a border: * * (1) Make a copy of the border * * Border* borderCopy = new Border(*border) * * (2) Modify the 'copied' border * * (3) When modification is complete, calling this method * will first make an 'undo' copy of 'border' that is stored * inside of border and then replace the points in 'border' * with those from 'borderCopy'. This will allow the * user to press the Border ToolBar's 'Undo Finish' button * if the changes are not acceptable. * * border->replacePointsWithUndoSaving(borderCopy) */ } catch (CaretException& e) {//all exceptions are errors errorMessageOut = "Caught exception during " + stageString + " stage: " + e.whatString(); return false; } return true; } void BorderOptimizeExecutor::saveResults(const BorderOptimizeExecutor::InputData& inputData, const AString& statisticsInformation) { AString completeBase = FileInformation(inputData.m_savingPath, inputData.m_savingBaseName).getAbsoluteFilePath(); BorderFile tempOutBorder; tempOutBorder.setNumberOfNodes(inputData.m_surface->getNumberOfNodes()); tempOutBorder.addBorder(new Border(*(inputData.m_borderEnclosingROI))); tempOutBorder.writeFile(completeBase + ".border"); if (inputData.m_combinedGradientDataOut != NULL) { inputData.m_combinedGradientDataOut->writeFile(completeBase + ".func.gii"); } TextFile textOut;//because QT's paths use non-native separators on windows textOut.replaceText(statisticsInformation); textOut.addLine("\n\nBorders chosen to optimize:"); for (std::vector::const_iterator bi = inputData.m_borders.begin(); bi != inputData.m_borders.end(); bi++) { textOut.addLine((*bi)->getName()); } textOut.addLine("\nBorder pair for statistics:"); for (std::vector::const_iterator bi = inputData.m_borderPair.begin(); bi != inputData.m_borderPair.end(); bi++) { textOut.addLine((*bi)->getName()); } textOut.addLine("\nOptimizing Surface: " + inputData.m_surface->getFileName()); textOut.addLine("\nData Files used:"); for (std::vector::const_iterator fi = inputData.m_dataFileInfo.begin(); fi != inputData.m_dataFileInfo.end(); fi++) { const DataFileInfo& dfi = *fi; textOut.addLine("\n" + dfi.m_mapFile->getFileName()); if (dfi.m_allMapsFlag) { textOut.addLine(" Map: All Maps"); } else { textOut.addLine(" Map: " + AString::number(dfi.m_mapIndex) + ", " + dfi.m_mapFile->getMapName(dfi.m_mapIndex)); } textOut.addLine(" Strength: " + AString::number(dfi.m_weight)); textOut.addLine(" Smoothing: " + AString::number(dfi.m_smoothing)); textOut.addLine(" Invert Gradient: " + AString::fromBool(dfi.m_invertGradientFlag)); } if (inputData.m_vertexAreasMetricFile != NULL) textOut.addLine("\nVertex Areas Metric File:\n" + inputData.m_vertexAreasMetricFile->getFileName()); if (inputData.m_upsamplingSphericalSurface != NULL) { textOut.addLine("\nUpsampling Sphere: " + inputData.m_upsamplingSphericalSurface->getFileName()); textOut.addLine("Upsampling Resolution: " + AString::number(inputData.m_upsamplingResolution)); } textOut.addLine("\nGradient Following Strength: " + AString::number(inputData.m_gradientFollowingStrength)); textOut.writeFile(completeBase + ".txt"); } /** * Run the border optimization algorithm. * * @param inputData * Input data for the algorithm. */ void BorderOptimizeExecutor::printInputs(const InputData& inputData) { std::cout << "Optimizing borders: " << std::endl; for (std::vector::const_iterator bi = inputData.m_borders.begin(); bi != inputData.m_borders.end(); bi++) { std::cout << " " << qPrintable((*bi)->getName()) << std::endl; } std::cout << "Border pair: " << std::endl; for (std::vector::const_iterator bi = inputData.m_borderPair.begin(); bi != inputData.m_borderPair.end(); bi++) { std::cout << " " << qPrintable((*bi)->getName()) << std::endl; } std::cout << "Optimizing Surface: " << qPrintable(inputData.m_surface->getFileNameNoPath()) << std::endl; std::cout << "Number of nodes in ROI: " << qPrintable(AString::number(inputData.m_nodesInsideROI.size())) << std::endl; std::cout << "Optimizing Data Files: " << std::endl; for (std::vector::const_iterator fi = inputData.m_dataFileInfo.begin(); fi != inputData.m_dataFileInfo.end(); fi++) { const DataFileInfo& dfi = *fi; std::cout << " Name: " << qPrintable(dfi.m_mapFile->getFileNameNoPath()) << std::endl; if (dfi.m_allMapsFlag) { std::cout << " Map: All Maps" << std::endl; } else { std::cout << " Map: " << qPrintable(AString::number(dfi.m_mapIndex)) << " " << qPrintable(dfi.m_mapFile->getMapName(dfi.m_mapIndex)) << std::endl; } std::cout << " Strength: " << dfi.m_weight << std::endl; std::cout << " Smoothing: " << dfi.m_smoothing << std::endl; std::cout << " Invert Gradient: " << AString::fromBool(dfi.m_invertGradientFlag) << std::endl; std::cout << " Skip Gradient: " << AString::fromBool(dfi.m_skipGradient) << std::endl; } std::cout << "Vertex Areas Metric File: " << ((inputData.m_vertexAreasMetricFile != NULL) ? qPrintable(inputData.m_vertexAreasMetricFile->getFileNameNoPath()) : "NULL") << std::endl; if (inputData.m_upsamplingSphericalSurface != NULL) { std::cout << "Upsampling Sphere: " << qPrintable(inputData.m_upsamplingSphericalSurface->getFileNameNoPath()) << std::endl; std::cout << "Upsampling Resolution: " << qPrintable(QString::number(inputData.m_upsamplingResolution)) << std::endl; } std::cout << "Gradient Following Strength: " << inputData.m_gradientFollowingStrength << std::endl; } connectome-workbench-1.4.2/src/GuiQt/BorderOptimizeExecutor.h000066400000000000000000000125251360521144700243060ustar00rootroot00000000000000#ifndef __BORDER_OPTIMIZE_EXECUTOR_H__ #define __BORDER_OPTIMIZE_EXECUTOR_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "CaretPointer.h" namespace caret { class Border; class CaretMappableDataFile; class MetricFile; class Surface; class BorderOptimizeExecutor : public CaretObject { public: /** * Info about the data files */ struct DataFileInfo { DataFileInfo(const CaretMappableDataFile* mapFile, const int32_t mapIndex, const bool allMapsFlag, const float smoothing, const float weight, const bool invertGradientFlag, const bool& skipGradient, const float& corrGradExcludeDist) : m_mapFile(mapFile), m_mapIndex(mapIndex), m_allMapsFlag(allMapsFlag), m_smoothing(smoothing), m_weight(weight), m_invertGradientFlag(invertGradientFlag), m_skipGradient(skipGradient), m_corrGradExcludeDist(corrGradExcludeDist) { } const CaretMappableDataFile* m_mapFile; int32_t m_mapIndex; bool m_allMapsFlag; float m_smoothing; float m_weight; bool m_invertGradientFlag; bool m_skipGradient; float m_corrGradExcludeDist; }; /** * Update data for the algorithm */ struct InputData { InputData(std::vector borders, std::vector borderPair, const Border* borderEnclosingROI, const std::vector& nodesInsideROI, Surface* surface, const std::vector& dataFileInfo, const MetricFile* vertexAreasMetricFile, const float& gradientFollowingStrength, Surface* upsamplingSphericalSurface, const int32_t upsamplingResolution, MetricFile* combinedGradientDataOut, bool saveResults, const AString& savingPath, const AString& savingBaseName) : m_borders(borders), m_borderPair(borderPair), m_borderEnclosingROI(borderEnclosingROI), m_nodesInsideROI(nodesInsideROI), m_surface(surface), m_dataFileInfo(dataFileInfo), m_vertexAreasMetricFile(vertexAreasMetricFile), m_gradientFollowingStrength(gradientFollowingStrength), m_upsamplingSphericalSurface(upsamplingSphericalSurface), m_upsamplingResolution(upsamplingResolution), m_combinedGradientDataOut(combinedGradientDataOut), m_saveResults(saveResults), m_savingPath(savingPath), m_savingBaseName(savingBaseName) { } std::vector m_borders; std::vector m_borderPair; const Border* m_borderEnclosingROI; const std::vector& m_nodesInsideROI; Surface* m_surface; const std::vector& m_dataFileInfo; const MetricFile* m_vertexAreasMetricFile; const float m_gradientFollowingStrength; Surface* m_upsamplingSphericalSurface; const int32_t m_upsamplingResolution; MetricFile* m_combinedGradientDataOut; bool m_saveResults; AString m_savingPath, m_savingBaseName; }; BorderOptimizeExecutor(); virtual ~BorderOptimizeExecutor(); static void printInputs(const InputData& inputData); static bool run(const InputData& inputData, AString& statisticsInformationOut, AString& errorMessageOut); static void saveResults(const InputData& inputData, const AString& statisticsInformation); private: BorderOptimizeExecutor(const BorderOptimizeExecutor&); BorderOptimizeExecutor& operator=(const BorderOptimizeExecutor&); // ADD_NEW_MEMBERS_HERE }; #ifdef __BORDER_OPTIMIZE_EXECUTOR_DECLARE__ // #endif // __BORDER_OPTIMIZE_EXECUTOR_DECLARE__ } // namespace #endif //__BORDER_OPTIMIZE_EXECUTOR_H__ connectome-workbench-1.4.2/src/GuiQt/BorderPropertiesEditorDialog.cxx000066400000000000000000000570671360521144700257770ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #define __BORDER_PROPERTIES_EDITOR_DIALOG__DECLARE__ #include "BorderPropertiesEditorDialog.h" #undef __BORDER_PROPERTIES_EDITOR_DIALOG__DECLARE__ #include "Brain.h" #include "Border.h" #include "BorderFile.h" #include "CaretAssert.h" #include "CaretFileDialog.h" #include "EventDataFileAdd.h" #include "EventManager.h" #include "GroupAndNameHierarchyModel.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "GiftiLabelTableEditor.h" #include "GiftiLabelTableSelectionComboBox.h" #include "GuiManager.h" #include "SurfaceFile.h" #include "WuQDataEntryDialog.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::BorderPropertiesEditorDialog * \brief Dialog that queries user to finish drawing of a border. * * This dialog is displayed when the user finishes drawing a * border. It allows the user to select the border file, * enter the border name, select the color, enter the class, * set the type of border (open/closed), and * possibly other attributes of the border. */ /** * Create a new instance of the border properties editor for finishing * a border using a drawing mode. * * @param border * Border that was drawn. * @param parent * Parent on which this dialog is shown. * @return * Dialog that will finish the border. * Users MUST DELETE the returned dialog. */ BorderPropertiesEditorDialog* BorderPropertiesEditorDialog::newInstanceFinishBorder(Border* border, SurfaceFile* surfaceFile, QWidget* parent) { CaretAssert(surfaceFile); BorderPropertiesEditorDialog* dialog = new BorderPropertiesEditorDialog("Finish Border", surfaceFile, BorderPropertiesEditorDialog::MODE_FINISH_DRAWING, NULL, border, parent); return dialog; } /** * Create a new instance of the border properties editor for editing * a border properties. * * @param editModeBorderFile * Border file containing the border that is being edited. * @param border * Border that is to be edited. * @param parent * Parent on which this dialog is shown. * @return * Dialog that will finish the border. * Users MUST DELETE the returned dialog. */ BorderPropertiesEditorDialog* BorderPropertiesEditorDialog::newInstanceEditBorder(BorderFile* editModeBorderFile, Border* border, QWidget* parent) { BorderPropertiesEditorDialog* dialog = new BorderPropertiesEditorDialog("Edit Border Properties", NULL, BorderPropertiesEditorDialog::MODE_EDIT, editModeBorderFile, border, parent); return dialog; } /** * Constructor. */ BorderPropertiesEditorDialog::BorderPropertiesEditorDialog(const QString& title, SurfaceFile* finishBorderSurfaceFile, Mode mode, BorderFile* editModeBorderFile, Border* border, QWidget* parent) : WuQDialogModal(title, parent) { CaretAssert(border); m_finishBorderSurfaceFile = finishBorderSurfaceFile; m_editModeBorderFile = editModeBorderFile; m_mode = mode; m_border = border; m_classComboBox = NULL; QString borderName = border->getName(); QString className = border->getClassName(); switch (m_mode) { case MODE_EDIT: break; case MODE_FINISH_DRAWING: if (s_previousDataValid) { borderName = s_previousName; className = s_previousClassName; } break; } /* * File selection combo box */ QLabel* borderFileLabel = new QLabel("Border File"); m_borderFileSelectionComboBox = new QComboBox(); WuQtUtilities::setToolTipAndStatusTip(m_borderFileSelectionComboBox, "Selects an existing border file\n" "to which new borders are added."); QObject::connect(m_borderFileSelectionComboBox, SIGNAL(activated(int)), this, SLOT(borderFileSelected())); QAction* newFileAction = WuQtUtilities::createAction("New", "Create a new border file", this, this, SLOT(newBorderFileButtonClicked())); QToolButton* newFileToolButton = new QToolButton(); newFileToolButton->setDefaultAction(newFileAction); WuQtUtilities::setToolButtonStyleForQt5Mac(newFileToolButton); /* * Completer for name */ m_nameCompleterStringListModel = new QStringListModel(this); /* * Name */ QLabel* nameLabel = new QLabel("Name"); m_nameComboBox = new GiftiLabelTableSelectionComboBox(this); m_nameComboBox->setUnassignedLabelTextOverride("Select Name"); // m_nameLineEdit->setText(borderName); QAction* displayNameColorEditorAction = WuQtUtilities::createAction("Add/Edit...", "Add and/or edit name colors", this, this, SLOT(displayNameEditor())); QToolButton* displayNameColorEditorToolButton = new QToolButton(); displayNameColorEditorToolButton->setDefaultAction(displayNameColorEditorAction); WuQtUtilities::setToolButtonStyleForQt5Mac(displayNameColorEditorToolButton); /* * Class */ QLabel* classLabel = new QLabel("Class"); m_classComboBox = new GiftiLabelTableSelectionComboBox(this); WuQtUtilities::setToolTipAndStatusTip(m_classComboBox->getWidget(), "The class is used to group borders with similar\n" "characteristics. Controls are available to\n" "display borders by their class attributes."); QAction* displayClassEditorAction = WuQtUtilities::createAction("Add/Edit...", "Add and/or edit classes", this, this, SLOT(displayClassEditor())); QToolButton* displayClassEditorToolButton = new QToolButton(); displayClassEditorToolButton->setDefaultAction(displayClassEditorAction); WuQtUtilities::setToolButtonStyleForQt5Mac(displayClassEditorToolButton); /* * Closed */ m_closedCheckBox = new QCheckBox("Closed Border"); WuQtUtilities::setToolTipAndStatusTip(m_closedCheckBox, "If checked, additional points will be added\n" "to the border so that the border forms a loop\n" "with the last point adjacent to the first point."); if (s_previousClosedSelected) { m_closedCheckBox->setChecked(true); } else { m_closedCheckBox->setChecked(false); } /* * Reverse point order */ m_reversePointOrderCheckBox = new QCheckBox("Reverse Point Order"); WuQtUtilities::setToolTipAndStatusTip(m_reversePointOrderCheckBox, "If checked, the order of the points in the \n" "border are reversed when the OK button is pressed."); /* * Layout widgets */ QWidget* widget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(widget); int row = 0; gridLayout->addWidget(borderFileLabel, row, 0); gridLayout->addWidget(m_borderFileSelectionComboBox, row, 1); gridLayout->addWidget(newFileToolButton, row, 2); row++; gridLayout->addWidget(nameLabel, row, 0); gridLayout->addWidget(m_nameComboBox->getWidget(), row, 1); gridLayout->addWidget(displayNameColorEditorToolButton, row, 2); row++; gridLayout->addWidget(classLabel, row, 0); gridLayout->addWidget(m_classComboBox->getWidget(), row, 1); gridLayout->addWidget(displayClassEditorToolButton, row, 2); row++; gridLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), row, 0, 1, 3, Qt::AlignLeft); row++; gridLayout->addWidget(m_closedCheckBox, row, 0, 1, 3, Qt::AlignLeft); row++; gridLayout->addWidget(m_reversePointOrderCheckBox, row, 0, 1, 3, Qt::AlignLeft); /* * Show/Hide options based upon mode */ bool showFileOptionFlag = false; bool showClosedOptionFlag = false; bool showReverseOptionFlag = false; switch (m_mode) { case MODE_EDIT: showReverseOptionFlag = true; break; case MODE_FINISH_DRAWING: showFileOptionFlag = true; showClosedOptionFlag = true; break; } borderFileLabel->setVisible(showFileOptionFlag); m_borderFileSelectionComboBox->setVisible(showFileOptionFlag); newFileToolButton->setVisible(showFileOptionFlag); m_closedCheckBox->setVisible(showClosedOptionFlag); m_reversePointOrderCheckBox->setVisible(showReverseOptionFlag); loadBorderFileComboBox(); loadNameComboBox(borderName); loadClassComboBox(className); /* * Set the widget for the dialog. */ setCentralWidget(widget, WuQDialog::SCROLL_AREA_NEVER); } /** * Destructor. */ BorderPropertiesEditorDialog::~BorderPropertiesEditorDialog() { } /** * Get the selected border file. * @return BorderFile or NULL if no border file. */ BorderFile* BorderPropertiesEditorDialog::getSelectedBorderFile() { if (m_editModeBorderFile != NULL) { return m_editModeBorderFile; } const int fileComboBoxIndex = m_borderFileSelectionComboBox->currentIndex(); void* filePointer = m_borderFileSelectionComboBox->itemData(fileComboBoxIndex).value(); BorderFile* borderFile = (BorderFile*)filePointer; s_previousBorderFile = borderFile; return borderFile; } /** * Load the SINGLE STRUCTURE border files into the border file combo box. */ void BorderPropertiesEditorDialog::loadBorderFileComboBox() { CaretAssert(m_border); const StructureEnum::Enum borderStructure = m_border->getStructure(); Brain* brain = GuiManager::get()->getBrain(); const int32_t numBorderFiles = brain->getNumberOfBorderFiles(); m_borderFileSelectionComboBox->clear(); int defaultFileComboIndex = 0; for (int32_t i = 0; i < numBorderFiles; i++) { BorderFile* borderFile = brain->getBorderFile(i); if (borderFile->isSingleStructure()) { if (borderFile->getStructure() == borderStructure) { const AString name = borderFile->getFileNameNoPath(); m_borderFileSelectionComboBox->addItem(name, qVariantFromValue((void*)borderFile)); if (s_previousBorderFile == borderFile) { defaultFileComboIndex = m_borderFileSelectionComboBox->count() - 1; } } } } if (m_borderFileSelectionComboBox->count() > 0) { m_borderFileSelectionComboBox->setCurrentIndex(defaultFileComboIndex); const BorderFile* borderFile = getSelectedBorderFile(); if (borderFile != NULL) { m_nameCompleterStringList = borderFile->getAllBorderNamesSorted(); m_nameCompleterStringListModel->setStringList(m_nameCompleterStringList); } } } /** * Called to create a new border file. */ void BorderPropertiesEditorDialog::newBorderFileButtonClicked() { CaretAssert(m_border); const StructureEnum::Enum borderStructure = m_border->getStructure(); if (StructureEnum::isSingleStructure(borderStructure)) { CaretAssert(m_finishBorderSurfaceFile); /* * Let user choose a different path/name */ BorderFile* newBorderFile = new BorderFile(); GuiManager::get()->getBrain()->convertDataFilePathNameToAbsolutePathName(newBorderFile); AString newBorderFileName = CaretFileDialog::getSaveFileNameDialog(DataFileTypeEnum::BORDER, this, "Choose Border File Name", newBorderFile->getFileName()); /* * If user cancels, delete the new border file and return */ if (newBorderFileName.isEmpty()) { delete newBorderFile; return; } /* * Set name of new border file along with structure and number of nodes */ newBorderFile->setFileName(newBorderFileName); newBorderFile->setStructure(borderStructure); newBorderFile->setNumberOfNodes(m_finishBorderSurfaceFile->getNumberOfNodes()); EventManager::get()->sendEvent(EventDataFileAdd(newBorderFile).getPointer()); s_previousBorderFile = newBorderFile; loadBorderFileComboBox(); borderFileSelected(); } else { WuQMessageBox::errorOk(this, ("Border must be for a single structure but it is for " + StructureEnum::toGuiName(borderStructure))); } } /** * Called when a border file is selected. */ void BorderPropertiesEditorDialog::borderFileSelected() { loadNameComboBox(); if (m_classComboBox != NULL) { loadClassComboBox(); } } /** * Load the class combo box. * * @param name * If not empty, make this name the selected name. */ void BorderPropertiesEditorDialog::loadClassComboBox(const QString& name) { BorderFile* borderFile = getSelectedBorderFile(); if (borderFile != NULL) { m_classComboBox->updateContent(borderFile->getClassColorTable()); if (name.isEmpty() == false) { m_classComboBox->setSelectedLabelName(name); } } else { m_classComboBox->updateContent(NULL); } } /** * Load the name combo box. * * @param name * If not empty, make this name the selected name. */ void BorderPropertiesEditorDialog::loadNameComboBox(const QString& name) { BorderFile* borderFile = getSelectedBorderFile(); if (borderFile != NULL) { m_nameComboBox->updateContent(borderFile->getNameColorTable()); if (name.isEmpty() == false) { m_nameComboBox->setSelectedLabelName(name); } } else { m_nameComboBox->updateContent(NULL); } } /** * Called when the OK button is pressed. */ void BorderPropertiesEditorDialog::okButtonClicked() { AString errorMessage; /* * Get border file. */ BorderFile* borderFile = getSelectedBorderFile(); if (borderFile == NULL) { WuQMessageBox::errorOk(this, "Border file is not valid, use the New button to create a border file."); return; } /* * Get data entered by the user. */ const AString name = m_nameComboBox->getSelectedLabelName(); if (name.isEmpty()) { errorMessage += ("Name is invalid.\n"); } else { const int32_t unassignedNameKey = borderFile->getNameColorTable()->getUnassignedLabelKey(); const int32_t selectedNameKey = m_nameComboBox->getSelectedLabelKey(); if (selectedNameKey == unassignedNameKey) { errorMessage += "Choose or create a name for the border"; } } const QString className = m_classComboBox->getSelectedLabelName(); /* * Error? */ if (errorMessage.isEmpty() == false) { WuQMessageBox::errorOk(this, errorMessage); return; } Border* borderBeingEdited = NULL; bool finishModeFlag = false; switch (m_mode) { case MODE_EDIT: borderBeingEdited = m_border; break; case MODE_FINISH_DRAWING: borderBeingEdited = new Border(*m_border); finishModeFlag = true; break; } /* * Make a copy of the border being drawn */ borderBeingEdited->setName(name); borderBeingEdited->setClassName(className); if (finishModeFlag) { /* * Close border */ if (m_closedCheckBox->isChecked()) { borderBeingEdited->addPointsToCloseBorderWithGeodesic(m_finishBorderSurfaceFile); borderBeingEdited->setClosed(true); } else { borderBeingEdited->setClosed(false); } /* * Add border to border file */ CaretAssert(borderFile); borderFile->addBorder(borderBeingEdited); /* * Save values entered by the user and * use them to initialize the dialog next * time it is displayed. */ s_previousDataValid = true; s_previousName = name; s_previousClassName = className; s_previousClosedSelected = m_closedCheckBox->isChecked(); s_previousBorderFile = borderFile; } else { if (m_reversePointOrderCheckBox->isChecked()) { m_border->reverse(); } } if (m_nameCompleterStringList.contains(name) == false) { m_nameCompleterStringList.append(name); m_nameCompleterStringList.sort(); m_nameCompleterStringListModel->setStringList(m_nameCompleterStringList); } /* * continue with OK button processing */ WuQDialogModal::okButtonClicked(); } /** * Display the class editor */ void BorderPropertiesEditorDialog::displayClassEditor() { BorderFile* borderFile = getSelectedBorderFile(); if (borderFile == NULL) { WuQMessageBox::errorOk(this, "Border file is not valid, use the New button to create a border file."); return; } /* * Need to detect a change in the name class table. * So: * (1) Save the modified status * (2) Clear the modified status * (3) After editing, see if the modified status is on indicating * that the user has made a change to the table * (4) If user modified table, invalidate border colors so that * the borders get the new color(s). * (5) If user DID NOT modify table, restore the modification * status of the table. */ GiftiLabelTable* classTable = borderFile->getClassColorTable(); const bool modifiedStatus = classTable->isModified(); classTable->clearModified(); GiftiLabelTableEditor editor(borderFile, classTable, "Edit Class Attributes", GiftiLabelTableEditor::OPTION_NONE, this); const QString className = m_classComboBox->getSelectedLabelName(); if (className.isEmpty() == false) { editor.selectLabelWithName(className); } const int dialogResult = editor.exec(); loadClassComboBox(); if (dialogResult == GiftiLabelTableEditor::Accepted) { const QString selectedClassName = editor.getLastSelectedLabelName(); if (selectedClassName.isEmpty() == false) { m_classComboBox->setSelectedLabelName(selectedClassName); } } if (classTable->isModified()) { /* * User changed something in the table. */ borderFile->invalidateAllAssignedColors(); } else { if (modifiedStatus) { /* * User did not change anything but need to restore * modified status. */ classTable->setModified(); } } } /** * Display the name editor */ void BorderPropertiesEditorDialog::displayNameEditor() { BorderFile* borderFile = getSelectedBorderFile(); if (borderFile == NULL) { WuQMessageBox::errorOk(this, "Border file is not valid, use the New button to create a border file."); return; } /* * Need to detect a change in the name color table. * So: * (1) Save the modified status * (2) Clear the modified status * (3) After editing, see if the modified status is on indicating * that the user has made a change to the table * (4) If user modified table, invalidate border colors so that * the borders get the new color(s). * (5) If user DID NOT modify table, restore the modification * status of the table. */ GiftiLabelTable* nameTable = borderFile->getNameColorTable(); const bool modifiedStatus = nameTable->isModified(); nameTable->clearModified(); GiftiLabelTableEditor editor(borderFile, nameTable, "Edit Name Attributes", GiftiLabelTableEditor::OPTION_UNASSIGNED_LABEL_HIDDEN, this); const QString name = m_nameComboBox->getSelectedLabelName(); if (name.isEmpty() == false) { editor.selectLabelWithName(name); } const int dialogResult = editor.exec(); loadNameComboBox(); if (dialogResult == GiftiLabelTableEditor::Accepted) { const QString selectedName = editor.getLastSelectedLabelName(); if (selectedName.isEmpty() == false) { m_nameComboBox->setSelectedLabelName(selectedName); } } if (nameTable->isModified()) { /* * User changed something in the table. */ borderFile->invalidateAllAssignedColors(); } else { if (modifiedStatus) { /* * User did not change anything but need to restore * modified status. */ nameTable->setModified(); } } } connectome-workbench-1.4.2/src/GuiQt/BorderPropertiesEditorDialog.h000066400000000000000000000103131360521144700254030ustar00rootroot00000000000000#ifndef __BORDER_PROPERTIES_EDITOR_DIALOG__H_ #define __BORDER_PROPERTIES_EDITOR_DIALOG__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WuQDialogModal.h" class QCheckBox; class QComboBox; class QDoubleSpinBox; class QLabel; class QLineEdit; class QStringListModel; namespace caret { class Border; class BorderFile; class GiftiLabelTableSelectionComboBox; class SurfaceFile; class BorderPropertiesEditorDialog : public WuQDialogModal { Q_OBJECT public: static BorderPropertiesEditorDialog* newInstanceFinishBorder(Border* border, SurfaceFile* surfaceFile, QWidget* parent = 0); static BorderPropertiesEditorDialog* newInstanceEditBorder(BorderFile* editModeBorderFile, Border* border, QWidget* parent = 0); virtual ~BorderPropertiesEditorDialog(); protected: virtual void okButtonClicked(); private slots: void displayNameEditor(); void displayClassEditor(); void borderFileSelected(); void newBorderFileButtonClicked(); private: enum Mode { MODE_EDIT, MODE_FINISH_DRAWING }; BorderPropertiesEditorDialog(const QString& title, SurfaceFile* finishBorderSurfaceFile, const Mode mode, BorderFile* editModeBorderFile, Border* border, QWidget* parent = 0); BorderPropertiesEditorDialog(const BorderPropertiesEditorDialog&); BorderPropertiesEditorDialog& operator=(const BorderPropertiesEditorDialog&); BorderFile* getSelectedBorderFile(); void loadBorderFileComboBox(); void loadNameComboBox(const QString& name = ""); void loadClassComboBox(const QString& className = ""); Mode m_mode; BorderFile* m_editModeBorderFile; Border* m_border; QComboBox* m_borderFileSelectionComboBox; GiftiLabelTableSelectionComboBox* m_nameComboBox; QStringList m_nameCompleterStringList; QStringListModel* m_nameCompleterStringListModel; QCheckBox* m_closedCheckBox; GiftiLabelTableSelectionComboBox* m_classComboBox; QCheckBox* m_reversePointOrderCheckBox; SurfaceFile* m_finishBorderSurfaceFile; static bool s_previousDataValid; static AString s_previousName; static BorderFile* s_previousBorderFile; static bool s_previousClosedSelected; static AString s_previousClassName; }; #ifdef __BORDER_PROPERTIES_EDITOR_DIALOG__DECLARE__ bool BorderPropertiesEditorDialog::s_previousDataValid = false; AString BorderPropertiesEditorDialog::s_previousName = "Name"; BorderFile* BorderPropertiesEditorDialog::s_previousBorderFile = NULL; bool BorderPropertiesEditorDialog::s_previousClosedSelected = false; AString BorderPropertiesEditorDialog::s_previousClassName = "None"; #endif // __BORDER_PROPERTIES_EDITOR_DIALOG__DECLARE__ } // namespace #endif //__BORDER_PROPERTIES_EDITOR_DIALOG__H_ connectome-workbench-1.4.2/src/GuiQt/BorderSelectionViewController.cxx000066400000000000000000000656211360521144700261730ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #define __BORDER_SELECTION_VIEW_CONTROLLER_DECLARE__ #include "BorderSelectionViewController.h" #undef __BORDER_SELECTION_VIEW_CONTROLLER_DECLARE__ #include "BorderDrawingTypeEnum.h" #include "Brain.h" #include "BrainOpenGL.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretColorEnumComboBox.h" #include "GroupAndNameHierarchyViewController.h" #include "DisplayGroupEnumComboBox.h" #include "DisplayPropertiesBorders.h" #include "EnumComboBoxTemplate.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "SceneClass.h" #include "WuQDataEntryDialog.h" #include "WuQFactory.h" #include "WuQMacroManager.h" #include "WuQTabWidget.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::BorderSelectionViewController * \brief Widget for controlling display of borders * * Widget for controlling the display of borders including * different display groups. */ /** * Constructor. * * @param browserWindowIndex * Index of browser window * @param parentObjectName * Name of parent object * @param parent * The parent object */ BorderSelectionViewController::BorderSelectionViewController(const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent) : QWidget(parent), m_objectNamePrefix(parentObjectName + ":Borders") { m_browserWindowIndex = browserWindowIndex; WuQMacroManager* macroManager = WuQMacroManager::instance(); QLabel* groupLabel = new QLabel("Group"); m_bordersDisplayGroupComboBox = new DisplayGroupEnumComboBox(this); QObject::connect(m_bordersDisplayGroupComboBox, SIGNAL(displayGroupSelected(const DisplayGroupEnum::Enum)), this, SLOT(borderDisplayGroupSelected(const DisplayGroupEnum::Enum))); QHBoxLayout* groupLayout = new QHBoxLayout(); groupLayout->addWidget(groupLabel); groupLayout->addWidget(m_bordersDisplayGroupComboBox->getWidget()); groupLayout->addStretch(); m_bordersDisplayCheckBox = new QCheckBox("Display Borders"); QObject::connect(m_bordersDisplayCheckBox, SIGNAL(clicked(bool)), this, SLOT(processAttributesChanges())); m_bordersDisplayCheckBox->setObjectName(m_objectNamePrefix + ":DisplayBorders"); m_bordersDisplayCheckBox->setToolTip("Display Borders on Surfaces"); macroManager->addMacroSupportToObject(m_bordersDisplayCheckBox, "Enable borders display"); QWidget* attributesWidget = this->createAttributesWidget(); QWidget* selectionWidget = this->createSelectionWidget(); m_tabWidget = new WuQTabWidget(WuQTabWidget::TAB_ALIGN_LEFT, this); m_tabWidget->addTab(attributesWidget, "Attributes"); m_tabWidget->addTab(selectionWidget, "Selection"); m_tabWidget->setCurrentWidget(attributesWidget); m_tabWidget->getTabBar()->setObjectName(m_objectNamePrefix + ":Tab"); macroManager->addMacroSupportToObjectWithToolTip(m_tabWidget->getTabBar(), "Features ToolBox Borders Tab", "Select tab"); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(m_bordersDisplayCheckBox); layout->addWidget(WuQtUtilities::createHorizontalLineWidget()); layout->addLayout(groupLayout); layout->addWidget(m_tabWidget->getWidget(), 0, Qt::AlignLeft); layout->addStretch(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); BorderSelectionViewController::allBorderSelectionViewControllers.insert(this); } /** * Destructor. */ BorderSelectionViewController::~BorderSelectionViewController() { EventManager::get()->removeAllEventsFromListener(this); BorderSelectionViewController::allBorderSelectionViewControllers.erase(this); } QWidget* BorderSelectionViewController::createSelectionWidget() { m_borderClassNameHierarchyViewController = new GroupAndNameHierarchyViewController(m_browserWindowIndex, (m_objectNamePrefix + ":Selection"), "borders", this); return m_borderClassNameHierarchyViewController; } /** * @return The attributes widget. */ QWidget* BorderSelectionViewController::createAttributesWidget() { WuQMacroManager* macroManager = WuQMacroManager::instance(); m_bordersContralateralCheckBox = new QCheckBox("Contralateral"); QObject::connect(m_bordersContralateralCheckBox, SIGNAL(clicked(bool)), this, SLOT(processAttributesChanges())); m_bordersContralateralCheckBox->setObjectName(m_objectNamePrefix + ":Contralateral"); m_bordersContralateralCheckBox->setToolTip("Show Contralateral Borders"); macroManager->addMacroSupportToObject(m_bordersContralateralCheckBox, "Enable contralateral borders display"); std::vector drawingTypeEnums; BorderDrawingTypeEnum::getAllEnums(drawingTypeEnums); const int32_t numDrawingTypeEnums = static_cast(drawingTypeEnums.size()); QLabel* drawAsLabel = new QLabel("Draw As"); m_drawTypeComboBox = new QComboBox(); for (int32_t i = 0; i < numDrawingTypeEnums; i++) { BorderDrawingTypeEnum::Enum drawType = drawingTypeEnums[i]; m_drawTypeComboBox->addItem(BorderDrawingTypeEnum::toGuiName(drawType), (int)drawType); } m_drawTypeComboBox->setToolTip("Select the drawing style of borders\n" "Lines are faster but have limited width\n" "Polylines are slower but have unlimited width"); QObject::connect(m_drawTypeComboBox, SIGNAL(activated(int)), this, SLOT(processAttributesChanges())); m_drawTypeComboBox->setObjectName(m_objectNamePrefix + ":DrawingType"); macroManager->addMacroSupportToObject(m_drawTypeComboBox, "Select border drawing style"); QLabel* coloringLabel = new QLabel("Coloring"); m_coloringTypeComboBox = new EnumComboBoxTemplate(this); m_coloringTypeComboBox->setup(); m_coloringTypeComboBox->getWidget()->setToolTip("Select the coloring assignment for borders"); QObject::connect(m_coloringTypeComboBox, SIGNAL(itemActivated()), this, SLOT(processAttributesChanges())); m_coloringTypeComboBox->getWidget()->setObjectName(m_objectNamePrefix + ":ColoringType"); macroManager->addMacroSupportToObject(m_coloringTypeComboBox->getWidget(), "Select border coloring type"); QLabel* standardColorLabel = new QLabel("Standard Color"); m_standardColorComboBox = new CaretColorEnumComboBox("", QIcon(), (m_objectNamePrefix + ":Color"), "Set border standard color", this); m_standardColorComboBox->getWidget()->setToolTip("Select the standard color"); QObject::connect(m_standardColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), this, SLOT(processAttributesChanges())); float minLineWidth = 0.1; float maxLineWidth = 1000; QLabel* lineWidthLabel = new QLabel("Line Diameter"); m_lineWidthSpinBox = WuQFactory::newDoubleSpinBox(); m_lineWidthSpinBox->setFixedWidth(80); m_lineWidthSpinBox->setRange(minLineWidth, maxLineWidth); m_lineWidthSpinBox->setSingleStep(0.1); m_lineWidthSpinBox->setDecimals(1); m_lineWidthSpinBox->setSuffix("px"); m_lineWidthSpinBox->setToolTip("Adjust the width of borders drawn as lines.\n" "Units is pixels\n" "The maximum width is dependent upon the \n" "graphics system. There is no maximum value\n" "for this control and the drawn width of the \n" "lines will stop increasing even though the\n" "value of this control is changing"); QObject::connect(m_lineWidthSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); m_lineWidthSpinBox->setObjectName(m_objectNamePrefix + ":LineWidth"); macroManager->addMacroSupportToObject(m_lineWidthSpinBox, "Set border line width"); QLabel* pointSizeLabel = new QLabel("Symbol Diameter"); m_pointSizeSpinBox = WuQFactory::newDoubleSpinBox(); m_pointSizeSpinBox->setFixedWidth(80); m_pointSizeSpinBox->setRange(minLineWidth, maxLineWidth); m_pointSizeSpinBox->setSingleStep(0.1); m_pointSizeSpinBox->setDecimals(1); m_pointSizeSpinBox->setToolTip("Adjust the size of borders drawn as points"); m_pointSizeSpinBox->setSuffix("mm"); QObject::connect(m_pointSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); m_pointSizeSpinBox->setObjectName(m_objectNamePrefix + ":PointSize"); macroManager->addMacroSupportToObject(m_pointSizeSpinBox, "Set border point size"); m_enableUnstretchedLinesCheckBox = new QCheckBox("Unstretched Lines"); QObject::connect(m_enableUnstretchedLinesCheckBox, SIGNAL(clicked(bool)), this, SLOT(processAttributesChanges())); m_enableUnstretchedLinesCheckBox->setToolTip("Disable lines that are invalid due to cuts in flat surface"); m_enableUnstretchedLinesCheckBox->setObjectName(m_objectNamePrefix + ":UnstretchedLines"); macroManager->addMacroSupportToObject(m_enableUnstretchedLinesCheckBox, "Enable border unstretched lines"); m_unstretchedLinesLengthSpinBox = WuQFactory::newDoubleSpinBox(); m_unstretchedLinesLengthSpinBox->setFixedWidth(80); m_unstretchedLinesLengthSpinBox->setRange(0.0, 10000000.0); m_unstretchedLinesLengthSpinBox->setSingleStep(1.0); m_unstretchedLinesLengthSpinBox->setDecimals(1); m_unstretchedLinesLengthSpinBox->setToolTip(WuQtUtilities::createWordWrappedToolTipText("Ratio = (length of border on flat surface divided by length of border of 3d (primary anatomical) surface. " "When ratio is greater than the unstretched lines value, the border segment is NOT drawn.")); m_unstretchedLinesLengthSpinBox->setSuffix("mm"); QObject::connect(m_unstretchedLinesLengthSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); m_unstretchedLinesLengthSpinBox->setObjectName(m_objectNamePrefix + ":UnstretchedLinesLength"); macroManager->addMacroSupportToObject(m_unstretchedLinesLengthSpinBox, "Set border unstretched lines lenght"); QLabel* aboveSurfaceLabel = new QLabel("Above Offset"); m_aboveSurfaceOffsetSpinBox =WuQFactory::newDoubleSpinBox(); m_aboveSurfaceOffsetSpinBox->setFixedWidth(80); m_aboveSurfaceOffsetSpinBox->setRange( 0.0, 100.0); m_aboveSurfaceOffsetSpinBox->setSingleStep(0.1); m_aboveSurfaceOffsetSpinBox->setDecimals(1); m_aboveSurfaceOffsetSpinBox->setToolTip(WuQtUtilities::createWordWrappedToolTipText("Moves surface away from borders (in depth) so that borders are above surface. " "Use with caution.")); QObject::connect(m_aboveSurfaceOffsetSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); m_aboveSurfaceOffsetSpinBox->setObjectName(m_objectNamePrefix + ":AboveSurfaceOffset"); macroManager->addMacroSupportToObject(m_aboveSurfaceOffsetSpinBox, "Set border above surface offset"); QWidget* gridWidget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(gridWidget); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 8, 2); int row = gridLayout->rowCount(); gridLayout->addWidget(m_bordersContralateralCheckBox, row, 0, 1, 2, Qt::AlignLeft); row++; gridLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), row, 0, 1, 2); row++; gridLayout->addWidget(drawAsLabel, row, 0); gridLayout->addWidget(m_drawTypeComboBox, row, 1); row++; gridLayout->addWidget(coloringLabel, row, 0); gridLayout->addWidget(m_coloringTypeComboBox->getWidget(), row, 1); row++; gridLayout->addWidget(standardColorLabel, row, 0); gridLayout->addWidget(m_standardColorComboBox->getWidget(), row, 1); row++; gridLayout->addWidget(lineWidthLabel, row, 0); gridLayout->addWidget(m_lineWidthSpinBox, row, 1); row++; gridLayout->addWidget(pointSizeLabel, row, 0); gridLayout->addWidget(m_pointSizeSpinBox, row, 1); row++; gridLayout->addWidget(m_enableUnstretchedLinesCheckBox, row, 0); gridLayout->addWidget(m_unstretchedLinesLengthSpinBox, row, 1); row++; gridLayout->addWidget(aboveSurfaceLabel, row, 0); gridLayout->addWidget(m_aboveSurfaceOffsetSpinBox, row, 1); gridWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(gridWidget); layout->addStretch(); return widget; } /** * Called when a widget on the attributes page has * its value changed. */ void BorderSelectionViewController::processAttributesChanges() { DisplayPropertiesBorders* dpb = GuiManager::get()->getBrain()->getDisplayPropertiesBorders(); const int selectedDrawTypeIndex = m_drawTypeComboBox->currentIndex(); const int drawTypeInteger = m_drawTypeComboBox->itemData(selectedDrawTypeIndex).toInt(); const BorderDrawingTypeEnum::Enum selectedDrawingType = static_cast(drawTypeInteger); const FeatureColoringTypeEnum::Enum selectedColoringType = m_coloringTypeComboBox->getSelectedItem(); const CaretColorEnum::Enum standardColorType = m_standardColorComboBox->getSelectedColor(); BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); const DisplayGroupEnum::Enum displayGroup = dpb->getDisplayGroupForTab(browserTabIndex); dpb->setDisplayed(displayGroup, browserTabIndex, m_bordersDisplayCheckBox->isChecked()); dpb->setContralateralDisplayed(displayGroup, browserTabIndex, m_bordersContralateralCheckBox->isChecked()); dpb->setDrawingType(displayGroup, browserTabIndex, selectedDrawingType); dpb->setColoringType(displayGroup, browserTabIndex, selectedColoringType); dpb->setStandardColorType(displayGroup, browserTabIndex, standardColorType); dpb->setLineWidth(displayGroup, browserTabIndex, m_lineWidthSpinBox->value()); dpb->setPointSize(displayGroup, browserTabIndex, m_pointSizeSpinBox->value()); dpb->setUnstretchedLinesEnabled(displayGroup, browserTabIndex, m_enableUnstretchedLinesCheckBox->isChecked()); dpb->setUnstretchedLinesLength(displayGroup, browserTabIndex, m_unstretchedLinesLengthSpinBox->value()); dpb->setAboveSurfaceOffset(m_aboveSurfaceOffsetSpinBox->value()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); updateOtherBorderViewControllers(); } /** * Called when the border display group combo box is changed. */ void BorderSelectionViewController::borderDisplayGroupSelected(const DisplayGroupEnum::Enum displayGroup) { /* * Update selected display group in model. */ BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, false); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); Brain* brain = GuiManager::get()->getBrain(); DisplayPropertiesBorders* dsb = brain->getDisplayPropertiesBorders(); dsb->setDisplayGroupForTab(browserTabIndex, displayGroup); /* * Since display group has changed, need to update controls */ updateBorderViewController(); /* * Apply the changes. */ processBorderSelectionChanges(); } /** * Update the border selection widget. */ void BorderSelectionViewController::updateBorderViewController() { setWindowTitle("Borders"); BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); Brain* brain = GuiManager::get()->getBrain(); DisplayPropertiesBorders* dpb = brain->getDisplayPropertiesBorders(); const DisplayGroupEnum::Enum displayGroup = dpb->getDisplayGroupForTab(browserTabIndex); m_bordersDisplayGroupComboBox->setSelectedDisplayGroup(dpb->getDisplayGroupForTab(browserTabIndex)); /*; * Get all of border files. */ std::vector allBorderFiles; const int32_t numberOfBorderFiles = brain->getNumberOfBorderFiles(); for (int32_t ibf= 0; ibf < numberOfBorderFiles; ibf++) { allBorderFiles.push_back(brain->getBorderFile(ibf)); } /* * Update the class/name hierarchy */ m_borderClassNameHierarchyViewController->updateContents(allBorderFiles, displayGroup); std::vector drawingTypeEnums; BorderDrawingTypeEnum::getAllEnums(drawingTypeEnums); const int32_t numDrawingTypeEnums = static_cast(drawingTypeEnums.size()); m_bordersDisplayCheckBox->setChecked(dpb->isDisplayed(displayGroup, browserTabIndex)); m_bordersContralateralCheckBox->setChecked(dpb->isContralateralDisplayed(displayGroup, browserTabIndex)); const BorderDrawingTypeEnum::Enum selectedDrawingType = dpb->getDrawingType(displayGroup, browserTabIndex); int32_t selectedDrawingTypeIndex = 0; for (int32_t i = 0; i < numDrawingTypeEnums; i++) { BorderDrawingTypeEnum::Enum drawType = drawingTypeEnums[i]; if (drawType == selectedDrawingType) { selectedDrawingTypeIndex = i; } } m_drawTypeComboBox->setCurrentIndex(selectedDrawingTypeIndex); m_coloringTypeComboBox->setSelectedItem(dpb->getColoringType(displayGroup, browserTabIndex)); m_standardColorComboBox->setSelectedColor(dpb->getStandardColorType(displayGroup, browserTabIndex)); m_lineWidthSpinBox->blockSignals(true); m_lineWidthSpinBox->setValue(dpb->getLineWidth(displayGroup, browserTabIndex)); m_lineWidthSpinBox->blockSignals(false); m_pointSizeSpinBox->blockSignals(true); m_pointSizeSpinBox->setValue(dpb->getPointSize(displayGroup, browserTabIndex)); m_pointSizeSpinBox->blockSignals(false); m_enableUnstretchedLinesCheckBox->setChecked(dpb->isUnstretchedLinesEnabled(displayGroup, browserTabIndex)); m_unstretchedLinesLengthSpinBox->blockSignals(true); m_unstretchedLinesLengthSpinBox->setValue(dpb->getUnstretchedLinesLength(displayGroup, browserTabIndex)); m_unstretchedLinesLengthSpinBox->blockSignals(false); m_aboveSurfaceOffsetSpinBox->blockSignals(true); m_aboveSurfaceOffsetSpinBox->setValue(dpb->getAboveSurfaceOffset()); m_aboveSurfaceOffsetSpinBox->blockSignals(false); } /** * Update other selection toolbox since they should all be the same. */ void BorderSelectionViewController::updateOtherBorderViewControllers() { for (std::set::iterator iter = BorderSelectionViewController::allBorderSelectionViewControllers.begin(); iter != BorderSelectionViewController::allBorderSelectionViewControllers.end(); iter++) { BorderSelectionViewController* bsw = *iter; if (bsw != this) { bsw->updateBorderViewController(); } } } /** * Gets called when border selections are changed. */ void BorderSelectionViewController::processBorderSelectionChanges() { BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, false); CaretAssert(browserTabContent); const int32_t browserTabIndex = browserTabContent->getTabNumber(); Brain* brain = GuiManager::get()->getBrain(); DisplayPropertiesBorders* dsb = brain->getDisplayPropertiesBorders(); dsb->setDisplayGroupForTab(browserTabIndex, m_bordersDisplayGroupComboBox->getSelectedDisplayGroup()); processSelectionChanges(); } /** * Issue update events after selections are changed. */ void BorderSelectionViewController::processSelectionChanges() { updateOtherBorderViewControllers(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Receive events from the event manager. * * @param event * Event sent by event manager. */ void BorderSelectionViewController::receiveEvent(Event* event) { bool doUpdate = false; if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiEvent = dynamic_cast(event); CaretAssert(uiEvent); if (uiEvent->isUpdateForWindow(m_browserWindowIndex)) { if (uiEvent->isBorderUpdate() || uiEvent->isToolBoxUpdate()) { doUpdate = true; uiEvent->setEventProcessed(); } } } if (doUpdate) { updateBorderViewController(); } } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* BorderSelectionViewController::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "BorderSelectionViewController", 1); sceneClass->addClass(m_tabWidget->saveToScene(sceneAttributes, "m_tabWidget")); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void BorderSelectionViewController::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_tabWidget->restoreFromScene(sceneAttributes, sceneClass->getClass("m_tabWidget")); } connectome-workbench-1.4.2/src/GuiQt/BorderSelectionViewController.h000066400000000000000000000077321360521144700256170ustar00rootroot00000000000000#ifndef __BORDER_SELECTION_VIEW_CONTROLLER__H_ #define __BORDER_SELECTION_VIEW_CONTROLLER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "DisplayGroupEnum.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" class QCheckBox; class QComboBox; class QDoubleSpinBox; namespace caret { class CaretColorEnumComboBox; class GroupAndNameHierarchyViewController; class DisplayGroupEnumComboBox; class EnumComboBoxTemplate; class WuQTabWidget; class BorderSelectionViewController : public QWidget, public EventListenerInterface, public SceneableInterface { Q_OBJECT public: BorderSelectionViewController(const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent = 0); virtual ~BorderSelectionViewController(); void receiveEvent(Event* event); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private slots: void processBorderSelectionChanges(); void processSelectionChanges(); void borderDisplayGroupSelected(const DisplayGroupEnum::Enum); void processAttributesChanges(); private: BorderSelectionViewController(const BorderSelectionViewController&); BorderSelectionViewController& operator=(const BorderSelectionViewController&); void updateBorderViewController(); void updateOtherBorderViewControllers(); QWidget* createSelectionWidget(); QWidget* createAttributesWidget(); const QString m_objectNamePrefix; int32_t m_browserWindowIndex; GroupAndNameHierarchyViewController* m_borderClassNameHierarchyViewController; QCheckBox* m_bordersDisplayCheckBox; QCheckBox* m_bordersContralateralCheckBox; DisplayGroupEnumComboBox* m_bordersDisplayGroupComboBox; QComboBox* m_drawTypeComboBox; EnumComboBoxTemplate* m_coloringTypeComboBox; CaretColorEnumComboBox* m_standardColorComboBox; QDoubleSpinBox* m_lineWidthSpinBox; QDoubleSpinBox* m_pointSizeSpinBox; QCheckBox* m_enableUnstretchedLinesCheckBox; QDoubleSpinBox* m_unstretchedLinesLengthSpinBox; QDoubleSpinBox* m_aboveSurfaceOffsetSpinBox; WuQTabWidget* m_tabWidget; static std::set allBorderSelectionViewControllers; }; #ifdef __BORDER_SELECTION_VIEW_CONTROLLER_DECLARE__ std::set BorderSelectionViewController::allBorderSelectionViewControllers; #endif // __BORDER_SELECTION_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__BORDER_SELECTION_VIEW_CONTROLLER__H_ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindow.cxx000066400000000000000000005403001360521144700237700ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_WEBKIT #include #endif #define __BRAIN_BROWSER_WINDOW_DECLARE__ #include "BrainBrowserWindow.h" #undef __BRAIN_BROWSER_WINDOW_DECLARE__ #include "AboutWorkbenchDialog.h" #include "ApplicationInformation.h" #include "BorderFile.h" #include "BorderFileSplitDialog.h" #include "Brain.h" #include "BrainBrowserWindowEditMenuItemEnum.h" #include "BrainBrowserWindowToolBar.h" #include "BrainBrowserWindowOrientedToolBox.h" #include "BrainOpenGLViewportContent.h" #include "BrainOpenGLWidget.h" #include "BrainStructure.h" #include "BrowserTabContent.h" #include "BrowserWindowContent.h" #include "CaretAssert.h" #include "CaretFileDialog.h" #include "CaretFileRemoteDialog.h" #include "CaretPreferences.h" #include "CursorDisplayScoped.h" #include "DataFileException.h" #include "DeveloperFlagsEnum.h" #include "DisplayPropertiesImages.h" #include "DisplayPropertiesVolume.h" #include "EventBrowserWindowNew.h" #include "CaretLogger.h" #include "ElapsedTimer.h" #include "EventGetViewportSize.h" #include "EventBrowserWindowCreateTabs.h" #include "EventBrowserWindowContent.h" #include "EventCaretMappableDataFilesAndMapsInDisplayedOverlays.h" #include "EventDataFileRead.h" #include "EventMacDockMenuUpdate.h" #include "EventManager.h" #include "EventModelGetAll.h" #include "EventGetOrSetUserInputModeProcessor.h" #include "EventGraphicsTimingOneWindow.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventSpecFileReadDataFiles.h" #include "EventSurfaceColoringInvalidate.h" #include "EventTileTabsConfigurationModification.h" #include "EventUserInterfaceUpdate.h" #include "FileInformation.h" #include "FociProjectionDialog.h" #include "GapsAndMargins.h" #include "GuiManager.h" #include "LockAspectWarningDialog.h" #include "ModelSurface.h" #include "ModelSurfaceMontage.h" #include "ModelWholeBrain.h" #include "PlainTextStringBuilder.h" #include "ProgressReportingDialog.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneClassAssistant.h" #include "SceneEnumeratedType.h" #include "SceneFile.h" #include "SceneFileXmlStreamFormatTester.h" #include "SceneWindowGeometry.h" #include "SessionManager.h" #include "SpacerTabContent.h" #include "SpecFile.h" #include "SpecFileManagementDialog.h" #include "StructureEnumComboBox.h" #include "Surface.h" #include "SurfaceMontageConfigurationAbstract.h" #include "SurfaceSelectionViewController.h" #include "TileTabsConfiguration.h" #include "TileTabsConfigurationModifier.h" #include "WuQDataEntryDialog.h" #include "WuQDoubleSpinBox.h" #include "WuQMacroManager.h" #include "WuQMacroMenu.h" #include "WuQMessageBox.h" #include "WuQTabBar.h" #include "WuQtUtilities.h" #include "WuQTextEditorDialog.h" #include "VtkFileExporter.h" using namespace caret; /** * Constructor. * * @param browserWindowIndex * Index for this window. * @param browserTabContent * If not NULL, this is the tab displayed in the window. * If NULL, a new tab is created. * @param parent * Parent of this object * @param flags * Flags for Qt. */ BrainBrowserWindow::BrainBrowserWindow(const int browserWindowIndex, BrowserTabContent* browserTabContent, const CreateDefaultTabsMode createDefaultTabsMode, QWidget* parent, Qt::WindowFlags flags) : QMainWindow(parent, flags), m_browserWindowIndex(browserWindowIndex) { m_developMenuAction = NULL; m_objectNamePrefix = QString("Window%1").arg((int)(browserWindowIndex + 1), 2, 10, QLatin1Char('0')); std::unique_ptr bwc = EventBrowserWindowContent::newWindowContent(m_browserWindowIndex); EventManager::get()->sendEvent(bwc->getPointer()); m_browserWindowContent = bwc->getBrowserWindowContent(); CaretAssert(m_browserWindowContent); if (BrainBrowserWindow::s_firstWindowFlag) { BrainBrowserWindow::s_firstWindowFlag = false; } setAttribute(Qt::WA_DeleteOnClose); setWindowTitle(ApplicationInformation().getName() + " " + AString::number(m_browserWindowIndex + 1)); setObjectName(windowTitle()); BrainOpenGLWidget* shareOpenGLContextWidget = NULL; if ( ! s_brainBrowserWindows.empty()) { std::set::iterator iter = s_brainBrowserWindows.begin(); CaretAssert(iter != s_brainBrowserWindows.end()); shareOpenGLContextWidget = (*iter)->m_openGLWidget; CaretAssert(shareOpenGLContextWidget); } m_openGLWidget = new BrainOpenGLWidget(this, shareOpenGLContextWidget, browserWindowIndex); const int openGLSizeX = 500; const int openGLSizeY = (WuQtUtilities::isSmallDisplay() ? 200 : 375); m_openGLWidget->setMinimumSize(openGLSizeX, openGLSizeY); setCentralWidget(m_openGLWidget); m_overlayVerticalToolBox = new BrainBrowserWindowOrientedToolBox(m_browserWindowIndex, "Overlay ToolBox", BrainBrowserWindowOrientedToolBox::TOOL_BOX_OVERLAYS_VERTICAL, m_objectNamePrefix, this); m_overlayVerticalToolBox->setAllowedAreas(Qt::LeftDockWidgetArea); m_overlayHorizontalToolBox = new BrainBrowserWindowOrientedToolBox(m_browserWindowIndex, "Overlay ToolBox ", BrainBrowserWindowOrientedToolBox::TOOL_BOX_OVERLAYS_HORIZONTAL, m_objectNamePrefix, this); m_overlayHorizontalToolBox->setAllowedAreas(Qt::BottomDockWidgetArea); if (WuQtUtilities::isSmallDisplay()) { m_overlayActiveToolBox = m_overlayVerticalToolBox; addDockWidget(Qt::LeftDockWidgetArea, m_overlayVerticalToolBox); m_overlayHorizontalToolBox->setVisible(false); } else { m_overlayActiveToolBox = m_overlayHorizontalToolBox; addDockWidget(Qt::BottomDockWidgetArea, m_overlayHorizontalToolBox); m_overlayVerticalToolBox->setVisible(false); } QObject::connect(m_overlayHorizontalToolBox, SIGNAL(visibilityChanged(bool)), this, SLOT(processOverlayHorizontalToolBoxVisibilityChanged(bool))); QObject::connect(m_overlayVerticalToolBox, SIGNAL(visibilityChanged(bool)), this, SLOT(processOverlayVerticalToolBoxVisibilityChanged(bool))); m_featuresToolBox = new BrainBrowserWindowOrientedToolBox(m_browserWindowIndex, "Features ToolBox", BrainBrowserWindowOrientedToolBox::TOOL_BOX_FEATURES, m_objectNamePrefix, this); m_featuresToolBox->setAllowedAreas(Qt::RightDockWidgetArea); addDockWidget(Qt::RightDockWidgetArea, m_featuresToolBox); createActionsUsedByToolBar(); m_overlayToolBoxAction->blockSignals(true); m_overlayToolBoxAction->setChecked(true); m_overlayToolBoxAction->blockSignals(false); m_featuresToolBoxAction->blockSignals(true); m_featuresToolBoxAction->setChecked(true); m_featuresToolBoxAction->blockSignals(false); m_toolbar = new BrainBrowserWindowToolBar(m_browserWindowIndex, browserTabContent, m_overlayToolBoxAction, m_featuresToolBoxAction, m_toolBarLockWindowAndAllTabAspectRatioButton, m_objectNamePrefix, this); m_showToolBarAction = m_toolbar->toolBarToolButtonAction; addToolBar(m_toolbar); createActions(); createMenus(); if (s_enableMacDuplicateMenuBarFlag) { s_enableMacDuplicateMenuBarFlag = false; m_toolbar->insertDuplicateMenuBar(this); } m_toolbar->updateToolBar(); processShowOverlayToolBox(m_overlayToolBoxAction->isChecked()); processHideFeaturesToolBox(); if (browserTabContent == NULL) { if (createDefaultTabsMode == CREATE_DEFAULT_TABS_YES) { m_toolbar->addDefaultTabsAfterLoadingSpecFile(); } } m_sceneAssistant = new SceneClassAssistant(); m_defaultWindowComponentStatus.isFeaturesToolBoxDisplayed = m_featuresToolBoxAction->isChecked(); m_defaultWindowComponentStatus.isOverlayToolBoxDisplayed = m_overlayToolBoxAction->isChecked(); m_defaultWindowComponentStatus.isToolBarDisplayed = m_showToolBarAction->isChecked(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_MENUS_UPDATE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GET_VIEWPORT_SIZE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_TILE_TABS_MODIFICATION); if (m_overlayHorizontalToolBox == m_overlayActiveToolBox) { /* * With Qt5, default height of overlay toolbox at bottom is * way too tall. Qt 5.6 added a 'resizeDocks' method and * it is used to initialize the height of the overlay toolbox. */ const int toolboxHeight = 150; QList docks; docks.push_back(m_overlayHorizontalToolBox); QList dockSizes; dockSizes.push_back(toolboxHeight); resizeDockWidgets(docks, dockSizes, Qt::Vertical); } s_brainBrowserWindows.insert(this); GapsAndMargins* gapsAndMargins = GuiManager::get()->getBrain()->getGapsAndMargins(); gapsAndMargins->setSurfaceMontageHorizontalGapForWindow(m_browserWindowIndex, 0.0f); gapsAndMargins->setSurfaceMontageVerticalGapForWindow(m_browserWindowIndex, 0.0f); gapsAndMargins->setVolumeMontageHorizontalGapForWindow(m_browserWindowIndex, 0.0f); gapsAndMargins->setVolumeMontageVerticalGapForWindow(m_browserWindowIndex, 0.0f); /* * Allows keyboard events */ setFocusPolicy(Qt::StrongFocus); } /** * Destructor. */ BrainBrowserWindow::~BrainBrowserWindow() { std::unique_ptr bwc = EventBrowserWindowContent::deleteWindowContent(m_browserWindowIndex); EventManager::get()->sendEvent(bwc->getPointer()); m_browserWindowContent = NULL; EventManager::get()->removeAllEventsFromListener(this); s_brainBrowserWindows.erase(this); if (s_brainBrowserWindows.empty()) { } delete m_sceneAssistant; } /** * Receive an event. * * @param event * The event that the receive can respond to. */ void BrainBrowserWindow::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_MENUS_UPDATE) { const CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); if (m_developMenuAction != NULL) { m_developMenuAction->setVisible(prefs->isDevelopMenuEnabled()); event->setEventProcessed(); } } else if (event->getEventType()== EventTypeEnum::EVENT_CARET_MAPPABLE_DATA_FILES_AND_MAPS_IN_DISPLAYED_OVERLAYS) { EventCaretMappableDataFilesAndMapsInDisplayedOverlays* filesEvent = dynamic_cast(event); CaretAssert(filesEvent); /* * If true, all tabs are included even if tile tabs is off */ const bool useAllTabsFlag(true); std::vector tabContent; if (isTileTabsSelected() || useAllTabsFlag) { m_toolbar->getAllTabContent(tabContent); } else { BrowserTabContent* btc = m_toolbar->getTabContentFromSelectedTab(); if (btc != NULL) { tabContent.push_back(btc); } } for (auto btc : tabContent) { btc->getFilesAndMapIndicesInOverlays(filesEvent); } } else if (event->getEventType() == EventTypeEnum::EVENT_GET_VIEWPORT_SIZE) { EventGetViewportSize* viewportSizeEvent = dynamic_cast(event); CaretAssert(viewportSizeEvent); std::vector allViewportContent = m_openGLWidget->getViewportContent(); int32_t viewport[4] = { 0, 0, 0, 0 }; bool viewportValid = false; int32_t notBestViewport[4] = { 0, 0, 0, 0 }; bool notBestViewportValid = false; switch (viewportSizeEvent->getMode()) { case EventGetViewportSize::MODE_SPACER_TAB_INDEX: for (std::vector::iterator vpIter = allViewportContent.begin(); vpIter != allViewportContent.end(); vpIter++) { const SpacerTabIndex requestedSpacerTabIndex = viewportSizeEvent->getSpacerTabIndex(); const BrainOpenGLViewportContent* vpContent = *vpIter; if (vpContent != NULL) { SpacerTabContent* stc = vpContent->getSpacerTabContent(); if (stc != NULL) { if (requestedSpacerTabIndex == stc->getSpacerTabIndex()) { vpContent->getTabViewportBeforeApplyingMargins(viewport); viewportValid = true; break; } } } } break; case EventGetViewportSize::MODE_SURFACE_MONTAGE: if (viewportSizeEvent->getIndex() == m_browserWindowIndex) { /* * Find a surface montage in this window */ for (std::vector::iterator vpIter = allViewportContent.begin(); vpIter != allViewportContent.end(); vpIter++) { const BrainOpenGLViewportContent* vpContent = *vpIter; if (vpContent != NULL) { BrowserTabContent* btc = vpContent->getBrowserTabContent(); if (btc != NULL) { const Model* model = btc->getModelForDisplay(); if (model->getModelType() == ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE) { vpContent->getTabViewportBeforeApplyingMargins(viewport); viewportValid = true; break; } } } } } break; case EventGetViewportSize::MODE_TAB_BEFORE_MARGINS_INDEX: for (std::vector::iterator vpIter = allViewportContent.begin(); vpIter != allViewportContent.end(); vpIter++) { const BrainOpenGLViewportContent* vpContent = *vpIter; if (vpContent != NULL) { BrowserTabContent* btc = vpContent->getBrowserTabContent(); if (btc != NULL) { if (btc->getTabNumber() == viewportSizeEvent->getIndex()) { for (std::vector::const_iterator vpIter = allViewportContent.begin(); vpIter != allViewportContent.end(); vpIter++) { const BrainOpenGLViewportContent* vpContent = *vpIter; if (vpContent->getTabIndex() == viewportSizeEvent->getIndex()) { vpContent->getTabViewportBeforeApplyingMargins(viewport); viewportValid = true; break; } } } } } } break; case EventGetViewportSize::MODE_TAB_AFTER_MARGINS_INDEX: for (std::vector::iterator vpIter = allViewportContent.begin(); vpIter != allViewportContent.end(); vpIter++) { const BrainOpenGLViewportContent* vpContent = *vpIter; if (vpContent != NULL) { BrowserTabContent* btc = vpContent->getBrowserTabContent(); if (btc != NULL) { if (btc->getTabNumber() == viewportSizeEvent->getIndex()) { for (std::vector::const_iterator vpIter = allViewportContent.begin(); vpIter != allViewportContent.end(); vpIter++) { const BrainOpenGLViewportContent* vpContent = *vpIter; if (vpContent->getTabIndex() == viewportSizeEvent->getIndex()) { vpContent->getModelViewport(viewport); viewportValid = true; break; } } } } } } break; case EventGetViewportSize::MODE_VOLUME_MONTAGE: if (viewportSizeEvent->getIndex() == m_browserWindowIndex) { /* * Find the viewport content containing the specified tab by index */ for (std::vector::iterator vpIter = allViewportContent.begin(); vpIter != allViewportContent.end(); vpIter++) { const BrainOpenGLViewportContent* vpContent = *vpIter; if (vpContent != NULL) { BrowserTabContent* btc = vpContent->getBrowserTabContent(); if (btc != NULL) { const Model* model = btc->getModelForDisplay(); if (model->getModelType() == ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES) { if (btc->getSliceDrawingType() == VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_MONTAGE) { vpContent->getTabViewportBeforeApplyingMargins(viewport); viewportValid = true; break; } else { vpContent->getTabViewportBeforeApplyingMargins(notBestViewport); notBestViewportValid = true; } } } } } } break; case EventGetViewportSize::MODE_WINDOW_INDEX: if (m_browserWindowIndex == viewportSizeEvent->getIndex()) { for (std::vector::iterator vpIter = allViewportContent.begin(); vpIter != allViewportContent.end(); vpIter++) { const BrainOpenGLViewportContent* vpContent = *vpIter; if (vpContent != NULL) { vpContent->getWindowViewport(viewport); viewportValid = true; } } } break; } if ( ! viewportValid) { if (notBestViewportValid) { viewport[0] = notBestViewport[0]; viewport[1] = notBestViewport[1]; viewport[2] = notBestViewport[2]; viewport[3] = notBestViewport[3]; viewportValid = true; } else { /* * Tab is in this window but not the active tab. * So, use the active tab's viewport */ if ( ! allViewportContent.empty()) { CaretAssertVectorIndex(allViewportContent, 0); allViewportContent[0]->getTabViewportBeforeApplyingMargins(viewport); viewportValid = true; } } } if (viewportValid) { viewportSizeEvent->setViewportSize(viewport); } } else if (event->getEventType() == EventTypeEnum::EVENT_TILE_TABS_MODIFICATION) { EventTileTabsConfigurationModification* modEvent = dynamic_cast(event); CaretAssert(modEvent); if (modEvent->getWindowIndex() == this->m_browserWindowIndex) { modifyTileTabsConfiguration(modEvent); } } else if ((event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW) || (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS)) { /* * When in annotations mode, items on the Edit Menu are enabled/disabled * based upon the selected annotations. While we can update the menu items * when the menu is about to show, that is sufficient. The menu items * have shortcut keys so it is possible for the selected annotations to change * and the user to use a short cut key but the item on the edit menu * may still be disabled. Since a change in the selected annotations is * followed by a graphics update event, update the enabled/disabled status * of items in the Edit menu when the graphics are updated so that the * shortcut keys will function. */ processEditMenuAboutToShow(); } } /** * Resize the Dock Widgets (same as QMainWindow::resizeDocks in Qt 5.7 and later) * * @param docks * The dock widgets. * @param sizes * Sizes for the dock widgets * @param orientation * Orientation for resizing. */ void BrainBrowserWindow::resizeDockWidgets(const QList &docks, const QList &sizes, Qt::Orientation orientation) { CaretAssert(docks.size() == sizes.size()); #if QT_VERSION >= 0x050600 resizeDocks(docks, sizes, orientation); #else const int32_t numDocks = std::min(docks.size(), sizes.size()); for (int32_t i = 0; i < numDocks; i++) { CaretAssert(docks[i]); BrainBrowserWindowOrientedToolBox* tb = dynamic_cast(docks[i]); CaretAssert(tb); switch (orientation) { case Qt::Horizontal: tb->setSizeHintWidth(sizes[i]); break; case Qt::Vertical: tb->setSizeHintHeight(sizes[i]); break; } } #endif } /** * @return True if OpenGL Context Sharing is valid among * multiple graphics windows. * Note: If there is one window, we declare sharing valid. */ bool BrainBrowserWindow::isOpenGLContextSharingValid() const { CaretAssert(m_openGLWidget); return m_openGLWidget->isOpenGLContextSharingValid(); } /** * Reset the graphics window size. * When the window is created, the graphics is set to a reasonable size * by setting the minimum size of the graphics region. If the minimum * size is small, */ void BrainBrowserWindow::resetGraphicsWidgetMinimumSize() { m_openGLWidget->setMinimumSize(100, 100); } void BrainBrowserWindow::setGraphicsWidgetFixedSize(const int32_t width, const int32_t height) { m_openGLWidget->setFixedSize(width, height); } /** * Get the graphics widget size. * * @param viewportXOut * X-coord of viewport in graphics region (may be non-zero when lock aspect applied) * @param viewportYOut * Y-coord of viewport in graphics region (may be non-zero when lock aspect applied) * @param viewportWidthOut * Width of the viewport into which graphics are drawn (may be less than * graphicsWidthOut when lock aspect is applied) * @param viewportHeightOut * Height of the viewport into which graphics are drawn (may be less than * graphicsHeightOut when lock aspect is applied) * @param openGLWidgetWidthOut * True width of the OpenGL Widget. * @param openGLWidgetHeightOut * True height of the OpenGL Widget. * @param applyLockedAspectRatiosFlag * True if locked tab or window aspect ratio should be applied for * viewport but only if lock aspect is enabled by the user. */ void BrainBrowserWindow::getGraphicsWidgetSize(int32_t& viewportXOut, int32_t& viewportYOut, int32_t& viewportWidthOut, int32_t& viewportHeightOut, int32_t& openGLWidgetWidthOut, int32_t& openGLWidgetHeightOut, const bool applyLockedAspectRatiosFlag) const { viewportXOut = 0; viewportYOut = 0; openGLWidgetWidthOut = m_openGLWidget->width(); openGLWidgetHeightOut = m_openGLWidget->height(); viewportWidthOut = m_openGLWidget->width(); viewportHeightOut = m_openGLWidget->height(); int aspectViewport[4] = { 0, 0, openGLWidgetWidthOut, openGLWidgetHeightOut }; if (isTileTabsSelected()) { if (isWindowAspectRatioLocked()) { BrainOpenGLViewportContent::adjustViewportForAspectRatio(aspectViewport, getAspectRatio()); } } else { const BrowserTabContent* btc = getBrowserTabContent(); if (btc != NULL) { if (btc->isAspectRatioLocked()) { BrainOpenGLViewportContent::adjustViewportForAspectRatio(aspectViewport, btc->getAspectRatio()); } else if (isWindowAspectRatioLocked()) { BrainOpenGLViewportContent::adjustViewportForAspectRatio(aspectViewport, getAspectRatio()); } } } if (applyLockedAspectRatiosFlag) { const std::vector allViewportContent = m_openGLWidget->getViewportContent(); if ( ! allViewportContent.empty()) { CaretAssertVectorIndex(allViewportContent, 0); int windowViewport[4]; allViewportContent[0]->getWindowViewport(windowViewport); const float windowWidth = windowViewport[2]; const float windowHeight = windowViewport[3]; if ((windowWidth > 0) && (windowHeight > 0)) { if ((windowWidth != viewportWidthOut) || (windowHeight != viewportHeightOut)) { viewportXOut = windowViewport[0]; viewportYOut = windowViewport[1]; viewportWidthOut = windowWidth; viewportHeightOut = windowHeight; } } } } } /** * @return True if tile tabs is selected, else false. */ bool BrainBrowserWindow::isTileTabsSelected() const { return m_browserWindowContent->isTileTabsEnabled(); } /** * @return the index of this browser window. */ int32_t BrainBrowserWindow::getBrowserWindowIndex() const { return m_browserWindowIndex; } /** * Called when the window is requested to close. * * @param event * CloseEvent that may or may not be accepted * allowing the window to close. */ void BrainBrowserWindow::closeEvent(QCloseEvent* event) { if (m_closeWithoutConfirmationFlag) { m_closeWithoutConfirmationFlag = false; event->accept(); return; } /* * The GuiManager may warn user about closing the * window and the user may cancel closing of the window. */ GuiManager* guiManager = GuiManager::get(); if (guiManager->allowBrainBrowserWindowToClose(this, m_toolbar->tabBar->count())) { event->accept(); } else { event->ignore(); } } /** * Called when a key is pressed. * * @param event * The key event. */ void BrainBrowserWindow::keyPressEvent(QKeyEvent* event) { /* * When there is a key press, it may take time to process such * as when a macro runs. If the macro calls QApplication::processEvents(), * it may result in this method getting called again by Qt * before the macro has completed from a previous key press event. * This flag will ignore key press events until a macro * has had time to finish */ if (m_keyEventProcessingFlag) { return; } m_keyEventProcessingFlag = true; bool keyEventWasProcessed = false; /* * Pressing the Escape Key exits full screen mode. */ if (event->key() == Qt::Key_Escape) { if (event->modifiers() == Qt::NoModifier) { if (isFullScreen()) { processViewFullScreenSelected(); keyEventWasProcessed = true; } } } if ( ! keyEventWasProcessed) { keyEventWasProcessed = WuQMacroManager::instance()->runMacroWithShortCutKeyEvent(this, event); } /* * According to the documentation, if the key event was not acted upon, * pass it on the base class implementation. */ if ( ! keyEventWasProcessed) { QMainWindow::keyPressEvent(event); } m_keyEventProcessingFlag = false; } /** * Create actions for this window. * NOTE: This is called BEFORE the toolbar is created. */ void BrainBrowserWindow::createActionsUsedByToolBar() { QIcon featuresToolBoxIcon; const bool featuresToolBoxIconValid = WuQtUtilities::loadIcon(":/ToolBar/features_toolbox.png", featuresToolBoxIcon); QIcon overlayToolBoxIcon; const bool overlayToolBoxIconValid = WuQtUtilities::loadIcon(":/ToolBar/overlay_toolbox.png", overlayToolBoxIcon); /* * Note: The name of a dock widget becomes its * name in the toggleViewAction(). So, use * a separate action here so that the name in * the menu is as set here. */ m_overlayToolBoxAction = WuQtUtilities::createAction("Overlay ToolBox", "Overlay ToolBox", this, this, SLOT(processShowOverlayToolBox(bool))); m_overlayToolBoxAction->setCheckable(true); if (overlayToolBoxIconValid) { m_overlayToolBoxAction->setIcon(overlayToolBoxIcon); m_overlayToolBoxAction->setIconVisibleInMenu(false); } else { m_overlayToolBoxAction->setIconText("OT"); } m_overlayToolBoxAction->setObjectName(m_objectNamePrefix + ":ToolBar:ShowOverlayToolBox"); WuQMacroManager::instance()->addMacroSupportToObject(m_overlayToolBoxAction, ("Show overlay toolbox in window " + QString::number(m_browserWindowIndex + 1))); /* * Note: The name of a dock widget becomes its * name in the toggleViewAction(). So, use * a separate action here so that the name in * the menu is as set here. */ m_featuresToolBoxAction = m_featuresToolBox->toggleViewAction(); m_featuresToolBoxAction->setCheckable(true); QObject::connect(m_featuresToolBoxAction, SIGNAL(triggered(bool)), this, SLOT(processShowFeaturesToolBox(bool))); if (featuresToolBoxIconValid) { m_featuresToolBoxAction->setIcon(featuresToolBoxIcon); m_featuresToolBoxAction->setIconVisibleInMenu(false); } else { m_featuresToolBoxAction->setIconText("LT"); } m_featuresToolBoxAction->setObjectName(m_objectNamePrefix + ":ToolBar:ShowFeaturesToolBox"); WuQMacroManager::instance()->addMacroSupportToObject(m_featuresToolBoxAction, ("Show features toolbox in window " + QString::number(m_browserWindowIndex + 1))); m_windowMenuLockWindowAspectRatioAction = new QAction(this); m_windowMenuLockWindowAspectRatioAction->setCheckable(true); m_windowMenuLockWindowAspectRatioAction->setChecked(m_browserWindowContent->isWindowAspectLocked()); m_windowMenuLockWindowAspectRatioAction->setText("Lock Window Aspect Ratio"); m_windowMenuLockWindowAspectRatioAction->setShortcut(Qt::SHIFT + Qt::CTRL+Qt::Key_K); QObject::connect(m_windowMenuLockWindowAspectRatioAction, &QAction::triggered, this, &BrainBrowserWindow::processWindowMenuLockWindowAspectRatioTriggered); m_windowMenuLockAllTabAspectRatioAction = new QAction(this); m_windowMenuLockAllTabAspectRatioAction->setCheckable(true); m_windowMenuLockAllTabAspectRatioAction->setChecked(false); m_windowMenuLockAllTabAspectRatioAction->setText("Lock All Tab Aspect Ratios"); m_windowMenuLockAllTabAspectRatioAction->setShortcut(Qt::CTRL+Qt::Key_K); QObject::connect(m_windowMenuLockAllTabAspectRatioAction, &QAction::triggered, this, &BrainBrowserWindow::processWindowMenuLockAllTabAspectRatioTriggered); const QString aspectButtonToolTipText("" "Lock the aspect ratio of the window and all tabs. " "Aspect ratios should be locked prior to creating " "annotations and remain locked while annotations are " "present." "

" "Advanced users can right-click (control-click on Mac) " "to manually adjust the aspect " "ratio for the selected tab or the window." ""); m_toolBarLockWindowAndAllTabAspectRatioAction = new QAction(this); m_toolBarLockWindowAndAllTabAspectRatioAction->setCheckable(true); m_toolBarLockWindowAndAllTabAspectRatioAction->setChecked(false); m_toolBarLockWindowAndAllTabAspectRatioAction->setText("Lock Aspect"); m_toolBarLockWindowAndAllTabAspectRatioAction->setToolTip(aspectButtonToolTipText); QObject::connect(m_toolBarLockWindowAndAllTabAspectRatioAction, &QAction::triggered, this, &BrainBrowserWindow::processToolBarLockWindowAndAllTabAspectTriggered); m_toolBarLockWindowAndAllTabAspectRatioAction->setObjectName(m_objectNamePrefix + ":ToolBar:LockAspectRatio"); WuQMacroManager::instance()->addMacroSupportToObject(m_toolBarLockWindowAndAllTabAspectRatioAction, ("Lock aspect ratio in window " + QString::number(m_browserWindowIndex + 1))); /* * Button for locking aspect is passed to ToolBar's constructor * and is displayed on the toolbar */ m_toolBarLockWindowAndAllTabAspectRatioButton = new QToolButton(); m_toolBarLockWindowAndAllTabAspectRatioButton->setDefaultAction(m_toolBarLockWindowAndAllTabAspectRatioAction); WuQtUtilities::setToolButtonStyleForQt5Mac(m_toolBarLockWindowAndAllTabAspectRatioButton); QObject::connect(m_toolBarLockWindowAndAllTabAspectRatioButton, &QToolButton::customContextMenuRequested, this, &BrainBrowserWindow::processToolBarLockWindowAndAllTabAspectMenu); m_toolBarLockWindowAndAllTabAspectRatioButton->setContextMenuPolicy(Qt::CustomContextMenu); } /** * Is called by toolbar when the user changes input mode to annotations. * * @return * True if it is okay to change to annotations mode, else false. */ bool BrainBrowserWindow::changeInputModeToAnnotationsWarningDialog() { LockAspectWarningDialog::Result result = LockAspectWarningDialog::runDialogEnterAnnotationsMode(m_browserWindowIndex); bool okFlag = true; switch (result) { case LockAspectWarningDialog::Result::CANCEL: okFlag = false; break; case LockAspectWarningDialog::Result::LOCK_ASPECT: processToolBarLockWindowAndAllTabAspectsRatios(true); break; case LockAspectWarningDialog::Result::NO_CHANGES: break; } return okFlag; } /** * Called when the window menu's lock window aspect is triggered by user. * * @param checked * True if checked, false if unchecked */ void BrainBrowserWindow::processWindowMenuLockWindowAspectRatioTriggered(bool checked) { lockWindowAspectRatio(checked); updateActionsForLockingAspectRatios(); } /** * Called when the window menu's lock all tab aspect is triggered by user * * @param checked * True if checked, false if unchecked */ void BrainBrowserWindow::processWindowMenuLockAllTabAspectRatioTriggered(bool checked) { lockAllTabAspectRatios(checked); updateActionsForLockingAspectRatios(); } /** * Lock the window's aspect ratio and if it transitions from * unlocked to locked, set the aspect ratio. */ void BrainBrowserWindow::lockWindowAspectRatio(const bool checked) { const bool oldCheckedStatus = m_browserWindowContent->isWindowAspectLocked(); m_browserWindowContent->setWindowAspectLocked(checked); if (checked) { if ( ! oldCheckedStatus) { m_browserWindowContent->setWindowAspectLockedRatio(getOpenGLWidgetAspectRatio()); } } } /** * Lock the window's aspect ratio and if it transitions from * unlocked to locked, set the aspect ratio. */ void BrainBrowserWindow::lockAllTabAspectRatios(const bool checked) { m_browserWindowContent->setAllTabsInWindowAspectRatioLocked(checked); if (checked) { /* * Locking takes place in BrainOpenGLViewportContent * when the tab is drawn as the size of the viewport * is needed. */ } else { /* * Turn off lock aspect for all tabs */ std::vector allTabContent; m_toolbar->getAllTabContent(allTabContent); for (auto tab : allTabContent) { tab->setAspectRatioLocked(false); } } } /** * Called when the toolbar's lock window and all tab aspect is triggered * * @param checked * True if checked, false if unchecked */ void BrainBrowserWindow::processToolBarLockWindowAndAllTabAspectTriggered(bool checked) { if (checked) { std::vector allTabContent; m_toolbar->getAllTabContent(allTabContent); const int32_t tabCount = static_cast(allTabContent.size()); const bool lockFlag = LockAspectWarningDialog::runDialogToolBarLockAspect(this, tabCount); if ( ! lockFlag) { m_toolBarLockWindowAndAllTabAspectRatioAction->setChecked(false); return; } } processToolBarLockWindowAndAllTabAspectsRatios(checked); } /** * Called when the toolbar's lock window and all tab aspect is triggered * * @param checked * True if checked, false if unchecked */ void BrainBrowserWindow::processToolBarLockWindowAndAllTabAspectsRatios(bool checked) { lockWindowAspectRatio(checked); lockAllTabAspectRatios(checked); updateActionsForLockingAspectRatios(); } /** * Called when an item is selected from the lock aspect action menu * * @param pos * Location of click. */ void BrainBrowserWindow::processToolBarLockWindowAndAllTabAspectMenu(const QPoint& pos) { BrowserTabContent* tabContent = getBrowserTabContent(); if (tabContent != NULL) { QMenu menu; QAction* tabAspectAction = menu.addAction("Set Selected Tab Aspect Ratio..."); QAction* windowAspectAction = menu.addAction("Set Window Aspect Ratio..."); QAction* selectedAction = menu.exec(m_toolBarLockWindowAndAllTabAspectRatioButton->parentWidget()->mapToGlobal(pos)); if (selectedAction == windowAspectAction) { float aspectRatio = getAspectRatioFromDialog(AspectRatioMode::WINDOW, ("Window " + AString::number(m_browserWindowIndex + 1) + " Aspect Ratio"), getAspectRatio(), this); if (aspectRatio > 0.0f) { aspectRatioDialogUpdateForWindow(aspectRatio); } } else if (selectedAction == tabAspectAction) { float aspectRatio = tabContent->getAspectRatio(); if ( ! tabContent->isAspectRatioLocked()) { /* * When aspect is NOT locked, need to get current aspect ratio */ aspectRatio = getOpenGLWidgetAspectRatio(); if (isTileTabsSelected()) { /* * When tile tabs is enabled, find the tab to get its aspect ratio */ std::vector allViewportContent = m_openGLWidget->getViewportContent(); for (auto vc : allViewportContent) { if (vc->getTabIndex() == tabContent->getTabNumber()) { int viewport[4]; vc->getModelViewport(viewport); if (viewport[3] > 0) { aspectRatio = (static_cast(viewport[3]) / static_cast(viewport[2])); break; } } } } } aspectRatio = getAspectRatioFromDialog(AspectRatioMode::TAB, ("Tab " + tabContent->getTabName() + " Aspect Ratio"), aspectRatio, this); if (aspectRatio > 0.0f) { aspectRatioDialogUpdateForTab(aspectRatio); } } } } /** * Get the new aspect ratio using a dialog. * * @param aspectRatioMode * Mode (tab or window) * @param title * Title for dialog. * @param originalAspectRatio * Default value for aspect ratio * @param parent * Parent for the dialog. */ float BrainBrowserWindow::getAspectRatioFromDialog(const AspectRatioMode aspectRatioMode, const QString& title, const float aspectRatio, QWidget* parent) const { float aspectRatioOut = -1.0; WuQDataEntryDialog ded("Set Aspect Ratio", parent); ded.setCancelButtonText(""); QDoubleSpinBox* ratioSpinBox = ded.addDoubleSpinBox(title, aspectRatio); ratioSpinBox->setSingleStep(0.01); ratioSpinBox->setRange(ratioSpinBox->singleStep(), 100.0); ratioSpinBox->setDecimals(3); ratioSpinBox->setKeyboardTracking(true); switch (aspectRatioMode) { case AspectRatioMode::TAB: QObject::connect(ratioSpinBox, static_cast(&QDoubleSpinBox::valueChanged), this, &BrainBrowserWindow::aspectRatioDialogUpdateForTab); break; case AspectRatioMode::WINDOW: QObject::connect(ratioSpinBox, static_cast(&QDoubleSpinBox::valueChanged), this, &BrainBrowserWindow::aspectRatioDialogUpdateForWindow); break; } if (ded.exec() == WuQDataEntryDialog::Accepted) { aspectRatioOut = ratioSpinBox->value(); } return aspectRatioOut; } /** * Called when the user manually adjust aspect ratio for all tabs. * * @param aspectRatio * New aspect ratio. */ void BrainBrowserWindow::aspectRatioDialogUpdateForTab(const double aspectRatio) { BrowserTabContent* tabContent = getBrowserTabContent(); if (aspectRatio > 0.0f) { lockAllTabAspectRatios(true); tabContent->setAspectRatio(aspectRatio); tabContent->setAspectRatioLocked(true); } updateActionsForLockingAspectRatios(); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); } /** * Called when the user manually adjust aspect ratio for window. * * @param aspectRatio * New aspect ratio. */ void BrainBrowserWindow::aspectRatioDialogUpdateForWindow(const double aspectRatio) { if (aspectRatio > 0.0f) { lockWindowAspectRatio(true); m_browserWindowContent->setWindowAspectLockedRatio(aspectRatio); } updateActionsForLockingAspectRatios(); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); } /** * Update the actions for window menu's lock window aspect, window menu's lock * all tab aspect, and the toolbar's lock window and all tab aspect. */ void BrainBrowserWindow::updateActionsForLockingAspectRatios() { QSignalBlocker windowAspectBlocker(m_windowMenuLockWindowAspectRatioAction); m_windowMenuLockWindowAspectRatioAction->setChecked(m_browserWindowContent->isWindowAspectLocked()); QSignalBlocker tabAspectBlocker(m_windowMenuLockAllTabAspectRatioAction); m_windowMenuLockAllTabAspectRatioAction->setChecked(m_browserWindowContent->isAllTabsInWindowAspectRatioLocked()); QSignalBlocker toolbarLockAllBlocker(m_toolBarLockWindowAndAllTabAspectRatioAction); m_toolBarLockWindowAndAllTabAspectRatioAction->setChecked(m_browserWindowContent->isWindowAspectLocked() && m_browserWindowContent->isAllTabsInWindowAspectRatioLocked()); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); } /** * @return Is the aspect ratio locked? */ bool BrainBrowserWindow::isWindowAspectRatioLocked() const { return m_browserWindowContent->isWindowAspectLocked(); } /** * @return The aspect ratio. */ float BrainBrowserWindow::getAspectRatio() const { if ( ! m_browserWindowContent->isWindowAspectLocked()) { /* * When aspect NOT locked, use the OpenGL widget's aspect ratio */ m_browserWindowContent->setWindowAspectLockedRatio(getOpenGLWidgetAspectRatio()); } return m_browserWindowContent->getWindowAspectLockedRatio(); } /** * Show the surface properties editor dialog. */ void BrainBrowserWindow::processShowSurfacePropertiesDialog() { GuiManager::get()->processShowSurfacePropertiesEditorDialog(this); } /** * Show the volume properties editor dialog. */ void BrainBrowserWindow::processShowVolumePropertiesDialog() { GuiManager::get()->processShowVolumePropertiesEditorDialog(this); } /** * Create actions for this window. * NOTE: This is called AFTER the toolbar is created. */ void BrainBrowserWindow::createActions() { CaretAssert(m_toolbar); GuiManager* guiManager = GuiManager::get(); m_aboutWorkbenchAction = WuQtUtilities::createAction("About Workbench...", "Information about Workbench", this, this, SLOT(processAboutWorkbench())); m_newWindowAction = WuQtUtilities::createAction("New Window", "Creates a new window for viewing brain models", Qt::CTRL+Qt::Key_N, this, this, SLOT(processNewWindow())); m_newTabAction = WuQtUtilities::createAction("New Tab", "Create a new tab (window pane) in the window", Qt::CTRL + Qt::Key_T, this, this, SLOT(processNewTab())); m_newTabAction->setObjectName(m_objectNamePrefix + ":Menu:NewTabAction"); WuQMacroManager::instance()->addMacroSupportToObject(m_newTabAction, ("Create new tab in Window " + QString::number(m_browserWindowIndex + 1))); m_duplicateTabAction = WuQtUtilities::createAction("Duplicate Tab", "Create a new tab (window pane) that duplicates the selected tab in the window", Qt::CTRL + Qt::Key_D, this, this, SLOT(processDuplicateTab())); m_duplicateTabAction->setObjectName(m_objectNamePrefix + ":Menu:DuplicateTabAction"); WuQMacroManager::instance()->addMacroSupportToObject(m_duplicateTabAction, ("Duplicate tab in Window " + QString::number(m_browserWindowIndex + 1))); m_openFileAction = WuQtUtilities::createAction("Open File...", "Open a data file including a spec file located on the computer", Qt::CTRL+Qt::Key_O, this, this, SLOT(processDataFileOpen())); m_openFileAction->setShortcutContext(Qt::ApplicationShortcut); m_openLocationAction = WuQtUtilities::createAction("Open Location...", "Open a data file including a spec file located on a web server (http)", Qt::CTRL+Qt::Key_L, this, this, SLOT(processDataFileLocationOpen())); m_openLocationAction->setShortcutContext(Qt::ApplicationShortcut); m_manageFilesAction = WuQtUtilities::createAction("Save/Manage Files...", "Save and Manage Loaded Files", Qt::CTRL + Qt::Key_S, this, this, SLOT(processManageSaveLoadedFiles())); m_manageFilesAction->setShortcutContext(Qt::ApplicationShortcut); m_closeSpecFileAction = WuQtUtilities::createAction("Close All Files", "Close all loaded files", this, this, SLOT(processCloseAllFiles())); m_closeTabAction = WuQtUtilities::createAction("Close Tab", "Close the active tab (window pane) in the window", Qt::CTRL + Qt::Key_W, this, m_toolbar, SLOT(closeSelectedTab())); m_closeWithoutConfirmationFlag = false; m_closeWindowActionConfirmTitle = "Close Window..."; m_closeWindowActionNoConfirmTitle = "Close Window"; m_closeWindowAction = WuQtUtilities::createAction(m_closeWindowActionConfirmTitle, "Close the window", Qt::CTRL + Qt::SHIFT + Qt::Key_W, this, this, SLOT(processCloseWindow())); m_captureImageAction = WuQtUtilities::createAction("Capture Image...", "Capture an Image of the windows content", this, this, SLOT(processCaptureImage())); m_movieRecordingAction = WuQtUtilities::createAction("Movie Recording...", "Record the windows content", this, this, SLOT(processMovieRecording())); m_recordMovieAction = WuQtUtilities::createAction("(obsolete)Animation Control...", "Animate Brain Surface", this, this, SLOT(processRecordMovie())); m_preferencesAction = WuQtUtilities::createAction("Preferences...", "Edit the preferences", this, this, SLOT(processEditPreferences())); m_exitProgramAction = WuQtUtilities::createAction("Exit", "Exit (quit) the program", Qt::CTRL+Qt::Key_Q, this, this, SLOT(processExitProgram())); m_dataFociProjectAction = WuQtUtilities::createAction("Project Foci...", "Project Foci to Surfaces", this, this, SLOT(processProjectFoci())); m_dataBorderFilesSplitAction = WuQtUtilities::createAction("Split Multi-Structure Border File(s)...", "Split Multi-Structure Border File(s", this, this, SLOT(processSplitBorderFiles())); m_viewFullScreenAction = WuQtUtilities::createAction("Full Screen", "View using all of screen", Qt::CTRL+Qt::Key_F, this); QObject::connect(m_viewFullScreenAction, SIGNAL(triggered()), this, SLOT(processViewFullScreenSelected())); /* * "Full Screen" Fix on MacOS with Qt 5.12: * Without this, the menu item may disappear on MacOS */ m_viewFullScreenAction->setMenuRole(QAction::NoRole); /* * Note: If shortcut key is changed, also change the shortcut key * for the tile tabs configuration dialog menu item to match. */ m_viewTileTabsAction = WuQtUtilities::createAction("Tile Tabs", "View all tabs in a tiled layout", Qt::CTRL+Qt::Key_M, this); QObject::connect(m_viewTileTabsAction, SIGNAL(triggered()), this, SLOT(processViewTileTabs())); /* * Fix on MacOS with Qt 5.12: * Set role to 'NoRole' or else Qt may interpret * "Enter Tile Tabs" and "Exit Tile Tabs" as "Enter * Full Screen" and remove this item from the menu */ m_viewTileTabsAction->setMenuRole(QAction::NoRole); m_viewTileTabsConfigurationDialogAction = WuQtUtilities::createAction("Edit Tile Tabs Configurations...", "", this, this, SLOT(processViewTileTabsConfigurationDialog())); m_viewTileTabsConfigurationDialogAction->setShortcut((Qt::CTRL + Qt::SHIFT + Qt::Key_M)); m_viewAutomaticTileTabsConfigurationAction = new QAction("Automatic", this); m_viewAutomaticTileTabsConfigurationAction->setCheckable(true); m_viewCustomTileTabsConfigurationAction = new QAction("Custom", this); m_viewCustomTileTabsConfigurationAction->setCheckable(true); QActionGroup* autoCustomGroup = new QActionGroup(this); autoCustomGroup->setExclusive(true); autoCustomGroup->addAction(m_viewAutomaticTileTabsConfigurationAction); autoCustomGroup->addAction(m_viewCustomTileTabsConfigurationAction); QObject::connect(autoCustomGroup, &QActionGroup::triggered, this, &BrainBrowserWindow::processViewTileTabsAutomaticCustomTriggered); m_gapsAndMarginsAction = WuQtUtilities::createAction("Gaps and Margins...", "Adjust the gaps and margins", this, this, SLOT(processGapsAndMargins())); m_nextTabAction = WuQtUtilities::createAction("Next Tab", "Move to the next tab", Qt::CTRL + Qt::Key_Right, this, m_toolbar, SLOT(nextTab())); m_previousTabAction = WuQtUtilities::createAction("Previous Tab", "Move to the previous tab", Qt::CTRL + Qt::Key_Left, this, m_toolbar, SLOT(previousTab())); m_renameSelectedTabAction = WuQtUtilities::createAction("Rename Selected Tab...", "Change the name of the selected tab", this, m_toolbar, SLOT(renameTab())); m_moveTabsInWindowToNewWindowsAction = WuQtUtilities::createAction("Move All Tabs in Current Window to New Windows", "Move all but the left most tab to new windows", this, m_toolbar, SLOT(moveTabsToNewWindows())); m_moveTabsFromAllWindowsToOneWindowAction = WuQtUtilities::createAction("Move All Tabs From All Windows Into Selected Window", "Move all tabs from all windows into selected window", this, this, SLOT(processMoveAllTabsToOneWindow())); m_bringAllToFrontAction = WuQtUtilities::createAction("Bring All To Front", "Move all windows on top of other application windows", this, guiManager, SLOT(processBringAllWindowsToFront())); m_tileWindowsAction = WuQtUtilities::createAction("Tile Windows", "Arrange the windows into grid so that the fill the screen", this, guiManager, SLOT(processTileWindows())); m_informationDialogAction = WuQtUtilities::createAction("Information...", "Show the Informaiton Window", this, guiManager, SLOT(processShowInformationWindow())); m_helpHcpWebsiteAction = WuQtUtilities::createAction("Go to HCP Website...", "Load the HCP Website in your computer's web browser", this, this, SLOT(processHcpWebsiteInBrowser())); m_helpHcpFeatureRequestAction = WuQtUtilities::createAction("Submit HCP Software Feature Request...", "Go to HCP Feature Request Website in your computer's web browser", this, this, SLOT(processHcpFeatureRequestWebsiteInBrowser())); m_helpWorkbenchBugReportAction = WuQtUtilities::createAction("Report a Workbench Bug...", "Send a Workbench Bug Report", this, this, SLOT(processReportWorkbenchBug())); m_connectToAllenDatabaseAction = WuQtUtilities::createAction("Allen Brain Institute Database...", "Open a connection to the Allen Brain Institute Database", this, this, SLOT(processConnectToAllenDataBase())); m_connectToAllenDatabaseAction->setEnabled(false); m_connectToConnectomeDatabaseAction = WuQtUtilities::createAction("Human Connectome Project Database...", "Open a connection to the Human Connectome Project Database", this, this, SLOT(processConnectToConnectomeDataBase())); m_connectToConnectomeDatabaseAction->setEnabled(false); m_developerGraphicsTimingAction = WuQtUtilities::createAction("Time Graphics Update", "Show the average time for updating the windows graphics", this, this, SLOT(processDevelopGraphicsTiming())); m_developerExportVtkFileAction = WuQtUtilities::createAction("Export to VTK File", "Export model(s) to VTK File", this, this, SLOT(processDevelopExportVtkFile())); } /** * Create menus for this window. */ void BrainBrowserWindow::createMenus() { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); /* * Create the menu bar and add menus to it. */ QMenuBar* menubar = menuBar(); menubar->addMenu(createMenuFile()); menubar->addMenu(createMenuEdit()); menubar->addMenu(createMenuView()); QMenu* dataMenu = createMenuData(); if (dataMenu != NULL) { menubar->addMenu(dataMenu); } menubar->addMenu(createMenuSurface()); QMenu* volumeMenu = createMenuVolume(); if (volumeMenu != NULL) { menubar->addMenu(volumeMenu); } QMenu* connectMenu = createMenuConnect(); if (connectMenu != NULL) { menubar->addMenu(connectMenu); } menubar->addMenu(new WuQMacroMenu(this, menubar)); QMenu* developMenu = createMenuDevelop(); m_developMenuAction = menubar->addMenu(developMenu); m_developMenuAction->setVisible(prefs->isDevelopMenuEnabled()); menubar->addMenu(createMenuWindow()); menubar->addMenu(createMenuHelp()); } /** * @return Create and return the developer menu. */ QMenu* BrainBrowserWindow::createMenuDevelop() { QMenu* menu = new QMenu("Develop", this); QObject::connect(menu, SIGNAL(aboutToShow()), this, SLOT(developerMenuAboutToShow())); menu->addAction(m_developerExportVtkFileAction); /* * Hide the Export to VTK menu item */ m_developerExportVtkFileAction->setVisible(false); menu->addAction(m_developerGraphicsTimingAction); std::vector developerFlags; DeveloperFlagsEnum::getAllEnums(developerFlags); m_developerFlagsActionGroup = NULL; if ( ! developerFlags.empty()) { menu->addSeparator(); m_developerFlagsActionGroup = new QActionGroup(this); m_developerFlagsActionGroup->setExclusive(false); QObject::connect(m_developerFlagsActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(developerMenuFlagTriggered(QAction*))); bool lastItemCheckableFlag(true); for (std::vector::iterator iter = developerFlags.begin(); iter != developerFlags.end(); iter++) { const DeveloperFlagsEnum::Enum flag = *iter; const bool itemCheckableFlag = DeveloperFlagsEnum::isCheckable(flag); if (itemCheckableFlag != lastItemCheckableFlag) { menu->addSeparator(); } QAction* action = menu->addAction(DeveloperFlagsEnum::toGuiName(flag)); action->setMenuRole(QAction::NoRole); // Menu item containing "Setup" is moved by Qt, see QTBUG-43588 action->setCheckable(itemCheckableFlag); action->setData(static_cast(DeveloperFlagsEnum::toIntegerCode(flag))); m_developerFlagsActionGroup->addAction(action); lastItemCheckableFlag = itemCheckableFlag; } } return menu; } /** * Called when developer menu is about to show. */ void BrainBrowserWindow::developerMenuAboutToShow() { std::vector developerFlags; DeveloperFlagsEnum::getAllEnums(developerFlags); QList actions = m_developerFlagsActionGroup->actions(); QListIterator iter(actions); while (iter.hasNext()) { QAction* action = iter.next(); const int integerCode = action->data().toInt(); bool valid = false; const DeveloperFlagsEnum::Enum enumValue = DeveloperFlagsEnum::fromIntegerCode(integerCode, &valid); if (valid) { const bool flag = DeveloperFlagsEnum::isFlag(enumValue); action->setChecked(flag); } else { CaretLogSevere("Failed to find develper flag for updating menu: " + action->text()); } } } /** * Called when developer flag is checked/unchecked. * * @param action * Action that is checked/unchecked. */ void BrainBrowserWindow::developerMenuFlagTriggered(QAction* action) { const int integerCode = action->data().toInt(); bool valid = false; const DeveloperFlagsEnum::Enum enumValue = DeveloperFlagsEnum::fromIntegerCode(integerCode, &valid); if (valid) { DeveloperFlagsEnum::setFlag(enumValue, action->isChecked()); /* * If a developer flag is "not checkable" and should call a function * test for the flag here and call the function * * if (enumValue == DeveloperFlagsEnum::) { * someFunction(); * } */ #ifdef HAVE_WEBKIT if (enumValue == DeveloperFlagsEnum::DEVELOPER_FLAG_BALSA) { static WuQDialogModal* balsaDialog(NULL); if (balsaDialog == NULL) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); balsaDialog = new WuQDialogModal("BALSA", this); QWebEngineView* webView = new QWebEngineView(); balsaDialog->setCentralWidget(webView, WuQDialogModal::SCROLL_AREA_NEVER); webView->setUrl(QUrl(QStringLiteral("https://balsa.wustl.edu"))); webView->resize(600, 800); } CaretAssert(balsaDialog); balsaDialog->show(); } /* * Update graphics and GUI */ EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); #else if (enumValue == DeveloperFlagsEnum::DEVELOPER_FLAG_BALSA) { WuQMessageBox::informationOk(this, "Software was built without Qt WebKit, BALSA test not available, see src/CMakeLists.txt"); } #endif } else { CaretLogSevere("Failed to find develper flag for reading menu: " + action->text()); } } /** * Create the file menu. * @return the file menu. */ QMenu* BrainBrowserWindow::createMenuFile() { QMenu* menu = new QMenu("File", this); QObject::connect(menu, SIGNAL(aboutToShow()), this, SLOT(processFileMenuAboutToShow())); menu->addAction(m_aboutWorkbenchAction); menu->addAction(m_preferencesAction); #ifndef CARET_OS_MACOSX menu->addSeparator(); #endif // CARET_OS_MACOSX menu->addAction(m_newWindowAction); menu->addAction(m_newTabAction); menu->addAction(m_duplicateTabAction); menu->addSeparator(); menu->addAction(m_openFileAction); menu->addAction(m_openLocationAction); m_recentSpecFileMenuOpenConfirmTitle = "Open Recent Spec File"; m_recentSpecFileMenuLoadNoConfirmTitle = "Load All Files in Recent Spec File"; m_recentSpecFileMenu = menu->addMenu(m_recentSpecFileMenuOpenConfirmTitle); QObject::connect(m_recentSpecFileMenu, SIGNAL(aboutToShow()), this, SLOT(processRecentSpecFileMenuAboutToBeDisplayed())); QObject::connect(m_recentSpecFileMenu, SIGNAL(triggered(QAction*)), this, SLOT(processRecentSpecFileMenuSelection(QAction*))); m_recentSceneFileMenu = menu->addMenu("Open Recent Scene File"); QObject::connect(m_recentSceneFileMenu, SIGNAL(aboutToShow()), this, SLOT(processRecentSceneFileMenuAboutToBeDisplayed())); QObject::connect(m_recentSceneFileMenu, SIGNAL(triggered(QAction*)), this, SLOT(processRecentSceneFileMenuSelection(QAction*))); menu->addAction(m_manageFilesAction); menu->addAction(m_closeSpecFileAction); menu->addSeparator(); menu->addAction(m_recordMovieAction); menu->addAction(m_captureImageAction); menu->addAction(m_movieRecordingAction); menu->addSeparator(); menu->addAction(m_closeTabAction); menu->addAction(m_closeWindowAction); menu->addSeparator(); #ifndef CARET_OS_MACOSX menu->addSeparator(); #endif // CARET_OS_MACOSX menu->addAction(m_exitProgramAction); return menu; } /** * Create an item for the edit menu. * * @param editMenu * The menu. * @param editMenuItem * Enumerated by that is inserted into the edit menu. * @return * Action that is created by adding item to menu. */ static QAction* addItemToEditMenu(QMenu* editMenu, const BrainBrowserWindowEditMenuItemEnum::Enum editMenuItem) { QAction* action = editMenu->addAction(BrainBrowserWindowEditMenuItemEnum::toGuiName(editMenuItem)); action->setData(static_cast(BrainBrowserWindowEditMenuItemEnum::toIntegerCode(editMenuItem))); action->setShortcut(BrainBrowserWindowEditMenuItemEnum::toShortcut(editMenuItem)); return action; } /** * @return A new instance of the edit menu. */ QMenu* BrainBrowserWindow::createMenuEdit() { /* * Why is there a space after 'Edit'. * If there is not a space, the Mac will see 'Edit' and add * two additional menu items "Start Dictation" and * "Emoji and Symbols". Use of these menu items * will sometimes cause a crash in the FTGL font code. */ m_editMenu = new QMenu("Edit "); m_editMenuUndoAction = addItemToEditMenu(m_editMenu, BrainBrowserWindowEditMenuItemEnum::UNDO); m_editMenuRedoAction = addItemToEditMenu(m_editMenu, BrainBrowserWindowEditMenuItemEnum::REDO); QAction* cutAction = addItemToEditMenu(m_editMenu, BrainBrowserWindowEditMenuItemEnum::CUT); addItemToEditMenu(m_editMenu, BrainBrowserWindowEditMenuItemEnum::COPY); addItemToEditMenu(m_editMenu, BrainBrowserWindowEditMenuItemEnum::PASTE); addItemToEditMenu(m_editMenu, BrainBrowserWindowEditMenuItemEnum::PASTE_SPECIAL); QKeySequence noKeySequence; addItemToEditMenu(m_editMenu, BrainBrowserWindowEditMenuItemEnum::DELETER); QAction* selectAllAction = NULL; const bool addSelectAllFlag = true; if (addSelectAllFlag) { selectAllAction = addItemToEditMenu(m_editMenu, BrainBrowserWindowEditMenuItemEnum::SELECT_ALL); } m_editMenu->insertSeparator(cutAction); if (selectAllAction != NULL) { m_editMenu->insertSeparator(selectAllAction); } QObject::connect(m_editMenu, SIGNAL(aboutToShow()), this, SLOT(processEditMenuAboutToShow())); QObject::connect(m_editMenu, SIGNAL(triggered(QAction*)), this, SLOT(processEditMenuItemTriggered(QAction*))); return m_editMenu; } /** * Gets called when an item is selected from the edit menu. * * @param action * Action (menu items) that was selected. */ void BrainBrowserWindow::processEditMenuItemTriggered(QAction* action) { EventGetOrSetUserInputModeProcessor inputEvent(m_browserWindowIndex); EventManager::get()->sendEvent(inputEvent.getPointer()); UserInputModeAbstract* inputProcessor = inputEvent.getUserInputProcessor(); if (inputProcessor != NULL) { const int actionDataInt = action->data().toInt(); bool validActionDataIntFlag = false; const BrainBrowserWindowEditMenuItemEnum::Enum item = BrainBrowserWindowEditMenuItemEnum::fromIntegerCode(actionDataInt, &validActionDataIntFlag); if (validActionDataIntFlag) { inputProcessor->processEditMenuItemSelection(item); } else { CaretLogSevere("Invalid conversion of integer code " + AString::number(actionDataInt) + " to BrainBrowserWindowEditMenuItemEnum::Enum"); } } /* * If Cut or Copy is selected and successful, * the menu needs to be updated so that * paste will be enabled for selection * via a shortcut key. */ processEditMenuAboutToShow(); } /** * Gets called when the edit menu is about to show. */ void BrainBrowserWindow::processEditMenuAboutToShow() { EventGetOrSetUserInputModeProcessor inputEvent(m_browserWindowIndex); EventManager::get()->sendEvent(inputEvent.getPointer()); /* * Get edit menu items that are enabled by the input processor */ std::vector editMenuItemsEnabled; UserInputModeAbstract* inputProcessor = inputEvent.getUserInputProcessor(); AString redoMenuItemSuffix; AString undoMenuItemSuffix; AString pasteText; AString pasteSpecialText; if (inputProcessor != NULL) { inputProcessor->getEnabledEditMenuItems(editMenuItemsEnabled, redoMenuItemSuffix, undoMenuItemSuffix, pasteText, pasteSpecialText); } /* * Enable/Disable each of the edit menu's actions */ QList menuActions = m_editMenu->actions(); QListIterator menuActionsIterator(menuActions); while (menuActionsIterator.hasNext()) { QAction* action = menuActionsIterator.next(); if ( ! action->isSeparator()) { const int actionDataInt = action->data().toInt(); bool validActionDataIntFlag = false; const BrainBrowserWindowEditMenuItemEnum::Enum editMenuItem = BrainBrowserWindowEditMenuItemEnum::fromIntegerCode(actionDataInt, &validActionDataIntFlag); action->setEnabled(false); if ( ! editMenuItemsEnabled.empty()) { if (validActionDataIntFlag) { if (std::find(editMenuItemsEnabled.begin(), editMenuItemsEnabled.end(), editMenuItem) != editMenuItemsEnabled.end()) { action->setEnabled(true); switch (editMenuItem) { case BrainBrowserWindowEditMenuItemEnum::COPY: break; case BrainBrowserWindowEditMenuItemEnum::CUT: break; case BrainBrowserWindowEditMenuItemEnum::DELETER: break; case BrainBrowserWindowEditMenuItemEnum::PASTE: if (pasteText.isEmpty()) { action->setText(BrainBrowserWindowEditMenuItemEnum::toGuiName(editMenuItem)); } else { action->setText(pasteText); } break; case BrainBrowserWindowEditMenuItemEnum::PASTE_SPECIAL: if (pasteSpecialText.isEmpty()) { action->setText(BrainBrowserWindowEditMenuItemEnum::toGuiName(editMenuItem)); } else { action->setText(pasteSpecialText); } break; case BrainBrowserWindowEditMenuItemEnum::REDO: break; case BrainBrowserWindowEditMenuItemEnum::SELECT_ALL: break; case BrainBrowserWindowEditMenuItemEnum::UNDO: break; } } } else { CaretLogSevere("Invalid conversion of integer code " + AString::number(actionDataInt) + " to BrainBrowserWindowEditMenuItemEnum::Enum"); } } } } /* * Redo menu may have a suffix */ AString redoMenuItemText("Redo"); if (std::find(editMenuItemsEnabled.begin(), editMenuItemsEnabled.end(), BrainBrowserWindowEditMenuItemEnum::REDO) != editMenuItemsEnabled.end()) { if ( ! redoMenuItemSuffix.isEmpty()) { redoMenuItemText.append(" " + redoMenuItemSuffix); } } m_editMenuRedoAction->setText(redoMenuItemText); /* * Undo menu may have a suffix */ AString undoMenuItemText("Undo"); if (std::find(editMenuItemsEnabled.begin(), editMenuItemsEnabled.end(), BrainBrowserWindowEditMenuItemEnum::UNDO) != editMenuItemsEnabled.end()) { if ( ! undoMenuItemSuffix.isEmpty()) { undoMenuItemText.append(" " + undoMenuItemSuffix); } } m_editMenuUndoAction->setText(undoMenuItemText); } /** * Called to display the overlay toolbox. */ void BrainBrowserWindow::processShowOverlayToolBox(bool status) { m_overlayActiveToolBox->setVisible(status); m_overlayToolBoxAction->blockSignals(true); m_overlayToolBoxAction->setChecked(status); m_overlayToolBoxAction->blockSignals(false); if (status) { m_overlayToolBoxAction->setToolTip("Hide Overlay Toolbox"); EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(m_browserWindowIndex).addToolBox().getPointer()); } else { m_overlayToolBoxAction->setToolTip("Show Overlay Toolbox"); } } /** * Called when visibility of horizontal overlay toolbox is changed. * @param visible * New visibility status. */ void BrainBrowserWindow::processOverlayHorizontalToolBoxVisibilityChanged(bool visible) { if (visible == false) { if (m_overlayActiveToolBox == m_overlayHorizontalToolBox) { m_overlayToolBoxAction->blockSignals(true); m_overlayToolBoxAction->setChecked(false); m_overlayToolBoxAction->blockSignals(false); } } } /** * Called when visibility of vertical overlay toolbox is changed. * @param visible * New visibility status. */ void BrainBrowserWindow::processOverlayVerticalToolBoxVisibilityChanged(bool visible) { if (visible == false) { if (m_overlayActiveToolBox == m_overlayVerticalToolBox) { m_overlayToolBoxAction->blockSignals(true); m_overlayToolBoxAction->setChecked(false); m_overlayToolBoxAction->blockSignals(false); } } } /** * Called when File Menu is about to show. */ void BrainBrowserWindow::processFileMenuAboutToShow() { if (isMacOptionKeyDown()) { m_closeWindowAction->setText(m_closeWindowActionNoConfirmTitle); m_recentSpecFileMenu->setTitle(m_recentSpecFileMenuLoadNoConfirmTitle); } else { m_closeWindowAction->setText(m_closeWindowActionConfirmTitle); m_recentSpecFileMenu->setTitle(m_recentSpecFileMenuOpenConfirmTitle); } } void BrainBrowserWindow::processCloseWindow() { if (m_closeWindowAction->text() == m_closeWindowActionConfirmTitle) { /* * When confirming, just use close slot and it will result * in confirmation dialog being displayed. */ m_closeWithoutConfirmationFlag = false; close(); } else if (m_closeWindowAction->text() == m_closeWindowActionNoConfirmTitle) { m_closeWithoutConfirmationFlag = true; close(); } else { CaretAssert(0); } } /** * @return Is the Option Key down on a Mac. * Always returns false if not a Mac. */ bool BrainBrowserWindow::isMacOptionKeyDown() const { bool keyDown = false; #ifdef CARET_OS_MACOSX keyDown = (QApplication::queryKeyboardModifiers() == Qt::AltModifier); #endif // CARET_OS_MACOSX return keyDown; } /** * Called when Open Recent Spec File Menu is about to be displayed * and creates the content of the menu. */ void BrainBrowserWindow::processRecentSpecFileMenuAboutToBeDisplayed() { m_recentSpecFileMenu->clear(); const int32_t numRecentSpecFiles = BrainBrowserWindow::loadRecentSpecFileMenu(m_recentSpecFileMenu); if (numRecentSpecFiles > 0) { m_recentSpecFileMenu->addSeparator(); QAction* action = new QAction("Clear Menu", m_recentSpecFileMenu); action->setData("CLEAR_CLEAR"); m_recentSpecFileMenu->addAction(action); } } /** * Load a menu with recent spec files. This method only ADDS * items to the menu, nothing is removed or cleared. * * @param recentSpecFileMenu * Menu to which recent spec files are added. * @return * Returns the number of recent spec files added to the menu. */ int32_t BrainBrowserWindow::loadRecentSpecFileMenu(QMenu* recentSpecFileMenu) { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); std::vector recentSpecFiles; prefs->getPreviousSpecFiles(recentSpecFiles); const int32_t numRecentSpecFiles = static_cast(recentSpecFiles.size()); for (int32_t i = 0; i < numRecentSpecFiles; i++) { AString actionName; AString actionFullPath; if (DataFile::isFileOnNetwork(recentSpecFiles[i])) { actionName = recentSpecFiles[i]; actionFullPath = recentSpecFiles[i]; } else { FileInformation fileInfo(recentSpecFiles[i]); QString path = fileInfo.getPathName(); QString name = fileInfo.getFileName(); if (path.isEmpty() == false) { name += (" (" + path + ")"); } actionName = name; actionFullPath = fileInfo.getAbsoluteFilePath(); } QAction* action = new QAction(actionName, recentSpecFileMenu); /* * If this "setData()" action changes you will need to update: * (1) BrainBrowserWindow::processRecentSpecFileMenuSelection * (2) MacDockMenu::menuActionTriggered */ action->setData(actionFullPath); recentSpecFileMenu->addAction(action); } return numRecentSpecFiles; } /** * Called when an item is selected from the recent spec file * menu. * @param itemAction * Action of the menu item that was selected. */ void BrainBrowserWindow::processRecentSpecFileMenuSelection(QAction* itemAction) { const AString specFileName = itemAction->data().toString(); if (specFileName == "CLEAR_CLEAR") { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->clearPreviousSpecFiles(); return; } if ( ! specFileName.isEmpty()) { SpecFile specFile; try { specFile.readFile(specFileName); SessionManager::get()->getCaretPreferences()->addToPreviousSpecFiles(specFileName); if (m_recentSpecFileMenu->title() == m_recentSpecFileMenuOpenConfirmTitle) { if (GuiManager::get()->processShowOpenSpecFileDialog(&specFile, this)) { m_toolbar->addDefaultTabsAfterLoadingSpecFile(); } } else if (m_recentSpecFileMenu->title() == m_recentSpecFileMenuLoadNoConfirmTitle) { std::vector fileNamesToLoad; fileNamesToLoad.push_back(specFileName); loadFilesFromCommandLine(fileNamesToLoad, BrainBrowserWindow::LOAD_SPEC_FILE_CONTENTS_VIA_COMMAND_LINE); m_toolbar->addDefaultTabsAfterLoadingSpecFile(); } else { CaretAssert(0); } } catch (const DataFileException& e) { QMessageBox::critical(this, "ERROR", e.whatString()); return; } EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } /** * Called when Open Recent Scene File Menu is about to be displayed * and creates the content of the menu. */ void BrainBrowserWindow::processRecentSceneFileMenuAboutToBeDisplayed() { m_recentSceneFileMenu->clear(); const int32_t numRecentSceneFiles = BrainBrowserWindow::loadRecentSceneFileMenu(m_recentSceneFileMenu); if (numRecentSceneFiles > 0) { m_recentSceneFileMenu->addSeparator(); QAction* action = new QAction("Clear Menu", m_recentSceneFileMenu); action->setData("CLEAR_CLEAR"); m_recentSceneFileMenu->addAction(action); } } /** * Load a menu with recent scene files. This method only ADDS * items to the menu, nothing is removed or cleared. * * @param recentSceneFileMenu * Menu to which recent scene files are added. * @return * Returns the number of recent scene files added to the menu. */ int32_t BrainBrowserWindow::loadRecentSceneFileMenu(QMenu* recentSceneFileMenu) { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); std::vector recentSceneFiles; prefs->getPreviousSceneFiles(recentSceneFiles); const int32_t numRecentSceneFiles = static_cast(recentSceneFiles.size()); for (int32_t i = 0; i < numRecentSceneFiles; i++) { AString actionName; AString actionFullPath; if (DataFile::isFileOnNetwork(recentSceneFiles[i])) { actionName = recentSceneFiles[i]; actionFullPath = recentSceneFiles[i]; } else { FileInformation fileInfo(recentSceneFiles[i]); QString path = fileInfo.getPathName(); QString name = fileInfo.getFileName(); if (path.isEmpty() == false) { name += (" (" + path + ")"); } actionName = name; actionFullPath = fileInfo.getAbsoluteFilePath(); } QAction* action = new QAction(actionName, recentSceneFileMenu); /* * If this "setData()" action changes you will need to update: * (1) BrainBrowserWindow::processRecentSceneFileMenuSelection * (2) MacDockMenu::menuActionTriggered */ action->setData(actionFullPath); recentSceneFileMenu->addAction(action); } return numRecentSceneFiles; } /** * Called when an item is selected from the recent scene file * menu. * @param itemAction * Action of the menu item that was selected. */ void BrainBrowserWindow::processRecentSceneFileMenuSelection(QAction* itemAction) { const AString sceneFileName = itemAction->data().toString(); if (sceneFileName == "CLEAR_CLEAR") { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->clearPreviousSceneFiles(); return; } if ( ! sceneFileName.isEmpty()) { std::vector filenamesVector; filenamesVector.push_back(sceneFileName); std::vector dataFileTypes; dataFileTypes.push_back(DataFileTypeEnum::SCENE); loadFiles(this, filenamesVector, dataFileTypes, LOAD_SPEC_FILE_CONTENTS_VIA_COMMAND_LINE, "", ""); EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } /** * Called when view menu is about to show. */ void BrainBrowserWindow::processViewMenuAboutToShow() { m_viewMoveFeaturesToolBoxMenu->setEnabled(isFullScreen() == false); m_viewMoveOverlayToolBoxMenu->setEnabled(isFullScreen()== false); if (isFullScreen()) { m_viewFullScreenAction->setText("Exit Full Screen"); } else { m_viewFullScreenAction->setText("Enter Full Screen"); } if (isTileTabsSelected()) { m_viewTileTabsAction->setText("Exit Tile Tabs"); } else { m_viewTileTabsAction->setText("Enter Tile Tabs"); } m_viewAutomaticTileTabsConfigurationAction->setText(getTileTabsConfigurationLabelText(TileTabsGridModeEnum::AUTOMATIC, true)); m_viewCustomTileTabsConfigurationAction->setText(getTileTabsConfigurationLabelText(TileTabsGridModeEnum::CUSTOM, true)); BrowserWindowContent* bwc = getBrowerWindowContent(); switch (bwc->getTileTabsConfigurationMode()) { case TileTabsGridModeEnum::AUTOMATIC: m_viewAutomaticTileTabsConfigurationAction->setChecked(true); break; case TileTabsGridModeEnum::CUSTOM: m_viewCustomTileTabsConfigurationAction->setChecked(true); break; } } /** * @return Label for given tile tabs configuration in View Menu * and Tile Tabs Configuration dialog. * * @param configurationMode * The configuration mode. * @param includeRowsAndColumnsIn * Include the number of rows and columns. */ AString BrainBrowserWindow::getTileTabsConfigurationLabelText(const TileTabsGridModeEnum::Enum configurationMode, const bool includeRowsAndColumnsIn) const { bool includeRowsAndColumns = includeRowsAndColumnsIn; AString modeLabel; switch (configurationMode) { case TileTabsGridModeEnum::AUTOMATIC: modeLabel = "Automatic"; break; case TileTabsGridModeEnum::CUSTOM: modeLabel = "Custom"; break; } std::vector windowTabIndices; getAllTabContentIndices(windowTabIndices); int32_t configRowCount(0), configColCount(0); const int32_t windowTabCount = static_cast(windowTabIndices.size()); AString errorText; switch (configurationMode) { case TileTabsGridModeEnum::AUTOMATIC: TileTabsConfiguration::getRowsAndColumnsForNumberOfTabs(windowTabCount, configRowCount, configColCount); break; case TileTabsGridModeEnum::CUSTOM: { const TileTabsConfiguration* customConfig = getBrowerWindowContent()->getCustomTileTabsConfiguration(); configRowCount = customConfig->getNumberOfRows(); configColCount = customConfig->getNumberOfColumns(); const int32_t customTabCount = (configRowCount * configColCount); const int32_t hiddenCount = windowTabCount - customTabCount; if (hiddenCount > 0) { errorText = " (configuration too small for all tabs)"; includeRowsAndColumns = false; } } break; } AString rowsColumnsText; if (includeRowsAndColumns) { rowsColumnsText = (" (" + AString::number(configRowCount) + " Rows, " + AString::number(configColCount) + " Columns)"); } const AString textLabel(modeLabel + rowsColumnsText + errorText); return textLabel; } /** * Modify the tile tabs configuration. * * @param modEvent * Event with modification information. */ void BrainBrowserWindow::modifyTileTabsConfiguration(EventTileTabsConfigurationModification* modEvent) { CaretAssert(modEvent); if (modEvent->getWindowIndex() != m_browserWindowIndex) { return; } std::vector vpContent; if (isTileTabsSelected()) { vpContent = m_openGLWidget->getViewportContent(); } TileTabsConfigurationModifier modifier(vpContent, modEvent); AString errorMessage; if (! modifier.run(errorMessage)) { modEvent->setErrorMessage(errorMessage); WuQMessageBox::errorOk(this, errorMessage); } /* * Update graphics and GUI */ EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); modEvent->setEventProcessed(); } /** * Update the tile tabs configuration menu just before it is shown. */ void BrainBrowserWindow::processViewTileTabsLoadUserConfigurationMenuAboutToShow() { /* * QMenu::clear will delete the actions that were in the menu */ m_viewTileTabsLoadUserConfigurationMenu->clear(); m_viewCustomTileTabsConfigurationActions.clear(); const CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); std::vector tileTabsConfigs = prefs->getTileTabsConfigurationsSortedByName(); for (auto config : tileTabsConfigs) { QAction* action = m_viewTileTabsLoadUserConfigurationMenu->addAction(config->getName()); m_viewCustomTileTabsConfigurationActions.push_back(std::make_pair(action, const_cast(config))); } } /** * Called when automatic/custom menu item is selected. * * @param action * Action that was selected. */ void BrainBrowserWindow::processViewTileTabsAutomaticCustomTriggered(QAction* action) { BrowserWindowContent* bwc = getBrowerWindowContent(); if (action == m_viewAutomaticTileTabsConfigurationAction) { bwc->setTileTabsConfigurationMode(TileTabsGridModeEnum::AUTOMATIC); } else if (action == m_viewCustomTileTabsConfigurationAction) { bwc->setTileTabsConfigurationMode(TileTabsGridModeEnum::CUSTOM); } else { CaretAssert(0); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); } /** * Process an item selected from the tile tabs configuration menu. */ void BrainBrowserWindow::processViewTileTabsLoadUserConfigurationMenuItemTriggered(QAction* action) { CaretAssert(action); BrowserWindowContent* bwc = getBrowerWindowContent(); bwc->setTileTabsConfigurationMode(TileTabsGridModeEnum::CUSTOM); TileTabsConfiguration* tileTabsConfig = NULL; for (auto& config : m_viewCustomTileTabsConfigurationActions) { if (config.first == action) { tileTabsConfig = config.second; CaretAssert(tileTabsConfig); break; } } CaretAssert(tileTabsConfig); bwc->getCustomTileTabsConfiguration()->copy(*tileTabsConfig); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); } /** * @return Instance of the tile tabs configuration menu. */ QMenu* BrainBrowserWindow::createMenuViewTileTabsLoadUserConfiguration() { QMenu* menu = new QMenu("Load Custom With User Configuration"); QObject::connect(menu, &QMenu::aboutToShow, this, &BrainBrowserWindow::processViewTileTabsLoadUserConfigurationMenuAboutToShow); QObject::connect(menu, &QMenu::triggered, this, &BrainBrowserWindow::processViewTileTabsLoadUserConfigurationMenuItemTriggered); return menu; } /** * Create the view menu. * @return the view menu. */ QMenu* BrainBrowserWindow::createMenuView() { QMenu* menu = new QMenu("View", this); QObject::connect(menu, SIGNAL(aboutToShow()), this, SLOT(processViewMenuAboutToShow())); QMenu* tileTabsModeMenu = new QMenu("Tile Tabs Configuration Mode"); tileTabsModeMenu->addAction(m_viewAutomaticTileTabsConfigurationAction); tileTabsModeMenu->addAction(m_viewCustomTileTabsConfigurationAction); m_viewMoveFeaturesToolBoxMenu = createMenuViewMoveFeaturesToolBox(); m_viewMoveOverlayToolBoxMenu = createMenuViewMoveOverlayToolBox(); m_viewTileTabsLoadUserConfigurationMenu = createMenuViewTileTabsLoadUserConfiguration(); menu->addAction(m_showToolBarAction); menu->addMenu(m_viewMoveFeaturesToolBoxMenu); menu->addMenu(m_viewMoveOverlayToolBoxMenu); menu->addSeparator(); menu->addAction(m_viewFullScreenAction); menu->addSeparator(); menu->addAction(m_gapsAndMarginsAction); menu->addSeparator(); menu->addAction(m_viewTileTabsAction); menu->addAction(m_viewTileTabsConfigurationDialogAction); menu->addMenu(tileTabsModeMenu); menu->addMenu(m_viewTileTabsLoadUserConfigurationMenu); return menu; } /** * @return Create and return the overlay toolbox menu. */ QMenu* BrainBrowserWindow::createMenuViewMoveFeaturesToolBox() { QMenu* menu = new QMenu("Features Toolbox", this); menu->addAction("Attach to Right", this, SLOT(processMoveFeaturesToolBoxToRight())); menu->addAction("Detach", this, SLOT(processMoveFeaturesToolBoxToFloat())); menu->addAction("Hide", this, SLOT(processHideFeaturesToolBox())); return menu; } /** * @return Create and return the overlay toolbox menu. */ QMenu* BrainBrowserWindow::createMenuViewMoveOverlayToolBox() { QMenu* menu = new QMenu("Overlay Toolbox", this); menu->addAction("Attach to Bottom", this, SLOT(processMoveOverlayToolBoxToBottom())); menu->addAction("Attach to Left", this, SLOT(processMoveOverlayToolBoxToLeft())); menu->addAction("Detach", this, SLOT(processMoveOverlayToolBoxToFloat())); menu->addAction("Hide", this, SLOT(processHideOverlayToolBox())); return menu; } /** * Create the connect menu. * @return the connect menu. */ QMenu* BrainBrowserWindow::createMenuConnect() { QMenu* menu = new QMenu("Connect"); if (m_connectToAllenDatabaseAction->isEnabled()) { menu->addAction(m_connectToAllenDatabaseAction); } if (m_connectToConnectomeDatabaseAction->isEnabled()) { menu->addAction(m_connectToConnectomeDatabaseAction); } /* * If none of the actions are enabled, the menu will be * empty so there is no need to display the menu. */ if (menu->isEmpty()) { delete menu; menu = NULL; } return menu; } /** * Create the data menu. * @return the data menu. */ QMenu* BrainBrowserWindow::createMenuData() { QMenu* menu = new QMenu("Data", this); QObject::connect(menu, SIGNAL(aboutToShow()), this, SLOT(processDataMenuAboutToShow())); menu->addAction(m_dataFociProjectAction); menu->addAction(m_dataBorderFilesSplitAction); return menu; } /** * Called when Data Menu is about to show. */ void BrainBrowserWindow::processDataMenuAboutToShow() { Brain* brain = GuiManager::get()->getBrain(); bool haveFociFiles = (GuiManager::get()->getBrain()->getNumberOfFociFiles() > 0); m_dataFociProjectAction->setEnabled(haveFociFiles); bool haveMultiStructureBorderFiles = false; const int32_t numBorderFiles = brain->getNumberOfBorderFiles(); for (int32_t i = 0; i < numBorderFiles; i++) { if ( ! brain->getBorderFile(i)->isSingleStructure()) { haveMultiStructureBorderFiles = true; break; } } m_dataBorderFilesSplitAction->setEnabled(haveMultiStructureBorderFiles); } /** * Create the surface menu. * @return the surface menu. */ QMenu* BrainBrowserWindow::createMenuSurface() { QMenu* menu = new QMenu("Surface", this); menu->addAction("Information...", this, SLOT(processSurfaceMenuInformation())); menu->addAction("Properties...", this, SLOT(processShowSurfacePropertiesDialog())); menu->addAction("Primary Anatomical...", this, SLOT(processSurfaceMenuPrimaryAnatomical())); return menu; } /** * Called when Primary Anatomical is selected from the surface menu. */ void BrainBrowserWindow::processSurfaceMenuPrimaryAnatomical() { Brain* brain = GuiManager::get()->getBrain(); const int32_t numBrainStructures = brain->getNumberOfBrainStructures(); if (numBrainStructures <= 0) { return; } WuQDataEntryDialog ded("Primary Anatomical Surfaces", this); std::vector surfaceSelectionControls; for (int32_t i = 0; i < numBrainStructures; i++) { BrainStructure* bs = brain->getBrainStructure(i); SurfaceSelectionViewController* ssc = ded.addSurfaceSelectionViewController(StructureEnum::toGuiName(bs->getStructure()), bs); ssc->setSurface(bs->getPrimaryAnatomicalSurface()); surfaceSelectionControls.push_back(ssc); } if (ded.exec() == WuQDataEntryDialog::Accepted) { for (int32_t i = 0; i < numBrainStructures; i++) { BrainStructure* bs = brain->getBrainStructure(i); bs->setPrimaryAnatomicalSurface(surfaceSelectionControls[i]->getSurface()); } EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } /** * Called when Information is selected from the surface menu. */ void BrainBrowserWindow::processSurfaceMenuInformation() { BrowserTabContent* btc = getBrowserTabContent(); if (btc != NULL) { AString txt = ""; Model* mdc = btc->getModelForDisplay(); ModelSurface* mdcs = dynamic_cast(mdc); if (mdcs != NULL) { txt += mdcs->getSurface()->getInformation(); } ModelWholeBrain* mdcwb = dynamic_cast(mdc); if (mdcwb != NULL) { std::vector allStructures; StructureEnum::getAllEnums(allStructures); for (std::vector::iterator iter = allStructures.begin(); iter != allStructures.end(); iter++) { const Surface* surface = mdcwb->getSelectedSurface(*iter, btc->getTabNumber()); if (surface != NULL) { txt += surface->getInformation(); txt += "\n"; } } } ModelSurfaceMontage* msm = dynamic_cast(mdc); if (msm != NULL) { std::vector surfaces; msm->getSelectedConfiguration(btc->getTabNumber())->getDisplayedSurfaces(surfaces); for (std::vector::iterator iter = surfaces.begin(); iter != surfaces.end(); iter++) { const Surface* s = *iter; txt += s->getInformation(); txt += "\n"; } } if (txt.isEmpty() == false) { WuQMessageBox::informationOk(this, txt); } } } /** * Create the volume menu. * @return the volume menu. */ QMenu* BrainBrowserWindow::createMenuVolume() { QMenu* menu = new QMenu("Volume", this); menu->addAction("Properties...", this, SLOT(processShowVolumePropertiesDialog())); return menu; } /** * Create the window menu. * @return the window menu. */ QMenu* BrainBrowserWindow::createMenuWindow() { m_moveSelectedTabToWindowMenu = new QMenu("Move Selected Tab to Window"); QObject::connect(m_moveSelectedTabToWindowMenu, SIGNAL(aboutToShow()), this, SLOT(processMoveSelectedTabToWindowMenuAboutToBeDisplayed())); QObject::connect(m_moveSelectedTabToWindowMenu, SIGNAL(triggered(QAction*)), this, SLOT(processMoveSelectedTabToWindowMenuSelection(QAction*))); QMenu* menu = new QMenu("Window", this); menu->addAction(m_windowMenuLockWindowAspectRatioAction); menu->addAction(m_windowMenuLockAllTabAspectRatioAction); menu->addSeparator(); menu->addAction(m_nextTabAction); menu->addAction(m_previousTabAction); menu->addAction(m_renameSelectedTabAction); menu->addSeparator(); menu->addAction(m_moveTabsInWindowToNewWindowsAction); menu->addAction(m_moveTabsFromAllWindowsToOneWindowAction); menu->addMenu(m_moveSelectedTabToWindowMenu); menu->addSeparator(); /* * Cannot use the Identify action since it sets the "checkable" attribute * and this will add checkbox and checkmark to the menu. In addition, * using the identify action would also hide the help viewer if it is * displayed and we don't want that. */ QAction* identifyAction = GuiManager::get()->getIdentifyBrainordinateDialogDisplayAction(); menu->addAction(identifyAction->text(), this, SLOT(processShowIdentifyBrainordinateDialog())); menu->addAction(m_informationDialogAction); menu->addAction(GuiManager::get()->getSceneDialogDisplayAction()); menu->addSeparator(); menu->addAction(m_bringAllToFrontAction); menu->addAction(m_tileWindowsAction); return menu; } /** * Create the help menu. * @return the help menu. */ QMenu* BrainBrowserWindow::createMenuHelp() { QMenu* menu = new QMenu("Help", this); /* * Cannot use the Help action since it sets the "checkable" attribute * and this will add checkbox and checkmark to the menu. In addition, * using the help action would also hide the help viewer if it is * dispalyed and we don't want that. */ QAction* helpAction = GuiManager::get()->getHelpViewerDialogDisplayAction(); menu->addAction(helpAction->text(), this, SLOT(processShowHelpInformation())); menu->addSeparator(); menu->addAction(m_helpHcpWebsiteAction); menu->addAction(m_helpWorkbenchBugReportAction); menu->addAction(m_helpHcpFeatureRequestAction); return menu; } /** * Called to show/hide help content. */ void BrainBrowserWindow::processShowHelpInformation() { /* * Always display the help viewer when selected from the menu. * Even if the help viewer is active it may be under other windows * so triggering it will cause it to display. */ QAction* helpAction = GuiManager::get()->getHelpViewerDialogDisplayAction(); if (helpAction->isChecked()) { helpAction->blockSignals(true); helpAction->setChecked(false); helpAction->blockSignals(false); } helpAction->trigger(); } void BrainBrowserWindow::processShowIdentifyBrainordinateDialog() { /* * Always display the identify dialog when selected from the menu. * Even if the identify dialog is active it may be under other windows * so triggering it will cause it to display. */ GuiManager::get()->showHideIdentfyBrainordinateDialog(true, this); } /** * Time the graphics drawing. */ void BrainBrowserWindow::processDevelopGraphicsTiming() { ElapsedTimer et; et.start(); const float numTimes(10.0); for (int32_t i = 0; i < numTimes; i++) { EventManager::get()->sendEvent(EventGraphicsTimingOneWindow(m_browserWindowIndex).getPointer()); } const float time = et.getElapsedTimeSeconds() / numTimes; const AString timeString = AString::number(time, 'f', 5); AString fpsString; if (time > 0.0) { const float fps(1.0 / time); fpsString = ("\nFrame per second: " + AString::number(fps, 'f', 3)); } const AString msg = ("Time to draw graphics (seconds): " + timeString + fpsString); WuQMessageBox::informationOk(this, msg); } /** * Export to VTK file. */ void BrainBrowserWindow::processDevelopExportVtkFile() { static QString previousVtkFileName = ""; BrowserTabContent* btc = getBrowserTabContent(); if (btc != NULL) { const int32_t tabIndex = btc->getTabNumber(); std::vector surfaceFiles; std::vector surfaceFilesColoring; ModelSurface* modelSurface = btc->getDisplayedSurfaceModel(); ModelWholeBrain* modelWholeBrain = btc->getDisplayedWholeBrainModel(); if (modelSurface != NULL) { SurfaceFile* sf = modelSurface->getSurface(); surfaceFiles.push_back(sf); surfaceFilesColoring.push_back(sf->getSurfaceNodeColoringRgbaForBrowserTab(tabIndex)); } else if (modelWholeBrain != NULL) { std::vector wholeBrainSurfaces = modelWholeBrain->getSelectedSurfaces(tabIndex); for (std::vector::iterator iter = wholeBrainSurfaces.begin(); iter != wholeBrainSurfaces.end(); iter++) { Surface* surface = *iter; surfaceFiles.push_back(surface); surfaceFilesColoring.push_back(surface->getWholeBrainNodeColoringRgbaForBrowserTab(tabIndex)); } } if (surfaceFiles.empty() == false) { QString vtkSurfaceFileFilter = "VTK Poly Data File (*.vtp)"; CaretFileDialog cfd(this, "Export to VTK File", GuiManager::get()->getBrain()->getCurrentDirectory(), vtkSurfaceFileFilter); cfd.selectNameFilter(vtkSurfaceFileFilter); cfd.setAcceptMode(QFileDialog::AcceptSave); cfd.setFileMode(CaretFileDialog::AnyFile); if (previousVtkFileName.isEmpty() == false) { cfd.selectFile(previousVtkFileName); } if (cfd.exec() == CaretFileDialog::Accepted) { QStringList selectedFiles = cfd.selectedFiles(); if (selectedFiles.size() > 0) { const QString vtkFileName = selectedFiles[0]; if (vtkFileName.isEmpty() == false) { try { previousVtkFileName = vtkFileName; VtkFileExporter::writeSurfaces(surfaceFiles, surfaceFilesColoring, vtkFileName); } catch (const DataFileException& dfe) { WuQMessageBox::errorOk(this, dfe.whatString()); } } } } } else { WuQMessageBox::errorOk(this, "Displayed model does not support exporting to VTK File at this time."); } } } /** * Project foci. */ void BrainBrowserWindow::processProjectFoci() { FociProjectionDialog fpd(this); fpd.exec(); } /** * Split multi-structure border files. */ void BrainBrowserWindow::processSplitBorderFiles() { BorderFileSplitDialog dialog(this); dialog.exec(); } /** * Called when capture image is selected. */ void BrainBrowserWindow::processCaptureImage() { GuiManager::get()->processShowImageCaptureDialog(this); } /** * Called when movie recording is selected. */ void BrainBrowserWindow::processMovieRecording() { GuiManager::get()->processShowMovieRecordingDialog(this); } /** * Called when capture image is selected. */ void BrainBrowserWindow::processGapsAndMargins() { GuiManager::get()->processShowGapsAndMarginsDialog(this); } /** * Called when record movie is selected. */ void BrainBrowserWindow::processRecordMovie() { GuiManager::get()->processShowMovieDialog(this); } /** * Called when capture image is selected. */ void BrainBrowserWindow::processEditPreferences() { GuiManager::get()->processShowPreferencesDialog(this); } /** * Called when information dialog is selected. */ void BrainBrowserWindow::processInformationDialog() { GuiManager::get()->processShowInformationDisplayDialog(true); } /** * Called when close spec file is selected. */ void BrainBrowserWindow::processCloseAllFiles() { if(!WuQMessageBox::warningYesNo(this, "Are you sure you want to close all files?")) return; Brain* brain = GuiManager::get()->getBrain(); brain->resetBrain(); CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setBackgroundAndForegroundColorsMode(BackgroundAndForegroundColorsModeEnum::USER_PREFERENCES); prefs->invalidateSceneDataValues(); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); GuiManager::get()->closeAllOtherWindows(this); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** * Create a new window. */ void BrainBrowserWindow::processNewWindow() { CursorDisplayScoped cursor; cursor.showWaitCursor(); EventManager::get()->blockEvent(EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW, true); EventBrowserWindowNew eventNewBrowser(this, NULL); EventManager::get()->sendEvent(eventNewBrowser.getPointer()); if (eventNewBrowser.isError()) { cursor.restoreCursor(); QMessageBox::critical(this, "", eventNewBrowser.getErrorMessage()); return; } const int32_t newWindowIndex = eventNewBrowser.getBrowserWindowCreated()->getBrowserWindowIndex(); EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(newWindowIndex).getPointer()); EventManager::get()->blockEvent(EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW, false); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(newWindowIndex).getPointer()); } /** * Display about workbench dialog. */ void BrainBrowserWindow::processAboutWorkbench() { AboutWorkbenchDialog awd(this->m_openGLWidget); awd.exec(); } /** * Called when open location is selected. */ void BrainBrowserWindow::processDataFileLocationOpen() { CaretFileRemoteDialog fileRemoteDialog(this); fileRemoteDialog.exec(); } /** * Called when open data file is selected. */ void BrainBrowserWindow::processDataFileOpen() { if (s_previousOpenFileNameFilter.isEmpty()) { s_previousOpenFileNameFilter = DataFileTypeEnum::toQFileDialogFilter(DataFileTypeEnum::SPECIFICATION); } /* * Get all file filters. */ std::vector dataFileTypes; DataFileTypeEnum::getAllEnums(dataFileTypes, DataFileTypeEnum::OPTIONS_NONE); QStringList filenameFilterList; filenameFilterList.append("Any File (*)"); for (std::vector::const_iterator iter = dataFileTypes.begin(); iter != dataFileTypes.end(); iter++) { AString filterName = DataFileTypeEnum::toQFileDialogFilter(*iter); filenameFilterList.append(filterName); } /* * Setup file selection dialog. */ CaretFileDialog fd(this); fd.setAcceptMode(CaretFileDialog::AcceptOpen); fd.setNameFilters(filenameFilterList); fd.setFileMode(CaretFileDialog::ExistingFiles); fd.setViewMode(CaretFileDialog::List); fd.selectNameFilter(s_previousOpenFileNameFilter); if (s_previousOpenFileDirectory.isEmpty() == false) { FileInformation fileInfo(s_previousOpenFileDirectory); if (fileInfo.exists()) { fd.setDirectory(s_previousOpenFileDirectory); } } if ( ! s_previousOpenFileGeometry.isEmpty()) { fd.restoreGeometry(s_previousOpenFileGeometry); } AString errorMessages; if (fd.exec() == CaretFileDialog::Accepted) { QStringList selectedFiles = fd.selectedFiles(); if (selectedFiles.empty() == false) { /* * Load the files. */ std::vector filenamesVector; QStringListIterator nameIter(selectedFiles); while (nameIter.hasNext()) { const QString name = nameIter.next(); filenamesVector.push_back(name); } std::vector dataFileTypesDummyNotUsed; loadFiles(this, filenamesVector, dataFileTypesDummyNotUsed, LOAD_SPEC_FILE_WITH_DIALOG, "", ""); } s_previousOpenFileNameFilter = fd.selectedNameFilter(); s_previousOpenFileDirectory = fd.directory().absolutePath(); s_previousOpenFileGeometry = fd.saveGeometry(); } } /** * Load files that are on the network * * @param parentForDialogs, * Parent widget on which dialogs are displayed. * @param filenames * List of filenames to read. * @param dataFileTypes * Type for each data file (optional, if not available type matched from file's extension). * @param username * Username for network file reading * @param password * Password for network file reading */ bool BrainBrowserWindow::loadFilesFromNetwork(QWidget* parentForDialogs, const std::vector& filenames, const std::vector dataFileTypes, const AString& username, const AString& password) { const bool successFlag = loadFiles(parentForDialogs, filenames, dataFileTypes, BrainBrowserWindow::LOAD_SPEC_FILE_WITH_DIALOG_VIA_COMMAND_LINE, username, password); return successFlag; } /** * Load the files that were specified on the command line. * @param filenames * Names of files on the command line. * @param loadSpecFileMode * Specifies handling of SpecFiles */ void BrainBrowserWindow::loadFilesFromCommandLine(const std::vector& filenames, const LoadSpecFileMode loadSpecFileMode) { std::vector dataFileTypesDummyNotUsed; AString userName; AString password; switch (loadSpecFileMode) { case LOAD_SPEC_FILE_CONTENTS_VIA_COMMAND_LINE: { /* * Spec file might contain a file on the network so try * using the saved username and password. */ CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->getRemoteFileUserNameAndPassword(userName, password); } break; case LOAD_SPEC_FILE_WITH_DIALOG: break; case LOAD_SPEC_FILE_WITH_DIALOG_VIA_COMMAND_LINE: break; } loadFiles(this, filenames, dataFileTypesDummyNotUsed, loadSpecFileMode, userName, password); } /** * Load the scene file and the scene with the given name or number * @param sceneFileName * Name of scene file. * @param sceneNameOrNumber * Name or number of scene. Name takes precedence over number. * Scene numbers start at one. */ void BrainBrowserWindow::loadSceneFromCommandLine(const AString& sceneFileName, const AString& sceneNameOrNumber) { std::vector filenames; filenames.push_back(sceneFileName); loadFilesFromCommandLine(filenames, LOAD_SPEC_FILE_CONTENTS_VIA_COMMAND_LINE); bool haveSceneFileError = true; bool haveSceneError = true; FileInformation fileInfo(sceneFileName); const AString nameNoExt = fileInfo.getFileName(); Brain* brain = GuiManager::get()->getBrain(); const int32_t numSceneFiles = brain->getNumberOfSceneFiles(); for (int32_t i = 0; i < numSceneFiles; i++) { SceneFile* sf = brain->getSceneFile(i); FileInformation fileInfo(sceneFileName); if (sf->getFileName().contains(fileInfo.getFileName())) { haveSceneFileError = false; Scene* scene = sf->getSceneWithName(sceneNameOrNumber); if (scene == NULL) { bool isValidNumber = false; int sceneNumber = sceneNameOrNumber.toInt(&isValidNumber); if (isValidNumber) { sceneNumber--; /* convert to index (numbers start at one) */ if ((sceneNumber >= 0) && (sceneNumber < sf->getNumberOfScenes())) { scene = sf->getSceneAtIndex(sceneNumber); } } } if (scene != NULL) { const bool showSceneDialogFlag(true); GuiManager::get()->processShowSceneDialogAndScene(this, sf, scene, showSceneDialogFlag); haveSceneError = false; break; } } } if (haveSceneFileError) { const AString msg = ("No scene file named \"" + sceneFileName + "\" was loaded."); WuQMessageBox::errorOk(this, msg); } else if (haveSceneError) { const AString msg = ("No scene with name/number \"" + sceneNameOrNumber + "\" found in scene file."); WuQMessageBox::errorOk(this, msg); } /* NOTE: File warning dialog is performed by scene dialog */ } /** * Load data files. If there are errors, an error message dialog * will be displayed. * * @param parentForDialogs * Parent widget for any dialogs (if NULL this window is used). * @param filenames * Names of files. * @param dataFileTypes * Type for each filename (optional). If the type is not present for a * filename, the type is inferred from the filename's extension. * @param loadSpecFileMode * Specifies handling of SpecFiles * @param username * Username for network file reading * @param password * Password for network file reading * @return true if there are no errors, else false. */ bool BrainBrowserWindow::loadFiles(QWidget* parentForDialogs, const std::vector& filenames, const std::vector dataFileTypes, const LoadSpecFileMode loadSpecFileMode, const AString& username, const AString& password) { QWidget* parentWidget = parentForDialogs; if (parentWidget == NULL) { parentWidget = this; } /* * Pick out specific file types. */ AString specFileName; std::vector volumeFileNames; std::vector surfaceFileNames; std::vector otherFileNames; std::vector otherDataFileTypes; AString typeErrorMessage = ""; const int32_t numFiles = static_cast(filenames.size()); const int32_t numDataTypes = static_cast(dataFileTypes.size()); for (int32_t i = 0; i < numFiles; i++) { const AString name = filenames[i]; bool isValidType = false; DataFileTypeEnum::Enum fileType = DataFileTypeEnum::UNKNOWN; if (i < numDataTypes) { fileType = dataFileTypes[i]; isValidType = true; } else { fileType = DataFileTypeEnum::fromFileExtension(name, &isValidType); if (isValidType == false) { typeErrorMessage.appendWithNewLine("Extension for " + name + " does not match a suppported file type"); } } switch (fileType) { case DataFileTypeEnum::SPECIFICATION: if (specFileName.isEmpty() == false) { QMessageBox::critical(parentWidget, "ERROR", "More than one spec file cannot be loaded"); return false; } specFileName = name; break; case DataFileTypeEnum::SURFACE: surfaceFileNames.push_back(name); break; case DataFileTypeEnum::VOLUME: volumeFileNames.push_back(name); break; default: otherFileNames.push_back(name); otherDataFileTypes.push_back(fileType); break; } } if (typeErrorMessage.isEmpty() == false) { QMessageBox::critical(parentWidget, "ERROR", typeErrorMessage); return false; } /* * Load files in this order: * (1) Spec File - Limit to one. * (2) Volume File * (3) Surface File * (4) All other files. */ std::vector > filesToLoad; const int32_t numVolumeFiles = static_cast(volumeFileNames.size()); for (int32_t i = 0; i < numVolumeFiles; i++) { filesToLoad.push_back(std::make_pair(volumeFileNames[i], DataFileTypeEnum::VOLUME)); } const int32_t numSurfaceFiles = static_cast(surfaceFileNames.size()); for (int32_t i = 0; i < numSurfaceFiles; i++) { filesToLoad.push_back(std::make_pair(surfaceFileNames[i], DataFileTypeEnum::SURFACE)); } const int32_t numOtherFiles = static_cast(otherFileNames.size()); for (int32_t i = 0; i < numOtherFiles; i++) { filesToLoad.push_back(std::make_pair(otherFileNames[i], otherDataFileTypes[i])); } bool createDefaultTabsFlag = false; /* * If there are no models loaded, will want to create default tabs. */ EventModelGetAll modelGetAllEvent; EventManager::get()->sendEvent(modelGetAllEvent.getPointer()); const int32_t numberOfModels = static_cast(modelGetAllEvent.getModels().size()); if (numberOfModels <= 0) { createDefaultTabsFlag = true; } AString errorMessages; ElapsedTimer timer; timer.start(); float specFileTimeStart = 0.0; float specFileTimeEnd = 0.0; bool sceneFileWasLoaded = false; /* * Load spec file (before data files) */ if (specFileName.isEmpty() == false) { SpecFile specFile; try { FileInformation fileInfo(specFileName); if (fileInfo.isRelative()) { specFileName = fileInfo.getAbsoluteFilePath(); } if (fileInfo.exists()) { SessionManager::get()->getCaretPreferences()->addToPreviousSpecFiles(specFileName); } specFile.readFile(specFileName); } catch (const DataFileException& e) { errorMessages += e.whatString(); QMessageBox::critical(parentWidget, "ERROR", errorMessages); return false; } switch (loadSpecFileMode) { case LOAD_SPEC_FILE_CONTENTS_VIA_COMMAND_LINE: { timer.reset(); /* resets timer */ specFileTimeStart = timer.getElapsedTimeSeconds(); /* * Load all files listed in spec file */ specFile.setAllFilesSelectedForLoading(true); EventSpecFileReadDataFiles readSpecFileEvent(GuiManager::get()->getBrain(), &specFile); if (username.isEmpty() == false) { readSpecFileEvent.setUsernameAndPassword(username, password); } ProgressReportingDialog::runEvent(&readSpecFileEvent, parentWidget, specFile.getFileNameNoPath()); if (readSpecFileEvent.isError()) { if (errorMessages.isEmpty() == false) { errorMessages += "\n"; } errorMessages += readSpecFileEvent.getErrorMessage(); } specFileTimeEnd = timer.getElapsedTimeSeconds(); createDefaultTabsFlag = true; } break; case LOAD_SPEC_FILE_WITH_DIALOG: case LOAD_SPEC_FILE_WITH_DIALOG_VIA_COMMAND_LINE: { if (GuiManager::get()->processShowOpenSpecFileDialog(&specFile, this)) { m_toolbar->addDefaultTabsAfterLoadingSpecFile(); createDefaultTabsFlag = true; } } break; } sceneFileWasLoaded = specFile.areAllFilesSelectedForLoadingSceneFiles(); } /* * Prepare to load any data files */ EventDataFileRead loadFilesEvent(GuiManager::get()->getBrain()); if (username.isEmpty() == false) { loadFilesEvent.setUsernameAndPassword(username, password); } /* * Add data files to data file loading event (after loading spec file) */ const int32_t numFilesToLoad = static_cast(filesToLoad.size()); for (int32_t i = 0; i < numFilesToLoad; i++) { AString name = filesToLoad[i].first; const DataFileTypeEnum::Enum fileType = filesToLoad[i].second; loadFilesEvent.addDataFile(fileType, name); } /* * Now, load the data files */ const int32_t numberOfValidFiles = loadFilesEvent.getNumberOfDataFilesToRead(); if (numberOfValidFiles > 0) { ProgressReportingDialog::runEvent(&loadFilesEvent, parentWidget, "Loading Data Files"); errorMessages.appendWithNewLine(loadFilesEvent.getErrorMessage()); /* * Check for errors */ for (int32_t i = 0; i < numberOfValidFiles; i++) { const AString& dataFileName = loadFilesEvent.getDataFileName(i); const DataFileTypeEnum::Enum dataFileType = loadFilesEvent.getDataFileType(i); const AString shortName = FileInformation(dataFileName).getFileName(); if (loadFilesEvent.isFileErrorInvalidStructure(i)) { /* * Allow user to specify the structure */ WuQDataEntryDialog ded("Structure", parentWidget); StructureEnumComboBox* ssc = ded.addStructureEnumComboBox(""); ded.setTextAtTop(("File \"" + shortName + "\"\nhas missing or invalid structure, select it's structure." "\nAfter loading, save file with File Menu->Save Manage Files" "\nto prevent this error."), false); if (ded.exec() == WuQDataEntryDialog::Accepted) { EventDataFileRead loadFileEventStructure(GuiManager::get()->getBrain()); loadFileEventStructure.addDataFile(ssc->getSelectedStructure(), dataFileType, dataFileName); if (username.isEmpty() == false) { loadFileEventStructure.setUsernameAndPassword(username, password); } ProgressReportingDialog::runEvent(&loadFileEventStructure, parentWidget, ("Loading " + shortName)); if (loadFileEventStructure.isError()) { errorMessages.appendWithNewLine(loadFileEventStructure.getErrorMessage()); } else { if (loadFileEventStructure.getNumberOfDataFilesToRead() == 1) { CaretDataFile* cdf = loadFileEventStructure.getDataFileRead(0); if (cdf != NULL) { cdf->setModified(); } } } } else { errorMessages.appendWithNewLine("File \"" + shortName + "\" not loaded due to invalid structure."); } } else if (loadFilesEvent.isFileError(i) == false) { if (dataFileType == DataFileTypeEnum::SCENE) { sceneFileWasLoaded = true; } } } } const float specFileTime = specFileTimeEnd - specFileTimeStart; const float createTabsStartTime = timer.getElapsedTimeSeconds(); const EventBrowserWindowCreateTabs::Mode tabMode = (createDefaultTabsFlag ? EventBrowserWindowCreateTabs::MODE_LOADED_SPEC_FILE : EventBrowserWindowCreateTabs::MODE_LOADED_DATA_FILE); EventBrowserWindowCreateTabs createTabsEvent(tabMode); EventManager::get()->sendEvent(createTabsEvent.getPointer()); const float createTabsTime = timer.getElapsedTimeSeconds() - createTabsStartTime; const float guiStartTime = timer.getElapsedTimeSeconds(); EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); const float guiTime = timer.getElapsedTimeSeconds() - guiStartTime; if (specFileName.isEmpty() == false) { CaretLogInfo("Time to read files from spec file (in GUI) \"" + FileInformation(specFileName).getFileName() + "\" was " + AString::number(timer.getElapsedTimeSeconds()) + " seconds.\n Time to read spec data files was " + AString::number(specFileTime) + " seconds.\n Time to update GUI was " + AString::number(guiTime) + " seconds.\n Time to create tabs was " + AString::number(createTabsTime)); } bool successFlag = true; if (errorMessages.isEmpty() == false) { successFlag = false; QMessageBox::critical(parentWidget, "ERROR", errorMessages); } if (sceneFileWasLoaded) { GuiManager::get()->processShowSceneDialog(this); } EventManager::get()->sendEvent(EventMacDockMenuUpdate().getPointer()); showDataFileReadWarningsDialog(); return successFlag; } /** * Called when manage/save loaded files is selected. */ void BrainBrowserWindow::processManageSaveLoadedFiles() { GuiManager::get()->processShowSaveManageFilesDialog(this); } /** * Exit the program. */ void BrainBrowserWindow::processExitProgram() { GuiManager::get()->exitProgram(this); } /** * Update full screen status. * * @param showFullScreenDisplay * If true, show as full screen, else show as normal screen * @param saveRestoreWindowStatus * If true, save/restore the window status */ void BrainBrowserWindow::processViewFullScreen(bool showFullScreenDisplay, const bool saveRestoreWindowStatus) { if (showFullScreenDisplay == false) { EventManager::get()->blockEvent(EventTypeEnum::EVENT_USER_INTERFACE_UPDATE, true); showNormal(); if (saveRestoreWindowStatus) { restoreWindowComponentStatus(m_normalWindowComponentStatus); } EventManager::get()->blockEvent(EventTypeEnum::EVENT_USER_INTERFACE_UPDATE, false); } else { if (saveRestoreWindowStatus) { saveWindowComponentStatus(m_normalWindowComponentStatus); } /* * Hide and disable Toolbar, Overlay, and Features ToolBox */ m_showToolBarAction->setChecked(true); m_showToolBarAction->trigger(); m_showToolBarAction->setEnabled(false); m_overlayToolBoxAction->setChecked(true); m_overlayToolBoxAction->trigger(); m_overlayToolBoxAction->setEnabled(false); m_featuresToolBoxAction->setChecked(true); m_featuresToolBoxAction->trigger(); m_featuresToolBoxAction->setEnabled(false); showFullScreen(); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(m_browserWindowIndex).addToolBar().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(m_browserWindowIndex).getPointer()); } /** * Called when view full screen is selected and toggles the status of full screen. */ void BrainBrowserWindow::processViewFullScreenSelected() { const bool toggledStatus = (! isFullScreen()); processViewFullScreen(toggledStatus, true); } /** * Called when tile tabs is selected and toggles the state of tile tabs. */ void BrainBrowserWindow::processViewTileTabs() { const bool toggledStatus = (! isTileTabsSelected()); setViewTileTabs(toggledStatus); } /** * Set the status of tile tabs. */ void BrainBrowserWindow::setViewTileTabs(const bool newStatus) { m_browserWindowContent->setTileTabsEnabled(newStatus); EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(m_browserWindowIndex).addToolBar().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(m_browserWindowIndex).getPointer()); } /** * View the Tile Tabs Configuration Dialog. */ void BrainBrowserWindow::processViewTileTabsConfigurationDialog() { GuiManager::get()->processShowTileTabsConfigurationDialog(this); } /** * Restore the status of window components. * @param wcs * Window component status that is restored. */ void BrainBrowserWindow::restoreWindowComponentStatus(const WindowComponentStatus& wcs) { if (wcs.windowGeometry.isEmpty() == false) { restoreGeometry(wcs.windowGeometry); } if (wcs.windowState.isEmpty() == false) { restoreState(wcs.windowState); } m_showToolBarAction->setEnabled(true); if (wcs.isToolBarDisplayed) { m_showToolBarAction->setChecked(false); m_showToolBarAction->trigger(); } else { m_showToolBarAction->setChecked(true); m_showToolBarAction->trigger(); } m_overlayToolBoxAction->setEnabled(true); if (wcs.isOverlayToolBoxDisplayed) { m_overlayToolBoxAction->blockSignals(true); m_overlayToolBoxAction->setChecked(false); m_overlayToolBoxAction->blockSignals(false); m_overlayToolBoxAction->trigger(); } else { m_overlayToolBoxAction->blockSignals(true); m_overlayToolBoxAction->setChecked(true); m_overlayToolBoxAction->blockSignals(false); m_overlayToolBoxAction->trigger(); } m_featuresToolBoxAction->setEnabled(true); if (wcs.isFeaturesToolBoxDisplayed) { m_featuresToolBoxAction->blockSignals(true); m_featuresToolBoxAction->setChecked(false); m_featuresToolBoxAction->blockSignals(false); m_featuresToolBoxAction->trigger(); } else { m_featuresToolBoxAction->blockSignals(true); m_featuresToolBoxAction->setChecked(true); m_featuresToolBoxAction->blockSignals(false); m_featuresToolBoxAction->trigger(); } if (m_featuresToolBox != NULL) { if (wcs.featuresGeometry.isEmpty() == false) { m_featuresToolBox->restoreGeometry(wcs.featuresGeometry); } } } /** * Save the status of window components. * @param wcs * Will contains status after exit. * @param hideComponents * If true, any components (toolbar/toolbox) will be hidden. */ void BrainBrowserWindow::saveWindowComponentStatus(WindowComponentStatus& wcs) { wcs.windowState = saveState(); wcs.windowGeometry = saveGeometry(); if (m_featuresToolBoxAction->isChecked()) { if (m_featuresToolBox != NULL) { wcs.featuresGeometry = m_featuresToolBox->saveGeometry(); } } wcs.isToolBarDisplayed = m_showToolBarAction->isChecked(); wcs.isOverlayToolBoxDisplayed = m_overlayToolBoxAction->isChecked(); wcs.isFeaturesToolBoxDisplayed = m_featuresToolBoxAction->isChecked(); m_showToolBarAction->setEnabled(false); m_overlayToolBoxAction->setEnabled(false); m_featuresToolBoxAction->setEnabled(false); } /** * Adds a new tab to the window. */ void BrainBrowserWindow::processNewTab() { m_toolbar->addNewTab(); } /** * Adds a new tab to the window. */ void BrainBrowserWindow::processDuplicateTab() { BrowserTabContent* previousTabContent = getBrowserTabContent(); m_toolbar->addNewDuplicatedTab(previousTabContent); } /** * Called when move all tabs to one window is selected. */ void BrainBrowserWindow::processMoveAllTabsToOneWindow() { /* * Wait cursor */ CursorDisplayScoped cursor; cursor.showWaitCursor(); std::vector otherTabContent; GuiManager::get()->closeOtherWindowsAndReturnTheirTabContent(this, otherTabContent); const int32_t numOtherTabs = static_cast(otherTabContent.size()); for (int32_t i = 0; i < numOtherTabs; i++) { m_toolbar->addNewTabWithContent(otherTabContent[i]); m_toolbar->updateToolBar(); } EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(m_browserWindowIndex).getPointer()); } /** * Called when the move tab to window is about to be displayed. */ void BrainBrowserWindow::processMoveSelectedTabToWindowMenuAboutToBeDisplayed() { m_moveSelectedTabToWindowMenu->clear(); if (getBrowserTabContent() == NULL) { return; } /* * Allow movement of tab to new window ONLY if this window * contains more than one tab. */ if (m_toolbar->tabBar->count() > 1) { QAction* toNewWindowAction = new QAction("New Window", m_moveSelectedTabToWindowMenu); toNewWindowAction->setData(qVariantFromValue((void*)NULL)); m_moveSelectedTabToWindowMenu->addAction(toNewWindowAction); } std::vector browserWindows = GuiManager::get()->getAllOpenBrainBrowserWindows(); for (int32_t i = 0; i < static_cast(browserWindows.size()); i++) { if (browserWindows[i] != this) { QAction* action = new QAction(browserWindows[i]->windowTitle(), m_moveSelectedTabToWindowMenu); action->setData(qVariantFromValue((void*)browserWindows[i])); m_moveSelectedTabToWindowMenu->addAction(action); } } } /** * Called when move tab to window menu item is selected. * This window may close if there are no more tabs after * the tab is removed. * @param action * Action from menu item that was selected. */ void BrainBrowserWindow::processMoveSelectedTabToWindowMenuSelection(QAction* action) { if (action != NULL) { /* * Wait cursor */ CursorDisplayScoped cursor; cursor.showWaitCursor(); void* p = action->data().value(); BrainBrowserWindow* moveToBrowserWindow = (BrainBrowserWindow*)p; BrowserTabContent* btc = getBrowserTabContent(); if (moveToBrowserWindow != NULL) { m_toolbar->removeTabWithContent(btc); moveToBrowserWindow->m_toolbar->addNewTabWithContent(btc); } else { EventBrowserWindowNew newWindow(this, btc); EventManager::get()->sendEvent(newWindow.getPointer()); if (newWindow.isError()) { cursor.restoreCursor(); QMessageBox::critical(this, "", newWindow.getErrorMessage()); return; } m_toolbar->removeTabWithContent(btc); } if (m_toolbar->tabBar->count() <= 0) { close(); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } } /** * Called to move the overlay toolbox to the left side of the window. */ void BrainBrowserWindow::processMoveOverlayToolBoxToLeft() { moveOverlayToolBox(Qt::LeftDockWidgetArea); } /** * Called to move the overlay toolbox to the bottom side of the window. */ void BrainBrowserWindow::processMoveOverlayToolBoxToBottom() { moveOverlayToolBox(Qt::BottomDockWidgetArea); } /** * Called to move the overlay toolbox to float outside of the window. */ void BrainBrowserWindow::processMoveOverlayToolBoxToFloat() { moveOverlayToolBox(Qt::NoDockWidgetArea); } /** * Called to hide the overlay toolbox. */ void BrainBrowserWindow::processHideOverlayToolBox() { processShowOverlayToolBox(false); } /** * Called to move the layers toolbox to the right side of the window. */ void BrainBrowserWindow::processMoveFeaturesToolBoxToRight() { moveFeaturesToolBox(Qt::RightDockWidgetArea); } /** * Called to move the layers toolbox to float outside of the window. */ void BrainBrowserWindow::processMoveFeaturesToolBoxToFloat() { moveFeaturesToolBox(Qt::NoDockWidgetArea); } /** * Called to hide the layers tool box. */ void BrainBrowserWindow::processHideFeaturesToolBox() { if (m_featuresToolBoxAction->isChecked()) { m_featuresToolBoxAction->trigger(); } } /** * Called to display the layers toolbox. */ void BrainBrowserWindow::processShowFeaturesToolBox(bool status) { if (status) { m_featuresToolBoxAction->setToolTip("Hide Features Toolbox"); EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(m_browserWindowIndex).addToolBox().getPointer()); } else { m_featuresToolBoxAction->setToolTip("Show Features Toolbox"); } } /** * Move the overlay toolbox to the desired location. * @param area * DockWidget location. */ void BrainBrowserWindow::moveFeaturesToolBox(Qt::DockWidgetArea area) { switch (area) { case Qt::LeftDockWidgetArea: CaretAssertMessage(0, "Layers toolbox not allowed on left"); break; case Qt::RightDockWidgetArea: m_featuresToolBox->setFloating(false); addDockWidget(Qt::RightDockWidgetArea, m_featuresToolBox); if (m_featuresToolBoxAction->isChecked() == false) { m_featuresToolBoxAction->trigger(); } break; case Qt::TopDockWidgetArea: CaretAssertMessage(0, "Layers toolbox not allowed on top"); break; case Qt::BottomDockWidgetArea: CaretAssertMessage(0, "Layers toolbox not allowed on bottom"); break; default: m_featuresToolBox->setFloating(true); if (m_featuresToolBoxAction->isChecked() == false) { m_featuresToolBoxAction->trigger(); } break; } } /** * Move the overlay toolbox to the desired location. * @param area * DockWidget location. */ void BrainBrowserWindow::moveOverlayToolBox(Qt::DockWidgetArea area) { bool isVisible = false; switch (area) { case Qt::LeftDockWidgetArea: m_overlayHorizontalToolBox->setVisible(false); m_overlayVerticalToolBox->setFloating(false); addDockWidget(Qt::LeftDockWidgetArea, m_overlayVerticalToolBox); m_overlayVerticalToolBox->setVisible(true); m_overlayActiveToolBox = m_overlayVerticalToolBox; isVisible = true; break; case Qt::RightDockWidgetArea: CaretAssertMessage(0, "Overlay toolbox not allowed on right"); break; case Qt::TopDockWidgetArea: CaretAssertMessage(0, "Overlay toolbox not allowed on top"); break; case Qt::BottomDockWidgetArea: m_overlayVerticalToolBox->setVisible(false); m_overlayHorizontalToolBox->setFloating(false); addDockWidget(Qt::BottomDockWidgetArea, m_overlayHorizontalToolBox); m_overlayHorizontalToolBox->setVisible(true); m_overlayActiveToolBox = m_overlayHorizontalToolBox; isVisible = true; break; default: m_overlayActiveToolBox->setVisible(true); m_overlayActiveToolBox->setFloating(true); isVisible = true; break; } processShowOverlayToolBox(isVisible); } /** * Remove and return all tabs from this toolbar. * After this the window containing this toolbar * will contain no tabs! * * @param allTabContent * Will contain the content from the tabs upon return. */ void BrainBrowserWindow::removeAndReturnAllTabs(std::vector& allTabContent) { m_toolbar->removeAndReturnAllTabs(allTabContent); } /** * @return Return the active browser tab content in * this browser window. */ BrowserTabContent* BrainBrowserWindow::getBrowserTabContent() { return m_toolbar->getTabContentFromSelectedTab(); } /** * @return Return the active browser tab content in * this browser window. */ const BrowserTabContent* BrainBrowserWindow::getBrowserTabContent() const { return m_toolbar->getTabContentFromSelectedTab(); } /** * get browser tab content for tab with specified tab Index * @param tabIndex * Desired tabIndex * @return Return the active browser tab content in * this browser window. */ BrowserTabContent* BrainBrowserWindow::getBrowserTabContent(int tabIndex) { return m_toolbar->getTabContentFromTab(tabIndex); } /** * Get content of all tabs * * @param allTabContent * Will contain the tabs in window upon return */ void BrainBrowserWindow::getAllTabContent(std::vector& allTabContent) const { m_toolbar->getAllTabContent(allTabContent); } /** * Get indices of all tabs in window * * @param allTabContentIndices * Will contain the indices from all tabs in window upon return. */ void BrainBrowserWindow::getAllTabContentIndices(std::vector& allTabContentIndices) const { allTabContentIndices.clear(); std::vector allTabContent; getAllTabContent(allTabContent); for (std::vector::iterator iter = allTabContent.begin(); iter != allTabContent.end(); iter++) { const BrowserTabContent* btc = *iter; CaretAssert(btc); allTabContentIndices.push_back(btc->getTabNumber()); } } /** * @return Browser window's content. */ BrowserWindowContent* BrainBrowserWindow::getBrowerWindowContent() { return m_browserWindowContent; } /** * @return Browser window's content (const method). */ const BrowserWindowContent* BrainBrowserWindow::getBrowerWindowContent() const { return m_browserWindowContent; } /** * Returns a popup menu for the main window. * Overrides that in QMainWindow and prevents the * default context menu from appearing. * "O * nothing available. */ QMenu* BrainBrowserWindow::createPopupMenu() { return NULL; } /** * Open a connection to the allen brain institute database. */ void BrainBrowserWindow::processConnectToAllenDataBase() { GuiManager::get()->processShowAllenDataBaseWebView(this); } /** * Open a connection to the human connectome project database. */ void BrainBrowserWindow::processConnectToConnectomeDataBase() { GuiManager::get()->processShowConnectomeDataBaseWebView(this); } /** * Load the HCP Website into the user's web browser. */ void BrainBrowserWindow::processHcpWebsiteInBrowser() { QUrl url("https://humanconnectome.org"); QDesktopServices::openUrl(url); } /** * Report a Workbench bug. */ void BrainBrowserWindow::processReportWorkbenchBug() { GuiManager::get()->processShowBugReportDialog(this, m_openGLWidget->getOpenGLInformation()); } /** * Load the HCP Feature Request Website into the user's web browser. */ void BrainBrowserWindow::processHcpFeatureRequestWebsiteInBrowser() { QUrl url("http://humanconnectome.org/contact/feature-request.php"); QDesktopServices::openUrl(url); } /** * @rerturn Aspect ratio of the OpenGL widget. */ float BrainBrowserWindow::getOpenGLWidgetAspectRatio() const { const float w = this->m_openGLWidget->width(); const float h = this->m_openGLWidget->height(); const float aspectRatio = ((w != 0.0) ? (h / w) : 1.0); return aspectRatio; } /** * BrowserWindowContent is owned and saved to and restored from * Scenes by SessionManager. Since SessionManager is save to * Scene before instances of this class, update content * of BrowserWindowContent. */ void BrainBrowserWindow::saveBrowserWindowContentForScene() { std::vector allTabIndices; getAllTabContentIndices(allTabIndices); m_browserWindowContent->setSceneWindowTabIndices(allTabIndices); const BrowserTabContent* activeTabContent = getBrowserTabContent(); if (activeTabContent != NULL) { m_browserWindowContent->setSceneSelectedTabIndex(activeTabContent->getTabNumber()); } m_browserWindowContent->setSceneGraphicsWidth(m_openGLWidget->width()); m_browserWindowContent->setSceneGraphicsHeight(m_openGLWidget->height()); } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* BrainBrowserWindow::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "BrainBrowserWindow", 2); /* Version 2: 07 feb 2018 */ m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); /* m_browserWindowIndex used with wb_command -show-scene */ sceneClass->addInteger("m_browserWindowIndex", m_browserWindowIndex); /* * Save toolbar */ sceneClass->addClass(m_toolbar->saveToScene(sceneAttributes, "m_toolbar")); /* * Save overlay toolbox */ { AString orientationName = ""; if (m_overlayActiveToolBox == m_overlayHorizontalToolBox) { orientationName = "horizontal"; } else if (m_overlayActiveToolBox == m_overlayVerticalToolBox) { orientationName = "vertical"; } SceneClass* overlayToolBoxClass = new SceneClass("overlayToolBox", "OverlayToolBox", 1); overlayToolBoxClass->addString("orientation", orientationName); overlayToolBoxClass->addBoolean("floating", m_overlayActiveToolBox->isFloating()); overlayToolBoxClass->addBoolean("visible", m_overlayActiveToolBox->isVisible()); sceneClass->addClass(overlayToolBoxClass); sceneClass->addClass(m_overlayActiveToolBox->saveToScene(sceneAttributes, "m_overlayActiveToolBox")); } switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } /* * Save features toolbox */ { SceneClass* featureToolBoxClass = new SceneClass("featureToolBox", "FeatureToolBox", 1); featureToolBoxClass->addBoolean("floating", m_featuresToolBox->isFloating()); featureToolBoxClass->addBoolean("visible", m_featuresToolBox->isVisible()); sceneClass->addClass(featureToolBoxClass); sceneClass->addClass(m_featuresToolBox->saveToScene(sceneAttributes, "m_featuresToolBox")); } /* * Position and size */ SceneWindowGeometry swg(this); sceneClass->addClass(swg.saveToScene(sceneAttributes, "geometry")); sceneClass->addBoolean("isFullScreen", isFullScreen()); sceneClass->addBoolean("isMaximized", isMaximized()); /* * Graphics position and size, used with wb_command -show-scene */ SceneWindowGeometry openGLGeometry(m_openGLWidget); sceneClass->addClass(openGLGeometry.saveToScene(sceneAttributes, "openGLWidgetGeometry")); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void BrainBrowserWindow::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } const int32_t sceneVersion = sceneClass->getVersionNumber(); /* * Restore toolbar */ const SceneClass* toolbarClass = sceneClass->getClass("m_toolbar"); if (toolbarClass != NULL) { m_toolbar->restoreFromScene(sceneAttributes, toolbarClass); } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); if ( ! m_browserWindowContent->isValid()) { sceneAttributes->addToErrorMessage("Scene Error: Browser window content is invalid for window " + AString::number(m_browserWindowIndex + 1)); return; } /* * Restoration status for full screen and tab tiles * * If "m_screenMode" is found, the scene is an older scene that was * created prior to splitting Full Screen and Tile Tabs into * separate functionality. */ bool restoreToFullScreen = false; bool restoreToTabTiles = false; const SceneObject* screenModeObject = sceneClass->getObjectWithName("m_screenMode"); if (screenModeObject != NULL) { const SceneEnumeratedType* screenEnum = dynamic_cast(screenModeObject); if (screenEnum != NULL) { const AString screenModeName = screenEnum->stringValue(); if (screenModeName == "NORMAL") { } else if (screenModeName == "FULL_SCREEN") { restoreToFullScreen = true; } else if (screenModeName == "TAB_MONTAGE") { restoreToTabTiles = true; } else if (screenModeName == "TAB_MONTAGE_FULL_SCREEN") { restoreToTabTiles = true; restoreToFullScreen = true; } else { CaretLogWarning("Unrecognized obsolete screen mode: " + screenModeName); } } } else { restoreToFullScreen = sceneClass->getBooleanValue("isFullScreen", false); if (sceneVersion >= 2) { restoreToTabTiles = m_browserWindowContent->isTileTabsEnabled(); } else { restoreToTabTiles = sceneClass->getBooleanValue("m_viewTileTabsAction", false); } setViewTileTabs(restoreToTabTiles); } m_normalWindowComponentStatus = m_defaultWindowComponentStatus; processViewFullScreen(restoreToFullScreen, false); /* * Position and size */ SceneWindowGeometry swg(this); swg.restoreFromScene(sceneAttributes, sceneClass->getClass("geometry")); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); QApplication::processEvents(); if (restoreToFullScreen == false) { /* * Restore feature toolbox */ const SceneClass* featureToolBoxClass = sceneClass->getClass("featureToolBox"); if (featureToolBoxClass != NULL) { const bool toolBoxVisible = featureToolBoxClass->getBooleanValue("visible", true); const bool toolBoxFloating = featureToolBoxClass->getBooleanValue("floating", false); if (toolBoxVisible) { if (toolBoxFloating) { processMoveFeaturesToolBoxToFloat(); } else { processMoveFeaturesToolBoxToRight(); } } m_featuresToolBoxAction->blockSignals(true); m_featuresToolBoxAction->setChecked(! toolBoxVisible); m_featuresToolBoxAction->blockSignals(false); m_featuresToolBoxAction->trigger(); m_featuresToolBox->restoreFromScene(sceneAttributes, sceneClass->getClass("m_featuresToolBox")); /* * Toolboxes were not restoring to correct size in Qt5. * Qt5.6 adds a new method, QMainWindow::resizeDocks() that * resizes a QDockWidget in one dimension. Use it to resize * the toolbox. */ const SceneClass* featureToolBoxClass = sceneClass->getClass("m_featuresToolBox"); if (featureToolBoxClass != NULL) { const int w = featureToolBoxClass->getIntegerValue("toolboxWidth", -1); const int h = featureToolBoxClass->getIntegerValue("toolboxHeight", -1); if ((w > 0) && (h > 0)) { QList dockList; dockList.append(m_featuresToolBox); QList sizeList; sizeList.append(w); resizeDockWidgets(dockList, sizeList, Qt::Horizontal); } } } /* * Restore overlay toolbox */ const SceneClass* overlayToolBoxClass = sceneClass->getClass("overlayToolBox"); if (overlayToolBoxClass != NULL) { const AString orientationName = overlayToolBoxClass->getStringValue("orientation", "horizontal"); const bool toolBoxVisible = overlayToolBoxClass->getBooleanValue("visible", true); const bool toolBoxFloating = overlayToolBoxClass->getBooleanValue("floating", false); if (orientationName == "horizontal") { processMoveOverlayToolBoxToBottom(); } else { processMoveOverlayToolBoxToLeft(); } if (toolBoxFloating) { processMoveOverlayToolBoxToFloat(); } processShowOverlayToolBox(toolBoxVisible); m_overlayActiveToolBox->restoreFromScene(sceneAttributes, sceneClass->getClass("m_overlayActiveToolBox")); /* * Toolboxes were not restoring to correct size in Qt5. * Qt5 adds a new method, QMainWindow::resizeDocks() that * resizes a QDockWidget in one dimension. Use it to resize * the toolbox. */ const SceneClass* activeToolBoxClass = sceneClass->getClass("m_overlayActiveToolBox"); if (activeToolBoxClass != NULL) { const int w = activeToolBoxClass->getIntegerValue("toolboxWidth", -1); const int h = activeToolBoxClass->getIntegerValue("toolboxHeight", -1); if ((w > 0) && (h > 0)) { QList dockList; dockList.append(m_overlayActiveToolBox); if (orientationName == "horizontal") { QList sizeList; sizeList.append(h); resizeDockWidgets(dockList, sizeList, Qt::Vertical); } else { QList sizeList; sizeList.append(w); resizeDockWidgets(dockList, sizeList, Qt::Horizontal); } } } } } switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } const bool maximizedWindow = sceneClass->getBooleanValue("isMaximized", false); if (maximizedWindow) { showMaximized(); } /* prevent "failed to restore" messages */ sceneClass->getIntegerValue("m_browserWindowIndex"); const SceneClass* openglGeomClass = sceneClass->getClass("openGLWidgetGeometry"); if (openglGeomClass != NULL) { openglGeomClass->setDescendantsRestored(true); } if (sceneVersion >= 2) { } else { /* * Before version 2, each tab was allowed its own aspect locking status */ std::vector allTabContent; m_toolbar->getAllTabContent(allTabContent); const int32_t lockedCount = std::count_if(allTabContent.begin(), allTabContent.end(), [](BrowserTabContent* btc) { return btc->isAspectRatioLocked(); }); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); lockAllTabAspectRatios(lockedCount > 0); } updateActionsForLockingAspectRatios(); } /** * @return A string describing the object's content. */ AString BrainBrowserWindow::toString() const { AString msg; msg.appendWithNewLine("Window " + AString::number(getBrowserWindowIndex() + 1) + ":"); const BrowserTabContent* btc = getBrowserTabContent(); if (btc != NULL) { msg.appendWithNewLine(btc->toString()); } return msg; } /** * Get a text description of the window's content. * * @param descriptionOut * Description of the window's content. */ void BrainBrowserWindow::getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const { descriptionOut.addLine("Window " + AString::number(getBrowserWindowIndex() + 1) + ":"); std::vector tabContent; if (isTileTabsSelected()) { m_toolbar->getAllTabContent(tabContent); } else { BrowserTabContent* btc = m_toolbar->getTabContentFromSelectedTab(); if (btc != NULL) { tabContent.push_back(btc); } } descriptionOut.pushIndentation(); for (std::vector::iterator iter = tabContent.begin(); iter != tabContent.end(); iter++) { const BrowserTabContent* btc = *iter; btc->getDescriptionOfContent(descriptionOut); } descriptionOut.popIndentation(); } /** * @return Has valid OpenGL. */ bool BrainBrowserWindow::hasValidOpenGL() { return m_openGLWidget->isValid(); } /** * Show the data file read warnings dialog but only * if warnings are found in any files. */ void BrainBrowserWindow::showDataFileReadWarningsDialog() { Brain* brain = GuiManager::get()->getBrain(); if (brain == NULL) { return; } std::vector dataFiles; brain->getAllDataFiles(dataFiles); AString messages; for (auto file : dataFiles) { const AString msg = file->getFileReadWarnings(); if ( ! msg.isEmpty()) { messages.append("

  • " + file->getFileName() + "
    " + msg + "
  • "); } } if ( ! messages.isEmpty()) { messages.insert(0, "
      "); messages.append("
    "); WuQTextEditorDialog::runNonModal("Data File Warnings", messages, WuQTextEditorDialog::TextMode::HTML, WuQTextEditorDialog::WrapMode::NO, this); } } /** * Set the enabled status for enabling mac duplicate menu bar for * the next created toolbar. */ void BrainBrowserWindow::setEnableMacDuplicateMenuBar(bool status) { s_enableMacDuplicateMenuBarFlag = status; } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindow.h000066400000000000000000000437471360521144700234320ustar00rootroot00000000000000 #ifndef __BRAIN_BROWSER_WINDOW_H__ #define __BRAIN_BROWSER_WINDOW_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include "AString.h" #include "DataFileTypeEnum.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" #include "TileTabsGridModeEnum.h" class QAction; class QActionGroup; class QMenu; class QToolButton; class QDockWidget; namespace caret { class BrainBrowserWindowToolBar; class BrainBrowserWindowOrientedToolBox; class BrainOpenGLWidget; class BrowserWindowContent; class BrowserTabContent; class EventTileTabsConfigurationModification; class PlainTextStringBuilder; class SceneClassAssistant; class TileTabsConfiguration; /** * The brain browser window is the viewer for * brain models. It may contain multiple tabs * with each tab displaying brain models. */ class BrainBrowserWindow : public QMainWindow, public EventListenerInterface, public SceneableInterface { Q_OBJECT public: virtual ~BrainBrowserWindow(); virtual void receiveEvent(Event* event); BrowserTabContent* getBrowserTabContent(); const BrowserTabContent* getBrowserTabContent() const; BrowserTabContent* getBrowserTabContent(int tabIndex); BrowserWindowContent* getBrowerWindowContent(); const BrowserWindowContent* getBrowerWindowContent() const; QMenu* createPopupMenu(); void getAllTabContent(std::vector& allTabContent) const; void getAllTabContentIndices(std::vector& allTabContentIndices) const; void removeAndReturnAllTabs(std::vector& allTabContent); int32_t getBrowserWindowIndex() const; bool isTileTabsSelected() const; /** * Mode for loading spec files */ enum LoadSpecFileMode { /** Do not show spec file dialog, just load all files listed in spec file listed on command line at program startup */ LOAD_SPEC_FILE_CONTENTS_VIA_COMMAND_LINE, /** Show spec file in spec file dialog for user selections */ LOAD_SPEC_FILE_WITH_DIALOG, /** Show spec file in spec file dialog for user selections from spec file listed on command line at program startup */ LOAD_SPEC_FILE_WITH_DIALOG_VIA_COMMAND_LINE }; void loadFilesFromCommandLine(const std::vector& filenames, const LoadSpecFileMode loadSpecFileMode); void loadSceneFromCommandLine(const AString& sceneFileName, const AString& sceneNameOrNumber); bool loadFilesFromNetwork(QWidget* parentForDialogs, const std::vector& filenames, const std::vector dataFileTypes, const AString& username, const AString& password); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); void resetGraphicsWidgetMinimumSize(); void setGraphicsWidgetFixedSize(const int32_t width, const int32_t height); void getGraphicsWidgetSize(int32_t& xOut, int32_t& yOut, int32_t& widthOut, int32_t& heightOut, int32_t& graphicsWidthOut, int32_t& graphicsHeightOut, const bool applyLockedAspectRatiosFlag) const; AString toString() const; virtual void getDescriptionOfContent(PlainTextStringBuilder& descriptionOut) const; static int32_t loadRecentSpecFileMenu(QMenu* recentSpecFileMenu); static int32_t loadRecentSceneFileMenu(QMenu* recentSpecFileMenu); float getOpenGLWidgetAspectRatio() const; bool changeInputModeToAnnotationsWarningDialog(); bool isWindowAspectRatioLocked() const; float getAspectRatio() const; bool hasValidOpenGL(); bool isOpenGLContextSharingValid() const; AString getTileTabsConfigurationLabelText(const TileTabsGridModeEnum::Enum configurationMode, const bool includeRowsAndColumns) const; void resizeDockWidgets(const QList &docks, const QList &sizes, Qt::Orientation orientation); static void setEnableMacDuplicateMenuBar(bool status); protected: void closeEvent(QCloseEvent* event); void keyPressEvent(QKeyEvent* event); private slots: void processAboutWorkbench(); void processInformationDialog(); void processNewWindow(); void processNewTab(); void processDuplicateTab(); void processDataFileLocationOpen(); void processDataFileOpen(); void processManageSaveLoadedFiles(); void processCaptureImage(); void processMovieRecording(); void processRecordMovie(); void processEditPreferences(); void processCloseAllFiles(); void processCloseWindow(); void processExitProgram(); void processMoveAllTabsToOneWindow(); void processViewFullScreenSelected(); void processViewTileTabs(); void processViewTileTabsConfigurationDialog(); void processShowHelpInformation(); void processShowIdentifyBrainordinateDialog(); void processGapsAndMargins(); void processViewTileTabsLoadUserConfigurationMenuAboutToShow(); void processViewTileTabsLoadUserConfigurationMenuItemTriggered(QAction* action); void processViewTileTabsAutomaticCustomTriggered(QAction* action); void processMoveOverlayToolBoxToLeft(); void processMoveOverlayToolBoxToBottom(); void processMoveOverlayToolBoxToFloat(); void processHideOverlayToolBox(); void processMoveFeaturesToolBoxToRight(); void processMoveFeaturesToolBoxToFloat(); void processHideFeaturesToolBox(); void processMoveSelectedTabToWindowMenuAboutToBeDisplayed(); void processMoveSelectedTabToWindowMenuSelection(QAction*); void processRecentSceneFileMenuAboutToBeDisplayed(); void processRecentSceneFileMenuSelection(QAction*); void processRecentSpecFileMenuAboutToBeDisplayed(); void processRecentSpecFileMenuSelection(QAction*); void processShowOverlayToolBox(bool); void processShowFeaturesToolBox(bool); void processOverlayHorizontalToolBoxVisibilityChanged(bool); void processOverlayVerticalToolBoxVisibilityChanged(bool); void processFileMenuAboutToShow(); void processDataMenuAboutToShow(); void processViewMenuAboutToShow(); void processSurfaceMenuInformation(); void processSurfaceMenuPrimaryAnatomical(); void processConnectToAllenDataBase(); void processConnectToConnectomeDataBase(); void processHcpWebsiteInBrowser(); void processHcpFeatureRequestWebsiteInBrowser(); void processReportWorkbenchBug(); void processShowSurfacePropertiesDialog(); void processShowVolumePropertiesDialog(); void processDevelopGraphicsTiming(); void processDevelopExportVtkFile(); void developerMenuAboutToShow(); void developerMenuFlagTriggered(QAction*); void processProjectFoci(); void processSplitBorderFiles(); void processWindowMenuLockWindowAspectRatioTriggered(bool checked); void processWindowMenuLockAllTabAspectRatioTriggered(bool checked); void processToolBarLockWindowAndAllTabAspectTriggered(bool checked); void processToolBarLockWindowAndAllTabAspectMenu(const QPoint& pos); void processEditMenuItemTriggered(QAction* action); void processEditMenuAboutToShow(); void aspectRatioDialogUpdateForTab(const double aspectRatio); void aspectRatioDialogUpdateForWindow(const double aspectRatio); private: /** Contains status of components such as enter/exit full screen */ struct WindowComponentStatus { bool isFeaturesToolBoxDisplayed; bool isOverlayToolBoxDisplayed; bool isToolBarDisplayed; QByteArray windowState; QByteArray windowGeometry; QByteArray featuresGeometry; }; enum CreateDefaultTabsMode { CREATE_DEFAULT_TABS_YES, CREATE_DEFAULT_TABS_NO }; enum class AspectRatioMode { TAB, WINDOW }; BrainBrowserWindow(const int browserWindowIndex, BrowserTabContent* browserTabContent, const CreateDefaultTabsMode createDefaultTabsMode, QWidget* parent = 0, Qt::WindowFlags flags = 0); BrainBrowserWindow(const BrainBrowserWindow&); BrainBrowserWindow& operator=(const BrainBrowserWindow&); bool loadFiles(QWidget* parentForDialogs, const std::vector& filenames, const std::vector dataFileTypes, const LoadSpecFileMode loadSpecFileMode, const AString& username, const AString& password); void createActions(); void createActionsUsedByToolBar(); void createMenus(); QMenu* createMenuDevelop(); QMenu* createMenuEdit(); QMenu* createMenuFile(); QMenu* createMenuView(); QMenu* createMenuViewMoveOverlayToolBox(); QMenu* createMenuViewMoveFeaturesToolBox(); QMenu* createMenuViewTileTabsLoadUserConfiguration(); QMenu* createMenuConnect(); QMenu* createMenuData(); QMenu* createMenuSurface(); QMenu* createMenuVolume(); QMenu* createMenuWindow(); QMenu* createMenuHelp(); void moveOverlayToolBox(Qt::DockWidgetArea area); void moveFeaturesToolBox(Qt::DockWidgetArea area); void restoreWindowComponentStatus(const WindowComponentStatus& wcs); void saveWindowComponentStatus(WindowComponentStatus& wcs); void openSpecFile(const AString& specFileName); void processViewFullScreen(bool showFullScreenDisplay, const bool saveRestoreWindowStatus); void setViewTileTabs(const bool newStatus); bool isMacOptionKeyDown() const; void showDataFileReadWarningsDialog(); void lockWindowAspectRatio(const bool checked); void lockAllTabAspectRatios(const bool checked); void updateActionsForLockingAspectRatios(); void processToolBarLockWindowAndAllTabAspectsRatios(bool checked); float getAspectRatioFromDialog(const AspectRatioMode aspectRatioMode, const QString& title, const float aspectRatio, QWidget* parent) const; void saveBrowserWindowContentForScene(); void modifyTileTabsConfiguration(EventTileTabsConfigurationModification* modEvent); /** Index of this window */ const int32_t m_browserWindowIndex; BrowserWindowContent* m_browserWindowContent = NULL; BrainOpenGLWidget* m_openGLWidget; BrainBrowserWindowToolBar* m_toolbar; QAction* m_aboutWorkbenchAction; QAction* m_newWindowAction; QAction* m_newTabAction; QAction* m_duplicateTabAction; QAction* m_openFileAction; QAction* m_openLocationAction; QAction* m_manageFilesAction; QAction* m_closeSpecFileAction; QAction* m_closeTabAction; QAction* m_closeWindowAction; AString m_closeWindowActionConfirmTitle; AString m_closeWindowActionNoConfirmTitle; bool m_closeWithoutConfirmationFlag; QAction* m_captureImageAction; QAction* m_movieRecordingAction; QAction* m_recordMovieAction; QAction* m_preferencesAction; QAction* m_exitProgramAction; QAction* m_showToolBarAction; QMenu* m_viewMoveFeaturesToolBoxMenu; QMenu* m_viewMoveOverlayToolBoxMenu; QMenu* m_viewTileTabsLoadUserConfigurationMenu; QAction* m_viewFullScreenAction; QAction* m_viewTileTabsAction; QAction* m_viewTileTabsConfigurationDialogAction; QAction* m_viewAutomaticTileTabsConfigurationAction; QAction* m_viewCustomTileTabsConfigurationAction; std::vector> m_viewCustomTileTabsConfigurationActions; QAction* m_gapsAndMarginsAction; QAction* m_nextTabAction; QAction* m_previousTabAction; QAction* m_renameSelectedTabAction; QAction* m_moveTabsInWindowToNewWindowsAction; QAction* m_moveTabsFromAllWindowsToOneWindowAction; QAction* m_bringAllToFrontAction; QAction* m_tileWindowsAction; QAction* m_informationDialogAction; QAction* m_connectToAllenDatabaseAction; QAction* m_connectToConnectomeDatabaseAction; QAction* m_helpHcpWebsiteAction; QAction* m_helpHcpFeatureRequestAction; QAction* m_helpWorkbenchBugReportAction; QAction* m_developMenuAction; QActionGroup* m_developerFlagsActionGroup; QAction* m_developerGraphicsTimingAction; QAction* m_developerExportVtkFileAction; QAction* m_overlayToolBoxAction; QAction* m_windowMenuLockWindowAspectRatioAction; QAction* m_windowMenuLockAllTabAspectRatioAction; QAction* m_toolBarLockWindowAndAllTabAspectRatioAction; QToolButton* m_toolBarLockWindowAndAllTabAspectRatioButton; QAction* m_featuresToolBoxAction; QAction* m_dataFociProjectAction; QAction* m_dataBorderFilesSplitAction; QMenu* m_moveSelectedTabToWindowMenu; QMenu* m_recentSpecFileMenu; AString m_recentSpecFileMenuOpenConfirmTitle; AString m_recentSpecFileMenuLoadNoConfirmTitle; QMenu* m_recentSceneFileMenu; QMenu* m_editMenu; QAction* m_editMenuRedoAction; QAction* m_editMenuUndoAction; BrainBrowserWindowOrientedToolBox* m_overlayHorizontalToolBox; BrainBrowserWindowOrientedToolBox* m_overlayVerticalToolBox; BrainBrowserWindowOrientedToolBox* m_overlayActiveToolBox; BrainBrowserWindowOrientedToolBox* m_featuresToolBox; static AString s_previousOpenFileNameFilter; static AString s_previousOpenFileDirectory; static QByteArray s_previousOpenFileGeometry; WindowComponentStatus m_defaultWindowComponentStatus; WindowComponentStatus m_normalWindowComponentStatus; static bool s_firstWindowFlag; friend class BrainBrowserWindowToolBar; friend class GuiManager; SceneClassAssistant* m_sceneAssistant; /** X position from scene file for first window */ static int32_t s_sceneFileFirstWindowX; /** Y position from scene file for first window */ static int32_t s_sceneFileFirstWindowY; static std::set s_brainBrowserWindows; QString m_objectNamePrefix; bool m_keyEventProcessingFlag = false; static bool s_enableMacDuplicateMenuBarFlag; }; #ifdef __BRAIN_BROWSER_WINDOW_DECLARE__ std::set BrainBrowserWindow::s_brainBrowserWindows; AString BrainBrowserWindow::s_previousOpenFileNameFilter; AString BrainBrowserWindow::s_previousOpenFileDirectory; QByteArray BrainBrowserWindow::s_previousOpenFileGeometry; bool BrainBrowserWindow::s_firstWindowFlag = true; int32_t BrainBrowserWindow::s_sceneFileFirstWindowX = -1; int32_t BrainBrowserWindow::s_sceneFileFirstWindowY = -1; bool BrainBrowserWindow::s_enableMacDuplicateMenuBarFlag = false; #endif // __BRAIN_BROWSER_WINDOW_DECLARE__ } #endif // __BRAIN_BROWSER_WINDOW_H__ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowComboBox.cxx000066400000000000000000000125351360521144700254250ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BRAIN_BROWSER_WINDOW_COMBO_BOX_DECLARE__ #include "BrainBrowserWindowComboBox.h" #undef __BRAIN_BROWSER_WINDOW_COMBO_BOX_DECLARE__ #include #include "BrainBrowserWindow.h" #include "CaretAssert.h" #include "GuiManager.h" using namespace caret; /** * \class caret::BrainBrowserWindowComboBox * \brief Combo box for selection of browser windows * \ingroup GuiQt */ /** * Constructor. * * @param style * Style of combo box content * @param parent * Parent of this combo box */ BrainBrowserWindowComboBox::BrainBrowserWindowComboBox(const Style style, QObject* parent) : WuQWidget(parent), m_style(style) { m_comboBox = new QComboBox(); QObject::connect(m_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(comboBoxIndexSelected(int))); } /** * Destructor. */ BrainBrowserWindowComboBox::~BrainBrowserWindowComboBox() { } /** * Called when the user selects an item from the combo box. * @param indx * Index of item selected. */ void BrainBrowserWindowComboBox::comboBoxIndexSelected(int /*indx*/) { BrainBrowserWindow* bbw = getSelectedBrowserWindow(); if (bbw != NULL) { emit browserWindowIndexSelected(bbw->getBrowserWindowIndex()); emit browserWindowSelected(bbw); } } /** * Update the combo box. */ void BrainBrowserWindowComboBox::updateComboBox() { m_comboBox->blockSignals(true); std::vector browserWindows = GuiManager::get()->getAllOpenBrainBrowserWindows(); BrainBrowserWindow* selectedWindow = getSelectedBrowserWindow(); m_comboBox->clear(); int32_t defaultIndex = 0; const int32_t numWindows = static_cast(browserWindows.size()); for (int32_t i = 0; i < numWindows; i++) { BrainBrowserWindow* bbw = browserWindows[i]; const int32_t browserWindowIndex = bbw->getBrowserWindowIndex(); switch (m_style) { case STYLE_NAME_AND_NUMBER: m_comboBox->addItem("Window " + QString::number(browserWindowIndex + 1)); break; case STYLE_NUMBER: m_comboBox->addItem(QString::number(browserWindowIndex + 1)); break; } m_comboBox->setItemData(i, qVariantFromValue((void*)bbw)); if (bbw == selectedWindow) { defaultIndex = i; } } if (defaultIndex < m_comboBox->count()) { m_comboBox->setCurrentIndex(defaultIndex); } m_comboBox->blockSignals(false); } /** * @return The widget inside this control. */ QWidget* BrainBrowserWindowComboBox::getWidget() { return m_comboBox; } /** * Set the selected browser window using the browser window index. * If the index is invalid selection will not change. * * @param browserWindowIndex * Index of window. */ void BrainBrowserWindowComboBox::setBrowserWindowByIndex(const int32_t browserWindowIndex) { for (int32_t i = 0; i < m_comboBox->count(); i++) { void* pointer = m_comboBox->itemData(i).value(); BrainBrowserWindow* bbw = (BrainBrowserWindow*)pointer; if (bbw->getBrowserWindowIndex() == browserWindowIndex) { m_comboBox->blockSignals(true); m_comboBox->setCurrentIndex(i); m_comboBox->blockSignals(false); return; } } } /** * Set the selected browser window. * If the window is invalid selection will not change. * * @param browserWindow * The window. */ void BrainBrowserWindowComboBox::setBrowserWindow(BrainBrowserWindow* browserWindow) { CaretAssert(browserWindow); setBrowserWindowByIndex(browserWindow->getBrowserWindowIndex()); } /** * @return Index of selected browser window. A negative value * is returned if invalid. */ int32_t BrainBrowserWindowComboBox::getSelectedBrowserWindowIndex() const { int32_t indx = -1; BrainBrowserWindow* bbw = getSelectedBrowserWindow(); if (bbw != NULL) { indx = bbw->getBrowserWindowIndex(); } return indx; } /** * @return Selected browser window. NULL is returned if invalid. */ BrainBrowserWindow* BrainBrowserWindowComboBox::getSelectedBrowserWindow() const { BrainBrowserWindow* bbw = NULL; const int32_t indx = m_comboBox->currentIndex(); if ((indx >= 0) && (indx < m_comboBox->count())) { void* pointer = m_comboBox->itemData(indx).value(); bbw = (BrainBrowserWindow*)pointer; } return bbw; } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowComboBox.h000066400000000000000000000053161360521144700250510ustar00rootroot00000000000000#ifndef __BRAIN_BROWSER_WINDOW_COMBO_BOX_H__ #define __BRAIN_BROWSER_WINDOW_COMBO_BOX_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "WuQWidget.h" class QComboBox; namespace caret { class BrainBrowserWindow; class BrainBrowserWindowComboBox : public WuQWidget { Q_OBJECT public: /** * Style of combo box content */ enum Style { /** Name and number: "Window 3" */ STYLE_NAME_AND_NUMBER, /** Number only: "3" */ STYLE_NUMBER }; BrainBrowserWindowComboBox(const Style style, QObject* parent); virtual ~BrainBrowserWindowComboBox(); void updateComboBox(); virtual QWidget* getWidget(); void setBrowserWindowByIndex(const int32_t browserWindowIndex); void setBrowserWindow(BrainBrowserWindow* browserWindow); int32_t getSelectedBrowserWindowIndex() const; BrainBrowserWindow* getSelectedBrowserWindow() const; signals: void browserWindowIndexSelected(const int32_t browserWindowIndex); void browserWindowSelected(BrainBrowserWindow* browserWindow); private slots: void comboBoxIndexSelected(int indx); private: BrainBrowserWindowComboBox(const BrainBrowserWindowComboBox&); BrainBrowserWindowComboBox& operator=(const BrainBrowserWindowComboBox&); public: // ADD_NEW_METHODS_HERE private: const Style m_style; QComboBox* m_comboBox; // ADD_NEW_MEMBERS_HERE }; #ifdef __BRAIN_BROWSER_WINDOW_COMBO_BOX_DECLARE__ // #endif // __BRAIN_BROWSER_WINDOW_COMBO_BOX_DECLARE__ } // namespace #endif //__BRAIN_BROWSER_WINDOW_COMBO_BOX_H__ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowEditMenuItemEnum.cxx000066400000000000000000000336001360521144700270670ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __BRAIN_BROWSER_WINDOW_EDIT_MENU_ITEM_ENUM_DECLARE__ #include "BrainBrowserWindowEditMenuItemEnum.h" #undef __BRAIN_BROWSER_WINDOW_EDIT_MENU_ITEM_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::BrainBrowserWindowEditMenuItemEnum * \brief Enumerated type for items on the Edit Menu * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_brainBrowserWindowEditMenuItemEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void brainBrowserWindowEditMenuItemEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "BrainBrowserWindowEditMenuItemEnum.h" * * Instatiate: * m_brainBrowserWindowEditMenuItemEnumComboBox = new EnumComboBoxTemplate(this); * m_brainBrowserWindowEditMenuItemEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_brainBrowserWindowEditMenuItemEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(brainBrowserWindowEditMenuItemEnumComboBoxItemActivated())); * * Update the selection: * m_brainBrowserWindowEditMenuItemEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const BrainBrowserWindowEditMenuItemEnum::Enum VARIABLE = m_brainBrowserWindowEditMenuItemEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * @param guiName * User-friendly name for use in user-interface. * @param shortCut * Shortcut for menu item. */ BrainBrowserWindowEditMenuItemEnum::BrainBrowserWindowEditMenuItemEnum(const Enum enumValue, const AString& name, const AString& guiName, const QKeySequence& shortCut) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; this->shortCut = shortCut; } /** * Destructor. */ BrainBrowserWindowEditMenuItemEnum::~BrainBrowserWindowEditMenuItemEnum() { } /** * Initialize the enumerated metadata. */ void BrainBrowserWindowEditMenuItemEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; QKeySequence noShortCutKeySequence; enumData.push_back(BrainBrowserWindowEditMenuItemEnum(COPY, "COPY", "Copy", (Qt::CTRL + Qt::Key_C))); enumData.push_back(BrainBrowserWindowEditMenuItemEnum(CUT, "CUT", "Cut", (Qt::CTRL + Qt::Key_X))); enumData.push_back(BrainBrowserWindowEditMenuItemEnum(DELETER, "DELETER", "Delete", noShortCutKeySequence)); enumData.push_back(BrainBrowserWindowEditMenuItemEnum(PASTE, "PASTE", "Paste", (Qt::CTRL + Qt::Key_V))); enumData.push_back(BrainBrowserWindowEditMenuItemEnum(PASTE_SPECIAL, "PASTE", "Paste Special", (Qt::CTRL + Qt::SHIFT + Qt::Key_V))); enumData.push_back(BrainBrowserWindowEditMenuItemEnum(REDO, "REDO", "Redo", (Qt::CTRL + Qt::Key_Y))); //(Qt::CTRL + Qt::SHIFT + Qt::Key_Z))); enumData.push_back(BrainBrowserWindowEditMenuItemEnum(SELECT_ALL, "SELECT_ALL", "Select All", (Qt::CTRL + Qt::Key_A))); enumData.push_back(BrainBrowserWindowEditMenuItemEnum(UNDO, "UNDO", "Undo", (Qt::CTRL + Qt::Key_Z))); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const BrainBrowserWindowEditMenuItemEnum* BrainBrowserWindowEditMenuItemEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const BrainBrowserWindowEditMenuItemEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString BrainBrowserWindowEditMenuItemEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const BrainBrowserWindowEditMenuItemEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ BrainBrowserWindowEditMenuItemEnum::Enum BrainBrowserWindowEditMenuItemEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = BrainBrowserWindowEditMenuItemEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const BrainBrowserWindowEditMenuItemEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type BrainBrowserWindowEditMenuItemEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString BrainBrowserWindowEditMenuItemEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const BrainBrowserWindowEditMenuItemEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ BrainBrowserWindowEditMenuItemEnum::Enum BrainBrowserWindowEditMenuItemEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = BrainBrowserWindowEditMenuItemEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const BrainBrowserWindowEditMenuItemEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type BrainBrowserWindowEditMenuItemEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t BrainBrowserWindowEditMenuItemEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const BrainBrowserWindowEditMenuItemEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ BrainBrowserWindowEditMenuItemEnum::Enum BrainBrowserWindowEditMenuItemEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = BrainBrowserWindowEditMenuItemEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const BrainBrowserWindowEditMenuItemEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type BrainBrowserWindowEditMenuItemEnum")); } return enumValue; } /** * Get the shortcut key for a data type. * * @return * Shortcut keys for data type. */ QKeySequence BrainBrowserWindowEditMenuItemEnum::toShortcut(Enum enumValue) { if (initializedFlag == false) initialize(); const BrainBrowserWindowEditMenuItemEnum* enumInstance = findData(enumValue); return enumInstance->shortCut; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void BrainBrowserWindowEditMenuItemEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void BrainBrowserWindowEditMenuItemEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(BrainBrowserWindowEditMenuItemEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void BrainBrowserWindowEditMenuItemEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(BrainBrowserWindowEditMenuItemEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowEditMenuItemEnum.h000066400000000000000000000074251360521144700265220ustar00rootroot00000000000000#ifndef __BRAIN_BROWSER_WINDOW_EDIT_MENU_ITEM_ENUM_H__ #define __BRAIN_BROWSER_WINDOW_EDIT_MENU_ITEM_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "AString.h" namespace caret { class BrainBrowserWindowEditMenuItemEnum { public: /** * Enumerated values. */ enum Enum { /** Copy */ COPY, /** Cut */ CUT, /** Delete (note: 'DELETE' is reserved word on Windows) */ DELETER, /** Paste */ PASTE, /** Paste Special */ PASTE_SPECIAL, /** Redo */ REDO, /** Select All */ SELECT_ALL, /** Undo */ UNDO }; ~BrainBrowserWindowEditMenuItemEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static QKeySequence toShortcut(Enum enumValue); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: BrainBrowserWindowEditMenuItemEnum(const Enum enumValue, const AString& name, const AString& guiName, const QKeySequence& shortCut); static const BrainBrowserWindowEditMenuItemEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; /** Shortcut key */ QKeySequence shortCut; }; #ifdef __BRAIN_BROWSER_WINDOW_EDIT_MENU_ITEM_ENUM_DECLARE__ std::vector BrainBrowserWindowEditMenuItemEnum::enumData; bool BrainBrowserWindowEditMenuItemEnum::initializedFlag = false; int32_t BrainBrowserWindowEditMenuItemEnum::integerCodeCounter = 0; #endif // __BRAIN_BROWSER_WINDOW_EDIT_MENU_ITEM_ENUM_DECLARE__ } // namespace #endif //__BRAIN_BROWSER_WINDOW_EDIT_MENU_ITEM_ENUM_H__ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx000066400000000000000000001114021360521144700267660ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "AnnotationFile.h" #include "AnnotationSelectionViewController.h" #include "AnnotationTextSubstitutionViewController.h" #include "BorderSelectionViewController.h" #include "Brain.h" #include "BrainBrowserWindow.h" #include "BrainBrowserWindowOrientedToolBox.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretDataFile.h" #include "CaretPreferences.h" #include "ChartableLineSeriesBrainordinateInterface.h" #include "ChartTwoOverlaySetViewController.h" #include "ChartableMatrixInterface.h" #include "ChartToolBoxViewController.h" #include "CiftiConnectivityMatrixViewController.h" #include "DeveloperFlagsEnum.h" #include "EventBrowserWindowDrawingContent.h" #include "EventGetOrSetUserInputModeProcessor.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "FiberOrientationSelectionViewController.h" #include "FociSelectionViewController.h" #include "GuiManager.h" #include "ImageSelectionViewController.h" #include "LabelSelectionViewController.h" #include "OverlaySetViewController.h" #include "SceneClass.h" #include "SceneWindowGeometry.h" #include "SessionManager.h" #include "VolumeDynamicConnectivityFile.h" #include "VolumeFile.h" #include "VolumeSurfaceOutlineSetViewController.h" #include "WuQMacroManager.h" #include "WuQTabWidgetWithSizeHint.h" #include "WuQtUtilities.h" using namespace caret; /** * Construct the toolbox. * * @param browserWindowIndex * Index of browser window that contains this toolbox. * @param title * Title for the toolbox. * @param toolBoxType * Type of toolbox * @param parentObjectName * Name of parent for macro objets * @param parent * The parent widget */ BrainBrowserWindowOrientedToolBox::BrainBrowserWindowOrientedToolBox(const int32_t browserWindowIndex, const QString& title, const ToolBoxType toolBoxType, const QString& parentObjectNamePrefix, QWidget* parent) : QDockWidget(parent) { m_browserWindowIndex = browserWindowIndex; toggleViewAction()->setText("Toolbox"); m_toolBoxTitle = title; setWindowTitle(m_toolBoxTitle); bool isFeaturesToolBox = false; bool isOverlayToolBox = false; QString typeSuffix; Qt::Orientation orientation = Qt::Horizontal; AString toolboxTypeName = ""; switch (toolBoxType) { case TOOL_BOX_FEATURES: orientation = Qt::Vertical; isFeaturesToolBox = true; toggleViewAction()->setText("Features Toolbox"); toolboxTypeName = "Features"; typeSuffix = "Features"; break; case TOOL_BOX_OVERLAYS_HORIZONTAL: orientation = Qt::Horizontal; isOverlayToolBox = true; toolboxTypeName = "OverlayHorizontal"; typeSuffix = "ToolBoxH"; break; case TOOL_BOX_OVERLAYS_VERTICAL: orientation = Qt::Vertical; isOverlayToolBox = true; toolboxTypeName = "OverlayVertical"; typeSuffix = "ToolBoxV"; break; } WuQMacroManager* macroManager = WuQMacroManager::instance(); QString objectNamePrefix = (parentObjectNamePrefix + ":" + typeSuffix); /* * Needed for saving and restoring window state in main window * CHANGING THIS WILL BREAK SCENES !!! */ CaretAssert(toolboxTypeName.length() > 0); setObjectName("BrainBrowserWindowOrientedToolBox_" + toolboxTypeName + "_" + AString::number(browserWindowIndex)); m_annotationTabWidget = NULL; m_annotationViewController = NULL; m_annotationTextSubstitutionViewController = NULL; m_borderSelectionViewController = NULL; m_chartOverlaySetViewController = NULL; m_chartToolBoxViewController = NULL; m_connectivityMatrixViewController = NULL; m_fiberOrientationViewController = NULL; m_fociSelectionViewController = NULL; m_imageSelectionViewController = NULL; m_labelSelectionViewController = NULL; m_overlaySetViewController = NULL; m_volumeSurfaceOutlineSetViewController = NULL; m_tabWidget = new WuQTabWidgetWithSizeHint(); #if QT_VERSION < 0x050600 /* * Versions of Qt prior to 5.7 do not have QMainWindow::resizeDocks(). * QDockWidget adjusts its size using the size hint from the child widget * and we have have a version of QTabWidget that overrides sizeHint. * Without this, the horizontal overlay toolbox uses most of the * window height (way too tall). */ switch (toolBoxType) { case TOOL_BOX_FEATURES: break; case TOOL_BOX_OVERLAYS_HORIZONTAL: m_tabWidget->setSizeHintHeight(100); break; case TOOL_BOX_OVERLAYS_VERTICAL: break; } #endif m_tabWidget->setObjectName(objectNamePrefix + ":Tab"); macroManager->addMacroSupportToObjectWithToolTip(m_tabWidget, "Toolbox tab", ""); m_annotationTabIndex = -1; m_borderTabIndex = -1; m_chartOverlayTabIndex = -1; m_chartTabIndex = -1; m_connectivityTabIndex = -1; m_fiberOrientationTabIndex = -1; m_fociTabIndex = -1; m_imageTabIndex = -1; m_labelTabIndex = -1; m_overlayTabIndex = -1; m_volumeSurfaceOutlineTabIndex = -1; if (isOverlayToolBox) { m_overlaySetViewController = new OverlaySetViewController(orientation, browserWindowIndex, objectNamePrefix, this); m_overlayTabIndex = addToTabWidget(m_overlaySetViewController, "Layers"); } if (isOverlayToolBox) { m_chartOverlaySetViewController = new ChartTwoOverlaySetViewController(orientation, browserWindowIndex, objectNamePrefix, this); m_chartOverlayTabIndex = addToTabWidget(m_chartOverlaySetViewController, "Chart Layers"); } if (isOverlayToolBox) { m_chartToolBoxViewController = new ChartToolBoxViewController(orientation, browserWindowIndex, objectNamePrefix, this); m_chartTabIndex = addToTabWidget(m_chartToolBoxViewController, "Charting"); } if (isOverlayToolBox) { m_connectivityMatrixViewController = new CiftiConnectivityMatrixViewController(objectNamePrefix, this); m_connectivityTabIndex = addToTabWidget(m_connectivityMatrixViewController, "Connectivity"); } if (isFeaturesToolBox) { m_annotationViewController = new AnnotationSelectionViewController(browserWindowIndex, objectNamePrefix, this); m_annotationTextSubstitutionViewController = new AnnotationTextSubstitutionViewController(browserWindowIndex, objectNamePrefix, this); m_annotationTabWidget = new QTabWidget(); m_annotationTabWidget->addTab(m_annotationViewController, "Annotations"); m_annotationTabWidget->addTab(m_annotationTextSubstitutionViewController, "Substitutions"); m_annotationTabWidget->setObjectName(objectNamePrefix + ":AnnotationTab"); macroManager->addMacroSupportToObjectWithToolTip(m_annotationTabWidget, "Features ToolBox Annotation Tab", ""); m_annotationTabIndex = addToTabWidget(m_annotationTabWidget, "Annot"); m_annotationTabWidget->setCurrentIndex(0); } if (isFeaturesToolBox) { m_borderSelectionViewController = new BorderSelectionViewController(browserWindowIndex, objectNamePrefix, this); m_borderTabIndex = addToTabWidget(m_borderSelectionViewController, "Borders"); } if (isFeaturesToolBox) { m_fiberOrientationViewController = new FiberOrientationSelectionViewController(browserWindowIndex, this); m_fiberOrientationTabIndex = addToTabWidget(m_fiberOrientationViewController, "Fibers"); } if (isFeaturesToolBox) { m_fociSelectionViewController = new FociSelectionViewController(browserWindowIndex, objectNamePrefix, this); m_fociTabIndex = addToTabWidget(m_fociSelectionViewController, "Foci"); } if (isFeaturesToolBox) { m_imageSelectionViewController = new ImageSelectionViewController(browserWindowIndex, objectNamePrefix, this); m_imageTabIndex = addToTabWidget(m_imageSelectionViewController, "Images"); } if (isFeaturesToolBox) { m_labelSelectionViewController = new LabelSelectionViewController(browserWindowIndex, objectNamePrefix, this); m_labelTabIndex = addToTabWidget(m_labelSelectionViewController, "Labels"); } if (isOverlayToolBox) { m_volumeSurfaceOutlineSetViewController = new VolumeSurfaceOutlineSetViewController(orientation, m_browserWindowIndex, objectNamePrefix, "toolbox"); m_volumeSurfaceOutlineTabIndex = addToTabWidget(m_volumeSurfaceOutlineSetViewController, "Vol/Surf Outline"); } setWidget(m_tabWidget); if (orientation == Qt::Horizontal) { setMinimumHeight(200); setMaximumHeight(800); } else { if (isOverlayToolBox) { setMinimumWidth(300); setMaximumWidth(800); } else { setMinimumWidth(200); setMaximumWidth(800); } } QObject::connect(this, SIGNAL(topLevelChanged(bool)), this, SLOT(floatingStatusChanged(bool))); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); } /** * Destructor. */ BrainBrowserWindowOrientedToolBox::~BrainBrowserWindowOrientedToolBox() { EventManager::get()->removeAllEventsFromListener(this); } /** * Place widget into a scroll area and then into the tab widget. * @param page * Widget that is added. * @param label * Name corresponding to widget's tab. */ int BrainBrowserWindowOrientedToolBox::addToTabWidget(QWidget* page, const QString& label) { QScrollArea* scrollArea = new QScrollArea(); scrollArea->setWidget(page); scrollArea->setWidgetResizable(true); scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); int indx = m_tabWidget->addTab(scrollArea, label); return indx; } /** * Called when floating status changes. * @param status * New floating status. */ void BrainBrowserWindowOrientedToolBox::floatingStatusChanged(bool /*status*/) { QString title = m_toolBoxTitle; setWindowTitle(title); } /** * Set the size hint width (non-positive uses default size hint for width) * * @param width * Width for size hint. */ void BrainBrowserWindowOrientedToolBox::setSizeHintWidth(const int width) { m_sizeHintWidth = width; if (m_sizeHintWidth > 0) { const int32_t childSize = std::max(m_sizeHintWidth - 50, 50); m_tabWidget->setSizeHintWidth(childSize); } } /** * Set the size hint height (non-positive uses default size hint for height) * * @param height * Height for size hint. */ void BrainBrowserWindowOrientedToolBox::setSizeHintHeight(const int height) { m_sizeHintHeight = height; if (m_sizeHintHeight > 0) { const int32_t childSize = std::max(m_sizeHintHeight - 50, 50); m_tabWidget->setSizeHintHeight(childSize); } } /** * @return Recommended size for this widget. */ QSize BrainBrowserWindowOrientedToolBox::sizeHint() const { QSize sh = QDockWidget::sizeHint(); return sh; } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* BrainBrowserWindowOrientedToolBox::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "BrainBrowserWindowOrientedToolBox", 1); AString tabName; const int tabIndex = m_tabWidget->currentIndex(); if ((tabIndex >= 0) && tabIndex < m_tabWidget->count()) { tabName = m_tabWidget->tabText(tabIndex); } sceneClass->addString("selectedTabName", tabName); if (m_chartToolBoxViewController != NULL) { sceneClass->addClass(m_chartToolBoxViewController->saveToScene(sceneAttributes, "m_chartToolBoxViewController")); } /* * Save current widget size */ QWidget* childWidget = m_tabWidget->currentWidget(); if (childWidget != NULL) { SceneWindowGeometry swg(childWidget, this); sceneClass->addClass(swg.saveToScene(sceneAttributes, "childWidget")); } /* * Save the toolbox */ SceneWindowGeometry swg(this, GuiManager::get()->getBrowserWindowByWindowIndex(this->m_browserWindowIndex)); sceneClass->addClass(swg.saveToScene(sceneAttributes, "geometry")); /** * Save the size when visible BUT NOT floating */ if (isFloating() == false) { sceneClass->addInteger("toolboxWidth", width()); sceneClass->addInteger("toolboxHeight", height()); } /* * Save controllers in the toolbox */ if (m_annotationTabWidget) { sceneClass->addInteger("annotationSubTabWidgetIndex", m_annotationTabWidget->currentIndex()); } if (m_annotationViewController != NULL) { sceneClass->addClass(m_annotationViewController->saveToScene(sceneAttributes, "m_annotationViewController")); } if (m_annotationTextSubstitutionViewController != NULL) { sceneClass->addClass(m_annotationTextSubstitutionViewController->saveToScene(sceneAttributes, "m_annotationTextSubstitutionViewController")); } if (m_borderSelectionViewController != NULL) { sceneClass->addClass(m_borderSelectionViewController->saveToScene(sceneAttributes, "m_borderSelectionViewController")); } if (m_fiberOrientationViewController != NULL) { sceneClass->addClass(m_fiberOrientationViewController->saveToScene(sceneAttributes, "m_fiberOrientationViewController")); } if (m_fociSelectionViewController != NULL) { sceneClass->addClass(m_fociSelectionViewController->saveToScene(sceneAttributes, "m_fociSelectionViewController")); } if (m_imageSelectionViewController != NULL) { sceneClass->addClass(m_imageSelectionViewController->saveToScene(sceneAttributes, "m_imageSelectionViewController")); } if (m_labelSelectionViewController != NULL) { sceneClass->addClass(m_labelSelectionViewController->saveToScene(sceneAttributes, "m_labelSelectionViewController")); } return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void BrainBrowserWindowOrientedToolBox::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } const AString tabName = sceneClass->getStringValue("selectedTabName", ""); for (int32_t i = 0; i < m_tabWidget->count(); i++) { if (m_tabWidget->tabText(i) == tabName) { m_tabWidget->setCurrentIndex(i); break; } } if (m_chartToolBoxViewController != NULL) { m_chartToolBoxViewController->restoreFromScene(sceneAttributes, sceneClass->getClass("m_chartToolBoxViewController")); } /* * Restore controllers in the toolbox */ if (m_annotationTabWidget != NULL) { const int32_t subTabIndex = sceneClass->getIntegerValue("annotationSubTabWidgetIndex", 0); if (subTabIndex >= 0) { m_annotationTabWidget->setCurrentIndex(subTabIndex); } } if (m_annotationViewController != NULL) { m_annotationViewController->restoreFromScene(sceneAttributes, sceneClass->getClass("m_annotationViewController")); } if (m_annotationTextSubstitutionViewController != NULL) { m_annotationTextSubstitutionViewController->restoreFromScene(sceneAttributes, sceneClass->getClass("m_annotationTextSubstitutionViewController")); } if (m_borderSelectionViewController != NULL) { m_borderSelectionViewController->restoreFromScene(sceneAttributes, sceneClass->getClass("m_borderSelectionViewController")); } if (m_fiberOrientationViewController != NULL) { m_fiberOrientationViewController->restoreFromScene(sceneAttributes, sceneClass->getClass("m_fiberOrientationViewController")); } if (m_fociSelectionViewController != NULL) { m_fociSelectionViewController->restoreFromScene(sceneAttributes, sceneClass->getClass("m_fociSelectionViewController")); } if (m_imageSelectionViewController != NULL) { m_imageSelectionViewController->restoreFromScene(sceneAttributes, sceneClass->getClass("m_imageSelectionViewController")); } if (m_labelSelectionViewController != NULL) { m_labelSelectionViewController->restoreFromScene(sceneAttributes, sceneClass->getClass("m_labelSelectionViewController")); } /* * Restore current widget size */ QWidget* childWidget = m_tabWidget->currentWidget(); QSize childMinSize; QSize childSize; if (childWidget != NULL) { childMinSize = childWidget->minimumSize(); SceneWindowGeometry swg(childWidget, this); swg.restoreFromScene(sceneAttributes, sceneClass->getClass("childWidget")); childSize = childWidget->size(); } if (isFloating() && isVisible()) { SceneWindowGeometry swg(this, GuiManager::get()->getBrowserWindowByWindowIndex(this->m_browserWindowIndex)); swg.restoreFromScene(sceneAttributes, sceneClass->getClass("geometry")); } else { const SceneClass* geometryClass = sceneClass->getClass("geometry"); if (geometryClass != NULL) { /* is restored only when floating and visible. */ geometryClass->setDescendantsRestored(true); } #if QT_VERSION < 0x050000 /* * Do this for Qt4 only. Qt5 restores size in BrainBrowserWindow. * * From http://stackoverflow.com/questions/2722939/c-resize-a-docked-qt-qdockwidget-programmatically * * Set the minimum and maximum sizes and restore them later. * Trying to restore them immediately does not work. So, as * explained in the link above, set the minimum and maximum * sizes to that the toolbox is the correct size and then use * a timer to restore the correct values for the minimum and * maximum sizes after a little delay. */ const int w = sceneClass->getIntegerValue("toolboxWidth", -1); const int h = sceneClass->getIntegerValue("toolboxHeight", -1); if ((w > 0) && (h > 0)) { m_minimumSizeAfterSceneRestored = minimumSize(); m_maximumSizeAfterSceneRestored = maximumSize(); setMaximumWidth(w); setMaximumHeight(h); setMinimumWidth(w); setMinimumHeight(h); QTimer::singleShot(1000, // 1000 ms => 1 second this, SLOT(restoreMinimumAndMaximumSizesAfterSceneRestored())); } #endif } } /** * This slot is called when restoring a scene */ void BrainBrowserWindowOrientedToolBox::restoreMinimumAndMaximumSizesAfterSceneRestored() { setMinimumSize(m_minimumSizeAfterSceneRestored); setMaximumSize(m_maximumSizeAfterSceneRestored); } /** * Receive events from the event manager. * * @param event * Event sent by event manager. */ void BrainBrowserWindowOrientedToolBox::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiEvent = dynamic_cast(event); CaretAssert(uiEvent); uiEvent->setEventProcessed(); Brain* brain = GuiManager::get()->getBrain(); /* * Determine types of data this is loaded */ bool haveAnnotation = ( ! brain->getSceneAnnotationFile()->isEmpty()); bool haveAnnSub = false; bool haveBorders = false; bool haveConnFiles = false; bool haveFibers = false; bool haveFoci = false; bool haveImages = false; bool haveLabels = false; bool haveSurfaces = false; bool haveVolumes = false; std::vector allDataFiles; brain->getAllDataFiles(allDataFiles); for (std::vector::iterator iter = allDataFiles.begin(); iter != allDataFiles.end(); iter++) { const CaretDataFile* caretDataFile = *iter; const DataFileTypeEnum::Enum dataFileType = caretDataFile->getDataFileType(); switch (dataFileType) { case DataFileTypeEnum::ANNOTATION: haveAnnotation = true; break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: haveAnnSub = true; break; case DataFileTypeEnum::BORDER: haveBorders = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE: haveConnFiles = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: haveConnFiles = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: haveLabels = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: haveConnFiles = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: haveFibers = true; break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: haveConnFiles = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: haveConnFiles = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: haveConnFiles = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: haveLabels = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: haveFoci = true; break; case DataFileTypeEnum::IMAGE: haveImages = true; break; case DataFileTypeEnum::LABEL: haveLabels = true; break; case DataFileTypeEnum::METRIC: break; case DataFileTypeEnum::METRIC_DYNAMIC: haveConnFiles = true; break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: haveSurfaces = true; break; case DataFileTypeEnum::UNKNOWN: break; case DataFileTypeEnum::VOLUME: { haveVolumes = true; const VolumeFile* vf = dynamic_cast(caretDataFile); CaretAssert(vf); if (vf->isMappedWithLabelTable()) { haveLabels = true; } } break; case DataFileTypeEnum::VOLUME_DYNAMIC: haveConnFiles = true; // haveVolumes = true; // const VolumeDynamicConnectivityFile* volDynConnFile = vf->getVolumeDynamicConnectivityFile(); // if (volDynConnFile != NULL) { // haveConnFiles = true; // } break; } } /* * Enable surface volume outline only if have both surfaces and volumes * loaded and model being viewed is allows drawing of volume surface * outline. */ int defaultTabIndex = -1; bool enableLayers = true; bool enableVolumeSurfaceOutline = false; bool enableChartOne = false; bool enableChartTwo = false; EventBrowserWindowDrawingContent browserContentEvent(m_browserWindowIndex); EventManager::get()->sendEvent(browserContentEvent.getPointer()); BrowserTabContent* windowContent = browserContentEvent.getSelectedBrowserTabContent(); if (windowContent != NULL) { switch (windowContent->getSelectedModelType()) { case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: defaultTabIndex = m_overlayTabIndex; break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: defaultTabIndex = m_overlayTabIndex; break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: defaultTabIndex = m_overlayTabIndex; enableVolumeSurfaceOutline = (haveSurfaces & haveVolumes); break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: defaultTabIndex = m_overlayTabIndex; enableVolumeSurfaceOutline = (haveSurfaces & haveVolumes); break; case ModelTypeEnum::MODEL_TYPE_CHART: defaultTabIndex = m_chartTabIndex; enableChartOne = true; enableLayers = false; enableVolumeSurfaceOutline = false; haveBorders = false; haveFibers = false; haveFoci = false; haveLabels = false; break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: defaultTabIndex = m_chartOverlayTabIndex; enableChartTwo = true; enableLayers = false; enableVolumeSurfaceOutline = false; haveBorders = false; haveFibers = false; haveFoci = false; haveLabels = false; break; } } EventGetOrSetUserInputModeProcessor inputModeEvent(m_browserWindowIndex); EventManager::get()->sendEvent(inputModeEvent.getPointer()); const UserInputModeEnum::Enum inputMode = inputModeEvent.getUserInputMode(); switch (inputMode) { case UserInputModeEnum::ANNOTATIONS: break; case UserInputModeEnum::BORDERS: /* * Enable borders tab if the input mode is 'borders' so that user * can edit border point size while drawing a border before any * borders exist. */ haveBorders = true; break; case UserInputModeEnum::FOCI: break; case UserInputModeEnum::IMAGE: break; case UserInputModeEnum::INVALID: break; case UserInputModeEnum::VIEW: break; case UserInputModeEnum::VOLUME_EDIT: break; } /* * Get the selected tab BEFORE enabling/disabling tabs. * Otherwise, the enabling/disabling of tabs may cause the selection * to change */ const int32_t tabIndex = m_tabWidget->currentIndex(); /* * Enable/disable Tabs based upon data that is loaded * NOTE: Order is important so that overlay tab is * automatically selected. */ if (m_chartTabIndex >= 0) m_tabWidget->setTabEnabled(m_chartTabIndex, enableChartOne); if (m_chartOverlayTabIndex >= 0) m_tabWidget->setTabEnabled(m_chartOverlayTabIndex, enableChartTwo); if (m_connectivityTabIndex >= 0) m_tabWidget->setTabEnabled(m_connectivityTabIndex, haveConnFiles); if (m_volumeSurfaceOutlineTabIndex >= 0) m_tabWidget->setTabEnabled(m_volumeSurfaceOutlineTabIndex, enableVolumeSurfaceOutline); if (m_annotationTabIndex >= 0) m_tabWidget->setTabEnabled(m_annotationTabIndex, (haveAnnotation || haveAnnSub)); if (m_borderTabIndex >= 0) m_tabWidget->setTabEnabled(m_borderTabIndex, haveBorders); if (m_fiberOrientationTabIndex >= 0) m_tabWidget->setTabEnabled(m_fiberOrientationTabIndex, haveFibers); if (m_fociTabIndex >= 0) m_tabWidget->setTabEnabled(m_fociTabIndex, haveFoci); if (m_imageTabIndex >= 0) m_tabWidget->setTabEnabled(m_imageTabIndex, haveImages); if (m_labelTabIndex >= 0) m_tabWidget->setTabEnabled(m_labelTabIndex, haveLabels); if (m_overlayTabIndex >= 0) m_tabWidget->setTabEnabled(m_overlayTabIndex, enableLayers); if (m_annotationTabWidget != NULL) { const int32_t numTabs = m_annotationTabWidget->count(); for (int32_t iTab = 0; iTab < numTabs; iTab++) { if (m_annotationTabWidget->widget(iTab) == m_annotationViewController) { m_annotationTabWidget->setTabEnabled(iTab, haveAnnotation); } else if (m_annotationTabWidget->widget(iTab) == m_annotationTextSubstitutionViewController) { m_annotationTabWidget->setTabEnabled(iTab, haveAnnSub); } else { CaretAssertMessage(0, "Has new annotation sub tab been added?"); } } } /* * Switch selected tab if it is not valid */ bool tabIndexValid = false; if ((tabIndex >= 0) && (tabIndex < m_tabWidget->count())) { if (m_tabWidget->isTabEnabled(tabIndex)) { tabIndexValid = true; } } if ( ! tabIndexValid) { if (m_tabWidget->isTabEnabled(defaultTabIndex)) { m_tabWidget->setCurrentIndex(defaultTabIndex); } else { for (int i = 0; i < m_tabWidget->count(); ++i) { if (m_tabWidget->isTabEnabled(i)) { m_tabWidget->setCurrentIndex(i); break; } } } } } else { } } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowOrientedToolBox.h000066400000000000000000000123131360521144700264140ustar00rootroot00000000000000#ifndef __BRAIN_BROWSER_WINDOW_ORIENTED_TOOLBOX_H__ #define __BRAIN_BROWSER_WINDOW_ORIENTED_TOOLBOX_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "EventListenerInterface.h" #include "SceneableInterface.h" class QTabWidget; namespace caret { class AnnotationSelectionViewController; class AnnotationTextSubstitutionViewController; class BorderSelectionViewController; class ChartTwoOverlaySetViewController; class ChartToolBoxViewController; class CiftiConnectivityMatrixViewController; class FiberOrientationSelectionViewController; class FociSelectionViewController; class ImageSelectionViewController; class LabelSelectionViewController; class OverlaySetViewController; class VolumeSurfaceOutlineSetViewController; class WuQTabWidgetWithSizeHint; class BrainBrowserWindowOrientedToolBox : public QDockWidget, public EventListenerInterface, public SceneableInterface { Q_OBJECT public: enum ToolBoxType { TOOL_BOX_FEATURES, TOOL_BOX_OVERLAYS_HORIZONTAL, TOOL_BOX_OVERLAYS_VERTICAL, }; BrainBrowserWindowOrientedToolBox(const int32_t browserWindowIndex, const QString& title, const ToolBoxType toolBoxType, const QString& parentObjectName, QWidget* parent = 0); ~BrainBrowserWindowOrientedToolBox(); void receiveEvent(Event* event); void setSizeHintWidth(const int width); void setSizeHintHeight(const int height); virtual QSize sizeHint() const override; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private slots: void floatingStatusChanged(bool); void restoreMinimumAndMaximumSizesAfterSceneRestored(); private: BrainBrowserWindowOrientedToolBox(const BrainBrowserWindowOrientedToolBox&); BrainBrowserWindowOrientedToolBox& operator=(const BrainBrowserWindowOrientedToolBox&); int addToTabWidget(QWidget* page, const QString& label); OverlaySetViewController* m_overlaySetViewController; AnnotationSelectionViewController* m_annotationViewController; AnnotationTextSubstitutionViewController* m_annotationTextSubstitutionViewController; BorderSelectionViewController* m_borderSelectionViewController; ChartTwoOverlaySetViewController* m_chartOverlaySetViewController; CiftiConnectivityMatrixViewController* m_connectivityMatrixViewController; ChartToolBoxViewController* m_chartToolBoxViewController; FiberOrientationSelectionViewController* m_fiberOrientationViewController; FociSelectionViewController* m_fociSelectionViewController; ImageSelectionViewController* m_imageSelectionViewController; LabelSelectionViewController* m_labelSelectionViewController; VolumeSurfaceOutlineSetViewController* m_volumeSurfaceOutlineSetViewController; WuQTabWidgetWithSizeHint* m_tabWidget; QTabWidget* m_annotationTabWidget; QString m_toolBoxTitle; int32_t m_browserWindowIndex; int32_t m_chartOverlayTabIndex; int32_t m_overlayTabIndex; int32_t m_annotationTabIndex; int32_t m_borderTabIndex; int32_t m_connectivityTabIndex; int32_t m_chartTabIndex; int32_t m_fiberOrientationTabIndex; int32_t m_fociTabIndex; int32_t m_imageTabIndex; int32_t m_labelTabIndex; int32_t m_volumeSurfaceOutlineTabIndex; int m_sizeHintWidth = -1; int m_sizeHintHeight = -1; QSize m_minimumSizeAfterSceneRestored; QSize m_maximumSizeAfterSceneRestored; }; } #endif // __BRAIN_BROWSER_WINDOW_ORIENTED_TOOLBOX_H__ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBar.cxx000066400000000000000000005745211360521144700252670ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #if QT_VERSION >= 0x050000 #else // QT_VERSION #include #endif // QT_VERSION #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "AnnotationManager.h" #include "Brain.h" #include "BrainBrowserWindow.h" #include "BrainBrowserWindowToolBar.h" #include "BrainBrowserWindowToolBarChartAttributes.h" #include "BrainBrowserWindowToolBarChartAxes.h" #include "BrainBrowserWindowToolBarChartTwoAttributes.h" #include "BrainBrowserWindowToolBarChartTwoAxes.h" #include "BrainBrowserWindowToolBarChartTwoOrientation.h" #include "BrainBrowserWindowToolBarChartTwoTitle.h" #include "BrainBrowserWindowToolBarChartTwoType.h" #include "BrainBrowserWindowToolBarChartType.h" #include "BrainBrowserWindowToolBarClipping.h" #include "BrainBrowserWindowToolBarSlicePlane.h" #include "BrainBrowserWindowToolBarSliceSelection.h" #include "BrainBrowserWindowToolBarSurfaceMontage.h" #include "BrainBrowserWindowToolBarTab.h" #include "BrainBrowserWindowToolBarTabPopUpMenu.h" #include "BrainBrowserWindowToolBarVolumeMontage.h" #include "BrainOpenGLWidget.h" #include "BrainStructure.h" #include "BrowserTabContent.h" #include "BrowserWindowContent.h" #include "CaretAssert.h" #include "CaretFunctionName.h" #include "CaretLogger.h" #include "CaretPreferences.h" #include "CursorDisplayScoped.h" #include "DeveloperFlagsEnum.h" #include "DisplayPropertiesBorders.h" #include "EventBrowserTabNewClone.h" #include "EventBrowserTabDelete.h" #include "EventBrowserTabGet.h" #include "EventBrowserTabGetAll.h" #include "EventBrowserTabGetAllViewed.h" #include "EventBrowserTabNew.h" #include "EventBrowserWindowDrawingContent.h" #include "EventBrowserWindowCreateTabs.h" #include "EventBrowserWindowNew.h" #include "EventBrowserWindowTileTabOperation.h" #include "EventGetOrSetUserInputModeProcessor.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventUserInterfaceUpdate.h" #include "EventManager.h" #include "EventModelGetAll.h" #include "EventSceneActive.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUpdateYokedWindows.h" #include "GuiManager.h" #include "LockAspectWarningDialog.h" #include "MacDuplicateMenuBar.h" #include "Model.h" #include "ModelChart.h" #include "ModelChartTwo.h" #include "ModelSurface.h" #include "ModelSurfaceMontage.h" #include "ModelSurfaceSelector.h" #include "ModelTransform.h" #include "ModelVolume.h" #include "ModelWholeBrain.h" #include "OverlaySet.h" #include "Scene.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneIntegerArray.h" #include "ScenePrimitiveArray.h" #include "SessionManager.h" #include "Surface.h" #include "SurfaceSelectionModel.h" #include "SurfaceSelectionViewController.h" #include "StructureSurfaceSelectionControl.h" #include "TileTabsConfiguration.h" #include "UserInputModeAbstract.h" #include "VolumeFile.h" #include "VolumeSliceViewPlaneEnum.h" #include "VolumeSurfaceOutlineSetModel.h" #include "WuQDataEntryDialog.h" #include "WuQFactory.h" #include "WuQMacroManager.h" #include "WuQMessageBox.h" #include "WuQTabBar.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" using namespace caret; /** * Constructor. * * @param browserWindowIndex * Index of the parent browser window. * @param initialBrowserTabContent * Content of default tab (may be NULL in which cast * new content is created). * @param overlayToolBoxAction * Action to show overlay tool box. * @param layersToolBoxAction * Action to show layers tool box. * @param toolBarLockWindowAndAllTabAspectRatioButton * Button to lock window's aspect ratio and aspect ratio of all tabs. * @param objectNamePrefix * Prefix for object name * @param parent * Parent for this toolbar. */ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindowIndex, BrowserTabContent* initialBrowserTabContent, QAction* overlayToolBoxAction, QAction* layersToolBoxAction, QToolButton* toolBarLockWindowAndAllTabAspectRatioButton, const QString& objectNamePrefix, BrainBrowserWindow* parentBrainBrowserWindow) : QToolBar(parentBrainBrowserWindow) { this->browserWindowIndex = browserWindowIndex; m_tabIndexForTileTabsHighlighting = -1; this->isContructorFinished = false; this->isDestructionInProgress = false; this->viewOrientationLeftIcon = NULL; this->viewOrientationRightIcon = NULL; this->viewOrientationAnteriorIcon = NULL; this->viewOrientationPosteriorIcon = NULL; this->viewOrientationDorsalIcon = NULL; this->viewOrientationVentralIcon = NULL; this->viewOrientationLeftLateralIcon = NULL; this->viewOrientationLeftMedialIcon = NULL; this->viewOrientationRightLateralIcon = NULL; this->viewOrientationRightMedialIcon = NULL; /* * Needed for saving and restoring window state in main window */ m_objectNamePrefix = (objectNamePrefix + ":ToolBar"); setObjectName(m_objectNamePrefix); /* * Create tab bar that displays models. */ this->tabBar = new WuQTabBar(); if (WuQtUtilities::isSmallDisplay()) { this->tabBar->setStyleSheet("QTabBar::tab:selected {" " font: bold;" "} " "QTabBar::tab {" " font: italic" "}"); } else { this->tabBar->setStyleSheet("QTabBar::tab:selected {" " font: bold 14px;" "} " "QTabBar::tab {" " font: italic" "}"); } this->tabBar->setShape(QTabBar::RoundedNorth); this->tabBar->setMovable(true); #ifdef Q_OS_MACX /* * Adding a parent to the style will result in it * being destroyed when this instance is destroyed. * The style must remain valid until the destruction * of this instance. It cannot be declared statically. */ #if QT_VERSION >= 0x050000 /* * "Cleanlooks Style" removed in Qt5. Fusion style * seems to have same effect on toolbar so that * tabs do not get shrunk too small and so the * scroll tabs arrows are available. */ QStyle* fusionStyle = QStyleFactory::create("Fusion"); if (fusionStyle != NULL) { fusionStyle->setParent(this); this->tabBar->setStyle(fusionStyle); } #else // QT_VERSION QCleanlooksStyle* cleanLooksStyle = new QCleanlooksStyle(); cleanLooksStyle->setParent(this); this->tabBar->setStyle(cleanLooksStyle); #endif // QT_VERSION #endif // Q_OS_MACX QObject::connect(this->tabBar, SIGNAL(currentChanged(int)), this, SLOT(selectedTabChanged(int))); QObject::connect(this->tabBar, SIGNAL(tabCloseRequested(int)), this, SLOT(tabCloseSelected(int))); QObject::connect(this->tabBar, SIGNAL(tabMoved(int,int)), this, SLOT(tabMoved(int,int))); this->tabBar->setObjectName(m_objectNamePrefix + ":Tab"); WuQMacroManager::instance()->addMacroSupportToObjectWithToolTip(qobject_cast(this->tabBar), "ToolBar Tab", "Select Tab"); /* * Add context menu * From the position, use QTabBar::tabAt(const QPoint& position) to get the * tab that the user has clicked and if over a tab, pop-up a menu * for the tab with Create New Tab and Place Right, Duplicate and Place on Right */ QObject::connect(this->tabBar, &QTabBar::customContextMenuRequested, this, &BrainBrowserWindowToolBar::showTabMenu); this->tabBar->setContextMenuPolicy(Qt::CustomContextMenu); /* * Custom view action */ const QString customToolTip = ("Pressing the \"Custom\" button displays a dialog for creating and editing orientations.\n" "Note that custom orientations are stored in your Workbench's preferences and thus\n" "will be availble in any concurrent or future instances of Workbench."); this->customViewAction = WuQtUtilities::createAction("Custom", customToolTip, this, this, SLOT(customViewActionTriggered())); this->customViewAction->setObjectName(m_objectNamePrefix + ":CustomView"); WuQMacroManager::instance()->addMacroSupportToObject(this->customViewAction, "Display custom view dialog"); /* * Actions at right side of toolbar */ QToolButton* informationDialogToolButton = new QToolButton(); informationDialogToolButton->setDefaultAction(GuiManager::get()->getInformationDisplayDialogEnabledAction()); QToolButton* identifyDialogToolButton = new QToolButton(); identifyDialogToolButton->setDefaultAction(GuiManager::get()->getIdentifyBrainordinateDialogDisplayAction()); QToolButton* helpDialogToolButton = new QToolButton(); helpDialogToolButton->setDefaultAction(GuiManager::get()->getHelpViewerDialogDisplayAction()); /* * Scene button */ QToolButton* sceneDialogToolButton = new QToolButton(); sceneDialogToolButton->setText(""); sceneDialogToolButton->setIcon(GuiManager::get()->getSceneDialogDisplayAction()->icon()); sceneDialogToolButton->setDefaultAction(GuiManager::get()->getSceneDialogDisplayAction()); QObject::connect(sceneDialogToolButton, &QToolButton::clicked, this, &BrainBrowserWindowToolBar::sceneToolButtonClicked); /* * Movie button */ QIcon movieIcon; QString movieButtonText; if ( ! WuQtUtilities::loadIcon(":/ToolBar/movie.png", movieIcon)) { movieButtonText = "Movie"; } const QString movieButtonToolTip("Show movie recording window"); m_movieToolButton = new QToolButton(); m_movieToolButton->setText(movieButtonText); m_movieToolButton->setIcon(movieIcon); m_movieToolButton->setToolTip(movieButtonToolTip); QObject::connect(m_movieToolButton, &QToolButton::clicked, parentBrainBrowserWindow, &BrainBrowserWindow::processMovieRecording); /* * Macros button */ QIcon macrosIcon; QAction* macrosAction = new QAction(); if (WuQtUtilities::loadIcon(":/ToolBar/macro.png", macrosIcon)) { macrosAction->setIcon(macrosIcon); } else { macrosAction->setText("M"); } macrosAction->setToolTip("Show macros window"); QObject::connect(macrosAction, &QAction::triggered, this, &BrainBrowserWindowToolBar::showMacroDialog); QToolButton* macrosToolButton = new QToolButton(); macrosToolButton->setDefaultAction(macrosAction); macrosAction->setParent(macrosToolButton); /* * Toolbar action and tool button at right of the tab bar */ QIcon toolBarIcon; const bool toolBarIconValid = WuQtUtilities::loadIcon(":/ToolBar/toolbar.png", toolBarIcon); this->toolBarToolButtonAction = WuQtUtilities::createAction("Toolbar", "Show or hide the toolbar", this, this, SLOT(showHideToolBar(bool))); if (toolBarIconValid) { this->toolBarToolButtonAction->setIcon(toolBarIcon); this->toolBarToolButtonAction->setIconVisibleInMenu(false); } this->toolBarToolButtonAction->setIconVisibleInMenu(false); this->toolBarToolButtonAction->blockSignals(true); this->toolBarToolButtonAction->setCheckable(true); this->toolBarToolButtonAction->setChecked(true); this->showHideToolBar(this->toolBarToolButtonAction->isChecked()); this->toolBarToolButtonAction->blockSignals(false); QToolButton* toolBarToolButton = new QToolButton(); toolBarToolButton->setDefaultAction(this->toolBarToolButtonAction); toolBarToolButtonAction->setObjectName(m_objectNamePrefix + ":ShowToolBar"); WuQMacroManager::instance()->addMacroSupportToObject(toolBarToolButtonAction, "Show toolbar"); /* * Toolbox control at right of the tab bar */ QToolButton* overlayToolBoxToolButton = new QToolButton(); overlayToolBoxToolButton->setDefaultAction(overlayToolBoxAction); QToolButton* layersToolBoxToolButton = new QToolButton(); layersToolBoxToolButton->setDefaultAction(layersToolBoxAction); QToolButton* dataToolTipsToolButton = new QToolButton(); dataToolTipsToolButton->setDefaultAction(GuiManager::get()->getDataToolTipsAction(dataToolTipsToolButton)); /* * Make all tool buttons the same height */ WuQtUtilities::matchWidgetHeights(macrosToolButton, m_movieToolButton, helpDialogToolButton, informationDialogToolButton, identifyDialogToolButton, sceneDialogToolButton, toolBarToolButton, overlayToolBoxToolButton, layersToolBoxToolButton, dataToolTipsToolButton); WuQtUtilities::setToolButtonStyleForQt5Mac(macrosToolButton); WuQtUtilities::setToolButtonStyleForQt5Mac(m_movieToolButton); WuQtUtilities::setToolButtonStyleForQt5Mac(helpDialogToolButton); WuQtUtilities::setToolButtonStyleForQt5Mac(informationDialogToolButton); WuQtUtilities::setToolButtonStyleForQt5Mac(identifyDialogToolButton); WuQtUtilities::setToolButtonStyleForQt5Mac(sceneDialogToolButton); WuQtUtilities::setToolButtonStyleForQt5Mac(toolBarToolButton); WuQtUtilities::setToolButtonStyleForQt5Mac(overlayToolBoxToolButton); WuQtUtilities::setToolButtonStyleForQt5Mac(layersToolBoxToolButton); WuQtUtilities::setToolButtonStyleForQt5Mac(dataToolTipsToolButton); /* * Tab bar and controls at far right side of toolbar */ this->tabBarWidget = new QWidget(); QHBoxLayout* tabBarLayout = new QHBoxLayout(this->tabBarWidget); WuQtUtilities::setLayoutSpacingAndMargins(tabBarLayout, 2, 1); tabBarLayout->addWidget(this->tabBar, 100); tabBarLayout->addWidget(dataToolTipsToolButton); tabBarLayout->addWidget(helpDialogToolButton); tabBarLayout->addWidget(informationDialogToolButton); tabBarLayout->addWidget(identifyDialogToolButton); tabBarLayout->addWidget(m_movieToolButton); tabBarLayout->addWidget(macrosToolButton); tabBarLayout->addWidget(sceneDialogToolButton); tabBarLayout->addWidget(toolBarToolButton); tabBarLayout->addWidget(overlayToolBoxToolButton); tabBarLayout->addWidget(layersToolBoxToolButton); /* * Create the toolbar's widgets. */ this->viewWidget = this->createViewWidget(); this->orientationWidget = this->createOrientationWidget(); this->chartAxesWidget = createChartAxesWidget(); this->chartAttributesWidget = createChartAttributesWidget(); this->chartTwoOrientationWidget = createChartTwoOrientationWidget(); this->chartTwoAttributesWidget = createChartTwoAttributesWidget(); this->chartTwoAxesWidget = createChartTwoAxesWidget(); this->chartTwoTitleWidget = createChartTwoTitleWidget(); this->chartTypeWidget = createChartTypeWidget(); this->chartTypeTwoWidget = createChartTypeTwoWidget(); this->wholeBrainSurfaceOptionsWidget = this->createWholeBrainSurfaceOptionsWidget(); this->volumeIndicesWidget = this->createVolumeIndicesWidget(); this->modeWidget = this->createModeWidget(); this->windowWidget = this->createTabOptionsWidget(toolBarLockWindowAndAllTabAspectRatioButton); this->singleSurfaceSelectionWidget = this->createSingleSurfaceOptionsWidget(); this->surfaceMontageSelectionWidget = this->createSurfaceMontageOptionsWidget(); m_clippingOptionsWidget = createClippingOptionsWidget(); this->volumeMontageWidget = this->createVolumeMontageWidget(); this->volumePlaneWidget = this->createVolumePlaneWidget(); /* * Layout the toolbar's widgets. */ m_toolbarWidget = new QWidget(); this->toolbarWidgetLayout = new QHBoxLayout(m_toolbarWidget); WuQtUtilities::setLayoutSpacingAndMargins(this->toolbarWidgetLayout, 2, 1); this->toolbarWidgetLayout->addWidget(this->viewWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->orientationWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->wholeBrainSurfaceOptionsWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->singleSurfaceSelectionWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->surfaceMontageSelectionWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->volumePlaneWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->volumeMontageWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->volumeIndicesWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->chartTypeWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->chartTypeTwoWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->chartAxesWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->chartTwoOrientationWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->chartTwoAttributesWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->chartTwoAxesWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->chartTwoTitleWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->chartAttributesWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->modeWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(m_clippingOptionsWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addWidget(this->windowWidget, 0, Qt::AlignLeft); this->toolbarWidgetLayout->addStretch(); /* * Widget below toolbar for user input mode mouse controls */ this->userInputControlsWidgetLayout = new QHBoxLayout(); this->userInputControlsWidgetLayout->addSpacing(5); WuQtUtilities::setLayoutSpacingAndMargins(this->userInputControlsWidgetLayout, 0, 0); this->userInputControlsWidget = new QWidget(); QVBoxLayout* userInputLayout = new QVBoxLayout(this->userInputControlsWidget); WuQtUtilities::setLayoutSpacingAndMargins(userInputLayout, 2, 0); userInputLayout->addWidget(WuQtUtilities::createHorizontalLineWidget()); userInputLayout->addLayout(this->userInputControlsWidgetLayout); userInputControlsWidgetActiveInputWidget = NULL; /* * Arrange the tabbar and the toolbar vertically. */ QWidget* w = new QWidget(); m_toolBarMainLayout = new QVBoxLayout(w); WuQtUtilities::setLayoutSpacingAndMargins(m_toolBarMainLayout, 1, 0); m_toolBarMainLayout->addWidget(this->tabBarWidget); m_toolBarMainLayout->addWidget(m_toolbarWidget); m_toolBarMainLayout->addWidget(this->userInputControlsWidget); this->addWidget(w); if (initialBrowserTabContent != NULL) { insertTabContentPrivate(InsertTabMode::APPEND, initialBrowserTabContent, -1); } else { AString errorMessage; BrowserTabContent* tabContent = this->createNewTab(errorMessage); if (tabContent != NULL) { insertTabContentPrivate(InsertTabMode::APPEND, tabContent, -1); } } this->updateToolBar(); this->isContructorFinished = true; m_tileTabsHighlightingTimerEnabledFlag = true; EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL_VIEWED); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_CREATE_TABS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); QObject::connect(this->tabBar, &WuQTabBar::mousePressedSignal, this, &BrainBrowserWindowToolBar::tabBarMousePressedSlot); QObject::connect(this->tabBar, &WuQTabBar::mouseReleasedSignal, this, &BrainBrowserWindowToolBar::tabBarMouseReleasedSlot); } /** * Destructor. */ BrainBrowserWindowToolBar::~BrainBrowserWindowToolBar() { this->isDestructionInProgress = true; if (this->viewOrientationLeftIcon != NULL) { delete this->viewOrientationLeftIcon; this->viewOrientationLeftIcon = NULL; } if (this->viewOrientationRightIcon != NULL) { delete this->viewOrientationRightIcon; this->viewOrientationRightIcon = NULL; } if (this->viewOrientationAnteriorIcon != NULL) { delete this->viewOrientationAnteriorIcon; this->viewOrientationAnteriorIcon = NULL; } if (this->viewOrientationPosteriorIcon != NULL) { delete this->viewOrientationPosteriorIcon; this->viewOrientationPosteriorIcon = NULL; } if (this->viewOrientationDorsalIcon != NULL) { delete this->viewOrientationDorsalIcon; this->viewOrientationDorsalIcon = NULL; } if (this->viewOrientationVentralIcon != NULL) { delete this->viewOrientationVentralIcon; this->viewOrientationVentralIcon = NULL; } if (this->viewOrientationLeftLateralIcon != NULL) { delete this->viewOrientationLeftLateralIcon; this->viewOrientationLeftLateralIcon = NULL; } if (this->viewOrientationLeftMedialIcon != NULL) { delete this->viewOrientationLeftMedialIcon; this->viewOrientationLeftMedialIcon = NULL; } if (this->viewOrientationRightLateralIcon != NULL) { delete this->viewOrientationRightLateralIcon; this->viewOrientationRightLateralIcon = NULL; } if (this->viewOrientationRightMedialIcon != NULL) { delete this->viewOrientationRightMedialIcon; this->viewOrientationRightMedialIcon = NULL; } EventManager::get()->removeAllEventsFromListener(this); this->viewWidgetGroup->clear(); this->orientationWidgetGroup->clear(); this->wholeBrainSurfaceOptionsWidgetGroup->clear(); this->modeWidgetGroup->clear(); this->singleSurfaceSelectionWidgetGroup->clear(); for (int i = (this->tabBar->count() - 1); i >= 0; i--) { this->tabClosed(i); } this->isDestructionInProgress = false; } /** * Insert a duplicate of the application's menu at the top of the toolbar. * This is only enabled on MacOSX. * * @param mainWindow * Main window whose menus are copied. */ void BrainBrowserWindowToolBar::insertDuplicateMenuBar(QMainWindow* mainWindow) { #ifndef CARET_OS_MACOSX return; #endif MacDuplicateMenuBar* menuBar = new MacDuplicateMenuBar(mainWindow, this); CaretAssert(menuBar); /* * Insert at top of tool bar */ m_toolBarMainLayout->insertWidget(0, menuBar); } /** * Create a new tab. NOTE: This method only creates * a new tab, it DOES NOT add the tab to the toolbar. * @param errorMessage * If fails to create new tab, it will contain a message * describing the error. * @return * Pointer to content of new tab or NULL if unable to * create the new tab. */ BrowserTabContent* BrainBrowserWindowToolBar::createNewTab(AString& errorMessage) { errorMessage = ""; EventBrowserTabNew newTabEvent; EventManager::get()->sendEvent(newTabEvent.getPointer()); if (newTabEvent.isError()) { errorMessage = newTabEvent.getErrorMessage(); return NULL; } BrowserTabContent* tabContent = newTabEvent.getBrowserTab(); Brain* brain = GuiManager::get()->getBrain(); tabContent->getVolumeSurfaceOutlineSet()->selectSurfacesAfterSpecFileLoaded(brain, false); return tabContent; } /** * Add a new tab and clone the content of the given tab. * @param browserTabContentToBeCloned * Tab Content that is to be cloned into the new tab. */ void BrainBrowserWindowToolBar::addNewDuplicatedTab(BrowserTabContent* browserTabContentToBeCloned) { insertAndCloneTabContentAtTabBarIndex(browserTabContentToBeCloned, -1); } /** * Clone and insert the cloned tab at the given index in the tab bar. * * @param browserTabContentToBeCloned * Tab Content that is to be cloned into the new tab. * @param tabBarIndex * Index in the tab bar. If invalid, tab is appended to the end of the toolbar. */ void BrainBrowserWindowToolBar::insertAndCloneTabContentAtTabBarIndex(const BrowserTabContent* browserTabContentToBeCloned, const int32_t tabBarIndex) { if ( ! allowAddingNewTab()) { return; } /* * Wait cursor */ CursorDisplayScoped cursor; cursor.showWaitCursor(); EventBrowserTabNewClone cloneTabEvent(browserTabContentToBeCloned->getTabNumber()); EventManager::get()->sendEvent(cloneTabEvent.getPointer()); if (cloneTabEvent.isError()) { cursor.restoreCursor(); QMessageBox::critical(this, "", cloneTabEvent.getErrorMessage()); return; } BrowserTabContent* tabContent = cloneTabEvent.getNewBrowserTab(); CaretAssert(tabContent); if (tabBarIndex >= 0){ insertTabContentPrivate(InsertTabMode::AT_TAB_BAR_INDEX, tabContent, tabBarIndex); } else { insertTabContentPrivate(InsertTabMode::APPEND, tabContent, -1); } this->updateToolBar(); EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(this->browserWindowIndex).getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(this->browserWindowIndex).getPointer()); } /** * Add a new tab containing the given content. * @param tabContent * Content for new tab. */ void BrainBrowserWindowToolBar::addNewTabWithContent(BrowserTabContent* tabContent) { insertTabContentPrivate(InsertTabMode::APPEND, tabContent, -1); } /** * Replace the current browser tabs with the given browser tabs. Tabs will be added * or removed as needed. * * @param browserTabs * Browser tabs for this window. */ void BrainBrowserWindowToolBar::replaceBrowserTabs(const std::vector& browserTabs) { const int32_t numTabs = static_cast(browserTabs.size()); if (numTabs <= 0) { return; } QSignalBlocker blocker(this->tabBar); int32_t selectedTabIndex = this->tabBar->currentIndex(); /* * Remove BrowserTabContent from all tabs since tabs may be * closed and closing the tab will try to delete the BrowserTabContent * in the tab but this BrowserTabContent may still be valid. */ const int32_t beforeNumTabs = this->tabBar->count(); for (int32_t iTab = 0; iTab < beforeNumTabs; iTab++) { this->tabBar->setTabData(iTab, qVariantFromValue((void*)NULL)); } /* * Add/remove tabs as needed */ if (beforeNumTabs < numTabs) { const int32_t numToAdd = numTabs - beforeNumTabs; for (int32_t i = 0; i < numToAdd; i++) { this->tabBar->addTab(""); } } else if (beforeNumTabs > numTabs) { const int32_t numToRemove = beforeNumTabs - numTabs; for (int32_t i = 0; i < numToRemove; i++) { const int32_t lastTabIndex = this->tabBar->count() - 1; this->tabBar->removeTab(lastTabIndex); } } CaretAssert(this->tabBar->count() == numTabs); /* * Set content and update name for each tab */ for (int32_t iTab = 0; iTab < numTabs; iTab++) { CaretAssertVectorIndex(browserTabs, iTab); BrowserTabContent* btc = browserTabs[iTab]; CaretAssert(btc); this->tabBar->setTabData(iTab, qVariantFromValue((void*)btc)); this->updateTabName(iTab); } const int32_t numOpenTabs = this->tabBar->count(); this->tabBar->setTabsClosable(numOpenTabs > 1); if (selectedTabIndex >= numTabs) { selectedTabIndex = numTabs - 1; } if (selectedTabIndex < 0) { selectedTabIndex = 0; } this->tabBar->setCurrentIndex(selectedTabIndex); } /** * Adds a new tab. */ void BrainBrowserWindowToolBar::addNewTab() { insertNewTabAtTabBarIndex(-1); } /** * Insert a new tab at the given index in the tab bar. * * @param tabBarIndex * Index in the tab bar. If invalid, tab is appended to the end of the toolbar. */ void BrainBrowserWindowToolBar::insertNewTabAtTabBarIndex(const int32_t tabBarIndex) { if ( ! allowAddingNewTab()) { return; } /* * Wait cursor */ CursorDisplayScoped cursor; cursor.showWaitCursor(); AString errorMessage; BrowserTabContent* tabContent = this->createNewTab(errorMessage); if (tabContent == NULL) { cursor.restoreCursor(); QMessageBox::critical(this, "", errorMessage); return; } if (tabBarIndex >= 0){ insertTabContentPrivate(InsertTabMode::AT_TAB_BAR_INDEX, tabContent, tabBarIndex); } else { insertTabContentPrivate(InsertTabMode::APPEND, tabContent, -1); } this->updateToolBar(); EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(this->browserWindowIndex).getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(this->browserWindowIndex).getPointer()); } /** * Insert tab content into a tab in the toolbar. * * @param insertTabMode * Mode for inserting the tab. * @param browserTabContent * The tab content. * @param tabBarIndex * Index of tab bar of where tab is inserted for mode AT_TAB_BAR_INDEX */ void BrainBrowserWindowToolBar::insertTabContentPrivate(const InsertTabMode insertTabMode, BrowserTabContent* browserTabContent, const int32_t tabBarIndex) { CaretAssert(browserTabContent); this->tabBar->blockSignals(true); int32_t newTabIndex = -1; switch (insertTabMode) { case InsertTabMode::APPEND: newTabIndex = this->tabBar->addTab("NewTab"); break; case InsertTabMode::AT_TAB_BAR_INDEX: if ((tabBarIndex >= 0) && (tabBarIndex <= this->tabBar->count())) { newTabIndex = this->tabBar->insertTab(tabBarIndex, "NewTab"); } break; } this->tabBar->setTabData(newTabIndex, qVariantFromValue((void*)browserTabContent)); const int32_t numOpenTabs = this->tabBar->count(); this->tabBar->setTabsClosable(numOpenTabs > 1); this->updateTabName(newTabIndex); this->tabBar->setCurrentIndex(newTabIndex); this->tabBar->blockSignals(false); } /** * When adding a new tab or duplicating a tab, the tab * may not be visible when Tile Tabs is enabled and there * is no available space in the tile tabs configuration. * * @return * True if new tab should be created, else false. */ bool BrainBrowserWindowToolBar::allowAddingNewTab() { static bool m_doNotShowDialogAgainFlag = false; if (m_doNotShowDialogAgainFlag) { return true; } BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->browserWindowIndex); CaretAssert(browserWindow); BrowserWindowContent* browserWindowContent = browserWindow->getBrowerWindowContent(); CaretAssert(browserWindowContent); /* * Is tile tabs off? */ if ( ! browserWindowContent->isTileTabsEnabled()) { return true; } /* * Automatic configuration always shows all tabs */ switch (browserWindowContent->getTileTabsConfigurationMode()) { case TileTabsGridModeEnum::AUTOMATIC: return true; break; case TileTabsGridModeEnum::CUSTOM: break; } /* * Is there space in the current configuration? */ const TileTabsConfiguration* tileTabs = browserWindowContent->getCustomTileTabsConfiguration(); CaretAssert(tileTabs); const int32_t tileTabsCount = tileTabs->getNumberOfColumns() * tileTabs->getNumberOfRows(); if (getNumberOfTabs() < tileTabsCount) { return true; } /* * Selected configuration is full, all user to continue/cancel */ const AString doNotShowAgainMsg("Remember my choice and do not show this dialog again"); const AString msg("" "Tile tabs is enabled and there is no space in the selected tile " "tabs configuration for the new tab. If you choose to continue, " "either the new tab will not be visible or an existing tab will " "become invisible until the tile tabs configuration is changed." "

    " "Do you want to create the new tab?" "
    " ""); if (WuQMessageBox::warningYesNoWithDoNotShowAgain(this, "NewTabNotDisplayedDueToTileTabs", msg)) { return true; } return false; } /** * Show the macro dialog */ void BrainBrowserWindowToolBar::showMacroDialog() { BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(this->browserWindowIndex); CaretAssert(bbw); WuQMacroManager::instance()->showMacrosDialog(bbw); } /** * Shows/hides the toolbar. */ void BrainBrowserWindowToolBar::showHideToolBar(bool showIt) { if (this->isContructorFinished) { m_toolbarWidget->setVisible(showIt); } this->toolBarToolButtonAction->blockSignals(true); if (showIt) { this->toolBarToolButtonAction->setToolTip("Hide Toolbar"); this->toolBarToolButtonAction->setChecked(true); } else { this->toolBarToolButtonAction->setToolTip("Show Toolbar"); this->toolBarToolButtonAction->setChecked(false); } this->toolBarToolButtonAction->blockSignals(false); } /** * Add the default tabs after loading a spec file. */ void BrainBrowserWindowToolBar::addDefaultTabsAfterLoadingSpecFile() { EventModelGetAll eventAllModels; EventManager::get()->sendEvent(eventAllModels.getPointer()); const std::vector allModels = eventAllModels.getModels(); ModelSurface* leftSurfaceModel = NULL; ModelSurface* leftSurfaceInflated = NULL; ModelSurface* leftSurfaceVeryInflated = NULL; int32_t leftSurfaceTypeCode = 1000000; ModelSurface* rightSurfaceModel = NULL; ModelSurface* rightSurfaceInflated = NULL; ModelSurface* rightSurfaceVeryInflated = NULL; int32_t rightSurfaceTypeCode = 1000000; ModelSurface* cerebellumSurfaceModel = NULL; ModelSurface* cerebellumSurfaceInflated = NULL; ModelSurface* cerebellumSurfaceVeryInflated = NULL; int32_t cerebellumSurfaceTypeCode = 1000000; ModelChart* chartModel = NULL; ModelChartTwo* chartTwoModel = NULL; ModelSurfaceMontage* surfaceMontageModel = NULL; ModelVolume* volumeModel = NULL; ModelWholeBrain* wholeBrainModel = NULL; const bool includeSingleSurfacesFlag = false; const bool includeOldChartFlag = false; for (std::vector::const_iterator iter = allModels.begin(); iter != allModels.end(); iter++) { ModelSurface* surfaceModel = dynamic_cast(*iter); if (surfaceModel != NULL) { if (includeSingleSurfacesFlag) { Surface* surface = surfaceModel->getSurface(); StructureEnum::Enum structure = surface->getStructure(); SurfaceTypeEnum::Enum surfaceType = surface->getSurfaceType(); const int32_t surfaceTypeCode = SurfaceTypeEnum::toIntegerCode(surfaceType); switch (structure) { case StructureEnum::CEREBELLUM: if (surfaceTypeCode < cerebellumSurfaceTypeCode) { cerebellumSurfaceModel = surfaceModel; cerebellumSurfaceTypeCode = surfaceTypeCode; } if (surfaceType == SurfaceTypeEnum::INFLATED) { cerebellumSurfaceInflated = surfaceModel; } else if (surfaceType == SurfaceTypeEnum::VERY_INFLATED) { cerebellumSurfaceVeryInflated = surfaceModel; } break; case StructureEnum::CORTEX_LEFT: if (surfaceTypeCode < leftSurfaceTypeCode) { leftSurfaceModel = surfaceModel; leftSurfaceTypeCode = surfaceTypeCode; } if (surfaceType == SurfaceTypeEnum::INFLATED) { leftSurfaceInflated = surfaceModel; } else if (surfaceType == SurfaceTypeEnum::VERY_INFLATED) { leftSurfaceVeryInflated = surfaceModel; } break; case StructureEnum::CORTEX_RIGHT: if (surfaceTypeCode < rightSurfaceTypeCode) { rightSurfaceModel = surfaceModel; rightSurfaceTypeCode = surfaceTypeCode; } if (surfaceType == SurfaceTypeEnum::INFLATED) { rightSurfaceInflated = surfaceModel; } else if (surfaceType == SurfaceTypeEnum::VERY_INFLATED) { rightSurfaceVeryInflated = surfaceModel; } break; default: break; } } } else if (dynamic_cast(*iter) != NULL) { surfaceMontageModel = dynamic_cast(*iter); } else if (dynamic_cast(*iter) != NULL) { volumeModel = dynamic_cast(*iter); } else if (dynamic_cast(*iter) != NULL) { wholeBrainModel = dynamic_cast(*iter); } else if (dynamic_cast(*iter)) { if (includeOldChartFlag) { chartModel = dynamic_cast(*iter); } } else if (dynamic_cast(*iter)) { chartTwoModel = dynamic_cast(*iter); } else { CaretAssertMessage(0, AString("Unknow controller type: ") + (*iter)->getNameForGUI(true)); } } if (cerebellumSurfaceInflated != NULL) { cerebellumSurfaceModel = cerebellumSurfaceInflated; } else if (cerebellumSurfaceVeryInflated != NULL) { cerebellumSurfaceModel = cerebellumSurfaceVeryInflated; } if (leftSurfaceInflated != NULL) { leftSurfaceModel = leftSurfaceInflated; } else if (leftSurfaceVeryInflated != NULL) { leftSurfaceModel = leftSurfaceVeryInflated; } if (rightSurfaceInflated != NULL) { rightSurfaceModel = rightSurfaceInflated; } else if (rightSurfaceVeryInflated != NULL) { rightSurfaceModel = rightSurfaceVeryInflated; } int32_t numberOfTabsNeeded = 0; if (surfaceMontageModel != NULL) { numberOfTabsNeeded++; } if (volumeModel != NULL) { numberOfTabsNeeded++; } if (wholeBrainModel != NULL) { numberOfTabsNeeded++; } if (chartModel != NULL) { numberOfTabsNeeded++; } if (chartTwoModel != NULL) { numberOfTabsNeeded++; } if (leftSurfaceModel != NULL) { numberOfTabsNeeded++; } if (rightSurfaceModel != NULL) { numberOfTabsNeeded++; } if (cerebellumSurfaceModel != NULL) { numberOfTabsNeeded++; } const int32_t numberOfTabsToAdd = numberOfTabsNeeded - this->tabBar->count(); for (int32_t i = 0; i < numberOfTabsToAdd; i++) { AString errorMessage; BrowserTabContent* tabContent = this->createNewTab(errorMessage); if (tabContent != NULL) { insertTabContentPrivate(InsertTabMode::APPEND, tabContent, -1); } } int32_t tabIndex = 0; tabIndex = loadIntoTab(tabIndex, surfaceMontageModel); tabIndex = loadIntoTab(tabIndex, volumeModel); tabIndex = loadIntoTab(tabIndex, wholeBrainModel); tabIndex = loadIntoTab(tabIndex, chartTwoModel); tabIndex = loadIntoTab(tabIndex, chartModel); tabIndex = loadIntoTab(tabIndex, leftSurfaceModel); tabIndex = loadIntoTab(tabIndex, rightSurfaceModel); tabIndex = loadIntoTab(tabIndex, cerebellumSurfaceModel); const int numTabs = this->tabBar->count(); if (numTabs > 0) { this->tabBar->setCurrentIndex(0); Brain* brain = GuiManager::get()->getBrain(); for (int32_t i = 0; i < numTabs; i++) { BrowserTabContent* btc = this->getTabContentFromTab(i); if (btc != NULL) { btc->getVolumeSurfaceOutlineSet()->selectSurfacesAfterSpecFileLoaded(brain, true); } } /* * Set the default tab to whole brain, if present */ int32_t surfaceTabIndex = -1; int32_t montageTabIndex = -1; int32_t wholeBrainTabIndex = -1; int32_t volumeTabIndex = -1; for (int32_t i = 0; i < numTabs; i++) { BrowserTabContent* btc = getTabContentFromTab(i); if (btc != NULL) { switch (btc->getSelectedModelType()) { case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: if (surfaceTabIndex < 0) { surfaceTabIndex = i; } break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: if (montageTabIndex < 0) { montageTabIndex = i; } break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: if (volumeTabIndex < 0) { volumeTabIndex = i; } break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: if (wholeBrainTabIndex < 0) { wholeBrainTabIndex = i; } break; case ModelTypeEnum::MODEL_TYPE_CHART: break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: break; } } } int32_t defaultTabIndex = 0; if (montageTabIndex >= 0) { defaultTabIndex = montageTabIndex; } else if (surfaceTabIndex >= 0) { defaultTabIndex = surfaceTabIndex; } else if (volumeTabIndex >= 0) { defaultTabIndex = volumeTabIndex; } else if (wholeBrainTabIndex >= 0) { defaultTabIndex = wholeBrainTabIndex; } this->tabBar->setCurrentIndex(defaultTabIndex); } } /** * Load a controller into the tab with the given index. * @param tabIndexIn * Index of tab into which controller is loaded. A * new tab will be created, if needed. * @param controller * Model that is to be displayed in the tab. If * NULL, this method does nothing. * @return * Index of next tab after controller is displayed. * If the input controller was NULL, the returned * value is identical to the input tab index. */ int32_t BrainBrowserWindowToolBar::loadIntoTab(const int32_t tabIndexIn, Model* controller) { if (tabIndexIn < 0) { return -1; } int32_t tabIndex = tabIndexIn; if (controller != NULL) { if (tabIndex >= this->tabBar->count()) { AString errorMessage; BrowserTabContent* tabContent = this->createNewTab(errorMessage); if (tabContent == NULL) { return -1; } insertTabContentPrivate(InsertTabMode::APPEND, tabContent, -1); tabIndex = this->tabBar->count() - 1; } void* p = this->tabBar->tabData(tabIndex).value(); BrowserTabContent* btc = (BrowserTabContent*)p; btc->setSelectedModelType(controller->getModelType()); ModelSurface* surfaceModel = dynamic_cast(controller); if (surfaceModel != NULL) { btc->getSurfaceModelSelector()->setSelectedStructure(surfaceModel->getSurface()->getStructure()); btc->getSurfaceModelSelector()->setSelectedSurfaceModel(surfaceModel); btc->setSelectedModelType(ModelTypeEnum::MODEL_TYPE_SURFACE); } this->updateTabName(tabIndex); tabIndex++; } return tabIndex; } /** * Move all but the current tab to new windows. */ void BrainBrowserWindowToolBar::moveTabsToNewWindows() { int32_t numTabs = this->tabBar->count(); if (numTabs > 1) { const int32_t currentIndex = this->tabBar->currentIndex(); QWidget* lastParent = this->parentWidget(); if (lastParent == NULL) { lastParent = this; } for (int32_t i = (numTabs - 1); i >= 0; i--) { if (i != currentIndex) { void* p = this->tabBar->tabData(i).value(); BrowserTabContent* btc = (BrowserTabContent*)p; EventBrowserWindowNew eventNewWindow(lastParent, btc); EventManager::get()->sendEvent(eventNewWindow.getPointer()); if (eventNewWindow.isError()) { QMessageBox::critical(this, "", eventNewWindow.getErrorMessage()); break; } else { lastParent = eventNewWindow.getBrowserWindowCreated(); this->tabBar->setTabData(i, qVariantFromValue((void*)NULL)); this->tabClosed(i); } } } } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** * Remove and return all tabs from this toolbar. * After this the window containing this toolbar * will contain no tabs! * * @param allTabContent * Will contain the content from the tabs upon return. */ void BrainBrowserWindowToolBar::removeAndReturnAllTabs(std::vector& allTabContent) { allTabContent.clear(); int32_t numTabs = this->tabBar->count(); for (int32_t i = (numTabs - 1); i >= 0; i--) { void* p = this->tabBar->tabData(i).value(); BrowserTabContent* btc = (BrowserTabContent*)p; if (btc != NULL) { allTabContent.push_back(btc); } this->tabBar->setTabData(i, qVariantFromValue((void*)NULL)); this->tabClosed(i); } } /** * Get content of all tabs * * @param allTabContent * Will contain the content from the tabs upon return. */ void BrainBrowserWindowToolBar::getAllTabContent(std::vector& allTabContent) const { allTabContent.clear(); int32_t numTabs = this->tabBar->count(); for (int32_t i = 0; i < numTabs; i++) { void* p = this->tabBar->tabData(i).value(); BrowserTabContent* btc = (BrowserTabContent*)p; if (btc != NULL) { allTabContent.push_back(btc); } } } /** * Remove the tab that contains the given tab content. * Note: The tab content is NOT deleted and the caller must * either delete it or move it into a window. * After this method completes, the windowo may contain no tabs. * * @param browserTabContent */ void BrainBrowserWindowToolBar::removeTabWithContent(BrowserTabContent* browserTabContent) { int32_t numTabs = this->tabBar->count(); for (int32_t i = 0; i < numTabs; i++) { void* p = this->tabBar->tabData(i).value(); BrowserTabContent* btc = (BrowserTabContent*)p; if (btc == browserTabContent) { this->tabBar->setTabData(i, qVariantFromValue((void*)NULL)); this->tabClosed(i); if (this->tabBar->count() <= 0) { EventManager::get()->removeAllEventsFromListener(this); } break; } } } /** * Select the next tab. */ void BrainBrowserWindowToolBar::nextTab() { int32_t numTabs = this->tabBar->count(); if (numTabs > 1) { int32_t tabIndex = this->tabBar->currentIndex(); tabIndex++; if (tabIndex >= numTabs) { tabIndex = 0; } this->tabBar->setCurrentIndex(tabIndex); } } /** * Select the previous tab. */ void BrainBrowserWindowToolBar::previousTab() { int32_t numTabs = this->tabBar->count(); if (numTabs > 1) { int32_t tabIndex = this->tabBar->currentIndex(); tabIndex--; if (tabIndex < 0) { tabIndex = numTabs - 1; } this->tabBar->setCurrentIndex(tabIndex); } } /** * Rename the current tab. */ void BrainBrowserWindowToolBar::renameTab() { const int tabIndex = this->tabBar->currentIndex(); if (tabIndex >= 0) { void* p = this->tabBar->tabData(tabIndex).value(); BrowserTabContent* btc = (BrowserTabContent*)p; AString currentName = btc->getUserTabName(); bool ok = false; AString newName = QInputDialog::getText(this, "Set Tab Name", "New Name (empty to reset)", QLineEdit::Normal, currentName, &ok); if (ok) { btc->setUserTabName(newName); this->updateTabName(tabIndex); } } } /** * Update the names of all tabs. */ void BrainBrowserWindowToolBar::updateAllTabNames() { for (int32_t i = 0; i < this->tabBar->count(); i++) { updateTabName(i); } } /** * Update the name of the tab at the given index. The * name is obtained from the tabs browser content. * * @param tabIndex * Index of tab. */ void BrainBrowserWindowToolBar::updateTabName(const int32_t tabIndex) { int32_t tabIndexForUpdate = tabIndex; if (tabIndexForUpdate < 0) { tabIndexForUpdate = this->tabBar->currentIndex(); } void* p = this->tabBar->tabData(tabIndexForUpdate).value(); AString newName = ""; BrowserTabContent* btc = (BrowserTabContent*)p; if (btc != NULL) { newName = btc->getTabName(); } this->tabBar->setTabText(tabIndexForUpdate, newName); } /** * Close the selected tab. This method is typically * called by the BrowswerWindow's File Menu. */ void BrainBrowserWindowToolBar::closeSelectedTab() { tabCloseSelected(this->tabBar->currentIndex()); } /** * Called when context menu requested for the tab bar. * * @param pos * Postion of mouse in parent widget. */ void BrainBrowserWindowToolBar::showTabMenu(const QPoint& pos) { const int tabIndexUnderMouseIndex = this->tabBar->tabAt(pos); if (tabIndexUnderMouseIndex >= 0) { BrainBrowserWindowToolBarTabPopUpMenu menu(this, tabIndexUnderMouseIndex); menu.exec(mapToGlobal(pos)); } else { QMenu menu(this->tabBar); menu.move(mapToGlobal(pos)); QAction* addAction = menu.addAction("Add New Tab"); const QAction* selectedAction = menu.exec(); if (selectedAction == addAction) { addNewTab(); } else if (selectedAction != NULL) { CaretAssertMessage(0, "Has a new action been added to the menu"); } } } /** * Called when the selected tab is changed. * @param index * Index of selected tab. */ void BrainBrowserWindowToolBar::selectedTabChanged(int indx) { this->updateTabName(indx); this->updateToolBar(); this->updateToolBox(); emit viewedModelChanged(); BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->browserWindowIndex); if (browserWindow != NULL) { if (browserWindow->isTileTabsSelected()) { const BrowserTabContent* btc = getTabContentFromSelectedTab(); if (btc != NULL) { if (m_tileTabsHighlightingTimerEnabledFlag) { m_tabIndexForTileTabsHighlighting = btc->getTabNumber(); /* * Short timer that will reset the tab highlighting */ if (m_tileTabsHighlightingTimer == NULL) { m_tileTabsHighlightingTimer = new QTimer(this); QObject::connect(m_tileTabsHighlightingTimer, &QTimer::timeout, this, &BrainBrowserWindowToolBar::resetTabIndexForTileTabsHighlighting); } /* * Note: There is no need to 'stop' the timer if it is running * as the start() method will stop and restart the timer */ const int timeInMilliseconds = 750; m_tileTabsHighlightingTimer->setSingleShot(true); m_tileTabsHighlightingTimer->start(timeInMilliseconds); } } } } /* * Graphics must be updated so border is visible around the selected tab */ this->updateGraphicsWindow(); } /** * Reset the tab index for tab tile highlighting. */ void BrainBrowserWindowToolBar::resetTabIndexForTileTabsHighlighting() { m_tabIndexForTileTabsHighlighting = -1; EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(this->browserWindowIndex).getPointer()); } /** * Called when tab bar mouse pressed. */ void BrainBrowserWindowToolBar::tabBarMousePressedSlot() { /* * Dragging tabs is slow because as the tab is moved, there are many graphics * and user-interface updates each time the tab changes. So, disable these updates * during the time the mouse is pressed and until it is released. Note that we * block the "all windows graphics" update but not the individual window update. * The individual window graphics update is needed to draw the box around the selected tab. */ EventManager::get()->blockEvent(EventTypeEnum::EVENT_USER_INTERFACE_UPDATE, true); EventManager::get()->blockEvent(EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS, true); } /** * Called when tab bar mouse released. */ void BrainBrowserWindowToolBar::tabBarMouseReleasedSlot() { /* * Enable user-interface updates and graphics drawing since any tab * dragging has finished. */ EventManager::get()->blockEvent(EventTypeEnum::EVENT_USER_INTERFACE_UPDATE, false); EventManager::get()->blockEvent(EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS, false); EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(this->browserWindowIndex).getPointer()); /** * Causes graphics and user-interface to update. * A box is drawn around selected tab. */ selectedTabChanged(tabBar->currentIndex()); } /** * Gets called when user closes a tab by clicking the tab's 'X'. * * @param tabIndex * Index of the tab that was closed. */ void BrainBrowserWindowToolBar::tabCloseSelected(int tabIndex) { if ((tabIndex >= 0) && (tabIndex < this->tabBar->count())) { tabClosed(tabIndex); } this->updateGraphicsWindow(); } /** * Close a tab. * * @param tabIndex * Index of tab that was closed. */ void BrainBrowserWindowToolBar::tabClosed(int tabIndex) { CaretAssertArrayIndex(this-tabBar->tabData(), this->tabBar->count(), tabIndex); this->removeTab(tabIndex); if (this->isDestructionInProgress == false) { this->updateToolBar(); this->updateToolBox(); emit viewedModelChanged(); } } /** * Called when a tab has been moved. * * @param from * Previous location of tab. * @param to * New location of tab. */ void BrainBrowserWindowToolBar::tabMoved(int /*from*/, int /*to*/) { /* No need to redraw as the selectedTabChanged() is also called when a tab is moved */ } /** * Remove the tab at the given index. * @param index */ void BrainBrowserWindowToolBar::removeTab(int tabIndex) { CaretAssertArrayIndex(this-tabBar->tabData(), this->tabBar->count(), tabIndex); void* p = this->tabBar->tabData(tabIndex).value(); if (p != NULL) { BrowserTabContent* btc = (BrowserTabContent*)p; EventBrowserTabDelete deleteTabEvent(btc, btc->getTabNumber()); EventManager::get()->sendEvent(deleteTabEvent.getPointer()); } this->tabBar->blockSignals(true); this->tabBar->removeTab(tabIndex); this->tabBar->blockSignals(false); const int numOpenTabs = this->tabBar->count(); this->tabBar->setTabsClosable(numOpenTabs > 1); } /** * Update the toolbar. */ void BrainBrowserWindowToolBar::updateToolBar() { if (this->isDestructionInProgress) { return; } /* * If this is true, it indicates that one of the 'update' methods has mistakenly emitted a signal * or an update. */ if (m_performingUpdateFlag) { const AString msg("During an update of the toolbar, a signal was issued and needs to be blocked.\n" "Set a break on this line and go through the call stack to find where the\n" "signal was emitted and block it."); CaretLogSevere(msg); } m_performingUpdateFlag = true; /* * If there are no models, close all but the first tab. */ EventModelGetAll getAllModelsEvent; EventManager::get()->sendEvent(getAllModelsEvent.getPointer()); if (getAllModelsEvent.getFirstModel() == NULL) { for (int i = (this->tabBar->count() - 1); i >= 0; i--) { this->removeTab(i); } } BrowserTabContent* browserTabContent = this->getTabContentFromSelectedTab(); const ModelTypeEnum::Enum viewModel = this->updateViewWidget(browserTabContent); bool showOrientationWidget = false; bool showWholeBrainSurfaceOptionsWidget = false; bool showSingleSurfaceOptionsWidget = false; bool showSurfaceMontageOptionsWidget = false; bool showClippingOptionsWidget = false; bool showVolumeIndicesWidget = false; bool showVolumePlaneWidget = false; bool showVolumeMontageWidget = false; bool showChartOneAxesWidget = false; bool showChartOneTypeWidget = false; bool showChartTwoTypeWidget = false; bool showChartOneAttributesWidget = false; bool showChartTwoOrientationWidget = false; bool showChartTwoAttributesWidget = false; bool showChartTwoAxesWidget = false; bool showChartTwoTitleWidget = false; bool showModeWidget = true; bool showWindowWidget = true; switch (viewModel) { case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: showOrientationWidget = true; showSingleSurfaceOptionsWidget = true; showClippingOptionsWidget = true; break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: showOrientationWidget = true; showSurfaceMontageOptionsWidget = true; showClippingOptionsWidget = true; break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: showVolumeIndicesWidget = true; showVolumePlaneWidget = true; showVolumeMontageWidget = true; showClippingOptionsWidget = true; break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: showOrientationWidget = true; showWholeBrainSurfaceOptionsWidget = true; showVolumeIndicesWidget = true; showClippingOptionsWidget = true; break; case ModelTypeEnum::MODEL_TYPE_CHART: { ModelChart* modelChart = browserTabContent->getDisplayedChartOneModel(); if (modelChart != NULL) { showChartOneTypeWidget = true; switch (modelChart->getSelectedChartOneDataType(browserTabContent->getTabNumber())) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: showChartOneAttributesWidget = true; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: showChartOneAttributesWidget = true; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: showChartOneAxesWidget = true; showChartOneAttributesWidget = true; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: showChartOneAxesWidget = true; showChartOneAttributesWidget = true; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: showChartOneAxesWidget = true; showChartOneAttributesWidget = true; break; } } } break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: { ModelChartTwo* modelChartTwo = browserTabContent->getDisplayedChartTwoModel(); if (modelChartTwo != NULL) { switch (modelChartTwo->getSelectedChartTwoDataType(browserTabContent->getTabNumber())) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: showChartTwoAxesWidget = true; showChartTwoTitleWidget = true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: showChartTwoAxesWidget = true; showChartTwoTitleWidget = true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: showChartTwoOrientationWidget = true; showChartTwoAttributesWidget = true; showChartTwoTitleWidget = true; break; } showChartTwoTypeWidget = true; } } break; } /* * Need to turn off display of all widgets, * otherwise, the toolbar width may be overly * expanded with empty space as other widgets * are turned on and off. */ this->orientationWidget->setVisible(false); this->wholeBrainSurfaceOptionsWidget->setVisible(false); this->singleSurfaceSelectionWidget->setVisible(false); this->surfaceMontageSelectionWidget->setVisible(false); this->chartTypeWidget->setVisible(false); this->chartTypeTwoWidget->setVisible(false); this->chartAxesWidget->setVisible(false); this->chartAttributesWidget->setVisible(false); this->chartTwoOrientationWidget->setVisible(false); this->chartTwoAttributesWidget->setVisible(false); this->chartTwoAxesWidget->setVisible(false); this->chartTwoTitleWidget->setVisible(false); this->volumeIndicesWidget->setVisible(false); this->volumePlaneWidget->setVisible(false); this->volumeMontageWidget->setVisible(false); this->modeWidget->setVisible(false); this->windowWidget->setVisible(false); m_clippingOptionsWidget->setVisible(false); this->orientationWidget->setVisible(showOrientationWidget); this->wholeBrainSurfaceOptionsWidget->setVisible(showWholeBrainSurfaceOptionsWidget); this->singleSurfaceSelectionWidget->setVisible(showSingleSurfaceOptionsWidget); this->surfaceMontageSelectionWidget->setVisible(showSurfaceMontageOptionsWidget); this->chartTypeWidget->setVisible(showChartOneTypeWidget); this->chartTypeTwoWidget->setVisible(showChartTwoTypeWidget); this->chartAxesWidget->setVisible(showChartOneAxesWidget); this->chartAttributesWidget->setVisible(showChartOneAttributesWidget); this->chartTwoOrientationWidget->setVisible(showChartTwoOrientationWidget); this->chartTwoAttributesWidget->setVisible(showChartTwoAttributesWidget); this->chartTwoAxesWidget->setVisible(showChartTwoAxesWidget); this->chartTwoTitleWidget->setVisible(showChartTwoTitleWidget); this->volumeIndicesWidget->setVisible(showVolumeIndicesWidget); this->volumePlaneWidget->setVisible(showVolumePlaneWidget); this->volumeMontageWidget->setVisible(showVolumeMontageWidget); this->modeWidget->setVisible(showModeWidget); m_clippingOptionsWidget->setVisible(showClippingOptionsWidget); this->windowWidget->setVisible(showWindowWidget); updateToolBarComponents(browserTabContent); this->updateAllTabNames(); BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->browserWindowIndex); if (browserWindow != NULL) { if (browserWindow->isFullScreen()) { this->setVisible(false); } else { this->setVisible(true); } } /* * Try to avoid resizing of Toolbar widget (view, orientation, etc) * height when models are changed. Let it grow but never shrink. */ if (isVisible()) { if (m_toolbarWidget->isVisible()) { const int sizeHintHeight = m_toolbarWidget->sizeHint().height(); const int actualHeight = m_toolbarWidget->height(); if (sizeHintHeight >= actualHeight) { m_toolbarWidget->setFixedHeight(sizeHintHeight); } } } m_performingUpdateFlag = false; } /** * Update the components in the toolbar with the given tab content. * * @param browserTabContent * The current tab content. */ void BrainBrowserWindowToolBar::updateToolBarComponents(BrowserTabContent* browserTabContent) { if (browserTabContent != NULL) { this->updateOrientationWidget(browserTabContent); this->updateWholeBrainSurfaceOptionsWidget(browserTabContent); this->updateVolumeIndicesWidget(browserTabContent); this->updateSingleSurfaceOptionsWidget(browserTabContent); this->updateSurfaceMontageOptionsWidget(browserTabContent); this->updateChartTypeWidget(browserTabContent); this->updateChartTypeTwoWidget(browserTabContent); this->updateChartAxesWidget(browserTabContent); this->updateChartAttributesWidget(browserTabContent); this->updateChartTwoOrientationWidget(browserTabContent); this->updateChartTwoAttributesWidget(browserTabContent); this->updateChartTwoAxesWidget(browserTabContent); this->updateChartTwoTitleWidget(browserTabContent); this->updateVolumeMontageWidget(browserTabContent); this->updateVolumePlaneWidget(browserTabContent); this->updateModeWidget(browserTabContent); this->updateTabOptionsWidget(browserTabContent); this->updateClippingOptionsWidget(browserTabContent); } } /** * Create the view widget. * * @return The view widget. */ QWidget* BrainBrowserWindowToolBar::createViewWidget() { WuQMacroManager* macroManager = WuQMacroManager::instance(); const QString objectNamePrefix(m_objectNamePrefix + ":ViewMode"); this->viewModeChartOneRadioButton = new QRadioButton("Chart Old"); this->viewModeChartOneRadioButton->setToolTip("Show Old Chart View"); this->viewModeChartOneRadioButton->setObjectName(objectNamePrefix + ":ChartOld"); macroManager->addMacroSupportToObject(this->viewModeChartOneRadioButton, "Select Chart Old View"); this->viewModeChartTwoRadioButton = new QRadioButton("Chart"); this->viewModeChartTwoRadioButton->setToolTip("Show Chart View"); this->viewModeChartTwoRadioButton->setObjectName(objectNamePrefix + ":Chart"); macroManager->addMacroSupportToObject(this->viewModeChartTwoRadioButton, "Select Chart View"); this->viewModeSurfaceRadioButton = new QRadioButton("Surface"); this->viewModeSurfaceRadioButton->setToolTip("Show Surace View"); this->viewModeSurfaceRadioButton->setObjectName(objectNamePrefix + ":Surface"); macroManager->addMacroSupportToObject(this->viewModeSurfaceRadioButton, "Select surface view"); this->viewModeSurfaceMontageRadioButton = new QRadioButton("Montage"); this->viewModeSurfaceMontageRadioButton->setToolTip("Show Montage View"); this->viewModeSurfaceMontageRadioButton->setObjectName(objectNamePrefix + ":Montage"); macroManager->addMacroSupportToObject(this->viewModeSurfaceMontageRadioButton, "Select surface montage view"); this->viewModeVolumeRadioButton = new QRadioButton("Volume"); this->viewModeVolumeRadioButton->setToolTip("Show Volume View"); this->viewModeVolumeRadioButton->setObjectName(objectNamePrefix + ":Volume"); macroManager->addMacroSupportToObject(this->viewModeVolumeRadioButton, "Select volume view"); this->viewModeWholeBrainRadioButton = new QRadioButton("All"); this->viewModeWholeBrainRadioButton->setToolTip("Show All View"); this->viewModeWholeBrainRadioButton->setObjectName(objectNamePrefix + ":All"); macroManager->addMacroSupportToObject(this->viewModeWholeBrainRadioButton, "Select all view"); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); #ifdef CARET_OS_MACOSX WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 2); #else WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 2); #endif layout->addWidget(this->viewModeSurfaceMontageRadioButton); layout->addWidget(this->viewModeVolumeRadioButton); layout->addWidget(this->viewModeWholeBrainRadioButton); layout->addWidget(this->viewModeChartTwoRadioButton); layout->addWidget(this->viewModeSurfaceRadioButton); layout->addWidget(this->viewModeChartOneRadioButton); QButtonGroup* viewModeRadioButtonGroup = new QButtonGroup(this); viewModeRadioButtonGroup->addButton(this->viewModeChartOneRadioButton); viewModeRadioButtonGroup->addButton(this->viewModeChartTwoRadioButton); viewModeRadioButtonGroup->addButton(this->viewModeSurfaceRadioButton); viewModeRadioButtonGroup->addButton(this->viewModeSurfaceMontageRadioButton); viewModeRadioButtonGroup->addButton(this->viewModeVolumeRadioButton); viewModeRadioButtonGroup->addButton(this->viewModeWholeBrainRadioButton); QObject::connect(viewModeRadioButtonGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(viewModeRadioButtonClicked(QAbstractButton*))); this->viewWidgetGroup = new WuQWidgetObjectGroup(this); this->viewWidgetGroup->add(this->viewModeChartOneRadioButton); this->viewWidgetGroup->add(this->viewModeChartTwoRadioButton); this->viewWidgetGroup->add(this->viewModeSurfaceRadioButton); this->viewWidgetGroup->add(this->viewModeSurfaceMontageRadioButton); this->viewWidgetGroup->add(this->viewModeVolumeRadioButton); this->viewWidgetGroup->add(this->viewModeWholeBrainRadioButton); QWidget* w = this->createToolWidget("View", widget, WIDGET_PLACEMENT_NONE, WIDGET_PLACEMENT_TOP, 0); return w; } /** * Update the view widget. * * @param browserTabContent * Content in the tab. * @return * An enumerated type indicating the type of model being viewed. */ ModelTypeEnum::Enum BrainBrowserWindowToolBar::updateViewWidget(BrowserTabContent* browserTabContent) { ModelTypeEnum::Enum modelType = ModelTypeEnum::MODEL_TYPE_INVALID; if (browserTabContent != NULL) { modelType = browserTabContent->getSelectedModelType(); } this->viewWidgetGroup->blockAllSignals(true); /* * Enable buttons for valid types */ if (browserTabContent != NULL) { this->viewModeSurfaceRadioButton->setEnabled(browserTabContent->isSurfaceModelValid()); this->viewModeSurfaceMontageRadioButton->setEnabled(browserTabContent->isSurfaceMontageModelValid()); this->viewModeVolumeRadioButton->setEnabled(browserTabContent->isVolumeSliceModelValid()); this->viewModeWholeBrainRadioButton->setEnabled(browserTabContent->isWholeBrainModelValid()); this->viewModeChartOneRadioButton->setEnabled(browserTabContent->isChartOneModelValid()); this->viewModeChartTwoRadioButton->setEnabled(browserTabContent->isChartTwoModelValid()); } else { this->viewModeSurfaceRadioButton->setEnabled(false); this->viewModeSurfaceMontageRadioButton->setEnabled(false); this->viewModeVolumeRadioButton->setEnabled(false); this->viewModeWholeBrainRadioButton->setEnabled(false); this->viewModeChartOneRadioButton->setEnabled(false); this->viewModeChartTwoRadioButton->setEnabled(false); } switch (modelType) { case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: this->viewModeSurfaceRadioButton->setChecked(true); break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: this->viewModeSurfaceMontageRadioButton->setChecked(true); break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: this->viewModeVolumeRadioButton->setChecked(true); break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: this->viewModeWholeBrainRadioButton->setChecked(true); break; case ModelTypeEnum::MODEL_TYPE_CHART: this->viewModeChartOneRadioButton->setChecked(true); break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: this->viewModeChartTwoRadioButton->setChecked(true); break; } this->viewWidgetGroup->blockAllSignals(false); return modelType; } /** * Create the orientation widget. * * @return The orientation widget. */ QWidget* BrainBrowserWindowToolBar::createOrientationWidget() { WuQMacroManager* macroManager = WuQMacroManager::instance(); CaretAssert(macroManager); const QString objectNamePrefix(m_objectNamePrefix + ":Orientation:"); this->viewOrientationLeftIcon = WuQtUtilities::loadIcon(":/ToolBar/view-left.png"); this->viewOrientationRightIcon = WuQtUtilities::loadIcon(":/ToolBar/view-right.png"); this->viewOrientationAnteriorIcon = WuQtUtilities::loadIcon(":/ToolBar/view-anterior.png"); this->viewOrientationPosteriorIcon = WuQtUtilities::loadIcon(":/ToolBar/view-posterior.png"); this->viewOrientationDorsalIcon = WuQtUtilities::loadIcon(":/ToolBar/view-dorsal.png"); this->viewOrientationVentralIcon = WuQtUtilities::loadIcon(":/ToolBar/view-ventral.png"); this->viewOrientationLeftLateralIcon = WuQtUtilities::loadIcon(":/ToolBar/view-left-lateral.png"); this->viewOrientationLeftMedialIcon = WuQtUtilities::loadIcon(":/ToolBar/view-left-medial.png"); this->viewOrientationRightLateralIcon = WuQtUtilities::loadIcon(":/ToolBar/view-right-lateral.png"); this->viewOrientationRightMedialIcon = WuQtUtilities::loadIcon(":/ToolBar/view-right-medial.png"); this->orientationLeftOrLateralToolButtonAction = WuQtUtilities::createAction("L", "View from a LEFT perspective", this, this, SLOT(orientationLeftOrLateralToolButtonTriggered(bool))); if (this->viewOrientationLeftIcon != NULL) { this->orientationLeftOrLateralToolButtonAction->setIcon(*this->viewOrientationLeftIcon); } else { this->orientationLeftOrLateralToolButtonAction->setIconText("L"); } this->orientationLeftOrLateralToolButtonAction->setObjectName(objectNamePrefix + "LeftOrLateralView"); macroManager->addMacroSupportToObject(this->orientationLeftOrLateralToolButtonAction, "Select left or lateral orientation"); this->orientationRightOrMedialToolButtonAction = WuQtUtilities::createAction("R", "View from a RIGHT perspective", this, this, SLOT(orientationRightOrMedialToolButtonTriggered(bool))); if (this->viewOrientationRightIcon != NULL) { this->orientationRightOrMedialToolButtonAction->setIcon(*this->viewOrientationRightIcon); } else { this->orientationRightOrMedialToolButtonAction->setIconText("R"); } this->orientationRightOrMedialToolButtonAction->setObjectName(objectNamePrefix + "RightOrMedialView"); macroManager->addMacroSupportToObject(this->orientationRightOrMedialToolButtonAction, "Select right or medial orientation"); this->orientationAnteriorToolButtonAction = WuQtUtilities::createAction("A", "View from an ANTERIOR perspective", this, this, SLOT(orientationAnteriorToolButtonTriggered(bool))); if (this->viewOrientationAnteriorIcon != NULL) { this->orientationAnteriorToolButtonAction->setIcon(*this->viewOrientationAnteriorIcon); } else { this->orientationAnteriorToolButtonAction->setIconText("A"); } this->orientationAnteriorToolButtonAction->setObjectName(objectNamePrefix + "AnteriorView"); macroManager->addMacroSupportToObject(this->orientationAnteriorToolButtonAction, "Select anterior orientation"); this->orientationPosteriorToolButtonAction = WuQtUtilities::createAction("P", "View from a POSTERIOR perspective", this, this, SLOT(orientationPosteriorToolButtonTriggered(bool))); if (this->viewOrientationPosteriorIcon != NULL) { this->orientationPosteriorToolButtonAction->setIcon(*this->viewOrientationPosteriorIcon); } else { this->orientationPosteriorToolButtonAction->setIconText("P"); } this->orientationPosteriorToolButtonAction->setObjectName(objectNamePrefix + "PosteriorView"); macroManager->addMacroSupportToObject(this->orientationPosteriorToolButtonAction, "Select posterior orientation"); this->orientationDorsalToolButtonAction = WuQtUtilities::createAction("D", "View from a DORSAL perspective", this, this, SLOT(orientationDorsalToolButtonTriggered(bool))); if (this->viewOrientationDorsalIcon != NULL) { this->orientationDorsalToolButtonAction->setIcon(*this->viewOrientationDorsalIcon); } else { this->orientationDorsalToolButtonAction->setIconText("D"); } this->orientationDorsalToolButtonAction->setObjectName(objectNamePrefix + "DorsalView"); macroManager->addMacroSupportToObject(this->orientationDorsalToolButtonAction, "Select dorsal orientation"); this->orientationVentralToolButtonAction = WuQtUtilities::createAction("V", "View from a VENTRAL perspective", this, this, SLOT(orientationVentralToolButtonTriggered(bool))); if (this->viewOrientationVentralIcon != NULL) { this->orientationVentralToolButtonAction->setIcon(*this->viewOrientationVentralIcon); } else { this->orientationVentralToolButtonAction->setIconText("V"); } this->orientationVentralToolButtonAction->setObjectName(objectNamePrefix + "VentralView"); macroManager->addMacroSupportToObject(this->orientationVentralToolButtonAction, "Select ventral orientation"); this->orientationLateralMedialToolButtonAction = WuQtUtilities::createAction("LM", "View from a Lateral/Medial perspective", this, this, SLOT(orientationLateralMedialToolButtonTriggered(bool))); this->orientationLateralMedialToolButtonAction->setObjectName(objectNamePrefix + "LateralMedialView"); macroManager->addMacroSupportToObject(this->orientationLateralMedialToolButtonAction, "Select lateral/medial orientation"); this->orientationDorsalVentralToolButtonAction = WuQtUtilities::createAction("DV", "View from a Dorsal/Ventral perspective", this, this, SLOT(orientationDorsalVentralToolButtonTriggered(bool))); this->orientationDorsalVentralToolButtonAction->setObjectName(objectNamePrefix + "DorsalVentralView"); macroManager->addMacroSupportToObject(this->orientationDorsalVentralToolButtonAction, "Select dorsal/ventral orientation"); this->orientationAnteriorPosteriorToolButtonAction = WuQtUtilities::createAction("AP", "View from a Anterior/Posterior perspective", this, this, SLOT(orientationAnteriorPosteriorToolButtonTriggered(bool))); this->orientationAnteriorPosteriorToolButtonAction->setObjectName(objectNamePrefix + "AnteriorPosteriorView"); macroManager->addMacroSupportToObject(this->orientationAnteriorPosteriorToolButtonAction, "Select anterior/posterior orientation"); this->orientationResetToolButtonAction = WuQtUtilities::createAction("R\nE\nS\nE\nT", "Reset the view to dorsal and remove any panning or zooming", this, this, SLOT(orientationResetToolButtonTriggered(bool))); this->orientationResetToolButtonAction->setObjectName(objectNamePrefix + "ResetView"); macroManager->addMacroSupportToObject(this->orientationResetToolButtonAction, "Reset to default orientation"); this->orientationLeftOrLateralToolButton = new QToolButton(); this->orientationLeftOrLateralToolButton->setDefaultAction(this->orientationLeftOrLateralToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationLeftOrLateralToolButton); this->orientationLeftOrLateralToolButtonAction->setParent(this->orientationLeftOrLateralToolButton); this->orientationRightOrMedialToolButton = new QToolButton(); this->orientationRightOrMedialToolButton->setDefaultAction(this->orientationRightOrMedialToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationRightOrMedialToolButton); orientationRightOrMedialToolButtonAction->setParent(orientationRightOrMedialToolButton); this->orientationAnteriorToolButton = new QToolButton(); this->orientationAnteriorToolButton->setDefaultAction(this->orientationAnteriorToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationAnteriorToolButton); this->orientationAnteriorToolButtonAction->setParent(this->orientationAnteriorToolButton); this->orientationPosteriorToolButton = new QToolButton(); this->orientationPosteriorToolButton->setDefaultAction(this->orientationPosteriorToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationPosteriorToolButton); this->orientationPosteriorToolButtonAction->setParent(this->orientationPosteriorToolButton); this->orientationDorsalToolButton = new QToolButton(); this->orientationDorsalToolButton->setDefaultAction(this->orientationDorsalToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationDorsalToolButton); this->orientationDorsalToolButtonAction->setParent(this->orientationDorsalToolButton); this->orientationVentralToolButton = new QToolButton(); this->orientationVentralToolButton->setDefaultAction(this->orientationVentralToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationVentralToolButton); this->orientationVentralToolButtonAction->setParent(this->orientationVentralToolButton); this->orientationLateralMedialToolButton = new QToolButton(); this->orientationLateralMedialToolButton->setDefaultAction(this->orientationLateralMedialToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationLateralMedialToolButton); orientationLateralMedialToolButtonAction->setParent(orientationLateralMedialToolButton); this->orientationDorsalVentralToolButton = new QToolButton(); this->orientationDorsalVentralToolButton->setDefaultAction(this->orientationDorsalVentralToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationDorsalVentralToolButton); orientationDorsalVentralToolButtonAction->setParent(orientationDorsalVentralToolButton); this->orientationAnteriorPosteriorToolButton = new QToolButton(); this->orientationAnteriorPosteriorToolButton->setDefaultAction(this->orientationAnteriorPosteriorToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationAnteriorPosteriorToolButton); orientationAnteriorPosteriorToolButtonAction->setParent(orientationAnteriorPosteriorToolButton); WuQtUtilities::matchWidgetWidths(this->orientationLateralMedialToolButton, this->orientationDorsalVentralToolButton, this->orientationAnteriorPosteriorToolButton); QToolButton* orientationResetToolButton = new QToolButton(); orientationResetToolButton->setDefaultAction(this->orientationResetToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(orientationResetToolButton); this->orientationCustomViewSelectToolButton = new QToolButton(); this->orientationCustomViewSelectToolButton->setDefaultAction(this->customViewAction); this->orientationCustomViewSelectToolButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); WuQtUtilities::setToolButtonStyleForQt5Mac(this->orientationCustomViewSelectToolButton); QGridLayout* buttonGridLayout = new QGridLayout(); buttonGridLayout->setColumnStretch(3, 100); WuQtUtilities::setLayoutSpacingAndMargins(buttonGridLayout, 0, 0); buttonGridLayout->addWidget(this->orientationLeftOrLateralToolButton, 0, 0); buttonGridLayout->addWidget(this->orientationRightOrMedialToolButton, 0, 1); buttonGridLayout->addWidget(this->orientationDorsalToolButton, 1, 0); buttonGridLayout->addWidget(this->orientationVentralToolButton, 1, 1); buttonGridLayout->addWidget(this->orientationAnteriorToolButton, 2, 0); buttonGridLayout->addWidget(this->orientationPosteriorToolButton, 2, 1); buttonGridLayout->addWidget(this->orientationLateralMedialToolButton, 0, 2); buttonGridLayout->addWidget(this->orientationDorsalVentralToolButton, 1, 2); buttonGridLayout->addWidget(this->orientationAnteriorPosteriorToolButton, 2, 2); buttonGridLayout->addWidget(this->orientationCustomViewSelectToolButton, 3, 0, 1, 5, Qt::AlignHCenter); buttonGridLayout->addWidget(orientationResetToolButton, 0, 4, 3, 1); QWidget* w = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(w); WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 0); layout->addLayout(buttonGridLayout); this->orientationWidgetGroup = new WuQWidgetObjectGroup(this); this->orientationWidgetGroup->add(this->orientationLeftOrLateralToolButtonAction); this->orientationWidgetGroup->add(this->orientationRightOrMedialToolButtonAction); this->orientationWidgetGroup->add(this->orientationAnteriorToolButtonAction); this->orientationWidgetGroup->add(this->orientationPosteriorToolButtonAction); this->orientationWidgetGroup->add(this->orientationDorsalToolButtonAction); this->orientationWidgetGroup->add(this->orientationVentralToolButtonAction); this->orientationWidgetGroup->add(this->orientationResetToolButtonAction); QWidget* orientWidget = this->createToolWidget("Orientation", w, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_TOP, 0); orientWidget->setVisible(false); return orientWidget; } /** * Update the orientation widget. * * @param browserTabContent * Content of browser tab. */ void BrainBrowserWindowToolBar::updateOrientationWidget(BrowserTabContent* browserTabContent) { if (this->orientationWidget->isHidden()) { return; } const int32_t tabIndex = browserTabContent->getTabNumber(); this->orientationWidgetGroup->blockAllSignals(true); const Model* mdc = this->getDisplayedModel(); if (mdc != NULL) { const ModelSurface* mdcs = dynamic_cast(mdc); const ModelSurfaceMontage* mdcsm = dynamic_cast(mdc); const ModelVolume* mdcv = dynamic_cast(mdc); const ModelWholeBrain* mdcwb = dynamic_cast(mdc); bool rightFlag = false; bool leftFlag = false; bool leftRightFlag = false; bool enableDualViewOrientationButtons = false; bool showDualViewOrientationButtons = false; bool showSingleViewOrientationButtons = false; if (mdcs != NULL) { const Surface* surface = mdcs->getSurface(); const StructureEnum::Enum structure = surface->getStructure(); if (StructureEnum::isLeft(structure)) { leftFlag = true; } else if (StructureEnum::isRight(structure)) { rightFlag = true; } else { leftRightFlag = true; } showSingleViewOrientationButtons = true; } else if (mdcsm != NULL) { AString latMedLeftRightText = "LM"; AString latMedLeftRightToolTipText = "View from a Lateral/Medial perspective"; switch (mdcsm->getSelectedConfigurationType(tabIndex)) { case SurfaceMontageConfigurationTypeEnum::CEREBELLAR_CORTEX_CONFIGURATION: latMedLeftRightText = "LR"; latMedLeftRightToolTipText = "View from a Right/Left Perspective"; enableDualViewOrientationButtons = true; break; case SurfaceMontageConfigurationTypeEnum::CEREBRAL_CORTEX_CONFIGURATION: enableDualViewOrientationButtons = true; break; case SurfaceMontageConfigurationTypeEnum::FLAT_CONFIGURATION: break; } this->orientationLateralMedialToolButtonAction->setText(latMedLeftRightText); WuQtUtilities::setToolTipAndStatusTip(this->orientationLateralMedialToolButtonAction, latMedLeftRightToolTipText); showDualViewOrientationButtons = true; } else if (mdcv != NULL) { /* nothing */ } else if (mdcwb != NULL) { leftRightFlag = true; showSingleViewOrientationButtons = true; } else { CaretAssertMessage(0, "Unknown model display controller type"); } if (rightFlag || leftFlag) { if (rightFlag) { if (this->viewOrientationRightLateralIcon != NULL) { this->orientationLeftOrLateralToolButtonAction->setIcon(*this->viewOrientationRightLateralIcon); } else { this->orientationLeftOrLateralToolButtonAction->setIconText("L"); } if (this->viewOrientationRightMedialIcon != NULL) { this->orientationRightOrMedialToolButtonAction->setIcon(*this->viewOrientationRightMedialIcon); } else { this->orientationRightOrMedialToolButtonAction->setIconText("M"); } } else if (leftFlag) { if (this->viewOrientationLeftLateralIcon != NULL) { this->orientationLeftOrLateralToolButtonAction->setIcon(*this->viewOrientationLeftLateralIcon); } else { this->orientationLeftOrLateralToolButtonAction->setIconText("L"); } if (this->viewOrientationLeftMedialIcon != NULL) { this->orientationRightOrMedialToolButtonAction->setIcon(*this->viewOrientationLeftMedialIcon); } else { this->orientationRightOrMedialToolButtonAction->setIconText("M"); } } WuQtUtilities::setToolTipAndStatusTip(this->orientationLeftOrLateralToolButtonAction, "View from a LATERAL perspective"); WuQtUtilities::setToolTipAndStatusTip(this->orientationRightOrMedialToolButtonAction, "View from a MEDIAL perspective"); } else if (leftRightFlag) { if (this->viewOrientationLeftIcon != NULL) { this->orientationLeftOrLateralToolButtonAction->setIcon(*this->viewOrientationLeftIcon); } else { this->orientationLeftOrLateralToolButtonAction->setIconText("L"); } if (this->viewOrientationRightIcon != NULL) { this->orientationRightOrMedialToolButtonAction->setIcon(*this->viewOrientationRightIcon); } else { this->orientationRightOrMedialToolButtonAction->setIconText("R"); } WuQtUtilities::setToolTipAndStatusTip(this->orientationLeftOrLateralToolButtonAction, "View from a LEFT perspective"); WuQtUtilities::setToolTipAndStatusTip(this->orientationRightOrMedialToolButtonAction, "View from a RIGHT perspective"); } /* * The dual view buttons are not need for a flat map montage. * However, if they are hidden, their space is not reallocated and the * Reset button remains on the right and it looks weird. So, * display them but disable them when a flat map montage. */ this->orientationLateralMedialToolButton->setVisible(showDualViewOrientationButtons); this->orientationDorsalVentralToolButton->setVisible(showDualViewOrientationButtons); this->orientationAnteriorPosteriorToolButton->setVisible(showDualViewOrientationButtons); this->orientationLateralMedialToolButton->setEnabled(enableDualViewOrientationButtons); this->orientationDorsalVentralToolButton->setEnabled(enableDualViewOrientationButtons); this->orientationAnteriorPosteriorToolButton->setEnabled(enableDualViewOrientationButtons); this->orientationLeftOrLateralToolButton->setVisible(showSingleViewOrientationButtons); this->orientationRightOrMedialToolButton->setVisible(showSingleViewOrientationButtons); this->orientationDorsalToolButton->setVisible(showSingleViewOrientationButtons); this->orientationVentralToolButton->setVisible(showSingleViewOrientationButtons); this->orientationAnteriorToolButton->setVisible(showSingleViewOrientationButtons); this->orientationPosteriorToolButton->setVisible(showSingleViewOrientationButtons); } this->orientationWidgetGroup->blockAllSignals(false); } /** * Create the whole brain surface options widget. * * @return The whole brain surface options widget. */ QWidget* BrainBrowserWindowToolBar::createWholeBrainSurfaceOptionsWidget() { WuQMacroManager* macroManager = WuQMacroManager::instance(); const QString objectNamePrefix(m_objectNamePrefix + ":All:"); this->wholeBrainSurfaceTypeComboBox = WuQFactory::newComboBox(); WuQtUtilities::setToolTipAndStatusTip(this->wholeBrainSurfaceTypeComboBox, "Select the geometric type of surface for display"); QObject::connect(this->wholeBrainSurfaceTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(wholeBrainSurfaceTypeComboBoxIndexChanged(int))); this->wholeBrainSurfaceTypeComboBox->setObjectName(objectNamePrefix + "SurfaceType"); macroManager->addMacroSupportToObject(this->wholeBrainSurfaceTypeComboBox, "Select all view surface type"); /* * Left */ this->wholeBrainSurfaceLeftCheckBox = new QCheckBox(" "); WuQtUtilities::setToolTipAndStatusTip(this->wholeBrainSurfaceLeftCheckBox, "Enable/Disable display of the left cortical surface"); QObject::connect(this->wholeBrainSurfaceLeftCheckBox, SIGNAL(stateChanged(int)), this, SLOT(wholeBrainSurfaceLeftCheckBoxStateChanged(int))); this->wholeBrainSurfaceLeftCheckBox->setObjectName(objectNamePrefix + "EnableLeft"); macroManager->addMacroSupportToObject(this->wholeBrainSurfaceLeftCheckBox, "Enable all view left surface"); QToolButton* wholeBrainLeftSurfaceToolButton = new QToolButton(); QAction* leftSurfaceAction = WuQtUtilities::createAction("Left", "Select the whole brain left surface", wholeBrainLeftSurfaceToolButton, this, SLOT(wholeBrainSurfaceLeftToolButtonTriggered(bool))); WuQtUtilities::setToolButtonStyleForQt5Mac(wholeBrainLeftSurfaceToolButton); wholeBrainLeftSurfaceToolButton->setDefaultAction(leftSurfaceAction); // leftSurfaceAction->setObjectName(objectNamePrefix // + "SelectLeft"); // macroManager->addMacroSupportToObject(leftSurfaceAction, // "Select all view left surface"); /* * Left menu is displayed when tool button is clicked */ this->wholeBrainSurfaceLeftMenu = new QMenu(wholeBrainLeftSurfaceToolButton); QObject::connect(this->wholeBrainSurfaceLeftMenu, &QMenu::triggered, this, &BrainBrowserWindowToolBar::wholeBrainSurfaceLeftMenuTriggered); this->wholeBrainSurfaceLeftMenu->setObjectName(objectNamePrefix + "SelectLeftSurfaceMenu"); this->wholeBrainSurfaceLeftMenu->setToolTip("Select all view left surface"); macroManager->addMacroSupportToObject(this->wholeBrainSurfaceLeftMenu, "Select all view left surface"); /* * Right */ this->wholeBrainSurfaceRightCheckBox = new QCheckBox(" "); WuQtUtilities::setToolTipAndStatusTip(this->wholeBrainSurfaceRightCheckBox, "Enable/Disable display of the right cortical surface"); QObject::connect(this->wholeBrainSurfaceRightCheckBox, SIGNAL(stateChanged(int)), this, SLOT(wholeBrainSurfaceRightCheckBoxStateChanged(int))); this->wholeBrainSurfaceRightCheckBox->setObjectName(objectNamePrefix + "EnableRight"); macroManager->addMacroSupportToObject(this->wholeBrainSurfaceRightCheckBox, "Enable all view right surface"); QToolButton* wholeBrainRightSurfaceToolButton = new QToolButton(); QAction* rightSurfaceAction = WuQtUtilities::createAction("Right", "Select the whole brain right surface", wholeBrainRightSurfaceToolButton, this, SLOT(wholeBrainSurfaceRightToolButtonTriggered(bool))); WuQtUtilities::setToolButtonStyleForQt5Mac(wholeBrainRightSurfaceToolButton); wholeBrainRightSurfaceToolButton->setDefaultAction(rightSurfaceAction); // rightSurfaceAction->setObjectName(objectNamePrefix // + "SelectRight"); // macroManager->addMacroSupportToObject(rightSurfaceAction, // "Select all view right surface"); /* * Right menu is displayed when tool button is clicked */ this->wholeBrainSurfaceRightMenu = new QMenu(wholeBrainRightSurfaceToolButton); QObject::connect(this->wholeBrainSurfaceRightMenu, &QMenu::triggered, this, &BrainBrowserWindowToolBar::wholeBrainSurfaceRightMenuTriggered); this->wholeBrainSurfaceRightMenu->setObjectName(objectNamePrefix + "SelectRightSurfaceMenu"); this->wholeBrainSurfaceRightMenu->setToolTip("Select all view right surface"); macroManager->addMacroSupportToObject(this->wholeBrainSurfaceRightMenu, "Select all view right surface"); /* * Cerebellum */ this->wholeBrainSurfaceCerebellumCheckBox = new QCheckBox(" "); WuQtUtilities::setToolTipAndStatusTip(this->wholeBrainSurfaceCerebellumCheckBox, "Enable/Disable display of the cerebellum surface"); QObject::connect(this->wholeBrainSurfaceCerebellumCheckBox, SIGNAL(stateChanged(int)), this, SLOT(wholeBrainSurfaceCerebellumCheckBoxStateChanged(int))); this->wholeBrainSurfaceCerebellumCheckBox->setObjectName(objectNamePrefix + "EnableCerebellum"); macroManager->addMacroSupportToObject(this->wholeBrainSurfaceCerebellumCheckBox, "Enable all view cerebellum"); QToolButton* wholeBrainCerebellumSurfaceToolButton = new QToolButton(); QAction* cerebellumSurfaceAction = WuQtUtilities::createAction("Cerebellum", "Select the whole brain cerebellum surface", wholeBrainCerebellumSurfaceToolButton, this, SLOT(wholeBrainSurfaceCerebellumToolButtonTriggered(bool))); WuQtUtilities::setToolButtonStyleForQt5Mac(wholeBrainCerebellumSurfaceToolButton); wholeBrainCerebellumSurfaceToolButton->setDefaultAction(cerebellumSurfaceAction); // cerebellumSurfaceAction->setObjectName(objectNamePrefix // + "SurfaceCerebellum"); // macroManager->addMacroSupportToObject(cerebellumSurfaceAction, // "Select all view cerebellum surface"); /* * Cerebellum menu is displayed when tool button is clicked */ this->wholeBrainSurfaceCerebellumMenu = new QMenu(wholeBrainCerebellumSurfaceToolButton); QObject::connect(this->wholeBrainSurfaceCerebellumMenu, &QMenu::triggered, this, &BrainBrowserWindowToolBar::wholeBrainSurfaceCerebellumMenuTriggered); this->wholeBrainSurfaceCerebellumMenu->setObjectName(objectNamePrefix + "SelectCerebellumSurfaceMenu"); this->wholeBrainSurfaceCerebellumMenu->setToolTip("Select all view cerebellum surface"); macroManager->addMacroSupportToObject(this->wholeBrainSurfaceCerebellumMenu, "Select all view cerebellum surface"); /* * Left/Right separation */ const int separationSpinngerWidth = 48; this->wholeBrainSurfaceSeparationLeftRightSpinBox = WuQFactory::newDoubleSpinBox(); this->wholeBrainSurfaceSeparationLeftRightSpinBox->setDecimals(0); this->wholeBrainSurfaceSeparationLeftRightSpinBox->setFixedWidth(separationSpinngerWidth); this->wholeBrainSurfaceSeparationLeftRightSpinBox->setMinimum(-100000.0); this->wholeBrainSurfaceSeparationLeftRightSpinBox->setMaximum(100000.0); WuQtUtilities::setToolTipAndStatusTip(this->wholeBrainSurfaceSeparationLeftRightSpinBox, "Adjust the separation of the left and right cortical surfaces"); QObject::connect(this->wholeBrainSurfaceSeparationLeftRightSpinBox, SIGNAL(valueChanged(double)), this, SLOT(wholeBrainSurfaceSeparationLeftRightSpinBoxValueChanged(double))); this->wholeBrainSurfaceSeparationLeftRightSpinBox->setObjectName(objectNamePrefix + "LeftRightSeparation"); macroManager->addMacroSupportToObject(this->wholeBrainSurfaceSeparationLeftRightSpinBox, "Set all view left/right separation"); /* * Cerebellum separation */ this->wholeBrainSurfaceSeparationCerebellumSpinBox = WuQFactory::newDoubleSpinBox(); this->wholeBrainSurfaceSeparationCerebellumSpinBox->setDecimals(0); this->wholeBrainSurfaceSeparationCerebellumSpinBox->setFixedWidth(separationSpinngerWidth); this->wholeBrainSurfaceSeparationCerebellumSpinBox->setMinimum(-100000.0); this->wholeBrainSurfaceSeparationCerebellumSpinBox->setMaximum(100000.0); WuQtUtilities::setToolTipAndStatusTip(this->wholeBrainSurfaceSeparationCerebellumSpinBox, "Adjust the separation of the cerebellum from the left and right cortical surfaces"); QObject::connect(this->wholeBrainSurfaceSeparationCerebellumSpinBox, SIGNAL(valueChanged(double)), this, SLOT(wholeBrainSurfaceSeparationCerebellumSpinBoxSelected(double))); this->wholeBrainSurfaceSeparationCerebellumSpinBox->setObjectName(objectNamePrefix + "CortexCerebellumSeparation"); macroManager->addMacroSupportToObject(this->wholeBrainSurfaceSeparationCerebellumSpinBox, "Set all view cerebral/cerebellum separation"); this->wholeBrainSurfaceMatchCheckBox = new QCheckBox("Match"); WuQtUtilities::setToolTipAndStatusTip(this->wholeBrainSurfaceMatchCheckBox, "Match position and size of all surfaces to primary anatomical. Useful for " "animation (surface interpolation) and recording movies."); QObject::connect(this->wholeBrainSurfaceMatchCheckBox, &QCheckBox::clicked, this, &BrainBrowserWindowToolBar::wholeBrainSurfaceMatchCheckBoxClicked); this->wholeBrainSurfaceMatchCheckBox->setObjectName(objectNamePrefix + "MatchSurface"); macroManager->addMacroSupportToObject(this->wholeBrainSurfaceMatchCheckBox, "Match position and size of all surfaces to primary anatomical"); wholeBrainLeftSurfaceToolButton->setText("L"); wholeBrainRightSurfaceToolButton->setText("R"); wholeBrainCerebellumSurfaceToolButton->setText("C"); QGridLayout* gridLayout = new QGridLayout(); gridLayout->setVerticalSpacing(2); gridLayout->setHorizontalSpacing(2); gridLayout->addWidget(this->wholeBrainSurfaceTypeComboBox, 0, 0, 1, 6); gridLayout->addWidget(this->wholeBrainSurfaceLeftCheckBox, 1, 0); gridLayout->addWidget(wholeBrainLeftSurfaceToolButton, 1, 1); gridLayout->addWidget(this->wholeBrainSurfaceRightCheckBox, 2, 0); gridLayout->addWidget(wholeBrainRightSurfaceToolButton, 2, 1); gridLayout->addWidget(this->wholeBrainSurfaceCerebellumCheckBox, 3, 0); gridLayout->addWidget(wholeBrainCerebellumSurfaceToolButton, 3, 1); gridLayout->addWidget(this->wholeBrainSurfaceSeparationLeftRightSpinBox, 1, 2, 2, 1); gridLayout->addWidget(this->wholeBrainSurfaceSeparationCerebellumSpinBox, 3, 2); gridLayout->addWidget(this->wholeBrainSurfaceMatchCheckBox, 4, 0, 1, 6); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 0); layout->addLayout(gridLayout); this->wholeBrainSurfaceOptionsWidgetGroup = new WuQWidgetObjectGroup(this); this->wholeBrainSurfaceOptionsWidgetGroup->add(this->wholeBrainSurfaceTypeComboBox); this->wholeBrainSurfaceOptionsWidgetGroup->add(this->wholeBrainSurfaceLeftCheckBox); this->wholeBrainSurfaceOptionsWidgetGroup->add(wholeBrainLeftSurfaceToolButton); this->wholeBrainSurfaceOptionsWidgetGroup->add(this->wholeBrainSurfaceRightCheckBox); this->wholeBrainSurfaceOptionsWidgetGroup->add(wholeBrainRightSurfaceToolButton); this->wholeBrainSurfaceOptionsWidgetGroup->add(this->wholeBrainSurfaceCerebellumCheckBox); this->wholeBrainSurfaceOptionsWidgetGroup->add(wholeBrainCerebellumSurfaceToolButton); this->wholeBrainSurfaceOptionsWidgetGroup->add(this->wholeBrainSurfaceSeparationLeftRightSpinBox); this->wholeBrainSurfaceOptionsWidgetGroup->add(this->wholeBrainSurfaceSeparationCerebellumSpinBox); this->wholeBrainSurfaceOptionsWidgetGroup->add(this->wholeBrainSurfaceMatchCheckBox); QWidget* w = this->createToolWidget("Surface Viewing", widget, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_TOP, 0); w->setVisible(false); return w; } /** * Update the whole brain surface options widget. * * @param browserTabContent * Content of browser tab. */ void BrainBrowserWindowToolBar::updateWholeBrainSurfaceOptionsWidget(BrowserTabContent* browserTabContent) { if (this->wholeBrainSurfaceOptionsWidget->isHidden()) { return; } ModelWholeBrain* wholeBrainModel = browserTabContent->getDisplayedWholeBrainModel(); if (wholeBrainModel != NULL) { const int32_t tabNumber = browserTabContent->getTabNumber(); this->wholeBrainSurfaceOptionsWidgetGroup->blockAllSignals(true); std::vector availableSurfaceTypes; wholeBrainModel->getAvailableSurfaceTypes(availableSurfaceTypes); const SurfaceTypeEnum::Enum selectedSurfaceType = wholeBrainModel->getSelectedSurfaceType(tabNumber); int32_t defaultIndex = 0; this->wholeBrainSurfaceTypeComboBox->clear(); int32_t numSurfaceTypes = static_cast(availableSurfaceTypes.size()); for (int32_t i = 0; i < numSurfaceTypes; i++) { const SurfaceTypeEnum::Enum st = availableSurfaceTypes[i]; if (st == selectedSurfaceType) { defaultIndex = this->wholeBrainSurfaceTypeComboBox->count(); } const AString name = SurfaceTypeEnum::toGuiName(st); const int integerCode = SurfaceTypeEnum::toIntegerCode(st); this->wholeBrainSurfaceTypeComboBox->addItem(name, integerCode); } if (defaultIndex < this->wholeBrainSurfaceTypeComboBox->count()) { this->wholeBrainSurfaceTypeComboBox->setCurrentIndex(defaultIndex); } this->wholeBrainSurfaceLeftCheckBox->setChecked(browserTabContent->isWholeBrainLeftEnabled()); this->wholeBrainSurfaceRightCheckBox->setChecked(browserTabContent->isWholeBrainRightEnabled()); this->wholeBrainSurfaceCerebellumCheckBox->setChecked(browserTabContent->isWholeBrainCerebellumEnabled()); updateAllWholeBrainSurfaceMenus(); this->wholeBrainSurfaceSeparationLeftRightSpinBox->setValue(browserTabContent->getWholeBrainLeftRightSeparation()); this->wholeBrainSurfaceSeparationCerebellumSpinBox->setValue(browserTabContent->getWholeBrainCerebellumSeparation()); this->wholeBrainSurfaceMatchCheckBox->setChecked(wholeBrainModel->getBrain()->isSurfaceMatchingToAnatomical()); this->wholeBrainSurfaceOptionsWidgetGroup->blockAllSignals(false); } } /** * Create the volume indices widget. * * @return The volume indices widget. */ QWidget* BrainBrowserWindowToolBar::createVolumeIndicesWidget() { m_sliceSelectionComponent = new BrainBrowserWindowToolBarSliceSelection(this, m_objectNamePrefix); QWidget* w = this->createToolWidget("Slice Indices/Coords", m_sliceSelectionComponent, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_TOP, 0); w->setVisible(false); return w; } /** * Update the volume indices widget. * * @param browserTabContent * Content of browser tab. */ void BrainBrowserWindowToolBar::updateVolumeIndicesWidget(BrowserTabContent* browserTabContent) { if (this->volumeIndicesWidget->isHidden()) { return; } m_sliceSelectionComponent->updateContent(browserTabContent); } /** * Create the mode widget. * * @return The mode widget. */ QWidget* BrainBrowserWindowToolBar::createModeWidget() { /* * Annotations */ this->modeInputModeAnnotationsAction = WuQtUtilities::createAction("Annotate", "Perform annotate operations with mouse", this); this->modeInputModeAnnotationsAction->setCheckable(true); QToolButton* inputModeAnnotationsToolButton = new QToolButton(); inputModeAnnotationsToolButton->setDefaultAction(this->modeInputModeAnnotationsAction); WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeAnnotationsToolButton); this->modeInputModeAnnotationsAction->setObjectName(m_objectNamePrefix + ":Mode:Annotate"); /* * Borders */ this->modeInputModeBordersAction = WuQtUtilities::createAction("Border", "Perform border operations with mouse", this); this->modeInputModeBordersAction->setCheckable(true); QToolButton* inputModeBordersToolButton = new QToolButton(); inputModeBordersToolButton->setDefaultAction(this->modeInputModeBordersAction); WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeBordersToolButton); this->modeInputModeBordersAction->setObjectName(m_objectNamePrefix + ":Mode:Border"); /* * Foci */ this->modeInputModeFociAction = WuQtUtilities::createAction("Foci", "Perform foci operations with mouse", this); this->modeInputModeFociAction->setCheckable(true); QToolButton* inputModeFociToolButton = new QToolButton(); inputModeFociToolButton->setDefaultAction(this->modeInputModeFociAction); WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeFociToolButton); this->modeInputModeFociAction->setObjectName(m_objectNamePrefix + ":Mode:Foci"); /* * Image */ const bool showImageButtonFlag = false; this->modeInputModeImageAction = NULL; QToolButton* inputModeImageToolButton = NULL; if (showImageButtonFlag) { modeInputModeImageAction = WuQtUtilities::createAction("Image", "Edit Image Control Points", this); this->modeInputModeImageAction->setCheckable(true); inputModeImageToolButton = new QToolButton(); inputModeImageToolButton->setDefaultAction(this->modeInputModeImageAction); WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeImageToolButton); this->modeInputModeImageAction->setObjectName(m_objectNamePrefix + ":Mode:Image"); } /* * Volume Edit */ this->modeInputVolumeEditAction = WuQtUtilities::createAction("Volume", "Edit volume voxels", this); this->modeInputVolumeEditAction->setCheckable(true); QToolButton* inputModeVolumeEditButton = new QToolButton(); inputModeVolumeEditButton->setDefaultAction(this->modeInputVolumeEditAction); WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeVolumeEditButton); this->modeInputVolumeEditAction->setObjectName(m_objectNamePrefix + ":Mode:Volume"); /* * View Mode */ this->modeInputModeViewAction = WuQtUtilities::createAction("View", "Perform viewing operations with mouse\n" "\n" "Identify: Click left mouse button (might cause rotation)\n" #ifdef CARET_OS_MACOSX "Identify: Click left mouse button while keyboard shift and apple keys are down (prevents rotation)\n" #else // CARET_OS_MACOSX "Identify: Click left mouse button while keyboard shift and controls keys are down (prevents rotation)\n" #endif // CARET_OS_MACOSX "Pan: Move mouse with left mouse button down and keyboard shift key down\n" "Rotate: Move mouse with left mouse button down\n" #ifdef CARET_OS_MACOSX "Zoom: Move mouse with left mouse button down and keyboard apple key down", #else // CARET_OS_MACOSX "Zoom: Move mouse with left mouse button down and keyboard control key down", #endif // CARET_OS_MACOSX this); this->modeInputModeViewAction->setCheckable(true); QToolButton* inputModeViewToolButton = new QToolButton(); inputModeViewToolButton->setDefaultAction(this->modeInputModeViewAction); WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeViewToolButton); this->modeInputModeViewAction->setObjectName(m_objectNamePrefix + ":Mode:View"); WuQtUtilities::matchWidgetWidths(inputModeAnnotationsToolButton, inputModeBordersToolButton, inputModeViewToolButton, inputModeVolumeEditButton); inputModeFociToolButton->setSizePolicy(QSizePolicy::Preferred, inputModeFociToolButton->sizePolicy().verticalPolicy()); if (inputModeImageToolButton != NULL) { inputModeImageToolButton->setSizePolicy(QSizePolicy::Preferred, inputModeImageToolButton->sizePolicy().verticalPolicy()); } /* * Layout for input modes */ QWidget* inputModeWidget = new QWidget(); QGridLayout* inputModeLayout = new QGridLayout(inputModeWidget); int modeRow = 0; WuQtUtilities::setLayoutSpacingAndMargins(inputModeLayout, 2, 2); inputModeLayout->addWidget(inputModeAnnotationsToolButton, modeRow, 0, 1, 2, Qt::AlignHCenter); modeRow++; inputModeLayout->addWidget(inputModeBordersToolButton, modeRow, 0, 1, 2, Qt::AlignHCenter); modeRow++; if (inputModeImageToolButton != NULL) { inputModeLayout->addWidget(inputModeFociToolButton, modeRow, 0); inputModeLayout->addWidget(inputModeImageToolButton, modeRow, 1); } else { inputModeLayout->addWidget(inputModeFociToolButton, modeRow, 0, 1, 2, Qt::AlignHCenter); } modeRow++; inputModeLayout->addWidget(inputModeViewToolButton, modeRow, 0, 1, 2, Qt::AlignHCenter); modeRow++; inputModeLayout->addWidget(inputModeVolumeEditButton, modeRow, 0, 1, 2, Qt::AlignHCenter); modeRow++; this->modeInputModeActionGroup = new QActionGroup(this); this->modeInputModeActionGroup->addAction(this->modeInputModeAnnotationsAction); this->modeInputModeActionGroup->addAction(this->modeInputModeBordersAction); this->modeInputModeActionGroup->addAction(this->modeInputModeFociAction); if (this->modeInputModeImageAction != NULL) { this->modeInputModeActionGroup->addAction(this->modeInputModeImageAction); } this->modeInputModeActionGroup->addAction(this->modeInputModeViewAction); this->modeInputModeActionGroup->addAction(this->modeInputVolumeEditAction); QObject::connect(this->modeInputModeActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(modeInputModeActionTriggered(QAction*))); this->modeInputModeActionGroup->setExclusive(true); WuQMacroManager::instance()->addMacroSupportToObject(this->modeInputModeAnnotationsAction, "Select annotate mode"); WuQMacroManager::instance()->addMacroSupportToObject(this->modeInputModeBordersAction, "Select border mode"); WuQMacroManager::instance()->addMacroSupportToObject(this->modeInputModeFociAction, "Select foci mode"); if (modeInputModeImageAction != NULL) { WuQMacroManager::instance()->addMacroSupportToObject(this->modeInputModeImageAction, "Select image mode"); } WuQMacroManager::instance()->addMacroSupportToObject(this->modeInputModeViewAction, "Select view mode"); WuQMacroManager::instance()->addMacroSupportToObject(this->modeInputVolumeEditAction, "Select volume mode"); // this->modeInputModeActionGroup->setObjectName(m_objectNamePrefix // + ":Mode_Action_Group"); // WuQMacroManager::instance()->addMacroSupportToObject(this->modeInputModeActionGroup, // "Selects Mode for Mouse Operations"); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 0); layout->addWidget(inputModeWidget, 0, Qt::AlignHCenter); layout->addStretch(); this->modeWidgetGroup = new WuQWidgetObjectGroup(this); this->modeWidgetGroup->add(this->modeInputModeActionGroup); QWidget* w = this->createToolWidget("Mode", widget, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_NONE, 0); return w; } /** * Called when a tools input mode button is clicked. * @param action * Action of tool button that was clicked. */ void BrainBrowserWindowToolBar::modeInputModeActionTriggered(QAction* action) { BrowserTabContent* tabContent = this->getTabContentFromSelectedTab(); if (tabContent == NULL) { return; } EventGetOrSetUserInputModeProcessor getInputModeEvent(this->browserWindowIndex); EventManager::get()->sendEvent(getInputModeEvent.getPointer()); const UserInputModeEnum::Enum currentMode = getInputModeEvent.getUserInputMode(); UserInputModeEnum::Enum inputMode = UserInputModeEnum::INVALID; if (action == this->modeInputModeAnnotationsAction) { if (currentMode != UserInputModeEnum::ANNOTATIONS) { BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(browserWindowIndex); CaretAssert(bbw); if ( ! bbw->changeInputModeToAnnotationsWarningDialog()) { /* * Since mode is rejected, need to update toolbar */ updateModeWidget(getTabContentFromSelectedTab()); return; } } inputMode = UserInputModeEnum::ANNOTATIONS; } else if (action == this->modeInputModeBordersAction) { inputMode = UserInputModeEnum::BORDERS; /* * If borders are not displayed, display them */ DisplayPropertiesBorders* dpb = GuiManager::get()->getBrain()->getDisplayPropertiesBorders(); const int32_t browserTabIndex = tabContent->getTabNumber(); const DisplayGroupEnum::Enum displayGroup = dpb->getDisplayGroupForTab(browserTabIndex); if (dpb->isDisplayed(displayGroup, browserTabIndex) == false) { dpb->setDisplayed(displayGroup, browserTabIndex, true); this->updateUserInterface(); this->updateGraphicsWindow(); } } else if (action == this->modeInputModeFociAction) { inputMode = UserInputModeEnum::FOCI; } else if ((action == this->modeInputModeImageAction) && (this->modeInputModeImageAction != NULL)) { inputMode = UserInputModeEnum::IMAGE; } else if (action == this->modeInputVolumeEditAction) { inputMode = UserInputModeEnum::VOLUME_EDIT; } else if (action == this->modeInputModeViewAction) { inputMode = UserInputModeEnum::VIEW; } else { CaretAssertMessage(0, "Tools input mode action is invalid, new action added???"); } EventManager::get()->sendEvent(EventGetOrSetUserInputModeProcessor(this->browserWindowIndex, inputMode).getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); this->updateModeWidget(tabContent); this->updateDisplayedModeUserInputWidget(); } /** * Update the tools widget. * * @param browserTabContent * Content of browser tab. */ void BrainBrowserWindowToolBar::updateModeWidget(BrowserTabContent* /*browserTabContent*/) { if (this->modeWidget->isHidden()) { return; } this->modeWidgetGroup->blockAllSignals(true); EventGetOrSetUserInputModeProcessor getInputModeEvent(this->browserWindowIndex); EventManager::get()->sendEvent(getInputModeEvent.getPointer()); switch (getInputModeEvent.getUserInputMode()) { case UserInputModeEnum::INVALID: /* may get here when program is exiting and widgets are being destroyed */ break; case UserInputModeEnum::ANNOTATIONS: this->modeInputModeAnnotationsAction->setChecked(true); break; case UserInputModeEnum::BORDERS: this->modeInputModeBordersAction->setChecked(true); break; case UserInputModeEnum::FOCI: this->modeInputModeFociAction->setChecked(true); break; case UserInputModeEnum::IMAGE: if (this->modeInputModeImageAction != NULL) { this->modeInputModeImageAction->setChecked(true); } break; case UserInputModeEnum::VOLUME_EDIT: this->modeInputVolumeEditAction->setChecked(true); break; case UserInputModeEnum::VIEW: this->modeInputModeViewAction->setChecked(true); break; } this->modeWidgetGroup->blockAllSignals(false); this->updateDisplayedModeUserInputWidget(); } void BrainBrowserWindowToolBar::updateDisplayedModeUserInputWidget() { EventGetOrSetUserInputModeProcessor getInputModeEvent(this->browserWindowIndex); EventManager::get()->sendEvent(getInputModeEvent.getPointer()); UserInputModeAbstract* userInputProcessor = getInputModeEvent.getUserInputProcessor(); QWidget* userInputWidget = userInputProcessor->getWidgetForToolBar(); /* * If a widget is display and needs to change, * remove the old widget. */ if (this->userInputControlsWidgetActiveInputWidget != NULL) { if (userInputWidget != this->userInputControlsWidgetActiveInputWidget) { /* * Remove the current input widget: * (1) Set its visibility to false * (2) Remove the widget from the toolbar's layout * (3) Set its parent to NULL. * * Why is the parent set to NULL? * * When a widget is put into a layout, the widget is put into * a QWidgetItem (subclass of QLayoutItem). * * QLayout::removeWidget() will delete the QWidgetItem but * it does not reset the parent for the widget that was in * QWidgetItem. So the user will need to delete the widget * unless it is placed into a layout. * * After removing the widget, set the widget's parent to NULL. * As a result, when the input receiver (owner of the widget) * is deleted, it can examine the parent, and, if the parent * is NULL, it can delete the widget preventing a memory link * and a possible crash. */ this->userInputControlsWidgetActiveInputWidget->setVisible(false); this->userInputControlsWidgetLayout->removeWidget(this->userInputControlsWidgetActiveInputWidget); this->userInputControlsWidgetActiveInputWidget->setParent(NULL); this->userInputControlsWidgetActiveInputWidget = NULL; } } if (this->userInputControlsWidgetActiveInputWidget == NULL) { if (userInputWidget != NULL) { this->userInputControlsWidgetActiveInputWidget = userInputWidget; this->userInputControlsWidgetActiveInputWidget->setVisible(true); this->userInputControlsWidgetLayout->addWidget(this->userInputControlsWidgetActiveInputWidget); this->userInputControlsWidget->setVisible(true); this->userInputControlsWidgetLayout->update(); } else { this->userInputControlsWidget->setVisible(false); } } if (userInputProcessor->getUserInputMode() != UserInputModeEnum::ANNOTATIONS) { /* * Delete all selected annotations and update graphics and UI. */ AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); annotationManager->deselectAllAnnotationsForEditing(this->browserWindowIndex); } } /** * Create the tab options widget. * * @param lockWindowAndAllTabAspectAction * Action for locking the window's aspect ratio and the aspect ratio of all tabs * * @return Button to lock window and tab's aspect ratios. */ QWidget* BrainBrowserWindowToolBar::createTabOptionsWidget(QToolButton* toolBarLockWindowAndAllTabAspectRatioButton) { m_tabOptionsComponent = new BrainBrowserWindowToolBarTab(this->browserWindowIndex, toolBarLockWindowAndAllTabAspectRatioButton, this, m_objectNamePrefix); QWidget* w = this->createToolWidget("Tab", m_tabOptionsComponent, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_TOP, 0); return w; } /** * Update the tab widget. * * @param browserTabContent * Content of browser tab. */ void BrainBrowserWindowToolBar::updateTabOptionsWidget(BrowserTabContent* browserTabContent) { if (this->windowWidget->isHidden()) { return; } m_tabOptionsComponent->updateContent(browserTabContent); } /** * Create the chart type widget. * * @return * Widget containing the chart options. */ QWidget* BrainBrowserWindowToolBar::createChartTypeWidget() { m_chartTypeToolBarComponent = new BrainBrowserWindowToolBarChartType(this, m_objectNamePrefix); QWidget* w = this->createToolWidget("Chart Type (OLD)", m_chartTypeToolBarComponent, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_TOP, 100); w->setVisible(false); return w; } /** * Update the chart type widget. * * @param browserTabContent * The active model display (may be NULL). */ void BrainBrowserWindowToolBar::updateChartTypeWidget(BrowserTabContent* browserTabContent) { if (this->chartTypeWidget->isHidden()) { return; } m_chartTypeToolBarComponent->updateContent(browserTabContent); } /** * Create the chart two title widget. * * @return * Widget containing the chart title. */ QWidget* BrainBrowserWindowToolBar::createChartTwoTitleWidget() { m_chartTwoTitleToolBarComponent = new BrainBrowserWindowToolBarChartTwoTitle(this, m_objectNamePrefix); QWidget* w = this->createToolWidget("Chart Title", m_chartTwoTitleToolBarComponent, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_TOP, 100); w->setVisible(false); return w; } /** * Update the chart title widget. * * @param browserTabContent * The active tab content. */ void BrainBrowserWindowToolBar::updateChartTwoTitleWidget(BrowserTabContent* browserTabContent) { if (this->chartTwoTitleWidget->isHidden()) { return; } m_chartTwoTitleToolBarComponent->updateContent(browserTabContent); } /** * Create the chart type two widget. * * @return * Widget containing the chart type. */ QWidget* BrainBrowserWindowToolBar::createChartTypeTwoWidget() { m_chartTwoTypeToolBarComponent = new BrainBrowserWindowToolBarChartTwoType(this, m_objectNamePrefix); QWidget* w = this->createToolWidget("Chart Type", m_chartTwoTypeToolBarComponent, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_TOP, 100); w->setVisible(false); return w; } /** * Update the chart type widget. * * @param browserTabContent * The active model display (may be NULL). */ void BrainBrowserWindowToolBar::updateChartTypeTwoWidget(BrowserTabContent* browserTabContent) { if (this->chartTypeTwoWidget->isHidden()) { return; } m_chartTwoTypeToolBarComponent->updateContent(browserTabContent); } /** * Create the chart axes widget. * * @return * Widget containing the chart axes. */ QWidget* BrainBrowserWindowToolBar::createChartAxesWidget() { m_chartAxisToolBarComponent = new BrainBrowserWindowToolBarChartAxes(this, m_objectNamePrefix); QWidget* w = this->createToolWidget("Chart Axes", m_chartAxisToolBarComponent, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_TOP, 100); w->setVisible(false); return w; } /** * Update the chart axes widget. * * @param browserTabContent * The active model display (may be NULL). */ void BrainBrowserWindowToolBar::updateChartAxesWidget(BrowserTabContent* browserTabContent) { if (this->chartAxesWidget->isHidden()) { return; } m_chartAxisToolBarComponent->updateContent(browserTabContent); } /** * Create the chart attributes widget. * * @return * Widget containing the chart attributes. */ QWidget* BrainBrowserWindowToolBar::createChartAttributesWidget() { m_chartAttributesToolBarComponent = new BrainBrowserWindowToolBarChartAttributes(this, m_objectNamePrefix); QWidget* w = this->createToolWidget("Chart Attributes", m_chartAttributesToolBarComponent, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_TOP, 100); w->setVisible(false); return w; } /** * Update the chart attributes widget. * * @param browserTabContent * The active model display (may be NULL). */ void BrainBrowserWindowToolBar::updateChartAttributesWidget(BrowserTabContent* browserTabContent) { if (this->chartAttributesWidget->isHidden()) { return; } m_chartAttributesToolBarComponent->updateContent(browserTabContent); } /** * Create the chart two orientation widget. * * @return * Widget containing the two chart orientation. */ QWidget* BrainBrowserWindowToolBar::createChartTwoOrientationWidget() { m_chartTwoOrientationToolBarComponent = new BrainBrowserWindowToolBarChartTwoOrientation(this, m_objectNamePrefix); QWidget* w = this->createToolWidget("Chart
    Orientation", m_chartTwoOrientationToolBarComponent, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_TOP, 100); w->setVisible(false); return w; } /** * Update the chart orientation widget. * * @param browserTabContent * The active model display (may be NULL). */ void BrainBrowserWindowToolBar::updateChartTwoOrientationWidget(BrowserTabContent* browserTabContent) { if (this->chartTwoOrientationWidget->isHidden()) { return; } m_chartTwoOrientationToolBarComponent->updateContent(browserTabContent); } /** * Create the chart two attributes widget. * * @return * Widget containing the chart two attributes. */ QWidget* BrainBrowserWindowToolBar::createChartTwoAttributesWidget() { this->m_chartTwoAttributesToolBarComponent = new BrainBrowserWindowToolBarChartTwoAttributes(this, m_objectNamePrefix); QWidget* w = this->createToolWidget("Chart
    Attributes", this->m_chartTwoAttributesToolBarComponent, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_TOP, 100); w->setVisible(false); return w; } /** * Update the chart attributes widget. * * @param browserTabContent * The active model display (may be NULL). */ void BrainBrowserWindowToolBar::updateChartTwoAttributesWidget(BrowserTabContent* browserTabContent) { if (this->chartTwoAttributesWidget->isHidden()) { return; } m_chartTwoAttributesToolBarComponent->updateContent(browserTabContent); } /** * Create the chart two axes widget. * * @return * Widget containing the chart two axes. */ QWidget* BrainBrowserWindowToolBar::createChartTwoAxesWidget() { this->m_chartTwoAxesToolBarComponent = new BrainBrowserWindowToolBarChartTwoAxes(this, m_objectNamePrefix); QWidget* w = this->createToolWidget("Chart Axes", this->m_chartTwoAxesToolBarComponent, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_TOP, 100); w->setVisible(false); return w; } /** * Update the chart axes widget. * * @param browserTabContent * The active model display (may be NULL). */ void BrainBrowserWindowToolBar::updateChartTwoAxesWidget(BrowserTabContent* browserTabContent) { if (this->chartTwoAxesWidget->isHidden()) { return; } m_chartTwoAxesToolBarComponent->updateContent(browserTabContent); } /** * Create the single surface options widget. * * @return The single surface options widget. */ QWidget* BrainBrowserWindowToolBar::createSingleSurfaceOptionsWidget() { QLabel* structureSurfaceLabel = new QLabel("Brain Structure and Surface: "); /* * Note: Macro support is in StructureSurfaceSelectionControl */ this->surfaceSurfaceSelectionControl = new StructureSurfaceSelectionControl(false, m_objectNamePrefix + ":Surface", "surface view", this); QObject::connect(this->surfaceSurfaceSelectionControl, SIGNAL(selectionChanged(const StructureEnum::Enum, ModelSurface*)), this, SLOT(surfaceSelectionControlChanged(const StructureEnum::Enum, ModelSurface*))); this->surfaceSurfaceSelectionControl->setMinimumWidth(150); this->surfaceSurfaceSelectionControl->setMaximumWidth(1200); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); layout->addWidget(structureSurfaceLabel); layout->addWidget(this->surfaceSurfaceSelectionControl); layout->addStretch(); this->singleSurfaceSelectionWidgetGroup = new WuQWidgetObjectGroup(this); this->singleSurfaceSelectionWidgetGroup->add(this->surfaceSurfaceSelectionControl); QWidget* w = this->createToolWidget("Selection", widget, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_TOP, 100); w->setVisible(false); return w; } /** * Update the single surface options widget. * * @param browserTabContent * The active model display controller (may be NULL). */ void BrainBrowserWindowToolBar::updateSingleSurfaceOptionsWidget(BrowserTabContent* browserTabContent) { if (this->singleSurfaceSelectionWidget->isHidden()) { return; } this->singleSurfaceSelectionWidgetGroup->blockAllSignals(true); this->surfaceSurfaceSelectionControl->updateControl(browserTabContent->getSurfaceModelSelector()); this->singleSurfaceSelectionWidgetGroup->blockAllSignals(false); } /** * @return Create and return the surface montage options widget. */ QWidget* BrainBrowserWindowToolBar::createSurfaceMontageOptionsWidget() { m_surfaceMontageToolBarComponent = new BrainBrowserWindowToolBarSurfaceMontage(this, m_objectNamePrefix); QWidget* w = this->createToolWidget("Montage Selection", m_surfaceMontageToolBarComponent, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_TOP, 100); w->setVisible(false); return w; } /** * Update the surface montage options widget. * * @param browserTabContent * The active model display controller (may be NULL). */ void BrainBrowserWindowToolBar::updateSurfaceMontageOptionsWidget(BrowserTabContent* browserTabContent) { if (this->surfaceMontageSelectionWidget->isHidden()) { return; } m_surfaceMontageToolBarComponent->updateContent(browserTabContent); } /** * @return Create and return the clipping options component. */ QWidget* BrainBrowserWindowToolBar::createClippingOptionsWidget() { m_clippingToolBarComponent = new BrainBrowserWindowToolBarClipping(this->browserWindowIndex, this, m_objectNamePrefix); QWidget* w = this->createToolWidget("Clipping", m_clippingToolBarComponent, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_TOP, 100); w->setVisible(false); return w; } /** * Update the clipping options widget. * * @param browserTabContent * The active browser tab. */ void BrainBrowserWindowToolBar::updateClippingOptionsWidget(BrowserTabContent* browserTabContent) { if (m_clippingOptionsWidget->isHidden()) { return; } m_clippingToolBarComponent->updateContent(browserTabContent); } /** * Create the volume montage widget. * * @return The volume montage widget. */ QWidget* BrainBrowserWindowToolBar::createVolumeMontageWidget() { m_volumeMontageComponent = new BrainBrowserWindowToolBarVolumeMontage(m_objectNamePrefix, this); QWidget* w = this->createToolWidget("Montage", m_volumeMontageComponent, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_TOP, 0); w->setVisible(false); return w; } /** * Update the volume montage widget. * * @param browserTabContent * Content of browser tab. */ void BrainBrowserWindowToolBar::updateVolumeMontageWidget(BrowserTabContent* browserTabContent) { if (this->volumeMontageWidget->isHidden()) { return; } m_volumeMontageComponent->updateContent(browserTabContent); } /** * Create the volume plane widget. * * @return The volume plane widget. */ QWidget* BrainBrowserWindowToolBar::createVolumePlaneWidget() { m_slicePlaneComponent = new BrainBrowserWindowToolBarSlicePlane(m_objectNamePrefix, this); QWidget* w = this->createToolWidget("Slice Plane", m_slicePlaneComponent, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_TOP, 0); w->setVisible(false); return w; } /** * Update the volume plane orientation widget. * * @param browserTabContent * Content of browser tab. */ void BrainBrowserWindowToolBar::updateVolumePlaneWidget(BrowserTabContent* browserTabContent) { if (this->volumePlaneWidget->isHidden()) { return; } m_slicePlaneComponent->updateContent(browserTabContent); } /** * Create a tool widget which is a group of widgets with * a descriptive label added. * * @param name * Name for the descriptive label. For a multi-line label, * separate the lines with an HTML "
    " tag. * @param childWidget * Child widget that is in the tool widget. * @param verticalBarPlacement * Where to place a vertical bar. Values other than right or * left are ignored in which case no vertical bar is displayed. * @param contentPlacement * Where to place widget which must be top or bottom. * @return The tool widget. */ QWidget* BrainBrowserWindowToolBar::createToolWidget(const QString& name, QWidget* childWidget, const WidgetPlacement verticalBarPlacement, const WidgetPlacement contentPlacement, const int /*horizontalStretching*/) { QLabel* nameLabel = new QLabel("

    " + name + "
    "); nameLabel->setFixedHeight(nameLabel->sizeHint().height()); QWidget* w = new QWidget(); QGridLayout* layout = new QGridLayout(w); layout->setColumnStretch(0, 100); layout->setColumnStretch(1, 100); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 0); switch (contentPlacement) { case WIDGET_PLACEMENT_BOTTOM: layout->setRowStretch(0, 100); layout->setRowStretch(1, 0); layout->addWidget(childWidget, 1, 0, 1, 2); break; case WIDGET_PLACEMENT_TOP: layout->setRowStretch(1, 100); layout->setRowStretch(0, 0); layout->addWidget(childWidget, 0, 0, 1, 2); break; case WIDGET_PLACEMENT_NONE: layout->setRowStretch(0, 0); layout->addWidget(childWidget, 0, 0, 1, 2); break; default: CaretAssert(0); } layout->addWidget(nameLabel, 2, 0, 1, 2, Qt::AlignHCenter); const bool addVerticalBarOnLeftSide = (verticalBarPlacement == WIDGET_PLACEMENT_LEFT); const bool addVerticalBarOnRightSide = (verticalBarPlacement == WIDGET_PLACEMENT_RIGHT); if (addVerticalBarOnLeftSide || addVerticalBarOnRightSide) { QWidget* w2 = new QWidget(); QHBoxLayout* horizLayout = new QHBoxLayout(w2); WuQtUtilities::setLayoutSpacingAndMargins(horizLayout, 0, 0); if (addVerticalBarOnLeftSide) { horizLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 0); horizLayout->addSpacing(3); } const int widgetStretchFactor = 100; horizLayout->addWidget(w, widgetStretchFactor); if (addVerticalBarOnRightSide) { horizLayout->addSpacing(3); horizLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 0); } w = w2; } return w; } /** * Update the graphics windows for the selected tab. */ void BrainBrowserWindowToolBar::updateGraphicsWindow() { EventManager::get()->sendEvent( EventGraphicsUpdateOneWindow(this->browserWindowIndex).getPointer()); } /** * Update the user-interface. */ void BrainBrowserWindowToolBar::updateUserInterface() { EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(this->browserWindowIndex).getPointer()); } /** * Update the toolbox for the window */ void BrainBrowserWindowToolBar::updateToolBox() { EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(this->browserWindowIndex).addToolBox().getPointer()); } /** * Called when a view mode is selected. */ void BrainBrowserWindowToolBar::viewModeRadioButtonClicked(QAbstractButton*) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); if (btc == NULL) { return; } if (this->viewModeChartOneRadioButton->isChecked()) { btc->setSelectedModelType(ModelTypeEnum::MODEL_TYPE_CHART); } else if (this->viewModeChartTwoRadioButton->isChecked()) { btc->setSelectedModelType(ModelTypeEnum::MODEL_TYPE_CHART_TWO); } else if (this->viewModeSurfaceRadioButton->isChecked()) { btc->setSelectedModelType(ModelTypeEnum::MODEL_TYPE_SURFACE); } else if (this->viewModeSurfaceMontageRadioButton->isChecked()) { btc->setSelectedModelType(ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE); } else if (this->viewModeVolumeRadioButton->isChecked()) { btc->setSelectedModelType(ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES); } else if (this->viewModeWholeBrainRadioButton->isChecked()) { btc->setSelectedModelType(ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN); } else { btc->setSelectedModelType(ModelTypeEnum::MODEL_TYPE_INVALID); } this->updateToolBar(); this->updateTabName(-1); this->updateToolBox(); emit viewedModelChanged(); this->updateGraphicsWindow(); } /** * Called when orientation left or lateral button is pressed. */ void BrainBrowserWindowToolBar::orientationLeftOrLateralToolButtonTriggered(bool /*checked*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->leftView(); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when orientation right or medial button is pressed. */ void BrainBrowserWindowToolBar::orientationRightOrMedialToolButtonTriggered(bool /*checked*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->rightView(); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when orientation anterior button is pressed. */ void BrainBrowserWindowToolBar::orientationAnteriorToolButtonTriggered(bool /*checked*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->anteriorView(); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when orientation posterior button is pressed. */ void BrainBrowserWindowToolBar::orientationPosteriorToolButtonTriggered(bool /*checked*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->posteriorView(); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when orientation dorsal button is pressed. */ void BrainBrowserWindowToolBar::orientationDorsalToolButtonTriggered(bool /*checked*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->dorsalView(); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when orientation ventral button is pressed. */ void BrainBrowserWindowToolBar::orientationVentralToolButtonTriggered(bool /*checked*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->ventralView(); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when orientation reset button is pressed. */ void BrainBrowserWindowToolBar::orientationResetToolButtonTriggered(bool /*checked*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->resetView(); Model* mdc = btc->getModelForDisplay(); if (mdc != NULL) { this->updateVolumeIndicesWidget(btc); this->updateGraphicsWindowAndYokedWindows(); } } /** * Called when orientation lateral/medial button is pressed. */ void BrainBrowserWindowToolBar::orientationLateralMedialToolButtonTriggered(bool /*checked*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->leftView(); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when orientation dorsal/ventral button is pressed. */ void BrainBrowserWindowToolBar::orientationDorsalVentralToolButtonTriggered(bool /*checked*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->dorsalView(); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when orientation anterior/posterior button is pressed. */ void BrainBrowserWindowToolBar::orientationAnteriorPosteriorToolButtonTriggered(bool /*checked*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->anteriorView(); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when the scene tool button is clicked to show scene dialog */ void BrainBrowserWindowToolBar::sceneToolButtonClicked() { GuiManager::get()->getSceneDialogDisplayAction()->trigger(); } /** * Called when custom view is triggered and displays Custom View Menu. */ void BrainBrowserWindowToolBar::customViewActionTriggered() { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->readCustomViews(); const std::vector > customViewNameAndComments = prefs->getCustomViewNamesAndComments(); QMenu menu; QAction* editAction = menu.addAction("Create and Edit..."); editAction->setToolTip("Add and delete Custom Views.\n" "Edit model transformations."); const int32_t numViews = static_cast(customViewNameAndComments.size()); if (numViews > 0) { menu.addSeparator(); } for (int32_t i = 0; i < numViews; i++) { QAction* action = menu.addAction(customViewNameAndComments[i].first); action->setToolTip(WuQtUtilities::createWordWrappedToolTipText(customViewNameAndComments[i].second)); } QAction* selectedAction = menu.exec(QCursor::pos()); if (selectedAction != NULL) { if (selectedAction == editAction) { BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(browserWindowIndex); GuiManager::get()->processShowCustomViewDialog(bbw); } else { const AString customViewName = selectedAction->text(); ModelTransform modelTransform; if (prefs->getCustomView(customViewName, modelTransform)) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->setTransformationsFromModelTransform(modelTransform); this->updateGraphicsWindowAndYokedWindows(); } } } } /** * Called when the whole brain surface type combo box is changed. */ void BrainBrowserWindowToolBar::wholeBrainSurfaceTypeComboBoxIndexChanged(int /*indx*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); const int32_t tabIndex = btc->getTabNumber(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); if (wholeBrainModel == NULL) { return; } int32_t comboBoxIndex = this->wholeBrainSurfaceTypeComboBox->currentIndex(); if (comboBoxIndex >= 0) { const int32_t integerCode = this->wholeBrainSurfaceTypeComboBox->itemData(comboBoxIndex).toInt(); bool isValid = false; const SurfaceTypeEnum::Enum surfaceType = SurfaceTypeEnum::fromIntegerCode(integerCode, &isValid); if (isValid) { wholeBrainModel->setSelectedSurfaceType(tabIndex, surfaceType); this->updateVolumeIndicesWidget(btc); /* slices may get deselected */ this->updateAllWholeBrainSurfaceMenus(); this->updateGraphicsWindowAndYokedWindows(); } } } /** * Called when whole brain surface left check box is toggled. */ void BrainBrowserWindowToolBar::wholeBrainSurfaceLeftCheckBoxStateChanged(int /*state*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); if (wholeBrainModel == NULL) { return; } btc->setWholeBrainLeftEnabled(this->wholeBrainSurfaceLeftCheckBox->isChecked()); this->updateGraphicsWindowAndYokedWindows(); } /** * Update all whole brain surface selection menus */ void BrainBrowserWindowToolBar::updateAllWholeBrainSurfaceMenus() { updateWholeBrainSurfaceMenu(this->wholeBrainSurfaceLeftMenu, StructureEnum::CORTEX_LEFT); updateWholeBrainSurfaceMenu(this->wholeBrainSurfaceRightMenu, StructureEnum::CORTEX_RIGHT); updateWholeBrainSurfaceMenu(this->wholeBrainSurfaceCerebellumMenu, StructureEnum::CEREBELLUM); } /** * Update the menu to contain surface for the given structure * * @param menu * Menu that is updated * @param structure * Structure for surfaces */ void BrainBrowserWindowToolBar::updateWholeBrainSurfaceMenu(QMenu* menu, const StructureEnum::Enum structure) { CaretAssert(menu); menu->clear(); BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); if (wholeBrainModel == NULL) { return; } const int32_t tabIndex = btc->getTabNumber(); Brain* brain = GuiManager::get()->getBrain(); BrainStructure* brainStructure = brain->getBrainStructure(structure, false); if (brainStructure != NULL) { std::vector surfaces; brainStructure->getSurfacesOfType(wholeBrainModel->getSelectedSurfaceType(tabIndex), surfaces); const int32_t numSurfaces = static_cast(surfaces.size()); if (numSurfaces > 0) { Surface* selectedSurface = wholeBrainModel->getSelectedSurface(structure, tabIndex); for (int32_t i = 0; i < numSurfaces; i++) { QString name = surfaces[i]->getFileNameNoPath(); QAction* action = new QAction(name); action->setCheckable(true); if (surfaces[i] == selectedSurface) { action->setChecked(true); } action->setData(qVariantFromValue((void*)surfaces[i])); menu->addAction(action); } } } } /** * Called when the left surface tool button is pressed. */ void BrainBrowserWindowToolBar::wholeBrainSurfaceLeftToolButtonTriggered(bool /*checked*/) { updateAllWholeBrainSurfaceMenus(); if ( ! this->wholeBrainSurfaceLeftMenu->isEmpty()) { this->wholeBrainSurfaceLeftMenu->exec(QCursor::pos()); } } /** * Called when left surface is selected from menu * * @param action * Action that was selected */ void BrainBrowserWindowToolBar::wholeBrainSurfaceLeftMenuTriggered(QAction* action) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); if (wholeBrainModel == NULL) { return; } if (action != NULL) { QVariant data = action->data(); void* p = data.value(); Surface* surface = (Surface*)p; wholeBrainModel->setSelectedSurface(StructureEnum::CORTEX_LEFT, btc->getTabNumber(), surface); this->updateGraphicsWindowAndYokedWindows(); } } /** * Called when the right surface tool button is pressed. */ void BrainBrowserWindowToolBar::wholeBrainSurfaceRightToolButtonTriggered(bool /*checked*/) { updateAllWholeBrainSurfaceMenus(); if ( ! this->wholeBrainSurfaceRightMenu->isEmpty()) { this->wholeBrainSurfaceRightMenu->exec(QCursor::pos()); } } /** * Called when right surface is selected from menu * * @param action * Action that was selected */ void BrainBrowserWindowToolBar::wholeBrainSurfaceRightMenuTriggered(QAction* action) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); if (wholeBrainModel == NULL) { return; } if (action != NULL) { QVariant data = action->data(); void* p = data.value(); Surface* surface = (Surface*)p; wholeBrainModel->setSelectedSurface(StructureEnum::CORTEX_RIGHT, btc->getTabNumber(), surface); this->updateGraphicsWindowAndYokedWindows(); } } /** * Called when the cerebellum surface tool button is pressed. */ void BrainBrowserWindowToolBar::wholeBrainSurfaceCerebellumToolButtonTriggered(bool /*checked*/) { updateAllWholeBrainSurfaceMenus(); if ( ! this->wholeBrainSurfaceCerebellumMenu->isEmpty()) { this->wholeBrainSurfaceCerebellumMenu->exec(QCursor::pos()); } } /** * Called when cerebellum surface is selected from menu * * @param action * Action that was selected */ void BrainBrowserWindowToolBar::wholeBrainSurfaceCerebellumMenuTriggered(QAction* action) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); if (wholeBrainModel == NULL) { return; } if (action != NULL) { QVariant data = action->data(); void* p = data.value(); Surface* surface = (Surface*)p; wholeBrainModel->setSelectedSurface(StructureEnum::CEREBELLUM, btc->getTabNumber(), surface); this->updateGraphicsWindowAndYokedWindows(); } } /** * Called when whole brain surface right checkbox is toggled. */ void BrainBrowserWindowToolBar::wholeBrainSurfaceRightCheckBoxStateChanged(int /*state*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); if (wholeBrainModel == NULL) { return; } btc->setWholeBrainRightEnabled(this->wholeBrainSurfaceRightCheckBox->isChecked()); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when whole brain cerebellum check box is toggled. */ void BrainBrowserWindowToolBar::wholeBrainSurfaceCerebellumCheckBoxStateChanged(int /*state*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); if (wholeBrainModel == NULL) { return; } btc->setWholeBrainCerebellumEnabled(this->wholeBrainSurfaceCerebellumCheckBox->isChecked()); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when whole brain separation left/right spin box value is changed. */ void BrainBrowserWindowToolBar::wholeBrainSurfaceSeparationLeftRightSpinBoxValueChanged(double /*d*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); if (wholeBrainModel == NULL) { return; } btc->setWholeBrainLeftRightSeparation(this->wholeBrainSurfaceSeparationLeftRightSpinBox->value()); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when whole brain left&right/cerebellum spin box value is changed. */ void BrainBrowserWindowToolBar::wholeBrainSurfaceSeparationCerebellumSpinBoxSelected(double /*d*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); if (wholeBrainModel == NULL) { return; } btc->setWholeBrainCerebellumSeparation(this->wholeBrainSurfaceSeparationCerebellumSpinBox->value()); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when match check box is clicked * * @param checked * New checked status. */ void BrainBrowserWindowToolBar::wholeBrainSurfaceMatchCheckBoxClicked(bool checked) { Brain* brain = GuiManager::get()->getBrain(); CaretAssert(brain); brain->setSurfaceMatchingToAnatomical(checked); this->updateGraphicsWindowAndYokedWindows(); this->updateUserInterface(); } /** * Called when a single surface control is changed. * @param structure * Structure that is selected. * @param surfaceModel * Model that is selected. */ void BrainBrowserWindowToolBar::surfaceSelectionControlChanged( const StructureEnum::Enum structure, ModelSurface* surfaceModel) { if (surfaceModel != NULL) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); ModelSurfaceSelector* surfaceModelSelector = btc->getSurfaceModelSelector(); surfaceModelSelector->setSelectedStructure(structure); surfaceModelSelector->setSelectedSurfaceModel(surfaceModel); EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); this->updateUserInterface(); this->updateGraphicsWindow(); } this->updateTabName(-1); } /** * Receive events from the event manager. * * @param event * Event sent by event manager. */ void BrainBrowserWindowToolBar::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET) { EventBrowserWindowDrawingContent* getModelEvent = dynamic_cast(event); CaretAssert(getModelEvent); if (getModelEvent->getBrowserWindowIndex() == this->browserWindowIndex) { BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->browserWindowIndex); if (browserWindow != NULL) { const int32_t numTabs = this->tabBar->count(); for (int32_t i = 0; i < numTabs; i++) { BrowserTabContent* btc = this->getTabContentFromTab(i); getModelEvent->addBrowserTab(btc); } BrowserWindowContent* windowContent = browserWindow->getBrowerWindowContent(); getModelEvent->setBrowserWindowContent(windowContent); if (windowContent->isTileTabsEnabled()) { /* * Tab that is highlighted so user knows which tab * any changes in toolbar/toolboxes apply to. */ getModelEvent->setTabIndexForTileTabsHighlighting(m_tabIndexForTileTabsHighlighting); } getModelEvent->setSelectedBrowserTabContent(this->getTabContentFromSelectedTab()); } getModelEvent->setEventProcessed(); } } else if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiEvent = dynamic_cast(event); CaretAssert(uiEvent); if (uiEvent->isToolBarUpdate() && uiEvent->isUpdateForWindow(this->browserWindowIndex)) { this->updateToolBar(); uiEvent->setEventProcessed(); } } else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_CREATE_TABS) { EventBrowserWindowCreateTabs* tabEvent = dynamic_cast(event); CaretAssert(tabEvent); EventModelGetAll eventAllModels; EventManager::get()->sendEvent(eventAllModels.getPointer()); const bool haveModels = (eventAllModels.getModels().empty() == false); if (haveModels) { switch (tabEvent->getMode()) { case EventBrowserWindowCreateTabs::MODE_LOADED_DATA_FILE: if (tabBar->count() == 0) { AString errorMessage; BrowserTabContent* tabContent = createNewTab(errorMessage); if (errorMessage.isEmpty() == false) { CaretLogSevere(errorMessage); } if (tabContent != NULL) { insertTabContentPrivate(InsertTabMode::APPEND, tabContent, -1); } } break; case EventBrowserWindowCreateTabs::MODE_LOADED_SPEC_FILE: this->addDefaultTabsAfterLoadingSpecFile(); break; } } tabEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION) { EventBrowserWindowTileTabOperation* tileTabsEvent = dynamic_cast(event); CaretAssert(tileTabsEvent); if (tileTabsEvent->getWindowIndex() == this->browserWindowIndex) { const int32_t browserTabIndex = tileTabsEvent->getBrowserTabIndex(); int32_t tabBarIndex = getTabBarIndexWithBrowserTabIndex(browserTabIndex); const EventBrowserWindowTileTabOperation::Operation operation = tileTabsEvent->getOperation(); switch (operation) { case EventBrowserWindowTileTabOperation::OPERATION_NEW_TAB_AFTER: if (tabBarIndex >= 0) { insertNewTabAtTabBarIndex(tabBarIndex + 1); } break; case EventBrowserWindowTileTabOperation::OPERATION_NEW_TAB_BEFORE: if (tabBarIndex >= 0) { insertNewTabAtTabBarIndex(tabBarIndex); } break; case EventBrowserWindowTileTabOperation::OPERATION_SELECT_TAB: if (tabBarIndex >= 0) { m_tileTabsHighlightingTimerEnabledFlag = false; this->tabBar->setCurrentIndex(tabBarIndex); m_tileTabsHighlightingTimerEnabledFlag = true; } break; case EventBrowserWindowTileTabOperation::OPERATION_REPLACE_TABS: replaceBrowserTabs(tileTabsEvent->getBrowserTabsForReplaceOperation()); break; } tileTabsEvent->setEventProcessed(); } } else if (event->getEventType() == EventTypeEnum::EVENT_UPDATE_YOKED_WINDOWS) { EventUpdateYokedWindows* yokeUpdateEvent = dynamic_cast(event); CaretAssert(yokeUpdateEvent); BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); if (browserTabContent != NULL) { if (this->browserWindowIndex != yokeUpdateEvent->getBrowserWindowIndexThatIssuedEvent()) { if (yokeUpdateEvent->isBrainOrChartModelYoking(browserTabContent->getBrainModelYokingGroup(), browserTabContent->getChartModelYokingGroup())) { this->updateToolBar(); this->updateGraphicsWindow(); } } } } else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL_VIEWED) { EventBrowserTabGetAllViewed* viewedTabsEvent = dynamic_cast(event); CaretAssert(viewedTabsEvent); BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->browserWindowIndex); if (browserWindow != NULL) { if (browserWindow->isTileTabsSelected()) { const int32_t numTabs = this->tabBar->count(); for (int32_t i = 0; i < numTabs; i++) { BrowserTabContent* btc = this->getTabContentFromTab(i); viewedTabsEvent->addViewedBrowserTab(btc); } } else { BrowserTabContent* btc = getTabContentFromSelectedTab(); if (btc != NULL) { viewedTabsEvent->addViewedBrowserTab(btc); } } } viewedTabsEvent->setEventProcessed(); } else { } } /** * Get the tab bar index containing the browser tab index. * * @param browserTabIndex * Index of the browser tab. * @return * Index in tab bar containing the browser tab index or -1 if not found. */ int32_t BrainBrowserWindowToolBar::getTabBarIndexWithBrowserTabIndex(const int32_t browserTabIndex) { const int numTabs = this->tabBar->count(); if (numTabs > 0) { for (int32_t i = 0; i < numTabs; i++) { const BrowserTabContent* btc = getTabContentFromTab(i); if (btc->getTabNumber() == browserTabIndex){ return i; } } } return -1; } /** * If this window is yoked, update all windows since they may * be yoked to this window. If NOT yoked, just update this window. */ void BrainBrowserWindowToolBar::updateGraphicsWindowAndYokedWindows() { BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); if (browserTabContent != NULL) { if (browserTabContent->isBrainModelYoked()) { EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendEvent(EventUpdateYokedWindows(this->browserWindowIndex, browserTabContent->getBrainModelYokingGroup(), browserTabContent->getChartModelYokingGroup()).getPointer()); } else { updateGraphicsWindow(); } } } /** * Get the content in the browser tab. * @return * Browser tab contents in the selected tab or NULL if none. */ BrowserTabContent* BrainBrowserWindowToolBar::getTabContentFromSelectedTab() { const int tabIndex = this->tabBar->currentIndex(); BrowserTabContent* btc = this->getTabContentFromTab(tabIndex); return btc; } /** * Get the content in the given browser tab * @param tabIndex * Index of tab. * @return * Browser tab contents in the selected tab or NULL if none. */ BrowserTabContent* BrainBrowserWindowToolBar::getTabContentFromTab(const int tabIndex) { if ((tabIndex >= 0) && (tabIndex < this->tabBar->count())) { void* p = this->tabBar->tabData(tabIndex).value(); BrowserTabContent* btc = (BrowserTabContent*)p; return btc; } return NULL; } /** * Get the model displayed in the selected tab. * @return * Model in the selected tab or NULL if * no model is displayed. */ Model* BrainBrowserWindowToolBar::getDisplayedModel() { Model* mdc = NULL; BrowserTabContent* btc = this->getTabContentFromSelectedTab(); if (btc != NULL) { mdc = btc->getModelForDisplay(); } return mdc; } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* BrainBrowserWindowToolBar::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "BrainBrowserWindowToolBar", 1); switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } /* * Determine tabs in this toolbar that should be saved to scene */ const std::vector tabIndicesForScene = sceneAttributes->getIndicesOfTabsForSavingToScene(); std::vector tabIndicesToSave; const int numTabsInToolbar = this->tabBar->count(); if (numTabsInToolbar > 0) { for (int32_t i = 0; i < numTabsInToolbar; i++) { BrowserTabContent* btc = this->getTabContentFromTab(i); const int32_t tabIndex = btc->getTabNumber(); if (std::find(tabIndicesForScene.begin(), tabIndicesForScene.end(), tabIndex) != tabIndicesForScene.end()) { tabIndicesToSave.push_back(tabIndex); } } } /* * Save the tabs */ const int numTabs = static_cast(tabIndicesToSave.size()); if (numTabs > 0) { SceneIntegerArray* sceneTabIndexArray = new SceneIntegerArray("tabIndices", numTabs); for (int32_t i = 0; i < numTabs; i++) { const int32_t tabIndex = tabIndicesToSave[i]; sceneTabIndexArray->setValue(i, tabIndex); } sceneClass->addChild(sceneTabIndexArray); } /* * Add selected tab to scene */ int32_t selectedTabIndex = -1; BrowserTabContent* selectedTab = getTabContentFromSelectedTab(); if (selectedTab != NULL) { selectedTabIndex = selectedTab->getTabNumber(); } sceneClass->addInteger("selectedTabIndex", selectedTabIndex); /* * Toolbar visible */ sceneClass->addBoolean("toolBarVisible", m_toolbarWidget->isVisible()); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void BrainBrowserWindowToolBar::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } /* * Close any tabs */ const int32_t numberOfOpenTabs = this->tabBar->count(); for (int32_t iClose = (numberOfOpenTabs - 1); iClose >= 0; iClose--) { this->tabClosed(iClose); } /* * Index of selected browser tab (NOT the tabBar) */ const int32_t selectedTabIndex = sceneClass->getIntegerValue("selectedTabIndex", -1); /* * Create new tabs */ int32_t defaultTabBarIndex = 0; const ScenePrimitiveArray* sceneTabIndexArray = sceneClass->getPrimitiveArray("tabIndices"); if (sceneTabIndexArray != NULL) { const int32_t numValidTabs = sceneTabIndexArray->getNumberOfArrayElements(); for (int32_t iTab = 0; iTab < numValidTabs; iTab++) { const int32_t tabIndex = sceneTabIndexArray->integerValue(iTab); EventBrowserTabGet getTabContent(tabIndex); EventManager::get()->sendEvent(getTabContent.getPointer()); BrowserTabContent* tabContent = getTabContent.getBrowserTab(); if (tabContent != NULL) { if (tabContent->getTabNumber() == selectedTabIndex) { defaultTabBarIndex = iTab; } CaretAssert(iTab >= 0); insertTabContentPrivate(InsertTabMode::AT_TAB_BAR_INDEX, tabContent, iTab); } else { sceneAttributes->addToErrorMessage("Toolbar in window " + AString::number(this->browserWindowIndex) + " failed to restore tab " + AString::number(selectedTabIndex)); } } } /* * Select tab */ if ((defaultTabBarIndex >= 0) && (defaultTabBarIndex < tabBar->count())) { tabBar->setCurrentIndex(defaultTabBarIndex); } /* * Show hide toolbar */ const bool showToolBar = sceneClass->getBooleanValue("toolBarVisible", true); showHideToolBar(showToolBar); } /** * @return Number of tabs in the tab bar. */ int32_t BrainBrowserWindowToolBar::getNumberOfTabs() const { return this->tabBar->count(); } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBar.h000066400000000000000000000466221360521144700247100ustar00rootroot00000000000000#ifndef __BRAIN_BROWSER_WINDOW_TOOLBAR_H__ #define __BRAIN_BROWSER_WINDOW_TOOLBAR_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "EnumComboBoxTemplate.h" #include "EventListenerInterface.h" #include "ModelTypeEnum.h" #include "SceneableInterface.h" #include "StructureEnum.h" class QAbstractButton; class QAction; class QActionGroup; class QButtonGroup; class QCheckBox; class QComboBox; class QDoubleSpinBox; class QHBoxLayout; class QIcon; class QLabel; class QMainWindow; class QMenu; class QRadioButton; class QSpinBox; class QToolButton; class QVBoxLayout; namespace caret { class BrainBrowserWindowToolBarChartAxes; class BrainBrowserWindowToolBarChartAttributes; class BrainBrowserWindowToolBarChartTwoAttributes; class BrainBrowserWindowToolBarChartTwoAxes; class BrainBrowserWindowToolBarChartTwoOrientation; class BrainBrowserWindowToolBarChartTwoTitle; class BrainBrowserWindowToolBarChartTwoType; class BrainBrowserWindowToolBarChartType; class BrainBrowserWindowToolBarClipping; class BrainBrowserWindowToolBarSlicePlane; class BrainBrowserWindowToolBarSliceSelection; class BrainBrowserWindowToolBarSurfaceMontage; class BrainBrowserWindowToolBarTab; class BrainBrowserWindowToolBarVolumeMontage; class BrainBrowserWindow; class BrowserTabContent; class Model; class ModelSurface; class ModelVolumeInterface; class SceneAttributes; class SceneClass; class Surface; class SurfaceSelectionViewController; class StructureSurfaceSelectionControl; class WuQTabBar; class WuQWidgetObjectGroup; class BrainBrowserWindowToolBar : public QToolBar, public EventListenerInterface, public SceneableInterface { Q_OBJECT public: BrainBrowserWindowToolBar(const int32_t browserWindowIndex, BrowserTabContent* initialBrowserTabContent, QAction* overlayToolBoxAction, QAction* layersToolBoxAction, QToolButton* toolBarLockWindowAndAllTabAspectRatioButton, const QString& objectNamePrefix, BrainBrowserWindow* parentBrainBrowserWindow); ~BrainBrowserWindowToolBar(); void addNewTab(); void addNewDuplicatedTab(BrowserTabContent* browserTabContentToBeCloned); void addNewTabWithContent(BrowserTabContent* browserTabContent); void addDefaultTabsAfterLoadingSpecFile(); void receiveEvent(Event* event); int32_t getNumberOfTabs() const; void insertDuplicateMenuBar(QMainWindow* mainWindow); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); signals: void viewedModelChanged(); private: enum WidgetPlacement { WIDGET_PLACEMENT_NONE, WIDGET_PLACEMENT_BOTTOM, WIDGET_PLACEMENT_LEFT, WIDGET_PLACEMENT_RIGHT, WIDGET_PLACEMENT_TOP }; BrainBrowserWindowToolBar(const BrainBrowserWindowToolBar&); BrainBrowserWindowToolBar& operator=(const BrainBrowserWindowToolBar&); BrowserTabContent* getTabContentFromSelectedTab(); BrowserTabContent* getTabContentFromTab(const int tabIndex); int32_t getTabBarIndexWithBrowserTabIndex(const int32_t browserTabIndex); Model* getDisplayedModel(); int32_t loadIntoTab(const int32_t tabIndex, Model* controller); void updateGraphicsWindow(); void updateGraphicsWindowAndYokedWindows(); void updateUserInterface(); void updateToolBox(); void updateAllTabNames(); void updateTabName(const int32_t tabIndex); QWidget* createViewWidget(); QWidget* createOrientationWidget(); QWidget* createWholeBrainSurfaceOptionsWidget(); QWidget* createVolumeIndicesWidget(); QWidget* createModeWidget(); QWidget* createTabOptionsWidget(QToolButton* toolBarLockWindowAndAllTabAspectRatioButton); QWidget* createChartAxesWidget(); QWidget* createChartAttributesWidget(); QWidget* createChartTwoOrientationWidget(); QWidget* createChartTwoAttributesWidget(); QWidget* createChartTwoAxesWidget(); QWidget* createChartTwoTitleWidget(); QWidget* createChartTypeWidget(); QWidget* createChartTypeTwoWidget(); QWidget* createSingleSurfaceOptionsWidget(); QWidget* createSurfaceMontageOptionsWidget(); QWidget* createClippingOptionsWidget(); QWidget* createVolumeMontageWidget(); QWidget* createVolumePlaneWidget(); ModelTypeEnum::Enum updateViewWidget(BrowserTabContent* browserTabContent); void updateOrientationWidget(BrowserTabContent* browserTabContent); void updateWholeBrainSurfaceOptionsWidget(BrowserTabContent* browserTabContent); void updateVolumeIndicesWidget(BrowserTabContent* browserTabContent); void updateModeWidget(BrowserTabContent* browserTabContent); void updateTabOptionsWidget(BrowserTabContent* browserTabContent); void updateSingleSurfaceOptionsWidget(BrowserTabContent* browserTabContent); void updateSurfaceMontageOptionsWidget(BrowserTabContent* browserTabContent); void updateChartAxesWidget(BrowserTabContent* browserTabContent); void updateChartAttributesWidget(BrowserTabContent* browserTabContent); void updateChartTwoAttributesWidget(BrowserTabContent* browserTabContent); void updateChartTwoAxesWidget(BrowserTabContent* browserTabContent); void updateChartTwoOrientationWidget(BrowserTabContent* browserTabContent); void updateChartTwoTitleWidget(BrowserTabContent* browserTabContent); void updateChartTypeWidget(BrowserTabContent* browserTabContent); void updateChartTypeTwoWidget(BrowserTabContent* browserTabContent); void updateVolumeMontageWidget(BrowserTabContent* browserTabContent); void updateVolumePlaneWidget(BrowserTabContent* browserTabContent); void updateClippingOptionsWidget(BrowserTabContent* browserTabContent); QWidget* createToolWidget(const QString& name, QWidget* childWidget, const WidgetPlacement verticalBarPlacement, const WidgetPlacement contentPlacement, const int horizontalStretching); QWidget* viewWidget; QWidget* orientationWidget; QWidget* wholeBrainSurfaceOptionsWidget; QWidget* volumeIndicesWidget; QWidget* modeWidget; QWidget* windowWidget; QWidget* singleSurfaceSelectionWidget; QWidget* surfaceMontageSelectionWidget; QWidget* m_clippingOptionsWidget; QWidget* volumeMontageWidget; QWidget* volumePlaneWidget; QWidget* chartTypeWidget; QWidget* chartTypeTwoWidget; QWidget* chartAxesWidget; QWidget* chartAttributesWidget; QWidget* chartTwoOrientationWidget; QWidget* chartTwoAttributesWidget; QWidget* chartTwoAxesWidget; QWidget* chartTwoTitleWidget; WuQWidgetObjectGroup* viewWidgetGroup; WuQWidgetObjectGroup* orientationWidgetGroup; WuQWidgetObjectGroup* wholeBrainSurfaceOptionsWidgetGroup; WuQWidgetObjectGroup* modeWidgetGroup; WuQWidgetObjectGroup* singleSurfaceSelectionWidgetGroup; QVBoxLayout* m_toolBarMainLayout; QWidget* fullToolBarWidget; QWidget* m_toolbarWidget; QHBoxLayout* toolbarWidgetLayout; QWidget* tabBarWidget; WuQTabBar* tabBar; /** Widget displayed at bottom of toolbar for mouse input controls */ QWidget* userInputControlsWidget; /** Layout for widget displayed at bottom of toolbar for mouse input controls */ QHBoxLayout* userInputControlsWidgetLayout; /** Is set to the user input widget provided by the user input processor */ QWidget* userInputControlsWidgetActiveInputWidget; void removeAndReturnAllTabs(std::vector& allTabContent); void getAllTabContent(std::vector& allTabContent) const; void removeTabWithContent(BrowserTabContent* browserTabContent); public slots: void closeSelectedTab(); void moveTabsToNewWindows(); void nextTab(); void previousTab(); void renameTab(); void updateToolBar(); void updateToolBarComponents(BrowserTabContent* browserTabContent); void showHideToolBar(bool showIt); void showMacroDialog(); private slots: void selectedTabChanged(int indx); void tabMoved(int, int); void tabCloseSelected(int); void showTabMenu(const QPoint& pos); void tabBarMousePressedSlot(); void tabBarMouseReleasedSlot(); private: enum class InsertTabMode { APPEND, AT_TAB_BAR_INDEX }; bool allowAddingNewTab(); void insertTabContentPrivate(const InsertTabMode insertTabMode, BrowserTabContent* browserTabContent, const int32_t tabBarIndex); void removeTab(int index); void tabClosed(int index); void insertNewTabAtTabBarIndex(int32_t tabBarIndex); void insertAndCloneTabContentAtTabBarIndex(const BrowserTabContent* tabContentToBeCloned, const int32_t tabBarIndex); void replaceBrowserTabs(const std::vector& browserTabs); BrowserTabContent* createNewTab(AString& errorMessage); QRadioButton* viewModeSurfaceRadioButton; QRadioButton* viewModeSurfaceMontageRadioButton; QRadioButton* viewModeVolumeRadioButton; QRadioButton* viewModeWholeBrainRadioButton; QRadioButton* viewModeChartOneRadioButton; QRadioButton* viewModeChartTwoRadioButton; QAction* customViewAction; private slots: void viewModeRadioButtonClicked(QAbstractButton*); void customViewActionTriggered(); void sceneToolButtonClicked(); private: QAction* orientationLateralMedialToolButtonAction; QAction* orientationDorsalVentralToolButtonAction; QAction* orientationAnteriorPosteriorToolButtonAction; QToolButton* orientationLateralMedialToolButton; QToolButton* orientationDorsalVentralToolButton; QToolButton* orientationAnteriorPosteriorToolButton; QAction* orientationLeftOrLateralToolButtonAction; QAction* orientationRightOrMedialToolButtonAction; QAction* orientationAnteriorToolButtonAction; QAction* orientationPosteriorToolButtonAction; QAction* orientationDorsalToolButtonAction; QAction* orientationVentralToolButtonAction; QToolButton* orientationLeftOrLateralToolButton; QToolButton* orientationRightOrMedialToolButton; QToolButton* orientationAnteriorToolButton; QToolButton* orientationPosteriorToolButton; QToolButton* orientationDorsalToolButton; QToolButton* orientationVentralToolButton; QAction* orientationResetToolButtonAction; QToolButton* orientationCustomViewSelectToolButton; QIcon* viewOrientationLeftIcon; QIcon* viewOrientationRightIcon; QIcon* viewOrientationAnteriorIcon; QIcon* viewOrientationPosteriorIcon; QIcon* viewOrientationDorsalIcon; QIcon* viewOrientationVentralIcon; QIcon* viewOrientationLeftLateralIcon; QIcon* viewOrientationLeftMedialIcon; QIcon* viewOrientationRightLateralIcon; QIcon* viewOrientationRightMedialIcon; QToolButton* m_movieToolButton = NULL; private slots: void orientationLeftOrLateralToolButtonTriggered(bool checked); void orientationRightOrMedialToolButtonTriggered(bool checked); void orientationAnteriorToolButtonTriggered(bool checked); void orientationPosteriorToolButtonTriggered(bool checked); void orientationDorsalToolButtonTriggered(bool checked); void orientationVentralToolButtonTriggered(bool checked); void orientationResetToolButtonTriggered(bool checked); void orientationLateralMedialToolButtonTriggered(bool checked); void orientationDorsalVentralToolButtonTriggered(bool checked); void orientationAnteriorPosteriorToolButtonTriggered(bool checked); private: QComboBox* wholeBrainSurfaceTypeComboBox; QCheckBox* wholeBrainSurfaceLeftCheckBox; QCheckBox* wholeBrainSurfaceRightCheckBox; QCheckBox* wholeBrainSurfaceCerebellumCheckBox; QMenu* wholeBrainSurfaceLeftMenu; QMenu* wholeBrainSurfaceRightMenu; QMenu* wholeBrainSurfaceCerebellumMenu; QDoubleSpinBox* wholeBrainSurfaceSeparationLeftRightSpinBox; QDoubleSpinBox* wholeBrainSurfaceSeparationCerebellumSpinBox; QCheckBox* wholeBrainSurfaceMatchCheckBox; void updateAllWholeBrainSurfaceMenus(); void updateWholeBrainSurfaceMenu(QMenu* menu, const StructureEnum::Enum structure); private slots: void wholeBrainSurfaceTypeComboBoxIndexChanged(int indx); void wholeBrainSurfaceLeftCheckBoxStateChanged(int state); void wholeBrainSurfaceRightCheckBoxStateChanged(int state); void wholeBrainSurfaceCerebellumCheckBoxStateChanged(int state); void wholeBrainSurfaceSeparationLeftRightSpinBoxValueChanged(double d); void wholeBrainSurfaceSeparationCerebellumSpinBoxSelected(double d); void wholeBrainSurfaceLeftToolButtonTriggered(bool checked); void wholeBrainSurfaceRightToolButtonTriggered(bool checked); void wholeBrainSurfaceCerebellumToolButtonTriggered(bool checked); void wholeBrainSurfaceMatchCheckBoxClicked(bool checked); void wholeBrainSurfaceLeftMenuTriggered(QAction*); void wholeBrainSurfaceRightMenuTriggered(QAction*); void wholeBrainSurfaceCerebellumMenuTriggered(QAction*); private: StructureSurfaceSelectionControl* surfaceSurfaceSelectionControl; private slots: void surfaceSelectionControlChanged(const StructureEnum::Enum, ModelSurface*); private: BrainBrowserWindowToolBarChartAxes* m_chartAxisToolBarComponent; BrainBrowserWindowToolBarChartTwoType* m_chartTwoTypeToolBarComponent; BrainBrowserWindowToolBarChartType* m_chartTypeToolBarComponent; BrainBrowserWindowToolBarChartAttributes* m_chartAttributesToolBarComponent; BrainBrowserWindowToolBarChartTwoAxes* m_chartTwoAxesToolBarComponent; BrainBrowserWindowToolBarChartTwoOrientation* m_chartTwoOrientationToolBarComponent; BrainBrowserWindowToolBarChartTwoAttributes* m_chartTwoAttributesToolBarComponent; BrainBrowserWindowToolBarChartTwoTitle* m_chartTwoTitleToolBarComponent; BrainBrowserWindowToolBarSurfaceMontage* m_surfaceMontageToolBarComponent; BrainBrowserWindowToolBarClipping* m_clippingToolBarComponent; BrainBrowserWindowToolBarSlicePlane* m_slicePlaneComponent; BrainBrowserWindowToolBarSliceSelection* m_sliceSelectionComponent; BrainBrowserWindowToolBarVolumeMontage* m_volumeMontageComponent; BrainBrowserWindowToolBarTab* m_tabOptionsComponent; private slots: void modeInputModeActionTriggered(QAction*); private: void updateDisplayedModeUserInputWidget(); QActionGroup* modeInputModeActionGroup; QAction* modeInputModeAnnotationsAction; QAction* modeInputModeBordersAction; QAction* modeInputModeFociAction; QAction* modeInputModeImageAction; QAction* modeInputModeViewAction; QAction* modeInputVolumeEditAction; private: QAction* toolBarToolButtonAction; QAction* toolBoxToolButtonAction; int32_t browserWindowIndex; private slots: void resetTabIndexForTileTabsHighlighting(); private: friend class BrainBrowserWindow; friend class BrainBrowserWindowToolBarChartAxes; friend class BrainBrowserWindowToolBarChartTwoAxes; friend class BrainBrowserWindowToolBarChartTwoOrientation; friend class BrainBrowserWindowToolBarChartTwoAttributes; friend class BrainBrowserWindowToolBarChartTwoType; friend class BrainBrowserWindowToolBarChartType; friend class BrainBrowserWindowToolBarClipping; friend class BrainBrowserWindowToolBarComponent; friend class BrainBrowserWindowToolBarSurfaceMontage; friend class BrainBrowserWindowToolBarSlicePlane; friend class BrainBrowserWindowToolBarSliceSelection; friend class BrainBrowserWindowToolBarTab; friend class BrainBrowserWindowToolBarVolumeMontage; /** * When a tab is selected in Tile Tabs viewing, * the graphics window content of the tab is * highlighted for a short time by drawing a * box around it. */ int32_t m_tabIndexForTileTabsHighlighting; QTimer* m_tileTabsHighlightingTimer = NULL; bool m_tileTabsHighlightingTimerEnabledFlag = true; QString m_objectNamePrefix; bool isContructorFinished; bool isDestructionInProgress; /** * Tracks when update is performed to catch incorrectly emitted signals. */ bool m_performingUpdateFlag = false; const int32_t TAB_INDEX_APPEND_TO_TOOLBAR = 10000; friend class BrainBrowserWindowToolBarTabPopUpMenu; }; #ifdef __BRAIN_BROWSER_WINDOW_TOOLBAR_DECLARE__ #endif // __BRAIN_BROWSER_WINDOW_TOOLBAR_DECLARE__ } #endif // __BRAIN_BROWSER_WINDOW_TOOLBAR_H__ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.cxx000066400000000000000000000557321360521144700303160ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ATTRIBUTES_DECLARE__ #include "BrainBrowserWindowToolBarChartAttributes.h" #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ATTRIBUTES_DECLARE__ #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretDataFile.h" #include "CaretDataFileSelectionModel.h" #include "EnumComboBoxTemplate.h" #include "CaretMappableDataFile.h" #include "ChartMatrixDisplayProperties.h" #include "ChartModelDataSeries.h" #include "ChartModelFrequencySeries.h" #include "ChartModelTimeSeries.h" #include "ChartableMatrixInterface.h" #include "EventBrowserWindowGraphicsRedrawn.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "ModelChart.h" #include "WuQFactory.h" #include "WuQMacroManager.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::BrainBrowserWindowToolBarChartAttributes * \brief Controls for chart attributes. * \ingroup GuiQt */ /** * Constructor. * * @param parentToolBar * The parent toolbar. */ BrainBrowserWindowToolBarChartAttributes::BrainBrowserWindowToolBarChartAttributes(BrainBrowserWindowToolBar* parentToolBar, const QString& parentObjectName) : BrainBrowserWindowToolBarComponent(parentToolBar) { const QString objectNamePrefix(parentObjectName + ":ChartOneAttributes"); m_cartesianChartAttributesWidget = new CartesianChartAttributesWidget(this, objectNamePrefix); m_matrixChartAttributesWidget = new MatrixChartAttributesWidget(this, objectNamePrefix); m_stackedWidget = new QStackedWidget(); m_stackedWidget->addWidget(m_cartesianChartAttributesWidget); m_stackedWidget->addWidget(m_matrixChartAttributesWidget); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 0); layout->addWidget(m_stackedWidget); layout->addStretch(); } /** * Destructor. */ BrainBrowserWindowToolBarChartAttributes::~BrainBrowserWindowToolBarChartAttributes() { } /** * Update content of this tool bar component. * * @param browserTabContent * Content of the browser tab. */ void BrainBrowserWindowToolBarChartAttributes::updateContent(BrowserTabContent* /*browserTabContent*/) { ChartModelCartesian* cartesianChart = getCartesianChart(); ChartMatrixDisplayProperties* matrixProperties = getChartableMatrixDisplayProperties(); if (cartesianChart != NULL) { m_stackedWidget->setCurrentWidget(m_cartesianChartAttributesWidget); m_cartesianChartAttributesWidget->updateContent(); m_stackedWidget->setEnabled(true); } else if (matrixProperties) { m_stackedWidget->setCurrentWidget(m_matrixChartAttributesWidget); m_matrixChartAttributesWidget->updateContent(); m_stackedWidget->setEnabled(true); } else { m_stackedWidget->setEnabled(false); } } /** * @return Cartesian chart in this widget. Returned value will * be NULL if the chart (or no chart) is not a Cartesian Chart. */ ChartModelCartesian* BrainBrowserWindowToolBarChartAttributes::getCartesianChart() { ChartModelCartesian* cartesianChart = NULL; BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); if (browserTabContent != NULL) { ModelChart* modelChart = browserTabContent->getDisplayedChartOneModel(); if (modelChart != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); const ChartOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartOneDataType(tabIndex); switch (chartType) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: cartesianChart = modelChart->getSelectedDataSeriesChartModel(tabIndex); //dynamic_cast(chart); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: cartesianChart = modelChart->getSelectedFrequencySeriesChartModel(tabIndex); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: cartesianChart = modelChart->getSelectedTimeSeriesChartModel(tabIndex); //dynamic_cast(chart); break; } } } return cartesianChart; } /** * @return Matrix chart interface in this widget. Returned value will * be NULL if the chart (or no chart) is not a Matrix Chart. */ ChartMatrixDisplayProperties* BrainBrowserWindowToolBarChartAttributes::getChartableMatrixDisplayProperties() { ChartMatrixDisplayProperties* matrixDisplayProperties = NULL; BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); if (browserTabContent != NULL) { ModelChart* modelChart = browserTabContent->getDisplayedChartOneModel(); if (modelChart != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); const ChartOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartOneDataType(tabIndex); switch (chartType) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: { ChartableMatrixInterface* matrixInterface = modelChart->getChartableMatrixParcelFileSelectionModel(tabIndex)->getSelectedFileOfType(); if (matrixInterface != NULL) { matrixDisplayProperties = matrixInterface->getChartMatrixDisplayProperties(tabIndex); } } break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: { CaretDataFileSelectionModel* fileModel = modelChart->getChartableMatrixSeriesFileSelectionModel(tabIndex); CaretDataFile* caretFile = fileModel->getSelectedFile(); if (caretFile != NULL) { ChartableMatrixInterface* matrixInterface = dynamic_cast(caretFile); if (matrixInterface != NULL) { matrixDisplayProperties = matrixInterface->getChartMatrixDisplayProperties(tabIndex); } } } break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: break; } } } return matrixDisplayProperties; } /** * Update the graphics. */ void BrainBrowserWindowToolBarChartAttributes::updateGraphics() { EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /* ===========================================================================*/ /** * \class caret::CartesianChartAttributesWidget * \brief Controls for cartesian chart attributes. * \ingroup GuiQt */ /** * Constructor. * * @param brainBrowserWindowToolBarChartAttributes * The parent attributes widget. */ CartesianChartAttributesWidget::CartesianChartAttributesWidget(BrainBrowserWindowToolBarChartAttributes* brainBrowserWindowToolBarChartAttributes, const QString& parentObjectName) : QWidget(brainBrowserWindowToolBarChartAttributes) { m_brainBrowserWindowToolBarChartAttributes = brainBrowserWindowToolBarChartAttributes; QLabel* cartesianLineWidthLabel = new QLabel("Line width "); m_cartesianLineWidthDoubleSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 10000.0, 0.1, 1, this, SLOT(cartesianLineWidthValueChanged(double))); m_cartesianLineWidthDoubleSpinBox->setFixedWidth(65); m_cartesianLineWidthDoubleSpinBox->setToolTip("Set line width"); m_cartesianLineWidthDoubleSpinBox->setObjectName(parentObjectName + ":LineWidth"); WuQMacroManager::instance()->addMacroSupportToObject(m_cartesianLineWidthDoubleSpinBox, "Set chart line width"); QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 0, 0); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(0, 100); gridLayout->addWidget(cartesianLineWidthLabel, 0, 0); gridLayout->addWidget(m_cartesianLineWidthDoubleSpinBox, 0, 1); this->setFixedSize(this->sizeHint()); } /** * Destructor. */ CartesianChartAttributesWidget::~CartesianChartAttributesWidget() { } /** * Update the content of this widget. */ void CartesianChartAttributesWidget::updateContent() { ChartModelCartesian* chart = m_brainBrowserWindowToolBarChartAttributes->getCartesianChart(); if (chart != NULL) { m_cartesianLineWidthDoubleSpinBox->blockSignals(true); m_cartesianLineWidthDoubleSpinBox->setValue(chart->getLineWidth()); m_cartesianLineWidthDoubleSpinBox->blockSignals(false); } } /** * Called when the cartesian line width is changed. * * @param value * New value for line width. */ void CartesianChartAttributesWidget::cartesianLineWidthValueChanged(double value) { ChartModelCartesian* chart = m_brainBrowserWindowToolBarChartAttributes->getCartesianChart(); if (chart != NULL) { chart->setLineWidth(value); m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); } } /* ===========================================================================*/ /** * \class caret::MatrixChartAttributesWidget * \brief Controls for matrix chart attributes. * \ingroup GuiQt */ /** * Constructor. * * @param brainBrowserWindowToolBarChartAttributes * The parent attributes widget. */ MatrixChartAttributesWidget::MatrixChartAttributesWidget(BrainBrowserWindowToolBarChartAttributes* brainBrowserWindowToolBarChartAttributes, const QString& parentObjectName) : QWidget(brainBrowserWindowToolBarChartAttributes), EventListenerInterface() { m_brainBrowserWindowToolBarChartAttributes = brainBrowserWindowToolBarChartAttributes; QLabel* cellWidthLabel = new QLabel("Cell Width"); m_cellWidthSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(1.0, 1000.0, 0.1, 2, this, SLOT(cellWidthSpinBoxValueChanged(double))); m_cellWidthSpinBox->setKeyboardTracking(true); m_cellWidthSpinBox->setToolTip("Set Cell Width"); m_cellWidthSpinBox->setObjectName(parentObjectName + ":Matrix:CellWidth"); WuQMacroManager::instance()->addMacroSupportToObject(m_cellWidthSpinBox, "Set matrix chart cell width"); QLabel* cellHeightLabel = new QLabel("Cell Height"); m_cellHeightSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(1.0, 1000.0, 0.1, 2, this, SLOT(cellHeightSpinBoxValueChanged(double))); m_cellHeightSpinBox->setKeyboardTracking(true); m_cellHeightSpinBox->setToolTip("Set Cell Height"); m_cellHeightSpinBox->setObjectName(parentObjectName + ":Matrix:CellHeight"); WuQMacroManager::instance()->addMacroSupportToObject(m_cellHeightSpinBox, "Set matrix chart cell height"); QAction* resetButtonAction = WuQtUtilities::createAction("Reset", "Reset panning (SHIFT-mouse),zooming (CTRL-mouse), and scale matrix to fit window", this, this, SLOT(resetButtonClicked())); QToolButton* resetToolButton = new QToolButton(); resetToolButton->setDefaultAction(resetButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(resetToolButton); resetToolButton->setObjectName(parentObjectName + ":Matrix:ResetButton"); WuQMacroManager::instance()->addMacroSupportToObject(resetToolButton, "Reset chart matrix scaling"); WuQtUtilities::matchWidgetWidths(m_cellHeightSpinBox, m_cellWidthSpinBox); m_highlightSelectionCheckBox = new QCheckBox("Highlight Selection"); QObject::connect(m_highlightSelectionCheckBox, SIGNAL(clicked(bool)), this, SLOT(highlightSelectionCheckBoxClicked(bool))); m_highlightSelectionCheckBox->setToolTip("Enable selected row/column highlight"); m_highlightSelectionCheckBox->setObjectName(parentObjectName + ":Matrix:EnableHighlight"); WuQMacroManager::instance()->addMacroSupportToObject(m_highlightSelectionCheckBox, "Enable chart matrix selected row height"); m_displayGridLinesCheckBox = new QCheckBox("Show Grid Outline"); QObject::connect(m_displayGridLinesCheckBox, SIGNAL(clicked(bool)), this, SLOT(displayGridLinesCheckBoxClicked(bool))); m_displayGridLinesCheckBox->setToolTip("Show Grid Outline around matrix cells"); m_displayGridLinesCheckBox->setObjectName(parentObjectName + ":Matrix:EnableGridOutline"); WuQMacroManager::instance()->addMacroSupportToObject(m_displayGridLinesCheckBox, "Enable chart matrix grid outline"); m_manualWidgetsGroup = new WuQWidgetObjectGroup(this); m_manualWidgetsGroup->add(m_cellWidthSpinBox); m_manualWidgetsGroup->add(m_cellHeightSpinBox); m_manualWidgetsGroup->add(m_displayGridLinesCheckBox); m_manualWidgetsGroup->add(resetToolButton); const int32_t COLUMN_LABEL = 0; const int32_t COLUMN_WIDGET = 1; QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 2); int32_t rowIndex = gridLayout->rowCount(); gridLayout->addWidget(cellWidthLabel, rowIndex, COLUMN_LABEL); gridLayout->addWidget(m_cellWidthSpinBox, rowIndex, COLUMN_WIDGET); rowIndex++; gridLayout->addWidget(cellHeightLabel, rowIndex, COLUMN_LABEL); gridLayout->addWidget(m_cellHeightSpinBox, rowIndex, COLUMN_WIDGET); rowIndex++; gridLayout->addWidget(resetToolButton, rowIndex, COLUMN_LABEL, 1, 2, Qt::AlignHCenter); rowIndex++; gridLayout->addWidget(m_highlightSelectionCheckBox, rowIndex, COLUMN_LABEL, 1, 2, Qt::AlignLeft); rowIndex++; gridLayout->addWidget(m_displayGridLinesCheckBox, rowIndex, COLUMN_LABEL, 1, 2, Qt::AlignLeft); rowIndex++; this->setFixedSize(this->sizeHint()); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN); } /** * Destructor. */ MatrixChartAttributesWidget::~MatrixChartAttributesWidget() { EventManager::get()->removeAllEventsFromListener(this); } /** * Receive an event. * * @param event * The event. */ void MatrixChartAttributesWidget::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN) { EventBrowserWindowGraphicsRedrawn* redrawEvent = dynamic_cast(event); CaretAssert(event); /* * When the matrix view mode is auto, the OpenGL graphics update the size of * the matrix cells for use by manual mode (cell sizes are in pixels). */ ChartMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableMatrixDisplayProperties(); if (matrixDisplayProperties != NULL) { const BrowserTabContent* tabContent = m_brainBrowserWindowToolBarChartAttributes->getTabContentFromSelectedTab(); if (tabContent->getTabNumber() == redrawEvent->getBrowserWindowIndex()) { updateContent(); } } } } /** * Update the content of this widget. */ void MatrixChartAttributesWidget::updateContent() { ChartMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableMatrixDisplayProperties(); if (matrixDisplayProperties != NULL) { m_cellWidthSpinBox->blockSignals(true); m_cellWidthSpinBox->setValue(matrixDisplayProperties->getCellWidth()); m_cellWidthSpinBox->blockSignals(false); m_cellHeightSpinBox->blockSignals(true); m_cellHeightSpinBox->setValue(matrixDisplayProperties->getCellHeight()); m_cellHeightSpinBox->blockSignals(false); m_highlightSelectionCheckBox->blockSignals(true); m_highlightSelectionCheckBox->setChecked(matrixDisplayProperties->isSelectedRowColumnHighlighted()); m_highlightSelectionCheckBox->blockSignals(false); m_displayGridLinesCheckBox->blockSignals(true); m_displayGridLinesCheckBox->setChecked(matrixDisplayProperties->isGridLinesDisplayed()); m_displayGridLinesCheckBox->blockSignals(false); } } /** * Called when the cell width spin box value is changed. * * @param value * New value for cell width. */ void MatrixChartAttributesWidget::cellWidthSpinBoxValueChanged(double value) { ChartMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableMatrixDisplayProperties(); if (matrixDisplayProperties != NULL) { matrixDisplayProperties->setScaleMode(ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_MANUAL); matrixDisplayProperties->setCellWidth(value); m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); } } /** * Called when the cell height spin box value is changed. * * @param value * New value for cell height. */ void MatrixChartAttributesWidget::cellHeightSpinBoxValueChanged(double value) { ChartMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableMatrixDisplayProperties(); if (matrixDisplayProperties != NULL) { matrixDisplayProperties->setScaleMode(ChartMatrixScaleModeEnum::CHART_MATRIX_SCALE_MANUAL); matrixDisplayProperties->setCellHeight(value); m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); } } /** * Called when the reset button is clicked. */ void MatrixChartAttributesWidget::resetButtonClicked() { ChartMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableMatrixDisplayProperties(); if (matrixDisplayProperties != NULL) { matrixDisplayProperties->resetPropertiesToDefault(); updateContent(); m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); } } /** * Called when the show selection check box is checked. * * @param checked * New checked status. */ void MatrixChartAttributesWidget::highlightSelectionCheckBoxClicked(bool checked) { ChartMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableMatrixDisplayProperties(); if (matrixDisplayProperties != NULL) { matrixDisplayProperties->setSelectedRowColumnHighlighted(checked); m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); } } /** * Called when the display grid lines check box is checked. * * @param checked * New checked status. */ void MatrixChartAttributesWidget::displayGridLinesCheckBoxClicked(bool checked) { ChartMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableMatrixDisplayProperties(); if (matrixDisplayProperties != NULL) { matrixDisplayProperties->setGridLinesDisplayed(checked); m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); } } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarChartAttributes.h000066400000000000000000000117151360521144700277340ustar00rootroot00000000000000#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ATTRIBUTES_H__ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ATTRIBUTES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainBrowserWindowToolBarComponent.h" #include "EventListenerInterface.h" class QCheckBox; class QDoubleSpinBox; class QStackedWidget; namespace caret { class CartesianChartAttributesWidget; class ChartMatrixDisplayProperties; class ChartModelCartesian; class EnumComboBoxTemplate; class MatrixChartAttributesWidget; class WuQWidgetObjectGroup; class BrainBrowserWindowToolBarChartAttributes : public BrainBrowserWindowToolBarComponent { Q_OBJECT public: BrainBrowserWindowToolBarChartAttributes(BrainBrowserWindowToolBar* parentToolBar, const QString& parentObjectName); virtual ~BrainBrowserWindowToolBarChartAttributes(); virtual void updateContent(BrowserTabContent* browserTabContent); // ADD_NEW_METHODS_HERE private: BrainBrowserWindowToolBarChartAttributes(const BrainBrowserWindowToolBarChartAttributes&); BrainBrowserWindowToolBarChartAttributes& operator=(const BrainBrowserWindowToolBarChartAttributes&); ChartModelCartesian* getCartesianChart(); ChartMatrixDisplayProperties* getChartableMatrixDisplayProperties(); void updateGraphics(); CartesianChartAttributesWidget* m_cartesianChartAttributesWidget; MatrixChartAttributesWidget* m_matrixChartAttributesWidget; QStackedWidget* m_stackedWidget; // ADD_NEW_MEMBERS_HERE friend class CartesianChartAttributesWidget; friend class MatrixChartAttributesWidget; }; /* * While this should be a private class in the class above * Qt's meta-object compiler (moc) does not allow it to be. */ class CartesianChartAttributesWidget : public QWidget { Q_OBJECT public: CartesianChartAttributesWidget(BrainBrowserWindowToolBarChartAttributes* brainBrowserWindowToolBarChartAttributes, const QString& parentObjectName); ~CartesianChartAttributesWidget(); virtual void updateContent(); private slots: void cartesianLineWidthValueChanged(double value); private: BrainBrowserWindowToolBarChartAttributes* m_brainBrowserWindowToolBarChartAttributes; QDoubleSpinBox* m_cartesianLineWidthDoubleSpinBox; }; /* * While this should be a private class in the class above * Qt's meta-object compiler (moc) does not allow it to be. */ class MatrixChartAttributesWidget : public QWidget, public EventListenerInterface { Q_OBJECT public: MatrixChartAttributesWidget(BrainBrowserWindowToolBarChartAttributes* brainBrowserWindowToolBarChartAttributes, const QString& parentObjectName); ~MatrixChartAttributesWidget(); virtual void receiveEvent(Event* event); virtual void updateContent(); private slots: void cellWidthSpinBoxValueChanged(double value); void cellHeightSpinBoxValueChanged(double value); void highlightSelectionCheckBoxClicked(bool checked); void displayGridLinesCheckBoxClicked(bool checked); void resetButtonClicked(); private: BrainBrowserWindowToolBarChartAttributes* m_brainBrowserWindowToolBarChartAttributes; QDoubleSpinBox* m_cellWidthSpinBox; QDoubleSpinBox* m_cellHeightSpinBox; WuQWidgetObjectGroup* m_manualWidgetsGroup; QCheckBox* m_highlightSelectionCheckBox; QCheckBox* m_displayGridLinesCheckBox; }; #ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ATTRIBUTES_DECLARE__ // #endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ATTRIBUTES_DECLARE__ } // namespace #endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_ATTRIBUTES_H__ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarChartAxes.cxx000066400000000000000000000451421360521144700270620ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_AXES_DECLARE__ #include "BrainBrowserWindowToolBarChartAxes.h" #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_AXES_DECLARE__ #include #include #include #include #include "BrowserTabContent.h" #include "BrainBrowserWindowToolBar.h" #include "CaretAssert.h" #include "ChartAxis.h" #include "ChartAxisCartesian.h" #include "ChartModelDataSeries.h" #include "ChartModelFrequencySeries.h" #include "ChartModelTimeSeries.h" #include "ModelChart.h" #include "WuQMacroManager.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::BrainBrowserWindowToolBarChartAxes * \brief Component of toolbar for chart axes. * \ingroup GuiQt */ /** * Constructor. * * @param parentToolBar * parent toolbar. */ BrainBrowserWindowToolBarChartAxes::BrainBrowserWindowToolBarChartAxes(BrainBrowserWindowToolBar* parentToolBar, const QString& parentObjectName) : BrainBrowserWindowToolBarComponent(parentToolBar), m_parentToolBar(parentToolBar) { const QString objectNamePrefix(parentObjectName + ":ChartOneAxes:"); WuQMacroManager* macroManager = WuQMacroManager::instance(); QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 0, 0); gridLayout->addWidget(new QLabel("Axis"), 0, 0, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Auto"), 0, 1, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Min"), 0, 2, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Max"), 0, 3, Qt::AlignHCenter); createAxisWidgets(gridLayout, m_bottomAxisLabel, m_bottomAxisAutoRangeScaleCheckBox, m_bottomAxisMinimumValueSpinBox, m_bottomAxisMaximumValueSpinBox, m_bottomAxisWidgetGroup); QObject::connect(m_bottomAxisAutoRangeScaleCheckBox, SIGNAL(clicked(bool)), this, SLOT(bottomAxisAutoRangeScaleCheckBoxClicked(bool))); QObject::connect(m_bottomAxisMinimumValueSpinBox, SIGNAL(valueChanged(double)), this, SLOT(bottomAxisValueChanged(double))); QObject::connect(m_bottomAxisMaximumValueSpinBox, SIGNAL(valueChanged(double)), this, SLOT(bottomAxisValueChanged(double))); m_bottomAxisAutoRangeScaleCheckBox->setObjectName(objectNamePrefix + "EnableBottomAxis"); macroManager->addMacroSupportToObject(m_bottomAxisAutoRangeScaleCheckBox, "Enable chart bottom axis auto scale"); m_bottomAxisMinimumValueSpinBox->setObjectName(objectNamePrefix + "BottomAxisMinimumValue"); macroManager->addMacroSupportToObject(m_bottomAxisMinimumValueSpinBox, "Set chart bottom axis minimum"); m_bottomAxisMaximumValueSpinBox->setObjectName(objectNamePrefix + "BottomAxisMaximumValue"); macroManager->addMacroSupportToObject(m_bottomAxisMaximumValueSpinBox, "Set chart bottom axis maximum"); createAxisWidgets(gridLayout, m_leftAxisLabel, m_leftAxisAutoRangeScaleCheckBox, m_leftAxisMinimumValueSpinBox, m_leftAxisMaximumValueSpinBox, m_leftAxisWidgetGroup); QObject::connect(m_leftAxisAutoRangeScaleCheckBox, SIGNAL(clicked(bool)), this, SLOT(leftAxisAutoRangeScaleCheckBoxClicked(bool))); QObject::connect(m_leftAxisMinimumValueSpinBox, SIGNAL(valueChanged(double)), this, SLOT(leftAxisValueChanged(double))); QObject::connect(m_leftAxisMaximumValueSpinBox, SIGNAL(valueChanged(double)), this, SLOT(leftAxisValueChanged(double))); m_leftAxisAutoRangeScaleCheckBox->setObjectName(objectNamePrefix + "EnableLeftAxis"); macroManager->addMacroSupportToObject(m_leftAxisAutoRangeScaleCheckBox, "Enable chart left axis auto scale"); m_leftAxisMinimumValueSpinBox->setObjectName(objectNamePrefix + "LeftAxisMinimumValue"); macroManager->addMacroSupportToObject(m_leftAxisMinimumValueSpinBox, "Set chart left axis minimum value"); m_leftAxisMaximumValueSpinBox->setObjectName(objectNamePrefix + "LeftAxisMaximumValue"); macroManager->addMacroSupportToObject(m_leftAxisMaximumValueSpinBox, "Set chart left axis maximum value"); // createAxisWidgets(gridLayout, // m_topAxisLabel, // m_topAxisAutoRangeScaleCheckBox, // m_topAxisMinimumValueSpinBox, // m_topAxisMaximumValueSpinBox, // m_topAxisWidgetGroup); // // createAxisWidgets(gridLayout, // m_rightAxisLabel, // m_rightAxisAutoRangeScaleCheckBox, // m_rightAxisMinimumValueSpinBox, // m_rightAxisMaximumValueSpinBox, // m_rightAxisWidgetGroup); } /** * Destructor. */ BrainBrowserWindowToolBarChartAxes::~BrainBrowserWindowToolBarChartAxes() { } /** * Create the widgets for an axis. * * @param gridLayout * Layout in which axis widgets are displayed. * @param nameLabel * Label that contains name of axis. * @param autoRangeScaleCheckBox * Checkbox for enabling auto range scale. * @param minimumValueSpinBox * Spin box for minimum value. * @param maximumValueSpinBox * Spin box for maximum value. * @param widgetGroup * Widget group for the axis' widgets. */ void BrainBrowserWindowToolBarChartAxes::createAxisWidgets(QGridLayout* gridLayout, QLabel*& nameLabel, QCheckBox*& autoRangeScaleCheckBox, QDoubleSpinBox*& minimumValueSpinBox, QDoubleSpinBox*& maximumValueSpinBox, WuQWidgetObjectGroup*& widgetGroup) { const int32_t spinBoxWidth = 100; nameLabel = new QLabel(); autoRangeScaleCheckBox = new QCheckBox(" "); WuQtUtilities::setWordWrappedToolTip(autoRangeScaleCheckBox, "Axis Auto Range\n\n" "When checked, the minimum and maximum values are " "automatically adjusted to show the full range " "of values for the axis.\n\n" "When not checked, the user may adjust the minimum " "and maximum values for the axis to show a " "desired range of data for the axis.\n\n" "Changing the status from not checked to checked " "will reset the minimum and maximum values to show " "the full range of data."); minimumValueSpinBox = new QDoubleSpinBox(); minimumValueSpinBox->setFixedWidth(spinBoxWidth); minimumValueSpinBox->setMinimum(-std::numeric_limits::max()); minimumValueSpinBox->setMaximum(std::numeric_limits::max()); minimumValueSpinBox->setSingleStep(1.0); minimumValueSpinBox->setDecimals(2); WuQtUtilities::setWordWrappedToolTip(minimumValueSpinBox, "Minimum value displayed for the axis"); maximumValueSpinBox = new QDoubleSpinBox(); maximumValueSpinBox->setFixedWidth(spinBoxWidth); maximumValueSpinBox->setMinimum(-std::numeric_limits::max()); maximumValueSpinBox->setMaximum(std::numeric_limits::max()); maximumValueSpinBox->setSingleStep(1.0); maximumValueSpinBox->setDecimals(2); WuQtUtilities::setWordWrappedToolTip(maximumValueSpinBox, "Maximum value displayed for the axis"); widgetGroup = new WuQWidgetObjectGroup(this); widgetGroup->add(nameLabel); widgetGroup->add(autoRangeScaleCheckBox); widgetGroup->add(minimumValueSpinBox); widgetGroup->add(maximumValueSpinBox); const int rowIndex = gridLayout->rowCount(); gridLayout->addWidget(nameLabel, rowIndex, 0, Qt::AlignLeft); gridLayout->addWidget(autoRangeScaleCheckBox, rowIndex, 1, Qt::AlignHCenter); gridLayout->addWidget(minimumValueSpinBox, rowIndex, 2, Qt::AlignHCenter); gridLayout->addWidget(maximumValueSpinBox, rowIndex, 3, Qt::AlignHCenter); } /** * Update content of this tool bar component. * * @param browserTabContent * Content of the browser tab. */ void BrainBrowserWindowToolBarChartAxes::updateContent(BrowserTabContent* /*browserTabContent*/) { m_bottomAxisWidgetGroup->blockAllSignals(true); m_leftAxisWidgetGroup->blockAllSignals(true); // m_topAxisWidgetGroup->blockAllSignals(true); // m_rightAxisWidgetGroup->blockAllSignals(true); ChartModelCartesian* cartesianChart = getCartesianChart(); if (cartesianChart != NULL) { if (cartesianChart != NULL) { updateAxisWidgets(cartesianChart->getLeftAxis(), m_leftAxisLabel, m_leftAxisAutoRangeScaleCheckBox, m_leftAxisMinimumValueSpinBox, m_leftAxisMaximumValueSpinBox, m_leftAxisWidgetGroup); updateAxisWidgets(cartesianChart->getBottomAxis(), m_bottomAxisLabel, m_bottomAxisAutoRangeScaleCheckBox, m_bottomAxisMinimumValueSpinBox, m_bottomAxisMaximumValueSpinBox, m_bottomAxisWidgetGroup); // updateAxisWidgets(lineSeriesChart->getRightAxis(), // m_rightAxisLabel, // m_rightAxisAutoRangeScaleCheckBox, // m_rightAxisMinimumValueSpinBox, // m_rightAxisMaximumValueSpinBox, // m_rightAxisWidgetGroup); // // updateAxisWidgets(lineSeriesChart->getTopAxis(), // m_topAxisLabel, // m_topAxisAutoRangeScaleCheckBox, // m_topAxisMinimumValueSpinBox, // m_topAxisMaximumValueSpinBox, // m_topAxisWidgetGroup); } } m_bottomAxisWidgetGroup->blockAllSignals(false); m_leftAxisWidgetGroup->blockAllSignals(false); // m_topAxisWidgetGroup->blockAllSignals(false); // m_rightAxisWidgetGroup->blockAllSignals(false); } /** * @return Cartesian chart in this widget. Returned value will * be NULL if the chart (or no chart) is not a Cartesian Chart. */ ChartModelCartesian* BrainBrowserWindowToolBarChartAxes::getCartesianChart() { ChartModelCartesian* cartesianChart = NULL; BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); if (browserTabContent != NULL) { ModelChart* modelChart = browserTabContent->getDisplayedChartOneModel(); if (modelChart != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); const ChartOneDataTypeEnum::Enum chartType = modelChart->getSelectedChartOneDataType(tabIndex); switch (chartType) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: cartesianChart = modelChart->getSelectedDataSeriesChartModel(tabIndex); //dynamic_cast(chart); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: cartesianChart = modelChart->getSelectedFrequencySeriesChartModel(tabIndex); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: cartesianChart = modelChart->getSelectedTimeSeriesChartModel(tabIndex); //dynamic_cast(chart); break; } } } return cartesianChart; } /** * Update the widgets for an axis. * * @param chartAxis * Source axis containing data. * @param nameLabel * Label that contains name of axis. * @param autoRangeScaleCheckBox * Checkbox for enabling auto range scale. * @param minimumValueSpinBox * Spin box for minimum value. * @param maximumValueSpinBox * Spin box for maximum value. * @param widgetGroup * Widget group for the axis' widgets. */ void BrainBrowserWindowToolBarChartAxes::updateAxisWidgets(const ChartAxis* chartAxis, QLabel* nameLabel, QCheckBox* autoRangeScaleCheckBox, QDoubleSpinBox* minimumValueSpinBox, QDoubleSpinBox* maximumValueSpinBox, WuQWidgetObjectGroup* widgetGroup) { if (chartAxis == NULL) { return; } const ChartAxisCartesian* chartAxisCartesian = dynamic_cast(chartAxis); CaretAssert(chartAxisCartesian); const bool visible = chartAxis->isVisible(); if (visible) { nameLabel->setText(chartAxis->getText()); autoRangeScaleCheckBox->setChecked(chartAxis->isAutoRangeScaleEnabled()); const float minValue = chartAxisCartesian->getMinimumValue(); const float maxValue = chartAxisCartesian->getMaximumValue(); minimumValueSpinBox->setValue(minValue); maximumValueSpinBox->setValue(maxValue); } widgetGroup->setVisible(visible); } /** * Called when left axis auto range scale checkbox is clicked. * * @param checked * New check status. */ void BrainBrowserWindowToolBarChartAxes::leftAxisAutoRangeScaleCheckBoxClicked(bool checked) { ChartModelCartesian* cartesianChart = getCartesianChart(); if (cartesianChart != NULL) { cartesianChart->getLeftAxis()->setAutoRangeScaleEnabled(checked); if (checked) { updateContent(getTabContentFromSelectedTab()); invalidateColoringAndUpdateGraphicsWindow(); } } } /** * Called when left axis minimum or maximum value is changed. * * @param value * New value. */ void BrainBrowserWindowToolBarChartAxes::leftAxisValueChanged(double /*value*/) { ChartModelCartesian* cartesianChart = getCartesianChart(); if (cartesianChart != NULL) { m_leftAxisAutoRangeScaleCheckBox->setChecked(false); ChartAxisCartesian* axis = dynamic_cast(cartesianChart->getLeftAxis()); CaretAssert(axis); axis->setAutoRangeScaleEnabled(false); axis->setMinimumValue(m_leftAxisMinimumValueSpinBox->value()); axis->setMaximumValue(m_leftAxisMaximumValueSpinBox->value()); invalidateColoringAndUpdateGraphicsWindow(); } } /** * Called when bottom axis auto range scale checkbox is clicked. * * @param checked * New check status. */ void BrainBrowserWindowToolBarChartAxes::bottomAxisAutoRangeScaleCheckBoxClicked(bool checked) { ChartModelCartesian* cartesianChart = getCartesianChart(); if (cartesianChart != NULL) { cartesianChart->getBottomAxis()->setAutoRangeScaleEnabled(checked); if (checked) { updateContent(getTabContentFromSelectedTab()); invalidateColoringAndUpdateGraphicsWindow(); } } } /** * Called when bottom axis minimum or maximum value is changed. * * @param value * New value. */ void BrainBrowserWindowToolBarChartAxes::bottomAxisValueChanged(double /*value*/) { ChartModelCartesian* cartesianChart = getCartesianChart(); if (cartesianChart != NULL) { m_bottomAxisAutoRangeScaleCheckBox->setChecked(false); ChartAxisCartesian* axis = dynamic_cast(cartesianChart->getBottomAxis()); CaretAssert(axis); axis->setAutoRangeScaleEnabled(false); axis->setMinimumValue(m_bottomAxisMinimumValueSpinBox->value()); axis->setMaximumValue(m_bottomAxisMaximumValueSpinBox->value()); invalidateColoringAndUpdateGraphicsWindow(); } } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarChartAxes.h000066400000000000000000000110441360521144700265010ustar00rootroot00000000000000#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_AXES_H__ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_AXES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ class QCheckBox; class QDoubleSpinBox; class QGridLayout; class QLabel; #include "BrainBrowserWindowToolBarComponent.h" namespace caret { class ChartAxis; class ChartModelCartesian; class BrainBrowserWindowToolBar; class WuQWidgetObjectGroup; class BrainBrowserWindowToolBarChartAxes : public BrainBrowserWindowToolBarComponent { Q_OBJECT public: BrainBrowserWindowToolBarChartAxes(BrainBrowserWindowToolBar* parentToolBar, const QString& parentObjectName); virtual ~BrainBrowserWindowToolBarChartAxes(); virtual void updateContent(BrowserTabContent* browserTabContent); private slots: void leftAxisAutoRangeScaleCheckBoxClicked(bool checked); void leftAxisValueChanged(double value); void bottomAxisAutoRangeScaleCheckBoxClicked(bool checked); void bottomAxisValueChanged(double value); private: BrainBrowserWindowToolBarChartAxes(const BrainBrowserWindowToolBarChartAxes&); BrainBrowserWindowToolBarChartAxes& operator=(const BrainBrowserWindowToolBarChartAxes&); void createAxisWidgets(QGridLayout* gridLayout, QLabel*& nameLabel, QCheckBox*& autoRangeScaleCheckBox, QDoubleSpinBox*& minimumValueSpinBox, QDoubleSpinBox*& maximumValueSpinBox, WuQWidgetObjectGroup*& widgetGroup); void updateAxisWidgets(const ChartAxis* chartAxis, QLabel* nameLabel, QCheckBox* autoRangeScaleCheckBox, QDoubleSpinBox* minimumValueSpinBox, QDoubleSpinBox* maximumValueSpinBox, WuQWidgetObjectGroup* widgetGroup); ChartModelCartesian* getCartesianChart(); public: // ADD_NEW_METHODS_HERE private: BrainBrowserWindowToolBar* m_parentToolBar; QLabel* m_bottomAxisLabel; QCheckBox* m_bottomAxisAutoRangeScaleCheckBox; QDoubleSpinBox* m_bottomAxisMinimumValueSpinBox; QDoubleSpinBox* m_bottomAxisMaximumValueSpinBox; WuQWidgetObjectGroup* m_bottomAxisWidgetGroup; QLabel* m_leftAxisLabel; QCheckBox* m_leftAxisAutoRangeScaleCheckBox; QDoubleSpinBox* m_leftAxisMinimumValueSpinBox; QDoubleSpinBox* m_leftAxisMaximumValueSpinBox; WuQWidgetObjectGroup* m_leftAxisWidgetGroup; // QLabel* m_topAxisLabel; // // QCheckBox* m_topAxisAutoRangeScaleCheckBox; // // QDoubleSpinBox* m_topAxisMinimumValueSpinBox; // // QDoubleSpinBox* m_topAxisMaximumValueSpinBox; // // WuQWidgetObjectGroup* m_topAxisWidgetGroup; // // QLabel* m_rightAxisLabel; // // QCheckBox* m_rightAxisAutoRangeScaleCheckBox; // // QDoubleSpinBox* m_rightAxisMinimumValueSpinBox; // // QDoubleSpinBox* m_rightAxisMaximumValueSpinBox; // // WuQWidgetObjectGroup* m_rightAxisWidgetGroup; // ADD_NEW_MEMBERS_HERE }; #ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_AXES_DECLARE__ // #endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_AXES_DECLARE__ } // namespace #endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_AXES_H__ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.cxx000066400000000000000000000377371360521144700310150ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ATTRIBUTES_DECLARE__ #include "BrainBrowserWindowToolBarChartTwoAttributes.h" #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ATTRIBUTES_DECLARE__ #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretDataFile.h" #include "CaretDataFileSelectionModel.h" #include "EnumComboBoxTemplate.h" #include "CaretMappableDataFile.h" #include "ChartTwoMatrixDisplayProperties.h" #include "EventChartTwoAttributesChanged.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "ModelChartTwo.h" #include "WuQFactory.h" #include "WuQMacroManager.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::BrainBrowserWindowToolBarChartTwoAttributes * \brief Controls for chart attributes. * \ingroup GuiQt */ /** * Constructor. * * @param parentToolBar * The parent toolbar. * @param parentObjectName * Name of parent for macros */ BrainBrowserWindowToolBarChartTwoAttributes::BrainBrowserWindowToolBarChartTwoAttributes(BrainBrowserWindowToolBar* parentToolBar, const QString& parentObjectName) : BrainBrowserWindowToolBarComponent(parentToolBar) { const QString objectNamePrefix(parentObjectName + ":ChartTwoAttributes"); m_cartesianChartAttributesWidget = new CartesianChartTwoAttributesWidget(this, objectNamePrefix); m_matrixChartTwoAttributesWidget = new MatrixChartTwoAttributesWidget(this, objectNamePrefix); m_stackedWidget = new QStackedWidget(); m_stackedWidget->addWidget(m_cartesianChartAttributesWidget); m_stackedWidget->addWidget(m_matrixChartTwoAttributesWidget); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 0); layout->addWidget(m_stackedWidget); layout->addStretch(); } /** * Destructor. */ BrainBrowserWindowToolBarChartTwoAttributes::~BrainBrowserWindowToolBarChartTwoAttributes() { } /** * Update content of this tool bar component. * * @param browserTabContent * Content of the browser tab. */ void BrainBrowserWindowToolBarChartTwoAttributes::updateContent(BrowserTabContent* browserTabContent) { if (browserTabContent != NULL) { ModelChartTwo* modelChartTwo = browserTabContent->getDisplayedChartTwoModel(); const int32_t tabIndex = browserTabContent->getTabNumber(); if (modelChartTwo != NULL) { switch (modelChartTwo->getSelectedChartTwoDataType(tabIndex)) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: m_stackedWidget->setCurrentWidget(m_cartesianChartAttributesWidget); m_cartesianChartAttributesWidget->updateContent(); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: m_stackedWidget->setCurrentWidget(m_matrixChartTwoAttributesWidget); m_matrixChartTwoAttributesWidget->updateContent(); break; } } } } /** * @return Matrix chart interface in this widget. Returned value will * be NULL if the chart (or no chart) is not a Matrix Chart. */ ChartTwoMatrixDisplayProperties* BrainBrowserWindowToolBarChartTwoAttributes::getChartableTwoMatrixDisplayProperties() { ChartTwoMatrixDisplayProperties* matrixDisplayProperties = NULL; BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); if (browserTabContent != NULL) { matrixDisplayProperties = browserTabContent->getChartTwoMatrixDisplayProperties(); } return matrixDisplayProperties; } /** * Update the graphics. */ void BrainBrowserWindowToolBarChartTwoAttributes::updateGraphics() { EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /* ===========================================================================*/ /** * \class caret::CartesianChartTwoAttributesWidget * \brief Controls for cartesian chart attributes. * \ingroup GuiQt */ /** * Constructor. * * @param brainBrowserWindowToolBarChartAttributes * The parent attributes widget. */ CartesianChartTwoAttributesWidget::CartesianChartTwoAttributesWidget(BrainBrowserWindowToolBarChartTwoAttributes* brainBrowserWindowToolBarChartAttributes, const QString& parentObjectName) : QWidget(brainBrowserWindowToolBarChartAttributes) { m_brainBrowserWindowToolBarChartAttributes = brainBrowserWindowToolBarChartAttributes; QLabel* cartesianLineWidthLabel = new QLabel("Line width "); m_cartesianLineWidthDoubleSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 10000.0, 0.1, 1, this, SLOT(cartesianLineWidthValueChanged(double))); m_cartesianLineWidthDoubleSpinBox->setFixedWidth(65); m_cartesianLineWidthDoubleSpinBox->setToolTip("Width of line"); m_cartesianLineWidthDoubleSpinBox->setObjectName(parentObjectName + ":LineWidth"); WuQMacroManager::instance()->addMacroSupportToObject(m_cartesianLineWidthDoubleSpinBox, "Set cartesian chart line width"); QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 0, 0); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(0, 100); gridLayout->addWidget(cartesianLineWidthLabel, 0, 0); gridLayout->addWidget(m_cartesianLineWidthDoubleSpinBox, 0, 1); this->setFixedSize(this->sizeHint()); } /** * Destructor. */ CartesianChartTwoAttributesWidget::~CartesianChartTwoAttributesWidget() { } /** * Update the content of this widget. */ void CartesianChartTwoAttributesWidget::updateContent() { } /** * Called when the cartesian line width is changed. * * @param value * New value for line width. */ void CartesianChartTwoAttributesWidget::cartesianLineWidthValueChanged(double /*value*/) { } /* ===========================================================================*/ /** * \class caret::MatrixChartTwoAttributesWidget * \brief Controls for matrix chart attributes. * \ingroup GuiQt */ /** * Constructor. * * @param brainBrowserWindowToolBarChartAttributes * The parent attributes widget. */ MatrixChartTwoAttributesWidget::MatrixChartTwoAttributesWidget(BrainBrowserWindowToolBarChartTwoAttributes* brainBrowserWindowToolBarChartAttributes, const QString& parentObjectName) : QWidget(brainBrowserWindowToolBarChartAttributes), EventListenerInterface() { m_brainBrowserWindowToolBarChartAttributes = brainBrowserWindowToolBarChartAttributes; QLabel* cellWidthLabel = new QLabel("Cell Width"); const float minPercent = 1.0; const float maxPercent = 100000.0; m_cellWidthPercentageSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(minPercent, maxPercent, 1.0, 1, this, SLOT(valueChanged())); m_cellWidthPercentageSpinBox->setToolTip("Percentage of tab width filled with matrix"); m_cellWidthPercentageSpinBox->setKeyboardTracking(false); m_cellWidthPercentageSpinBox->setSuffix("%"); m_cellWidthPercentageSpinBox->setObjectName(parentObjectName + ":CellWidth"); WuQMacroManager::instance()->addMacroSupportToObject(m_cellWidthPercentageSpinBox, "Set matrix chart cell width"); QLabel* cellHeightLabel = new QLabel("Cell Height"); m_cellHeightPercentageSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(minPercent, maxPercent, 1.0, 1, this, SLOT(valueChanged())); m_cellHeightPercentageSpinBox->setToolTip("Percentage of tab height filled with matrix"); m_cellHeightPercentageSpinBox->setKeyboardTracking(false); m_cellHeightPercentageSpinBox->setSuffix("%"); m_cellHeightPercentageSpinBox->setObjectName(parentObjectName + ":CellHeight"); WuQMacroManager::instance()->addMacroSupportToObject(m_cellHeightPercentageSpinBox, "Set matrix chart cell height"); WuQtUtilities::matchWidgetWidths(m_cellHeightPercentageSpinBox, m_cellWidthPercentageSpinBox); m_highlightSelectionCheckBox = new QCheckBox("Highlight Selection"); m_highlightSelectionCheckBox->setToolTip("Highlight selected row/column in the matrix"); QObject::connect(m_highlightSelectionCheckBox, SIGNAL(clicked(bool)), this, SLOT(valueChanged())); m_highlightSelectionCheckBox->setObjectName(parentObjectName + ":HighlightSelection"); WuQMacroManager::instance()->addMacroSupportToObject(m_highlightSelectionCheckBox, "Enable outline of selected chart matrix row/column"); m_displayGridLinesCheckBox = new QCheckBox("Show Grid Outline"); QObject::connect(m_displayGridLinesCheckBox, SIGNAL(clicked(bool)), this, SLOT(valueChanged())); m_displayGridLinesCheckBox->setToolTip("Outline cells in the matrix"); m_displayGridLinesCheckBox->setObjectName(parentObjectName + ":EnableGridOutline"); WuQMacroManager::instance()->addMacroSupportToObject(m_displayGridLinesCheckBox, "Enable matrix chart grid outline"); m_manualWidgetsGroup = new WuQWidgetObjectGroup(this); m_manualWidgetsGroup->add(m_cellWidthPercentageSpinBox); m_manualWidgetsGroup->add(m_cellHeightPercentageSpinBox); m_manualWidgetsGroup->add(m_displayGridLinesCheckBox); const int32_t COLUMN_LABEL = 0; const int32_t COLUMN_WIDGET = 1; QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 2); int32_t rowIndex = gridLayout->rowCount(); gridLayout->addWidget(cellWidthLabel, rowIndex, COLUMN_LABEL); gridLayout->addWidget(m_cellWidthPercentageSpinBox, rowIndex, COLUMN_WIDGET); rowIndex++; gridLayout->addWidget(cellHeightLabel, rowIndex, COLUMN_LABEL); gridLayout->addWidget(m_cellHeightPercentageSpinBox, rowIndex, COLUMN_WIDGET); rowIndex++; gridLayout->addWidget(m_highlightSelectionCheckBox, rowIndex, COLUMN_LABEL, 1, 2, Qt::AlignLeft); rowIndex++; gridLayout->addWidget(m_displayGridLinesCheckBox, rowIndex, COLUMN_LABEL, 1, 2, Qt::AlignLeft); rowIndex++; this->setFixedSize(this->sizeHint()); } /** * Destructor. */ MatrixChartTwoAttributesWidget::~MatrixChartTwoAttributesWidget() { EventManager::get()->removeAllEventsFromListener(this); } /** * Receive an event. * * @param event * The event. */ void MatrixChartTwoAttributesWidget::receiveEvent(Event* /*event*/) { } /** * Update the content of this widget. */ void MatrixChartTwoAttributesWidget::updateContent() { ChartTwoMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableTwoMatrixDisplayProperties(); if (matrixDisplayProperties != NULL) { m_cellWidthPercentageSpinBox->blockSignals(true); m_cellWidthPercentageSpinBox->setValue(matrixDisplayProperties->getCellPercentageZoomWidth()); m_cellWidthPercentageSpinBox->blockSignals(false); m_cellHeightPercentageSpinBox->blockSignals(true); m_cellHeightPercentageSpinBox->setValue(matrixDisplayProperties->getCellPercentageZoomHeight()); m_cellHeightPercentageSpinBox->blockSignals(false); m_highlightSelectionCheckBox->blockSignals(true); m_highlightSelectionCheckBox->setChecked(matrixDisplayProperties->isSelectedRowColumnHighlighted()); m_highlightSelectionCheckBox->blockSignals(false); m_displayGridLinesCheckBox->blockSignals(true); m_displayGridLinesCheckBox->setChecked(matrixDisplayProperties->isGridLinesDisplayed()); m_displayGridLinesCheckBox->blockSignals(false); } } /** * Gets called when user changes value of a user-interface component. */ void MatrixChartTwoAttributesWidget::valueChanged() { ChartTwoMatrixDisplayProperties* matrixDisplayProperties = m_brainBrowserWindowToolBarChartAttributes->getChartableTwoMatrixDisplayProperties(); if (matrixDisplayProperties != NULL) { matrixDisplayProperties->setCellPercentageZoomWidth(m_cellWidthPercentageSpinBox->value()); matrixDisplayProperties->setCellPercentageZoomHeight(m_cellHeightPercentageSpinBox->value()); matrixDisplayProperties->setSelectedRowColumnHighlighted(m_highlightSelectionCheckBox->isChecked()); matrixDisplayProperties->setGridLinesDisplayed(m_displayGridLinesCheckBox->isChecked()); BrowserTabContent* tabContent = m_brainBrowserWindowToolBarChartAttributes->getTabContentFromSelectedTab(); CaretAssert(tabContent); tabContent->updateChartModelYokedBrowserTabs(); m_brainBrowserWindowToolBarChartAttributes->updateGraphics(); EventManager::get()->sendEvent(EventUserInterfaceUpdate().addToolBar().getPointer()); } } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarChartTwoAttributes.h000066400000000000000000000114331360521144700304230ustar00rootroot00000000000000#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ATTRIBUTES_H__ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ATTRIBUTES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainBrowserWindowToolBarComponent.h" #include "EventListenerInterface.h" class QCheckBox; class QDoubleSpinBox; class QStackedWidget; namespace caret { class CartesianChartTwoAttributesWidget; class ChartTwoMatrixDisplayProperties; class EnumComboBoxTemplate; class MatrixChartTwoAttributesWidget; class WuQWidgetObjectGroup; class BrainBrowserWindowToolBarChartTwoAttributes : public BrainBrowserWindowToolBarComponent { Q_OBJECT public: BrainBrowserWindowToolBarChartTwoAttributes(BrainBrowserWindowToolBar* parentToolBar, const QString& parentObjectName); virtual ~BrainBrowserWindowToolBarChartTwoAttributes(); virtual void updateContent(BrowserTabContent* browserTabContent); // ADD_NEW_METHODS_HERE private: BrainBrowserWindowToolBarChartTwoAttributes(const BrainBrowserWindowToolBarChartTwoAttributes&); BrainBrowserWindowToolBarChartTwoAttributes& operator=(const BrainBrowserWindowToolBarChartTwoAttributes&); //ChartModelCartesian* getCartesianChart(); ChartTwoMatrixDisplayProperties* getChartableTwoMatrixDisplayProperties(); void updateGraphics(); CartesianChartTwoAttributesWidget* m_cartesianChartAttributesWidget; MatrixChartTwoAttributesWidget* m_matrixChartTwoAttributesWidget; QStackedWidget* m_stackedWidget; // ADD_NEW_MEMBERS_HERE friend class CartesianChartTwoAttributesWidget; friend class MatrixChartTwoAttributesWidget; }; /* * While this should be a private class in the class above * Qt's meta-object compiler (moc) does not allow it to be. */ class CartesianChartTwoAttributesWidget : public QWidget { Q_OBJECT public: CartesianChartTwoAttributesWidget(BrainBrowserWindowToolBarChartTwoAttributes* brainBrowserWindowToolBarChartAttributes, const QString& parentObjectName); ~CartesianChartTwoAttributesWidget(); virtual void updateContent(); private slots: void cartesianLineWidthValueChanged(double value); private: BrainBrowserWindowToolBarChartTwoAttributes* m_brainBrowserWindowToolBarChartAttributes; QDoubleSpinBox* m_cartesianLineWidthDoubleSpinBox; }; /* * While this should be a private class in the class above * Qt's meta-object compiler (moc) does not allow it to be. */ class MatrixChartTwoAttributesWidget : public QWidget, public EventListenerInterface { Q_OBJECT public: MatrixChartTwoAttributesWidget(BrainBrowserWindowToolBarChartTwoAttributes* brainBrowserWindowToolBarChartAttributes, const QString& parentObjectName); ~MatrixChartTwoAttributesWidget(); virtual void receiveEvent(Event* event); virtual void updateContent(); private slots: void valueChanged(); private: BrainBrowserWindowToolBarChartTwoAttributes* m_brainBrowserWindowToolBarChartAttributes; QDoubleSpinBox* m_cellWidthPercentageSpinBox; QDoubleSpinBox* m_cellHeightPercentageSpinBox; QCheckBox* m_highlightSelectionCheckBox; QCheckBox* m_displayGridLinesCheckBox; WuQWidgetObjectGroup* m_manualWidgetsGroup; }; #ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ATTRIBUTES_DECLARE__ // #endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ATTRIBUTES_DECLARE__ } // namespace #endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ATTRIBUTES_H__ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.cxx000066400000000000000000001163001360521144700275470ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_AXES_DECLARE__ #include "BrainBrowserWindowToolBarChartTwoAxes.h" #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_AXES_DECLARE__ #include "AnnotationPercentSizeText.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretDataFile.h" #include "CaretDataFileSelectionModel.h" #include "CaretMappableDataFile.h" #include "ChartTwoCartesianAxis.h" #include "ChartTwoOverlay.h" #include "ChartTwoOverlaySet.h" #include "ChartableTwoFileBaseChart.h" #include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileHistogramChart.h" #include "ChartableTwoFileLineSeriesChart.h" #include "EnumComboBoxTemplate.h" #include "EventBrowserWindowGraphicsRedrawn.h" #include "EventChartTwoAttributesChanged.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "ModelChartTwo.h" #include "WuQDataEntryDialog.h" #include "WuQFactory.h" #include "WuQDoubleSpinBox.h" #include "WuQMacroManager.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::BrainBrowserWindowToolBarChartTwoAxes * \brief Controls for chart attributes. * \ingroup GuiQt */ /** * Constructor. * * @param parentToolBar * The parent toolbar. * @param parentObjectName * Name of parent object for macros */ BrainBrowserWindowToolBarChartTwoAxes::BrainBrowserWindowToolBarChartTwoAxes(BrainBrowserWindowToolBar* parentToolBar, const QString& parentObjectName) : BrainBrowserWindowToolBarComponent(parentToolBar) { m_chartOverlaySet = NULL; m_chartAxis = NULL; WuQMacroManager* macroManager = WuQMacroManager::instance(); const QString objectNamePrefix(parentObjectName + ":ChartAxes:"); /* * 'Show' checkboxes */ m_axisDisplayedByUserCheckBox = new QCheckBox("Axis"); m_axisDisplayedByUserCheckBox->setToolTip("Show/hide the axis"); QObject::connect(m_axisDisplayedByUserCheckBox, &QCheckBox::clicked, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChanged); m_axisDisplayedByUserCheckBox->setObjectName(objectNamePrefix + "ShowAxis"); macroManager->addMacroSupportToObject(m_axisDisplayedByUserCheckBox, "Enable chart axis"); m_showTickMarksCheckBox = new QCheckBox("Ticks"); QObject::connect(m_showTickMarksCheckBox, &QCheckBox::clicked, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); m_showTickMarksCheckBox->setToolTip("Show ticks along the axis"); m_showTickMarksCheckBox->setObjectName(objectNamePrefix + "ShowTicks"); macroManager->addMacroSupportToObject(m_showTickMarksCheckBox, "Enable chart axis ticks"); m_showLabelCheckBox = new QCheckBox("Label"); QObject::connect(m_showLabelCheckBox, &QCheckBox::clicked, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); m_showLabelCheckBox->setToolTip("Show label on axis"); m_showLabelCheckBox->setObjectName(objectNamePrefix + "ShowLabel"); macroManager->addMacroSupportToObject(m_showLabelCheckBox, "Enable chart axis label"); m_showNumericsCheckBox = new QCheckBox("Nums"); QObject::connect(m_showNumericsCheckBox, &QCheckBox::clicked, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); m_showNumericsCheckBox->setToolTip("Show numeric scale values on axis"); m_showNumericsCheckBox->setObjectName(objectNamePrefix + "ShowNumerics"); macroManager->addMacroSupportToObject(m_showNumericsCheckBox, "Enable chart axis numerics"); m_rotateNumericsCheckBox = new QCheckBox("Rotate"); QObject::connect(m_rotateNumericsCheckBox, &QCheckBox::clicked, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool); m_rotateNumericsCheckBox->setToolTip("Rotate numeric scale values on axis"); m_rotateNumericsCheckBox->setObjectName(objectNamePrefix + "EnableNumericsRotate"); macroManager->addMacroSupportToObject(m_rotateNumericsCheckBox, "Enable rotation of chart axis numerics"); /* * Axes selection */ m_axisComboBox = new EnumComboBoxTemplate(this); m_axisComboBox->setup(); QObject::connect(m_axisComboBox, &EnumComboBoxTemplate::itemActivated, this, &BrainBrowserWindowToolBarChartTwoAxes::axisChanged); m_axisComboBox->getWidget()->setToolTip("Choose axis for editing"); m_axisComboBox->getWidget()->setObjectName(objectNamePrefix + "ChooseAxis"); macroManager->addMacroSupportToObject(m_axisComboBox->getComboBox(), "Select chart axis"); /* * Controls for layer selection and label editing */ m_axisLabelToolButton = new QToolButton(); m_axisLabelToolButton->setText("Edit Label..."); QObject::connect(m_axisLabelToolButton, &QToolButton::clicked, this, &BrainBrowserWindowToolBarChartTwoAxes::axisLabelToolButtonClicked); WuQtUtilities::setToolButtonStyleForQt5Mac(m_axisLabelToolButton); m_axisLabelToolButton->setToolTip("Edit the axis name for the file in the selected overlay"); m_axisLabelToolButton->setObjectName(objectNamePrefix + "EditAxis"); macroManager->addMacroSupportToObject(m_axisLabelToolButton, "Edit chart axis label"); QLabel* axisLabelFromOverlayLabel = new QLabel("Label From File In"); m_axisLabelFromOverlayComboBox = new QComboBox(); m_axisLabelFromOverlayComboBox->setToolTip("Label for axis is from file in selected layer"); QObject::connect(m_axisLabelFromOverlayComboBox, static_cast(&QComboBox::activated), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt); m_axisLabelFromOverlayComboBox->setObjectName(objectNamePrefix + "LabelFromOverlay"); macroManager->addMacroSupportToObject(m_axisLabelFromOverlayComboBox, "Select chart axis overlay source"); /* * Range controls */ const AString rangeTooltip("Auto - Adjusts axis range to fit data with some\n" " padding so that scale value are usually\n" " whole numbers\n" "Data - Axis range is limited to minimum and \n" " maximum values of the data\n" "User - Axis range is controlled by user"); m_autoUserRangeComboBox = new EnumComboBoxTemplate(this); m_autoUserRangeComboBox->setup(); QObject::connect(m_autoUserRangeComboBox, &EnumComboBoxTemplate::itemActivated, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChanged); m_autoUserRangeComboBox->getWidget()->setToolTip(rangeTooltip); m_autoUserRangeComboBox->getWidget()->setObjectName(objectNamePrefix + "RangeMode"); macroManager->addMacroSupportToObject(m_autoUserRangeComboBox->getWidget(), "Select chart axis range mode"); m_userMinimumValueSpinBox = new WuQDoubleSpinBox(this); m_userMinimumValueSpinBox->setDecimalsModeAuto(); m_userMinimumValueSpinBox->setSingleStepPercentage(1.0); QObject::connect(m_userMinimumValueSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::axisMinimumValueChanged); m_userMinimumValueSpinBox->setToolTip("Set user scaling axis minimum value"); m_userMinimumValueSpinBox->getWidget()->setObjectName(objectNamePrefix + "ScaleMinimum"); macroManager->addMacroSupportToObject(m_userMinimumValueSpinBox->getWidget(), "Set chart axis minimum"); m_userMaximumValueSpinBox = new WuQDoubleSpinBox(this); m_userMaximumValueSpinBox->setDecimalsModeAuto(); m_userMaximumValueSpinBox->setSingleStepPercentage(1.0); QObject::connect(m_userMaximumValueSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::axisMaximumValueChanged); m_userMaximumValueSpinBox->setToolTip("Set user scaling axis maximum value"); m_userMaximumValueSpinBox->getWidget()->setObjectName(objectNamePrefix + "ScaleMaximum"); macroManager->addMacroSupportToObject(m_userMaximumValueSpinBox->getWidget(), "See chart axis maximum"); /* * Format controls */ m_userNumericFormatComboBox = new EnumComboBoxTemplate(this); m_userNumericFormatComboBox->setup(); QObject::connect(m_userNumericFormatComboBox, &EnumComboBoxTemplate::itemActivated, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChanged); m_userNumericFormatComboBox->getWidget()->setToolTip("Choose format of axis scale numeric values"); m_userNumericFormatComboBox->getWidget()->setObjectName(objectNamePrefix + "Format"); macroManager->addMacroSupportToObject(m_userNumericFormatComboBox->getWidget(), "Select chart axis numeric format"); m_userDigitsRightOfDecimalSpinBox = WuQFactory::newSpinBoxWithMinMaxStep(0, 10, 1); QObject::connect(m_userDigitsRightOfDecimalSpinBox, static_cast(&QSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt); m_userDigitsRightOfDecimalSpinBox->setToolTip("Set digits right of decimal for\ndecimal or scientific format"); m_userDigitsRightOfDecimalSpinBox->setObjectName(objectNamePrefix + "DigitsRightOfDecimal"); macroManager->addMacroSupportToObject(m_userDigitsRightOfDecimalSpinBox, "Set chart axis digits right of decimal"); m_numericSubdivisionsModeComboBox = new EnumComboBoxTemplate(this); m_numericSubdivisionsModeComboBox->setup(); QObject::connect(m_numericSubdivisionsModeComboBox, &EnumComboBoxTemplate::itemActivated, this, &BrainBrowserWindowToolBarChartTwoAxes::valueChanged); m_numericSubdivisionsModeComboBox->getWidget()->setToolTip("Numeric subdivisions mode"); m_numericSubdivisionsModeComboBox->getWidget()->setObjectName(objectNamePrefix + "NumericSubdivisionsMode"); macroManager->addMacroSupportToObject(m_numericSubdivisionsModeComboBox->getWidget(), "Set chart axis numeric subdivisions mode"); m_userSubdivisionsSpinBox = WuQFactory::newSpinBoxWithMinMaxStep(0, 100, 1); QObject::connect(m_userSubdivisionsSpinBox, static_cast(&QSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt); m_userSubdivisionsSpinBox->setToolTip("Set subdivisions on the axis when Auto is not checked"); m_userSubdivisionsSpinBox->setObjectName(objectNamePrefix + "NumberOfSubdivisions"); macroManager->addMacroSupportToObject(m_userSubdivisionsSpinBox, "Set chart axis number of subivisions"); /* * Size spin boxes */ m_labelSizeSpinBox = new WuQDoubleSpinBox(this); m_labelSizeSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_labelSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); m_labelSizeSpinBox->setToolTip("Set height of label as percentage of tab height for selected axis"); m_labelSizeSpinBox->getWidget()->setObjectName(objectNamePrefix + "LabelHeight"); macroManager->addMacroSupportToObject(m_labelSizeSpinBox->getWidget(), "Set chart axis label height"); m_numericsSizeSpinBox = new WuQDoubleSpinBox(this); m_numericsSizeSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_numericsSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); m_numericsSizeSpinBox->setToolTip("Set height of numeric values as percentage of tab height for selected axis"); m_numericsSizeSpinBox->getWidget()->setObjectName(objectNamePrefix + "NumericValueHeight"); macroManager->addMacroSupportToObject(m_numericsSizeSpinBox->getWidget(), "Set chart axis numerics height"); m_linesTicksSizeSpinBox = new WuQDoubleSpinBox(this); m_linesTicksSizeSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_linesTicksSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::axisLineThicknessChanged); m_linesTicksSizeSpinBox->setToolTip("Set thickness of axis lines as percentage of tab height for ALL axes"); m_linesTicksSizeSpinBox->getWidget()->setObjectName(objectNamePrefix + "TicksSize"); macroManager->addMacroSupportToObject(m_linesTicksSizeSpinBox->getWidget(), "Set chart axis ticks height"); m_paddingSizeSpinBox = new WuQDoubleSpinBox(this); m_paddingSizeSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_paddingSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble); m_paddingSizeSpinBox->setToolTip("Set padding (space between edge and labels) as percentage of tab height for selected axis"); m_paddingSizeSpinBox->getWidget()->setObjectName(objectNamePrefix + "PaddingSize"); macroManager->addMacroSupportToObject(m_paddingSizeSpinBox->getWidget(), "Set chart axis padding height"); /* * Group widgets for blocking signals */ m_widgetGroup = new WuQWidgetObjectGroup(this); m_widgetGroup->add(m_axisComboBox); m_widgetGroup->add(m_axisDisplayedByUserCheckBox); m_widgetGroup->add(m_axisLabelToolButton); m_widgetGroup->add(m_autoUserRangeComboBox->getWidget()); m_widgetGroup->add(m_userMinimumValueSpinBox); m_widgetGroup->add(m_userMaximumValueSpinBox); m_widgetGroup->add(m_showTickMarksCheckBox); m_widgetGroup->add(m_showLabelCheckBox); m_widgetGroup->add(m_showNumericsCheckBox); m_widgetGroup->add(m_rotateNumericsCheckBox); m_widgetGroup->add(m_axisLabelFromOverlayComboBox); m_widgetGroup->add(m_userNumericFormatComboBox->getWidget()); m_widgetGroup->add(m_userDigitsRightOfDecimalSpinBox); m_widgetGroup->add(m_numericSubdivisionsModeComboBox->getWidget()); m_widgetGroup->add(m_userSubdivisionsSpinBox); m_widgetGroup->add(m_labelSizeSpinBox); m_widgetGroup->add(m_numericsSizeSpinBox); m_widgetGroup->add(m_linesTicksSizeSpinBox); m_widgetGroup->add(m_paddingSizeSpinBox); /* * Size layout */ QWidget* sizesWidget = new QWidget(); QGridLayout* sizesLayout = new QGridLayout(sizesWidget); WuQtUtilities::setLayoutSpacingAndMargins(sizesLayout, 2, 0); int32_t sizesRow = 0; sizesLayout->addWidget(new QLabel("Label"), sizesRow, 0); sizesLayout->addWidget(m_labelSizeSpinBox->getWidget(), sizesRow, 1); sizesRow++; sizesLayout->addWidget(new QLabel("Scale"), sizesRow, 0); sizesLayout->addWidget(m_numericsSizeSpinBox->getWidget(), sizesRow, 1); sizesRow++; sizesLayout->addWidget(new QLabel("Pad"), sizesRow, 0); sizesLayout->addWidget(m_paddingSizeSpinBox->getWidget(), sizesRow, 1); sizesRow++; sizesLayout->addWidget(new QLabel("Lines"), sizesRow, 0); sizesLayout->addWidget(m_linesTicksSizeSpinBox->getWidget(), sizesRow, 1); sizesRow++; /* * Show widgets layout */ const bool displayLabelShowAtTopFlag = false; QWidget* showWidget = new QWidget(); QGridLayout* showLayout = new QGridLayout(showWidget); WuQtUtilities::setLayoutSpacingAndMargins(showLayout, 1, 0); int32_t axisRow = 0; if (displayLabelShowAtTopFlag) { showLayout->addWidget(new QLabel("Show"), axisRow, 0, Qt::AlignHCenter); axisRow++; } showLayout->addWidget(m_axisDisplayedByUserCheckBox, axisRow, 0); axisRow++; showLayout->addWidget(m_showLabelCheckBox, axisRow, 0); axisRow++; showLayout->addWidget(m_showNumericsCheckBox, axisRow, 0); axisRow++; showLayout->addWidget(m_rotateNumericsCheckBox, axisRow, 0); axisRow++; showLayout->addWidget(m_showTickMarksCheckBox, axisRow, 0); axisRow++; showWidget->setSizePolicy(showWidget->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); /* * Range widgets layout */ QWidget* rangeWidget = new QWidget(); QGridLayout* rangeLayout = new QGridLayout(rangeWidget); WuQtUtilities::setLayoutSpacingAndMargins(rangeLayout, 3, 0); int rangeRow = 0; rangeLayout->addWidget(new QLabel("Range"), rangeRow, 0); m_autoUserRangeComboBox->getComboBox()->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); rangeLayout->addWidget(m_autoUserRangeComboBox->getWidget(), rangeRow, 1); rangeRow++; m_userMinimumValueSpinBox->setFixedWidth(90); m_userMaximumValueSpinBox->setFixedWidth(90); rangeLayout->addWidget(new QLabel("Max"), rangeRow, 0); rangeLayout->addWidget(m_userMaximumValueSpinBox->getWidget(), rangeRow, 1); rangeRow++; rangeLayout->addWidget(new QLabel("Min"), rangeRow, 0); rangeLayout->addWidget(m_userMinimumValueSpinBox->getWidget(), rangeRow, 1); /* * Numerics widgets layout */ QWidget* numericsWidget = new QWidget(); QGridLayout* numericsLayout = new QGridLayout(numericsWidget); WuQtUtilities::setLayoutSpacingAndMargins(numericsLayout, 3, 0); int numericsRow = 0; numericsLayout->addWidget(new QLabel("Format"), numericsRow, 0); numericsLayout->addWidget(m_userNumericFormatComboBox->getWidget(), numericsRow, 1); numericsRow++; numericsLayout->addWidget(new QLabel("Decimals"), numericsRow, 0); numericsLayout->addWidget(m_userDigitsRightOfDecimalSpinBox, numericsRow, 1); numericsRow++; numericsLayout->addWidget(new QLabel("Subdivisions"), numericsRow, 0); numericsLayout->addWidget(m_numericSubdivisionsModeComboBox->getWidget(), numericsRow, 1); numericsRow++; numericsLayout->addWidget(m_userSubdivisionsSpinBox, numericsRow, 1); /* * Top layout */ QHBoxLayout* topLayout = new QHBoxLayout(); WuQtUtilities::setLayoutSpacingAndMargins(topLayout, 3, 0); topLayout->addWidget(new QLabel("Edit Axis ")); topLayout->addWidget(m_axisComboBox->getWidget()); topLayout->addSpacing(10); topLayout->addStretch(); topLayout->addWidget(axisLabelFromOverlayLabel); topLayout->addWidget(m_axisLabelFromOverlayComboBox); topLayout->addSpacing(10); topLayout->addWidget(m_axisLabelToolButton); /* * Grid layout containing layouts */ QGridLayout* gridLayout = new QGridLayout(); gridLayout->setHorizontalSpacing(4); gridLayout->setVerticalSpacing(1); gridLayout->setContentsMargins(0, 0, 0, 0); // WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 0); gridLayout->addLayout(topLayout, 0, 0, 1, 7); gridLayout->addWidget(showWidget, 1, 0, Qt::AlignTop); gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 1, 1); gridLayout->addWidget(sizesWidget, 1, 2, Qt::AlignTop); gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 1, 3); gridLayout->addWidget(rangeWidget, 1, 4, Qt::AlignTop); gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 1, 5); gridLayout->addWidget(numericsWidget, 1, 6, Qt::AlignTop); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 0); //2); layout->addLayout(gridLayout); layout->addStretch(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN); } /** * Destructor. */ BrainBrowserWindowToolBarChartTwoAxes::~BrainBrowserWindowToolBarChartTwoAxes() { EventManager::get()->removeEventFromListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN); } /** * Receive an event. * * @param event * The event. */ void BrainBrowserWindowToolBarChartTwoAxes::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN) { CaretAssert(dynamic_cast(event)); updateContent(getTabContentFromSelectedTab()); } else { BrainBrowserWindowToolBarComponent::receiveEvent(event); } } /** * Update content of this tool bar component. * * @param browserTabContent * Content of the browser tab. */ void BrainBrowserWindowToolBarChartTwoAxes::updateContent(BrowserTabContent* browserTabContent) { if (browserTabContent == NULL) { setEnabled(false); return; } updateControls(browserTabContent); } /** * Get the selection data. * * @param browserTabContent * The tab content. * @param chartOverlaySetOut * The chart overlay set (may be NULL) * @param validAxesLocationsOut * The valid axes locations. * @param selectedAxisOut * Output with selected axis (may be NULL) */ void BrainBrowserWindowToolBarChartTwoAxes::getSelectionData(BrowserTabContent* browserTabContent, ChartTwoOverlaySet* &chartOverlaySetOut, std::vector& validAxesLocationsOut, ChartTwoCartesianAxis* &selectedAxisOut) const { chartOverlaySetOut = NULL; validAxesLocationsOut.clear(); selectedAxisOut = NULL; if (browserTabContent == NULL) { return; } const ChartAxisLocationEnum::Enum lastSelectedAxis = getSelectedAxisLocation(); if (browserTabContent != NULL) { ModelChartTwo* modelChartTwo = browserTabContent->getDisplayedChartTwoModel(); const int32_t tabIndex = browserTabContent->getTabNumber(); if (modelChartTwo != NULL) { switch (modelChartTwo->getSelectedChartTwoDataType(tabIndex)) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: chartOverlaySetOut = modelChartTwo->getChartTwoOverlaySet(tabIndex); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: chartOverlaySetOut = modelChartTwo->getChartTwoOverlaySet(tabIndex); break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; } if (chartOverlaySetOut != NULL) { int32_t defaultAxisIndex = -1; std::vector axes; chartOverlaySetOut->getDisplayedChartAxes(axes); const int32_t numAxes = static_cast(axes.size()); for (int32_t i = 0; i < numAxes; i++) { const ChartAxisLocationEnum::Enum axisLocation = axes[i]->getAxisLocation(); if (lastSelectedAxis == axisLocation) { defaultAxisIndex = i; } validAxesLocationsOut.push_back(axisLocation); } CaretAssert(validAxesLocationsOut.size() == axes.size()); if (defaultAxisIndex < 0) { /* * If selected axis not found, switch to opposite axis * User may have switched vertical axis from left to right */ ChartAxisLocationEnum::Enum oppositeAxis = ChartAxisLocationEnum::getOppositeAxis(lastSelectedAxis); for (int32_t i = 0; i < numAxes; i++) { if (oppositeAxis == axes[i]->getAxisLocation()) { defaultAxisIndex = i; break; } } } if ( ! axes.empty()) { if (defaultAxisIndex < 0) { defaultAxisIndex = 0; } CaretAssertVectorIndex(axes, defaultAxisIndex); selectedAxisOut = axes[defaultAxisIndex]; } } } } } /** * Called when axis is changed. */ void BrainBrowserWindowToolBarChartTwoAxes::axisChanged() { updateContent(getTabContentFromSelectedTab()); } /** * @return The selected axes location (will return left even if no valid selection). */ ChartAxisLocationEnum::Enum BrainBrowserWindowToolBarChartTwoAxes::getSelectedAxisLocation() const { ChartAxisLocationEnum::Enum axis = ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT; if (m_axisComboBox->getComboBox()->count() > 0) { axis = m_axisComboBox->getSelectedItem(); } return axis; } void BrainBrowserWindowToolBarChartTwoAxes::updateControls(BrowserTabContent* browserTabContent) { m_chartOverlaySet = NULL; std::vector validAxesLocations; ChartTwoCartesianAxis* selectedAxis = NULL; getSelectionData(browserTabContent, m_chartOverlaySet, validAxesLocations, selectedAxis); m_widgetGroup->blockAllSignals(true); m_chartAxis = selectedAxis; if ((m_chartOverlaySet != NULL) && (m_chartAxis != NULL)) { m_axisComboBox->setupWithItems(validAxesLocations); m_axisComboBox->setSelectedItem(m_chartAxis->getAxisLocation()); m_axisDisplayedByUserCheckBox->setChecked(m_chartAxis->isDisplayedByUser()); m_autoUserRangeComboBox->setSelectedItem(m_chartAxis->getScaleRangeMode()); float rangeMin(0.0f), rangeMax(0.0f); m_chartAxis->getDataRange(rangeMin, rangeMax); m_userMinimumValueSpinBox->setRangeExceedable(rangeMin, rangeMax); m_userMinimumValueSpinBox->setValue(m_chartAxis->getUserScaleMinimumValue()); m_userMaximumValueSpinBox->setRangeExceedable(rangeMin, rangeMax); m_userMaximumValueSpinBox->setValue(m_chartAxis->getUserScaleMaximumValue()); m_showTickMarksCheckBox->setChecked(m_chartAxis->isShowTickmarks()); m_showLabelCheckBox->setChecked(m_chartAxis->isShowLabel()); m_showNumericsCheckBox->setChecked(m_chartAxis->isNumericsTextDisplayed()); m_rotateNumericsCheckBox->setChecked(m_chartAxis->isNumericsTextRotated()); const NumericFormatModeEnum::Enum numericFormat = m_chartAxis->getUserNumericFormat(); m_userNumericFormatComboBox->setSelectedItem(numericFormat); m_userDigitsRightOfDecimalSpinBox->setValue(m_chartAxis->getUserDigitsRightOfDecimal()); m_userDigitsRightOfDecimalSpinBox->setEnabled(numericFormat != NumericFormatModeEnum::AUTO); m_numericSubdivisionsModeComboBox->setSelectedItem(m_chartAxis->getNumericSubdivsionsMode()); m_userSubdivisionsSpinBox->setValue(m_chartAxis->getUserNumberOfSubdivisions()); m_userSubdivisionsSpinBox->setEnabled( m_chartAxis->getNumericSubdivsionsMode() == ChartTwoNumericSubdivisionsModeEnum::USER); m_labelSizeSpinBox->setValue(m_chartAxis->getLabelTextSize()); m_numericsSizeSpinBox->setValue(m_chartAxis->getNumericsTextSize()); m_linesTicksSizeSpinBox->setValue(m_chartOverlaySet->getAxisLineThickness()); m_paddingSizeSpinBox->setValue(m_chartAxis->getPaddingSize()); const int32_t overlayCount = m_chartOverlaySet->getNumberOfDisplayedOverlays(); int32_t selectedOverlayIndex = m_chartAxis->getLabelOverlayIndex(overlayCount); const int32_t comboBoxCount = m_axisLabelFromOverlayComboBox->count(); if (overlayCount < comboBoxCount) { m_axisLabelFromOverlayComboBox->setMaxCount(overlayCount); } else if (overlayCount > comboBoxCount) { for (int32_t j = comboBoxCount; j < overlayCount; j++) { m_axisLabelFromOverlayComboBox->addItem("Layer " + AString::number(j + 1)); } } if ((selectedOverlayIndex >= 0) && (selectedOverlayIndex < m_axisLabelFromOverlayComboBox->count())) { m_axisLabelFromOverlayComboBox->setCurrentIndex(selectedOverlayIndex); } setEnabled(true); } else { setEnabled(false); } m_widgetGroup->blockAllSignals(false); } /** * Called when the axis line thickness changes. */ void BrainBrowserWindowToolBarChartTwoAxes::axisLineThicknessChanged(double) { if (m_chartOverlaySet != NULL) { m_chartOverlaySet->setAxisLineThickness(m_linesTicksSizeSpinBox->value()); const BrowserTabContent* tabContent = getTabContentFromSelectedTab(); CaretAssert(tabContent); const YokingGroupEnum::Enum yokingGroup = tabContent->getChartModelYokingGroup(); if (yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) { const ModelChartTwo* modelChartTwo = tabContent->getDisplayedChartTwoModel(); CaretAssert(modelChartTwo); const int32_t tabIndex = tabContent->getTabNumber(); EventChartTwoAttributesChanged attributesEvent; attributesEvent.setLineThicknessChanged(yokingGroup, modelChartTwo->getSelectedChartTwoDataType(tabIndex), m_linesTicksSizeSpinBox->value()); EventManager::get()->sendEvent(attributesEvent.getPointer()); } } updateGraphics(); updateContent(getTabContentFromSelectedTab()); } /** * Called when a widget is changed by the user. */ void BrainBrowserWindowToolBarChartTwoAxes::valueChanged() { CaretAssert(m_chartAxis); if (m_chartAxis != NULL) { m_chartAxis->setLabelOverlayIndex(m_axisLabelFromOverlayComboBox->currentIndex()); m_chartAxis->setDisplayedByUser(m_axisDisplayedByUserCheckBox->isChecked()); m_chartAxis->setScaleRangeMode(m_autoUserRangeComboBox->getSelectedItem()); m_chartAxis->setUserScaleMinimumValue(m_userMinimumValueSpinBox->value()); m_chartAxis->setUserScaleMaximumValue(m_userMaximumValueSpinBox->value()); m_chartAxis->setShowTickmarks(m_showTickMarksCheckBox->isChecked()); m_chartAxis->setShowLabel(m_showLabelCheckBox->isChecked()); m_chartAxis->setNumericsTextDisplayed(m_showNumericsCheckBox->isChecked()); m_chartAxis->setNumericsTextRotated(m_rotateNumericsCheckBox->isChecked()); m_chartAxis->setUserNumericFormat(m_userNumericFormatComboBox->getSelectedItem()); m_chartAxis->setUserDigitsRightOfDecimal(m_userDigitsRightOfDecimalSpinBox->value()); m_chartAxis->setNumericSubdivsionsMode(m_numericSubdivisionsModeComboBox->getSelectedItem()); m_chartAxis->setUserNumberOfSubdivisions(m_userSubdivisionsSpinBox->value()); m_chartAxis->setLabelTextSize(m_labelSizeSpinBox->value()); m_chartAxis->setNumericsTextSize(m_numericsSizeSpinBox->value()); m_chartAxis->setPaddingSize(m_paddingSizeSpinBox->value()); const BrowserTabContent* tabContent = getTabContentFromSelectedTab(); CaretAssert(tabContent); const YokingGroupEnum::Enum yokingGroup = tabContent->getChartModelYokingGroup(); if (yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) { const ModelChartTwo* modelChartTwo = tabContent->getDisplayedChartTwoModel(); CaretAssert(modelChartTwo); const int32_t tabIndex = tabContent->getTabNumber(); EventChartTwoAttributesChanged attributesEvent; attributesEvent.setCartesianAxisChanged(yokingGroup, modelChartTwo->getSelectedChartTwoDataType(tabIndex), m_chartAxis); EventManager::get()->sendEvent(attributesEvent.getPointer()); } } updateGraphics(); updateContent(getTabContentFromSelectedTab()); } /** * Update the graphics. */ void BrainBrowserWindowToolBarChartTwoAxes::updateGraphics() { EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called when the minimum value is changed. * * @param minimumValue * New minimum value. */ void BrainBrowserWindowToolBarChartTwoAxes::axisMinimumValueChanged(double minimumValue) { if (m_chartAxis != NULL) { /* * If the minimum or maximum value is modified by user, * ensure Auto/User Range selection is USER */ m_autoUserRangeComboBox->getWidget()->blockSignals(true); m_autoUserRangeComboBox->setSelectedItem(ChartTwoAxisScaleRangeModeEnum::USER); m_autoUserRangeComboBox->getWidget()->blockSignals(false); /* * Ensure maximum value is always greater than or equal to minimum */ if (minimumValue > m_userMaximumValueSpinBox->value()) { m_userMaximumValueSpinBox->getWidget()->blockSignals(true); m_userMaximumValueSpinBox->setValue(minimumValue); m_userMaximumValueSpinBox->getWidget()->blockSignals(false); } valueChanged(); } } /** * Called when the maximum value is changed. * * @param maximumValue * New maximum value. */ void BrainBrowserWindowToolBarChartTwoAxes::axisMaximumValueChanged(double maximumValue) { if (m_chartAxis != NULL) { /* * If the minimum or maximum value is modified by user, * ensure Auto/User Range selection is USER */ m_autoUserRangeComboBox->getWidget()->blockSignals(true); m_autoUserRangeComboBox->setSelectedItem(ChartTwoAxisScaleRangeModeEnum::USER); m_autoUserRangeComboBox->getWidget()->blockSignals(false); /* * Ensure minimum value is always less than or equal to maximum */ if (maximumValue < m_userMinimumValueSpinBox->value()) { m_userMinimumValueSpinBox->getWidget()->blockSignals(true); m_userMinimumValueSpinBox->setValue(maximumValue); m_userMinimumValueSpinBox->getWidget()->blockSignals(false); } valueChanged(); } } /** * Called when a widget is changed by a slot using a bool parameter. * Parameters must match when using function pointers. */ void BrainBrowserWindowToolBarChartTwoAxes::valueChangedBool(bool) { valueChanged(); } /** * Called when a widget is changed by a slot using a double parameter. * Parameters must match when using function pointers. */ void BrainBrowserWindowToolBarChartTwoAxes::valueChangedDouble(double) { valueChanged(); } /** * Called when a widget is changed by a slot using a int parameter. * Parameters must match when using function pointers. */ void BrainBrowserWindowToolBarChartTwoAxes::valueChangedInt(int) { valueChanged(); } /** * Called when name toolbutton is clicked to change axis label. */ void BrainBrowserWindowToolBarChartTwoAxes::axisLabelToolButtonClicked(bool) { ChartTwoOverlaySet* chartOverlaySet = NULL; std::vector validAxesLocations; ChartTwoCartesianAxis* selectedAxis = NULL; getSelectionData(getTabContentFromSelectedTab(), chartOverlaySet, validAxesLocations, selectedAxis); if ((chartOverlaySet != NULL) && (selectedAxis != NULL)) { WuQDataEntryDialog newNameDialog("Axis Label", m_axisLabelToolButton); QLineEdit* lineEdit = newNameDialog.addLineEditWidget("Label"); lineEdit->setText(chartOverlaySet->getAxisLabel(selectedAxis)); if (newNameDialog.exec() == WuQDataEntryDialog::Accepted) { const AString name = lineEdit->text().trimmed(); chartOverlaySet->setAxisLabel(selectedAxis, name); valueChanged(); } } } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarChartTwoAxes.h000066400000000000000000000111711360521144700271740ustar00rootroot00000000000000#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_AXES_H__ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_AXES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainBrowserWindowToolBarComponent.h" #include "ChartAxisLocationEnum.h" class QCheckBox; class QComboBox; class QDoubleSpinBox; class QLabel; class QSpinBox; class QToolButton; namespace caret { class AnnotationPercentSizeText; class ChartTwoCartesianAxis; class ChartTwoCartesianAxisWidget; class ChartTwoOverlaySet; class EnumComboBoxTemplate; class WuQDoubleSpinBox; class WuQWidgetObjectGroup; class BrainBrowserWindowToolBarChartTwoAxes : public BrainBrowserWindowToolBarComponent { Q_OBJECT public: BrainBrowserWindowToolBarChartTwoAxes(BrainBrowserWindowToolBar* parentToolBar, const QString& parentObjectName); virtual ~BrainBrowserWindowToolBarChartTwoAxes(); virtual void updateContent(BrowserTabContent* browserTabContent); virtual void receiveEvent(Event* event); // ADD_NEW_METHODS_HERE private slots: void axisChanged(); void valueChanged(); void valueChangedBool(bool); void valueChangedDouble(double); void valueChangedInt(int); void axisMinimumValueChanged(double); void axisMaximumValueChanged(double); void axisLabelToolButtonClicked(bool); void axisLineThicknessChanged(double); private: BrainBrowserWindowToolBarChartTwoAxes(const BrainBrowserWindowToolBarChartTwoAxes&); BrainBrowserWindowToolBarChartTwoAxes& operator=(const BrainBrowserWindowToolBarChartTwoAxes&); ChartAxisLocationEnum::Enum getSelectedAxisLocation() const; void getSelectionData(BrowserTabContent* browserTabContent, ChartTwoOverlaySet* &chartOverlaySetOut, std::vector& validAxesLocationsOut, ChartTwoCartesianAxis* &selectedAxisOut) const; void updateControls(BrowserTabContent* browserTabContent); void updateGraphics(); // ADD_NEW_MEMBERS_HERE QCheckBox* m_axisDisplayedByUserCheckBox; EnumComboBoxTemplate* m_axisComboBox; QToolButton* m_axisLabelToolButton; QComboBox* m_axisLabelFromOverlayComboBox; EnumComboBoxTemplate* m_autoUserRangeComboBox; WuQDoubleSpinBox* m_userMinimumValueSpinBox; WuQDoubleSpinBox* m_userMaximumValueSpinBox; QCheckBox* m_showTickMarksCheckBox; QCheckBox* m_showLabelCheckBox; QCheckBox* m_showNumericsCheckBox; QCheckBox* m_rotateNumericsCheckBox; EnumComboBoxTemplate* m_userNumericFormatComboBox; QSpinBox* m_userDigitsRightOfDecimalSpinBox; EnumComboBoxTemplate* m_numericSubdivisionsModeComboBox; QSpinBox* m_userSubdivisionsSpinBox; WuQDoubleSpinBox* m_labelSizeSpinBox; WuQDoubleSpinBox* m_numericsSizeSpinBox; WuQDoubleSpinBox* m_linesTicksSizeSpinBox; WuQDoubleSpinBox* m_paddingSizeSpinBox; ChartTwoOverlaySet* m_chartOverlaySet; ChartTwoCartesianAxis* m_chartAxis; WuQWidgetObjectGroup* m_widgetGroup; }; #ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_AXES_DECLARE__ // #endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_AXES_DECLARE__ } // namespace #endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_AXES_H__ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.cxx000066400000000000000000000132151360521144700311430ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ORIENTATION_DECLARE__ #include "BrainBrowserWindowToolBarChartTwoOrientation.h" #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ORIENTATION_DECLARE__ #include #include #include "BrainBrowserWindowToolBar.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretPreferences.h" #include "EventManager.h" #include "ModelChartTwo.h" #include "SessionManager.h" #include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::BrainBrowserWindowToolBarChartTwoOrientation * \brief Toolbar component for chart orientation. * \ingroup GuiQt */ /** * Constructor. */ BrainBrowserWindowToolBarChartTwoOrientation::BrainBrowserWindowToolBarChartTwoOrientation(BrainBrowserWindowToolBar* parentToolBar, const QString& parentObjectName) : BrainBrowserWindowToolBarComponent(parentToolBar) { const QString objectNamePrefix(parentObjectName + ":ChartOrientation"); QToolButton* orientationResetToolButton = new QToolButton(); m_orientationResetToolButtonAction = WuQtUtilities::createAction("Reset", "Reset the view to remove any panning or zooming", orientationResetToolButton, this, SLOT(orientationResetToolButtonTriggered(bool))); m_orientationResetToolButtonAction->setObjectName(objectNamePrefix + ":ResetButton"); WuQMacroManager::instance()->addMacroSupportToObject(m_orientationResetToolButtonAction, "Reset chart panning and zooming"); const QString customToolTip = ("Pressing the \"Custom\" button displays a dialog for creating and editing orientations.\n" "Note that custom orientations are stored in your Workbench's preferences and thus\n" "will be availble in any concurrent or future instances of Workbench."); m_orientationCustomViewSelectToolButton = new QToolButton(); m_customViewAction = WuQtUtilities::createAction("Custom", customToolTip, m_orientationCustomViewSelectToolButton, this, SLOT(customViewActionTriggered())); m_customViewAction->setObjectName(objectNamePrefix + ":ShowCustomViewDialog"); WuQMacroManager::instance()->addMacroSupportToObject(m_customViewAction, "Display chart custom view dialog"); orientationResetToolButton->setDefaultAction(m_orientationResetToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(orientationResetToolButton); m_orientationCustomViewSelectToolButton->setDefaultAction(m_customViewAction); m_orientationCustomViewSelectToolButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); WuQtUtilities::setToolButtonStyleForQt5Mac(m_orientationCustomViewSelectToolButton); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 5); layout->addWidget(orientationResetToolButton, 0, Qt::AlignHCenter); layout->addWidget(m_orientationCustomViewSelectToolButton, 0, Qt::AlignHCenter); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } /** * Destructor. */ BrainBrowserWindowToolBarChartTwoOrientation::~BrainBrowserWindowToolBarChartTwoOrientation() { EventManager::get()->removeAllEventsFromListener(this); } /** * Update content of this tool bar component. * * @param browserTabContent * Content of the browser tab. */ void BrainBrowserWindowToolBarChartTwoOrientation::updateContent(BrowserTabContent* /*browserTabContent*/) { } /** * Called when orientation reset button is pressed. */ void BrainBrowserWindowToolBarChartTwoOrientation::orientationResetToolButtonTriggered(bool /*checked*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->resetView(); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when custom view is triggered and displays Custom View Menu. */ void BrainBrowserWindowToolBarChartTwoOrientation::customViewActionTriggered() { m_parentToolBar->customViewActionTriggered(); } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarChartTwoOrientation.h000066400000000000000000000046521360521144700305750ustar00rootroot00000000000000#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ORIENTATION_H__ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ORIENTATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainBrowserWindowToolBarComponent.h" class QToolButton; namespace caret { class BrainBrowserWindowToolBarChartTwoOrientation : public BrainBrowserWindowToolBarComponent { Q_OBJECT public: BrainBrowserWindowToolBarChartTwoOrientation(BrainBrowserWindowToolBar* parentToolBar, const QString& parentObjectName); virtual ~BrainBrowserWindowToolBarChartTwoOrientation(); virtual void updateContent(BrowserTabContent* browserTabContent); // ADD_NEW_METHODS_HERE private slots: void customViewActionTriggered(); void orientationResetToolButtonTriggered(bool /*checked*/); private: BrainBrowserWindowToolBarChartTwoOrientation(const BrainBrowserWindowToolBarChartTwoOrientation&); BrainBrowserWindowToolBarChartTwoOrientation& operator=(const BrainBrowserWindowToolBarChartTwoOrientation&); QAction* m_orientationResetToolButtonAction; QAction* m_customViewAction; QToolButton* m_orientationCustomViewSelectToolButton; // ADD_NEW_MEMBERS_HERE }; #ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ORIENTATION_DECLARE__ // #endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ORIENTATION_DECLARE__ } // namespace #endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_ORIENTATION_H__ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.cxx000066400000000000000000000225101360521144700277270ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TITLE_DECLARE__ #include "BrainBrowserWindowToolBarChartTwoTitle.h" #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TITLE_DECLARE__ #include #include #include #include #include #include #include #include "AnnotationPercentSizeText.h" #include "BrainBrowserWindowToolBar.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "ChartTwoOverlaySet.h" #include "ChartTwoTitle.h" #include "EventChartTwoAttributesChanged.h" #include "EventManager.h" #include "ModelChartTwo.h" #include "WuQDataEntryDialog.h" #include "WuQDoubleSpinBox.h" #include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::BrainBrowserWindowToolBarChartTwoTitle * \brief Toolbar component for chart orientation. * \ingroup GuiQt */ /** * Constructor. * * @param parentToolBar * The parent toolbar * @param parentObjectName * Name of parent object for macros */ BrainBrowserWindowToolBarChartTwoTitle::BrainBrowserWindowToolBarChartTwoTitle(BrainBrowserWindowToolBar* parentToolBar, const QString& parentObjectName) : BrainBrowserWindowToolBarComponent(parentToolBar) { WuQMacroManager* macroManager = WuQMacroManager::instance(); const QString objectNamePrefix(parentObjectName + ":ChartTitle:"); m_showTitleCheckBox = new QCheckBox("Show Title"); m_showTitleCheckBox->setToolTip("Show the title at the top of the chart"); QObject::connect(m_showTitleCheckBox, &QCheckBox::clicked, this, &BrainBrowserWindowToolBarChartTwoTitle::showTitleCheckBoxClicked); m_showTitleCheckBox->setObjectName(objectNamePrefix + "Show"); macroManager->addMacroSupportToObject(m_showTitleCheckBox, "Show chart title"); QToolButton* editTitleToolButton = new QToolButton; QAction* editTitleAction = new QAction("Edit Title...", editTitleToolButton); editTitleAction->setToolTip("Edit the chart title in a dialog"); QObject::connect(editTitleAction, &QAction::triggered, this, &BrainBrowserWindowToolBarChartTwoTitle::editTitleActionTriggered); editTitleAction->setObjectName(objectNamePrefix + "Edit"); macroManager->addMacroSupportToObject(editTitleAction, "Display dialog to edit chart title"); WuQtUtilities::setToolButtonStyleForQt5Mac(editTitleToolButton); editTitleToolButton->setDefaultAction(editTitleAction); m_titleSizeSpinBox = new WuQDoubleSpinBox(this); m_titleSizeSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_titleSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoTitle::sizeSpinBoxValueChanged); m_titleSizeSpinBox->setToolTip("Set height of title as percentage of tab height"); m_titleSizeSpinBox->getWidget()->setObjectName(objectNamePrefix + "Height"); macroManager->addMacroSupportToObject(m_titleSizeSpinBox->getWidget(), "Set chart title height"); m_paddingSizeSpinBox = new WuQDoubleSpinBox(this); m_paddingSizeSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_paddingSizeSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarChartTwoTitle::sizeSpinBoxValueChanged); m_paddingSizeSpinBox->getWidget()->setObjectName(objectNamePrefix + "Padding"); macroManager->addMacroSupportToObject(m_paddingSizeSpinBox->getWidget(), "Set chart padding"); m_paddingSizeSpinBox->setToolTip("Set padding (space between edge and labels) as percentage of tab height"); QGridLayout* layout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 3, 0); //4, 5); int row = 0; layout->addWidget(m_showTitleCheckBox, row, 0, 1, 2, Qt::AlignHCenter); row++; layout->addWidget(new QLabel("Size"), row, 0); layout->addWidget(m_titleSizeSpinBox->getWidget(), row, 1); row++; layout->addWidget(new QLabel("Pad"), row, 0); layout->addWidget(m_paddingSizeSpinBox->getWidget(), row, 1); row++; layout->addWidget(editTitleToolButton, row, 0, 1, 2, Qt::AlignHCenter); row++; setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } /** * Destructor. */ BrainBrowserWindowToolBarChartTwoTitle::~BrainBrowserWindowToolBarChartTwoTitle() { } /** * Update content of this tool bar component. * * @param browserTabContent * Content of the browser tab. */ void BrainBrowserWindowToolBarChartTwoTitle::updateContent(BrowserTabContent* browserTabContent) { m_chartOverlaySet = NULL; if (browserTabContent != NULL) { ModelChartTwo* modelChartTwo = browserTabContent->getDisplayedChartTwoModel(); if (modelChartTwo != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); m_chartOverlaySet = modelChartTwo->getChartTwoOverlaySet(tabIndex); } } if (m_chartOverlaySet != NULL) { setEnabled(true); const ChartTwoTitle* chartTitle = m_chartOverlaySet->getChartTitle(); m_showTitleCheckBox->setChecked(chartTitle->isDisplayed()); m_titleSizeSpinBox->blockSignals(true); m_titleSizeSpinBox->setValue(chartTitle->getTextSize()); m_titleSizeSpinBox->blockSignals(false); m_paddingSizeSpinBox->blockSignals(true); m_paddingSizeSpinBox->setValue(chartTitle->getPaddingSize()); m_paddingSizeSpinBox->blockSignals(false); } else { setEnabled(false); } } /** * Called when show title checkbox is clicked. * * @param checked * Status of checkbox. */ void BrainBrowserWindowToolBarChartTwoTitle::showTitleCheckBoxClicked(bool checked) { if (m_chartOverlaySet != NULL) { ChartTwoTitle* chartTitle = m_chartOverlaySet->getChartTitle(); chartTitle->setDisplayed(checked); this->performUpdating(); } } /** * Called when a size spin box value is changed */ void BrainBrowserWindowToolBarChartTwoTitle::sizeSpinBoxValueChanged(double) { if (m_chartOverlaySet != NULL) { ChartTwoTitle* chartTitle = m_chartOverlaySet->getChartTitle(); chartTitle->setTextSize(m_titleSizeSpinBox->value()); chartTitle->setPaddingSize(m_paddingSizeSpinBox->value()); this->performUpdating(); } } /** * Called when edit title action is triggered. */ void BrainBrowserWindowToolBarChartTwoTitle::editTitleActionTriggered() { if (m_chartOverlaySet != NULL) { WuQDataEntryDialog newNameDialog("Chart Title", this); QLineEdit* lineEdit = newNameDialog.addLineEditWidget("Title"); lineEdit->setText(m_chartOverlaySet->getChartTitle()->getText()); if (newNameDialog.exec() == WuQDataEntryDialog::Accepted) { const AString name = lineEdit->text().trimmed(); m_chartOverlaySet->getChartTitle()->setText(name); if ( ! name.isEmpty()) { m_chartOverlaySet->getChartTitle()->setDisplayed(true); m_showTitleCheckBox->setChecked(true); } this->performUpdating(); } } } void BrainBrowserWindowToolBarChartTwoTitle::performUpdating() { const BrowserTabContent* tabContent = getTabContentFromSelectedTab(); CaretAssert(tabContent); const YokingGroupEnum::Enum yokingGroup = tabContent->getChartModelYokingGroup(); if (yokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) { const ModelChartTwo* modelChartTwo = tabContent->getDisplayedChartTwoModel(); CaretAssert(modelChartTwo); const int32_t tabIndex = tabContent->getTabNumber(); EventChartTwoAttributesChanged attributesEvent; attributesEvent.setTitleChanged(yokingGroup, modelChartTwo->getSelectedChartTwoDataType(tabIndex), m_chartOverlaySet->getChartTitle()); EventManager::get()->sendEvent(attributesEvent.getPointer()); } this->updateGraphicsWindowAndYokedWindows(); } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarChartTwoTitle.h000066400000000000000000000050141360521144700273540ustar00rootroot00000000000000#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TITLE_H__ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TITLE_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainBrowserWindowToolBarComponent.h" class QCheckBox; namespace caret { class ChartTwoOverlaySet; class WuQDoubleSpinBox; class BrainBrowserWindowToolBarChartTwoTitle : public BrainBrowserWindowToolBarComponent { Q_OBJECT public: BrainBrowserWindowToolBarChartTwoTitle(BrainBrowserWindowToolBar* parentToolBar, const QString& parentObjectName); virtual ~BrainBrowserWindowToolBarChartTwoTitle(); virtual void updateContent(BrowserTabContent* browserTabContent); // ADD_NEW_METHODS_HERE private slots: void editTitleActionTriggered(); void showTitleCheckBoxClicked(bool); void sizeSpinBoxValueChanged(double); private: BrainBrowserWindowToolBarChartTwoTitle(const BrainBrowserWindowToolBarChartTwoTitle&); BrainBrowserWindowToolBarChartTwoTitle& operator=(const BrainBrowserWindowToolBarChartTwoTitle&); void performUpdating(); QCheckBox* m_showTitleCheckBox; WuQDoubleSpinBox* m_titleSizeSpinBox; WuQDoubleSpinBox* m_paddingSizeSpinBox; ChartTwoOverlaySet* m_chartOverlaySet; // ADD_NEW_MEMBERS_HERE }; #ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TITLE_DECLARE__ // #endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TITLE_DECLARE__ } // namespace #endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TITLE_H__ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.cxx000066400000000000000000000132761360521144700276000ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TYPE_DECLARE__ #include "BrainBrowserWindowToolBarChartTwoType.h" #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TYPE_DECLARE__ #include #include #include #include "BrowserTabContent.h" #include "BrainBrowserWindowToolBar.h" #include "CaretAssert.h" #include "EnumComboBoxTemplate.h" #include "ModelChartTwo.h" #include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::BrainBrowserWindowToolBarChartTwoType * \brief Chart Component of Brain Browser Window ToolBar * \ingroup GuiQt */ /** * Constructor. * * @param parentToolBar * parent toolbar. * @param parentObjectName * Name of parent object for macros */ BrainBrowserWindowToolBarChartTwoType::BrainBrowserWindowToolBarChartTwoType(BrainBrowserWindowToolBar* parentToolBar, const QString& parentObjectName) : BrainBrowserWindowToolBarComponent(parentToolBar), m_parentToolBar(parentToolBar) { m_chartTypeButtonGroup = new QButtonGroup(this); QVBoxLayout* radioButtonLayout = new QVBoxLayout(this); std::vector allChartTypes; ChartTwoDataTypeEnum::getAllEnums(allChartTypes); for (auto ct : allChartTypes) { if (ct == ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID) { continue; } QRadioButton* rb = new QRadioButton(ChartTwoDataTypeEnum::toGuiName(ct)); m_chartTypeButtonGroup->addButton(rb, m_chartTypeRadioButtons.size()); rb->setToolTip("Set chart to " + rb->text()); QString chartTypeName = rb->text(); chartTypeName = chartTypeName.replace(" ", ""); rb->setObjectName(parentObjectName + ":ChartType:" + chartTypeName); WuQMacroManager::instance()->addMacroSupportToObject(rb, "Select " + chartTypeName + " chart"); radioButtonLayout->addWidget(rb); m_chartTypeRadioButtons.push_back(std::make_pair(ct, rb)); } WuQtUtilities::setLayoutSpacingAndMargins(radioButtonLayout, 4, 5); radioButtonLayout->addStretch(); QObject::connect(m_chartTypeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(chartTypeRadioButtonClicked(int))); } /** * Destructor. */ BrainBrowserWindowToolBarChartTwoType::~BrainBrowserWindowToolBarChartTwoType() { } /** * Called when a radio button is clicked. * * @param buttonIndex * Index of button that is clicked. */ void BrainBrowserWindowToolBarChartTwoType::chartTypeRadioButtonClicked(int buttonIndex) { CaretAssertVectorIndex(m_chartTypeRadioButtons, buttonIndex); ChartTwoDataTypeEnum::Enum chartDataType = m_chartTypeRadioButtons[buttonIndex].first; m_parentToolBar->getTabContentFromSelectedTab(); BrowserTabContent* btc = m_parentToolBar->getTabContentFromSelectedTab(); ModelChartTwo* chartModelTwo = btc->getDisplayedChartTwoModel(); const int32_t tabIndex = btc->getTabNumber(); chartModelTwo->setSelectedChartTwoDataType(tabIndex, chartDataType); //updateContent(btc); invalidateColoringAndUpdateGraphicsWindow(); m_parentToolBar->updateUserInterface(); } /** * Update content of this tool bar component. * * @param browserTabContent * Content of the browser tab. */ void BrainBrowserWindowToolBarChartTwoType::updateContent(BrowserTabContent* browserTabContent) { m_chartTypeButtonGroup->blockSignals(true); const ModelChartTwo* chartModelTwo = browserTabContent->getDisplayedChartTwoModel(); if (chartModelTwo != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); const ChartTwoDataTypeEnum::Enum selectedChartType = chartModelTwo->getSelectedChartTwoDataType(tabIndex); std::vector validChartDataTypes; chartModelTwo->getValidChartTwoDataTypes(validChartDataTypes); for (auto chartTypeButton : m_chartTypeRadioButtons) { ChartTwoDataTypeEnum::Enum chartType = chartTypeButton.first; QRadioButton* radioButton = chartTypeButton.second; const bool validTypeFlag = (std::find(validChartDataTypes.begin(), validChartDataTypes.end(), chartType) != validChartDataTypes.end()); radioButton->setEnabled(validTypeFlag); if (chartType == selectedChartType) { radioButton->setChecked(true); } } } m_chartTypeButtonGroup->blockSignals(false); } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarChartTwoType.h000066400000000000000000000047261360521144700272250ustar00rootroot00000000000000#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TYPE_H__ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TYPE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ class QAbstractButton; class QButtonGroup; class QRadioButton; #include "BrainBrowserWindowToolBarComponent.h" #include "ChartTwoDataTypeEnum.h" namespace caret { class EnumComboBoxTemplate; class BrainBrowserWindowToolBarChartTwoType : public BrainBrowserWindowToolBarComponent { Q_OBJECT public: BrainBrowserWindowToolBarChartTwoType(BrainBrowserWindowToolBar* parentToolBar, const QString& parentObjectName); virtual ~BrainBrowserWindowToolBarChartTwoType(); virtual void updateContent(BrowserTabContent* browserTabContent); private slots: void chartTypeRadioButtonClicked(int buttonIndex); private: BrainBrowserWindowToolBarChartTwoType(const BrainBrowserWindowToolBarChartTwoType&); BrainBrowserWindowToolBarChartTwoType& operator=(const BrainBrowserWindowToolBarChartTwoType&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE BrainBrowserWindowToolBar* m_parentToolBar; std::vector > m_chartTypeRadioButtons; QButtonGroup* m_chartTypeButtonGroup; }; #ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TYPE_DECLARE__ // #endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TYPE_DECLARE__ } // namespace #endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_TWO_TYPE_H__ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarChartType.cxx000066400000000000000000000135601360521144700271020ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_DECLARE__ #include "BrainBrowserWindowToolBarChartType.h" #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_DECLARE__ #include #include #include #include "BrowserTabContent.h" #include "BrainBrowserWindowToolBar.h" #include "CaretAssert.h" #include "ChartModel.h" #include "EnumComboBoxTemplate.h" #include "ModelChart.h" #include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::BrainBrowserWindowToolBarChartType * \brief Chart Component of Brain Browser Window ToolBar * \ingroup GuiQt */ /** * Constructor. * * @param parentToolBar * parent toolbar. */ BrainBrowserWindowToolBarChartType::BrainBrowserWindowToolBarChartType(BrainBrowserWindowToolBar* parentToolBar, const QString& parentObjectName) : BrainBrowserWindowToolBarComponent(parentToolBar), m_parentToolBar(parentToolBar) { m_chartTypeButtonGroup = new QButtonGroup(this); QVBoxLayout* radioButtonLayout = new QVBoxLayout(this); std::vector allChartTypes; ChartOneDataTypeEnum::getAllEnums(allChartTypes); for (std::vector::iterator chartIter = allChartTypes.begin(); chartIter != allChartTypes.end(); chartIter++) { const ChartOneDataTypeEnum::Enum ct = *chartIter; if (ct == ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID) { continue; } QRadioButton* rb = new QRadioButton(ChartOneDataTypeEnum::toGuiName(ct)); m_chartTypeButtonGroup->addButton(rb, m_chartTypeRadioButtons.size()); rb->setToolTip("Set chart to " + rb->text()); QString chartTypeName = rb->text(); chartTypeName = chartTypeName.replace(" ", ""); rb->setObjectName(parentObjectName + ":ChartOneType:" + chartTypeName); WuQMacroManager::instance()->addMacroSupportToObject(rb, "Select " + chartTypeName + " chart"); radioButtonLayout->addWidget(rb); m_chartTypeRadioButtons.push_back(std::make_pair(ct, rb)); } WuQtUtilities::setLayoutSpacingAndMargins(radioButtonLayout, 4, 5); radioButtonLayout->addStretch(); QObject::connect(m_chartTypeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(chartTypeRadioButtonClicked(int))); } /** * Destructor. */ BrainBrowserWindowToolBarChartType::~BrainBrowserWindowToolBarChartType() { } /** * Called when a radio button is clicked. * * @param buttonIndex * Index of button that is clicked. */ void BrainBrowserWindowToolBarChartType::chartTypeRadioButtonClicked(int buttonIndex) { CaretAssertVectorIndex(m_chartTypeRadioButtons, buttonIndex); ChartOneDataTypeEnum::Enum chartDataType = m_chartTypeRadioButtons[buttonIndex].first; m_parentToolBar->getTabContentFromSelectedTab(); BrowserTabContent* btc = m_parentToolBar->getTabContentFromSelectedTab(); ModelChart* chartModel = btc->getDisplayedChartOneModel(); const int32_t tabIndex = btc->getTabNumber(); chartModel->setSelectedChartOneDataType(tabIndex, chartDataType); invalidateColoringAndUpdateGraphicsWindow(); m_parentToolBar->updateUserInterface(); } /** * Update content of this tool bar component. * * @param browserTabContent * Content of the browser tab. */ void BrainBrowserWindowToolBarChartType::updateContent(BrowserTabContent* browserTabContent) { m_chartTypeButtonGroup->blockSignals(true); const ModelChart* chartModel = browserTabContent->getDisplayedChartOneModel(); if (chartModel != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); const ChartOneDataTypeEnum::Enum selectedChartType = chartModel->getSelectedChartOneDataType(tabIndex); std::vector validChartDataTypes; chartModel->getValidChartOneDataTypes(validChartDataTypes); for (std::vector >::iterator buttIter = m_chartTypeRadioButtons.begin(); buttIter != m_chartTypeRadioButtons.end(); buttIter++) { ChartOneDataTypeEnum::Enum chartType = buttIter->first; QRadioButton* radioButton = buttIter->second; const bool validTypeFlag = (std::find(validChartDataTypes.begin(), validChartDataTypes.end(), chartType) != validChartDataTypes.end()); radioButton->setEnabled(validTypeFlag); if (chartType == selectedChartType) { radioButton->setChecked(true); } } } m_chartTypeButtonGroup->blockSignals(false); } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarChartType.h000066400000000000000000000053611360521144700265270ustar00rootroot00000000000000#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_H__ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ class QAbstractButton; class QButtonGroup; class QRadioButton; #include "BrainBrowserWindowToolBarComponent.h" #include "ChartOneDataTypeEnum.h" namespace caret { class EnumComboBoxTemplate; class BrainBrowserWindowToolBarChartType : public BrainBrowserWindowToolBarComponent { Q_OBJECT public: BrainBrowserWindowToolBarChartType(BrainBrowserWindowToolBar* parentToolBar, const QString& parentObjectName); virtual ~BrainBrowserWindowToolBarChartType(); virtual void updateContent(BrowserTabContent* browserTabContent); private slots: void chartTypeRadioButtonClicked(int buttonIndex); private: BrainBrowserWindowToolBarChartType(const BrainBrowserWindowToolBarChartType&); BrainBrowserWindowToolBarChartType& operator=(const BrainBrowserWindowToolBarChartType&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE BrainBrowserWindowToolBar* m_parentToolBar; std::vector > m_chartTypeRadioButtons; QButtonGroup* m_chartTypeButtonGroup; // QRadioButton* m_chartMatrixLayerTypeRadioButton; // // QRadioButton* m_chartMatrixSeriesTypeRadioButton; // // QRadioButton* m_chartDataSeriesTypeRadioButton; // // QRadioButton* m_chartFrequencySeriesTypeRadioButton; // // QRadioButton* m_chartTimeSeriesTypeRadioButton; }; #ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_DECLARE__ // #endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_DECLARE__ } // namespace #endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_CHART_H__ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarClipping.cxx000066400000000000000000000223701360521144700267430ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CLIPPING_DECLARE__ #include "BrainBrowserWindowToolBarClipping.h" #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CLIPPING_DECLARE__ #include "BrowserTabContent.h" #include "CaretAssert.h" #include "GuiManager.h" #include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::BrainBrowserWindowToolBarClipping * \brief Clipping group for toolbar. * \ingroup GuiQt */ /** * Constructor. * * @param browserWindowIndex * Index of window * @param parentToolBar * The parent toolbar * @param parentObjectNamePrefix * Name of parent object */ BrainBrowserWindowToolBarClipping::BrainBrowserWindowToolBarClipping(const int32_t browserWindowIndex, BrainBrowserWindowToolBar* parentToolBar, const QString& parentObjectNamePrefix) : BrainBrowserWindowToolBarComponent(parentToolBar), m_browserWindowIndex(browserWindowIndex), m_parentToolBar(parentToolBar) { WuQMacroManager* macroManager = WuQMacroManager::instance(); CaretAssert(macroManager); const QString objectNamePrefix(parentObjectNamePrefix + ":Clipping"); m_xClippingEnabledCheckBox = new QCheckBox("X"); QObject::connect(m_xClippingEnabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(clippingCheckBoxCheckStatusChanged())); m_xClippingEnabledCheckBox->setToolTip("Enable X clipping plane"); m_xClippingEnabledCheckBox->setObjectName(objectNamePrefix + ":EnableX"); macroManager->addMacroSupportToObject(m_xClippingEnabledCheckBox, "Enable X clipping plane"); m_yClippingEnabledCheckBox = new QCheckBox("Y"); QObject::connect(m_yClippingEnabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(clippingCheckBoxCheckStatusChanged())); m_yClippingEnabledCheckBox->setToolTip("Enable Y clipping plane"); m_yClippingEnabledCheckBox->setObjectName(objectNamePrefix + ":EnableY"); macroManager->addMacroSupportToObject(m_yClippingEnabledCheckBox, "Enable Y clipping plane"); m_zClippingEnabledCheckBox = new QCheckBox("Z"); QObject::connect(m_zClippingEnabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(clippingCheckBoxCheckStatusChanged())); m_zClippingEnabledCheckBox->setToolTip("Enable Z clipping plane"); m_zClippingEnabledCheckBox->setObjectName(objectNamePrefix + ":EnableZ"); macroManager->addMacroSupportToObject(m_zClippingEnabledCheckBox, "Enable Z clipping"); m_surfaceClippingEnabledCheckBox = new QCheckBox("Surface"); QObject::connect(m_surfaceClippingEnabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(clippingCheckBoxCheckStatusChanged())); m_surfaceClippingEnabledCheckBox->setToolTip("Enable Clipping of Surface"); m_surfaceClippingEnabledCheckBox->setObjectName(objectNamePrefix + ":EnableSurface"); macroManager->addMacroSupportToObject(m_surfaceClippingEnabledCheckBox, "Enable surface clipping"); m_volumeClippingEnabledCheckBox = new QCheckBox("Volume"); QObject::connect(m_volumeClippingEnabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(clippingCheckBoxCheckStatusChanged())); m_volumeClippingEnabledCheckBox->setToolTip("Enable Clipping of Volume Slices"); m_volumeClippingEnabledCheckBox->setObjectName(objectNamePrefix + ":EnableVolume"); macroManager->addMacroSupportToObject(m_volumeClippingEnabledCheckBox, "Enable volume clipping"); m_featuresClippingEnabledCheckBox = new QCheckBox("Features"); QObject::connect(m_featuresClippingEnabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(clippingCheckBoxCheckStatusChanged())); m_featuresClippingEnabledCheckBox->setToolTip("Enable Clipping of Features"); m_featuresClippingEnabledCheckBox->setObjectName(objectNamePrefix + ":EnableFeatures"); macroManager->addMacroSupportToObject(m_featuresClippingEnabledCheckBox, "Enable features clipping"); QToolButton* setupToolButton = new QToolButton(); setupToolButton->setText("Setup"); QObject::connect(setupToolButton, SIGNAL(clicked()), this, SLOT(setupClippingPushButtonClicked())); WuQtUtilities::setToolButtonStyleForQt5Mac(setupToolButton); setupToolButton->setToolTip("Display Clipping Planes Setup Dialog"); setupToolButton->setObjectName(objectNamePrefix + ":ShowSetupDialog"); macroManager->addMacroSupportToObject(setupToolButton, "Display clipping planes dialog"); QGridLayout* gridLayout = new QGridLayout(this); gridLayout->setHorizontalSpacing(6); gridLayout->setVerticalSpacing(4); gridLayout->setContentsMargins(1, 1, 1, 1); int32_t rowIndex = gridLayout->rowCount(); gridLayout->addWidget(m_xClippingEnabledCheckBox, rowIndex, 0); gridLayout->addWidget(m_yClippingEnabledCheckBox, rowIndex, 1); gridLayout->addWidget(m_zClippingEnabledCheckBox, rowIndex, 2); rowIndex++; gridLayout->addWidget(m_featuresClippingEnabledCheckBox, rowIndex, 0, 1, 3); rowIndex++; gridLayout->addWidget(m_surfaceClippingEnabledCheckBox, rowIndex, 0, 1, 3); rowIndex++; gridLayout->addWidget(m_volumeClippingEnabledCheckBox, rowIndex, 0, 1, 3); rowIndex++; gridLayout->addWidget(setupToolButton, rowIndex, 0, 1, 3, Qt::AlignHCenter); } /** * Destructor. */ BrainBrowserWindowToolBarClipping::~BrainBrowserWindowToolBarClipping() { } /** * Update the surface montage options widget. * * @param browserTabContent * The active model display controller (may be NULL). */ void BrainBrowserWindowToolBarClipping::updateContent(BrowserTabContent* browserTabContent) { bool xEnabled; bool yEnabled; bool zEnabled; bool surfaceEnabled; bool volumeEnabled; bool featuresEnabled; browserTabContent->getClippingPlaneEnabled(xEnabled, yEnabled, zEnabled, surfaceEnabled, volumeEnabled, featuresEnabled); m_xClippingEnabledCheckBox->setChecked(xEnabled); m_yClippingEnabledCheckBox->setChecked(yEnabled); m_zClippingEnabledCheckBox->setChecked(zEnabled); m_surfaceClippingEnabledCheckBox->setChecked(surfaceEnabled); m_volumeClippingEnabledCheckBox->setChecked(volumeEnabled); m_featuresClippingEnabledCheckBox->setChecked(featuresEnabled); } /** * Called when a clipping checkbox status is changed. */ void BrainBrowserWindowToolBarClipping::clippingCheckBoxCheckStatusChanged() { BrowserTabContent* browserTabContent = getTabContentFromSelectedTab(); if (browserTabContent != NULL) { browserTabContent->setClippingPlaneEnabled(m_xClippingEnabledCheckBox->isChecked(), m_yClippingEnabledCheckBox->isChecked(), m_zClippingEnabledCheckBox->isChecked(), m_surfaceClippingEnabledCheckBox->isChecked(), m_volumeClippingEnabledCheckBox->isChecked(), m_featuresClippingEnabledCheckBox->isChecked()); this->updateGraphicsWindowAndYokedWindows(); } } /** * Called when the setup clipping push button is clicked. */ void BrainBrowserWindowToolBarClipping::setupClippingPushButtonClicked() { BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(m_browserWindowIndex); GuiManager::get()->processShowClippingPlanesDialog(browserWindow); } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarClipping.h000066400000000000000000000052011360521144700263620ustar00rootroot00000000000000#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CLIPPING_H__ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_CLIPPING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "BrainBrowserWindowToolBarComponent.h" namespace caret { class BrainBrowserWindowToolBarClipping : public BrainBrowserWindowToolBarComponent { Q_OBJECT public: BrainBrowserWindowToolBarClipping(const int32_t browserWindowIndex, BrainBrowserWindowToolBar* parentToolBar, const QString& objectNamePrefix); virtual ~BrainBrowserWindowToolBarClipping(); virtual void updateContent(BrowserTabContent* browserTabContent); // ADD_NEW_METHODS_HERE private slots: void clippingCheckBoxCheckStatusChanged(); void setupClippingPushButtonClicked(); private: BrainBrowserWindowToolBarClipping(const BrainBrowserWindowToolBarClipping&); BrainBrowserWindowToolBarClipping& operator=(const BrainBrowserWindowToolBarClipping&); const int32_t m_browserWindowIndex; BrainBrowserWindowToolBar* m_parentToolBar; QCheckBox* m_xClippingEnabledCheckBox; QCheckBox* m_yClippingEnabledCheckBox; QCheckBox* m_zClippingEnabledCheckBox; QCheckBox* m_surfaceClippingEnabledCheckBox; QCheckBox* m_volumeClippingEnabledCheckBox; QCheckBox* m_featuresClippingEnabledCheckBox; // ADD_NEW_MEMBERS_HERE }; #ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_CLIPPING_DECLARE__ // #endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_CLIPPING_DECLARE__ } // namespace #endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_CLIPPING_H__ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarComponent.cxx000066400000000000000000000076411360521144700271440ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_COMPONENT_DECLARE__ #include "BrainBrowserWindowToolBarComponent.h" #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_COMPONENT_DECLARE__ #include "BrainBrowserWindowToolBar.h" #include "CaretAssert.h" #include "EventManager.h" #include "EventSurfaceColoringInvalidate.h" #include "WuQWidgetObjectGroup.h" using namespace caret; /** * \class caret::BrainBrowserWindowToolBarComponent * \brief Abstract class for brain browser window tool bar components. * \ingroup GuiQt * */ /** * Constructor. * * @param parent * Parent widget. */ BrainBrowserWindowToolBarComponent::BrainBrowserWindowToolBarComponent(BrainBrowserWindowToolBar* parentToolBar) : QWidget(parentToolBar), m_parentToolBar(parentToolBar) { m_widgetGroup = new WuQWidgetObjectGroup(this); // EventManager::get()->addEventListener(this, EventTypeEnum::); } /** * Destructor. */ BrainBrowserWindowToolBarComponent::~BrainBrowserWindowToolBarComponent() { m_widgetGroup->clear(); EventManager::get()->removeAllEventsFromListener(this); } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void BrainBrowserWindowToolBarComponent::receiveEvent(Event* /*event*/) { // if (event->getEventType() == EventTypeEnum::) { // eventName = dynamic_cast(event); // CaretAssert(eventName); // // event->setEventProcessed(); // } } /** * Add a widget/object to the widget group so that all items can be * enabled or disabled. * * @param qObject * QObject or QWidget subclass added to widget group. */ void BrainBrowserWindowToolBarComponent::addToWidgetGroup(QObject* qObject) { CaretAssert(qObject); m_widgetGroup->add(qObject); } /** * Block/unblock signals for components in the widget group. * * @param blocked * New status for blocked (true/false). */ void BrainBrowserWindowToolBarComponent::blockAllSignals(const bool blocked) { m_widgetGroup->blockAllSignals(blocked); } /** * @return The browser tab content for the selected tab. */ BrowserTabContent* BrainBrowserWindowToolBarComponent::getTabContentFromSelectedTab() { return m_parentToolBar->getTabContentFromSelectedTab(); } /** * Invalidate surface coloring and update the graphics in the * window containing this toolbar. */ void BrainBrowserWindowToolBarComponent::invalidateColoringAndUpdateGraphicsWindow() { EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); updateGraphicsWindow(); } /** * Update the graphics window. */ void BrainBrowserWindowToolBarComponent::updateGraphicsWindow() { m_parentToolBar->updateGraphicsWindow(); } /** * If this window is yoked, update all windows since they may * be yoked to this window. If NOT yoked, just update this window. */ void BrainBrowserWindowToolBarComponent::updateGraphicsWindowAndYokedWindows() { m_parentToolBar->updateGraphicsWindowAndYokedWindows(); } /** * Update the user interface. */ void BrainBrowserWindowToolBarComponent::updateUserInterface() { m_parentToolBar->updateUserInterface(); } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarComponent.h000066400000000000000000000052511360521144700265640ustar00rootroot00000000000000#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_COMPONENT_H__ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_COMPONENT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "EventListenerInterface.h" namespace caret { class BrainBrowserWindowToolBar; class BrowserTabContent; class WuQWidgetObjectGroup; class BrainBrowserWindowToolBarComponent : public QWidget, public EventListenerInterface { Q_OBJECT protected: BrainBrowserWindowToolBarComponent(BrainBrowserWindowToolBar* parentToolBar); public: virtual ~BrainBrowserWindowToolBarComponent(); virtual void updateContent(BrowserTabContent* browserTabContent) = 0; BrowserTabContent* getTabContentFromSelectedTab(); void invalidateColoringAndUpdateGraphicsWindow(); void updateGraphicsWindow(); void updateGraphicsWindowAndYokedWindows(); void updateUserInterface(); private: BrainBrowserWindowToolBarComponent(const BrainBrowserWindowToolBarComponent&); BrainBrowserWindowToolBarComponent& operator=(const BrainBrowserWindowToolBarComponent&); protected: void addToWidgetGroup(QObject* qObject); void blockAllSignals(const bool status); public: // ADD_NEW_METHODS_HERE virtual void receiveEvent(Event* event); private: BrainBrowserWindowToolBar* m_parentToolBar; WuQWidgetObjectGroup* m_widgetGroup; // ADD_NEW_MEMBERS_HERE friend class BrainBrowserWindowToolBarChartTwoOrientation; }; #ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_COMPONENT_DECLARE__ // #endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_COMPONENT_DECLARE__ } // namespace #endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_COMPONENT_H__ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.cxx000066400000000000000000000621371360521144700272220ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_SLICE_PLANE_DECLARE__ #include "BrainBrowserWindowToolBarSlicePlane.h" #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_SLICE_PLANE_DECLARE__ #include #include #include #include #include #include #include #include #include #include "BrainBrowserWindowToolBar.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPreferenceDataValue.h" #include "CaretPreferences.h" #include "GuiManager.h" #include "SessionManager.h" #include "WuQMacroManager.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::BrainBrowserWindowToolBarSlicePlane * \brief Toolbar component for volume slice plane and projection selection. * \ingroup GuiQt */ /** * Constructor. * * @param parentToolBar * The parent toolbar */ BrainBrowserWindowToolBarSlicePlane::BrainBrowserWindowToolBarSlicePlane(const QString& parentObjectName, BrainBrowserWindowToolBar* parentToolBar) : BrainBrowserWindowToolBarComponent(parentToolBar), m_parentToolBar(parentToolBar) { WuQMacroManager* macroManager = WuQMacroManager::instance(); CaretAssert(macroManager); const QString objectNamePrefix(parentObjectName + ":SlicePlane:"); QIcon parasagittalIcon; const bool parasagittalIconValid = WuQtUtilities::loadIcon(":/ToolBar/view-plane-parasagittal.png", parasagittalIcon); QIcon coronalIcon; const bool coronalIconValid = WuQtUtilities::loadIcon(":/ToolBar/view-plane-coronal.png", coronalIcon); QIcon axialIcon; const bool axialIconValid = WuQtUtilities::loadIcon(":/ToolBar/view-plane-axial.png", axialIcon); m_volumePlaneParasagittalToolButtonAction = WuQtUtilities::createAction(VolumeSliceViewPlaneEnum::toGuiNameAbbreviation(VolumeSliceViewPlaneEnum::PARASAGITTAL), "View the PARASAGITTAL slice", this); m_volumePlaneParasagittalToolButtonAction->setCheckable(true); if (parasagittalIconValid) { m_volumePlaneParasagittalToolButtonAction->setIcon(parasagittalIcon); } m_volumePlaneParasagittalToolButtonAction->setObjectName(objectNamePrefix + "ParasagittalSliceView"); macroManager->addMacroSupportToObject(m_volumePlaneParasagittalToolButtonAction, "Select parasagittal slice view"); m_volumePlaneCoronalToolButtonAction = WuQtUtilities::createAction(VolumeSliceViewPlaneEnum::toGuiNameAbbreviation(VolumeSliceViewPlaneEnum::CORONAL), "View the CORONAL slice", this); m_volumePlaneCoronalToolButtonAction->setCheckable(true); if (coronalIconValid) { m_volumePlaneCoronalToolButtonAction->setIcon(coronalIcon); } m_volumePlaneCoronalToolButtonAction->setObjectName(objectNamePrefix + "CoronalSliceView"); macroManager->addMacroSupportToObject(m_volumePlaneCoronalToolButtonAction, "Select coronal slice view"); m_volumePlaneAxialToolButtonAction = WuQtUtilities::createAction(VolumeSliceViewPlaneEnum::toGuiNameAbbreviation(VolumeSliceViewPlaneEnum::AXIAL), "View the AXIAL slice", this); m_volumePlaneAxialToolButtonAction->setCheckable(true); if (axialIconValid) { m_volumePlaneAxialToolButtonAction->setIcon(axialIcon); } m_volumePlaneAxialToolButtonAction->setObjectName(objectNamePrefix + "AxialSliceView"); macroManager->addMacroSupportToObject(m_volumePlaneAxialToolButtonAction, "Select axial slice view"); m_volumePlaneAllToolButtonAction = WuQtUtilities::createAction(VolumeSliceViewPlaneEnum::toGuiNameAbbreviation(VolumeSliceViewPlaneEnum::ALL), "View the PARASAGITTAL, CORONAL, and AXIAL slices\n" "Press arrow to display menu for layout selection", this); m_volumePlaneAllToolButtonAction->setCheckable(true); m_volumePlaneAllToolButtonAction->setMenu(createViewAllSlicesLayoutMenu(objectNamePrefix)); m_volumePlaneAllToolButtonAction->setObjectName(objectNamePrefix + "AllSlicesView"); macroManager->addMacroSupportToObject(m_volumePlaneAllToolButtonAction, "Select all planes view"); m_volumePlaneActionGroup = new QActionGroup(this); m_volumePlaneActionGroup->addAction(m_volumePlaneParasagittalToolButtonAction); m_volumePlaneActionGroup->addAction(m_volumePlaneCoronalToolButtonAction); m_volumePlaneActionGroup->addAction(m_volumePlaneAxialToolButtonAction); m_volumePlaneActionGroup->addAction(m_volumePlaneAllToolButtonAction); m_volumePlaneActionGroup->setExclusive(true); QObject::connect(m_volumePlaneActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(volumePlaneActionGroupTriggered(QAction*))); m_volumePlaneResetToolButtonAction = WuQtUtilities::createAction("Reset", "Reset to remove panning, zooming, and/or oblique rotation", this, this, SLOT(volumePlaneResetToolButtonTriggered(bool))); m_volumePlaneResetToolButtonAction->setObjectName(objectNamePrefix + "ResetView"); macroManager->addMacroSupportToObject(m_volumePlaneResetToolButtonAction, "Reset slice view pan/rotate/zoom"); QToolButton* volumePlaneParasagittalToolButton = new QToolButton(); volumePlaneParasagittalToolButton->setDefaultAction(m_volumePlaneParasagittalToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(volumePlaneParasagittalToolButton); m_volumePlaneParasagittalToolButtonAction->setParent(volumePlaneParasagittalToolButton); QToolButton* volumePlaneCoronalToolButton = new QToolButton(); volumePlaneCoronalToolButton->setDefaultAction(m_volumePlaneCoronalToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(volumePlaneCoronalToolButton); m_volumePlaneCoronalToolButtonAction->setParent(volumePlaneCoronalToolButton); QToolButton* volumePlaneAxialToolButton = new QToolButton(); volumePlaneAxialToolButton->setDefaultAction(m_volumePlaneAxialToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(volumePlaneAxialToolButton); m_volumePlaneAxialToolButtonAction->setParent(volumePlaneAxialToolButton); QToolButton* volumePlaneAllToolButton = new QToolButton(); volumePlaneAllToolButton->setDefaultAction(m_volumePlaneAllToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(volumePlaneAllToolButton); m_volumePlaneAllToolButtonAction->setParent(volumePlaneAllToolButton); QToolButton* volumePlaneResetToolButton = new QToolButton(); volumePlaneResetToolButton->setDefaultAction(m_volumePlaneResetToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(volumePlaneResetToolButton); WuQtUtilities::matchWidgetHeights(volumePlaneParasagittalToolButton, volumePlaneCoronalToolButton, volumePlaneAxialToolButton, volumePlaneAllToolButton); WuQtUtilities::matchWidgetWidths(volumePlaneParasagittalToolButton, volumePlaneCoronalToolButton, volumePlaneAxialToolButton, volumePlaneAllToolButton); QToolButton* slicePlaneCustomToolButton = new QToolButton(); slicePlaneCustomToolButton->setDefaultAction(m_parentToolBar->customViewAction); slicePlaneCustomToolButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); WuQtUtilities::setToolButtonStyleForQt5Mac(slicePlaneCustomToolButton); m_volumeAxisCrosshairsToolButtonAction = new QAction("", this); m_volumeAxisCrosshairsToolButtonAction->setCheckable(true); m_volumeAxisCrosshairsToolButtonAction->setToolTip("" "Show crosshairs on slice planes.
    " "Press arrow to adjust gap" ""); m_volumeAxisCrosshairsToolButtonAction->setMenu(createCrosshairMenu(objectNamePrefix)); QObject::connect(m_volumeAxisCrosshairsToolButtonAction, &QAction::triggered, this, &BrainBrowserWindowToolBarSlicePlane::volumeAxisCrosshairsTriggered); m_volumeAxisCrosshairsToolButtonAction->setObjectName(objectNamePrefix + "ShowVolumeSliceCrosshairs"); macroManager->addMacroSupportToObject(m_volumeAxisCrosshairsToolButtonAction, "Show slice axis crosshairs"); QToolButton* volumeCrosshairsToolButton = new QToolButton(); QPixmap xhairPixmap = createCrosshairsIcon(volumeCrosshairsToolButton); volumeCrosshairsToolButton->setDefaultAction(m_volumeAxisCrosshairsToolButtonAction); m_volumeAxisCrosshairsToolButtonAction->setIcon(QIcon(xhairPixmap)); volumeCrosshairsToolButton->setIconSize(xhairPixmap.size()); WuQtUtilities::setToolButtonStyleForQt5Mac(volumeCrosshairsToolButton); m_volumeAxisCrosshairLabelsToolButtonAction = new QAction("", this); m_volumeAxisCrosshairLabelsToolButtonAction->setCheckable(true); m_volumeAxisCrosshairLabelsToolButtonAction->setToolTip("Show crosshair slice plane labels"); QObject::connect(m_volumeAxisCrosshairLabelsToolButtonAction, &QAction::triggered, this, &BrainBrowserWindowToolBarSlicePlane::volumeAxisCrosshairLabelsTriggered); m_volumeAxisCrosshairLabelsToolButtonAction->setObjectName(objectNamePrefix + "ShowVolumeSliceLabels"); macroManager->addMacroSupportToObject(m_volumeAxisCrosshairLabelsToolButtonAction, "Show slice axis labels"); QToolButton* volumeCrosshairLabelsToolButton = new QToolButton(); volumeCrosshairLabelsToolButton->setDefaultAction(m_volumeAxisCrosshairLabelsToolButtonAction); QPixmap labelsPixmap = createCrosshairLabelsIcon(volumeCrosshairLabelsToolButton); m_volumeAxisCrosshairLabelsToolButtonAction->setIcon(QIcon(labelsPixmap)); volumeCrosshairLabelsToolButton->setIconSize(labelsPixmap.size()); WuQtUtilities::setToolButtonStyleForQt5Mac(volumeCrosshairLabelsToolButton); QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 0, 0); int32_t rowIndex = gridLayout->rowCount(); gridLayout->addWidget(volumePlaneParasagittalToolButton, rowIndex, 0); gridLayout->addWidget(volumePlaneCoronalToolButton, rowIndex, 1); rowIndex++; gridLayout->addWidget(volumePlaneAxialToolButton, rowIndex, 0); gridLayout->addWidget(volumePlaneAllToolButton, rowIndex, 1); rowIndex++; gridLayout->addWidget(volumePlaneResetToolButton, rowIndex, 0, 1, 2, Qt::AlignHCenter); rowIndex++; gridLayout->addWidget(slicePlaneCustomToolButton, rowIndex, 0, 1, 2, Qt::AlignHCenter); rowIndex++; gridLayout->addWidget(volumeCrosshairsToolButton, rowIndex, 0, Qt::AlignRight); gridLayout->addWidget(volumeCrosshairLabelsToolButton, rowIndex, 1, Qt::AlignLeft); m_volumePlaneWidgetGroup = new WuQWidgetObjectGroup(this); m_volumePlaneWidgetGroup->add(m_volumePlaneActionGroup); m_volumePlaneWidgetGroup->add(m_volumePlaneResetToolButtonAction); } /** * Destructor. */ BrainBrowserWindowToolBarSlicePlane::~BrainBrowserWindowToolBarSlicePlane() { } /** * Update the surface montage options widget. * * @param browserTabContent * The active model display controller (may be NULL). */ void BrainBrowserWindowToolBarSlicePlane::updateContent(BrowserTabContent* browserTabContent) { m_volumePlaneWidgetGroup->blockAllSignals(true); switch (browserTabContent->getSliceViewPlane()) { case VolumeSliceViewPlaneEnum::ALL: m_volumePlaneAllToolButtonAction->setChecked(true); break; case VolumeSliceViewPlaneEnum::AXIAL: m_volumePlaneAxialToolButtonAction->setChecked(true); break; case VolumeSliceViewPlaneEnum::CORONAL: m_volumePlaneCoronalToolButtonAction->setChecked(true); break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: m_volumePlaneParasagittalToolButtonAction->setChecked(true); break; } updateViewAllSlicesLayoutMenu(browserTabContent); m_volumeAxisCrosshairsToolButtonAction->setChecked(browserTabContent->isVolumeAxesCrosshairsDisplayed()); m_volumeAxisCrosshairLabelsToolButtonAction->setChecked(browserTabContent->isVolumeAxesCrosshairLabelsDisplayed()); m_volumePlaneWidgetGroup->blockAllSignals(false); } /** * @return A new instance of the view all slices layout menu. * @param objectNamePrefix * Prefix for object names in macro system */ QMenu* BrainBrowserWindowToolBarSlicePlane::createViewAllSlicesLayoutMenu(const QString& objectNamePrefix) { std::vector allLayouts; VolumeSliceViewAllPlanesLayoutEnum::getAllEnums(allLayouts); QMenu* menu = new QMenu(this); menu->setObjectName(objectNamePrefix + "LayoutMenu"); menu->setToolTip("Selects layout of volume slices (column, grid, row)"); QActionGroup* actionGroup = new QActionGroup(this); for (auto layout : allLayouts) { QAction* action = menu->addAction(VolumeSliceViewAllPlanesLayoutEnum::toGuiName(layout)); action->setData((int)VolumeSliceViewAllPlanesLayoutEnum::toIntegerCode(layout)); action->setCheckable(true); action->setObjectName(objectNamePrefix + ":Layout:" + VolumeSliceViewAllPlanesLayoutEnum::toName(layout)); m_viewAllSliceLayoutMenuActions.push_back(action); actionGroup->addAction(action); WuQMacroManager::instance()->addMacroSupportToObject(action, "Select " + VolumeSliceViewAllPlanesLayoutEnum::toGuiName(layout) + " volume slice layout"); } QObject::connect(menu, &QMenu::triggered, this, &BrainBrowserWindowToolBarSlicePlane::viewAllSliceLayoutMenuTriggered); return menu; } /** * @return A new instance of the crosshair menu * @param objectNamePrefix * Prefix for object names in macro system * @return * Menu for crosshair button */ QMenu* BrainBrowserWindowToolBarSlicePlane::createCrosshairMenu(const QString& objectNamePrefix) { m_crosshairGapSpinBox = new QDoubleSpinBox(); m_crosshairGapSpinBox->setMinimum(0.0); m_crosshairGapSpinBox->setMaximum(100); m_crosshairGapSpinBox->setSingleStep(0.1); m_crosshairGapSpinBox->setDecimals(1); m_crosshairGapSpinBox->setSuffix("%"); m_crosshairGapSpinBox->setObjectName(objectNamePrefix + "CrossHairGapSinBox"); m_crosshairGapSpinBox->setToolTip("Gap for cross hairs as percentage of window height"); QObject::connect(m_crosshairGapSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), this, &BrainBrowserWindowToolBarSlicePlane::crosshairGapSpinBoxValueChanged); QLabel* crosshairLabel = new QLabel("Gap "); QWidget* crosshairWidget = new QWidget(); QHBoxLayout* crosshairLayout = new QHBoxLayout(crosshairWidget); crosshairLayout->setContentsMargins(0, 0, 0, 0); crosshairLayout->addWidget(crosshairLabel); crosshairLayout->addWidget(m_crosshairGapSpinBox); crosshairWidget->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); QWidgetAction* crossHairGapWidgetAction = new QWidgetAction(this); crossHairGapWidgetAction->setDefaultWidget(crosshairWidget); QMenu* menu = new QMenu(this); QObject::connect(menu, &QMenu::aboutToShow, this, &BrainBrowserWindowToolBarSlicePlane::crosshairMenuAboutToShow); menu->addAction(crossHairGapWidgetAction); return menu; } /** * Called when crosshair menu is about to show */ void BrainBrowserWindowToolBarSlicePlane::crosshairMenuAboutToShow() { const float gapValue = SessionManager::get()->getCaretPreferences()->getVolumeCrosshairGap(); QSignalBlocker blocker(m_crosshairGapSpinBox); m_crosshairGapSpinBox->setValue(gapValue); } /** * Called when crosshair gap spin box value changed * * @param value * New value for crosshair gap. */ void BrainBrowserWindowToolBarSlicePlane::crosshairGapSpinBoxValueChanged(double value) { SessionManager::get()->getCaretPreferences()->setVolumeCrosshairGap(value); GuiManager::updateGraphicsAllWindows(); } /** * Gets called when the user selects an item on the view all slices layout menu. * * @param action * Action of menu item selected. */ void BrainBrowserWindowToolBarSlicePlane::viewAllSliceLayoutMenuTriggered(QAction* action) { const int layoutInt = action->data().toInt(); bool validFlag = false; const VolumeSliceViewAllPlanesLayoutEnum::Enum layout = VolumeSliceViewAllPlanesLayoutEnum::fromIntegerCode(layoutInt, &validFlag); if (validFlag) { BrowserTabContent* btc = getTabContentFromSelectedTab(); btc->setSlicePlanesAllViewLayout(layout); m_parentToolBar->updateVolumeIndicesWidget(btc); updateGraphicsWindowAndYokedWindows(); } else { CaretLogSevere("Invalid layout in menu item: " + action->text()); } } /** * Update the view all slices layout menu. */ void BrainBrowserWindowToolBarSlicePlane::updateViewAllSlicesLayoutMenu(BrowserTabContent* browserTabContent) { const VolumeSliceViewAllPlanesLayoutEnum::Enum layout = browserTabContent->getSlicePlanesAllViewLayout(); const int layoutIntValue = VolumeSliceViewAllPlanesLayoutEnum::toIntegerCode(layout); for (auto action : m_viewAllSliceLayoutMenuActions) { if (action->data().toInt() == layoutIntValue) { action->setChecked(true); break; } } } /** * Called when volume slice plane button is clicked. */ void BrainBrowserWindowToolBarSlicePlane::volumePlaneActionGroupTriggered(QAction* action) { VolumeSliceViewPlaneEnum::Enum plane = VolumeSliceViewPlaneEnum::AXIAL; if (action == m_volumePlaneAllToolButtonAction) { plane = VolumeSliceViewPlaneEnum::ALL; } else if (action == m_volumePlaneAxialToolButtonAction) { plane = VolumeSliceViewPlaneEnum::AXIAL; } else if (action == m_volumePlaneCoronalToolButtonAction) { plane = VolumeSliceViewPlaneEnum::CORONAL; } else if (action == m_volumePlaneParasagittalToolButtonAction) { plane = VolumeSliceViewPlaneEnum::PARASAGITTAL; } else { CaretLogSevere("Invalid volume plane action: " + action->text()); } BrowserTabContent* btc = getTabContentFromSelectedTab(); btc->setSliceViewPlane(plane); m_parentToolBar->updateVolumeIndicesWidget(btc); updateGraphicsWindowAndYokedWindows(); } /** * Called when volume reset slice view button is pressed. */ void BrainBrowserWindowToolBarSlicePlane::volumePlaneResetToolButtonTriggered(bool /*checked*/) { BrowserTabContent* btc = getTabContentFromSelectedTab(); btc->resetView(); m_parentToolBar->updateVolumeIndicesWidget(btc); updateGraphicsWindowAndYokedWindows(); } /** * Called when volume axis crosshairs button triggered * * @param checked * New checked status */ void BrainBrowserWindowToolBarSlicePlane::volumeAxisCrosshairsTriggered(bool checked) { BrowserTabContent* btc = getTabContentFromSelectedTab(); btc->setVolumeAxesCrosshairsDisplayed(checked); updateGraphicsWindowAndYokedWindows(); } /** * Called when volume axis crosshair labels button triggered * * @param checked * New checked status */ void BrainBrowserWindowToolBarSlicePlane::volumeAxisCrosshairLabelsTriggered(bool checked) { BrowserTabContent* btc = getTabContentFromSelectedTab(); btc->setVolumeAxesCrosshairLabelsDisplayed(checked); updateGraphicsWindowAndYokedWindows(); } /** * Create a pixmap for the crosshairs button. * * @param widget * To color the pixmap with backround and foreground, * the palette from the given widget is used. * @return * The pixmap. */ QPixmap BrainBrowserWindowToolBarSlicePlane::createCrosshairsIcon(const QWidget* widget) { CaretAssert(widget); const float pixmapSize = 22.0; QPixmap pixmap(static_cast(pixmapSize), static_cast(pixmapSize)); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginCenter(widget, pixmap, static_cast(WuQtUtilities::PixMapCreationOptions::TransparentBackground)); const int startXY = 4; const int endXY = 10; QPen pen(painter->pen()); pen.setWidth(2); painter->setPen(pen); painter->drawLine(-startXY, 0, -endXY, 0); painter->drawLine( startXY, 0, endXY, 0); painter->drawLine(0, -startXY, 0, -endXY); painter->drawLine(0, startXY, 0, endXY); return pixmap; } /** * Create a pixmap for the crosshairs button. * * @param widget * To color the pixmap with backround and foreground, * the palette from the given widget is used. * @return * The pixmap. */ QPixmap BrainBrowserWindowToolBarSlicePlane::createCrosshairLabelsIcon(const QWidget* widget) { CaretAssert(widget); const float pixmapSize = 22.0f; const float fullXY = pixmapSize; const float halfXY = fullXY / 2.0f; const float boxWH = 8.0f; const float halfBoxWH = boxWH / 2.0f; QPixmap pixmap(static_cast(pixmapSize), static_cast(pixmapSize)); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainter(widget, pixmap, static_cast(WuQtUtilities::PixMapCreationOptions::TransparentBackground)); QFont font = painter->font(); font.setPixelSize(10); painter->setFont(font); const float edgeOffset = 1.0f; painter->drawText(QRectF(edgeOffset, halfXY - halfBoxWH, boxWH, boxWH), "L", QTextOption(Qt::AlignCenter)); painter->drawText(QRectF(fullXY - boxWH - edgeOffset + 1, halfXY - halfBoxWH - 1, boxWH, boxWH), "R", QTextOption(Qt::AlignCenter)); painter->drawText(QRectF(halfXY - halfBoxWH, edgeOffset, boxWH, boxWH), "A", QTextOption(Qt::AlignCenter)); painter->drawText(QRectF(halfXY - halfBoxWH + 1, fullXY - boxWH - edgeOffset, boxWH, boxWH), "P", QTextOption(Qt::AlignCenter)); return pixmap; } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarSlicePlane.h000066400000000000000000000071641360521144700266460ustar00rootroot00000000000000#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_SLICE_PLANE_H__ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_SLICE_PLANE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainBrowserWindowToolBarComponent.h" class QActionGroup; class QDoubleSpinBox; class QMenu; class QPixmap; namespace caret { class WuQWidgetObjectGroup; class BrainBrowserWindowToolBarSlicePlane : public BrainBrowserWindowToolBarComponent { Q_OBJECT public: BrainBrowserWindowToolBarSlicePlane(const QString& parentObjectName, BrainBrowserWindowToolBar* parentToolBar); virtual ~BrainBrowserWindowToolBarSlicePlane(); virtual void updateContent(BrowserTabContent* browserTabContent); // ADD_NEW_METHODS_HERE private slots: void volumePlaneActionGroupTriggered(QAction*); void volumePlaneResetToolButtonTriggered(bool checked); void viewAllSliceLayoutMenuTriggered(QAction* action); void volumeAxisCrosshairsTriggered(bool checked); void volumeAxisCrosshairLabelsTriggered(bool checked); void crosshairMenuAboutToShow(); private: BrainBrowserWindowToolBarSlicePlane(const BrainBrowserWindowToolBarSlicePlane&); BrainBrowserWindowToolBarSlicePlane& operator=(const BrainBrowserWindowToolBarSlicePlane&); QMenu* createViewAllSlicesLayoutMenu(const QString& objectNamePrefix); void updateViewAllSlicesLayoutMenu(BrowserTabContent* browserTabContent); QPixmap createCrosshairsIcon(const QWidget* widget); QPixmap createCrosshairLabelsIcon(const QWidget* widget); QMenu* createCrosshairMenu(const QString& objectNamePrefix); void crosshairGapSpinBoxValueChanged(double value); BrainBrowserWindowToolBar* m_parentToolBar; std::vector m_viewAllSliceLayoutMenuActions; WuQWidgetObjectGroup* m_volumePlaneWidgetGroup; QAction* m_volumePlaneParasagittalToolButtonAction; QAction* m_volumePlaneCoronalToolButtonAction; QAction* m_volumePlaneAxialToolButtonAction; QAction* m_volumePlaneAllToolButtonAction; QAction* m_volumePlaneResetToolButtonAction; QAction* m_volumeAxisCrosshairsToolButtonAction; QAction* m_volumeAxisCrosshairLabelsToolButtonAction; QActionGroup* m_volumePlaneActionGroup; QDoubleSpinBox* m_crosshairGapSpinBox; // ADD_NEW_MEMBERS_HERE }; #ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_SLICE_PLANE_DECLARE__ // #endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_SLICE_PLANE_DECLARE__ } // namespace #endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_SLICE_PLANE_H__ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.cxx000066400000000000000000001236351360521144700301110ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_SLICE_SELECTION_DECLARE__ #include "BrainBrowserWindowToolBarSliceSelection.h" #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_SLICE_SELECTION_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include "BrainBrowserWindowToolBar.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "EnumComboBoxTemplate.h" #include "EventManager.h" #include "EventUpdateVolumeEditingToolBar.h" #include "GuiManager.h" #include "ModelVolume.h" #include "ModelWholeBrain.h" #include "VolumeFile.h" #include "VolumeSliceInterpolationEdgeEffectsMaskingEnum.h" #include "VolumeSliceProjectionTypeEnum.h" #include "WuQFactory.h" #include "WuQMacroManager.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::BrainBrowserWindowToolBarSliceSelection * \brief Toolbar component for selection of volume slices. * \ingroup GuiQt */ /** * Constructor. * * @param parentToolBar * The parent toolbar. * @param parentObjectName * Name of parent object. */ BrainBrowserWindowToolBarSliceSelection::BrainBrowserWindowToolBarSliceSelection(BrainBrowserWindowToolBar* parentToolBar, const QString parentObjectName) : BrainBrowserWindowToolBarComponent(parentToolBar), m_parentToolBar(parentToolBar) { WuQMacroManager* macroManager = WuQMacroManager::instance(); CaretAssert(macroManager); const QString objectNamePrefix(parentObjectName + ":ToolBar:SliceSelection:"); QAction* volumeIndicesOriginToolButtonAction = WuQtUtilities::createAction("O\nR\nI\nG\nI\nN", "Set the slice indices to the origin, \n" "stereotaxic coordinate (0, 0, 0)", this, this, SLOT(volumeIndicesOriginActionTriggered())); QToolButton* volumeIndicesOriginToolButton = new QToolButton; volumeIndicesOriginToolButton->setDefaultAction(volumeIndicesOriginToolButtonAction); WuQtUtilities::setToolButtonStyleForQt5Mac(volumeIndicesOriginToolButton); volumeIndicesOriginToolButtonAction->setObjectName(objectNamePrefix + "MoveVolumeSlicesToOrigin"); volumeIndicesOriginToolButtonAction->setParent(volumeIndicesOriginToolButton); macroManager->addMacroSupportToObject(volumeIndicesOriginToolButtonAction, "Set volume slices to origin"); QLabel* parasagittalLabel = new QLabel("P:"); QLabel* coronalLabel = new QLabel("C:"); QLabel* axialLabel = new QLabel("A:"); m_volumeIndicesParasagittalCheckBox = new QCheckBox(" "); WuQtUtilities::setToolTipAndStatusTip(m_volumeIndicesParasagittalCheckBox, "Enable/Disable display of PARASAGITTAL slice"); m_volumeIndicesParasagittalCheckBox->setObjectName(objectNamePrefix + "EnableParasagittalSlice"); QObject::connect(m_volumeIndicesParasagittalCheckBox, SIGNAL(stateChanged(int)), this, SLOT(volumeIndicesParasagittalCheckBoxStateChanged(int))); macroManager->addMacroSupportToObject(m_volumeIndicesParasagittalCheckBox, "Enable parasagittal volume slice"); m_volumeIndicesCoronalCheckBox = new QCheckBox(" "); WuQtUtilities::setToolTipAndStatusTip(m_volumeIndicesCoronalCheckBox, "Enable/Disable display of CORONAL slice"); m_volumeIndicesCoronalCheckBox->setObjectName(objectNamePrefix + "EnableCoronalSlice"); QObject::connect(m_volumeIndicesCoronalCheckBox, SIGNAL(stateChanged(int)), this, SLOT(volumeIndicesCoronalCheckBoxStateChanged(int))); macroManager->addMacroSupportToObject(m_volumeIndicesCoronalCheckBox, "Enable coronal volume slice"); m_volumeIndicesAxialCheckBox = new QCheckBox(" "); WuQtUtilities::setToolTipAndStatusTip(m_volumeIndicesAxialCheckBox, "Enable/Disable display of AXIAL slice"); m_volumeIndicesAxialCheckBox->setObjectName(objectNamePrefix + "EnableAxialSlice"); QObject::connect(m_volumeIndicesAxialCheckBox, SIGNAL(stateChanged(int)), this, SLOT(volumeIndicesAxialCheckBoxStateChanged(int))); macroManager->addMacroSupportToObject(m_volumeIndicesAxialCheckBox, "Enable axial volume slice"); const int sliceIndexSpinBoxWidth = 55; const int sliceCoordinateSpinBoxWidth = 60; m_volumeIndicesParasagittalSpinBox = WuQFactory::newSpinBox(); m_volumeIndicesParasagittalSpinBox->setFixedWidth(sliceIndexSpinBoxWidth); WuQtUtilities::setToolTipAndStatusTip(m_volumeIndicesParasagittalSpinBox, "Change the selected PARASAGITTAL slice"); QObject::connect(m_volumeIndicesParasagittalSpinBox, SIGNAL(valueChanged(int)), this, SLOT(volumeIndicesParasagittalSpinBoxValueChanged(int))); m_volumeIndicesParasagittalSpinBox->setObjectName(objectNamePrefix + "VolumeParasagittalSliceIndex"); macroManager->addMacroSupportToObject(m_volumeIndicesParasagittalSpinBox, "Set parasagittal volume slice index"); m_volumeIndicesCoronalSpinBox = WuQFactory::newSpinBox(); m_volumeIndicesCoronalSpinBox->setFixedWidth(sliceIndexSpinBoxWidth); WuQtUtilities::setToolTipAndStatusTip(m_volumeIndicesCoronalSpinBox, "Change the selected CORONAL slice"); QObject::connect(m_volumeIndicesCoronalSpinBox, SIGNAL(valueChanged(int)), this, SLOT(volumeIndicesCoronalSpinBoxValueChanged(int))); m_volumeIndicesCoronalSpinBox->setObjectName(objectNamePrefix + "VolumeCoronalSliceIndex"); macroManager->addMacroSupportToObject(m_volumeIndicesCoronalSpinBox, "Set coronal volume slice index"); m_volumeIndicesAxialSpinBox = WuQFactory::newSpinBox(); m_volumeIndicesAxialSpinBox->setFixedWidth(sliceIndexSpinBoxWidth); WuQtUtilities::setToolTipAndStatusTip(m_volumeIndicesAxialSpinBox, "Change the selected AXIAL slice"); QObject::connect(m_volumeIndicesAxialSpinBox, SIGNAL(valueChanged(int)), this, SLOT(volumeIndicesAxialSpinBoxValueChanged(int))); m_volumeIndicesAxialSpinBox->setObjectName(objectNamePrefix + "VolumeAxialSliceIndex"); macroManager->addMacroSupportToObject(m_volumeIndicesAxialSpinBox, "Set axial volume slice index"); m_volumeIndicesXcoordSpinBox = WuQFactory::newDoubleSpinBox(); m_volumeIndicesXcoordSpinBox->setDecimals(1); m_volumeIndicesXcoordSpinBox->setFixedWidth(sliceCoordinateSpinBoxWidth); WuQtUtilities::setToolTipAndStatusTip(m_volumeIndicesXcoordSpinBox, "Adjust coordinate to select PARASAGITTAL slice"); QObject::connect(m_volumeIndicesXcoordSpinBox, SIGNAL(valueChanged(double)), this, SLOT(volumeIndicesXcoordSpinBoxValueChanged(double))); m_volumeIndicesXcoordSpinBox->setObjectName(objectNamePrefix + "VolumeParasagittalCoordinate"); macroManager->addMacroSupportToObject(m_volumeIndicesXcoordSpinBox, "Set parasagittal volume slice coordinate"); m_volumeIndicesYcoordSpinBox = WuQFactory::newDoubleSpinBox(); m_volumeIndicesYcoordSpinBox->setDecimals(1); m_volumeIndicesYcoordSpinBox->setFixedWidth(sliceCoordinateSpinBoxWidth); WuQtUtilities::setToolTipAndStatusTip(m_volumeIndicesYcoordSpinBox, "Adjust coordinate to select CORONAL slice"); QObject::connect(m_volumeIndicesYcoordSpinBox, SIGNAL(valueChanged(double)), this, SLOT(volumeIndicesYcoordSpinBoxValueChanged(double))); m_volumeIndicesYcoordSpinBox->setObjectName(objectNamePrefix + "VolumeCoronalCoordinate"); macroManager->addMacroSupportToObject(m_volumeIndicesYcoordSpinBox, "Set coronal volume slice coordinate"); m_volumeIndicesZcoordSpinBox = WuQFactory::newDoubleSpinBox(); m_volumeIndicesZcoordSpinBox->setDecimals(1); m_volumeIndicesZcoordSpinBox->setFixedWidth(sliceCoordinateSpinBoxWidth); WuQtUtilities::setToolTipAndStatusTip(m_volumeIndicesZcoordSpinBox, "Adjust coordinate to select AXIAL slice"); QObject::connect(m_volumeIndicesZcoordSpinBox, SIGNAL(valueChanged(double)), this, SLOT(volumeIndicesZcoordSpinBoxValueChanged(double))); m_volumeIndicesZcoordSpinBox->setObjectName(objectNamePrefix + "VolumeAxialCoordinate"); macroManager->addMacroSupportToObject(m_volumeIndicesZcoordSpinBox, "Set axial volume slice coordinate"); const AString idToolTipText = ("When selected: If there is an identification operation " "in ths tab or any other tab with the same yoking status " "(not Off), the volume slices will move to the location " "of the identified brainordinate."); m_volumeIdentificationUpdatesSlicesAction = WuQtUtilities::createAction("", WuQtUtilities::createWordWrappedToolTipText(idToolTipText), this, this, SLOT(volumeIdentificationToggled(bool))); m_volumeIdentificationUpdatesSlicesAction->setCheckable(true); QIcon volumeCrossHairIcon; const bool volumeCrossHairIconValid = WuQtUtilities::loadIcon(":/ToolBar/volume-crosshair-pointer.png", volumeCrossHairIcon); QToolButton* volumeIDToolButton = new QToolButton; if (volumeCrossHairIconValid) { m_volumeIdentificationUpdatesSlicesAction->setIcon(volumeCrossHairIcon); m_volumeIdentificationUpdatesSlicesAction->setIcon(createVolumeIdentificationUpdatesSlicesIcon(volumeIDToolButton)); } else { m_volumeIdentificationUpdatesSlicesAction->setText("ID"); } volumeIDToolButton->setDefaultAction(m_volumeIdentificationUpdatesSlicesAction); WuQtUtilities::setToolButtonStyleForQt5Mac(volumeIDToolButton); m_volumeIdentificationUpdatesSlicesAction->setObjectName(objectNamePrefix + "MoveSliceToID"); macroManager->addMacroSupportToObject(m_volumeIdentificationUpdatesSlicesAction, "Enable move volume slice to ID location"); m_volumeSliceProjectionTypeEnumComboBox = new EnumComboBoxTemplate(this); m_volumeSliceProjectionTypeEnumComboBox->setup(); m_volumeSliceProjectionTypeEnumComboBox->getComboBox()->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); QObject::connect(m_volumeSliceProjectionTypeEnumComboBox, SIGNAL(itemActivated()), this, SLOT(volumeSliceProjectionTypeEnumComboBoxItemActivated())); WuQtUtilities::setToolTipAndStatusTip(m_volumeSliceProjectionTypeEnumComboBox->getWidget(), "Chooses viewing orientation (oblique or orthogonal)"); m_volumeSliceProjectionTypeEnumComboBox->getComboBox()->setObjectName(objectNamePrefix + "Orthogonal/Oblique"); macroManager->addMacroSupportToObject(m_volumeSliceProjectionTypeEnumComboBox->getComboBox(), "Select volume slice projection type"); m_obliqueMaskingAction = new QAction("M", this); m_obliqueMaskingAction->setToolTip(VolumeSliceInterpolationEdgeEffectsMaskingEnum::getToolTip()); m_obliqueMaskingAction->setCheckable(true); QObject::connect(m_obliqueMaskingAction, &QAction::triggered, this, &BrainBrowserWindowToolBarSliceSelection::obliqueMaskingActionTriggered); m_obliqueMaskingAction->setObjectName(objectNamePrefix + "ObliqueMasking"); QToolButton* obliqueMaskingToolButton = new QToolButton(); obliqueMaskingToolButton->setDefaultAction(m_obliqueMaskingAction); WuQtUtilities::setToolButtonStyleForQt5Mac(obliqueMaskingToolButton); QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 0, 0); gridLayout->addWidget(m_volumeIndicesParasagittalCheckBox, 0, 0); gridLayout->addWidget(parasagittalLabel, 0, 1); gridLayout->addWidget(m_volumeIndicesCoronalCheckBox, 1, 0); gridLayout->addWidget(coronalLabel, 1, 1); gridLayout->addWidget(m_volumeIndicesAxialCheckBox, 2, 0); gridLayout->addWidget(axialLabel, 2, 1); gridLayout->addWidget(m_volumeIndicesParasagittalSpinBox, 0, 2); gridLayout->addWidget(m_volumeIndicesCoronalSpinBox, 1, 2); gridLayout->addWidget(m_volumeIndicesAxialSpinBox, 2, 2); gridLayout->addWidget(m_volumeIndicesXcoordSpinBox, 0, 3); gridLayout->addWidget(m_volumeIndicesYcoordSpinBox, 1, 3); gridLayout->addWidget(m_volumeIndicesZcoordSpinBox, 2, 3); gridLayout->addWidget(volumeIDToolButton, 3, 0, 1, 2, Qt::AlignLeft); gridLayout->addWidget(m_volumeSliceProjectionTypeEnumComboBox->getWidget(), 3, 2, 1, 2, Qt::AlignCenter); gridLayout->addWidget(obliqueMaskingToolButton, 3, 4); gridLayout->addWidget(volumeIndicesOriginToolButton, 0, 4, 3, 1); m_volumeIndicesWidgetGroup = new WuQWidgetObjectGroup(this); m_volumeIndicesWidgetGroup->add(volumeIndicesOriginToolButtonAction); m_volumeIndicesWidgetGroup->add(m_volumeIndicesParasagittalCheckBox); m_volumeIndicesWidgetGroup->add(m_volumeIndicesParasagittalSpinBox); m_volumeIndicesWidgetGroup->add(m_volumeIndicesCoronalCheckBox); m_volumeIndicesWidgetGroup->add(m_volumeIndicesCoronalSpinBox); m_volumeIndicesWidgetGroup->add(m_volumeIndicesAxialCheckBox); m_volumeIndicesWidgetGroup->add(m_volumeIndicesAxialSpinBox); m_volumeIndicesWidgetGroup->add(m_volumeIndicesXcoordSpinBox); m_volumeIndicesWidgetGroup->add(m_volumeIndicesYcoordSpinBox); m_volumeIndicesWidgetGroup->add(m_volumeIndicesZcoordSpinBox); m_volumeIndicesWidgetGroup->add(m_volumeSliceProjectionTypeEnumComboBox->getWidget()); m_volumeIndicesWidgetGroup->add(m_volumeIdentificationUpdatesSlicesAction); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_UPDATE_VOLUME_SLICE_INDICES_COORDS_TOOLBAR); } /** * Destructor. */ BrainBrowserWindowToolBarSliceSelection::~BrainBrowserWindowToolBarSliceSelection() { EventManager::get()->removeAllEventsFromListener(this); } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void BrainBrowserWindowToolBarSliceSelection::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_UPDATE_VOLUME_SLICE_INDICES_COORDS_TOOLBAR) { m_volumeIndicesWidgetGroup->blockAllSignals(true); this->updateSliceIndicesAndCoordinatesRanges(); m_volumeIndicesWidgetGroup->blockAllSignals(false); event->setEventProcessed(); } else { BrainBrowserWindowToolBarSliceSelection::receiveEvent(event); } } /** * Update the surface montage options widget. * * @param browserTabContent * The active model display controller (may be NULL). */ void BrainBrowserWindowToolBarSliceSelection::updateContent(BrowserTabContent* browserTabContent) { m_volumeIndicesWidgetGroup->blockAllSignals(true); const int32_t tabIndex = browserTabContent->getTabNumber(); VolumeMappableInterface* vf = NULL; ModelVolume* volumeModel = browserTabContent->getDisplayedVolumeModel(); if (volumeModel != NULL) { if (m_parentToolBar->getDisplayedModel() == volumeModel) { vf = volumeModel->getUnderlayVolumeFile(tabIndex); m_volumeIndicesAxialCheckBox->setVisible(false); m_volumeIndicesCoronalCheckBox->setVisible(false); m_volumeIndicesParasagittalCheckBox->setVisible(false); } } ModelWholeBrain* wholeBrainModel = browserTabContent->getDisplayedWholeBrainModel(); if (wholeBrainModel != NULL) { if (m_parentToolBar->getDisplayedModel() == wholeBrainModel) { vf = wholeBrainModel->getUnderlayVolumeFile(tabIndex); m_volumeIndicesAxialCheckBox->setVisible(true); m_volumeIndicesCoronalCheckBox->setVisible(true); m_volumeIndicesParasagittalCheckBox->setVisible(true); } } if (vf != NULL) { /* * Test selected file to see if it is an oblique volume file (not a CIFTI file) */ bool obliqueVolumeFlag = false; if ( ! vf->getVolumeSpace().isPlumb()) { obliqueVolumeFlag = true; } /* * Update slice projection type for allowed projection types */ std::vector validSliceProjections; validSliceProjections.push_back(VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE); if ( ! obliqueVolumeFlag) { validSliceProjections.push_back(VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL); } m_volumeSliceProjectionTypeEnumComboBox->setupWithItems(validSliceProjections); /* * If volume is oblique, change its projection type to oblique */ switch (browserTabContent->getSliceProjectionType()) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: if (obliqueVolumeFlag) { browserTabContent->setSliceProjectionType(VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE); } break; } m_volumeIndicesAxialCheckBox->setChecked(browserTabContent->isSliceAxialEnabled()); m_volumeIndicesCoronalCheckBox->setChecked(browserTabContent->isSliceCoronalEnabled()); m_volumeIndicesParasagittalCheckBox->setChecked(browserTabContent->isSliceParasagittalEnabled()); } updateObliqueMaskingButton(); m_volumeSliceProjectionTypeEnumComboBox->setSelectedItem(browserTabContent->getSliceProjectionType()); m_volumeIdentificationUpdatesSlicesAction->setChecked(browserTabContent->isIdentificationUpdatesVolumeSlices()); this->updateSliceIndicesAndCoordinatesRanges(); m_volumeIndicesWidgetGroup->blockAllSignals(false); } /* * Set the values/minimums/maximums for volume slice indices and coordinate spin controls. */ void BrainBrowserWindowToolBarSliceSelection::updateSliceIndicesAndCoordinatesRanges() { const bool blockedStatus = m_volumeIndicesWidgetGroup->signalsBlocked(); m_volumeIndicesWidgetGroup->blockAllSignals(true); BrowserTabContent* btc = this->getTabContentFromSelectedTab(); const int32_t tabIndex = btc->getTabNumber(); VolumeMappableInterface* vf = NULL; ModelVolume* volumeModel = btc->getDisplayedVolumeModel(); if (volumeModel != NULL) { vf = volumeModel->getUnderlayVolumeFile(tabIndex); } ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); if (wholeBrainModel != NULL) { vf = wholeBrainModel->getUnderlayVolumeFile(tabIndex); } if (vf != NULL) { m_volumeIndicesAxialSpinBox->setEnabled(true); m_volumeIndicesCoronalSpinBox->setEnabled(true); m_volumeIndicesParasagittalSpinBox->setEnabled(true); std::vector dimensions; vf->getDimensions(dimensions); /* * Setup minimum and maximum slices for each dimension. * Range is unlimited when Yoked. */ int minAxialDim = 0; int minCoronalDim = 0; int minParasagittalDim = 0; int maxAxialDim = (dimensions[2] > 0) ? (dimensions[2] - 1) : 0; int maxCoronalDim = (dimensions[1] > 0) ? (dimensions[1] - 1) : 0; int maxParasagittalDim = (dimensions[0] > 0) ? (dimensions[0] - 1) : 0; /* * BUG NOTE: * On Linux, if the user hold down an arrow key in a spin box * and the time to process the signal is "slow", qt will emit * a second signal (QTBUG-14259). In addition, calling any of * the setMinimum(), setMaximum(), or setRange() methods seems * to also cause emission of a signal. The result when the * user releases the arrow key, there are many backlogged signals * and it may take a while for them to process and the user * sees the slices scrolling for a while after the arrow key * is released. * * So, do not update range min/max unless the new range * is different than the range in the spin box. */ if (m_volumeIndicesAxialSpinBox->minimum() != minAxialDim) { m_volumeIndicesAxialSpinBox->setMinimum(minAxialDim); } if (m_volumeIndicesAxialSpinBox->maximum() != maxAxialDim) { m_volumeIndicesAxialSpinBox->setMaximum(maxAxialDim); } if (m_volumeIndicesCoronalSpinBox->minimum() != minCoronalDim) { m_volumeIndicesCoronalSpinBox->setMinimum(minCoronalDim); } if (m_volumeIndicesCoronalSpinBox->maximum() != maxCoronalDim) { m_volumeIndicesCoronalSpinBox->setMaximum(maxCoronalDim); } if (m_volumeIndicesParasagittalSpinBox->minimum() != minParasagittalDim) { m_volumeIndicesParasagittalSpinBox->setMinimum(minParasagittalDim); } if (m_volumeIndicesParasagittalSpinBox->maximum() != maxParasagittalDim) { m_volumeIndicesParasagittalSpinBox->setMaximum(maxParasagittalDim); } /* * Setup minimum and maximum coordinates for each dimension. * Range is unlimited when Yoked. */ int64_t slicesZero[3] = { 0, 0, 0 }; float sliceZeroCoords[3]; vf->indexToSpace(slicesZero, sliceZeroCoords); int64_t slicesMax[3] = { maxParasagittalDim, maxCoronalDim, maxAxialDim }; float sliceMaxCoords[3]; vf->indexToSpace(slicesMax, sliceMaxCoords); const double minX = std::min(sliceZeroCoords[0], sliceMaxCoords[0]); const double maxX = std::max(sliceZeroCoords[0], sliceMaxCoords[0]); const double minY = std::min(sliceZeroCoords[1], sliceMaxCoords[1]); const double maxY = std::max(sliceZeroCoords[1], sliceMaxCoords[1]); const double minZ = std::min(sliceZeroCoords[2], sliceMaxCoords[2]); const double maxZ = std::max(sliceZeroCoords[2], sliceMaxCoords[2]); /* * See BUG NOTE above. */ if (m_volumeIndicesXcoordSpinBox->minimum() != minX) { m_volumeIndicesXcoordSpinBox->setMinimum(minX); } if (m_volumeIndicesXcoordSpinBox->maximum() != maxX) { m_volumeIndicesXcoordSpinBox->setMaximum(maxX); } if (m_volumeIndicesYcoordSpinBox->minimum() != minY) { m_volumeIndicesYcoordSpinBox->setMinimum(minY); } if (m_volumeIndicesYcoordSpinBox->maximum() != maxY) { m_volumeIndicesYcoordSpinBox->setMaximum(maxY); } if (m_volumeIndicesZcoordSpinBox->minimum() != minZ) { m_volumeIndicesZcoordSpinBox->setMinimum(minZ); } if (m_volumeIndicesZcoordSpinBox->maximum() != maxZ) { m_volumeIndicesZcoordSpinBox->setMaximum(maxZ); } int64_t slicesOne[3] = { 1, 1, 1 }; float slicesOneCoords[3]; vf->indexToSpace(slicesOne, slicesOneCoords); const float dx = std::fabs(slicesOneCoords[0] - sliceZeroCoords[0]); const float dy = std::fabs(slicesOneCoords[1] - sliceZeroCoords[1]); const float dz = std::fabs(slicesOneCoords[2] - sliceZeroCoords[2]); m_volumeIndicesXcoordSpinBox->setSingleStep(dx); m_volumeIndicesYcoordSpinBox->setSingleStep(dy); m_volumeIndicesZcoordSpinBox->setSingleStep(dz); m_volumeIndicesAxialSpinBox->setValue(btc->getSliceIndexAxial(vf)); m_volumeIndicesCoronalSpinBox->setValue(btc->getSliceIndexCoronal(vf)); m_volumeIndicesParasagittalSpinBox->setValue(btc->getSliceIndexParasagittal(vf)); int64_t slices[3] = { btc->getSliceIndexParasagittal(vf), btc->getSliceIndexCoronal(vf), btc->getSliceIndexAxial(vf) }; float sliceCoords[3] = { 0.0, 0.0, 0.0 }; if (vf != NULL) { vf->indexToSpace(slices, sliceCoords); } m_volumeIndicesXcoordSpinBox->setValue(btc->getSliceCoordinateParasagittal()); m_volumeIndicesYcoordSpinBox->setValue(btc->getSliceCoordinateCoronal()); m_volumeIndicesZcoordSpinBox->setValue(btc->getSliceCoordinateAxial()); } m_volumeIndicesWidgetGroup->blockAllSignals(blockedStatus); } /** * Called when volume indices ORIGIN tool button is pressed. */ void BrainBrowserWindowToolBarSliceSelection::volumeIndicesOriginActionTriggered() { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->setSlicesToOrigin(); updateContent(btc); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when volume indices parasagittal check box is toggled. */ void BrainBrowserWindowToolBarSliceSelection::volumeIndicesParasagittalCheckBoxStateChanged(int /*state*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->setSliceParasagittalEnabled(m_volumeIndicesParasagittalCheckBox->isChecked()); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when volume indices coronal check box is toggled. */ void BrainBrowserWindowToolBarSliceSelection::volumeIndicesCoronalCheckBoxStateChanged(int /*state*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->setSliceCoronalEnabled(m_volumeIndicesCoronalCheckBox->isChecked()); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when volume indices axial check box is toggled. */ void BrainBrowserWindowToolBarSliceSelection::volumeIndicesAxialCheckBoxStateChanged(int /*state*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->setSliceAxialEnabled(m_volumeIndicesAxialCheckBox->isChecked()); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when volume indices parasagittal spin box value is changed. * * @param sliceIndex * New index of slice. */ void BrainBrowserWindowToolBarSliceSelection::volumeIndicesParasagittalSpinBoxValueChanged(int sliceIndex) { this->readVolumeSliceIndicesAndUpdateSliceCoordinates(VolumeSliceViewPlaneEnum::PARASAGITTAL, sliceIndex); } /** * Called when volume indices coronal spin box value is changed. * * @param sliceIndex * New index of slice. */ void BrainBrowserWindowToolBarSliceSelection::volumeIndicesCoronalSpinBoxValueChanged(int sliceIndex) { this->readVolumeSliceIndicesAndUpdateSliceCoordinates(VolumeSliceViewPlaneEnum::CORONAL, sliceIndex); } /** * Called when volume indices axial spin box value is changed. * * @param sliceIndex * New index of slice. */ void BrainBrowserWindowToolBarSliceSelection::volumeIndicesAxialSpinBoxValueChanged(int sliceIndex) { this->readVolumeSliceIndicesAndUpdateSliceCoordinates(VolumeSliceViewPlaneEnum::AXIAL, sliceIndex); } /** * Called when X stereotaxic coordinate is changed. * @param d * New value. */ void BrainBrowserWindowToolBarSliceSelection::volumeIndicesXcoordSpinBoxValueChanged(double /*d*/) { this->readVolumeSliceCoordinatesAndUpdateSliceIndices(); } /** * Called when Y stereotaxic coordinate is changed. * @param d * New value. */ void BrainBrowserWindowToolBarSliceSelection::volumeIndicesYcoordSpinBoxValueChanged(double /*d*/) { this->readVolumeSliceCoordinatesAndUpdateSliceIndices(); } /** * Called when Z stereotaxic coordinate is changed. * @param d * New value. */ void BrainBrowserWindowToolBarSliceSelection::volumeIndicesZcoordSpinBoxValueChanged(double /*d*/) { this->readVolumeSliceCoordinatesAndUpdateSliceIndices(); } /** * Read the slice indices and update the slice coordinates. * * @param viewPlane * View plane whose slice index was changed * @param sliceIndex * New slice index. */ void BrainBrowserWindowToolBarSliceSelection::readVolumeSliceIndicesAndUpdateSliceCoordinates(const VolumeSliceViewPlaneEnum::Enum viewPlane, const int64_t sliceIndex) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); const int32_t tabIndex = btc->getTabNumber(); VolumeMappableInterface* underlayVolumeFile = NULL; ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); if (wholeBrainModel != NULL) { if (m_parentToolBar->getDisplayedModel() == wholeBrainModel) { underlayVolumeFile = wholeBrainModel->getUnderlayVolumeFile(tabIndex); } } ModelVolume* volumeModel = btc->getDisplayedVolumeModel(); if (volumeModel != NULL) { if (m_parentToolBar->getDisplayedModel() == volumeModel) { underlayVolumeFile = volumeModel->getUnderlayVolumeFile(tabIndex); } } if (underlayVolumeFile != NULL) { const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType = m_volumeSliceProjectionTypeEnumComboBox->getSelectedItem(); switch (sliceProjectionType) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: { switch (viewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: btc->setSliceIndexAxial(underlayVolumeFile, sliceIndex); break; case VolumeSliceViewPlaneEnum::CORONAL: btc->setSliceIndexCoronal(underlayVolumeFile, sliceIndex); break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: btc->setSliceIndexParasagittal(underlayVolumeFile, sliceIndex); break; } } break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: switch (viewPlane) { case VolumeSliceViewPlaneEnum::ALL: CaretAssert(0); break; case VolumeSliceViewPlaneEnum::AXIAL: btc->setSliceIndexAxial(underlayVolumeFile, sliceIndex); break; case VolumeSliceViewPlaneEnum::CORONAL: btc->setSliceIndexCoronal(underlayVolumeFile, sliceIndex); break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: btc->setSliceIndexParasagittal(underlayVolumeFile, sliceIndex); break; } break; } } this->updateSliceIndicesAndCoordinatesRanges(); this->updateGraphicsWindowAndYokedWindows(); } /** * Read the slice coordinates and convert to slices indices and then * update the displayed slices. */ void BrainBrowserWindowToolBarSliceSelection::readVolumeSliceCoordinatesAndUpdateSliceIndices() { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); const int32_t tabIndex = btc->getTabNumber(); VolumeMappableInterface* underlayVolumeFile = NULL; ModelWholeBrain* wholeBrainModel = btc->getDisplayedWholeBrainModel(); if (wholeBrainModel != NULL) { if (m_parentToolBar->getDisplayedModel() == wholeBrainModel) { underlayVolumeFile = wholeBrainModel->getUnderlayVolumeFile(tabIndex); } } ModelVolume* volumeModel = btc->getDisplayedVolumeModel(); if (volumeModel != NULL) { if (m_parentToolBar->getDisplayedModel() == volumeModel) { underlayVolumeFile = volumeModel->getUnderlayVolumeFile(tabIndex); } } if (underlayVolumeFile != NULL) { float sliceCoords[3] = { (float)m_volumeIndicesXcoordSpinBox->value(), (float)m_volumeIndicesYcoordSpinBox->value(), (float)m_volumeIndicesZcoordSpinBox->value() }; btc->selectSlicesAtCoordinate(sliceCoords); } this->updateSliceIndicesAndCoordinatesRanges(); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when projection type is changed. */ void BrainBrowserWindowToolBarSliceSelection::volumeSliceProjectionTypeEnumComboBoxItemActivated() { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType = m_volumeSliceProjectionTypeEnumComboBox->getSelectedItem(); btc->setSliceProjectionType(sliceProjectionType); this->updateGraphicsWindowAndYokedWindows(); updateObliqueMaskingButton(); EventManager::get()->sendEvent(EventUpdateVolumeEditingToolBar().getPointer()); } /** * Called when volume identification action toggled. * * @param value * New value. */ void BrainBrowserWindowToolBarSliceSelection::volumeIdentificationToggled(bool value) { BrowserTabContent* browserTabContent = this->getTabContentFromSelectedTab(); if (browserTabContent == NULL) { return; } browserTabContent->setIdentificationUpdatesVolumeSlices(value); } /** * Called when the oblique masking action is triggered. */ void BrainBrowserWindowToolBarSliceSelection::obliqueMaskingActionTriggered(bool) { static bool addMacroSupportStaticFlag(true); BrowserTabContent* browserTabContent = this->getTabContentFromSelectedTab(); if (browserTabContent == NULL) { return; } std::vector allMaskEnums; VolumeSliceInterpolationEdgeEffectsMaskingEnum::getAllEnums(allMaskEnums); QMenu obliqueMaskingMenu("Oblique Sampling"); QActionGroup* maskActionGroup = new QActionGroup(this); maskActionGroup->setExclusive(true); QAction* selectedAction = NULL; for (auto maskEnum : allMaskEnums) { QAction* action = maskActionGroup->addAction(VolumeSliceInterpolationEdgeEffectsMaskingEnum::toGuiName(maskEnum)); action->setObjectName(m_obliqueMaskingAction->objectName() + ":" + VolumeSliceInterpolationEdgeEffectsMaskingEnum::toName(maskEnum)); action->setCheckable(true); action->setData(VolumeSliceInterpolationEdgeEffectsMaskingEnum::toIntegerCode(maskEnum)); if (maskEnum == browserTabContent->getVolumeSliceInterpolationEdgeEffectsMaskingType()) { selectedAction = action; } if (addMacroSupportStaticFlag) { addMacroSupportStaticFlag = false; WuQMacroManager::instance()->addMacroSupportToObject(action, "Select " + action->text() + " oblique sampling"); } obliqueMaskingMenu.addAction(action); } if (selectedAction != NULL) { selectedAction->setChecked(true); } selectedAction = obliqueMaskingMenu.exec(QCursor::pos()); if (selectedAction != NULL) { const int32_t intValue = selectedAction->data().toInt(); bool validFlag = false; VolumeSliceInterpolationEdgeEffectsMaskingEnum::Enum maskType = VolumeSliceInterpolationEdgeEffectsMaskingEnum::fromIntegerCode(intValue, &validFlag); CaretAssert(validFlag); browserTabContent->setVolumeSliceInterpolationEdgeEffectsMaskingType(maskType); this->updateGraphicsWindowAndYokedWindows(); EventManager::get()->sendEvent(EventUpdateVolumeEditingToolBar().getPointer()); } updateObliqueMaskingButton(); } /** * Update the oblique masking button so that it enabled only * when oblique slice drawing is selected and it is "checked" * when a masking is applied. */ void BrainBrowserWindowToolBarSliceSelection::updateObliqueMaskingButton() { BrowserTabContent* browserTabContent = this->getTabContentFromSelectedTab(); if (browserTabContent == NULL) { return; } QSignalBlocker obliqueBlocker(m_obliqueMaskingAction); switch (browserTabContent->getVolumeSliceInterpolationEdgeEffectsMaskingType()) { case VolumeSliceInterpolationEdgeEffectsMaskingEnum::OFF: m_obliqueMaskingAction->setChecked(false); break; case VolumeSliceInterpolationEdgeEffectsMaskingEnum::LOOSE: case VolumeSliceInterpolationEdgeEffectsMaskingEnum::TIGHT: m_obliqueMaskingAction->setChecked(true); break; } switch (browserTabContent->getSliceProjectionType()) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: m_obliqueMaskingAction->setEnabled(true); break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: m_obliqueMaskingAction->setEnabled(false); break; } } /** * Create a pixmap for the volume identification updates slice selection button. * * @param widget * To color the pixmap with backround and foreground, * the palette from the given widget is used. * @return * The pixmap. */ QPixmap BrainBrowserWindowToolBarSliceSelection::createVolumeIdentificationUpdatesSlicesIcon(const QWidget* widget) { CaretAssert(widget); const int pixmapSize = 24; const int halfSize = pixmapSize / 2; QPixmap pixmap(pixmapSize, pixmapSize); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginCenter(widget, pixmap, static_cast(WuQtUtilities::PixMapCreationOptions::TransparentBackground)); const int startXY = 3; const int endXY = 8; QPen pen(painter->pen()); pen.setWidth(2); painter->setPen(pen); const int tx(-3); const int ty(3); painter->translate(tx, ty); painter->drawLine(-startXY, 0, -endXY, 0); painter->drawLine( startXY, 0, endXY, 0); painter->drawLine(0, -startXY, 0, -endXY); painter->drawLine(0, startXY, 0, endXY); painter->translate(-tx, -ty); const int tipX(3); const int tipY(-3); const int tailX(halfSize); const int tailY(-halfSize); painter->drawLine(tipX, tipY, tailX, tailY); const int headLength(3); painter->drawLine(tipX, tipY, tipX + headLength, tipY); painter->drawLine(tipX, tipY, tipX, tipY - headLength); return pixmap; } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarSliceSelection.h000066400000000000000000000104711360521144700275270ustar00rootroot00000000000000#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_SLICE_SELECTION_H__ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_SLICE_SELECTION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainBrowserWindowToolBarComponent.h" #include "VolumeSliceViewPlaneEnum.h" class QAction; class QCheckBox; class QDoubleSpinBox; class QSpinBox; class WuQWidgetObjectGroup; namespace caret { class EnumComboBoxTemplate; class BrainBrowserWindowToolBarSliceSelection : public BrainBrowserWindowToolBarComponent { Q_OBJECT public: BrainBrowserWindowToolBarSliceSelection(BrainBrowserWindowToolBar* parentToolBar, const QString parentObjectName); virtual ~BrainBrowserWindowToolBarSliceSelection(); virtual void updateContent(BrowserTabContent* browserTabContent); virtual void receiveEvent(Event* event) override; // ADD_NEW_METHODS_HERE private slots: void volumeIndicesOriginActionTriggered(); void volumeIndicesParasagittalCheckBoxStateChanged(int state); void volumeIndicesCoronalCheckBoxStateChanged(int state); void volumeIndicesAxialCheckBoxStateChanged(int state); void volumeIndicesParasagittalSpinBoxValueChanged(int sliceIndex); void volumeIndicesCoronalSpinBoxValueChanged(int sliceIndex); void volumeIndicesAxialSpinBoxValueChanged(int sliceIndex); void volumeIndicesXcoordSpinBoxValueChanged(double d); void volumeIndicesYcoordSpinBoxValueChanged(double d); void volumeIndicesZcoordSpinBoxValueChanged(double d); void volumeSliceProjectionTypeEnumComboBoxItemActivated(); void volumeIdentificationToggled(bool value); void obliqueMaskingActionTriggered(bool); private: BrainBrowserWindowToolBarSliceSelection(const BrainBrowserWindowToolBarSliceSelection&); BrainBrowserWindowToolBarSliceSelection& operator=(const BrainBrowserWindowToolBarSliceSelection&); void readVolumeSliceCoordinatesAndUpdateSliceIndices(); void readVolumeSliceIndicesAndUpdateSliceCoordinates(const VolumeSliceViewPlaneEnum::Enum viewPlane, const int64_t sliceIndex); void updateSliceIndicesAndCoordinatesRanges(); void updateObliqueMaskingButton(); QPixmap createVolumeIdentificationUpdatesSlicesIcon(const QWidget* widget); BrainBrowserWindowToolBar* m_parentToolBar; WuQWidgetObjectGroup* m_volumeIndicesWidgetGroup; QAction* m_volumeIdentificationUpdatesSlicesAction; QCheckBox* m_volumeIndicesParasagittalCheckBox; QCheckBox* m_volumeIndicesCoronalCheckBox; QCheckBox* m_volumeIndicesAxialCheckBox; QSpinBox* m_volumeIndicesParasagittalSpinBox; QSpinBox* m_volumeIndicesCoronalSpinBox; QSpinBox* m_volumeIndicesAxialSpinBox; QDoubleSpinBox* m_volumeIndicesXcoordSpinBox; QDoubleSpinBox* m_volumeIndicesYcoordSpinBox; QDoubleSpinBox* m_volumeIndicesZcoordSpinBox; QAction* m_obliqueMaskingAction; EnumComboBoxTemplate* m_volumeSliceProjectionTypeEnumComboBox; // ADD_NEW_MEMBERS_HERE }; #ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_SLICE_SELECTION_DECLARE__ // #endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_SLICE_SELECTION_DECLARE__ } // namespace #endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_SLICE_SELECTION_H__ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarSurfaceMontage.cxx000066400000000000000000001271721360521144700301070ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_SURFACE_MONTAGE_DECLARE__ #include "BrainBrowserWindowToolBarSurfaceMontage.h" #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_SURFACE_MONTAGE_DECLARE__ #include "BrainBrowserWindowToolBar.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "EnumComboBoxTemplate.h" #include "EventManager.h" #include "EventSurfaceColoringInvalidate.h" #include "ModelSurfaceMontage.h" #include "SurfaceMontageConfigurationCerebellar.h" #include "SurfaceMontageConfigurationCerebral.h" #include "SurfaceMontageConfigurationFlatMaps.h" #include "SurfaceMontageLayoutOrientationEnum.h" #include "SurfaceSelectionModel.h" #include "SurfaceSelectionViewController.h" #include "WuQMacroManager.h" #include "WuQtUtilities.h" #include "WuQWidgetObjectGroup.h" using namespace caret; /** * \class caret::BrainBrowserWindowToolBarSurfaceMontage * \brief Surface Montage Component of Brain Browser Window ToolBar * \ingroup GuiQt */ /** * Constructor. * * @param parentToolBar * parent toolbar. * @param objectNamePrefix * Prefix name for naming objects */ BrainBrowserWindowToolBarSurfaceMontage::BrainBrowserWindowToolBarSurfaceMontage(BrainBrowserWindowToolBar* parentToolBar, const QString& objectNamePrefix) : BrainBrowserWindowToolBarComponent(parentToolBar), m_parentToolBar(parentToolBar) { m_surfaceMontageConfigurationTypeEnumComboBox = new EnumComboBoxTemplate(this); m_surfaceMontageConfigurationTypeEnumComboBox->setup(); QObject::connect(m_surfaceMontageConfigurationTypeEnumComboBox, SIGNAL(itemActivated()), this, SLOT(surfaceMontageConfigurationTypeEnumComboBoxItemActivated())); addToWidgetGroup(m_surfaceMontageConfigurationTypeEnumComboBox->getWidget()); WuQtUtilities::setToolTipAndStatusTip(m_surfaceMontageConfigurationTypeEnumComboBox->getWidget(), ("Selects Surface Montage Configuration:\n" " Cerebellar Cortex\n" " Cerebral Cortex\n" " Flat Maps")); m_surfaceMontageConfigurationTypeEnumComboBox->getComboBox()->setObjectName(objectNamePrefix + ":SurfaceMontageConfiguration"); WuQMacroManager::instance()->addMacroSupportToObject(m_surfaceMontageConfigurationTypeEnumComboBox->getComboBox(), "Select surface montage configuration"); m_surfaceMontageLayoutOrientationEnumComboBox = new EnumComboBoxTemplate(this); m_surfaceMontageLayoutOrientationEnumComboBox->setup(); QObject::connect(m_surfaceMontageLayoutOrientationEnumComboBox, SIGNAL(itemActivated()), this, SLOT(surfaceMontageLayoutOrientationEnumComboBoxItemActivated())); addToWidgetGroup(m_surfaceMontageLayoutOrientationEnumComboBox->getWidget()); WuQtUtilities::setToolTipAndStatusTip(m_surfaceMontageLayoutOrientationEnumComboBox->getWidget(), ("Selects Surface Layout:\n" " Landscape (Layout left-to-right)\n" " Portrait (Layout top-to-bottom)")); m_surfaceMontageLayoutOrientationEnumComboBox->getComboBox()->setObjectName(objectNamePrefix + ":SurfaceMontageOrientation"); WuQMacroManager::instance()->addMacroSupportToObject(m_surfaceMontageLayoutOrientationEnumComboBox->getComboBox(), "Select surface montage layout"); m_cerebellarComponent = new SurfaceMontageCerebellarComponent(this, objectNamePrefix); m_cerebralComponent = new SurfaceMontageCerebralComponent(this, objectNamePrefix); m_flatMapsComponent = new SurfaceMontageFlatMapsComponent(this, objectNamePrefix); QHBoxLayout* configOrientationLayout = new QHBoxLayout(); WuQtUtilities::setLayoutSpacingAndMargins(configOrientationLayout, 2, 0); configOrientationLayout->addStretch(); configOrientationLayout->addWidget(m_surfaceMontageConfigurationTypeEnumComboBox->getWidget()); configOrientationLayout->addStretch(); configOrientationLayout->addSpacing(10); configOrientationLayout->addWidget(m_surfaceMontageLayoutOrientationEnumComboBox->getWidget()); configOrientationLayout->addStretch(); m_stackedWidget = new QStackedWidget(); m_stackedWidget->addWidget(m_cerebellarComponent); m_stackedWidget->addWidget(m_cerebralComponent); m_stackedWidget->addWidget(m_flatMapsComponent); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 0); layout->addLayout(configOrientationLayout); layout->addWidget(WuQtUtilities::createHorizontalLineWidget()); layout->addWidget(m_stackedWidget); // EventManager::get()->addEventListener(this, EventTypeEnum::); } /** * Destructor. */ BrainBrowserWindowToolBarSurfaceMontage::~BrainBrowserWindowToolBarSurfaceMontage() { EventManager::get()->removeAllEventsFromListener(this); } /** * Called when the montage configuration is changed. */ void BrainBrowserWindowToolBarSurfaceMontage::surfaceMontageConfigurationTypeEnumComboBoxItemActivated() { m_parentToolBar->getTabContentFromSelectedTab(); BrowserTabContent* btc = m_parentToolBar->getTabContentFromSelectedTab(); const SurfaceMontageConfigurationTypeEnum::Enum configType = m_surfaceMontageConfigurationTypeEnumComboBox->getSelectedItem(); ModelSurfaceMontage* msm = btc->getDisplayedSurfaceMontageModel(); const int32_t tabIndex = btc->getTabNumber(); msm->setSelectedConfigurationType(tabIndex, configType); updateContent(btc); invalidateColoringAndUpdateGraphicsWindow(); m_parentToolBar->updateUserInterface(); } /** * Called when the layout orientation value is changed. */ void BrainBrowserWindowToolBarSurfaceMontage::surfaceMontageLayoutOrientationEnumComboBoxItemActivated() { m_parentToolBar->getTabContentFromSelectedTab(); BrowserTabContent* btc = m_parentToolBar->getTabContentFromSelectedTab(); ModelSurfaceMontage* msm = btc->getDisplayedSurfaceMontageModel(); const int32_t tabIndex = btc->getTabNumber(); SurfaceMontageConfigurationAbstract* selectedConfiguration = msm->getSelectedConfiguration(tabIndex); selectedConfiguration->setLayoutOrientation(m_surfaceMontageLayoutOrientationEnumComboBox->getSelectedItem()); invalidateColoringAndUpdateGraphicsWindow(); } /** * Update the surface montage options widget. * * @param browserTabContent * The active model display controller (may be NULL). */ void BrainBrowserWindowToolBarSurfaceMontage::updateContent(BrowserTabContent* browserTabContent) { ModelSurfaceMontage* msm = browserTabContent->getDisplayedSurfaceMontageModel(); if (msm == NULL) { return; } const int32_t tabIndex = browserTabContent->getTabNumber(); std::vector validConfigs; if (msm->getCerebellarConfiguration(tabIndex)->isValid()) { validConfigs.push_back(SurfaceMontageConfigurationTypeEnum::CEREBELLAR_CORTEX_CONFIGURATION); } if (msm->getCerebralConfiguration(tabIndex)->isValid()) { validConfigs.push_back(SurfaceMontageConfigurationTypeEnum::CEREBRAL_CORTEX_CONFIGURATION); } if (msm->getFlatMapsConfiguration(tabIndex)->isValid()) { validConfigs.push_back(SurfaceMontageConfigurationTypeEnum::FLAT_CONFIGURATION); } m_surfaceMontageConfigurationTypeEnumComboBox->setupWithItems(validConfigs); SurfaceMontageConfigurationAbstract* selectedConfiguration = msm->getSelectedConfiguration(tabIndex); m_surfaceMontageConfigurationTypeEnumComboBox->setSelectedItem(msm->getSelectedConfigurationType(tabIndex)); m_surfaceMontageLayoutOrientationEnumComboBox->setSelectedItem(selectedConfiguration->getLayoutOrientation()); switch (msm->getSelectedConfigurationType(tabIndex)) { case SurfaceMontageConfigurationTypeEnum::CEREBELLAR_CORTEX_CONFIGURATION: m_cerebellarComponent->updateContent(browserTabContent); m_stackedWidget->setCurrentWidget(m_cerebellarComponent); break; case SurfaceMontageConfigurationTypeEnum::CEREBRAL_CORTEX_CONFIGURATION: m_cerebralComponent->updateContent(browserTabContent); m_stackedWidget->setCurrentWidget(m_cerebralComponent); break; case SurfaceMontageConfigurationTypeEnum::FLAT_CONFIGURATION: m_flatMapsComponent->updateContent(browserTabContent); m_stackedWidget->setCurrentWidget(m_flatMapsComponent); break; } } /* ******************************************************************************************** */ /** * \class caret::SurfaceMontageCerebralComponent * \brief Cerebral Surface Montage Component of Brain Browser Window ToolBar * \ingroup GuiQt */ /** * Constructor. * * @param parentToolBar * parent toolbar. * @param objectNamePrefix * Prefix name for naming objects */ SurfaceMontageCerebralComponent::SurfaceMontageCerebralComponent(BrainBrowserWindowToolBarSurfaceMontage* parentToolBarMontage, const QString& parentObjectNamePrefix) : QWidget(parentToolBarMontage) { const QString objectNamePrefix(parentObjectNamePrefix + ":SurfaceMontage"); m_parentToolBarMontage = parentToolBarMontage; WuQMacroManager* macroManager = WuQMacroManager::instance(); m_leftCheckBox = new QCheckBox("Left"); QObject::connect(m_leftCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); m_leftCheckBox->setObjectName(objectNamePrefix + ":EnableLeft"); m_leftCheckBox->setToolTip("Enable Left Surfaces"); macroManager->addMacroSupportToObject(m_leftCheckBox, "Enable left surface in cerebral montage"); m_rightCheckBox = new QCheckBox("Right"); QObject::connect(m_rightCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); m_rightCheckBox->setObjectName(objectNamePrefix + ":EnableRight"); m_rightCheckBox->setToolTip("Enable Right Surface"); macroManager->addMacroSupportToObject(m_rightCheckBox, "Enable right surface in cerebral montage"); m_lateralCheckBox = new QCheckBox("Lateral"); QObject::connect(m_lateralCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); m_lateralCheckBox->setObjectName(objectNamePrefix + ":EnableLateralView"); m_lateralCheckBox->setToolTip("Enable Lateral View"); macroManager->addMacroSupportToObject(m_lateralCheckBox, "Enable lateral view in cerebral montage"); m_medialCheckBox = new QCheckBox("Medial"); QObject::connect(m_medialCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); m_medialCheckBox->setObjectName(objectNamePrefix + ":EnableMedialView"); m_medialCheckBox->setToolTip("Enable Medial View"); macroManager->addMacroSupportToObject(m_medialCheckBox, "Enable medial view in cerebral montage"); m_surfaceMontageFirstSurfaceCheckBox = new QCheckBox(" "); QObject::connect(m_surfaceMontageFirstSurfaceCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); m_surfaceMontageFirstSurfaceCheckBox->setObjectName(objectNamePrefix + ":EnableFirstRowSurfaces"); m_surfaceMontageFirstSurfaceCheckBox->setToolTip("Enable First Surfaces"); macroManager->addMacroSupportToObject(m_surfaceMontageFirstSurfaceCheckBox, "Enable first surface row in cerebral montage"); m_surfaceMontageSecondSurfaceCheckBox = new QCheckBox(" "); QObject::connect(m_surfaceMontageSecondSurfaceCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); m_surfaceMontageSecondSurfaceCheckBox->setObjectName(objectNamePrefix + ":EnableSecondRowSurfaces"); m_surfaceMontageSecondSurfaceCheckBox->setToolTip("Enable Second Surfaces"); macroManager->addMacroSupportToObject(m_surfaceMontageSecondSurfaceCheckBox, "Enable second row in cerebral montage"); m_leftSurfaceViewController = new SurfaceSelectionViewController(this, objectNamePrefix + ":SurfaceLeftTop", "cerebral montage left top"); QObject::connect(m_leftSurfaceViewController, SIGNAL(surfaceSelected(Surface*)), this, SLOT(leftSurfaceSelected(Surface*))); m_leftSecondSurfaceViewController = new SurfaceSelectionViewController(this, objectNamePrefix + ":SurfaceLeftBottom", "cerebral montage left bottom"); QObject::connect(m_leftSecondSurfaceViewController, SIGNAL(surfaceSelected(Surface*)), this, SLOT(leftSecondSurfaceSelected(Surface*))); m_rightSurfaceViewController = new SurfaceSelectionViewController(this, objectNamePrefix + ":SurfaceRightTop", "cerebral montage right top"); QObject::connect(m_rightSurfaceViewController, SIGNAL(surfaceSelected(Surface*)), this, SLOT(rightSurfaceSelected(Surface*))); m_rightSecondSurfaceViewController = new SurfaceSelectionViewController(this, objectNamePrefix + ":SurfaceRightBottom", "cerebral montage right bottom"); QObject::connect(m_rightSecondSurfaceViewController, SIGNAL(surfaceSelected(Surface*)), this, SLOT(rightSecondSurfaceSelected(Surface*))); QHBoxLayout* checkBoxLayout = new QHBoxLayout(); WuQtUtilities::setLayoutSpacingAndMargins(checkBoxLayout, 2, 0); checkBoxLayout->addWidget(m_leftCheckBox); checkBoxLayout->addSpacing(10); checkBoxLayout->addStretch(); checkBoxLayout->addWidget(m_lateralCheckBox); checkBoxLayout->addSpacing(10); checkBoxLayout->addStretch(); checkBoxLayout->addWidget(m_medialCheckBox); checkBoxLayout->addSpacing(10); checkBoxLayout->addStretch(); checkBoxLayout->addWidget(m_rightCheckBox); int32_t columnIndex = 0; const int32_t COLUMN_ONE_TWO = columnIndex++; const int32_t COLUMN_INDEX_LEFT = columnIndex++; const int32_t COLUMN_INDEX_RIGHT = columnIndex++; QGridLayout* layout = new QGridLayout(this); layout->setColumnStretch(0, 0); layout->setColumnStretch(1, 100); layout->setColumnStretch(2, 100); WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 0); int row = layout->rowCount(); layout->addWidget(m_surfaceMontageFirstSurfaceCheckBox, row, COLUMN_ONE_TWO); layout->addWidget(m_leftSurfaceViewController->getWidget(), row, COLUMN_INDEX_LEFT); layout->addWidget(m_rightSurfaceViewController->getWidget(), row, COLUMN_INDEX_RIGHT); row = layout->rowCount(); layout->addWidget(m_surfaceMontageSecondSurfaceCheckBox, row, COLUMN_ONE_TWO); layout->addWidget(m_leftSecondSurfaceViewController->getWidget(), row, COLUMN_INDEX_LEFT); layout->addWidget(m_rightSecondSurfaceViewController->getWidget(), row, COLUMN_INDEX_RIGHT); row = layout->rowCount(); layout->addLayout(checkBoxLayout, row, COLUMN_INDEX_LEFT, 1, 2); row = layout->rowCount(); m_widgetGroup = new WuQWidgetObjectGroup(this); m_widgetGroup->add(m_leftSurfaceViewController->getWidget()); m_widgetGroup->add(m_leftSecondSurfaceViewController->getWidget()); m_widgetGroup->add(m_rightSurfaceViewController->getWidget()); m_widgetGroup->add(m_rightSecondSurfaceViewController->getWidget()); m_widgetGroup->add(m_leftCheckBox); m_widgetGroup->add(m_rightCheckBox); m_widgetGroup->add(m_surfaceMontageFirstSurfaceCheckBox); m_widgetGroup->add(m_surfaceMontageSecondSurfaceCheckBox); m_widgetGroup->add(m_medialCheckBox); m_widgetGroup->add(m_lateralCheckBox); setFixedHeight(sizeHint().height()); } /** * Destructor. */ SurfaceMontageCerebralComponent::~SurfaceMontageCerebralComponent() { } /** * Update the cerebral montage options widget. * * @param browserTabContent * The active model display controller (may be NULL). */ void SurfaceMontageCerebralComponent::updateContent(BrowserTabContent* browserTabContent) { m_widgetGroup->blockAllSignals(true); const int32_t tabIndex = browserTabContent->getTabNumber(); ModelSurfaceMontage* msm = browserTabContent->getDisplayedSurfaceMontageModel(); SurfaceMontageConfigurationCerebral* smcc = msm->getCerebralConfiguration(tabIndex); m_leftCheckBox->setChecked(smcc->isLeftEnabled()); m_rightCheckBox->setChecked(smcc->isRightEnabled()); m_surfaceMontageFirstSurfaceCheckBox->setChecked(smcc->isFirstSurfaceEnabled()); m_surfaceMontageSecondSurfaceCheckBox->setChecked(smcc->isSecondSurfaceEnabled()); m_lateralCheckBox->setChecked(smcc->isLateralEnabled()); m_medialCheckBox->setChecked(smcc->isMedialEnabled()); m_leftSurfaceViewController->updateControl(smcc->getLeftFirstSurfaceSelectionModel()); m_leftSecondSurfaceViewController->updateControl(smcc->getLeftSecondSurfaceSelectionModel()); m_rightSurfaceViewController->updateControl(smcc->getRightFirstSurfaceSelectionModel()); m_rightSecondSurfaceViewController->updateControl(smcc->getRightSecondSurfaceSelectionModel()); m_widgetGroup->blockAllSignals(false); } /** * Called when montage left first surface is selected. * @param surface * Surface that was selected. */ void SurfaceMontageCerebralComponent::leftSurfaceSelected(Surface* surface) { if (surface != NULL) { BrowserTabContent* btc = m_parentToolBarMontage->getTabContentFromSelectedTab(); const int32_t tabIndex = btc->getTabNumber(); ModelSurfaceMontage* msm = btc->getDisplayedSurfaceMontageModel(); SurfaceMontageConfigurationCerebral* smcc = msm->getCerebralConfiguration(tabIndex); smcc->getLeftFirstSurfaceSelectionModel()->setSurface(surface); m_parentToolBarMontage->invalidateColoringAndUpdateGraphicsWindow(); } } /** * Called when montage left second surface is selected. * @param surface * Surface that was selected. */ void SurfaceMontageCerebralComponent::leftSecondSurfaceSelected(Surface* surface) { if (surface != NULL) { BrowserTabContent* btc = m_parentToolBarMontage->getTabContentFromSelectedTab(); const int32_t tabIndex = btc->getTabNumber(); ModelSurfaceMontage* msm = btc->getDisplayedSurfaceMontageModel(); SurfaceMontageConfigurationCerebral* smcc = msm->getCerebralConfiguration(tabIndex); smcc->getLeftSecondSurfaceSelectionModel()->setSurface(surface); m_parentToolBarMontage->invalidateColoringAndUpdateGraphicsWindow(); } } /** * Called when montage right surface is selected. * @param surface * Surface that was selected. */ void SurfaceMontageCerebralComponent::rightSurfaceSelected(Surface* surface) { if (surface != NULL) { BrowserTabContent* btc = m_parentToolBarMontage->getTabContentFromSelectedTab(); const int32_t tabIndex = btc->getTabNumber(); ModelSurfaceMontage* msm = btc->getDisplayedSurfaceMontageModel(); SurfaceMontageConfigurationCerebral* smcc = msm->getCerebralConfiguration(tabIndex); smcc->getRightFirstSurfaceSelectionModel()->setSurface(surface); m_parentToolBarMontage->invalidateColoringAndUpdateGraphicsWindow(); } } /** * Called when montage right second surface is selected. * @param surface * Surface that was selected. */ void SurfaceMontageCerebralComponent::rightSecondSurfaceSelected(Surface* surface) { if (surface != NULL) { BrowserTabContent* btc = m_parentToolBarMontage->getTabContentFromSelectedTab(); const int32_t tabIndex = btc->getTabNumber(); ModelSurfaceMontage* msm = btc->getDisplayedSurfaceMontageModel(); SurfaceMontageConfigurationCerebral* smcc = msm->getCerebralConfiguration(tabIndex); smcc->getRightSecondSurfaceSelectionModel()->setSurface(surface); m_parentToolBarMontage->invalidateColoringAndUpdateGraphicsWindow(); } } /** * Called when surface montage checkbox is toggled. * @param status * New status of check box. */ void SurfaceMontageCerebralComponent::checkBoxSelected(bool /*status*/) { BrowserTabContent* btc = m_parentToolBarMontage->getTabContentFromSelectedTab(); const int32_t tabIndex = btc->getTabNumber(); ModelSurfaceMontage* msm = btc->getDisplayedSurfaceMontageModel(); SurfaceMontageConfigurationCerebral* smcc = msm->getCerebralConfiguration(tabIndex); smcc->setLeftEnabled(m_leftCheckBox->isChecked()); smcc->setRightEnabled(m_rightCheckBox->isChecked()); smcc->setFirstSurfaceEnabled(m_surfaceMontageFirstSurfaceCheckBox->isChecked()); smcc->setSecondSurfaceEnabled(m_surfaceMontageSecondSurfaceCheckBox->isChecked()); smcc->setLateralEnabled(m_lateralCheckBox->isChecked()); smcc->setMedialEnabled(m_medialCheckBox->isChecked()); m_parentToolBarMontage->updateUserInterface(); m_parentToolBarMontage->invalidateColoringAndUpdateGraphicsWindow(); } /* ******************************************************************************************** */ /** * \class caret::SurfaceMontageCerebellarComponent * \brief Cerebellar Surface Montage Component of Brain Browser Window ToolBar * \ingroup GuiQt */ /** * Constructor. * * @param parentToolBar * parent toolbar. * @param objectNamePrefix * Prefix name for naming objects */ SurfaceMontageCerebellarComponent::SurfaceMontageCerebellarComponent(BrainBrowserWindowToolBarSurfaceMontage* parentToolBarMontage, const QString& parentObjectNamePrefix) : QWidget(parentToolBarMontage) { const QString objectNamePrefix(parentObjectNamePrefix + ":SurfaceMontageCerebellum"); m_parentToolBarMontage = parentToolBarMontage; WuQMacroManager* macroManager = WuQMacroManager::instance(); m_dorsalCheckBox = new QCheckBox("Dorsal"); QObject::connect(m_dorsalCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); m_dorsalCheckBox->setObjectName(objectNamePrefix + ":EnableDorsalView"); m_dorsalCheckBox->setToolTip("Enable Dorsal View"); macroManager->addMacroSupportToObject(m_dorsalCheckBox, "Enable dorsal view in cerebellar montage"); m_ventralCheckBox = new QCheckBox("Ventral"); QObject::connect(m_ventralCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); m_ventralCheckBox->setObjectName(objectNamePrefix + ":EnableVentralView"); m_ventralCheckBox->setToolTip("Enable Ventral View"); macroManager->addMacroSupportToObject(m_ventralCheckBox, "Enable ventral view in cerebellar montage"); m_anteriorCheckBox = new QCheckBox("Anterior"); QObject::connect(m_anteriorCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); m_anteriorCheckBox->setObjectName(objectNamePrefix + ":EnableAnteriorView"); m_anteriorCheckBox->setToolTip("Enable Anterior View"); macroManager->addMacroSupportToObject(m_anteriorCheckBox, "Enable anterior view in cerebellar montage"); m_posteriorCheckBox = new QCheckBox("Posterior"); QObject::connect(m_posteriorCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); m_posteriorCheckBox->setObjectName(objectNamePrefix + ":EnablePosteriorView"); m_posteriorCheckBox->setToolTip("Enable Posterior View"); macroManager->addMacroSupportToObject(m_posteriorCheckBox, "Enable posterior view in cerebellar montage"); m_firstSurfaceCheckBox = new QCheckBox(" "); QObject::connect(m_firstSurfaceCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); m_firstSurfaceCheckBox->setObjectName(objectNamePrefix + ":EnableFirstSurface"); m_firstSurfaceCheckBox->setToolTip("Enable First Cerebellar Surface"); macroManager->addMacroSupportToObject(m_firstSurfaceCheckBox, "Enable first in cerebellar montage"); m_secondSurfaceCheckBox = new QCheckBox(" "); QObject::connect(m_secondSurfaceCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); m_secondSurfaceCheckBox->setObjectName(objectNamePrefix + ":EnableSecondSurface"); m_secondSurfaceCheckBox->setToolTip("Enable Second Cerebellar Surface"); macroManager->addMacroSupportToObject(m_secondSurfaceCheckBox, "Enable second surface in cerebellar montage"); m_firstSurfaceViewController = new SurfaceSelectionViewController(this, objectNamePrefix + ":SurfaceFirst", "cerebellar monage first"); QObject::connect(m_firstSurfaceViewController, SIGNAL(surfaceSelected(Surface*)), this, SLOT(firstSurfaceSelected(Surface*))); m_secondSurfaceViewController = new SurfaceSelectionViewController(this, objectNamePrefix + ":SecondSurface", "cerebellar montage second"); QObject::connect(m_secondSurfaceViewController, SIGNAL(surfaceSelected(Surface*)), this, SLOT(secondSurfaceSelected(Surface*))); QHBoxLayout* checkBoxLayout = new QHBoxLayout(); WuQtUtilities::setLayoutSpacingAndMargins(checkBoxLayout, 2, 0); checkBoxLayout->addStretch(); checkBoxLayout->addWidget(m_dorsalCheckBox); checkBoxLayout->addSpacing(5); checkBoxLayout->addStretch(); checkBoxLayout->addWidget(m_ventralCheckBox); checkBoxLayout->addSpacing(5); checkBoxLayout->addStretch(); checkBoxLayout->addWidget(m_anteriorCheckBox); checkBoxLayout->addSpacing(5); checkBoxLayout->addStretch(); checkBoxLayout->addWidget(m_posteriorCheckBox); checkBoxLayout->addStretch(); int32_t columnIndex = 0; const int32_t COLUMN_CHECKBOX = columnIndex++; const int32_t COLUMN_SELECTION = columnIndex++; QGridLayout* layout = new QGridLayout(this); layout->setColumnStretch(COLUMN_CHECKBOX, 0); layout->setColumnStretch(COLUMN_SELECTION, 100); WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 0); int row = layout->rowCount(); layout->addWidget(m_firstSurfaceCheckBox, row, COLUMN_CHECKBOX); layout->addWidget(m_firstSurfaceViewController->getWidget(), row, COLUMN_SELECTION); row = layout->rowCount(); layout->addWidget(m_secondSurfaceCheckBox, row, COLUMN_CHECKBOX); layout->addWidget(m_secondSurfaceViewController->getWidget(), row, COLUMN_SELECTION); row = layout->rowCount(); layout->addLayout(checkBoxLayout, row, COLUMN_CHECKBOX, 1, 2); row = layout->rowCount(); m_widgetGroup = new WuQWidgetObjectGroup(this); m_widgetGroup->add(m_firstSurfaceViewController->getWidget()); m_widgetGroup->add(m_secondSurfaceViewController->getWidget()); m_widgetGroup->add(m_firstSurfaceCheckBox); m_widgetGroup->add(m_secondSurfaceCheckBox); m_widgetGroup->add(m_dorsalCheckBox); m_widgetGroup->add(m_ventralCheckBox); m_widgetGroup->add(m_anteriorCheckBox); m_widgetGroup->add(m_posteriorCheckBox); setFixedHeight(sizeHint().height()); } /** * Destructor. */ SurfaceMontageCerebellarComponent::~SurfaceMontageCerebellarComponent() { } /** * Update the cerebellar montage options widget. * * @param browserTabContent * The active model display controller (may be NULL). */ void SurfaceMontageCerebellarComponent::updateContent(BrowserTabContent* browserTabContent) { m_widgetGroup->blockAllSignals(true); const int32_t tabIndex = browserTabContent->getTabNumber(); ModelSurfaceMontage* msm = browserTabContent->getDisplayedSurfaceMontageModel(); SurfaceMontageConfigurationCerebellar* smcc = msm->getCerebellarConfiguration(tabIndex); m_firstSurfaceCheckBox->setChecked(smcc->isFirstSurfaceEnabled()); m_secondSurfaceCheckBox->setChecked(smcc->isSecondSurfaceEnabled()); m_dorsalCheckBox->setChecked(smcc->isDorsalEnabled()); m_ventralCheckBox->setChecked(smcc->isVentralEnabled()); m_anteriorCheckBox->setChecked(smcc->isAnteriorEnabled()); m_posteriorCheckBox->setChecked(smcc->isPosteriorEnabled()); m_firstSurfaceViewController->updateControl(smcc->getFirstSurfaceSelectionModel()); m_secondSurfaceViewController->updateControl(smcc->getSecondSurfaceSelectionModel()); m_widgetGroup->blockAllSignals(false); } /** * Called when first cerebellar surface is selected. * @param surface * Surface that was selected. */ void SurfaceMontageCerebellarComponent::firstSurfaceSelected(Surface* surface) { if (surface != NULL) { BrowserTabContent* btc = m_parentToolBarMontage->getTabContentFromSelectedTab(); const int32_t tabIndex = btc->getTabNumber(); ModelSurfaceMontage* msm = btc->getDisplayedSurfaceMontageModel(); SurfaceMontageConfigurationCerebellar* smcc = msm->getCerebellarConfiguration(tabIndex); smcc->getFirstSurfaceSelectionModel()->setSurface(surface); m_parentToolBarMontage->invalidateColoringAndUpdateGraphicsWindow(); } } /** * Called when second cerebellar surface is selected. * @param surface * Surface that was selected. */ void SurfaceMontageCerebellarComponent::secondSurfaceSelected(Surface* surface) { if (surface != NULL) { BrowserTabContent* btc = m_parentToolBarMontage->getTabContentFromSelectedTab(); const int32_t tabIndex = btc->getTabNumber(); ModelSurfaceMontage* msm = btc->getDisplayedSurfaceMontageModel(); SurfaceMontageConfigurationCerebellar* smcc = msm->getCerebellarConfiguration(tabIndex); smcc->getSecondSurfaceSelectionModel()->setSurface(surface); m_parentToolBarMontage->invalidateColoringAndUpdateGraphicsWindow(); } } /** * Called cerebellar surface montage checkbox is toggled. * @param status * New status of check box. */ void SurfaceMontageCerebellarComponent::checkBoxSelected(bool /*status*/) { BrowserTabContent* btc = m_parentToolBarMontage->getTabContentFromSelectedTab(); const int32_t tabIndex = btc->getTabNumber(); ModelSurfaceMontage* msm = btc->getDisplayedSurfaceMontageModel(); SurfaceMontageConfigurationCerebellar* smcc = msm->getCerebellarConfiguration(tabIndex); smcc->setDorsalEnabled(m_dorsalCheckBox->isChecked()); smcc->setVentralEnabled(m_ventralCheckBox->isChecked()); smcc->setAnteriorEnabled(m_anteriorCheckBox->isChecked()); smcc->setPosteriorEnabled(m_posteriorCheckBox->isChecked()); smcc->setFirstSurfaceEnabled(m_firstSurfaceCheckBox->isChecked()); smcc->setSecondSurfaceEnabled(m_secondSurfaceCheckBox->isChecked()); m_parentToolBarMontage->updateUserInterface(); m_parentToolBarMontage->invalidateColoringAndUpdateGraphicsWindow(); } /* ******************************************************************************************** */ /** * \class caret::SurfaceMontageFlatMapsComponent * \brief Flat Surface Montage Component of Brain Browser Window ToolBar * \ingroup GuiQt */ /** * Constructor. * * @param parentToolBar * parent toolbar. * @param objectNamePrefix * Prefix name for naming objects */ SurfaceMontageFlatMapsComponent::SurfaceMontageFlatMapsComponent(BrainBrowserWindowToolBarSurfaceMontage* parentToolBarMontage, const QString& parentObjectNamePrefix) : QWidget(parentToolBarMontage) { const QString objectNamePrefix(parentObjectNamePrefix + ":SurfaceMontageFlat"); m_parentToolBarMontage = parentToolBarMontage; WuQMacroManager* macroManager = WuQMacroManager::instance(); m_leftSurfaceCheckBox = new QCheckBox("Left"); QObject::connect(m_leftSurfaceCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); m_leftSurfaceCheckBox->setObjectName(objectNamePrefix + ":EnableLeft"); m_leftSurfaceCheckBox->setToolTip("Enable Left Flat Surface"); macroManager->addMacroSupportToObject(m_leftSurfaceCheckBox, "Enable left surface in flat montage"); m_rightSurfaceCheckBox = new QCheckBox("Right"); QObject::connect(m_rightSurfaceCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); m_rightSurfaceCheckBox->setObjectName(objectNamePrefix + ":EnableRight"); m_rightSurfaceCheckBox->setToolTip("Enable Right Flat Surface"); macroManager->addMacroSupportToObject(m_rightSurfaceCheckBox, "Enable right surface in flat montage"); m_cerebellumSurfaceCheckBox = new QCheckBox("Cerebellum "); QObject::connect(m_cerebellumSurfaceCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxSelected(bool))); m_cerebellumSurfaceCheckBox->setObjectName(objectNamePrefix + ":EnableCerebellum"); m_cerebellumSurfaceCheckBox->setToolTip("Enable Cerebellum Flat Surface"); macroManager->addMacroSupportToObject(m_cerebellumSurfaceCheckBox, "Enable cerebellar surface in flat montage"); m_leftSurfaceViewController = new SurfaceSelectionViewController(this, objectNamePrefix + ":LeftFlatSurface", "montage flat left"); QObject::connect(m_leftSurfaceViewController, SIGNAL(surfaceSelected(Surface*)), this, SLOT(leftSurfaceSelected(Surface*))); m_rightSurfaceViewController = new SurfaceSelectionViewController(this, objectNamePrefix + ":RightFlatSurface", "montage flat right"); QObject::connect(m_rightSurfaceViewController, SIGNAL(surfaceSelected(Surface*)), this, SLOT(rightSurfaceSelected(Surface*))); m_cerebellumSurfaceViewController = new SurfaceSelectionViewController(this, objectNamePrefix + ":CerebellumSurface", "montage flat cerebellum"); QObject::connect(m_cerebellumSurfaceViewController, SIGNAL(surfaceSelected(Surface*)), this, SLOT(cerebellumSurfaceSelected(Surface*))); int32_t columnIndex = 0; const int32_t COLUMN_CHECKBOX = columnIndex++; const int32_t COLUMN_SELECTION = columnIndex++; QGridLayout* layout = new QGridLayout(this); layout->setColumnStretch(COLUMN_CHECKBOX, 0); layout->setColumnStretch(COLUMN_SELECTION, 100); WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 2); int row = layout->rowCount(); layout->addWidget(m_leftSurfaceCheckBox, row, COLUMN_CHECKBOX); layout->addWidget(m_leftSurfaceViewController->getWidget(), row, COLUMN_SELECTION); row = layout->rowCount(); layout->addWidget(m_rightSurfaceCheckBox, row, COLUMN_CHECKBOX); layout->addWidget(m_rightSurfaceViewController->getWidget(), row, COLUMN_SELECTION); row = layout->rowCount(); layout->addWidget(m_cerebellumSurfaceCheckBox, row, COLUMN_CHECKBOX); layout->addWidget(m_cerebellumSurfaceViewController->getWidget(), row, COLUMN_SELECTION); row = layout->rowCount(); m_widgetGroup = new WuQWidgetObjectGroup(this); m_widgetGroup->add(m_leftSurfaceViewController->getWidget()); m_widgetGroup->add(m_rightSurfaceViewController->getWidget()); m_widgetGroup->add(m_cerebellumSurfaceViewController->getWidget()); m_widgetGroup->add(m_leftSurfaceCheckBox); m_widgetGroup->add(m_rightSurfaceCheckBox); m_widgetGroup->add(m_cerebellumSurfaceCheckBox); setFixedHeight(sizeHint().height()); } /** * Destructor. */ SurfaceMontageFlatMapsComponent::~SurfaceMontageFlatMapsComponent() { } /** * Update the flat maps montage options widget. * * @param browserTabContent * The active model display controller (may be NULL). */ void SurfaceMontageFlatMapsComponent::updateContent(BrowserTabContent* browserTabContent) { m_widgetGroup->blockAllSignals(true); const int32_t tabIndex = browserTabContent->getTabNumber(); ModelSurfaceMontage* msm = browserTabContent->getDisplayedSurfaceMontageModel(); SurfaceMontageConfigurationFlatMaps* smcc = msm->getFlatMapsConfiguration(tabIndex); m_leftSurfaceCheckBox->setChecked(smcc->isLeftEnabled()); m_rightSurfaceCheckBox->setChecked(smcc->isRightEnabled()); m_cerebellumSurfaceCheckBox->setChecked(smcc->isCerebellumEnabled()); m_leftSurfaceViewController->updateControl(smcc->getLeftSurfaceSelectionModel()); m_rightSurfaceViewController->updateControl(smcc->getRightSurfaceSelectionModel()); m_cerebellumSurfaceViewController->updateControl(smcc->getCerebellumSurfaceSelectionModel()); m_widgetGroup->blockAllSignals(false); } /** * Called when flat left surface is selected. * @param surface * Surface that was selected. */ void SurfaceMontageFlatMapsComponent::leftSurfaceSelected(Surface* surface) { if (surface != NULL) { BrowserTabContent* btc = m_parentToolBarMontage->getTabContentFromSelectedTab(); const int32_t tabIndex = btc->getTabNumber(); ModelSurfaceMontage* msm = btc->getDisplayedSurfaceMontageModel(); SurfaceMontageConfigurationFlatMaps* smcc = msm->getFlatMapsConfiguration(tabIndex); smcc->getLeftSurfaceSelectionModel()->setSurface(surface); m_parentToolBarMontage->invalidateColoringAndUpdateGraphicsWindow(); } } /** * Called when flat right surface is selected. * @param surface * Surface that was selected. */ void SurfaceMontageFlatMapsComponent::rightSurfaceSelected(Surface* surface) { if (surface != NULL) { BrowserTabContent* btc = m_parentToolBarMontage->getTabContentFromSelectedTab(); const int32_t tabIndex = btc->getTabNumber(); ModelSurfaceMontage* msm = btc->getDisplayedSurfaceMontageModel(); SurfaceMontageConfigurationFlatMaps* smcc = msm->getFlatMapsConfiguration(tabIndex); smcc->getRightSurfaceSelectionModel()->setSurface(surface); m_parentToolBarMontage->invalidateColoringAndUpdateGraphicsWindow(); } } /** * Called when flat cerebellum surface is selected. * @param surface * Surface that was selected. */ void SurfaceMontageFlatMapsComponent::cerebellumSurfaceSelected(Surface* surface) { if (surface != NULL) { BrowserTabContent* btc = m_parentToolBarMontage->getTabContentFromSelectedTab(); const int32_t tabIndex = btc->getTabNumber(); ModelSurfaceMontage* msm = btc->getDisplayedSurfaceMontageModel(); SurfaceMontageConfigurationFlatMaps* smcc = msm->getFlatMapsConfiguration(tabIndex); smcc->getCerebellumSurfaceSelectionModel()->setSurface(surface); m_parentToolBarMontage->invalidateColoringAndUpdateGraphicsWindow(); } } /** * Called when flat maps surface montage checkbox is toggled. * @param status * New status of check box. */ void SurfaceMontageFlatMapsComponent::checkBoxSelected(bool /*status*/) { BrowserTabContent* btc = m_parentToolBarMontage->getTabContentFromSelectedTab(); const int32_t tabIndex = btc->getTabNumber(); ModelSurfaceMontage* msm = btc->getDisplayedSurfaceMontageModel(); SurfaceMontageConfigurationFlatMaps* smcc = msm->getFlatMapsConfiguration(tabIndex); smcc->setLeftEnabled(m_leftSurfaceCheckBox->isChecked()); smcc->setRightEnabled(m_rightSurfaceCheckBox->isChecked()); smcc->setCerebellumEnabled(m_cerebellumSurfaceCheckBox->isChecked()); m_parentToolBarMontage->updateUserInterface(); m_parentToolBarMontage->invalidateColoringAndUpdateGraphicsWindow(); } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarSurfaceMontage.h000066400000000000000000000155011360521144700275240ustar00rootroot00000000000000#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_SURFACE_MONTAGE_H__ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_SURFACE_MONTAGE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainBrowserWindowToolBarComponent.h" class QCheckBox; class QStackedWidget; namespace caret { class BrowserTabContent; class EnumComboBoxTemplate; class Surface; class SurfaceMontageCerebellarComponent; class SurfaceMontageCerebralComponent; class SurfaceMontageFlatMapsComponent; class SurfaceSelectionViewController; class BrainBrowserWindowToolBarSurfaceMontage : public BrainBrowserWindowToolBarComponent { Q_OBJECT public: BrainBrowserWindowToolBarSurfaceMontage(BrainBrowserWindowToolBar* parentToolBar, const QString& parentObjectNamePrefix); virtual ~BrainBrowserWindowToolBarSurfaceMontage(); virtual void updateContent(BrowserTabContent* browserTabContent); private slots: void surfaceMontageConfigurationTypeEnumComboBoxItemActivated(); void surfaceMontageLayoutOrientationEnumComboBoxItemActivated(); private: BrainBrowserWindowToolBarSurfaceMontage(const BrainBrowserWindowToolBarSurfaceMontage&); BrainBrowserWindowToolBarSurfaceMontage& operator=(const BrainBrowserWindowToolBarSurfaceMontage&); BrainBrowserWindowToolBar* m_parentToolBar; SurfaceMontageCerebralComponent* m_cerebralComponent; SurfaceMontageCerebellarComponent* m_cerebellarComponent; SurfaceMontageFlatMapsComponent* m_flatMapsComponent; QStackedWidget* m_stackedWidget; EnumComboBoxTemplate* m_surfaceMontageConfigurationTypeEnumComboBox; EnumComboBoxTemplate* m_surfaceMontageLayoutOrientationEnumComboBox; // ADD_NEW_MEMBERS_HERE private slots: }; /* ===========================================================================*/ class SurfaceMontageCerebralComponent : public QWidget { Q_OBJECT public: SurfaceMontageCerebralComponent(BrainBrowserWindowToolBarSurfaceMontage* parentToolBarMontage, const QString& parentObjectNamePrefix); ~SurfaceMontageCerebralComponent(); void updateContent(BrowserTabContent* browserTabContent); private slots: void leftSurfaceSelected(Surface*); void leftSecondSurfaceSelected(Surface*); void rightSurfaceSelected(Surface*); void rightSecondSurfaceSelected(Surface*); void checkBoxSelected(bool); private: BrainBrowserWindowToolBarSurfaceMontage* m_parentToolBarMontage; SurfaceSelectionViewController* m_leftSurfaceViewController; SurfaceSelectionViewController* m_leftSecondSurfaceViewController; SurfaceSelectionViewController* m_rightSurfaceViewController; SurfaceSelectionViewController* m_rightSecondSurfaceViewController; QCheckBox* m_leftCheckBox; QCheckBox* m_rightCheckBox; QCheckBox* m_surfaceMontageFirstSurfaceCheckBox; QCheckBox* m_surfaceMontageSecondSurfaceCheckBox; QCheckBox* m_lateralCheckBox; QCheckBox* m_medialCheckBox; WuQWidgetObjectGroup* m_widgetGroup; }; /* ===========================================================================*/ class SurfaceMontageCerebellarComponent : public QWidget { Q_OBJECT public: SurfaceMontageCerebellarComponent(BrainBrowserWindowToolBarSurfaceMontage* parentToolBarMontage, const QString& parentObjectNamePrefix); ~SurfaceMontageCerebellarComponent(); void updateContent(BrowserTabContent* browserTabContent); private slots: void firstSurfaceSelected(Surface*); void secondSurfaceSelected(Surface*); void checkBoxSelected(bool); private: BrainBrowserWindowToolBarSurfaceMontage* m_parentToolBarMontage; SurfaceSelectionViewController* m_firstSurfaceViewController; SurfaceSelectionViewController* m_secondSurfaceViewController; QCheckBox* m_firstSurfaceCheckBox; QCheckBox* m_secondSurfaceCheckBox; QCheckBox* m_dorsalCheckBox; QCheckBox* m_ventralCheckBox; QCheckBox* m_anteriorCheckBox; QCheckBox* m_posteriorCheckBox; WuQWidgetObjectGroup* m_widgetGroup; }; /* ===========================================================================*/ class SurfaceMontageFlatMapsComponent : public QWidget { Q_OBJECT public: SurfaceMontageFlatMapsComponent(BrainBrowserWindowToolBarSurfaceMontage* parentToolBarMontage, const QString& parentObjectNamePrefix); ~SurfaceMontageFlatMapsComponent(); void updateContent(BrowserTabContent* browserTabContent); private slots: void leftSurfaceSelected(Surface*); void rightSurfaceSelected(Surface*); void cerebellumSurfaceSelected(Surface*); void checkBoxSelected(bool); private: BrainBrowserWindowToolBarSurfaceMontage* m_parentToolBarMontage; SurfaceSelectionViewController* m_leftSurfaceViewController; SurfaceSelectionViewController* m_rightSurfaceViewController; SurfaceSelectionViewController* m_cerebellumSurfaceViewController; QCheckBox* m_leftSurfaceCheckBox; QCheckBox* m_rightSurfaceCheckBox; QCheckBox* m_cerebellumSurfaceCheckBox; WuQWidgetObjectGroup* m_widgetGroup; }; #ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_SURFACE_MONTAGE_DECLARE__ // #endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_SURFACE_MONTAGE_DECLARE__ } // namespace #endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_SURFACE_MONTAGE_H__ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarTab.cxx000066400000000000000000000216021360521144700257010ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_DECLARE__ #include "BrainBrowserWindowToolBarTab.h" #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_DECLARE__ #include #include #include #include #include #include #include "BrainBrowserWindow.h" #include "BrainBrowserWindowToolBar.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "EnumComboBoxTemplate.h" #include "GuiManager.h" #include "WuQtUtilities.h" #include "WuQWidgetObjectGroup.h" #include "YokingGroupEnum.h" #include "WuQDataEntryDialog.h" #include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::BrainBrowserWindowToolBarTab * \brief Tab section of Browser Window Toolbar. * \ingroup GuiQt */ /** * Constructor. * * @param browserWindowIndex * Index of browser window. * @param toolBarLockWindowAndAllTabAspectRatioButton * Button for locking window and all tab aspect ratio. * @param parentToolBar * Parent toolbar. * @param objectNamePrefix Prefix for naming objects */ BrainBrowserWindowToolBarTab::BrainBrowserWindowToolBarTab(const int32_t browserWindowIndex, QToolButton* toolBarLockWindowAndAllTabAspectRatioButton, BrainBrowserWindowToolBar* parentToolBar, const QString& objectNamePrefix) : BrainBrowserWindowToolBarComponent(parentToolBar), m_browserWindowIndex(browserWindowIndex), m_parentToolBar(parentToolBar), m_lockWindowAndAllTabAspectButton(toolBarLockWindowAndAllTabAspectRatioButton) { m_yokingGroupComboBox = new EnumComboBoxTemplate(this); m_yokingGroupComboBox->setup(); m_yokingGroupComboBox->getWidget()->setStatusTip("Select a yoking group (linked views)"); m_yokingGroupComboBox->getWidget()->setToolTip(("Select a yoking group (linked views).\n" "Models yoked to a group are displayed in the same view.\n" "Surface Yoking is applied to Surface, Surface Montage\n" "and Whole Brain. Volume Yoking is applied to Volumes.")); QComboBox* encapComboBox = m_yokingGroupComboBox->getComboBox(); encapComboBox->setObjectName(objectNamePrefix + ":Tab:YokingGroup"); WuQMacroManager::instance()->addMacroSupportToObject(encapComboBox, "Select yoking group"); m_yokeToLabel = new QLabel("Yoking:"); QObject::connect(m_yokingGroupComboBox, SIGNAL(itemActivated()), this, SLOT(yokeToGroupComboBoxIndexChanged())); const AString lightToolTip = WuQtUtilities::createWordWrappedToolTipText("Enables shading on surfaces. Shading affects " "palette colors (but not by much) and in rare circumstances it " "may be helpful to turn shading off."); m_lightingEnabledCheckBox = new QCheckBox("Shading"); m_lightingEnabledCheckBox->setToolTip(lightToolTip); QObject::connect(m_lightingEnabledCheckBox, &QCheckBox::clicked, this, &BrainBrowserWindowToolBarTab::lightingEnabledCheckBoxChecked); m_lightingEnabledCheckBox->setObjectName(objectNamePrefix + ":Tab:EnableShading"); WuQMacroManager::instance()->addMacroSupportToObject(m_lightingEnabledCheckBox, "Enable shading"); m_macroRecordingLabel = new QLabel(""); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 0); layout->addWidget(m_yokeToLabel); layout->addWidget(m_yokingGroupComboBox->getWidget()); layout->addWidget(m_lockWindowAndAllTabAspectButton); layout->addWidget(m_lightingEnabledCheckBox); layout->addWidget(m_macroRecordingLabel); addToWidgetGroup(m_yokeToLabel); addToWidgetGroup(m_yokingGroupComboBox->getWidget()); addToWidgetGroup(m_lightingEnabledCheckBox); addToWidgetGroup(m_macroRecordingLabel); } /** * Destructor. */ BrainBrowserWindowToolBarTab::~BrainBrowserWindowToolBarTab() { } /** * Update the surface montage options widget. * * @param browserTabContent * The active model display controller (may be NULL). */ void BrainBrowserWindowToolBarTab::updateContent(BrowserTabContent* browserTabContent) { if (browserTabContent == NULL) { return; } blockAllSignals(true); bool chartFlag = false; switch (browserTabContent->getSelectedModelType()) { case ModelTypeEnum::MODEL_TYPE_CHART: chartFlag = true; break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: chartFlag = true; break; case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: break; } if (chartFlag) { m_yokeToLabel->setText("Chart Yoking:"); m_yokingGroupComboBox->setSelectedItem(browserTabContent->getChartModelYokingGroup()); } else { m_yokeToLabel->setText("Yoking:"); m_yokingGroupComboBox->setSelectedItem(browserTabContent->getBrainModelYokingGroup()); } m_lightingEnabledCheckBox->setChecked(browserTabContent->isLightingEnabled()); m_macroRecordingLabel->setText(""); switch (WuQMacroManager::instance()->getMode()) { case WuQMacroModeEnum::OFF: break; case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: case WuQMacroModeEnum::RECORDING_NEW_MACRO: m_macroRecordingLabel->setText("Macro"); break; case WuQMacroModeEnum::RUNNING: break; } blockAllSignals(false); } /** * Called when lighting checkbox is checked by user * * @param checked * New status of lighting. */ void BrainBrowserWindowToolBarTab::lightingEnabledCheckBoxChecked(bool checked) { BrowserTabContent* browserTabContent = this->getTabContentFromSelectedTab(); if (browserTabContent == NULL) { return; } browserTabContent->setLightingEnabled(checked); this->updateGraphicsWindow(); } /** * Called when window yoke to tab combo box is selected. */ void BrainBrowserWindowToolBarTab::yokeToGroupComboBoxIndexChanged() { BrowserTabContent* browserTabContent = this->getTabContentFromSelectedTab(); if (browserTabContent == NULL) { return; } bool chartFlag = false; switch (browserTabContent->getSelectedModelType()) { case ModelTypeEnum::MODEL_TYPE_CHART: chartFlag = true; break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: chartFlag = true; break; case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: break; } YokingGroupEnum::Enum yokingGroup = m_yokingGroupComboBox->getSelectedItem(); if (chartFlag) { browserTabContent->setChartModelYokingGroup(yokingGroup); } else { browserTabContent->setBrainModelYokingGroup(yokingGroup); } m_parentToolBar->updateToolBarComponents(browserTabContent); this->updateGraphicsWindow(); } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarTab.h000066400000000000000000000052711360521144700253320ustar00rootroot00000000000000#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_H__ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "BrainBrowserWindowToolBarComponent.h" class QCheckBox; class QLabel; class QToolButton; namespace caret { class BrainBrowserWindowToolBar; class EnumComboBoxTemplate; class BrainBrowserWindowToolBarTab : public BrainBrowserWindowToolBarComponent { Q_OBJECT public: BrainBrowserWindowToolBarTab(const int32_t browserWindowIndex, QToolButton* toolBarLockWindowAndAllTabAspectRatioButton, BrainBrowserWindowToolBar* parentToolBar, const QString& objectNamePrefix); virtual ~BrainBrowserWindowToolBarTab(); virtual void updateContent(BrowserTabContent* browserTabContent); // ADD_NEW_METHODS_HERE private slots: void yokeToGroupComboBoxIndexChanged(); void lightingEnabledCheckBoxChecked(bool checked); private: BrainBrowserWindowToolBarTab(const BrainBrowserWindowToolBarTab&); BrainBrowserWindowToolBarTab& operator=(const BrainBrowserWindowToolBarTab&); QLabel* m_yokeToLabel; EnumComboBoxTemplate* m_yokingGroupComboBox; const int32_t m_browserWindowIndex; BrainBrowserWindowToolBar* m_parentToolBar; QToolButton* m_lockWindowAndAllTabAspectButton; QCheckBox* m_lightingEnabledCheckBox; QLabel* m_macroRecordingLabel; // ADD_NEW_MEMBERS_HERE }; #ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_DECLARE__ // #endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_DECLARE__ } // namespace #endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_H__ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx000066400000000000000000000254471360521144700275250ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_POP_UP_MENU_DECLARE__ #include "BrainBrowserWindowToolBarTabPopUpMenu.h" #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_POP_UP_MENU_DECLARE__ #include "BrainBrowserWindowToolBar.h" #include "CaretAssert.h" #include "WuQTabBar.h" using namespace caret; /** * \class caret::BrainBrowserWindowToolBarTabPopUpMenu * \brief Pop up (context-sensitive) menu for tab in toolbar to add new tabs * \ingroup GuiQt * * This menu is displayed when the user performs a right-click * with the mouse over a tab in the brain browswer window toolbar. * The menu allows users to add/duplicate/remove tabs. */ /** * Constructor. * * @param toolBar * The toolbar. * @param tabIndexUnderMouse * Index of tab over which mouse was clicked * @param parent * Optional parent widget. */ BrainBrowserWindowToolBarTabPopUpMenu::BrainBrowserWindowToolBarTabPopUpMenu(BrainBrowserWindowToolBar* toolBar, const int32_t tabIndexUnderMouse, QWidget* parent) : QMenu(parent), m_toolBar(toolBar), m_tabIndexUnderMouse(tabIndexUnderMouse) { CaretAssert(m_toolBar); CaretAssert(m_toolBar->tabBar); m_numberOfTabs = m_toolBar->tabBar->count(); m_activeTabIndex = m_toolBar->tabBar->currentIndex(); addItem(MenuItem::CREATE_NEW_TAB_BEFORE); addItem(MenuItem::CREATE_NEW_TAB_AFTER); addSeparator(); addItem(MenuItem::DUPLICATE_TAB_AT_BEGINNING); addItem(MenuItem::DUPLICATE_TAB_BEFORE); addItem(MenuItem::DUPLICATE_TAB_AFTER); addItem(MenuItem::DUPLICATE_TAB_AT_END); addSeparator(); addItem(MenuItem::MOVE_TAB_TO_BEGINNING); addItem(MenuItem::MOVE_TAB_BEFORE); addItem(MenuItem::MOVE_TAB_AFTER); addItem(MenuItem::MOVE_TAB_TO_END); addSeparator(); addItem(MenuItem::DELETE_TAB); QObject::connect(this, &QMenu::triggered, this, &BrainBrowserWindowToolBarTabPopUpMenu::menuItemSelected); } /** * Destructor. */ BrainBrowserWindowToolBarTabPopUpMenu::~BrainBrowserWindowToolBarTabPopUpMenu() { } /** * Add an item to the menu. * * @param menuItem * Item to be added to menu. */ void BrainBrowserWindowToolBarTabPopUpMenu::addItem(const MenuItem menuItem) { QString thisTabName = "This Tab"; QString activeTabName = "Active Tab"; const bool includeNamesInMenuFlag = false; if (includeNamesInMenuFlag) { if (m_tabIndexUnderMouse >= 0) { thisTabName = ("Tab \"" + m_toolBar->tabBar->tabText(m_tabIndexUnderMouse) + "\""); } const int32_t activeTabIndex = m_toolBar->tabBar->currentIndex(); if (activeTabIndex >= 0) { activeTabName = ("Tab \"" + m_toolBar->tabBar->tabText(activeTabIndex) + "\""); } } QString text; switch (menuItem) { case MenuItem::NONE: CaretAssert(0); break; case MenuItem::CREATE_NEW_TAB_BEFORE: text = "Create New Tab Before " + thisTabName; break; case MenuItem::CREATE_NEW_TAB_AFTER: text = "Create New Tab After " + thisTabName; break; case MenuItem::DUPLICATE_TAB_AT_BEGINNING: text = "Duplicate " + thisTabName + " at Beginning"; break; case MenuItem::DUPLICATE_TAB_BEFORE: text = "Duplicate " + thisTabName + " Before " + activeTabName; break; case MenuItem::DUPLICATE_TAB_AFTER: text = "Duplicate " + thisTabName + " After " + activeTabName; break; case MenuItem::DUPLICATE_TAB_AT_END: text = "Duplicate " + thisTabName + " at End"; break; case MenuItem::MOVE_TAB_TO_BEGINNING: text = "Move " + thisTabName + " to Beginning"; break; case MenuItem::MOVE_TAB_BEFORE: text = "Move " + thisTabName + " to Before " + activeTabName; break; case MenuItem::MOVE_TAB_AFTER: text = "Move " + thisTabName + " to After " + activeTabName; break; case MenuItem::MOVE_TAB_TO_END: text = "Move " + thisTabName + " to End"; break; case MenuItem::DELETE_TAB: text = "Delete " + thisTabName; break; } QAction* action = addAction(text); action->setData(static_cast(menuItem)); action->setEnabled(isEnabled(menuItem)); } /** * Called when a menu item is selected. * * @param action * Action for item in menu that was selected. */ void BrainBrowserWindowToolBarTabPopUpMenu::menuItemSelected(QAction* action) { if (action != NULL) { const BrowserTabContent* activeTabContent = m_toolBar->getTabContentFromTab(m_activeTabIndex); MenuItem menuItem = static_cast(action->data().toInt()); CaretAssert(isEnabled(menuItem)); int32_t createNewIndex = -1; int32_t deleteIndex = -1; int32_t duplicateToIndex = -1; int32_t moveToIndex = -1; switch (menuItem) { case MenuItem::NONE: CaretAssert(0); break; case MenuItem::CREATE_NEW_TAB_BEFORE: createNewIndex = m_tabIndexUnderMouse; break; case MenuItem::CREATE_NEW_TAB_AFTER: createNewIndex = m_tabIndexUnderMouse + 1; break; case MenuItem::DUPLICATE_TAB_AT_BEGINNING: duplicateToIndex = 0; break; case MenuItem::DUPLICATE_TAB_BEFORE: duplicateToIndex = m_activeTabIndex; break; case MenuItem::DUPLICATE_TAB_AFTER: duplicateToIndex = m_activeTabIndex + 1; break; case MenuItem::DUPLICATE_TAB_AT_END: duplicateToIndex = m_numberOfTabs; break; case MenuItem::MOVE_TAB_TO_BEGINNING: moveToIndex = 0; break; case MenuItem::MOVE_TAB_BEFORE: if (m_tabIndexUnderMouse < m_activeTabIndex) { moveToIndex = m_activeTabIndex - 1; } else { moveToIndex = m_activeTabIndex; } break; case MenuItem::MOVE_TAB_AFTER: if (m_tabIndexUnderMouse < m_activeTabIndex) { moveToIndex = m_activeTabIndex; } else { moveToIndex = m_activeTabIndex + 1; } break; case MenuItem::MOVE_TAB_TO_END: moveToIndex = m_numberOfTabs - 1; break; case MenuItem::DELETE_TAB: deleteIndex = m_tabIndexUnderMouse; break; } if (createNewIndex >= 0) { m_toolBar->insertNewTabAtTabBarIndex(createNewIndex); } else if (deleteIndex >= 0) { m_toolBar->tabCloseSelected(deleteIndex); } else if (duplicateToIndex >= 0) { BrowserTabContent* tabContent = m_toolBar->getTabContentFromTab(m_tabIndexUnderMouse); CaretAssert(tabContent); m_toolBar->insertAndCloneTabContentAtTabBarIndex(tabContent, duplicateToIndex); } else if (moveToIndex >= 0) { if (moveToIndex != m_tabIndexUnderMouse) { m_toolBar->tabBar->moveTab(m_tabIndexUnderMouse, moveToIndex); } } /* * Ensure active tab remains active. Note that number of tabs may have changed. */ int32_t updatedActiveTabIndex = -1; const int32_t numTabs = m_toolBar->tabBar->count(); for (int32_t iTab = 0; iTab < numTabs; iTab++) { if (activeTabContent == m_toolBar->getTabContentFromTab(iTab)) { updatedActiveTabIndex = iTab; break; } } if (updatedActiveTabIndex >= 0) { m_toolBar->tabBar->setCurrentIndex(updatedActiveTabIndex); } } } /** * @return True if the menu item is enabled. * Items are enabled if action would do nothing such as * moving a tab to itself. * * @param item * Item for testing enabled. */ bool BrainBrowserWindowToolBarTabPopUpMenu::isEnabled(const MenuItem menuItem) const { bool enabledFlag = false; BrowserTabContent* tabContent = m_toolBar->getTabContentFromTab(m_tabIndexUnderMouse); switch (menuItem) { case MenuItem::NONE: CaretAssert(0); break; case MenuItem::CREATE_NEW_TAB_BEFORE: enabledFlag = true; break; case MenuItem::CREATE_NEW_TAB_AFTER: enabledFlag = true; break; case MenuItem::DUPLICATE_TAB_AT_BEGINNING: case MenuItem::DUPLICATE_TAB_BEFORE: case MenuItem::DUPLICATE_TAB_AFTER: case MenuItem::DUPLICATE_TAB_AT_END: if (tabContent != NULL) { enabledFlag = true; } break; case MenuItem::MOVE_TAB_TO_BEGINNING: if (m_tabIndexUnderMouse > 0) { enabledFlag = true; } break; case MenuItem::MOVE_TAB_BEFORE: if ((m_tabIndexUnderMouse != m_activeTabIndex) && (m_tabIndexUnderMouse != (m_activeTabIndex - 1))) { enabledFlag = true; } break; case MenuItem::MOVE_TAB_AFTER: if ((m_tabIndexUnderMouse != m_activeTabIndex) && (m_tabIndexUnderMouse != (m_activeTabIndex + 1))) { enabledFlag = true; } break; case MenuItem::MOVE_TAB_TO_END: if (m_tabIndexUnderMouse != (m_numberOfTabs - 1)) { enabledFlag = true; } break; case MenuItem::DELETE_TAB: enabledFlag = true; break; } return enabledFlag; } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.h000066400000000000000000000054301360521144700271400ustar00rootroot00000000000000#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_POP_UP_MENU_H__ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_POP_UP_MENU_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include namespace caret { class BrainBrowserWindowToolBar; class BrainBrowserWindowToolBarTabPopUpMenu : public QMenu { Q_OBJECT public: BrainBrowserWindowToolBarTabPopUpMenu(BrainBrowserWindowToolBar* toolBar, const int32_t tabIndexUnderMouse, QWidget* parent = 0); virtual ~BrainBrowserWindowToolBarTabPopUpMenu(); // ADD_NEW_METHODS_HERE private slots: void menuItemSelected(QAction* action); private: enum class MenuItem { NONE, CREATE_NEW_TAB_BEFORE, CREATE_NEW_TAB_AFTER, DUPLICATE_TAB_AT_BEGINNING, DUPLICATE_TAB_BEFORE, DUPLICATE_TAB_AFTER, DUPLICATE_TAB_AT_END, MOVE_TAB_TO_BEGINNING, MOVE_TAB_BEFORE, MOVE_TAB_AFTER, MOVE_TAB_TO_END, DELETE_TAB }; BrainBrowserWindowToolBarTabPopUpMenu(const BrainBrowserWindowToolBarTabPopUpMenu&); BrainBrowserWindowToolBarTabPopUpMenu& operator=(const BrainBrowserWindowToolBarTabPopUpMenu&); void addItem(const MenuItem menuItem); bool isEnabled(const MenuItem menuItem) const; BrainBrowserWindowToolBar* m_toolBar; int32_t m_tabIndexUnderMouse; int32_t m_numberOfTabs; int32_t m_activeTabIndex; // ADD_NEW_MEMBERS_HERE }; #ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_POP_UP_MENU_DECLARE__ // #endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_POP_UP_MENU_DECLARE__ } // namespace #endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_POP_UP_MENU_H__ connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarVolumeMontage.cxx000066400000000000000000000276411360521144700277660ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_VOLUME_MONTAGE_DECLARE__ #include "BrainBrowserWindowToolBarVolumeMontage.h" #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_VOLUME_MONTAGE_DECLARE__ #include #include #include #include #include #include #include "BrowserTabContent.h" #include "CaretAssert.h" #include "WuQFactory.h" #include "WuQMacroManager.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::BrainBrowserWindowToolBarVolumeMontage * \brief Toolbar component for volume montage slice selections * \ingroup GuiQt */ /** * Constructor. * * @param parentObjectName * Name of parent for macros * @param parentToolBar * The parent toolbar */ BrainBrowserWindowToolBarVolumeMontage::BrainBrowserWindowToolBarVolumeMontage(const QString& parentObjectName, BrainBrowserWindowToolBar* parentToolBar) : BrainBrowserWindowToolBarComponent(parentToolBar), m_parentToolBar(parentToolBar) { const QString objectNamePrefix(parentObjectName + ":VolumeSliceMontage:"); const int spinBoxWidth = 48; QLabel* rowsLabel = new QLabel("Rows:"); rowsLabel->setToolTip("Select the number of rows in montage of volume slices"); m_montageRowsSpinBox = WuQFactory::newSpinBox(); m_montageRowsSpinBox->setRange(1, 20); m_montageRowsSpinBox->setMaximumWidth(spinBoxWidth); m_montageRowsSpinBox->setToolTip(rowsLabel->toolTip()); QObject::connect(m_montageRowsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(montageRowsSpinBoxValueChanged(int))); m_montageRowsSpinBox->setObjectName(objectNamePrefix + "Rows"); WuQMacroManager::instance()->addMacroSupportToObject(m_montageRowsSpinBox, "Set volume montage rows"); QLabel* columnsLabel = new QLabel("Cols:"); columnsLabel->setToolTip("Select the number of columns in montage of volume slices"); m_montageColumnsSpinBox = WuQFactory::newSpinBox(); m_montageColumnsSpinBox->setRange(1, 20); m_montageColumnsSpinBox->setMaximumWidth(spinBoxWidth); m_montageColumnsSpinBox->setToolTip(columnsLabel->toolTip()); QObject::connect(m_montageColumnsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(montageColumnsSpinBoxValueChanged(int))); m_montageColumnsSpinBox->setObjectName(objectNamePrefix + "Columns"); WuQMacroManager::instance()->addMacroSupportToObject(m_montageColumnsSpinBox, "Set volume montage columns"); QLabel* spacingLabel = new QLabel("Step:"); spacingLabel->setToolTip("Select the number of slices stepped (incremented) between displayed montage slices"); m_montageSpacingSpinBox = WuQFactory::newSpinBox(); m_montageSpacingSpinBox->setRange(1, 2500); m_montageSpacingSpinBox->setMaximumWidth(spinBoxWidth); m_montageSpacingSpinBox->setToolTip(spacingLabel->toolTip()); QObject::connect(m_montageSpacingSpinBox, SIGNAL(valueChanged(int)), this, SLOT(montageSpacingSpinBoxValueChanged(int))); m_montageSpacingSpinBox->setObjectName(objectNamePrefix + "Step"); WuQMacroManager::instance()->addMacroSupportToObject(m_montageSpacingSpinBox, "Set volume montage spacing"); m_showSliceCoordinateAction = new QAction("XYZ", this); m_showSliceCoordinateAction->setText("XYZ"); m_showSliceCoordinateAction->setCheckable(true); m_showSliceCoordinateAction->setToolTip("Show coordinates on slices"); QObject::connect(m_showSliceCoordinateAction, &QAction::triggered, this, &BrainBrowserWindowToolBarVolumeMontage::showSliceCoordinateToolButtonClicked); m_showSliceCoordinateAction->setObjectName(objectNamePrefix + "ShowCoordinateOnSlice"); WuQMacroManager::instance()->addMacroSupportToObject(m_showSliceCoordinateAction, "Enable coordinates in volume montage"); QToolButton* showSliceCoordToolButton = new QToolButton; showSliceCoordToolButton->setDefaultAction(m_showSliceCoordinateAction); WuQtUtilities::setToolButtonStyleForQt5Mac(showSliceCoordToolButton); QLabel* decimalsLabel = new QLabel("Prec:"); decimalsLabel->setToolTip("Digits right of decimal in slice coordinates"); m_sliceCoordinatePrecisionSpinBox = WuQFactory::newSpinBox(); m_sliceCoordinatePrecisionSpinBox->setRange(0, 10); m_sliceCoordinatePrecisionSpinBox->setMaximumWidth(spinBoxWidth); m_sliceCoordinatePrecisionSpinBox->setToolTip(decimalsLabel->toolTip()); QObject::connect(m_sliceCoordinatePrecisionSpinBox, static_cast(&QSpinBox::valueChanged), this, &BrainBrowserWindowToolBarVolumeMontage::slicePrecisionSpinBoxValueChanged); m_sliceCoordinatePrecisionSpinBox->setObjectName(objectNamePrefix + "Precision"); WuQMacroManager::instance()->addMacroSupportToObject(m_sliceCoordinatePrecisionSpinBox, "Set volume montage coordinate precision"); QToolButton* montageEnabledToolButton = new QToolButton(); m_montageEnabledAction = WuQtUtilities::createAction("On", "View a montage of parallel slices", montageEnabledToolButton, this, SLOT(montageEnabledActionToggled(bool))); m_montageEnabledAction->setCheckable(true); montageEnabledToolButton->setDefaultAction(m_montageEnabledAction); WuQtUtilities::setToolButtonStyleForQt5Mac(montageEnabledToolButton); m_montageEnabledAction->setObjectName(objectNamePrefix + "Enable"); WuQMacroManager::instance()->addMacroSupportToObject(m_montageEnabledAction, "Enable volume slice montage"); QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 0, 0); gridLayout->setVerticalSpacing(2); gridLayout->addWidget(rowsLabel, 0, 0); gridLayout->addWidget(m_montageRowsSpinBox, 0, 1); gridLayout->addWidget(columnsLabel, 1, 0); gridLayout->addWidget(m_montageColumnsSpinBox, 1, 1); gridLayout->addWidget(spacingLabel, 2, 0); gridLayout->addWidget(m_montageSpacingSpinBox, 2, 1); gridLayout->addWidget(decimalsLabel, 3, 0); gridLayout->addWidget(m_sliceCoordinatePrecisionSpinBox, 3, 1); gridLayout->addWidget(showSliceCoordToolButton, 4, 0); gridLayout->addWidget(montageEnabledToolButton, 4, 1); m_volumeMontageWidgetGroup = new WuQWidgetObjectGroup(this); m_volumeMontageWidgetGroup->add(m_montageRowsSpinBox); m_volumeMontageWidgetGroup->add(m_montageColumnsSpinBox); m_volumeMontageWidgetGroup->add(m_montageSpacingSpinBox); m_volumeMontageWidgetGroup->add(m_montageEnabledAction); m_volumeMontageWidgetGroup->add(m_showSliceCoordinateAction); m_volumeMontageWidgetGroup->add(m_sliceCoordinatePrecisionSpinBox); } /** * Destructor. */ BrainBrowserWindowToolBarVolumeMontage::~BrainBrowserWindowToolBarVolumeMontage() { } /** * Update the surface montage options widget. * * @param browserTabContent * The active model display controller (may be NULL). */ void BrainBrowserWindowToolBarVolumeMontage::updateContent(BrowserTabContent* browserTabContent) { m_volumeMontageWidgetGroup->blockAllSignals(true); switch (browserTabContent->getSliceDrawingType()) { case VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_MONTAGE: m_montageEnabledAction->setChecked(true); break; case VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE: m_montageEnabledAction->setChecked(false); break; } m_montageRowsSpinBox->setValue(browserTabContent->getMontageNumberOfRows()); m_montageColumnsSpinBox->setValue(browserTabContent->getMontageNumberOfColumns()); m_montageSpacingSpinBox->setValue(browserTabContent->getMontageSliceSpacing()); m_showSliceCoordinateAction->setChecked(browserTabContent->isVolumeMontageAxesCoordinatesDisplayed()); m_sliceCoordinatePrecisionSpinBox->setValue(browserTabContent->getVolumeMontageCoordinatePrecision()); m_volumeMontageWidgetGroup->blockAllSignals(false); } /** * Called when montage enabled button toggled. */ void BrainBrowserWindowToolBarVolumeMontage::montageEnabledActionToggled(bool) { VolumeSliceDrawingTypeEnum::Enum drawingType = VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_SINGLE; if (m_montageEnabledAction->isChecked()) { drawingType = VolumeSliceDrawingTypeEnum::VOLUME_SLICE_DRAW_MONTAGE; } BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->setSliceDrawingType(drawingType); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when montage rows spin box value is changed. */ void BrainBrowserWindowToolBarVolumeMontage::montageRowsSpinBoxValueChanged(int /*i*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->setMontageNumberOfRows(m_montageRowsSpinBox->value()); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when montage columns spin box value is changed. */ void BrainBrowserWindowToolBarVolumeMontage::montageColumnsSpinBoxValueChanged(int /*i*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->setMontageNumberOfColumns(m_montageColumnsSpinBox->value()); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when montage spacing spin box value is changed. */ void BrainBrowserWindowToolBarVolumeMontage::montageSpacingSpinBoxValueChanged(int /*i*/) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->setMontageSliceSpacing(m_montageSpacingSpinBox->value()); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when show slice coordinate tool button is clicked * * @param checked * New checked status */ void BrainBrowserWindowToolBarVolumeMontage::showSliceCoordinateToolButtonClicked(bool checked) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->setVolumeMontageAxesCoordinatesDisplayed(checked); this->updateGraphicsWindowAndYokedWindows(); } /** * Called when montage slice precision spin box value is changed. * * @param value * New value */ void BrainBrowserWindowToolBarVolumeMontage::slicePrecisionSpinBoxValueChanged(int value) { BrowserTabContent* btc = this->getTabContentFromSelectedTab(); btc->setVolumeMontageCoordinatePrecision(value); this->updateGraphicsWindowAndYokedWindows(); } connectome-workbench-1.4.2/src/GuiQt/BrainBrowserWindowToolBarVolumeMontage.h000066400000000000000000000055311360521144700274050ustar00rootroot00000000000000#ifndef __BRAIN_BROWSER_WINDOW_TOOL_BAR_VOLUME_MONTAGE_H__ #define __BRAIN_BROWSER_WINDOW_TOOL_BAR_VOLUME_MONTAGE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainBrowserWindowToolBarComponent.h" class QAction; class QCheckBox; class QSpinBox; namespace caret { class WuQWidgetObjectGroup; class BrainBrowserWindowToolBarVolumeMontage : public BrainBrowserWindowToolBarComponent { Q_OBJECT public: BrainBrowserWindowToolBarVolumeMontage(const QString& parentObjectName, BrainBrowserWindowToolBar* parentToolBar); virtual ~BrainBrowserWindowToolBarVolumeMontage(); virtual void updateContent(BrowserTabContent* browserTabContent); // ADD_NEW_METHODS_HERE private slots: void montageRowsSpinBoxValueChanged(int i); void montageColumnsSpinBoxValueChanged(int i); void montageSpacingSpinBoxValueChanged(int i); void montageEnabledActionToggled(bool); void showSliceCoordinateToolButtonClicked(bool); void slicePrecisionSpinBoxValueChanged(int); private: BrainBrowserWindowToolBarVolumeMontage(const BrainBrowserWindowToolBarVolumeMontage&); BrainBrowserWindowToolBarVolumeMontage& operator=(const BrainBrowserWindowToolBarVolumeMontage&); BrainBrowserWindowToolBar* m_parentToolBar; QSpinBox* m_montageRowsSpinBox; QSpinBox* m_montageColumnsSpinBox; QSpinBox* m_montageSpacingSpinBox; QAction* m_showSliceCoordinateAction; QSpinBox* m_sliceCoordinatePrecisionSpinBox; QAction* m_montageEnabledAction; WuQWidgetObjectGroup* m_volumeMontageWidgetGroup; // ADD_NEW_MEMBERS_HERE }; #ifdef __BRAIN_BROWSER_WINDOW_TOOL_BAR_VOLUME_MONTAGE_DECLARE__ // #endif // __BRAIN_BROWSER_WINDOW_TOOL_BAR_VOLUME_MONTAGE_DECLARE__ } // namespace #endif //__BRAIN_BROWSER_WINDOW_TOOL_BAR_VOLUME_MONTAGE_H__ connectome-workbench-1.4.2/src/GuiQt/BrainOpenGLWidget.cxx000066400000000000000000002530401360521144700234470ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __BRAIN_OPENGL_WIDGET_DEFINE__ #include "BrainOpenGLWidget.h" #undef __BRAIN_OPENGL_WIDGET_DEFINE__ #include #include #include #include #include #include #include #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET #endif #include #include #include #include "AnnotationManager.h" #include "Border.h" #include "Brain.h" #include "BrainBrowserWindow.h" #include "BrainOpenGLFixedPipeline.h" #include "BrainOpenGLShape.h" #include "BrainOpenGLViewportContent.h" #include "BrainStructure.h" #include "BrowserTabContent.h" #include "BrowserWindowContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPreferences.h" #include "CursorManager.h" #include "DataToolTipsManager.h" #include "DeveloperFlagsEnum.h" #include "DummyFontTextRenderer.h" #include "ElapsedTimer.h" #include "EventBrainReset.h" #include "EventImageCapture.h" #include "EventModelGetAll.h" #include "EventManager.h" #include "EventBrowserWindowDrawingContent.h" #include "EventBrowserWindowGraphicsRedrawn.h" #include "EventGraphicsTimingOneWindow.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventGetOrSetUserInputModeProcessor.h" #include "EventIdentificationRequest.h" #include "EventMovieManualModeRecording.h" #include "EventUserInterfaceUpdate.h" #include "FtglFontTextRenderer.h" #include "GuiManager.h" #include "ImageFile.h" #include "KeyEvent.h" #include "MathFunctions.h" #include "Matrix4x4.h" #include "Model.h" #include "MouseEvent.h" #include "MovieRecorder.h" #include "OffScreenOpenGLRenderer.h" #include "SelectionManager.h" #include "SelectionItemAnnotation.h" #include "SelectionItemSurfaceNode.h" #include "SelectionItemVoxelEditing.h" #include "SessionManager.h" #include "Surface.h" #include "TileTabsConfiguration.h" #include "UserInputModeAnnotations.h" #include "UserInputModeBorders.h" #include "UserInputModeFoci.h" #include "UserInputModeImage.h" #include "UserInputModeView.h" #include "UserInputModeVolumeEdit.h" #include "WuQMacroManager.h" #include "WuQMessageBox.h" using namespace caret; /** * Constructor. * * NOTE: We do not use "sharing" of textures and display lists * between windows. There are some issues with sharing and * recreation of OpenGL contexts such as when renderPixmap() * function is used. * * @param * The parent widget. * @param shareWidget * Widget used for sharing OpenGL contexts when the deprecated * QGLWidget is used. Note that with QOpenGLWidget, * sharing is enabled by calling QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts) * in desktop.cxx * @param windowIndex * Index of this window */ BrainOpenGLWidget::BrainOpenGLWidget(QWidget* parent, #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET const BrainOpenGLWidget* /*shareWidget*/, #else const BrainOpenGLWidget* shareWidget, #endif const int32_t windowIndex) #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET : QOpenGLWidget(parent), #else : QGLWidget(parent, shareWidget), #endif windowIndex(windowIndex) { setObjectName("Window_" + AString::number(windowIndex + 1) + ":OpenGLWidget"); this->borderBeingDrawn = new Border(); m_mousePositionValid = false; m_mousePositionEvent.grabNew(new MouseEvent(NULL, NULL, -1, 0, 0, 0, 0, 0, 0, false)); this->userInputAnnotationsModeProcessor = new UserInputModeAnnotations(windowIndex); this->userInputBordersModeProcessor = new UserInputModeBorders(this->borderBeingDrawn, windowIndex); this->userInputFociModeProcessor = new UserInputModeFoci(windowIndex); this->userInputImageModeProcessor = new UserInputModeImage(windowIndex); this->userInputVolumeEditModeProcessor = new UserInputModeVolumeEdit(windowIndex); this->userInputViewModeProcessor = new UserInputModeView(); this->selectedUserInputProcessor = this->userInputViewModeProcessor; this->selectedUserInputProcessor->initialize(); this->mousePressX = -10000; this->mousePressY = -10000; this->mouseNewDraggingStartedFlag = false; m_newKeyPressStartedFlag = true; /* * Mouse tracking must be on to receive mouse move events * when the mouse is NOT down. When this property is false * mouse move events are only received when the at least * one mouse button is down. */ setMouseTracking(true); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BRAIN_RESET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_TIMING_ONE_WINDOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GET_OR_SET_USER_INPUT_MODE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_IDENTIFICATION_REQUEST); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_IMAGE_CAPTURE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MOVIE_RECORDING_MANUAL_MODE_CAPTURE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); m_openGLContextSharingValid = true; #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET /* * Default format is set by desktop.cxx call to initializeDefaultGLFormat(). */ setFormat(QSurfaceFormat::defaultFormat()); #else /* * Test to see if OpenGL context sharing is valid. * If there is no sharingWidget, then this is the * first window opened. */ if (shareWidget != NULL) { if ( ! isSharing()) { m_openGLContextSharingValid = false; } } #endif // std::cout << "Share widget: " << std::hex << (uint64_t)shareWidget // << ", Context Pointer: " << std::hex << (uint64_t)context() // << ", Share Group: " << std::hex << (uint64_t)context()->contextHandle()->shareGroup() // << ", Sharing enabled: " << (isSharing() ? "Yes" : "No") // << std::endl; #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET /* Context is not yet valid for QOpenGLWidget */ m_contextShareGroupPointer = NULL; #else CaretAssert(context()); CaretAssert(context()->contextHandle()); m_contextShareGroupPointer = context()->contextHandle()->shareGroup(); CaretAssert(m_contextShareGroupPointer); #endif s_brainOpenGLWidgets.insert(this); } /** * Destructor. */ BrainOpenGLWidget::~BrainOpenGLWidget() { makeCurrent(); this->clearDrawingViewportContents(); delete this->userInputViewModeProcessor; delete this->userInputAnnotationsModeProcessor; delete this->userInputBordersModeProcessor; delete this->userInputFociModeProcessor; delete this->userInputImageModeProcessor; delete this->userInputVolumeEditModeProcessor; this->selectedUserInputProcessor = NULL; /* DO NOT DELETE since it does not own the object to which it points */ delete this->borderBeingDrawn; EventManager::get()->removeAllEventsFromListener(this); s_brainOpenGLWidgets.erase(this); if (s_brainOpenGLWidgets.empty()) { if (s_singletonOpenGL != NULL) { delete s_singletonOpenGL; s_singletonOpenGL = NULL; } } } /** * @return True if OpenGL Context Sharing is valid among * multiple graphics windows. * Note: If there is one window, we declare sharing valid. */ bool BrainOpenGLWidget::isOpenGLContextSharingValid() const { return m_openGLContextSharingValid; } /** * Initializes graphics. */ void BrainOpenGLWidget::initializeGL() { if (s_singletonOpenGL == NULL) { /* * OpenGL drawing will take ownership of the text renderer * and handle deletion of the text renderer. */ BrainOpenGLTextRenderInterface* textRenderer = NULL; #ifdef HAVE_FREETYPE textRenderer = new FtglFontTextRenderer(); if (! textRenderer->isValid()) { delete textRenderer; textRenderer = NULL; CaretLogWarning("Unable to create FTGL Font Renderer.\n" "No text will be available in graphics window."); } #else CaretLogWarning("Unable to create FTGL Font Renderer due to FreeType not found during configuration.\n" "No text will be available in graphics window."); #endif if (textRenderer == NULL) { textRenderer = new DummyFontTextRenderer(); } CaretAssert(textRenderer); s_singletonOpenGL = new BrainOpenGLFixedPipeline(textRenderer); } s_singletonOpenGL->initializeOpenGL(); this->lastMouseX = 0; this->lastMouseY = 0; this->isMousePressedNearToolBox = false; this->setFocusPolicy(Qt::StrongFocus); CaretLogConfig(getOpenGLInformation()); if (s_defaultGLFormatInitialized == false) { CaretLogSevere("PROGRAM ERROR: The default OpenGL has not been set.\n" "Need to call BrainOpenGLWidget::initializeDefaultGLFormat() prior to " "instantiating an instance of this class."); } } /** * @return Information about OpenGL. */ QString BrainOpenGLWidget::getOpenGLInformation() { AString info; #if QT_VERSION >= 0x050000 #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET info += ("Rendering with Qt5 QOpenGLWidget.\n"); #else info += ("Rendering with Qt5 QGLWidget (deprecated).\n"); #endif info += ("\n"); #endif #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET QSurfaceFormat format = this->format(); AString swapInfo("Swap Behavior: "); switch (format.swapBehavior()) { case QSurfaceFormat::DefaultSwapBehavior: swapInfo += ("DefaultSwapBehavior"); break; case QSurfaceFormat::SingleBuffer: swapInfo += ("SingleBuffer"); break; case QSurfaceFormat::DoubleBuffer: swapInfo += ("DoubleBuffer"); break; case QSurfaceFormat::TripleBuffer: swapInfo += ("TripleBuffer"); break; } info += ("QOpenGLWidget Context:" "\n Alpha: " + AString::fromBool(format.hasAlpha()) + "\n Alpha size: " + AString::number(format.alphaBufferSize()) + "\n Depth size: " + AString::number(format.depthBufferSize()) + "\n Red size: " + AString::number(format.redBufferSize()) + "\n Green size: " + AString::number(format.greenBufferSize()) + "\n Blue size: " + AString::number(format.blueBufferSize()) + "\n Samples size: " + AString::number(format.samples()) + "\n Stencil size: " + AString::number(format.stencilBufferSize()) + "\n " + swapInfo + "\n Swap Interval: " + AString::number(format.swapInterval()) + "\n Stereo: " + AString::fromBool(format.stereo()) + "\n Major Version: " + AString::number(format.majorVersion()) + "\n Minor Version: " + AString::number(format.minorVersion())); switch (format.profile()) { case QSurfaceFormat::NoProfile: info += ("\nOpenGL NoProfile - OpenGL version is lower than 3.2. For 3.2 and newer this is same as CoreProfile."); break; case QSurfaceFormat::CoreProfile: info += ("\nOpenGL CoreProfile - Functionality deprecated in OpenGL version 3.0 is not available."); break; case QSurfaceFormat::CompatibilityProfile: info += ("\nOpenGL CompatibilityProfile - Functionality from earlier OpenGL versions is available."); break; } #else QGLFormat format = this->format(); info += ("QGLWidget Context:" "\n Accum: " + AString::fromBool(format.accum()) + "\n Accum size: " + AString::number(format.accumBufferSize()) + "\n Alpha: " + AString::fromBool(format.alpha()) + "\n Alpha size: " + AString::number(format.alphaBufferSize()) + "\n Depth: " + AString::fromBool(format.depth()) + "\n Depth size: " + AString::number(format.depthBufferSize()) + "\n Direct Rendering: " + AString::fromBool(format.directRendering()) + "\n Red size: " + AString::number(format.redBufferSize()) + "\n Green size: " + AString::number(format.greenBufferSize()) + "\n Blue size: " + AString::number(format.blueBufferSize()) + "\n Double Buffer: " + AString::fromBool(format.doubleBuffer()) + "\n RGBA: " + AString::fromBool(format.rgba()) + "\n Samples: " + AString::fromBool(format.sampleBuffers()) + "\n Samples size: " + AString::number(format.samples()) + "\n Stencil: " + AString::fromBool(format.stencil()) + "\n Stencil size: " + AString::number(format.stencilBufferSize()) + "\n Swap Interval: " + AString::number(format.swapInterval()) + "\n Stereo: " + AString::fromBool(format.stereo()) + "\n Major Version: " + AString::number(format.majorVersion()) + "\n Minor Version: " + AString::number(format.minorVersion())); #endif info += ("\n\n" + s_singletonOpenGL->getOpenGLInformation()); #if BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS int32_t numDisplayLists = 0; for (GLuint iList = 1; iList < 1000; iList++) { if (glIsList(iList)) { numDisplayLists++; } } info += ("\nAt least " + AString::number(numDisplayLists) + " display lists are allocated in first OpenGL context."); #endif // BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS info += "\n"; return std::move(info); } /** * Called when widget is resized. */ void BrainOpenGLWidget::resizeGL(int w, int h) { this->windowWidth[this->windowIndex] = w; this->windowHeight[this->windowIndex] = h; } /** * @return Pointer to the border that is being drawn. */ Border* BrainOpenGLWidget::getBorderBeingDrawn() { return this->borderBeingDrawn; } /** * Clear the contents for drawing into the viewports. */ void BrainOpenGLWidget::clearDrawingViewportContents() { m_windowContent.clear(); } /** * Update the cursor from the active user input processor. */ void BrainOpenGLWidget::updateCursor() { /* * Set the cursor to that requested by the user input processor */ CursorEnum::Enum cursor = this->selectedUserInputProcessor->getCursor(); GuiManager::get()->getCursorManager()->setCursorForWidget(this, cursor); } /** * Perform experimental off screen image capture. */ QImage BrainOpenGLWidget::performOffScreenImageCapture(const int32_t imageWidth, const int32_t imageHeight) { makeCurrent(); QImage image; OffScreenOpenGLRenderer offscreen(this, imageWidth, imageHeight); if (offscreen.isError()) { WuQMessageBox::errorOk(this, offscreen.getErrorMessage()); doneCurrent(); return image; } const int32_t viewport[4] = { 0, 0, imageWidth, imageHeight }; BrainOpenGLWindowContent windowContent; getDrawingWindowContent(viewport, windowContent); s_singletonOpenGL->drawModels(this->windowIndex, this->selectedUserInputProcessor->getUserInputMode(), GuiManager::get()->getBrain(), m_contextShareGroupPointer, windowContent.getAllTabViewports()); if (offscreen.isError()) { WuQMessageBox::errorOk(this, offscreen.getErrorMessage()); doneCurrent(); return image; } return offscreen.getImage(); } /** * Get the content for drawing the window. * * @param windowViewport * Viewport of the window. * @param windowContent * Window content that is updated with window and its tabs. */ void BrainOpenGLWidget::getDrawingWindowContent(const int32_t windowViewportIn[4], BrainOpenGLWindowContent& windowContent) const { windowContent.clear(); BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(this->windowIndex); /* * When restoring scene, the first browser window may get closed. * This occurs when the user creates a scene that does not contain * the first browser window. The close() method in QWindow may not execute * destruction of the window so this widget may still be valid but * GuiManager no longer has a pointer to the window since it is being closed. * In this case, the window will be NULL. * * This problem is related to the moving window properties to the SessionManager, * in Feb 2018. */ if (bbw == NULL) { return; } EventBrowserWindowDrawingContent getModelEvent(this->windowIndex); EventManager::get()->sendEvent(getModelEvent.getPointer()); if (getModelEvent.isError()) { return; } int32_t windowViewport[4] = { windowViewportIn[0], windowViewportIn[1], windowViewportIn[2], windowViewportIn[3] }; if (bbw->isWindowAspectRatioLocked()) { const float aspectRatio = bbw->getAspectRatio(); if (aspectRatio > 0.0) { BrainOpenGLViewportContent::adjustViewportForAspectRatio(windowViewport, aspectRatio); } } /* * Highlighting of border points */ s_singletonOpenGL->setDrawHighlightedEndPoints(false); if (this->selectedUserInputProcessor == this->userInputBordersModeProcessor) { s_singletonOpenGL->setDrawHighlightedEndPoints(this->userInputBordersModeProcessor->isHighlightBorderEndPoints()); } const GapsAndMargins* gapsAndMargins = GuiManager::get()->getBrain()->getGapsAndMargins(); const int32_t numberOfTabs = getModelEvent.getNumberOfBrowserTabs(); std::vector allTabs; for (int32_t i = 0; i < numberOfTabs; i++) { allTabs.push_back(getModelEvent.getBrowserTab(i)); } BrowserWindowContent* browserWindowContent = getModelEvent.getBrowserWindowContent(); CaretAssert(browserWindowContent); if (browserWindowContent->isTileTabsEnabled() && (numberOfTabs > 1)) { const int32_t windowWidth = windowViewport[2]; const int32_t windowHeight = windowViewport[3]; std::vector rowHeights; std::vector columnsWidths; /* * Determine if default configuration for tiles */ TileTabsConfiguration* tileTabsConfiguration = browserWindowContent->getSelectedTileTabsConfiguration(); CaretAssert(tileTabsConfiguration); /* * Get the sizes of the tab tiles from the tile tabs configuration */ if (tileTabsConfiguration->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, windowHeight, numberOfTabs, browserWindowContent->getTileTabsConfigurationMode(), rowHeights, columnsWidths)) { /* * Create the viewport drawing contents for all tabs */ std::vector tabViewportContent = BrainOpenGLViewportContent::createViewportContentForTileTabs(allTabs, browserWindowContent, gapsAndMargins, windowViewport, this->windowIndex, getModelEvent.getTabIndexForTileTabsHighlighting()); for (auto tabvp : tabViewportContent) { windowContent.addTabViewport(tabvp); } } else { CaretLogSevere("Tile Tabs Row/Column sizing failed !!!"); } } else if (numberOfTabs >= 1) { BrainOpenGLViewportContent* vc = BrainOpenGLViewportContent::createViewportForSingleTab(allTabs, getModelEvent.getSelectedBrowserTabContent(), gapsAndMargins, this->windowIndex, windowViewport); windowContent.addTabViewport(vc); } std::vector emptyTabVector; BrainOpenGLViewportContent* windowViewportContent = BrainOpenGLViewportContent::createViewportForSingleTab(emptyTabVector, NULL, gapsAndMargins, windowIndex, windowViewport); windowContent.setWindowViewport(windowViewportContent); } /** * Paints the graphics. */ void BrainOpenGLWidget::paintGL() { #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET if (m_contextShareGroupPointer == NULL) { m_contextShareGroupPointer = context()->shareGroup(); CaretAssert(m_contextShareGroupPointer); } #endif updateCursor(); this->clearDrawingViewportContents(); const int windowViewport[4] = { 0, 0, this->windowWidth[this->windowIndex], this->windowHeight[this->windowIndex] }; getDrawingWindowContent(windowViewport, m_windowContent); if (this->selectedUserInputProcessor == userInputBordersModeProcessor) { s_singletonOpenGL->setBorderBeingDrawn(this->borderBeingDrawn); } else { s_singletonOpenGL->setBorderBeingDrawn(NULL); } s_singletonOpenGL->drawModels(this->windowIndex, this->selectedUserInputProcessor->getUserInputMode(), GuiManager::get()->getBrain(), m_contextShareGroupPointer, m_windowContent.getAllTabViewports()); /* * Issue browser window redrawn event */ BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(this->windowIndex); if (bbw != NULL) { EventManager::get()->sendEvent(EventBrowserWindowGraphicsRedrawn(bbw).getPointer()); } } /** * Override of event handling. */ bool BrainOpenGLWidget::event(QEvent* event) { if (SessionManager::get()->getDataToolTipsManager()->isEnabled()) { if (event->type() == QEvent::ToolTip) { QHelpEvent* helpEvent = static_cast(event); CaretAssert(helpEvent); QPoint globalXY = helpEvent->globalPos(); QPoint xyPoint = helpEvent->pos(); const int32_t x = xyPoint.x(); const int32_t y = this->height() - xyPoint.y(); DataToolTipsManager* dttm = SessionManager::get()->getDataToolTipsManager(); CaretAssert(dttm); AString toolTipText; const BrainOpenGLViewportContent* idViewport = this->getViewportContentAtXY(x, y); if (idViewport != NULL) { BrowserTabContent* browserTabContent = idViewport->getBrowserTabContent(); if (browserTabContent != NULL) { SelectionManager* selectionManager = performIdentification(x, y, false); // include items in background toolTipText = dttm->getToolTip(GuiManager::get()->getBrain(), browserTabContent, selectionManager); } } if (toolTipText.isEmpty()) { QToolTip::hideText(); event->ignore(); } else { const int millisecondsDisplayTime = (3 * 1000); QToolTip::showText(globalXY, toolTipText, nullptr, QRect(), millisecondsDisplayTime); } return true; } } #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET return QOpenGLWidget::event(event); #else return QGLWidget::event(event); #endif } /** * Receive Content Menu events from Qt. * @param contextMenuEvent * The context menu event. */ void BrainOpenGLWidget::contextMenuEvent(QContextMenuEvent* contextMenuEvent) { const int mouseX = contextMenuEvent->x(); const int mouseY = this->height() - contextMenuEvent->y(); const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, mouseY); if (viewportContent != NULL) { MouseEvent mouseEvent(viewportContent, this, this->windowIndex, mouseX, mouseY, 0, 0, mouseX, mouseY, false); this->selectedUserInputProcessor->showContextMenu(mouseEvent, contextMenuEvent->globalPos(), this); } } /** * Receive Mouse Wheel events from Qt. A wheel event is that same * as CTRL-LEFT-DRAG. The wheel's change in value is reported as * change in Y. Change in X is reported as zero. * * @param we * The wheel event. */ void BrainOpenGLWidget::wheelEvent(QWheelEvent* we) { /* * Notes 24 Sep 2019 * * QWheelEvent::pixelDelta() is not used since it is only set on Mac. * * Trackpad usage is when QWheelEvent::source()==Qt::MouseEventSynthesizedBySystem * Mouse usage is when QWheelEvent::source()==Qt::MouseEventNotSynthesized * * Inverted flag is only used by Mouse on MacOS. It is true when * Preferences->Trackpad->Scroll & Zoom is ON. The Wheel's inverted * flag is ignored since Mac alters the sign of the mouse Y-value. * It appears that "Scroll Direction:Natural is defaulted ON" on Macs * * Forward Wheel or Trackpad (moving away from user) * ** Negative when MacOS->Preferences->Trackpad->Scroll&Zoom->Scroll Direction:Natural is ON * ** Positive when MacOS->Preferences->Trackpad->Scroll&Zoom->Scroll Direction:Natural is OFF * ** Negative when MacOS->Preferences->Mouse->Scroll Direction:Natural is ON * ** Positive when MacOS->Preferences->Mouse->Scroll Direction:Natural is OFF * * ** Positive on Linux */ const QPoint angleDelta = we->angleDelta(); if (angleDelta.isNull()) { return; } int32_t deltaDegrees = angleDelta.y(); if (deltaDegrees == 0) { return; } /* * While the mouse/trackpad flags are not used at this time, * we also do not have access to a Linux or Windows system * with a trackpad. */ bool mouseFlag(false); bool trackpadFlag(false); switch (we->source()) { case Qt::MouseEventNotSynthesized: mouseFlag = true; break; case Qt::MouseEventSynthesizedByApplication: break; case Qt::MouseEventSynthesizedByQt: break; case Qt::MouseEventSynthesizedBySystem: trackpadFlag = true; break; } const bool debugFlag(false); if (debugFlag) { std::cout << "Angle Delta: " << we->angleDelta().y() << std::endl; std::cout << "Inverted: " << AString::fromBool(we->inverted()) << std::endl; std::cout << "Source: " << (int32_t)we->source() << std::endl; std::cout << "Mouse Flag: " << AString::fromBool(mouseFlag) << std::endl; std::cout << "Trackpad Flag: " << AString::fromBool(trackpadFlag) << std::endl; } /* * If not limited, it is way too fast */ const int limitValue(8); deltaDegrees = MathFunctions::limitRange(deltaDegrees, -limitValue, limitValue); /* * Use location of mouse press so that the model * being manipulated does not change if mouse moves * out of its viewport without releasing the mouse * button. */ const int wheelX = we->x(); const int wheelY = this->windowHeight[this->windowIndex] - we->y(); const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(wheelX, wheelY); if (viewportContent != NULL) { MouseEvent mouseEvent(viewportContent, this, this->windowIndex, wheelX, wheelY, 0, deltaDegrees, 0, 0, this->mouseNewDraggingStartedFlag); this->selectedUserInputProcessor->mouseLeftDragWithCtrl(mouseEvent); } we->accept(); } /* * A mouse event that is the middle mouse button but with no keys pressed * is reported as a SHIFT-LEFT-DRAG and the mouse event is changed. * * @param mouseButtons * Button state when event was generated * @param button * Button that caused the event. * @param keyModifiers * Keys that are down, may be modified. * @param isMouseMoving * True if mouse is moving, else false. */ void BrainOpenGLWidget::checkForMiddleMouseButton(Qt::MouseButtons& mouseButtons, Qt::MouseButton& button, Qt::KeyboardModifiers& keyModifiers, const bool isMouseMoving) { if (isMouseMoving) { if (button == Qt::NoButton) { if (mouseButtons == Qt::MiddleButton) { if (keyModifiers == Qt::NoModifier) { mouseButtons = Qt::LeftButton; button = Qt::NoButton; keyModifiers = Qt::ShiftModifier; } } } } else { if (button == Qt::MiddleButton) { if (keyModifiers == Qt::NoModifier) { button = Qt::LeftButton; keyModifiers = Qt::ShiftModifier; } } } } /** * Receive key press events from Qt. * @param e * The key event. */ void BrainOpenGLWidget::keyPressEvent(QKeyEvent* e) { Qt::KeyboardModifiers keyModifiers = e->modifiers(); const bool shiftKeyDownFlag = ((keyModifiers & Qt::ShiftModifier) != 0); KeyEvent keyEvent(this, this->windowIndex, e->key(), m_newKeyPressStartedFlag, shiftKeyDownFlag); const bool keyWasProcessedFlag = this->selectedUserInputProcessor->keyPressEvent(keyEvent); e->accept(); m_newKeyPressStartedFlag = false; if ( ! keyWasProcessedFlag) { #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET QOpenGLWidget::keyPressEvent(e); #else QGLWidget::keyPressEvent(e); #endif } } /** * Receive key release events from Qt. * @param e * The key event. */ void BrainOpenGLWidget::keyReleaseEvent(QKeyEvent* e) { m_newKeyPressStartedFlag = true; e->accept(); } /** * Receive mouse press events from Qt. * @param me * The mouse event. */ void BrainOpenGLWidget::mousePressEvent(QMouseEvent* me) { WuQMacroManager::instance()->addMouseEventToRecording(this, "Mouse Press in Window" + AString::number(this->windowIndex + 1), me); Qt::MouseButton button = me->button(); Qt::KeyboardModifiers keyModifiers = me->modifiers(); Qt::MouseButtons mouseButtons = me->buttons(); checkForMiddleMouseButton(mouseButtons, button, keyModifiers, false); /* * When the mouse is dragged, a mouse input receiver may want to * know that a new dragging has started. */ this->mouseNewDraggingStartedFlag = true; this->isMousePressedNearToolBox = false; if (button == Qt::LeftButton) { const int mouseX = me->x(); const int mouseY = this->windowHeight[this->windowIndex] - me->y(); this->mousePressX = mouseX; this->mousePressY = mouseY; this->lastMouseX = mouseX; this->lastMouseY = mouseY; this->mouseMovementMinimumX = mouseX; this->mouseMovementMaximumX = mouseX; this->mouseMovementMinimumY = mouseY; this->mouseMovementMaximumY = mouseY; /* * The user may intend to increase the size of a toolbox * but instead misses the edge of the toolbox when trying * to drag the toolbox and make it larger. So, indicate * when the user is very close to the edge of the graphics * window. */ const int nearToolBoxDistance = 5; if ((mouseX < nearToolBoxDistance) || (mouseX > (this->windowWidth[this->windowIndex] - 5)) || (mouseY < nearToolBoxDistance) || (mouseY > (this->windowHeight[this->windowIndex] - 5))) { this->isMousePressedNearToolBox = true; } const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, mouseY); if (viewportContent != NULL) { MouseEvent mouseEvent(viewportContent, this, this->windowIndex, mouseX, mouseY, 0, 0, this->mousePressX, this->mousePressY, this->mouseNewDraggingStartedFlag); if (keyModifiers == Qt::NoModifier) { this->selectedUserInputProcessor->mouseLeftPress(mouseEvent); } else if (keyModifiers == Qt::ShiftModifier) { /* not implemented this->selectedUserInputProcessor->mouseLeftPressWithShift(mouseEvent); */ } } } else { this->mousePressX = -10000; this->mousePressY = -10000; } me->accept(); } /** * Receive mouse button release events from Qt. * @param me * The mouse event. */ void BrainOpenGLWidget::mouseReleaseEvent(QMouseEvent* me) { WuQMacroManager::instance()->addMouseEventToRecording(this, "Mouse Release in Window" + AString::number(this->windowIndex + 1), me); Qt::MouseButton button = me->button(); Qt::KeyboardModifiers keyModifiers = me->modifiers(); Qt::MouseButtons mouseButtons = me->buttons(); checkForMiddleMouseButton(mouseButtons, button, keyModifiers, false); if (button == Qt::LeftButton) { const int mouseX = me->x(); const int mouseY = this->windowHeight[this->windowIndex] - me->y(); this->mouseMovementMinimumX = std::min(this->mouseMovementMinimumX, mouseX); this->mouseMovementMaximumX = std::max(this->mouseMovementMaximumX, mouseX); this->mouseMovementMinimumY = std::min(this->mouseMovementMinimumY, mouseY); this->mouseMovementMaximumY = std::max(this->mouseMovementMaximumY, mouseY); const int dx = this->mouseMovementMaximumX - this->mouseMovementMinimumX; const int dy = this->mouseMovementMaximumY - this->mouseMovementMinimumY; const int absDX = (dx >= 0) ? dx : -dx; const int absDY = (dy >= 0) ? dy : -dy; { /* * Mouse button RELEASE event */ const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, mouseY); if (viewportContent != NULL) { MouseEvent mouseEvent(viewportContent, this, this->windowIndex, mouseX, mouseY, 0, 0, this->mousePressX, this->mousePressY, this->mouseNewDraggingStartedFlag); this->selectedUserInputProcessor->mouseLeftRelease(mouseEvent); } } /* * Use location of mouse press so that the model * being manipulated does not change if mouse moves * out of its viewport without releasing the mouse * button. */ const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(this->mousePressX, this->mousePressY); if (viewportContent != NULL) { if ((absDX <= BrainOpenGLWidget::MOUSE_MOVEMENT_TOLERANCE) && (absDY <= BrainOpenGLWidget::MOUSE_MOVEMENT_TOLERANCE)) { MouseEvent mouseEvent(viewportContent, this, this->windowIndex, mouseX, mouseY, dx, dy, this->mousePressX, this->mousePressY, this->mouseNewDraggingStartedFlag); if (keyModifiers == Qt::NoModifier) { this->selectedUserInputProcessor->mouseLeftClick(mouseEvent); } else if (keyModifiers == Qt::ShiftModifier) { this->selectedUserInputProcessor->mouseLeftClickWithShift(mouseEvent); } else if (keyModifiers == (Qt::ShiftModifier | Qt::ControlModifier)) { this->selectedUserInputProcessor->mouseLeftClickWithCtrlShift(mouseEvent); } } } } this->mousePressX = -10000; this->mousePressY = -10000; this->isMousePressedNearToolBox = false; me->accept(); } /** * Receive mouse button double click events from Qt. * @param me * The mouse event. */ void BrainOpenGLWidget::mouseDoubleClickEvent(QMouseEvent* me) { WuQMacroManager::instance()->addMouseEventToRecording(this, "Mouse Double Click in Window" + AString::number(this->windowIndex + 1), me); Qt::MouseButton button = me->button(); Qt::KeyboardModifiers keyModifiers = me->modifiers(); Qt::MouseButtons mouseButtons = me->buttons(); checkForMiddleMouseButton(mouseButtons, button, keyModifiers, false); if (button == Qt::LeftButton) { if (keyModifiers == Qt::NoModifier) { const int mouseX = me->x(); const int mouseY = this->windowHeight[this->windowIndex] - me->y(); /* * Use location of mouse press so that the model * being manipulated does not change if mouse moves * out of its viewport without releasing the mouse * button. */ const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, mouseY); if (viewportContent != NULL) { MouseEvent mouseEvent(viewportContent, this, this->windowIndex, mouseX, mouseY, 0, 0, this->mousePressX, this->mousePressY, this->mouseNewDraggingStartedFlag); this->selectedUserInputProcessor->mouseLeftDoubleClick(mouseEvent); } } } this->isMousePressedNearToolBox = false; me->accept(); } void BrainOpenGLWidget::enterEvent(QEvent* /*e*/) { m_mousePositionValid = true; } void BrainOpenGLWidget::leaveEvent(QEvent* /*e*/) { m_mousePositionValid = false; this->selectedUserInputProcessor->setMousePosition(m_mousePositionEvent, m_mousePositionValid); } /** * Get the viewport content at the given location. * @param x * X-coordinate. * @param y * Y-coordinate. */ const BrainOpenGLViewportContent* BrainOpenGLWidget::getViewportContentAtXY(const int x, const int y) { const BrainOpenGLViewportContent* tabViewportContent = m_windowContent.getTabViewportWithLockAspectXY(x, y); if (tabViewportContent != NULL) { return tabViewportContent; } /* * If not in a tab, then use the window viewport information. * This allows selection of annotations in window space that are not * within a tab (tab may be small in height due to lock aspect). */ return m_windowContent.getWindowViewport(); } /** * Get all viewport content. If tile tabs is ON, the output will contain * viewport content for all tabs. Otherwise, the output will contain viewport * content for only the selected tab. * * @return Viewport content. */ std::vector BrainOpenGLWidget::getViewportContent() const { std::vector contentOut = m_windowContent.getAllTabViewports(); return contentOut; } /** * Perform identification on all items EXCEPT voxel editing. * * @param x * X-coordinate for identification. * @param y * Y-coordinate for identification. * @param applySelectionBackgroundFiltering * If true (which is in most cases), if there are multiple items * selected, those items "behind" other items are not reported. * For example, suppose a focus is selected and there is a node * the focus. If this parameter is true, the node will NOT be * selected. If this parameter is false, the node will be * selected. * @return * SelectionManager providing identification information. */ SelectionManager* BrainOpenGLWidget::performIdentification(const int x, const int y, const bool applySelectionBackgroundFiltering) { const BrainOpenGLViewportContent* idViewport = this->getViewportContentAtXY(x, y); this->makeCurrent(); CaretLogFine("Performing selection"); SelectionManager* idManager = GuiManager::get()->getBrain()->getSelectionManager(); idManager->reset(); idManager->setAllSelectionsEnabled(true); idManager->getVoxelEditingIdentification()->setEnabledForSelection(false); if (idViewport != NULL) { s_singletonOpenGL->selectModel(this->windowIndex, this->selectedUserInputProcessor->getUserInputMode(), GuiManager::get()->getBrain(), m_contextShareGroupPointer, idViewport, x, y, applySelectionBackgroundFiltering); } #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET /* * Note: The QOpenGLWidget always renders in a * frame buffer object (see its documentation) so * there is no "back" or "front buffer". Since * identification is encoded in the framebuffer, * it is necessary to repaint (udpates graphics * immediately) to redraw the models. Otherwise, * the graphics flash with strange looking drawing. */ this->repaintGraphics(); this->doneCurrent(); #else this->repaintGraphics(); #endif return idManager; } /** * Perform identification of only annotations. Identification of other * data types is off. * * @param x * X-coordinate for identification. * @param y * Y-coordinate for identification. * @return * A pointer to the annotation selection item. Its * "isValid()" method may be queried to determine * if the selected annotation is valid. */ SelectionItemAnnotation* BrainOpenGLWidget::performIdentificationAnnotations(const int x, const int y) { const BrainOpenGLViewportContent* idViewport = this->getViewportContentAtXY(x, y); this->makeCurrent(); CaretLogFine("Performing selection"); SelectionManager* idManager = GuiManager::get()->getBrain()->getSelectionManager(); idManager->reset(); idManager->setAllSelectionsEnabled(false); SelectionItemAnnotation* annotationID = idManager->getAnnotationIdentification(); annotationID->setEnabledForSelection(true); if (idViewport != NULL) { /* * ID coordinate needs to be relative to the viewport * int vp[4]; idViewport->getViewport(vp); const int idX = x - vp[0]; const int idY = y - vp[1]; */ s_singletonOpenGL->selectModel(this->windowIndex, this->selectedUserInputProcessor->getUserInputMode(), GuiManager::get()->getBrain(), m_contextShareGroupPointer, idViewport, x, y, true); } #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET /* * Note: The QOpenGLWidget always renders in a * frame buffer object (see its documentation) so * there is no "back" or "front buffer". Since * identification is encoded in the framebuffer, * it is necessary to repaint (udpates graphics * immediately) to redraw the models. Otherwise, * the graphics flash with strange looking drawing. */ this->repaintGraphics(); this->doneCurrent(); #else this->repaintGraphics(); #endif return annotationID; } /** * Perform identification of only voxel editing. Identification of other * data types is off. * * @param editingVolumeFile * Volume file that is being edited. * @param x * X-coordinate for identification. * @param y * Y-coordinate for identification. * @return * SelectionManager providing identification information. */ SelectionManager* BrainOpenGLWidget::performIdentificationVoxelEditing(VolumeFile* editingVolumeFile, const int x, const int y) { const BrainOpenGLViewportContent* idViewport = this->getViewportContentAtXY(x, y); this->makeCurrent(); CaretLogFine("Performing selection"); SelectionManager* idManager = GuiManager::get()->getBrain()->getSelectionManager(); idManager->reset(); idManager->setAllSelectionsEnabled(false); SelectionItemVoxelEditing* idVoxelEdit = idManager->getVoxelEditingIdentification(); idVoxelEdit->setEnabledForSelection(true); idVoxelEdit->setVolumeFileForEditing(editingVolumeFile); if (idViewport != NULL) { /* * ID coordinate needs to be relative to the viewport * int vp[4]; idViewport->getViewport(vp); const int idX = x - vp[0]; const int idY = y - vp[1]; */ s_singletonOpenGL->selectModel(this->windowIndex, this->selectedUserInputProcessor->getUserInputMode(), GuiManager::get()->getBrain(), m_contextShareGroupPointer, idViewport, x, y, true); } #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET /* * Note: The QOpenGLWidget always renders in a * frame buffer object (see its documentation) so * there is no "back" or "front buffer". Since * identification is encoded in the framebuffer, * it is necessary to repaint (udpates graphics * immediately) to redraw the models. Otherwise, * the graphics flash with strange looking drawing. */ this->repaintGraphics(); this->doneCurrent(); #else this->repaintGraphics(); #endif return idManager; } /** * Project the given item to a model. * * @param x * X-coordinate for projection. * @param y * Y-coordinate for projection. * @param projectionOut * Projection updated for the given x and y coordinates. */ void BrainOpenGLWidget::performProjection(const int x, const int y, SurfaceProjectedItem& projectionOut) { const BrainOpenGLViewportContent* projectionViewport = this->getViewportContentAtXY(x, y); this->makeCurrent(); CaretLogFine("Performing projection"); if (projectionViewport != NULL) { s_singletonOpenGL->projectToModel(this->windowIndex, this->selectedUserInputProcessor->getUserInputMode(), GuiManager::get()->getBrain(), m_contextShareGroupPointer, projectionViewport, x, y, projectionOut); } #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET /* * Note: The QOpenGLWidget always renders in a * frame buffer object (see its documentation) so * there is no "back" or "front buffer". Since * identification is encoded in the framebuffer, * it is necessary to repaint (udpates graphics * immediately) to redraw the models. Otherwise, * the graphics flash with strange looking drawing. */ this->repaintGraphics(); this->doneCurrent(); #endif } /** * Receive mouse move events from Qt. * @param me * The mouse event. */ void BrainOpenGLWidget::mouseMoveEvent(QMouseEvent* me) { WuQMacroManager::instance()->addMouseEventToRecording(this, "Mouse Move in Window" + AString::number(this->windowIndex + 1), me); /* * Tooltip will remain displayed for several seconds. * So if the user moves the mouse, remove the tooltip. */ QToolTip::hideText(); Qt::MouseButton button = me->button(); Qt::KeyboardModifiers keyModifiers = me->modifiers(); Qt::MouseButtons mouseButtons = me->buttons(); checkForMiddleMouseButton(mouseButtons, button, keyModifiers, true); const int mouseX = me->x(); const int mouseY = this->windowHeight[this->windowIndex] - me->y(); if (mouseButtons == Qt::LeftButton) { this->mouseMovementMinimumX = std::min(this->mouseMovementMinimumX, mouseX); this->mouseMovementMaximumX = std::max(this->mouseMovementMaximumX, mouseX); this->mouseMovementMinimumY = std::min(this->mouseMovementMinimumY, mouseY); this->mouseMovementMaximumY = std::max(this->mouseMovementMaximumY, mouseY); const int dx = mouseX - this->lastMouseX; const int dy = mouseY - this->lastMouseY; const int absDX = (dx >= 0) ? dx : -dx; const int absDY = (dy >= 0) ? dy : -dy; if ((absDX > 0) || (absDY > 0)) { /* * Use location of mouse press so that the model * being manipulated does not change if mouse moves * out of its viewport without releasing the mouse * button. */ const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(this->mousePressX, this->mousePressY); if (viewportContent != NULL) { MouseEvent mouseEvent(viewportContent, this, this->windowIndex, mouseX, mouseY, dx, dy, this->mousePressX, this->mousePressY, this->mouseNewDraggingStartedFlag); if (keyModifiers == Qt::NoModifier) { this->selectedUserInputProcessor->mouseLeftDrag(mouseEvent); } else if (keyModifiers == Qt::ControlModifier) { this->selectedUserInputProcessor->mouseLeftDragWithCtrl(mouseEvent); } else if (keyModifiers == Qt::ShiftModifier) { this->selectedUserInputProcessor->mouseLeftDragWithShift(mouseEvent); } else if (keyModifiers == Qt::AltModifier) { this->selectedUserInputProcessor->mouseLeftDragWithAlt(mouseEvent); } else if (keyModifiers == (Qt::ShiftModifier | Qt::ControlModifier)) { this->selectedUserInputProcessor->mouseLeftDragWithCtrlShift(mouseEvent); } this->mouseNewDraggingStartedFlag = false; } } this->lastMouseX = mouseX; this->lastMouseY = mouseY; } else if (mouseButtons == Qt::NoButton) { const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, mouseY); if (viewportContent != NULL) { MouseEvent mouseEvent(viewportContent, this, this->windowIndex, mouseX, mouseY, 0, 0, this->mousePressX, this->mousePressY, this->mouseNewDraggingStartedFlag); if (keyModifiers == Qt::NoModifier) { this->selectedUserInputProcessor->mouseMove(mouseEvent); } else if (keyModifiers == Qt::ShiftModifier) { this->selectedUserInputProcessor->mouseMoveWithShift(mouseEvent); } } } const BrainOpenGLViewportContent* viewportContent = this->getViewportContentAtXY(mouseX, mouseY); if (viewportContent != NULL) { m_mousePositionEvent.grabNew(new MouseEvent(viewportContent, this, this->windowIndex, mouseX, mouseY, 0, 0, this->mousePressX, this->mousePressY, this->mouseNewDraggingStartedFlag)); this->selectedUserInputProcessor->setMousePosition(m_mousePositionEvent, m_mousePositionValid); } else { } me->accept(); } /** * Receive events from the event manager. * * @param event * Event sent by event manager. */ void BrainOpenGLWidget::receiveEvent(Event* event) { MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); MovieRecorderModeEnum::Enum movieRecordingMode = movieRecorder->getRecordingMode(); bool doRepaintGraphicsFlag(false); bool doUpdateGraphicsFlag(false); int32_t captureManualMovieModeImageRepeatCount(-1); if (event->getEventType() == EventTypeEnum::EVENT_BRAIN_RESET) { EventBrainReset* brainResetEvent = dynamic_cast(event); CaretAssert(brainResetEvent); this->borderBeingDrawn->clear(); brainResetEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_TIMING_ONE_WINDOW) { EventGraphicsTimingOneWindow* timingEvent = dynamic_cast(event); CaretAssert(timingEvent); if (timingEvent->getWindowIndex() == this->windowIndex) { doRepaintGraphicsFlag = true; timingEvent->setEventProcessed(); } } else if (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS) { EventGraphicsUpdateAllWindows* updateAllEvent = dynamic_cast(event); CaretAssert(updateAllEvent); updateAllEvent->setEventProcessed(); if (updateAllEvent->isRepaint()) { doRepaintGraphicsFlag = true; } else { doUpdateGraphicsFlag = true; } } else if (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW) { EventGraphicsUpdateOneWindow* updateOneEvent = dynamic_cast(event); CaretAssert(updateOneEvent); if (updateOneEvent->getWindowIndex() == this->windowIndex) { updateOneEvent->setEventProcessed(); doUpdateGraphicsFlag = true; } else { /* * If a window is yoked, update its graphics. */ EventBrowserWindowDrawingContent getModelEvent(this->windowIndex); EventManager::get()->sendEvent(getModelEvent.getPointer()); if (getModelEvent.isError()) { return; } bool needUpdate = false; if (needUpdate) { doUpdateGraphicsFlag = true; } } } else if (event->getEventType() == EventTypeEnum::EVENT_GET_OR_SET_USER_INPUT_MODE) { EventGetOrSetUserInputModeProcessor* inputModeEvent = dynamic_cast(event); CaretAssert(inputModeEvent); if (inputModeEvent->getWindowIndex() == this->windowIndex) { if (inputModeEvent->isGetUserInputMode()) { inputModeEvent->setUserInputProcessor(this->selectedUserInputProcessor); } else if (inputModeEvent->isSetUserInputMode()) { UserInputModeAbstract* newUserInputProcessor = NULL; switch (inputModeEvent->getUserInputMode()) { case UserInputModeEnum::INVALID: CaretAssertMessage(0, "INVALID is NOT allowed for user input mode"); break; case UserInputModeEnum::ANNOTATIONS: newUserInputProcessor = this->userInputAnnotationsModeProcessor; break; case UserInputModeEnum::BORDERS: newUserInputProcessor = this->userInputBordersModeProcessor; break; case UserInputModeEnum::FOCI: newUserInputProcessor = this->userInputFociModeProcessor; break; case UserInputModeEnum::IMAGE: newUserInputProcessor = this->userInputImageModeProcessor; break; case UserInputModeEnum::VOLUME_EDIT: newUserInputProcessor = this->userInputVolumeEditModeProcessor; break; case UserInputModeEnum::VIEW: newUserInputProcessor = this->userInputViewModeProcessor; break; } if ((newUserInputProcessor == this->userInputAnnotationsModeProcessor) || (this->selectedUserInputProcessor == this->userInputAnnotationsModeProcessor)) { AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); CaretAssert(annMan); annMan->deselectAllAnnotationsForEditing(this->windowIndex); } if (newUserInputProcessor != NULL) { if (newUserInputProcessor != this->selectedUserInputProcessor) { this->selectedUserInputProcessor->finish(); this->selectedUserInputProcessor = newUserInputProcessor; this->selectedUserInputProcessor->initialize(); } } } inputModeEvent->setEventProcessed(); } } else if (event->getEventType() == EventTypeEnum::EVENT_IMAGE_CAPTURE) { EventImageCapture* imageCaptureEvent = dynamic_cast(event); CaretAssert(imageCaptureEvent); if (imageCaptureEvent->getBrowserWindowIndex() == this->windowIndex) { captureImage(imageCaptureEvent); imageCaptureEvent->setEventProcessed(); } } else if (event->getEventType() == EventTypeEnum::EVENT_IDENTIFICATION_REQUEST) { EventIdentificationRequest* idRequestEvent = dynamic_cast(event); CaretAssert(idRequestEvent); if (idRequestEvent->getWindowIndex() == this->windowIndex) { SelectionManager* sm = performIdentification(idRequestEvent->getWindowX(), idRequestEvent->getWindowY(), false); idRequestEvent->setSelectionManager(sm); idRequestEvent->setEventProcessed(); } } else if (event->getEventType() == EventTypeEnum::EVENT_MOVIE_RECORDING_MANUAL_MODE_CAPTURE) { EventMovieManualModeRecording* movieEvent = dynamic_cast(event); CaretAssert(movieEvent); const int32_t windowIndex = movieEvent->getBrowserWindowIndex(); if ((windowIndex < 0) || (windowIndex == this->windowIndex)) { /* * Movie mode may be automatic but override with manual * so that images are captured */ movieRecordingMode = MovieRecorderModeEnum::MANUAL; const float durationSeconds = movieEvent->getDurationSeconds(); const float frameRate = movieRecorder->getFramesRate(); captureManualMovieModeImageRepeatCount = static_cast(frameRate * durationSeconds); if (captureManualMovieModeImageRepeatCount < 1) { captureManualMovieModeImageRepeatCount = 1; } doRepaintGraphicsFlag = true; movieEvent->setEventProcessed(); } } else if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* guiUpdateEvent = dynamic_cast(event); CaretAssert(guiUpdateEvent); guiUpdateEvent->setEventProcessed(); this->selectedUserInputProcessor->update(); } else { } if (doRepaintGraphicsFlag || doUpdateGraphicsFlag) { bool captureAutomaticImageForMovieFlag(false); if (movieRecorder->getRecordingWindowIndex() == this->windowIndex) { switch (movieRecordingMode) { case MovieRecorderModeEnum::MANUAL: break; case MovieRecorderModeEnum::AUTOMATIC: captureAutomaticImageForMovieFlag = true; doRepaintGraphicsFlag = true; break; } } if (doRepaintGraphicsFlag) { repaintGraphics(); if (captureAutomaticImageForMovieFlag || (captureManualMovieModeImageRepeatCount > 0)) { const bool showTimingResultFlag(false); int captureRegionOffsetX(0); int captureRegionOffsetY(0); int captureRegionWidth(0); int captureRegionHeight(0); int widgetWidth(0); int widgetHeight(0); BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->windowIndex); if (browserWindow != NULL) { browserWindow->getGraphicsWidgetSize(captureRegionOffsetX, captureRegionOffsetY, captureRegionWidth, captureRegionHeight, widgetWidth, widgetHeight, true); int outputImageWidth(0); int outputImageHeight(0); movieRecorder->getVideoWidthAndHeight(outputImageWidth, outputImageHeight); AString msg; if ((outputImageWidth <= 0) || (outputImageHeight <= 0)) { msg.appendWithNewLine("Movie width=" + AString::number(outputImageWidth) + ", height=" + AString::number(outputImageHeight) + " is invalid."); } if ((captureRegionWidth <= 0) || (captureRegionHeight <= 0)) { msg.appendWithNewLine("Movie capture region width=" + AString::number(captureRegionWidth) + ", height=" + AString::number(captureRegionHeight) + " is invalid."); } if ( ! msg.isEmpty()) { CaretLogSevere(msg); } else { QImage image; bool imageValid(false); switch (movieRecorder->getCaptureRegionType()) { case MovieRecorderCaptureRegionTypeEnum::GRAPHICS: { bool adjustImageSizeFlag(false); int captureWidth = outputImageWidth; int captureHeight = outputImageHeight; if ((captureWidth != captureRegionWidth) || (captureHeight != captureRegionHeight)) { const float outputAspectRatio = (outputImageHeight / outputImageWidth); const float captureRegionAspectRatio = (captureRegionHeight / captureRegionWidth); if (captureRegionAspectRatio > outputAspectRatio) { const float ratio = outputImageHeight / captureRegionHeight; captureWidth = outputImageWidth * ratio; captureHeight = outputImageHeight; } else { const float ratio = outputImageWidth / captureRegionWidth; captureHeight = outputImageHeight * ratio; captureWidth = outputImageWidth; } adjustImageSizeFlag = true; } ElapsedTimer timer; timer.start(); EventImageCapture captureEvent(this->windowIndex, captureRegionOffsetX, captureRegionOffsetY, captureRegionWidth, captureRegionHeight, captureWidth, captureHeight); captureImage(&captureEvent); if (showTimingResultFlag) { std::cout << "Capture time: " << timer.getElapsedTimeSeconds() << std::endl; } if (captureEvent.isError()) { CaretLogSevere("Failed to capture image of graphics for movie recording"); } else { image = captureEvent.getImage(); imageValid = true; if (adjustImageSizeFlag) { QImage scaledImage = ImageFile::scaleToSizeWithPadding(image, outputImageWidth, outputImageHeight); if (scaledImage.isNull()) { CaretLogSevere("Failed to scale image for movie recording"); } else { image = scaledImage; } } } } break; case MovieRecorderCaptureRegionTypeEnum::WINDOW: { BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(this->windowIndex); QRect rect(0, 0, bbw->width(), bbw->height()); QPixmap pm = bbw->grab(rect); if ((pm.width() > 0) && (pm.height() > 0)) { image = pm.toImage(); imageValid = true; QImage scaledImage = ImageFile::scaleToSizeWithPadding(image, outputImageWidth, outputImageHeight); if (scaledImage.isNull()) { CaretLogSevere("Failed to scale image for movie recording"); } else { image = scaledImage; } } else { CaretLogSevere("Failed to capture image of window"); } } break; } if (imageValid) { ElapsedTimer imageTimer; imageTimer.start(); if (captureAutomaticImageForMovieFlag) { movieRecorder->addImageToMovie(&image); } else if (captureManualMovieModeImageRepeatCount > 0) { movieRecorder->addImageToMovieWithCopies(&image, captureManualMovieModeImageRepeatCount); } if (showTimingResultFlag) { std::cout << " Image write time: " << imageTimer.getElapsedTimeSeconds() << std::endl; } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_MOVIE_RECORDING_DIALOG_UPDATE); } } } } } else if (doUpdateGraphicsFlag) { #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET this->update(); #else this->updateGL(); #endif } } } /** * Perform an immediate repaint of the graphics */ void BrainOpenGLWidget::repaintGraphics() { repaint(); #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET /* * As of QT 5.12.0. * * When using QOpenGLWidget, calling repaint() returns before * it calls paintGL() so graphics are not updated even though * the documentation states that drawing will complete during * the call to repaint(). Essentially, repaint() functions * the same as update(). * * Two Qt bug reports have been submitted by others: * QTBUG-74404, QTBUG-53107. * * A previous kludge to fix this problem made a call to * QApplication::processEvents(). However, it was found * to cause a problem with annotation dragging as multiple * mouse events were getting issued. * Commit: 666b0e7c3d8d443aa9668a5cff986f7b83158488 * * Now, the kludge is to call grabFramebuffer() which I * assume has to complete drawing before capturing an * image. This fixes the problem with dragging annotations. */ (void)grabFramebuffer(); #endif } /** * Capture an image using the parameters from the event. * * @param imageCaptureEvent * The image capture event. */ void BrainOpenGLWidget::captureImage(EventImageCapture* imageCaptureEvent) { const int oldSizeX = this->windowWidth[this->windowIndex]; const int oldSizeY = this->windowHeight[this->windowIndex]; /* * Note that a size of zero indicates capture graphics in its * current size. */ int captureOffsetX = imageCaptureEvent->getCaptureOffsetX(); int captureOffsetY = imageCaptureEvent->getCaptureOffsetY(); int captureWidth = imageCaptureEvent->getCaptureWidth(); int captureHeight = imageCaptureEvent->getCaptureHeight(); int outputImageWidth = imageCaptureEvent->getOutputWidth(); int outputImageHeight = imageCaptureEvent->getOutputHeight(); if ((outputImageWidth <= 0) || (outputImageHeight <= 0)) { BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->windowIndex); if (browserWindow != NULL) { int32_t widgetWidth(0), widgetHeight(0); browserWindow->getGraphicsWidgetSize(captureOffsetX, captureOffsetY, captureWidth, captureHeight, widgetWidth, widgetHeight, true); /* true => apply lock aspect ratio */ outputImageWidth = captureWidth; outputImageHeight = captureHeight; } } /* * Disable tab highlighting when capturing images */ BrainOpenGL::setAllowTabHighlighting(false); /* * Force immediate mode since problems with display lists * in image capture. */ BrainOpenGLShape::setImmediateModeOverride(true); QImage image; const CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); const ImageCaptureMethodEnum::Enum imageCaptureMethod = prefs->getImageCaptureMethod(); switch (imageCaptureMethod) { case ImageCaptureMethodEnum::IMAGE_CAPTURE_WITH_GRAB_FRAME_BUFFER: { /* * Grab frame buffer seems to have a bug in that it grabs * the previous buffer on Mac so repaint to ensure frame * buffer is updated. (repaint() updates immediately, * update() is a scheduled update). */ repaintGraphics(); #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET image = grabFramebuffer(); #else image = grabFrameBuffer(); #endif if ((captureWidth > 0) && (captureHeight > 0)) { image = image.copy(captureOffsetX, captureOffsetY, captureWidth, captureHeight); } if ((outputImageWidth != image.width()) || (outputImageHeight != image.height())) { image = image.scaled(outputImageWidth, outputImageHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } } break; case ImageCaptureMethodEnum::IMAGE_CAPTURE_WITH_RENDER_PIXMAP: { #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET WuQMessageBox::errorOk(this, "Render PixMap not implemented with Qt5"); #else /* * When the user chooses to exclude regions * caused by locking of tab/window aspect ratio, * the pixmap is rendered to the output width and * height and in the correct aspect ratio so when * the rendering takes place, there is no empty * region caused by aspect locking that needs to * be excluded. */ QPixmap pixmap = this->renderPixmap(outputImageWidth, outputImageHeight, true); image = pixmap.toImage(); #endif } break; case ImageCaptureMethodEnum::IMAGE_CAPTURE_WITH_OFFSCREEN_FRAME_BUFFER: { image = performOffScreenImageCapture(outputImageWidth, outputImageHeight); } break; } if ((image.size().width() <= 0) || (image.size().height() <= 0)) { imageCaptureEvent->setErrorMessage("Image capture appears to have failed (invalid size)."); } else { imageCaptureEvent->setImage(image); uint8_t backgroundColor[3]; s_singletonOpenGL->getBackgroundColor(backgroundColor); imageCaptureEvent->setBackgroundColor(backgroundColor); } BrainOpenGLShape::setImmediateModeOverride(false); BrainOpenGL::setAllowTabHighlighting(true); this->resizeGL(oldSizeX, oldSizeY); } /** * Initialize the OpenGL format. This must be called * prior to initializing an instance of this class so * that the OpenGL is setup properly. */ void BrainOpenGLWidget::initializeDefaultGLFormat() { #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET QSurfaceFormat glfmt; glfmt.setAlphaBufferSize(8); glfmt.setBlueBufferSize(8); glfmt.setDepthBufferSize(24); glfmt.setGreenBufferSize(8); glfmt.setProfile(QSurfaceFormat::CompatibilityProfile); glfmt.setRedBufferSize(8); glfmt.setRenderableType(QSurfaceFormat::OpenGL); /* * Values greater than zero for setSamples() cause an OpenGL error in * glReadPixels(). * QtBug-43127 */ glfmt.setSamples(0); //6); glfmt.setStereo(false); glfmt.setSwapBehavior(QSurfaceFormat::DoubleBuffer); glfmt.setMajorVersion(2); glfmt.setMinorVersion(1); QSurfaceFormat::setDefaultFormat(glfmt); #else QGLFormat glfmt; glfmt.setAccum(false); glfmt.setAlpha(true); glfmt.setAlphaBufferSize(8); glfmt.setDepth(true); glfmt.setDepthBufferSize(24); glfmt.setDirectRendering(true); glfmt.setDoubleBuffer(true); glfmt.setOverlay(false); glfmt.setProfile(QGLFormat::CompatibilityProfile); glfmt.setVersion(2, 1); glfmt.setSampleBuffers(true); glfmt.setStencil(false); glfmt.setStereo(false); glfmt.setRgba(true); glfmt.setRedBufferSize(8); glfmt.setGreenBufferSize(8); glfmt.setBlueBufferSize(8); QGLFormat::setDefaultFormat(glfmt); #endif s_defaultGLFormatInitialized = true; } /** * Process a mouse event from the macro system. * * @param me * The mouse event */ void BrainOpenGLWidget::processMouseEventFromMacro(QMouseEvent* me) { m_mousePositionValid = true; switch (me->type()) { case QEvent::MouseButtonDblClick: mouseDoubleClickEvent(me); break; case QEvent::MouseButtonPress: mousePressEvent(me); break; case QEvent::MouseButtonRelease: mouseReleaseEvent(me); break; case QEvent::MouseMove: mouseMoveEvent(me); break; default: CaretAssert(0); break; } m_mousePositionValid = false; } connectome-workbench-1.4.2/src/GuiQt/BrainOpenGLWidget.h000066400000000000000000000172671360521144700231050ustar00rootroot00000000000000 #ifndef __BRAIN_OPENGL_WIDGET_H__ #define __BRAIN_OPENGL_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include /* * When GLEW is used, CaretOpenGLInclude.h will include "Gl/glew.h". * Gl/glew.h MUST BE BEFORE Gl/gl.h and Gl/gl.h is included by * QGLWidget so, we must include CaretOpenGL.h before QGLWidget. */ #include "CaretOpenGLInclude.h" #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET #include #else #include #endif #include #include #include "BrainConstants.h" #include "BrainOpenGLWindowContent.h" #include "CaretPointer.h" #include "EventListenerInterface.h" #include "WuQMacroMouseEventWidgetInterface.h" class QMouseEvent; class QWidget; namespace caret { class Border; class BrainOpenGL; class BrainOpenGLViewportContent; class BrowserTabContent; class EventImageCapture; class SelectionItemAnnotation; class SelectionManager; class Model; class MouseEvent; class SurfaceProjectedItem; class UserInputModeAnnotations; class UserInputModeBorders; class UserInputModeFoci; class UserInputModeImage; class UserInputModeView; class UserInputModeVolumeEdit; class UserInputModeAbstract; class VolumeFile; #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET class BrainOpenGLWidget : public QOpenGLWidget, public EventListenerInterface, public WuQMacroMouseEventWidgetInterface { #else class BrainOpenGLWidget : public QGLWidget, public EventListenerInterface, public WuQMacroMouseEventWidgetInterface { #endif Q_OBJECT public: BrainOpenGLWidget(QWidget* parent, const BrainOpenGLWidget* shareWidget, const int32_t windowIndex); ~BrainOpenGLWidget(); void receiveEvent(Event* event); SelectionManager* performIdentification(const int x, const int y, const bool applySelectionBackgroundFiltering); SelectionItemAnnotation* performIdentificationAnnotations(const int x, const int y); SelectionManager* performIdentificationVoxelEditing(VolumeFile* editingVolumeFile, const int x, const int y); void performProjection(const int x, const int y, SurfaceProjectedItem& projectionOut); Border* getBorderBeingDrawn(); static void initializeDefaultGLFormat(); QString getOpenGLInformation(); void updateCursor(); std::vector getViewportContent() const; bool isOpenGLContextSharingValid() const; QImage performOffScreenImageCapture(const int32_t imageWidth, const int32_t imageHeight); virtual void processMouseEventFromMacro(QMouseEvent* me) override; protected: virtual void initializeGL(); virtual void resizeGL(int w, int h); virtual void paintGL(); virtual void contextMenuEvent(QContextMenuEvent* contextMenuEvent); virtual bool event(QEvent* event); virtual void keyPressEvent(QKeyEvent* e); virtual void keyReleaseEvent(QKeyEvent* e); virtual void mouseDoubleClickEvent(QMouseEvent* e); virtual void mouseMoveEvent(QMouseEvent* e); virtual void mousePressEvent(QMouseEvent* e); virtual void mouseReleaseEvent(QMouseEvent* e); virtual void wheelEvent(QWheelEvent* e); virtual void enterEvent(QEvent* e); virtual void leaveEvent(QEvent* e); private: std::vector getDrawingViewportContent(const int32_t windowViewportIn[4]) const; void getDrawingWindowContent(const int32_t windowViewportIn[4], BrainOpenGLWindowContent& windowContent) const; void clearDrawingViewportContents(); const BrainOpenGLViewportContent* getViewportContentAtXY(const int x, const int y); void checkForMiddleMouseButton(Qt::MouseButtons& mouseButtons, Qt::MouseButton& button, Qt::KeyboardModifiers& keyModifiers, const bool isMouseMoving); void captureImage(EventImageCapture* imageCaptureEvent); void repaintGraphics(); const int32_t windowIndex; BrainOpenGLWindowContent m_windowContent; int32_t windowWidth[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS]; int32_t windowHeight[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS]; int32_t mouseMovementMinimumX; int32_t mouseMovementMaximumX; int32_t mouseMovementMinimumY; int32_t mouseMovementMaximumY; bool mouseNewDraggingStartedFlag; static const int32_t MOUSE_MOVEMENT_TOLERANCE; int mousePressX; int mousePressY; bool isMousePressedNearToolBox; int lastMouseX; int lastMouseY; bool m_newKeyPressStartedFlag; UserInputModeAbstract* selectedUserInputProcessor; UserInputModeAnnotations* userInputAnnotationsModeProcessor; UserInputModeView* userInputViewModeProcessor; UserInputModeBorders* userInputBordersModeProcessor; UserInputModeFoci* userInputFociModeProcessor; UserInputModeImage* userInputImageModeProcessor; UserInputModeVolumeEdit* userInputVolumeEditModeProcessor; Border* borderBeingDrawn; bool m_mousePositionValid; CaretPointer m_mousePositionEvent; bool m_openGLContextSharingValid = false; void* m_contextShareGroupPointer = NULL; static bool s_defaultGLFormatInitialized; static std::set s_brainOpenGLWidgets; static BrainOpenGL* s_singletonOpenGL; }; #ifdef __BRAIN_OPENGL_WIDGET_DEFINE__ const int32_t BrainOpenGLWidget::MOUSE_MOVEMENT_TOLERANCE = 0; bool BrainOpenGLWidget::s_defaultGLFormatInitialized = false; std::set BrainOpenGLWidget::s_brainOpenGLWidgets; BrainOpenGL* BrainOpenGLWidget::s_singletonOpenGL = NULL; #endif // __BRAIN_OPENGL_WIDGET_DEFINE__ } // namespace #endif // __BRAIN_OPENGL_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/BugReportDialog.cxx000066400000000000000000000176461360521144700232460ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #define __BUG_REPORT_DIALOG_DECLARE__ #include "BugReportDialog.h" #undef __BUG_REPORT_DIALOG_DECLARE__ #include "ApplicationInformation.h" #include "CaretAssert.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::BugReportDialog * \brief Dialog for reporting bugs in Workbench. * \ingroup GuiQt */ /** * Constructor. * * @param parent * Parent on which this dialog is displayed. * @param openGLInformation * Information about OpenGL. */ BugReportDialog::BugReportDialog(QWidget* parent, const AString& openGLInformation) : WuQDialogNonModal("Report Workbench Bug", parent) { const AString emailAddress("workbench_bugs@brainvis.wustl.edu"); m_emailAddressURL = ("mailto:" + emailAddress + "?subject=Workbench Bug Report"); m_uploadWebSite = "http://brainvis.wustl.edu/cgi-bin/upload.cgi"; const AString newLines("\n\n"); AString bugInfo; bugInfo.appendWithNewLine(""); bugInfo.appendWithNewLine("(1) SUMMARY_OF_PROBLEM" + newLines); bugInfo.appendWithNewLine("(2) HOW TO REPRODUCE PROBLEM" + newLines); bugInfo.appendWithNewLine("(3) WHAT HAPPENS" + newLines); bugInfo.appendWithNewLine("(4) WHAT SHOULD HAPPEN" + newLines); bugInfo.appendWithNewLine("(5) NAME OF UPLOADED DATA ZIP FILE (Press \"Upload Data\" button to go to the upload website)" + newLines); bugInfo.appendWithNewLine("(6) SCREEN CAPTURES - After this information is copied into your email client, " "image captures (File Menu->Capture Image) that help describe the bug may be " "copied into the email message." + newLines); bugInfo.appendWithNewLine("------------------------------------------------------------------"); bugInfo.appendWithNewLine("PLEASE DO NOT CHANGE TEXT BELOW THIS LINE.\n" "It is used to help us understand the context of your reported bug.\n"); bugInfo.appendWithNewLine(ApplicationInformation().getAllInformationInString("\n\n")); bugInfo.appendWithNewLine(openGLInformation); const AString hcpURL("http://humanconnectome.org/connectome/get-connectome-workbench.html"); const AString infoMessage = ("Verify that your bug occurs in the latest version of Workbench: " "" + hcpURL + ". " + "You are using version " + ApplicationInformation().getVersion() + "." + "

    " + "Do not submit bug reports for these problems:
      " + "
    1. wb_command, if run from the GUI by double-clicking (it will start and immediately " + "exit). wb_command must be run inside a terminal window (DOS Prompt on Windows).
    2. " + "
    3. wb_view may crash if run with a remote desktop due to XCB and OpenGL problems in " + "the remote desktop. Some users have had success with NX and/or VirtualGL.
    4. " + "
    " + "Please address each of the numbered items in the field below." + " Use the \"Copy to Email\" button to submit your bug report to " + emailAddress + "

    " + "Data files that cause the bug may be uploaded (as a ZIP file) at " + "" + m_uploadWebSite + "." + " wb_command -zip-spec-file can be used to zip a data set." + ""); QLabel* versionLabel = new QLabel(infoMessage); versionLabel->setWordWrap(true); versionLabel->setOpenExternalLinks(true); m_textEdit = new QTextEdit(); m_textEdit->setMinimumSize(600, 400); m_textEdit->setText(bugInfo); QPushButton* copyToClipboardPushButton = new QPushButton("Copy to Clipboard"); QObject::connect(copyToClipboardPushButton, SIGNAL(clicked()), this, SLOT(copyToClipboard())); QPushButton* copyToEmailPushButton = new QPushButton("Copy to Email"); QObject::connect(copyToEmailPushButton, SIGNAL(clicked()), this, SLOT(copyToEmail())); QPushButton* uploadWebSitePushButton = new QPushButton("Upload Data"); QObject::connect(uploadWebSitePushButton, SIGNAL(clicked()), this, SLOT(openUploadWebsite())); copyToClipboardPushButton->setToolTip("Copies information to the computer's clipboard"); copyToEmailPushButton->setToolTip("Sends information to the user's email client"); uploadWebSitePushButton->setToolTip("Display upload website in user's web browser"); QHBoxLayout* buttonsLayout = new QHBoxLayout(); buttonsLayout->addStretch(); buttonsLayout->addWidget(uploadWebSitePushButton); buttonsLayout->addStretch(); buttonsLayout->addWidget(copyToClipboardPushButton); buttonsLayout->addStretch(); buttonsLayout->addWidget(copyToEmailPushButton); buttonsLayout->addStretch(); QWidget* contentWidget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(contentWidget); layout->addWidget(versionLabel, 0); layout->addSpacing(8); layout->addWidget(m_textEdit, 1000); layout->addLayout(buttonsLayout, 0); setCentralWidget(contentWidget, WuQDialog::SCROLL_AREA_NEVER); setApplyButtonText(""); disableAutoDefaultForAllPushButtons(); } /** * Destructor. */ BugReportDialog::~BugReportDialog() { } /** * Copy the text to the user's clipboard. */ void BugReportDialog::copyToClipboard() { QApplication::clipboard()->setText(m_textEdit->toPlainText().trimmed(), QClipboard::Clipboard); } /** * Copy the text to the user's email client. */ void BugReportDialog::copyToEmail() { const AString mailURL = (m_emailAddressURL + "&body=" + m_textEdit->toPlainText().trimmed()); QUrl url(mailURL); QDesktopServices::openUrl(url); } /** * Update the dialog. */ void BugReportDialog::updateDialog() { /* nothing to do */ } /** * Open the Upload Website in the user's web browser. */ void BugReportDialog::openUploadWebsite() { QDesktopServices::openUrl(QUrl(m_uploadWebSite)); } connectome-workbench-1.4.2/src/GuiQt/BugReportDialog.h000066400000000000000000000036431360521144700226630ustar00rootroot00000000000000#ifndef __BUG_REPORT_DIALOG_H__ #define __BUG_REPORT_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WuQDialogNonModal.h" class QTextEdit; namespace caret { class BugReportDialog : public WuQDialogNonModal { Q_OBJECT public: BugReportDialog(QWidget* parent, const AString& openGLInformation); virtual ~BugReportDialog(); virtual void updateDialog(); private: BugReportDialog(const BugReportDialog&); BugReportDialog& operator=(const BugReportDialog&); public: // ADD_NEW_METHODS_HERE private slots: void copyToClipboard(); void copyToEmail(); void openUploadWebsite(); private: QTextEdit* m_textEdit; QString m_emailAddressURL; QString m_uploadWebSite; // ADD_NEW_MEMBERS_HERE }; #ifdef __BUG_REPORT_DIALOG_DECLARE__ // #endif // __BUG_REPORT_DIALOG_DECLARE__ } // namespace #endif //__BUG_REPORT_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/CMakeLists.txt000066400000000000000000000612301360521144700222150ustar00rootroot00000000000000 # # Name of project # PROJECT (GuiQt) # # QT include files # if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) include_directories(${Qt5OpenGL_INCLUDE_DIRS}) include_directories(${Qt5Network_INCLUDE_DIRS}) include_directories(${Qt5Widgets_INCLUDE_DIRS}) if(HAVE_QT_WEBKIT) include_directories(${Qt5WebEngine_INCLUDE_DIRS}) include_directories(${Qt5WebEngineCore_INCLUDE_DIRS}) include_directories(${Qt5WebEngineWidgets_INCLUDE_DIRS}) include_directories(${Qt5WebView_INCLUDE_DIRS}) endif(HAVE_QT_WEBKIT) endif() IF (QT4_FOUND) SET(QT_USE_QTNETWORK TRUE) SET(QT_USE_QTOPENGL TRUE) INCLUDE(${QT_USE_FILE}) ENDIF () # # Let CMake find files for moc and uic. # # # With AUTOMOC, do not need to specify files # that contain Q_OBJECT macro for Qt to process with 'moc' # (meta-object compiler). # IF(WORKBENCH_USE_CMAKE_AUTOMOC) SET(CMAKE_AUTOMOC ON) SET(CMAKE_AUTOUIC ON) ELSE() SET(FORMS MovieDialog.ui ) SET(MOC_INPUT_HEADER_FILES AboutWorkbenchDialog.h AnnotationChangeCoordinateDialog.h AnnotationColorWidget.h AnnotationCoordinateSelectionWidget.h AnnotationCoordinateSpaceWidget.h AnnotationCoordinateWidget.h AnnotationCreateDialog.h AnnotationDeleteWidget.h AnnotationFontWidget.h AnnotationFormatWidget.h AnnotationInsertNewWidget.h AnnotationLineArrowTipsWidget.h AnnotationMenuArrange.h AnnotationMenuFileSelection.h AnnotationRedoUndoWidget.h AnnotationRotationWidget.h AnnotationSelectionViewController.h AnnotationPasteDialog.h AnnotationTextAlignmentWidget.h AnnotationTextEditorDialog.h AnnotationTextEditorWidget.h AnnotationTextOrientationWidget.h AnnotationTextSubstitutionViewController.h AnnotationWidthHeightWidget.h BalsaDatabaseUploadSceneFileDialog.h BalsaStudySelectionDialog.h BorderEditingSelectionDialog.h BorderFileSplitDialog.h BorderOptimizeDialog.h BorderPropertiesEditorDialog.h BorderSelectionViewController.h BrainBrowserWindow.h BrainBrowserWindowComboBox.h BrainBrowserWindowOrientedToolBox.h BrainBrowserWindowToolBar.h BrainBrowserWindowToolBarChartAttributes.h BrainBrowserWindowToolBarChartAxes.h BrainBrowserWindowToolBarChartTwoAttributes.h BrainBrowserWindowToolBarChartTwoAxes.h BrainBrowserWindowToolBarChartTwoOrientation.h BrainBrowserWindowToolBarChartTwoTitle.h BrainBrowserWindowToolBarChartTwoType.h BrainBrowserWindowToolBarChartType.h BrainBrowserWindowToolBarClipping.h BrainBrowserWindowToolBarComponent.h BrainBrowserWindowToolBarSlicePlane.h BrainBrowserWindowToolBarSliceSelection.h BrainBrowserWindowToolBarSurfaceMontage.h BrainBrowserWindowToolBarTab.h BrainBrowserWindowToolBarTabPopUpMenu.h BrainBrowserWindowToolBarVolumeMontage.h BrainOpenGLWidget.h BugReportDialog.h CaretColorEnumComboBox.h CaretColorEnumMenu.h CaretDataFileSelectionComboBox.h CaretFileDialog.h CaretFileDialogExtendable.h CaretFileRemoteDialog.h CaretMappableDataFileAndMapSelector.h CaretMappableDataFileAndMapSelectorObject.h ChartHistoryViewController.h ChartLinesSelectionViewController.h ChartMatrixParcelSelectionViewController.h ChartMatrixSeriesSelectionViewController.h ChartTwoOverlaySetViewController.h ChartTwoOverlayViewController.h ChartSelectionViewController.h ChartToolBoxViewController.h CiftiConnectivityMatrixViewController.h CiftiParcelSelectionComboBox.h ClippingPlanesDialog.h ColorEditorWidget.h CopyPaletteColorMappingToFilesDialog.h CustomViewDialog.h DataFileContentCopyMoveDialog.h DisplayGroupAndTabItemViewController.h DisplayGroupEnumComboBox.h EnumComboBoxTemplate.h FiberOrientationSelectionViewController.h FiberSamplesOpenGLWidget.h FociProjectionDialog.h FociPropertiesEditorDialog.h FociSelectionViewController.h GapsAndMarginsDialog.h GiftiLabelTableEditor.h GiftiLabelTableSelectionComboBox.h GroupAndNameHierarchyViewController.h GuiManager.h HelpViewerDialog.h HyperLinkTextBrowser.h IdentifyBrainordinateDialog.h ImageCaptureDialog.h ImageFileConvertToVolumeFileDialog.h ImageSelectionViewController.h InformationDisplayDialog.h InformationDisplayPropertiesDialog.h LabelSelectionViewController.h LockAspectWarningDialog.h MacApplication.h MacDockMenu.h MacDuplicateMenuBar.h MapSettingsChartTwoLineHistoryWidget.h MapSettingsColorBarPaletteOptionsWidget.h MapSettingsColorBarWidget.h MapSettingsFiberTrajectoryWidget.h MapSettingsLabelsWidget.h MapSettingsLayerWidget.h MapSettingsPaletteColorMappingWidget.h MapSettingsParcelsWidget.h MapYokingGroupComboBox.h MetaDataEditorDialog.h MetaDataEditorWidget.h MovieDialog.h MovieRecordingDialog.h OffScreenOpenGLRenderer.h OverlaySetViewController.h OverlaySettingsEditorDialog.h OverlayViewController.h PaletteColorMappingEditorDialog.h PlotMagnifier.h PlotPanner.h PreferencesDialog.h ProgressReportingDialog.h ProgressReportingFromEvent.h ProgressReportingWithSlots.h RegionOfInterestCreateFromBorderDialog.h SceneBasePathWidget.h SceneCreateReplaceDialog.h SceneDialog.h SceneFileInformationDialog.h SceneDataFileTreeItemModel.h ScenePreviewDialog.h SceneReplaceAllDialog.h SceneShowOptionsDialog.h SpecFileManagementDialog.h SplashScreen.h StructureEnumComboBox.h StructureSurfaceSelectionControl.h SurfacePropertiesEditorDialog.h SurfaceSelectionViewController.h ThresholdingSetMapsDialog.h TileTabsConfigurationDialog.h UserInputModeAnnotationsContextMenu.h UserInputModeAnnotationsWidget.h UserInputModeBordersWidget.h UserInputModeFociWidget.h UserInputModeImageWidget.h UserInputModeViewContextMenu.h UserInputModeVolumeEditWidget.h UserInputTileTabsContextMenu.h UsernamePasswordWidget.h VolumeFileCreateDialog.h VolumePropertiesEditorDialog.h VolumeSurfaceOutlineColorOrTabViewController.h VolumeSurfaceOutlineSetViewController.h VolumeSurfaceOutlineViewController.h WbMacroHelper.h WbMacroWidgetActionsManager.h WuQCollapsibleWidget.h WuQDataEntryDialog.h WuQDialog.h WuQDialogModal.h WuQDialogNonModal.h WuQDoubleSlider.h WuQDoubleSpinBox.h WuQEventBlockingFilter.h WuQGridLayoutGroup.h WuQGroupBoxExclusiveWidget.h WuQImageLabel.h WuQListWidget.h WuQMacroCommandParameterWidget.h WuQMacroCopyDialog.h WuQMacroCreateDialog.h WuQMacroDialog.h WuQMacroExecutor.h WuQMacroExecutorMonitor.h WuQMacroHelperInterface.h WuQMacroManager.h WuQMacroMenu.h WuQMacroNewCommandSelectionDialog.h WuQMacroShortCutKeyComboBox.h WuQMacroSignalEmitter.h WuQMacroSignalWatcher.h WuQMacroWidgetAction.h WuQMessageBox.h WuQwtPlot.h WuQSpecialIncrementDoubleSpinBox.h WuQSpinBox.h WuQSpinBoxGroup.h WuQSpinBoxOddValue.h WuQTabBar.h WuQTabWidget.h WuQTabWidgetWithSizeHint.h WuQTextEditorDialog.h WuQTimedMessageDisplay.h WuQTreeWidget.h WuQTrueFalseComboBox.h #WuQWebView.h WuQWidget.h WuQWidgetObjectGroup.h ZipSceneFileDialog.h ) IF(Qt5_FOUND) QT5_WRAP_CPP(MOC_SOURCE_FILES ${MOC_INPUT_HEADER_FILES}) QT5_WRAP_UI(FORMS_HEADERS ${FORMS}) ENDIF() IF (QT4_FOUND) QT4_WRAP_CPP(MOC_SOURCE_FILES ${MOC_INPUT_HEADER_FILES}) QT4_WRAP_UI(FORMS_HEADERS ${FORMS}) ENDIF () ENDIF() # # Header files # SET(SOURCE_FILES AboutWorkbenchDialog.h AnnotationChangeCoordinateDialog.h AnnotationColorWidget.h AnnotationCoordinateInformation.h AnnotationCoordinateSelectionWidget.h AnnotationCoordinateSpaceWidget.h AnnotationCoordinateWidget.h AnnotationCreateDialog.h AnnotationDeleteWidget.h AnnotationFontWidget.h AnnotationFormatWidget.h AnnotationInsertNewWidget.h AnnotationLineArrowTipsWidget.h AnnotationMenuArrange.h AnnotationMenuFileSelection.h AnnotationPasteDialog.h AnnotationRedoUndoWidget.h AnnotationRotationWidget.h AnnotationSelectionViewController.h AnnotationTextAlignmentWidget.h AnnotationTextEditorDialog.h AnnotationTextEditorWidget.h AnnotationTextOrientationWidget.h AnnotationTextSubstitutionViewController.h AnnotationWidgetParentEnum.h AnnotationWidthHeightWidget.h BalsaDatabaseManager.h BalsaDatabaseUploadSceneFileDialog.h BalsaStudySelectionDialog.h BalsaStudyInformation.h BalsaUserRoles.h BorderEditingSelectionDialog.h BorderFileSplitDialog.h BorderOptimizeDialog.h BorderOptimizeExecutor.h BorderPropertiesEditorDialog.h BorderSelectionViewController.h BrainBrowserWindow.h BrainBrowserWindowComboBox.h BrainBrowserWindowEditMenuItemEnum.h BrainBrowserWindowOrientedToolBox.h BrainBrowserWindowToolBar.h BrainBrowserWindowToolBarChartAttributes.h BrainBrowserWindowToolBarChartAxes.h BrainBrowserWindowToolBarChartTwoAttributes.h BrainBrowserWindowToolBarChartTwoAxes.h BrainBrowserWindowToolBarChartTwoOrientation.h BrainBrowserWindowToolBarChartTwoTitle.h BrainBrowserWindowToolBarChartTwoType.h BrainBrowserWindowToolBarChartType.h BrainBrowserWindowToolBarClipping.h BrainBrowserWindowToolBarComponent.h BrainBrowserWindowToolBarSlicePlane.h BrainBrowserWindowToolBarSliceSelection.h BrainBrowserWindowToolBarSurfaceMontage.h BrainBrowserWindowToolBarTab.h BrainBrowserWindowToolBarTabPopUpMenu.h BrainBrowserWindowToolBarVolumeMontage.h BrainOpenGLWidget.h BugReportDialog.h CaretColorEnumComboBox.h CaretColorEnumMenu.h CaretDataFileSelectionComboBox.h CaretFileDialog.h CaretFileDialogExtendable.h CaretFileRemoteDialog.h CaretMappableDataFileAndMapSelector.h CaretMappableDataFileAndMapSelectorObject.h ChartHistoryViewController.h ChartLinesSelectionViewController.h ChartMatrixParcelSelectionViewController.h ChartMatrixSeriesSelectionViewController.h ChartTwoOverlaySetViewController.h ChartTwoOverlayViewController.h ChartSelectionViewController.h ChartToolBoxViewController.h CiftiConnectivityMatrixViewController.h CiftiParcelSelectionComboBox.h ClippingPlanesDialog.h ColorEditorWidget.h CopyPaletteColorMappingToFilesDialog.h CursorDisplayScoped.h CursorEnum.h CursorManager.h CustomViewDialog.h DataFileContentCopyMoveDialog.h DisplayGroupAndTabItemTreeWidgetItem.h DisplayGroupAndTabItemViewController.h DisplayGroupEnumComboBox.h EnumComboBoxTemplate.h EventAnnotationCreateNewType.h EventAnnotationGetDrawnInWindow.h EventBrowserWindowDrawingContent.h EventBrowserWindowCreateTabs.h EventBrowserWindowGraphicsRedrawn.h EventBrowserWindowNew.h EventBrowserWindowTileTabOperation.h EventGetOrSetUserInputModeProcessor.h EventGraphicsTimingOneWindow.h EventGraphicsUpdateAllWindows.h EventGraphicsUpdateOneWindow.h EventHelpViewerDisplay.h EventIdentificationRequest.h EventImageCapture.h EventMacDockMenuUpdate.h EventMovieManualModeRecording.h EventOperatingSystemRequestOpenDataFile.h EventOverlaySettingsEditorDialogRequest.h EventPaletteColorMappingEditorDialogRequest.h EventShowDataFileReadWarningsDialog.h EventUpdateInformationWindows.h EventUpdateVolumeEditingToolBar.h EventUpdateYokedWindows.h EventUserInterfaceUpdate.h FiberOrientationSelectionViewController.h FiberSamplesOpenGLWidget.h FociProjectionDialog.h FociPropertiesEditorDialog.h FociSelectionViewController.h GapsAndMarginsDialog.h GiftiLabelTableEditor.h GiftiLabelTableSelectionComboBox.h GroupAndNameHierarchyTreeWidgetItem.h GroupAndNameHierarchyViewController.h GuiManager.h HelpViewerDialog.h HyperLinkTextBrowser.h IdentifyBrainordinateDialog.h ImageCaptureDialog.h ImageFileConvertToVolumeFileDialog.h ImageSelectionViewController.h InformationDisplayDialog.h InformationDisplayPropertiesDialog.h KeyEvent.h LabelSelectionViewController.h LockAspectWarningDialog.h MacApplication.h MacDockMenu.h MacDuplicateMenuBar.h MapSettingsChartTwoLineHistoryWidget.h MapSettingsColorBarPaletteOptionsWidget.h MapSettingsColorBarWidget.h MapSettingsFiberTrajectoryWidget.h MapSettingsLabelsWidget.h MapSettingsLayerWidget.h MapSettingsPaletteColorMappingWidget.h MapSettingsParcelsWidget.h MapYokingGroupComboBox.h MetaDataEditorDialog.h MetaDataEditorWidget.h MouseEvent.h MovieDialog.h MovieRecordingDialog.h OffScreenOpenGLRenderer.h OverlaySetViewController.h OverlaySettingsEditorDialog.h OverlayViewController.h PaletteColorMappingEditorDialog.h PlotMagnifier.h PlotPanner.h PreferencesDialog.h ProgressReportingDialog.h ProgressReportingFromEvent.h ProgressReportingWithSlots.h QGLWidgetTextRenderer.h RegionOfInterestCreateFromBorderDialog.h SceneBasePathWidget.h SceneCreateReplaceDialog.h SceneDialog.h SceneFileInformationDialog.h SceneDataFileTreeItem.h SceneDataFileTreeItemModel.h ScenePreviewDialog.h SceneReplaceAllDialog.h SceneShowOptionsDialog.h SceneWindowGeometry.h SpecFileManagementDialog.h SplashScreen.h StructureEnumComboBox.h StructureSurfaceSelectionControl.h SurfacePropertiesEditorDialog.h SurfaceSelectionViewController.h ThresholdingSetMapsDialog.h TileTabsConfigurationDialog.h TileTabsConfigurationModifier.h UserInputModeAbstract.h UserInputModeAnnotations.h UserInputModeAnnotationsContextMenu.h UserInputModeAnnotationsWidget.h UserInputModeBorders.h UserInputModeBordersWidget.h UserInputModeFociWidget.h UserInputModeFoci.h UserInputModeImageWidget.h UserInputModeImage.h UserInputModeView.h UserInputModeViewContextMenu.h UserInputModeVolumeEdit.h UserInputModeVolumeEditWidget.h UserInputTileTabsContextMenu.h UsernamePasswordWidget.h ViewModeEnum.h VolumeFileCreateDialog.h VolumePropertiesEditorDialog.h VolumeSurfaceOutlineColorOrTabViewController.h VolumeSurfaceOutlineSetViewController.h VolumeSurfaceOutlineViewController.h WbMacroCustomDataInfo.h WbMacroCustomDataTypeEnum.h WbMacroCustomOperationAnimateOverlayCrossFade.h WbMacroCustomOperationAnimateRotation.h WbMacroCustomOperationAnimateSurfaceInterpolation.h WbMacroCustomOperationAnimateVolumeSliceSequence.h WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade.h WbMacroCustomOperationBase.h WbMacroCustomOperationDelay.h WbMacroCustomOperationIncrementRotation.h WbMacroCustomOperationIncrementVolumeSlice.h WbMacroCustomOperationManager.h WbMacroCustomOperationTypeEnum.h WbMacroHelper.h WbMacroWidgetActionNames.h WbMacroWidgetActionsManager.h WuQCollapsibleWidget.h WuQDataEntryDialog.h WuQDialog.h WuQDialogModal.h WuQDialogNonModal.h WuQDoubleSlider.h WuQDoubleSpinBox.h WuQEventBlockingFilter.h WuQFactory.h WuQGridLayoutGroup.h WuQGroupBoxExclusiveWidget.h WuQImageLabel.h WuQListWidget.h WuQMacroCommandParameterWidget.h WuQMacroCopyDialog.h WuQMacroCreateDialog.h WuQMacroCustomOperationManagerInterface.h WuQMacroDialog.h WuQMacroExecutor.h WuQMacroExecutorMonitor.h WuQMacroExecutorOptions.h WuQMacroHelperInterface.h WuQMacroManager.h WuQMacroMenu.h WuQMacroMouseEventWidgetInterface.h WuQMacroNewCommandSelectionDialog.h WuQMacroShortCutKeyComboBox.h WuQMacroSignalEmitter.h WuQMacroSignalWatcher.h WuQMacroWidgetAction.h WuQMessageBox.h WuQwtPlot.h WuQSpecialIncrementDoubleSpinBox.h WuQSpinBox.h WuQSpinBoxGroup.h WuQSpinBoxOddValue.h WuQTabBar.h WuQTabWidget.h WuQTabWidgetWithSizeHint.h WuQTextEditorDialog.h WuQTimedMessageDisplay.h WuQTreeWidget.h WuQTrueFalseComboBox.h #WuQWebView.h WuQWidget.h WuQWidgetDisabler.h WuQWidgetObjectGroup.h WuQtUtilities.h ZipSceneFileDialog.h AboutWorkbenchDialog.cxx AnnotationChangeCoordinateDialog.cxx AnnotationColorWidget.cxx AnnotationCoordinateInformation.cxx AnnotationCoordinateSelectionWidget.cxx AnnotationCoordinateSpaceWidget.cxx AnnotationCoordinateWidget.cxx AnnotationCreateDialog.cxx AnnotationDeleteWidget.cxx AnnotationFontWidget.cxx AnnotationFormatWidget.cxx AnnotationInsertNewWidget.cxx AnnotationLineArrowTipsWidget.cxx AnnotationMenuArrange.cxx AnnotationMenuFileSelection.cxx AnnotationPasteDialog.cxx AnnotationRedoUndoWidget.cxx AnnotationRotationWidget.cxx AnnotationSelectionViewController.cxx AnnotationTextAlignmentWidget.cxx AnnotationTextEditorDialog.cxx AnnotationTextEditorWidget.cxx AnnotationTextOrientationWidget.cxx AnnotationTextSubstitutionViewController.cxx AnnotationWidgetParentEnum.cxx AnnotationWidthHeightWidget.cxx BalsaDatabaseManager.cxx BalsaDatabaseUploadSceneFileDialog.cxx BalsaStudyInformation.cxx BalsaUserRoles.cxx BalsaStudySelectionDialog.cxx BorderEditingSelectionDialog.cxx BorderFileSplitDialog.cxx BorderOptimizeDialog.cxx BorderOptimizeExecutor.cxx BorderPropertiesEditorDialog.cxx BorderSelectionViewController.cxx BrainBrowserWindow.cxx BrainBrowserWindowComboBox.cxx BrainBrowserWindowEditMenuItemEnum.cxx BrainBrowserWindowOrientedToolBox.cxx BrainBrowserWindowToolBar.cxx BrainBrowserWindowToolBarChartAttributes.cxx BrainBrowserWindowToolBarChartAxes.cxx BrainBrowserWindowToolBarChartTwoAttributes.cxx BrainBrowserWindowToolBarChartTwoAxes.cxx BrainBrowserWindowToolBarChartTwoOrientation.cxx BrainBrowserWindowToolBarChartTwoTitle.cxx BrainBrowserWindowToolBarChartTwoType.cxx BrainBrowserWindowToolBarChartType.cxx BrainBrowserWindowToolBarClipping.cxx BrainBrowserWindowToolBarComponent.cxx BrainBrowserWindowToolBarSlicePlane.cxx BrainBrowserWindowToolBarSliceSelection.cxx BrainBrowserWindowToolBarSurfaceMontage.cxx BrainBrowserWindowToolBarTab.cxx BrainBrowserWindowToolBarTabPopUpMenu.cxx BrainBrowserWindowToolBarVolumeMontage.cxx BrainOpenGLWidget.cxx BugReportDialog.cxx CaretColorEnumComboBox.cxx CaretColorEnumMenu.cxx CaretDataFileSelectionComboBox.cxx CaretFileDialog.cxx CaretFileDialogExtendable.cxx CaretFileRemoteDialog.cxx CaretMappableDataFileAndMapSelector.cxx CaretMappableDataFileAndMapSelectorObject.cxx ChartHistoryViewController.cxx ChartLinesSelectionViewController.cxx ChartMatrixParcelSelectionViewController.cxx ChartMatrixSeriesSelectionViewController.cxx ChartTwoOverlaySetViewController.cxx ChartTwoOverlayViewController.cxx ChartSelectionViewController.cxx ChartToolBoxViewController.cxx CiftiConnectivityMatrixViewController.cxx CiftiParcelSelectionComboBox.cxx ClippingPlanesDialog.cxx ColorEditorWidget.cxx CopyPaletteColorMappingToFilesDialog.cxx CursorDisplayScoped.cxx CursorEnum.cxx CursorManager.cxx CustomViewDialog.cxx DataFileContentCopyMoveDialog.cxx DisplayGroupAndTabItemTreeWidgetItem.cxx DisplayGroupAndTabItemViewController.cxx DisplayGroupEnumComboBox.cxx EventAnnotationCreateNewType.cxx EventAnnotationGetDrawnInWindow.cxx EventBrowserWindowDrawingContent.cxx EventBrowserWindowCreateTabs.cxx EventBrowserWindowGraphicsRedrawn.cxx EventBrowserWindowNew.cxx EventBrowserWindowTileTabOperation.cxx EventGetOrSetUserInputModeProcessor.cxx EventGraphicsTimingOneWindow.cxx EventGraphicsUpdateAllWindows.cxx EventGraphicsUpdateOneWindow.cxx EventHelpViewerDisplay.cxx EventIdentificationRequest.cxx EventImageCapture.cxx EventMacDockMenuUpdate.cxx EventMovieManualModeRecording.cxx EventOperatingSystemRequestOpenDataFile.cxx EventOverlaySettingsEditorDialogRequest.cxx EventPaletteColorMappingEditorDialogRequest.cxx EventShowDataFileReadWarningsDialog.cxx EventUpdateInformationWindows.cxx EventUpdateVolumeEditingToolBar.cxx EventUpdateYokedWindows.cxx EventUserInterfaceUpdate.cxx FiberOrientationSelectionViewController.cxx FiberSamplesOpenGLWidget.cxx FociProjectionDialog.cxx FociPropertiesEditorDialog.cxx FociSelectionViewController.cxx GapsAndMarginsDialog.cxx GiftiLabelTableEditor.cxx GiftiLabelTableSelectionComboBox.cxx GroupAndNameHierarchyTreeWidgetItem.cxx GroupAndNameHierarchyViewController.cxx GuiManager.cxx HelpViewerDialog.cxx HyperLinkTextBrowser.cxx IdentifyBrainordinateDialog.cxx ImageCaptureDialog.cxx ImageFileConvertToVolumeFileDialog.cxx ImageSelectionViewController.cxx InformationDisplayDialog.cxx InformationDisplayPropertiesDialog.cxx KeyEvent.cxx LabelSelectionViewController.cxx LockAspectWarningDialog.cxx MacApplication.cxx MacDockMenu.cxx MacDuplicateMenuBar.cxx MapSettingsChartTwoLineHistoryWidget.cxx MapSettingsColorBarPaletteOptionsWidget.cxx MapSettingsColorBarWidget.cxx MapSettingsFiberTrajectoryWidget.cxx MapSettingsLabelsWidget.cxx MapSettingsLayerWidget.cxx MapSettingsPaletteColorMappingWidget.cxx MapSettingsParcelsWidget.cxx MapYokingGroupComboBox.cxx MetaDataEditorDialog.cxx MetaDataEditorWidget.cxx MouseEvent.cxx MovieDialog.cxx MovieRecordingDialog.cxx OffScreenOpenGLRenderer.cxx OverlaySetViewController.cxx OverlayViewController.cxx OverlaySettingsEditorDialog.cxx PaletteColorMappingEditorDialog.cxx PlotMagnifier.cxx PlotPanner.cxx PreferencesDialog.cxx ProgressReportingDialog.cxx ProgressReportingFromEvent.cxx ProgressReportingWithSlots.cxx QGLWidgetTextRenderer.cxx RegionOfInterestCreateFromBorderDialog.cxx SceneBasePathWidget.cxx SceneCreateReplaceDialog.cxx SceneDialog.cxx SceneFileInformationDialog.cxx SceneDataFileTreeItem.cxx SceneDataFileTreeItemModel.cxx ScenePreviewDialog.cxx SceneReplaceAllDialog.cxx SceneShowOptionsDialog.cxx SceneWindowGeometry.cxx SpecFileManagementDialog.cxx SplashScreen.cxx StructureEnumComboBox.cxx StructureSurfaceSelectionControl.cxx SurfacePropertiesEditorDialog.cxx SurfaceSelectionViewController.cxx ThresholdingSetMapsDialog.cxx TileTabsConfigurationDialog.cxx TileTabsConfigurationModifier.cxx UserInputModeAbstract.cxx UserInputModeAnnotations.cxx UserInputModeAnnotationsContextMenu.cxx UserInputModeAnnotationsWidget.cxx UserInputModeBorders.cxx UserInputModeBordersWidget.cxx UserInputModeFoci.cxx UserInputModeFociWidget.cxx UserInputModeImage.cxx UserInputModeImageWidget.cxx UserInputModeView.cxx UserInputModeViewContextMenu.cxx UserInputModeVolumeEdit.cxx UserInputModeVolumeEditWidget.cxx UserInputTileTabsContextMenu.cxx UsernamePasswordWidget.cxx ViewModeEnum.cxx VolumeFileCreateDialog.cxx VolumePropertiesEditorDialog.cxx VolumeSurfaceOutlineColorOrTabViewController.cxx VolumeSurfaceOutlineSetViewController.cxx VolumeSurfaceOutlineViewController.cxx WbMacroCustomDataInfo.cxx WbMacroCustomDataTypeEnum.cxx WbMacroCustomOperationAnimateOverlayCrossFade.cxx WbMacroCustomOperationAnimateRotation.cxx WbMacroCustomOperationAnimateSurfaceInterpolation.cxx WbMacroCustomOperationAnimateVolumeSliceSequence.cxx WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade.cxx WbMacroCustomOperationBase.cxx WbMacroCustomOperationDelay.cxx WbMacroCustomOperationIncrementRotation.cxx WbMacroCustomOperationIncrementVolumeSlice.cxx WbMacroCustomOperationManager.cxx WbMacroCustomOperationTypeEnum.cxx WbMacroHelper.cxx WbMacroWidgetActionsManager.cxx WuQCollapsibleWidget.cxx WuQDataEntryDialog.cxx WuQDialog.cxx WuQDialogModal.cxx WuQDialogNonModal.cxx WuQDoubleSlider.cxx WuQDoubleSpinBox.cxx WuQEventBlockingFilter.cxx WuQFactory.cxx WuQGridLayoutGroup.cxx WuQGroupBoxExclusiveWidget.cxx WuQImageLabel.cxx WuQListWidget.cxx WuQMacroCommandParameterWidget.cxx WuQMacroCopyDialog.cxx WuQMacroCreateDialog.cxx WuQMacroDialog.cxx WuQMacroExecutor.cxx WuQMacroExecutorMonitor.cxx WuQMacroExecutorOptions.cxx WuQMacroManager.cxx WuQMacroMenu.cxx WuQMacroNewCommandSelectionDialog.cxx WuQMacroShortCutKeyComboBox.cxx WuQMacroSignalEmitter.cxx WuQMacroSignalWatcher.cxx WuQMacroWidgetAction.cxx WuQMessageBox.cxx WuQwtPlot.cxx WuQSpecialIncrementDoubleSpinBox.cxx WuQSpinBox.cxx WuQSpinBoxGroup.cxx WuQSpinBoxOddValue.cxx WuQTabBar.cxx WuQTabWidget.cxx WuQTabWidgetWithSizeHint.cxx WuQTextEditorDialog.cxx WuQTimedMessageDisplay.cxx WuQTreeWidget.cxx WuQTrueFalseComboBox.cxx #WuQWebView.cxx WuQWidget.cxx WuQWidgetDisabler.cxx WuQWidgetObjectGroup.cxx WuQtUtilities.cxx ZipSceneFileDialog.cxx ) # # Process the header files with moc producing moc_*.cpp files # INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/GuiQt) # # Create the GUI library # ADD_LIBRARY(GuiQt ${FORMS_HEADERS} ${MOC_SOURCE_FILES} ${SOURCE_FILES} ) TARGET_LINK_LIBRARIES(GuiQt ${CARET_QT5_LINK}) INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/GuiQt ${Qwt_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/Algorithms ${CMAKE_SOURCE_DIR}/Annotations ${CMAKE_SOURCE_DIR}/Brain ${CMAKE_SOURCE_DIR}/Commands ${CMAKE_SOURCE_DIR}/Charting ${CMAKE_SOURCE_DIR}/FilesBase ${CMAKE_SOURCE_DIR}/Files ${CMAKE_SOURCE_DIR}/Cifti ${CMAKE_SOURCE_DIR}/Gifti ${CMAKE_SOURCE_DIR}/Graphics ${CMAKE_SOURCE_DIR}/Nifti ${CMAKE_SOURCE_DIR}/OSMesaDummy ${CMAKE_SOURCE_DIR}/Operations ${CMAKE_SOURCE_DIR}/OperationsBase ${CMAKE_SOURCE_DIR}/Palette ${CMAKE_SOURCE_DIR}/Scenes ${CMAKE_SOURCE_DIR}/Xml ${CMAKE_SOURCE_DIR}/Common ) connectome-workbench-1.4.2/src/GuiQt/CaretColorEnumComboBox.cxx000066400000000000000000000205751360521144700245230ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CARET_COLOR_ENUM_COMBOBOX_DECLARE__ #include "CaretColorEnumComboBox.h" #undef __CARET_COLOR_ENUM_COMBOBOX_DECLARE__ #include #include "CaretAssert.h" #include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::CaretColorEnumComboBox * \brief Control for selection of Caret Color enumerated types. * * Control for selection of Caret Color enumerated types. */ /** * Constructor. * * @param parent * Parent object. */ CaretColorEnumComboBox::CaretColorEnumComboBox(QObject* parent) : WuQWidget(parent) { initializeCaretColorComboBox("", NULL); } /** * Constructor. * * @param customColorSelectionName * CaretColorEnum::CUSTOM is added to the combo with this name as the text. * Text must NOT be empty. * @param parent * Parent object. */ CaretColorEnumComboBox::CaretColorEnumComboBox(const AString& customColorSelectionName, QObject* parent) : WuQWidget(parent) { CaretAssert( ! customColorSelectionName.isEmpty()); initializeCaretColorComboBox(customColorSelectionName, NULL); } /** * Constructor. * * @param customColorSelectionName * CaretColorEnum::CUSTOM is added to the combo with this name as the text. * Text must NOT be empty. * @param customColorSelectionIcon * ICon for custom color. * @param parent * Parent object. */ CaretColorEnumComboBox::CaretColorEnumComboBox(const AString& customColorSelectionName, const QIcon& customColorSelectionIcon, QObject* parent) : WuQWidget(parent) { CaretAssert( ! customColorSelectionName.isEmpty()); initializeCaretColorComboBox(customColorSelectionName, &customColorSelectionIcon); } /** * Constructor. * * @param customColorSelectionName * If not empty, CaretColorEnum::CUSTOM is added to the combo with this name as the text. * @param customColorSelectionIcon * Icon for custom color. * @param objectNameForMacros * If not empty, name is used to set this combo box for macro support * @param objectDescriptiveNameForMacros * Descriptive name for macros * @param parent * Parent object. */ CaretColorEnumComboBox::CaretColorEnumComboBox(const AString& customColorSelectionName, const QIcon& customColorSelectionIcon, const QString& objectNameForMacros, const QString& objectDescriptiveNameForMacros, QObject* parent) : WuQWidget(parent) { initializeCaretColorComboBox(customColorSelectionName, &customColorSelectionIcon); if ( ! objectNameForMacros.isEmpty()) { this->colorComboBox->setObjectName(objectNameForMacros); this->colorComboBox->setToolTip("Select Color"); WuQMacroManager::instance()->addMacroSupportToObject(this->colorComboBox, objectDescriptiveNameForMacros); } } /** * Destructor. */ CaretColorEnumComboBox::~CaretColorEnumComboBox() { } /** * Initialize instance that may have optional caret color enums. * * @param customColorSelectionName * If NOT empty, CaretColorEnum::CUSTOM is added with text from this name. * @param customColorSelectionIcon * ICON for custom color (ignored if NULL) */ void CaretColorEnumComboBox::initializeCaretColorComboBox(const AString& customColorSelectionName, const QIcon* customColorSelectionIcon) { this->colorComboBox = new QComboBox(); std::vector colors; int64_t caretColorOptions = 0; if ( ! customColorSelectionName.isEmpty()) { caretColorOptions |= CaretColorEnum::OPTION_INCLUDE_CUSTOM_COLOR; } CaretColorEnum::getColorAndOptionalEnums(colors, caretColorOptions); const int32_t numColors = static_cast(colors.size()); for (int32_t i = 0; i < numColors; i++) { const CaretColorEnum::Enum colorEnum = colors[i]; const int32_t indx = this->colorComboBox->count(); AString name = CaretColorEnum::toGuiName(colorEnum); if (colorEnum == CaretColorEnum::CUSTOM) { if ( ! customColorSelectionName.isEmpty()) { name = customColorSelectionName; } } this->colorComboBox->addItem(name); this->colorComboBox->setItemData(indx, CaretColorEnum::toIntegerCode(colorEnum)); /* * Create an icon with the color. */ float rgba[4]; CaretColorEnum::toRGBAFloat(colorEnum, rgba); if (colorEnum == CaretColorEnum::NONE) { rgba[3] = 0.0; } else if (colorEnum == CaretColorEnum::CUSTOM) { /* * If NO icon for CUSTOM */ if (customColorSelectionIcon == NULL) { rgba[3] = 0.0; } } else { rgba[3] = 1.0; } if (rgba[3] > 0.0) { QPixmap pm(WuQtUtilities::createCaretColorEnumPixmap(getWidget(), 10, 10, colorEnum, rgba, false)); QIcon icon(pm); if (colorEnum == CaretColorEnum::CUSTOM) { if (customColorSelectionIcon != NULL) { icon = *customColorSelectionIcon; } } this->colorComboBox->setItemIcon(indx, icon); } } setSelectedColor(CaretColorEnum::BLACK); QObject::connect(this->colorComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(colorComboBoxIndexChanged(int))); } /** * @return The actual widget. */ QWidget* CaretColorEnumComboBox::getWidget() { return this->colorComboBox; } /** * @return The actual combo box encapsulated in this instance. */ QComboBox* CaretColorEnumComboBox::getComboBox() { return this->colorComboBox; } /** * @return The selected color. */ CaretColorEnum::Enum CaretColorEnumComboBox::getSelectedColor() { const int32_t indx = this->colorComboBox->currentIndex(); const int32_t integerCode = this->colorComboBox->itemData(indx).toInt(); CaretColorEnum::Enum color = CaretColorEnum::fromIntegerCode(integerCode, NULL); return color; } /** * Set the selected color. * @param color * New color for selection. */ void CaretColorEnumComboBox::setSelectedColor(const CaretColorEnum::Enum color) { const int32_t numColors = static_cast(this->colorComboBox->count()); for (int32_t i = 0; i < numColors; i++) { const int32_t integerCode = this->colorComboBox->itemData(i).toInt(); CaretColorEnum::Enum c = CaretColorEnum::fromIntegerCode(integerCode, NULL); if (c == color) { this->colorComboBox->blockSignals(true); this->colorComboBox->setCurrentIndex(i); this->colorComboBox->blockSignals(false); break; } } } /** * Called when a color is selected. * @param indx * Index of item selected. */ void CaretColorEnumComboBox::colorComboBoxIndexChanged(int indx) { const int32_t integerCode = this->colorComboBox->itemData(indx).toInt(); CaretColorEnum::Enum color = CaretColorEnum::fromIntegerCode(integerCode, NULL); emit colorSelected(color); } connectome-workbench-1.4.2/src/GuiQt/CaretColorEnumComboBox.h000066400000000000000000000054401360521144700241420ustar00rootroot00000000000000#ifndef __CARET_COLOR_ENUM_COMBOBOX__H_ #define __CARET_COLOR_ENUM_COMBOBOX__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretColorEnum.h" #include "WuQWidget.h" class QComboBox; namespace caret { class CaretColorEnumComboBox : public WuQWidget { Q_OBJECT public: CaretColorEnumComboBox(QObject* parent); CaretColorEnumComboBox(const AString& customColorSelectionName, QObject* parent); CaretColorEnumComboBox(const AString& customColorSelectionName, const QIcon& customColorSelectionIcon, QObject* parent); CaretColorEnumComboBox(const AString& customColorSelectionName, const QIcon& customColorSelectionIcon, const QString& objectNameForMacros, const QString& objectDescriptiveNameForMacros, QObject* parent); virtual ~CaretColorEnumComboBox(); CaretColorEnum::Enum getSelectedColor(); void setSelectedColor(const CaretColorEnum::Enum color); QWidget* getWidget(); QComboBox* getComboBox(); signals: void colorSelected(const CaretColorEnum::Enum); private slots: void colorComboBoxIndexChanged(int); private: CaretColorEnumComboBox(const CaretColorEnumComboBox&); CaretColorEnumComboBox& operator=(const CaretColorEnumComboBox&); private: QComboBox* colorComboBox; void initializeCaretColorComboBox(const AString& customColorSelectionName, const QIcon* customColorSelectionIcon); }; #ifdef __CARET_COLOR_ENUM_COMBOBOX_DECLARE__ // #endif // __CARET_COLOR_ENUM_COMBOBOX_DECLARE__ } // namespace #endif //__CARET_COLOR_ENUM_COMBOBOX__H_ connectome-workbench-1.4.2/src/GuiQt/CaretColorEnumMenu.cxx000066400000000000000000000145711360521144700237160ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CARET_COLOR_ENUM_MENU_DECLARE__ #include "CaretColorEnumMenu.h" #undef __CARET_COLOR_ENUM_MENU_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::CaretColorEnumMenu * \brief Menu for selection of the standard caret colors * \ingroup GuiQt */ /** * Constructor. */ CaretColorEnumMenu::CaretColorEnumMenu() : QMenu() { initializeCaretColorEnumMenu(CaretColorEnum::OPTION_NO_OPTIONS); } /** * Constructor for menu that may provide optional caret color enums. * * @param caretColorOptions * Options for caret color enums. */ CaretColorEnumMenu::CaretColorEnumMenu(const int64_t caretColorOptions) : QMenu() { initializeCaretColorEnumMenu(caretColorOptions); } /** * Destructor. */ CaretColorEnumMenu::~CaretColorEnumMenu() { } /** * Initialize instance that may have optional caret color enums. * * @param caretColorOptions * Options for caret color enums. */ void CaretColorEnumMenu::initializeCaretColorEnumMenu(const int64_t caretColorOptions) { m_customColorAction = NULL; std::vector colors; CaretColorEnum::getColorAndOptionalEnums(colors, caretColorOptions); const int32_t numColors = static_cast(colors.size()); for (int32_t i = 0; i < numColors; i++) { const CaretColorEnum::Enum colorEnum = colors[i]; const int colorIntegerCode = CaretColorEnum::toIntegerCode(colorEnum); const AString name = CaretColorEnum::toGuiName(colorEnum); /* * Create an icon with the color. */ float rgba[4]; CaretColorEnum::toRGBAFloat(colorEnum, rgba); if (colorEnum == CaretColorEnum::NONE) { rgba[3] = 0.0; } else if (colorEnum == CaretColorEnum::CUSTOM) { /* * No pixmap for CUSTOM */ rgba[3] = 0.0; } else { rgba[3] = 1.0; } /* * Add color action to menu and make it checkable */ QAction* action = addAction(name); action->setData(colorIntegerCode); action->setIconText(name); QPixmap pm = WuQtUtilities::createCaretColorEnumPixmap(this, 10, 10, colorEnum, rgba, false); action->setIcon(QIcon(pm)); action->setCheckable(true); if (colorEnum == CaretColorEnum::CUSTOM) { m_customColorAction = action; } } QObject::connect(this, SIGNAL(triggered(QAction*)), this, SLOT(colorActionSelected(QAction*))); } /** * Set the selected color. * * @param color * New selected color. */ void CaretColorEnumMenu::setSelectedColor(const CaretColorEnum::Enum color) { blockSignals(true); const int colorIntegerCode = CaretColorEnum::toIntegerCode(color); /* * Set checkbox next to selected color. */ QList actionList = actions(); QListIterator actionIter(actionList); while (actionIter.hasNext()) { QAction* action = actionIter.next(); CaretAssert(action); const int actionIntegerCode = action->data().toInt(); if (actionIntegerCode == colorIntegerCode) { action->setChecked(true); } else { action->setChecked(false); } } blockSignals(false); } /** * Gets called when a color is selected. * * @param action * Action that is selected. */ void CaretColorEnumMenu::colorActionSelected(QAction* action) { const int integerCode = action->data().toInt(); bool valid = false; const CaretColorEnum::Enum color = CaretColorEnum::fromIntegerCode(integerCode, &valid); if (valid) { /* * Update checkboxes */ setSelectedColor(color); /* * Emit color changed signal. */ emit colorSelected(color); } else { CaretLogSevere("Invalid CaretColorEnum integer code=" + AString::number(integerCode)); } } /** * @return The selected color. */ CaretColorEnum::Enum CaretColorEnumMenu::getSelectedColor() { QList actionList = actions(); QListIterator actionIter(actionList); while (actionIter.hasNext()) { QAction* action = actionIter.next(); CaretAssert(action); if (action->isChecked()) { const int actionIntegerCode = action->data().toInt(); bool valid = false; CaretColorEnum::Enum colorSelected = CaretColorEnum::fromIntegerCode(actionIntegerCode, &valid); if (valid) { return colorSelected; } } } CaretAssertMessage(0, "Did not find selected color."); return CaretColorEnum::WHITE; } /** * Set the color for the custom color's icon. * * @param rgb * Red/Green/Blue/Alpha color components [0.0, 1.0] */ void CaretColorEnumMenu::setCustomIconColor(const float rgba[4]) { if (m_customColorAction != NULL) { QPixmap pm = WuQtUtilities::createCaretColorEnumPixmap(this, 10, 10, CaretColorEnum::CUSTOM, rgba, false); m_customColorAction->setIcon(QIcon(pm)); } } connectome-workbench-1.4.2/src/GuiQt/CaretColorEnumMenu.h000066400000000000000000000040741360521144700233400ustar00rootroot00000000000000#ifndef __CARET_COLOR_ENUM_MENU_H__ #define __CARET_COLOR_ENUM_MENU_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretColorEnum.h" namespace caret { class CaretColorEnumMenu : public QMenu { Q_OBJECT public: CaretColorEnumMenu(); CaretColorEnumMenu(const int64_t caretColorOptions); virtual ~CaretColorEnumMenu(); CaretColorEnum::Enum getSelectedColor(); void setSelectedColor(const CaretColorEnum::Enum color); void setCustomIconColor(const float rgba[4]); // ADD_NEW_METHODS_HERE signals: void colorSelected(const CaretColorEnum::Enum); private slots: void colorActionSelected(QAction* action); private: CaretColorEnumMenu(const CaretColorEnumMenu&); CaretColorEnumMenu& operator=(const CaretColorEnumMenu&); void initializeCaretColorEnumMenu(const int64_t caretColorOptions); QAction* m_customColorAction; // ADD_NEW_MEMBERS_HERE }; #ifdef __CARET_COLOR_ENUM_MENU_DECLARE__ // #endif // __CARET_COLOR_ENUM_MENU_DECLARE__ } // namespace #endif //__CARET_COLOR_ENUM_MENU_H__ connectome-workbench-1.4.2/src/GuiQt/CaretDataFileSelectionComboBox.cxx000066400000000000000000000107171360521144700261340ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CARET_DATA_FILE_SELECTION_COMBO_BOX_DECLARE__ #include "CaretDataFileSelectionComboBox.h" #undef __CARET_DATA_FILE_SELECTION_COMBO_BOX_DECLARE__ #include "CaretAssert.h" #include "CaretDataFile.h" #include "CaretDataFileSelectionModel.h" #include "FilePathNamePrefixCompactor.h" #include "WuQEventBlockingFilter.h" using namespace caret; /** * \class caret::CaretDataFileSelectionComboBox * \brief Combo box for selection of a CaretDataFile. * \ingroup GuiQt */ /** * Constructor. * * @param parent * Parent of combo box. */ CaretDataFileSelectionComboBox::CaretDataFileSelectionComboBox(QObject* parent) : WuQWidget(parent) { m_selectionModel = NULL; m_comboBox = new QComboBox(); m_comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); QObject::connect(m_comboBox, SIGNAL(activated(int)), this, SLOT(slotFileIndexSelected(int))); WuQEventBlockingFilter::blockMouseWheelEventInMacComboBox(m_comboBox); } /** * Destructor. */ CaretDataFileSelectionComboBox::~CaretDataFileSelectionComboBox() { } /** * @return The widget (combobox) for insertion into a layout. */ QWidget* CaretDataFileSelectionComboBox::getWidget() { return m_comboBox; } /** * Gets called when the user makes a selection. Issues the * 'fileSelected()' signal. * * @param indx * Index of the item that was selected. */ void CaretDataFileSelectionComboBox::slotFileIndexSelected(int indx) { CaretDataFile* caretDataFile = NULL; if ((indx >= 0) && (indx < m_comboBox->count())) { void* filePointer = m_comboBox->itemData(indx).value(); caretDataFile = (CaretDataFile*)filePointer; } if (m_selectionModel != NULL) { m_selectionModel->setSelectedFile(caretDataFile); } emit fileSelected(caretDataFile); } /** * Update the content of the combo box. * * @param * Selection model for the combo box. */ void CaretDataFileSelectionComboBox::updateComboBox(CaretDataFileSelectionModel* selectionModel) { m_comboBox->blockSignals(true); m_comboBox->clear(); m_selectionModel = selectionModel; if (m_selectionModel != NULL) { const CaretDataFile* selectedFile = m_selectionModel->getSelectedFile(); int defaultIndex = 0; std::vector caretDataFiles = m_selectionModel->getAvailableFiles(); std::vector displayNames; FilePathNamePrefixCompactor::removeMatchingPathPrefixFromCaretDataFiles(caretDataFiles, displayNames); CaretAssert(caretDataFiles.size() == displayNames.size()); const int32_t numFiles = static_cast(caretDataFiles.size()); for (int32_t iFile = 0; iFile < numFiles; iFile++) { CaretAssertVectorIndex(caretDataFiles, iFile); CaretDataFile* cdf = caretDataFiles[iFile]; CaretAssert(cdf); CaretAssertVectorIndex(displayNames, iFile); m_comboBox->addItem(displayNames[iFile], qVariantFromValue((void*)cdf)); if (cdf == selectedFile) { defaultIndex = m_comboBox->count() - 1; } } if ((defaultIndex >= 0) && (defaultIndex < m_comboBox->count())) { m_comboBox->setCurrentIndex(defaultIndex); } } m_comboBox->blockSignals(false); } /** * @return Selection model in this combo box. */ CaretDataFileSelectionModel* CaretDataFileSelectionComboBox::getSelectionModel() { return m_selectionModel; } connectome-workbench-1.4.2/src/GuiQt/CaretDataFileSelectionComboBox.h000066400000000000000000000043741360521144700255630ustar00rootroot00000000000000#ifndef __CARET_DATA_FILE_SELECTION_COMBO_BOX_H__ #define __CARET_DATA_FILE_SELECTION_COMBO_BOX_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "DataFileTypeEnum.h" #include "WuQWidget.h" class QComboBox; namespace caret { class CaretDataFile; class CaretDataFileSelectionModel; class CaretDataFileSelectionComboBox : public WuQWidget { Q_OBJECT public: CaretDataFileSelectionComboBox(QObject* parent); virtual ~CaretDataFileSelectionComboBox(); void updateComboBox(CaretDataFileSelectionModel* selectionModel); CaretDataFileSelectionModel* getSelectionModel(); virtual QWidget* getWidget(); // ADD_NEW_METHODS_HERE signals: void fileSelected(CaretDataFile* caretDataFile); private slots: void slotFileIndexSelected(int indx); private: CaretDataFileSelectionComboBox(const CaretDataFileSelectionComboBox&); CaretDataFileSelectionComboBox& operator=(const CaretDataFileSelectionComboBox&); QComboBox* m_comboBox; CaretDataFileSelectionModel* m_selectionModel; // ADD_NEW_MEMBERS_HERE }; #ifdef __CARET_DATA_FILE_SELECTION_COMBO_BOX_DECLARE__ // #endif // __CARET_DATA_FILE_SELECTION_COMBO_BOX_DECLARE__ } // namespace #endif //__CARET_DATA_FILE_SELECTION_COMBO_BOX_H__ connectome-workbench-1.4.2/src/GuiQt/CaretFileDialog.cxx000066400000000000000000000501101360521144700231520ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #define __CARET_FILE_DIALOG_DECLARE__ #include "CaretFileDialog.h" #undef __CARET_FILE_DIALOG_DECLARE__ #include "Brain.h" #include "GuiManager.h" using namespace caret; FilterFilesProxyModel::FilterFilesProxyModel() { m_dataFileType = DataFileTypeEnum::UNKNOWN; } FilterFilesProxyModel::~FilterFilesProxyModel() { } /** * On Macs, Qt shows files that do not match the filter as disabled. This * method looks for disabled files and prevents them from being displayed. * * @return True to display file, else false. */ bool FilterFilesProxyModel::filterAcceptsRow ( int sourceRow, const QModelIndex & sourceParent ) const { /* * See if the 'super' allows file to be displayed. */ bool showIt = QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent); if (showIt) { /* * See if item is disabled, and if so, do not show it. */ QModelIndex modelIndex = sourceModel()->index(sourceRow, 0, sourceParent); QFileSystemModel* fileModel = qobject_cast(sourceModel()); Qt::ItemFlags flags = fileModel->flags(modelIndex); if((flags & Qt::ItemIsEnabled) == 0) { showIt = false; } /* * All CIFTI files use a 'CIFTI prefix' followed by the NIFTI volume * extension. As a result, when the File Dialog's filter is set * to volume files, both volume and CIFTI files are displayed. * So, when the filter is volume files, inhibit the display CIFTI * files in the file selection dialog. */ if (showIt) { if (m_dataFileType == DataFileTypeEnum::VOLUME) { const AString name = fileModel->fileName(modelIndex); bool isValid = false; const DataFileTypeEnum::Enum fileType = DataFileTypeEnum::fromFileExtension(name, &isValid); if (isValid) { if (fileType != DataFileTypeEnum::VOLUME) { showIt = false; } } } } } return showIt; } void FilterFilesProxyModel::setDataFileTypeForFiltering(const DataFileTypeEnum::Enum dataFileType) { m_dataFileType = dataFileType; } /** * \class caret::CaretFileDialog * \brief Adds additional functionality over Qt's QFileDialog. */ /** * Constructor. */ CaretFileDialog::CaretFileDialog(QWidget* parent, Qt::WindowFlags f) : QFileDialog(parent, f) { this->initializeCaretFileDialog(); this->setDirectory(GuiManager::get()->getBrain()->getCurrentDirectory()); } /** * Constructor. */ CaretFileDialog::CaretFileDialog(QWidget* parent, const QString& caption, const QString& directory, const QString& filter) : QFileDialog(parent, caption, directory, filter) { this->initializeCaretFileDialog(); if (directory.isEmpty()) { this->setDirectory(GuiManager::get()->getBrain()->getCurrentDirectory()); } } /** * Destructor. */ CaretFileDialog::~CaretFileDialog() { } /** * Initialize the file dialog. */ void CaretFileDialog::initializeCaretFileDialog() { /* * We MUST use a non-native dialog. * Otherwise, the file filter proxy model * will not work. */ setOption(QFileDialog::DontUseNativeDialog); /* * Create a proxy model for filtering the data files. * The proxy is used to limit the displayed files to * only those with the proper file extension. In addition, * since CIFTI and NIFTI files end in ".nii", filtering is * performed so that CIFTI files are not displayed when * the user selectes Volume files. */ m_filterFilesProxyModel = new FilterFilesProxyModel(); this->setProxyModel(m_filterFilesProxyModel); #ifdef Q_OS_MACX /* * On Macs, add /Volumes to the sidebar URLs * so that mounted disks can be accessed. */ QList urls = this->sidebarUrls(); urls.append(QUrl::fromLocalFile("/Volumes")); this->setSidebarUrls(urls); #endif // Q_OS_MACX QObject::connect(this, SIGNAL(filterSelected(const QString&)), this, SLOT(fileFilterWasChanged(const QString&))); } /** * Overrides parent's setVisible to ensure file filter is properly set * * @param visible * New visibility status. */ void CaretFileDialog::setVisible(bool visible) { if (visible) { fileFilterWasChanged(selectedNameFilter()); } QFileDialog::setVisible(visible); } /** * Gets called when the file filter is changed. * * @param filter * Newly selected file filter. */ void CaretFileDialog::fileFilterWasChanged(const QString& filter) { bool isValid = false; DataFileTypeEnum::Enum dataFileType = DataFileTypeEnum::fromQFileDialogFilter(filter, &isValid); if ( ! isValid) { dataFileType = DataFileTypeEnum::UNKNOWN; } m_filterFilesProxyModel->setDataFileTypeForFiltering(dataFileType); } /** * Like QFileDialog::getOpenFileName() except that this * NEVER uses the native file dialog thus providing * a consistent user-interface across platforms. * * @param parent * Parent on which this dialog is displayed. * @param caption * Caption for dialog (if not provided a default caption is shown) * @param dir * Directory show by dialog (Brain's current directory if empty string) * @param filter * Filter for file file selection. * @param selectedFilter * Optional selected filter. * @param options * Options (see QFileDialog). * @return * Name of file selected or empty string if user cancelled. */ QString CaretFileDialog::getOpenFileNameDialog(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options ) { CaretFileDialog cfd(parent, caption, dir, filter); if (selectedFilter != 0) { cfd.selectNameFilter(*selectedFilter); } cfd.setOptions(options); cfd.setAcceptMode(CaretFileDialog::AcceptOpen); cfd.setFileMode(CaretFileDialog::AnyFile); if (cfd.exec() == CaretFileDialog::Accepted) { QStringList selectedFiles = cfd.selectedFiles(); if (selectedFiles.size() > 0) { return selectedFiles[0]; } } return QString(); } /** * Like QFileDialog::getOpenFileName() except that this * NEVER uses the native file dialog thus providing * a consistent user-interface across platforms. * * @param dataFileType * Type of Workbench data file * @param parent * Parent on which this dialog is displayed. * @param caption * Caption for dialog (if not provided a default caption is shown) * @param dir * Directory show by dialog (Brain's current directory if empty string) * @param options * Options (see QFileDialog). * @return * Name of file selected or empty string if user cancelled. */ QString CaretFileDialog::getOpenFileNameDialog(const DataFileTypeEnum::Enum dataFileType, QWidget* parent, const QString& caption, const QString& dir, Options options) { CaretFileDialog cfd(parent, caption, dir, DataFileTypeEnum::toQFileDialogFilter(dataFileType)); cfd.selectNameFilter(DataFileTypeEnum::toQFileDialogFilter(dataFileType)); cfd.setOptions(options); cfd.setAcceptMode(CaretFileDialog::AcceptOpen); cfd.setFileMode(CaretFileDialog::AnyFile); if (cfd.exec() == CaretFileDialog::Accepted) { QStringList selectedFiles = cfd.selectedFiles(); if (selectedFiles.size() > 0) { return selectedFiles[0]; } } return QString(); } /** * Like QFileDialog::getSaveFileName() except that this * NEVER uses the native file dialog thus providing * a consistent user-interface across platforms. * * @param parent * Parent on which this dialog is displayed. * @param caption * Caption for dialog (if not provided a default caption is shown) * @param dir * Directory show by dialog (Brain's current directory if empty string) * @param filter * Filter for file file selection. * @param selectedFilter * Optional selected filter. * @param options * Options (see QFileDialog). * @return * Name of file selected or empty string if user cancelled. */ QString CaretFileDialog::getSaveFileNameDialog(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options) { CaretFileDialog cfd(parent, caption, dir, filter); if (selectedFilter != 0) { cfd.selectNameFilter(*selectedFilter); } cfd.setOptions(options); cfd.setAcceptMode(QFileDialog::AcceptSave); cfd.setFileMode(CaretFileDialog::AnyFile); if (cfd.exec() == CaretFileDialog::Accepted) { QStringList selectedFiles = cfd.selectedFiles(); if (selectedFiles.size() > 0) { return selectedFiles[0]; } } return QString(); } /** * Like QFileDialog::getSaveFileName() except that this * NEVER uses the native file dialog thus providing * a consistent user-interface across platforms. * * The file filter will be from the given data file type. * The returned file will contain a valid extension from the * given data file type. * * @param dataFileType * Type of file being saved. * @param parent * Parent on which this dialog is displayed. * @param caption * Caption for dialog (if not provided a default caption is shown) * @param dir * Directory show by dialog (Brain's current directory if empty string) * @param options * Options (see QFileDialog). * @return * Name of file selected or empty string if user cancelled. If there is * no file extension or it is invalid, a valid extension will be added. */ QString CaretFileDialog::getSaveFileNameDialog(const DataFileTypeEnum::Enum dataFileType, QWidget *parent, const QString &caption, const QString &dir, Options options) { CaretFileDialog cfd(parent, caption, dir, DataFileTypeEnum::toQFileDialogFilter(dataFileType)); cfd.selectNameFilter(DataFileTypeEnum::toQFileDialogFilter(dataFileType)); cfd.setOptions(options); cfd.setAcceptMode(QFileDialog::AcceptSave); cfd.setFileMode(CaretFileDialog::AnyFile); if (cfd.exec() == CaretFileDialog::Accepted) { QStringList selectedFiles = cfd.selectedFiles(); if (selectedFiles.size() > 0) { AString filename = DataFileTypeEnum::addFileExtensionIfMissing(selectedFiles[0], dataFileType); return std::move(filename); } } return QString(); } /** * Like QFileDialog::getSaveFileName() except that this * NEVER uses the native file dialog thus providing * a consistent user-interface across platforms. It also will * display "Choose" for the selection button. * * The file filter will be from the given data file type. * The returned file will contain a valid extension from the * given data file type. * * @param dataFileType * Type of file being saved. * @param directoryOrFileName * Name of directory or name of file. * @param parent * Parent on which this dialog is displayed. * @param caption * Caption for dialog (if not provided a default caption is shown) * @param dir * Directory show by dialog (Brain's current directory if empty string) * @param options * Options (see QFileDialog). * @return * Name of file selected or empty string if user cancelled. If there is * no file extension or it is invalid, a valid extension will be added. */ QString CaretFileDialog::getChooseFileNameDialog(const DataFileTypeEnum::Enum dataFileType, const QString& directoryOrFileName, QWidget *parent) { CaretFileDialog fd(parent); if (dataFileType != DataFileTypeEnum::UNKNOWN) { fd.setNameFilter(DataFileTypeEnum::toQFileDialogFilter(dataFileType)); } fd.selectNameFilter(DataFileTypeEnum::toQFileDialogFilter(dataFileType)); fd.setAcceptMode(CaretFileDialog::AcceptSave); fd.setFileMode(CaretFileDialog::AnyFile); fd.setViewMode(CaretFileDialog::List); if (directoryOrFileName.isEmpty() == false) { QFileInfo fileInfo(directoryOrFileName); if (fileInfo.isDir()) { fd.setDirectory(directoryOrFileName); } else { fd.selectFile(directoryOrFileName); } } else { fd.setDirectory(GuiManager::get()->getBrain()->getCurrentDirectory()); } fd.setLabelText(CaretFileDialog::Accept, "Choose"); fd.setWindowTitle("Choose File Name"); if (fd.exec() == CaretFileDialog::Accepted) { QStringList selectedFiles = fd.selectedFiles(); if (selectedFiles.size() > 0) { AString filename = DataFileTypeEnum::addFileExtensionIfMissing(selectedFiles[0], dataFileType); return std::move(filename); } } return QString(); } /** * Like QFileDialog::getExistingDirectory() except that this * NEVER uses the native file dialog thus providing * a consistent user-interface across platforms. * * @param parent * Parent on which this dialog is displayed. * @param caption * Caption for dialog (if not provided a default caption is shown) * @param dir * Directory show by dialog (Brain's current directory if empty string) * @param filter * Filter for file file selection. * @param selectedFilter * Optional selected filter. * @param options * Options (see QFileDialog). * @return * Name of directory selected or empty string if user cancelled. */ QString CaretFileDialog::getExistingDirectoryDialog(QWidget *parent, const QString &caption, const QString &dir, Options options) { CaretFileDialog cfd(parent, caption, dir, ""); cfd.setOptions(options); cfd.setAcceptMode(CaretFileDialog::AcceptOpen); cfd.setFileMode(CaretFileDialog::Directory); cfd.setOption(CaretFileDialog::ShowDirsOnly, true); if (cfd.exec() == CaretFileDialog::Accepted) { QStringList selectedFiles = cfd.selectedFiles(); if (selectedFiles.size() > 0) { return selectedFiles[0]; } } return QString(); } /** * Like QFileDialog::getOpenFileNames() except that this * NEVER uses the native file dialog thus providing * a consistent user-interface across platforms. * * @param parent * Parent on which this dialog is displayed. * @param caption * Caption for dialog (if not provided a default caption is shown) * @param dir * Directory show by dialog (Brain's current directory if empty string) * @param filter * Filter for file file selection. * @param selectedFilter * Optional selected filter. * @param options * Options (see QFileDialog). * @return * StringList of file(s) selected or empty list if user cancelled. */ QStringList CaretFileDialog::getOpenFileNamesDialog(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options) { CaretFileDialog cfd(parent, caption, dir, filter); if (selectedFilter != 0) { cfd.selectNameFilter(*selectedFilter); } cfd.setOptions(options); cfd.setAcceptMode(CaretFileDialog::AcceptOpen); cfd.setFileMode(CaretFileDialog::ExistingFiles); if (cfd.exec() == CaretFileDialog::Accepted) { QStringList selectedFiles = cfd.selectedFiles(); if (selectedFiles.size() > 0) { return selectedFiles; } } QStringList sl; return sl; } /** * Save the dialog settings (directory, filename filter, and geometry) * for next time dialog displayed. * * @param settingsName * Name for settings. */ void CaretFileDialog::saveDialogSettings(const AString& settingsName) { PreviousDialogSettings previousSettings(selectedNameFilter(), directory().absolutePath(), saveGeometry()); std::map::iterator iter = s_previousDialogSettingsMap.find(settingsName); if (iter != s_previousDialogSettingsMap.end()) { iter->second = previousSettings; } else { s_previousDialogSettingsMap.insert(std::make_pair(settingsName, previousSettings)); } } /** * Restore the dialog settings (directory, filename filter, and geometry) * for next time dialog displayed. * * @param settingsName * Name for settings used when settings were saved. */ void CaretFileDialog::restoreDialogSettings(const AString& settingsName) { std::map::iterator iter = s_previousDialogSettingsMap.find(settingsName); if (iter != s_previousDialogSettingsMap.end()) { std::cout << "Found and restoring settings for " << qPrintable(settingsName) << std::endl; const PreviousDialogSettings previousSettings = iter->second; FileInformation fileInfo(previousSettings.m_directoryName); if (fileInfo.exists()) { setDirectory(previousSettings.m_directoryName); } QStringList dialogFilters = nameFilters(); QStringListIterator filterIter(dialogFilters); while (filterIter.hasNext()) { const AString filterName = filterIter.next(); if (filterName == previousSettings.m_fileFilterName) { selectNameFilter(previousSettings.m_fileFilterName); break; } } restoreGeometry(previousSettings.m_dialogGeometry); } } connectome-workbench-1.4.2/src/GuiQt/CaretFileDialog.h000066400000000000000000000146511360521144700226110ustar00rootroot00000000000000#ifndef __CARET_FILE_DIALOG__H_ #define __CARET_FILE_DIALOG__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "DataFileTypeEnum.h" namespace caret { class FilterFilesProxyModel; class CaretFileDialog : public QFileDialog { Q_OBJECT public: CaretFileDialog(QWidget* parent, Qt::WindowFlags f); CaretFileDialog(QWidget* parent = 0, const QString& caption = QString(), const QString& directory = QString(), const QString& filter = QString()); virtual ~CaretFileDialog(); // modal method to get open file name static QString getOpenFileNameDialog(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, Options options = 0); // model method to get open file name static QString getOpenFileNameDialog(const DataFileTypeEnum::Enum dataFileType, QWidget* parent = 0, const QString& caption = QString(), const QString& dir = QString(), Options options = 0); // modal method to get save file name static QString getSaveFileNameDialog(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, Options options = 0); // modal method to get save file name static QString getSaveFileNameDialog(const DataFileTypeEnum::Enum dataFileType, QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), Options options = 0); // modal method to get choose file name static QString getChooseFileNameDialog(const DataFileTypeEnum::Enum dataFileType, const QString& directoryOrFileName, QWidget *parent = 0); // modal method to get directory name static QString getExistingDirectoryDialog(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), Options options = ShowDirsOnly); // modal method to get open file names static QStringList getOpenFileNamesDialog(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, Options options = 0); void saveDialogSettings(const AString& settingsName); void restoreDialogSettings(const AString& settingsName); public slots: virtual void setVisible(bool visible); private slots: void fileFilterWasChanged(const QString& filter); private: CaretFileDialog(const CaretFileDialog&); CaretFileDialog& operator=(const CaretFileDialog&); void initializeCaretFileDialog(); FilterFilesProxyModel* m_filterFilesProxyModel; class PreviousDialogSettings { public: PreviousDialogSettings(const AString& fileFilterName, const AString& directoryName, const QByteArray& dialogGeometry) : m_fileFilterName(fileFilterName), m_directoryName(directoryName), m_dialogGeometry(dialogGeometry) { } AString m_fileFilterName; AString m_directoryName; QByteArray m_dialogGeometry; }; static std::map s_previousDialogSettingsMap; }; /** * May be fully implemented to provide additional filtering of files. */ class FilterFilesProxyModel : public QSortFilterProxyModel { public: FilterFilesProxyModel(); virtual ~FilterFilesProxyModel(); void setDataFileTypeForFiltering(const DataFileTypeEnum::Enum dataFileType); protected: bool filterAcceptsRow ( int sourceRow, const QModelIndex & sourceParent ) const; private: DataFileTypeEnum::Enum m_dataFileType; }; #ifdef __CARET_FILE_DIALOG_DECLARE__ std::map CaretFileDialog::s_previousDialogSettingsMap; #endif // __CARET_FILE_DIALOG_DECLARE__ } // namespace #endif //__CARET_FILE_DIALOG__H_ connectome-workbench-1.4.2/src/GuiQt/CaretFileDialogExtendable.cxx000066400000000000000000000115751360521144700251620ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #define __CARET_FILE_DIALOG_EXTENDABLE_DECLARE__ #include "CaretFileDialogExtendable.h" #undef __CARET_FILE_DIALOG_EXTENDABLE_DECLARE__ #include "CaretAssert.h" #include "CaretFileDialog.h" using namespace caret; /** * \class caret::CaretFileDialogExtendable * \brief A File Dialog that can have a widget added to it. * * Embeds a QFileDialog inside a dialog so that a widget * can be inserted below the FileDialog. All public methods * from QFileDialog are duplicated and go straight to * the embedded QFileDialog. */ /** * Constructor. */ CaretFileDialogExtendable::CaretFileDialogExtendable(QWidget* parent, Qt::WindowFlags f) : QDialog(parent, f) { Qt::WindowFlags flags = 0; m_caretFileDialog = new CaretFileDialogPrivate(NULL, flags); createDialog(); } /** * Constructor. */ CaretFileDialogExtendable::CaretFileDialogExtendable(QWidget* parent, const QString& caption, const QString& directory, const QString& filter) : QDialog(parent) { m_caretFileDialog = new CaretFileDialogPrivate(NULL, caption, directory, filter); createDialog(); } /** * Destructor. */ CaretFileDialogExtendable::~CaretFileDialogExtendable() { } /** * Create the dialog. */ void CaretFileDialogExtendable::createDialog() { QObject::connect(m_caretFileDialog, SIGNAL(currentChanged(const QString&)), this, SIGNAL(currentChanged(const QString&))); QObject::connect(m_caretFileDialog, SIGNAL( directoryEntered(const QString&)), this, SIGNAL( directoryEntered(const QString&))); QObject::connect(m_caretFileDialog, SIGNAL(fileSelected(const QString&)), this, SIGNAL(fileSelected(const QString&))); QObject::connect(m_caretFileDialog, SIGNAL(filesSelected(const QStringList&)), this, SIGNAL(filesSelected(const QStringList&))); QObject::connect(m_caretFileDialog, SIGNAL(filterSelected(const QString&)), this, SIGNAL(filterSelected(const QString&))); QObject::connect(m_caretFileDialog, SIGNAL(finished(int)), this, SLOT(fileDialogFinished(int))); m_caretFileDialog->setAttribute(Qt::WA_DeleteOnClose, false); m_caretFileDialog->setSizeGripEnabled(false); m_dialogLayout = new QVBoxLayout(this); m_dialogLayout->addWidget(m_caretFileDialog); } /** * Gets called when child file dialog issues its finished signal. * @param result * Result of dialog. */ void CaretFileDialogExtendable::fileDialogFinished(int result) { this->setResult(result); this->done(result); } /** * Add a widget at the bottom to this file dialog. * @param widget * Widget that is added. */ void CaretFileDialogExtendable::addWidget(QWidget* widget) { CaretAssert(widget); m_dialogLayout->addWidget(widget); } //================================================================================== CaretFileDialogPrivate::CaretFileDialogPrivate(QWidget* parent, Qt::WindowFlags /*f*/) : CaretFileDialog(parent, Qt::Widget) { } CaretFileDialogPrivate::CaretFileDialogPrivate(QWidget* parent, const QString& caption, const QString& directory, const QString& filter) : CaretFileDialog(parent, caption, directory, filter) { } CaretFileDialogPrivate::~CaretFileDialogPrivate() { } void CaretFileDialogPrivate::closeEvent(QCloseEvent* event) { event->ignore(); } void CaretFileDialogPrivate::done(int result) { CaretFileDialog::done(result); } connectome-workbench-1.4.2/src/GuiQt/CaretFileDialogExtendable.h000066400000000000000000000175111360521144700246030ustar00rootroot00000000000000#ifndef __CARET_FILE_DIALOG_EXTENDABLE__H_ #define __CARET_FILE_DIALOG_EXTENDABLE__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretFileDialog.h" class QVBoxLayout; namespace caret { class CaretFileDialogPrivate : public CaretFileDialog { Q_OBJECT public: CaretFileDialogPrivate(QWidget* parent, Qt::WindowFlags f); CaretFileDialogPrivate(QWidget* parent = 0, const QString& caption = QString(), const QString& directory = QString(), const QString& filter = QString()); virtual ~CaretFileDialogPrivate(); protected: virtual void done(int result); virtual void closeEvent(QCloseEvent* event); }; class CaretFileDialogExtendable : public QDialog { Q_OBJECT public: CaretFileDialogExtendable(QWidget* parent, Qt::WindowFlags f); CaretFileDialogExtendable(QWidget* parent = 0, const QString& caption = QString(), const QString& directory = QString(), const QString& filter = QString()); virtual ~CaretFileDialogExtendable(); void addWidget(QWidget* widget); QFileDialog::AcceptMode acceptMode() const { return m_caretFileDialog->acceptMode(); } bool confirmOverwrite() const { return m_caretFileDialog->confirmOverwrite(); } QString defaultSuffix() const { return m_caretFileDialog->defaultSuffix(); } QDir directory() const { return m_caretFileDialog->directory(); } QFileDialog::FileMode fileMode() const { return m_caretFileDialog->fileMode(); } QStringList filters() const { return m_caretFileDialog->nameFilters(); } QStringList history() const { return m_caretFileDialog->history(); } QFileIconProvider* iconProvider() const { return m_caretFileDialog->iconProvider(); } bool isReadOnly() const { return m_caretFileDialog->isReadOnly(); } QAbstractItemDelegate* itemDelegate() const { return m_caretFileDialog->itemDelegate(); } QString labelText(const QFileDialog::DialogLabel label) const { return m_caretFileDialog->labelText(label); } QStringList nameFilters() const { return m_caretFileDialog->nameFilters(); } //void open(QObject* receiver, const char* member) { m_caretFileDialog->open(receiver, member); } QFileDialog::Options options() const { return m_caretFileDialog->options(); } QAbstractProxyModel* proxyModel() const { return m_caretFileDialog->proxyModel(); } bool resolveSymlinks() const { return m_caretFileDialog->resolveSymlinks(); } bool restoreState(const QByteArray& state) { return m_caretFileDialog->restoreState(state); } QByteArray saveState() const { return m_caretFileDialog->saveState(); } void selectFile(const QString& name) { m_caretFileDialog->selectFile(name); } void selectNameFilter(const QString& filter) { m_caretFileDialog->selectNameFilter(filter); } QStringList selectedFiles() const { return m_caretFileDialog->selectedFiles(); } QString selectedNameFilter() const { return m_caretFileDialog->selectedNameFilter(); } void setAcceptMode(const QFileDialog::AcceptMode mode) { m_caretFileDialog->setAcceptMode(mode); } void setConfirmOverwrite(const bool enabled) { m_caretFileDialog->setConfirmOverwrite(enabled); } void setDefaultSuffix(const QString& suffix) { m_caretFileDialog->setDefaultSuffix(suffix); } void setDirectory(const QString& dir) { m_caretFileDialog->setDirectory(dir); } void setDirectory(const QDir& dir) { m_caretFileDialog->setDirectory(dir); } void setFileMode(const QFileDialog::FileMode mode) { m_caretFileDialog->setFileMode(mode); } // void setFilter(const QString& filter) { m_caretFileDialog->setNameFilter(filter); } void setHistory(const QStringList& paths) { m_caretFileDialog->setHistory(paths); } void setIconProvider(QFileIconProvider* provider) { m_caretFileDialog->setIconProvider(provider); } void setItemDelegate(QAbstractItemDelegate* delegate) { m_caretFileDialog->setItemDelegate(delegate); } void setLabelText(const QFileDialog::DialogLabel label, const QString& text) { m_caretFileDialog->setLabelText(label, text); } void setNameFilter(const QString& filter) { m_caretFileDialog->setNameFilter(filter); } void setNameFilterDetailsVisible(bool enabled) { m_caretFileDialog->setNameFilterDetailsVisible(enabled); } void setNameFilters(const QStringList& filters) { m_caretFileDialog->setNameFilters(filters); } void setOption(QFileDialog::Option option, bool on = true) { m_caretFileDialog->setOption(option, on); } void setOptions(QFileDialog::Options options) { m_caretFileDialog->setOptions(options); } void setProxyModel(QAbstractProxyModel* proxyModel) { m_caretFileDialog->setProxyModel(proxyModel); } void setReadOnly(const bool enabled) { m_caretFileDialog->setReadOnly(enabled); } void setResolveSymlinks(bool enabled) { m_caretFileDialog->setResolveSymlinks(enabled); } void setSidebarUrls(const QList& urls) { m_caretFileDialog->setSidebarUrls(urls); } void setViewMode(const QFileDialog::ViewMode viewMode) { m_caretFileDialog->setViewMode(viewMode); } QList sidebarUrls() const { return m_caretFileDialog->sidebarUrls(); } bool testOption(QFileDialog::Option option) const { return m_caretFileDialog->testOption(option); } QFileDialog::ViewMode viewMode() const { return m_caretFileDialog->viewMode(); } signals: void currentChanged(const QString& path); void directoryEntered(const QString& directory); void fileSelected(const QString& file); void filesSelected(const QStringList& selected); void filterSelected(const QString& filter); private slots: void fileDialogFinished(int); private: CaretFileDialogExtendable(const CaretFileDialogExtendable&); CaretFileDialogExtendable& operator=(const CaretFileDialogExtendable&); void createDialog(); QVBoxLayout* m_dialogLayout; CaretFileDialogPrivate* m_caretFileDialog; }; #ifdef __CARET_FILE_DIALOG_EXTENDABLE_DECLARE__ // #endif // __CARET_FILE_DIALOG_EXTENDABLE_DECLARE__ } // namespace #endif //__CARET_FILE_DIALOG_EXTENDABLE__H_ connectome-workbench-1.4.2/src/GuiQt/CaretFileRemoteDialog.cxx000066400000000000000000000270131360521144700243340ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #define __CARET_FILE_REMOTE_DIALOG_DECLARE__ #include "CaretFileRemoteDialog.h" #undef __CARET_FILE_REMOTE_DIALOG_DECLARE__ #include "Brain.h" #include "BrainBrowserWindow.h" #include "CaretAssert.h" #include "CaretPreferences.h" #include "DataFileTypeEnum.h" #include "EnumComboBoxTemplate.h" #include "EventDataFileRead.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "ProgressReportingDialog.h" #include "SessionManager.h" #include "SpecFile.h" #include "UsernamePasswordWidget.h" #include "WuQMessageBox.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::CaretFileRemoteDialog * \brief Open a remote data file * */ /** * Constructor. */ CaretFileRemoteDialog::CaretFileRemoteDialog(QWidget* parent) : WuQDialogModal("Open Location", parent) { QWidget* locationWidget = createLocationWidget(); m_usernamePasswordWidget = new UsernamePasswordWidget(); createAndLoadStandardData(); QWidget* controlsWidget = new QWidget(); QVBoxLayout* controlsLayout = new QVBoxLayout(controlsWidget); controlsLayout->addWidget(locationWidget); controlsLayout->addWidget(m_usernamePasswordWidget, 0, Qt::AlignCenter); WuQtUtilities::setLayoutSpacingAndMargins(controlsLayout, 4, 2); setCentralWidget(controlsWidget, WuQDialog::SCROLL_AREA_NEVER); /* * Restore previous selections */ QRadioButton* defaultRadioButton = NULL; if (s_previousSelections.m_firstTime) { s_previousSelections.m_firstTime = false; } m_customUrlLineEdit->setText(s_previousSelections.m_customURL); m_customUrlFileTypeComboBox->setSelectedItem(s_previousSelections.m_customDataFileType); m_standardFileComboBox->setCurrentIndex(s_previousSelections.m_standardFileComboBoxIndex); if (m_locationCustomRadioButton->text() == s_previousSelections.m_radioButtonText) { defaultRadioButton = m_locationCustomRadioButton; } else if (m_locationStandardRadioButton->text() == s_previousSelections.m_radioButtonText) { defaultRadioButton = m_locationStandardRadioButton; } if (defaultRadioButton != NULL) { defaultRadioButton->setChecked(true); } locationSourceRadioButtonClicked(defaultRadioButton); } /** * Destructor. */ CaretFileRemoteDialog::~CaretFileRemoteDialog() { } /** * @return The location widget. */ QWidget* CaretFileRemoteDialog::createLocationWidget() { QStringList filenameFilterList; std::vector dataFileTypes; DataFileTypeEnum::getAllEnums(dataFileTypes, DataFileTypeEnum::OPTIONS_NONE); m_locationCustomRadioButton = new QRadioButton("Custom"); m_locationStandardRadioButton = new QRadioButton("Standard"); QButtonGroup* locationButtonGroup = new QButtonGroup(this); locationButtonGroup->addButton(m_locationCustomRadioButton); locationButtonGroup->addButton(m_locationStandardRadioButton); QObject::connect(locationButtonGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(locationSourceRadioButtonClicked(QAbstractButton*))); QLabel* customUrlLabel = new QLabel("URL: "); QLabel* customUrlTypeLabel = new QLabel("Type: "); m_customUrlLineEdit = new QLineEdit(); m_customUrlLineEdit->setMinimumWidth(400); m_customUrlFileTypeComboBox = new EnumComboBoxTemplate(this); m_customUrlFileTypeComboBox->setupWithItems(dataFileTypes); m_customUrlFileTypeComboBox->setSelectedItem(DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR); m_standardFileComboBox = new QComboBox(); QGroupBox* locationGroupBox = new QGroupBox("Location"); QGridLayout* locationGridLayout = new QGridLayout(locationGroupBox); locationGridLayout->setColumnStretch(0, 0); locationGridLayout->setColumnStretch(1, 0); locationGridLayout->setColumnStretch(2, 100); int row = locationGridLayout->rowCount(); locationGridLayout->addWidget(m_locationCustomRadioButton, row, 0, 2, 1); locationGridLayout->addWidget(customUrlLabel, row, 1); locationGridLayout->addWidget(m_customUrlLineEdit, row, 2); row++; locationGridLayout->addWidget(customUrlTypeLabel, row, 1); locationGridLayout->addWidget(m_customUrlFileTypeComboBox->getWidget(), row, 2); row++; locationGridLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), row, 0, 1, 3); row++; locationGridLayout->addWidget(m_locationStandardRadioButton, row, 0, 1, 2); locationGridLayout->addWidget(m_standardFileComboBox, row, 2); m_customWidgetGroup = new WuQWidgetObjectGroup(this); m_customWidgetGroup->add(customUrlLabel); m_customWidgetGroup->add(customUrlTypeLabel); m_customWidgetGroup->add(m_customUrlLineEdit); m_customWidgetGroup->add(m_customUrlFileTypeComboBox); m_standardWidgetGroup = new WuQWidgetObjectGroup(this); m_standardWidgetGroup->add(m_standardFileComboBox); QObject::connect(m_customUrlLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(selectCustomRadioButton())); QObject::connect(m_customUrlFileTypeComboBox, SIGNAL(itemActivated()), this, SLOT(selectCustomRadioButton())); QObject::connect(m_standardFileComboBox, SIGNAL(activated(int)), this, SLOT(selectStandardRadioButton())); return locationGroupBox; } /** * To select standard radio button. */ void CaretFileRemoteDialog::selectStandardRadioButton() { m_locationStandardRadioButton->setChecked(true); locationSourceRadioButtonClicked(m_locationStandardRadioButton); } /** * To select custom radio button. */ void CaretFileRemoteDialog::selectCustomRadioButton() { m_locationCustomRadioButton->setChecked(true); locationSourceRadioButtonClicked(m_locationCustomRadioButton); } /** * Called when a location source radio button is clicked. */ void CaretFileRemoteDialog::locationSourceRadioButtonClicked(QAbstractButton* button) { bool okButtonEnabled = true; if (button == m_locationCustomRadioButton) { /* nothing */ } else if (button == m_locationStandardRadioButton) { /* nothing */ } else { okButtonEnabled = false; } getDialogButtonBox()->button(QDialogButtonBox::Ok)->setEnabled(okButtonEnabled); } /** * Create and load the standard data. */ void CaretFileRemoteDialog::createAndLoadStandardData() { m_standardFileComboBox->blockSignals(true); m_standardData.push_back(StandardData("HCP-Q1 Correlation with Mean Gray Regression (Avg 20)", "https://db.humanconnectome.org/spring/cifti-average?resource=HCP_Q1:Q1:Demo_HCP_unrelated20_FunctionalConnectivity_mgt-regression", DataFileTypeEnum::CONNECTIVITY_DENSE)); m_standardData.push_back(StandardData("HCP-Q1 Full Correlation (Avg 20)", "https://db.humanconnectome.org/spring/cifti-average?resource=HCP_Q1:Q1:Demo_HCP_unrelated20_FunctionalConnectivity_FullCorrel", DataFileTypeEnum::CONNECTIVITY_DENSE)); m_standardData.push_back(StandardData("Pilot1 Average Dense Connectome", "https://db.humanconnectome.org/data/services/cifti-average?searchID=PILOT1_AVG_xnat:subjectData", DataFileTypeEnum::CONNECTIVITY_DENSE)); const int numStandardData = static_cast(m_standardData.size()); for (int i = 0; i < numStandardData; i++) { m_standardFileComboBox->addItem(m_standardData[i].m_userFriendlyName, qVariantFromValue(i)); } m_standardFileComboBox->blockSignals(false); } /** * Called when OK button is pressed. */ void CaretFileRemoteDialog::okButtonClicked() { AString username; AString password; m_usernamePasswordWidget->getUsernameAndPassword(username, password); bool customSelected = false; if (m_locationCustomRadioButton->isChecked()) { customSelected = true; } else if (m_locationStandardRadioButton->isChecked()) { customSelected = false; } else { CaretAssert(0); // OK button only enabled if radio button selected } AString dataFileURL; DataFileTypeEnum::Enum dataFileType = DataFileTypeEnum::UNKNOWN; if (customSelected) { dataFileURL = m_customUrlLineEdit->text().trimmed(); dataFileType = m_customUrlFileTypeComboBox->getSelectedItem(); s_previousSelections.m_customURL = dataFileURL; s_previousSelections.m_customDataFileType = dataFileType; s_previousSelections.m_radioButtonText = m_locationCustomRadioButton->text(); } else { const int indx = m_standardFileComboBox->currentIndex(); if (indx >= 0) { dataFileURL = m_standardData[indx].m_locationUrl; dataFileType = m_standardData[indx].m_dataFileType; } s_previousSelections.m_standardFileComboBoxIndex = indx; s_previousSelections.m_radioButtonText = m_locationStandardRadioButton->text(); } BrainBrowserWindow* browserWindow = GuiManager::get()->getActiveBrowserWindow(); std::vector files; files.push_back(dataFileURL); std::vector dataFileTypes; dataFileTypes.push_back(dataFileType); const bool successFlag = browserWindow->loadFilesFromNetwork(this, files, dataFileTypes, username, password); if (successFlag) { WuQDialogModal::okButtonClicked(); } } connectome-workbench-1.4.2/src/GuiQt/CaretFileRemoteDialog.h000066400000000000000000000073541360521144700237670ustar00rootroot00000000000000#ifndef __CARET_FILE_REMOTE_DIALOG__H_ #define __CARET_FILE_REMOTE_DIALOG__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "DataFileTypeEnum.h" #include "WuQDialogModal.h" class QCheckBox; class QComboBox; class QLineEdit; class QRadioButton; namespace caret { class EnumComboBoxTemplate; class UsernamePasswordWidget; class WuQWidgetObjectGroup; class CaretFileRemoteDialog : public WuQDialogModal { Q_OBJECT public: CaretFileRemoteDialog(QWidget* parent = 0); virtual ~CaretFileRemoteDialog(); protected: void okButtonClicked(); private slots: void locationSourceRadioButtonClicked(QAbstractButton* button); void selectCustomRadioButton(); void selectStandardRadioButton(); private: CaretFileRemoteDialog(const CaretFileRemoteDialog&); CaretFileRemoteDialog& operator=(const CaretFileRemoteDialog&); class StandardData { public: StandardData(const AString& userFriendlyName, const AString locationUrl, const DataFileTypeEnum::Enum dataFileType) : m_userFriendlyName(userFriendlyName), m_locationUrl(locationUrl), m_dataFileType(dataFileType) { } AString m_userFriendlyName; AString m_locationUrl; DataFileTypeEnum::Enum m_dataFileType; }; class PreviousSelections { public: PreviousSelections() { m_customURL = "http://"; m_customDataFileType = DataFileTypeEnum::CONNECTIVITY_DENSE; m_standardFileComboBoxIndex = 0; m_firstTime = true; } AString m_customURL; DataFileTypeEnum::Enum m_customDataFileType; int m_standardFileComboBoxIndex; AString m_radioButtonText; bool m_firstTime; }; QWidget* createLocationWidget(); void createAndLoadStandardData(); UsernamePasswordWidget* m_usernamePasswordWidget; QRadioButton* m_locationCustomRadioButton; QRadioButton* m_locationStandardRadioButton; QComboBox* m_standardFileComboBox; EnumComboBoxTemplate* m_customUrlFileTypeComboBox; QLineEdit* m_customUrlLineEdit; QCheckBox* m_savePasswordToPreferencesCheckBox; WuQWidgetObjectGroup* m_customWidgetGroup; WuQWidgetObjectGroup* m_standardWidgetGroup; std::vector m_standardData; static PreviousSelections s_previousSelections; }; #ifdef __CARET_FILE_REMOTE_DIALOG_DECLARE__ CaretFileRemoteDialog::PreviousSelections CaretFileRemoteDialog::s_previousSelections; #endif // __CARET_FILE_REMOTE_DIALOG_DECLARE__ } // namespace #endif //__CARET_FILE_REMOTE_DIALOG__H_ connectome-workbench-1.4.2/src/GuiQt/CaretMappableDataFileAndMapSelector.cxx000066400000000000000000001142421360521144700270570ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include "WuQDataEntryDialog.h" #include "WuQFactory.h" #include "WuQMessageBox.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" #define __CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTOR_DECLARE__ #include "CaretMappableDataFileAndMapSelector.h" #undef __CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTOR_DECLARE__ #include "Brain.h" #include "BrainStructure.h" #include "CaretAssert.h" #include "CiftiBrainordinateLabelFile.h" #include "CiftiBrainordinateScalarFile.h" #include "DataFileException.h" #include "EventDataFileAdd.h" #include "EventManager.h" #include "GiftiLabel.h" #include "GiftiLabelTableEditor.h" #include "GiftiLabelTable.h" #include "GiftiMetaData.h" #include "GuiManager.h" #include "LabelFile.h" #include "MetricFile.h" #include "SpecFile.h" #include "StructureEnumComboBox.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::CaretMappableDataFileAndMapSelector * \brief Widget for selecting a map file and map. * * Dialog that allows the user to select a map file and * a map within the map file. The dialog also allows * the user to create a new map file and/or map. */ /** * Constructor. * * @param defaultName * Default name for file. * @param brain * Brain structure that contains map files. * @param structure * Type of map file. * @param parent * The parent. */ CaretMappableDataFileAndMapSelector::CaretMappableDataFileAndMapSelector(const AString defaultName, Brain* brain, const std::vector& supportedMapFileTypes, const std::vector& supportedStructures, QObject* parent) : WuQWidget(parent) { m_brain = brain; m_defaultName = defaultName; m_newMapAction = NULL; m_supportedMapFileTypes = supportedMapFileTypes; m_supportedStructures = supportedStructures; m_mapFileTypesThatAllowAddingMaps.push_back(DataFileTypeEnum::LABEL); m_mapFileTypesThatAllowAddingMaps.push_back(DataFileTypeEnum::METRIC); /* * File Type */ QLabel* mapFileTypeLabel = new QLabel("File Type: "); this->mapFileTypeComboBox = new QComboBox(); for (std::vector::iterator dataFileTypeIterator = m_supportedMapFileTypes.begin(); dataFileTypeIterator != m_supportedMapFileTypes.end(); dataFileTypeIterator++) { const DataFileTypeEnum::Enum dataFileType = *dataFileTypeIterator; const AString name = DataFileTypeEnum::toGuiName(dataFileType); this->mapFileTypeComboBox->addItem(name, (int)DataFileTypeEnum::toIntegerCode(dataFileType)); } QObject::connect(this->mapFileTypeComboBox, SIGNAL(activated(int)), this, SLOT(mapFileTypeComboBoxSelected(int))); /* * Structure */ QLabel* mapFileStructureLabel = new QLabel("Structure: "); m_mapFileStructureComboBox = new StructureEnumComboBox(this); m_mapFileStructureComboBox->listOnlyTheseStructures(supportedStructures); if ( ! supportedStructures.empty()) { m_mapFileStructureComboBox->setSelectedStructure(supportedStructures[0]); } QObject::connect(m_mapFileStructureComboBox, SIGNAL(structureSelected(const StructureEnum::Enum)), this, SLOT(mapFileStructureComboBoxSelected(const StructureEnum::Enum))); /* * File Selection */ QLabel* mapFileLabel = new QLabel("File: "); this->mapFileComboBox = new QComboBox(); QObject::connect(this->mapFileComboBox, SIGNAL(activated(int)), this, SLOT(mapFileComboBoxSelected(int))); QAction* newMapFileAction = WuQtUtilities::createAction("New...", "", this, this, SLOT(newMapFileToolButtonSelected())); QToolButton* newMapFileToolButton = new QToolButton(); newMapFileToolButton->setDefaultAction(newMapFileAction); /* * Map Name Selection */ QLabel* mapNameLabel = new QLabel("Map: "); this->mapNameComboBox = new QComboBox(); QObject::connect(this->mapNameComboBox, SIGNAL(activated(int)), this, SLOT(mapNameComboBoxSelected(int))); m_newMapAction = WuQtUtilities::createAction("New...", "", this, this, SLOT(newMapToolButtonSelected())); QToolButton* newMapToolButton = new QToolButton(); newMapToolButton->setDefaultAction(m_newMapAction); /* * Label selection */ QLabel* labelNameLabel = new QLabel("Label Name: "); this->labelSelectionComboBox = new QComboBox(); QObject::connect(this->labelSelectionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(labelNameComboBoxSelected(int))); QAction* editLabelsAction = WuQtUtilities::createAction("Edit...", "Add/Edit/Delete Labels\nand edit their colors", this, this, SLOT(showLabelsEditor())); QToolButton* editLabelsToolButton = new QToolButton(); editLabelsToolButton->setDefaultAction(editLabelsAction); this->labelValueControlsGroup = new WuQWidgetObjectGroup(this); this->labelValueControlsGroup->add(labelNameLabel); this->labelValueControlsGroup->add(this->labelSelectionComboBox); this->labelValueControlsGroup->add(editLabelsToolButton); /* * Float Value Entry */ QLabel* floatValueLabel = new QLabel("Value: "); m_floatValueSpinBox = WuQFactory::newDoubleSpinBox(); m_floatValueSpinBox->setMaximumWidth(100); m_floatValueSpinBox->setRange(-std::numeric_limits::max(), std::numeric_limits::max()); m_floatValueSpinBox->setValue(1.0); QObject::connect(m_floatValueSpinBox, SIGNAL(valueChanged(double)), this, SLOT(floatValueChanged(double))); m_floatValueControlsGroup = new WuQWidgetObjectGroup(this); m_floatValueControlsGroup->add(floatValueLabel); m_floatValueControlsGroup->add(m_floatValueSpinBox); /* * Layout widgets */ this->widget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(this->widget); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 4, 2); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); gridLayout->setColumnStretch(2, 0); int32_t rowIndex = gridLayout->rowCount(); gridLayout->addWidget(mapFileTypeLabel, rowIndex, 0); gridLayout->addWidget(this->mapFileTypeComboBox, rowIndex, 1); rowIndex++; gridLayout->addWidget(mapFileStructureLabel, rowIndex, 0); gridLayout->addWidget(m_mapFileStructureComboBox->getWidget(), rowIndex, 1); rowIndex++; gridLayout->addWidget(mapFileLabel, rowIndex, 0); gridLayout->addWidget(this->mapFileComboBox, rowIndex, 1); gridLayout->addWidget(newMapFileToolButton, rowIndex, 2); rowIndex++; gridLayout->addWidget(mapNameLabel, rowIndex, 0); gridLayout->addWidget(this->mapNameComboBox, rowIndex, 1); gridLayout->addWidget(newMapToolButton, rowIndex, 2); rowIndex++; gridLayout->addWidget(labelNameLabel, rowIndex, 0); gridLayout->addWidget(this->labelSelectionComboBox, rowIndex, 1); gridLayout->addWidget(editLabelsToolButton, rowIndex, 2); rowIndex++; gridLayout->addWidget(floatValueLabel, rowIndex, 0, Qt::AlignLeft); gridLayout->addWidget(m_floatValueSpinBox, rowIndex, 1); rowIndex++; this->setMapFileTypeComboBoxCurrentIndex(0); loadLastSelectionsForFileType(DataFileTypeEnum::UNKNOWN); } /** * Destructor. */ CaretMappableDataFileAndMapSelector::~CaretMappableDataFileAndMapSelector() { } /** * Load the map file combo box. * * @param selectedFileIndex * Index of selected file. */ void CaretMappableDataFileAndMapSelector::loadMapFileComboBox(const int32_t selectedFileIndex) { /* * Fill widgets */ std::vector matchingMapFiles; const DataFileTypeEnum::Enum selectedDataFileType = this->getSelectedMapFileType(); const StructureEnum::Enum selectedStructure = this->getSelectedMapFileStructure(); std::vector caretMappableDataFiles; m_brain->getAllMappableDataFiles(caretMappableDataFiles); for (std::vector::iterator iter = caretMappableDataFiles.begin(); iter != caretMappableDataFiles.end(); iter++) { CaretMappableDataFile* caretMapFile = *iter; const DataFileTypeEnum::Enum fileType = caretMapFile->getDataFileType(); if (selectedDataFileType == fileType) { if (caretMapFile->isMappableToSurfaceStructure(selectedStructure)) { matchingMapFiles.push_back(caretMapFile); } } } this->mapFileComboBox->clear(); for (std::vector::iterator iter = matchingMapFiles.begin(); iter != matchingMapFiles.end(); iter++) { CaretMappableDataFile* cmdf = *iter; this->mapFileComboBox->addItem(cmdf->getFileNameNoPath(), qVariantFromValue((void*)cmdf)); } if ((selectedFileIndex >= 0) && (selectedFileIndex < this->mapFileComboBox->count())) { this->setMapFileComboBoxCurrentIndex(selectedFileIndex); } this->loadMapNameComboBox(0); } /** * Called when the user makes a selection from the map file type combo box. * A signal indicating that the selections have changed will be emitted. * * @param indx * Index of item selected. */ void CaretMappableDataFileAndMapSelector::mapFileTypeComboBoxSelected(int indx) { this->setMapFileTypeComboBoxCurrentIndex(indx); loadLastSelectionsForFileType(this->getSelectedMapFileType()); enableDisableNewMapAction(); emit selectionChanged(this); } /** * Enable/disable the new map action. */ void CaretMappableDataFileAndMapSelector::enableDisableNewMapAction() { if (m_newMapAction != NULL) { const DataFileTypeEnum::Enum dataFileType = this->getSelectedMapFileType(); if (std::find(m_mapFileTypesThatAllowAddingMaps.begin(), m_mapFileTypesThatAllowAddingMaps.end(), dataFileType) != m_mapFileTypesThatAllowAddingMaps.end()) { m_newMapAction->setEnabled(true); } else { m_newMapAction->setEnabled(false); } } } /** * Called when the structure is changed. * * @param structure * Selected structure. */ void CaretMappableDataFileAndMapSelector::mapFileStructureComboBoxSelected(const StructureEnum::Enum /*structure*/) { loadLastSelectionsForFileType(getSelectedMapFileType()); emit selectionChanged(this); } /** * Set the map file type combo box to the given index. * @param indx * Index for selection. */ void CaretMappableDataFileAndMapSelector::setMapFileTypeComboBoxCurrentIndex(int indx) { this->mapFileTypeComboBox->setCurrentIndex(indx); const int32_t integerCode = this->mapFileTypeComboBox->itemData(indx).toInt(); const DataFileTypeEnum::Enum dataFileType = DataFileTypeEnum::fromIntegerCode(integerCode, NULL); this->updateFileTypeSelections(dataFileType); this->loadMapFileComboBox(0); } /** * Update the selections for specific file types. */ void CaretMappableDataFileAndMapSelector::updateFileTypeSelections(const DataFileTypeEnum::Enum dataFileType) { bool showLabelSelectionWidgets = false; bool showScalarSelectionWidgets = false; switch (dataFileType) { case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: showLabelSelectionWidgets = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: showScalarSelectionWidgets = true; break; case DataFileTypeEnum::LABEL: showLabelSelectionWidgets = true; break; case DataFileTypeEnum::METRIC: showScalarSelectionWidgets = true; break; default: break; } labelValueControlsGroup->setVisible(showLabelSelectionWidgets); m_floatValueControlsGroup->setVisible(showScalarSelectionWidgets); } /** * Called when the user makes a selection from the map file combo box. * A signal indicating that the selections have changed will be emitted. * * @param indx * Index of item selected. */ void CaretMappableDataFileAndMapSelector::mapFileComboBoxSelected(int indx) { this->setMapFileComboBoxCurrentIndex(indx); emit selectionChanged(this); } /** * Set the map file combo box to the given index. * @param indx * Index for selection. */ void CaretMappableDataFileAndMapSelector::setMapFileComboBoxCurrentIndex(int indx) { this->mapFileComboBox->setCurrentIndex(indx); this->loadMapNameComboBox(0); this->loadLabelNameComboBox(); } /** * Set the map name combo box to the given index. * @param indx * Index for selection. */ void CaretMappableDataFileAndMapSelector::setMapNameComboBoxCurrentIndex(int indx) { this->mapNameComboBox->setCurrentIndex(indx); } /** * Load the contents of the map name combo box. * @param selectedMapIndex * Index of the map that is selected. */ void CaretMappableDataFileAndMapSelector::loadMapNameComboBox(const int32_t selectedMapIndex) { this->mapNameComboBox->clear(); CaretMappableDataFile* cmdf = this->getSelectedMapFile(); if (cmdf != NULL) { const int32_t numMaps = cmdf->getNumberOfMaps(); for (int32_t i = 0; i < numMaps; i++) { this->mapNameComboBox->addItem(cmdf->getMapName(i)); } if ((selectedMapIndex >= 0) && (selectedMapIndex < numMaps)) { this->mapNameComboBox->setCurrentIndex(selectedMapIndex); } } } /** * Called when the user makes a selection from the map name combo box. * * @param indx * Index of item selected. */ void CaretMappableDataFileAndMapSelector::mapNameComboBoxSelected(int /*indx*/) { emit selectionChanged(this); } /** * Called when the new map file tool button is pressed. */ void CaretMappableDataFileAndMapSelector::newMapFileToolButtonSelected() { const DataFileTypeEnum::Enum dataFileType = this->getSelectedMapFileType(); QString fileExtension = DataFileTypeEnum::toFileExtension(dataFileType); QString newFileName = "NewFile"; QString newMapName = "Map Name"; if (m_defaultName.isEmpty() == false) { newFileName = m_defaultName; newMapName = m_defaultName; } newFileName += ("." + fileExtension); WuQDataEntryDialog newFileMapDialog("New Map File and Map", this->widget); QLineEdit* mapFileNameLineEdit = newFileMapDialog.addLineEditWidget("New Map File Name", newFileName); QLineEdit* mapNameLineEdit = newFileMapDialog.addLineEditWidget("New Map Name", newMapName); if (newFileMapDialog.exec() == WuQDataEntryDialog::Accepted) { QString mapFileName = mapFileNameLineEdit->text(); const QString mapName = mapNameLineEdit->text(); try { if (mapFileName.endsWith(fileExtension) == false) { mapFileName += ("." + fileExtension); } const StructureEnum::Enum structure = getSelectedMapFileStructure(); BrainStructure* brainStructure = GuiManager::get()->getBrain()->getBrainStructure(structure, false); if (brainStructure == NULL) { throw DataFileException(newFileName, "Invalid brain structure (not loaded): " + StructureEnum::toGuiName(structure)); } const int32_t numberOfNodes = brainStructure->getNumberOfNodes(); if (numberOfNodes <= 0) { throw DataFileException(newFileName, "Invalid number of nodes (0) in brain structure: " + StructureEnum::toGuiName(structure)); } switch (dataFileType) { case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: { AString errorMessage; CiftiMappableDataFile* ciftiMappableDataFile = CiftiMappableDataFile::newInstanceForCiftiFileTypeAndSurface(DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL, structure, numberOfNodes, errorMessage); if (ciftiMappableDataFile == NULL) { throw DataFileException(mapFileName, errorMessage); } CaretAssert(dynamic_cast(ciftiMappableDataFile) != NULL); if (ciftiMappableDataFile != NULL) { ciftiMappableDataFile->setMapName(0, mapName); ciftiMappableDataFile->setFileName(mapFileName); EventManager::get()->sendEvent(EventDataFileAdd(ciftiMappableDataFile).getPointer()); } else { throw DataFileException(mapFileName, errorMessage); } } break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: { AString errorMessage; CiftiMappableDataFile* ciftiMappableDataFile = CiftiMappableDataFile::newInstanceForCiftiFileTypeAndSurface(DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR, structure, numberOfNodes, errorMessage); if (ciftiMappableDataFile == NULL) { throw DataFileException(mapFileName, errorMessage); } CaretAssert(dynamic_cast(ciftiMappableDataFile) != NULL); if (ciftiMappableDataFile != NULL) { ciftiMappableDataFile->setMapName(0, mapName); ciftiMappableDataFile->setFileName(mapFileName); EventManager::get()->sendEvent(EventDataFileAdd(ciftiMappableDataFile).getPointer()); } else { throw DataFileException(mapFileName, errorMessage); } } break; case DataFileTypeEnum::LABEL: { LabelFile* labelFile = new LabelFile(); labelFile->setNumberOfNodesAndColumns(numberOfNodes, 1); labelFile->setMapName(0, mapName); labelFile->setStructure(structure); labelFile->setFileName(mapFileName); EventManager::get()->sendEvent(EventDataFileAdd(labelFile).getPointer()); } break; case DataFileTypeEnum::METRIC: { MetricFile* metricFile = new MetricFile(); metricFile->setNumberOfNodesAndColumns(numberOfNodes, 1); metricFile->setMapName(0, mapName); metricFile->setStructure((structure)); metricFile->setFileName(mapFileName); EventManager::get()->sendEvent(EventDataFileAdd(metricFile).getPointer()); } break; default: CaretAssertMessage(0, ("File Type " + DataFileTypeEnum::toName(dataFileType) + " not allowed.")); break; } this->loadMapFileComboBox(0); const int numMapFiles = this->mapFileComboBox->count(); if (numMapFiles > 0) { this->setMapFileComboBoxCurrentIndex(numMapFiles - 1); } this->setMapNameComboBoxCurrentIndex(0); emit selectionChanged(this); } catch (const DataFileException& dfe) { WuQMessageBox::errorOk(this->widget, dfe.whatString()); } } } /** * @return The widget is for displaying this selector. */ QWidget* CaretMappableDataFileAndMapSelector::getWidget() { return this->widget; } /** * Called when the new map tool button is pressed. */ void CaretMappableDataFileAndMapSelector::newMapToolButtonSelected() { CaretMappableDataFile* mapFile = this->getSelectedMapFile(); if (mapFile != NULL) { const StructureEnum::Enum structure = getSelectedMapFileStructure(); if ( ! mapFile->isMappableToSurfaceStructure(structure)) { WuQMessageBox::errorOk(this->getWidget(), "The selected file cannot be mapped to the given structure, use the New button to create a new file."); return; } QString presetMapName = "Map Name"; if (m_defaultName.isEmpty() == false) { presetMapName = m_defaultName; } bool valid = false; const QString newMapName = QInputDialog::getText(this->mapFileComboBox, "Map Name", "Map Name", QLineEdit::Normal, presetMapName, &valid); if (valid) { try { GiftiTypeFile* gtf = dynamic_cast(mapFile); int32_t mapIndex = 0; if (gtf != NULL ) { gtf->addMaps(gtf->getNumberOfNodes(), 1); mapIndex = gtf->getNumberOfMaps() - 1; gtf->setMapName(mapIndex, newMapName); this->loadMapNameComboBox(mapIndex); } else { CaretAssertMessage(0, "Add support for non-GIFTI files !!!!"); } this->loadLabelNameComboBox(); } catch (const DataFileException& e) { WuQMessageBox::errorOk(this->getWidget(), e.whatString()); } } } else { WuQMessageBox::errorOk(this->getWidget(), "The selected file is invalid, use the New button to create a new file."); } } /** * @return The selected map file. Value will be NULL * if no map file is selected. */ CaretMappableDataFile* CaretMappableDataFileAndMapSelector::getSelectedMapFile() { const int indx = this->mapFileComboBox->currentIndex(); if ((indx >= 0) && (indx < this->mapFileComboBox->count())) { void* pointer = this->mapFileComboBox->itemData(indx).value(); CaretMappableDataFile* cmdf = (CaretMappableDataFile*)pointer; return cmdf; } return NULL; } /** * @return The index of the selected map. Will be negative * value if there is no map file or the map file contains * no maps. */ int32_t CaretMappableDataFileAndMapSelector::getSelectedMapIndex() { const int indx = this->mapNameComboBox->currentIndex(); CaretMappableDataFile* cmdf = this->getSelectedMapFile(); if (cmdf != NULL) { if ((indx >= 0) && (indx < cmdf->getNumberOfMaps())) { return indx; } } return -1; } /** * @return The name of the selected map file type. */ AString CaretMappableDataFileAndMapSelector::getNameOfSelectedMapFileType() { const DataFileTypeEnum::Enum dataFileType = this->getSelectedMapFileType(); const AString name = DataFileTypeEnum::toGuiName(dataFileType); return name; } /** * @return The selected map file type. */ DataFileTypeEnum::Enum CaretMappableDataFileAndMapSelector::getSelectedMapFileType() const { int32_t indx = this->mapFileTypeComboBox->currentIndex(); if (indx < 0) { indx = 0; } if ((indx >= 0) && (indx < this->mapFileTypeComboBox->count())) { const int32_t integerCode = this->mapFileTypeComboBox->itemData(indx).toInt(); DataFileTypeEnum::Enum dataFileType = DataFileTypeEnum::fromIntegerCode(integerCode, NULL); return dataFileType; } CaretAssertMessage(0, "Invalid data file type"); return DataFileTypeEnum::UNKNOWN; } /** * @return The selected structure. */ StructureEnum::Enum CaretMappableDataFileAndMapSelector::getSelectedMapFileStructure() const { return m_mapFileStructureComboBox->getSelectedStructure(); } /** * Are the selections valid? * @param errorMessageOut * Contains error messages on output if selections * are not valid. * @return true if the selections are valid, else false. */ bool CaretMappableDataFileAndMapSelector::isValidSelections(AString& errorMessageOut) { errorMessageOut = ""; if (this->getSelectedMapFileType() == DataFileTypeEnum::UNKNOWN) { errorMessageOut = "Selected file type is invalid."; } else if (this->getSelectedMapFile() == NULL) { errorMessageOut = "No map file is selected, create a file with New button."; } else if (this->getSelectedMapIndex() < 0) { errorMessageOut = "No map is selected, create a map with New button."; } const bool valid = errorMessageOut.isEmpty(); return valid; } /** * Called when a selection is made from the label combo box. * @param indx * Index of selection. */ void CaretMappableDataFileAndMapSelector::labelNameComboBoxSelected(int /*indx*/) { emit selectionChanged(this); } /** * Called when a selection is made from the label combo box. * @param value * New value. */ void CaretMappableDataFileAndMapSelector::floatValueChanged(double /*value*/) { emit selectionChanged(this); } /** * Load the label names into the label selection combo box. */ void CaretMappableDataFileAndMapSelector::loadLabelNameComboBox() { const int32_t selectedKey = this->getSelectedLabelKey(); this->labelSelectionComboBox->clear(); CaretMappableDataFile* cmdf = this->getSelectedMapFile(); if (cmdf != NULL) { if (cmdf->isMappedWithLabelTable()) { const int32_t mapIndex = getSelectedMapIndex(); if (mapIndex >= 0) { GiftiLabelTable* labelTable = cmdf->getMapLabelTable(mapIndex); int32_t selectedIndex = 0; std::vector labelKeys = labelTable->getLabelKeysSortedByName(); const int numKeys = static_cast(labelKeys.size()); for (int32_t i = 0; i < numKeys; i++) { const int32_t key = labelKeys[i]; if (selectedKey == key) { selectedIndex = i; } const AString name = labelTable->getLabelName(key); this->labelSelectionComboBox->addItem(name, (int)key); } if ((selectedIndex >= 0) && (selectedIndex < this->labelSelectionComboBox->count())) { this->labelSelectionComboBox->setCurrentIndex(selectedIndex); } } } } } /** * Display the label editor. */ void CaretMappableDataFileAndMapSelector::showLabelsEditor() { CaretMappableDataFile* cmdf = this->getSelectedMapFile(); if (cmdf != NULL) { if (cmdf->isMappedWithLabelTable()) { const int32_t mapIndex = getSelectedMapIndex(); if (mapIndex >= 0) { GiftiLabelTable* labelTable = cmdf->getMapLabelTable(mapIndex); GiftiLabelTableEditor labelsEditor(cmdf, mapIndex, "Edit Labels", GiftiLabelTableEditor::OPTION_NONE, this->getWidget()); const int dialogResult = labelsEditor.exec(); this->loadLabelNameComboBox(); if (dialogResult == GiftiLabelTableEditor::Accepted) { const AString labelName = labelsEditor.getLastSelectedLabelName(); const int32_t labelKey = labelTable->getLabelKeyFromName(labelName); const int labelIndex = this->labelSelectionComboBox->findData((int)labelKey); if (labelIndex >= 0) { if (labelKey != labelTable->getUnassignedLabelKey()) { this->labelSelectionComboBox->setCurrentIndex(labelIndex); } } } } } } } /** * @return The metric value from the metric value spin box. */ float CaretMappableDataFileAndMapSelector::getSelectedMetricValue() const { const float value = m_floatValueSpinBox->value(); return value; } /** * @return Key of the selected label. */ int32_t CaretMappableDataFileAndMapSelector::getSelectedLabelKey() const { int32_t key = 0; const int indx = this->labelSelectionComboBox->currentIndex(); if ((indx >= 0) && (indx < this->labelSelectionComboBox->count())) { key = this->labelSelectionComboBox->itemData(indx).toInt(); } return key; } /** * @return Name of the selected label, empty string if no selection. */ AString CaretMappableDataFileAndMapSelector::getSelectedLabelName() const { AString name = ""; const int indx = this->labelSelectionComboBox->currentIndex(); if ((indx >= 0) && (indx < this->labelSelectionComboBox->count())) { name = this->labelSelectionComboBox->currentText(); } return name; } /** * Load the last selection that matches the given data file type. If the file type is unknown, * then just find the last selection of any kind. * * @param dataFileTypeIn * Last selected data file type. */ void CaretMappableDataFileAndMapSelector::loadLastSelectionsForFileType(const DataFileTypeEnum::Enum dataFileTypeIn) { DataFileTypeEnum::Enum dataFileType = dataFileTypeIn; StructureEnum::Enum structure = StructureEnum::INVALID; if (dataFileType != DataFileTypeEnum::UNKNOWN) { structure = getSelectedMapFileStructure(); } PreviousSelection* ps = getPreviousSelection(dataFileType, structure); // if (dataFileType == DataFileTypeEnum::UNKNOWN) { // dataFileType = DataFileTypeEnum::LABEL; // //// if (this->brainStructure->getNumberOfLabelFiles() > 0) { //// dataFileType = DataFileTypeEnum::LABEL; //// } //// else if (this->brainStructure->getNumberOfMetricFiles() > 0) { //// dataFileType = DataFileTypeEnum::METRIC; //// } // } // const int mapTypeIndex = this->mapFileTypeComboBox->findData((int)dataFileType); // if (mapTypeIndex >= 0) { // this->setMapFileTypeComboBoxCurrentIndex(mapTypeIndex); // } if (ps != NULL) { const int dataFileTypeInt = DataFileTypeEnum::toIntegerCode(ps->m_dataFileType); const int mapFileTypeIndex = mapFileTypeComboBox->findData(dataFileTypeInt); if (mapFileTypeIndex >= 0) { this->setMapFileTypeComboBoxCurrentIndex(mapFileTypeIndex); } m_mapFileStructureComboBox->setSelectedStructure(ps->m_structure); const int fileIndex = this->mapFileComboBox->findData(qVariantFromValue((void*)ps->m_mapFile)); if (fileIndex >= 0) { this->setMapFileComboBoxCurrentIndex(fileIndex); const int mapIndex = ps->m_mapFile->getMapIndexFromName(ps->m_mapName); if (mapIndex >= 0) { this->setMapNameComboBoxCurrentIndex(mapIndex); } if ( ! ps->m_labelName.isEmpty()) { this->labelSelectionComboBox->clear(); loadLabelNameComboBox(); const int labelIndex = labelSelectionComboBox->findText(ps->m_labelName); if (labelIndex >= 0) { this->labelSelectionComboBox->setCurrentIndex(labelIndex); } } m_floatValueSpinBox->blockSignals(true); m_floatValueSpinBox->setValue(ps->m_scalarValue); m_floatValueSpinBox->blockSignals(false); } } enableDisableNewMapAction(); } /** * Save the current selections. User of this selector * MUST call this to save the selections so that they * can be initialized the next time a selector for the * brain structure is used. */ void CaretMappableDataFileAndMapSelector::saveCurrentSelections() { DataFileTypeEnum::Enum dataFileType = DataFileTypeEnum::UNKNOWN; StructureEnum::Enum structure = StructureEnum::INVALID; CaretMappableDataFile* cmdf = getSelectedMapFile(); if (cmdf != NULL) { dataFileType = cmdf->getDataFileType(); structure = m_mapFileStructureComboBox->getSelectedStructure(); AString mapName = cmdf->getMapName(getSelectedMapIndex()); PreviousSelection* ps = new PreviousSelection(structure, dataFileType, cmdf, mapName, labelSelectionComboBox->currentText(), m_floatValueSpinBox->value()); previousSelections.push_back(ps); } } /** * Get the previous selections for a data file type and structure. * * @param dataFileType * Data file type. If UNKNOWN, match to any file type. * @param structure * Structure for which previous selections are desired. * @return * Pointer to matching previous selection or NULL if no match * with a valid data file. */ CaretMappableDataFileAndMapSelector::PreviousSelection* CaretMappableDataFileAndMapSelector::getPreviousSelection(const DataFileTypeEnum::Enum dataFileType, const StructureEnum::Enum structure) { std::vector allMapFiles; GuiManager::get()->getBrain()->getAllMappableDataFiles(allMapFiles); for (std::vector::reverse_iterator iter = previousSelections.rbegin(); iter != previousSelections.rend(); iter++) { PreviousSelection* ps = *iter; bool matchFlag = false; if (dataFileType == DataFileTypeEnum::UNKNOWN) { matchFlag = true; } else if ((ps->m_dataFileType == dataFileType) && (ps->m_structure == structure)) { matchFlag = true; } if (matchFlag) { if (std::find(allMapFiles.begin(), allMapFiles.end(), ps->m_mapFile) != allMapFiles.end()) { return ps; } } } return NULL; } connectome-workbench-1.4.2/src/GuiQt/CaretMappableDataFileAndMapSelector.h000066400000000000000000000155271360521144700265120ustar00rootroot00000000000000#ifndef __CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTOR__H_ #define __CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTOR__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" #include "CaretMappableDataFile.h" #include "DataFileTypeEnum.h" #include "StructureEnum.h" #include "WuQWidget.h" class QAction; class QComboBox; class QDoubleSpinBox; class QLineEdit; class QStackedWidget; namespace caret { class Brain; class BrainStructure; class CiftiBrainordinateScalarFile; class GiftiTypeFile; class LabelFile; class MetricFile; class StructureEnumComboBox; class WuQWidgetObjectGroup; class CaretMappableDataFileAndMapSelector : public WuQWidget { Q_OBJECT public: CaretMappableDataFileAndMapSelector(const AString defaultName, Brain* brain, const std::vector& supportedMapFileTypes, const std::vector& supportedStructures, QObject* parent); virtual ~CaretMappableDataFileAndMapSelector(); QWidget* getWidget(); CaretMappableDataFile* getSelectedMapFile(); DataFileTypeEnum::Enum getSelectedMapFileType() const; StructureEnum::Enum getSelectedMapFileStructure() const; int32_t getSelectedMapIndex(); AString getNameOfSelectedMapFileType(); bool isValidSelections(AString& errorMessageOut); float getSelectedMetricValue() const; int32_t getSelectedLabelKey() const; AString getSelectedLabelName() const; void saveCurrentSelections(); signals: void selectionChanged(CaretMappableDataFileAndMapSelector*); private: CaretMappableDataFileAndMapSelector(const CaretMappableDataFileAndMapSelector&); CaretMappableDataFileAndMapSelector& operator=(const CaretMappableDataFileAndMapSelector&); private slots: void mapFileTypeComboBoxSelected(int); void mapFileStructureComboBoxSelected(const StructureEnum::Enum); void mapFileComboBoxSelected(int); void mapNameComboBoxSelected(int); void labelNameComboBoxSelected(int); void floatValueChanged(double); void newMapFileToolButtonSelected(); void newMapToolButtonSelected(); void showLabelsEditor(); private: void setMapFileTypeComboBoxCurrentIndex(int indx); void setMapFileComboBoxCurrentIndex(int indx); void setMapNameComboBoxCurrentIndex(int indx); void loadMapFileComboBox(const int32_t selectedFileIndex); void loadMapNameComboBox(const int32_t selectedMapIndex); void loadLabelNameComboBox(); void updateFileTypeSelections(const DataFileTypeEnum::Enum dataFileType); void enableDisableNewMapAction(); QWidget* widget; QComboBox* mapFileTypeComboBox; StructureEnumComboBox* m_mapFileStructureComboBox; QComboBox* mapFileComboBox; QComboBox* mapNameComboBox; QAction* m_newMapAction; Brain* m_brain; QWidget* m_valueWidgetFloat; WuQWidgetObjectGroup* m_floatValueControlsGroup; QDoubleSpinBox* m_floatValueSpinBox; QWidget* valueWidgetLabel; WuQWidgetObjectGroup* labelValueControlsGroup; QComboBox* labelSelectionComboBox; QStackedWidget* valueEntryStackedWidget; std::vector m_supportedMapFileTypes; std::vector m_supportedStructures; std::vector m_mapFileTypesThatAllowAddingMaps; AString m_defaultName; class PreviousSelection { public: StructureEnum::Enum m_structure; DataFileTypeEnum::Enum m_dataFileType; CaretMappableDataFile* m_mapFile; AString m_mapName; AString m_labelName; float m_scalarValue; PreviousSelection(const StructureEnum::Enum structure, const DataFileTypeEnum::Enum dataFileType, CaretMappableDataFile* mapFile, const AString& mapName, const AString& labelName, const float scalarValue) { m_structure = structure; m_dataFileType = dataFileType; m_mapFile = mapFile; m_mapName = mapName; m_labelName = labelName; m_scalarValue = scalarValue; } bool operator=(const PreviousSelection& ps) const { if ((m_structure == ps.m_structure) && (m_dataFileType == ps.m_dataFileType)) { return true; } return false; } }; PreviousSelection* getPreviousSelection(const DataFileTypeEnum::Enum dataFileType, const StructureEnum::Enum structure); void loadLastSelectionsForFileType(const DataFileTypeEnum::Enum dataFileType); static std::vector previousSelections; }; #ifdef __CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTOR_DECLARE__ std::vector CaretMappableDataFileAndMapSelector::previousSelections; #endif // __CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTOR_DECLARE__ } // namespace #endif //__CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTOR__H_ connectome-workbench-1.4.2/src/GuiQt/CaretMappableDataFileAndMapSelectorObject.cxx000066400000000000000000000234151360521144700302070ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTOR_OBJECT_DECLARE__ #include "CaretMappableDataFileAndMapSelectorObject.h" #undef __CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTOR_OBJECT_DECLARE__ #include #include #include "CaretAssert.h" #include "CaretDataFileSelectionComboBox.h" #include "CaretMappableDataFile.h" #include "CaretMappableDataFileAndMapSelectionModel.h" #include "GuiManager.h" #include "WuQEventBlockingFilter.h" using namespace caret; /** * \class caret::CaretMappableDataFileAndMapSelectorObject * \brief Widgets for selecting a map file and map index. * \ingroup GuiQt */ /** * Constructor that creates a selection object. User will need to * insert a model into an instance created with this constructor. * This constructor is used when the selection model is stored * in another object. * * @param options * Options for this instance. * @param parent * Parent of this instance. */ CaretMappableDataFileAndMapSelectorObject::CaretMappableDataFileAndMapSelectorObject(const Options options, QObject* parent) : QObject(parent) { m_model = NULL; initializeConstruction(options); m_needToDestroyModelFlag = false; } /** * Constructor that creates a selection object with a model for the selected * data file type. * * @param dataFileType * File type for selection * @param options * Options for this instance. * @param parent * Parent of this instance. */ CaretMappableDataFileAndMapSelectorObject::CaretMappableDataFileAndMapSelectorObject(const DataFileTypeEnum::Enum dataFileType, const Options options, QObject* parent) : QObject(parent) { m_model = new CaretMappableDataFileAndMapSelectionModel(dataFileType); initializeConstruction(options); m_needToDestroyModelFlag = true; } /** * Constructor that creates a selection object with a model for the selected * data file types. * * @param dataFileTypes * File types for selection * @param options * Options for this instance. * @param parent * Parent of this instance. */ CaretMappableDataFileAndMapSelectorObject::CaretMappableDataFileAndMapSelectorObject(const std::vector& dataFileTypes, const Options options, QObject* parent) : QObject(parent) { m_model = new CaretMappableDataFileAndMapSelectionModel(dataFileTypes); initializeConstruction(options); m_needToDestroyModelFlag = true; } /** * Destructor. */ CaretMappableDataFileAndMapSelectorObject::~CaretMappableDataFileAndMapSelectorObject() { if (m_needToDestroyModelFlag) { delete m_model; m_model = NULL; } } /** * Assist with construction. * * @param options * Options for this instance. */ void CaretMappableDataFileAndMapSelectorObject::initializeConstruction(const Options options) { m_enabled = true; m_mapFileComboBox = new CaretDataFileSelectionComboBox(this); QObject::connect(m_mapFileComboBox, SIGNAL(fileSelected(CaretDataFile*)), this, SLOT(mapFileComboBoxFileSelected(CaretDataFile*))); m_mapIndexSpinBox = NULL; if (options & OPTION_SHOW_MAP_INDEX_SPIN_BOX) { m_mapIndexSpinBox = new QSpinBox(); m_mapIndexSpinBox->setMinimum(1); m_mapIndexSpinBox->setSingleStep(1); QObject::connect(m_mapIndexSpinBox, SIGNAL(valueChanged(int)), this, SLOT(mapIndexSpinBoxValuesChanged(int))); } m_mapNameComboBox = new QComboBox(); QObject::connect(m_mapNameComboBox, SIGNAL(activated(int)), this, SLOT(mapNameComboBoxActivated(int))); WuQEventBlockingFilter::blockMouseWheelEventInMacComboBox(m_mapNameComboBox); } /** * Update the model in this file and map selector. * * @param model * The model. */ void CaretMappableDataFileAndMapSelectorObject::updateFileAndMapSelector(CaretMappableDataFileAndMapSelectionModel* model) { CaretAssert(model); m_model = model; m_mapFileComboBox->updateComboBox(model->getCaretDataFileSelectionModel()); updateContent(); } /** * @return Model in this file and map selector. */ CaretMappableDataFileAndMapSelectionModel* CaretMappableDataFileAndMapSelectorObject::getModel() { return m_model; } /** * Get the widgets for this file and map selector. * * @param mapFileComboBox * Combo box for file selection. * @param mapIndexSpinBox * Spin box for map index selection. * @param mapNameComboBox * Combo box for map name selection. */ void CaretMappableDataFileAndMapSelectorObject::getWidgetsForAddingToLayout(QWidget* &mapFileComboBox, QWidget* &mapIndexSpinBox, QWidget* &mapNameComboBox) { mapFileComboBox = m_mapFileComboBox->getWidget(); mapIndexSpinBox = m_mapIndexSpinBox; mapNameComboBox = m_mapNameComboBox; } /** * Update the content of this object. */ void CaretMappableDataFileAndMapSelectorObject::updateContent() { bool validFlag = false; bool validMapsFlag = false; if (m_model != NULL) { CaretMappableDataFile* mapFile = m_model->getSelectedFile(); if (mapFile != NULL) { validFlag = true; const int32_t numMaps = mapFile->getNumberOfMaps(); const int32_t mapIndex = m_model->getSelectedMapIndex(); if ((mapIndex >= 0) && (mapIndex < numMaps)) { validMapsFlag = true; if (m_mapIndexSpinBox != NULL) { m_mapIndexSpinBox->blockSignals(true); m_mapIndexSpinBox->setMaximum(numMaps); m_mapIndexSpinBox->blockSignals(false); } m_mapNameComboBox->clear(); for (int32_t i = 0; i < numMaps; i++) { m_mapNameComboBox->addItem(mapFile->getMapName(i)); } if (m_mapIndexSpinBox != NULL) { /* * Note: Indices are zero to num-maps minus 1 * but show 1 to num-maps */ m_mapIndexSpinBox->blockSignals(true); m_mapIndexSpinBox->setValue(mapIndex + 1); m_mapIndexSpinBox->blockSignals(false); } m_mapNameComboBox->setCurrentIndex(mapIndex); } /* * Dense connectivity does not allow map selection. */ if (mapFile->getDataFileType() == DataFileTypeEnum::CONNECTIVITY_DENSE) { validMapsFlag = false; } } } const bool fileEnabledFlag = (validFlag & m_enabled); m_mapFileComboBox->getWidget()->setEnabled(fileEnabledFlag); const bool mapEnabledFlag = (validMapsFlag && m_enabled); if (m_mapIndexSpinBox != NULL) { m_mapIndexSpinBox->setEnabled(mapEnabledFlag); } m_mapNameComboBox->setEnabled(mapEnabledFlag); } /** * Gets called when a file is selected by the user. * * @param caretDataFile * File that is selected. */ void CaretMappableDataFileAndMapSelectorObject::mapFileComboBoxFileSelected(CaretDataFile* /*caretDataFile*/) { updateContent(); emit selectionWasPerformed(); } /** * Gets called when a file is selected by the user. * * @param mapIndex * Index of the map. */ void CaretMappableDataFileAndMapSelectorObject::mapIndexSpinBoxValuesChanged(int mapIndex) { if (m_model != NULL) { /* * Note: Indices are zero to num-maps minus 1 * but show 1 to num-maps */ int32_t zeroToOneMapIndex = mapIndex - 1; m_model->setSelectedMapIndex(zeroToOneMapIndex); updateContent(); emit selectionWasPerformed(); } } /** * Gets called when a file is selected by the user. * * @param mapIndex * Index of the map. */ void CaretMappableDataFileAndMapSelectorObject::mapNameComboBoxActivated(int mapIndex) { if (m_model != NULL) { m_model->setSelectedMapIndex(mapIndex); updateContent(); emit selectionWasPerformed(); } } /** * @return Is the selector's widgets enabled. */ bool CaretMappableDataFileAndMapSelectorObject::isEnabled() const { return m_enabled; } /** * Set the selector's widgets enabled. * * @enabled * New enabled status. */ void CaretMappableDataFileAndMapSelectorObject::setEnabled(const bool enabled) { m_enabled = enabled; updateContent(); } connectome-workbench-1.4.2/src/GuiQt/CaretMappableDataFileAndMapSelectorObject.h000066400000000000000000000075601360521144700276370ustar00rootroot00000000000000#ifndef __CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTOR_OBJECT_H__ #define __CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTOR_OBJECT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "DataFileTypeEnum.h" class QComboBox; class QSpinBox; namespace caret { class CaretDataFile; class CaretDataFileSelectionComboBox; class CaretMappableDataFileAndMapSelectionModel; class CaretMappableDataFileAndMapSelectorObject : public QObject { Q_OBJECT public: /** Options for selector */ enum Options { /** Create the map index spin box */ OPTION_SHOW_MAP_INDEX_SPIN_BOX = 1 }; CaretMappableDataFileAndMapSelectorObject(const Options options, QObject* parent); CaretMappableDataFileAndMapSelectorObject(const DataFileTypeEnum::Enum dataFileType, const Options options, QObject* parent); CaretMappableDataFileAndMapSelectorObject(const std::vector& dataFileTypes, const Options options, QObject* parent); void updateFileAndMapSelector(CaretMappableDataFileAndMapSelectionModel* model); CaretMappableDataFileAndMapSelectionModel* getModel(); virtual ~CaretMappableDataFileAndMapSelectorObject(); void getWidgetsForAddingToLayout(QWidget* &mapFileComboBox, QWidget* &mapIndexSpinBox, QWidget* &mapNameComboBox); bool isEnabled() const; void setEnabled(const bool enabled); // ADD_NEW_METHODS_HERE signals: void selectionWasPerformed(); private slots: void mapFileComboBoxFileSelected(CaretDataFile* caretDataFile); void mapIndexSpinBoxValuesChanged(int); void mapNameComboBoxActivated(int); private: CaretMappableDataFileAndMapSelectorObject(const CaretMappableDataFileAndMapSelectorObject&); CaretMappableDataFileAndMapSelectorObject& operator=(const CaretMappableDataFileAndMapSelectorObject&); void initializeConstruction(const Options options); void updateContent(); CaretMappableDataFileAndMapSelectionModel* m_model; bool m_needToDestroyModelFlag; CaretDataFileSelectionComboBox* m_mapFileComboBox; QSpinBox* m_mapIndexSpinBox; QComboBox* m_mapNameComboBox; bool m_enabled; // ADD_NEW_MEMBERS_HERE }; #ifdef __CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTOR_OBJECT_DECLARE__ // #endif // __CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTOR_OBJECT_DECLARE__ } // namespace #endif //__CARET_MAPPABLE_DATA_FILE_AND_MAP_SELECTOR_OBJECT_H__ connectome-workbench-1.4.2/src/GuiQt/ChartHistoryViewController.cxx000066400000000000000000000564041360521144700255320ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #define __CHART_HISTORY_VIEW_CONTROLLER_DECLARE__ #include "ChartHistoryViewController.h" #undef __CHART_HISTORY_VIEW_CONTROLLER_DECLARE__ #include "Brain.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretColorEnumComboBox.h" #include "ChartDataCartesian.h" #include "ChartDataSource.h" #include "ChartModelDataSeries.h" #include "ChartModelFrequencySeries.h" #include "ChartModelTimeSeries.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "EventGraphicsUpdateOneWindow.h" #include "GuiManager.h" #include "ModelChart.h" #include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::ChartHistoryViewController * \brief Shows history of loaded charts in the selected tab. * \ingroup GuiQt */ /** * Constructor. */ ChartHistoryViewController::ChartHistoryViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent) : QWidget(parent), m_orientation(orientation), m_browserWindowIndex(browserWindowIndex), m_objectNamePrefix(parentObjectName + ":History") { WuQMacroManager* macroManager = WuQMacroManager::instance(); m_averageCheckBox = new QCheckBox("Show Average"); WuQtUtilities::setWordWrappedToolTip(m_averageCheckBox, "Display an average of the displayed chart data. " "NOTE: If the charts contain a different number of points " "the average will be that of those charts that contain " "the same number of points as the most recently displayed " "chart."); QObject::connect(m_averageCheckBox, SIGNAL(clicked(bool)), this, SLOT(averageCheckBoxClicked(bool))); m_averageCheckBox->setObjectName(m_objectNamePrefix + ":ShowAverage"); macroManager->addMacroSupportToObject(m_averageCheckBox, "Enable linew chart history average"); QPushButton* clearPushButton = new QPushButton("Clear"); clearPushButton->setFixedWidth(clearPushButton->sizeHint().width() + 20); QObject::connect(clearPushButton, SIGNAL(clicked()), this, SLOT(clearPushButtonClicked())); WuQtUtilities::setWordWrappedToolTip(clearPushButton, "Remove all charts of the selected type in this tab"); clearPushButton->setObjectName(m_objectNamePrefix + ":ClearButton"); macroManager->addMacroSupportToObject(clearPushButton, "Remove line charts in tab"); QLabel* maximumDisplayedLabel = new QLabel("Show last "); m_maximumDisplayedSpinBox = new QSpinBox(); m_maximumDisplayedSpinBox->setMinimum(1); m_maximumDisplayedSpinBox->setMaximum(1000); QObject::connect(m_maximumDisplayedSpinBox, SIGNAL(valueChanged(int)), this, SLOT(maximumDisplayedSpinBoxValueChanged(int))); m_maximumDisplayedSpinBox->setToolTip("Show Last Lines"); m_maximumDisplayedSpinBox->setObjectName(m_objectNamePrefix + ":ShowLastCount"); macroManager->addMacroSupportToObject(m_maximumDisplayedSpinBox, "Set maximum line charts"); QHBoxLayout* maxDisplayedLayout = new QHBoxLayout(); maxDisplayedLayout->addWidget(maximumDisplayedLabel); maxDisplayedLayout->addWidget(m_maximumDisplayedSpinBox); maxDisplayedLayout->addStretch(); WuQtUtilities::setWordWrappedToolTip(m_maximumDisplayedSpinBox, "Maximum number of charts of the selected type " "displayed in this tab"); m_chartDataCheckBoxesSignalMapper = new QSignalMapper(this); QObject::connect(m_chartDataCheckBoxesSignalMapper, SIGNAL(mapped(int)), this, SLOT(chartDataCheckBoxSignalMapped(int))); m_chartDataColorComboBoxesSignalMapper = new QSignalMapper(this); QObject::connect(m_chartDataColorComboBoxesSignalMapper, SIGNAL(mapped(int)), this, SLOT(chartDataColorComboBoxSignalMapped(int))); m_chartDataColorConstructionButtonSignalMapper = new QSignalMapper(this); QObject::connect(m_chartDataColorConstructionButtonSignalMapper, SIGNAL(mapped(int)), this, SLOT(chartDataConstructionToolButtonSignalMapped(int))); QWidget* chartDataWidget = new QWidget(); m_chartDataGridLayout = new QGridLayout(chartDataWidget); m_chartDataGridLayout->setHorizontalSpacing(6); m_chartDataGridLayout->setVerticalSpacing(2); m_chartDataGridLayout->setContentsMargins(0, 0, 0, 0); m_chartDataGridLayout->setColumnStretch(COLUMN_CHART_DATA_CHECKBOX, 0); m_chartDataGridLayout->setColumnStretch(COLUMN_CHART_DATA_CONSTRUCTION, 0); m_chartDataGridLayout->setColumnStretch(COLUMN_CHART_DATA_COLOR, 0); m_chartDataGridLayout->setColumnStretch(COLUMN_CHART_DATA_NAME, 100); m_chartDataGridLayout->addWidget(new QLabel("On"), 0, COLUMN_CHART_DATA_CHECKBOX, Qt::AlignHCenter); m_chartDataGridLayout->addWidget(new QLabel("Move"), 0, COLUMN_CHART_DATA_CONSTRUCTION, Qt::AlignHCenter); m_chartDataGridLayout->addWidget(new QLabel("Color"), 0, COLUMN_CHART_DATA_COLOR, Qt::AlignHCenter); QVBoxLayout* leftOrTopLayout = new QVBoxLayout(); leftOrTopLayout->addWidget(m_averageCheckBox); leftOrTopLayout->addLayout(maxDisplayedLayout); leftOrTopLayout->addWidget(clearPushButton); leftOrTopLayout->addStretch(); QVBoxLayout* rightOrBottomLayout = new QVBoxLayout(); rightOrBottomLayout->addWidget(chartDataWidget); rightOrBottomLayout->addStretch(); switch (m_orientation) { case Qt::Horizontal: { m_chartDataGridLayout->addWidget(new QLabel("Name"), 0, COLUMN_CHART_DATA_NAME, Qt::AlignHCenter); QHBoxLayout* layout = new QHBoxLayout(this); layout->addLayout(leftOrTopLayout, 0); layout->addWidget(WuQtUtilities::createVerticalLineWidget()); layout->addLayout(rightOrBottomLayout, 100); layout->addStretch(); } break; case Qt::Vertical: { QVBoxLayout* layout = new QVBoxLayout(this); layout->addLayout(leftOrTopLayout, 0); layout->addLayout(rightOrBottomLayout, 100); layout->addStretch(); } break; } EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); } /** * Destructor. */ ChartHistoryViewController::~ChartHistoryViewController() { EventManager::get()->removeAllEventsFromListener(this); } /** * Gets called when the average checkbox is clicked. * * @param clicked * New status. */ void ChartHistoryViewController::averageCheckBoxClicked(bool clicked) { ChartModel* chartModel = NULL; int32_t tabIndex = -1; getSelectedChartModelAndTab(chartModel, tabIndex); if (chartModel == NULL) { return; } chartModel->setAverageChartDisplaySelected(clicked); updateAfterSelectionsChanged(); } /** * Called when clear push button is clicked. */ void ChartHistoryViewController::clearPushButtonClicked() { ChartModel* chartModel = NULL; int32_t tabIndex = -1; getSelectedChartModelAndTab(chartModel, tabIndex); if (chartModel == NULL) { return; } chartModel->removeChartData(); updateAfterSelectionsChanged(); } /** * Called when maximum number of displayed charts is changed. * * @param value * New value. */ void ChartHistoryViewController::maximumDisplayedSpinBoxValueChanged(int value) { ChartModel* chartModel = NULL; int32_t tabIndex = -1; getSelectedChartModelAndTab(chartModel, tabIndex); if (chartModel == NULL) { return; } switch (chartModel->getChartSelectionMode()) { case ChartSelectionModeEnum::CHART_SELECTION_MODE_SINGLE: break; case ChartSelectionModeEnum::CHART_SELECTION_MODE_ANY: chartModel->setMaximumNumberOfChartDatasToDisplay(value); break; } updateAfterSelectionsChanged(); } /** * Update after selections in this view controller are changed. */ void ChartHistoryViewController::updateAfterSelectionsChanged() { EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(m_browserWindowIndex).getPointer()); updateHistoryViewController(); } /** * Update this view controller. */ void ChartHistoryViewController::updateHistoryViewController() { ChartModel* chartModel = NULL; int32_t tabIndex = -1; getSelectedChartModelAndTab(chartModel, tabIndex); if (chartModel == NULL) { return; } switch (chartModel->getChartSelectionMode()) { case ChartSelectionModeEnum::CHART_SELECTION_MODE_ANY: m_maximumDisplayedSpinBox->setEnabled(true); m_maximumDisplayedSpinBox->setValue(chartModel->getMaximumNumberOfChartDatasToDisplay()); break; case ChartSelectionModeEnum::CHART_SELECTION_MODE_SINGLE: m_maximumDisplayedSpinBox->setValue(1); m_maximumDisplayedSpinBox->setEnabled(false); break; } WuQMacroManager* macroManager = WuQMacroManager::instance(); const std::vector chartDataVector = chartModel->getAllChartDatas(); const int32_t numData = static_cast(chartDataVector.size()); const int32_t numWidgetRows = static_cast(m_chartDataCheckBoxes.size()); const int32_t maxItems = std::max(numData, numWidgetRows); for (int32_t i = 0; i < maxItems; i++) { if (i >= static_cast(m_chartDataCheckBoxes.size())) { const QString numberString(QString("%1").arg((int)i+1, 2, 10, QLatin1Char('0'))); /* * Checkbox */ QCheckBox* checkBox = new QCheckBox(" "); QObject::connect(checkBox, SIGNAL(clicked(bool)), m_chartDataCheckBoxesSignalMapper, SLOT(map())); m_chartDataCheckBoxesSignalMapper->setMapping(checkBox, i); m_chartDataCheckBoxes.push_back(checkBox); checkBox->setToolTip("Show Chart Line"); checkBox->setObjectName(m_objectNamePrefix + ":ShowChartLine" + numberString); macroManager->addMacroSupportToObject(checkBox, "Show line chart " + numberString); /* * Construction Tool Button */ QIcon constructionIcon; const bool constructionIconValid = WuQtUtilities::loadIcon(":/LayersPanel/construction.png", constructionIcon); QToolButton* constructionToolButton = new QToolButton(); if (constructionIconValid) { constructionToolButton->setIcon(constructionIcon); } else { constructionToolButton->setText("M"); } m_chartDataContructionToolButtons.push_back(constructionToolButton); QObject::connect(constructionToolButton, SIGNAL(clicked()), m_chartDataColorConstructionButtonSignalMapper, SLOT(map())); m_chartDataColorConstructionButtonSignalMapper->setMapping(constructionToolButton, i); /* * Color */ CaretColorEnumComboBox* colorComboBox = new CaretColorEnumComboBox(this); QObject::connect(colorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), m_chartDataColorComboBoxesSignalMapper, SLOT(map())); m_chartDataColorComboBoxesSignalMapper->setMapping(colorComboBox, i); m_chartDataColorComboBoxes.push_back(colorComboBox); colorComboBox->getWidget()->setToolTip("Select Color"); colorComboBox->getWidget()->setObjectName(m_objectNamePrefix + ":Color" + numberString); macroManager->addMacroSupportToObject(colorComboBox->getWidget(), "Set line chart " + numberString + " color"); /* * Label */ m_chartDataNameLabels.push_back(new QLabel()); /* * Layout */ const int widgetIndex = static_cast(m_chartDataCheckBoxes.size()) - 1; CaretAssertVectorIndex(m_chartDataCheckBoxes, widgetIndex); const int row = m_chartDataGridLayout->rowCount(); m_chartDataGridLayout->addWidget(m_chartDataCheckBoxes[widgetIndex], row, COLUMN_CHART_DATA_CHECKBOX); m_chartDataGridLayout->addWidget(constructionToolButton, row, COLUMN_CHART_DATA_CONSTRUCTION); m_chartDataGridLayout->addWidget(m_chartDataColorComboBoxes[widgetIndex]->getWidget(), row, COLUMN_CHART_DATA_COLOR); switch (m_orientation) { case Qt::Horizontal: { m_chartDataGridLayout->addWidget(m_chartDataNameLabels[widgetIndex], row, COLUMN_CHART_DATA_NAME); } break; case Qt::Vertical: { const int nextRow = m_chartDataGridLayout->rowCount(); m_chartDataGridLayout->addWidget(m_chartDataNameLabels[widgetIndex], nextRow, COLUMN_CHART_DATA_CHECKBOX, 1, COLUMN_COUNT, Qt::AlignLeft); } break; } } CaretAssertVectorIndex(m_chartDataCheckBoxes, i); CaretAssertVectorIndex(m_chartDataContructionToolButtons, i); CaretAssertVectorIndex(m_chartDataColorComboBoxes, i); CaretAssertVectorIndex(m_chartDataNameLabels, i); QCheckBox* checkBox = m_chartDataCheckBoxes[i]; QToolButton* constructToolButton = m_chartDataContructionToolButtons[i]; CaretColorEnumComboBox* colorComboBox = m_chartDataColorComboBoxes[i]; QLabel* nameLabel = m_chartDataNameLabels[i]; bool showRowFlag = false; if (i < numData) { showRowFlag = true; const ChartData* chartData = chartDataVector[i]; const ChartDataCartesian* chartDataCartesian = dynamic_cast(chartData); const ChartDataSource* dataSource = chartData->getChartDataSource(); checkBox->setChecked(chartData->isSelected(tabIndex)); if (chartDataCartesian != NULL) { colorComboBox->setSelectedColor(chartDataCartesian->getColor()); colorComboBox->getWidget()->setEnabled(true); } else { colorComboBox->getWidget()->setEnabled(false); } nameLabel->setText(dataSource->getDescription()); } checkBox->setVisible(showRowFlag); constructToolButton->setVisible(showRowFlag); colorComboBox->getWidget()->setVisible(showRowFlag); nameLabel->setVisible(showRowFlag); } /* * Update averaging. */ bool enableAvergeWidgetsFlag = false; if (chartModel != NULL) { if (chartModel->isAverageChartDisplaySupported()) { enableAvergeWidgetsFlag = true; m_averageCheckBox->setChecked(chartModel->isAverageChartDisplaySelected()); } } m_averageCheckBox->setEnabled(enableAvergeWidgetsFlag); } /** * Get the chart model and the selected tab. * * @param chartModelOut * Output containing chart model (may be NULL). * @param tabIndexOut * Output containing tab index (negative if invalid). */ void ChartHistoryViewController::getSelectedChartModelAndTab(ChartModel* &chartModelOut, int32_t& tabIndexOut) { chartModelOut = NULL; tabIndexOut = -1; Brain* brain = GuiManager::get()->getBrain(); BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } tabIndexOut = browserTabContent->getTabNumber(); ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { switch (modelChart->getSelectedChartOneDataType(tabIndexOut)) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: chartModelOut = modelChart->getSelectedDataSeriesChartModel(tabIndexOut); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: chartModelOut = modelChart->getSelectedFrequencySeriesChartModel(tabIndexOut); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: chartModelOut = modelChart->getSelectedTimeSeriesChartModel(tabIndexOut); break; } } } /** * Called when a check box is changed. * * @param indx * Index of checkbox. */ void ChartHistoryViewController::chartDataCheckBoxSignalMapped(int indx) { CaretAssertVectorIndex(m_chartDataCheckBoxes, indx); ChartModel* chartModel = NULL; int32_t tabIndex = -1; getSelectedChartModelAndTab(chartModel, tabIndex); if (chartModel == NULL) { return; } std::vector chartDataVector = chartModel->getAllChartDatas(); CaretAssertVectorIndex(chartDataVector, indx); chartDataVector[indx]->setSelected(tabIndex, m_chartDataCheckBoxes[indx]->isChecked()); updateAfterSelectionsChanged(); } /** * Called when a check box is changed. * * @param indx * Index of checkbox. */ void ChartHistoryViewController::chartDataColorComboBoxSignalMapped(int indx) { CaretAssertVectorIndex(m_chartDataColorComboBoxes, indx); ChartModel* chartModel = NULL; int32_t tabIndex = -1; getSelectedChartModelAndTab(chartModel, tabIndex); if (chartModel == NULL) { return; } std::vector chartDataVector = chartModel->getAllChartDatas(); CaretAssertVectorIndex(chartDataVector, indx); ChartDataCartesian* chartDataCartesian = dynamic_cast(chartDataVector[indx]); if (chartDataCartesian != NULL) { chartDataCartesian->setColor(m_chartDataColorComboBoxes[indx]->getSelectedColor()); } updateAfterSelectionsChanged(); } /** * Called when construction tool button is clicked * * @param indx * Index of tool button. */ void ChartHistoryViewController::chartDataConstructionToolButtonSignalMapped(int indx) { CaretAssertVectorIndex(m_chartDataContructionToolButtons, indx); ChartModel* chartModel = NULL; int32_t tabIndex = -1; getSelectedChartModelAndTab(chartModel, tabIndex); if (chartModel == NULL) { return; } std::vector chartDataVector = chartModel->getAllChartDatas(); const int32_t numCharts = static_cast(chartDataVector.size()); QMenu menu(m_chartDataContructionToolButtons[indx]); QAction* moveUpAction = menu.addAction("Move Chart Up"); if (indx <= 0) { moveUpAction->setEnabled(false); } QAction* moveDownAction = menu.addAction("Move Chart Down"); if (indx >= (numCharts - 1)) { moveDownAction->setEnabled(false); } QAction* removeAction = menu.addAction("Remove Chart"); QAction* selectedAction = menu.exec(m_chartDataContructionToolButtons[indx]->mapToGlobal(QPoint(0,0))); if (selectedAction != NULL) { if (selectedAction == moveUpAction) { chartModel->moveChartDataAtIndexToOneLowerIndex(indx); } else if (selectedAction == moveDownAction) { chartModel->moveChartDataAtIndexToOneHigherIndex(indx); } else if (selectedAction == removeAction) { chartModel->removeChartAtIndex(indx); } else { CaretAssertMessage(0, "Has a new action been added but not processed?"); } this->updateAfterSelectionsChanged(); } } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void ChartHistoryViewController::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiEvent = dynamic_cast(event); CaretAssert(uiEvent); if (uiEvent->isUpdateForWindow(m_browserWindowIndex) || uiEvent->isToolBoxUpdate()) { this->updateHistoryViewController(); uiEvent->setEventProcessed(); } } } connectome-workbench-1.4.2/src/GuiQt/ChartHistoryViewController.h000066400000000000000000000102001360521144700251370ustar00rootroot00000000000000#ifndef __CHART_HISTORY_VIEW_CONTROLLER_H__ #define __CHART_HISTORY_VIEW_CONTROLLER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "EventListenerInterface.h" class QCheckBox; class QGridLayout; class QLabel; class QMenu; class QSignalMapper; class QSpinBox; class QToolButton; namespace caret { class CaretColorEnumComboBox; class ChartModel; class ChartHistoryViewController : public QWidget, public EventListenerInterface { Q_OBJECT public: ChartHistoryViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent); virtual ~ChartHistoryViewController(); private: ChartHistoryViewController(const ChartHistoryViewController&); ChartHistoryViewController& operator=(const ChartHistoryViewController&); public: // ADD_NEW_METHODS_HERE virtual void receiveEvent(Event* event); private slots: void averageCheckBoxClicked(bool); void clearPushButtonClicked(); void maximumDisplayedSpinBoxValueChanged(int); void chartDataCheckBoxSignalMapped(int); void chartDataColorComboBoxSignalMapped(int); void chartDataConstructionToolButtonSignalMapped(int); private: // ADD_NEW_MEMBERS_HERE void updateAfterSelectionsChanged(); void updateHistoryViewController(); void getSelectedChartModelAndTab(ChartModel* &chartModelOut, int32_t& tabIndexOut); const Qt::Orientation m_orientation; const int32_t m_browserWindowIndex; const QString m_objectNamePrefix; QCheckBox* m_averageCheckBox; QSpinBox* m_maximumDisplayedSpinBox; QGridLayout* m_chartDataGridLayout; std::vector m_chartDataCheckBoxes; std::vector m_chartDataContructionToolButtons; std::vector m_chartDataColorComboBoxes; std::vector m_chartDataNameLabels; QSignalMapper* m_chartDataCheckBoxesSignalMapper; QSignalMapper* m_chartDataColorComboBoxesSignalMapper; QSignalMapper* m_chartDataColorConstructionButtonSignalMapper; static const int32_t COLUMN_CHART_DATA_CHECKBOX; static const int32_t COLUMN_CHART_DATA_CONSTRUCTION; static const int32_t COLUMN_CHART_DATA_COLOR; static const int32_t COLUMN_CHART_DATA_NAME; static const int32_t COLUMN_COUNT; }; #ifdef __CHART_HISTORY_VIEW_CONTROLLER_DECLARE__ const int32_t ChartHistoryViewController::COLUMN_CHART_DATA_CHECKBOX = 0; const int32_t ChartHistoryViewController::COLUMN_CHART_DATA_CONSTRUCTION = 1; const int32_t ChartHistoryViewController::COLUMN_CHART_DATA_COLOR = 2; const int32_t ChartHistoryViewController::COLUMN_CHART_DATA_NAME = 3; const int32_t ChartHistoryViewController::COLUMN_COUNT = 4; #endif // __CHART_HISTORY_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__CHART_HISTORY_VIEW_CONTROLLER_H__ connectome-workbench-1.4.2/src/GuiQt/ChartLinesSelectionViewController.cxx000066400000000000000000000337521360521144700270120ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_LINES_SELECTION_VIEW_CONTROLLER_DECLARE__ #include "ChartLinesSelectionViewController.h" #undef __CHART_LINES_SELECTION_VIEW_CONTROLLER_DECLARE__ #include #include #include #include #include #include #include #include #include "Brain.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretMappableDataFile.h" #include "ChartModel.h" #include "ChartableLineSeriesBrainordinateInterface.h" #include "ChartableMatrixSeriesInterface.h" #include "CiftiMappableDataFile.h" #include "CiftiParcelLabelFile.h" #include "EventManager.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventPaletteColorMappingEditorDialogRequest.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "MapYokingGroupComboBox.h" #include "ModelChart.h" #include "WuQFactory.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; static const char* BRAINORDINATE_FILE_POINTER_PROPERTY_NAME = "brainordinateFilePointer"; /** * \class caret::ChartLinesSelectionViewController * \brief Handles selection of charts displayed in chart model. * \ingroup GuiQt */ /** * Constructor. */ ChartLinesSelectionViewController::ChartLinesSelectionViewController(const Qt::Orientation /*orientation */, const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { /* * In the grid layout, there are columns for the checkboxes (used * for brainordinate charts) and radio buttons (used for matrix * charts). Display of checkboxes and radiobuttons is mutually * exclusive. The "Select" column title is over both the checkbox * and radio button columns. */ m_brainordinateGridLayout = new QGridLayout(); WuQtUtilities::setLayoutSpacingAndMargins(m_brainordinateGridLayout, 4, 2); m_brainordinateGridLayout->setColumnStretch(BRAINORDINATE_COLUMN_CHECKBOX, 0); m_brainordinateGridLayout->setColumnStretch(BRAINORDINATE_COLUMN_YOKING_COMBO_BOX, 0); m_brainordinateGridLayout->setColumnStretch(BRAINORDINATE_COLUMN_LINE_EDIT, 100); const int titleRow = m_brainordinateGridLayout->rowCount(); m_brainordinateGridLayout->addWidget(new QLabel("Select"), titleRow, BRAINORDINATE_COLUMN_CHECKBOX, Qt::AlignHCenter); m_brainordinateGridLayout->addWidget(new QLabel("Yoke"), titleRow, BRAINORDINATE_COLUMN_YOKING_COMBO_BOX, Qt::AlignHCenter); m_brainordinateGridLayout->addWidget(new QLabel("Charting File"), titleRow, BRAINORDINATE_COLUMN_LINE_EDIT, Qt::AlignHCenter); m_signalMapperBrainordinateFileEnableCheckBox = new QSignalMapper(this); QObject::connect(m_signalMapperBrainordinateFileEnableCheckBox, SIGNAL(mapped(int)), this, SLOT(brainordinateSelectionCheckBoxClicked(int))); m_signalMapperBrainordinateYokingComboBox = new QSignalMapper(this); QObject::connect(m_signalMapperBrainordinateYokingComboBox, SIGNAL(mapped(int)), this, SLOT(brainordinateYokingComboBoxActivated(int))); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 0); layout->addLayout(m_brainordinateGridLayout); layout->addStretch(); } /** * Destructor. */ ChartLinesSelectionViewController::~ChartLinesSelectionViewController() { EventManager::get()->removeAllEventsFromListener(this); } /** * Update the view controller. */ void ChartLinesSelectionViewController::updateSelectionViewController() { Brain* brain = GuiManager::get()->getBrain(); BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); ChartOneDataTypeEnum::Enum chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { chartDataType = modelChart->getSelectedChartOneDataType(browserTabIndex); } bool validFlag = false; switch (chartDataType) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: validFlag = true; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: validFlag = true; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: validFlag = true; break; } if (validFlag) { std::vector chartableLineSeriesFilesVector; const ChartOneDataTypeEnum::Enum chartDataType = modelChart->getSelectedChartOneDataType(browserTabIndex); brain->getAllChartableLineSeriesDataFilesForChartDataType(chartDataType, chartableLineSeriesFilesVector); const int32_t numChartableFiles = static_cast(chartableLineSeriesFilesVector.size()); for (int32_t i = 0; i < numChartableFiles; i++) { QCheckBox* checkBox = NULL; QLineEdit* lineEdit = NULL; MapYokingGroupComboBox* yokeComboBox = NULL; if (i < static_cast(m_fileInfoRows.size())) { checkBox = m_fileInfoRows[i].m_fileEnableCheckBox;// m_brainordinateFileEnableCheckBoxes[i]; lineEdit = m_fileInfoRows[i].m_fileNameLineEdit; // m_brainordinateFileNameLineEdits[i]; yokeComboBox = m_fileInfoRows[i].m_fileYokingComboBox; // m_brainordinateSeriesYokingComboBoxes[i]; } else { checkBox = new QCheckBox(""); QObject::connect(checkBox, SIGNAL(clicked(bool)), m_signalMapperBrainordinateFileEnableCheckBox, SLOT(map())); m_signalMapperBrainordinateFileEnableCheckBox->setMapping(checkBox, i); yokeComboBox = new MapYokingGroupComboBox(this); yokeComboBox->getWidget()->setStatusTip("Synchronize enabled status and map indices)"); yokeComboBox->getWidget()->setToolTip("Yoke to Overlay Mapped Files"); QObject::connect(yokeComboBox, SIGNAL(itemActivated()), m_signalMapperBrainordinateYokingComboBox, SLOT(map())); m_signalMapperBrainordinateYokingComboBox->setMapping(yokeComboBox, i); lineEdit = new QLineEdit(); lineEdit->setReadOnly(true); FileInfoRow rowInfo; rowInfo.m_fileEnableCheckBox = checkBox; rowInfo.m_fileNameLineEdit = lineEdit; rowInfo.m_fileYokingComboBox = yokeComboBox; rowInfo.m_lineSeriesFile = NULL; m_fileInfoRows.push_back(rowInfo); const int row = m_brainordinateGridLayout->rowCount(); m_brainordinateGridLayout->addWidget(checkBox, row, BRAINORDINATE_COLUMN_CHECKBOX, Qt::AlignHCenter); m_brainordinateGridLayout->addWidget(yokeComboBox->getWidget(), row, BRAINORDINATE_COLUMN_YOKING_COMBO_BOX, Qt::AlignHCenter); m_brainordinateGridLayout->addWidget(lineEdit, row, BRAINORDINATE_COLUMN_LINE_EDIT); } CaretAssertVectorIndex(chartableLineSeriesFilesVector, i); ChartableLineSeriesInterface* chartBrainFile = chartableLineSeriesFilesVector[i]; CaretAssert(chartBrainFile); m_fileInfoRows[i].m_lineSeriesFile = chartBrainFile; const bool checkBoxStatus = chartBrainFile->isLineSeriesChartingEnabled(browserTabIndex); QVariant brainordinateFilePointerVariant = qVariantFromValue((void*)chartBrainFile); CaretMappableDataFile* caretMappableDataFile = chartBrainFile->getLineSeriesChartCaretMappableDataFile(); checkBox->blockSignals(true); checkBox->setChecked(checkBoxStatus); checkBox->blockSignals(false); checkBox->setProperty(BRAINORDINATE_FILE_POINTER_PROPERTY_NAME, brainordinateFilePointerVariant); /* * Could be line chart for matrix series file */ ChartableMatrixSeriesInterface* matrixFile = dynamic_cast(caretMappableDataFile); if (matrixFile != NULL) { yokeComboBox->getWidget()->setEnabled(true); yokeComboBox->setMapYokingGroup(matrixFile->getMatrixRowColumnMapYokingGroup(browserTabIndex)); } else { yokeComboBox->getWidget()->setEnabled(false); } CaretAssert(caretMappableDataFile); lineEdit->setText(caretMappableDataFile->getFileName()); } const int32_t numItems = static_cast(m_fileInfoRows.size()); for (int32_t i = 0; i < numItems; i++) { bool showCheckBox = false; bool showYokeComboBox = false; bool showLineEdit = false; if (i < numChartableFiles) { showLineEdit = true; showYokeComboBox = true; showCheckBox = true; } else { m_fileInfoRows[i].m_lineSeriesFile = NULL; } m_fileInfoRows[i].m_fileEnableCheckBox->setVisible(showCheckBox); m_fileInfoRows[i].m_fileNameLineEdit->setVisible(showLineEdit); m_fileInfoRows[i].m_fileYokingComboBox->getWidget()->setVisible(showYokeComboBox); } } } /** * Called when a brainordinate yoking combo box changes. * * @param indx * Index of yoking combo box that was clicked. */ void ChartLinesSelectionViewController::brainordinateYokingComboBoxActivated(int indx) { CaretAssertVectorIndex(m_fileInfoRows, indx); ChartableMatrixSeriesInterface* matrixFile = dynamic_cast(m_fileInfoRows[indx].m_lineSeriesFile); if (matrixFile != NULL) { BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); matrixFile->setMatrixRowColumnMapYokingGroup(browserTabIndex, m_fileInfoRows[indx].m_fileYokingComboBox->getMapYokingGroup()); } } /** * Called when a brainordinate enabled check box changes state. * * @param indx * Index of checkbox that was clicked. */ void ChartLinesSelectionViewController::brainordinateSelectionCheckBoxClicked(int indx) { CaretAssertVectorIndex(m_fileInfoRows, indx); BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); const bool newStatus = m_fileInfoRows[indx].m_fileEnableCheckBox->isChecked(); if (m_fileInfoRows[indx].m_lineSeriesFile != NULL) { m_fileInfoRows[indx].m_lineSeriesFile->setLineSeriesChartingEnabled(browserTabIndex, newStatus); } } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void ChartLinesSelectionViewController::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiEvent = dynamic_cast(event); CaretAssert(uiEvent); if (uiEvent->isUpdateForWindow(m_browserWindowIndex) || uiEvent->isToolBoxUpdate()) { this->updateSelectionViewController(); uiEvent->setEventProcessed(); } } } connectome-workbench-1.4.2/src/GuiQt/ChartLinesSelectionViewController.h000066400000000000000000000066711360521144700264370ustar00rootroot00000000000000#ifndef __CHART_LINES_SELECTION_VIEW_CONTROLLER_H__ #define __CHART_LINES_SELECTION_VIEW_CONTROLLER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "EventListenerInterface.h" class QCheckBox; class QGridLayout; class QLineEdit; class QSignalMapper; namespace caret { class Brain; class ChartableLineSeriesInterface; class ChartableLineSeriesBrainordinateInterface; class MapYokingGroupComboBox; class ModelChart; class ChartLinesSelectionViewController : public QWidget, public EventListenerInterface { Q_OBJECT public: ChartLinesSelectionViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, QWidget* parent); virtual ~ChartLinesSelectionViewController(); private slots: void brainordinateSelectionCheckBoxClicked(int); void brainordinateYokingComboBoxActivated(int); private: ChartLinesSelectionViewController(const ChartLinesSelectionViewController&); ChartLinesSelectionViewController& operator=(const ChartLinesSelectionViewController&); public: // ADD_NEW_METHODS_HERE virtual void receiveEvent(Event* event); private: // ADD_NEW_MEMBERS_HERE void updateSelectionViewController(); const int32_t m_browserWindowIndex; struct FileInfoRow { QLineEdit* m_fileNameLineEdit; QCheckBox* m_fileEnableCheckBox; MapYokingGroupComboBox* m_fileYokingComboBox; ChartableLineSeriesInterface* m_lineSeriesFile; }; std::vector m_fileInfoRows; QGridLayout* m_brainordinateGridLayout; QSignalMapper* m_signalMapperBrainordinateFileEnableCheckBox; QSignalMapper* m_signalMapperBrainordinateYokingComboBox; static const int BRAINORDINATE_COLUMN_CHECKBOX; static const int BRAINORDINATE_COLUMN_YOKING_COMBO_BOX; static const int BRAINORDINATE_COLUMN_LINE_EDIT; }; #ifdef __CHART_LINES_SELECTION_VIEW_CONTROLLER_DECLARE__ const int ChartLinesSelectionViewController::BRAINORDINATE_COLUMN_CHECKBOX = 0; const int ChartLinesSelectionViewController::BRAINORDINATE_COLUMN_YOKING_COMBO_BOX = 1; const int ChartLinesSelectionViewController::BRAINORDINATE_COLUMN_LINE_EDIT = 2; #endif // __CHART_LINES_SELECTION_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__CHART_LINES_SELECTION_VIEW_CONTROLLER_H__ connectome-workbench-1.4.2/src/GuiQt/ChartMatrixParcelSelectionViewController.cxx000066400000000000000000001373061360521144700303330ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_MATRIX_PARCEL_SELECTION_VIEW_CONTROLLER_DECLARE__ #include "ChartMatrixParcelSelectionViewController.h" #undef __CHART_MATRIX_PARCEL_SELECTION_VIEW_CONTROLLER_DECLARE__ #include #include #include #include #include #include #include #include "AnnotationColorBar.h" #include "Brain.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretDataFileSelectionComboBox.h" #include "CaretDataFileSelectionModel.h" #include "CaretLogger.h" #include "CaretMappableDataFile.h" #include "CaretMappableDataFileAndMapSelectionModel.h" #include "CaretMappableDataFileAndMapSelectorObject.h" #include "ChartableMatrixInterface.h" #include "ChartMatrixDisplayProperties.h" #include "ChartMatrixLoadingDimensionEnum.h" #include "ChartableMatrixSeriesInterface.h" #include "ChartModel.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "CiftiMappableDataFile.h" #include "CiftiParcelLabelFile.h" #include "DeveloperFlagsEnum.h" #include "EnumComboBoxTemplate.h" #include "EventChartMatrixParcelYokingValidation.h" #include "EventManager.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventPaletteColorMappingEditorDialogRequest.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "ModelChart.h" #include "WuQFactory.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::ChartMatrixParcelSelectionViewController * \brief Handles selection of charts displayed in chart model. * \ingroup GuiQt */ /** * Constructor. */ ChartMatrixParcelSelectionViewController::ChartMatrixParcelSelectionViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { m_matrixParcelChartWidget = createMatrixParcelChartWidget(orientation); m_parcelRemappingGroupBox = createParcelRemappingWidget(orientation); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 1, 0); layout->addWidget(m_matrixParcelChartWidget); layout->addWidget(m_parcelRemappingGroupBox); //layout->addStretch(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); // /* // * ColorBar Tool Button // */ // QIcon colorBarIcon; // const bool colorBarIconValid = WuQtUtilities::loadIcon(":/LayersPanel/colorbar.png", // colorBarIcon); // m_matrixParcelColorBarAction = WuQtUtilities::createAction("CB", // "Display color bar for this overlay", // this, // this, // SLOT(matrixParcelColorBarActionTriggered(bool))); // m_matrixParcelColorBarAction->setCheckable(true); // if (colorBarIconValid) { // m_matrixParcelColorBarAction->setIcon(colorBarIcon); // } // QToolButton* colorBarToolButton = new QToolButton(); // colorBarToolButton->setDefaultAction(m_matrixParcelColorBarAction); // // /* // * Settings Tool Button // */ // QLabel* settingsLabel = new QLabel("Settings"); // QIcon settingsIcon; // const bool settingsIconValid = WuQtUtilities::loadIcon(":/LayersPanel/wrench.png", // settingsIcon); // // m_matrixParcelSettingsAction = WuQtUtilities::createAction("S", // "Edit settings for this map and overlay", // this, // this, // SLOT(matrixParcelSettingsActionTriggered())); // if (settingsIconValid) { // m_matrixParcelSettingsAction->setIcon(settingsIcon); // } // QToolButton* settingsToolButton = new QToolButton(); // settingsToolButton->setDefaultAction(m_matrixParcelSettingsAction); // // // QLabel* fileLabel = new QLabel("Matrix File"); // m_matrixParcelFileSelectionComboBox = new CaretDataFileSelectionComboBox(this); // QObject::connect(m_matrixParcelFileSelectionComboBox, SIGNAL(fileSelected(CaretDataFile*)), // this, SLOT(matrixParcelFileSelected(CaretDataFile*))); // // QLabel* loadDimensionLabel = new QLabel("Load By"); // m_matrixParcelLoadByColumnRowComboBox = new EnumComboBoxTemplate(this); // m_matrixParcelLoadByColumnRowComboBox->setup(); // QObject::connect(m_matrixParcelLoadByColumnRowComboBox, SIGNAL(itemActivated()), // this, SLOT(matrixParcelFileLoadingComboBoxActivated())); // // // QLabel* yokeLabel = new QLabel("Yoke "); // m_matrixParcelYokingGroupComboBox = new EnumComboBoxTemplate(this); // m_matrixParcelYokingGroupComboBox->setup(); // QObject::connect(m_matrixParcelYokingGroupComboBox, SIGNAL(itemActivated()), // this, SLOT(matrixParcelYokingGroupEnumComboBoxActivated())); // // m_matrixParcelChartWidget = new QGroupBox("Matrix Loading"); // QGridLayout* matrixLayout = new QGridLayout(m_matrixParcelChartWidget); // // switch (orientation) { // case Qt::Horizontal: // { // WuQtUtilities::setLayoutSpacingAndMargins(matrixLayout, 2, 0); // matrixLayout->setColumnStretch(0, 0); // matrixLayout->setColumnStretch(1, 0); // matrixLayout->setColumnStretch(2, 0); // matrixLayout->setColumnStretch(3, 0); // matrixLayout->setColumnStretch(4, 100); // // matrixLayout->addWidget(loadDimensionLabel, // 0, 0, // Qt::AlignHCenter); // matrixLayout->addWidget(settingsLabel, // 0, 1, // 1, 2, // Qt::AlignHCenter); // matrixLayout->addWidget(yokeLabel, // 0, 3, // Qt::AlignHCenter); // matrixLayout->addWidget(fileLabel, // 0, 4, // Qt::AlignHCenter); // matrixLayout->addWidget(m_matrixParcelLoadByColumnRowComboBox->getWidget(), // 1, 0); // matrixLayout->addWidget(settingsToolButton, // 1, 1); // matrixLayout->addWidget(colorBarToolButton, // 1, 2); // matrixLayout->addWidget(m_matrixParcelYokingGroupComboBox->getWidget(), // 1, 3); // matrixLayout->addWidget(m_matrixParcelFileSelectionComboBox->getWidget(), // 1, 4); // } // break; // case Qt::Vertical: // { // WuQtUtilities::setLayoutSpacingAndMargins(matrixLayout, 2, 0); // matrixLayout->setColumnStretch(0, 0); // matrixLayout->setColumnStretch(1, 0); // matrixLayout->setColumnStretch(2, 0); // matrixLayout->setColumnStretch(3, 0); // matrixLayout->setColumnStretch(4, 100); // // matrixLayout->addWidget(loadDimensionLabel, // 0, 0, // Qt::AlignHCenter); // matrixLayout->addWidget(settingsLabel, // 0, 1, // 1, 2, // Qt::AlignHCenter); // matrixLayout->addWidget(yokeLabel, // 0, 3, // Qt::AlignHCenter); // matrixLayout->addWidget(m_matrixParcelLoadByColumnRowComboBox->getWidget(), // 1, 0); // matrixLayout->addWidget(settingsToolButton, // 1, 1); // matrixLayout->addWidget(colorBarToolButton, // 1, 2); // matrixLayout->addWidget(m_matrixParcelYokingGroupComboBox->getWidget(), // 1, 3); // matrixLayout->addWidget(fileLabel, // 2, 0, 1, 4, // Qt::AlignHCenter); // matrixLayout->addWidget(m_matrixParcelFileSelectionComboBox->getWidget(), // 3, 0, 1, 4); // } // break; // default: // CaretAssert(0); // break; // } // // m_parcelReorderingEnabledCheckBox = new QCheckBox(""); // QObject::connect(m_parcelReorderingEnabledCheckBox, SIGNAL(clicked(bool)), // this, SLOT(parcelLabelFileRemappingFileSelectorChanged())); // // m_parcelLabelFileRemappingFileSelector = new CaretMappableDataFileAndMapSelectorObject(DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL, // CaretMappableDataFileAndMapSelectorObject::OPTION_SHOW_MAP_INDEX_SPIN_BOX, // this); // QObject::connect(m_parcelLabelFileRemappingFileSelector, SIGNAL(selectionWasPerformed()), // this, SLOT(parcelLabelFileRemappingFileSelectorChanged())); // // QLabel* parcelCheckBoxLabel = new QLabel("On"); // QLabel* parcelFileLabel = new QLabel("Parcel Label File"); // QLabel* parcelFileMapLabel = new QLabel("Map"); // QLabel* parcelFileMapIndexLabel = new QLabel("Index"); // QWidget* mapFileComboBox = NULL; // QWidget* mapIndexSpinBox = NULL; // QWidget* mapNameComboBox = NULL; // m_parcelLabelFileRemappingFileSelector->getWidgetsForAddingToLayout(mapFileComboBox, // mapIndexSpinBox, // mapNameComboBox); // m_parcelRemappingGroupBox = new QGroupBox("Parcel Reordering"); // m_parcelRemappingGroupBox->setFlat(true); // m_parcelRemappingGroupBox->setAlignment(Qt::AlignHCenter); // QGridLayout* parcelMapFileLayout = new QGridLayout(m_parcelRemappingGroupBox); // switch (orientation) { // case Qt::Horizontal: // { // WuQtUtilities::setLayoutSpacingAndMargins(parcelMapFileLayout, 2, 0); // parcelMapFileLayout->setColumnStretch(0, 0); // parcelMapFileLayout->setColumnStretch(1, 100); // parcelMapFileLayout->setColumnStretch(2, 0); // parcelMapFileLayout->setColumnStretch(3, 100); // parcelMapFileLayout->addWidget(parcelCheckBoxLabel, 0, 0, Qt::AlignHCenter); // parcelMapFileLayout->addWidget(parcelFileLabel, 0, 1, Qt::AlignHCenter); // parcelMapFileLayout->addWidget(parcelFileMapLabel, 0, 2, 1, 2, Qt::AlignHCenter); // parcelMapFileLayout->addWidget(m_parcelReorderingEnabledCheckBox, 1,0); // parcelMapFileLayout->addWidget(mapFileComboBox, 1, 1); // parcelMapFileLayout->addWidget(mapIndexSpinBox, 1, 2); // parcelMapFileLayout->addWidget(mapNameComboBox, 1, 3); // } // break; // case Qt::Vertical: // { // WuQtUtilities::setLayoutSpacingAndMargins(parcelMapFileLayout, 2, 0); // parcelMapFileLayout->setColumnStretch(0, 0); // parcelMapFileLayout->setColumnStretch(1, 100); // parcelMapFileLayout->addWidget(parcelCheckBoxLabel, 0, 0, Qt::AlignHCenter); // parcelMapFileLayout->addWidget(parcelFileLabel, 0, 1, Qt::AlignHCenter); // parcelMapFileLayout->addWidget(m_parcelReorderingEnabledCheckBox, 1,0, Qt::AlignHCenter); // parcelMapFileLayout->addWidget(mapFileComboBox, 1, 1); // parcelMapFileLayout->addWidget(parcelFileMapIndexLabel, 2, 0, Qt::AlignHCenter); // parcelMapFileLayout->addWidget(parcelFileMapLabel, 2, 1, Qt::AlignHCenter); // parcelMapFileLayout->addWidget(mapIndexSpinBox, 3, 0); // parcelMapFileLayout->addWidget(mapNameComboBox, 3, 1); // } // break; // default: // CaretAssert(0); // } // // // QWidget* widget = new QWidget(this); // QVBoxLayout* layout = new QVBoxLayout(widget); // WuQtUtilities::setLayoutSpacingAndMargins(layout, 1, 0); // layout->addWidget(m_matrixParcelChartWidget); // layout->addWidget(m_parcelRemappingGroupBox); // //layout->addStretch(); // // /* // * TEMP TODO // * FINISH IMPLEMENTATION OF LOADING AND YOKING // */ // const bool hideLoadControls = false; // const bool hideYokeControls = false; // if (hideLoadControls) { // loadDimensionLabel->hide(); // m_matrixParcelLoadByColumnRowComboBox->getWidget()->hide(); // } // if (hideYokeControls) { // yokeLabel->hide(); // m_matrixParcelYokingGroupComboBox->getWidget()->hide(); // } // // EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); } /** * Destructor. */ ChartMatrixParcelSelectionViewController::~ChartMatrixParcelSelectionViewController() { EventManager::get()->removeAllEventsFromListener(this); } /** * Update the view controller. */ void ChartMatrixParcelSelectionViewController::updateSelectionViewController() { Brain* brain = GuiManager::get()->getBrain(); BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); ChartOneDataTypeEnum::Enum chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { chartDataType = modelChart->getSelectedChartOneDataType(browserTabIndex); } if (chartDataType == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER) { updateMatrixParcelChartWidget(brain, modelChart, browserTabIndex); } } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void ChartMatrixParcelSelectionViewController::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiEvent = dynamic_cast(event); CaretAssert(uiEvent); if (uiEvent->isUpdateForWindow(m_browserWindowIndex) || uiEvent->isToolBoxUpdate()) { this->updateSelectionViewController(); uiEvent->setEventProcessed(); } } } /** * Called when a matrix file is selected. * * @param caretDataFile * Caret data file that was selected. */ void ChartMatrixParcelSelectionViewController::matrixParcelFileSelected(CaretDataFile* /*caretDataFile*/) { updateSelectionViewController(); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(m_browserWindowIndex).getPointer()); } /** * Gets called when matrix loading combo box is changed. */ void ChartMatrixParcelSelectionViewController::matrixParcelFileLoadingComboBoxActivated() { CaretMappableDataFile* caretMappableDataFile = NULL; ChartableMatrixInterface* chartableMatrixInterface = NULL; ChartMatrixDisplayProperties* chartMatrixDisplayProperties = NULL; ChartableMatrixParcelInterface* chartableMatrixParcelInterface = NULL; ChartableMatrixSeriesInterface* chartableMatrixSeriesInterface = NULL; int32_t browserTabIndex = -1; if ( ! getChartMatrixAndProperties(caretMappableDataFile, chartableMatrixInterface, chartableMatrixParcelInterface, chartableMatrixSeriesInterface, chartMatrixDisplayProperties, browserTabIndex)) { return; } CaretAssert(chartableMatrixParcelInterface); chartableMatrixParcelInterface->setMatrixLoadingDimension(m_matrixParcelLoadByColumnRowComboBox->getSelectedItem()); EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Gets called when yoking gruup is changed. */ void ChartMatrixParcelSelectionViewController::matrixParcelYokingGroupEnumComboBoxActivated() { CaretMappableDataFile* caretMappableDataFile = NULL; ChartableMatrixInterface* chartableMatrixInterface = NULL; ChartMatrixDisplayProperties* chartMatrixDisplayProperties = NULL; ChartableMatrixParcelInterface* chartableMatrixParcelInterface = NULL; ChartableMatrixSeriesInterface* chartableMatrixSeriesInterface = NULL; int32_t browserTabIndex = -1; if ( ! getChartMatrixAndProperties(caretMappableDataFile, chartableMatrixInterface, chartableMatrixParcelInterface, chartableMatrixSeriesInterface, chartMatrixDisplayProperties, browserTabIndex)) { return; } CaretAssert(chartableMatrixParcelInterface); YokingGroupEnum::Enum newYokingGroup = m_matrixParcelYokingGroupComboBox->getSelectedItem(); int32_t selectedRowColumnIndex = -1; if (newYokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) { const YokingGroupEnum::Enum previousYokingGroup = chartableMatrixParcelInterface->getYokingGroup(); EventChartMatrixParcelYokingValidation yokeEvent(chartableMatrixParcelInterface, newYokingGroup); EventManager::get()->sendEvent(yokeEvent.getPointer()); AString message; if ( ! yokeEvent.isValidateYokingCompatible(message, selectedRowColumnIndex)) { message = WuQtUtilities::createWordWrappedToolTipText(message); WuQMessageBox::YesNoCancelResult result = WuQMessageBox::warningYesNoCancel(m_matrixParcelYokingGroupComboBox->getWidget(), message, ""); switch (result) { case WuQMessageBox::RESULT_YES: break; case WuQMessageBox::RESULT_NO: newYokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; selectedRowColumnIndex = -1; break; case WuQMessageBox::RESULT_CANCEL: newYokingGroup = previousYokingGroup; selectedRowColumnIndex = -1; break; } } } /* * Need to update combo box since user may have changed mind and * the combo box status needs to change */ m_matrixParcelYokingGroupComboBox->setSelectedItem(newYokingGroup); chartableMatrixParcelInterface->setYokingGroup(newYokingGroup); /* * If yoking changed update the file's selected row or column */ if (newYokingGroup != YokingGroupEnum::YOKING_GROUP_OFF) { if (selectedRowColumnIndex >= 0) { CiftiMappableConnectivityMatrixDataFile* matrixFile = dynamic_cast(chartableMatrixInterface); if (matrixFile != NULL) { switch (chartableMatrixParcelInterface->getMatrixLoadingDimension()) { case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: matrixFile->loadDataForColumnIndex(selectedRowColumnIndex); break; case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: matrixFile->loadDataForRowIndex(selectedRowColumnIndex); break; } } } } EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called when colorbar icon button is clicked. */ void ChartMatrixParcelSelectionViewController::matrixParcelColorBarActionTriggered(bool status) { CaretMappableDataFile* caretMappableDataFile = NULL; ChartableMatrixInterface* chartableMatrixInterface = NULL; ChartMatrixDisplayProperties* chartMatrixDisplayProperties = NULL; ChartableMatrixParcelInterface* chartableMatrixParcelInterface = NULL; ChartableMatrixSeriesInterface* chartableMatrixSeriesInterface = NULL; int32_t browserTabIndex = -1; if ( ! getChartMatrixAndProperties(caretMappableDataFile, chartableMatrixInterface, chartableMatrixParcelInterface, chartableMatrixSeriesInterface, chartMatrixDisplayProperties, browserTabIndex)) { return; } chartMatrixDisplayProperties->getColorBar()->setDisplayed(status); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called when settings icon button is clicked to display palette editor. */ void ChartMatrixParcelSelectionViewController::matrixParcelSettingsActionTriggered() { CaretMappableDataFile* caretMappableDataFile = NULL; ChartableMatrixInterface* chartableMatrixInterface = NULL; ChartMatrixDisplayProperties* chartMatrixDisplayProperties = NULL; ChartableMatrixParcelInterface* chartableMatrixParcelInterface = NULL; ChartableMatrixSeriesInterface* chartableMatrixSeriesInterface = NULL; int32_t browserTabIndex = -1; if ( ! getChartMatrixAndProperties(caretMappableDataFile, chartableMatrixInterface, chartableMatrixParcelInterface, chartableMatrixSeriesInterface, chartMatrixDisplayProperties, browserTabIndex)) { return; } const int32_t mapIndex = 0; EventPaletteColorMappingEditorDialogRequest dialogEvent(m_browserWindowIndex, caretMappableDataFile, mapIndex); EventManager::get()->sendEvent(dialogEvent.getPointer()); } /** * @param orientation * Orientation for the widget. * @return * The matrix chart widget. */ QGroupBox* ChartMatrixParcelSelectionViewController::createMatrixParcelChartWidget(const Qt::Orientation orientation) { /* * ColorBar Tool Button */ QIcon colorBarIcon; const bool colorBarIconValid = WuQtUtilities::loadIcon(":/LayersPanel/colorbar.png", colorBarIcon); m_matrixParcelColorBarAction = WuQtUtilities::createAction("CB", "Display color bar for this overlay", this, this, SLOT(matrixParcelColorBarActionTriggered(bool))); m_matrixParcelColorBarAction->setCheckable(true); if (colorBarIconValid) { m_matrixParcelColorBarAction->setIcon(colorBarIcon); } QToolButton* colorBarToolButton = new QToolButton(); colorBarToolButton->setDefaultAction(m_matrixParcelColorBarAction); /* * Settings Tool Button */ QLabel* settingsLabel = new QLabel("Settings"); QIcon settingsIcon; const bool settingsIconValid = WuQtUtilities::loadIcon(":/LayersPanel/wrench.png", settingsIcon); m_matrixParcelSettingsAction = WuQtUtilities::createAction("S", "Edit settings for this map and overlay", this, this, SLOT(matrixParcelSettingsActionTriggered())); if (settingsIconValid) { m_matrixParcelSettingsAction->setIcon(settingsIcon); } QToolButton* settingsToolButton = new QToolButton(); settingsToolButton->setDefaultAction(m_matrixParcelSettingsAction); QLabel* fileLabel = new QLabel("Matrix File"); m_matrixParcelFileSelectionComboBox = new CaretDataFileSelectionComboBox(this); QObject::connect(m_matrixParcelFileSelectionComboBox, SIGNAL(fileSelected(CaretDataFile*)), this, SLOT(matrixParcelFileSelected(CaretDataFile*))); QLabel* loadDimensionLabel = new QLabel("Load By"); m_matrixParcelLoadByColumnRowComboBox = new EnumComboBoxTemplate(this); m_matrixParcelLoadByColumnRowComboBox->setup(); QObject::connect(m_matrixParcelLoadByColumnRowComboBox, SIGNAL(itemActivated()), this, SLOT(matrixParcelFileLoadingComboBoxActivated())); QLabel* yokeLabel = new QLabel("Yoke "); m_matrixParcelYokingGroupComboBox = new EnumComboBoxTemplate(this); m_matrixParcelYokingGroupComboBox->setup(); QObject::connect(m_matrixParcelYokingGroupComboBox, SIGNAL(itemActivated()), this, SLOT(matrixParcelYokingGroupEnumComboBoxActivated())); QGroupBox* fileYokeGroupBox = new QGroupBox("Matrix Loading"); fileYokeGroupBox->setFlat(true); fileYokeGroupBox->setAlignment(Qt::AlignHCenter); QGridLayout* fileYokeLayout = new QGridLayout(fileYokeGroupBox); switch (orientation) { case Qt::Horizontal: { WuQtUtilities::setLayoutSpacingAndMargins(fileYokeLayout, 2, 0); fileYokeLayout->setColumnStretch(0, 0); fileYokeLayout->setColumnStretch(1, 0); fileYokeLayout->setColumnStretch(2, 0); fileYokeLayout->setColumnStretch(3, 0); fileYokeLayout->setColumnStretch(4, 100); fileYokeLayout->addWidget(loadDimensionLabel, 0, 0, Qt::AlignHCenter); fileYokeLayout->addWidget(settingsLabel, 0, 1, 1, 2, Qt::AlignHCenter); fileYokeLayout->addWidget(yokeLabel, 0, 3, Qt::AlignHCenter); fileYokeLayout->addWidget(fileLabel, 0, 4, Qt::AlignHCenter); fileYokeLayout->addWidget(m_matrixParcelLoadByColumnRowComboBox->getWidget(), 1, 0); fileYokeLayout->addWidget(settingsToolButton, 1, 1); fileYokeLayout->addWidget(colorBarToolButton, 1, 2); fileYokeLayout->addWidget(m_matrixParcelYokingGroupComboBox->getWidget(), 1, 3); fileYokeLayout->addWidget(m_matrixParcelFileSelectionComboBox->getWidget(), 1, 4); } break; case Qt::Vertical: { WuQtUtilities::setLayoutSpacingAndMargins(fileYokeLayout, 2, 0); fileYokeLayout->setColumnStretch(0, 0); fileYokeLayout->setColumnStretch(1, 0); fileYokeLayout->setColumnStretch(2, 0); fileYokeLayout->setColumnStretch(3, 0); fileYokeLayout->setColumnStretch(4, 100); fileYokeLayout->addWidget(loadDimensionLabel, 0, 0, Qt::AlignHCenter); fileYokeLayout->addWidget(settingsLabel, 0, 1, 1, 2, Qt::AlignHCenter); fileYokeLayout->addWidget(yokeLabel, 0, 3, Qt::AlignHCenter); fileYokeLayout->addWidget(m_matrixParcelLoadByColumnRowComboBox->getWidget(), 1, 0); fileYokeLayout->addWidget(settingsToolButton, 1, 1); fileYokeLayout->addWidget(colorBarToolButton, 1, 2); fileYokeLayout->addWidget(m_matrixParcelYokingGroupComboBox->getWidget(), 1, 3); fileYokeLayout->addWidget(fileLabel, 2, 0, 1, 4, Qt::AlignHCenter); fileYokeLayout->addWidget(m_matrixParcelFileSelectionComboBox->getWidget(), 3, 0, 1, 4); } break; default: CaretAssert(0); break; } return fileYokeGroupBox; } /** * @param orientation * Orientation for the widget. * @return * The parcel remapping widget. */ QGroupBox* ChartMatrixParcelSelectionViewController::createParcelRemappingWidget(const Qt::Orientation orientation) { m_parcelReorderingEnabledCheckBox = new QCheckBox(""); QObject::connect(m_parcelReorderingEnabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(parcelLabelFileRemappingFileSelectorChanged())); m_parcelLabelFileRemappingFileSelector = new CaretMappableDataFileAndMapSelectorObject(DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL, CaretMappableDataFileAndMapSelectorObject::OPTION_SHOW_MAP_INDEX_SPIN_BOX, this); QObject::connect(m_parcelLabelFileRemappingFileSelector, SIGNAL(selectionWasPerformed()), this, SLOT(parcelLabelFileRemappingFileSelectorChanged())); QLabel* parcelCheckBoxLabel = new QLabel("On"); QLabel* parcelFileLabel = new QLabel("Parcel Label File"); QLabel* parcelFileMapLabel = new QLabel("Map"); QLabel* parcelFileMapIndexLabel = new QLabel("Index"); QWidget* mapFileComboBox = NULL; QWidget* mapIndexSpinBox = NULL; QWidget* mapNameComboBox = NULL; m_parcelLabelFileRemappingFileSelector->getWidgetsForAddingToLayout(mapFileComboBox, mapIndexSpinBox, mapNameComboBox); QGroupBox* groupBox = new QGroupBox("Parcel Reordering"); groupBox->setFlat(true); groupBox->setAlignment(Qt::AlignHCenter); QGridLayout* parcelMapFileLayout = new QGridLayout(groupBox); switch (orientation) { case Qt::Horizontal: { WuQtUtilities::setLayoutSpacingAndMargins(parcelMapFileLayout, 2, 0); parcelMapFileLayout->setColumnStretch(0, 0); parcelMapFileLayout->setColumnStretch(1, 100); parcelMapFileLayout->setColumnStretch(2, 0); parcelMapFileLayout->setColumnStretch(3, 100); parcelMapFileLayout->addWidget(parcelCheckBoxLabel, 0, 0, Qt::AlignHCenter); parcelMapFileLayout->addWidget(parcelFileLabel, 0, 1, Qt::AlignHCenter); parcelMapFileLayout->addWidget(parcelFileMapLabel, 0, 2, 1, 2, Qt::AlignHCenter); parcelMapFileLayout->addWidget(m_parcelReorderingEnabledCheckBox, 1,0); parcelMapFileLayout->addWidget(mapFileComboBox, 1, 1); parcelMapFileLayout->addWidget(mapIndexSpinBox, 1, 2); parcelMapFileLayout->addWidget(mapNameComboBox, 1, 3); } break; case Qt::Vertical: { WuQtUtilities::setLayoutSpacingAndMargins(parcelMapFileLayout, 2, 0); parcelMapFileLayout->setColumnStretch(0, 0); parcelMapFileLayout->setColumnStretch(1, 100); parcelMapFileLayout->addWidget(parcelCheckBoxLabel, 0, 0, Qt::AlignHCenter); parcelMapFileLayout->addWidget(parcelFileLabel, 0, 1, Qt::AlignHCenter); parcelMapFileLayout->addWidget(m_parcelReorderingEnabledCheckBox, 1,0, Qt::AlignHCenter); parcelMapFileLayout->addWidget(mapFileComboBox, 1, 1); parcelMapFileLayout->addWidget(parcelFileMapIndexLabel, 2, 0, Qt::AlignHCenter); parcelMapFileLayout->addWidget(parcelFileMapLabel, 2, 1, Qt::AlignHCenter); parcelMapFileLayout->addWidget(mapIndexSpinBox, 3, 0); parcelMapFileLayout->addWidget(mapNameComboBox, 3, 1); } break; default: CaretAssert(0); } return groupBox; } /** * Get the matrix related files and properties in this view controller. * * @param caretMappableDataFileOut * Output with selected caret mappable data file. * @param chartableMatrixInterfaceOut * Output with ChartableMatrixInterface implemented by the caret * mappable data file. * @param chartableMatrixParcelInterfaceOut * Output with ChartableMatrixParcelInterfaceOut implemented by the * caret mappable data file (may be NULL). * @param chartableMatrixSeriesInterfaceOut * Output with ChartableMatrixSeriesInterfaceOut implemented by the * caret mappable data file (may be NULL). * @param browserTabIndexOut * Index selected tab. * @param chartMatrixDisplayPropertiesOut * Matrix display properties from the ChartableMatrixInterface. * @return True if all output values are valid, else false. */ bool ChartMatrixParcelSelectionViewController::getChartMatrixAndProperties(CaretMappableDataFile* &caretMappableDataFileOut, ChartableMatrixInterface* & chartableMatrixInterfaceOut, ChartableMatrixParcelInterface* &chartableMatrixParcelInterfaceOut, ChartableMatrixSeriesInterface* &chartableMatrixSeriesInterfaceOut, ChartMatrixDisplayProperties* &chartMatrixDisplayPropertiesOut, int32_t& browserTabIndexOut) { caretMappableDataFileOut = NULL; chartableMatrixInterfaceOut = NULL; chartableMatrixParcelInterfaceOut = NULL; chartableMatrixSeriesInterfaceOut = NULL; chartMatrixDisplayPropertiesOut = NULL; browserTabIndexOut = -1; Brain* brain = GuiManager::get()->getBrain(); BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return false; } browserTabIndexOut = browserTabContent->getTabNumber(); if (browserTabIndexOut < 0) { return false; } ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { switch (modelChart->getSelectedChartOneDataType(browserTabIndexOut)) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: { CaretDataFileSelectionModel* parcelFileSelectionModel = modelChart->getChartableMatrixParcelFileSelectionModel(browserTabIndexOut); //m_matrixParcelFileSelectionComboBox->updateComboBox(parcelFileSelectionModel); CaretDataFile* caretParcelFile = parcelFileSelectionModel->getSelectedFile(); if (caretParcelFile != NULL) { chartableMatrixInterfaceOut = dynamic_cast(caretParcelFile); if (chartableMatrixInterfaceOut != NULL) { chartableMatrixParcelInterfaceOut = dynamic_cast(caretParcelFile); chartMatrixDisplayPropertiesOut = chartableMatrixInterfaceOut->getChartMatrixDisplayProperties(browserTabIndexOut); caretMappableDataFileOut = chartableMatrixInterfaceOut->getMatrixChartCaretMappableDataFile(); return true; } } } break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: { CaretDataFileSelectionModel* seriesFileSelectionModel = modelChart->getChartableMatrixSeriesFileSelectionModel(browserTabIndexOut); CaretDataFile* caretSeriesFile = seriesFileSelectionModel->getSelectedFile(); if (caretSeriesFile != NULL) { chartableMatrixInterfaceOut = dynamic_cast(caretSeriesFile); if (chartableMatrixInterfaceOut != NULL) { chartableMatrixSeriesInterfaceOut = dynamic_cast(caretSeriesFile); chartMatrixDisplayPropertiesOut = chartableMatrixInterfaceOut->getChartMatrixDisplayProperties(browserTabIndexOut); caretMappableDataFileOut = chartableMatrixInterfaceOut->getMatrixChartCaretMappableDataFile(); return true; } } } break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: break; } // CaretDataFileSelectionModel* parcelFileSelectionModel = modelChart->getChartableMatrixParcelFileSelectionModel(browserTabIndexOut); // //m_matrixParcelFileSelectionComboBox->updateComboBox(parcelFileSelectionModel); // CaretDataFile* caretParcelFile = parcelFileSelectionModel->getSelectedFile(); // // CaretDataFileSelectionModel* seriesFileSelectionModel = modelChart->getChartableMatrixSeriesFileSelectionModel(browserTabIndexOut); // CaretDataFile* caretSeriesFile = seriesFileSelectionModel->getSelectedFile(); // // if (caretParcelFile != NULL) { // chartableMatrixInterfaceOut = dynamic_cast(caretParcelFile); // if (chartableMatrixInterfaceOut != NULL) { // chartableMatrixParcelInterfaceOut = dynamic_cast(caretParcelFile); // chartableMatrixSeriesInterfaceOut = dynamic_cast(caretParcelFile); // chartMatrixDisplayPropertiesOut = chartableMatrixInterfaceOut->getChartMatrixDisplayProperties(browserTabIndexOut); // caretMappableDataFileOut = chartableMatrixInterfaceOut->getMatrixChartCaretMappableDataFile(); // return true; // } // } } return false; } /** * Gets called when a change is made in the parcel label file remapping * selections. */ void ChartMatrixParcelSelectionViewController::parcelLabelFileRemappingFileSelectorChanged() { CaretMappableDataFile* caretMappableDataFile = NULL; ChartableMatrixInterface* chartableMatrixInterface = NULL; ChartMatrixDisplayProperties* chartMatrixDisplayProperties = NULL; ChartableMatrixParcelInterface* chartableMatrixParcelInterface = NULL; ChartableMatrixSeriesInterface* chartableMatrixSeriesInterface = NULL; int32_t browserTabIndex = -1; if ( ! getChartMatrixAndProperties(caretMappableDataFile, chartableMatrixInterface, chartableMatrixParcelInterface, chartableMatrixSeriesInterface, chartMatrixDisplayProperties, browserTabIndex)) { return; } CaretAssert(chartableMatrixParcelInterface); const bool remappingEnabled = m_parcelReorderingEnabledCheckBox->isChecked(); CaretMappableDataFileAndMapSelectionModel* model = m_parcelLabelFileRemappingFileSelector->getModel(); CiftiParcelLabelFile* parcelLabelFile = model->getSelectedFileOfType(); int32_t parcelLabelFileMapIndex = model->getSelectedMapIndex(); chartableMatrixParcelInterface->setSelectedParcelLabelFileAndMapForReordering(parcelLabelFile, parcelLabelFileMapIndex, remappingEnabled); if (remappingEnabled) { AString errorMessage; if ( ! chartableMatrixParcelInterface->createParcelReordering(parcelLabelFile, parcelLabelFileMapIndex, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } } } /** * Update the matrix chart widget. * * @param brain * The Brain. * @param modelChart * The Model for charts. * @param browserTabIndex * Index of the browser tab. */ void ChartMatrixParcelSelectionViewController::updateMatrixParcelChartWidget(Brain* /* brain */, ModelChart* modelChart, const int32_t /*browserTabIndex*/) { CaretMappableDataFile* caretMappableDataFile = NULL; ChartableMatrixInterface* chartableMatrixInterface = NULL; ChartMatrixDisplayProperties* chartMatrixDisplayProperties = NULL; ChartableMatrixParcelInterface* chartableMatrixParcelInterface = NULL; ChartableMatrixSeriesInterface* chartableMatrixSeriesInterface = NULL; int32_t browserTabIndex = -1; if ( ! getChartMatrixAndProperties(caretMappableDataFile, chartableMatrixInterface, chartableMatrixParcelInterface, chartableMatrixSeriesInterface, chartMatrixDisplayProperties, browserTabIndex)) { return; } if (chartableMatrixParcelInterface != NULL) { CaretDataFileSelectionModel* fileSelectionModel = modelChart->getChartableMatrixParcelFileSelectionModel(browserTabIndex); m_matrixParcelFileSelectionComboBox->updateComboBox(fileSelectionModel); const ChartMatrixLoadingDimensionEnum::Enum loadType = chartableMatrixParcelInterface->getMatrixLoadingDimension(); m_matrixParcelLoadByColumnRowComboBox->setSelectedItem(loadType); const YokingGroupEnum::Enum yokingGroup = chartableMatrixParcelInterface->getYokingGroup(); m_matrixParcelYokingGroupComboBox->setSelectedItem(yokingGroup); m_matrixParcelColorBarAction->blockSignals(true); m_matrixParcelColorBarAction->setChecked(chartMatrixDisplayProperties->getColorBar()->isDisplayed()); m_matrixParcelColorBarAction->blockSignals(false); m_matrixParcelYokingGroupComboBox->getWidget()->setEnabled(chartableMatrixParcelInterface->isSupportsLoadingAttributes()); m_matrixParcelLoadByColumnRowComboBox->getWidget()->setEnabled(chartableMatrixParcelInterface->isSupportsLoadingAttributes()); /* * Update palette reordering. */ std::vector parcelLabelFiles; CiftiParcelLabelFile* parcelLabelFile = NULL; int32_t parcelLabelFileMapIndex = -1; bool remappingEnabled = false; chartableMatrixParcelInterface->getSelectedParcelLabelFileAndMapForReordering(parcelLabelFiles, parcelLabelFile, parcelLabelFileMapIndex, remappingEnabled); std::vector caretMapDataFiles; if ( ! parcelLabelFiles.empty()) { caretMapDataFiles.insert(caretMapDataFiles.end(), parcelLabelFiles.begin(), parcelLabelFiles.end()); } m_parcelReorderingEnabledCheckBox->setChecked(remappingEnabled); CaretMappableDataFileAndMapSelectionModel* model = m_parcelLabelFileRemappingFileSelector->getModel(); model->overrideAvailableDataFiles(caretMapDataFiles); model->setSelectedFile(parcelLabelFile); model->setSelectedMapIndex(parcelLabelFileMapIndex); m_parcelLabelFileRemappingFileSelector->updateFileAndMapSelector(model); bool reorderCheckBoxEnabledFlag = false; if (model->getSelectedFile() != NULL) { if ((model->getSelectedMapIndex() >= 0) && (model->getSelectedMapIndex() < model->getSelectedFile()->getNumberOfMaps())) { reorderCheckBoxEnabledFlag = true; } } m_parcelReorderingEnabledCheckBox->setEnabled(reorderCheckBoxEnabledFlag); m_matrixParcelColorBarAction->setEnabled(caretMappableDataFile->isMappedWithPalette()); m_matrixParcelSettingsAction->setEnabled(caretMappableDataFile->isMappedWithPalette()); m_parcelRemappingGroupBox->setVisible(true); } m_parcelRemappingGroupBox->setEnabled(chartableMatrixParcelInterface != NULL); } connectome-workbench-1.4.2/src/GuiQt/ChartMatrixParcelSelectionViewController.h000066400000000000000000000110361360521144700277470ustar00rootroot00000000000000#ifndef __CHART_MATRIX_PARCEL_SELECTION_VIEW_CONTROLLER_H__ #define __CHART_MATRIX_PARCEL_SELECTION_VIEW_CONTROLLER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "EventListenerInterface.h" class QCheckBox; class QGroupBox; namespace caret { class Brain; class CaretDataFile; class CaretDataFileSelectionComboBox; class CaretMappableDataFile; class CaretMappableDataFileAndMapSelectorObject; class ChartMatrixDisplayProperties; class ChartableMatrixInterface; class ChartableMatrixParcelInterface; class ChartableMatrixSeriesInterface; class EnumComboBoxTemplate; class ModelChart; class ChartMatrixParcelSelectionViewController : public QWidget, public EventListenerInterface { Q_OBJECT public: ChartMatrixParcelSelectionViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, QWidget* parent); virtual ~ChartMatrixParcelSelectionViewController(); private slots: void matrixParcelFileSelected(CaretDataFile* caretDataFile); void matrixParcelFileLoadingComboBoxActivated(); void matrixParcelYokingGroupEnumComboBoxActivated(); void matrixParcelColorBarActionTriggered(bool status); void matrixParcelSettingsActionTriggered(); void parcelLabelFileRemappingFileSelectorChanged(); private: ChartMatrixParcelSelectionViewController(const ChartMatrixParcelSelectionViewController&); ChartMatrixParcelSelectionViewController& operator=(const ChartMatrixParcelSelectionViewController&); public: // ADD_NEW_METHODS_HERE virtual void receiveEvent(Event* event); private: // ADD_NEW_MEMBERS_HERE QGroupBox* createMatrixParcelChartWidget(const Qt::Orientation orientation); QGroupBox* createParcelRemappingWidget(const Qt::Orientation orientation); void updateSelectionViewController(); void updateMatrixParcelChartWidget(Brain* brain, ModelChart* modelChart, const int32_t browserTabIndex); bool getChartMatrixAndProperties(CaretMappableDataFile* &caretMappableDataFileOut, ChartableMatrixInterface* & chartableMatrixInterfaceOut, ChartableMatrixParcelInterface* &chartableMatrixParcelInterfaceOut, ChartableMatrixSeriesInterface* &chartableMatrixSeriesInterfaceOut, ChartMatrixDisplayProperties* &chartMatrixDisplayPropertiesOut, int32_t& browserTabIndexOut); QGroupBox* m_matrixParcelChartWidget; const int32_t m_browserWindowIndex; CaretDataFileSelectionComboBox* m_matrixParcelFileSelectionComboBox; EnumComboBoxTemplate* m_matrixParcelLoadByColumnRowComboBox; EnumComboBoxTemplate* m_matrixParcelYokingGroupComboBox; QAction* m_matrixParcelColorBarAction; QAction* m_matrixParcelSettingsAction; QGroupBox* m_parcelRemappingGroupBox; QCheckBox* m_parcelReorderingEnabledCheckBox; CaretMappableDataFileAndMapSelectorObject* m_parcelLabelFileRemappingFileSelector; }; #ifdef __CHART_MATRIX_PARCEL_SELECTION_VIEW_CONTROLLER_DECLARE__ #endif // __CHART_MATRIX_PARCEL_SELECTION_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__CHART_MATRIX_PARCEL_SELECTION_VIEW_CONTROLLER_H__ connectome-workbench-1.4.2/src/GuiQt/ChartMatrixSeriesSelectionViewController.cxx000066400000000000000000000521131360521144700303470ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_MATRIX_SERIES_SELECTION_VIEW_CONTROLLER_DECLARE__ #include "ChartMatrixSeriesSelectionViewController.h" #undef __CHART_MATRIX_SERIES_SELECTION_VIEW_CONTROLLER_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include #include #include "AnnotationColorBar.h" #include "Brain.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretDataFileSelectionComboBox.h" #include "CaretDataFileSelectionModel.h" #include "CaretLogger.h" #include "CaretMappableDataFile.h" #include "CaretMappableDataFileAndMapSelectorObject.h" #include "ChartableMatrixInterface.h" #include "ChartMatrixDisplayProperties.h" #include "ChartMatrixLoadingDimensionEnum.h" #include "ChartModel.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "CiftiMappableDataFile.h" #include "CiftiParcelLabelFile.h" #include "CiftiScalarDataSeriesFile.h" #include "DeveloperFlagsEnum.h" #include "EnumComboBoxTemplate.h" #include "EventChartMatrixParcelYokingValidation.h" #include "EventManager.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventPaletteColorMappingEditorDialogRequest.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "MapYokingGroupComboBox.h" #include "ModelChart.h" #include "WuQFactory.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::ChartMatrixSeriesSelectionViewController * \brief Handles selection of charts displayed in chart model. * \ingroup GuiQt */ /** * Constructor. */ ChartMatrixSeriesSelectionViewController::ChartMatrixSeriesSelectionViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { /* * ColorBar Tool Button */ QIcon colorBarIcon; const bool colorBarIconValid = WuQtUtilities::loadIcon(":/LayersPanel/colorbar.png", colorBarIcon); m_matrixSeriesColorBarAction = WuQtUtilities::createAction("CB", "Display color bar for this overlay", this, this, SLOT(matrixSeriesColorBarActionTriggered(bool))); m_matrixSeriesColorBarAction->setCheckable(true); if (colorBarIconValid) { m_matrixSeriesColorBarAction->setIcon(colorBarIcon); } QToolButton* colorBarToolButton = new QToolButton(); colorBarToolButton->setDefaultAction(m_matrixSeriesColorBarAction); /* * Settings Tool Button */ QLabel* settingsLabel = new QLabel("Settings"); QIcon settingsIcon; const bool settingsIconValid = WuQtUtilities::loadIcon(":/LayersPanel/wrench.png", settingsIcon); m_matrixSeriesSettingsAction = WuQtUtilities::createAction("S", "Edit settings for this map and overlay", this, this, SLOT(matrixSeriesSettingsActionTriggered())); if (settingsIconValid) { m_matrixSeriesSettingsAction->setIcon(settingsIcon); } QToolButton* settingsToolButton = new QToolButton(); settingsToolButton->setDefaultAction(m_matrixSeriesSettingsAction); QLabel* fileLabel = new QLabel("Matrix File"); m_matrixSeriesFileSelectionComboBox = new CaretDataFileSelectionComboBox(this); QObject::connect(m_matrixSeriesFileSelectionComboBox, SIGNAL(fileSelected(CaretDataFile*)), this, SLOT(matrixSeriesFileSelected(CaretDataFile*))); /* * Yoking Group */ QLabel* yokeLabel = new QLabel("Yoke "); m_matrixSeriesYokingComboBox = new MapYokingGroupComboBox(this); m_matrixSeriesYokingComboBox->getWidget()->setStatusTip("Synchronize enabled status and map indices)"); m_matrixSeriesYokingComboBox->getWidget()->setToolTip("Yoke to Overlay Mapped Files"); QObject::connect(m_matrixSeriesYokingComboBox, SIGNAL(itemActivated()), this, SLOT(matrixSeriesYokingGroupActivated())); QWidget* gridWidget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(gridWidget); switch (orientation) { case Qt::Horizontal: { WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 0); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 0); gridLayout->setColumnStretch(2, 0); gridLayout->setColumnStretch(3, 100); gridLayout->addWidget(settingsLabel, 0, 0, 1, 2, Qt::AlignHCenter); gridLayout->addWidget(yokeLabel, 0, 2, Qt::AlignHCenter); gridLayout->addWidget(fileLabel, 0, 3, Qt::AlignHCenter); gridLayout->addWidget(settingsToolButton, 1, 0); gridLayout->addWidget(colorBarToolButton, 1, 1); gridLayout->addWidget(m_matrixSeriesYokingComboBox->getWidget(), 1, 2); gridLayout->addWidget(m_matrixSeriesFileSelectionComboBox->getWidget(), 1, 3); } break; case Qt::Vertical: { WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 0); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 0); gridLayout->setColumnStretch(2, 0); gridLayout->setColumnStretch(3, 100); gridLayout->addWidget(settingsLabel, 0, 0, 1, 2, Qt::AlignHCenter); gridLayout->addWidget(yokeLabel, 0, 2, Qt::AlignHCenter); gridLayout->addWidget(settingsToolButton, 1, 0); gridLayout->addWidget(colorBarToolButton, 1, 1); gridLayout->addWidget(m_matrixSeriesYokingComboBox->getWidget(), 1, 2); gridLayout->addWidget(fileLabel, 2, 0, 1, 4, Qt::AlignHCenter); gridLayout->addWidget(m_matrixSeriesFileSelectionComboBox->getWidget(), 3, 0, 1, 4); } break; default: CaretAssert(0); break; } gridWidget->setSizePolicy(gridWidget->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 1, 0); layout->addWidget(gridWidget); layout->addStretch(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); } /** * Destructor. */ ChartMatrixSeriesSelectionViewController::~ChartMatrixSeriesSelectionViewController() { EventManager::get()->removeAllEventsFromListener(this); } /** * Update the view controller. */ void ChartMatrixSeriesSelectionViewController::updateSelectionViewController() { Brain* brain = GuiManager::get()->getBrain(); BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); ChartOneDataTypeEnum::Enum chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { chartDataType = modelChart->getSelectedChartOneDataType(browserTabIndex); } if (chartDataType == ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES) { CaretMappableDataFile* caretMappableDataFile = NULL; ChartableMatrixInterface* chartableMatrixInterface = NULL; ChartMatrixDisplayProperties* chartMatrixDisplayProperties = NULL; ChartableMatrixParcelInterface* chartableMatrixParcelInterface = NULL; ChartableMatrixSeriesInterface* chartableMatrixSeriesInterface = NULL; int32_t browserTabIndex = -1; if ( ! getChartMatrixAndProperties(caretMappableDataFile, chartableMatrixInterface, chartableMatrixParcelInterface, chartableMatrixSeriesInterface, chartMatrixDisplayProperties, browserTabIndex)) { return; } if (chartableMatrixSeriesInterface != NULL) { CaretDataFileSelectionModel* fileSelectionModel = modelChart->getChartableMatrixSeriesFileSelectionModel(browserTabIndex); m_matrixSeriesFileSelectionComboBox->updateComboBox(fileSelectionModel); const MapYokingGroupEnum::Enum yokingGroup = chartableMatrixSeriesInterface->getMatrixRowColumnMapYokingGroup(browserTabIndex); m_matrixSeriesYokingComboBox->setMapYokingGroup(yokingGroup); m_matrixSeriesColorBarAction->blockSignals(true); m_matrixSeriesColorBarAction->setChecked(chartMatrixDisplayProperties->getColorBar()->isDisplayed()); m_matrixSeriesColorBarAction->blockSignals(false); m_matrixSeriesColorBarAction->setEnabled(caretMappableDataFile->isMappedWithPalette()); m_matrixSeriesSettingsAction->setEnabled(caretMappableDataFile->isMappedWithPalette()); } } } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void ChartMatrixSeriesSelectionViewController::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiEvent = dynamic_cast(event); CaretAssert(uiEvent); if (uiEvent->isUpdateForWindow(m_browserWindowIndex) || uiEvent->isToolBoxUpdate()) { this->updateSelectionViewController(); uiEvent->setEventProcessed(); } } } /** * Get the matrix related files and properties in this view controller. * * @param caretMappableDataFileOut * Output with selected caret mappable data file. * @param chartableMatrixInterfaceOut * Output with ChartableMatrixInterface implemented by the caret * mappable data file. * @param chartableMatrixParcelInterfaceOut * Output with ChartableMatrixParcelInterfaceOut implemented by the * caret mappable data file (may be NULL). * @param chartableMatrixSeriesInterfaceOut * Output with ChartableMatrixSeriesInterfaceOut implemented by the * caret mappable data file (may be NULL). * @param browserTabIndexOut * Index selected tab. * @param chartMatrixDisplayPropertiesOut * Matrix display properties from the ChartableMatrixInterface. * @return True if all output values are valid, else false. */ bool ChartMatrixSeriesSelectionViewController::getChartMatrixAndProperties(CaretMappableDataFile* &caretMappableDataFileOut, ChartableMatrixInterface* & chartableMatrixInterfaceOut, ChartableMatrixParcelInterface* &chartableMatrixParcelInterfaceOut, ChartableMatrixSeriesInterface* &chartableMatrixSeriesInterfaceOut, ChartMatrixDisplayProperties* &chartMatrixDisplayPropertiesOut, int32_t& browserTabIndexOut) { caretMappableDataFileOut = NULL; chartableMatrixInterfaceOut = NULL; chartableMatrixParcelInterfaceOut = NULL; chartableMatrixSeriesInterfaceOut = NULL; chartMatrixDisplayPropertiesOut = NULL; browserTabIndexOut = -1; Brain* brain = GuiManager::get()->getBrain(); BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return false; } browserTabIndexOut = browserTabContent->getTabNumber(); if (browserTabIndexOut < 0) { return false; } ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { switch (modelChart->getSelectedChartOneDataType(browserTabIndexOut)) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: { CaretDataFileSelectionModel* parcelFileSelectionModel = modelChart->getChartableMatrixParcelFileSelectionModel(browserTabIndexOut); //m_matrixParcelFileSelectionComboBox->updateComboBox(parcelFileSelectionModel); CaretDataFile* caretParcelFile = parcelFileSelectionModel->getSelectedFile(); if (caretParcelFile != NULL) { chartableMatrixInterfaceOut = dynamic_cast(caretParcelFile); if (chartableMatrixInterfaceOut != NULL) { chartableMatrixParcelInterfaceOut = dynamic_cast(caretParcelFile); chartMatrixDisplayPropertiesOut = chartableMatrixInterfaceOut->getChartMatrixDisplayProperties(browserTabIndexOut); caretMappableDataFileOut = chartableMatrixInterfaceOut->getMatrixChartCaretMappableDataFile(); return true; } } } break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: { CaretDataFileSelectionModel* seriesFileSelectionModel = modelChart->getChartableMatrixSeriesFileSelectionModel(browserTabIndexOut); CaretDataFile* caretSeriesFile = seriesFileSelectionModel->getSelectedFile(); if (caretSeriesFile != NULL) { chartableMatrixInterfaceOut = dynamic_cast(caretSeriesFile); if (chartableMatrixInterfaceOut != NULL) { chartableMatrixSeriesInterfaceOut = dynamic_cast(caretSeriesFile); chartMatrixDisplayPropertiesOut = chartableMatrixInterfaceOut->getChartMatrixDisplayProperties(browserTabIndexOut); caretMappableDataFileOut = chartableMatrixInterfaceOut->getMatrixChartCaretMappableDataFile(); return true; } } } break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: break; } } return false; } /** * Called when a matrix series file is selected. * * @param caretDataFile * Caret data file that was selected. */ void ChartMatrixSeriesSelectionViewController::matrixSeriesFileSelected(CaretDataFile* /*caretDataFile*/) { updateSelectionViewController(); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(m_browserWindowIndex).getPointer()); } /** * Called when colorbar icon button is clicked for matrix series file. */ void ChartMatrixSeriesSelectionViewController::matrixSeriesColorBarActionTriggered(bool status) { CaretMappableDataFile* caretMappableDataFile = NULL; ChartableMatrixInterface* chartableMatrixInterface = NULL; ChartMatrixDisplayProperties* chartMatrixDisplayProperties = NULL; ChartableMatrixParcelInterface* chartableMatrixParcelInterface = NULL; ChartableMatrixSeriesInterface* chartableMatrixSeriesInterface = NULL; int32_t browserTabIndex = -1; if ( ! getChartMatrixAndProperties(caretMappableDataFile, chartableMatrixInterface, chartableMatrixParcelInterface, chartableMatrixSeriesInterface, chartMatrixDisplayProperties, browserTabIndex)) { return; } if (chartableMatrixSeriesInterface != NULL) { chartMatrixDisplayProperties->getColorBar()->setDisplayed(status); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } /** * Called when settings icon button is clicked to display palette editor * for matrix series file. */ void ChartMatrixSeriesSelectionViewController::matrixSeriesSettingsActionTriggered() { CaretMappableDataFile* caretMappableDataFile = NULL; ChartableMatrixInterface* chartableMatrixInterface = NULL; ChartMatrixDisplayProperties* chartMatrixDisplayProperties = NULL; ChartableMatrixParcelInterface* chartableMatrixParcelInterface = NULL; ChartableMatrixSeriesInterface* chartableMatrixSeriesInterface = NULL; int32_t browserTabIndex = -1; if ( ! getChartMatrixAndProperties(caretMappableDataFile, chartableMatrixInterface, chartableMatrixParcelInterface, chartableMatrixSeriesInterface, chartMatrixDisplayProperties, browserTabIndex)) { return; } if (chartableMatrixSeriesInterface != NULL) { const int32_t mapIndex = 0; EventPaletteColorMappingEditorDialogRequest dialogEvent(m_browserWindowIndex, caretMappableDataFile, mapIndex); EventManager::get()->sendEvent(dialogEvent.getPointer()); } } /** * Called when matrix series yoking group is changed. */ void ChartMatrixSeriesSelectionViewController::matrixSeriesYokingGroupActivated() { CaretMappableDataFile* caretMappableDataFile = NULL; ChartableMatrixInterface* chartableMatrixInterface = NULL; ChartMatrixDisplayProperties* chartMatrixDisplayProperties = NULL; ChartableMatrixParcelInterface* chartableMatrixParcelInterface = NULL; ChartableMatrixSeriesInterface* chartableMatrixSeriesInterface = NULL; int32_t browserTabIndex = -1; if ( ! getChartMatrixAndProperties(caretMappableDataFile, chartableMatrixInterface, chartableMatrixParcelInterface, chartableMatrixSeriesInterface, chartMatrixDisplayProperties, browserTabIndex)) { return; } m_matrixSeriesYokingComboBox->validateYokingChange(chartableMatrixSeriesInterface, browserTabIndex); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } connectome-workbench-1.4.2/src/GuiQt/ChartMatrixSeriesSelectionViewController.h000066400000000000000000000070551360521144700300010ustar00rootroot00000000000000#ifndef __CHART_MATRIX_SERIES_SELECTION_VIEW_CONTROLLER_H__ #define __CHART_MATRIX_SERIES_SELECTION_VIEW_CONTROLLER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "EventListenerInterface.h" namespace caret { class CaretDataFile; class CaretDataFileSelectionComboBox; class CaretMappableDataFile; class ChartMatrixDisplayProperties; class ChartableMatrixInterface; class ChartableMatrixParcelInterface; class ChartableMatrixSeriesInterface; class MapYokingGroupComboBox; class ChartMatrixSeriesSelectionViewController : public QWidget, public EventListenerInterface { Q_OBJECT public: ChartMatrixSeriesSelectionViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, QWidget* parent); virtual ~ChartMatrixSeriesSelectionViewController(); private slots: void matrixSeriesFileSelected(CaretDataFile* caretDataFile); void matrixSeriesColorBarActionTriggered(bool status); void matrixSeriesSettingsActionTriggered(); void matrixSeriesYokingGroupActivated(); private: ChartMatrixSeriesSelectionViewController(const ChartMatrixSeriesSelectionViewController&); ChartMatrixSeriesSelectionViewController& operator=(const ChartMatrixSeriesSelectionViewController&); public: // ADD_NEW_METHODS_HERE virtual void receiveEvent(Event* event); private: // ADD_NEW_MEMBERS_HERE void updateSelectionViewController(); bool getChartMatrixAndProperties(CaretMappableDataFile* &caretMappableDataFileOut, ChartableMatrixInterface* & chartableMatrixInterfaceOut, ChartableMatrixParcelInterface* &chartableMatrixParcelInterfaceOut, ChartableMatrixSeriesInterface* &chartableMatrixSeriesInterfaceOut, ChartMatrixDisplayProperties* &chartMatrixDisplayPropertiesOut, int32_t& browserTabIndexOut); const int32_t m_browserWindowIndex; QAction* m_matrixSeriesColorBarAction; QAction* m_matrixSeriesSettingsAction; CaretDataFileSelectionComboBox* m_matrixSeriesFileSelectionComboBox; MapYokingGroupComboBox* m_matrixSeriesYokingComboBox; }; #ifdef __CHART_MATRIX_SERIES_SELECTION_VIEW_CONTROLLER_DECLARE__ #endif // __CHART_MATRIX_SERIES_SELECTION_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__CHART_MATRIX_SERIES_SELECTION_VIEW_CONTROLLER_H__ connectome-workbench-1.4.2/src/GuiQt/ChartSelectionViewController.cxx000066400000000000000000000144221360521144700260100ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_SELECTION_VIEW_CONTROLLER_DECLARE__ #include "ChartSelectionViewController.h" #undef __CHART_SELECTION_VIEW_CONTROLLER_DECLARE__ #include #include #include #include "Brain.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "ChartLinesSelectionViewController.h" #include "ChartMatrixParcelSelectionViewController.h" #include "ChartMatrixSeriesSelectionViewController.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "ModelChart.h" #include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::ChartSelectionViewController * \brief Handles selection of charts displayed in chart model. * \ingroup GuiQt */ /** * Constructor. */ ChartSelectionViewController::ChartSelectionViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { const QString objectNamePrefix(parentObjectName + ":History"); m_mode = MODE_INVALID; m_brainordinateChartWidget = new ChartLinesSelectionViewController(orientation, browserWindowIndex, parent); m_matrixParcelChartWidget = new ChartMatrixParcelSelectionViewController(orientation, browserWindowIndex, parent); m_matrixSeriesChartWidget = new ChartMatrixSeriesSelectionViewController(orientation, browserWindowIndex, parent); m_stackedWidget = new QStackedWidget(); m_stackedWidget->addWidget(m_brainordinateChartWidget); m_stackedWidget->addWidget(m_matrixParcelChartWidget); m_stackedWidget->addWidget(m_matrixSeriesChartWidget); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 0); layout->addWidget(m_stackedWidget); layout->addStretch(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); } /** * Destructor. */ ChartSelectionViewController::~ChartSelectionViewController() { EventManager::get()->removeAllEventsFromListener(this); } /** * Update the view controller. */ void ChartSelectionViewController::updateSelectionViewController() { m_mode = MODE_INVALID; Brain* brain = GuiManager::get()->getBrain(); BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); ChartOneDataTypeEnum::Enum chartDataType = ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID; ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { chartDataType = modelChart->getSelectedChartOneDataType(browserTabIndex); } switch (chartDataType) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: m_mode = MODE_MATRIX_LAYER; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: m_mode = MODE_MATRIX_SERIES; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: m_mode = MODE_BRAINORDINATE; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: m_mode = MODE_BRAINORDINATE; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: m_mode = MODE_BRAINORDINATE; break; } switch (m_mode) { case MODE_INVALID: break; case MODE_BRAINORDINATE: m_stackedWidget->setCurrentWidget(m_brainordinateChartWidget); //m_brainordinateChartWidget->updateSelectionViewController(); break; case MODE_MATRIX_LAYER: m_stackedWidget->setCurrentWidget(m_matrixParcelChartWidget); //m_matrixParcelChartWidget->updateSelectionViewController(); break; case MODE_MATRIX_SERIES: m_stackedWidget->setCurrentWidget(m_matrixSeriesChartWidget); //m_matrixSeriesChartWidget->updateSelectionViewController(); break; } } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void ChartSelectionViewController::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiEvent = dynamic_cast(event); CaretAssert(uiEvent); if (uiEvent->isUpdateForWindow(m_browserWindowIndex) || uiEvent->isToolBoxUpdate()) { this->updateSelectionViewController(); uiEvent->setEventProcessed(); } } } connectome-workbench-1.4.2/src/GuiQt/ChartSelectionViewController.h000066400000000000000000000053221360521144700254340ustar00rootroot00000000000000#ifndef __CHART_SELECTION_VIEW_CONTROLLER_H__ #define __CHART_SELECTION_VIEW_CONTROLLER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "EventListenerInterface.h" class QStackedWidget; namespace caret { class ChartLinesSelectionViewController; class ChartMatrixParcelSelectionViewController; class ChartMatrixSeriesSelectionViewController; class ChartSelectionViewController : public QWidget, public EventListenerInterface { Q_OBJECT public: ChartSelectionViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent); virtual ~ChartSelectionViewController(); private: ChartSelectionViewController(const ChartSelectionViewController&); ChartSelectionViewController& operator=(const ChartSelectionViewController&); public: // ADD_NEW_METHODS_HERE virtual void receiveEvent(Event* event); private: enum Mode { MODE_INVALID, MODE_BRAINORDINATE, MODE_MATRIX_LAYER, MODE_MATRIX_SERIES }; // ADD_NEW_MEMBERS_HERE void updateSelectionViewController(); QStackedWidget* m_stackedWidget; ChartLinesSelectionViewController* m_brainordinateChartWidget; ChartMatrixParcelSelectionViewController* m_matrixParcelChartWidget; ChartMatrixSeriesSelectionViewController* m_matrixSeriesChartWidget; Mode m_mode; const int32_t m_browserWindowIndex; }; #ifdef __CHART_SELECTION_VIEW_CONTROLLER_DECLARE__ #endif // __CHART_SELECTION_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__CHART_SELECTION_VIEW_CONTROLLER_H__ connectome-workbench-1.4.2/src/GuiQt/ChartToolBoxViewController.cxx000066400000000000000000000240201360521144700254440ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_TOOL_BOX_VIEW_CONTROLLER_DECLARE__ #include "ChartToolBoxViewController.h" #undef __CHART_TOOL_BOX_VIEW_CONTROLLER_DECLARE__ #include #include #include #include "Brain.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "ChartHistoryViewController.h" #include "ChartModel.h" #include "ChartModelDataSeries.h" #include "ChartModelFrequencySeries.h" #include "ChartModelTimeSeries.h" #include "ChartSelectionViewController.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "ModelChart.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "WuQMacroManager.h" using namespace caret; /** * \class caret::ChartToolBoxViewController * \brief View controller for the "Charting" tab of the overlay toolbox * \ingroup GuiQt */ /** * Constructor. * * @param orientation * Orientation of toolbox * @param browserWindowIndex * Index of browser window * @param parentObjectName * Name of parent object for macros * @param parent * Parent widget */ ChartToolBoxViewController::ChartToolBoxViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent) : QWidget(parent), EventListenerInterface(), m_browserWindowIndex(browserWindowIndex) { const QString objectNamePrefix(parentObjectName + ":Chart"); /* * Data series widgets */ m_chartSelectionViewController = new ChartSelectionViewController(orientation, browserWindowIndex, objectNamePrefix, NULL); m_chartHistoryViewController = new ChartHistoryViewController(orientation, browserWindowIndex, objectNamePrefix, NULL); m_tabWidget = new QTabWidget(); m_tabWidget->addTab(m_chartSelectionViewController, "Loading"); m_tabWidget->addTab(m_chartHistoryViewController, "History"); m_tabWidget->setObjectName(objectNamePrefix + ":Tab"); WuQMacroManager::instance()->addMacroSupportToObjectWithToolTip(m_tabWidget, "Overlay ToolBox Chart Tab", ""); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(m_tabWidget); layout->addStretch(); m_sceneAssistant = new SceneClassAssistant(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); } /** * Destructor. */ ChartToolBoxViewController::~ChartToolBoxViewController() { EventManager::get()->removeAllEventsFromListener(this); delete m_sceneAssistant; } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void ChartToolBoxViewController::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiEvent = dynamic_cast(event); CaretAssert(uiEvent); if (uiEvent->isUpdateForWindow(m_browserWindowIndex) || uiEvent->isToolBoxUpdate()) { uiEvent->setEventProcessed(); ChartModel* chartModel = getSelectedChartModel(); bool historyWidgetValid = false; if (chartModel != NULL) { switch (chartModel->getChartDataType()) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: historyWidgetValid = true; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: historyWidgetValid = true; break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: historyWidgetValid = true; break; } } const int32_t historyTabIndex = m_tabWidget->indexOf(m_chartHistoryViewController); if (historyTabIndex >= 0) { m_tabWidget->setTabEnabled(historyTabIndex, historyWidgetValid); } if ( ! historyWidgetValid) { m_tabWidget->setCurrentWidget(m_chartSelectionViewController); } } } } /** * @return Chart model selected in the selected tab (NULL if not valid) */ ChartModel* ChartToolBoxViewController::getSelectedChartModel() { Brain* brain = GuiManager::get()->getBrain(); BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return NULL; } ChartModel* chartModel = NULL; ModelChart* modelChart = brain->getChartModel(); if (modelChart != NULL) { const int32_t browserTabIndex = browserTabContent->getTabNumber(); switch (modelChart->getSelectedChartOneDataType(browserTabIndex)) { case ChartOneDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_LAYER: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_MATRIX_SERIES: break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_DATA_SERIES: chartModel = modelChart->getSelectedDataSeriesChartModel(browserTabIndex); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_FREQUENCY_SERIES: chartModel = modelChart->getSelectedFrequencySeriesChartModel(browserTabIndex); break; case ChartOneDataTypeEnum::CHART_DATA_TYPE_LINE_TIME_SERIES: chartModel = modelChart->getSelectedTimeSeriesChartModel(browserTabIndex); break; } } return chartModel; } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* ChartToolBoxViewController::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ChartToolBoxViewController", 1); AString tabName; const int tabIndex = m_tabWidget->currentIndex(); if ((tabIndex >= 0) && tabIndex < m_tabWidget->count()) { tabName = m_tabWidget->tabText(tabIndex); } sceneClass->addString("selectedChartTabName", tabName); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ChartToolBoxViewController::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } const AString tabName = sceneClass->getStringValue("selectedChartTabName", ""); for (int32_t i = 0; i < m_tabWidget->count(); i++) { if (m_tabWidget->tabText(i) == tabName) { m_tabWidget->setCurrentIndex(i); break; } } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/GuiQt/ChartToolBoxViewController.h000066400000000000000000000066161360521144700251040ustar00rootroot00000000000000#ifndef __CHART_TOOL_BOX_VIEW_CONTROLLER_H__ #define __CHART_TOOL_BOX_VIEW_CONTROLLER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "EventListenerInterface.h" #include "SceneableInterface.h" class QStackedWidget; class QTabWidget; namespace caret { class ChartHistoryViewController; class ChartModel; class ChartSelectionViewController; class SceneClassAssistant; class ChartToolBoxViewController : public QWidget, public EventListenerInterface, public SceneableInterface { Q_OBJECT public: ChartToolBoxViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent); virtual ~ChartToolBoxViewController(); // ADD_NEW_METHODS_HERE virtual void receiveEvent(Event* event); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implemetation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: ChartToolBoxViewController(const ChartToolBoxViewController&); ChartToolBoxViewController& operator=(const ChartToolBoxViewController&); ChartModel* getSelectedChartModel(); SceneClassAssistant* m_sceneAssistant; const int32_t m_browserWindowIndex; QTabWidget* m_tabWidget; ChartSelectionViewController* m_chartSelectionViewController; ChartHistoryViewController* m_chartHistoryViewController; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHART_TOOL_BOX_VIEW_CONTROLLER_DECLARE__ // #endif // __CHART_TOOL_BOX_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__CHART_TOOL_BOX_VIEW_CONTROLLER_H__ connectome-workbench-1.4.2/src/GuiQt/ChartTwoOverlaySetViewController.cxx000066400000000000000000000432411360521144700266530ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_OVERLAY_SET_VIEW_CONTROLLER_DECLARE__ #include "ChartTwoOverlaySetViewController.h" #undef __CHART_OVERLAY_SET_VIEW_CONTROLLER_DECLARE__ #include #include #include #include #include #include #include #include #include #include "BrainConstants.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "ChartTwoOverlay.h" #include "ChartTwoOverlaySet.h" #include "ChartTwoOverlayViewController.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "MapYokingGroupComboBox.h" #include "WuQGridLayoutGroup.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::ChartTwoOverlaySetViewController * \brief View controller for a chart overlay set * \ingroup GuiQt */ /** * Constructor. * @param orientation * Orientation for layout * @param browserWindowIndex * Index of browser window that contains this view controller. * @param parentObjectName * Name of parent object for macros * @param parent * Parent widget. */ ChartTwoOverlaySetViewController::ChartTwoOverlaySetViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { QWidget* gridWidget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(gridWidget); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 4, 2); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { ChartTwoOverlayViewController* ovc = new ChartTwoOverlayViewController(orientation, m_browserWindowIndex, i, parentObjectName, this); m_chartOverlayViewControllers.push_back(ovc); m_chartOverlayGridLayoutGroups.push_back(new WuQGridLayoutGroup(gridLayout, this)); QObject::connect(ovc, SIGNAL(requestAddOverlayAbove(const int32_t)), this, SLOT(processAddOverlayAbove(const int32_t))); QObject::connect(ovc, SIGNAL(requestAddOverlayBelow(const int32_t)), this, SLOT(processAddOverlayBelow(const int32_t))); QObject::connect(ovc, SIGNAL(requestRemoveOverlay(const int32_t)), this, SLOT(processRemoveOverlay(const int32_t))); QObject::connect(ovc, SIGNAL(requestMoveOverlayUp(const int32_t)), this, SLOT(processMoveOverlayUp(const int32_t))); QObject::connect(ovc, SIGNAL(requestMoveOverlayDown(const int32_t)), this, SLOT(processMoveOverlayDown(const int32_t))); } if (orientation == Qt::Horizontal) { static const int COLUMN_ON = 0; static const int COLUMN_LOAD = 1; static const int COLUMN_SETTINGS_EDIT = 2; static const int COLUMN_SETTINGS_COLOR_BAR = 3; static const int COLUMN_SETTINGS_CONSTRUCTION = 4; static const int COLUMN_MATRIX_VIEW = 5; static const int COLUMN_AXIS = 6; static const int COLUMN_FILE = 7; static const int COLUMN_YOKE = 8; static const int COLUMN_MAP_INDEX = 9; static const int COLUMN_ALL_MAPS = 10; static const int COLUMN_MAP_NAME = 11; gridLayout->setColumnStretch(COLUMN_ON, 0); gridLayout->setColumnStretch(COLUMN_LOAD, 0); gridLayout->setColumnStretch(COLUMN_SETTINGS_EDIT, 0); gridLayout->setColumnStretch(COLUMN_SETTINGS_COLOR_BAR, 0); gridLayout->setColumnStretch(COLUMN_SETTINGS_CONSTRUCTION, 0); gridLayout->setColumnStretch(COLUMN_MATRIX_VIEW, 0); gridLayout->setColumnStretch(COLUMN_AXIS, 0); gridLayout->setColumnStretch(COLUMN_FILE, 100); gridLayout->setColumnStretch(COLUMN_YOKE, 0); gridLayout->setColumnStretch(COLUMN_ALL_MAPS, 0); gridLayout->setColumnStretch(COLUMN_MAP_INDEX, 0); gridLayout->setColumnStretch(COLUMN_MAP_NAME, 100); QLabel* onLabel = new QLabel("On"); QLabel* loadLabel = new QLabel("Load"); QLabel* settingsLabel = new QLabel("Settings"); QLabel* fileLabel = new QLabel("File"); QLabel* yokeLabel = new QLabel("Yoke"); QLabel* allMapsLabel = new QLabel("All"); m_mapRowOrColumnIndexLabel = new QLabel("Index"); m_mapRowOrColumnNameLabel = new QLabel("Name"); int row = gridLayout->rowCount(); gridLayout->addWidget(onLabel, row, COLUMN_ON, Qt::AlignHCenter); gridLayout->addWidget(loadLabel, row, COLUMN_LOAD, Qt::AlignHCenter); gridLayout->addWidget(settingsLabel, row, COLUMN_SETTINGS_EDIT, 1, 5, Qt::AlignHCenter); gridLayout->addWidget(fileLabel, row, COLUMN_FILE, Qt::AlignHCenter); gridLayout->addWidget(yokeLabel, row, COLUMN_YOKE, Qt::AlignHCenter); gridLayout->addWidget(allMapsLabel, row, COLUMN_ALL_MAPS, Qt::AlignHCenter); gridLayout->addWidget(m_mapRowOrColumnIndexLabel, row, COLUMN_MAP_INDEX, Qt::AlignHCenter); gridLayout->addWidget(m_mapRowOrColumnNameLabel, row, COLUMN_MAP_NAME, Qt::AlignHCenter); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { row = gridLayout->rowCount(); ChartTwoOverlayViewController* covc = m_chartOverlayViewControllers[i]; WuQGridLayoutGroup* glg = m_chartOverlayGridLayoutGroups[i]; glg->addWidget(covc->m_enabledCheckBox, row, COLUMN_ON, Qt::AlignHCenter); glg->addWidget(covc->m_lineSeriesLoadingEnabledCheckBox, row, COLUMN_LOAD, Qt::AlignHCenter); glg->addWidget(covc->m_settingsToolButton, row, COLUMN_SETTINGS_EDIT, Qt::AlignHCenter); glg->addWidget(covc->m_colorBarToolButton, row, COLUMN_SETTINGS_COLOR_BAR, Qt::AlignHCenter); glg->addWidget(covc->m_constructionToolButton, row, COLUMN_SETTINGS_CONSTRUCTION, Qt::AlignHCenter); glg->addWidget(covc->m_matrixTriangularViewModeToolButton, row, COLUMN_MATRIX_VIEW, Qt::AlignHCenter); glg->addWidget(covc->m_axisLocationToolButton, row, COLUMN_AXIS, Qt::AlignHCenter); glg->addWidget(covc->m_mapFileComboBox, row, COLUMN_FILE); glg->addWidget(covc->m_mapRowOrColumnYokingGroupComboBox->getWidget(), row, COLUMN_YOKE, Qt::AlignHCenter); glg->addWidget(covc->m_allMapsCheckBox, row, COLUMN_ALL_MAPS, Qt::AlignHCenter); glg->addWidget(covc->m_mapRowOrColumnIndexSpinBox, row, COLUMN_MAP_INDEX, Qt::AlignHCenter); glg->addWidget(covc->m_mapRowOrColumnNameComboBox, row, COLUMN_MAP_NAME); } } else { static const int ROW_ONE_COLUMN_ON = 0; static const int ROW_ONE_COLUMN_SETTINGS_EDIT = 1; static const int ROW_ONE_COLUMN_SETTINGS_COLOR_BAR = 2; static const int ROW_ONE_COLUMN_SETTINGS_CONSTRUCTION = 3; static const int ROW_ONE_COLUMN_MATRIX_VIEW = 4; static const int ROW_ONE_COLUMN_AXIS = 5; static const int ROW_ONE_COLUMN_FILE_LABEL = 6; static const int ROW_ONE_COLUMN_FILE_COMBO_BOX = 7; static const int ROW_TWO_COLUMN_LOAD = 0; static const int ROW_TWO_COLUMN_YOKE = 2; static const int ROW_TWO_COLUMN_ALL_MAPS = 4; static const int ROW_TWO_COLUMN_MAP_INDEX = 6; static const int ROW_TWO_COLUMN_MAP_NAME = 7; gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 0); gridLayout->setColumnStretch(2, 0); gridLayout->setColumnStretch(3, 0); gridLayout->setColumnStretch(4, 0); gridLayout->setColumnStretch(5, 0); gridLayout->setColumnStretch(6, 0); gridLayout->setColumnStretch(7, 100); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { WuQGridLayoutGroup* glg = m_chartOverlayGridLayoutGroups[i]; int row = gridLayout->rowCount(); if (i > 0) { QFrame* bottomHorizontalLineWidget = new QFrame(); bottomHorizontalLineWidget->setLineWidth(0); bottomHorizontalLineWidget->setMidLineWidth(1); bottomHorizontalLineWidget->setFrameStyle(QFrame::HLine | QFrame::Raised); glg->addWidget(bottomHorizontalLineWidget, row, 0, 1, -1); row++; } ChartTwoOverlayViewController* covc = m_chartOverlayViewControllers[i]; QLabel* fileLabel = new QLabel("File"); glg->addWidget(covc->m_enabledCheckBox, row, ROW_ONE_COLUMN_ON, Qt::AlignLeft); glg->addWidget(covc->m_settingsToolButton, row, ROW_ONE_COLUMN_SETTINGS_EDIT, Qt::AlignHCenter); glg->addWidget(covc->m_colorBarToolButton, row, ROW_ONE_COLUMN_SETTINGS_COLOR_BAR, Qt::AlignHCenter); glg->addWidget(covc->m_constructionToolButton, row, ROW_ONE_COLUMN_SETTINGS_CONSTRUCTION, Qt::AlignHCenter); glg->addWidget(covc->m_matrixTriangularViewModeToolButton, row, ROW_ONE_COLUMN_MATRIX_VIEW, Qt::AlignHCenter); glg->addWidget(covc->m_axisLocationToolButton, row, ROW_ONE_COLUMN_AXIS, Qt::AlignHCenter); glg->addWidget(fileLabel, row, ROW_ONE_COLUMN_FILE_LABEL, Qt::AlignHCenter); glg->addWidget(covc->m_mapFileComboBox, row, ROW_ONE_COLUMN_FILE_COMBO_BOX, 1, 2); row++; glg->addWidget(covc->m_lineSeriesLoadingEnabledCheckBox, row, ROW_TWO_COLUMN_LOAD, Qt::AlignLeft); glg->addWidget(covc->m_mapRowOrColumnYokingGroupComboBox->getWidget(), row, ROW_TWO_COLUMN_YOKE, 1, 2, Qt::AlignHCenter); glg->addWidget(covc->m_allMapsCheckBox, row, ROW_TWO_COLUMN_ALL_MAPS, 1, 2, Qt::AlignHCenter); glg->addWidget(covc->m_mapRowOrColumnIndexSpinBox, row, ROW_TWO_COLUMN_MAP_INDEX, Qt::AlignHCenter); glg->addWidget(covc->m_mapRowOrColumnNameComboBox, row, ROW_TWO_COLUMN_MAP_NAME); } } if (orientation == Qt::Horizontal) { QVBoxLayout* verticalLayout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(verticalLayout, 2, 2); verticalLayout->addWidget(gridWidget); verticalLayout->addStretch(); } else { /* * Resolve WB-649 */ QVBoxLayout* verticalLayout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(verticalLayout, 1, 1); verticalLayout->addWidget(gridWidget); verticalLayout->addStretch(); } EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); } /** * Destructor. */ ChartTwoOverlaySetViewController::~ChartTwoOverlaySetViewController() { EventManager::get()->removeAllEventsFromListener(this); } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void ChartTwoOverlaySetViewController::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiEvent = dynamic_cast(event); CaretAssert(uiEvent); if (uiEvent->isUpdateForWindow(m_browserWindowIndex)) { if (uiEvent->isToolBoxUpdate()) { this->updateViewController(); uiEvent->setEventProcessed(); } } } } /** * Update this overlay set view controller using the given overlay set. */ void ChartTwoOverlaySetViewController::updateViewController() { ChartTwoOverlaySet* chartOverlaySet = getChartTwoOverlaySet(); if (chartOverlaySet == NULL) { return; } const int32_t numberOfOverlays = static_cast(m_chartOverlayViewControllers.size()); const int32_t numberOfDisplayedOverlays = chartOverlaySet->getNumberOfDisplayedOverlays(); for (int32_t i = 0; i < numberOfOverlays; i++) { ChartTwoOverlay* chartOverlay = NULL; if (chartOverlaySet != NULL) { chartOverlay = chartOverlaySet->getOverlay(i); } m_chartOverlayViewControllers[i]->updateViewController(chartOverlay); bool displayOverlay = (chartOverlay != NULL); if (i >= numberOfDisplayedOverlays) { displayOverlay = false; } CaretAssertVectorIndex(m_chartOverlayGridLayoutGroups, i); m_chartOverlayGridLayoutGroups[i]->setVisible(displayOverlay); } // const ChartTwoOverlay* primaryOverlay = chartOverlaySet->getPrimaryOverlay(); // if (primaryOverlay != NULL) { // AString mapRowOrColumnName = "Map"; // switch (primaryOverlay->getChartTwoDataType()) { // case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: // break; // case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: // break; // case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: // break; // case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: // mapRowOrColumnName = "Row"; // break; // } // // if (m_mapRowOrColumnIndexLabel != NULL) { // m_mapRowOrColumnIndexLabel->setText(mapRowOrColumnName+ " Index"); // } // if (m_mapRowOrColumnNameLabel != NULL) { // m_mapRowOrColumnNameLabel->setText(mapRowOrColumnName + " Name"); // } // } } /** * @return The overlay set in this view controller. */ ChartTwoOverlaySet* ChartTwoOverlaySetViewController::getChartTwoOverlaySet() { ChartTwoOverlaySet* chartOverlaySet = NULL; BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent != NULL) { chartOverlaySet = browserTabContent->getChartTwoOverlaySet(); } return chartOverlaySet; } /** * Add an overlay above the overlay with the given index. * @param overlayIndex * Index of overlay that will have an overlay added above it. */ void ChartTwoOverlaySetViewController::processAddOverlayAbove(const int32_t overlayIndex) { ChartTwoOverlaySet* chartOverlaySet = getChartTwoOverlaySet(); if (chartOverlaySet != NULL) { chartOverlaySet->insertOverlayAbove(overlayIndex); this->updateColoringAndGraphics(); } } /** * Add an overlay below the overlay with the given index. * @param overlayIndex * Index of overlay that will have an overlay added below it. */ void ChartTwoOverlaySetViewController::processAddOverlayBelow(const int32_t overlayIndex) { ChartTwoOverlaySet* chartOverlaySet = getChartTwoOverlaySet(); if (chartOverlaySet != NULL) { chartOverlaySet->insertOverlayBelow(overlayIndex); this->updateColoringAndGraphics(); } } /** * Remove an overlay above the overlay with the given index. * @param overlayIndex * Index of overlay that will be removed */ void ChartTwoOverlaySetViewController::processRemoveOverlay(const int32_t overlayIndex) { ChartTwoOverlaySet* chartOverlaySet = getChartTwoOverlaySet(); if (chartOverlaySet != NULL) { chartOverlaySet->removeDisplayedOverlay(overlayIndex); this->updateColoringAndGraphics(); } } /** * Remove an overlay above the overlay with the given index. * @param overlayIndex * Index of overlay that will be removed */ void ChartTwoOverlaySetViewController::processMoveOverlayDown(const int32_t overlayIndex) { ChartTwoOverlaySet* chartOverlaySet = getChartTwoOverlaySet(); if (chartOverlaySet != NULL) { chartOverlaySet->moveDisplayedOverlayDown(overlayIndex); this->updateColoringAndGraphics(); } } /** * Remove an overlay above the overlay with the given index. * @param overlayIndex * Index of overlay that will be removed */ void ChartTwoOverlaySetViewController::processMoveOverlayUp(const int32_t overlayIndex) { ChartTwoOverlaySet* chartOverlaySet = getChartTwoOverlaySet(); if (chartOverlaySet != NULL) { chartOverlaySet->moveDisplayedOverlayUp(overlayIndex); this->updateColoringAndGraphics(); } } /** * Update surface coloring and graphics after overlay changes. */ void ChartTwoOverlaySetViewController::updateColoringAndGraphics() { this->updateViewController(); EventGraphicsUpdateOneWindow graphicsUpdate(m_browserWindowIndex); EventManager::get()->sendEvent(graphicsUpdate.getPointer()); } connectome-workbench-1.4.2/src/GuiQt/ChartTwoOverlaySetViewController.h000066400000000000000000000060621360521144700263000ustar00rootroot00000000000000#ifndef __CHART_TWO_OVERLAY_SET_VIEW_CONTROLLER_H__ #define __CHART_TWO_OVERLAY_SET_VIEW_CONTROLLER_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "EventListenerInterface.h" class QLabel; class QScrollArea; namespace caret { class ChartTwoOverlaySet; class ChartTwoOverlayViewController; class WuQGridLayoutGroup; class ChartTwoOverlaySetViewController : public QWidget, public EventListenerInterface { Q_OBJECT public: ChartTwoOverlaySetViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent = 0); virtual ~ChartTwoOverlaySetViewController(); // ADD_NEW_METHODS_HERE virtual void receiveEvent(Event* event); private slots: void processAddOverlayAbove(const int32_t overlayIndex); void processAddOverlayBelow(const int32_t overlayIndex); void processRemoveOverlay(const int32_t overlayIndex); void processMoveOverlayDown(const int32_t overlayIndex); void processMoveOverlayUp(const int32_t overlayIndex); private: ChartTwoOverlaySetViewController(const ChartTwoOverlaySetViewController&); ChartTwoOverlaySetViewController& operator=(const ChartTwoOverlaySetViewController&); ChartTwoOverlaySet* getChartTwoOverlaySet(); void updateViewController(); void updateColoringAndGraphics(); const int32_t m_browserWindowIndex; std::vector m_chartOverlayViewControllers; std::vector m_chartOverlayGridLayoutGroups; QScrollArea* m_scrollArea; QLabel* m_mapRowOrColumnIndexLabel = NULL; QLabel* m_mapRowOrColumnNameLabel = NULL; // ADD_NEW_MEMBERS_HERE }; #ifdef __CHART_TWO_OVERLAY_SET_VIEW_CONTROLLER_DECLARE__ // #endif // __CHART_OVERLAY_SET_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__CHART_TWO_OVERLAY_SET_VIEW_CONTROLLER_H__ connectome-workbench-1.4.2/src/GuiQt/ChartTwoOverlayViewController.cxx000066400000000000000000001624711360521144700262060ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CHART_TWO_OVERLAY_VIEW_CONTROLLER_DECLARE__ #include "ChartTwoOverlayViewController.h" #undef __CHART_TWO_OVERLAY_VIEW_CONTROLLER_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include "CaretAssert.h" using namespace caret; #include "AnnotationColorBar.h" #include "Brain.h" #include "CaretMappableDataFile.h" #include "ChartTwoOverlay.h" #include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileHistogramChart.h" #include "ChartableTwoFileLineSeriesChart.h" #include "ChartableTwoFileMatrixChart.h" #include "EventDataFileReload.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventManager.h" #include "EventMapYokingSelectMap.h" #include "EventOverlaySettingsEditorDialogRequest.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUserInterfaceUpdate.h" #include "FileInformation.h" #include "FilePathNamePrefixCompactor.h" #include "GuiManager.h" #include "MapYokingGroupComboBox.h" #include "UsernamePasswordWidget.h" #include "WuQFactory.h" #include "WuQMacroManager.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" /** * \class caret::ChartTwoOverlayViewController * \brief View controller for a chart overlay * \ingroup GuiQt */ /** * Constructor. * * @param orientation * Orientation of view controller. * @param browserWindowIndex * Index of browser window in which this view controller resides. * @param chartOverlayIndex * Index of this overlay view controller. * @param parentObjectName * Name of parent object for macros * @param parent * The parent widget. */ ChartTwoOverlayViewController::ChartTwoOverlayViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, const int32_t chartOverlayIndex, const QString& parentObjectName, QObject* parent) : QObject(parent), m_browserWindowIndex(browserWindowIndex), m_chartOverlayIndex(chartOverlayIndex), m_chartOverlay(NULL) { int minComboBoxWidth = 200; int maxComboBoxWidth = 100000; //400; if (orientation == Qt::Horizontal) { minComboBoxWidth = 50; maxComboBoxWidth = 100000; } const QComboBox::SizeAdjustPolicy comboSizePolicy = QComboBox::AdjustToContentsOnFirstShow; //QComboBox::AdjustToContents; WuQMacroManager* macroManager = WuQMacroManager::instance(); CaretAssert(macroManager); QString objectNamePrefix = QString(parentObjectName + ":ChartOverlay%1" + ":").arg((int)(chartOverlayIndex + 1), 2, 10, QLatin1Char('0')); QString descriptivePrefix = QString("chart overlay " + QString::number(chartOverlayIndex + 1)); /* * Enabled Check Box */ const QString enabledCheckboxText = ((orientation == Qt::Horizontal) ? " " : "On"); m_enabledCheckBox = new QCheckBox(enabledCheckboxText); m_enabledCheckBox->setObjectName(objectNamePrefix + "OnOff"); QObject::connect(m_enabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(enabledCheckBoxClicked(bool))); m_enabledCheckBox->setToolTip("Display line charts from the selected file"); macroManager->addMacroSupportToObject(m_enabledCheckBox, "Enable line chart display for " + descriptivePrefix); /* * Line Series Enabled Check Box */ const QString loadingCheckboxText = ((orientation == Qt::Horizontal) ? " " : "Load"); m_lineSeriesLoadingEnabledCheckBox = new QCheckBox(loadingCheckboxText); QObject::connect(m_lineSeriesLoadingEnabledCheckBox, &QCheckBox::clicked, this, &ChartTwoOverlayViewController::lineSeriesLoadingEnabledCheckBoxClicked); m_lineSeriesLoadingEnabledCheckBox->setToolTip("Enable loading of line charts for the selected file"); m_lineSeriesLoadingEnabledCheckBox->setObjectName(objectNamePrefix + "EnableLoading"); macroManager->addMacroSupportToObject(m_lineSeriesLoadingEnabledCheckBox, "Enable line chart loading for " + descriptivePrefix); /* * Settings Tool Button */ QIcon settingsIcon; const bool settingsIconValid = WuQtUtilities::loadIcon(":/LayersPanel/wrench.png", settingsIcon); m_settingsToolButton = new QToolButton(); m_settingsAction = WuQtUtilities::createAction("S", "Edit settings for this chart", m_settingsToolButton, this, SLOT(settingsActionTriggered())); if (settingsIconValid) { m_settingsAction->setIcon(settingsIcon); } m_settingsAction->setObjectName(objectNamePrefix + "ShowSettingsDialog"); macroManager->addMacroSupportToObject(m_settingsAction, "Show settings dialog for " + descriptivePrefix); m_settingsToolButton->setDefaultAction(m_settingsAction); /* * ColorBar Tool Button */ QIcon colorBarIcon; const bool colorBarIconValid = WuQtUtilities::loadIcon(":/LayersPanel/colorbar.png", colorBarIcon); m_colorBarToolButton = new QToolButton(); m_colorBarAction = WuQtUtilities::createAction("CB", "Display color bar for this overlay", m_colorBarToolButton, this, SLOT(colorBarActionTriggered(bool))); m_colorBarAction->setCheckable(true); if (colorBarIconValid) { m_colorBarAction->setIcon(colorBarIcon); } m_colorBarAction->setObjectName(objectNamePrefix + "ShowColorBar"); macroManager->addMacroSupportToObject(m_colorBarAction, "Enable color bar for " + descriptivePrefix); m_colorBarToolButton->setDefaultAction(m_colorBarAction); /* * Construction Tool Button * Note: macro support is on each action in menu in 'createConstructionMenu' */ QIcon constructionIcon; const bool constructionIconValid = WuQtUtilities::loadIcon(":/LayersPanel/construction.png", constructionIcon); m_constructionAction = WuQtUtilities::createAction("C", "Add/Move/Remove Layers", this); if (constructionIconValid) { m_constructionAction->setIcon(constructionIcon); } m_constructionToolButton = new QToolButton(); QMenu* constructionMenu = createConstructionMenu(m_constructionToolButton, (objectNamePrefix + "ConstructionMenu:"), descriptivePrefix); m_constructionAction->setMenu(constructionMenu); m_constructionToolButton->setDefaultAction(m_constructionAction); m_constructionToolButton->setPopupMode(QToolButton::InstantPopup); /* * Matrix triangular view mode button * Note: macro support is on each action in menu in createMatrixTriangularViewModeMenu */ m_matrixTriangularViewModeToolButton = new QToolButton(); m_matrixTriangularViewModeAction = WuQtUtilities::createAction("M", "Select a triangular view of the matrix", m_matrixTriangularViewModeToolButton); QMenu* matrixTriangularViewModeMenu = createMatrixTriangularViewModeMenu(m_matrixTriangularViewModeToolButton, (objectNamePrefix + "TriangularViewMenu:"), descriptivePrefix); m_matrixTriangularViewModeAction->setMenu(matrixTriangularViewModeMenu); m_matrixTriangularViewModeToolButton->setDefaultAction(m_matrixTriangularViewModeAction); m_matrixTriangularViewModeToolButton->setPopupMode(QToolButton::InstantPopup); /* * Axis location button * Note: macro support is on each action in menu in createMatrixTriangularViewModeMenu */ m_axisLocationToolButton = new QToolButton(); m_axisLocationAction = WuQtUtilities::createAction("A", "Select location of vertical axis for the selected file", m_axisLocationToolButton); QMenu* axisLocationMenu = createAxisLocationMenu(m_axisLocationToolButton, (objectNamePrefix + "VerticalAxisLocationMenu:"), descriptivePrefix); m_axisLocationAction->setMenu(axisLocationMenu); m_axisLocationToolButton->setDefaultAction(m_axisLocationAction); m_axisLocationToolButton->setPopupMode(QToolButton::InstantPopup); /* * Map file Selection Check Box */ m_mapFileComboBox = WuQFactory::newComboBox(); m_mapFileComboBox->setMinimumWidth(minComboBoxWidth); m_mapFileComboBox->setMaximumWidth(maxComboBoxWidth); QObject::connect(m_mapFileComboBox, SIGNAL(activated(int)), this, SLOT(fileComboBoxSelected(int))); m_mapFileComboBox->setToolTip("Selects file for this overlay"); m_mapFileComboBox->setSizeAdjustPolicy(comboSizePolicy); m_mapFileComboBox->setObjectName(objectNamePrefix + "FileSelection"); macroManager->addMacroSupportToObject(m_mapFileComboBox, "Select file in " + descriptivePrefix); /* * Yoking Group */ const AString yokeToolTip = ("Select a yoking group.\n" "\n" "When files with more than one map are yoked,\n" "the seleted maps are synchronized by map index.\n" "\n" "If the SAME FILE is in yoked in multiple overlays,\n" "the overlay enabled statuses are synchronized.\n"); m_mapRowOrColumnYokingGroupComboBox = new MapYokingGroupComboBox(this); m_mapRowOrColumnYokingGroupComboBox->getWidget()->setStatusTip("Synchronize enabled status and map indices)"); m_mapRowOrColumnYokingGroupComboBox->getWidget()->setToolTip("Yoke to Overlay Mapped Files"); QObject::connect(m_mapRowOrColumnYokingGroupComboBox, SIGNAL(itemActivated()), this, SLOT(yokingGroupActivated())); /* * All maps check box */ m_allMapsCheckBox = new QCheckBox("All Maps"); m_allMapsCheckBox->setToolTip("Show histogram of all maps"); if (orientation == Qt::Horizontal) { m_allMapsCheckBox->setText(" "); } QObject::connect(m_allMapsCheckBox, SIGNAL(clicked(bool)), this, SLOT(allMapsCheckBoxClicked(bool))); m_allMapsCheckBox->setObjectName(objectNamePrefix + "AllMaps"); macroManager->addMacroSupportToObject(m_allMapsCheckBox, "Enable all maps in " + descriptivePrefix); /* * Map/Row/Column Index Spin Box */ m_mapRowOrColumnIndexSpinBox = WuQFactory::newSpinBox(); QObject::connect(m_mapRowOrColumnIndexSpinBox, SIGNAL(valueChanged(int)), this, SLOT(mapRowOrColumnIndexSpinBoxValueChanged(int))); m_mapRowOrColumnIndexSpinBox->setToolTip("Select map/row/column by its index"); m_mapRowOrColumnIndexSpinBox->setRange(1, 9999); // fix size for 4 digits m_mapRowOrColumnIndexSpinBox->setFixedSize(m_mapRowOrColumnIndexSpinBox->sizeHint()); m_mapRowOrColumnIndexSpinBox->setRange(1, 1); m_mapRowOrColumnIndexSpinBox->setValue(1); m_mapRowOrColumnIndexSpinBox->setObjectName(objectNamePrefix + "MapIndex"); macroManager->addMacroSupportToObject(m_mapRowOrColumnIndexSpinBox, "Select map by index in " + descriptivePrefix); /* * Map/Row/Column Name Combo Box */ m_mapRowOrColumnNameComboBox = WuQFactory::newComboBox(); m_mapRowOrColumnNameComboBox->setMinimumWidth(minComboBoxWidth); m_mapRowOrColumnNameComboBox->setMaximumWidth(maxComboBoxWidth); QObject::connect(m_mapRowOrColumnNameComboBox, SIGNAL(activated(int)), this, SLOT(mapRowOrColumnNameComboBoxSelected(int))); m_mapRowOrColumnNameComboBox->setToolTip("Select map/row/column by its name"); m_mapRowOrColumnNameComboBox->setSizeAdjustPolicy(comboSizePolicy); m_mapRowOrColumnNameComboBox->setObjectName(objectNamePrefix + "MapSelection"); macroManager->addMacroSupportToObject(m_mapRowOrColumnNameComboBox, "Select map name in " + descriptivePrefix); } /** * Destructor. */ ChartTwoOverlayViewController::~ChartTwoOverlayViewController() { } /* * If this overlay ins an overlay settings editor, update its content */ void ChartTwoOverlayViewController::updateOverlaySettingsEditor() { if (m_chartOverlay == NULL) { return; } CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; m_chartOverlay->getSelectionData(mapFile, selectedIndexType, selectedIndex); if ((mapFile != NULL) && (selectedIndex >= 0)) { EventOverlaySettingsEditorDialogRequest pcme(EventOverlaySettingsEditorDialogRequest::MODE_OVERLAY_MAP_CHANGED, m_browserWindowIndex, m_chartOverlay, mapFile, selectedIndexType, selectedIndex); EventManager::get()->sendEvent(pcme.getPointer()); } } /** * Called when a selection is made from the file combo box. * @parm indx * Index of selection. */ void ChartTwoOverlayViewController::fileComboBoxSelected(int indx) { if (m_chartOverlay == NULL) { return; } void* pointer = m_mapFileComboBox->itemData(indx).value(); CaretMappableDataFile* file = (CaretMappableDataFile*)pointer; m_chartOverlay->setSelectionData(file, -1); updateViewController(m_chartOverlay); m_mapRowOrColumnYokingGroupComboBox->validateYokingChange(m_chartOverlay); updateUserInterfaceAndGraphicsWindow(); updateOverlaySettingsEditor(); } /** * Called when a selection is made from the map index spin box. * @parm indxIn * Index of selection. */ void ChartTwoOverlayViewController::mapRowOrColumnIndexSpinBoxValueChanged(int indxIn) { if (m_chartOverlay == NULL) { //TSC: not sure how to put the displayed integer back to 0 where it starts when opening without data files return; } const bool focusFlag = m_mapRowOrColumnIndexSpinBox->hasFocus(); /* * Get the file that is selected from the file combo box */ const int32_t fileIndex = m_mapFileComboBox->currentIndex(); void* pointer = m_mapFileComboBox->itemData(fileIndex).value(); CaretMappableDataFile* file = (CaretMappableDataFile*)pointer; /* * Spin box may range [0, N-1] or [1, N] but in source code * indices are always [0, N-1] */ const int32_t indx = indxIn - m_mapRowOrColumnIndexSpinBox->minimum(); m_chartOverlay->setSelectionData(file, indx); const MapYokingGroupEnum::Enum mapYoking = m_chartOverlay->getMapYokingGroup(); if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { EventMapYokingSelectMap selectMapEvent(mapYoking, file, NULL, indx, m_chartOverlay->isEnabled()); EventManager::get()->sendEvent(selectMapEvent.getPointer()); } /* * Need to update map name combo box. */ m_mapRowOrColumnNameComboBox->blockSignals(true); if ((indx >= 0) && (indx < m_mapRowOrColumnNameComboBox->count())) { m_mapRowOrColumnNameComboBox->setCurrentIndex(indx); } m_mapRowOrColumnNameComboBox->blockSignals(false); this->updateUserInterfaceAndGraphicsWindow(); updateOverlaySettingsEditor(); /* * User interface update may cause loss of focus so restore it */ if (focusFlag) { m_mapRowOrColumnIndexSpinBox->setFocus(); } } /** * Called when a selection is made from the map name combo box. * @parm indx * Index of selection. */ void ChartTwoOverlayViewController::mapRowOrColumnNameComboBoxSelected(int indx) { if (m_chartOverlay == NULL) { return; } /* * Get the file that is selected from the file combo box */ const int32_t fileIndex = m_mapFileComboBox->currentIndex(); void* pointer = m_mapFileComboBox->itemData(fileIndex).value(); CaretMappableDataFile* file = (CaretMappableDataFile*)pointer; m_chartOverlay->setSelectionData(file, indx); const MapYokingGroupEnum::Enum mapYoking = m_chartOverlay->getMapYokingGroup(); if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { EventMapYokingSelectMap selectMapEvent(mapYoking, file, NULL, indx, m_chartOverlay->isEnabled()); EventManager::get()->sendEvent(selectMapEvent.getPointer()); } /* * Need to update map index spin box. * Spin box may range [0, N-1] or [1, N] but in source code * indices are always [0, N-1] */ const int spinBoxIndex = indx + m_mapRowOrColumnIndexSpinBox->minimum(); m_mapRowOrColumnIndexSpinBox->blockSignals(true); m_mapRowOrColumnIndexSpinBox->setValue(spinBoxIndex); m_mapRowOrColumnIndexSpinBox->blockSignals(false); this->updateUserInterfaceAndGraphicsWindow(); updateOverlaySettingsEditor(); /* * User interface update may cause loss of focus so restore it */ m_mapRowOrColumnNameComboBox->setFocus(); } /** * Called when enabled checkbox state is changed * @parm checked * Checked status */ void ChartTwoOverlayViewController::enabledCheckBoxClicked(bool checked) { if (m_chartOverlay == NULL) { return; } m_chartOverlay->setEnabled(checked); const MapYokingGroupEnum::Enum mapYoking = m_chartOverlay->getMapYokingGroup(); if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; m_chartOverlay->getSelectionData(mapFile, selectedIndexType, selectedIndex); if (selectedIndexType == ChartTwoOverlay::SelectedIndexType::MAP) { EventMapYokingSelectMap selectMapEvent(mapYoking, mapFile, NULL, selectedIndex, m_chartOverlay->isEnabled()); EventManager::get()->sendEvent(selectMapEvent.getPointer()); } } this->updateUserInterfaceAndGraphicsWindow(); } /** * Called when line-series loading enabled checkbox status is changed * @parm checked * Checked status */ void ChartTwoOverlayViewController::lineSeriesLoadingEnabledCheckBoxClicked(bool checked) { if (m_chartOverlay == NULL) { return; } m_chartOverlay->setLineSeriesLoadingEnabled(checked); this->updateUserInterfaceAndGraphicsWindow(); } /** * Called when colorbar toolbutton is toggled. * @param status * New status. */ void ChartTwoOverlayViewController::colorBarActionTriggered(bool status) { if (m_chartOverlay == NULL) { return; } m_chartOverlay->getColorBar()->setDisplayed(status); this->updateGraphicsWindow(); } /** * Called when colorbar toolbutton is toggled. * @param status * New status. */ void ChartTwoOverlayViewController::allMapsCheckBoxClicked(bool status) { if (m_chartOverlay == NULL) { return; } CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; m_chartOverlay->getSelectionData(mapFile, selectedIndexType, selectedIndex); bool doAllMapsFlag = true; if (mapFile != NULL) { if (status) { doAllMapsFlag = WuQMessageBox::warningLargeFileSizeOkCancel(m_allMapsCheckBox, mapFile); } if (doAllMapsFlag) { mapFile->invalidateHistogramChartColoring(); } } if (doAllMapsFlag) { m_chartOverlay->setAllMapsSelected(status); } else { QSignalBlocker blocker(m_allMapsCheckBox); m_allMapsCheckBox->setChecked(false); } this->updateGraphicsWindow(); } /** * Validate yoking when there are changes made to the overlay. */ void ChartTwoOverlayViewController::validateYokingSelection() { m_mapRowOrColumnYokingGroupComboBox->validateYokingChange(m_chartOverlay); updateViewController(m_chartOverlay); updateUserInterfaceAndGraphicsWindow(); } /** * Called when the yoking group is changed. */ void ChartTwoOverlayViewController::yokingGroupActivated() { MapYokingGroupEnum::Enum yokingGroup = m_mapRowOrColumnYokingGroupComboBox->getMapYokingGroup(); /* * Has yoking group changed? * TSC: overlay can be null when opened without loaded files */ if (m_chartOverlay != NULL && yokingGroup != m_chartOverlay->getMapYokingGroup()) { validateYokingSelection(); } } /** * Called when the settings action is selected. */ void ChartTwoOverlayViewController::settingsActionTriggered() { if (m_chartOverlay == NULL) { return; } CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; m_chartOverlay->getSelectionData(mapFile, selectedIndexType, selectedIndex); if (mapFile != NULL) { EventOverlaySettingsEditorDialogRequest pcme(EventOverlaySettingsEditorDialogRequest::MODE_SHOW_EDITOR, m_browserWindowIndex, m_chartOverlay, mapFile, selectedIndexType, selectedIndex); EventManager::get()->sendEvent(pcme.getPointer()); } } /** * Update this view controller using the given overlay. * @param overlay * Overlay that is used in this view controller. */ void ChartTwoOverlayViewController::updateViewController(ChartTwoOverlay* chartOverlay) { m_chartOverlay = chartOverlay; /* * Get the selection information for the overlay. */ std::vector dataFiles; CaretMappableDataFile* selectedFile = NULL; std::vector selectedFileMapNames; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; if (m_chartOverlay != NULL) { m_chartOverlay->getSelectionData(dataFiles, selectedFile, selectedFileMapNames, selectedIndexType, selectedIndex); } /* * Setup names of file for display in combo box */ std::vector displayNames; FilePathNamePrefixCompactor::removeMatchingPathPrefixFromCaretDataFiles(dataFiles, displayNames); CaretAssert(dataFiles.size() == displayNames.size()); /* * Update tooltips with full path to file and name of map * as names may be too long to fit into combo boxes */ AString fileComboBoxToolTip("Select file for this overlay"); AString nameComboBoxToolTip("Select map by its name"); if (selectedFile != NULL) { FileInformation fileInfo(selectedFile->getFileName()); fileComboBoxToolTip.append(":\n" + fileInfo.getFileName() + "\n" + fileInfo.getPathName() + "\n\n" + "Copy File Name/Path to Clipboard with Construction Menu"); nameComboBoxToolTip.append(":\n" + m_mapRowOrColumnNameComboBox->currentText()); } m_mapFileComboBox->setToolTip(fileComboBoxToolTip); m_mapRowOrColumnNameComboBox->setToolTip(nameComboBoxToolTip); /* * Load the file selection combo box. */ m_mapFileComboBox->clear(); int32_t selectedFileIndex = -1; const int32_t numFiles = static_cast(dataFiles.size()); for (int32_t i = 0; i < numFiles; i++) { CaretMappableDataFile* dataFile = dataFiles[i]; AString dataTypeName = DataFileTypeEnum::toOverlayTypeName(dataFile->getDataFileType()); CaretAssertVectorIndex(displayNames, i); m_mapFileComboBox->addItem(displayNames[i], qVariantFromValue((void*)dataFile)); if (dataFile == selectedFile) { selectedFileIndex = i; } } if (selectedFileIndex >= 0) { m_mapFileComboBox->setCurrentIndex(selectedFileIndex); } /* * Load the map name selection combo box and map index spin box */ m_mapRowOrColumnNameComboBox->setEnabled(false); m_mapRowOrColumnNameComboBox->blockSignals(true); m_mapRowOrColumnNameComboBox->clear(); m_mapRowOrColumnIndexSpinBox->setEnabled(false); m_mapRowOrColumnIndexSpinBox->blockSignals(true); m_mapRowOrColumnIndexSpinBox->setRange(1, 1); m_mapRowOrColumnIndexSpinBox->setValue(1); const int32_t numberOfMaps = static_cast(selectedFileMapNames.size()); if (numberOfMaps > 0) { m_mapRowOrColumnNameComboBox->setEnabled(true); m_mapRowOrColumnIndexSpinBox->setEnabled(true); for (int32_t i = 0; i < numberOfMaps; i++) { CaretAssertVectorIndex(selectedFileMapNames, i); m_mapRowOrColumnNameComboBox->addItem(selectedFileMapNames[i]); } m_mapRowOrColumnNameComboBox->setCurrentIndex(selectedIndex); /* * Spin box ranges [0, N-1] or [1, N] depending upon data */ int32_t mapIndexMinimumValue = 1; int32_t mapIndexMaximumValue = numberOfMaps; switch (m_chartOverlay->getChartTwoDataType()) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; } m_mapRowOrColumnIndexSpinBox->setRange(mapIndexMinimumValue, mapIndexMaximumValue); const int spinBoxIndex = selectedIndex + m_mapRowOrColumnIndexSpinBox->minimum(); m_mapRowOrColumnIndexSpinBox->setValue(spinBoxIndex); } m_mapRowOrColumnNameComboBox->blockSignals(false); m_mapRowOrColumnIndexSpinBox->blockSignals(false); const bool validOverlayAndFileFlag = ((m_chartOverlay != NULL) && (selectedFile != NULL)); /* * Update enabled checkbox */ m_enabledCheckBox->setEnabled(false); m_enabledCheckBox->setChecked(false); if (validOverlayAndFileFlag) { m_enabledCheckBox->setEnabled(true); m_enabledCheckBox->setChecked(m_chartOverlay->isEnabled()); } /* * Update lines series loading checkbox */ m_lineSeriesLoadingEnabledCheckBox->setEnabled(false); m_lineSeriesLoadingEnabledCheckBox->setChecked(false); if ((validOverlayAndFileFlag) && (m_chartOverlay->getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES)) { m_lineSeriesLoadingEnabledCheckBox->setEnabled(true); m_lineSeriesLoadingEnabledCheckBox->setChecked(m_chartOverlay->isLineSeriesLoadingEnabled()); } /* * Update yoking */ m_mapRowOrColumnYokingGroupComboBox->getWidget()->setEnabled(false); m_mapRowOrColumnYokingGroupComboBox->setMapYokingGroup(MapYokingGroupEnum::MAP_YOKING_GROUP_OFF); if (validOverlayAndFileFlag) { if (m_chartOverlay->isMapYokingSupported()) { m_mapRowOrColumnYokingGroupComboBox->getWidget()->setEnabled(true); m_mapRowOrColumnYokingGroupComboBox->setMapYokingGroup(m_chartOverlay->getMapYokingGroup()); } } /* * Update all maps */ m_allMapsCheckBox->setEnabled(false); m_allMapsCheckBox->setChecked(false); if (validOverlayAndFileFlag) { m_allMapsCheckBox->setEnabled(m_chartOverlay->isAllMapsSupported()); if (m_chartOverlay->isAllMapsSupported()) { m_allMapsCheckBox->setChecked(m_chartOverlay->isAllMapsSelected()); } } /* * Update settings (wrench) button */ bool enableSettingsActionFlag = validOverlayAndFileFlag; switch (m_chartOverlay->getChartTwoDataType()) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: enableSettingsActionFlag = false; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: break; } m_settingsAction->setEnabled(enableSettingsActionFlag); /* * Update color bar button */ m_colorBarAction->blockSignals(true); m_colorBarAction->setEnabled(false); m_colorBarAction->setChecked(false); if (validOverlayAndFileFlag) { if (selectedFile->isMappedWithPalette()) { m_colorBarAction->setEnabled(true); m_colorBarAction->setChecked(m_chartOverlay->getColorBar()->isDisplayed()); } } m_colorBarAction->blockSignals(false); /* * Update construction button */ m_constructionAction->setEnabled(true); /* * Update matrix triangular view mode */ m_matrixTriangularViewModeAction->setEnabled(false); if (validOverlayAndFileFlag) { const ChartTwoMatrixTriangularViewingModeEnum::Enum viewMode = m_chartOverlay->getMatrixTriangularViewingMode(); for (auto& mvmd : m_matrixViewMenuData) { if (std::get<0>(mvmd) == viewMode) { std::get<1>(mvmd)->setChecked(true); updateMatrixTriangularViewModeAction(viewMode); break; } } if (m_chartOverlay->isMatrixTriangularViewingModeSupported()) { m_matrixTriangularViewModeAction->setEnabled(true); } } /* * Update vertical axis location */ m_axisLocationAction->setEnabled(false); if (validOverlayAndFileFlag) { if (m_chartOverlay->isCartesianVerticalAxisLocationSupported()) { m_axisLocationAction->setEnabled(true); const ChartAxisLocationEnum::Enum axisLocation = m_chartOverlay->getCartesianVerticalAxisLocation(); for (auto& almd : m_axisLocationMenuData) { if (std::get<0>(almd) == axisLocation) { updateAxisLocationAction(axisLocation); break; } } } } } /** * Update the matrix triangular view mode button. * * @param matrixViewMode * Matrix triangular view mode. */ void ChartTwoOverlayViewController::updateMatrixTriangularViewModeAction(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode) { CaretAssert(m_matrixTriangularViewModeAction); m_matrixTriangularViewModeAction->blockSignals(true); for (auto& mvmd : m_matrixViewMenuData) { if (std::get<0>(mvmd) == matrixViewMode) { QPixmap pixmap = std::get<2>(mvmd); if ( ! pixmap.isNull()) { m_matrixTriangularViewModeAction->setIcon(pixmap); m_matrixTriangularViewModeAction->setText(""); } else { m_matrixTriangularViewModeAction->setText("M"); } break; } } m_matrixTriangularViewModeAction->blockSignals(false); } /** * Update the axis location button. * * @param axisLocation * Axis location. */ void ChartTwoOverlayViewController::updateAxisLocationAction(const ChartAxisLocationEnum::Enum axisLocation) { CaretAssert(m_axisLocationAction); m_axisLocationAction->blockSignals(true); for (auto& almd : m_axisLocationMenuData) { if (std::get<0>(almd) == axisLocation) { QPixmap pixmap = std::get<2>(almd); if ( ! pixmap.isNull()) { m_axisLocationAction->setIcon(pixmap); m_axisLocationAction->setText(""); } else { m_axisLocationAction->setText("A"); } break; } } m_axisLocationAction->blockSignals(false); } /** * Update graphics and GUI after selections made */ void ChartTwoOverlayViewController::updateUserInterfaceAndGraphicsWindow() { updateUserInterface(); updateGraphicsWindow(); } /** * Update graphics and GUI after selections made */ void ChartTwoOverlayViewController::updateUserInterface() { EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** * Update graphics after selections made */ void ChartTwoOverlayViewController::updateGraphicsWindow() { if (m_chartOverlay->getMapYokingGroup() != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } else { EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(m_browserWindowIndex).getPointer()); } } /** * Create the matrix triangular view mode menu. * @param parent * Parent widget. * @param parentObjectName * Name of parent object for macros * @param descriptivePrefix * Descriptive prefix for macros */ QMenu* ChartTwoOverlayViewController::createMatrixTriangularViewModeMenu(QWidget* parent, const QString& parentObjectName, const QString& descriptivePrefix) { std::vector allViewModes; ChartTwoMatrixTriangularViewingModeEnum::getAllEnums(allViewModes); QMenu* menu = new QMenu(parent); QObject::connect(menu, &QMenu::triggered, this, &ChartTwoOverlayViewController::menuMatrixTriangularViewModeTriggered); QActionGroup* actionGroup = new QActionGroup(this); actionGroup->setExclusive(true); for (auto viewMode: allViewModes) { QAction* action = menu->addAction(ChartTwoMatrixTriangularViewingModeEnum::toGuiName(viewMode)); action->setCheckable(true); action->setData((int)ChartTwoMatrixTriangularViewingModeEnum::toIntegerCode(viewMode)); QPixmap pixmap = createMatrixTriangularViewModePixmap(menu, viewMode); action->setIcon(pixmap); actionGroup->addAction(action); QString objName = (parentObjectName + ChartTwoMatrixTriangularViewingModeEnum::toGuiName(viewMode)); objName = objName.replace(" ", ""); action->setObjectName(objName); WuQMacroManager::instance()->addMacroSupportToObject(action, "Set triangular view in " + descriptivePrefix); m_matrixViewMenuData.push_back(std::make_tuple(viewMode, action, pixmap)); } return menu; } /** * Called when an item is selected on matrix triangular view mode menu. * * @action * Action of menu item selected. */ void ChartTwoOverlayViewController::menuMatrixTriangularViewModeTriggered(QAction* action) { const QVariant itemData = action->data(); CaretAssert(itemData.isValid()); bool valid = false; ChartTwoMatrixTriangularViewingModeEnum::Enum viewMode = ChartTwoMatrixTriangularViewingModeEnum::fromIntegerCode(itemData.toInt(), &valid); if (valid) { m_chartOverlay->setMatrixTriangularViewingMode(viewMode); updateMatrixTriangularViewModeAction(viewMode); CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; m_chartOverlay->getSelectionData(mapFile, selectedIndexType, selectedIndex); if (mapFile != NULL) { mapFile->updateScalarColoringForAllMaps(); } this->updateGraphicsWindow(); } } /** * Create the axis location menu. * @param parent * Parent widget. * @param parentObjectName * Name of parent object for macros */ QMenu* ChartTwoOverlayViewController::createAxisLocationMenu(QWidget* widget, const QString& parentObjectName, const QString& descriptivePrefix) { std::vector axisLocations; axisLocations.push_back(ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT); axisLocations.push_back(ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT); QMenu* menu = new QMenu(widget); QObject::connect(menu, &QMenu::triggered, this, &ChartTwoOverlayViewController::menuAxisLocationTriggered); QActionGroup* actionGroup = new QActionGroup(this); actionGroup->setExclusive(true); for (auto axis: axisLocations) { QAction* action = menu->addAction(ChartAxisLocationEnum::toGuiName(axis)); action->setCheckable(true); action->setData((int)ChartAxisLocationEnum::toIntegerCode(axis)); QPixmap pixmap = createAxisLocationPixmap(menu, axis); action->setIcon(pixmap); actionGroup->addAction(action); QString objName = (parentObjectName + ChartAxisLocationEnum::toGuiName(axis)); objName = objName.replace(" ", ""); action->setObjectName(objName); WuQMacroManager::instance()->addMacroSupportToObject(action, "Select chart axis location for " + descriptivePrefix); m_axisLocationMenuData.push_back(std::make_tuple(axis, action, pixmap)); } return menu; } /** * Called when an item is selected on axis location menu. * * @action * Action of menu item selected. */ void ChartTwoOverlayViewController::menuAxisLocationTriggered(QAction* action) { const QVariant itemData = action->data(); CaretAssert(itemData.isValid()); bool valid = false; ChartAxisLocationEnum::Enum axisLocation = ChartAxisLocationEnum::fromIntegerCode(itemData.toInt(), &valid); if (valid) { m_chartOverlay->setCartesianVerticalAxisLocation(axisLocation); updateAxisLocationAction(axisLocation); this->updateGraphicsWindow(); } } /** * Create the construction menu. * @param parent * Parent widget. * @param parentObjectName * Name of parent object for macros * @param descriptivePrefix * Descriptive name for macros */ QMenu* ChartTwoOverlayViewController::createConstructionMenu(QWidget* parent, const QString& menuActionNamePrefix, const QString& descriptivePrefix) { WuQMacroManager* macroManager = WuQMacroManager::instance(); CaretAssert(macroManager); QMenu* menu = new QMenu(parent); QObject::connect(menu, SIGNAL(aboutToShow()), this, SLOT(menuConstructionAboutToShow())); QAction* addAboveAction = menu->addAction("Add Overlay Above", this, SLOT(menuAddOverlayAboveTriggered())); addAboveAction->setObjectName(menuActionNamePrefix + "AddOverlayAbove"); addAboveAction->setToolTip("Add an overlay above this overlay"); macroManager->addMacroSupportToObject(addAboveAction, "Add overlay above " + descriptivePrefix); QAction* addBelowAction = menu->addAction("Add Overlay Below", this, SLOT(menuAddOverlayBelowTriggered())); addBelowAction->setObjectName(menuActionNamePrefix + "AddOverlayBelow"); addBelowAction->setToolTip("Add an overlay below this overlay"); macroManager->addMacroSupportToObject(addBelowAction, "Add overlay below " + descriptivePrefix); menu->addSeparator(); QAction* moveUpAction = menu->addAction("Move Overlay Up", this, SLOT(menuMoveOverlayUpTriggered())); moveUpAction->setObjectName(menuActionNamePrefix + "MoveOverlayUp"); moveUpAction->setToolTip("Move this overlay up"); macroManager->addMacroSupportToObject(moveUpAction, "Move " + descriptivePrefix + " up"); QAction* moveDownAction = menu->addAction("Move Overlay Down", this, SLOT(menuMoveOverlayDownTriggered())); moveDownAction->setObjectName(menuActionNamePrefix + "MoveOverlayDown"); moveDownAction->setToolTip("Move this overlay down"); macroManager->addMacroSupportToObject(moveDownAction, "Move " + descriptivePrefix + " down"); menu->addSeparator(); QAction* removeAction = menu->addAction("Remove This Overlay", this, SLOT(menuRemoveOverlayTriggered())); removeAction->setObjectName(menuActionNamePrefix + "RemoveOverlay"); removeAction->setToolTip("Remove this overlay"); macroManager->addMacroSupportToObject(removeAction, "Remove " + descriptivePrefix + " overlay"); menu->addSeparator(); m_constructionReloadFileAction = menu->addAction("Reload Selected File", this, SLOT(menuReloadFileTriggered())); m_constructionReloadFileAction->setObjectName(menuActionNamePrefix + "ReloadSelectedFile"); m_constructionReloadFileAction->setToolTip("Reload file in this overlay"); macroManager->addMacroSupportToObject(m_constructionReloadFileAction, "Reload file in " + descriptivePrefix); menu->addSeparator(); QAction* copyPathFileNameAction = menu->addAction("Copy Path and File Name to Clipboard", this, SLOT(menuCopyFileNameToClipBoard())); copyPathFileNameAction->setObjectName(menuActionNamePrefix + "CopyPathAndFileNameToClipboard"); copyPathFileNameAction->setToolTip("Copy path and file name of file in this overlay to clipboard"); macroManager->addMacroSupportToObject(copyPathFileNameAction, "Copy path and name to clipboard from " + descriptivePrefix); QAction* copyMapNameAction = menu->addAction("Copy Map Name to Clipboard", this, SLOT(menuCopyMapNameToClipBoard())); copyMapNameAction->setObjectName(menuActionNamePrefix + "CopyMapNameToClipboard"); copyMapNameAction->setToolTip("Copy name of selected map to the clipboard"); macroManager->addMacroSupportToObject(copyMapNameAction, "Copy map name to clipboard from " + descriptivePrefix); return menu; } /** * Called when construction menu is about to be displayed. */ void ChartTwoOverlayViewController::menuConstructionAboutToShow() { if (m_chartOverlay != NULL) { CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; m_chartOverlay->getSelectionData(mapFile, selectedIndexType, selectedIndex); QString menuText = "Reload Selected File"; if (mapFile != NULL) { if (mapFile->isModified()) { QString suffix = " (MODIFIED)"; if (mapFile->isModifiedPaletteColorMapping()) { if ( ! mapFile->isModifiedExcludingPaletteColorMapping()) { suffix = " (MODIFIED PALETTE)"; } } menuText += suffix; } } m_constructionReloadFileAction->setText(menuText); } } /** * Add an overlay above this overlay. */ void ChartTwoOverlayViewController::menuAddOverlayAboveTriggered() { emit requestAddOverlayAbove(m_chartOverlayIndex); } /** * Add an overlay below this overlay. */ void ChartTwoOverlayViewController::menuAddOverlayBelowTriggered() { emit requestAddOverlayBelow(m_chartOverlayIndex); } /** * Remove this overlay. */ void ChartTwoOverlayViewController::menuRemoveOverlayTriggered() { emit requestRemoveOverlay(m_chartOverlayIndex); } /** * Move this overlay down. */ void ChartTwoOverlayViewController::menuMoveOverlayDownTriggered() { emit requestMoveOverlayDown(m_chartOverlayIndex); } /** * Move this overlay down. */ void ChartTwoOverlayViewController::menuMoveOverlayUpTriggered() { emit requestMoveOverlayUp(m_chartOverlayIndex); } /** * Copy the file name to the clip board. */ void ChartTwoOverlayViewController::menuCopyFileNameToClipBoard() { if (m_chartOverlay != NULL) { CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; m_chartOverlay->getSelectionData(mapFile, selectedIndexType, selectedIndex); if (mapFile != NULL) { QApplication::clipboard()->setText(mapFile->getFileName().trimmed(), QClipboard::Clipboard); } } } /** * Copy the map name to the clip board. */ void ChartTwoOverlayViewController::menuCopyMapNameToClipBoard() { if (m_chartOverlay != NULL) { std::vector allMapFiles; std::vector indexNames; CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; m_chartOverlay->getSelectionData(allMapFiles, mapFile, indexNames, selectedIndexType, selectedIndex); if (mapFile != NULL) { if ((selectedIndex >= 0) && (selectedIndex < static_cast(indexNames.size()))) { QApplication::clipboard()->setText(indexNames[selectedIndex], QClipboard::Clipboard); } } } } /** * Reload the file in the overlay. */ void ChartTwoOverlayViewController::menuReloadFileTriggered() { if (m_chartOverlay != NULL) { CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; m_chartOverlay->getSelectionData(mapFile, selectedIndexType, selectedIndex); if (mapFile != NULL) { AString username; AString password; if (DataFile::isFileOnNetwork(mapFile->getFileName())) { const QString msg("This file is on the network. " "If accessing the file requires a username and " "password, enter it here. Otherwise, remove any " "text from the username and password fields."); if (UsernamePasswordWidget::getUserNameAndPasswordInDialog(m_constructionToolButton, "Username and Password", msg, username, password)) { /* nothing */ } else { return; } } EventDataFileReload reloadEvent(GuiManager::get()->getBrain(), mapFile); reloadEvent.setUsernameAndPassword(username, password); EventManager::get()->sendEvent(reloadEvent.getPointer()); if (reloadEvent.isError()) { WuQMessageBox::errorOk(m_constructionToolButton, reloadEvent.getErrorMessage()); } updateOverlaySettingsEditor(); updateUserInterfaceAndGraphicsWindow(); } } } /** * Create a axis location mode pixmap. * * @param widget * To color the pixmap with backround and foreground, * the palette from the given widget is used. * @param axisLocation * Axis location represented by the icon. * @return * Pixmap for matrix view mode. */ QPixmap ChartTwoOverlayViewController::createAxisLocationPixmap(QWidget* widget, const ChartAxisLocationEnum::Enum axisLocation) { CaretAssert(widget); /* * Create a small, square pixmap that will contain * the foreground color around the pixmap's perimeter. */ const qreal iconSize = 24.0; const qreal minValue = 2.0; const qreal maxValue = iconSize - minValue; QPixmap pixmap(static_cast(iconSize), static_cast(iconSize)); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginBottomLeft(widget, pixmap); QPen pen = painter->pen(); pen.setWidthF(2.0); painter->setPen(pen); const int offsetFromEdge = 3; switch (axisLocation) { case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: painter->drawLine(QPointF(minValue, minValue + offsetFromEdge), QPointF(maxValue, minValue + offsetFromEdge)); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: painter->drawLine(QPointF(minValue + offsetFromEdge, minValue), QPointF(minValue + offsetFromEdge, maxValue)); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: painter->drawLine(QPointF(maxValue - offsetFromEdge, minValue), QPointF(maxValue - offsetFromEdge, maxValue)); break; case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: painter->drawLine(QPointF(minValue, maxValue - offsetFromEdge), QPointF(maxValue, maxValue - offsetFromEdge)); break; } return pixmap; } /** * Create a matrix view mode pixmap. * * @param widget * To color the pixmap with backround and foreground, * the palette from the given widget is used. * @param matrixViewMode * Matrix view mode represented by the icon. * @return * Pixmap for matrix view mode. */ QPixmap ChartTwoOverlayViewController::createMatrixTriangularViewModePixmap(QWidget* widget, const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode) { CaretAssert(widget); /* * Create a small, square pixmap that will contain * the foreground color around the pixmap's perimeter. */ const qreal iconSize = 24.0; const qreal minValue = 2.0; const qreal maxValue = iconSize - minValue; const QPointF bottomLeft(minValue, minValue); const QPointF bottomRight(maxValue, minValue); const QPointF topRight(maxValue, maxValue); const QPointF topLeft(minValue, maxValue); QPixmap pixmap(static_cast(iconSize), static_cast(iconSize)); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginBottomLeft(widget, pixmap); QPen pen = painter->pen(); pen.setWidthF(2.0); painter->setPen(pen); QPolygonF polygon; switch (matrixViewMode) { case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL: { polygon.push_back(bottomLeft); polygon.push_back(bottomRight); polygon.push_back(topRight); polygon.push_back(topLeft); } break; case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_FULL_NO_DIAGONAL: { polygon.push_back(bottomLeft); polygon.push_back(bottomRight); polygon.push_back(topRight); polygon.push_back(topLeft); painter->drawLine(topLeft, bottomRight); } break; case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_LOWER_NO_DIAGONAL: { polygon.push_back(bottomLeft); polygon.push_back(bottomRight); polygon.push_back(topLeft); } break; case ChartTwoMatrixTriangularViewingModeEnum::MATRIX_VIEW_UPPER_NO_DIAGONAL: { polygon.push_back(bottomRight); polygon.push_back(topRight); polygon.push_back(topLeft); } break; } painter->drawPolygon(polygon); return pixmap; } connectome-workbench-1.4.2/src/GuiQt/ChartTwoOverlayViewController.h000066400000000000000000000151561360521144700256300ustar00rootroot00000000000000#ifndef __CHART_TWO_OVERLAY_VIEW_CONTROLLER_H__ #define __CHART_TWO_OVERLAY_VIEW_CONTROLLER_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "ChartAxisLocationEnum.h" #include "ChartTwoMatrixTriangularViewingModeEnum.h" class QAction; class QCheckBox; class QComboBox; class QGridLayout; class QMenu; class QSpinBox; class QToolButton; namespace caret { class ChartTwoOverlay; class MapYokingGroupComboBox; class WuQGridLayoutGroup; class ChartTwoOverlayViewController : public QObject { Q_OBJECT public: ChartTwoOverlayViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, const int32_t chartOverlayIndex, const QString& parentObjectName, QObject* parent); virtual ~ChartTwoOverlayViewController(); void updateViewController(ChartTwoOverlay* overlay); // ADD_NEW_METHODS_HERE signals: void requestAddOverlayAbove(const int32_t overlayIndex); void requestAddOverlayBelow(const int32_t overlayIndex); void requestRemoveOverlay(const int32_t overlayIndex); void requestMoveOverlayUp(const int32_t overlayIndex); void requestMoveOverlayDown(const int32_t overlayIndex); private slots: void fileComboBoxSelected(int); void mapRowOrColumnNameComboBoxSelected(int); void mapRowOrColumnIndexSpinBoxValueChanged(int); void enabledCheckBoxClicked(bool); void lineSeriesLoadingEnabledCheckBoxClicked(bool); void colorBarActionTriggered(bool); void settingsActionTriggered(); void yokingGroupActivated(); void allMapsCheckBoxClicked(bool); void menuAddOverlayAboveTriggered(); void menuAddOverlayBelowTriggered(); void menuRemoveOverlayTriggered(); void menuMoveOverlayDownTriggered(); void menuMoveOverlayUpTriggered(); void menuReloadFileTriggered(); void menuCopyFileNameToClipBoard(); void menuCopyMapNameToClipBoard(); void menuConstructionAboutToShow(); void menuMatrixTriangularViewModeTriggered(QAction* action); void menuAxisLocationTriggered(QAction* action); private: ChartTwoOverlayViewController(const ChartTwoOverlayViewController&); ChartTwoOverlayViewController& operator=(const ChartTwoOverlayViewController&); void updateUserInterfaceAndGraphicsWindow(); void updateUserInterface(); void updateGraphicsWindow(); QMenu* createConstructionMenu(QWidget* parent, const QString& parentObjectName, const QString& descriptivePrefix); QMenu* createMatrixTriangularViewModeMenu(QWidget* widget, const QString& parentObjectName, const QString& descriptivePrefix); QMenu* createAxisLocationMenu(QWidget* widget, const QString& parentObjectName, const QString& descriptivePrefix); void validateYokingSelection(); void updateOverlaySettingsEditor(); QPixmap createMatrixTriangularViewModePixmap(QWidget* widget, const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode); QPixmap createAxisLocationPixmap(QWidget* widget, const ChartAxisLocationEnum::Enum axisLocation); void updateMatrixTriangularViewModeAction(const ChartTwoMatrixTriangularViewingModeEnum::Enum matrixViewMode); void updateAxisLocationAction(const ChartAxisLocationEnum::Enum axisLocation); const int32_t m_browserWindowIndex; const int32_t m_chartOverlayIndex; ChartTwoOverlay* m_chartOverlay; QCheckBox* m_enabledCheckBox; QCheckBox* m_lineSeriesLoadingEnabledCheckBox; QToolButton* m_settingsToolButton; QAction* m_settingsAction; QToolButton* m_colorBarToolButton; QAction* m_colorBarAction; QAction* m_constructionAction; QToolButton* m_matrixTriangularViewModeToolButton; QAction* m_matrixTriangularViewModeAction; QAction* m_axisLocationAction; QToolButton* m_axisLocationToolButton; std::vector> m_matrixViewMenuData; std::vector> m_axisLocationMenuData; QComboBox* m_mapFileComboBox; MapYokingGroupComboBox* m_mapRowOrColumnYokingGroupComboBox; QCheckBox* m_allMapsCheckBox; QSpinBox* m_mapRowOrColumnIndexSpinBox; QComboBox* m_mapRowOrColumnNameComboBox; QToolButton* m_constructionToolButton; QAction* m_constructionReloadFileAction; // ADD_NEW_MEMBERS_HERE friend class ChartTwoOverlaySetViewController; }; #ifdef __CHART_TWO_OVERLAY_VIEW_CONTROLLER_DECLARE__ // #endif // __CHART_TWO_OVERLAY_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__CHART_TWO_OVERLAY_VIEW_CONTROLLER_H__ connectome-workbench-1.4.2/src/GuiQt/CiftiConnectivityMatrixViewController.cxx000066400000000000000000000733141360521144700277300ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CIFTI_CONNECTIVITY_MATRIX_VIEW_CONTROLLER_DECLARE__ #include "CiftiConnectivityMatrixViewController.h" #undef __CIFTI_CONNECTIVITY_MATRIX_VIEW_CONTROLLER_DECLARE__ #include #include #include #include #include #include #include #include #include "Brain.h" #include "CiftiBrainordinateScalarFile.h" #include "CiftiConnectivityMatrixDenseDynamicFile.h" #include "CiftiFiberOrientationFile.h" #include "CiftiFiberTrajectoryFile.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "CursorDisplayScoped.h" #include "EventDataFileAdd.h" #include "EventManager.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUserInterfaceUpdate.h" #include "FiberTrajectoryMapProperties.h" #include "FilePathNamePrefixCompactor.h" #include "GuiManager.h" #include "MetricDynamicConnectivityFile.h" #include "VolumeDynamicConnectivityFile.h" #include "WuQMacroManager.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; static const char* FILE_POINTER_PROPERTY_NAME = "filePointer"; /** * \class caret::CiftiConnectivityMatrixViewController * \brief View-Controller connectivity files * \ingroup GuiQt */ /** * Constructor. * * @param parentObjectName * Name of parent object for macros * @param parent * The parent widget */ CiftiConnectivityMatrixViewController::CiftiConnectivityMatrixViewController(const QString& parentObjectName, QWidget* parent) : QWidget(parent), m_objectNamePrefix(parentObjectName + ":Connectivity") { m_gridLayout = new QGridLayout(); WuQtUtilities::setLayoutSpacingAndMargins(m_gridLayout, 2, 2); m_gridLayout->setColumnStretch(COLUMN_ENABLE_CHECKBOX, 0); m_gridLayout->setColumnStretch(COLUMN_LAYER_CHECKBOX, 0); m_gridLayout->setColumnStretch(COLUMN_COPY_BUTTON, 0); m_gridLayout->setColumnStretch(COLUMN_NAME_LINE_EDIT, 100); m_gridLayout->setColumnStretch(COLUMN_ORIENTATION_FILE_COMBO_BOX, 100); const int titleRow = m_gridLayout->rowCount(); m_gridLayout->addWidget(new QLabel("Load"), titleRow, COLUMN_ENABLE_CHECKBOX); m_gridLayout->addWidget(new QLabel("Layer"), titleRow, COLUMN_LAYER_CHECKBOX); m_gridLayout->addWidget(new QLabel("Copy"), titleRow, COLUMN_COPY_BUTTON); m_gridLayout->addWidget(new QLabel("Connectivity File"), titleRow, COLUMN_NAME_LINE_EDIT); m_gridLayout->addWidget(new QLabel("Fiber Orientation File"), titleRow, COLUMN_ORIENTATION_FILE_COMBO_BOX); m_signalMapperFileEnableCheckBox = new QSignalMapper(this); QObject::connect(m_signalMapperFileEnableCheckBox, SIGNAL(mapped(int)), this, SLOT(enabledCheckBoxClicked(int))); m_signalMapperLayerCheckBox = new QSignalMapper(this); QObject::connect(m_signalMapperLayerCheckBox, SIGNAL(mapped(int)), this, SLOT(layerCheckBoxClicked(int))); m_signalMapperFileCopyToolButton = new QSignalMapper(this); QObject::connect(m_signalMapperFileCopyToolButton, SIGNAL(mapped(int)), this, SLOT(copyToolButtonClicked(int))); m_signalMapperFiberOrientationFileComboBox = new QSignalMapper(this); QObject::connect(m_signalMapperFiberOrientationFileComboBox, SIGNAL(mapped(int)), this, SLOT(fiberOrientationFileComboBoxActivated(int))); QVBoxLayout* layout = new QVBoxLayout(this); layout->addLayout(m_gridLayout); layout->addStretch(); s_allCiftiConnectivityMatrixViewControllers.insert(this); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); } /** * Destructor. */ CiftiConnectivityMatrixViewController::~CiftiConnectivityMatrixViewController() { s_allCiftiConnectivityMatrixViewControllers.erase(this); EventManager::get()->removeAllEventsFromListener(this); } /** * Update this view controller. */ void CiftiConnectivityMatrixViewController::updateViewController() { Brain* brain = GuiManager::get()->getBrain(); std::vector files; std::vector trajFiles; brain->getConnectivityFiberTrajectoryFiles(trajFiles); for (std::vector::iterator trajIter = trajFiles.begin(); trajIter != trajFiles.end(); trajIter++) { files.push_back(*trajIter); } std::vector matrixFiles; brain->getAllCiftiConnectivityMatrixFiles(matrixFiles); for (std::vector::iterator matrixIter = matrixFiles.begin(); matrixIter != matrixFiles.end(); matrixIter++) { files.push_back(*matrixIter); } std::vector metricDynConnFiles; brain->getMetricDynamicConnectivityFiles(metricDynConnFiles); files.insert(files.end(), metricDynConnFiles.begin(), metricDynConnFiles.end()); std::vector volumeDynConnFiles; brain->getVolumeDynamicConnectivityFiles(volumeDynConnFiles); files.insert(files.end(), volumeDynConnFiles.begin(), volumeDynConnFiles.end()); WuQMacroManager* macroManager = WuQMacroManager::instance(); const int32_t numFiles = static_cast(files.size()); for (int32_t i = 0; i < numFiles; i++) { QCheckBox* checkBox = NULL; QCheckBox* layerCheckBox = NULL; QLineEdit* lineEdit = NULL; QToolButton* copyToolButton = NULL; QComboBox* comboBox = NULL; if (i < static_cast(m_fileEnableCheckBoxes.size())) { checkBox = m_fileEnableCheckBoxes[i]; layerCheckBox = m_layerCheckBoxes[i]; lineEdit = m_fileNameLineEdits[i]; copyToolButton = m_fileCopyToolButtons[i]; comboBox = m_fiberOrientationFileComboBoxes[i]; } else { const QString objectNamePrefix(m_objectNamePrefix + QString("%1").arg((int)i+1, 2, 10, QLatin1Char('0')) + ":"); const QString descriptivePrefix("connectivity file " + QString::number(i+1)); checkBox = new QCheckBox(""); checkBox->setToolTip("When selected, load data during\n" "an identification operation"); m_fileEnableCheckBoxes.push_back(checkBox); checkBox->setObjectName(objectNamePrefix + "Enable"); macroManager->addMacroSupportToObject(checkBox, "Enable " + descriptivePrefix); const AString dynToolTip("This option is enabled only for dynamic connectivity files. " "When checked, this dynamic connectivity file will appear in the Overlay Layers' File selection combo box. " "Dynamic connectivity files do not explicitly exist but allow dynamic " "computation of connectivity from a CIFTI data-series, metric, or volume file. " "In Preferences, one may set the default to show/hide dynamic connectivity files."); layerCheckBox = new QCheckBox(""); WuQtUtilities::setWordWrappedToolTip(layerCheckBox, dynToolTip); m_layerCheckBoxes.push_back(layerCheckBox); layerCheckBox->setObjectName(objectNamePrefix + "EnableLayer"); macroManager->addMacroSupportToObject(layerCheckBox, "Enable dynamic connectivity for " + descriptivePrefix); lineEdit = new QLineEdit(); lineEdit->setReadOnly(true); m_fileNameLineEdits.push_back(lineEdit); copyToolButton = new QToolButton(); copyToolButton->setText("Copy"); copyToolButton->setToolTip("Copy loaded connectivity data into a writable file that is added to layers"); m_fileCopyToolButtons.push_back(copyToolButton); copyToolButton->setObjectName(objectNamePrefix + "CopyButton"); macroManager->addMacroSupportToObject(copyToolButton, "Copy load row to new CIFTI scalar or Volume file for " + descriptivePrefix); comboBox = new QComboBox(); m_fiberOrientationFileComboBoxes.push_back(comboBox); comboBox->setToolTip("Select Fiber Orientation File"); comboBox->setObjectName(objectNamePrefix + "FiberOrientationFile"); macroManager->addMacroSupportToObject(comboBox, "Select fiber orientation for " + descriptivePrefix); QObject::connect(copyToolButton, SIGNAL(clicked()), m_signalMapperFileCopyToolButton, SLOT(map())); m_signalMapperFileCopyToolButton->setMapping(copyToolButton, i); QObject::connect(checkBox, SIGNAL(clicked(bool)), m_signalMapperFileEnableCheckBox, SLOT(map())); m_signalMapperFileEnableCheckBox->setMapping(checkBox, i); QObject::connect(layerCheckBox, SIGNAL(clicked(bool)), m_signalMapperLayerCheckBox, SLOT(map())); m_signalMapperLayerCheckBox->setMapping(layerCheckBox, i); QObject::connect(comboBox, SIGNAL(activated(int)), m_signalMapperFiberOrientationFileComboBox, SLOT(map())); m_signalMapperFiberOrientationFileComboBox->setMapping(comboBox, i); const int row = m_gridLayout->rowCount(); m_gridLayout->addWidget(checkBox, row, COLUMN_ENABLE_CHECKBOX); m_gridLayout->addWidget(layerCheckBox, row, COLUMN_LAYER_CHECKBOX); m_gridLayout->addWidget(copyToolButton, row, COLUMN_COPY_BUTTON); m_gridLayout->addWidget(lineEdit, row, COLUMN_NAME_LINE_EDIT); m_gridLayout->addWidget(comboBox, row, COLUMN_ORIENTATION_FILE_COMBO_BOX); } const CiftiMappableConnectivityMatrixDataFile* matrixFile = dynamic_cast(files[i]); const CiftiFiberTrajectoryFile* trajFile = dynamic_cast(files[i]); const VolumeDynamicConnectivityFile* volDynConnFile = dynamic_cast(files[i]); const MetricDynamicConnectivityFile* metricDynConnFile = dynamic_cast(files[i]); bool checkStatus = false; if (matrixFile != NULL) { checkStatus = matrixFile->isMapDataLoadingEnabled(0); } else if (trajFile != NULL) { checkStatus = trajFile->isDataLoadingEnabled(); } else if (volDynConnFile != NULL) { checkStatus = volDynConnFile->isDataLoadingEnabled(); } else if (metricDynConnFile != NULL) { checkStatus = metricDynConnFile->isDataLoadingEnabled(); } else { CaretAssertMessage(0, "Has a new file type been added?"); } checkBox->setChecked(checkStatus); checkBox->setProperty(FILE_POINTER_PROPERTY_NAME, qVariantFromValue((void*)files[i])); const CiftiConnectivityMatrixDenseDynamicFile* dynConnFile = dynamic_cast(files[i]); if (dynConnFile != NULL) { layerCheckBox->setChecked(dynConnFile->isEnabledAsLayer()); } else if (volDynConnFile != NULL) { layerCheckBox->setChecked(volDynConnFile->isEnabledAsLayer()); } else if (metricDynConnFile != NULL) { layerCheckBox->setChecked(metricDynConnFile->isEnabledAsLayer()); } else { layerCheckBox->setChecked(false); } lineEdit->setText(files[i]->getFileName()); // displayNames[i]); } const int32_t numItems = static_cast(m_fileEnableCheckBoxes.size()); for (int32_t i = 0; i < numItems; i++) { bool layerCheckBoxValid = false; bool showRow = false; bool showOrientationComboBox = false; if (i < numFiles) { showRow = true; if (dynamic_cast(files[i]) != NULL) { showOrientationComboBox = true; } if (dynamic_cast(files[i]) != NULL) { layerCheckBoxValid = true; } else if (dynamic_cast(files[i]) != NULL) { layerCheckBoxValid = true; } else if (dynamic_cast(files[i]) != NULL) { layerCheckBoxValid = true; } } m_fileEnableCheckBoxes[i]->setVisible(showRow); m_layerCheckBoxes[i]->setVisible(showRow); m_layerCheckBoxes[i]->setEnabled(layerCheckBoxValid); m_fileCopyToolButtons[i]->setVisible(showRow); m_fileNameLineEdits[i]->setVisible(showRow); m_fiberOrientationFileComboBoxes[i]->setVisible(showOrientationComboBox); m_fiberOrientationFileComboBoxes[i]->setEnabled(showOrientationComboBox); } updateFiberOrientationComboBoxes(); } /** * Update the fiber orientation combo boxes. */ void CiftiConnectivityMatrixViewController::updateFiberOrientationComboBoxes() { std::vector orientationFiles; GuiManager::get()->getBrain()->getConnectivityFiberOrientationFiles(orientationFiles); const int32_t numOrientationFiles = static_cast(orientationFiles.size()); const int32_t numItems = static_cast(m_fiberOrientationFileComboBoxes.size()); for (int32_t i = 0; i < numItems; i++) { QComboBox* comboBox = m_fiberOrientationFileComboBoxes[i]; CiftiMappableConnectivityMatrixDataFile* matrixFile = NULL; CiftiFiberTrajectoryFile* trajFile = NULL; MetricDynamicConnectivityFile* metricDynConnFile(NULL); VolumeDynamicConnectivityFile* volDynConnFile = NULL; if (comboBox->isEnabled()) { getFileAtIndex(i, matrixFile, trajFile, metricDynConnFile, volDynConnFile); } if (trajFile != NULL) { int32_t selectedIndex = 0; CiftiFiberOrientationFile* selectedOrientationFile = trajFile->getMatchingFiberOrientationFile(); comboBox->clear(); for (int32_t iOrient = 0; iOrient < numOrientationFiles; iOrient++) { CiftiFiberOrientationFile* orientFile = orientationFiles[iOrient]; if (trajFile->isFiberOrientationFileCombatible(orientFile)) { if (orientFile == selectedOrientationFile) { selectedIndex = iOrient; } comboBox->addItem(orientFile->getFileNameNoPath(), qVariantFromValue((void*)orientFile)); } } if ((selectedIndex >= 0) && (selectedIndex < comboBox->count())) { comboBox->setCurrentIndex(selectedIndex); } } else { comboBox->clear(); } // const bool showComboBox = (trajFile != NULL); // m_fiberOrientationFileComboBoxes[i]->setVisible(showComboBox); // m_fiberOrientationFileComboBoxes[i]->setEnabled(showComboBox); // std::cout << "Show Orientation File Combo Box: " // << i // << ": " // << qPrintable(AString::fromBool(showComboBox)) // << std::endl; } } /** * Called when an enabled check box changes state. * * @param indx * Index of checkbox that was clicked. */ void CiftiConnectivityMatrixViewController::enabledCheckBoxClicked(int indx) { CaretAssertVectorIndex(m_fileEnableCheckBoxes, indx); const bool newStatus = m_fileEnableCheckBoxes[indx]->isChecked(); CiftiMappableConnectivityMatrixDataFile* matrixFile = NULL; CiftiFiberTrajectoryFile* trajFile = NULL; VolumeDynamicConnectivityFile* volDynConnFile(NULL); MetricDynamicConnectivityFile* metricDynConnFile(NULL); getFileAtIndex(indx, matrixFile, trajFile, metricDynConnFile, volDynConnFile); if (matrixFile != NULL) { matrixFile->setMapDataLoadingEnabled(0, newStatus); } else if (metricDynConnFile != NULL) { metricDynConnFile->setDataLoadingEnabled(newStatus); } else if (trajFile != NULL) { trajFile->setDataLoadingEnabled(newStatus); } else if (volDynConnFile != NULL) { volDynConnFile->setDataLoadingEnabled(newStatus); } else { CaretAssertMessage(0, "Has a new file type been added?"); } updateOtherCiftiConnectivityMatrixViewControllers(); } /** * Called when a layer check box changes state. * * @param indx * Index of checkbox that was clicked. */ void CiftiConnectivityMatrixViewController::layerCheckBoxClicked(int indx) { CaretAssertVectorIndex(m_layerCheckBoxes, indx); const bool newStatus = m_layerCheckBoxes[indx]->isChecked(); CiftiMappableConnectivityMatrixDataFile* matrixFile = NULL; CiftiFiberTrajectoryFile* trajFile = NULL; MetricDynamicConnectivityFile* metricDynConnFile(NULL); VolumeDynamicConnectivityFile* volDynConnFile(NULL); getFileAtIndex(indx, matrixFile, trajFile, metricDynConnFile, volDynConnFile); if (matrixFile != NULL) { CiftiConnectivityMatrixDenseDynamicFile* dynConnFile = dynamic_cast(matrixFile); if (dynConnFile != NULL) { dynConnFile->setEnabledAsLayer(newStatus); } } else if (metricDynConnFile != NULL) { metricDynConnFile->setEnabledAsLayer(newStatus); } else if (volDynConnFile != NULL) { volDynConnFile->setEnabledAsLayer(newStatus); } else if (trajFile != NULL) { CaretAssertMessage(0, "Should never get caled for fiber trajectory file"); } else { CaretAssertMessage(0, "Has a new file type been added?"); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); //updateOtherCiftiConnectivityMatrixViewControllers(); } /** * Get the file associated with the given index. One of the output files * will be NULL and the other will be non-NULL. * * @param indx * The index. * @param ciftiMatrixFileOut * If there is a CIFTI matrix file at the given index, this will be non-NULL. * @param ciftiTrajFileOut * If there is a CIFTI trajectory file at the given index, this will be non-NULL. * @param metricDynConnFileOut * If there is a Metric Dynamic file at the given index, this will be non-NULL * @param volDynConnFileOut * If there is a volume dynamnic connectivity files at the given index, this will be non-NULL */ void CiftiConnectivityMatrixViewController::getFileAtIndex(const int32_t indx, CiftiMappableConnectivityMatrixDataFile* &ciftiMatrixFileOut, CiftiFiberTrajectoryFile* &ciftiTrajFileOut, MetricDynamicConnectivityFile* &metricDynConnFileOut, VolumeDynamicConnectivityFile* &volDynConnFileOut) { CaretAssertVectorIndex(m_fileEnableCheckBoxes, indx); void* ptr = m_fileEnableCheckBoxes[indx]->property(FILE_POINTER_PROPERTY_NAME).value(); CaretMappableDataFile* mapFilePointer = (CaretMappableDataFile*)ptr; ciftiMatrixFileOut = dynamic_cast(mapFilePointer); ciftiTrajFileOut = dynamic_cast(mapFilePointer); metricDynConnFileOut = dynamic_cast(mapFilePointer); volDynConnFileOut = dynamic_cast(mapFilePointer); AString name = ""; if (mapFilePointer != NULL) { name = mapFilePointer->getFileNameNoPath(); } // std::cout << "File at index: " // << indx // << " name: " // << qPrintable(name) // << " cifti-matrix-ptr: " // << (long)ciftiMatrixFileOut // << " cifti-traj-ptr: " // << (long)ciftiTrajFileOut // << std::endl; if (ciftiMatrixFileOut != NULL) { /* OK */ } else if (ciftiTrajFileOut != NULL) { /* OK */ } else if (metricDynConnFileOut != NULL) { /* OK */ } else if (volDynConnFileOut != NULL) { /* OK */ } else { CaretAssertMessage(0, "Has a new file type been added?"); } } /** * Called when fiber orientation file combo box changed. * * @param indx * Index of combo box that was changed. */ void CiftiConnectivityMatrixViewController::fiberOrientationFileComboBoxActivated(int indx) { CaretAssertVectorIndex(m_fiberOrientationFileComboBoxes, indx); CiftiMappableConnectivityMatrixDataFile* matrixFile = NULL; CiftiFiberTrajectoryFile* trajFile = NULL; MetricDynamicConnectivityFile* metricDynConnFile(NULL); VolumeDynamicConnectivityFile* volDynConnFile(NULL); getFileAtIndex(indx, matrixFile, trajFile, metricDynConnFile, volDynConnFile); CaretAssertMessage(trajFile, "Selected orientation file but trajectory file is invalid."); QComboBox* cb = m_fiberOrientationFileComboBoxes[indx]; void* ptr = cb->itemData(indx, Qt::UserRole).value(); CaretAssert(ptr); CiftiFiberOrientationFile* orientFile = (CiftiFiberOrientationFile*)ptr; std::vector orientationFiles; GuiManager::get()->getBrain()->getConnectivityFiberOrientationFiles(orientationFiles); if (std::find(orientationFiles.begin(), orientationFiles.end(), orientFile) == orientationFiles.end()) { CaretAssertMessage(0, "Selected fiber orientation file is no longer valid."); return; } trajFile->setMatchingFiberOrientationFile(orientFile); updateOtherCiftiConnectivityMatrixViewControllers(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called when copy tool button is clicked. * * @param indx * Index of copy tool button that was clicked. */ void CiftiConnectivityMatrixViewController::copyToolButtonClicked(int indx) { CursorDisplayScoped cursor; cursor.showWaitCursor(); CiftiMappableConnectivityMatrixDataFile* matrixFile = NULL; CiftiFiberTrajectoryFile* trajFile = NULL; MetricDynamicConnectivityFile* metricDynConnFile(NULL); VolumeDynamicConnectivityFile* volDynConnFile(NULL); getFileAtIndex(indx, matrixFile, trajFile, metricDynConnFile, volDynConnFile); bool errorFlag = false; AString errorMessage; const AString directoryName = GuiManager::get()->getBrain()->getCurrentDirectory(); if (matrixFile != NULL) { CiftiBrainordinateScalarFile* scalarFile = CiftiBrainordinateScalarFile::newInstanceFromRowInCiftiConnectivityMatrixFile(matrixFile, directoryName, errorMessage); if (scalarFile != NULL) { EventDataFileAdd dataFileAdd(scalarFile); EventManager::get()->sendEvent(dataFileAdd.getPointer()); if (dataFileAdd.isError()) { errorMessage = dataFileAdd.getErrorMessage(); errorFlag = true; } } else { errorFlag = true; } } else if (volDynConnFile != NULL) { VolumeFile* newVolumeFile = volDynConnFile->newVolumeFileFromLoadedData(directoryName, errorMessage); if (newVolumeFile != NULL) { EventDataFileAdd dataFileAdd(newVolumeFile); EventManager::get()->sendEvent(dataFileAdd.getPointer()); if (dataFileAdd.isError()) { errorMessage = dataFileAdd.getErrorMessage(); errorFlag = true; } } else { errorFlag = true; } } else if (metricDynConnFile != NULL) { MetricFile* newMetricFile = metricDynConnFile->newMetricFileFromLoadedData(directoryName, errorMessage); if (newMetricFile != NULL) { EventDataFileAdd dataFileAdd(newMetricFile); EventManager::get()->sendEvent(dataFileAdd.getPointer()); if (dataFileAdd.isError()) { errorMessage = dataFileAdd.getErrorMessage(); errorFlag = true; } } else { errorFlag = true; } } else if (trajFile != NULL) { CiftiFiberTrajectoryFile* newTrajFile = trajFile->newFiberTrajectoryFileFromLoadedRowData(directoryName, errorMessage); if (newTrajFile != NULL) { EventDataFileAdd dataFileAdd(newTrajFile); EventManager::get()->sendEvent(dataFileAdd.getPointer()); if (dataFileAdd.isError()) { errorMessage = dataFileAdd.getErrorMessage(); errorFlag = true; } } else { errorFlag = true; } } else { CaretAssertMessage(0, "Has a new file type been added?"); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); cursor.restoreCursor(); if (errorFlag) { WuQMessageBox::errorOk(m_fileCopyToolButtons[indx], errorMessage); } } ///** // * Update graphics and GUI after // */ //void //CiftiConnectivityMatrixViewController::updateUserInterfaceAndGraphicsWindow() //{ // updateOtherCiftiConnectivityMatrixViewControllers(); // // EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); // EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); //} /** * Update other connectivity view controllers other than 'this' instance * that contain the same connectivity file. */ void CiftiConnectivityMatrixViewController::updateOtherCiftiConnectivityMatrixViewControllers() { for (std::set::iterator iter = s_allCiftiConnectivityMatrixViewControllers.begin(); iter != s_allCiftiConnectivityMatrixViewControllers.end(); iter++) { CiftiConnectivityMatrixViewController* clvc = *iter; if (clvc != this) { clvc->updateViewController(); } } } /** * Receive events from the event manager. * * @param event * Event sent by event manager. */ void CiftiConnectivityMatrixViewController::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiEvent = dynamic_cast(event); CaretAssert(uiEvent); // if (uiEvent->isUpdateForWindow(this->browserWindowIndex)) { if (uiEvent->isConnectivityUpdate() || uiEvent->isToolBoxUpdate()) { this->updateViewController(); uiEvent->setEventProcessed(); } // } } } connectome-workbench-1.4.2/src/GuiQt/CiftiConnectivityMatrixViewController.h000066400000000000000000000107601360521144700273510ustar00rootroot00000000000000#ifndef __CIFTI_CONNECTIVITY_MATRIX_VIEW_CONTROLLER__H_ #define __CIFTI_CONNECTIVITY_MATRIX_VIEW_CONTROLLER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "EventListenerInterface.h" class QCheckBox; class QComboBox; class QGridLayout; class QLineEdit; class QSignalMapper; class QToolButton; namespace caret { class CiftiMappableConnectivityMatrixDataFile; class CiftiFiberTrajectoryFile; class MetricDynamicConnectivityFile; class VolumeDynamicConnectivityFile; class CiftiConnectivityMatrixViewController : public QWidget, EventListenerInterface { Q_OBJECT public: CiftiConnectivityMatrixViewController(const QString& parentObjectName, QWidget* parent); virtual ~CiftiConnectivityMatrixViewController(); void receiveEvent(Event* event); private slots: void enabledCheckBoxClicked(int); void layerCheckBoxClicked(int); void copyToolButtonClicked(int); void fiberOrientationFileComboBoxActivated(int); private: CiftiConnectivityMatrixViewController(const CiftiConnectivityMatrixViewController&); CiftiConnectivityMatrixViewController& operator=(const CiftiConnectivityMatrixViewController&); // void updateUserInterfaceAndGraphicsWindow(); void updateViewController(); void updateOtherCiftiConnectivityMatrixViewControllers(); void updateFiberOrientationComboBoxes(); void getFileAtIndex(const int32_t indx, CiftiMappableConnectivityMatrixDataFile* &ciftiMatrixFileOut, CiftiFiberTrajectoryFile* &ciftiTrajFileOut, MetricDynamicConnectivityFile* &metricDynConnFileOut, VolumeDynamicConnectivityFile* &volDynConnFileOut); const QString m_objectNamePrefix; std::vector m_fileEnableCheckBoxes; std::vector m_layerCheckBoxes; std::vector m_fileNameLineEdits; std::vector m_fileCopyToolButtons; std::vector m_fiberOrientationFileComboBoxes; QGridLayout* m_gridLayout; QSignalMapper* m_signalMapperFileEnableCheckBox; QSignalMapper* m_signalMapperLayerCheckBox; QSignalMapper* m_signalMapperFileCopyToolButton; QSignalMapper* m_signalMapperFiberOrientationFileComboBox; static std::set s_allCiftiConnectivityMatrixViewControllers; static int COLUMN_ENABLE_CHECKBOX; static int COLUMN_LAYER_CHECKBOX; static int COLUMN_COPY_BUTTON; static int COLUMN_NAME_LINE_EDIT; static int COLUMN_ORIENTATION_FILE_COMBO_BOX; }; #ifdef __CIFTI_CONNECTIVITY_MATRIX_VIEW_CONTROLLER_DECLARE__ std::set CiftiConnectivityMatrixViewController::s_allCiftiConnectivityMatrixViewControllers; int CiftiConnectivityMatrixViewController::COLUMN_ENABLE_CHECKBOX = 0; int CiftiConnectivityMatrixViewController::COLUMN_LAYER_CHECKBOX = 1; int CiftiConnectivityMatrixViewController::COLUMN_COPY_BUTTON = 2; int CiftiConnectivityMatrixViewController::COLUMN_NAME_LINE_EDIT = 3; int CiftiConnectivityMatrixViewController::COLUMN_ORIENTATION_FILE_COMBO_BOX = 4; #endif // __CIFTI_CONNECTIVITY_MATRIX_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__CIFTI_CONNECTIVITY_MATRIX_VIEW_CONTROLLER__H_ connectome-workbench-1.4.2/src/GuiQt/CiftiParcelSelectionComboBox.cxx000066400000000000000000000100351360521144700256620ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CIFTI_PARCEL_SELECTION_COMBO_BOX_DECLARE__ #include "CiftiParcelSelectionComboBox.h" #undef __CIFTI_PARCEL_SELECTION_COMBO_BOX_DECLARE__ #include #include "AStringNaturalComparison.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CiftiParcelsMap.h" using namespace caret; /** * \class caret::CiftiParcelSelectionComboBox * \brief ComboBox for selection of a Parcel from a CiftiParcelsMap. * \ingroup GuiQt */ /** * Constructor. */ CiftiParcelSelectionComboBox::CiftiParcelSelectionComboBox(QObject* parent) : WuQWidget(parent) { m_comboBox = new QComboBox(); QObject::connect(m_comboBox, SIGNAL(activated(const QString&)), this, SIGNAL(parcelNameSelected(const QString&))); } /** * Destructor. */ CiftiParcelSelectionComboBox::~CiftiParcelSelectionComboBox() { } /** * @return The QComboBox for adding to a layout, enalbling, etc. */ QWidget* CiftiParcelSelectionComboBox::getWidget() { return m_comboBox; } /** * Update the combo box with the given parcels map. If NULL, * combo box will be empty. * * @param parcelsMap * Parcels map inserted into combo box. */ void CiftiParcelSelectionComboBox::updateComboBox(const CiftiParcelsMap* parcelsMap) { QString selectedParcelName = m_comboBox->currentText(); m_comboBox->clear(); if (parcelsMap != NULL) { std::set sortedNames; const std::vector& allParcels = parcelsMap->getParcels(); for (std::vector::const_iterator parcelIter = allParcels.begin(); parcelIter != allParcels.end(); parcelIter++) { sortedNames.insert(parcelIter->m_name); } for (std::set::iterator iter = sortedNames.begin(); iter != sortedNames.end(); iter++) { m_comboBox->addItem(*iter); } // QStringList parcelNamesList = QStringList::fromSet(sortedNames); // parcelNamesList.append(parcelIter->m_name); // // m_comboBox->addItems(parcelNamesList); } if ( ! selectedParcelName.isEmpty()) { if (m_comboBox->findText(selectedParcelName) < 0) { selectedParcelName = ""; } } if (selectedParcelName.isEmpty()) { if (m_comboBox->count() > 0) { selectedParcelName = m_comboBox->itemText(0); } } if ( ! selectedParcelName.isEmpty()) { setSelectedParcelName(selectedParcelName); } } /** * @return Name of selected parcel. */ AString CiftiParcelSelectionComboBox::getSelectedParcelName() { return m_comboBox->currentText(); } /** * Set the selected parcel to the parcel with the given name. */ void CiftiParcelSelectionComboBox::setSelectedParcelName(const QString& parcelName) { const int32_t parcelNameIndex = m_comboBox->findText(parcelName); if (parcelNameIndex >= 0) { m_comboBox->setCurrentIndex(parcelNameIndex); } else { CaretLogWarning("Parcel named \"" + parcelName + "\" is not valid name in CiftiParcelSelectionComboBox"); } } connectome-workbench-1.4.2/src/GuiQt/CiftiParcelSelectionComboBox.h000066400000000000000000000041061360521144700253110ustar00rootroot00000000000000#ifndef __CIFTI_PARCEL_SELECTION_COMBO_BOX_H__ #define __CIFTI_PARCEL_SELECTION_COMBO_BOX_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AString.h" #include "WuQWidget.h" class QComboBox; namespace caret { class CiftiParcelsMap; class CiftiParcelSelectionComboBox : public WuQWidget { Q_OBJECT public: CiftiParcelSelectionComboBox(QObject* parent); virtual ~CiftiParcelSelectionComboBox(); virtual QWidget* getWidget(); void updateComboBox(const CiftiParcelsMap* parcelsMap); AString getSelectedParcelName(); public slots: void setSelectedParcelName(const QString& parcelName); signals: void parcelNameSelected(const QString& parcelName); // ADD_NEW_METHODS_HERE private: CiftiParcelSelectionComboBox(const CiftiParcelSelectionComboBox&); CiftiParcelSelectionComboBox& operator=(const CiftiParcelSelectionComboBox&); QComboBox* m_comboBox; // ADD_NEW_MEMBERS_HERE }; #ifdef __CIFTI_PARCEL_SELECTION_COMBO_BOX_DECLARE__ // #endif // __CIFTI_PARCEL_SELECTION_COMBO_BOX_DECLARE__ } // namespace #endif //__CIFTI_PARCEL_SELECTION_COMBO_BOX_H__ connectome-workbench-1.4.2/src/GuiQt/ClippingPlanesDialog.cxx000066400000000000000000000421271360521144700242350ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CLIPPING_PLANES_DIALOG_DECLARE__ #include "ClippingPlanesDialog.h" #undef __CLIPPING_PLANES_DIALOG_DECLARE__ #include #include #include #include #include #include "BrainBrowserWindow.h" #include "BrainBrowserWindowComboBox.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "WuQtUtilities.h" #include "WuQWidgetObjectGroup.h" using namespace caret; /** * \class caret::ClippingPlanesDialog * \brief Dialog for adjusting clipping planes transformation. * \ingroup GuiQt */ /** * Constructor. */ ClippingPlanesDialog::ClippingPlanesDialog(QWidget* parent) : WuQDialogNonModal("Clipping Planes", parent) { m_blockDialogUpdate = true; /*------------------------------------------------------------------------*/ /* * Create widgets */ /* * Window number */ QLabel* windowLabel = new QLabel("Workbench Window: "); m_browserWindowComboBox = new BrainBrowserWindowComboBox(BrainBrowserWindowComboBox::STYLE_NUMBER, this); m_browserWindowComboBox->getWidget()->setFixedWidth(50); QObject::connect(m_browserWindowComboBox, SIGNAL(browserWindowSelected(BrainBrowserWindow*)), this, SLOT(browserWindowComboBoxValueChanged(BrainBrowserWindow*))); QHBoxLayout* windowLayout = new QHBoxLayout(); windowLayout->addWidget(windowLabel); windowLayout->addWidget(m_browserWindowComboBox->getWidget()); windowLayout->addStretch(); /* * X, Y, Z column labels */ QLabel* xColumnLabel = new QLabel("X"); QLabel* yColumnLabel = new QLabel("Y"); QLabel* zColumnLabel = new QLabel("Z"); const int spinBoxWidth = 90; /* * Panning */ const double panStep = 1.0; QLabel* panLabel = new QLabel("Pan:"); m_xPanDoubleSpinBox = new QDoubleSpinBox; m_xPanDoubleSpinBox->setMinimum(-100000.0); m_xPanDoubleSpinBox->setMaximum( 100000.0); m_xPanDoubleSpinBox->setSingleStep(panStep); m_xPanDoubleSpinBox->setDecimals(2); m_xPanDoubleSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_xPanDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(clippingValueChanged())); m_yPanDoubleSpinBox = new QDoubleSpinBox; m_yPanDoubleSpinBox->setMinimum(-100000.0); m_yPanDoubleSpinBox->setMaximum( 100000.0); m_yPanDoubleSpinBox->setSingleStep(panStep); m_yPanDoubleSpinBox->setDecimals(2); m_yPanDoubleSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_yPanDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(clippingValueChanged())); m_zPanDoubleSpinBox = new QDoubleSpinBox; m_zPanDoubleSpinBox->setMinimum(-100000.0); m_zPanDoubleSpinBox->setMaximum( 100000.0); m_zPanDoubleSpinBox->setSingleStep(panStep); m_zPanDoubleSpinBox->setDecimals(2); m_zPanDoubleSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_zPanDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(clippingValueChanged())); /* * Rotation */ const double rotationMinimum = -360.0; const double rotationMaximum = 360.0; const double rotateStep = 1.0; QLabel* rotateLabel = new QLabel("Rotate: "); m_xRotateDoubleSpinBox = new QDoubleSpinBox; m_xRotateDoubleSpinBox->setWrapping(true); m_xRotateDoubleSpinBox->setMinimum(rotationMinimum); m_xRotateDoubleSpinBox->setMaximum(rotationMaximum); m_xRotateDoubleSpinBox->setSingleStep(rotateStep); m_xRotateDoubleSpinBox->setDecimals(2); m_xRotateDoubleSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_xRotateDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(clippingValueChanged())); m_yRotateDoubleSpinBox = new QDoubleSpinBox; m_yRotateDoubleSpinBox->setWrapping(true); m_yRotateDoubleSpinBox->setMinimum(rotationMinimum); m_yRotateDoubleSpinBox->setMaximum(rotationMaximum); m_yRotateDoubleSpinBox->setSingleStep(rotateStep); m_yRotateDoubleSpinBox->setDecimals(2); m_yRotateDoubleSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_yRotateDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(clippingValueChanged())); m_zRotateDoubleSpinBox = new QDoubleSpinBox; m_zRotateDoubleSpinBox->setWrapping(true); m_zRotateDoubleSpinBox->setMinimum(rotationMinimum); m_zRotateDoubleSpinBox->setMaximum(rotationMaximum); m_zRotateDoubleSpinBox->setSingleStep(rotateStep); m_zRotateDoubleSpinBox->setDecimals(2); m_zRotateDoubleSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_zRotateDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(clippingValueChanged())); /* * Thickness */ const double thicknessMinimum = 0.0; const double thicknessMaximum = 1000000.0; const double thicknessStep = 1.0; QLabel* thicknessLabel = new QLabel("Thickness (mm)"); m_xThicknessDoubleSpinBox = new QDoubleSpinBox(); m_xThicknessDoubleSpinBox->setMinimum(thicknessMinimum); m_xThicknessDoubleSpinBox->setMaximum(thicknessMaximum); m_xThicknessDoubleSpinBox->setSingleStep(thicknessStep); m_xThicknessDoubleSpinBox->setDecimals(2); m_xThicknessDoubleSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_xThicknessDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(clippingValueChanged())); m_yThicknessDoubleSpinBox = new QDoubleSpinBox(); m_yThicknessDoubleSpinBox->setMinimum(thicknessMinimum); m_yThicknessDoubleSpinBox->setMaximum(thicknessMaximum); m_yThicknessDoubleSpinBox->setSingleStep(thicknessStep); m_yThicknessDoubleSpinBox->setDecimals(2); m_yThicknessDoubleSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_yThicknessDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(clippingValueChanged())); m_zThicknessDoubleSpinBox = new QDoubleSpinBox(); m_zThicknessDoubleSpinBox->setMinimum(thicknessMinimum); m_zThicknessDoubleSpinBox->setMaximum(thicknessMaximum); m_zThicknessDoubleSpinBox->setSingleStep(thicknessStep); m_zThicknessDoubleSpinBox->setDecimals(2); m_zThicknessDoubleSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_zThicknessDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(clippingValueChanged())); m_clippingWidgetGroup = new WuQWidgetObjectGroup(this); m_clippingWidgetGroup->add(m_xPanDoubleSpinBox); m_clippingWidgetGroup->add(m_yPanDoubleSpinBox); m_clippingWidgetGroup->add(m_zPanDoubleSpinBox); m_clippingWidgetGroup->add(m_xRotateDoubleSpinBox); m_clippingWidgetGroup->add(m_yRotateDoubleSpinBox); m_clippingWidgetGroup->add(m_zRotateDoubleSpinBox); m_clippingWidgetGroup->add(m_xThicknessDoubleSpinBox); m_clippingWidgetGroup->add(m_yThicknessDoubleSpinBox); m_clippingWidgetGroup->add(m_zThicknessDoubleSpinBox); /* * Show clipping box checkbox */ m_displayClippingBoxCheckBox = new QCheckBox("Show Clipping Box Outline"); QObject::connect(m_displayClippingBoxCheckBox, SIGNAL(clicked(bool)), this, SLOT(clippingValueChanged())); /*------------------------------------------------------------------------*/ /* * Layout widgets */ /* * Columns for grid layout */ int column = 0; const int COLUMN_LABEL = column++; const int COLUMN_X = column++; const int COLUMN_Y = column++; const int COLUMN_Z = column++; QWidget* gridWidget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(gridWidget); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 4, 4); int row = 0; gridLayout->addWidget(xColumnLabel, row, COLUMN_X, Qt::AlignHCenter); gridLayout->addWidget(yColumnLabel, row, COLUMN_Y, Qt::AlignHCenter); gridLayout->addWidget(zColumnLabel, row, COLUMN_Z, Qt::AlignHCenter); row++; gridLayout->addWidget(panLabel, row, COLUMN_LABEL); gridLayout->addWidget(m_xPanDoubleSpinBox, row, COLUMN_X); gridLayout->addWidget(m_yPanDoubleSpinBox, row, COLUMN_Y); gridLayout->addWidget(m_zPanDoubleSpinBox, row, COLUMN_Z); row++; gridLayout->addWidget(rotateLabel, row, COLUMN_LABEL); gridLayout->addWidget(m_xRotateDoubleSpinBox, row, COLUMN_X); gridLayout->addWidget(m_yRotateDoubleSpinBox, row, COLUMN_Y); gridLayout->addWidget(m_zRotateDoubleSpinBox, row, COLUMN_Z); row++; gridLayout->addWidget(thicknessLabel, row, COLUMN_LABEL); gridLayout->addWidget(m_xThicknessDoubleSpinBox, row, COLUMN_X); gridLayout->addWidget(m_yThicknessDoubleSpinBox, row, COLUMN_Y); gridLayout->addWidget(m_zThicknessDoubleSpinBox, row, COLUMN_Z); /*------------------------------------------------------------------------*/ /* * Finish up */ QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 4); layout->addLayout(windowLayout); layout->addWidget(m_displayClippingBoxCheckBox); layout->addWidget(WuQtUtilities::createHorizontalLineWidget()); layout->addWidget(gridWidget); widget->setFixedSize(widget->sizeHint()); /* * Remove apply button by using an empty name */ setApplyButtonText(""); m_resetPushButton = addUserPushButton("Reset", QDialogButtonBox::NoRole); setCentralWidget(widget, WuQDialog::SCROLL_AREA_NEVER); /* * No auto default button processing (Qt highlights button) */ disableAutoDefaultForAllPushButtons(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); m_blockDialogUpdate = false; } /** * Destructor. */ ClippingPlanesDialog::~ClippingPlanesDialog() { EventManager::get()->removeAllEventsFromListener(this); } /** * Called when a user (added) push button is clicked. * * @param userPushButton * Button that was clicked. */ WuQDialogNonModal::DialogUserButtonResult ClippingPlanesDialog::userButtonPressed(QPushButton* userPushButton) { if (userPushButton == m_resetPushButton) { BrainBrowserWindow* bbw = m_browserWindowComboBox->getSelectedBrowserWindow(); if (bbw != NULL) { BrowserTabContent* btc = bbw->getBrowserTabContent(); if (btc != NULL) { btc->resetClippingPlaneTransformation(); updateContent(btc->getTabNumber()); updateGraphicsWindow(); } } } else { CaretAssert(0); } return WuQDialogNonModal::RESULT_NONE; } /** * Called when window number combo box value changed. */ void ClippingPlanesDialog::browserWindowComboBoxValueChanged(BrainBrowserWindow* browserWindow) { int32_t windowIndex = -1; if (browserWindow != NULL) { windowIndex = browserWindow->getBrowserWindowIndex(); } updateContent(windowIndex); } /** * Called when a clipping value is changed. */ void ClippingPlanesDialog::clippingValueChanged() { const float panning[3] = { (float)m_xPanDoubleSpinBox->value(), (float)m_yPanDoubleSpinBox->value(), (float)m_zPanDoubleSpinBox->value() }; const float rotation[3] = { (float)m_xRotateDoubleSpinBox->value(), (float)m_yRotateDoubleSpinBox->value(), (float)m_zRotateDoubleSpinBox->value() }; const float thickness[3] ={ (float)m_xThicknessDoubleSpinBox->value(), (float)m_yThicknessDoubleSpinBox->value(), (float)m_zThicknessDoubleSpinBox->value() }; /* * Update, set, and validate selected browser window */ BrainBrowserWindow* bbw = m_browserWindowComboBox->getSelectedBrowserWindow(); if (bbw != NULL) { BrowserTabContent* btc = bbw->getBrowserTabContent(); if (btc != NULL) { btc->setClippingPlaneTransformation(panning, rotation, thickness, m_displayClippingBoxCheckBox->isChecked()); updateGraphicsWindow(); } } } /** * Update the selected graphics window. */ void ClippingPlanesDialog::updateGraphicsWindow() { EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** * Gets called when the dialog gains focus. */ void ClippingPlanesDialog::focusGained() { updateDialog(); } /** * Update the dialog. */ void ClippingPlanesDialog::updateDialog() { m_browserWindowComboBox->updateComboBox(); updateContent(m_browserWindowComboBox->getSelectedBrowserWindowIndex()); } /** * Update the content in the dialog * @param browserWindowIndexIn * Index of the browser window. */ void ClippingPlanesDialog::updateContent(const int32_t browserWindowIndexIn) { /* * May get updates when graphics are redrawn by this dialog * and not doing this could result in infinite loop */ if (m_blockDialogUpdate) { return; } /* * Update, set, and validate selected browser window */ m_browserWindowComboBox->updateComboBox(); m_browserWindowComboBox->setBrowserWindowByIndex(browserWindowIndexIn); const int32_t browserWindowIndex = m_browserWindowComboBox->getSelectedBrowserWindowIndex(); BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(browserWindowIndex); if (bbw != NULL) { BrowserTabContent* btc = bbw->getBrowserTabContent(); if (btc != NULL) { m_clippingWidgetGroup->blockAllSignals(true); float panning[3]; float rotation[3]; float thickness[3]; bool displayClippingBox; btc->getClippingPlaneTransformation(panning, rotation, thickness, displayClippingBox); m_xPanDoubleSpinBox->setValue(panning[0]); m_yPanDoubleSpinBox->setValue(panning[1]); m_zPanDoubleSpinBox->setValue(panning[2]); m_xRotateDoubleSpinBox->setValue(rotation[0]); m_yRotateDoubleSpinBox->setValue(rotation[1]); m_zRotateDoubleSpinBox->setValue(rotation[2]); m_xThicknessDoubleSpinBox->setValue(thickness[0]); m_yThicknessDoubleSpinBox->setValue(thickness[1]); m_zThicknessDoubleSpinBox->setValue(thickness[2]); m_displayClippingBoxCheckBox->setChecked(displayClippingBox); m_clippingWidgetGroup->blockAllSignals(false); } } } /** * Receive events from the event manager. * * @param event * Event sent by event manager. */ void ClippingPlanesDialog::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* updateEvent = dynamic_cast(event); CaretAssert(updateEvent); updateEvent->setEventProcessed(); updateDialog(); } } connectome-workbench-1.4.2/src/GuiQt/ClippingPlanesDialog.h000066400000000000000000000060711360521144700236600ustar00rootroot00000000000000#ifndef __CLIPPING_PLANES_DIALOG_H__ #define __CLIPPING_PLANES_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WuQDialogNonModal.h" #include "EventListenerInterface.h" class QCheckBox; class QDoubleSpinBox; class QPushButton; namespace caret { class BrainBrowserWindow; class BrainBrowserWindowComboBox; class WuQWidgetObjectGroup; class ClippingPlanesDialog : public WuQDialogNonModal, public EventListenerInterface { Q_OBJECT public: ClippingPlanesDialog(QWidget* parent); virtual ~ClippingPlanesDialog(); void updateDialog(); void updateContent(const int32_t browserWindowIndex); // ADD_NEW_METHODS_HERE virtual void receiveEvent(Event* event); private slots: void browserWindowComboBoxValueChanged(BrainBrowserWindow* browserWindow); void clippingValueChanged(); protected: void focusGained(); virtual DialogUserButtonResult userButtonPressed(QPushButton* userPushButton); private: void updateGraphicsWindow(); ClippingPlanesDialog(const ClippingPlanesDialog&); ClippingPlanesDialog& operator=(const ClippingPlanesDialog&); QPushButton* m_resetPushButton; BrainBrowserWindowComboBox* m_browserWindowComboBox; WuQWidgetObjectGroup* m_clippingWidgetGroup; QDoubleSpinBox* m_xPanDoubleSpinBox; QDoubleSpinBox* m_yPanDoubleSpinBox; QDoubleSpinBox* m_zPanDoubleSpinBox; QDoubleSpinBox* m_xRotateDoubleSpinBox; QDoubleSpinBox* m_yRotateDoubleSpinBox; QDoubleSpinBox* m_zRotateDoubleSpinBox; QDoubleSpinBox* m_xThicknessDoubleSpinBox; QDoubleSpinBox* m_yThicknessDoubleSpinBox; QDoubleSpinBox* m_zThicknessDoubleSpinBox; QCheckBox* m_displayClippingBoxCheckBox; bool m_blockDialogUpdate; // ADD_NEW_MEMBERS_HERE }; #ifdef __CLIPPING_PLANES_DIALOG_DECLARE__ // #endif // __CLIPPING_PLANES_DIALOG_DECLARE__ } // namespace #endif //__CLIPPING_PLANES_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/ColorEditorWidget.cxx000066400000000000000000000233601360521144700235740ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #define __COLOR_EDITOR_WIDGET_DECLARE__ #include "ColorEditorWidget.h" #undef __COLOR_EDITOR_WIDGET_DECLARE__ #include "WuQFactory.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::ColorEditorWidget * \brief Widget for editing RGBA colors. * \ingroup GuiQt */ /** * Constructor. */ ColorEditorWidget::ColorEditorWidget(const bool alphaControlEnabled, QWidget* parent) : QWidget(parent) { this->colorSwatchWidget = new QWidget(); this->colorSwatchWidget->setFixedHeight(25); QLabel* redLabel = new QLabel("Red"); this->redSpinBox = WuQFactory::newSpinBox(); this->redSpinBox->setRange(0, 255); this->redSpinBox->setSingleStep(1); QObject::connect(this->redSpinBox, SIGNAL(valueChanged(int)), this, SLOT(redValueChanged(int))); this->redSlider = new QSlider(); this->redSlider->setRange(0, 255); this->redSlider->setOrientation(Qt::Horizontal); QObject::connect(this->redSlider, SIGNAL(valueChanged(int)), this, SLOT(redValueChanged(int))); QLabel* greenLabel = new QLabel("Green"); this->greenSpinBox = WuQFactory::newSpinBox(); this->greenSpinBox->setRange(0, 255); this->greenSpinBox->setSingleStep(1); QObject::connect(this->greenSpinBox, SIGNAL(valueChanged(int)), this, SLOT(greenValueChanged(int))); this->greenSlider = new QSlider(); this->greenSlider->setRange(0, 255); this->greenSlider->setOrientation(Qt::Horizontal); QObject::connect(this->greenSlider, SIGNAL(valueChanged(int)), this, SLOT(greenValueChanged(int))); QLabel* blueLabel = new QLabel("Blue"); this->blueSpinBox = WuQFactory::newSpinBox(); this->blueSpinBox->setRange(0, 255); this->blueSpinBox->setSingleStep(1); QObject::connect(this->blueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(blueValueChanged(int))); this->blueSlider = new QSlider(); this->blueSlider->setRange(0, 255); this->blueSlider->setOrientation(Qt::Horizontal); QObject::connect(this->blueSlider, SIGNAL(valueChanged(int)), this, SLOT(blueValueChanged(int))); QLabel* alphaLabel = NULL; this->alphaSpinBox = NULL; if (alphaControlEnabled) { alphaLabel = new QLabel("Alpha"); this->alphaSpinBox = WuQFactory::newSpinBox(); this->alphaSpinBox->setRange(0, 255); this->alphaSpinBox->setSingleStep(1); QObject::connect(this->alphaSpinBox, SIGNAL(valueChanged(int)), this, SLOT(alphaValueChanged(int))); this->alphaSlider = new QSlider(); this->alphaSlider->setRange(0, 255); this->alphaSlider->setOrientation(Qt::Horizontal); QObject::connect(this->alphaSlider, SIGNAL(valueChanged(int)), this, SLOT(alphaValueChanged(int))); } int columnCount = 0; const int COLUMN_NAME = columnCount++; const int COLUMN_SLIDER = columnCount++; const int COLUMN_SPINBOX = columnCount++; const int COLUMN_LAST = columnCount; int row = 0; QGridLayout* gridLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 2); gridLayout->addWidget(this->colorSwatchWidget, row, 0, 1, COLUMN_LAST); row++; gridLayout->addWidget(redLabel, row, COLUMN_NAME); gridLayout->addWidget(this->redSlider, row, COLUMN_SLIDER); gridLayout->addWidget(this->redSpinBox, row, COLUMN_SPINBOX); row++; gridLayout->addWidget(greenLabel, row, COLUMN_NAME); gridLayout->addWidget(this->greenSlider, row, COLUMN_SLIDER); gridLayout->addWidget(this->greenSpinBox, row, COLUMN_SPINBOX); row++; gridLayout->addWidget(blueLabel, row, COLUMN_NAME); gridLayout->addWidget(this->blueSlider, row, COLUMN_SLIDER); gridLayout->addWidget(this->blueSpinBox, row, COLUMN_SPINBOX); row++; if (this->alphaSpinBox != NULL) { gridLayout->addWidget(alphaLabel, row, COLUMN_NAME); gridLayout->addWidget(this->alphaSlider, row, COLUMN_SLIDER); gridLayout->addWidget(this->alphaSpinBox, row, COLUMN_SPINBOX); row++; } this->controlsWidgetGroup = new WuQWidgetObjectGroup(this); this->controlsWidgetGroup->add(this->redSpinBox); this->controlsWidgetGroup->add(this->redSlider); this->controlsWidgetGroup->add(this->greenSpinBox); this->controlsWidgetGroup->add(this->greenSlider); this->controlsWidgetGroup->add(this->blueSpinBox); this->controlsWidgetGroup->add(this->blueSlider); if (this->alphaSpinBox != NULL) { this->controlsWidgetGroup->add(this->alphaSpinBox); this->controlsWidgetGroup->add(this->alphaSlider); } } /** * Destructor. */ ColorEditorWidget::~ColorEditorWidget() { } /** * Set the color in the control with RGBA * values ranging 0.0 to 1.0. * @param rgba * Input RGBA values. */ void ColorEditorWidget::setColor(const float rgba[4]) { const int32_t intRGBA[4] = { std::min(static_cast(rgba[0] * 255.0), 255), std::min(static_cast(rgba[1] * 255.0), 255), std::min(static_cast(rgba[2] * 255.0), 255), std::min(static_cast(rgba[3] * 255.0), 255) }; this->setColor(intRGBA); } /** * Get the color in the control with RGBA * values ranging 0.0 to 1.0. * @param rgba * Output RGBA values. */ void ColorEditorWidget::getColor(float rgba[4]) const { int intRGBA[4]; this->getColor(intRGBA); rgba[0] = intRGBA[0] / 255.0; rgba[1] = intRGBA[1] / 255.0; rgba[2] = intRGBA[2] / 255.0; rgba[3] = intRGBA[3] / 255.0; } /** * Set the color in the control with RGBA * values ranging 0 to 255. * @param rgba * Input RGBA values. */ void ColorEditorWidget::setColor(const int rgba[4]) { this->controlsWidgetGroup->blockAllSignals(true); this->redSpinBox->setValue(rgba[0]); this->redSlider->setValue(rgba[0]); this->greenSpinBox->setValue(rgba[1]); this->greenSlider->setValue(rgba[1]); this->blueSpinBox->setValue(rgba[2]); this->blueSlider->setValue(rgba[2]); if (this->alphaSpinBox != NULL) { this->alphaSpinBox->setValue(rgba[3]); this->alphaSlider->setValue(rgba[3]); } this->updateColorSwatch(); this->controlsWidgetGroup->blockAllSignals(false); } /** * Get the color in the control with RGBA * values ranging 0 to 255 * @param rgba * Output RGBA values. */ void ColorEditorWidget::getColor(int rgba[4]) const { rgba[0] = this->redSpinBox->value(); rgba[1] = this->greenSpinBox->value(); rgba[2] = this->blueSpinBox->value(); if (this->alphaSpinBox != NULL) { rgba[3] = this->alphaSpinBox->value(); } else { rgba[3] = 255; } } /** * Called when a red component value is changed. */ void ColorEditorWidget::redValueChanged(int value) { this->controlsWidgetGroup->blockAllSignals(true); this->redSlider->setValue(value); this->redSpinBox->setValue(value); this->emitColorChangedSignal(); this->controlsWidgetGroup->blockAllSignals(false); } /** * Called when a green component value is changed. */ void ColorEditorWidget::greenValueChanged(int value) { this->controlsWidgetGroup->blockAllSignals(true); this->greenSlider->setValue(value); this->greenSpinBox->setValue(value); this->emitColorChangedSignal(); this->controlsWidgetGroup->blockAllSignals(false); } /** * Called when a blue component value is changed. */ void ColorEditorWidget::blueValueChanged(int value) { this->controlsWidgetGroup->blockAllSignals(true); this->blueSlider->setValue(value); this->blueSpinBox->setValue(value); this->emitColorChangedSignal(); this->controlsWidgetGroup->blockAllSignals(false); } /** * Called when a alpha component value is changed. */ void ColorEditorWidget::alphaValueChanged(int value) { this->controlsWidgetGroup->blockAllSignals(true); this->alphaSlider->setValue(value); this->alphaSpinBox->setValue(value); this->emitColorChangedSignal(); this->controlsWidgetGroup->blockAllSignals(false); } void ColorEditorWidget::updateColorSwatch() { int rgb[4]; this->getColor(rgb); QPalette pal; pal.setColor(QPalette::Window, QColor(rgb[0], rgb[1], rgb[2])); this->colorSwatchWidget->setAutoFillBackground(true); this->colorSwatchWidget->setBackgroundRole(QPalette::Window); this->colorSwatchWidget->setPalette(pal); } /** * Call to emit the color changed signals. */ void ColorEditorWidget::emitColorChangedSignal() { this->updateColorSwatch(); float rgba[4]; this->getColor(rgba); emit colorChanged(rgba); int intRgba[4]; this->getColor(intRgba); emit colorChanged(intRgba); } connectome-workbench-1.4.2/src/GuiQt/ColorEditorWidget.h000066400000000000000000000050031360521144700232130ustar00rootroot00000000000000#ifndef __COLOR_EDITOR_WIDGET__H_ #define __COLOR_EDITOR_WIDGET__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include class QSlider; class QSpinBox; namespace caret { class WuQWidgetObjectGroup; class ColorEditorWidget : public QWidget { Q_OBJECT public: ColorEditorWidget(const bool alphaControlEnabled = false, QWidget* parent = 0); virtual ~ColorEditorWidget(); void setColor(const float rgba[4]); void getColor(float rgba[4]) const; void setColor(const int rgba[4]); void getColor(int rgba[4]) const; signals: void colorChanged(const float*); void colorChanged(const int*); public slots: void redValueChanged(int); void blueValueChanged(int); void greenValueChanged(int); void alphaValueChanged(int); void emitColorChangedSignal(); private: ColorEditorWidget(const ColorEditorWidget&); ColorEditorWidget& operator=(const ColorEditorWidget&); private: void updateColorSwatch(); WuQWidgetObjectGroup* controlsWidgetGroup; QWidget* colorSwatchWidget; QSpinBox* redSpinBox; QSpinBox* greenSpinBox; QSpinBox* blueSpinBox; QSpinBox* alphaSpinBox; QSlider* redSlider; QSlider* greenSlider; QSlider* blueSlider; QSlider* alphaSlider; }; #ifdef __COLOR_EDITOR_WIDGET_DECLARE__ // #endif // __COLOR_EDITOR_WIDGET_DECLARE__ } // namespace #endif //__COLOR_EDITOR_WIDGET__H_ connectome-workbench-1.4.2/src/GuiQt/CopyPaletteColorMappingToFilesDialog.cxx000066400000000000000000000237061360521144700273610ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __COPY_PALETTE_COLOR_MAPPING_TO_FILES_DIALOG_DECLARE__ #include "CopyPaletteColorMappingToFilesDialog.h" #undef __COPY_PALETTE_COLOR_MAPPING_TO_FILES_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include "Brain.h" #include "CaretAssert.h" #include "CaretMappableDataFile.h" #include "CursorDisplayScoped.h" #include "EventCaretMappableDataFilesGet.h" #include "EventManager.h" #include "GuiManager.h" #include "WuQMessageBox.h" using namespace caret; /** * \class caret::CopyPaletteColorMappingToFilesDialog * \brief Dialog for copying palette color mapping to other files * \ingroup GuiQt */ /** * Constructor. * * @param allPaletteMapFiles * All palette mappable data files. * @param selectedMapFile * Map file that contains palette being copied * @param selectedPaletteColorMapping * Palette color mapping that is being copied * @param parent * Parent widget for this dialog. * */ CopyPaletteColorMappingToFilesDialog::CopyPaletteColorMappingToFilesDialog(const std::vector& allPaletteMapFiles, CaretMappableDataFile* selectedMapFile, const PaletteColorMapping* selectedPaletteColorMapping, QWidget* parent) : WuQDialogModal("Copy Palette Color Mapping", parent), m_selectedMapFile(selectedMapFile), m_selectedPaletteColorMapping(selectedPaletteColorMapping) { CaretAssert(m_selectedMapFile); CaretAssert(m_selectedPaletteColorMapping); for (const auto mapFile : allPaletteMapFiles) { CaretAssert(mapFile); QCheckBox* checkBox = new QCheckBox(mapFile->getFileNameNoPath()); if (mapFile == selectedMapFile) { checkBox->setStyleSheet("font : bold"); } m_fileCheckBoxes.push_back(std::make_pair(checkBox, mapFile)); if (s_previousCheckedFiles.find(mapFile) != s_previousCheckedFiles.end()) { checkBox->setChecked(true); } else { checkBox->setChecked(false); } } QToolButton* allOnToolButton = new QToolButton(); allOnToolButton->setText("All On"); QObject::connect(allOnToolButton, &QToolButton::clicked, this, &CopyPaletteColorMappingToFilesDialog::allCheckBoxesOnClicked); QToolButton* allOffToolButton = new QToolButton(); allOffToolButton->setText("All Off"); QObject::connect(allOffToolButton, &QToolButton::clicked, this, &CopyPaletteColorMappingToFilesDialog::allCheckBoxesOffClicked); QHBoxLayout* toolButtonLayout = new QHBoxLayout(); toolButtonLayout->addWidget(allOnToolButton); toolButtonLayout->addWidget(allOffToolButton); toolButtonLayout->addStretch(); QGridLayout* checkBoxLayout = new QGridLayout(); checkBoxLayout->setColumnMinimumWidth(0, 10); AString lastFileTypeName; int32_t row = checkBoxLayout->rowCount(); for (auto checkFile : m_fileCheckBoxes) { const AString fileTypeName = DataFileTypeEnum::toShortGuiName(checkFile.second->getDataFileType()); if (fileTypeName != lastFileTypeName) { checkBoxLayout->addWidget(new QLabel(fileTypeName), row, 0, 1, 2); ++row; } lastFileTypeName = fileTypeName; checkBoxLayout->addWidget(checkFile.first, row, 1); ++row; } QWidget* widget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(widget); layout->addLayout(toolButtonLayout); layout->addLayout(checkBoxLayout); setCentralWidget(widget, SCROLL_AREA_AS_NEEDED); } /** * Destructor. */ CopyPaletteColorMappingToFilesDialog::~CopyPaletteColorMappingToFilesDialog() { } /** * Called when the OK button is clicked. */ void CopyPaletteColorMappingToFilesDialog::okButtonClicked() { { /* * Note: Cursor MUST go out of scope (be removed) * before calling parent's okButtonClicked() */ CursorDisplayScoped cursor; cursor.showWaitCursor(); s_previousCheckedFiles.clear(); int32_t checkedCount = 0; bool sourceFileFlag = false; for (auto checkFile : m_fileCheckBoxes) { QCheckBox* checkBox = checkFile.first; CaretAssert(checkBox); CaretMappableDataFile* mapFile = checkFile.second; CaretAssert(mapFile); if (checkBox->isChecked()) { if (mapFile != m_selectedMapFile) { ++checkedCount; mapFile->setPaletteNormalizationMode(m_selectedMapFile->getPaletteNormalizationMode()); const int32_t numMaps = mapFile->getNumberOfMaps(); for (int32_t iMap = 0; iMap < numMaps; iMap++) { PaletteColorMapping* pcm = mapFile->getMapPaletteColorMapping(iMap); pcm->copy(*m_selectedPaletteColorMapping, false); } mapFile->updateScalarColoringForAllMaps(); } else { sourceFileFlag = true; } s_previousCheckedFiles.insert(mapFile); } } if (checkedCount <= 0) { cursor.restoreCursor(); if (sourceFileFlag) { WuQMessageBox::errorOk(this, "The selected file is the 'copy from' file. Select files for 'copying to'"); } else { WuQMessageBox::errorOk(this, "No files are selected for palette copying."); } return; } } WuQDialogModal::okButtonClicked(); } /** * Called when 'All On' checkboxes button is clicked. */ void CopyPaletteColorMappingToFilesDialog::allCheckBoxesOnClicked() { for (auto checkFile : m_fileCheckBoxes) { checkFile.first->setChecked(true); } } /** * Called when 'All Off' checkboxes button is clicked. */ void CopyPaletteColorMappingToFilesDialog::allCheckBoxesOffClicked() { for (auto checkFile : m_fileCheckBoxes) { checkFile.first->setChecked(false); } } /** * Run the dialog. * * @param selectedMapFile * Map file that contains palette being copied * @param selectedPaletteColorMapping * Palette color mapping that is being copied * @param parent * Parent widget for this dialog. * @param errorMessageOut * If not empty, there was an error * @return * True if the user pressed OK and palettes were copied. * False if user pressed Cancel or if there was an error (errorMessageOut * will contain description of the error). */ bool CopyPaletteColorMappingToFilesDialog::run(CaretMappableDataFile* selectedMapFile, const PaletteColorMapping* selectedPaletteColorMapping, QWidget* parent, AString& errorMessageOut) { errorMessageOut.clear(); EventCaretMappableDataFilesGet mapFilesGet; EventManager::get()->sendEvent(mapFilesGet.getPointer()); std::vector allMapFiles; mapFilesGet.getAllFiles(allMapFiles); std::vector paletteMappedFiles; for (auto mapFile: allMapFiles) { if (mapFile->isMappedWithPalette()) { paletteMappedFiles.push_back(mapFile); } } allMapFiles.clear(); /* * Sort by Type and Filename */ std::sort(paletteMappedFiles.begin(), paletteMappedFiles.end(), [](CaretMappableDataFile* m1, CaretMappableDataFile* m2) { if (m1->getDataFileType() == m2->getDataFileType()) { return (m1->getFileNameNoPath().toLower() < m2->getFileNameNoPath().toLower()); } return (DataFileTypeEnum::toShortGuiName(m1->getDataFileType()) < DataFileTypeEnum::toShortGuiName(m2->getDataFileType())); } ); bool noFilesFlag = false; if (paletteMappedFiles.empty()) { noFilesFlag = true; } else if (paletteMappedFiles.size() == 1) { CaretAssert(paletteMappedFiles[0] == selectedMapFile); noFilesFlag = true; } if (noFilesFlag) { errorMessageOut = "There are no other files that accept copying of palette color mapping."; return false; } CopyPaletteColorMappingToFilesDialog dialog(paletteMappedFiles, selectedMapFile, selectedPaletteColorMapping, parent); if (dialog.exec() == CopyPaletteColorMappingToFilesDialog::Accepted) { return true; } return false; } connectome-workbench-1.4.2/src/GuiQt/CopyPaletteColorMappingToFilesDialog.h000066400000000000000000000056631360521144700270100ustar00rootroot00000000000000#ifndef __COPY_PALETTE_COLOR_MAPPING_TO_FILES_DIALOG_H__ #define __COPY_PALETTE_COLOR_MAPPING_TO_FILES_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "WuQDialogModal.h" class QCheckBox; namespace caret { class CaretMappableDataFile; class PaletteColorMapping; class CopyPaletteColorMappingToFilesDialog : public WuQDialogModal { Q_OBJECT public: static bool run(CaretMappableDataFile* selectedMapFile, const PaletteColorMapping* selectedPaletteColorMapping, QWidget* parent, AString& errorMessageOut); virtual ~CopyPaletteColorMappingToFilesDialog(); protected: virtual void okButtonClicked() override; // ADD_NEW_METHODS_HERE private slots: void allCheckBoxesOnClicked(); void allCheckBoxesOffClicked(); private: CopyPaletteColorMappingToFilesDialog(const std::vector& allPaletteMapFiles, CaretMappableDataFile* selectedMapFile, const PaletteColorMapping* selectedPaletteColorMapping, QWidget* parent); CopyPaletteColorMappingToFilesDialog(const CopyPaletteColorMappingToFilesDialog&); CopyPaletteColorMappingToFilesDialog& operator=(const CopyPaletteColorMappingToFilesDialog&); const CaretMappableDataFile* m_selectedMapFile; const PaletteColorMapping* m_selectedPaletteColorMapping; std::vector> m_fileCheckBoxes; static std::set s_previousCheckedFiles; // ADD_NEW_MEMBERS_HERE }; #ifdef __COPY_PALETTE_COLOR_MAPPING_TO_FILES_DIALOG_DECLARE__ std::set CopyPaletteColorMappingToFilesDialog::s_previousCheckedFiles; #endif // __COPY_PALETTE_COLOR_MAPPING_TO_FILES_DIALOG_DECLARE__ } // namespace #endif //__COPY_PALETTE_COLOR_MAPPING_TO_FILES_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/CursorDisplayScoped.cxx000066400000000000000000000043411360521144700241420ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CURSOR_DISPLAY_SCOPED_DECLARE__ #include "CursorDisplayScoped.h" #undef __CURSOR_DISPLAY_SCOPED_DECLARE__ #include "CursorManager.h" #include "GuiManager.h" using namespace caret; /** * \class caret::CursorDisplayScoped * \brief Displays a override cursor * \ingroup GuiQt * * When one of the 'show' methods is called, * displays a cursor that overrides all other cursors in the * application until an instance of this goes out of scope or the * method restoreCursor() is called. */ /** * Constructor that displays a wait cursor. * */ CursorDisplayScoped::CursorDisplayScoped() : CaretObject() { this->isCursorActive = false; } /** * Destructor. */ CursorDisplayScoped::~CursorDisplayScoped() { this->restoreCursor(); } /** * Display the given cursor. * * @param cursor * Cursor that is displayed. */ void CursorDisplayScoped::showCursor(const QCursor& cursor) { this->isCursorActive = true; QApplication::setOverrideCursor(cursor); QApplication::processEvents(); } /** * Display the wait cursor. */ void CursorDisplayScoped::showWaitCursor() { this->showCursor(Qt::WaitCursor); } /** * Restore the default cursor. */ void CursorDisplayScoped::restoreCursor() { if (this->isCursorActive) { QApplication::restoreOverrideCursor(); QApplication::processEvents(); this->isCursorActive = false; } } connectome-workbench-1.4.2/src/GuiQt/CursorDisplayScoped.h000066400000000000000000000032061360521144700235660ustar00rootroot00000000000000#ifndef __CURSOR_DISPLAY_SCOPED_H_ #define __CURSOR_DISPLAY_SCOPED_H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" class QCursor; namespace caret { class CursorDisplayScoped : public CaretObject { public: CursorDisplayScoped(); void showWaitCursor(); void showCursor(const QCursor& cursor); void restoreCursor(); virtual ~CursorDisplayScoped(); private: CursorDisplayScoped(const CursorDisplayScoped&); CursorDisplayScoped& operator=(const CursorDisplayScoped&); bool isCursorActive; private: }; #ifdef __CURSOR_DISPLAY_SCOPED_DECLARE__ // #endif // __CURSOR_DISPLAY_SCOPED_DECLARE__ } // namespace #endif //__CURSOR_DISPLAY_SCOPED__H_ connectome-workbench-1.4.2/src/GuiQt/CursorEnum.cxx000066400000000000000000000300771360521144700223100ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CURSOR_ENUM_DECLARE__ #include "CursorEnum.h" #undef __CURSOR_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::CursorEnum * \brief Enumerated type for Cursors (both Qt and custom) * \ingroup GuiQt * * An enumerated type for cursors. Some cursors are * from Qt and others are created using bitmaps. */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ CursorEnum::CursorEnum(const Enum enumValue, const AString& name, const AString& guiName, const Qt::CursorShape qtCursorShape) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; this->qtCursorShape = qtCursorShape; } /** * Destructor. */ CursorEnum::~CursorEnum() { } /** * Initialize the enumerated metadata. */ void CursorEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(CursorEnum(CURSOR_DEFAULT, "CURSOR_DEFAULT", "Default Cursor", Qt::ArrowCursor)); enumData.push_back(CursorEnum(CURSOR_ARROW, "CURSOR_ARROW", "Arrow Cursor", Qt::ArrowCursor)); enumData.push_back(CursorEnum(CURSOR_CLOSED_HAND, "CURSOR_CLOSED_HAND", "Closed Hand Cursor", Qt::ClosedHandCursor)); enumData.push_back(CursorEnum(CURSOR_CROSS, "CURSOR_CROSS", "Cross Cursor", Qt::CrossCursor)); enumData.push_back(CursorEnum(CURSOR_DRAWING_PEN, "CURSOR_DRAWING_PEN", "Drawing Pen Cursor", Qt::ArrowCursor)); enumData.push_back(CursorEnum(CURSOR_FOUR_ARROWS, "CURSOR_FOUR_ARROWS", "Four Arrows Cursor", Qt::SizeAllCursor)); enumData.push_back(CursorEnum(CURSOR_POINTING_HAND, "CURSOR_POINTING_HAND", "Pointing Hand Cursor", Qt::PointingHandCursor)); enumData.push_back(CursorEnum(CURSOR_RESIZE_BOTTOM_LEFT_TOP_RIGHT, "CURSOR_RESIZE_BOTTOM_LEFT_TOP_RIGHT", "Resize arrows pointing bottom left and top right Cursor", Qt::SizeBDiagCursor)); enumData.push_back(CursorEnum(CURSOR_RESIZE_BOTTOM_RIGHT_TOP_LEFT, "CURSOR_RESIZE_BOTTOM_RIGHT_TOP_LEFT", "Resize arrows pointing top left and bottom right Cursor", Qt::SizeFDiagCursor)); enumData.push_back(CursorEnum(CURSOR_RESIZE_HORIZONTAL, "CURSOR_RESIZE_HORIZONTAL", "Resize Horizontal Cursor", Qt::SizeHorCursor)); enumData.push_back(CursorEnum(CURSOR_RESIZE_VERTICAL, "CURSOR_RESIZE_VERTICAL", "Resize Vertical Cursor", Qt::SizeVerCursor)); enumData.push_back(CursorEnum(CURSOR_ROTATION, "CURSOR_ROTATION", "Rotation Cursor", Qt::ArrowCursor)); enumData.push_back(CursorEnum(CURSOR_WAIT, "CURSOR_WAIT", "Wait Cursor", Qt::WaitCursor)); enumData.push_back(CursorEnum(CURSOR_WHATS_THIS, "CURSOR_WHATS_THIS", "What's this Cursor", Qt::WhatsThisCursor)); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const CursorEnum* CursorEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const CursorEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get the Qt Cursor corresponding to the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ Qt::CursorShape CursorEnum::toQtCursorShape(Enum enumValue) { if (initializedFlag == false) initialize(); const CursorEnum* enumInstance = findData(enumValue); return enumInstance->qtCursorShape; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString CursorEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const CursorEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ CursorEnum::Enum CursorEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = CURSOR_DEFAULT; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const CursorEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type CursorEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString CursorEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const CursorEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ CursorEnum::Enum CursorEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = CURSOR_DEFAULT; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const CursorEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type CursorEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t CursorEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const CursorEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ CursorEnum::Enum CursorEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = CURSOR_DEFAULT; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const CursorEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type CursorEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void CursorEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void CursorEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(CursorEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void CursorEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(CursorEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/GuiQt/CursorEnum.h000066400000000000000000000101731360521144700217300ustar00rootroot00000000000000#ifndef __CURSOR_ENUM__H_ #define __CURSOR_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class CursorEnum { public: /** * Enumerated values. */ enum Enum { /** The default cursor which is usually the parent widget's cursor */ CURSOR_DEFAULT, /** Arrow (typically same as CURSOR_DEFAULT but overrides cursor provided by parent widget, Qt::ArrowCursor) */ CURSOR_ARROW, /** Closed Hand */ CURSOR_CLOSED_HAND, /** Cross (plus symbol) */ CURSOR_CROSS, /** Drawing Pen */ CURSOR_DRAWING_PEN, /** Size All "four arrows", Qt::SizeAllCursor */ CURSOR_FOUR_ARROWS, /** Pointing hand, Qt::PointingHandCursor*/ CURSOR_POINTING_HAND, /** Resize arrows pointing bottom left and top right */ CURSOR_RESIZE_BOTTOM_LEFT_TOP_RIGHT, /** Resize arrows pointing top left and bottom right */ CURSOR_RESIZE_BOTTOM_RIGHT_TOP_LEFT, /** Resize Horizontal */ CURSOR_RESIZE_HORIZONTAL, /** Resize Vertical */ CURSOR_RESIZE_VERTICAL, /** Rotation Cursor */ CURSOR_ROTATION, /** Wait, Qt::WaitCursor*/ CURSOR_WAIT, /** What's this? Arrow with question mark */ CURSOR_WHATS_THIS }; ~CursorEnum(); static Qt::CursorShape toQtCursorShape(Enum enumValue); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: CursorEnum(const Enum enumValue, const AString& name, const AString& guiName, const Qt::CursorShape qtCursorShape); static const CursorEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; /** The corresponding Qt Cursor Shape */ Qt::CursorShape qtCursorShape; }; #ifdef __CURSOR_ENUM_DECLARE__ std::vector CursorEnum::enumData; bool CursorEnum::initializedFlag = false; int32_t CursorEnum::integerCodeCounter = 0; #endif // __CURSOR_ENUM_DECLARE__ } // namespace #endif //__CURSOR_ENUM__H_ connectome-workbench-1.4.2/src/GuiQt/CursorManager.cxx000066400000000000000000000206621360521144700227550ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #define __CURSOR_MANAGER_DECLARE__ #include "CursorManager.h" #undef __CURSOR_MANAGER_DECLARE__ #include "WuQtUtilities.h" using namespace caret; /** * \class caret::CursorManager * \brief Manages cursors * \ingroup GuiQt * Provides cursors, some predefined by Qt and * others unique to workbench. */ /** * Constructor. */ CursorManager::CursorManager() : CaretObject() { m_fourArrowsCursor = createFourArrowsCursor(); m_penCursor = this->loadCursor(":Cursor/pen_eraser.png", 6, 32 - 7, Qt::UpArrowCursor); m_rotationCursor = createRotationCursor(); } /** * Destructor. */ CursorManager::~CursorManager() { } /** * Set the given cursor for the given widget. * @param widget * Widget that has its cursor set. * @param cursor * Cursor for the widget. */ void CursorManager::setCursorForWidget(QWidget* widget, const CursorEnum::Enum cursor) const { switch (cursor) { case CursorEnum::CURSOR_DEFAULT: widget->unsetCursor(); break; case CursorEnum::CURSOR_DRAWING_PEN: widget->setCursor(m_penCursor); break; case CursorEnum::CURSOR_FOUR_ARROWS: widget->setCursor(m_fourArrowsCursor); break; case CursorEnum::CURSOR_ROTATION: widget->setCursor(m_rotationCursor); break; default: widget->setCursor(CursorEnum::toQtCursorShape(cursor)); break; } } /** * Load an image and create a cursor using the image. * * @param filename * Name of file containing the image. * @param hotSpotX * Hot spot (location in cursor reported to GUI) * @param hotSpotY * Hot spot (location in cursor reported to GUI) * @param cursorShapeIfImageLoadingFails * Cursor shape used if loading the image fails. * @return * Cursor that was created. */ QCursor CursorManager::loadCursor(const QString& filename, const int hotSpotX, const int hotSpotY, const Qt::CursorShape& cursorShapeIfImageLoadingFails) const { QPixmap cursorPixmap; if (WuQtUtilities::loadPixmap(filename, cursorPixmap)) { QCursor cursor(cursorPixmap, hotSpotX, hotSpotY); return cursor; } return QCursor(cursorShapeIfImageLoadingFails); } /** * @return A four-arrows cursor */ QCursor CursorManager::createFourArrowsCursor() { /* * Create image into which to draw */ const int width = 32; const int height = width; QImage image(width, height, QImage::Format_ARGB32); image.fill(Qt::transparent); /* * Create painter with black for filling and white for outline */ QPainter painter(&image); painter.setRenderHint(QPainter::Antialiasing, false); painter.setBackgroundMode(Qt::OpaqueMode); QPen pen = painter.pen(); pen.setColor(Qt::white); pen.setWidth(1); painter.setPen(pen); QBrush brush(QColor(0, 0, 0), Qt::SolidPattern); painter.setBrush(brush); /* * Four arrows symbol is symmetric */ const int middle = width / 2; const int a = 2; const int b = 8; const int c = middle - 6; const int d = middle - 2; const int e = middle; const int f = width - d; const int g = width - c; const int h = width - b; const int i = width - a; /* * Points for polygon filled with black */ QPolygon polygon; polygon.push_back(QPoint(a, e)); polygon.push_back(QPoint(b, g)); polygon.push_back(QPoint(b, f)); polygon.push_back(QPoint(d, f)); polygon.push_back(QPoint(d, h)); polygon.push_back(QPoint(c, h)); polygon.push_back(QPoint(e, i)); polygon.push_back(QPoint(g, h)); polygon.push_back(QPoint(f, h)); polygon.push_back(QPoint(f, f)); polygon.push_back(QPoint(h, f)); polygon.push_back(QPoint(h, g)); polygon.push_back(QPoint(i, e)); polygon.push_back(QPoint(h, c)); polygon.push_back(QPoint(h, d)); polygon.push_back(QPoint(f, d)); polygon.push_back(QPoint(f, b)); polygon.push_back(QPoint(g, b)); polygon.push_back(QPoint(e, a)); polygon.push_back(QPoint(c, b)); polygon.push_back(QPoint(d, b)); polygon.push_back(QPoint(d, d)); polygon.push_back(QPoint(b, d)); polygon.push_back(QPoint(b, c)); /* * Draw filled polygon. * Note that last point is connected to first point by drawPolygon(). */ painter.drawPolygon(polygon); /* * Draw white around arrows. * Note that drawPolyline() DOES NOT connect last point to first point so add first point again at end. * Turn anti-aliasing on for lines */ polygon.push_back(QPoint(a, e)); painter.setRenderHint(QPainter::Antialiasing, false); painter.drawPolyline(polygon); /* * Create the cursor */ QPixmap cursorPixmap = QPixmap::fromImage(image); QCursor cursor(cursorPixmap); return cursor; } /** * @return A rotation cursor */ QCursor CursorManager::createRotationCursor() { /* * Create image into which to draw */ const int width = 32; const int height = width; QImage image(width, height, QImage::Format_ARGB32); image.fill(Qt::transparent); /* * Create painter with black for filling and white for outline */ QPainter painter(&image); painter.setRenderHint(QPainter::Antialiasing, false); painter.setBackgroundMode(Qt::OpaqueMode); QPen pen = painter.pen(); pen.setColor(Qt::white); pen.setWidth(1); painter.setPen(pen); QBrush brush(QColor(0, 0, 0), Qt::SolidPattern); painter.setBrush(brush); /* * points left to right in rotation symbol */ const int a = 2; const int b = 6; const int c = width - 14; const int d = width - 10; const int e = width - 8; const int f = width - 6; const int g = width - 2; /* * Points top to bottom in rotation symbol */ const int h = 2; const int i = 6; const int j = height - 8; const int k = height - 2; /* * Points for polygon filled with black */ QPolygon polygon; polygon.push_back(QPoint(a, k)); polygon.push_back(QPoint(b, k)); polygon.push_back(QPoint(b, i)); polygon.push_back(QPoint(d, i)); polygon.push_back(QPoint(d, j)); polygon.push_back(QPoint(c, j)); polygon.push_back(QPoint(e, k)); polygon.push_back(QPoint(g, j)); polygon.push_back(QPoint(f, j)); polygon.push_back(QPoint(f, h)); polygon.push_back(QPoint(a, h)); /* * Draw filled polygon. * Note that last point is connected to first point by drawPolygon(). */ painter.drawPolygon(polygon); /* * Draw white around arrows. * Note that drawPolyline() DOES NOT connect last point to first point so add first point again at end. * Turn anti-aliasing on for lines */ polygon.push_back(QPoint(a, k)); painter.setRenderHint(QPainter::Antialiasing, false); painter.drawPolyline(polygon); /* * Create the cursor */ QPixmap cursorPixmap = QPixmap::fromImage(image); QCursor cursor(cursorPixmap); return cursor; } connectome-workbench-1.4.2/src/GuiQt/CursorManager.h000066400000000000000000000037711360521144700224040ustar00rootroot00000000000000#ifndef __CURSOR_MANAGER__H_ #define __CURSOR_MANAGER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "CursorEnum.h" class QWidget; namespace caret { class CursorManager : public CaretObject { public: CursorManager(); virtual ~CursorManager(); void setCursorForWidget(QWidget* widget, const CursorEnum::Enum cursor) const; private: CursorManager(const CursorManager&); CursorManager& operator=(const CursorManager&); QCursor loadCursor(const QString& filename, const int hotSpotX, const int hotSpotY, const Qt::CursorShape& cursorShapeIfImageLoadingFails) const; QCursor createFourArrowsCursor(); QCursor createRotationCursor(); QCursor m_penCursor; QCursor m_fourArrowsCursor; QCursor m_rotationCursor; }; #ifdef __CURSOR_MANAGER_DECLARE__ // #endif // __CURSOR_MANAGER_DECLARE__ } // namespace #endif //__CURSOR_MANAGER__H_ connectome-workbench-1.4.2/src/GuiQt/CustomViewDialog.cxx000066400000000000000000001145521360521144700234340ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CUSTOM_VIEW_DIALOG_DECLARE__ #include "CustomViewDialog.h" #undef __CUSTOM_VIEW_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include "BrainBrowserWindow.h" #include "BrainBrowserWindowComboBox.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretPreferences.h" #include "EventBrowserWindowGraphicsRedrawn.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventManager.h" #include "GuiManager.h" #include "Matrix4x4.h" #include "Model.h" #include "ModelTransform.h" #include "SessionManager.h" #include "WuQDataEntryDialog.h" #include "WuQListWidget.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" #include "WuQWidgetObjectGroup.h" using namespace caret; /** * \class caret::CustomViewDialog * \brief Dialog for creation of custom views (orientations). * \ingroup GuiQt */ /** * Constructor. */ CustomViewDialog::CustomViewDialog(QWidget* parent) : WuQDialogNonModal("Custom Orientation", parent) { m_blockDialogUpdate = true; /* * Remove apply button by using an empty name */ setApplyButtonText(""); /* * Create the controls */ QWidget* customViewWidget = createCustomViewWidget(); QWidget* transformWidget = createTransformsWidget(); m_copyWidget = createCopyWidget(); /* * Layout for dialog */ QWidget* widget = new QWidget(); QHBoxLayout* layout = new QHBoxLayout(widget); layout->setSpacing(layout->spacing() / 2); layout->addWidget(transformWidget, 0, Qt::AlignVCenter); layout->addWidget(m_copyWidget, 0, Qt::AlignVCenter); layout->addWidget(customViewWidget, 0, Qt::AlignVCenter); setCentralWidget(widget, WuQDialog::SCROLL_AREA_NEVER); /* * No auto default button processing (Qt highlights button) */ disableAutoDefaultForAllPushButtons(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); m_blockDialogUpdate = false; } /** * Destructor. */ CustomViewDialog::~CustomViewDialog() { EventManager::get()->removeAllEventsFromListener(this); } /** * @return The Custom View widget. */ QWidget* CustomViewDialog::createCustomViewWidget() { /* * View selection list widget */ m_customViewListWidget = new WuQListWidget(); m_customViewListWidget->setFixedHeight(100); m_customViewListWidget->setFixedWidth(140); m_customViewListWidget->setSelectionMode(QListWidget::SingleSelection); QObject::connect(m_customViewListWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(customViewSelected())); QObject::connect(m_customViewListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(customViewSelectedAndApplied())); m_newCustomViewPushButton = new QPushButton("New..."); WuQtUtilities::setWordWrappedToolTip(m_newCustomViewPushButton, "Create a new Custom View by entering its name. The view will use the current transformation values."); QObject::connect(m_newCustomViewPushButton, SIGNAL(clicked()), this, SLOT(newCustomViewPushButtonClicked())); m_deleteCustomViewPushButton = new QPushButton("Delete..."); WuQtUtilities::setWordWrappedToolTip(m_deleteCustomViewPushButton, "Delete the selected Custom View."); QObject::connect(m_deleteCustomViewPushButton, SIGNAL(clicked()), this, SLOT(deleteCustomViewPushButtonClicked())); WuQtUtilities::matchWidgetWidths(m_newCustomViewPushButton, m_deleteCustomViewPushButton); QGroupBox* groupBox = new QGroupBox("Custom Orientation"); QVBoxLayout* layout = new QVBoxLayout(groupBox); WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 2); layout->addWidget(m_customViewListWidget, 100, Qt::AlignHCenter); layout->addWidget(m_newCustomViewPushButton, 0, Qt::AlignHCenter); layout->addWidget(m_deleteCustomViewPushButton, 0, Qt::AlignHCenter); layout->addStretch(); groupBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); return groupBox; } /** * Called when a custom view is selected. */ void CustomViewDialog::customViewSelected() { } /** * Called when a custom view name is double-clicked. */ void CustomViewDialog::customViewSelectedAndApplied() { copyToTransformPushButtonClicked(); } /** * @return Name of selected custom view.. */ AString CustomViewDialog::getSelectedCustomViewName() { AString viewName; QListWidgetItem* lwi = m_customViewListWidget->currentItem(); if (lwi != NULL) { viewName = lwi->text(); } return viewName; } /** * Load content of custom view list widget. * * @param selectedName * If not empty, this name will be selected. */ void CustomViewDialog::loadCustomViewListWidget(const AString& selectedName) { /* * Cannot use getSelectedUserView() since the item returned may be invalid * if items have been removed. */ QString previousViewName = getSelectedCustomViewName(); if (selectedName.isEmpty() == false) { previousViewName = selectedName; } int defaultSelectedIndex = m_customViewListWidget->currentRow(); m_customViewListWidget->clear(); CaretPreferences* prefs = getCaretPreferences(); prefs->readCustomViews(); const std::vector > customViewNamesAndComments = prefs->getCustomViewNamesAndComments(); const int32_t numViews = static_cast(customViewNamesAndComments.size()); for (int32_t i = 0; i < numViews; i++) { const AString viewName = customViewNamesAndComments[i].first; const AString comment = customViewNamesAndComments[i].second; if (viewName == previousViewName) { defaultSelectedIndex = i; } QListWidgetItem* lwi = new QListWidgetItem(viewName); if (comment.isEmpty() == false) { lwi->setToolTip(WuQtUtilities::createWordWrappedToolTipText(comment)); } m_customViewListWidget->addItem(lwi); } if (defaultSelectedIndex >= numViews) { defaultSelectedIndex = numViews - 1; } if (defaultSelectedIndex < 0) { defaultSelectedIndex = 0; } if ((defaultSelectedIndex >= 0) && (defaultSelectedIndex < m_customViewListWidget->count())) { m_customViewListWidget->setCurrentRow(defaultSelectedIndex); customViewSelected(); m_customViewListWidget->scrollToItem(m_customViewListWidget->currentItem()); } const bool haveViews = (numViews > 0); m_copyWidget->setEnabled(haveViews); const bool haveSelectedView = (getSelectedCustomViewName().isEmpty() == false); m_deleteCustomViewPushButton->setEnabled(haveSelectedView); } /** * @return Create and return the copy buttons widget. */ QWidget* CustomViewDialog::createCopyWidget() { QPushButton* copyToCustomViewPushButton = new QPushButton("Copy -->"); WuQtUtilities::setWordWrappedToolTip(copyToCustomViewPushButton, "Copy the Transform's values into the selected Custom Orientation."); QObject::connect(copyToCustomViewPushButton, SIGNAL(clicked()), this, SLOT(copyToCustomViewPushButtonClicked())); QPushButton* copyToTransformPushButton = new QPushButton("<-- Load"); WuQtUtilities::setWordWrappedToolTip(copyToTransformPushButton, "Load the Custom Orientation's transform values into the Transform."); QObject::connect(copyToTransformPushButton, SIGNAL(clicked()), this, SLOT(copyToTransformPushButtonClicked())); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(copyToCustomViewPushButton); layout->addWidget(copyToTransformPushButton); widget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); return widget; } /** * Called when Copy To Custom View push buttton is clicked. */ void CustomViewDialog::copyToCustomViewPushButtonClicked() { CaretPreferences* prefs = getCaretPreferences(); ModelTransform modelTransform; if (prefs->getCustomView(getSelectedCustomViewName(), modelTransform)) { moveTransformToCustomView(modelTransform); prefs->addOrReplaceCustomView(modelTransform); } } /** * Move the transform values to the given user view. * * @param userView * User View into which transform values are moved. */ void CustomViewDialog::moveTransformToCustomView(ModelTransform& modelTransform) { double panX, panY, panZ, rotX, rotY, rotZ, obRotX, obRotY, obRotZ, zoom, rightFlatX, rightFlatY, rightFlatZoom; getTransformationControlValues(panX, panY, panZ, rotX, rotY, rotZ, obRotX, obRotY, obRotZ, zoom, rightFlatX, rightFlatY, rightFlatZoom); Matrix4x4 rotationMatrix; rotationMatrix.setRotation(rotX, rotY, rotZ); float rotationMatrixArray[4][4]; rotationMatrix.getMatrix(rotationMatrixArray); Matrix4x4 obliqueRotationMatrix; obliqueRotationMatrix.setRotation(obRotX, obRotY, obRotZ); float obliqueRotationMatrixArray[4][4]; obliqueRotationMatrix.getMatrix(obliqueRotationMatrixArray); modelTransform.setPanningRotationMatrixAndZoom(panX, panY, panZ, rotationMatrixArray, obliqueRotationMatrixArray, zoom, rightFlatX, rightFlatY, rightFlatZoom); } /** * Called when Move To Transform push buttton is clicked. */ void CustomViewDialog::copyToTransformPushButtonClicked() { CaretPreferences* prefs = getCaretPreferences(); const AString customViewName = getSelectedCustomViewName(); ModelTransform modelTransform; if (prefs->getCustomView(customViewName, modelTransform)) { float panX, panY, panZ, rotationMatrixArray[4][4], obliqueRotationMatrixArray[4][4], zoom, rightFlatX, rightFlatY, rightFlatZoom; modelTransform.getPanningRotationMatrixAndZoom(panX, panY, panZ, rotationMatrixArray, obliqueRotationMatrixArray, zoom, rightFlatX, rightFlatY, rightFlatZoom); Matrix4x4 rotationMatrix; rotationMatrix.setMatrix(rotationMatrixArray); double rotX, rotY, rotZ; rotationMatrix.getRotation(rotX, rotY, rotZ); Matrix4x4 obliqueRotationMatrix; obliqueRotationMatrix.setMatrix(obliqueRotationMatrixArray); double obRotX, obRotY, obRotZ; obliqueRotationMatrix.getRotation(obRotX, obRotY, obRotZ); setTransformationControlValues(panX, panY, panZ, rotX, rotY, rotZ, obRotX, obRotY, obRotZ, zoom, rightFlatX, rightFlatY, rightFlatZoom); transformValueChanged(); } } /** * @return The Transform widget. */ QWidget* CustomViewDialog::createTransformsWidget() { const int spinBoxWidth = 90; /* * Window number */ QLabel* windowLabel = new QLabel("Workbench Window: "); m_browserWindowComboBox = new BrainBrowserWindowComboBox(BrainBrowserWindowComboBox::STYLE_NUMBER, this); m_browserWindowComboBox->getWidget()->setFixedWidth(spinBoxWidth); QObject::connect(m_browserWindowComboBox, SIGNAL(browserWindowSelected(BrainBrowserWindow*)), this, SLOT(browserWindowComboBoxValueChanged(BrainBrowserWindow*))); /* * Panning */ const double panStep = 1.0; QLabel* panLabel = new QLabel("Pan (X,Y):"); m_xPanDoubleSpinBox = new QDoubleSpinBox; m_xPanDoubleSpinBox->setMinimum(-100000.0); m_xPanDoubleSpinBox->setMaximum( 100000.0); m_xPanDoubleSpinBox->setSingleStep(panStep); m_xPanDoubleSpinBox->setDecimals(2); m_xPanDoubleSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_xPanDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(transformValueChanged())); m_yPanDoubleSpinBox = new QDoubleSpinBox; m_yPanDoubleSpinBox->setMinimum(-100000.0); m_yPanDoubleSpinBox->setMaximum( 100000.0); m_yPanDoubleSpinBox->setSingleStep(panStep); m_yPanDoubleSpinBox->setDecimals(2); m_yPanDoubleSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_yPanDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(transformValueChanged())); m_zPanDoubleSpinBox = new QDoubleSpinBox; m_zPanDoubleSpinBox->setMinimum(-100000.0); m_zPanDoubleSpinBox->setMaximum( 100000.0); m_zPanDoubleSpinBox->setSingleStep(panStep); m_zPanDoubleSpinBox->setDecimals(2); m_zPanDoubleSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_zPanDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(transformValueChanged())); /* * Rotation */ const double rotationMinimum = -360.0; const double rotationMaximum = 360.0; const double rotateStep = 1.0; QLabel* rotateLabel = new QLabel("Rotate (X,Y,Z): "); m_xRotateDoubleSpinBox = new QDoubleSpinBox; m_xRotateDoubleSpinBox->setWrapping(true); m_xRotateDoubleSpinBox->setMinimum(rotationMinimum); m_xRotateDoubleSpinBox->setMaximum(rotationMaximum); m_xRotateDoubleSpinBox->setSingleStep(rotateStep); m_xRotateDoubleSpinBox->setDecimals(2); m_xRotateDoubleSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_xRotateDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(transformValueChanged())); m_yRotateDoubleSpinBox = new QDoubleSpinBox; m_yRotateDoubleSpinBox->setWrapping(true); m_yRotateDoubleSpinBox->setMinimum(rotationMinimum); m_yRotateDoubleSpinBox->setMaximum(rotationMaximum); m_yRotateDoubleSpinBox->setSingleStep(rotateStep); m_yRotateDoubleSpinBox->setDecimals(2); m_yRotateDoubleSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_yRotateDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(transformValueChanged())); m_zRotateDoubleSpinBox = new QDoubleSpinBox; m_zRotateDoubleSpinBox->setWrapping(true); m_zRotateDoubleSpinBox->setMinimum(rotationMinimum); m_zRotateDoubleSpinBox->setMaximum(rotationMaximum); m_zRotateDoubleSpinBox->setSingleStep(rotateStep); m_zRotateDoubleSpinBox->setDecimals(2); m_zRotateDoubleSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_zRotateDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(transformValueChanged())); /* * Rotation */ QLabel* obliqueRotateLabel = new QLabel("Oblique Rotate (X,Y,Z): "); m_xObliqueRotateDoubleSpinBox = new QDoubleSpinBox; m_xObliqueRotateDoubleSpinBox->setWrapping(true); m_xObliqueRotateDoubleSpinBox->setMinimum(rotationMinimum); m_xObliqueRotateDoubleSpinBox->setMaximum(rotationMaximum); m_xObliqueRotateDoubleSpinBox->setSingleStep(rotateStep); m_xObliqueRotateDoubleSpinBox->setDecimals(2); m_xObliqueRotateDoubleSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_xObliqueRotateDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(transformValueChanged())); m_yObliqueRotateDoubleSpinBox = new QDoubleSpinBox; m_yObliqueRotateDoubleSpinBox->setWrapping(true); m_yObliqueRotateDoubleSpinBox->setMinimum(rotationMinimum); m_yObliqueRotateDoubleSpinBox->setMaximum(rotationMaximum); m_yObliqueRotateDoubleSpinBox->setSingleStep(rotateStep); m_yObliqueRotateDoubleSpinBox->setDecimals(2); m_yObliqueRotateDoubleSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_yObliqueRotateDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(transformValueChanged())); m_zObliqueRotateDoubleSpinBox = new QDoubleSpinBox; m_zObliqueRotateDoubleSpinBox->setWrapping(true); m_zObliqueRotateDoubleSpinBox->setMinimum(rotationMinimum); m_zObliqueRotateDoubleSpinBox->setMaximum(rotationMaximum); m_zObliqueRotateDoubleSpinBox->setSingleStep(rotateStep); m_zObliqueRotateDoubleSpinBox->setDecimals(2); m_zObliqueRotateDoubleSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_zObliqueRotateDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(transformValueChanged())); /* * Zoom */ const double zoomStep = 0.01; QLabel* zoomLabel = new QLabel("Zoom: "); m_zoomDoubleSpinBox = new QDoubleSpinBox; m_zoomDoubleSpinBox->setMinimum(0.001); m_zoomDoubleSpinBox->setMaximum(10000.0); m_zoomDoubleSpinBox->setSingleStep(zoomStep); m_zoomDoubleSpinBox->setDecimals(3); m_zoomDoubleSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_zoomDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(transformValueChanged())); /* * Flat offset */ QLabel* rightFlatOffsetLabel = new QLabel("Right Flat Offset: "); m_xRightFlatMapSpinBox = new QDoubleSpinBox; m_xRightFlatMapSpinBox->setMinimum(-100000.0); m_xRightFlatMapSpinBox->setMaximum( 100000.0); m_xRightFlatMapSpinBox->setSingleStep(panStep); m_xRightFlatMapSpinBox->setDecimals(2); m_xRightFlatMapSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_xRightFlatMapSpinBox, SIGNAL(valueChanged(double)), this, SLOT(transformValueChanged())); m_yRightFlatMapSpinBox = new QDoubleSpinBox; m_yRightFlatMapSpinBox->setMinimum(-100000.0); m_yRightFlatMapSpinBox->setMaximum( 100000.0); m_yRightFlatMapSpinBox->setSingleStep(panStep); m_yRightFlatMapSpinBox->setDecimals(2); m_xRightFlatMapSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_yRightFlatMapSpinBox, SIGNAL(valueChanged(double)), this, SLOT(transformValueChanged())); QLabel* rightFlatZoomLabel = new QLabel("Right Flat Zoom: "); m_rightFlatMapZoomFactorSpinBox = new QDoubleSpinBox; m_rightFlatMapZoomFactorSpinBox->setMinimum(0.001); m_rightFlatMapZoomFactorSpinBox->setMaximum(10000.0); m_rightFlatMapZoomFactorSpinBox->setSingleStep(zoomStep); m_rightFlatMapZoomFactorSpinBox->setDecimals(3); m_rightFlatMapZoomFactorSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_rightFlatMapZoomFactorSpinBox, SIGNAL(valueChanged(double)), this, SLOT(transformValueChanged())); m_transformWidgetGroup = new WuQWidgetObjectGroup(this); m_transformWidgetGroup->add(m_xPanDoubleSpinBox); m_transformWidgetGroup->add(m_yPanDoubleSpinBox); m_transformWidgetGroup->add(m_zPanDoubleSpinBox); m_transformWidgetGroup->add(m_xRotateDoubleSpinBox); m_transformWidgetGroup->add(m_yRotateDoubleSpinBox); m_transformWidgetGroup->add(m_zRotateDoubleSpinBox); m_transformWidgetGroup->add(m_xObliqueRotateDoubleSpinBox); m_transformWidgetGroup->add(m_yObliqueRotateDoubleSpinBox); m_transformWidgetGroup->add(m_zObliqueRotateDoubleSpinBox); m_transformWidgetGroup->add(m_zoomDoubleSpinBox); m_transformWidgetGroup->add(m_xRightFlatMapSpinBox); m_transformWidgetGroup->add(m_yRightFlatMapSpinBox); m_transformWidgetGroup->add(m_rightFlatMapZoomFactorSpinBox); /*------------------------------------------------------------------------*/ /* * Layout widgets */ /* * Columns for grid layout */ int column = 0; const int COLUMN_LABEL = column++; const int COLUMN_X = column++; const int COLUMN_Y = column++; const int COLUMN_Z = column++; const int COLUMN_COUNT = column++; QGroupBox* groupBox = new QGroupBox("Transform"); QGridLayout* gridLayout = new QGridLayout(groupBox); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 4, 4); int row = 0; gridLayout->addWidget(windowLabel, row, COLUMN_LABEL); gridLayout->addWidget(m_browserWindowComboBox->getWidget(), row, COLUMN_X); row++; gridLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), row, COLUMN_LABEL, 1, COLUMN_COUNT); gridLayout->setRowMinimumHeight(row, 10.0); row++; gridLayout->addWidget(panLabel, row, COLUMN_LABEL); gridLayout->addWidget(m_xPanDoubleSpinBox, row, COLUMN_X); gridLayout->addWidget(m_yPanDoubleSpinBox, row, COLUMN_Y); gridLayout->addWidget(m_zPanDoubleSpinBox, row, COLUMN_Z); row++; gridLayout->addWidget(rotateLabel, row, COLUMN_LABEL); gridLayout->addWidget(m_xRotateDoubleSpinBox, row, COLUMN_X); gridLayout->addWidget(m_yRotateDoubleSpinBox, row, COLUMN_Y); gridLayout->addWidget(m_zRotateDoubleSpinBox, row, COLUMN_Z); row++; gridLayout->addWidget(obliqueRotateLabel, row, COLUMN_LABEL); gridLayout->addWidget(m_xObliqueRotateDoubleSpinBox, row, COLUMN_X); gridLayout->addWidget(m_yObliqueRotateDoubleSpinBox, row, COLUMN_Y); gridLayout->addWidget(m_zObliqueRotateDoubleSpinBox, row, COLUMN_Z); row++; gridLayout->addWidget(zoomLabel, row, COLUMN_LABEL); gridLayout->addWidget(m_zoomDoubleSpinBox, row, COLUMN_X); row++; gridLayout->addWidget(rightFlatOffsetLabel, row, COLUMN_LABEL); gridLayout->addWidget(m_xRightFlatMapSpinBox, row, COLUMN_X); gridLayout->addWidget(m_yRightFlatMapSpinBox, row, COLUMN_Y); row++; gridLayout->addWidget(rightFlatZoomLabel, row, COLUMN_LABEL); gridLayout->addWidget(m_rightFlatMapZoomFactorSpinBox, row, COLUMN_X); groupBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); return groupBox; } /** * Called when window number combo box value changed. */ void CustomViewDialog::browserWindowComboBoxValueChanged(BrainBrowserWindow* browserWindow) { int32_t windowIndex = -1; if (browserWindow != NULL) { windowIndex = browserWindow->getBrowserWindowIndex(); } updateContent(windowIndex); } /** * Called when a transform value is changed. */ void CustomViewDialog::transformValueChanged() { double panX, panY, panZ, rotX, rotY, rotZ, obRotX, obRotY, obRotZ, zoom, rightFlatX, rightFlatY, rightFlatZoom; getTransformationControlValues(panX, panY, panZ, rotX, rotY, rotZ, obRotX, obRotY, obRotZ, zoom, rightFlatX, rightFlatY, rightFlatZoom); BrainBrowserWindow* bbw = m_browserWindowComboBox->getSelectedBrowserWindow(); if (bbw != NULL) { BrowserTabContent* btc = bbw->getBrowserTabContent(); if (btc != NULL) { Model* model = btc->getModelForDisplay(); if (model != NULL) { Matrix4x4 rotationMatrix; rotationMatrix.setRotation(rotX, rotY, rotZ); float rotationMatrixArray[4][4]; rotationMatrix.getMatrix(rotationMatrixArray); Matrix4x4 obliqueRotationMatrix; obliqueRotationMatrix.setRotation(obRotX, obRotY, obRotZ); float obliqueRotationMatrixArray[4][4]; obliqueRotationMatrix.getMatrix(obliqueRotationMatrixArray); ModelTransform modelTransform; modelTransform.setPanningRotationMatrixAndZoom(panX, panY, panZ, rotationMatrixArray, obliqueRotationMatrixArray, zoom, rightFlatX, rightFlatY, rightFlatZoom); btc->setTransformationsFromModelTransform(modelTransform); updateGraphicsWindow(); } } } } /** * Update the selected graphics window. */ void CustomViewDialog::updateGraphicsWindow() { BrainBrowserWindow* bbw = m_browserWindowComboBox->getSelectedBrowserWindow(); if (bbw != NULL) { const int32_t windowIndex = bbw->getBrowserWindowIndex(); m_blockDialogUpdate = true; EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(windowIndex).getPointer()); m_blockDialogUpdate = false; } } /** * Gets called when the dialog gains focus. */ void CustomViewDialog::focusGained() { updateDialog(); } /** * Update the dialog. */ void CustomViewDialog::updateDialog() { m_browserWindowComboBox->updateComboBox(); updateContent(m_browserWindowComboBox->getSelectedBrowserWindowIndex()); } /** * Update the dialog. */ void CustomViewDialog::updateContent(const int32_t browserWindowIndexIn) { /* * May get updates when graphics are redrawn by this dialog * and not doing this could result in infinite loop */ if (m_blockDialogUpdate) { return; } /* * Update, set, and validate selected browser window */ m_browserWindowComboBox->updateComboBox(); m_browserWindowComboBox->setBrowserWindowByIndex(browserWindowIndexIn); const int32_t browserWindowIndex = m_browserWindowComboBox->getSelectedBrowserWindowIndex(); BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(browserWindowIndex); if (bbw != NULL) { BrowserTabContent* btc = bbw->getBrowserTabContent(); if (btc != NULL) { Model* model = btc->getModelForDisplay(); if (model != NULL) { const float* panning = btc->getTranslation(); const Matrix4x4 rotationMatrix = btc->getRotationMatrix(); const float zooming = btc->getScaling(); const Matrix4x4 obliqueRotationMatrix = btc->getObliqueVolumeRotationMatrix(); double rotX, rotY, rotZ; rotationMatrix.getRotation(rotX, rotY, rotZ); double obRotX, obRotY, obRotZ; obliqueRotationMatrix.getRotation(obRotX, obRotY, obRotZ); float rightFlatX, rightFlatY; btc->getRightCortexFlatMapOffset(rightFlatX, rightFlatY); const float rightFlatZoom = btc->getRightCortexFlatMapZoomFactor(); setTransformationControlValues(panning[0], panning[1], panning[2], rotX, rotY, rotZ, obRotX, obRotY, obRotZ, zooming, rightFlatX, rightFlatY, rightFlatZoom); } } m_transformWidgetGroup->setEnabled(true); } else { m_transformWidgetGroup->setEnabled(false); } loadCustomViewListWidget(); } /** * Get the transformation values. * * @param panX * X pannning * @param panX * X pannning * @param rotX * X rotation * @param rotY * Y rotation * @param rotZ * Z rotation * @param zoom * Zooming * @param rightFlatX * Offset for right flat map. * @param rightFlat& * Offset for right flat map. * @param rightFlatZoom * Zoom for right flat map. */ void CustomViewDialog::getTransformationControlValues(double& panX, double& panY, double& panZ, double& rotX, double& rotY, double& rotZ, double& obRotX, double& obRotY, double& obRotZ, double& zoom, double& rightFlatX, double& rightFlatY, double& rightFlatZoom) const { panX = m_xPanDoubleSpinBox->value(); panY = m_yPanDoubleSpinBox->value(); panZ = m_zPanDoubleSpinBox->value(); rotX = m_xRotateDoubleSpinBox->value(); rotY = m_yRotateDoubleSpinBox->value(); rotZ = m_zRotateDoubleSpinBox->value(); obRotX = m_xObliqueRotateDoubleSpinBox->value(); obRotY = m_yObliqueRotateDoubleSpinBox->value(); obRotZ = m_zObliqueRotateDoubleSpinBox->value(); zoom = m_zoomDoubleSpinBox->value(); rightFlatX = m_xRightFlatMapSpinBox->value(); rightFlatY = m_yRightFlatMapSpinBox->value(); rightFlatZoom = m_rightFlatMapZoomFactorSpinBox->value(); } /** * Set the transformation values. * * @param panX * X pannning * @param panX * X pannning * @param rotX * X rotation * @param rotY * Y rotation * @param rotZ * Z rotation * @param zoom * Zooming * @param rightFlatX * Offset for right flat map. * @param rightFlat * Offset for right flat map. * @param rightFlatZoom * Zoom factor for right flat map. */ void CustomViewDialog::setTransformationControlValues(const double panX, const double panY, const double panZ, const double rotX, const double rotY, const double rotZ, const double obRotX, const double obRotY, const double obRotZ, const double zoom, const double rightFlatX, const double rightFlatY, const double rightFlatZoom) const { m_transformWidgetGroup->blockAllSignals(true); m_xPanDoubleSpinBox->setValue(panX); m_yPanDoubleSpinBox->setValue(panY); m_zPanDoubleSpinBox->setValue(panZ); m_xRotateDoubleSpinBox->setValue(rotX); m_yRotateDoubleSpinBox->setValue(rotY); m_zRotateDoubleSpinBox->setValue(rotZ); m_xObliqueRotateDoubleSpinBox->setValue(obRotX); m_yObliqueRotateDoubleSpinBox->setValue(obRotY); m_zObliqueRotateDoubleSpinBox->setValue(obRotZ); m_zoomDoubleSpinBox->setValue(zoom); m_xRightFlatMapSpinBox->setValue(rightFlatX); m_yRightFlatMapSpinBox->setValue(rightFlatY); m_rightFlatMapZoomFactorSpinBox->setValue(rightFlatZoom); m_transformWidgetGroup->blockAllSignals(false); } /** * @return The caret preferences. */ CaretPreferences* CustomViewDialog::getCaretPreferences() { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); return prefs; } /** * Called when new custom view push button clicked. */ void CustomViewDialog::newCustomViewPushButtonClicked() { CaretPreferences* prefs = getCaretPreferences(); const std::vector existingCustomViewNames = prefs->getCustomViewNames(); bool createViewFlag = false; AString newViewName; AString newViewComment; bool exitLoop = false; while (exitLoop == false) { WuQDataEntryDialog ded("New Custom View", m_newCustomViewPushButton); QLineEdit* nameLineEdit = ded.addLineEditWidget("View Name"); QTextEdit* commentTextEdit = ded.addTextEdit("Comment", "", false); nameLineEdit->setFocus(); if (ded.exec() == WuQDataEntryDialog::Accepted) { newViewName = nameLineEdit->text().trimmed(); if (newViewName.isEmpty() == false) { newViewComment = commentTextEdit->toPlainText().trimmed(); /* * If custom view exists with name entered by user, * then warn the user. */ if (std::find(existingCustomViewNames.begin(), existingCustomViewNames.end(), newViewName) != existingCustomViewNames.end()) { const QString msg = ("View named \"" + newViewName + "\" already exits. Replace?"); if (WuQMessageBox::warningYesNo(m_newCustomViewPushButton, msg)) { exitLoop = true; createViewFlag = true; } } else { exitLoop = true; createViewFlag = true; } } } else { exitLoop = true; } } if (createViewFlag && (newViewName.isEmpty() == false)) { ModelTransform mt; mt.setName(newViewName); mt.setComment(newViewComment); moveTransformToCustomView(mt); prefs->addOrReplaceCustomView(mt); loadCustomViewListWidget(newViewName); } } /** * Called when save custom view push button clicked. */ void CustomViewDialog::deleteCustomViewPushButtonClicked() { const AString viewName = getSelectedCustomViewName(); if (viewName.isEmpty() == false) { const QString msg = ("Delete view named \"" + viewName + "\" ?"); if (WuQMessageBox::warningYesNo(m_newCustomViewPushButton, msg)) { CaretPreferences* prefs = getCaretPreferences(); prefs->removeCustomView(viewName); loadCustomViewListWidget(); } } } /** * Receive events from the event manager. * * @param event * Event sent by event manager. */ void CustomViewDialog::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN) { EventBrowserWindowGraphicsRedrawn* redrawnEvent = dynamic_cast(event); CaretAssert(redrawnEvent); redrawnEvent->setEventProcessed(); const int32_t selectedBrowserWindowIndex = m_browserWindowComboBox->getSelectedBrowserWindowIndex(); if (redrawnEvent->getBrowserWindowIndex() == selectedBrowserWindowIndex) { updateContent(selectedBrowserWindowIndex); } } } connectome-workbench-1.4.2/src/GuiQt/CustomViewDialog.h000066400000000000000000000134771360521144700230650ustar00rootroot00000000000000#ifndef __CUSTOM_VIEW_DIALOG_H__ #define __CUSTOM_VIEW_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventListenerInterface.h" #include "WuQDialogNonModal.h" class QDoubleSpinBox; class QPushButton; namespace caret { class BrainBrowserWindow; class BrainBrowserWindowComboBox; class CaretPreferences; class ModelTransform; class WuQListWidget; class WuQWidgetObjectGroup; class CustomViewDialog : public WuQDialogNonModal, public EventListenerInterface { Q_OBJECT public: CustomViewDialog(QWidget* parent); virtual ~CustomViewDialog(); void updateDialog(); void updateContent(const int32_t browserWindowIndex); void receiveEvent(Event* event); private: CustomViewDialog(const CustomViewDialog&); CustomViewDialog& operator=(const CustomViewDialog&); private slots: void transformValueChanged(); void newCustomViewPushButtonClicked(); void deleteCustomViewPushButtonClicked(); void browserWindowComboBoxValueChanged(BrainBrowserWindow* browserWindow); void customViewSelected(); void customViewSelectedAndApplied(); void copyToCustomViewPushButtonClicked(); void copyToTransformPushButtonClicked(); public: // ADD_NEW_METHODS_HERE protected: void focusGained(); private: void loadCustomViewListWidget(const AString& selectedName = ""); void updateGraphicsWindow(); void getTransformationControlValues(double& panX, double& panY, double& panZ, double& rotX, double& rotY, double& rotZ, double& obRotX, double& obRotY, double& obRotZ, double& zoom, double& rightFlatX, double& rightFlatY, double& rightFlatZoom) const; void setTransformationControlValues(const double panX, const double panY, const double panZ, const double rotX, const double rotY, const double rotZ, const double obRotX, const double obRotY, const double obRotZ, const double zoom, const double rightFlatX, const double rightFlatY, const double rightFlatZoom) const; // ADD_NEW_MEMBERS_HERE CaretPreferences* getCaretPreferences(); //std::vector getAllCustomViewNames(); QWidget* createCustomViewWidget(); QWidget* createCopyWidget(); QWidget* createTransformsWidget(); //UserView* getSelectedUserView(); AString getSelectedCustomViewName(); void moveTransformToCustomView(ModelTransform& modelTransform); QWidget* m_copyWidget; QDoubleSpinBox* m_xPanDoubleSpinBox; QDoubleSpinBox* m_yPanDoubleSpinBox; QDoubleSpinBox* m_zPanDoubleSpinBox; QDoubleSpinBox* m_xRotateDoubleSpinBox; QDoubleSpinBox* m_yRotateDoubleSpinBox; QDoubleSpinBox* m_zRotateDoubleSpinBox; QDoubleSpinBox* m_xObliqueRotateDoubleSpinBox; QDoubleSpinBox* m_yObliqueRotateDoubleSpinBox; QDoubleSpinBox* m_zObliqueRotateDoubleSpinBox; QDoubleSpinBox* m_zoomDoubleSpinBox; QDoubleSpinBox* m_xRightFlatMapSpinBox; QDoubleSpinBox* m_yRightFlatMapSpinBox; QDoubleSpinBox* m_rightFlatMapZoomFactorSpinBox; WuQWidgetObjectGroup* m_transformWidgetGroup; BrainBrowserWindowComboBox* m_browserWindowComboBox; QPushButton* m_newCustomViewPushButton; QPushButton* m_deleteCustomViewPushButton; WuQListWidget* m_customViewListWidget; bool m_blockDialogUpdate; }; #ifdef __CUSTOM_VIEW_DIALOG_DECLARE__ // #endif // __CUSTOM_VIEW_DIALOG_DECLARE__ } // namespace #endif //__CUSTOM_VIEW_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/DataFileContentCopyMoveDialog.cxx000066400000000000000000000261741360521144700260170ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __DATA_FILE_CONTENT_COPY_MOVE_DIALOG_DECLARE__ #include "DataFileContentCopyMoveDialog.h" #undef __DATA_FILE_CONTENT_COPY_MOVE_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include #include #include "CaretAssert.h" #include "CaretDataFile.h" #include "CaretFileDialog.h" #include "DataFile.h" #include "DataFileContentCopyMoveInterface.h" #include "DataFileContentCopyMoveParameters.h" #include "DataFileException.h" #include "EventDataFileAdd.h" #include "EventDataFileDelete.h" #include "EventManager.h" #include "FileInformation.h" #include "WuQMessageBox.h" using namespace caret; /** * \class caret::DataFileContentCopyMoveDialog * \brief Dialog for copying/moving content between data files * \ingroup GuiQt */ /** * Constructor. * * @param windowIndex * Index of window. * @param sourceDataFileInterface * The source data file (copy from file) * @param destinationDataFileInterfaces * Files to which data may be moved. * @param parent * Optional parent for this dialog. */ DataFileContentCopyMoveDialog::DataFileContentCopyMoveDialog(const int32_t windowIndex, DataFileContentCopyMoveInterface* sourceDataFileInterface, std::vector& destinationDataFileInterfaces, QWidget* parent) : WuQDialogModal("Copy/Move Data File Content", parent), m_windowIndex(windowIndex), m_sourceDataFileInterface(sourceDataFileInterface), m_newDestinatonFileButtonGroupIndex(-1) { CaretAssert(m_sourceDataFileInterface); /* * Copy pointers to destination files but ignore the source file */ for (std::vector::iterator fileIter = destinationDataFileInterfaces.begin(); fileIter != destinationDataFileInterfaces.end(); fileIter++) { DataFileContentCopyMoveInterface* df = *fileIter; if (df != sourceDataFileInterface) { m_destinationDataFileInterfaces.push_back(df); } } QWidget* dialogWidget = new QWidget; QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); dialogLayout->addWidget(createSourceWidget()); dialogLayout->addWidget(createDestinationWidget()); dialogLayout->addWidget(createOptionsWidget()); setCentralWidget(dialogWidget, WuQDialog::SCROLL_AREA_AS_NEEDED); } /** * Destructor. */ DataFileContentCopyMoveDialog::~DataFileContentCopyMoveDialog() { } /** * @return The source widget. */ QWidget* DataFileContentCopyMoveDialog::createSourceWidget() { QLabel* sourceFileLabel = new QLabel(m_sourceDataFileInterface->getAsDataFile()->getFileNameNoPath()); QGroupBox* groupBox = new QGroupBox("Source File"); QVBoxLayout* layout = new QVBoxLayout(groupBox); layout->addWidget(sourceFileLabel); return groupBox; } /** * @return The options widget. */ QWidget* DataFileContentCopyMoveDialog::createOptionsWidget() { m_closeSourceFileCheckBox = new QCheckBox("Close Source File After Copying Data"); m_closeSourceFileCheckBox->setChecked(true); QObject::connect(m_closeSourceFileCheckBox, SIGNAL(toggled(bool)), this, SLOT(closeSourceFileCheckBoxToggled(bool))); m_copySelectedAnnotationsOnlyCheckBox = new QCheckBox("Copy Only Annotations SELECTED FOR EDITING"); m_copySelectedAnnotationsOnlyCheckBox->setChecked(false); QGroupBox* groupBox = new QGroupBox("Options"); QVBoxLayout* layout = new QVBoxLayout(groupBox); layout->addWidget(m_closeSourceFileCheckBox); layout->addWidget(m_copySelectedAnnotationsOnlyCheckBox); return groupBox; } /** * Called when the close source file checkbox is toggled. * * @param checked * New checked status. */ void DataFileContentCopyMoveDialog::closeSourceFileCheckBoxToggled(bool checked) { if ( ! checked) { /* * Display warning only once. */ static bool firstTimeFlag = true; if (firstTimeFlag) { const QString msg("If the source file is not closed, identical data items will appear " "in the graphics region."); WuQMessageBox::warningOk(m_closeSourceFileCheckBox, msg); firstTimeFlag = false; } } } /** * @return The destination widget. */ QWidget* DataFileContentCopyMoveDialog::createDestinationWidget() { m_destinationButtonGroup = new QButtonGroup; const int32_t numberOfFiles = static_cast(m_destinationDataFileInterfaces.size()); for (int32_t iFile = 0; iFile < numberOfFiles; iFile++) { DataFile* dataFile = m_destinationDataFileInterfaces[iFile]->getAsDataFile(); QRadioButton* rb = new QRadioButton(dataFile->getFileNameNoPath()); m_destinationButtonGroup->addButton(rb, iFile); } QToolButton* newDestinationFileToolButton = new QToolButton(); QObject::connect(newDestinationFileToolButton, SIGNAL(clicked(bool)), this, SLOT(newDestinationFileToolButtonClicked())); newDestinationFileToolButton->setText("New File Name..."); m_newDestinationFileNameLabel = new QLabel(" "); m_newDestinatonFileButtonGroupIndex = m_destinationButtonGroup->buttons().size(); m_newDestinationFileRadioButton = new QRadioButton(""); m_destinationButtonGroup->addButton(m_newDestinationFileRadioButton, m_newDestinatonFileButtonGroupIndex); QGroupBox* groupBox = new QGroupBox("Destination File"); QGridLayout* layout = new QGridLayout(groupBox); layout->setColumnStretch(0, 0); layout->setColumnStretch(1, 0); layout->setColumnStretch(2, 0); layout->setColumnStretch(3, 100); QListIterator buttonIter(m_destinationButtonGroup->buttons()); while (buttonIter.hasNext()) { const int row = layout->rowCount(); QAbstractButton* button = buttonIter.next(); if (button == m_newDestinationFileRadioButton) { layout->addWidget(button, row, 0); layout->addWidget(newDestinationFileToolButton, row, 1); layout->addWidget(m_newDestinationFileNameLabel, row, 2, Qt::AlignLeft); } else { layout->addWidget(button, row, 0, 1, 3, Qt::AlignLeft); } } return groupBox; } /** * Gets called when "New File..." button is clicked. */ void DataFileContentCopyMoveDialog::newDestinationFileToolButtonClicked() { const CaretDataFile* caretDataFile = dynamic_cast(m_sourceDataFileInterface); CaretAssert(caretDataFile); const QString fileName = CaretFileDialog::getSaveFileNameDialog(caretDataFile->getDataFileType(), this, "Choose New File"); if ( ! fileName.isEmpty()) { m_newDestinationFileName = fileName; FileInformation fileInfo(fileName); m_newDestinationFileNameLabel->setText(fileInfo.getFileName()); m_newDestinationFileRadioButton->setChecked(true); } } /** * Called when OK button clicked. */ void DataFileContentCopyMoveDialog::okButtonClicked() { try { DataFileContentCopyMoveInterface* destinationFile = NULL; bool newFileFlag = false; const int32_t destinationFileIndex = m_destinationButtonGroup->checkedId(); if (destinationFileIndex >= 0) { if (destinationFileIndex == m_newDestinatonFileButtonGroupIndex) { if (m_newDestinationFileName.isEmpty()) { throw DataFileException("New file name is empty."); } CaretAssert(dynamic_cast(m_sourceDataFileInterface)); destinationFile = m_sourceDataFileInterface->newInstanceOfDataFile(); if (destinationFile == NULL) { throw DataFileException("Failed to created new file."); } destinationFile->getAsDataFile()->setFileName(m_newDestinationFileName); newFileFlag = true; } else { CaretAssertVectorIndex(m_destinationDataFileInterfaces, destinationFileIndex); destinationFile = m_destinationDataFileInterfaces[destinationFileIndex]; } } if (destinationFile == NULL) { throw DataFileException("No destination file is selected"); } CaretAssert(destinationFile); DataFileContentCopyMoveParameters copyMoveParams(m_sourceDataFileInterface, m_windowIndex); copyMoveParams.setOptionSelectedItems(m_copySelectedAnnotationsOnlyCheckBox->isChecked()); destinationFile->appendContentFromDataFile(copyMoveParams); if (newFileFlag) { CaretDataFile* destinationCaretFile = dynamic_cast(destinationFile); CaretAssert(destinationCaretFile); if (destinationCaretFile->isEmpty()) { throw DataFileException("There was no data to copy. New file was not created."); } EventDataFileAdd addFileEvent(destinationCaretFile); EventManager::get()->sendEvent(addFileEvent.getPointer()); if (addFileEvent.isError()) { throw DataFileException(addFileEvent.getErrorMessage()); } } if (m_closeSourceFileCheckBox->isChecked()) { CaretDataFile* sourceCaretFile = dynamic_cast(m_sourceDataFileInterface); CaretAssert(sourceCaretFile); EventManager::get()->sendEvent(EventDataFileDelete(sourceCaretFile).getPointer()); } } catch (const DataFileException& dfe) { WuQMessageBox::errorOk(this, dfe.whatString()); return; } WuQDialogModal::okButtonClicked(); } connectome-workbench-1.4.2/src/GuiQt/DataFileContentCopyMoveDialog.h000066400000000000000000000057731360521144700254460ustar00rootroot00000000000000#ifndef __DATA_FILE_CONTENT_COPY_MOVE_DIALOG_H__ #define __DATA_FILE_CONTENT_COPY_MOVE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WuQDialogModal.h" class QButtonGroup; class QCheckBox; class QLabel; class QRadioButton; namespace caret { class DataFileContentCopyMoveInterface; class DataFileContentCopyMoveDialog : public WuQDialogModal { Q_OBJECT public: DataFileContentCopyMoveDialog(const int32_t windowIndex, DataFileContentCopyMoveInterface* sourceDataFileInterface, std::vector& dataFilesInterface, QWidget* parent); virtual ~DataFileContentCopyMoveDialog(); // ADD_NEW_METHODS_HERE private slots: void newDestinationFileToolButtonClicked(); void closeSourceFileCheckBoxToggled(bool); private: DataFileContentCopyMoveDialog(const DataFileContentCopyMoveDialog&); DataFileContentCopyMoveDialog& operator=(const DataFileContentCopyMoveDialog&); virtual void okButtonClicked(); QWidget* createOptionsWidget(); QWidget* createSourceWidget(); QWidget* createDestinationWidget(); const int32_t m_windowIndex; DataFileContentCopyMoveInterface* m_sourceDataFileInterface; std::vector m_destinationDataFileInterfaces; QButtonGroup* m_destinationButtonGroup; QLabel* m_newDestinationFileNameLabel; int m_newDestinatonFileButtonGroupIndex; QString m_newDestinationFileName; QRadioButton* m_newDestinationFileRadioButton; QCheckBox* m_closeSourceFileCheckBox; QCheckBox* m_copySelectedAnnotationsOnlyCheckBox; // ADD_NEW_MEMBERS_HERE }; #ifdef __DATA_FILE_CONTENT_COPY_MOVE_DIALOG_DECLARE__ // #endif // __DATA_FILE_CONTENT_COPY_MOVE_DIALOG_DECLARE__ } // namespace #endif //__DATA_FILE_CONTENT_COPY_MOVE_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/DisplayGroupAndTabItemTreeWidgetItem.cxx000066400000000000000000000257421360521144700273270ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __DISPLAY_GROUP_AND_TAB_ITEM_TREE_WIDGET_ITEM_DECLARE__ #include "DisplayGroupAndTabItemTreeWidgetItem.h" #undef __DISPLAY_GROUP_AND_TAB_ITEM_TREE_WIDGET_ITEM_DECLARE__ #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "DisplayGroupAndTabItemInterface.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::DisplayGroupAndTabItemTreeWidgetItem * \brief Item for display group and tab selection hierarchy * \ingroup GuiQt */ /** * Constructor. */ DisplayGroupAndTabItemTreeWidgetItem::DisplayGroupAndTabItemTreeWidgetItem(const int32_t browserWindowIndex) : QTreeWidgetItem(), m_browserWindowIndex(browserWindowIndex) { m_displayGroup = DisplayGroupEnum::DISPLAY_GROUP_A; m_tabIndex = -1; } /** * Destructor. */ DisplayGroupAndTabItemTreeWidgetItem::~DisplayGroupAndTabItemTreeWidgetItem() { } /** * @return A deep copy of the item. */ QTreeWidgetItem* DisplayGroupAndTabItemTreeWidgetItem::clone() const { const QString msg("Cloning of DisplayGroupAndTabItemTreeWidgetItem not allowed."); CaretAssertMessage(0, msg); CaretLogSevere(msg); return NULL; } /** * Update the content of this widget. * * @param displayGroupAndTabItem * Display group and tab item for this instance. * @param treeWidget * Tree widget that owns this item. * @param displayGroup * The display group. * @param tabIndex * The tab index. */ void DisplayGroupAndTabItemTreeWidgetItem::updateContent(DisplayGroupAndTabItemInterface *displayGroupAndTabItem, QTreeWidget* treeWidget, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) { CaretAssert(displayGroupAndTabItem); m_displayGroup = displayGroup; m_tabIndex = tabIndex; setText(NAME_COLUMN, displayGroupAndTabItem->getItemName()); setDisplayGroupAndTabItem(displayGroupAndTabItem); Qt::CheckState qtCheckState = toQCheckState(displayGroupAndTabItem->getItemDisplaySelected(m_displayGroup, m_tabIndex)); setCheckState(NAME_COLUMN, qtCheckState); setItemIcon(treeWidget, displayGroupAndTabItem); const int32_t numExistingChildren = childCount(); const int32_t numValidChildren = displayGroupAndTabItem->getNumberOfItemChildren(); const int32_t numberOfChildrenToAdd = numValidChildren - numExistingChildren; for (int32_t i = 0; i < numberOfChildrenToAdd; i++) { addChild(new DisplayGroupAndTabItemTreeWidgetItem(m_browserWindowIndex)); } CaretAssert(childCount() >= numValidChildren); for (int32_t i = 0; i < numValidChildren; i++) { QTreeWidgetItem* treeWidgetChild = child(i); if (i < numValidChildren) { treeWidgetChild->setHidden(false); DisplayGroupAndTabItemTreeWidgetItem* dgtChild = dynamic_cast(treeWidgetChild); CaretAssert(dgtChild); dgtChild->updateContent(displayGroupAndTabItem->getItemChild(i), treeWidget, displayGroup, tabIndex); } else { treeWidgetChild->setHidden(true); setDisplayGroupAndTabItem(NULL); } } // const bool expandedFlag = displayGroupAndTabItem->isItemExpanded(m_displayGroup, // m_tabIndex); // setExpanded(expandedFlag); // setSelected(displayGroupAndTabItem->isItemSelectedForEditingInWindow()) for (int32_t i = (numExistingChildren - 1); i >= numValidChildren; i--) { /* * Take removes it from the parent but * does not destruct it. */ QTreeWidgetItem* item = takeChild(i); delete item; } } /** * @return The data item in this tree widget item (may be NULL). */ DisplayGroupAndTabItemInterface* DisplayGroupAndTabItemTreeWidgetItem::getDisplayGroupAndTabItem() const { DisplayGroupAndTabItemInterface* myItem = NULL; void* myDataPtr = data(NAME_COLUMN, Qt::UserRole).value(); if (myDataPtr != NULL) { myItem = (DisplayGroupAndTabItemInterface*)myDataPtr; CaretAssert(myItem); } return myItem; } /** * Set the data item in this tree widget item. * * @param displayGroupAndTabItem * The data item (may be NULL). */ void DisplayGroupAndTabItemTreeWidgetItem::setDisplayGroupAndTabItem(DisplayGroupAndTabItemInterface* displayGroupAndTabItem) { setData(NAME_COLUMN, Qt::UserRole, qVariantFromValue(displayGroupAndTabItem)); } /** * Set the icon for this item. */ void DisplayGroupAndTabItemTreeWidgetItem::setItemIcon(QTreeWidget* treeWidget, DisplayGroupAndTabItemInterface* myDataItem) { CaretAssert(myDataItem); float backgroundRGBA[4]; float outlineRGBA[4]; float textRGBA[4]; myDataItem->getItemIconColorsRGBA(backgroundRGBA, outlineRGBA, textRGBA); if ((backgroundRGBA[3] > 0.0) || (outlineRGBA[3] > 0.0) || (textRGBA[3] > 0.0)) { const int pixmapSize = 24; QPixmap pixmap(pixmapSize, pixmapSize); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginBottomLeft(treeWidget, pixmap); if (backgroundRGBA[3] > 0.0) { painter->fillRect(pixmap.rect(), QColor::fromRgbF(backgroundRGBA[0], backgroundRGBA[1], backgroundRGBA[2])); } if (outlineRGBA[3] > 0.0) { QPen pen = painter->pen(); QColor outlineColor = QColor::fromRgbF(outlineRGBA[0], outlineRGBA[1], outlineRGBA[2]); painter->fillRect(0, 0, 3, pixmapSize, outlineColor); painter->fillRect(pixmapSize - 3, 0, 3, pixmapSize, outlineColor); painter->fillRect(0, 0, pixmapSize, 3, outlineColor); painter->fillRect(0, pixmapSize - 4, pixmapSize, 3, outlineColor); } if (textRGBA[3] > 0.0) { QColor textColor = QColor::fromRgbF(textRGBA[0], textRGBA[1], textRGBA[2]); const int rectSize = 8; const int cornerXY = (pixmapSize / 2) - (rectSize / 2); painter->fillRect(cornerXY, cornerXY, rectSize, rectSize, textColor); } setIcon(NAME_COLUMN, QIcon(pixmap)); } else { setIcon(NAME_COLUMN, QIcon()); } } /** * Update the selected and expanded checkboxes. * * @param displayGroup * The display group. * @param tabIndex * Index of the tab. */ void DisplayGroupAndTabItemTreeWidgetItem::updateSelectedAndExpandedCheckboxes(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) { const int32_t numChildren = childCount(); for (int32_t iChild = 0; iChild < numChildren; iChild++) { QTreeWidgetItem* treeChild = child(iChild); CaretAssert(treeChild); DisplayGroupAndTabItemTreeWidgetItem* item = dynamic_cast(treeChild); CaretAssert(item); DisplayGroupAndTabItemInterface* data = item->getDisplayGroupAndTabItem(); if (data != NULL) { item->updateSelectedAndExpandedCheckboxes(displayGroup, tabIndex); } } DisplayGroupAndTabItemInterface* myData = getDisplayGroupAndTabItem(); if (myData != NULL) { Qt::CheckState checkState = toQCheckState(myData->getItemDisplaySelected(displayGroup, tabIndex)); setCheckState(NAME_COLUMN, checkState); setExpanded(myData->isItemExpanded(displayGroup, tabIndex)); setSelected(myData->isItemSelectedForEditingInWindow(m_browserWindowIndex)); } } /** * Convert QCheckState to GroupAndNameCheckStateEnum * @param checkState * The QCheckState * @return GroupAndNameCheckStateEnum converted from QCheckState */ TriStateSelectionStatusEnum::Enum DisplayGroupAndTabItemTreeWidgetItem::fromQCheckState(const Qt::CheckState checkState) { switch (checkState) { case Qt::Unchecked: return TriStateSelectionStatusEnum::UNSELECTED; break; case Qt::PartiallyChecked: return TriStateSelectionStatusEnum::PARTIALLY_SELECTED; break; case Qt::Checked: return TriStateSelectionStatusEnum::SELECTED; break; } return TriStateSelectionStatusEnum::UNSELECTED; } /** * Convert the tri state selection status to Qt::CheckState * * @param triStateStatus * The tri state selection status. * @return * Qt::CheckState status. */ Qt::CheckState DisplayGroupAndTabItemTreeWidgetItem::toQCheckState(const TriStateSelectionStatusEnum::Enum triStateStatus) { switch (triStateStatus) { case TriStateSelectionStatusEnum::PARTIALLY_SELECTED: return Qt::PartiallyChecked; break; case TriStateSelectionStatusEnum::SELECTED: return Qt::Checked; break; case TriStateSelectionStatusEnum::UNSELECTED: return Qt::Unchecked; break; } return Qt::Unchecked; } connectome-workbench-1.4.2/src/GuiQt/DisplayGroupAndTabItemTreeWidgetItem.h000066400000000000000000000062671360521144700267550ustar00rootroot00000000000000#ifndef __DISPLAY_GROUP_AND_TAB_ITEM_TREE_WIDGET_ITEM_H__ #define __DISPLAY_GROUP_AND_TAB_ITEM_TREE_WIDGET_ITEM_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "DisplayGroupEnum.h" #include "TriStateSelectionStatusEnum.h" class QTreeWidget; namespace caret { class DisplayGroupAndTabItemInterface; class DisplayGroupAndTabItemTreeWidgetItem : public QTreeWidgetItem { public: DisplayGroupAndTabItemTreeWidgetItem(const int32_t browserWindowIndex); virtual ~DisplayGroupAndTabItemTreeWidgetItem(); void updateContent(DisplayGroupAndTabItemInterface *displayGroupAndTabItem, QTreeWidget* treeWidget, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex); DisplayGroupAndTabItemInterface* getDisplayGroupAndTabItem() const; virtual QTreeWidgetItem* clone() const; // ADD_NEW_METHODS_HERE private: DisplayGroupAndTabItemTreeWidgetItem(const DisplayGroupAndTabItemTreeWidgetItem&); DisplayGroupAndTabItemTreeWidgetItem& operator=(const DisplayGroupAndTabItemTreeWidgetItem&); static TriStateSelectionStatusEnum::Enum fromQCheckState(const Qt::CheckState checkState); static Qt::CheckState toQCheckState(const TriStateSelectionStatusEnum::Enum triStateStatus); void setItemIcon(QTreeWidget* treeWidget, DisplayGroupAndTabItemInterface* myDataItem); void setDisplayGroupAndTabItem(DisplayGroupAndTabItemInterface* displayGroupAndTabItem); void updateSelectedAndExpandedCheckboxes(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex); const int32_t m_browserWindowIndex; DisplayGroupEnum::Enum m_displayGroup; int32_t m_tabIndex; // ADD_NEW_MEMBERS_HERE static const int NAME_COLUMN; friend class DisplayGroupAndTabItemViewController; }; #ifdef __DISPLAY_GROUP_AND_TAB_ITEM_TREE_WIDGET_ITEM_DECLARE__ const int DisplayGroupAndTabItemTreeWidgetItem::NAME_COLUMN = 0; #endif // __DISPLAY_GROUP_AND_TAB_ITEM_TREE_WIDGET_ITEM_DECLARE__ } // namespace #endif //__DISPLAY_GROUP_AND_TAB_ITEM_TREE_WIDGET_ITEM_H__ connectome-workbench-1.4.2/src/GuiQt/DisplayGroupAndTabItemViewController.cxx000066400000000000000000000501161360521144700274140ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __DISPLAY_GROUP_AND_TAB_ITEM_VIEW_CONTROLLER_DECLARE__ #include "DisplayGroupAndTabItemViewController.h" #undef __DISPLAY_GROUP_AND_TAB_ITEM_VIEW_CONTROLLER_DECLARE__ #include #include #include #include #include #include "Annotation.h" #include "AnnotationGroup.h" #include "AnnotationManager.h" #include "Brain.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "DisplayGroupAndTabItemInterface.h" #include "DisplayGroupAndTabItemTreeWidgetItem.h" #include "DisplayPropertiesAnnotation.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "GuiManager.h" using namespace caret; /** * \class caret::DisplayGroupAndTabItemViewController * \brief View controller for display group and tab item hierarchy * \ingroup GuiQt */ /** * Constructor. * * @param dataFileType * Type of data file using this view controller. * @param browserWindowIndex * The browser window containing this instance. * @param parent * Parent of this instance. */ DisplayGroupAndTabItemViewController::DisplayGroupAndTabItemViewController(const DataFileTypeEnum::Enum dataFileType, const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), m_dataFileType(dataFileType), m_browserWindowIndex(browserWindowIndex) { const QString onOffToolTip("" "To select more than one item:
    " "* For a contiguous selection, click an item " "and then click another item while holding down " "the SHIFT key.
    " "* For non-contiguous selection, select items while " "holding down the CTRL key (Command key on Apple)" ""); m_turnOnSelectedItemsAction = new QAction("On"); m_turnOnSelectedItemsAction->setToolTip(onOffToolTip); m_turnOnSelectedItemsAction->setCheckable(false); QObject::connect(m_turnOnSelectedItemsAction, &QAction::triggered, this, &DisplayGroupAndTabItemViewController::turnOnSelectedItemsTriggered); QToolButton* turnOnToolButton = new QToolButton(); turnOnToolButton->setDefaultAction(m_turnOnSelectedItemsAction); m_turnOffSelectedItemsAction = new QAction("Off"); m_turnOffSelectedItemsAction->setToolTip(onOffToolTip); m_turnOffSelectedItemsAction->setCheckable(false); QObject::connect(m_turnOffSelectedItemsAction, &QAction::triggered, this, &DisplayGroupAndTabItemViewController::turnOffSelectedItemsTriggered); QToolButton* turnOffToolButton = new QToolButton(); turnOffToolButton->setDefaultAction(m_turnOffSelectedItemsAction); m_treeWidget = new QTreeWidget(); m_treeWidget->setHeaderHidden(true); m_treeWidget->setSelectionMode(QTreeWidget::NoSelection); QObject::connect(m_treeWidget, SIGNAL(itemCollapsed(QTreeWidgetItem*)), this, SLOT(itemWasCollapsed(QTreeWidgetItem*))); QObject::connect(m_treeWidget, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(itemWasExpanded(QTreeWidgetItem*))); QObject::connect(m_treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(itemWasChanged(QTreeWidgetItem*, int))); QObject::connect(m_treeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(itemsWereSelected())); m_treeWidget->setContextMenuPolicy(Qt::CustomContextMenu); QObject::connect(m_treeWidget, &QTreeWidget::customContextMenuRequested, this, &DisplayGroupAndTabItemViewController::displayContextMenu); QHBoxLayout* buttonLayout = new QHBoxLayout(); buttonLayout->setContentsMargins(0, 0, 0, 0); buttonLayout->addWidget(new QLabel("Selected Items: ")); buttonLayout->addWidget(turnOnToolButton); buttonLayout->addSpacing(5); buttonLayout->addWidget(turnOffToolButton); buttonLayout->addStretch(); QVBoxLayout* layout = new QVBoxLayout(this); layout->addLayout(buttonLayout); layout->addWidget(m_treeWidget, 100); s_allViewControllers.insert(this); } /** * Destructor. */ DisplayGroupAndTabItemViewController::~DisplayGroupAndTabItemViewController() { s_allViewControllers.erase(this); } /** * Gets called when items are selected. */ void DisplayGroupAndTabItemViewController::itemsWereSelected() { QList itemsSelected = m_treeWidget->selectedItems(); if ( ! itemsSelected.empty()) { std::vector itemInterfacesVector; QListIterator itemsIter(itemsSelected); while (itemsIter.hasNext()) { QTreeWidgetItem* item = itemsIter.next(); DisplayGroupAndTabItemTreeWidgetItem* widgetItem = dynamic_cast(item); CaretAssert(widgetItem); DisplayGroupAndTabItemInterface* itemInterface = widgetItem->getDisplayGroupAndTabItem(); CaretAssert(itemInterface); if (itemInterface != NULL) { itemInterfacesVector.push_back(itemInterface); } } if ( ! itemInterfacesVector.empty()) { if (m_dataFileType == DataFileTypeEnum::ANNOTATION) { processAnnotationDataSelection(itemInterfacesVector); } } } DisplayGroupEnum::Enum displayGroup = DisplayGroupEnum::DISPLAY_GROUP_TAB; int32_t tabIndex = -1; getDisplayGroupAndTabIndex(displayGroup, tabIndex); updateSelectedAndExpandedCheckboxes(displayGroup, tabIndex); updateGraphics(); } /** * Display a context sensitive (right-click) menu. * * @param pos * Position for context menu */ void DisplayGroupAndTabItemViewController::displayContextMenu(const QPoint& pos) { QList itemsSelected = m_treeWidget->selectedItems(); if (itemsSelected.isEmpty()) { return; } QMenu menu(this); QAction* onAction = menu.addAction("Turn all selected items ON"); menu.addAction("Turn all selected items OFF"); QSignalBlocker blocker(m_treeWidget); QAction* selectedAction = menu.exec(m_treeWidget->mapToGlobal(pos)); if (selectedAction == NULL) { return; } const bool newStatus = (selectedAction == onAction); setCheckedStatusOfSelectedItems(newStatus); } /** * Process the selection of annotations. * * @param interfaceItems * Items that should be annotations ! */ void DisplayGroupAndTabItemViewController::processAnnotationDataSelection(const std::vector& interfaceItems) { std::set annotationSet; for (std::vector::const_iterator iter = interfaceItems.begin(); iter != interfaceItems.end(); iter++) { Annotation* ann = dynamic_cast(*iter); if (ann != NULL) { annotationSet.insert(ann); } else { AnnotationGroup* annGroup = dynamic_cast(*iter); if (annGroup != NULL) { std::vector groupAnns; annGroup->getAllAnnotations(groupAnns); annotationSet.insert(groupAnns.begin(), groupAnns.end()); } } } if ( ! annotationSet.empty()) { std::vector selectedAnnotations(annotationSet.begin(), annotationSet.end()); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); annMan->setAnnotationsForEditing(m_browserWindowIndex, selectedAnnotations); } } /** * Gets called when an item is collapsed so that its children are not visible. * * @param item * The QTreeWidgetItem that was collapsed. */ void DisplayGroupAndTabItemViewController::itemWasCollapsed(QTreeWidgetItem* item) { processItemExpanded(item, false); } /** * Gets called when an item is expaned so that its children are visible. * * @param item * The QTreeWidgetItem that was expanded. */ void DisplayGroupAndTabItemViewController::itemWasExpanded(QTreeWidgetItem* item) { processItemExpanded(item, true); } /** * Called when an item is changed (checkbox selected/deselected). * * @param item * The QTreeWidgetItem that was collapsed. * @param column * Ignored. */ void DisplayGroupAndTabItemViewController::itemWasChanged(QTreeWidgetItem* item, int /*column*/) { DisplayGroupEnum::Enum displayGroup = DisplayGroupEnum::DISPLAY_GROUP_TAB; int32_t tabIndex = -1; getDisplayGroupAndTabIndex(displayGroup, tabIndex); DisplayGroupAndTabItemInterface* dataItem = getDataItem(item); const Qt::CheckState checkState = item->checkState(DisplayGroupAndTabItemTreeWidgetItem::NAME_COLUMN); const TriStateSelectionStatusEnum::Enum itemCheckState = DisplayGroupAndTabItemTreeWidgetItem::fromQCheckState(checkState); dataItem->setItemDisplaySelected(displayGroup, tabIndex, itemCheckState); updateSelectedAndExpandedCheckboxes(displayGroup, tabIndex); updateSelectedAndExpandedCheckboxesInOtherViewControllers(); updateGraphics(); } /** * Process item expanded or collapsed. * * @param item * The QTreeWidgetItem that was expanded or collapsed. * @param expandedStatus * True if expanded, false if collapsed. */ void DisplayGroupAndTabItemViewController::processItemExpanded(QTreeWidgetItem* item, const bool expandedStatus) { DisplayGroupEnum::Enum displayGroup = DisplayGroupEnum::DISPLAY_GROUP_TAB; int32_t tabIndex = -1; getDisplayGroupAndTabIndex(displayGroup, tabIndex); DisplayGroupAndTabItemInterface* dataItem = getDataItem(item); dataItem->setItemExpanded(displayGroup, tabIndex, expandedStatus); updateSelectedAndExpandedCheckboxes(displayGroup, tabIndex); updateSelectedAndExpandedCheckboxesInOtherViewControllers(); } /** * Get the data item in the given tree widget item. * * @param item * The tree widget item. * @return * The data item in the tree widget item. */ DisplayGroupAndTabItemInterface* DisplayGroupAndTabItemViewController::getDataItem(QTreeWidgetItem* item) const { DisplayGroupAndTabItemTreeWidgetItem* treeItem = dynamic_cast(item); CaretAssert(treeItem); DisplayGroupAndTabItemInterface* dataItem = treeItem->getDisplayGroupAndTabItem(); CaretAssert(dataItem); return dataItem; } /** * Get the display group and tab index currently active. */ void DisplayGroupAndTabItemViewController::getDisplayGroupAndTabIndex(DisplayGroupEnum::Enum& displayGroupOut, int32_t& tabIndexOut) const { BrowserTabContent* tabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, false); CaretAssert(tabContent); tabIndexOut= tabContent->getTabNumber(); CaretAssert(tabIndexOut >= 0); DisplayPropertiesAnnotation* dpa = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotation(); displayGroupOut = dpa->getDisplayGroupForTab(tabIndexOut); } /** * Update the content. * * @param contentItemsIn * Items that are displayed. * @param displayGroup * The display group. * @param tabIndex * Index of the tab * @param allowSelectionFlag * Allows selection of items by user clicking items. */ void DisplayGroupAndTabItemViewController::updateContent(std::vector& contentItemsIn, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool allowSelectionFlag) { if (allowSelectionFlag) { m_treeWidget->setSelectionMode(QTreeWidget::ExtendedSelection); } else { m_treeWidget->setSelectionMode(QTreeWidget::NoSelection); } /* * Ignore items without children */ std::vector contentItems; for (std::vector::iterator contIter = contentItemsIn.begin(); contIter != contentItemsIn.end(); contIter++) { DisplayGroupAndTabItemInterface* item = *contIter; if (item->getNumberOfItemChildren() > 0) { contentItems.push_back(item); } } /* * Updating the tree will cause signals so block them until update is done */ m_treeWidget->blockSignals(true); const int32_t numExistingChildren = m_treeWidget->topLevelItemCount(); const int32_t numValidChildren = contentItems.size(); const int32_t numberOfChildrenToAdd = numValidChildren - numExistingChildren; for (int32_t i = 0; i < numberOfChildrenToAdd; i++) { m_treeWidget->addTopLevelItem(new DisplayGroupAndTabItemTreeWidgetItem(m_browserWindowIndex)); } CaretAssert(m_treeWidget->topLevelItemCount() >= numValidChildren); for (int32_t i = 0; i < numValidChildren; i++) { QTreeWidgetItem* treeWidgetChild = m_treeWidget->topLevelItem(i); CaretAssert(treeWidgetChild); DisplayGroupAndTabItemTreeWidgetItem* dgtChild = dynamic_cast(treeWidgetChild); CaretAssert(dgtChild); treeWidgetChild->setHidden(false); CaretAssertVectorIndex(contentItems, i); CaretAssert(contentItems[i]); DisplayGroupAndTabItemInterface* displayGroupAndTabItem = contentItems[i]; dgtChild->updateContent(displayGroupAndTabItem, m_treeWidget, displayGroup, tabIndex); } for (int32_t i = (numExistingChildren - 1); i >= numValidChildren; i--) { /* * Take removes it from the parent but * does not destruct it. */ QTreeWidgetItem* item = m_treeWidget->takeTopLevelItem(i); delete item; } updateSelectedAndExpandedCheckboxes(displayGroup, tabIndex); /* * Allow signals now that updating is done */ m_treeWidget->blockSignals(false); } /** * Update graphics and, in some circumstances, surface node coloring. */ void DisplayGroupAndTabItemViewController::updateGraphics() { EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Update the selected and expanded checkboxes. */ void DisplayGroupAndTabItemViewController::updateSelectedAndExpandedCheckboxes(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) { m_treeWidget->blockSignals(true); const int32_t numChildren = m_treeWidget->topLevelItemCount(); for (int32_t itemIndex = 0; itemIndex < numChildren; itemIndex++) { QTreeWidgetItem* treeChild = m_treeWidget->topLevelItem(itemIndex); CaretAssert(treeChild); DisplayGroupAndTabItemTreeWidgetItem* item = dynamic_cast(treeChild); CaretAssert(item); DisplayGroupAndTabItemInterface* data = item->getDisplayGroupAndTabItem(); if (data != NULL) { item->updateSelectedAndExpandedCheckboxes(displayGroup, tabIndex); } } const bool itemsSelectedFlag = ( ! m_treeWidget->selectedItems().isEmpty()); m_turnOnSelectedItemsAction->setEnabled(itemsSelectedFlag); m_turnOffSelectedItemsAction->setEnabled(itemsSelectedFlag); m_treeWidget->blockSignals(false); } /** * Update the selection and expansion controls in ALL other view controllers. * All of them need to be updated since window annotation selection is not * affected by the display group and tab selection. */ void DisplayGroupAndTabItemViewController::updateSelectedAndExpandedCheckboxesInOtherViewControllers() { for (std::set::iterator iter = s_allViewControllers.begin(); iter != s_allViewControllers.end(); iter++) { DisplayGroupAndTabItemViewController* otherViewController = *iter; if (otherViewController != this) { if (otherViewController->m_dataFileType == m_dataFileType) { DisplayGroupEnum::Enum otherDisplayGroup = DisplayGroupEnum::DISPLAY_GROUP_TAB; int32_t otherTabIndex = -1; otherViewController->getDisplayGroupAndTabIndex(otherDisplayGroup, otherTabIndex); otherViewController->updateSelectedAndExpandedCheckboxes(otherDisplayGroup, otherTabIndex); } } } } /** * Turn on all selected items */ void DisplayGroupAndTabItemViewController::turnOnSelectedItemsTriggered() { setCheckedStatusOfSelectedItems(true); } /** * Turn off all selected items */ void DisplayGroupAndTabItemViewController::turnOffSelectedItemsTriggered() { setCheckedStatusOfSelectedItems(false); } /** * Set the checked status of all selected itemsj * * @param checkedStatus * Checked status */ void DisplayGroupAndTabItemViewController::setCheckedStatusOfSelectedItems(const bool checkedStatus) { QList itemsSelected = m_treeWidget->selectedItems(); if (itemsSelected.isEmpty()) { return; } DisplayGroupEnum::Enum displayGroup = DisplayGroupEnum::DISPLAY_GROUP_TAB; int32_t tabIndex = -1; getDisplayGroupAndTabIndex(displayGroup, tabIndex); const Qt::CheckState newCheckState = (checkedStatus ? Qt::Checked : Qt::Unchecked); QListIterator iter(itemsSelected); while (iter.hasNext()) { QTreeWidgetItem* item = iter.next(); DisplayGroupAndTabItemInterface* dataItem = getDataItem(item); const TriStateSelectionStatusEnum::Enum itemCheckState = DisplayGroupAndTabItemTreeWidgetItem::fromQCheckState(newCheckState); dataItem->setItemDisplaySelected(displayGroup, tabIndex, itemCheckState); } updateSelectedAndExpandedCheckboxes(displayGroup, tabIndex); updateSelectedAndExpandedCheckboxesInOtherViewControllers(); updateGraphics();} connectome-workbench-1.4.2/src/GuiQt/DisplayGroupAndTabItemViewController.h000066400000000000000000000102711360521144700270370ustar00rootroot00000000000000#ifndef __DISPLAY_GROUP_AND_TAB_ITEM_VIEW_CONTROLLER_H__ #define __DISPLAY_GROUP_AND_TAB_ITEM_VIEW_CONTROLLER_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "DataFileTypeEnum.h" #include "DisplayGroupEnum.h" class QAction; class QTreeWidget; class QTreeWidgetItem; namespace caret { class DisplayGroupAndTabItemInterface; class DisplayGroupAndTabItemTreeWidgetItem; class DisplayGroupAndTabItemViewController : public QWidget { Q_OBJECT public: DisplayGroupAndTabItemViewController(const DataFileTypeEnum::Enum dataFileType, const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~DisplayGroupAndTabItemViewController(); void updateContent(std::vector& contentItemsIn, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const bool allowSelectionFlag); // ADD_NEW_METHODS_HERE private slots: void itemWasCollapsed(QTreeWidgetItem* item); void itemWasExpanded(QTreeWidgetItem* item); void itemWasChanged(QTreeWidgetItem* item, int column); void itemsWereSelected(); void displayContextMenu(const QPoint& pos); void turnOnSelectedItemsTriggered(); void turnOffSelectedItemsTriggered(); private: DisplayGroupAndTabItemViewController(const DisplayGroupAndTabItemViewController&); DisplayGroupAndTabItemViewController& operator=(const DisplayGroupAndTabItemViewController&); DisplayGroupAndTabItemInterface *m_displayGroupAndTabItem; void getDisplayGroupAndTabIndex(DisplayGroupEnum::Enum& displayGroupOut, int32_t& tabIndexOut) const; void processItemExpanded(QTreeWidgetItem* item, const bool expandedStatus); void processAnnotationDataSelection(const std::vector& interfaceItems); DisplayGroupAndTabItemInterface* getDataItem(QTreeWidgetItem* item) const; void updateGraphics(); void updateSelectedAndExpandedCheckboxes(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex); void updateSelectedAndExpandedCheckboxesInOtherViewControllers(); void setCheckedStatusOfSelectedItems(const bool checkedFlag); const DataFileTypeEnum::Enum m_dataFileType; const int32_t m_browserWindowIndex; QTreeWidget* m_treeWidget; QAction* m_turnOnSelectedItemsAction; QAction* m_turnOffSelectedItemsAction; static std::set s_allViewControllers; // ADD_NEW_MEMBERS_HERE }; #ifdef __DISPLAY_GROUP_AND_TAB_ITEM_VIEW_CONTROLLER_DECLARE__ std::set DisplayGroupAndTabItemViewController::s_allViewControllers; #endif // __DISPLAY_GROUP_AND_TAB_ITEM_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__DISPLAY_GROUP_AND_TAB_ITEM_VIEW_CONTROLLER_H__ connectome-workbench-1.4.2/src/GuiQt/DisplayGroupEnumComboBox.cxx000066400000000000000000000134441360521144700251050ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __DISPLAY_GROUP_ENUM_COMBO_BOX_DECLARE__ #include "DisplayGroupEnumComboBox.h" #undef __DISPLAY_GROUP_ENUM_COMBO_BOX_DECLARE__ #include "WuQMacroManager.h" using namespace caret; /** * \class caret::DisplayGroupEnumComboBox * \brief Combo box for selection of a display group. * \ingroup GuiQt * * Encapsulates a QComboBox for the selection of a * DisplayGroupEnum value. QComboBox is not extended * to prevent access to its methods that could cause * the selection to get messed up. */ /** * Constructor. * @param Parent * Parent object. */ DisplayGroupEnumComboBox::DisplayGroupEnumComboBox(QObject* parent) : DisplayGroupEnumComboBox(parent, "", "") { } //: WuQWidget(parent) //{ // std::vector allDisplayGroups; // DisplayGroupEnum::getAllEnums(allDisplayGroups); // const int32_t numStructures = static_cast(allDisplayGroups.size()); // // this->displayGroupComboBox = new QComboBox(); // for (int32_t i = 0; i < numStructures; i++) { // this->displayGroupComboBox->addItem(DisplayGroupEnum::toGuiName(allDisplayGroups[i])); // this->displayGroupComboBox->setItemData(i, DisplayGroupEnum::toIntegerCode(allDisplayGroups[i])); // } // // QObject::connect(this->displayGroupComboBox, SIGNAL(activated(int)), // this, SLOT(displayGroupComboBoxSelection(int))); //} /** * Constructor. * @param Parent * Parent object. * @param objectNameForMacros * Name of object for macros * @param descriptiveNameForMacros * Descriptive name for macros */ DisplayGroupEnumComboBox::DisplayGroupEnumComboBox(QObject* parent, const QString& objectNameForMacros, const QString& descriptiveNameForMacros) : WuQWidget(parent) { std::vector allDisplayGroups; DisplayGroupEnum::getAllEnums(allDisplayGroups); const int32_t numStructures = static_cast(allDisplayGroups.size()); this->displayGroupComboBox = new QComboBox(); for (int32_t i = 0; i < numStructures; i++) { this->displayGroupComboBox->addItem(DisplayGroupEnum::toGuiName(allDisplayGroups[i])); this->displayGroupComboBox->setItemData(i, DisplayGroupEnum::toIntegerCode(allDisplayGroups[i])); } QObject::connect(this->displayGroupComboBox, SIGNAL(activated(int)), this, SLOT(displayGroupComboBoxSelection(int))); if ( ! objectNameForMacros.isEmpty()) { this->displayGroupComboBox->setToolTip("Select Display Group"); this->displayGroupComboBox->setObjectName(objectNameForMacros); WuQMacroManager::instance()->addMacroSupportToObject(this->displayGroupComboBox, "Select display group for " + descriptiveNameForMacros); } } /** * Destructor. */ DisplayGroupEnumComboBox::~DisplayGroupEnumComboBox() { } /** * @return The selected display group. */ DisplayGroupEnum::Enum DisplayGroupEnumComboBox::getSelectedDisplayGroup() const { DisplayGroupEnum::Enum displayGroup = DisplayGroupEnum::getDefaultValue(); const int32_t indx = this->displayGroupComboBox->currentIndex(); if (indx >= 0) { const int32_t integerCode = this->displayGroupComboBox->itemData(indx).toInt(); displayGroup = DisplayGroupEnum::fromIntegerCode(integerCode, NULL); } return displayGroup; } /** * @return The widget (combo box) for adding to layout. */ QWidget* DisplayGroupEnumComboBox::getWidget() { return this->displayGroupComboBox; } /** * Set the display group. * @param displayGroup * New value for display group. */ void DisplayGroupEnumComboBox::setSelectedDisplayGroup(const DisplayGroupEnum::Enum displayGroup) { const int32_t displayGroupIntegerCode = DisplayGroupEnum::toIntegerCode(displayGroup); const int numStructures = this->displayGroupComboBox->count(); for (int32_t i = 0; i < numStructures; i++) { if (displayGroupIntegerCode == this->displayGroupComboBox->itemData(i).toInt()) { if (this->signalsBlocked()) { this->displayGroupComboBox->blockSignals(true); } this->displayGroupComboBox->setCurrentIndex(i); if (this->signalsBlocked()) { this->displayGroupComboBox->blockSignals(false); } break; } } } /** * Called when a display group is selected (receives signal) * @param indx * Index of selected item. */ void DisplayGroupEnumComboBox::displayGroupComboBoxSelection(int indx) { if (this->signalsBlocked() == false) { const int32_t integerCode = this->displayGroupComboBox->itemData(indx).toInt(); DisplayGroupEnum::Enum displayGroup = DisplayGroupEnum::fromIntegerCode(integerCode, NULL); emit displayGroupSelected(displayGroup); } } connectome-workbench-1.4.2/src/GuiQt/DisplayGroupEnumComboBox.h000066400000000000000000000042731360521144700245320ustar00rootroot00000000000000#ifndef __DISPLAY_GROUP_ENUM_COMBO_BOX__H_ #define __DISPLAY_GROUP_ENUM_COMBO_BOX__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "DisplayGroupEnum.h" #include "WuQWidget.h" class QComboBox; namespace caret { class DisplayGroupEnumComboBox : public WuQWidget { Q_OBJECT public: DisplayGroupEnumComboBox(QObject* parent); DisplayGroupEnumComboBox(QObject* parent, const QString& objectNameForMacros, const QString& descriptiveNameForMacros); virtual ~DisplayGroupEnumComboBox(); DisplayGroupEnum::Enum getSelectedDisplayGroup() const; QWidget* getWidget(); public slots: void setSelectedDisplayGroup(const DisplayGroupEnum::Enum displayGroup); signals: void displayGroupSelected(const DisplayGroupEnum::Enum); private slots: void displayGroupComboBoxSelection(int); private: DisplayGroupEnumComboBox(const DisplayGroupEnumComboBox&); DisplayGroupEnumComboBox& operator=(const DisplayGroupEnumComboBox&); QComboBox* displayGroupComboBox; }; #ifdef __DISPLAY_GROUP_ENUM_COMBO_BOX_DECLARE__ // #endif // __DISPLAY_GROUP_ENUM_COMBO_BOX_DECLARE__ } // namespace #endif //__DISPLAY_GROUP_ENUM_COMBO_BOX__H_ connectome-workbench-1.4.2/src/GuiQt/EnumComboBoxTemplate.h000066400000000000000000000167201360521144700236630ustar00rootroot00000000000000#ifndef __ENUM_COMBOBOX_TEMPLATE__H_ #define __ENUM_COMBOBOX_TEMPLATE__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AString.h" #include "WuQFactory.h" #include "WuQWidget.h" /** * \class caret::EnumComboBoxTemplate * \brief Create a combo box for a workbench enumerated type. * \ingroup GuiQt * * Create a combo box for a workbench enumerated type. Typically, * the enumerated types are created with wb_command: * wb_command.app/Contents/MacOS/wb_command -class-create-enum LabelDrawingTypeEnum 2 true * * This class is not a template class because QObject subclasses may * not be templates. See http://doc.trolltech.com/qq/qq15-academic.html * While the class cannot be a template, methods in the class be templates. * *

    * How to Use This Class *

    * Declare:
    * EnumComboBoxTemplate* m_someTypeComboBox; * *

    * Construct:
    * m_someTypeComboBox = new EnumComboBoxTemplate(this);
    * m_someTypeComboBox->setup();
    * *

    * Read:
    * const SomeTypeEnum::Enum enumValue = m_someTypeComboBox->getSelectedItem(); * *

    * Set:
    * m_someTypeComboBox->setSelectedItem(enumValue); * *

    * Get notified when user makes selection:
    * See itemActivated() and itemChanged(). * */ namespace caret { class EnumComboBoxTemplate : public WuQWidget { Q_OBJECT public: /** * Constructor. * @param parent * Parent object. */ EnumComboBoxTemplate(QObject* parent) : WuQWidget(parent) { m_itemComboBox = WuQFactory::newComboBox(); QObject::connect(m_itemComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(itemComboBoxIndexChanged(int))); QObject::connect(m_itemComboBox, SIGNAL(activated(int)), this, SLOT(itemComboBoxActivated(int))); } /** * Destructor. */ virtual ~EnumComboBoxTemplate() { } /** * Setup the combo box. */ template void setup() { std::vector allEnums; CT::getAllEnums(allEnums); m_itemComboBox->blockSignals(true); m_itemComboBox->clear(); const int32_t numColors = static_cast(allEnums.size()); for (int32_t i = 0; i < numColors; i++) { const ET enumValue = allEnums[i]; const int32_t indx = m_itemComboBox->count(); const AString name = CT::toGuiName(enumValue); m_itemComboBox->addItem(name); m_itemComboBox->setItemData(indx, CT::toIntegerCode(enumValue)); } m_itemComboBox->blockSignals(false); } /** * Setup the combo box. */ template void setupWithItems(const std::vector& comboBoxItems) { m_itemComboBox->blockSignals(true); m_itemComboBox->clear(); const int32_t numColors = static_cast(comboBoxItems.size()); for (int32_t i = 0; i < numColors; i++) { const ET enumValue = comboBoxItems[i]; const int32_t indx = m_itemComboBox->count(); const AString name = CT::toGuiName(enumValue); m_itemComboBox->addItem(name); m_itemComboBox->setItemData(indx, CT::toIntegerCode(enumValue)); } m_itemComboBox->blockSignals(false); } /** * @return The selected item. */ template ET getSelectedItem() const { const int32_t indx = m_itemComboBox->currentIndex(); const int32_t integerCode = m_itemComboBox->itemData(indx).toInt(); ET item = CT::fromIntegerCode(integerCode, NULL); return item; } /** * Set the selected item. * @param item * New item for selection. */ template void setSelectedItem(const ET item) { const int32_t numItems = static_cast(m_itemComboBox->count()); for (int32_t i = 0; i < numItems; i++) { const int32_t integerCode = m_itemComboBox->itemData(i).toInt(); ET enumValue = CT::fromIntegerCode(integerCode, NULL); if (enumValue == item) { m_itemComboBox->blockSignals(true); m_itemComboBox->setCurrentIndex(i); m_itemComboBox->blockSignals(false); break; } } } /** * @return The actual widget. */ virtual QWidget* getWidget() { return m_itemComboBox; } /** * @return The actual combo box. */ QComboBox* getComboBox() { return m_itemComboBox; } signals: /** * This signal is sent when the user chooses an item in the combobox. * The item's index is passed. Note that this signal is sent even * when the choice is not changed. If you need to know when the * choice actually changes, use signal itemChanged(). */ void itemActivated(); /** * This signal is sent whenever the currentIndex in the * combobox changes either through user interaction or * programmatically. */ void itemChanged(); private slots: /** * Called when the user selects an item * @param indx * Index of item selected. */ void itemComboBoxIndexChanged(int) { emit itemChanged(); } /** * Called when the user selects an item * @param indx * Index of item selected. */ void itemComboBoxActivated(int) { emit itemActivated(); } private: EnumComboBoxTemplate(const EnumComboBoxTemplate&); EnumComboBoxTemplate& operator=(const EnumComboBoxTemplate&); private: QComboBox* m_itemComboBox; }; #ifdef __ENUM_COMBOBOX_TEMPLATE_DECLARE__ // #endif // __ENUM_COMBOBOX_TEMPLATE_DECLARE__ } // namespace #endif //__ENUM_COMBOBOX_TEMPLATE__H_ connectome-workbench-1.4.2/src/GuiQt/EventAnnotationCreateNewType.cxx000066400000000000000000000046301360521144700257560ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_ANNOTATION_CREATE_NEW_TYPE_DECLARE__ #include "EventAnnotationCreateNewType.h" #undef __EVENT_ANNOTATION_CREATE_NEW_TYPE_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventAnnotationCreateNewType * \brief Event that starts creationg of a new annotation with the annotation type. * \ingroup GuiQt */ /** * Constructor. * * @param annotationSpace * Space for new annotation. * @param annotationType * Type for new annotation. * */ EventAnnotationCreateNewType::EventAnnotationCreateNewType(AnnotationFile* annotationFile, const AnnotationCoordinateSpaceEnum::Enum annotationSpace, const AnnotationTypeEnum::Enum annotationType) : Event(EventTypeEnum::EVENT_ANNOTATION_CREATE_NEW_TYPE), m_annotationFile(annotationFile), m_annotationSpace(annotationSpace), m_annotationType(annotationType) { } /** * Destructor. */ EventAnnotationCreateNewType::~EventAnnotationCreateNewType() { } /** * @return Annotation file for new anotation. */ AnnotationFile* EventAnnotationCreateNewType::getAnnotationFile() const { return m_annotationFile; } /** * @return Space of annotation for creation. */ AnnotationCoordinateSpaceEnum::Enum EventAnnotationCreateNewType::getAnnotationSpace() const { return m_annotationSpace; } /** * @return Type of annotation for creation. */ AnnotationTypeEnum::Enum EventAnnotationCreateNewType::getAnnotationType() const { return m_annotationType; } connectome-workbench-1.4.2/src/GuiQt/EventAnnotationCreateNewType.h000066400000000000000000000044631360521144700254070ustar00rootroot00000000000000#ifndef __EVENT_ANNOTATION_CREATE_NEW_TYPE_H__ #define __EVENT_ANNOTATION_CREATE_NEW_TYPE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationCoordinateSpaceEnum.h" #include "AnnotationTypeEnum.h" #include "Event.h" namespace caret { class AnnotationFile; class EventAnnotationCreateNewType : public Event { public: EventAnnotationCreateNewType(AnnotationFile* annotationFile, const AnnotationCoordinateSpaceEnum::Enum annotationSpace, const AnnotationTypeEnum::Enum annotationType); virtual ~EventAnnotationCreateNewType(); AnnotationFile* getAnnotationFile() const; AnnotationCoordinateSpaceEnum::Enum getAnnotationSpace() const; AnnotationTypeEnum::Enum getAnnotationType() const; // ADD_NEW_METHODS_HERE private: EventAnnotationCreateNewType(const EventAnnotationCreateNewType&); EventAnnotationCreateNewType& operator=(const EventAnnotationCreateNewType&); AnnotationFile* m_annotationFile; const AnnotationCoordinateSpaceEnum::Enum m_annotationSpace; const AnnotationTypeEnum::Enum m_annotationType; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_ANNOTATION_CREATE_NEW_TYPE_DECLARE__ // #endif // __EVENT_ANNOTATION_CREATE_NEW_TYPE_DECLARE__ } // namespace #endif //__EVENT_ANNOTATION_CREATE_NEW_TYPE_H__ connectome-workbench-1.4.2/src/GuiQt/EventAnnotationGetDrawnInWindow.cxx000066400000000000000000000044431360521144700264330ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_ANNOTATION_GET_DRAWN_IN_WINDOW_DECLARE__ #include "EventAnnotationGetDrawnInWindow.h" #undef __EVENT_ANNOTATION_GET_DRAWN_IN_WINDOW_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventAnnotationGetDrawnInWindow * \brief Event to get annotations that are drawn in a window. * \ingroup GuiQt */ /** * Constructor. * * @param windowIndex * Index of window. */ EventAnnotationGetDrawnInWindow::EventAnnotationGetDrawnInWindow(const int32_t windowIndex) : Event(EventTypeEnum::EVENT_ANNOTATION_GET_DRAWN_IN_WINDOW), m_windowIndex(windowIndex) { } /** * Destructor. */ EventAnnotationGetDrawnInWindow::~EventAnnotationGetDrawnInWindow() { } /** * @return Index of the window. */ int32_t EventAnnotationGetDrawnInWindow::getWindowIndex() const { return m_windowIndex; } /** * Add annotations that were drawn in the requested window. * * @param annotations * Annotations added. */ void EventAnnotationGetDrawnInWindow::addAnnotations(const std::vector& annotations) { m_annotations.insert(m_annotations.end(), annotations.begin(), annotations.end()); } /** * Get annotations that were drawn in the requested window. * * @param annotationsOut * Annotations output. */ void EventAnnotationGetDrawnInWindow::getAnnotations(std::vector& annotationsOut) const { annotationsOut = m_annotations; } connectome-workbench-1.4.2/src/GuiQt/EventAnnotationGetDrawnInWindow.h000066400000000000000000000037711360521144700260630ustar00rootroot00000000000000#ifndef __EVENT_ANNOTATION_GET_DRAWN_IN_WINDOW_H__ #define __EVENT_ANNOTATION_GET_DRAWN_IN_WINDOW_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class Annotation; class EventAnnotationGetDrawnInWindow : public Event { public: EventAnnotationGetDrawnInWindow(const int32_t windowIndex); virtual ~EventAnnotationGetDrawnInWindow(); int32_t getWindowIndex() const; void addAnnotations(const std::vector& annotations); void getAnnotations(std::vector& annotationsOut) const; // ADD_NEW_METHODS_HERE private: EventAnnotationGetDrawnInWindow(const EventAnnotationGetDrawnInWindow&); EventAnnotationGetDrawnInWindow& operator=(const EventAnnotationGetDrawnInWindow&); const int32_t m_windowIndex; std::vector m_annotations; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_ANNOTATION_GET_DRAWN_IN_WINDOW_DECLARE__ // #endif // __EVENT_ANNOTATION_GET_DRAWN_IN_WINDOW_DECLARE__ } // namespace #endif //__EVENT_ANNOTATION_GET_DRAWN_IN_WINDOW_H__ connectome-workbench-1.4.2/src/GuiQt/EventBrowserWindowCreateTabs.cxx000066400000000000000000000031321360521144700257510ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_BROWSER_WINDOW_CREATE_TABS_DECLARE__ #include "EventBrowserWindowCreateTabs.h" #undef __EVENT_BROWSER_WINDOW_CREATE_TABS_DECLARE__ using namespace caret; /** * \class caret::EventBrowserWindowCreateTabs * \brief If needed, create browser tabs after loading a spec or data files * \ingroup GuiQt */ /** * Constructor. * @param mode * Mode for tab creation. */ EventBrowserWindowCreateTabs::EventBrowserWindowCreateTabs(const Mode mode) : Event(EventTypeEnum::EVENT_BROWSER_WINDOW_CREATE_TABS), m_mode(mode) { } /** * Destructor. */ EventBrowserWindowCreateTabs::~EventBrowserWindowCreateTabs() { } /** * @return The mode. */ EventBrowserWindowCreateTabs::Mode EventBrowserWindowCreateTabs::getMode() const { return m_mode; } connectome-workbench-1.4.2/src/GuiQt/EventBrowserWindowCreateTabs.h000066400000000000000000000035031360521144700254000ustar00rootroot00000000000000#ifndef __EVENT_BROWSER_WINDOW_CREATE_TABS__H_ #define __EVENT_BROWSER_WINDOW_CREATE_TABS__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class EventBrowserWindowCreateTabs : public Event { public: enum Mode { MODE_LOADED_DATA_FILE, MODE_LOADED_SPEC_FILE }; EventBrowserWindowCreateTabs(const Mode mode); virtual ~EventBrowserWindowCreateTabs(); Mode getMode() const; private: EventBrowserWindowCreateTabs(const EventBrowserWindowCreateTabs&); EventBrowserWindowCreateTabs& operator=(const EventBrowserWindowCreateTabs&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE const Mode m_mode; }; #ifdef __EVENT_BROWSER_WINDOW_CREATE_TABS_DECLARE__ // #endif // __EVENT_BROWSER_WINDOW_CREATE_TABS_DECLARE__ } // namespace #endif //__EVENT_BROWSER_WINDOW_CREATE_TABS__H_ connectome-workbench-1.4.2/src/GuiQt/EventBrowserWindowDrawingContent.cxx000066400000000000000000000100411360521144700266570ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventBrowserWindowDrawingContent.h" using namespace caret; #include "CaretAssert.h" /** * \class caret::EventBrowserWindowDrawingContent * \brief Event to get content for drawing browser window. * \ingroup GuiQt */ /** * Constructor. * @param browserWindowIndex * Index of browser window. */ EventBrowserWindowDrawingContent::EventBrowserWindowDrawingContent(const int32_t browserWindowIndex) : Event(EventTypeEnum::EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET) { m_browserWindowContent = NULL; m_browserWindowIndex = browserWindowIndex; m_tabIndexForTileTabsHighlighting = -1; m_selectedBrowserTabContent = NULL; } /* * Destructor. */ EventBrowserWindowDrawingContent::~EventBrowserWindowDrawingContent() { } /** * @return Get the browser window index. */ int32_t EventBrowserWindowDrawingContent::getBrowserWindowIndex() const { return m_browserWindowIndex; } /** * @return The number of browser tabs in window */ int32_t EventBrowserWindowDrawingContent::getNumberOfBrowserTabs() const { return this->browserTabContents.size(); } /** * Add browser tab */ void EventBrowserWindowDrawingContent::addBrowserTab(BrowserTabContent* browserTabContent) { this->browserTabContents.push_back(browserTabContent); } /** * Get the browser tab at the given index * * @param itemIndex * Index of the item to browser tab. * @return * Pointer to tab contents for the item index. */ BrowserTabContent* EventBrowserWindowDrawingContent::getBrowserTab(const int32_t itemIndex) { CaretAssertVectorIndex(this->browserTabContents, itemIndex); return this->browserTabContents[itemIndex]; } /** * Set index of tab for highlighting in tile tabs mode. * * @param tabIndex * Index of tab for highlighting. */ void EventBrowserWindowDrawingContent::setTabIndexForTileTabsHighlighting(const int32_t tabIndex) { m_tabIndexForTileTabsHighlighting = tabIndex; } /** * @return Index of tab for highlighting in Tile Tabs mode. */ int32_t EventBrowserWindowDrawingContent::getTabIndexForTileTabsHighlighting() const { return m_tabIndexForTileTabsHighlighting; } /** * @return The selected browser tab content. May be NULL. * In single tab mode, this is the tab to draw. */ BrowserTabContent* EventBrowserWindowDrawingContent::getSelectedBrowserTabContent() { return m_selectedBrowserTabContent; } /** * Set the selected browser tab content. * * @param browserTabContent * The selected browser tab content. */ void EventBrowserWindowDrawingContent::setSelectedBrowserTabContent(BrowserTabContent* browserTabContent) { m_selectedBrowserTabContent = browserTabContent; } /** * @return Browser window content. */ BrowserWindowContent* EventBrowserWindowDrawingContent::getBrowserWindowContent() { return m_browserWindowContent; } /** * @return Browser window content (const method) */ const BrowserWindowContent* EventBrowserWindowDrawingContent::getBrowserWindowContent() const { return m_browserWindowContent; } /** * Set the browser window content. * * @param browserWindowContent * New content. */ void EventBrowserWindowDrawingContent::setBrowserWindowContent(BrowserWindowContent* browserWindowContent) { m_browserWindowContent = browserWindowContent; } connectome-workbench-1.4.2/src/GuiQt/EventBrowserWindowDrawingContent.h000066400000000000000000000056221360521144700263150ustar00rootroot00000000000000#ifndef __EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET_H__ #define __EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class BrowserTabContent; class BrowserWindowContent; class Model; class TileTabsConfiguration; /// Get the content of a browser window class EventBrowserWindowDrawingContent : public Event { public: EventBrowserWindowDrawingContent(const int32_t browserWindowIndex); virtual ~EventBrowserWindowDrawingContent(); int32_t getBrowserWindowIndex() const; int32_t getNumberOfBrowserTabs() const; void addBrowserTab(BrowserTabContent* browserTabContent); BrowserTabContent* getBrowserTab(const int32_t itemIndex); void setTabIndexForTileTabsHighlighting(const int32_t tabIndex); int32_t getTabIndexForTileTabsHighlighting() const; BrowserWindowContent* getBrowserWindowContent(); const BrowserWindowContent* getBrowserWindowContent() const; void setBrowserWindowContent(BrowserWindowContent* browserWindowContent); BrowserTabContent* getSelectedBrowserTabContent(); void setSelectedBrowserTabContent(BrowserTabContent* browserTabContent); private: EventBrowserWindowDrawingContent(const EventBrowserWindowDrawingContent&); EventBrowserWindowDrawingContent& operator=(const EventBrowserWindowDrawingContent&); BrowserTabContent* m_selectedBrowserTabContent; /** index of browswer window */ int32_t m_browserWindowIndex; /** all browser tabs in the window */ std::vector browserTabContents; /** content of browser window */ BrowserWindowContent* m_browserWindowContent; /** Index of tab that is highlighted in Tile Tabs mode */ int32_t m_tabIndexForTileTabsHighlighting; }; } // namespace #endif // __EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET_H__ connectome-workbench-1.4.2/src/GuiQt/EventBrowserWindowGraphicsRedrawn.cxx000066400000000000000000000037531360521144700270300ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_BROWSER_WINDOW_GRAPHICS_REDRAWN_DECLARE__ #include "EventBrowserWindowGraphicsRedrawn.h" #undef __EVENT_BROWSER_WINDOW_GRAPHICS_REDRAWN_DECLARE__ #include "BrainBrowserWindow.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventBrowserWindowGraphicsRedrawn * \brief Event issued when a browser windows graphics are redrawn. * \ingroup GuiQt */ /** * Constructor. */ EventBrowserWindowGraphicsRedrawn::EventBrowserWindowGraphicsRedrawn(BrainBrowserWindow* brainBrowserWindow) : Event(EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN) { m_brainBrowserWindow = brainBrowserWindow; m_brainBrowserWindowIndex = m_brainBrowserWindow->getBrowserWindowIndex(); } /** * Destructor. */ EventBrowserWindowGraphicsRedrawn::~EventBrowserWindowGraphicsRedrawn() { } /** * @return Browser window that was redrawn. */ BrainBrowserWindow* EventBrowserWindowGraphicsRedrawn::getBrowserWindow() const { return m_brainBrowserWindow; } /** * @return Index of browser window that was redrawn. */ int32_t EventBrowserWindowGraphicsRedrawn::getBrowserWindowIndex() const { return m_brainBrowserWindowIndex; } connectome-workbench-1.4.2/src/GuiQt/EventBrowserWindowGraphicsRedrawn.h000066400000000000000000000037601360521144700264530ustar00rootroot00000000000000#ifndef __EVENT_BROWSER_WINDOW_GRAPHICS_REDRAWN_H__ #define __EVENT_BROWSER_WINDOW_GRAPHICS_REDRAWN_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class BrainBrowserWindow; class EventBrowserWindowGraphicsRedrawn : public Event { public: EventBrowserWindowGraphicsRedrawn(BrainBrowserWindow* brainBrowserWindow); virtual ~EventBrowserWindowGraphicsRedrawn(); BrainBrowserWindow* getBrowserWindow() const; int32_t getBrowserWindowIndex() const; private: EventBrowserWindowGraphicsRedrawn(const EventBrowserWindowGraphicsRedrawn&); EventBrowserWindowGraphicsRedrawn& operator=(const EventBrowserWindowGraphicsRedrawn&); public: // ADD_NEW_METHODS_HERE private: BrainBrowserWindow* m_brainBrowserWindow; int32_t m_brainBrowserWindowIndex; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_BROWSER_WINDOW_GRAPHICS_REDRAWN_DECLARE__ // #endif // __EVENT_BROWSER_WINDOW_GRAPHICS_REDRAWN_DECLARE__ } // namespace #endif //__EVENT_BROWSER_WINDOW_GRAPHICS_REDRAWN_H__ connectome-workbench-1.4.2/src/GuiQt/EventBrowserWindowNew.cxx000066400000000000000000000050711360521144700244710ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventBrowserWindowNew.h" using namespace caret; /** * \class caret::EventBrowserWindowNew * \brief Event Issued to create a new browser window * \ingroup GuiQt */ /** * Constructor. * @param parent * Widget used for window placement (may be NULL). * @param browserTabContent * Initial content for window (may be NULL). */ EventBrowserWindowNew::EventBrowserWindowNew(QWidget* parent, BrowserTabContent* browserTabContent) : Event(EventTypeEnum::EVENT_BROWSER_WINDOW_NEW) { this->parent = parent; this->browserTabContent = browserTabContent; this->browserWindowCreated = NULL; } /** * Constructor. */ EventBrowserWindowNew::EventBrowserWindowNew() : Event(EventTypeEnum::EVENT_BROWSER_WINDOW_NEW) { this->browserTabContent = NULL; } /* * Destructor. */ EventBrowserWindowNew::~EventBrowserWindowNew() { } /** * @return Parent for placement of new window (my be NULL). */ QWidget* EventBrowserWindowNew::getParent() { return this->parent; } /** * Returns the tab content for the window. If the * returned value is NULL, then a new tab should be * created. * * @return Returns the browser tab content. */ BrowserTabContent* EventBrowserWindowNew::getBrowserTabContent() const { return this->browserTabContent; } /** * @return The browser window that was created. */ BrainBrowserWindow* EventBrowserWindowNew::getBrowserWindowCreated() const { return this->browserWindowCreated; } /** * Set the browser window that was created. * param browserWindowCreated * Browser window that was created. */ void EventBrowserWindowNew::setBrowserWindowCreated(BrainBrowserWindow* browserWindowCreated) { this->browserWindowCreated = browserWindowCreated; } connectome-workbench-1.4.2/src/GuiQt/EventBrowserWindowNew.h000066400000000000000000000041271360521144700241170ustar00rootroot00000000000000#ifndef __EVENT_BROWSER_WINDOW_NEW_H__ #define __EVENT_BROWSER_WINDOW_NEW_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" class QWidget; namespace caret { class BrainBrowserWindow; class BrowserTabContent; /// Create a new browser window class EventBrowserWindowNew : public Event { public: EventBrowserWindowNew(); EventBrowserWindowNew(QWidget* parent, BrowserTabContent* browserTabContent); virtual ~EventBrowserWindowNew(); QWidget* getParent(); BrowserTabContent* getBrowserTabContent() const; BrainBrowserWindow* getBrowserWindowCreated() const; void setBrowserWindowCreated(BrainBrowserWindow* browserWindowCreated); private: EventBrowserWindowNew(const EventBrowserWindowNew&); EventBrowserWindowNew& operator=(const EventBrowserWindowNew&); /** Widget used for placement of new window */ QWidget* parent; /** If not NULL, contains tab for the new window */ BrowserTabContent* browserTabContent; /** Window that was created. */ BrainBrowserWindow* browserWindowCreated; }; } // namespace #endif // __EVENT_BROWSER_WINDOW_NEW_H__ connectome-workbench-1.4.2/src/GuiQt/EventBrowserWindowTileTabOperation.cxx000066400000000000000000000111561360521144700271460ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION_DECLARE__ #include "EventBrowserWindowTileTabOperation.h" #undef __EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION_DECLARE__ #include #include "CaretAssert.h" #include "EventManager.h" #include "EventTypeEnum.h" #include "WuQMessageBox.h" using namespace caret; /** * \class caret::EventBrowserWindowTileTabOperation * \brief Operations for tab changes * \ingroup GuiQt */ /** * Constructor. * * @param operation * The operation * @param parentWidget * Parent widget for error dialogs. * @param windowIndex * Index of the window. * @param browserTabIndex * Index of the browser tab. */ EventBrowserWindowTileTabOperation::EventBrowserWindowTileTabOperation(const Operation operation, QWidget* parentWidget, const int32_t windowIndex, const int32_t browserTabIndex, const std::vector& browserTabsForReplaceOperation) : Event(EventTypeEnum::EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION), m_operation(operation), m_parentWidget(parentWidget), m_windowIndex(windowIndex), m_browserTabIndex(browserTabIndex), m_browserTabsForReplaceOperation(browserTabsForReplaceOperation) { CaretAssert(m_parentWidget); CaretAssert(m_windowIndex >= 0); switch (m_operation) { case OPERATION_NEW_TAB_AFTER: CaretAssert(m_browserTabIndex >= 0); break; case OPERATION_NEW_TAB_BEFORE: CaretAssert(m_browserTabIndex >= 0); break; case OPERATION_REPLACE_TABS: break; case OPERATION_SELECT_TAB: CaretAssert(m_browserTabIndex >= 0); break; } } /** * Destructor. */ EventBrowserWindowTileTabOperation::~EventBrowserWindowTileTabOperation() { } /** * Operation that selects the given tab in the given window. * * @param parentWidget * Parent widget for error dialogs. * @param windowIndex * Index of the window. * @param browserTabIndex * Index of the browser tab. */ void EventBrowserWindowTileTabOperation::selectTabInWindow(QWidget* parentWidget, const int32_t windowIndex, const int32_t browserTabIndex) { std::vector emptyBrowserTabs; EventBrowserWindowTileTabOperation tabOperation(Operation::OPERATION_SELECT_TAB, parentWidget, windowIndex, browserTabIndex, emptyBrowserTabs); EventManager::get()->sendEvent(tabOperation.getPointer()); if (tabOperation.getEventProcessCount() <= 0) { WuQMessageBox::errorOk(parentWidget, "Tab not created, invalid window or tab index"); } } /** * @return The mode */ EventBrowserWindowTileTabOperation::Operation EventBrowserWindowTileTabOperation::getOperation() const { return m_operation; } /** * @return The window index. */ int32_t EventBrowserWindowTileTabOperation::getWindowIndex() const { return m_windowIndex; } /** * @return The browser tab index. */ int32_t EventBrowserWindowTileTabOperation::getBrowserTabIndex() const { return m_browserTabIndex; } /** * @return Get the browser tabs for a replace tabs operation. */ const std::vector EventBrowserWindowTileTabOperation::getBrowserTabsForReplaceOperation() const { return m_browserTabsForReplaceOperation; } connectome-workbench-1.4.2/src/GuiQt/EventBrowserWindowTileTabOperation.h000066400000000000000000000057461360521144700266030ustar00rootroot00000000000000#ifndef __EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION_H__ #define __EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "Event.h" class QWidget; namespace caret { class BrowserTabContent; class EventBrowserWindowTileTabOperation : public Event { public: static void selectTabInWindow(QWidget* parentWidget, const int32_t windowIndex, const int32_t browserTabIndex); enum Operation { OPERATION_NEW_TAB_AFTER, OPERATION_NEW_TAB_BEFORE, OPERATION_REPLACE_TABS, OPERATION_SELECT_TAB }; EventBrowserWindowTileTabOperation(const Operation operation, QWidget* parentWidget, const int32_t windowIndex, const int32_t browserTabIndex, const std::vector& browserTabsForReplaceOperation); virtual ~EventBrowserWindowTileTabOperation(); Operation getOperation() const; int32_t getWindowIndex() const; int32_t getBrowserTabIndex() const; const std::vector getBrowserTabsForReplaceOperation() const; // ADD_NEW_METHODS_HERE private: EventBrowserWindowTileTabOperation(const EventBrowserWindowTileTabOperation&); EventBrowserWindowTileTabOperation& operator=(const EventBrowserWindowTileTabOperation&); const Operation m_operation; QWidget* m_parentWidget; const int32_t m_windowIndex; const int32_t m_browserTabIndex; const std::vector m_browserTabsForReplaceOperation; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION_DECLARE__ // #endif // __EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION_DECLARE__ } // namespace #endif //__EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION_H__ connectome-workbench-1.4.2/src/GuiQt/EventGetOrSetUserInputModeProcessor.cxx000066400000000000000000000066441360521144700272730ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventGetOrSetUserInputModeProcessor.h" using namespace caret; /** * \class caret::EventGetOrSetUserInputModeProcessor * \brief Event that acts as a getter/setting for user input mode. * \ingroup GuiQt */ /** * Constructor for SETTING the user input mode. * * @param windowIndex * Index of the window for the user input mode. * @param userInputMode * The requested input mode. */ EventGetOrSetUserInputModeProcessor::EventGetOrSetUserInputModeProcessor(const int32_t windowIndex, const UserInputModeEnum::Enum userInputMode) : Event(EventTypeEnum::EVENT_GET_OR_SET_USER_INPUT_MODE) { this->userInputProcessor = NULL; this->userInputMode = userInputMode; this->windowIndex = windowIndex; this->modeGetOrSet = SET; } /** * Constructor for GETTING the user input mode. * * @param windowIndex * Index of the window for the user input mode. */ EventGetOrSetUserInputModeProcessor::EventGetOrSetUserInputModeProcessor(const int32_t windowIndex) : Event(EventTypeEnum::EVENT_GET_OR_SET_USER_INPUT_MODE) { this->userInputProcessor = NULL; this->userInputMode = UserInputModeEnum::INVALID; this->windowIndex = windowIndex; this->modeGetOrSet = GET; } /* * Destructor. */ EventGetOrSetUserInputModeProcessor::~EventGetOrSetUserInputModeProcessor() { } /** * @return The window index. */ int32_t EventGetOrSetUserInputModeProcessor::getWindowIndex() const { return this->windowIndex; } /** * @return The requested input mode. */ UserInputModeEnum::Enum EventGetOrSetUserInputModeProcessor::getUserInputMode() const { return this->userInputMode; } /** * Set the user input processor which is called when GETTING. * @param userInputProcessor * Value of current input processor. */ void EventGetOrSetUserInputModeProcessor::setUserInputProcessor(UserInputModeAbstract* userInputProcessor) { this->userInputProcessor = userInputProcessor; this->userInputMode = this->userInputProcessor->getUserInputMode(); } /** * @return The user input processor valid only when GETTING. */ UserInputModeAbstract* EventGetOrSetUserInputModeProcessor::getUserInputProcessor() { return this->userInputProcessor; } /** * @return true if this event is GETTING the user input mode. */ bool EventGetOrSetUserInputModeProcessor::isGetUserInputMode() const { return (this->modeGetOrSet == GET); } /** * @return true if this event is SETTING the user input mode. */ bool EventGetOrSetUserInputModeProcessor::isSetUserInputMode() const { return (this->modeGetOrSet == SET); } connectome-workbench-1.4.2/src/GuiQt/EventGetOrSetUserInputModeProcessor.h000066400000000000000000000050711360521144700267110ustar00rootroot00000000000000#ifndef __EVENT_GET_OR_SET_USER_INPUT_MODE_PROCESSOR_H__ #define __EVENT_GET_OR_SET_USER_INPUT_MODE_PROCESSOR_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" #include "UserInputModeAbstract.h" namespace caret { /// Event for getting or setting the user input mode processor class EventGetOrSetUserInputModeProcessor : public Event { public: EventGetOrSetUserInputModeProcessor(const int32_t windowIndex, const UserInputModeEnum::Enum userInputMode); EventGetOrSetUserInputModeProcessor(const int32_t windowIndex); virtual ~EventGetOrSetUserInputModeProcessor(); bool isGetUserInputMode() const; bool isSetUserInputMode() const; int32_t getWindowIndex() const; UserInputModeEnum::Enum getUserInputMode() const; void setUserInputProcessor(UserInputModeAbstract* userInputProcessor); UserInputModeAbstract* getUserInputProcessor(); private: enum MODE_GET_OR_SET { GET, SET }; EventGetOrSetUserInputModeProcessor(const EventGetOrSetUserInputModeProcessor&); EventGetOrSetUserInputModeProcessor& operator=(const EventGetOrSetUserInputModeProcessor&); /** Is set when GETTING input mode */ UserInputModeAbstract* userInputProcessor; /** Requested input mode for SETTING and set when GETTING*/ UserInputModeEnum::Enum userInputMode; /** index of window for update */ int32_t windowIndex; /** getting or setting */ MODE_GET_OR_SET modeGetOrSet; }; } // namespace #endif // __EVENT_GET_OR_SET_USER_INPUT_MODE_PROCESSOR_H__ connectome-workbench-1.4.2/src/GuiQt/EventGraphicsTimingOneWindow.cxx000066400000000000000000000032151360521144700257440ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_GRAPHICS_TIMING_ONE_WINDOW_DECLARE__ #include "EventGraphicsTimingOneWindow.h" #undef __EVENT_GRAPHICS_TIMING_ONE_WINDOW_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventGraphicsTimingOneWindow * \brief Event for timing graphics * \ingroup GuiQt */ /** * Constructor. * * @param windowIndex * Index of window for timing */ EventGraphicsTimingOneWindow::EventGraphicsTimingOneWindow(const int32_t windowIndex) : Event(EventTypeEnum::EVENT_GRAPHICS_TIMING_ONE_WINDOW), m_windowIndex(windowIndex) { } /** * Destructor. */ EventGraphicsTimingOneWindow::~EventGraphicsTimingOneWindow() { } /** * @return Index of window for timinig test */ int32_t EventGraphicsTimingOneWindow::getWindowIndex() const { return m_windowIndex; } connectome-workbench-1.4.2/src/GuiQt/EventGraphicsTimingOneWindow.h000066400000000000000000000033731360521144700253760ustar00rootroot00000000000000#ifndef __EVENT_GRAPHICS_TIMING_ONE_WINDOW_H__ #define __EVENT_GRAPHICS_TIMING_ONE_WINDOW_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class EventGraphicsTimingOneWindow : public Event { public: EventGraphicsTimingOneWindow(const int32_t windowIndex); virtual ~EventGraphicsTimingOneWindow(); EventGraphicsTimingOneWindow(const EventGraphicsTimingOneWindow&) = delete; EventGraphicsTimingOneWindow& operator=(const EventGraphicsTimingOneWindow&) = delete; int32_t getWindowIndex() const; // ADD_NEW_METHODS_HERE private: int32_t m_windowIndex; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_GRAPHICS_TIMING_ONE_WINDOW_DECLARE__ // #endif // __EVENT_GRAPHICS_TIMING_ONE_WINDOW_DECLARE__ } // namespace #endif //__EVENT_GRAPHICS_TIMING_ONE_WINDOW_H__ connectome-workbench-1.4.2/src/GuiQt/EventGraphicsUpdateAllWindows.cxx000066400000000000000000000033341360521144700261130ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventGraphicsUpdateAllWindows.h" using namespace caret; /** * \class caret::EventGraphicsUpdateAllWindows * \brief Event for updating all Window gui elements. * \ingroup GuiQt */ /** * Constructor. * @param doRepaint * If true, a repaint is performed and this event does not * return until painting is complete. If false, an update * is performed which schedules a repaint but does not dictate * when the repaint is performed. */ EventGraphicsUpdateAllWindows::EventGraphicsUpdateAllWindows(const bool doRepaint) : Event(EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS) { this->doRepaint = doRepaint; } /* * Destructor. */ EventGraphicsUpdateAllWindows::~EventGraphicsUpdateAllWindows() { } /** * @return Indicates a repaint (instead of updates) is * to be performed. */ bool EventGraphicsUpdateAllWindows::isRepaint() const { return this->doRepaint; } connectome-workbench-1.4.2/src/GuiQt/EventGraphicsUpdateAllWindows.h000066400000000000000000000030461360521144700255400ustar00rootroot00000000000000#ifndef __EVENT_GRAPHICS_UPDATE_ALL_WINDOWS_H__ #define __EVENT_GRAPHICS_UPDATE_ALL_WINDOWS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { /// Event for updating all graphics windows. class EventGraphicsUpdateAllWindows : public Event { public: EventGraphicsUpdateAllWindows(const bool doRepaint = false); virtual ~EventGraphicsUpdateAllWindows(); bool isRepaint() const; private: EventGraphicsUpdateAllWindows(const EventGraphicsUpdateAllWindows&); EventGraphicsUpdateAllWindows& operator=(const EventGraphicsUpdateAllWindows&); bool doRepaint; }; } // namespace #endif // __EVENT_GRAPHICS_UPDATE_ALL_WINDOWS_H__ connectome-workbench-1.4.2/src/GuiQt/EventGraphicsUpdateOneWindow.cxx000066400000000000000000000024571360521144700257460ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventGraphicsUpdateOneWindow.h" using namespace caret; /** * \class caret::EventGraphicsUpdateOneWindow * \brief Event for updating a single window * \ingroup GuiQt */ /** * Constructor. */ EventGraphicsUpdateOneWindow::EventGraphicsUpdateOneWindow(const int32_t windowIndex) : Event(EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW) { this->windowIndex = windowIndex; } /* * Destructor. */ EventGraphicsUpdateOneWindow::~EventGraphicsUpdateOneWindow() { } connectome-workbench-1.4.2/src/GuiQt/EventGraphicsUpdateOneWindow.h000066400000000000000000000032561360521144700253710ustar00rootroot00000000000000#ifndef __EVENT_GRAPHICS_UPDATE_ONE_WINDOW_H__ #define __EVENT_GRAPHICS_UPDATE_ONE_WINDOW_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { /// Event for updating graphics in one window. class EventGraphicsUpdateOneWindow : public Event { public: EventGraphicsUpdateOneWindow(const int32_t windowIndex); virtual ~EventGraphicsUpdateOneWindow(); /// get the index of the window that is to be updated. int32_t getWindowIndex() const { return this->windowIndex; } private: EventGraphicsUpdateOneWindow(const EventGraphicsUpdateOneWindow&); EventGraphicsUpdateOneWindow& operator=(const EventGraphicsUpdateOneWindow&); /** index of window for update */ int32_t windowIndex; }; } // namespace #endif // __EVENT_GRAPHICS_UPDATE_ONE_WINDOW_H__ connectome-workbench-1.4.2/src/GuiQt/EventHelpViewerDisplay.cxx000066400000000000000000000041751360521144700246100ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_HELP_VIEWER_DISPLAY_DECLARE__ #include "EventHelpViewerDisplay.h" #undef __EVENT_HELP_VIEWER_DISPLAY_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventHelpViewerDisplay * \brief Display the topic in the help viewer. * \ingroup GuiQt */ /** * Constructor displays help dialog with specific topic. * * @param brainBrowserWindow * Parent window. * @param helpPageName * Name of HTML file without any path nor ".html" extension. */ EventHelpViewerDisplay::EventHelpViewerDisplay(BrainBrowserWindow* brainBrowserWindow, const AString helpPageName) : Event(EventTypeEnum::EVENT_HELP_VIEWER_DISPLAY), m_brainBrowserWindow(brainBrowserWindow), m_helpPageName(helpPageName) { } /** * Destructor. */ EventHelpViewerDisplay::~EventHelpViewerDisplay() { } /** * @return Brain browser window on which a new help viewer dialog is displayed * May be NULL in which case any browser window should be used as parent. */ const BrainBrowserWindow* EventHelpViewerDisplay::getBrainBrowserWindow() const { return m_brainBrowserWindow; } /** * @return Name of page for display (may be empty string). */ AString EventHelpViewerDisplay::getHelpPageName() const { return m_helpPageName; } connectome-workbench-1.4.2/src/GuiQt/EventHelpViewerDisplay.h000066400000000000000000000036071360521144700242340ustar00rootroot00000000000000#ifndef __EVENT_HELP_VIEWER_DISPLAY_H__ #define __EVENT_HELP_VIEWER_DISPLAY_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class BrainBrowserWindow; class EventHelpViewerDisplay : public Event { public: EventHelpViewerDisplay(BrainBrowserWindow* brainBrowserWindow, const AString helpPageName); virtual ~EventHelpViewerDisplay(); const BrainBrowserWindow* getBrainBrowserWindow() const; AString getHelpPageName() const; // ADD_NEW_METHODS_HERE private: EventHelpViewerDisplay(const EventHelpViewerDisplay&); EventHelpViewerDisplay& operator=(const EventHelpViewerDisplay&); const BrainBrowserWindow* m_brainBrowserWindow; const AString m_helpPageName; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_HELP_VIEWER_DISPLAY_DECLARE__ // #endif // __EVENT_HELP_VIEWER_DISPLAY_DECLARE__ } // namespace #endif //__EVENT_HELP_VIEWER_DISPLAY_H__ connectome-workbench-1.4.2/src/GuiQt/EventIdentificationRequest.cxx000066400000000000000000000047621360521144700255140ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_IDENTIFICATION_REQUEST_DECLARE__ #include "EventIdentificationRequest.h" #undef __EVENT_IDENTIFICATION_REQUEST_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventIdentificationRequest * \brief Perform an identification operation in a window * \ingroup GuiQt */ /** * Constructor. */ EventIdentificationRequest::EventIdentificationRequest(const int32_t windowIndex, const int32_t windowX, const int32_t windowY) : Event(EventTypeEnum::EVENT_IDENTIFICATION_REQUEST), m_windowIndex(windowIndex), m_windowX(windowX), m_windowY(windowY) { m_selectionManager = NULL; } /** * Destructor. */ EventIdentificationRequest::~EventIdentificationRequest() { } /** * @return Selection manager (NULL if event failed). */ SelectionManager* EventIdentificationRequest::getSelectionManager() const { return m_selectionManager; } /** * Set the selection manager. * * @param selectionManager * The selection manager. */ void EventIdentificationRequest::setSelectionManager(SelectionManager* selectionManager) { m_selectionManager = selectionManager; } /** * @return Index of window in which identification is performed. */ int32_t EventIdentificationRequest::getWindowIndex() const { return m_windowIndex; } /** * @return X window coordinate for identification. */ int32_t EventIdentificationRequest::getWindowX() const { return m_windowX; } /** * @return Y window coordinate for identification. */ int32_t EventIdentificationRequest::getWindowY() const { return m_windowY; } connectome-workbench-1.4.2/src/GuiQt/EventIdentificationRequest.h000066400000000000000000000043021360521144700251270ustar00rootroot00000000000000#ifndef __EVENT_IDENTIFICATION_REQUEST_H__ #define __EVENT_IDENTIFICATION_REQUEST_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class SelectionManager; class EventIdentificationRequest : public Event { public: EventIdentificationRequest(const int32_t windowIndex, const int32_t windowX, const int32_t windowY); virtual ~EventIdentificationRequest(); SelectionManager* getSelectionManager() const; void setSelectionManager(SelectionManager* selectionManager); int32_t getWindowIndex() const; int32_t getWindowX() const; int32_t getWindowY() const; // ADD_NEW_METHODS_HERE private: EventIdentificationRequest(const EventIdentificationRequest&); EventIdentificationRequest& operator=(const EventIdentificationRequest&); const int32_t m_windowIndex; const int32_t m_windowX; const int32_t m_windowY; SelectionManager* m_selectionManager; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_IDENTIFICATION_REQUEST_DECLARE__ // #endif // __EVENT_IDENTIFICATION_REQUEST_DECLARE__ } // namespace #endif //__EVENT_IDENTIFICATION_REQUEST_H__ connectome-workbench-1.4.2/src/GuiQt/EventImageCapture.cxx000066400000000000000000000114171360521144700235530ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_IMAGE_CAPTURE_DECLARE__ #include "EventImageCapture.h" #undef __EVENT_IMAGE_CAPTURE_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventImageCapture * \brief Event for capturing images. * \ingroup GuiQt */ /** * Constructor for capturing image of window with the image * dimensions identical to the dimensions of the window. * * @param browserWindowIndex * The browser window index. */ EventImageCapture::EventImageCapture(const int32_t browserWindowIndex) : Event(EventTypeEnum::EVENT_IMAGE_CAPTURE), m_browserWindowIndex(browserWindowIndex), m_captureOffsetX(0), m_captureOffsetY(0), m_captureWidth(0), m_captureHeight(0), m_outputWidth(0), m_outputHeight(0) { } /** * Constructor for capturing image of window with the given sizing. If * the X & Y sizes are both zero, the no image resizing is performed. * * @param browserWindowIndex * The browser window index. * @param captureOffsetX * X-offset for capturing image. * @param captureOffsetY * Y-offset for capturing image. * @param captureWidth * Width for capturing image. * @param captureHeight * Height for capturing image. * @param outputWidth * Width of output image. * @param outputHeight * Height of output image. */ EventImageCapture::EventImageCapture(const int32_t browserWindowIndex, const int32_t captureOffsetX, const int32_t captureOffsetY, const int32_t captureWidth, const int32_t captureHeight, const int32_t outputWidth, const int32_t outputHeight) : Event(EventTypeEnum::EVENT_IMAGE_CAPTURE), m_browserWindowIndex(browserWindowIndex), m_captureOffsetX(captureOffsetX), m_captureOffsetY(captureOffsetY), m_captureWidth(captureWidth), m_captureHeight(captureHeight), m_outputWidth(outputWidth), m_outputHeight(outputHeight) { m_backgroundColor[0] = 0; m_backgroundColor[1] = 0; m_backgroundColor[2] = 0; } /** * Destructor. */ EventImageCapture::~EventImageCapture() { } /** * @return The browser window index. */ int32_t EventImageCapture::getBrowserWindowIndex() const { return m_browserWindowIndex; } /** * @return The capture X offset */ int32_t EventImageCapture::getCaptureOffsetX() const { return m_captureOffsetX; } /** * @return The capture Y offset */ int32_t EventImageCapture::getCaptureOffsetY() const { return m_captureOffsetY; } /** * @return The capture width */ int32_t EventImageCapture::getCaptureWidth() const { return m_captureWidth; } /** * @return The capture height */ int32_t EventImageCapture::getCaptureHeight() const { return m_captureHeight; } /** * @return The output image width. */ int32_t EventImageCapture::getOutputWidth() const { return m_outputWidth; } /** * @return The output image height. */ int32_t EventImageCapture::getOutputHeight() const { return m_outputHeight; } /** * Get the graphics area's background color. * * @param backgroundColor * RGB components of background color [0, 255] */ void EventImageCapture::getBackgroundColor(uint8_t backgroundColor[3]) const { backgroundColor[0] = m_backgroundColor[0]; backgroundColor[1] = m_backgroundColor[1]; backgroundColor[2] = m_backgroundColor[2]; } /** * Set the graphics area's background color. * * @param backgroundColor * RGB components of background color [0, 255] */ void EventImageCapture::setBackgroundColor(const uint8_t backgroundColor[3]) { m_backgroundColor[0] = backgroundColor[0]; m_backgroundColor[1] = backgroundColor[1]; m_backgroundColor[2] = backgroundColor[2]; } /** * @return The captured image. */ QImage EventImageCapture::getImage() const { return m_image; } /** * Set the captured image. */ void EventImageCapture::setImage(const QImage& image) { m_image = image; } connectome-workbench-1.4.2/src/GuiQt/EventImageCapture.h000066400000000000000000000056671360521144700232120ustar00rootroot00000000000000#ifndef __EVENT_IMAGE_CAPTURE_H__ #define __EVENT_IMAGE_CAPTURE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class EventImageCapture : public Event { public: EventImageCapture(const int32_t browserWindowIndex); EventImageCapture(const int32_t browserWindowIndex, const int32_t captureOffsetX, const int32_t captureOffsetY, const int32_t captureWidth, const int32_t captureHeight, const int32_t outputWidth, const int32_t outputHeight); virtual ~EventImageCapture(); int32_t getBrowserWindowIndex() const; int32_t getOutputWidth() const; int32_t getOutputHeight() const; int32_t getCaptureOffsetX() const; int32_t getCaptureOffsetY() const; int32_t getCaptureWidth() const; int32_t getCaptureHeight() const; QImage getImage() const; void setImage(const QImage& image); void getBackgroundColor(uint8_t backgroundColor[3]) const; void setBackgroundColor(const uint8_t backgroundColor[3]); private: EventImageCapture(const EventImageCapture&); EventImageCapture& operator=(const EventImageCapture&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE const int32_t m_browserWindowIndex; const int32_t m_captureOffsetX; const int32_t m_captureOffsetY; const int32_t m_captureWidth; const int32_t m_captureHeight; const int32_t m_outputWidth; const int32_t m_outputHeight; uint8_t m_backgroundColor[3]; QImage m_image; }; #ifdef __EVENT_IMAGE_CAPTURE_DECLARE__ // #endif // __EVENT_IMAGE_CAPTURE_DECLARE__ } // namespace #endif //__EVENT_IMAGE_CAPTURE_H__ connectome-workbench-1.4.2/src/GuiQt/EventMacDockMenuUpdate.cxx000066400000000000000000000026131360521144700244740ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_MAC_DOCK_MENU_UPDATE_DECLARE__ #include "EventMacDockMenuUpdate.h" #undef __EVENT_MAC_DOCK_MENU_UPDATE_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventMacDockMenuUpdate * \brief * \ingroup GuiQt * * */ /** * Constructor. */ EventMacDockMenuUpdate::EventMacDockMenuUpdate() : Event(EventTypeEnum::EVENT_MAC_DOCK_MENU_UPDATE) { } /** * Destructor. */ EventMacDockMenuUpdate::~EventMacDockMenuUpdate() { } connectome-workbench-1.4.2/src/GuiQt/EventMacDockMenuUpdate.h000066400000000000000000000030441360521144700241200ustar00rootroot00000000000000#ifndef __EVENT_MAC_DOCK_MENU_UPDATE_H__ #define __EVENT_MAC_DOCK_MENU_UPDATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class EventMacDockMenuUpdate : public Event { public: EventMacDockMenuUpdate(); virtual ~EventMacDockMenuUpdate(); // ADD_NEW_METHODS_HERE private: EventMacDockMenuUpdate(const EventMacDockMenuUpdate&); EventMacDockMenuUpdate& operator=(const EventMacDockMenuUpdate&); // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_MAC_DOCK_MENU_UPDATE_DECLARE__ // #endif // __EVENT_MAC_DOCK_MENU_UPDATE_DECLARE__ } // namespace #endif //__EVENT_MAC_DOCK_MENU_UPDATE_H__ connectome-workbench-1.4.2/src/GuiQt/EventMovieManualModeRecording.cxx000066400000000000000000000042111360521144700260560ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_MOVIE_MANUAL_MODE_RECORDING_DECLARE__ #include "EventMovieManualModeRecording.h" #undef __EVENT_MOVIE_MANUAL_MODE_RECORDING_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventMovieManualModeRecording * \brief Manual mode recording image capture * \ingroup GuiQt */ /** * Constructor. * * @param browserWindowIndex * Index of the browser window * @param durationSeconds * Time in seconds for manual recording (used with movie recording frame * rate to determine number of images captured) */ EventMovieManualModeRecording::EventMovieManualModeRecording(const int32_t browserWindowIndex, const float durationSeconds) : Event(EventTypeEnum::EVENT_MOVIE_RECORDING_MANUAL_MODE_CAPTURE), m_browserWindowIndex(browserWindowIndex), m_durationSeconds(durationSeconds) { } /** * Destructor. */ EventMovieManualModeRecording::~EventMovieManualModeRecording() { } /** * @return Index of browser window or negative for all windows */ int32_t EventMovieManualModeRecording::getBrowserWindowIndex() const { return m_browserWindowIndex; } /** * @return Duration in seconds */ float EventMovieManualModeRecording::getDurationSeconds() const { return m_durationSeconds; } connectome-workbench-1.4.2/src/GuiQt/EventMovieManualModeRecording.h000066400000000000000000000037101360521144700255060ustar00rootroot00000000000000#ifndef __EVENT_MOVIE_MANUAL_MODE_RECORDING_H__ #define __EVENT_MOVIE_MANUAL_MODE_RECORDING_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class EventMovieManualModeRecording : public Event { public: EventMovieManualModeRecording(const int32_t browserWindowIndex, const float durationSeconds); virtual ~EventMovieManualModeRecording(); EventMovieManualModeRecording(const EventMovieManualModeRecording&) = delete; EventMovieManualModeRecording& operator=(const EventMovieManualModeRecording&) = delete; int32_t getBrowserWindowIndex() const; float getDurationSeconds() const; // ADD_NEW_METHODS_HERE private: const int32_t m_browserWindowIndex; const float m_durationSeconds; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_MOVIE_MANUAL_MODE_RECORDING_DECLARE__ // #endif // __EVENT_MOVIE_MANUAL_MODE_RECORDING_DECLARE__ } // namespace #endif //__EVENT_MOVIE_MANUAL_MODE_RECORDING_H__ connectome-workbench-1.4.2/src/GuiQt/EventOperatingSystemRequestOpenDataFile.cxx000066400000000000000000000032561360521144700301310ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventOperatingSystemRequestOpenDataFile.h" using namespace caret; /** * \class caret::EventOperatingSystemRequestOpenDataFile * \brief Event for responding to an open file request from the operating system * \ingroup GuiQt * * On Macs, the QApplication instance may receive an open data file request * from the operating system. This event is used to by the QApplication * instance (actually MacApplication derived from QApplication) to route * the request for opening the file to the GUI. */ /** * Constructor. */ EventOperatingSystemRequestOpenDataFile::EventOperatingSystemRequestOpenDataFile(const AString& dataFileName) : Event(EventTypeEnum::EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE), m_dataFileName(dataFileName) { } /* * Destructor. */ EventOperatingSystemRequestOpenDataFile::~EventOperatingSystemRequestOpenDataFile() { } connectome-workbench-1.4.2/src/GuiQt/EventOperatingSystemRequestOpenDataFile.h000066400000000000000000000032071360521144700275520ustar00rootroot00000000000000#ifndef __EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE_H__ #define __EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class EventOperatingSystemRequestOpenDataFile : public Event { public: EventOperatingSystemRequestOpenDataFile(const AString& dataFileName); virtual ~EventOperatingSystemRequestOpenDataFile(); AString getDataFileName() const { return m_dataFileName; } private: EventOperatingSystemRequestOpenDataFile(const EventOperatingSystemRequestOpenDataFile&); EventOperatingSystemRequestOpenDataFile& operator=(const EventOperatingSystemRequestOpenDataFile&); const AString m_dataFileName; }; } // namespace #endif // __EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE_H__ connectome-workbench-1.4.2/src/GuiQt/EventOverlaySettingsEditorDialogRequest.cxx000066400000000000000000000070401360521144700302040ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventOverlaySettingsEditorDialogRequest.h" using namespace caret; /** * \class caret::EventOverlaySettingsEditorDialogRequest * \brief Event for creating overlay settings editor dialog * \ingroup GuiQt */ /** * Constructor. * * @param mode * The mode. * @param browserWindowIndex * Index of browser window. * @param overlay * Overlay for map editor. * @param mapFile * Caret Mappable Data File. * @param selectedIndex * Selected index in mapFile. */ EventOverlaySettingsEditorDialogRequest::EventOverlaySettingsEditorDialogRequest(const Mode mode, const int32_t browserWindowIndex, Overlay* overlay, CaretMappableDataFile* mapFile, const int32_t selectedIndex) : Event(EventTypeEnum::EVENT_OVERLAY_SETTINGS_EDITOR_SHOW), m_mode(mode) { m_browserWindowIndex = browserWindowIndex; m_overlay = overlay; m_chartOverlay = NULL; m_mapFile = mapFile; m_chartSelectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; m_selectedIndex = selectedIndex; } /** * Constructor. * * @param mode * The mode. * @param browserWindowIndex * Index of browser window. * @param overlay * Overlay for map editor. * @param mapFile * Caret Mappable Data File. * @param selectedIndexType * Type of index selected in chart. * @param selectedIndex * Selected index in mapFile. */ EventOverlaySettingsEditorDialogRequest::EventOverlaySettingsEditorDialogRequest(const Mode mode, const int32_t browserWindowIndex, ChartTwoOverlay* chartOverlay, CaretMappableDataFile* mapFile, ChartTwoOverlay::SelectedIndexType selectedIndexType, const int32_t selectedIndex) : Event(EventTypeEnum::EVENT_OVERLAY_SETTINGS_EDITOR_SHOW), m_mode(mode) { m_browserWindowIndex = browserWindowIndex; m_overlay = NULL; m_chartOverlay = chartOverlay; m_mapFile = mapFile; m_chartSelectedIndexType = selectedIndexType; m_selectedIndex = selectedIndex; } /* * Destructor. */ EventOverlaySettingsEditorDialogRequest::~EventOverlaySettingsEditorDialogRequest() { } connectome-workbench-1.4.2/src/GuiQt/EventOverlaySettingsEditorDialogRequest.h000066400000000000000000000112431360521144700276310ustar00rootroot00000000000000#ifndef __EVENT_MAP_SETTINGS_EDITOR_DIALOG_REQUEST_H__ #define __EVENT_MAP_SETTINGS_EDITOR_DIALOG_REQUEST_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ChartTwoOverlay.h" #include "Event.h" namespace caret { class CaretMappableDataFile; class ChartTwoOverlay; class Overlay; /// Event for showing edit map scalar color mapping editor class EventOverlaySettingsEditorDialogRequest : public Event { public: enum Mode { MODE_SHOW_EDITOR, MODE_OVERLAY_MAP_CHANGED, MODE_UPDATE_ALL }; EventOverlaySettingsEditorDialogRequest(const Mode mode, const int32_t browserWindowIndex, Overlay* overlay, CaretMappableDataFile* mapFile, const int32_t selectedIndex); EventOverlaySettingsEditorDialogRequest(const Mode mode, const int32_t browserWindowIndex, ChartTwoOverlay* chartOverlay, CaretMappableDataFile* mapFile, ChartTwoOverlay::SelectedIndexType selectedIndexType, const int32_t selectedIndex); virtual ~EventOverlaySettingsEditorDialogRequest(); /** * @return The mode (show or update) */ Mode getMode() const { return m_mode; } /** * @return Get the index of the browser window for palette being edited. */ int32_t getBrowserWindowIndex() const { return m_browserWindowIndex; } /** * @return Map file containing map whose color palette is edited */ CaretMappableDataFile* getCaretMappableDataFile() const { return m_mapFile; } // /** // * @return Index of selection in the map file // */ // int32_t getSelectedIndex() const { return m_selectedIndex; } /** * @return The overlay for the editor. */ Overlay* getOverlay() { return m_overlay; } /** * @return The overlay for the editor. */ const Overlay* getOverlay() const { return m_overlay; } /** * @return The chart overlay for the editor. */ ChartTwoOverlay* getChartTwoOverlay() { return m_chartOverlay; } /** * @return The overlay for the editor. */ const ChartTwoOverlay* getChartTwoOverlay() const { return m_chartOverlay; } // /** // * @return The type of index for chart file // */ // ChartTwoOverlay::SelectedIndexType getChartSelectedIndexType() const { return m_chartSelectedIndexType; } private: EventOverlaySettingsEditorDialogRequest(const EventOverlaySettingsEditorDialogRequest&); EventOverlaySettingsEditorDialogRequest& operator=(const EventOverlaySettingsEditorDialogRequest&); /** The mode show/update */ const Mode m_mode; /** index of browser window for palette editing */ int32_t m_browserWindowIndex; /** Overlay for editor. */ Overlay* m_overlay; /** Chart Overlay for editor. */ ChartTwoOverlay* m_chartOverlay; /** Map file containing map whose color palette is edited */ CaretMappableDataFile* m_mapFile; /** Selected index type for charts */ ChartTwoOverlay::SelectedIndexType m_chartSelectedIndexType; /** Selected index in the map file */ int32_t m_selectedIndex; }; } // namespace #endif // __EVENT_MAP_SETTINGS_EDITOR_DIALOG_REQUEST_H__ connectome-workbench-1.4.2/src/GuiQt/EventPaletteColorMappingEditorDialogRequest.cxx000066400000000000000000000037021360521144700307540ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_PALETTE_COLOR_MAPPING_EDITOR_DIALOG_REQUEST_DECLARE__ #include "EventPaletteColorMappingEditorDialogRequest.h" #undef __EVENT_PALETTE_COLOR_MAPPING_EDITOR_DIALOG_REQUEST_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventPaletteColorMappingEditorDialogRequest * \brief Event for editing palette color mapping in a dialog * \ingroup GuiQt */ /** * Constructor. */ EventPaletteColorMappingEditorDialogRequest::EventPaletteColorMappingEditorDialogRequest(const int32_t browserWindowIndex, CaretMappableDataFile* mapFile, const int32_t mapIndex) : Event(EventTypeEnum::EVENT_PALETTE_COLOR_MAPPING_EDITOR_SHOW), m_browserWindowIndex(browserWindowIndex), m_mapFile(mapFile), m_mapIndex(mapIndex) { CaretAssert(mapFile); CaretAssert(mapIndex >= 0); } /** * Destructor. */ EventPaletteColorMappingEditorDialogRequest::~EventPaletteColorMappingEditorDialogRequest() { } connectome-workbench-1.4.2/src/GuiQt/EventPaletteColorMappingEditorDialogRequest.h000066400000000000000000000055101360521144700304000ustar00rootroot00000000000000#ifndef __EVENT_PALETTE_COLOR_MAPPING_EDITOR_DIALOG_REQUEST_H__ #define __EVENT_PALETTE_COLOR_MAPPING_EDITOR_DIALOG_REQUEST_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class CaretMappableDataFile; class EventPaletteColorMappingEditorDialogRequest : public Event { public: EventPaletteColorMappingEditorDialogRequest(const int32_t browserWindowIndex, CaretMappableDataFile* mapFile, const int32_t mapIndex); virtual ~EventPaletteColorMappingEditorDialogRequest(); /** * @return Get the index of the browser window for palette being edited. */ int32_t getBrowserWindowIndex() const { return m_browserWindowIndex; } /** * @return Map file containing map whose color palette is edited */ CaretMappableDataFile* getCaretMappableDataFile() const { return m_mapFile; } /** * @return Index of map in the map file */ int32_t getMapIndex() const { return m_mapIndex; } // ADD_NEW_METHODS_HERE private: EventPaletteColorMappingEditorDialogRequest(const EventPaletteColorMappingEditorDialogRequest&); EventPaletteColorMappingEditorDialogRequest& operator=(const EventPaletteColorMappingEditorDialogRequest&); /** index of browser window for palette editing */ int32_t m_browserWindowIndex; /** Map file containing map whose color palette is edited */ CaretMappableDataFile* m_mapFile; /** Index of map in the map file */ int32_t m_mapIndex; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_PALETTE_COLOR_MAPPING_EDITOR_DIALOG_REQUEST_DECLARE__ // #endif // __EVENT_PALETTE_COLOR_MAPPING_EDITOR_DIALOG_REQUEST_DECLARE__ } // namespace #endif //__EVENT_PALETTE_COLOR_MAPPING_EDITOR_DIALOG_REQUEST_H__ connectome-workbench-1.4.2/src/GuiQt/EventShowDataFileReadWarningsDialog.cxx000066400000000000000000000044421360521144700271440ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_DISPLAY_DATA_FILE_READ_WARNINGS_DIALOG_DECLARE__ #include "EventShowDataFileReadWarningsDialog.h" #undef __EVENT_DISPLAY_DATA_FILE_READ_WARNINGS_DIALOG_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventShowDataFileReadWarningsDialog * \brief This event is sent after files are read to show any warnings during file reading * \ingroup GuiQt * * All data files are tested for the prescence of warnings from reading of the files. * If there are warnings, a dialog is displayed listing the file read warnings. * If there are no file read warnings, no dialog is displayed. */ /** * Constructor. * * @param browserWindowIndex * Index of browser window on which dialog is displayed. * If the window index is invalid, the warning * will be displayed on an open browser window. */ EventShowDataFileReadWarningsDialog::EventShowDataFileReadWarningsDialog(const int32_t browserWindowIndex) : Event(EventTypeEnum::EVENT_SHOW_FILE_DATA_READ_WARNING_DIALOG), m_browserWindowIndex(browserWindowIndex) { } /** * Destructor. */ EventShowDataFileReadWarningsDialog::~EventShowDataFileReadWarningsDialog() { } /** * @return Index of window on which the dialog is displayed. If * the index is not a valid window, the dialog is dispalayed over * any available browser window. */ int32_t EventShowDataFileReadWarningsDialog::getBrowserWindowIndex() const { return m_browserWindowIndex; } connectome-workbench-1.4.2/src/GuiQt/EventShowDataFileReadWarningsDialog.h000066400000000000000000000035661360521144700265770ustar00rootroot00000000000000#ifndef __EVENT_DISPLAY_DATA_FILE_READ_WARNINGS_DIALOG_H__ #define __EVENT_DISPLAY_DATA_FILE_READ_WARNINGS_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "Event.h" namespace caret { class EventShowDataFileReadWarningsDialog : public Event { public: EventShowDataFileReadWarningsDialog(const int32_t browserWindowIndex = -1); virtual ~EventShowDataFileReadWarningsDialog(); int32_t getBrowserWindowIndex() const; // ADD_NEW_METHODS_HERE private: EventShowDataFileReadWarningsDialog(const EventShowDataFileReadWarningsDialog&); EventShowDataFileReadWarningsDialog& operator=(const EventShowDataFileReadWarningsDialog&); const int32_t m_browserWindowIndex; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_DISPLAY_DATA_FILE_READ_WARNINGS_DIALOG_DECLARE__ // #endif // __EVENT_DISPLAY_DATA_FILE_READ_WARNINGS_DIALOG_DECLARE__ } // namespace #endif //__EVENT_DISPLAY_DATA_FILE_READ_WARNINGS_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/EventUpdateInformationWindows.cxx000066400000000000000000000051601360521144700262060ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Brain.h" #include "EventUpdateInformationWindows.h" #include "GuiManager.h" #include "IdentificationManager.h" #include "IdentifiedItem.h" using namespace caret; /** * \class caret::EventUpdateInformationWindows * \brief Event for updating Information Windows * \ingroup GuiQt */ /** * Construct an event for update of information window with * content from the identification manager. The given * text will be added to the information manager prior to * update of information window. * * @param informationText * Next text that will be added to the information manager. */ EventUpdateInformationWindows::EventUpdateInformationWindows(const AString& informationText) : Event(EventTypeEnum::EVENT_UPDATE_INFORMATION_WINDOWS) { if ( ! informationText.isEmpty()) { IdentificationManager* idManager = GuiManager::get()->getBrain()->getIdentificationManager(); CaretAssert(idManager); idManager->addIdentifiedItem(new IdentifiedItem(informationText)); } m_important = true; } /** * Construct an event for update of information window with * content from the identification manager. */ EventUpdateInformationWindows::EventUpdateInformationWindows() : Event(EventTypeEnum::EVENT_UPDATE_INFORMATION_WINDOWS) { m_important = true; } /** * Destructor. */ EventUpdateInformationWindows::~EventUpdateInformationWindows() { } /** * Set the message as not important so that the toolbox * does NOT switch to the information panel. */ EventUpdateInformationWindows* EventUpdateInformationWindows::setNotImportant() { m_important = false; return this; } /** * @return Is this message important. If so, * the Toolbox will switch to the information * display. */ bool EventUpdateInformationWindows::isImportant() const { return m_important; } connectome-workbench-1.4.2/src/GuiQt/EventUpdateInformationWindows.h000066400000000000000000000032711360521144700256340ustar00rootroot00000000000000#ifndef __EVENT_UPDATE_INFORMATION_WINDOWS_H__ #define __EVENT_UPDATE_INFORMATION_WINDOWS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class BrainStructure; /// Request display of text in the information window(s). class EventUpdateInformationWindows : public Event { public: EventUpdateInformationWindows(); EventUpdateInformationWindows(const AString& informationText); virtual ~EventUpdateInformationWindows(); EventUpdateInformationWindows* setNotImportant(); bool isImportant() const; private: EventUpdateInformationWindows(const EventUpdateInformationWindows&); EventUpdateInformationWindows& operator=(const EventUpdateInformationWindows&); bool m_important; }; } // namespace #endif // __EVENT_UPDATE_INFORMATION_WINDOWS_H__ connectome-workbench-1.4.2/src/GuiQt/EventUpdateVolumeEditingToolBar.cxx000066400000000000000000000027361360521144700264120ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_UPDATE_VOLUME_EDITING_TOOL_BAR_DECLARE__ #include "EventUpdateVolumeEditingToolBar.h" #undef __EVENT_UPDATE_VOLUME_EDITING_TOOL_BAR_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventUpdateVolumeEditingToolBar * \brief * \ingroup GuiQt * * */ /** * Constructor. */ EventUpdateVolumeEditingToolBar::EventUpdateVolumeEditingToolBar() : Event(EventTypeEnum::EVENT_UPDATE_VOLUME_EDITING_TOOLBAR) { } /** * Destructor. */ EventUpdateVolumeEditingToolBar::~EventUpdateVolumeEditingToolBar() { } connectome-workbench-1.4.2/src/GuiQt/EventUpdateVolumeEditingToolBar.h000066400000000000000000000032251360521144700260310ustar00rootroot00000000000000#ifndef __EVENT_UPDATE_VOLUME_EDITING_TOOL_BAR_H__ #define __EVENT_UPDATE_VOLUME_EDITING_TOOL_BAR_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { class EventUpdateVolumeEditingToolBar : public Event { public: EventUpdateVolumeEditingToolBar(); virtual ~EventUpdateVolumeEditingToolBar(); // ADD_NEW_METHODS_HERE private: EventUpdateVolumeEditingToolBar(const EventUpdateVolumeEditingToolBar&); EventUpdateVolumeEditingToolBar& operator=(const EventUpdateVolumeEditingToolBar&); // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_UPDATE_VOLUME_EDITING_TOOL_BAR_DECLARE__ // #endif // __EVENT_UPDATE_VOLUME_EDITING_TOOL_BAR_DECLARE__ } // namespace #endif //__EVENT_UPDATE_VOLUME_EDITING_TOOL_BAR_H__ connectome-workbench-1.4.2/src/GuiQt/EventUpdateYokedWindows.cxx000066400000000000000000000104561360521144700250000ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __EVENT_UPDATE_YOKED_WINDOWS_DECLARE__ #include "EventUpdateYokedWindows.h" #undef __EVENT_UPDATE_YOKED_WINDOWS_DECLARE__ #include "EventTypeEnum.h" using namespace caret; /** * \class caret::EventUpdateYokedWindows * \brief Updates windows that are yoked. * \ingroup GuiQt */ /** * Constructor for a window. This given window will NOT be updated. * * @param browserWindowIndexThatIssuedEvent * Index of browser window that issued event. * @param brainModelYokingGroup * brain model yoking group that is selected. * @param chartModelYokingGroup * chart model yoking group that is selected. */ EventUpdateYokedWindows::EventUpdateYokedWindows(const int32_t browserWindowIndexThatIssuedEvent, const YokingGroupEnum::Enum brainModelYokingGroup, const YokingGroupEnum::Enum chartModelYokingGroup) : Event(EventTypeEnum::EVENT_UPDATE_YOKED_WINDOWS), m_browserWindowIndexThatIssuedEvent(browserWindowIndexThatIssuedEvent), m_brainModelYokingGroup(brainModelYokingGroup), m_chartModelYokingGroup(chartModelYokingGroup) { } /** * Constructor for updating all windows. * * @param browserWindowIndexThatIssuedEvent * Index of browser window that issued event. * @param brainModelYokingGroup * brain model yoking group that is selected. * @param chartModelYokingGroup * chart model yoking group that is selected. */ EventUpdateYokedWindows::EventUpdateYokedWindows(const YokingGroupEnum::Enum brainModelYokingGroup, const YokingGroupEnum::Enum chartModelYokingGroup) : Event(EventTypeEnum::EVENT_UPDATE_YOKED_WINDOWS), m_browserWindowIndexThatIssuedEvent(-1), m_brainModelYokingGroup(brainModelYokingGroup), m_chartModelYokingGroup(chartModelYokingGroup) { } /** * Destructor. */ EventUpdateYokedWindows::~EventUpdateYokedWindows() { } /** * @return Index of browser window that issued the event. */ int32_t EventUpdateYokedWindows::getBrowserWindowIndexThatIssuedEvent() const { return m_browserWindowIndexThatIssuedEvent; } /** * @return Is the given brain model yoking group needing an update? * * @param brainModelYokingGroup * The brain model yoking group. */ bool EventUpdateYokedWindows::isBrainModelYoking(const YokingGroupEnum::Enum brainModelYokingGroup) const { if (m_brainModelYokingGroup == YokingGroupEnum::YOKING_GROUP_OFF) { return false; } return (m_brainModelYokingGroup == brainModelYokingGroup); } /** * @return Is the given chart model yoking group needing an update? * * @param chartModelYokingGroup * The chart model yoking group. */ bool EventUpdateYokedWindows::isChartModelYoking(const YokingGroupEnum::Enum chartModelYokingGroup) const { if (m_chartModelYokingGroup == YokingGroupEnum::YOKING_GROUP_OFF) { return false; } return (m_chartModelYokingGroup == chartModelYokingGroup); } /** * @return Is the given brain OR chart model yoking group needing an update? * * @param brainModelYokingGroup * The brain model yoking group. * @param chartModelYokingGroup * The chart model yoking group. */ bool EventUpdateYokedWindows::isBrainOrChartModelYoking(const YokingGroupEnum::Enum brainModelYokingGroup, const YokingGroupEnum::Enum chartModelYokingGroup) const { return (isBrainModelYoking(brainModelYokingGroup) || isChartModelYoking(chartModelYokingGroup)); } connectome-workbench-1.4.2/src/GuiQt/EventUpdateYokedWindows.h000066400000000000000000000052201360521144700244160ustar00rootroot00000000000000#ifndef __EVENT_UPDATE_YOKED_WINDOWS_H__ #define __EVENT_UPDATE_YOKED_WINDOWS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" #include "YokingGroupEnum.h" namespace caret { class EventUpdateYokedWindows : public Event { public: EventUpdateYokedWindows(const int32_t browserWindowIndexThatIssuedEvent, const YokingGroupEnum::Enum brainModelYokingGroup, const YokingGroupEnum::Enum chartModelYokingGroup); EventUpdateYokedWindows(const YokingGroupEnum::Enum brainModelYokingGroup, const YokingGroupEnum::Enum chartModelYokingGroup); virtual ~EventUpdateYokedWindows(); int32_t getBrowserWindowIndexThatIssuedEvent() const; bool isBrainModelYoking(const YokingGroupEnum::Enum brainModelYokingGroup) const; bool isChartModelYoking(const YokingGroupEnum::Enum chartModelYokingGroup) const; bool isBrainOrChartModelYoking(const YokingGroupEnum::Enum brainModelYokingGroup, const YokingGroupEnum::Enum chartModelYokingGroup) const; private: EventUpdateYokedWindows(const EventUpdateYokedWindows&); EventUpdateYokedWindows& operator=(const EventUpdateYokedWindows&); public: // ADD_NEW_METHODS_HERE private: const int32_t m_browserWindowIndexThatIssuedEvent; const YokingGroupEnum::Enum m_brainModelYokingGroup; const YokingGroupEnum::Enum m_chartModelYokingGroup; // ADD_NEW_MEMBERS_HERE }; #ifdef __EVENT_UPDATE_YOKED_WINDOWS_DECLARE__ // #endif // __EVENT_UPDATE_YOKED_WINDOWS_DECLARE__ } // namespace #endif //__EVENT_UPDATE_YOKED_WINDOWS_H__ connectome-workbench-1.4.2/src/GuiQt/EventUserInterfaceUpdate.cxx000066400000000000000000000153061360521144700251100ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventUserInterfaceUpdate.h" using namespace caret; /** * \class caret::EventUserInterfaceUpdate * \brief Event for updating the user-interface. * \ingroup GuiQt * * After the user executes an action, there is often the * need to update the user-interface. Options are available * to limit the update for specific types of data. However, * some receivers will update regardless of any specific * update type requests. In addition, the update can * be targeted to a specific window. */ /** * Constructor. By default, everything is updated. * The 'add...()' methods can be used to limit the * types of data that get updated. */ EventUserInterfaceUpdate::EventUserInterfaceUpdate() : Event(EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { m_windowIndex = -1; this->setAll(true); } /* * Destructor. */ EventUserInterfaceUpdate::~EventUserInterfaceUpdate() { } /** * @return Is the update for the given window? * * @param windowIndex * Index of window. */ bool EventUserInterfaceUpdate::isUpdateForWindow(const int32_t windowIndex) const { if (m_windowIndex < 0) { return true; } else if (m_windowIndex == windowIndex) { return true; } return false; } /** * Set the update so that it only updates a specific window. * * @return A reference to the instance so that the * request update calls can be chained. */ EventUserInterfaceUpdate& EventUserInterfaceUpdate::setWindowIndex(const int32_t windowIndex) { m_windowIndex = windowIndex; return *this; } /** * Set the status of all update types. * @param new selection status. */ void EventUserInterfaceUpdate::setAll(bool selected) { m_borderUpdate = selected; m_connectivityUpdate = selected; m_fociUpdate = selected; m_surfaceUpdate = selected; m_tabUpdate = selected; m_toolBarUpdate = selected; m_toolBoxUpdate = selected; } /** * Add borders for update (borders have changed). * * Note the first call to an 'add...()' method will * set all other updates to off. * * @return A reference to the instance so that the * request update calls can be chained. */ EventUserInterfaceUpdate& EventUserInterfaceUpdate::addBorder() { addInitialization(); m_borderUpdate = true; return *this; } /** * Add connectivity for update (connectivity has changed). * * Note the first call to an 'add...()' method will * set all other updates to off. * * @return A reference to the instance so that the * request update calls can be chained. */ EventUserInterfaceUpdate& EventUserInterfaceUpdate::addConnectivity() { addInitialization(); m_connectivityUpdate = true; return *this; } /** * Add foci for update (foci have changed). * * Note the first call to an 'add...()' method will * set all other updates to off. * * @return A reference to the instance so that the * request update calls can be chained. */ EventUserInterfaceUpdate& EventUserInterfaceUpdate::addFoci() { addInitialization(); m_fociUpdate = true; return *this; } /** * Add surface for update (surfaces have changed). * * Note the first call to an 'add...()' method will * set all other updates to off. * * @return A reference to the instance so that the * request update calls can be chained. */ EventUserInterfaceUpdate& EventUserInterfaceUpdate::addSurface() { addInitialization(); m_surfaceUpdate = true; return *this; } /** * Add browser tabs for update (browser tabs have changed). * * Note the first call to an 'add...()' method will * set all other updates to off. * * @return A reference to the instance so that the * request update calls can be chained. */ EventUserInterfaceUpdate& EventUserInterfaceUpdate::addTab() { addInitialization(); m_tabUpdate = true; return *this; } /** * Add toolbar for update (toolbar data has changed). * * Note the first call to an 'add...()' method will * set all other updates to off. * * @return A reference to the instance so that the * request update calls can be chained. */ EventUserInterfaceUpdate& EventUserInterfaceUpdate::addToolBar() { addInitialization(); m_toolBarUpdate = true; return *this; } /** * Add toolbox for update (toolbox data has changed). * * Note the first call to an 'add...()' method will * set all other updates to off. * * @return A reference to the instance so that the * request update calls can be chained. */ EventUserInterfaceUpdate& EventUserInterfaceUpdate::addToolBox() { addInitialization(); m_toolBoxUpdate = true; return *this; } /** * This is called by any of the 'add...() methods * and, if this is the first time called after * creation of an instance, it will turn off all * update types so that the 'add...()' only has * to turn on its update type. */ void EventUserInterfaceUpdate::addInitialization() { if (m_isFirstUpdateType) { setAll(false); m_isFirstUpdateType = false; } } /** * @return Is border update requested. */ bool EventUserInterfaceUpdate::isBorderUpdate() const { return m_borderUpdate; } /** * @return Is connectivity update requested. */ bool EventUserInterfaceUpdate::isConnectivityUpdate() const { return m_connectivityUpdate; } /** * @return Is foci update requested. */ bool EventUserInterfaceUpdate::isFociUpdate() const { return m_fociUpdate; } /** * @return Is surface update requested. */ bool EventUserInterfaceUpdate::isSurfaceUpdate() const { return m_surfaceUpdate; } /** * @return Is tab update requested (browser tabs have changed) */ bool EventUserInterfaceUpdate::isTabUpdate() const { return m_tabUpdate; } /** * @return Is toolbar update requested. */ bool EventUserInterfaceUpdate::isToolBarUpdate() const { return m_toolBarUpdate; } /** * @return Is toolbox update requested. */ bool EventUserInterfaceUpdate::isToolBoxUpdate() const { return m_toolBoxUpdate; } connectome-workbench-1.4.2/src/GuiQt/EventUserInterfaceUpdate.h000066400000000000000000000052531360521144700245350ustar00rootroot00000000000000#ifndef __EVENT_USER_INTERFACE_UPDATE_H__ #define __EVENT_USER_INTERFACE_UPDATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Event.h" namespace caret { /// Event for updating the user-interface class EventUserInterfaceUpdate : public Event { public: EventUserInterfaceUpdate(); virtual ~EventUserInterfaceUpdate(); EventUserInterfaceUpdate& addBorder(); EventUserInterfaceUpdate& addConnectivity(); EventUserInterfaceUpdate& addFoci(); EventUserInterfaceUpdate& addSurface(); EventUserInterfaceUpdate& addTab(); EventUserInterfaceUpdate& addToolBar(); EventUserInterfaceUpdate& addToolBox(); bool isBorderUpdate() const; bool isConnectivityUpdate() const; bool isFociUpdate() const; bool isSurfaceUpdate() const; bool isTabUpdate() const; bool isToolBarUpdate() const; bool isToolBoxUpdate() const; bool isUpdateForWindow(const int32_t windowIndex) const; EventUserInterfaceUpdate& setWindowIndex(const int32_t windowIndex); private: EventUserInterfaceUpdate(const EventUserInterfaceUpdate&); EventUserInterfaceUpdate& operator=(const EventUserInterfaceUpdate&); void setAll(bool selected); void addInitialization(); bool m_borderUpdate; bool m_connectivityUpdate; bool m_fociUpdate; bool m_surfaceUpdate; bool m_tabUpdate; bool m_toolBarUpdate; bool m_toolBoxUpdate; bool m_isFirstUpdateType; int32_t m_windowIndex; }; } // namespace #endif // __EVENT_USER_INTERFACE_UPDATE_H__ connectome-workbench-1.4.2/src/GuiQt/FiberOrientationSelectionViewController.cxx000066400000000000000000000603351360521144700302160ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __FIBER_ORIENTATION_SELECTION_VIEW_CONTROLLER_DECLARE__ #include "FiberOrientationSelectionViewController.h" #undef __FIBER_ORIENTATION_SELECTION_VIEW_CONTROLLER_DECLARE__ #include #include #include #include #include #include #include #include "Brain.h" #include "BrowserTabContent.h" #include "DisplayGroupEnumComboBox.h" #include "DisplayPropertiesFiberOrientation.h" #include "EventManager.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventUserInterfaceUpdate.h" #include "CiftiFiberOrientationFile.h" #include "FiberOrientationColoringTypeEnum.h" #include "FiberOrientationSelectionViewController.h" #include "FiberSamplesOpenGLWidget.h" #include "GuiManager.h" #include "SceneClass.h" #include "WuQFactory.h" #include "WuQTabWidget.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::FiberOrientationSelectionViewController * \brief View/Controller for fiber orientations * \ingroup GuiQt * */ /** * Constructor. */ FiberOrientationSelectionViewController::FiberOrientationSelectionViewController(const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex) { QLabel* groupLabel = new QLabel("Group"); m_displayGroupComboBox = new DisplayGroupEnumComboBox(this); QObject::connect(m_displayGroupComboBox, SIGNAL(displayGroupSelected(const DisplayGroupEnum::Enum)), this, SLOT(displayGroupSelected(const DisplayGroupEnum::Enum))); QHBoxLayout* groupLayout = new QHBoxLayout(); WuQtUtilities::setLayoutSpacingAndMargins(groupLayout, 2, 2); groupLayout->addWidget(groupLabel); groupLayout->addWidget(m_displayGroupComboBox->getWidget()); groupLayout->addStretch(); QWidget* attributesWidget = this->createAttributesWidget(); QWidget* selectionWidget = this->createSelectionWidget(); QWidget* samplesWidget = this->createSamplesWidget(); m_displayFibersCheckBox = new QCheckBox("Display Fibers"); m_displayFibersCheckBox->setToolTip("Display Fibers"); QObject::connect(m_displayFibersCheckBox, SIGNAL(clicked(bool)), this, SLOT(processSelectionChanges())); m_tabWidget = new WuQTabWidget(WuQTabWidget::TAB_ALIGN_LEFT, this); m_tabWidget->addTab(attributesWidget, "Attributes"); m_tabWidget->addTab(selectionWidget, "Selection"); m_tabWidget->addTab(samplesWidget, "Samples"); m_tabWidget->setCurrentWidget(attributesWidget); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); layout->addLayout(groupLayout); layout->addSpacing(10); layout->addWidget(m_displayFibersCheckBox); layout->addWidget(m_tabWidget->getWidget(), 0, Qt::AlignLeft); layout->addStretch(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); s_allViewControllers.insert(this); } /** * Destructor. */ FiberOrientationSelectionViewController::~FiberOrientationSelectionViewController() { EventManager::get()->removeAllEventsFromListener(this); s_allViewControllers.erase(this); } /** * @return The selection widget. */ QWidget* FiberOrientationSelectionViewController::createSelectionWidget() { m_selectionWidgetLayout = new QVBoxLayout(); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addLayout(m_selectionWidgetLayout); layout->addStretch(); return widget; } /** * @return The attributes widget. */ QWidget* FiberOrientationSelectionViewController::createAttributesWidget() { m_updateInProgress = true; QLabel* aboveLimitLabel = new QLabel("Slice Above Limit"); m_aboveLimitSpinBox = WuQFactory::newDoubleSpinBox(); m_aboveLimitSpinBox->setRange(0.0, std::numeric_limits::max()); m_aboveLimitSpinBox->setDecimals(3); m_aboveLimitSpinBox->setSingleStep(0.1); m_aboveLimitSpinBox->setToolTip("Fibers within this distance above the volume slice will be displayed"); QObject::connect(m_aboveLimitSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); QLabel* belowLimitLabel = new QLabel("Slice Below Limit"); m_belowLimitSpinBox = WuQFactory::newDoubleSpinBox(); m_belowLimitSpinBox->setRange(-std::numeric_limits::max(), 0.0); m_belowLimitSpinBox->setDecimals(3); m_belowLimitSpinBox->setSingleStep(0.1); m_belowLimitSpinBox->setToolTip("Fibers within this distance below the volume slice will be displayed"); QObject::connect(m_belowLimitSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); QLabel* minimumMagnitudeLabel = new QLabel("Minimum Magnitude"); m_minimumMagnitudeSpinBox = WuQFactory::newDoubleSpinBox(); m_minimumMagnitudeSpinBox->setRange(0.0, std::numeric_limits::max()); m_minimumMagnitudeSpinBox->setDecimals(2); m_minimumMagnitudeSpinBox->setSingleStep(0.05); m_minimumMagnitudeSpinBox->setToolTip("Minimum magnitude for displaying fibers"); QObject::connect(m_minimumMagnitudeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); QLabel* lengthMultiplierLabel = new QLabel("Length Multiplier"); m_lengthMultiplierSpinBox = WuQFactory::newDoubleSpinBox(); m_lengthMultiplierSpinBox->setRange(0.0, std::numeric_limits::max()); m_lengthMultiplierSpinBox->setDecimals(2); m_lengthMultiplierSpinBox->setSingleStep(1.0); m_lengthMultiplierSpinBox->setToolTip("Fiber lengths are scaled by this value"); QObject::connect(m_lengthMultiplierSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); QLabel* fanMultiplierLabel = new QLabel("Fan Multiplier"); m_fanMultiplierSpinBox = WuQFactory::newDoubleSpinBox(); m_fanMultiplierSpinBox->setRange(0.0, std::numeric_limits::max()); m_fanMultiplierSpinBox->setDecimals(2); m_fanMultiplierSpinBox->setSingleStep(0.05); m_fanMultiplierSpinBox->setToolTip("Fan angles are scaled by this value"); QObject::connect(m_fanMultiplierSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); m_drawWithMagnitudeCheckBox = new QCheckBox("Draw With Magnitude"); m_drawWithMagnitudeCheckBox->setToolTip("When drawing fibers, the magnitude is reflected in the length of the fiber"); QObject::connect(m_drawWithMagnitudeCheckBox, SIGNAL(clicked(bool)), this, SLOT(processAttributesChanges())); QLabel* coloringTypeLabel = new QLabel("Coloring"); m_coloringTypeComboBox = new EnumComboBoxTemplate(this); m_coloringTypeComboBox->getWidget()->setToolTip("Selects method for assigning the red, green, and blue\n" "color components when drawing fibers"); QObject::connect(m_coloringTypeComboBox, SIGNAL(itemActivated()), this, SLOT(processAttributesChanges())); m_coloringTypeComboBox->setup(); QLabel* symbolTypeLabel = new QLabel("Symbol"); m_symbolTypeComboBox = new EnumComboBoxTemplate(this); m_symbolTypeComboBox->getWidget()->setToolTip("Selects type of symbol for drawing fibers"); QObject::connect(m_symbolTypeComboBox, SIGNAL(itemActivated()), this, SLOT(processAttributesChanges())); m_symbolTypeComboBox->setup(); QWidget* gridWidget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(gridWidget); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 8, 2); int row = gridLayout->rowCount(); gridLayout->addWidget(coloringTypeLabel, row, 0); gridLayout->addWidget(m_coloringTypeComboBox->getWidget() , row, 1); row++; gridLayout->addWidget(symbolTypeLabel, row, 0); gridLayout->addWidget(m_symbolTypeComboBox->getWidget() , row, 1); row++; gridLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), row, 0, 1, 2); row++; gridLayout->addWidget(m_drawWithMagnitudeCheckBox, row, 0, 1, 2, Qt::AlignLeft); row++; gridLayout->addWidget(minimumMagnitudeLabel, row, 0); gridLayout->addWidget(m_minimumMagnitudeSpinBox , row, 1); row++; gridLayout->addWidget(lengthMultiplierLabel, row, 0); gridLayout->addWidget(m_lengthMultiplierSpinBox , row, 1); row++; gridLayout->addWidget(fanMultiplierLabel, row, 0); gridLayout->addWidget(m_fanMultiplierSpinBox , row, 1); row++; gridLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), row, 0, 1, 2); row++; gridLayout->addWidget(aboveLimitLabel, row, 0); gridLayout->addWidget(m_aboveLimitSpinBox, row, 1); row++; gridLayout->addWidget(belowLimitLabel, row, 0); gridLayout->addWidget(m_belowLimitSpinBox, row, 1); row++; gridWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); layout->addWidget(gridWidget); layout->addStretch(); m_updateInProgress = false; return widget; } /** * Called when a widget on the attributes page has * its value changed. */ void FiberOrientationSelectionViewController::processAttributesChanges() { if (m_updateInProgress) { return; } DisplayPropertiesFiberOrientation* dpfo = GuiManager::get()->getBrain()->getDisplayPropertiesFiberOrientation(); BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); const DisplayGroupEnum::Enum displayGroup = dpfo->getDisplayGroupForTab(browserTabIndex); dpfo->setAboveLimit(displayGroup, browserTabIndex, m_aboveLimitSpinBox->value()); dpfo->setBelowLimit(displayGroup, browserTabIndex, m_belowLimitSpinBox->value()); dpfo->setMinimumMagnitude(displayGroup, browserTabIndex, m_minimumMagnitudeSpinBox->value()); dpfo->setLengthMultiplier(displayGroup, browserTabIndex, m_lengthMultiplierSpinBox->value()); dpfo->setFanMultiplier(displayGroup, browserTabIndex, m_fanMultiplierSpinBox->value()); dpfo->setDrawWithMagnitude(displayGroup, browserTabIndex, m_drawWithMagnitudeCheckBox->isChecked()); const FiberOrientationColoringTypeEnum::Enum coloringType = m_coloringTypeComboBox->getSelectedItem(); dpfo->setColoringType(displayGroup, browserTabIndex, coloringType); const FiberOrientationSymbolTypeEnum::Enum symbolType = m_symbolTypeComboBox->getSelectedItem(); dpfo->setSymbolType(displayGroup, browserTabIndex, symbolType); dpfo->setSphereOrientationsDisplayed(displayGroup, browserTabIndex, m_displaySphereOrientationsCheckBox->isChecked()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); updateOtherViewControllers(); } /** * Called when the fiber orientation display group combo box is changed. */ void FiberOrientationSelectionViewController::displayGroupSelected(const DisplayGroupEnum::Enum displayGroup) { if (m_updateInProgress) { return; } /* * Update selected display group in model. */ BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, false); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); Brain* brain = GuiManager::get()->getBrain(); DisplayPropertiesFiberOrientation* dpfo = brain->getDisplayPropertiesFiberOrientation(); dpfo->setDisplayGroupForTab(browserTabIndex, displayGroup); /* * Since display group has changed, need to update controls */ updateViewController(); /* * Apply the changes. */ processSelectionChanges(); } /** * Update the fiber orientation widget. */ void FiberOrientationSelectionViewController::updateViewController() { m_updateInProgress = true; BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); Brain* brain = GuiManager::get()->getBrain(); DisplayPropertiesFiberOrientation* dpfo = brain->getDisplayPropertiesFiberOrientation(); const DisplayGroupEnum::Enum displayGroup = dpfo->getDisplayGroupForTab(browserTabIndex); m_displayGroupComboBox->setSelectedDisplayGroup(displayGroup); //dpfo->isDisplayed(displayGroup, browserTabIndex) /* * Update file selection checkboxes */ const int32_t numberOfFileCheckBoxes = static_cast(m_fileSelectionCheckBoxes.size()); const int32_t numberOfFiberOrientFiles = brain->getNumberOfConnectivityFiberOrientationFiles(); for (int32_t iff = 0; iff < numberOfFiberOrientFiles; iff++) { CiftiFiberOrientationFile* cfof = brain->getConnectivityFiberOrientationFile(iff); QCheckBox* cb = NULL; if (iff < numberOfFileCheckBoxes) { cb = m_fileSelectionCheckBoxes[iff]; } else { cb = new QCheckBox(""); QObject::connect(cb, SIGNAL(clicked(bool)), this, SLOT(processSelectionChanges())); m_fileSelectionCheckBoxes.push_back(cb); m_selectionWidgetLayout->addWidget(cb); } cb->setText(cfof->getFileNameNoPath()); cb->setChecked(cfof->isDisplayed(displayGroup, browserTabIndex)); cb->setVisible(true); } /* * Hide unused file selection checkboxes */ for (int32_t iff = numberOfFiberOrientFiles; iff < numberOfFileCheckBoxes; iff++) { m_fileSelectionCheckBoxes[iff]->setVisible(false); } /* * Update the attributes */ m_displayFibersCheckBox->setChecked(dpfo->isDisplayed(displayGroup, browserTabIndex)); m_aboveLimitSpinBox->setValue(dpfo->getAboveLimit(displayGroup, browserTabIndex)); m_belowLimitSpinBox->setValue(dpfo->getBelowLimit(displayGroup, browserTabIndex)); m_lengthMultiplierSpinBox->setValue(dpfo->getLengthMultiplier(displayGroup, browserTabIndex)); m_fanMultiplierSpinBox->setValue(dpfo->getFanMultiplier(displayGroup, browserTabIndex)); m_minimumMagnitudeSpinBox->setValue(dpfo->getMinimumMagnitude(displayGroup, browserTabIndex)); m_drawWithMagnitudeCheckBox->setChecked(dpfo->isDrawWithMagnitude(displayGroup, browserTabIndex)); m_coloringTypeComboBox->setSelectedItem(dpfo->getColoringType(displayGroup, browserTabIndex)); m_symbolTypeComboBox->setSelectedItem(dpfo->getSymbolType(displayGroup, browserTabIndex)); m_displaySphereOrientationsCheckBox->setChecked(dpfo->isSphereOrientationsDisplayed(displayGroup, browserTabIndex)); /* * Update the samples */ m_samplesOpenGLWidget->update(); m_updateInProgress = false; } /** * Issue update events after selections are changed. */ void FiberOrientationSelectionViewController::processSelectionChanges() { if (m_updateInProgress) { return; } BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } Brain* brain = GuiManager::get()->getBrain(); const int32_t browserTabIndex = browserTabContent->getTabNumber(); DisplayPropertiesFiberOrientation* dpfo = brain->getDisplayPropertiesFiberOrientation(); const DisplayGroupEnum::Enum displayGroup = dpfo->getDisplayGroupForTab(browserTabIndex); dpfo->setDisplayed(displayGroup, browserTabIndex, m_displayFibersCheckBox->isChecked()); const int32_t numberOfFiberOrientFiles = brain->getNumberOfConnectivityFiberOrientationFiles(); CaretAssert(numberOfFiberOrientFiles <= static_cast(m_fileSelectionCheckBoxes.size())); for (int32_t iff = 0; iff < numberOfFiberOrientFiles; iff++) { CiftiFiberOrientationFile* cfof = brain->getConnectivityFiberOrientationFile(iff); cfof->setDisplayed(displayGroup, browserTabIndex, m_fileSelectionCheckBoxes[iff]->isChecked()); } updateOtherViewControllers(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * @return Create and return the spherical samples widget. */ QWidget* FiberOrientationSelectionViewController::createSamplesWidget() { m_displaySphereOrientationsCheckBox = new QCheckBox("Show Orientations"); QObject::connect(m_displaySphereOrientationsCheckBox, SIGNAL(clicked(bool)), this, SLOT(processAttributesChanges())); QGridLayout* fiberLabelsGridLayout = new QGridLayout(); fiberLabelsGridLayout->setColumnStretch(0, 0); fiberLabelsGridLayout->setColumnStretch(1, 50); fiberLabelsGridLayout->setColumnStretch(2, 50); int row = 0; fiberLabelsGridLayout->addWidget(new QLabel("Fiber "), row, 0); fiberLabelsGridLayout->addWidget(new QLabel("Mean "), row, 1); fiberLabelsGridLayout->addWidget(new QLabel("Variance"), row, 2); row++; QLabel* fiberMeanLabels[3]; QLabel* fiberVarianceLabels[3]; for (int32_t i = 0; i < 3; i++) { fiberMeanLabels[i] = new QLabel(""); fiberVarianceLabels[i] = new QLabel(""); fiberLabelsGridLayout->addWidget(new QLabel(QString::number(i+1)), row, 0); fiberLabelsGridLayout->addWidget(fiberMeanLabels[i], row, 1); fiberLabelsGridLayout->addWidget(fiberVarianceLabels[i], row, 2); row++; } m_samplesOpenGLWidget = new FiberSamplesOpenGLWidget(this->m_browserWindowIndex, m_displaySphereOrientationsCheckBox, fiberMeanLabels, fiberVarianceLabels); m_samplesOpenGLWidget->setMinimumSize(200, 200); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); layout->addWidget(m_displaySphereOrientationsCheckBox); layout->addWidget(m_samplesOpenGLWidget, 100); // stretch factor layout->addLayout(fiberLabelsGridLayout); // layout->addStretch(); return widget; } /** * Update other fiber orientation view controllers. */ void FiberOrientationSelectionViewController::updateOtherViewControllers() { for (std::set::iterator iter = s_allViewControllers.begin(); iter != s_allViewControllers.end(); iter++) { FiberOrientationSelectionViewController* fosvc = *iter; if (fosvc != this) { fosvc->updateViewController(); } } } /** * Receive events from the event manager. * * @param event * Event sent by event manager. */ void FiberOrientationSelectionViewController::receiveEvent(Event* event) { bool doUpdate = false; if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiEvent = dynamic_cast(event); CaretAssert(uiEvent); if (uiEvent->isUpdateForWindow(m_browserWindowIndex)) { if (uiEvent->isToolBoxUpdate()) { doUpdate = true; uiEvent->setEventProcessed(); } } } if (doUpdate) { updateViewController(); } } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* FiberOrientationSelectionViewController::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "FiberOrientationSelectionViewController", 1); sceneClass->addClass(m_tabWidget->saveToScene(sceneAttributes, "m_tabWidget")); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void FiberOrientationSelectionViewController::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_tabWidget->restoreFromScene(sceneAttributes, sceneClass->getClass("m_tabWidget")); } connectome-workbench-1.4.2/src/GuiQt/FiberOrientationSelectionViewController.h000066400000000000000000000102261360521144700276350ustar00rootroot00000000000000#ifndef __FIBER_ORIENTATION_SELECTION_VIEW_CONTROLLER__H_ #define __FIBER_ORIENTATION_SELECTION_VIEW_CONTROLLER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "DisplayGroupEnum.h" #include "EnumComboBoxTemplate.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" class QCheckBox; class QDoubleSpinBox; class QVBoxLayout; namespace caret { class DisplayGroupEnumComboBox; class FiberSamplesOpenGLWidget; class WuQTabWidget; class WuQTrueFalseComboBox; class FiberOrientationSelectionViewController : public QWidget, public EventListenerInterface, public SceneableInterface { Q_OBJECT public: FiberOrientationSelectionViewController(const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~FiberOrientationSelectionViewController(); void receiveEvent(Event* event); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // ADD_NEW_METHODS_HERE private slots: void processSelectionChanges(); void displayGroupSelected(const DisplayGroupEnum::Enum); void processAttributesChanges(); private: FiberOrientationSelectionViewController(const FiberOrientationSelectionViewController&); FiberOrientationSelectionViewController& operator=(const FiberOrientationSelectionViewController&); void updateViewController(); void updateOtherViewControllers(); QWidget* createSelectionWidget(); QWidget* createAttributesWidget(); QWidget* createSamplesWidget(); const int32_t m_browserWindowIndex; DisplayGroupEnumComboBox* m_displayGroupComboBox; QCheckBox* m_displayFibersCheckBox; std::vector m_fileSelectionCheckBoxes; QDoubleSpinBox* m_aboveLimitSpinBox; QDoubleSpinBox* m_belowLimitSpinBox; QDoubleSpinBox* m_minimumMagnitudeSpinBox; QDoubleSpinBox* m_lengthMultiplierSpinBox; QDoubleSpinBox* m_fanMultiplierSpinBox; EnumComboBoxTemplate* m_coloringTypeComboBox; EnumComboBoxTemplate* m_symbolTypeComboBox; QCheckBox* m_drawWithMagnitudeCheckBox; QVBoxLayout* m_selectionWidgetLayout; FiberSamplesOpenGLWidget* m_samplesOpenGLWidget; QCheckBox* m_displaySphereOrientationsCheckBox; WuQTabWidget* m_tabWidget; bool m_updateInProgress; // ADD_NEW_MEMBERS_HERE static std::set s_allViewControllers; }; #ifdef __FIBER_ORIENTATION_SELECTION_VIEW_CONTROLLER_DECLARE__ std::set FiberOrientationSelectionViewController::s_allViewControllers; #endif // __FIBER_ORIENTATION_SELECTION_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__FIBER_ORIENTATION_SELECTION_VIEW_CONTROLLER__H_ connectome-workbench-1.4.2/src/GuiQt/FiberSamplesOpenGLWidget.cxx000066400000000000000000000520511360521144700247670ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #define __FIBER_SAMPLES_OPEN_G_L_WIDGET_DECLARE__ #include "FiberSamplesOpenGLWidget.h" #undef __FIBER_SAMPLES_OPEN_G_L_WIDGET_DECLARE__ using namespace caret; #include "Brain.h" #include "BrainOpenGL.h" #include "BrainOpenGLShapeRing.h" #include "BrainOpenGLShapeSphere.h" #include "DisplayPropertiesFiberOrientation.h" #include "Fiber.h" #include "FiberOrientation.h" #include "GuiManager.h" #include "WuQMessageBox.h" /** * \class caret::FiberSamplesOpenGLWidget * \brief OpenGL Widget for drawing fiber samples on a sphere * \defgroup GuiQt * \ingroup GuiQt */ /** * Constructor. */ FiberSamplesOpenGLWidget::FiberSamplesOpenGLWidget(const int32_t browserWindowIndex, QCheckBox* enabledCheckBox, QLabel* fiberMeanLabels[3], QLabel* fiberVarianceLabels[3], QWidget* parent) #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET : QOpenGLWidget(parent) #else : QGLWidget(parent) #endif { m_browserWindowIndex = browserWindowIndex; m_enabledCheckBox = enabledCheckBox; for (int32_t i = 0; i < 3; i++) { m_fiberMeanLabels[i] = fiberMeanLabels[i]; m_fiberVarianceLabels[i] = fiberVarianceLabels[i]; } m_ring = NULL; m_sphereBig = NULL; m_sphereSmall = NULL; setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); } /** * Destructor. */ FiberSamplesOpenGLWidget::~FiberSamplesOpenGLWidget() { makeCurrent(); if (m_ring != NULL) { delete m_ring; } if (m_sphereBig != NULL) { delete m_sphereBig; } if (m_sphereSmall != NULL) { delete m_sphereSmall; } } /** * Called once prior to resizeGL() and paintGL() to * make any necessary initializations. */ void FiberSamplesOpenGLWidget::initializeGL() { glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glClearDepth(1.0); glFrontFace(GL_CCW); glEnable(GL_NORMALIZE); // // Avoid drawing backfacing polygons // glCullFace(GL_BACK); glEnable(GL_CULL_FACE); glShadeModel(GL_SMOOTH); createShapes(); } /** * Setup lighting parameters. */ void FiberSamplesOpenGLWidget::setupLighting() { glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE); float lightColor[] = { 0.9f, 0.9f, 0.9f, 1.0f }; glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor); glLightfv(GL_LIGHT1, GL_DIFFUSE, lightColor); float materialColor[] = { 0.8f, 0.8f, 0.8f, 1.0f }; glMaterialfv(GL_FRONT, GL_DIFFUSE, materialColor); glColorMaterial(GL_FRONT, GL_DIFFUSE); float ambient[] = { 0.8f, 0.8f, 0.8f, 1.0f }; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); float lightPosition[] = { 0.0f, 0.0f, 100.0f, 0.0f }; glPushMatrix(); glLoadIdentity(); glLightfv(GL_LIGHT0, GL_POSITION, lightPosition); glEnable(GL_LIGHT0); // // Light 1 position is opposite of light 0 // lightPosition[0] = -lightPosition[0]; lightPosition[1] = -lightPosition[1]; lightPosition[2] = -lightPosition[2]; glLightfv(GL_LIGHT1, GL_POSITION, lightPosition); glEnable(GL_LIGHT1); glPopMatrix(); glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT, GL_DIFFUSE); } /** * Gets called whenever the widget is resized. * @param width * New width of widget. * @param height * New height of widget. */ void FiberSamplesOpenGLWidget::resizeGL(int width, int height) { setOrthographicProjection(width, height); } /** * Set the orthographic projection. * @param width * New width. * @param height * New height. */ void FiberSamplesOpenGLWidget::setOrthographicProjection(const int width, const int height) { m_widgetWidth = width; m_widgetHeight = height; glViewport(0, 0, width, height); const double orthoSize = 125.0; const double aspectRatio = (static_cast(width) / static_cast(height)); double orthoWidth = orthoSize; double orthoHeight = orthoSize; if (aspectRatio > 1.0) { orthoWidth *= aspectRatio; } else { const float inverseAspectRatio = 1.0 / aspectRatio; orthoHeight *= inverseAspectRatio; } const double orthoNearFar = 5000.0; // allows zooming double orthographicRight = orthoWidth; double orthographicLeft = -orthoWidth; double orthographicTop = orthoHeight; double orthographicBottom = -orthoHeight; double orthographicNear = -orthoNearFar; double orthographicFar = orthoNearFar; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(orthographicLeft, orthographicRight, orthographicBottom, orthographicTop, orthographicNear, orthographicFar); glMatrixMode(GL_MODELVIEW); } /** * Called when the widget needs to be repainted. */ void FiberSamplesOpenGLWidget::paintGL() { setOrthographicProjection(width(), height()); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glMatrixMode(GL_MODELVIEW); setupLighting(); glPushMatrix(); glLoadIdentity(); double rotationMatrixElements[16]; m_rotationMatrix.getMatrixForOpenGL(rotationMatrixElements); glMultMatrixd(rotationMatrixElements); const GLfloat lineStart = -s_sphereBigRadius * 5.0; const GLfloat lineEnd = s_sphereBigRadius * 5.0; glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); /* * Axis lines */ glLineWidth(3.0); glBegin(GL_LINES); glColor3f(0.5, 0.0, 0.0); glVertex3f(lineStart, 0.0, 0.0); glVertex3f(0.0, 0.0, 0.0); glColor3f(1.0,0.0, 0.0); glVertex3f(0.0, 0.0, 0.0); glVertex3f(lineEnd, 0.0, 0.0); glColor3f(0.0, 0.5, 0.0); glVertex3f(0.0, lineStart, 0.0); glVertex3f(0.0, 0.0, 0.0); glColor3f(0.0, 1.0, 0.0); glVertex3f(0.0, 0.0, 0.0); glVertex3f(0.0, lineEnd, 0.0); glColor3f(0.0, 0.0, 0.5); glVertex3f(0.0, 0.0, lineStart); glVertex3f(0.0, 0.0, 0.0); glColor3f(0.0,0.0, 1.0); glVertex3f(0.0, 0.0, 0.0); glVertex3f(0.0, 0.0, lineEnd); glEnd(); glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); /* * Sphere */ // glColor3f(0.7, // 0.7, // 0.7); const float rgba[4] = { 0.7f, 0.7f, 0.7f, 1.0f }; m_sphereBig->draw(rgba); glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); if (m_enabledCheckBox->isChecked()) { drawOrientations(); } glPopMatrix(); } /** * Draw the fibers on the sphere */ void FiberSamplesOpenGLWidget::drawOrientations() { glDisable(GL_CULL_FACE); DisplayPropertiesFiberOrientation* dpfo = GuiManager::get()->getBrain()->getDisplayPropertiesFiberOrientation(); std::vector xVectors; std::vector yVectors; std::vector zVectors; FiberOrientation* fiberOrientation; AString errorMessage; Brain* brain = GuiManager::get()->getBrain(); if (brain->getFiberOrientationSphericalSamplesVectors(xVectors, yVectors, zVectors, fiberOrientation, errorMessage)) { const DisplayGroupEnum::Enum displayGroup = dpfo->getDisplayGroupForTab(this->m_browserWindowIndex); const FiberOrientationColoringTypeEnum::Enum coloringType = dpfo->getColoringType(displayGroup, m_browserWindowIndex); const float minimumMagnitude = dpfo->getMinimumMagnitude(displayGroup, m_browserWindowIndex); /* * First orientations */ const int32_t numVectorsX = static_cast(xVectors.size()); for (int32_t i = 0; i < numVectorsX; i++) { if (xVectors[i].magnitude < minimumMagnitude) { continue; } float xyz[3] = { xVectors[i].direction[0] * s_sphereBigRadius, xVectors[i].direction[1] * s_sphereBigRadius, xVectors[i].direction[2] * s_sphereBigRadius }; float rgba[4] = { 0.0, 0.0, 0.0, 255.0 }; switch (coloringType) { case FiberOrientationColoringTypeEnum::FIBER_COLORING_FIBER_INDEX_AS_RGB: //glColor3f(1.0, 0.0, 0.0); rgba[0] = 1.0; break; case FiberOrientationColoringTypeEnum::FIBER_COLORING_XYZ_AS_RGB: //glColor3fv(xVectors[i].rgb); rgba[0] = xVectors[i].rgb[0]; rgba[1] = xVectors[i].rgb[1]; rgba[2] = xVectors[i].rgb[2]; break; } glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); m_sphereSmall->draw(rgba); glPopMatrix(); glPushMatrix(); glTranslatef(-xyz[0], -xyz[1], -xyz[2]); m_sphereSmall->draw(rgba); glPopMatrix(); } /* * Second orientations */ const int32_t numVectorsY = static_cast(yVectors.size()); for (int32_t i = 0; i < numVectorsY; i++) { if (yVectors[i].magnitude < minimumMagnitude) { continue; } float xyz[3] = { yVectors[i].direction[0] * s_sphereBigRadius, yVectors[i].direction[1] * s_sphereBigRadius, yVectors[i].direction[2] * s_sphereBigRadius }; float rgba[4] = { 0.0, 0.0, 0.0, 255.0 }; switch (coloringType) { case FiberOrientationColoringTypeEnum::FIBER_COLORING_FIBER_INDEX_AS_RGB: //glColor3f(0.0, 0.0, 1.0); // BLUE (RBG!) rgba[2] = 1.0; break; case FiberOrientationColoringTypeEnum::FIBER_COLORING_XYZ_AS_RGB: //glColor3fv(yVectors[i].rgb); rgba[0] = yVectors[i].rgb[0]; rgba[1] = yVectors[i].rgb[1]; rgba[2] = yVectors[i].rgb[2]; break; } glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); m_sphereSmall->draw(rgba); glPopMatrix(); glPushMatrix(); glTranslatef(-xyz[0], -xyz[1], -xyz[2]); m_sphereSmall->draw(rgba); glPopMatrix(); } /* * Third orientations */ const int32_t numVectorsZ = static_cast(zVectors.size()); for (int32_t i = 0; i < numVectorsZ; i++) { if (zVectors[i].magnitude < minimumMagnitude) { continue; } float xyz[3] = { zVectors[i].direction[0] * s_sphereBigRadius, zVectors[i].direction[1] * s_sphereBigRadius, zVectors[i].direction[2] * s_sphereBigRadius }; float rgba[4] = { 0.0, 0.0, 0.0, 255.0 }; switch (coloringType) { case FiberOrientationColoringTypeEnum::FIBER_COLORING_FIBER_INDEX_AS_RGB: //glColor3f(0.0, 1.0, 0.0); // GREEN (RBG!) rgba[1] = 1.0; break; case FiberOrientationColoringTypeEnum::FIBER_COLORING_XYZ_AS_RGB: //glColor3fv(zVectors[i].rgb); rgba[0] = zVectors[i].rgb[0]; rgba[1] = zVectors[i].rgb[1]; rgba[2] = zVectors[i].rgb[2]; break; } glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); m_sphereSmall->draw(rgba); glPopMatrix(); glPushMatrix(); glTranslatef(-xyz[0], -xyz[1], -xyz[2]); m_sphereSmall->draw(rgba); glPopMatrix(); } double viewingMatrixArray[16]; glGetDoublev(GL_MODELVIEW_MATRIX, viewingMatrixArray); Matrix4x4 viewingMatrix; viewingMatrix.setMatrixFromOpenGL(viewingMatrixArray); Matrix4x4 inverseViewingMatrix(viewingMatrix); inverseViewingMatrix.invert(); inverseViewingMatrix.setTranslation(0.0, 0.0, 0.0); double inverseViewingMatrixArray[16]; inverseViewingMatrix.getMatrixForOpenGL(inverseViewingMatrixArray); /* * Orientation Ellipse */ const float radiansToDegrees = 180.0 / M_PI; if (fiberOrientation != NULL) { const int32_t numFibers = fiberOrientation->m_numberOfFibers; for (int32_t j = 0; j < numFibers; j++) { const Fiber* fiber = fiberOrientation->m_fibers[j]; if (fiber->m_valid) { if (j < 3) { m_fiberMeanLabels[j]->setText(AString::number(fiber->m_meanF)); m_fiberVarianceLabels[j]->setText(AString::number(fiber->m_varF)); } /* * Only draw if magnitude exceeds minimum magnitude */ if (fiber->m_meanF < minimumMagnitude) { continue; } float rgba[4] = { 0.0, 0.0, 0.0, 1.0 }; switch (coloringType) { case FiberOrientationColoringTypeEnum::FIBER_COLORING_FIBER_INDEX_AS_RGB: { const int32_t colorIndex = j % 3; switch (colorIndex) { case 0: rgba[0] = 1.0; //glColor3f(1.0, 0.0, 0.0); break; case 1: rgba[2] = 1.0; //glColor3f(0.0, 0.0, 1.0); break; case 2: rgba[1] = 1.0; //glColor3f(0.0, 1.0, 0.0); break; } } break; case FiberOrientationColoringTypeEnum::FIBER_COLORING_XYZ_AS_RGB: //glColor3fv(fiber->m_directionUnitVectorRGB); rgba[0] = fiber->m_directionUnitVectorRGB[0]; rgba[1] = fiber->m_directionUnitVectorRGB[1]; rgba[2] = fiber->m_directionUnitVectorRGB[2]; break; } const float maxAngle = M_PI_2 * 0.95; float baseMajorAngle = fiber->m_fanningMajorAxisAngle; if (baseMajorAngle > maxAngle) { baseMajorAngle = maxAngle; } float baseMinorAngle = fiber->m_fanningMinorAxisAngle; if (baseMinorAngle > maxAngle) { baseMinorAngle = maxAngle; } const float z = s_sphereBigRadius; const float baseRadiusScaling = 1.0; const float maxWidth = z; const float majorAxis = std::min(z * std::tan(baseMajorAngle) * baseRadiusScaling, maxWidth); const float minorAxis = std::min(z * std::tan(baseMinorAngle) * baseRadiusScaling, maxWidth); glPushMatrix(); glRotatef(-fiber->m_phi * radiansToDegrees, 0.0, 0.0, 1.0); glRotatef(-fiber->m_theta * radiansToDegrees, 0.0, 1.0, 0.0); glRotatef(-fiber->m_psi * radiansToDegrees, 0.0, 0.0, 1.0); glPushMatrix(); glTranslatef(0.0, 0.0, s_sphereBigRadius); glScalef(majorAxis * 4.0, minorAxis * 4.0, 1.0); m_ring->draw(rgba); glPopMatrix(); glPushMatrix(); glTranslatef(0.0, 0.0, -s_sphereBigRadius); glScalef(majorAxis * 4.0, minorAxis * 4.0, 1.0); m_ring->draw(rgba); glPopMatrix(); glPopMatrix(); } } } } else { if (errorMessage.isEmpty() == false) { WuQMessageBox::errorOk(this, errorMessage); } } glEnable(GL_CULL_FACE); } /** * Create the shapes on which fibers are viewed. */ void FiberSamplesOpenGLWidget::createShapes() { if (m_sphereBig == NULL) { m_sphereBig = new BrainOpenGLShapeSphere(25, s_sphereBigRadius); } if (m_sphereSmall == NULL) { m_sphereSmall = new BrainOpenGLShapeSphere(5, s_sphereSmallRadius); } if (m_ring == NULL) { m_ring = new BrainOpenGLShapeRing(10, 0.75, 1.0); } } /** * Receive mouse press events from Qt. * @param me * The mouse event. */ void FiberSamplesOpenGLWidget::mousePressEvent(QMouseEvent* me) { const Qt::MouseButton button = me->button(); // const Qt::KeyboardModifiers keyModifiers = me->modifiers(); if (button == Qt::LeftButton) { const int mouseX = me->x(); const int mouseY = m_widgetHeight - me->y(); m_mousePressX = mouseX; m_mousePressY = mouseY; m_lastMouseX = mouseX; m_lastMouseY = mouseY; } else { m_mousePressX = -10000; m_mousePressY = -10000; } me->accept(); } /** * Receive mouse button release events from Qt. * @param me * The mouse event. */ void FiberSamplesOpenGLWidget::mouseReleaseEvent(QMouseEvent* me) { m_mousePressX = -10000; m_mousePressY = -10000; me->accept(); } /** * Receive mouse move events from Qt. * @param me * The mouse event. */ void FiberSamplesOpenGLWidget::mouseMoveEvent(QMouseEvent* me) { const Qt::MouseButton button = me->button(); // Qt::KeyboardModifiers keyModifiers = me->modifiers(); if (button == Qt::NoButton) { if (me->buttons() == Qt::LeftButton) { const int mouseX = me->x(); const int mouseY = m_widgetHeight - me->y(); const int dx = mouseX - m_lastMouseX; const int dy = mouseY - m_lastMouseY; const int absDX = (dx >= 0) ? dx : -dx; const int absDY = (dy >= 0) ? dy : -dy; if ((absDX > 0) || (absDY > 0)) { m_rotationMatrix.rotateX(-dy); m_rotationMatrix.rotateY(dx); } m_lastMouseX = mouseX; m_lastMouseY = mouseY; } } me->accept(); #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET this->update(); #else this->updateGL(); #endif } connectome-workbench-1.4.2/src/GuiQt/FiberSamplesOpenGLWidget.h000066400000000000000000000073351360521144700244210ustar00rootroot00000000000000#ifndef __FIBER_SAMPLES_OPEN_G_L_WIDGET__H_ #define __FIBER_SAMPLES_OPEN_G_L_WIDGET__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /* * When GLEW is used, CaretOpenGLInclude.h will include "Gl/glew.h". * Gl/glew.h MUST BE BEFORE Gl/gl.h and Gl/gl.h is included by * QGLWidget so, we must include CaretOpenGL.h before QGLWidget. */ #include "CaretOpenGLInclude.h" #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET #include #else #include #endif #include "Matrix4x4.h" class QLabel; class QCheckBox; namespace caret { class BrainOpenGLShapeRing; class BrainOpenGLShapeSphere; #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET class FiberSamplesOpenGLWidget : public QOpenGLWidget { #else class FiberSamplesOpenGLWidget : public QGLWidget { #endif Q_OBJECT public: FiberSamplesOpenGLWidget(const int32_t browserWindowIndex, QCheckBox* enabledCheckBox, QLabel* fiberMeanLabels[3], QLabel* fiberVarianceLabels[3], QWidget* parent = 0); virtual ~FiberSamplesOpenGLWidget(); // ADD_NEW_METHODS_HERE protected: void initializeGL(); void resizeGL(int width, int height); void paintGL(); void mouseMoveEvent(QMouseEvent* e); void mousePressEvent(QMouseEvent* e); void mouseReleaseEvent(QMouseEvent* e); private: FiberSamplesOpenGLWidget(const FiberSamplesOpenGLWidget&); FiberSamplesOpenGLWidget& operator=(const FiberSamplesOpenGLWidget&); void createShapes(); void setupLighting(); void setOrthographicProjection(const int width, const int height); void drawOrientations(); // ADD_NEW_MEMBERS_HERE int32_t m_browserWindowIndex; BrainOpenGLShapeSphere* m_sphereBig; BrainOpenGLShapeSphere* m_sphereSmall; BrainOpenGLShapeRing* m_ring; GLint m_widgetWidth; GLint m_widgetHeight; int m_mousePressX; int m_mousePressY; int m_lastMouseX; int m_lastMouseY; Matrix4x4 m_rotationMatrix; QCheckBox* m_enabledCheckBox; QLabel* m_fiberMeanLabels[3]; QLabel* m_fiberVarianceLabels[3]; static const float s_sphereBigRadius; static const float s_sphereSmallRadius; }; #ifdef __FIBER_SAMPLES_OPEN_G_L_WIDGET_DECLARE__ const float FiberSamplesOpenGLWidget::s_sphereBigRadius = 100.0; const float FiberSamplesOpenGLWidget::s_sphereSmallRadius = 1.0; #endif // __FIBER_SAMPLES_OPEN_G_L_WIDGET_DECLARE__ } // namespace #endif //__FIBER_SAMPLES_OPEN_G_L_WIDGET__H_ connectome-workbench-1.4.2/src/GuiQt/FociProjectionDialog.cxx000066400000000000000000000252621360521144700242430ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #define __FOCI_PROJECTION_DIALOG_DECLARE__ #include "FociProjectionDialog.h" #undef __FOCI_PROJECTION_DIALOG_DECLARE__ #include "Brain.h" #include "CursorDisplayScoped.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "FociFile.h" #include "GuiManager.h" #include "Surface.h" #include "SurfaceProjector.h" #include "SurfaceSelectionViewController.h" #include "WuQFactory.h" #include "WuQMessageBox.h" using namespace caret; /** * \class caret::FociProjectionDialog * \brief Dialog for projection of foci. * \ingroup GuiQt */ /** * Constructor. * @param parent * The parent widget. */ FociProjectionDialog::FociProjectionDialog(QWidget* parent) : WuQDialogModal("Project Foci", parent) { m_objectNamePrefix = "FociProjectDialog"; QWidget* surfaceWidget = NULL; //createSurfaceSelectionWidget(); QWidget* fociFileWidget = createFociFileSelectionWidget(); QWidget* optionsWidget = createOptionsWidget(); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); if (surfaceWidget != NULL) { layout->addWidget(surfaceWidget); } layout->addWidget(fociFileWidget); layout->addWidget(optionsWidget); setCentralWidget(widget, WuQDialog::SCROLL_AREA_NEVER); } /** * Destructor. */ FociProjectionDialog::~FociProjectionDialog() { } /** * Called when the OK button is clicked. */ void FociProjectionDialog::okButtonClicked() { CursorDisplayScoped cursor; cursor.showWaitCursor(); Brain* brain = GuiManager::get()->getBrain(); std::vector surfaceFiles = brain->getPrimaryAnatomicalSurfaceFiles(); SurfaceFile* leftSurfaceFile = NULL; SurfaceFile* rightSurfaceFile = NULL; SurfaceFile* cerebellumSurfaceFile = NULL; for (std::vector::iterator iter = surfaceFiles.begin(); iter != surfaceFiles.end(); iter++) { const SurfaceFile* sf = *iter; switch (sf->getStructure()) { case StructureEnum::CORTEX_LEFT: leftSurfaceFile = const_cast(sf); break; case StructureEnum::CORTEX_RIGHT: rightSurfaceFile = const_cast(sf); break; case StructureEnum::CEREBELLUM: cerebellumSurfaceFile = const_cast(sf); break; default: break; } } // if (m_leftSurfaceCheckBox != NULL) { // if (m_leftSurfaceCheckBox->isChecked()) { // const Surface* sf = m_leftSurfaceViewController->getSurface(); // if (sf != NULL) { // surfaceFiles.push_back(sf); // } // } // } // if (m_rightSurfaceCheckBox != NULL) { // if (m_rightSurfaceCheckBox->isChecked()) { // const Surface* sf = m_rightSurfaceViewController->getSurface(); // if (sf != NULL) { // surfaceFiles.push_back(sf); // } // } // } // if (m_cerebellumSurfaceCheckBox != NULL) { // if (m_cerebellumSurfaceCheckBox->isChecked()) { // const Surface* sf = m_cerebellumSurfaceViewController->getSurface(); // if (sf != NULL) { // surfaceFiles.push_back(sf); // } // } // } AString errorMessages = ""; const int32_t numberOfFociFiles = static_cast(m_fociFiles.size()); for (int32_t i = 0; i < numberOfFociFiles; i++) { if (m_fociFileCheckBoxes[i]->isChecked()) { SurfaceProjector projector(leftSurfaceFile, rightSurfaceFile, cerebellumSurfaceFile); if (m_projectAboveSurfaceCheckBox->isChecked()) { projector.setSurfaceOffset(m_projectAboveSurfaceSpinBox->value()); } FociFile* ff = brain->getFociFile(i); try { projector.projectFociFile(ff); } catch (const SurfaceProjectorException& spe) { errorMessages += (spe.whatString() + "\n"); } } } EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); cursor.restoreCursor(); if (errorMessages.isEmpty() == false) { WuQMessageBox::errorOk(this, errorMessages); } WuQDialogModal::okButtonClicked(); } /** * @return The controls for surface selection. */ QWidget* FociProjectionDialog::createSurfaceSelectionWidget() { Brain* brain = GuiManager::get()->getBrain(); BrainStructure* leftBrainStructure = brain->getBrainStructure(StructureEnum::CORTEX_LEFT, false); BrainStructure* rightBrainStructure = brain->getBrainStructure(StructureEnum::CORTEX_RIGHT, false); BrainStructure* cerebellumBrainStructure = brain->getBrainStructure(StructureEnum::CEREBELLUM, false); m_leftSurfaceCheckBox = NULL; m_leftSurfaceViewController = NULL; if (leftBrainStructure != NULL) { m_leftSurfaceCheckBox = new QCheckBox("Left: "); m_leftSurfaceCheckBox->setChecked(true); m_leftSurfaceViewController = new SurfaceSelectionViewController(this, leftBrainStructure, (m_objectNamePrefix + ":LeftSurface"), "foci projection left"); m_leftSurfaceViewController->updateControl(); } m_rightSurfaceCheckBox = NULL; m_rightSurfaceViewController = NULL; if (rightBrainStructure != NULL) { m_rightSurfaceCheckBox = new QCheckBox("Right: "); m_rightSurfaceCheckBox->setChecked(true); m_rightSurfaceViewController = new SurfaceSelectionViewController(this, rightBrainStructure, (m_objectNamePrefix + ":RightSurface"), "foci projection right"); m_rightSurfaceViewController->updateControl(); } m_cerebellumSurfaceCheckBox = NULL; m_cerebellumSurfaceViewController = NULL; if (cerebellumBrainStructure != NULL) { m_cerebellumSurfaceCheckBox = new QCheckBox("Cerebellum: "); m_cerebellumSurfaceCheckBox->setChecked(true); m_cerebellumSurfaceViewController = new SurfaceSelectionViewController(this, cerebellumBrainStructure, (m_objectNamePrefix + ":CerebellumSurface"), "foci projection cerebellum"); m_cerebellumSurfaceViewController->updateControl(); } QGroupBox* groupBox = new QGroupBox("Projection Surfaces"); QGridLayout* layout = new QGridLayout(groupBox); layout->setColumnStretch(0, 0); layout->setColumnStretch(1, 100); int rowIndex = layout->rowCount(); if (m_leftSurfaceCheckBox != NULL) { layout->addWidget(m_leftSurfaceCheckBox, rowIndex, 0); layout->addWidget(m_leftSurfaceViewController->getWidget(), rowIndex, 1); rowIndex++; } if (m_rightSurfaceCheckBox != NULL) { layout->addWidget(m_rightSurfaceCheckBox, rowIndex, 0); layout->addWidget(m_rightSurfaceViewController->getWidget(), rowIndex, 1); rowIndex++; } if (m_cerebellumSurfaceCheckBox != NULL) { layout->addWidget(m_cerebellumSurfaceCheckBox, rowIndex, 0); layout->addWidget(m_cerebellumSurfaceViewController->getWidget(), rowIndex, 1); rowIndex++; } return groupBox; } /** * @return The controls for foci file selection. */ QWidget* FociProjectionDialog::createFociFileSelectionWidget() { QGroupBox* groupBox = new QGroupBox("Foci Files for Projection"); QVBoxLayout* layout = new QVBoxLayout(groupBox); Brain* brain = GuiManager::get()->getBrain(); const int32_t numberOfFociFiles = brain->getNumberOfFociFiles(); for (int32_t i = 0; i < numberOfFociFiles; i++) { FociFile* ff = brain->getFociFile(i); m_fociFiles.push_back(ff); QCheckBox* checkBox = new QCheckBox(ff->getFileNameNoPath()); checkBox->setChecked(true); m_fociFileCheckBoxes.push_back(checkBox); layout->addWidget(checkBox); } return groupBox; } /** * @return The options controls. */ QWidget* FociProjectionDialog::createOptionsWidget() { m_projectAboveSurfaceCheckBox = new QCheckBox("Project fixed distance above surface(s)"); m_projectAboveSurfaceSpinBox = WuQFactory::newDoubleSpinBox(); m_projectAboveSurfaceSpinBox->setRange(-100000.0, 100000.0); m_projectAboveSurfaceSpinBox->setDecimals(2); m_projectAboveSurfaceSpinBox->setSingleStep(1.0); QObject::connect(m_projectAboveSurfaceCheckBox, SIGNAL(toggled(bool)), m_projectAboveSurfaceSpinBox, SLOT(setEnabled(bool))); m_projectAboveSurfaceCheckBox->setChecked(false); QGroupBox* groupBox = new QGroupBox("Projection Options"); QGridLayout* layout = new QGridLayout(groupBox); layout->setColumnStretch(0, 0); layout->setColumnStretch(1, 100); int rowIndex = layout->rowCount(); layout->addWidget(m_projectAboveSurfaceCheckBox, rowIndex, 0); layout->addWidget(m_projectAboveSurfaceSpinBox, rowIndex, 1); rowIndex++; return groupBox; } connectome-workbench-1.4.2/src/GuiQt/FociProjectionDialog.h000066400000000000000000000050701360521144700236630ustar00rootroot00000000000000#ifndef __FOCI_PROJECTION_DIALOG__H_ #define __FOCI_PROJECTION_DIALOG__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WuQDialogModal.h" class QCheckBox; class QDoubleSpinBox; namespace caret { class FociFile; class SurfaceSelectionViewController; class FociProjectionDialog : public WuQDialogModal { Q_OBJECT public: FociProjectionDialog(QWidget* parent); virtual ~FociProjectionDialog(); // ADD_NEW_METHODS_HERE protected: virtual void okButtonClicked(); private: FociProjectionDialog(const FociProjectionDialog&); FociProjectionDialog& operator=(const FociProjectionDialog&); QWidget* createSurfaceSelectionWidget(); QWidget* createFociFileSelectionWidget(); QWidget* createOptionsWidget(); QString m_objectNamePrefix; QCheckBox* m_leftSurfaceCheckBox; SurfaceSelectionViewController* m_leftSurfaceViewController; QCheckBox* m_rightSurfaceCheckBox; SurfaceSelectionViewController* m_rightSurfaceViewController; QCheckBox* m_cerebellumSurfaceCheckBox; SurfaceSelectionViewController* m_cerebellumSurfaceViewController; QCheckBox* m_projectAboveSurfaceCheckBox; QDoubleSpinBox* m_projectAboveSurfaceSpinBox; std::vector m_fociFiles; std::vector m_fociFileCheckBoxes; // ADD_NEW_MEMBERS_HERE }; #ifdef __FOCI_PROJECTION_DIALOG_DECLARE__ // #endif // __FOCI_PROJECTION_DIALOG_DECLARE__ } // namespace #endif //__FOCI_PROJECTION_DIALOG__H_ connectome-workbench-1.4.2/src/GuiQt/FociPropertiesEditorDialog.cxx000066400000000000000000000612451360521144700254330ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #define __FOCI_PROPERTIES_EDITOR_DIALOG__DECLARE__ #include "FociPropertiesEditorDialog.h" #undef __FOCI_PROPERTIES_EDITOR_DIALOG__DECLARE__ #include "Brain.h" #include "BrowserTabContent.h" #include "Focus.h" #include "FociFile.h" #include "CaretAssert.h" #include "CaretFileDialog.h" #include "DisplayPropertiesFoci.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventDataFileAdd.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "GiftiLabelTableEditor.h" #include "GiftiLabelTableSelectionComboBox.h" #include "CaretLogger.h" #include "GuiManager.h" #include "SurfaceProjector.h" #include "WuQDataEntryDialog.h" #include "WuQFactory.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::FociPropertiesEditorDialog * \brief dialog for Foci Properties Editor * \ingroup GuiQt */ /** * Create (edit and add) a new focus. * * @param focus * The focus that will be displayed in the focus editor. * If the user accepts (presses OK) to add the focus * it will be added to the selected foci file. If the * user cancels, the focus will be destroyed. Thus, * the caller MUST NEVER access the focus after calling * this static method. * @param browserTabContent * Tab content on which focis are created. * @param parent * Parent widget on which dialog is displayed. * @return * true if user pressed OK, else false. */ bool FociPropertiesEditorDialog::createFocus(Focus* focus, BrowserTabContent* browserTabContent, QWidget* parent) { CaretAssert(focus); if (s_previousCreateFocus != NULL) { focus->setName(s_previousCreateFocus->getName()); focus->setArea(s_previousCreateFocus->getArea()); focus->setClassName(s_previousCreateFocus->getClassName()); focus->setComment(s_previousCreateFocus->getComment()); focus->setExtent(s_previousCreateFocus->getExtent()); focus->setGeography(s_previousCreateFocus->getGeography()); focus->setRegionOfInterest(s_previousCreateFocus->getRegionOfInterest()); focus->setStatistic(s_previousCreateFocus->getStatistic()); } FociPropertiesEditorDialog focusCreateDialog("Create Focus", s_previousCreateFociFile, focus, true, parent); if (focusCreateDialog.exec() == FociPropertiesEditorDialog::Accepted) { s_previousCreateFociFile = focusCreateDialog.getSelectedFociFile(); if (s_previousCreateFocus == NULL) { s_previousCreateFocus = new Focus(); } focusCreateDialog.loadFromDialogIntoFocusData(s_previousCreateFocus); s_previousCreateFociFile->addFocus(focus); if (browserTabContent != NULL) { const int32_t tabIndex = browserTabContent->getTabNumber(); DisplayPropertiesFoci* dsf = GuiManager::get()->getBrain()->getDisplayPropertiesFoci(); DisplayGroupEnum::Enum displayGroup = dsf->getDisplayGroupForTab(tabIndex); dsf->setDisplayed(displayGroup, tabIndex, true); } focusCreateDialog.updateGraphicsAndUserInterface(); return true; } delete focus; return false; } /** * Edit an existing focus. * * @param focus * The focus that will be displayed in the focus editor. * If the user presses the OK button the focus will be * updated. Otherwise, no further action is taken. * @param parent * Parent widget on which dialog is displayed. * @return * true if user pressed OK, else false. */ bool FociPropertiesEditorDialog::editFocus(FociFile* fociFile, Focus* focus, QWidget* parent) { FociPropertiesEditorDialog fped("Edit Focus", fociFile, focus, false, parent); if (fped.exec() == FociPropertiesEditorDialog::Accepted) { return true; } return false; } /** * Delete all static members to eliminate reported memory leaks. */ void FociPropertiesEditorDialog::deleteStaticMembers() { if (s_previousCreateFocus != NULL) { delete s_previousCreateFocus; s_previousCreateFocus = NULL; } } /** * Constructor. */ FociPropertiesEditorDialog::FociPropertiesEditorDialog(const QString& title, FociFile* fociFile, Focus* focus, const bool allowFociFileSelection, QWidget* parent) : WuQDialogModal(title, parent) { CaretAssert(focus); m_focus = focus; m_classComboBox = NULL; /* * File selection combo box */ QLabel* fociFileLabel = new QLabel("File"); m_fociFileSelectionComboBox = new QComboBox(); WuQtUtilities::setToolTipAndStatusTip(m_fociFileSelectionComboBox, "Selects an existing focus file\n" "to which new focus are added."); QObject::connect(m_fociFileSelectionComboBox, SIGNAL(activated(int)), this, SLOT(fociFileSelected())); QAction* newFileAction = WuQtUtilities::createAction("New", "Create a new focus file", this, this, SLOT(newFociFileButtonClicked())); QToolButton* newFileToolButton = new QToolButton(); newFileToolButton->setDefaultAction(newFileAction); WuQtUtilities::setToolButtonStyleForQt5Mac(newFileToolButton); /* * Completer for name */ m_nameCompleterStringListModel = new QStringListModel(this); /* * Name */ QLabel* nameLabel = new QLabel("Name"); m_nameComboBox = new GiftiLabelTableSelectionComboBox(this); m_nameComboBox->setUnassignedLabelTextOverride("Select Name"); QAction* displayNameColorEditorAction = WuQtUtilities::createAction("Add/Edit...", "Add and/or edit name colors", this, this, SLOT(displayNameEditor())); QToolButton* displayNameColorEditorToolButton = new QToolButton(); displayNameColorEditorToolButton->setDefaultAction(displayNameColorEditorAction); WuQtUtilities::setToolButtonStyleForQt5Mac(displayNameColorEditorToolButton); /* * Class */ QLabel* classLabel = new QLabel("Class"); m_classComboBox = new GiftiLabelTableSelectionComboBox(this); WuQtUtilities::setToolTipAndStatusTip(m_classComboBox->getWidget(), "The class is used to group focuss with similar\n" "characteristics. Controls are available to\n" "display focuss by their class attributes."); QAction* displayClassEditorAction = WuQtUtilities::createAction("Add/Edit...", "Add and/or edit classes", this, this, SLOT(displayClassEditor())); QToolButton* displayClassEditorToolButton = new QToolButton(); displayClassEditorToolButton->setDefaultAction(displayClassEditorAction); WuQtUtilities::setToolButtonStyleForQt5Mac(displayClassEditorToolButton); /* * Coordinates */ QLabel* coordLabel = new QLabel("XYZ (mm)"); m_xCoordSpinBox = WuQFactory::newDoubleSpinBox(); m_xCoordSpinBox->setDecimals(2); m_xCoordSpinBox->setSingleStep(1.0); m_xCoordSpinBox->setRange(-10000000.0, 10000000.0); m_yCoordSpinBox = WuQFactory::newDoubleSpinBox(); m_yCoordSpinBox->setDecimals(2); m_yCoordSpinBox->setSingleStep(1.0); m_yCoordSpinBox->setRange(-10000000.0, 10000000.0); m_zCoordSpinBox = WuQFactory::newDoubleSpinBox(); m_zCoordSpinBox->setDecimals(2); m_zCoordSpinBox->setSingleStep(1.0); m_zCoordSpinBox->setRange(-10000000.0, 10000000.0); /* * Comment */ QLabel* commentLabel = new QLabel("Comment"); m_commentTextEdit = new QTextEdit(); m_commentTextEdit->setFixedHeight(60); QLabel* areaLabel = new QLabel("Area"); m_areaLineEdit = new QLineEdit(); QLabel* geographyLabel = new QLabel("Geography"); m_geographyLineEdit = new QLineEdit(); QLabel* extentLabel = new QLabel("Extent"); m_extentSpinBox = WuQFactory::newDoubleSpinBox(); m_extentSpinBox->setDecimals(2); m_extentSpinBox->setSingleStep(1.0); m_extentSpinBox->setRange(-10000000.0, 10000000.0); QLabel* regionOfInterestLabel = new QLabel("ROI"); m_regionOfInterestLineEdit = new QLineEdit(); QLabel* statisticLabel = new QLabel("Statistic"); m_statisticLineEdit = new QLineEdit(); m_projectCheckBox = new QCheckBox("Project to Surface"); m_projectCheckBox->setChecked(s_previousFociProjectSelected); /* * Layout widgets */ QWidget* widget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 4, 4); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); gridLayout->setColumnStretch(2, 100); gridLayout->setColumnStretch(3, 100); gridLayout->setColumnStretch(4, 0); int row = 0; gridLayout->addWidget(fociFileLabel, row, 0); gridLayout->addWidget(m_fociFileSelectionComboBox, row, 1, 1, 3); gridLayout->addWidget(newFileToolButton, row, 4); row++; gridLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), row, 0, 1, 5); row++; gridLayout->addWidget(nameLabel, row, 0); gridLayout->addWidget(m_nameComboBox->getWidget(), row, 1, 1, 3); gridLayout->addWidget(displayNameColorEditorToolButton, row, 4); row++; gridLayout->addWidget(classLabel, row, 0); gridLayout->addWidget(m_classComboBox->getWidget(), row, 1, 1, 3); gridLayout->addWidget(displayClassEditorToolButton, row, 4); row++; gridLayout->addWidget(coordLabel, row, 0); gridLayout->addWidget(m_xCoordSpinBox, row, 1); gridLayout->addWidget(m_yCoordSpinBox, row, 2); gridLayout->addWidget(m_zCoordSpinBox, row, 3); row++; gridLayout->addWidget(commentLabel, row, 0); gridLayout->addWidget(m_commentTextEdit, row, 1, 1, 3); row++; gridLayout->addWidget(areaLabel, row, 0); gridLayout->addWidget(m_areaLineEdit, row, 1, 1, 3); row++; gridLayout->addWidget(geographyLabel, row, 0); gridLayout->addWidget(m_geographyLineEdit, row, 1, 1, 3); row++; gridLayout->addWidget(extentLabel, row, 0); gridLayout->addWidget(m_extentSpinBox, row, 1, 1, 1); row++; gridLayout->addWidget(regionOfInterestLabel, row, 0); gridLayout->addWidget(m_regionOfInterestLineEdit, row, 1, 1, 3); row++; gridLayout->addWidget(statisticLabel, row, 0); gridLayout->addWidget(m_statisticLineEdit, row, 1, 1, 3); row++; gridLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), row, 0, 1, 4); row++; gridLayout->addWidget(m_projectCheckBox, row, 0, 1, 4); row++; /* * Allow/Disallow file selection */ fociFileLabel->setEnabled(allowFociFileSelection); m_fociFileSelectionComboBox->setEnabled(allowFociFileSelection); newFileToolButton->setEnabled(allowFociFileSelection); /* * Set the widget for the dialog. */ setCentralWidget(widget, WuQDialog::SCROLL_AREA_NEVER); loadFociFileComboBox(fociFile); loadFromFocusDataIntoDialog(m_focus); } /** * Destructor. */ FociPropertiesEditorDialog::~FociPropertiesEditorDialog() { } /** * Get the selected focus file. * @return FociFile or NULL if no focus file. */ FociFile* FociPropertiesEditorDialog::getSelectedFociFile() { FociFile* fociFile = NULL; const int fileComboBoxIndex = m_fociFileSelectionComboBox->currentIndex(); if (fileComboBoxIndex >= 0) { void* filePointer = m_fociFileSelectionComboBox->itemData(fileComboBoxIndex).value(); fociFile = (FociFile*)filePointer; } return fociFile; } /** * Load the focus files into the focus file combo box. * @param fociFile * Selected foci file, may be NULL. */ void FociPropertiesEditorDialog::loadFociFileComboBox(const FociFile* selectedFociFile) { Brain* brain = GuiManager::get()->getBrain(); const int32_t numFociFiles = brain->getNumberOfFociFiles(); m_fociFileSelectionComboBox->clear(); int defaultFileComboIndex = 0; for (int32_t i = 0; i < numFociFiles; i++) { FociFile* fociFile = brain->getFociFile(i); const AString name = fociFile->getFileNameNoPath(); m_fociFileSelectionComboBox->addItem(name, qVariantFromValue((void*)fociFile)); if (selectedFociFile == fociFile) { defaultFileComboIndex = m_fociFileSelectionComboBox->count() - 1; } } if (numFociFiles > 0) { m_fociFileSelectionComboBox->setCurrentIndex(defaultFileComboIndex); const FociFile* fociFile = getSelectedFociFile(); if (fociFile != NULL) { m_nameCompleterStringList = fociFile->getAllFociNamesSorted(); m_nameCompleterStringListModel->setStringList(m_nameCompleterStringList); } } } /** * Called to create a new focus file. */ void FociPropertiesEditorDialog::newFociFileButtonClicked() { /* * Let user choose a different path/name */ FociFile* newFociFile = new FociFile(); GuiManager::get()->getBrain()->convertDataFilePathNameToAbsolutePathName(newFociFile); AString newFociFileName = CaretFileDialog::getSaveFileNameDialog(DataFileTypeEnum::FOCI, this, "Choose Foci File Name", newFociFile->getFileName()); /* * If user cancels, delete the new focus file and return */ if (newFociFileName.isEmpty()) { delete newFociFile; return; } /* * Set name of new scene file */ newFociFile->setFileName(newFociFileName); EventManager::get()->sendEvent(EventDataFileAdd(newFociFile).getPointer()); loadFociFileComboBox(newFociFile); fociFileSelected(); } /** * Called when a focus file is selected. */ void FociPropertiesEditorDialog::fociFileSelected() { loadNameComboBox(); if (m_classComboBox != NULL) { loadClassComboBox(); } } /** * Load the class combo box. * * @param name * If not empty, make this name the selected name. */ void FociPropertiesEditorDialog::loadClassComboBox(const QString& name) { FociFile* fociFile = getSelectedFociFile(); if (fociFile != NULL) { m_classComboBox->updateContent(fociFile->getClassColorTable()); if (name.isEmpty() == false) { m_classComboBox->setSelectedLabelName(name); } } else { m_classComboBox->updateContent(NULL); } } /** * Load the name combo box. * * @param name * If not empty, make this name the selected name. */ void FociPropertiesEditorDialog::loadNameComboBox(const QString& name) { FociFile* fociFile = getSelectedFociFile(); if (fociFile != NULL) { m_nameComboBox->updateContent(fociFile->getNameColorTable()); if (name.isEmpty() == false) { m_nameComboBox->setSelectedLabelName(name); } } else { m_nameComboBox->updateContent(NULL); } } /** * Called when the OK button is pressed. */ void FociPropertiesEditorDialog::okButtonClicked() { AString errorMessage; /* * Get focus file. */ FociFile* fociFile = getSelectedFociFile(); if (fociFile == NULL) { WuQMessageBox::errorOk(this, "Foci file is not valid, use the New button to create a foci file."); return; } /* * Get data entered by the user. */ const AString name = m_nameComboBox->getSelectedLabelName(); if (name.isEmpty()) { errorMessage += ("Name is invalid.\n"); } else { const int32_t unassignedNameKey = fociFile->getNameColorTable()->getUnassignedLabelKey(); const int32_t selectedNameKey = m_nameComboBox->getSelectedLabelKey(); if (selectedNameKey == unassignedNameKey) { errorMessage += "Choose or create a name for the border"; } } const QString className = m_classComboBox->getSelectedLabelName(); if ((m_xCoordSpinBox->value() == 0.0) && (m_yCoordSpinBox->value() == 0.0) && (m_zCoordSpinBox->value() == 0.0)) { errorMessage += "Coordinates are invalid (all zeros)\n"; } /* * Error? */ if (errorMessage.isEmpty() == false) { WuQMessageBox::errorOk(this, errorMessage); return; } /* * Copy data to the focus */ loadFromDialogIntoFocusData(m_focus); /* * Project the focus */ if (m_projectCheckBox->isChecked()) { Brain* brain = GuiManager::get()->getBrain(); std::vector surfaceFiles = brain->getPrimaryAnatomicalSurfaceFiles(); try { SurfaceProjector projector(surfaceFiles); projector.projectFocus(0, m_focus); } catch (SurfaceProjectorException& spe) { CaretLogSevere(spe.whatString()); } } /* * Save project status */ s_previousFociProjectSelected = m_projectCheckBox->isChecked(); updateGraphicsAndUserInterface(); if (m_nameCompleterStringList.contains(name) == false) { m_nameCompleterStringList.append(name); m_nameCompleterStringList.sort(); m_nameCompleterStringListModel->setStringList(m_nameCompleterStringList); } /* * continue with OK button processing */ WuQDialogModal::okButtonClicked(); } /** * Update the graphics and user interface. */ void FociPropertiesEditorDialog::updateGraphicsAndUserInterface() { EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Load data from the given focus into the dialog. * @param focus * Focus from which data is obtained. */ void FociPropertiesEditorDialog::loadFromFocusDataIntoDialog(const Focus* focus) { loadNameComboBox(focus->getName()); loadClassComboBox(focus->getClassName()); float xyz[3] = { 0.0, 0.0, 0.0 }; if (focus->getNumberOfProjections() > 0) { focus->getProjection(0)->getStereotaxicXYZ(xyz); } m_xCoordSpinBox->setValue(xyz[0]); m_yCoordSpinBox->setValue(xyz[1]); m_zCoordSpinBox->setValue(xyz[2]); m_commentTextEdit->setText(focus->getComment()); m_areaLineEdit->setText(focus->getArea()); m_geographyLineEdit->setText(focus->getGeography()); m_extentSpinBox->setValue(focus->getExtent()); m_regionOfInterestLineEdit->setText(focus->getRegionOfInterest()); m_statisticLineEdit->setText(focus->getStatistic()); } /** * Load data from dialog into the focus. * @param focus * Focus into which data is placed. */ void FociPropertiesEditorDialog::loadFromDialogIntoFocusData(Focus* focus) const { focus->setName(m_nameComboBox->getSelectedLabelName()); focus->setClassName(m_classComboBox->getSelectedLabelName()); const float xyz[3] = { (float)m_xCoordSpinBox->value(), (float)m_yCoordSpinBox->value(), (float)m_zCoordSpinBox->value() }; CaretAssert(focus->getNumberOfProjections() > 0); focus->getProjection(0)->setStereotaxicXYZ(xyz); focus->setComment(m_commentTextEdit->toPlainText().trimmed()); focus->setArea(m_areaLineEdit->text().trimmed()); focus->setGeography(m_geographyLineEdit->text().trimmed()); focus->setExtent(m_extentSpinBox->value()); focus->setRegionOfInterest(m_regionOfInterestLineEdit->text().trimmed()); focus->setStatistic(m_statisticLineEdit->text().trimmed()); } /** * Display the class editor */ void FociPropertiesEditorDialog::displayClassEditor() { FociFile* fociFile = getSelectedFociFile(); if (fociFile == NULL) { WuQMessageBox::errorOk(this, "Focus file is not valid, use the New button to create a focus file."); return; } GiftiLabelTableEditor editor(fociFile, fociFile->getClassColorTable(), "Edit Class Attributes", GiftiLabelTableEditor::OPTION_NONE, this); const QString className = m_classComboBox->getSelectedLabelName(); if (className.isEmpty() == false) { editor.selectLabelWithName(className); } const int dialogResult = editor.exec(); loadClassComboBox(); if (dialogResult == GiftiLabelTableEditor::Accepted) { const QString selectedClassName = editor.getLastSelectedLabelName(); if (selectedClassName.isEmpty() == false) { m_classComboBox->setSelectedLabelName(selectedClassName); } } } /** * Display the name editor */ void FociPropertiesEditorDialog::displayNameEditor() { FociFile* fociFile = getSelectedFociFile(); if (fociFile == NULL) { WuQMessageBox::errorOk(this, "Focus file is not valid, use the New button to create a focus file."); return; } GiftiLabelTableEditor editor(fociFile, fociFile->getNameColorTable(), "Edit Name Attributes", GiftiLabelTableEditor::OPTION_UNASSIGNED_LABEL_HIDDEN, this); const QString name = this->m_nameComboBox->getSelectedLabelName(); if (name.isEmpty() == false) { editor.selectLabelWithName(name); } const int dialogResult = editor.exec(); this->loadNameComboBox(); if (dialogResult == GiftiLabelTableEditor::Accepted) { const QString selectedName = editor.getLastSelectedLabelName(); if (selectedName.isEmpty() == false) { m_nameComboBox->setSelectedLabelName(selectedName); } } } /** * @return Is the project checkbox selected? */ bool FociPropertiesEditorDialog::isProjectSelected() { return m_projectCheckBox->isChecked(); } /** * set the status of the project checkbox. * @param selected * New status. */ void FociPropertiesEditorDialog::setProjectSelected(const bool selected) { m_projectCheckBox->setChecked(selected); } connectome-workbench-1.4.2/src/GuiQt/FociPropertiesEditorDialog.h000066400000000000000000000110711360521144700250500ustar00rootroot00000000000000#ifndef __FOCI_PROPERTIES_EDITOR_DIALOG__H_ #define __FOCI_PROPERTIES_EDITOR_DIALOG__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretColorEnum.h" #include "WuQDialogModal.h" class QCheckBox; class QComboBox; class QDoubleSpinBox; class QLabel; class QLineEdit; class QStringListModel; class QTextEdit; namespace caret { class BrowserTabContent; class Focus; class FociFile; class GiftiLabelTableSelectionComboBox; class FociPropertiesEditorDialog : public WuQDialogModal { Q_OBJECT public: static bool createFocus(Focus* focus, BrowserTabContent* browserTabContent, QWidget* parent); static bool editFocus(FociFile* fociFile, Focus* focus, QWidget* parent); FociPropertiesEditorDialog(const QString& title, FociFile* fociFile, Focus* focus, const bool allowFociFileSelection, QWidget* parent = 0); virtual ~FociPropertiesEditorDialog(); FociFile* getSelectedFociFile(); void loadFromFocusDataIntoDialog(const Focus* focus); void loadFromDialogIntoFocusData(Focus* focus) const; bool isProjectSelected(); void setProjectSelected(const bool selected); static void deleteStaticMembers(); protected: virtual void okButtonClicked(); private slots: void displayClassEditor(); void displayNameEditor(); void fociFileSelected(); void newFociFileButtonClicked(); private: FociPropertiesEditorDialog(const FociPropertiesEditorDialog&); FociPropertiesEditorDialog& operator=(const FociPropertiesEditorDialog&); void loadFociFileComboBox(const FociFile* fociFile); void loadClassComboBox(const QString& name = ""); void loadNameComboBox(const QString& name = ""); void updateGraphicsAndUserInterface(); Focus* m_focus; QComboBox* m_fociFileSelectionComboBox; GiftiLabelTableSelectionComboBox* m_nameComboBox; GiftiLabelTableSelectionComboBox* m_classComboBox; QDoubleSpinBox* m_xCoordSpinBox; QDoubleSpinBox* m_yCoordSpinBox; QDoubleSpinBox* m_zCoordSpinBox; QTextEdit* m_commentTextEdit; QLineEdit* m_areaLineEdit; QLineEdit* m_geographyLineEdit; QDoubleSpinBox* m_extentSpinBox; QLineEdit* m_regionOfInterestLineEdit; QLineEdit* m_statisticLineEdit; QCheckBox* m_projectCheckBox; QStringList m_nameCompleterStringList; QStringListModel* m_nameCompleterStringListModel; static bool s_previousFociProjectSelected; /** * Previous selected foci file for creation of foci * NOTE: DO NOT DELETE THIS SINCE IT POINTS TO * AN EXISTING FOCI FILE */ static FociFile* s_previousCreateFociFile; /** Copy of previously created focus */ static Focus* s_previousCreateFocus; }; #ifdef __FOCI_PROPERTIES_EDITOR_DIALOG__DECLARE__ bool FociPropertiesEditorDialog::s_previousFociProjectSelected = true; FociFile* FociPropertiesEditorDialog::s_previousCreateFociFile = NULL; Focus* FociPropertiesEditorDialog::s_previousCreateFocus = NULL; #endif // __FOCI_PROPERTIES_EDITOR_DIALOG__DECLARE__ } // namespace #endif //__FOCI_PROPERTIES_EDITOR_DIALOG__H_ connectome-workbench-1.4.2/src/GuiQt/FociSelectionViewController.cxx000066400000000000000000000523701360521144700256330ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include //#include #include #define __FOCI_SELECTION_VIEW_CONTROLLER_DECLARE__ #include "FociSelectionViewController.h" #undef __FOCI_SELECTION_VIEW_CONTROLLER_DECLARE__ #include "Brain.h" #include "BrainOpenGL.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretColorEnumComboBox.h" #include "GroupAndNameHierarchyViewController.h" #include "DisplayGroupEnumComboBox.h" #include "DisplayPropertiesFoci.h" #include "EnumComboBoxTemplate.h" #include "FeatureColoringTypeEnum.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "SceneClass.h" #include "WuQDataEntryDialog.h" #include "WuQFactory.h" #include "WuQMacroManager.h" #include "WuQTabWidget.h" #include "WuQTrueFalseComboBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::FociSelectionViewController * \brief Widget for controlling display of foci * \ingroup GuiQt * * Widget for controlling the display of foci including * different display groups. */ /** * Constructor. * * @param browserWindowIndex * Index of browser window * @param parentObjectName * Name of parent object * @param parent * The parent object */ FociSelectionViewController::FociSelectionViewController(const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent) : QWidget(parent), m_objectNamePrefix(parentObjectName + ":Foci") { m_browserWindowIndex = browserWindowIndex; QLabel* groupLabel = new QLabel("Group"); m_fociDisplayGroupComboBox = new DisplayGroupEnumComboBox(this); QObject::connect(m_fociDisplayGroupComboBox, SIGNAL(displayGroupSelected(const DisplayGroupEnum::Enum)), this, SLOT(fociDisplayGroupSelected(const DisplayGroupEnum::Enum))); QHBoxLayout* groupLayout = new QHBoxLayout(); groupLayout->addWidget(groupLabel); groupLayout->addWidget(m_fociDisplayGroupComboBox->getWidget()); groupLayout->addStretch(); m_fociDisplayCheckBox = new QCheckBox("Display Foci"); m_fociDisplayCheckBox->setToolTip("Enable the display of foci"); QObject::connect(m_fociDisplayCheckBox, SIGNAL(clicked(bool)), this, SLOT(processAttributesChanges())); m_fociDisplayCheckBox->setObjectName(m_objectNamePrefix + ":DisplayFoci"); WuQMacroManager::instance()->addMacroSupportToObject(m_fociDisplayCheckBox, "Enable foci display"); QWidget* attributesWidget = this->createAttributesWidget(); QWidget* selectionWidget = this->createSelectionWidget(); m_tabWidget = new WuQTabWidget(WuQTabWidget::TAB_ALIGN_LEFT, this); m_tabWidget->addTab(attributesWidget, "Attributes"); m_tabWidget->addTab(selectionWidget, "Selection"); m_tabWidget->setCurrentWidget(attributesWidget); m_tabWidget->getTabBar()->setToolTip("Select foci tab"); m_tabWidget->getTabBar()->setObjectName(m_objectNamePrefix + ":Tab"); WuQMacroManager::instance()->addMacroSupportToObject(m_tabWidget->getTabBar(), "Select features toolbox foci tab"); QVBoxLayout* layout = new QVBoxLayout(this); //WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); layout->addWidget(m_fociDisplayCheckBox); layout->addWidget(WuQtUtilities::createHorizontalLineWidget()); layout->addLayout(groupLayout); layout->addWidget(m_tabWidget->getWidget(), 0, Qt::AlignLeft); layout->addStretch(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); FociSelectionViewController::allFociSelectionViewControllers.insert(this); } /** * Destructor. */ FociSelectionViewController::~FociSelectionViewController() { EventManager::get()->removeAllEventsFromListener(this); FociSelectionViewController::allFociSelectionViewControllers.erase(this); } /** * @return New instance of foci selection widget */ QWidget* FociSelectionViewController::createSelectionWidget() { m_fociClassNameHierarchyViewController = new GroupAndNameHierarchyViewController(m_browserWindowIndex, (m_objectNamePrefix + ":Selection"), "foci", this); return m_fociClassNameHierarchyViewController; } /** * @return The attributes widget. */ QWidget* FociSelectionViewController::createAttributesWidget() { WuQMacroManager* macroManager = WuQMacroManager::instance(); m_fociContralateralCheckBox = new QCheckBox("Contralateral"); m_fociContralateralCheckBox->setToolTip("Enable display of foci from contralateral brain structure"); QObject::connect(m_fociContralateralCheckBox, SIGNAL(clicked(bool)), this, SLOT(processAttributesChanges())); m_fociContralateralCheckBox->setObjectName(m_objectNamePrefix + ":Contralateral"); macroManager->addMacroSupportToObject(m_fociContralateralCheckBox, "Enable contralateral foci"); m_pasteOntoSurfaceCheckBox = new QCheckBox("Paste Onto Surface"); m_pasteOntoSurfaceCheckBox->setToolTip("Place the foci onto the surface"); QObject::connect(m_pasteOntoSurfaceCheckBox, SIGNAL(clicked(bool)), this, SLOT(processAttributesChanges())); m_pasteOntoSurfaceCheckBox->setObjectName(m_objectNamePrefix + ":PasteOntoSurface"); macroManager->addMacroSupportToObject(m_pasteOntoSurfaceCheckBox, "Enable paste foci onto surface"); QLabel* coloringLabel = new QLabel("Coloring"); m_coloringTypeComboBox = new EnumComboBoxTemplate(this); m_coloringTypeComboBox->setup(); m_coloringTypeComboBox->getWidget()->setToolTip("Select the coloring assignment for foci"); QObject::connect(m_coloringTypeComboBox, SIGNAL(itemActivated()), this, SLOT(processAttributesChanges())); m_coloringTypeComboBox->getComboBox()->setObjectName(m_objectNamePrefix + ":ColorType"); macroManager->addMacroSupportToObject(m_coloringTypeComboBox->getComboBox(), "Select foci color type"); QLabel* standardColorLabel = new QLabel("Standard Color"); m_standardColorComboBox = new CaretColorEnumComboBox("", QIcon(), (m_objectNamePrefix + ":Color"), "Select foci standard color", this); m_standardColorComboBox->getWidget()->setToolTip("Select the standard color"); QObject::connect(m_standardColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), this, SLOT(processAttributesChanges())); std::vector drawingTypeEnums; FociDrawingTypeEnum::getAllEnums(drawingTypeEnums); const int32_t numDrawingTypeEnums = static_cast(drawingTypeEnums.size()); QLabel* drawAsLabel = new QLabel("Draw As"); m_drawTypeComboBox = new QComboBox(); for (int32_t i = 0; i < numDrawingTypeEnums; i++) { FociDrawingTypeEnum::Enum drawType = drawingTypeEnums[i]; m_drawTypeComboBox->addItem(FociDrawingTypeEnum::toGuiName(drawType), (int)drawType); } m_drawTypeComboBox->setToolTip("Select the drawing style of foci"); QObject::connect(m_drawTypeComboBox, SIGNAL(activated(int)), this, SLOT(processAttributesChanges())); m_drawTypeComboBox->setObjectName(m_objectNamePrefix + ":DrawingStyle"); macroManager->addMacroSupportToObject(m_drawTypeComboBox, "Select foci drawing style"); float minLineWidth = 0; float maxLineWidth = 1000; //BrainOpenGL::getMinMaxLineWidth(minLineWidth, // maxLineWidth); QLabel* pointSizeLabel = new QLabel("Symbol Diameter"); m_sizeSpinBox = WuQFactory::newDoubleSpinBox(); m_sizeSpinBox->setFixedWidth(80); m_sizeSpinBox->setRange(minLineWidth, maxLineWidth); m_sizeSpinBox->setSingleStep(1.0); m_sizeSpinBox->setDecimals(1); m_sizeSpinBox->setToolTip("Adjust the diameter of foci"); m_sizeSpinBox->setSuffix("mm"); QObject::connect(m_sizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); m_sizeSpinBox->setObjectName(m_objectNamePrefix + ":Diameter"); macroManager->addMacroSupportToObject(m_sizeSpinBox, "Set foci size"); QWidget* gridWidget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(gridWidget); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 8, 2); int row = gridLayout->rowCount(); gridLayout->addWidget(m_fociContralateralCheckBox, row, 0, 1, 2); row++; gridLayout->addWidget(m_pasteOntoSurfaceCheckBox, row, 0, 1, 2); row++; gridLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), row, 0, 1, 2); row++; gridLayout->addWidget(coloringLabel, row, 0); gridLayout->addWidget(m_coloringTypeComboBox->getWidget(), row, 1); row++; gridLayout->addWidget(standardColorLabel, row, 0); gridLayout->addWidget(m_standardColorComboBox->getWidget(), row, 1); row++; gridLayout->addWidget(drawAsLabel, row, 0); gridLayout->addWidget(m_drawTypeComboBox , row, 1); row++; gridLayout->addWidget(pointSizeLabel, row, 0); gridLayout->addWidget(m_sizeSpinBox, row, 1); gridWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(gridWidget); layout->addStretch(); return widget; } /** * Called when a widget on the attributes page has * its value changed. */ void FociSelectionViewController::processAttributesChanges() { DisplayPropertiesFoci* dpf = GuiManager::get()->getBrain()->getDisplayPropertiesFoci(); const FeatureColoringTypeEnum::Enum selectedColoringType = m_coloringTypeComboBox->getSelectedItem(); const int selectedDrawTypeIndex = m_drawTypeComboBox->currentIndex(); const int drawTypeInteger = m_drawTypeComboBox->itemData(selectedDrawTypeIndex).toInt(); const FociDrawingTypeEnum::Enum selectedDrawingType = static_cast(drawTypeInteger); const CaretColorEnum::Enum standardColorType = m_standardColorComboBox->getSelectedColor(); BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); const DisplayGroupEnum::Enum displayGroup = dpf->getDisplayGroupForTab(browserTabIndex); dpf->setDisplayed(displayGroup, browserTabIndex, m_fociDisplayCheckBox->isChecked()); dpf->setContralateralDisplayed(displayGroup, browserTabIndex, m_fociContralateralCheckBox->isChecked()); dpf->setPasteOntoSurface(displayGroup, browserTabIndex, m_pasteOntoSurfaceCheckBox->isChecked()); dpf->setColoringType(displayGroup, browserTabIndex, selectedColoringType); dpf->setStandardColorType(displayGroup, browserTabIndex, standardColorType); dpf->setFociSize(displayGroup, browserTabIndex, m_sizeSpinBox->value()); dpf->setDrawingType(displayGroup, browserTabIndex, selectedDrawingType); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); updateOtherFociViewControllers(); } /** * Called when the foci display group combo box is changed. */ void FociSelectionViewController::fociDisplayGroupSelected(const DisplayGroupEnum::Enum displayGroup) { /* * Update selected display group in model. */ BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, false); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); Brain* brain = GuiManager::get()->getBrain(); DisplayPropertiesFoci* dpf = brain->getDisplayPropertiesFoci(); dpf->setDisplayGroupForTab(browserTabIndex, displayGroup); /* * Since display group has changed, need to update controls */ updateFociViewController(); /* * Apply the changes. */ processFociSelectionChanges(); } /** * Update the foci widget. */ void FociSelectionViewController::updateFociViewController() { BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); Brain* brain = GuiManager::get()->getBrain(); DisplayPropertiesFoci* dpf = brain->getDisplayPropertiesFoci(); const DisplayGroupEnum::Enum displayGroup = dpf->getDisplayGroupForTab(browserTabIndex); // dpf->setDisplayGroupForTab(browserTabIndex, // m_fociDisplayGroupComboBox->getSelectedDisplayGroup()); setWindowTitle("Foci"); m_fociDisplayGroupComboBox->setSelectedDisplayGroup(dpf->getDisplayGroupForTab(browserTabIndex)); /*; * Get all of foci files. */ std::vector allFociFiles; const int32_t numberOfFociFiles = brain->getNumberOfFociFiles(); for (int32_t iff = 0; iff < numberOfFociFiles; iff++) { allFociFiles.push_back(brain->getFociFile(iff)); } /* * Update the class/name hierarchy */ m_fociClassNameHierarchyViewController->updateContents(allFociFiles, displayGroup); std::vector drawingTypeEnums; FociDrawingTypeEnum::getAllEnums(drawingTypeEnums); const int32_t numDrawingTypeEnums = static_cast(drawingTypeEnums.size()); m_fociDisplayCheckBox->setChecked(dpf->isDisplayed(displayGroup, browserTabIndex)); m_fociContralateralCheckBox->setChecked(dpf->isContralateralDisplayed(displayGroup, browserTabIndex)); m_pasteOntoSurfaceCheckBox->setChecked(dpf->isPasteOntoSurface(displayGroup, browserTabIndex)); m_coloringTypeComboBox->setSelectedItem(dpf->getColoringType(displayGroup, browserTabIndex)); m_standardColorComboBox->setSelectedColor(dpf->getStandardColorType(displayGroup, browserTabIndex)); const FociDrawingTypeEnum::Enum selectedDrawingType = dpf->getDrawingType(displayGroup, browserTabIndex); int32_t selectedDrawingTypeIndex = 0; for (int32_t i = 0; i < numDrawingTypeEnums; i++) { FociDrawingTypeEnum::Enum drawType = drawingTypeEnums[i]; if (drawType == selectedDrawingType) { selectedDrawingTypeIndex = i; } } m_drawTypeComboBox->setCurrentIndex(selectedDrawingTypeIndex); m_sizeSpinBox->blockSignals(true); m_sizeSpinBox->setValue(dpf->getFociSize(displayGroup, browserTabIndex)); m_sizeSpinBox->blockSignals(false); } /** * Update other foci view controllers. */ void FociSelectionViewController::updateOtherFociViewControllers() { for (std::set::iterator iter = FociSelectionViewController::allFociSelectionViewControllers.begin(); iter != FociSelectionViewController::allFociSelectionViewControllers.end(); iter++) { FociSelectionViewController* bsw = *iter; if (bsw != this) { bsw->updateFociViewController(); } } } /** * Gets called when foci selections are changed. */ void FociSelectionViewController::processFociSelectionChanges() { processSelectionChanges(); } /** * Issue update events after selections are changed. */ void FociSelectionViewController::processSelectionChanges() { updateOtherFociViewControllers(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Receive events from the event manager. * * @param event * Event sent by event manager. */ void FociSelectionViewController::receiveEvent(Event* event) { bool doUpdate = false; if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiEvent = dynamic_cast(event); CaretAssert(uiEvent); if (uiEvent->isUpdateForWindow(m_browserWindowIndex)) { if (uiEvent->isFociUpdate() || uiEvent->isToolBoxUpdate()) { doUpdate = true; uiEvent->setEventProcessed(); } } } if (doUpdate) { updateFociViewController(); } } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* FociSelectionViewController::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "FociSelectionViewController", 1); sceneClass->addClass(m_tabWidget->saveToScene(sceneAttributes, "m_tabWidget")); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void FociSelectionViewController::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_tabWidget->restoreFromScene(sceneAttributes, sceneClass->getClass("m_tabWidget")); } connectome-workbench-1.4.2/src/GuiQt/FociSelectionViewController.h000066400000000000000000000074251360521144700252610ustar00rootroot00000000000000#ifndef __FOCI_SELECTION_VIEW_CONTROLLER__H_ #define __FOCI_SELECTION_VIEW_CONTROLLER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "DisplayGroupEnum.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" class QCheckBox; class QComboBox; class QDoubleSpinBox; namespace caret { class CaretColorEnumComboBox; class GroupAndNameHierarchyViewController; class DisplayGroupEnumComboBox; class EnumComboBoxTemplate; class WuQTabWidget; class FociSelectionViewController : public QWidget, public EventListenerInterface, public SceneableInterface { Q_OBJECT public: FociSelectionViewController(const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent = 0); virtual ~FociSelectionViewController(); void receiveEvent(Event* event); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private slots: void processFociSelectionChanges(); void processSelectionChanges(); void fociDisplayGroupSelected(const DisplayGroupEnum::Enum); void processAttributesChanges(); private: FociSelectionViewController(const FociSelectionViewController&); FociSelectionViewController& operator=(const FociSelectionViewController&); void updateFociViewController(); void updateOtherFociViewControllers(); QWidget* createSelectionWidget(); QWidget* createAttributesWidget(); const QString m_objectNamePrefix; int32_t m_browserWindowIndex; GroupAndNameHierarchyViewController* m_fociClassNameHierarchyViewController; QCheckBox* m_fociDisplayCheckBox; QCheckBox* m_fociContralateralCheckBox; QCheckBox* m_pasteOntoSurfaceCheckBox; DisplayGroupEnumComboBox* m_fociDisplayGroupComboBox; EnumComboBoxTemplate* m_coloringTypeComboBox; CaretColorEnumComboBox* m_standardColorComboBox; QDoubleSpinBox* m_lineWidthSpinBox; QDoubleSpinBox* m_sizeSpinBox; QComboBox* m_drawTypeComboBox; WuQTabWidget* m_tabWidget; static std::set allFociSelectionViewControllers; }; #ifdef __FOCI_SELECTION_VIEW_CONTROLLER_DECLARE__ std::set FociSelectionViewController::allFociSelectionViewControllers; #endif // __FOCI_SELECTION_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__FOCI_SELECTION_VIEW_CONTROLLER__H_ connectome-workbench-1.4.2/src/GuiQt/GapsAndMarginsDialog.cxx000066400000000000000000000732711360521144700241670ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GAPS_AND_MARGINS_DIALOG_DECLARE__ #include "GapsAndMarginsDialog.h" #undef __GAPS_AND_MARGINS_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include #include "Brain.h" #include "BrainBrowserWindow.h" #include "BrainBrowserWindowComboBox.h" #include "BrainConstants.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "EventBrowserTabGet.h" #include "EventBrowserTabGetAll.h" #include "EventGetViewportSize.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "GapsAndMargins.h" #include "GuiManager.h" #include "WuQGridLayoutGroup.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::GapsAndMarginsDialog * \brief Dialog for adjustment of tab margins. * \ingroup GuiQt */ /** * Constructor. */ GapsAndMarginsDialog::GapsAndMarginsDialog(QWidget* parent) : WuQDialogNonModal("Gaps and Margins", parent) { setApplyButtonText(""); m_browserWindowComboBox = new BrainBrowserWindowComboBox(BrainBrowserWindowComboBox::STYLE_NAME_AND_NUMBER, this); QObject::connect(m_browserWindowComboBox, SIGNAL(browserWindowIndexSelected(const int32_t)), this, SLOT(browserWindowIndexChanged(const int32_t))); QWidget* gapsWidget = createGapsWidget(); QWidget* marginsWidget = createMarginsWidget(); QWidget* dialogWidget = new QWidget; QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); dialogLayout->addWidget(m_browserWindowComboBox->getWidget(), 0, Qt::AlignHCenter); //dialogLayout->addWidget(WuQtUtilities::createHorizontalLineWidget()); dialogLayout->addSpacing(8); dialogLayout->addWidget(gapsWidget, 0, Qt::AlignHCenter); dialogLayout->addWidget(marginsWidget); setCentralWidget(dialogWidget, SCROLL_AREA_AS_NEEDED); updateDialog(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); } /** * Destructor. */ GapsAndMarginsDialog::~GapsAndMarginsDialog() { EventManager::get()->removeAllEventsFromListener(this); } /** * @return Create the gaps widget. */ QWidget* GapsAndMarginsDialog::createGapsWidget() { QLabel* surfaceLabel = new QLabel("Surface"); QLabel* volumeLabel = new QLabel("Volume"); QLabel* horizontalLabel = new QLabel("Horizontal"); QLabel* verticalLabel = new QLabel("Vertical"); m_surfaceMontageHorizontalGapSpinBox = createPercentageSpinBox(); QObject::connect(m_surfaceMontageHorizontalGapSpinBox, SIGNAL(valueChanged(double)), this, SLOT(surfaceMontageGapChanged())); m_surfaceMontageVerticalGapSpinBox = createPercentageSpinBox(); QObject::connect(m_surfaceMontageVerticalGapSpinBox, SIGNAL(valueChanged(double)), this, SLOT(surfaceMontageGapChanged())); m_surfaceMontageMatchPixelToolButton = new QToolButton; m_surfaceMontageMatchPixelToolButton->setText("Match Pixel Width\nto Pixel Height"); m_surfaceMontageMatchPixelToolButton->setToolTip("Set the width to same pixel size as height"); QObject::connect(m_surfaceMontageMatchPixelToolButton, SIGNAL(clicked(bool)), this, SLOT(surfaceMontageMatchPixelButtonClicked())); m_volumeMontageHorizontalGapSpinBox = createPercentageSpinBox(); QObject::connect(m_volumeMontageHorizontalGapSpinBox, SIGNAL(valueChanged(double)), this, SLOT(volumeMontageGapChanged())); m_volumeMontageVerticalGapSpinBox = createPercentageSpinBox(); QObject::connect(m_volumeMontageVerticalGapSpinBox, SIGNAL(valueChanged(double)), this, SLOT(volumeMontageGapChanged())); m_volumeMontageMatchPixelToolButton = new QToolButton; m_volumeMontageMatchPixelToolButton->setText("Match Pixel Width\nto Pixel Height"); m_volumeMontageMatchPixelToolButton->setToolTip("Set the width to same pixel size as height"); QObject::connect(m_volumeMontageMatchPixelToolButton, SIGNAL(clicked(bool)), this, SLOT(volumeMontageMatchPixelButtonClicked())); const int COLUMN_LABEL = 0; const int COLUMN_HORIZONTAL = 1; const int COLUMN_VERTICAL = 2; const int COLUMN_SCALE = 3; QWidget* widget = new QGroupBox("Montage Gaps"); QGridLayout* gridLayout = new QGridLayout(widget); int row = gridLayout->rowCount(); gridLayout->addWidget(horizontalLabel, row, COLUMN_HORIZONTAL, Qt::AlignHCenter); gridLayout->addWidget(verticalLabel, row, COLUMN_VERTICAL, Qt::AlignHCenter); row++; gridLayout->addWidget(surfaceLabel, row, COLUMN_LABEL); gridLayout->addWidget(m_surfaceMontageHorizontalGapSpinBox, row, COLUMN_HORIZONTAL); gridLayout->addWidget(m_surfaceMontageVerticalGapSpinBox, row, COLUMN_VERTICAL); gridLayout->addWidget(m_surfaceMontageMatchPixelToolButton, row, COLUMN_SCALE, Qt::AlignHCenter); row++; gridLayout->addWidget(volumeLabel, row, COLUMN_LABEL); gridLayout->addWidget(m_volumeMontageHorizontalGapSpinBox, row, COLUMN_HORIZONTAL); gridLayout->addWidget(m_volumeMontageVerticalGapSpinBox, row, COLUMN_VERTICAL); gridLayout->addWidget(m_volumeMontageMatchPixelToolButton, row, COLUMN_SCALE, Qt::AlignHCenter); row++; widget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); return widget; } /** * @return Create the margins widget. */ QWidget* GapsAndMarginsDialog::createMarginsWidget() { m_tabIndexSignalMapper = new QSignalMapper(this); QObject::connect(m_tabIndexSignalMapper, SIGNAL(mapped(int)), this, SLOT(tabMarginChanged(int))); m_tabMarginMatchPixelsToolButtonSignalMapper = new QSignalMapper(this); QObject::connect(m_tabMarginMatchPixelsToolButtonSignalMapper, SIGNAL(mapped(int)), this, SLOT(tabMarginMatchPixelButtonClicked(int))); QLabel* tabLabel = new QLabel("Tab"); QLabel* leftLabel = new QLabel("Left"); QLabel* rightLabel = new QLabel("Right"); QLabel* topLabel = new QLabel("Top"); QLabel* bottomLabel = new QLabel("Bottom"); m_applyFirstTabToAllToolButton = new QToolButton(); m_applyFirstTabToAllToolButton->setText("Apply First Row to All"); QObject::connect(m_applyFirstTabToAllToolButton, SIGNAL(clicked(bool)), this, SLOT(applyFirstTabToAllButtonClicked())); QWidget* tabsWidget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(tabsWidget); int32_t columnCounter = 0; const int32_t COLUMN_LABEL = columnCounter++; const int32_t COLUMN_LEFT = columnCounter++; const int32_t COLUMN_RIGHT = columnCounter++; const int32_t COLUMN_BOTTOM = columnCounter++; const int32_t COLUMN_TOP = columnCounter++; const int32_t COLUMN_MATCH = columnCounter++; const int32_t applyToAllRow = gridLayout->rowCount(); gridLayout->addWidget(m_applyFirstTabToAllToolButton, applyToAllRow, COLUMN_LABEL, 1, COLUMN_MATCH, Qt::AlignHCenter); const int32_t titlesRow = gridLayout->rowCount(); gridLayout->addWidget(tabLabel, titlesRow, COLUMN_LABEL, Qt::AlignLeft); gridLayout->addWidget(leftLabel, titlesRow, COLUMN_LEFT, Qt::AlignHCenter); gridLayout->addWidget(rightLabel, titlesRow, COLUMN_RIGHT, Qt::AlignHCenter); gridLayout->addWidget(bottomLabel, titlesRow, COLUMN_BOTTOM, Qt::AlignHCenter); gridLayout->addWidget(topLabel, titlesRow, COLUMN_TOP, Qt::AlignHCenter); for (int32_t iTab = 0; iTab < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; iTab++) { QLabel* tabLabel = new QLabel("123456789012345"); m_tabNumberLabels.push_back(tabLabel); QDoubleSpinBox* leftMarginSpinBox = createPercentageSpinBox(); m_leftMarginSpinBoxes.push_back(leftMarginSpinBox); QObject::connect(leftMarginSpinBox, SIGNAL(valueChanged(double)), m_tabIndexSignalMapper, SLOT(map())); m_tabIndexSignalMapper->setMapping(leftMarginSpinBox, iTab); QDoubleSpinBox* rightMarginSpinBox = createPercentageSpinBox(); m_rightMarginSpinBoxes.push_back(rightMarginSpinBox); QObject::connect(rightMarginSpinBox, SIGNAL(valueChanged(double)), m_tabIndexSignalMapper, SLOT(map())); m_tabIndexSignalMapper->setMapping(rightMarginSpinBox, iTab); QDoubleSpinBox* bottomMarginSpinBox = createPercentageSpinBox(); m_bottomMarginSpinBoxes.push_back(bottomMarginSpinBox); QObject::connect(bottomMarginSpinBox, SIGNAL(valueChanged(double)), m_tabIndexSignalMapper, SLOT(map())); m_tabIndexSignalMapper->setMapping(bottomMarginSpinBox, iTab); QDoubleSpinBox* topMarginSpinBox = createPercentageSpinBox(); m_topMarginSpinBoxes.push_back(topMarginSpinBox); QObject::connect(topMarginSpinBox, SIGNAL(valueChanged(double)), m_tabIndexSignalMapper, SLOT(map())); m_tabIndexSignalMapper->setMapping(topMarginSpinBox, iTab); QToolButton* matchPixelsToolButton = new QToolButton; matchPixelsToolButton->setText("Match Pixel\nSize to Top"); matchPixelsToolButton->setToolTip("When clicked, percentages of Left, Right, and\n" "Top are set to match the pixel height of Top"); m_tabMarginMatchPixelToolButtons.push_back(matchPixelsToolButton); QObject::connect(matchPixelsToolButton, SIGNAL(clicked(bool)), m_tabMarginMatchPixelsToolButtonSignalMapper, SLOT(map())); m_tabMarginMatchPixelsToolButtonSignalMapper->setMapping(matchPixelsToolButton, iTab); const int32_t gridRow = gridLayout->rowCount(); gridLayout->addWidget(tabLabel, gridRow, COLUMN_LABEL); //, Qt::AlignRight); gridLayout->addWidget(leftMarginSpinBox, gridRow, COLUMN_LEFT); gridLayout->addWidget(rightMarginSpinBox, gridRow, COLUMN_RIGHT); gridLayout->addWidget(bottomMarginSpinBox, gridRow, COLUMN_BOTTOM); gridLayout->addWidget(topMarginSpinBox, gridRow, COLUMN_TOP); gridLayout->addWidget(matchPixelsToolButton, gridRow, COLUMN_MATCH); } QScrollArea* scrollArea = new QScrollArea(); scrollArea->setWidget(tabsWidget); scrollArea->setWidgetResizable(true); scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); /* * Ensure scroll are width is set so widget is fully visible in the horizontal direction */ const int width = tabsWidget->sizeHint().width() + scrollArea->verticalScrollBar()->sizeHint().width(); scrollArea->setMinimumWidth(width); QWidget* widget = new QGroupBox("Tab Margins"); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(scrollArea); return widget; } /** * @return Create a double spin box for percentage values. */ QDoubleSpinBox* GapsAndMarginsDialog::createPercentageSpinBox() { const double minValue = 0.0; const double maxValue = 100.0; const int decimals = 1; const double singleStep = 0.1; QDoubleSpinBox* doubleSpinBox = new QDoubleSpinBox(); doubleSpinBox->setMinimum(minValue); doubleSpinBox->setMaximum(maxValue); doubleSpinBox->setSingleStep(singleStep); doubleSpinBox->setDecimals(decimals); doubleSpinBox->setKeyboardTracking(false); doubleSpinBox->setSuffix("%"); return doubleSpinBox; } /** * Update the content of the dialog. */ void GapsAndMarginsDialog::updateDialog() { m_browserWindowComboBox->updateComboBox(); const int32_t windowIndex = m_browserWindowComboBox->getSelectedBrowserWindowIndex(); updateGapsSpinBoxes(windowIndex); updateMarginSpinBoxes(windowIndex); if (windowIndex >= 0) { setEnabled(true); } else { setDisabled(true); } } /** * Update the gaps spin boxes. * * @param windowIndex * Index of window whose gaps are being updated. */ void GapsAndMarginsDialog::updateGapsSpinBoxes(const int32_t windowIndex) { const GapsAndMargins* gapsAndMargins = GuiManager::get()->getBrain()->getGapsAndMargins(); m_surfaceMontageHorizontalGapSpinBox->blockSignals(true); m_surfaceMontageHorizontalGapSpinBox->setValue(gapsAndMargins->getSurfaceMontageHorizontalGapForWindow(windowIndex)); m_surfaceMontageHorizontalGapSpinBox->blockSignals(false); m_surfaceMontageVerticalGapSpinBox->blockSignals(true); m_surfaceMontageVerticalGapSpinBox->setValue(gapsAndMargins->getSurfaceMontageVerticalGapForWindow(windowIndex)); m_surfaceMontageVerticalGapSpinBox->blockSignals(false); m_volumeMontageHorizontalGapSpinBox->blockSignals(true); m_volumeMontageHorizontalGapSpinBox->setValue(gapsAndMargins->getVolumeMontageHorizontalGapForWindow(windowIndex)); m_volumeMontageHorizontalGapSpinBox->blockSignals(false); m_volumeMontageVerticalGapSpinBox->blockSignals(true); m_volumeMontageVerticalGapSpinBox->setValue(gapsAndMargins->getVolumeMontageVerticalGapForWindow(windowIndex)); m_volumeMontageVerticalGapSpinBox->blockSignals(false); } /** * Update the margin spin boxes. * * @param windowIndex * Index of window whose margins are being updated. */ void GapsAndMarginsDialog::updateMarginSpinBoxes(const int32_t windowIndex) { std::vector tabContents; // std::vector tabIndices; const BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(windowIndex); if (browserWindow != NULL) { // browserWindow->getAllTabContentIndices(tabIndices); browserWindow->getAllTabContent(tabContents); } const GapsAndMargins* gapsAndMargins = GuiManager::get()->getBrain()->getGapsAndMargins(); const int32_t numValidTabs = static_cast(tabContents.size()); for (int32_t iTab = 0; iTab < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; iTab++) { bool tabValid = false; if (iTab < numValidTabs) { CaretAssertVectorIndex(tabContents, iTab); const BrowserTabContent* browserTab = tabContents[iTab]; CaretAssert(browserTab); const int32_t tabIndex = browserTab->getTabNumber(); CaretAssertArrayIndex(m_tabIndexInTabMarginRow, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, iTab); m_tabIndexInTabMarginRow[iTab] = tabIndex; const float leftMargin = gapsAndMargins->getMarginLeftForTab(tabIndex); const float rightMargin = gapsAndMargins->getMarginRightForTab(tabIndex); const float bottomMargin = gapsAndMargins->getMarginBottomForTab(tabIndex); const float topMargin = gapsAndMargins->getMarginTopForTab(tabIndex); CaretAssertVectorIndex(m_tabNumberLabels, iTab); // m_tabNumberLabels[iTab]->setText("Tab " + QString::number(tabIndex + 1)); m_tabNumberLabels[iTab]->setText(browserTab->getTabName()); CaretAssertVectorIndex(m_leftMarginSpinBoxes, iTab); m_leftMarginSpinBoxes[iTab]->blockSignals(true); m_leftMarginSpinBoxes[iTab]->setValue(leftMargin); m_leftMarginSpinBoxes[iTab]->blockSignals(false); CaretAssertVectorIndex(m_rightMarginSpinBoxes, iTab); m_rightMarginSpinBoxes[iTab]->blockSignals(true); m_rightMarginSpinBoxes[iTab]->setValue(rightMargin); m_rightMarginSpinBoxes[iTab]->blockSignals(false); CaretAssertVectorIndex(m_bottomMarginSpinBoxes, iTab); m_bottomMarginSpinBoxes[iTab]->blockSignals(true); m_bottomMarginSpinBoxes[iTab]->setValue(bottomMargin); m_bottomMarginSpinBoxes[iTab]->blockSignals(false); CaretAssertVectorIndex(m_topMarginSpinBoxes, iTab); m_topMarginSpinBoxes[iTab]->blockSignals(true); m_topMarginSpinBoxes[iTab]->setValue(topMargin); m_topMarginSpinBoxes[iTab]->blockSignals(false); tabValid = true; } else { m_tabIndexInTabMarginRow[iTab] = -1; } CaretAssertVectorIndex(m_tabNumberLabels, iTab); m_tabNumberLabels[iTab]->setVisible(tabValid); CaretAssertVectorIndex(m_leftMarginSpinBoxes, iTab); m_leftMarginSpinBoxes[iTab]->setVisible(tabValid); CaretAssertVectorIndex(m_rightMarginSpinBoxes, iTab); m_rightMarginSpinBoxes[iTab]->setVisible(tabValid); CaretAssertVectorIndex(m_bottomMarginSpinBoxes, iTab); m_bottomMarginSpinBoxes[iTab]->setVisible(tabValid); CaretAssertVectorIndex(m_topMarginSpinBoxes, iTab); m_topMarginSpinBoxes[iTab]->setVisible(tabValid); CaretAssertVectorIndex(m_tabMarginMatchPixelToolButtons, iTab); m_tabMarginMatchPixelToolButtons[iTab]->setVisible(tabValid); } } /** * Find the horizontal percentage that is the equivalent pixel * size as the vertical percentage. * * @param verticalPercentage * Vertical percentage size. * @param viewportWidth * Width of viewport in pixels. * @param viewportHeight * Height of viewport in pixels. * @return * The horizontal percentage. */ float GapsAndMarginsDialog::matchHorizontalPercentageFromVerticalPercentage(const float verticalPercentage, const float viewportWidth, const float viewportHeight) const { float horizontalPercentageOut = 0.0; const float marginPixelSize = verticalPercentage * viewportHeight; if (viewportWidth > 0) { horizontalPercentageOut = marginPixelSize / viewportWidth; } return horizontalPercentageOut; } /** * Called when match pixel button is clicked. * * @param setVisible(tabValid); * Index of row that is clicked */ void GapsAndMarginsDialog::tabMarginMatchPixelButtonClicked(int rowIndex) { CaretAssertArrayIndex(m_tabIndexInTabMarginRow, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, rowIndex); const int32_t tabIndex = m_tabIndexInTabMarginRow[rowIndex]; if (tabIndex >= 0) { EventGetViewportSize viewportSizeEvent(EventGetViewportSize::MODE_TAB_BEFORE_MARGINS_INDEX, tabIndex); EventManager::get()->sendEvent(viewportSizeEvent.getPointer()); if (viewportSizeEvent.isViewportSizeValid()) { int32_t viewport[4]; viewportSizeEvent.getViewportSize(viewport); CaretAssertVectorIndex(m_topMarginSpinBoxes, rowIndex); const float bottomTopPercentage = m_topMarginSpinBoxes[rowIndex]->value(); const float leftRightMarginPercentage = matchHorizontalPercentageFromVerticalPercentage(bottomTopPercentage, viewport[2], viewport[3]); CaretAssertVectorIndex(m_leftMarginSpinBoxes, rowIndex); CaretAssertVectorIndex(m_rightMarginSpinBoxes, rowIndex); CaretAssertVectorIndex(m_bottomMarginSpinBoxes, rowIndex); CaretAssertVectorIndex(m_topMarginSpinBoxes, rowIndex); m_leftMarginSpinBoxes[rowIndex]->blockSignals(true); m_leftMarginSpinBoxes[rowIndex]->setValue(leftRightMarginPercentage); m_leftMarginSpinBoxes[rowIndex]->blockSignals(false); m_rightMarginSpinBoxes[rowIndex]->blockSignals(true); m_rightMarginSpinBoxes[rowIndex]->setValue(leftRightMarginPercentage); m_rightMarginSpinBoxes[rowIndex]->blockSignals(false); m_bottomMarginSpinBoxes[rowIndex]->blockSignals(true); m_bottomMarginSpinBoxes[rowIndex]->setValue(bottomTopPercentage); m_bottomMarginSpinBoxes[rowIndex]->blockSignals(false); m_topMarginSpinBoxes[rowIndex]->blockSignals(true); m_topMarginSpinBoxes[rowIndex]->setValue(bottomTopPercentage); m_topMarginSpinBoxes[rowIndex]->blockSignals(false); tabMarginChanged(rowIndex); } else { CaretLogWarning("Unable to get tab " + AString::number(tabIndex + 1) + " viewport size."); } } } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void GapsAndMarginsDialog::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* eventUpdate = dynamic_cast(event); CaretAssert(eventUpdate); updateDialog(); eventUpdate->setEventProcessed(); } } /** * Gets called when the browser window index is changed. * * @param browserWindowIndex * Index of the browser window. */ void GapsAndMarginsDialog::browserWindowIndexChanged(const int32_t /*browserWindowIndex*/) { updateDialog(); } /** * Gets called when a tab's margin is changed. * * @param rowIndex * Index of the tab. */ void GapsAndMarginsDialog::tabMarginChanged(int rowIndex) { GapsAndMargins* gapsAndMargins = GuiManager::get()->getBrain()->getGapsAndMargins(); CaretAssertArrayIndex(m_tabIndexInTabMarginRow, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, rowIndex); const int32_t tabIndex = m_tabIndexInTabMarginRow[rowIndex]; CaretAssert(tabIndex >= 0); CaretAssertVectorIndex(m_leftMarginSpinBoxes, rowIndex); CaretAssertVectorIndex(m_rightMarginSpinBoxes, rowIndex); CaretAssertVectorIndex(m_bottomMarginSpinBoxes, rowIndex); CaretAssertVectorIndex(m_topMarginSpinBoxes, rowIndex); gapsAndMargins->setMarginLeftForTab(tabIndex, m_leftMarginSpinBoxes[rowIndex]->value()); gapsAndMargins->setMarginRightForTab(tabIndex, m_rightMarginSpinBoxes[rowIndex]->value()); gapsAndMargins->setMarginBottomForTab(tabIndex, m_bottomMarginSpinBoxes[rowIndex]->value()); gapsAndMargins->setMarginTopForTab(tabIndex, m_topMarginSpinBoxes[rowIndex]->value()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Gets called when apply first tab to all button is clicked. */ void GapsAndMarginsDialog::applyFirstTabToAllButtonClicked() { const int32_t rowZero = 0; CaretAssertVectorIndex(m_leftMarginSpinBoxes, rowZero); const float leftMargin = m_leftMarginSpinBoxes[rowZero]->value(); CaretAssertVectorIndex(m_rightMarginSpinBoxes, rowZero); const float rightMargin = m_rightMarginSpinBoxes[rowZero]->value(); CaretAssertVectorIndex(m_bottomMarginSpinBoxes, rowZero); const float bottomMargin = m_bottomMarginSpinBoxes[rowZero]->value(); CaretAssertVectorIndex(m_topMarginSpinBoxes, rowZero); const float topMargin = m_topMarginSpinBoxes[rowZero]->value(); GapsAndMargins* gapsAndMargins = GuiManager::get()->getBrain()->getGapsAndMargins(); for (int32_t iRow = 1; iRow < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS; iRow++) { CaretAssertArrayIndex(m_tabIndexInTabMarginRow, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS, iRow); const int32_t tabIndex = m_tabIndexInTabMarginRow[iRow]; if (tabIndex >= 0) { gapsAndMargins->setMarginLeftForTab(tabIndex, leftMargin); gapsAndMargins->setMarginRightForTab(tabIndex, rightMargin); gapsAndMargins->setMarginBottomForTab(tabIndex, bottomMargin); gapsAndMargins->setMarginTopForTab(tabIndex, topMargin); } } /* * Update dialog since "select all" will change all margins to the first margin value */ updateDialog(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Gets called when a surface montage gap is changed. */ void GapsAndMarginsDialog::surfaceMontageGapChanged() { const int32_t windowIndex = m_browserWindowComboBox->getSelectedBrowserWindowIndex(); if (windowIndex < 0) { return; } GapsAndMargins* gapsAndMargins = GuiManager::get()->getBrain()->getGapsAndMargins(); gapsAndMargins->setSurfaceMontageHorizontalGapForWindow(windowIndex, m_surfaceMontageHorizontalGapSpinBox->value()); gapsAndMargins->setSurfaceMontageVerticalGapForWindow(windowIndex, m_surfaceMontageVerticalGapSpinBox->value()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Gets called when a volume montage gap is changed. */ void GapsAndMarginsDialog::volumeMontageGapChanged() { const int32_t windowIndex = m_browserWindowComboBox->getSelectedBrowserWindowIndex(); if (windowIndex < 0) { return; } GapsAndMargins* gapsAndMargins = GuiManager::get()->getBrain()->getGapsAndMargins(); gapsAndMargins->setVolumeMontageHorizontalGapForWindow(windowIndex, m_volumeMontageHorizontalGapSpinBox->value()); gapsAndMargins->setVolumeMontageVerticalGapForWindow(windowIndex, m_volumeMontageVerticalGapSpinBox->value()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Gets called when the surface montage match pixels tool button is clicked. */ void GapsAndMarginsDialog::surfaceMontageMatchPixelButtonClicked() { const int32_t windowIndex = m_browserWindowComboBox->getSelectedBrowserWindowIndex(); if (windowIndex < 0) { return; } EventGetViewportSize viewportSizeEvent(EventGetViewportSize::MODE_SURFACE_MONTAGE, windowIndex); EventManager::get()->sendEvent(viewportSizeEvent.getPointer()); if (viewportSizeEvent.isViewportSizeValid()) { int32_t viewport[4]; viewportSizeEvent.getViewportSize(viewport); const float verticalPercentage = m_surfaceMontageVerticalGapSpinBox->value(); const float leftRightMarginPercentage = matchHorizontalPercentageFromVerticalPercentage(verticalPercentage, viewport[2], viewport[3]); m_surfaceMontageHorizontalGapSpinBox->blockSignals(true); m_surfaceMontageHorizontalGapSpinBox->setValue(leftRightMarginPercentage); m_surfaceMontageHorizontalGapSpinBox->blockSignals(false); surfaceMontageGapChanged(); } EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Gets called when the volume montage match pixels tool button is clicked. */ void GapsAndMarginsDialog::volumeMontageMatchPixelButtonClicked() { const int32_t windowIndex = m_browserWindowComboBox->getSelectedBrowserWindowIndex(); if (windowIndex < 0) { return; } EventGetViewportSize viewportSizeEvent(EventGetViewportSize::MODE_VOLUME_MONTAGE, windowIndex); EventManager::get()->sendEvent(viewportSizeEvent.getPointer()); if (viewportSizeEvent.isViewportSizeValid()) { int32_t viewport[4]; viewportSizeEvent.getViewportSize(viewport); const float verticalPercentage = m_volumeMontageVerticalGapSpinBox->value(); const float horizontalPercentage = matchHorizontalPercentageFromVerticalPercentage(verticalPercentage, viewport[2], viewport[3]); m_volumeMontageHorizontalGapSpinBox->blockSignals(true); m_volumeMontageHorizontalGapSpinBox->setValue(horizontalPercentage); m_volumeMontageHorizontalGapSpinBox->blockSignals(false); volumeMontageGapChanged(); } EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } connectome-workbench-1.4.2/src/GuiQt/GapsAndMarginsDialog.h000066400000000000000000000102611360521144700236020ustar00rootroot00000000000000#ifndef __GAPS_AND_MARGINS_DIALOG_H__ #define __GAPS_AND_MARGINS_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainConstants.h" #include "EventListenerInterface.h" #include "WuQDialogNonModal.h" class QLabel; class QSignalMapper; class QDoubleSpinBox; class QToolButton; namespace caret { class BrainBrowserWindowComboBox; class WuQGridLayoutGroup; class GapsAndMarginsDialog : public WuQDialogNonModal, public EventListenerInterface { Q_OBJECT public: GapsAndMarginsDialog(QWidget* parent = 0); virtual ~GapsAndMarginsDialog(); virtual void updateDialog(); // ADD_NEW_METHODS_HERE virtual void receiveEvent(Event* event); private slots: void browserWindowIndexChanged(const int32_t browserWindowIndex); void tabMarginChanged(int rowIndex); void surfaceMontageGapChanged(); void volumeMontageGapChanged(); void applyFirstTabToAllButtonClicked(); void surfaceMontageMatchPixelButtonClicked(); void volumeMontageMatchPixelButtonClicked(); void tabMarginMatchPixelButtonClicked(int rowIndex); private: GapsAndMarginsDialog(const GapsAndMarginsDialog&); GapsAndMarginsDialog& operator=(const GapsAndMarginsDialog&); QWidget* createGapsWidget(); QWidget* createMarginsWidget(); QDoubleSpinBox* createPercentageSpinBox(); void updateGapsSpinBoxes(const int32_t windowIndex); void updateMarginSpinBoxes(const int32_t windowIndex); float matchHorizontalPercentageFromVerticalPercentage(const float verticalPercentage, const float viewportWidth, const float viewportHeight) const; BrainBrowserWindowComboBox* m_browserWindowComboBox; WuQGridLayoutGroup* m_gridLayoutGroup; std::vector m_tabNumberLabels; std::vector m_leftMarginSpinBoxes; std::vector m_rightMarginSpinBoxes; std::vector m_bottomMarginSpinBoxes; std::vector m_topMarginSpinBoxes; QToolButton* m_applyFirstTabToAllToolButton; QDoubleSpinBox* m_surfaceMontageHorizontalGapSpinBox; QDoubleSpinBox* m_surfaceMontageVerticalGapSpinBox; QDoubleSpinBox* m_volumeMontageHorizontalGapSpinBox; QDoubleSpinBox* m_volumeMontageVerticalGapSpinBox; QToolButton* m_surfaceMontageMatchPixelToolButton; QToolButton* m_volumeMontageMatchPixelToolButton; std::vector m_tabMarginMatchPixelToolButtons; QSignalMapper* m_tabIndexSignalMapper; QSignalMapper* m_tabMarginMatchPixelsToolButtonSignalMapper; int32_t m_tabIndexInTabMarginRow[BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS]; // ADD_NEW_MEMBERS_HERE }; #ifdef __GAPS_AND_MARGINS_DIALOG_DECLARE__ // #endif // __GAPS_AND_MARGINS_DIALOG_DECLARE__ } // namespace #endif //__GAPS_AND_MARGINS_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/GiftiLabelTableEditor.cxx000066400000000000000000001012231360521144700243170ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __GIFTI_LABEL_TABLE_EDITOR_DECLARE__ #include "GiftiLabelTableEditor.h" #undef __GIFTI_LABEL_TABLE_EDITOR_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include #include "ApplicationInformation.h" #include "BorderFile.h" #include "Brain.h" #include "CaretAssert.h" #include "CaretMappableDataFile.h" #include "ColorEditorWidget.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUserInterfaceUpdate.h" #include "FociFile.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "GroupAndNameHierarchyItem.h" #include "GuiManager.h" #include "WuQDataEntryDialog.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" #include "WuQWidgetObjectGroup.h" using namespace caret; /** * \class caret::GiftiLabelTableEditor * \brief Dialog for editing a GIFTI lable table. * \ingroup GuiQt */ /** * Constructor for editing label table in a mappable data file. * * @param fociFile * Foci file whose color table being edited. As colors are edited, * the assigned foci will have their color validity invalidated. * @param giftiLabelTable * Label table being edited. * @param dialogTitle * Title for the dialog. * @param options * Bitwise OR'ed Options values. * @param parent * Parent on which this dialog is displayed. */ GiftiLabelTableEditor::GiftiLabelTableEditor(CaretMappableDataFile* caretMappableDataFile, const int32_t mapIndex, const AString& dialogTitle, const uint32_t options, QWidget* parent) : WuQDialogModal(dialogTitle, parent) { CaretAssert(caretMappableDataFile); CaretAssert(mapIndex >= 0); CaretAssert(mapIndex < caretMappableDataFile->getNumberOfMaps()); initializeDialog(caretMappableDataFile->getMapLabelTable(mapIndex), options); m_caretMappableDataFile = caretMappableDataFile; m_caretMappableDataFileMapIndex = mapIndex; } /** * Constructor for a label table in a foci file. * * @param fociFile * Foci file whose color table being edited. As colors are edited, * the assigned foci will have their color validity invalidated. * @param giftiLabelTable * Label table being edited. * @param dialogTitle * Title for the dialog. * @param options * Bitwise OR'ed Options values. * @param parent * Parent on which this dialog is displayed. */ GiftiLabelTableEditor::GiftiLabelTableEditor(FociFile* fociFile, GiftiLabelTable* giftiLableTable, const AString& dialogTitle, const uint32_t options, QWidget* parent) : WuQDialogModal(dialogTitle, parent) { CaretAssert(fociFile); initializeDialog(giftiLableTable, options); m_fociFile = fociFile; } /** * Constructor for a label table in a border file. * * @param borderFile * Border file whose color table being edited. As colors are edited, * the assigned borders will have their color validity invalidated. * @param giftiLabelTable * Label table being edited. * @param dialogTitle * Title for the dialog. * @param options * Bitwise OR'ed Options values. * @param parent * Parent on which this dialog is displayed. */ GiftiLabelTableEditor::GiftiLabelTableEditor(BorderFile* borderFile, GiftiLabelTable* giftiLableTable, const AString& dialogTitle, const uint32_t options, QWidget* parent) : WuQDialogModal(dialogTitle, parent) { CaretAssert(borderFile); initializeDialog(giftiLableTable, options); m_borderFile = borderFile; } /** * Destructor. */ GiftiLabelTableEditor::~GiftiLabelTableEditor() { if (m_undoGiftiLabel != NULL) { delete m_undoGiftiLabel; m_undoGiftiLabel = NULL; } } /** * Initialize the dialog. * * @param giftiLabelTable * Label table being edited. * @param options * Bitwise OR'ed Options values. */ void GiftiLabelTableEditor::initializeDialog(GiftiLabelTable* giftiLabelTable, const uint32_t options) { m_borderFile = NULL; m_caretMappableDataFile = NULL; m_caretMappableDataFileMapIndex = -1; m_fociFile = NULL; m_showUnassignedLabelInEditor = true; if (options & OPTION_UNASSIGNED_LABEL_HIDDEN) { m_showUnassignedLabelInEditor = false; } CaretAssert(giftiLabelTable); m_giftiLableTable = giftiLabelTable; m_undoGiftiLabel = NULL; /* * Sorting */ QLabel* sortByLabel = new QLabel("Sort by "); m_sortLabelsByComboBox = new QComboBox(); m_sortLabelsByComboBox->addItem(s_SORT_COMBO_BOX_NAME_BY_KEY); m_sortLabelsByComboBox->addItem(s_SORT_COMBO_BOX_NAME_BY_NAME); m_sortLabelsByComboBox->setCurrentIndex(1); QObject::connect(m_sortLabelsByComboBox, SIGNAL(activated(int)), this, SLOT(sortingLabelsActivated())); /* * Sorting layout */ QHBoxLayout* sortingLayout = new QHBoxLayout(); sortingLayout->addWidget(sortByLabel); sortingLayout->addWidget(m_sortLabelsByComboBox); sortingLayout->addStretch(); /* * List widget for editing labels. */ m_labelSelectionListWidget = new QListWidget(); m_labelSelectionListWidget->setSelectionMode(QListWidget::SingleSelection); // QObject::connect(m_labelSelectionListWidget, SIGNAL(currentRowChanged(int)), // this, SLOT(listWidgetLabelSelected())); QObject::connect(m_labelSelectionListWidget, SIGNAL(itemClicked(QListWidgetItem*)), //SIGNAL(currentRowChanged(int)), this, SLOT(listWidgetLabelSelected())); /* * New color button. */ QPushButton* newPushButton = WuQtUtilities::createPushButton("New", "Create a new entry", this, SLOT(newButtonClicked())); /* * Undo Edit button. */ QPushButton* undoPushButton = WuQtUtilities::createPushButton("Undo Edit", "Create a new entry", this, SLOT(undoButtonClicked())); /* * Delete button. */ QPushButton* deletePushButton = WuQtUtilities::createPushButton("Delete", "Delete the selected entry", this, SLOT(deleteButtonClicked())); /* * Color editor widget */ m_colorEditorWidget = new ColorEditorWidget(); QObject::connect(m_colorEditorWidget, SIGNAL(colorChanged(const float*)), this, SLOT(colorEditorColorChanged(const float*))); /* * Label name line edit */ QLabel* nameLabel = new QLabel("Name "); m_labelNameLineEdit = new QLineEdit(); QObject::connect(m_labelNameLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(labelNameLineEditTextEdited(const QString&))); WuQtUtilities::setToolTipAndStatusTip(m_labelNameLineEdit, "Edit the name"); /* * Key value editing */ QLabel* keyLabel = NULL; m_keyValueLineEdit = NULL; m_changeKeyValueToolButton = NULL; if (options & OPTION_ADD_KEY_EDITING) { keyLabel = new QLabel("Key "); m_keyValueLineEdit = new QLineEdit(); m_keyValueLineEdit->setFixedWidth(100); m_keyValueLineEdit->setAlignment(Qt::AlignRight); m_keyValueLineEdit->setReadOnly(true); m_changeKeyValueToolButton = new QToolButton(); m_changeKeyValueToolButton->setText("Change..."); m_changeKeyValueToolButton->setToolTip("Change a label's key"); QObject::connect(m_changeKeyValueToolButton, SIGNAL(clicked(bool)), this, SLOT(changeLabelKeyLockButtonClicked())); } /* * Layout for name and key */ QGridLayout* nameKeyLayout = new QGridLayout(); nameKeyLayout->setColumnStretch(0, 0); nameKeyLayout->setColumnStretch(1, 0); nameKeyLayout->setColumnStretch(2, 100); nameKeyLayout->addWidget(nameLabel, 0, 0); nameKeyLayout->addWidget(m_labelNameLineEdit, 0, 1, 1, 2); if (options & OPTION_ADD_KEY_EDITING) { CaretAssert(keyLabel); CaretAssert(m_keyValueLineEdit); CaretAssert(m_changeKeyValueToolButton); nameKeyLayout->addWidget(keyLabel, 1, 0); nameKeyLayout->addWidget(m_keyValueLineEdit, 1, 1); nameKeyLayout->addWidget(m_changeKeyValueToolButton, 1, 2, Qt::AlignLeft); } /* * Layout for buttons */ QHBoxLayout* buttonsLayout = new QHBoxLayout(); buttonsLayout->addWidget(newPushButton); buttonsLayout->addStretch(); buttonsLayout->addWidget(undoPushButton); buttonsLayout->addStretch(); buttonsLayout->addWidget(deletePushButton); /* * Layout items in dialog */ QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 4, 2); layout->addLayout(sortingLayout); layout->addWidget(m_labelSelectionListWidget); layout->addLayout(buttonsLayout); layout->addWidget(WuQtUtilities::createHorizontalLineWidget()); layout->addLayout(nameKeyLayout); layout->addWidget(m_colorEditorWidget); setCentralWidget(widget, WuQDialog::SCROLL_AREA_NEVER); m_editingGroup = new WuQWidgetObjectGroup(this); m_editingGroup->add(undoPushButton); m_editingGroup->add(deletePushButton); m_editingGroup->add(nameLabel); m_editingGroup->add(m_labelNameLineEdit); if (options & OPTION_ADD_KEY_EDITING) { CaretAssert(keyLabel); CaretAssert(m_keyValueLineEdit); CaretAssert(m_changeKeyValueToolButton); m_editingGroup->add(keyLabel); m_editingGroup->add(m_keyValueLineEdit); m_editingGroup->add(m_changeKeyValueToolButton); } m_editingGroup->add(m_colorEditorWidget); loadLabels("", false); m_applyPushButton = NULL; if (options & OPTION_ADD_APPLY_BUTTON) { m_applyPushButton = addUserPushButton("Apply", QDialogButtonBox::ApplyRole); } //setOkButtonText("Close"); //setCancelButtonText(""); /* * No auto default button processing (Qt highlights button) */ disableAutoDefaultForAllPushButtons(); std::map::iterator lastEditIter = s_previousSelections.find(m_giftiLableTable); if (lastEditIter != s_previousSelections.end()) { const PreviousSelections& ps = lastEditIter->second; const int sortIndex = m_sortLabelsByComboBox->findText(ps.m_sortingName); if (sortIndex >= 0) { m_sortLabelsByComboBox->setCurrentIndex(sortIndex); } sortingLabelsActivated(); selectLabelWithName(ps.m_selectedLabelName); } } /** * Called when name line edit text is changed. * @param text * Text currently in the line edit. */ void GiftiLabelTableEditor::labelNameLineEditTextEdited(const QString& text) { GiftiLabel* gl = getSelectedLabel(); if (gl != NULL) { gl->setName(text); } QListWidgetItem* selectedItem = m_labelSelectionListWidget->currentItem(); if (selectedItem != NULL) { selectedItem->setText(gl->getNameAndKeyForLabelEditor()); } m_lastSelectedLabelName = text; } /** * @return * The last name that was selected. */ AString GiftiLabelTableEditor::getLastSelectedLabelName() const { return m_lastSelectedLabelName; } /** * Select the label with the given name. * @param labelName * Name of label that is to be selected. */ void GiftiLabelTableEditor::selectLabelWithName(const AString& labelName) { const GiftiLabel* gl = m_giftiLableTable->getLabel(labelName); if (gl != NULL) { const AString keyLabelName = gl->getNameAndKeyForLabelEditor(); QList itemsWithLabelName = m_labelSelectionListWidget->findItems(keyLabelName, Qt::MatchExactly); if ( ! itemsWithLabelName.empty()) { QListWidgetItem* item = itemsWithLabelName.at(0); m_labelSelectionListWidget->setCurrentItem(item); listWidgetLabelSelected(); } } } ///** // * Called when a label in the list widget is selected. // * @param row // * Row of label selected. // */ //void //GiftiLabelTableEditor::listWidgetLabelSelected(int /*row*/) //{ // if (m_undoGiftiLabel != NULL) { // delete m_undoGiftiLabel; // m_undoGiftiLabel = NULL; // } // // bool isEditingAllowed = false; // GiftiLabel* gl = getSelectedLabel(); // if (gl != NULL) { // const bool isUnassignedLabel = (gl->getKey() == m_giftiLableTable->getUnassignedLabelKey()); // float rgba[4]; // gl->getColor(rgba); // m_colorEditorWidget->setColor(rgba); // m_labelNameLineEdit->setText(gl->getName()); // if (m_keyValueLabel != NULL) { // m_keyValueLabel->setNum(gl->getKey()); // } // // m_lastSelectedLabelName = gl->getName(); // // if (isUnassignedLabel) { // m_undoGiftiLabel = NULL; // } // else { // m_undoGiftiLabel = new GiftiLabel(*gl); // isEditingAllowed = true; // } // } // else { // m_lastSelectedLabelName = ""; // if (m_keyValueLabel != NULL) { // m_keyValueLabel->setText(""); // } // // } // // m_editingGroup->setEnabled(isEditingAllowed); //} /** * Called when a label in the list widget is selected. */ void GiftiLabelTableEditor::listWidgetLabelSelected() { if (m_undoGiftiLabel != NULL) { delete m_undoGiftiLabel; m_undoGiftiLabel = NULL; } bool isEditingAllowed = false; GiftiLabel* gl = getSelectedLabel(); if (gl != NULL) { const bool isUnassignedLabel = (gl->getKey() == m_giftiLableTable->getUnassignedLabelKey()); float rgba[4]; gl->getColor(rgba); m_colorEditorWidget->setColor(rgba); m_labelNameLineEdit->setText(gl->getName()); if (m_keyValueLineEdit != NULL) { m_keyValueLineEdit->setText(AString::number(gl->getKey())); } m_lastSelectedLabelName = gl->getName(); if (isUnassignedLabel) { m_undoGiftiLabel = NULL; } else { m_undoGiftiLabel = new GiftiLabel(*gl); isEditingAllowed = true; } } else { m_lastSelectedLabelName = ""; if (m_keyValueLineEdit != NULL) { m_keyValueLineEdit->setText(""); } } //m_editingGroup->setEnabled(isEditingAllowed); allowLabelDataEditing(isEditingAllowed); } /** * Called when a change is made in the color editor. * @param rgba * New RGBA values. */ void GiftiLabelTableEditor::colorEditorColorChanged(const float* rgba) { QListWidgetItem* selectedItem = m_labelSelectionListWidget->currentItem(); if (selectedItem != NULL) { setWidgetItemIconColor(selectedItem, rgba); } GiftiLabel* gl = getSelectedLabel(); if (gl != NULL) { gl->setColor(rgba); if (m_fociFile != NULL) { m_fociFile->invalidateAllAssignedColors(); } else if (m_borderFile != NULL) { m_borderFile->invalidateAllAssignedColors(); } else if (m_caretMappableDataFile != NULL) { VolumeFile* volumeFile = dynamic_cast(m_caretMappableDataFile); if (volumeFile != NULL) { volumeFile->clearVoxelColoringForMap(m_caretMappableDataFileMapIndex); } GroupAndNameHierarchyItem* item = gl->getGroupNameSelectionItem(); if (item != NULL) { item->setIconColorRGBA(rgba); } } } } /** * Called when label sorting is changed. */ void GiftiLabelTableEditor::sortingLabelsActivated() { AString selectedLabelName; const GiftiLabel* gl = getSelectedLabel(); if (gl != NULL) { selectedLabelName = gl->getName(); } loadLabels(selectedLabelName, false); } /** * Load labels into the list widget. * * @param selectedName * If not empty, select the label with this name * @param usePreviouslySelectedIndex * If true, use selected index prior to reloading list widget. */ void GiftiLabelTableEditor::loadLabels(const AString& selectedNameIn, const bool usePreviouslySelectedIndex) { m_labelSelectionListWidget->blockSignals(true); int32_t previousSelectedIndex = -1; if (usePreviouslySelectedIndex) { previousSelectedIndex = m_labelSelectionListWidget->currentRow(); } // const int32_t invalidLabelKey = GiftiLabel::getInvalidLabelKey(); // const GiftiLabel* invalidLabel = m_giftiLableTable->getLabel(invalidLabelKey); const GiftiLabel* selectedLabel = getSelectedLabel(); AString selectedName; if (selectedLabel != NULL) { selectedName = selectedLabel->getName(); } if ( ! selectedNameIn.isEmpty()) { const GiftiLabel* selectedNameInLabel = m_giftiLableTable->getLabel(selectedNameIn); if (selectedNameInLabel != NULL) { selectedName = selectedNameInLabel->getName(); } } m_labelSelectionListWidget->clear(); int defaultIndex = -1; const int32_t unassignedLabelKey = m_giftiLableTable->getUnassignedLabelKey(); std::vector keys; const QString sortName = m_sortLabelsByComboBox->currentText(); if (sortName == s_SORT_COMBO_BOX_NAME_BY_KEY) { m_giftiLableTable->getKeys(keys); } else if (sortName == s_SORT_COMBO_BOX_NAME_BY_NAME) { keys = m_giftiLableTable->getLabelKeysSortedByName(); } else { CaretAssertMessage(0, "Invalid sort by name"); } for (std::vector::iterator keyIterator = keys.begin(); keyIterator != keys.end(); keyIterator++) { const int32_t key = *keyIterator; if ( ! m_showUnassignedLabelInEditor) { if (key == unassignedLabelKey) { continue; } } const GiftiLabel* gl = m_giftiLableTable->getLabel(key); float rgba[4]; gl->getColor(rgba); QString keyAndNameText(QString::number(gl->getKey()).rightJustified(4, ' ', false) + ": " + (gl->getName())); QListWidgetItem* colorItem = new QListWidgetItem(keyAndNameText); setWidgetItemIconColor(colorItem, rgba); colorItem->setData(Qt::UserRole, qVariantFromValue((void*)gl)); m_labelSelectionListWidget->addItem(colorItem); if (selectedName == gl->getName()) { defaultIndex = m_labelSelectionListWidget->count() - 1; } } if (usePreviouslySelectedIndex) { defaultIndex = previousSelectedIndex; if (defaultIndex >= m_labelSelectionListWidget->count()) { defaultIndex--; } } if (usePreviouslySelectedIndex) { if (defaultIndex < 0) { if (m_labelSelectionListWidget->count() > 0) { defaultIndex = 0; } } } m_labelSelectionListWidget->blockSignals(false); if (defaultIndex >= 0) { m_labelSelectionListWidget->setCurrentRow(defaultIndex); } else { //m_editingGroup->setEnabled(false); allowLabelDataEditing(false); } } /** * Allow editing of label data. * * @param allowEditingFlag * If true allow editing of label data. */ void GiftiLabelTableEditor::allowLabelDataEditing(const bool allowEditingFlag) { m_editingGroup->setEnabled(allowEditingFlag); } /** * Set the Icon color for the item. * @param item * The list widget item. * @param rgba * RGBA values. */ void GiftiLabelTableEditor::setWidgetItemIconColor(QListWidgetItem* item, const float rgba[4]) { QColor color; color.setRedF(rgba[0]); color.setGreenF(rgba[1]); color.setBlueF(rgba[2]); color.setAlphaF(1.0); QPixmap pixmap(14, 14); pixmap.fill(color); QIcon colorIcon(pixmap); item->setIcon(colorIcon); } /** * @return The selected label or NULL if * no label is selected. */ GiftiLabel* GiftiLabelTableEditor::getSelectedLabel() { GiftiLabel* gl = NULL; QListWidgetItem* selectedItem = m_labelSelectionListWidget->currentItem(); if (selectedItem != NULL) { void* pointer = selectedItem->data(Qt::UserRole).value(); gl = (GiftiLabel*)pointer; } return gl; } /** * Called to create a new label. */ void GiftiLabelTableEditor::newButtonClicked() { /* * Make sure default name does not already exist */ AString name = "NewName_"; for (int i = 1; i < 10000; i++) { const AString testName = name + QString::number(i); if (m_giftiLableTable->getLabel(testName) == NULL) { name = testName; break; } } float rgba[4] = { 0.0, 0.0, 0.0, 1.0 }; m_giftiLableTable->addLabel(name, rgba[0], rgba[1], rgba[2], rgba[3]); loadLabels(name, false); // m_labelNameLineEdit->grabKeyboard(); // m_labelNameLineEdit->grabMouse(); listWidgetLabelSelected(); m_labelNameLineEdit->setFocus(); m_labelNameLineEdit->selectAll(); colorEditorColorChanged(rgba); } /** * Called when change label key lock button is clicked. * * @param checked * Checked status of button. */ void GiftiLabelTableEditor::changeLabelKeyLockButtonClicked() { if (m_changeKeyValueToolButton == NULL) { return; } const GiftiLabel* selectedLabel = getSelectedLabel(); if (selectedLabel == NULL) { return; } if (s_displayKeyEditingWarningFlag) { s_displayKeyEditingWarningFlag = false; const AString text("Are you sure that you want to edit label keys?"); const AString infoText("Brainordinate values are not changed in the label type file\n" "and changing label keys may cause label data to display\n" "incorrectly.\n" "\n" "This warning will not be displayed again until " + ApplicationInformation().getName() + " is restarted."); if ( ! WuQMessageBox::warningOkCancel(m_changeKeyValueToolButton, text, infoText)) { return; } } const AString labelName = selectedLabel->getName(); ChangeLabelKeyDialog changeLabelDialog(m_giftiLableTable, selectedLabel, m_changeKeyValueToolButton); if (changeLabelDialog.exec() == ChangeLabelKeyDialog::Accepted) { loadLabels(labelName, false); processApplyButton(); } } /** * Called to undo changes to selected label. */ void GiftiLabelTableEditor::undoButtonClicked() { if (m_undoGiftiLabel != NULL) { labelNameLineEditTextEdited(m_undoGiftiLabel->getName()); float rgba[4]; m_undoGiftiLabel->getColor(rgba); colorEditorColorChanged(rgba); listWidgetLabelSelected(); } } /** * Called to delete the label. */ void GiftiLabelTableEditor::deleteButtonClicked() { GiftiLabel* gl = getSelectedLabel(); if (gl != NULL) { if (WuQMessageBox::warningOkCancel(this, "Delete " + gl->getName())) { m_giftiLableTable->deleteLabel(gl); loadLabels("", true); listWidgetLabelSelected(); } } } /** * Gets called when a button this dialog added is clicked. * * @param userPushButton * Button that was clicked. */ WuQDialogModal::DialogUserButtonResult GiftiLabelTableEditor::userButtonPressed(QPushButton* userPushButton) { DialogUserButtonResult result = RESULT_NONE; if (userPushButton == m_applyPushButton) { processApplyButton(); result = RESULT_NONE; } else { result = WuQDialogModal::userButtonPressed(userPushButton); } return result; } /** * Process as if the apply button was pressed. * Apply is like OK, except that the dialog remains open. */ void GiftiLabelTableEditor::processApplyButton() { if (m_caretMappableDataFile != NULL) { m_caretMappableDataFile->updateScalarColoringForMap(m_caretMappableDataFileMapIndex); } EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** * Called when the OK button is clicked. */ void GiftiLabelTableEditor::okButtonClicked() { processApplyButton(); const GiftiLabel* gl = getSelectedLabel(); const AString labelName = (gl != NULL) ? gl->getName() : ""; const AString sortingName = m_sortLabelsByComboBox->currentText(); std::map::iterator lastEditIter = s_previousSelections.find(m_giftiLableTable); if (lastEditIter != s_previousSelections.end()) { PreviousSelections& ps = lastEditIter->second; ps.m_selectedLabelName = labelName; ps.m_sortingName = sortingName; } else { PreviousSelections ps; ps.m_selectedLabelName = labelName; ps.m_sortingName = sortingName; s_previousSelections.insert(std::make_pair(m_giftiLableTable, ps)); } WuQDialogModal::okButtonClicked(); } /* ==================================================================================================================== */ /** * Dialog for changing a label's key. * * @param giftiLabelTable * Label table that is being edited. * @param giftiLabel * Label that may have its key changed. * @param parent * Parent on which this dialog is displayed. */ ChangeLabelKeyDialog::ChangeLabelKeyDialog(GiftiLabelTable* giftiLabelTable, const GiftiLabel* giftiLabel, QWidget* parent) : WuQDialogModal("Change Label Key", parent), m_giftiLabelTable(giftiLabelTable), m_giftiLabel(giftiLabel) { QLabel* nameLabel = new QLabel("Name: "); QLabel* nameTextLabel = new QLabel(giftiLabel->getName()); QLabel* keyLabel = new QLabel("Key: "); QLabel* keyValueLabel = new QLabel(AString::number(giftiLabel->getKey())); QLabel* newKeyLabel = new QLabel("New Key: "); m_labelKeyLineEdit = new QLineEdit(); m_labelKeyLineEdit->setFixedWidth(100); m_labelKeyLineEdit->setValidator(new QIntValidator(0, 999999, m_labelKeyLineEdit)); m_labelKeyLineEdit->setText(keyValueLabel->text()); QWidget* widget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(widget); gridLayout->addWidget(nameLabel, 0, 0); gridLayout->addWidget(nameTextLabel, 0, 1, Qt::AlignLeft); gridLayout->addWidget(keyLabel, 1, 0); gridLayout->addWidget(keyValueLabel, 1, 1, Qt::AlignLeft); gridLayout->addWidget(newKeyLabel, 2, 0); gridLayout->addWidget(m_labelKeyLineEdit, 2, 1, Qt::AlignLeft); setCentralWidget(widget, WuQDialog::SCROLL_AREA_NEVER); } /** * Destructor. */ ChangeLabelKeyDialog::~ChangeLabelKeyDialog() { } /** * Called when ok button is clicked. */ void ChangeLabelKeyDialog::okButtonClicked() { const AString keyText = m_labelKeyLineEdit->text().trimmed(); if ( ! keyText.isEmpty()) { const int32_t newKey = keyText.toInt(); const int32_t oldKey = m_giftiLabel->getKey(); if (newKey != oldKey) { const AString oldKeyMsg("Any brainordinates assigned to \"" + m_giftiLabel->getName() + "\" will no long receive any coloring since there is no longer a label matching the brainordinates' value."); const GiftiLabel* newKeyLabel = m_giftiLabelTable->getLabel(newKey); if (newKeyLabel != NULL) { const AString msg("WARNING: Each label must have a unique key.\n" "\n" "\n" "\n" "In addition:\n" " (1) A label named \"" + newKeyLabel->getName() + "\" is assigned the key " + AString::number(newKey) + " and this label will be removed.\n\n" " (2) Any brainordinates assigned to \"" + newKeyLabel->getName() + "\" will be assigned to \"" + m_giftiLabel->getName() + "\".\n\n" + " (3) " + oldKeyMsg); if (WuQMessageBox::warningOkCancel(this, msg)) { m_giftiLabelTable->changeLabelKey(oldKey, newKey); } else { return; } } else { if (WuQMessageBox::warningOkCancel(this, ("WARNING: " + oldKeyMsg))) { m_giftiLabelTable->changeLabelKey(oldKey, newKey); } else { return; } } } } WuQDialogModal::okButtonClicked(); } ///** // * // */ //int32_t //ChangeLabelKeyDialog::getNewKeyValue() const //{ // //} // connectome-workbench-1.4.2/src/GuiQt/GiftiLabelTableEditor.h000066400000000000000000000157561360521144700237630ustar00rootroot00000000000000#ifndef __GIFTI_LABEL_TABLE_EDITOR__H_ #define __GIFTI_LABEL_TABLE_EDITOR__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretPointer.h" #include "WuQDialogModal.h" class QAction; class QComboBox; class QLabel; class QLineEdit; class QListWidget; class QListWidgetItem; class QPushButton; class QToolButton; namespace caret { class BorderFile; class CaretMappableDataFile; class ColorEditorWidget; class FociFile; class GiftiLabel; class GiftiLabelTable; class WuQWidgetObjectGroup; class GiftiLabelTableEditor : public WuQDialogModal { Q_OBJECT public: enum Options { /** * No options */ OPTION_NONE = 0, /** * Hide the unassigned label so that it is not shown in editor. * May be bitwise OR'ed with other options. */ OPTION_UNASSIGNED_LABEL_HIDDEN = 1, /** * Add an apply button so that the graphics windows can be * updated without having to close the dialog. */ OPTION_ADD_APPLY_BUTTON = 2, /** * Add GUI components that allow the user to edit the * key assigned to the selected label. */ OPTION_ADD_KEY_EDITING = 4 }; // GiftiLabelTableEditor(GiftiLabelTable* giftiLableTable, // const AString& dialogTitle, // const uint32_t options, // QWidget* parent); GiftiLabelTableEditor(CaretMappableDataFile* caretMappableDataFile, const int32_t mapIndex, const AString& dialogTitle, const uint32_t options, QWidget* parent); GiftiLabelTableEditor(FociFile* fociFile, GiftiLabelTable* giftiLableTable, const AString& dialogTitle, const uint32_t options, QWidget* parent); GiftiLabelTableEditor(BorderFile* borderFile, GiftiLabelTable* giftiLableTable, const AString& dialogTitle, const uint32_t options, QWidget* parent); virtual ~GiftiLabelTableEditor(); AString getLastSelectedLabelName() const; void selectLabelWithName(const AString& labelName); private: GiftiLabelTableEditor(const GiftiLabelTableEditor&); GiftiLabelTableEditor& operator=(const GiftiLabelTableEditor&); private slots: void newButtonClicked(); void deleteButtonClicked(); void undoButtonClicked(); void changeLabelKeyLockButtonClicked(); // void listWidgetLabelSelected(int row); void listWidgetLabelSelected(); void colorEditorColorChanged(const float*); void labelNameLineEditTextEdited(const QString&); void sortingLabelsActivated(); protected: virtual void okButtonClicked(); DialogUserButtonResult userButtonPressed(QPushButton* userPushButton); private: void initializeDialog(GiftiLabelTable* giftiLabelTable, const uint32_t options); void loadLabels(const AString& selectedName, const bool usePreviouslySelectedIndex); GiftiLabel* getSelectedLabel(); void setWidgetItemIconColor(QListWidgetItem* item, const float rgba[4]); void processApplyButton(); void allowLabelDataEditing(const bool allowEditingFlag); QListWidget* m_labelSelectionListWidget; BorderFile* m_borderFile; FociFile* m_fociFile; CaretMappableDataFile* m_caretMappableDataFile; int32_t m_caretMappableDataFileMapIndex; GiftiLabelTable* m_giftiLableTable; ColorEditorWidget* m_colorEditorWidget; QLineEdit* m_labelNameLineEdit; QLineEdit* m_keyValueLineEdit; QToolButton* m_changeKeyValueToolButton; AString m_lastSelectedLabelName; GiftiLabel* m_undoGiftiLabel; bool m_showUnassignedLabelInEditor; WuQWidgetObjectGroup* m_editingGroup; QPushButton* m_applyPushButton; QComboBox* m_sortLabelsByComboBox; struct PreviousSelections { AString m_sortingName; AString m_selectedLabelName; }; static std::map s_previousSelections; static const AString s_SORT_COMBO_BOX_NAME_BY_KEY; static const AString s_SORT_COMBO_BOX_NAME_BY_NAME; static bool s_displayKeyEditingWarningFlag; }; class ChangeLabelKeyDialog : public WuQDialogModal { Q_OBJECT public: ChangeLabelKeyDialog(GiftiLabelTable* giftiLabelTable, const GiftiLabel* giftiLabel, QWidget* parent); ~ChangeLabelKeyDialog(); // int32_t getNewKeyValue() const; protected: virtual void okButtonClicked(); private: GiftiLabelTable* m_giftiLabelTable; const GiftiLabel* m_giftiLabel; QLineEdit* m_labelKeyLineEdit; }; #ifdef __GIFTI_LABEL_TABLE_EDITOR_DECLARE__ std::map GiftiLabelTableEditor::s_previousSelections; const AString GiftiLabelTableEditor::s_SORT_COMBO_BOX_NAME_BY_KEY = "Key"; const AString GiftiLabelTableEditor::s_SORT_COMBO_BOX_NAME_BY_NAME = "Name"; bool GiftiLabelTableEditor::s_displayKeyEditingWarningFlag = true; #endif // __GIFTI_LABEL_TABLE_EDITOR_DECLARE__ } // namespace #endif //__GIFTI_LABEL_TABLE_EDITOR__H_ connectome-workbench-1.4.2/src/GuiQt/GiftiLabelTableSelectionComboBox.cxx000066400000000000000000000262561360521144700264630ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __GIFTI_LABEL_TABLE_SELECTION_COMBO_BOX_DECLARE__ #include "GiftiLabelTableSelectionComboBox.h" #undef __GIFTI_LABEL_TABLE_SELECTION_COMBO_BOX_DECLARE__ #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" using namespace caret; /** * \class caret::GiftiLabelTableSelectionComboBox * \brief Combo box for selection of a gifti label. * \ingroup GuiQt */ /** * Constructor. * * @param parent * Parent of this object. */ GiftiLabelTableSelectionComboBox::GiftiLabelTableSelectionComboBox(QObject* parent) : WuQWidget(parent) { m_ignoreInsertedRowsFlag = true; m_giftiLabelTable = NULL; m_unassignedLabelTextOverride = ""; m_comboBox = new QComboBox(); m_comboBox->setMaxVisibleItems(20); QObject::connect(m_comboBox, SIGNAL(activated(int)), this, SLOT(itemActivated(int))); QObject::connect(m_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(currentIndexChanged(int))); #ifdef CARET_OS_MACOSX /* * On Mac, use a windows combo box so that * the pop-up is not a list the covers the * full vertical dimension of the monitor. */ QStyle* style = QStyleFactory::create("Windows"); if (style != NULL) { m_comboBox->setStyle(style); //QPalette macPalette(QPalette(m_comboBox->palette())); //m_comboBox->setPalette(macPalette); } // QStringList styleNames; // //styleNames << "Windows" << "Plastique"; // QStringListIterator styleNameIterator(styleNames); // while (styleNameIterator.hasNext()) { // style = QStyleFactory::create(styleNameIterator.next()); // if (style != NULL) { // break; // } // } #endif // CARET_OS_MACOSX QStyle::SH_ComboBox_Popup const bool allowEditingFlag = false; if (allowEditingFlag) { m_comboBox->setEditable(true); m_comboBox->setDuplicatesEnabled(false); m_comboBox->setInsertPolicy(QComboBox::InsertAlphabetically); QAbstractItemModel* model = m_comboBox->model(); QObject::connect(model, SIGNAL(rowsInserted(const QModelIndex&, int, int)), this, SLOT(rowsWereInserted(const QModelIndex, int, int))); } } /** * Destructor. */ GiftiLabelTableSelectionComboBox::~GiftiLabelTableSelectionComboBox() { } /** * Override the text of the unassigned label. * * @param text * Text that overrides the text of the unassigned label. */ void GiftiLabelTableSelectionComboBox::setUnassignedLabelTextOverride(const AString& text) { m_unassignedLabelTextOverride = text; } /** * If the combo box is editable, this can be used to create the new * label. * * @param parent * The parent model index. * @param start * First new row index. * @param end * Last new row index. */ void GiftiLabelTableSelectionComboBox::rowsWereInserted(const QModelIndex& /*parent*/, int start, int end) { if (m_ignoreInsertedRowsFlag) { return; } for (int i = start; i <= end; i++) { const QString text = m_comboBox->itemText(i); QVariant userData = m_comboBox->itemData(i); void* pointer = userData.value(); if (pointer == NULL) { const int32_t key = m_giftiLabelTable->addLabel(text, 0.0f, 0.0f, 0.0f, 1.0f); GiftiLabel* label = m_giftiLabelTable->getLabel(key); QPixmap pm(10, 10); pm.fill(QColor::fromRgbF(label->getRed(), label->getGreen(), label->getBlue())); QIcon icon(pm); QVariant userData = qVariantFromValue((void*)label); m_comboBox->setItemData(i, userData); m_comboBox->setItemIcon(i, icon); } } } /** * Called when the add/edit button is clicked. */ void GiftiLabelTableSelectionComboBox::addEditButtonClicked() { } /** * Gets called when the index is changed by user or program code. * * @parma index * Index of item. */ void GiftiLabelTableSelectionComboBox::currentIndexChanged(int /*indx*/) { GiftiLabel* gl = getSelectedLabel(); emit labelChanged(gl); if (gl != NULL) { emit labelKeyChanged(gl->getKey()); } else { emit labelKeyChanged(GiftiLabel::getInvalidLabelKey()); } } /** * Gets called when the user selects an item even if the selection * does not change. * * @parma index * Index of item. */ void GiftiLabelTableSelectionComboBox::itemActivated(int /*indx*/) { GiftiLabel* gl = getSelectedLabel(); emit labelActivated(gl); if (gl != NULL) { emit labelKeyActivated(gl->getKey()); } else { emit labelKeyActivated(GiftiLabel::getInvalidLabelKey()); } } /** * Update the content of this control with the given lable table. * * @param giftiLabelTable * The label table. */ void GiftiLabelTableSelectionComboBox::updateContent(GiftiLabelTable* giftiLabelTable) { m_ignoreInsertedRowsFlag = true; m_giftiLabelTable = giftiLabelTable; const AString selectedLabelName = m_comboBox->currentText(); m_comboBox->clear(); int32_t defaultIndex = -1; if (m_giftiLabelTable != NULL) { const int32_t unassignedKey = m_giftiLabelTable->getUnassignedLabelKey(); const std::vector keySet = m_giftiLabelTable->getLabelKeysSortedByName(); for (std::vector::const_iterator iter = keySet.begin(); iter != keySet.end(); iter++) { const int32_t key = *iter; GiftiLabel* label = giftiLabelTable->getLabel(key); AString labelName = label->getName(); if (key == unassignedKey) { if (m_unassignedLabelTextOverride.isEmpty() == false) { labelName = m_unassignedLabelTextOverride; } } if (labelName == selectedLabelName) { defaultIndex = m_comboBox->count(); } QPixmap pm(10, 10); pm.fill(QColor::fromRgbF(label->getRed(), label->getGreen(), label->getBlue())); QIcon icon(pm); QVariant userData = qVariantFromValue((void*)label); m_comboBox->addItem(icon, labelName, userData); } m_comboBox->setEnabled(true); if (defaultIndex >= 0) { m_comboBox->blockSignals(true); m_comboBox->setCurrentIndex(defaultIndex); m_comboBox->blockSignals(false); } } else { m_comboBox->setEnabled(false); } m_ignoreInsertedRowsFlag = false; } /** * Return the widget in this object. */ QWidget* GiftiLabelTableSelectionComboBox::getWidget() { return m_comboBox; } /** * @return The selected label (NULL if no selection). */ const GiftiLabel* GiftiLabelTableSelectionComboBox::getSelectedLabel() const { const int indx = m_comboBox->currentIndex(); if (indx >= 0) { QVariant userData = m_comboBox->itemData(indx); void* pointer = userData.value(); GiftiLabel* giftiLabel = (GiftiLabel*)pointer; return giftiLabel; } return NULL; } /** * @return The selected label (NULL if no selection). */ GiftiLabel* GiftiLabelTableSelectionComboBox::getSelectedLabel() { const int indx = m_comboBox->currentIndex(); if (indx >= 0) { QVariant userData = m_comboBox->itemData(indx); void* pointer = userData.value(); GiftiLabel* giftiLabel = (GiftiLabel*)pointer; return giftiLabel; } return NULL; } /** * Set the selected label to the given label. * * @param label * The label that is to be selected. */ void GiftiLabelTableSelectionComboBox::setSelectedLabel(const GiftiLabel* label) { if (label != NULL) { QVariant userData = qVariantFromValue((void*)label); int indx = m_comboBox->findData(userData); if (indx >= 0) { m_comboBox->setCurrentIndex(indx); } else { CaretLogSevere("Label not found: " + label->getName()); } } } /** * @return Key of the selected label or GiftiLabel::getInvalidLabelKey() * if no label selected. */ int32_t GiftiLabelTableSelectionComboBox::getSelectedLabelKey() const { const GiftiLabel* gl = getSelectedLabel(); if (gl != NULL) { return gl->getKey(); } return GiftiLabel::getInvalidLabelKey(); } /** * Set the selected label to the label with the given key. * * @param key * Key of label that is to be selected. */ void GiftiLabelTableSelectionComboBox::setSelectedLabelKey(const int32_t key) { const GiftiLabel* label = m_giftiLabelTable->getLabel(key); if (label != NULL) { setSelectedLabel(label); } else { CaretLogSevere("No label with key found: " + QString::number(key)); } } /** * @return Name of selected label or empty string if no label selected. */ QString GiftiLabelTableSelectionComboBox::getSelectedLabelName() const { const GiftiLabel* gl = getSelectedLabel(); if (gl != NULL) { return gl->getName(); } return ""; } /** * Set the selected label to the label with the given name. * * @param labelName * Name of label that is to be selected. */ void GiftiLabelTableSelectionComboBox::setSelectedLabelName(const QString& labelName) { const GiftiLabel* label = m_giftiLabelTable->getLabel(labelName); if (label != NULL) { setSelectedLabel(label); } else { // CaretLogSevere("No label with name found: " + // labelName); } } connectome-workbench-1.4.2/src/GuiQt/GiftiLabelTableSelectionComboBox.h000066400000000000000000000105571360521144700261050ustar00rootroot00000000000000#ifndef __GIFTI_LABEL_TABLE_SELECTION_COMBO_BOX_H__ #define __GIFTI_LABEL_TABLE_SELECTION_COMBO_BOX_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AString.h" #include "WuQWidget.h" class QComboBox; class QModelIndex; namespace caret { class GiftiLabel; class GiftiLabelTable; class GiftiLabelTableSelectionComboBox : public WuQWidget { Q_OBJECT public: GiftiLabelTableSelectionComboBox(QObject* parent); virtual ~GiftiLabelTableSelectionComboBox(); void updateContent(GiftiLabelTable* giftiLabelTable); virtual QWidget* getWidget(); const GiftiLabel* getSelectedLabel() const; GiftiLabel* getSelectedLabel(); void setSelectedLabel(const GiftiLabel* label); int32_t getSelectedLabelKey() const; void setSelectedLabelKey(const int32_t key); QString getSelectedLabelName() const; void setSelectedLabelName(const QString& labelName); void setUnassignedLabelTextOverride(const AString& text); signals: /** * This signal is sent when the user chooses a label in the combobox. * The item's label is passed. Note that this signal is sent even when * the choice is not changed. If you need to know when the choice * actually changes, use signal labelChanged(). If the selected * label is invalid, NULL is passed. */ void labelActivated(GiftiLabel*); /** * This signal is sent when the user chooses a label in the combobox. * The item's key is passed. Note that this signal is sent even when * the choice is not changed. If you need to know when the choice * actually changes, use signal labelKeyChanged(). If the selected * label is invalid, GiftiLabel::getInvalidLabelKey() is passed. */ void labelKeyActivated(const int32_t key); /** * This signal is sent whenever the label in the combobox * changes either through user interaction or programmatically. * If the selected label is invalid, NULL is passed. */ void labelChanged(GiftiLabel*); /** * This signal is sent whenever the label in the combobox * changes either through user interaction or programmatically. * If the selected label is invalid, GiftiLabel::getInvalidLabelKey() is passed. */ void labelKeyChanged(const int32_t key); // ADD_NEW_METHODS_HERE private slots: void currentIndexChanged(int indx); void itemActivated(int indx); void addEditButtonClicked(); void rowsWereInserted(const QModelIndex& parent, int start, int end); private: GiftiLabelTableSelectionComboBox(const GiftiLabelTableSelectionComboBox&); GiftiLabelTableSelectionComboBox& operator=(const GiftiLabelTableSelectionComboBox&); GiftiLabelTable* m_giftiLabelTable; QComboBox* m_comboBox; bool m_ignoreInsertedRowsFlag; AString m_unassignedLabelTextOverride; // ADD_NEW_MEMBERS_HERE }; #ifdef __GIFTI_LABEL_TABLE_SELECTION_COMBO_BOX_DECLARE__ // #endif // __GIFTI_LABEL_TABLE_SELECTION_COMBO_BOX_DECLARE__ } // namespace #endif //__GIFTI_LABEL_TABLE_SELECTION_COMBO_BOX_H__ connectome-workbench-1.4.2/src/GuiQt/GroupAndNameHierarchyTreeWidgetItem.cxx000066400000000000000000000422261360521144700271670ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CLASS_AND_NAME_HIERARCHY_TREE_WIDGET_ITEM_DECLARE__ #include "GroupAndNameHierarchyTreeWidgetItem.h" #undef __CLASS_AND_NAME_HIERARCHY_TREE_WIDGET_ITEM_DECLARE__ #include "CaretAssert.h" #include "GroupAndNameHierarchyGroup.h" #include "GroupAndNameHierarchyModel.h" #include "GroupAndNameHierarchyName.h" using namespace caret; /** * \class caret::ClassAndNameHierarchySelectionInfo * \brief Tree Widget Item for Class and Name Hierarchy * \ingroup GuiQt */ /** * Constructor for ClassAndNameHierarchyModel * @param classAndNameHierarchyModel * The class name hierarchy model. */ GroupAndNameHierarchyTreeWidgetItem::GroupAndNameHierarchyTreeWidgetItem(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, GroupAndNameHierarchyModel* classAndNameHierarchyModel) : QTreeWidgetItem() { CaretAssert(classAndNameHierarchyModel); initialize(classAndNameHierarchyModel, displayGroup, tabIndex, ITEM_TYPE_HIERARCHY_MODEL, classAndNameHierarchyModel->getName(), NULL); m_classAndNameHierarchyModel = classAndNameHierarchyModel; /* * Loop through each class */ std::vector classChildren = m_classAndNameHierarchyModel->getChildren(); for (std::vector::iterator classIter = classChildren.begin(); classIter != classChildren.end(); classIter++) { GroupAndNameHierarchyItem* classItem = *classIter; CaretAssert(classItem); GroupAndNameHierarchyGroup* group = dynamic_cast(classItem); CaretAssert(group); GroupAndNameHierarchyTreeWidgetItem* groupItem = new GroupAndNameHierarchyTreeWidgetItem(displayGroup, tabIndex, group); addChildItem(groupItem); } } /** * Constructor for ClassDisplayGroupSelector * @param classDisplayGroupSelector * The class display group selector. */ GroupAndNameHierarchyTreeWidgetItem::GroupAndNameHierarchyTreeWidgetItem(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, GroupAndNameHierarchyGroup* classDisplayGroupSelector) : QTreeWidgetItem() { CaretAssert(classDisplayGroupSelector); initialize(classDisplayGroupSelector, displayGroup, tabIndex, ITEM_TYPE_CLASS, classDisplayGroupSelector->getName(), classDisplayGroupSelector->getIconColorRGBA()); m_classDisplayGroupSelector = classDisplayGroupSelector; std::vector nameChildren = m_classDisplayGroupSelector->getChildren(); for (std::vector::iterator nameIter = nameChildren.begin(); nameIter != nameChildren.end(); nameIter++) { GroupAndNameHierarchyItem* nameItem = *nameIter; CaretAssert(nameItem); GroupAndNameHierarchyName* name = dynamic_cast(nameItem); CaretAssert(name); GroupAndNameHierarchyTreeWidgetItem* nameTreeItem = new GroupAndNameHierarchyTreeWidgetItem(displayGroup, tabIndex, name); addChildItem(nameTreeItem); } } /** * Constructor for NameDisplayGroupSelector * @param nameDisplayGroupSelector * The name display group selector. */ GroupAndNameHierarchyTreeWidgetItem::GroupAndNameHierarchyTreeWidgetItem(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, GroupAndNameHierarchyName* nameDisplayGroupSelector) : QTreeWidgetItem() { CaretAssert(nameDisplayGroupSelector); initialize(nameDisplayGroupSelector, displayGroup, tabIndex, ITEM_TYPE_NAME, nameDisplayGroupSelector->getName(), nameDisplayGroupSelector->getIconColorRGBA()); m_nameDisplayGroupSelector = nameDisplayGroupSelector; } /** * Destructor. */ GroupAndNameHierarchyTreeWidgetItem::~GroupAndNameHierarchyTreeWidgetItem() { /* * Note: Do not need to delete children since they are added to * Qt layouts which will delete them. */ } /** * Initialize this instance. * @param itemType * Type of item contained in this instance. */ void GroupAndNameHierarchyTreeWidgetItem::initialize(GroupAndNameHierarchyItem* groupAndNameHierarchyItem, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const ItemType itemType, const QString text, const float* /*iconColorRGBA*/) { m_groupAndNameHierarchyItem = groupAndNameHierarchyItem; m_classAndNameHierarchyModel = dynamic_cast(groupAndNameHierarchyItem); m_classDisplayGroupSelector = dynamic_cast(groupAndNameHierarchyItem); m_nameDisplayGroupSelector = dynamic_cast(groupAndNameHierarchyItem); const int32_t count = (((m_classAndNameHierarchyModel != NULL) ? 1 : 0) + ((m_classDisplayGroupSelector != NULL) ? 1 : 0) + ((m_nameDisplayGroupSelector != NULL) ? 1 : 0)); if (count != 1) { CaretAssertMessage(0, "Invalid item added to group/name hierarchy tree."); } m_iconColorRGBA[0] = -1.0; m_iconColorRGBA[1] = -1.0; m_iconColorRGBA[2] = -1.0; m_iconColorRGBA[3] = -1.0; m_displayGroup = displayGroup; m_tabIndex = tabIndex; m_itemType = itemType; // m_classAndNameHierarchyModel = NULL; // m_classDisplayGroupSelector = NULL; // m_nameDisplayGroupSelector = NULL; m_hasChildren = false; switch (m_itemType) { case ITEM_TYPE_CLASS: m_hasChildren = true; break; case ITEM_TYPE_HIERARCHY_MODEL: m_hasChildren = true; break; case ITEM_TYPE_NAME: m_hasChildren = false; break; } setText(TREE_COLUMN, text); /*Qt::ItemFlags itemFlags = (Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);//*/ if (m_hasChildren) { // itemFlags |= Qt::ItemIsTristate; } // setFlags(itemFlags); // NEW 11/14/12 // if (iconColorRGBA != NULL) { // if (iconColorRGBA[3] > 0.0) { // QPixmap pm(10, 10); // pm.fill(QColor::fromRgbF(iconColorRGBA[0], // iconColorRGBA[1], // iconColorRGBA[2])); // QIcon icon(pm); // setIcon(TREE_COLUMN, icon); // } // } updateIconColorIncludingChildren(); } /** * Update the selections in this and its children. * @param displayGroup * Display group that is active. * @param tabIndex * Index of tab that is displayed. */ void GroupAndNameHierarchyTreeWidgetItem::updateSelections(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex) { m_displayGroup = displayGroup; m_tabIndex = tabIndex; GroupAndNameCheckStateEnum::Enum checkState = GroupAndNameCheckStateEnum::UNCHECKED; bool expandedStatus = false; switch (m_itemType) { case ITEM_TYPE_CLASS: CaretAssert(m_classDisplayGroupSelector); checkState = m_classDisplayGroupSelector->getCheckState(m_displayGroup, m_tabIndex); expandedStatus = m_classDisplayGroupSelector->isExpandedToDisplayChildren(m_displayGroup, m_tabIndex); break; case ITEM_TYPE_HIERARCHY_MODEL: CaretAssert(m_classAndNameHierarchyModel); checkState = m_classAndNameHierarchyModel->getCheckState(m_displayGroup, m_tabIndex); expandedStatus = m_classAndNameHierarchyModel->isExpandedToDisplayChildren(m_displayGroup, m_tabIndex); break; case ITEM_TYPE_NAME: CaretAssert(m_nameDisplayGroupSelector); checkState = m_nameDisplayGroupSelector->getCheckState(m_displayGroup, m_tabIndex); expandedStatus = false; break; } Qt::CheckState qtCheckState = toQCheckState(checkState); setCheckState(TREE_COLUMN, qtCheckState); if (m_hasChildren) { setExpanded(expandedStatus); for (std::vector::iterator iter = m_children.begin(); iter != m_children.end(); iter++) { GroupAndNameHierarchyTreeWidgetItem* item = *iter; item->updateSelections(m_displayGroup, tabIndex); } } } /** * If this item's color has changed, update its icon. * Process all of its children. */ void GroupAndNameHierarchyTreeWidgetItem::updateIconColorIncludingChildren() { if (m_groupAndNameHierarchyItem != NULL) { const float* rgba = m_groupAndNameHierarchyItem->getIconColorRGBA(); if (rgba != NULL) { if (rgba[3] > 0.0) { bool colorChanged = false; for (int32_t i = 0; i < 4; i++) { if (m_iconColorRGBA[i] != rgba[i]) { colorChanged = true; break; } } if (colorChanged) { m_iconColorRGBA[0] = rgba[0]; m_iconColorRGBA[1] = rgba[1]; m_iconColorRGBA[2] = rgba[2]; m_iconColorRGBA[3] = rgba[3]; QPixmap pm(10, 10); pm.fill(QColor::fromRgbF(m_iconColorRGBA[0], m_iconColorRGBA[1], m_iconColorRGBA[2])); QIcon icon(pm); setIcon(TREE_COLUMN, icon); } } } } for (std::vector::iterator iter = m_children.begin(); iter != m_children.end(); iter++) { GroupAndNameHierarchyTreeWidgetItem* item = *iter; item->updateIconColorIncludingChildren(); } } /** * Add a child. * @param child. * The child. */ void GroupAndNameHierarchyTreeWidgetItem::addChildItem(GroupAndNameHierarchyTreeWidgetItem* child) { CaretAssert(child); m_children.push_back(child); addChild(child); } /** * @return ItemType of the selected item. */ GroupAndNameHierarchyTreeWidgetItem::ItemType GroupAndNameHierarchyTreeWidgetItem::getItemType() const { return m_itemType; } /** * @return The class name and hierarchy model. NULL * if this instance contains another type of data. */ GroupAndNameHierarchyModel* GroupAndNameHierarchyTreeWidgetItem::getClassAndNameHierarchyModel() { CaretAssert(m_itemType == ITEM_TYPE_HIERARCHY_MODEL); return m_classAndNameHierarchyModel; } /** * @return The class name and hierarchy model. NULL * if this instance contains another type of data. */ GroupAndNameHierarchyGroup* GroupAndNameHierarchyTreeWidgetItem::getClassDisplayGroupSelector() { CaretAssert(m_itemType == ITEM_TYPE_CLASS); return m_classDisplayGroupSelector; } /** * @return The class name and hierarchy model. NULL * if this instance contains another type of data. */ GroupAndNameHierarchyName* GroupAndNameHierarchyTreeWidgetItem::getNameDisplayGroupSelector() { CaretAssert(m_itemType == ITEM_TYPE_NAME); return m_nameDisplayGroupSelector; } /** * Convert QCheckState to GroupAndNameCheckStateEnum * @param checkState * The QCheckState * @return GroupAndNameCheckStateEnum converted from QCheckState */ GroupAndNameCheckStateEnum::Enum GroupAndNameHierarchyTreeWidgetItem::fromQCheckState(const Qt::CheckState checkState) { switch (checkState) { case Qt::Unchecked: return GroupAndNameCheckStateEnum::UNCHECKED; break; case Qt::PartiallyChecked: return GroupAndNameCheckStateEnum::PARTIALLY_CHECKED; break; case Qt::Checked: return GroupAndNameCheckStateEnum::CHECKED; break; } return GroupAndNameCheckStateEnum::UNCHECKED; } /** * Convert GroupAndNameCheckStateEnum to QCheckState * @param checkState * The GroupAndNameCheckStateEnum * @return QCheckState converted from GroupAndNameCheckStateEnum converted. */ Qt::CheckState GroupAndNameHierarchyTreeWidgetItem::toQCheckState(const GroupAndNameCheckStateEnum::Enum checkState) { switch (checkState) { case GroupAndNameCheckStateEnum::CHECKED: return Qt::Checked; break; case GroupAndNameCheckStateEnum::PARTIALLY_CHECKED: return Qt::PartiallyChecked; break; case GroupAndNameCheckStateEnum::UNCHECKED: return Qt::Unchecked; break; } return Qt::Unchecked; } /** * Set the expanded status of the data in the model that is presented * by this item. * @param expanded * Status of expansion. */ void GroupAndNameHierarchyTreeWidgetItem::setModelDataExpanded(const bool expanded) { GroupAndNameHierarchyItem* item = NULL; switch (m_itemType) { case ITEM_TYPE_CLASS: item = m_classDisplayGroupSelector; break; case ITEM_TYPE_HIERARCHY_MODEL: item = m_classAndNameHierarchyModel; break; case ITEM_TYPE_NAME: item = m_nameDisplayGroupSelector; break; } if (item != NULL) { item->setExpandedToDisplayChildren(m_displayGroup, m_tabIndex, expanded); } } /** * Set the selected status of the data in the model that is presented * by this item. * @param selected * Status of selection. */ void GroupAndNameHierarchyTreeWidgetItem::setModelDataSelected(const bool selected) { GroupAndNameHierarchyItem* item = NULL; switch (m_itemType) { case ITEM_TYPE_CLASS: item = m_classDisplayGroupSelector; break; case ITEM_TYPE_HIERARCHY_MODEL: item = m_classAndNameHierarchyModel; break; case ITEM_TYPE_NAME: item = m_nameDisplayGroupSelector; break; } if (item != NULL) { const GroupAndNameCheckStateEnum::Enum existingCheckState = item->getCheckState(m_displayGroup, m_tabIndex); switch (existingCheckState) { case GroupAndNameCheckStateEnum::CHECKED: break; case GroupAndNameCheckStateEnum::PARTIALLY_CHECKED: break; case GroupAndNameCheckStateEnum::UNCHECKED: break; } if (selected) { item->setSelected(m_displayGroup, m_tabIndex, true); item->setAncestorsSelected(m_displayGroup, m_tabIndex, true); item->setDescendantsSelected(m_displayGroup, m_tabIndex, true); } else { item->setSelected(m_displayGroup, m_tabIndex, false); item->setDescendantsSelected(m_displayGroup, m_tabIndex, false); } } } connectome-workbench-1.4.2/src/GuiQt/GroupAndNameHierarchyTreeWidgetItem.h000066400000000000000000000116541360521144700266150ustar00rootroot00000000000000#ifndef __CLASS_AND_NAME_HIERARCHY_TREE_WIDGET_ITEM__H_ #define __CLASS_AND_NAME_HIERARCHY_TREE_WIDGET_ITEM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "DisplayGroupEnum.h" #include "GroupAndNameCheckStateEnum.h" class QAction; class QCheckBox; class QVBoxLayout; namespace caret { class GroupAndNameHierarchyGroup; class GroupAndNameHierarchyItem; class GroupAndNameHierarchyModel; class GroupAndNameHierarchyName; class GroupAndNameHierarchyTreeWidgetItem : public QTreeWidgetItem { public: /** Type of item within the hierarchy */ enum ItemType { /** The class/name hierarchy model */ ITEM_TYPE_HIERARCHY_MODEL, /** Class in the class/name hierarchy */ ITEM_TYPE_CLASS, /** Name in the class/name hieracrchy */ ITEM_TYPE_NAME }; GroupAndNameHierarchyTreeWidgetItem(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, GroupAndNameHierarchyModel* classAndNameHierarchyModel); GroupAndNameHierarchyTreeWidgetItem(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, GroupAndNameHierarchyGroup* classDisplayGroupSelector); GroupAndNameHierarchyTreeWidgetItem(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, GroupAndNameHierarchyName* nameDisplayGroupSelector); ~GroupAndNameHierarchyTreeWidgetItem(); ItemType getItemType() const; GroupAndNameHierarchyModel* getClassAndNameHierarchyModel(); GroupAndNameHierarchyGroup* getClassDisplayGroupSelector(); GroupAndNameHierarchyName* getNameDisplayGroupSelector(); void addChildItem(GroupAndNameHierarchyTreeWidgetItem* child); void updateSelections(const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex); void setModelDataExpanded(const bool expanded); void setModelDataSelected(const bool selected); void updateIconColorIncludingChildren(); private: GroupAndNameHierarchyTreeWidgetItem(const GroupAndNameHierarchyTreeWidgetItem&); GroupAndNameHierarchyTreeWidgetItem& operator=(const GroupAndNameHierarchyTreeWidgetItem&); void initialize(GroupAndNameHierarchyItem* groupAndNameHierarchyItem, const DisplayGroupEnum::Enum displayGroup, const int32_t tabIndex, const ItemType itemType, const QString text, const float* iconColorRGBA); static GroupAndNameCheckStateEnum::Enum fromQCheckState(const Qt::CheckState checkState); static Qt::CheckState toQCheckState(const GroupAndNameCheckStateEnum::Enum checkState); ItemType m_itemType; DisplayGroupEnum::Enum m_displayGroup; int32_t m_tabIndex; GroupAndNameHierarchyItem* m_groupAndNameHierarchyItem; GroupAndNameHierarchyModel* m_classAndNameHierarchyModel; GroupAndNameHierarchyGroup* m_classDisplayGroupSelector; GroupAndNameHierarchyName* m_nameDisplayGroupSelector; std::vector m_children; bool m_displayNamesWithZeroCount; bool m_hasChildren; float m_iconColorRGBA[4]; static const int TREE_COLUMN; friend class GroupAndNameHierarchyViewController; }; #ifdef __CLASS_AND_NAME_HIERARCHY_TREE_WIDGET_ITEM_DECLARE__ const int GroupAndNameHierarchyTreeWidgetItem::TREE_COLUMN = 0; #endif // __CLASS_AND_NAME_HIERARCHY_TREE_WIDGET_ITEM_DECLARE__ } // namespace #endif //__CLASS_AND_NAME_HIERARCHY_TREE_WIDGET_ITEM__H_ connectome-workbench-1.4.2/src/GuiQt/GroupAndNameHierarchyViewController.cxx000066400000000000000000000466011360521144700272640ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __CLASS_AND_NAME_HIERARCHY_VIEW_CONTROLLER_DECLARE__ #include "GroupAndNameHierarchyViewController.h" #undef __CLASS_AND_NAME_HIERARCHY_VIEW_CONTROLLER_DECLARE__ #include #include #include #include #include #include #include "Brain.h" #include "BorderFile.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CiftiBrainordinateLabelFile.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUserInterfaceUpdate.h" #include "GroupAndNameHierarchyGroup.h" #include "GroupAndNameHierarchyModel.h" #include "GroupAndNameHierarchyName.h" #include "GroupAndNameHierarchyTreeWidgetItem.h" #include "FociFile.h" #include "GuiManager.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "LabelFile.h" #include "VolumeFile.h" #include "WuQMacroManager.h" #include "WuQTreeWidget.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::GroupAndNameHierarchyViewController * \brief View controller for ClassAndNameHierarchyModels * \ingroup GuiQt * * A view controller for one or more ClassAndNameHierarchyModel * instances. */ /** * Constructor. * * @param browserWindowIndex * Index of browser window * @param objectNameForMacros * Name of this object for macros * @param descriptiveNameForMacros * Descriptive name for macros * @param parent * Parent widget. */ GroupAndNameHierarchyViewController::GroupAndNameHierarchyViewController(const int32_t browserWindowIndex, const QString& objectNameForMacros, const QString& descriptiveNameForMacros, QWidget* parent) : QWidget(parent) { m_dataFileType = DataFileTypeEnum::UNKNOWN; m_displayGroup = DisplayGroupEnum::getDefaultValue(); m_previousDisplayGroup = DisplayGroupEnum::getDefaultValue(); m_previousBrowserTabIndex = -1; m_browserWindowIndex = browserWindowIndex; QWidget* allOnOffWidget = createAllOnOffControls(objectNameForMacros, descriptiveNameForMacros); m_modelTreeWidgetLayout = new QVBoxLayout(); WuQtUtilities::setLayoutSpacingAndMargins(m_modelTreeWidgetLayout, 0, 0); m_modelTreeWidget = NULL; createTreeWidget(); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 0); layout->addWidget(allOnOffWidget); layout->addSpacing(5); layout->addLayout(m_modelTreeWidgetLayout, 100); layout->addStretch(); s_allViewControllers.insert(this); } /** * Destructor. */ GroupAndNameHierarchyViewController::~GroupAndNameHierarchyViewController() { s_allViewControllers.erase(this); } /** * Gets called when an item is collapsed so that its children are not visible. * * @param item * The QTreeWidgetItem that was collapsed. */ void GroupAndNameHierarchyViewController::itemWasCollapsed(QTreeWidgetItem* item) { GroupAndNameHierarchyTreeWidgetItem* treeItem = dynamic_cast(item); CaretAssert(treeItem); treeItem->setModelDataExpanded(false); updateSelectedAndExpandedCheckboxes(); updateSelectedAndExpandedCheckboxesInOtherViewControllers(); } /** * Gets called when an item is expaned so that its children are visible. * * @param item * The QTreeWidgetItem that was expanded. */ void GroupAndNameHierarchyViewController::itemWasExpanded(QTreeWidgetItem* item) { GroupAndNameHierarchyTreeWidgetItem* treeItem = dynamic_cast(item); CaretAssert(treeItem); treeItem->setModelDataExpanded(true); updateSelectedAndExpandedCheckboxes(); updateSelectedAndExpandedCheckboxesInOtherViewControllers(); } /** * Called when an item is changed (checkbox selected/deselected). * * @param item * The QTreeWidgetItem that was collapsed. * @param column * Ignored. */ void GroupAndNameHierarchyViewController::itemWasChanged(QTreeWidgetItem* item, int /*column*/) { GroupAndNameHierarchyTreeWidgetItem* treeItem = dynamic_cast(item); CaretAssert(treeItem); const Qt::CheckState checkState = item->checkState(GroupAndNameHierarchyTreeWidgetItem::TREE_COLUMN); const GroupAndNameCheckStateEnum::Enum itemCheckState = GroupAndNameHierarchyTreeWidgetItem::fromQCheckState(checkState); const bool newStatus = (itemCheckState != GroupAndNameCheckStateEnum::UNCHECKED); treeItem->setModelDataSelected(newStatus); updateSelectedAndExpandedCheckboxes(); updateSelectedAndExpandedCheckboxesInOtherViewControllers(); updateGraphics(); } /** * Update graphics and, in some circumstances, surface node coloring. */ void GroupAndNameHierarchyViewController::updateGraphics() { if (m_selectionInvalidatesSurfaceNodeColoring) { EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); } EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Create buttons for all on and off * * @param objectNameForMacros * Name of this object for macros * @param descriptiveNameForMacros * Descriptive name for macros */ QWidget* GroupAndNameHierarchyViewController::createAllOnOffControls(const QString& objectNameForMacros, const QString& descriptiveNameForMacros) { WuQMacroManager* macroManager = WuQMacroManager::instance(); QLabel* allLabel = new QLabel("All: "); QPushButton* onPushButton = new QPushButton("On"); onPushButton->setToolTip("Turn all on"); onPushButton->setObjectName(objectNameForMacros + ":AllOn"); QObject::connect(onPushButton, SIGNAL(clicked()), this, SLOT(allOnPushButtonClicked())); macroManager->addMacroSupportToObject(onPushButton, "Turn on all in " + descriptiveNameForMacros + " selection"); QPushButton* offPushButton = new QPushButton("Off"); offPushButton->setToolTip("Turn all of"); offPushButton->setObjectName(objectNameForMacros + ":AllOff"); QObject::connect(offPushButton, SIGNAL(clicked()), this, SLOT(allOffPushButtonClicked())); macroManager->addMacroSupportToObject(offPushButton, "Turn off all in " + descriptiveNameForMacros + " selection"); QWidget* w = new QWidget(); QHBoxLayout* layout = new QHBoxLayout(w); layout->addWidget(allLabel); layout->addWidget(onPushButton); layout->addWidget(offPushButton); layout->addStretch(); return w; } /** * Called when all on push button clicked. */ void GroupAndNameHierarchyViewController::allOnPushButtonClicked() { setAllSelected(true); } /** * Called when all off push button clicked. */ void GroupAndNameHierarchyViewController::allOffPushButtonClicked() { setAllSelected(false); } /** * Set selection status of all items. * @param selected * New selection status for all items. */ void GroupAndNameHierarchyViewController::setAllSelected(bool selected) { BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, false); if (browserTabContent != NULL) { const int32_t browserTabIndex = browserTabContent->getTabNumber(); std::vector allModels = getAllModels(); const int32_t numModels = static_cast(allModels.size()); for (int32_t i = 0; i < numModels; i++) { GroupAndNameHierarchyModel* model = allModels[i]; model->setAllSelected(m_displayGroup, browserTabIndex, selected); } updateSelectedAndExpandedCheckboxesInOtherViewControllers(); updateSelectedAndExpandedCheckboxes(); updateGraphics(); } } /** * @return All models in this view controller. */ std::vector GroupAndNameHierarchyViewController::getAllModels() const { std::vector allModels; const int32_t numItems = static_cast(m_treeWidgetItems.size()); for (int32_t i = 0; i < numItems; i++) { GroupAndNameHierarchyTreeWidgetItem* treeItem = m_treeWidgetItems[i]; GroupAndNameHierarchyModel* model = treeItem->getClassAndNameHierarchyModel(); allModels.push_back(model); } return allModels; } /** * Update with border files. * @param borderFiles * The border files. * @param displayGroup * The selected display group. */ void GroupAndNameHierarchyViewController::updateContents(std::vector& borderFiles, const DisplayGroupEnum::Enum displayGroup) { std::vector models; m_displayGroup = displayGroup; std::vector classAndNameHierarchyModels; for (std::vector::iterator iter = borderFiles.begin(); iter != borderFiles.end(); iter++) { BorderFile* bf = *iter; CaretAssert(bf); models.push_back(bf->getGroupAndNameHierarchyModel()); } updateContents(models, DataFileTypeEnum::BORDER, false); } /** * Update with border files. * @param borderFiles * The border files. * @param displayGroup * The selected display group. */ void GroupAndNameHierarchyViewController::updateContents(std::vector& fociFiles, const DisplayGroupEnum::Enum displayGroup) { std::vector models; m_displayGroup = displayGroup; std::vector classAndNameHierarchyModels; for (std::vector::iterator iter = fociFiles.begin(); iter != fociFiles.end(); iter++) { FociFile* ff = *iter; CaretAssert(ff); models.push_back(ff->getGroupAndNameHierarchyModel()); } updateContents(models, DataFileTypeEnum::FOCI, false); } /** * Update with label files. * @param labelFiles * The label files. * @param ciftiLabelFiles * The CIFTI label files. * @param volumeLabelFiles * The volume label files. * @param displayGroup * The selected display group. */ void GroupAndNameHierarchyViewController::updateContents(std::vector& labelFiles, std::vector& ciftiLabelFiles, std::vector& volumeLabelFiles, const DisplayGroupEnum::Enum displayGroup) { std::vector models; m_displayGroup = displayGroup; std::vector classAndNameHierarchyModels; for (std::vector::iterator iter = labelFiles.begin(); iter != labelFiles.end(); iter++) { LabelFile* lf = *iter; CaretAssert(lf); models.push_back(lf->getGroupAndNameHierarchyModel()); } for (std::vector::iterator iter = ciftiLabelFiles.begin(); iter != ciftiLabelFiles.end(); iter++) { CiftiBrainordinateLabelFile* clf = *iter; CaretAssert(clf); models.push_back(clf->getGroupAndNameHierarchyModel()); } for (std::vector::iterator iter = volumeLabelFiles.begin(); iter != volumeLabelFiles.end(); iter++) { VolumeFile* vf = *iter; CaretAssert(vf); models.push_back(vf->getGroupAndNameHierarchyModel()); } updateContents(models, DataFileTypeEnum::LABEL, true); } /** * Create/recreate the tree widget. */ void GroupAndNameHierarchyViewController::createTreeWidget() { /* * Delete and recreate the tree widget * Seems that adding and removing items from tree widget eventually * causes a crash. */ m_treeWidgetItems.clear(); if (m_modelTreeWidget != NULL) { m_modelTreeWidget->blockSignals(true); m_modelTreeWidget->clear(); m_modelTreeWidgetLayout->removeWidget(m_modelTreeWidget); delete m_modelTreeWidget; } m_modelTreeWidget = new WuQTreeWidget(); QObject::connect(m_modelTreeWidget, SIGNAL(itemCollapsed(QTreeWidgetItem*)), this, SLOT(itemWasCollapsed(QTreeWidgetItem*))); QObject::connect(m_modelTreeWidget, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(itemWasExpanded(QTreeWidgetItem*))); QObject::connect(m_modelTreeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(itemWasChanged(QTreeWidgetItem*, int))); m_modelTreeWidgetLayout->addWidget(m_modelTreeWidget); m_modelTreeWidget->blockSignals(false); } /** * Update the content of the view controller. * @param classAndNameHierarchyModels * ClassAndNameHierarchyModels instances for display. * @param allowNamesWithZeroCounts * If true, display names even if the usage count is zero. */ void GroupAndNameHierarchyViewController::updateContents(std::vector& classAndNameHierarchyModels, const DataFileTypeEnum::Enum dataFileType, const bool selectionInvalidatesSurfaceNodeColoring) { m_dataFileType= dataFileType; m_selectionInvalidatesSurfaceNodeColoring = selectionInvalidatesSurfaceNodeColoring; BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, false); CaretAssert(browserTabContent); const int32_t browserTabIndex = browserTabContent->getTabNumber(); /* * May need an update */ bool needUpdate = false; int32_t numberOfModels = static_cast(classAndNameHierarchyModels.size()); /* * Has the number of models changed? */ if (numberOfModels != static_cast(this->m_treeWidgetItems.size())) { needUpdate = true; } // else if (m_displayGroup != m_previousDisplayGroup) { // needUpdate = true; // } // else if (browserTabIndex != m_previousBrowserTabIndex) { // needUpdate = true; // } else { /* * Have the displayed models changed? */ for (int32_t iModel = 0; iModel < numberOfModels; iModel++) { if (classAndNameHierarchyModels[iModel] != this->m_treeWidgetItems[iModel]->getClassAndNameHierarchyModel()) { needUpdate = true; break; } else if (classAndNameHierarchyModels[iModel]->getChildren().size() != this->m_treeWidgetItems[iModel]->getClassAndNameHierarchyModel()->getChildren().size()) { needUpdate = true; break; } } /* * Has the model's content been altered? */ for (int32_t iModel = 0; iModel < numberOfModels; iModel++) { if (classAndNameHierarchyModels[iModel]->needsUserInterfaceUpdate(m_displayGroup, browserTabIndex)) { needUpdate = true; break; } } } m_modelTreeWidget->blockSignals(true); if (needUpdate) { createTreeWidget(); m_modelTreeWidget->blockSignals(true); // gets reset /* * Copy the models */ for (int32_t iModel = 0; iModel < numberOfModels; iModel++) { GroupAndNameHierarchyTreeWidgetItem* modelItem = new GroupAndNameHierarchyTreeWidgetItem(m_displayGroup, browserTabIndex, classAndNameHierarchyModels[iModel]); this->m_treeWidgetItems.push_back(modelItem); m_modelTreeWidget->addTopLevelItem(modelItem); } } else { for (int32_t iModel = 0; iModel < numberOfModels; iModel++) { this->m_treeWidgetItems[iModel]->updateIconColorIncludingChildren(); } } updateSelectedAndExpandedCheckboxes(); m_previousBrowserTabIndex = browserTabIndex; m_previousDisplayGroup = m_displayGroup; m_modelTreeWidget->blockSignals(false); if (needUpdate) { m_modelTreeWidget->resizeToFitContent(); } } /** * Update the selection and expansion controls. */ void GroupAndNameHierarchyViewController::updateSelectedAndExpandedCheckboxes() { if (m_modelTreeWidget == NULL) { return; } m_modelTreeWidget->blockSignals(true); BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, false); CaretAssert(browserTabContent); const int32_t browserTabIndex = browserTabContent->getTabNumber(); const int32_t numberOfModels = static_cast(this->m_treeWidgetItems.size()); for (int32_t iModel = 0; iModel < numberOfModels; iModel++) { m_treeWidgetItems[iModel]->updateSelections(m_displayGroup, browserTabIndex); } m_modelTreeWidget->blockSignals(false); } /** * Update the selection and expansion controls in other view controllers * that are set to the same display group (not tab) and contain the * same type of data. */ void GroupAndNameHierarchyViewController::updateSelectedAndExpandedCheckboxesInOtherViewControllers() { if (m_displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { return; } for (std::set::iterator iter = s_allViewControllers.begin(); iter != s_allViewControllers.end(); iter++) { GroupAndNameHierarchyViewController* vc = *iter; if (vc != this) { if (vc->m_displayGroup == m_displayGroup) { if (vc->m_dataFileType == m_dataFileType) { vc->updateSelectedAndExpandedCheckboxes(); } } } } } connectome-workbench-1.4.2/src/GuiQt/GroupAndNameHierarchyViewController.h000066400000000000000000000112561360521144700267070ustar00rootroot00000000000000#ifndef __CLASS_AND_NAME_HIERARCHY_VIEW_CONTROLLER__H_ #define __CLASS_AND_NAME_HIERARCHY_VIEW_CONTROLLER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "DataFileTypeEnum.h" #include "DisplayGroupEnum.h" class QTreeWidgetItem; class QVBoxLayout; namespace caret { class BorderFile; class CiftiBrainordinateLabelFile; class FociFile; class LabelFile; class GroupAndNameHierarchyModel; class GroupAndNameHierarchyTreeWidgetItem; class VolumeFile; class WuQTreeWidget; class GroupAndNameHierarchyViewController : public QWidget { Q_OBJECT public: GroupAndNameHierarchyViewController(const int32_t browserWindowIndex, const QString& objectNameForMacros, const QString& descriptiveNameForMacros, QWidget* parent); virtual ~GroupAndNameHierarchyViewController(); void updateContents(std::vector& borderFiles, const DisplayGroupEnum::Enum displayGroup); void updateContents(std::vector& fociFiles, const DisplayGroupEnum::Enum displayGroup); void updateContents(std::vector& labelFiles, std::vector& ciftiLabelFiles, std::vector& volumeLabelFiles, const DisplayGroupEnum::Enum displayGroup); private slots: void allOnPushButtonClicked(); void allOffPushButtonClicked(); void itemWasCollapsed(QTreeWidgetItem* item); void itemWasExpanded(QTreeWidgetItem* item); void itemWasChanged(QTreeWidgetItem* item, int column); private: GroupAndNameHierarchyViewController(const GroupAndNameHierarchyViewController&); GroupAndNameHierarchyViewController& operator=(const GroupAndNameHierarchyViewController&); void updateContents(std::vector& modelItems, const DataFileTypeEnum::Enum dataFileType, const bool selectionInvalidatesSurfaceNodeColoring); std::vector getAllModels() const; void updateGraphics(); void updateSelectedAndExpandedCheckboxes(); void updateSelectedAndExpandedCheckboxesInOtherViewControllers(); void createTreeWidget(); QWidget* createAllOnOffControls(const QString& objectNameForMacros, const QString& descriptiveNameForMacros); void setAllSelected(bool selected); DataFileTypeEnum::Enum m_dataFileType; /** Contains pointers to items managed by Qt, so do not delete content */ std::vector m_treeWidgetItems; QVBoxLayout* m_modelTreeWidgetLayout; WuQTreeWidget* m_modelTreeWidget; int32_t m_browserWindowIndex; DisplayGroupEnum::Enum m_displayGroup; DisplayGroupEnum::Enum m_previousDisplayGroup; int32_t m_previousBrowserTabIndex; bool m_selectionInvalidatesSurfaceNodeColoring; static std::set s_allViewControllers; }; #ifdef __CLASS_AND_NAME_HIERARCHY_VIEW_CONTROLLER_DECLARE__ std::set GroupAndNameHierarchyViewController::s_allViewControllers; #endif // __CLASS_AND_NAME_HIERARCHY_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__CLASS_AND_NAME_HIERARCHY_VIEW_CONTROLLER__H_ connectome-workbench-1.4.2/src/GuiQt/GuiManager.cxx000066400000000000000000004157031360521144700222300ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #define __GUI_MANAGER_DEFINE__ #include "GuiManager.h" #undef __GUI_MANAGER_DEFINE__ #include "Annotation.h" #include "AnnotationFile.h" #include "AnnotationManager.h" #include "Brain.h" #include "BrainBrowserWindow.h" #include "BrainOpenGL.h" #include "BrainStructure.h" #include "BrowserTabContent.h" #include "BugReportDialog.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretMappableDataFile.h" #include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileMatrixChart.h" #include "ChartingDataManager.h" #include "ChartTwoOverlay.h" #include "ChartTwoOverlaySet.h" #include "CiftiConnectivityMatrixDataFileManager.h" #include "CiftiFiberTrajectoryManager.h" #include "CiftiConnectivityMatrixParcelFile.h" #include "CiftiScalarDataSeriesFile.h" #include "ClippingPlanesDialog.h" #include "CursorDisplayScoped.h" #include "CursorManager.h" #include "CustomViewDialog.h" #include "DataFileException.h" #include "DataToolTipsManager.h" #include "ElapsedTimer.h" #include "EventAlertUser.h" #include "EventAnnotationGetDrawnInWindow.h" #include "EventBrowserTabGet.h" #include "EventBrowserTabGetAll.h" #include "EventBrowserWindowNew.h" #include "EventShowDataFileReadWarningsDialog.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventHelpViewerDisplay.h" #include "EventIdentificationHighlightLocation.h" #include "EventMacDockMenuUpdate.h" #include "EventManager.h" #include "EventMapYokingSelectMap.h" #include "EventModelGetAll.h" #include "EventOperatingSystemRequestOpenDataFile.h" #include "EventOverlaySettingsEditorDialogRequest.h" #include "EventPaletteColorMappingEditorDialogRequest.h" #include "EventProgressUpdate.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUpdateInformationWindows.h" #include "EventUserInterfaceUpdate.h" #include "FociPropertiesEditorDialog.h" #include "GapsAndMarginsDialog.h" #include "HelpViewerDialog.h" #include "IdentifiedItemNode.h" #include "IdentifiedItemVoxel.h" #include "IdentificationManager.h" #include "IdentificationStringBuilder.h" #include "IdentifyBrainordinateDialog.h" #include "ImageFile.h" #include "ImageCaptureDialog.h" #include "InformationDisplayDialog.h" #include "MetricDynamicConnectivityFile.h" #include "ModelChartTwo.h" #include "OverlaySettingsEditorDialog.h" #include "MacDockMenu.h" #include "MovieDialog.h" #include "MovieRecordingDialog.h" #include "PaletteColorMappingEditorDialog.h" #include "PreferencesDialog.h" #include "Scene.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneDialog.h" #include "SceneFile.h" #include "SceneWindowGeometry.h" #include "SelectionManager.h" #include "SelectionItemChartMatrix.h" #include "SelectionItemChartTwoMatrix.h" #include "SelectionItemCiftiConnectivityMatrixRowColumn.h" #include "SelectionItemSurfaceNode.h" #include "SelectionItemSurfaceNodeIdentificationSymbol.h" #include "SelectionItemVoxel.h" #include "SelectionItemVoxelIdentificationSymbol.h" #include "SessionManager.h" #include "SpecFile.h" #include "SpecFileManagementDialog.h" #include "SurfacePropertiesEditorDialog.h" #include "Surface.h" #include "TileTabsConfigurationDialog.h" #include "VolumeDynamicConnectivityFile.h" #include "VolumeMappableInterface.h" #include "VolumePropertiesEditorDialog.h" #include "WbMacroCustomOperationManager.h" #include "WbMacroHelper.h" #include "WuQMessageBox.h" #include "WuQMacroManager.h" #include "WuQMacroWidgetTypeEnum.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" #include "CaretAssert.h" using namespace caret; /** * \defgroup GuiQt */ /** * \class caret::GuiManager * \brief Top level class for passing events to Gui widgets belonging to workbench window * \ingroup GuiQt */ /** * Constructor. * @param parent * Parent of this object. */ GuiManager::GuiManager(QObject* parent) : QObject(parent) { /* * This constructor should be called only once. * When the first instance of GuiManager is created, * singletonGuiManager will be NULL. */ CaretAssertMessage((GuiManager::singletonGuiManager == NULL), "There should never be more than one instance of GuiManager."); } /** * Initialize the GUI manager. * * NOTE: This method is NOT called from the constructor. * If there are problems loading some of the images, there will * be calls to GuiManager::get() which results in recursive calls. */ void GuiManager::initializeGuiManager() { this->allowBrowserWindowsToCloseWithoutConfirmation = false; m_bugReportDialog = NULL; m_clippingPlanesDialog = NULL; m_customViewDialog = NULL; m_gapsAndMarginsDialog = NULL; this->imageCaptureDialog = NULL; this->movieDialog = NULL; m_movieRecordingDialog = NULL; m_informationDisplayDialog = NULL; m_identifyBrainordinateDialog = NULL; this->preferencesDialog = NULL; this->connectomeDatabaseWebView = NULL; m_helpViewerDialog = NULL; m_paletteColorMappingEditor = NULL; m_chartTwoLineSeriesHistoryDialog = NULL; this->sceneDialog = NULL; m_surfacePropertiesEditorDialog = NULL; m_volumePropertiesEditorDialog = NULL; m_tileTabsConfigurationDialog = NULL; this->cursorManager = new CursorManager(); /* * When running macro commands, some object may be child * of GuiManager and not found when searching a window * for children objects */ WuQMacroWidgetTypeEnum::addWidgetClassNameAlias("QTabWidget", "caret::WuQTabWidgetWithSizeHint"); WuQMacroWidgetTypeEnum::addWidgetClassNameAlias("QTabBar", "caret::WuQTabBar"); WuQMacroManager::instance()->addParentObject(this); WuQMacroManager::instance()->setMacroHelper(new WbMacroHelper(this)); WuQMacroManager::instance()->setCustomCommandManager(new WbMacroCustomOperationManager()); /* * Windows vector never changes size */ m_brainBrowserWindows.resize(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, NULL); /* * Information window. */ QIcon infoDisplayIcon; const bool infoDisplayIconValid = WuQtUtilities::loadIcon(":/ToolBar/info.png", infoDisplayIcon); m_informationDisplayDialogEnabledAction = WuQtUtilities::createAction("Information...", "Enables display of the Information Window\n" "when new information is available", this, this, SLOT(showHideInfoWindowSelected(bool))); if (infoDisplayIconValid) { m_informationDisplayDialogEnabledAction->setIcon(infoDisplayIcon); m_informationDisplayDialogEnabledAction->setIconVisibleInMenu(false); } else { m_informationDisplayDialogEnabledAction->setIconText("Info"); } m_informationDisplayDialogEnabledAction->blockSignals(true); m_informationDisplayDialogEnabledAction->setCheckable(true); m_informationDisplayDialogEnabledAction->setChecked(true); this->showHideInfoWindowSelected(m_informationDisplayDialogEnabledAction->isChecked()); m_informationDisplayDialogEnabledAction->setIconText("Info"); m_informationDisplayDialogEnabledAction->blockSignals(false); m_informationDisplayDialogEnabledAction->setObjectName("ToolBar:ShowInformationWindow"); WuQMacroManager::instance()->addMacroSupportToObject(m_informationDisplayDialogEnabledAction, "Display information window"); /* * Identify brainordinate window */ QIcon identifyDisplayIcon; const bool identifyDisplayIconValid = WuQtUtilities::loadIcon(":/ToolBar/identify.png", identifyDisplayIcon); m_identifyBrainordinateDialogEnabledAction = WuQtUtilities::createAction("Identify...", "Enables display of the Identify Brainordinate Window", this, this, SLOT(showIdentifyBrainordinateDialogActionToggled(bool))); if (identifyDisplayIconValid) { m_identifyBrainordinateDialogEnabledAction->setIcon(identifyDisplayIcon); m_identifyBrainordinateDialogEnabledAction->setIconVisibleInMenu(false); } else { m_identifyBrainordinateDialogEnabledAction->setIconText("ID"); } m_identifyBrainordinateDialogEnabledAction->blockSignals(true); m_identifyBrainordinateDialogEnabledAction->setCheckable(true); m_identifyBrainordinateDialogEnabledAction->setChecked(false); m_identifyBrainordinateDialogEnabledAction->blockSignals(false); m_identifyBrainordinateDialogEnabledAction->setObjectName("ToolBar:ShowIdentifyBrainordinateWindow"); WuQMacroManager::instance()->addMacroSupportToObject(m_identifyBrainordinateDialogEnabledAction, "Display Identify Brainordinate Window"); /* * Scene dialog action */ m_sceneDialogDisplayAction = new QAction("Scenes...", this); QObject::connect(m_sceneDialogDisplayAction, &QAction::triggered, this, &GuiManager::sceneDialogDisplayActionTriggered); QIcon clapBoardIcon; const bool clapBoardIconValid = WuQtUtilities::loadIcon(":/ToolBar/clapboard.png", clapBoardIcon); if (clapBoardIconValid) { m_sceneDialogDisplayAction->setIcon(clapBoardIcon); m_sceneDialogDisplayAction->setIconVisibleInMenu(false); } else { m_sceneDialogDisplayAction->setIconText("Scenes"); } m_sceneDialogDisplayAction->blockSignals(true); m_sceneDialogDisplayAction->setCheckable(false); m_sceneDialogDisplayAction->blockSignals(false); m_sceneDialogDisplayAction->setObjectName("ToolBar:ShowScenesWindow"); m_sceneDialogDisplayAction->setToolTip("Show the scenes window"); WuQMacroManager::instance()->addMacroSupportToObject(m_sceneDialogDisplayAction, "Display Scene Dialog"); /* * Help dialog action */ m_helpViewerDialogDisplayAction = WuQtUtilities::createAction("Workbench Help...", "Show/Hide the Help Window", QKeySequence::HelpContents, this, this, SLOT(showHelpDialogActionToggled(bool))); QIcon helpIcon; const bool helpIconValid = WuQtUtilities::loadIcon(":/ToolBar/help.png", helpIcon); if (helpIconValid) { m_helpViewerDialogDisplayAction->setIcon(helpIcon); m_helpViewerDialogDisplayAction->setIconVisibleInMenu(false); } else { m_helpViewerDialogDisplayAction->setIconText("?"); } m_helpViewerDialogDisplayAction->blockSignals(true); m_helpViewerDialogDisplayAction->setCheckable(true); m_helpViewerDialogDisplayAction->setChecked(false); m_helpViewerDialogDisplayAction->blockSignals(false); m_helpViewerDialogDisplayAction->setObjectName("ToolBar:ShowHelpWindow"); WuQMacroManager::instance()->addMacroSupportToObject(m_helpViewerDialogDisplayAction, "Display Help Dialog"); /* * Data tooltip action is created when requested by a toolbar */ m_dataToolTipsEnabledAction = NULL; EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ALERT_USER); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_GET_DRAWN_IN_WINDOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_NEW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_HELP_VIEWER_DISPLAY); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MAC_DOCK_MENU_UPDATE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_OVERLAY_SETTINGS_EDITOR_SHOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_PALETTE_COLOR_MAPPING_EDITOR_SHOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_SHOW_FILE_DATA_READ_WARNING_DIALOG); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_UPDATE_INFORMATION_WINDOWS); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); } /** * Destructor. */ GuiManager::~GuiManager() { EventManager::get()->removeAllEventsFromListener(this); delete this->cursorManager; if (this->connectomeDatabaseWebView != NULL) { CaretAssertMessage(0, "Need to uncomment out line below if webkit is renabled"); /* delete this->connectomeDatabaseWebView; */ } FociPropertiesEditorDialog::deleteStaticMembers(); for (std::set::iterator iter = m_parentlessNonModalDialogs.begin(); iter != m_parentlessNonModalDialogs.end(); iter++) { QWidget* w = *iter; delete w; } m_parentlessNonModalDialogs.clear(); } /** * Get the GUI Manager. */ GuiManager* GuiManager::get() { CaretAssertMessage((GuiManager::singletonGuiManager != NULL), "GuiManager::singletonGuiManager has not been created. Must call GuiManager::createGuiManager()"); return GuiManager::singletonGuiManager; } /* * Create the singleton GUI Manager. */ void GuiManager::createGuiManager() { CaretAssertMessage((GuiManager::singletonGuiManager == NULL), "GUI manager has already been created."); GuiManager::singletonGuiManager = new GuiManager(); GuiManager::singletonGuiManager->initializeGuiManager(); WuQtUtilities::sendListOfResourcesToCaretLogger(); } /* * Delete the singleton GUI Manager. */ void GuiManager::deleteGuiManager() { CaretAssertMessage((GuiManager::singletonGuiManager != NULL), "GUI manager does not exist, cannot delete it."); delete GuiManager::singletonGuiManager; GuiManager::singletonGuiManager = NULL; } /** * Beep to alert the user. */ void GuiManager::beep() { QApplication::beep(); } /** * Send an event to update the user interface */ void GuiManager::updateUserInterface() { EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** * Send an event to update all graphics windows */ void GuiManager::updateGraphicsAllWindows() { EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Send an event to update one graphics window */ void GuiManager::updateGraphicsOneWindow(const int32_t windowIndex) { EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(windowIndex).getPointer()); } /** * Send an event to update surface coloring */ void GuiManager::updateSurfaceColoring() { EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); } /** * @return The brain. */ Brain* GuiManager::getBrain() const { return SessionManager::get()->getBrain(0); } /** * See if a brain browser window can be closed. If there is only * one brain browser window, the user will be warned that any * changes to files will be lost and the application will exit. * If there is more than one brain browser window open and the * window being closed contains more than one tab, the user will * be warned. * * @param brainBrowserWindow * Brain browser window that will be closed. * @param numberOfOpenTabs * Number of tabs in window. * @return * True if window should be closed, else false. */ bool GuiManager::allowBrainBrowserWindowToClose(BrainBrowserWindow* brainBrowserWindow, const int32_t numberOfOpenTabs) { bool isBrowserWindowAllowedToClose = false; if (this->allowBrowserWindowsToCloseWithoutConfirmation) { isBrowserWindowAllowedToClose = true; } else { if (this->getNumberOfOpenBrainBrowserWindows() > 1) { /* * Warn if multiple tabs in window */ if (numberOfOpenTabs > 1) { QString tabMessage = QString::number(numberOfOpenTabs) + " tabs are open."; isBrowserWindowAllowedToClose = WuQMessageBox::warningCloseCancel(brainBrowserWindow, "Are you sure you want to close this window?", tabMessage); } else { isBrowserWindowAllowedToClose = true; } } else { isBrowserWindowAllowedToClose = this->exitProgram(brainBrowserWindow); } } if (isBrowserWindowAllowedToClose) { for (int32_t i = 0; i < static_cast(m_brainBrowserWindows.size()); i++) { if (m_brainBrowserWindows[i] == brainBrowserWindow) { m_brainBrowserWindows[i] = NULL; // must set to NULL BEFORE reparenting non-modal dialogs so they dont' see it this->reparentNonModalDialogs(brainBrowserWindow); } } EventManager::get()->sendEvent(EventMacDockMenuUpdate().getPointer()); } return isBrowserWindowAllowedToClose; } /** * Get the number of brain browser windows. * * @return Number of brain browser windows that are valid. */ int32_t GuiManager::getNumberOfOpenBrainBrowserWindows() const { int32_t numberOfWindows = 0; for (int32_t i = 0; i < static_cast(m_brainBrowserWindows.size()); i++) { if (m_brainBrowserWindows[i] != NULL) { numberOfWindows++; } } return numberOfWindows; } /** * Get all of the brain browser windows. * * @return * Vector containing all open brain browser windows. */ std::vector GuiManager::getAllOpenBrainBrowserWindows() const { std::vector windows; int32_t numWindows = static_cast(m_brainBrowserWindows.size()); for (int32_t i = 0; i < numWindows; i++) { if (m_brainBrowserWindows[i] != NULL) { windows.push_back(m_brainBrowserWindows[i]); } } return windows; } /** * Get all of the brain browser window indices * * @return * Vector containing all open brain browser window indices. */ std::vector GuiManager::getAllOpenBrainBrowserWindowIndices() const { std::vector windowIndices; int32_t numWindows = static_cast(m_brainBrowserWindows.size()); for (int32_t i = 0; i < numWindows; i++) { if (m_brainBrowserWindows[i] != NULL) { windowIndices.push_back(i); } } return windowIndices; } /** * @return Return the active browser window. If no browser window is active, * the browser window with the lowest index is returned. If no browser * window is open (which likely should never occur), NULL is returned. * * To verify that the returned window was the active window, call its * "isActiveWindow()" method. */ BrainBrowserWindow* GuiManager::getActiveBrowserWindow() const { BrainBrowserWindow* firstWindowFound = NULL; int32_t numWindows = static_cast(m_brainBrowserWindows.size()); for (int32_t i = 0; i < numWindows; i++) { BrainBrowserWindow* bbw = m_brainBrowserWindows[i]; if (bbw != NULL) { if (firstWindowFound == NULL) { firstWindowFound = bbw; } if (bbw->isActiveWindow()) { return bbw; } } } return firstWindowFound; } /** * Get the brain browser window with the given window index. * Note that as browser windows are opened or closed, a window's * index NEVER changes. Thus, a NULL value may be returned for * a window index referring to a window that was closed. * * @param browserWindowIndex * Index of the window. * @return * Pointer to window at given index or NULL in cases where * the window was closed. */ BrainBrowserWindow* GuiManager::getBrowserWindowByWindowIndex(const int32_t browserWindowIndex) { if ((browserWindowIndex >= 0) && (browserWindowIndex < static_cast(m_brainBrowserWindows.size()))) { return m_brainBrowserWindows[browserWindowIndex]; } return NULL; } /** * Create a new BrainBrowser Window. * @param parent * Optional parent that is used only for window placement. * @param useWindowIndex * Create the new window in this index if this index is valid * @param browserTabContent * Optional tab for initial windwo tab. * @param createDefaultTabs * If true, create the default tabs in the new window. * @param errorMessageOut * Contains message if window could not be created. * @return * Pointer to new window or NULL if unable to create a window. */ BrainBrowserWindow* GuiManager::newBrainBrowserWindow(QWidget* parent, const int32_t useWindowIndex, BrowserTabContent* browserTabContent, const bool createDefaultTabs, AString& errorMessageOut) { errorMessageOut.clear(); /* * If no tabs can be created, do not create a new window. */ EventBrowserTabGetAll getAllTabs; EventManager::get()->sendEvent(getAllTabs.getPointer()); if (getAllTabs.getNumberOfBrowserTabs() == BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS) { errorMessageOut = ("All browser tabs are being used. " "Close some browser tabs and then try creating a new window."); return NULL; } EventManager::get()->blockEvent(EventTypeEnum::EVENT_ANNOTATION_COLOR_BAR_GET, true); int32_t windowIndex = -1; /* * Is window required to be at a specific index? */ int32_t numWindows = static_cast(m_brainBrowserWindows.size()); if (useWindowIndex >= 0) { CaretAssertVectorIndex(m_brainBrowserWindows, useWindowIndex); windowIndex = useWindowIndex; } else { /* * Use first available window */ for (int32_t i = 0; i < numWindows; i++) { if (m_brainBrowserWindows[i] == NULL) { windowIndex = i; break; } } } if (windowIndex < 0) { /* * No windows are available */ errorMessageOut = ("Unable to create a new window as the maximum number of windows (" + AString::number(BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS) + ") are currently open."); return NULL; } BrainBrowserWindow* bbw = NULL; BrainBrowserWindow::CreateDefaultTabsMode tabsMode = (createDefaultTabs ? BrainBrowserWindow::CREATE_DEFAULT_TABS_YES : BrainBrowserWindow::CREATE_DEFAULT_TABS_NO); if (m_brainBrowserWindows[windowIndex] != NULL) { bbw = m_brainBrowserWindows[windowIndex]; } else { bbw = new BrainBrowserWindow(windowIndex, browserTabContent, tabsMode); m_brainBrowserWindows[windowIndex] = bbw; } /* * Did OpenGL Context sharing fail? */ if ( ! bbw->isOpenGLContextSharingValid()) { delete bbw; errorMessageOut = ("There has been a failure when creating an OpenGL Widget " "with a \"shared context\" for the new window. " "This may be caused by a limitation of the OpenGL graphics or the " "windowing system on your computer.\n" "\n" "Please restart wb_view and report this problem as a bug using " "Help Menu --> Report a Workbench Bug...\n" "\n" "You will be able to continue using wb_view but you will not " "be able to have more than one window open."); if (windowIndex >= 0) { m_brainBrowserWindows[windowIndex] = NULL; } return NULL; } if (parent != NULL) { WuQtUtilities::moveWindowToOffset(parent, bbw, 20, 20); } bbw->show(); bbw->resetGraphicsWidgetMinimumSize(); EventManager::get()->blockEvent(EventTypeEnum::EVENT_ANNOTATION_COLOR_BAR_GET, false); return bbw; } /** * Test for modified data files. * * @param testModifiedMode * Mode of testing for modified files. * @param textMessageOut * Message displayed at top of dialog. * @param modifiedFilesMessageOut * If there are any modified files, this will contain information * about the modified files. * @return * True if there are modified files and the warning message is valid, * else false. */ bool GuiManager::testForModifiedFiles(const TestModifiedMode testModifiedMode, AString& textMessageOut, AString& modifiedFilesMessageOut) const { textMessageOut.clear(); modifiedFilesMessageOut.clear(); /* * Exclude all * Connectivity Files */ std::vector dataFileTypesToExclude; dataFileTypesToExclude.push_back(DataFileTypeEnum::CONNECTIVITY_DENSE); dataFileTypesToExclude.push_back(DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC); dataFileTypesToExclude.push_back(DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY); dataFileTypesToExclude.push_back(DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY); dataFileTypesToExclude.push_back(DataFileTypeEnum::METRIC_DYNAMIC); dataFileTypesToExclude.push_back(DataFileTypeEnum::VOLUME_DYNAMIC); switch (testModifiedMode) { case TEST_FOR_MODIFIED_FILES_MODE_FOR_EXIT: break; case TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD: case TEST_FOR_MODIFIED_FILES_PALETTE_ONLY_MODE_FOR_SCENE_ADD: dataFileTypesToExclude.push_back(DataFileTypeEnum::SCENE); dataFileTypesToExclude.push_back(DataFileTypeEnum::SPECIFICATION); break; case TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_SHOW: dataFileTypesToExclude.push_back(DataFileTypeEnum::SCENE); break; } /* * Are files modified? */ std::vector allModifiedDataFiles; getBrain()->getAllModifiedFiles(dataFileTypesToExclude, allModifiedDataFiles); std::vector modifiedDataFiles; std::vector paletteModifiedDataFiles; for (std::vector::iterator allModFilesIter = allModifiedDataFiles.begin(); allModFilesIter != allModifiedDataFiles.end(); allModFilesIter++) { CaretDataFile* file = *allModFilesIter; CaretAssert(file); switch (testModifiedMode) { case TEST_FOR_MODIFIED_FILES_MODE_FOR_EXIT: case TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_SHOW: { /* * Show both data modified and palette modified */ CaretMappableDataFile* mappableDataFile = dynamic_cast(file); bool paletteOnlyModFlag = false; if (mappableDataFile != NULL) { if (mappableDataFile->isModifiedPaletteColorMapping()) { if ( ! mappableDataFile->isModifiedExcludingPaletteColorMapping()) { paletteOnlyModFlag = true; } } } if (paletteOnlyModFlag) { paletteModifiedDataFiles.push_back(file); } else { modifiedDataFiles.push_back(file); } } break; case TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD: { /* * Is modification data but NOT palette */ CaretMappableDataFile* mappableDataFile = dynamic_cast(file); if (mappableDataFile != NULL) { if ( ! mappableDataFile->isModifiedPaletteColorMapping()) { if (mappableDataFile->isModifiedExcludingPaletteColorMapping()) { modifiedDataFiles.push_back(file); } } } else { modifiedDataFiles.push_back(file); } break; } case TEST_FOR_MODIFIED_FILES_PALETTE_ONLY_MODE_FOR_SCENE_ADD: { /* * Is modification just the palette color mapping? */ CaretMappableDataFile* mappableDataFile = dynamic_cast(file); bool paletteOnlyModFlag = false; if (mappableDataFile != NULL) { if (mappableDataFile->isModifiedPaletteColorMapping()) { if ( ! mappableDataFile->isModifiedExcludingPaletteColorMapping()) { paletteOnlyModFlag = true; } } } if (paletteOnlyModFlag) { paletteModifiedDataFiles.push_back(file); } } break; } } const int32_t modFileCount = static_cast(modifiedDataFiles.size()); const int32_t paletteModFileCount = static_cast(paletteModifiedDataFiles.size()); /* * Are there scene annotations ? */ const CaretDataFile* sceneAnnotationFile = getBrain()->getSceneAnnotationFile(); bool sceneAnnotationsModifiedFlag = sceneAnnotationFile->isModified(); switch (testModifiedMode) { case TEST_FOR_MODIFIED_FILES_MODE_FOR_EXIT: break; case TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD: case TEST_FOR_MODIFIED_FILES_PALETTE_ONLY_MODE_FOR_SCENE_ADD: /* * Do not need to notify about modified scene annotations * since scene annotations are saved to the scene */ sceneAnnotationsModifiedFlag = false; break; case TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_SHOW: break; } if ((modFileCount > 0) || sceneAnnotationsModifiedFlag || paletteModFileCount > 0) { /* * Display dialog allowing user to save files (goes to Save/Manage * Files dialog), exit without saving, or cancel. */ AString paletteModifiedMessage("These file(s) contain modified palette color mapping " "(this may result from loading scenes that contained modified palette color " "mapping and this modified status is needed if scenes " "are added or replaced): "); switch (testModifiedMode) { case TEST_FOR_MODIFIED_FILES_MODE_FOR_EXIT: textMessageOut = "Do you want to save changes you made to these files?"; break; case TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD: case TEST_FOR_MODIFIED_FILES_PALETTE_ONLY_MODE_FOR_SCENE_ADD: textMessageOut = "Do you want to continue creating the scene?"; paletteModifiedMessage = ("These file(s) contain modified palette color mapping " "AND \"Add modified palette color mapping to scene\" " "is NOT checked on the Create New Scene Dialog:"); break; case TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_SHOW: textMessageOut = "Do you want to continue showing the scene?"; break; } AString infoTextMsg(""); if (sceneAnnotationsModifiedFlag || (modFileCount > 0)) { infoTextMsg.appendWithNewLine("These file(s) contain modified data:\n"); infoTextMsg.appendWithNewLine("

      "); if (sceneAnnotationsModifiedFlag) { infoTextMsg.appendWithNewLine("
    • Scene Annotations (must be saved to a scene)"); } if (modFileCount > 0) { for (std::vector::iterator iter = modifiedDataFiles.begin(); iter != modifiedDataFiles.end(); iter++) { const CaretDataFile* cdf = *iter; infoTextMsg.appendWithNewLine("
    • " + cdf->getFileNameNoPath()); } } infoTextMsg.appendWithNewLine("
    "); } if (paletteModFileCount > 0) { infoTextMsg.appendWithNewLine(paletteModifiedMessage); infoTextMsg.appendWithNewLine("
      "); for (std::vector::iterator iter = paletteModifiedDataFiles.begin(); iter != paletteModifiedDataFiles.end(); iter++) { const CaretDataFile* cdf = *iter; infoTextMsg.appendWithNewLine("
    • " + cdf->getFileNameNoPath()); } infoTextMsg.appendWithNewLine("
    "); } infoTextMsg.appendWithNewLine(""); modifiedFilesMessageOut = infoTextMsg; return true; } return false; } /** * Exit the program. * @param * Parent over which dialogs are displayed for saving/verifying. * return * true if application should exit, else false. */ bool GuiManager::exitProgram(BrainBrowserWindow* parent) { bool okToExit = false; AString textMessage; AString modifiedFilesMessage; if (testForModifiedFiles(TEST_FOR_MODIFIED_FILES_MODE_FOR_EXIT, textMessage, modifiedFilesMessage)) { modifiedFilesMessage.appendWithNewLine(""); QMessageBox quitDialog(QMessageBox::Warning, "Exit Workbench", textMessage, QMessageBox::NoButton, parent); quitDialog.setInformativeText(modifiedFilesMessage); QPushButton* saveButton = quitDialog.addButton("Save...", QMessageBox::AcceptRole); saveButton->setToolTip("Display manage files window to save files"); QPushButton* dontSaveButton = quitDialog.addButton("Don't Save", QMessageBox::DestructiveRole); dontSaveButton->setToolTip("Do not save changes and exit."); QPushButton* cancelButton = quitDialog.addButton("Cancel", QMessageBox::RejectRole); quitDialog.setDefaultButton(saveButton); quitDialog.setEscapeButton(cancelButton); quitDialog.exec(); const QAbstractButton* clickedButton = quitDialog.clickedButton(); if (clickedButton == saveButton) { if (SpecFileManagementDialog::runSaveFilesDialogWhileQuittingWorkbench(this->getBrain(), parent)) { okToExit = true; } } else if (clickedButton == dontSaveButton) { okToExit = true; } else if (clickedButton == cancelButton) { /* nothing */ } else { CaretAssert(0); } } else { const AString textMsg("Exit Workbench?"); QMessageBox quitDialog(QMessageBox::Warning, "Exit Workbench", textMsg, QMessageBox::NoButton, parent); if (SceneDialog::isInformUserAboutScenesOnExit()) { const AString infoTextMsg("Would you like to save your Workbench windows in scene file " "so you can easily pick up where you left off?" "

    " "Click the Show Details button for " "more information."); const AString detailTextMsg("Scenes allow one to regenerate exactly what is displayed in " "Workbench. This can be useful in these and other situations:" "\n\n" " * During manuscript preparation to restore Workbench to match " "a previously generated figure (image capture)." "\n\n" " * When returning to this dataset for further analysis." "\n\n" " * When sharing data sets with others to provide a particular " "view of a surface/volume with desired data (overlay and feature) " "selections."); quitDialog.setInformativeText(infoTextMsg); quitDialog.setDetailedText(detailTextMsg); } QPushButton* exitButton = quitDialog.addButton("Exit", QMessageBox::AcceptRole); QPushButton* cancelButton = quitDialog.addButton("Cancel", QMessageBox::RejectRole); quitDialog.setDefaultButton(exitButton); quitDialog.setEscapeButton(cancelButton); quitDialog.exec(); const QAbstractButton* clickedButton = quitDialog.clickedButton(); if (clickedButton == exitButton) { okToExit = true; } else if (clickedButton == cancelButton) { /* Nothing */ } else { CaretAssert(0); } } if (okToExit) { /* * While resetting the brain is not absolutely necessary, * some files may use GraphicsOpenGLBufferObject that are * created by BrainOpenGL. Resetting the brain will close * all files which results in the GraphicsOpenGLBufferObject * being released. If the brain is not reset, the files * are deleted after BrainOpenGL so BrainOpenGL will report * that GraphicsOpenGLBufferObjects were not deleted. */ get()->getBrain()->resetBrain(); std::vector bws = this->getAllOpenBrainBrowserWindows(); for (int i = 0; i < static_cast(bws.size()); i++) { bws[i]->deleteLater(); } QCoreApplication::instance()->quit(); } return okToExit; } /** * Show the Open Spec File Dialog with the given spec file. * * @param specFile * SpecFile displayed in the dialog. * @param browserWindow * Window on which dialog is displayed. * @return * True if user opened spec file, else false. */ bool GuiManager::processShowOpenSpecFileDialog(SpecFile* specFile, BrainBrowserWindow* browserWindow) { return SpecFileManagementDialog::runOpenSpecFileDialog(getBrain(), specFile, browserWindow); } /** * Show the Save/Manage Files Dialog. * * @param browserWindow * Window on which dialog is displayed. */ void GuiManager::processShowSaveManageFilesDialog(BrainBrowserWindow* browserWindow) { SpecFileManagementDialog::runManageFilesDialog(getBrain(), browserWindow); } /** * Get the model displayed in the given browser window. * @param browserWindowIndex * Index of browser window. * @return * Model in the browser window. May be NULL if no data loaded. */ Model* GuiManager::getModelInBrowserWindow(const int32_t browserWindowIndex) { BrowserTabContent* browserTabContent = getBrowserTabContentForBrowserWindow(browserWindowIndex, true); Model* model = NULL; if (browserTabContent != NULL) { model = browserTabContent->getModelForDisplay(); } return model; } /** * Get the browser tab content in a browser window. * @param browserWindowIndex * Index of browser window. * @param allowInvalidBrowserWindowIndex * In some instance, such as GUI construction or destruction, the window is not * fully created or deleted, thus "this->brainBrowserWindows" is invalid for * the given index. If this parameter is true, NULL will be * returned in this case. * @return * Browser tab content in the browser window. Value may be NULL * is allowInvalidBrowserWindowIndex is true */ BrowserTabContent* GuiManager::getBrowserTabContentForBrowserWindow(const int32_t browserWindowIndex, const bool allowInvalidBrowserWindowIndex) { if (allowInvalidBrowserWindowIndex) { if (browserWindowIndex >= static_cast(m_brainBrowserWindows.size())) { return NULL; } } CaretAssertVectorIndex(m_brainBrowserWindows, browserWindowIndex); BrainBrowserWindow* browserWindow = m_brainBrowserWindows[browserWindowIndex]; if (allowInvalidBrowserWindowIndex) { if (browserWindow == NULL) { return NULL; } } CaretAssert(browserWindow); BrowserTabContent* tabContent = browserWindow->getBrowserTabContent(); return tabContent; } /** * Called when bring all windows to front is selected. */ void GuiManager::processBringAllWindowsToFront() { for (int32_t i = 0; i < static_cast(m_brainBrowserWindows.size()); i++) { if (m_brainBrowserWindows[i] != NULL) { m_brainBrowserWindows[i]->show(); m_brainBrowserWindows[i]->activateWindow(); } } for (std::set::iterator iter = this->nonModalDialogs.begin(); iter != this->nonModalDialogs.end(); iter++) { QWidget* w = *iter; if (w->isVisible()) { w->raise(); } } for (std::set::iterator iter = m_parentlessNonModalDialogs.begin(); iter != m_parentlessNonModalDialogs.end(); iter++) { QWidget* w = *iter; if (w->isVisible()) { w->raise(); } } std::vector macroDialogs = WuQMacroManager::instance()->getNonModalDialogs(); for (auto md : macroDialogs) { if (md->isVisible()) { md->raise(); } } } /** * Called to tile the windows (arrange browser windows in a grid). */ void GuiManager::processTileWindows() { std::vector windows = getAllOpenBrainBrowserWindows(); const int32_t numWindows = static_cast(windows.size()); if (numWindows <= 1) { return; } QDesktopWidget* dw = QApplication::desktop(); const int32_t numScreens = dw->screenCount(); const int32_t windowsPerScreen = std::max(numWindows / numScreens, 1); /** * Determine the number of rows and columns for the montage. * Since screen width typically exceeds height, always have * columns greater than or equal to rows. */ int32_t numRows = (int)std::sqrt((double)windowsPerScreen); int32_t numCols = numRows; int32_t row2 = numRows * numRows; if (row2 < numWindows) { numCols++; } if ((numRows * numCols) < numWindows) { numRows++; } AString windowInfo("Tiled Windows"); /* * Arrange models left-to-right and top-to-bottom. * Note that origin is top-left corner. */ int32_t windowIndex = 0; for (int32_t iScreen = 0; iScreen < numScreens; iScreen++) { const QRect rect = dw->availableGeometry(iScreen); const int screenX = rect.x(); const int screenY = rect.y(); const int screenWidth = rect.width(); const int screenHeight = rect.height(); const int32_t windowWidth = screenWidth / numCols; const int32_t windowHeight = screenHeight / numRows; int32_t windowX = 0; int32_t windowY = screenY; for (int32_t iRow = 0; iRow < numRows; iRow++) { windowX = screenX; for (int32_t iCol = 0; iCol < numCols; iCol++) { windows[windowIndex]->setGeometry(windowX, windowY, windowWidth, windowHeight); windowX += windowWidth; QString info = (" Window: " + windows[windowIndex]->windowTitle() + " screen/x/y/w/h (" + QString::number(iScreen) + ", " + QString::number(windowX) + ", " + QString::number(windowY) + ", " + QString::number(windowWidth) + ", " + QString::number(windowHeight) + ")"); windowInfo.appendWithNewLine(info); windowIndex++; if (windowIndex >= numWindows) { /* * No more windows to place. * Containing loops would cause a crash. */ CaretLogFine(windowInfo); return; } } windowY += windowHeight; } } CaretLogFine(windowInfo); } /** * Receive events from the event manager. * * @param event * Event sent by event manager. */ void GuiManager::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_ALERT_USER) { EventAlertUser* alertUserEvent = dynamic_cast(event); const AString message = alertUserEvent->getMessage(); BrainBrowserWindow* bbw = getActiveBrowserWindow(); CaretAssert(bbw); WuQMessageBox::errorOk(bbw, message); } else if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_GET_DRAWN_IN_WINDOW) { EventAnnotationGetDrawnInWindow* annGetEvent = dynamic_cast(event); CaretAssert(annGetEvent); const int32_t windowIndex = annGetEvent->getWindowIndex(); Brain* brain = getBrain(); std::vector allAnnotationFiles; brain->getAllAnnotationFilesIncludingSceneAnnotationFile(allAnnotationFiles); /* * Clear "drawn in window status" for all annotations */ for (std::vector::iterator fileIter = allAnnotationFiles.begin(); fileIter != allAnnotationFiles.end(); fileIter++) { (*fileIter)->clearAllAnnotationsDrawnInWindowStatus(); } /* * Draw the given window */ EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(windowIndex).getPointer()); /* * Find annotations that were drawn in the given window. */ for (std::vector::iterator fileIter = allAnnotationFiles.begin(); fileIter != allAnnotationFiles.end(); fileIter++) { std::vector annotations; (*fileIter)->getAllAnnotationWithDrawnInWindowStatusSet(windowIndex, annotations); annGetEvent->addAnnotations(annotations); } } else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_NEW) { EventBrowserWindowNew* eventNewBrowser = dynamic_cast(event); CaretAssert(eventNewBrowser); AString errorMessage; BrainBrowserWindow* bbw = this->newBrainBrowserWindow(eventNewBrowser->getParent(), -1, /* allow any window index */ eventNewBrowser->getBrowserTabContent(), true, errorMessage); if (bbw == NULL) { eventNewBrowser->setErrorMessage(errorMessage); eventNewBrowser->setEventProcessed(); return; } eventNewBrowser->setBrowserWindowCreated(bbw); eventNewBrowser->setEventProcessed(); /* * Initialize the size of the window */ const int w = bbw->width(); const int preferredMaxHeight = (WuQtUtilities::isSmallDisplay() ? 550 : 850); const int h = std::min(bbw->height(), preferredMaxHeight); bbw->resize(w, h); EventManager::get()->sendEvent(EventMacDockMenuUpdate().getPointer()); } else if ((event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS) || (event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW)) { for (auto overlayEditor : m_overlaySettingsEditors) { overlayEditor->updateChartLinesInDialog(); } } else if (event->getEventType() == EventTypeEnum::EVENT_MAC_DOCK_MENU_UPDATE) { EventMacDockMenuUpdate* macDockMenuEvent = dynamic_cast(event); CaretAssert(event); MacDockMenu::createUpdateMacDockMenu(); macDockMenuEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_UPDATE_INFORMATION_WINDOWS) { EventUpdateInformationWindows* infoEvent = dynamic_cast(event); CaretAssert(infoEvent); bool showInfoDialog = infoEvent->isImportant(); if (showInfoDialog) { this->processShowInformationDisplayDialog(false); } infoEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_OVERLAY_SETTINGS_EDITOR_SHOW) { EventOverlaySettingsEditorDialogRequest* mapEditEvent = dynamic_cast(event); CaretAssert(mapEditEvent); const EventOverlaySettingsEditorDialogRequest::Mode mode = mapEditEvent->getMode(); const int browserWindowIndex = mapEditEvent->getBrowserWindowIndex(); CaretAssertVectorIndex(m_brainBrowserWindows, browserWindowIndex); BrainBrowserWindow* browserWindow = m_brainBrowserWindows[browserWindowIndex]; CaretAssert(browserWindow); Overlay* overlay = mapEditEvent->getOverlay(); ChartTwoOverlay* chartOverlay = mapEditEvent->getChartTwoOverlay(); switch (mode) { case EventOverlaySettingsEditorDialogRequest::MODE_OVERLAY_MAP_CHANGED: { for (std::set::iterator overlayEditorIter = m_overlaySettingsEditors.begin(); overlayEditorIter != m_overlaySettingsEditors.end(); overlayEditorIter++) { OverlaySettingsEditorDialog* med = *overlayEditorIter; med->updateIfThisOverlayIsInDialog(overlay, chartOverlay); } } break; case EventOverlaySettingsEditorDialogRequest::MODE_SHOW_EDITOR: { OverlaySettingsEditorDialog* overlayEditor = NULL; for (std::set::iterator overlayEditorIter = m_overlaySettingsEditors.begin(); overlayEditorIter != m_overlaySettingsEditors.end(); overlayEditorIter++) { OverlaySettingsEditorDialog* med = *overlayEditorIter; if (med->isDoNotReplaceSelected() == false) { overlayEditor = med; break; } } bool placeInDefaultLocation = false; if (overlayEditor == NULL) { overlayEditor = new OverlaySettingsEditorDialog(browserWindow); m_overlaySettingsEditors.insert(overlayEditor); this->addNonModalDialog(overlayEditor); placeInDefaultLocation = true; } else { if (overlayEditor->isHidden()) { placeInDefaultLocation = true; } /* * Is the overlay editor requested for a window * that is not the parent of this overlay editor? */ if (browserWindow != overlayEditor->parent()) { /* * Switch the parent of the overlay editor. * On Linux, this will cause the overlay editor * to be "brought to the front" only when its * parent is "brought to the front". * * The position must be preserved. */ const QPoint globalPos = overlayEditor->pos(); overlayEditor->setParent(browserWindow, overlayEditor->windowFlags()); overlayEditor->move(globalPos); } } overlayEditor->updateDialogContent(overlay, chartOverlay); overlayEditor->show(); overlayEditor->raise(); overlayEditor->activateWindow(); if (placeInDefaultLocation) { WuQtUtilities::moveWindowToSideOfParent(browserWindow, overlayEditor); } } break; case EventOverlaySettingsEditorDialogRequest::MODE_UPDATE_ALL: for (std::set::iterator overlayEditorIter = m_overlaySettingsEditors.begin(); overlayEditorIter != m_overlaySettingsEditors.end(); overlayEditorIter++) { OverlaySettingsEditorDialog* med = *overlayEditorIter; med->updateDialog(); } break; } mapEditEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_OPERATING_SYSTEM_REQUEST_OPEN_DATA_FILE) { EventOperatingSystemRequestOpenDataFile* openFileEvent = dynamic_cast(event); CaretAssert(openFileEvent); BrainBrowserWindow* bbw = getActiveBrowserWindow(); if (bbw != NULL) { std::vector filenamesVector; std::vector dataFileTypeVectorNotUsed; filenamesVector.push_back(openFileEvent->getDataFileName()); bbw->loadFiles(bbw, filenamesVector, dataFileTypeVectorNotUsed, BrainBrowserWindow::LOAD_SPEC_FILE_WITH_DIALOG, "", ""); } else { /* * Browser window has not yet been created. * After it is created, the file will be opened. */ m_nameOfDataFileToOpenAfterStartup = openFileEvent->getDataFileName(); } } else if (event->getEventType() == EventTypeEnum::EVENT_PALETTE_COLOR_MAPPING_EDITOR_SHOW) { EventPaletteColorMappingEditorDialogRequest* paletteEditEvent = dynamic_cast(event); CaretAssert(paletteEditEvent); BrainBrowserWindow* browserWindow = m_brainBrowserWindows[paletteEditEvent->getBrowserWindowIndex()]; CaretAssert(browserWindow); int32_t browserTabIndex = -1; BrowserTabContent* tabContent = browserWindow->getBrowserTabContent(); if (tabContent != NULL) { browserTabIndex = tabContent->getTabNumber(); } bool placeInDefaultLocation = false; if (m_paletteColorMappingEditor == NULL) { m_paletteColorMappingEditor = new PaletteColorMappingEditorDialog(browserWindow); addNonModalDialog(m_paletteColorMappingEditor); placeInDefaultLocation = true; } else if (m_paletteColorMappingEditor->isHidden()) { placeInDefaultLocation = true; } m_paletteColorMappingEditor->updateDialogContent(paletteEditEvent->getCaretMappableDataFile(), paletteEditEvent->getMapIndex(), browserTabIndex); m_paletteColorMappingEditor->show(); m_paletteColorMappingEditor->raise(); m_paletteColorMappingEditor->activateWindow(); if (placeInDefaultLocation) { WuQtUtilities::moveWindowToSideOfParent(browserWindow, m_paletteColorMappingEditor); } paletteEditEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_HELP_VIEWER_DISPLAY) { EventHelpViewerDisplay* helpEvent = dynamic_cast(event); CaretAssert(helpEvent); showHideHelpDialog(true, helpEvent->getBrainBrowserWindow()); if (m_helpViewerDialog != NULL) { m_helpViewerDialog->showHelpPageWithName(helpEvent->getHelpPageName()); } helpEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_SHOW_FILE_DATA_READ_WARNING_DIALOG) { EventShowDataFileReadWarningsDialog* warningEvent = dynamic_cast(event); CaretAssert(warningEvent); BrainBrowserWindow* bbw = getBrowserWindowByWindowIndex(warningEvent->getBrowserWindowIndex()); if (bbw == NULL) { bbw = getActiveBrowserWindow(); } CaretAssert(bbw); bbw->showDataFileReadWarningsDialog(); warningEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { if (m_movieRecordingDialog != NULL) { m_movieRecordingDialog->updateDialog(); } } } /** * Remove the tab content from all browser windows except for the given * browser windows, close the other browser windows, and then return * the tab content. * * @param browserWindow * Browser window that gets tab content from all other windows. * @param tabContents * Tab content from all other windows. */ void GuiManager::closeOtherWindowsAndReturnTheirTabContent(BrainBrowserWindow* browserWindow, std::vector& tabContents) { tabContents.clear(); const int32_t numWindows = m_brainBrowserWindows.size(); for (int32_t i = 0; i < numWindows; i++) { BrainBrowserWindow* bbw = m_brainBrowserWindows[i]; if (bbw != NULL) { if (bbw != browserWindow) { std::vector tabs; bbw->removeAndReturnAllTabs(tabs); tabContents.insert(tabContents.end(), tabs.begin(), tabs.end()); this->allowBrowserWindowsToCloseWithoutConfirmation = true; bbw->close(); /* * Should delete the windows that were closed! * When a window is closed, Qt uses 'deleteLater' * but we need them deleted now so that event listeners * are shut down since the closed windows no longer * have any content. */ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); this->allowBrowserWindowsToCloseWithoutConfirmation = false; } } } } /** * Close all but the given window. * @param browserWindow * Window that is NOT closed. */ void GuiManager::closeAllOtherWindows(BrainBrowserWindow* browserWindow) { const int32_t numWindows = m_brainBrowserWindows.size(); for (int32_t i = 0; i < numWindows; i++) { BrainBrowserWindow* bbw = m_brainBrowserWindows[i]; if (bbw != NULL) { if (bbw != browserWindow) { this->allowBrowserWindowsToCloseWithoutConfirmation = true; bbw->close(); /* * Should delete the windows that were closed! * When a window is closed, Qt uses 'deleteLater' * but we need them deleted now so that event listeners * are shut down since the closed windows no longer * have any content. */ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); this->allowBrowserWindowsToCloseWithoutConfirmation = false; } } } } /** * Reparent non-modal dialogs that may need to be reparented if the * original parent, a BrainBrowserWindow is closed in which case the * dialog is reparented to a different BrainBrowserWindow. * * @param closingBrainBrowserWindow * Browser window that is closing. */ void GuiManager::reparentNonModalDialogs(BrainBrowserWindow* closingBrainBrowserWindow) { /* * Find valid windows and use first window for reparenting */ std::set validWindows; for (auto bbw : m_brainBrowserWindows) { if ((bbw != NULL) && (bbw != closingBrainBrowserWindow)) { validWindows.insert(bbw); } } QWidget* firstBrainBrowserWindow = (validWindows.empty() ? NULL : *(validWindows.begin())); std::vector allNonModalDialogs(this->nonModalDialogs.begin(), this->nonModalDialogs.end()); std::vector macroDialogs = WuQMacroManager::instance()->getNonModalDialogs(); allNonModalDialogs.insert(allNonModalDialogs.end(), macroDialogs.begin(), macroDialogs.end()); if (firstBrainBrowserWindow != NULL) { for (auto dialog : allNonModalDialogs) { QWidget* dialogParent = dialog->parentWidget(); if (validWindows.find(dialogParent) == validWindows.end()) { const bool wasVisible = dialog->isVisible(); const QPoint globalPos = dialog->pos(); dialog->setParent(firstBrainBrowserWindow, dialog->windowFlags()); dialog->move(globalPos); if (wasVisible) { dialog->show(); } else { dialog->hide(); } } } } updateNonModalDialogs(); } /** * Update the non-modal dialogs. */ void GuiManager::updateNonModalDialogs() { for (auto dialog : this->nonModalDialogs) { WuQDialogNonModal* wuqNonModalDialog = dynamic_cast(dialog); if (wuqNonModalDialog != NULL) { wuqNonModalDialog->updateDialog(); } } WuQMacroManager::instance()->updateNonModalDialogs(); } /** * Show the surface properties editor dialog. * @param browserWindow * Browser window on which dialog is displayed. */ void GuiManager::processShowSurfacePropertiesEditorDialog(BrainBrowserWindow* browserWindow) { bool wasCreatedFlag = false; if (this->m_surfacePropertiesEditorDialog == NULL) { m_surfacePropertiesEditorDialog = new SurfacePropertiesEditorDialog(browserWindow); this->addNonModalDialog(m_surfacePropertiesEditorDialog); m_surfacePropertiesEditorDialog->setSaveWindowPositionForNextTime(true); wasCreatedFlag = true; } m_surfacePropertiesEditorDialog->showDialog(); if (wasCreatedFlag) { WuQtUtilities::moveWindowToSideOfParent(browserWindow, m_surfacePropertiesEditorDialog); } } /** * Show the volume properties editor dialog. * @param browserWindow * Browser window on which dialog is displayed. */ void GuiManager::processShowVolumePropertiesEditorDialog(BrainBrowserWindow* browserWindow) { bool wasCreatedFlag = false; if (this->m_volumePropertiesEditorDialog == NULL) { m_volumePropertiesEditorDialog = new VolumePropertiesEditorDialog(browserWindow); this->addNonModalDialog(m_volumePropertiesEditorDialog); m_volumePropertiesEditorDialog->setSaveWindowPositionForNextTime(true); wasCreatedFlag = true; } m_volumePropertiesEditorDialog->showDialog(); if (wasCreatedFlag) { WuQtUtilities::moveWindowToSideOfParent(browserWindow, m_volumePropertiesEditorDialog); } } /** * @return The action for showing/hiding the scene dialog. */ QAction* GuiManager::getSceneDialogDisplayAction() { return m_sceneDialogDisplayAction; } /** * Gets called when the scene dialog action is toggled. * * @param status * New status (true display dialog, false hide it). */ void GuiManager::sceneDialogDisplayActionTriggered(bool /*status*/) { showHideSceneDialog(true, NULL); } /** * Gets called by the scene dialog when the scene dialog is closed. * Ensures that the scene dialog display action status remains * synchronized with the displayed status of the scene dialog. */ void GuiManager::sceneDialogWasClosed() { m_sceneDialogDisplayAction->blockSignals(true); m_sceneDialogDisplayAction->blockSignals(false); } /** * Show or hide the scene dialog. * * @param status * True means show, false means hide. * @param parentBrainBrowserWindow * If this is not NULL, and the scene dialog needs to be created, * use this window as the parent and place the dialog next to this * window. */ void GuiManager::showHideSceneDialog(const bool status, BrainBrowserWindow* parentBrainBrowserWindow) { bool dialogWasCreated = false; QWidget* moveWindowParent = parentBrainBrowserWindow; if (status) { if (this->sceneDialog == NULL) { BrainBrowserWindow* sceneDialogParent = parentBrainBrowserWindow; if (sceneDialogParent == NULL) { sceneDialogParent = getActiveBrowserWindow(); } this->sceneDialog = new SceneDialog(sceneDialogParent); this->addNonModalDialog(this->sceneDialog); QObject::connect(this->sceneDialog, SIGNAL(dialogWasClosed()), this, SLOT(sceneDialogWasClosed())); dialogWasCreated = true; /* * If there was no parent dialog for placement of the scene * dialog and there is only one browser window, use the browser * for placement of the scene dialog. */ if (moveWindowParent == NULL) { if (getAllOpenBrainBrowserWindows().size() == 1) { moveWindowParent = sceneDialogParent; } } } this->sceneDialog->showDialog(); this->sceneDialog->createDefaultSceneFile(); } else { this->sceneDialog->close(); } if (dialogWasCreated) { if (moveWindowParent != NULL) { WuQtUtilities::moveWindowToSideOfParent(moveWindowParent, this->sceneDialog); } } m_sceneDialogDisplayAction->blockSignals(true); m_sceneDialogDisplayAction->blockSignals(false); } /** * Show the scene dialog. If dialog needs to be created, use the * given window as the parent. * @param browserWindowIn * Parent of scene dialog if it needs to be created. */ void GuiManager::processShowSceneDialog(BrainBrowserWindow* browserWindowIn) { showHideSceneDialog(true, browserWindowIn); } /** * Show the scene dialog and load the given scene from the given scene file. * If displaying the scene had an error, the scene dialog will remain open. * Otherwise, the scene dialog is closed. * * @param browserWindow * Parent of scene dialog if it needs to be created. * @param sceneFileIn * Scene File that contains the scene. If NULL, the scene file * containing the scene will be located and used * @param scene * Scene that is displayed. * @param showSceneDialogFlag * If true, update the scene dialog. Otherwise, load the scene * without showing the scene dialog */ void GuiManager::processShowSceneDialogAndScene(BrainBrowserWindow* browserWindow, SceneFile* sceneFileIn, Scene* scene, const bool showSceneDialogFlag) { CaretAssert(browserWindow); CaretAssert(scene); SceneFile* sceneFile(sceneFileIn); if (sceneFile == NULL) { /* * If scene file is not valid, find scene file containing the scene */ Brain* brain = getBrain(); CaretAssert(brain); const int32_t numSceneFiles = brain->getNumberOfSceneFiles(); for (int32_t i = 0; i < numSceneFiles; i++) { SceneFile* sf = brain->getSceneFile(i); CaretAssert(sf); const int32_t numScenes = sf->getNumberOfScenes(); for (int32_t j = 0; j < numScenes; j++) { if (sf->getSceneAtIndex(j) == scene) { sceneFile = sf; break; } } if (sceneFile != NULL) { break; } } if (sceneFile == NULL) { const QString msg("Cannot load scene. Unable to find scene file containing scene named \"" + scene->getName() + "\""); WuQMessageBox::errorOk(browserWindow, msg); return; } } /* * Update scene dialog if it is open or if it should be displayed */ const bool updateSceneDialogFlag(showSceneDialogFlag || (this->sceneDialog != NULL)); if (updateSceneDialogFlag) { this->sceneDialog->displayScene(sceneFile, scene); if (showSceneDialogFlag) { showHideSceneDialog(true, NULL); } } else { SceneDialog::displaySceneWithErrorMessageDialog(browserWindow, sceneFile, scene); } } /** * Show the Workbench Bug Report Dialog. * * @param browserWindow * Parent of dialog if it needs to be created. * @param openGLInformation * Information about OpenGL. */ void GuiManager::processShowBugReportDialog(BrainBrowserWindow* browserWindow, const AString& openGLInformation) { if (m_bugReportDialog == NULL) { m_bugReportDialog = new BugReportDialog(browserWindow, openGLInformation); this->addNonModalDialog(m_bugReportDialog); } m_bugReportDialog->showDialog(); } /** * @return Action for display of help viewer. */ QAction* GuiManager::getHelpViewerDialogDisplayAction() { return m_helpViewerDialogDisplayAction; } /** * Get the action for the data tooltips. The action * is lazily initialized since a widget is needed to * create the tooltip's icon. The background and foreground * colors are copied from the widget and nothing is dependent * upon the widget after this method returns. * * @param buttonWidget * Widget that is used the first time this method is called * to provide foreground/background colors for the pixmap. * * @return Action for display of data tool tips. */ QAction* GuiManager::getDataToolTipsAction(QWidget* buttonWidget) { if (m_dataToolTipsEnabledAction == NULL) { m_dataToolTipsEnabledAction = WuQtUtilities::createAction("Data ToolTips", "Enable/Disable Data Tool Tips", this, this, SLOT(dataToolTipsActionTriggered(bool))); m_dataToolTipsEnabledAction->setIcon(createDataToolTipsIcon(buttonWidget)); m_dataToolTipsEnabledAction->setIconVisibleInMenu(false); m_dataToolTipsEnabledAction->setCheckable(true); m_dataToolTipsEnabledAction->setChecked(SessionManager::get()->getDataToolTipsManager()->isEnabled()); m_dataToolTipsEnabledAction->setObjectName("ToolBar:DataToolTipsEnabled"); WuQMacroManager::instance()->addMacroSupportToObject(m_dataToolTipsEnabledAction, "Enable data tool tips"); } return m_dataToolTipsEnabledAction; } /** * Create a pixmap for the data tool tips button. * * @param widget * To color the pixmap with backround and foreground, * the palette from the given widget is used. * @return * The pixmap. */ QPixmap GuiManager::createDataToolTipsIcon(const QWidget* widget) { CaretAssert(widget); const float pixmapSize = 32.0; QPixmap pixmap(static_cast(pixmapSize), static_cast(pixmapSize)); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginCenter(widget, pixmap, WuQtUtilities::PixMapCreationOptions::TransparentBackground); const int leftX(-14); const int rightX(14); const int bottomY(-8); const int topY(14); const int tipLeftX(-6); const int tipRightX(6); const int tipY(-14); const int tipX(0); QPen pen(painter->pen()); pen.setWidth(2); painter->setPen(pen); /* * Outline of icon */ QPolygon polygon; polygon.push_back(QPoint(leftX, topY)); polygon.push_back(QPoint(leftX, bottomY)); polygon.push_back(QPoint(tipLeftX, bottomY)); polygon.push_back(QPoint(tipX, tipY)); polygon.push_back(QPoint(tipRightX, bottomY)); polygon.push_back(QPoint(rightX, bottomY)); polygon.push_back(QPoint(rightX, topY)); painter->drawPolygon(polygon); /* * Horizontal lines inside outline */ const int lineLeftX(-8); const int lineRightX(8); const int lineOneY(6); const int lineTwoY(0); painter->drawLine(lineLeftX, lineOneY, lineRightX, lineOneY); painter->drawLine(lineLeftX, lineTwoY, lineRightX, lineTwoY); return pixmap; } /** * Show or hide the help dialog. * * @param status * True means show, false means hide. * @param parentBrainBrowserWindow * If this is not NULL, and the help dialog needs to be created, * use this window as the parent and place the dialog next to this * window. */ void GuiManager::showHideHelpDialog(const bool status, const BrainBrowserWindow* parentBrainBrowserWindow) { BrainBrowserWindow* helpDialogParentWindow = getActiveBrowserWindow(); if (parentBrainBrowserWindow != NULL) { for (auto bbw : m_brainBrowserWindows) { if (bbw == parentBrainBrowserWindow) { helpDialogParentWindow = bbw; break; } } } CaretAssert(helpDialogParentWindow); #ifndef WORKBENCH_HAVE_HELP_HTML const QString msg("Help not available.\n" "wb_view was configured without inclusion of Help Information."); WuQMessageBox::errorOk(helpDialogParentWindow, msg); return; #endif if (status) { if (m_helpViewerDialog == NULL) { m_helpViewerDialog = new HelpViewerDialog(helpDialogParentWindow); this->addNonModalDialog(m_helpViewerDialog); QObject::connect(m_helpViewerDialog, SIGNAL(dialogWasClosed()), this, SLOT(helpDialogWasClosed())); WuQtUtilities::moveWindowToSideOfParent(helpDialogParentWindow, m_helpViewerDialog); } m_helpViewerDialog->showDialog(); } else if (m_helpViewerDialog != NULL) { m_helpViewerDialog->close(); } m_helpViewerDialogDisplayAction->blockSignals(true); m_helpViewerDialogDisplayAction->setChecked(status); m_helpViewerDialogDisplayAction->blockSignals(false); } /** * Gets called by the help dialog when the help dialog is closed. * Ensures that the help dialog display action status remains * synchronized with the displayed status of the help dialog. */ void GuiManager::helpDialogWasClosed() { m_helpViewerDialogDisplayAction->blockSignals(true); m_helpViewerDialogDisplayAction->setChecked(false); m_helpViewerDialogDisplayAction->blockSignals(false); } /** * Called when show help action is triggered * * @param status * New status. */ void GuiManager::showHelpDialogActionToggled(bool status) { showHideHelpDialog(status, NULL); } /** * Called when data tooltips action is triggered * * @param status * New status. */ void GuiManager::dataToolTipsActionTriggered(bool status) { SessionManager::get()->getDataToolTipsManager()->setEnabled(status); } /** * @return The action that indicates the enabled status * for display of the information window. */ QAction* GuiManager::getInformationDisplayDialogEnabledAction() { return m_informationDisplayDialogEnabledAction; } /** * @return The action that indicates the enabled status * for display of the identify brainordinate dialog. */ QAction* GuiManager::getIdentifyBrainordinateDialogDisplayAction() { return m_identifyBrainordinateDialogEnabledAction; } /** * Show the information window. */ void GuiManager::processShowInformationWindow() { this->processShowInformationDisplayDialog(true); } void GuiManager::showHideInfoWindowSelected(bool status) { QString text("Show Information Window"); if (status) { text = "Hide Information Window"; if (m_informationDisplayDialogEnabledAction->signalsBlocked() == false) { this->processShowInformationDisplayDialog(true); } } text += ("\n\n" "When this button is 'on', the information window\n" "is automatically displayed when an identification\n" "operation (mouse click over surface or volume slice)\n" "is performed. "); m_informationDisplayDialogEnabledAction->setToolTip(text); } /** * Show the information display window. * @param forceDisplayOfDialog * If true, the window will be displayed even if its display * enabled status is off. */ void GuiManager::processShowInformationDisplayDialog(const bool forceDisplayOfDialog) { if (m_informationDisplayDialog == NULL) { std::vector bbws = this->getAllOpenBrainBrowserWindows(); if (bbws.empty() == false) { BrainBrowserWindow* parentWindow = bbws[0]; #ifdef CARET_OS_MACOSX m_informationDisplayDialog = new InformationDisplayDialog(parentWindow); this->addNonModalDialog(m_informationDisplayDialog); #else // CARET_OS_MACOSX m_informationDisplayDialog = new InformationDisplayDialog(NULL); addParentLessNonModalDialog(m_informationDisplayDialog); #endif // CARET_OS_MACOSX m_informationDisplayDialog->resize(600, 200); m_informationDisplayDialog->setSaveWindowPositionForNextTime(true); WuQtUtilities::moveWindowToSideOfParent(parentWindow, m_informationDisplayDialog); } } if (forceDisplayOfDialog || m_informationDisplayDialogEnabledAction->isChecked()) { if (m_informationDisplayDialog != NULL) { m_informationDisplayDialog->showDialog(); } } } /** * Show/hide the identify dialog. * * @param status * Status (true/false) to display dialog. */ void GuiManager::showIdentifyBrainordinateDialogActionToggled(bool status) { showHideIdentfyBrainordinateDialog(status, NULL); } /** * Show or hide the identify brainordinate dialog. * * @param status * True means show, false means hide. * @param parentBrainBrowserWindow * If this is not NULL, and the help dialog needs to be created, * use this window as the parent and place the dialog next to this * window. */ void GuiManager::showHideIdentfyBrainordinateDialog(const bool status, BrainBrowserWindow* parentBrainBrowserWindow) { bool dialogWasCreated = false; QWidget* moveWindowParent = parentBrainBrowserWindow; if (status) { if (m_identifyBrainordinateDialog == NULL) { BrainBrowserWindow* idDialogParent = parentBrainBrowserWindow; if (idDialogParent == NULL) { idDialogParent = getActiveBrowserWindow(); } m_identifyBrainordinateDialog = new IdentifyBrainordinateDialog(idDialogParent); //m_identifyBrainordinateDialog->setSaveWindowPositionForNextTime(true); this->addNonModalDialog(m_identifyBrainordinateDialog); QObject::connect(m_identifyBrainordinateDialog, SIGNAL(dialogWasClosed()), this, SLOT(identifyBrainordinateDialogWasClosed())); dialogWasCreated = true; /* * If there was no parent dialog for placement of the help * dialog and there is only one browser window, use the browser * for placement of the help dialog. */ if (moveWindowParent == NULL) { if (getAllOpenBrainBrowserWindows().size() == 1) { moveWindowParent = idDialogParent; } } } m_identifyBrainordinateDialog->showDialog(); } else { m_identifyBrainordinateDialog->close(); } if (dialogWasCreated) { if (moveWindowParent != NULL) { WuQtUtilities::moveWindowToSideOfParent(moveWindowParent, m_identifyBrainordinateDialog); } } m_identifyBrainordinateDialogEnabledAction->blockSignals(true); m_identifyBrainordinateDialogEnabledAction->setChecked(status); m_identifyBrainordinateDialogEnabledAction->blockSignals(false); } /** * Gets called when the identify dialog is closed. */ void GuiManager::identifyBrainordinateDialogWasClosed() { m_identifyBrainordinateDialogEnabledAction->blockSignals(true); m_identifyBrainordinateDialogEnabledAction->setChecked(false); m_identifyBrainordinateDialogEnabledAction->blockSignals(false); } /** * Add a non-modal dialog so that it may be reparented. * * @param dialog * The dialog. */ void GuiManager::addNonModalDialog(QWidget* dialog) { CaretAssert(dialog); this->nonModalDialogs.insert(dialog); } /** * Add a parent-less dialog so that it may be deleted when * the application is exited. * * @param dialog * The dialog. */ void GuiManager::addParentLessNonModalDialog(QWidget* dialog) { CaretAssert(dialog); m_parentlessNonModalDialogs.insert(dialog); } /** * Show the clipping planes dialog. * @param browserWindow * Window on which dialog was requested. */ void GuiManager::processShowClippingPlanesDialog(BrainBrowserWindow* browserWindow) { if (m_clippingPlanesDialog == NULL) { m_clippingPlanesDialog = new ClippingPlanesDialog(browserWindow); this->addNonModalDialog(m_clippingPlanesDialog); } const int32_t browserWindowIndex = browserWindow->getBrowserWindowIndex(); m_clippingPlanesDialog->updateContent(browserWindowIndex); m_clippingPlanesDialog->showDialog(); } /** * Show the custom view dialog. * @param browserWindow * Window on which dialog was requested. */ void GuiManager::processShowCustomViewDialog(BrainBrowserWindow* browserWindow) { if (m_customViewDialog == NULL) { m_customViewDialog = new CustomViewDialog(browserWindow); this->addNonModalDialog(m_customViewDialog); } const int32_t browserWindowIndex = browserWindow->getBrowserWindowIndex(); m_customViewDialog->updateContent(browserWindowIndex); m_customViewDialog->showDialog(); } /** * Show the tile tabs configuration dialog. * @param browserWindow * Window on which dialog was requested. */ void GuiManager::processShowTileTabsConfigurationDialog(caret::BrainBrowserWindow *browserWindow) { if (m_tileTabsConfigurationDialog == NULL) { m_tileTabsConfigurationDialog = new TileTabsConfigurationDialog(browserWindow); this->addNonModalDialog(m_tileTabsConfigurationDialog); } m_tileTabsConfigurationDialog->updateDialogWithSelectedTileTabsFromWindow(browserWindow); m_tileTabsConfigurationDialog->showDialog(); } /** * Show the image capture window. * @param browserWindow * Window on which dialog was requested. */ void GuiManager::processShowImageCaptureDialog(BrainBrowserWindow* browserWindow) { if (this->imageCaptureDialog == NULL) { this->imageCaptureDialog = new ImageCaptureDialog(browserWindow); this->addNonModalDialog(this->imageCaptureDialog); } this->imageCaptureDialog->updateDialog(); this->imageCaptureDialog->setBrowserWindowIndex(browserWindow->getBrowserWindowIndex()); this->imageCaptureDialog->showDialog(); } /** * Show the image capture window. * @param browserWindow * Window on which dialog was requested. */ void GuiManager::processShowMovieRecordingDialog(BrainBrowserWindow* browserWindow) { if (m_movieRecordingDialog == NULL) { m_movieRecordingDialog = new MovieRecordingDialog(browserWindow); this->addNonModalDialog(m_movieRecordingDialog); } m_movieRecordingDialog->updateDialog(); m_movieRecordingDialog->setBrowserWindowIndex(browserWindow->getBrowserWindowIndex()); m_movieRecordingDialog->showDialog(); m_movieRecordingDialog->restorePositionAndSize(); } /** * Show the gaps and margins window. * @param browserWindow * Window on which dialog was requested. */ void GuiManager::processShowGapsAndMarginsDialog(BrainBrowserWindow* browserWindow) { if (m_gapsAndMarginsDialog == NULL) { m_gapsAndMarginsDialog = new GapsAndMarginsDialog(browserWindow); this->addNonModalDialog(m_gapsAndMarginsDialog); } m_gapsAndMarginsDialog->updateDialog(); m_gapsAndMarginsDialog->showDialog(); } /** * Show the record movie window. * @param browserWindow * Window on which dialog was requested. */ void GuiManager::processShowMovieDialog(BrainBrowserWindow* browserWindow) { if (this->movieDialog == NULL) { this->movieDialog = new MovieDialog(browserWindow); this->addNonModalDialog(this->movieDialog); } this->movieDialog->setVisible(true); this->movieDialog->show(); this->movieDialog->activateWindow(); this->movieDialog->raise(); } /** * Show the preferences window. * @param browserWindow * Window on which dialog was requested. */ void GuiManager::processShowPreferencesDialog(BrainBrowserWindow* browserWindow) { if (this->preferencesDialog == NULL) { this->preferencesDialog = new PreferencesDialog(browserWindow); this->addNonModalDialog(this->preferencesDialog); } this->preferencesDialog->updateDialog(); this->preferencesDialog->showDialog(); } /** * Show the allen database web view. * @param browserWindow * If the web view needs to be created, use this as parent. */ void GuiManager::processShowAllenDataBaseWebView(BrainBrowserWindow* browserWindow) { WuQMessageBox::informationOk(browserWindow, "Allen Database connection not yet implemented"); } /** * Show the connectome database web view. * @param browserWindow * If the web view needs to be created, use this as parent. */ void GuiManager::processShowConnectomeDataBaseWebView(BrainBrowserWindow* /*browserWindow*/) { CaretLogSevere("Webkit is disabled !!!"); // no webkit // if (this->connectomeDatabaseWebView == NULL) { // this->connectomeDatabaseWebView = new WuQWebView(); // this->connectomeDatabaseWebView->load(QUrl("https://db.humanconnectome.org/")); // this->addNonModalDialog(this->connectomeDatabaseWebView); // } // this->connectomeDatabaseWebView->show(); } /** * sets animation start time for Time Course Dialogs */ void GuiManager::updateAnimationStartTime(double /*value*/) { } /** * @return The cursor manager. */ const CursorManager* GuiManager::getCursorManager() const { return this->cursorManager; } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* GuiManager::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "GuiManager", 1); /* * BrowserWindowContent is saved and restored by SessionManager. * Some of the data in BrowserWindowContent needs to be updated * by BrainBrowserWindow which is not saved until AFTER SessionManager * so direct each window to update its BrowserWindowContent so that * BrowserWindowContent can be saved by the SessionManager. */ for (auto browserWindow : m_brainBrowserWindows) { if (browserWindow != NULL) { browserWindow->saveBrowserWindowContentForScene(); } } /* * Save session manager (brain, etc) */ sceneClass->addClass(SessionManager::get()->saveToScene(sceneAttributes, "m_sessionManager")); /* * Save windows */ std::vector browserWindowClasses; const int32_t numBrowserWindows = static_cast(m_brainBrowserWindows.size()); for (int32_t i = 0; i < numBrowserWindows; i++) { BrainBrowserWindow* bbw = m_brainBrowserWindows[i]; if (bbw != NULL) { browserWindowClasses.push_back(bbw->saveToScene(sceneAttributes, "m_brainBrowserWindows")); } } SceneClassArray* browserWindowArray = new SceneClassArray("m_brainBrowserWindows", browserWindowClasses); sceneClass->addChild(browserWindowArray); /* * Save information window */ if (m_informationDisplayDialog != NULL) { sceneClass->addClass(m_informationDisplayDialog->saveToScene(sceneAttributes, "m_informationDisplayDialog")); } /* * Save surface properties window */ if (m_surfacePropertiesEditorDialog != NULL) { sceneClass->addClass(m_surfacePropertiesEditorDialog->saveToScene(sceneAttributes, "m_surfacePropertiesEditorDialog")); } if (m_volumePropertiesEditorDialog != NULL) { sceneClass->addClass(m_volumePropertiesEditorDialog->saveToScene(sceneAttributes, "m_volumePropertiesEditorDialog")); } switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void GuiManager::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { const int64_t eventCountAtStart = EventManager::get()->getEventIssuedCounter(); ElapsedTimer sceneRestoreTimer; sceneRestoreTimer.start(); if (sceneClass == NULL) { return; } switch (sceneAttributes->getSceneType()) { case SceneTypeEnum::SCENE_TYPE_FULL: break; case SceneTypeEnum::SCENE_TYPE_GENERIC: break; } /* * Invalid first window position used when * positioning other windows */ SceneWindowGeometry::setFirstBrowserWindowCoordinatesInvalid(); /* * Close all but one window and remove its tabs */ BrainBrowserWindow* firstBrowserWindow = getActiveBrowserWindow();; if (firstBrowserWindow != NULL) { closeAllOtherWindows(firstBrowserWindow); /* * Remove all tabs from window. * The tab content will be deleted by the session manager. */ std::vector windowTabContent; firstBrowserWindow->removeAndReturnAllTabs(windowTabContent); } /* * Close Overlay and palette editor windows since the files * displayed in them may become invalid */ for (std::set::iterator overlayEditorIter = m_overlaySettingsEditors.begin(); overlayEditorIter != m_overlaySettingsEditors.end(); overlayEditorIter++) { OverlaySettingsEditorDialog* med = *overlayEditorIter; med->close(); } if (m_paletteColorMappingEditor != NULL) { m_paletteColorMappingEditor->close(); } /* * Update the windows */ EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); /* * Blocking user-interface and graphics event will speed up * restoration of the user interface. */ bool blockUserInteraceUpdateEvents = true; if (blockUserInteraceUpdateEvents) { EventManager::get()->blockEvent(EventTypeEnum::EVENT_USER_INTERFACE_UPDATE, true); } EventManager::get()->blockEvent(EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS, true); EventManager::get()->blockEvent(EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW, true); /* * Restore session manager */ SessionManager::get()->restoreFromScene(sceneAttributes, sceneClass->getClass("m_sessionManager")); EventProgressUpdate progressEvent(""); /* * See if models available (user may have cancelled scene loading. */ EventModelGetAll getAllModelsEvent; EventManager::get()->sendEvent(getAllModelsEvent.getPointer()); const bool haveModels = (getAllModelsEvent.getModels().empty() == false); ElapsedTimer timer; timer.start(); if (haveModels) { /* * Get open windows */ std::list availableWindows; const int32_t numBrowserWindows = static_cast(m_brainBrowserWindows.size()); for (int32_t i = 0; i < numBrowserWindows; i++) { if (m_brainBrowserWindows[i] != NULL) { availableWindows.push_back(m_brainBrowserWindows[i]); } } /* * Restore windows */ progressEvent.setProgressMessage("Restoring browser windows"); EventManager::get()->sendEvent(progressEvent.getPointer()); const SceneClassArray* browserWindowArray = sceneClass->getClassArray("m_brainBrowserWindows"); if (browserWindowArray != NULL) { bool windowWasRestoredFlag = false; const int32_t numBrowserClasses = browserWindowArray->getNumberOfArrayElements(); for (int32_t i = 0; i < numBrowserClasses; i++) { const SceneClass* browserClass = browserWindowArray->getClassAtIndex(i); CaretAssert(browserClass); const int32_t windowIndex = browserClass->getIntegerValue("m_browserWindowIndex", -1); BrainBrowserWindow* bbw = NULL; AString errorMessage; if ( ! availableWindows.empty()) { bbw = availableWindows.front(); if (windowIndex >= 0) { /* * Use window only if it has same index as window being restored. */ if (bbw->getBrowserWindowIndex() != windowIndex) { bbw = NULL; } } if (bbw != NULL) { availableWindows.pop_front(); } } if (bbw == NULL) { bbw = newBrainBrowserWindow(NULL, windowIndex, NULL, false, errorMessage); } if (bbw != NULL) { bbw->restoreFromScene(sceneAttributes, browserClass); windowWasRestoredFlag = true; } else { sceneAttributes->addToErrorMessage("\n" + errorMessage); } } if (windowWasRestoredFlag) { if ( ! availableWindows.empty()) { BrainBrowserWindow* bbw = availableWindows.front(); bbw->close(); } } } CaretLogFine("Time to restore browser windows was " + QString::number(timer.getElapsedTimeSeconds(), 'f', 3) + " seconds"); timer.reset(); /* * Restore information window */ progressEvent.setProgressMessage("Restoring Information Window"); EventManager::get()->sendEvent(progressEvent.getPointer()); const SceneClass* infoWindowClass = sceneClass->getClass("m_informationDisplayDialog"); if (infoWindowClass != NULL) { if (m_informationDisplayDialog == NULL) { processShowInformationWindow(); } else if (m_informationDisplayDialog->isVisible() == false) { processShowInformationWindow(); } m_informationDisplayDialog->restoreFromScene(sceneAttributes, infoWindowClass); } else { if (m_informationDisplayDialog != NULL) { /* * Will clear text */ m_informationDisplayDialog->restoreFromScene(sceneAttributes, NULL); } } /* * Restore surface properties */ progressEvent.setProgressMessage("Restoring Surface Properties Window"); EventManager::get()->sendEvent(progressEvent.getPointer()); const SceneClass* surfPropClass = sceneClass->getClass("m_surfacePropertiesEditorDialog"); if (surfPropClass != NULL) { if (m_surfacePropertiesEditorDialog == NULL) { processShowSurfacePropertiesEditorDialog(firstBrowserWindow); } else if (m_surfacePropertiesEditorDialog->isVisible() == false) { processShowSurfacePropertiesEditorDialog(firstBrowserWindow); } m_surfacePropertiesEditorDialog->restoreFromScene(sceneAttributes, surfPropClass); } const SceneClass* volPropClass = sceneClass->getClass("m_volumePropertiesEditorDialog"); if (volPropClass != NULL) { if (m_volumePropertiesEditorDialog == NULL) { processShowVolumePropertiesEditorDialog(firstBrowserWindow); } else if ( ! m_volumePropertiesEditorDialog->isVisible()) { processShowVolumePropertiesEditorDialog(firstBrowserWindow); } m_volumePropertiesEditorDialog->restoreFromScene(sceneAttributes, volPropClass); } CaretLogFine("Time to restore information/property windows was " + QString::number(timer.getElapsedTimeSeconds(), 'f', 3) + " seconds"); timer.reset(); } updateNonModalDialogs(); if (imageCaptureDialog != NULL) { imageCaptureDialog->updateDialog(); } if (m_movieRecordingDialog != NULL) { m_movieRecordingDialog->updateDialog(); } progressEvent.setProgressMessage("Invalidating coloring and updating user interface"); EventManager::get()->sendEvent(progressEvent.getPointer()); EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); if (blockUserInteraceUpdateEvents) { EventManager::get()->blockEvent(EventTypeEnum::EVENT_USER_INTERFACE_UPDATE, false); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); /* * Unblock graphics updates */ EventManager::get()->blockEvent(EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS, false); EventManager::get()->blockEvent(EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW, false); progressEvent.setProgressMessage("Updating graphics in all windows"); EventManager::get()->sendEvent(progressEvent.getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); CaretLogFine("Time to update graphics in all windows was " + QString::number(timer.getElapsedTimeSeconds(), 'f', 3) + " seconds"); timer.reset(); const int64_t totalNumberOfEvents = (EventManager::get()->getEventIssuedCounter() - eventCountAtStart); CaretLogFine("Time to restore scene was " + QString::number(sceneRestoreTimer.getElapsedTimeSeconds(), 'f', 3) + " seconds with " + AString::number(totalNumberOfEvents) + " events"); } /** * Get the name of the data file that may have been set * if Workbench was started by double-clicking a file * in the Mac OSX finder. */ AString GuiManager::getNameOfDataFileToOpenAfterStartup() const { return m_nameOfDataFileToOpenAfterStartup; } /** * Process identification after item(s) selected using a selection manager. * * @parma tabIndex * Index of tab in which identification took place. This value may * be negative indicating that the identification request is not * from a browser tab. One source for this is the Select Brainordinate * option on the Information Window. * @param selectionManager * The selection manager. * @param parentWidget * Widget on which any error message windows are displayed. */ void GuiManager::processIdentification(const int32_t tabIndex, SelectionManager* selectionManager, QWidget* parentWidget) { CursorDisplayScoped cursor; cursor.showWaitCursor(); Brain* brain = GuiManager::get()->getBrain(); CiftiConnectivityMatrixDataFileManager* ciftiConnectivityManager = SessionManager::get()->getCiftiConnectivityMatrixDataFileManager(); CiftiFiberTrajectoryManager* ciftiFiberTrajectoryManager = SessionManager::get()->getCiftiFiberTrajectoryManager(); ChartingDataManager* chartingDataManager = brain->getChartingDataManager(); IdentificationManager* identificationManager = brain->getIdentificationManager(); bool updateGraphicsFlag = false; bool updateInformationFlag = false; std::vector ciftiLoadingInfo; const QString breakAndIndent("
        "); SelectionItemSurfaceNodeIdentificationSymbol* nodeIdSymbol = selectionManager->getSurfaceNodeIdentificationSymbol(); SelectionItemVoxelIdentificationSymbol* voxelIdSymbol = selectionManager->getVoxelIdentificationSymbol(); if ((nodeIdSymbol->getSurface() != NULL) && (nodeIdSymbol->getNodeNumber() >= 0)) { const Surface* surface = nodeIdSymbol->getSurface(); const int32_t surfaceNumberOfNodes = surface->getNumberOfNodes(); const int32_t nodeIndex = nodeIdSymbol->getNodeNumber(); const StructureEnum::Enum structure = surface->getStructure(); identificationManager->removeIdentifiedNodeItem(structure, surfaceNumberOfNodes, nodeIndex); updateGraphicsFlag = true; updateInformationFlag = true; } else if (voxelIdSymbol->isValid()) { float voxelXYZ[3]; voxelIdSymbol->getVoxelXYZ(voxelXYZ); identificationManager->removeIdentifiedVoxelItem(voxelXYZ); updateGraphicsFlag = true; updateInformationFlag = true; } else { IdentifiedItem* identifiedItem = NULL; SelectionItemSurfaceNode* idNode = selectionManager->getSurfaceNodeIdentification(); SelectionItemVoxel* idVoxel = selectionManager->getVoxelIdentification(); /* * If there is a voxel ID but no node ID, identify a * node near the voxel coordinate, if it is close by. */ bool nodeIdentificationCreatedFromVoxelIdentificationFlag = false; if (idNode->isValid() == false) { if (idVoxel->isValid()) { double doubleXYZ[3]; idVoxel->getModelXYZ(doubleXYZ); const float voxelXYZ[3] = { (float)doubleXYZ[0], (float)doubleXYZ[1], (float)doubleXYZ[2] }; Surface* surface = brain->getPrimaryAnatomicalSurfaceNearestCoordinate(voxelXYZ, 3.0); if (surface != NULL) { const int nodeIndex = surface->closestNode(voxelXYZ); if (nodeIndex >= 0) { idNode->reset(); idNode->setBrain(brain); idNode->setSurface(surface); idNode->setNodeNumber(nodeIndex); nodeIdentificationCreatedFromVoxelIdentificationFlag = true; } } } } /* * Load CIFTI NODE data prior to ID Message so that CIFTI * data shown in identification text is correct for the * node that was loaded. */ bool triedToLoadSurfaceODemandData = false; if (idNode->isValid()) { /* * NOT: node id was NOT created from voxel ID */ if (nodeIdentificationCreatedFromVoxelIdentificationFlag == false) { Surface* surface = idNode->getSurface(); const int32_t nodeIndex = idNode->getNodeNumber(); try { triedToLoadSurfaceODemandData = true; ciftiConnectivityManager->loadDataForSurfaceNode(brain, surface, nodeIndex, ciftiLoadingInfo); ciftiFiberTrajectoryManager->loadDataForSurfaceNode(brain, surface, nodeIndex, ciftiLoadingInfo); chartingDataManager->loadChartForSurfaceNode(surface, nodeIndex); std::vector metricDynConnFiles; brain->getMetricDynamicConnectivityFiles(metricDynConnFiles); for (auto mdc : metricDynConnFiles) { if (mdc->isEnabledAsLayer()) { mdc->loadDataForSurfaceNode(surface->getNumberOfNodes(), surface->getStructure(), nodeIndex); } } updateGraphicsFlag = true; } catch (const DataFileException& e) { cursor.restoreCursor(); QMessageBox::critical(parentWidget, "", e.whatString()); cursor.showWaitCursor(); } } } /* * Load CIFTI VOXEL data prior to ID Message so that CIFTI * data shown in identification text is correct for the * voxel that was loaded. * * Note: If there was an attempt to load data for surface, * do not try to load voxel data. Otherwise, if the voxel * data loading fails, it will clear the coloring for * the connetivity data and make it appear as if loading data * failed. */ if (idVoxel->isValid() && ( ! triedToLoadSurfaceODemandData)) { const VolumeMappableInterface* volumeFile = idVoxel->getVolumeFile(); int64_t voxelIJK[3]; idVoxel->getVoxelIJK(voxelIJK); if (volumeFile != NULL) { float xyz[3]; volumeFile->indexToSpace(voxelIJK, xyz); updateGraphicsFlag = true; try { ciftiConnectivityManager->loadDataForVoxelAtCoordinate(brain, xyz, ciftiLoadingInfo); ciftiFiberTrajectoryManager->loadDataForVoxelAtCoordinate(brain, xyz, ciftiLoadingInfo); } catch (const DataFileException& e) { cursor.restoreCursor(); QMessageBox::critical(parentWidget, "", e.whatString()); cursor.showWaitCursor(); } try { chartingDataManager->loadChartForVoxelAtCoordinate(xyz); } catch (const DataFileException& e) { cursor.restoreCursor(); QMessageBox::critical(parentWidget, "", e.whatString()); cursor.showWaitCursor(); } } } if (idVoxel->isValid()) { std::vector volumeDynConnFiles; brain->getVolumeDynamicConnectivityFiles(volumeDynConnFiles); for (auto vdc : volumeDynConnFiles) { if (vdc->isEnabledAsLayer()) { double xyzDouble[3]; idVoxel->getModelXYZ(xyzDouble); float xyz[3] { static_cast(xyzDouble[0]), static_cast(xyzDouble[1]), static_cast(xyzDouble[2]) }; vdc->loadConnectivityForVoxelXYZ(xyz); } } } SelectionItemChartMatrix* idChartOneMatrix = selectionManager->getChartMatrixIdentification(); if (idChartOneMatrix->isValid()) { ChartableMatrixInterface* chartMatrixInterface = idChartOneMatrix->getChartableMatrixInterface(); if (chartMatrixInterface != NULL) { CiftiConnectivityMatrixParcelFile* ciftiParcelFile = dynamic_cast(chartMatrixInterface); if (ciftiParcelFile != NULL) { if (ciftiParcelFile->isMapDataLoadingEnabled(0)) { const int32_t rowIndex = idChartOneMatrix->getMatrixRowIndex(); const int32_t columnIndex = idChartOneMatrix->getMatrixColumnIndex(); if ((rowIndex >= 0) && (columnIndex >= 0)) { try { ciftiConnectivityManager->loadRowOrColumnFromParcelFile(brain, ciftiParcelFile, rowIndex, columnIndex, ciftiLoadingInfo); } catch (const DataFileException& e) { cursor.restoreCursor(); QMessageBox::critical(parentWidget, "", e.whatString()); cursor.showWaitCursor(); } updateGraphicsFlag = true; } } } CiftiScalarDataSeriesFile* scalarDataSeriesFile = dynamic_cast(chartMatrixInterface); if (scalarDataSeriesFile != NULL) { const int32_t rowIndex = idChartOneMatrix->getMatrixRowIndex(); if (rowIndex >= 0) { scalarDataSeriesFile->setSelectedMapIndex(tabIndex, rowIndex); const MapYokingGroupEnum::Enum mapYoking = scalarDataSeriesFile->getMatrixRowColumnMapYokingGroup(tabIndex); if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { EventMapYokingSelectMap selectMapEvent(mapYoking, scalarDataSeriesFile, NULL, rowIndex, true); EventManager::get()->sendEvent(selectMapEvent.getPointer()); } else { chartingDataManager->loadChartForCiftiMappableFileRow(scalarDataSeriesFile, rowIndex); } updateGraphicsFlag = true; } } } } SelectionItemCiftiConnectivityMatrixRowColumn* idCiftiConnMatrix = selectionManager->getCiftiConnectivityMatrixRowColumnIdentification(); if (idCiftiConnMatrix != NULL) { CiftiMappableConnectivityMatrixDataFile* matrixFile = idCiftiConnMatrix->getCiftiConnectivityMatrixFile(); if (matrixFile != NULL) { const int32_t rowIndex = idCiftiConnMatrix->getMatrixRowIndex(); const int32_t columnIndex = idCiftiConnMatrix->getMatrixColumnIndex(); if ((rowIndex >= 0) || (columnIndex >= 0)) { ciftiConnectivityManager->loadRowOrColumnFromConnectivityMatrixFile(matrixFile, rowIndex, columnIndex, ciftiLoadingInfo); updateGraphicsFlag = true; } } } SelectionItemChartTwoMatrix* idChartTwoMatrix = selectionManager->getChartTwoMatrixIdentification(); if (idChartTwoMatrix != NULL) { if (idChartTwoMatrix->isValid()) { ChartableTwoFileMatrixChart* matrixChart = idChartTwoMatrix->getFileMatrixChart(); const int32_t rowIndex = idChartTwoMatrix->getRowIndex(); const int32_t colIndex = idChartTwoMatrix->getColumnIndex(); CaretMappableDataFile* cmdf = matrixChart->getCaretMappableDataFile(); CaretAssert(cmdf); bool loadMapFlag = false; ChartTwoOverlay* chartOverlayContainingDataFile = NULL; EventBrowserTabGet eventBrowserTab(tabIndex); EventManager::get()->sendEvent(eventBrowserTab.getPointer()); BrowserTabContent* tabContent = eventBrowserTab.getBrowserTab(); if (tabContent != NULL) { ModelChartTwo* chartTwoModel = tabContent->getDisplayedChartTwoModel(); if (chartTwoModel != NULL) { if (chartTwoModel->getSelectedChartTwoDataType(tabIndex) == ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX) { ChartTwoOverlaySet* chartOverlaySet = tabContent->getChartTwoOverlaySet(); chartOverlayContainingDataFile = chartOverlaySet->getDisplayedOverlayContainingDataFile(cmdf); } } } bool foundChartOverlayFlag = false; if (chartOverlayContainingDataFile != NULL) { ChartableTwoFileMatrixChart* matrixChart = cmdf->getChartingDelegate()->getMatrixCharting(); if (matrixChart != NULL) { if (matrixChart->isValid()) { int32_t rowColumnIndex = -1; switch (matrixChart->getSelectedRowColumnDimension()) { case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: rowColumnIndex = colIndex; break; case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: rowColumnIndex = rowIndex; break; } chartOverlayContainingDataFile->setSelectionData(cmdf, rowColumnIndex); const MapYokingGroupEnum::Enum mapYoking = chartOverlayContainingDataFile->getMapYokingGroup(); if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { EventMapYokingSelectMap selectMapEvent(mapYoking, cmdf, NULL, rowColumnIndex, true); EventManager::get()->sendEvent(selectMapEvent.getPointer()); } updateGraphicsFlag = true; foundChartOverlayFlag = true; chartingDataManager->loadChartForCiftiMappableFileRow(matrixChart->getCiftiMappableDataFile(), rowIndex); } } } if ( ! foundChartOverlayFlag) { CaretLogWarning("PROGRAMMER NOTE: Failed to find chart overlay containing identified matrix row/column"); switch (matrixChart->getMatrixContentType()) { case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_BRAINORDINATE_MAPPABLE: { CiftiConnectivityMatrixParcelFile* ciftiParcelFile = dynamic_cast(cmdf); if (ciftiParcelFile != NULL) { if (ciftiParcelFile->isMapDataLoadingEnabled(0)) { if ((rowIndex >= 0) && (colIndex >= 0)) { try { ciftiConnectivityManager->loadRowOrColumnFromParcelFile(brain, ciftiParcelFile, rowIndex, colIndex, ciftiLoadingInfo); } catch (const DataFileException& e) { cursor.restoreCursor(); QMessageBox::critical(parentWidget, "", e.whatString()); cursor.showWaitCursor(); } updateGraphicsFlag = true; } } } else { CiftiMappableConnectivityMatrixDataFile* matrixFile = dynamic_cast(cmdf); if (matrixFile != NULL) { if ((rowIndex >= 0) || (colIndex >= 0)) { ciftiConnectivityManager->loadRowOrColumnFromConnectivityMatrixFile(matrixFile, rowIndex, colIndex, ciftiLoadingInfo); updateGraphicsFlag = true; } } else { loadMapFlag = true; } } } break; case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_SCALARS: { CiftiScalarDataSeriesFile* scalarDataSeriesFile = dynamic_cast(cmdf); if (scalarDataSeriesFile != NULL) { if (rowIndex >= 0) { scalarDataSeriesFile->setSelectedMapIndex(tabIndex, rowIndex); const MapYokingGroupEnum::Enum mapYoking = scalarDataSeriesFile->getMatrixRowColumnMapYokingGroup(tabIndex); if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { EventMapYokingSelectMap selectMapEvent(mapYoking, scalarDataSeriesFile, NULL, rowIndex, true); EventManager::get()->sendEvent(selectMapEvent.getPointer()); } else { chartingDataManager->loadChartForCiftiMappableFileRow(scalarDataSeriesFile, rowIndex); } updateGraphicsFlag = true; } } } break; case ChartTwoMatrixContentTypeEnum::MATRIX_CONTENT_UNSUPPORTED: break; } if (loadMapFlag) { ChartableTwoFileMatrixChart* matrixChart = cmdf->getChartingDelegate()->getMatrixCharting(); if (matrixChart != NULL) { if (matrixChart->isValid()) { int32_t rowColumnIndex = -1; switch (matrixChart->getSelectedRowColumnDimension()) { case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: rowColumnIndex = colIndex; break; case ChartTwoMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: rowColumnIndex = rowIndex; break; } matrixChart->setSelectedRowColumnIndex(tabIndex, rowColumnIndex); updateGraphicsFlag = true; } } } } } } /* * Generate identification manager */ const AString identificationMessage = selectionManager->getIdentificationText(brain); bool issuedIdentificationLocationEvent = false; if (idNode->isValid()) { Surface* surface = idNode->getSurface(); const int32_t nodeIndex = idNode->getNodeNumber(); /* * Save last selected node which may get used for foci creation. */ selectionManager->setLastSelectedItem(idNode); BrainStructure* brainStructure = surface->getBrainStructure(); CaretAssert(brainStructure); float xyz[3]; const Surface* primaryAnatomicalSurface = brainStructure->getPrimaryAnatomicalSurface(); if (primaryAnatomicalSurface != NULL) { primaryAnatomicalSurface->getCoordinate(nodeIndex, xyz); } else { CaretLogWarning("No surface/primary anatomical surface for " + StructureEnum::toGuiName(brainStructure->getStructure())); xyz[0] = -10000000.0; xyz[1] = -10000000.0; xyz[2] = -10000000.0; } identifiedItem = new IdentifiedItemNode(identificationMessage, surface->getStructure(), surface->getNumberOfNodes(), nodeIndex); /* * Only issue identification event for node * if it WAS NOT created from the voxel identification * location. */ if (nodeIdentificationCreatedFromVoxelIdentificationFlag == false) { if (issuedIdentificationLocationEvent == false) { EventIdentificationHighlightLocation idLocation(tabIndex, xyz, EventIdentificationHighlightLocation::LOAD_FIBER_ORIENTATION_SAMPLES_MODE_YES); EventManager::get()->sendEvent(idLocation.getPointer()); issuedIdentificationLocationEvent = true; } } } if (idVoxel->isValid()) { const VolumeMappableInterface* volumeFile = idVoxel->getVolumeFile(); int64_t voxelIJK[3]; idVoxel->getVoxelIJK(voxelIJK); if (volumeFile != NULL) { float xyz[3]; volumeFile->indexToSpace(voxelIJK, xyz); if (identifiedItem == NULL) { identifiedItem = new IdentifiedItemVoxel(identificationMessage, xyz); } if (issuedIdentificationLocationEvent == false) { EventIdentificationHighlightLocation idLocation(tabIndex, xyz, EventIdentificationHighlightLocation::LOAD_FIBER_ORIENTATION_SAMPLES_MODE_YES); EventManager::get()->sendEvent(idLocation.getPointer()); issuedIdentificationLocationEvent = true; } /* * Save last selected node which may get used for foci creation. */ selectionManager->setLastSelectedItem(idVoxel); } } if (identifiedItem == NULL) { if (identificationMessage.isEmpty() == false) { identifiedItem = new IdentifiedItem(identificationMessage); } } AString ciftiInfo; if (ciftiLoadingInfo.empty() == false) { IdentificationStringBuilder ciftiIdStringBuilder; ciftiIdStringBuilder.addLine(false, "CIFTI data loaded", " "); for (std::vector::iterator iter = ciftiLoadingInfo.begin(); iter != ciftiLoadingInfo.end(); iter++) { ciftiIdStringBuilder.addLine(true, *iter); } ciftiInfo = ciftiIdStringBuilder.toString(); } if (ciftiInfo.isEmpty() == false) { if (identifiedItem != NULL) { identifiedItem->appendText(ciftiInfo); } else { identifiedItem = new IdentifiedItem(ciftiInfo); } } if (identifiedItem != NULL) { identificationManager->addIdentifiedItem(identifiedItem); updateInformationFlag = true; } } if (updateInformationFlag) { EventManager::get()->sendEvent(EventUpdateInformationWindows().getPointer()); } if (updateGraphicsFlag) { EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().addToolBar().addToolBox().getPointer()); } } connectome-workbench-1.4.2/src/GuiQt/GuiManager.h000066400000000000000000000325071360521144700216520ustar00rootroot00000000000000 #ifndef __GUI_MANAGER_H__ #define __GUI_MANAGER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include "DataFileTypeEnum.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" class QAction; class QDialog; class QMenu; class QWidget; class MovieDialog; class WuQWebView; namespace caret { class Brain; class BrainBrowserWindow; class BrowserTabContent; class BugReportDialog; class ChartTwoLineSeriesHistoryDialog; class ClippingPlanesDialog; class CursorManager; class CustomViewDialog; class GapsAndMarginsDialog; class HelpViewerDialog; class IdentifyBrainordinateDialog; class ImageFile; class ImageCaptureDialog; class InformationDisplayDialog; class MovieRecordingDialog; class OverlaySettingsEditorDialog; class Model; class PaletteColorMappingEditorDialog; class PreferencesDialog; class Scene; class SceneDialog; class SceneFile; class SelectionManager; class SpecFile; class SurfacePropertiesEditorDialog; class VolumePropertiesEditorDialog; class TileTabsConfigurationDialog; /** * Manages the graphical user-interface. */ class GuiManager : public QObject, public EventListenerInterface, public SceneableInterface { Q_OBJECT public: static GuiManager* get(); static void createGuiManager(); static void deleteGuiManager(); static void beep(); static void updateUserInterface(); static void updateGraphicsAllWindows(); static void updateGraphicsOneWindow(const int32_t windowIndex); static void updateSurfaceColoring(); Brain* getBrain() const; int32_t getNumberOfOpenBrainBrowserWindows() const; BrainBrowserWindow* getActiveBrowserWindow() const; std::vector getAllOpenBrainBrowserWindows() const; std::vector getAllOpenBrainBrowserWindowIndices() const; BrainBrowserWindow* getBrowserWindowByWindowIndex(const int32_t browserWindowIndex); bool allowBrainBrowserWindowToClose(BrainBrowserWindow* bbw, const int32_t numberOfOpenTabs); bool exitProgram(BrainBrowserWindow* parent); bool processShowOpenSpecFileDialog(SpecFile* specFile, BrainBrowserWindow* browserWindow); void processShowSaveManageFilesDialog(BrainBrowserWindow* browserWindow); BrowserTabContent* getBrowserTabContentForBrowserWindow(const int32_t browserWindowIndex, const bool allowInvalidBrowserWindowIndex); Model* getModelInBrowserWindow(const int32_t browserWindowIndex); void receiveEvent(Event* event); const CursorManager* getCursorManager() const; QAction* getInformationDisplayDialogEnabledAction(); QAction* getIdentifyBrainordinateDialogDisplayAction(); QAction* getSceneDialogDisplayAction(); QAction* getHelpViewerDialogDisplayAction(); QAction* getDataToolTipsAction(QWidget* buttonWidget); void closeAllOtherWindows(BrainBrowserWindow* browserWindow); void closeOtherWindowsAndReturnTheirTabContent(BrainBrowserWindow* browserWindow, std::vector& tabContents); void processShowBugReportDialog(BrainBrowserWindow* browserWindow, const AString& openGLInformation); void processShowClippingPlanesDialog(BrainBrowserWindow* browserWindow); void processShowCustomViewDialog(BrainBrowserWindow* browserWindow); void processShowGapsAndMarginsDialog(BrainBrowserWindow* browserWindow); void processShowImageCaptureDialog(BrainBrowserWindow* browserWindow); void processShowMovieRecordingDialog(BrainBrowserWindow* browserWindow); void processShowMovieDialog(BrainBrowserWindow* browserWindow); void processShowPreferencesDialog(BrainBrowserWindow* browserWindow); void processShowInformationDisplayDialog(const bool forceDisplayOfDialog); void processShowTileTabsConfigurationDialog(BrainBrowserWindow* browserWindow); void showHideIdentfyBrainordinateDialog(const bool status, BrainBrowserWindow* parentBrainBrowserWindow); void processShowSceneDialog(BrainBrowserWindow* browserWindow); void processShowSurfacePropertiesEditorDialog(BrainBrowserWindow* browserWindow); void processShowVolumePropertiesEditorDialog(BrainBrowserWindow* browserWindow); void processShowSceneDialogAndScene(BrainBrowserWindow* browserWindow, SceneFile* sceneFile, Scene* scene, const bool showSceneDialogFlag); void processShowAllenDataBaseWebView(BrainBrowserWindow* browserWindow); void processShowConnectomeDataBaseWebView(BrainBrowserWindow* browserWindow); void updateAnimationStartTime(double value); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); AString getNameOfDataFileToOpenAfterStartup() const; void processIdentification(const int32_t tabIndex, SelectionManager* selectionManager, QWidget* parentWidget); /* * Mode used when testing for modified files */ enum TestModifiedMode { /** Testing when user is exiting Workbench */ TEST_FOR_MODIFIED_FILES_MODE_FOR_EXIT, /** Testing when a scene is added for modified but not palette modified */ TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD, /** Testing when a scene is added for modified palettes only */ TEST_FOR_MODIFIED_FILES_PALETTE_ONLY_MODE_FOR_SCENE_ADD, /** Testing when a scene is shown */ TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_SHOW }; bool testForModifiedFiles(const TestModifiedMode testModifiedMode, AString& textMesssageOut, AString& modifiedFilesMessageOut) const; public slots: void processBringAllWindowsToFront(); void processShowInformationWindow(); void processTileWindows(); void showHideInfoWindowSelected(bool); void showIdentifyBrainordinateDialogActionToggled(bool); void sceneDialogDisplayActionTriggered(bool); void showHelpDialogActionToggled(bool); private slots: void helpDialogWasClosed(); void sceneDialogWasClosed(); void identifyBrainordinateDialogWasClosed(); void dataToolTipsActionTriggered(bool); private: GuiManager(QObject* parent = 0); virtual ~GuiManager(); GuiManager(const GuiManager&); GuiManager& operator=(const GuiManager&); void initializeGuiManager(); BrainBrowserWindow* newBrainBrowserWindow(QWidget* parent, const int32_t useWindowIndex, BrowserTabContent* browserTabContent, const bool createDefaultTabs, AString& errorMessageOut); void reparentNonModalDialogs(BrainBrowserWindow* closingBrainBrowserWindow); void showHideSceneDialog(const bool status, BrainBrowserWindow* parentBrainBrowserWindow); void showHideHelpDialog(const bool status, const BrainBrowserWindow* parentBrainBrowserWindow); void addNonModalDialog(QWidget* dialog); void updateNonModalDialogs(); void addParentLessNonModalDialog(QWidget* dialog); QPixmap createDataToolTipsIcon(const QWidget* widget); /** One instance of the GuiManager */ static GuiManager* singletonGuiManager; /** Contains pointers to Brain Browser windows */ std::vector m_brainBrowserWindows; /** Skips confirmation of browser window closing when all tabs are moved to one window */ bool allowBrowserWindowsToCloseWithoutConfirmation; /* Editor for overlay settings. */ std::set m_overlaySettingsEditors; /** Editor for palette color mapping editing */ PaletteColorMappingEditorDialog* m_paletteColorMappingEditor; ChartTwoLineSeriesHistoryDialog* m_chartTwoLineSeriesHistoryDialog; TileTabsConfigurationDialog* m_tileTabsConfigurationDialog; ClippingPlanesDialog* m_clippingPlanesDialog; CustomViewDialog* m_customViewDialog; ImageCaptureDialog* imageCaptureDialog; MovieRecordingDialog* m_movieRecordingDialog; GapsAndMarginsDialog* m_gapsAndMarginsDialog; MovieDialog* movieDialog; PreferencesDialog* preferencesDialog; InformationDisplayDialog* m_informationDisplayDialog; IdentifyBrainordinateDialog* m_identifyBrainordinateDialog; SceneDialog* sceneDialog; QAction* m_sceneDialogDisplayAction; SurfacePropertiesEditorDialog* m_surfacePropertiesEditorDialog; VolumePropertiesEditorDialog* m_volumePropertiesEditorDialog; WuQWebView* connectomeDatabaseWebView; CursorManager* cursorManager; QAction* m_informationDisplayDialogEnabledAction; QAction* m_identifyBrainordinateDialogEnabledAction; QAction* m_dataToolTipsEnabledAction; BugReportDialog* m_bugReportDialog; QAction* m_helpViewerDialogDisplayAction; HelpViewerDialog* m_helpViewerDialog; /** * Tracks non-modal dialogs that are created only one time * and may need to be reparented if the original parent, a * BrainBrowserWindow is closed in which case the dialog * is reparented to a different BrainBrowserWindow. * * On Linux and Windows, behavior is that when a dialog becomes active, * its parent window is brought forward to be directly behind the * dialog. When there are multiple browser windows, this may cause * the parent browser window to be brought forward and obscure * a browser window (not a parent of the dialog) that the user * was viewing. In this case, it may be desirable to make * the dialog parent-less. */ std::set nonModalDialogs; /** * Tracks non-modal dialogs WITHOUT parents. Dialogs without parents * are undesirable on Mac because when the parent-less dialog is * the active window, the menu bar will disappear. See the * comment for 'nonModalDialogs' for more information. */ std::set m_parentlessNonModalDialogs; /** * If Workbench is started by double-clicking a data file in * the Mac OSX Finder, this will contain the name of the data * file. When the event is received, Workbench has not yet * created windows. After creating the first Browser Window, * the values of this string is requested, and if valid, * the data file is opened. */ AString m_nameOfDataFileToOpenAfterStartup; }; #ifdef __GUI_MANAGER_DEFINE__ GuiManager* GuiManager::singletonGuiManager = NULL; #endif // __GUI_MANAGER_DEFINE__ } #endif // __GUI_MANAGER_H__ connectome-workbench-1.4.2/src/GuiQt/HelpViewerDialog.cxx000066400000000000000000001112341360521144700233730ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __HELP_VIEWER_DIALOG_DECLARE__ #include "HelpViewerDialog.h" #undef __HELP_VIEWER_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include #include #if QT_VERSION >= 0x050000 #include #include #else // QT_VERSION #include #include #endif // QT_VERSION #include #include #include #include #include #include #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "CommandOperation.h" #include "CommandOperationManager.h" #include "FileInformation.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::HelpViewerDialog * \brief Dialog that displays the applications help information. * \ingroup GuiQt */ /** * Constructor. * * @param parent * Parent of this dialog. * @param f * Qt's window flags. */ HelpViewerDialog::HelpViewerDialog(QWidget* parent, Qt::WindowFlags f) : WuQDialogNonModal("Help", parent, f) { m_helpBrowser = NULL; m_topicSearchLineEditFirstMouseClick = true; setApplyButtonText(""); QTabWidget* indexSearchTabWidget = new QTabWidget(); indexSearchTabWidget->addTab(createTableOfContentsWidget(), "Table of Contents"); indexSearchTabWidget->addTab(createIndexSearchWidget(), "Search"); /* * Need some space above the tab widget */ QWidget* indexSearchWidget = new QWidget(); QVBoxLayout* indexSearchLayout = new QVBoxLayout(indexSearchWidget); indexSearchLayout->addWidget(indexSearchTabWidget); /* * Create the splitter and add the widgets to the splitter */ m_splitter = new QSplitter; m_splitter->setOrientation(Qt::Horizontal); m_splitter->addWidget(indexSearchWidget); m_splitter->addWidget(createHelpViewerWidget()); QList sizeList; sizeList << 225 << 375; m_splitter->setSizes(sizeList); setCentralWidget(m_splitter, WuQDialog::SCROLL_AREA_NEVER); loadHelpTopicsIntoIndexTree(); loadSearchListWidget(); resize(800, 600); } /** * Destructor. */ HelpViewerDialog::~HelpViewerDialog() { } /** * Update the content of the dialog. */ void HelpViewerDialog::updateDialog() { } /** * @return Create and return the table of contents widget. */ QWidget* HelpViewerDialog::createTableOfContentsWidget() { /* * Create the tree widget for the help topics */ m_topicIndexTreeWidget = new QTreeWidget; m_topicIndexTreeWidget->setColumnCount(1); m_topicIndexTreeWidget->setColumnHidden(0, false); m_topicIndexTreeWidget->headerItem()->setHidden(true); QObject::connect(m_topicIndexTreeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), this, SLOT(topicIndexTreeItemChanged(QTreeWidgetItem*, QTreeWidgetItem*))); /* * Collapse All button */ QAction* collapseAllAction = WuQtUtilities::createAction("Collapse All", "", this, this, SLOT(topicCollapseAllTriggered())); QToolButton* collapseAllToolButton = new QToolButton; collapseAllToolButton->setDefaultAction(collapseAllAction); /* * Expand All button */ QAction* expandAllAction = WuQtUtilities::createAction("Expand All", "", this, this, SLOT(topicExpandAllTriggered())); QToolButton* expandAllToolButton = new QToolButton; expandAllToolButton->setDefaultAction(expandAllAction); /* * Layout for collapse/expand all buttons */ QHBoxLayout* collapseExpandLayout = new QHBoxLayout; collapseExpandLayout->addStretch(); collapseExpandLayout->addWidget(collapseAllToolButton); collapseExpandLayout->addWidget(expandAllToolButton); collapseExpandLayout->addStretch(); /* * Layout for search line edit and topics */ QWidget* topicWidgets = new QWidget(); QVBoxLayout* topicLayout = new QVBoxLayout(topicWidgets); WuQtUtilities::setLayoutMargins(topicLayout, 0); topicLayout->addLayout(collapseExpandLayout); topicLayout->addWidget(m_topicIndexTreeWidget); return topicWidgets; } /** * @return Create and return the search widget. */ QWidget* HelpViewerDialog::createIndexSearchWidget() { /* * Search line edit and list widget */ const AString searchText = ("All searches are case insensitive.\n" "\n" "You may use wildcard characters:\n" " * - Matches any characters.\n" " ? - Matches a single character.\n"); const AString topicSearchToolTipText = ("Enter text to search content of ALL help pages.\n" + searchText); m_topicSearchLineEdit = new QLineEdit; m_topicSearchLineEdit->setToolTip(topicSearchToolTipText.convertToHtmlPage()); QObject::connect(m_topicSearchLineEdit, SIGNAL(returnPressed()), this, SLOT(topicSearchLineEditStartSearch())); QObject::connect(m_topicSearchLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(topicSearchLineEditStartSearch())); QObject::connect(m_topicSearchLineEdit, SIGNAL(cursorPositionChanged(int,int)), this, SLOT(topicSearchLineEditCursorPositionChanged(int,int))); /* * List widget containing matched topics */ m_topicSearchListWidget = new QListWidget(); m_topicSearchListWidget->setSortingEnabled(false); QObject::connect(m_topicSearchListWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(topicSearchListWidgetItemClicked(QListWidgetItem*))); /* * Layout for search line edit and topics */ QWidget* searchWidgets = new QWidget(); QVBoxLayout* searchLayout = new QVBoxLayout(searchWidgets); WuQtUtilities::setLayoutSpacingAndMargins(searchLayout, 4, 2); searchLayout->addWidget(m_topicSearchLineEdit); searchLayout->addWidget(m_topicSearchListWidget); return searchWidgets; } /** * @return Create and return the help viewer widget. */ QWidget* HelpViewerDialog::createHelpViewerWidget() { /* DISPLAY HELP SECTION */ /* * create the back toolbar button */ QToolButton* backwardButton = new QToolButton; backwardButton->setArrowType(Qt::LeftArrow); backwardButton->setToolTip("Show the previous page"); /* * Create the forward toolbar button */ QToolButton* forwardButton = new QToolButton; forwardButton->setArrowType(Qt::RightArrow); forwardButton->setToolTip("Show the next page"); /* * Create the print toolbar button */ QToolButton* printButton = new QToolButton; connect(printButton, SIGNAL(clicked()), this, SLOT(helpPagePrintButtonClicked())); printButton->setText("Print"); /** * Copy button */ QToolButton* copyButton = new QToolButton; copyButton->setText("Copy"); copyButton->setToolTip("Copies selected help text to clipboard."); copyButton->setEnabled(false); /* * create the help browser */ m_helpBrowser = new HelpTextBrowser(this); m_helpBrowser->setMinimumWidth(400); m_helpBrowser->setMinimumHeight(200); m_helpBrowser->setOpenExternalLinks(false); m_helpBrowser->setOpenLinks(true); QObject::connect(forwardButton, SIGNAL(clicked()), m_helpBrowser, SLOT(forward())); QObject::connect(backwardButton, SIGNAL(clicked()), m_helpBrowser, SLOT(backward())); /* * Hook up copy button to help browser */ QObject::connect(m_helpBrowser, SIGNAL(copyAvailable(bool)), copyButton, SLOT(setEnabled(bool))); QObject::connect(copyButton, SIGNAL(clicked()), m_helpBrowser, SLOT(copy())); /* * Layout for toolbuttons */ QHBoxLayout* toolButtonLayout = new QHBoxLayout; toolButtonLayout->addWidget(new QLabel("Navigate:")); toolButtonLayout->addWidget(backwardButton); toolButtonLayout->addWidget(forwardButton); toolButtonLayout->addStretch(); toolButtonLayout->addWidget(copyButton); toolButtonLayout->addWidget(printButton); /* * Layout for help browser and buttons */ QWidget* helpBrowserWidgets = new QWidget; QVBoxLayout* helpBrowserLayout = new QVBoxLayout(helpBrowserWidgets); helpBrowserLayout->addLayout(toolButtonLayout); helpBrowserLayout->addWidget(m_helpBrowser); return helpBrowserWidgets; } /** * Show the help page with the given name. * * @param helpPageName * Name of help page. */ void HelpViewerDialog::showHelpPageWithName(const AString& helpPageName) { const AString pageName = QString(helpPageName).replace('_', ' '); if (pageName.isEmpty()) { return; } for (auto searchItem : m_allHelpSearchListWidgetItems) { CaretAssert(searchItem); HelpTreeWidgetItem* helpItem = searchItem->m_matchingTreeWidgetItem; if (helpItem != NULL) { if (helpItem->text(0) == pageName) { displayHelpTextForHelpTreeWidgetItem(helpItem); return; } } } WuQMessageBox::errorOk(this, "Error: Help page \"" + helpPageName + "\" not found."); } /** * Load Workbench help from the given directory and add it to the * the given parent. Also process any subdirectories * * @param parent * Parent tree widget item * @param dirInfo * The directory examined for HTML pages and subdirectories * @return * Tree widget item that was created. */ HelpTreeWidgetItem* HelpViewerDialog::loadWorkbenchHelpInfoFromDirectory(QTreeWidgetItem* parent, const QFileInfo& dirInfo) { QDir directory(dirInfo.absoluteFilePath()); /* * Get all HTML pages in the directory * and file an HTML page that is the same * name as the directory. */ QStringList htmlNameFilter; htmlNameFilter << "*.htm" << "*.html"; QFileInfoList htmlFileList = directory.entryInfoList(htmlNameFilter, QDir::Files, QDir::Name); QString dirHtmlPageName; QFileInfoList otherHtmlPagesList; QListIterator htmlFileIter(htmlFileList); while (htmlFileIter.hasNext()) { const QFileInfo htmlFileInfo = htmlFileIter.next(); if (htmlFileInfo.baseName() == dirInfo.baseName()) { dirHtmlPageName = htmlFileInfo.absoluteFilePath(); } else { otherHtmlPagesList.append(htmlFileInfo.absoluteFilePath()); } } /* * Create a tree widget item for this directory * that may have a help page. */ HelpTreeWidgetItem* treeItem = NULL; if ( ! dirHtmlPageName.isEmpty()) { treeItem = createHelpTreeWidgetItemForHelpPage(parent, dirInfo.baseName(), dirHtmlPageName); } else { QString text = dirInfo.fileName(); text = text.replace('_', ' '); treeItem = HelpTreeWidgetItem::newInstanceEmptyItem(parent, text); } /* * Add items for any other HTML pages found in the directory */ QListIterator otherHtmlPageIter(otherHtmlPagesList); while (otherHtmlPageIter.hasNext()) { // const QFileInfo pageInfo = otherHtmlPageIter.next(); // createHelpTreeWidgetItemForHelpPage(treeItem, // pageInfo.baseName(), // pageInfo.absoluteFilePath()); const QFileInfo qtPageInfo = otherHtmlPageIter.next(); const FileInformation pageInfo(qtPageInfo.absoluteFilePath()); createHelpTreeWidgetItemForHelpPage(treeItem, pageInfo.getFileNameNoExtension(), qtPageInfo.absoluteFilePath()); } /* * Add any subdirectories as children */ QFileInfoList subDirList = directory.entryInfoList((QDir::AllDirs | QDir::NoDotAndDotDot), QDir::Name); QListIterator subDirIter(subDirList); while (subDirIter.hasNext()) { const QFileInfo subDirInfo = subDirIter.next(); const QString name = subDirInfo.fileName(); if (name.endsWith(".fld")) { /* * Ignore directories ending in ".fld" which is created when * a Microsoft Word file is saved as HTML. The ".fld" * directory contains image files from the Word file. */ } else { loadWorkbenchHelpInfoFromDirectory(treeItem, subDirInfo); } } return treeItem; } /** * load the index tree with the help topics. */ void HelpViewerDialog::loadHelpTopicsIntoIndexTree() { m_topicIndexTreeWidget->blockSignals(true); QTreeWidgetItem* workbenchItem = new QTreeWidgetItem(m_topicIndexTreeWidget, TREE_ITEM_NONE); workbenchItem->setText(0, "wb_view"); QDir resourceHelpDirectory(":/HelpFiles"); QTreeWidgetItem* bestPracticesItem = NULL; QTreeWidgetItem* glossaryItem = NULL; QFileInfoList subDirList = resourceHelpDirectory.entryInfoList((QDir::AllDirs | QDir::NoDotAndDotDot), QDir::Name); QListIterator subDirIter(subDirList); while (subDirIter.hasNext()) { const QFileInfo subDirInfo = subDirIter.next(); HelpTreeWidgetItem* item = loadWorkbenchHelpInfoFromDirectory(workbenchItem, subDirInfo); /* * Is this the Best Practices? * If so, move it so that it is a top level item. */ if (subDirInfo.baseName().toLower() == "best_practices_guides") { if (bestPracticesItem != NULL) { CaretAssertMessage(0, "There should be only one best practices subdirectory !!!!"); } bestPracticesItem = item; workbenchItem->removeChild(bestPracticesItem); } /* * Is this the GLOSSARY? * If so, move it so that it is a top level item. */ if (subDirInfo.baseName().toLower() == "glossary") { if (glossaryItem != NULL) { CaretAssertMessage(0, "There should be only one glossary subdirectory !!!!"); } glossaryItem = item; workbenchItem->removeChild(glossaryItem); } } if (bestPracticesItem != NULL) { m_topicIndexTreeWidget->addTopLevelItem(bestPracticesItem); } if (glossaryItem != NULL) { m_topicIndexTreeWidget->addTopLevelItem(glossaryItem); } /* * Load commands */ CommandOperationManager* commandOperationManager = CommandOperationManager::getCommandOperationManager(); std::vector commandOperations = commandOperationManager->getCommandOperations(); QTreeWidgetItem* wbCommandItem = NULL; if ( ! commandOperations.empty()) { /* * Use map to sort commands by short description */ std::map sortCommandsMap; for (std::vector::iterator vecIter = commandOperations.begin(); vecIter != commandOperations.end(); vecIter++) { CommandOperation* op = *vecIter; sortCommandsMap.insert(std::make_pair(op->getCommandLineSwitch(), op)); } wbCommandItem = new QTreeWidgetItem(m_topicIndexTreeWidget, TREE_ITEM_NONE); wbCommandItem->setText(0, "wb_command"); QFont commandFont = wbCommandItem->font(0); commandFont.setPointSize(10); for (std::map::iterator mapIter = sortCommandsMap.begin(); mapIter != sortCommandsMap.end(); mapIter++) { CommandOperation* op = mapIter->second; HelpTreeWidgetItem* item = HelpTreeWidgetItem::newInstanceForCommandOperation(wbCommandItem, op); item->setFont(0, commandFont); addToAllItems(item); } } /* * Using setExpanded on a QTreeWidgetItem only expands its immediate children. * So, expand everything and then collapse Glossary and wb_command items so * that only wb_view items are expanded. */ m_topicIndexTreeWidget->expandAll(); if (glossaryItem != NULL) { glossaryItem->setExpanded(false); } if (wbCommandItem != NULL) { wbCommandItem->setExpanded(false); } m_topicIndexTreeWidget->sortItems(0, Qt::AscendingOrder); m_topicIndexTreeWidget->blockSignals(false); } /** * Add an item to the menu's item. * If the given item is NULL, it was not found an an error message will * be logged. * * @param parentMenu * The parent menu item. * @param item * The item that is added to the parent menu. * @param itemName * Name for item. */ void HelpViewerDialog::addItemToParentMenu(QTreeWidgetItem* parentMenu, QTreeWidgetItem* item, const AString& itemName) { CaretAssert(parentMenu); if (item != NULL) { if ( ! itemName.isEmpty()) { item->setText(0, itemName); } parentMenu->addChild(item); } else { CaretLogSevere("Did not find help for menu: " + itemName); } } /** * Create a help tree widget item for a help page URL. * * @param parent * Parent for item in index. * @param itemText * Text for the item shown in the topic index. * @param helpPageURL * URL for the help page. */ HelpTreeWidgetItem* HelpViewerDialog::createHelpTreeWidgetItemForHelpPage(QTreeWidgetItem* parent, const AString& itemText, const AString& helpPageURL) { HelpTreeWidgetItem* helpItem = HelpTreeWidgetItem::newInstanceForHtmlHelpPage(parent, itemText, helpPageURL); addToAllItems(helpItem); return helpItem; } /** * Called when selected index tree item changes. * * @param currentItem * The selected item * @param previousItem * The previously selected item */ void HelpViewerDialog::topicIndexTreeItemChanged(QTreeWidgetItem* currentItem, QTreeWidgetItem* /*previousItem*/) { if (currentItem != NULL) { /* * Note not all items are castable to HelpTreeWidgetItem. * Items not castable are category items that have an arrow to * expand/collapse its children. */ HelpTreeWidgetItem* helpItem = dynamic_cast(currentItem); if (helpItem != NULL) { displayHelpTextForHelpTreeWidgetItem(helpItem); m_topicIndexTreeWidget->scrollToItem(helpItem, QTreeWidget::EnsureVisible); } else { const AString html = AString(currentItem->text(0)).convertToHtmlPage(); m_helpBrowser->setHtml(html); } } } /** * Add the help item to all items and to the search list widget. * * @helpItem * Help item to add. */ void HelpViewerDialog::addToAllItems(HelpTreeWidgetItem* helpItem) { m_allHelpTreeWidgetItems.push_back(helpItem); } /** * Load the search list widget. List all Workbench items in alphabetical * order followed by all commands in alphabetical order. */ void HelpViewerDialog::loadSearchListWidget() { std::vector commandItems; std::vector workbenchItems; for (std::vector::iterator allIter = m_allHelpTreeWidgetItems.begin(); allIter != m_allHelpTreeWidgetItems.end(); allIter++) { HelpTreeWidgetItem* treeItem = *allIter; switch (treeItem->m_treeItemType) { case HelpTreeWidgetItem::TREE_ITEM_NONE: /* * Do not allow in search */ continue; break; case HelpTreeWidgetItem::TREE_ITEM_HELP_PAGE_URL: break; case HelpTreeWidgetItem::TREE_ITEM_HELP_TEXT: break; } HelpSearchListItem* searchItem = new HelpSearchListItem(treeItem); m_allHelpSearchListWidgetItems.push_back(searchItem); if (treeItem->text(0).startsWith("-")) { commandItems.push_back(searchItem); } else { workbenchItems.push_back(searchItem); } } std::sort(commandItems.begin(), commandItems.end(), HelpSearchListItem::sortAlphabetically); std::sort(workbenchItems.begin(), workbenchItems.end(), HelpSearchListItem::sortAlphabetically); for (std::vector::iterator wbIter = workbenchItems.begin(); wbIter != workbenchItems.end(); wbIter++) { m_topicSearchListWidget->addItem(*wbIter); } for (std::vector::iterator cmdIter = commandItems.begin(); cmdIter != commandItems.end(); cmdIter++) { m_topicSearchListWidget->addItem(*cmdIter); } } /** * Called when an item in the search list widget is clicked. * * @param item * The selected item */ void HelpViewerDialog::topicSearchListWidgetItemClicked(QListWidgetItem* item) { HelpSearchListItem* searchItem = dynamic_cast(item); if (searchItem != NULL) { HelpTreeWidgetItem* helpItem = searchItem->m_matchingTreeWidgetItem; if (helpItem != NULL) { displayHelpTextForHelpTreeWidgetItem(helpItem); } } } /** * Display the help information for the given help item. * * @param helpItem * Item for which help text is loaded. */ void HelpViewerDialog::displayHelpTextForHelpTreeWidgetItem(HelpTreeWidgetItem* helpItem) { CaretAssert(helpItem); m_helpBrowser->setSource(helpItem->m_helpPageURL); } /** * Called when search text is changed or return pressed to start * searching the help topics */ void HelpViewerDialog::topicSearchLineEditStartSearch() { const QString searchText = m_topicSearchLineEdit->text().trimmed(); const bool haveSearchTextFlag = ( ! searchText.isEmpty()); QRegExp regEx; bool haveWildcardSearchFlag = false; if (haveSearchTextFlag) { if (searchText.contains('*') || searchText.contains('?')) { haveWildcardSearchFlag = true; regEx.setPatternSyntax(QRegExp::Wildcard); regEx.setPattern(searchText); regEx.setCaseSensitivity(Qt::CaseInsensitive); } } for (std::vector::iterator iter = m_allHelpSearchListWidgetItems.begin(); iter != m_allHelpSearchListWidgetItems.end(); iter++) { HelpSearchListItem* helpListItem = *iter; CaretAssert(helpListItem); HelpTreeWidgetItem* helpTreeItem = helpListItem->m_matchingTreeWidgetItem; CaretAssert(helpTreeItem); bool showItemFlag = true; if (haveSearchTextFlag) { showItemFlag = false; if (haveWildcardSearchFlag) { if (regEx.exactMatch(helpTreeItem->m_helpText)) { showItemFlag = true; } } else if (helpTreeItem->m_helpText.contains(searchText, Qt::CaseInsensitive)) { showItemFlag = true; } } helpListItem->setHidden( ! showItemFlag); } } /** * called to print currently displayed page. */ void HelpViewerDialog::helpPagePrintButtonClicked() { QPrinter printer; QPrintDialog* printDialog = new QPrintDialog(&printer, this); if (printDialog->exec() == QPrintDialog::Accepted) { m_helpBrowser->document()->print(&printer); } } /** * Called when the cursor position is changed */ void HelpViewerDialog::topicSearchLineEditCursorPositionChanged(int,int) { if (m_topicSearchLineEditFirstMouseClick) { m_topicSearchLineEditFirstMouseClick = false; m_topicSearchLineEdit->clear(); topicSearchLineEditStartSearch(); } } /** * Expand all help topics */ void HelpViewerDialog::topicExpandAllTriggered() { m_topicIndexTreeWidget->expandAll(); } /** * Collapse all help topics */ void HelpViewerDialog::topicCollapseAllTriggered() { m_topicIndexTreeWidget->collapseAll(); } // ========================================================================= // /** * Create a help viewer widget. * * @param parentHelpViewerDialog * The parent help viewer dialog. */ HelpTextBrowser::HelpTextBrowser(HelpViewerDialog* parentHelpViewerDialog) : QTextBrowser(parentHelpViewerDialog), m_parentHelpViewerDialog(parentHelpViewerDialog) { CaretAssert(parentHelpViewerDialog); } /** * Destructor. */ HelpTextBrowser::~HelpTextBrowser() { } /** * Overrides superclass version so that images get loaded properly. * Setting search paths may eliminate need for this method. * * @param type * Type of resource. * @param url * URL of resource. * @return * QVariant containing content for display in the help viewer. */ QVariant HelpTextBrowser::loadResource(int type, const QUrl& url) { const QString urlText = url.toString(); QVariant result; for (std::vector::iterator iter = m_parentHelpViewerDialog->m_allHelpTreeWidgetItems.begin(); iter != m_parentHelpViewerDialog->m_allHelpTreeWidgetItems.end(); iter++) { HelpTreeWidgetItem* treeItem = *iter; if (treeItem->m_helpPageURL == urlText) { result = treeItem->m_helpText; break; } } if ( ! result.isValid()) { result = QTextBrowser::loadResource(type, url); if (result.isValid()) { /* nothing */ } else { QString typeName("Unknown"); if ( ! result.isValid()) { switch (type) { case QTextDocument::HtmlResource: typeName = "Html Resource"; break; case QTextDocument::ImageResource: typeName = "Image Resource"; break; case QTextDocument::StyleSheetResource: typeName = "Style Sheet Resource"; break; } } CaretLogSevere("Failed to load type: " + typeName + " file: " + url.toString()); } } return result; } /** * Set the source of the help browser. * * @param url * URL directing to content. */ void HelpTextBrowser::setSource(const QUrl& url) { const AString urlText = url.toString(); if (urlText.startsWith("http:")) { if (WuQMessageBox::warningOkCancel(this, "The link clicked will be displayed in your web browser.")) { if ( ! QDesktopServices::openUrl(urlText)) { WuQMessageBox::errorOk(this, ("Failed to load " + urlText)); } } } else if (urlText.startsWith("mailto")) { if (WuQMessageBox::warningOkCancel(this, "This link will open your mail client.")) { if ( ! QDesktopServices::openUrl(urlText)) { WuQMessageBox::errorOk(this, ("Failed to load " + urlText)); } } } else { QTextBrowser::setSource(url); } } // ========================================================================= // /** * Create a new help tree widget item for a wb_command item. * * @param parent * Parent for item in index. * @param commandOperation * The command. */ HelpTreeWidgetItem* HelpTreeWidgetItem::newInstanceForCommandOperation(QTreeWidgetItem* parent, CommandOperation* commandOperation) { const AString itemText = commandOperation->getCommandLineSwitch(); const AString helpInfoCopy = commandOperation->getHelpInformation("wb_command"); const AString helpText = helpInfoCopy.convertToHtmlPageWithFontSize(2); const AString helpPageURL("command:/" + commandOperation->getOperationShortDescription().replace(' ', '_')); HelpTreeWidgetItem* instance = new HelpTreeWidgetItem(parent, TREE_ITEM_HELP_TEXT, itemText, helpPageURL, helpText); return instance; } /** * Create a new help tree widget item for a help page URL. * * @param parent * Parent for item in index. * @param itemText * Text for the item shown in the topic index. * @param helpPageURL * URL for the help page. */ HelpTreeWidgetItem* HelpTreeWidgetItem::newInstanceForHtmlHelpPage(QTreeWidgetItem* parent, const AString& itemText, const AString& helpPageURL) { CaretAssertMessage( ( ! itemText.startsWith(":/")), "All help pages must be resources (page name starts with \":/\")"); QString helpText; QFile file(helpPageURL); if (file.exists()) { if (file.open(QFile::ReadOnly)) { QTextStream stream(&file); helpText = stream.readAll(); file.close(); } else { AString msg = ("Help file exists but unable to open for reading: " + helpPageURL); CaretLogSevere(msg); helpText = msg.convertToHtmlPage(); } } else { AString msg = ("HTML Help file missing: " + helpPageURL); CaretLogSevere(msg); helpText = msg.convertToHtmlPage(); } HelpTreeWidgetItem* instance = NULL; AString text = itemText; text = text.replace('_', ' '); if (parent != NULL) { instance = new HelpTreeWidgetItem(parent, TREE_ITEM_HELP_TEXT, text, "qrc" + helpPageURL, helpText); } else { instance = new HelpTreeWidgetItem(TREE_ITEM_HELP_TEXT, text, "qrc" + helpPageURL, helpText); } return instance; } /** * Constructor for item with parent but only a name. * * @param parent * Parent for item in index. * @param itemText * Text for the item shown in the topic index. */ HelpTreeWidgetItem* HelpTreeWidgetItem::newInstanceEmptyItem(QTreeWidgetItem* parent, const AString& itemText) { HelpTreeWidgetItem* item = new HelpTreeWidgetItem(parent, TREE_ITEM_NONE, itemText, "", ""); return item; } /** * Constructor for item with parent * * @param parent * Parent for item in index. * @param treeItemType * Type of tree item. * @param itemText * Text for the item shown in the topic index. * @param helpPageURL * URL for external help pages * @param helpText * Text displayed in help browser. */ HelpTreeWidgetItem::HelpTreeWidgetItem(QTreeWidgetItem* parent, const TreeItemType treeItemType, const AString& itemText, const AString& helpPageURL, const AString& helpText) : QTreeWidgetItem(parent), m_treeItemType(treeItemType), m_helpPageURL(helpPageURL), m_helpText(helpText) { setText(0, itemText); } /** * Constructor for item WITHOUT parent * * @param treeItemType * Type of tree item. * @param itemText * Text for the item shown in the topic index. * @param helpPageURL * URL for external help pages * @param helpText * Text displayed in help browser. */ HelpTreeWidgetItem::HelpTreeWidgetItem(const TreeItemType treeItemType, const AString& itemText, const AString& helpPageURL, const AString& helpText) : QTreeWidgetItem(), m_treeItemType(treeItemType), m_helpPageURL(helpPageURL), m_helpText(helpText) { setText(0, itemText); } /** * Destructor. */ HelpTreeWidgetItem::~HelpTreeWidgetItem() { } // ========================================================================= // /** * Constructs a list widget item for use during search operation * * @param matchingTreeWidgetItem * The matching tree widget item that contains the help information. */ HelpSearchListItem::HelpSearchListItem(HelpTreeWidgetItem* matchingTreeWidgetItem) { CaretAssert(matchingTreeWidgetItem); m_matchingTreeWidgetItem = matchingTreeWidgetItem; setText(m_matchingTreeWidgetItem->text(0)); } /** * Destructor. */ HelpSearchListItem::~HelpSearchListItem() { } /** * Sort the two "pointed to" items alphabetically. * * @param h1 * First item. * @param h2 * Second item. * @return * True if h1 is alphabetically before h2. */ bool HelpSearchListItem::sortAlphabetically(const HelpSearchListItem* h1, const HelpSearchListItem* h2) { CaretAssert(h1); CaretAssert(h2); return (h1->m_matchingTreeWidgetItem->text(0) < h2->m_matchingTreeWidgetItem->text(0)); } connectome-workbench-1.4.2/src/GuiQt/HelpViewerDialog.h000066400000000000000000000156311360521144700230240ustar00rootroot00000000000000#ifndef __HELP_VIEWER_DIALOG_H__ #define __HELP_VIEWER_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "WuQDialogNonModal.h" class QFileInfo; class QLineEdit; class QListWidget; class QSplitter; class QToolButton; class QTreeWidget; class QUrl; namespace caret { class CommandOperation; class HelpSearchListItem; class HelpTreeWidgetItem; class HelpViewerDialog : public WuQDialogNonModal { Q_OBJECT public: HelpViewerDialog(QWidget* parent, Qt::WindowFlags f = 0); virtual ~HelpViewerDialog(); virtual void updateDialog(); void showHelpPageWithName(const AString& helpPageName); // ADD_NEW_METHODS_HERE private slots: void topicIndexTreeItemChanged(QTreeWidgetItem* currentItem, QTreeWidgetItem* previousItem); void helpPagePrintButtonClicked(); void topicSearchLineEditStartSearch(); void topicSearchLineEditCursorPositionChanged(int,int); void topicExpandAllTriggered(); void topicCollapseAllTriggered(); void topicSearchListWidgetItemClicked(QListWidgetItem*); private: enum TreeItemType { TREE_ITEM_NONE, TREE_ITEM_HELP_PAGE, TREE_ITEM_WB_COMMAND }; HelpViewerDialog(const HelpViewerDialog&); HelpViewerDialog& operator=(const HelpViewerDialog&); QWidget* createTableOfContentsWidget(); QWidget* createIndexSearchWidget(); QWidget* createHelpViewerWidget(); void loadHelpTopicsIntoIndexTree(); HelpTreeWidgetItem* createHelpTreeWidgetItemForHelpPage(QTreeWidgetItem* parent, const AString& itemText, const AString& helpPageURL); void displayHelpTextForHelpTreeWidgetItem(HelpTreeWidgetItem* helpItem); void addItemToParentMenu(QTreeWidgetItem* parentMenu, QTreeWidgetItem* item, const AString& itemName); HelpTreeWidgetItem* loadWorkbenchHelpInfoFromDirectory(QTreeWidgetItem* parent, const QFileInfo& dirInfo); void addToAllItems(HelpTreeWidgetItem* helpItem); void loadSearchListWidget(); /// the help browser QTextBrowser* m_helpBrowser; /// the splitter QSplitter* m_splitter; /// the topic index tree widget QTreeWidget* m_topicIndexTreeWidget; /// line edit for searching topics QLineEdit* m_topicSearchLineEdit; QListWidget* m_topicSearchListWidget; /// tracks first mouse click in search topic line edit bool m_topicSearchLineEditFirstMouseClick; /// All help pages in tree widget std::vector m_allHelpTreeWidgetItems; /// All items in search list widget std::vector m_allHelpSearchListWidgetItems; // ADD_NEW_MEMBERS_HERE friend class HelpTextBrowser; }; /** * The help text browser. */ class HelpTextBrowser : public QTextBrowser { Q_OBJECT public: HelpTextBrowser(HelpViewerDialog* parentHelpViewerDialog); virtual ~HelpTextBrowser(); virtual QVariant loadResource(int type, const QUrl& url); virtual void setSource(const QUrl& url); private: HelpViewerDialog* m_parentHelpViewerDialog; }; /** * Base class for items in the tree widget. */ class HelpTreeWidgetItem : public QTreeWidgetItem { public: enum TreeItemType { TREE_ITEM_NONE, TREE_ITEM_HELP_PAGE_URL, TREE_ITEM_HELP_TEXT }; static HelpTreeWidgetItem* newInstanceForCommandOperation(QTreeWidgetItem* parent, CommandOperation* commandOperation); static HelpTreeWidgetItem* newInstanceForHtmlHelpPage(QTreeWidgetItem* parent, const AString& itemText, const AString& helpPageURL); static HelpTreeWidgetItem* newInstanceEmptyItem(QTreeWidgetItem* parent, const AString& itemText); private: HelpTreeWidgetItem(QTreeWidgetItem* parent, const TreeItemType treeItemType, const AString& itemText, const AString& helpPageURL, const AString& helpText); HelpTreeWidgetItem(const TreeItemType treeItemType, const AString& itemText, const AString& helpPageURL, const AString& helpText); public: virtual ~HelpTreeWidgetItem(); const TreeItemType m_treeItemType; const AString m_helpPageURL; const AString m_helpText; }; class HelpSearchListItem : public QListWidgetItem { public: HelpSearchListItem(HelpTreeWidgetItem* matchingTreeWidgetItem); ~HelpSearchListItem(); static bool sortAlphabetically(const HelpSearchListItem* h1, const HelpSearchListItem* h2); HelpTreeWidgetItem* m_matchingTreeWidgetItem; }; #ifdef __HELP_VIEWER_DIALOG_DECLARE__ // #endif // __HELP_VIEWER_DIALOG_DECLARE__ } // namespace #endif //__HELP_VIEWER_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/HyperLinkTextBrowser.cxx000066400000000000000000000107601360521144700243210ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" #include "HyperLinkTextBrowser.h" using namespace caret; /** * \class caret::HyperLinkTextBrowser * \brief Displays HTML text. * \ingroup GuiQt * * Displays HTML text. Input text may contain URLs * which are converted into hyperlinks. */ /** * Constructor */ HyperLinkTextBrowser::HyperLinkTextBrowser(QWidget* parent) : QTextBrowser(parent) { //QT4setTextFormat(QTextBrowser::RichText); } /** * Destructor */ HyperLinkTextBrowser::~HyperLinkTextBrowser() { } /** * Override of QT's QTextBrowser method. * Called when the user clicks a link in this browser. * @param url * User for display. */ void HyperLinkTextBrowser::setSource(const QUrl& url) { const AString s(url.toString()); if (s.startsWith("vocabulary://")) { this->appendHtml("Vocabulary links not supported yet."); // const AString name = s.mid(13); // BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); // const AString idString(bmi->getIdentificationTextForVocabulary(true, name)); // if (idString.isEmpty() == false) { // appendHtml(idString); // } } else { this->appendHtml("Displaying of web pages not supported yet."); // theMainWindow->displayWebPage(s); } } /** * Append text (Override of QT's QTextBrowser method). * Any URLs in text are converted to hyperlinks. */ void HyperLinkTextBrowser::append(const AString& textIn) { // // See if string contains a URL // AString text; if (textIn.indexOf("http://") >= 0) { // // Insert the string with hyperlinks into text browser // text = textIn.convertURLsToHyperlinks(); } else { text = textIn; } text.replace("\n", "
    "); AString displayText = toHtml(); displayText.append("
    "); displayText.append(text); setHtml(displayText); // // Scroll to newest text (at end of scroll bar) // QScrollBar* vsb = verticalScrollBar(); vsb->setValue(vsb->maximum()); } /** * Append html. * @param html * HTML that is appended. */ void HyperLinkTextBrowser::appendHtml(const AString& html) { AString displayText = toHtml(); displayText.append("
    "); displayText.append(html); setHtml(displayText); // // Scroll to newest text (at end of scroll bar) // QScrollBar* vsb = verticalScrollBar(); vsb->setValue(vsb->maximum()); } /** * Set the content of the browser to the given html and then * scroll to the bottom. * * @param html * Html for browser. */ void HyperLinkTextBrowser::setContentToHtml(const AString& html) { this->setHtml(html); // // Scroll to newest text (at end of scroll bar) // QScrollBar* vsb = verticalScrollBar(); vsb->setValue(vsb->maximum()); } /** * Set the content of the browser to the given text and then * scroll to the bottom. * * @param textIn * Text for browser. */ void HyperLinkTextBrowser::setContentToText(const AString& textIn) { // // See if string contains a URL // AString displayText; if (textIn.indexOf("http://") != -1) { // // Insert the string with hyperlinks into text browser // displayText = textIn.convertURLsToHyperlinks(); } else { displayText = textIn; } displayText.replace("\n", "
    "); setHtml(displayText); // // Scroll to newest text (at end of scroll bar) // QScrollBar* vsb = verticalScrollBar(); vsb->setValue(vsb->maximum()); } /** * called if a key is pressed over the text browser. * @param key * Key that is pressed. */ void HyperLinkTextBrowser::keyPressEvent(QKeyEvent* /*e*/) { emit keyPressed(); } connectome-workbench-1.4.2/src/GuiQt/HyperLinkTextBrowser.h000066400000000000000000000032201360521144700237370ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #ifndef __HYPER_LINK_TEXT_BROWSER_H__ #define __HYPER_LINK_TEXT_BROWSER_H__ #include class QKeyEvent; namespace caret { class AString; class HyperLinkTextBrowser : public QTextBrowser { Q_OBJECT public: HyperLinkTextBrowser(QWidget* parent = 0); ~HyperLinkTextBrowser(); void setContentToHtml(const AString& html); void setContentToText(const AString& text); signals: void keyPressed(); public slots: void append(const AString& text); void appendHtml(const AString& html); private slots: void setSource(const QUrl& url); private: void keyPressEvent(QKeyEvent* e); }; } #endif // __HYPER_LINK_TEXT_BROWSER_H__ connectome-workbench-1.4.2/src/GuiQt/IdentifyBrainordinateDialog.cxx000066400000000000000000001150331360521144700255770ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __IDENTIFY_BRAINORDINATE_DIALOG_DECLARE__ #include "IdentifyBrainordinateDialog.h" #undef __IDENTIFY_BRAINORDINATE_DIALOG_DECLARE__ using namespace caret; #include #include #include #include #include #include #include "Brain.h" #include "BrainordinateRegionOfInterest.h" #include "BrainStructure.h" #include "CaretAssert.h" #include "CaretDataFileSelectionComboBox.h" #include "CaretDataFileSelectionModel.h" #include "CaretLogger.h" #include "CiftiFiberTrajectoryFile.h" #include "CaretMappableDataFile.h" #include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileLineSeriesChart.h" #include "ChartableTwoFileMatrixChart.h" #include "CiftiConnectivityMatrixDataFileManager.h" #include "CiftiFiberTrajectoryManager.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "CaretMappableDataFileAndMapSelectionModel.h" #include "CaretMappableDataFileAndMapSelectorObject.h" #include "CiftiParcelSelectionComboBox.h" #include "CiftiScalarDataSeriesFile.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventIdentificationHighlightLocation.h" #include "EventManager.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUpdateInformationWindows.h" #include "EventUserInterfaceUpdate.h" #include "GiftiLabelTableSelectionComboBox.h" #include "GuiManager.h" #include "IdentifiedItemNode.h" #include "IdentificationManager.h" #include "SelectionItemCiftiConnectivityMatrixRowColumn.h" #include "SelectionItemSurfaceNode.h" #include "SelectionItemVoxel.h" #include "SelectionManager.h" #include "SessionManager.h" #include "StructureEnumComboBox.h" #include "Surface.h" #include "SystemUtilities.h" #include "WuQFactory.h" #include "WuQGroupBoxExclusiveWidget.h" #include "WuQMessageBox.h" #include "WuQSpinBox.h" #include "WuQtUtilities.h" #include static const int INDEX_SPIN_BOX_WIDTH = 100; /** * Constructor. */ IdentifyBrainordinateDialog::IdentifyBrainordinateDialog(QWidget* parent) : WuQDialogNonModal("Identify Brainordinate", parent) { /* * Surface Vertex widgets */ m_surfaceVertexWidget = createSurfaceVertexlWidget(); /* * Filter file types for CIFTI type files */ std::vector allDataFileTypes; DataFileTypeEnum::getAllEnums(allDataFileTypes, (DataFileTypeEnum::OPTIONS_INCLUDE_CONNECTIVITY_DENSE_DYNAMIC | DataFileTypeEnum::OPTIONS_INCLUDE_METRIC_DENSE_DYNAMIC | DataFileTypeEnum::OPTIONS_INCLUDE_VOLUME_DENSE_DYNAMIC)); std::vector supportedCiftiRowFileTypes; std::vector supportedLabelFileTypes; for (std::vector::iterator dtIter = allDataFileTypes.begin(); dtIter != allDataFileTypes.end(); dtIter++) { const DataFileTypeEnum::Enum dataFileType = *dtIter; bool ciftiRowFlag = false; bool labelFileFlag = false; ParcelSourceDimension parcelSourceDimension = PARCEL_SOURCE_INVALID_DIMENSION; switch (dataFileType) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: ciftiRowFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: ciftiRowFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: labelFileFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: ciftiRowFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: parcelSourceDimension = PARCEL_SOURCE_LOADING_DIMENSION; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: parcelSourceDimension = PARCEL_SOURCE_LOADING_DIMENSION; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: parcelSourceDimension = PARCEL_SOURCE_MAPPING_DIMENSION; labelFileFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: parcelSourceDimension = PARCEL_SOURCE_MAPPING_DIMENSION; break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: parcelSourceDimension = PARCEL_SOURCE_MAPPING_DIMENSION; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: ciftiRowFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: ciftiRowFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: ciftiRowFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: ciftiRowFlag = true; break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::LABEL: labelFileFlag = true; break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::METRIC: break; case DataFileTypeEnum::METRIC_DYNAMIC: break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: break; } if (parcelSourceDimension != PARCEL_SOURCE_INVALID_DIMENSION) { CaretAssert(parcelSourceDimension != PARCEL_SOURCE_INVALID_DIMENSION); m_parcelSourceDimensionMap.insert(std::make_pair(dataFileType, parcelSourceDimension)); } if (ciftiRowFlag) { supportedCiftiRowFileTypes.push_back(dataFileType); } if (labelFileFlag) { supportedLabelFileTypes.push_back(dataFileType); } } /* * CIFTI row widgets */ m_ciftiRowWidget = createCiftiRowWidget(supportedCiftiRowFileTypes); /* * Label files widget */ m_labelFileWidgets.m_widget = createLabelFilesWidget(supportedLabelFileTypes); /* * CIFTI Parcel Widgets */ m_ciftiParcelWidget = createCiftiParcelWidget(); m_widgetBox = new WuQGroupBoxExclusiveWidget(); m_widgetBox->addWidget(m_ciftiRowWidget, "Identify from CIFTI File Row"); m_widgetBox->addWidget(m_ciftiParcelWidget, "Identify CIFTI File Parcel"); m_widgetBox->addWidget(m_labelFileWidgets.m_widget, "Identify Label"); m_widgetBox->addWidget(m_surfaceVertexWidget, "Identify Surface Vertex"); QObject::connect(m_widgetBox, SIGNAL(currentChanged(int32_t)), this, SLOT(selectedWidgetChanged())); setCentralWidget(m_widgetBox, WuQDialog::SCROLL_AREA_NEVER); updateDialog(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); } /** * Destructor. */ IdentifyBrainordinateDialog::~IdentifyBrainordinateDialog() { EventManager::get()->removeAllEventsFromListener(this); delete m_ciftiRowFileSelectionModel; m_ciftiRowFileSelectionModel = NULL; } /** * Receive an event. * * @param event * The event that the receive can respond to. */ void IdentifyBrainordinateDialog::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiEvent = dynamic_cast(event); CaretAssert(uiEvent); uiEvent->setEventProcessed(); updateDialog(); } } /** * Create and return the CIFTI Parcel Widget * * @param supportedFileTypes * The supported file types for this widget. * @return * The CIFTI Parcel Widget */ QWidget* IdentifyBrainordinateDialog::createCiftiParcelWidget() { int columnCount = 0; const int COLUMN_LABEL = columnCount++; const int COLUMN_MAP_LEFT = columnCount++; const int COLUMN_MAP_RIGHT = columnCount++; m_ciftiParcelFileLabel = new QLabel("File"); m_ciftiParcelFileMapLabel = new QLabel("Map"); std::vector supportedParcelFileTypes; for (std::map::iterator iter = m_parcelSourceDimensionMap.begin(); iter != m_parcelSourceDimensionMap.end(); iter++) { const DataFileTypeEnum::Enum dataFileType = iter->first; CaretAssert(dataFileType != DataFileTypeEnum::UNKNOWN); supportedParcelFileTypes.push_back(dataFileType); } m_ciftiParcelFileSelector = new CaretMappableDataFileAndMapSelectorObject(supportedParcelFileTypes, CaretMappableDataFileAndMapSelectorObject::OPTION_SHOW_MAP_INDEX_SPIN_BOX, this); QObject::connect(m_ciftiParcelFileSelector, SIGNAL(selectionWasPerformed()), this, SLOT(slotParcelFileOrMapSelectionChanged())); m_ciftiParcelFileSelector->getWidgetsForAddingToLayout(m_ciftiParcelFileComboBox, m_ciftiParcelFileMapSpinBox, m_ciftiParcelFileMapComboBox); m_ciftiParcelFileMapSpinBox->setFixedWidth(INDEX_SPIN_BOX_WIDTH); m_ciftiParcelFileMapSpinBox->setToolTip("Map indices start at one."); m_ciftiParcelFileParcelLabel = new QLabel("Parcel"); m_ciftiParcelFileParcelNameComboBox = new CiftiParcelSelectionComboBox(this); /* * Widget and layout */ QWidget* widget = new QWidget(); QGridLayout* ciftiParcelLayout = new QGridLayout(widget); ciftiParcelLayout->addWidget(m_ciftiParcelFileLabel, 0, COLUMN_LABEL); ciftiParcelLayout->addWidget(m_ciftiParcelFileComboBox, 0, COLUMN_MAP_LEFT, 1, 2); ciftiParcelLayout->addWidget(m_ciftiParcelFileMapLabel, 1, COLUMN_LABEL); ciftiParcelLayout->addWidget(m_ciftiParcelFileMapSpinBox, 1, COLUMN_MAP_LEFT); //, Qt::AlignLeft); ciftiParcelLayout->addWidget(m_ciftiParcelFileMapComboBox, 1, COLUMN_MAP_RIGHT); //, Qt::AlignLeft); ciftiParcelLayout->addWidget(m_ciftiParcelFileParcelLabel, 2, COLUMN_LABEL); ciftiParcelLayout->addWidget(m_ciftiParcelFileParcelNameComboBox->getWidget(), 2, COLUMN_MAP_LEFT, 1, 2); return widget; } /** * Create and return the CIFTI Row Widget * * @param supportedFileTypes * The supported file types for this widget. * @return * The CIFTI Row Widget */ QWidget* IdentifyBrainordinateDialog::createCiftiRowWidget(const std::vector& supportedFileTypes) { int columnCount = 0; const int COLUMN_LABEL = columnCount++; const int COLUMN_MAP_LEFT = columnCount++; /* * CIFTI Row selection */ m_ciftiRowFileLabel = new QLabel("File"); m_ciftiRowFileSelectionModel = CaretDataFileSelectionModel::newInstanceForCaretDataFileTypes(supportedFileTypes); m_ciftiRowFileComboBox = new CaretDataFileSelectionComboBox(this); m_ciftiRowFileIndexLabel = new QLabel("Row Index"); m_ciftiRowFileIndexSpinBox = new WuQSpinBox(); m_ciftiRowFileIndexSpinBox->setMinimum(1); m_ciftiRowFileIndexSpinBox->setMaximum(std::numeric_limits::max()); QObject::connect(m_ciftiRowFileIndexSpinBox, SIGNAL(signalReturnPressed()), this, SLOT(apply())); m_ciftiRowFileIndexSpinBox->setFixedWidth(INDEX_SPIN_BOX_WIDTH); switch (CiftiMappableDataFile::getCiftiFileRowColumnIndexBaseForGUI()) { case 0: m_ciftiRowFileIndexSpinBox->setToolTip("Row indices start at zero."); break; case 1: m_ciftiRowFileIndexSpinBox->setToolTip("Row indices start at one."); break; default: CaretAssert(0); m_ciftiRowFileIndexSpinBox->setToolTip("PROGRAM ERROR CIFTI FILE ROW/COLUMN BASE INDEX SHOULD BE ONE OR ZERO."); } QWidget* widget = new QWidget(); QGridLayout* ciftiRowLayout = new QGridLayout(widget); ciftiRowLayout->addWidget(m_ciftiRowFileLabel, 0, COLUMN_LABEL); ciftiRowLayout->addWidget(m_ciftiRowFileComboBox->getWidget(), 0, COLUMN_MAP_LEFT, 1, 2); ciftiRowLayout->addWidget(m_ciftiRowFileIndexLabel, 1, COLUMN_LABEL); ciftiRowLayout->addWidget(m_ciftiRowFileIndexSpinBox, 1, COLUMN_MAP_LEFT); return widget; } /** * Create and return the Label Files Widget * * @param supportedFileTypes * The supported file types for this widget. * @return * The Label Files Row Widget */ QWidget* IdentifyBrainordinateDialog::createLabelFilesWidget(const std::vector& supportedFileTypes) { int columnCount = 0; const int COLUMN_LABEL = columnCount++; const int COLUMN_MAP_LEFT = columnCount++; const int COLUMN_MAP_RIGHT = columnCount++; m_labelFileWidgets.m_fileLabel = new QLabel("File"); m_labelFileWidgets.m_fileMapLabel = new QLabel("Map"); m_labelFileWidgets.m_fileSelector = new CaretMappableDataFileAndMapSelectorObject(supportedFileTypes, CaretMappableDataFileAndMapSelectorObject::OPTION_SHOW_MAP_INDEX_SPIN_BOX, this); QObject::connect(m_labelFileWidgets.m_fileSelector, SIGNAL(selectionWasPerformed()), this, SLOT(slotLabelFileOrMapSelectionChanged())); m_labelFileWidgets.m_fileSelector->getWidgetsForAddingToLayout(m_labelFileWidgets.m_fileComboBox, m_labelFileWidgets.m_fileMapSpinBox, m_labelFileWidgets.m_fileMapComboBox); m_labelFileWidgets.m_fileMapSpinBox->setFixedWidth(INDEX_SPIN_BOX_WIDTH); m_labelFileWidgets.m_fileMapSpinBox->setToolTip("Map indices start at one."); m_labelFileWidgets.m_fileLabellLabel = new QLabel("Label"); m_labelFileWidgets.m_fileLabelComboBox = new GiftiLabelTableSelectionComboBox(this); /* * Widget and layout */ QWidget* widget = new QWidget(); QGridLayout* labelWidgetLayout = new QGridLayout(widget); labelWidgetLayout->addWidget(m_labelFileWidgets.m_fileLabel, 0, COLUMN_LABEL); labelWidgetLayout->addWidget(m_labelFileWidgets.m_fileComboBox, 0, COLUMN_MAP_LEFT, 1, 2); labelWidgetLayout->addWidget(m_labelFileWidgets.m_fileMapLabel, 1, COLUMN_LABEL); labelWidgetLayout->addWidget(m_labelFileWidgets.m_fileMapSpinBox, 1, COLUMN_MAP_LEFT); //, Qt::AlignLeft); labelWidgetLayout->addWidget(m_labelFileWidgets.m_fileMapComboBox, 1, COLUMN_MAP_RIGHT); //, Qt::AlignLeft); labelWidgetLayout->addWidget(m_labelFileWidgets.m_fileLabellLabel, 2, COLUMN_LABEL); labelWidgetLayout->addWidget(m_labelFileWidgets.m_fileLabelComboBox->getWidget(), 2, COLUMN_MAP_LEFT, 1, 2); return widget; } /** * Called when the user changes the label file or map. */ void IdentifyBrainordinateDialog::slotLabelFileOrMapSelectionChanged() { updateDialog(); } /** * @return Create a Surface Vertex Widget */ QWidget* IdentifyBrainordinateDialog::createSurfaceVertexlWidget() { int columnCount = 0; const int COLUMN_LABEL = columnCount++; const int COLUMN_MAP_LEFT = columnCount++; m_vertexStructureLabel = new QLabel("Structure"); m_vertexStructureComboBox = new StructureEnumComboBox(this); m_vertexStructureComboBox->listOnlyValidStructures(); m_vertexIndexLabel = new QLabel("Vertex Index"); m_vertexIndexSpinBox = WuQFactory::newSpinBoxWithMinMaxStep(0, std::numeric_limits::max(), 1); m_vertexIndexSpinBox->setFixedWidth(INDEX_SPIN_BOX_WIDTH); m_vertexIndexSpinBox->setToolTip("Vertex indices start at zero."); QWidget* widget = new QWidget(); QGridLayout* surfaceVertexLayout = new QGridLayout(widget); surfaceVertexLayout->addWidget(m_vertexStructureLabel, 0, COLUMN_LABEL); surfaceVertexLayout->addWidget(m_vertexStructureComboBox->getWidget(), 0, COLUMN_MAP_LEFT, 1, 2); surfaceVertexLayout->addWidget(m_vertexIndexLabel, 1, COLUMN_LABEL); surfaceVertexLayout->addWidget(m_vertexIndexSpinBox, 1, COLUMN_MAP_LEFT); return widget; } /** * Called when the user changes the parcel file or map. */ void IdentifyBrainordinateDialog::slotParcelFileOrMapSelectionChanged() { updateDialog(); } /** * Called when the selected widget changes. */ void IdentifyBrainordinateDialog::selectedWidgetChanged() { updateDialog(); } /** * Update the dialog. */ void IdentifyBrainordinateDialog::updateDialog() { CaretMappableDataFileAndMapSelectionModel* parcelFileModel = m_ciftiParcelFileSelector->getModel(); m_ciftiParcelFileSelector->updateFileAndMapSelector(parcelFileModel); CaretMappableDataFile* parcelFile = parcelFileModel->getSelectedFile(); bool parcelsMapValidFlag = false; if (parcelFile != NULL) { const int32_t mapIndex = parcelFileModel->getSelectedMapIndex(); if ((mapIndex >= 0) && (mapIndex < parcelFile->getNumberOfMaps())) { CiftiMappableDataFile* ciftiMapFile = dynamic_cast(parcelFile); if (ciftiMapFile != NULL) { const ParcelSourceDimension parcelSourceDimension = getParcelSourceDimensionFromFile(parcelFile); switch (parcelSourceDimension) { case PARCEL_SOURCE_INVALID_DIMENSION: CaretAssertMessage(0, "Should never be invalid."); break; case PARCEL_SOURCE_LOADING_DIMENSION: m_ciftiParcelFileParcelNameComboBox->updateComboBox(ciftiMapFile->getCiftiParcelsMapForLoading()); parcelsMapValidFlag = true; break; case PARCEL_SOURCE_MAPPING_DIMENSION: m_ciftiParcelFileParcelNameComboBox->updateComboBox(ciftiMapFile->getCiftiParcelsMapForBrainordinateMapping()); parcelsMapValidFlag = true; break; } } } } if ( ! parcelsMapValidFlag) { m_ciftiParcelFileParcelNameComboBox->updateComboBox(NULL); } CaretMappableDataFileAndMapSelectionModel* labelFileModel = m_labelFileWidgets.m_fileSelector->getModel(); m_labelFileWidgets.m_fileSelector->updateFileAndMapSelector(labelFileModel); CaretMappableDataFile* labelFile = labelFileModel->getSelectedFile(); bool labelTableComboBoxValid = false; if (labelFile != NULL) { const int32_t mapIndex = labelFileModel->getSelectedMapIndex(); if ((mapIndex >= 0) && (mapIndex < labelFile->getNumberOfMaps())) { GiftiLabelTable* labelTable = labelFile->getMapLabelTable(mapIndex); m_labelFileWidgets.m_fileLabelComboBox->updateContent(labelTable); labelTableComboBoxValid = true; } } if ( ! labelTableComboBoxValid) { m_labelFileWidgets.m_fileLabelComboBox->updateContent(NULL); } m_ciftiRowFileComboBox->updateComboBox(m_ciftiRowFileSelectionModel); m_vertexStructureComboBox->listOnlyValidStructures(); } /** * Get the source of parcels for a caret data file. * * @param mapFile * The caret data file. * @return * The source for parcels (loading or mapping dimension). */ IdentifyBrainordinateDialog::ParcelSourceDimension IdentifyBrainordinateDialog::getParcelSourceDimensionFromFile(const CaretMappableDataFile* mapFile) { ParcelSourceDimension parcelSourceDim = PARCEL_SOURCE_INVALID_DIMENSION; std::map::iterator typeIter = m_parcelSourceDimensionMap.find(mapFile->getDataFileType()); if (typeIter != m_parcelSourceDimensionMap.end()) { parcelSourceDim = typeIter->second; } CaretAssert(parcelSourceDim != PARCEL_SOURCE_INVALID_DIMENSION); return parcelSourceDim; } /** * Gets called when Apply button is clicked. */ void IdentifyBrainordinateDialog::applyButtonClicked() { AString errorMessage; QWidget* selectedWidget = m_widgetBox->currentWidget(); if (m_surfaceVertexWidget == selectedWidget) { processSurfaceVertexWidget(errorMessage); } else if (m_ciftiParcelWidget == selectedWidget) { processCiftiParcelWidget(errorMessage); } else if (m_ciftiRowWidget == selectedWidget) { processCiftiRowWidget(errorMessage); } else if (m_labelFileWidgets.m_widget == selectedWidget) { processLabelFileWidget(errorMessage); } else { const QString msg("Choose one of the methods for identifying a brainordinate."); errorMessage = (WuQtUtilities::createWordWrappedToolTipText(msg)); } if ( ! errorMessage.isEmpty()) { WuQMessageBox::errorOk(this, errorMessage); return; } WuQDialogNonModal::applyButtonClicked(); } /** * Update coloring and redraw all windows. */ void IdentifyBrainordinateDialog::updateColoringAndDrawAllWindows() { EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Flash the brainordinate highlighting region of interest. * * @param brainROI * brainordinate highlighting region of interest that is flashed. */ void IdentifyBrainordinateDialog::flashBrainordinateHighlightingRegionOfInterest(BrainordinateRegionOfInterest* brainROI) { const float flashDelayTime = 0.25; const int32_t flashCount = 4; for (int32_t iFlash = 0; iFlash < flashCount; iFlash++) { brainROI->setBrainordinateHighlightingEnabled(true); updateColoringAndDrawAllWindows(); SystemUtilities::sleepSeconds(flashDelayTime); brainROI->setBrainordinateHighlightingEnabled(false); updateColoringAndDrawAllWindows(); SystemUtilities::sleepSeconds(flashDelayTime); } } /** * Process user's selectons in the Label File Widget * * @param errorMessageOut * Output containing error message. */ void IdentifyBrainordinateDialog::processLabelFileWidget(AString& errorMessageOut) { Brain* brain = GuiManager::get()->getBrain(); CaretMappableDataFile* mapFile = m_labelFileWidgets.m_fileSelector->getModel()->getSelectedFile(); const int32_t mapIndex = m_labelFileWidgets.m_fileSelector->getModel()->getSelectedMapIndex(); if (mapFile != NULL) { const AString labelName = m_labelFileWidgets.m_fileLabelComboBox->getSelectedLabelName(); BrainordinateRegionOfInterest* brainROI = brain->getBrainordinateHighlightRegionOfInterest(); if (brainROI->setWithLabelFileLabel(mapFile, mapIndex, labelName, errorMessageOut)) { flashBrainordinateHighlightingRegionOfInterest(brainROI); } } } /** * Process user's selectons in the CIFTI Parcel Widget * * @param errorMessageOut * Output containing error message. */ void IdentifyBrainordinateDialog::processCiftiParcelWidget(AString& errorMessageOut) { Brain* brain = GuiManager::get()->getBrain(); CaretMappableDataFile* mapFile = m_ciftiParcelFileSelector->getModel()->getSelectedFile(); const int32_t mapIndex = m_ciftiParcelFileSelector->getModel()->getSelectedMapIndex(); if (mapFile != NULL) { CiftiMappableDataFile* ciftiFile = dynamic_cast(mapFile); const QString parcelName = m_ciftiParcelFileParcelNameComboBox->getSelectedParcelName(); const ParcelSourceDimension parcelSourceDimension = getParcelSourceDimensionFromFile(ciftiFile); BrainordinateRegionOfInterest* brainROI = brain->getBrainordinateHighlightRegionOfInterest(); switch (parcelSourceDimension) { case PARCEL_SOURCE_INVALID_DIMENSION: CaretAssertMessage(0, "Should never be invalid."); break; case PARCEL_SOURCE_LOADING_DIMENSION: brainROI->setWithCiftiParcelLoadingBrainordinates(ciftiFile, mapIndex, parcelName, errorMessageOut); break; case PARCEL_SOURCE_MAPPING_DIMENSION: brainROI->setWithCiftiParcelMappingBrainordinates(ciftiFile, mapIndex, parcelName, errorMessageOut); break; } if (brainROI->hasSurfaceNodes() || brainROI->hasVolumeVoxels()) { /* * Need to load data? */ if (parcelSourceDimension == PARCEL_SOURCE_LOADING_DIMENSION) { CiftiMappableConnectivityMatrixDataFile* connMatrixFile = dynamic_cast(ciftiFile); if (connMatrixFile != NULL) { SelectionManager* selectionManager = brain->getSelectionManager(); selectionManager->reset(); selectionManager->setAllSelectionsEnabled(true); SelectionItemCiftiConnectivityMatrixRowColumn* selectionCiftiRowColumn = selectionManager->getCiftiConnectivityMatrixRowColumnIdentification(); const CiftiParcelsMap* ciftiParcelsMap = connMatrixFile->getCiftiParcelsMapForLoading(); const int64_t parcelIndex = ciftiParcelsMap->getIndexFromNumberOrName(parcelName); if (parcelIndex >= 0) { switch (connMatrixFile->getChartMatrixLoadingDimension()) { case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_COLUMN: selectionCiftiRowColumn->setFileColumn(connMatrixFile, parcelIndex); break; case ChartMatrixLoadingDimensionEnum::CHART_MATRIX_LOADING_BY_ROW: selectionCiftiRowColumn->setFileRow(connMatrixFile, parcelIndex); break; } GuiManager::get()->processIdentification(-1, // invalid tab index selectionManager, this); } else { errorMessageOut = ("Parcel name=" + parcelName + " not found in parcels map for file " + connMatrixFile->getFileNameNoPath()); } } } /* * Highlight the selected parcel */ flashBrainordinateHighlightingRegionOfInterest(brainROI); } else { brainROI->setBrainordinateHighlightingEnabled(false); updateColoringAndDrawAllWindows(); } } else { errorMessageOut = ("No parcel-type file is selected."); } } /** * Process user's selectons in the * * @param errorMessageOut * Output containing error message. */ void IdentifyBrainordinateDialog::processCiftiRowWidget(AString& errorMessageOut) { Brain* brain = GuiManager::get()->getBrain(); SelectionManager* selectionManager = brain->getSelectionManager(); selectionManager->reset(); selectionManager->setAllSelectionsEnabled(true); CaretDataFile* dataFile = m_ciftiRowFileSelectionModel->getSelectedFile(); if (dataFile != NULL) { CiftiMappableDataFile* ciftiMapFile = dynamic_cast(dataFile); CiftiFiberTrajectoryFile* ciftiTrajFile = dynamic_cast(dataFile); CiftiScalarDataSeriesFile* ciftiSdsFile = dynamic_cast(dataFile); const int32_t selectedCiftiRowIndex = m_ciftiRowFileIndexSpinBox->value() - m_ciftiRowFileIndexSpinBox->minimum(); try { StructureEnum::Enum surfaceStructure; int32_t surfaceNodeIndex; int32_t surfaceNumberOfNodes; bool surfaceNodeValid = false; int64_t voxelIJK[3]; float voxelXYZ[3]; bool voxelValid = false; if (ciftiSdsFile != NULL) { ChartableTwoFileDelegate* chartDelegate = ciftiSdsFile->getChartingDelegate(); CaretAssert(chartDelegate); ChartableTwoFileMatrixChart* matrixChart = chartDelegate->getMatrixCharting(); ChartableTwoFileLineSeriesChart* lineSeriesChart = chartDelegate->getLineSeriesCharting(); if (matrixChart != NULL) { int32_t rowCount(0), columnCount(0); matrixChart->getMatrixDimensions(rowCount, columnCount); if (selectedCiftiRowIndex < rowCount) { const int32_t tabIndex = 0; // selections are same in all tabs matrixChart->setSelectedRowColumnIndex(tabIndex, selectedCiftiRowIndex); if (lineSeriesChart) { lineSeriesChart->loadDataForRowOrColumn(tabIndex, selectedCiftiRowIndex); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } } else { if (ciftiMapFile != NULL) { ciftiMapFile->getBrainordinateFromRowIndex(selectedCiftiRowIndex, surfaceStructure, surfaceNodeIndex, surfaceNumberOfNodes, surfaceNodeValid, voxelIJK, voxelXYZ, voxelValid); } else if (ciftiTrajFile != NULL) { ciftiTrajFile->getBrainordinateFromRowIndex(selectedCiftiRowIndex, surfaceStructure, surfaceNodeIndex, surfaceNumberOfNodes, surfaceNodeValid, voxelIJK, voxelXYZ, voxelValid); } else { errorMessageOut = "Neither CIFTI Mappable nor CIFTI Trajectory file. Has new file type been added?"; } if (surfaceNodeValid) { SelectionItemSurfaceNode* surfaceID = selectionManager->getSurfaceNodeIdentification(); const Surface* surface = brain->getPrimaryAnatomicalSurfaceForStructure(surfaceStructure); if (surface != NULL) { if ((surfaceNodeIndex >= 0) && (surfaceNodeIndex < surface->getNumberOfNodes())) { surfaceID->setSurface(const_cast(surface)); surfaceID->setBrain(brain); const float* xyz = surface->getCoordinate(surfaceNodeIndex); const double doubleXYZ[3] = { xyz[0], xyz[1], xyz[2] }; surfaceID->setModelXYZ(doubleXYZ); surfaceID->setNodeNumber(surfaceNodeIndex); GuiManager::get()->processIdentification(-1, // invalid tab index selectionManager, this); } else { errorMessageOut = ("Surface vertex index " + AString::number(surfaceNodeIndex) + " is not valid for surface " + surface->getFileNameNoPath()); } } else{ errorMessageOut = ("No surfaces are loaded for structure " + StructureEnum::toGuiName(surfaceStructure)); } } else if (voxelValid) { SelectionItemVoxel* voxelID = selectionManager->getVoxelIdentification(); voxelID->setBrain(brain); voxelID->setEnabledForSelection(true); voxelID->setVoxelIdentification(brain, ciftiMapFile, voxelIJK, 0.0); const double doubleXYZ[3] = { voxelXYZ[0], voxelXYZ[1], voxelXYZ[2] }; voxelID->setModelXYZ(doubleXYZ); GuiManager::get()->processIdentification(-1, // invalid tab index selectionManager, this); } } } catch (const DataFileException& dfe) { errorMessageOut = dfe.whatString(); } } } /** * Process user's selectons in the * * @param errorMessageOut * Output containing error message. */ void IdentifyBrainordinateDialog::processSurfaceVertexWidget(AString& errorMessageOut) { Brain* brain = GuiManager::get()->getBrain(); SelectionManager* selectionManager = brain->getSelectionManager(); selectionManager->reset(); const StructureEnum::Enum selectedStructure = m_vertexStructureComboBox->getSelectedStructure(); const int32_t selectedVertexIndex = m_vertexIndexSpinBox->value(); BrainStructure* bs = brain->getBrainStructure(selectedStructure, false); if (bs != NULL) { if (selectedVertexIndex < bs->getNumberOfNodes()) { Surface* surface = bs->getPrimaryAnatomicalSurface(); if (surface != NULL) { SelectionItemSurfaceNode* nodeID = selectionManager->getSurfaceNodeIdentification(); nodeID->setBrain(brain); nodeID->setNodeNumber(selectedVertexIndex); nodeID->setSurface(surface); const float* fxyz = surface->getCoordinate(selectedVertexIndex); const double xyz[3] = { fxyz[0], fxyz[1], fxyz[2] }; nodeID->setModelXYZ(xyz); GuiManager::get()->processIdentification(-1, selectionManager, this); } else { errorMessageOut = ("PROGRAM ERROR: Primary Anatomical Surface not found for structure " + StructureEnum::toName(selectedStructure)); } } else { errorMessageOut = ("Vertex Index " + AString::number(selectedVertexIndex) + " is out of range [0, " + AString::number(bs->getNumberOfNodes() - 1) + "] for " + StructureEnum::toGuiName(selectedStructure)); } } else { errorMessageOut = ("Structure " + StructureEnum::toName(selectedStructure) + " not found."); } } connectome-workbench-1.4.2/src/GuiQt/IdentifyBrainordinateDialog.h000066400000000000000000000131021360521144700252160ustar00rootroot00000000000000#ifndef __IDENTIFY_BRAINORDINATE_DIALOG_H__ #define __IDENTIFY_BRAINORDINATE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "DataFileTypeEnum.h" #include "EventListenerInterface.h" #include "WuQDialogNonModal.h" class QLabel; class QRadioButton; class QSpinBox; namespace caret { class BrainordinateRegionOfInterest; class CaretDataFileSelectionComboBox; class CaretDataFileSelectionModel; class CaretMappableDataFileAndMapSelectorObject; class CaretMappableDataFile; class CiftiParcelSelectionComboBox; class GiftiLabelTableSelectionComboBox; class StructureEnumComboBox; class WuQGroupBoxExclusiveWidget; class IdentifyBrainordinateDialog : public WuQDialogNonModal, public EventListenerInterface { Q_OBJECT public: IdentifyBrainordinateDialog(QWidget* parent); virtual ~IdentifyBrainordinateDialog(); virtual void updateDialog(); virtual void receiveEvent(Event* event); protected: virtual void applyButtonClicked(); private: IdentifyBrainordinateDialog(const IdentifyBrainordinateDialog&); IdentifyBrainordinateDialog& operator=(const IdentifyBrainordinateDialog&); public: // ADD_NEW_METHODS_HERE private slots: void slotParcelFileOrMapSelectionChanged(); void slotLabelFileOrMapSelectionChanged(); void selectedWidgetChanged(); private: enum Mode { MODE_NONE, MODE_CIFTI_PARCEL, MODE_CIFTI_ROW, MODE_SURFACE_VERTEX }; enum ParcelSourceDimension { PARCEL_SOURCE_INVALID_DIMENSION, PARCEL_SOURCE_LOADING_DIMENSION, PARCEL_SOURCE_MAPPING_DIMENSION }; // ADD_NEW_MEMBERS_HERE QWidget* createCiftiParcelWidget(); QWidget* createCiftiRowWidget(const std::vector& supportedFileTypes); QWidget* createLabelFilesWidget(const std::vector& supportedFileTypes); QWidget* createSurfaceVertexlWidget(); void processCiftiParcelWidget(AString& errorMessageOut); void processCiftiRowWidget(AString& errorMessageOut); void processLabelFileWidget(AString& errorMessageOut); void processSurfaceVertexWidget(AString& errorMessageOut); void flashBrainordinateHighlightingRegionOfInterest(BrainordinateRegionOfInterest* brainROI); void updateColoringAndDrawAllWindows(); ParcelSourceDimension getParcelSourceDimensionFromFile(const CaretMappableDataFile* mapFile); StructureEnumComboBox* m_vertexStructureComboBox; QWidget* m_surfaceVertexWidget; QLabel* m_vertexStructureLabel; QSpinBox* m_vertexIndexSpinBox; QLabel* m_vertexIndexLabel; QWidget* m_ciftiRowWidget; struct LabelFileWidgets { QWidget* m_widget; CaretMappableDataFileAndMapSelectorObject* m_fileSelector; QLabel* m_fileLabel; QLabel* m_fileMapLabel; QWidget* m_fileComboBox; QWidget* m_fileMapSpinBox; QWidget* m_fileMapComboBox; QLabel* m_fileLabellLabel; GiftiLabelTableSelectionComboBox* m_fileLabelComboBox; }; LabelFileWidgets m_labelFileWidgets; QLabel* m_ciftiRowFileLabel; CaretDataFileSelectionComboBox* m_ciftiRowFileComboBox; CaretDataFileSelectionModel* m_ciftiRowFileSelectionModel; QLabel* m_ciftiRowFileIndexLabel; QSpinBox* m_ciftiRowFileIndexSpinBox; QWidget* m_ciftiParcelWidget; QLabel* m_ciftiParcelFileLabel; QLabel* m_ciftiParcelFileMapLabel; QWidget* m_ciftiParcelFileComboBox; QWidget* m_ciftiParcelFileMapSpinBox; QWidget* m_ciftiParcelFileMapComboBox; QLabel* m_ciftiParcelFileParcelLabel; CiftiParcelSelectionComboBox* m_ciftiParcelFileParcelNameComboBox; CaretMappableDataFileAndMapSelectorObject* m_ciftiParcelFileSelector; WuQGroupBoxExclusiveWidget* m_widgetBox; std::map m_parcelSourceDimensionMap; }; #ifdef __IDENTIFY_BRAINORDINATE_DIALOG_DECLARE__ #endif // __IDENTIFY_BRAINORDINATE_DIALOG_DECLARE__ } // namespace #endif //__IDENTIFY_BRAINORDINATE_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/ImageCaptureDialog.cxx000066400000000000000000001230171360521144700236710ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define __IMAGE_CAPTURE_DIALOG__H__DECLARE__ #include "ImageCaptureDialog.h" #undef __IMAGE_CAPTURE_DIALOG__H__DECLARE__ #include "Brain.h" #include "BrainBrowserWindow.h" #include "CaretAssert.h" #include "CaretPreferences.h" #include "ChartMatrixDisplayProperties.h" #include "DataFileException.h" #include "EnumComboBoxTemplate.h" #include "EventBrowserWindowGraphicsRedrawn.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventImageCapture.h" #include "EventManager.h" #include "FileInformation.h" #include "GuiManager.h" #include "ImageFile.h" #include "ImageCaptureSettings.h" #include "SessionManager.h" #include "CaretFileDialog.h" #include "WuQFactory.h" #include "WuQMessageBox.h" #include "WuQTimedMessageDisplay.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::ImageCaptureDialog * \brief Dialog for capturing images. * \ingroup GuiQt * */ /** * Constructor for editing a palette selection. * * @param parent * Parent widget on which this dialog is displayed. */ ImageCaptureDialog::ImageCaptureDialog(BrainBrowserWindow* parent) : WuQDialogNonModal("Image Capture", parent) { m_imageDimensionsWidget = NULL; setDeleteWhenClosed(false); /* * Use Apply button for image capture */ setApplyButtonText("Capture"); /* * Image Source */ QWidget* imageSourceWidget = createImageSourceSection(); /* * Image Size * Note: Label is updated when window size is updated */ m_imageDimensionsWidget = createImageDimensionsSection(); /* * Image Options */ QWidget* imageOptionsWidget = createImageOptionsSection(); /* * Image Destination */ QWidget* imageDestinationWidget = createImageDestinationSection(); QWidget* w = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(imageSourceWidget); layout->addWidget(m_imageDimensionsWidget); layout->addWidget(imageOptionsWidget); layout->addWidget(imageDestinationWidget); setCentralWidget(w, WuQDialog::SCROLL_AREA_NEVER); /* * Make apply button the default button. */ QPushButton* applyButton = getDialogButtonBox()->button(QDialogButtonBox::Apply); CaretAssert(applyButton); applyButton->setAutoDefault(true); applyButton->setDefault(true); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN); updateBrowserWindowWidthAndHeightLabel(); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); updateDimensionsSection(); } /** * Destructor. */ ImageCaptureDialog::~ImageCaptureDialog() { EventManager::get()->removeAllEventsFromListener(this); } /** * @return Create and return the image source section. */ QWidget* ImageCaptureDialog::createImageSourceSection() { QLabel* windowLabel = new QLabel("Workbench Window: "); m_windowSelectionSpinBox = new QSpinBox(); m_windowSelectionSpinBox->setRange(1, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS); m_windowSelectionSpinBox->setSingleStep(1); m_windowSelectionSpinBox->setFixedWidth(60); QObject::connect(m_windowSelectionSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateBrowserWindowWidthAndHeightLabel())); const QString cbTT = WuQtUtilities::createWordWrappedToolTipText("When Tab/Window Lock Aspect is selected, empty " "regions may appear in the graphics region. Selection " "of this option will exclude these empty regions in " "the captured image."); m_windowCropToLockAspectRegionCheckBox = new QCheckBox("Crop to Tab/Window Lock Aspect Region"); m_windowCropToLockAspectRegionCheckBox->setChecked(true); QObject::connect(m_windowCropToLockAspectRegionCheckBox, SIGNAL(clicked(bool)), this, SLOT(cropToTabWindowLockAspectRegionClicked(bool))); m_windowCropToLockAspectRegionCheckBox->setToolTip(cbTT); QGroupBox* groupBox = new QGroupBox("Source"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(windowLabel, 0, 0); gridLayout->addWidget(m_windowSelectionSpinBox, 0, 1, Qt::AlignLeft); gridLayout->addWidget(m_windowCropToLockAspectRegionCheckBox, 1, 0, 1, 2, Qt::AlignLeft); return groupBox; } /** * @return Create and return the image options section. */ QWidget* ImageCaptureDialog::createImageOptionsSection() { m_imageAutoCropCheckBox = new QCheckBox("Automatically Crop Image"); QObject::connect(m_imageAutoCropCheckBox, SIGNAL(clicked(bool)), this, SLOT(imageCroppingCheckBoxClicked(bool))); QLabel* imageAutoCropMarginLabel = new QLabel(" Margin"); m_imageAutoCropMarginSpinBox = new QSpinBox(); QObject::connect(m_imageAutoCropMarginSpinBox, SIGNAL(valueChanged(int)), this, SLOT(imageCroppingMarginValueChanged(int))); m_imageAutoCropMarginSpinBox->setMinimum(0); m_imageAutoCropMarginSpinBox->setMaximum(100000); m_imageAutoCropMarginSpinBox->setSingleStep(1); m_imageAutoCropMarginSpinBox->setMaximumWidth(100); QHBoxLayout* cropMarginLayout = new QHBoxLayout(); cropMarginLayout->addWidget(imageAutoCropMarginLabel); cropMarginLayout->addWidget(m_imageAutoCropMarginSpinBox); cropMarginLayout->addStretch(); QGroupBox* groupBox = new QGroupBox("Image Options"); QVBoxLayout* layout = new QVBoxLayout(groupBox); layout->addWidget(m_imageAutoCropCheckBox); layout->addLayout(cropMarginLayout); return groupBox; } /** * @return Create and return the image dimensions section. */ QWidget* ImageCaptureDialog::createImageDimensionsSection() { m_imageSizeWindowRadioButton = new QRadioButton("Size of Window"); m_imageSizeCustomRadioButton = new QRadioButton("Custom"); QButtonGroup* sizeButtonGroup = new QButtonGroup(this); sizeButtonGroup->addButton(m_imageSizeWindowRadioButton); sizeButtonGroup->addButton(m_imageSizeCustomRadioButton); QObject::connect(sizeButtonGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(sizeRadioButtonClicked(QAbstractButton*))); QLabel* customPixelsWidthLabel = new QLabel("Width:"); QLabel* customPixelsHeightLabel = new QLabel("Height:"); QLabel* customUnitsWidthLabel = new QLabel("Width:"); QLabel* customUnitsHeightLabel = new QLabel("Height:"); QLabel* customResolutionLabel = new QLabel("Resolution:"); const int pixelSpinBoxWidth = 80; QLabel* pixelDimensionsLabel = new QLabel("Pixel Dimensions"); m_pixelWidthSpinBox = new QSpinBox(); m_pixelWidthSpinBox->setFixedWidth(pixelSpinBoxWidth); m_pixelWidthSpinBox->setRange(100, 10000000); m_pixelWidthSpinBox->setSingleStep(1); QObject::connect(m_pixelWidthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(pixelWidthValueChanged(int))); m_pixelHeightSpinBox = new QSpinBox(); m_pixelHeightSpinBox->setFixedWidth(pixelSpinBoxWidth); m_pixelHeightSpinBox->setRange(100, 10000000); m_pixelHeightSpinBox->setSingleStep(1); QObject::connect(m_pixelHeightSpinBox, SIGNAL(valueChanged(int)), this, SLOT(pixelHeightValueChanged(int))); const int imageSpinBoxWidth = 100; QLabel* imageDimensionsLabel = new QLabel("Image Dimensions"); m_imageWidthSpinBox = new QDoubleSpinBox(); m_imageWidthSpinBox->setFixedWidth(imageSpinBoxWidth); m_imageWidthSpinBox->setRange(0.01, 100000000.0); m_imageWidthSpinBox->setSingleStep(0.1); QObject::connect(m_imageWidthSpinBox, SIGNAL(valueChanged(double)), this, SLOT(imageWidthValueChanged(double))); m_imageHeightSpinBox = new QDoubleSpinBox(); m_imageHeightSpinBox->setFixedWidth(imageSpinBoxWidth); m_imageHeightSpinBox->setRange(0.01, 100000000.0); m_imageHeightSpinBox->setSingleStep(0.1); QObject::connect(m_imageHeightSpinBox, SIGNAL(valueChanged(double)), this, SLOT(imageHeightValueChanged(double))); m_imageResolutionSpinBox = new QDoubleSpinBox(); m_imageResolutionSpinBox->setFixedWidth(imageSpinBoxWidth); m_imageResolutionSpinBox->setRange(0.01, 1000000); m_imageResolutionSpinBox->setSingleStep(1); QObject::connect(m_imageResolutionSpinBox, SIGNAL(valueChanged(double)), this, SLOT(imageResolutionValueChanged(double))); m_imageSpatialUnitsEnumComboBox = new EnumComboBoxTemplate(this); m_imageSpatialUnitsEnumComboBox->setup(); QObject::connect(m_imageSpatialUnitsEnumComboBox, SIGNAL(itemActivated()), this, SLOT(imageSizeUnitsEnumComboBoxItemActivated())); m_imagePixelsPerSpatialUnitsEnumComboBox = new EnumComboBoxTemplate(this); m_imagePixelsPerSpatialUnitsEnumComboBox->setup(); QObject::connect(m_imagePixelsPerSpatialUnitsEnumComboBox, SIGNAL(itemActivated()), this, SLOT(imageResolutionUnitsEnumComboBoxItemActivated())); m_scaleProportionallyCheckBox = new QCheckBox("Scale Proportionally"); WuQtUtilities::setWordWrappedToolTip(m_scaleProportionallyCheckBox, ("If checked, the heights of the pixel and image dimensions " "are automatically adjusted so that their proportions " "match the proportion of the selected window's " "graphics region.")); QObject::connect(m_scaleProportionallyCheckBox, SIGNAL(clicked(bool)), this, SLOT(scaleProportionallyCheckBoxClicked(bool))); QWidget* pixelsSizeWidget = new QWidget(); QGridLayout* pixelsSizeLayout = new QGridLayout(pixelsSizeWidget); WuQtUtilities::setLayoutSpacingAndMargins(pixelsSizeLayout, 4, 0); int pixelsRow = 0; pixelsSizeLayout->addWidget(pixelDimensionsLabel, pixelsRow, 0, 1, 2, Qt::AlignHCenter); pixelsRow++; pixelsSizeLayout->addWidget(customPixelsWidthLabel, pixelsRow, 0); pixelsSizeLayout->addWidget(m_pixelWidthSpinBox, pixelsRow, 1); pixelsRow++; pixelsSizeLayout->addWidget(customPixelsHeightLabel, pixelsRow, 0); pixelsSizeLayout->addWidget(m_pixelHeightSpinBox, pixelsRow, 1); pixelsRow++; pixelsSizeLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), pixelsRow, 0, 1, 2); pixelsRow++; pixelsSizeLayout->addWidget(m_scaleProportionallyCheckBox, pixelsRow, 0, 1, 2, Qt::AlignLeft); pixelsRow++; pixelsSizeWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); QWidget* imageUnitsWidget = new QWidget(); QGridLayout* imageUnitsLayout = new QGridLayout(imageUnitsWidget); WuQtUtilities::setLayoutSpacingAndMargins(imageUnitsLayout, 4, 0); int unitsRow = 0; imageUnitsLayout->addWidget(imageDimensionsLabel, unitsRow, 0, 1, 3, Qt::AlignHCenter); unitsRow++; imageUnitsLayout->addWidget(customUnitsWidthLabel, unitsRow, 0); imageUnitsLayout->addWidget(m_imageWidthSpinBox, unitsRow, 1); imageUnitsLayout->addWidget(m_imageSpatialUnitsEnumComboBox->getWidget(), unitsRow, 2, 2, 1); unitsRow++; imageUnitsLayout->addWidget(customUnitsHeightLabel, unitsRow, 0); imageUnitsLayout->addWidget(m_imageHeightSpinBox, unitsRow, 1); unitsRow++; imageUnitsLayout->addWidget(customResolutionLabel, unitsRow, 0); imageUnitsLayout->addWidget(m_imageResolutionSpinBox, unitsRow, 1); imageUnitsLayout->addWidget(m_imagePixelsPerSpatialUnitsEnumComboBox->getWidget(), unitsRow, 2); unitsRow++; imageUnitsWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); m_customDimensionsWidget = new QWidget(); QHBoxLayout* customDimensionsLayout = new QHBoxLayout(m_customDimensionsWidget); customDimensionsLayout->addSpacing(20); customDimensionsLayout->addWidget(pixelsSizeWidget, 0, Qt::AlignTop); customDimensionsLayout->addWidget(WuQtUtilities::createVerticalLineWidget()); customDimensionsLayout->addWidget(imageUnitsWidget, 0, Qt::AlignTop); QLabel* imageBytesLabel = new QLabel("Uncompressed Image Memory Size: "); m_imageNumberOfBytesLabel = new QLabel(" "); QWidget* imageBytesWidget = new QWidget(); QHBoxLayout* imageBytesLayout = new QHBoxLayout(imageBytesWidget); WuQtUtilities::setLayoutSpacingAndMargins(imageBytesLayout, 4, 0); imageBytesLayout->addWidget(imageBytesLabel); imageBytesLayout->addWidget(m_imageNumberOfBytesLabel); imageBytesLayout->addStretch(); QGroupBox* groupBox = new QGroupBox("Dimensions"); QVBoxLayout* layout = new QVBoxLayout(groupBox); layout->addWidget(m_imageSizeWindowRadioButton, 0, Qt::AlignLeft); layout->addWidget(m_imageSizeCustomRadioButton, 0, Qt::AlignLeft); layout->addWidget(m_customDimensionsWidget, 0, Qt::AlignLeft); layout->addWidget(WuQtUtilities::createHorizontalLineWidget()); layout->addWidget(imageBytesWidget); return groupBox; } /** * Gets called when the Window Size or Custom radio button is clicked. * * @param button * Button that was clicked. */ void ImageCaptureDialog::sizeRadioButtonClicked(QAbstractButton* /*button*/) { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); if (m_imageSizeCustomRadioButton->isChecked()) { imageCaptureSettings->setImageCaptureDimensionsMode(ImageCaptureDimensionsModeEnum::IMAGE_CAPTURE_DIMENSIONS_MODE_CUSTOM); } else if (m_imageSizeWindowRadioButton->isChecked()) { imageCaptureSettings->setImageCaptureDimensionsMode(ImageCaptureDimensionsModeEnum::IMAGE_CAPTURE_DIMENSIONS_MODE_WINDOW_SIZE); } updateDimensionsSection(); } /** * Gets called when the image resolution units are changed. */ void ImageCaptureDialog::imageResolutionUnitsEnumComboBoxItemActivated() { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); imageCaptureSettings->setImageResolutionUnits(m_imagePixelsPerSpatialUnitsEnumComboBox->getSelectedItem()); updateDimensionsSection(); } /** * Gets called when the image size units are changed. */ void ImageCaptureDialog::imageSizeUnitsEnumComboBoxItemActivated() { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); imageCaptureSettings->setSpatialUnits(m_imageSpatialUnitsEnumComboBox->getSelectedItem()); updateDimensionsSection(); } /** * Gets called when Crop to Tab/Window Lock Aspect Region checkbox clicked * * @param checked * New checked status. */ void ImageCaptureDialog::cropToTabWindowLockAspectRegionClicked(bool checked) { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); imageCaptureSettings->setCropToTabWindowLockAspectRegionEnabled(checked); updateBrowserWindowWidthAndHeightLabel(); } /** * May be called to update the dialog's content. */ void ImageCaptureDialog::updateDialog() { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); m_windowCropToLockAspectRegionCheckBox->setChecked(imageCaptureSettings->isCropToTabWindowLockAspectRegionEnabled()); updateBrowserWindowWidthAndHeightLabel(); updateDimensionsSection(); updateImageOptionsSection(); updateDestinationSection(); } /** * Update the section. */ void ImageCaptureDialog::updateDimensionsSection() { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); CaretAssert(imageCaptureSettings); switch (imageCaptureSettings->getImageCaptureDimensionsMode()) { case ImageCaptureDimensionsModeEnum::IMAGE_CAPTURE_DIMENSIONS_MODE_CUSTOM: m_imageSizeCustomRadioButton->setChecked(true); m_customDimensionsWidget->setEnabled(true); break; case ImageCaptureDimensionsModeEnum::IMAGE_CAPTURE_DIMENSIONS_MODE_WINDOW_SIZE: m_imageSizeWindowRadioButton->setChecked(true); m_customDimensionsWidget->setEnabled(false); break; } m_pixelWidthSpinBox->blockSignals(true); m_pixelWidthSpinBox->setValue(imageCaptureSettings->getPixelWidth()); m_pixelWidthSpinBox->blockSignals(false); m_pixelHeightSpinBox->blockSignals(true); m_pixelHeightSpinBox->setValue(imageCaptureSettings->getPixelHeight()); m_pixelHeightSpinBox->blockSignals(false); m_scaleProportionallyCheckBox->setChecked(imageCaptureSettings->isScaleProportionately()); m_imageWidthSpinBox->blockSignals(true); m_imageWidthSpinBox->setValue(imageCaptureSettings->getSpatialWidth()); m_imageWidthSpinBox->blockSignals(false); m_imageHeightSpinBox->blockSignals(true); m_imageHeightSpinBox->setValue(imageCaptureSettings->getSpatialHeight()); m_imageHeightSpinBox->blockSignals(false); m_imageResolutionSpinBox->blockSignals(true); m_imageResolutionSpinBox->setValue(imageCaptureSettings->getImageResolutionInSelectedUnits()); m_imageResolutionSpinBox->blockSignals(false); m_imageSpatialUnitsEnumComboBox->setSelectedItem(imageCaptureSettings->getSpatialUnits()); m_imagePixelsPerSpatialUnitsEnumComboBox->setSelectedItem(imageCaptureSettings->getImageResolutionUnits()); AString windowSizeText = "Size of Window"; int32_t width; int32_t height; float aspectRatio; if (getSelectedWindowWidthAndHeight(width, height, aspectRatio)) { windowSizeText += (" (" + AString::number(width) + " x " + AString::number(height) + " pixels)"); if (imageCaptureSettings->isScaleProportionately()) { imageCaptureSettings->updateForAspectRatio(width, height); } CaretAssert(m_imageDimensionsWidget); m_imageDimensionsWidget->setEnabled(true); } else { windowSizeText += (" (Invalid Window Number)"); CaretAssert(m_imageDimensionsWidget); m_imageDimensionsWidget->setEnabled(false); } m_imageSizeWindowRadioButton->setText(windowSizeText); updateImageNumberOfBytesLabel(); } /** * Update the section. */ void ImageCaptureDialog::updateImageOptionsSection() { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); CaretAssert(imageCaptureSettings); m_imageAutoCropCheckBox->setChecked(imageCaptureSettings->isCroppingEnabled()); m_imageAutoCropMarginSpinBox->blockSignals(true); m_imageAutoCropMarginSpinBox->setValue(imageCaptureSettings->getCroppingMargin()); m_imageAutoCropMarginSpinBox->blockSignals(false); } /** * Update the section. */ void ImageCaptureDialog::updateDestinationSection() { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); CaretAssert(imageCaptureSettings); m_copyImageToClipboardCheckBox->setChecked(imageCaptureSettings->isCopyToClipboardEnabled()); m_saveImageToFileCheckBox->setChecked(imageCaptureSettings->isSaveToFileEnabled()); m_imageFileNameLineEdit->setText(imageCaptureSettings->getImageFileName()); } /** * Update the image number of bytes label. */ void ImageCaptureDialog::updateImageNumberOfBytesLabel() { int32_t imageWidth = 0; int32_t imageHeight = 0; if (m_imageSizeCustomRadioButton->isChecked()) { imageWidth = m_pixelWidthSpinBox->value(); imageHeight = m_pixelHeightSpinBox->value(); } else if (m_imageSizeWindowRadioButton->isChecked()) { float aspectRatio = 0.0; if ( ! getSelectedWindowWidthAndHeight(imageWidth, imageHeight, aspectRatio)) { imageWidth = 0; imageHeight = 0; } } const int64_t bytesPerPixel = 3; // RGB const int64_t numberOfBytes = (static_cast(imageWidth) * static_cast(imageHeight) * bytesPerPixel); if (numberOfBytes > 0) { const AString sizeString = FileInformation::fileSizeToStandardUnits(numberOfBytes); m_imageNumberOfBytesLabel->setText(sizeString); } else { m_imageNumberOfBytesLabel->setText("Invalid/Unknown"); } } /** * Update the radio containing the size of the window. */ void ImageCaptureDialog::updateBrowserWindowWidthAndHeightLabel() { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); AString windowSizeText = "Size of Window"; int32_t width; int32_t height; float aspectRatio; if (getSelectedWindowWidthAndHeight(width, height, aspectRatio)) { windowSizeText += (" (" + AString::number(width) + " x " + AString::number(height) + " pixels)"); if (m_scaleProportionallyCheckBox->isChecked()) { imageCaptureSettings->updateForAspectRatio(width, height); } updateDimensionsSection(); CaretAssert(m_imageDimensionsWidget); m_imageDimensionsWidget->setEnabled(true); } else { windowSizeText += (" (Invalid Window Number)"); CaretAssert(m_imageDimensionsWidget); m_imageDimensionsWidget->setEnabled(false); } m_imageSizeWindowRadioButton->setText(windowSizeText); } /** * Called when pixel width value is changed. * * @param value * New value. */ void ImageCaptureDialog::pixelWidthValueChanged(int value) { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); imageCaptureSettings->setPixelWidth(value); updateDimensionsSection(); } /** * Called when pixel height value is changed. * * @param value * New value. */ void ImageCaptureDialog::pixelHeightValueChanged(int value) { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); imageCaptureSettings->setPixelHeight(value); updateDimensionsSection(); } /** * Called when image width value is changed. * * @param value * New value. */ void ImageCaptureDialog::imageWidthValueChanged(double value) { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); imageCaptureSettings->setSpatialWidth(value); updateDimensionsSection(); } /** * Called when image height value is changed. * * @param value * New value. */ void ImageCaptureDialog::imageHeightValueChanged(double value) { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); imageCaptureSettings->setSpatialHeight(value); updateDimensionsSection(); } /** * Called when image resolution value changed. * * @param value * New value. */ void ImageCaptureDialog::imageResolutionValueChanged(double value) { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); imageCaptureSettings->setImageResolutionInSelectedUnits(value); updateDimensionsSection(); } /** * Called when scale proportionately check box clicked. * * @parm checked * New checked status. */ void ImageCaptureDialog::scaleProportionallyCheckBoxClicked(bool checked) { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); imageCaptureSettings->setScaleProportionately(checked); if (checked) { /* * Will cause pixel height to change appropriately */ int32_t windowWidth; int32_t windowHeight; float aspectRatio; if (getSelectedWindowWidthAndHeight(windowWidth, windowHeight, aspectRatio)) { imageCaptureSettings->updateForAspectRatio(windowWidth, windowHeight); updateDimensionsSection(); } } } /** * Called when value for cropping margin is changed. * * @parm value * New value for cropping margin. */ void ImageCaptureDialog::imageCroppingMarginValueChanged(int value) { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); imageCaptureSettings->setCroppingMargin(value); } /** * Called when scale proportionately check box clicked. * * @parm checked * New checked status. */ void ImageCaptureDialog::imageCroppingCheckBoxClicked(bool checked) { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); imageCaptureSettings->setCroppingEnabled(checked); } /** * Called when scale proportionately check box clicked. * * @parm checked * New checked status. */ void ImageCaptureDialog::copyImageToClipboardCheckBoxClicked(bool checked) { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); imageCaptureSettings->setCopyToClipboardEnabled(checked); } /** * Called when scale proportionately check box clicked. * * @parm checked * New checked status. */ void ImageCaptureDialog::saveImageToFileCheckBoxClicked(bool checked) { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); imageCaptureSettings->setSaveToFileEnabled(checked); } /** * @return Create and return the image destination section. */ QWidget* ImageCaptureDialog::createImageDestinationSection() { m_copyImageToClipboardCheckBox = new QCheckBox("Copy to Clipboard"); QObject::connect(m_copyImageToClipboardCheckBox, SIGNAL(clicked(bool)), this, SLOT(copyImageToClipboardCheckBoxClicked(bool))); m_saveImageToFileCheckBox = new QCheckBox("Save to File: " ); QObject::connect(m_saveImageToFileCheckBox, SIGNAL(clicked(bool)), this, SLOT(saveImageToFileCheckBoxClicked(bool))); m_imageFileNameLineEdit = new QLineEdit(); m_imageFileNameLineEdit->setText("untitled.png"); QObject::connect(m_imageFileNameLineEdit, SIGNAL(editingFinished()), this, SLOT(imageFileNameValueChanged())); QPushButton* fileNameSelectionPushButton = new QPushButton("Choose File..."); QObject::connect(fileNameSelectionPushButton, SIGNAL(clicked()), this, SLOT(selectImagePushButtonPressed())); QGroupBox* groupBox = new QGroupBox("Destination"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(m_copyImageToClipboardCheckBox, 0, 0, 1, 3); gridLayout->addWidget(m_saveImageToFileCheckBox, 1, 0); gridLayout->addWidget(m_imageFileNameLineEdit, 1, 1); gridLayout->addWidget(fileNameSelectionPushButton, 1, 2); return groupBox; } /** * Receive events from the event manager. * * @param event * Event sent by event manager. */ void ImageCaptureDialog::receiveEvent(Event* event) { AString windowSizeText = ""; if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN) { EventBrowserWindowGraphicsRedrawn* graphicsRedrawnEvent = dynamic_cast(event); CaretAssert(graphicsRedrawnEvent); graphicsRedrawnEvent->setEventProcessed(); updateBrowserWindowWidthAndHeightLabel(); } } /** * Get the width and height of the selected window. * * @param xOut * X-Offset of window graphics * @param yOut * Y-Offset of window graphics * @param widthOut * Width of window with aspect applied. * @param heightOut * Height of window with aspect applied * @param int32_t& graphicsWidthOut * Width of graphics without aspect applied. * @param int32_t& graphicsHeightOut * Height of graphics without aspect applied. * @param aspectRatioOut * Aspect ratio of window (height / width) * @return * True if selected window is valid and both height and width * are greater than zero, else false. */ bool ImageCaptureDialog::getSelectedWindowCoordsWidthAndHeight(int32_t& xOut, int32_t& yOut, int32_t& widthOut, int32_t& heightOut, int32_t& graphicsWidthOut, int32_t& graphicsHeightOut, float& aspectRatioOut) const { xOut = 0; yOut = 0; widthOut = 0; heightOut = 0; graphicsWidthOut = 0; graphicsHeightOut = 0; const int selectedBrowserWindowIndex = m_windowSelectionSpinBox->value() - 1; BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(selectedBrowserWindowIndex); if (browserWindow != NULL) { browserWindow->getGraphicsWidgetSize(xOut, yOut, widthOut, heightOut, graphicsWidthOut, graphicsHeightOut, m_windowCropToLockAspectRegionCheckBox->isChecked()); if ((widthOut > 0) && (heightOut > 0)) { aspectRatioOut = (static_cast(heightOut) / static_cast(widthOut)); return true; } } return false; } /** * Get the width and height of the selected window. * * @param widthOut * Width of window. * @param heightOut * Height of window. * @param aspectRatioOut * Aspect ratio of window (height / width) * @return * True if selected window is valid and both height and width * are greater than zero, else false. */ bool ImageCaptureDialog::getSelectedWindowWidthAndHeight(int32_t& widthOut, int32_t& heightOut, float& aspectRatioOut) const { int32_t x = 0; int32_t y = 0; int32_t graphicsWidth = 0; int32_t graphicsHeight = 0; return getSelectedWindowCoordsWidthAndHeight(x, y, widthOut, heightOut, graphicsWidth, graphicsHeight, aspectRatioOut); } /** * Set the selected browser window to the browser window with the * given index. * @param browserWindowIndex * Index of browser window. */ void ImageCaptureDialog::setBrowserWindowIndex(const int32_t browserWindowIndex) { m_windowSelectionSpinBox->setValue(browserWindowIndex + 1); } /** * Called when choose file pushbutton is pressed. */ void ImageCaptureDialog::selectImagePushButtonPressed() { QString defaultFileName = m_imageFileNameLineEdit->text().trimmed(); if (defaultFileName.isEmpty()) { defaultFileName = "untitled.png"; } FileInformation fileInfo(m_imageFileNameLineEdit->text().trimmed()); if (fileInfo.isRelative()) { FileInformation absFileInfo(GuiManager::get()->getBrain()->getCurrentDirectory(), m_imageFileNameLineEdit->text().trimmed()); defaultFileName = absFileInfo.getAbsoluteFilePath(); } std::vector imageFileFilters; AString defaultFileFilter; ImageFile::getImageFileFilters(imageFileFilters, defaultFileFilter); QString filters; for (std::vector::iterator filterIterator = imageFileFilters.begin(); filterIterator != imageFileFilters.end(); filterIterator++) { if (filters.isEmpty() == false) { filters += ";;"; } filters += *filterIterator; } AString name = CaretFileDialog::getSaveFileNameDialog(this, "Choose File Name", defaultFileName, //GuiManager::get()->getBrain()->getCurrentDirectory(), filters, &defaultFileFilter); if (name.isEmpty() == false) { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); imageCaptureSettings->setImageFileName(name); updateDestinationSection(); } } /** * Gets called when user changes name of the image file. */ void ImageCaptureDialog::imageFileNameValueChanged() { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); imageCaptureSettings->setImageFileName(m_imageFileNameLineEdit->text().trimmed()); } /** * Called when the apply button is pressed. */ void ImageCaptureDialog::applyButtonClicked() { ImageCaptureSettings* imageCaptureSettings = SessionManager::get()->getImageCaptureDialogSettings(); const int browserWindowIndex = m_windowSelectionSpinBox->value() - 1; int32_t windowX; int32_t windowY; int32_t windowWidth; int32_t windowHeight; int32_t widgetWidth; int32_t widgetHeight; float windowAspectRatio; if ( ! getSelectedWindowCoordsWidthAndHeight(windowX, windowY, windowWidth, windowHeight, widgetWidth, widgetHeight, windowAspectRatio)) { WuQMessageBox::errorOk(this, "Failed to get window size"); return; } AString imageFileName = m_imageFileNameLineEdit->text().trimmed(); if (m_saveImageToFileCheckBox->isChecked()) { if (imageFileName.isEmpty()) { WuQMessageBox::errorOk(this, "Save to File name is empty. Choose an Image File."); return; } } /* * Default to width of window that may exclude empty regions * caused by locking of aspect ratio. */ int32_t imageWidth = windowWidth; int32_t imageHeight = windowHeight; if (m_imageSizeCustomRadioButton->isChecked()) { imageWidth = m_pixelWidthSpinBox->value(); imageHeight = m_pixelHeightSpinBox->value(); if ((windowWidth > 0) && (windowHeight > 0)) { const float windowWidthScaling = (static_cast(imageWidth) / static_cast(windowWidth)); const float windowHeightScaling = (static_cast(imageHeight) / static_cast(windowHeight)); ChartMatrixDisplayProperties::setManualScaleModeWindowWidthHeightScaling(windowWidthScaling, windowHeightScaling); } } EventImageCapture imageCaptureEvent(browserWindowIndex, windowX, windowY, windowWidth, windowHeight, imageWidth, imageHeight); EventManager::get()->sendEvent(imageCaptureEvent.getPointer()); bool errorFlag = false; if (imageCaptureEvent.getEventProcessCount() <= 0) { WuQMessageBox::errorOk(this, "Invalid window selected"); errorFlag = true; } else if (imageCaptureEvent.isError()) { WuQMessageBox::errorOk(this, imageCaptureEvent.getErrorMessage()); errorFlag = true; } if ( ! errorFlag) { uint8_t backgroundColor[3]; imageCaptureEvent.getBackgroundColor(backgroundColor); ImageFile imageFile; imageFile.setFromQImage(imageCaptureEvent.getImage()); const float pixelsPerCentimeter = imageCaptureSettings->getImageResolutionInCentimeters(); const float pixelsPerMeter = pixelsPerCentimeter * 100; imageFile.setDotsPerMeter(pixelsPerMeter, pixelsPerMeter); if (imageCaptureSettings->isCroppingEnabled()) { const int32_t marginSize = imageCaptureSettings->getCroppingMargin(); imageFile.cropImageRemoveBackground(marginSize, backgroundColor); } if (m_copyImageToClipboardCheckBox->isChecked()) { QApplication::clipboard()->setImage(*imageFile.getAsQImage(), QClipboard::Clipboard); } if (m_saveImageToFileCheckBox->isChecked()) { std::vector imageFileExtensions; AString defaultFileExtension; ImageFile::getImageFileExtensions(imageFileExtensions, defaultFileExtension); CaretAssert( ! imageFileName.isEmpty()); bool validExtension = false; for (std::vector::iterator extensionIterator = imageFileExtensions.begin(); extensionIterator != imageFileExtensions.end(); extensionIterator++) { if (imageFileName.endsWith(*extensionIterator)) { validExtension = true; } } if ( ! validExtension) { if (defaultFileExtension.isEmpty() == false) { imageFileName += ("." + defaultFileExtension); } } try { imageFile.writeFile(imageFileName); } catch (const DataFileException& /*e*/) { QString msg("Unable to save: " + imageFileName); WuQMessageBox::errorOk(this, msg); errorFlag = true; } } } ChartMatrixDisplayProperties::setManualScaleModeWindowWidthHeightScaling(1.0, 1.0); if ( ! errorFlag) { /* * Display over "Capture" (the renamed Apply) button. */ QWidget* parent = getDialogButtonBox()->button(QDialogButtonBox::Apply); CaretAssert(parent); WuQTimedMessageDisplay::showNonModal(parent, 3.0, "Image captured"); } EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(browserWindowIndex).getPointer()); } connectome-workbench-1.4.2/src/GuiQt/ImageCaptureDialog.h000066400000000000000000000121331360521144700233120ustar00rootroot00000000000000#ifndef __IMAGE_CAPTURE_DIALOG__H_ #define __IMAGE_CAPTURE_DIALOG__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventListenerInterface.h" #include "WuQDialogNonModal.h" class QCheckBox; class QDoubleSpinBox; class QLabel; class QLineEdit; class QRadioButton; class QSpinBox; namespace caret { class BrainBrowserWindow; class EnumComboBoxTemplate; class ImageCaptureSettings; class WuQWidgetObjectGroup; class ImageCaptureDialog : public WuQDialogNonModal, public EventListenerInterface { Q_OBJECT public: ImageCaptureDialog(BrainBrowserWindow* parent); virtual ~ImageCaptureDialog(); void setBrowserWindowIndex(const int32_t browserWindowIndex); void updateDialog(); void receiveEvent(Event* event); protected: virtual void applyButtonClicked(); private slots: void selectImagePushButtonPressed(); void cropToTabWindowLockAspectRegionClicked(bool clicked); void updateBrowserWindowWidthAndHeightLabel(); void imageResolutionUnitsEnumComboBoxItemActivated(); void imageSizeUnitsEnumComboBoxItemActivated(); void pixelWidthValueChanged(int); void pixelHeightValueChanged(int); void imageFileNameValueChanged(); void imageWidthValueChanged(double); void imageHeightValueChanged(double); void imageResolutionValueChanged(double); void scaleProportionallyCheckBoxClicked(bool); void imageCroppingCheckBoxClicked(bool); void imageCroppingMarginValueChanged(int); void copyImageToClipboardCheckBoxClicked(bool); void saveImageToFileCheckBoxClicked(bool); void sizeRadioButtonClicked(QAbstractButton* button); private: ImageCaptureDialog(const ImageCaptureDialog&); ImageCaptureDialog& operator=(const ImageCaptureDialog&); QWidget* createImageSourceSection(); QWidget* createImageOptionsSection(); QWidget* createImageDimensionsSection(); QWidget* createImageDestinationSection(); void updateDimensionsSection(); void updateImageOptionsSection(); void updateDestinationSection(); bool getSelectedWindowCoordsWidthAndHeight(int32_t& xOut, int32_t& yOut, int32_t& widthOut, int32_t& heightOut, int32_t& graphicsWidthOut, int32_t& graphicsHeightOut, float& aspectRatioOut) const; bool getSelectedWindowWidthAndHeight(int32_t& widthOut, int32_t& heightOut, float& aspectRatioOut) const; void updateImageNumberOfBytesLabel(); QCheckBox* m_saveImageToFileCheckBox; QCheckBox* m_copyImageToClipboardCheckBox; QLineEdit* m_imageFileNameLineEdit; QRadioButton* m_imageSizeWindowRadioButton; QRadioButton* m_imageSizeCustomRadioButton; QSpinBox* m_pixelWidthSpinBox; QSpinBox* m_pixelHeightSpinBox; QDoubleSpinBox* m_imageWidthSpinBox; QDoubleSpinBox* m_imageHeightSpinBox; QDoubleSpinBox* m_imageResolutionSpinBox; QCheckBox* m_scaleProportionallyCheckBox; EnumComboBoxTemplate* m_imagePixelsPerSpatialUnitsEnumComboBox; EnumComboBoxTemplate* m_imageSpatialUnitsEnumComboBox; QLabel* m_imageNumberOfBytesLabel; QCheckBox* m_imageAutoCropCheckBox; QSpinBox* m_imageAutoCropMarginSpinBox; QSpinBox* m_windowSelectionSpinBox; QCheckBox* m_windowCropToLockAspectRegionCheckBox; QWidget* m_customDimensionsWidget; QWidget* m_imageDimensionsWidget; }; #ifdef __IMAGE_CAPTURE_DIALOG__H__DECLARE__ #endif // __IMAGE_CAPTURE_DIALOG__H__DECLARE__ } // namespace #endif //__IMAGE_CAPTURE_DIALOG__H_ connectome-workbench-1.4.2/src/GuiQt/ImageFileConvertToVolumeFileDialog.cxx000066400000000000000000000335411360521144700270030ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __IMAGE_FILE_CONVERT_TO_VOLUME_FILE_DIALOG_DECLARE__ #include "ImageFileConvertToVolumeFileDialog.h" #undef __IMAGE_FILE_CONVERT_TO_VOLUME_FILE_DIALOG_DECLARE__ #include #include #include #include #include #include "Brain.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "ControlPointFile.h" #include "ControlPoint3D.h" #include "DisplayPropertiesImages.h" #include "EventBrowserTabGet.h" #include "EventDataFileAdd.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "FileInformation.h" #include "GuiManager.h" #include "ImageFile.h" #include "Matrix4x4.h" #include "VolumeFile.h" #include "VolumeSliceViewPlaneEnum.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::ImageFileConvertToVolumeFileDialog * \brief Dialog for converting an image file to a volume file. * \ingroup GuiQt */ /** * Constructor. */ ImageFileConvertToVolumeFileDialog::ImageFileConvertToVolumeFileDialog(QWidget* parent, const int32_t tabIndex, ImageFile* imageFile) : WuQDialogModal("Convert Image File to Volume File", parent), m_tabIndex(tabIndex), m_imageFile(imageFile) { CaretAssert(m_imageFile); QWidget* volumeWidget = createVolumeSelectionWidget(); QWidget* controlPointWidget = createControlPointWidget(); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(volumeWidget); layout->addWidget(controlPointWidget); setCentralWidget(widget, WuQDialog::SCROLL_AREA_NEVER); } /** * Destructor. */ ImageFileConvertToVolumeFileDialog::~ImageFileConvertToVolumeFileDialog() { } /** * @return New instance of the volume selection widget. */ QWidget* ImageFileConvertToVolumeFileDialog::createVolumeSelectionWidget() { FileInformation fileInfo(m_imageFile->getFileName()); const AString volumeFileName = FileInformation::assembleFileComponents(fileInfo.getAbsolutePath(), fileInfo.getFileNameNoExtension(), DataFileTypeEnum::toFileExtension(DataFileTypeEnum::VOLUME)); QLabel* volumeFileNameLabel = new QLabel("Volume File Name:"); m_volumeFileNameLineEdit = new QLineEdit; m_volumeFileNameLineEdit->setText(volumeFileName); std::vector slicePlanes; slicePlanes.push_back(VolumeSliceViewPlaneEnum::ALL); slicePlanes.push_back(VolumeSliceViewPlaneEnum::AXIAL); slicePlanes.push_back(VolumeSliceViewPlaneEnum::CORONAL); slicePlanes.push_back(VolumeSliceViewPlaneEnum::PARASAGITTAL); QLabel* colorConversionLabel = new QLabel("Color Conversion:"); m_colorConversionComboBox = new QComboBox(); m_colorConversionComboBox->addItem("Grayscale"); m_colorConversionComboBox->setItemData(0, ImageFile::CONVERT_TO_VOLUME_COLOR_GRAYSCALE); m_colorConversionComboBox->addItem("RGB"); m_colorConversionComboBox->setItemData(1, ImageFile::CONVERT_TO_VOLUME_COLOR_RGB); QGroupBox* groupBox = new QGroupBox("Volume Selection"); QGridLayout* layout = new QGridLayout(groupBox); layout->setColumnStretch(0, 0); layout->setColumnStretch(1, 100); layout->setColumnMinimumWidth(1, 250); int row = layout->rowCount(); layout->addWidget(volumeFileNameLabel, row, 0); layout->addWidget(m_volumeFileNameLineEdit, row, 1); row++; layout->addWidget(colorConversionLabel, row, 0); layout->addWidget(m_colorConversionComboBox, row, 1); row++; return groupBox; } /** * @return New instance of the control point widget. */ QWidget* ImageFileConvertToVolumeFileDialog::createControlPointWidget() { const ControlPointFile* controlPointFile = m_imageFile->getControlPointFile(); const int32_t numberOfControlPoints = controlPointFile->getNumberOfControlPoints(); int32_t columnCounter = 0; const int32_t COLUMN_PIXEL_I = columnCounter++; const int32_t COLUMN_PIXEL_J = columnCounter++; const int32_t COLUMN_SEPARATOR_1 = columnCounter++; const int32_t COLUMN_VOLUME_X = columnCounter++; const int32_t COLUMN_VOLUME_Y = columnCounter++; const int32_t COLUMN_VOLUME_Z = columnCounter++; const int32_t COLUMN_SEPARATOR_2 = columnCounter++; const int32_t COLUMN_TRANSFORMED_X = columnCounter++; const int32_t COLUMN_TRANSFORMED_Y = columnCounter++; const int32_t COLUMN_TRANSFORMED_Z = columnCounter++; const int32_t COLUMN_SEPARATOR_3 = columnCounter++; const int32_t COLUMN_ERROR_X = columnCounter++; const int32_t COLUMN_ERROR_Y = columnCounter++; const int32_t COLUMN_ERROR_Z = columnCounter++; const int32_t COLUMN_ERROR_TOTAL = columnCounter++; const int32_t FLOAT_PRECISION = 1; QGroupBox* widget = new QGroupBox("Control Points"); QGridLayout* gridLayout = new QGridLayout(widget); int32_t row = gridLayout->rowCount(); gridLayout->addWidget(new QLabel("Image"), row, COLUMN_PIXEL_I, 1, 2, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Volume"), row, COLUMN_VOLUME_X, 1, 3, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Transformed"), row, COLUMN_TRANSFORMED_X, 1, 3, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Error"), row, COLUMN_ERROR_X, 1, 4, Qt::AlignHCenter); row++; gridLayout->addWidget(new QLabel("I"), row, COLUMN_PIXEL_I, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("J"), row, COLUMN_PIXEL_J, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("X"), row, COLUMN_VOLUME_X, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Y"), row, COLUMN_VOLUME_Y, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Z"), row, COLUMN_VOLUME_Z, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("X"), row, COLUMN_TRANSFORMED_X, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Y"), row, COLUMN_TRANSFORMED_Y, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Z"), row, COLUMN_TRANSFORMED_Z, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("X"), row, COLUMN_ERROR_X, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Y"), row, COLUMN_ERROR_Y, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Z"), row, COLUMN_ERROR_Z, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Total"), row, COLUMN_ERROR_TOTAL, Qt::AlignHCenter); row++; for (int32_t icp = 0; icp < numberOfControlPoints; icp++) { const ControlPoint3D* cp = controlPointFile->getControlPointAtIndex(icp); float sourceXYZ[3]; cp->getSourceXYZ(sourceXYZ); gridLayout->addWidget(new QLabel(QString::number(sourceXYZ[0], 'f', 0)), row, COLUMN_PIXEL_I, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(sourceXYZ[1], 'f', 0)), row, COLUMN_PIXEL_J, Qt::AlignRight); float targetXYZ[3]; cp->getTargetXYZ(targetXYZ); gridLayout->addWidget(new QLabel(QString::number(targetXYZ[0], 'f', FLOAT_PRECISION)), row, COLUMN_VOLUME_X, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(targetXYZ[1], 'f', FLOAT_PRECISION)), row, COLUMN_VOLUME_Y, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(targetXYZ[2], 'f', FLOAT_PRECISION)), row, COLUMN_VOLUME_Z, Qt::AlignRight); float transformedXYZ[3]; cp->getTransformedXYZ(transformedXYZ); gridLayout->addWidget(new QLabel(QString::number(transformedXYZ[0], 'f', FLOAT_PRECISION)), row, COLUMN_TRANSFORMED_X, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(transformedXYZ[1], 'f', FLOAT_PRECISION)), row, COLUMN_TRANSFORMED_Y, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(transformedXYZ[2], 'f', FLOAT_PRECISION)), row, COLUMN_TRANSFORMED_Z, Qt::AlignRight); float errorXYZTotal[4]; cp->getErrorMeasurements(errorXYZTotal); gridLayout->addWidget(new QLabel(QString::number(errorXYZTotal[0], 'f', FLOAT_PRECISION)), row, COLUMN_ERROR_X, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(errorXYZTotal[1], 'f', FLOAT_PRECISION)), row, COLUMN_ERROR_Y, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(errorXYZTotal[2], 'f', FLOAT_PRECISION)), row, COLUMN_ERROR_Z, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(errorXYZTotal[3], 'f', FLOAT_PRECISION)), row, COLUMN_ERROR_TOTAL, Qt::AlignRight); row++; } gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 0, COLUMN_SEPARATOR_1, row, 1); gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 0, COLUMN_SEPARATOR_2, row, 1); gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 0, COLUMN_SEPARATOR_3, row, 1); return widget; } /** * Gets called when the OK button is clicked. */ void ImageFileConvertToVolumeFileDialog::okButtonClicked() { EventBrowserTabGet tabEvent(m_tabIndex); EventManager::get()->sendEvent(tabEvent.getPointer()); BrowserTabContent* tabContent = tabEvent.getBrowserTab(); ModelWholeBrain* wholeBrainModel = NULL; ModelVolume* volumeModel = NULL; if (tabContent != NULL) { volumeModel = tabContent->getDisplayedVolumeModel(); wholeBrainModel = tabContent->getDisplayedWholeBrainModel(); } if ((volumeModel == NULL) && (wholeBrainModel == NULL)) { WuQMessageBox::errorOk(this, "Conversion must be performed in ALL or VOLUME view."); return; } float translation[3]; tabContent->getTranslation(translation); Matrix4x4 rotMatrix = tabContent->getRotationMatrix(); const float scaling = tabContent->getScaling(); Matrix4x4 sformMatrix; sformMatrix.translate(translation[0], translation[1], translation[2]); sformMatrix.postmultiply(rotMatrix); sformMatrix.scale(scaling, scaling, scaling); CaretAssert(m_imageFile); std::vector controlPoints; const ControlPointFile* controlPointFile = m_imageFile->getControlPointFile(); const int32_t numberOfControlPoints = controlPointFile->getNumberOfControlPoints(); for (int32_t icp = 0; icp < numberOfControlPoints; icp++) { controlPoints.push_back(*controlPointFile->getControlPointAtIndex(icp)); } const int colorConversionIndex = m_colorConversionComboBox->itemData(m_colorConversionComboBox->currentIndex()).toInt(); const ImageFile::CONVERT_TO_VOLUME_COLOR_MODE colorMode = static_cast(colorConversionIndex); AString errorMessage; VolumeFile* volumeFile = m_imageFile->convertToVolumeFile(colorMode, errorMessage); if (volumeFile == NULL) { WuQMessageBox::errorOk(this, errorMessage); return; } volumeFile->setFileName(m_volumeFileNameLineEdit->text().trimmed()); EventManager::get()->sendEvent(EventDataFileAdd(volumeFile).getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); WuQDialogModal::okButtonClicked(); } connectome-workbench-1.4.2/src/GuiQt/ImageFileConvertToVolumeFileDialog.h000066400000000000000000000045361360521144700264320ustar00rootroot00000000000000#ifndef __IMAGE_FILE_CONVERT_TO_VOLUME_FILE_DIALOG_H__ #define __IMAGE_FILE_CONVERT_TO_VOLUME_FILE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretPointer.h" #include "WuQDialogModal.h" class QComboBox; class QLineEdit; class QTableWidget; namespace caret { class ImageFile; class ImageFileConvertToVolumeFileDialog : public WuQDialogModal { Q_OBJECT public: ImageFileConvertToVolumeFileDialog(QWidget* parent, const int32_t tabIndex, ImageFile* imageFile); virtual ~ImageFileConvertToVolumeFileDialog(); // ADD_NEW_METHODS_HERE protected: virtual void okButtonClicked(); private: ImageFileConvertToVolumeFileDialog(const ImageFileConvertToVolumeFileDialog&); ImageFileConvertToVolumeFileDialog& operator=(const ImageFileConvertToVolumeFileDialog&); QWidget* createVolumeSelectionWidget(); QWidget* createControlPointWidget(); // ADD_NEW_MEMBERS_HERE const int32_t m_tabIndex; ImageFile* m_imageFile; QLineEdit* m_volumeFileNameLineEdit; QComboBox* m_colorConversionComboBox; QTableWidget* m_tableWidget; }; #ifdef __IMAGE_FILE_CONVERT_TO_VOLUME_FILE_DIALOG_DECLARE__ // #endif // __IMAGE_FILE_CONVERT_TO_VOLUME_FILE_DIALOG_DECLARE__ } // namespace #endif //__IMAGE_FILE_CONVERT_TO_VOLUME_FILE_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/ImageSelectionViewController.cxx000066400000000000000000000540651360521144700260000ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #define __IMAGE_SELECTION_VIEW_CONTROLLER_DECLARE__ #include "ImageSelectionViewController.h" #undef __IMAGE_SELECTION_VIEW_CONTROLLER_DECLARE__ #include "Brain.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "DisplayGroupEnumComboBox.h" #include "DisplayPropertiesImages.h" #include "EnumComboBoxTemplate.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "ImageFile.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "WuQMacroManager.h" #include "WuQSpinBoxGroup.h" #include "WuQtUtilities.h" #include "WuQTabWidget.h" using namespace caret; static const int COLUMN_RADIO_BUTTON = 0; /** * \class caret::ImageSelectionViewController * \brief View controller for image selection * \ingroup GuiQt */ /** * Constructor. */ ImageSelectionViewController::ImageSelectionViewController(const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent) : QWidget(parent), m_browserWindowIndex(browserWindowIndex), m_objectNamePrefix(parentObjectName + ":Image") { setWindowTitle("Images"); WuQMacroManager* macroManager = WuQMacroManager::instance(); m_sceneAssistant = new SceneClassAssistant(); QLabel* groupLabel = new QLabel("Group"); m_imagesDisplayGroupComboBox = new DisplayGroupEnumComboBox(this, (m_objectNamePrefix + ":DisplayGroup"), "images"); QObject::connect(m_imagesDisplayGroupComboBox, SIGNAL(displayGroupSelected(const DisplayGroupEnum::Enum)), this, SLOT(imageDisplayGroupSelected(const DisplayGroupEnum::Enum))); QHBoxLayout* groupLayout = new QHBoxLayout(); groupLayout->addWidget(groupLabel); groupLayout->addWidget(m_imagesDisplayGroupComboBox->getWidget()); groupLayout->addStretch(); m_imageDisplayCheckBox = new QCheckBox("Display Image"); QObject::connect(m_imageDisplayCheckBox, SIGNAL(clicked(bool)), this, SLOT(processAttributesChanges())); m_imageDisplayCheckBox->setToolTip("Display Image"); m_imageDisplayCheckBox->setObjectName(m_objectNamePrefix + ":Display"); macroManager->addMacroSupportToObject(m_imageDisplayCheckBox, "Enable display of image"); m_controlPointsDisplayCheckBox = new QCheckBox("Display Control Points"); QObject::connect(m_controlPointsDisplayCheckBox, SIGNAL(clicked(bool)), this, SLOT(processAttributesChanges())); m_controlPointsDisplayCheckBox->setToolTip("Display Control Points"); m_controlPointsDisplayCheckBox->setObjectName(m_objectNamePrefix + ":DisplayControlPoints"); macroManager->addMacroSupportToObject(m_controlPointsDisplayCheckBox, "Display image control points"); QWidget* attributesWidget = this->createAttributesWidget(); QWidget* selectionWidget = this->createSelectionWidget(); m_tabWidget = new WuQTabWidget(WuQTabWidget::TAB_ALIGN_LEFT, this); m_tabWidget->addTab(attributesWidget, "Attributes"); m_tabWidget->addTab(selectionWidget, "Selection"); m_tabWidget->setCurrentWidget(attributesWidget); m_tabWidget->getTabBar()->setObjectName(m_objectNamePrefix + ":Tab"); macroManager->addMacroSupportToObjectWithToolTip(m_tabWidget->getTabBar(), "Select features toolbox image tab", "Features ToolBox Image Tab"); QVBoxLayout* layout = new QVBoxLayout(this); // WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); layout->addLayout(groupLayout, 0); layout->addWidget(m_imageDisplayCheckBox, 0); layout->addWidget(m_controlPointsDisplayCheckBox, 0); layout->addSpacing(10); layout->addWidget(m_tabWidget->getWidget(), 100); layout->addStretch(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); s_allImageSelectionViewControllers.insert(this); } /** * Destructor. */ ImageSelectionViewController::~ImageSelectionViewController() { EventManager::get()->removeAllEventsFromListener(this); s_allImageSelectionViewControllers.erase(this); delete m_sceneAssistant; } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void ImageSelectionViewController::receiveEvent(Event* event) { bool doUpdate = false; if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiEvent = dynamic_cast(event); CaretAssert(uiEvent); if (uiEvent->isUpdateForWindow(m_browserWindowIndex)) { if (uiEvent->isToolBoxUpdate()) { doUpdate = true; uiEvent->setEventProcessed(); } } } if (doUpdate) { updateImageViewController(); } } /** * Create the image selection widget. */ QWidget* ImageSelectionViewController::createSelectionWidget() { m_imageRadioButtonGroup = new QButtonGroup(this); QObject::connect(m_imageRadioButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(imageRadioButtonClicked(int))); QWidget* imageRadioButtonWidget = new QWidget(); imageRadioButtonWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); m_imageRadioButtonLayout = new QGridLayout(imageRadioButtonWidget); m_imageRadioButtonLayout->setColumnStretch(COLUMN_RADIO_BUTTON, 100); const int imageLayoutRow = m_imageRadioButtonLayout->rowCount(); m_imageRadioButtonLayout->addWidget(new QLabel("Image"), imageLayoutRow, COLUMN_RADIO_BUTTON, Qt::AlignHCenter); QScrollArea* imageRadioButtonScrollArea = new QScrollArea(); imageRadioButtonScrollArea->setWidget(imageRadioButtonWidget); imageRadioButtonScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); imageRadioButtonScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); imageRadioButtonScrollArea->setWidgetResizable(true); return imageRadioButtonScrollArea; } /** * @return The attributes widget. */ QWidget* ImageSelectionViewController::createAttributesWidget() { WuQMacroManager* macroManager = WuQMacroManager::instance(); const QString objectNamePrefix(m_objectNamePrefix + ":Attributes"); QLabel* depthLabel = new QLabel("Depth"); m_depthComboBox = new EnumComboBoxTemplate(this); m_depthComboBox->setup(); m_depthComboBox->getWidget()->setToolTip("Set the depth position of the image3"); QObject::connect(m_depthComboBox, SIGNAL(itemActivated()), this, SLOT(processAttributesChanges())); m_depthComboBox->getComboBox()->setObjectName(objectNamePrefix + ":DepthPosition"); macroManager->addMacroSupportToObject(m_depthComboBox->getComboBox(), "Set image depth"); const float threshMin = -1.0; const float threshMax = 100000.0; QLabel* thresholdMinimumLabel = new QLabel("Minimum Threshold"); m_thresholdMinimumSpinBox = WuQFactory::newDoubleSpinBox(); m_thresholdMinimumSpinBox->setFixedWidth(80); m_thresholdMinimumSpinBox->setRange(threshMin, threshMax); m_thresholdMinimumSpinBox->setSingleStep(1.0); m_thresholdMinimumSpinBox->setDecimals(1); m_thresholdMinimumSpinBox->setToolTip("Do not display image pixels containing a color component less than this value"); QObject::connect(m_thresholdMinimumSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); m_thresholdMinimumSpinBox->setObjectName(objectNamePrefix + "MinimumThreshold"); macroManager->addMacroSupportToObject(m_thresholdMinimumSpinBox, "Set image threshold minimum"); QLabel* thresholdMaximumLabel = new QLabel("Maximum Threshold"); m_thresholdMaximumSpinBox = WuQFactory::newDoubleSpinBox(); m_thresholdMaximumSpinBox->setFixedWidth(80); m_thresholdMaximumSpinBox->setRange(threshMin, threshMax); m_thresholdMaximumSpinBox->setSingleStep(1.0); m_thresholdMaximumSpinBox->setDecimals(1); m_thresholdMaximumSpinBox->setToolTip("Do not display image pixels containing a color component greater than this value"); QObject::connect(m_thresholdMaximumSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); m_thresholdMaximumSpinBox->setObjectName(objectNamePrefix + "MaximumThreshold"); macroManager->addMacroSupportToObject(m_thresholdMaximumSpinBox, "Set image threshold maximum"); const float minOpacity = 0.0; const float maxOpacity = 1.0; QLabel* opacityLabel = new QLabel("Opacity"); m_opacitySpinBox = WuQFactory::newDoubleSpinBox(); m_opacitySpinBox->setFixedWidth(80); m_opacitySpinBox->setRange(minOpacity, maxOpacity); m_opacitySpinBox->setSingleStep(0.1); m_opacitySpinBox->setDecimals(1); m_opacitySpinBox->setToolTip("Opacity for image"); QObject::connect(m_opacitySpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); m_opacitySpinBox->setObjectName(objectNamePrefix + ":Opacity"); macroManager->addMacroSupportToObject(m_opacitySpinBox, "Set image opacity"); QWidget* gridWidget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(gridWidget); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 8, 2); int row = gridLayout->rowCount(); gridLayout->addWidget(depthLabel, row, 0); gridLayout->addWidget(m_depthComboBox->getWidget(), row, 1); row++; gridLayout->addWidget(thresholdMinimumLabel, row, 0); gridLayout->addWidget(m_thresholdMinimumSpinBox, row, 1); row++; gridLayout->addWidget(thresholdMaximumLabel, row, 0); gridLayout->addWidget(m_thresholdMaximumSpinBox, row, 1); row++; gridLayout->addWidget(opacityLabel, row, 0); gridLayout->addWidget(m_opacitySpinBox, row, 1); row++; QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(gridWidget); layout->addStretch(); return widget; } /** * Called when a selection changes. */ void ImageSelectionViewController::processAttributesChanges() { DisplayPropertiesImages* dpi = GuiManager::get()->getBrain()->getDisplayPropertiesImages(); BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); const DisplayGroupEnum::Enum displayGroup = dpi->getDisplayGroupForTab(browserTabIndex); dpi->setDisplayed(displayGroup, browserTabIndex, m_imageDisplayCheckBox->isChecked()); dpi->setControlPointsDisplayed(displayGroup, browserTabIndex, m_controlPointsDisplayCheckBox->isChecked()); dpi->setImagePosition(displayGroup, browserTabIndex, m_depthComboBox->getSelectedItem()); dpi->setThresholdMinimum(displayGroup, browserTabIndex, m_thresholdMinimumSpinBox->value()); dpi->setThresholdMaximum(displayGroup, browserTabIndex, m_thresholdMaximumSpinBox->value()); dpi->setOpacity(displayGroup, browserTabIndex, m_opacitySpinBox->value()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); updateOtherImageViewControllers(); } /** * Called when the display group is changed. * * @param displayGroup * Display group selected. */ void ImageSelectionViewController::imageDisplayGroupSelected(const DisplayGroupEnum::Enum displayGroup) { /* * Update selected display group in model. */ BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, false); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); Brain* brain = GuiManager::get()->getBrain(); DisplayPropertiesImages* dsb = brain->getDisplayPropertiesImages(); dsb->setDisplayGroupForTab(browserTabIndex, displayGroup); /* * Since display group has changed, need to update controls */ updateImageViewController(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called when an image radio button is clicked. * * @param buttonID * ID of button that was clicked. */ void ImageSelectionViewController::imageRadioButtonClicked(int buttonID) { BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); Brain* brain = GuiManager::get()->getBrain(); DisplayPropertiesImages* dpi = brain->getDisplayPropertiesImages(); const DisplayGroupEnum::Enum displayGroup = dpi->getDisplayGroupForTab(browserTabIndex); std::vector allImageFiles = brain->getAllImagesFiles(); CaretAssertVectorIndex(allImageFiles, buttonID); dpi->setSelectedImageFile(displayGroup, browserTabIndex, allImageFiles[buttonID]); updateOtherImageViewControllers(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Update the image selection widget. */ void ImageSelectionViewController::updateImageViewController() { BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); Brain* brain = GuiManager::get()->getBrain(); DisplayPropertiesImages* dpi = brain->getDisplayPropertiesImages(); const DisplayGroupEnum::Enum displayGroup = dpi->getDisplayGroupForTab(browserTabIndex); m_imagesDisplayGroupComboBox->setSelectedDisplayGroup(dpi->getDisplayGroupForTab(browserTabIndex)); std::vector allImageFiles = brain->getAllImagesFiles(); m_imageDisplayCheckBox->setChecked(dpi->isDisplayed(displayGroup, browserTabIndex)); m_controlPointsDisplayCheckBox->setChecked(dpi->isControlPointsDisplayed(displayGroup, browserTabIndex)); const int32_t numImageFiles = static_cast(allImageFiles.size()); int32_t numRadioButtons = static_cast(m_imageRadioButtons.size()); if (numImageFiles > numRadioButtons) { const int32_t numToAdd = numImageFiles - numRadioButtons; for (int32_t i = 0; i < numToAdd; i++) { const int buttonID = static_cast(m_imageRadioButtons.size()); QRadioButton* rb = new QRadioButton(""); m_imageRadioButtons.push_back(rb); const int row = m_imageRadioButtonLayout->rowCount(); m_imageRadioButtonLayout->addWidget(rb, row, COLUMN_RADIO_BUTTON); m_imageRadioButtonGroup->addButton(rb, buttonID); const QString buttonName(m_objectNamePrefix + ":Selection:Image" + QString("%1").arg((int)i+1, 2, 10, QLatin1Char('0'))); rb->setObjectName(buttonName); const QString descriptiveName("Select Image" + QString("%1").arg(i + 1)); WuQMacroManager::instance()->addMacroSupportToObjectWithToolTip(rb, descriptiveName, ""); } numRadioButtons = static_cast(m_imageRadioButtons.size()); } const ImageFile* selectedImageFile = dpi->getSelectedImageFile(displayGroup, browserTabIndex); for (int32_t i = 0; i < numRadioButtons; i++) { CaretAssertVectorIndex(m_imageRadioButtons, i); QRadioButton* rb = m_imageRadioButtons[i]; if (i < numImageFiles) { rb->setText(allImageFiles[i]->getFileNameNoPath()); if (allImageFiles[i] == selectedImageFile) { rb->setChecked(true); } rb->setVisible(true); } else { rb->setVisible(false); } } m_depthComboBox->setSelectedItem(dpi->getImagePosition(displayGroup, browserTabIndex)); m_thresholdMinimumSpinBox->blockSignals(true); m_thresholdMinimumSpinBox->setValue(dpi->getThresholdMinimum(displayGroup, browserTabIndex)); m_thresholdMinimumSpinBox->blockSignals(false); m_thresholdMaximumSpinBox->blockSignals(true); m_thresholdMaximumSpinBox->setValue(dpi->getThresholdMaximum(displayGroup, browserTabIndex)); m_thresholdMaximumSpinBox->blockSignals(false); m_opacitySpinBox->blockSignals(true); m_opacitySpinBox->setValue(dpi->getOpacity(displayGroup, browserTabIndex)); m_opacitySpinBox->blockSignals(false); } /** * Update other selection toolbox since they should all be the same. */ void ImageSelectionViewController::updateOtherImageViewControllers() { for (std::set::iterator iter = s_allImageSelectionViewControllers.begin(); iter != s_allImageSelectionViewControllers.end(); iter++) { ImageSelectionViewController* ivc = *iter; if (ivc != this) { ivc->updateImageViewController(); } } } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* ImageSelectionViewController::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ImageSelectionViewController", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); // Uncomment if sub-classes must save to scene //saveSubClassDataToScene(sceneAttributes, // sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ImageSelectionViewController::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, // sceneClass); } connectome-workbench-1.4.2/src/GuiQt/ImageSelectionViewController.h000066400000000000000000000106311360521144700254140ustar00rootroot00000000000000#ifndef __IMAGE_SELECTION_VIEW_CONTROLLER_H__ #define __IMAGE_SELECTION_VIEW_CONTROLLER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "DisplayGroupEnum.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" class QButtonGroup; class QCheckBox; class QDoubleSpinBox; class QGridLayout; class QRadioButton; class QSignalMapper; namespace caret { class DisplayGroupEnumComboBox; class EnumComboBoxTemplate; class SceneClassAssistant; class WuQTabWidget; class ImageSelectionViewController : public QWidget, public EventListenerInterface, public SceneableInterface { Q_OBJECT public: ImageSelectionViewController(const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent = 0); virtual ~ImageSelectionViewController(); // ADD_NEW_METHODS_HERE virtual void receiveEvent(Event* event); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private slots: void processAttributesChanges(); void imageDisplayGroupSelected(const DisplayGroupEnum::Enum); void imageRadioButtonClicked(int); // If there will be sub-classes of this class that need to save // and restore data from scenes, these pure virtual methods can // be uncommented to force their implemetation by sub-classes. // protected: // virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, // SceneClass* sceneClass) = 0; // // virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, // const SceneClass* sceneClass) = 0; private: ImageSelectionViewController(const ImageSelectionViewController&); ImageSelectionViewController& operator=(const ImageSelectionViewController&); void updateOtherImageViewControllers(); void updateImageViewController(); QWidget* createSelectionWidget(); QWidget* createAttributesWidget(); const int32_t m_browserWindowIndex; const QString m_objectNamePrefix; WuQTabWidget* m_tabWidget; SceneClassAssistant* m_sceneAssistant; DisplayGroupEnumComboBox* m_imagesDisplayGroupComboBox; QCheckBox* m_imageDisplayCheckBox; QCheckBox* m_controlPointsDisplayCheckBox; std::vector m_imageRadioButtons; QButtonGroup* m_imageRadioButtonGroup; QGridLayout* m_imageRadioButtonLayout; EnumComboBoxTemplate* m_depthComboBox; QDoubleSpinBox* m_thresholdMinimumSpinBox; QDoubleSpinBox* m_thresholdMaximumSpinBox; QDoubleSpinBox* m_opacitySpinBox; static std::set s_allImageSelectionViewControllers; // ADD_NEW_MEMBERS_HERE }; #ifdef __IMAGE_SELECTION_VIEW_CONTROLLER_DECLARE__ std::set ImageSelectionViewController::s_allImageSelectionViewControllers; #endif // __IMAGE_SELECTION_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__IMAGE_SELECTION_VIEW_CONTROLLER_H__ connectome-workbench-1.4.2/src/GuiQt/InformationDisplayDialog.cxx000066400000000000000000000255611360521144700251430ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #define __INFORMATION_DISPLAY_DIALOG_DECLARE__ #include "InformationDisplayDialog.h" #undef __INFORMATION_DISPLAY_DIALOG_DECLARE__ #include "Brain.h" #include "BrainBrowserWindow.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventUserInterfaceUpdate.h" #include "EventUpdateInformationWindows.h" #include "EventManager.h" #include "GuiManager.h" #include "HyperLinkTextBrowser.h" #include "IdentificationManager.h" #include "InformationDisplayPropertiesDialog.h" #include "SceneClass.h" #include "SceneWindowGeometry.h" #include "SelectionItemSurfaceNode.h" #include "SelectionManager.h" #include "StructureEnumComboBox.h" #include "Surface.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::InformationDisplayDialog * \brief Dialog for display of information. * \ingroup GuiQt * */ /** * Constructor. */ InformationDisplayDialog::InformationDisplayDialog(BrainBrowserWindow* parent) : WuQDialogNonModal("Information", parent) { this->setDeleteWhenClosed(false); /* * No apply button */ this->setApplyButtonText(""); m_propertiesDialog = NULL; m_informationTextBrowser = new HyperLinkTextBrowser(); m_informationTextBrowser->setLineWrapMode(QTextEdit::NoWrap); m_informationTextBrowser->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum)); QAction* clearAction = WuQtUtilities::createAction("Clear", "Clear contents of information display", this, this, SLOT(clearInformationText())); m_contralateralIdentificationAction = WuQtUtilities::createAction("Contra ID", "Enable contralateral identification", this, this, SLOT(contralateralIdentificationToggled(bool))); m_contralateralIdentificationAction->setCheckable(true); QAction* copyAction = WuQtUtilities::createAction("Copy", "Copy selection from information display", this, m_informationTextBrowser, SLOT(copy())); QAction* removeIdSymbolAction = WuQtUtilities::createAction("RID", "Remove All ID symbols", this, this, SLOT(removeIdSymbols())); QAction* settingsAction = WuQtUtilities::createAction("Properties", "Displays dialog for changing ID symbol colors and size", this, this, SLOT(showPropertiesDialog())); QObject::connect(m_informationTextBrowser, SIGNAL(copyAvailable(bool)), copyAction, SLOT(setEnabled(bool))); copyAction->setEnabled(false); QToolBar* idToolBarLeft = new QToolBar(); idToolBarLeft->setOrientation(Qt::Vertical); idToolBarLeft->setFloatable(false); idToolBarLeft->setMovable(false); idToolBarLeft->addAction(clearAction); idToolBarLeft->addSeparator(); idToolBarLeft->addAction(copyAction); idToolBarLeft->addSeparator(); QToolBar* idToolBarRight = new QToolBar(); idToolBarRight->setOrientation(Qt::Vertical); idToolBarRight->setFloatable(false); idToolBarRight->setMovable(false); idToolBarRight->addAction(removeIdSymbolAction); idToolBarRight->addSeparator(); idToolBarRight->addAction(m_contralateralIdentificationAction); idToolBarRight->addSeparator(); idToolBarRight->addAction(settingsAction); idToolBarRight->addSeparator(); QWidget* widget = new QWidget(); QHBoxLayout* layout = new QHBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 0); layout->addWidget(idToolBarLeft); layout->addWidget(m_informationTextBrowser); layout->addWidget(idToolBarRight); layout->setStretchFactor(idToolBarLeft, 0); layout->setStretchFactor(m_informationTextBrowser, 100); layout->setStretchFactor(idToolBarRight, 0); /* * Use processed event listener since the text event * is first processed by GuiManager which will create * this dialog, if needed, and then display it. */ EventManager::get()->addProcessedEventListener(this, EventTypeEnum::EVENT_UPDATE_INFORMATION_WINDOWS); this->setCentralWidget(widget, WuQDialog::SCROLL_AREA_NEVER); /* * There may already be identification text, so try to display it. */ updateDialog(); } /** * Destructor. */ InformationDisplayDialog::~InformationDisplayDialog() { EventManager::get()->removeAllEventsFromListener(this); } /** * Update the dialog's content. */ void InformationDisplayDialog::updateDialog() { Brain* brain = GuiManager::get()->getBrain(); IdentificationManager* idManager = brain->getIdentificationManager(); const AString text = idManager->getIdentificationText(); m_informationTextBrowser->setContentToHtml(text); if (m_propertiesDialog != NULL) { m_propertiesDialog->updateDialog(); } m_contralateralIdentificationAction->blockSignals(true); m_contralateralIdentificationAction->setChecked(idManager->isContralateralIdentificationEnabled()); m_contralateralIdentificationAction->blockSignals(false); } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* InformationDisplayDialog::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "InformationDisplayDialog", 1); /* * Position and size */ SceneWindowGeometry swg(this); sceneClass->addClass(swg.saveToScene(sceneAttributes, "geometry")); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void InformationDisplayDialog::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } /* * Position and size */ SceneWindowGeometry swg(this); swg.restoreFromScene(sceneAttributes, sceneClass->getClass("geometry")); } /** * Called when contralateral toolbutton is toggled. */ void InformationDisplayDialog::contralateralIdentificationToggled(bool) { Brain* brain = GuiManager::get()->getBrain(); IdentificationManager* idManager = brain->getIdentificationManager(); idManager->setContralateralIdentificationEnabled(m_contralateralIdentificationAction->isChecked()); } /** * Clear the information text. */ void InformationDisplayDialog::clearInformationText() { Brain* brain = GuiManager::get()->getBrain(); IdentificationManager* idManager = brain->getIdentificationManager(); idManager->removeIdentificationText(); updateDialog(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Remove ID symbols from all surfaces. */ void InformationDisplayDialog::removeIdSymbols() { Brain* brain = GuiManager::get()->getBrain(); IdentificationManager* idManager = brain->getIdentificationManager(); idManager->removeAllIdentifiedSymbols(); updateDialog(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Receive events from the event manager. * * @param event * Event sent by event manager. */ void InformationDisplayDialog::receiveEvent(Event* event) { bool doUpdate = false; if (event->getEventType() == EventTypeEnum::EVENT_UPDATE_INFORMATION_WINDOWS) { EventUpdateInformationWindows* textEvent = dynamic_cast(event); CaretAssert(textEvent); textEvent->setEventProcessed(); doUpdate = true; } else if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiUpdateEvent = dynamic_cast(event); CaretAssert(uiUpdateEvent); uiUpdateEvent->setEventProcessed(); doUpdate = true; } if (doUpdate) { updateDialog(); } } /** * Show the symbol properties dialog */ void InformationDisplayDialog::showPropertiesDialog() { if (m_propertiesDialog == NULL) { m_propertiesDialog = new InformationDisplayPropertiesDialog(this); } m_propertiesDialog->showDialog(); } connectome-workbench-1.4.2/src/GuiQt/InformationDisplayDialog.h000066400000000000000000000052661360521144700245700ustar00rootroot00000000000000#ifndef __INFORMATION_DISPLAY_DIALOG__H_ #define __INFORMATION_DISPLAY_DIALOG__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventListenerInterface.h" #include "SceneableInterface.h" #include "WuQDialogNonModal.h" namespace caret { class BrainBrowserWindow; class HyperLinkTextBrowser; class InformationDisplayPropertiesDialog; class InformationDisplayDialog : public WuQDialogNonModal, public EventListenerInterface, public SceneableInterface { Q_OBJECT public: InformationDisplayDialog(BrainBrowserWindow* parent); virtual ~InformationDisplayDialog(); void receiveEvent(Event* event); virtual void updateDialog(); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private slots: void clearInformationText(); void removeIdSymbols(); void contralateralIdentificationToggled(bool); //void volumeSliceIdentificationToggled(bool); void showPropertiesDialog(); private: InformationDisplayDialog(const InformationDisplayDialog&); InformationDisplayDialog& operator=(const InformationDisplayDialog&); HyperLinkTextBrowser* m_informationTextBrowser; QAction* m_contralateralIdentificationAction; QString m_informationText; InformationDisplayPropertiesDialog* m_propertiesDialog; }; #ifdef __INFORMATION_DISPLAY_DIALOG_DECLARE__ // #endif // __INFORMATION_DISPLAY_DIALOG_DECLARE__ } // namespace #endif //__INFORMATION_DISPLAY_DIALOG__H_ connectome-workbench-1.4.2/src/GuiQt/InformationDisplayPropertiesDialog.cxx000066400000000000000000000202311360521144700272050ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __INFORMATION_DISPLAY_OPTIONS_DIALOG_DECLARE__ #include "InformationDisplayPropertiesDialog.h" #undef __INFORMATION_DISPLAY_OPTIONS_DIALOG_DECLARE__ #include #include #include #include "Brain.h" #include "CaretAssert.h" #include "CaretColorEnumComboBox.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "GuiManager.h" #include "IdentificationManager.h" #include "WuQFactory.h" #include "WuQTrueFalseComboBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::InformationDisplayPropertiesDialog * \brief Options for information dialog display. * \ingroup GuiQt */ /** * Constructor. */ InformationDisplayPropertiesDialog::InformationDisplayPropertiesDialog(QWidget* parent, Qt::WindowFlags f) : WuQDialogNonModal("Information Properties", parent, f) { const int WIDGET_WIDTH = 100; QLabel* surfaceLabel = new QLabel("Show Surface ID Symbols"); m_surfaceIdentificationSymbolComboBox = new WuQTrueFalseComboBox("On", "Off", this); QObject::connect(m_surfaceIdentificationSymbolComboBox, SIGNAL(statusChanged(bool)), this, SLOT(informationPropertyChanged())); QLabel* volumeLabel = new QLabel("Show Volume ID Symbols"); m_volumeIdentificationSymbolComboBox = new WuQTrueFalseComboBox("On", "Off", this); QObject::connect(m_volumeIdentificationSymbolComboBox, SIGNAL(statusChanged(bool)), this, SLOT(informationPropertyChanged())); QLabel* idColorLabel = new QLabel("ID Symbol Color: "); m_idColorComboBox = new CaretColorEnumComboBox(this); m_idColorComboBox->getWidget()->setFixedWidth(WIDGET_WIDTH); QObject::connect(m_idColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), this, SLOT(informationPropertyChanged())); QLabel* idContralateralLabel = new QLabel("ID Contralateral Symbol Color: "); m_idContralateralColorComboBox = new CaretColorEnumComboBox(this); m_idContralateralColorComboBox->getWidget()->setFixedWidth(WIDGET_WIDTH); QObject::connect(m_idContralateralColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), this, SLOT(informationPropertyChanged())); QLabel* symbolSizeLabel = new QLabel("Symbol Diameter: "); m_symbolSizeSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.1, 10000.0, 0.1, 1, this, SLOT(informationPropertyChanged())); m_symbolSizeSpinBox->setFixedWidth(WIDGET_WIDTH); m_symbolSizeSpinBox->setSuffix("mm"); QObject::connect(m_symbolSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(informationPropertyChanged())); QLabel* mostRecentSymbolSizeLabel = new QLabel("Most Recent ID Symbol Diameter: "); m_mostRecentSymbolSizeSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.1, 10000.0, 0.1, 1, this, SLOT(informationPropertyChanged())); m_mostRecentSymbolSizeSpinBox->setFixedWidth(WIDGET_WIDTH); m_mostRecentSymbolSizeSpinBox->setSuffix("mm"); QObject::connect(m_mostRecentSymbolSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(informationPropertyChanged())); const int COLUMN_LABEL = 0; const int COLUMN_WIDGET = 1; QWidget* widget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(widget); int row = 0; gridLayout->addWidget(surfaceLabel, row, COLUMN_LABEL); gridLayout->addWidget(m_surfaceIdentificationSymbolComboBox->getWidget(), row, COLUMN_WIDGET); row++; gridLayout->addWidget(volumeLabel, row, COLUMN_LABEL); gridLayout->addWidget(m_volumeIdentificationSymbolComboBox->getWidget(), row, COLUMN_WIDGET); row++; gridLayout->addWidget(idColorLabel, row, COLUMN_LABEL); gridLayout->addWidget(m_idColorComboBox->getWidget(), row, COLUMN_WIDGET); row++; gridLayout->addWidget(idContralateralLabel, row, COLUMN_LABEL); gridLayout->addWidget(m_idContralateralColorComboBox->getWidget(), row, COLUMN_WIDGET); row++; gridLayout->addWidget(symbolSizeLabel, row, COLUMN_LABEL); gridLayout->addWidget(m_symbolSizeSpinBox, row, COLUMN_WIDGET); row++; gridLayout->addWidget(mostRecentSymbolSizeLabel, row, COLUMN_LABEL); gridLayout->addWidget(m_mostRecentSymbolSizeSpinBox, row, COLUMN_WIDGET); row++; gridLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), row, COLUMN_LABEL, 1, 2); row++; setCentralWidget(widget, WuQDialog::SCROLL_AREA_NEVER); setApplyButtonText(""); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); updateDialog(); setSaveWindowPositionForNextTime(true); } /** * Destructor. */ InformationDisplayPropertiesDialog::~InformationDisplayPropertiesDialog() { } /** * update its content */ void InformationDisplayPropertiesDialog::updateDialog() { Brain* brain = GuiManager::get()->getBrain(); IdentificationManager* info = brain->getIdentificationManager(); m_surfaceIdentificationSymbolComboBox->setStatus(info->isShowSurfaceIdentificationSymbols()); m_volumeIdentificationSymbolComboBox->setStatus(info->isShowVolumeIdentificationSymbols()); m_idColorComboBox->setSelectedColor(info->getIdentificationSymbolColor()); m_idContralateralColorComboBox->setSelectedColor(info->getIdentificationContralateralSymbolColor()); m_symbolSizeSpinBox->blockSignals(true); m_symbolSizeSpinBox->setValue(info->getIdentificationSymbolSize()); m_symbolSizeSpinBox->blockSignals(false); m_mostRecentSymbolSizeSpinBox->blockSignals(true); m_mostRecentSymbolSizeSpinBox->setValue(info->getMostRecentIdentificationSymbolSize()); m_mostRecentSymbolSizeSpinBox->blockSignals(false); } /** * Gets called when a property changes. */ void InformationDisplayPropertiesDialog::informationPropertyChanged() { Brain* brain = GuiManager::get()->getBrain(); IdentificationManager* info = brain->getIdentificationManager(); info->setShowSurfaceIdentificationSymbols(m_surfaceIdentificationSymbolComboBox->isTrue()); info->setShowVolumeIdentificationSymbols(m_volumeIdentificationSymbolComboBox->isTrue()); info->setIdentificationSymbolColor(m_idColorComboBox->getSelectedColor()); info->setIdentificationContralateralSymbolColor(m_idContralateralColorComboBox->getSelectedColor()); info->setIdentificationSymbolSize(m_symbolSizeSpinBox->value()); info->setMostRecentIdentificationSymbolSize(m_mostRecentSymbolSizeSpinBox->value()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } connectome-workbench-1.4.2/src/GuiQt/InformationDisplayPropertiesDialog.h000066400000000000000000000045661360521144700266470ustar00rootroot00000000000000#ifndef __INFORMATION_DISPLAY_OPTIONS_DIALOG_H__ #define __INFORMATION_DISPLAY_OPTIONS_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WuQDialogNonModal.h" #include namespace caret { class CaretColorEnumComboBox; class WuQTrueFalseComboBox; class InformationDisplayPropertiesDialog : public WuQDialogNonModal { Q_OBJECT public: InformationDisplayPropertiesDialog(QWidget* parent, Qt::WindowFlags f = 0); virtual ~InformationDisplayPropertiesDialog(); void updateDialog(); // ADD_NEW_METHODS_HERE private slots: void informationPropertyChanged(); private: InformationDisplayPropertiesDialog(const InformationDisplayPropertiesDialog&); InformationDisplayPropertiesDialog& operator=(const InformationDisplayPropertiesDialog&); CaretColorEnumComboBox* m_idColorComboBox; CaretColorEnumComboBox* m_idContralateralColorComboBox; QDoubleSpinBox* m_symbolSizeSpinBox; QDoubleSpinBox* m_mostRecentSymbolSizeSpinBox; WuQTrueFalseComboBox* m_surfaceIdentificationSymbolComboBox; WuQTrueFalseComboBox* m_volumeIdentificationSymbolComboBox; // ADD_NEW_MEMBERS_HERE }; #ifdef __INFORMATION_DISPLAY_OPTIONS_DIALOG_DECLARE__ // #endif // __INFORMATION_DISPLAY_OPTIONS_DIALOG_DECLARE__ } // namespace #endif //__INFORMATION_DISPLAY_OPTIONS_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/KeyEvent.cxx000066400000000000000000000061711360521144700217360ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "KeyEvent.h" using namespace caret; /** * \class caret::KeyEvent * \brief Event issued when key is moved or buttons are pressed. * \ingroup GuiQt */ /** * Constructor. * @param openGLWidget * OpenGL Widget in which key activity took place. * @param browserWindowIndex * Index of the browser winddow in which key activity took place. * @param keyCode * The key that was pressed. See Qt::Key for list of codes. * @param firstKeyPressFlag * True if this is the first key press when key is held down for a period of time * @param shiftKeyDownFlag * True if the shift key is down */ KeyEvent::KeyEvent(BrainOpenGLWidget* openGLWidget, const int32_t browserWindowIndex, const int32_t keyCode, const bool firstKeyPressFlag, const bool shiftKeyDownFlag) : CaretObject(), m_openGLWidget(openGLWidget), m_browserWindowIndex(browserWindowIndex), m_keyCode(keyCode), m_firstKeyPressFlag(firstKeyPressFlag), m_shiftKeyDownFlag(shiftKeyDownFlag) { } /** * Destructor */ KeyEvent::~KeyEvent() { } /** * Initialize all members. */ void KeyEvent::initializeMembersKeyEvent() { } /** * @return The OpenGL Widget in which the key event occurred. */ BrainOpenGLWidget* KeyEvent::getOpenGLWidget() const { return m_openGLWidget; } /** * Get a string showing the contents of this key event. * @return String describing the key status. */ AString KeyEvent::toString() const { const AString msg = ", keyCord=" + AString::number(m_keyCode); return msg; } /** * @return Index of the browser window in which the * event took place. */ int32_t KeyEvent::getBrowserWindowIndex() const { return m_browserWindowIndex; } /** * Get the key code. See Qt::Key for list of codes. * @return The key code. * */ int32_t KeyEvent::getKeyCode() const { return m_keyCode; } /** * @return Is this the first (of possibly many) key press events? * If a key is held down for a period of time, this method * will return true for only the first key press events. * */ bool KeyEvent::isFirstKeyPressFlag() const { return m_firstKeyPressFlag; } /** * @return Is this the SHIFT key down? * */ bool KeyEvent::isShiftKeyDownFlag() const { return m_shiftKeyDownFlag; } connectome-workbench-1.4.2/src/GuiQt/KeyEvent.h000066400000000000000000000042511360521144700213600ustar00rootroot00000000000000#ifndef __KEY_EVENT_H__ #define __KEY_EVENT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include class QKeyEvent; namespace caret { class BrainOpenGLWidget; /** * Contains information about a key event in the OpenGL region. */ class KeyEvent : public CaretObject { public: KeyEvent(BrainOpenGLWidget* openGLWidget, const int32_t browserWindowIndex, const int32_t keyCode, const bool firstKeyPressFlag, const bool shiftKeyDownFlag); virtual ~KeyEvent(); private: void initializeMembersKeyEvent(); KeyEvent(const KeyEvent& o); KeyEvent& operator=(const KeyEvent& o); public: AString toString() const; BrainOpenGLWidget* getOpenGLWidget() const; int32_t getBrowserWindowIndex() const; int32_t getKeyCode() const; bool isFirstKeyPressFlag() const; bool isShiftKeyDownFlag() const; private: BrainOpenGLWidget* m_openGLWidget; const int32_t m_browserWindowIndex; const int32_t m_keyCode; const bool m_firstKeyPressFlag; const bool m_shiftKeyDownFlag; }; } // namespace #endif // __KEY_EVENT_H__ connectome-workbench-1.4.2/src/GuiQt/LabelDrawingTypeComboBox.cxx000066400000000000000000000025001360521144700250220ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __LABEL_DRAWING_TYPE_COMBO_BOX_DECLARE__ #include "LabelDrawingTypeComboBox.h" #undef __LABEL_DRAWING_TYPE_COMBO_BOX_DECLARE__ using namespace caret; /** * \class caret::LabelDrawingTypeComboBox * \brief * * */ /** * Constructor. */ LabelDrawingTypeComboBox::LabelDrawingTypeComboBox() : EnumComboBoxTemplate() { } /** * Destructor. */ LabelDrawingTypeComboBox::~LabelDrawingTypeComboBox() { } connectome-workbench-1.4.2/src/GuiQt/LabelDrawingTypeComboBox.h000066400000000000000000000031631360521144700244550ustar00rootroot00000000000000#ifndef __LABEL_DRAWING_TYPE_COMBO_BOX__H_ #define __LABEL_DRAWING_TYPE_COMBO_BOX__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EnumComboBoxTemplate.h" namespace caret { class LabelDrawingTypeComboBox : public EnumComboBoxTemplate { public: LabelDrawingTypeComboBox(); virtual ~LabelDrawingTypeComboBox(); private: LabelDrawingTypeComboBox(const LabelDrawingTypeComboBox&); LabelDrawingTypeComboBox& operator=(const LabelDrawingTypeComboBox&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE }; #ifdef __LABEL_DRAWING_TYPE_COMBO_BOX_DECLARE__ // #endif // __LABEL_DRAWING_TYPE_COMBO_BOX_DECLARE__ } // namespace #endif //__LABEL_DRAWING_TYPE_COMBO_BOX__H_ connectome-workbench-1.4.2/src/GuiQt/LabelSelectionViewController.cxx000066400000000000000000000266021360521144700257710ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include //#include #include #define __LABEL_SELECTION_VIEW_CONTROLLER_DECLARE__ #include "LabelSelectionViewController.h" #undef __LABEL_SELECTION_VIEW_CONTROLLER_DECLARE__ #include "Brain.h" #include "BrainOpenGL.h" #include "BrainStructure.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "GroupAndNameHierarchyViewController.h" #include "DisplayGroupEnumComboBox.h" #include "DisplayPropertiesLabels.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "SceneClass.h" #include "VolumeFile.h" #include "WuQDataEntryDialog.h" #include "WuQMacroManager.h" #include "WuQTabWidget.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::LabelSelectionViewController * \brief Widget for controlling display of labels * \ingroup GuiQt * * Widget for controlling the display of labels including * different display groups. */ /** * Constructor. * * @param browserWindowIndex * Index of browser window * @param parentObjectName * Name of parent object * @param parent * The parent object */ LabelSelectionViewController::LabelSelectionViewController(const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent) : QWidget(parent), m_objectNamePrefix(parentObjectName + ":Label") { m_browserWindowIndex = browserWindowIndex; QLabel* groupLabel = new QLabel("Group"); m_labelsDisplayGroupComboBox = new DisplayGroupEnumComboBox(this, (m_objectNamePrefix + ":DisplayGroup"), "labels"); QObject::connect(m_labelsDisplayGroupComboBox, SIGNAL(displayGroupSelected(const DisplayGroupEnum::Enum)), this, SLOT(labelDisplayGroupSelected(const DisplayGroupEnum::Enum))); QHBoxLayout* groupLayout = new QHBoxLayout(); groupLayout->addWidget(groupLabel); groupLayout->addWidget(m_labelsDisplayGroupComboBox->getWidget()); groupLayout->addStretch(); QWidget* selectionWidget = this->createSelectionWidget(); QVBoxLayout* layout = new QVBoxLayout(this); layout->addLayout(groupLayout); layout->addWidget(selectionWidget, 0, Qt::AlignLeft); layout->addStretch(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); LabelSelectionViewController::allLabelSelectionViewControllers.insert(this); } /** * Destructor. */ LabelSelectionViewController::~LabelSelectionViewController() { EventManager::get()->removeAllEventsFromListener(this); LabelSelectionViewController::allLabelSelectionViewControllers.erase(this); } QWidget* LabelSelectionViewController::createSelectionWidget() { m_labelClassNameHierarchyViewController = new GroupAndNameHierarchyViewController(m_browserWindowIndex, (m_objectNamePrefix + ":Selection"), "labels", this); return m_labelClassNameHierarchyViewController; } /** * Called when the label display group combo box is changed. */ void LabelSelectionViewController::labelDisplayGroupSelected(const DisplayGroupEnum::Enum displayGroup) { /* * Update selected display group in model. */ BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, false); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); Brain* brain = GuiManager::get()->getBrain(); DisplayPropertiesLabels* dsb = brain->getDisplayPropertiesLabels(); dsb->setDisplayGroupForTab(browserTabIndex, displayGroup); /* * Since display group has changed, need to update controls */ updateLabelViewController(); /* * Apply the changes. */ processLabelSelectionChanges(); } /** * Update the label selection widget. */ void LabelSelectionViewController::updateLabelViewController() { setWindowTitle("Labels"); BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } const int32_t browserTabIndex = browserTabContent->getTabNumber(); Brain* brain = GuiManager::get()->getBrain(); DisplayPropertiesLabels* dpb = brain->getDisplayPropertiesLabels(); const DisplayGroupEnum::Enum displayGroup = dpb->getDisplayGroupForTab(browserTabIndex); m_labelsDisplayGroupComboBox->setSelectedDisplayGroup(dpb->getDisplayGroupForTab(browserTabIndex)); /* * Get all of label files. */ std::vector allLabelFiles; const int numBrainStructures = brain->getNumberOfBrainStructures(); for (int32_t ibs = 0; ibs < numBrainStructures; ibs++) { BrainStructure* brainStructure = brain->getBrainStructure(ibs); const int32_t numLabelFiles = brainStructure->getNumberOfLabelFiles(); for (int32_t ilf = 0; ilf < numLabelFiles; ilf++) { allLabelFiles.push_back(brainStructure->getLabelFile(ilf)); } } /* * Get all CIFTI label files */ std::vector allCiftiLabelFiles; const int32_t numCiftiLabelFiles = brain->getNumberOfConnectivityDenseLabelFiles(); for (int32_t iclf = 0; iclf < numCiftiLabelFiles; iclf++) { allCiftiLabelFiles.push_back(brain->getConnectivityDenseLabelFile(iclf)); } /* * Get all Volume Files that are mapped with label tables */ std::vector allVolumeLabelFiles; const int32_t numVolumeFiles = brain->getNumberOfVolumeFiles(); for (int32_t iVol = 0; iVol < numVolumeFiles; iVol++) { VolumeFile* vf = brain->getVolumeFile(iVol); if (vf->isMappedWithLabelTable()) { allVolumeLabelFiles.push_back(vf); } } /* * Update the class/name hierarchy */ m_labelClassNameHierarchyViewController->updateContents(allLabelFiles, allCiftiLabelFiles, allVolumeLabelFiles, displayGroup); } /** * Update other selection toolbox since they should all be the same. */ void LabelSelectionViewController::updateOtherLabelViewControllers() { for (std::set::iterator iter = LabelSelectionViewController::allLabelSelectionViewControllers.begin(); iter != LabelSelectionViewController::allLabelSelectionViewControllers.end(); iter++) { LabelSelectionViewController* bsw = *iter; if (bsw != this) { bsw->updateLabelViewController(); } } } /** * Gets called when label selections are changed. */ void LabelSelectionViewController::processLabelSelectionChanges() { BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, false); CaretAssert(browserTabContent); const int32_t browserTabIndex = browserTabContent->getTabNumber(); Brain* brain = GuiManager::get()->getBrain(); DisplayPropertiesLabels* dsb = brain->getDisplayPropertiesLabels(); dsb->setDisplayGroupForTab(browserTabIndex, m_labelsDisplayGroupComboBox->getSelectedDisplayGroup()); processSelectionChanges(); } /** * Issue update events after selections are changed. */ void LabelSelectionViewController::processSelectionChanges() { updateOtherLabelViewControllers(); EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Receive events from the event manager. * * @param event * Event sent by event manager. */ void LabelSelectionViewController::receiveEvent(Event* event) { bool doUpdate = false; if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiEvent = dynamic_cast(event); CaretAssert(uiEvent); if (uiEvent->isUpdateForWindow(m_browserWindowIndex)) { if (uiEvent->isToolBoxUpdate()) { doUpdate = true; uiEvent->setEventProcessed(); } } } if (doUpdate) { updateLabelViewController(); } } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* LabelSelectionViewController::saveToScene(const SceneAttributes* /*sceneAttributes*/, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "LabelSelectionViewController", 1); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void LabelSelectionViewController::restoreFromScene(const SceneAttributes* /*sceneAttributes*/, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } } connectome-workbench-1.4.2/src/GuiQt/LabelSelectionViewController.h000066400000000000000000000063321360521144700254140ustar00rootroot00000000000000#ifndef __LABEL_SELECTION_VIEW_CONTROLLER__H_ #define __LABEL_SELECTION_VIEW_CONTROLLER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "DisplayGroupEnum.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" class QCheckBox; namespace caret { class GroupAndNameHierarchyViewController; class DisplayGroupEnumComboBox; class LabelSelectionViewController : public QWidget, public EventListenerInterface, public SceneableInterface { Q_OBJECT public: LabelSelectionViewController(const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent = 0); virtual ~LabelSelectionViewController(); void receiveEvent(Event* event); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private slots: void processLabelSelectionChanges(); void processSelectionChanges(); void labelDisplayGroupSelected(const DisplayGroupEnum::Enum); private: LabelSelectionViewController(const LabelSelectionViewController&); LabelSelectionViewController& operator=(const LabelSelectionViewController&); void updateLabelViewController(); void updateOtherLabelViewControllers(); QWidget* createSelectionWidget(); const QString m_objectNamePrefix; int32_t m_browserWindowIndex; GroupAndNameHierarchyViewController* m_labelClassNameHierarchyViewController; QCheckBox* m_labelsDisplayCheckBox; QCheckBox* m_labelsContralateralCheckBox; DisplayGroupEnumComboBox* m_labelsDisplayGroupComboBox; static std::set allLabelSelectionViewControllers; }; #ifdef __LABEL_SELECTION_VIEW_CONTROLLER_DECLARE__ std::set LabelSelectionViewController::allLabelSelectionViewControllers; #endif // __LABEL_SELECTION_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__LABEL_SELECTION_VIEW_CONTROLLER__H_ connectome-workbench-1.4.2/src/GuiQt/LockAspectWarningDialog.cxx000066400000000000000000000277461360521144700247150ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __LOCK_ASPECT_WARNING_DIALOG_DECLARE__ #include "LockAspectWarningDialog.h" #undef __LOCK_ASPECT_WARNING_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include #include "BrainBrowserWindow.h" #include "BrowserTabContent.h" #include "BrowserWindowContent.h" #include "CaretAssert.h" #include "EventHelpViewerDisplay.h" #include "EventManager.h" #include "GuiManager.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::LockAspectWarningDialog * \brief Dialog that warns and allows user to lock tab/window aspect. * \ingroup GuiQt */ /** * Run the dialog for when the user turns on the Lock Aspect button in the toolbar * * @param bbw * Parent brain browser window * @param numberOfTabsInWindow * Number of tabs in the window */ bool LockAspectWarningDialog::runDialogToolBarLockAspect(BrainBrowserWindow* bbw, const int32_t numberOfTabsInWindow) { CaretAssert(bbw); /* * Show warning if all of these conditions are met: * * (1) User has NOT set do not show again * (2) Tile tabs is NOT selected * (3) There is more than one tab in the window */ if (s_doNotShowAgainLockAspectModeStatusFlag) { return true; } if (bbw->isTileTabsSelected()) { return true; } if (numberOfTabsInWindow <= 1) { return true; } LockAspectWarningDialog dialog(bbw, Mode::TOOLBAR_LOCK_ASPECT); const bool acceptedFlag = (dialog.exec() == LockAspectWarningDialog::Accepted); s_doNotShowAgainLockAspectModeStatusFlag = dialog.isDoNotShowAgainChecked(); return acceptedFlag; } /** * Run the lock aspect warning dialog when the user presses the * Annotation mode button and return the result. * * @param browserWindowIndex * Index of the browser window. * @return * Result of user interaction with dialog. */ LockAspectWarningDialog::Result LockAspectWarningDialog::runDialogEnterAnnotationsMode(const int32_t browserWindowIndex) { BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(browserWindowIndex); CaretAssert(bbw); const BrowserWindowContent* browserWindowContent = bbw->getBrowerWindowContent(); CaretAssert(browserWindowContent); const bool aspectLockedFlag = (browserWindowContent->isWindowAspectLocked() && browserWindowContent->isAllTabsInWindowAspectRatioLocked()); if (aspectLockedFlag) { return Result::NO_CHANGES; } const BrowserTabContent* selectedTab = bbw->getBrowserTabContent(); if (selectedTab == NULL) { return Result::NO_CHANGES; } if (s_doNotShowAgainEnterAnnotationsModeStatusFlag) { return Result::NO_CHANGES; } LockAspectWarningDialog dialog(bbw, Mode::ENTER_ANNOTATIONS_MODE); if (dialog.exec() == LockAspectWarningDialog::Accepted) { s_doNotShowAgainEnterAnnotationsModeStatusFlag = dialog.isDoNotShowAgainChecked(); return dialog.getOkResult(); } return Result::CANCEL; } /** * @return Locking aspect instruction containing importance of window sizing * and locking tabs. * * @parm buttonText * Text of button that user has clicked * @param showBestPracticesLink If true, include a link to the best practices guide. */ QString LockAspectWarningDialog::getLockingInstructionsText(const QString& buttonText, const bool showBestPracticesLink) { QString text("" "Prior to locking the aspect ratio, the user should: " "

      " "
    • Adjust the size of the window;" "
    • Optionally enable Tile Tabs for a multi-tab view; " "If annotating a Tile Tabs view, Tile Tabs " "(View Menu -> Enter Tile Tabs) should ALWAYS be enabled prior to " "locking the aspect ratio. Failure to do so may cause excess, " "undesirable space around and between the drawing of tab rows." "
    " "If this has not been done, click the Cancel button, make those " "adjustments, and then click the " + buttonText + " button."); if (showBestPracticesLink) { text.append("

    " "View the Best Practices Guide (this dialog " "will close). This guide explains the importance of aspect " "locking and documents procedures for successful creation of annotations " "and scenes."); } text.append(""); return text; } /** * Constructor. * * @param mode * The mode for the dialog * @param brainBrowserWindow * Parent window for help dialog that is linked from this dialog * @param parent * The parent widget. */ LockAspectWarningDialog::LockAspectWarningDialog(BrainBrowserWindow* brainBrowserWindow, const Mode mode) : WuQDialogModal("Enter Annotations Mode", brainBrowserWindow), m_brainBrowserWindow(brainBrowserWindow), m_mode(mode) { QString buttonName; switch (m_mode) { case Mode::ENTER_ANNOTATIONS_MODE: setWindowTitle("Enter Annotations Mode"); buttonName = "Toolbar's Annotate Mode"; break; case Mode::TOOLBAR_LOCK_ASPECT: setWindowTitle("Lock Aspect Ratio"); buttonName = "Lock Aspect"; break; } const QString supplementalInstructions(getLockingInstructionsText(buttonName, true)); QLabel* supplementalInstructionLabel = new QLabel(supplementalInstructions); supplementalInstructionLabel->setWordWrap(true); QObject::connect(supplementalInstructionLabel, &QLabel::linkActivated, this, &LockAspectWarningDialog::detailsLabelLinkActivated); m_doNotShowAgainCheckBox = new QCheckBox("Do not show this dialog again. User will not be warned about " "aspect locking and unlocking."); QWidget* dialogWidget = new QWidget; QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); switch (m_mode) { case Mode::ENTER_ANNOTATIONS_MODE: { const QString mainInstructions("Do you want to lock the aspect ratio while entering annotations mode?"); const QString lockAspectInstructions("Locking the aspect ratio, and never unlocking the aspect " "ratio, ensures annotations stay in the correct location."); const QString leaveUnlockedInstructions("Advanced users may choose to lock and unlock the aspect ratio"); QLabel* mainInstructionsLabel = new QLabel(mainInstructions); QFont font = mainInstructionsLabel->font(); font.setPointSize(font.pointSize() * 1.4); font.setBold(true); mainInstructionsLabel->setFont(font); QLabel* lockAspectLabel = new QLabel(lockAspectInstructions); lockAspectLabel->setWordWrap(true); QLabel* lockAspectRadioButtonLabel = new QLabel("Lock Aspect Ratio (Recommended)"); m_lockAspectRadioButton = new QRadioButton(); QLabel* leaveUnlockedAspectRadioButtonLabel = new QLabel("Leave Aspect Ratio Unlocked"); m_leaveUnlockedAspectRadioButton = new QRadioButton(); QLabel* leaveUnlockedLabel = new QLabel(leaveUnlockedInstructions); QButtonGroup* buttGroup = new QButtonGroup(this); buttGroup->addButton(m_lockAspectRadioButton); buttGroup->addButton(m_leaveUnlockedAspectRadioButton); m_lockAspectRadioButton->setChecked(true); /* * No text is added to readio buttons since * radio buttons and labels seem to get a different * height in a grid layout. */ const int COL_RADIO_EMPTY = 0; const int COL_RADIO_BUTTON = 1; const int COL_RADIO_LABEL = 2; const int COL_RADIO_INFO = 3; const int COL_RADIO_STRETCH = 4; QGridLayout* buttonGridLayout = new QGridLayout(); buttonGridLayout->setVerticalSpacing(4); buttonGridLayout->setColumnMinimumWidth(COL_RADIO_EMPTY, 20); buttonGridLayout->setColumnMinimumWidth(COL_RADIO_LABEL, 20); buttonGridLayout->setColumnStretch(COL_RADIO_EMPTY, 0); buttonGridLayout->setColumnStretch(COL_RADIO_BUTTON, 0); buttonGridLayout->setColumnStretch(COL_RADIO_STRETCH, 100); int row = 0; buttonGridLayout->addWidget(m_lockAspectRadioButton, row, COL_RADIO_BUTTON); buttonGridLayout->addWidget(lockAspectRadioButtonLabel, row, COL_RADIO_LABEL, 1, 2); row++; buttonGridLayout->addWidget(lockAspectLabel, row, COL_RADIO_INFO); row++; buttonGridLayout->addWidget(m_leaveUnlockedAspectRadioButton, row, COL_RADIO_BUTTON); buttonGridLayout->addWidget(leaveUnlockedAspectRadioButtonLabel, row, COL_RADIO_LABEL, 1, 2); row++; buttonGridLayout->addWidget(leaveUnlockedLabel, row, COL_RADIO_INFO); dialogLayout->addWidget(mainInstructionsLabel); dialogLayout->addLayout(buttonGridLayout); dialogLayout->addSpacing(10); } break; case Mode::TOOLBAR_LOCK_ASPECT: break; } dialogLayout->addWidget(supplementalInstructionLabel); dialogLayout->addSpacing(10); dialogLayout->addWidget(m_doNotShowAgainCheckBox); setCentralWidget(dialogWidget, WuQDialogModal::SCROLL_AREA_NEVER); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } /** * Destructor. */ LockAspectWarningDialog::~LockAspectWarningDialog() { } /** * @return The result if the user clicked the OK button. */ LockAspectWarningDialog::Result LockAspectWarningDialog::getOkResult() const { if (m_lockAspectRadioButton->isChecked()) { return Result::LOCK_ASPECT; } else if (m_leaveUnlockedAspectRadioButton->isChecked()) { return Result::NO_CHANGES; } else { CaretAssert(0); } return m_result; } /** * Called when link in details label is clicked * * @param text of the link. */ void LockAspectWarningDialog::detailsLabelLinkActivated(const QString& /*link*/) { EventHelpViewerDisplay helpViewerEvent(m_brainBrowserWindow, "Annotation_and_Scenes_Best_Practices"); EventManager::get()->sendEvent(helpViewerEvent.getPointer()); reject(); } /** * @return True if the "do not show again" checkbox is checked. */ bool LockAspectWarningDialog::isDoNotShowAgainChecked() const { return m_doNotShowAgainCheckBox->isChecked(); } connectome-workbench-1.4.2/src/GuiQt/LockAspectWarningDialog.h000066400000000000000000000064401360521144700243260ustar00rootroot00000000000000#ifndef __LOCK_ASPECT_WARNING_DIALOG_H__ #define __LOCK_ASPECT_WARNING_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "WuQDialogModal.h" class QCheckBox; class QRadioButton; namespace caret { class BrainBrowserWindow; class LockAspectWarningDialog : public WuQDialogModal { Q_OBJECT public: enum class Result { LOCK_ASPECT, NO_CHANGES, CANCEL }; enum class Mode { ENTER_ANNOTATIONS_MODE, TOOLBAR_LOCK_ASPECT }; static bool runDialogToolBarLockAspect(BrainBrowserWindow* bbw, const int32_t numberOfTabsInWindow); static Result runDialogEnterAnnotationsMode(const int32_t browserWindowIndex); LockAspectWarningDialog(BrainBrowserWindow* brainBrowserWindow, const Mode mode); virtual ~LockAspectWarningDialog(); Result getOkResult() const; bool isDoNotShowAgainChecked() const; // ADD_NEW_METHODS_HERE enum class LockingMode { ENTER_ANNOTATIONS_MODE, LOCK_ASPECT }; static QString getLockingInstructionsText(const QString& buttonText, const bool showBestPracticesLink); private slots: void detailsLabelLinkActivated(const QString& link); private: LockAspectWarningDialog(const LockAspectWarningDialog&); LockAspectWarningDialog& operator=(const LockAspectWarningDialog&); BrainBrowserWindow* m_brainBrowserWindow; const Mode m_mode; Result m_result = Result::CANCEL; QCheckBox* m_doNotShowAgainCheckBox; QRadioButton* m_lockAspectRadioButton = NULL; QRadioButton* m_leaveUnlockedAspectRadioButton = NULL; static bool s_doNotShowAgainEnterAnnotationsModeStatusFlag; static bool s_doNotShowAgainLockAspectModeStatusFlag; // ADD_NEW_MEMBERS_HERE }; #ifdef __LOCK_ASPECT_WARNING_DIALOG_DECLARE__ bool LockAspectWarningDialog::s_doNotShowAgainEnterAnnotationsModeStatusFlag = false; bool LockAspectWarningDialog::s_doNotShowAgainLockAspectModeStatusFlag = false; #endif // __LOCK_ASPECT_WARNING_DIALOG_DECLARE__ } // namespace #endif //__LOCK_ASPECT_WARNING_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/MacApplication.cxx000066400000000000000000000046511360521144700230710ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __MAC_APPLICATION_DECLARE__ #include "MacApplication.h" #undef __MAC_APPLICATION_DECLARE__ #include #include #include #include "CaretAssert.h" #include "EventManager.h" #include "EventOperatingSystemRequestOpenDataFile.h" using namespace caret; /** * \class caret::MacApplication * \brief Subclass of QApplication so that Macs can receive file open events * \ingroup GuiQt * * Allows user to open a spec file via Mac Finder. * * Based upon: http://www.qtcentre.org/wiki/index.php?title=Opening_documents_in_the_Mac_OS_X_Finder&printable=yes&useskin=vector */ /** * Constructor. */ MacApplication::MacApplication(int& argc, char** argv) : QApplication(argc, argv) { } /** * Destructor. */ MacApplication::~MacApplication() { } /** * Receive events and processes them. * * @param event * The event. * @return true if the event was processed, else false. */ bool MacApplication::event(QEvent *event) { bool eventWasProcessed = false; switch (event->type()) { case QEvent::FileOpen: { QFileOpenEvent* openFileEvent = static_cast(event); CaretAssert(openFileEvent); const QString filename = openFileEvent->file(); EventManager::get()->sendEvent(EventOperatingSystemRequestOpenDataFile(filename).getPointer()); eventWasProcessed = true; } break; default: eventWasProcessed = QApplication::event(event); break; } return eventWasProcessed; } connectome-workbench-1.4.2/src/GuiQt/MacApplication.h000066400000000000000000000033161360521144700225130ustar00rootroot00000000000000#ifndef __MAC_APPLICATION_H__ #define __MAC_APPLICATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /* * Based upon: http://www.qtcentre.org/wiki/index.php?title=Opening_documents_in_the_Mac_OS_X_Finder&printable=yes&useskin=vector */ #include namespace caret { class MacApplication : public QApplication { Q_OBJECT public: MacApplication(int& argc, char** argv); virtual ~MacApplication(); private: MacApplication(const MacApplication&); MacApplication& operator=(const MacApplication&); public: // ADD_NEW_METHODS_HERE protected: virtual bool event(QEvent *event); private: // ADD_NEW_MEMBERS_HERE }; #ifdef __MAC_APPLICATION_DECLARE__ // #endif // __MAC_APPLICATION_DECLARE__ } // namespace #endif //__MAC_APPLICATION_H__ connectome-workbench-1.4.2/src/GuiQt/MacDockMenu.cxx000066400000000000000000000173161360521144700223350ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __MAC_DOCK_MENU_DECLARE__ #include "MacDockMenu.h" #undef __MAC_DOCK_MENU_DECLARE__ #include "Brain.h" #include "BrainBrowserWindow.h" #include "CaretAssert.h" #include "EventBrowserWindowNew.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "SpecFile.h" using namespace caret; #ifdef CARET_OS_MACOSX /* * Not in Qt Header Files. * See http://qt-project.org/doc/qt-4.8/exportedfunctions.html */ extern void qt_mac_set_dock_menu(QMenu *menu); #endif // CARET_OS_MACOSX /** * \class caret::MacDockMenu * \brief Menu that is displayed Mac's Dock Menu. * \ingroup GuiQt * * The Mac Dock Menu is displayed when the user either holds the mouse button * down or Control-Clicks the icon for a running wb_view instance in the * Mac's Dock. */ /** * Constructor. */ MacDockMenu::MacDockMenu(QWidget* parent) : QMenu(parent) { /* * Recent Spec Files */ const int32_t firstRecentSpecFileIndex = actions().size(); const int32_t numRecentSpecFiles = BrainBrowserWindow::loadRecentSpecFileMenu(this); QList menuActions = actions(); const int32_t numberOfRecentSpecFileActions = menuActions.size() - firstRecentSpecFileIndex; for (int32_t i = firstRecentSpecFileIndex; i < numberOfRecentSpecFileActions; i++) { m_recentSpecFileActions.push_back(menuActions.at(i)); } if (numRecentSpecFiles > 0) { addSeparator(); } /* * Name of spec file */ const AString specFileName = GuiManager::get()->getBrain()->getSpecFile()->getFileNameNoPath(); /* * Open Windows */ const std::vector browserWindows = GuiManager::get()->getAllOpenBrainBrowserWindows(); if ( ! browserWindows.empty()) { for (std::vector::const_iterator bwIter = browserWindows.begin(); bwIter != browserWindows.end(); bwIter++) { const BrainBrowserWindow* bbw = *bwIter; const AString title = (bbw->windowTitle() + " " + specFileName); QAction* action = addAction(title); action->setData(bbw->getBrowserWindowIndex()); m_browserWindowActions.push_back(action); } addSeparator(); } /* * Create New Window */ m_newBrowserWindowAction = addAction("New Window"); /* * Connect the menu to a slot for processing menu selections */ QObject::connect(this, SIGNAL(triggered(QAction*)), this, SLOT(menuActionTriggered(QAction*))); } /** * Destructor. */ MacDockMenu::~MacDockMenu() { std::cout << "Deleting Mac Dock Menu" << std::endl; } /** * Called when an item in the menu is selected. * * @param action * Menu's action that was triggered. */ void MacDockMenu::menuActionTriggered(QAction* action) { if (action == m_newBrowserWindowAction) { createNewBrowserWindow(); } else if (std::find(m_recentSpecFileActions.begin(), m_recentSpecFileActions.end(), action) != m_recentSpecFileActions.end()) { const AString specFileName = action->data().toString(); std::vector fileNamesToLoad; fileNamesToLoad.push_back(specFileName); BrainBrowserWindow* browserWindow = GuiManager::get()->getActiveBrowserWindow(); browserWindow->loadFilesFromCommandLine(fileNamesToLoad, BrainBrowserWindow::LOAD_SPEC_FILE_WITH_DIALOG); } else if (std::find(m_browserWindowActions.begin(), m_browserWindowActions.end(), action) != m_browserWindowActions.end()) { const int32_t browserWindowIndex = action->data().toInt(); BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(browserWindowIndex); if (bbw != NULL) { bbw->activateWindow(); bbw->raise(); } } else if (action != NULL) { CaretAssertMessage(0, ("Mac Dock menu action not processed: " + action->text())); } } /** * Factory method to create/update the Mac Dock Menu. * On non-Mac platforms, this method does nothing. * * With Qt Menus, the "aboutToShow()" signal is used to * update the content of the menu so that the menu * can be updated just before it is displayed. However, * when a menu is added to the Dock, it is converted * to a platform native menu so the "aboutToShow()" signal * does not get issued. So, in Workbench, a Workbench event * is issued when something happens that requires an * update to the Dock Menu. This results in a new menu * being created and replacing the current Dock menu. */ void MacDockMenu::createUpdateMacDockMenu() { const bool DISABLE_DOCK_MENU = true; if (DISABLE_DOCK_MENU) { return; } #ifdef CARET_OS_MACOSX BrainBrowserWindow* browserWindow = GuiManager::get()->getActiveBrowserWindow(); if (browserWindow == NULL) { return; } MacDockMenu* menu = new MacDockMenu(); qt_mac_set_dock_menu(menu); /* * Previously created menus probably should be deleted but * it is not clear if QT takes ownership of the menu * which could result in a "double delete". In Qt 4.8.x, * the code does not show the menu being deleted at * any time but if that changes a crash would result. * * Another problem is that selection from the Dock * menu may cause the Dock menu to get recreated. */ // if (s_previousMacDockMenu != NULL) { // delete s_previousMacDockMenu; // } // s_previousMacDockMenu = menu; #endif // CARET_OS_MACOSX } /** * Gets called to create a new browser window. */ void MacDockMenu::createNewBrowserWindow() { EventManager::get()->blockEvent(EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW, true); BrainBrowserWindow* browserWindow = GuiManager::get()->getActiveBrowserWindow(); EventBrowserWindowNew eventNewBrowser(browserWindow, NULL); EventManager::get()->sendEvent(eventNewBrowser.getPointer()); if (eventNewBrowser.isError()) { QMessageBox::critical(browserWindow, "", eventNewBrowser.getErrorMessage()); return; } const int32_t newWindowIndex = eventNewBrowser.getBrowserWindowCreated()->getBrowserWindowIndex(); EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(newWindowIndex).getPointer()); EventManager::get()->blockEvent(EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW, false); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(newWindowIndex).getPointer()); } connectome-workbench-1.4.2/src/GuiQt/MacDockMenu.h000066400000000000000000000035461360521144700217620ustar00rootroot00000000000000#ifndef __MAC_DOCK_MENU_H__ #define __MAC_DOCK_MENU_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include namespace caret { class MacDockMenu : public QMenu { Q_OBJECT public: static void createUpdateMacDockMenu(); virtual ~MacDockMenu(); // ADD_NEW_METHODS_HERE private slots: void menuActionTriggered(QAction*); private: MacDockMenu(QWidget* parent = 0); MacDockMenu(const MacDockMenu&); MacDockMenu& operator=(const MacDockMenu&); void createNewBrowserWindow(); QAction* m_newBrowserWindowAction; std::vector m_recentSpecFileActions; std::vector m_browserWindowActions; static MacDockMenu* s_previousMacDockMenu; // ADD_NEW_MEMBERS_HERE }; #ifdef __MAC_DOCK_MENU_DECLARE__ MacDockMenu* MacDockMenu::s_previousMacDockMenu = NULL; #endif // __MAC_DOCK_MENU_DECLARE__ } // namespace #endif //__MAC_DOCK_MENU_H__ connectome-workbench-1.4.2/src/GuiQt/MacDuplicateMenuBar.cxx000066400000000000000000000105651360521144700240130ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __MAC_DUPLICATE_MENU_BAR_DECLARE__ #include "MacDuplicateMenuBar.h" #undef __MAC_DUPLICATE_MENU_BAR_DECLARE__ #include #include #include #include #include #include #include "AString.h" #include "CaretAssert.h" using namespace caret; /** * \class caret::MacDuplicateMenuBar * \brief A duplicate of the mac menu bar placed in the main window * \ingroup GuiQt * * The menu on macs is separate from the main window and placed at the * top of the display. When creating screen images, such as for tutorials, * it makes it difficult to include the menu bar in the image. This class * creates a copy of the menu bar in a widget that can be added to * the main window. */ /** * Constructor. * * @param mainWindow * Main window whose menu bar is copied. * @param parent * Optional parent widget. */ MacDuplicateMenuBar::MacDuplicateMenuBar(QMainWindow* mainWindow, QWidget* parent) : QWidget(parent) { QHBoxLayout* layout = new QHBoxLayout(this); QMargins margins = layout->contentsMargins(); margins.setTop(0); margins.setBottom(0); layout->setContentsMargins(margins); CaretAssert(mainWindow); /* * Examine contents of menu bar and duplicate all items in it */ QList menuList = mainWindow->menuBar()->actions(); QListIterator iter(menuList); while (iter.hasNext()) { QAction* action = iter.next(); QMenu* menu = action->menu(); if (menu != NULL) { QMenu* dupMenu = duplicateMenu(menu); if (dupMenu != NULL) { /* * Cannot add a menu bar to the window so each menu * is attached to a new QToolButton */ QToolButton* tb = new QToolButton(); tb->setPopupMode(QToolButton::InstantPopup); tb->setText(menu->title()); tb->setMenu(dupMenu); layout->addWidget(tb); } } } layout->addStretch(); } /** * Destructor. */ MacDuplicateMenuBar::~MacDuplicateMenuBar() { } /** * Recursively duplicate the given menu. * * @param copyFromMenu * Menu that is examined and copied * @return * Pointer to duplicated menu or NULL if failed to duplicate. */ QMenu* MacDuplicateMenuBar::duplicateMenu(QMenu* copyFromMenu) { const bool printFlag(false); if (printFlag) { std::cout << std::endl; std::cout << m_indentText << "Menu: " << copyFromMenu->title() << std::endl; } m_indentText.append(" "); QMenu* newMenu = new QMenu(copyFromMenu->title()); QList actionList = copyFromMenu->actions(); QListIterator iter(actionList); while (iter.hasNext()) { QAction* action = iter.next(); QMenu* subMenu = action->menu(); if (subMenu != NULL) { QMenu* dupMenu = duplicateMenu(subMenu); if (dupMenu != NULL) { newMenu->addMenu(dupMenu); } } else if (action->isSeparator()) { if (printFlag) { std::cout << m_indentText << "Separator" << std::endl; } newMenu->addSeparator(); } else { if (printFlag) { std::cout << m_indentText << "Item: " << action->text() << std::endl; } newMenu->addAction(action); } } m_indentText.resize(m_indentText.length() - 3); return newMenu; } connectome-workbench-1.4.2/src/GuiQt/MacDuplicateMenuBar.h000066400000000000000000000033661360521144700234410ustar00rootroot00000000000000#ifndef __MAC_DUPLICATE_MENU_BAR_H__ #define __MAC_DUPLICATE_MENU_BAR_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include class QMainWindow; class QMenu; namespace caret { class MacDuplicateMenuBar : public QWidget { Q_OBJECT public: MacDuplicateMenuBar(QMainWindow* mainWindow, QWidget* parent = 0); virtual ~MacDuplicateMenuBar(); MacDuplicateMenuBar(const MacDuplicateMenuBar&) = delete; MacDuplicateMenuBar& operator=(const MacDuplicateMenuBar&) = delete; // ADD_NEW_METHODS_HERE private: QMenu* duplicateMenu(QMenu* menu); QString m_indentText; // ADD_NEW_MEMBERS_HERE }; #ifdef __MAC_DUPLICATE_MENU_BAR_DECLARE__ // #endif // __MAC_DUPLICATE_MENU_BAR_DECLARE__ } // namespace #endif //__MAC_DUPLICATE_MENU_BAR_H__ connectome-workbench-1.4.2/src/GuiQt/MapSettingsChartTwoLineHistoryWidget.cxx000066400000000000000000000623621360521144700274600ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __MAP_SETTINGS_CHART_TWO_LINE_HISTORY_WIDGET_DECLARE__ #include "MapSettingsChartTwoLineHistoryWidget.h" #undef __MAP_SETTINGS_CHART_TWO_LINE_HISTORY_WIDGET_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include "CaretAssert.h" #include "CaretColorEnumComboBox.h" #include "CaretMappableDataFile.h" #include "ChartTwoDataCartesian.h" #include "ChartableTwoFileDelegate.h" #include "ChartableTwoFileLineSeriesChart.h" #include "ChartTwoLineSeriesHistory.h" #include "ChartTwoOverlay.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "MapFileDataSelector.h" #include "WuQDoubleSpinBox.h" #include "WuQImageLabel.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::MapSettingsChartTwoLineHistoryWidget * \brief Dialog for controlling the display of line series chart data. * \ingroup GuiQt */ /** * Constructor. */ MapSettingsChartTwoLineHistoryWidget::MapSettingsChartTwoLineHistoryWidget(QWidget* parent) : QWidget(parent) { const AString maxHistoryString(AString::number(ChartTwoLineSeriesHistory::getMaximumRetainedHistoryCount())); const AString defaultColorToolTip("Color assigned to newly added line-series items"); const AString displayMaximumToolTip("Maximum number of line-series items enabled for viewing\n" "As new items are added, older items are disabled for viewing\n" "The number of history items retained (including those not\n" "displayed) is limited to this value or " + maxHistoryString + ", whichever is larger."); m_removeAllHistoryIcon = WuQtUtilities::loadIcon(":/SpecFileDialog/delete_icon.png"); QLabel* defaultColorLabel = new QLabel("Default Color: "); defaultColorLabel->setToolTip(defaultColorToolTip); m_defaultColorComboBox = new CaretColorEnumComboBox(this); m_defaultColorComboBox->getWidget()->setToolTip(defaultColorToolTip); m_defaultColorComboBox->getComboBox()->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); QObject::connect(m_defaultColorComboBox, &CaretColorEnumComboBox::colorSelected, this, &MapSettingsChartTwoLineHistoryWidget::defaultColorSelected); QLabel* defaultLineWidthLabel = new QLabel("Default Line Width: "); m_defaultLineWidthSpinBox = new WuQDoubleSpinBox(this); m_defaultLineWidthSpinBox->setRangePercentage(0.0, 100.0); m_defaultLineWidthSpinBox->setToolTip("Default width of new chart lines"); defaultLineWidthLabel->setToolTip(m_defaultLineWidthSpinBox->getWidget()->toolTip()); QObject::connect(m_defaultLineWidthSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &MapSettingsChartTwoLineHistoryWidget::defaultLineWidthChanged); QToolButton* removeAllHistoryToolButton = new QToolButton(); removeAllHistoryToolButton->setText("Remove All History..."); QObject::connect(removeAllHistoryToolButton, &QToolButton::clicked, this, &MapSettingsChartTwoLineHistoryWidget::removeAllHistoryButtonClicked); QLabel* viewedMaximumLabel = new QLabel("Viewed Maximum: "); viewedMaximumLabel->setToolTip(displayMaximumToolTip); m_viewedMaximumCountSpinBox = new QSpinBox(); m_viewedMaximumCountSpinBox->setToolTip(displayMaximumToolTip); m_viewedMaximumCountSpinBox->setRange(1, 10000); QObject::connect(m_viewedMaximumCountSpinBox, SIGNAL(valueChanged(int)), this, SLOT(viewedMaximumSpinBoxValueChanged(int))); m_removeHistoryItemSignalMapper = new QSignalMapper(this); QObject::connect(m_removeHistoryItemSignalMapper, SIGNAL(mapped(int)), this, SLOT(removeHistoryItemSelected(int))); m_colorItemSignalMapper = new QSignalMapper(this); QObject::connect(m_colorItemSignalMapper, SIGNAL(mapped(int)), this, SLOT(colorItemSelected(int))); m_lineWidthItemSignalMapper = new QSignalMapper(this); QObject::connect(m_lineWidthItemSignalMapper, SIGNAL(mapped(int)), this, SLOT(lineWidthItemSelected(int))); m_tableWidget = new QTableWidget(); m_tableWidget->setSelectionBehavior(QTableWidget::SelectItems); m_tableWidget->setSelectionMode(QTableWidget::SingleSelection); QObject::connect(m_tableWidget, &QTableWidget::cellChanged, this, &MapSettingsChartTwoLineHistoryWidget::tableWidgetCellChanged); QGridLayout* topLayout = new QGridLayout(); topLayout->setColumnStretch(0, 0); topLayout->setColumnStretch(1, 0); topLayout->setColumnStretch(2, 0); topLayout->setColumnStretch(3, 0); topLayout->setColumnStretch(4, 100); int gridRow = 0; topLayout->addWidget(defaultLineWidthLabel, gridRow, 0); topLayout->addWidget(m_defaultLineWidthSpinBox->getWidget(), gridRow, 1); topLayout->addWidget(defaultColorLabel, gridRow, 2); topLayout->addWidget(m_defaultColorComboBox->getWidget(), gridRow, 3); gridRow++; topLayout->addWidget(viewedMaximumLabel, gridRow, 0); topLayout->addWidget(m_viewedMaximumCountSpinBox, gridRow, 1); topLayout->addWidget(removeAllHistoryToolButton, gridRow, 2, 1, 2, Qt::AlignLeft); QVBoxLayout* layout = new QVBoxLayout(this); layout->addLayout(topLayout, 0); layout->addWidget(m_tableWidget, 100); } /** * Destructor. */ MapSettingsChartTwoLineHistoryWidget::~MapSettingsChartTwoLineHistoryWidget() { } /** * @return The chart overlay in this dialog (May be NULL !) */ ChartTwoOverlay* MapSettingsChartTwoLineHistoryWidget::getChartOverlay() { ChartTwoOverlay* chartOverlay = NULL; if (m_chartOverlayWeakPointer.expired()) { m_chartOverlayWeakPointer.reset(); } else { chartOverlay = m_chartOverlayWeakPointer.lock().get(); } return chartOverlay; } /** * Update dialog if the given chart overlay is in the dialog. * This may occur when the user changes the file in the chart overlay. * * @param chartOverlay * Chart overlay for history display. */ void MapSettingsChartTwoLineHistoryWidget::updateIfThisChartOverlayIsInDialog(const ChartTwoOverlay* chartOverlay) { ChartTwoOverlay* currentChartOverlay = getChartOverlay(); if (currentChartOverlay != NULL) { if (chartOverlay != currentChartOverlay) { return; } } updateDialogContentPrivate(); } /** * Update the content of the widget. * * @param chartOverlay * Chart overlay for history display. */ void MapSettingsChartTwoLineHistoryWidget::updateContent(ChartTwoOverlay* chartOverlay) { CaretAssert(chartOverlay); m_chartOverlayWeakPointer = chartOverlay->getWeakPointerToSelf(); updateDialogContentPrivate(); } void MapSettingsChartTwoLineHistoryWidget::updateDialogContentPrivate() { ChartTwoOverlay* chartOverlay = getChartOverlay(); if (chartOverlay == NULL) { close(); return; } ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); if (lineSeriesHistory != NULL) { m_defaultColorComboBox->setSelectedColor(lineSeriesHistory->getDefaultColor()); m_defaultLineWidthSpinBox->blockSignals(true); m_defaultLineWidthSpinBox->setValue(lineSeriesHistory->getDefaultLineWidth()); m_defaultLineWidthSpinBox->blockSignals(false); m_viewedMaximumCountSpinBox->blockSignals(true); m_viewedMaximumCountSpinBox->setValue(lineSeriesHistory->getDisplayCount()); m_viewedMaximumCountSpinBox->blockSignals(false); loadHistoryIntoTableWidget(lineSeriesHistory); } else { close(); } } /** * @return Map file in the dialog. */ CaretMappableDataFile* MapSettingsChartTwoLineHistoryWidget::getMapFile() { CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay* chartOverlay = getChartOverlay(); if (chartOverlay != NULL) { if (chartOverlay->getChartTwoDataType() == ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES) { ChartTwoOverlay::SelectedIndexType indexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t mapIndex = -1; chartOverlay->getSelectionData(mapFile, indexType, mapIndex); } } return mapFile; } /** * @return The line series history for the current chart overlay */ ChartTwoLineSeriesHistory* MapSettingsChartTwoLineHistoryWidget::getLineSeriesHistory() { ChartTwoLineSeriesHistory* lineSeriesHistory = NULL; CaretMappableDataFile* mapFile = getMapFile(); if (mapFile != NULL) { ChartableTwoFileLineSeriesChart* chartTwoLineSeries = mapFile->getChartingDelegate()->getLineSeriesCharting(); lineSeriesHistory = chartTwoLineSeries->getHistory(); } return lineSeriesHistory; } /** * Load the line-series history into the table widget. * * @param lineSeriesHistory * The line series history. */ void MapSettingsChartTwoLineHistoryWidget::loadHistoryIntoTableWidget(ChartTwoLineSeriesHistory* lineSeriesHistory) { CaretAssert(lineSeriesHistory); /* * NOTE: We never remove items from a table due to issues * with widget ownership (and destruction) and the signal mappers. * * When new rows are needed, they are added. * When there are two many rows, they are hidden. */ const QSignalBlocker tableSignalBlocker(m_tableWidget); const int32_t oldRowCount = m_tableWidget->rowCount(); const int32_t numHistory = lineSeriesHistory->getHistoryCount(); /* * Setup table dimensions */ m_tableWidget->setRowCount(std::max(numHistory, oldRowCount)); m_tableWidget->setColumnCount(COLUMN_COUNT); /* * If needed, add cells */ for (int32_t iRow = oldRowCount; iRow < numHistory; iRow++) { for (int32_t j = 0; j < COLUMN_COUNT; j++) { if (j == COLUMN_VIEW) { QTableWidgetItem* item = new QTableWidgetItem(""); item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable); m_tableWidget->setItem(iRow, j, item); } else if (j == COLUMN_REMOVE) { WuQImageLabel* removeHistoryLabel = new WuQImageLabel(m_removeAllHistoryIcon, "Remove"); QObject::connect(removeHistoryLabel, SIGNAL(clicked()), m_removeHistoryItemSignalMapper, SLOT(map())); m_removeHistoryItemSignalMapper->setMapping(removeHistoryLabel, iRow); m_tableWidget->setCellWidget(iRow, COLUMN_REMOVE, removeHistoryLabel); } else if (j == COLUMN_MOVE) { QLabel dummyLabel(""); QPixmap moveDownPixmap = createIcon(&dummyLabel, IconType::ARROW_DOWN); WuQImageLabel* moveDownLabel = new WuQImageLabel(moveDownPixmap, "Move Down"); QObject::connect(moveDownLabel, &WuQImageLabel::clicked, this, [=] { moveDownHistoryItemSelected(iRow); }); QPixmap moveUpPixmap = createIcon(&dummyLabel, IconType::ARROW_UP); WuQImageLabel* moveUpLabel = new WuQImageLabel(moveUpPixmap, "Move Up"); QObject::connect(moveUpLabel, &WuQImageLabel::clicked, this, [=] { moveUpHistoryItemSelected(iRow); }); QWidget* moveWidget = new QWidget; QHBoxLayout* moveLayout = new QHBoxLayout(moveWidget); moveLayout->setContentsMargins(4, 0, 4, 0); moveLayout->setSpacing(6); moveLayout->addWidget(moveDownLabel); moveLayout->addWidget(moveUpLabel); moveWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); m_tableWidget->setCellWidget(iRow, COLUMN_MOVE, moveWidget); } else if (j == COLUMN_COLOR) { CaretColorEnumComboBox* caretColorComboBox = new CaretColorEnumComboBox(this); QObject::connect(caretColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), m_colorItemSignalMapper, SLOT(map())); m_colorItemSignalMapper->setMapping(caretColorComboBox, iRow); m_tableWidget->setCellWidget(iRow, COLUMN_COLOR, caretColorComboBox->getWidget()); m_colorComboBoxes.push_back(caretColorComboBox); } else if (j == COLUMN_LINE_WIDTH) { WuQDoubleSpinBox* lineWidthSpinBox = new WuQDoubleSpinBox(this); lineWidthSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(lineWidthSpinBox, SIGNAL(valueChanged(double)), m_lineWidthItemSignalMapper, SLOT(map())); m_lineWidthItemSignalMapper->setMapping(lineWidthSpinBox, iRow); m_tableWidget->setCellWidget(iRow, COLUMN_LINE_WIDTH, lineWidthSpinBox->getWidget()); m_lineWidthSpinBoxes.push_back(lineWidthSpinBox); } else if (j == COLUMN_DESCRIPTION) { QTableWidgetItem* item = new QTableWidgetItem(""); item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); m_tableWidget->setItem(iRow, j, item); } else { CaretAssert(0); } } } CaretAssert(m_lineWidthSpinBoxes.size() == m_colorComboBoxes.size()); /* * Hide rows not needed */ for (int32_t iRow = numHistory; iRow < oldRowCount; iRow++) { m_tableWidget->setRowHidden(iRow, true); } /* * Load cells */ CaretAssert(numHistory <= m_tableWidget->rowCount()); for (int32_t iRow = 0; iRow < numHistory; iRow++) { ChartTwoDataCartesian* historyData = lineSeriesHistory->getHistoryItem(iRow); const MapFileDataSelector* mapFileDataSelector = historyData->getMapFileDataSelector(); m_tableWidget->item(iRow, COLUMN_VIEW)->setCheckState(historyData->isSelected() ? Qt::Checked : Qt::Unchecked); CaretAssertVectorIndex(m_colorComboBoxes, iRow); m_colorComboBoxes[iRow]->setSelectedColor(historyData->getColor()); CaretAssertVectorIndex(m_lineWidthSpinBoxes, iRow); m_lineWidthSpinBoxes[iRow]->setValue(historyData->getLineWidth()); QTableWidgetItem* item = m_tableWidget->item(iRow, COLUMN_DESCRIPTION); item->setText(mapFileDataSelector->toString()); m_tableWidget->setRowHidden(iRow, false); } /* * If table was empty, add column titles * and adjust column widths */ if ((oldRowCount == 0) && (numHistory > 0)) { m_tableWidget->setHorizontalHeaderItem(COLUMN_VIEW, new QTableWidgetItem("View")); m_tableWidget->setHorizontalHeaderItem(COLUMN_REMOVE, new QTableWidgetItem("Remove")); m_tableWidget->setHorizontalHeaderItem(COLUMN_MOVE, new QTableWidgetItem("Move")); m_tableWidget->setHorizontalHeaderItem(COLUMN_COLOR, new QTableWidgetItem("Color")); m_tableWidget->setHorizontalHeaderItem(COLUMN_LINE_WIDTH, new QTableWidgetItem("Line Width")); m_tableWidget->setHorizontalHeaderItem(COLUMN_DESCRIPTION, new QTableWidgetItem("Description")); m_tableWidget->resizeColumnToContents(COLUMN_VIEW); m_tableWidget->resizeColumnToContents(COLUMN_REMOVE); m_tableWidget->resizeColumnToContents(COLUMN_MOVE); m_tableWidget->resizeColumnToContents(COLUMN_COLOR); m_tableWidget->resizeColumnToContents(COLUMN_LINE_WIDTH); m_tableWidget->setColumnWidth(COLUMN_DESCRIPTION, 350); QSize tableSize = WuQtUtilities::estimateTableWidgetSize(m_tableWidget); WuQtUtilities::resizeWindow(this, tableSize.width() + 30, sizeHint().height()); } } /** * Called when the content of a cell changes. * Update corresponding item in the spec file. * * @param rowIndex * The row of the cell that was clicked. * @param columnIndex * The columnof the cell that was clicked. */ void MapSettingsChartTwoLineHistoryWidget::tableWidgetCellChanged(int rowIndex, int columnIndex) { QTableWidgetItem* item = m_tableWidget->item(rowIndex, columnIndex); if (item != NULL) { if (columnIndex == COLUMN_VIEW) { ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); if (lineSeriesHistory != NULL) { ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(rowIndex); CaretAssert(data); data->setSelected(WuQtUtilities::checkStateToBool(item->checkState())); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } } } /** * Remove a history item selected * * @param rowIndex * Row index of item. */ void MapSettingsChartTwoLineHistoryWidget::removeHistoryItemSelected(int rowIndex) { /* * May be possible for user to press another remove button * before this one is finished */ const QSignalBlocker removeSignalBlocker(m_removeHistoryItemSignalMapper); ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); lineSeriesHistory->removeHistoryItem(rowIndex); updateDialogContentPrivate(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Move a history item up * * @param rowIndex * Row index of item. */ void MapSettingsChartTwoLineHistoryWidget::moveUpHistoryItemSelected(int rowIndex) { ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); lineSeriesHistory->moveUpHistoryItem(rowIndex); updateDialogContentPrivate(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Move a history item down * * @param rowIndex * Row index of item. */ void MapSettingsChartTwoLineHistoryWidget::moveDownHistoryItemSelected(int rowIndex) { ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); lineSeriesHistory->moveDownHistoryItem(rowIndex); updateDialogContentPrivate(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Color item selected * * @param rowIndex * Row index of item. */ void MapSettingsChartTwoLineHistoryWidget::colorItemSelected(int rowIndex) { CaretAssertVectorIndex(m_colorComboBoxes, rowIndex); CaretAssert(m_colorComboBoxes[rowIndex]); ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); if (lineSeriesHistory != NULL) { ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(rowIndex); CaretAssert(data); data->setColor(m_colorComboBoxes[rowIndex]->getSelectedColor()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } /** * line width item selected * * @param rowIndex * Row index of item. */ void MapSettingsChartTwoLineHistoryWidget::lineWidthItemSelected(int rowIndex) { CaretAssertVectorIndex(m_lineWidthSpinBoxes, rowIndex); CaretAssert(m_lineWidthSpinBoxes[rowIndex]); ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); if (lineSeriesHistory != NULL) { ChartTwoDataCartesian* data = lineSeriesHistory->getHistoryItem(rowIndex); CaretAssert(data); data->setLineWidth(m_lineWidthSpinBoxes[rowIndex]->value()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } /** * Called when the "Remove All History" button is clicked. */ void MapSettingsChartTwoLineHistoryWidget::removeAllHistoryButtonClicked() { if (WuQMessageBox::warningOkCancel(this, ("Remove all line series history from the file " + getMapFile()->getFileNameNoPath()))) { ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); lineSeriesHistory->clearHistory(); updateDialogContentPrivate(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } /** * Called when the default color is changed. * * @param color * New default color. */ void MapSettingsChartTwoLineHistoryWidget::defaultColorSelected(const CaretColorEnum::Enum color) { ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); if (lineSeriesHistory != NULL) { lineSeriesHistory->setDefaultColor(color); } } /** * Called when line width is changed * * @param defaultLineWidth * New default line width. */ void MapSettingsChartTwoLineHistoryWidget::defaultLineWidthChanged(double defaultLineWidth) { ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); if (lineSeriesHistory != NULL) { lineSeriesHistory->setDefaultLineWidth(defaultLineWidth); } } /** * Gets called when display last count is changed. * * @param num * Number of history items to display. */ void MapSettingsChartTwoLineHistoryWidget::viewedMaximumSpinBoxValueChanged(int num) { ChartTwoLineSeriesHistory* lineSeriesHistory = getLineSeriesHistory(); if (lineSeriesHistory != NULL) { lineSeriesHistory->setDisplayCount(num); updateDialogContentPrivate(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } /** * Create a pixmap for the given widget * * @param editButton * The edit button identifier * @return * Pixmap for the given button */ QPixmap MapSettingsChartTwoLineHistoryWidget::createIcon(const QWidget* widget, const IconType iconType) const { CaretAssert(widget); const qreal pixmapSize = 22.0; const qreal maxValue = pixmapSize / 2.0 - 1.0; const qreal arrowTip = maxValue * (2.0 / 3.0); uint32_t pixmapOptions(static_cast(WuQtUtilities::PixMapCreationOptions::TransparentBackground)); QPixmap pixmap(static_cast(pixmapSize), static_cast(pixmapSize)); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginCenter(widget, pixmap, pixmapOptions); QPen pen(painter->pen()); pen.setWidth(3); painter->setPen(pen); switch (iconType) { case IconType::ARROW_DOWN: /* * Down arrow */ painter->drawLine(QPointF(0, maxValue), QPointF(0, -maxValue)); painter->drawLine(QPointF(0, -maxValue), QPointF(arrowTip, -maxValue + arrowTip)); painter->drawLine(QPointF(0, -maxValue), QPointF(-arrowTip, -maxValue + arrowTip)); break; case IconType::ARROW_UP: /* * Up arrow */ painter->drawLine(QPointF(0, maxValue), QPointF(0, -maxValue)); painter->drawLine(QPointF(0, maxValue), QPointF(arrowTip, maxValue - arrowTip)); painter->drawLine(QPointF(0, maxValue), QPointF(-arrowTip, maxValue - arrowTip)); break; } return pixmap; } connectome-workbench-1.4.2/src/GuiQt/MapSettingsChartTwoLineHistoryWidget.h000066400000000000000000000106751360521144700271050ustar00rootroot00000000000000#ifndef __MAP_SETTINGS_CHART_TWO_LINE_HISTORY_WIDGET_H__ #define __MAP_SETTINGS_CHART_TWO_LINE_HISTORY_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretColorEnum.h" class QLabel; class QIcon; class QSignalMapper; class QSpinBox; class QTableWidget; namespace caret { class CaretColorEnumComboBox; class CaretMappableDataFile; class ChartTwoLineSeriesHistory; class ChartTwoOverlay; class WuQDoubleSpinBox; class MapSettingsChartTwoLineHistoryWidget : public QWidget { Q_OBJECT public: MapSettingsChartTwoLineHistoryWidget(QWidget* parent = 0); virtual ~MapSettingsChartTwoLineHistoryWidget(); void updateContent(ChartTwoOverlay* chartOverlay); void updateIfThisChartOverlayIsInDialog(const ChartTwoOverlay* chartOverlay); // ADD_NEW_METHODS_HERE private slots: void tableWidgetCellChanged(int rowIndex, int columnIndex); void removeHistoryItemSelected(int rowIndex); void moveUpHistoryItemSelected(int rowIndex); void moveDownHistoryItemSelected(int rowIndex); void colorItemSelected(int rowIndex); void lineWidthItemSelected(int rowIndex); void removeAllHistoryButtonClicked(); void defaultColorSelected(const CaretColorEnum::Enum color); void defaultLineWidthChanged(double); void viewedMaximumSpinBoxValueChanged(int); private: enum class IconType { ARROW_DOWN, ARROW_UP }; MapSettingsChartTwoLineHistoryWidget(const MapSettingsChartTwoLineHistoryWidget&); MapSettingsChartTwoLineHistoryWidget& operator=(const MapSettingsChartTwoLineHistoryWidget&); void updateDialogContentPrivate(); void loadHistoryIntoTableWidget(ChartTwoLineSeriesHistory* lineSeriesHistory); ChartTwoOverlay* getChartOverlay(); ChartTwoLineSeriesHistory* getLineSeriesHistory(); CaretMappableDataFile* getMapFile(); QPixmap createIcon(const QWidget* widget, const IconType iconType) const; std::weak_ptr m_chartOverlayWeakPointer; QTableWidget* m_tableWidget; QIcon* m_removeAllHistoryIcon; QIcon* m_downArrowIcon; QIcon* m_upArrowIcon; QSignalMapper* m_removeHistoryItemSignalMapper; QSignalMapper* m_colorItemSignalMapper; QSignalMapper* m_lineWidthItemSignalMapper; std::vector m_colorComboBoxes; std::vector m_lineWidthSpinBoxes; CaretColorEnumComboBox* m_defaultColorComboBox; WuQDoubleSpinBox* m_defaultLineWidthSpinBox; QSpinBox* m_viewedMaximumCountSpinBox; static const int32_t COLUMN_VIEW = 0; static const int32_t COLUMN_REMOVE = 1; static const int32_t COLUMN_MOVE = 2; static const int32_t COLUMN_COLOR = 3; static const int32_t COLUMN_LINE_WIDTH = 4; static const int32_t COLUMN_DESCRIPTION = 5; static const int32_t COLUMN_COUNT = 6; // ADD_NEW_MEMBERS_HERE }; #ifdef __MAP_SETTINGS_CHART_TWO_LINE_HISTORY_WIDGET_DECLARE__ // #endif // __MAP_SETTINGS_CHART_TWO_LINE_HISTORY_WIDGET_DECLARE__ } // namespace #endif //__MAP_SETTINGS_CHART_TWO_LINE_HISTORY_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/MapSettingsColorBarPaletteOptionsWidget.cxx000066400000000000000000000142051360521144700301220ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __MAP_SETTINGS_COLOR_BAR_PALETTE_OPTIONS_WIDGET_DECLARE__ #include "MapSettingsColorBarPaletteOptionsWidget.h" #undef __MAP_SETTINGS_COLOR_BAR_PALETTE_OPTIONS_WIDGET_DECLARE__ #include #include #include #include #include "CaretAssert.h" #include "CaretMappableDataFile.h" #include "CopyPaletteColorMappingToFilesDialog.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventSurfaceColoringInvalidate.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::MapSettingsColorBarPaletteOptionsWidget * \brief Widget for apply to all maps checkbox and apply to files button for color bar and palette * \ingroup GuiQt */ /** * Constructor. * * @param parent * The parent widget. */ MapSettingsColorBarPaletteOptionsWidget::MapSettingsColorBarPaletteOptionsWidget(QWidget* parent) : QGroupBox("Color Bar and Palette Settings", parent) { m_applyToAllMapsCheckBox = new QCheckBox("Apply to All Maps"); QObject::connect(m_applyToAllMapsCheckBox, &QCheckBox::clicked, this, &MapSettingsColorBarPaletteOptionsWidget::applyToAllMapsCheckBoxClicked); m_applyToAllMapsCheckBox->setToolTip("When checked, these color bar and palette settings\n" "are applied to all maps in the file.\n" "When disabled, the file uses one palette for all maps."); m_applyToAllFilesAction = new QAction(this); m_applyToAllFilesAction->setText("Apply to Files..."); m_applyToAllFilesAction->setToolTip("Displays a dialog that allows selection of data\n" "files to which the palette settings are applied"); QObject::connect(m_applyToAllFilesAction, &QAction::triggered, this, &MapSettingsColorBarPaletteOptionsWidget::applyToAllFilesToolButtonClicked); QToolButton* applyToFilesToolButton = new QToolButton(); applyToFilesToolButton->setDefaultAction(m_applyToAllFilesAction); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(m_applyToAllMapsCheckBox); layout->addWidget(applyToFilesToolButton); setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed)); } /** * Destructor. */ MapSettingsColorBarPaletteOptionsWidget::~MapSettingsColorBarPaletteOptionsWidget() { } /** * Update contents for editing a map settings for data in a caret * mappable data file. * * @param caretMappableDataFile * Data file containing palette that is edited. * @param mapIndex * Index of map for palette that is edited. */ void MapSettingsColorBarPaletteOptionsWidget::updateEditor(CaretMappableDataFile* caretMappableDataFile, const int32_t mapIndex) { m_mapFile = caretMappableDataFile; m_mapFileIndex = mapIndex; if ((m_mapFile != NULL) && (m_mapFileIndex >= 0)) { if (m_mapFile->isOnePaletteUsedForAllMaps()) { m_applyToAllMapsCheckBox->setEnabled(false); m_applyToAllMapsCheckBox->setChecked(false); } else { m_applyToAllMapsCheckBox->setEnabled(true); m_applyToAllMapsCheckBox->setChecked(m_mapFile->isApplyPaletteColorMappingToAllMaps()); } setEnabled(true); } else { setEnabled(false); } } /** * Called by users of this widget to apply the selected options. */ void MapSettingsColorBarPaletteOptionsWidget::applyOptions() { if (m_mapFile != NULL) { if (m_mapFile->isApplyPaletteColorMappingToAllMaps()) { m_mapFile->applyPaletteColorMappingToAllMaps(m_mapFileIndex); m_mapFile->updateScalarColoringForAllMaps(); } } updateColoringAndGraphics(); } /** * Called when the "Apply to All Maps" checkbox is clicked * * @param checked * New status of button. */ void MapSettingsColorBarPaletteOptionsWidget::applyToAllMapsCheckBoxClicked(bool checked) { if (m_mapFile != NULL) { m_mapFile->setApplyPaletteColorMappingToAllMaps(checked); } applyOptions(); } /** * Called when the Apply to Files tool button is clicked */ void MapSettingsColorBarPaletteOptionsWidget::applyToAllFilesToolButtonClicked() { if (m_mapFile != NULL) { AString errorMessage; if ( ! CopyPaletteColorMappingToFilesDialog::run(m_mapFile, m_mapFile->getMapPaletteColorMapping(m_mapFileIndex), this, errorMessage)) { if ( ! errorMessage.isEmpty()) { WuQMessageBox::errorOk(this, errorMessage); } } updateColoringAndGraphics(); } } /** * Update coloring and graphics */ void MapSettingsColorBarPaletteOptionsWidget::updateColoringAndGraphics() { if (m_applyToAllMapsCheckBox->isChecked()) { m_mapFile->updateScalarColoringForAllMaps(); } else { m_mapFile->updateScalarColoringForMap(m_mapFileIndex); } EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } connectome-workbench-1.4.2/src/GuiQt/MapSettingsColorBarPaletteOptionsWidget.h000066400000000000000000000046601360521144700275530ustar00rootroot00000000000000#ifndef __MAP_SETTINGS_COLOR_BAR_PALETTE_OPTIONS_WIDGET_H__ #define __MAP_SETTINGS_COLOR_BAR_PALETTE_OPTIONS_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include class QAction; class QCheckBox; namespace caret { class CaretMappableDataFile; class MapSettingsColorBarPaletteOptionsWidget : public QGroupBox { Q_OBJECT public: MapSettingsColorBarPaletteOptionsWidget(QWidget* parent = 0); virtual ~MapSettingsColorBarPaletteOptionsWidget(); void updateEditor(CaretMappableDataFile* caretMappableDataFile, const int32_t mapIndex); void applyOptions(); // ADD_NEW_METHODS_HERE private slots: void applyToAllMapsCheckBoxClicked(bool checked); void applyToAllFilesToolButtonClicked(); private: MapSettingsColorBarPaletteOptionsWidget(const MapSettingsColorBarPaletteOptionsWidget&); MapSettingsColorBarPaletteOptionsWidget& operator=(const MapSettingsColorBarPaletteOptionsWidget&); void updateColoringAndGraphics(); QCheckBox* m_applyToAllMapsCheckBox; QAction* m_applyToAllFilesAction; CaretMappableDataFile* m_mapFile = NULL; int32_t m_mapFileIndex = -1; // ADD_NEW_MEMBERS_HERE }; #ifdef __MAP_SETTINGS_COLOR_BAR_PALETTE_OPTIONS_WIDGET_DECLARE__ // #endif // __MAP_SETTINGS_COLOR_BAR_PALETTE_OPTIONS_WIDGET_DECLARE__ } // namespace #endif //__MAP_SETTINGS_COLOR_BAR_PALETTE_OPTIONS_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/MapSettingsColorBarWidget.cxx000066400000000000000000000445761360521144700252450ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __MAP_SETTINGS_COLOR_BAR_WIDGET_DECLARE__ #include "MapSettingsColorBarWidget.h" #undef __MAP_SETTINGS_COLOR_BAR_WIDGET_DECLARE__ #include #include #include #include #include #include #include "AnnotationColorBar.h" #include "CaretAssert.h" #include "CaretMappableDataFile.h" #include "EnumComboBoxTemplate.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "MapSettingsColorBarPaletteOptionsWidget.h" #include "NumericFormatModeEnum.h" #include "Overlay.h" #include "PaletteColorBarValuesModeEnum.h" #include "PaletteColorMapping.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::MapSettingsColorBarWidget * \brief Contains controls for adjusting a color bar's attributes. * \ingroup GuiQt */ /** * Constructor. */ MapSettingsColorBarWidget::MapSettingsColorBarWidget(QWidget* parent) : QWidget(parent) { m_colorBar = NULL; m_paletteColorMapping = NULL; QWidget* locationPositionWidget = this->createLocationPositionSection(); QWidget* numericsWidget = this->createDataNumericsSection(); m_paletteOptionsWidget = new MapSettingsColorBarPaletteOptionsWidget(); QGridLayout* layout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 6, 6); layout->addWidget(locationPositionWidget, 0, 0, Qt::AlignLeft); layout->addWidget(numericsWidget, 1, 0, Qt::AlignLeft); layout->addWidget(m_paletteOptionsWidget); layout->setSizeConstraint(QLayout::SetFixedSize); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } /** * Destructor. */ MapSettingsColorBarWidget::~MapSettingsColorBarWidget() { } ///** // * Update the content of widget. // * // * @param overlay // * Overlay for display in this widget. // */ //void //MapSettingsColorBarWidget::updateContent(Overlay* overlay) //{ // m_colorBar = NULL; // m_paletteColorMapping = NULL; // // if (overlay != NULL) { // CaretMappableDataFile* mapFile = NULL; // int32_t mapIndex = 0; // overlay->getSelectionData(mapFile, // mapIndex); // if (mapFile != NULL) { // if ((mapIndex >= 0) // && (mapIndex < mapFile->getNumberOfMaps())) { // if (mapFile->isMappedWithPalette()) { // m_paletteColorMapping = mapFile->getMapPaletteColorMapping(mapIndex); // m_colorBar = overlay->getColorBar(); // } // } // } // } //} /** * Update the content of the widget. * * @param caretMappableDataFile * Data file containing palette that is edited. * @param mapIndex * Index of map for palette that is edited. */ void MapSettingsColorBarWidget::updateContent(CaretMappableDataFile* caretMappableDataFile, const int32_t mapIndex, AnnotationColorBar* annotationColorBar, PaletteColorMapping* paletteColorMapping) { m_caretMappableDataFile = caretMappableDataFile; m_mapIndex = mapIndex; m_colorBar = annotationColorBar; m_paletteColorMapping = paletteColorMapping; updateContentPrivate(); } /** * Update the content of the widget. */ void MapSettingsColorBarWidget::updateContentPrivate() { bool enableWidget = false; if ((m_colorBar != NULL) && (m_paletteColorMapping != NULL)) { const AnnotationColorBarPositionModeEnum::Enum positionMode = m_colorBar->getPositionMode(); m_annotationColorBarPositionModeEnumComboBox->setSelectedItem(positionMode); const AnnotationCoordinateSpaceEnum::Enum coordinateSpace = m_colorBar->getCoordinateSpace(); m_annotationCoordinateSpaceEnumComboBox->setSelectedItem(coordinateSpace); std::vector annotationVector; annotationVector.push_back(m_colorBar); std::vector annotationTwoDimVector; annotationTwoDimVector.push_back(m_colorBar); m_paletteOptionsWidget->updateEditor(m_caretMappableDataFile, m_mapIndex); enableWidget = true; } this->updateColorBarAttributes(); setEnabled(enableWidget); } /** * Called when a control is changed. */ void MapSettingsColorBarWidget::applySelections() { if (m_paletteColorMapping != NULL) { m_paletteColorMapping->setColorBarValuesMode(m_colorBarDataModeComboBox->getSelectedItem()); m_paletteColorMapping->setColorBarNumericFormatMode(m_colorBarNumericFormatModeComboBox->getSelectedItem()); m_paletteColorMapping->setColorBarPrecisionDigits(m_colorBarDecimalsSpinBox->value()); m_paletteColorMapping->setColorBarNumericSubdivisionCount(m_colorBarNumericSubdivisionsSpinBox->value()); m_paletteColorMapping->setColorBarShowTickMarksSelected(m_showTickMarksCheckBox->isChecked()); } m_paletteOptionsWidget->applyOptions(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Gets called when a position mode combo box item is selected. */ void MapSettingsColorBarWidget::annotationColorBarPositionModeEnumComboBoxItemActivated() { const AnnotationColorBarPositionModeEnum::Enum positionMode = m_annotationColorBarPositionModeEnumComboBox->getSelectedItem(); if (m_colorBar != NULL) { m_colorBar->setPositionMode(positionMode); switch (positionMode) { case AnnotationColorBarPositionModeEnum::AUTOMATIC: m_colorBar->resetSizeAttributes(); break; case AnnotationColorBarPositionModeEnum::MANUAL: break; } EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } updateContentPrivate(); } /** * Gets called when a coordinate space combo box item is selected. */ void MapSettingsColorBarWidget::annotationCoordinateSpaceEnumComboBoxItemActivated() { const AnnotationCoordinateSpaceEnum::Enum coordinateSpace = m_annotationCoordinateSpaceEnumComboBox->getSelectedItem(); if (m_colorBar != NULL) { m_colorBar->setCoordinateSpace(coordinateSpace); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } QWidget* MapSettingsColorBarWidget::createLocationPositionSection() { QLabel* positionModeLabel = new QLabel("Positioning"); m_annotationColorBarPositionModeEnumComboBox = new EnumComboBoxTemplate(this); m_annotationColorBarPositionModeEnumComboBox->setup(); QObject::connect(m_annotationColorBarPositionModeEnumComboBox, SIGNAL(itemActivated()), this, SLOT(annotationColorBarPositionModeEnumComboBoxItemActivated())); m_annotationColorBarPositionModeEnumComboBox->getWidget()->setToolTip("AUTOMATIC - color bars are stacked\n" " in lower left corner of Tab/Window\n" "MANUAL - user must set the X and Y\n" " coordinates in the Tab/Window\n"); std::vector supportedSpaces; supportedSpaces.push_back(AnnotationCoordinateSpaceEnum::TAB); supportedSpaces.push_back(AnnotationCoordinateSpaceEnum::WINDOW); QLabel* coordinateSpaceLabel = new QLabel("Show Color Bar in "); m_annotationCoordinateSpaceEnumComboBox = new EnumComboBoxTemplate(this); m_annotationCoordinateSpaceEnumComboBox->setupWithItems(supportedSpaces); QObject::connect(m_annotationCoordinateSpaceEnumComboBox, SIGNAL(itemActivated()), this, SLOT(annotationCoordinateSpaceEnumComboBoxItemActivated())); m_annotationCoordinateSpaceEnumComboBox->getWidget()->setToolTip("TAB - Restricts location of colorbar\n" " to within its respective tab's\n" " region in the graphics area\n" "WINDOW - Allows colorbar in any\n" " location in the graphics area"); QWidget* modeSpaceWidget = new QWidget(); QGridLayout* modeSpaceLayout = new QGridLayout(modeSpaceWidget); modeSpaceLayout->setContentsMargins(0, 0, 0, 0); modeSpaceLayout->addWidget(coordinateSpaceLabel, 0, 0); modeSpaceLayout->addWidget(m_annotationCoordinateSpaceEnumComboBox->getWidget(), 0, 1); modeSpaceLayout->addWidget(positionModeLabel, 1, 0); modeSpaceLayout->addWidget(m_annotationColorBarPositionModeEnumComboBox->getWidget(), 1, 1); QGroupBox* locationAndDimGroupBox = new QGroupBox("Location and Positioning"); QVBoxLayout* locationAndDimLayout = new QVBoxLayout(locationAndDimGroupBox); locationAndDimLayout->setContentsMargins(0, 0, 0, 0); locationAndDimLayout->setSpacing(2); locationAndDimLayout->addWidget(modeSpaceWidget, 0, Qt::AlignLeft); locationAndDimGroupBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); return locationAndDimGroupBox; } /** * @return Create the color bar section. */ QWidget* MapSettingsColorBarWidget::createDataNumericsSection() { QLabel* valuesModeLabel = new QLabel("Data Mode"); m_colorBarDataModeComboBox = new EnumComboBoxTemplate(this); QObject::connect(m_colorBarDataModeComboBox, SIGNAL(itemActivated()), this, SLOT(colorBarItemActivated())); m_colorBarDataModeComboBox->setup(); m_colorBarDataModeComboBox->getWidget()->setToolTip("Format of numbers above color bar\n" " DATA: Numbers show mapping of data to the colobar\n" " PERCENTILE: Numbers show data percentiles\n" " SIGN ONLY: Text above colorbar indicates sign of data"); m_colorBarNumericFormatModeLabel = new QLabel("Numeric Format"); m_colorBarNumericFormatModeComboBox = new EnumComboBoxTemplate(this); QObject::connect(m_colorBarNumericFormatModeComboBox, SIGNAL(itemActivated()), this, SLOT(colorBarItemActivated())); m_colorBarNumericFormatModeComboBox->setup(); m_colorBarNumericFormatModeComboBox->getWidget()->setToolTip("Format of numbers above color bar\n" " AUTO: Format (decimal or scientific notation)\n" " and precision digits are automatically\n" " generated by examination of the data\n" " DECIMAL: Format as decimal number with the\n" " selected precision\n" " SCIENTIFIC: Format as scientific notation\n" " with the selected precision in the\n" " significand"); m_colorBarDecimalsLabel = new QLabel("Dec/Sci Decimals"); //Precision Digits"); m_colorBarDecimalsSpinBox = new QSpinBox(); m_colorBarDecimalsSpinBox->setMinimum(0); m_colorBarDecimalsSpinBox->setMaximum(100); m_colorBarDecimalsSpinBox->setSingleStep(1); QObject::connect(m_colorBarDecimalsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(applySelections())); m_colorBarDecimalsSpinBox->setToolTip("Number of digits right of the decimal point\n" "in the numbers above the color bar when format\n" "is " + NumericFormatModeEnum::toGuiName(NumericFormatModeEnum::DECIMAL) + " or " + NumericFormatModeEnum::toGuiName(NumericFormatModeEnum::SCIENTIFIC)); m_colorBarNumericSubdivisionsLabel = new QLabel("Subdivisions"); m_colorBarNumericSubdivisionsSpinBox = new QSpinBox(); m_colorBarNumericSubdivisionsSpinBox->setMinimum(0); m_colorBarNumericSubdivisionsSpinBox->setMaximum(100); m_colorBarNumericSubdivisionsSpinBox->setSingleStep(1); QObject::connect(m_colorBarNumericSubdivisionsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(applySelections())); m_colorBarNumericSubdivisionsSpinBox->setToolTip("Adds additional numbers to the negative\n" "and positive regions in the color bar"); m_showTickMarksCheckBox = new QCheckBox("Show Tick Marks"); QObject::connect(m_showTickMarksCheckBox, SIGNAL(clicked(bool)), this, SLOT(applySelections())); QGroupBox* colorBarGroupBox = new QGroupBox("Data Numerics"); QGridLayout* gridLayout = new QGridLayout(colorBarGroupBox); int row = gridLayout->rowCount(); // this->setLayoutSpacingAndMargins(gridLayout); gridLayout->addWidget(valuesModeLabel, row, 0); gridLayout->addWidget(m_colorBarDataModeComboBox->getWidget(), row, 1); row++; gridLayout->addWidget(m_colorBarNumericFormatModeLabel, row, 0); gridLayout->addWidget(m_colorBarNumericFormatModeComboBox->getWidget(), row, 1); row++; gridLayout->addWidget(m_colorBarDecimalsLabel, row, 0); gridLayout->addWidget(m_colorBarDecimalsSpinBox, row, 1); row++; gridLayout->addWidget(m_colorBarNumericSubdivisionsLabel, row, 0); gridLayout->addWidget(m_colorBarNumericSubdivisionsSpinBox, row, 1); row++; gridLayout->addWidget(m_showTickMarksCheckBox, row, 0, 1, 2, Qt::AlignLeft); colorBarGroupBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); return colorBarGroupBox; } /** * Gets called when a color bar item is selected. */ void MapSettingsColorBarWidget::colorBarItemActivated() { applySelections(); updateColorBarAttributes(); } /** * Update the colorbar attributes section. */ void MapSettingsColorBarWidget::updateColorBarAttributes() { if (m_paletteColorMapping != NULL) { bool numericForatComboBoxEnabled = true; bool precisionDigitsSpinBoxEnabled = true; bool subdivisionsSpinBoxEnabled = true; const PaletteColorBarValuesModeEnum::Enum valuesMode = m_paletteColorMapping->getColorBarValuesMode(); switch (valuesMode) { case PaletteColorBarValuesModeEnum::DATA: break; case PaletteColorBarValuesModeEnum::PERCENTILE: break; case PaletteColorBarValuesModeEnum::SIGN_ONLY: numericForatComboBoxEnabled = false; precisionDigitsSpinBoxEnabled = false; subdivisionsSpinBoxEnabled = false; break; } const NumericFormatModeEnum::Enum numericFormat = m_paletteColorMapping->getColorBarNumericFormatMode(); switch (numericFormat) { case NumericFormatModeEnum::AUTO: precisionDigitsSpinBoxEnabled = false; break; case NumericFormatModeEnum::DECIMAL: break; case NumericFormatModeEnum::SCIENTIFIC: break; } m_colorBarDataModeComboBox->setSelectedItem(valuesMode); m_colorBarNumericFormatModeLabel->setEnabled(numericForatComboBoxEnabled); m_colorBarNumericFormatModeComboBox->setSelectedItem(numericFormat); m_colorBarNumericFormatModeComboBox->getWidget()->setEnabled(numericForatComboBoxEnabled); m_colorBarDecimalsLabel->setEnabled(precisionDigitsSpinBoxEnabled); m_colorBarDecimalsSpinBox->blockSignals(true); m_colorBarDecimalsSpinBox->setValue(m_paletteColorMapping->getColorBarPrecisionDigits()); m_colorBarDecimalsSpinBox->blockSignals(false); m_colorBarDecimalsSpinBox->setEnabled(precisionDigitsSpinBoxEnabled); m_colorBarNumericSubdivisionsLabel->setEnabled(subdivisionsSpinBoxEnabled); m_colorBarNumericSubdivisionsSpinBox->blockSignals(true); m_colorBarNumericSubdivisionsSpinBox->setValue(m_paletteColorMapping->getColorBarNumericSubdivisionCount()); m_colorBarNumericSubdivisionsSpinBox->blockSignals(false); m_colorBarNumericSubdivisionsSpinBox->setEnabled(subdivisionsSpinBoxEnabled); m_showTickMarksCheckBox->setChecked(m_paletteColorMapping->isColorBarShowTickMarksSelected()); } } connectome-workbench-1.4.2/src/GuiQt/MapSettingsColorBarWidget.h000066400000000000000000000070341360521144700246560ustar00rootroot00000000000000#ifndef __MAP_SETTINGS_COLOR_BAR_WIDGET_H__ #define __MAP_SETTINGS_COLOR_BAR_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include class QCheckBox; class QLabel; class QSpinBox; namespace caret { class AnnotationColorBar; class CaretMappableDataFile; class EnumComboBoxTemplate; class MapSettingsColorBarPaletteOptionsWidget; class PaletteColorMapping; class Overlay; class MapSettingsColorBarWidget : public QWidget { Q_OBJECT public: MapSettingsColorBarWidget(QWidget* parent = 0); virtual ~MapSettingsColorBarWidget(); // void updateContent(Overlay* overlay); void updateContent(CaretMappableDataFile* caretMappableDataFile, const int32_t mapIndex, AnnotationColorBar* annotationColorBar, PaletteColorMapping* paletteColorMapping); // ADD_NEW_METHODS_HERE private slots: void applySelections(); void annotationColorBarPositionModeEnumComboBoxItemActivated(); void annotationCoordinateSpaceEnumComboBoxItemActivated(); void colorBarItemActivated(); private: MapSettingsColorBarWidget(const MapSettingsColorBarWidget&); MapSettingsColorBarWidget& operator=(const MapSettingsColorBarWidget&); QWidget* createDataNumericsSection(); QWidget* createLocationPositionSection(); void updateContentPrivate(); void updateColorBarAttributes(); CaretMappableDataFile* m_caretMappableDataFile = NULL; int32_t m_mapIndex = -1; AnnotationColorBar* m_colorBar; PaletteColorMapping* m_paletteColorMapping; EnumComboBoxTemplate* m_annotationColorBarPositionModeEnumComboBox; EnumComboBoxTemplate* m_annotationCoordinateSpaceEnumComboBox; EnumComboBoxTemplate* m_colorBarDataModeComboBox; QLabel* m_colorBarNumericFormatModeLabel; EnumComboBoxTemplate* m_colorBarNumericFormatModeComboBox; QLabel* m_colorBarDecimalsLabel; QSpinBox* m_colorBarDecimalsSpinBox; QLabel* m_colorBarNumericSubdivisionsLabel; QSpinBox* m_colorBarNumericSubdivisionsSpinBox; QCheckBox* m_showTickMarksCheckBox; MapSettingsColorBarPaletteOptionsWidget* m_paletteOptionsWidget; // ADD_NEW_MEMBERS_HERE }; #ifdef __MAP_SETTINGS_COLOR_BAR_WIDGET_DECLARE__ // #endif // __MAP_SETTINGS_COLOR_BAR_WIDGET_DECLARE__ } // namespace #endif //__MAP_SETTINGS_COLOR_BAR_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/MapSettingsFiberTrajectoryWidget.cxx000066400000000000000000000416101360521144700266220ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __MAP_SETTINGS_FIBER_TRAJECTORY_WIDGET_DECLARE__ #include "MapSettingsFiberTrajectoryWidget.h" #undef __MAP_SETTINGS_FIBER_TRAJECTORY_WIDGET_DECLARE__ #include #include #include #include #include #include #include #include #include #include "CiftiFiberTrajectoryFile.h" #include "EventManager.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventUserInterfaceUpdate.h" #include "FiberTrajectoryColorModel.h" #include "FiberTrajectoryMapProperties.h" #include "GuiManager.h" #include "WuQFactory.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::MapSettingsFiberTrajectoryWidget * \brief View/Controller for fiber trajectories * \ingroup GuiQt */ /** * Constructor. * @param browserWindowIndex * Index of browser window in which this view controller is displayed. * @param parent * Parent of this object. */ MapSettingsFiberTrajectoryWidget::MapSettingsFiberTrajectoryWidget(QWidget* parent) : QWidget(parent) { m_updateInProgress = true; QWidget* attributesWidget = createAttributesWidget(); QWidget* displayModeWidget = createDisplayModeWidget(); QWidget* dataMappingWidget = createDataMappingWidget(); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(attributesWidget, 0, Qt::AlignLeft); layout->addWidget(displayModeWidget, 0, Qt::AlignLeft); layout->addWidget(dataMappingWidget, 0, Qt::AlignLeft); layout->addStretch(); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } /** * Destructor. */ MapSettingsFiberTrajectoryWidget::~MapSettingsFiberTrajectoryWidget() { } QWidget* MapSettingsFiberTrajectoryWidget::createAttributesWidget() { QLabel* colorLabel = new QLabel("Coloring: "); m_colorSelectionComboBox = WuQFactory::newComboBoxSignalInt(this, SLOT(processAttributesChanges())); QGroupBox* attributesGroupBox = new QGroupBox("Attributes"); QGridLayout* attributesGridLayout = new QGridLayout(attributesGroupBox); int row = 0; attributesGridLayout->addWidget(colorLabel, row, 0); attributesGridLayout->addWidget(m_colorSelectionComboBox, row, 1); return attributesGroupBox; } /** * @return Create and return the display mode widget. */ QWidget* MapSettingsFiberTrajectoryWidget::createDisplayModeWidget() { m_displayModeButtonGroup = new QButtonGroup(this); QObject::connect(m_displayModeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(processAttributesChanges())); std::vector displayModes; FiberTrajectoryDisplayModeEnum::getAllEnums(displayModes); const int32_t numDisplayModes = static_cast(displayModes.size()); for (int32_t i = 0; i < numDisplayModes; i++) { const FiberTrajectoryDisplayModeEnum::Enum mode = displayModes[i]; QRadioButton* radioButton = new QRadioButton(FiberTrajectoryDisplayModeEnum::toGuiName(mode)); m_displayModeButtonGroup->addButton(radioButton, i); m_displayModeRadioButtons.push_back(radioButton); m_displayModeRadioButtonData.push_back(mode); } QGroupBox* modeGroupBox = new QGroupBox("Display Mode"); QVBoxLayout* modeGroupLayout = new QVBoxLayout(modeGroupBox); for (int32_t i = 0; i < numDisplayModes; i++) { modeGroupLayout->addWidget(m_displayModeRadioButtons[i]); } return modeGroupBox; } /** * @return Create and return the data mapping widget. */ QWidget* MapSettingsFiberTrajectoryWidget::createDataMappingWidget() { const int spinBoxWidth = 85; m_proportionStreamlineSpinBox = WuQFactory::newDoubleSpinBox(); m_proportionStreamlineSpinBox->setRange(0, std::numeric_limits::max()); m_proportionStreamlineSpinBox->setSingleStep(5); m_proportionStreamlineSpinBox->setFixedWidth(spinBoxWidth); m_proportionStreamlineSpinBox->setDecimals(3); m_proportionStreamlineSpinBox->setToolTip("A fiber is displayed only if the total number of its\n" "streamlines is greater than or equal to this value"); QObject::connect(m_proportionStreamlineSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); m_proportionMinimumSpinBox = WuQFactory::newDoubleSpinBox(); m_proportionMinimumSpinBox->setRange(0.0, 1.0); m_proportionMinimumSpinBox->setDecimals(3); m_proportionMinimumSpinBox->setSingleStep(0.05); m_proportionMinimumSpinBox->setFixedWidth(spinBoxWidth); m_proportionMinimumSpinBox->setToolTip("If the proportion for an axis is less than or equal\n" "to this value, the opacity will be zero (clear)"); QObject::connect(m_proportionMinimumSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); m_proportionMaximumSpinBox = WuQFactory::newDoubleSpinBox(); m_proportionMaximumSpinBox->setRange(0.0, 1.0); m_proportionMaximumSpinBox->setDecimals(3); m_proportionMaximumSpinBox->setSingleStep(0.05); m_proportionMaximumSpinBox->setFixedWidth(spinBoxWidth); m_proportionMaximumSpinBox->setToolTip("If the proportion for an axis is greater than or equal\n" "to this value, the opacity will be one (opaque)"); QObject::connect(m_proportionMaximumSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); m_countStreamlineSpinBox = WuQFactory::newDoubleSpinBox(); m_countStreamlineSpinBox->setRange(0, std::numeric_limits::max()); m_countStreamlineSpinBox->setDecimals(3); m_countStreamlineSpinBox->setSingleStep(5); m_countStreamlineSpinBox->setFixedWidth(spinBoxWidth); m_countStreamlineSpinBox->setToolTip("A fiber is displayed only if the total number of its\n" "streamlines is greater than or equal to this value"); QObject::connect(m_countStreamlineSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); m_countMinimumSpinBox = WuQFactory::newDoubleSpinBox(); m_countMinimumSpinBox->setRange(0, std::numeric_limits::max()); m_countMinimumSpinBox->setDecimals(3); m_countMinimumSpinBox->setSingleStep(5); m_countMinimumSpinBox->setFixedWidth(spinBoxWidth); m_countMinimumSpinBox->setToolTip("If the number of fibers for an axis is less than or equal\n" "to this value, the opacity will be zero (clear)"); QObject::connect(m_countMinimumSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); m_countMaximumSpinBox = WuQFactory::newDoubleSpinBox(); m_countMaximumSpinBox->setRange(0, std::numeric_limits::max()); m_countMaximumSpinBox->setDecimals(3); m_countMaximumSpinBox->setSingleStep(5); m_countMaximumSpinBox->setFixedWidth(spinBoxWidth); m_countMaximumSpinBox->setToolTip("If the number of fibers for an axis is greater than or equal\n" "to this value, the opacity will be one (opaque)"); QObject::connect(m_countMaximumSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); m_distanceStreamlineSpinBox = WuQFactory::newDoubleSpinBox(); m_distanceStreamlineSpinBox->setRange(0, std::numeric_limits::max()); m_distanceStreamlineSpinBox->setDecimals(3); m_distanceStreamlineSpinBox->setSingleStep(5); m_distanceStreamlineSpinBox->setFixedWidth(spinBoxWidth); m_distanceStreamlineSpinBox->setToolTip("A fiber is displayed only if the total number of its\n" "streamlines is greater than or equal to this value"); QObject::connect(m_distanceStreamlineSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); m_distanceMinimumSpinBox = WuQFactory::newDoubleSpinBox(); m_distanceMinimumSpinBox->setRange(0, std::numeric_limits::max()); m_distanceMinimumSpinBox->setDecimals(3); m_distanceMinimumSpinBox->setSingleStep(5); m_distanceMinimumSpinBox->setFixedWidth(spinBoxWidth); m_distanceMinimumSpinBox->setToolTip("If count times distance for an axis is less than or equal\n" "to this value, the opacity will be zero (clear)"); QObject::connect(m_distanceMinimumSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); m_distanceMaximumSpinBox = WuQFactory::newDoubleSpinBox(); m_distanceMaximumSpinBox->setRange(0, std::numeric_limits::max()); m_distanceMaximumSpinBox->setDecimals(3); m_distanceMaximumSpinBox->setSingleStep(5); m_distanceMaximumSpinBox->setFixedWidth(spinBoxWidth); m_distanceMaximumSpinBox->setToolTip("If the count times distance for an axis is greater than or equal\n" "to this value, the opacity will be one (opaque)"); QObject::connect(m_distanceMaximumSpinBox, SIGNAL(valueChanged(double)), this, SLOT(processAttributesChanges())); QGroupBox* dataMappingGroupBox = new QGroupBox("Data Mapping"); QGridLayout* dataMappingLayout = new QGridLayout(dataMappingGroupBox); WuQtUtilities::setLayoutSpacingAndMargins(dataMappingLayout, 4, 2); int row = dataMappingLayout->rowCount(); int columnCounter = 0; const int COLUMN_LABELS = columnCounter++; const int COLUMN_THRESHOLD = columnCounter++; const int COLUMN_MINIMUM = columnCounter++; const int COLUMN_MAXIMUM = columnCounter++; dataMappingLayout->addWidget(new QLabel("Display
    Mode"), row, COLUMN_LABELS, Qt::AlignLeft); dataMappingLayout->addWidget(new QLabel("Streamline
    Threshold"), row, COLUMN_THRESHOLD, Qt::AlignLeft); dataMappingLayout->addWidget(new QLabel("Map to
    Clear"), row, COLUMN_MINIMUM, Qt::AlignLeft); dataMappingLayout->addWidget(new QLabel("Map to
    Opaque"), row, COLUMN_MAXIMUM, Qt::AlignLeft); row++; dataMappingLayout->addWidget(new QLabel("Absolute"), row, COLUMN_LABELS, Qt::AlignHCenter); dataMappingLayout->addWidget(m_countStreamlineSpinBox, row, COLUMN_THRESHOLD, Qt::AlignHCenter); dataMappingLayout->addWidget(m_countMinimumSpinBox, row, COLUMN_MINIMUM, Qt::AlignHCenter); dataMappingLayout->addWidget(m_countMaximumSpinBox, row, COLUMN_MAXIMUM, Qt::AlignHCenter); row++; dataMappingLayout->addWidget(new QLabel("Distance"), row, COLUMN_LABELS, Qt::AlignHCenter); dataMappingLayout->addWidget(m_distanceStreamlineSpinBox, row, COLUMN_THRESHOLD, Qt::AlignHCenter); dataMappingLayout->addWidget(m_distanceMinimumSpinBox, row, COLUMN_MINIMUM, Qt::AlignHCenter); dataMappingLayout->addWidget(m_distanceMaximumSpinBox, row, COLUMN_MAXIMUM, Qt::AlignHCenter); row++; dataMappingLayout->addWidget(new QLabel("Proportion"), row, COLUMN_LABELS, Qt::AlignHCenter); dataMappingLayout->addWidget(m_proportionStreamlineSpinBox, row, COLUMN_THRESHOLD, Qt::AlignHCenter); dataMappingLayout->addWidget(m_proportionMinimumSpinBox, row, COLUMN_MINIMUM, Qt::AlignHCenter); dataMappingLayout->addWidget(m_proportionMaximumSpinBox, row, COLUMN_MAXIMUM, Qt::AlignHCenter); row++; return dataMappingGroupBox; } /** * Called when a widget on the attributes page has * its value changed. */ void MapSettingsFiberTrajectoryWidget::processAttributesChanges() { if (m_updateInProgress) { return; } if (m_fiberTrajectoryFile == NULL) { return; } FiberTrajectoryMapProperties* ftmp = m_fiberTrajectoryFile->getFiberTrajectoryMapProperties(); const int32_t selectedColorIndex = m_colorSelectionComboBox->currentIndex(); if (selectedColorIndex >= 0) { void* ptr = m_colorSelectionComboBox->itemData(selectedColorIndex, Qt::UserRole).value(); const FiberTrajectoryColorModel::Item* item = (FiberTrajectoryColorModel::Item*)ptr; ftmp->getFiberTrajectoryColorModel()->setSelectedItem(item); } const int32_t selectedModeRadioButtonIndex = m_displayModeButtonGroup->checkedId(); const FiberTrajectoryDisplayModeEnum::Enum displayMode = m_displayModeRadioButtonData[selectedModeRadioButtonIndex]; ftmp->setDisplayMode(displayMode); ftmp->setProportionStreamline(m_proportionStreamlineSpinBox->value());; ftmp->setProportionMinimumOpacity(m_proportionMinimumSpinBox->value()); ftmp->setProportionMaximumOpacity(m_proportionMaximumSpinBox->value()); ftmp->setCountStreamline(m_countStreamlineSpinBox->value()); ftmp->setCountMaximumOpacity(m_countMaximumSpinBox->value()); ftmp->setCountMinimumOpacity(m_countMinimumSpinBox->value()); ftmp->setDistanceStreamline(m_distanceStreamlineSpinBox->value()); ftmp->setDistanceMaximumOpacity(m_distanceMaximumSpinBox->value()); ftmp->setDistanceMinimumOpacity(m_distanceMinimumSpinBox->value()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Update with the given fiber trajectory file. */ void MapSettingsFiberTrajectoryWidget::updateEditor(CiftiFiberTrajectoryFile* fiberTrajectoryFile) { m_fiberTrajectoryFile = fiberTrajectoryFile; if (m_fiberTrajectoryFile == NULL) { return; } m_updateInProgress = true; FiberTrajectoryMapProperties* ftmp = m_fiberTrajectoryFile->getFiberTrajectoryMapProperties(); FiberTrajectoryColorModel* colorModel = ftmp->getFiberTrajectoryColorModel(); std::vector colorItems = colorModel->getValidItems(); const FiberTrajectoryColorModel::Item* selectedItem = colorModel->getSelectedItem(); const int32_t numColorItems = static_cast(colorItems.size()); m_colorSelectionComboBox->blockSignals(true); m_colorSelectionComboBox->clear(); int32_t defaultIndex = 0; for (int32_t i = 0; i < numColorItems; i++) { FiberTrajectoryColorModel::Item* item = colorItems[i]; if (item == selectedItem) { defaultIndex = i; } m_colorSelectionComboBox->addItem(item->getName(), qVariantFromValue((void*)item)); } if ((defaultIndex >= 0) && (defaultIndex < m_colorSelectionComboBox->count())) { m_colorSelectionComboBox->setCurrentIndex(defaultIndex); } m_colorSelectionComboBox->blockSignals(false); const FiberTrajectoryDisplayModeEnum::Enum selectedDisplayMode = ftmp->getDisplayMode(); const int32_t numDisplayModeRadioButtons = m_displayModeButtonGroup->buttons().size(); for (int32_t i = 0; i < numDisplayModeRadioButtons; i++) { if (m_displayModeRadioButtonData[i] == selectedDisplayMode) { m_displayModeRadioButtons[i]->setChecked(true); break; } } /* * Update the attributes */ m_proportionStreamlineSpinBox->setValue(ftmp->getProportionStreamline()); m_proportionMaximumSpinBox->setValue(ftmp->getProportionMaximumOpacity()); m_proportionMinimumSpinBox->setValue(ftmp->getProportionMinimumOpacity()); m_countStreamlineSpinBox->setValue(ftmp->getCountStreamline()); m_countMaximumSpinBox->setValue(ftmp->getCountMaximumOpacity()); m_countMinimumSpinBox->setValue(ftmp->getCountMinimumOpacity()); m_distanceStreamlineSpinBox->setValue(ftmp->getDistanceStreamline()); m_distanceMaximumSpinBox->setValue(ftmp->getDistanceMaximumOpacity()); m_distanceMinimumSpinBox->setValue(ftmp->getDistanceMinimumOpacity()); m_updateInProgress = false; } /** * Update the fiber trajectory widget. */ void MapSettingsFiberTrajectoryWidget::updateWidget() { updateEditor(m_fiberTrajectoryFile); } connectome-workbench-1.4.2/src/GuiQt/MapSettingsFiberTrajectoryWidget.h000066400000000000000000000061141360521144700262470ustar00rootroot00000000000000#ifndef __MAP_SETTINGS_FIBER_TRAJECTORY_WIDGET__H_ #define __MAP_SETTINGS_FIBER_TRAJECTORY_WIDGET__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "FiberTrajectoryDisplayModeEnum.h" class QButtonGroup; class QComboBox; class QDoubleSpinBox; class QRadioButton; namespace caret { class CaretMappableDataFile; class CiftiFiberTrajectoryFile; class MapSettingsFiberTrajectoryWidget : public QWidget { Q_OBJECT public: MapSettingsFiberTrajectoryWidget(QWidget* parent = 0); virtual ~MapSettingsFiberTrajectoryWidget(); void updateEditor(CiftiFiberTrajectoryFile* fiberTrajectoryFile); void updateWidget(); // ADD_NEW_METHODS_HERE private slots: void processAttributesChanges(); private: MapSettingsFiberTrajectoryWidget(const MapSettingsFiberTrajectoryWidget&); MapSettingsFiberTrajectoryWidget& operator=(const MapSettingsFiberTrajectoryWidget&); QWidget* createAttributesWidget(); QWidget* createDisplayModeWidget(); QWidget* createDataMappingWidget(); CiftiFiberTrajectoryFile* m_fiberTrajectoryFile; QComboBox* m_colorSelectionComboBox; std::vector m_displayModeRadioButtons; std::vector m_displayModeRadioButtonData; QButtonGroup* m_displayModeButtonGroup; QDoubleSpinBox* m_proportionStreamlineSpinBox; QDoubleSpinBox* m_proportionMinimumSpinBox; QDoubleSpinBox* m_proportionMaximumSpinBox; QDoubleSpinBox* m_countStreamlineSpinBox; QDoubleSpinBox* m_countMinimumSpinBox; QDoubleSpinBox* m_countMaximumSpinBox; QDoubleSpinBox* m_distanceStreamlineSpinBox; QDoubleSpinBox* m_distanceMinimumSpinBox; QDoubleSpinBox* m_distanceMaximumSpinBox; bool m_updateInProgress; // ADD_NEW_MEMBERS_HERE }; #ifdef __MAP_SETTINGS_FIBER_TRAJECTORY_WIDGET_DECLARE__ #endif // __MAP_SETTINGS_FIBER_TRAJECTORY_WIDGET_DECLARE__ } // namespace #endif //__MAP_SETTINGS_FIBER_TRAJECTORY_WIDGET__H_ connectome-workbench-1.4.2/src/GuiQt/MapSettingsLabelsWidget.cxx000066400000000000000000000167471360521144700247430ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __MAP_SETTINGS_LABELS_WIDGET_DECLARE__ #include "MapSettingsLabelsWidget.h" #undef __MAP_SETTINGS_LABELS_WIDGET_DECLARE__ #include #include #include #include #include #include "CaretAssert.h" #include "CaretColorEnumComboBox.h" #include "CaretMappableDataFile.h" #include "EnumComboBoxTemplate.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventSurfaceColoringInvalidate.h" #include "GiftiLabelTableEditor.h" #include "LabelDrawingTypeEnum.h" #include "LabelDrawingProperties.h" #include "Overlay.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::MapSettingsLabelsWidget * \brief Labels page for overlay and map settings. * \ingroup GuiQt */ /** * Constructor. */ MapSettingsLabelsWidget::MapSettingsLabelsWidget(QWidget* parent) : QWidget(parent) { QLabel* drawingTypeLabel = new QLabel("Drawing Type"); m_drawingTypeComboBox = new EnumComboBoxTemplate(this); m_drawingTypeComboBox->setup(); QObject::connect(m_drawingTypeComboBox, SIGNAL(itemActivated()), this, SLOT(applySelections())); QLabel* outlineColorLabel = new QLabel("Outline Color"); m_outlineColorComboBox = new CaretColorEnumComboBox(this); QObject::connect(m_outlineColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), this, SLOT(applySelections())); m_drawMedialWallFilledCheckBox = new QCheckBox("Draw Surface Medial Wall Filled"); QObject::connect(m_drawMedialWallFilledCheckBox, SIGNAL(clicked(bool)), this, SLOT(applySelections())); m_drawMedialWallFilledCheckBox->setToolTip(WuQtUtilities::createWordWrappedToolTipText("When an outline type drawing is selected and if the " "selected map contains vertices identified as the " "'medial wall', checking this option will fill the medial " "wall vertices.")); QPushButton* editLabelsPushButton = new QPushButton("Edit Map's Labels"); QObject::connect(editLabelsPushButton, SIGNAL(clicked()), this, SLOT(editLabelTablePushButtonClicked())); editLabelsPushButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); QWidget* gridWidget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(gridWidget); gridLayout->addWidget(drawingTypeLabel, 0, 0); gridLayout->addWidget(m_drawingTypeComboBox->getWidget(), 0, 1); gridLayout->addWidget(outlineColorLabel, 1, 0); gridLayout->addWidget(m_outlineColorComboBox->getWidget(), 1, 1); gridLayout->addWidget(m_drawMedialWallFilledCheckBox, 2, 0, 1, 2, Qt::AlignLeft); gridLayout->addWidget(editLabelsPushButton, 3, 0, 1, 2, Qt::AlignLeft); gridWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(gridWidget); layout->addStretch(); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } /** * Destructor. */ MapSettingsLabelsWidget::~MapSettingsLabelsWidget() { } /** * Update the content of widget. * * @param overlay * Overlay for display in this widget. */ void MapSettingsLabelsWidget::updateContent(Overlay* overlay) { m_overlay = overlay; bool enableWidget = false; if (m_overlay != NULL) { CaretMappableDataFile* mapFile = NULL; int32_t mapIndex = -1; m_overlay->getSelectionData(mapFile, mapIndex); if (mapFile != NULL) { if (mapFile->isMappedWithLabelTable()) { const LabelDrawingProperties* labelProps = mapFile->getLabelDrawingProperties(); m_drawingTypeComboBox->setSelectedItem(labelProps->getDrawingType()); m_outlineColorComboBox->setSelectedColor(labelProps->getOutlineColor()); m_drawMedialWallFilledCheckBox->setChecked(labelProps->isDrawMedialWallFilled()); m_drawMedialWallFilledCheckBox->setEnabled(mapFile->isMedialWallLabelInMapLabelTable(mapIndex)); enableWidget = true; } } } setEnabled(enableWidget); } /** * Called when a control is changed. */ void MapSettingsLabelsWidget::applySelections() { if (m_overlay != NULL) { CaretMappableDataFile* mapFile = NULL; int32_t mapIndex = -1; m_overlay->getSelectionData(mapFile, mapIndex); if (mapFile != NULL) { if (mapFile->isMappedWithLabelTable()) { const LabelDrawingTypeEnum::Enum drawType = m_drawingTypeComboBox->getSelectedItem(); const CaretColorEnum::Enum outlineColor = m_outlineColorComboBox->getSelectedColor(); LabelDrawingProperties* labelProps = mapFile->getLabelDrawingProperties(); labelProps->setDrawingType(drawType); labelProps->setOutlineColor(outlineColor); labelProps->setDrawMedialWallFilled(m_drawMedialWallFilledCheckBox->isChecked()); EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } } } /** * Called when the edit label table button is clicked. */ void MapSettingsLabelsWidget::editLabelTablePushButtonClicked() { if (m_overlay != NULL) { CaretMappableDataFile* mapFile = NULL; int32_t mapIndex = -1; m_overlay->getSelectionData(mapFile, mapIndex); if (mapFile != NULL) { if (mapFile->isMappedWithLabelTable()) { if (mapIndex >= 0) { GiftiLabelTableEditor labelTableEditor(mapFile, mapIndex, "Edit Labels", GiftiLabelTableEditor::OPTION_ADD_APPLY_BUTTON, this); labelTableEditor.exec(); } } } } } connectome-workbench-1.4.2/src/GuiQt/MapSettingsLabelsWidget.h000066400000000000000000000041061360521144700243520ustar00rootroot00000000000000#ifndef __MAP_SETTINGS_LABELS_WIDGET_H__ #define __MAP_SETTINGS_LABELS_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include class QCheckBox; namespace caret { class CaretColorEnumComboBox; class EnumComboBoxTemplate; class Overlay; class MapSettingsLabelsWidget : public QWidget { Q_OBJECT public: MapSettingsLabelsWidget(QWidget* parent = 0); virtual ~MapSettingsLabelsWidget(); void updateContent(Overlay* overlay); private slots: void applySelections(); void editLabelTablePushButtonClicked(); // ADD_NEW_METHODS_HERE private: MapSettingsLabelsWidget(const MapSettingsLabelsWidget&); MapSettingsLabelsWidget& operator=(const MapSettingsLabelsWidget&); // ADD_NEW_MEMBERS_HERE Overlay* m_overlay; CaretColorEnumComboBox* m_outlineColorComboBox; EnumComboBoxTemplate* m_drawingTypeComboBox; QCheckBox* m_drawMedialWallFilledCheckBox; }; #ifdef __MAP_SETTINGS_LABELS_WIDGET_DECLARE__ // #endif // __MAP_SETTINGS_LABELS_WIDGET_DECLARE__ } // namespace #endif //__MAP_SETTINGS_LABELS_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/MapSettingsLayerWidget.cxx000066400000000000000000000111631360521144700246000ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __MAP_SETTINGS_LAYER_WIDGET_DECLARE__ #include "MapSettingsLayerWidget.h" #undef __MAP_SETTINGS_LAYER_WIDGET_DECLARE__ #include #include #include #include #include #include "CaretMappableDataFile.h" #include "EnumComboBoxTemplate.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventSurfaceColoringInvalidate.h" #include "Overlay.h" #include "VolumeMappableInterface.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::MapSettingsLayerWidget * \brief Contains user-interface components for overlay parameters. * \ingroup GuiQt */ /** * Constructor. */ MapSettingsLayerWidget::MapSettingsLayerWidget(QWidget* parent) : QWidget(parent) { QLabel* wholeBrainVoxelDrawingModeLabel = new QLabel("Voxel Drawing Mode"); m_wholeBrainVoxelDrawingModeComboBox = new EnumComboBoxTemplate(this); m_wholeBrainVoxelDrawingModeComboBox->setup(); QObject::connect(m_wholeBrainVoxelDrawingModeComboBox, SIGNAL(itemActivated()), this, SLOT(applySelections())); const AString warningText("Drawing voxels in Whole Brain view with 3D cubes can be very slow " "and should only be used with a volume that displays a limited number " "of voxels. One example is a label volume that identifies subcortical " "structures. Another example is a functional volume that is thresholded " "so that a small number of voxels are displayed. 3D cubes should never " "be used with anatomical volumes."); // QLabel* voxelWarningLabel = new QLabel(WuQtUtilities::createWordWrappedToolTipText(warningText)); QLabel* voxelWarningLabel = new QLabel(warningText); voxelWarningLabel->setWordWrap(true); QGroupBox* wholeBraingroupBox = new QGroupBox("Whole Brain"); wholeBraingroupBox->setFlat(true); QGridLayout* wholeBrainGridLayout = new QGridLayout(wholeBraingroupBox); wholeBrainGridLayout->addWidget(wholeBrainVoxelDrawingModeLabel, 0, 0); wholeBrainGridLayout->addWidget(m_wholeBrainVoxelDrawingModeComboBox->getWidget(), 0, 1); wholeBrainGridLayout->addWidget(voxelWarningLabel, 1, 0, 1, 2); wholeBraingroupBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(wholeBraingroupBox); layout->addStretch(); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } /** * Destructor. */ MapSettingsLayerWidget::~MapSettingsLayerWidget() { } /** * Update the content of widget. * * @param overlay * Overlay for display in this widget. */ void MapSettingsLayerWidget::updateContent(Overlay* overlay) { m_overlay = overlay; bool enableWidget = false; if (m_overlay != NULL) { m_wholeBrainVoxelDrawingModeComboBox->setSelectedItem(m_overlay->getWholeBrainVoxelDrawingMode()); enableWidget = true; } setEnabled(enableWidget); } /** * Called when a control is changed. */ void MapSettingsLayerWidget::applySelections() { const WholeBrainVoxelDrawingMode::Enum wholeBrainVoxelDrawingMode = m_wholeBrainVoxelDrawingModeComboBox->getSelectedItem(); if (m_overlay != NULL) { m_overlay->setWholeBrainVoxelDrawingMode(wholeBrainVoxelDrawingMode); } EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } connectome-workbench-1.4.2/src/GuiQt/MapSettingsLayerWidget.h000066400000000000000000000036071360521144700242310ustar00rootroot00000000000000#ifndef __MAP_SETTINGS_LAYER_WIDGET_H__ #define __MAP_SETTINGS_LAYER_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include class QPushButton; namespace caret { class EnumComboBoxTemplate; class Overlay; class MapSettingsLayerWidget : public QWidget { Q_OBJECT public: MapSettingsLayerWidget(QWidget* parent = 0); virtual ~MapSettingsLayerWidget(); void updateContent(Overlay* overlay); private slots: void applySelections(); private: MapSettingsLayerWidget(const MapSettingsLayerWidget&); MapSettingsLayerWidget& operator=(const MapSettingsLayerWidget&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE Overlay* m_overlay; EnumComboBoxTemplate* m_wholeBrainVoxelDrawingModeComboBox; }; #ifdef __MAP_SETTINGS_LAYER_WIDGET_DECLARE__ // #endif // __MAP_SETTINGS_LAYER_WIDGET_DECLARE__ } // namespace #endif //__MAP_SETTINGS_LAYER_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/MapSettingsPaletteColorMappingWidget.cxx000066400000000000000000003606721360521144700274510ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define __MAP_SETTINGS_PALETTE_COLOR_MAPPING_WIDGET_DECLARE__ #include "MapSettingsPaletteColorMappingWidget.h" #undef __MAP_SETTINGS_PALETTE_COLOR_MAPPING_WIDGET_DECLARE__ #include "Brain.h" #include "CaretColorEnumComboBox.h" #include "CaretMappableDataFile.h" #include "CaretMappableDataFileAndMapSelectorObject.h" #include "CopyPaletteColorMappingToFilesDialog.h" #include "CursorDisplayScoped.h" #include "EnumComboBoxTemplate.h" #include "EventCaretMappableDataFilesGet.h" #include "EventManager.h" #include "FastStatistics.h" #include "GuiManager.h" #include "Histogram.h" #include "MapSettingsColorBarPaletteOptionsWidget.h" #include "MathFunctions.h" #include "NodeAndVoxelColoring.h" #include "NumericTextFormatting.h" #include "Palette.h" #include "PaletteColorMapping.h" #include "PaletteFile.h" #include "ThresholdingSetMapsDialog.h" #include "VolumeFile.h" #include "WuQWidgetObjectGroup.h" #include "WuQDoubleSlider.h" #include "WuQDoubleSpinBox.h" #include "WuQFactory.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" #include "WuQwtPlot.h" #include "qwt_plot_curve.h" #include "qwt_plot_histogram.h" #include "qwt_plot_intervalcurve.h" #include "qwt_plot_layout.h" #include "PlotMagnifier.h" #include "PlotPanner.h" using namespace caret; /* The QSlider uses integer for min/max so use max-int / 4 (approximately) */ static const int32_t BIG_NUMBER = 500000000; /** * \class caret::MapSettingsScalarDataEditorDialog * \brief Dialog for editing scalar data map settings * \ingroup GuiQt * * Presents controls for setting palettes, and thresholding used to color * scalar data. */ /** * Constructor for editing a palette selection. * * @param parent * Parent widget on which this dialog is displayed. */ MapSettingsPaletteColorMappingWidget::MapSettingsPaletteColorMappingWidget(QWidget* parent) : QWidget(parent) { /* * No context menu, it screws things up * but one is used on the histogram plot */ this->setContextMenuPolicy(Qt::NoContextMenu); this->caretMappableDataFile = NULL; this->mapFileIndex = -1; this->paletteWidgetGroup = new WuQWidgetObjectGroup(this); this->thresholdWidgetGroup = new WuQWidgetObjectGroup(this); this->paletteColorMapping = NULL; QWidget* histogramWidget = this->createHistogramSection(); QWidget* histogramControlWidget = this->createHistogramControlSection(); m_paletteOptionsWidget = new MapSettingsColorBarPaletteOptionsWidget(); QWidget* normalizationWidget = this->createNormalizationControlSection(); QWidget* paletteWidget = this->createPaletteSection(); QWidget* thresholdWidget = this->createThresholdSection(); thresholdWidget->setMaximumWidth(paletteWidget->sizeHint().width() + 50); QWidget* leftWidget = new QWidget(); QVBoxLayout* leftLayout = new QVBoxLayout(leftWidget); this->setLayoutSpacingAndMargins(leftLayout); leftLayout->addWidget(thresholdWidget); leftLayout->addWidget(paletteWidget); QVBoxLayout* dataLayout = new QVBoxLayout(); dataLayout->addWidget(normalizationWidget); dataLayout->addWidget(m_paletteOptionsWidget); QWidget* bottomRightWidget = new QWidget(); QHBoxLayout* bottomRightLayout = new QHBoxLayout(bottomRightWidget); this->setLayoutSpacingAndMargins(bottomRightLayout); bottomRightLayout->addWidget(histogramControlWidget); bottomRightLayout->addLayout(dataLayout); bottomRightLayout->addStretch(); bottomRightWidget->setFixedHeight(bottomRightWidget->sizeHint().height()); QWidget* rightWidget = new QWidget(); QVBoxLayout* rightLayout = new QVBoxLayout(rightWidget); this->setLayoutSpacingAndMargins(rightLayout); rightLayout->addWidget(histogramWidget, 100); rightLayout->addWidget(bottomRightWidget, 0); rightWidget->setFixedHeight(leftWidget->sizeHint().height()); QHBoxLayout* layout = new QHBoxLayout(this); this->setLayoutSpacingAndMargins(layout); layout->addWidget(leftWidget, 0); layout->addWidget(rightWidget, 100); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } /** * Destructor. */ MapSettingsPaletteColorMappingWidget::~MapSettingsPaletteColorMappingWidget() { } /** * May be called to update the widget's content. */ void MapSettingsPaletteColorMappingWidget::updateWidget() { this->updateEditorInternal(this->caretMappableDataFile, this->mapFileIndex); } /** * Called when the threshold type is changed. */ void MapSettingsPaletteColorMappingWidget::thresholdTypeChanged(int indx) { PaletteThresholdTypeEnum::Enum paletteThresholdType = static_cast(this->thresholdTypeComboBox->itemData(indx).toInt()); this->paletteColorMapping->setThresholdType(paletteThresholdType); this->updateEditorInternal(this->caretMappableDataFile, this->mapFileIndex); this->applySelections(); } /** * Called when set all maps is selected for thresholding */ void MapSettingsPaletteColorMappingWidget::thresholdSetAllMapsToolButtonClicked() { if (this->caretMappableDataFile->getNumberOfMaps() <= 1) { WuQMessageBox::errorOk(this, "Data file contains one map (must have more than one map for this option)"); return; } CaretMappableDataFile* threshFile = this->thresholdMapFileIndexSelector->getModel()->getSelectedFile(); if (threshFile == NULL) { WuQMessageBox::errorOk(this, "No thresholding file is selected"); return; } const int32_t threshFileNumberOfMaps = threshFile->getNumberOfMaps(); if (threshFileNumberOfMaps <= 0) { WuQMessageBox::errorOk(this, "Thresholding file contains no data"); return; } ThresholdingSetMapsDialog threshDialog(this->caretMappableDataFile, threshFile, (this->thresholdMapFileIndexSelector->getModel()->getSelectedMapIndex()), this); if (threshDialog.exec() == ThresholdingSetMapsDialog::Accepted) { this->updateEditorInternal(this->caretMappableDataFile, this->mapFileIndex); this->applySelections(); } } /** * Update the minimum and maximum values for the thresholding controls. */ void MapSettingsPaletteColorMappingWidget::updateThresholdControlsMinimumMaximumRangeValues() { if (paletteColorMapping != NULL) { if (this->caretMappableDataFile != NULL) { if ((this->mapFileIndex >= 0) && (this->mapFileIndex < this->caretMappableDataFile->getNumberOfMaps())) { const PaletteThresholdRangeModeEnum::Enum thresholdRangeMode = paletteColorMapping->getThresholdRangeMode(); this->thresholdRangeModeComboBox->setSelectedItem(thresholdRangeMode); float maxValue = BIG_NUMBER; float minValue = -maxValue; float stepMax = maxValue; float stepMin = minValue; switch (thresholdRangeMode) { case PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_FILE: this->caretMappableDataFile->getDataRangeFromAllMaps(minValue, maxValue); stepMin = minValue; stepMax = maxValue; break; case PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_MAP: { FastStatistics* statistics = NULL; switch (this->caretMappableDataFile->getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: statistics = const_cast(this->caretMappableDataFile->getFileFastStatistics()); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: statistics = const_cast(this->caretMappableDataFile->getMapFastStatistics(this->mapFileIndex)); break; } if (statistics != NULL) { minValue = statistics->getMin(); maxValue = statistics->getMax(); stepMin = minValue; stepMax = maxValue; } } break; case PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_UNLIMITED: { /* * For unlimited range, use twice the maximum value in the file * Using very large values can cause problems with some * Qt widgets. */ float allMapMinValue = 0.0; float allMapMaxValue = 0.0; this->caretMappableDataFile->getDataRangeFromAllMaps(allMapMinValue, allMapMaxValue); if (allMapMaxValue > allMapMinValue) { const float absMax = std::max(std::fabs(allMapMaxValue), std::fabs(allMapMinValue)); minValue = -absMax * 2.0; maxValue = absMax * 2.0; } stepMin = minValue; stepMax = maxValue; } break; } /* * Set the spin box step value to one percent of * the data's range. */ float stepValue = 1.0; const float diff = stepMax - stepMin; if (diff > 0.0) { stepValue = diff / 100.0; } float lowMin = minValue; float lowMax = maxValue; float highMin = minValue; float highMax = maxValue; if (this->paletteColorMapping->isThresholdNegMinPosMaxLinked()) { const float absMax = std::max(std::fabs(minValue), std::fabs(maxValue)); lowMin = -absMax; lowMax = 0.0; highMin = 0.0; highMax = absMax; } this->thresholdLowSlider->setRange(lowMin, lowMax); this->thresholdHighSlider->setRange(highMin, highMax); /* * Since there are multiple ways for the user to adjust * a threshold (slider or spin box) these controls must * dispaly the same values. In addition, linking the * thresholds requires updating the spin boxes and sliders * for both low and high thresholding. * * The spin box allows the user to hold down one of the * arrow keys to continuously update the data. However, * if any of the spin box's "set" methods are called * while the user holds down the arrow, holding down of * the arrow key will not work. So, when the signal is * emitted for the spin box value being changed, we need * to avoid updating that spin box during that time. */ if (allowUpdateOfThresholdLowSpinBox) { this->thresholdLowSpinBox->setRange(lowMin, lowMax); this->thresholdLowSpinBox->setSingleStep(stepValue); } if (allowUpdateOfThresholdHighSpinBox) { this->thresholdHighSpinBox->setRange(highMin, highMax); this->thresholdHighSpinBox->setSingleStep(stepValue); } } } } } /** * Should be called when a control is changed and * the change requires and update to other controls. */ void MapSettingsPaletteColorMappingWidget::applyAndUpdate() { this->applySelections(); this->updateEditorInternal(this->caretMappableDataFile, this->mapFileIndex); } /** * Update after a threshold value is changed. * * @param lowThreshold * New value for low threshold. * @param highThreshold * New value for high threshold. */ void MapSettingsPaletteColorMappingWidget::updateAfterThresholdValuesChanged(const float lowThreshold, const float highThreshold) { const PaletteThresholdTypeEnum::Enum threshType = this->paletteColorMapping->getThresholdType(); this->paletteColorMapping->setThresholdMinimum(threshType, lowThreshold); this->paletteColorMapping->setThresholdMaximum(threshType, highThreshold); updateThresholdSection(); this->applySelections(); } /** * Called when low value spin box changed. * @param thresholdLow * New value. */ void MapSettingsPaletteColorMappingWidget::thresholdLowSpinBoxValueChanged(double thresholdLow) { const PaletteThresholdTypeEnum::Enum threshType = this->paletteColorMapping->getThresholdType(); float thresholdHigh = this->paletteColorMapping->getThresholdMaximum(threshType); if (this->paletteColorMapping->isThresholdNegMinPosMaxLinked()) { thresholdHigh = -thresholdLow; } else { if (thresholdLow > thresholdHigh) { thresholdHigh = thresholdLow; } } allowUpdateOfThresholdLowSpinBox = false; updateAfterThresholdValuesChanged(thresholdLow, thresholdHigh); allowUpdateOfThresholdLowSpinBox = true; } /** * Called when high value spin box changed. * @param thresholdHigh * New value. */ void MapSettingsPaletteColorMappingWidget::thresholdHighSpinBoxValueChanged(double thresholdHigh) { const PaletteThresholdTypeEnum::Enum threshType = this->paletteColorMapping->getThresholdType(); float thresholdLow = this->paletteColorMapping->getThresholdMinimum(threshType); if (this->paletteColorMapping->isThresholdNegMinPosMaxLinked()) { thresholdLow = -thresholdHigh; } else { if (thresholdHigh < thresholdLow) { thresholdLow = thresholdHigh; } } allowUpdateOfThresholdHighSpinBox = false; updateAfterThresholdValuesChanged(thresholdLow, thresholdHigh); allowUpdateOfThresholdHighSpinBox = true; } /** * Called when low value slider changed. * @param thresholdLow * New value. */ void MapSettingsPaletteColorMappingWidget::thresholdLowSliderValueChanged(double thresholdLow) { const PaletteThresholdTypeEnum::Enum threshType = this->paletteColorMapping->getThresholdType(); float thresholdHigh = this->paletteColorMapping->getThresholdMaximum(threshType); if (this->paletteColorMapping->isThresholdNegMinPosMaxLinked()) { thresholdHigh = -thresholdLow; } else { if (thresholdLow > thresholdHigh) { thresholdHigh = thresholdLow; } } updateAfterThresholdValuesChanged(thresholdLow, thresholdHigh); } /** * Called when high value slider changed. * @param thresholdHigh * New value. */ void MapSettingsPaletteColorMappingWidget::thresholdHighSliderValueChanged(double thresholdHigh) { const PaletteThresholdTypeEnum::Enum threshType = this->paletteColorMapping->getThresholdType(); float thresholdLow = this->paletteColorMapping->getThresholdMinimum(threshType); if (this->paletteColorMapping->isThresholdNegMinPosMaxLinked()) { thresholdLow = -thresholdHigh; } else { if (thresholdHigh < thresholdLow) { thresholdLow = thresholdHigh; } } updateAfterThresholdValuesChanged(thresholdLow, thresholdHigh); } /** * Gets called when the threshold map file/index is changed. */ void MapSettingsPaletteColorMappingWidget::thresholdMapFileIndexSelectorChanged() { this->applySelections(); } /** * Called when the threshold link check box is toggled. * * @param checked * Checked status of the checkbox. */ void MapSettingsPaletteColorMappingWidget::thresholdLinkCheckBoxToggled(bool checked) { if (this->paletteColorMapping != NULL) { this->paletteColorMapping->setThresholdNegMinPosMaxLinked(checked); const PaletteThresholdTypeEnum::Enum threshType = this->paletteColorMapping->getThresholdType(); float lowValue = this->paletteColorMapping->getThresholdMinimum(threshType); float highValue = this->paletteColorMapping->getThresholdMaximum(threshType); if (checked) { if (highValue > 0.0) { lowValue = -highValue; } else if (lowValue < 0.0) { highValue = -lowValue; } else { highValue = 1.0; lowValue = -1.0; } } updateAfterThresholdValuesChanged(lowValue, highValue); } } /** * Create the threshold section of the dialog. * @return * The threshold section. */ QWidget* MapSettingsPaletteColorMappingWidget::createThresholdSection() { allowUpdateOfThresholdLowSpinBox = true; allowUpdateOfThresholdHighSpinBox = true; /* * Threshold Outline */ QLabel* thresholdOutlineLabel = new QLabel("Outline "); this->thresholdOutlineDrawingModeComboBox = new EnumComboBoxTemplate(this); this->thresholdOutlineDrawingModeComboBox->setup(); QObject::connect(this->thresholdOutlineDrawingModeComboBox, &EnumComboBoxTemplate::itemActivated, this, &MapSettingsPaletteColorMappingWidget::applySelections); QLabel* thresholdOutlineColorLabel = new QLabel(" Color "); this->thresholdOutlineDrawingColorComboBox = new CaretColorEnumComboBox(this); QObject::connect(this->thresholdOutlineDrawingColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), this, SLOT(applySelections())); this->thresholdOutlineDrawingWidget = new QWidget(); QHBoxLayout* thresholdOutlineLayout = new QHBoxLayout(this->thresholdOutlineDrawingWidget); WuQtUtilities::setLayoutSpacingAndMargins(thresholdOutlineLayout, 2, 0); thresholdOutlineLayout->addWidget(thresholdOutlineLabel); thresholdOutlineLayout->addWidget(this->thresholdOutlineDrawingModeComboBox->getWidget()); thresholdOutlineLayout->addWidget(thresholdOutlineColorLabel); thresholdOutlineLayout->addWidget(this->thresholdOutlineDrawingColorComboBox->getWidget()); thresholdOutlineLayout->addStretch(); /* * Threshold types on/off */ QLabel* thresholdTypeLabel = new QLabel("Source"); std::vector thresholdTypes; PaletteThresholdTypeEnum::getAllEnums(thresholdTypes); const int32_t numThresholdTypes = static_cast(thresholdTypes.size()); this->thresholdTypeComboBox = new QComboBox(); WuQtUtilities::setToolTipAndStatusTip(this->thresholdTypeComboBox, "Select thresholding off/on"); for (int32_t i = 0; i < numThresholdTypes; i++) { this->thresholdTypeComboBox->addItem(PaletteThresholdTypeEnum::toGuiName(thresholdTypes[i])); this->thresholdTypeComboBox->setItemData(i, static_cast(thresholdTypes[i])); } QObject::connect(this->thresholdTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(thresholdTypeChanged(int))); this->thresholdSetAllMapsToolButton = new QToolButton(); this->thresholdSetAllMapsToolButton->setText("Set All Maps..."); this->thresholdSetAllMapsToolButton->setToolTip("Setup thresholding for all maps in the data file"); QObject::connect(this->thresholdSetAllMapsToolButton, &QToolButton::clicked, this, &MapSettingsPaletteColorMappingWidget::thresholdSetAllMapsToolButtonClicked); QLabel* thresholdRangeLabel = new QLabel("Range"); this->thresholdRangeModeComboBox = new EnumComboBoxTemplate(this); QObject::connect(this->thresholdRangeModeComboBox, SIGNAL(itemActivated()), this, SLOT(thresholdRangeModeChanged())); this->thresholdRangeModeComboBox->setup(); const AString rangeModeToolTip = ("Controls range of threshold controls\n" " File: Range is from all values in file.\n" " Map: Range is from all values in selected map.\n" " Unlimited: Range is +/- infinity."); this->thresholdRangeModeComboBox->getWidget()->setToolTip(WuQtUtilities::createWordWrappedToolTipText(rangeModeToolTip)); /* * Threshold file and map selector */ this->thresholdMapFileIndexSelector = new CaretMappableDataFileAndMapSelectorObject(CaretMappableDataFileAndMapSelectorObject::OPTION_SHOW_MAP_INDEX_SPIN_BOX, this); QObject::connect(this->thresholdMapFileIndexSelector, &CaretMappableDataFileAndMapSelectorObject::selectionWasPerformed, this, &MapSettingsPaletteColorMappingWidget::thresholdMapFileIndexSelectorChanged); QWidget* threshFileComboBox(0); QWidget* threshMapIndexSpinBox(0); QWidget* threshMapNameComboBox(0); this->thresholdMapFileIndexSelector->getWidgetsForAddingToLayout(threshFileComboBox, threshMapIndexSpinBox, threshMapNameComboBox); this->thresholdFileWidget = new QWidget(); QGridLayout* threshFileLayout = new QGridLayout(this->thresholdFileWidget); QLabel* threshFileLabel = new QLabel("File"); QLabel* threshMapLabel = new QLabel("Map"); threshFileLayout->setContentsMargins(0, 0, 0, 0); threshFileLayout->setSpacing(4); threshFileLayout->setColumnStretch(0, 0); threshFileLayout->setColumnStretch(1, 0); threshFileLayout->setColumnStretch(2, 100); threshFileLayout->addWidget(threshFileLabel, 0, 0); threshFileLayout->addWidget(threshFileComboBox, 0, 1, 1, 2); threshFileLayout->addWidget(threshMapLabel, 1, 0); threshFileLayout->addWidget(threshMapIndexSpinBox, 1, 1); threshFileLayout->addWidget(threshMapNameComboBox, 1, 2); /* * Linking of low/high thresholds */ QPixmap chainLinkPixmap; const bool chainLinkPixmapValid = WuQtUtilities::loadPixmap(":/PaletteSettings/chain_link_icon.png", chainLinkPixmap); const AString linkToolTipText("When linked, both low and high are the same\n" "ABSOLUTE value with low always being negative and\n" "high always being positive.\n" " low range: [- maximum-absolute value, 0]\n" " high range: [0, + maximum-absolute-value]\n" "\n" "When NOT linked, the low and high range controls\n" "operate independently.\n" " low and high range: [minimum-value, maximum-value]\n" "\n" "NOTE: When 'Link' is unchecked, the thresholds may \n" "change due to a difference in the allowable range of \n" "values while linked and unlinked."); this->thresholdLinkCheckBox = new QCheckBox(""); QObject::connect(this->thresholdLinkCheckBox, SIGNAL(toggled(bool)), this, SLOT(thresholdLinkCheckBoxToggled(bool))); this->thresholdLinkCheckBox->setToolTip(linkToolTipText); this->thresholdWidgetGroup->add(this->thresholdLinkCheckBox); QLabel* linkLabel = new QLabel(); if (chainLinkPixmapValid) { linkLabel->setPixmap(chainLinkPixmap); } else { linkLabel->setText("Link"); } linkLabel->setToolTip(linkToolTipText); QVBoxLayout* linkLayout = new QVBoxLayout(); linkLayout->addWidget(this->thresholdLinkCheckBox); linkLayout->addWidget(linkLabel); /* * Sliders and Spin Boxes for adjustment */ QLabel* thresholdLowLabel = new QLabel("Low"); QLabel* thresholdHighLabel = new QLabel("High"); const float thresholdMinimum = -BIG_NUMBER; const float thresholdMaximum = BIG_NUMBER; this->thresholdLowSlider = new WuQDoubleSlider(Qt::Horizontal, this); this->thresholdLowSlider->setRange(thresholdMinimum, thresholdMaximum); WuQtUtilities::setToolTipAndStatusTip(this->thresholdLowSlider->getWidget(), "Adjust the low threshold value"); this->thresholdWidgetGroup->add(this->thresholdLowSlider); QObject::connect(this->thresholdLowSlider, SIGNAL(valueChanged(double)), this, SLOT(thresholdLowSliderValueChanged(double))); this->thresholdHighSlider = new WuQDoubleSlider(Qt::Horizontal, this); this->thresholdHighSlider->setRange(thresholdMinimum, thresholdMaximum); WuQtUtilities::setToolTipAndStatusTip(this->thresholdHighSlider->getWidget(), "Adjust the high threshold value"); this->thresholdWidgetGroup->add(this->thresholdHighSlider); QObject::connect(this->thresholdHighSlider, SIGNAL(valueChanged(double)), this, SLOT(thresholdHighSliderValueChanged(double))); const int spinBoxWidth = 80.0; this->thresholdLowSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(thresholdMinimum, thresholdMaximum, 1.0, 3, this, SLOT(thresholdLowSpinBoxValueChanged(double))); this->thresholdLowSpinBox->setAccelerated(true); WuQtUtilities::setToolTipAndStatusTip(this->thresholdLowSpinBox, "Adjust the low threshold value"); this->thresholdWidgetGroup->add(this->thresholdLowSpinBox); this->thresholdLowSpinBox->setFixedWidth(spinBoxWidth); this->thresholdHighSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(thresholdMinimum, thresholdMaximum, 1.0, 3, this, SLOT(thresholdHighSpinBoxValueChanged(double))); WuQtUtilities::setToolTipAndStatusTip(this->thresholdHighSpinBox, "Adjust the high threshold value"); this->thresholdWidgetGroup->add(this->thresholdHighSpinBox); this->thresholdHighSpinBox->setFixedWidth(spinBoxWidth); this->thresholdShowInsideRadioButton = new QRadioButton("Show Data Inside Thresholds"); WuQtUtilities::setWordWrappedToolTip(this->thresholdShowInsideRadioButton, "Displays data that is greater than or equal to " "the minimum threshold value and less than or " "equal to the maximum threshold value."); this->thresholdShowOutsideRadioButton = new QRadioButton("Show Data Outside Thresholds"); WuQtUtilities::setWordWrappedToolTip(this->thresholdShowOutsideRadioButton, "Displays data that is less than the minimum " "threshold value or greater than the maximum " "threshold value."); QButtonGroup* thresholdShowButtonGroup = new QButtonGroup(this); this->thresholdWidgetGroup->add(thresholdShowButtonGroup); thresholdShowButtonGroup->addButton(this->thresholdShowInsideRadioButton); thresholdShowButtonGroup->addButton(this->thresholdShowOutsideRadioButton); QObject::connect(thresholdShowButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(applyAndUpdate())); QHBoxLayout* rangeLayout = new QHBoxLayout(); rangeLayout->addWidget(thresholdRangeLabel); rangeLayout->addWidget(this->thresholdRangeModeComboBox->getWidget()); this->thresholdAdjustmentWidget = new QWidget(); QGridLayout* thresholdAdjustmentLayout = new QGridLayout(thresholdAdjustmentWidget); this->setLayoutSpacingAndMargins(thresholdAdjustmentLayout); thresholdAdjustmentLayout->setColumnStretch(0, 0); thresholdAdjustmentLayout->setColumnStretch(1, 0); thresholdAdjustmentLayout->setColumnStretch(2, 100); thresholdAdjustmentLayout->setColumnStretch(3, 100); thresholdAdjustmentLayout->setColumnStretch(4, 0); thresholdAdjustmentLayout->addLayout(linkLayout, 0, 0, 2, 1, Qt::AlignCenter); thresholdAdjustmentLayout->addWidget(thresholdHighLabel, 0, 1); thresholdAdjustmentLayout->addWidget(this->thresholdHighSlider->getWidget(), 0, 2, 1, 2); thresholdAdjustmentLayout->addWidget(this->thresholdHighSpinBox, 0, 4); thresholdAdjustmentLayout->addWidget(thresholdLowLabel, 1, 1); thresholdAdjustmentLayout->addWidget(this->thresholdLowSlider->getWidget(), 1, 2, 1, 2); thresholdAdjustmentLayout->addWidget(this->thresholdLowSpinBox, 1, 4); thresholdAdjustmentLayout->addWidget(this->thresholdShowInsideRadioButton, 2, 0, 1, 3, Qt::AlignLeft); thresholdAdjustmentLayout->addWidget(this->thresholdShowOutsideRadioButton, 3, 0, 1, 3, Qt::AlignLeft); thresholdAdjustmentLayout->addLayout(rangeLayout, 2, 3, 2, 2, Qt::AlignRight); thresholdAdjustmentWidget->setFixedHeight(thresholdAdjustmentWidget->sizeHint().height()); QWidget* topWidget = new QWidget(); QHBoxLayout* topLayout = new QHBoxLayout(topWidget); topLayout->setContentsMargins(0, 0, 0, 0); topLayout->addWidget(thresholdTypeLabel); topLayout->addWidget(this->thresholdTypeComboBox); topLayout->addWidget(this->thresholdSetAllMapsToolButton); topLayout->addStretch(); QGroupBox* thresholdGroupBox = new QGroupBox("Threshold"); QVBoxLayout* layout = new QVBoxLayout(thresholdGroupBox); this->setLayoutSpacingAndMargins(layout); layout->addWidget(topWidget, 0, Qt::AlignLeft); layout->addWidget(this->thresholdFileWidget); layout->addWidget(this->thresholdOutlineDrawingWidget); layout->addWidget(WuQtUtilities::createHorizontalLineWidget()); layout->addWidget(thresholdAdjustmentWidget); thresholdGroupBox->setFixedHeight(thresholdGroupBox->sizeHint().height()); this->thresholdAdjustmentWidgetGroup = new WuQWidgetObjectGroup(this); this->thresholdAdjustmentWidgetGroup->add(this->thresholdLinkCheckBox); this->thresholdAdjustmentWidgetGroup->add(thresholdLowLabel); this->thresholdAdjustmentWidgetGroup->add(thresholdHighLabel); this->thresholdAdjustmentWidgetGroup->add(this->thresholdLowSlider->getWidget()); this->thresholdAdjustmentWidgetGroup->add(this->thresholdHighSlider->getWidget()); this->thresholdAdjustmentWidgetGroup->add(this->thresholdLowSpinBox); this->thresholdAdjustmentWidgetGroup->add(this->thresholdHighSpinBox); this->thresholdAdjustmentWidgetGroup->add(this->thresholdShowInsideRadioButton); this->thresholdAdjustmentWidgetGroup->add(this->thresholdShowOutsideRadioButton); this->thresholdAdjustmentWidgetGroup->add(thresholdRangeLabel); this->thresholdAdjustmentWidgetGroup->add(this->thresholdRangeModeComboBox->getWidget()); this->thresholdAdjustmentWidgetGroup->add(threshFileComboBox); this->thresholdAdjustmentWidgetGroup->add(threshMapIndexSpinBox); this->thresholdAdjustmentWidgetGroup->add(threshMapNameComboBox); this->thresholdAdjustmentWidgetGroup->add(this->thresholdSetAllMapsToolButton); this->thresholdAdjustmentWidgetGroup->add(this->thresholdOutlineDrawingColorComboBox->getWidget()); this->thresholdAdjustmentWidgetGroup->add(this->thresholdOutlineDrawingModeComboBox->getWidget()); return thresholdGroupBox; } /** * Called when threshold range mode is changed. */ void MapSettingsPaletteColorMappingWidget::thresholdRangeModeChanged() { const PaletteThresholdRangeModeEnum::Enum thresholdRange = this->thresholdRangeModeComboBox->getSelectedItem(); this->paletteColorMapping->setThresholdRangeMode(thresholdRange); updateThresholdControlsMinimumMaximumRangeValues(); applySelections(); } /** * Create the statistics section * @return the statistics section widget. */ QWidget* MapSettingsPaletteColorMappingWidget::createHistogramControlSection() { QLabel* showLabel = new QLabel("Show "); m_histogramBarsVisibleCheckBox = new QCheckBox("Bars"); QObject::connect(m_histogramBarsVisibleCheckBox, &QCheckBox::clicked, [=] { this->applyAndUpdate(); } ); m_histogramEnvelopeVisibleCheckBox = new QCheckBox("Envelope"); QObject::connect(m_histogramEnvelopeVisibleCheckBox, &QCheckBox::clicked, [=] { this->applyAndUpdate(); }); QHBoxLayout* showLayout = new QHBoxLayout(); showLayout->addWidget(m_histogramBarsVisibleCheckBox); showLayout->addStretch(); showLayout->addWidget(m_histogramEnvelopeVisibleCheckBox); QLabel* horizRangeLabel = new QLabel("Range"); m_histogramHorizontalRangeComboBox = new EnumComboBoxTemplate(this); QObject::connect(this->m_histogramHorizontalRangeComboBox, SIGNAL(itemActivated()), this, SLOT(applyAndUpdate())); this->m_histogramHorizontalRangeComboBox->setup(); this->m_histogramHorizontalRangeComboBox->getWidget()->setToolTip("Horizontal range of histogram"); QIcon colorBarIcon; const bool colorBarIconValid = WuQtUtilities::loadIcon(":/LayersPanel/colorbar.png", colorBarIcon); QLabel* barsColorLabel = new QLabel("Bars Color"); if (colorBarIconValid) { m_histogramBarsColorComboBox = new CaretColorEnumComboBox("Palette", colorBarIcon, this); } else { m_histogramBarsColorComboBox = new CaretColorEnumComboBox("Palette", this); } WuQtUtilities::setToolTipAndStatusTip(m_histogramBarsColorComboBox->getWidget(), "Set histogram bars coloring"); QObject::connect(m_histogramBarsColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), this, SLOT(applyAndUpdate())); QLabel* envelopeColorLabel = new QLabel("Envelope"); if (colorBarIconValid) { m_histogramEnvelopeColorComboBox = new CaretColorEnumComboBox("Palette", colorBarIcon, this); } else { m_histogramEnvelopeColorComboBox = new CaretColorEnumComboBox("Palette", this); } WuQtUtilities::setToolTipAndStatusTip(m_histogramEnvelopeColorComboBox->getWidget(), "Set histogram envelope coloring"); QObject::connect(m_histogramEnvelopeColorComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), this, SLOT(applyAndUpdate())); QLabel* envelopeLineWidthLabel = new QLabel("Envelope Width"); m_histogramEnvelopeLineWidthPercentageSpinBox = new WuQDoubleSpinBox(this); m_histogramEnvelopeLineWidthPercentageSpinBox->setRangePercentage(0.0, 100.0); QObject::connect(m_histogramEnvelopeLineWidthPercentageSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), [=](double) { this->applyAndUpdate(); }); const int32_t maxBuckets = 100000; QLabel* bucketsLabel = new QLabel("Buckets"); m_histogramBucketsSpinBox = WuQFactory::newSpinBoxWithMinMaxStep(1, maxBuckets, 1); QObject::connect(m_histogramBucketsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(applyAndUpdate())); QWidget* controlWidget = new QWidget(); QGridLayout* controlLayout = new QGridLayout(controlWidget); this->setLayoutSpacingAndMargins(controlLayout); int rowIndex = 0; controlLayout->addWidget(showLabel, rowIndex, 0); controlLayout->addLayout(showLayout, rowIndex, 1); rowIndex++; controlLayout->addWidget(barsColorLabel, rowIndex, 0); controlLayout->addWidget(m_histogramBarsColorComboBox->getWidget(), rowIndex, 1); rowIndex++; controlLayout->addWidget(envelopeColorLabel, rowIndex, 0); controlLayout->addWidget(m_histogramEnvelopeColorComboBox->getWidget(), rowIndex, 1); rowIndex++; controlLayout->addWidget(envelopeLineWidthLabel, rowIndex, 0); controlLayout->addWidget(m_histogramEnvelopeLineWidthPercentageSpinBox->getWidget(), rowIndex, 1); rowIndex++; controlLayout->addWidget(horizRangeLabel, rowIndex, 0); controlLayout->addWidget(m_histogramHorizontalRangeComboBox->getWidget(), rowIndex, 1); rowIndex++; controlLayout->addWidget(bucketsLabel, rowIndex, 0); controlLayout->addWidget(m_histogramBucketsSpinBox, rowIndex, 1); rowIndex++; controlWidget->setFixedSize(controlWidget->sizeHint()); /* * Statistics */ const AString blankText(""); this->statisticsMinimumValueLabel = new QLabel(blankText); this->statisticsMinimumValueLabel->setAlignment(Qt::AlignRight); this->statisticsMaximumValueLabel = new QLabel(blankText); this->statisticsMaximumValueLabel->setAlignment(Qt::AlignRight); this->statisticsMeanValueLabel = new QLabel(blankText); this->statisticsMeanValueLabel->setAlignment(Qt::AlignRight); this->statisticsStandardDeviationLabel = new QLabel(blankText); this->statisticsStandardDeviationLabel->setAlignment(Qt::AlignRight); QWidget* statisticsWidget = new QWidget(); QGridLayout* statisticsLayout = new QGridLayout(statisticsWidget); statisticsLayout->setColumnStretch(0, 0); statisticsLayout->setColumnStretch(0, 100); statisticsLayout->setColumnMinimumWidth(1, 10); this->setLayoutSpacingAndMargins(statisticsLayout); statisticsLayout->addWidget(new QLabel("Mean"), 0, 0); statisticsLayout->addWidget(this->statisticsMeanValueLabel, 0, 1); statisticsLayout->addWidget(new QLabel("Std Dev"), 1, 0); statisticsLayout->addWidget(this->statisticsStandardDeviationLabel, 1, 1); statisticsLayout->addWidget(new QLabel("Max"), 2, 0); statisticsLayout->addWidget(this->statisticsMaximumValueLabel, 2, 1); statisticsLayout->addWidget(new QLabel("Min"), 3, 0); statisticsLayout->addWidget(this->statisticsMinimumValueLabel, 3, 1); statisticsLayout->setRowStretch(statisticsLayout->rowCount(), 100); QGroupBox* groupBox = new QGroupBox("Histogram"); QHBoxLayout* layout = new QHBoxLayout(groupBox); this->setLayoutSpacingAndMargins(layout); layout->addWidget(controlWidget); layout->addWidget(WuQtUtilities::createVerticalLineWidget()); layout->addWidget(statisticsWidget); groupBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); return groupBox; } /** * Create the histogram section of the dialog. * @return * The histogram section. */ QWidget* MapSettingsPaletteColorMappingWidget::createHistogramSection() { this->thresholdPlot = new WuQwtPlot(); QObject::connect(this->thresholdPlot, SIGNAL(contextMenuDisplay(QContextMenuEvent*, float, float)), this, SLOT(contextMenuDisplayRequested(QContextMenuEvent*, float, float))); this->thresholdPlot->plotLayout()->setAlignCanvasToScales(true); /* * Allow zooming */ PlotMagnifier* magnifier = new PlotMagnifier(qobject_cast(this->thresholdPlot->canvas())); magnifier->setAxisEnabled(QwtPlot::yLeft, true); magnifier->setAxisEnabled(QwtPlot::yRight, true); /* * Allow panning */ (void)new PlotPanner(qobject_cast(this->thresholdPlot->canvas())); /* * Auto scaling */ this->thresholdPlot->setAxisAutoScale(QwtPlot::xBottom); this->thresholdPlot->setAxisAutoScale(QwtPlot::yLeft); /* * Reset View tool button */ QAction* resetViewAction = WuQtUtilities::createAction("Reset View", "Remove any zooming/panning from histogram chart", this, this, SLOT(histogramResetViewButtonClicked())); QToolButton* resetViewToolButton = new QToolButton(); resetViewToolButton->setDefaultAction(resetViewAction); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(this->thresholdPlot); layout->addWidget(resetViewToolButton, 0, Qt::AlignHCenter); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 0); return widget; } /** * Called when the context menu is to be displayed. * * @param event * The context menu event. * @param graphX * X-coordinate on plot. * @param graphY * Y-coordinate on plot. */ void MapSettingsPaletteColorMappingWidget::contextMenuDisplayRequested(QContextMenuEvent* event, float graphX, float /*graphY*/) { if (this->paletteColorMapping != NULL) { const PaletteThresholdTypeEnum::Enum threshType = this->paletteColorMapping->getThresholdType(); if (threshType != PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF) { const float absValue = std::fabs(graphX); AString textValue = NumericTextFormatting::formatValue(absValue); CursorDisplayScoped cursor; cursor.showCursor(Qt::ArrowCursor); QMenu menu(this); QAction* linkedAction = NULL; QAction* minThreshAction = NULL; QAction* maxThreshAction = NULL; if (this->paletteColorMapping->isThresholdNegMinPosMaxLinked()) { linkedAction = menu.addAction("Set Thresholds to -" + textValue + " and " + textValue); } else { minThreshAction = menu.addAction("Set Minimum Threshold to " + textValue); maxThreshAction = menu.addAction("Set Maximum Threshold to " + textValue); } QAction* selectedAction = menu.exec(event->globalPos()); if (selectedAction != NULL) { float minThresh = this->paletteColorMapping->getThresholdMinimum(threshType); float maxThresh = this->paletteColorMapping->getThresholdMaximum(threshType); if (selectedAction == linkedAction) { minThresh = -absValue; maxThresh = absValue; } else if (selectedAction == minThreshAction) { minThresh = graphX; } else if (selectedAction == maxThreshAction) { maxThresh = graphX; } updateAfterThresholdValuesChanged(minThresh, maxThresh); } } } } /** * Called to reset the view of the histogram chart. */ void MapSettingsPaletteColorMappingWidget::histogramResetViewButtonClicked() { this->thresholdPlot->setAxisAutoScale(QwtPlot::xBottom,true); this->thresholdPlot->setAxisAutoScale(QwtPlot::yLeft,true); this->updateHistogramPlot(); this->thresholdPlot->setAxisAutoScale(QwtPlot::xBottom,false); this->thresholdPlot->setAxisAutoScale(QwtPlot::yLeft,false); } /** * Called when the auto percentage negative maximum value changes. * * @param value * The new value. */ void MapSettingsPaletteColorMappingWidget::scaleAutoPercentageNegativeMaximumValueChanged(double value) { /* * Ensure maximum >= minimum */ if (value < this->scaleAutoPercentageNegativeMinimumSpinBox->value()) { this->scaleAutoPercentageNegativeMinimumSpinBox->blockSignals(true); this->scaleAutoPercentageNegativeMinimumSpinBox->setValue(value); this->scaleAutoPercentageNegativeMinimumSpinBox->blockSignals(false); } applySelections(); updatePaletteMappedToDataValueLabels(); } /** * Called when the auto percentage negative minimum value changes. * * @param value * The new value. */ void MapSettingsPaletteColorMappingWidget::scaleAutoPercentageNegativeMinimumValueChanged(double value) { /* * Ensure maximum >= minimum */ if (value > this->scaleAutoPercentageNegativeMaximumSpinBox->value()) { this->scaleAutoPercentageNegativeMaximumSpinBox->blockSignals(true); this->scaleAutoPercentageNegativeMaximumSpinBox->setValue(value); this->scaleAutoPercentageNegativeMaximumSpinBox->blockSignals(false); } applySelections(); updatePaletteMappedToDataValueLabels(); } /** * Called when the auto percentage positive minimum value changes. * * @param value * The new value. */ void MapSettingsPaletteColorMappingWidget::scaleAutoPercentagePositiveMinimumValueChanged(double value) { /* * Ensure maximum >= minimum */ if (value > this->scaleAutoPercentagePositiveMaximumSpinBox->value()) { this->scaleAutoPercentagePositiveMaximumSpinBox->blockSignals(true); this->scaleAutoPercentagePositiveMaximumSpinBox->setValue(value); this->scaleAutoPercentagePositiveMaximumSpinBox->blockSignals(false); } applySelections(); updatePaletteMappedToDataValueLabels(); } /** * Called when the auto percentage maximum value changes. * * @param value * The new value. */ void MapSettingsPaletteColorMappingWidget::scaleAutoPercentagePositiveMaximumValueChanged(double value) { /* * Ensure maximum >= minimum */ if (value < this->scaleAutoPercentagePositiveMinimumSpinBox->value()) { this->scaleAutoPercentagePositiveMinimumSpinBox->blockSignals(true); this->scaleAutoPercentagePositiveMinimumSpinBox->setValue(value); this->scaleAutoPercentagePositiveMinimumSpinBox->blockSignals(false); } applySelections(); updatePaletteMappedToDataValueLabels(); } /** * Called when the auto absolute percentage minimum value changes. * * @param value * The new value. */ void MapSettingsPaletteColorMappingWidget::scaleAutoAbsolutePercentageMinimumValueChanged(double value) { /* * Ensure maximum >= minimum */ if (value > this->scaleAutoAbsolutePercentageMaximumSpinBox->value()) { this->scaleAutoAbsolutePercentageMaximumSpinBox->blockSignals(true); this->scaleAutoAbsolutePercentageMaximumSpinBox->setValue(value); this->scaleAutoAbsolutePercentageMaximumSpinBox->blockSignals(false); } applySelections(); updatePaletteMappedToDataValueLabels(); } /** * Called when the auto absolute percentage maximum value changes. * * @param value * The new value. */ void MapSettingsPaletteColorMappingWidget::scaleAutoAbsolutePercentageMaximumValueChanged(double value) { /* * Ensure maximum >= minimum */ if (value < this->scaleAutoAbsolutePercentageMinimumSpinBox->value()) { this->scaleAutoAbsolutePercentageMinimumSpinBox->blockSignals(true); this->scaleAutoAbsolutePercentageMinimumSpinBox->setValue(value); this->scaleAutoAbsolutePercentageMinimumSpinBox->blockSignals(false); } applySelections(); updatePaletteMappedToDataValueLabels(); } /** * Called when the fixed negative maximum value changes. * * @param value * The new value. */ void MapSettingsPaletteColorMappingWidget::scaleFixedNegativeMaximumValueChanged(double value) { /* * Ensure maximum >= minimum */ if (value > this->scaleFixedNegativeMinimumSpinBox->value()) { this->scaleFixedNegativeMinimumSpinBox->blockSignals(true); this->scaleFixedNegativeMinimumSpinBox->setValue(value); this->scaleFixedNegativeMinimumSpinBox->blockSignals(false); } applySelections(); updatePaletteMappedToDataValueLabels(); } /** * Called when the fixed negative minimum value changes. * * @param value * The new value. */ void MapSettingsPaletteColorMappingWidget::scaleFixedNegativeMinimumValueChanged(double value) { /* * Ensure maximum >= minimum */ if (value < this->scaleFixedNegativeMaximumSpinBox->value()) { this->scaleFixedNegativeMaximumSpinBox->blockSignals(true); this->scaleFixedNegativeMaximumSpinBox->setValue(value); this->scaleFixedNegativeMaximumSpinBox->blockSignals(false); } applySelections(); updatePaletteMappedToDataValueLabels(); } /** * Called when the fixed positive minimum value changes. * * @param value * The new value. */ void MapSettingsPaletteColorMappingWidget::scaleFixedPositiveMinimumValueChanged(double value) { /* * Ensure maximum >= minimum */ if (value > this->scaleFixedPositiveMaximumSpinBox->value()) { this->scaleFixedPositiveMaximumSpinBox->blockSignals(true); this->scaleFixedPositiveMaximumSpinBox->setValue(value); this->scaleFixedPositiveMaximumSpinBox->blockSignals(false); } applySelections(); updatePaletteMappedToDataValueLabels(); } /** * Called when the fixed positive maximum value changes. * * @param value * The new value. */ void MapSettingsPaletteColorMappingWidget::scaleFixedPositiveMaximumValueChanged(double value) { /* * Ensure maximum >= minimum */ if (value < this->scaleFixedPositiveMinimumSpinBox->value()) { this->scaleFixedPositiveMinimumSpinBox->blockSignals(true); this->scaleFixedPositiveMinimumSpinBox->setValue(value); this->scaleFixedPositiveMinimumSpinBox->blockSignals(false); } applySelections(); updatePaletteMappedToDataValueLabels(); } /** * Create the palette section of the dialog. * @return * The palette section. */ QWidget* MapSettingsPaletteColorMappingWidget::createPaletteSection() { /* * Selection */ QLabel* paletteNameLabel = new QLabel("Name"); this->paletteNameComboBox = new QComboBox(); WuQtUtilities::setToolTipAndStatusTip(this->paletteNameComboBox, "Select palette for coloring map data"); this->paletteWidgetGroup->add(this->paletteNameComboBox); QObject::connect(this->paletteNameComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(applySelections())); /* * Interpolate Colors */ this->interpolateColorsCheckBox = new QCheckBox("Interpolate\nColors"); WuQtUtilities::setToolTipAndStatusTip(this->interpolateColorsCheckBox, "Smooth colors for data between palette colors"); this->paletteWidgetGroup->add(this->interpolateColorsCheckBox); QObject::connect(this->interpolateColorsCheckBox, SIGNAL(toggled(bool)), this, SLOT(applySelections())); /* * Invert palette checkbox */ QLabel* invertLabel = new QLabel("Invert"); this->invertPaletteModeComboBox = new EnumComboBoxTemplate(this); QObject::connect(this->invertPaletteModeComboBox, SIGNAL(itemActivated()), this, SLOT(applySelections())); this->invertPaletteModeComboBox->setup(); const AString invertModeToolTip = ("" "Controls inversion of Palette:

    " " " + PaletteInvertModeEnum::toGuiName(PaletteInvertModeEnum::POSITIVE_WITH_NEGATIVE) + " - Positive and negative sections of the palette are swapped

    " " " + PaletteInvertModeEnum::toGuiName(PaletteInvertModeEnum::POSITIVE_NEGATIVE_SEPARATE) + " - Swaps the negative range within the negative range AND " " swaps the positive range within the positive range" ""); this->invertPaletteModeComboBox->getWidget()->setToolTip(invertModeToolTip); this->paletteWidgetGroup->add(this->invertPaletteModeComboBox->getComboBox()); QWidget* paletteSelectionWidget = new QWidget(); QGridLayout* paletteSelectionLayout = new QGridLayout(paletteSelectionWidget); paletteSelectionLayout->setColumnStretch(0, 0); paletteSelectionLayout->setColumnStretch(1, 0); paletteSelectionLayout->setColumnStretch(2, 100); this->setLayoutSpacingAndMargins(paletteSelectionLayout); paletteSelectionLayout->addWidget(paletteNameLabel, 0, 0); paletteSelectionLayout->addWidget(this->paletteNameComboBox, 0, 1); paletteSelectionLayout->addWidget(this->interpolateColorsCheckBox, 0, 2, 2, 1, Qt::AlignCenter); paletteSelectionLayout->addWidget(invertLabel, 1, 0); paletteSelectionLayout->addWidget(this->invertPaletteModeComboBox->getComboBox(), 1, 1); paletteSelectionWidget->setFixedHeight(paletteSelectionWidget->sizeHint().height()); /* * Color Mapping */ this->scaleAutoRadioButton = new QRadioButton("Full"); this->scaleAutoAbsolutePercentageRadioButton = new QRadioButton("Abs Pct"); this->scaleAutoPercentageRadioButton = new QRadioButton("Percent"); this->scaleFixedRadioButton = new QRadioButton("Fixed"); WuQtUtilities::setToolTipAndStatusTip(this->scaleAutoRadioButton, "Map (most negative, zero, most positive) data values to (-1, 0, 0, 1) in palette"); WuQtUtilities::setToolTipAndStatusTip(this->scaleAutoAbsolutePercentageRadioButton, "Map (most absolute percentiles (NOT percentages) data values to (-1, 0, 0, 1) in palette"); WuQtUtilities::setToolTipAndStatusTip(this->scaleAutoPercentageRadioButton, "Map percentiles (NOT percentages) of (most neg, least neg, least pos, most pos) data values to (-1, 0, 0, 1) in palette"); WuQtUtilities::setToolTipAndStatusTip(this->scaleFixedRadioButton, "Map specified values (most neg, least neg, least pos, most pos) to (-1, 0, 0, 1) in palette"); QButtonGroup* scaleButtonGroup = new QButtonGroup(this); this->paletteWidgetGroup->add(scaleButtonGroup); scaleButtonGroup->addButton(this->scaleAutoRadioButton); scaleButtonGroup->addButton(this->scaleAutoAbsolutePercentageRadioButton); scaleButtonGroup->addButton(this->scaleAutoPercentageRadioButton); scaleButtonGroup->addButton(this->scaleFixedRadioButton); QObject::connect(scaleButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(applyAndUpdate())); /* * Spin box width (fixed may have much larger data values) */ const int percentSpinBoxWidth = 75; const int fixedSpinBoxWidth = 82; /* * Percentage mapping */ this->scaleAutoPercentageNegativeMaximumSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 100.0, 1.0, 2, this, SLOT(scaleAutoPercentageNegativeMaximumValueChanged(double))); WuQtUtilities::setToolTipAndStatusTip(this->scaleAutoPercentageNegativeMaximumSpinBox, "Map percentile (NOT percentage) most negative value to -1.0 in palette"); this->paletteWidgetGroup->add(this->scaleAutoPercentageNegativeMaximumSpinBox); this->scaleAutoPercentageNegativeMaximumSpinBox->setFixedWidth(percentSpinBoxWidth); this->scaleAutoPercentageNegativeMinimumSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 100.0, 1.0, 2, this, SLOT(scaleAutoPercentageNegativeMinimumValueChanged(double))); WuQtUtilities::setToolTipAndStatusTip(this->scaleAutoPercentageNegativeMinimumSpinBox, "Map percentile (NOT percentage) least negative value to 0.0 in palette"); this->paletteWidgetGroup->add(this->scaleAutoPercentageNegativeMinimumSpinBox); this->scaleAutoPercentageNegativeMinimumSpinBox->setFixedWidth(percentSpinBoxWidth); this->scaleAutoPercentagePositiveMinimumSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 100.0, 1.0, 2, this, SLOT(scaleAutoPercentagePositiveMinimumValueChanged(double))); WuQtUtilities::setToolTipAndStatusTip(this->scaleAutoPercentagePositiveMinimumSpinBox, "Map percentile (NOT percentage) least positive value to 0.0 in palette"); this->paletteWidgetGroup->add(this->scaleAutoPercentagePositiveMinimumSpinBox); this->scaleAutoPercentagePositiveMinimumSpinBox->setFixedWidth(percentSpinBoxWidth); this->scaleAutoPercentagePositiveMaximumSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 100.0, 1.0, 2, this, SLOT(scaleAutoPercentagePositiveMaximumValueChanged(double))); WuQtUtilities::setToolTipAndStatusTip(this->scaleAutoPercentagePositiveMaximumSpinBox, "Map percentile (NOT percentage) most positive value to 1.0 in palette"); this->paletteWidgetGroup->add(this->scaleAutoPercentagePositiveMaximumSpinBox); this->scaleAutoPercentagePositiveMaximumSpinBox->setFixedWidth(percentSpinBoxWidth); /* * Absolute percentage mapping */ this->scaleAutoAbsolutePercentageMinimumSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 100.0, 1.0, 2, this, SLOT(scaleAutoAbsolutePercentageMinimumValueChanged(double))); WuQtUtilities::setToolTipAndStatusTip(this->scaleAutoAbsolutePercentageMinimumSpinBox, "Map percentile (NOT percentage) least absolute value to 0.0 in palette"); this->paletteWidgetGroup->add(this->scaleAutoAbsolutePercentageMinimumSpinBox); this->scaleAutoAbsolutePercentageMinimumSpinBox->setFixedWidth(percentSpinBoxWidth); this->scaleAutoAbsolutePercentageMaximumSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 100.0, 1.0, 2, this, SLOT(scaleAutoAbsolutePercentageMaximumValueChanged(double))); WuQtUtilities::setToolTipAndStatusTip(this->scaleAutoAbsolutePercentageMaximumSpinBox, "Map percentile (NOT percentage) most absolute value to 1.0 in palette"); this->paletteWidgetGroup->add(this->scaleAutoAbsolutePercentageMaximumSpinBox); this->scaleAutoAbsolutePercentageMaximumSpinBox->setFixedWidth(percentSpinBoxWidth); /* * Fixed mapping */ this->scaleFixedNegativeMaximumSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(-BIG_NUMBER, 0.0, 1.0, 2, this, SLOT(scaleFixedNegativeMaximumValueChanged(double))); WuQtUtilities::setToolTipAndStatusTip(this->scaleFixedNegativeMaximumSpinBox, "Map this value to -1.0 in palette"); this->paletteWidgetGroup->add(this->scaleFixedNegativeMaximumSpinBox); this->scaleFixedNegativeMaximumSpinBox->setFixedWidth(fixedSpinBoxWidth); this->scaleFixedNegativeMinimumSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(-BIG_NUMBER, 0.0, 1.0, 2, this, SLOT(scaleFixedNegativeMinimumValueChanged(double))); WuQtUtilities::setToolTipAndStatusTip(this->scaleFixedNegativeMinimumSpinBox, "Map this value to 0.0 in palette"); this->paletteWidgetGroup->add(this->scaleFixedNegativeMinimumSpinBox); this->scaleFixedNegativeMinimumSpinBox->setFixedWidth(fixedSpinBoxWidth); this->scaleFixedPositiveMinimumSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, BIG_NUMBER, 1.0, 2, this, SLOT(scaleFixedPositiveMinimumValueChanged(double))); WuQtUtilities::setToolTipAndStatusTip(this->scaleFixedPositiveMinimumSpinBox, "Map this value to 0.0 in palette"); this->paletteWidgetGroup->add(this->scaleFixedPositiveMinimumSpinBox); this->scaleFixedPositiveMinimumSpinBox->setFixedWidth(fixedSpinBoxWidth); this->scaleFixedPositiveMaximumSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, BIG_NUMBER, 1.0, 2, this, SLOT(scaleFixedPositiveMaximumValueChanged(double))); WuQtUtilities::setToolTipAndStatusTip(this->scaleFixedPositiveMaximumSpinBox, "Map this value to 1.0 in palette"); this->paletteWidgetGroup->add(this->scaleFixedPositiveMaximumSpinBox); this->scaleFixedPositiveMaximumSpinBox->setFixedWidth(fixedSpinBoxWidth); /* * Labels for values at palette percentages */ const AString bigText(7, QChar(' ')); this->scaleNegativeMaximumValueLabel = new QLabel(bigText); this->scaleNegativeMinimumValueLabel = new QLabel(bigText); this->scalePositiveMinimumValueLabel = new QLabel(bigText); this->scalePositiveMaximumValueLabel = new QLabel(bigText); /* * Layout widgets */ QWidget* colorMappingWidget = new QWidget(); QGridLayout* colorMappingLayout = new QGridLayout(colorMappingWidget); colorMappingLayout->setColumnStretch(0, 0); colorMappingLayout->setColumnStretch(1, 100); colorMappingLayout->setColumnStretch(2, 100); colorMappingLayout->setColumnStretch(3, 100); colorMappingLayout->setColumnStretch(4, 100); this->setLayoutSpacingAndMargins(colorMappingLayout); colorMappingLayout->addWidget(this->scaleAutoRadioButton, 0, 0, Qt::AlignHCenter); colorMappingLayout->addWidget(this->scaleAutoAbsolutePercentageRadioButton, 0, 1, Qt::AlignHCenter); colorMappingLayout->addWidget(this->scaleAutoPercentageRadioButton, 0, 2, Qt::AlignHCenter); colorMappingLayout->addWidget(this->scaleFixedRadioButton, 0, 3, Qt::AlignHCenter); colorMappingLayout->addWidget(new QLabel("Data"), 0, 4, Qt::AlignRight); colorMappingLayout->addWidget(new QLabel("Pos Max"), 1, 0, Qt::AlignRight); colorMappingLayout->addWidget(new QLabel("Pos Min"), 2, 0, Qt::AlignRight); colorMappingLayout->addWidget(new QLabel("Neg Min"), 3, 0, Qt::AlignRight); colorMappingLayout->addWidget(new QLabel("Neg Max"), 4, 0, Qt::AlignRight); colorMappingLayout->addWidget(this->scaleAutoAbsolutePercentageMaximumSpinBox, 1, 1); colorMappingLayout->addWidget(this->scaleAutoAbsolutePercentageMinimumSpinBox, 2, 1); colorMappingLayout->addWidget(this->scaleAutoPercentagePositiveMaximumSpinBox, 1, 2); colorMappingLayout->addWidget(this->scaleAutoPercentagePositiveMinimumSpinBox, 2, 2); colorMappingLayout->addWidget(this->scaleAutoPercentageNegativeMinimumSpinBox, 3, 2); colorMappingLayout->addWidget(this->scaleAutoPercentageNegativeMaximumSpinBox, 4, 2); colorMappingLayout->addWidget(this->scaleFixedPositiveMaximumSpinBox, 1, 3); colorMappingLayout->addWidget(this->scaleFixedPositiveMinimumSpinBox, 2, 3); colorMappingLayout->addWidget(this->scaleFixedNegativeMinimumSpinBox, 3, 3); colorMappingLayout->addWidget(this->scaleFixedNegativeMaximumSpinBox, 4, 3); colorMappingLayout->addWidget(this->scalePositiveMaximumValueLabel, 1, 4, Qt::AlignRight); colorMappingLayout->addWidget(this->scalePositiveMinimumValueLabel, 2, 4, Qt::AlignRight); colorMappingLayout->addWidget(this->scaleNegativeMinimumValueLabel, 3, 4, Qt::AlignRight); colorMappingLayout->addWidget(this->scaleNegativeMaximumValueLabel, 4, 4, Qt::AlignRight); /* * Display Mode */ this->displayModePositiveCheckBox = new QCheckBox("Positive"); this->paletteWidgetGroup->add(this->displayModePositiveCheckBox); QObject::connect(this->displayModePositiveCheckBox, SIGNAL(toggled(bool)), this, SLOT(applySelections())); this->displayModeZeroCheckBox = new QCheckBox("Zero"); this->paletteWidgetGroup->add(this->displayModeZeroCheckBox); QObject::connect(this->displayModeZeroCheckBox, SIGNAL(toggled(bool)), this, SLOT(applySelections())); this->displayModeNegativeCheckBox = new QCheckBox("Negative"); this->paletteWidgetGroup->add(this->displayModeNegativeCheckBox); QObject::connect(this->displayModeNegativeCheckBox , SIGNAL(toggled(bool)), this, SLOT(applySelections())); WuQtUtilities::setToolTipAndStatusTip(this->displayModePositiveCheckBox, "Enable/Disable the display of positive data"); WuQtUtilities::setToolTipAndStatusTip(this->displayModeZeroCheckBox, "Enable/Disable the display of zero data.\n" "A value in the range [" + AString::number(PaletteColorMapping::SMALL_NEGATIVE, 'f', 6) + ", " + AString::number(PaletteColorMapping::SMALL_POSITIVE, 'f', 6) + "]\n" "is considered to be zero."); WuQtUtilities::setToolTipAndStatusTip(this->displayModeNegativeCheckBox, "Enable/Disable the display of negative data"); QWidget* displayModeWidget = new QWidget(); QHBoxLayout* displayModeLayout = new QHBoxLayout(displayModeWidget); WuQtUtilities::setLayoutSpacingAndMargins(displayModeLayout, 10, 3); displayModeLayout->addWidget(this->displayModeNegativeCheckBox); displayModeLayout->addStretch(); displayModeLayout->addWidget(this->displayModeZeroCheckBox); displayModeLayout->addStretch(); displayModeLayout->addWidget(this->displayModePositiveCheckBox); /* * Layout widgets */ QGroupBox* paletteGroupBox = new QGroupBox("Palette"); QVBoxLayout* paletteLayout = new QVBoxLayout(paletteGroupBox); this->setLayoutSpacingAndMargins(paletteLayout); paletteLayout->addWidget(paletteSelectionWidget); paletteLayout->addWidget(WuQtUtilities::createHorizontalLineWidget()); paletteLayout->addWidget(colorMappingWidget); paletteLayout->addWidget(WuQtUtilities::createHorizontalLineWidget()); paletteLayout->addWidget(displayModeWidget); paletteGroupBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); return paletteGroupBox; } /** * Update contents for editing a map settings for data in a caret * mappable data file. * * @param caretMappableDataFile * Data file containing palette that is edited. * @param mapIndex * Index of map for palette that is edited. */ void MapSettingsPaletteColorMappingWidget::updateEditor(CaretMappableDataFile* caretMappableDataFile, const int32_t mapIndex) { updateEditorInternal(caretMappableDataFile, mapIndex); } /** * Update the threshold section. */ void MapSettingsPaletteColorMappingWidget::updateThresholdSection() { this->thresholdWidgetGroup->blockAllSignals(true); const int32_t numTypes = this->thresholdTypeComboBox->count(); for (int32_t i = 0; i < numTypes; i++) { const int value = this->thresholdTypeComboBox->itemData(i).toInt(); if (value == static_cast(this->paletteColorMapping->getThresholdType())) { this->thresholdTypeComboBox->setCurrentIndex(i); break; } } CaretAssert(this->caretMappableDataFile); this->thresholdMapFileIndexSelector->updateFileAndMapSelector(this->caretMappableDataFile->getMapThresholdFileSelectionModel(this->mapFileIndex)); const bool enableThresholdControls = (this->paletteColorMapping->getThresholdType() != PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF); this->thresholdAdjustmentWidgetGroup->setEnabled(enableThresholdControls); const float lowValue = this->paletteColorMapping->getThresholdMinimum(this->paletteColorMapping->getThresholdType()); const float highValue = this->paletteColorMapping->getThresholdMaximum(this->paletteColorMapping->getThresholdType()); switch (this->paletteColorMapping->getThresholdTest()) { case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE: this->thresholdShowOutsideRadioButton->setChecked(true); break; case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE: this->thresholdShowInsideRadioButton->setChecked(true); break; } const PaletteThresholdRangeModeEnum::Enum thresholdRangeMode = paletteColorMapping->getThresholdRangeMode(); this->thresholdRangeModeComboBox->blockSignals(true); this->thresholdRangeModeComboBox->setSelectedItem(thresholdRangeMode); this->thresholdRangeModeComboBox->blockSignals(false); updateThresholdControlsMinimumMaximumRangeValues(); this->thresholdLowSlider->setValue(lowValue); this->thresholdHighSlider->setValue(highValue); if (allowUpdateOfThresholdLowSpinBox) { this->thresholdLowSpinBox->setValue(lowValue); } if (allowUpdateOfThresholdHighSpinBox) { this->thresholdHighSpinBox->setValue(highValue); } this->thresholdLinkCheckBox->setChecked(this->paletteColorMapping->isThresholdNegMinPosMaxLinked()); this->thresholdAdjustmentWidget->setEnabled(paletteColorMapping->getThresholdType() == PaletteThresholdTypeEnum::THRESHOLD_TYPE_NORMAL); this->thresholdFileWidget->setEnabled(paletteColorMapping->getThresholdType() == PaletteThresholdTypeEnum::THRESHOLD_TYPE_FILE); this->thresholdOutlineDrawingModeComboBox->setSelectedItem(this->paletteColorMapping->getThresholdOutlineDrawingMode()); this->thresholdOutlineDrawingColorComboBox->setSelectedColor(this->paletteColorMapping->getThresholdOutlineDrawingColor()); this->thresholdOutlineDrawingWidget->setEnabled(this->paletteColorMapping->getThresholdType() != PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF); this->thresholdWidgetGroup->blockAllSignals(false); bool enableSetAllMapsButtonFlag = false; if (this->paletteColorMapping->getThresholdType() == PaletteThresholdTypeEnum::THRESHOLD_TYPE_FILE) { if (this->caretMappableDataFile->getNumberOfMaps() > 1) { const CaretMappableDataFile* threshFile = this->caretMappableDataFile->getMapThresholdFileSelectionModel(this->mapFileIndex)->getSelectedFile(); if (threshFile != NULL) { if (threshFile->getNumberOfMaps() > 0) { enableSetAllMapsButtonFlag = true; } } } } this->thresholdSetAllMapsToolButton->setEnabled(enableSetAllMapsButtonFlag); } /** * Update the labels that list values that correspond to the palette * mapping values (percent neg/pos min/max, full, etc). */ void MapSettingsPaletteColorMappingWidget::updatePaletteMappedToDataValueLabels() { if (this->caretMappableDataFile == NULL) { return; } else if (this->mapFileIndex < 0) { return; } FastStatistics* statistics = NULL; switch (this->caretMappableDataFile->getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: statistics = const_cast(this->caretMappableDataFile->getFileFastStatistics()); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: statistics = const_cast(this->caretMappableDataFile->getMapFastStatistics(this->mapFileIndex)); break; } double posMaxLabelValue = 0.0; double posMinLabelValue = 0.0; double negMinLabelValue = 0.0; double negMaxLabelValue = 0.0; if (statistics != NULL) { switch (this->paletteColorMapping->getScaleMode()) { case PaletteScaleModeEnum::MODE_AUTO_SCALE: posMaxLabelValue = statistics->getMostPositiveValue(); posMinLabelValue = 0.0; negMinLabelValue = 0.0; negMaxLabelValue = statistics->getMostNegativeValue(); break; case PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE: posMaxLabelValue = statistics->getApproxPositivePercentile(this->paletteColorMapping->getAutoScaleAbsolutePercentageMaximum()); posMinLabelValue = statistics->getApproxPositivePercentile(this->paletteColorMapping->getAutoScaleAbsolutePercentageMinimum()); negMinLabelValue = -posMinLabelValue; negMaxLabelValue = -posMaxLabelValue; break; case PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE: posMaxLabelValue = statistics->getApproxPositivePercentile(this->paletteColorMapping->getAutoScalePercentagePositiveMaximum()); posMinLabelValue = statistics->getApproxPositivePercentile(this->paletteColorMapping->getAutoScalePercentagePositiveMinimum()); negMinLabelValue = statistics->getApproxNegativePercentile(this->paletteColorMapping->getAutoScalePercentageNegativeMinimum()); negMaxLabelValue = statistics->getApproxNegativePercentile(this->paletteColorMapping->getAutoScalePercentageNegativeMaximum()); break; case PaletteScaleModeEnum::MODE_USER_SCALE: posMaxLabelValue = this->paletteColorMapping->getUserScalePositiveMaximum(); posMinLabelValue = this->paletteColorMapping->getUserScalePositiveMinimum(); negMinLabelValue = this->paletteColorMapping->getUserScaleNegativeMinimum(); negMaxLabelValue = this->paletteColorMapping->getUserScaleNegativeMaximum(); break; } } this->scalePositiveMaximumValueLabel->setText(QString::number(posMaxLabelValue, 'f', 2)); this->scalePositiveMinimumValueLabel->setText(QString::number(posMinLabelValue, 'f', 2)); this->scaleNegativeMinimumValueLabel->setText(QString::number(negMinLabelValue, 'f', 2)); this->scaleNegativeMaximumValueLabel->setText(QString::number(negMaxLabelValue, 'f', 2)); } /** * This PRIVATE method updates the editor content and MUST always be used * when something within this class requires updating the displayed data. * * Update contents for editing a map settings for data in a caret * mappable data file. * * @param caretMappableDataFile * Data file containing palette that is edited. * @param mapIndexIn * Index of map for palette that is edited. */ void MapSettingsPaletteColorMappingWidget::updateEditorInternal(CaretMappableDataFile* caretMappableDataFile, const int32_t mapIndexIn) { this->caretMappableDataFile = caretMappableDataFile; this->mapFileIndex = mapIndexIn; if (this->caretMappableDataFile == NULL) { return; } else if (this->mapFileIndex < 0) { return; } this->paletteWidgetGroup->blockAllSignals(true); const AString title = this->caretMappableDataFile->getFileNameNoPath() + ": " + this->caretMappableDataFile->getMapName(this->mapFileIndex); this->setWindowTitle(title); this->paletteNameComboBox->clear(); this->paletteColorMapping = this->caretMappableDataFile->getMapPaletteColorMapping(this->mapFileIndex); if (this->paletteColorMapping != NULL) { PaletteFile* paletteFile = GuiManager::get()->getBrain()->getPaletteFile(); int defaultIndex = 0; const int32_t numPalettes = paletteFile->getNumberOfPalettes(); for (int32_t i = 0; i < numPalettes; i++) { Palette* palette = paletteFile->getPalette(i); const AString name = palette->getName(); if (name == this->paletteColorMapping->getSelectedPaletteName()) { defaultIndex = i; } this->paletteNameComboBox->addItem(name, name); } if (defaultIndex < this->paletteNameComboBox->count()) { this->paletteNameComboBox->setCurrentIndex(defaultIndex); } bool isPercentageSpinBoxesEnabled = false; bool isAbsolutePercentageSpinBoxesEnabled = false; bool isFixedSpinBoxesEnabled = false; switch (this->paletteColorMapping->getScaleMode()) { case PaletteScaleModeEnum::MODE_AUTO_SCALE: this->scaleAutoRadioButton->setChecked(true); break; case PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE: this->scaleAutoAbsolutePercentageRadioButton->setChecked(true); isAbsolutePercentageSpinBoxesEnabled = true; break; case PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE: this->scaleAutoPercentageRadioButton->setChecked(true); isPercentageSpinBoxesEnabled = true; break; case PaletteScaleModeEnum::MODE_USER_SCALE: this->scaleFixedRadioButton->setChecked(true); isFixedSpinBoxesEnabled = true; break; } this->scaleAutoPercentageNegativeMaximumSpinBox->setValue(this->paletteColorMapping->getAutoScalePercentageNegativeMaximum()); this->scaleAutoPercentageNegativeMinimumSpinBox->setValue(this->paletteColorMapping->getAutoScalePercentageNegativeMinimum()); this->scaleAutoPercentagePositiveMinimumSpinBox->setValue(this->paletteColorMapping->getAutoScalePercentagePositiveMinimum()); this->scaleAutoPercentagePositiveMaximumSpinBox->setValue(this->paletteColorMapping->getAutoScalePercentagePositiveMaximum()); this->scaleAutoPercentageNegativeMaximumSpinBox->setEnabled(isPercentageSpinBoxesEnabled); this->scaleAutoPercentageNegativeMinimumSpinBox->setEnabled(isPercentageSpinBoxesEnabled); this->scaleAutoPercentagePositiveMinimumSpinBox->setEnabled(isPercentageSpinBoxesEnabled); this->scaleAutoPercentagePositiveMaximumSpinBox->setEnabled(isPercentageSpinBoxesEnabled); this->scaleAutoAbsolutePercentageMaximumSpinBox->setValue(this->paletteColorMapping->getAutoScaleAbsolutePercentageMaximum()); this->scaleAutoAbsolutePercentageMinimumSpinBox->setValue(this->paletteColorMapping->getAutoScaleAbsolutePercentageMinimum()); this->scaleAutoAbsolutePercentageMaximumSpinBox->setEnabled(isAbsolutePercentageSpinBoxesEnabled); this->scaleAutoAbsolutePercentageMinimumSpinBox->setEnabled(isAbsolutePercentageSpinBoxesEnabled); this->scaleFixedNegativeMaximumSpinBox->setValue(this->paletteColorMapping->getUserScaleNegativeMaximum()); this->scaleFixedNegativeMinimumSpinBox->setValue(this->paletteColorMapping->getUserScaleNegativeMinimum()); this->scaleFixedPositiveMinimumSpinBox->setValue(this->paletteColorMapping->getUserScalePositiveMinimum()); this->scaleFixedPositiveMaximumSpinBox->setValue(this->paletteColorMapping->getUserScalePositiveMaximum()); this->scaleFixedNegativeMaximumSpinBox->setEnabled(isFixedSpinBoxesEnabled); this->scaleFixedNegativeMinimumSpinBox->setEnabled(isFixedSpinBoxesEnabled); this->scaleFixedPositiveMinimumSpinBox->setEnabled(isFixedSpinBoxesEnabled); this->scaleFixedPositiveMaximumSpinBox->setEnabled(isFixedSpinBoxesEnabled); this->displayModePositiveCheckBox->setChecked(this->paletteColorMapping->isDisplayPositiveDataFlag()); this->displayModeZeroCheckBox->setChecked(this->paletteColorMapping->isDisplayZeroDataFlag()); this->displayModeNegativeCheckBox->setChecked(this->paletteColorMapping->isDisplayNegativeDataFlag()); this->interpolateColorsCheckBox->setChecked(this->paletteColorMapping->isInterpolatePaletteFlag()); this->invertPaletteModeComboBox->setSelectedItem(this->paletteColorMapping->getInvertedMode()); m_histogramBarsColorComboBox->setSelectedColor(this->paletteColorMapping->getHistogramBarsColor()); m_histogramEnvelopeColorComboBox->setSelectedColor(this->paletteColorMapping->getHistogramEnvelopeColor()); m_histogramEnvelopeLineWidthPercentageSpinBox->setValue(this->paletteColorMapping->getHistogramEnvelopeLineWidthPercentage()); m_histogramBarsVisibleCheckBox->setChecked(this->paletteColorMapping->isHistogramBarsVisible()); m_histogramEnvelopeVisibleCheckBox->setChecked(this->paletteColorMapping->isHistogramEnvelopeVisible()); m_histogramHorizontalRangeComboBox->setSelectedItem(this->paletteColorMapping->getHistogramRangeMode()); updatePaletteMappedToDataValueLabels(); updateThresholdSection(); float minValue = 0.0; float maxValue = 0.0; m_histogramBucketsSpinBox->blockSignals(true); switch (this->caretMappableDataFile->getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: m_histogramBucketsSpinBox->setValue(this->caretMappableDataFile->getFileHistogramNumberOfBuckets()); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: m_histogramBucketsSpinBox->setValue(this->paletteColorMapping->getHistogramNumberOfBuckets()); break; } m_histogramBucketsSpinBox->blockSignals(false); FastStatistics* statistics = NULL; switch (this->caretMappableDataFile->getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: statistics = const_cast(this->caretMappableDataFile->getFileFastStatistics()); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: statistics = const_cast(this->caretMappableDataFile->getMapFastStatistics(this->mapFileIndex)); break; } if (statistics != NULL) { minValue = statistics->getMin(); maxValue = statistics->getMax(); } /* * Set fixed spin boxes so that they increment by 1% of data. */ float stepValue = 1.0; const float diff = maxValue - minValue; if (diff > 0.0) { stepValue = diff / 100.0; } this->scaleFixedNegativeMaximumSpinBox->setSingleStep(stepValue); this->scaleFixedNegativeMinimumSpinBox->setSingleStep(stepValue); this->scaleFixedPositiveMinimumSpinBox->setSingleStep(stepValue); this->scaleFixedPositiveMaximumSpinBox->setSingleStep(stepValue); } m_paletteOptionsWidget->updateEditor(this->caretMappableDataFile, this->mapFileIndex); this->updateHistogramPlot(); this->updateNormalizationControlSection(); this->paletteWidgetGroup->blockAllSignals(false); } /** * Get histogram for displaying data * @param statisticsForAll * Statistics for all data. * @param * Histogram. */ const Histogram* MapSettingsPaletteColorMappingWidget::getHistogram(const FastStatistics* statisticsForAll) const { float mostPos = 0.0; float leastPos = 0.0; float leastNeg = 0.0; float mostNeg = 0.0; bool matchFlag = false; switch (this->paletteColorMapping->getHistogramRangeMode()) { case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL: { float dummy; statisticsForAll->getNonzeroRanges(mostNeg, dummy, dummy, mostPos); } break; case PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE: { matchFlag = true; switch (this->paletteColorMapping->getScaleMode()) { case PaletteScaleModeEnum::MODE_AUTO_SCALE: mostPos = statisticsForAll->getMax(); leastPos = 0.0; leastNeg = 0.0; mostNeg = statisticsForAll->getMin(); break; case PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE: mostPos = statisticsForAll->getApproxAbsolutePercentile(this->scaleAutoAbsolutePercentageMaximumSpinBox->value()); leastPos = statisticsForAll->getApproxAbsolutePercentile(this->scaleAutoAbsolutePercentageMinimumSpinBox->value()); leastNeg = -statisticsForAll->getApproxAbsolutePercentile(this->scaleAutoAbsolutePercentageMinimumSpinBox->value()); mostNeg = -statisticsForAll->getApproxAbsolutePercentile(this->scaleAutoAbsolutePercentageMaximumSpinBox->value()); break; case PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE: mostPos = statisticsForAll->getApproxPositivePercentile(this->scaleAutoPercentagePositiveMaximumSpinBox->value()); leastPos = statisticsForAll->getApproxPositivePercentile(this->scaleAutoPercentagePositiveMinimumSpinBox->value()); leastNeg = statisticsForAll->getApproxNegativePercentile(this->scaleAutoPercentageNegativeMinimumSpinBox->value()); mostNeg = statisticsForAll->getApproxNegativePercentile(this->scaleAutoPercentageNegativeMaximumSpinBox->value()); break; case PaletteScaleModeEnum::MODE_USER_SCALE: mostPos = this->scaleFixedPositiveMaximumSpinBox->value(); leastPos = this->scaleFixedPositiveMinimumSpinBox->value(); leastNeg = this->scaleFixedNegativeMinimumSpinBox->value(); mostNeg = this->scaleFixedNegativeMaximumSpinBox->value(); break; } } break; } const PaletteNormalizationModeEnum::Enum normMode = this->caretMappableDataFile->getPaletteNormalizationMode(); /* * Remove data that is not displayed */ bool isZeroIncluded = true; const Histogram* ret = NULL; if (matchFlag) { isZeroIncluded = this->displayModeZeroCheckBox->isChecked(); if (this->displayModeNegativeCheckBox->isChecked() == false) { mostNeg = 0.0; leastNeg = 0.0; } if (this->displayModePositiveCheckBox->isChecked() == false) { mostPos = 0.0; leastPos = 0.0; } switch (normMode) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: ret = this->caretMappableDataFile->getFileHistogram(mostPos, leastPos, leastNeg, mostNeg, isZeroIncluded); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: ret = this->caretMappableDataFile->getMapHistogram(this->mapFileIndex, mostPos, leastPos, leastNeg, mostNeg, isZeroIncluded); break; } } else { switch (normMode) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: ret = caretMappableDataFile->getFileHistogram(); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: ret = caretMappableDataFile->getMapHistogram(this->mapFileIndex); break; } } CaretAssert(ret); return ret; } /** * Update the histogram plot. */ void MapSettingsPaletteColorMappingWidget::updateHistogramPlot() { /* * Remove all previously attached items from the histogram plot. * The items are automatically deleted by the plot. */ this->thresholdPlot->detachItems(); if (this->paletteColorMapping == NULL) { return; } FastStatistics* statistics = NULL; switch (this->caretMappableDataFile->getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: statistics = const_cast(this->caretMappableDataFile->getFileFastStatistics()); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: statistics = const_cast(this->caretMappableDataFile->getMapFastStatistics(this->mapFileIndex)); break; } if (statistics == NULL) { return; } if (this->paletteColorMapping->isHistogramBarsVisible() || this->paletteColorMapping->isHistogramEnvelopeVisible()) { /* okay */ } else { /* nothing to display */ return; } /* * Data values table */ const float statsMean = statistics->getMean(); const float statsStdDev = statistics->getSampleStdDev(); const float statsMin = statistics->getMin(); const float statsMax = statistics->getMax(); this->statisticsMeanValueLabel->setText(QString::number(statsMean, 'f', 4)); this->statisticsStandardDeviationLabel->setText(QString::number(statsStdDev, 'f', 4)); this->statisticsMaximumValueLabel->setText(QString::number(statsMax, 'f', 4)); this->statisticsMinimumValueLabel->setText(QString::number(statsMin, 'f', 4)); /* * Get data for this histogram. */ const Histogram* myHist = getHistogram(statistics); float minValue, maxValue; myHist->getRange(minValue, maxValue); const std::vector& displayDataReference = myHist->getHistogramDisplay(); std::vector displayData = displayDataReference; const int64_t numHistogramValues = (int64_t)(displayData.size()); /* * Width of each 'bar' in the histogram */ float step = 1.0; if (numHistogramValues > 1) { step = ((maxValue - minValue) / numHistogramValues); } const CaretColorEnum::Enum histogramBarsColor = paletteColorMapping->getHistogramBarsColor(); const CaretColorEnum::Enum histogramEnvelopeColor = paletteColorMapping->getHistogramEnvelopeColor(); float* dataValues = NULL; float* dataRGBA = NULL; if (numHistogramValues > 0) { /* * Compute color for 'bar' in the histogram. * Note that number of data values is one more * than the number of histogram values due to that * a data value is needed on the right of the last * histogram bar. Otherwise, if there is an outlier * value, the histogram will not be drawn * correctly. */ const int64_t numDataValues = numHistogramValues + 1; dataValues = new float[numDataValues]; dataRGBA = new float[numDataValues * 4]; for (int64_t ix = 0; ix < numDataValues; ix++) { const float value = (minValue + (ix * step)); dataValues[ix] = value; } dataValues[0] = minValue; dataValues[numDataValues - 1] = maxValue; /* * Color with palette so that alpha values are zero for regions not displayed */ NodeAndVoxelColoring::colorScalarsWithPalette(statistics, paletteColorMapping, dataValues, paletteColorMapping, dataValues, numDataValues, dataRGBA, true); /* ignore thresholding */ /* * If bucket is not colored (zero alpha) set bucket height to zero */ for (int32_t i = 0; i < numHistogramValues; i++) { const int32_t alphaIndex = i * 4 + 3; CaretAssertArrayIndex(dataRGBA, (numDataValues * 4), alphaIndex); if (dataRGBA[alphaIndex] <= 0.0) { CaretAssertVectorIndex(displayData, i); displayData[i] = 0.0; } } } float z = 0.0; float maxDataFrequency = 0.0; for (int32_t drawModeInt = 0; drawModeInt < 2; drawModeInt++) { bool drawBarsFlag = false; bool drawEnvelopeFlag = false; if (drawModeInt == 0) { drawBarsFlag = this->paletteColorMapping->isHistogramBarsVisible(); } else if (drawModeInt == 1) { drawEnvelopeFlag = this->paletteColorMapping->isHistogramEnvelopeVisible(); } if (drawBarsFlag || drawEnvelopeFlag) { float barsSolidRGBA[4]; CaretColorEnum::toRGBAFloat(histogramBarsColor, barsSolidRGBA); float envelopeSolidRGBA[4]; CaretColorEnum::toRGBAFloat(histogramEnvelopeColor, envelopeSolidRGBA); const int32_t lastIndex = numHistogramValues - 1; for (int64_t ix = 0; ix < numHistogramValues; ix++) { QColor color; const int64_t ix4 = ix * 4; if (drawBarsFlag) { if (histogramBarsColor == CaretColorEnum::CUSTOM) { color.setRedF(dataRGBA[ix4]); color.setGreenF(dataRGBA[ix4+1]); color.setBlueF(dataRGBA[ix4+2]); color.setAlphaF(1.0); } else { color.setRgbF(barsSolidRGBA[0], barsSolidRGBA[1], barsSolidRGBA[2]); } } else if (drawEnvelopeFlag) { if (histogramEnvelopeColor == CaretColorEnum::CUSTOM) { color.setRedF(dataRGBA[ix4]); color.setGreenF(dataRGBA[ix4+1]); color.setBlueF(dataRGBA[ix4+2]); color.setAlphaF(1.0); } else { color.setRgbF(envelopeSolidRGBA[0], envelopeSolidRGBA[1], envelopeSolidRGBA[2]); } } else { CaretAssert(0); } const float startValue = dataValues[ix]; const float stopValue = dataValues[ix + 1]; float dataFrequency = displayData[ix]; bool displayIt = true; if (dataFrequency > maxDataFrequency) { maxDataFrequency = dataFrequency; } /* * If color is not displayed ('none' or thresholded), * set its frequncey value to a small value so that the plot * retains its shape and color is still slightly visible */ if (dataRGBA[ix4+3] <= 0.0) { displayIt = false; } if ( ! displayIt) { if (drawBarsFlag) { color.setAlpha(0); } if (drawEnvelopeFlag) { dataFrequency = 0.0f; } } QVector samples; QwtPlotCurve* curve = new QwtPlotCurve(); curve->setRenderHint(QwtPlotItem::RenderAntialiased); curve->setVisible(true); curve->setPen(QPen(color)); if (drawBarsFlag) { curve->setStyle(QwtPlotCurve::Steps); curve->setBrush(QBrush(color)); samples.push_back(QPointF(startValue, dataFrequency)); samples.push_back(QPointF(stopValue, dataFrequency)); } if (drawEnvelopeFlag) { curve->setStyle(QwtPlotCurve::Lines); static float lastX = 0.0f; static float lastY = 0.0f; /* * Left side */ if (ix == 0) { samples.push_back(QPointF(startValue, 0.0)); samples.push_back(QPointF(startValue, dataFrequency)); lastX = startValue; lastY = dataFrequency; } else { CaretAssertVectorIndex(displayData, ix - 1); const float lastValue = dataValues[ix - 1]; const float halfX = (startValue - lastValue) / 2.0f; const float x = startValue + halfX; const float y = dataFrequency; samples.push_back(QPointF(lastX, lastY)); samples.push_back(QPointF(x, y)); lastX = x; lastY = y; } /* * Right side */ if (ix == lastIndex) { samples.push_back(QPointF(stopValue, dataFrequency)); samples.push_back(QPointF(stopValue, 0.0)); lastX = stopValue; lastY = 0.0f; } } curve->setSamples(samples); curve->attach(this->thresholdPlot); if (ix == 0) { z = curve->z(); } } } z--; } z--; if ((numHistogramValues > 2) && (this->paletteColorMapping->getThresholdType() == PaletteThresholdTypeEnum::THRESHOLD_TYPE_NORMAL)) { float threshMinValue = this->paletteColorMapping->getThresholdNormalMinimum(); float threshMaxValue = this->paletteColorMapping->getThresholdNormalMaximum(); maxDataFrequency *= 1.05; switch (this->paletteColorMapping->getThresholdTest()) { case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE: { const float plotMinValue = this->thresholdPlot->axisScaleDiv(QwtPlot::xBottom).lowerBound(); const float plotMaxValue = this->thresholdPlot->axisScaleDiv(QwtPlot::xBottom).upperBound(); /* * Draw shaded region to left of minimum threshold */ QVector minSamples; minSamples.push_back(QPointF(plotMinValue, maxDataFrequency)); minSamples.push_back(QPointF(threshMinValue, maxDataFrequency)); QwtPlotCurve* minBox = new QwtPlotCurve(); minBox->setRenderHint(QwtPlotItem::RenderAntialiased); minBox->setVisible(true); minBox->setStyle(QwtPlotCurve::Dots); QColor minColor(100, 100, 255, 160); minBox->setBrush(QBrush(minColor, Qt::Dense4Pattern)); minBox->setPen(QPen(minColor)); minBox->setSamples(minSamples); minBox->setZ(z); minBox->attach(this->thresholdPlot); /* * Draw shaded region to right of maximum threshold */ QVector maxSamples; maxSamples.push_back(QPointF(threshMaxValue, maxDataFrequency)); maxSamples.push_back(QPointF(plotMaxValue, maxDataFrequency)); QwtPlotCurve* maxBox = new QwtPlotCurve(); maxBox->setRenderHint(QwtPlotItem::RenderAntialiased); maxBox->setVisible(true); maxBox->setStyle(QwtPlotCurve::Dots); QColor maxColor(100, 100, 255, 160); maxBox->setBrush(QBrush(maxColor, Qt::Dense4Pattern)); maxBox->setPen(QPen(maxColor)); maxBox->setSamples(maxSamples); maxBox->setZ(z); maxBox->attach(this->thresholdPlot); } break; case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE: { /* * Draw shaded region between minimum and maximum threshold */ QVector minSamples; minSamples.push_back(QPointF(threshMinValue, maxDataFrequency)); minSamples.push_back(QPointF(threshMaxValue, maxDataFrequency)); QwtPlotCurve* minBox = new QwtPlotCurve(); minBox->setRenderHint(QwtPlotItem::RenderAntialiased); minBox->setVisible(true); QColor minColor(100, 100, 255, 160); minBox->setBrush(QBrush(minColor)); minBox->setPen(QPen(minColor)); minBox->setSamples(minSamples); minBox->setZ(z); minBox->attach(this->thresholdPlot); } break; } const bool showLinesFlag = false; if (showLinesFlag) { /* * Line for high threshold */ QVector minSamples; minSamples.push_back(QPointF(threshMinValue, 0)); minSamples.push_back(QPointF(threshMinValue, maxDataFrequency)); QwtPlotCurve* minLine = new QwtPlotCurve(); minLine->setRenderHint(QwtPlotItem::RenderAntialiased); minLine->setVisible(true); minLine->setStyle(QwtPlotCurve::Lines); QColor minColor(0.0, 0.0, 1.0); minLine->setPen(QPen(minColor)); minLine->setSamples(minSamples); minLine->setZ(1.0); minLine->attach(this->thresholdPlot); /* * Line for high threshold */ QVector maxSamples; maxSamples.push_back(QPointF(threshMaxValue, 0)); maxSamples.push_back(QPointF(threshMaxValue, maxDataFrequency)); QwtPlotCurve* maxLine = new QwtPlotCurve(); maxLine->setRenderHint(QwtPlotItem::RenderAntialiased); maxLine->setVisible(true); maxLine->setStyle(QwtPlotCurve::Lines); QColor maxColor(1.0, 0.0, 0.0); maxLine->setPen(QPen(maxColor)); maxLine->setSamples(maxSamples); maxLine->setZ(1.0); maxLine->attach(this->thresholdPlot); } } if (dataValues != NULL) { delete[] dataValues; } if (dataRGBA != NULL) { delete[] dataRGBA; } /* * Causes updates of plots. */ this->thresholdPlot->replot(); } /** * Called to apply selections. */ void MapSettingsPaletteColorMappingWidget::applySelections() { if (this->caretMappableDataFile == NULL) { return; } else if (this->mapFileIndex < 0) { return; } const int itemIndex = this->paletteNameComboBox->currentIndex(); if (itemIndex >= 0) { const AString name = this->paletteNameComboBox->itemData(itemIndex).toString(); if (this->paletteColorMapping != NULL) { this->paletteColorMapping->setSelectedPaletteName(name); } } if (this->scaleAutoRadioButton->isChecked()) { this->paletteColorMapping->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE); } else if (this->scaleAutoAbsolutePercentageRadioButton->isChecked()) { this->paletteColorMapping->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE); } else if (this->scaleAutoPercentageRadioButton->isChecked()) { this->paletteColorMapping->setScaleMode(PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE); } else if (this->scaleFixedRadioButton->isChecked()) { this->paletteColorMapping->setScaleMode(PaletteScaleModeEnum::MODE_USER_SCALE); } this->paletteColorMapping->setUserScaleNegativeMaximum(this->scaleFixedNegativeMaximumSpinBox->value()); this->paletteColorMapping->setUserScaleNegativeMinimum(this->scaleFixedNegativeMinimumSpinBox->value()); this->paletteColorMapping->setUserScalePositiveMinimum(this->scaleFixedPositiveMinimumSpinBox->value()); this->paletteColorMapping->setUserScalePositiveMaximum(this->scaleFixedPositiveMaximumSpinBox->value()); this->paletteColorMapping->setAutoScalePercentageNegativeMaximum(this->scaleAutoPercentageNegativeMaximumSpinBox->value()); this->paletteColorMapping->setAutoScalePercentageNegativeMinimum(this->scaleAutoPercentageNegativeMinimumSpinBox->value()); this->paletteColorMapping->setAutoScalePercentagePositiveMinimum(this->scaleAutoPercentagePositiveMinimumSpinBox->value()); this->paletteColorMapping->setAutoScalePercentagePositiveMaximum(this->scaleAutoPercentagePositiveMaximumSpinBox->value()); this->paletteColorMapping->setAutoScaleAbsolutePercentageMaximum(this->scaleAutoAbsolutePercentageMaximumSpinBox->value()); this->paletteColorMapping->setAutoScaleAbsolutePercentageMinimum(this->scaleAutoAbsolutePercentageMinimumSpinBox->value()); this->paletteColorMapping->setDisplayPositiveDataFlag(this->displayModePositiveCheckBox->isChecked()); this->paletteColorMapping->setDisplayNegativeDataFlag(this->displayModeNegativeCheckBox->isChecked()); this->paletteColorMapping->setDisplayZeroDataFlag(this->displayModeZeroCheckBox->isChecked()); this->paletteColorMapping->setInterpolatePaletteFlag(this->interpolateColorsCheckBox->isChecked()); this->paletteColorMapping->setInvertedMode(this->invertPaletteModeComboBox->getSelectedItem()); this->paletteColorMapping->setHistogramBarsColor(m_histogramBarsColorComboBox->getSelectedColor()); this->paletteColorMapping->setHistogramEnvelopeColor(m_histogramEnvelopeColorComboBox->getSelectedColor()); this->paletteColorMapping->setHistogramEnvelopeLineWidthPercentage(m_histogramEnvelopeLineWidthPercentageSpinBox->value()); this->paletteColorMapping->setHistogramBarsVisible(m_histogramBarsVisibleCheckBox->isChecked()); this->paletteColorMapping->setHistogramEnvelopeVisible(m_histogramEnvelopeVisibleCheckBox->isChecked()); this->paletteColorMapping->setHistogramRangeMode(m_histogramHorizontalRangeComboBox->getSelectedItem()); switch (this->caretMappableDataFile->getPaletteNormalizationMode()) { case PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA: this->caretMappableDataFile->setFileHistogramNumberOfBuckets(m_histogramBucketsSpinBox->value()); break; case PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA: this->paletteColorMapping->setHistogramNumberOfBuckets(m_histogramBucketsSpinBox->value()); break; } float lowValue = this->thresholdLowSpinBox->value(); float highValue = this->thresholdHighSpinBox->value(); const int thresholdTypeIndex = this->thresholdTypeComboBox->currentIndex(); PaletteThresholdTypeEnum::Enum paletteThresholdType = static_cast(this->thresholdTypeComboBox->itemData(thresholdTypeIndex).toInt()); this->paletteColorMapping->setThresholdType(paletteThresholdType); this->paletteColorMapping->setThresholdMinimum(paletteThresholdType, lowValue); this->paletteColorMapping->setThresholdMaximum(paletteThresholdType, highValue); if (this->thresholdShowInsideRadioButton->isChecked()) { this->paletteColorMapping->setThresholdTest(PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE); } else if (this->thresholdShowOutsideRadioButton->isChecked()) { this->paletteColorMapping->setThresholdTest(PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE); } this->paletteColorMapping->setThresholdOutlineDrawingMode(this->thresholdOutlineDrawingModeComboBox->getSelectedItem()); this->paletteColorMapping->setThresholdOutlineDrawingColor(this->thresholdOutlineDrawingColorComboBox->getSelectedColor()); this->updateHistogramPlot(); m_paletteOptionsWidget->applyOptions(); } /** * Set the layout margins. * @param layout * Layout for which margins are set. */ void MapSettingsPaletteColorMappingWidget::setLayoutSpacingAndMargins(QLayout* layout) { WuQtUtilities::setLayoutSpacingAndMargins(layout, 5, 3); } /** * @return The normalization control section. */ QWidget* MapSettingsPaletteColorMappingWidget::createNormalizationControlSection() { m_normalizationModeComboBox = new QComboBox(); QObject::connect(m_normalizationModeComboBox, SIGNAL(activated(int)), this, SLOT(normalizationModeComboBoxActivated(int))); /* * Initially load with all modes so that the combo box can * be set to a fixed size that allows display of all text */ std::vector allModes; PaletteNormalizationModeEnum::getAllEnums(allModes); for (std::vector::iterator allModesIter = allModes.begin(); allModesIter != allModes.end(); allModesIter++) { const PaletteNormalizationModeEnum::Enum normalMode = *allModesIter; m_normalizationModeComboBox->addItem(PaletteNormalizationModeEnum::toGuiName(normalMode), (int)PaletteNormalizationModeEnum::toIntegerCode(normalMode)); } m_normalizationModeComboBox->setToolTip(PaletteNormalizationModeEnum::getEnumToolTopInHTML()); QGroupBox* groupBox = new QGroupBox("Data Normalization"); QVBoxLayout* layout = new QVBoxLayout(groupBox); layout->addWidget(m_normalizationModeComboBox); groupBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); return groupBox; } /** * Update the normalization control section. */ void MapSettingsPaletteColorMappingWidget::updateNormalizationControlSection() { m_normalizationModeComboBox->clear(); std::vector validModes; if (this->caretMappableDataFile != NULL) { this->caretMappableDataFile->getPaletteNormalizationModesSupported(validModes); const int32_t numValidModes = static_cast(validModes.size()); if (numValidModes > 0) { const PaletteNormalizationModeEnum::Enum selectedMode = this->caretMappableDataFile->getPaletteNormalizationMode(); int selectedModeIndex = -1; /* * Loop through ALL modes so that the selections are always * in a consistent order. */ std::vector allModes; PaletteNormalizationModeEnum::getAllEnums(allModes); for (std::vector::iterator allModesIter = allModes.begin(); allModesIter != allModes.end(); allModesIter++) { const PaletteNormalizationModeEnum::Enum normalMode = *allModesIter; if (std::find(validModes.begin(), validModes.end(), normalMode) != validModes.end()) { if (selectedMode == normalMode) { selectedModeIndex = m_normalizationModeComboBox->count(); } m_normalizationModeComboBox->addItem(PaletteNormalizationModeEnum::toGuiName(normalMode), (int)PaletteNormalizationModeEnum::toIntegerCode(normalMode)); } } if (selectedModeIndex >= 0) { m_normalizationModeComboBox->setCurrentIndex(selectedModeIndex); } } } } /** * Called when normalization combo box is changed by user. */ void MapSettingsPaletteColorMappingWidget::normalizationModeComboBoxActivated(int) { if (this->caretMappableDataFile != NULL) { const int selectedIndex = m_normalizationModeComboBox->currentIndex(); if ((selectedIndex >= 0) && (selectedIndex < m_normalizationModeComboBox->count())) { const int32_t enumIntegerCode = m_normalizationModeComboBox->itemData(selectedIndex).toInt(); bool validFlag = false; const PaletteNormalizationModeEnum::Enum mode = PaletteNormalizationModeEnum::fromIntegerCode(enumIntegerCode, &validFlag); if (validFlag) { if (mode != this->caretMappableDataFile->getPaletteNormalizationMode()) { bool doItFlag = true; if (mode == PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA) { doItFlag = WuQMessageBox::warningLargeFileSizeOkCancel(m_normalizationModeComboBox, this->caretMappableDataFile); } if (doItFlag) { CursorDisplayScoped cursor; cursor.showCursor(Qt::WaitCursor); this->caretMappableDataFile->setPaletteNormalizationMode(mode); this->updateEditorInternal(this->caretMappableDataFile, this->mapFileIndex); m_paletteOptionsWidget->applyOptions(); } else { this->updateNormalizationControlSection(); } } } } } } connectome-workbench-1.4.2/src/GuiQt/MapSettingsPaletteColorMappingWidget.h000066400000000000000000000211261360521144700270620ustar00rootroot00000000000000#ifndef __MAP_SETTINGS_PALETTE_COLOR_MAPPING_WIDGET_H_ #define __MAP_SETTINGS_PALETTE_COLOR_MAPPING_WIDGET_H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include // needed by windows #include #include class QAbstractButton; class QCheckBox; class QDoubleSpinBox; class QComboBox; class QLabel; class QLayout; class QPushButton; class QRadioButton; class QSpinBox; class QToolButton; class QwtPlot; namespace caret { class CaretColorEnumComboBox; class CaretMappableDataFileAndMapSelectorObject; class CaretMappableDataFile; class EnumComboBoxTemplate; class FastStatistics; class Histogram; class MapSettingsColorBarPaletteOptionsWidget; class PaletteColorMapping; class WuQDoubleSlider; class WuQDoubleSpinBox; class WuQWidgetObjectGroup; class WuQwtPlot; class MapSettingsPaletteColorMappingWidget : public QWidget { Q_OBJECT public: MapSettingsPaletteColorMappingWidget(QWidget* parent = 0); void updateEditor(CaretMappableDataFile* caretMappableDataFile, const int32_t mapIndex); virtual ~MapSettingsPaletteColorMappingWidget(); void updateWidget(); private: MapSettingsPaletteColorMappingWidget(const MapSettingsPaletteColorMappingWidget&); MapSettingsPaletteColorMappingWidget& operator=(const MapSettingsPaletteColorMappingWidget&); private slots: void thresholdLowSpinBoxValueChanged(double); void thresholdHighSpinBoxValueChanged(double); void thresholdLowSliderValueChanged(double); void thresholdHighSliderValueChanged(double); void thresholdTypeChanged(int); void thresholdRangeModeChanged(); void thresholdLinkCheckBoxToggled(bool); void thresholdMapFileIndexSelectorChanged(); void thresholdSetAllMapsToolButtonClicked(); void scaleAutoPercentageNegativeMaximumValueChanged(double value); void scaleAutoPercentageNegativeMinimumValueChanged(double value); void scaleAutoPercentagePositiveMinimumValueChanged(double value); void scaleAutoPercentagePositiveMaximumValueChanged(double value); void scaleAutoAbsolutePercentageMinimumValueChanged(double value); void scaleAutoAbsolutePercentageMaximumValueChanged(double value); void scaleFixedNegativeMaximumValueChanged(double value); void scaleFixedNegativeMinimumValueChanged(double value); void scaleFixedPositiveMinimumValueChanged(double value); void scaleFixedPositiveMaximumValueChanged(double value); void histogramResetViewButtonClicked(); void applyAndUpdate(); void applySelections(); void contextMenuDisplayRequested(QContextMenuEvent* event, float graphX, float graphY); void normalizationModeComboBoxActivated(int); private: void updateEditorInternal(CaretMappableDataFile* caretMappableDataFile, const int32_t mapIndex); QWidget* createPaletteSection(); QWidget* createThresholdSection(); void updateThresholdSection(); QWidget* createHistogramSection(); QWidget* createHistogramControlSection(); QWidget* createNormalizationControlSection(); void updateNormalizationControlSection(); void updateAfterThresholdValuesChanged(const float lowThreshold, const float highThreshold); void updateHistogramPlot(); void updateThresholdControlsMinimumMaximumRangeValues(); void updatePaletteMappedToDataValueLabels(); void setLayoutSpacingAndMargins(QLayout* layout); const Histogram* getHistogram(const FastStatistics* statisticsForAll) const; PaletteColorMapping* paletteColorMapping; QComboBox* paletteNameComboBox; QRadioButton* scaleAutoRadioButton; QRadioButton* scaleAutoAbsolutePercentageRadioButton; QRadioButton* scaleAutoPercentageRadioButton; QRadioButton* scaleFixedRadioButton; QDoubleSpinBox* scaleAutoPercentageNegativeMaximumSpinBox; QDoubleSpinBox* scaleAutoPercentageNegativeMinimumSpinBox; QDoubleSpinBox* scaleAutoPercentagePositiveMinimumSpinBox; QDoubleSpinBox* scaleAutoPercentagePositiveMaximumSpinBox; QDoubleSpinBox* scaleAutoAbsolutePercentageMinimumSpinBox; QDoubleSpinBox* scaleAutoAbsolutePercentageMaximumSpinBox; QDoubleSpinBox* scaleFixedNegativeMaximumSpinBox; QDoubleSpinBox* scaleFixedNegativeMinimumSpinBox; QDoubleSpinBox* scaleFixedPositiveMinimumSpinBox; QDoubleSpinBox* scaleFixedPositiveMaximumSpinBox; QLabel* scaleNegativeMaximumValueLabel; QLabel* scaleNegativeMinimumValueLabel; QLabel* scalePositiveMinimumValueLabel; QLabel* scalePositiveMaximumValueLabel; QCheckBox* displayModePositiveCheckBox; QCheckBox* displayModeZeroCheckBox; QCheckBox* displayModeNegativeCheckBox; QCheckBox* interpolateColorsCheckBox; EnumComboBoxTemplate* invertPaletteModeComboBox; QWidget* thresholdOutlineDrawingWidget; EnumComboBoxTemplate* thresholdOutlineDrawingModeComboBox; CaretColorEnumComboBox* thresholdOutlineDrawingColorComboBox; QComboBox* thresholdTypeComboBox; QToolButton* thresholdSetAllMapsToolButton; CaretMappableDataFileAndMapSelectorObject* thresholdMapFileIndexSelector; QWidget* thresholdFileWidget; WuQDoubleSlider* thresholdLowSlider; WuQDoubleSlider* thresholdHighSlider; WuQWidgetObjectGroup* thresholdAdjustmentWidgetGroup; QDoubleSpinBox* thresholdLowSpinBox; QDoubleSpinBox* thresholdHighSpinBox; bool allowUpdateOfThresholdLowSpinBox; bool allowUpdateOfThresholdHighSpinBox; QRadioButton* thresholdShowInsideRadioButton; QRadioButton* thresholdShowOutsideRadioButton; QWidget* thresholdAdjustmentWidget; EnumComboBoxTemplate* thresholdRangeModeComboBox; QCheckBox* thresholdLinkCheckBox; WuQwtPlot* thresholdPlot; QLabel* statisticsMinimumValueLabel; QLabel* statisticsMaximumValueLabel; QLabel* statisticsMeanValueLabel; QLabel* statisticsStandardDeviationLabel; QComboBox* m_normalizationModeComboBox; EnumComboBoxTemplate* m_histogramHorizontalRangeComboBox; CaretColorEnumComboBox* m_histogramBarsColorComboBox; CaretColorEnumComboBox* m_histogramEnvelopeColorComboBox; WuQDoubleSpinBox* m_histogramEnvelopeLineWidthPercentageSpinBox; QCheckBox* m_histogramBarsVisibleCheckBox; QCheckBox* m_histogramEnvelopeVisibleCheckBox; QSpinBox* m_histogramBucketsSpinBox; CaretMappableDataFile* caretMappableDataFile; int32_t mapFileIndex; std::set previousApplyPaletteToMapFilesSelected; WuQWidgetObjectGroup* paletteWidgetGroup; WuQWidgetObjectGroup* thresholdWidgetGroup; MapSettingsColorBarPaletteOptionsWidget* m_paletteOptionsWidget; }; #ifdef __MAP_SETTINGS_PALETTE_COLOR_MAPPING_WIDGET_DECLARE__ // #endif // __MAP_SETTINGS_PALETTE_COLOR_MAPPING_WIDGET_DECLARE__ } // namespace #endif //__MAP_SETTINGS_PALETTE_COLOR_MAPPING_WIDGET_H_ connectome-workbench-1.4.2/src/GuiQt/MapSettingsParcelsWidget.cxx000066400000000000000000000110461360521144700251150ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __MAP_SETTINGS_PARCELS_WIDGET_DECLARE__ #include "MapSettingsParcelsWidget.h" #undef __MAP_SETTINGS_PARCELS_WIDGET_DECLARE__ #include #include #include "CaretAssert.h" #include "CaretColorEnumComboBox.h" #include "CiftiConnectivityMatrixParcelFile.h" #include "CiftiParcelColoringModeEnum.h" #include "EnumComboBoxTemplate.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventSurfaceColoringInvalidate.h" using namespace caret; /** * \class caret::MapSettingsParcelsWidget * \brief Widget for setting parcel coloring properties. * \ingroup GuiQt */ /** * Constructor. */ MapSettingsParcelsWidget::MapSettingsParcelsWidget(QWidget* parent) : QWidget(parent) { m_ciftiParcelFile = NULL; QLabel* colorModeLabel = new QLabel("Color Mode"); m_parcelColoringModeEnumComboBox = new EnumComboBoxTemplate(this); m_parcelColoringModeEnumComboBox->setup(); QObject::connect(m_parcelColoringModeEnumComboBox, SIGNAL(itemActivated()), this, SLOT(ciftiParcelColoringModeEnumComboBoxItemActivated())); QLabel* colorLabel = new QLabel("Color"); m_parcelColorEnumComboBox = new CaretColorEnumComboBox(this); QObject::connect(m_parcelColorEnumComboBox, SIGNAL(colorSelected(const CaretColorEnum::Enum)), this, SLOT(parcelColorSelected(const CaretColorEnum::Enum))); QWidget* gridWidget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(gridWidget); gridLayout->addWidget(colorModeLabel, 0, 0); gridLayout->addWidget(m_parcelColoringModeEnumComboBox->getWidget(), 0, 1); gridLayout->addWidget(colorLabel, 1, 0); gridLayout->addWidget(m_parcelColorEnumComboBox->getWidget(), 1, 1); gridWidget->setFixedSize(gridWidget->sizeHint()); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(gridWidget, 0, Qt::AlignLeft); layout->addStretch(); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } /** * Destructor. */ MapSettingsParcelsWidget::~MapSettingsParcelsWidget() { } /** * Update the editor with the given CIFTI matrix file. */ void MapSettingsParcelsWidget::updateEditor(CiftiConnectivityMatrixParcelFile* ciftiParcelFile) { CaretAssert(ciftiParcelFile); m_ciftiParcelFile = ciftiParcelFile; m_parcelColoringModeEnumComboBox->setSelectedItem(m_ciftiParcelFile->getSelectedParcelColoringMode()); m_parcelColorEnumComboBox->setSelectedColor(m_ciftiParcelFile->getSelectedParcelColor()); } /** * Update the widget. */ void MapSettingsParcelsWidget::updateWidget() { updateEditor(m_ciftiParcelFile); } /** * Called when parcel color combo box is changed. */ void MapSettingsParcelsWidget::parcelColorSelected(const CaretColorEnum::Enum color) { m_ciftiParcelFile->setSelectedParcelColor(color); EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called when parcel coloring mode combo box is changed. */ void MapSettingsParcelsWidget::ciftiParcelColoringModeEnumComboBoxItemActivated() { const CiftiParcelColoringModeEnum::Enum colorMode = m_parcelColoringModeEnumComboBox->getSelectedItem(); m_ciftiParcelFile->setSelectedParcelColoringMode(colorMode); EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } connectome-workbench-1.4.2/src/GuiQt/MapSettingsParcelsWidget.h000066400000000000000000000043331360521144700245430ustar00rootroot00000000000000#ifndef __MAP_SETTINGS_PARCELS_WIDGET_H__ #define __MAP_SETTINGS_PARCELS_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretColorEnum.h" namespace caret { class CaretColorEnumComboBox; class CiftiConnectivityMatrixParcelFile; class EnumComboBoxTemplate; class MapSettingsParcelsWidget : public QWidget { Q_OBJECT public: MapSettingsParcelsWidget(QWidget* parent = 0); virtual ~MapSettingsParcelsWidget(); void updateEditor(CiftiConnectivityMatrixParcelFile* ciftiMatrixFile); void updateWidget(); private slots: void ciftiParcelColoringModeEnumComboBoxItemActivated(); void parcelColorSelected(const CaretColorEnum::Enum); // ADD_NEW_METHODS_HERE private: MapSettingsParcelsWidget(const MapSettingsParcelsWidget&); MapSettingsParcelsWidget& operator=(const MapSettingsParcelsWidget&); EnumComboBoxTemplate* m_parcelColoringModeEnumComboBox; CaretColorEnumComboBox* m_parcelColorEnumComboBox; CiftiConnectivityMatrixParcelFile* m_ciftiParcelFile; // ADD_NEW_MEMBERS_HERE }; #ifdef __MAP_SETTINGS_PARCELS_WIDGET_DECLARE__ // #endif // __MAP_SETTINGS_PARCELS_WIDGET_DECLARE__ } // namespace #endif //__MAP_SETTINGS_PARCELS_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/MapYokingGroupComboBox.cxx000066400000000000000000000376261360521144700245610ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __MAP_YOKING_GROUP_COMBO_BOX_DECLARE__ #include "MapYokingGroupComboBox.h" #undef __MAP_YOKING_GROUP_COMBO_BOX_DECLARE__ #include "AnnotationTextSubstitutionFile.h" #include "CaretAssert.h" #include "CaretMappableDataFile.h" #include "ChartTwoOverlay.h" #include "ChartableMatrixSeriesInterface.h" #include "CiftiScalarDataSeriesFile.h" #include "EnumComboBoxTemplate.h" #include "EventManager.h" #include "EventMapYokingValidation.h" #include "Overlay.h" #include "WuQMacroManager.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::MapYokingGroupComboBox * \brief Combo box for selection of a map yoking group. * \ingroup GuiQt */ /** * Constructor. */ MapYokingGroupComboBox::MapYokingGroupComboBox(QObject* parent) : MapYokingGroupComboBox(parent, "", "") { } //: WuQWidget(parent) //{ // m_comboBox = new EnumComboBoxTemplate(this); // m_comboBox->setup(); // m_comboBox->getWidget()->setStatusTip("Synchronize selected map indices (and selection status for overlays)"); // m_comboBox->getWidget()->setToolTip("Synchronize selected map indices (and selection status for overlays)"); //#ifdef CARET_OS_MACOSX // m_comboBox->getComboBox()->setFixedWidth(m_comboBox->getComboBox()->sizeHint().width() - 20); //#endif // CARET_OS_MACOSX // QObject::connect(m_comboBox, SIGNAL(itemActivated()), // this, SLOT(comboBoxActivated())); // WuQObject::watchObjectForMacroRecording(m_comboBox); //} /** * Constructor. * * @param parent * Parent of this combo box * @param objectName * Object name for macros * @param descriptiveName Descriptive name for macros */ MapYokingGroupComboBox::MapYokingGroupComboBox(QObject* parent, const QString& objectName, const QString& descriptiveName) : WuQWidget(parent) { m_comboBox = new EnumComboBoxTemplate(this); m_comboBox->setup(); m_comboBox->getWidget()->setStatusTip("Synchronize selected map indices (and selection status for overlays)"); m_comboBox->getWidget()->setToolTip("Synchronize selected map indices (and selection status for overlays)"); m_comboBox->getComboBox()->setSizeAdjustPolicy(QComboBox::AdjustToContents); #ifdef CARET_OS_MACOSX // m_comboBox->getComboBox()->setFixedWidth(m_comboBox->getComboBox()->sizeHint().width() - 20); #endif // CARET_OS_MACOSX QObject::connect(m_comboBox, SIGNAL(itemActivated()), this, SLOT(comboBoxActivated())); if ( ! objectName.isEmpty()) { QWidget* encapsulatedComboBox = m_comboBox->getWidget(); encapsulatedComboBox->setObjectName(objectName); WuQMacroManager::instance()->addMacroSupportToObject(encapsulatedComboBox, "Select map yoking for " + descriptiveName); } } /** * Destructor. */ MapYokingGroupComboBox::~MapYokingGroupComboBox() { } /** * Called when the user selects a yoking group. * Verify compatibility before accepting the selection. */ void MapYokingGroupComboBox::comboBoxActivated() { emit itemActivated(); // MapYokingGroupEnum::Enum mapYokingGroup = getMapYokingGroup(); // EventMapYokingValidation validateEvent(mapYokingGroup); } /** * @return The widget. */ QWidget* MapYokingGroupComboBox::getWidget() { return m_comboBox->getWidget(); } /** * @return The selected map yoking group. */ MapYokingGroupEnum::Enum MapYokingGroupComboBox::getMapYokingGroup() const { return m_comboBox->getSelectedItem(); } /** * Set the map yoking group. * * @param mapYokingGroup * The map yoking group. */ void MapYokingGroupComboBox::setMapYokingGroup(const MapYokingGroupEnum::Enum mapYokingGroup) { m_comboBox->setSelectedItem(mapYokingGroup); } /** * Validate a change in yoking for a matrix series file. * * @param chartableMatrixSeriesInterface * Matrix series file that has yoking changed. * @param tabIndex * Index of tab for the file. */ void MapYokingGroupComboBox::validateYokingChange(ChartableMatrixSeriesInterface* chartableMatrixSeriesInterface, const int32_t tabIndex) { if (chartableMatrixSeriesInterface != NULL) { int32_t mapIndex = chartableMatrixSeriesInterface->getSelectedMapIndex(tabIndex); const MapYokingGroupEnum::Enum previousMapYokingGroup = chartableMatrixSeriesInterface->getMatrixRowColumnMapYokingGroup(tabIndex); const MapYokingGroupEnum::Enum newYokingGroup = getMapYokingGroup(); CaretMappableDataFile* mapFile = dynamic_cast(chartableMatrixSeriesInterface); CaretAssert(mapFile); bool selectionStatus = true; if ((mapFile != NULL) && (mapIndex >= 0)) { const YokeValidationResult result = validateYoking(NULL, mapFile, mapIndex, selectionStatus); switch (result) { case YOKE_VALIDATE_RESULT_ACCEPT: chartableMatrixSeriesInterface->setMatrixRowColumnMapYokingGroup(tabIndex, newYokingGroup); chartableMatrixSeriesInterface->setSelectedMapIndex(tabIndex, mapIndex); break; case YOKE_VALIDATE_RESULT_OFF: chartableMatrixSeriesInterface->setMatrixRowColumnMapYokingGroup(tabIndex, MapYokingGroupEnum::MAP_YOKING_GROUP_OFF); break; case YOKE_VALIDATE_RESULT_PREVIOUS: chartableMatrixSeriesInterface->setMatrixRowColumnMapYokingGroup(tabIndex, previousMapYokingGroup); break; } setMapYokingGroup(chartableMatrixSeriesInterface->getMatrixRowColumnMapYokingGroup(tabIndex)); } } } /** * Validate a change in yoking for an overlay. * * @param annTextSubFile * Annotation text substitution file */ void MapYokingGroupComboBox::validateYokingChange(AnnotationTextSubstitutionFile* annTextSubFile) { CaretAssert(annTextSubFile); const MapYokingGroupEnum::Enum previousMapYokingGroup = annTextSubFile->getMapYokingGroup(); const MapYokingGroupEnum::Enum newYokingGroup = getMapYokingGroup(); int32_t mapIndex = annTextSubFile->getSelectedValueIndex(); bool selectionStatus = true; const YokeValidationResult result = validateYoking(annTextSubFile, NULL, mapIndex, selectionStatus); switch (result) { case YOKE_VALIDATE_RESULT_ACCEPT: annTextSubFile->setSelectedValueIndex(mapIndex); annTextSubFile->setMapYokingGroup(newYokingGroup); break; case YOKE_VALIDATE_RESULT_OFF: annTextSubFile->setMapYokingGroup(MapYokingGroupEnum::MAP_YOKING_GROUP_OFF); break; case YOKE_VALIDATE_RESULT_PREVIOUS: annTextSubFile->setMapYokingGroup(previousMapYokingGroup); break; } setMapYokingGroup(annTextSubFile->getMapYokingGroup()); } /** * Validate a change in yoking for an overlay. * * @param overlay * Overlay whose yoking changes. */ void MapYokingGroupComboBox::validateYokingChange(Overlay* overlay) { const MapYokingGroupEnum::Enum previousMapYokingGroup = overlay->getMapYokingGroup(); const MapYokingGroupEnum::Enum newYokingGroup = getMapYokingGroup(); CaretMappableDataFile* mapFile = NULL; int32_t mapIndex = -1; overlay->getSelectionData(mapFile, mapIndex); bool selectionStatus = overlay->isEnabled(); if ((mapFile != NULL) && (mapIndex >= 0)) { const YokeValidationResult result = validateYoking(NULL, mapFile, mapIndex, selectionStatus); switch (result) { case YOKE_VALIDATE_RESULT_ACCEPT: overlay->setEnabled(selectionStatus); overlay->setSelectionData(mapFile, mapIndex); overlay->setMapYokingGroup(newYokingGroup); break; case YOKE_VALIDATE_RESULT_OFF: overlay->setMapYokingGroup(MapYokingGroupEnum::MAP_YOKING_GROUP_OFF); break; case YOKE_VALIDATE_RESULT_PREVIOUS: overlay->setMapYokingGroup(previousMapYokingGroup); break; } setMapYokingGroup(overlay->getMapYokingGroup()); } } /** * Validate a change in yoking for a chart overlay. * * @param chartOverlay * Chart overlay whose yoking changes. */ void MapYokingGroupComboBox::validateYokingChange(ChartTwoOverlay* chartOverlay) { const MapYokingGroupEnum::Enum previousMapYokingGroup = chartOverlay->getMapYokingGroup(); const MapYokingGroupEnum::Enum newYokingGroup = getMapYokingGroup(); CaretMappableDataFile* mapFile = NULL; ChartTwoOverlay::SelectedIndexType selectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; int32_t selectedIndex = -1; chartOverlay->getSelectionData(mapFile, selectedIndexType, selectedIndex); bool selectionStatus = chartOverlay->isEnabled(); if ((mapFile != NULL) && chartOverlay->isMapYokingSupported()) { if (mapFile->getNumberOfMaps() > 0) { if (selectedIndex < 0) { selectedIndex = 0; } } const YokeValidationResult result = validateYoking(NULL, mapFile, selectedIndex, selectionStatus); switch (result) { case YOKE_VALIDATE_RESULT_ACCEPT: chartOverlay->setEnabled(selectionStatus); chartOverlay->setSelectionData(mapFile, selectedIndex); chartOverlay->setMapYokingGroup(newYokingGroup); break; case YOKE_VALIDATE_RESULT_OFF: chartOverlay->setMapYokingGroup(MapYokingGroupEnum::MAP_YOKING_GROUP_OFF); break; case YOKE_VALIDATE_RESULT_PREVIOUS: chartOverlay->setMapYokingGroup(previousMapYokingGroup); break; } setMapYokingGroup(chartOverlay->getMapYokingGroup()); } } /** * Validate yoking when a new file is added to a yoking group. * * @param annTextSubFile * The annotation text substitution file. * @param mapFile * The file that the user would like to yoke. * @param selectedMapIndexInOut * The current map selected for the file. Its value will be updated * if yoking is selected (turned on or changed). * @param selectionStatusInOut * The selection status for an overlay. Its value will be updated * if yoking is selected (turned on or changed). */ MapYokingGroupComboBox::YokeValidationResult MapYokingGroupComboBox::validateYoking(AnnotationTextSubstitutionFile* annTextSubFile, CaretMappableDataFile* mapFile, int32_t& selectedMapIndexInOut, bool& /* selectionStatusInOut */) { YokeValidationResult yokeResult = YOKE_VALIDATE_RESULT_OFF; //YOKE_VALIDATE_RESULT_PREVIOUS; const bool validFileFlag = ((annTextSubFile != NULL) || (mapFile != NULL)); MapYokingGroupEnum::Enum newYokingGroup = getMapYokingGroup(); if (newYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { if (validFileFlag && (selectedMapIndexInOut >= 0)) { /* * Get info on yoking selections */ EventMapYokingValidation validateEvent(newYokingGroup); EventManager::get()->sendEvent(validateEvent.getPointer()); /* * Check compatibility based (number of maps in yoked files) * and warn use if there is an incompatibility. */ int32_t numberOfYokedFiles = 0; AString message; if (validateEvent.validateCompatibility(annTextSubFile, mapFile, numberOfYokedFiles, message)) { yokeResult = YOKE_VALIDATE_RESULT_ACCEPT; } else { message.appendWithNewLine(""); message.appendWithNewLine("Allow yoking?"); message = WuQtUtilities::createWordWrappedToolTipText(message); WuQMessageBox::YesNoCancelResult result = WuQMessageBox::warningYesNoCancel(m_comboBox->getWidget(), message, ""); switch (result) { case WuQMessageBox::RESULT_YES: yokeResult = YOKE_VALIDATE_RESULT_ACCEPT; break; case WuQMessageBox::RESULT_NO: yokeResult = YOKE_VALIDATE_RESULT_OFF; break; case WuQMessageBox::RESULT_CANCEL: yokeResult = YOKE_VALIDATE_RESULT_PREVIOUS; break; } } if (yokeResult == YOKE_VALIDATE_RESULT_ACCEPT) { if (numberOfYokedFiles > 0) { /* * Already have files yoked to this group so use * the map index and status from the yoking group. */ selectedMapIndexInOut = MapYokingGroupEnum::getSelectedMapIndex(newYokingGroup); } else { /* * This is the first file added to the yoking group * so set the map index and status in the yoking group * to the file's selections. */ MapYokingGroupEnum::setSelectedMapIndex(newYokingGroup, selectedMapIndexInOut); } } } } return yokeResult; } connectome-workbench-1.4.2/src/GuiQt/MapYokingGroupComboBox.h000066400000000000000000000063121360521144700241720ustar00rootroot00000000000000#ifndef __MAP_YOKING_GROUP_COMBO_BOX_H__ #define __MAP_YOKING_GROUP_COMBO_BOX_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "MapYokingGroupEnum.h" #include "WuQWidget.h" namespace caret { class AnnotationTextSubstitutionFile; class CaretMappableDataFile; class ChartTwoOverlay; class ChartableMatrixSeriesInterface; class EnumComboBoxTemplate; class Overlay; class MapYokingGroupComboBox : public WuQWidget { Q_OBJECT public: MapYokingGroupComboBox(QObject* parent); MapYokingGroupComboBox(QObject* parent, const QString& objectName, const QString& descriptiveName); virtual ~MapYokingGroupComboBox(); virtual QWidget* getWidget(); MapYokingGroupEnum::Enum getMapYokingGroup() const; void setMapYokingGroup(const MapYokingGroupEnum::Enum mapYokingGroup); void validateYokingChange(ChartableMatrixSeriesInterface* chartableMatrixSeriesInterface, const int32_t tabIndex); void validateYokingChange(Overlay* overlay); void validateYokingChange(ChartTwoOverlay* chartOverlay); void validateYokingChange(AnnotationTextSubstitutionFile* annTextSubFile); // ADD_NEW_METHODS_HERE signals: void itemActivated(); private slots: void comboBoxActivated(); private: enum YokeValidationResult { YOKE_VALIDATE_RESULT_ACCEPT, YOKE_VALIDATE_RESULT_OFF, YOKE_VALIDATE_RESULT_PREVIOUS }; MapYokingGroupComboBox(const MapYokingGroupComboBox&); MapYokingGroupComboBox& operator=(const MapYokingGroupComboBox&); YokeValidationResult validateYoking(AnnotationTextSubstitutionFile* annTextSubFile, CaretMappableDataFile* selectedFile, int32_t& selectedMapIndexInOut, bool& selectionStatusInOut); EnumComboBoxTemplate* m_comboBox; // ADD_NEW_MEMBERS_HERE }; #ifdef __MAP_YOKING_GROUP_COMBO_BOX_DECLARE__ // #endif // __MAP_YOKING_GROUP_COMBO_BOX_DECLARE__ } // namespace #endif //__MAP_YOKING_GROUP_COMBO_BOX_H__ connectome-workbench-1.4.2/src/GuiQt/MetaDataEditorDialog.cxx000066400000000000000000000077311360521144700241560ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __META_DATA_EDITOR_DIALOG_DECLARE__ #include "MetaDataEditorDialog.h" #undef __META_DATA_EDITOR_DIALOG_DECLARE__ #include #include #include #include #include "CaretAssert.h" #include "CaretDataFile.h" #include "CaretMappableDataFile.h" #include "GiftiMetaData.h" #include "MetaDataEditorWidget.h" #include "WuQMessageBox.h" using namespace caret; /** * \class caret::MetaDataEditorDialog * \brief Dialog for editing metadata. * \ingroup GuiQt */ /** * Constructor for editing a file's metadata. * * @param caretDataFile * Caret Data File that will have its metadata edited. * @param parent * Widget on which this dialog is displayed. */ MetaDataEditorDialog::MetaDataEditorDialog(CaretDataFile* caretDataFile, QWidget* parent) : WuQDialogModal("", parent) { CaretAssert(caretDataFile); initializeDialog(("Edit File Metadata: " + caretDataFile->getFileNameNoPath()), caretDataFile->getFileMetaData()); } /** * Constructor for editing a map's metadata. * * @param caretMappableDataFile * Caret Data File that will have its map's metadata edited. * @param mapIndex * Index of map that will have its metadata edited. * @param parent * Widget on which this dialog is displayed. */ MetaDataEditorDialog::MetaDataEditorDialog(CaretMappableDataFile* caretMappableDataFile, const int32_t mapIndex, QWidget* parent) : WuQDialogModal("", parent) { CaretAssert(caretMappableDataFile); const AString mapName = caretMappableDataFile->getMapName(mapIndex); initializeDialog(("Edit Map Metadata: " + mapName), caretMappableDataFile->getMapMetaData(mapIndex)); } /** * Destructor. */ MetaDataEditorDialog::~MetaDataEditorDialog() { } void MetaDataEditorDialog::initializeDialog(const AString& dialogTitle, GiftiMetaData* metaData) { CaretAssert(metaData); setWindowTitle(dialogTitle); m_metaDataEditorWidget = new MetaDataEditorWidget(this); setCentralWidget(m_metaDataEditorWidget, WuQDialog::SCROLL_AREA_NEVER); m_metaDataEditorWidget->loadMetaData(metaData); } /** * Called when OK button clicked. */ void MetaDataEditorDialog::okButtonClicked() { const AString errorMessage = m_metaDataEditorWidget->saveMetaData(); if (errorMessage.isEmpty() == false) { WuQMessageBox::errorOk(this, errorMessage); return; } WuQDialogModal::okButtonClicked(); } /** * Called when Cancel button clicked. */ void MetaDataEditorDialog::cancelButtonClicked() { if (m_metaDataEditorWidget->isMetaDataModified()) { const AString errorMessage = ("The metadata has been modified. Discard changes?"); if (WuQMessageBox::warningOkCancel(this, errorMessage)) { WuQDialogModal::cancelButtonClicked(); } } else { WuQDialogModal::cancelButtonClicked(); } } connectome-workbench-1.4.2/src/GuiQt/MetaDataEditorDialog.h000066400000000000000000000042421360521144700235750ustar00rootroot00000000000000#ifndef __META_DATA_EDITOR_DIALOG_H__ #define __META_DATA_EDITOR_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WuQDialogModal.h" namespace caret { class CaretDataFile; class CaretMappableDataFile; class GiftiMetaData; class MetaDataEditorWidget; class MetaDataEditorDialog : public WuQDialogModal { Q_OBJECT public: MetaDataEditorDialog(CaretDataFile* caretDataFile, QWidget* parent); MetaDataEditorDialog(CaretMappableDataFile* caretMappableDataFile, const int32_t mapIndex, QWidget* parent); virtual ~MetaDataEditorDialog(); virtual void okButtonClicked(); virtual void cancelButtonClicked(); private: MetaDataEditorDialog(const MetaDataEditorDialog&); MetaDataEditorDialog& operator=(const MetaDataEditorDialog&); void initializeDialog(const AString& dialogTitle, GiftiMetaData* metaData); MetaDataEditorWidget* m_metaDataEditorWidget; // ADD_NEW_MEMBERS_HERE }; #ifdef __META_DATA_EDITOR_DIALOG_DECLARE__ // #endif // __META_DATA_EDITOR_DIALOG_DECLARE__ } // namespace #endif //__META_DATA_EDITOR_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/MetaDataEditorWidget.cxx000066400000000000000000000352431360521144700242010ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __META_DATA_EDITOR_WIDGET_DECLARE__ #include "MetaDataEditorWidget.h" #undef __META_DATA_EDITOR_WIDGET_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include #include #include "CaretAssert.h" #include "GiftiMetaData.h" #include "WuQDataEntryDialog.h" #include "WuQWidgetObjectGroup.h" using namespace caret; /** * \class caret::MetaDataEditorWidget * \brief Widget for editing GIFTI MetaData. * \ingroup GuiQt */ /** * Constructor. * @param parent * Parent widget. */ MetaDataEditorWidget::MetaDataEditorWidget(QWidget* parent) : QWidget(parent) { m_metaDataBeingEdited = NULL; m_deleteActionSignalMapper = new QSignalMapper(); QObject::connect(m_deleteActionSignalMapper, SIGNAL(mapped(int)), this, SLOT(deleteActionTriggered(int))); m_newPushButton = new QPushButton("New..."); QObject::connect(m_newPushButton, SIGNAL(clicked()), this, SLOT(newPushButtonClicked())); QVBoxLayout* buttonsLayout = new QVBoxLayout(); buttonsLayout->addStretch(); buttonsLayout->addWidget(m_newPushButton); buttonsLayout->addSpacing(10); m_metaGridLayout = new QGridLayout(); m_metaGridLayout->addWidget(new QLabel("Delete"), 0, COLUMN_DELETE, Qt::AlignCenter); m_metaGridLayout->addWidget(new QLabel("Name"), 0, COLUMN_NAME, Qt::AlignCenter); m_metaGridLayout->addWidget(new QLabel("Value"), 0, COLUMN_VALUE, Qt::AlignCenter); QWidget* metaDataWidget = new QWidget(); QVBoxLayout* metaDataWidgetLayout = new QVBoxLayout(metaDataWidget); metaDataWidgetLayout->addLayout(m_metaGridLayout); metaDataWidgetLayout->addStretch(); m_metaDataNameValueScrollArea = new QScrollArea(); m_metaDataNameValueScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); m_metaDataNameValueScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); m_metaDataNameValueScrollArea->setWidget(metaDataWidget); m_metaDataNameValueScrollArea->setWidgetResizable(true); m_metaDataNameValueScrollArea->setFrameShape(QFrame::NoFrame); QHBoxLayout* dialogLayout = new QHBoxLayout(this); dialogLayout->addWidget(m_metaDataNameValueScrollArea, 100); dialogLayout->addLayout(buttonsLayout, 0); setMinimumWidth(600); setMinimumHeight(260); } /** * Destructor. */ MetaDataEditorWidget::~MetaDataEditorWidget() { } /** * Called when Add push button is clicked. */ void MetaDataEditorWidget::newPushButtonClicked() { WuQDataEntryDialog ded("New Metadata Name", m_newPushButton); m_newNameDialogLineEdit = ded.addLineEditWidget("New MetaData Name"); QObject::connect(&ded, SIGNAL(validateData(WuQDataEntryDialog*)), this, SLOT(validateNewName(WuQDataEntryDialog*))); if (ded.exec() == WuQDataEntryDialog::Accepted) { readNamesAndValues(); m_namesAndValues.push_back(std::make_pair(m_newNameDialogLineEdit->text().trimmed(), "")); displayNamesAndValues(); const int32_t numNames = static_cast(m_namesAndValues.size()); m_metaDataWidgetRows[numNames - 1]->m_valueLineEdit->setFocus(); m_metaDataNameValueScrollArea->ensureWidgetVisible(m_metaDataWidgetRows[numNames-1]->m_nameLineEdit); } } /** * Validate the new name from new name dialog. * @param dataEntryDialog * The dialog used for entry of new name. */ void MetaDataEditorWidget::validateNewName(WuQDataEntryDialog* dataEntryDialog) { const AString newName = m_newNameDialogLineEdit->text().trimmed(); if (newName.isEmpty()) { dataEntryDialog->setDataValid(false, "Name may not be empty."); return; } std::set allNames; getNamesInDialog(allNames, NULL, NULL); if (std::find(allNames.begin(), allNames.end(), newName) != allNames.end()) { const AString msg = ("Name \"" + newName + "\" already exists. Duplicate names are not allowed."); dataEntryDialog->setDataValid(false, Qt::convertFromPlainText(msg)); return; } dataEntryDialog->setDataValid(true, ""); } /** * Load the given metadata in this widget. * * @param metaData * Metadata that displayed in widget. */ void MetaDataEditorWidget::loadMetaData(GiftiMetaData* metaData) { CaretAssert(metaData); m_metaDataBeingEdited = metaData; std::vector metaDataNames = m_metaDataBeingEdited->getAllMetaDataNames(); const int32_t numMetaData = static_cast(metaDataNames.size()); /* * Get names and values */ m_unmodifiedNamesAndValues.clear(); m_namesAndValues.clear(); for (int32_t iRow = 0; iRow < numMetaData; iRow++) { const AString name = metaDataNames[iRow].trimmed(); const AString value = m_metaDataBeingEdited->get(name).trimmed(); m_namesAndValues.push_back(std::make_pair(name, value)); m_unmodifiedNamesAndValues.insert(std::make_pair(name, value)); } displayNamesAndValues(); } /** * Display the names and values. */ void MetaDataEditorWidget::displayNamesAndValues() { const int32_t numNamesAndValues = static_cast(m_namesAndValues.size()); int32_t numWidgetRows = static_cast(m_metaDataWidgetRows.size()); /* * Update existing rows and add new rows as needed. */ for (int32_t iRow = 0; iRow < numNamesAndValues; iRow++) { const AString name = m_namesAndValues[iRow].first; const AString value = m_namesAndValues[iRow].second; MetaDataWidgetRow* widgetsRow = NULL; if (iRow < numWidgetRows) { widgetsRow = m_metaDataWidgetRows[iRow]; } else { widgetsRow = new MetaDataWidgetRow(this, m_deleteActionSignalMapper, iRow); const int layoutRow = m_metaGridLayout->rowCount(); m_metaGridLayout->addWidget(widgetsRow->m_deleteToolButton, layoutRow, COLUMN_DELETE, Qt::AlignCenter); m_metaGridLayout->addWidget(widgetsRow->m_nameLineEdit, layoutRow, COLUMN_NAME); m_metaGridLayout->addWidget(widgetsRow->m_valueLineEdit, layoutRow, COLUMN_VALUE); m_metaDataWidgetRows.push_back(widgetsRow); } widgetsRow->m_nameLineEdit->setText(name); widgetsRow->m_valueLineEdit->setText(value); widgetsRow->m_widgetGroup->setVisible(true); } /* * Hide rows that are no longer used. */ numWidgetRows = static_cast(m_metaDataWidgetRows.size()); for (int32_t iRow = numNamesAndValues; iRow < numWidgetRows; iRow++) { m_metaDataWidgetRows[iRow]->m_widgetGroup->setVisible(false); } } /** * Read the names and values from the GUI. */ void MetaDataEditorWidget::readNamesAndValues() { m_namesAndValues.clear(); /* * Read from the rows. */ int32_t numWidgetRows = static_cast(m_metaDataWidgetRows.size()); for (int32_t iRow = 0; iRow < numWidgetRows; iRow++) { MetaDataWidgetRow* widgetRow = m_metaDataWidgetRows[iRow]; if (widgetRow->m_widgetGroup->isVisible()) { m_namesAndValues.push_back(std::make_pair(widgetRow->m_nameLineEdit->text().trimmed(), widgetRow->m_valueLineEdit->text().trimmed())); } } } /** * Get the names that are listed in the editor. * * @param namesOut * Output will contain all unique names. * @param duplicateNamesOut * If not NULL, any duplicate names will be placed here. * @param haveEmptyNamesOut * If not NULL, will be true if any empty names were found. * @return true if all names valid, else false. */ bool MetaDataEditorWidget::getNamesInDialog(std::set& namesOut, std::set* duplicateNamesOut, bool* haveEmptyNamesOut) { readNamesAndValues(); namesOut.clear(); if (duplicateNamesOut != NULL) { duplicateNamesOut->clear(); } if (haveEmptyNamesOut != NULL) { *haveEmptyNamesOut = false; } bool allValidNames = true; const int32_t numItems = static_cast(m_namesAndValues.size()); for (int32_t i = 0; i < numItems; i++) { const AString name = m_namesAndValues[i].first; if (name.isEmpty()) { if (haveEmptyNamesOut != NULL) { *haveEmptyNamesOut = true; } allValidNames = false; } else if (std::find(namesOut.begin(), namesOut.end(), name) != namesOut.end()) { if (duplicateNamesOut != NULL) { duplicateNamesOut->insert(name); } allValidNames = false; } else { namesOut.insert(name); } } return allValidNames; } /** * Transfer values in dialog into metadata. * * @return Empty string if no errors, otherwise error message. */ AString MetaDataEditorWidget::saveMetaData() { if (isMetaDataModified() == false) { return ""; } readNamesAndValues(); std::set allNames; std::set duplicateNames; bool haveEmptyNames; const bool valid = getNamesInDialog(allNames, &duplicateNames, &haveEmptyNames); if (valid) { m_metaDataBeingEdited->clear(); const int32_t numItems = static_cast(m_namesAndValues.size()); for (int32_t i = 0; i < numItems; i++) { const AString name = m_namesAndValues[i].first; const AString value = m_namesAndValues[i].second; m_metaDataBeingEdited->set(name, value); } return ""; } AString errorMessage = ""; if (haveEmptyNames) { errorMessage.appendWithNewLine("Empty names are not allowed."); } if (duplicateNames.empty() == false) { errorMessage.appendWithNewLine("Duplicate names are not allowed:"); for (std::set::iterator iter = duplicateNames.begin(); iter != duplicateNames.end(); iter++) { errorMessage.appendWithNewLine(" " + *iter); } } return errorMessage; } /** * @return true if the names and values been modified, else false. */ bool MetaDataEditorWidget::isMetaDataModified() { readNamesAndValues(); const int32_t numItems = static_cast(m_namesAndValues.size()); if (numItems != static_cast(m_unmodifiedNamesAndValues.size())) { return true; } std::map nameValueMap; for (int32_t i = 0; i < numItems; i++) { nameValueMap.insert(std::make_pair(m_namesAndValues[i].first, m_namesAndValues[i].second)); } const bool theSame = std::equal(m_unmodifiedNamesAndValues.begin(), m_unmodifiedNamesAndValues.end(), nameValueMap.begin()); return (theSame == false); } /** * Called when a delete tool button is clicked. */ void MetaDataEditorWidget::deleteActionTriggered(int indx) { readNamesAndValues(); CaretAssertVectorIndex(m_namesAndValues, indx); m_namesAndValues.erase(m_namesAndValues.begin() + indx); displayNamesAndValues(); } /** * Constructor. * @param parent * The parent widget. * @param deleteActionSignalMapper * The signal mapper for delete action. * @param rowIndex * Row index of widgets and used by signal mapper. */ MetaDataEditorWidget::MetaDataWidgetRow::MetaDataWidgetRow(QWidget* parent, QSignalMapper* deleteActionSignalMapper, const int32_t rowIndex) { QAction* deleteAction = new QAction("X", parent); QObject::connect(deleteAction, SIGNAL(triggered(bool)), deleteActionSignalMapper, SLOT(map())); deleteActionSignalMapper->setMapping(deleteAction, rowIndex); m_deleteToolButton = new QToolButton(); m_deleteToolButton->setDefaultAction(deleteAction); const int minWidth = 150; m_nameLineEdit = new QLineEdit(); m_nameLineEdit->setMinimumWidth(minWidth); m_valueLineEdit = new QLineEdit(); m_valueLineEdit->setMinimumWidth(minWidth); m_widgetGroup = new WuQWidgetObjectGroup(parent); m_widgetGroup->add(deleteAction); m_widgetGroup->add(m_deleteToolButton); m_widgetGroup->add(m_nameLineEdit); m_widgetGroup->add(m_valueLineEdit); } MetaDataEditorWidget::MetaDataWidgetRow::~MetaDataWidgetRow() { } connectome-workbench-1.4.2/src/GuiQt/MetaDataEditorWidget.h000066400000000000000000000071111360521144700236170ustar00rootroot00000000000000#ifndef __META_DATA_EDITOR_WIDGET_H__ #define __META_DATA_EDITOR_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "AString.h" class QAction; class QGridLayout; class QLineEdit; class QPushButton; class QScrollArea; class QSignalMapper; class QToolButton; namespace caret { class GiftiMetaData; class WuQDataEntryDialog; class WuQWidgetObjectGroup; class MetaDataEditorWidget : public QWidget { Q_OBJECT public: MetaDataEditorWidget(QWidget* parent); virtual ~MetaDataEditorWidget(); void loadMetaData(GiftiMetaData* metaData); bool isMetaDataModified(); AString saveMetaData(); private slots: void newPushButtonClicked(); void deleteActionTriggered(int indx); void validateNewName(WuQDataEntryDialog* dataEntryDialog); private: MetaDataEditorWidget(const MetaDataEditorWidget&); MetaDataEditorWidget& operator=(const MetaDataEditorWidget&); enum { COLUMN_DELETE = 0, COLUMN_NAME = 1, COLUMN_VALUE = 2 }; class MetaDataWidgetRow { public: MetaDataWidgetRow(QWidget* parent, QSignalMapper* deleteActionSignalMapper, const int32_t indx); ~MetaDataWidgetRow(); QToolButton* m_deleteToolButton; QLineEdit* m_nameLineEdit; QLineEdit* m_valueLineEdit; WuQWidgetObjectGroup* m_widgetGroup; }; void displayNamesAndValues(); void readNamesAndValues(); bool getNamesInDialog(std::set& namesOut, std::set* duplicateNamesOut, bool* haveEmptyNamesOut); std::vector > m_namesAndValues; std::map m_unmodifiedNamesAndValues; /** Metadata that is being edited */ GiftiMetaData* m_metaDataBeingEdited; QGridLayout* m_metaGridLayout; std::vector m_metaDataWidgetRows; QSignalMapper* m_deleteActionSignalMapper; QPushButton* m_newPushButton; QLineEdit* m_newNameDialogLineEdit; QScrollArea* m_metaDataNameValueScrollArea; // ADD_NEW_MEMBERS_HERE }; #ifdef __META_DATA_EDITOR_WIDGET_DECLARE__ // #endif // __META_DATA_EDITOR_WIDGET_DECLARE__ } // namespace #endif //__META_DATA_EDITOR_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/MouseEvent.cxx000066400000000000000000000202021360521144700222650ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "BrainOpenGLViewportContent.h" #include "BrainOpenGLWidget.h" #include "CaretAssert.h" #include "MouseEvent.h" using namespace caret; /** * \class caret::MouseEvent * \brief Event issued when mouse is moved or buttons are pressed. * \ingroup GuiQt */ /** * Constructor. * @param viewportContent * Content of viewport. * @param openGLWidget * OpenGL Widget in which mouse activity took place. * @param browserWindowIndex * Index of the browser winddow in which mouse activity took place. * @param x * Current mouse X-coordinate (left == 0) * @param y * Current mouse Y-coordinate (bottom == 0) * @param dx * Change in mouse X-coordinate since last mouse event * @param dy * Change in mouse Y-coordinate since last mouse event * @param mousePressX * X-coordinate of mouse when button was pressed * @param mousePressY * Y-coordinate of mouse when button was pressed * @param firstDraggingFlag * Should be true the first time in in a mouse dragging operation. */ MouseEvent::MouseEvent(const BrainOpenGLViewportContent* viewportContent, BrainOpenGLWidget* openGLWidget, const int32_t browserWindowIndex, const int32_t x, const int32_t y, const int32_t dx, const int32_t dy, const int32_t mousePressX, const int32_t mousePressY, const bool firstDraggingFlag) : CaretObject() { initializeMembersMouseEvent(); /* * MUST copy viewport content as it may be deleted by caller * prior to this instance being deleted */ m_viewportContent = NULL; if (viewportContent != NULL) { m_viewportContent = new BrainOpenGLViewportContent(*viewportContent); } m_openGLWidget = openGLWidget; m_browserWindowIndex = browserWindowIndex; m_x = x; m_y = y; m_dx = dx; m_dy = dy; m_pressX = mousePressX; m_pressY = mousePressY; m_firstDraggingFlag = firstDraggingFlag; } /** * Destructor */ MouseEvent::~MouseEvent() { if (m_viewportContent != NULL) { delete m_viewportContent; } } /** * Copy constructor. * @param obj * Object that is copied. */ MouseEvent::MouseEvent(const MouseEvent& obj) : CaretObject(obj) { this->initializeMembersMouseEvent(); this->copyHelperMouseEvent(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ MouseEvent& MouseEvent::operator=(const MouseEvent& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperMouseEvent(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void MouseEvent::copyHelperMouseEvent(const MouseEvent& obj) { /* * MUST copy viewport content as it may be deleted */ if (m_viewportContent != NULL) { delete m_viewportContent; m_viewportContent = NULL; } CaretAssert(obj.m_viewportContent); if (obj.m_viewportContent != NULL) { m_viewportContent = new BrainOpenGLViewportContent(*obj.m_viewportContent); } m_openGLWidget = obj.m_openGLWidget; m_browserWindowIndex = obj.m_browserWindowIndex; m_x = obj.m_x; m_y = obj.m_y; m_dx = obj.m_dx; m_dy = obj.m_dy; m_pressX = obj.m_pressX; m_pressY = obj.m_pressY; m_wheelRotation = obj.m_wheelRotation; m_firstDraggingFlag = obj.m_firstDraggingFlag; } /** * Initialize all members. */ void MouseEvent::initializeMembersMouseEvent() { m_viewportContent = NULL; m_openGLWidget = NULL; m_browserWindowIndex = -1; m_x = 0; m_y = 0; m_dx = 0; m_dy = 0; m_pressX = 0; m_pressY = 0; m_wheelRotation = 0; m_firstDraggingFlag = false; } /** * @return The viewport content in which the mouse was pressed. */ BrainOpenGLViewportContent* MouseEvent::getViewportContent() const { return m_viewportContent; } /** * @return The OpenGL Widget in which the mouse event occurred. */ BrainOpenGLWidget* MouseEvent::getOpenGLWidget() const { return m_openGLWidget; } /** * Get a string showing the contents of this mouse event. * @return String describing the mouse status. */ AString MouseEvent::toString() const { const AString msg = ", x=" + AString::number(m_x) + ", y=" + AString::number(m_y) + ", dx=" + AString::number(m_dx) + ", dy=" + AString::number(m_dy); + ", pressX=" + AString::number(m_pressX) + ", pressY=" + AString::number(m_pressY); + ", wheelRotation=" + AString::number(m_wheelRotation); return msg; } /** * @return Index of the browser window in which the * event took place. */ int32_t MouseEvent::getBrowserWindowIndex() const { return m_browserWindowIndex; } /** * Get the change in the X-coordinate. * @return change in the X-coordinate. * */ int32_t MouseEvent::getDx() const { return m_dx; } /** * Get the change in the Y-coordinate. * @return change in the Y-coordinate. * */ int32_t MouseEvent::getDy() const { return m_dy; } /** * Get the X-coordinate of the mouse. * @return The X-coordinate. * */ int32_t MouseEvent::getX() const { return m_x; } /** * Get the Y-coordinate of the mouse. * Origin is at the BOTTOM of the widget !!! * @return The Y-coordinate. * */ int32_t MouseEvent::getY() const { return m_y; } /** * Get the X-coordinate of where the mouse was pressed. * @return The X-coordinate. * */ int32_t MouseEvent::getPressedX() const { return m_pressX; } /** * Get the Y-coordinate of where the mouse was pressed. * Origin is at the BOTTOM of the widget !!! * @return The Y-coordinate. * */ int32_t MouseEvent::getPressedY() const { return m_pressY; } /** * Get the Global X-coordinate of where the mouse was pressed. * @return The Global X-coordinate. * * @param x * X-coordinate in widget (0 is left side of widget) * @param y * Y-coordinate in widget (0 is bottom side of widget) * @param outGlobalX * Output with global X-coordinate * @param outGlobalY * Output with global Y-coordinate */ void MouseEvent::getGlobalXY(const int32_t x, const int32_t y, int32_t& outGlobalX, int32_t& outGlobalY) const { CaretAssert(m_openGLWidget); const int32_t yOriginTop = m_openGLWidget->height() - y; const QPoint globalPoint = m_openGLWidget->mapToGlobal(QPoint(x, yOriginTop)); outGlobalX = globalPoint.x(); outGlobalY = globalPoint.y(); } /** * Get the amount of rotation in the mouse wheel. * @return Amount mouse wheel rotated. * */ int32_t MouseEvent::getWheelRotation() const { return m_wheelRotation; } /** * @return Is this the first in a sequence of mouse dragging? * * A mouse drag is the sequence: * (1) User presses the mouse * (2) One or more calls are made to the input receivers mouseLeftDrag() method * (3) User releases the mouse ending the dragging. * * This method returns true for the first call made to mouseLeftDrag() in * step 2 and false in all other calls to mouseLeftDrag(). */ bool MouseEvent::isFirstDragging() const { return m_firstDraggingFlag; } connectome-workbench-1.4.2/src/GuiQt/MouseEvent.h000066400000000000000000000062311360521144700217200ustar00rootroot00000000000000#ifndef __MouseEvent_H__ #define __MouseEvent_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include class QMouseEvent; namespace caret { class BrainOpenGLViewportContent; class BrainOpenGLWidget; /** * Contains information about a mouse event in the OpenGL region. */ class MouseEvent : public CaretObject { public: MouseEvent(const BrainOpenGLViewportContent* viewportContent, BrainOpenGLWidget* openGLWidget, const int32_t browserWindowIndex, const int32_t x, const int32_t y, const int32_t dx, const int32_t dy, const int32_t mousePressX, const int32_t mousePressY, const bool firstDraggingFlag); virtual ~MouseEvent(); MouseEvent(const MouseEvent& o); MouseEvent& operator=(const MouseEvent& o); private: void initializeMembersMouseEvent(); void copyHelperMouseEvent(const MouseEvent& me); public: AString toString() const; BrainOpenGLViewportContent* getViewportContent() const; BrainOpenGLWidget* getOpenGLWidget() const; int32_t getBrowserWindowIndex() const; int32_t getDx() const; int32_t getDy() const; int32_t getX() const; int32_t getY() const; int32_t getPressedX() const; int32_t getPressedY() const; void getGlobalXY(const int32_t x, const int32_t y, int32_t& outGlobalX, int32_t& outGlobalY) const; int32_t getWheelRotation() const; bool isFirstDragging() const; private: BrainOpenGLViewportContent* m_viewportContent; BrainOpenGLWidget* m_openGLWidget; int32_t m_browserWindowIndex; int32_t m_x; int32_t m_y; int32_t m_dx; int32_t m_dy; int32_t m_pressX; int32_t m_pressY; int32_t m_wheelRotation; bool m_firstDraggingFlag; }; } // namespace #endif // __MouseEvent_H__ connectome-workbench-1.4.2/src/GuiQt/MovieDialog.cxx000066400000000000000000000722411360521144700224040ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #ifdef CARET_OS_WINDOWS #include #else #include #endif #include "MovieDialog.h" #include "ui_MovieDialog.h" #include "BrowserTabContent.h" #include "BrainBrowserWindow.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPreferences.h" #include "DataFileException.h" #include "EventManager.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventImageCapture.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "ImageFile.h" #include #include "Model.h" #include "ModelSurface.h" #include "ModelSurfaceSelector.h" #include "SessionManager.h" #include "Surface.h" #include "WuQMessageBox.h" #include #include #include using namespace caret; /** * \class caret::MovieDialog * \brief Dialog used for setting up and rendering Movies. * \ingroup GuiQt */ MovieDialog::MovieDialog(QWidget *parent) : QDialog(parent), ui(new Ui::MovieDialog) { ui->setupUi(this); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS); m_browserWindowIndex = 0; frame_number = 0; rotate_frame_number = 0; imageX = 0; imageY = 0; m_animationStarted = false; m_volumeSliceIncrement = 0; m_reverseVolumeSliceDirection = false; m_PStart = 0; m_CStart = 0; m_AStart = 0; m_PEnd = 0; m_CEnd = 0; m_AEnd = 0; m_interpolationIndex = 0; m_surface = NULL; m_surface1 = NULL; m_surface2 = NULL; } MovieDialog::~MovieDialog() { ui->animateButton->setChecked(false); delete ui; EventManager::get()->removeAllEventsFromListener(this); } void MovieDialog::on_closeButton_clicked() { ui->animateButton->setChecked(false); this->close(); } void MovieDialog::on_interpolateSurfaceCheckbox_toggled(bool checked) { if ( ! checked) { return; } BrainBrowserWindow *bw = GuiManager::get()->getBrowserWindowByWindowIndex(m_browserWindowIndex); if(!bw) { WuQMessageBox::errorOk(this, "Invalid browser window index, " + AString::number(m_browserWindowIndex)); return; } BrowserTabContent *btc1 = bw->getBrowserTabContent(0); BrowserTabContent *btc2 = bw->getBrowserTabContent(1); if(!btc1 || !btc2) { this->ui->interpolateSurfaceCheckbox->blockSignals(true); this->ui->interpolateSurfaceCheckbox->setChecked(false); this->ui->interpolateSurfaceCheckbox->blockSignals(false); WuQMessageBox::errorOk(this, "There must be two browser tabs."); return; } // int32_t tabIndex1 = btc1->getTabNumber(); if ((btc1->getSelectedModelType() != ModelTypeEnum::MODEL_TYPE_SURFACE) || (btc2->getSelectedModelType() != ModelTypeEnum::MODEL_TYPE_SURFACE)) { this->ui->interpolateSurfaceCheckbox->blockSignals(true); this->ui->interpolateSurfaceCheckbox->setChecked(false); this->ui->interpolateSurfaceCheckbox->blockSignals(false); WuQMessageBox::errorOk(this, "Both Tab 1 and Tab 2 must contain surface models."); return; } ModelSurface *ms1 = btc1->getDisplayedSurfaceModel(); // int32_t tabIndex2 = btc2->getTabNumber(); ModelSurface *ms2 = btc2->getDisplayedSurfaceModel(); if(!(ms1&&ms2)) return; if (ms1->getSurface()->getStructure() != ms2->getSurface()->getStructure()) { this->ui->interpolateSurfaceCheckbox->blockSignals(true); this->ui->interpolateSurfaceCheckbox->setChecked(false); this->ui->interpolateSurfaceCheckbox->blockSignals(false); WuQMessageBox::errorOk(this, "Surfaces in Tab 1 and Tab 2 must be the same structure."); return; } } void MovieDialog::on_animateButton_toggled(bool checked) { // this->renderMovieButton->setChecked(status); dx = this->ui->rotateXSpinBox->value(); dy = this->ui->rotateYSpinBox->value(); dz = this->ui->rotateZSpinBox->value(); frameCount = this->ui->rotateFrameCountSpinBox->value(); reverseDirection = this->ui->reverseDirectionCheckBox->isChecked(); frameCountEnabled = this->ui->rotateFrameCountSpinBox->value() ? true : false; m_interpolationEnabled = this->ui->interpolateSurfaceCheckbox->isChecked(); m_interpolationSteps = this->ui->interpolationStepsSpinBox->value(); if(checked) { //this->renderMovieButton->setText("Stop"); this->m_animationStarted = true; this->m_isInterpolating = true; while(this->ui->animateButton->isChecked()) { EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows(true).getPointer()); QCoreApplication::instance()->processEvents(); m_animationStarted = false; } this->m_animationStarted = false; } else { //this->renderMovieButton->setText("Play"); this->CleanupInterpolation(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows(true).getPointer()); } rotate_frame_number = 0; } void MovieDialog::on_recordButton_toggled(bool checked) { if(checked) { m_useCustomSize = ui->customSizeRadioButton->isChecked(); imageX = 0; imageY = 0; if(m_useCustomSize) { imageX = ui->windowWidthSpinBox->value(); imageY = ui->windowHeightSpinBox->value(); } } if(!checked&&(frame_number > 0)) { //render frames.... QString formatString("Movie Files (*.mpg *.mp4)"); AString fileName = QFileDialog::getSaveFileName( this, tr("Save File"),QString::null, formatString ); AString tempDir = QDir::tempPath(); if ( !fileName.isEmpty() ) { // int crop[4]; // crop[0] = imageX; // crop[1] = imageY; // crop[2] = 0; // crop[3] = 0; // if(!(crop[0]&&crop[1])) GuiManager::get()->getBrowserWindowByWindowIndex(m_browserWindowIndex)->getViewportSize(crop[0],crop[1]); unlink(fileName); CaretLogInfo("Rendering movie to:" + fileName); AString ffmpeg = SystemUtilities::getWorkbenchHome() + AString("/ffmpeg "); // JWH ffmpeg = "/mnt/myelin/distribution/caret7_distribution/workbench//macosx64_apps/ffmpeg "; double frame_rate = 30.0/double(1 + this->ui->repeatFramesSpinBox->value()); // if(ui->cropImageCheckBox->isChecked()) // { // this->getImageCrop(tempDir + "/movie0" + AString(".png"),crop); // } // // crop[0] = (crop[0]/2)*2; // crop[1] = (crop[1]/2)*2; // CaretLogInfo("Resizing image from " + AString::number(imageX) + AString(":") + AString::number(imageY) + AString(" to ") + // AString::number(crop[0]) + AString(":") + AString::number(crop[1])); // // AString command = ffmpeg + AString("-threads 4 -r " + AString::number(frame_rate) + " -i "+ tempDir + "/movie%d.png -r 30 -q:v 1 -vf crop=" + // AString::number(crop[0]) + ":" + AString::number(crop[1]) + ":" + // AString::number(crop[2]) + ":" + AString::number(crop[3]) + " " + fileName); AString command = ffmpeg + AString("-threads 4 -r " + AString::number(frame_rate) + " -i "+ tempDir + "/movie%d.png -r 30 -q:v 1 " + fileName); CaretLogFine("running " + command); system(command.toLatin1().data()); CaretLogFine("Finished rendering " + fileName); } for(int i = 0;iui->marginSpinBox->value(); // CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); // uint8_t backgroundColor[3]; // prefs->getColorBackground(backgroundColor); // // ImageFile file; // file.readFile(fileName); // // int leftTopRightBottom[4]; // file.findImageObject(backgroundColor,leftTopRightBottom); // // const int width = leftTopRightBottom[2] - leftTopRightBottom[0] + 1; // const int height = leftTopRightBottom[3] - leftTopRightBottom[1] + 1; // cropOut[0] = width + 2*marginSize; // cropOut[1] = height + 2*marginSize; // cropOut[2] = leftTopRightBottom[0]+marginSize; // cropOut[3] = leftTopRightBottom[1]+marginSize; //} void MovieDialog::processRotateTransformation(const double dx, const double dy, const double dz) { BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); if (browserTabContent == NULL) { return; } Model* modelController = browserTabContent->getModelForDisplay(); if (modelController != NULL) { // const int32_t tabIndex = browserTabContent->getTabNumber(); { Matrix4x4 rotationMatrix = browserTabContent->getRotationMatrix(); rotationMatrix.rotateX(dx); rotationMatrix.rotateY(dy); rotationMatrix.rotateZ(dz); browserTabContent->setRotationMatrix(rotationMatrix); // /* // * There are several rotation matrix. The 'NORMAL' matrix is used // * in most cases and others are used in special viewing modes // * such as surface montage and right/left lateral medial yoking // */ // if (browserTabContent->isDisplayedModelSurfaceRightLateralMedialYoked()) { // Matrix4x4* rotationMatrix = modelController->getViewingRotationMatrix(tabIndex, // Model::VIEWING_TRANSFORM_NORMAL); // rotationMatrix->rotateX(dx); // rotationMatrix->rotateY(dy); // rotationMatrix->rotateZ(dz); // // /* // * Matrix for a right medial/lateral yoked surface // */ // Matrix4x4* rotationMatrixRightLatMedYoked = modelController->getViewingRotationMatrix(tabIndex, // Model::VIEWING_TRANSFORM_RIGHT_LATERAL_MEDIAL_YOKED); // rotationMatrixRightLatMedYoked->rotateX(-dx); // rotationMatrixRightLatMedYoked->rotateY(-dy); // rotationMatrixRightLatMedYoked->rotateZ(-dz); // } // else { // // // Matrix4x4* rotationMatrix = modelController->getViewingRotationMatrix(tabIndex, // Model::VIEWING_TRANSFORM_NORMAL); // rotationMatrix->rotateX(-dx); // rotationMatrix->rotateY(dy); // rotationMatrix->rotateZ(dz); // // /* // * Matrix for a left surface opposite view in surface montage // */ // Matrix4x4* rotationMatrixSurfMontLeftOpp = modelController->getViewingRotationMatrix(tabIndex, // Model::VIEWING_TRANSFORM_SURFACE_MONTAGE_LEFT_OPPOSITE); // rotationMatrixSurfMontLeftOpp->rotateX(-dx); // rotationMatrixSurfMontLeftOpp->rotateY(dy); // rotationMatrixSurfMontLeftOpp->rotateZ(dz); // // /* // * Matrix for a right surface view in surface montage // */ // Matrix4x4* rotationMatrixSurfMontRight = modelController->getViewingRotationMatrix(tabIndex, // Model::VIEWING_TRANSFORM_SURFACE_MONTAGE_RIGHT); // rotationMatrixSurfMontRight->rotateX(dx); // rotationMatrixSurfMontRight->rotateY(-dy); // rotationMatrixSurfMontRight->rotateZ(dz); // // /* // * Matrix for a right surface opposite view in surface montage // */ // Matrix4x4* rotationMatrixSurfMontRightOpp = modelController->getViewingRotationMatrix(tabIndex, // Model::VIEWING_TRANSFORM_SURFACE_MONTAGE_RIGHT_OPPOSITE); // rotationMatrixSurfMontRightOpp->rotateX(dx); // rotationMatrixSurfMontRightOpp->rotateY(-dy); // rotationMatrixSurfMontRightOpp->rotateZ(dz); // // /* // * Matrix for a right medial/lateral yoked surface // */ // Matrix4x4* rotationMatrixRightLatMedYoked = modelController->getViewingRotationMatrix(tabIndex, // Model::VIEWING_TRANSFORM_RIGHT_LATERAL_MEDIAL_YOKED); // rotationMatrixRightLatMedYoked->rotateX(dx); // rotationMatrixRightLatMedYoked->rotateY(-dy); // rotationMatrixRightLatMedYoked->rotateZ(dz); // } } } } /** * Receive events from the event manager. * * @param event * Event sent by event manager. */ void MovieDialog::receiveEvent(Event* event) { if(event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS || event->getEventType() == EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW ) { AString tempPath = QDir::tempPath(); if(this->ui->recordButton->isChecked()) { this->captureFrame(tempPath + AString("/movie") + AString::number(frame_number) + AString(".png")); AString temp = tempPath + AString("/movie") + AString::number(frame_number) + AString(".png"); CaretLogFine(temp); CaretLogFine("frame number:" + QString::number(frame_number)); frame_number++; } if(this->ui->animateButton->isChecked()) { this->processUpdateVolumeSlice(); this->processUpdateSurfaceInterpolation(); if(frameCountEnabled && frameCount) { if(!reverseDirection) { if(frameCount <= rotate_frame_number) { //this->ui->animateButton->setChecked(false); dx = dy = dz = 0.0; return; } } else { if(!(rotate_frame_number %frameCount) && (rotate_frame_number > 0)) { dx *= -1.0; dy *= -1.0; dz *= -1.0; } } } if(dx || dy || dz) { this->processRotateTransformation(dx, dy, dz); } rotate_frame_number++; } } } int32_t MovieDialog::getSliceDelta(const std::vector &dim, const caret::VolumeSliceViewPlaneEnum::Enum &vpe, const int32_t &sliceIndex) { if(m_animationStarted) { m_volumeSliceIncrement = ui->sliceIncrementCountSpinBox->value(); m_reverseVolumeSliceDirection = ui->reverseSliceDirectionCheckBox->isChecked(); m_sliceIncrementIsNegative = (m_volumeSliceIncrement != abs(m_volumeSliceIncrement)); switch(vpe) { case VolumeSliceViewPlaneEnum::AXIAL: if(m_sliceIncrementIsNegative) { m_AEnd = sliceIndex; m_AStart = 0>(m_AEnd+m_volumeSliceIncrement)?0:m_AEnd+m_volumeSliceIncrement; dA=-1; } else { m_AStart = sliceIndex; m_AEnd = (dim[2]-1)<(m_AStart+m_volumeSliceIncrement)?(dim[2]-1):m_AStart+m_volumeSliceIncrement; dA=1; } break; case VolumeSliceViewPlaneEnum::CORONAL: if(m_sliceIncrementIsNegative) { m_CEnd = sliceIndex; m_CStart = 0>(m_CEnd+m_volumeSliceIncrement)?0:m_CEnd+m_volumeSliceIncrement; dC=-1; } else { m_CStart = sliceIndex; m_CEnd = (dim[1]-1)<(m_CStart+m_volumeSliceIncrement)?(dim[1]-1):m_CStart+m_volumeSliceIncrement; dC=1; } break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: if(m_sliceIncrementIsNegative) { m_PEnd = sliceIndex; m_PStart = 0>(m_PEnd+m_volumeSliceIncrement)?0:m_PEnd+m_volumeSliceIncrement; dP=-1; } else { m_PStart = sliceIndex; m_PEnd = (dim[0]-1)<(m_PStart+m_volumeSliceIncrement)?(dim[0]-1):m_PStart+m_volumeSliceIncrement; dP=1; } break; default: break; } } switch(vpe) { case VolumeSliceViewPlaneEnum::AXIAL: if(dA > 0 ) //the current increment is positive { if((m_AEnd-sliceIndex) > 0) //there is still room to increment by one { return dA; } else if(m_reverseVolumeSliceDirection) { return dA = -dA; } else { return 0; } } else if(dA < 0) { if((sliceIndex-m_AStart) > 0) { return dA; } else if(m_reverseVolumeSliceDirection) { return dA = -dA; } else { return 0; } } return dA; break; case VolumeSliceViewPlaneEnum::CORONAL: if(dC > 0 ) //the current increment is positive { if((m_CEnd-sliceIndex) > 0) //there is still room to increment by one { return dC; } else if(m_reverseVolumeSliceDirection) { return dC = -dC; } else { return 0; } } else if(dC < 0) { if((sliceIndex-m_CStart) > 0) { return dC; } else if(m_reverseVolumeSliceDirection) { return dC = -dC; } else { return 0; } } return dC; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: if(dP > 0 ) //the current increment is positive { if((m_PEnd-sliceIndex) > 0) //there is still room to increment by one { return dP; } else if(m_reverseVolumeSliceDirection) { return dP = -dP; } else { return 0; } } else if(dP < 0) { if((sliceIndex-m_PStart) > 0) { return dP; } else if(m_reverseVolumeSliceDirection) { return dP = -dP; } else { return 0; } } return dP; break; default: break; } return 0; } void MovieDialog::processUpdateVolumeSlice() { BrainBrowserWindow *bw = GuiManager::get()->getBrowserWindowByWindowIndex(m_browserWindowIndex); if(!bw) { CaretLogInfo("Invalid browser window index, " + AString::number(m_browserWindowIndex)); ui->animateButton->setChecked(false); return; } BrowserTabContent *btc = bw->getBrowserTabContent(); int32_t tabIndex = btc->getTabNumber(); ModelVolume* mv = btc->getDisplayedVolumeModel(); if(mv == NULL) { return; } switch (btc->getSliceProjectionType()) { case caret::VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: return; break; case caret::VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: break; } // VolumeSliceCoordinateSelection* vscs = btc->getSelectedVolumeSlices(); VolumeMappableInterface* vf = mv->getUnderlayVolumeFile(tabIndex); std::vector dim; vf->getDimensions(dim); VolumeSliceViewPlaneEnum::Enum vpe = btc->getSliceViewPlane(); if(vpe == VolumeSliceViewPlaneEnum::ALL || vpe == VolumeSliceViewPlaneEnum::AXIAL) { int64_t sliceIndex = btc->getSliceIndexAxial(vf); sliceIndex += this->getSliceDelta(dim,VolumeSliceViewPlaneEnum::AXIAL,sliceIndex); btc->setSliceIndexAxial(vf,sliceIndex); } if(vpe == VolumeSliceViewPlaneEnum::ALL || vpe == VolumeSliceViewPlaneEnum::CORONAL) { int64_t sliceIndex = btc->getSliceIndexCoronal(vf); sliceIndex += this->getSliceDelta(dim,VolumeSliceViewPlaneEnum::CORONAL,sliceIndex); btc->setSliceIndexCoronal(vf,sliceIndex); } if(vpe == VolumeSliceViewPlaneEnum::ALL || vpe == VolumeSliceViewPlaneEnum::PARASAGITTAL) { int64_t sliceIndex = btc->getSliceIndexParasagittal(vf); sliceIndex += this->getSliceDelta(dim,VolumeSliceViewPlaneEnum::PARASAGITTAL,sliceIndex); btc->setSliceIndexParasagittal(vf,sliceIndex); } } void MovieDialog::captureFrame(AString filename) { ImageFile imageFile; QApplication::setOverrideCursor(QCursor(Qt::BlankCursor)); // bool valid = GuiManager::get()->captureImageOfBrowserWindowGraphicsArea(m_browserWindowIndex, // imageX, // imageY, // imageFile, // false); EventImageCapture imageCaptureEvent(m_browserWindowIndex, 0, 0, 0, 0, imageX, imageY); EventManager::get()->sendEvent(imageCaptureEvent.getPointer()); bool valid = true; AString errorMessage; if (imageCaptureEvent.getEventProcessCount() <= 0) { errorMessage = "Invalid window selected"; valid = false; } else if (imageCaptureEvent.isError()) { errorMessage = imageCaptureEvent.getErrorMessage(); valid = false; } imageFile.setFromQImage(imageCaptureEvent.getImage()); QApplication::restoreOverrideCursor(); if (valid == false) { WuQMessageBox::errorOk(this, errorMessage); // "Invalid window selected"); ui->recordButton->setChecked(false); return; } /*if (ui->cropImageCheckBox->isChecked()) { const int marginSize = ui->marginSpinBox->value(); CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); uint8_t backgroundColor[3]; prefs->getColorBackground(backgroundColor); imageFile.cropImageRemoveBackground(marginSize, backgroundColor); croppedImageX = imageFile.getAsQImage()->size().height(); croppedImageY = imageFile.getAsQImage()->size().width(); }*/ std::vector imageFileExtensions; AString defaultFileExtension; ImageFile::getImageFileExtensions(imageFileExtensions, defaultFileExtension); bool validExtension = false; for (std::vector::iterator extensionIterator = imageFileExtensions.begin(); extensionIterator != imageFileExtensions.end(); extensionIterator++) { if (filename.endsWith(*extensionIterator)) { validExtension = true; } } if (validExtension == false) { if (defaultFileExtension.isEmpty() == false) { filename += ("." + defaultFileExtension); } } uint8_t backgroundColor[3]; imageCaptureEvent.getBackgroundColor(backgroundColor); try { const int marginSize = this->ui->marginSpinBox->value(); if (marginSize > 0) { imageFile.addMargin(marginSize, backgroundColor); } imageFile.writeFile(filename); } catch (const DataFileException& /*e*/) { QString msg("Unable to save: " + filename); WuQMessageBox::errorOk(this, msg); } } void MovieDialog::on_workbenchWindowSpinBox_valueChanged(int arg1) { m_browserWindowIndex = arg1-1; } void MovieDialog::processUpdateSurfaceInterpolation() { if(!m_interpolationEnabled||!m_isInterpolating) return; BrainBrowserWindow *bw = GuiManager::get()->getBrowserWindowByWindowIndex(m_browserWindowIndex); if(!bw) { CaretLogInfo("Invalid browser window index, " + AString::number(m_browserWindowIndex)); ui->animateButton->setChecked(false); return; } BrowserTabContent *btc1 = bw->getBrowserTabContent(0); BrowserTabContent *btc2 = bw->getBrowserTabContent(1); if(!btc1) return; if(!btc2) return; // int32_t tabIndex1 = btc1->getTabNumber(); if ((btc1->getSelectedModelType() != ModelTypeEnum::MODEL_TYPE_SURFACE) || (btc2->getSelectedModelType() != ModelTypeEnum::MODEL_TYPE_SURFACE)) { CaretLogInfo("Both Tab 1 and Tab 2 must contain surface models."); return; } ModelSurface *ms1 = btc1->getDisplayedSurfaceModel(); // int32_t tabIndex2 = btc2->getTabNumber(); ModelSurface *ms2 = btc2->getDisplayedSurfaceModel(); if(!(ms1&&ms2)) return; if (ms1->getSurface()->getStructure() != ms2->getSurface()->getStructure()) { CaretLogInfo("Surfaces in Tab 1 and Tab 2 must be the same structure."); return; } if(m_interpolationIndex == 0) { m_surface1 = ms1->getSurface(); m_surface2 = ms2->getSurface(); int32_t coordCount1 = m_surface1->getNumberOfNodes(); int32_t coordCount2 = m_surface2->getNumberOfNodes(); if(coordCount1 != coordCount2) return; const float* coords1 = m_surface1->getCoordinateData(); const float* coords2 = m_surface2->getCoordinateData(); float center1[3]; float center2[3]; float centerdelta[3]; m_surface1->getBoundingBox()->getCenter(center1); m_surface2->getBoundingBox()->getCenter(center2); for(int i = 0;i<3;i++) { centerdelta[i] = center2[i]-center1[i]; } m_surfaceCoords2Back.clear(); m_delta.clear(); for(int32_t i = 0;isetCoordinates(coords); m_surface2->invalidateNormals(); m_surface2->computeNormals(); btc1->getSurfaceModelSelector()->setSelectedSurfaceModel(btc2->getSurfaceModelSelector()->getSelectedSurfaceModel()); btc1->getSurfaceModelSelector()->setSelectedStructure(btc2->getSurfaceModelSelector()->getSelectedStructure()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } if(m_interpolationIndex setCoordinates(coords); m_surface2->invalidateNormals(); m_surface2->computeNormals(); m_interpolationIndex++; } else { CleanupInterpolation(); } } void MovieDialog::CleanupInterpolation() { if(!m_interpolationEnabled||!m_isInterpolating) return; if (m_surface2 == NULL) { return; } for(int64_t i = 0;isetCoordinates(coords); m_surface2->invalidateNormals(); m_surface2->computeNormals(); m_isInterpolating = false; m_interpolationIndex = 0; if(!coords) { delete coords; coords = NULL; coordsCount = 0; } m_surface1 = NULL; m_surface2 = NULL; } connectome-workbench-1.4.2/src/GuiQt/MovieDialog.h000066400000000000000000000061301360521144700220230ustar00rootroot00000000000000#ifndef MOVIE_DIALOG_H #define MOVIE_DIALOG_H /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "Event.h" #include "EventListenerInterface.h" #include namespace Ui { class MovieDialog; } using namespace caret; namespace caret { class Surface; } class MovieDialog : public QDialog, public EventListenerInterface { Q_OBJECT public: explicit MovieDialog(QWidget *parent = 0); ~MovieDialog(); void receiveEvent(Event* event); void processUpdateVolumeSlice(); void processUpdateSurfaceInterpolation(); int32_t getSliceDelta(const std::vector &dim, const caret::VolumeSliceViewPlaneEnum::Enum &vpe, const int32_t &sliceIndex); //void getImageCrop(AString fileName, int *cropout); private slots: void on_closeButton_clicked(); void on_animateButton_toggled(bool checked); void on_interpolateSurfaceCheckbox_toggled(bool checked); void on_recordButton_toggled(bool checked); void on_workbenchWindowSpinBox_valueChanged(int arg1); private: Ui::MovieDialog *ui; void captureFrame(AString filename); void processRotateTransformation(const double dx, const double dy, const double dz); void CleanupInterpolation(); int32_t m_browserWindowIndex; int frame_number; int rotate_frame_number; double dx; double dy; double dz; bool frameCountEnabled; int frameCount; bool reverseDirection; int32_t dP;//change in Parasagital slice int32_t dC;//change in Coronal slice int32_t dA;//change in Axial slice bool m_useCustomSize; int32_t imageX; int32_t imageY; int32_t croppedImageX; int32_t croppedImageY; bool m_animationStarted; int32_t m_volumeSliceIncrement; bool m_sliceIncrementIsNegative; bool m_reverseVolumeSliceDirection; int64_t m_AStart; int64_t m_AEnd; int64_t m_CStart; int64_t m_CEnd; int64_t m_PStart; int64_t m_PEnd; bool m_interpolationEnabled; int64_t m_interpolationSteps; int64_t m_interpolationIndex; bool m_isInterpolating; std::vector m_delta; std::vector m_surfaceCoords2Back; float *coords; int64_t coordsCount; Surface *m_surface1; Surface *m_surface2; Surface *m_surface; }; #endif // MOVIE_DIALOG_H connectome-workbench-1.4.2/src/GuiQt/MovieDialog.ui000077500000000000000000000355471360521144700222320ustar00rootroot00000000000000 MovieDialog 0 0 459 567 0 0 Animation Control true Image Source Workbench Window: 1 10 Qt::Horizontal 40 20 Recording Control true Repeat Frames: true Qt::Horizontal 40 20 true Record true Rotation Control 0 0 Y: 0 0 X: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter -180.000000000000000 180.000000000000000 -180.000000000000000 180.000000000000000 999999999 Rotate Frame Count: Reverse Direction -180.000000000000000 180.000000000000000 Z: Qt::Horizontal 40 20 true Slice Control Slice Increment Count -999 999 Reverse Direction Qt::Horizontal 40 20 true Interpolate Surfaces true Interpolate Surface in Tab 1 to Surface in Tab 2 Qt::Horizontal 40 20 Interpolation Steps true 1 99999 20 Qt::Horizontal 40 20 true Image Size Size of Window true Custom 1 10000 2560 1 10000 1600 Qt::Horizontal 40 20 true Image Options true Margin true 1000 10 Qt::Horizontal 40 20 Qt::Horizontal 40 20 Animate true Close true connectome-workbench-1.4.2/src/GuiQt/MovieRecordingDialog.cxx000066400000000000000000000625371360521144700242500ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __MOVIE_RECORDING_DIALOG_DECLARE__ #include "MovieRecordingDialog.h" #undef __MOVIE_RECORDING_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include #include #include "Brain.h" #include "BrainBrowserWindowComboBox.h" #include "CaretAssert.h" #include "CaretFileDialog.h" #include "CursorDisplayScoped.h" #include "Event.h" #include "EventManager.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventMovieManualModeRecording.h" #include "EventUserInterfaceUpdate.h" #include "EnumComboBoxTemplate.h" #include "FileInformation.h" #include "GuiManager.h" #include "MovieRecorder.h" #include "MovieRecorderVideoFormatTypeEnum.h" #include "SessionManager.h" #include "WuQMessageBox.h" using namespace caret; /** * \class caret::MovieRecordingDialog * \brief Dialog for control of movie recording and creation * \ingroup GuiQt */ /** * Constructor. */ MovieRecordingDialog::MovieRecordingDialog(QWidget* parent) : WuQDialogNonModal("Movie Recording", parent) { QTabWidget* tabWidget = new QTabWidget(); tabWidget->addTab(createMainWidget(), "Main"); tabWidget->addTab(createSettingsWidget(), "Settings"); setCentralWidget(tabWidget, SCROLL_AREA_NEVER); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_MOVIE_RECORDING_DIALOG_UPDATE); setApplyButtonText(""); disableAutoDefaultForAllPushButtons(); CaretAssert(SessionManager::get()->getMovieRecorder()); } /** * Destructor. */ MovieRecordingDialog::~MovieRecordingDialog() { EventManager::get()->removeAllEventsFromListener(this); } /** * Called when close event is issuedf * * @param event * The close event */ void MovieRecordingDialog::closeEvent(QCloseEvent* event) { s_previousDialogGeometry = saveGeometry(); WuQDialogNonModal::closeEvent(event); } void MovieRecordingDialog::restorePositionAndSize() { if ( ! s_previousDialogGeometry.isEmpty()) { restoreGeometry(s_previousDialogGeometry); } } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void MovieRecordingDialog::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_MOVIE_RECORDING_DIALOG_UPDATE) { updateDialog(); event->setEventProcessed(); } } /** * May be called to update the dialog's content. */ void MovieRecordingDialog::updateDialog() { const MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); CaretAssert(movieRecorder); m_windowComboBox->updateComboBox(); m_windowComboBox->setBrowserWindowByIndex(movieRecorder->getRecordingWindowIndex()); switch (movieRecorder->getRecordingMode()) { case MovieRecorderModeEnum::MANUAL: m_recordingManualRadioButton->setChecked(true); break; case MovieRecorderModeEnum::AUTOMATIC: m_recordingAutomaticRadioButton->setChecked(true); break; } const MovieRecorderVideoResolutionTypeEnum::Enum resType = movieRecorder->getVideoResolutionType(); m_movieRecorderVideoResolutionTypeEnumComboBox->setSelectedItem(resType); const MovieRecorderCaptureRegionTypeEnum::Enum captureType = movieRecorder->getCaptureRegionType(); m_movieRecorderCaptureRegionTypeComboBox->setSelectedItem(captureType); updateManualRecordingOptions(); updateCustomWidthHeightSpinBoxes(); updateFrameCountLabel(); } /** * Update the manual recording options */ void MovieRecordingDialog::updateManualRecordingOptions() { const MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); CaretAssert(movieRecorder); bool manualRecordingEnabledFlag(false); switch (movieRecorder->getRecordingMode()) { case MovieRecorderModeEnum::MANUAL: manualRecordingEnabledFlag = true; break; case MovieRecorderModeEnum::AUTOMATIC: break; } m_manualCaptureToolButton->setEnabled(manualRecordingEnabledFlag); } /** * Update the custom width/height spin boxes */ void MovieRecordingDialog::updateCustomWidthHeightSpinBoxes() { const MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); CaretAssert(movieRecorder); int32_t customWidth(0); int32_t customHeight(0); movieRecorder->getCustomWidthAndHeight(customWidth, customHeight); QSignalBlocker widthBlocker(m_customWidthSpinBox); m_customWidthSpinBox->setValue(customWidth); QSignalBlocker heightBlocker(m_customHeightSpinBox); m_customHeightSpinBox->setValue(customHeight); QSignalBlocker frameRateBlocker(m_frameRateSpinBox); m_frameRateSpinBox->setValue(movieRecorder->getFramesRate()); m_removeTemporaryImagesAfterMovieCreationCheckBox->setChecked(movieRecorder->isRemoveTemporaryImagesAfterMovieCreation()); const bool customSpinBoxesEnabled(movieRecorder->getVideoResolutionType() == MovieRecorderVideoResolutionTypeEnum::CUSTOM); m_customWidthSpinBox->setEnabled(customSpinBoxesEnabled); m_customHeightSpinBox->setEnabled(customSpinBoxesEnabled); } /** * Update the frame count label */ void MovieRecordingDialog::updateFrameCountLabel() { MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); const int32_t numberOfFrames = movieRecorder->getNumberOfFrames(); m_frameCountNumberLabel->setNum(numberOfFrames); const int32_t timeSeconds = (movieRecorder->getNumberOfFrames() / movieRecorder->getFramesRate()); QTime qtime(0, 0, 0, 0); QTime timeForString = qtime.addSecs(timeSeconds); m_lengthLabel->setText(timeForString.toString("h:mm:ss")); /* * Do not allow user to change image size once an image has been captured */ m_movieRecorderVideoResolutionTypeEnumComboBox->getWidget()->setEnabled(numberOfFrames <= 0); } /** * Called when window index is changed * * @param windowIndex * Index of window for recording */ void MovieRecordingDialog::windowIndexSelected(const int32_t windowIndex) { SessionManager::get()->getMovieRecorder()->setRecordingWindowIndex(windowIndex); } /** * Called when video resolution type is changed */ void MovieRecordingDialog::movieRecorderVideoResolutionTypeEnumComboBoxItemActivated() { const MovieRecorderVideoResolutionTypeEnum::Enum dimType = m_movieRecorderVideoResolutionTypeEnumComboBox->getSelectedItem(); SessionManager::get()->getMovieRecorder()->setVideoResolutionType(dimType); updateCustomWidthHeightSpinBoxes(); } /** * Called when capture region type is changed */ void MovieRecordingDialog::movieRecorderCaptureRegionTypeComboBoxActivated() { const MovieRecorderCaptureRegionTypeEnum::Enum regionType = m_movieRecorderCaptureRegionTypeComboBox->getSelectedItem(); SessionManager::get()->getMovieRecorder()->setCaptureRegionType(regionType); } /** * Set the selected browser window to the browser window with the * given index. * @param browserWindowIndex * Index of browser window. */ void MovieRecordingDialog::setBrowserWindowIndex(const int32_t browserWindowIndex) { m_windowComboBox->setBrowserWindowByIndex(browserWindowIndex); windowIndexSelected(browserWindowIndex); } /** * @param Called when custom width spin box value changed * * @param width * New custom width */ void MovieRecordingDialog::customWidthSpinBoxValueChanged(int width) { SessionManager::get()->getMovieRecorder()->setCustomWidthAndHeight(width, m_customHeightSpinBox->value()); } /** * @param Called when custom height spin box value changed * * @param height * New custom height */ void MovieRecordingDialog::customHeightSpinBoxValueChanged(int height) { SessionManager::get()->getMovieRecorder()->setCustomWidthAndHeight(m_customWidthSpinBox->value(), height); } /** * @param Called when frame rate spin box value changed * * @param frameRate * New frame rate */ void MovieRecordingDialog::frameRateSpinBoxValueChanged(int frameRate) { SessionManager::get()->getMovieRecorder()->setFramesRate(frameRate); } /** * @param Called when remove temporary images checkbox is clicked * * @param checked * New checked status */ void MovieRecordingDialog::removeTemporaryImagesCheckBoxClicked(bool checked) { if ( ! checked) { const QString text("If this is deselected, additional movies may contain images from previous movies."); if ( ! WuQMessageBox::warningOkCancel(m_removeTemporaryImagesAfterMovieCreationCheckBox, text)) { checked = true; } } SessionManager::get()->getMovieRecorder()->setRemoveTemporaryImagesAfterMovieCreation(checked); m_removeTemporaryImagesAfterMovieCreationCheckBox->setChecked(checked); } /** * Called when recording mode button is clicked * * @param button * Button that was clicked */ void MovieRecordingDialog::recordingModeRadioButtonClicked(QAbstractButton* button) { MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); CaretAssert(movieRecorder); if (button == m_recordingAutomaticRadioButton) { movieRecorder->setRecordingMode(MovieRecorderModeEnum::AUTOMATIC); } else if (button == m_recordingManualRadioButton) { movieRecorder->setRecordingMode(MovieRecorderModeEnum::MANUAL); } else { CaretAssert(0); } updateManualRecordingOptions(); } /** * Called when manual capture tool button is clicked */ void MovieRecordingDialog::manualCaptureToolButtonClicked() { CursorDisplayScoped cursor; cursor.showWaitCursor(); EventMovieManualModeRecording movieEvent(m_windowComboBox->getSelectedBrowserWindowIndex(), m_manualCaptureSecondsSpinBox->value()); EventManager::get()->sendEvent(movieEvent.getPointer()); updateFrameCountLabel(); } /** * Called when manual capture seconds spin box value changed */ void MovieRecordingDialog::manualCaptureSecondsSpinBoxValueChanged(int /*seconds*/) { } /** * Called when create movie push button is clicked */ void MovieRecordingDialog::createMoviePushButtonClicked() { createMoviePrivate(m_createMoviePushButton, true); QApplication::beep(); } /** * Get the movie file name * * @param parent * Widget as parent for file selection dialog * @return * Name for movie file or empty string if canceled. */ QString MovieRecordingDialog::getMovieFileNameFromFileDialog(QWidget* parent) { MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); QString currentFileName = movieRecorder->getMovieFileName(); MovieRecorderVideoFormatTypeEnum::Enum formatType = MovieRecorderVideoFormatTypeEnum::MPEG; QString filters; QString selectedFilter = MovieRecorderVideoFormatTypeEnum::toFileDialogFilter(formatType); std::vector formatEnums; MovieRecorderVideoFormatTypeEnum::getAllEnums(formatEnums); for (auto fe : formatEnums) { if ( ! filters.isEmpty()) { filters.append(";;"); } filters.append(MovieRecorderVideoFormatTypeEnum::toFileDialogFilter(fe)); if (currentFileName.endsWith(MovieRecorderVideoFormatTypeEnum::toFileNameExtensionNoDot(fe))) { formatType = fe; selectedFilter = MovieRecorderVideoFormatTypeEnum::toFileDialogFilter(fe); } } QString filename = CaretFileDialog::getSaveFileNameDialog(parent, "Choose Movie File", currentFileName, filters, &selectedFilter, CaretFileDialog::DontConfirmOverwrite); if (filename.isEmpty()) { return ""; } for (auto fe : formatEnums) { if (selectedFilter == MovieRecorderVideoFormatTypeEnum::toFileDialogFilter(fe)) { const QString ext = ("." + MovieRecorderVideoFormatTypeEnum::toFileNameExtensionNoDot(fe)); if ( ! filename.endsWith(ext)) { filename.append(ext); break; } } } return filename; } /** * Create a movie from captured images and if current * filename is empty, ask for name in file dialog * * @param parent * Parent widget for error message dialog. */ void MovieRecordingDialog::createMovie(QWidget* parent) { createMoviePrivate(parent, false); } /** * Create a movie from captured images. * * @param parent * Parent widget for error message dialog. * @param askForFileNameFlag * If true always query for filename, even if filename is valid */ void MovieRecordingDialog::createMoviePrivate(QWidget* parent, const bool askForFileNameFlag) { MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); QString filename(movieRecorder->getMovieFileName()); if (filename.isEmpty() || askForFileNameFlag) { filename = getMovieFileNameFromFileDialog(parent); } if (filename.isEmpty()) { return; } FileInformation fileInfo(filename); const QString name(fileInfo.getCanonicalFilePath()); if (fileInfo.exists()) { if ( ! fileInfo.remove()) { AString msg("Unable to remove movie file \"" + name + "\""); WuQMessageBox::errorOk(parent, msg); } } AString errorMessage; const bool successFlag = movieRecorder->createMovie(filename, errorMessage); if ( ! successFlag) { WuQMessageBox::errorOk(parent, errorMessage); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** * Called when reset push button is clicked */ void MovieRecordingDialog::resetPushButtonClicked() { if (WuQMessageBox::warningOkCancel(m_resetPushButton, "Reset (delete) recorded images for new movie")) { SessionManager::get()->getMovieRecorder()->removeTemporaryImages(); updateDialog(); } } /** * @return New instance of main widget */ QWidget* MovieRecordingDialog::createMainWidget() { QLabel* windowLabel = new QLabel("Record from Window:"); m_windowComboBox = new BrainBrowserWindowComboBox(BrainBrowserWindowComboBox::STYLE_NUMBER, this); m_windowComboBox->setToolTip("Sets window that is recorded"); QObject::connect(m_windowComboBox, &BrainBrowserWindowComboBox::browserWindowIndexSelected, this, &MovieRecordingDialog::windowIndexSelected); QLabel* regionLabel = new QLabel("Record Region:"); m_movieRecorderCaptureRegionTypeComboBox = new EnumComboBoxTemplate(this); m_movieRecorderCaptureRegionTypeComboBox->getWidget()->setToolTip("Choose region that is capture for movie"); m_movieRecorderCaptureRegionTypeComboBox->setup(); QObject::connect(m_movieRecorderCaptureRegionTypeComboBox, SIGNAL(itemActivated()), this, SLOT(movieRecorderCaptureRegionTypeComboBoxActivated())); QGroupBox* sourceGroupBox = new QGroupBox("Source"); QGridLayout* sourceLayout = new QGridLayout(sourceGroupBox); sourceLayout->setColumnStretch(0, 0); sourceLayout->setColumnStretch(0, 1); sourceLayout->setColumnStretch(2, 100); int sourceRow(0); sourceLayout->addWidget(windowLabel, sourceRow, 0); sourceLayout->addWidget(m_windowComboBox->getWidget(), sourceRow, 1); sourceRow++; sourceLayout->addWidget(regionLabel, sourceRow, 0); sourceLayout->addWidget(m_movieRecorderCaptureRegionTypeComboBox->getWidget(), sourceRow, 1); sourceRow++; m_recordingAutomaticRadioButton = new QRadioButton(MovieRecorderModeEnum::toGuiName(MovieRecorderModeEnum::AUTOMATIC)); m_recordingAutomaticRadioButton->setToolTip("When selected, images are recorded as graphics updated"); const QString recordButtonText("Record"); m_recordingManualRadioButton = new QRadioButton(MovieRecorderModeEnum::toGuiName(MovieRecorderModeEnum::MANUAL)); m_recordingManualRadioButton->setToolTip("When selected, images recorded when " + recordButtonText + " is clicked"); QButtonGroup* recordingButtonGroup = new QButtonGroup(this); recordingButtonGroup->addButton(m_recordingAutomaticRadioButton); recordingButtonGroup->addButton(m_recordingManualRadioButton); QObject::connect(recordingButtonGroup, QOverload::of(&QButtonGroup::buttonClicked), this, &MovieRecordingDialog::recordingModeRadioButtonClicked); m_manualCaptureToolButton = new QToolButton(); m_manualCaptureToolButton->setText(recordButtonText); m_manualCaptureToolButton->setToolTip("Duration of image displayed in movie"); QObject::connect(m_manualCaptureToolButton, &QToolButton::clicked, this, &MovieRecordingDialog::manualCaptureToolButtonClicked); m_manualCaptureSecondsSpinBox = new QSpinBox(); m_manualCaptureSecondsSpinBox->setMinimum(1); m_manualCaptureSecondsSpinBox->setMaximum(100); m_manualCaptureSecondsSpinBox->setSingleStep(1); m_manualCaptureSecondsSpinBox->setSizePolicy(QSizePolicy::Fixed, m_manualCaptureSecondsSpinBox->sizePolicy().verticalPolicy()); QObject::connect(m_manualCaptureSecondsSpinBox, QOverload::of(&QSpinBox::valueChanged), this, &MovieRecordingDialog::manualCaptureSecondsSpinBoxValueChanged); QLabel* captureSecondsLabel = new QLabel("seconds"); QGroupBox* modeGroupBox = new QGroupBox("Recording Mode"); QGridLayout* modeLayout = new QGridLayout(modeGroupBox); modeLayout->setColumnStretch(0, 0); modeLayout->setColumnStretch(1, 0); modeLayout->setColumnStretch(2, 0); modeLayout->setColumnStretch(3, 0); modeLayout->setColumnStretch(4, 100); int32_t modeRow(0); modeLayout->addWidget(m_recordingAutomaticRadioButton, modeRow, 0); modeRow++; modeLayout->addWidget(m_recordingManualRadioButton, modeRow, 0); modeLayout->addWidget(m_manualCaptureToolButton, modeRow, 1); modeLayout->addWidget(m_manualCaptureSecondsSpinBox, modeRow, 2); modeLayout->addWidget(captureSecondsLabel, modeRow, 3); modeRow++; m_createMoviePushButton = new QPushButton("Create Movie"); m_createMoviePushButton->setToolTip("Create a movie file using images that have been recorded"); QObject::connect(m_createMoviePushButton, &QPushButton::clicked, this, &MovieRecordingDialog::createMoviePushButtonClicked); m_resetPushButton = new QPushButton("Reset"); m_resetPushButton->setToolTip("Remove all recorded images to start a new movie"); QObject::connect(m_resetPushButton, &QPushButton::clicked, this, &MovieRecordingDialog::resetPushButtonClicked); QLabel* frameCountLabel = new QLabel("Frames: "); m_frameCountNumberLabel = new QLabel("0"); QLabel* lengthLabel = new QLabel("Length: "); m_lengthLabel = new QLabel("0"); QGroupBox* movieFileGroupBox = new QGroupBox("Output Movie"); QGridLayout* movieLayout = new QGridLayout(movieFileGroupBox); movieLayout->setColumnStretch(0, 0); movieLayout->setColumnStretch(1, 0); movieLayout->setColumnStretch(2, 0); movieLayout->setColumnStretch(3, 100); int32_t movieRow(0); movieLayout->addWidget(m_createMoviePushButton, movieRow, 0); movieLayout->addWidget(lengthLabel, movieRow, 1); movieLayout->addWidget(m_lengthLabel, movieRow, 2); movieRow++; movieLayout->addWidget(m_resetPushButton, movieRow, 0); movieLayout->addWidget(frameCountLabel, movieRow, 1); movieLayout->addWidget(m_frameCountNumberLabel, movieRow, 2); movieRow++; QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(sourceGroupBox); layout->addWidget(modeGroupBox); layout->addWidget(movieFileGroupBox); layout->addStretch(); return widget; } /** * @return New instance of settings widget */ QWidget* MovieRecordingDialog::createSettingsWidget() { const int spinBoxWidth(100); QLabel* resolutionLabel = new QLabel("Resolution:"); m_movieRecorderVideoResolutionTypeEnumComboBox = new EnumComboBoxTemplate(this); m_movieRecorderVideoResolutionTypeEnumComboBox->getWidget()->setToolTip("Choose width and height of movie"); m_movieRecorderVideoResolutionTypeEnumComboBox->setup(); QObject::connect(m_movieRecorderVideoResolutionTypeEnumComboBox, SIGNAL(itemActivated()), this, SLOT(movieRecorderVideoResolutionTypeEnumComboBoxItemActivated())); QLabel* customLabel = new QLabel("Custom Resolution:"); m_customWidthSpinBox = new QSpinBox(); m_customWidthSpinBox->setMinimum(1); m_customWidthSpinBox->setMaximum(500000); m_customWidthSpinBox->setSingleStep(1); QObject::connect(m_customWidthSpinBox, QOverload::of(&QSpinBox::valueChanged), this, &MovieRecordingDialog::customWidthSpinBoxValueChanged); m_customWidthSpinBox->setFixedWidth(spinBoxWidth); m_customHeightSpinBox = new QSpinBox(); m_customHeightSpinBox->setMinimum(1); m_customHeightSpinBox->setMaximum(500000); m_customHeightSpinBox->setSingleStep(1); m_customHeightSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_customHeightSpinBox, QOverload::of(&QSpinBox::valueChanged), this, &MovieRecordingDialog::customHeightSpinBoxValueChanged); QLabel* frameRateLabel = new QLabel("Frames Per Second:"); m_frameRateSpinBox = new QSpinBox(); m_frameRateSpinBox->setToolTip("20 or 30 recommended"); m_frameRateSpinBox->setMinimum(1); m_frameRateSpinBox->setMaximum(1000); m_frameRateSpinBox->setSingleStep(1); m_frameRateSpinBox->setFixedWidth(spinBoxWidth); QObject::connect(m_frameRateSpinBox, QOverload::of(&QSpinBox::valueChanged), this, &MovieRecordingDialog::frameRateSpinBoxValueChanged); m_removeTemporaryImagesAfterMovieCreationCheckBox = new QCheckBox("Remove temporary images after movie creation"); m_removeTemporaryImagesAfterMovieCreationCheckBox->setToolTip("Temporary images are removed after a movie is created"); QObject::connect(m_removeTemporaryImagesAfterMovieCreationCheckBox, &QCheckBox::clicked, this, &MovieRecordingDialog::removeTemporaryImagesCheckBoxClicked); QWidget* widget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(widget); gridLayout->setRowStretch(100, 100); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 0); gridLayout->setColumnStretch(2, 0); gridLayout->setColumnStretch(3, 100); int32_t row(0); gridLayout->addWidget(resolutionLabel, row, 0); gridLayout->addWidget(m_movieRecorderVideoResolutionTypeEnumComboBox->getWidget(), row, 1, 1, 2, Qt::AlignLeft); row++; gridLayout->addWidget(customLabel, row, 0); gridLayout->addWidget(m_customWidthSpinBox, row, 1); gridLayout->addWidget(m_customHeightSpinBox, row, 2); row++; gridLayout->addWidget(frameRateLabel, row, 0); gridLayout->addWidget(m_frameRateSpinBox, row, 1, 1, 2, Qt::AlignLeft); row++; gridLayout->addWidget(m_removeTemporaryImagesAfterMovieCreationCheckBox, row, 0, 1, 3, Qt::AlignLeft); row++; return widget; } connectome-workbench-1.4.2/src/GuiQt/MovieRecordingDialog.h000066400000000000000000000106331360521144700236630ustar00rootroot00000000000000#ifndef __MOVIE_RECORDING_DIALOG_H__ #define __MOVIE_RECORDING_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "EventListenerInterface.h" #include "WuQDialogNonModal.h" class QAbstractButton; class QCheckBox; class QLabel; class QPushButton; class QRadioButton; class QSpinBox; class QToolButton; namespace caret { class BrainBrowserWindowComboBox; class EnumComboBoxTemplate; class MovieRecordingDialog : public WuQDialogNonModal, public EventListenerInterface { Q_OBJECT public: MovieRecordingDialog(QWidget* parent); virtual ~MovieRecordingDialog(); MovieRecordingDialog(const MovieRecordingDialog&) = delete; MovieRecordingDialog& operator=(const MovieRecordingDialog&) = delete; void setBrowserWindowIndex(const int32_t browserWindowIndex); void updateDialog(); void restorePositionAndSize(); // ADD_NEW_METHODS_HERE virtual void receiveEvent(Event* event); static void createMovie(QWidget* parent); static QString getMovieFileNameFromFileDialog(QWidget* parent); private slots: void movieRecorderVideoResolutionTypeEnumComboBoxItemActivated(); void movieRecorderCaptureRegionTypeComboBoxActivated(); void recordingModeRadioButtonClicked(QAbstractButton* button); void customWidthSpinBoxValueChanged(int width); void customHeightSpinBoxValueChanged(int width); void frameRateSpinBoxValueChanged(int frameRate); void removeTemporaryImagesCheckBoxClicked(bool checked); void windowIndexSelected(const int32_t windowIndex); void createMoviePushButtonClicked(); void resetPushButtonClicked(); void manualCaptureToolButtonClicked(); void manualCaptureSecondsSpinBoxValueChanged(int seconds); protected: virtual void closeEvent(QCloseEvent* event) override; private: void updateFrameCountLabel(); void updateCustomWidthHeightSpinBoxes(); void updateManualRecordingOptions(); QWidget* createMainWidget(); QWidget* createSettingsWidget(); static void createMoviePrivate(QWidget* parent, const bool askForFileNameFlag); QRadioButton* m_recordingAutomaticRadioButton; QRadioButton* m_recordingManualRadioButton; QToolButton* m_manualCaptureToolButton; QSpinBox* m_manualCaptureSecondsSpinBox; EnumComboBoxTemplate* m_movieRecorderVideoResolutionTypeEnumComboBox; QSpinBox* m_customWidthSpinBox; QSpinBox* m_customHeightSpinBox; QSpinBox* m_frameRateSpinBox; QCheckBox* m_removeTemporaryImagesAfterMovieCreationCheckBox; QPushButton* m_createMoviePushButton; QPushButton* m_resetPushButton; QLabel* m_frameCountNumberLabel; QLabel* m_lengthLabel; BrainBrowserWindowComboBox* m_windowComboBox; EnumComboBoxTemplate* m_movieRecorderCaptureRegionTypeComboBox; static QByteArray s_previousDialogGeometry; // ADD_NEW_MEMBERS_HERE }; #ifdef __MOVIE_RECORDING_DIALOG_DECLARE__ QByteArray MovieRecordingDialog::s_previousDialogGeometry; #endif // __MOVIE_RECORDING_DIALOG_DECLARE__ } // namespace #endif //__MOVIE_RECORDING_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/OffScreenOpenGLRenderer.cxx000066400000000000000000000114501360521144700246060ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretOpenGLInclude.h" #define __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ #include "OffScreenOpenGLRenderer.h" #undef __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ #include #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET #include #else #include #include #endif #include #include #include #include "BrainOpenGLWidget.h" #include "CaretAssert.h" using namespace caret; /** * \class caret::OffScreenOpenGLRenderer * \brief Performs offscreen rendering of a window. * \ingroup GuiQt */ /** * Constructor. * * @param openGLWidgetInstance * An instance of either QGLWidget or QOpenGLWidget * @param width * Width for image (may be different, perhaps larger, than width of 'openglWidget' * @param height * Height for image (may be different, perhaps larger, than hight of 'openglWidget' */ #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET OffScreenOpenGLRenderer::OffScreenOpenGLRenderer(QOpenGLWidget* openglWidget, #else OffScreenOpenGLRenderer::OffScreenOpenGLRenderer(QGLWidget* openglWidget, #endif const int32_t width, const int32_t height) : QObject() { CaretAssert(openglWidget); m_openglContext = NULL;; QSurfaceFormat surfaceFormat; /* * Copy the surface format */ #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET surfaceFormat = openglWidget->format(); m_openglContext = openglWidget->context(); #else surfaceFormat = QGLFormat::toSurfaceFormat(openglWidget->format()); CaretAssert(openglWidget->context()); m_openglContext = openglWidget->context()->contextHandle(); #endif // QGLWidget* glWidget = dynamic_cast(openGLWidgetInstance); // QOpenGLWidget* openglWidget = dynamic_cast(openGLWidgetInstance); // if (glWidget != NULL) { // } // else if (openglWidget != NULL) { // } // else { // m_errorMessage = "Unable to cast openglQtWidget to QGLWidget nor QOpenGLWidget"; // return; // } CaretAssert(m_openglContext); if ( ! m_openglContext->isValid()) { m_errorMessage = "The OpenGL Context is not valid"; return; } // since context is already valid, do not need to do this: openglContext->setFormat(surfaceFormat); m_offScreenSurface.reset(new QOffscreenSurface()); m_offScreenSurface->setFormat(surfaceFormat); m_offScreenSurface->create(); if ( ! m_offScreenSurface->isValid()) { m_errorMessage = "Offscreen surface is not valid after setFormat() and create()"; return; } if ( ! m_openglContext->makeCurrent(m_offScreenSurface.get())) { m_errorMessage = "Unable to makeCurrent() using Off Screen Surface"; return; } QOpenGLFramebufferObjectFormat frameBufferFormat; frameBufferFormat.setSamples(2); frameBufferFormat.setAttachment(QOpenGLFramebufferObject::Depth); frameBufferFormat.setTextureTarget(GL_TEXTURE_2D); m_frameBuffer.reset(new QOpenGLFramebufferObject(width, height, frameBufferFormat)); if ( ! m_frameBuffer->isValid()) { m_errorMessage = "Unable to create frame buffer object for Off Screen Rendering"; m_openglContext->doneCurrent(); return; } } /** * Destructor. */ OffScreenOpenGLRenderer::~OffScreenOpenGLRenderer() { m_openglContext->doneCurrent(); } bool OffScreenOpenGLRenderer::isError() const { return ( ! m_errorMessage.isEmpty()); } QString OffScreenOpenGLRenderer::getErrorMessage() const { return m_errorMessage; } QImage OffScreenOpenGLRenderer::getImage() { QImage image; if ( ! m_frameBuffer) { m_errorMessage = "Frame buffer is invalid while trying to get image"; return image; } image = m_frameBuffer->toImage(); return image; } connectome-workbench-1.4.2/src/GuiQt/OffScreenOpenGLRenderer.h000066400000000000000000000045031360521144700242340ustar00rootroot00000000000000#ifndef __OFF_SCREEN_OPEN_G_L_RENDERER_H__ #define __OFF_SCREEN_OPEN_G_L_RENDERER_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include class QGLWidget; class QOpenGLFramebufferObject; class QOffscreenSurface; class QOpenGLContext; class QOpenGLWidget; class QSurfaceFormat; class QWidget; namespace caret { class OffScreenOpenGLRenderer : public QObject { Q_OBJECT public: #ifdef WORKBENCH_USE_QT5_QOPENGL_WIDGET OffScreenOpenGLRenderer(QOpenGLWidget* openglWidget, #else OffScreenOpenGLRenderer(QGLWidget* openglWidget, #endif const int32_t width, const int32_t height); virtual ~OffScreenOpenGLRenderer(); bool isError() const; QString getErrorMessage() const; QImage getImage(); // ADD_NEW_METHODS_HERE private: OffScreenOpenGLRenderer(const OffScreenOpenGLRenderer&); OffScreenOpenGLRenderer& operator=(const OffScreenOpenGLRenderer&); std::unique_ptr m_offScreenSurface; std::unique_ptr m_frameBuffer; QOpenGLContext* m_openglContext; QString m_errorMessage; // ADD_NEW_MEMBERS_HERE }; #ifdef __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ // #endif // __OFF_SCREEN_OPEN_G_L_RENDERER_DECLARE__ } // namespace #endif //__OFF_SCREEN_OPEN_G_L_RENDERER_H__ connectome-workbench-1.4.2/src/GuiQt/OverlaySetViewController.cxx000066400000000000000000000254621360521144700252040ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #define __OVERLAY_SET_VIEW_CONTROLLER_DECLARE__ #include "OverlaySetViewController.h" #undef __OVERLAY_SET_VIEW_CONTROLLER_DECLARE__ #include "BrainConstants.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventManager.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "OverlaySet.h" #include "OverlayViewController.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::OverlaySetViewController * \brief View Controller for an overlay set. * \ingroup GuiQt */ /** * Constructor. * * @param orientation * Orientation for layout * @param browserWindowIndex * Index of browser window that contains this view controller. * @param parentObjectName * Name of parent * @param parent * Parent widget. */ OverlaySetViewController::OverlaySetViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent) : QWidget(parent) { this->browserWindowIndex = browserWindowIndex; QWidget* gridWidget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(gridWidget); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 4, 2); if (orientation == Qt::Horizontal) { gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 0); gridLayout->setColumnStretch(2, 0); gridLayout->setColumnStretch(3, 0); gridLayout->setColumnStretch(4, 0); gridLayout->setColumnStretch(5, 100); gridLayout->setColumnStretch(6, 0); gridLayout->setColumnStretch(7, 0); gridLayout->setColumnStretch(8, 100); QLabel* onLabel = new QLabel("On"); QLabel* settingsLabel = new QLabel("Settings"); QLabel* opacityLabel = new QLabel("Opacity"); QLabel* fileLabel = new QLabel("File"); QLabel* yokeLabel = new QLabel("Yoke"); QLabel* mapLabel = new QLabel("Map"); const int row = gridLayout->rowCount(); gridLayout->addWidget(onLabel, row, 0, Qt::AlignHCenter); gridLayout->addWidget(settingsLabel, row, 1, 1, 3, Qt::AlignHCenter); gridLayout->addWidget(opacityLabel, row, 4, Qt::AlignHCenter); gridLayout->addWidget(fileLabel, row, 5, Qt::AlignHCenter); gridLayout->addWidget(yokeLabel, row, 6, Qt::AlignHCenter); gridLayout->addWidget(mapLabel, row, 8, 1, 2, Qt::AlignHCenter); } else { gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 0); gridLayout->setColumnStretch(2, 0); gridLayout->setColumnStretch(3, 0); gridLayout->setColumnStretch(4, 0); gridLayout->setColumnStretch(5, 0); gridLayout->setColumnStretch(6, 100); } for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS; i++) { OverlayViewController* ovc = new OverlayViewController(orientation, gridLayout, browserWindowIndex, i, parentObjectName, this); this->overlayViewControllers.push_back(ovc); QObject::connect(ovc, SIGNAL(requestAddOverlayAbove(const int32_t)), this, SLOT(processAddOverlayAbove(const int32_t))); QObject::connect(ovc, SIGNAL(requestAddOverlayBelow(const int32_t)), this, SLOT(processAddOverlayBelow(const int32_t))); QObject::connect(ovc, SIGNAL(requestRemoveOverlay(const int32_t)), this, SLOT(processRemoveOverlay(const int32_t))); QObject::connect(ovc, SIGNAL(requestMoveOverlayUp(const int32_t)), this, SLOT(processMoveOverlayUp(const int32_t))); QObject::connect(ovc, SIGNAL(requestMoveOverlayDown(const int32_t)), this, SLOT(processMoveOverlayDown(const int32_t))); } if (orientation == Qt::Horizontal) { QVBoxLayout* verticalLayout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(verticalLayout, 2, 2); verticalLayout->addWidget(gridWidget); verticalLayout->addStretch(); } else { /* * Resolve WB-649 */ QVBoxLayout* verticalLayout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(verticalLayout, 1, 1); verticalLayout->addWidget(gridWidget); verticalLayout->addStretch(); // QVBoxLayout* verticalLayout = new QVBoxLayout(); // WuQtUtilities::setLayoutSpacingAndMargins(verticalLayout, 1, 1); // verticalLayout->addWidget(gridWidget); // verticalLayout->addStretch(); // // QHBoxLayout* horizontalLayout = new QHBoxLayout(this); // WuQtUtilities::setLayoutSpacingAndMargins(horizontalLayout, 1, 1); // horizontalLayout->addLayout(verticalLayout); // horizontalLayout->addStretch(); } EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); } /** * Destructor. */ OverlaySetViewController::~OverlaySetViewController() { EventManager::get()->removeAllEventsFromListener(this); } /** * @return The overlay set in this view controller. */ OverlaySet* OverlaySetViewController::getOverlaySet() { OverlaySet* overlaySet = NULL; BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(this->browserWindowIndex, true); if (browserTabContent != NULL) { overlaySet = browserTabContent->getOverlaySet(); } return overlaySet; } /** * Update this overlay set view controller using the given overlay set. */ void OverlaySetViewController::updateViewController() { OverlaySet* overlaySet = this->getOverlaySet(); if (overlaySet == NULL) { return; } const int32_t numberOfOverlays = static_cast(this->overlayViewControllers.size()); const int32_t numberOfDisplayedOverlays = overlaySet->getNumberOfDisplayedOverlays(); for (int32_t i = 0; i < numberOfOverlays; i++) { Overlay* overlay = NULL; if (overlaySet != NULL) { overlay = overlaySet->getOverlay(i); } this->overlayViewControllers[i]->updateViewController(overlay); bool displayOverlay = (overlay != NULL); if (i >= numberOfDisplayedOverlays) { displayOverlay = false; } this->overlayViewControllers[i]->setVisible(displayOverlay); } } /** * Receive events from the event manager. * * @param event * Event sent by event manager. */ void OverlaySetViewController::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiEvent = dynamic_cast(event); CaretAssert(uiEvent); if (uiEvent->isUpdateForWindow(this->browserWindowIndex)) { if (uiEvent->isToolBoxUpdate()) { this->updateViewController(); uiEvent->setEventProcessed(); } } } } /** * Add an overlay above the overlay with the given index. * @param overlayIndex * Index of overlay that will have an overlay added above it. */ void OverlaySetViewController::processAddOverlayAbove(const int32_t overlayIndex) { OverlaySet* overlaySet = getOverlaySet(); if (overlaySet != NULL) { overlaySet->insertOverlayAbove(overlayIndex); this->updateColoringAndGraphics(); } } /** * Add an overlay below the overlay with the given index. * @param overlayIndex * Index of overlay that will have an overlay added below it. */ void OverlaySetViewController::processAddOverlayBelow(const int32_t overlayIndex) { OverlaySet* overlaySet = getOverlaySet(); if (overlaySet != NULL) { overlaySet->insertOverlayBelow(overlayIndex); this->updateColoringAndGraphics(); } } /** * Remove an overlay above the overlay with the given index. * @param overlayIndex * Index of overlay that will be removed */ void OverlaySetViewController::processRemoveOverlay(const int32_t overlayIndex) { OverlaySet* overlaySet = getOverlaySet(); if (overlaySet != NULL) { overlaySet->removeDisplayedOverlay(overlayIndex); this->updateColoringAndGraphics(); } } /** * Remove an overlay above the overlay with the given index. * @param overlayIndex * Index of overlay that will be removed */ void OverlaySetViewController::processMoveOverlayDown(const int32_t overlayIndex) { OverlaySet* overlaySet = getOverlaySet(); if (overlaySet != NULL) { overlaySet->moveDisplayedOverlayDown(overlayIndex); this->updateColoringAndGraphics(); } } /** * Remove an overlay above the overlay with the given index. * @param overlayIndex * Index of overlay that will be removed */ void OverlaySetViewController::processMoveOverlayUp(const int32_t overlayIndex) { OverlaySet* overlaySet = getOverlaySet(); if (overlaySet != NULL) { overlaySet->moveDisplayedOverlayUp(overlayIndex); this->updateColoringAndGraphics(); } } /** * Update surface coloring and graphics after overlay changes. */ void OverlaySetViewController::updateColoringAndGraphics() { this->updateViewController(); EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventGraphicsUpdateOneWindow graphicsUpdate(this->browserWindowIndex); EventManager::get()->sendEvent(graphicsUpdate.getPointer()); } connectome-workbench-1.4.2/src/GuiQt/OverlaySetViewController.h000066400000000000000000000052031360521144700246200ustar00rootroot00000000000000#ifndef __OVERLAY_SET_VIEW_CONTROLLER__H_ #define __OVERLAY_SET_VIEW_CONTROLLER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "EventListenerInterface.h" class QScrollArea; class QSpinBox; namespace caret { class OverlaySet; class OverlayViewController; class OverlaySetViewController : public QWidget, public EventListenerInterface { Q_OBJECT public: OverlaySetViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, const QString& parentObjectName, QWidget* parent = 0); virtual ~OverlaySetViewController(); void receiveEvent(Event* event); private slots: void processAddOverlayAbove(const int32_t overlayIndex); void processAddOverlayBelow(const int32_t overlayIndex); void processRemoveOverlay(const int32_t overlayIndex); void processMoveOverlayDown(const int32_t overlayIndex); void processMoveOverlayUp(const int32_t overlayIndex); private: OverlaySetViewController(const OverlaySetViewController&); OverlaySetViewController& operator=(const OverlaySetViewController&); OverlaySet* getOverlaySet(); void updateViewController(); void updateColoringAndGraphics(); std::vector overlayViewControllers; int32_t browserWindowIndex; QScrollArea* scrollArea; }; #ifdef __OVERLAY_SET_VIEW_CONTROLLER_DECLARE__ // #endif // __OVERLAY_SET_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__OVERLAY_SET_VIEW_CONTROLLER__H_ connectome-workbench-1.4.2/src/GuiQt/OverlaySettingsEditorDialog.cxx000066400000000000000000000653621360521144700256440ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #define __OVERLAY_SETTINGS_EDITOR_DIALOG_DECLARE__ #include "OverlaySettingsEditorDialog.h" #undef __OVERLAY_SETTINGS_EDITOR_DIALOG_DECLARE__ #include "CaretMappableDataFile.h" #include "ChartTwoOverlay.h" #include "CiftiFiberTrajectoryFile.h" #include "CiftiConnectivityMatrixParcelFile.h" #include "EventChartOverlayValidate.h" #include "EventDataFileDelete.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventOverlayValidate.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUserInterfaceUpdate.h" #include "GiftiLabelTableEditor.h" #include "MapSettingsChartTwoLineHistoryWidget.h" #include "MapSettingsColorBarWidget.h" #include "MapSettingsFiberTrajectoryWidget.h" #include "MapSettingsLabelsWidget.h" #include "MapSettingsLayerWidget.h" #include "MapSettingsPaletteColorMappingWidget.h" #include "MapSettingsParcelsWidget.h" #include "Overlay.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::__OVERLAY_SETTINGS_EDITOR_DIALOG_DECLARE__ * \brief Dialog for editing an overlay's settings * \ingroup GuiQt */ /** * Constructor for editing a palette selection. * * @param parent * Parent widget on which this dialog is displayed. */ OverlaySettingsEditorDialog::OverlaySettingsEditorDialog(QWidget* parent) : WuQDialogNonModal("Overlay and Map Settings", parent), EventListenerInterface() { /* * No context menu, it screws things up */ this->setContextMenuPolicy(Qt::NoContextMenu); this->setDeleteWhenClosed(false); m_caretMappableDataFile = NULL; m_selectedMapFileIndex = -1; m_brainordinateOverlay = NULL; m_chartOverlay = NULL; m_chartOverlaySelectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; /* * No apply button */ this->setApplyButtonText(""); QWidget* mapNameWidget = createMapFileAndNameSection(); m_colorBarWidget = new MapSettingsColorBarWidget(); m_fiberTrajectoryWidget = new MapSettingsFiberTrajectoryWidget(); m_layerWidget = new MapSettingsLayerWidget(); m_paletteColorMappingWidget = new MapSettingsPaletteColorMappingWidget(); m_parcelsWidget = new MapSettingsParcelsWidget(); QWidget* windowOptionsWidget = this->createWindowOptionsSection(); m_labelsWidget = new MapSettingsLabelsWidget(); m_lineHistoryWidget = new MapSettingsChartTwoLineHistoryWidget(); m_tabWidget = new QTabWidget(); m_colorBarWidgetTabIndex = m_tabWidget->addTab(m_colorBarWidget, "Color Bar"); m_labelsWidgetTabIndex = m_tabWidget->addTab(m_labelsWidget, "Labels"); m_tabWidget->setTabEnabled(m_tabWidget->count() - 1, false); m_layersWidgetTabIndex = m_tabWidget->addTab(m_layerWidget, "Layer"); m_lineHistoryWidgetTabIndex = m_tabWidget->addTab(m_lineHistoryWidget, "Lines"); m_metadataWidgetTabIndex = m_tabWidget->addTab(new QWidget(), "Metadata"); m_tabWidget->setTabEnabled(m_tabWidget->count() - 1, false); m_paletteWidgetTabIndex = m_tabWidget->addTab(m_paletteColorMappingWidget, "Palette"); m_parcelsWidgetTabIndex = m_tabWidget->addTab(m_parcelsWidget, "Parcels"); m_trajectoryWidgetTabIndex = m_tabWidget->addTab(m_fiberTrajectoryWidget, "Trajectory"); m_tabWidget->setCurrentIndex(m_tabWidget->count() - 1); QWidget* w = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(w); this->setLayoutSpacingAndMargins(layout); layout->addWidget(mapNameWidget); layout->addWidget(m_tabWidget); //layout->addWidget(windowOptionsWidget); this->setCentralWidget(w, WuQDialog::SCROLL_AREA_NEVER); this->addWidgetToLeftOfButtons(windowOptionsWidget); disableAutoDefaultForAllPushButtons(); EventManager::get()->addProcessedEventListener(this, EventTypeEnum::EVENT_DATA_FILE_DELETE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN); } /** * Destructor. */ OverlaySettingsEditorDialog::~OverlaySettingsEditorDialog() { EventManager::get()->removeAllEventsFromListener(this); } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void OverlaySettingsEditorDialog::receiveEvent(Event* event) { if ((event->getEventType() == EventTypeEnum::EVENT_DATA_FILE_DELETE) || (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN)) { updateDialog(); } } /** * @return Create and return map file and name section of the dialog. * */ QWidget* OverlaySettingsEditorDialog::createMapFileAndNameSection() { QLabel* mapFileNameLabel = new QLabel("Map File: "); m_selectedMapFileNameLabel = new QLabel(""); QLabel* mapNameLabel = new QLabel("Map Name: "); m_selectedMapNameLabel = new QLabel(""); QGroupBox* groupBox = new QGroupBox(); QGridLayout* gridLayout = new QGridLayout(groupBox); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 2); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); gridLayout->addWidget(mapFileNameLabel, 0, 0); gridLayout->addWidget(m_selectedMapFileNameLabel, 0, 1, Qt::AlignLeft); gridLayout->addWidget(mapNameLabel, 1, 0); gridLayout->addWidget(m_selectedMapNameLabel, 1, 1, Qt::AlignLeft); return groupBox; } /** * Called for focus events. Since this dialog stores a pointer * to the overlay, we need to be aware that the overlay's parameters * may change or the overlay may even be deleted. So, when * this dialog gains focus, validate the overlay and then update * the dialog. * * @param event * The focus event. */ void OverlaySettingsEditorDialog::focusInEvent(QFocusEvent* event) { if (event->reason() == Qt::PopupFocusReason) { /* * This occurs when a combo box is popped up Mac, * causes a problem, and can be ignored. */ return; } updateDialog(); } /** * Update if the given overlay is displayed in the dialog. * * @param brainordinateOverlay * Brainordinate overlay for the dialog. * @param chartOverlay * Chart overlay for the dialog. */ void OverlaySettingsEditorDialog::updateIfThisOverlayIsInDialog(Overlay* brainordinateOverlay, ChartTwoOverlay* chartOverlay) { if (m_brainordinateOverlay != NULL) { if (m_brainordinateOverlay == brainordinateOverlay) { updateDialogContent(m_brainordinateOverlay, NULL); } } else if (m_chartOverlay != NULL) { if (m_chartOverlay == chartOverlay) { updateDialogContent(NULL, m_chartOverlay); } } } /** * May be called to update the dialog's content. * * @param brainordinateOverlay * Brainordinate overlay for the dialog. * @param chartOverlay * Chart overlay for the dialog. */ void OverlaySettingsEditorDialog::updateDialogContent(Overlay* brainordinateOverlay, ChartTwoOverlay* chartOverlay) { updateDialogContentPrivate(brainordinateOverlay, chartOverlay); } /** * Update the dialog's content. Only one of the parameters * should be non-NULL. * * @param brainordinateOverlay * Brainordinate overlay for the dialog. * @param chartOverlay * Chart overlay for the dialog. */ void OverlaySettingsEditorDialog::updateDialogContentPrivate(Overlay* brainordinateOverlay, ChartTwoOverlay* chartOverlay) { if ((brainordinateOverlay != NULL) && (chartOverlay != NULL)) { CaretAssert(0); // only one should be non-NULL } const int32_t selectedTabIndex = m_tabWidget->currentIndex(); m_brainordinateOverlay = brainordinateOverlay; m_chartOverlay = chartOverlay; m_caretMappableDataFile = NULL; m_chartOverlaySelectedIndexType = ChartTwoOverlay::SelectedIndexType::INVALID; m_selectedMapFileIndex = -1; if (m_brainordinateOverlay != NULL) { m_brainordinateOverlay->getSelectionData(m_caretMappableDataFile, m_selectedMapFileIndex); } if (m_chartOverlay != NULL) { m_chartOverlay->getSelectionData(m_caretMappableDataFile, m_chartOverlaySelectedIndexType, m_selectedMapFileIndex); } bool isLabelsValid = false; bool isMetadataValid = false; GiftiMetaData* metadata = NULL; bool isPaletteValid = false; bool isParcelsValid = false; bool isFiberTrajectoryValid = false; bool isVolumeLayer = false; bool isLinesValid = false; QString mapFileName = ""; QString mapName = ""; if (m_caretMappableDataFile != NULL) { if (m_brainordinateOverlay != NULL) { if ((m_selectedMapFileIndex >= 0) && (m_selectedMapFileIndex < m_caretMappableDataFile->getNumberOfMaps())) { /* * Get name of file and map */ mapFileName = m_caretMappableDataFile->getFileNameNoPath(); if (m_selectedMapFileIndex >= 0) { mapName = m_caretMappableDataFile->getMapName(m_selectedMapFileIndex); } /* * Update layer widget */ m_layerWidget->updateContent(m_brainordinateOverlay); if (m_caretMappableDataFile->isMappedWithLabelTable()) { if (m_caretMappableDataFile->getMapLabelTable(m_selectedMapFileIndex) != NULL) { /* * Update label editor */ isLabelsValid = true; m_labelsWidget->updateContent(m_brainordinateOverlay); } } metadata = m_caretMappableDataFile->getMapMetaData(m_selectedMapFileIndex); if (metadata != NULL) { /* * TODO: Update metadata widget */ //isMetadataValid = true; } if (m_caretMappableDataFile->isMappedWithPalette()) { PaletteColorMapping* paletteColorMapping = m_caretMappableDataFile->getMapPaletteColorMapping(m_selectedMapFileIndex); if (paletteColorMapping != NULL) { /* * Update palette settings */ isPaletteValid = true; m_paletteColorMappingWidget->updateEditor(m_caretMappableDataFile, m_selectedMapFileIndex); AnnotationColorBar* colorBar = NULL; if (m_brainordinateOverlay != NULL) { colorBar = m_brainordinateOverlay->getColorBar(); } else if (m_chartOverlay != NULL) { colorBar = m_chartOverlay->getColorBar(); } m_colorBarWidget->updateContent(m_caretMappableDataFile, m_selectedMapFileIndex, colorBar, paletteColorMapping); } } CiftiFiberTrajectoryFile* trajFile = dynamic_cast(m_caretMappableDataFile); if (trajFile != NULL) { /* * Update trajectory */ isFiberTrajectoryValid = true; m_fiberTrajectoryWidget->updateEditor(trajFile); } CiftiConnectivityMatrixParcelFile* parcelsFile = dynamic_cast(m_caretMappableDataFile); if (parcelsFile != NULL) { /* * Update parcels */ isParcelsValid = true; m_parcelsWidget->updateEditor(parcelsFile); } /* * Is volume mappable */ if (m_caretMappableDataFile->isVolumeMappable()) { if (isFiberTrajectoryValid) { /* nothing */ } else { isVolumeLayer = true; } } } } else if (m_chartOverlay != NULL) { mapFileName = m_caretMappableDataFile->getFileNameNoPath(); bool hasMapsFlag = false; bool hasHistoryFlag = false; switch (m_chartOverlay->getChartTwoDataType()) { case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: hasMapsFlag = true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: hasHistoryFlag = true; break; case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: hasMapsFlag = true; break; } int32_t selectedMapIndex = -1; bool mapTypeFlag = false; if (hasMapsFlag) { switch (m_chartOverlaySelectedIndexType) { case ChartTwoOverlay::SelectedIndexType::INVALID: CaretAssert(0); break; case ChartTwoOverlay::SelectedIndexType::MAP: if ((m_selectedMapFileIndex >= 0) && (m_selectedMapFileIndex < m_caretMappableDataFile->getNumberOfMaps())) { selectedMapIndex = m_selectedMapFileIndex; mapTypeFlag = true; } break; case ChartTwoOverlay::SelectedIndexType::COLUMN: case ChartTwoOverlay::SelectedIndexType::ROW: if (m_selectedMapFileIndex >= 0) { if (m_caretMappableDataFile->getNumberOfMaps() == 1) { m_selectedMapFileIndex = 0; } selectedMapIndex = m_selectedMapFileIndex; } break; } if ((selectedMapIndex >= 0) && (selectedMapIndex < m_caretMappableDataFile->getNumberOfMaps())) { if (m_selectedMapFileIndex >= 0) { mapName = m_caretMappableDataFile->getMapName(selectedMapIndex); } if (mapTypeFlag) { metadata = m_caretMappableDataFile->getMapMetaData(selectedMapIndex); if (metadata != NULL) { /* * TODO: Update metadata widget */ //isMetadataValid = true; } } if (m_caretMappableDataFile->isMappedWithPalette()) { PaletteColorMapping* paletteColorMapping = m_caretMappableDataFile->getMapPaletteColorMapping(selectedMapIndex); if (paletteColorMapping != NULL) { /* * Update palette settings */ isPaletteValid = true; m_paletteColorMappingWidget->updateEditor(m_caretMappableDataFile, selectedMapIndex); AnnotationColorBar* colorBar = NULL; if (m_brainordinateOverlay != NULL) { colorBar = m_brainordinateOverlay->getColorBar(); } else if (m_chartOverlay != NULL) { colorBar = m_chartOverlay->getColorBar(); } m_colorBarWidget->updateContent(m_caretMappableDataFile, selectedMapIndex, colorBar, paletteColorMapping); } } CiftiConnectivityMatrixParcelFile* parcelsFile = dynamic_cast(m_caretMappableDataFile); if (parcelsFile != NULL) { /* * Update parcels */ isParcelsValid = true; m_parcelsWidget->updateEditor(parcelsFile); } } } else if (hasHistoryFlag) { isLinesValid = true; m_lineHistoryWidget->updateContent(m_chartOverlay); if (mapName.isEmpty()) { mapName = "Line Chart History"; } } } else { CaretAssert(0); } } /* * Set enabled status of tabs */ m_tabWidget->setTabEnabled(m_colorBarWidgetTabIndex, isPaletteValid); m_tabWidget->setTabEnabled(m_labelsWidgetTabIndex, isLabelsValid); m_tabWidget->setTabEnabled(m_layersWidgetTabIndex, isVolumeLayer); m_tabWidget->setTabEnabled(m_metadataWidgetTabIndex, isMetadataValid); m_tabWidget->setTabEnabled(m_paletteWidgetTabIndex, isPaletteValid); m_tabWidget->setTabEnabled(m_parcelsWidgetTabIndex, isParcelsValid); m_tabWidget->setTabEnabled(m_trajectoryWidgetTabIndex, isFiberTrajectoryValid); m_tabWidget->setTabEnabled(m_lineHistoryWidgetTabIndex, isLinesValid); /* * When the selected tab is invalid, we want to select the * "best" tab that is enabled. The order in this vector * is the priority of the tabs. */ std::vector priorityTabIndices; priorityTabIndices.push_back(m_paletteWidgetTabIndex); priorityTabIndices.push_back(m_lineHistoryWidgetTabIndex); priorityTabIndices.push_back(m_colorBarWidgetTabIndex); priorityTabIndices.push_back(m_labelsWidgetTabIndex); priorityTabIndices.push_back(m_parcelsWidgetTabIndex); priorityTabIndices.push_back(m_trajectoryWidgetTabIndex); priorityTabIndices.push_back(m_layersWidgetTabIndex); priorityTabIndices.push_back(m_metadataWidgetTabIndex); CaretAssertMessage((static_cast(priorityTabIndices.size()) == m_tabWidget->count()), "Number of elements in priorityTabIndices is different " "than number of tab indices. Was a new tab added?"); /* * Make sure an enabled tab is selected using the tabs * in the priority order */ if (selectedTabIndex >= 0) { if (m_tabWidget->isTabEnabled(selectedTabIndex) == false) { const int32_t numPriorityTabs = static_cast(priorityTabIndices.size()); for (int32_t i = 0; i < numPriorityTabs; i++) { const int32_t tabIndex = priorityTabIndices[i]; if (m_tabWidget->isTabEnabled(tabIndex)) { m_tabWidget->setCurrentIndex(tabIndex); break; } } } } m_selectedMapFileNameLabel->setText(mapFileName); m_selectedMapNameLabel->setText(mapName); } /** * May be called to update the dialog. */ void OverlaySettingsEditorDialog::updateDialog() { /* * Validate overlay to prevent crash */ if (m_brainordinateOverlay != NULL) { EventOverlayValidate validateOverlayEvent(m_brainordinateOverlay); EventManager::get()->sendEvent(validateOverlayEvent.getPointer()); if ( ! validateOverlayEvent.isValidOverlay()) { m_brainordinateOverlay = NULL; } } if (m_chartOverlay != NULL) { EventChartOverlayValidate validateChartOverlayEvent(m_chartOverlay); EventManager::get()->sendEvent(validateChartOverlayEvent.getPointer()); if ( ! validateChartOverlayEvent.isValidChartOverlay()) { m_chartOverlay = NULL; } } updateDialogContentPrivate(m_brainordinateOverlay, m_chartOverlay); if ((m_brainordinateOverlay == NULL) && (m_chartOverlay == NULL)) { close(); } } /** * Update chart lines in the dialog */ void OverlaySettingsEditorDialog::updateChartLinesInDialog() { if (m_chartOverlay != NULL) { EventChartOverlayValidate validateChartOverlayEvent(m_chartOverlay); EventManager::get()->sendEvent(validateChartOverlayEvent.getPointer()); if ( ! validateChartOverlayEvent.isValidChartOverlay()) { m_chartOverlay = NULL; } if (m_chartOverlay != NULL) { updateDialogContentPrivate(NULL, m_chartOverlay); } } } /** * Called when close button pressed. */ void OverlaySettingsEditorDialog::closeButtonPressed() { /* * Clear the content since it could be tied to an overlay * and we don't want the dialog updating if it is not * visible. */ updateDialogContent(NULL, NULL); /* * Allow this dialog to be reused (checked means DO NOT reuse) */ m_doNotReplaceCheckBox->setCheckState(Qt::Unchecked); WuQDialogNonModal::closeButtonClicked(); } /** * Set the layout margins. * @param layout * Layout for which margins are set. */ void OverlaySettingsEditorDialog::setLayoutSpacingAndMargins(QLayout* layout) { WuQtUtilities::setLayoutSpacingAndMargins(layout, 5, 3); } /** * @return Is the Do Not Replace selected. If so, this instance of the * dialog should not be replaced. */ bool OverlaySettingsEditorDialog::isDoNotReplaceSelected() const { const bool checked = (m_doNotReplaceCheckBox->checkState() == Qt::Checked); return checked; } /** * Called when the state of the do not reply checkbox is changed. * @param state * New state of checkbox. */ void OverlaySettingsEditorDialog::doNotReplaceCheckBoxStateChanged(int /*state*/) { // const bool checked = (state == Qt::Checked); } /** * @return A widget containing the window options. */ QWidget* OverlaySettingsEditorDialog::createWindowOptionsSection() { m_doNotReplaceCheckBox = new QCheckBox("Do Not Replace"); m_doNotReplaceCheckBox->setToolTip("If checked: \n" " (1) this window remains displayed until it is\n" " closed.\n" " (2) if the user selects editing of another map's\n" " palette, it will not replace the content of\n" " this window.\n" "If NOT checked:\n" " If the user selects editing of another map's \n" " palette, it will replace the content of this\n" " window."); QWidget* optionsWidget = new QWidget(); QVBoxLayout* optionsLayout = new QVBoxLayout(optionsWidget); this->setLayoutSpacingAndMargins(optionsLayout); optionsLayout->addWidget(m_doNotReplaceCheckBox); optionsWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); return optionsWidget; } /** * Called when the edit label table button is clicked. */ void OverlaySettingsEditorDialog::editLabelTablePushButtonClicked() { if (m_caretMappableDataFile != NULL) { if (m_caretMappableDataFile->isMappedWithLabelTable()) { if (m_selectedMapFileIndex >= 0) { GiftiLabelTableEditor labelTableEditor(m_caretMappableDataFile, m_selectedMapFileIndex, "Edit Labels", GiftiLabelTableEditor::OPTION_ADD_APPLY_BUTTON, m_editLabelTablePushButton); labelTableEditor.exec(); } } } } /** * Create and return widget for editing label tables. */ QWidget* OverlaySettingsEditorDialog::createLabelsSection() { m_editLabelTablePushButton = new QPushButton("Edit"); QObject::connect(m_editLabelTablePushButton, SIGNAL(clicked()), this, SLOT(editLabelTablePushButtonClicked())); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(m_editLabelTablePushButton, 0, Qt::AlignLeft); layout->addStretch(); return widget; } connectome-workbench-1.4.2/src/GuiQt/OverlaySettingsEditorDialog.h000066400000000000000000000113021360521144700252520ustar00rootroot00000000000000#ifndef __OVERLAY_SETTINGS_EDITOR_DIALOG__H_ #define __OVERLAY_SETTINGS_EDITOR_DIALOG__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ChartTwoOverlay.h" #include "EventListenerInterface.h" #include "WuQDialogNonModal.h" class QCheckBox; class QLabel; class QLayout; class QPushButton; class QTabWidget; namespace caret { class CaretMappableDataFile; class ChartTwoOverlay; class LabelTableEditorWidget; class MapSettingsChartTwoLineHistoryWidget; class MapSettingsColorBarWidget; class MapSettingsFiberTrajectoryWidget; class MapSettingsLabelsWidget; class MapSettingsLayerWidget; class MapSettingsPaletteColorMappingWidget; class MapSettingsParcelsWidget; class Overlay; class OverlaySettingsEditorDialog : public WuQDialogNonModal, public EventListenerInterface { Q_OBJECT public: OverlaySettingsEditorDialog(QWidget* parent); void updateDialogContent(Overlay* brainordinateOverlay, ChartTwoOverlay* chartOverlay); void updateIfThisOverlayIsInDialog(Overlay* brainordinateOverlay, ChartTwoOverlay* chartOverlay); void updateDialog(); void updateChartLinesInDialog(); virtual ~OverlaySettingsEditorDialog(); bool isDoNotReplaceSelected() const; virtual void receiveEvent(Event* event); protected: virtual void closeButtonPressed(); virtual void focusInEvent(QFocusEvent* event); private: OverlaySettingsEditorDialog(const OverlaySettingsEditorDialog&); OverlaySettingsEditorDialog& operator=(const OverlaySettingsEditorDialog&); private slots: void doNotReplaceCheckBoxStateChanged(int state); void editLabelTablePushButtonClicked(); private: void updateDialogContentPrivate(Overlay* brainordinateOverlay, ChartTwoOverlay* chartOverlay); QWidget* createWindowOptionsSection(); QWidget* createMapFileAndNameSection(); QWidget* createLabelsSection(); void setLayoutSpacingAndMargins(QLayout* layout); QTabWidget* m_tabWidget; QCheckBox* m_doNotReplaceCheckBox; CaretMappableDataFile* m_caretMappableDataFile; Overlay* m_brainordinateOverlay; ChartTwoOverlay* m_chartOverlay; ChartTwoOverlay::SelectedIndexType m_chartOverlaySelectedIndexType; int32_t m_selectedMapFileIndex; MapSettingsPaletteColorMappingWidget* m_paletteColorMappingWidget; MapSettingsParcelsWidget* m_parcelsWidget; MapSettingsColorBarWidget* m_colorBarWidget; LabelTableEditorWidget* m_labelTableEditorWidget; MapSettingsFiberTrajectoryWidget* m_fiberTrajectoryWidget; MapSettingsLayerWidget* m_layerWidget; MapSettingsLabelsWidget* m_labelsWidget; MapSettingsChartTwoLineHistoryWidget* m_lineHistoryWidget; QPushButton* m_editLabelTablePushButton; QLabel* m_selectedMapFileNameLabel; QLabel* m_selectedMapNameLabel; int32_t m_colorBarWidgetTabIndex; int32_t m_labelsWidgetTabIndex; int32_t m_layersWidgetTabIndex; int32_t m_metadataWidgetTabIndex; int32_t m_paletteWidgetTabIndex; int32_t m_parcelsWidgetTabIndex; int32_t m_trajectoryWidgetTabIndex; int32_t m_lineHistoryWidgetTabIndex; }; #ifdef __OVERLAY_SETTINGS_EDITOR_DIALOG_DECLARE__ #endif // __OVERLAY_SETTINGS_EDITOR_DIALOG_DECLARE__ } // namespace #endif //__OVERLAY_SETTINGS_EDITOR_DIALOG__H_ connectome-workbench-1.4.2/src/GuiQt/OverlayViewController.cxx000066400000000000000000001303011360521144700245150ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #define __OVERLAY_VIEW_CONTROLLER_DECLARE__ #include "OverlayViewController.h" #undef __OVERLAY_VIEW_CONTROLLER_DECLARE__ #include "AnnotationColorBar.h" #include "CaretMappableDataFile.h" #include "EventDataFileReload.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventManager.h" #include "EventMapYokingSelectMap.h" #include "EventOverlaySettingsEditorDialogRequest.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUserInterfaceUpdate.h" #include "FileInformation.h" #include "FilePathNamePrefixCompactor.h" #include "GuiManager.h" #include "MapYokingGroupComboBox.h" #include "Overlay.h" #include "UsernamePasswordWidget.h" #include "WuQFactory.h" #include "WuQMacroManager.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" #include "WuQGridLayoutGroup.h" #include "WuQWidgetObjectGroup.h" using namespace caret; /** * \class caret::OverlayViewController * \brief View Controller for an overlay. * \ingroup GuiQt */ /** * Constructor. * * @param orientation * Orientation of overlay (horizontal/vertical) * @param gridLayout * Layout for widegets * @param browserWindowIndex * Index of browser window in which this view controller resides. * @param overlayIndex * Index of the overlay * @param parentObjectName * Name of parent object for macros * @param parent * The parent widget. */ OverlayViewController::OverlayViewController(const Qt::Orientation orientation, QGridLayout* gridLayout, const int32_t browserWindowIndex, const int32_t overlayIndex, const QString& parentObjectName, QObject* parent) : QObject(parent), browserWindowIndex(browserWindowIndex), m_overlayIndex(overlayIndex) { this->overlay = NULL; m_constructionReloadFileAction = NULL; int minComboBoxWidth = 200; int maxComboBoxWidth = 100000; //400; if (orientation == Qt::Horizontal) { minComboBoxWidth = 50; maxComboBoxWidth = 100000; } const QComboBox::SizeAdjustPolicy comboSizePolicy = QComboBox::AdjustToContentsOnFirstShow; //QComboBox::AdjustToContents; WuQMacroManager* macroManager = WuQMacroManager::instance(); CaretAssert(macroManager); QString objectNamePrefix = QString(parentObjectName + ":Overlay%1" + ":").arg((int)(overlayIndex + 1), 2, 10, QLatin1Char('0')); const QString descriptivePrefix = QString("overlay %1").arg(overlayIndex + 1); /* * Enabled Check Box */ const QString checkboxText = ((orientation == Qt::Horizontal) ? " " : " "); this->enabledCheckBox = new QCheckBox(checkboxText); this->enabledCheckBox->setObjectName(objectNamePrefix + "OnOff"); QObject::connect(this->enabledCheckBox, SIGNAL(clicked(bool)), this, SLOT(enabledCheckBoxClicked(bool))); this->enabledCheckBox->setToolTip("Enables display of this overlay"); macroManager->addMacroSupportToObject(this->enabledCheckBox, "Enable " + descriptivePrefix); /* * File Selection Combo Box */ this->fileComboBox = WuQFactory::newComboBox(); this->fileComboBox->setObjectName(objectNamePrefix + "FileSelection"); this->fileComboBox->setMinimumWidth(minComboBoxWidth); this->fileComboBox->setMaximumWidth(maxComboBoxWidth); QObject::connect(this->fileComboBox, SIGNAL(activated(int)), this, SLOT(fileComboBoxSelected(int))); this->fileComboBox->setToolTip("Selects file for this overlay"); this->fileComboBox->setSizeAdjustPolicy(comboSizePolicy); macroManager->addMacroSupportToObject(this->fileComboBox, ("Select file in " + descriptivePrefix)); /* * Map Index Spin Box */ m_mapIndexSpinBox = WuQFactory::newSpinBox(); this->m_mapIndexSpinBox->setObjectName(objectNamePrefix + "MapIndex"); QObject::connect(m_mapIndexSpinBox, SIGNAL(valueChanged(int)), this, SLOT(mapIndexSpinBoxValueChanged(int))); m_mapIndexSpinBox->setToolTip("Select map by its index"); macroManager->addMacroSupportToObject(m_mapIndexSpinBox, ("Select " + descriptivePrefix + " map index")); /* * Map Name Combo Box */ this->mapNameComboBox = WuQFactory::newComboBox(); this->mapNameComboBox->setObjectName(objectNamePrefix + "MapSelection"); this->mapNameComboBox->setMinimumWidth(minComboBoxWidth); this->mapNameComboBox->setMaximumWidth(maxComboBoxWidth); QObject::connect(this->mapNameComboBox, SIGNAL(activated(int)), this, SLOT(mapNameComboBoxSelected(int))); this->mapNameComboBox->setToolTip("Select map by its name"); this->mapNameComboBox->setSizeAdjustPolicy(comboSizePolicy); macroManager->addMacroSupportToObject(this->mapNameComboBox, ("Select " + descriptivePrefix + " map name")); /* * Opacity double spin box */ this->opacityDoubleSpinBox = WuQFactory::newDoubleSpinBox(); this->opacityDoubleSpinBox->setObjectName(objectNamePrefix + "Opacity"); this->opacityDoubleSpinBox->setMinimum(0.0); this->opacityDoubleSpinBox->setMaximum(1.0); this->opacityDoubleSpinBox->setSingleStep(0.10); this->opacityDoubleSpinBox->setDecimals(1); this->opacityDoubleSpinBox->setFixedWidth(50); QObject::connect(this->opacityDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(opacityDoubleSpinBoxValueChanged(double))); this->opacityDoubleSpinBox->setToolTip("Opacity (0.0=transparent, 1.0=opaque)"); macroManager->addMacroSupportToObject(this->opacityDoubleSpinBox, ("Set " + descriptivePrefix + " opacity")); /* * ColorBar Tool Button */ m_colorBarToolButton = WuQtUtilities::createToolButtonWithIcon("CB", ":/LayersPanel/colorbar.png", "Display color bar for this overlay", this, SLOT(colorBarActionTriggered(bool))); m_colorBarToolButton->setCheckable(true); m_colorBarToolButton->setObjectName(objectNamePrefix + "ShowColorBar"); macroManager->addMacroSupportToObject(m_colorBarToolButton, ("Enable " + descriptivePrefix + " colorbar")); // /* // * ColorBar Tool Button // */ // QIcon colorBarIcon; // const bool colorBarIconValid = WuQtUtilities::loadIcon(":/LayersPanel/colorbar.png", // colorBarIcon); // this->colorBarAction = WuQtUtilities::createAction("CB", // "Display color bar for this overlay", // this, // this, // SLOT(colorBarActionTriggered(bool))); // this->colorBarAction->setCheckable(true); // if (colorBarIconValid) { // this->colorBarAction->setIcon(colorBarIcon); // } // QToolButton* colorBarToolButton = new QToolButton(); // colorBarToolButton->setDefaultAction(this->colorBarAction); /* * Settings Tool Button */ QIcon settingsIcon; const bool settingsIconValid = WuQtUtilities::loadIcon(":/LayersPanel/wrench.png", settingsIcon); this->settingsAction = WuQtUtilities::createAction("S", "Edit settings for this map and overlay", this, this, SLOT(settingsActionTriggered())); this->settingsAction->setObjectName(objectNamePrefix + "ShowSettingsDialog"); if (settingsIconValid) { this->settingsAction->setIcon(settingsIcon); } QToolButton* settingsToolButton = new QToolButton(); settingsToolButton->setDefaultAction(this->settingsAction); macroManager->addMacroSupportToObject(this->settingsAction, ("Display " + descriptivePrefix + " palette settings")); /* * Construction Tool Button * Note: macro support is on each action in menu in 'createConstructionMenu' */ QIcon constructionIcon; const bool constructionIconValid = WuQtUtilities::loadIcon(":/LayersPanel/construction.png", constructionIcon); this->constructionAction = WuQtUtilities::createAction("M", "Add/Move/Remove Overlays", this); if (constructionIconValid) { this->constructionAction->setIcon(constructionIcon); } m_constructionToolButton = new QToolButton(); QMenu* constructionMenu = createConstructionMenu(m_constructionToolButton, descriptivePrefix, (objectNamePrefix + "ConstructionMenu:")); this->constructionAction->setMenu(constructionMenu); m_constructionToolButton->setDefaultAction(this->constructionAction); m_constructionToolButton->setPopupMode(QToolButton::InstantPopup); const AString yokeToolTip = ("Select a yoking group.\n" "\n" "When files with more than one map are yoked,\n" "the seleted maps are synchronized by map index.\n" "\n" "If the SAME FILE is in yoked in multiple overlays,\n" "the overlay enabled statuses are synchronized.\n"); /* * Yoking Group * Note: macro support is in the class MapYokingGroupComboBox */ m_mapYokingGroupComboBox = new MapYokingGroupComboBox(this, (objectNamePrefix + "MapYokingSelection"), descriptivePrefix); m_mapYokingGroupComboBox->getWidget()->setStatusTip("Synchronize enabled status and map indices)"); m_mapYokingGroupComboBox->getWidget()->setToolTip("Yoke to Overlay Mapped Files"); QObject::connect(m_mapYokingGroupComboBox, SIGNAL(itemActivated()), this, SLOT(yokingGroupActivated())); /* * Use layout group so that items can be shown/hidden */ this->gridLayoutGroup = new WuQGridLayoutGroup(gridLayout, this); if (orientation == Qt::Horizontal) { int row = this->gridLayoutGroup->rowCount(); this->gridLayoutGroup->addWidget(this->enabledCheckBox, row, 0, Qt::AlignHCenter); this->gridLayoutGroup->addWidget(settingsToolButton, row, 1, Qt::AlignHCenter); this->gridLayoutGroup->addWidget(m_colorBarToolButton, //colorBarToolButton, row, 2); this->gridLayoutGroup->addWidget(m_constructionToolButton, row, 3); this->gridLayoutGroup->addWidget(this->opacityDoubleSpinBox, row, 4); this->gridLayoutGroup->addWidget(this->fileComboBox, row, 5); this->gridLayoutGroup->addWidget(this->m_mapYokingGroupComboBox->getWidget(), row, 6, Qt::AlignHCenter); this->gridLayoutGroup->addWidget(m_mapIndexSpinBox, row, 7); this->gridLayoutGroup->addWidget(this->mapNameComboBox, row, 8); } else { QFrame* bottomHorizontalLineWidget = new QFrame(); bottomHorizontalLineWidget->setLineWidth(0); bottomHorizontalLineWidget->setMidLineWidth(1); bottomHorizontalLineWidget->setFrameStyle(QFrame::HLine | QFrame::Raised); QLabel* fileLabel = new QLabel("File"); QLabel* mapLabel = new QLabel("Map"); int row = this->gridLayoutGroup->rowCount(); this->gridLayoutGroup->addWidget(this->enabledCheckBox, row, 0); this->gridLayoutGroup->addWidget(settingsToolButton, row, 1); this->gridLayoutGroup->addWidget(m_colorBarToolButton, //colorBarToolButton, row, 2); this->gridLayoutGroup->addWidget(m_constructionToolButton, row, 3); this->gridLayoutGroup->addWidget(fileLabel, row, 4); this->gridLayoutGroup->addWidget(this->fileComboBox, row, 5, 1, 2); row++; this->gridLayoutGroup->addWidget(this->opacityDoubleSpinBox, row, 0, 1, 2, Qt::AlignCenter); this->gridLayoutGroup->addWidget(this->m_mapYokingGroupComboBox->getWidget(), row, 2, 1, 2); this->gridLayoutGroup->addWidget(mapLabel, row, 4); this->gridLayoutGroup->addWidget(m_mapIndexSpinBox, row, 5); this->gridLayoutGroup->addWidget(this->mapNameComboBox, row, 6); row++; this->gridLayoutGroup->addWidget(bottomHorizontalLineWidget, row, 0, 1, -1); } } /** * Destructor. */ OverlayViewController::~OverlayViewController() { } /** * Set the visiblity of this overlay view controller. */ void OverlayViewController::setVisible(bool visible) { this->gridLayoutGroup->setVisible(visible); } /* * If this overlay ins an overlay settings editor, update its content */ void OverlayViewController::updateOverlaySettingsEditor() { if (overlay == NULL) { return; } CaretMappableDataFile* mapFile = NULL; int32_t mapIndex = -1; overlay->getSelectionData(mapFile, mapIndex); if ((mapFile != NULL) && (mapIndex >= 0)) { EventOverlaySettingsEditorDialogRequest pcme(EventOverlaySettingsEditorDialogRequest::MODE_OVERLAY_MAP_CHANGED, this->browserWindowIndex, this->overlay, mapFile, mapIndex); EventManager::get()->sendEvent(pcme.getPointer()); } } /** * Called when a selection is made from the file combo box. * @parm indx * Index of selection. */ void OverlayViewController::fileComboBoxSelected(int indx) { if (overlay == NULL) { return; } void* pointer = this->fileComboBox->itemData(indx).value(); CaretMappableDataFile* file = (CaretMappableDataFile*)pointer; overlay->setSelectionData(file, 0); validateYokingSelection(); //validateYokingSelection(overlay->getYokingGroup()); // not needed with call to validateYokingSelection: this->updateViewController(this->overlay); // called inside validateYokingSelection(); this->updateUserInterfaceAndGraphicsWindow(); updateOverlaySettingsEditor(); updateViewController(this->overlay); if (file != NULL) { if (file->isVolumeMappable()) { /* * Need to update slice indices/coords in toolbar. */ EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(browserWindowIndex).addToolBar().getPointer()); } } updateGraphicsWindow(); } /** * Called when a selection is made from the map index spin box. * @parm indx * Index of selection. */ void OverlayViewController::mapIndexSpinBoxValueChanged(int indx) { if (overlay == NULL) { //TSC: not sure how to put the displayed integer back to 0 where it starts when opening without data files return; } /* * Get the file that is selected from the file combo box */ const int32_t fileIndex = this->fileComboBox->currentIndex(); void* pointer = this->fileComboBox->itemData(fileIndex).value(); CaretMappableDataFile* file = (CaretMappableDataFile*)pointer; /* * Overlay indices range [0, N-1] but spin box shows [1, N]. */ const int overlayIndex = indx - 1; overlay->setSelectionData(file, overlayIndex); const MapYokingGroupEnum::Enum mapYoking = overlay->getMapYokingGroup(); if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { EventMapYokingSelectMap selectMapEvent(mapYoking, file, NULL, overlayIndex, overlay->isEnabled()); EventManager::get()->sendEvent(selectMapEvent.getPointer()); } /* * Need to update map name combo box. */ mapNameComboBox->blockSignals(true); if ((overlayIndex >= 0) && (overlayIndex < mapNameComboBox->count())) { mapNameComboBox->setCurrentIndex(overlayIndex); } mapNameComboBox->blockSignals(false); this->updateUserInterface(); this->updateGraphicsWindow(); updateOverlaySettingsEditor(); } /** * Called when a selection is made from the map name combo box. * @parm indx * Index of selection. */ void OverlayViewController::mapNameComboBoxSelected(int indx) { if (overlay == NULL) { return; } /* * Get the file that is selected from the file combo box */ const int32_t fileIndex = this->fileComboBox->currentIndex(); void* pointer = this->fileComboBox->itemData(fileIndex).value(); CaretMappableDataFile* file = (CaretMappableDataFile*)pointer; overlay->setSelectionData(file, indx); const MapYokingGroupEnum::Enum mapYoking = overlay->getMapYokingGroup(); if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { EventMapYokingSelectMap selectMapEvent(mapYoking, file, NULL, indx, overlay->isEnabled()); EventManager::get()->sendEvent(selectMapEvent.getPointer()); } /* * Need to update map index spin box. * Note that the map index spin box ranges [1, N]. */ m_mapIndexSpinBox->blockSignals(true); m_mapIndexSpinBox->setValue(indx + 1); m_mapIndexSpinBox->blockSignals(false); this->updateUserInterface(); this->updateGraphicsWindow(); updateOverlaySettingsEditor(); } /** * Called when enabled checkbox state is changed * @parm checked * Checked status */ void OverlayViewController::enabledCheckBoxClicked(bool checked) { if (overlay == NULL) { return; } overlay->setEnabled(checked); const MapYokingGroupEnum::Enum mapYoking = overlay->getMapYokingGroup(); if (mapYoking != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { CaretMappableDataFile* myFile = NULL; int32_t myIndex = -1; this->overlay->getSelectionData(myFile, myIndex); EventMapYokingSelectMap selectMapEvent(mapYoking, myFile, NULL, myIndex, overlay->isEnabled()); EventManager::get()->sendEvent(selectMapEvent.getPointer()); } this->updateUserInterface(); this->updateGraphicsWindow(); } /** * Called when colorbar toolbutton is toggled. * @param status * New status. */ void OverlayViewController::colorBarActionTriggered(bool status) { if (overlay == NULL) { return; } this->overlay->getColorBar()->setDisplayed(status); this->updateGraphicsWindow(); } /** * Called when opacity value is changed. * @param value * New value. */ void OverlayViewController::opacityDoubleSpinBoxValueChanged(double value) { if (overlay == NULL) { return; } this->overlay->setOpacity(value); this->updateGraphicsWindow(); } /** * Validate yoking when there are changes made to the overlay. */ void OverlayViewController::validateYokingSelection() { m_mapYokingGroupComboBox->validateYokingChange(this->overlay); updateViewController(this->overlay); updateGraphicsWindow(); //EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called when the yoking group is changed. */ void OverlayViewController::yokingGroupActivated() { MapYokingGroupEnum::Enum yokingGroup = m_mapYokingGroupComboBox->getMapYokingGroup(); /* * Has yoking group changed? * TSC: overlay can be null when opened without loaded files */ if (overlay != NULL && yokingGroup != overlay->getMapYokingGroup()) { validateYokingSelection(); } } /** * Called when the settings action is selected. */ void OverlayViewController::settingsActionTriggered() { if (overlay == NULL) { return; } CaretMappableDataFile* mapFile; int32_t mapIndex = -1; this->overlay->getSelectionData(mapFile, mapIndex); if (mapFile != NULL) { EventOverlaySettingsEditorDialogRequest pcme(EventOverlaySettingsEditorDialogRequest::MODE_SHOW_EDITOR, this->browserWindowIndex, this->overlay, mapFile, mapIndex); EventManager::get()->sendEvent(pcme.getPointer()); } } /** * Update this view controller using the given overlay. * @param overlay * Overlay that is used in this view controller. */ void OverlayViewController::updateViewController(Overlay* overlay) { this->overlay = overlay; this->fileComboBox->clear(); /* * Get the selection information for the overlay. */ std::vector dataFiles; CaretMappableDataFile* selectedFile = NULL; //AString selectedMapUniqueID = ""; int32_t selectedMapIndex = -1; if (this->overlay != NULL) { this->overlay->getSelectionData(dataFiles, selectedFile, //selectedMapUniqueID, selectedMapIndex); } std::vector displayNames; FilePathNamePrefixCompactor::removeMatchingPathPrefixFromCaretDataFiles(dataFiles, displayNames); CaretAssert(dataFiles.size() == displayNames.size()); /* * Load the file selection combo box. */ int32_t selectedFileIndex = -1; const int32_t numFiles = static_cast(dataFiles.size()); for (int32_t i = 0; i < numFiles; i++) { CaretMappableDataFile* dataFile = dataFiles[i]; AString dataTypeName = DataFileTypeEnum::toOverlayTypeName(dataFile->getDataFileType()); CaretAssertVectorIndex(displayNames, i); this->fileComboBox->addItem(displayNames[i], qVariantFromValue((void*)dataFile)); if (dataFile == selectedFile) { selectedFileIndex = i; } } if (selectedFileIndex >= 0) { this->fileComboBox->setCurrentIndex(selectedFileIndex); } /* * Load the map selection combo box */ int32_t numberOfMaps = 0; this->mapNameComboBox->blockSignals(true); this->mapNameComboBox->clear(); if (selectedFile != NULL) { numberOfMaps = selectedFile->getNumberOfMaps(); for (int32_t i = 0; i < numberOfMaps; i++) { this->mapNameComboBox->addItem(selectedFile->getMapName(i)); } this->mapNameComboBox->setCurrentIndex(selectedMapIndex); } this->mapNameComboBox->blockSignals(false); /* * Load the map index spin box that ranges [1, N]. */ m_mapIndexSpinBox->blockSignals(true); m_mapIndexSpinBox->setRange(1, numberOfMaps); if (selectedFile != NULL) { m_mapIndexSpinBox->setValue(selectedMapIndex + 1); } m_mapIndexSpinBox->blockSignals(false); /* * Update enable check box */ Qt::CheckState checkState = Qt::Unchecked; if (this->overlay != NULL) { if (this->overlay->isEnabled()) { checkState = Qt::Checked; } } this->enabledCheckBox->setCheckState(checkState); m_mapYokingGroupComboBox->setMapYokingGroup(overlay->getMapYokingGroup()); m_colorBarToolButton->setChecked(overlay->getColorBar()->isDisplayed()); // this->colorBarAction->blockSignals(true); // this->colorBarAction->setChecked(overlay->getColorBar()->isDisplayed()); // this->colorBarAction->blockSignals(false); this->opacityDoubleSpinBox->blockSignals(true); this->opacityDoubleSpinBox->setValue(overlay->getOpacity()); this->opacityDoubleSpinBox->blockSignals(false); const bool haveFile = (selectedFile != NULL); bool haveMultipleMaps = false; bool dataIsMappedWithPalette = false; bool dataIsMappedWithLabelTable = false; bool dataIsMappedWithRGBA = false; bool haveOpacity = false; if (haveFile) { dataIsMappedWithPalette = selectedFile->isMappedWithPalette(); dataIsMappedWithLabelTable = selectedFile->isMappedWithLabelTable(); dataIsMappedWithRGBA = selectedFile->isMappedWithRGBA(); haveMultipleMaps = (selectedFile->getNumberOfMaps() > 1); haveOpacity = (dataIsMappedWithLabelTable || dataIsMappedWithPalette || dataIsMappedWithRGBA); } /** * Yoking is enabled when either: * (1) The file maps to both surface and volumes * (2) The file has multiple maps. */ bool haveYoking = false; if (haveFile) { if (selectedFile->isSurfaceMappable() && selectedFile->isVolumeMappable()) { haveYoking = true; } if (haveMultipleMaps) { haveYoking = true; } } /* * Update tooltips with full path to file and name of map * as names may be too long to fit into combo boxes */ AString fileComboBoxToolTip("Select file for this overlay"); AString nameComboBoxToolTip("Select map by its name"); if (selectedFile != NULL) { FileInformation fileInfo(selectedFile->getFileName()); fileComboBoxToolTip.append(":\n" + fileInfo.getFileName() + "\n" + fileInfo.getPathName() + "\n\n" + "Copy File Name/Path to Clipboard with Construction Menu"); nameComboBoxToolTip.append(":\n" + this->mapNameComboBox->currentText()); } this->fileComboBox->setToolTip(fileComboBoxToolTip); this->mapNameComboBox->setToolTip(nameComboBoxToolTip); /* * Make sure items are enabled at the appropriate time */ this->fileComboBox->setEnabled(haveFile); this->mapNameComboBox->setEnabled(haveFile); this->m_mapIndexSpinBox->setEnabled(haveMultipleMaps); this->enabledCheckBox->setEnabled(haveFile); this->constructionAction->setEnabled(true); this->opacityDoubleSpinBox->setEnabled(haveOpacity); this->m_mapYokingGroupComboBox->getWidget()->setEnabled(haveYoking); //this->colorBarAction->setEnabled(dataIsMappedWithPalette); this->m_colorBarToolButton->setEnabled(dataIsMappedWithPalette); this->settingsAction->setEnabled(true); } /** * Update graphics and GUI after selections made */ void OverlayViewController::updateUserInterfaceAndGraphicsWindow() { updateUserInterface(); updateGraphicsWindow(); } /** * Update graphics and GUI after selections made */ void OverlayViewController::updateUserInterface() { if (this->overlay->getMapYokingGroup() != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } else { EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(this->browserWindowIndex).getPointer()); } } /** * Update graphics after selections made */ void OverlayViewController::updateGraphicsWindow() { EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); if (this->overlay->getMapYokingGroup() != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } else { EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(this->browserWindowIndex).getPointer()); } } /** * Create the construction menu. * @param parent * Parent widget. * @param descriptivePrefix * Descriptive prefix * @param menuActionNamePrefix * Prefix for macros */ QMenu* OverlayViewController::createConstructionMenu(QWidget* parent, const AString& descriptivePrefix, const AString& menuActionNamePrefix) { WuQMacroManager* macroManager = WuQMacroManager::instance(); CaretAssert(macroManager); QMenu* menu = new QMenu(parent); QObject::connect(menu, SIGNAL(aboutToShow()), this, SLOT(menuConstructionAboutToShow())); QAction* addAboveAction = menu->addAction("Add Overlay Above", this, SLOT(menuAddOverlayAboveTriggered())); addAboveAction->setObjectName(menuActionNamePrefix + "AddOverlayAbove"); addAboveAction->setToolTip("Add an overlay above this overlay"); macroManager->addMacroSupportToObject(addAboveAction, ("Add overlay above " + descriptivePrefix)); QAction* addBelowAction = menu->addAction("Add Overlay Below", this, SLOT(menuAddOverlayBelowTriggered())); addBelowAction->setObjectName(menuActionNamePrefix + "AddOverlayBelow"); addBelowAction->setToolTip("Add an overlay below this overlay"); macroManager->addMacroSupportToObject(addBelowAction, ("Add overlay below " + descriptivePrefix)); menu->addSeparator(); QAction* moveUpAction = menu->addAction("Move Overlay Up", this, SLOT(menuMoveOverlayUpTriggered())); moveUpAction->setObjectName(menuActionNamePrefix + "MoveOverlayUp"); moveUpAction->setToolTip("Move this overlay up"); macroManager->addMacroSupportToObject(moveUpAction, ("Move " + descriptivePrefix + " up")); QAction* moveDownAction = menu->addAction("Move Overlay Down", this, SLOT(menuMoveOverlayDownTriggered())); moveDownAction->setObjectName(menuActionNamePrefix + "MoveOverlayDown"); moveDownAction->setToolTip("Move this overlay down"); macroManager->addMacroSupportToObject(moveDownAction, ("Move " + descriptivePrefix + " down")); menu->addSeparator(); QAction* removeAction = menu->addAction("Remove This Overlay", this, SLOT(menuRemoveOverlayTriggered())); removeAction->setObjectName(menuActionNamePrefix + "RemoveOverlay"); removeAction->setToolTip("Remove this overlay"); macroManager->addMacroSupportToObject(removeAction, ("Remove " + descriptivePrefix)); menu->addSeparator(); m_constructionReloadFileAction = menu->addAction("Reload Selected File", this, SLOT(menuReloadFileTriggered())); m_constructionReloadFileAction->setObjectName(menuActionNamePrefix + "ReloadSelectedFile"); m_constructionReloadFileAction->setToolTip("Reload file in this overlay"); macroManager->addMacroSupportToObject(m_constructionReloadFileAction, ("Reload file in " + descriptivePrefix)); menu->addSeparator(); m_copyPathAndFileNameToClipboardAction = menu->addAction("Copy Path and File Name to Clipboard", this, SLOT(menuCopyFileNameToClipBoard())); m_copyPathAndFileNameToClipboardAction->setObjectName(menuActionNamePrefix + "CopyPathAndFileNameToClipboard"); m_copyPathAndFileNameToClipboardAction->setToolTip("Copy path and file name of file in this overlay to clipboard"); macroManager->addMacroSupportToObject(m_copyPathAndFileNameToClipboardAction, ("Copy path and filename from " + descriptivePrefix + " to clipboard")); QAction* copyMapNameAction = menu->addAction("Copy Map Name to Clipboard", this, SLOT(menuCopyMapNameToClipBoard())); copyMapNameAction->setObjectName(menuActionNamePrefix + "CopyMapNameToClipboard"); copyMapNameAction->setToolTip("Copy name of selected map to the clipboard"); macroManager->addMacroSupportToObject(copyMapNameAction, ("Copy map namne in " + descriptivePrefix + " to clipboard")); return menu; } /** * Called when construction menu is about to be displayed. */ void OverlayViewController::menuConstructionAboutToShow() { if (this->overlay != NULL) { CaretMappableDataFile* caretDataFile = NULL; int32_t mapIndex = -1; this->overlay->getSelectionData(caretDataFile, mapIndex); QString menuText = "Reload Selected File"; if (caretDataFile != NULL) { if (caretDataFile->isModified()) { QString suffix = " (MODIFIED)"; if (caretDataFile->isModifiedPaletteColorMapping()) { if ( ! caretDataFile->isModifiedExcludingPaletteColorMapping()) { suffix = " (MODIFIED PALETTE)"; } } menuText += suffix; } bool dynConnFlag(false); switch (caretDataFile->getDataFileType()) { case DataFileTypeEnum::ANNOTATION: break; case DataFileTypeEnum::ANNOTATION_TEXT_SUBSTITUTION: break; case DataFileTypeEnum::BORDER: break; case DataFileTypeEnum::CONNECTIVITY_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_DYNAMIC: dynConnFlag = true; break; case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_LABEL: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_PARCEL_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: break; case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_ORIENTATIONS_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_FIBER_TRAJECTORY_TEMPORARY: break; case DataFileTypeEnum::CONNECTIVITY_SCALAR_DATA_SERIES: break; case DataFileTypeEnum::FOCI: break; case DataFileTypeEnum::IMAGE: break; case DataFileTypeEnum::LABEL: break; case DataFileTypeEnum::METRIC: break; case DataFileTypeEnum::METRIC_DYNAMIC: dynConnFlag = true; break; case DataFileTypeEnum::PALETTE: break; case DataFileTypeEnum::RGBA: break; case DataFileTypeEnum::SCENE: break; case DataFileTypeEnum::SPECIFICATION: break; case DataFileTypeEnum::SURFACE: break; case DataFileTypeEnum::UNKNOWN: break; case DataFileTypeEnum::VOLUME: break; case DataFileTypeEnum::VOLUME_DYNAMIC: dynConnFlag = true; break; } m_constructionReloadFileAction->setEnabled( ! dynConnFlag); m_copyPathAndFileNameToClipboardAction->setEnabled( ! dynConnFlag); } m_constructionReloadFileAction->setText(menuText); } } /** * Add an overlay above this overlay. */ void OverlayViewController::menuAddOverlayAboveTriggered() { emit requestAddOverlayAbove(m_overlayIndex); } /** * Add an overlay below this overlay. */ void OverlayViewController::menuAddOverlayBelowTriggered() { emit requestAddOverlayBelow(m_overlayIndex); } /** * Remove this overlay. */ void OverlayViewController::menuRemoveOverlayTriggered() { emit requestRemoveOverlay(m_overlayIndex); } /** * Move this overlay down. */ void OverlayViewController::menuMoveOverlayDownTriggered() { emit requestMoveOverlayDown(m_overlayIndex); } /** * Move this overlay down. */ void OverlayViewController::menuMoveOverlayUpTriggered() { emit requestMoveOverlayUp(m_overlayIndex); } /** * Copy the file name to the clip board. */ void OverlayViewController::menuCopyFileNameToClipBoard() { if (this->overlay != NULL) { CaretMappableDataFile* caretDataFile = NULL; int32_t mapIndex = -1; this->overlay->getSelectionData(caretDataFile, mapIndex); if (caretDataFile != NULL) { QApplication::clipboard()->setText(caretDataFile->getFileName().trimmed(), QClipboard::Clipboard); } } } /** * Copy the map name to the clip board. */ void OverlayViewController::menuCopyMapNameToClipBoard() { if (this->overlay != NULL) { CaretMappableDataFile* caretDataFile = NULL; int32_t mapIndex = -1; this->overlay->getSelectionData(caretDataFile, mapIndex); if (caretDataFile != NULL) { if ((mapIndex >= 0) && (mapIndex < caretDataFile->getNumberOfMaps())) { QApplication::clipboard()->setText(caretDataFile->getMapName(mapIndex).trimmed(), QClipboard::Clipboard); } } } } /** * Reload the file in the overlay. */ void OverlayViewController::menuReloadFileTriggered() { if (this->overlay != NULL) { CaretMappableDataFile* caretDataFile = NULL; int32_t mapIndex = -1; this->overlay->getSelectionData(caretDataFile, mapIndex); if (caretDataFile != NULL) { AString username; AString password; if (DataFile::isFileOnNetwork(caretDataFile->getFileName())) { const QString msg("This file is on the network. " "If accessing the file requires a username and " "password, enter it here. Otherwise, remove any " "text from the username and password fields."); if (UsernamePasswordWidget::getUserNameAndPasswordInDialog(m_constructionToolButton, "Username and Password", msg, username, password)) { /* nothing */ } else { return; } } EventDataFileReload reloadEvent(GuiManager::get()->getBrain(), caretDataFile); reloadEvent.setUsernameAndPassword(username, password); EventManager::get()->sendEvent(reloadEvent.getPointer()); if (reloadEvent.isError()) { WuQMessageBox::errorOk(m_constructionToolButton, reloadEvent.getErrorMessage()); } updateOverlaySettingsEditor(); updateUserInterfaceAndGraphicsWindow(); } } } connectome-workbench-1.4.2/src/GuiQt/OverlayViewController.h000066400000000000000000000113711360521144700241470ustar00rootroot00000000000000#ifndef __OVERLAY_VIEW_CONTROLLER__H_ #define __OVERLAY_VIEW_CONTROLLER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include class QAction; class QCheckBox; class QComboBox; class QDoubleSpinBox; class QGridLayout; class QMenu; class QSpinBox; class QToolButton; namespace caret { class AString; class MapYokingGroupComboBox; class Overlay; class WuQGridLayoutGroup; class OverlayViewController : public QObject { Q_OBJECT public: OverlayViewController(const Qt::Orientation orientation, QGridLayout* gridLayout, const int32_t browserWindowIndex, const int32_t overlayIndex, const QString& parentObjectName, QObject* parent); virtual ~OverlayViewController(); void setVisible(bool visible); void updateViewController(Overlay* overlay); signals: void requestAddOverlayAbove(const int32_t overlayIndex); void requestAddOverlayBelow(const int32_t overlayIndex); void requestRemoveOverlay(const int32_t overlayIndex); void requestMoveOverlayUp(const int32_t overlayIndex); void requestMoveOverlayDown(const int32_t overlayIndex); private slots: void fileComboBoxSelected(int); void mapNameComboBoxSelected(int); void mapIndexSpinBoxValueChanged(int); void enabledCheckBoxClicked(bool); void colorBarActionTriggered(bool); void settingsActionTriggered(); void opacityDoubleSpinBoxValueChanged(double value); void yokingGroupActivated(); void menuAddOverlayAboveTriggered(); void menuAddOverlayBelowTriggered(); void menuRemoveOverlayTriggered(); void menuMoveOverlayDownTriggered(); void menuMoveOverlayUpTriggered(); void menuReloadFileTriggered(); void menuCopyFileNameToClipBoard(); void menuCopyMapNameToClipBoard(); void menuConstructionAboutToShow(); private: OverlayViewController(const OverlayViewController&); OverlayViewController& operator=(const OverlayViewController&); void updateUserInterfaceAndGraphicsWindow(); void updateUserInterface(); void updateGraphicsWindow(); QMenu* createConstructionMenu(QWidget* parent, const AString& descriptivePrefix, const AString& menuActionNamePrefix); void validateYokingSelection(); void updateOverlaySettingsEditor(); const int32_t browserWindowIndex; const int32_t m_overlayIndex; Overlay* overlay; QCheckBox* enabledCheckBox; QComboBox* fileComboBox; QComboBox* mapNameComboBox; QSpinBox* m_mapIndexSpinBox; QDoubleSpinBox* opacityDoubleSpinBox; QToolButton* m_constructionToolButton; QAction* constructionAction; QToolButton* m_colorBarToolButton; //QAction* colorBarAction; QAction* settingsAction; MapYokingGroupComboBox* m_mapYokingGroupComboBox; QAction* m_constructionReloadFileAction; QAction* m_copyPathAndFileNameToClipboardAction; WuQGridLayoutGroup* gridLayoutGroup; friend class OverlaySetViewController; }; #ifdef __OVERLAY_VIEW_CONTROLLER_DECLARE__ // #endif // __OVERLAY_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__OVERLAY_VIEW_CONTROLLER__H_ connectome-workbench-1.4.2/src/GuiQt/PaletteColorMappingEditorDialog.cxx000066400000000000000000000173731360521144700264120ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #define __PALETTE_COLOR_MAPPING_EDITOR_DIALOG_DECLARE__ #include "PaletteColorMappingEditorDialog.h" #undef __PALETTE_COLOR_MAPPING_EDITOR_DIALOG_DECLARE__ #include "CaretAssert.h" #include "CaretMappableDataFile.h" #include "ChartableMatrixInterface.h" #include "ChartMatrixDisplayProperties.h" #include "EventCaretMappableDataFilesGet.h" #include "EventManager.h" #include "MapSettingsColorBarWidget.h" #include "MapSettingsPaletteColorMappingWidget.h" using namespace caret; /** * \class caret::PaletteColorMappingEditorDialog * \brief Dialog for editing color palettes * \ingroup GuiQt */ /** * Constructor. */ PaletteColorMappingEditorDialog::PaletteColorMappingEditorDialog(QWidget* parent) : WuQDialogNonModal("Palette Color Mapping Editor", parent) { m_mapFile = NULL; m_mapIndex = -1; m_browserTabIndex = -1; QLabel* fileLabel = new QLabel("Map File: "); m_fileNameValueLabel = new QLabel(""); QLabel* mapLabel = new QLabel("Map Name: "); m_mapNameValueLabel = new QLabel(""); m_paletteColorBarWidget = new MapSettingsColorBarWidget(); m_paletteColorMappingEditor = new MapSettingsPaletteColorMappingWidget(this); QGridLayout* namesLayout = new QGridLayout(); namesLayout->setColumnStretch(0, 0); namesLayout->setColumnStretch(1, 100); int namesRow = 0; namesLayout->addWidget(fileLabel, namesRow, 0); namesLayout->addWidget(m_fileNameValueLabel, namesRow, 1, Qt::AlignLeft); namesRow++; namesLayout->addWidget(mapLabel, namesRow, 0); namesLayout->addWidget(m_mapNameValueLabel, namesRow, 1, Qt::AlignLeft); /* * For now, hide map name labels */ mapLabel->hide(); m_mapNameValueLabel->hide(); m_tabWidget = new QTabWidget(); m_paletteColorBarWidgetTabIndex = m_tabWidget->addTab(m_paletteColorBarWidget, "Color Bar"); m_paletteEditorWidgetTabIndex = m_tabWidget->addTab(m_paletteColorMappingEditor, "Palette"); QWidget* w = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(w); layout->addLayout(namesLayout); layout->addWidget(m_tabWidget); setCentralWidget(w, WuQDialog::SCROLL_AREA_NEVER); disableAutoDefaultForAllPushButtons(); EventManager::get()->addProcessedEventListener(this, EventTypeEnum::EVENT_DATA_FILE_DELETE); } /** * Destructor. */ PaletteColorMappingEditorDialog::~PaletteColorMappingEditorDialog() { EventManager::get()->removeAllEventsFromListener(this); } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void PaletteColorMappingEditorDialog::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_DATA_FILE_DELETE) { updateDialog(); } } /** * Called for focus events. Since this dialog stores a pointer * to the overlay, we need to be aware that the overlay's parameters * may change or the overlay may even be deleted. So, when * this dialog gains focus, validate the overlay and then update * the dialog. * * @param event * The focus event. */ void PaletteColorMappingEditorDialog::focusInEvent(QFocusEvent* event) { if (event->reason() == Qt::PopupFocusReason) { /* * This occurs when a combo box is popped up Mac, * causes a problem, and can be ignored. */ return; } updateDialog(); } /** * May be called to update the dialog's content. * * @param mapFile * Map file whose map is having its palette color mapping edited * @param mapIndex * Index of the map whose color mapping is being edited. */ void PaletteColorMappingEditorDialog::updateDialogContent(CaretMappableDataFile* mapFile, const int32_t mapIndex, const int32_t browserTabIndex) { m_mapFile = mapFile; m_mapIndex = mapIndex; m_browserTabIndex = browserTabIndex; bool enableEditor = false; if (m_mapFile != NULL) { if ((m_mapIndex >= 0) && (m_mapIndex < m_mapFile->getNumberOfMaps())) { if (browserTabIndex >= 0) { enableEditor = true; } } } if (enableEditor) { m_fileNameValueLabel->setText(m_mapFile->getFileNameNoPath()); m_mapNameValueLabel->setText(m_mapFile->getMapName(m_mapIndex)); m_paletteColorBarWidget->setEnabled(true); AnnotationColorBar* colorBar = NULL; PaletteColorMapping* paletteColorMapping = mapFile->getMapPaletteColorMapping(m_mapIndex); ChartableMatrixInterface* matrixInterface = dynamic_cast(m_mapFile); if (matrixInterface != NULL) { ChartMatrixDisplayProperties* matrixProps = matrixInterface->getChartMatrixDisplayProperties(m_browserTabIndex); if (matrixProps != NULL) { colorBar = matrixProps->getColorBar(); } } m_paletteColorBarWidget->updateContent(m_mapFile, m_mapIndex, colorBar, paletteColorMapping); m_paletteColorMappingEditor->setEnabled(true); m_paletteColorMappingEditor->updateEditor(m_mapFile, m_mapIndex); } else { m_fileNameValueLabel->setText(""); m_mapNameValueLabel->setText(""); m_paletteColorBarWidget->setEnabled(false); m_paletteColorMappingEditor->setEnabled(false); } } /** * May be called to update the dialog. */ void PaletteColorMappingEditorDialog::updateDialog() { if (m_mapFile != NULL) { /* * Validate map file to prevent crash */ EventCaretMappableDataFilesGet getMapFilesEvent; EventManager::get()->sendEvent(getMapFilesEvent.getPointer()); std::vector allMapFiles; getMapFilesEvent.getAllFiles(allMapFiles); if (std::find(allMapFiles.begin(), allMapFiles.end(), m_mapFile) != allMapFiles.end()) { if (m_mapIndex < 0) { m_mapIndex = 0; } if (m_mapFile->getNumberOfMaps() > 0) { if (m_mapIndex >= m_mapFile->getNumberOfMaps()) { m_mapIndex = m_mapFile->getNumberOfMaps() - 1; } } else { m_mapFile = NULL; m_mapIndex = -1; } } else { m_mapFile = NULL; m_mapIndex = -1; } updateDialogContent(m_mapFile, m_mapIndex, m_browserTabIndex); } if (m_mapFile == NULL) { close(); } } connectome-workbench-1.4.2/src/GuiQt/PaletteColorMappingEditorDialog.h000066400000000000000000000055751360521144700260400ustar00rootroot00000000000000#ifndef __PALETTE_COLOR_MAPPING_EDITOR_DIALOG_H__ #define __PALETTE_COLOR_MAPPING_EDITOR_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventListenerInterface.h" #include "WuQDialogNonModal.h" class QLabel; class QTabWidget; namespace caret { class CaretMappableDataFile; class MapSettingsColorBarWidget; class MapSettingsPaletteColorMappingWidget; class PaletteColorMappingEditorDialog : public WuQDialogNonModal, public EventListenerInterface { Q_OBJECT public: PaletteColorMappingEditorDialog(QWidget* parent = 0); virtual ~PaletteColorMappingEditorDialog(); virtual void receiveEvent(Event* event); /** May be called requesting the dialog to update its content */ virtual void updateDialog(); void updateDialogContent(CaretMappableDataFile* mapFile, const int32_t mapIndex, const int32_t browserTabIndex); protected: virtual void focusInEvent(QFocusEvent* event); // ADD_NEW_METHODS_HERE private: PaletteColorMappingEditorDialog(const PaletteColorMappingEditorDialog&); PaletteColorMappingEditorDialog& operator=(const PaletteColorMappingEditorDialog&); CaretMappableDataFile* m_mapFile; int32_t m_mapIndex; int32_t m_browserTabIndex; QTabWidget* m_tabWidget; MapSettingsColorBarWidget* m_paletteColorBarWidget; MapSettingsPaletteColorMappingWidget* m_paletteColorMappingEditor; QLabel* m_fileNameValueLabel; QLabel* m_mapNameValueLabel; int32_t m_paletteColorBarWidgetTabIndex; int32_t m_paletteEditorWidgetTabIndex; // ADD_NEW_MEMBERS_HERE }; #ifdef __PALETTE_COLOR_MAPPING_EDITOR_DIALOG_DECLARE__ // #endif // __PALETTE_COLOR_MAPPING_EDITOR_DIALOG_DECLARE__ } // namespace #endif //__PALETTE_COLOR_MAPPING_EDITOR_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/PlotMagnifier.cxx000066400000000000000000000111741360521144700227430ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /** * \class caret::PlotMagnifier * \brief Helper class for magnifying Qwt plots * \ingroup GuiQt */ #include "PlotMagnifier.h" using namespace caret; PlotMagnifier::PlotMagnifier(QwtPlotCanvas * canvas) : QwtPlotMagnifier(canvas) { this->setEnabled(true); //The three function calls below reverse the default behavior of zooming so that it is consistent with //brainview's zooming this->setMouseFactor(1.05);//inverse of default value, 0.95 this->setWheelFactor(1.11);//inverse of default value, 0.9 this->setMouseButton(Qt::LeftButton); } bool PlotMagnifier::eventFilter(QObject * object,QEvent *event) { if ( object && (object == parent() || object == parent()->parent()) ) { switch ( event->type() ) { case QEvent::MouseButtonPress: { widgetMousePressEvent( ( QMouseEvent * )event ); break; } case QEvent::MouseMove: { widgetMouseMoveEvent( ( QMouseEvent * )event ); break; } case QEvent::MouseButtonRelease: { widgetMouseReleaseEvent( ( QMouseEvent * )event ); break; } case QEvent::Wheel: { widgetWheelEvent( ( QWheelEvent * )event ); break; } case QEvent::KeyPress: { widgetKeyPressEvent( ( QKeyEvent * )event ); break; } case QEvent::KeyRelease: { widgetKeyReleaseEvent( ( QKeyEvent * )event ); break; } default:; } } return QObject::eventFilter( object, event ); } /*! Handle a mouse press event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMouseReleaseEvent(), widgetMouseMoveEvent() */ void PlotMagnifier::widgetMousePressEvent( QMouseEvent *mouseEvent ) { if(mouseEvent->modifiers() != Qt::ControlModifier || mouseEvent->modifiers() == Qt::ShiftModifier) { return; } mouseEvent->setModifiers(Qt::NoModifier); // remove modifier so base class accepts event, we ignore events when shift key is pressed so panning works QwtPlotMagnifier::widgetMousePressEvent( mouseEvent); } /*! Handle a mouse release event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseMoveEvent(), */ void PlotMagnifier::widgetMouseReleaseEvent( QMouseEvent *mouseEvent ) { /*if(mouseEvent->modifiers() != Qt::ControlModifier || mouseEvent->modifiers() == Qt::ShiftModifier) { return; }*/ mouseEvent->setModifiers(Qt::NoModifier); // remove modifier so base class accepts event, we ignore events when shift key is pressed so panning works QwtPlotMagnifier::widgetMouseReleaseEvent( mouseEvent); } /*! Handle a mouse move event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), */ void PlotMagnifier::widgetMouseMoveEvent( QMouseEvent *mouseEvent ) { if(mouseEvent->modifiers() != Qt::ControlModifier || mouseEvent->modifiers() == Qt::ShiftModifier) { return; } mouseEvent->setModifiers(Qt::NoModifier);// remove modifier so base class accepts event, we ignore events when shift key is pressed so panning works QwtPlotMagnifier::widgetMouseMoveEvent( mouseEvent); } /*! Handle a wheel event for the observed widget. \param wheelEvent Wheel event \sa eventFilter() */ void PlotMagnifier::widgetWheelEvent( QWheelEvent *wheelEvent ) { // remove modifier so base class accepts event wheelEvent->setModifiers(Qt::NoModifier); QwtPlotMagnifier::widgetWheelEvent( wheelEvent); }connectome-workbench-1.4.2/src/GuiQt/PlotMagnifier.h000066400000000000000000000034341360521144700223700ustar00rootroot00000000000000#ifndef __PLOT_MAGNIFIER__ #define __PLOT_MAGNIFIER__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" //qwt includes #include #include "qlayout.h" #include "qwt_plot.h" #include "qwt_plot_marker.h" #include "qwt_plot_curve.h" #include "qwt_legend.h" #include "qwt_series_data.h" #include "qwt_plot_canvas.h" #include "qwt_plot_panner.h" #include "qwt_plot_magnifier.h" #include "qwt_text.h" #include "qwt_math.h" #include namespace caret { class PlotMagnifier : public QwtPlotMagnifier { Q_OBJECT public: PlotMagnifier(QwtPlotCanvas * canvas = NULL); protected: virtual bool eventFilter(QObject * object,QEvent *event); virtual void widgetWheelEvent( QWheelEvent *wheelEvent ); virtual void widgetMouseMoveEvent( QMouseEvent *mouseEvent ); virtual void widgetMousePressEvent( QMouseEvent *mouseEvent ); virtual void widgetMouseReleaseEvent( QMouseEvent *mouseEvent ); private: }; } #endif //__PLOT_MAGNIFIER__ connectome-workbench-1.4.2/src/GuiQt/PlotPanner.cxx000066400000000000000000000075711360521144700222730ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /** * \class caret::PlotPanner * \brief Helper class for panning Qwt plots * \ingroup GuiQt */ #include "PlotPanner.h" using namespace caret; PlotPanner::PlotPanner(QwtPlotCanvas * canvas) : QwtPlotPanner(canvas) { this->setEnabled(true); this->setMouseButton(Qt::LeftButton); } bool PlotPanner::eventFilter(QObject * object,QEvent *event) { if ( object && (object == parent() || object == parent()->parent()) ) { switch ( event->type() ) { case QEvent::MouseButtonPress: { widgetMousePressEvent( ( QMouseEvent * )event ); break; } case QEvent::MouseMove: { widgetMouseMoveEvent( ( QMouseEvent * )event ); break; } case QEvent::MouseButtonRelease: { widgetMouseReleaseEvent( ( QMouseEvent * )event ); break; } case QEvent::KeyPress: { widgetKeyPressEvent( ( QKeyEvent * )event ); break; } case QEvent::KeyRelease: { widgetKeyReleaseEvent( ( QKeyEvent * )event ); break; } default:; } } return QObject::eventFilter( object, event ); } /*! Handle a mouse press event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMouseReleaseEvent(), widgetMouseMoveEvent() */ void PlotPanner::widgetMousePressEvent( QMouseEvent *mouseEvent ) { if(mouseEvent->modifiers() != Qt::ShiftModifier || mouseEvent->modifiers() == Qt::ControlModifier) { return; } mouseEvent->setModifiers(Qt::NoModifier); // remove modifier so base class accepts event, we ignore events when shift key is pressed so panning works QwtPlotPanner::widgetMousePressEvent( mouseEvent); } /*! Handle a mouse release event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseMoveEvent(), */ void PlotPanner::widgetMouseReleaseEvent( QMouseEvent *mouseEvent ) { /*if(mouseEvent->modifiers() != Qt::ShiftModifier || mouseEvent->modifiers() == Qt::ControlModifier) { return; }*/ mouseEvent->setModifiers(Qt::NoModifier); // remove modifier so base class accepts event, we ignore events when shift key is pressed so panning works QwtPlotPanner::widgetMouseReleaseEvent( mouseEvent); } /*! Handle a mouse move event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), */ void PlotPanner::widgetMouseMoveEvent( QMouseEvent *mouseEvent ) { if(mouseEvent->modifiers() != Qt::ShiftModifier || mouseEvent->modifiers() == Qt::ControlModifier) { return; } mouseEvent->setModifiers(Qt::NoModifier);// remove modifier so base class accepts event, we ignore events when shift key is pressed so panning works QwtPlotPanner::widgetMouseMoveEvent( mouseEvent); } connectome-workbench-1.4.2/src/GuiQt/PlotPanner.h000066400000000000000000000033141360521144700217070ustar00rootroot00000000000000#ifndef __PLOT_PANNER__ #define __PLOT_PANNER__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" //qwt includes #include #include "qlayout.h" #include "qwt_plot.h" #include "qwt_plot_marker.h" #include "qwt_plot_curve.h" #include "qwt_legend.h" #include "qwt_series_data.h" #include "qwt_plot_canvas.h" #include "qwt_plot_panner.h" #include "qwt_plot_magnifier.h" #include "qwt_text.h" #include "qwt_math.h" #include namespace caret { class PlotPanner : public QwtPlotPanner { Q_OBJECT public: PlotPanner(QwtPlotCanvas * canvas = NULL); protected: virtual bool eventFilter(QObject * object,QEvent *event); virtual void widgetMouseMoveEvent( QMouseEvent *mouseEvent ); virtual void widgetMousePressEvent( QMouseEvent *mouseEvent ); virtual void widgetMouseReleaseEvent( QMouseEvent *mouseEvent ); private: }; } #endif //__PLOT_PANNER__ connectome-workbench-1.4.2/src/GuiQt/PreferencesDialog.cxx000066400000000000000000001204401360521144700235610ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #define __PREFERENCES_DIALOG__H__DECLARE__ #include "PreferencesDialog.h" #undef __PREFERENCES_DIALOG__H__DECLARE__ #include "Brain.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPreferences.h" #include "EnumComboBoxTemplate.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventSurfaceColoringInvalidate.h" #include "GuiManager.h" #include "ImageCaptureMethodEnum.h" #include "OpenGLDrawingMethodEnum.h" #include "SessionManager.h" #include "WuQtUtilities.h" #include "WuQFactory.h" #include "WuQMessageBox.h" #include "WuQTrueFalseComboBox.h" #include "WuQWidgetObjectGroup.h" using namespace caret; /** * \class caret::PreferencesDialog * \brief Dialog for display/editing of prefernces. * \ingroup GuiQt * * Presents controls for editing palettes used to color * scalar data. */ /** * Constructor for editing a palette selection. * * @param parent * Parent widget on which this dialog is displayed. */ PreferencesDialog::PreferencesDialog(QWidget* parent) : WuQDialogNonModal("Preferences", parent) { setDeleteWhenClosed(false); /* * No apply button */ setApplyButtonText(""); /* * Used to block signals in all widgets */ m_allWidgets = new WuQWidgetObjectGroup(this); /* * Create the tab widget and all tab content */ QTabWidget* tabWidget = new QTabWidget(); tabWidget->addTab(createColorsWidget(), "Colors"); tabWidget->addTab(createIdentificationSymbolWidget(), "ID"); tabWidget->addTab(createMiscellaneousWidget(), "Misc"); tabWidget->addTab(createTabDefaltsWidget(), "New Tabs"); tabWidget->addTab(createOpenGLWidget(), "OpenGL"); setCentralWidget(tabWidget, WuQDialog::SCROLL_AREA_NEVER); disableAutoDefaultForAllPushButtons(); } /** * Destructor. */ PreferencesDialog::~PreferencesDialog() { } /** * Add a color button and swatch. * * @param gridLayout * Grid layout for widgets. * @param prefColor * Enumerated value for color. * @param colorSignalMapper * Signal mapper for buttons. */ void PreferencesDialog::addColorButtonAndSwatch(QGridLayout* gridLayout, const PREF_COLOR prefColor, QSignalMapper* colorSignalMapper) { QString buttonText; QWidget* colorSwatchWidget = new QWidget(); switch (prefColor) { case PREF_COLOR_BACKGROUND_ALL: buttonText = "All Background"; m_backgroundColorAllWidget = colorSwatchWidget; break; case PREF_COLOR_BACKGROUND_CHART: buttonText = "Chart Background"; m_backgroundColorChartWidget = colorSwatchWidget; break; case PREF_COLOR_BACKGROUND_SURFACE: buttonText = "Surface Background"; m_backgroundColorSurfaceWidget = colorSwatchWidget; break; case PREF_COLOR_BACKGROUND_VOLUME: buttonText = "Volume Background"; m_backgroundColorVolumeWidget = colorSwatchWidget; break; case PREF_COLOR_FOREGROUND_ALL: buttonText = "All Foreground"; m_foregroundColorAllWidget = colorSwatchWidget; break; case PREF_COLOR_FOREGROUND_CHART: buttonText = "Chart Foreground"; m_foregroundColorChartWidget = colorSwatchWidget; break; case PREF_COLOR_FOREGROUND_SURFACE: buttonText = "Surface Foreground"; m_foregroundColorSurfaceWidget = colorSwatchWidget; break; case PREF_COLOR_FOREGROUND_VOLUME: buttonText = "Volume Foreground"; m_foregroundColorVolumeWidget = colorSwatchWidget; break; case PREF_COLOR_CHART_MATRIX_GRID_LINES: buttonText = "Chart Grid Lines"; m_chartMatrixGridLinesColorWidget = colorSwatchWidget; break; case PREF_COLOR_CHART_THRESHOLD: buttonText = "Chart Threshold"; m_chartHistogramThresholdColorWidget = colorSwatchWidget; break; case PREF_COLOR_BACKGROUND_WINDOW: buttonText = "Window Background"; m_backgroundColorWindowWidget = colorSwatchWidget; break; case PREF_COLOR_FOREGROUND_WINDOW: buttonText = "Window Foreground"; m_foregroundColorWindowWidget = colorSwatchWidget; break; case NUMBER_OF_PREF_COLORS: CaretAssert(0); break; } buttonText.append("..."); CaretAssert( ! buttonText.isEmpty()); QPushButton* colorPushButton = new QPushButton(buttonText); QObject::connect(colorPushButton, SIGNAL(clicked()), colorSignalMapper, SLOT(map())); colorSignalMapper->setMapping(colorPushButton, (int)prefColor); addWidgetsToLayout(gridLayout, colorPushButton, colorSwatchWidget); } /** * @return The colors widget. */ QWidget* PreferencesDialog::createColorsWidget() { QSignalMapper* colorSignalMapper = new QSignalMapper(this); QGridLayout* gridLayout = new QGridLayout(); addColorButtonAndSwatch(gridLayout, PREF_COLOR_FOREGROUND_WINDOW, colorSignalMapper); addColorButtonAndSwatch(gridLayout, PREF_COLOR_BACKGROUND_WINDOW, colorSignalMapper); addColorButtonAndSwatch(gridLayout, PREF_COLOR_FOREGROUND_ALL, colorSignalMapper); addColorButtonAndSwatch(gridLayout, PREF_COLOR_BACKGROUND_ALL, colorSignalMapper); addColorButtonAndSwatch(gridLayout, PREF_COLOR_FOREGROUND_CHART, colorSignalMapper); addColorButtonAndSwatch(gridLayout, PREF_COLOR_BACKGROUND_CHART, colorSignalMapper); addColorButtonAndSwatch(gridLayout, PREF_COLOR_CHART_MATRIX_GRID_LINES, colorSignalMapper); addColorButtonAndSwatch(gridLayout, PREF_COLOR_CHART_THRESHOLD, colorSignalMapper); addColorButtonAndSwatch(gridLayout, PREF_COLOR_FOREGROUND_SURFACE, colorSignalMapper); addColorButtonAndSwatch(gridLayout, PREF_COLOR_BACKGROUND_SURFACE, colorSignalMapper); addColorButtonAndSwatch(gridLayout, PREF_COLOR_FOREGROUND_VOLUME, colorSignalMapper); addColorButtonAndSwatch(gridLayout, PREF_COLOR_BACKGROUND_VOLUME, colorSignalMapper); QObject::connect(colorSignalMapper, SIGNAL(mapped(int)), this, SLOT(colorPushButtonClicked(int))); m_allWidgets->add(colorSignalMapper); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addLayout(gridLayout); layout->addStretch(); return widget; } /** * Update the color widget's items. * * @param prefs * The Caret preferences. */ void PreferencesDialog::updateColorWidget(CaretPreferences* prefs) { const BackgroundAndForegroundColors colors = prefs->getUserBackgroundAndForegroundColors(); for (int32_t i = 0; i < NUMBER_OF_PREF_COLORS; i++) { const PREF_COLOR prefColor = (PREF_COLOR)i; uint8_t rgb[3] = { 0, 0, 0 }; QWidget* colorSwatchWidget = NULL; switch (prefColor) { case PREF_COLOR_BACKGROUND_ALL: colors.getColorBackgroundAllView(rgb); colorSwatchWidget = m_backgroundColorAllWidget; break; case PREF_COLOR_BACKGROUND_CHART: colors.getColorBackgroundChartView(rgb); colorSwatchWidget = m_backgroundColorChartWidget; break; case PREF_COLOR_BACKGROUND_SURFACE: colors.getColorBackgroundSurfaceView(rgb); colorSwatchWidget = m_backgroundColorSurfaceWidget; break; case PREF_COLOR_BACKGROUND_VOLUME: colors.getColorBackgroundVolumeView(rgb); colorSwatchWidget = m_backgroundColorVolumeWidget; break; case PREF_COLOR_FOREGROUND_ALL: colors.getColorForegroundAllView(rgb); colorSwatchWidget = m_foregroundColorAllWidget; break; case PREF_COLOR_FOREGROUND_CHART: colors.getColorForegroundChartView(rgb); colorSwatchWidget = m_foregroundColorChartWidget; break; case PREF_COLOR_FOREGROUND_SURFACE: colors.getColorForegroundSurfaceView(rgb); colorSwatchWidget = m_foregroundColorSurfaceWidget; break; case PREF_COLOR_FOREGROUND_VOLUME: colors.getColorForegroundVolumeView(rgb); colorSwatchWidget = m_foregroundColorVolumeWidget; break; case PREF_COLOR_CHART_MATRIX_GRID_LINES: colors.getColorChartMatrixGridLines(rgb); colorSwatchWidget = m_chartMatrixGridLinesColorWidget; break; case PREF_COLOR_CHART_THRESHOLD: colors.getColorChartHistogramThreshold(rgb); colorSwatchWidget = m_chartHistogramThresholdColorWidget; break; case PREF_COLOR_BACKGROUND_WINDOW: colors.getColorBackgroundWindow(rgb); colorSwatchWidget = m_backgroundColorWindowWidget; break; case PREF_COLOR_FOREGROUND_WINDOW: colors.getColorForegroundWindow(rgb); colorSwatchWidget = m_foregroundColorWindowWidget; break; case NUMBER_OF_PREF_COLORS: CaretAssert(0); break; } CaretAssert(colorSwatchWidget); colorSwatchWidget->setStyleSheet("background-color: rgb(" + AString::number(rgb[0]) + ", " + AString::number(rgb[1]) + ", " + AString::number(rgb[2]) + ");"); } } /** * @return The miscellaneous widget. */ QWidget* PreferencesDialog::createMiscellaneousWidget() { /* * Dynamic connectivity defautl */ m_dynamicConnectivityComboBox = new WuQTrueFalseComboBox("On", "Off", this); QObject::connect(m_dynamicConnectivityComboBox, SIGNAL(statusChanged(bool)), this, SLOT(miscDynamicConnectivityComboBoxChanged(bool))); m_allWidgets->add(m_dynamicConnectivityComboBox); m_dynamicConnectivityComboBox->setToolTip("Sets default (checked or unchecked) for dynamic connectivity files " "on the Overlay ToolBox --> Connectivity tab."); /* * Logging Level */ m_miscLoggingLevelComboBox = new QComboBox(); std::vector loggingLevels; LogLevelEnum::getAllEnums(loggingLevels); const int32_t numLogLevels = static_cast(loggingLevels.size()); for (int32_t i = 0; i < numLogLevels; i++) { const LogLevelEnum::Enum logLevel = loggingLevels[i]; m_miscLoggingLevelComboBox->addItem(LogLevelEnum::toGuiName(logLevel)); m_miscLoggingLevelComboBox->setItemData(i, LogLevelEnum::toIntegerCode(logLevel)); } QObject::connect(m_miscLoggingLevelComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(miscLoggingLevelComboBoxChanged(int))); m_allWidgets->add(m_miscLoggingLevelComboBox); /* * Splash Screen */ m_miscSplashScreenShowAtStartupComboBox = new WuQTrueFalseComboBox("On", "Off", this); QObject::connect(m_miscSplashScreenShowAtStartupComboBox, SIGNAL(statusChanged(bool)), this, SLOT(miscSplashScreenShowAtStartupComboBoxChanged(bool))); m_allWidgets->add(m_miscSplashScreenShowAtStartupComboBox); /* * Developer Menu */ m_miscDevelopMenuEnabledComboBox = new WuQTrueFalseComboBox("On", "Off", this); QObject::connect(m_miscDevelopMenuEnabledComboBox, SIGNAL(statusChanged(bool)), this, SLOT(miscDevelopMenuEnabledComboBoxChanged(bool))); m_allWidgets->add(m_miscDevelopMenuEnabledComboBox); /* * Manage Files View Files Type */ m_miscSpecFileDialogViewFilesTypeEnumComboBox = new EnumComboBoxTemplate(this); m_miscSpecFileDialogViewFilesTypeEnumComboBox->setup(); QObject::connect(m_miscSpecFileDialogViewFilesTypeEnumComboBox, SIGNAL(itemActivated()), this, SLOT(miscSpecFileDialogViewFilesTypeEnumComboBoxItemActivated())); m_allWidgets->add(m_miscSpecFileDialogViewFilesTypeEnumComboBox->getWidget()); QGridLayout* gridLayout = new QGridLayout(); addWidgetToLayout(gridLayout, "Dynconn As Layer Default: ", m_dynamicConnectivityComboBox->getWidget()); addWidgetToLayout(gridLayout, "Logging Level: ", m_miscLoggingLevelComboBox); addWidgetToLayout(gridLayout, "Save/Manage View Files: ", m_miscSpecFileDialogViewFilesTypeEnumComboBox->getWidget()); addWidgetToLayout(gridLayout, "Show Develop Menu in Menu Bar: ", m_miscDevelopMenuEnabledComboBox->getWidget()); addWidgetToLayout(gridLayout, "Show Splash Screen at Startup: ", m_miscSplashScreenShowAtStartupComboBox->getWidget()); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addLayout(gridLayout); layout->addStretch(); return widget; } /** * Update the miscellaneous widget's items. * * @param prefs * The Caret preferences. */ void PreferencesDialog::updateMiscellaneousWidget(CaretPreferences* prefs) { m_dynamicConnectivityComboBox->setStatus(prefs->isDynamicConnectivityDefaultedOn()); const LogLevelEnum::Enum loggingLevel = prefs->getLoggingLevel(); int indx = m_miscLoggingLevelComboBox->findData(LogLevelEnum::toIntegerCode(loggingLevel)); if (indx >= 0) { m_miscLoggingLevelComboBox->setCurrentIndex(indx); } m_miscDevelopMenuEnabledComboBox->setStatus(prefs->isDevelopMenuEnabled()); m_miscSplashScreenShowAtStartupComboBox->setStatus(prefs->isSplashScreenEnabled()); m_yokingDefaultComboBox->setStatus(prefs->isYokingDefaultedOn()); m_miscSpecFileDialogViewFilesTypeEnumComboBox->setSelectedItem(prefs->getManageFilesViewFileType()); } /** * @return The identification symbol widget. */ QWidget* PreferencesDialog::createIdentificationSymbolWidget() { QLabel* infoLabel = new QLabel("These are defaults for Information Properties"); infoLabel->setWordWrap(true); m_surfaceIdentificationSymbolComboBox = new WuQTrueFalseComboBox("On", "Off", this); QObject::connect(m_surfaceIdentificationSymbolComboBox, SIGNAL(statusChanged(bool)), this, SLOT(identificationSymbolToggled())); m_volumeIdentificationSymbolComboBox = new WuQTrueFalseComboBox("On", "Off", this); QObject::connect(m_volumeIdentificationSymbolComboBox, SIGNAL(statusChanged(bool)), this, SLOT(identificationSymbolToggled())); m_dataToolTipsComboBox = new WuQTrueFalseComboBox("On", "Off", this); QObject::connect(m_dataToolTipsComboBox, SIGNAL(statusChanged(bool)), this, SLOT(identificationSymbolToggled())); QGridLayout* gridLayout = new QGridLayout(); int row = gridLayout->rowCount(); gridLayout->addWidget(infoLabel, row, 0, 1, 2); addWidgetToLayout(gridLayout, "Show Surface ID Symbols: ", m_surfaceIdentificationSymbolComboBox->getWidget()); addWidgetToLayout(gridLayout, "Show Volume ID Symbols: ", m_volumeIdentificationSymbolComboBox->getWidget()); addWidgetToLayout(gridLayout, "Show Data Tool Tips: ", m_dataToolTipsComboBox->getWidget()); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addLayout(gridLayout); layout->addStretch(); return widget; } /** * Update the identification widget. * * @param prefs * The Caret preferences. */ void PreferencesDialog::updateIdentificationWidget(CaretPreferences* prefs) { m_surfaceIdentificationSymbolComboBox->setStatus(prefs->isShowSurfaceIdentificationSymbols()); m_volumeIdentificationSymbolComboBox->setStatus(prefs->isShowVolumeIdentificationSymbols()); m_dataToolTipsComboBox->setStatus(prefs->isShowDataToolTipsEnabled()); } /** * Gets called when an identification symbol check box is toggled. */ void PreferencesDialog::identificationSymbolToggled() { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setShowSurfaceIdentificationSymbols(m_surfaceIdentificationSymbolComboBox->isTrue()); prefs->setShowVolumeIdentificationSymbols(m_volumeIdentificationSymbolComboBox->isTrue()); prefs->setShowDataToolTipsEnabled(m_dataToolTipsComboBox->isTrue()); } /** * @return The OpenGL widget. */ QWidget* PreferencesDialog::createOpenGLWidget() { /* * Image Capture Method */ m_openGLImageCaptureMethodEnumComboBox = new EnumComboBoxTemplate(this); m_openGLImageCaptureMethodEnumComboBox->setup(); QObject::connect(m_openGLImageCaptureMethodEnumComboBox, SIGNAL(itemActivated()), this, SLOT(openGLImageCaptureMethodEnumComboBoxItemActivated())); const AString captureMethodToolTip = ("Sometimes, the default image capture method fails to " "function correctly and the captured image does not match " "the content of the graphics window. If this occurs, " "try changing the Capture Method to Grab Frame Buffer."); WuQtUtilities::setWordWrappedToolTip(m_openGLImageCaptureMethodEnumComboBox->getComboBox(), captureMethodToolTip); m_allWidgets->add(m_openGLImageCaptureMethodEnumComboBox->getWidget()); /* * OpenGL Drawing Method */ m_openGLDrawingMethodEnumComboBox = new EnumComboBoxTemplate(this); m_openGLDrawingMethodEnumComboBox->setup(); QObject::connect(m_openGLDrawingMethodEnumComboBox, SIGNAL(itemActivated()), this, SLOT(openGLDrawingMethodEnumComboBoxItemActivated())); m_allWidgets->add(m_openGLDrawingMethodEnumComboBox->getWidget()); QGridLayout* gridLayout = new QGridLayout(); addWidgetToLayout(gridLayout, "Image Capture Method: ", m_openGLImageCaptureMethodEnumComboBox->getWidget()); QLabel* vertexBuffersLabel = addWidgetToLayout(gridLayout, "OpenGL Vertex Buffers: ", m_openGLDrawingMethodEnumComboBox->getWidget()); /* * HIDE THE VERTEX BUFFERS OPTION */ vertexBuffersLabel->setHidden(true); m_openGLDrawingMethodEnumComboBox->getWidget()->setHidden(true); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addLayout(gridLayout); layout->addStretch(); return widget; } /** * Update the OpenGL widget's items. * * @param prefs * The Caret preferences. */ void PreferencesDialog::updateOpenGLWidget(CaretPreferences* prefs) { const ImageCaptureMethodEnum::Enum captureMethod = prefs->getImageCaptureMethod(); m_openGLImageCaptureMethodEnumComboBox->setSelectedItem(captureMethod); const OpenGLDrawingMethodEnum::Enum drawingMethod = prefs->getOpenDrawingMethod(); m_openGLDrawingMethodEnumComboBox->setSelectedItem(drawingMethod); } /** * @return The volume widget. */ QWidget* PreferencesDialog::createTabDefaltsWidget() { /* * Yoking */ m_yokingDefaultComboBox = new WuQTrueFalseComboBox("On", "Off", this); QObject::connect(m_yokingDefaultComboBox, SIGNAL(statusChanged(bool)), this, SLOT(yokingComboBoxToggled(bool))); m_allWidgets->add(m_yokingDefaultComboBox); /* * Crosshairs On/Off */ m_volumeAxesCrosshairsComboBox = new WuQTrueFalseComboBox("On", "Off", this); QObject::connect(m_volumeAxesCrosshairsComboBox, SIGNAL(statusChanged(bool)), this, SLOT(volumeAxesCrosshairsComboBoxToggled(bool))); m_allWidgets->add(m_volumeAxesCrosshairsComboBox); /* * Axes Labels On/Off */ m_volumeAxesLabelsComboBox = new WuQTrueFalseComboBox("On", "Off", this); QObject::connect(m_volumeAxesLabelsComboBox, SIGNAL(statusChanged(bool)), this, SLOT(volumeAxesLabelsComboBoxToggled(bool))); m_allWidgets->add(m_volumeAxesLabelsComboBox); /* * Identification On/Off */ m_volumeIdentificationComboBox = new WuQTrueFalseComboBox("On", "Off", this); QObject::connect(m_volumeIdentificationComboBox, SIGNAL(statusChanged(bool)), this, SLOT(volumeIdentificationComboBoxToggled(bool))); m_allWidgets->add(m_volumeIdentificationComboBox); /* * Montage Coordinates On/Off */ m_volumeAxesMontageCoordinatesComboBox = new WuQTrueFalseComboBox("On", "Off", this); QObject::connect(m_volumeAxesMontageCoordinatesComboBox, SIGNAL(statusChanged(bool)), this, SLOT(volumeAxesMontageCoordinatesComboBoxToggled(bool))); m_allWidgets->add(m_volumeAxesMontageCoordinatesComboBox); /* * Montage Slice Coordinate Precision */ m_volumeMontageCoordinatePrecisionSpinBox = WuQFactory::newSpinBoxWithMinMaxStepSignalInt(0, 5, 1, this, SLOT(volumeMontageCoordinatePrecisionChanged(int))); m_allWidgets->add(m_volumeMontageCoordinatePrecisionSpinBox); /* * All slice planes layout default */ m_volumeAllSlicePlanesLayoutComboBox = new EnumComboBoxTemplate(this); m_volumeAllSlicePlanesLayoutComboBox->setup(); QObject::connect(m_volumeAllSlicePlanesLayoutComboBox, SIGNAL(itemActivated()), this, SLOT(m_volumeAllSlicePlanesLayoutItemActivated())); m_allWidgets->add(m_volumeAllSlicePlanesLayoutComboBox->getWidget()); QGridLayout* gridLayout = new QGridLayout(); QLabel* infoLabel = new QLabel("" "These are the default settings for new Tabs. If " "Yoked to Group A is on, the volume settings are overriden " "by the yoked Tabs." ""); infoLabel->setWordWrap(true); gridLayout->addWidget(infoLabel, 0, 0, 1, 2); addWidgetToLayout(gridLayout, "Yoked to Group A: ", m_yokingDefaultComboBox->getWidget()); addWidgetToLayout(gridLayout, "Volume Axes Crosshairs: ", m_volumeAxesCrosshairsComboBox->getWidget()); addWidgetToLayout(gridLayout, "Volume Axes Labels: ", m_volumeAxesLabelsComboBox->getWidget()); addWidgetToLayout(gridLayout, "Volume ID Moves Slice Selection: ", m_volumeIdentificationComboBox->getWidget()); addWidgetToLayout(gridLayout, "Volume Montage Slice Coord: ", m_volumeAxesMontageCoordinatesComboBox->getWidget()); addWidgetToLayout(gridLayout, "Volume Montage Precision: ", m_volumeMontageCoordinatePrecisionSpinBox); addWidgetToLayout(gridLayout, "All Slice Planes Layout: ", m_volumeAllSlicePlanesLayoutComboBox->getWidget()); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addLayout(gridLayout); layout->addStretch(); return widget; } /** * Update the Volume widget's items. * * @param prefs * The Caret preferences. */ void PreferencesDialog::updateVolumeWidget(CaretPreferences* prefs) { m_volumeAxesCrosshairsComboBox->setStatus(prefs->isVolumeAxesCrosshairsDisplayed()); m_volumeAxesLabelsComboBox->setStatus(prefs->isVolumeAxesLabelsDisplayed()); m_volumeAxesMontageCoordinatesComboBox->setStatus(prefs->isVolumeMontageAxesCoordinatesDisplayed()); m_volumeIdentificationComboBox->setStatus(prefs->isVolumeIdentificationDefaultedOn()); m_volumeMontageCoordinatePrecisionSpinBox->setValue(prefs->getVolumeMontageCoordinatePrecision()); m_volumeAllSlicePlanesLayoutComboBox->setSelectedItem(prefs->getVolumeAllSlicePlanesLayout()); } /** * Add a label in the left column and the widget in the right column. * * @param gridLayout * The grid layout to which the widgets are added. * @param labelText * Text for label. * @param widget * Widget for right column. * @return * The label that corresponds to the widget. */ QLabel* PreferencesDialog::addWidgetToLayout(QGridLayout* gridLayout, const QString& labelText, QWidget* widget) { QLabel* label = new QLabel(labelText); label->setAlignment(Qt::AlignRight); addWidgetsToLayout(gridLayout, label, widget); return label; } /** * Add widgets to the layout. If rightWidget is NULL, * leftItem spans both columns. * * @param leftWidget * Widget for left column. * @param rightWidget * Widget for right column. */ void PreferencesDialog::addWidgetsToLayout(QGridLayout* gridLayout, QWidget* leftWidget, QWidget* rightWidget) { int row = gridLayout->rowCount(); if (rightWidget != NULL) { gridLayout->addWidget(leftWidget, row, 0); gridLayout->addWidget(rightWidget, row, 1); } else { gridLayout->addWidget(leftWidget, row, 0, 1, 2, Qt::AlignLeft); } } /** * May be called to update the dialog's content. */ void PreferencesDialog::updateDialog() { m_allWidgets->blockAllSignals(true); CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); updateColorWidget(prefs); updateMiscellaneousWidget(prefs); updateIdentificationWidget(prefs); updateOpenGLWidget(prefs); updateVolumeWidget(prefs); m_allWidgets->blockAllSignals(false); } /** * Update the colors in the dialog. * * @param prefColor * Color that will be updated. */ void PreferencesDialog::updateColorWithDialog(const PREF_COLOR prefColor) { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); const BackgroundAndForegroundColors colors = prefs->getUserBackgroundAndForegroundColors(); uint8_t rgb[3]; AString prefColorName; switch (prefColor) { case PREF_COLOR_BACKGROUND_ALL: colors.getColorBackgroundAllView(rgb); prefColorName = "Background - All"; break; case PREF_COLOR_BACKGROUND_CHART: colors.getColorBackgroundChartView(rgb); prefColorName = "Background - Chart"; break; case PREF_COLOR_BACKGROUND_SURFACE: colors.getColorBackgroundSurfaceView(rgb); prefColorName = "Background - Surface"; break; case PREF_COLOR_BACKGROUND_VOLUME: colors.getColorBackgroundVolumeView(rgb); prefColorName = "Background - Volume"; break; case PREF_COLOR_FOREGROUND_ALL: colors.getColorForegroundAllView(rgb); prefColorName = "Foreground - All"; break; case PREF_COLOR_FOREGROUND_CHART: colors.getColorForegroundChartView(rgb); prefColorName = "Foreground - Chart"; break; case PREF_COLOR_FOREGROUND_SURFACE: colors.getColorForegroundSurfaceView(rgb); prefColorName = "Foreground - Surface"; break; case PREF_COLOR_FOREGROUND_VOLUME: colors.getColorForegroundVolumeView(rgb); prefColorName = "Foreground - Volume"; break; case PREF_COLOR_CHART_MATRIX_GRID_LINES: colors.getColorChartMatrixGridLines(rgb); prefColorName = "Chart Matrix Grid Lines"; break; case PREF_COLOR_CHART_THRESHOLD: colors.getColorChartHistogramThreshold(rgb); prefColorName = "Chart Histogram Threshold"; break; case PREF_COLOR_BACKGROUND_WINDOW: colors.getColorBackgroundWindow(rgb); prefColorName = "Background - Window"; break; case PREF_COLOR_FOREGROUND_WINDOW: colors.getColorForegroundWindow(rgb); prefColorName = "Foreground - Window"; break; case NUMBER_OF_PREF_COLORS: CaretAssert(0); break; } const QColor initialColor(rgb[0], rgb[1], rgb[2]); QColorDialog colorDialog(this); colorDialog.setOption(QColorDialog::DontUseNativeDialog); colorDialog.setWindowTitle(prefColorName); colorDialog.setCurrentColor(initialColor); if (colorDialog.exec() == QColorDialog::Accepted) { const QColor newColor = colorDialog.currentColor(); rgb[0] = newColor.red(); rgb[1] = newColor.green(); rgb[2] = newColor.blue(); BackgroundAndForegroundColors colors = prefs->getUserBackgroundAndForegroundColors(); switch (prefColor) { case PREF_COLOR_BACKGROUND_ALL: colors.setColorBackgroundAllView(rgb); break; case PREF_COLOR_BACKGROUND_CHART: colors.setColorBackgroundChartView(rgb); break; case PREF_COLOR_BACKGROUND_SURFACE: colors.setColorBackgroundSurfaceView(rgb); break; case PREF_COLOR_BACKGROUND_VOLUME: colors.setColorBackgroundVolumeView(rgb); break; case PREF_COLOR_FOREGROUND_ALL: colors.setColorForegroundAllView(rgb); break; case PREF_COLOR_FOREGROUND_CHART: colors.setColorForegroundChartView(rgb); break; case PREF_COLOR_FOREGROUND_SURFACE: colors.setColorForegroundSurfaceView(rgb); break; case PREF_COLOR_FOREGROUND_VOLUME: colors.setColorForegroundVolumeView(rgb); break; case PREF_COLOR_CHART_MATRIX_GRID_LINES: colors.setColorChartMatrixGridLines(rgb); break; case PREF_COLOR_CHART_THRESHOLD: colors.setColorChartHistogramThreshold(rgb); break; case PREF_COLOR_BACKGROUND_WINDOW: colors.setColorBackgroundWindow(rgb); break; case PREF_COLOR_FOREGROUND_WINDOW: colors.setColorForegroundWindow(rgb); break; case NUMBER_OF_PREF_COLORS: CaretAssert(0); break; } prefs->setUserBackgroundAndForegroundColors(colors); prefs->setBackgroundAndForegroundColorsMode(BackgroundAndForegroundColorsModeEnum::USER_PREFERENCES); updateColorWidget(prefs); EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } /** * Called when a color button is clicked. * * @param enumIndex * color enum integer value indicating button that was clicked. */ void PreferencesDialog::colorPushButtonClicked(int enumIndex) { const PREF_COLOR prefColor = (PREF_COLOR)enumIndex; updateColorWithDialog(prefColor); } /** * Called when the logging level is changed. * @param int indx * New index of logging level combo box. */ void PreferencesDialog::miscLoggingLevelComboBoxChanged(int indx) { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); const int32_t logLevelIntegerCode = m_miscLoggingLevelComboBox->itemData(indx).toInt(); prefs->setLoggingLevel(LogLevelEnum::fromIntegerCode(logLevelIntegerCode, NULL)); } /** * Called when the apply button is pressed. */ void PreferencesDialog::applyButtonClicked() { EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called when the OpenGL drawing method is changed. */ void PreferencesDialog::openGLDrawingMethodEnumComboBoxItemActivated() { const OpenGLDrawingMethodEnum::Enum drawingMethod = m_openGLDrawingMethodEnumComboBox->getSelectedItem(); CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setOpenGLDrawingMethod(drawingMethod); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called when the image capture method is changed. */ void PreferencesDialog::openGLImageCaptureMethodEnumComboBoxItemActivated() { const ImageCaptureMethodEnum::Enum imageCaptureMethod = m_openGLImageCaptureMethodEnumComboBox->getSelectedItem(); CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setImageCaptureMethod(imageCaptureMethod); } /** * Called when volume crosshairs is toggled. * @param value * New value. */ void PreferencesDialog::volumeAxesCrosshairsComboBoxToggled(bool value) { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setVolumeAxesCrosshairsDisplayed(value); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called when volume labels is toggled. * @param value * New value. */ void PreferencesDialog::volumeAxesLabelsComboBoxToggled(bool value) { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setVolumeAxesLabelsDisplayed(value); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called when volume labels is toggled. * @param value * New value. */ void PreferencesDialog::volumeAxesMontageCoordinatesComboBoxToggled(bool value) { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setVolumeMontageAxesCoordinatesDisplayed(value); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called when ALL view slice plane layout changed by user */ void PreferencesDialog::m_volumeAllSlicePlanesLayoutItemActivated() { VolumeSliceViewAllPlanesLayoutEnum::Enum layoutValue = m_volumeAllSlicePlanesLayoutComboBox->getSelectedItem(); CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setVolumeAllSlicePlanesLayout(layoutValue); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called when volume montage coordinate precision value is changed. */ void PreferencesDialog::volumeMontageCoordinatePrecisionChanged(int value) { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setVolumeMontageCoordinatePrecision(value); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called when volume identification value is changed. */ void PreferencesDialog::volumeIdentificationComboBoxToggled(bool value) { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setVolumeIdentificationDefaultedOn(value); } /** * Called when yoking default value is changed. */ void PreferencesDialog::yokingComboBoxToggled(bool value) { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setYokingDefaultedOn(value); } /** * Called when show splash screen option changed. * @param value * New value. */ void PreferencesDialog::miscSplashScreenShowAtStartupComboBoxChanged(bool value) { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setSplashScreenEnabled(value); } /** * Called when dynamic connectivity option changed. * @param value * New value. */ void PreferencesDialog::miscDynamicConnectivityComboBoxChanged(bool value) { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setDynamicConnectivityDefaultedOn(value); } /** * Called when show develop menu option changed. * @param value * New value. */ void PreferencesDialog::miscDevelopMenuEnabledComboBoxChanged(bool value) { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setDevelopMenuEnabled(value); EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_BROWSER_WINDOW_MENUS_UPDATE); } /** * Gets called when view files type is changed. */ void PreferencesDialog::miscSpecFileDialogViewFilesTypeEnumComboBoxItemActivated() { const SpecFileDialogViewFilesTypeEnum::Enum viewFilesType = m_miscSpecFileDialogViewFilesTypeEnumComboBox->getSelectedItem(); CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setManageFilesViewFileType(viewFilesType); } connectome-workbench-1.4.2/src/GuiQt/PreferencesDialog.h000066400000000000000000000145321360521144700232120ustar00rootroot00000000000000#ifndef __PREFERENCES_DIALOG__H_ #define __PREFERENCES_DIALOG__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WuQDialogNonModal.h" class QCheckBox; class QComboBox; class QDoubleSpinBox; class QGridLayout; class QLabel; class QSignalMapper; class QSpinBox; namespace caret { class CaretPreferences; class EnumComboBoxTemplate; class WuQTrueFalseComboBox; class WuQWidgetObjectGroup; class PreferencesDialog : public WuQDialogNonModal { Q_OBJECT public: PreferencesDialog(QWidget* parent); virtual ~PreferencesDialog(); void updateDialog(); protected: virtual void applyButtonClicked(); private slots: void colorPushButtonClicked(int); void miscDevelopMenuEnabledComboBoxChanged(bool value); void miscLoggingLevelComboBoxChanged(int); void miscSplashScreenShowAtStartupComboBoxChanged(bool value); void miscSpecFileDialogViewFilesTypeEnumComboBoxItemActivated(); void miscDynamicConnectivityComboBoxChanged(bool value); void openGLDrawingMethodEnumComboBoxItemActivated(); void openGLImageCaptureMethodEnumComboBoxItemActivated(); void volumeAxesCrosshairsComboBoxToggled(bool value); void volumeAxesLabelsComboBoxToggled(bool value); void volumeAxesMontageCoordinatesComboBoxToggled(bool value); void volumeMontageCoordinatePrecisionChanged(int value); void volumeIdentificationComboBoxToggled(bool value); void m_volumeAllSlicePlanesLayoutItemActivated(); void yokingComboBoxToggled(bool value); void identificationSymbolToggled(); private: enum PREF_COLOR { PREF_COLOR_BACKGROUND_ALL = 0, PREF_COLOR_BACKGROUND_CHART = 1, PREF_COLOR_BACKGROUND_SURFACE = 2, PREF_COLOR_BACKGROUND_VOLUME = 3, PREF_COLOR_FOREGROUND_ALL = 4, PREF_COLOR_FOREGROUND_CHART = 5, PREF_COLOR_FOREGROUND_SURFACE = 6, PREF_COLOR_FOREGROUND_VOLUME = 7, PREF_COLOR_CHART_MATRIX_GRID_LINES = 8, PREF_COLOR_CHART_THRESHOLD = 9, PREF_COLOR_BACKGROUND_WINDOW = 10, PREF_COLOR_FOREGROUND_WINDOW = 11, NUMBER_OF_PREF_COLORS = 12 }; QWidget* createColorsWidget(); QWidget* createIdentificationSymbolWidget(); QWidget* createMiscellaneousWidget(); QWidget* createOpenGLWidget(); QWidget* createTabDefaltsWidget(); void updateColorWidget(CaretPreferences* prefs); void updateIdentificationWidget(CaretPreferences* prefs); void updateMiscellaneousWidget(CaretPreferences* prefs); void updateOpenGLWidget(CaretPreferences* prefs); void updateVolumeWidget(CaretPreferences* prefs); void updateColorWithDialog(const PREF_COLOR prefColor); QLabel* addWidgetToLayout(QGridLayout* gridLayout, const QString& labelText, QWidget* widget); void addWidgetsToLayout(QGridLayout* gridLayout, QWidget* leftWidget, QWidget* rightWidget); void addColorButtonAndSwatch(QGridLayout* gridLayout, const PREF_COLOR prefColor, QSignalMapper* colorSignalMapper); PreferencesDialog(const PreferencesDialog&); PreferencesDialog& operator=(const PreferencesDialog&); QWidget* m_foregroundColorWindowWidget; QWidget* m_foregroundColorAllWidget; QWidget* m_foregroundColorChartWidget; QWidget* m_foregroundColorSurfaceWidget; QWidget* m_foregroundColorVolumeWidget; QWidget* m_backgroundColorWindowWidget; QWidget* m_backgroundColorAllWidget; QWidget* m_backgroundColorChartWidget; QWidget* m_backgroundColorSurfaceWidget; QWidget* m_backgroundColorVolumeWidget; QWidget* m_chartMatrixGridLinesColorWidget; QWidget* m_chartHistogramThresholdColorWidget; WuQTrueFalseComboBox* m_miscDevelopMenuEnabledComboBox; QComboBox* m_miscLoggingLevelComboBox; WuQTrueFalseComboBox* m_miscSplashScreenShowAtStartupComboBox; EnumComboBoxTemplate* m_miscSpecFileDialogViewFilesTypeEnumComboBox; EnumComboBoxTemplate* m_openGLDrawingMethodEnumComboBox; EnumComboBoxTemplate* m_openGLImageCaptureMethodEnumComboBox; WuQTrueFalseComboBox* m_dynamicConnectivityComboBox; EnumComboBoxTemplate* m_volumeAllSlicePlanesLayoutComboBox; WuQTrueFalseComboBox* m_volumeAxesCrosshairsComboBox; WuQTrueFalseComboBox* m_volumeAxesLabelsComboBox; WuQTrueFalseComboBox* m_volumeAxesMontageCoordinatesComboBox; QSpinBox* m_volumeMontageCoordinatePrecisionSpinBox; WuQTrueFalseComboBox* m_volumeIdentificationComboBox; WuQTrueFalseComboBox* m_yokingDefaultComboBox; WuQTrueFalseComboBox* m_surfaceIdentificationSymbolComboBox; WuQTrueFalseComboBox* m_volumeIdentificationSymbolComboBox; WuQTrueFalseComboBox* m_dataToolTipsComboBox; WuQWidgetObjectGroup* m_allWidgets; }; #ifdef __PREFERENCES_DIALOG__H__DECLARE__ #endif // __PREFERENCES_DIALOG__H__DECLARE__ } // namespace #endif //__PREFERENCES_DIALOG__H_ connectome-workbench-1.4.2/src/GuiQt/ProgressReportingDialog.cxx000066400000000000000000000127511360521144700250230ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __PROGRESS_REPORTING_DIALOG_DECLARE__ #include "ProgressReportingDialog.h" #undef __PROGRESS_REPORTING_DIALOG_DECLARE__ #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "EventManager.h" #include "EventProgressUpdate.h" #include "ProgressReportingFromEvent.h" #include "ProgressReportingWithSlots.h" using namespace caret; /** * \class caret::ProgressReportingDialog * \brief Progress Report Dialog * \ingroup GuiQt */ /** * \class caret::ProgressReportingDialog * \brief Dialog that displays "progress" as an event is running. * * This dialog will the display the "progress" on a task as the * task executes. As the task is running, it should send * EventProgressUpdate events indicating the progress of the processing. * If the user chooses to cancel the event, this dialog will indicate so * on the first EventProgressUpdate received after the Cancel button is * clicked. The task should query the ProgressReportingDialog::isCancelled() * after each progress update is sent. * * Tasks may send the EventProgressUpdate event from other threads. * When the event is received signals and slots are used to update * the contents of the dialog instead of directly updating the dialog's * content. Qt's signals and slots mechanism supports signals connecting * to slots that are in a different thread. * * Use the static method "runEvent" to run an event with a progress dialog. * * For other cases, use the public constructor. Create an instance of the * progress dialog and then start the desired task. The progress dialog * will automatically close when the progress value equals the maximum * progress value or when the progress dialog goes out of scope. */ /** * Constructor. * * User will need to send EventProgressUpdate events to update * this progress dialog. * * @param title * Title for dialog. * @param initialMessage * Message that is first displayed. * @param parent * Parent on which this progress dialog is displayed. * @param f * Window flags. */ ProgressReportingDialog::ProgressReportingDialog(const AString& title, const AString& initialMessage, QWidget* parent, Qt::WindowFlags f) : QProgressDialog(initialMessage, "Cancel", 0, 100, parent, f) { ProgressReportingFromEvent* progressFromEvent = new ProgressReportingFromEvent(this); m_progressReporter = progressFromEvent; if (title.isEmpty() == false) { setWindowTitle(title); } const int minimumTimeInMillisecondsBeforeDialogDisplayed = 0; setMinimumDuration(minimumTimeInMillisecondsBeforeDialogDisplayed); QObject::connect(progressFromEvent, SIGNAL(reportProgressRange(const int, const int)), this, SLOT(setRange(int, int))); QObject::connect(progressFromEvent, SIGNAL(reportProgressValue(const int)), this, SLOT(setValue(int))); QObject::connect(progressFromEvent, SIGNAL(reportProgressMessage(const QString&)), this, SLOT(setLabelText(const QString&))); QObject::connect(this, SIGNAL(canceled()), progressFromEvent, SLOT(requestCancel())); } /** * Destructor. */ ProgressReportingDialog::~ProgressReportingDialog() { } /** * Run the event in a progress dialog. Dialog will close after the * event completes. Progress is updated each time a * EventProgressUpdate is received. * * @param event * Event that is executed. * @param parent * Widget on which the dialog is displayed. * @param title * If not empty, title is in window's title bar */ void ProgressReportingDialog::runEvent(Event* event, QWidget* parent, const AString& title) { ProgressReportingDialog prd(title, "", parent); prd.setValue(0); EventManager::get()->sendEvent(event); prd.setValue(prd.maximum()); } /** * Set event receiving enabled. This method is used to enable * and disable the receiving of EventProgressUpdate events. * The default is true. * * @param enabled * New status for receiving the events. */ void ProgressReportingDialog::setEventReceivingEnabled(bool status) { ProgressReportingFromEvent* progFromEvent = dynamic_cast(m_progressReporter); if (progFromEvent != NULL) { progFromEvent->setEventReceivingEnabled(status); } } connectome-workbench-1.4.2/src/GuiQt/ProgressReportingDialog.h000066400000000000000000000042051360521144700244430ustar00rootroot00000000000000#ifndef __PROGRESS_REPORTING_DIALOG_H__ #define __PROGRESS_REPORTING_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AString.h" #include "EventListenerInterface.h" namespace caret { class ProgressReportingInterface; class ProgressReportingDialog : public QProgressDialog { Q_OBJECT public: ProgressReportingDialog(const AString& title, const AString& initialMessage, QWidget* parent, Qt::WindowFlags f = 0); static void runEvent(Event* event, QWidget* parent, const AString& title); void setEventReceivingEnabled(bool status); public: virtual ~ProgressReportingDialog(); private: ProgressReportingDialog(const ProgressReportingDialog&); ProgressReportingDialog& operator=(const ProgressReportingDialog&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE ProgressReportingInterface* m_progressReporter; }; #ifdef __PROGRESS_REPORTING_DIALOG_DECLARE__ // #endif // __PROGRESS_REPORTING_DIALOG_DECLARE__ } // namespace #endif //__PROGRESS_REPORTING_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/ProgressReportingFromEvent.cxx000066400000000000000000000101151360521144700255210ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __PROGRESS_REPORTING_FROM_EVENT_DECLARE__ #include "ProgressReportingFromEvent.h" #undef __PROGRESS_REPORTING_FROM_EVENT_DECLARE__ #include #include "CaretAssert.h" #include "EventManager.h" #include "EventProgressUpdate.h" using namespace caret; //============================================================================= /** * \class caret::ProgressReportingFromEvent * \brief Interfaces between the ProgressReportingDialog and the Workbench event system * * Listens for EventProgressUpdate events and then updates the progress * dialog using signals and slots. Using signals and slots should allow * the progress events to be sent from a thread that is not the GUI thread. */ /** * Constructor. * * @parent * Parent of this instance. */ ProgressReportingFromEvent::ProgressReportingFromEvent(QObject* parent) : ProgressReportingWithSlots(parent) { EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_PROGRESS_UPDATE); m_eventReceivingEnabled = true; } /** * Destructor. */ ProgressReportingFromEvent::~ProgressReportingFromEvent() { EventManager::get()->removeAllEventsFromListener(this); } /** * Set event receiving enabled. This method is used to enable * and disable the receiving of EventProgressUpdate events. * The default is true. * * @param enabled * New status for receiving the events. */ void ProgressReportingFromEvent::setEventReceivingEnabled(bool enabled) { m_eventReceivingEnabled = enabled; } /** * @return Is event receiving enabled? The default is true. */ bool ProgressReportingFromEvent::isEventReceivingEnabled() const { return m_eventReceivingEnabled; } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void ProgressReportingFromEvent::receiveEvent(Event* event) { if ( ! m_eventReceivingEnabled) { return; } if (event->getEventType() == EventTypeEnum::EVENT_PROGRESS_UPDATE) { EventProgressUpdate* progressEvent = dynamic_cast(event); CaretAssert(progressEvent); const int minProg = progressEvent->getMinimumProgressValue(); const int maxProg = progressEvent->getMaximumProgressValue(); const int progValue = progressEvent->getProgressValue(); const AString progMessage = progressEvent->getProgressMessage(); /* * Note: It appears that the content of the progress dialog * only changes when the progress value is changed. So, set * the message prior to the progress value so that if the message * changes, the message in the progress dialog will be updated * when the progress value changes. */ if (progMessage.isEmpty() == false) { setProgressMessage(progMessage); } if ((minProg >= 0) && (maxProg >= minProg)) { setProgressRange(minProg, maxProg); } if (progValue >= 0) { setProgressValue(progValue); } if (isCancelRequested()) { progressEvent->setCancelled(); } QApplication::processEvents(); progressEvent->setEventProcessed(); } } connectome-workbench-1.4.2/src/GuiQt/ProgressReportingFromEvent.h000066400000000000000000000036411360521144700251540ustar00rootroot00000000000000#ifndef __PROGRESS_REPORTING_FROM_EVENT_H__ #define __PROGRESS_REPORTING_FROM_EVENT_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ProgressReportingWithSlots.h" #include "EventListenerInterface.h" namespace caret { class ProgressReportingFromEvent : public ProgressReportingWithSlots, public EventListenerInterface { Q_OBJECT public: ProgressReportingFromEvent(QObject* parent); virtual ~ProgressReportingFromEvent(); void setEventReceivingEnabled(bool enabled); bool isEventReceivingEnabled() const; // ADD_NEW_METHODS_HERE virtual void receiveEvent(Event* event); private: ProgressReportingFromEvent(const ProgressReportingFromEvent&); ProgressReportingFromEvent& operator=(const ProgressReportingFromEvent&); bool m_eventReceivingEnabled; // ADD_NEW_MEMBERS_HERE }; #ifdef __PROGRESS_REPORTING_FROM_EVENT_DECLARE__ // #endif // __PROGRESS_REPORTING_FROM_EVENT_DECLARE__ } // namespace #endif //__PROGRESS_REPORTING_FROM_EVENT_H__ connectome-workbench-1.4.2/src/GuiQt/ProgressReportingWithSlots.cxx000066400000000000000000000104531360521144700255610ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __PROGRESS_REPORTING_WITH_SLOTS_DECLARE__ #include "ProgressReportingWithSlots.h" #undef __PROGRESS_REPORTING_WITH_SLOTS_DECLARE__ using namespace caret; /** * \class caret::ProgressReportingWithSlots * \brief Interfaces between the ProgressReportingDialog and the Workbench event system * \ingroup GuiQt * * Listens for EventProgressUpdate events and then updates the progress * dialog using signals and slots. Using signals and slots should allow * the progress events to be sent from a thread that is not the GUI thread. */ /** * Constructor. */ ProgressReportingWithSlots::ProgressReportingWithSlots(QObject* parent) : QObject(parent), ProgressReportingInterface() { #if QT_VERSION >= 0x050000 #else m_synchronizeMutex.unlock(); #endif m_cancelled = false; } /** * Constructor. */ ProgressReportingWithSlots::~ProgressReportingWithSlots() { } /** * Used by task to set the range of progress reporting. * * @param minimumProgress * The minimum amount reported (typically zero). * @param maximumProgress * The maximum amount of progress. */ void ProgressReportingWithSlots::setProgressRange(const int minimumProgress, const int maximumProgress) { /* * Don't let any other method in an instance of this * class execute until this method completes. */ QMutexLocker locker(&m_synchronizeMutex); if ((minimumProgress >= 0) && (maximumProgress >= minimumProgress)) { emit reportProgressRange(minimumProgress, maximumProgress); } } /** * Used by task to set the current progress. * * @param progressValue * The current progress within range of the minimum and maximum. */ void ProgressReportingWithSlots::setProgressValue(const int progressValue) { /* * Don't let any other method in an instance of this * class execute until this method completes. */ QMutexLocker locker(&m_synchronizeMutex); if (progressValue >= 0) { emit reportProgressValue(progressValue); } } /** * Used by task to set the message describing the task's activity. * * @param message * Message that is displayed. */ void ProgressReportingWithSlots::setProgressMessage(const AString& progressMessage) { /* * Don't let any other method in an instance of this * class execute until this method completes. */ QMutexLocker locker(&m_synchronizeMutex); if (progressMessage.isEmpty() == false) { emit reportProgressMessage(progressMessage); } } /** * (SLOT) Used by the user-interface to request that the task end as * soon as possible. */ void ProgressReportingWithSlots::requestCancel() { setCancelRequested(); } /** * @return "true" if a request been made to cancel the task, else false. * * Used by the task to see if the task should end as soon as * possible. If so, the task should clean up after itself * (release resources); */ bool ProgressReportingWithSlots::isCancelRequested() const { /* * Don't let any other method in an instance of this * class execute until this method completes. */ QMutexLocker locker(&m_synchronizeMutex); return m_cancelled; } /** * Set the cancel request. */ void ProgressReportingWithSlots::setCancelRequested() { /* * Don't let any other method in an instance of this * class execute until this method completes. */ QMutexLocker locker(&m_synchronizeMutex); m_cancelled = true; } connectome-workbench-1.4.2/src/GuiQt/ProgressReportingWithSlots.h000066400000000000000000000061431360521144700252070ustar00rootroot00000000000000#ifndef __PROGRESS_REPORTING_WITH_SLOTS_H__ #define __PROGRESS_REPORTING_WITH_SLOTS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "ProgressReportingInterface.h" namespace caret { class ProgressReportingWithSlots : public QObject, public ProgressReportingInterface { Q_OBJECT public: ProgressReportingWithSlots(QObject* parent); virtual ~ProgressReportingWithSlots(); virtual void setProgressRange(const int minimumProgress, const int maximumProgress); virtual void setProgressValue(const int progressValue); virtual void setProgressMessage(const AString& message); virtual bool isCancelRequested() const; virtual void setCancelRequested(); public slots: void requestCancel(); signals: /* * Emitted when the range of progress is updated. * @param minimumProgress * New value for minimum. * @param maximumProgress * New value for maximum. */ void reportProgressRange(const int minimumProgress, const int maximumProgress); /** * Emitted when the progress value is updated. * @param progressValue * New value for progress. */ void reportProgressValue(const int progressValue); /** * Emitted when the progress message is updated. * @param progressMessage * New value for progress message. * * NOTE: This must use a QString (not AString) since * it connects to a Qt slot expecting a QString */ void reportProgressMessage(const QString& progressMessage); private: /** * Ensures each method is synchronized meaning that each of * the methods for updating complete blocks if any other * methods are in progress. */ mutable QMutex m_synchronizeMutex; bool m_cancelled; }; #ifdef __PROGRESS_REPORTING_WITH_SLOTS_DECLARE__ // #endif // __PROGRESS_REPORTING_WITH_SLOTS_DECLARE__ } // namespace #endif //__PROGRESS_REPORTING_WITH_SLOTS_H__ connectome-workbench-1.4.2/src/GuiQt/QGLWidgetTextRenderer.cxx000066400000000000000000001306701360521144700243310ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /* * QOpenGLWidget does not have renderText() methods. * renderText() methods are in deprecated QGLWidget. */ #ifndef WORKBENCH_USE_QT5_QOPENGL_WIDGET #define __QT_OPEN_G_L_TEXT_RENDERER_DECLARE__ #include "QGLWidgetTextRenderer.h" #undef __QT_OPEN_G_L_TEXT_RENDERER_DECLARE__ /* * When GLEW is used, CaretOpenGLInclude.h will include "Gl/glew.h". * Gl/glew.h MUST BE BEFORE Gl/gl.h and Gl/gl.h is included by * QGLWidget so, we must include CaretOpenGL.h before QGLWidget. */ #include "CaretOpenGLInclude.h" #include #include #include #include #include #include #include "AnnotationPointSizeText.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretOpenGLInclude.h" using namespace caret; /** * \class caret::QGLWidgetTextRenderer * \brief Draw text in OpenGL using Qt's GLWidget. * \ingroup GuiQt */ /** * Constructor. * * @param glWidget * Qt's GL Widget used for drawing text. */ QGLWidgetTextRenderer::QGLWidgetTextRenderer(QGLWidget* glWidget) : BrainOpenGLTextRenderInterface(), m_glWidget(glWidget) { m_defaultFont = NULL; AnnotationPointSizeText defaultAnnotationText(AnnotationAttributesDefaultTypeEnum::NORMAL); defaultAnnotationText.setFontPointSize(AnnotationTextFontPointSizeEnum::SIZE14); defaultAnnotationText.setFont(AnnotationTextFontNameEnum::VERA); defaultAnnotationText.setItalicStyleEnabled(false); defaultAnnotationText.setBoldStyleEnabled(false); defaultAnnotationText.setUnderlineStyleEnabled(false); m_defaultFont = findFont(defaultAnnotationText, true); } /** * Destructor. */ QGLWidgetTextRenderer::~QGLWidgetTextRenderer() { for (FONT_MAP_ITERATOR iter = m_fontNameToFontMap.begin(); iter != m_fontNameToFontMap.end(); iter++) { delete iter->second; } m_fontNameToFontMap.clear(); /* * Do not delete "m_defaultFont" since it points to a font * in m_fontNameToFontMap. Doing so would cause * a double delete. */ } /** * Draw annnotation text at the given viewport coordinates using * the the annotations attributes for the style of text. * * Depth testing is DISABLED when drawing text with this method. * * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. * @param annotationText * Annotation text and attributes. */ void QGLWidgetTextRenderer::drawTextAtViewportCoords(const double viewportX, const double viewportY, const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags) { setViewportHeight(); drawTextAtViewportCoords(viewportX, viewportY, 0.0, annotationText, flags); } /** * Draw annnotation text at the given viewport coordinates using * the the annotations attributes for the style of text. * * Depth testing is ENABLED when drawing text with this method. * * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. * @param annotationText * Annotation text and attributes. */ void QGLWidgetTextRenderer::drawTextAtViewportCoords(const double viewportX, const double viewportY, const double /*viewportZ */, const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags) { setViewportHeight(); GLdouble modelMatrix[16]; GLdouble projectionMatrix[16]; GLint viewport[4]; glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix); glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix); glGetIntegerv(GL_VIEWPORT, viewport); /* * Set the orthographic projection so that its origin is in the bottom * left corner. It needs to be there since we are drawing in window * coordinates. We do not know the true size of the window but that * is okay since we can set the orthographic view so that the bottom * left corner is the origin and the top right corner is the top * right corner of the user's viewport. */ glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0, (viewport[2]), 0, (viewport[3]), -1, 1); /* * Viewing projection is just the identity matrix since * we are drawing in window coordinates. */ glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); //std::cout << "Drawing \"" << qPrintable(text) << "\" at " << windowX << ", " << windowY << std::endl; if (annotationText.getText().isEmpty()) { return; } switch (annotationText.getOrientation()) { case AnnotationTextOrientationEnum::HORIZONTAL: drawHorizontalTextAtWindowCoords(viewportX, viewportY, annotationText, flags); break; case AnnotationTextOrientationEnum::STACKED: drawVerticalTextAtWindowCoords(viewportX, viewportY, annotationText, flags); break; } glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } /** * Draw annnotation text at the given model coordinates using * the the annotations attributes for the style of text. * Text is drawn so that is in the plane of the screen (faces user) * * Depth testing is ENABLED when drawing text with this method. * * @param modelX * Model X-coordinate. * @param modelY * Model Y-coordinate. * @param modelZ * Model Z-coordinate. * @param annotationText * Annotation text and attributes. * @param flags * Drawing flags. */ void QGLWidgetTextRenderer::drawTextAtModelCoordsFacingUser(const double modelX, const double modelY, const double modelZ, const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags) { setViewportHeight(); GLdouble modelMatrix[16]; GLdouble projectionMatrix[16]; GLint viewport[4]; glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix); glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix); glGetIntegerv(GL_VIEWPORT, viewport); /* * Project model coordinate to a window coordinate. */ GLdouble windowX, windowY, windowZ; if (gluProject(modelX, modelY, modelZ, modelMatrix, projectionMatrix, viewport, &windowX, &windowY, &windowZ) == GL_TRUE) { glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); // /* // * Set the orthographic projection so that its origin is in the bottom // * left corner. It needs to be there since we are drawing in window // * coordinates. We do not know the true size of the window but that // * is okay since we can set the orthographic view so that the bottom // * left corner is the origin and the top right corner is the top // * right corner of the user's viewport. // */ // glMatrixMode(GL_PROJECTION); // glPushMatrix(); // glLoadIdentity(); // glOrtho(0, // (viewport[2]), // 0, // (viewport[3]), // -1, // 1); // /* // * Viewing projection is just the identity matrix since // * we are drawing in window coordinates. // */ // glMatrixMode(GL_MODELVIEW); // glPushMatrix(); // glLoadIdentity(); // std::cout << "VP:" << AString::fromNumbers(viewport, 4, ",") // << " Window: " << windowX << ", " << windowY << std::endl; /* * Convert window coordinate to viewport coordinatde */ const double x = windowX - viewport[0]; const double y = windowY - viewport[1]; drawTextAtViewportCoords(x, y, 0.0, annotationText, flags); // glPopMatrix(); // glMatrixMode(GL_PROJECTION); // glPopMatrix(); // glMatrixMode(GL_MODELVIEW); } else { CaretLogSevere("gluProject() failed for drawing text at model coordinates."); } } /** * Draw text in model space using the current model transformations. * * Depth testing is ENABLED when drawing text with this method. * * @param annotationText * Annotation text and attributes. * @param modelSpaceScaling * Scaling in the model space. * @param heightOrWidthForPercentageSizeText * If positive, use it to override width/height of viewport. * @param normalVector * Normal vector of text. * @param flags * Drawing flags. */ void QGLWidgetTextRenderer::drawTextInModelSpace(const AnnotationText& /* annotationText */, const float /*modelSpaceScaling*/, const float /*heightOrWidthForPercentageSizeText*/, const float* /*normalVector[3]*/, const DrawingFlags& /* flags */) { CaretAssertMessage(0, "Not implemented"); } /** * Draw horizontal annotation text at the given window coordinates. * * @param viewport * The current viewport. * @param windowX * X-coordinate in the window of first text character * using the 'alignment' * @param windowY * Y-coordinate in the window at which bottom of text is placed. * @param annotationText * Annotation Text that is to be drawn. */ void QGLWidgetTextRenderer::drawHorizontalTextAtWindowCoords(const double windowX, const double windowY, const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags) { QFont* font = findFont(annotationText, false); if (! font) { return; } /* * Get the viewport */ GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); const bool drawCrosshairsAtFontStartingCoordinate = false; if (drawCrosshairsAtFontStartingCoordinate) { GLfloat savedRGBA[4]; glGetFloatv(GL_CURRENT_COLOR, savedRGBA); glColor3f(1.0, 0.0, 0.0); glLineWidth(1.0); glPushMatrix(); glTranslatef(windowX, windowY, 0.0); glBegin(GL_LINES); glVertex2i(-50, 0); glVertex2i( 50, 0); glVertex2i(0, -50); glVertex2i(0, 50); glEnd(); glPopMatrix(); glColor3f(savedRGBA[0], savedRGBA[1], savedRGBA[2]); } const AString text = annotationText.getText(); double bottomLeft[3], bottomRight[3], topRight[3], topLeft[3]; getBoundsForTextAtViewportCoords(annotationText, flags, windowX, windowY, 0.0, viewport[2], viewport[3], bottomLeft, bottomRight, topRight, topLeft); double left = bottomLeft[0]; double right = bottomRight[0]; double bottom = bottomLeft[1]; double top = topLeft[1]; // getTextBoundsInPixels(annotationText, // left, // right, // bottom, // top); double textOffsetX = 0; switch (annotationText.getHorizontalAlignment()) { case AnnotationTextAlignHorizontalEnum::CENTER: textOffsetX = -((right - left) / 2.0); break; case AnnotationTextAlignHorizontalEnum::LEFT: textOffsetX = -left; break; case AnnotationTextAlignHorizontalEnum::RIGHT: textOffsetX = -right; break; } double textOffsetY = 0; // switch (annotationText.getVerticalAlignment()) { // case AnnotationTextAlignVerticalEnum::BOTTOM: // textOffsetY = 0.0; //-bottom; // break; // case AnnotationTextAlignVerticalEnum::CENTER: // textOffsetY = ((top - bottom) / 2.0); // break; // case AnnotationTextAlignVerticalEnum::TOP: // textOffsetY = top; // break; // } switch (annotationText.getVerticalAlignment()) { case AnnotationTextAlignVerticalEnum::BOTTOM: textOffsetY = -bottom; break; case AnnotationTextAlignVerticalEnum::MIDDLE: textOffsetY = -((top - bottom) / 2.0); break; case AnnotationTextAlignVerticalEnum::TOP: textOffsetY = -top; break; } // /* // * Qt seems to place coordinate at TOP of text // */ // const double height = top - bottom; // if (height > 0.0) { // const double oneCharHeight = (height / text.length()); // textOffsetY -= oneCharHeight; // } double textX = windowX + textOffsetX; double textY = windowY + textOffsetY; if (drawCrosshairsAtFontStartingCoordinate) { std::cout << "BBox: (" << left << " " << bottom << ") (" << right << ", " << top << ")" << std::endl; // const float width = right - left; // const float height = top - bottom; // // GLfloat savedRGBA[4]; // glGetFloatv(GL_CURRENT_COLOR, savedRGBA); // glColor3f(1.0, 0.0, 1.0); // glLineWidth(1.0); // glPushMatrix(); // glRectf(textX, textY, textX + width, textY + height); // glPopMatrix(); // glColor3f(savedRGBA[0], savedRGBA[1], savedRGBA[2]); } const double backgroundBounds[4] = { textX, textY, textX + (right - left), textY + (top - bottom) }; glPushMatrix(); //glLoadIdentity(); applyBackgroundColoring(annotationText, backgroundBounds); applyForegroundColoring(annotationText); glPopMatrix(); /* * Qt places origin at TOP LEFT */ // const int qtWindowX = textX + viewport[0]; // const int qtWindowY = m_glWidget->height() - textY + viewport[1]; const int qtWindowX = textX + viewport[0]; const int qtWindowY = m_glWidget->height() - textY - viewport[1]; if (drawCrosshairsAtFontStartingCoordinate) { std::cout << "Drawing " << qPrintable(text) << " at XY: " << textX << ", " << textY << " qtXY=" << qtWindowX << ", " << qtWindowY << " windowXY=" << windowX << ", " << windowY << std::endl; GLdouble modelMatrix[16]; GLdouble projectionMatrix[16]; GLint viewport[4]; glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix); glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix); glGetIntegerv(GL_VIEWPORT, viewport); std::cout << std::endl; std::cout << "Drawing Text: " << qPrintable(annotationText.getText()) << std::endl; std::cout << " Model Matrix: " << AString::fromNumbers(modelMatrix, 16, ",") << std::endl; std::cout << " Proj Matrix: " << AString::fromNumbers(projectionMatrix, 16, ",") << std::endl; std::cout << " Viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; std::cout << std::endl; } m_glWidget->renderText(qtWindowX, qtWindowY, text, *font); } /** * Draw vertical text at the given window coordinates. * * @param windowX * X-coordinate in the window of first text character * using the 'alignment' * @param windowY * Y-coordinate in the window at which bottom of text is placed. * @param annotationText * Text that is to be drawn. */ void QGLWidgetTextRenderer::drawVerticalTextAtWindowCoords(const double windowX, const double windowY, const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags) { QFont* font = findFont(annotationText, false); if ( ! font) { return; } /* * Get the viewport */ GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); bool drawCrosshairsAtFontStartingCoordinate = false; if (drawCrosshairsAtFontStartingCoordinate) { GLfloat savedRGBA[4]; glGetFloatv(GL_CURRENT_COLOR, savedRGBA); glColor3f(1.0, 0.0, 1.0); glLineWidth(1.0); glPushMatrix(); //glTranslatef(windowX, windowY, 0.0); const double yStart = windowY - 50.0; const double yEnd = windowY + 50.0; glBegin(GL_LINES); glVertex2d(windowX, yStart); glVertex2d(windowX, yEnd); glVertex2d(-50.0, windowY); glVertex2d( 50.0, windowY); glEnd(); glPopMatrix(); glColor3f(savedRGBA[0], savedRGBA[1], savedRGBA[2]); } double textMinX = 0.0; double textMaxX = 0.0; double textHeight = 0.0; std::vector textCharsToDraw; getVerticalTextCharInfo(annotationText, flags, textMinX, textMaxX, textHeight, textCharsToDraw); const double textBoundsWidth = textMaxX - textMinX; const double textBoundsHeight = textHeight; double textOffsetX = 0; switch (annotationText.getHorizontalAlignment()) { case AnnotationTextAlignHorizontalEnum::CENTER: textOffsetX = -((textMaxX - textMinX) / 2.0); textOffsetX = 0.0; break; case AnnotationTextAlignHorizontalEnum::LEFT: textOffsetX = -textMinX; textOffsetX = (textBoundsWidth / 2.0); break; case AnnotationTextAlignHorizontalEnum::RIGHT: textOffsetX = -textMaxX; textOffsetX = -(textBoundsWidth / 2.0); break; } /* * The character coordinates are set so that the top of the first * will be at Y=0. */ double textOffsetY = 0.0; double textBackgroundTopOffsetY = 0.0; switch (annotationText.getVerticalAlignment()) { case AnnotationTextAlignVerticalEnum::BOTTOM: textOffsetY = textHeight; textBackgroundTopOffsetY = textHeight; break; case AnnotationTextAlignVerticalEnum::MIDDLE: textOffsetY = (textHeight / 2.0); textBackgroundTopOffsetY = (textHeight / 2.0); break; case AnnotationTextAlignVerticalEnum::TOP: textOffsetY = 0.0; textBackgroundTopOffsetY = 0.0; break; } const double backMinX = windowX - (textBoundsWidth / 2.0) + textOffsetX; const double backMaxX = backMinX + textBoundsWidth; const double backMaxY = windowY + textBackgroundTopOffsetY; const double backMinY = backMaxY - textBoundsHeight; const double backgroundBounds[4] = { backMinX, backMinY, backMaxX, backMaxY }; applyBackgroundColoring(annotationText, backgroundBounds); applyForegroundColoring(annotationText); for (std::vector::const_iterator textIter = textCharsToDraw.begin(); textIter != textCharsToDraw.end(); textIter++) { const double charX = windowX + textIter->m_x + textOffsetX; const double charY = windowY + textIter->m_y + textOffsetY; const int qtWindowX = charX + viewport[0]; const int qtWindowY = m_glWidget->height() - charY - viewport[1]; m_glWidget->renderText(qtWindowX, qtWindowY, textIter->m_char, *font); } } /** * Apply the background coloring by drawing a rectangle in the background * color that encloses the text. If the background color is * invalid (alpha => 0), no action is taken. * * @param annotationText * Annotation Text that is to be drawn. * @param textBoundsBox * Bounding box for text (min-x, min-y, max-x, max-y) */ void QGLWidgetTextRenderer::applyBackgroundColoring(const AnnotationText& annotationText, const double textBoundsBox[4]) { // GLdouble modelMatrix[16]; // GLdouble projectionMatrix[16]; // GLint viewport[4]; // // glGetDoublev(GL_MODELVIEW_MATRIX, // modelMatrix); // glGetDoublev(GL_PROJECTION_MATRIX, // projectionMatrix); // glGetIntegerv(GL_VIEWPORT, // viewport); // // std::cout << std::endl; // std::cout << "Background for: " << qPrintable(annotationText.getText()) << std::endl; // std::cout << " Rectangle: " << AString::fromNumbers(textBoundsBox, 4, ",") << std::endl; // std::cout << " Model Matrix: " << AString::fromNumbers(modelMatrix, 16, ",") << std::endl; // std::cout << " Proj Matrix: " << AString::fromNumbers(projectionMatrix, 16, ",") << std::endl; // std::cout << " Viewport: " << AString::fromNumbers(viewport, 4, ",") << std::endl; // std::cout << std::endl; float backgroundColor[4]; annotationText.getBackgroundColorRGBA(backgroundColor); if (backgroundColor[3] > 0.0) { glColor4fv(backgroundColor); const double margin = s_textMarginSize * 2; glRectd(textBoundsBox[0] - margin, textBoundsBox[1] - margin, textBoundsBox[2] + margin, textBoundsBox[3] + margin); } } /** * Apply the foreground color. * * @param annotationText * Annotation Text that is to be drawn. * @param textBoundsBox * Bounding box for text (min-x, min-y, max-x, max-y) */ void QGLWidgetTextRenderer::applyForegroundColoring(const AnnotationText& annotationText) { float rgba[4]; annotationText.getLineColorRGBA(rgba); glColor4fv(rgba); } /** * Get the estimated width and height of text (in pixels) using the given text * attributes. * * See http://ftgl.sourceforge.net/docs/html/metrics.png * * @param annotationText * Text for width and height estimation. * @param viewportWidth * Height of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param widthOut * Estimated width of text. * @param heightOut * Estimated height of text. */ void QGLWidgetTextRenderer::getTextWidthHeightInPixels(const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags, const double viewportWidth, const double viewportHeight, double& widthOut, double& heightOut) { setViewportHeight(); double xMin = 0.0; double xMax = 0.0; double yMin = 0.0; double yMax = 0.0; double bottomLeft[3], bottomRight[3], topRight[3], topLeft[3]; getBoundsForTextAtViewportCoords(annotationText, flags, 0.0, 0.0, 0.0, viewportWidth, viewportHeight, bottomLeft, bottomRight, topRight, topLeft); widthOut = xMax - xMin; heightOut = yMax - yMin; } /** * Get the bounds of text drawn in model space using the current model transformations. * * @param annotationText * Text that is to be drawn. * @param modelSpaceScaling * Scaling in the model space. * @param heightOrWidthForPercentageSizeText * Size of region used when converting percentage size to a fixed size * @param flags * Drawing flags. * @param bottomLeftOut * The bottom left corner of the text bounds. * @param bottomRightOut * The bottom right corner of the text bounds. * @param topRightOut * The top right corner of the text bounds. * @param topLeftOut * The top left corner of the text bounds. * @param underlineStartOut * Starting coordinate for drawing text underline. * @param underlineEndOut * Ending coordinate for drawing text underline. */ void QGLWidgetTextRenderer::getBoundsForTextInModelSpace(const AnnotationText& /*annotationText*/, const float /*modelSpaceScaling*/, const float /*heightOrWidthForPercentageSizeText*/, const DrawingFlags& /*flags*/, double* /*bottomLeftOut[3]*/, double* /*bottomRightOut[3]*/, double* /*topRightOut[3]*/, double* /*topLeftOut[3]*/, double* /*underlineStartOut[3]*/, double* /*underlineEndOut[3]*/) { } /** * Get the bounds of text (in pixels) using the given text * attributes. * * See http://ftgl.sourceforge.net/docs/html/metrics.png * * @param annotationText * Text that is to be drawn. * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. * @param viewportWidth * Height of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param bottomLeftOut * The bottom left corner of the text bounds. * @param bottomRightOut * The bottom right corner of the text bounds. * @param topRightOut * The top right corner of the text bounds. * @param topLeftOut * The top left corner of the text bounds. */ void QGLWidgetTextRenderer::getBoundsForTextAtViewportCoords(const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags, const double viewportX, const double viewportY, const double viewportZ, const double /*viewportWidth*/, const double /*viewportHeight*/, double bottomLeftOut[3], double bottomRightOut[3], double topRightOut[3], double topLeftOut[3]) { setViewportHeight(); QFont* font = findFont(annotationText, false); if (font == NULL) { return; } double xMin = 0.0; double xMax = 0.0; double yMin = 0.0; double yMax = 0.0; switch (annotationText.getOrientation()) { case AnnotationTextOrientationEnum::HORIZONTAL: { QFontMetricsF fontMetrics(*font); QRectF boundsRect = fontMetrics.boundingRect(annotationText.getText()); /* * Note: sometimes boundsRect.top() is negative and * that screws things up. */ xMin = boundsRect.left(); xMax = boundsRect.right(); yMin = boundsRect.bottom(); yMax = boundsRect.bottom() + boundsRect.height(); } break; case AnnotationTextOrientationEnum::STACKED: { double textHeight = 0.0; std::vector charInfo; getVerticalTextCharInfo(annotationText, flags, xMin, xMax, textHeight, charInfo); yMax = textHeight; } break; } const double width = xMax - xMin; double left = 0.0; switch (annotationText.getHorizontalAlignment()) { case AnnotationTextAlignHorizontalEnum::LEFT: left = viewportX; break; case AnnotationTextAlignHorizontalEnum::CENTER: left = viewportX - (width / 2.0); break; case AnnotationTextAlignHorizontalEnum::RIGHT: left = viewportX - width; break; } const double right = left + width; const double height = yMax - yMin; double bottom = 0.0; switch (annotationText.getVerticalAlignment()) { case AnnotationTextAlignVerticalEnum::BOTTOM: bottom = viewportY; break; case AnnotationTextAlignVerticalEnum::MIDDLE: bottom = viewportY - (height / 2.0); break; case AnnotationTextAlignVerticalEnum::TOP: bottom = viewportY - height; break; } const double top = bottom + height; bottomLeftOut[0] = left; bottomLeftOut[1] = bottom; bottomLeftOut[2] = viewportZ; bottomRightOut[0] = right; bottomRightOut[0] = bottom; bottomRightOut[0] = viewportZ; topRightOut[0] = right; topRightOut[0] = top; topRightOut[0] = viewportZ; topLeftOut[0] = left; topLeftOut[0] = top; topLeftOut[0] = viewportZ; } /** * Get the bounds of text (in pixels) using the given text * attributes. NO MARGIN is placed around the text. * * See http://ftgl.sourceforge.net/docs/html/metrics.png * * @param annotationText * Text that is to be drawn. * @param viewportX * Viewport X-coordinate. * @param viewportY * Viewport Y-coordinate. * @param viewportZ * Viewport Z-coordinate. * @param viewportWidth * Height of the viewport needed for percentage height text. * @param viewportHeight * Height of the viewport needed for percentage height text. * @param bottomLeftOut * The bottom left corner of the text bounds. * @param bottomRightOut * The bottom right corner of the text bounds. * @param topRightOut * The top right corner of the text bounds. * @param topLeftOut * The top left corner of the text bounds. */ void QGLWidgetTextRenderer::getBoundsWithoutMarginForTextAtViewportCoords(const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags, const double viewportX, const double viewportY, const double viewportZ, const double /*viewportWidth*/, const double /*viewportHeight*/, double bottomLeftOut[3], double bottomRightOut[3], double topRightOut[3], double topLeftOut[3]) { setViewportHeight(); QFont* font = findFont(annotationText, false); if (font == NULL) { return; } double xMin = 0.0; double xMax = 0.0; double yMin = 0.0; double yMax = 0.0; switch (annotationText.getOrientation()) { case AnnotationTextOrientationEnum::HORIZONTAL: { QFontMetricsF fontMetrics(*font); QRectF boundsRect = fontMetrics.boundingRect(annotationText.getText()); /* * Note: sometimes boundsRect.top() is negative and * that screws things up. */ xMin = boundsRect.left(); xMax = boundsRect.right(); yMin = boundsRect.bottom(); yMax = boundsRect.bottom() + boundsRect.height(); } break; case AnnotationTextOrientationEnum::STACKED: { double textHeight = 0.0; std::vector charInfo; getVerticalTextCharInfo(annotationText, flags, xMin, xMax, textHeight, charInfo); yMax = textHeight; } break; } const double width = xMax - xMin; double left = 0.0; switch (annotationText.getHorizontalAlignment()) { case AnnotationTextAlignHorizontalEnum::LEFT: left = viewportX; break; case AnnotationTextAlignHorizontalEnum::CENTER: left = viewportX - (width / 2.0); break; case AnnotationTextAlignHorizontalEnum::RIGHT: left = viewportX - width; break; } const double right = left + width; const double height = yMax - yMin; double bottom = 0.0; switch (annotationText.getVerticalAlignment()) { case AnnotationTextAlignVerticalEnum::BOTTOM: bottom = viewportY; break; case AnnotationTextAlignVerticalEnum::MIDDLE: bottom = viewportY - (height / 2.0); break; case AnnotationTextAlignVerticalEnum::TOP: bottom = viewportY - height; break; } const double top = bottom + height; bottomLeftOut[0] = left; bottomLeftOut[1] = bottom; bottomLeftOut[2] = viewportZ; bottomRightOut[0] = right; bottomRightOut[0] = bottom; bottomRightOut[0] = viewportZ; topRightOut[0] = right; topRightOut[0] = top; topRightOut[0] = viewportZ; topLeftOut[0] = left; topLeftOut[0] = top; topLeftOut[0] = viewportZ; } /** * Get the character info for drawing vertical text which includes * position for each of the characters. The TOP of the first * character will be at Y=0. * * @param annotationText * Text that is to be drawn. * @param xMinOut * Minimum X of text. * @param xMaxOut * Maximum X of text. * @param heightOut * Total height of text. * @param charInfoOut * Contains each character and its X, Y position * for rendering vertically. */ void QGLWidgetTextRenderer::getVerticalTextCharInfo(const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags, double& xMinOut, double& xMaxOut, double& heightOut, std::vector& charInfoOut) { charInfoOut.clear(); xMinOut = 0.0; xMaxOut = 0.0; heightOut = 0.0; const AString text = (flags.isDrawSubstitutedText() ? annotationText.getTextWithSubstitutionsApplied() : annotationText.getText()); const int32_t numChars = static_cast(text.size()); if (numChars <= 0) { return; } QFont* font = findFont(annotationText, false); if ( ! font) { return; } xMinOut = std::numeric_limits::max(); xMaxOut = -std::numeric_limits::max(); double y = 0.0; const int32_t lastCharIndex = numChars - 1; for (int32_t i = 0; i < numChars; i++) { const QString oneChar = text[i]; QFontMetricsF fontMetrics(*font); QRectF boundsRect = fontMetrics.boundingRect(oneChar); /* * Note: sometimes boundsRect.top() is negative and * that screws things up. */ const double lowerX = boundsRect.left(); const double upperX = boundsRect.right(); const double lowerY = boundsRect.bottom(); const double upperY = boundsRect.bottom() + boundsRect.height(); const double width = upperX - lowerX; xMinOut = std::min(xMinOut, lowerX); xMaxOut = std::max(xMaxOut, upperX); /* * Center the character horizontally. */ const double xChar = -lowerX - (width / 2.0); /* * Want the top of character at the Y-coordinate. */ const double yChar = y - upperY; charInfoOut.push_back(CharInfo(oneChar, xChar, yChar)); const double height = upperY - lowerY; if (i == lastCharIndex) { y -= height; } else { const double heightWithSpacing = height + s_textMarginSize; y -= heightWithSpacing; } } heightOut = std::fabs(y); } /** * Set the height of the viewport. This method must be called * at the beginning of all public methods. */ void QGLWidgetTextRenderer::setViewportHeight() { GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); m_viewportWidth = viewport[2]; m_viewportHeight = viewport[3]; } /** * Find a font with the given name, height, and style. * Once a font is created it is cached so that it can be * used again and avoids font creation which may be * expensive. * * @return a font */ QFont* QGLWidgetTextRenderer::findFont(const AnnotationText& annotationText, const bool creatingDefaultFontFlag) { const AString fontName = annotationText.getFontRenderingEncodedName(m_viewportWidth, m_viewportHeight); /* * Has the font already has been created? */ FONT_MAP_ITERATOR fontIter = m_fontNameToFontMap.find(fontName); if (fontIter != m_fontNameToFontMap.end()) { FontData* fontData = fontIter->second; CaretAssert(fontData); return fontData->m_font; } /* * Create and save the font */ FontData* fontData = new FontData(annotationText, m_viewportWidth, m_viewportHeight); if (fontData->m_valid) { /* * Request font is valid. */ m_fontNameToFontMap.insert(std::make_pair(fontName, fontData)); CaretLogFine("Created font with encoded name " + fontName); return fontData->m_font; } else { /* * Error creating font */ delete fontData; fontData = NULL; /* * Issue a message about failure to create font but * don't print same message more than once. */ if (std::find(m_failedFontNames.begin(), m_failedFontNames.end(), fontName) == m_failedFontNames.end()) { m_failedFontNames.insert(fontName); CaretLogSevere("Failed to create font with encoded name " + fontName); } } /* * Were we trying to create the default font? */ if (creatingDefaultFontFlag) { return NULL; } /* * Failed so use the default font. */ return m_defaultFont; } /** * @return The font system is valid. */ bool QGLWidgetTextRenderer::isValid() const { return true; } /** * @return Name of the text renderer. */ AString QGLWidgetTextRenderer::getName() const { return AString("Qt OpenGL Text Renderer"); } /** * Constructs invalid font data. */ QGLWidgetTextRenderer::FontData::FontData() { m_valid = false; m_font = NULL; } /** * Constructs a font with the given attributes. * Called should verify that this instance is valid (construction was successful). * * @param annotationText * Annotation Text that is to be drawn. * @param viewportHeight * Height of viewport. */ QGLWidgetTextRenderer::FontData::FontData(const AnnotationText& annotationText, const int32_t viewportWidth, const int32_t viewportHeight) { m_valid = false; m_font = NULL; const AnnotationTextFontNameEnum::Enum fontEnumName = annotationText.getFont(); AString fontFileName = AnnotationTextFontNameEnum::getResourceFontFileName(fontEnumName); if (annotationText.isBoldStyleEnabled() && annotationText.isItalicStyleEnabled()) { fontFileName = AnnotationTextFontNameEnum::getResourceBoldItalicFontFileName(fontEnumName); } else if (annotationText.isBoldStyleEnabled()) { fontFileName = AnnotationTextFontNameEnum::getResourceBoldFontFileName(fontEnumName); } else if (annotationText.isItalicStyleEnabled()) { fontFileName = AnnotationTextFontNameEnum::getResourceItalicFontFileName(fontEnumName); } switch (fontEnumName) { case AnnotationTextFontNameEnum::LIBERTINE: case AnnotationTextFontNameEnum::VERA: fontFileName = "Helvetica"; break; case AnnotationTextFontNameEnum::VERA_MONOSPACE: fontFileName = "Monaco"; break; } CaretAssert( ! fontFileName.isEmpty()); const QString fontName = AnnotationTextFontNameEnum::toGuiName(fontEnumName); m_font = new QFont(fontName); CaretAssert(m_font); const int32_t fontSizePoints = annotationText.getFontSizeForDrawing(viewportWidth, viewportHeight); m_font->setPointSize(fontSizePoints); m_font->setBold(annotationText.isBoldStyleEnabled()); m_font->setItalic(annotationText.isItalicStyleEnabled()); m_font->setUnderline(annotationText.isUnderlineStyleEnabled()); m_valid = true; QFontInfo fontInfo(*m_font); CaretLogWarning("Requested font \"" + fontName + "\" and actual font is \"" + fontInfo.family() + " exact match=" + AString::fromBool(m_font->exactMatch())); if ( ! m_valid) { if (m_font != NULL) { delete m_font; m_font = NULL; } } } /** * Destructs font data. */ QGLWidgetTextRenderer::FontData::~FontData() { if (m_font != NULL) { delete m_font; m_font = NULL; } } #endif // not - WORKBENCH_USE_QT5_QOPENGL_WIDGET connectome-workbench-1.4.2/src/GuiQt/QGLWidgetTextRenderer.h000066400000000000000000000235261360521144700237570ustar00rootroot00000000000000#ifndef __QGLWIDGET_TEXT_RENDERER_H__ #define __QGLWIDGET_TEXT_RENDERER_H__ /* * QOpenGLWidget does not have renderText() methods. * renderText() methods are in deprecated QGLWidget. */ #ifndef WORKBENCH_USE_QT5_QOPENGL_WIDGET /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "BrainOpenGLTextRenderInterface.h" class QFont; class QGLWidget; namespace caret { class QGLWidgetTextRenderer : public BrainOpenGLTextRenderInterface { public: QGLWidgetTextRenderer(QGLWidget* glWidget); virtual ~QGLWidgetTextRenderer(); virtual void drawTextAtViewportCoords(const double viewportX, const double viewportY, const double viewportZ, const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags) override; virtual void drawTextAtViewportCoords(const double viewportX, const double viewportY, const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags) override; virtual void drawTextAtModelCoordsFacingUser(const double modelX, const double modelY, const double modelZ, const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags) override; virtual void drawTextInModelSpace(const AnnotationText& annotationText, const float modelSpaceScaling, const float heightOrWidthForPercentageSizeText, const float normalVector[3], const DrawingFlags& flags) override; virtual void getTextWidthHeightInPixels(const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags, const double viewportWidth, const double viewportHeight, double& widthOut, double& heightOut) override; virtual void getBoundsForTextInModelSpace(const AnnotationText& annotationText, const float modelSpaceScaling, const float heightOrWidthForPercentageSizeText, const DrawingFlags& flags, double bottomLeftOut[3], double bottomRightOut[3], double topRightOut[3], double topLeftOut[3], double underlineStartOut[3], double underlineEndOut[3]) override; virtual void getBoundsForTextAtViewportCoords(const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags, const double viewportX, const double viewportY, const double viewportZ, const double viewportWidth, const double viewportHeight, double bottomLeftOut[3], double bottomRightOut[3], double topRightOut[3], double topLeftOut[3]) override; virtual void getBoundsWithoutMarginForTextAtViewportCoords(const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags, const double viewportX, const double viewportY, const double viewportZ, const double viewportWidth, const double viewportHeight, double bottomLeftOut[3], double bottomRightOut[3], double topRightOut[3], double topLeftOut[3]) override; virtual bool isValid() const; virtual AString getName() const; // ADD_NEW_METHODS_HERE private: class FontData { public: FontData(); FontData(const AnnotationText& annotationText, const int32_t viewportWidth, const int32_t viewportHeight); ~FontData(); void initialize(const AString& fontFileName); QFont* m_font; bool m_valid; }; struct CharInfo { CharInfo(const QString& theChar, double x, double y) : m_char(theChar), m_x(x), m_y(y) { } QString m_char; double m_x; double m_y; }; QGLWidgetTextRenderer(const QGLWidgetTextRenderer&); QGLWidgetTextRenderer& operator=(const QGLWidgetTextRenderer&); QFont* findFont(const AnnotationText& annotationText, const bool creatingDefaultFontFlag); void getVerticalTextCharInfo(const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags, double& xMinOut, double& xMaxOut, double& heightOut, std::vector& charInfoOut); void drawHorizontalTextAtWindowCoords(const double windowX, const double windowY, const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags); void drawVerticalTextAtWindowCoords(const double windowX, const double windowY, const AnnotationText& annotationText, const BrainOpenGLTextRenderInterface::DrawingFlags& flags); void applyForegroundColoring(const AnnotationText& annotationText); void applyBackgroundColoring(const AnnotationText& annotationText, const double textBoundsBox[4]); void setViewportHeight(); QGLWidget* m_glWidget; /** * The default font. DO NOT delete it since it points to * a font in "m_fontNameToFontMap". */ QFont* m_defaultFont; /** * Map for caching font */ typedef std::map FONT_MAP; /** * Iterator for cached fonts. */ typedef FONT_MAP::iterator FONT_MAP_ITERATOR; /** * Caches fonts as they are created */ FONT_MAP m_fontNameToFontMap; /** * Tracks fonts that failed creation to avoid * printing an error message more than once. */ std::set m_failedFontNames; /** Height of the viewport */ int32_t m_viewportHeight; /** Width of the viewport */ int32_t m_viewportWidth; // ADD_NEW_MEMBERS_HERE static const double s_textMarginSize; }; #ifdef __QT_OPEN_G_L_TEXT_RENDERER_DECLARE__ const double QGLWidgetTextRenderer::s_textMarginSize = 2.0; #endif // __QT_OPEN_G_L_TEXT_RENDERER_DECLARE__ } // namespace #endif // not - WORKBENCH_USE_QT5_QOPENGL_WIDGET #endif //__QT_OPEN_G_L_TEXT_RENDERER_H__ connectome-workbench-1.4.2/src/GuiQt/RegionOfInterestCreateFromBorderDialog.cxx000066400000000000000000000534611360521144700276640ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __REGION_OF_INTEREST_CREATE_FROM_BORDER_DIALOG_DECLARE__ #include "RegionOfInterestCreateFromBorderDialog.h" #undef __REGION_OF_INTEREST_CREATE_FROM_BORDER_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include using namespace caret; #include "AlgorithmException.h" #include "AlgorithmNodesInsideBorder.h" #include "Border.h" #include "BorderFile.h" #include "Brain.h" #include "BrainStructure.h" #include "CaretAssert.h" #include "CaretMappableDataFileAndMapSelector.h" #include "CiftiBrainordinateLabelFile.h" #include "CiftiBrainordinateScalarFile.h" #include "CursorDisplayScoped.h" #include "EventDataFileAdd.h" #include "EventManager.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "LabelFile.h" #include "MetricFile.h" #include "Surface.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" /** * \class caret::RegionOfInterestCreateFromBorderDialog * \brief Dailog for creating regions of interest from border(s). * \ingroup GuiQt * * Dialog that creates regions of interest from nodes inside * borders. */ /** * Constructor. * * @param border * Border used to create region of interest. * @param surface * Surface on which border is drawn and whose nodes are selected. * @param parent * Parent on which dialog is displayed. * */ RegionOfInterestCreateFromBorderDialog::RegionOfInterestCreateFromBorderDialog(Border* border, Surface* surface, QWidget* parent) : WuQDialogModal("Create Region of Interest", parent) { std::vector borders; borders.push_back(border); std::vector surfaces; surfaces.push_back(surface); this->createDialog(borders, surfaces); } /** * Destructor. */ RegionOfInterestCreateFromBorderDialog::~RegionOfInterestCreateFromBorderDialog() { } /** * Create the dialog. * * @param borders * Borders used to create regions of interest. * @param surfaceFiles * Surface files used for node selections. */ void RegionOfInterestCreateFromBorderDialog::createDialog(const std::vector& borders, std::vector& surfaces) { this->borders = borders; this->surfaces = surfaces; std::set requiredStructures; const int32_t numberOfBorders = static_cast(borders.size()); for (int32_t i = 0; i < numberOfBorders; i++) { const StructureEnum::Enum structure = borders[i]->getStructure(); requiredStructures.insert(structure); } QWidget* selectorWidget = this->createSelectors(requiredStructures, this->surfaces, this->mapFileTypeSelectors); this->inverseCheckBox = new QCheckBox("Invert Selected Vertices"); QWidget* widget = new QWidget(); QVBoxLayout* dialogLayout = new QVBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(dialogLayout, 2, 2); dialogLayout->addWidget(selectorWidget); dialogLayout->addWidget(this->inverseCheckBox, 0, Qt::AlignLeft); this->setCentralWidget(widget, WuQDialog::SCROLL_AREA_NEVER); } /** * Create map files selectors for a map file type. * * @param mapFileType * Type of map file for selector. * @param requiredStructures * Structures needed. * @param surfaces * Surfaces available. * @param mapFileSelectors * Output containing the selectors. * @return Widget containing the map selector controls. */ QWidget* RegionOfInterestCreateFromBorderDialog::createSelectors(std::set& requiredStructures, std::vector& surfaces, STRUCTURE_MAP_FILE_SELECTOR_MAP& mapFileSelectors) { AString borderName; if (this->borders.empty() == false) { borderName = this->borders[0]->getName(); } QWidget* widget = new QWidget(); QVBoxLayout* mapSelectionLayout = new QVBoxLayout(widget); std::vector allowedMapFileTypes; allowedMapFileTypes.push_back(DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL); allowedMapFileTypes.push_back(DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR); allowedMapFileTypes.push_back(DataFileTypeEnum::LABEL); allowedMapFileTypes.push_back(DataFileTypeEnum::METRIC); for (std::set::iterator structureIter = requiredStructures.begin(); structureIter != requiredStructures.end(); structureIter++) { const StructureEnum::Enum structure = *structureIter; for (std::vector::iterator surfaceIter = this->surfaces.begin(); surfaceIter != surfaces.end(); surfaceIter++) { Surface* surface = *surfaceIter; if (surface->getStructure() == structure) { std::vector allowedStructures; allowedStructures.push_back(surface->getStructure()); CaretMappableDataFileAndMapSelector* mapSelector = new CaretMappableDataFileAndMapSelector(borderName, GuiManager::get()->getBrain(), allowedMapFileTypes, allowedStructures, this); QObject::connect(mapSelector, SIGNAL(selectionChanged(CaretMappableDataFileAndMapSelector*)), this, SLOT(fileSelectionWasChanged(CaretMappableDataFileAndMapSelector*))); mapSelectionLayout->addWidget(mapSelector->getWidget()); mapFileSelectors.insert(std::make_pair(structure, mapSelector)); } } } return widget; } /** * Called when a map type/file/name is selected. * @param selector * Selector in which selection was made. */ void RegionOfInterestCreateFromBorderDialog::fileSelectionWasChanged(CaretMappableDataFileAndMapSelector* /*selector*/) { // std::cout << "Selection changed. " << std::endl; } /** * Called when the user presses the OK button. */ void RegionOfInterestCreateFromBorderDialog::okButtonClicked() { AString errorMessage; for (STRUCTURE_MAP_FILE_SELECTOR_ITERATOR iter = this->mapFileTypeSelectors.begin(); iter != this->mapFileTypeSelectors.end(); iter++) { //const StructureEnum::Enum structure = iter->first; CaretMappableDataFileAndMapSelector* mapSelector = iter->second; AString msg; if (mapSelector->isValidSelections(msg) == false) { if (errorMessage.isEmpty() == false) { errorMessage += "\n"; } errorMessage += msg; } } BorderFile* debugBorderFile = NULL; const bool isInverseSelection = this->inverseCheckBox->isChecked(); bool allowDialogToClose = true; if (errorMessage.isEmpty() == false) { allowDialogToClose = false; } else { /* * Show the wait cursor. */ CursorDisplayScoped cursor; cursor.showWaitCursor(); for (std::vector::iterator borderIterator = this->borders.begin(); borderIterator != this->borders.end(); borderIterator++) { Border* border = *borderIterator; const StructureEnum::Enum structure = border->getStructure(); STRUCTURE_MAP_FILE_SELECTOR_ITERATOR structureMapIterator = this->mapFileTypeSelectors.find(structure); if (structureMapIterator != this->mapFileTypeSelectors.end()) { const StructureEnum::Enum structure = structureMapIterator->first; CaretMappableDataFileAndMapSelector* mapSelector = structureMapIterator->second; mapSelector->saveCurrentSelections(); // save for next time switch (mapSelector->getSelectedMapFileType()) { case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: { AString errorMessage; CiftiBrainordinateLabelFile* ciftiLabelFile = dynamic_cast(mapSelector->getSelectedMapFile()); CaretAssert(ciftiLabelFile); const int32_t mapIndex = mapSelector->getSelectedMapIndex(); const int32_t labelKey = mapSelector->getSelectedLabelKey(); Surface* surface = NULL; for (std::vector::iterator surfaceIterator = this->surfaces.begin(); surfaceIterator != this->surfaces.end(); surfaceIterator++) { Surface* s = *surfaceIterator; if (s->getStructure() == structure) { surface = s; break; } } CaretAssert(surface); if (surface != NULL) { try { AlgorithmNodesInsideBorder algorithmInsideBorder(NULL, surface, border, isInverseSelection, mapIndex, labelKey, ciftiLabelFile); const BorderFile* dbf = algorithmInsideBorder.getDebugBorderFile(); if (dbf != NULL) { debugBorderFile = new BorderFile(*dbf); } } catch (const AlgorithmException& e) { if (errorMessage.isEmpty() == false) { errorMessage += "\n"; } errorMessage += e.whatString(); } } else { if (errorMessage.isEmpty() == false) { errorMessage += "\n"; } errorMessage += ("Surface for structure " + StructureEnum::toGuiName(structure) + " was not found"); } } break; case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: { AString errorMessage; CiftiBrainordinateScalarFile* ciftiScalarFile = dynamic_cast(mapSelector->getSelectedMapFile()); CaretAssert(ciftiScalarFile); const int32_t mapIndex = mapSelector->getSelectedMapIndex(); const float value = mapSelector->getSelectedMetricValue(); Surface* surface = NULL; for (std::vector::iterator surfaceIterator = this->surfaces.begin(); surfaceIterator != this->surfaces.end(); surfaceIterator++) { Surface* s = *surfaceIterator; if (s->getStructure() == structure) { surface = s; break; } } CaretAssert(surface); if (surface != NULL) { try { AlgorithmNodesInsideBorder algorithmInsideBorder(NULL, surface, border, isInverseSelection, mapIndex, value, ciftiScalarFile); const BorderFile* dbf = algorithmInsideBorder.getDebugBorderFile(); if (dbf != NULL) { debugBorderFile = new BorderFile(*dbf); } } catch (const AlgorithmException& e) { if (errorMessage.isEmpty() == false) { errorMessage += "\n"; } errorMessage += e.whatString(); } } else { if (errorMessage.isEmpty() == false) { errorMessage += "\n"; } errorMessage += ("Surface for structure " + StructureEnum::toGuiName(structure) + " was not found"); } } break; case DataFileTypeEnum::LABEL: { LabelFile* labelFile = dynamic_cast(mapSelector->getSelectedMapFile()); const int32_t mapIndex = mapSelector->getSelectedMapIndex(); const int32_t labelKey = mapSelector->getSelectedLabelKey(); Surface* surface = NULL; for (std::vector::iterator surfaceIterator = this->surfaces.begin(); surfaceIterator != this->surfaces.end(); surfaceIterator++) { Surface* s = *surfaceIterator; if (s->getStructure() == structure) { surface = s; break; } } CaretAssert(surface); if (surface != NULL) { try { AlgorithmNodesInsideBorder algorithmInsideBorder(NULL, surface, border, isInverseSelection, mapIndex, labelKey, labelFile); const BorderFile* dbf = algorithmInsideBorder.getDebugBorderFile(); if (dbf != NULL) { debugBorderFile = new BorderFile(*dbf); } } catch (const AlgorithmException& e) { if (errorMessage.isEmpty() == false) { errorMessage += "\n"; } errorMessage += e.whatString(); } } else { if (errorMessage.isEmpty() == false) { errorMessage += "\n"; } errorMessage += ("Surface for structure " + StructureEnum::toGuiName(structure) + " was not found"); } } break; case DataFileTypeEnum::METRIC: { MetricFile* metricFile = dynamic_cast(mapSelector->getSelectedMapFile()); const int32_t mapIndex = mapSelector->getSelectedMapIndex(); const float value = mapSelector->getSelectedMetricValue(); Surface* surface = NULL; for (std::vector::iterator surfaceIterator = this->surfaces.begin(); surfaceIterator != this->surfaces.end(); surfaceIterator++) { Surface* s = *surfaceIterator; if (s->getStructure() == structure) { surface = s; break; } } CaretAssert(surface); if (surface != NULL) { try { AlgorithmNodesInsideBorder algorithmInsideBorder(NULL, surface, border, isInverseSelection, mapIndex, value, metricFile); const BorderFile* dbf = algorithmInsideBorder.getDebugBorderFile(); if (dbf != NULL) { debugBorderFile = new BorderFile(*dbf); } } catch (const AlgorithmException& e) { if (errorMessage.isEmpty() == false) { errorMessage += "\n"; } errorMessage += e.whatString(); } } else { if (errorMessage.isEmpty() == false) { errorMessage += "\n"; } errorMessage += ("Surface for structure " + StructureEnum::toGuiName(structure) + " was not found"); } } break; default: CaretAssertMessage(0, "Unsupported file type."); break; } } else { } } } if (debugBorderFile != NULL) { EventManager::get()->sendEvent(EventDataFileAdd(debugBorderFile).getPointer()); } EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); if (errorMessage.isEmpty() == false) { WuQMessageBox::errorOk(this, errorMessage); } if (allowDialogToClose) { WuQDialogModal::okButtonClicked(); } } connectome-workbench-1.4.2/src/GuiQt/RegionOfInterestCreateFromBorderDialog.h000066400000000000000000000061101360521144700272760ustar00rootroot00000000000000#ifndef __REGION_OF_INTEREST_CREATE_FROM_BORDER_DIALOG__H_ #define __REGION_OF_INTEREST_CREATE_FROM_BORDER_DIALOG__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretMappableDataFileAndMapSelector.h" #include "StructureEnum.h" #include "WuQDialogModal.h" class QButtonGroup; class QCheckBox; class QDoubleSpinBox; class QLineEdit; class QStackedWidget; namespace caret { class Border; class Surface; class RegionOfInterestCreateFromBorderDialog : public WuQDialogModal { Q_OBJECT public: RegionOfInterestCreateFromBorderDialog(Border* border, Surface* surface, QWidget* parent); virtual ~RegionOfInterestCreateFromBorderDialog(); private slots: void fileSelectionWasChanged(CaretMappableDataFileAndMapSelector*); protected: virtual void okButtonClicked(); private: RegionOfInterestCreateFromBorderDialog(const RegionOfInterestCreateFromBorderDialog&); RegionOfInterestCreateFromBorderDialog& operator=(const RegionOfInterestCreateFromBorderDialog&); void createDialog(const std::vector& borders, std::vector& surfaces); typedef std::map STRUCTURE_MAP_FILE_SELECTOR_MAP; typedef STRUCTURE_MAP_FILE_SELECTOR_MAP::iterator STRUCTURE_MAP_FILE_SELECTOR_ITERATOR; QWidget* createSelectors(std::set& requiredStructures, std::vector& surfaces, STRUCTURE_MAP_FILE_SELECTOR_MAP& mapFileSelectors); STRUCTURE_MAP_FILE_SELECTOR_MAP mapFileTypeSelectors; std::vector surfaces; std::vector borders; QCheckBox* inverseCheckBox; }; #ifdef __REGION_OF_INTEREST_CREATE_FROM_BORDER_DIALOG_DECLARE__ // #endif // __REGION_OF_INTEREST_CREATE_FROM_BORDER_DIALOG_DECLARE__ } // namespace #endif //__REGION_OF_INTEREST_CREATE_FROM_BORDER_DIALOG__H_ connectome-workbench-1.4.2/src/GuiQt/SceneBasePathWidget.cxx000066400000000000000000000277641360521144700240300ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #define __SCENE_BASE_PATH_WIDGET_DECLARE__ #include "SceneBasePathWidget.h" #undef __SCENE_BASE_PATH_WIDGET_DECLARE__ #include "CaretAssert.h" #include "CaretFileDialog.h" #include "FileInformation.h" #include "SceneFile.h" #include "WuQFactory.h" #include "WuQMessageBox.h" using namespace caret; /** * \class caret::SceneBasePathWidget * \brief Widget for setting scene file base path. * \ingroup GuiQt */ /** * Constructor. * * @param widget * Optional parent. */ SceneBasePathWidget::SceneBasePathWidget(QWidget* widget) : QWidget(widget) { m_automaticRadioButton = new QRadioButton("Automatic"); m_automaticBasePathLineEdit = new QLineEdit; m_automaticBasePathLineEdit->setReadOnly(true); m_customRadioButton = new QRadioButton("Custom"); QButtonGroup* buttGroup = new QButtonGroup(this); buttGroup->addButton(m_automaticRadioButton); buttGroup->addButton(m_customRadioButton); QObject::connect(buttGroup, static_cast(&QButtonGroup::buttonClicked), this, [=](QAbstractButton* button){ this->basePathTypeButtonGroupClicked(button); }); m_customBasePathComboBox = WuQFactory::newComboBox(); m_customBasePathComboBox->setEditable(false); QObject::connect(m_customBasePathComboBox, static_cast(&QComboBox::activated), this, [=](int index){ this->customPathComboBoxActivated(index); }); QPushButton* copyAutoBasePathPushButton = new QPushButton("Copy"); copyAutoBasePathPushButton->setToolTip("Copy automatic base path to clipboard"); QObject::connect(copyAutoBasePathPushButton, &QPushButton::clicked, this, &SceneBasePathWidget::copyAutoBasePathToClipboard); QPushButton* customBrowsePushButton = new QPushButton("Browse..."); QObject::connect(customBrowsePushButton, &QPushButton::clicked, this, &SceneBasePathWidget::customBrowseButtonClicked); QPushButton* whatsThisPushButton = new QPushButton("What's this?"); whatsThisPushButton->setSizePolicy(QSizePolicy::Fixed, whatsThisPushButton->sizePolicy().verticalPolicy()); QObject::connect(whatsThisPushButton, &QPushButton::clicked, this, &SceneBasePathWidget::whatsThisBasePath); QGroupBox* groupBox = new QGroupBox("Base Path"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->setSpacing(2); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); gridLayout->setColumnStretch(2, 0); int row = 0; gridLayout->addWidget(whatsThisPushButton, row, 0, 1, 3, Qt::AlignLeft); row++; gridLayout->addWidget(m_automaticRadioButton, row, 0); gridLayout->addWidget(m_automaticBasePathLineEdit, row, 1); gridLayout->addWidget(copyAutoBasePathPushButton, row, 2); row++; gridLayout->addWidget(m_customRadioButton, row, 0); gridLayout->addWidget(m_customBasePathComboBox, row, 1); gridLayout->addWidget(customBrowsePushButton, row, 2); QVBoxLayout* widgetLayout = new QVBoxLayout(this); widgetLayout->setContentsMargins(0, 0, 0, 0); widgetLayout->addWidget(groupBox); // setSizePolicy(sizePolicy().horizontalPolicy(), // QSizePolicy::Fixed); } /** * Destructor. */ SceneBasePathWidget::~SceneBasePathWidget() { } /** * Update the widget with the given scene file. * * @param sceneFile * The scene file. */ void SceneBasePathWidget::updateWithSceneFile(SceneFile* sceneFile) { m_sceneFile = sceneFile; m_automaticBasePathLineEdit->clear(); QSignalBlocker customPathSignalBlocker(m_customBasePathComboBox); if (m_sceneFile != NULL) { AString customBaseDirectoryName = m_sceneFile->getBalsaCustomBaseDirectory(); m_customBasePathComboBox->clear(); const std::vector dirNames = m_sceneFile->getBaseDirectoryHierarchyForDataFiles(); if ( ! customBaseDirectoryName.isEmpty()) { /* * If the base directory is in neither the base path hierarchy * nor the user custom paths, add it to the user custom paths * so that it appears in the combo box and is selected. */ if (std::find(dirNames.begin(), dirNames.end(), customBaseDirectoryName) == dirNames.end()) { if (std::find(s_userCustomBasePaths.begin(), s_userCustomBasePaths.end(), customBaseDirectoryName) == s_userCustomBasePaths.end()) { s_userCustomBasePaths.push_back(customBaseDirectoryName); } } } for (auto name : s_userCustomBasePaths) { m_customBasePathComboBox->addItem(name); } for (auto name : dirNames) { m_customBasePathComboBox->addItem(name); } if ( ! customBaseDirectoryName.isEmpty()) { m_customBasePathComboBox->setCurrentText(customBaseDirectoryName); } switch (m_sceneFile->getBasePathType()) { case SceneFileBasePathTypeEnum::AUTOMATIC: m_automaticRadioButton->setChecked(true); m_customBasePathComboBox->setEnabled(false); break; case SceneFileBasePathTypeEnum::CUSTOM: m_customRadioButton->setChecked(true); m_customBasePathComboBox->setEnabled(true); break; } AString baseDirectoryName; std::vector missingFileNames; AString errorMessage; sceneFile->findBaseDirectoryForDataFiles(baseDirectoryName, missingFileNames, errorMessage); m_automaticBasePathLineEdit->setText(baseDirectoryName); setEnabled(true); } else { m_customBasePathComboBox->clear(); setEnabled(false); } } /** * Copy the automatic base path to the clipboard */ void SceneBasePathWidget::copyAutoBasePathToClipboard() { const QString txt = m_automaticBasePathLineEdit->text().trimmed(); if ( ! txt.isEmpty()) { QApplication::clipboard()->setText(txt, QClipboard::Clipboard); } } /** * Called when the user selects and item in the custom * path combo box. * * @param index * Index of the item selected. */ void SceneBasePathWidget::customPathComboBoxActivated(int index) { const AString text = m_customBasePathComboBox->itemText(index); if ( ! text.isEmpty()) { m_sceneFile->setBalsaCustomBaseDirectory(text); } } /** * Gets called when the custom browse button is clicked. */ void SceneBasePathWidget::customBrowseButtonClicked() { const AString msg("The only reason to use this Browse button is when the Automatic mode fails. " "If you select a base path that is a not a parent directory of the " "scene file and its data files, zipping of the scene file and its " "data files will fail.\n\n" "Do you want to continue?"); if ( ! WuQMessageBox::warningOkCancel(this, msg)) { return; } CaretAssert(m_sceneFile); /* * Let user choose directory path */ QString directoryName; FileInformation fileInfo(m_customBasePathComboBox->currentText().trimmed()); if (fileInfo.exists()) { if (fileInfo.isDirectory()) { directoryName = fileInfo.getAbsoluteFilePath(); } } const AString newDirectoryName = CaretFileDialog::getExistingDirectoryDialog(this, "Choose Base Path", directoryName); /* * If user cancels, return */ if (newDirectoryName.isEmpty()) { return; } if (std::find(s_userCustomBasePaths.begin(), s_userCustomBasePaths.end(), newDirectoryName) == s_userCustomBasePaths.end()) { s_userCustomBasePaths.push_back(newDirectoryName); } m_sceneFile->setBasePathType(SceneFileBasePathTypeEnum::CUSTOM); m_sceneFile->setBalsaCustomBaseDirectory(newDirectoryName); updateWithSceneFile(m_sceneFile); } /** * Gets called when on of the radio buttons is clicked. * * @param button * Button that was clicked. */ void SceneBasePathWidget::basePathTypeButtonGroupClicked(QAbstractButton* button) { if (button == m_automaticRadioButton) { m_sceneFile->setBasePathType(SceneFileBasePathTypeEnum::AUTOMATIC); } else if (button == m_customRadioButton) { m_sceneFile->setBasePathType(SceneFileBasePathTypeEnum::CUSTOM); } else { CaretAssertMessage(0, "Has a new SceneFileBasePathTypeEnum::Enum been added?"); } updateWithSceneFile(m_sceneFile); } /** * @return True if the selections in the widget are valid, else false. * * @param errorMessageOut * Output contains error information if false returned. */ bool SceneBasePathWidget::isValid(AString& errorMessageOut) const { errorMessageOut.clear(); if (m_automaticRadioButton->isChecked()) { /* valid */ } else if (m_customRadioButton->isChecked()) { const AString basePath = m_customBasePathComboBox->currentText().trimmed(); if (basePath.isEmpty()) { errorMessageOut = "CUSTOM base path is empty."; } else { FileInformation fileInfo(basePath); if (fileInfo.exists() && fileInfo.isDirectory()) { /* Valid directory */ } else { errorMessageOut = "CUSTOM base path is not a valid directory"; } } } else { CaretAssert(0); errorMessageOut = "Neither AUTOMATIC nor CUSTOM is selected."; } return (errorMessageOut.isEmpty()); } /** * Displays a dialog explaining base path options */ void SceneBasePathWidget::whatsThisBasePath() { const AString text("The Automatic Base Path is the \"lowest level\" path that contains the Scene File and " "all data files referenced by the Scene File. " "The directory structure of all files contained in the Scene File relative to (at or below) " "the Base Path will be preserved in your dataset when it is downloaded from BALSA and " "unzipped by other users. You may set a Custom path above the Automatic Base Path, but " "it will add additional, unnecessary path layers to the unzipped dataset."); WuQMessageBox::informationOk(this, text); } connectome-workbench-1.4.2/src/GuiQt/SceneBasePathWidget.h000066400000000000000000000046741360521144700234500ustar00rootroot00000000000000#ifndef __SCENE_BASE_PATH_WIDGET_H__ #define __SCENE_BASE_PATH_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include class QAbstractButton; class QComboBox; class QLineEdit; class QRadioButton; #include "AString.h" namespace caret { class SceneFile; class SceneBasePathWidget : public QWidget { Q_OBJECT public: SceneBasePathWidget(QWidget* parent = 0); virtual ~SceneBasePathWidget(); void updateWithSceneFile(SceneFile* sceneFile); bool isValid(AString& errorMessageOut) const; // ADD_NEW_METHODS_HERE private slots: void customBrowseButtonClicked(); void customPathComboBoxActivated(int index); void copyAutoBasePathToClipboard(); void basePathTypeButtonGroupClicked(QAbstractButton* button); void whatsThisBasePath(); private: SceneBasePathWidget(const SceneBasePathWidget&); SceneBasePathWidget& operator=(const SceneBasePathWidget&); SceneFile* m_sceneFile = NULL; QComboBox* m_customBasePathComboBox; QRadioButton* m_automaticRadioButton; QRadioButton* m_customRadioButton; QLineEdit* m_automaticBasePathLineEdit; static std::vector s_userCustomBasePaths; // ADD_NEW_MEMBERS_HERE }; #ifdef __SCENE_BASE_PATH_WIDGET_DECLARE__ std::vector SceneBasePathWidget::s_userCustomBasePaths; #endif // __SCENE_BASE_PATH_WIDGET_DECLARE__ } // namespace #endif //__SCENE_BASE_PATH_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/SceneCreateReplaceDialog.cxx000066400000000000000000000664761360521144700250170ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __SCENE_CREATE_REPLACE_DIALOG_DECLARE__ #include "SceneCreateReplaceDialog.h" #undef __SCENE_CREATE_REPLACE_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include "ApplicationInformation.h" #include "Brain.h" #include "BrainBrowserWindow.h" #include "CaretAssert.h" #include "CaretPreferences.h" #include "DataFileException.h" #include "EventBrowserTabGetAll.h" #include "EventBrowserTabGetAllViewed.h" #include "EventImageCapture.h" #include "EventSceneActive.h" #include "EventManager.h" #include "GuiManager.h" #include "ImageFile.h" #include "PlainTextStringBuilder.h" #include "Scene.h" #include "SceneAttributes.h" #include "SceneDialog.h" #include "SceneFile.h" #include "SceneInfo.h" #include "SessionManager.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::SceneCreateReplaceDialog * \brief Dialog for creating or replacing a scene. * \ingroup GuiQt * */ #include "Scene.h" /** * Constructor. * * @param dialogTitle * Title of the dialog. * @param parent * Parent on which dialog is displayed. * @param sceneFile * Scene file to which scene is added or replaced. * @param mode * Scene add/insert/replace mode * @param sceneToReplace * If non-NULL, this scene will be replaced. */ SceneCreateReplaceDialog::SceneCreateReplaceDialog(const AString& dialogTitle, QWidget* parent, SceneFile* sceneFile, const Mode mode, Scene* sceneToInsertOrReplace) : WuQDialogModal(dialogTitle, parent) { CaretAssert(sceneFile); switch (m_mode) { case MODE_ADD_NEW_SCENE: break; case MODE_INSERT_NEW_SCENE: CaretAssert(sceneToInsertOrReplace); break; case MODE_REPLACE_SCENE: CaretAssert(sceneToInsertOrReplace); break; } if ( ! s_previousSelectionsValid) { s_previousSelectionsValid = true; s_previousSelections.m_addAllLoadedFiles = true; s_previousSelections.m_addAllTabs = true; s_previousSelections.m_addModifiedPaletteSettings = true; s_previousSelections.m_addSpecFileNameToScene = true; } m_sceneFile = sceneFile; m_mode = mode; m_sceneToInsertOrReplace = sceneToInsertOrReplace; m_sceneThatWasCreated = NULL; /* * Options widget */ QLabel* optionsLabel = new QLabel("Options"); QWidget* optionsWidget = createSceneOptionsWidget(); /* * Create scene information widgets */ QLabel* nameLabel = new QLabel("Name"); m_nameLineEdit = new QLineEdit(); QLabel* sceneIDLabel = new QLabel("BALSA Scene ID"); m_balsaSceneIDLineEdit = new QLineEdit(); m_balsaSceneIDLineEdit->setToolTip("Scene ID is for use with BALSA Database"); QPushButton* addWindowDescriptionPushButton = new QPushButton("Add Window Info"); QObject::connect(addWindowDescriptionPushButton, &QPushButton::clicked, this, &SceneCreateReplaceDialog::addWindowContentToolButtonClicked); QLabel* descriptionLabel = new QLabel("Description"); m_descriptionTextEdit = new QPlainTextEdit(); const Qt::Alignment labelAlignment = (Qt::AlignLeft | Qt::AlignTop); int32_t columnCounter = 0; const int32_t labelColumn = columnCounter++; const int32_t widgetColumn = columnCounter++; QGridLayout* infoGridLayout = new QGridLayout(); infoGridLayout->setColumnStretch(labelColumn, 0); infoGridLayout->setColumnStretch(widgetColumn, 100); int32_t rowCounter = 0; infoGridLayout->setRowStretch(rowCounter, 0); infoGridLayout->addWidget(nameLabel, rowCounter, labelColumn, labelAlignment); infoGridLayout->addWidget(m_nameLineEdit, rowCounter, widgetColumn); rowCounter++; infoGridLayout->addWidget(sceneIDLabel, rowCounter, labelColumn, labelAlignment); infoGridLayout->addWidget(m_balsaSceneIDLineEdit, rowCounter, widgetColumn); rowCounter++; infoGridLayout->addWidget(descriptionLabel, rowCounter, labelColumn, labelAlignment); infoGridLayout->addWidget(m_descriptionTextEdit, rowCounter, widgetColumn, 2, 1); rowCounter++; infoGridLayout->addWidget(addWindowDescriptionPushButton, rowCounter, labelColumn, labelAlignment); infoGridLayout->setRowStretch(rowCounter, 100); rowCounter++; infoGridLayout->addWidget(optionsLabel, rowCounter, labelColumn, labelAlignment); infoGridLayout->addWidget(optionsWidget, rowCounter, widgetColumn); rowCounter++; /* * Add the layout to a widget and return the widget. */ QWidget* infoWidget = new QWidget(); infoWidget->setLayout(infoGridLayout); QWidget* dialogWidget = new QWidget(); QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); dialogLayout->addWidget(infoWidget, 100); setCentralWidget(dialogWidget, WuQDialog::SCROLL_AREA_NEVER); PlainTextStringBuilder windowDescriptionBuilder; std::vector windows = GuiManager::get()->getAllOpenBrainBrowserWindows(); for (std::vector::iterator iter = windows.begin(); iter != windows.end(); iter++) { BrainBrowserWindow* window = *iter; window->getDescriptionOfContent(windowDescriptionBuilder); windowDescriptionBuilder.addLine(""); } const AString windowDescription = windowDescriptionBuilder.getText().trimmed(); QDateTime dateTime = QDateTime::currentDateTime(); const QString dateTimeText = dateTime.toString("dd MMM yyyy hh:mm:ss"); const QString commitName = (ApplicationInformation().getCommit()); const QString dataTimeCommitText(dateTimeText + "\n" + commitName); const AString defaultNewSceneName = ("New Scene " + AString::number(sceneFile->getNumberOfScenes() + 1)); m_nameLineEdit->setText(defaultNewSceneName); switch (m_mode) { case MODE_ADD_NEW_SCENE: case MODE_INSERT_NEW_SCENE: m_sceneWindowDescription = ("Created on " + dataTimeCommitText + "\n"); m_sceneWindowDescription.appendWithNewLine(windowDescription); break; case MODE_REPLACE_SCENE: m_nameLineEdit->setText(sceneToInsertOrReplace->getName()); m_balsaSceneIDLineEdit->setText(sceneToInsertOrReplace->getBalsaSceneID()); m_sceneWindowDescription = ("Replaced on " + dataTimeCommitText + "\n"); m_sceneWindowDescription.appendWithNewLine(windowDescription); m_sceneWindowDescription.appendWithNewLine(" "); m_sceneWindowDescription.appendWithNewLine(sceneToInsertOrReplace->getDescription()); m_descriptionTextEdit->setPlainText(sceneToInsertOrReplace->getDescription()); break; } m_nameLineEdit->setFocus(); m_nameLineEdit->selectAll(); setMinimumWidth(600); setMinimumHeight(300); setSaveWindowPositionForNextTime("SceneCreateDialog"); } /** * Destructor. */ SceneCreateReplaceDialog::~SceneCreateReplaceDialog() { } /** * Static method that creates a dialog for creating a new scene and * returns the scene that was created or NULL if scene was not created. * * @param parent * Parent widget on which dialog is displayed. * @param sceneFile * Scene file to which new scene is added. * @return * Scene that was created or NULL if user cancelled or there was an error. */ Scene* SceneCreateReplaceDialog::createNewScene(QWidget* parent, SceneFile* sceneFile) { SceneCreateReplaceDialog dialog("Create New Scene", parent, sceneFile, MODE_ADD_NEW_SCENE, NULL); dialog.exec(); Scene* scene = dialog.m_sceneThatWasCreated; return scene; } /** * Static method that creates a dialog for creating a new scene and * returns the scene that was created or NULL if scene was not created. * * @param parent * Parent widget on which dialog is displayed. * @param sceneFile * Scene file to which new scene is added. * @param insertBeforeScene * Insert the newly created scene BEFORE this scene. * @return * Scene that was created or NULL if user cancelled or there was an error. */ Scene* SceneCreateReplaceDialog::createNewSceneInsertBeforeScene(QWidget* parent, SceneFile* sceneFile, const Scene* insertBeforeScene) { SceneCreateReplaceDialog dialog("Insert New Scene", parent, sceneFile, MODE_INSERT_NEW_SCENE, const_cast(insertBeforeScene)); dialog.exec(); Scene* scene = dialog.m_sceneThatWasCreated; return scene; } /** * Static method that creates a dialog for replacing and existing scene and * returns the scene that was created or NULL if scene was not created. * * @param parent * Parent widget on which dialog is displayed. * @param sceneFile * File in which the given scene exists and will be replaced. * @param sceneToReplace * Scene that is being replaced. If the user presses the OK button * to replace this scene it will be destroyed so the pointer must not * be deferenced at any time after calling this method. * @return * Scene that was created or NULL if user cancelled or there was an error. */ Scene* SceneCreateReplaceDialog::replaceExistingScene(QWidget* parent, SceneFile* sceneFile, Scene* sceneToReplace) { const AString title = ("Replace Scene: " + sceneToReplace->getName()); SceneCreateReplaceDialog dialog(title, parent, sceneFile, MODE_REPLACE_SCENE, sceneToReplace); /* * Run the dialog. * If user cancels, "dialog.m_sceneThatWasCreated" will be NULL. */ dialog.exec(); Scene* scene = dialog.m_sceneThatWasCreated; return scene; } /** * Add an image to the scene. * * @param scene * Scene to which image is added. */ void SceneCreateReplaceDialog::addImageToScene(Scene* scene, AString& errorMessageOut) { errorMessageOut.clear(); CaretAssert(scene); uint8_t backgroundColor[3] = { 0, 0, 0 }; bool backgroundColorValid = false; /* * Capture an image of each window */ std::vector imageFiles; std::vector windows = GuiManager::get()->getAllOpenBrainBrowserWindows(); for (std::vector::iterator iter = windows.begin(); iter != windows.end(); iter++) { BrainBrowserWindow* bbw = *iter; const int32_t browserWindowIndex = bbw->getBrowserWindowIndex(); EventImageCapture imageCaptureEvent(browserWindowIndex); EventManager::get()->sendEvent(imageCaptureEvent.getPointer()); if (imageCaptureEvent.getEventProcessCount() > 0) { if (imageCaptureEvent.isError()) { errorMessageOut.appendWithNewLine(imageCaptureEvent.getErrorMessage()); } else { imageFiles.push_back(new ImageFile(imageCaptureEvent.getImage())); if ( ! backgroundColorValid) { imageCaptureEvent.getBackgroundColor(backgroundColor); backgroundColorValid = true; } } } } /* * Assemble images of each window into a single image * and add it to the scene. Use one image per row * since the images are limited in horizontal space * when shown in the listing of scenes. */ if ( ! imageFiles.empty()) { try { const int32_t numImagesPerRow = 1; ImageFile compositeImageFile; compositeImageFile.combinePreservingAspectAndFillIfNeeded(imageFiles, numImagesPerRow, backgroundColor); if (backgroundColorValid) { const int marginSize = 5; compositeImageFile.cropImageRemoveBackground(marginSize, backgroundColor); } const int MAXIMUM_IMAGE_WIDTH = 1024; compositeImageFile.resizeToMaximumWidth(MAXIMUM_IMAGE_WIDTH); const AString PREFERRED_IMAGE_FORMAT = "png"; QByteArray byteArray; compositeImageFile.getImageInByteArray(byteArray, PREFERRED_IMAGE_FORMAT); scene->getSceneInfo()->setImageBytes(byteArray, PREFERRED_IMAGE_FORMAT); } catch (const DataFileException& dfe) { errorMessageOut.appendWithNewLine((dfe.whatString() + "\n\nEven though image failed, scene was created.")); } } /* * Free memory from the image files. */ for (std::vector::iterator iter = imageFiles.begin(); iter != imageFiles.end(); iter++) { delete *iter; } } /** * Create an image for the loaded scene. * * @param imageOut * Output image of the scene. * @param errorMessageOut * Contains error information if image was not created. * @return * True if output image is valid, else false. */ bool SceneCreateReplaceDialog::createSceneImage(QImage& imageOut, AString& errorMessageOut) { bool validImageFlag = false; imageOut = QImage(); errorMessageOut.clear(); uint8_t backgroundColor[3] = { 0, 0, 0 }; bool backgroundColorValid = false; /* * Capture an image of each window */ std::vector imageFiles; std::vector windows = GuiManager::get()->getAllOpenBrainBrowserWindows(); for (std::vector::iterator iter = windows.begin(); iter != windows.end(); iter++) { BrainBrowserWindow* bbw = *iter; const int32_t browserWindowIndex = bbw->getBrowserWindowIndex(); EventImageCapture imageCaptureEvent(browserWindowIndex); EventManager::get()->sendEvent(imageCaptureEvent.getPointer()); if (imageCaptureEvent.getEventProcessCount() > 0) { if (imageCaptureEvent.isError()) { errorMessageOut.appendWithNewLine(imageCaptureEvent.getErrorMessage()); } else { imageFiles.push_back(new ImageFile(imageCaptureEvent.getImage())); if ( ! backgroundColorValid) { imageCaptureEvent.getBackgroundColor(backgroundColor); backgroundColorValid = true; } } } } /* * Assemble images of each window into a single image * and add it to the scene. Use one image per row * since the images are limited in horizontal space * when shown in the listing of scenes. */ if ( ! imageFiles.empty()) { try { const int32_t numImagesPerRow = 1; ImageFile compositeImageFile; compositeImageFile.combinePreservingAspectAndFillIfNeeded(imageFiles, numImagesPerRow, backgroundColor); if (backgroundColorValid) { const int marginSize = 5; compositeImageFile.cropImageRemoveBackground(marginSize, backgroundColor); } const int MAXIMUM_IMAGE_WIDTH = 1024; compositeImageFile.resizeToMaximumWidth(MAXIMUM_IMAGE_WIDTH); const AString PREFERRED_IMAGE_FORMAT = "png"; QByteArray byteArray; compositeImageFile.getImageInByteArray(byteArray, PREFERRED_IMAGE_FORMAT); imageOut = *compositeImageFile.getAsQImage(); validImageFlag = true; } catch (const DataFileException&) { errorMessageOut.appendWithNewLine("Even though image generation failed, scene was created."); } } /* * Free memory from the image files. */ for (std::vector::iterator iter = imageFiles.begin(); iter != imageFiles.end(); iter++) { delete *iter; } return validImageFlag; } /** * @return Widget containing the scene options widgets. */ QWidget* SceneCreateReplaceDialog::createSceneOptionsWidget() { /* * Create scene options widgets */ m_addSpecFileNameToSceneCheckBox = new QCheckBox("Add name of spec file to scene"); m_addSpecFileNameToSceneCheckBox->setChecked(s_previousSelections.m_addSpecFileNameToScene); WuQtUtilities::setWordWrappedToolTip(m_addSpecFileNameToSceneCheckBox, "Include name of spec file in the scene"); m_addAllTabsCheckBox = new QCheckBox("Add all tabs to scene"); m_addAllTabsCheckBox->setChecked(s_previousSelections.m_addAllTabs); WuQtUtilities::setWordWrappedToolTip(m_addAllTabsCheckBox, "Add all tabs to the scene. When this option is selected, " "the scene will be larger and require additional time to " "load. If NOT selected, only the selected tab in each " "window is saved to the scene."); m_addAllLoadedFilesCheckBox = new QCheckBox("Add all loaded files to scene"); m_addAllLoadedFilesCheckBox->setChecked(s_previousSelections.m_addAllLoadedFiles); WuQtUtilities::setWordWrappedToolTip(m_addAllLoadedFilesCheckBox, "Add all loaded files to scene. When this option is selected, " "the scene may require additional time to load as file that " "play no role in reproducing the scene will be loaded. If NOT " "selected, the scene may load more quickly."); m_addModifiedPaletteSettingsCheckBox = new QCheckBox("Add modified palette color mapping to scene"); m_addModifiedPaletteSettingsCheckBox->setChecked(s_previousSelections.m_addModifiedPaletteSettings); WuQtUtilities::setWordWrappedToolTip(m_addModifiedPaletteSettingsCheckBox, "The palette color mapping is saved within each data files that maps " "its data to brainordinates. However, there are instances in which " "the user wants the scene to display the data with palette color mapping " "that is different from that in the file. If this option is " "selected, modified palettes color mapping will be saved to the scene " "and the data files with modified palette color mapping do not need " "to be saved."); /* * Layout for scene options widgets */ QVBoxLayout* optionsLayout = new QVBoxLayout(); optionsLayout->addWidget(m_addSpecFileNameToSceneCheckBox); optionsLayout->addWidget(m_addAllTabsCheckBox); optionsLayout->addWidget(m_addAllLoadedFilesCheckBox); optionsLayout->addWidget(m_addModifiedPaletteSettingsCheckBox); /* * Add the layout to a widget and return the widget. */ QFrame* optionsWidget = new QFrame(); optionsWidget->setFrameStyle(QFrame::Box | QFrame::Plain); optionsWidget->setLineWidth(1); // QWidget* optionsWidget = new QWidget(); optionsWidget->setLayout(optionsLayout); return optionsWidget; } /** * Gets called if the user presses the OK button. */ void SceneCreateReplaceDialog::okButtonClicked() { s_previousSelections.m_addAllLoadedFiles = m_addAllLoadedFilesCheckBox->isChecked(); s_previousSelections.m_addAllTabs = m_addAllTabsCheckBox->isChecked(); s_previousSelections.m_addModifiedPaletteSettings = m_addModifiedPaletteSettingsCheckBox->isChecked(); s_previousSelections.m_addSpecFileNameToScene = m_addSpecFileNameToSceneCheckBox->isChecked(); const AString newSceneName = m_nameLineEdit->text(); AString errorMessage; if (newSceneName.isEmpty()) { errorMessage = "Scene Name is empty."; } else { const Scene* sceneWithName = m_sceneFile->getSceneWithName(newSceneName); if (sceneWithName != NULL) { bool nameErrorFlag = true; switch (m_mode) { case MODE_ADD_NEW_SCENE: break; case MODE_INSERT_NEW_SCENE: break; case MODE_REPLACE_SCENE: if (m_sceneToInsertOrReplace == sceneWithName) { nameErrorFlag = false; } break; } if (nameErrorFlag) { errorMessage = ("An existing scene uses the name \"" + newSceneName + "\". Scene names must be unique."); } } } if ( ! errorMessage.isEmpty()) { WuQMessageBox::errorOk(this, errorMessage); return; } if ( ! s_previousSelections.m_addModifiedPaletteSettings) { if ( ! SceneDialog::checkForModifiedFiles(GuiManager::TEST_FOR_MODIFIED_FILES_PALETTE_ONLY_MODE_FOR_SCENE_ADD, this)) { /* * Add modified palettes to scene is off but * there are modified palettes and user has * chose to not create the scene */ return; } } Scene* newScene = new Scene(SceneTypeEnum::SCENE_TYPE_FULL); Scene::setSceneBeingCreated(newScene); newScene->setName(newSceneName); newScene->setDescription(m_descriptionTextEdit->toPlainText()); newScene->setBalsaSceneID(m_balsaSceneIDLineEdit->text().trimmed()); const std::vector windowIndices = GuiManager::get()->getAllOpenBrainBrowserWindowIndices(); /* * Get all browser tabs and only save transformations for tabs * that are valid. */ std::vector tabIndices; if (m_addAllTabsCheckBox->isChecked()) { EventBrowserTabGetAll getAllTabs; EventManager::get()->sendEvent(getAllTabs.getPointer()); tabIndices = getAllTabs.getBrowserTabIndices(); } else { EventBrowserTabGetAllViewed getViewedTabs; EventManager::get()->sendEvent(getViewedTabs.getPointer()); tabIndices = getViewedTabs.getViewdedBrowserTabIndices(); } std::sort(tabIndices.begin(), tabIndices.end()); SceneAttributes* sceneAttributes = newScene->getAttributes(); sceneAttributes->setSceneFileName(m_sceneFile->getFileName()); sceneAttributes->setSceneName(newSceneName); sceneAttributes->setIndicesOfTabsAndWindowsForSavingToScene(tabIndices, windowIndices); sceneAttributes->setSpecFileNameSavedToScene(m_addSpecFileNameToSceneCheckBox->isChecked()); sceneAttributes->setAllLoadedFilesSavedToScene(m_addAllLoadedFilesCheckBox->isChecked()); sceneAttributes->setModifiedPaletteSettingsSavedToScene(m_addModifiedPaletteSettingsCheckBox->isChecked()); newScene->addClass(GuiManager::get()->saveToScene(sceneAttributes, "guiManager")); AString imageErrorMessage; addImageToScene(newScene, imageErrorMessage); if ( ! imageErrorMessage.isEmpty()) { WuQMessageBox::errorOk(this, imageErrorMessage); } /* * Copy macros from active scene to the new scene */ EventSceneActive activeSceneEvent(EventSceneActive::MODE_GET); EventManager::get()->sendEvent(activeSceneEvent.getPointer()); const Scene* activeScene = activeSceneEvent.getScene(); if (activeScene != NULL) { newScene->copyMacrosFromScene(activeScene); } switch (m_mode) { case MODE_ADD_NEW_SCENE: m_sceneFile->addScene(newScene); break; case MODE_INSERT_NEW_SCENE: m_sceneFile->insertScene(newScene, m_sceneToInsertOrReplace); break; case MODE_REPLACE_SCENE: m_sceneFile->replaceScene(newScene, m_sceneToInsertOrReplace); break; } m_sceneThatWasCreated = newScene; Scene::setSceneBeingCreated(NULL); WuQDialogModal::okButtonClicked(); } /** * Called when add window content button clicked */ void SceneCreateReplaceDialog::addWindowContentToolButtonClicked() { AString txt = m_descriptionTextEdit->document()->toPlainText(); txt.appendWithNewLine(m_sceneWindowDescription); m_descriptionTextEdit->setPlainText(txt); } connectome-workbench-1.4.2/src/GuiQt/SceneCreateReplaceDialog.h000066400000000000000000000102321360521144700244170ustar00rootroot00000000000000#ifndef __SCENE_CREATE_REPLACE_DIALOG_H__ #define __SCENE_CREATE_REPLACE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WuQDialogModal.h" class QCheckBox; class QLineEdit; class QPlainTextEdit; namespace caret { class Scene; class SceneFile; class SceneCreateReplaceDialog : public WuQDialogModal { Q_OBJECT public: static Scene* createNewScene(QWidget* parent, SceneFile* sceneFile); static Scene* createNewSceneInsertBeforeScene(QWidget* parent, SceneFile* sceneFile, const Scene* insertBeforeScene); static Scene* replaceExistingScene(QWidget* parent, SceneFile* sceneFile, Scene* sceneToReplace); static void addImageToScene(Scene* scene, AString& errorMessageOut); static bool createSceneImage(QImage& imageOut, AString& errorMessageOut); virtual ~SceneCreateReplaceDialog(); private: enum Mode { MODE_ADD_NEW_SCENE, MODE_INSERT_NEW_SCENE, MODE_REPLACE_SCENE }; SceneCreateReplaceDialog(const AString& dialogTitle, QWidget* parent, SceneFile* sceneFile, const Mode mode, Scene* sceneToInsertOrReplace); SceneCreateReplaceDialog(const SceneCreateReplaceDialog&); SceneCreateReplaceDialog& operator=(const SceneCreateReplaceDialog&); public: // ADD_NEW_METHODS_HERE protected: virtual void okButtonClicked(); private slots: void addWindowContentToolButtonClicked(); private: // ADD_NEW_MEMBERS_HERE SceneFile* m_sceneFile; Mode m_mode; Scene* m_sceneToInsertOrReplace; /** Scene that was created DO NOT DESTROY SINCE RETURNED TO CALLER */ Scene* m_sceneThatWasCreated; QWidget* createSceneOptionsWidget(); QLineEdit* m_nameLineEdit; QLineEdit* m_balsaSceneIDLineEdit; QPlainTextEdit* m_descriptionTextEdit; QCheckBox* m_addSpecFileNameToSceneCheckBox; QCheckBox* m_addAllTabsCheckBox; QCheckBox* m_addAllLoadedFilesCheckBox; QCheckBox* m_addModifiedPaletteSettingsCheckBox; AString m_sceneWindowDescription; struct PreviousSelections { bool m_addSpecFileNameToScene; bool m_addAllTabs; bool m_addAllLoadedFiles; bool m_addModifiedPaletteSettings; }; static PreviousSelections s_previousSelections; static bool s_previousSelectionsValid; }; #ifdef __SCENE_CREATE_REPLACE_DIALOG_DECLARE__ SceneCreateReplaceDialog::PreviousSelections SceneCreateReplaceDialog::s_previousSelections; bool SceneCreateReplaceDialog::s_previousSelectionsValid = false; #endif // __SCENE_CREATE_REPLACE_DIALOG_DECLARE__ } // namespace #endif //__SCENE_CREATE_REPLACE_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/SceneDataFileTreeItem.cxx000066400000000000000000000061731360521144700242740ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SCENE_DATA_FILE_TREE_ITEM_DECLARE__ #include "SceneDataFileTreeItem.h" #undef __SCENE_DATA_FILE_TREE_ITEM_DECLARE__ #include "CaretAssert.h" #include "FileInformation.h" using namespace caret; /** * \class caret::SceneDataFileTreeItem * \brief Item for insertion in a SceneDataFileTreeItemModel * \ingroup GuiQt */ /** * Constructor. * * @param text * Text for the model item * @param absolutePathName * Absolute path name including name of file (if a data file) * @param itemType * Item type indicating file or directory. * Use getItemTypeDirectory() or getItemTypeFile(). */ SceneDataFileTreeItem::SceneDataFileTreeItem(const AString& text, const AString& absolutePathName, const int32_t itemType) : QStandardItem(text), m_absolutePathName(absolutePathName), m_itemType(itemType) { FileInformation fileInfo(absolutePathName); if ( ! fileInfo.exists()) { setText(text + " "); } setColumnCount(1); } /** * Destructor. */ SceneDataFileTreeItem::~SceneDataFileTreeItem() { } /** * Copy constructor. * @param obj * Object that is copied. */ SceneDataFileTreeItem::SceneDataFileTreeItem(const SceneDataFileTreeItem& obj) : QStandardItem(obj) { this->copyHelperSceneDataFileTreeItem(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ SceneDataFileTreeItem& SceneDataFileTreeItem::operator=(const SceneDataFileTreeItem& obj) { if (this != &obj) { QStandardItem::operator=(obj); this->copyHelperSceneDataFileTreeItem(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void SceneDataFileTreeItem::copyHelperSceneDataFileTreeItem(const SceneDataFileTreeItem& obj) { m_absolutePathName = obj.m_absolutePathName; m_itemType = obj.m_itemType; } /** * @return Full absolute path name */ AString SceneDataFileTreeItem::getAbsolutePathName() const { return m_absolutePathName; } /** * @return The type of this item. The type is used to distinguish custom items from the base class */ int SceneDataFileTreeItem::type() const { return m_itemType; } connectome-workbench-1.4.2/src/GuiQt/SceneDataFileTreeItem.h000066400000000000000000000044471360521144700237230ustar00rootroot00000000000000#ifndef __SCENE_DATA_FILE_TREE_ITEM_H__ #define __SCENE_DATA_FILE_TREE_ITEM_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class SceneDataFileTreeItem : public QStandardItem { public: /** * @return ItemType for a directory */ static int32_t getItemTypeDirectory() { return (QStandardItem::UserType + 1); } /** * @return ItemType for a data file */ static int32_t getItemTypeFile() { return (QStandardItem::UserType + 2); } SceneDataFileTreeItem(const AString& text, const AString& absolutePathName, const int32_t itemType); virtual ~SceneDataFileTreeItem(); SceneDataFileTreeItem(const SceneDataFileTreeItem&); SceneDataFileTreeItem& operator=(const SceneDataFileTreeItem&); AString getAbsolutePathName() const; virtual int type() const; // ADD_NEW_METHODS_HERE private: void copyHelperSceneDataFileTreeItem(const SceneDataFileTreeItem& obj); AString m_absolutePathName; int32_t m_itemType; // ADD_NEW_MEMBERS_HERE }; #ifdef __SCENE_DATA_FILE_TREE_ITEM_DECLARE__ // #endif // __SCENE_DATA_FILE_TREE_ITEM_DECLARE__ } // namespace #endif //__SCENE_DATA_FILE_TREE_ITEM_H__ connectome-workbench-1.4.2/src/GuiQt/SceneDataFileTreeItemModel.cxx000066400000000000000000000321321360521144700252470ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SCENE_DATA_FILE_TREE_ITEM_MODEL_DECLARE__ #include "SceneDataFileTreeItemModel.h" #undef __SCENE_DATA_FILE_TREE_ITEM_MODEL_DECLARE__ #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "FileInformation.h" #include "SceneDataFileTreeItem.h" using namespace caret; static bool debugFlag(false); /** * \class caret::SceneDataFileTreeItemModel * \brief Tree item model for hierarchical list of files in a scene file * \ingroup GuiQt */ /** * Constructor. * * @param sceneFilePathAndName * Scene file path and name. * @param baseDirectoryPath * Path of the base directory. * @param sceneDataFileInfo * The scene file info. * @param sortMode * The sorting mode. */ SceneDataFileTreeItemModel::SceneDataFileTreeItemModel(const AString& sceneFilePathAndName, const AString& baseDirectoryPath, const std::vector& sceneDataFileInfo, const SceneDataFileInfo::SortMode sortMode) : QStandardItemModel() { if ( ! baseDirectoryPath.isEmpty()) { /* * Add a root element to the tree containing the base path */ addDirectory(baseDirectoryPath, ""); } if ( ! sceneFilePathAndName.isEmpty()) { /* * Add the scene file and highlight the name to make it stand out from other files */ SceneDataFileTreeItem* sceneFileItem = addFile(sceneFilePathAndName, ""); CaretAssert(sceneFileItem); QFont font = sceneFileItem->font(); font.setBold(true); sceneFileItem->setFont(font); } /* * Add the data files */ for (const auto dataFileInfo : sceneDataFileInfo) { AString pathName; AString pathAndFileName; switch (sortMode) { case SceneDataFileInfo::SortMode::AbsolutePath: pathName = dataFileInfo.getAbsolutePath(); pathAndFileName = dataFileInfo.getAbsolutePathAndFileName(); break; case SceneDataFileInfo::SortMode::RelativeToBasePath: pathName = dataFileInfo.getRelativePathToBasePath(); pathAndFileName = (dataFileInfo.getRelativePathToBasePath() + "/" + dataFileInfo.getDataFileName()); break; case SceneDataFileInfo::SortMode::RelativeToSceneFilePath: pathName = dataFileInfo.getRelativePathToSceneFile(); pathAndFileName = (dataFileInfo.getRelativePathToSceneFile() + "/" + dataFileInfo.getDataFileName()); break; } addFile(pathAndFileName, dataFileInfo.getSceneIndicesAsString()); } } /** * Destructor. */ SceneDataFileTreeItemModel::~SceneDataFileTreeItemModel() { } /** * Find or add all components in a directory path. * @param absoluteDirName * Full path of directory. * @return * Tree item containing directory with the given name. */ SceneDataFileTreeItem* SceneDataFileTreeItemModel::addFindDirectoryPath(const AString& absoluteDirName) { SceneDataFileTreeItem* directoryItemOut = findDirectory(absoluteDirName); if (directoryItemOut == NULL) { const AString httpsPrefix("https://"); AString rootPrefix("/"); AString nameForSplitting(absoluteDirName); if (absoluteDirName.startsWith(httpsPrefix)) { nameForSplitting = absoluteDirName.mid(httpsPrefix.length()); rootPrefix = httpsPrefix; } QStringList components(nameForSplitting.split("/", QString::SkipEmptyParts)); const int32_t componentCount = components.length(); std::vector parentDirectoryHierarchy; /* * Create a vector containing all directory paths * in the hierarchy as absolute paths. This is necessary * to avoid duplicating a hierarchy that matches the * base path. */ AString dirName; AString parentDirName; for (int32_t i = 0; i < componentCount; i++) { if (i == 0) { if (absoluteDirName.startsWith(rootPrefix)) { dirName = rootPrefix; parentDirectoryHierarchy.push_back(dirName); } } parentDirName = dirName; if ( ! dirName.isEmpty()) { if ( ! dirName.endsWith('/')) { dirName.append("/"); } } dirName.append(components.at(i)); parentDirectoryHierarchy.push_back(dirName); } if (debugFlag) { std::cout << "Parent directory hierarchy: " << std::endl; for (const auto s : parentDirectoryHierarchy) { std::cout << " " << s << std::endl; } } /* * Start at the deepest directory path and work way up * to find the deepest existing path. */ int32_t iStart(0); const int32_t numDirs = static_cast(parentDirectoryHierarchy.size()); for (int32_t iDir = (numDirs - 1); iDir >= 0; iDir--) { CaretAssertVectorIndex(parentDirectoryHierarchy, iDir); SceneDataFileTreeItem* dirItem = findDirectory(parentDirectoryHierarchy[iDir]); if (dirItem != NULL) { iStart = iDir + 1; break; } } if (iStart < numDirs) { /* * Create directories that are children of the deepest existing path */ for (int32_t iDir = iStart; iDir < numDirs; iDir++) { AString parentDirName; if (iDir > 0) { CaretAssertVectorIndex(parentDirectoryHierarchy, iDir - 1); parentDirName = parentDirectoryHierarchy[iDir - 1]; } CaretAssertVectorIndex(parentDirectoryHierarchy, iDir); if (debugFlag) { std::cout << "Creating directory " << parentDirectoryHierarchy[iDir] << " with parent " << parentDirName << std::endl; } addDirectory(parentDirectoryHierarchy[iDir], parentDirName); } } directoryItemOut = findDirectory(absoluteDirName); CaretAssert(directoryItemOut); } return directoryItemOut; } /** * Add a directory. If directory already in tree, the existing item is returned. * * @param absoluteDirName * Full path of directory. * @param absoluteParentDirName * Full path of parent directory. * @return * Tree item containing directory. */ SceneDataFileTreeItem* SceneDataFileTreeItemModel::addDirectory(const AString& absoluteDirName, const AString& absoluteParentDirName) { SceneDataFileTreeItem* directoryItemOut = findDirectory(absoluteDirName); if (directoryItemOut == NULL) { if (absoluteParentDirName.isEmpty()) { directoryItemOut = new SceneDataFileTreeItem(absoluteDirName, absoluteDirName, SceneDataFileTreeItem::getItemTypeDirectory()); invisibleRootItem()->appendRow(directoryItemOut); m_directoryToTreeItemMap.insert(std::make_pair(absoluteDirName, directoryItemOut)); if (debugFlag) { std::cout << "Added root directory: " << absoluteDirName << std::endl; } } else { SceneDataFileTreeItem* parentDirItem = findDirectory(absoluteParentDirName); if (parentDirItem != NULL) { FileInformation dirInfo(absoluteDirName); const AString name = dirInfo.getFileName(); directoryItemOut = new SceneDataFileTreeItem(name, absoluteDirName, SceneDataFileTreeItem::getItemTypeDirectory()); parentDirItem->appendRow(directoryItemOut); m_directoryToTreeItemMap.insert(std::make_pair(absoluteDirName, directoryItemOut)); if (debugFlag) { std::cout << "Added directory " << name << " to parent " << absoluteParentDirName << std::endl; } } else { CaretLogSevere("Unable to find parent directory named " + absoluteParentDirName + " for " + absoluteDirName); } } } return directoryItemOut; } /** * Find a directory with the given directory name. * * @param absoluteDirName * Full path including directory. * @return * Tree item containing directory or NULL if not found. */ SceneDataFileTreeItem* SceneDataFileTreeItemModel::findDirectory(const AString& absoluteDirName) { SceneDataFileTreeItem* directoryItemOut = NULL; auto iter = m_directoryToTreeItemMap.find(absoluteDirName); if (iter != m_directoryToTreeItemMap.end()) { directoryItemOut = iter->second; } return directoryItemOut; } /** * Add a file. If file already in tree, the existing item is returned. * * @param absoluteFilePathAndName * Full path including directory and filename. * @param sceneIndicesText * Text containing indices of scenes using file. * @return * Tree item containing file. */ SceneDataFileTreeItem* SceneDataFileTreeItemModel::addFile(const AString& absoluteFilePathAndName, const AString& sceneIndicesText) { SceneDataFileTreeItem* fileItemOut = findFile(absoluteFilePathAndName); if (fileItemOut == NULL) { FileInformation fileInfo(absoluteFilePathAndName); /* * First look for parent directory, which may be the base directory. */ SceneDataFileTreeItem* directoryItem = findDirectory(fileInfo.getAbsolutePath()); if (directoryItem == NULL) { /* * Start looking/adding directory from root down to file's parent */ directoryItem = addFindDirectoryPath(fileInfo.getAbsolutePath()); } if (directoryItem != NULL) { AString itemText(fileInfo.getFileName()); if ( ! sceneIndicesText.isEmpty()) { itemText.append(" (" + sceneIndicesText + ")"); } fileItemOut = new SceneDataFileTreeItem(itemText, absoluteFilePathAndName, SceneDataFileTreeItem::getItemTypeFile()); directoryItem->appendRow(fileItemOut); m_fileNameToTreeItemMap.insert(std::make_pair(absoluteFilePathAndName, fileItemOut)); } else { CaretLogSevere("Failed to find directory named " + fileInfo.getAbsolutePath() + " for inserting file named " + fileInfo.getFileName()); } } return fileItemOut; } /** * Find a file with the given filename. * * @param absoluteFilePathAndName * Full path including directory and filename. * @return * Tree item containing file or NULL if not found. */ SceneDataFileTreeItem* SceneDataFileTreeItemModel::findFile(const AString& absoluteFilePathAndName) { SceneDataFileTreeItem* fileItemOut = NULL; auto iter = m_fileNameToTreeItemMap.find(absoluteFilePathAndName); if (iter != m_fileNameToTreeItemMap.end()) { fileItemOut = iter->second; } return fileItemOut; } connectome-workbench-1.4.2/src/GuiQt/SceneDataFileTreeItemModel.h000066400000000000000000000053771360521144700247070ustar00rootroot00000000000000#ifndef __SCENE_DATA_FILE_TREE_ITEM_MODEL_H__ #define __SCENE_DATA_FILE_TREE_ITEM_MODEL_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "SceneDataFileInfo.h" namespace caret { class SceneDataFileTreeItem; class SceneDataFileTreeItemModel : public QStandardItemModel { Q_OBJECT public: SceneDataFileTreeItemModel(const AString& sceneFilePathAndName, const AString& baseDirectoryPath, const std::vector& sceneDataFileInfo, const SceneDataFileInfo::SortMode sortMode); virtual ~SceneDataFileTreeItemModel(); SceneDataFileTreeItemModel(const SceneDataFileTreeItemModel&) = delete; SceneDataFileTreeItemModel& operator=(const SceneDataFileTreeItemModel&) = delete; SceneDataFileTreeItem* addFindDirectoryPath(const AString& absoluteDirName); SceneDataFileTreeItem* addDirectory(const AString& absoluteDirName, const AString& absoluteParentDirName); SceneDataFileTreeItem* findDirectory(const AString& absoluteDirName); SceneDataFileTreeItem* addFile(const AString& absoluteFilePathAndName, const AString& sceneIndicesText); SceneDataFileTreeItem* findFile(const AString& absoluteFilePathAndName); // ADD_NEW_METHODS_HERE private: std::map m_directoryToTreeItemMap; std::map m_fileNameToTreeItemMap; // ADD_NEW_MEMBERS_HERE }; #ifdef __SCENE_DATA_FILE_TREE_ITEM_MODEL_DECLARE__ // #endif // __SCENE_DATA_FILE_TREE_ITEM_MODEL_DECLARE__ } // namespace #endif //__SCENE_DATA_FILE_TREE_ITEM_MODEL_H__ connectome-workbench-1.4.2/src/GuiQt/SceneDialog.cxx000066400000000000000000003366541360521144700223750ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define __SCENE_DIALOG_DECLARE__ #include "SceneDialog.h" #undef __SCENE_DIALOG_DECLARE__ #include "Annotation.h" #include "AnnotationManager.h" #include "ApplicationInformation.h" #include "BalsaDatabaseUploadSceneFileDialog.h" #include "Brain.h" #include "BrainBrowserWindow.h" #include "BrainConstants.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretFileDialog.h" #include "CaretLogger.h" #include "CaretMappableDataFile.h" #include "CursorDisplayScoped.h" #include "CaretPreferences.h" #include "DataFileException.h" #include "ElapsedTimer.h" #include "EventBrowserTabGetAll.h" #include "EventDataFileAdd.h" #include "EventDataFileRead.h" #include "EventDataFileReload.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventImageCapture.h" #include "EventManager.h" #include "EventModelGetAll.h" #include "EventHelpViewerDisplay.h" #include "EventUserInterfaceUpdate.h" #include "EventShowDataFileReadWarningsDialog.h" #include "EventSceneActive.h" #include "FileInformation.h" #include "GuiManager.h" #include "ImageFile.h" #include "ProgressReportingDialog.h" #include "Scene.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneCreateReplaceDialog.h" #include "SceneFile.h" #include "SceneFileInformationDialog.h" #include "SceneInfo.h" #include "ScenePreviewDialog.h" #include "SceneReplaceAllDialog.h" #include "SceneShowOptionsDialog.h" #include "SessionManager.h" #include "UsernamePasswordWidget.h" #include "WuQDataEntryDialog.h" #include "WuQDialogNonModal.h" #include "WuQMessageBox.h" #include "WuQTextEditorDialog.h" #include "WuQtUtilities.h" #include "WuQWidgetObjectGroup.h" #include "ZipSceneFileDialog.h" using namespace caret; /** * \class caret::SceneDialog * \brief Dialog for manipulation of scenes. * \ingroup GuiQt */ /** * Constructor. * * @param parent * The parent widget. */ SceneDialog::SceneDialog(QWidget* parent) : WuQDialogNonModal("Scenes", parent) { m_selectedSceneClassInfoIndex = -1; m_replaceAllScenesDescription = ("This operation may be slow as it loads and replaces all scenes."); m_testAllScenesDescription = ("This operation may be slow as it requires displaying all scenes. " "\n" "Each scene is displayed and an image of the graphic(s) regions is generated " "from the scene. After all scenes have been loaded, a dialog is " "displayed that shows a scene's preview image on the left and " "on the right, the image created by loading the scene. If the " "two images do not match, it indicates a problem with the scene. " "Possible problems include data files missing, data files that " "have changed, or a change to the software."); m_testAllScenesDescription = WuQtUtilities::createWordWrappedToolTipText(m_testAllScenesDescription); /* * No apply buton and show help button */ setApplyButtonText(""); setStandardButtonText(QDialogButtonBox::Help, "Help"); /* * Icons */ m_cautionIconValid = WuQtUtilities::loadIcon(":/SceneFileDialog/caution.png", m_cautionIcon); /* * Set the dialog's widget */ this->setCentralWidget(createScenesWidget(), WuQDialog::SCROLL_AREA_NEVER); /* * No auto default button processing (Qt highlights button) */ disableAutoDefaultForAllPushButtons(); setSaveWindowPositionForNextTime(true); /* * Update the dialog. */ updateDialog(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); /* * Need to use a "processed" event listener for file read and reload events * so that our receiveEvent() method is called after the files have been * read. */ EventManager::get()->addProcessedEventListener(this, EventTypeEnum::EVENT_DATA_FILE_ADD); EventManager::get()->addProcessedEventListener(this, EventTypeEnum::EVENT_DATA_FILE_READ); EventManager::get()->addProcessedEventListener(this, EventTypeEnum::EVENT_DATA_FILE_RELOAD); resize(900, 700); } /** * Destructor. */ SceneDialog::~SceneDialog() { EventManager::get()->removeAllEventsFromListener(this); } /** * Process a close event. * * @param event * The close event. */ void SceneDialog::closeEvent(QCloseEvent* event) { WuQDialogNonModal::closeEvent(event); } /** * Called when the close button is clicked. */ void SceneDialog::closeButtonClicked() { /* * If there are any modified scene files, inform the user */ Brain* brain = GuiManager::get()->getBrain(); const int32_t numSceneFiles = brain->getNumberOfSceneFiles(); int32_t numberOfModifiedSceneFiles = 0; for (int32_t i = 0; i < numSceneFiles; i++) { const SceneFile* sceneFile = brain->getSceneFile(i); if (sceneFile->isModified()) { numberOfModifiedSceneFiles++; } } bool allowToCloseFlag = true; if (numberOfModifiedSceneFiles > 0) { const AString msg("There are modified scene file(s). You can save modified scene files using File Menu->Save/Manage Files " "or by selecting them on the Scene Dialog and using the Save/Save As buttons.

    " "Continue closing this Scene Dialog?"); if ( ! WuQMessageBox::warningOkCancel(this, msg)) { allowToCloseFlag = false; } } if (allowToCloseFlag) { WuQDialogNonModal::closeButtonClicked(); } } /** * Update the scene dialog. */ void SceneDialog::updateDialog() { loadSceneFileComboBox(NULL); loadScenesIntoDialog(NULL); updateSceneFileModifiedStatusLabel(); } /** * Create the default scene file if * there are any models and there are no * scene files. */ void SceneDialog::createDefaultSceneFile() { if (getSelectedSceneFile() == NULL) { EventModelGetAll allModelsEvent; EventManager::get()->sendEvent(allModelsEvent.getPointer()); if ( ! allModelsEvent.getModels().empty()) { newSceneFileButtonClicked(); } } } /** * Get the selected scene file. * @return SceneFile or NULL if no scene file. */ SceneFile* SceneDialog::getSelectedSceneFile() { SceneFile* sceneFile = NULL; const int fileComboBoxIndex = m_sceneFileSelectionComboBox->currentIndex(); if (fileComboBoxIndex >= 0) { void* filePointer = m_sceneFileSelectionComboBox->itemData(fileComboBoxIndex).value(); sceneFile = (SceneFile*)filePointer; } return sceneFile; } /** * @return The selected scene. */ Scene* SceneDialog::getSelectedScene() { Scene* selectedScene = NULL; SceneFile* sceneFile = getSelectedSceneFile(); if (sceneFile != NULL) { int32_t numValidScenes = sceneFile->getNumberOfScenes(); bool selectedSceneChanged = false; if (m_selectedSceneClassInfoIndex >= numValidScenes) { m_selectedSceneClassInfoIndex = numValidScenes - 1; selectedSceneChanged = true; } if (m_selectedSceneClassInfoIndex < 0) { if (numValidScenes > 0) { m_selectedSceneClassInfoIndex = 0; selectedSceneChanged = true; } } if ((m_selectedSceneClassInfoIndex >= 0) && (m_selectedSceneClassInfoIndex < numValidScenes)) { selectedScene = sceneFile->getSceneAtIndex(m_selectedSceneClassInfoIndex); } if (selectedSceneChanged) { highlightSceneAtIndex(m_selectedSceneClassInfoIndex); } } return selectedScene; } /** * Update the modified icons in the scene file combo box. */ void SceneDialog::updateSceneFileComboBoxModifiedIcons() { if ( ! m_cautionIconValid) { return; } m_sceneFileSelectionComboBox->blockSignals(true); const int32_t numItems = m_sceneFileSelectionComboBox->count(); for (int32_t itemIndex = 0; itemIndex < numItems; itemIndex++) { void* filePointer = m_sceneFileSelectionComboBox->itemData(itemIndex).value(); SceneFile* sceneFile = (SceneFile*)filePointer; CaretAssert(sceneFile); if (sceneFile->isModified()) { m_sceneFileSelectionComboBox->setItemIcon(itemIndex, m_cautionIcon); } else { m_sceneFileSelectionComboBox->setItemIcon(itemIndex, QIcon()); } } m_sceneFileSelectionComboBox->blockSignals(false); /* comment */ } /** * Load the scene files into the scene file combo box. * * @param selectedSceneFileIn * Scene file that is added. */ void SceneDialog::loadSceneFileComboBox(SceneFile* selectedSceneFileIn) { SceneFile* selectedSceneFile = selectedSceneFileIn; if (selectedSceneFile == NULL) { selectedSceneFile = getSelectedSceneFile(); } Brain* brain = GuiManager::get()->getBrain(); const int32_t numSceneFiles = brain->getNumberOfSceneFiles(); m_sceneFileSelectionComboBox->clear(); int defaultFileComboIndex = 0; for (int32_t i = 0; i < numSceneFiles; i++) { SceneFile* sceneFile = brain->getSceneFile(i); if (sceneFile == selectedSceneFile) { defaultFileComboIndex = i; } const AString name = sceneFile->getFileNameNoPath(); if (sceneFile->isModified() && m_cautionIconValid) { m_sceneFileSelectionComboBox->addItem(m_cautionIcon, name, qVariantFromValue((void*)sceneFile)); } else { m_sceneFileSelectionComboBox->addItem(name, qVariantFromValue((void*)sceneFile)); } } if (numSceneFiles > 0) { m_sceneFileSelectionComboBox->setCurrentIndex(defaultFileComboIndex); } m_sceneFileButtonsGroup->setEnabled(getSelectedSceneFile() != NULL); updateSceneFileModifiedStatusLabel(); } /** * Load the scene into the dialog. * * @param selectedSceneIn * Scene to add. */ void SceneDialog::loadScenesIntoDialog(Scene* selectedSceneIn) { SceneFile* sceneFile = getSelectedSceneFile(); Scene* selectedScene = selectedSceneIn; if (selectedScene == NULL) { selectedScene = getSelectedScene(); } EventSceneActive activeSceneEvent(EventSceneActive::MODE_GET); EventManager::get()->sendEvent(activeSceneEvent.getPointer()); const Scene* activeScene = activeSceneEvent.getScene(); for (std::vector::iterator iter = m_sceneClassInfoWidgets.begin(); iter != m_sceneClassInfoWidgets.end(); iter++) { SceneClassInfoWidget* sciw = *iter; sciw->blockSignals(true); sciw->updateContent(NULL, -1, false); } int32_t numberOfValidSceneInfoWidgets = 0; int32_t defaultIndex = -1; if (sceneFile != NULL) { const int32_t numScenes = sceneFile->getNumberOfScenes(); for (int32_t i = 0; i < numScenes; i++) { Scene* scene = sceneFile->getSceneAtIndex(i); QByteArray imageByteArray; AString imageBytesFormat; scene->getSceneInfo()->getImageBytes(imageByteArray, imageBytesFormat); SceneClassInfoWidget* sciw = NULL; if (i >= static_cast(m_sceneClassInfoWidgets.size())) { sciw = new SceneClassInfoWidget(); QObject::connect(sciw, SIGNAL(activated(int32_t)), this, SLOT(sceneActivated(int32_t))); QObject::connect(sciw, SIGNAL(highlighted(int32_t)), this, SLOT(sceneHighlighted(int32_t))); m_sceneClassInfoWidgets.push_back(sciw); m_sceneSelectionLayout->addWidget(sciw, 1); } else { sciw = m_sceneClassInfoWidgets[i]; } const bool activeSceneFlag(scene == activeScene); sciw->updateContent(scene, i, activeSceneFlag); sciw->setBackgroundForSelected(i == 1); if (scene == selectedScene) { defaultIndex = i; } else if (defaultIndex < 0) { defaultIndex = i; } } numberOfValidSceneInfoWidgets = numScenes; } const int32_t numberOfSceneInfoWidgets = static_cast(m_sceneClassInfoWidgets.size()); for (int32_t i = 0; i < numberOfSceneInfoWidgets; i++) { bool visibilityStatus = false; if (i < numberOfValidSceneInfoWidgets) { visibilityStatus = true; } m_sceneClassInfoWidgets[i]->setVisible(visibilityStatus); m_sceneClassInfoWidgets[i]->blockSignals(false); } if (defaultIndex >= 0) { highlightSceneAtIndex(defaultIndex); } const bool validFile = (getSelectedSceneFile() != NULL); bool validScene = false; bool haveScenes = false; if (validFile) { const Scene* scene = getSelectedScene(); if (scene != NULL) { validScene = true; } haveScenes = (sceneFile->getNumberOfScenes() > 0); } enableSceneMoveUpAndDownButtons(); m_addNewScenePushButton->setEnabled(validFile); m_deleteScenePushButton->setEnabled(validScene); if (m_replaceAllScenesPushButton != NULL) { m_replaceAllScenesPushButton->setEnabled(haveScenes); } m_testScenesPushButton->setEnabled(haveScenes); m_insertNewScenePushButton->setEnabled(validScene); m_replaceScenePushButton->setEnabled(validScene); m_showScenePushButton->setEnabled(validScene); m_showSceneImagePreviewPushButton->setEnabled(validScene); m_showSceneOptionsPushButton->setEnabled(validScene); } /** * @return Number of valid scene info widgets. */ int32_t SceneDialog::getNumberOfValidSceneInfoWidgets() const { int32_t numValid = 0; for (auto ssiw : m_sceneClassInfoWidgets) { if (ssiw->isValid()) { numValid++; } } return numValid; } /** * Enable the move up/down buttons */ void SceneDialog::enableSceneMoveUpAndDownButtons() { const int32_t numberOfSceneInfoWidgets = getNumberOfValidSceneInfoWidgets(); m_moveSceneUpPushButton->setEnabled(m_selectedSceneClassInfoIndex > 0); m_moveSceneDownPushButton->setEnabled((m_selectedSceneClassInfoIndex >= 0) && (m_selectedSceneClassInfoIndex < (numberOfSceneInfoWidgets - 1))); } /** * Highlight the scene at the given index. * * @param sceneIndex * Index of scene to highlight. */ void SceneDialog::highlightSceneAtIndex(const int32_t sceneIndex) { bool sceneIndexValid = false; const int32_t numberOfSceneInfoWidgets = static_cast(m_sceneClassInfoWidgets.size()); for (int32_t i = 0; i < numberOfSceneInfoWidgets; i++) { SceneClassInfoWidget* sciw = m_sceneClassInfoWidgets[i]; if (sciw->isValid()) { if (sciw->getSceneIndex() == sceneIndex) { sciw->setBackgroundForSelected(true); sceneIndexValid = true; m_selectedSceneClassInfoIndex = i; /* * Ensure that the selected scene remains visible * and do not alter value of horiztonal scroll bar */ const int horizValue = m_sceneSelectionScrollArea->horizontalScrollBar()->value(); const int xMargin = 0; const int yMargin = 50; m_sceneSelectionScrollArea->ensureWidgetVisible(sciw, xMargin, yMargin); m_sceneSelectionScrollArea->horizontalScrollBar()->setSliderPosition(horizValue); } else { sciw->setBackgroundForSelected(false); } } } if ( ! sceneIndexValid) { m_selectedSceneClassInfoIndex = -1; } enableSceneMoveUpAndDownButtons(); } /** * Highlight the given scene. * * @param scene * Scene to highlight. */ void SceneDialog::highlightScene(const Scene* scene) { const int32_t numberOfSceneInfoWidgets = static_cast(m_sceneClassInfoWidgets.size()); for (int32_t i = 0; i < numberOfSceneInfoWidgets; i++) { SceneClassInfoWidget* sciw = m_sceneClassInfoWidgets[i]; if (sciw->isValid()) { if (sciw->getScene() == scene) { highlightSceneAtIndex(sciw->getSceneIndex()); return; } } } } /** * Called to open a scene file. */ void SceneDialog::openSceneFileButtonClicked() { if ( ! displayNewSceneWarning()) { return; } if ( ! warnIfSceneFileIsModified(ModifiedWarningType::OPEN_FILE_BUTTON)) { return; } /* * Let user choose a different path/name */ AString openSceneFileName = CaretFileDialog::getOpenFileNameDialog(DataFileTypeEnum::SCENE, m_openSceneFilePushButton, "Open a Scene File", ""); /* * If user cancels, return */ if (openSceneFileName.isEmpty()) { return; } CursorDisplayScoped cursor; cursor.showWaitCursor(); /* * Note that this dialog receives EventDataFileRead * as a post-processed event and will take care of * the dialog updates. */ EventDataFileRead dataFileEvent(GuiManager::get()->getBrain()); dataFileEvent.addDataFile(DataFileTypeEnum::SCENE, openSceneFileName); EventManager::get()->sendEvent(dataFileEvent.getPointer()); EventManager::get()->sendEvent(EventShowDataFileReadWarningsDialog().getPointer()); } /** * Called to create a new scene file. */ void SceneDialog::newSceneFileButtonClicked() { if ( ! displayNewSceneWarning()) { return; } if ( ! warnIfSceneFileIsModified(ModifiedWarningType::NEW_FILE_BUTTON)) { return; } SceneFile* newSceneFile = new SceneFile(); GuiManager::get()->getBrain()->convertDataFilePathNameToAbsolutePathName(newSceneFile); newSceneFile->clearModified(); /* * Note that this dialog receives EventDataFileAdd * as a post-processed event and will take care of * the dialog updates. */ EventManager::get()->sendEvent(EventDataFileAdd(newSceneFile).getPointer()); } /** * Save the selected scene file. */ void SceneDialog::saveSceneFileButtonClicked() { saveSelectedSceneFile(); } /** * Save the selected scene file with a new name. */ void SceneDialog::saveAsSceneFileButtonClicked() { saveAsSelectedSceneFile(); } /** * Save the selected scene file using the file' current name. * * @return True if file was saved else false and an error message is displayed. */ bool SceneDialog::saveSelectedSceneFile() { SceneFile* sceneFile = getSelectedSceneFile(); if (sceneFile == NULL) { WuQMessageBox::errorOk(m_saveSceneFilePushButton, "There is no selected scene file to save"); return false; } try { CursorDisplayScoped cursor; cursor.showWaitCursor(); Brain* brain = GuiManager::get()->getBrain(); brain->writeDataFile(sceneFile); } catch (const DataFileException& e) { WuQMessageBox::errorOk(m_saveSceneFilePushButton, e.whatString()); return false; } loadSceneFileComboBox(sceneFile); return true; } /** * Save the selected scene file with display of a file selection dialog using the file' current name. * * @return True if file was saved else false and an error message is displayed. */ bool SceneDialog::saveAsSelectedSceneFile() { SceneFile* sceneFile = getSelectedSceneFile(); if (sceneFile == NULL) { WuQMessageBox::errorOk(m_saveAsSceneFilePushButton, "There is no selected scene file to save"); return false; } const AString filename = CaretFileDialog::getSaveFileNameDialog(sceneFile->getDataFileType(), m_saveAsSceneFilePushButton, "Save Scene File As", sceneFile->getFileName()); if (filename.isEmpty()) { return false; } try { CursorDisplayScoped cursor; cursor.showWaitCursor(); sceneFile->setFileName(filename); Brain* brain = GuiManager::get()->getBrain(); brain->writeDataFile(sceneFile); } catch (const DataFileException& e) { WuQMessageBox::errorOk(m_saveAsSceneFilePushButton, e.whatString()); return false; } loadSceneFileComboBox(sceneFile); return true; } /** * If the selected scene file is modified, warn the user and * suggest saving the file prior to continuing. * * @param warningType * Type of warning. * @return * True if the operation should continue, else false. */ bool SceneDialog::warnIfSceneFileIsModified(const ModifiedWarningType warningType) { const SceneFile* sceneFile = getSelectedSceneFile(); if (sceneFile == NULL) { return true; } if ( ! sceneFile->isModified()) { return true; } /** * Return true if warning is disabled for an operation */ switch (warningType) { case ModifiedWarningType::CLOSE_DIALOG_BUTTON: break; case ModifiedWarningType::FILE_COMBO_BOX_CHANGE_FILE: return true; break; case ModifiedWarningType::NEW_FILE_BUTTON: return true; break; case ModifiedWarningType::OPEN_FILE_BUTTON: return true; break; case ModifiedWarningType::UPLOAD_FILE_BUTTON: break; case ModifiedWarningType::ZIP_FILE_BUTTON: break; } /* * Parent for message box dialogs */ QWidget* messageBoxParent = NULL; switch (warningType) { case ModifiedWarningType::CLOSE_DIALOG_BUTTON: messageBoxParent = this; break; case ModifiedWarningType::FILE_COMBO_BOX_CHANGE_FILE: messageBoxParent = m_sceneFileSelectionComboBox; break; case ModifiedWarningType::NEW_FILE_BUTTON: messageBoxParent = m_newSceneFilePushButton; break; case ModifiedWarningType::OPEN_FILE_BUTTON: messageBoxParent = m_openSceneFilePushButton; break; case ModifiedWarningType::UPLOAD_FILE_BUTTON: messageBoxParent = m_uploadSceneFilePushButton; break; case ModifiedWarningType::ZIP_FILE_BUTTON: messageBoxParent = m_zipSceneFilePushButton; break; } CaretAssert(messageBoxParent); if (sceneFile->getNumberOfScenes() <= 0) { switch (warningType) { case ModifiedWarningType::CLOSE_DIALOG_BUTTON: return true; break; case ModifiedWarningType::FILE_COMBO_BOX_CHANGE_FILE: return true; break; case ModifiedWarningType::NEW_FILE_BUTTON: return true; break; case ModifiedWarningType::OPEN_FILE_BUTTON: return true; break; case ModifiedWarningType::UPLOAD_FILE_BUTTON: break; case ModifiedWarningType::ZIP_FILE_BUTTON: break; } WuQMessageBox::errorOk(messageBoxParent, "There are no scenes in the scene file !"); return false; } bool enableContinueButton = false; bool enableSaveButton = sceneFile->exists(); QMessageBox::Icon messageBoxIcon = QMessageBox::NoIcon; /* * Set up the informative text */ AString saveText = ("Press the Save button to save the scene file with its current name "); AString saveAsText = ("Press the Save As button to save the scene file to a new name using a file dialog "); AString continueText = ("Press the Continue button to skip saving the scene file (you may save it at a later time) "); AString cancelText = ("Press the Cancel button to skip saving the scene file and "); switch (warningType) { case ModifiedWarningType::CLOSE_DIALOG_BUTTON: messageBoxIcon = QMessageBox::Warning; enableContinueButton = true; saveText.append("and close the scene dialog"); saveAsText.append("and close the scene dialog"); continueText.append("and close the scene dialog"); cancelText.append("do not close the scene dialog"); break; case ModifiedWarningType::FILE_COMBO_BOX_CHANGE_FILE: messageBoxIcon = QMessageBox::Warning; enableContinueButton = true; saveText.append("and change the selected scene file"); saveAsText.append("and change the selected scene file"); continueText.append("and change the selected scene file"); cancelText.append("cancel changing the selected scene file"); break; case ModifiedWarningType::NEW_FILE_BUTTON: messageBoxIcon = QMessageBox::Warning; enableContinueButton = true; saveText.append(" and create a new scene file"); saveAsText.append(" and create a new scene file"); continueText.append(" and create a new scene file"); cancelText.append("cancel creation of a new scene file"); break; case ModifiedWarningType::OPEN_FILE_BUTTON: messageBoxIcon = QMessageBox::Warning; enableContinueButton = true; saveText.append("and display a dialog for opening a scene file"); saveAsText.append("and display a dialog for opening a scene file"); continueText.append("and display a dialog for opening a scene file"); cancelText.append("cancel opening a scene file"); break; case ModifiedWarningType::UPLOAD_FILE_BUTTON: messageBoxIcon = QMessageBox::Warning; saveText.append("and continue uploading the scene file"); saveAsText.append("and continue uploading the scene file"); continueText.append(""); cancelText.append("cancel uploading the scene file"); break; case ModifiedWarningType::ZIP_FILE_BUTTON: messageBoxIcon = QMessageBox::Warning; saveText.append("and zip the scene file"); saveAsText.append("and zip the scene file"); continueText.append("and zip the scene file"); cancelText.append("and cancel zipping the scene file"); break; } AString informativeText(""); if (enableSaveButton) { informativeText.append(saveText + "

    "); } informativeText.append(saveAsText + "

    "); if (enableContinueButton) { informativeText.append(continueText + "

    "); } informativeText.append(cancelText + "

    "); informativeText.append(""); /* * Create and display the message box dialog */ QMessageBox messageBox(messageBoxParent); messageBox.setText("The selected scene file has been modified but not saved: " + sceneFile->getFileNameNoPath()); messageBox.setInformativeText(informativeText); messageBox.setIcon(messageBoxIcon); QPushButton* saveButton = NULL; if (enableSaveButton) { saveButton = messageBox.addButton("Save", QMessageBox::AcceptRole); } QPushButton* saveAsButton = messageBox.addButton("Save As...", QMessageBox::AcceptRole); QPushButton* cancelButton = messageBox.addButton("Cancel", QMessageBox::NoRole); QPushButton* continueButton = NULL; if (enableContinueButton) { continueButton = messageBox.addButton("Continue", QMessageBox::AcceptRole); } if (saveButton != NULL) { messageBox.setDefaultButton(saveButton); } else { messageBox.setDefaultButton(saveAsButton); } messageBox.exec(); QAbstractButton* button = messageBox.clickedButton(); CaretAssert(button); bool successFlag = false; if (button == saveButton) { successFlag = saveSelectedSceneFile(); } else if (button == saveAsButton) { successFlag = saveAsSelectedSceneFile(); } else if (button == cancelButton) { successFlag = false; } else if (button == continueButton) { successFlag = true; } else { CaretAssertMessage(0, "Button clicked not handled " + button->text()); } return successFlag; } /** * Display a message if there are missing files in the Scene File. * * @param missingFilesMode * The missing file mode. * @return * True if there are no missing files, else false. */ bool SceneDialog::warnIfMissingFilesInSceneFile(SceneFile* sceneFile, const MissingFilesMode missingFilesMode) { CaretAssert(sceneFile); AString baseDirectoryName; std::vector missingFileNames; AString errorMessage; sceneFile->findBaseDirectoryForDataFiles(baseDirectoryName, missingFileNames, errorMessage); if (missingFileNames.empty()) { return true; } AString verbText; AString acceptButtonText; switch (missingFilesMode) { case MissingFilesMode::UPLOAD: acceptButtonText = "Upload"; verbText = "uploading to BALSA"; break; case MissingFilesMode::ZIP: acceptButtonText = "Zip"; verbText = "zipping the scene file"; break; } const AString labelText("Do you want to continue " + verbText + " ?"); AString text; for (auto name : missingFileNames) { text.append(name + "\n"); } WuQDataEntryDialog dialog("Data Files Not Found", this, false); dialog.setTextAtTop("These data files were not found but are used by scenes in the scene file. Scenes may not display correctly. " + labelText, true); dialog.addTextEdit("", text, true); dialog.setMinimumWidth(500); if (dialog.exec() == WuQDataEntryDialog::Accepted) { return true; } return false; } /** * Called when upload scene file is selected. */ void SceneDialog::uploadSceneFileButtonClicked() { if ( ! warnIfSceneFileIsModified(ModifiedWarningType::UPLOAD_FILE_BUTTON)) { return; } SceneFile* sceneFile = getSelectedSceneFile(); if ( ! warnIfMissingFilesInSceneFile(sceneFile, MissingFilesMode::UPLOAD)) { return; } BalsaDatabaseUploadSceneFileDialog uploadDialog(sceneFile, this); uploadDialog.exec(); /* Scene ID may have been added and it is shown in info section for each scene */ loadScenesIntoDialog(NULL); updateSceneFileModifiedStatusLabel(); } /** * Called when zip scene file is selected. */ void SceneDialog::zipSceneFileButtonClicked() { if ( ! warnIfSceneFileIsModified(ModifiedWarningType::ZIP_FILE_BUTTON)) { return; } SceneFile* sceneFile = getSelectedSceneFile(); if ( ! warnIfMissingFilesInSceneFile(sceneFile, MissingFilesMode::ZIP)) { return; } ZipSceneFileDialog zipDialog(sceneFile, this); zipDialog.exec(); updateSceneFileModifiedStatusLabel(); } /** * Called when a scene file is selected. * * @param index * Index of item selected. */ void SceneDialog::sceneFileSelected(int /*index*/) { loadScenesIntoDialog(NULL); updateSceneFileModifiedStatusLabel(); } //Modified status for both scenes and _LIBCPP_POP_MACROS //In Scene info panel indicate if scene is the active scene //Add macro group to Scene //Remove macro group from scene FILE //List active scene file on macros Dialog /** * Called when add new scene button clicked. */ void SceneDialog::addNewSceneButtonClicked() { if ( ! displayNewSceneWarning()) { return; } if ( ! checkForModifiedFiles(GuiManager::TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD, this)) { return; } SceneFile* sceneFile = getSelectedSceneFile(); if (sceneFile != NULL) { Scene* newScene = SceneCreateReplaceDialog::createNewScene(m_addNewScenePushButton, sceneFile); if (newScene != NULL) { s_informUserAboutScenesOnExitFlag = false; /* * Set the active scene */ EventSceneActive activeSceneEvent(EventSceneActive::MODE_SET); activeSceneEvent.setScene(newScene); EventManager::get()->sendEvent(activeSceneEvent.getPointer()); } loadScenesIntoDialog(newScene); } updateSceneFileModifiedStatusLabel(); /* Ensures macros dialog gets updated with active scene */ EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** * Called when insert new scene button clicked. */ void SceneDialog::insertSceneButtonClicked() { if ( ! displayNewSceneWarning()) { return; } if ( ! checkForModifiedFiles(GuiManager::TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD, this)) { return; } SceneFile* sceneFile = getSelectedSceneFile(); if (sceneFile != NULL) { Scene* scene = getSelectedScene(); if (scene != NULL) { Scene* newScene = SceneCreateReplaceDialog::createNewSceneInsertBeforeScene(m_insertNewScenePushButton, sceneFile, scene); if (newScene != NULL) { s_informUserAboutScenesOnExitFlag = false; /* * Set the active scene */ EventSceneActive activeSceneEvent(EventSceneActive::MODE_SET); activeSceneEvent.setScene(newScene); EventManager::get()->sendEvent(activeSceneEvent.getPointer()); } loadScenesIntoDialog(newScene); } } updateSceneFileModifiedStatusLabel(); /* Ensures macros dialog gets updated with active scene */ EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** * Get the image from the scene info. * * @param sceneInfo * The scene info. * @return * Point to image that caller must delete. Will be NULL * if image is not valid. */ QImage* SceneDialog::getQImageFromSceneInfo(const SceneInfo* sceneInfo) const { QImage* imageOut = NULL; QByteArray imageByteArray; AString imageBytesFormat; sceneInfo->getImageBytes(imageByteArray, imageBytesFormat); if (imageByteArray.isEmpty()) { return new QImage(); } ImageFile imageFile; imageFile.setImageFromByteArray(imageByteArray, imageBytesFormat); const QImage* image = imageFile.getAsQImage(); if (image != NULL) { if (image->isNull()) { CaretLogSevere("Preview image is invalid (isNull)"); } else { imageOut = new QImage(*image); } } return imageOut; } /** * Replace all scenes. */ void SceneDialog::replaceAllScenesPushButtonClicked() { SceneFile* sceneFile = getSelectedSceneFile(); if (sceneFile == NULL) { WuQMessageBox::errorOk(m_replaceAllScenesPushButton, "No scene file is loaded."); return; } const int32_t numScenes = sceneFile->getNumberOfScenes(); if (numScenes == 0) { WuQMessageBox::errorOk(m_replaceAllScenesPushButton, "Selected scene file contains no scenes."); return; } SceneReplaceAllDialog replaceDialog(m_replaceAllScenesDescription, m_replaceAllScenesPushButton); if (replaceDialog.exec() == SceneReplaceAllDialog::Rejected) { return; } AString username; AString password; /* * Check to see if any scenes need a login/password. * Same login/password is used for all scenes. */ for (int32_t i = 0; i < numScenes; i++) { const Scene* scene = sceneFile->getSceneAtIndex(i); if (scene != NULL) { if (scene->hasFilesWithRemotePaths()) { const QString msg("This scene contains files that are on the network. " "If accessing the files requires a username and " "password, enter it here. Otherwise, remove any " "text from the username and password fields."); if (UsernamePasswordWidget::getUserNameAndPasswordInDialog(m_replaceAllScenesPushButton, "Username and Password", msg, username, password)) { CaretDataFile::setFileReadingUsernameAndPassword(username, password); break; } } } } showWaitCursor(); ProgressReportingDialog progressDialog("Replace All Scenes", "Starting...", m_testScenesPushButton); progressDialog.setEventReceivingEnabled(false); progressDialog.setMinimumDuration(0); progressDialog.setMinimum(0); progressDialog.setMaximum(numScenes); progressDialog.setValue(1); progressDialog.setLabelText("Starting replacement..."); progressDialog.repaint(); progressDialog.setCursor(Qt::ArrowCursor); progressDialog.show(); QApplication::processEvents(); const int IMAGE_DISPLAY_WIDTH = 400; std::vector sceneNames; std::vector sceneErrors; std::vector oldImages; std::vector newImages; bool canceledFlag = false; for (int32_t i = 0; i < numScenes; i++) { if (progressDialog.wasCanceled()) { canceledFlag = true; break; } Scene* origScene = sceneFile->getSceneAtIndex(i); if (origScene != NULL) { progressDialog.setValue(i+1); progressDialog.setLabelText("Replacing " + AString::number(i + 1) + " of " + AString::number(numScenes) + ": " + origScene->getName() + "\n\nPressing the Cancel button will stop replacement after the next scene finishes loading."); progressDialog.repaint(); progressDialog.show(); QApplication::processEvents(); if (origScene->hasFilesWithRemotePaths()) { CaretDataFile::setFileReadingUsernameAndPassword(username, password); } const QImage* imageFromScene = getQImageFromSceneInfo(origScene->getSceneInfo()); if (imageFromScene != NULL) { if (imageFromScene->isNull()) { oldImages.push_back(QImage()); } else { oldImages.push_back(imageFromScene->scaledToWidth(IMAGE_DISPLAY_WIDTH)); } delete imageFromScene; } else { oldImages.push_back(QImage()); } /* * Display the scene */ AString errorMessage; SceneDialog::displayScenePrivateWithErrorMessage(sceneFile, origScene, false, errorMessage); sceneNames.push_back(origScene->getName()); /* * Assume scene loads correctly */ Scene* newScene = new Scene(SceneTypeEnum::SCENE_TYPE_FULL); Scene::setSceneBeingCreated(newScene); newScene->setName(origScene->getName()); newScene->setDescription(origScene->getDescription()); newScene->setBalsaSceneID(origScene->getBalsaSceneID()); /* * Set the active scene */ EventSceneActive activeSceneEvent(EventSceneActive::MODE_SET); activeSceneEvent.setScene(newScene); EventManager::get()->sendEvent(activeSceneEvent.getPointer()); /* * Process options */ if (replaceDialog.isChangeSurfaceAnnotationOffsetToOffset()) { AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); std::vector annotations = annMan->getAllAnnotations(); for (auto ann : annotations) { ann->changeSurfaceSpaceToTangentOffset(); } } const std::vector windowIndices = GuiManager::get()->getAllOpenBrainBrowserWindowIndices(); /* * Get all browser tabs and only save transformations for tabs * that are valid. */ std::vector tabIndices; EventBrowserTabGetAll getAllTabs; EventManager::get()->sendEvent(getAllTabs.getPointer()); tabIndices = getAllTabs.getBrowserTabIndices(); std::sort(tabIndices.begin(), tabIndices.end()); SceneAttributes* sceneAttributes = newScene->getAttributes(); sceneAttributes->setSceneFileName(getSelectedSceneFile()->getFileName()); sceneAttributes->setSceneName(origScene->getName()); sceneAttributes->setIndicesOfTabsAndWindowsForSavingToScene(tabIndices, windowIndices); sceneAttributes->setSpecFileNameSavedToScene(true); sceneAttributes->setAllLoadedFilesSavedToScene(true); sceneAttributes->setModifiedPaletteSettingsSavedToScene(true); newScene->addClass(GuiManager::get()->saveToScene(sceneAttributes, "guiManager")); AString imageErrorMessage; SceneCreateReplaceDialog::addImageToScene(newScene, imageErrorMessage); if ( ! imageErrorMessage.isEmpty()) { errorMessage.appendWithNewLine(imageErrorMessage); } getSelectedSceneFile()->replaceScene(newScene, origScene); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); /* Ensures macros dialog gets updated with active scene */ EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); loadScenesIntoDialog(newScene); const QImage* newImage = getQImageFromSceneInfo(newScene->getSceneInfo()); if (newImage != NULL) { if (newImage->isNull()) { newImages.push_back(QImage()); } else { newImages.push_back(newImage->scaledToWidth(IMAGE_DISPLAY_WIDTH)); } delete newImage; } else { newImages.push_back(QImage()); } sceneErrors.push_back(errorMessage); } } progressDialog.close(); CaretAssert(sceneNames.size() == sceneErrors.size()); CaretAssert(sceneNames.size() == oldImages.size()); CaretAssert(sceneNames.size() == newImages.size()); showNormalCursor(); if (canceledFlag) { WuQMessageBox::warningOk(m_replaceAllScenesPushButton, "Replacment of scenes was canceled so scene file may contain both original and " "replaced scenes. It may be best to reload the scene file or exit without saving " "the scene file."); } const int32_t numValidScenes = static_cast(sceneNames.size()); if (numValidScenes <= 0) { WuQMessageBox::errorOk(m_replaceAllScenesPushButton, "No scenes were loaded."); return; } QGridLayout* gridLayout = new QGridLayout(); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 0); gridLayout->setColumnStretch(2, 0); gridLayout->setColumnStretch(3, 0); for (int32_t i = 0; i < numValidScenes; i++) { int row = gridLayout->rowCount(); if (i > 0) { gridLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), row, 0, 1, 4); row++; } gridLayout->addWidget(new QLabel("Scene Name: " + sceneNames[i]), row, 0, Qt::AlignLeft); if ( ! sceneErrors[i].isEmpty()) { QLabel* errorLabel = new QLabel("Scene Errors: " + sceneErrors[i]); errorLabel->setWordWrap(true); gridLayout->addWidget(errorLabel, row, 1, Qt::AlignLeft); } row++; const QSizePolicy::Policy imageSizePolicy = QSizePolicy::Preferred; QLabel* sceneImageLabel = new QLabel("Image Invalid"); if ( ! oldImages[i].isNull()) { sceneImageLabel->clear(); sceneImageLabel->setPixmap(QPixmap::fromImage(oldImages[i])); sceneImageLabel->setSizePolicy(imageSizePolicy, imageSizePolicy); } gridLayout->addWidget(sceneImageLabel, row, 0); QLabel* newImageLabel = new QLabel("Image Invalid"); if ( ! newImages[i].isNull()) { newImageLabel->clear(); newImageLabel->setPixmap(QPixmap::fromImage(newImages[i])); newImageLabel->setSizePolicy(imageSizePolicy, imageSizePolicy); } gridLayout->addWidget(newImageLabel, row, 1); } const int numRows = gridLayout->rowCount(); for (int32_t i = 0; i < numRows; i++) { gridLayout->setRowStretch(i, 0); } QWidget* dialogWidget = new QWidget(); QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); dialogLayout->addLayout(gridLayout); WuQDialogNonModal* dialog = new WuQDialogNonModal("Replace All Scenes Comparison", m_replaceAllScenesPushButton); dialog->setDeleteWhenClosed(true); dialog->setApplyButtonText(""); dialog->setCentralWidget(dialogWidget, WuQDialogNonModal::SCROLL_AREA_ALWAYS); dialog->show(); WuQtUtilities::limitWindowSizePercentageOfMaximum(dialog, 100.0, 100.0); const int dialogWidth = (IMAGE_DISPLAY_WIDTH * 2) + 50; const int dialogHeight = (IMAGE_DISPLAY_WIDTH * 2.5); WuQtUtilities::resizeWindow(dialog, dialogWidth, dialogHeight); dialog->show(); } /** * Test all scenes by loading them and then * displaying images that are stored with the * scene and new image of the displayed scene. */ void SceneDialog::testScenesPushButtonClicked() { SceneFile* sceneFile = getSelectedSceneFile(); if (sceneFile == NULL) { WuQMessageBox::errorOk(m_testScenesPushButton, "No scene file is loaded."); return; } const int32_t numScenes = sceneFile->getNumberOfScenes(); if (numScenes == 0) { WuQMessageBox::errorOk(m_testScenesPushButton, "Selected scene file contains no scenes."); return; } if ( ! WuQMessageBox::warningOkCancel(m_testScenesPushButton, "Test All Scenes", m_testAllScenesDescription)) { return; } AString username; AString password; /* * Check to see if any scenes need a login/password. * Same login/password is used for all scenes. */ for (int32_t i = 0; i < numScenes; i++) { const Scene* scene = sceneFile->getSceneAtIndex(i); if (scene != NULL) { if (scene->hasFilesWithRemotePaths()) { const QString msg("This scene contains files that are on the network. " "If accessing the files requires a username and " "password, enter it here. Otherwise, remove any " "text from the username and password fields."); if (UsernamePasswordWidget::getUserNameAndPasswordInDialog(this, "Username and Password", msg, username, password)) { CaretDataFile::setFileReadingUsernameAndPassword(username, password); break; } } } } ProgressReportingDialog progressDialog("Test All Scenes", "Starting...", m_testScenesPushButton); progressDialog.setEventReceivingEnabled(false); progressDialog.setMinimumDuration(0); progressDialog.setMinimum(0); progressDialog.setMaximum(numScenes); progressDialog.setValue(1); progressDialog.setLabelText("Starting testing..."); progressDialog.repaint(); progressDialog.setCursor(Qt::ArrowCursor); progressDialog.show(); QApplication::processEvents(); std::vector sceneNames; std::vector sceneErrors; std::vector sceneImages; std::vector newImages; const int IMAGE_DISPLAY_WIDTH = 500; for (int32_t i = 0; i < numScenes; i++) { if (progressDialog.wasCanceled()) { break; } Scene* origScene = sceneFile->getSceneAtIndex(i); if (origScene != NULL) { progressDialog.setValue(i+1); progressDialog.setLabelText("Testing " + AString::number(i + 1) + " of " + AString::number(numScenes) + ": " + origScene->getName() + "\n\nPressing the Cancel button will stop testing after the next scene finishes loading."); progressDialog.repaint(); progressDialog.show(); QApplication::processEvents(); if (origScene->hasFilesWithRemotePaths()) { CaretDataFile::setFileReadingUsernameAndPassword(username, password); } AString errorMessage; SceneDialog::displayScenePrivateWithErrorMessage(sceneFile, origScene, false, errorMessage); /* * Set the active scene */ EventSceneActive activeSceneEvent(EventSceneActive::MODE_SET); activeSceneEvent.setScene(origScene); EventManager::get()->sendEvent(activeSceneEvent.getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); /* Ensures macros dialog gets updated with active scene */ EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); /* * Always generate an image, even if the scene fails and failure may * be a very minor error. */ QImage image; AString imageErrorMessage; const bool validImage = SceneCreateReplaceDialog::createSceneImage(image, imageErrorMessage); if (validImage) { newImages.push_back(image.scaledToWidth(IMAGE_DISPLAY_WIDTH)); } else { newImages.push_back(QImage()); errorMessage.appendWithNewLine("Generate image error: " + imageErrorMessage); } sceneNames.push_back(origScene->getName()); const QImage* imageFromScene = getQImageFromSceneInfo(origScene->getSceneInfo()); if (imageFromScene != NULL) { if (imageFromScene->isNull()) { sceneImages.push_back(QImage()); } else { sceneImages.push_back(imageFromScene->scaledToWidth(IMAGE_DISPLAY_WIDTH)); } delete imageFromScene; } else { sceneImages.push_back(QImage()); } sceneErrors.push_back(errorMessage); } } progressDialog.close(); CaretAssert(sceneNames.size() == sceneErrors.size()); CaretAssert(sceneNames.size() == sceneImages.size()); CaretAssert(sceneNames.size() == sceneErrors.size()); CaretAssert(sceneNames.size() == newImages.size()); showNormalCursor(); const int32_t numValidScenes = static_cast(sceneNames.size()); if (numValidScenes <= 0) { WuQMessageBox::errorOk(m_testScenesPushButton, "No scenes were loaded."); return; } QGridLayout* gridLayout = new QGridLayout(); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 0); gridLayout->setColumnStretch(2, 100); for (int32_t i = 0; i < numValidScenes; i++) { int row = gridLayout->rowCount(); if (i > 0) { gridLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), row, 0, 1, 4); row = gridLayout->rowCount(); } gridLayout->addWidget(new QLabel("Scene Name: " + sceneNames[i]), row, 0, 1, 2, Qt::AlignLeft); row = gridLayout->rowCount(); if ( ! sceneErrors[i].isEmpty()) { QLabel* errorLabel = new QLabel("Scene Errors: " + sceneErrors[i]); errorLabel->setWordWrap(true); gridLayout->addWidget(errorLabel, row, 0, 1, 2, Qt::AlignLeft); row = gridLayout->rowCount(); } const QSizePolicy::Policy imageSizePolicy = QSizePolicy::Preferred; QLabel* sceneImageLabel = new QLabel("Image Invalid"); if ( ! sceneImages[i].isNull()) { sceneImageLabel->clear(); sceneImageLabel->setPixmap(QPixmap::fromImage(sceneImages[i])); sceneImageLabel->setSizePolicy(imageSizePolicy, imageSizePolicy); } gridLayout->addWidget(sceneImageLabel, row, 0); QLabel* newImageLabel = new QLabel("Image Invalid"); if ( ! newImages[i].isNull()) { newImageLabel->clear(); newImageLabel->setPixmap(QPixmap::fromImage(newImages[i])); newImageLabel->setSizePolicy(imageSizePolicy, imageSizePolicy); } gridLayout->addWidget(newImageLabel, row, 1); } const int numRows = gridLayout->rowCount(); for (int32_t i = 0; i < numRows; i++) { gridLayout->setRowStretch(i, 0); } QWidget* dialogWidget = new QWidget(); QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); dialogLayout->addLayout(gridLayout); dialogLayout->addStretch(); WuQDialogNonModal* dialog = new WuQDialogNonModal("Test All Scene Comparisons", m_testScenesPushButton); dialog->setDeleteWhenClosed(true); dialog->setApplyButtonText(""); dialog->setCentralWidget(dialogWidget, WuQDialogNonModal::SCROLL_AREA_ALWAYS); dialog->show(); WuQtUtilities::limitWindowSizePercentageOfMaximum(dialog, 100.0, 100.0); const int dialogWidth = (IMAGE_DISPLAY_WIDTH * 2) + 50; const int dialogHeight = (IMAGE_DISPLAY_WIDTH * 2.5); WuQtUtilities::resizeWindow(dialog, dialogWidth, dialogHeight); dialog->show(); } /** * Move the selected scene up. */ void SceneDialog::moveSceneUpButtonClicked() { SceneFile* sceneFile = getSelectedSceneFile(); if (sceneFile != NULL) { Scene* scene = getSelectedScene(); if (scene != NULL) { sceneFile->moveScene(scene, -1); loadScenesIntoDialog(scene); updateSceneFileModifiedStatusLabel(); } } } /** * Move the selected scene down. */ void SceneDialog::moveSceneDownButtonClicked() { SceneFile* sceneFile = getSelectedSceneFile(); if (sceneFile != NULL) { Scene* scene = getSelectedScene(); if (scene != NULL) { sceneFile->moveScene(scene, 1); loadScenesIntoDialog(scene); updateSceneFileModifiedStatusLabel(); } } } /** * Called when replace scene button clicked. */ void SceneDialog::replaceSceneButtonClicked() { if ( ! displayNewSceneWarning()) { return; } if ( ! checkForModifiedFiles(GuiManager::TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD, this)) { return; } SceneFile* sceneFile = getSelectedSceneFile(); if (sceneFile != NULL) { Scene* scene = getSelectedScene(); if (scene != NULL) { Scene* newScene = SceneCreateReplaceDialog::replaceExistingScene(m_addNewScenePushButton, sceneFile, scene); if (newScene != NULL) { s_informUserAboutScenesOnExitFlag = false; /* * Set the active scene */ EventSceneActive activeSceneEvent(EventSceneActive::MODE_SET); activeSceneEvent.setScene(newScene); EventManager::get()->sendEvent(activeSceneEvent.getPointer()); } loadScenesIntoDialog(newScene); updateSceneFileModifiedStatusLabel(); } } /* Ensures macros dialog gets updated with active scene */ EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** * Check to see if there are modified files. If there are * allow the user to continue or cancel creation of the scene. * * param creatingSceneFlag * When true scene is being created, else a scene is being shown * @return * true if the scene should be created, otherwise false. */ bool SceneDialog::checkForModifiedFiles(const GuiManager::TestModifiedMode testMode, QWidget* parent) { bool creatingSceneFlag = false; switch (testMode) { case GuiManager::TEST_FOR_MODIFIED_FILES_EXCLUDING_PALETTES_MODE_FOR_SCENE_ADD: creatingSceneFlag = true; break; case GuiManager::TEST_FOR_MODIFIED_FILES_MODE_FOR_EXIT: break; case GuiManager::TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_SHOW: break; case GuiManager::TEST_FOR_MODIFIED_FILES_PALETTE_ONLY_MODE_FOR_SCENE_ADD: break; } if (creatingSceneFlag) { EventModelGetAll allModelsEvent; EventManager::get()->sendEvent(allModelsEvent.getPointer()); if (allModelsEvent.getModels().empty()) { const QString msg("No surfaces or volumes are loaded. Continue creating scene?"); if ( ! WuQMessageBox::warningYesNo(parent, msg)) { return false; } } } AString dialogMessage; AString modifiedFilesMessage; const bool haveModifiedFilesFlag = GuiManager::get()->testForModifiedFiles(testMode, dialogMessage, modifiedFilesMessage); bool result = true; if (haveModifiedFilesFlag) { QMessageBox warningDialog(QMessageBox::Warning, "Warning", dialogMessage, QMessageBox::NoButton, parent); warningDialog.setInformativeText(modifiedFilesMessage); QPushButton* yesButton = warningDialog.addButton("Yes", QMessageBox::AcceptRole); QPushButton* noButton = warningDialog.addButton("No", QMessageBox::RejectRole); warningDialog.setDefaultButton(noButton); warningDialog.setEscapeButton(noButton); warningDialog.exec(); const QAbstractButton* clickedButton = warningDialog.clickedButton(); if (clickedButton == yesButton) { result = true; } else if (clickedButton == noButton) { result = false; } else { CaretAssert(0); } } return result; } /** * Show the data file structure in a dialog. */ void SceneDialog::showFileStructure() { SceneFile* sceneFile = getSelectedSceneFile(); CaretAssert(sceneFile); CursorDisplayScoped cursor; cursor.showWaitCursor(); SceneFileInformationDialog* infoDialog = new SceneFileInformationDialog(sceneFile, this); infoDialog->setVisible(true); infoDialog->show(); infoDialog->activateWindow(); infoDialog->raise(); } /** * @return The Scenes widget. */ QWidget* SceneDialog::createScenesWidget() { QWidget* sceneFileWidget = createSceneFileWidget(); /* * Scene controls */ QLabel* sceneLabel = new QLabel(" Scenes"); /* * Add new scene button */ m_addNewScenePushButton = new QPushButton("Add..."); m_addNewScenePushButton->setToolTip("Add a new scene to the END of the list"); QObject::connect(m_addNewScenePushButton, SIGNAL(clicked()), this, SLOT(addNewSceneButtonClicked())); /* * Delete new scene button */ m_deleteScenePushButton = new QPushButton("Delete..."); m_deleteScenePushButton->setToolTip("Delete the selected scene"); QObject::connect(m_deleteScenePushButton, SIGNAL(clicked()), this, SLOT(deleteSceneButtonClicked())); /* * Replace all scenes */ m_replaceAllScenesPushButton = new QPushButton("Replace All..."); m_replaceAllScenesPushButton->setToolTip(m_replaceAllScenesDescription); QObject::connect(m_replaceAllScenesPushButton, SIGNAL(clicked()), this, SLOT(replaceAllScenesPushButtonClicked())); /* * Test all scenes */ m_testScenesPushButton = new QPushButton("Test All..."); m_testScenesPushButton->setToolTip(m_testAllScenesDescription); QObject::connect(m_testScenesPushButton, SIGNAL(clicked()), this, SLOT(testScenesPushButtonClicked())); /* * Move scene up button */ m_moveSceneUpPushButton = new QPushButton("Move Up"); m_moveSceneUpPushButton->setToolTip("Move the selected scene up one position"); QObject::connect(m_moveSceneUpPushButton, SIGNAL(clicked()), this, SLOT(moveSceneUpButtonClicked())); /* * Move scene down button */ m_moveSceneDownPushButton = new QPushButton("Move Down"); m_moveSceneDownPushButton->setToolTip("Move the selected scene down one position"); QObject::connect(m_moveSceneDownPushButton, SIGNAL(clicked()), this, SLOT(moveSceneDownButtonClicked())); /* * Insert scene button */ m_insertNewScenePushButton = new QPushButton("Insert..."); m_insertNewScenePushButton->setToolTip("Insert a new scene ABOVE the selected scene in the list"); QObject::connect(m_insertNewScenePushButton, SIGNAL(clicked()), this, SLOT(insertSceneButtonClicked())); /* * Replace scene button */ m_replaceScenePushButton = new QPushButton("Replace..."); m_replaceScenePushButton->setToolTip("Replace the selected scene"); QObject::connect(m_replaceScenePushButton, SIGNAL(clicked()), this, SLOT(replaceSceneButtonClicked())); /* * Show new scene button */ m_showScenePushButton = new QPushButton("Show"); m_showScenePushButton->setToolTip("Show the selected scene"); QObject::connect(m_showScenePushButton, SIGNAL(clicked()), this, SLOT(showSceneButtonClicked())); /* * Show scene image button */ m_showSceneImagePreviewPushButton = new QPushButton("Preview..."); m_showSceneImagePreviewPushButton->setToolTip("Show larger preview image and full description\n" "for the selected scene"); QObject::connect(m_showSceneImagePreviewPushButton, SIGNAL(clicked()), this, SLOT(showImagePreviewButtonClicked())); /* * Show scene options button */ m_showSceneOptionsPushButton = new QPushButton("Options..."); m_showSceneOptionsPushButton->setToolTip("Display a dialog for show scene options"); QObject::connect(m_showSceneOptionsPushButton, &QPushButton::clicked, this, &SceneDialog::showSceneOptionsButtonClicked); /* * Group for show buttons */ QGroupBox* showGroupBox = new QGroupBox("Show Scene"); showGroupBox->setFlat(true); showGroupBox->setSizePolicy(showGroupBox->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); QVBoxLayout* showGroupLayout = new QVBoxLayout(showGroupBox); WuQtUtilities::setLayoutSpacingAndMargins(showGroupLayout, 2, 2); showGroupLayout->addWidget(m_showScenePushButton); showGroupLayout->addWidget(m_showSceneImagePreviewPushButton); showGroupLayout->addWidget(m_showSceneOptionsPushButton); /* * Group for create buttons */ QGroupBox* createGroupBox = new QGroupBox("Create Scene"); createGroupBox->setFlat(true); createGroupBox->setSizePolicy(createGroupBox->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); QVBoxLayout* createGroupLayout = new QVBoxLayout(createGroupBox); WuQtUtilities::setLayoutSpacingAndMargins(createGroupLayout, 2, 2); createGroupLayout->addWidget(m_addNewScenePushButton); createGroupLayout->addWidget(m_insertNewScenePushButton); createGroupLayout->addWidget(m_replaceScenePushButton); /* * Group for test buttons */ QGroupBox* testGroupBox = new QGroupBox("Testing"); testGroupBox->setFlat(true); testGroupBox->setSizePolicy(testGroupBox->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); QVBoxLayout* testGroupLayout = new QVBoxLayout(testGroupBox); WuQtUtilities::setLayoutSpacingAndMargins(testGroupLayout, 2, 2); if (m_replaceAllScenesPushButton != NULL) { testGroupLayout->addWidget(m_replaceAllScenesPushButton); } testGroupLayout->addWidget(m_testScenesPushButton); /* * Group for organize buttons */ QGroupBox* organizeGroupBox = new QGroupBox("Selected Scene"); organizeGroupBox->setFlat(true); organizeGroupBox->setSizePolicy(organizeGroupBox->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); QVBoxLayout* organizeGroupLayout = new QVBoxLayout(organizeGroupBox); WuQtUtilities::setLayoutSpacingAndMargins(organizeGroupLayout, 2, 2); organizeGroupLayout->addWidget(m_moveSceneUpPushButton); organizeGroupLayout->addWidget(m_moveSceneDownPushButton); organizeGroupLayout->addSpacing(5); organizeGroupLayout->addWidget(m_deleteScenePushButton); /* * Layout for scene buttons */ QVBoxLayout* sceneButtonLayout = new QVBoxLayout(); sceneButtonLayout->addWidget(showGroupBox); sceneButtonLayout->addSpacing(20); sceneButtonLayout->addWidget(createGroupBox); sceneButtonLayout->addSpacing(20); sceneButtonLayout->addWidget(organizeGroupBox); sceneButtonLayout->addStretch(); sceneButtonLayout->addWidget(testGroupBox); /* * Widget and layout containing the scene class info. */ m_sceneSelectionLayout = new QVBoxLayout(); m_sceneSelectionWidget = new QWidget(); QVBoxLayout* sceneSelectionWidgetLayout = new QVBoxLayout(m_sceneSelectionWidget); sceneSelectionWidgetLayout->addLayout(m_sceneSelectionLayout); sceneSelectionWidgetLayout->addStretch(); m_sceneSelectionScrollArea = new QScrollArea(); m_sceneSelectionScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); m_sceneSelectionScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); m_sceneSelectionScrollArea->setWidget(m_sceneSelectionWidget); m_sceneSelectionScrollArea->setWidgetResizable(true); /* * Layout widgets */ QWidget* widget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(widget); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); gridLayout->setColumnStretch(2, 0); gridLayout->setSpacing(6); WuQtUtilities::setLayoutMargins(gridLayout, 0); int row = 0; gridLayout->addWidget(sceneFileWidget, row, 0, 1, 3); row++; gridLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), row, 0, 1, 3); row++; gridLayout->addWidget(sceneLabel, row, 0, (Qt::AlignTop | Qt::AlignRight)); gridLayout->addWidget(m_sceneSelectionScrollArea, row, 1); gridLayout->addLayout(sceneButtonLayout, row, 2); row++; gridLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), row, 0, 1, 3); row++; return widget; } /** * @return The Scene File Widget. */ QWidget* SceneDialog::createSceneFileWidget() { /* * Scene File Controls */ QLabel* sceneFileLabel = new QLabel("Scene File"); m_sceneFileSelectionComboBox = new QComboBox(); m_sceneFileSelectionComboBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength); m_sceneFileSelectionComboBox->setSizePolicy(QSizePolicy::MinimumExpanding, m_sceneFileSelectionComboBox->sizePolicy().verticalPolicy()); WuQtUtilities::setToolTipAndStatusTip(m_sceneFileSelectionComboBox, "Selects an existing scene file\n" "to which new scenes are added."); QObject::connect(m_sceneFileSelectionComboBox, SIGNAL(activated(int)), this, SLOT(sceneFileSelected(int))); /* * Scene file modified status */ QLabel* modifiedLabel = new QLabel("Modified"); m_sceneFileModifiedStatusLabel = new QLabel(""); /* * File structure buttons */ m_showFileStructurePushButton = new QPushButton("Show Files and Folders..."); WuQtUtilities::setWordWrappedToolTip(m_showFileStructurePushButton, "In a dialog, show the organization files and folders contained in the Scene File"); QObject::connect(m_showFileStructurePushButton, &QPushButton::clicked, this, &SceneDialog::showFileStructure); /* * New File button */ m_newSceneFilePushButton = new QPushButton("New"); m_newSceneFilePushButton->setToolTip("Create a new scene file"); QObject::connect(m_newSceneFilePushButton, SIGNAL(clicked()), this, SLOT(newSceneFileButtonClicked())); /* * Open File button */ m_openSceneFilePushButton = new QPushButton("Open..."); m_openSceneFilePushButton->setToolTip("Open an existing scene file"); QObject::connect(m_openSceneFilePushButton, SIGNAL(clicked()), this, SLOT(openSceneFileButtonClicked())); /* * Save File button */ m_saveSceneFilePushButton = new QPushButton("Save"); m_saveSceneFilePushButton->setToolTip("Save the scene file using its current name"); QObject::connect(m_saveSceneFilePushButton, SIGNAL(clicked()), this, SLOT(saveSceneFileButtonClicked())); /* * Save As File button */ m_saveAsSceneFilePushButton = new QPushButton("Save As..."); m_saveAsSceneFilePushButton->setToolTip("Display a file selection dialog for saving scene file with a new name"); QObject::connect(m_saveAsSceneFilePushButton, SIGNAL(clicked()), this, SLOT(saveAsSceneFileButtonClicked())); /* * Upload button */ m_uploadSceneFilePushButton = new QPushButton("Upload..."); m_uploadSceneFilePushButton->setToolTip("Upload the selected scene file to the BALSA Database"); QObject::connect(m_uploadSceneFilePushButton, SIGNAL(clicked()), this, SLOT(uploadSceneFileButtonClicked())); /* * Zip button */ m_zipSceneFilePushButton = new QPushButton("Zip..."); m_zipSceneFilePushButton->setToolTip("Zip the selected scene file"); QObject::connect(m_zipSceneFilePushButton, SIGNAL(clicked()), this, SLOT(zipSceneFileButtonClicked())); /* * Group for scene file buttons that are only valid when a scene file is available */ m_sceneFileButtonsGroup = new WuQWidgetObjectGroup(this); m_sceneFileButtonsGroup->add(m_saveSceneFilePushButton); m_sceneFileButtonsGroup->add(m_saveAsSceneFilePushButton); m_sceneFileButtonsGroup->add(m_uploadSceneFilePushButton); m_sceneFileButtonsGroup->add(m_zipSceneFilePushButton); /* * Layout widgets */ QWidget* widget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(widget); QMargins gridMargins = gridLayout->contentsMargins(); gridMargins.setBottom(0); gridMargins.setTop(3); gridLayout->setContentsMargins(gridMargins); gridLayout->setSpacing(6); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); gridLayout->setColumnStretch(2, 0); gridLayout->setColumnStretch(3, 0); gridLayout->setColumnStretch(4, 0); gridLayout->setColumnStretch(5, 0); int row = 0; gridLayout->addWidget(sceneFileLabel, row, 0, Qt::AlignRight); gridLayout->addWidget(m_sceneFileSelectionComboBox, row, 1, 1, 2); gridLayout->addWidget(m_newSceneFilePushButton, row, 3); gridLayout->addWidget(m_saveSceneFilePushButton, row, 4); gridLayout->addWidget(m_zipSceneFilePushButton, row, 5); row++; gridLayout->addWidget(modifiedLabel, row, 0, Qt::AlignRight); gridLayout->addWidget(m_sceneFileModifiedStatusLabel, row, 1, Qt::AlignLeft); gridLayout->addWidget(m_showFileStructurePushButton, row, 2); gridLayout->addWidget(m_openSceneFilePushButton, row, 3); gridLayout->addWidget(m_saveAsSceneFilePushButton, row, 4); gridLayout->addWidget(m_uploadSceneFilePushButton, row, 5); row++; return widget; } /** * Gets called to verify the content of the scene creation dialog. * @param sceneCreateDialog * Scene creation dialog. */ void SceneDialog::validateContentOfCreateSceneDialog(WuQDataEntryDialog* sceneCreateDialog) { CaretAssert(sceneCreateDialog); bool dataValid = true; QString errorMessage = ""; QWidget* sceneNameWidget = sceneCreateDialog->getDataWidgetWithName("sceneNameLineEdit"); if (sceneNameWidget != NULL) { QLineEdit* sceneNameLineEdit = qobject_cast(sceneNameWidget); const AString sceneName = sceneNameLineEdit->text().trimmed(); if (sceneName.isEmpty()) { dataValid = false; if (errorMessage.isEmpty() == false) { errorMessage += "\n"; } errorMessage += ("Scene Name is empty."); } else { SceneFile* sceneFile = getSelectedSceneFile(); if (sceneFile != NULL) { const int32_t numScenes = sceneFile->getNumberOfScenes(); for (int32_t i = 0; i < numScenes; i++) { Scene* scene = sceneFile->getSceneAtIndex(i); if (scene->getName() == sceneName) { dataValid = false; if (errorMessage.isEmpty() == false) { errorMessage += "\n"; } errorMessage += ("An existing scene uses the name \"" + sceneName + "\". Scene names must be unique."); break; } } } } } sceneCreateDialog->setDataValid(dataValid, errorMessage); } /** * Slot that get called when a scene is highlighted (clicked). * * @param sceneIndex * Index of the scene. */ void SceneDialog::sceneHighlighted(const int32_t sceneIndex) { highlightSceneAtIndex(sceneIndex); } /** * Slot that get called when a scene is activated (double clicked). * * @param sceneIndex * Index of the scene. */ void SceneDialog::sceneActivated(const int32_t sceneIndex) { highlightSceneAtIndex(sceneIndex); showSceneButtonClicked(); } /** * Called when delete scene button clicked. */ void SceneDialog::deleteSceneButtonClicked() { Scene* scene = getSelectedScene(); if (scene != NULL) { const AString sceneName = scene->getName(); const AString msg = ("Are you sure you want to delete scene named: " + sceneName); if (WuQMessageBox::warningYesNo(m_deleteScenePushButton, msg)) { SceneFile* sceneFile = getSelectedSceneFile(); sceneFile->removeScene(scene); updateDialog(); /* Ensures macros dialog gets updated with active scene */ EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } } } /** * Called when show scene button clicked. */ void SceneDialog::showSceneButtonClicked() { if ( ! checkForModifiedFiles(GuiManager::TEST_FOR_MODIFIED_FILES_MODE_FOR_SCENE_SHOW, this)) { return; } AString sceneFileName; SceneFile* sceneFile = getSelectedSceneFile(); if (sceneFile != NULL) { sceneFileName = sceneFile->getFileName(); } Scene* scene = getSelectedScene(); if (scene != NULL) { if (scene->hasFilesWithRemotePaths()) { const QString msg("This scene contains files that are on the network. " "If accessing the files requires a username and " "password, enter it here. Otherwise, remove any " "text from the username and password fields."); AString username; AString password; if (UsernamePasswordWidget::getUserNameAndPasswordInDialog(this, "Username and Password", msg, username, password)) { CaretDataFile::setFileReadingUsernameAndPassword(username, password); } else { return; } } ProgressReportingDialog progressDialog(("Restoring Scene " + scene->getName()), "", this); progressDialog.setValue(0); displayScenePrivateWithErrorMessageDialog(this, sceneFile, scene, false); } /* Ensures macros dialog gets updated with active scene */ EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** * Display the scene show options dialog */ void SceneDialog::showSceneOptionsButtonClicked() { Scene* scene = getSelectedScene(); if (scene != NULL) { SceneShowOptionsDialog::Options options(s_useSceneForegroundBackgroundColorsFlag); SceneShowOptionsDialog optionsDialog(options, m_showSceneOptionsPushButton); if (optionsDialog.exec() == QDialog::Accepted) { const SceneShowOptionsDialog::Options optionsResult = optionsDialog.getOptions(); s_useSceneForegroundBackgroundColorsFlag = optionsResult.isUseSceneColorsSelected(); if ( ! optionsResult.isUseSceneColorsSelected()) { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setBackgroundAndForegroundColorsMode(BackgroundAndForegroundColorsModeEnum::USER_PREFERENCES); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } } } /** * Called when show image preview button is clicked. */ void SceneDialog::showImagePreviewButtonClicked() { const Scene* scene = getSelectedScene(); if (scene != NULL) { QByteArray imageByteArray; AString imageBytesFormat; scene->getSceneInfo()->getImageBytes(imageByteArray, imageBytesFormat); bool useNonModalDialogFlag = true; if (useNonModalDialogFlag) { /* * Scene preview dialog will be deleted when user closes it */ ScenePreviewDialog* spd = new ScenePreviewDialog(scene, m_showSceneImagePreviewPushButton); spd->show(); } else { WuQDataEntryDialog ded(scene->getName(), m_showSceneImagePreviewPushButton, WuQDialog::SCROLL_AREA_AS_NEEDED); ded.setCancelButtonText(""); ded.setOkButtonText("Close"); try { if (imageByteArray.length() > 0) { ImageFile imageFile; imageFile.setImageFromByteArray(imageByteArray, imageBytesFormat); const QImage* image = imageFile.getAsQImage(); if (image != NULL) { if (image->isNull()) { CaretLogSevere("Preview image is invalid (isNull)"); } else { QLabel* imageLabel = new QLabel(); imageLabel->setPixmap(QPixmap::fromImage(*image)); ded.addWidget("", imageLabel); } } } } catch (const DataFileException& dfe) { CaretLogSevere("Converting preview to image: " + dfe.whatString()); } AString nameText; AString sceneIdText; AString descriptionText; const int32_t negativeIsUnlimitedNumberOfLines = -1; SceneClassInfoWidget::getFormattedTextForSceneNameAndDescription(scene->getSceneInfo(), -1, nameText, sceneIdText, descriptionText, negativeIsUnlimitedNumberOfLines); QLabel* nameLabel = new QLabel(nameText); ded.addWidget("", nameLabel); QLabel* sceneIdLabel = new QLabel(sceneIdText); ded.addWidget("", sceneIdLabel); if (! descriptionText.isEmpty()) { QLabel* descriptionLabel = new QLabel(descriptionText); descriptionLabel->setWordWrap(true); ded.addWidget("", descriptionLabel); } ded.exec(); } } } /** * Gets called when the use scene colors checkbox is clicked. * * @param checked * New checked status. */ void SceneDialog::useSceneColorsCheckBoxClicked(bool checked) { if ( ! checked) { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setBackgroundAndForegroundColorsMode(BackgroundAndForegroundColorsModeEnum::USER_PREFERENCES); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } /** * Display the given scene from the given scene file. * @param sceneFile * Scene file. * @param scene * Scene that is displayed. * @return * true if scene was displayed without error, else false. */ bool SceneDialog::displayScene(SceneFile* sceneFile, Scene* scene) { const bool isSuccessful = displayScenePrivateWithErrorMessageDialog(this, sceneFile, scene, true); loadSceneFileComboBox(sceneFile); loadScenesIntoDialog(scene); /* Ensures macros dialog gets updated with active scene */ EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); return isSuccessful; } /** * Display the given scene from the given scene file. * If the scene fails to load, an error message is displayed * in a dialog. * * @param dialogParent * Parent for error message dialog * @param sceneFile * Scene file. * @param scene * Scene that is displayed. * @return * true if scene was displayed without error, else false. */ bool SceneDialog::displaySceneWithErrorMessageDialog(QWidget* dialogParent, SceneFile* sceneFile, Scene* scene) { const bool showWaitCursorFlag(true); const bool flag = SceneDialog::displayScenePrivateWithErrorMessageDialog(dialogParent, sceneFile, scene, showWaitCursorFlag); return flag; } /** * Display the given scene from the given scene file. * If the scene fails to load, an error message is displayed * in a dialog. * * @param dialogParent * Parent for error message dialog * @param sceneFile * Scene file. * @param scene * Scene that is displayed. * @param showWaitCursor * If true, show a wait cursor * @return * true if scene was displayed without error, else false. */ bool SceneDialog::displayScenePrivateWithErrorMessageDialog(QWidget* dialogParent, SceneFile* sceneFile, Scene* scene, const bool showWaitCursor) { AString errorMessage; ElapsedTimer et; et.start(); const bool successFlag = displayScenePrivateWithErrorMessage(sceneFile, scene, showWaitCursor, errorMessage); AString msg = (AString::number(et.getElapsedTimeSeconds()) + " seconds to read Scene " + scene->getName()); CaretLogInfo(msg); if ( ! successFlag) { WuQMessageBox::errorOk(dialogParent, errorMessage); } EventManager::get()->sendEvent(EventShowDataFileReadWarningsDialog().getPointer()); return successFlag; } /** * Display the given scene from the given scene file. * @param sceneFile * Scene file. * @param scene * Scene that is displayed. * param showWaitCursor * Show a wait cursor while loading scene * @param errorMessageOut * Contains error information if scene fails to load. * @return * true if scene was displayed without error, else false. */ bool SceneDialog::displayScenePrivateWithErrorMessage(SceneFile* sceneFile, Scene* scene, const bool showWaitCursor, AString& errorMessageOut) { CaretAssert(sceneFile); CaretAssert(scene); errorMessageOut.clear(); const AString sceneFileName = sceneFile->getFileName(); const SceneClass* guiManagerClass = scene->getClassWithName("guiManager"); if (guiManagerClass->getName() != "guiManager") { errorMessageOut = ("Top level scene class should be guiManager but it is: " + guiManagerClass->getName()); return false; } /* * When compiled in debug mode, log any SceneObject and * subclasses that fail to restore */ bool logObjectFailedToRestoreFlag = true; #ifdef NDEBUG logObjectFailedToRestoreFlag = false; #endif // NDEBUG std::vector allSceneObjects; if (logObjectFailedToRestoreFlag) { allSceneObjects = scene->getDescendants(); } SceneClass::setDebugLoggingEnabled(logObjectFailedToRestoreFlag); /* * Show the wait cursor */ CursorDisplayScoped cursor; if (showWaitCursor) { cursor.showWaitCursor(); } /* * Setup scene attributes */ SceneAttributes* sceneAttributes = scene->getAttributes(); sceneAttributes->clearErrorMessage(); sceneAttributes->setSceneFileName(sceneFileName); sceneAttributes->setSceneName(scene->getName()); sceneAttributes->setWindowRestoreBehaviorInSceneDisplay(SceneAttributes::RESTORE_WINDOW_POSITION_RELATIVE_TO_FIRST_AND_USE_SIZES); sceneAttributes->setUseSceneForegroundAndBackgroundColors(s_useSceneForegroundBackgroundColorsFlag); if ( ! allSceneObjects.empty()) { SceneObject::setRestoredStatus(allSceneObjects, false); } GuiManager::get()->restoreFromScene(sceneAttributes, guiManagerClass); guiManagerClass->setRestored(true); if ( ! allSceneObjects.empty()) { SceneObject::logObjectsFailedRestore(scene->getName(), allSceneObjects); } SceneClass::setDebugLoggingEnabled(false); cursor.restoreCursor(); /* * Set the active scene */ EventSceneActive activeSceneEvent(EventSceneActive::MODE_SET); activeSceneEvent.setScene(scene); EventManager::get()->sendEvent(activeSceneEvent.getPointer()); const AString sceneErrorMessage = sceneAttributes->getErrorMessage(); if (sceneErrorMessage.isEmpty()) { /* * Add to recent scene files but only if the scene * file is NOT modified. * * It is possible for the user to create a new scene in * a new scene file and never write the scene file. * So, we don't want a non-existent scene file in the * recent scene file's menu. */ if ( ! sceneFile->isModified()) { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->addToPreviousSceneFiles(sceneFile->getFileName()); } } else { errorMessageOut = sceneErrorMessage; return false; } return true; } /** * Receive events from the event manager. * * @param event * Event sent by event manager. */ void SceneDialog::receiveEvent(Event* event) { SceneFile* lastSceneFileRead = NULL; if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiEvent = dynamic_cast(event); CaretAssert(uiEvent); updateDialog(); uiEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_DATA_FILE_ADD) { EventDataFileAdd* addEvent = dynamic_cast(event); CaretAssert(addEvent); /* * Determine if a scene file was read */ CaretDataFile* dataFile = addEvent->getCaretDataFile(); if (dataFile != NULL) { lastSceneFileRead = dynamic_cast(dataFile); } } else if (event->getEventType() == EventTypeEnum::EVENT_DATA_FILE_READ) { EventDataFileRead* readEvent = dynamic_cast(event); CaretAssert(readEvent); /* * Determine if a scene file was read */ const int32_t numFilesRead = readEvent->getNumberOfDataFilesToRead(); for (int32_t i = (numFilesRead - 1); i >= 0; i--) { if ( ! readEvent->isFileError(i)) { if (readEvent->getDataFileType(i) == DataFileTypeEnum::SCENE) { CaretDataFile* dataFileRead = readEvent->getDataFileRead(i); lastSceneFileRead = dynamic_cast(dataFileRead); if (lastSceneFileRead != NULL) { break; } } } } } else if (event->getEventType() == EventTypeEnum::EVENT_DATA_FILE_RELOAD) { EventDataFileReload* reloadEvent = dynamic_cast(event); CaretAssert(reloadEvent); if ( ! reloadEvent->isError()) { CaretDataFile* dataFileRead = reloadEvent->getCaretDataFile(); lastSceneFileRead = dynamic_cast(dataFileRead); } } /* * If a scene file was read, make it the selected scene file * in this dialog. */ if (lastSceneFileRead != NULL) { loadSceneFileComboBox(lastSceneFileRead); loadScenesIntoDialog(NULL); highlightSceneAtIndex(0); m_sceneSelectionScrollArea->horizontalScrollBar()->setSliderPosition(0); } updateSceneFileModifiedStatusLabel(); } /** * @return True if user should be informed about * creating scenes when exiting wb_view (user * never created a scene). */ bool SceneDialog::isInformUserAboutScenesOnExit() { return s_informUserAboutScenesOnExitFlag; } /** * Under some circumstances, the user may be warned * when creating a new scene or scene file. * * @return * True if scene or scene file should be created, else false. */ bool SceneDialog::displayNewSceneWarning() { if (s_warnUserWhenCreatingSceneFlag) { s_warnUserWhenCreatingSceneFlag = false; ApplicationInformation appInfo; switch (appInfo.getWorkbenchSpecialVersion()) { case WorkbenchSpecialVersionEnum::WORKBENCH_SPECIAL_VERSION_NO: break; case WorkbenchSpecialVersionEnum::WORKBENCH_SPECIAL_VERSION_FIRST_CHARTING: { const QString text("This is a special version of Workbench that correctly " "displays scene files containing the first implementation " "of matrix and line charting. Charting is undergoing a " "redesign and any scenes created with this special version " "of Workbench will not display correctly in newer, official " "releases of Workbench."); if (WuQMessageBox::warningOkCancel(this, "Do you want to continue?", text)) { return true; } else { return false; } } break; } } return true; } /** * Update the modified status label. */ void SceneDialog::updateSceneFileModifiedStatusLabel() { /* * Modified icons in scene file selection combo box */ updateSceneFileComboBoxModifiedIcons(); /* * Modified status of selected scene file */ AString statusText; /* * Save button is enabled only if: * (1) The scene file is modified * (2) The filename is not the untitled file name */ bool haveScenesFlag = false; bool saveButtonEnabledFlag = false; SceneFile* sceneFile = getSelectedSceneFile(); if (sceneFile != NULL) { if (sceneFile->isModified()) { if (sceneFile->exists()) { saveButtonEnabledFlag = true; } statusText = "YES"; } else { statusText = "NO"; } if (sceneFile->getNumberOfScenes() > 0) { haveScenesFlag = true; } } m_sceneFileModifiedStatusLabel->setText(statusText); m_saveSceneFilePushButton->setEnabled(saveButtonEnabledFlag); m_showFileStructurePushButton->setEnabled(haveScenesFlag); m_zipSceneFilePushButton->setEnabled(haveScenesFlag); m_uploadSceneFilePushButton->setEnabled(haveScenesFlag); } /** * Called when help button is clicked. */ void SceneDialog::helpButtonClicked() { EventHelpViewerDisplay helpViewerEvent(NULL, "Scenes_Window"); EventManager::get()->sendEvent(helpViewerEvent.getPointer()); } /* ======================================================================== */ /** * \class caret::SceneClassWidget * \brief Dialog for manipulation of scenes. * \ingroup GuiQt */ /** * Constructor. */ SceneClassInfoWidget::SceneClassInfoWidget() : QGroupBox(0) { m_scene = NULL; m_sceneIndex = -1; m_defaultBackgroundRole = backgroundRole(); m_defaultAutoFillBackgroundStatus = autoFillBackground(); m_activeSceneLabel = new QLabel(); m_nameLabel = new QLabel(); m_nameLabel->setWordWrap(true); m_descriptionLabel = new QLabel(); m_descriptionLabel->setWordWrap(true); m_sceneIdLabel = new QLabel(); m_previewImageLabel = new QLabel(); m_previewImageLabel->setContentsMargins(0, 0, 0, 0); m_rightSideWidget = new QWidget(); QVBoxLayout* rightLayout = new QVBoxLayout(m_rightSideWidget); rightLayout->setContentsMargins(0, 0, 0, 0); rightLayout->setSpacing(3); rightLayout->addWidget(m_activeSceneLabel); rightLayout->addWidget(m_nameLabel,1); rightLayout->addWidget(m_sceneIdLabel); rightLayout->addWidget(m_descriptionLabel, 100); rightLayout->addStretch(); m_leftSideWidget = new QWidget(); QVBoxLayout* leftLayout = new QVBoxLayout(m_leftSideWidget); leftLayout->setContentsMargins(0, 0, 0, 0); leftLayout->setSpacing(0); leftLayout->addWidget(m_previewImageLabel); leftLayout->addStretch(); QHBoxLayout* layout = new QHBoxLayout(this); layout->setContentsMargins(0, 3, 0, 0); layout->setSpacing(3); layout->addWidget(m_leftSideWidget); layout->addWidget(m_rightSideWidget, 100, Qt::AlignTop); } /** * Destructor. */ SceneClassInfoWidget::~SceneClassInfoWidget() { } /** * Set/reset the background so that the widget appears to be * selected/unselected. * * @param selected * Selection status. */ void SceneClassInfoWidget::setBackgroundForSelected(const bool selected) { if (selected) { setAutoFillBackground(true); setBackgroundRole(QPalette::Highlight); } else { setAutoFillBackground(m_defaultAutoFillBackgroundStatus); setBackgroundRole(m_defaultBackgroundRole); } } /** * Update the content. * * @param scene * Scene for display. * @param sceneIndex * Index of the scene. * @param activeSceneFlag * True if this is the active scene */ void SceneClassInfoWidget::updateContent(Scene* scene, const int32_t sceneIndex, const bool activeSceneFlag) { m_scene = scene; m_sceneIndex = sceneIndex; if ((m_scene != NULL) && (m_sceneIndex >= 0)) { AString nameText; AString sceneIdText; AString descriptionText; const int32_t numLinesToDisplay = 9; SceneClassInfoWidget::getFormattedTextForSceneNameAndDescription(scene->getSceneInfo(), sceneIndex, nameText, sceneIdText, descriptionText, numLinesToDisplay); if (activeSceneFlag) { m_activeSceneLabel->setText("Current Scene"); m_activeSceneLabel->setVisible(true); } else { m_activeSceneLabel->setText(""); m_activeSceneLabel->setVisible(false); } m_nameLabel->setText(nameText); m_sceneIdLabel->setText(sceneIdText); m_descriptionLabel->setText(descriptionText); QByteArray imageByteArray; AString imageBytesFormat; scene->getSceneInfo()->getImageBytes(imageByteArray, imageBytesFormat); const int previewImageWidth = 192; QImage previewImage; bool previewImageValid = false; if (imageByteArray.length() > 0) { ImageFile imageFile; imageFile.setImageFromByteArray(imageByteArray, imageBytesFormat); previewImage = *imageFile.getAsQImage(); if ( ! previewImage.isNull()) { imageFile.resizeToWidth(previewImageWidth); QImage newPreviewImage = *imageFile.getAsQImage(); if ( ! newPreviewImage.isNull()) { previewImage = newPreviewImage; previewImageValid = true; } } } m_previewImageLabel->clear(); m_previewImageLabel->setAlignment(Qt::AlignHCenter | Qt::AlignTop); if (previewImageValid) { m_previewImageLabel->setPixmap(QPixmap::fromImage(previewImage)); } else { m_previewImageLabel->setText("No preview
    image"); } } } /** * Examine the given string for newlines and remove * any lines that exceed the maximum allowed. * * @param textLines * String containing lines of text separated by a newline character. * @param maximumNumberOfLines * Maximum number of lines for the text. */ void SceneClassInfoWidget::limitToNumberOfLines(AString& textLines, const int32_t maximumNumberOfLines) { if (textLines.isEmpty()) { return; } const QString lineSeparator("\n"); QStringList descriptionLines = textLines.split(lineSeparator, QString::KeepEmptyParts); const int32_t numLines = descriptionLines.size(); const int32_t numLinesToRemove = numLines - maximumNumberOfLines; if (numLinesToRemove > 0) { for (int32_t i = 0; i < numLinesToRemove; i++) { descriptionLines.pop_back(); } } textLines = descriptionLines.join(lineSeparator); } /** * Get formatted text for display of scene name and description. * * @param sceneInfo * Info for the scene. * @param nameTextOut * Text for name. * @param sceneIdTextOut * Text for scene ID. * @param desciptionTextOut * Text for description. * @param maximumLinesInDescription * Maximum number of lines allowed in description. * If value is negative, an unlimited number of lines are allowed. */ void SceneClassInfoWidget::getFormattedTextForSceneNameAndDescription(const SceneInfo* sceneInfo, const int32_t sceneIndex, AString& nameTextOut, AString& sceneIdTextOut, AString& descriptionTextOut, const int32_t maximumLinesInDescription) { CaretAssert(sceneInfo); AString name = sceneInfo->getName(); if (name.isEmpty()) { name = "NAME IS MISSING !!!"; } AString indexText; const bool showSceneIndexFlag = false; if (showSceneIndexFlag) { if (sceneIndex >= 0) { indexText = ("(" + AString::number(sceneIndex + 1) + ") "); } } nameTextOut = ("" + indexText + "NAME (" + AString::number(sceneIndex + 1) + "): " + name + ""); sceneIdTextOut = ("BALSA SCENE ID: " + sceneInfo->getBalsaSceneID() + ""); AString description = sceneInfo->getDescription(); if (maximumLinesInDescription > 0) { SceneClassInfoWidget::limitToNumberOfLines(description, maximumLinesInDescription); } if ( ! description.isEmpty()) { /* * HTML formatting is needed so text is properly displayed. * Want to put "Description" at beginning in bold but any * HTML tags are converted to text. So, after conversion to * HTML, perform a replace to insert "Description" in bold. */ const AString replaceWithDescriptionBoldText = "REPLACE_WITH_DESCRIPTION"; description = WuQtUtilities::createWordWrappedToolTipText(replaceWithDescriptionBoldText + description); description.replace(replaceWithDescriptionBoldText, "DESCRIPTION: "); } descriptionTextOut = description; } /** * Called by Qt when the mouse is pressed. * * @param event * The mouse event information. */ void SceneClassInfoWidget::mousePressEvent(QMouseEvent* event) { emit highlighted(m_sceneIndex); event->setAccepted(true); } /** * Called when the mouse is double clicked. * * @param event * The mouse event information. */ void SceneClassInfoWidget::mouseDoubleClickEvent(QMouseEvent* event) { emit activated(m_sceneIndex); event->setAccepted(true); } /** * @return The scene. */ Scene* SceneClassInfoWidget::getScene() { return m_scene; } /** * @return The index of the scene. */ int32_t SceneClassInfoWidget::getSceneIndex() const { return m_sceneIndex; } /** * @return True if this scene class info widget is valid (has * a scene with a valid index). */ bool SceneClassInfoWidget::isValid() const { if ((m_scene != NULL) && (m_sceneIndex >= 0)) { return true; } return false; } connectome-workbench-1.4.2/src/GuiQt/SceneDialog.h000066400000000000000000000247411360521144700220110ustar00rootroot00000000000000#ifndef __SCENE_DIALOG__H_ #define __SCENE_DIALOG__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "EventListenerInterface.h" #include "GuiManager.h" #include "WuQDialogNonModal.h" class QCheckBox; class QCloseEvent; class QComboBox; class QLabel; class QLineEdit; class QPushButton; class QScrollArea; class QVBoxLayout; namespace caret { class Scene; class SceneClassInfoWidget; class SceneFile; class SceneInfo; class WuQDataEntryDialog; class WuQWidgetObjectGroup; class SceneDialog : public WuQDialogNonModal, public EventListenerInterface { Q_OBJECT public: SceneDialog(QWidget* parent = 0); virtual ~SceneDialog(); void updateDialog(); void receiveEvent(Event* event); bool displayScene(SceneFile* sceneFile, Scene* scene); void createDefaultSceneFile(); static bool isInformUserAboutScenesOnExit(); static bool checkForModifiedFiles(const GuiManager::TestModifiedMode testMode, QWidget* parent); static bool displaySceneWithErrorMessageDialog(QWidget* dialogParent, SceneFile* sceneFile, Scene* scene); private: SceneDialog(const SceneDialog&); SceneDialog& operator=(const SceneDialog&); private slots: virtual void closeButtonClicked(); void sceneFileSelected(int); void newSceneFileButtonClicked(); void openSceneFileButtonClicked(); void saveSceneFileButtonClicked(); void saveAsSceneFileButtonClicked(); void uploadSceneFileButtonClicked(); void zipSceneFileButtonClicked(); void addNewSceneButtonClicked(); void deleteSceneButtonClicked(); void insertSceneButtonClicked(); void moveSceneUpButtonClicked(); void moveSceneDownButtonClicked(); void replaceSceneButtonClicked(); void showSceneButtonClicked(); void showImagePreviewButtonClicked(); void showSceneOptionsButtonClicked(); void validateContentOfCreateSceneDialog(WuQDataEntryDialog*); void sceneHighlighted(const int32_t sceneIndex); void sceneActivated(const int32_t sceneIndex); void useSceneColorsCheckBoxClicked(bool checked); void testScenesPushButtonClicked(); void replaceAllScenesPushButtonClicked(); void showFileStructure(); public: // ADD_NEW_METHODS_HERE protected: virtual void closeEvent(QCloseEvent* event); virtual void helpButtonClicked() override; private: SceneFile* getSelectedSceneFile(); Scene* getSelectedScene(); void loadSceneFileComboBox(SceneFile* selectedSceneFileIn); void updateSceneFileComboBoxModifiedIcons(); void loadScenesIntoDialog(Scene* selectedSceneIn); int32_t getNumberOfValidSceneInfoWidgets() const; void addImageToScene(Scene* scene); void highlightSceneAtIndex(const int32_t sceneIndex); void highlightScene(const Scene* scene); QWidget* createScenesWidget(); QWidget* createSceneFileWidget(); static bool displayScenePrivateWithErrorMessageDialog(QWidget* dialogParent, SceneFile* sceneFile, Scene* scene, const bool showWaitCursor); static bool displayScenePrivateWithErrorMessage(SceneFile* sceneFile, Scene* scene, const bool showWaitCursor, AString& errorMessageOut); bool displayNewSceneWarning(); void enableSceneMoveUpAndDownButtons(); void updateSceneFileModifiedStatusLabel(); QImage* getQImageFromSceneInfo(const SceneInfo* sceneInfo) const; enum class ModifiedWarningType { CLOSE_DIALOG_BUTTON, FILE_COMBO_BOX_CHANGE_FILE, NEW_FILE_BUTTON, OPEN_FILE_BUTTON, UPLOAD_FILE_BUTTON, ZIP_FILE_BUTTON }; enum class MissingFilesMode { UPLOAD, ZIP }; bool warnIfSceneFileIsModified(const ModifiedWarningType warningType); bool saveSelectedSceneFile(); bool saveAsSelectedSceneFile(); bool warnIfMissingFilesInSceneFile(SceneFile* sceneFile, const MissingFilesMode missingFilesMode); // ADD_NEW_MEMBERS_HERE QLabel* m_sceneFileModifiedStatusLabel; QComboBox* m_sceneFileSelectionComboBox; QPushButton* m_showFileStructurePushButton; QPushButton* m_newSceneFilePushButton; QPushButton* m_openSceneFilePushButton; QPushButton* m_saveSceneFilePushButton; QPushButton* m_saveAsSceneFilePushButton; QPushButton* m_uploadSceneFilePushButton; QPushButton* m_zipSceneFilePushButton; QPushButton* m_addNewScenePushButton; QPushButton* m_insertNewScenePushButton; QPushButton* m_deleteScenePushButton; QPushButton* m_replaceAllScenesPushButton; QPushButton* m_testScenesPushButton; QPushButton* m_moveSceneUpPushButton; QPushButton* m_moveSceneDownPushButton; QPushButton* m_replaceScenePushButton; QPushButton* m_showScenePushButton; QPushButton* m_showSceneImagePreviewPushButton; QPushButton* m_showSceneOptionsPushButton; QScrollArea* m_sceneSelectionScrollArea; QWidget* m_sceneSelectionWidget; QVBoxLayout* m_sceneSelectionLayout; std::vector m_sceneClassInfoWidgets; int32_t m_selectedSceneClassInfoIndex; WuQWidgetObjectGroup* m_sceneFileButtonsGroup; AString m_replaceAllScenesDescription; AString m_testAllScenesDescription; QIcon m_cautionIcon; bool m_cautionIconValid = false; static const AString PREFERRED_IMAGE_FORMAT; static bool s_informUserAboutScenesOnExitFlag; static bool s_warnUserWhenCreatingSceneFlag; static bool s_useSceneForegroundBackgroundColorsFlag; }; class SceneClassInfoWidget : public QGroupBox { Q_OBJECT public: SceneClassInfoWidget(); ~SceneClassInfoWidget(); void updateContent(Scene* scene, const int32_t sceneIndex, const bool activeSceneFlag); void setBackgroundForSelected(const bool selected); Scene* getScene(); int32_t getSceneIndex() const; bool isValid() const; static void getFormattedTextForSceneNameAndDescription(const SceneInfo* sceneInfo, const int32_t sceneIndex, AString& nameTextOut, AString& sceneIdTextOut, AString& descriptionTextOut, const int32_t maximumLinesInDescription); signals: /** * Emited when user activates (double clicks) this widget. */ void activated(const int32_t sceneIndex); /** * Emited when user highlights (clicks) this widget. */ void highlighted(const int32_t sceneIndex); protected: virtual void mousePressEvent(QMouseEvent* event); virtual void mouseDoubleClickEvent(QMouseEvent* event); private: static void limitToNumberOfLines(AString& textLines, const int32_t maximumNumberOfLines); QWidget* m_leftSideWidget; QWidget* m_rightSideWidget; QLabel* m_previewImageLabel; QLabel* m_activeSceneLabel; QLabel* m_nameLabel; QLabel* m_sceneIdLabel; QLabel* m_descriptionLabel; Scene* m_scene; int32_t m_sceneIndex; bool m_previewImageValid; bool m_defaultAutoFillBackgroundStatus; QPalette::ColorRole m_defaultBackgroundRole; }; #ifdef __SCENE_DIALOG_DECLARE__ const AString SceneDialog::PREFERRED_IMAGE_FORMAT = "jpg"; bool SceneDialog::s_informUserAboutScenesOnExitFlag = true; bool SceneDialog::s_warnUserWhenCreatingSceneFlag = true; bool SceneDialog::s_useSceneForegroundBackgroundColorsFlag = true; #endif // __SCENE_DIALOG_DECLARE__ } // namespace #endif //__SCENE_DIALOG__H_ connectome-workbench-1.4.2/src/GuiQt/SceneFileInformationDialog.cxx000066400000000000000000000300631360521144700253640ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SCENE_FILE_INFORMATION_DIALOG_DECLARE__ #include "SceneFileInformationDialog.h" #undef __SCENE_FILE_INFORMATION_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include #include "CaretAssert.h" #include "CursorDisplayScoped.h" #include "FileInformation.h" #include "SceneDataFileTreeItemModel.h" #include "SceneFile.h" #include "WuQMessageBox.h" using namespace caret; /** * \class caret::SceneFileInformationDialog * \brief Dialog for display of scene file organization * \ingroup GuiQt */ /** * Constructor. * * @param sceneFile * The scene file whose file information is displayed. * @param parent * Dialog's parent widget. */ SceneFileInformationDialog::SceneFileInformationDialog(const SceneFile* sceneFile, QWidget* parent) : WuQDialogNonModal("Files and Folders", parent), m_sceneFile(sceneFile) { setDeleteWhenClosed(true); setApplyButtonText(""); AString basePathName; std::vector missingDataFiles; AString basePathErrorMessage; const bool validBasePathFlag = sceneFile->findBaseDirectoryForDataFiles(basePathName, missingDataFiles, basePathErrorMessage); if ( ! validBasePathFlag) { basePathName = basePathErrorMessage; } QLabel* basePathLabel = new QLabel("Base Path:"); m_basePathLineEdit = new QLineEdit(); m_basePathLineEdit->setReadOnly(true); m_basePathLineEdit->setText(basePathName); m_basePathLineEdit->home(true); FileInformation sceneFileInfo(sceneFile->getFileName()); QLabel* sceneFileNameLabel = new QLabel("Scene File Name:"); m_sceneFileNameLineEdit = new QLineEdit(); m_sceneFileNameLineEdit->setReadOnly(true); m_sceneFileNameLineEdit->setText(sceneFileInfo.getFileName()); m_sceneFileNameLineEdit->home(true); QLabel* sceneFilePathLabel = new QLabel("Scene File Path:"); m_sceneFilePathLineEdit = new QLineEdit(); m_sceneFilePathLineEdit->setReadOnly(true); m_sceneFilePathLineEdit->setText(sceneFileInfo.getPathName()); m_sceneFilePathLineEdit->home(true); m_textEdit = new QTextEdit(); m_sceneFileHierarchyTreeView = new QTreeView(); m_sceneFileHierarchyTreeView->setHeaderHidden(true); QTabWidget* tabWidget = new QTabWidget(); tabWidget->addTab(m_sceneFileHierarchyTreeView, "Hierarchy"); tabWidget->addTab(m_textEdit, "List"); QGridLayout* namesLayout = new QGridLayout(); namesLayout->setColumnStretch(0, 0); namesLayout->setColumnStretch(1, 100); namesLayout->addWidget(basePathLabel, 0, 0); namesLayout->addWidget(m_basePathLineEdit, 0, 1); namesLayout->addWidget(sceneFileNameLabel, 1, 0); namesLayout->addWidget(m_sceneFileNameLineEdit, 1, 1); namesLayout->addWidget(sceneFilePathLabel, 2, 0); namesLayout->addWidget(m_sceneFilePathLineEdit, 2, 1); QWidget* dialogWidget = new QWidget(); QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); dialogLayout->setSpacing(3); dialogLayout->addLayout(namesLayout, 0); dialogLayout->addWidget(tabWidget, 100); setCentralWidget(dialogWidget, WuQDialog::SCROLL_AREA_NEVER); displayFilesHierarchy(); displayFilesList(); setSizeOfDialogWhenDisplayed(QSize(600, 800)); } /** * Destructor. */ SceneFileInformationDialog::~SceneFileInformationDialog() { } ///** // * Setup the list of files // */ //void //SceneFileInformationDialog::displayFilesList() //{ // const SceneDataFileInfo::SortMode sortMode = SceneDataFileInfo::SortMode::RelativeToSceneFilePath; // CaretAssert(m_sceneFile); // // std::vector fileSceneInfo = m_sceneFile->getAllDataFileInfoFromAllScenes(); // SceneDataFileInfo::sort(fileSceneInfo, // sortMode); // // if (fileSceneInfo.empty()) { // WuQMessageBox::errorOk(this, // "Scene file is empty."); // return; // } // // AString baseDirectoryName; // std::vector missingFileNames; // AString errorMessage; // const bool validBasePathFlag = m_sceneFile->findBaseDirectoryForDataFiles(baseDirectoryName, // missingFileNames, // errorMessage); // // const AString sceneFileName = m_sceneFile->getFileName(); // AString text(""); // // text.appendWithNewLine("Automatic Base Path: " // + (validBasePathFlag ? baseDirectoryName : ("INVALID: " + errorMessage)) // + "

    "); // text.appendWithNewLine("Scene File: " // + sceneFileName // + "

    "); // // bool needListEndElementFlag = false; // AString lastPathName("bogus ##(*&$UI()#NFGK path name"); // for (const auto& fileData : fileSceneInfo) { // AString missingText; // // AString pathName; // switch (sortMode) { // case SceneDataFileInfo::SortMode::AbsolutePath: // pathName = fileData.getAbsolutePath(); // break; // case SceneDataFileInfo::SortMode::RelativeToBasePath: // pathName = fileData.getRelativePathToBasePath(); // if (pathName.isEmpty()) { // pathName = "Files in Base Path"; // } // break; // case SceneDataFileInfo::SortMode::RelativeToSceneFilePath: // pathName = fileData.getRelativePathToSceneFile(); // if (pathName.isEmpty()) { // pathName = "Files in Scene File Path"; // } // break; // } // // if (pathName != lastPathName) { // if (needListEndElementFlag) { // text.append(""); // } // text.append("

    " // + pathName // + ""); // text.append("

      "); // needListEndElementFlag = true; // lastPathName = pathName; // } // // if (fileData.isMissing()) { // missingText = "MISSING "; // } // // text.append("
    • " // + missingText // + fileData.getDataFileName() // + " (" // + fileData.getSceneIndicesAsString() // + ")"); // } // if (needListEndElementFlag) { // text.append("
    "); // } // text.append(""); // // m_textEdit->clear(); // m_textEdit->setHtml(text); //} /** * Setup the list of files */ void SceneFileInformationDialog::displayFilesList() { const SceneDataFileInfo::SortMode sortMode = SceneDataFileInfo::SortMode::RelativeToSceneFilePath; CaretAssert(m_sceneFile); std::vector fileSceneInfo = m_sceneFile->getAllDataFileInfoFromAllScenes(); SceneDataFileInfo::sort(fileSceneInfo, sortMode); if (fileSceneInfo.empty()) { WuQMessageBox::errorOk(this, "Scene file is empty."); return; } AString baseDirectoryName; std::vector missingFileNames; AString errorMessage; const bool validBasePathFlag = m_sceneFile->findBaseDirectoryForDataFiles(baseDirectoryName, missingFileNames, errorMessage); const AString sceneFileName = m_sceneFile->getFileName(); AString text(""); text.appendWithNewLine("Automatic Base Path: " + (validBasePathFlag ? baseDirectoryName : ("INVALID: " + errorMessage)) + "

    "); text.appendWithNewLine("Scene File: " + sceneFileName + "

    "); AString pathName; switch (sortMode) { case SceneDataFileInfo::SortMode::AbsolutePath: pathName = "Absolute File Paths"; break; case SceneDataFileInfo::SortMode::RelativeToBasePath: pathName = "Files in Base Path"; break; case SceneDataFileInfo::SortMode::RelativeToSceneFilePath: pathName = "Data File paths relative to Scene File"; break; } text.append("" + pathName + ""); text.append("

      "); for (const auto& fileData : fileSceneInfo) { AString missingText; AString pathName; switch (sortMode) { case SceneDataFileInfo::SortMode::AbsolutePath: pathName = fileData.getAbsolutePath(); break; case SceneDataFileInfo::SortMode::RelativeToBasePath: pathName = fileData.getRelativePathToBasePath(); break; case SceneDataFileInfo::SortMode::RelativeToSceneFilePath: pathName = fileData.getRelativePathToSceneFile(); break; } if (! pathName.isEmpty()) { pathName.append("/ "); } if (fileData.isMissing()) { missingText = " "; } text.append("
    • " + missingText + pathName + fileData.getDataFileName() + " (" + fileData.getSceneIndicesAsString() + ")"); } text.append("
    "); text.append(""); m_textEdit->clear(); m_textEdit->setHtml(text); } /** * Setup the hierarchy of files */ void SceneFileInformationDialog::displayFilesHierarchy() { AString baseDirectoryName; std::vector missingFileNames; AString errorMessage; const bool validBasePathFlag = m_sceneFile->findBaseDirectoryForDataFiles(baseDirectoryName, missingFileNames, errorMessage); if ( ! validBasePathFlag) { return; } CaretAssert(m_sceneFile); std::vector fileSceneInfo = m_sceneFile->getAllDataFileInfoFromAllScenes(); SceneDataFileInfo::sort(fileSceneInfo, SceneDataFileInfo::SortMode::AbsolutePath); m_sceneFileHierarchyTreeModel.reset(new SceneDataFileTreeItemModel(m_sceneFile->getFileName(), baseDirectoryName, fileSceneInfo, SceneDataFileInfo::SortMode::AbsolutePath)); m_sceneFileHierarchyTreeView->setModel(m_sceneFileHierarchyTreeModel.get()); m_sceneFileHierarchyTreeView->expandAll(); } connectome-workbench-1.4.2/src/GuiQt/SceneFileInformationDialog.h000066400000000000000000000044771360521144700250230ustar00rootroot00000000000000#ifndef __SCENE_FILE_INFORMATION_DIALOG_H__ #define __SCENE_FILE_INFORMATION_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "WuQDialogNonModal.h" class QLineEdit; class QTextEdit; class QTreeView; namespace caret { class SceneDataFileTreeItemModel; class SceneFile; class SceneFileInformationDialog : public WuQDialogNonModal { Q_OBJECT public: SceneFileInformationDialog(const SceneFile* sceneFile, QWidget* parent); virtual ~SceneFileInformationDialog(); SceneFileInformationDialog(const SceneFileInformationDialog&) = delete; SceneFileInformationDialog& operator=(const SceneFileInformationDialog&) = delete; // ADD_NEW_METHODS_HERE private: void displayFilesList(); void displayFilesHierarchy(); const SceneFile* m_sceneFile; QTextEdit* m_textEdit; QTreeView* m_sceneFileHierarchyTreeView; std::unique_ptr m_sceneFileHierarchyTreeModel; QLineEdit* m_basePathLineEdit; QLineEdit* m_sceneFileNameLineEdit; QLineEdit* m_sceneFilePathLineEdit; // ADD_NEW_MEMBERS_HERE }; #ifdef __SCENE_FILE_INFORMATION_DIALOG_DECLARE__ // #endif // __SCENE_FILE_INFORMATION_DIALOG_DECLARE__ } // namespace #endif //__SCENE_FILE_INFORMATION_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/ScenePreviewDialog.cxx000066400000000000000000000104451360521144700237220ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SCENE_PREVIEW_DIALOG_DECLARE__ #include "ScenePreviewDialog.h" #undef __SCENE_PREVIEW_DIALOG_DECLARE__ #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "DataFileException.h" #include "ImageFile.h" #include "Scene.h" #include "SceneDialog.h" #include "SceneInfo.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::ScenePreviewDialog * \brief Non-modal dialog that shows preview image of a scene. * \ingroup GuiQt */ /** * Constructor. */ ScenePreviewDialog::ScenePreviewDialog(const Scene* scene, QWidget* parent) : WuQDialogNonModal(scene->getName(), parent) { /* * Dialog will be deleted when closed. */ setDeleteWhenClosed(true); setApplyButtonText(""); setCloseButtonText("Close"); QByteArray imageByteArray; AString imageBytesFormat; scene->getSceneInfo()->getImageBytes(imageByteArray, imageBytesFormat); QLabel* imageLabel = new QLabel(); bool imageValidFlag = false; try { if (imageByteArray.length() > 0) { ImageFile imageFile; imageFile.setImageFromByteArray(imageByteArray, imageBytesFormat); const QImage* image = imageFile.getAsQImage(); if (image != NULL) { if (image->isNull()) { CaretLogSevere("Preview image is invalid (isNull)"); } else { imageLabel->setPixmap(QPixmap::fromImage(*image)); imageValidFlag = true; } } } } catch (const DataFileException& dfe) { CaretLogSevere("Converting preview to image: " + dfe.whatString()); } if ( ! imageValidFlag) { imageLabel->setText("No image available"); } AString nameText; AString sceneIdText; AString descriptionText; const int32_t negativeIsUnlimitedNumberOfLines = -1; SceneClassInfoWidget::getFormattedTextForSceneNameAndDescription(scene->getSceneInfo(), -1, nameText, sceneIdText, descriptionText, negativeIsUnlimitedNumberOfLines); QLabel* nameLabel = new QLabel(nameText); QLabel* sceneIdLabel = new QLabel(sceneIdText); QLabel* descriptionLabel = NULL; if (! descriptionText.isEmpty()) { descriptionLabel = new QLabel(descriptionText); descriptionLabel->setWordWrap(true); } QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(imageLabel); layout->addWidget(nameLabel); layout->addWidget(sceneIdLabel); if (descriptionLabel != NULL) { layout->addWidget(descriptionLabel); } setCentralWidget(widget, SCROLL_AREA_ALWAYS); WuQtUtilities::limitWindowSizePercentageOfMaximum(this, 90.0, 80.0); } /** * Destructor. */ ScenePreviewDialog::~ScenePreviewDialog() { } /** May be called requesting the dialog to update its content */ void ScenePreviewDialog::updateDialog() { /* nothing to update */ } connectome-workbench-1.4.2/src/GuiQt/ScenePreviewDialog.h000066400000000000000000000033261360521144700233470ustar00rootroot00000000000000#ifndef __SCENE_PREVIEW_DIALOG_H__ #define __SCENE_PREVIEW_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WuQDialogNonModal.h" namespace caret { class Scene; class ScenePreviewDialog : public WuQDialogNonModal { Q_OBJECT public: ScenePreviewDialog(const Scene* scene, QWidget* parent); virtual ~ScenePreviewDialog(); /** May be called requesting the dialog to update its content */ virtual void updateDialog(); // ADD_NEW_METHODS_HERE private: ScenePreviewDialog(const ScenePreviewDialog&); ScenePreviewDialog& operator=(const ScenePreviewDialog&); // ADD_NEW_MEMBERS_HERE }; #ifdef __SCENE_PREVIEW_DIALOG_DECLARE__ // #endif // __SCENE_PREVIEW_DIALOG_DECLARE__ } // namespace #endif //__SCENE_PREVIEW_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/SceneReplaceAllDialog.cxx000066400000000000000000000050031360521144700242770ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SCENE_REPLACE_ALL_DIALOG_DECLARE__ #include "SceneReplaceAllDialog.h" #undef __SCENE_REPLACE_ALL_DIALOG_DECLARE__ #include #include #include #include #include "CaretAssert.h" using namespace caret; /** * \class caret::SceneReplaceAllDialog * \brief Dialog for replacing scenes * \ingroup GuiQt */ /** * Constructor. */ SceneReplaceAllDialog::SceneReplaceAllDialog(const AString& replaceDescription, QWidget* parent) : WuQDialogModal("Replace All Scenes", parent) { QLabel* slowLabel = new QLabel(replaceDescription); slowLabel->setWordWrap(true); m_changeSurfaceAnntotationOffsetCheckBox = new QCheckBox("Change offset of all surface annotations to TANGENT"); QGroupBox* optionsGroupBox = new QGroupBox("Options"); QVBoxLayout* optionsLayout = new QVBoxLayout(optionsGroupBox); optionsLayout->addWidget(m_changeSurfaceAnntotationOffsetCheckBox); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(slowLabel); layout->addWidget(optionsGroupBox); setCentralWidget(widget, WuQDialogModal::SCROLL_AREA_NEVER); } /** * Destructor. */ SceneReplaceAllDialog::~SceneReplaceAllDialog() { } /** * Is true if the offset for all surface annotations should be changed * to TANGENT. */ bool SceneReplaceAllDialog::isChangeSurfaceAnnotationOffsetToOffset() const { return m_changeSurfaceAnntotationOffsetCheckBox->isChecked(); } /** * Called when OK button is clicked. */ void SceneReplaceAllDialog::okButtonClicked() { WuQDialogModal::okButtonClicked(); } connectome-workbench-1.4.2/src/GuiQt/SceneReplaceAllDialog.h000066400000000000000000000035751360521144700237400ustar00rootroot00000000000000#ifndef __SCENE_REPLACE_ALL_DIALOG_H__ #define __SCENE_REPLACE_ALL_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "WuQDialogModal.h" class QCheckBox; namespace caret { class SceneReplaceAllDialog : public WuQDialogModal { Q_OBJECT public: SceneReplaceAllDialog(const AString& replaceDescription, QWidget* parent = 0); virtual ~SceneReplaceAllDialog(); SceneReplaceAllDialog(const SceneReplaceAllDialog&) = delete; SceneReplaceAllDialog& operator=(const SceneReplaceAllDialog&) = delete; bool isChangeSurfaceAnnotationOffsetToOffset() const; protected: virtual void okButtonClicked(); // ADD_NEW_METHODS_HERE private: QCheckBox* m_changeSurfaceAnntotationOffsetCheckBox; // ADD_NEW_MEMBERS_HERE }; #ifdef __SCENE_REPLACE_ALL_DIALOG_DECLARE__ // #endif // __SCENE_REPLACE_ALL_DIALOG_DECLARE__ } // namespace #endif //__SCENE_REPLACE_ALL_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/SceneShowOptionsDialog.cxx000066400000000000000000000107451360521144700246000ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SCENE_SHOW_OPTIONS_DIALOG_DECLARE__ #include "SceneShowOptionsDialog.h" #undef __SCENE_SHOW_OPTIONS_DIALOG_DECLARE__ #include #include #include #include #include #include "CaretAssert.h" #include "WuQDataEntryDialog.h" using namespace caret; /** * \class caret::SceneShowOptionsDialog * \brief Dialog for setting show scene options * \ingroup GuiQt */ /** * Constructor. * * @param options * Options displayed in dialog. * @param parent * Optional parent for dialog. */ SceneShowOptionsDialog::SceneShowOptionsDialog(const Options& options, QWidget* parent) : WuQDialogModal("Show Scene Options", parent) { /* * Use colors contained in the scene for background and foreground */ const QString colorTip("Override foreground/background colors from preferences with those in scene"); m_useSceneColorsCheckBox = new QCheckBox("Use background and foreground colors from scene"); m_useSceneColorsCheckBox->setToolTip(colorTip); m_useSceneColorsCheckBox->setChecked(options.isUseSceneColorsSelected()); m_useSceneColorsToolButton = new QToolButton(); m_useSceneColorsToolButton->setText("Info..."); QObject::connect(m_useSceneColorsToolButton, &QToolButton::clicked, this, &SceneShowOptionsDialog::useSceneColorsInfoButtonClicked); QHBoxLayout* useSceneColorsLayout = new QHBoxLayout(); useSceneColorsLayout->addWidget(m_useSceneColorsCheckBox); useSceneColorsLayout->addWidget(m_useSceneColorsToolButton); useSceneColorsLayout->addStretch(); QWidget* dialogWidget = new QWidget; QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); dialogLayout->addLayout(useSceneColorsLayout); dialogWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); setCentralWidget(dialogWidget, WuQDialog::SCROLL_AREA_NEVER); } /** * Destructor. */ SceneShowOptionsDialog::~SceneShowOptionsDialog() { } /** * @return Status of options in dialog. */ SceneShowOptionsDialog::Options SceneShowOptionsDialog::getOptions() const { return Options(m_useSceneColorsCheckBox->isChecked()); } void SceneShowOptionsDialog::useSceneColorsInfoButtonClicked() { const QString infoText("Scenes created after 01 May 2016 contain the background and foreground from when the\n" "scene was created. If this box is checked, background and foreground colors from the\n" "scene will override the foreground and background colors in the Preferences Dialog.\n" "The background and foreground colors will revert to those on the Preferences Dialog\n" "when any of these events occur:\n" " * This checkbox is unchecked\n" " * A scene without background and foreground colors is loaded\n" " * A Spec File and its data files are loaded\n" " * File Menu->Close All Files is selected\n" " * Any of the colors on the Preferences Dialog are changed\n" " * The user quits wb_view"); WuQDataEntryDialog ded("Scene Colors Info", m_useSceneColorsToolButton); ded.hideCancelButton(); QLabel* label = new QLabel(infoText); ded.addWidget(label); ded.exec(); } /** * Gets called if the user presses the OK button. */ void SceneShowOptionsDialog::okButtonClicked() { WuQDialogModal::okButtonClicked(); } connectome-workbench-1.4.2/src/GuiQt/SceneShowOptionsDialog.h000066400000000000000000000051451360521144700242230ustar00rootroot00000000000000#ifndef __SCENE_SHOW_OPTIONS_DIALOG_H__ #define __SCENE_SHOW_OPTIONS_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "WuQDialogModal.h" class QCheckBox; class QToolButton; namespace caret { class SceneShowOptionsDialog : public WuQDialogModal { Q_OBJECT public: /** * Options for display in dialog */ class Options { public: /** * Constructor * * @param useSceneColorsSelected * Status of use scene colors */ Options(const bool useSceneColorsSelected) : m_useSceneColorsSelected(useSceneColorsSelected) { } /** @return Status of use scene colors */ bool isUseSceneColorsSelected() const { return m_useSceneColorsSelected; } private: bool m_useSceneColorsSelected = false; }; SceneShowOptionsDialog(const Options& options, QWidget* parent = 0); virtual ~SceneShowOptionsDialog(); Options getOptions() const; // ADD_NEW_METHODS_HERE protected: virtual void okButtonClicked(); void useSceneColorsInfoButtonClicked(); private: SceneShowOptionsDialog(const SceneShowOptionsDialog&); SceneShowOptionsDialog& operator=(const SceneShowOptionsDialog&); QCheckBox* m_useSceneColorsCheckBox; QToolButton* m_useSceneColorsToolButton; // ADD_NEW_MEMBERS_HERE }; #ifdef __SCENE_SHOW_OPTIONS_DIALOG_DECLARE__ // #endif // __SCENE_SHOW_OPTIONS_DIALOG_DECLARE__ } // namespace #endif //__SCENE_SHOW_OPTIONS_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/SceneWindowGeometry.cxx000066400000000000000000000256141360521144700241500ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #define __SCENE_WINDOW_GEOMETRY_DECLARE__ #include "SceneWindowGeometry.h" #undef __SCENE_WINDOW_GEOMETRY_DECLARE__ #include "BrainBrowserWindow.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::SceneWindowGeometry * \brief Assists with saving and restoring a window's geometry * \ingroup GuiQt */ /** * Constructor for window that is child of the first browser window. * @param window * The window for which geometry is restored/saved */ SceneWindowGeometry::SceneWindowGeometry(QWidget* window) : CaretObject() { m_window = window; m_parentWindow = NULL; } /** * Constructor for window that is child of the given parent window. * The window is ALWAYS positioned relative to the parent. * @param window * The window for which geometry is restored/saved * @param parentWindow * The parent window of 'window'. */ SceneWindowGeometry::SceneWindowGeometry(QWidget* window, QWidget* parentWindow) : CaretObject() { m_window = window; m_parentWindow = parentWindow; } /** * Destructor. */ SceneWindowGeometry::~SceneWindowGeometry() { } /** * Set the coordinates of the first browser window invalid. * Normally called at beginning of scene restoration prior * to restoration of windows. */ void SceneWindowGeometry::setFirstBrowserWindowCoordinatesInvalid() { s_firstBrowserWindowCoordinatesValid = false; s_firstBrowserWindow = NULL; } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* SceneWindowGeometry::saveToScene(const SceneAttributes* /*sceneAttributes*/, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "SceneWindowGeometry", 1); /* * Position and size */ sceneClass->addInteger("geometryX", m_window->x()); sceneClass->addInteger("geometryY", m_window->y()); sceneClass->addInteger("geometryWidth", m_window->width()); sceneClass->addInteger("geometryHeight", m_window->height()); int32_t geometryOffsetX = 0; int32_t geometryOffsetY = 0; if (m_parentWindow != NULL) { geometryOffsetX = m_window->x() - m_parentWindow->x(); geometryOffsetY = m_window->y() - m_parentWindow->y(); } sceneClass->addInteger("geometryOffsetX", geometryOffsetX); sceneClass->addInteger("geometryOffsetY", geometryOffsetY); sceneClass->addBoolean("visibility", m_window->isVisible()); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void SceneWindowGeometry::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } /* * Get window geometry from the scene */ const int32_t sceneX = sceneClass->getIntegerValue("geometryX", 100); const int32_t sceneY = sceneClass->getIntegerValue("geometryY", 100); const int32_t sceneWidth = sceneClass->getIntegerValue("geometryWidth", -1); const int32_t sceneHeight = sceneClass->getIntegerValue("geometryHeight", -1); const int32_t offsetX = sceneClass->getIntegerValue("geometryOffsetX", 100); const int32_t offsetY = sceneClass->getIntegerValue("geometryOffsetY", 100); const bool windowVisible = sceneClass->getBooleanValue("visibility", true); const bool isDialog = (qobject_cast(m_window) != NULL); QDockWidget* dockWidget = qobject_cast(m_window); const bool isDockWidget = (dockWidget != NULL); const bool isWindow = (qobject_cast(m_window) != NULL); bool isWidget = true; if (isDialog || isDockWidget || isWindow) { isWidget = false; } /* * If it is a widget */ if (isWidget) { if ((sceneWidth > 0) && (sceneHeight > 0)) { m_window->resize(sceneWidth, sceneHeight); return; } } /* * If dock widget and not floating * just set size and exit */ if (isDockWidget && (dockWidget->isFloating() == false)) { if ((sceneWidth > 0) && (sceneHeight > 0)) { m_window->resize(sceneWidth, sceneHeight); return; } } /* * Is this window always positions relative to parent window? */ if (m_parentWindow != NULL) { /* * Get offset from parent */ const int32_t windowX = m_parentWindow->x() + offsetX; const int32_t windowY = m_parentWindow->y() + offsetY; /* * Move the window to its desired position and set its width/height * but limit to available screen space */ int32_t xywh[4]; WuQtUtilities::moveAndSizeWindow(m_window, windowX, windowY, sceneWidth, sceneHeight, xywh); return; } /* * Visibility */ m_window->setVisible(windowVisible); /* * Is this a browser window? */ bool isFirstBrowserWindow = false; BrainBrowserWindow* browserWindow = dynamic_cast(m_window); if (browserWindow != NULL) { /* * Is this the first browser window being restored? * If so, save its positions from scene file and * its actual position. */ if (s_firstBrowserWindowCoordinatesValid == false) { isFirstBrowserWindow = true; } } /* * Determine how windows are positions and sized */ bool isResizeWindow = false; bool isMoveWindow = false; bool isMoveWindowRelative = false; switch (sceneAttributes->getRestoreWindowBehaviorInSceneDisplay()) { case SceneAttributes::RESTORE_WINDOW_USE_ALL_POSITIONS_AND_SIZES: isResizeWindow = true; isMoveWindow = true; break; case SceneAttributes::RESTORE_WINDOW_IGNORE_ALL_POSITIONS_AND_SIZES: break; case SceneAttributes::RESTORE_WINDOW_POSITION_RELATIVE_TO_FIRST_AND_USE_SIZES: if (isFirstBrowserWindow == false) { isMoveWindow = true; isMoveWindowRelative = true; } isResizeWindow = true; break; } // const QDesktopWidget* desktopWidget = QApplication::desktop(); // const QSize screenSize = WuQtUtilities::getMinimumScreenSize(); // const int maxX = screenSize.width() - 100; // const int maxY = screenSize.height() - 100; /* * Position of window defaults to window's current position */ int32_t windowX = m_window->x(); int32_t windowY = m_window->y(); if (isMoveWindow) { if ((sceneX > 0) & (sceneY > 0)) { /* * Use position in scene */ windowX = sceneX; windowY = sceneY; /* * Move position relative to first window? */ if (isMoveWindowRelative) { if ((s_firstBrowserWindowRestoredX > 0) && (s_firstBrowserWindowRestoredY > 0)) { const int32_t dx = windowX - s_firstBrowserWindowSceneX; const int32_t dy = windowY - s_firstBrowserWindowSceneY; windowX = s_firstBrowserWindowRestoredX + dx; windowY = s_firstBrowserWindowRestoredY + dy; } else { } } } } /* * NOT Resize window? */ int32_t windowWidth = sceneWidth; int32_t windowHeight = sceneHeight; if (isResizeWindow == false) { windowWidth = -1; windowHeight = -1; } /* * Move the window to its desired position and set its width/height * but limit to available screen space */ int32_t xywh[4]; WuQtUtilities::moveAndSizeWindow(m_window, windowX, windowY, windowWidth, windowHeight, xywh); /* * Is this a browser window? */ if (isFirstBrowserWindow) { s_firstBrowserWindowCoordinatesValid = true; s_firstBrowserWindow = browserWindow; s_firstBrowserWindowSceneX = sceneX; s_firstBrowserWindowSceneY = sceneY; s_firstBrowserWindowRestoredX = xywh[0]; s_firstBrowserWindowRestoredY = xywh[1]; } } connectome-workbench-1.4.2/src/GuiQt/SceneWindowGeometry.h000066400000000000000000000066371360521144700236010ustar00rootroot00000000000000#ifndef __SCENE_WINDOW_GEOMETRY__H_ #define __SCENE_WINDOW_GEOMETRY__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "SceneableInterface.h" class QWidget; namespace caret { class BrainBrowserWindow; class SceneAttributes; class SceneClass; class SceneWindowGeometry : public CaretObject, public SceneableInterface { public: SceneWindowGeometry(QWidget* window); SceneWindowGeometry(QWidget* window, QWidget* parentWindow); virtual ~SceneWindowGeometry(); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); static void setFirstBrowserWindowCoordinatesInvalid(); private: SceneWindowGeometry(const SceneWindowGeometry&); SceneWindowGeometry& operator=(const SceneWindowGeometry&); /** The window whose geometry is restored/saved */ QWidget* m_window; /** Optional parent window (may be NULL) */ QWidget* m_parentWindow; /** X-coordinate of first browser window from the scene file */ static int32_t s_firstBrowserWindowSceneX; /** Y-coordinate of first browser window from the scene file */ static int32_t s_firstBrowserWindowSceneY; /** X-coordinate of first browser window after restoration from scene */ static int32_t s_firstBrowserWindowRestoredX; /** Y-coordinate of first browser window after restoration from scene */ static int32_t s_firstBrowserWindowRestoredY; /** First browser window */ static BrainBrowserWindow* s_firstBrowserWindow; /** Are first browser window coordinates valid */ static bool s_firstBrowserWindowCoordinatesValid; // ADD_NEW_MEMBERS_HERE }; #ifdef __SCENE_WINDOW_GEOMETRY_DECLARE__ BrainBrowserWindow* SceneWindowGeometry::s_firstBrowserWindow = NULL; int32_t SceneWindowGeometry::s_firstBrowserWindowSceneX = 0; int32_t SceneWindowGeometry::s_firstBrowserWindowSceneY = 0; int32_t SceneWindowGeometry::s_firstBrowserWindowRestoredX = 0; int32_t SceneWindowGeometry::s_firstBrowserWindowRestoredY = 0; bool SceneWindowGeometry::s_firstBrowserWindowCoordinatesValid = false; #endif // __SCENE_WINDOW_GEOMETRY_DECLARE__ } // namespace #endif //__SCENE_WINDOW_GEOMETRY__H_ connectome-workbench-1.4.2/src/GuiQt/SpecFileManagementDialog.cxx000066400000000000000000003341701360521144700250160ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SPEC_FILE_MANAGEMENT_DIALOG_DECLARE__ #include "SpecFileManagementDialog.h" #undef __SPEC_FILE_MANAGEMENT_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "AnnotationFile.h" #include "Brain.h" #include "BrowserTabContent.h" #include "BrainBrowserWindow.h" #include "CaretAssert.h" #include "CaretDataFile.h" #include "CaretFileDialog.h" #include "CaretLogger.h" #include "CaretMappableDataFile.h" #include "CaretPreferences.h" #include "CursorDisplayScoped.h" #include "DataFileContentCopyMoveDialog.h" #include "DataFileContentCopyMoveInterface.h" #include "DataFileException.h" #include "DataFileContentInformation.h" #include "EventBrowserTabGetAllViewed.h" #include "EventDataFileRead.h" #include "EventDataFileReload.h" #include "EventGetDisplayedDataFiles.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventShowDataFileReadWarningsDialog.h" #include "EventSpecFileReadDataFiles.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUserInterfaceUpdate.h" #include "FileInformation.h" #include "GuiManager.h" #include "MetaDataEditorDialog.h" #include "ProgressReportingDialog.h" #include "SessionManager.h" #include "SpecFile.h" #include "SpecFileDataFile.h" #include "SpecFileDataFileTypeGroup.h" #include "UsernamePasswordWidget.h" #include "WuQImageLabel.h" #include "WuQMessageBox.h" #include "WuQTextEditorDialog.h" #include "WuQWidgetObjectGroup.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::SpecFileManagementDialog * \brief Dialog for operations with Spec Files. * \ingroup GuiQt */ /** * Run a dialog for opening a spec file. * * @param brain * Brain into which spec file is read. * @param specFile * Spec File. * @param parent * Parent of dialog. * @return * True if user loaded the spec file, else false. */ bool SpecFileManagementDialog::runOpenSpecFileDialog(Brain* brain, SpecFile* specFile, BrainBrowserWindow* parent) { CaretAssert(brain); CaretAssert(specFile); const AString title = ("Open Spec File: " + specFile->getFileNameNoPath()); SpecFileManagementDialog dialog(MODE_OPEN_SPEC_FILE, brain, specFile, title, parent); if (dialog.exec() == SpecFileManagementDialog::Accepted) { return true; } return false; } /** * Run a dialog for managing files in a brain. * * DO NOT delete the returned dialog as it will delete itself when closed. * * @param brain * Brain for which files are managed. * @param parent * Parent of dialog. */ void SpecFileManagementDialog::runManageFilesDialog(Brain* brain, BrainBrowserWindow* parent) { CaretAssert(brain); const AString title = ("Manage Data Files"); SpecFileManagementDialog dialog(MODE_MANAGE_FILES, brain, brain->getSpecFile(), title, parent); /* * Override view files type the first time the dialog is displayed * using the value from the user's preferences */ static bool firstTime = true; if (firstTime) { const CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); s_manageFilesViewFilesType = prefs->getManageFilesViewFileType(); firstTime = false; } dialog.setFilterSelections(s_manageFilesViewFilesType, s_manageFilesFilteredDataFileType, s_manageFilesFilteredStructureType); if ( ! s_manageFilesGeometry.isEmpty()) { dialog.restoreGeometry(s_manageFilesGeometry); } dialog.loadSpecFileContentIntoDialog(); dialog.exec(); dialog.getFilterSelections(s_manageFilesViewFilesType, s_manageFilesFilteredDataFileType, s_manageFilesFilteredStructureType); s_manageFilesGeometry = dialog.saveGeometry(); } /** * Run a dialog for saving files in a brain while exiting workbench. * * DO NOT delete the returned dialog as it will delete itself when closed. * * @param brain * Brain for which files are managed. * @param parent * Parent of dialog. * @return * true if workbench is allowed to exit, else false. */ bool SpecFileManagementDialog::runSaveFilesDialogWhileQuittingWorkbench(Brain* brain, BrainBrowserWindow* parent) { CaretAssert(brain); const AString title = ("Save Data Files"); SpecFileManagementDialog dialog(MODE_SAVE_FILES_WHILE_QUITTING, brain, brain->getSpecFile(), title, parent); if (dialog.exec()) { return true; } return false; } /** * Constructor. * * @param dialogMode * Mode of dialog. * @param brain * Brain * @param specFile * Spec File. * @param dialogTitle * Title for dialog. * @param parent * Parent of dialog. */ SpecFileManagementDialog::SpecFileManagementDialog(const Mode dialogMode, Brain* brain, SpecFile* specFile, const AString& dialogTitle, BrainBrowserWindow* parent) : WuQDialogModal(dialogTitle, parent), m_parentBrainBrowserWindow(parent), m_dialogMode(dialogMode), m_brain(brain), m_specFile(specFile) { CaretAssert(parent); /* * Initialize members */ m_filesTableWidget = NULL; m_fileSelectionActionGroup = NULL; m_manageFilesLoadedNotLoadedActionGroup = NULL; m_specFileDataFileCounter = 0; m_specFileTableRowIndex = -1; m_sceneAnnotationFileRowIndex = -1; m_fileSorting = SpecFileManagementDialogRowContent::SORTING_TYPE_STRUCTURE_NAME; /* * Load icons. */ m_iconOpenFile = WuQtUtilities::loadIcon(":/SpecFileDialog/load_icon.png"); m_iconOptions = WuQtUtilities::loadIcon(":/SpecFileDialog/options_icon.png"); m_iconReloadFile = WuQtUtilities::loadIcon(":/SpecFileDialog/reload_icon.png"); m_iconCloseFile = WuQtUtilities::loadIcon(":/SpecFileDialog/delete_icon.png"); /* * Open Spec File or Manage Files? */ bool enableManageItems = false; bool enableOpenItems = false; switch (m_dialogMode) { case SpecFileManagementDialog::MODE_MANAGE_FILES: case SpecFileManagementDialog::MODE_SAVE_FILES_WHILE_QUITTING: m_specFile->setModifiedFilesSelectedForSaving(); enableManageItems = true; break; case SpecFileManagementDialog::MODE_OPEN_SPEC_FILE: enableOpenItems = true; break; } /* * Signal mappers for buttons */ m_fileReloadOrOpenFileActionSignalMapper = new QSignalMapper(this); QObject::connect(m_fileReloadOrOpenFileActionSignalMapper, SIGNAL(mapped(int)), this, SLOT(fileReloadOrOpenFileActionSelected(int))); m_fileOptionsActionSignalMapper = new QSignalMapper(this); QObject::connect(m_fileOptionsActionSignalMapper, SIGNAL(mapped(int)), this, SLOT(fileOptionsActionSelected(int))); m_fileCloseFileActionSignalMapper = new QSignalMapper(this); QObject::connect(m_fileCloseFileActionSignalMapper, SIGNAL(mapped(int)), this, SLOT(fileRemoveActionSelected(int))); int tableRowCounter = 0; /* * Spec and scene annotations only when managing files */ if (enableManageItems) { m_specFileTableRowIndex = tableRowCounter++; m_sceneAnnotationFileRowIndex = tableRowCounter++; } bool testForDisplayedDataFiles = false; m_loadScenesPushButton = NULL; switch (m_dialogMode) { case SpecFileManagementDialog::MODE_MANAGE_FILES: setOkButtonText("Save Checked Files"); setCancelButtonText("Close"); testForDisplayedDataFiles = true; break; case SpecFileManagementDialog::MODE_OPEN_SPEC_FILE: setOkButtonText("Load"); setCancelButtonText("Cancel"); m_loadScenesPushButton = addUserPushButton("Load Scenes", QDialogButtonBox::AcceptRole); break; case SpecFileManagementDialog::MODE_SAVE_FILES_WHILE_QUITTING: setOkButtonText("Save Selected Files and Exit"); setCancelButtonText("Cancel"); testForDisplayedDataFiles = true; break; } if (testForDisplayedDataFiles) { const std::vector windowIndices = GuiManager::get()->getAllOpenBrainBrowserWindowIndices(); /* * Get all browser tabs and only save transformations for tabs * that are valid. */ EventBrowserTabGetAllViewed getViewedTabs; EventManager::get()->sendEvent(getViewedTabs.getPointer()); std::vector tabIndices = getViewedTabs.getViewdedBrowserTabIndices(); EventGetDisplayedDataFiles displayedFilesEvent(windowIndices, tabIndices); EventManager::get()->sendEvent(displayedFilesEvent.getPointer()); m_displayedDataFiles = displayedFilesEvent.getDisplayedDataFiles(); } /* * Set column indices for table's members */ int columnCounter = 0; m_COLUMN_LOAD_CHECKBOX = -1; m_COLUMN_SAVE_CHECKBOX = -1; m_COLUMN_STATUS_LABEL = -1; m_COLUMN_DISPLAYED_LABEL = -1; m_COLUMN_IN_SPEC_FILE_CHECKBOX = -1; m_COLUMN_READ_BUTTON = -1; m_COLUMN_CLOSE_BUTTON = -1; m_COLUMN_OPTIONS_TOOLBUTTON = -1; m_COLUMN_DATA_FILE_TYPE_LABEL = -1; m_COLUMN_STRUCTURE = -1; m_COLUMN_FILE_NAME_LABEL = -1; m_COLUMN_COUNT = -1; if (enableOpenItems) { m_COLUMN_LOAD_CHECKBOX = columnCounter++; } if (enableManageItems) { m_COLUMN_SAVE_CHECKBOX = columnCounter++; m_COLUMN_STATUS_LABEL = columnCounter++; m_COLUMN_DISPLAYED_LABEL = columnCounter++; m_COLUMN_IN_SPEC_FILE_CHECKBOX = columnCounter++; m_COLUMN_READ_BUTTON = columnCounter++; m_COLUMN_CLOSE_BUTTON = columnCounter++; } m_COLUMN_OPTIONS_TOOLBUTTON = columnCounter++; m_COLUMN_DATA_FILE_TYPE_LABEL = columnCounter++; m_COLUMN_STRUCTURE = columnCounter++; m_COLUMN_FILE_NAME_LABEL = columnCounter++; m_COLUMN_COUNT = columnCounter++; /* * Get the content from the spec file. * It is examined when creating some of the toolbars. */ getDataFileContentFromSpecFile(); /* * Create the table */ m_filesTableWidget = new QTableWidget(); m_filesTableWidget->setAlternatingRowColors(true); m_filesTableWidget->setSelectionBehavior(QTableWidget::SelectItems); m_filesTableWidget->setSelectionMode(QTableWidget::SingleSelection); QObject::connect(m_filesTableWidget, SIGNAL(cellChanged(int,int)), this, SLOT(filesTableWidgetCellChanged(int,int))); QObject::connect(m_filesTableWidget->horizontalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(horizontalHeaderSelectedForSorting(int))); const QString headerToolTip = ("Click on the column names (of those columns that contain text) to sort."); m_filesTableWidget->horizontalHeader()->setToolTip(WuQtUtilities::createWordWrappedToolTipText(headerToolTip)); /* * Widget and layout for files. * * Two layouts used so widget is pushed to the top left (and not * spread out) when groups of files are hidden. */ QWidget* centralWidget = NULL; centralWidget = m_filesTableWidget; m_filesTableWidget->resizeColumnsToContents(); m_filesTableWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); QWidget* toolbarWidget = new QWidget(); QVBoxLayout* toolbarLayout = new QVBoxLayout(toolbarWidget); WuQtUtilities::setLayoutSpacingAndMargins(toolbarLayout, 0, 0); QLabel* fileTypesToolBarLabel = NULL; toolbarLayout->addWidget(createFilesTypesToolBar(fileTypesToolBarLabel)); QLabel* fileStructureToolBarLabel = NULL; toolbarLayout->addWidget(createStructureToolBar(fileStructureToolBarLabel)); QLabel* fileSelectionToolBarLabel = NULL; QLabel* fileLoadedNotLoadedToolBarLabel = NULL; if (enableOpenItems) { toolbarLayout->addWidget(createFilesSelectionToolBar(fileSelectionToolBarLabel)); } else if (enableManageItems) { toolbarLayout->addWidget(createManageFilesLoadedNotLoadedToolBar(fileLoadedNotLoadedToolBarLabel)); } toolbarWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); /* * Make all of the toolbar labels have the same width to that * they line up nicely. Note that the match widgets widgets * method will ignore NULL values. */ WuQtUtilities::matchWidgetWidths(fileTypesToolBarLabel, fileStructureToolBarLabel, fileSelectionToolBarLabel, fileLoadedNotLoadedToolBarLabel); /* * No scrollbars in dialog since the table widget will have scroll bars */ // const bool enableScrollBars = false; setTopBottomAndCentralWidgets(toolbarWidget, centralWidget, NULL, WuQDialog::SCROLL_AREA_NEVER); /* * Display the data files. */ updateTableDimensionsToFitFiles(); loadSpecFileContentIntoDialog(); disableAutoDefaultForAllPushButtons(); // /* // * Table widget has a default size of 640 x 480. // * So estimate the size of the dialog with the table fully // * expanded. // */ // QHeaderView* columnHeader = m_filesTableWidget->horizontalHeader(); // const int columnHeaderHeight = columnHeader->sizeHint().height(); // // int dialogWidth = 10; // start out with a little extra space // int dialogHeight = 0; // // const int numRows = m_filesTableWidget->rowCount(); // const int numCols = m_filesTableWidget->columnCount(); // const int cellGap = 1; // if ((numRows > 0) // && (numCols > 0)) { // for (int i = 0; i < numCols; i++) { // dialogWidth += (m_filesTableWidget->columnWidth(i) + cellGap); // std::cout << "column width " << i << ": " << m_filesTableWidget->columnWidth(i) << std::endl; // } // // for (int i = 0; i < numRows; i++) { // dialogHeight += (m_filesTableWidget->rowHeight(i) + cellGap); // } // } const QSize tableSize = WuQtUtilities::estimateTableWidgetSize(m_filesTableWidget); int dialogWidth = std::max(tableSize.width(), toolbarWidget->sizeHint().width()); int dialogHeight = (toolbarWidget->sizeHint().height() + getDialogButtonBox()->sizeHint().height() + tableSize.height()); WuQtUtilities::resizeWindow(this, dialogWidth, dialogHeight); } /** * Destructor. */ SpecFileManagementDialog::~SpecFileManagementDialog() { clearSpecFileManagementDialogRowContent(); if (m_iconOpenFile != NULL) { delete m_iconOpenFile; } if (m_iconOptions != NULL) { delete m_iconOptions; } if (m_iconReloadFile != NULL) { delete m_iconReloadFile; } if (m_iconCloseFile != NULL) { delete m_iconCloseFile; } } /** * Clear content of all of the table row. */ void SpecFileManagementDialog::clearSpecFileManagementDialogRowContent() { const int32_t numRows = static_cast(m_tableRowDataFileContent.size()); for (int32_t i = 0; i < numRows; i++) { delete m_tableRowDataFileContent[i]; } m_tableRowDataFileContent.clear(); } /** * Get the info about the data files from the spec file. */ void SpecFileManagementDialog::getDataFileContentFromSpecFile() { clearSpecFileManagementDialogRowContent(); bool haveSceneFiles = false; /* * Display each type of data file */ const int32_t numGroups = m_specFile->getNumberOfDataFileTypeGroups(); for (int32_t ig = 0 ; ig < numGroups; ig++) { /* * File type of group */ SpecFileDataFileTypeGroup* group = m_specFile->getDataFileTypeGroupByIndex(ig); const DataFileTypeEnum::Enum dataFileType = group->getDataFileType(); const int32_t numFiles = group->getNumberOfFiles(); for (int iFile = 0; iFile < numFiles; iFile++) { SpecFileDataFile* sfdf = group->getFileInformation(iFile); /* * If the spec file entry is not a member of the spec file, * AND if it does not match a loaded file * AND the file does not exist * THEN the file likely was a duplicate (more than one copy * of a specific file was loaded with the same name) and * the user had removed it from Workbench. * * So, hide the file from view. */ if ( ! sfdf->isSpecFileMember()) { if (sfdf->getCaretDataFile() == NULL) { if (! sfdf->exists()) { continue; } } } SpecFileManagementDialogRowContent* rowContent = new SpecFileManagementDialogRowContent(group, sfdf); m_tableRowDataFileContent.push_back(rowContent); m_specFileDataFileCounter++; } if (dataFileType == DataFileTypeEnum::SCENE) { if (numFiles > 0) { haveSceneFiles = true; } } } if (m_loadScenesPushButton != NULL) { m_loadScenesPushButton->setEnabled(haveSceneFiles); } } /** * Called when the content of a cell changes. * Update corresponding item in the spec file. * * @param rowIndex * The row of the cell that was clicked. * @param columnIndex * The columnof the cell that was clicked. */ void SpecFileManagementDialog::filesTableWidgetCellChanged(int rowIndex, int columnIndex) { QTableWidgetItem* item = getTableWidgetItem(rowIndex, columnIndex); if (item != NULL) { /* * Is this the row containing the spec file? */ if (rowIndex == m_specFileTableRowIndex) { /* * Nothing to do for spec file */ } else if (rowIndex == m_sceneAnnotationFileRowIndex) { /* Nothing to do for annotation scene file */ } else { SpecFileManagementDialogRowContent* rowContent = getFileContentInRow(rowIndex); CaretAssert(rowContent); SpecFileDataFile* sfdf = rowContent->m_specFileDataFile; const bool isSelected = WuQtUtilities::checkStateToBool(item->checkState()); if (columnIndex == m_COLUMN_SAVE_CHECKBOX) { sfdf->setSavingSelected(isSelected); } else if (columnIndex == m_COLUMN_LOAD_CHECKBOX) { sfdf->setLoadingSelected(isSelected); } else if (columnIndex == m_COLUMN_IN_SPEC_FILE_CHECKBOX) { sfdf->setSpecFileMember(isSelected); updateSpecFileRowInTable(); /* * Check the Spec File SAVE checkbox since the user has changed the * "in spec" status for a data file */ if (m_specFileTableRowIndex >= 0) { QTableWidgetItem* saveItem = getTableWidgetItem(m_specFileTableRowIndex, m_COLUMN_SAVE_CHECKBOX); saveItem->setCheckState(Qt::Checked); } } } } enableLoadOrSaveButton(); } void SpecFileManagementDialog::enableLoadOrSaveButton() { bool isAnyFileSelected = false; if (m_specFile != NULL) { switch (m_dialogMode) { case MODE_MANAGE_FILES: case MODE_SAVE_FILES_WHILE_QUITTING: { if (m_specFile->getNumberOfFilesSelectedForSaving() > 0) { isAnyFileSelected = true; } QTableWidgetItem* specCheckItem = getTableWidgetItem(m_specFileTableRowIndex, m_COLUMN_SAVE_CHECKBOX); if (WuQtUtilities::checkStateToBool(specCheckItem->checkState())) { isAnyFileSelected = true; } } break; case MODE_OPEN_SPEC_FILE: if (m_specFile->getNumberOfFilesSelectedForLoading() > 0) { isAnyFileSelected = true; } break; } } QAbstractButton* okButton = getDialogButtonBox()->button(QDialogButtonBox::Ok); CaretAssert(okButton); okButton->setEnabled(isAnyFileSelected); } /** * Get the table widget item at the given row and column. If compiled * debug the assertions will fail if the row or column is invalid. * * @param rowIndex * The row of the desired cell. * @param columnIndex * The column of the desired cell. * @return * item at row and column. */ QTableWidgetItem* SpecFileManagementDialog::getTableWidgetItem(const int rowIndex, const int columnIndex) { CaretAssert((rowIndex >= 0) && (rowIndex < m_filesTableWidget->rowCount())); CaretAssert((columnIndex >= 0) && (columnIndex < m_filesTableWidget->columnCount())); return m_filesTableWidget->item(rowIndex, columnIndex); } /** * Set the table widget item at the given row and column. If compiled * debug the assertions will fail if the row or column is invalid. * * @param rowIndex * The row of the desired cell. * @param columnIndex * The column of the desired cell. * @param item * The item to add. */ void SpecFileManagementDialog::setTableWidgetItem(const int rowIndex, const int columnIndex, QTableWidgetItem* item) { CaretAssert(item); CaretAssert((rowIndex >= 0) && (rowIndex < m_filesTableWidget->rowCount())); CaretAssert((columnIndex >= 0) && (columnIndex < m_filesTableWidget->columnCount())); m_filesTableWidget->blockSignals(true); m_filesTableWidget->setItem(rowIndex, columnIndex, item); m_filesTableWidget->blockSignals(false); } /** * Set the labels for the column names in the table. */ void SpecFileManagementDialog::setTableColumnLabels() { /* * Set names of table's columns */ if (m_COLUMN_LOAD_CHECKBOX >= 0){ m_filesTableWidget->setHorizontalHeaderItem(m_COLUMN_LOAD_CHECKBOX, createHeaderTextItem("Load")); } if (m_COLUMN_SAVE_CHECKBOX >= 0){ m_filesTableWidget->setHorizontalHeaderItem(m_COLUMN_SAVE_CHECKBOX, createHeaderTextItem("Save")); } if (m_COLUMN_STATUS_LABEL >= 0){ m_filesTableWidget->setHorizontalHeaderItem(m_COLUMN_STATUS_LABEL, createHeaderTextItem("Modified")); } if (m_COLUMN_DISPLAYED_LABEL >= 0) { m_filesTableWidget->setHorizontalHeaderItem(m_COLUMN_DISPLAYED_LABEL, createHeaderTextItem("Displayed")); } if (m_COLUMN_IN_SPEC_FILE_CHECKBOX >= 0){ m_filesTableWidget->setHorizontalHeaderItem(m_COLUMN_IN_SPEC_FILE_CHECKBOX, createHeaderTextItem("In Spec")); } if (m_COLUMN_READ_BUTTON >= 0){ m_filesTableWidget->setHorizontalHeaderItem(m_COLUMN_READ_BUTTON, createHeaderTextItem("Read")); } if (m_COLUMN_CLOSE_BUTTON >= 0) { m_filesTableWidget->setHorizontalHeaderItem(m_COLUMN_CLOSE_BUTTON, createHeaderTextItem("Close")); } if (m_COLUMN_OPTIONS_TOOLBUTTON >= 0){ m_filesTableWidget->setHorizontalHeaderItem(m_COLUMN_OPTIONS_TOOLBUTTON, createHeaderTextItem("More")); } if (m_COLUMN_DATA_FILE_TYPE_LABEL >= 0){ m_filesTableWidget->setHorizontalHeaderItem(m_COLUMN_DATA_FILE_TYPE_LABEL, createHeaderTextItem("Data Type")); } if (m_COLUMN_STRUCTURE >= 0){ m_filesTableWidget->setHorizontalHeaderItem(m_COLUMN_STRUCTURE, createHeaderTextItem("Structure")); } if (m_COLUMN_FILE_NAME_LABEL >= 0){ m_filesTableWidget->setHorizontalHeaderItem(m_COLUMN_FILE_NAME_LABEL, createHeaderTextItem("Data File Name")); } } /** * @return A table widget item used in the column header. * * @param text * Text for the item. * @return Table widget item containing the given text. */ QTableWidgetItem* SpecFileManagementDialog::createHeaderTextItem(const QString& text) { QList sizesList = QFontDatabase::standardSizes(); std::sort(sizesList.begin(), sizesList.end()); QTableWidgetItem* item = createTextItem(); item->setText(text); QFont font = item->font(); QListIterator sizeIter(sizesList); while (sizeIter.hasNext()) { const int nextSize = sizeIter.next(); if (nextSize > font.pointSize()) { font.setPointSize(nextSize); break; } } font.setBold(true); item->setFont(font); return item; } /** * Load items into the table widget adding rows as needed. */ void SpecFileManagementDialog::updateTableDimensionsToFitFiles() { /* * If needed, add a row for the spec file */ m_specFileTableRowIndex = -1; m_sceneAnnotationFileRowIndex = -1; int numberOfRows = 0; switch (m_dialogMode) { case MODE_MANAGE_FILES: case MODE_SAVE_FILES_WHILE_QUITTING: m_specFileTableRowIndex = numberOfRows; numberOfRows++; // if ( ! m_brain->getSceneAnnotationFile()->isEmpty()) { m_sceneAnnotationFileRowIndex = numberOfRows; numberOfRows++; // } break; case MODE_OPEN_SPEC_FILE: break; } /* * Update rows indices for data files */ const int32_t numFiles = static_cast(m_tableRowDataFileContent.size()); for (int32_t i = 0; i < numFiles; i++) { m_tableRowDataFileContent[i]->m_tableRowIndex = numberOfRows; numberOfRows++; } /* * If the number of rows has not changed, no need to update table dimensions */ bool needToCreateColumnHeaders = false; if (numberOfRows == m_filesTableWidget->rowCount()) { return; } else if (m_filesTableWidget->rowCount() == 0) { needToCreateColumnHeaders = true; } /* * Update the dimensions of the table */ const int32_t firstNewRowIndex = m_filesTableWidget->rowCount(); m_filesTableWidget->setRowCount(numberOfRows); m_filesTableWidget->setColumnCount(m_COLUMN_COUNT); m_filesTableWidget->verticalHeader()->hide(); m_filesTableWidget->setGridStyle(Qt::NoPen); m_filesTableWidget->setSortingEnabled(false); if (needToCreateColumnHeaders) { setTableColumnLabels(); } const int32_t lastNewRowIndex = m_filesTableWidget->rowCount(); // value changed by setRowCount() /* * Add new cells to the table widget */ for (int32_t iRow = firstNewRowIndex; iRow < lastNewRowIndex; iRow++) { bool hasCloseCheckBoxFlag = true; bool hasDisplayedLabelFlag = true; bool hasInSpecCheckBoxFlag = true; bool hasLoadCheckBoxFlag = true; bool hasOptionsButtonFlag = true; bool hasReadCheckBoxFlag = true; bool hasSaveCheckBoxFlag = true; bool hasStatusLabelFlag = true; if (iRow == m_specFileTableRowIndex) { hasCloseCheckBoxFlag = false; hasDisplayedLabelFlag = false; hasInSpecCheckBoxFlag = false; hasLoadCheckBoxFlag = false; hasReadCheckBoxFlag = false; } else if (iRow == m_sceneAnnotationFileRowIndex) { hasDisplayedLabelFlag = false; hasInSpecCheckBoxFlag = false; hasLoadCheckBoxFlag = false; hasReadCheckBoxFlag = false; hasSaveCheckBoxFlag = false; } if (hasLoadCheckBoxFlag) { if (m_COLUMN_LOAD_CHECKBOX >= 0) { QTableWidgetItem* item = createCheckableItem(); item->setTextAlignment(Qt::AlignHCenter); setTableWidgetItem(iRow, m_COLUMN_LOAD_CHECKBOX, item); } } if (hasSaveCheckBoxFlag) { if (m_COLUMN_SAVE_CHECKBOX >= 0) { QTableWidgetItem* item = createCheckableItem(); item->setTextAlignment(Qt::AlignHCenter); setTableWidgetItem(iRow, m_COLUMN_SAVE_CHECKBOX, item); } } if (hasStatusLabelFlag) { if (m_COLUMN_STATUS_LABEL >= 0) { QTableWidgetItem* item = createTextItem(); setTableWidgetItem(iRow, m_COLUMN_STATUS_LABEL, item); /* * Text for modified cell is always red and centered */ item->setTextAlignment(Qt::AlignCenter); QBrush modifiedBrush = item->foreground(); modifiedBrush.setColor(Qt::red); item->setForeground(modifiedBrush); } } if (hasDisplayedLabelFlag) { if (m_COLUMN_DISPLAYED_LABEL >= 0) { QTableWidgetItem* item = createTextItem(); setTableWidgetItem(iRow, m_COLUMN_DISPLAYED_LABEL, item); item->setTextAlignment(Qt::AlignCenter); } } if (hasInSpecCheckBoxFlag) { if (m_COLUMN_IN_SPEC_FILE_CHECKBOX >= 0) { QTableWidgetItem* item = createCheckableItem(); item->setTextAlignment(Qt::AlignHCenter); setTableWidgetItem(iRow, m_COLUMN_IN_SPEC_FILE_CHECKBOX, item); } } if (hasReadCheckBoxFlag) { if (m_COLUMN_READ_BUTTON >= 0) { WuQImageLabel* loadImageLabel = new WuQImageLabel(m_iconReloadFile, "Reload"); QObject::connect(loadImageLabel, SIGNAL(clicked()), m_fileReloadOrOpenFileActionSignalMapper, SLOT(map())); m_fileReloadOrOpenFileActionSignalMapper->setMapping(loadImageLabel, iRow); m_filesTableWidget->setCellWidget(iRow, m_COLUMN_READ_BUTTON, loadImageLabel); } } if (hasCloseCheckBoxFlag) { if (m_COLUMN_CLOSE_BUTTON >= 0) { WuQImageLabel* closeImageLabel = new WuQImageLabel(m_iconCloseFile, "Close"); QObject::connect(closeImageLabel, SIGNAL(clicked()), m_fileCloseFileActionSignalMapper, SLOT(map())); m_fileCloseFileActionSignalMapper->setMapping(closeImageLabel, iRow); m_filesTableWidget->setCellWidget(iRow, m_COLUMN_CLOSE_BUTTON, closeImageLabel); } } if (hasOptionsButtonFlag) { if (m_COLUMN_OPTIONS_TOOLBUTTON >= 0) { WuQImageLabel* optionsImageLabel = new WuQImageLabel(m_iconOptions, "Options"); QObject::connect(optionsImageLabel, SIGNAL(clicked()), m_fileOptionsActionSignalMapper, SLOT(map())); m_fileOptionsActionSignalMapper->setMapping(optionsImageLabel, iRow); m_filesTableWidget->setCellWidget(iRow, m_COLUMN_OPTIONS_TOOLBUTTON, optionsImageLabel); } } if (m_COLUMN_DATA_FILE_TYPE_LABEL >= 0) { setTableWidgetItem(iRow, m_COLUMN_DATA_FILE_TYPE_LABEL, createTextItem()); } if (m_COLUMN_STRUCTURE >= 0) { setTableWidgetItem(iRow, m_COLUMN_STRUCTURE, createTextItem()); } if (m_COLUMN_FILE_NAME_LABEL >= 0) { setTableWidgetItem(iRow, m_COLUMN_FILE_NAME_LABEL, createTextItem()); } } } /** * Update the table row containing the spec file. */ void SpecFileManagementDialog::updateSpecFileRowInTable() { bool isUpdateRow = false; switch (m_dialogMode) { case MODE_MANAGE_FILES: case MODE_SAVE_FILES_WHILE_QUITTING: isUpdateRow = true; break; case MODE_OPEN_SPEC_FILE: break; } /* * Update spec file data */ if (isUpdateRow) { if (m_specFileTableRowIndex >= 0) { CaretAssert(m_COLUMN_DATA_FILE_TYPE_LABEL >= 0); QTableWidgetItem* dataTypeItem = getTableWidgetItem(m_specFileTableRowIndex, m_COLUMN_DATA_FILE_TYPE_LABEL); dataTypeItem->setText(getEditedDataFileTypeName(DataFileTypeEnum::SPECIFICATION)); CaretAssert(m_COLUMN_FILE_NAME_LABEL >= 0); QTableWidgetItem* nameItem = getTableWidgetItem(m_specFileTableRowIndex, m_COLUMN_FILE_NAME_LABEL); CaretAssert(nameItem); const AString specFileName = m_specFile->getFileName(); AString path; AString name; if (specFileName.isEmpty() == false) { FileInformation fileInfo(specFileName); path = fileInfo.getAbsolutePath(); name = fileInfo.getFileName(); } nameItem->setText(name); nameItem->setToolTip(path); CaretAssert(m_COLUMN_STATUS_LABEL >= 0); QTableWidgetItem* statusItem = getTableWidgetItem(m_specFileTableRowIndex, m_COLUMN_STATUS_LABEL); CaretAssert(statusItem); if (m_specFile->isModified()) { statusItem->setText("YES"); } else { statusItem->setText(""); } /* * Get filtering selections */ SpecFileDialogViewFilesTypeEnum::Enum viewFilesType; DataFileTypeEnum::Enum filteredDataFileType; StructureEnum::Enum filteredStructureType; getFilterSelections(viewFilesType, filteredDataFileType, filteredStructureType); bool hideSpecFileRow = false; if ((filteredStructureType != StructureEnum::ALL) && (filteredStructureType != StructureEnum::OTHER)) { hideSpecFileRow = true; } switch (viewFilesType) { case SpecFileDialogViewFilesTypeEnum::VIEW_FILES_ALL: break; case SpecFileDialogViewFilesTypeEnum::VIEW_FILES_LOADED: break; case SpecFileDialogViewFilesTypeEnum::VIEW_FILES_LOADED_MODIFIED: if (! m_specFile->isModified()) { hideSpecFileRow = true; } break; case SpecFileDialogViewFilesTypeEnum::VIEW_FILES_LOADED_NOT_MODIFIED: if (m_specFile->isModified()) { hideSpecFileRow = true; } break; case SpecFileDialogViewFilesTypeEnum::VIEW_FILES_NOT_LOADED: hideSpecFileRow = true; break; } if (filteredDataFileType != DataFileTypeEnum::UNKNOWN) { hideSpecFileRow = true; } m_filesTableWidget->setRowHidden(m_specFileTableRowIndex, hideSpecFileRow); } } } /** * Update the table row containing the annotation scene. */ void SpecFileManagementDialog::updateAnnotationSceneFileRowInTable() { bool isUpdateRow = false; switch (m_dialogMode) { case MODE_MANAGE_FILES: case MODE_SAVE_FILES_WHILE_QUITTING: isUpdateRow = true; break; case MODE_OPEN_SPEC_FILE: break; } /* * Update spec file data */ if (isUpdateRow) { if (m_sceneAnnotationFileRowIndex >= 0) { const AnnotationFile* sceneAnnotationFile = m_brain->getSceneAnnotationFile(); CaretAssert(m_COLUMN_DATA_FILE_TYPE_LABEL >= 0); QTableWidgetItem* dataTypeItem = getTableWidgetItem(m_sceneAnnotationFileRowIndex, m_COLUMN_DATA_FILE_TYPE_LABEL); dataTypeItem->setText("Scene Annotations"); CaretAssert(m_COLUMN_FILE_NAME_LABEL >= 0); QTableWidgetItem* nameItem = getTableWidgetItem(m_sceneAnnotationFileRowIndex, m_COLUMN_FILE_NAME_LABEL); CaretAssert(nameItem); nameItem->setText(""); nameItem->setToolTip(""); CaretAssert(m_COLUMN_STATUS_LABEL >= 0); QTableWidgetItem* statusItem = getTableWidgetItem(m_sceneAnnotationFileRowIndex, m_COLUMN_STATUS_LABEL); /* * Scene annotation file is considered modified if * it is NOT empty. */ const bool modifiedStatusFlag = sceneAnnotationFile->isModified(); CaretAssert(statusItem); if (modifiedStatusFlag) { statusItem->setText("YES"); } else { statusItem->setText(""); } const bool haveSceneAnnotationsFlag = ( ! sceneAnnotationFile->isEmpty()); QWidget* closeWidget = m_filesTableWidget->cellWidget(m_sceneAnnotationFileRowIndex, m_COLUMN_CLOSE_BUTTON); CaretAssert(closeWidget); QWidget* optionsWidget = m_filesTableWidget->cellWidget(m_sceneAnnotationFileRowIndex, m_COLUMN_OPTIONS_TOOLBUTTON); CaretAssert(optionsWidget); closeWidget->setEnabled(haveSceneAnnotationsFlag); optionsWidget->setEnabled(haveSceneAnnotationsFlag); /* * Get filtering selections */ SpecFileDialogViewFilesTypeEnum::Enum viewFilesType; DataFileTypeEnum::Enum filteredDataFileType; StructureEnum::Enum filteredStructureType; getFilterSelections(viewFilesType, filteredDataFileType, filteredStructureType); bool hideSceneAnnontationFileRow = false; if ((filteredStructureType != StructureEnum::ALL) && (filteredStructureType != StructureEnum::OTHER)) { hideSceneAnnontationFileRow = true; } switch (viewFilesType) { case SpecFileDialogViewFilesTypeEnum::VIEW_FILES_ALL: break; case SpecFileDialogViewFilesTypeEnum::VIEW_FILES_LOADED: break; case SpecFileDialogViewFilesTypeEnum::VIEW_FILES_LOADED_MODIFIED: if (! modifiedStatusFlag) { hideSceneAnnontationFileRow = true; } break; case SpecFileDialogViewFilesTypeEnum::VIEW_FILES_LOADED_NOT_MODIFIED: if (modifiedStatusFlag) { hideSceneAnnontationFileRow = true; } break; case SpecFileDialogViewFilesTypeEnum::VIEW_FILES_NOT_LOADED: hideSceneAnnontationFileRow = true; break; } if (filteredDataFileType != DataFileTypeEnum::UNKNOWN) { hideSceneAnnontationFileRow = true; } m_filesTableWidget->setRowHidden(m_sceneAnnotationFileRowIndex, hideSceneAnnontationFileRow); } } } /** * Gets called when a column header is selected. * @param logicalIndex * Index of item that was selected. */ void SpecFileManagementDialog::horizontalHeaderSelectedForSorting(int logicalIndex) { if (logicalIndex == m_COLUMN_DATA_FILE_TYPE_LABEL) { m_fileSorting = SpecFileManagementDialogRowContent::SORTING_TYPE_STRUCTURE_NAME; loadSpecFileContentIntoDialog(); } else if (logicalIndex == m_COLUMN_FILE_NAME_LABEL) { m_fileSorting = SpecFileManagementDialogRowContent::SORTING_NAME; loadSpecFileContentIntoDialog(); } else if (logicalIndex == m_COLUMN_STRUCTURE) { m_fileSorting = SpecFileManagementDialogRowContent::SORTING_STRUCTURE_TYPE_NAME; loadSpecFileContentIntoDialog(); } } /** * Get the file filtering selections * * @param viewFilesTypeOut * view files types * @param filteredDataFileTypeOut * Data file type * @param filteredStructureTypeOut * Structure */ void SpecFileManagementDialog::getFilterSelections(SpecFileDialogViewFilesTypeEnum::Enum& viewFilesTypeOut, DataFileTypeEnum::Enum& filteredDataFileTypeOut, StructureEnum::Enum& filteredStructureTypeOut) const { /* * All/Loaded/Not-Loaded */ viewFilesTypeOut = SpecFileDialogViewFilesTypeEnum::VIEW_FILES_ALL; if (m_manageFilesLoadedNotLoadedActionGroup != NULL) { const QAction* manageFileAction = m_manageFilesLoadedNotLoadedActionGroup->checkedAction(); if (manageFileAction != NULL) { viewFilesTypeOut = SpecFileDialogViewFilesTypeEnum::fromIntegerCode(manageFileAction->data().toInt(), NULL); } } /* * Filter for data file type selection */ filteredDataFileTypeOut = DataFileTypeEnum::UNKNOWN; const QAction* dataFileTypeAction = m_fileTypesActionGroup->checkedAction(); if (dataFileTypeAction != NULL) { const int dataFileTypeInt = dataFileTypeAction->data().toInt(); filteredDataFileTypeOut = DataFileTypeEnum::fromIntegerCode(dataFileTypeInt, NULL); } /* * Filter for structure */ filteredStructureTypeOut = StructureEnum::ALL; const QAction* filteredStructureAction = m_structureActionGroup->checkedAction(); if (filteredStructureAction != NULL) { const int structureTypeInt = filteredStructureAction->data().toInt(); filteredStructureTypeOut = StructureEnum::fromIntegerCode(structureTypeInt, NULL); } } /** * Set the file filtering selections * * @param viewFilesType * View files type * @param filteredDataFileType * Data file type * @param filteredStructureType * Structure */ void SpecFileManagementDialog::setFilterSelections(const SpecFileDialogViewFilesTypeEnum::Enum viewFilesType, const DataFileTypeEnum::Enum filteredDataFileType, const StructureEnum::Enum filteredStructureType) { const int32_t viewFilesTypeInt = SpecFileDialogViewFilesTypeEnum::toIntegerCode(viewFilesType); QList manageActions = m_manageFilesLoadedNotLoadedActionGroup->actions(); QListIterator manageIterator(manageActions); while (manageIterator.hasNext()) { QAction* action = manageIterator.next(); if (action->data().toInt() == viewFilesTypeInt) { action->setChecked(true); break; } } const int32_t dataFileTypeInt = DataFileTypeEnum::toIntegerCode(filteredDataFileType); QList fileTypeActions = m_fileTypesActionGroup->actions(); QListIterator fileTypeIterator(fileTypeActions); while (fileTypeIterator.hasNext()) { QAction* action = fileTypeIterator.next(); if (action->data() == dataFileTypeInt) { action->setChecked(true); break; } } const int32_t structureTypeInt = StructureEnum::toIntegerCode(filteredStructureType); QList structureTypeActions = m_structureActionGroup->actions(); QListIterator structureTypeIterator(structureTypeActions); while (structureTypeIterator.hasNext()) { QAction* action = structureTypeIterator.next(); if (action->data() == structureTypeInt) { action->setChecked(true); break; } } } ///** // * Less than method for sorting using the sorting key. // * // * @param item1 // * Tested for less than the item2 // * @param item2 // * Tested for greater than the item1 // * @return // * True if item1 is less than item2, else false. // */ //bool //lessThanForSorting(const SpecFileManagementDialogRowContent *item1, // const SpecFileManagementDialogRowContent* item2) //{ // return (item1->m_sortingKey < item2->m_sortingKey); //} /** * Sort the file content. */ void SpecFileManagementDialog::sortFileContent() { /* * Update key used for sorting */ const int32_t numDataFiles = static_cast(m_tableRowDataFileContent.size()); for (int32_t i = 0; i < numDataFiles; i++) { m_tableRowDataFileContent[i]->setSortingKey(m_fileSorting); } /* * Sort */ std::sort(m_tableRowDataFileContent.begin(), m_tableRowDataFileContent.end(), SpecFileManagementDialogRowContent::lessThanForSorting); /* * Update row indices in table */ int rowCounter = 0; if (m_specFileTableRowIndex >= 0) { rowCounter++; } if (m_sceneAnnotationFileRowIndex >= 0) { rowCounter++; } for (int32_t i = 0; i < numDataFiles; i++) { m_tableRowDataFileContent[i]->m_tableRowIndex= rowCounter; rowCounter++; } } /** * Load the spec file data into the dialog. */ void SpecFileManagementDialog::loadSpecFileContentIntoDialog() { /* * Disable signals so cell changed signal not emitted while * modifying table content. */ m_filesTableWidget->blockSignals(true); /* * Sort the rows */ sortFileContent(); SpecFileDialogViewFilesTypeEnum::Enum filteredViewFilesType; DataFileTypeEnum::Enum filteredDataFileType; StructureEnum::Enum filteredStructureType; getFilterSelections(filteredViewFilesType, filteredDataFileType, filteredStructureType); updateSpecFileRowInTable(); updateAnnotationSceneFileRowInTable(); /* * Load all of the data file content. */ const int32_t numDataFiles = static_cast(m_tableRowDataFileContent.size()); for (int32_t i = 0; i < numDataFiles; i++) { const int rowIndex = m_tableRowDataFileContent[i]->m_tableRowIndex; CaretAssert((rowIndex >= 0) && (rowIndex < m_filesTableWidget->rowCount())); SpecFileDataFile* specFileDataFile = m_tableRowDataFileContent[i]->m_specFileDataFile; CaretDataFile* caretDataFile = specFileDataFile->getCaretDataFile(); const StructureEnum::Enum structure = specFileDataFile->getStructure(); bool isFileSavable = false; if (caretDataFile != NULL) { if (caretDataFile->supportsWriting()) { isFileSavable = true; } } const DataFileTypeEnum::Enum dataFileType = specFileDataFile->getDataFileType(); switch (m_dialogMode) { case MODE_MANAGE_FILES: case MODE_SAVE_FILES_WHILE_QUITTING: { /* * Save checkbox */ CaretAssert(m_COLUMN_SAVE_CHECKBOX >= 0); QTableWidgetItem* saveItem = getTableWidgetItem(rowIndex, m_COLUMN_SAVE_CHECKBOX); CaretAssert(saveItem); if (isFileSavable) { saveItem->setFlags(saveItem->flags() | Qt::ItemIsEnabled); saveItem->setCheckState(WuQtUtilities::boolToCheckState(specFileDataFile->isSavingSelected())); } else { saveItem->setFlags(saveItem->flags() & (~ Qt::ItemIsEnabled)); saveItem->setCheckState(Qt::Unchecked); } /* * Status label. */ CaretAssert(m_COLUMN_STATUS_LABEL >= 0); QTableWidgetItem* statusItem = getTableWidgetItem(rowIndex, m_COLUMN_STATUS_LABEL); CaretAssert(statusItem); statusItem->setText(""); if (caretDataFile != NULL) { if (isFileSavable) { /* * Is this a Caret Mappable Data file and is the modification * only in the palette color mapping? */ CaretMappableDataFile* mapFile = dynamic_cast(caretDataFile); if (mapFile != NULL) { /* * Is modification just the palette color mapping? */ if (mapFile->isModifiedExcludingPaletteColorMapping()) { statusItem->setText("YES"); } else { switch (mapFile->getPaletteColorMappingModifiedStatus()) { case PaletteModifiedStatusEnum::MODIFIED: statusItem->setText("PALETTE"); break; case PaletteModifiedStatusEnum::MODIFIED_BY_SHOW_SCENE: statusItem->setText("SCENE PALETTE"); break; case PaletteModifiedStatusEnum::UNMODIFIED: break; } } } else { if (caretDataFile->isModified()) { statusItem->setText("YES"); } } } } /* * Displayed label. */ CaretAssert(m_COLUMN_DISPLAYED_LABEL >= 0); QTableWidgetItem* displayedItem = getTableWidgetItem(rowIndex, m_COLUMN_DISPLAYED_LABEL); CaretAssert(displayedItem); displayedItem->setText(""); if (caretDataFile != NULL) { if (m_displayedDataFiles.find(caretDataFile) != m_displayedDataFiles.end()) { displayedItem->setText("YES"); } } /* * In-spec checkbox */ CaretAssert(m_COLUMN_IN_SPEC_FILE_CHECKBOX >= 0); QTableWidgetItem* inSpecItem = getTableWidgetItem(rowIndex, m_COLUMN_IN_SPEC_FILE_CHECKBOX); CaretAssert(inSpecItem); inSpecItem->setCheckState(WuQtUtilities::boolToCheckState(specFileDataFile->isSpecFileMember())); /* * Read button */ CaretAssert(m_COLUMN_READ_BUTTON >= 0); QWidget* readCellWidget = m_filesTableWidget->cellWidget(rowIndex, m_COLUMN_READ_BUTTON); CaretAssert(readCellWidget); WuQImageLabel* readImageLabel = dynamic_cast(readCellWidget); CaretAssert(readImageLabel); QWidget* closeWidget = m_filesTableWidget->cellWidget(rowIndex, m_COLUMN_CLOSE_BUTTON); CaretAssert(closeWidget); closeWidget->setEnabled(caretDataFile != NULL); if (caretDataFile != NULL) { readImageLabel->updateIconText(m_iconReloadFile, "Reload"); readImageLabel->setToolTip("Reload this file"); } else { readImageLabel->updateIconText(m_iconOpenFile, "Load"); readImageLabel->setToolTip("Load this file"); } } break; case MODE_OPEN_SPEC_FILE: { /* * Load checkbox */ CaretAssert(m_COLUMN_LOAD_CHECKBOX >= 0); QTableWidgetItem* loadItem = getTableWidgetItem(rowIndex, m_COLUMN_LOAD_CHECKBOX); CaretAssert(loadItem); loadItem->setCheckState(WuQtUtilities::boolToCheckState(specFileDataFile->isLoadingSelected())); } break; } /* * Data file type label */ CaretAssert(m_COLUMN_DATA_FILE_TYPE_LABEL >= 0); QTableWidgetItem* dataTypeItem = getTableWidgetItem(rowIndex, m_COLUMN_DATA_FILE_TYPE_LABEL); CaretAssert(dataTypeItem); dataTypeItem->setText(SpecFileManagementDialog::getEditedDataFileTypeName(dataFileType)); /* * Structure label */ CaretAssert(m_COLUMN_STRUCTURE >= 0); QTableWidgetItem* structureItem = getTableWidgetItem(rowIndex, m_COLUMN_STRUCTURE); CaretAssert(structureItem); structureItem->setText(""); if (DataFileTypeEnum::isFileUsedWithOneStructure(dataFileType)) { structureItem->setText(StructureEnum::toGuiName(specFileDataFile->getStructure())); } /* * File name and path */ CaretAssert(m_COLUMN_FILE_NAME_LABEL >= 0); QTableWidgetItem* nameItem = getTableWidgetItem(rowIndex, m_COLUMN_FILE_NAME_LABEL); CaretAssert(nameItem); AString path; AString name; const QString fileName(specFileDataFile->getFileName()); if (fileName.isEmpty()) { CaretLogSevere("While loading spec file dialog, file of type " + DataFileTypeEnum::toGuiName(dataFileType) + " has empty file name."); } else { FileInformation fileInfo(specFileDataFile->getFileName()); path = fileInfo.getAbsolutePath(); name = fileInfo.getFileName(); } nameItem->setText(name); nameItem->setToolTip(path); /* * Should file (row) be hidden? */ bool isFileHidden = false; if (filteredDataFileType != DataFileTypeEnum::UNKNOWN) { if (dataFileType != filteredDataFileType) { isFileHidden = true; } } if (filteredStructureType != StructureEnum::ALL) { switch (filteredStructureType) { case StructureEnum::CORTEX_LEFT: if (structure != StructureEnum::CORTEX_LEFT) { isFileHidden = true; } break; case StructureEnum::CORTEX_RIGHT: if (structure != StructureEnum::CORTEX_RIGHT) { isFileHidden = true; } break; case StructureEnum::CEREBELLUM: case StructureEnum::CEREBELLUM_LEFT: case StructureEnum::CEREBELLUM_RIGHT: if (structure != StructureEnum::CEREBELLUM) { isFileHidden = true; } break; case StructureEnum::OTHER: { switch (structure) { case StructureEnum::CORTEX_LEFT: case StructureEnum::CORTEX_RIGHT: case StructureEnum::CEREBELLUM: case StructureEnum::CEREBELLUM_LEFT: case StructureEnum::CEREBELLUM_RIGHT: isFileHidden = true; break; default: break; } } break; default: break; } } switch (filteredViewFilesType) { case SpecFileDialogViewFilesTypeEnum::VIEW_FILES_ALL: break; case SpecFileDialogViewFilesTypeEnum::VIEW_FILES_LOADED: if (caretDataFile == NULL) { isFileHidden = true; } break; case SpecFileDialogViewFilesTypeEnum::VIEW_FILES_LOADED_MODIFIED: if (caretDataFile != NULL) { if ( ! caretDataFile->isModified()) { isFileHidden = true; } } else { isFileHidden = true; } break; case SpecFileDialogViewFilesTypeEnum::VIEW_FILES_LOADED_NOT_MODIFIED: if (caretDataFile != NULL) { if (caretDataFile->isModified()) { isFileHidden = true; } } else { isFileHidden = true; } break; case SpecFileDialogViewFilesTypeEnum::VIEW_FILES_NOT_LOADED: if (caretDataFile != NULL) { isFileHidden = true; } break; } m_filesTableWidget->setRowHidden(rowIndex, isFileHidden); } /* * Enable cell changed signal now that table has been updated. */ m_filesTableWidget->blockSignals(false); /* * Fix table geometry. */ m_filesTableWidget->horizontalHeader()->setStretchLastSection(true); m_filesTableWidget->resizeColumnsToContents(); m_filesTableWidget->resizeRowsToContents(); enableLoadOrSaveButton(); } /** * @return Create and return a text item for the table. */ QTableWidgetItem* SpecFileManagementDialog::createTextItem() { QTableWidgetItem* item = new QTableWidgetItem(); Qt::ItemFlags flags(Qt::ItemIsEnabled); item->setFlags(flags); return item; } /** * @return Create and return a checkable item for the table. */ QTableWidgetItem* SpecFileManagementDialog::createCheckableItem() { QTableWidgetItem* item = new QTableWidgetItem(); Qt::ItemFlags flags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable); item->setFlags(flags); item->setCheckState(Qt::Unchecked); return item; } #include "EventDataFileDelete.h" /** * Called when a push button was added using addUserPushButton(). * Subclasses MUST override this if user push buttons were * added using addUserPushButton(). * * @param userPushButton * User push button that was pressed. * @return * The result that indicates action that should be taken * as a result of the button being pressed. */ WuQDialogModal::DialogUserButtonResult SpecFileManagementDialog::userButtonPressed(QPushButton* userPushButton) { if (userPushButton == m_loadScenesPushButton) { /* * Load all of the scene files but nothing else */ m_specFile->setAllSceneFilesSelectedForLoadingAndAllOtherFilesNotSelected(); okButtonClickedOpenSpecFile(); GuiManager::get()->processShowSceneDialog(GuiManager::get()->getActiveBrowserWindow()); return RESULT_MODAL_ACCEPT; } else { CaretAssert(0); } return RESULT_NONE; } /** * Gets called when the OK button is pressed. */ void SpecFileManagementDialog::okButtonClicked () { bool allowDialogToClose = false; switch (m_dialogMode) { case MODE_MANAGE_FILES: allowDialogToClose = okButtonClickedManageAndSaveFiles(); break; case MODE_OPEN_SPEC_FILE: okButtonClickedOpenSpecFile(); allowDialogToClose = true; break; case MODE_SAVE_FILES_WHILE_QUITTING: allowDialogToClose = okButtonClickedManageAndSaveFiles(); break; } if (allowDialogToClose) { WuQDialogModal::okButtonClicked(); } else { getDataFileContentFromSpecFile(); loadSpecFileContentIntoDialog(); updateGraphicWindowsAndUserInterface(); } } /** * Perform processing when the Open button is pressed for Open Spec File mode. */ void SpecFileManagementDialog::okButtonClickedOpenSpecFile() { AString username; AString password; if (m_specFile->hasFilesWithRemotePathSelectedForLoading()) { const QString msg("This spec file contains files that are on the network. " "If accessing the files requires a username and " "password, enter it here. Otherwise, remove any " "text from the username and password fields."); if (UsernamePasswordWidget::getUserNameAndPasswordInDialog(this, "Username and Password", msg, username, password)) { /* nothing */ } else { return; } } AString specFileErrorMessage = writeSpecFile(true); AString errorMessages; errorMessages.appendWithNewLine(specFileErrorMessage); EventSpecFileReadDataFiles readSpecFileEvent(m_brain, m_specFile); readSpecFileEvent.setUsernameAndPassword(username, password); ProgressReportingDialog::runEvent(&readSpecFileEvent, this, m_specFile->getFileNameNoPath()); errorMessages.appendWithNewLine(readSpecFileEvent.getErrorMessage()); updateGraphicWindowsAndUserInterface(); if (errorMessages.isEmpty() == false) { WuQMessageBox::errorOk(this, errorMessages); } } /** * Perform processing when the Open button is pressed for Manage Files * or Save Files mode. */ bool SpecFileManagementDialog::okButtonClickedManageAndSaveFiles() { /* * Wait cursor */ CursorDisplayScoped cursor; cursor.showWaitCursor(); AString errorMessages; const int32_t numDataFiles = static_cast(m_tableRowDataFileContent.size()); for (int32_t i = 0; i < numDataFiles; i++) { SpecFileDataFile* specFileDataFile = m_tableRowDataFileContent[i]->m_specFileDataFile; CaretAssert(specFileDataFile); if (specFileDataFile->isSavingSelected()) { CaretDataFile* caretDataFile = specFileDataFile->getCaretDataFile(); if (caretDataFile != NULL) { if (caretDataFile->supportsWriting()) { try { m_brain->writeDataFile(caretDataFile); specFileDataFile->setSavingSelected(false); } catch (const DataFileException& e) { errorMessages.appendWithNewLine(e.whatString()); } } } } } CaretAssert(m_COLUMN_SAVE_CHECKBOX >= 0); QTableWidgetItem* saveItem = getTableWidgetItem(m_specFileTableRowIndex, m_COLUMN_SAVE_CHECKBOX); if (saveItem->checkState() == Qt::Checked) { AString specFileName = m_specFile->getFileName(); if (m_specFile->getFileName().isEmpty()) { errorMessages.appendWithNewLine("Spec File name is empty."); } else { m_specFile->removeAnyFileInformationIfNotInSpecAndNoCaretDataFile(); AString specFileErrorMessage = writeSpecFile(false); if (specFileErrorMessage.isEmpty() == false) { errorMessages.appendWithNewLine(specFileErrorMessage); } else { } saveItem->setCheckState(Qt::Unchecked); } } /* * Spec file may have changed by SpecFile::removeAnyFileInformationIfNotInSpecAndNoCaretDataFile(). */ getDataFileContentFromSpecFile(); updateTableDimensionsToFitFiles(); loadSpecFileContentIntoDialog(); cursor.restoreCursor(); if (errorMessages.isEmpty() == false) { WuQMessageBox::errorOk(this, errorMessages); return false; } bool allowDialogToClose = false; switch (m_dialogMode) { case MODE_MANAGE_FILES: break; case MODE_OPEN_SPEC_FILE: break; case MODE_SAVE_FILES_WHILE_QUITTING: allowDialogToClose = true; break; } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); return allowDialogToClose; } /** * Write the spec file if it is modified. * * @param writeOnlyIfModified * Write only if the spec file is modified. * @return Non-empty string if there was an error writing the spec file. */ AString SpecFileManagementDialog::writeSpecFile(const bool writeOnlyIfModified) { if (writeOnlyIfModified) { if (m_specFile->isModified() == false) { return ""; } } AString errorMessage; try { m_specFile->writeFile(m_specFile->getFileName()); CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->addToPreviousSpecFiles(m_specFile->getFileName()); } catch (const DataFileException& e) { errorMessage = e.whatString(); } return errorMessage; } /** * Called when a file remove button is clicked. * * @param rowIndex * Row index of the item selected. */ void SpecFileManagementDialog::fileRemoveActionSelected(int rowIndex) { QWidget* removeButtonWidget = m_filesTableWidget->cellWidget(rowIndex, m_COLUMN_CLOSE_BUTTON); CaretAssert(removeButtonWidget); bool updateFlag = false; if (rowIndex == m_sceneAnnotationFileRowIndex) { AnnotationFile* sceneAnnotationFile = m_brain->getSceneAnnotationFile(); CaretAssert(sceneAnnotationFile); if ( ! sceneAnnotationFile->isEmpty()) { const QString msg = ("Remove all scene annotations?"); if ( ! WuQMessageBox::warningOkCancel(removeButtonWidget, msg)) { return; } sceneAnnotationFile->clear(); updateFlag = true; } } else { SpecFileManagementDialogRowContent* rowContent = getFileContentInRow(rowIndex); SpecFileDataFile* specFileDataFile = rowContent->m_specFileDataFile; CaretDataFile* caretDataFile = specFileDataFile->getCaretDataFile(); if (caretDataFile != NULL) { if (caretDataFile->isModified()) { const QString msg = (caretDataFile->getFileNameNoPath() + " is modified. Close without saving changes?"); if ( ! WuQMessageBox::warningOkCancel(removeButtonWidget, msg)) { return; } } if (m_COLUMN_SAVE_CHECKBOX >= 0) { /* * Turn of save check box in case file was modified to prevent * crash if user hits save file button */ QTableWidgetItem* saveItem = getTableWidgetItem(rowIndex, m_COLUMN_SAVE_CHECKBOX); CaretAssert(saveItem); saveItem->setCheckState(WuQtUtilities::boolToCheckState(false)); } EventManager::get()->sendEvent(EventDataFileDelete(caretDataFile).getPointer()); updateFlag = true; } } if (updateFlag) { getDataFileContentFromSpecFile(); loadSpecFileContentIntoDialog(); updateGraphicWindowsAndUserInterface(); } } /** * Get the content for the given row. * * @param rowIndex * Index of the row. * @return * Content for the given row. */ SpecFileManagementDialogRowContent* SpecFileManagementDialog::getFileContentInRow(const int rowIndex) { const int numDataFiles = static_cast(m_tableRowDataFileContent.size()); for (int32_t i = 0; i < numDataFiles; i++) { if (m_tableRowDataFileContent[i]->m_tableRowIndex == rowIndex) { return m_tableRowDataFileContent[i]; } } CaretAssertMessage(0, ("Invalid data file rowIndex (0 is spec file!!!): " + AString::number(rowIndex))); return NULL; } /** * Called when a file reload or open button is clicked. * * @param rowIndex * Index of the SpecFileDataFile item. */ void SpecFileManagementDialog::fileReloadOrOpenFileActionSelected(int rowIndex) { SpecFileManagementDialogRowContent* rowContent = getFileContentInRow(rowIndex); SpecFileDataFile* specFileDataFile = rowContent->m_specFileDataFile; QWidget* toolButtonWidget = m_filesTableWidget->cellWidget(rowIndex, m_COLUMN_READ_BUTTON); CaretAssert(toolButtonWidget); AString errorMessage; CaretDataFile* caretDataFile = specFileDataFile->getCaretDataFile(); if (caretDataFile != NULL) { if (caretDataFile->isModified()) { const QString msg = (caretDataFile->getFileNameNoPath() + " is modified. Reopen without saving changes?"); if (WuQMessageBox::warningOkCancel(toolButtonWidget, msg) == false) { return; } } AString username; AString password; if (DataFile::isFileOnNetwork(caretDataFile->getFileName())) { const QString msg("This file is on the network. " "If accessing the file requires a username and " "password, enter it here. Otherwise, remove any " "text from the username and password fields."); if (UsernamePasswordWidget::getUserNameAndPasswordInDialog(this, "Username and Password", msg, username, password)) { /* nothing */ } else { return; } } specFileDataFile->setSavingSelected(false); EventDataFileReload reloadEvent(m_brain, caretDataFile); reloadEvent.setUsernameAndPassword(username, password); EventManager::get()->sendEvent(reloadEvent.getPointer()); if (reloadEvent.isError()) { errorMessage.appendWithNewLine(reloadEvent.getErrorMessage()); } } else { AString username; AString password; if (DataFile::isFileOnNetwork(specFileDataFile->getFileName())) { const QString msg("This file is on the network. " "If accessing the file requires a username and " "password, enter it here. Otherwise, remove any " "text from the username and password fields."); if (UsernamePasswordWidget::getUserNameAndPasswordInDialog(this, "Username and Password", msg, username, password)) { /* nothing */ } else { return; } } EventDataFileRead readEvent(m_brain); readEvent.setUsernameAndPassword(username, password); readEvent.addDataFile(specFileDataFile->getStructure(), specFileDataFile->getDataFileType(), specFileDataFile->getFileName()); EventManager::get()->sendEvent(readEvent.getPointer()); if (readEvent.isError()) { errorMessage.appendWithNewLine(readEvent.getErrorMessage()); } } updateGraphicWindowsAndUserInterface(); loadSpecFileContentIntoDialog(); if (errorMessage.isEmpty() == false) { WuQMessageBox::errorOk(toolButtonWidget, errorMessage); } EventManager::get()->sendEvent(EventShowDataFileReadWarningsDialog().getPointer()); } /** * Updates graphics windows and user interface */ void SpecFileManagementDialog::updateGraphicWindowsAndUserInterface() { EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called when a file options button is clicked. * * @param rowIndex * Index of the SpecFileDataFile item. */ void SpecFileManagementDialog::fileOptionsActionSelected(int rowIndex) { m_filesTableWidget->setRangeSelected(QTableWidgetSelectionRange(rowIndex, m_COLUMN_OPTIONS_TOOLBUTTON, rowIndex, m_COLUMN_OPTIONS_TOOLBUTTON), false); const AString copyPathText("Copy Path and File Name to Clipboard"); if (rowIndex == m_specFileTableRowIndex) { QMenu menu; QAction* copyFilePathToClipboardAction = NULL; if (m_specFile != NULL) { if ( ! m_specFile->getFileName().trimmed().isEmpty()) { copyFilePathToClipboardAction = menu.addAction(copyPathText); } } QAction* editMetaDataAction = menu.addAction("Edit Metadata...");; QAction* setFileNameAction = menu.addAction("Set File Name..."); QAction* selectedAction = menu.exec(QCursor::pos()); if (selectedAction == NULL) { /* * If the selected action is NULL, it indicates that the user did * not make a selection. This test is needed as some of the actions * (such as setFileNameAction) may be NULL and with out this test, * those NULL actions would match. */ } else if (selectedAction == setFileNameAction) { changeFileName(&menu, NULL, m_specFile); } else if (selectedAction == editMetaDataAction) { MetaDataEditorDialog mded(m_specFile, &menu); mded.exec(); loadSpecFileContentIntoDialog(); } else if (selectedAction == copyFilePathToClipboardAction) { QApplication::clipboard()->setText(m_specFile->getFileName().trimmed(), QClipboard::Clipboard); } else if (selectedAction != NULL) { CaretAssertMessage(0, ("Unhandled Menu Action: " + selectedAction->text())); } } else { const bool sceneAnnotationFileFlag = (rowIndex == m_sceneAnnotationFileRowIndex); SpecFileDataFile* specFileDataFile = NULL; CaretDataFile* caretDataFile = NULL; if (sceneAnnotationFileFlag) { caretDataFile = m_brain->getSceneAnnotationFile(); if (caretDataFile->isEmpty()) { WuQMessageBox::informationOk(this, "There are no scene annotations"); return; } } else { SpecFileManagementDialogRowContent* rowContent = getFileContentInRow(rowIndex); specFileDataFile = rowContent->m_specFileDataFile; caretDataFile = specFileDataFile->getCaretDataFile(); } QAction* copyFilePathToClipboardAction = NULL; QAction* copyMoveFileContentAction = NULL; QAction* editMetaDataAction = NULL; QAction* setFileNameAction = NULL; QAction* showFileInformationAction = NULL; QAction* setStructureAction = NULL; QAction* unloadFileMapsAction = NULL; QAction* viewMetaDataAction = NULL; QMenu menu; switch (m_dialogMode) { case MODE_MANAGE_FILES: case MODE_SAVE_FILES_WHILE_QUITTING: if (caretDataFile != NULL) { DataFileContentCopyMoveInterface* copyMoveInterface = dynamic_cast(caretDataFile); if (copyMoveInterface != NULL) { copyMoveFileContentAction = menu.addAction("Copy/Move Content..."); } if ( ! sceneAnnotationFileFlag) { copyFilePathToClipboardAction = menu.addAction(copyPathText); editMetaDataAction = menu.addAction("Edit Metadata..."); setFileNameAction = menu.addAction("Set File Name..."); showFileInformationAction = menu.addAction("Show File Information..."); } } else if ( ! sceneAnnotationFileFlag) { copyFilePathToClipboardAction = menu.addAction(copyPathText); } break; case MODE_OPEN_SPEC_FILE: if ( ! sceneAnnotationFileFlag) { copyFilePathToClipboardAction = menu.addAction(copyPathText); } break; } if ( ! menu.actions().isEmpty()) { QAction* selectedAction = menu.exec(QCursor::pos()); if (selectedAction == NULL) { /* * If the selected action is NULL, it indicates that the user did * not make a selection. This test is needed as some of the actions * (such as setFileNameAction) may be NULL and with out this test, * those NULL actions would match. */ } else if (selectedAction == copyMoveFileContentAction) { copyMoveFileContent(&menu, caretDataFile); } else if (selectedAction == copyFilePathToClipboardAction) { copyFilePathToClipboard(specFileDataFile, caretDataFile); } else if (selectedAction == setFileNameAction) { changeFileName(&menu, specFileDataFile, caretDataFile); } else if (selectedAction == showFileInformationAction) { showFileInformation(caretDataFile); } else if (selectedAction == setStructureAction) { CaretAssert(0); } else if (selectedAction == unloadFileMapsAction) { } else if (selectedAction == editMetaDataAction) { if (caretDataFile != NULL) { MetaDataEditorDialog mded(caretDataFile, &menu); mded.exec(); if (caretDataFile->isModified()) { specFileDataFile->setSavingSelected(true); } loadSpecFileContentIntoDialog(); } } else if (selectedAction == viewMetaDataAction) { } else if (selectedAction != NULL) { CaretAssertMessage(0, ("Unhandled Menu Action: " + selectedAction->text())); } } } } /** * Copy the loaded file's path to the clipboard. * * @param caretDataFile * The data file. */ void SpecFileManagementDialog::copyFilePathToClipboard(const SpecFileDataFile* specFileDataFile, const CaretDataFile* caretDataFile) { if (caretDataFile != NULL) { QApplication::clipboard()->setText(caretDataFile->getFileName().trimmed(), QClipboard::Clipboard); } else if (specFileDataFile != NULL) { QApplication::clipboard()->setText(specFileDataFile->getFileName().trimmed(), QClipboard::Clipboard); } else { CaretAssert(0); } } /** * Copy or move content of the data file to another data file of same type. * * @param parent * Widget on which copy/move dialog is displayed. * @param caretDataFile * Caret Data File that is having is content copied or moved */ void SpecFileManagementDialog::copyMoveFileContent(QWidget* parent, CaretDataFile* caretDataFile) { CaretAssert(caretDataFile); DataFileContentCopyMoveInterface* copyMoveInterfaceFile = dynamic_cast(caretDataFile); CaretAssert(copyMoveInterfaceFile); Brain* brain = GuiManager::get()->getBrain(); std::vector copyMoveDataFiles; if (caretDataFile->getDataFileType() == DataFileTypeEnum::ANNOTATION) { std::vector annotationFiles; brain->getAllAnnotationFilesIncludingSceneAnnotationFile(annotationFiles); copyMoveDataFiles.insert(copyMoveDataFiles.end(), annotationFiles.begin(), annotationFiles.end()); } else { brain->getAllDataFilesWithDataFileType(caretDataFile->getDataFileType(), copyMoveDataFiles); } std::vector copyMoveDestinationFiles; for (std::vector::iterator fileIter = copyMoveDataFiles.begin(); fileIter != copyMoveDataFiles.end(); fileIter++) { DataFileContentCopyMoveInterface* cmFile = dynamic_cast(*fileIter); if (cmFile != NULL) { copyMoveDestinationFiles.push_back(cmFile); } } DataFileContentCopyMoveDialog copyMoveDialog(m_parentBrainBrowserWindow->getBrowserWindowIndex(), copyMoveInterfaceFile, copyMoveDestinationFiles, parent); copyMoveDialog.exec(); /* * Spec file has changed */ getDataFileContentFromSpecFile(); /* * Table may need to add/remove rows */ updateTableDimensionsToFitFiles(); /* * Update the table rows with data */ loadSpecFileContentIntoDialog(); /* * Files have changed */ updateGraphicWindowsAndUserInterface(); } /** * Change the name of a file. * * @param parent * Widget on which file dialog is displayed. * @param specFileDataFile * Entry in spec file (NULL if caretDataFile is spec file). * @param caretDataFileIn * Caret Data File that is having name changed. */ void SpecFileManagementDialog::changeFileName(QWidget* parent, SpecFileDataFile* specFileDataFile, CaretDataFile* caretDataFileIn) { CaretDataFile* caretDataFile = caretDataFileIn; CaretAssert(caretDataFile); if (caretDataFile != m_specFile) { CaretAssert(m_specFile); } const AString newFileName = CaretFileDialog::getChooseFileNameDialog(caretDataFile->getDataFileType(), caretDataFile->getFileName(), parent); if (newFileName.isEmpty()) { return; } // QStringList filenameFilterList; // filenameFilterList.append(DataFileTypeEnum::toQFileDialogFilter(caretDataFile->getDataFileType())); // CaretFileDialog fd(parent); // fd.setAcceptMode(CaretFileDialog::AcceptSave); // fd.setNameFilters(filenameFilterList); // fd.setFileMode(CaretFileDialog::AnyFile); // fd.setViewMode(CaretFileDialog::List); // fd.selectFile(caretDataFile->getFileName()); // fd.setLabelText(CaretFileDialog::Accept, "Choose"); // fd.setWindowTitle("Choose File Name"); // if (fd.exec() == CaretFileDialog::Accepted) { // QStringList files = fd.selectedFiles(); // if (files.isEmpty() == false) { // AString newFileName = files.at(0); if (newFileName != caretDataFile->getFileName()) { /* * Clone current item, remove file from it, * and create new item. * * Note: specFileDataFile is NULL when changing the name * of the spec file. */ if (specFileDataFile != NULL) { SpecFileDataFile* sfdf = m_specFile->changeFileName(specFileDataFile, newFileName); caretDataFile = sfdf->getCaretDataFile(); CaretAssert(caretDataFile); if (caretDataFile->isModified()) { sfdf->setSavingSelected(true); } } caretDataFile->setFileName(newFileName); /* * Spec file has changed */ getDataFileContentFromSpecFile(); /* * Table may need to add/remove rows */ updateTableDimensionsToFitFiles(); /* * Update the table rows with data */ loadSpecFileContentIntoDialog(); /* * Files have changed */ updateGraphicWindowsAndUserInterface(); } // } // } } /** * Show information about a file. * * @param caretDataFileIn * File for which information is displayed. */ void SpecFileManagementDialog::showFileInformation(CaretDataFile* caretDataFile) { DataFileContentInformation dataFileContentInformation; const bool showMapInformationFlag(true); dataFileContentInformation.setOptionFlag(DataFileContentInformation::OPTION_SHOW_MAP_INFORMATION, showMapInformationFlag); caretDataFile->addToDataFileContentInformation(dataFileContentInformation); WuQTextEditorDialog::runNonModal("File Information", dataFileContentInformation.getInformationInString(), WuQTextEditorDialog::TextMode::PLAIN, WuQTextEditorDialog::WrapMode::NO, this); } ///** // * Called when spec file options tool button is triggered. // */ //void //SpecFileManagementDialog::specFileOptionsActionTriggered() //{ // QAction* setFileNameAction = NULL; // // QMenu menu; // QAction* metadataAction = menu.addAction("Edit Metadata..."); // metadataAction->setEnabled(false); // switch (m_dialogMode) { // case MODE_MANAGE_FILES: // case MODE_SAVE_FILES_WHILE_QUITTING: // setFileNameAction = menu.addAction("Set File Name..."); // break; // case MODE_OPEN_SPEC_FILE: // break; // } // // QAction* selectedAction = menu.exec(QCursor::pos()); // // if (selectedAction == setFileNameAction) { // QStringList filenameFilterList; // filenameFilterList.append(DataFileTypeEnum::toQFileDialogFilter(DataFileTypeEnum::SPECIFICATION)); // CaretFileDialog fd(&menu); // fd.setAcceptMode(CaretFileDialog::AcceptSave); // fd.setNameFilters(filenameFilterList); // fd.setFileMode(CaretFileDialog::AnyFile); // fd.setViewMode(CaretFileDialog::List); // fd.selectFile(m_specFile->getFileName()); // fd.setLabelText(CaretFileDialog::Accept, "Choose"); // fd.setWindowTitle("Choose Spec File Name"); // if (fd.exec() == CaretFileDialog::Accepted) { // QStringList files = fd.selectedFiles(); // if (files.isEmpty() == false) { // AString newFileName = files.at(0); // m_specFile->setFileName(newFileName); // loadSpecFileContentIntoDialog(); // } // } // } // else if (selectedAction == metadataAction) { // // } // else if (selectedAction != NULL) { // CaretAssertMessage(0, // ("Unhandled Menu Action: " + selectedAction->text())); // } //} ///** // * Called to choose the name of the spec file. // */ //void //SpecFileManagementDialog::chooseSpecFileNameActionTriggered() //{ // QWidget* toolButtonWidget = m_filesTableWidget->cellWidget(m_specFileTableRowIndex, // m_COLUMN_OPTIONS_TOOLBUTTON); // CaretAssert(toolButtonWidget); // // QStringList filenameFilterList; // filenameFilterList.append(DataFileTypeEnum::toQFileDialogFilter(DataFileTypeEnum::SPECIFICATION)); // CaretFileDialog fd(toolButtonWidget); // fd.setAcceptMode(CaretFileDialog::AcceptSave); // fd.setNameFilters(filenameFilterList); // fd.setFileMode(CaretFileDialog::AnyFile); // fd.setViewMode(CaretFileDialog::List); // fd.selectFile(m_specFile->getFileName()); // fd.setLabelText(CaretFileDialog::Accept, "Choose"); // fd.setWindowTitle("Choose Spec File Name"); // if (fd.exec() == CaretFileDialog::Accepted) { // QStringList files = fd.selectedFiles(); // if (files.isEmpty() == false) { // AString newFileName = files.at(0); // m_specFile->setFileName(newFileName); // loadSpecFileContentIntoDialog(); // } // } //} /** * @return Create and return a toolbar for viewing files by type of file. * @param labelOut * If text was not empty, this parameter will be set to the QLabel that * contains the text. Otherwise, it will be NULL upon exit. */ QToolBar* SpecFileManagementDialog::createFilesTypesToolBar(QLabel* &labelOut) { m_fileTypesActionGroup = new QActionGroup(this); m_fileTypesActionGroup->setExclusive(true); QObject::connect(m_fileTypesActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(toolBarFileTypeActionTriggered(QAction*))); QAction* fileTypeAllAction = m_fileTypesActionGroup->addAction("All"); fileTypeAllAction->setCheckable(true); fileTypeAllAction->setData(qVariantFromValue(DataFileTypeEnum::toIntegerCode(DataFileTypeEnum::UNKNOWN))); /* * All types of files */ std::vector allDataFileTypes; DataFileTypeEnum::getAllEnums(allDataFileTypes, DataFileTypeEnum::OPTIONS_INCLUDE_UNKNOWN); /* * Get data types of files that are listed in the dialog */ std::set loadedDataFileTypes; const int32_t numFiles = static_cast(m_tableRowDataFileContent.size()); for (int32_t i = 0; i < numFiles; i++) { SpecFileDataFile* sfdf = m_tableRowDataFileContent[i]->m_specFileDataFile; loadedDataFileTypes.insert(sfdf->getDataFileType()); } for (std::vector::iterator iter = allDataFileTypes.begin(); iter != allDataFileTypes.end(); iter++) { DataFileTypeEnum::Enum dataFileType = *iter; /* * Only list file types if listed in dialog */ if (dataFileType == DataFileTypeEnum::SPECIFICATION) { continue; } if (std::find(loadedDataFileTypes.begin(), loadedDataFileTypes.end(), dataFileType) == loadedDataFileTypes.end()) { continue; } const AString text = getEditedDataFileTypeName(dataFileType); QAction* action = m_fileTypesActionGroup->addAction(text); action->setCheckable(true); action->setData(qVariantFromValue(DataFileTypeEnum::toIntegerCode(dataFileType))); } if (m_fileTypesActionGroup->actions().isEmpty() == false) { m_fileTypesActionGroup->blockSignals(true); m_fileTypesActionGroup->actions().at(0)->setChecked(true); m_fileTypesActionGroup->blockSignals(false); } QToolBar* toolbar = createToolBarWithActionGroup("View File Types: ", labelOut, m_fileTypesActionGroup); return toolbar; } /** * @return Create and return a toolbar for selecting all or no files. * @param labelOut * If text was not empty, this parameter will be set to the QLabel that * contains the text. Otherwise, it will be NULL upon exit. */ QToolBar* SpecFileManagementDialog::createFilesSelectionToolBar(QLabel* &labelOut) { // * When loading, ALL or NONE but only ones that are visibleRegion() m_fileSelectionActionGroup = new QActionGroup(this); QObject::connect(m_fileSelectionActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(toolBarSelectFilesActionTriggered(QAction*))); QAction* allFilesAction = m_fileSelectionActionGroup->addAction("All"); allFilesAction->setData(qVariantFromValue(SHOW_FILES_ALL)); QAction* noneFilesAction = m_fileSelectionActionGroup->addAction("None"); noneFilesAction->setData(qVariantFromValue(SHOW_FILES_NONE)); QToolBar* toolbar = createToolBarWithActionGroup("Select Files: ", labelOut, m_fileSelectionActionGroup); return toolbar; } /** * @return Create and return a toolbar for selecting loaded or not loaded files. * @param labelOut * If text was not empty, this parameter will be set to the QLabel that * contains the text. Otherwise, it will be NULL upon exit. */ QToolBar* SpecFileManagementDialog::createManageFilesLoadedNotLoadedToolBar(QLabel* &labelOut) { m_manageFilesLoadedNotLoadedActionGroup = new QActionGroup(this); QObject::connect(m_manageFilesLoadedNotLoadedActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(toolBarManageFilesLoadedNotLoadedActionTriggered(QAction*))); QAction* allFilesAction = m_manageFilesLoadedNotLoadedActionGroup->addAction("All"); allFilesAction->setData(qVariantFromValue((int)MANAGE_FILES_ALL)); allFilesAction->setCheckable(true); QAction* loadedFilesAction = m_manageFilesLoadedNotLoadedActionGroup->addAction("Loaded"); loadedFilesAction->setData(qVariantFromValue((int)MANAGE_FILES_LOADED)); loadedFilesAction->setCheckable(true); QAction* loadedFilesModifiedAction = m_manageFilesLoadedNotLoadedActionGroup->addAction("Loaded:Modified"); loadedFilesModifiedAction->setData(qVariantFromValue((int)MANAGE_FILES_LOADED_MODIFIED)); loadedFilesModifiedAction->setCheckable(true); QAction* loadedFilesNotModifiedAction = m_manageFilesLoadedNotLoadedActionGroup->addAction("Loaded:Not Modified"); loadedFilesNotModifiedAction->setData(qVariantFromValue((int)MANAGE_FILES_LOADED_NOT_MODIFIED)); loadedFilesNotModifiedAction->setCheckable(true); QAction* notLoadedFilesAction = m_manageFilesLoadedNotLoadedActionGroup->addAction("Not Loaded"); notLoadedFilesAction->setData(qVariantFromValue((int)MANAGE_FILES_NOT_LOADED)); notLoadedFilesAction->setCheckable(true); m_manageFilesLoadedNotLoadedActionGroup->blockSignals(true); switch (m_dialogMode) { case MODE_MANAGE_FILES: allFilesAction->setChecked(true); break; case MODE_OPEN_SPEC_FILE: allFilesAction->setChecked(true); break; case MODE_SAVE_FILES_WHILE_QUITTING: loadedFilesModifiedAction->setChecked(true); break; } m_manageFilesLoadedNotLoadedActionGroup->blockSignals(false); QToolBar* toolbar = createToolBarWithActionGroup("View Files: ", labelOut, m_manageFilesLoadedNotLoadedActionGroup); return toolbar; } /** * @return Edit and return the text for a data file type. */ AString SpecFileManagementDialog::getEditedDataFileTypeName(const DataFileTypeEnum::Enum dataFileType) { return DataFileTypeEnum::toShortGuiName(dataFileType); } /** * @return Create and return a toolbar for viewing files by structure. */ QToolBar* SpecFileManagementDialog::createStructureToolBar(QLabel* &labelOut) { std::vector structureTypes; structureTypes.push_back(StructureEnum::ALL); structureTypes.push_back(StructureEnum::CORTEX_LEFT); structureTypes.push_back(StructureEnum::CORTEX_RIGHT); structureTypes.push_back(StructureEnum::CEREBELLUM); structureTypes.push_back(StructureEnum::OTHER); m_structureActionGroup = new QActionGroup(this); m_structureActionGroup->setExclusive(true); QObject::connect(m_structureActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(toolBarStructuresActionTriggered(QAction*))); for (std::vector::iterator iter = structureTypes.begin(); iter != structureTypes.end(); iter++) { StructureEnum::Enum structure = *iter; QAction* action = m_structureActionGroup->addAction(StructureEnum::toGuiName(structure)); action->setCheckable(true); action->setData(qVariantFromValue(StructureEnum::toIntegerCode(structure))); } if (m_structureActionGroup->actions().isEmpty() == false) { m_structureActionGroup->blockSignals(true); m_structureActionGroup->actions().at(0)->setChecked(true); m_structureActionGroup->blockSignals(false); } QToolBar* toolbar = createToolBarWithActionGroup("View Structures: ", labelOut, m_structureActionGroup); return toolbar; } /** * Create a toolbar with the given label containing all items * in the given action group. * * @param text * If not empty, this text is inserted into the left side of the toolbar. * @param labelOut * If text was not empty, this parameter will be set to the QLabel that * contains the text. Otherwise, it will be NULL upon exit. * @param actionGroup * All actions from this action group are added to the toolbar. * @return * The toolbar. */ QToolBar* SpecFileManagementDialog::createToolBarWithActionGroup(const QString& text, QLabel* &labelOut, QActionGroup* actionGroup) { QToolBar* toolbar = new QToolBar(); if (text.isEmpty() == false) { labelOut = new QLabel(text); labelOut->setAlignment(Qt::AlignLeft); toolbar->addWidget(labelOut); } else { labelOut = NULL; } QList actions = actionGroup->actions(); QListIterator iterator(actions); while (iterator.hasNext()) { toolbar->addAction(iterator.next()); } return toolbar; } /** * Called when a tool bar's file type button is selected. * * @param action * QAction of item selected. */ void SpecFileManagementDialog::toolBarFileTypeActionTriggered(QAction* /*action*/) { // if (action != NULL) { // const int dataValue = action->data().toInt(); // bool isValid = false; // const DataFileTypeEnum::Enum dataFileType = DataFileTypeEnum::fromIntegerCode(dataValue, // &isValid); // } loadSpecFileContentIntoDialog(); } /** * Called when tool bar's structure button is selected. * * @param action * QAction of item selected. */ void SpecFileManagementDialog::toolBarStructuresActionTriggered(QAction* /*action*/) { // if (action != NULL) { // const int dataValue = action->data().toInt(); // bool isValid = false; // const StructureEnum::Enum structure = StructureEnum::fromIntegerCode(dataValue, // &isValid); // } loadSpecFileContentIntoDialog(); } /** * Show loaded/not loaded files when manage files mode. * * @param action * QAction of item selected. */ void SpecFileManagementDialog::toolBarManageFilesLoadedNotLoadedActionTriggered(QAction* /*action*/) { loadSpecFileContentIntoDialog(); } /** * Set all files as selected. * * @param action * QAction of item selected. */ void SpecFileManagementDialog::toolBarSelectFilesActionTriggered(QAction* action) { // m_filesTableWidget->blockSignals(true); if (action != NULL) { const int dataValue = action->data().toInt(); bool newStatus = false; if (dataValue == SHOW_FILES_ALL) { newStatus = true; } else if (dataValue == SHOW_FILES_NONE) { newStatus = false; } const int32_t numFiles = static_cast(m_tableRowDataFileContent.size()); for (int32_t i = 0; i < numFiles; i++) { const int32_t rowIndex = m_tableRowDataFileContent[i]->m_tableRowIndex; if (m_filesTableWidget->isRowHidden(rowIndex) == false) { if (m_COLUMN_LOAD_CHECKBOX >= 0) { QTableWidgetItem* loadItem = getTableWidgetItem(rowIndex, m_COLUMN_LOAD_CHECKBOX); CaretAssert(loadItem); loadItem->setCheckState(WuQtUtilities::boolToCheckState(newStatus)); } if (m_COLUMN_SAVE_CHECKBOX >= 0) { QTableWidgetItem* saveItem = getTableWidgetItem(rowIndex, m_COLUMN_SAVE_CHECKBOX); CaretAssert(saveItem); saveItem->setCheckState(WuQtUtilities::boolToCheckState(newStatus)); } } } } // m_filesTableWidget->blockSignals(false); } /* ======================================================================= */ /** * \class caret::SpecFileManagementDialogRowContent * \brief Content of a row in the SpecFileManagementDialog. * \ingroup GuiQt */ SpecFileManagementDialogRowContent::SpecFileManagementDialogRowContent(SpecFileDataFileTypeGroup* specFileDataFileTypeGroup, SpecFileDataFile* specFileDataFile) { m_tableRowIndex = -1; m_specFileDataFileTypeGroup = specFileDataFileTypeGroup; m_specFileDataFile = specFileDataFile; } SpecFileManagementDialogRowContent::~SpecFileManagementDialogRowContent() { } /** * Less than method for sorting using the sorting key. * * @param item1 * Tested for less than the item2 * @param item2 * Tested for greater than the item1 * @return * True if item1 is less than item2, else false. */ bool SpecFileManagementDialogRowContent::lessThanForSorting(const SpecFileManagementDialogRowContent* item1, const SpecFileManagementDialogRowContent* item2) { return (item1->m_sortingKey < item2->m_sortingKey); } /** * Set the sorting key for the given sorting type prior to sorting. * Creates a text string that is used for sorting that is used by * the static sorting method. * * @param sorting * Type of sorting. */ void SpecFileManagementDialogRowContent::setSortingKey(const Sorting sorting) { FileInformation fileInfo(m_specFileDataFile->getFileName()); const QString filename = fileInfo.getFileName().toUpper(); const DataFileTypeEnum::Enum dataFileType = m_specFileDataFile->getDataFileType(); QString typeName = SpecFileManagementDialog::getEditedDataFileTypeName(dataFileType); /* * Push surface files to the top??? */ // if (dataFileType == DataFileTypeEnum::SURFACE) { // typeName = "AAAAAA"; // } /* * Push non-specific structures to the bottom */ const StructureEnum::Enum structure = m_specFileDataFile->getStructure(); QString structureName = StructureEnum::toGuiName(structure); switch (structure) { case StructureEnum::ALL: case StructureEnum::ALL_GREY_MATTER: case StructureEnum::ALL_WHITE_MATTER: case StructureEnum::INVALID: case StructureEnum::OTHER: structureName = "zzzzzz"; break; default: break; } m_sortingKey = ""; switch (sorting) { case SORTING_TYPE_STRUCTURE_NAME: m_sortingKey = (typeName + structureName + filename); break; case SORTING_NAME: m_sortingKey = filename; break; case SORTING_STRUCTURE_TYPE_NAME: m_sortingKey = (structureName + typeName + filename); break; } } connectome-workbench-1.4.2/src/GuiQt/SpecFileManagementDialog.h000066400000000000000000000252121360521144700244350ustar00rootroot00000000000000#ifndef __SPEC_FILE_MANAGEMENT_DIALOG_H__ #define __SPEC_FILE_MANAGEMENT_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretObject.h" #include "DataFileTypeEnum.h" #include "SpecFileDialogViewFilesTypeEnum.h" #include "StructureEnum.h" #include "WuQDialogModal.h" class QActionGroup; class QIcon; class QLabel; class QSignalMapper; class QTableWidget; class QTableWidgetItem; class QToolBar; namespace caret { class Brain; class BrainBrowserWindow; class CaretDataFile; class SpecFile; class SpecFileDataFile; class SpecFileDataFileTypeGroup; class SpecFileManagementDialogRowContent; /** * Data in a row of the table widget */ class SpecFileManagementDialogRowContent : public CaretObject { public: /** * Type of sorting */ enum Sorting { SORTING_TYPE_STRUCTURE_NAME, SORTING_STRUCTURE_TYPE_NAME, SORTING_NAME }; SpecFileManagementDialogRowContent(SpecFileDataFileTypeGroup* specFileDataFileTypeGroup, SpecFileDataFile* specFileDataFile); ~SpecFileManagementDialogRowContent(); void setSortingKey(const Sorting sorting); int m_tableRowIndex; SpecFileDataFileTypeGroup* m_specFileDataFileTypeGroup; SpecFileDataFile* m_specFileDataFile; QString m_sortingKey; static bool lessThanForSorting(const SpecFileManagementDialogRowContent* item1, const SpecFileManagementDialogRowContent* item2); }; class SpecFileManagementDialog : public WuQDialogModal { Q_OBJECT public: static bool runOpenSpecFileDialog(Brain* brain, SpecFile* specFile, BrainBrowserWindow* parent); static void runManageFilesDialog(Brain* brain, BrainBrowserWindow* parent); static bool runSaveFilesDialogWhileQuittingWorkbench(Brain* brain, BrainBrowserWindow* parent); virtual ~SpecFileManagementDialog(); protected: WuQDialogModal::DialogUserButtonResult userButtonPressed(QPushButton* userPushButton); private slots: void toolBarFileTypeActionTriggered(QAction* action); void toolBarStructuresActionTriggered(QAction* action); void toolBarSelectFilesActionTriggered(QAction* action); void toolBarManageFilesLoadedNotLoadedActionTriggered(QAction* action); // void chooseSpecFileNameActionTriggered(); // void specFileOptionsActionTriggered(); void fileReloadOrOpenFileActionSelected(int indx); void fileRemoveActionSelected(int indx); void fileOptionsActionSelected(int indx); void filesTableWidgetCellChanged(int row, int column); void horizontalHeaderSelectedForSorting(int logicalIndex); private: enum Mode { MODE_MANAGE_FILES, MODE_OPEN_SPEC_FILE, MODE_SAVE_FILES_WHILE_QUITTING }; enum ManageFilesDisplay { MANAGE_FILES_ALL, MANAGE_FILES_LOADED, MANAGE_FILES_LOADED_MODIFIED, MANAGE_FILES_LOADED_NOT_MODIFIED, MANAGE_FILES_NOT_LOADED }; SpecFileManagementDialog(const Mode dialogMode, Brain* brain, SpecFile* specFile, const AString& dialogTitle, BrainBrowserWindow* parent); SpecFileManagementDialog(const SpecFileManagementDialog&); SpecFileManagementDialog& operator=(const SpecFileManagementDialog&); BrainBrowserWindow* m_parentBrainBrowserWindow; QToolBar* createFilesTypesToolBar(QLabel* &labelOut); QToolBar* createFilesSelectionToolBar(QLabel* &labelOut); QToolBar* createManageFilesLoadedNotLoadedToolBar(QLabel* &labelOut); QToolBar* createStructureToolBar(QLabel* &labelOut); QToolBar* createToolBarWithActionGroup(const QString& text, QLabel* &labelOut, QActionGroup* actionGroup); static AString getEditedDataFileTypeName(const DataFileTypeEnum::Enum dataFileType); SpecFileManagementDialogRowContent* getFileContentInRow(const int rowIndex); void updateGraphicWindowsAndUserInterface(); void getDataFileContentFromSpecFile(); void loadSpecFileContentIntoDialog(); void loadDialogContentIntoSpecFile(); void updateSpecFileRowInTable(); void updateAnnotationSceneFileRowInTable(); void sortFileContent(); void setTableColumnLabels(); virtual void okButtonClicked(); void okButtonClickedOpenSpecFile(); bool okButtonClickedManageAndSaveFiles(); void changeFileName(QWidget* parent, SpecFileDataFile* specFileDataFile, CaretDataFile* caretDataFile); void showFileInformation(CaretDataFile* caretDataFile); void copyMoveFileContent(QWidget* parent, CaretDataFile* caretDataFile); void updateTableDimensionsToFitFiles(); QTableWidgetItem* createHeaderTextItem(const QString& text); QTableWidgetItem* createTextItem(); QTableWidgetItem* createCheckableItem(); AString writeSpecFile(const bool writeOnlyIfModified); QTableWidgetItem* getTableWidgetItem(const int rowIndex, const int columnIndex); void setTableWidgetItem(const int rowIndex, const int columnIndex, QTableWidgetItem* item); void getFilterSelections(SpecFileDialogViewFilesTypeEnum::Enum& viewFilesTypeOut, DataFileTypeEnum::Enum& filteredDataFileTypeOut, StructureEnum::Enum& filteredStructureTypeOut) const; void setFilterSelections(const SpecFileDialogViewFilesTypeEnum::Enum viewFilesType, const DataFileTypeEnum::Enum filteredDataFileType, const StructureEnum::Enum filteredStructureType); void clearSpecFileManagementDialogRowContent(); void enableLoadOrSaveButton(); void copyFilePathToClipboard(const SpecFileDataFile* specFileDataFile, const CaretDataFile* caretDataFile); // ADD_NEW_MEMBERS_HERE const Mode m_dialogMode; Brain* m_brain; SpecFile* m_specFile; QPushButton* m_loadScenesPushButton; QActionGroup* m_fileTypesActionGroup; QActionGroup* m_fileSelectionActionGroup; QActionGroup* m_manageFilesLoadedNotLoadedActionGroup; QActionGroup* m_structureActionGroup; std::vector m_tableRowDataFileContent; int m_specFileTableRowIndex; int m_sceneAnnotationFileRowIndex; QSignalMapper* m_fileReloadOrOpenFileActionSignalMapper; QSignalMapper* m_fileCloseFileActionSignalMapper; QSignalMapper* m_fileOptionsActionSignalMapper; int m_specFileDataFileCounter; QTableWidget* m_filesTableWidget; SpecFileManagementDialogRowContent::Sorting m_fileSorting; QIcon* m_iconOptions; QIcon* m_iconOpenFile; QIcon* m_iconReloadFile; QIcon* m_iconCloseFile; std::set m_displayedDataFiles; static QByteArray s_manageFilesGeometry; static SpecFileDialogViewFilesTypeEnum::Enum s_manageFilesViewFilesType; static DataFileTypeEnum::Enum s_manageFilesFilteredDataFileType; static StructureEnum::Enum s_manageFilesFilteredStructureType; static const int SHOW_FILES_ALL; static const int SHOW_FILES_NONE; int m_COLUMN_LOAD_CHECKBOX; int m_COLUMN_SAVE_CHECKBOX; int m_COLUMN_STATUS_LABEL; int m_COLUMN_DISPLAYED_LABEL; int m_COLUMN_IN_SPEC_FILE_CHECKBOX; int m_COLUMN_READ_BUTTON; int m_COLUMN_CLOSE_BUTTON; int m_COLUMN_OPTIONS_TOOLBUTTON; int m_COLUMN_DATA_FILE_TYPE_LABEL; int m_COLUMN_STRUCTURE; int m_COLUMN_FILE_NAME_LABEL; int m_COLUMN_COUNT; friend class SpecFileManagementDialogRowContent; }; #ifdef __SPEC_FILE_MANAGEMENT_DIALOG_DECLARE__ QByteArray SpecFileManagementDialog::s_manageFilesGeometry; SpecFileDialogViewFilesTypeEnum::Enum SpecFileManagementDialog::s_manageFilesViewFilesType = SpecFileDialogViewFilesTypeEnum::VIEW_FILES_ALL; DataFileTypeEnum::Enum SpecFileManagementDialog::s_manageFilesFilteredDataFileType = DataFileTypeEnum::UNKNOWN; StructureEnum::Enum SpecFileManagementDialog::s_manageFilesFilteredStructureType = StructureEnum::ALL; const int SpecFileManagementDialog::SHOW_FILES_ALL = -1; const int SpecFileManagementDialog::SHOW_FILES_NONE = -2; #endif // __SPEC_FILE_MANAGEMENT_DIALOG_DECLARE__ } // namespace #endif //__SPEC_FILE_MANAGEMENT_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/SplashScreen.cxx000066400000000000000000000431611360521144700225760ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #define __SPLASH_SCREEN_DECLARE__ #include "SplashScreen.h" #undef __SPLASH_SCREEN_DECLARE__ #include "ApplicationInformation.h" #include "Brain.h" #include "CaretAssert.h" #include "CaretFileDialog.h" #include "CaretPreferences.h" #include "DataFile.h" #include "DataFileTypeEnum.h" #include "FileInformation.h" #include "GuiManager.h" #include "SessionManager.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::SplashScreen * \brief Splash Screen display when Workbench is started. * \ingroup GuiQt */ /** * Constructor. */ SplashScreen::SplashScreen(QWidget* parent) : WuQDialogModal("", parent) { QLabel* imageLabel = NULL; QPixmap pixmap; if (WuQtUtilities::loadPixmap(":/Splash/startup_image.png", pixmap)) { imageLabel = new QLabel(); imageLabel->setPixmap(pixmap); imageLabel->setAlignment(Qt::AlignCenter); } const QString labelStyle = ("QLabel { " " font: 20px bold " "}"); ApplicationInformation appInfo; QLabel* workbenchLabel = new QLabel(appInfo.getNameForGuiLabel()); workbenchLabel->setStyleSheet(labelStyle); workbenchLabel->setAlignment(Qt::AlignCenter); QLabel* versionLabel = new QLabel("Version: " + appInfo.getVersion()); versionLabel->setAlignment(Qt::AlignCenter); QLabel* hcpWebsiteLabel = new QLabel("" "Visit
    " "Human Connectome Project
    " "Website" ""); hcpWebsiteLabel->setStyleSheet(labelStyle); hcpWebsiteLabel->setAlignment(Qt::AlignCenter); QObject::connect(hcpWebsiteLabel, SIGNAL(linkActivated(const QString&)), this, SLOT(websiteLinkActivated(const QString&))); QToolButton* twitterToolButton = NULL; QIcon twitterIcon; if (WuQtUtilities::loadIcon(":/Splash/twitter.png", twitterIcon)) { QAction* twitterAction = WuQtUtilities::createAction("Twitter", "Follow HCP on Twitter", this, this, SLOT(twitterActionTriggered())); twitterAction->setIcon(twitterIcon); twitterToolButton = new QToolButton(); twitterToolButton->setDefaultAction(twitterAction); } QStringList headerText; headerText.append("Spec File"); headerText.append("Path"); m_dataFileTreeWidget = new QTreeWidget(); m_dataFileTreeWidget->setHeaderLabels(headerText); QObject::connect(m_dataFileTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(dataFileTreeWidgetItemClicked(QTreeWidgetItem*))); QObject::connect(m_dataFileTreeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(dataFileTreeWidgetItemDoubleClicked(QTreeWidgetItem*))); QScrollArea* treeScrollArea = new QScrollArea(); treeScrollArea->setWidget(m_dataFileTreeWidget); treeScrollArea->setWidgetResizable(true); QWidget* leftWidget = new QWidget(); QVBoxLayout* leftColumnLayout = new QVBoxLayout(leftWidget); if (imageLabel != NULL) { leftColumnLayout->addWidget(imageLabel); leftColumnLayout->addSpacing(15); } leftColumnLayout->addWidget(workbenchLabel); leftColumnLayout->addWidget(versionLabel); leftColumnLayout->addSpacing(10); leftColumnLayout->addWidget(hcpWebsiteLabel); if (twitterToolButton != NULL) { leftColumnLayout->addSpacing(3); leftColumnLayout->addWidget(twitterToolButton, 0, Qt::AlignHCenter); } leftColumnLayout->addStretch(); QWidget* widget = new QWidget(); QHBoxLayout* horizLayout = new QHBoxLayout(widget); horizLayout->addWidget(leftWidget); horizLayout->addWidget(treeScrollArea); const int32_t treeDesiredWidth = loadDataFileTreeWidget(); m_openOtherSpecFilePushButton = addUserPushButton("Open Other...", QDialogButtonBox::AcceptRole); setCancelButtonText("Skip"); setOkButtonText("Open"); setCentralWidget(widget, WuQDialog::SCROLL_AREA_NEVER); /* * Set a minimum width so spec files are visible */ int totalWidth = (leftWidget->sizeHint().width() + treeDesiredWidth); const int maxWidth = std::max(WuQtUtilities::getMinimumScreenSize().width() - 300, 600); if (totalWidth > maxWidth) { totalWidth = maxWidth; } widget->setMinimumWidth(totalWidth); } /** * Destructor. */ SplashScreen::~SplashScreen() { } /** * @return The selected data file name. */ AString SplashScreen::getSelectedDataFileName() const { return m_selectedDataFileName; } /** * Called when a label's hyperlink is selected. * @param link * The URL. */ void SplashScreen::websiteLinkActivated(const QString& link) { if (link.isEmpty() == false) { QDesktopServices::openUrl(QUrl(link)); } } /** * Display twitter page in web browser. */ void SplashScreen::twitterActionTriggered() { websiteLinkActivated("http://twitter.com/#!/HumanConnectome"); } /** * Called when spec file tree widget item is clicked. * @param item * Item clicked. */ void SplashScreen::dataFileTreeWidgetItemClicked(QTreeWidgetItem* item) { m_selectedDataFileName = ""; if (item != NULL) { if ( ! item->isDisabled()) { m_selectedDataFileName = item->data(0, Qt::UserRole).toString(); } } } /** * Called when spec file tree widget item is double-clicked. * @param item * Item clicked. */ void SplashScreen::dataFileTreeWidgetItemDoubleClicked(QTreeWidgetItem* item) { m_selectedDataFileName = ""; if (item != NULL) { if ( ! item->isDisabled()) { if (item->flags() & Qt::ItemIsSelectable) { m_selectedDataFileName = item->data(0, Qt::UserRole).toString(); /* * Accept is like hitting OK button */ this->accept(); } } } } /** * Called when a push button was added using addUserPushButton(). * * @param userPushButton * User push button that was pressed. */ WuQDialogModal::DialogUserButtonResult SplashScreen::userButtonPressed(QPushButton* userPushButton) { if (userPushButton == m_openOtherSpecFilePushButton) { chooseDataFileViaOpenFileDialog(); } else { CaretAssertMessage(0, "Unrecognized user pushbutton clicked \"" + userPushButton->text() + "\""); } return WuQDialogModal::RESULT_NONE; } /** * Choose a data file with the Open File Dialog. */ void SplashScreen::chooseDataFileViaOpenFileDialog() { QStringList filenameFilterList; filenameFilterList.append(DataFileTypeEnum::toQFileDialogFilter(DataFileTypeEnum::SCENE)); filenameFilterList.append(DataFileTypeEnum::toQFileDialogFilter(DataFileTypeEnum::SPECIFICATION)); CaretFileDialog fd(this); fd.setAcceptMode(CaretFileDialog::AcceptOpen); fd.setNameFilters(filenameFilterList); fd.setFileMode(CaretFileDialog::ExistingFile); fd.setViewMode(CaretFileDialog::List); fd.selectNameFilter(DataFileTypeEnum::toQFileDialogFilter(DataFileTypeEnum::SPECIFICATION)); AString errorMessages; if (fd.exec()) { QStringList selectedFiles = fd.selectedFiles(); if (selectedFiles.empty() == false) { m_selectedDataFileName = selectedFiles.at(0); /* * Accept indicates user has 'accepted' the * dialog so dialog is closed (like OK clicked) */ accept(); } } } /** * Load Spec Files into the tree widget. */ int32_t SplashScreen::loadDataFileTreeWidget() { m_dataFileTreeWidget->clear(); QTreeWidgetItem* selectedItem = addDirectorySceneFiles(); QTreeWidgetItem* dirSpecItem = addDirectorySpecFiles(); if (selectedItem == NULL) { selectedItem = dirSpecItem; } QTreeWidgetItem* sceneItem = addRecentSceneFiles(); if (selectedItem == NULL) { selectedItem = sceneItem; } QTreeWidgetItem* specItem = addRecentSpecFiles(); if (selectedItem == NULL) { selectedItem = specItem; } int nameColWidth = 0; int pathColWidth = 0; if (selectedItem != NULL) { m_dataFileTreeWidget->setCurrentItem(selectedItem); m_dataFileTreeWidget->resizeColumnToContents(0); m_dataFileTreeWidget->resizeColumnToContents(1); nameColWidth = m_dataFileTreeWidget->columnWidth(0) + 25; pathColWidth = m_dataFileTreeWidget->columnWidth(1); this->dataFileTreeWidgetItemClicked(selectedItem); } int treeWidgetWidth = (nameColWidth + pathColWidth); if (treeWidgetWidth < 250) { treeWidgetWidth = 250; } m_dataFileTreeWidget->setMinimumWidth(treeWidgetWidth); return treeWidgetWidth; } /** * Add recent spec files. */ QTreeWidgetItem* SplashScreen::addRecentSpecFiles() { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); std::vector recentSpecFiles; prefs->getPreviousSpecFiles(recentSpecFiles); if (recentSpecFiles.empty()) { return NULL; } QTreeWidgetItem* titleItem = createTopLevelItem("Recent Spec Files", "-------------------------------"); QTreeWidgetItem* firstItem = NULL; const int32_t numRecentSpecFiles = static_cast(recentSpecFiles.size()); for (int32_t i = 0; i < numRecentSpecFiles; i++) { QString path; QString name; QString fullPath; const QString specFileName = recentSpecFiles[i]; if (DataFile::isFileOnNetwork(specFileName)) { const int lastSlash = specFileName.lastIndexOf('/'); name = specFileName.mid(lastSlash + 1); path = specFileName.left(lastSlash); fullPath = specFileName; } else { FileInformation fileInfo(specFileName); path = fileInfo.getPathName().trimmed(); name = fileInfo.getFileName().trimmed(); fullPath = fileInfo.getAbsoluteFilePath(); } if (name.isEmpty() == false) { QTreeWidgetItem* lwi = createChildItem(titleItem, name, path, fullPath); if (firstItem == NULL) { firstItem = lwi; } } } titleItem->setExpanded(true); return firstItem; } /** * Add recent scene files. */ QTreeWidgetItem* SplashScreen::addRecentSceneFiles() { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); std::vector recentSceneFiles; prefs->getPreviousSceneFiles(recentSceneFiles); if (recentSceneFiles.empty()) { return NULL; } QTreeWidgetItem* titleItem = createTopLevelItem("Recent Scene Files", "-------------------------------"); QTreeWidgetItem* firstItem = NULL; const int32_t numRecentSceneFiles = static_cast(recentSceneFiles.size()); for (int32_t i = 0; i < numRecentSceneFiles; i++) { QString path; QString name; QString fullPath; const QString sceneFileName = recentSceneFiles[i]; if (DataFile::isFileOnNetwork(sceneFileName)) { const int lastSlash = sceneFileName.lastIndexOf('/'); name = sceneFileName.mid(lastSlash + 1); path = sceneFileName.left(lastSlash); fullPath = sceneFileName; } else { FileInformation fileInfo(sceneFileName); path = fileInfo.getPathName().trimmed(); name = fileInfo.getFileName().trimmed(); fullPath = fileInfo.getAbsoluteFilePath(); } if (name.isEmpty() == false) { QTreeWidgetItem* lwi = createChildItem(titleItem, name, path, fullPath); if (firstItem == NULL) { firstItem = lwi; } } } titleItem->setExpanded(true); return firstItem; } /** * Add spec files in current directory */ QTreeWidgetItem* SplashScreen::addDirectorySpecFiles() { Brain* brain = GuiManager::get()->getBrain(); const QString dirName = brain->getCurrentDirectory(); QTreeWidgetItem* firstItem = NULL; QStringList nameFilters; nameFilters.append("*." + DataFileTypeEnum::toFileExtension(DataFileTypeEnum::SPECIFICATION)); QDir dir(dirName); QStringList specFileList = dir.entryList(nameFilters, QDir::Files, QDir::Name); if (specFileList.isEmpty()) { return NULL; } QTreeWidgetItem* titleItem = createTopLevelItem("Current Directory Spec Files", dirName); const int32_t numFiles = specFileList.count(); for (int32_t i = 0; i < numFiles; i++) { FileInformation fileInfo(specFileList.at(i)); const QString name = fileInfo.getFileName().trimmed(); const QString fullPath = fileInfo.getAbsoluteFilePath(); QTreeWidgetItem* lwi = createChildItem(titleItem, name, " . ", fullPath); if (firstItem == NULL) { firstItem = lwi; } } titleItem->setExpanded(true); return firstItem; } /** * Add scene files in current directory */ QTreeWidgetItem* SplashScreen::addDirectorySceneFiles() { Brain* brain = GuiManager::get()->getBrain(); const QString dirName = brain->getCurrentDirectory(); QStringList nameFilters; nameFilters.append("*." + DataFileTypeEnum::toFileExtension(DataFileTypeEnum::SCENE)); QDir dir(dirName); QStringList sceneFileList = dir.entryList(nameFilters, QDir::Files, QDir::Name); if (sceneFileList.isEmpty()) { return NULL; } QTreeWidgetItem* titleItem = createTopLevelItem("Current Directory Scenes", dirName); QTreeWidgetItem* firstItem = NULL; const int32_t numFiles = sceneFileList.count(); for (int32_t i = 0; i < numFiles; i++) { FileInformation fileInfo(sceneFileList.at(i)); const QString name = fileInfo.getFileName().trimmed(); const QString fullPath = fileInfo.getAbsoluteFilePath(); QTreeWidgetItem* lwi = createChildItem(titleItem, name, " . ", fullPath); if (firstItem == NULL) { firstItem = lwi; } } titleItem->setExpanded(true); return firstItem; } /** * Create a top level item with given titles for the columns * @param parentItem * Parent for the child item * @param textOne * Text for column one * @param textTwo * Text for second column * @return New child item. */ QTreeWidgetItem* SplashScreen::createChildItem(QTreeWidgetItem* parentItem, const AString& textOne, const AString& textTwo, const QVariant& childData) { CaretAssert(parentItem); QStringList itemText; itemText.append(textOne); itemText.append(textTwo); QTreeWidgetItem* item = new QTreeWidgetItem(itemText); item->setData(0, Qt::UserRole, childData); item->setData(1, Qt::UserRole, childData); CaretAssert(parentItem); parentItem->addChild(item); return item; } /** * Create a top level item with given titles for the columns * @param titleOne * Title for column one * @param titleTwo * Title for second column * @return New top-level item */ QTreeWidgetItem* SplashScreen::createTopLevelItem(const AString& titleOne, const AString& titleTwo) { QStringList itemText; itemText.append(titleOne); itemText.append(titleTwo); QTreeWidgetItem* item = new QTreeWidgetItem(itemText); item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); Qt::ItemFlags flags(Qt::ItemIsEnabled); item->setFlags(flags); m_dataFileTreeWidget->addTopLevelItem(item); return item; } connectome-workbench-1.4.2/src/GuiQt/SplashScreen.h000066400000000000000000000054671360521144700222320ustar00rootroot00000000000000#ifndef __SPLASH_SCREEN__H_ #define __SPLASH_SCREEN__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WuQDialogModal.h" class QPushButton; class QTreeWidget; class QTreeWidgetItem; namespace caret { class SplashScreen : public WuQDialogModal { Q_OBJECT public: SplashScreen(QWidget* parent = 0); virtual ~SplashScreen(); AString getSelectedDataFileName() const; private slots: void websiteLinkActivated(const QString& link); void dataFileTreeWidgetItemClicked(QTreeWidgetItem* item); void dataFileTreeWidgetItemDoubleClicked(QTreeWidgetItem* item); void chooseDataFileViaOpenFileDialog(); void twitterActionTriggered(); protected: WuQDialogModal::DialogUserButtonResult userButtonPressed(QPushButton* userPushButton); private: SplashScreen(const SplashScreen&); SplashScreen& operator=(const SplashScreen&); QTreeWidgetItem* addRecentSceneFiles(); QTreeWidgetItem* addRecentSpecFiles(); QTreeWidgetItem* addDirectorySceneFiles(); QTreeWidgetItem* addDirectorySpecFiles(); QTreeWidgetItem* createTopLevelItem(const AString& titleOne, const AString& titleTwo); QTreeWidgetItem* createChildItem(QTreeWidgetItem* parentItem, const AString& textOne, const AString& textTwo, const QVariant& childData); int32_t loadDataFileTreeWidget(); QTreeWidget* m_dataFileTreeWidget; AString m_selectedDataFileName; QPushButton* m_openOtherSpecFilePushButton; }; #ifdef __SPLASH_SCREEN_DECLARE__ // #endif // __SPLASH_SCREEN_DECLARE__ } // namespace #endif //__SPLASH_SCREEN__H_ connectome-workbench-1.4.2/src/GuiQt/StructureEnumComboBox.cxx000066400000000000000000000136731360521144700244670ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __STRUCTURE_ENUM_COMBOBOX_DECLARE__ #include "StructureEnumComboBox.h" #undef __STRUCTURE_ENUM_COMBOBOX_DECLARE__ #include "Brain.h" #include "BrainStructure.h" #include "GuiManager.h" using namespace caret; /** * \class caret::StructureEnumComboBox * \brief Control for selection of a structure. * \ingroup GuiQt */ /** * Constructor. * @param parent * The parent. */ StructureEnumComboBox::StructureEnumComboBox(QObject* parent) : WuQWidget(parent) { std::vector allStructures; StructureEnum::getAllEnums(allStructures); const int32_t numStructures = static_cast(allStructures.size()); this->structureComboBox = new QComboBox(); for (int32_t i = 0; i < numStructures; i++) { this->structureComboBox->addItem(StructureEnum::toGuiName(allStructures[i])); this->structureComboBox->setItemData(i, StructureEnum::toIntegerCode(allStructures[i])); } QObject::connect(this->structureComboBox, SIGNAL(activated(int)), this, SLOT(structureComboBoxSelection(int))); } /** * Destructor. */ StructureEnumComboBox::~StructureEnumComboBox() { } /** * @return Number of items in combo box. */ int StructureEnumComboBox::count() const { return structureComboBox->count(); } /** * Limit the available structure to the given structures * * @param structures * Structures for display in combo box. */ void StructureEnumComboBox::listOnlyTheseStructures(const std::vector& structures) { this->structureComboBox->clear(); this->structureComboBox->blockSignals(true); const int32_t numStructures = static_cast(structures.size()); for (int32_t i = 0; i < numStructures; i++) { const StructureEnum::Enum structure = structures[i]; this->structureComboBox->addItem(StructureEnum::toGuiName(structure)); this->structureComboBox->setItemData(i, StructureEnum::toIntegerCode(structure)); } this->structureComboBox->blockSignals(false); } /** * Limit selections to those structures that are loaded. */ void StructureEnumComboBox::listOnlyValidStructures() { const StructureEnum::Enum selectedStructure = getSelectedStructure(); this->structureComboBox->clear(); this->structureComboBox->blockSignals(true); int32_t selectedStructureIndex = -1; const Brain* brain = GuiManager::get()->getBrain(); const int32_t numStructures = brain->getNumberOfBrainStructures(); for (int32_t i = 0; i < numStructures; i++) { const BrainStructure* bs = brain->getBrainStructure(i); const StructureEnum::Enum structure = bs->getStructure(); this->structureComboBox->addItem(StructureEnum::toGuiName(structure)); this->structureComboBox->setItemData(i, StructureEnum::toIntegerCode(structure)); if (selectedStructure != StructureEnum::INVALID) { if (structure == selectedStructure) { selectedStructureIndex = this->structureComboBox->count() - 1; } } } if (selectedStructureIndex >= 0) { this->structureComboBox->setCurrentIndex(selectedStructureIndex); } this->structureComboBox->blockSignals(false); } /** * Called to set the selected structure. * @param structure * New value for structure. */ void StructureEnumComboBox::setSelectedStructure(const StructureEnum::Enum structure) { const int32_t structureIntegerCode = StructureEnum::toIntegerCode(structure); const int numStructures = this->structureComboBox->count(); for (int32_t i = 0; i < numStructures; i++) { if (structureIntegerCode == this->structureComboBox->itemData(i).toInt()) { if (this->signalsBlocked()) { this->structureComboBox->blockSignals(true); } this->structureComboBox->setCurrentIndex(i); if (this->signalsBlocked()) { this->structureComboBox->blockSignals(false); } break; } } } /** * @return The selected structure. */ StructureEnum::Enum StructureEnumComboBox::getSelectedStructure() const { StructureEnum::Enum structure = StructureEnum::INVALID; const int32_t indx = this->structureComboBox->currentIndex(); if (indx >= 0) { const int32_t integerCode = this->structureComboBox->itemData(indx).toInt(); structure = StructureEnum::fromIntegerCode(integerCode, NULL); } return structure; } /** * @return The widget for this control. */ QWidget* StructureEnumComboBox::getWidget() { return this->structureComboBox; } /** * Called when a structure is selected * @param indx * Index of selection. */ void StructureEnumComboBox::structureComboBoxSelection(int indx) { if (this->signalsBlocked() == false) { if ((indx >= 0) && (indx < this->structureComboBox->count())) { const int32_t integerCode = this->structureComboBox->itemData(indx).toInt(); StructureEnum::Enum structure = StructureEnum::fromIntegerCode(integerCode, NULL); emit structureSelected(structure); } } } connectome-workbench-1.4.2/src/GuiQt/StructureEnumComboBox.h000066400000000000000000000042231360521144700241030ustar00rootroot00000000000000#ifndef __STRUCTURE_ENUM_COMBOBOX__H_ #define __STRUCTURE_ENUM_COMBOBOX__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "StructureEnum.h" #include "WuQWidget.h" namespace caret { class Surface; class StructureEnumComboBox : public WuQWidget { Q_OBJECT public: StructureEnumComboBox(QObject* parent); virtual ~StructureEnumComboBox(); StructureEnum::Enum getSelectedStructure() const; int count() const; void listOnlyTheseStructures(const std::vector& structures); void listOnlyValidStructures(); QWidget* getWidget(); public slots: void setSelectedStructure(const StructureEnum::Enum structure); signals: void structureSelected(const StructureEnum::Enum); private slots: void structureComboBoxSelection(int); private: StructureEnumComboBox(const StructureEnumComboBox&); StructureEnumComboBox& operator=(const StructureEnumComboBox&); QComboBox* structureComboBox; public: private: }; #ifdef __STRUCTURE_ENUM_COMBOBOX_DECLARE__ // #endif // __STRUCTURE_ENUM_COMBOBOX_DECLARE__ } // namespace #endif //__STRUCTURE_ENUM_COMBOBOX__H_ connectome-workbench-1.4.2/src/GuiQt/StructureSurfaceSelectionControl.cxx000066400000000000000000000256611360521144700267310ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "Brain.h" #include "BrainStructure.h" #include "CaretAssert.h" #include "EventManager.h" #include "EventModelGetAll.h" #include "WuQFactory.h" #include "GuiManager.h" #include "WuQMacroManager.h" #include "WuQtUtilities.h" #define __STRUCTURE_SURFACE_SELECTION_CONTROL_DECLARE__ #include "StructureSurfaceSelectionControl.h" #undef __STRUCTURE_SURFACE_SELECTION_CONTROL_DECLARE__ #include "ModelSurface.h" #include "ModelSurfaceSelector.h" #include "Surface.h" using namespace caret; /** * \class caret::StructureSufaceSelectionControl * \brief * \ingroup GuiQt */ /** * Constructor. * * @param showLabels * Show labels on controls * @param objectNamePrefix * Object name prefix used for macros * @param descriptivePrefix * Descriptive prefix for macros * @param parent * Parent widget for controls */ StructureSurfaceSelectionControl::StructureSurfaceSelectionControl(const bool showLabels, const QString& objectNamePrefix, const QString& descriptivePrefix, QWidget* parent) : QWidget(parent) { this->surfaceControllerSelector = NULL; this->structureSelectionComboBox = WuQFactory::newComboBox(); this->structureSelectionComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); QObject::connect(this->structureSelectionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(structureSelected(int))); this->structureSelectionComboBox->setToolTip("Selects Structure of Surface"); this->structureSelectionComboBox->setObjectName(objectNamePrefix + ":StructureSelection"); WuQMacroManager::instance()->addMacroSupportToObject(this->structureSelectionComboBox, "Select structure for " + descriptivePrefix); this->surfaceControllerSelectionComboBox = WuQFactory::newComboBox(); this->surfaceControllerSelectionComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); QObject::connect(this->surfaceControllerSelectionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(surfaceControllerSelected(int))); this->surfaceControllerSelectionComboBox->setToolTip("Selects Surface"); this->surfaceControllerSelectionComboBox->setObjectName(objectNamePrefix + ":SurfaceSelection"); WuQMacroManager::instance()->addMacroSupportToObject(this->surfaceControllerSelectionComboBox, "Select surface for " + descriptivePrefix); QGridLayout* layout = new QGridLayout(this); layout->setColumnStretch(0, 0); layout->setColumnStretch(1, 100); WuQtUtilities::setLayoutSpacingAndMargins(layout, 3, 2); if (showLabels) { QLabel* structureLabel = new QLabel("Structure"); QLabel* surfaceLabel = new QLabel("Surface"); layout->addWidget(structureLabel, 0, 0); layout->addWidget(surfaceLabel, 1, 0); } layout->addWidget(this->structureSelectionComboBox, 0, 1); layout->addWidget(this->surfaceControllerSelectionComboBox, 1, 1); } /** * Destructor. */ StructureSurfaceSelectionControl::~StructureSurfaceSelectionControl() { } void StructureSurfaceSelectionControl::structureSelected(int currentIndex) { CaretAssert((currentIndex >= 0) && (currentIndex < this->structureSelectionComboBox->count())); int32_t structID = this->structureSelectionComboBox->itemData(currentIndex).toInt(); StructureEnum::Enum selectedStructure = StructureEnum::fromIntegerCode(structID, NULL); this->surfaceControllerSelector->setSelectedStructure(selectedStructure); emitSelectionChangedSignal(); // emit selectionChanged(this->surfaceControllerSelector->getSelectedStructure(), // this->surfaceControllerSelector->getSelectedSurfaceModel()); this->updateControlAfterSelection(); } void StructureSurfaceSelectionControl::surfaceControllerSelected(int currentIndex) { CaretAssert((currentIndex >= 0) && (currentIndex < this->surfaceControllerSelectionComboBox->count())); void* pointer = this->surfaceControllerSelectionComboBox->itemData(currentIndex).value(); ModelSurface* surfaceController = (ModelSurface*)pointer; this->surfaceControllerSelector->setSelectedSurfaceModel(surfaceController); emitSelectionChangedSignal(); // emit selectionChanged(this->surfaceControllerSelector->getSelectedStructure(), // this->surfaceControllerSelector->getSelectedSurfaceModel()); } /** * Emit the selection changed signal. * Also preserves mouse focus that can be disrupted by user-interface updates. */ void StructureSurfaceSelectionControl::emitSelectionChangedSignal() { const bool structureHasFocus = this->structureSelectionComboBox->hasFocus(); const bool surfaceHasFocus = this->surfaceControllerSelectionComboBox->hasFocus(); emit selectionChanged(this->surfaceControllerSelector->getSelectedStructure(), this->surfaceControllerSelector->getSelectedSurfaceModel()); if (structureHasFocus) { this->structureSelectionComboBox->setFocus(); } else if (surfaceHasFocus) { this->surfaceControllerSelectionComboBox->setFocus(); } } /** * @return The selected mode surface. */ ModelSurface* StructureSurfaceSelectionControl::getSelectedSurfaceModel() { return this->surfaceControllerSelector->getSelectedSurfaceModel(); } /** * @return The selected structure. */ StructureEnum::Enum StructureSurfaceSelectionControl::getSelectedStructure() { return this->surfaceControllerSelector->getSelectedStructure(); } /* void StructureSurfaceSelectionControl::setSelectedSurfaceModel( ModelSurface* surfaceController) { this->surfaceControllerSelector->setSelectedSurfaceModel(surfaceController); this->updateControl(); } void StructureSurfaceSelectionControl::setSelectedStructure(const StructureEnum::Enum selectedStructure) { this->surfaceControllerSelector->setSelectedStructure(selectedStructure); this->updateControl(); } */ void StructureSurfaceSelectionControl::updateControl(ModelSurfaceSelector* surfaceControllerSelector) { this->surfaceControllerSelector = surfaceControllerSelector; this->updateControlAfterSelection(); } void StructureSurfaceSelectionControl::updateControlAfterSelection() { /* * Don't let any signals get sent by updating. */ this->structureSelectionComboBox->blockSignals(true); this->surfaceControllerSelectionComboBox->blockSignals(true); this->structureSelectionComboBox->clear(); this->surfaceControllerSelectionComboBox->clear(); if (this->surfaceControllerSelector == NULL) { return; } std::vector availableSurfaceModels; std::vector availableStructures; this->surfaceControllerSelector->getSelectableStructures(availableStructures); this->surfaceControllerSelector->getSelectableSurfaceModels(availableSurfaceModels); Surface* primaryAnatomicalSurface = NULL; /* * Update the structure selection. */ StructureEnum::Enum selectedStructure = this->surfaceControllerSelector->getSelectedStructure(); int32_t defaultStructureIndex = 0; for (int32_t i = 0; i < static_cast(availableStructures.size()); i++) { StructureEnum::Enum structType = availableStructures[i]; if (structType == selectedStructure) { defaultStructureIndex = i; } this->structureSelectionComboBox->addItem(StructureEnum::toGuiName(structType), StructureEnum::toIntegerCode(structType)); } if (defaultStructureIndex < this->structureSelectionComboBox->count()) { this->structureSelectionComboBox->setCurrentIndex(defaultStructureIndex); BrainStructure* brainStructure = GuiManager::get()->getBrain()->getBrainStructure(availableStructures[defaultStructureIndex], false); if (brainStructure != NULL) { primaryAnatomicalSurface = brainStructure->getPrimaryAnatomicalSurface(); } } const bool allSelected (selectedStructure == StructureEnum::ALL); /* * Update the surface selection. */ ModelSurface* selectedSurfaceController = this->surfaceControllerSelector->getSelectedSurfaceModel(); int32_t defaultSurfaceIndex = -1; int32_t primaryAnatomicalSurfaceIndex = -1; for (std::vector::const_iterator iter = availableSurfaceModels.begin(); iter != availableSurfaceModels.end(); iter++) { ModelSurface* surfaceController = *iter; this->surfaceControllerSelectionComboBox->addItem(surfaceController->getNameForGUI(allSelected), qVariantFromValue((void*)surfaceController)); if (selectedSurfaceController == surfaceController) { defaultSurfaceIndex = this->surfaceControllerSelectionComboBox->count() - 1; } if (surfaceController->getSurface() == primaryAnatomicalSurface) { primaryAnatomicalSurfaceIndex = this->surfaceControllerSelectionComboBox->count() - 1; } } if (defaultSurfaceIndex < 0) { if (primaryAnatomicalSurfaceIndex >= 0) { defaultSurfaceIndex = primaryAnatomicalSurfaceIndex; } else if (this->surfaceControllerSelectionComboBox->count() > 0) { defaultSurfaceIndex = 0; } } if (defaultSurfaceIndex < this->surfaceControllerSelectionComboBox->count()) { this->surfaceControllerSelectionComboBox->setCurrentIndex(defaultSurfaceIndex); } this->structureSelectionComboBox->blockSignals(false); this->surfaceControllerSelectionComboBox->blockSignals(false); } connectome-workbench-1.4.2/src/GuiQt/StructureSurfaceSelectionControl.h000066400000000000000000000056361360521144700263560ustar00rootroot00000000000000#ifndef __STRUCTURE_SURFACE_SELECTION_CONTROL__H_ #define __STRUCTURE_SURFACE_SELECTION_CONTROL__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "StructureEnum.h" class QComboBox; namespace caret { class ModelSurfaceSelector; class ModelSurface; class Structure; class StructureSurfaceSelectionControl : public QWidget { Q_OBJECT public: StructureSurfaceSelectionControl(const bool showLabels, const QString& objectNamePrefix, const QString& descriptivePrefix, QWidget* parent); virtual ~StructureSurfaceSelectionControl(); ModelSurface* getSelectedSurfaceModel(); StructureEnum::Enum getSelectedStructure(); //void setSelectedSurfaceModel(ModelSurface* surfaceController); //void setSelectedStructure(const StructureEnum::Enum selectedStructure); void updateControl(ModelSurfaceSelector* surfaceControllerSelector); signals: void selectionChanged(const StructureEnum::Enum selectedStructure, ModelSurface* surfaceController); private slots: void structureSelected(int currentIndex); void surfaceControllerSelected(int currentIndex); private: void updateControlAfterSelection(); void emitSelectionChangedSignal(); StructureSurfaceSelectionControl(const StructureSurfaceSelectionControl&); StructureSurfaceSelectionControl& operator=(const StructureSurfaceSelectionControl&); QComboBox* structureSelectionComboBox; QComboBox* surfaceControllerSelectionComboBox; ModelSurfaceSelector* surfaceControllerSelector; public: private: }; #ifdef __STRUCTURE_SURFACE_SELECTION_CONTROL_DECLARE__ // #endif // __STRUCTURE_SURFACE_SELECTION_CONTROL_DECLARE__ } // namespace #endif //__STRUCTURE_SURFACE_SELECTION_CONTROL__H_ connectome-workbench-1.4.2/src/GuiQt/SurfacePropertiesEditorDialog.cxx000066400000000000000000000216051360521144700261370ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SURFACE_PROPERTIES_EDITOR_DIALOG_DECLARE__ #include "SurfacePropertiesEditorDialog.h" #undef __SURFACE_PROPERTIES_EDITOR_DIALOG_DECLARE__ #include #include #include #include #include using namespace caret; #include "CaretAssert.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "SceneClass.h" #include "SceneWindowGeometry.h" #include "WuQFactory.h" #include "WuQMacroManager.h" #include "WuQMacroWidgetAction.h" #include "WbMacroWidgetActionNames.h" #include "WuQTrueFalseComboBox.h" #include "WuQtUtilities.h" /** * \class caret::SurfacePropertiesEditorDialog * \brief Dialog for adjusting surface display properties. * \ingroup GuitQt */ /** * Constructor. */ SurfacePropertiesEditorDialog::SurfacePropertiesEditorDialog(QWidget* parent) : WuQDialogNonModal("Surface Properties", parent) { m_updateInProgress = true; WuQMacroManager* mm = WuQMacroManager::instance(); CaretAssert(mm); QLabel* surfaceDrawingTypeLabel = new QLabel("Drawing Type: "); QWidget* drawTypeWidget = mm->getWidgetForMacroWidgetActionByName(WbMacroWidgetActionNames::getSurfacePropertiesDrawingTypeName()); if (drawTypeWidget != NULL) { m_surfaceDrawingTypeComboBox = qobject_cast(drawTypeWidget); CaretAssert(m_surfaceDrawingTypeComboBox); } if (m_surfaceDrawingTypeComboBox == NULL) { m_surfaceDrawingTypeComboBox = new QComboBox(); m_surfaceDrawingTypeComboBox->setEnabled(false); } QLabel* linkSizeLabel = new QLabel("Link Diameter: "); QWidget* linkSizeMacroWidget = mm->getWidgetForMacroWidgetActionByName(WbMacroWidgetActionNames::getSurfacePropertiesLinkDiameterName()); if (linkSizeMacroWidget != NULL) { m_linkSizeSpinBox = qobject_cast(linkSizeMacroWidget); CaretAssert(m_linkSizeSpinBox); } if (m_linkSizeSpinBox == NULL) { m_linkSizeSpinBox = WuQFactory::newDoubleSpinBox(); m_linkSizeSpinBox->setEnabled(false); } m_linkSizeSpinBox->setSuffix("mm"); QLabel* nodeSizeLabel = new QLabel("Vertex Diameter: "); QWidget* nodeSizeWidget = mm->getWidgetForMacroWidgetActionByName(WbMacroWidgetActionNames::getSurfacePropertiesVertexDiameterName()); if (nodeSizeWidget != NULL) { m_nodeSizeSpinBox = qobject_cast(nodeSizeWidget); CaretAssert(m_nodeSizeSpinBox); } if (m_nodeSizeSpinBox == NULL) { m_nodeSizeSpinBox = WuQFactory::newDoubleSpinBox(); m_nodeSizeSpinBox->setEnabled(false); } m_nodeSizeSpinBox->setSuffix("mm"); QWidget* displayNormalsWidget = mm->getWidgetForMacroWidgetActionByName(WbMacroWidgetActionNames::getSurfacePropertiesDisplayNormalVectorsName()); if (displayNormalsWidget != NULL) { m_displayNormalVectorsCheckBox = qobject_cast(displayNormalsWidget); CaretAssert(m_displayNormalVectorsCheckBox); } if (m_displayNormalVectorsCheckBox == NULL) { m_displayNormalVectorsCheckBox = new QCheckBox(); m_displayNormalVectorsCheckBox->setEnabled(false); } m_displayNormalVectorsCheckBox->setText("Display Normal Vectors"); QLabel* opacityLabel = new QLabel("Opacity: "); QWidget* opacityMacroWidget = mm->getWidgetForMacroWidgetActionByName(WbMacroWidgetActionNames::getSurfacePropertiesOpacityName()); if (opacityMacroWidget != NULL) { m_opacitySpinBox = qobject_cast(opacityMacroWidget); CaretAssert(m_opacitySpinBox); } if (m_opacitySpinBox == NULL) { m_opacitySpinBox = new QDoubleSpinBox(); m_opacitySpinBox->setEnabled(false); } QWidget* w = new QWidget(); QGridLayout* gridLayout = new QGridLayout(w); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 2); int row = gridLayout->rowCount(); gridLayout->addWidget(m_displayNormalVectorsCheckBox, row, 0, 1, 2); row++; gridLayout->addWidget(surfaceDrawingTypeLabel, row, 0); gridLayout->addWidget(m_surfaceDrawingTypeComboBox, row, 1); row++; gridLayout->addWidget(linkSizeLabel, row, 0); gridLayout->addWidget(m_linkSizeSpinBox, row, 1); row++; gridLayout->addWidget(nodeSizeLabel, row, 0); gridLayout->addWidget(m_nodeSizeSpinBox, row, 1); row++; gridLayout->addWidget(opacityLabel, row, 0); gridLayout->addWidget(m_opacitySpinBox, row, 1); row++; setCentralWidget(w, WuQDialog::SCROLL_AREA_NEVER); updateDialog(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); /* * No apply button */ setApplyButtonText(""); } /** * Destructor. */ SurfacePropertiesEditorDialog::~SurfacePropertiesEditorDialog() { EventManager::get()->removeAllEventsFromListener(this); WuQMacroManager::instance()->releaseWidgetFromMacroWidgetAction(m_surfaceDrawingTypeComboBox, m_linkSizeSpinBox, m_nodeSizeSpinBox, m_opacitySpinBox, m_displayNormalVectorsCheckBox); } /** * Update the properties editor. */ void SurfacePropertiesEditorDialog::updateDialog() { m_updateInProgress = true; WuQMacroManager::instance()->updateValueInWidgetFromMacroWidgetAction(m_surfaceDrawingTypeComboBox, m_linkSizeSpinBox, m_nodeSizeSpinBox, m_opacitySpinBox, m_displayNormalVectorsCheckBox); m_updateInProgress = false; } /** * Receive events from the event manager. * * @param event * Event sent by event manager. */ void SurfacePropertiesEditorDialog::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { CaretAssert(dynamic_cast(event) != NULL); updateDialog(); } } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* SurfacePropertiesEditorDialog::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "SurfacePropertiesEditorDialog", 1); /* * Position and size */ SceneWindowGeometry swg(this); sceneClass->addClass(swg.saveToScene(sceneAttributes, "geometry")); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void SurfacePropertiesEditorDialog::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } /* * Position and size */ SceneWindowGeometry swg(this); swg.restoreFromScene(sceneAttributes, sceneClass->getClass("geometry")); } connectome-workbench-1.4.2/src/GuiQt/SurfacePropertiesEditorDialog.h000066400000000000000000000050411360521144700255600ustar00rootroot00000000000000#ifndef __SURFACE_PROPERTIES_EDITOR_DIALOG__H_ #define __SURFACE_PROPERTIES_EDITOR_DIALOG__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventListenerInterface.h" #include "SceneableInterface.h" #include "WuQDialogNonModal.h" class QCheckBox; class QComboBox; class QDoubleSpinBox; namespace caret { class EnumComboBoxTemplate; class WuQTrueFalseComboBox; class SurfacePropertiesEditorDialog : public WuQDialogNonModal, public EventListenerInterface, public SceneableInterface { Q_OBJECT public: SurfacePropertiesEditorDialog(QWidget* parent = 0); virtual ~SurfacePropertiesEditorDialog(); void receiveEvent(Event* event); void updateDialog(); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private: SurfacePropertiesEditorDialog(const SurfacePropertiesEditorDialog&); SurfacePropertiesEditorDialog& operator=(const SurfacePropertiesEditorDialog&); QCheckBox* m_displayNormalVectorsCheckBox; QDoubleSpinBox* m_linkSizeSpinBox; QDoubleSpinBox* m_nodeSizeSpinBox; QComboBox* m_surfaceDrawingTypeComboBox; QDoubleSpinBox* m_opacitySpinBox; bool m_updateInProgress; // ADD_NEW_MEMBERS_HERE }; #ifdef __SURFACE_PROPERTIES_EDITOR_DIALOG_DECLARE__ #endif // __SURFACE_PROPERTIES_EDITOR_DIALOG_DECLARE__ } // namespace #endif //__SURFACE_PROPERTIES_EDITOR_DIALOG__H_ connectome-workbench-1.4.2/src/GuiQt/SurfaceSelectionViewController.cxx000066400000000000000000000255251360521144700263450ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __SURFACE_SELECTION_CONTROL_DECLARE__ #include "SurfaceSelectionViewController.h" #undef __SURFACE_SELECTION_CONTROL_DECLARE__ #include #include "BrainStructure.h" #include "FileInformation.h" #include "FilePathNamePrefixCompactor.h" #include "Surface.h" #include "SurfaceSelectionModel.h" #include "WuQEventBlockingFilter.h" #include "WuQFactory.h" #include "WuQMacroManager.h" using namespace caret; /** * \class caret::SurfaceSelectionViewController * \brief Control for selecting surfaces. * \ingroup GuiQt * * Control for selecting surfaces. */ /** * Constructor. * @param parent * The parent. * @param surfaceSelection * Surface selection that is controlled through this control. * @param objectName * Name for combo box * @param descriptiveName * Descriptive name for macros */ SurfaceSelectionViewController::SurfaceSelectionViewController(QObject* parent, SurfaceSelectionModel* surfaceSelectionModel, const QString& objectName, const QString& descriptiveName) : WuQWidget(parent) { this->initializeControl(MODE_SELECTION_MODEL_STATIC, surfaceSelectionModel, objectName, descriptiveName); } /** * Constructor. * @param parent * The parent. * @param brainStructure * Allows selection of any surface with the specified brain structure. * @param objectName * Name for combo box * @param descriptiveName * Descriptive name for macros */ SurfaceSelectionViewController::SurfaceSelectionViewController(QObject* parent, BrainStructure* brainStructure, const QString& objectName, const QString& descriptiveName) : WuQWidget(parent) { std::vector allSurfaceTypes; SurfaceTypeEnum::getAllEnums(allSurfaceTypes); SurfaceSelectionModel* ss = new SurfaceSelectionModel(brainStructure->getStructure(), allSurfaceTypes); this->initializeControl(MODE_BRAIN_STRUCTURE, ss, objectName, descriptiveName); } /** * Destructor. */ SurfaceSelectionViewController::~SurfaceSelectionViewController() { bool isDeleteSelectionModel = false; switch (this->mode) { case MODE_BRAIN_STRUCTURE: isDeleteSelectionModel = true; break; case MODE_SELECTION_MODEL_DYNAMIC: break; case MODE_SELECTION_MODEL_STATIC: break; } if (isDeleteSelectionModel) { delete this->surfaceSelectionModel; } } /** * Constructor. Creates a selection control. User MUST call updateControl(SurfaceSelectionModel*) * so that surfaces get loaded. A instance created this way will NEVER use the selection * model this is passed to updateControl() anywhere outside of updateControl(). Thus, * slots in the model are NEVER called. * * @param parent * The parent. * @param objectName * Name for combo box */ SurfaceSelectionViewController::SurfaceSelectionViewController(QObject* parent, const QString& objectName, const QString& descriptiveName) : WuQWidget(parent) { this->initializeControl(MODE_SELECTION_MODEL_DYNAMIC, NULL, objectName, descriptiveName); } /** * @param mode * The mode. * @param surfaceSelectionModel * Model for surface selection * @param objectName * Name for combo box * @param descriptiveName * Descriptive name for macros */ void SurfaceSelectionViewController::initializeControl(const Mode mode, SurfaceSelectionModel* surfaceSelectionModel, const QString& objectName, const QString& descriptiveName) { this->mode = mode; this->surfaceComboBox = WuQFactory::newComboBox(); this->surfaceComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); QObject::connect(this->surfaceComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(comboBoxCurrentIndexChanged(int))); this->surfaceComboBox->setToolTip("Selects a surface in a combo box"); this->surfaceComboBox->setObjectName(objectName); WuQMacroManager::instance()->addMacroSupportToObject(this->surfaceComboBox, "Select surface for " + descriptiveName); //#ifdef CARET_OS_MACOSX // /* // * Block the wheel event on Mac since it get issued when a mouse // * is moved over the combo box. // */ // WuQEventBlockingFilter* comboBoxWheelEventBlockingFilter = new WuQEventBlockingFilter(this); // comboBoxWheelEventBlockingFilter->setEventBlocked(QEvent::Wheel, // true); // surfaceComboBox->installEventFilter(comboBoxWheelEventBlockingFilter); //#endif // CARET_OS_MACOSX this->surfaceSelectionModel = surfaceSelectionModel; } /** * Update the control using the given selection model. The model is NEVER * used outside this method so slots in the model are NEVER called. * * @param selectionModel * Selection model used to update this control. If this parameter is NULL * all selections are removed from the control. */ void SurfaceSelectionViewController::updateControl(SurfaceSelectionModel* selectionModel) { std::vector surfaces; Surface* selectedSurface = NULL; if (selectionModel != NULL) { surfaces = selectionModel->getAvailableSurfaces(); selectedSurface = selectionModel->getSurface(); } this->surfaceComboBox->blockSignals(true); /* * There may be surface files with the same name but different * paths so include unique parts of path in names */ std::vector caretDataFiles(surfaces.begin(), surfaces.end()); std::vector displayNames; FilePathNamePrefixCompactor::removeMatchingPathPrefixFromCaretDataFiles(caretDataFiles, displayNames); CaretAssert(surfaces.size() == displayNames.size()); int32_t selectedIndex = 0; this->surfaceComboBox->clear(); const int32_t numSurfaces = static_cast(surfaces.size()); for (int32_t i = 0; i < numSurfaces; i++) { const int32_t indx = this->surfaceComboBox->count(); this->surfaceComboBox->addItem(displayNames[i]); this->surfaceComboBox->setItemData(indx, qVariantFromValue((void*)surfaces[i])); if (surfaces[i] == selectedSurface) { selectedIndex = indx; } } AString toolTipText; if (numSurfaces > 0) { this->surfaceComboBox->setCurrentIndex(selectedIndex); /* * ToolTip contains file and path */ CaretAssertVectorIndex(surfaces, selectedIndex); const Surface* s = surfaces[selectedIndex]; if (s != NULL) { FileInformation fileInfo(s->getFileName()); toolTipText = ("Name: " + fileInfo.getFileName() + "\nPath: " + fileInfo.getPathName()); } } this->surfaceComboBox->setToolTip(toolTipText); this->surfaceComboBox->blockSignals(false); } /** * Update the control. */ void SurfaceSelectionViewController::updateControl() { CaretAssertMessage(this->surfaceSelectionModel, "The surface selection model is NULL, you should have called " "updateControl(SurfaceSelectionModel*)"); this->updateControl(this->surfaceSelectionModel); } /** * @return the actual widget. */ QWidget* SurfaceSelectionViewController::getWidget() { return this->surfaceComboBox; } /** * @return the selected surface. NULL if no surface selected. */ Surface* SurfaceSelectionViewController::getSurface() { //return this->surfaceSelectionModel->getSurface(); Surface* s = NULL; const int indx = this->surfaceComboBox->currentIndex(); if ((indx >= 0) && (indx < this->surfaceComboBox->count())) { void* pointer = this->surfaceComboBox->itemData(indx).value(); s = (Surface*)pointer; } return s; } /** * Set the selected surface. * @param surface * The selected surface. */ void SurfaceSelectionViewController::setSurface(Surface* surface) { if (this->surfaceSelectionModel != NULL) { this->surfaceSelectionModel->setSurface(surface); this->updateControl(); } else { const int32_t numItems = this->surfaceComboBox->count(); for (int32_t i = 0; i < numItems; i++) { void* pointer = this->surfaceComboBox->itemData(i).value(); Surface* s = (Surface*)pointer; if (surface == s) { this->surfaceComboBox->blockSignals(true); this->surfaceComboBox->setCurrentIndex(i); this->surfaceComboBox->blockSignals(false); break; } } } } /** * Called when the item in the combo box is changed. * @param indx * Index of item that was selected. */ void SurfaceSelectionViewController::comboBoxCurrentIndexChanged(int indx) { void* pointer = this->surfaceComboBox->itemData(indx).value(); Surface* s = (Surface*)pointer; if (this->surfaceSelectionModel != NULL) { this->surfaceSelectionModel->setSurface(s); } emit surfaceSelected(s); } connectome-workbench-1.4.2/src/GuiQt/SurfaceSelectionViewController.h000066400000000000000000000067771360521144700260020ustar00rootroot00000000000000#ifndef __SURFACE_SELECTION_CONTROL__H_ #define __SURFACE_SELECTION_CONTROL__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WuQWidget.h" class QComboBox; namespace caret { class BrainStructure; class Surface; class SurfaceSelectionModel; class SurfaceSelectionViewController : public WuQWidget { Q_OBJECT public: SurfaceSelectionViewController(QObject* parent, SurfaceSelectionModel* surfaceSelectionModel, const QString& objectName, const QString& descriptiveName); SurfaceSelectionViewController(QObject* parent, BrainStructure* brainStructure, const QString& objectName, const QString& descriptiveName); SurfaceSelectionViewController(QObject* parent, const QString& objectName, const QString& descriptiveName); virtual ~SurfaceSelectionViewController(); QWidget* getWidget(); Surface* getSurface(); void updateControl(); void updateControl(SurfaceSelectionModel* surfaceSelectionModel); signals: void surfaceSelected(Surface*); public slots: void setSurface(Surface*); private slots: void comboBoxCurrentIndexChanged(int); private: SurfaceSelectionViewController(const SurfaceSelectionViewController&); SurfaceSelectionViewController& operator=(const SurfaceSelectionViewController&); private: enum Mode { /** Use all surfaces from a brain structure */ MODE_BRAIN_STRUCTURE, /** Selection mode NOT passed to constructor, user must use updateControl(SurfaceSelectionModel*) */ MODE_SELECTION_MODEL_DYNAMIC, /** Selection model passed to constructor, and use it */ MODE_SELECTION_MODEL_STATIC }; void initializeControl(const Mode mode, SurfaceSelectionModel* surfaceSelectionModel, const QString& objectName, const QString& descriptiveName); Mode mode; SurfaceSelectionModel* surfaceSelectionModel; QComboBox* surfaceComboBox; }; #ifdef __SURFACE_SELECTION_CONTROL_DECLARE__ // #endif // __SURFACE_SELECTION_CONTROL_DECLARE__ } // namespace #endif //__SURFACE_SELECTION_CONTROL__H_ connectome-workbench-1.4.2/src/GuiQt/ThresholdingSetMapsDialog.cxx000066400000000000000000000116721360521144700252550ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __THRESHOLDING_SET_MAPS_DIALOG_DECLARE__ #include "ThresholdingSetMapsDialog.h" #undef __THRESHOLDING_SET_MAPS_DIALOG_DECLARE__ #include "CaretAssert.h" #include "CaretMappableDataFile.h" #include "WuQMessageBox.h" using namespace caret; #include #include #include /** * \class caret::ThresholdingSetMapsDialog * \brief Dialog for setting threshold * \ingroup GuiQt */ /** * Constructor. * * @param dataFile * Data file that is being thresholded * @param thresholdFile * File that is used for thresholding * @param thresholdFileMapIndex * Map index from thresholding file. * @param parent * Parent widget for this dialog. */ ThresholdingSetMapsDialog::ThresholdingSetMapsDialog(CaretMappableDataFile* dataFile, CaretMappableDataFile* thresholdFile, const int32_t thresholdFileMapIndex, QWidget* parent) : WuQDialogModal("Set Thresholding Maps", parent), m_dataFile(dataFile), m_thresholdFile(thresholdFile), m_thresholdFileMapIndex(thresholdFileMapIndex) { CaretAssert(m_dataFile); CaretAssert(m_thresholdFile); CaretAssert(m_thresholdFileMapIndex >= 0); CaretAssert(m_thresholdFileMapIndex < m_thresholdFile->getNumberOfMaps()); const AString numName("(" + AString::number(m_thresholdFileMapIndex + 1) + "): " + m_thresholdFile->getMapName(m_thresholdFileMapIndex)); m_setSameIndexRadioButton = new QRadioButton("Threshold Each Map With Map " + numName); const int32_t numMaps = std::min(m_dataFile->getNumberOfMaps(), m_thresholdFile->getNumberOfMaps()); m_setOneToEnRadioButton = new QRadioButton("Threshold Each Map With Sequential Indices " "1 to " + AString::number(numMaps)); m_setOneToEnRadioButton->setEnabled(m_thresholdFile->getNumberOfMaps() > 1); QButtonGroup* buttonGroup = new QButtonGroup(this); buttonGroup->addButton(m_setSameIndexRadioButton); buttonGroup->addButton(m_setOneToEnRadioButton); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(m_setSameIndexRadioButton); layout->addWidget(m_setOneToEnRadioButton); widget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); setCentralWidget(widget, WuQDialog::SCROLL_AREA_NEVER); } /** * Destructor. */ ThresholdingSetMapsDialog::~ThresholdingSetMapsDialog() { } /** * Called when user presses the OK or Cancel button * * @param resultCode * Result code from dialog. */ void ThresholdingSetMapsDialog::done(int resultCode) { if (resultCode == Accepted) { if (m_setSameIndexRadioButton->isChecked()) { const int32_t numMaps = m_dataFile->getNumberOfMaps(); for (int32_t i = 0; i < numMaps; i++) { m_dataFile->getMapThresholdFileSelectionModel(i)->setSelectedFile(m_thresholdFile); m_dataFile->getMapThresholdFileSelectionModel(i)->setSelectedMapIndex(m_thresholdFileMapIndex); } } else if (m_setOneToEnRadioButton->isChecked()) { const int32_t numMaps = std::min(m_dataFile->getNumberOfMaps(), m_thresholdFile->getNumberOfMaps()); for (int32_t i = 0; i < numMaps; i++) { m_dataFile->getMapThresholdFileSelectionModel(i)->setSelectedFile(m_thresholdFile); m_dataFile->getMapThresholdFileSelectionModel(i)->setSelectedMapIndex(i); } } else { WuQMessageBox::errorOk(this, "Select a Threshold Option"); return; } } else if (resultCode == Rejected) { /* nothing */ } else { CaretAssertMessage(0, "Should never get here"); } WuQDialogModal::done(resultCode); } connectome-workbench-1.4.2/src/GuiQt/ThresholdingSetMapsDialog.h000066400000000000000000000044211360521144700246740ustar00rootroot00000000000000#ifndef __THRESHOLDING_SET_MAPS_DIALOG_H__ #define __THRESHOLDING_SET_MAPS_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "WuQDialogModal.h" class QRadioButton; namespace caret { class CaretMappableDataFile; class ThresholdingSetMapsDialog : public WuQDialogModal { Q_OBJECT public: ThresholdingSetMapsDialog(CaretMappableDataFile* dataFile, CaretMappableDataFile* thresholdFile, const int32_t thresholdFileMapIndex, QWidget* parent = 0); virtual ~ThresholdingSetMapsDialog(); ThresholdingSetMapsDialog(const ThresholdingSetMapsDialog&) = delete; ThresholdingSetMapsDialog& operator=(const ThresholdingSetMapsDialog&) = delete; // ADD_NEW_METHODS_HERE public slots: virtual void done(int resultCode) override; private: CaretMappableDataFile* m_dataFile; CaretMappableDataFile* m_thresholdFile; const int32_t m_thresholdFileMapIndex; QRadioButton* m_setSameIndexRadioButton; QRadioButton* m_setOneToEnRadioButton; // ADD_NEW_MEMBERS_HERE }; #ifdef __THRESHOLDING_SET_MAPS_DIALOG_DECLARE__ // #endif // __THRESHOLDING_SET_MAPS_DIALOG_DECLARE__ } // namespace #endif //__THRESHOLDING_SET_MAPS_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/TileTabsConfigurationDialog.cxx000066400000000000000000001527211360521144700255660ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define __TILE_TABS_CONFIGURATION_DIALOG_DECLARE__ #include "TileTabsConfigurationDialog.h" #undef __TILE_TABS_CONFIGURATION_DIALOG_DECLARE__ #include "BrainBrowserWindow.h" #include "BrainBrowserWindowComboBox.h" #include "BrowserWindowContent.h" #include "CaretAssert.h" #include "CaretPreferences.h" #include "EnumComboBoxTemplate.h" #include "EventBrowserWindowGraphicsRedrawn.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventHelpViewerDisplay.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "SessionManager.h" #include "TileTabsConfiguration.h" #include "TileTabsGridRowColumnElement.h" #include "WuQDataEntryDialog.h" #include "WuQFactory.h" #include "WuQGridLayoutGroup.h" #include "WuQListWidget.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::TileTabsConfigurationDialog * \brief Edit and create configurations for tile tabs viewing. * \ingroup GuiQt */ /** * Constructor. * * @param parentBrainBrowserWindow * Parent window. */ TileTabsConfigurationDialog::TileTabsConfigurationDialog(BrainBrowserWindow* parentBrainBrowserWindow) : WuQDialogNonModal("Tile Tabs Configurations", parentBrainBrowserWindow) { m_blockReadConfigurationsFromPreferences = false; m_caretPreferences = SessionManager::get()->getCaretPreferences(); QWidget* dialogWidget = new QWidget(); QHBoxLayout* configurationLayout = new QHBoxLayout(dialogWidget); configurationLayout->setSpacing(0); configurationLayout->addWidget(createActiveConfigurationWidget(), 0); configurationLayout->addWidget(createCopyLoadPushButtonsWidget(), 0, Qt::AlignTop); configurationLayout->addWidget(createUserConfigurationSelectionWidget(), 100, Qt::AlignTop); setApplyButtonText(""); setStandardButtonText(QDialogButtonBox::Help, "Help"); updateDialogWithSelectedTileTabsFromWindow(parentBrainBrowserWindow); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); setCentralWidget(dialogWidget, WuQDialog::SCROLL_AREA_NEVER); resize(750, 500); disableAutoDefaultForAllPushButtons(); } /** * Destructor. */ TileTabsConfigurationDialog::~TileTabsConfigurationDialog() { EventManager::get()->removeAllEventsFromListener(this); } /** * Receive an event. * * @param event * The event that the receive can respond to. */ void TileTabsConfigurationDialog::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN) { auto redrawEvent = dynamic_cast(event); CaretAssert(redrawEvent); BrowserWindowContent* browserWindowContent = getBrowserWindowContent(); CaretAssert(browserWindowContent); if (redrawEvent->getBrowserWindowIndex() == browserWindowContent->getWindowIndex()) { updateDialog(); } } } /** * Gets called when the dialog gains focus. */ void TileTabsConfigurationDialog::focusGained() { updateDialog(); } /** * @return Create and return the copy and load buttons widget. */ QWidget* TileTabsConfigurationDialog::createCopyLoadPushButtonsWidget() { m_replacePushButton = new QPushButton("Replace -->"); m_replacePushButton->setAutoDefault(false); WuQtUtilities::setWordWrappedToolTip(m_replacePushButton, "Replace the Rows, Columns, and Stretch Factors in the User Configuration " "with those from the Custom Configuration"); QObject::connect(m_replacePushButton, SIGNAL(clicked()), this, SLOT(replaceUserConfigurationPushButtonClicked())); m_loadPushButton = new QPushButton("<-- Load"); m_loadPushButton->setAutoDefault(false); WuQtUtilities::setWordWrappedToolTip(m_loadPushButton, "Load the User Configuration's Rows, Columns, and Stretch Factors into " "the Custom Configuration"); QObject::connect(m_loadPushButton, SIGNAL(clicked()), this, SLOT(loadIntoActiveConfigurationPushButtonClicked())); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addSpacing(50); layout->addWidget(m_replacePushButton); layout->addSpacing(50); layout->addWidget(m_loadPushButton); layout->addStretch(); return widget; } /** * Called when Replace to user configuration pushbutton is clicked. */ void TileTabsConfigurationDialog::replaceUserConfigurationPushButtonClicked() { m_blockReadConfigurationsFromPreferences = true; const TileTabsConfiguration* activeConfiguration = getCustomTileTabsConfiguration(); CaretAssert(activeConfiguration); TileTabsConfiguration* userConfiguration = getSelectedUserTileTabsConfiguration(); if (userConfiguration == NULL) { newUserConfigurationButtonClicked(); userConfiguration = getSelectedUserTileTabsConfiguration(); if (userConfiguration == NULL) { WuQMessageBox::errorOk(this, "There are no user configurations"); m_blockReadConfigurationsFromPreferences = false; return; } } else { const AString msg("Do you want to replace " + userConfiguration->getName() + "?"); if ( ! WuQMessageBox::warningOkCancel(m_replacePushButton, msg)) { m_blockReadConfigurationsFromPreferences = false; return; } } userConfiguration->copy(*activeConfiguration); m_caretPreferences->writeTileTabsConfigurations(); m_blockReadConfigurationsFromPreferences = false; updateDialog(); } /** * Called when Load pushbutton is clicked. */ void TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() { if (m_automaticConfigurationRadioButton->isChecked()) { return; } TileTabsConfiguration* activeConfiguration = getCustomTileTabsConfiguration(); CaretAssert(activeConfiguration); const TileTabsConfiguration* userConfiguration = getSelectedUserTileTabsConfiguration(); if (userConfiguration == NULL) { WuQMessageBox::errorOk(this, "There are no user configurations"); return; } activeConfiguration->copy(*userConfiguration); updateStretchFactors(); updateGraphicsWindow(); } /** * @return The browser window selected window index. */ BrainBrowserWindow* TileTabsConfigurationDialog::getBrowserWindow() { m_browserWindowComboBox->updateComboBox(); /* * This can be NULL when wb_view is closing. */ BrainBrowserWindow* bbw = m_browserWindowComboBox->getSelectedBrowserWindow(); return bbw; } /** * @return The browser window content for the selected window index. * May be NULL when no tabs are open. */ BrowserWindowContent* TileTabsConfigurationDialog::getBrowserWindowContent() { BrowserWindowContent* bwc(NULL); BrainBrowserWindow* bbw = getBrowserWindow(); if (bbw != NULL) { bwc = bbw->getBrowerWindowContent(); } return bwc; } /** * @return The configuration selection widget. */ QWidget* TileTabsConfigurationDialog::createUserConfigurationSelectionWidget() { m_userConfigurationSelectionListWidget = new WuQListWidget(); m_userConfigurationSelectionListWidget->setSelectionMode(QListWidget::SingleSelection); QHBoxLayout* selectionLayout = new QHBoxLayout(); WuQtUtilities::setLayoutMargins(selectionLayout, 0); selectionLayout->addWidget(m_userConfigurationSelectionListWidget, 100); const AString newToolTip = WuQtUtilities::createWordWrappedToolTipText("Create new User Configuration by entering a name.\n" "It will contain rows/columns/factors from the Custom Configuration"); m_newConfigurationPushButton = new QPushButton("New..."); m_newConfigurationPushButton->setAutoDefault(false); m_newConfigurationPushButton->setToolTip(newToolTip); QObject::connect(m_newConfigurationPushButton, SIGNAL(clicked()), this, SLOT(newUserConfigurationButtonClicked())); m_renameConfigurationPushButton = new QPushButton("Rename..."); m_renameConfigurationPushButton->setToolTip("Rename the selected User Configuration"); m_renameConfigurationPushButton->setAutoDefault(false); QObject::connect(m_renameConfigurationPushButton, SIGNAL(clicked()), this, SLOT(renameUserConfigurationButtonClicked())); m_deleteConfigurationPushButton = new QPushButton("Delete..."); m_deleteConfigurationPushButton->setToolTip("Delete the selected User Configuration"); m_deleteConfigurationPushButton->setAutoDefault(false); QObject::connect(m_deleteConfigurationPushButton, SIGNAL(clicked()), this, SLOT(deleteUserConfigurationButtonClicked())); QGridLayout* buttonsLayout = new QGridLayout(); buttonsLayout->setContentsMargins(0, 0, 0, 0); buttonsLayout->addWidget(m_newConfigurationPushButton, 0, 0, Qt::AlignRight); buttonsLayout->addWidget(m_renameConfigurationPushButton, 0, 1, Qt::AlignLeft); buttonsLayout->addWidget(m_deleteConfigurationPushButton, 1, 0, 1, 2, Qt::AlignHCenter); QGroupBox* configurationWidget = new QGroupBox("User Configurations"); QVBoxLayout* configurationLayout = new QVBoxLayout(configurationWidget); configurationLayout->addWidget(m_userConfigurationSelectionListWidget, 100); configurationLayout->addLayout(buttonsLayout, 0); return configurationWidget; } /** * @return Instance of workbench window widget. */ QWidget* TileTabsConfigurationDialog::createWorkbenchWindowWidget() { /* * Window number */ QLabel* windowLabel = new QLabel("Workbench Window"); m_browserWindowComboBox = new BrainBrowserWindowComboBox(BrainBrowserWindowComboBox::STYLE_NUMBER, this); m_browserWindowComboBox->getWidget()->setFixedWidth(60); QObject::connect(m_browserWindowComboBox, SIGNAL(browserWindowSelected(BrainBrowserWindow*)), this, SLOT(browserWindowComboBoxValueChanged(BrainBrowserWindow*))); QWidget* widget = new QWidget(); QHBoxLayout* layout = new QHBoxLayout(widget); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(windowLabel); layout->addWidget(m_browserWindowComboBox->getWidget()); layout->addStretch(); return widget; } /** * @return The rows/columns stretch layout */ QWidget* TileTabsConfigurationDialog::createCustomOptionsWidget() { const QString toolTip("" "Removes any space between rows and columns in the tile tabs configuration. " "Some scenes created in previous versions of wb_view may not appear correctly " "due to changes in layout of the tabs. Enabling this option may fix the " "problem. In addition, if the Lock Aspect option is selected prior to " "to enabling tile tabs, this option may improve the layout." ""); m_centeringCorrectionCheckBox = new QCheckBox("Centering Correction"); m_centeringCorrectionCheckBox->setToolTip(toolTip); QObject::connect(m_centeringCorrectionCheckBox, &QCheckBox::clicked, this, &TileTabsConfigurationDialog::centeringCorrectionCheckBoxClicked); QGroupBox* groupBox = new QGroupBox("Options"); QVBoxLayout* layout = new QVBoxLayout(groupBox); layout->addWidget(m_centeringCorrectionCheckBox); return groupBox; } /** * Called when user checks/unchecks the centering correction checkbox * * @bool checked * New checked status */ void TileTabsConfigurationDialog::centeringCorrectionCheckBoxClicked(bool checked) { TileTabsConfiguration* config = getCustomTileTabsConfiguration(); if (config != NULL) { config->setCenteringCorrectionEnabled(checked); updateGraphicsWindow(); } } /** * Update the custom options */ void TileTabsConfigurationDialog::updateCustomOptionsWidget() { TileTabsConfiguration* config = getCustomTileTabsConfiguration(); if (config != NULL) { m_centeringCorrectionCheckBox->setChecked(config->isCenteringCorrectionEnabled()); } } /** * @return The rows/columns stretch layout */ QWidget* TileTabsConfigurationDialog::createRowColumnStretchWidget() { QGroupBox* rowGroupBox = new QGroupBox("Rows"); rowGroupBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); m_rowElementsGridLayout = new QGridLayout(rowGroupBox); WuQtUtilities::setLayoutSpacingAndMargins(m_rowElementsGridLayout, 4, 2); QGroupBox* columnsGroupBox = new QGroupBox("Columns"); m_columnElementsGridLayout = new QGridLayout(columnsGroupBox); WuQtUtilities::setLayoutSpacingAndMargins(m_columnElementsGridLayout, 2, 2); QWidget* widget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(widget); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(rowGroupBox); layout->addSpacing(6); layout->addWidget(columnsGroupBox); layout->addStretch(); return widget; } /** * update the row and column stretching widgets. * * @param configuration * Current custom configuration. */ void TileTabsConfigurationDialog::updateRowColumnStretchWidgets(TileTabsConfiguration* configuration) { /* * Update rows */ { const int32_t numRows = configuration->getNumberOfRows(); int32_t numRowElements = static_cast(m_rowElements.size()); /** * Add elements as needed. */ const int32_t numToAdd = numRows - numRowElements; for (int32_t iRow = 0; iRow < numToAdd; iRow++) { addRowColumnStretchWidget(EventTileTabsConfigurationModification::RowColumnType::ROW, m_rowElementsGridLayout, m_rowElements); } /* * Update widgets with element content */ numRowElements = static_cast(m_rowElements.size()); for (int32_t iRow = 0; iRow < numRowElements; iRow++) { TileTabsGridRowColumnElement* element(NULL); if (iRow < numRows) { element = configuration->getRow(iRow); } CaretAssertVectorIndex(m_rowElements, iRow); m_rowElements[iRow]->updateContent(element); } m_rowElementsGridLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); } /* * Update columns */ { const int32_t numColumns = configuration->getNumberOfColumns(); int32_t numColumnElements = static_cast(m_columnElements.size()); /** * Add elements as needed. */ const int32_t numToAdd = numColumns - numColumnElements; for (int32_t iColumn = 0; iColumn < numToAdd; iColumn++) { addRowColumnStretchWidget(EventTileTabsConfigurationModification::RowColumnType::COLUMN, m_columnElementsGridLayout, m_columnElements); } /* * Update widgets with element content */ numColumnElements = static_cast(m_columnElements.size()); for (int32_t iColumn = 0; iColumn < numColumnElements; iColumn++) { TileTabsGridRowColumnElement* element(NULL); if (iColumn < numColumns) { element = configuration->getColumn(iColumn); } CaretAssertVectorIndex(m_columnElements, iColumn); m_columnElements[iColumn]->updateContent(element); } m_columnElementsGridLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); } updateCustomOptionsWidget(); // m_customConfigurationWidget->adjustSize(); } /** * Add a row/column stretch widget. * * @param rowColumnType * The row or column type. * @param gridLayout * Grid layout for widgets. * @param elementVector * Container for row/column elements. */ void TileTabsConfigurationDialog::addRowColumnStretchWidget(const EventTileTabsConfigurationModification::RowColumnType rowColumnType, QGridLayout* gridLayout, std::vector& elementVector) { const int32_t index = static_cast(elementVector.size()); if (index == 0) { int32_t columnIndex(0); int32_t row = gridLayout->rowCount(); gridLayout->addWidget(new QLabel("Index"), row, columnIndex++, Qt::AlignRight); gridLayout->addWidget(new QLabel(" "), row, columnIndex++); gridLayout->addWidget(new QLabel("Content"), row, columnIndex++, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Type"), row, columnIndex++, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Stretch"), row, columnIndex++, Qt::AlignHCenter); for (int32_t i = 0; i < columnIndex; i++) { gridLayout->setColumnStretch(i, 0); } } TileTabElementWidgets* elementWidget = new TileTabElementWidgets(this, rowColumnType, index, gridLayout, this); QObject::connect(elementWidget, &TileTabElementWidgets::itemChanged, this, &TileTabsConfigurationDialog::configurationStretchFactorWasChanged); QObject::connect(elementWidget, &TileTabElementWidgets::modificationRequested, this, &TileTabsConfigurationDialog::tileTabsModificationRequested); elementVector.push_back(elementWidget); } /** * @return The active configuration widget. */ QWidget* TileTabsConfigurationDialog::createActiveConfigurationWidget() { const AString autoToolTip("Workbench adjusts the number of rows and columns so " "that all tabs are displayed"); m_automaticConfigurationRadioButton = new QRadioButton("Automatic Configuration"); m_automaticConfigurationRadioButton->setToolTip(WuQtUtilities::createWordWrappedToolTipText(autoToolTip)); const AString customToolTip("User sets the number of row, columns, and stretch factors"); m_customConfigurationRadioButton = new QRadioButton("Custom Configuration"); m_customConfigurationRadioButton->setToolTip(WuQtUtilities::createWordWrappedToolTipText(customToolTip)); QButtonGroup* buttonGroup = new QButtonGroup(this); buttonGroup->addButton(m_automaticConfigurationRadioButton); buttonGroup->addButton(m_customConfigurationRadioButton); QObject::connect(buttonGroup, static_cast(&QButtonGroup::buttonClicked), this, &TileTabsConfigurationDialog::automaticCustomButtonClicked); QLabel* rowsLabel = new QLabel("Rows"); m_numberOfRowsSpinBox = WuQFactory::newSpinBoxWithMinMaxStepSignalInt(1, s_maximumRowsColumns, 1, this, SLOT(configurationNumberOfRowsOrColumnsChanged())); m_numberOfRowsSpinBox->setToolTip("Number of rows for the tab configuration"); QLabel* columnsLabel = new QLabel("Columns"); m_numberOfColumnsSpinBox = WuQFactory::newSpinBoxWithMinMaxStepSignalInt(1, s_maximumRowsColumns, 1, this, SLOT(configurationNumberOfRowsOrColumnsChanged())); m_numberOfColumnsSpinBox->setToolTip("Number of columns for the tab configuration"); m_customConfigurationWidget = createRowColumnStretchWidget(); m_customConfigurationWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); m_customOptionsWidget = createCustomOptionsWidget(); m_customOptionsWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); QScrollArea* stretchFactorScrollArea = new QScrollArea(); stretchFactorScrollArea->setWidget(m_customConfigurationWidget); stretchFactorScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // stretchFactorScrollArea->setSizeAdjustPolicy(QScrollArea::AdjustToContents); stretchFactorScrollArea->setWidgetResizable(true); QGroupBox* widget = new QGroupBox("Tile Tabs Configuration in Workbench Window"); QGridLayout* widgetLayout = new QGridLayout(widget); widgetLayout->setColumnStretch(0, 0); widgetLayout->setColumnStretch(1, 0); widgetLayout->setColumnStretch(2, 0); widgetLayout->setColumnStretch(3, 0); widgetLayout->setColumnStretch(4, 0); widgetLayout->setColumnStretch(5, 100); widgetLayout->setColumnMinimumWidth(0, 20); widgetLayout->addWidget(createWorkbenchWindowWidget(), 0, 0, 1, 6, Qt::AlignLeft); widgetLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), 1, 0, 1, 6); widgetLayout->addWidget(m_automaticConfigurationRadioButton, 2, 0, 1, 6, Qt::AlignLeft); widgetLayout->addWidget(m_customConfigurationRadioButton, 3, 0, 1, 1, Qt::AlignLeft); widgetLayout->addWidget(rowsLabel, 3, 1, 1, 1); widgetLayout->addWidget(m_numberOfRowsSpinBox, 3, 2, 1, 1); widgetLayout->addWidget(columnsLabel, 3, 3, 1, 1); widgetLayout->addWidget(m_numberOfColumnsSpinBox, 3, 4, 1, 1); widgetLayout->addWidget(stretchFactorScrollArea, 4, 0, 1, 6); widgetLayout->addWidget(m_customOptionsWidget, 5, 0, 1, 6, Qt::AlignLeft); widget->setFixedWidth(widget->sizeHint().width()); return widget; } /** * Called when window number combo box value changed. */ void TileTabsConfigurationDialog::browserWindowComboBoxValueChanged(BrainBrowserWindow* browserWindow) { int32_t windowIndex = -1; if (browserWindow != NULL) { windowIndex = browserWindow->getBrowserWindowIndex(); } updateDialogWithSelectedTileTabsFromWindow(GuiManager::get()->getBrowserWindowByWindowIndex(windowIndex)); } /** * Called when automatic/custom configuration radiobutton is clicked * * @param button * New checked status of checkbox. */ void TileTabsConfigurationDialog::automaticCustomButtonClicked(QAbstractButton* button) { BrowserWindowContent* browserWindowContent = getBrowserWindowContent(); if (button == m_automaticConfigurationRadioButton) { browserWindowContent->setTileTabsConfigurationMode(TileTabsGridModeEnum::AUTOMATIC); } else if (button == m_customConfigurationRadioButton) { browserWindowContent->setTileTabsConfigurationMode(TileTabsGridModeEnum::CUSTOM); } else { CaretAssert(0); } updateStretchFactors(); updateGraphicsWindow(); } /** * Update the content of the dialog. If tile tabs is selected in the given * window, the dialog will be initialized with the tile tabs configuration * selected in the window. * * @param brainBrowserWindow * Browser window from which dialog was selected. */ void TileTabsConfigurationDialog::updateDialogWithSelectedTileTabsFromWindow(BrainBrowserWindow* brainBrowserWindow) { CaretAssert(brainBrowserWindow); m_browserWindowComboBox->updateComboBox(); m_browserWindowComboBox->setBrowserWindow(brainBrowserWindow); updateDialog(); } /** * Read the configurations from the preferences. */ void TileTabsConfigurationDialog::readConfigurationsFromPreferences() { if (m_blockReadConfigurationsFromPreferences) { return; } m_caretPreferences->readTileTabsConfigurations(); } /** * Update the content of the dialog. */ void TileTabsConfigurationDialog::updateDialog() { BrowserWindowContent* browserWindowContent = getBrowserWindowContent(); if (browserWindowContent == NULL) { return; } switch (browserWindowContent->getTileTabsConfigurationMode()) { case TileTabsGridModeEnum::AUTOMATIC: m_automaticConfigurationRadioButton->setChecked(true); break; case TileTabsGridModeEnum::CUSTOM: m_customConfigurationRadioButton->setChecked(true); break; } readConfigurationsFromPreferences(); int defaultIndex = m_userConfigurationSelectionListWidget->currentRow(); QSignalBlocker blocker(m_userConfigurationSelectionListWidget); m_userConfigurationSelectionListWidget->clear(); std::vector configurations = m_caretPreferences->getTileTabsConfigurationsSortedByName(); const int32_t numConfig = static_cast(configurations.size()); for (int32_t i = 0; i < numConfig; i++) { const TileTabsConfiguration* configuration = configurations[i]; AString configName = configuration->getName(); configName.append(" (" + AString::number(configuration->getNumberOfRows()) + ", " + AString::number(configuration->getNumberOfColumns()) + ")"); /* * Second element is user data which contains the Unique ID */ QListWidgetItem* item = new QListWidgetItem(configName); item->setData(Qt::UserRole, QVariant(configuration->getUniqueIdentifier())); m_userConfigurationSelectionListWidget->addItem(item); } const int32_t numItemsInComboBox = m_userConfigurationSelectionListWidget->count(); if (defaultIndex >= numItemsInComboBox) { defaultIndex = numItemsInComboBox - 1; } if (defaultIndex < 0) { defaultIndex = 0; } if (defaultIndex < m_userConfigurationSelectionListWidget->count()) { m_userConfigurationSelectionListWidget->setCurrentRow(defaultIndex); } updateStretchFactors(); } /** * Update the stretch factors. */ void TileTabsConfigurationDialog::updateStretchFactors() { BrainBrowserWindow* browserWindow = getBrowserWindow(); m_automaticConfigurationRadioButton->setText(browserWindow->getTileTabsConfigurationLabelText(TileTabsGridModeEnum::AUTOMATIC, true)); m_customConfigurationRadioButton->setText(browserWindow->getTileTabsConfigurationLabelText(TileTabsGridModeEnum::CUSTOM, false)); const TileTabsConfiguration* configuration = getCustomTileTabsConfiguration(); if (configuration != NULL) { updateRowColumnStretchWidgets(const_cast(configuration)); QSignalBlocker rowBlocker(m_numberOfRowsSpinBox); m_numberOfRowsSpinBox->setValue(configuration->getNumberOfRows()); QSignalBlocker columnBlocker(m_numberOfColumnsSpinBox); m_numberOfColumnsSpinBox->setValue(configuration->getNumberOfColumns()); } const bool editableFlag = ( ! m_automaticConfigurationRadioButton->isChecked()); // This does not re-enable the construction menu //m_customConfigurationWidget->setEnabled(editableFlag); m_loadPushButton->setEnabled(editableFlag); } /** * Select the tile tabs configuration with the given name. */ void TileTabsConfigurationDialog::selectTileTabConfigurationByUniqueID(const AString& uniqueID) { const int32_t numItems = m_userConfigurationSelectionListWidget->count(); for (int32_t i = 0; i < numItems; i++) { QListWidgetItem* item = m_userConfigurationSelectionListWidget->item(i); const AString itemID = item->data(Qt::UserRole).toString(); if (itemID == uniqueID) { QSignalBlocker blocker(m_userConfigurationSelectionListWidget); m_userConfigurationSelectionListWidget->setCurrentItem(item); break; } } } /** * Called when new user configuration button is clicked. */ void TileTabsConfigurationDialog::newUserConfigurationButtonClicked() { AString newTileTabsName; AString configurationUniqueID; bool exitLoop = false; while (exitLoop == false) { /* * Popup dialog to get name for new configuration */ WuQDataEntryDialog ded("New Tile Tabs Configuration", m_newConfigurationPushButton); QLineEdit* nameLineEdit = ded.addLineEditWidget("Configuration Name"); nameLineEdit->setText(newTileTabsName); if (ded.exec() == WuQDataEntryDialog::Accepted) { /* * Make sure name is not empty */ newTileTabsName = nameLineEdit->text().trimmed(); if (newTileTabsName.isEmpty()) { WuQMessageBox::errorOk(m_newConfigurationPushButton, "Enter a name"); } else { /* * See if a configuration with the user entered name already exists */ TileTabsConfiguration* configuration = m_caretPreferences->getTileTabsConfigurationByName(newTileTabsName); if (configuration != NULL) { const QString msg = ("Configuration named \"" + newTileTabsName + "\" already exits. Rename it?"); if (WuQMessageBox::warningYesNo(m_newConfigurationPushButton, msg)) { configuration->setName(newTileTabsName); configurationUniqueID = configuration->getUniqueIdentifier(); exitLoop = true; } } else { /* * New configuration is copy of selected configuration (if available) */ const TileTabsConfiguration* selectedConfiguration = getCustomTileTabsConfiguration(); TileTabsConfiguration* configuration = ((selectedConfiguration != NULL) ? selectedConfiguration->newCopyWithNewUniqueIdentifier() : new TileTabsConfiguration()); configuration->setName(newTileTabsName); configurationUniqueID = configuration->getUniqueIdentifier(); m_caretPreferences->addTileTabsConfiguration(configuration); exitLoop = true; } } } else { /* * User pressed cancel button. */ exitLoop = true; } } if ( ! configurationUniqueID.isEmpty()) { updateDialog(); selectTileTabConfigurationByUniqueID(configurationUniqueID); } } /** * Called when delete user configuration button is clicked. */ void TileTabsConfigurationDialog::deleteUserConfigurationButtonClicked() { TileTabsConfiguration* configuration = getSelectedUserTileTabsConfiguration(); if (configuration != NULL) { const AString uniqueID = configuration->getUniqueIdentifier(); const QString msg = ("Delete configuration named \"" + configuration->getName() + "\" ?"); if (WuQMessageBox::warningYesNo(m_newConfigurationPushButton, msg)) { m_caretPreferences->removeTileTabsConfigurationByUniqueIdentifier(uniqueID); updateDialog(); } } } /** * Called when rename user configuration button is clicked. */ void TileTabsConfigurationDialog::renameUserConfigurationButtonClicked() { TileTabsConfiguration* configuration = getSelectedUserTileTabsConfiguration(); if (configuration != NULL) { m_blockReadConfigurationsFromPreferences = true; bool ok = false; const AString oldName = configuration->getName(); const AString newName = QInputDialog::getText(m_deleteConfigurationPushButton, "Rename Configuration", "Name", QLineEdit::Normal, oldName, &ok); if (ok && (newName.isEmpty() == false)) { configuration->setName(newName); m_caretPreferences->writeTileTabsConfigurations(); m_blockReadConfigurationsFromPreferences = false; updateDialog(); } else { m_blockReadConfigurationsFromPreferences = false; } } } /** * @return A pointer to the automatic tile tabs configuration. */ TileTabsConfiguration* TileTabsConfigurationDialog::getAutomaticTileTabsConfiguration() { BrowserWindowContent* browserWindowContent = getBrowserWindowContent(); TileTabsConfiguration* configuration = browserWindowContent->getAutomaticTileTabsConfiguration(); CaretAssert(configuration); return configuration; } /** * @return A pointer to the custom tile tabs configuration. */ TileTabsConfiguration* TileTabsConfigurationDialog::getCustomTileTabsConfiguration() { BrowserWindowContent* browserWindowContent = getBrowserWindowContent(); TileTabsConfiguration* configuration = browserWindowContent->getCustomTileTabsConfiguration(); CaretAssert(configuration); return configuration; } /** * @return The selected user tile tabs configuration (will be * NULL if there are no user configurations). */ TileTabsConfiguration* TileTabsConfigurationDialog::getSelectedUserTileTabsConfiguration() { TileTabsConfiguration* configuration = NULL; const int32_t indx = m_userConfigurationSelectionListWidget->currentRow(); if ((indx >= 0) && (indx < m_userConfigurationSelectionListWidget->count())) { QListWidgetItem* item = m_userConfigurationSelectionListWidget->item(indx); const AString itemID = item->data(Qt::UserRole).toString(); configuration = m_caretPreferences->getTileTabsConfigurationByUniqueIdentifier(itemID); } return configuration; } /** * Called when the number of rows or columns changes. */ void TileTabsConfigurationDialog::configurationNumberOfRowsOrColumnsChanged() { TileTabsConfiguration* configuration = getCustomTileTabsConfiguration(); if (configuration != NULL) { configuration->setNumberOfRows(m_numberOfRowsSpinBox->value()); configuration->setNumberOfColumns(m_numberOfColumnsSpinBox->value()); updateStretchFactors(); updateGraphicsWindow(); } } /** * Called when a configuration stretch factor value is changed. */ void TileTabsConfigurationDialog::configurationStretchFactorWasChanged() { TileTabsConfiguration* configuration = getCustomTileTabsConfiguration(); if (configuration == NULL) { return; } updateStretchFactors(); updateGraphicsWindow(); } /** * Called when a tile tabs configuration modification is requested * * @param modification * Modification that is requested. */ void TileTabsConfigurationDialog::tileTabsModificationRequested(EventTileTabsConfigurationModification& modification) { TileTabsConfiguration* configuration = getCustomTileTabsConfiguration(); if (configuration != NULL) { modification.setWindowIndex(m_browserWindowComboBox->getSelectedBrowserWindowIndex()); EventManager::get()->sendEvent(modification.getPointer()); updateStretchFactors(); updateGraphicsWindow(); } } /** * Update the graphics for the selected window. */ void TileTabsConfigurationDialog::updateGraphicsWindow() { const BrowserWindowContent* bwc = getBrowserWindowContent(); if (bwc->isTileTabsEnabled()) { const int32_t windowIndex = bwc->getWindowIndex(); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(windowIndex).getPointer()); } } /** * Called when help button is clicked. */ void TileTabsConfigurationDialog::helpButtonClicked() { EventHelpViewerDisplay helpViewerEvent(getBrowserWindow(), "Tile_Tabs_Configuration"); EventManager::get()->sendEvent(helpViewerEvent.getPointer()); } /** * Constructor. * * @param tileTabsConfigurationDialog * The tile tabs configuration dialog. * @param rowColumnType * 'Row' or 'Column' * @param index * Index of the row/column * @param gridLayout * Gridlayout for widgets * @param parent * Parent QObject */ TileTabElementWidgets::TileTabElementWidgets(TileTabsConfigurationDialog* tileTabsConfigurationDialog, const EventTileTabsConfigurationModification::RowColumnType rowColumnType, const int32_t index, QGridLayout* gridLayout, QObject* parent) : QObject(parent), m_tileTabsConfigurationDialog(tileTabsConfigurationDialog), m_rowColumnType(rowColumnType), m_index(index), m_element(NULL) { m_indexLabel = new QLabel(QString::number(m_index + 1)); m_indexLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); const AString rowColText((rowColumnType == EventTileTabsConfigurationModification::RowColumnType::ROW) ? "Row" : "Column"); const AString contructionToolTip(WuQtUtilities::createWordWrappedToolTipText("Delete, Duplicate, or Move " + rowColText)); const AString contentToolTip(WuQtUtilities::createWordWrappedToolTipText("Content of the " + rowColText + ": Spacer (empty space for Annotations) " "or Tabs (Browser Tabs)")); const AString typeToolTip(WuQtUtilities::createWordWrappedToolTipText("Type of Stretching: Percent or Weight")); const AString stretchToolTip(WuQtUtilities::createWordWrappedToolTipText("Value of Stretching Percentage [0, 100] or Stretching Weight")); /* * Construction Tool Button */ QIcon constructionIcon; const bool constructionIconValid = WuQtUtilities::loadIcon(":/LayersPanel/construction.png", constructionIcon); m_constructionAction = WuQtUtilities::createAction("M", "Add/Move/Remove", this); if (constructionIconValid) { m_constructionAction->setIcon(constructionIcon); } m_constructionToolButton = new QToolButton(); QMenu* constructionMenu = createConstructionMenu(m_constructionToolButton); QObject::connect(constructionMenu, &QMenu::aboutToShow, this, &TileTabElementWidgets::constructionMenuAboutToShow); QObject::connect(constructionMenu, &QMenu::triggered, this, &TileTabElementWidgets::constructionMenuTriggered); m_constructionAction->setMenu(constructionMenu); m_constructionToolButton->setDefaultAction(m_constructionAction); m_constructionToolButton->setPopupMode(QToolButton::InstantPopup); m_constructionToolButton->setFixedWidth(m_constructionToolButton->sizeHint().width()); m_constructionToolButton->setToolTip(contructionToolTip); /* * Content type combo box */ m_contentTypeComboBox = new EnumComboBoxTemplate(this); m_contentTypeComboBox->setup(); QObject::connect(m_contentTypeComboBox, &EnumComboBoxTemplate::itemActivated, this, &TileTabElementWidgets::contentTypeActivated); m_contentTypeComboBox->getComboBox()->setFixedWidth(m_contentTypeComboBox->getComboBox()->sizeHint().width()); m_contentTypeComboBox->getComboBox()->setToolTip(contentToolTip); /* * Stretch type combo box */ m_stretchTypeComboBox = new EnumComboBoxTemplate(this); m_stretchTypeComboBox->setup(); QObject::connect(m_stretchTypeComboBox, &EnumComboBoxTemplate::itemActivated, this, &TileTabElementWidgets::stretchTypeActivated); m_stretchTypeComboBox->getComboBox()->setFixedWidth(m_stretchTypeComboBox->getComboBox()->sizeHint().width()); m_stretchTypeComboBox->getComboBox()->setToolTip(typeToolTip); /* * Stretch value spin box */ m_stretchValueSpinBox = new QDoubleSpinBox(); m_stretchValueSpinBox->setKeyboardTracking(false); m_stretchValueSpinBox->setRange(0.0, 1000.0); m_stretchValueSpinBox->setDecimals(2); m_stretchValueSpinBox->setSingleStep(0.1); QObject::connect(m_stretchValueSpinBox, static_cast(&QDoubleSpinBox::valueChanged), this, &TileTabElementWidgets::stretchValueChanged); m_stretchValueSpinBox->setFixedWidth(m_stretchValueSpinBox->sizeHint().width()); m_stretchValueSpinBox->setToolTip(stretchToolTip); m_gridLayoutGroup = new WuQGridLayoutGroup(gridLayout); const int32_t rowIndex(gridLayout->rowCount()); int32_t columnIndex(0); m_gridLayoutGroup->addWidget(m_indexLabel, rowIndex, columnIndex++, Qt::AlignRight); m_gridLayoutGroup->addWidget(m_constructionToolButton, rowIndex, columnIndex++); m_gridLayoutGroup->addWidget(m_contentTypeComboBox->getWidget(), rowIndex, columnIndex++); m_gridLayoutGroup->addWidget(m_stretchTypeComboBox->getWidget(), rowIndex, columnIndex++); m_gridLayoutGroup->addWidget(m_stretchValueSpinBox, rowIndex, columnIndex++); } /** * Destructor. */ TileTabElementWidgets::~TileTabElementWidgets() { } /** * @return The construction menu. * * @param toolButton * The parent toolbutton. */ QMenu* TileTabElementWidgets::createConstructionMenu(QToolButton* toolButton) { const AString deleteText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) ? "Delete this Column" : "Delete this Row"); const AString duplicateAfterText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) ? "Duplicate this Column to Right" : "Duplicate this Row Below"); const AString duplicateBeforeText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) ? "Duplicate this Column to Left" : "Duplicate this Row Above"); const AString insertSpacerAfterText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) ? "Insert Spacer Column to Right" : "Insert Spacer Row Below"); const AString insertSpacerBeforeText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) ? "Insert Spacer Column to Left" : "Insert Spacer Row Above"); const AString moveAfterText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) ? "Move this Column to Right" : "Move this Row Down"); const AString moveBeforeText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) ? "Move this Column to Left" : "Move this Row Up"); m_menuDeleteAction = new QAction(deleteText); m_menuDeleteAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::DELETE_IT)); m_menuDuplicateAfterAction = new QAction(duplicateAfterText); m_menuDuplicateAfterAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::DUPLICATE_AFTER)); m_menuDuplicateBeforeAction = new QAction(duplicateBeforeText); m_menuDuplicateBeforeAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::DUPLICATE_BEFORE)); m_insertSpacerAfterAction = new QAction(insertSpacerAfterText); m_insertSpacerAfterAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::INSERT_SPACER_AFTER)); m_insertSpacerBeforeAction = new QAction(insertSpacerBeforeText); m_insertSpacerBeforeAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::INSERT_SPACER_BEFORE)); m_menuMoveAfterAction = new QAction(moveAfterText); m_menuMoveAfterAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::MOVE_AFTER)); m_menuMoveBeforeAction = new QAction(moveBeforeText); m_menuMoveBeforeAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::MOVE_BEFORE)); QMenu* menu = new QMenu(toolButton); menu->addAction(m_menuDuplicateBeforeAction); menu->addAction(m_menuDuplicateAfterAction); menu->addSeparator(); menu->addAction(m_insertSpacerBeforeAction); menu->addAction(m_insertSpacerAfterAction); menu->addSeparator(); menu->addAction(m_menuMoveBeforeAction); menu->addAction(m_menuMoveAfterAction); menu->addSeparator(); menu->addAction(m_menuDeleteAction); return menu; } /** * Update with the given row/column element. */ void TileTabElementWidgets::updateContent(TileTabsGridRowColumnElement* element) { m_element = element; const bool showFlag(m_element != NULL); if (showFlag) { m_contentTypeComboBox->setSelectedItem(element->getContentType()); m_stretchTypeComboBox->setSelectedItem(element->getStretchType()); QSignalBlocker valueBlocker(m_stretchValueSpinBox); switch (m_element->getStretchType()) { case TileTabsGridRowColumnStretchTypeEnum::PERCENT: m_stretchValueSpinBox->setRange(0.0, 100.0); m_stretchValueSpinBox->setSingleStep(1.0); m_stretchValueSpinBox->setValue(m_element->getPercentStretch()); m_stretchValueSpinBox->setSuffix("%"); break; case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: m_stretchValueSpinBox->setRange(0.0, 1000.0); m_stretchValueSpinBox->setSingleStep(0.1); m_stretchValueSpinBox->setValue(m_element->getWeightStretch()); m_stretchValueSpinBox->setSuffix(""); break; } } m_gridLayoutGroup->setVisible(showFlag); } /** * Called when an item is selected from the construction menu * * @param action * Action that was selected. */ void TileTabElementWidgets::constructionMenuTriggered(QAction* action) { if (action != NULL) { const EventTileTabsConfigurationModification::Operation operation = static_cast(action->data().toInt()); /* * This switch is here so that it will cause a compilation error * if the operations are changed. */ switch (operation) { case EventTileTabsConfigurationModification::Operation::DELETE_IT: break; case EventTileTabsConfigurationModification::Operation::DUPLICATE_AFTER: break; case EventTileTabsConfigurationModification::Operation::DUPLICATE_BEFORE: break; case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_BEFORE: break; case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_AFTER: break; case EventTileTabsConfigurationModification::Operation::MOVE_AFTER: break; case EventTileTabsConfigurationModification::Operation::MOVE_BEFORE: break; } EventTileTabsConfigurationModification modification(m_tileTabsConfigurationDialog->getCustomTileTabsConfiguration(), m_index, m_rowColumnType, operation); emit modificationRequested(modification); } } /** * Called when construction menu is about to show. */ void TileTabElementWidgets::constructionMenuAboutToShow() { const TileTabsConfiguration* config = m_tileTabsConfigurationDialog->getCustomTileTabsConfiguration(); if (config != NULL) { int32_t numItems(-1); switch (m_rowColumnType) { case EventTileTabsConfigurationModification::RowColumnType::COLUMN: numItems = config->getNumberOfColumns(); break; case EventTileTabsConfigurationModification::RowColumnType::ROW: numItems = config->getNumberOfRows(); break; } m_menuDeleteAction->setEnabled(numItems > 1); m_menuDuplicateAfterAction->setEnabled(numItems >= 1); m_menuDuplicateBeforeAction->setEnabled(numItems >= 1); m_menuMoveAfterAction->setEnabled((numItems > 1) && (m_index < (numItems - 1))); m_menuMoveBeforeAction->setEnabled((numItems > 1) && (m_index > 0)); } } /** * Called when content type combo box changed. */ void TileTabElementWidgets::contentTypeActivated() { if (m_element != NULL) { m_element->setContentType(m_contentTypeComboBox->getSelectedItem()); emit itemChanged(); } } /** * Called when stretch type combo box changed. */ void TileTabElementWidgets::stretchTypeActivated() { if (m_element != NULL) { m_element->setStretchType(m_stretchTypeComboBox->getSelectedItem()); emit itemChanged(); } } /** * Called when stretch value changed. */ void TileTabElementWidgets::stretchValueChanged(double) { if (m_element != NULL) { switch (m_element->getStretchType()) { case TileTabsGridRowColumnStretchTypeEnum::PERCENT: m_element->setPercentStretch(m_stretchValueSpinBox->value()); break; case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: m_element->setWeightStretch(m_stretchValueSpinBox->value()); break; } emit itemChanged(); } } connectome-workbench-1.4.2/src/GuiQt/TileTabsConfigurationDialog.h000066400000000000000000000206711360521144700252110ustar00rootroot00000000000000#ifndef __TILE_TABS_CONFIGURATION_DIALOG_H__ #define __TILE_TABS_CONFIGURATION_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventListenerInterface.h" #include "EventTileTabsConfigurationModification.h" #include "TileTabsGridRowColumnContentTypeEnum.h" #include "TileTabsGridRowColumnStretchTypeEnum.h" #include "WuQDialogNonModal.h" class QCheckBox; class QDoubleSpinBox; class QGridLayout; class QLabel; class QLineEdit; class QListWidgetItem; class QPushButton; class QRadioButton; class QSpinBox; class QToolButton; namespace caret { class BrainBrowserWindow; class BrainBrowserWindowComboBox; class BrowserWindowContent; class CaretPreferences; class EnumComboBoxTemplate; class TileTabsConfiguration; class TileTabElementWidgets; class TileTabsGridRowColumnElement; class WuQGridLayoutGroup; class WuQListWidget; class TileTabsConfigurationDialog : public WuQDialogNonModal, public EventListenerInterface { Q_OBJECT public: TileTabsConfigurationDialog(BrainBrowserWindow* parentBrainBrowserWindow); virtual ~TileTabsConfigurationDialog(); void updateDialogWithSelectedTileTabsFromWindow(BrainBrowserWindow* brainBrowserWindow); void updateDialog(); virtual void receiveEvent(Event* event) override; private: TileTabsConfigurationDialog(const TileTabsConfigurationDialog&); TileTabsConfigurationDialog& operator=(const TileTabsConfigurationDialog&); public: // ADD_NEW_METHODS_HERE private slots: void browserWindowComboBoxValueChanged(BrainBrowserWindow* browserWindow); void newUserConfigurationButtonClicked(); void deleteUserConfigurationButtonClicked(); void renameUserConfigurationButtonClicked(); void configurationNumberOfRowsOrColumnsChanged(); void configurationStretchFactorWasChanged(); void replaceUserConfigurationPushButtonClicked(); void loadIntoActiveConfigurationPushButtonClicked(); void automaticCustomButtonClicked(QAbstractButton*); void tileTabsModificationRequested(EventTileTabsConfigurationModification& modification); void centeringCorrectionCheckBoxClicked(bool checked); protected: void focusGained(); virtual void helpButtonClicked() override; private: // ADD_NEW_MEMBERS_HERE QWidget* createCopyLoadPushButtonsWidget(); QWidget* createWorkbenchWindowWidget(); void selectTileTabConfigurationByUniqueID(const AString& uniqueID); TileTabsConfiguration* getAutomaticTileTabsConfiguration(); TileTabsConfiguration* getCustomTileTabsConfiguration(); TileTabsConfiguration* getSelectedUserTileTabsConfiguration(); QWidget* createUserConfigurationSelectionWidget(); QWidget* createActiveConfigurationWidget(); QWidget* createRowColumnStretchWidget(); QWidget* createCustomOptionsWidget(); void updateRowColumnStretchWidgets(TileTabsConfiguration* configuration); void addRowColumnStretchWidget(const EventTileTabsConfigurationModification::RowColumnType rowColumnType, QGridLayout* gridLayout, std::vector& elementVector); void updateStretchFactors(); void updateGraphicsWindow(); void updateCustomOptionsWidget(); void readConfigurationsFromPreferences(); BrainBrowserWindow* getBrowserWindow(); BrowserWindowContent* getBrowserWindowContent(); BrainBrowserWindowComboBox* m_browserWindowComboBox; QWidget* m_customConfigurationWidget; QWidget* m_customOptionsWidget; QRadioButton* m_automaticConfigurationRadioButton; QRadioButton* m_customConfigurationRadioButton; QPushButton* m_newConfigurationPushButton; QPushButton* m_deleteConfigurationPushButton; QPushButton* m_renameConfigurationPushButton; QPushButton* m_replacePushButton; QPushButton* m_loadPushButton; WuQListWidget* m_userConfigurationSelectionListWidget; QSpinBox* m_numberOfRowsSpinBox; QSpinBox* m_numberOfColumnsSpinBox; std::vector m_columnElements; std::vector m_rowElements; QGridLayout* m_rowElementsGridLayout = NULL; QGridLayout* m_columnElementsGridLayout = NULL; QCheckBox* m_centeringCorrectionCheckBox; /** Blocks reading of preferences since that may invalidate data pointers */ bool m_blockReadConfigurationsFromPreferences; /** * Keep a pointer to preferences but DO NOT delete it * since the preferences are managed by the session * manager. */ CaretPreferences* m_caretPreferences; friend class TileTabElementWidgets; static const int32_t s_maximumRowsColumns = 50; }; /** * Contains widgets for one row or column of stretching. */ class TileTabElementWidgets : public QObject { Q_OBJECT public: TileTabElementWidgets(TileTabsConfigurationDialog* tileTabsConfigurationDialog, const EventTileTabsConfigurationModification::RowColumnType rowColumnType, const int32_t index, QGridLayout* gridLayout, QObject* parent); virtual ~TileTabElementWidgets(); void updateContent(TileTabsGridRowColumnElement* element); signals: void itemChanged(); void modificationRequested(EventTileTabsConfigurationModification& modification); private slots: void constructionMenuAboutToShow(); void constructionMenuTriggered(QAction*); void contentTypeActivated(); void stretchTypeActivated(); void stretchValueChanged(double); private: QMenu* createConstructionMenu(QToolButton* toolButton); TileTabsConfigurationDialog* m_tileTabsConfigurationDialog; const EventTileTabsConfigurationModification::RowColumnType m_rowColumnType; const int32_t m_index; TileTabsGridRowColumnElement* m_element; QLabel* m_indexLabel; QAction* m_constructionAction; QToolButton* m_constructionToolButton; EnumComboBoxTemplate* m_contentTypeComboBox; EnumComboBoxTemplate* m_stretchTypeComboBox; QDoubleSpinBox* m_stretchValueSpinBox; QAction* m_menuDeleteAction; QAction* m_menuDuplicateAfterAction; QAction* m_menuDuplicateBeforeAction; QAction* m_insertSpacerAfterAction; QAction* m_insertSpacerBeforeAction; QAction* m_menuMoveAfterAction; QAction* m_menuMoveBeforeAction; WuQGridLayoutGroup* m_gridLayoutGroup; }; #ifdef __TILE_TABS_CONFIGURATION_DIALOG_DECLARE__ // const AString TileTabsConfigurationDialog::s_automaticConfigurationPrefix = "Automatic Configuration"; #endif // __TILE_TABS_CONFIGURATION_DIALOG_DECLARE__ } // namespace #endif //__TILE_TABS_CONFIGURATION_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/TileTabsConfigurationModifier.cxx000066400000000000000000000547551360521144700261350ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __TILE_TABS_CONFIGURATION_MODIFIER_DECLARE__ #include "TileTabsConfigurationModifier.h" #undef __TILE_TABS_CONFIGURATION_MODIFIER_DECLARE__ #include "BrainBrowserWindow.h" #include "BrainOpenGLViewportContent.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "EventBrowserTabNewClone.h" #include "EventBrowserTabDelete.h" #include "EventBrowserTabNew.h" #include "EventBrowserWindowTileTabOperation.h" #include "EventManager.h" #include "EventTileTabsConfigurationModification.h" #include "GuiManager.h" #include "SpacerTabContent.h" #include "TileTabsConfiguration.h" using namespace caret; static bool debugFlag = false; /** * \class caret::TileTabsConfigurationModifier * \brief Modifies a tile tabs configuration. * \ingroup GuiQt */ /** * Constructor. * * @param existingTabs * All tabs in the window. * @param modifyEvent * Event describing modification. */ TileTabsConfigurationModifier::TileTabsConfigurationModifier(const std::vector& existingTabs, EventTileTabsConfigurationModification* modifyEvent) : CaretObject(), m_existingTabs(existingTabs), m_modifyEvent(modifyEvent) { CaretAssert(modifyEvent); m_currentTileTabsConfiguration = modifyEvent->getTileTabsConfiguration(); CaretAssert(m_currentTileTabsConfiguration); } /** * Destructor. */ TileTabsConfigurationModifier::~TileTabsConfigurationModifier() { for (auto rc : m_rowColumns) { delete rc; } m_rowColumns.clear(); } /** * Get a description of this object's content. * @return String describing this object's content. */ AString TileTabsConfigurationModifier::toString() const { AString s; for (const auto rc : m_rowColumns) { if ( ! s.isEmpty()) { s.append("\n"); } s.append(rc->toString()); } return s; } /** * Run to perform the operation. * * @param errorMessageOut * Contains error information if operation fails. * @return * True if successful, else false. */ bool TileTabsConfigurationModifier::run(AString& errorMessageOut) { errorMessageOut.clear(); loadRowColumnsFromTileTabsConfiguration(); if (debugFlag) { std::cout << "Loaded: " << toString() << std::endl << std::flush; } bool validFlag = performModification(errorMessageOut); if (debugFlag) { std::cout << "After Modification: " << toString() << std::endl << std::endl << std::flush; } if (validFlag) { validFlag = loadRowColumnsIntoTileTabsConfiguration(errorMessageOut); } return validFlag; } /** * Load the rows or columns from the Tile Tabs Configuration */ void TileTabsConfigurationModifier::loadRowColumnsFromTileTabsConfiguration() { const int32_t numRows = m_currentTileTabsConfiguration->getNumberOfRows(); const int32_t numColumns = m_currentTileTabsConfiguration->getNumberOfColumns(); switch (m_modifyEvent->getRowColumnType()) { case EventTileTabsConfigurationModification::RowColumnType::COLUMN: for (int32_t jCol = 0; jCol < numColumns; jCol++) { m_rowColumns.push_back(new RowColumnContent(m_existingTabs, m_modifyEvent->getTileTabsConfiguration(), jCol, false)); } break; case EventTileTabsConfigurationModification::RowColumnType::ROW: for (int32_t iRow = 0; iRow < numRows; iRow++) { m_rowColumns.push_back(new RowColumnContent(m_existingTabs, m_modifyEvent->getTileTabsConfiguration(), iRow, true)); } break; } } /** * Perform the modification. * * @param errorMessageOut * Contains error information if operation fails. * @return * True if successful, else false. */ bool TileTabsConfigurationModifier::performModification(AString& errorMessageOut) { const int32_t rowColumnIndex = m_modifyEvent->getRowColumnIndex(); const int32_t numRowColumns = static_cast(m_rowColumns.size()); switch (m_modifyEvent->getOperation()) { case EventTileTabsConfigurationModification::Operation::DELETE_IT: if (numRowColumns <= 1) { errorMessageOut = "Cannot delete ROWCOL when there is only one ROWCOL"; } else if ((rowColumnIndex >= 0) && (rowColumnIndex < numRowColumns)) { CaretAssertVectorIndex(m_rowColumns, rowColumnIndex); RowColumnContent* deleteRowColumn = m_rowColumns[rowColumnIndex]; CaretAssert(deleteRowColumn); m_rowColumns.erase(m_rowColumns.begin() + rowColumnIndex); CaretAssert(std::find(m_rowColumns.begin(), m_rowColumns.end(), deleteRowColumn) == m_rowColumns.end()); for (auto t : deleteRowColumn->m_tabElements) { if (t->m_browserTabContent != NULL) { m_browserTabsToDelete.push_back(t->m_browserTabContent); } } delete deleteRowColumn; } else { errorMessageOut = "Invalid ROWCOL index=RCINDEX when deleting"; } break; case EventTileTabsConfigurationModification::Operation::DUPLICATE_AFTER: if ((rowColumnIndex >= 0) && (rowColumnIndex < numRowColumns)) { RowColumnContent* rowColumnCopy = m_rowColumns[rowColumnIndex]->clone(errorMessageOut); if (rowColumnCopy != NULL) { const int32_t insertOffset = (rowColumnIndex + 1); m_rowColumns.insert(m_rowColumns.begin() + insertOffset, rowColumnCopy); } } else { errorMessageOut = "Invalid ROWCOL index=RCINDEX when duplicating"; } break; case EventTileTabsConfigurationModification::Operation::DUPLICATE_BEFORE: if ((rowColumnIndex >= 0) && (rowColumnIndex < numRowColumns)) { RowColumnContent* rowColumnCopy = m_rowColumns[rowColumnIndex]->clone(errorMessageOut); if (rowColumnCopy != NULL) { const int32_t insertOffset = rowColumnIndex; m_rowColumns.insert(m_rowColumns.begin() + insertOffset, rowColumnCopy); } } else { errorMessageOut = "Invalid ROWCOL index=RCINDEX when duplicating"; } break; case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_AFTER: case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_BEFORE: if ((rowColumnIndex >= 0) && (rowColumnIndex < numRowColumns)) { CaretAssertVectorIndex(m_rowColumns, 0); const int32_t numberOfElements = m_rowColumns[0]->m_tabElements.size(); RowColumnContent* rowColumnSpacer = RowColumnContent::newInstanceContainingSpacers(numberOfElements); if (rowColumnSpacer != NULL) { int32_t insertOffset = rowColumnIndex; if (m_modifyEvent->getOperation() == EventTileTabsConfigurationModification::Operation::INSERT_SPACER_AFTER) { insertOffset++; } m_rowColumns.insert(m_rowColumns.begin() + insertOffset, rowColumnSpacer); } } else { errorMessageOut = "Invalid ROWCOL index=RCINDEX when insert spacer"; } break; case EventTileTabsConfigurationModification::Operation::MOVE_AFTER: if (numRowColumns <= 1) { errorMessageOut = "Cannot move ROWCOL when there is only one ROWCOL"; } else if (rowColumnIndex == (numRowColumns - 1)) { errorMessageOut = "Cannot move last ROWCOL after itself"; } else if ((rowColumnIndex >= 0) && (rowColumnIndex < (numRowColumns - 1))) { CaretAssertVectorIndex(m_rowColumns, rowColumnIndex); CaretAssertVectorIndex(m_rowColumns, rowColumnIndex + 1); std::swap(m_rowColumns[rowColumnIndex], m_rowColumns[rowColumnIndex + 1]); } else { errorMessageOut = "Invalid ROWCOL index=RCINDEX when moving"; } break; case EventTileTabsConfigurationModification::Operation::MOVE_BEFORE: if (numRowColumns <= 1) { errorMessageOut = "Cannot move ROWCOL when there is only one ROWCOL"; } else if (rowColumnIndex == 0) { errorMessageOut = "Cannot move last ROWCOL before itself"; } else if ((rowColumnIndex >= 1) && (rowColumnIndex < numRowColumns)) { CaretAssertVectorIndex(m_rowColumns, rowColumnIndex); CaretAssertVectorIndex(m_rowColumns, rowColumnIndex - 1); std::swap(m_rowColumns[rowColumnIndex], m_rowColumns[rowColumnIndex - 1]); } else { errorMessageOut = "Invalid ROWCOL index=RCINDEX when moving"; } break; } if ( ! errorMessageOut.isEmpty()) { AString nameText; switch (m_modifyEvent->getRowColumnType()) { case EventTileTabsConfigurationModification::RowColumnType::COLUMN: nameText = " Column "; break; case EventTileTabsConfigurationModification::RowColumnType::ROW: nameText = " Row "; break; } /* * "substite names" */ errorMessageOut = errorMessageOut.replace("ROWCOL", nameText); errorMessageOut = errorMessageOut.replace("RCINDEX", AString::number(rowColumnIndex + 1)); } const bool validFlag = errorMessageOut.isEmpty(); return validFlag; } /** * Load the modified rows/columns into the tile tabs configuration current in the browser window * * @param errorMessageOut * Contains error information if operation fails. * @return * True if successful, else false. */ bool TileTabsConfigurationModifier::loadRowColumnsIntoTileTabsConfiguration(AString& errorMessageOut) { TileTabsConfiguration newConfiguration(*m_currentTileTabsConfiguration); std::vector browserTabs; switch (m_modifyEvent->getRowColumnType()) { case EventTileTabsConfigurationModification::RowColumnType::COLUMN: { const int32_t numRows = static_cast(m_rowColumns[0]->m_tabElements.size()); CaretAssert(numRows == m_currentTileTabsConfiguration->getNumberOfRows()); const int32_t numColumns = static_cast(m_rowColumns.size()); newConfiguration.setNumberOfRows(numRows); newConfiguration.setNumberOfColumns(numColumns); for (int32_t iRow = 0; iRow < numRows; iRow++) { for (int32_t jCol = 0; jCol < numColumns; jCol++) { RowColumnContent* columnContent = m_rowColumns[jCol]; CaretAssertVectorIndex(columnContent->m_tabElements, iRow); BrowserTabContent* btc = columnContent->m_tabElements[iRow]->m_browserTabContent; if (btc != NULL) { browserTabs.push_back(btc); } } } for (int32_t jCol = 0; jCol < numColumns; jCol++) { TileTabsGridRowColumnElement* rce = newConfiguration.getColumn(jCol); CaretAssertVectorIndex(m_rowColumns, jCol); CaretAssert(m_rowColumns[jCol]->m_stretching); *rce = *m_rowColumns[jCol]->m_stretching; } } break; case EventTileTabsConfigurationModification::RowColumnType::ROW: { const int32_t numRows = static_cast(m_rowColumns.size()); const int32_t numColumns = static_cast(m_rowColumns[0]->m_tabElements.size()); CaretAssert(numColumns == m_currentTileTabsConfiguration->getNumberOfColumns()); newConfiguration.setNumberOfRows(numRows); newConfiguration.setNumberOfColumns(numColumns); for (int32_t iRow = 0; iRow < numRows; iRow++) { CaretAssertVectorIndex(m_rowColumns, iRow); RowColumnContent* rowContent = m_rowColumns[iRow]; for (int32_t jCol = 0; jCol < numColumns; jCol++) { CaretAssertVectorIndex(rowContent->m_tabElements, jCol); BrowserTabContent* btc = rowContent->m_tabElements[jCol]->m_browserTabContent; if (btc != NULL) { browserTabs.push_back(btc); } } } for (int32_t iRow = 0; iRow < numRows; iRow++) { TileTabsGridRowColumnElement* rce = newConfiguration.getRow(iRow); CaretAssertVectorIndex(m_rowColumns, iRow); CaretAssert(m_rowColumns[iRow]->m_stretching); *rce = *m_rowColumns[iRow]->m_stretching; } } break; } /* * Copy new tile tabs configuration into the current configuration */ *m_currentTileTabsConfiguration = newConfiguration; /* * Update tabs in the window's toolbar */ QWidget* parentWindow(GuiManager::get()->getBrowserWindowByWindowIndex(m_modifyEvent->getWindowIndex())); const int32_t invalidTabIndex(-1); EventBrowserWindowTileTabOperation updateTabsEvent(EventBrowserWindowTileTabOperation::OPERATION_REPLACE_TABS, parentWindow, m_modifyEvent->getWindowIndex(), invalidTabIndex, browserTabs); EventManager::get()->sendEvent(updateTabsEvent.getPointer()); if (updateTabsEvent.isError()) { errorMessageOut.appendWithNewLine(updateTabsEvent.getErrorMessage()); } if ( ! m_browserTabsToDelete.empty()) { for (auto btc : m_browserTabsToDelete) { EventBrowserTabDelete deleteEvent(btc, btc->getTabNumber()); EventManager::get()->sendEvent(deleteEvent.getPointer()); if (deleteEvent.isError()) { errorMessageOut.appendWithNewLine(deleteEvent.getErrorMessage()); } } m_browserTabsToDelete.clear(); } if (errorMessageOut.isEmpty()) { return true; } return false; } /* * Constructor for element in the row column matrix. * * @param rowIndex * The row index * @param columnIndex * The column index * @param browserTabContent * Browser tab content at (rowIndex, columnIndex) in the current * Tile Tabs Configuration */ TileTabsConfigurationModifier::Element::Element(const int32_t rowIndex, const int32_t columnIndex, BrowserTabContent* browserTabContent) : m_targetRowIndex(rowIndex), m_targetColumnIndex(columnIndex), m_sourceRowIndex(rowIndex), m_sourceColumnIndex(columnIndex), m_browserTabContent(browserTabContent) { } /** * @return String representation of object. */ AString TileTabsConfigurationModifier::Element::toString() const { AString s("(row=%1, column=%2)"); s = s.arg(m_sourceRowIndex).arg(m_sourceColumnIndex); return s; } /* * Constructor for content of a row/column element that * contains the tabs and stretching for one row or one column * * @param existingTabs * Existing browser tabs. * @param tileTabsConfiguration * The current tile tabs configuration in the browser window. * @param rowColumnIndex * Index of the row or column related to modification. * @param rowFlag * True if rows are being operated upon, false if operating on columns */ TileTabsConfigurationModifier::RowColumnContent::RowColumnContent(const std::vector& existingTabs, TileTabsConfiguration* tileTabsConfiguration, const int32_t rowColumnIndex, const bool rowFlag) { const int32_t numRows = tileTabsConfiguration->getNumberOfRows(); const int32_t numColumns = tileTabsConfiguration->getNumberOfColumns(); const int32_t numberOfTabs =static_cast(existingTabs.size()); if (rowFlag) { for (int32_t jCol = 0; jCol < numColumns; jCol++) { BrowserTabContent* browserTabContent(NULL); const int32_t tabIndex = (rowColumnIndex * numColumns) + jCol; if (tabIndex < numberOfTabs) { CaretAssertVectorIndex(existingTabs, tabIndex); browserTabContent = existingTabs[tabIndex]->getBrowserTabContent(); } m_tabElements.push_back(new Element(rowColumnIndex, jCol, browserTabContent)); } m_stretching = new TileTabsGridRowColumnElement(*tileTabsConfiguration->getRow(rowColumnIndex)); } else { for (int32_t iRow = 0; iRow < numRows; iRow++) { BrowserTabContent* browserTabContent(NULL); const int32_t tabIndex = (iRow * numColumns) + rowColumnIndex; if (tabIndex < numberOfTabs) { CaretAssertVectorIndex(existingTabs, tabIndex); browserTabContent = existingTabs[tabIndex]->getBrowserTabContent(); } m_tabElements.push_back(new Element(iRow, rowColumnIndex, browserTabContent)); } m_stretching = new TileTabsGridRowColumnElement(*tileTabsConfiguration->getColumn(rowColumnIndex)); } } /* * Constructor that creates the given number of elements. * * @param numberOfElements * Number of elements for row/column. */ TileTabsConfigurationModifier::RowColumnContent::RowColumnContent(const int32_t numberOfElements) { for (int32_t i = 0; i < numberOfElements; i++) { m_tabElements.push_back(new Element(i, i, NULL)); } m_stretching = new TileTabsGridRowColumnElement(); } /** * @return New instance containing the given number of elements setup as spacers. * * @param numberOfElements * Number of elements for row/column. */ TileTabsConfigurationModifier::RowColumnContent* TileTabsConfigurationModifier::RowColumnContent::newInstanceContainingSpacers(const int32_t numberOfElements) { RowColumnContent* content = new RowColumnContent(numberOfElements); content->m_stretching->setContentType(TileTabsGridRowColumnContentTypeEnum::SPACE); content->m_stretching->setStretchType(TileTabsGridRowColumnStretchTypeEnum::WEIGHT); content->m_stretching->setWeightStretch(1.0); return content; } /** * Destructor. */ TileTabsConfigurationModifier::RowColumnContent::~RowColumnContent() { for (auto te : m_tabElements) { delete te; } m_tabElements.clear(); delete m_stretching; m_stretching = NULL; } /** * Copy constructor. * * @param obj * Instance that is copied. */ TileTabsConfigurationModifier::RowColumnContent::RowColumnContent(const RowColumnContent& obj) : CaretObject(obj) { for (auto te : obj.m_tabElements) { m_tabElements.push_back(new Element(*te)); } m_stretching = new TileTabsGridRowColumnElement(*obj.m_stretching); } /** * @return String representation of object. */ AString TileTabsConfigurationModifier::RowColumnContent::toString() const { AString s; for (const auto te : m_tabElements) { s += (" " + te->toString()); } return s; } /** * Clone this Row/column content instance. * * @param errorMessageOut * Output with error message. * @return * True if successful, else false */ TileTabsConfigurationModifier::RowColumnContent* TileTabsConfigurationModifier::RowColumnContent::clone(AString& errorMessageOut) const { RowColumnContent* cloned = new RowColumnContent(*this); CaretAssert(cloned); for (auto te : cloned->m_tabElements) { if (te->m_browserTabContent != NULL) { EventBrowserTabNewClone cloneTabEvent(te->m_browserTabContent->getTabNumber()); EventManager::get()->sendEvent(cloneTabEvent.getPointer()); if (cloneTabEvent.isError()) { errorMessageOut.appendWithNewLine(cloneTabEvent.getErrorMessage()); te->m_browserTabContent = NULL; } else { te->m_browserTabContent = cloneTabEvent.getNewBrowserTab(); } } } return cloned; } connectome-workbench-1.4.2/src/GuiQt/TileTabsConfigurationModifier.h000066400000000000000000000107161360521144700255470ustar00rootroot00000000000000#ifndef __TILE_TABS_CONFIGURATION_MODIFIER_H__ #define __TILE_TABS_CONFIGURATION_MODIFIER_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretObject.h" namespace caret { class BrainOpenGLViewportContent; class BrowserTabContent; class EventTileTabsConfigurationModification; class SpacerTabContent; class TileTabsConfiguration; class TileTabsGridRowColumnElement; class TileTabsConfigurationModifier : public CaretObject { public: TileTabsConfigurationModifier(const std::vector& existingTabs, EventTileTabsConfigurationModification* modifyEvent); virtual ~TileTabsConfigurationModifier(); TileTabsConfigurationModifier(const TileTabsConfigurationModifier&) = delete; TileTabsConfigurationModifier& operator=(const TileTabsConfigurationModifier&) = delete; bool run(AString& errorMessageOut); // ADD_NEW_METHODS_HERE virtual AString toString() const; class Element : public CaretObject { public: Element(const int32_t rowIndex, const int32_t columnIndex, BrowserTabContent* browserTabContent); AString toString() const override; int32_t m_targetRowIndex; int32_t m_targetColumnIndex; int32_t m_sourceRowIndex; int32_t m_sourceColumnIndex; BrowserTabContent* m_browserTabContent; }; /** * Contains the tabs and stretching for one row or one column */ class RowColumnContent : public CaretObject { public: RowColumnContent(const std::vector& existingTabs, TileTabsConfiguration* tileTabsConfiguration, const int32_t rowColumnIndex, const bool rowFlag); RowColumnContent(const RowColumnContent& obj); static RowColumnContent* newInstanceContainingSpacers(const int32_t numberOfElements); ~RowColumnContent(); RowColumnContent* clone(AString& errorMessageOut) const; AString toString() const override; std::vector m_tabElements; TileTabsGridRowColumnElement* m_stretching; private: RowColumnContent(const int32_t numberOfElements); }; private: void loadRowColumnsFromTileTabsConfiguration(); bool loadRowColumnsIntoTileTabsConfiguration(AString& errorMessageOut); bool performModification(AString& errorMessageOut); const std::vector& m_existingTabs; EventTileTabsConfigurationModification* m_modifyEvent; std::vector m_rowColumns; std::vector m_browserTabsToDelete; /** * This is the current tile tabs configuration in the window so DO NOT delete it */ TileTabsConfiguration* m_currentTileTabsConfiguration = NULL; // ADD_NEW_MEMBERS_HERE }; #ifdef __TILE_TABS_CONFIGURATION_MODIFIER_DECLARE__ // #endif // __TILE_TABS_CONFIGURATION_MODIFIER_DECLARE__ } // namespace #endif //__TILE_TABS_CONFIGURATION_MODIFIER_H__ connectome-workbench-1.4.2/src/GuiQt/UserInputModeAbstract.cxx000066400000000000000000000133341360521144700244320ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __USER_INPUT_MODE_ABSTRACT_DECLARE__ #include "UserInputModeAbstract.h" #undef __USER_INPUT_MODE_ABSTRACT_DECLARE__ #include #include #include "CaretAssert.h" #include "MouseEvent.h" using namespace caret; /** * \class caret::UserInputModeAbstract * \brief Abstract class for processing user input events * \ingroup GuiQt * * Classes implementing this interface receive * user input events from the OpenGL graphics * region of a BrowserWindow containing brain * models. */ /** * Constructor. */ UserInputModeAbstract::UserInputModeAbstract(const UserInputModeEnum::Enum inputMode) : CaretObject(), m_userInputMode(inputMode), m_widgetForToolBar(NULL), m_mousePositionValid(false) { m_mousePositionEvent.grabNew(new MouseEvent(NULL, NULL, -1, 0, 0, 0, 0, 0, 0, false)); } /** * Destructor. */ UserInputModeAbstract::~UserInputModeAbstract() { /* * If the widget does not have a parent, then it is not * displayed (owned by another QWidget class) and must * be destroyed to avoid a memory leak. */ if (m_widgetForToolBar != NULL) { if (m_widgetForToolBar->parent() == 0) { delete m_widgetForToolBar; } m_widgetForToolBar = NULL; } } /** * @return The input mode enumerated type. */ UserInputModeEnum::Enum UserInputModeAbstract::getUserInputMode() const { return m_userInputMode; } /** * @return A widget for display at the bottom of the * Browser Window Toolbar when this mode is active. * If no user-interface controls are needed, this * method will return NULL. */ QWidget* UserInputModeAbstract::getWidgetForToolBar() { return m_widgetForToolBar; } /** * Set the widget that is displayed in the toolbar when * the user input mode is active. * * @param widgetForToolBar * Widget that is displayed in toolbar, may be NULL indicating * no widget. */ void UserInputModeAbstract::setWidgetForToolBar(QWidget* widgetForToolBar) { m_widgetForToolBar = widgetForToolBar; } /** * Process a selection that was made from the browser window's edit menu. * Intended for override by sub-classes. * * @param editMenuItem * Item that was selected from the edit menu. */ void UserInputModeAbstract::processEditMenuItemSelection(const BrainBrowserWindowEditMenuItemEnum::Enum /*editMenuItem*/) { } /** * Get the menu items that should be enabled for the current user input processor. * Intended for override by sub-classes. * Unless this method is overridden, all items on Edit menu are disabled. * * @param enabledEditMenuItemsOut * Upon exit contains edit menu items that should be enabled. * @param redoMenuItemSuffixTextOut * If the redo menu is enabled, the contents of string becomes * the suffix for the 'Redo' menu item. * @param undoMenuItemSuffixTextOut * If the undo menu is enabled, the contents of string becomes * the suffix for the 'Undo' menu item. * @param pasteTextOut * If not empty, this text is shown for the PASTE menu item * @param pasteSpecialTextOut * If not empty, this text is shown for the PASTE_SPECIAL menu item */ void UserInputModeAbstract::getEnabledEditMenuItems(std::vector& enabledEditMenuItemsOut, AString& redoMenuItemSuffixTextOut, AString& undoMenuItemSuffixTextOut, AString& pasteTextOut, AString& pasteSpecialTextOut) { enabledEditMenuItemsOut.clear(); redoMenuItemSuffixTextOut = ""; undoMenuItemSuffixTextOut = ""; pasteTextOut = ""; pasteSpecialTextOut = ""; } /** * Get information about the current mouse location. * * @return Pointer to a MouseEvent or NULL if the * mouse location is invalid. */ const MouseEvent* UserInputModeAbstract::getMousePosition() const { if (m_mousePositionValid) { return m_mousePositionEvent; } return NULL; } /** * Set the position of the mouse. * * @param mouseEvent * Information about the current mouse location. * @param valid * True if the mouse position is valid, else false. */ void UserInputModeAbstract::setMousePosition(const MouseEvent* mouseEvent, const bool valid) { m_mousePositionValid = valid; if (m_mousePositionValid) { CaretAssert(mouseEvent); *m_mousePositionEvent = *mouseEvent; } } connectome-workbench-1.4.2/src/GuiQt/UserInputModeAbstract.h000066400000000000000000000174521360521144700240640ustar00rootroot00000000000000#ifndef __USER_INPUT_MODE_ABSTRACT_H__ #define __USER_INPUT_MODE_ABSTRACT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "BrainBrowserWindowEditMenuItemEnum.h" #include "CaretObject.h" #include "CaretPointer.h" #include "CursorEnum.h" #include "UserInputModeEnum.h" class QPoint; class QWidget; namespace caret { class BrainOpenGLViewportContent; class BrainOpenGLWidget; class KeyEvent; class MouseEvent; class UserInputModeAbstract : public CaretObject { public: UserInputModeAbstract(const UserInputModeEnum::Enum inputMode); virtual ~UserInputModeAbstract(); /** * @return The input mode enumerated type. */ UserInputModeEnum::Enum getUserInputMode() const; /** * Called when 'this' user input receiver is set * to receive events. */ virtual void initialize() = 0; /** * Called when 'this' user input receiver is no * longer set to receive events. */ virtual void finish() = 0; /** * Called to update the input receiver for various events. */ virtual void update() = 0; QWidget* getWidgetForToolBar(); /** * @return The cursor for display in the OpenGL widget. */ virtual CursorEnum::Enum getCursor() const = 0; /** * Process a key press event * * @param keyEvent * Key event information. * @return * True if the input process recognized the key event * and the key event SHOULD NOT be propagated to parent * widgets */ virtual bool keyPressEvent(const KeyEvent& /*keyEvent*/) { return false; } /** * Process a mouse left double-click event. * * @param mouseEvent * Mouse event information. */ virtual void mouseLeftDoubleClick(const MouseEvent& /*mouseEvent*/) { } /** * Process a mouse left press event. * * @param mouseEvent * Mouse event information. */ virtual void mouseLeftPress(const MouseEvent& /*mouseEvent*/) { } /** * Process a mouse left release event. * * @param mouseEvent * Mouse event information. */ virtual void mouseLeftRelease(const MouseEvent& /*mouseEvent*/) { } /** * Process a mouse left click event. * * @param mouseEvent * Mouse event information. */ virtual void mouseLeftClick(const MouseEvent& /*mouseEvent*/) { } /** * Process a mouse left click with shift key down event. * * @param mouseEvent * Mouse event information. */ virtual void mouseLeftClickWithShift(const MouseEvent& /*mouseEvent*/) { } /** * Process a mouse left click with ctrl and shift keys down event. * * @param mouseEvent * Mouse event information. */ virtual void mouseLeftClickWithCtrlShift(const MouseEvent& /*mouseEvent*/) { } /** * Process a mouse left drag with no keys down event. * * @param mouseEvent * Mouse event information. */ virtual void mouseLeftDrag(const MouseEvent& /*mouseEvent*/) { } /** * Process a mouse left drag with only the alt key down event. * * @param mouseEvent * Mouse event information. */ virtual void mouseLeftDragWithAlt(const MouseEvent& /*mouseEvent*/) { } /** * Process a mouse left drag with ctrl key down event. * * @param mouseEvent * Mouse event information. */ virtual void mouseLeftDragWithCtrl(const MouseEvent& /*mouseEvent*/) { } /** * Process a mouse left drag with ctrl and shift keys down event. * * @param mouseEvent * Mouse event information. */ virtual void mouseLeftDragWithCtrlShift(const MouseEvent& /*mouseEvent*/) { } /** * Process a mouse left drag with shift key down event. * * @param mouseEvent * Mouse event information. */ virtual void mouseLeftDragWithShift(const MouseEvent& /*mouseEvent*/) { } /** * Process a mouse move with no buttons or keys down * * @param mouseEvent * Mouse event information. */ virtual void mouseMove(const MouseEvent& /*mouseEvent*/) { } /** * Process a mouse move with no buttons and shift key down * * @param mouseEvent * Mouse event information. */ virtual void mouseMoveWithShift(const MouseEvent& /*mouseEvent*/) { } /** * Show a context menu (pop-up menu at mouse location) * * @param mouseEvent * Mouse event information. * @param menuPosition * Point at which menu is displayed (passed to QMenu::exec()) * @param openGLWidget * OpenGL widget in which context menu is requested */ virtual void showContextMenu(const MouseEvent& /*mouseEvent*/, const QPoint& /* menuPosition */, BrainOpenGLWidget* /* openGLWidget */) { } virtual void processEditMenuItemSelection(const BrainBrowserWindowEditMenuItemEnum::Enum editMenuItem); virtual void getEnabledEditMenuItems(std::vector& enabledEditMenuItemsOut, AString& redoMenuItemSuffixTextOut, AString& undoMenuItemSuffixTextOut, AString& pasteTextOut, AString& pasteSpecialTextOut); const MouseEvent* getMousePosition() const; void setMousePosition(const MouseEvent* mouseEvent, const bool valid); protected: void setWidgetForToolBar(QWidget* widgetForToolBar); private: UserInputModeAbstract(const UserInputModeAbstract&); UserInputModeAbstract& operator=(const UserInputModeAbstract&); const UserInputModeEnum::Enum m_userInputMode; QWidget* m_widgetForToolBar; bool m_mousePositionValid; CaretPointer m_mousePositionEvent; // ADD_NEW_MEMBERS_HERE }; #ifdef __USER_INPUT_MODE_ABSTRACT_DECLARE__ // #endif // __USER_INPUT_MODE_ABSTRACT_DECLARE__ } // namespace #endif //__USER_INPUT_MODE_ABSTRACT_H__ connectome-workbench-1.4.2/src/GuiQt/UserInputModeAnnotations.cxx000066400000000000000000002220521360521144700251630ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __USER_INPUT_MODE_ANNOTATIONS_DECLARE__ #include "UserInputModeAnnotations.h" #undef __USER_INPUT_MODE_ANNOTATIONS_DECLARE__ #include #include "AnnotationChangeCoordinateDialog.h" #include "AnnotationCreateDialog.h" #include "AnnotationColorBar.h" #include "AnnotationCoordinate.h" #include "AnnotationCoordinateInformation.h" #include "AnnotationFile.h" #include "AnnotationManager.h" #include "AnnotationOneDimensionalShape.h" #include "AnnotationPasteDialog.h" #include "AnnotationRedoUndoCommand.h" #include "AnnotationSpatialModification.h" #include "AnnotationText.h" #include "AnnotationTextEditorDialog.h" #include "AnnotationTwoDimensionalShape.h" #include "Brain.h" #include "BrainOpenGLViewportContent.h" #include "BrainOpenGLWidget.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretUndoStack.h" #include "CursorEnum.h" #include "CaretPreferences.h" #include "DisplayPropertiesAnnotation.h" #include "EventAnnotationCreateNewType.h" #include "EventAnnotationGetDrawnInWindow.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventIdentificationRequest.h" #include "EventUserInterfaceUpdate.h" #include "EventManager.h" #include "GuiManager.h" #include "IdentificationManager.h" #include "KeyEvent.h" #include "ModelSurfaceMontage.h" #include "MouseEvent.h" #include "SelectionItemAnnotation.h" #include "SelectionManager.h" #include "SelectionItemSurfaceNode.h" #include "SelectionItemVoxel.h" #include "SessionManager.h" #include "Surface.h" #include "SurfaceMontageViewport.h" #include "UserInputModeAnnotationsContextMenu.h" #include "UserInputModeAnnotationsWidget.h" #include "WuQMessageBox.h" using namespace caret; /** * \class caret::UserInputModeAnnotations * \brief Input mode processor for Annotations. * \ingroup GuiQt */ /** * Constructor. */ UserInputModeAnnotations::UserInputModeAnnotations(const int32_t windowIndex) : UserInputModeView(UserInputModeEnum::ANNOTATIONS), m_browserWindowIndex(windowIndex), m_annotationUnderMouse(NULL), m_annotationBeingDragged(NULL) { m_allowMultipleSelectionModeFlag = true; m_mode = MODE_SELECT; m_annotationUnderMouseSizeHandleType = AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE; m_modeNewAnnotationFileSpaceAndType.grabNew(new NewAnnotationFileSpaceAndType(NULL, AnnotationCoordinateSpaceEnum::VIEWPORT, AnnotationTypeEnum::LINE)); m_newAnnotationCreatingWithMouseDrag.grabNew(NULL); m_annotationToolsWidget = new UserInputModeAnnotationsWidget(this, m_browserWindowIndex); setWidgetForToolBar(m_annotationToolsWidget); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_CREATE_NEW_TYPE); } /** * Destructor. */ UserInputModeAnnotations::~UserInputModeAnnotations() { EventManager::get()->removeAllEventsFromListener(this); } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void UserInputModeAnnotations::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_CREATE_NEW_TYPE) { EventAnnotationCreateNewType* annotationEvent = dynamic_cast(event); CaretAssert(annotationEvent); AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); annotationManager->deselectAllAnnotationsForEditing(m_browserWindowIndex); resetAnnotationUnderMouse(); m_modeNewAnnotationFileSpaceAndType.grabNew(new NewAnnotationFileSpaceAndType(annotationEvent->getAnnotationFile(), annotationEvent->getAnnotationSpace(), annotationEvent->getAnnotationType())); setMode(MODE_NEW_WITH_CLICK); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } /** * Called when 'this' user input receiver is set * to receive events. */ void UserInputModeAnnotations::initialize() { m_mode = MODE_SELECT; DisplayPropertiesAnnotation* dpa = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotation(); dpa->setDisplayAnnotations(true); resetAnnotationUnderMouse(); } /** * Called when 'this' user input receiver is no * longer set to receive events. */ void UserInputModeAnnotations::finish() { m_mode = MODE_SELECT; resetAnnotationUnderMouse(); } void UserInputModeAnnotations::resetAnnotationUnderMouse() { m_annotationUnderMouse = NULL; m_annotationUnderMouseSizeHandleType = AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE; m_annotationBeingDragged = NULL; m_annotationBeingDraggedHandleType = AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE; } /** * Called to update the input receiver for various events. */ void UserInputModeAnnotations::update() { } /** * Get a description of this object's content. * @return String describing this object's content. */ AString UserInputModeAnnotations::toString() const { return "UserInputModeBorders"; } /** * @return the mode. */ UserInputModeAnnotations::Mode UserInputModeAnnotations::getMode() const { return m_mode; } /** * Set the mode. * @param mode * New value for mode. */ void UserInputModeAnnotations::setMode(const Mode mode) { if (m_mode != mode) { m_mode = mode; } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** * @return The cursor for display in the OpenGL widget. */ CursorEnum::Enum UserInputModeAnnotations::getCursor() const { CursorEnum::Enum cursor = CursorEnum::CURSOR_DEFAULT; switch (m_mode) { case MODE_NEW_WITH_CLICK: cursor = CursorEnum::CURSOR_CROSS; break; case MODE_NEW_WITH_DRAG: cursor = CursorEnum::CURSOR_CROSS; break; case MODE_PASTE: cursor = CursorEnum::CURSOR_CROSS; break; case MODE_PASTE_SPECIAL: cursor = CursorEnum::CURSOR_CROSS; break; case MODE_SELECT: if (m_annotationUnderMouse != NULL) { cursor = CursorEnum::CURSOR_FOUR_ARROWS; switch (m_annotationUnderMouseSizeHandleType) { case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM: cursor = CursorEnum::CURSOR_RESIZE_VERTICAL; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT: cursor = CursorEnum::CURSOR_RESIZE_BOTTOM_LEFT_TOP_RIGHT; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_RIGHT: cursor = CursorEnum::CURSOR_RESIZE_BOTTOM_RIGHT_TOP_LEFT; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_LEFT: cursor = CursorEnum::CURSOR_RESIZE_HORIZONTAL; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_RIGHT: cursor = CursorEnum::CURSOR_RESIZE_HORIZONTAL; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP: cursor = CursorEnum::CURSOR_RESIZE_VERTICAL; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_LEFT: cursor = CursorEnum::CURSOR_RESIZE_BOTTOM_RIGHT_TOP_LEFT; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_TOP_RIGHT: cursor = CursorEnum::CURSOR_RESIZE_BOTTOM_LEFT_TOP_RIGHT; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_END: cursor = CursorEnum::CURSOR_RESIZE_BOTTOM_LEFT_TOP_RIGHT; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START: cursor = CursorEnum::CURSOR_RESIZE_BOTTOM_LEFT_TOP_RIGHT; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE: cursor = CursorEnum::CURSOR_FOUR_ARROWS; break; case AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_ROTATION: cursor = CursorEnum::CURSOR_ROTATION; break; } } break; case MODE_SET_COORDINATE_ONE: cursor = CursorEnum::CURSOR_CROSS; break; case MODE_SET_COORDINATE_TWO: cursor = CursorEnum::CURSOR_CROSS; break; } return cursor; } /** * Delete all selected annotations. */ void UserInputModeAnnotations::deleteSelectedAnnotations() { AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); if (annotationManager->isAnnotationSelectedForEditingDeletable(m_browserWindowIndex)) { std::vector selectedAnnotations = annotationManager->getAnnotationsSelectedForEditing(m_browserWindowIndex); if ( ! selectedAnnotations.empty()) { AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeDeleteAnnotations(selectedAnnotations); AString errorMessage; if ( ! annotationManager->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(m_annotationToolsWidget, errorMessage); } } } else { std::vector selectedAnnotations = annotationManager->getAnnotationsSelectedForEditing(m_browserWindowIndex); for (std::vector::iterator iter = selectedAnnotations.begin(); iter != selectedAnnotations.end(); iter++) { Annotation* ann = *iter; CaretAssert(ann); if (ann->getType() == AnnotationTypeEnum::COLOR_BAR) { AnnotationColorBar* colorBar = dynamic_cast(ann); CaretAssert(colorBar); colorBar->setDisplayed(false); } } } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Process a key press event * * @param keyEvent * Key event information. * @return * True if the input process recognized the key event * and the key event SHOULD NOT be propagated to parent * widgets */ bool UserInputModeAnnotations::keyPressEvent(const KeyEvent& keyEvent) { bool keyWasProcessedFlag(false); const int32_t keyCode = keyEvent.getKeyCode(); switch (keyCode) { case Qt::Key_Backspace: case Qt::Key_Delete: { switch (m_mode) { case MODE_NEW_WITH_CLICK: break; case MODE_NEW_WITH_DRAG: break; case MODE_PASTE: break; case MODE_PASTE_SPECIAL: break; case MODE_SELECT: deleteSelectedAnnotations(); keyWasProcessedFlag = true; break; case MODE_SET_COORDINATE_ONE: break; case MODE_SET_COORDINATE_TWO: break; } } break; case Qt::Key_Escape: { bool selectModeFlag = false; switch (m_mode) { case MODE_NEW_WITH_CLICK: break; case MODE_NEW_WITH_DRAG: break; case MODE_PASTE: selectModeFlag = true; break; case MODE_PASTE_SPECIAL: selectModeFlag = true; break; case MODE_SELECT: break; case MODE_SET_COORDINATE_ONE: selectModeFlag = true; break; case MODE_SET_COORDINATE_TWO: selectModeFlag = true; break; } if (selectModeFlag) { setMode(MODE_SELECT); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); keyWasProcessedFlag = true; } } break; case Qt::Key_Down: case Qt::Key_Left: case Qt::Key_Right: case Qt::Key_Up: { Annotation* selectedAnnotation = getSingleSelectedAnnotation(); if (selectedAnnotation != NULL) { bool changeCoordFlag = false; bool moveOnePixelFlag = false; switch (selectedAnnotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: changeCoordFlag = true; break; case AnnotationCoordinateSpaceEnum::SPACER: changeCoordFlag = true; moveOnePixelFlag = true; break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: changeCoordFlag = true; break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: changeCoordFlag = true; moveOnePixelFlag = true; break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: changeCoordFlag = true; moveOnePixelFlag = true; break; } if (changeCoordFlag) { keyWasProcessedFlag = true; float distanceX = 1.0; float distanceY = 1.0; if (moveOnePixelFlag) { const float pixelHeight = keyEvent.getOpenGLWidget()->height(); const float pixelWidth = keyEvent.getOpenGLWidget()->width(); /* * 100 is "full width/height" in relative coordinates. */ distanceX = 100.0 / pixelWidth; distanceY = 100.0 / pixelHeight; } if (keyEvent.isShiftKeyDownFlag()) { const float multiplier = 10; distanceX *= multiplier; distanceY *= multiplier; } float dx = 0.0; float dy = 0.0; switch (keyCode) { case Qt::Key_Down: dy = -distanceY; break; case Qt::Key_Left: dx = -distanceX; break; case Qt::Key_Right: dx = distanceX; break; case Qt::Key_Up: dy = distanceY; break; default: CaretAssert(0); break; } AnnotationOneDimensionalShape* oneDim = dynamic_cast(selectedAnnotation); AnnotationTwoDimensionalShape* twoDim = dynamic_cast(selectedAnnotation); { bool surfaceFlag = false; switch (selectedAnnotation->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: surfaceFlag = true; break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } if ( ! surfaceFlag) { AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); std::vector annotations; annotations.push_back(selectedAnnotation); if (oneDim != NULL) { AnnotationCoordinate startCoord = *oneDim->getStartCoordinate(); float xyzStart[3]; startCoord.getXYZ(xyzStart); xyzStart[0] += dx; xyzStart[1] += dy; startCoord.setXYZ(xyzStart); AnnotationCoordinate endCoord = *oneDim->getEndCoordinate(); float xyzEnd[3]; endCoord.getXYZ(xyzEnd); xyzEnd[0] += dx; xyzEnd[1] += dy; endCoord.setXYZ(xyzEnd); undoCommand->setModeCoordinateOneAndTwo(startCoord, endCoord, annotations); } else if (twoDim != NULL) { AnnotationCoordinate coord = *twoDim->getCoordinate(); float xyz[3]; coord.getXYZ(xyz); xyz[0] += dx; xyz[1] += dy; coord.setXYZ(xyz); undoCommand->setModeCoordinateOne(coord, annotations); } else { CaretAssert(0); } if ( ! keyEvent.isFirstKeyPressFlag()) { undoCommand->setMergeEnabled(true); } AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(m_annotationToolsWidget, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } } } } break; } return keyWasProcessedFlag; } /** * Process a mouse left drag with no keys down event. * * @param mouseEvent * Mouse event information. */ void UserInputModeAnnotations::mouseLeftDrag(const MouseEvent& mouseEvent) { AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); switch (m_mode) { case MODE_NEW_WITH_CLICK: { if (m_newAnnotationCreatingWithMouseDrag != NULL) { m_newAnnotationCreatingWithMouseDrag.grabNew(NULL); } /* * Note ALWAYS use WINDOW space for the drag anntotion. * Otherwise it will not get displayed if surface/stereotaxic */ m_newAnnotationCreatingWithMouseDrag.grabNew(new NewMouseDragCreateAnnotation(m_modeNewAnnotationFileSpaceAndType->m_annotationFile, AnnotationCoordinateSpaceEnum::WINDOW, m_modeNewAnnotationFileSpaceAndType->m_annotationType, mouseEvent)); m_mode = MODE_NEW_WITH_DRAG; return; } break; case MODE_NEW_WITH_DRAG: userDrawingAnnotationFromMouseDrag(mouseEvent); return; break; case MODE_PASTE: break; case MODE_PASTE_SPECIAL: break; case MODE_SELECT: break; case MODE_SET_COORDINATE_ONE: break; case MODE_SET_COORDINATE_TWO: break; } AnnotationCoordinateSpaceEnum::Enum draggingCoordinateSpace = AnnotationCoordinateSpaceEnum::VIEWPORT; std::vector selectedAnnotations = annotationManager->getAnnotationsSelectedForEditing(m_browserWindowIndex); const int32_t numSelectedAnnotations = static_cast(selectedAnnotations.size()); bool draggingValid = false; if (numSelectedAnnotations == 1) { draggingCoordinateSpace = selectedAnnotations[0]->getCoordinateSpace(); draggingValid = true; } else if (numSelectedAnnotations > 1) { if (m_annotationBeingDraggedHandleType == AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE) { bool allSameSpaceFlag = true; draggingCoordinateSpace = selectedAnnotations[0]->getCoordinateSpace(); for (int32_t i = 1; i < numSelectedAnnotations; i++) { if (selectedAnnotations[i]->getCoordinateSpace() != draggingCoordinateSpace) { allSameSpaceFlag = false; break; } } if (allSameSpaceFlag) { draggingValid = true; } } } switch (draggingCoordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: break; case AnnotationCoordinateSpaceEnum::SURFACE: break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: /* * No dragging in viewport space */ draggingValid = false; break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } if (draggingValid) { BrainOpenGLViewportContent* vpContent = mouseEvent.getViewportContent(); if (vpContent == NULL) { return; } AnnotationCoordinateInformation coordInfo; AnnotationCoordinateInformation::createCoordinateInformationFromXY(mouseEvent.getOpenGLWidget(), mouseEvent.getViewportContent(), mouseEvent.getX(), mouseEvent.getY(), coordInfo); float spaceOriginX = 0.0; float spaceOriginY = 0.0; float spaceWidth = 0.0; float spaceHeight = 0.0; switch (draggingCoordinateSpace) { case AnnotationCoordinateSpaceEnum::CHART: { /* * Want viewport within montage that contains the surface */ Matrix4x4 projectionMatrix; Matrix4x4 modelviewMatrix; int32_t chartVP[4]; if (vpContent->getChartDataMatricesAndViewport(projectionMatrix, modelviewMatrix, chartVP)) { spaceOriginX = chartVP[0]; spaceOriginY = chartVP[1]; spaceWidth = chartVP[2]; spaceHeight = chartVP[3]; } } break; case AnnotationCoordinateSpaceEnum::SPACER: { int viewport[4]; vpContent->getTabViewportBeforeApplyingMargins(viewport); spaceOriginX = viewport[0]; spaceOriginY = viewport[1]; spaceWidth = viewport[2]; spaceHeight = viewport[3]; } break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: { /* * Want viewport within montage that contains the surface */ int montVP[4]; vpContent->getSurfaceMontageModelViewport(mouseEvent.getX(), mouseEvent.getY(), montVP); spaceOriginX = montVP[0]; spaceOriginY = montVP[1]; spaceWidth = montVP[2]; spaceHeight = montVP[3]; } break; case AnnotationCoordinateSpaceEnum::SURFACE: { /* * Want viewport within montage that contains the surface */ int montVP[4]; vpContent->getSurfaceMontageModelViewport(mouseEvent.getX(), mouseEvent.getY(), montVP); spaceOriginX = montVP[0]; spaceOriginY = montVP[1]; spaceWidth = montVP[2]; spaceHeight = montVP[3]; /* * Also need to find viewport where mouse was originally * pressed. If the viewports are different, then * mouse has left the viewport in which it was pressed * and the mouse position is no longer valid. */ int pressVP[4]; vpContent->getSurfaceMontageModelViewport(mouseEvent.getPressedX(), mouseEvent.getPressedY(), pressVP); if ((montVP[0] != pressVP[0]) || (montVP[1] != pressVP[1]) || (montVP[2] != pressVP[2]) || (montVP[3] != pressVP[3])) { draggingValid = false; } } break; case AnnotationCoordinateSpaceEnum::TAB: { int viewport[4]; vpContent->getModelViewport(viewport); spaceOriginX = viewport[0]; spaceOriginY = viewport[1]; spaceWidth = viewport[2]; spaceHeight = viewport[3]; } break; case AnnotationCoordinateSpaceEnum::VIEWPORT: CaretAssert(0); break; case AnnotationCoordinateSpaceEnum::WINDOW: { int viewport[4]; vpContent->getWindowViewport(viewport); spaceOriginX = viewport[0]; spaceOriginY = viewport[1]; spaceWidth = viewport[2]; spaceHeight = viewport[3]; } break; } if (draggingValid) { const float dx = mouseEvent.getDx(); const float dy = mouseEvent.getDy(); const float mouseViewportX = mouseEvent.getX() - spaceOriginX; const float mouseViewportY = mouseEvent.getY() - spaceOriginY; const float mousePressViewportX = mouseEvent.getPressedX() - spaceOriginX; const float mousePressViewportY = mouseEvent.getPressedY() - spaceOriginY; AnnotationSpatialModification annSpatialMod(m_annotationBeingDraggedHandleType, spaceWidth, spaceHeight, mousePressViewportX, mousePressViewportY, mouseViewportX, mouseViewportY, dx, dy, mouseEvent.isFirstDragging()); if (coordInfo.m_surfaceSpaceInfo.m_validFlag) { annSpatialMod.setSurfaceCoordinateAtMouseXY(coordInfo.m_surfaceSpaceInfo.m_structure, coordInfo.m_surfaceSpaceInfo.m_numberOfNodes, coordInfo.m_surfaceSpaceInfo.m_nodeIndex); } if (coordInfo.m_modelSpaceInfo.m_validFlag) { annSpatialMod.setStereotaxicCoordinateAtMouseXY(coordInfo.m_modelSpaceInfo.m_xyz[0], coordInfo.m_modelSpaceInfo.m_xyz[1], coordInfo.m_modelSpaceInfo.m_xyz[2]); } if (coordInfo.m_chartSpaceInfo.m_validFlag) { annSpatialMod.setChartCoordinateAtMouseXY(coordInfo.m_chartSpaceInfo.m_xyz[0], coordInfo.m_chartSpaceInfo.m_xyz[1], coordInfo.m_chartSpaceInfo.m_xyz[2]); } if ((dx != 0.0) || (dy != 0.0)) { AnnotationCoordinateInformation previousMouseXYCoordInfo; AnnotationCoordinateInformation::createCoordinateInformationFromXY(mouseEvent.getOpenGLWidget(), mouseEvent.getViewportContent(), mouseEvent.getX() - dx, mouseEvent.getY() - dy, previousMouseXYCoordInfo); if (previousMouseXYCoordInfo.m_chartSpaceInfo.m_validFlag) { annSpatialMod.setChartCoordinateAtPreviousMouseXY(previousMouseXYCoordInfo.m_chartSpaceInfo.m_xyz[0], previousMouseXYCoordInfo.m_chartSpaceInfo.m_xyz[1], previousMouseXYCoordInfo.m_chartSpaceInfo.m_xyz[2]); } } std::vector annotationsBeforeMoveAndResize; std::vector annotationsAfterMoveAndResize; for (int32_t i = 0; i < numSelectedAnnotations; i++) { Annotation* annotationModified(selectedAnnotations[i]->clone()); if (annotationModified->applySpatialModification(annSpatialMod)) { annotationsBeforeMoveAndResize.push_back(selectedAnnotations[i]); annotationsAfterMoveAndResize.push_back(annotationModified); } else { delete annotationModified; annotationModified = NULL; } } CaretAssert(annotationsAfterMoveAndResize.size() == annotationsBeforeMoveAndResize.size()); if ( ! annotationsAfterMoveAndResize.empty()) { AnnotationRedoUndoCommand* command = new AnnotationRedoUndoCommand(); command->setModeLocationAndSize(annotationsBeforeMoveAndResize, annotationsAfterMoveAndResize); if ( ! mouseEvent.isFirstDragging()) { command->setMergeEnabled(true); } AString errorMessage; if ( ! annotationManager->applyCommand(command, errorMessage)) { WuQMessageBox::errorOk(m_annotationToolsWidget, errorMessage); } } for (std::vector::iterator iter = annotationsAfterMoveAndResize.begin(); iter != annotationsAfterMoveAndResize.end(); iter++) { delete *iter; } annotationsAfterMoveAndResize.clear(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); } } } /** * Process a mouse left drag with only the alt key down event. * * @param mouseEvent * Mouse event information. */ void UserInputModeAnnotations::mouseLeftDragWithAlt(const MouseEvent& /*mouseEvent*/) { } /** * Process a mouse left drag with ctrl key down event. * * @param mouseEvent * Mouse event information. */ void UserInputModeAnnotations::mouseLeftDragWithCtrl(const MouseEvent& /*mouseEvent*/) { } /** * Process a mouse left drag with ctrl and shift keys down event. * * @param mouseEvent * Mouse event information. */ void UserInputModeAnnotations::mouseLeftDragWithCtrlShift(const MouseEvent& /*mouseEvent*/) { } /** * Process a mouse left drag with shift key down event. * * @param mouseEvent * Mouse event information. */ void UserInputModeAnnotations::mouseLeftDragWithShift(const MouseEvent& mouseEvent) { mouseLeftDrag(mouseEvent); } /** * Process a mouse left click event. * * @param mouseEvent * Mouse event information. */ void UserInputModeAnnotations::mouseLeftClick(const MouseEvent& mouseEvent) { switch (m_mode) { case MODE_NEW_WITH_CLICK: processModeNewMouseLeftClick(mouseEvent); break; case MODE_NEW_WITH_DRAG: break; case MODE_PASTE: pasteAnnotationFromAnnotationClipboard(mouseEvent); break; case MODE_PASTE_SPECIAL: pasteAnnotationFromAnnotationClipboardAndChangeSpace(mouseEvent); break; case MODE_SELECT: break; case MODE_SET_COORDINATE_ONE: processModeSetCoordinate(mouseEvent); break; case MODE_SET_COORDINATE_TWO: processModeSetCoordinate(mouseEvent); break; } } /** * Process a mouse left click with Shift key event. * * @param mouseEvent * Mouse event information. */ void UserInputModeAnnotations::mouseLeftClickWithShift(const MouseEvent& mouseEvent) { switch (m_mode) { case MODE_NEW_WITH_CLICK: break; case MODE_NEW_WITH_DRAG: break; case MODE_PASTE: break; case MODE_PASTE_SPECIAL: break; case MODE_SELECT: if (m_allowMultipleSelectionModeFlag) { processMouseSelectAnnotation(mouseEvent, true); } break; case MODE_SET_COORDINATE_ONE: break; case MODE_SET_COORDINATE_TWO: break; } } /** * Process a mouse left press event. * * @param mouseEvent * Mouse event information. */ void UserInputModeAnnotations::mouseLeftPress(const MouseEvent& mouseEvent) { switch (m_mode) { case MODE_NEW_WITH_CLICK: break; case MODE_NEW_WITH_DRAG: break; case MODE_PASTE: break; case MODE_PASTE_SPECIAL: break; case MODE_SELECT: processMouseSelectAnnotation(mouseEvent, false); break; case MODE_SET_COORDINATE_ONE: break; case MODE_SET_COORDINATE_TWO: break; } } /** * Set the annotation under the mouse that results in update of the cursor. * * @param mouseEvent * Mouse event information. * @param annotationIDIn * Optional (if not NULL) annotation ID that may be provided by caller * and can be used to avoid an identification operation. */ void UserInputModeAnnotations::setAnnotationUnderMouse(const MouseEvent& mouseEvent, SelectionItemAnnotation* annotationIDIn) { m_annotationUnderMouse = NULL; m_annotationUnderMouseSizeHandleType = AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE; BrainOpenGLWidget* openGLWidget = mouseEvent.getOpenGLWidget(); SelectionItemAnnotation* annotationID = annotationIDIn; if (annotationID == NULL) { annotationID = openGLWidget->performIdentificationAnnotations(mouseEvent.getX(), mouseEvent.getY()); } if (annotationID->isValid()) { m_annotationUnderMouse = annotationID->getAnnotation(); m_annotationUnderMouseSizeHandleType = annotationID->getSizingHandle(); } openGLWidget->updateCursor(); /* * Update graphics only if an annotation was passed to this method (WB-820) */ if (annotationIDIn != NULL) { #if BRAIN_OPENGL_INFO_SUPPORTS_DISPLAY_LISTS openGLWidget->updateGL(); #else openGLWidget->update(); #endif } } /** * User drawing a new annotation from dragging the mouse from corner/end to another * corner/end. * * @param mouseEvent * Mouse event issued when mouse button was released. */ void UserInputModeAnnotations::userDrawingAnnotationFromMouseDrag(const MouseEvent& mouseEvent) { if (m_newAnnotationCreatingWithMouseDrag != NULL) { m_newAnnotationCreatingWithMouseDrag->update(mouseEvent.getX(), mouseEvent.getY()); AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); annotationManager->setAnnotationBeingDrawnInWindow(m_browserWindowIndex, m_newAnnotationCreatingWithMouseDrag->getAnnotation()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } /** * Create a new annotation from dragging the mouse from corner/end to another * corner/end. * * @param mouseEvent * Mouse event issued when mouse button was released. */ void UserInputModeAnnotations::createNewAnnotationFromMouseDrag(const MouseEvent& mouseEvent) { if (m_newAnnotationCreatingWithMouseDrag != NULL) { Annotation* ann = AnnotationCreateDialog::newAnnotationFromSpaceTypeAndBounds(mouseEvent, m_modeNewAnnotationFileSpaceAndType->m_annotationSpace, m_modeNewAnnotationFileSpaceAndType->m_annotationType, m_modeNewAnnotationFileSpaceAndType->m_annotationFile); if (ann != NULL) { selectAnnotation(ann); } setMode(MODE_SELECT); m_newAnnotationCreatingWithMouseDrag.grabNew(NULL); AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); annotationManager->setAnnotationBeingDrawnInWindow(m_browserWindowIndex, NULL); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } /** * Process a mouse left release event. * * @param mouseEvent * Mouse event information. */ void UserInputModeAnnotations::mouseLeftRelease(const MouseEvent& mouseEvent) { switch (m_mode) { case MODE_NEW_WITH_CLICK: break; case MODE_NEW_WITH_DRAG: createNewAnnotationFromMouseDrag(mouseEvent); m_mode = MODE_SELECT; break; case MODE_PASTE: break; case MODE_PASTE_SPECIAL: break; case MODE_SELECT: break; case MODE_SET_COORDINATE_ONE: break; case MODE_SET_COORDINATE_TWO: break; } m_annotationBeingDragged = NULL; setAnnotationUnderMouse(mouseEvent, NULL); } /** * Process a mouse left double-click event. * * @param mouseEvent * Mouse event information. */ void UserInputModeAnnotations::mouseLeftDoubleClick(const MouseEvent& mouseEvent) { const int32_t mouseX = mouseEvent.getX(); const int32_t mouseY = mouseEvent.getY(); BrainOpenGLWidget* openGLWidget = mouseEvent.getOpenGLWidget(); SelectionItemAnnotation* annotationID = openGLWidget->performIdentificationAnnotations(mouseX, mouseY); if (annotationID->isValid()) { Annotation* annotation = annotationID->getAnnotation(); if (annotation != NULL) { AnnotationText* textAnnotation = dynamic_cast(annotation); if (textAnnotation != NULL) { AnnotationTextEditorDialog ted(textAnnotation, openGLWidget); /* * Note: Y==0 is at top for widget. * Y==0 is at bottom for OpenGL mouse x,y */ ted.move(openGLWidget->mapToGlobal(QPoint(mouseX, (openGLWidget->height() - mouseY + 20)))); ted.exec(); EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); } } } } /** * Process a mouse move with no buttons or keys down * * @param mouseEvent * Mouse event information. */ void UserInputModeAnnotations::mouseMove(const MouseEvent& mouseEvent) { setAnnotationUnderMouse(mouseEvent, NULL); } /** * Process a mouse move with no buttons and shift key down * * @param mouseEvent * Mouse event information. */ void UserInputModeAnnotations::mouseMoveWithShift(const MouseEvent& mouseEvent) { setAnnotationUnderMouse(mouseEvent, NULL); } /** * Process a mouse left click to set a coordinate. * * @param mouseEvent * Mouse event information. */ void UserInputModeAnnotations::processModeSetCoordinate(const MouseEvent& mouseEvent) { Annotation* selectedAnnotation = getSingleSelectedAnnotation(); if (selectedAnnotation == NULL) { return; } AnnotationCoordinateInformation coordInfo; AnnotationCoordinateInformation::createCoordinateInformationFromXY(mouseEvent.getOpenGLWidget(), mouseEvent.getViewportContent(), mouseEvent.getX(), mouseEvent.getY(), coordInfo); AnnotationOneDimensionalShape* oneDimAnn = dynamic_cast(selectedAnnotation); AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(selectedAnnotation); AnnotationCoordinate* coordinate = NULL; AnnotationCoordinate* otherCoordinate = NULL; switch (m_mode) { case MODE_NEW_WITH_CLICK: break; case MODE_NEW_WITH_DRAG: break; case MODE_PASTE: break; case MODE_PASTE_SPECIAL: break; case MODE_SELECT: break; case MODE_SET_COORDINATE_ONE: if (oneDimAnn != NULL) { coordinate = oneDimAnn->getStartCoordinate(); otherCoordinate = oneDimAnn->getEndCoordinate(); } else if (twoDimAnn != NULL) { coordinate = twoDimAnn->getCoordinate(); } break; case MODE_SET_COORDINATE_TWO: if (oneDimAnn != NULL) { coordinate = oneDimAnn->getEndCoordinate(); otherCoordinate = oneDimAnn->getStartCoordinate(); } break; } if (coordinate != NULL) { StructureEnum::Enum structure = StructureEnum::INVALID; int32_t numNodes = -1; int32_t nodeIndex = -1; float surfaceOffset = 0.0; AnnotationSurfaceOffsetVectorTypeEnum::Enum surfaceVectorType = AnnotationSurfaceOffsetVectorTypeEnum::CENTROID_THRU_VERTEX; coordinate->getSurfaceSpace(structure, numNodes, nodeIndex, surfaceOffset, surfaceVectorType); coordInfo.m_surfaceSpaceInfo.m_nodeOffsetLength = surfaceOffset; coordInfo.m_surfaceSpaceInfo.m_nodeVectorOffsetType = surfaceVectorType; } AnnotationChangeCoordinateDialog changeCoordDialog(coordInfo, selectedAnnotation, coordinate, otherCoordinate, m_annotationToolsWidget); if (changeCoordDialog.exec() == AnnotationChangeCoordinateDialog::Accepted) { } setMode(MODE_SELECT); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); } /** * Process a mouse left click for new mode. * * @param mouseEvent * Mouse event information. */ void UserInputModeAnnotations::processModeNewMouseLeftClick(const MouseEvent& mouseEvent) { resetAnnotationUnderMouse(); Annotation* ann = AnnotationCreateDialog::newAnnotationFromSpaceAndType(mouseEvent, m_modeNewAnnotationFileSpaceAndType->m_annotationSpace, m_modeNewAnnotationFileSpaceAndType->m_annotationType, m_modeNewAnnotationFileSpaceAndType->m_annotationFile); if (ann != NULL) { selectAnnotation(ann); } setMode(MODE_SELECT); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); } /** * @return The single selected annotation. If there is ONE and ONLY one annotation * selected, it is returned. Otherwise, NULL is returned. */ Annotation* UserInputModeAnnotations::getSingleSelectedAnnotation() { AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); std::vector allSelectedAnnotations = annotationManager->getAnnotationsSelectedForEditing(m_browserWindowIndex); Annotation* selectedAnnotation = NULL; if (allSelectedAnnotations.size() == 1) { CaretAssertVectorIndex(allSelectedAnnotations, 0); selectedAnnotation = allSelectedAnnotations[0]; } return selectedAnnotation; } /** * Select the given annotation (typically when a new annontation is created). * * @param annotation * Annotation that is selected. */ void UserInputModeAnnotations::selectAnnotation(Annotation* annotation) { resetAnnotationUnderMouse(); m_annotationBeingDragged = annotation; m_annotationUnderMouse = annotation; } /** * Process a mouse left click for selection mode. * * @param mouseEvent * Mouse event information. * @param shiftKeyDownFlag * True if shift key is down. */ void UserInputModeAnnotations::processMouseSelectAnnotation(const MouseEvent& mouseEvent, const bool shiftKeyDownFlag) { BrainOpenGLWidget* openGLWidget = mouseEvent.getOpenGLWidget(); const int mouseX = mouseEvent.getX(); const int mouseY = mouseEvent.getY(); m_annotationBeingDragged = NULL; /* * NOTE: When selecting annotations: * (A) When the mouse is clicked WITHOUT the SHIFT key down, the user is in * 'single-annotation-selection-mode' and at most one annotation will * be selected when this method completes. * (B) If the mouse is clicked with the SHIFT key down, the user is in * 'multi-annotation-selection-mode' and any number of annotation will * be selected when this method completes. */ SelectionItemAnnotation* annotationID = openGLWidget->performIdentificationAnnotations(mouseX, mouseY); Annotation* selectedAnnotation = annotationID->getAnnotation(); AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); AnnotationManager::SelectionMode selectionMode = AnnotationManager::SELECTION_MODE_SINGLE; if (m_allowMultipleSelectionModeFlag) { selectionMode = AnnotationManager::SELECTION_MODE_EXTENDED; } annotationManager->selectAnnotationForEditing(m_browserWindowIndex, selectionMode, shiftKeyDownFlag, selectedAnnotation); setAnnotationUnderMouse(mouseEvent, annotationID); if (selectedAnnotation != NULL) { m_annotationBeingDragged = selectedAnnotation; m_annotationBeingDraggedHandleType = annotationID->getSizingHandle(); } EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); } /** * Show a context menu (pop-up menu at mouse location) * * @param mouseEvent * Mouse event information. * @param menuPosition * Point at which menu is displayed (passed to QMenu::exec()) * @param openGLWidget * OpenGL widget in which context menu is requested */ void UserInputModeAnnotations::showContextMenu(const MouseEvent& mouseEvent, const QPoint& menuPosition, BrainOpenGLWidget* openGLWidget) { BrainOpenGLViewportContent* viewportContent = mouseEvent.getViewportContent(); BrowserTabContent* tabContent = viewportContent->getBrowserTabContent(); if (tabContent == NULL) { return; } /* * Select any annotation that is under the mouse. * There might not be an annotation under the * mouse and that is okay. */ processMouseSelectAnnotation(mouseEvent, false); UserInputModeAnnotationsContextMenu contextMenu(this, mouseEvent, NULL, tabContent, openGLWidget); if (contextMenu.actions().size() > 0) { contextMenu.exec(menuPosition); Annotation* newAnnotation = contextMenu.getNewAnnotationCreatedByContextMenu(); if (newAnnotation != NULL) { selectAnnotation(newAnnotation); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); } } } /** * @return True if the edit menu items should be enabled, else false. */ bool UserInputModeAnnotations::isEditMenuValid() const { bool editMenuValid = false; switch (m_mode) { case MODE_NEW_WITH_CLICK: break; case MODE_NEW_WITH_DRAG: break; case MODE_PASTE: editMenuValid = true; break; case MODE_PASTE_SPECIAL: editMenuValid = true; break; case MODE_SELECT: editMenuValid = true; break; case MODE_SET_COORDINATE_ONE: break; case MODE_SET_COORDINATE_TWO: break; } return editMenuValid; } /** * Cut the selected annotation. Only functions if * one and only one annotation is selected. */ void UserInputModeAnnotations::cutAnnotation() { std::vector > selectedAnnotations; AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); annotationManager->getAnnotationsSelectedForEditing(m_browserWindowIndex, selectedAnnotations); if (selectedAnnotations.size() == 1) { CaretAssertVectorIndex(selectedAnnotations, 0); AnnotationFile* annotationFile = selectedAnnotations[0].second; Annotation* annotation = selectedAnnotations[0].first; annotationManager->copyAnnotationToClipboard(annotationFile, annotation); std::vector annotationVector; annotationVector.push_back(annotation); AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeCutAnnotations(annotationVector); AString errorMessage; if ( ! annotationManager->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(m_annotationToolsWidget, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } /** * Process a selection that was made from the browser window's edit menu. * Intended for override by sub-classes. * * @param editMenuItem * Item that was selected from the edit menu. */ void UserInputModeAnnotations::processEditMenuItemSelection(const BrainBrowserWindowEditMenuItemEnum::Enum editMenuItem) { if ( ! isEditMenuValid()) { return; } switch (editMenuItem) { case BrainBrowserWindowEditMenuItemEnum::COPY: { AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); std::vector > selectedAnnotations; annotationManager->getAnnotationsSelectedForEditing(m_browserWindowIndex, selectedAnnotations); if (selectedAnnotations.size() == 1) { CaretAssertVectorIndex(selectedAnnotations, 0); annotationManager->copyAnnotationToClipboard(selectedAnnotations[0].second, selectedAnnotations[0].first); } } break; case BrainBrowserWindowEditMenuItemEnum::CUT: cutAnnotation(); break; case BrainBrowserWindowEditMenuItemEnum::DELETER: deleteSelectedAnnotations(); break; case BrainBrowserWindowEditMenuItemEnum::PASTE: { const MouseEvent* mouseEvent = getMousePosition(); if (mouseEvent != NULL) { pasteAnnotationFromAnnotationClipboard(*mouseEvent); } else { setMode(MODE_PASTE); } } break; case BrainBrowserWindowEditMenuItemEnum::PASTE_SPECIAL: { const MouseEvent* mouseEvent = getMousePosition(); if (mouseEvent != NULL) { pasteAnnotationFromAnnotationClipboardAndChangeSpace(*mouseEvent); } else { setMode(MODE_PASTE_SPECIAL); } } break; case BrainBrowserWindowEditMenuItemEnum::REDO: { AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); CaretUndoStack* undoStack = annMan->getCommandRedoUndoStack(); AString errorMessage; if ( ! undoStack->redo(errorMessage)) { WuQMessageBox::errorOk(m_annotationToolsWidget, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } break; case BrainBrowserWindowEditMenuItemEnum::SELECT_ALL: processSelectAllAnnotations(); break; case BrainBrowserWindowEditMenuItemEnum::UNDO: { AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); CaretUndoStack* undoStack = annMan->getCommandRedoUndoStack(); AString errorMessage; if ( ! undoStack->undo(errorMessage)) { WuQMessageBox::errorOk(m_annotationToolsWidget, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } break; } } /** * Process the selection of all annotations. */ void UserInputModeAnnotations::processSelectAllAnnotations() { AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); annMan->deselectAllAnnotationsForEditing(m_browserWindowIndex); EventAnnotationGetDrawnInWindow getDrawnEvent(m_browserWindowIndex); EventManager::get()->sendEvent(getDrawnEvent.getPointer()); std::vector annotationsSelected; getDrawnEvent.getAnnotations(annotationsSelected); annMan->setAnnotationsForEditing(m_browserWindowIndex, annotationsSelected); EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Get the menu items that should be enabled for the current user input processor. * Intended for override by sub-classes. * Unless this method is overridden, all items on Edit menu are disabled. * * @param enabledEditMenuItemsOut * Upon exit contains edit menu items that should be enabled. * @param redoMenuItemSuffixTextOut * If the redo menu is enabled, the contents of string becomes * the suffix for the 'Redo' menu item. * @param undoMenuItemSuffixTextOut * If the undo menu is enabled, the contents of string becomes * the suffix for the 'Undo' menu item. * @param pasteTextOut * If not empty, this text is shown for the PASTE menu item * @param pasteSpecialTextOut * If not empty, this text is shown for the PASTE_SPECIAL menu item */ void UserInputModeAnnotations::getEnabledEditMenuItems(std::vector& enabledEditMenuItemsOut, AString& redoMenuItemSuffixTextOut, AString& undoMenuItemSuffixTextOut, AString& pasteTextOut, AString& pasteSpecialTextOut) { enabledEditMenuItemsOut.clear(); redoMenuItemSuffixTextOut = ""; undoMenuItemSuffixTextOut = ""; pasteTextOut = BrainBrowserWindowEditMenuItemEnum::toGuiName(BrainBrowserWindowEditMenuItemEnum::PASTE); pasteSpecialTextOut = BrainBrowserWindowEditMenuItemEnum::toGuiName(BrainBrowserWindowEditMenuItemEnum::PASTE_SPECIAL); if (isEditMenuValid()) { AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); const std::vector allSelectedAnnotations = annotationManager->getAnnotationsSelectedForEditing(m_browserWindowIndex); /* * Copy, Cut, and Delete disabled if ANY colorbar is selected. */ bool allAllowCopyCutPasteFlag = true; bool allAllowDeleteFlag = true; bool allAllowSelectFlag = true; for (std::vector::const_iterator iter = allSelectedAnnotations.begin(); iter != allSelectedAnnotations.end(); iter++) { const Annotation* ann = *iter; if ( ! ann->testProperty(Annotation::Property::COPY_CUT_PASTE)) { allAllowCopyCutPasteFlag = false; } if ( ! ann->testProperty(Annotation::Property::DELETION)) { allAllowDeleteFlag = false; } } const bool anySelectedFlag = ( ! allSelectedAnnotations.empty()); const bool oneSelectedFlag = (allSelectedAnnotations.size() == 1); if (allAllowCopyCutPasteFlag) { if (oneSelectedFlag) { enabledEditMenuItemsOut.push_back(BrainBrowserWindowEditMenuItemEnum::COPY); enabledEditMenuItemsOut.push_back(BrainBrowserWindowEditMenuItemEnum::CUT); } } if (allAllowDeleteFlag) { if (anySelectedFlag) { enabledEditMenuItemsOut.push_back(BrainBrowserWindowEditMenuItemEnum::DELETER); } } if (allAllowSelectFlag) { enabledEditMenuItemsOut.push_back(BrainBrowserWindowEditMenuItemEnum::SELECT_ALL); } if (annotationManager->isAnnotationOnClipboardValid()) { const Annotation* clipBoardAnn = annotationManager->getAnnotationOnClipboard(); CaretAssert(clipBoardAnn); enabledEditMenuItemsOut.push_back(BrainBrowserWindowEditMenuItemEnum::PASTE); enabledEditMenuItemsOut.push_back(BrainBrowserWindowEditMenuItemEnum::PASTE_SPECIAL); clipBoardAnn->getTextForPasteMenuItems(pasteTextOut, pasteSpecialTextOut); } CaretUndoStack* undoStack = annotationManager->getCommandRedoUndoStack(); if (undoStack->canRedo()) { enabledEditMenuItemsOut.push_back(BrainBrowserWindowEditMenuItemEnum::REDO); redoMenuItemSuffixTextOut = undoStack->redoText(); } if (undoStack->canUndo()) { enabledEditMenuItemsOut.push_back(BrainBrowserWindowEditMenuItemEnum::UNDO); undoMenuItemSuffixTextOut = undoStack->undoText(); } } } /** * Paste the annotation from the annotation clipboard. * * @param mouseEvent * Mouse event containing XY location for placement of * pasted annotation. */ void UserInputModeAnnotations::pasteAnnotationFromAnnotationClipboard(const MouseEvent& mouseEvent) { Annotation* newPastedAnnotation = AnnotationPasteDialog::pasteAnnotationOnClipboard(mouseEvent, m_browserWindowIndex); if (newPastedAnnotation != NULL) { selectAnnotation(newPastedAnnotation); DisplayPropertiesAnnotation* dpa = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotation(); dpa->updateForNewAnnotation(newPastedAnnotation); } setMode(MODE_SELECT); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** * Paste the annotation from the annotation clipboard and allow user to change its space. * * @param mouseEvent * Mouse event containing XY location for placement of * pasted annotation. */ void UserInputModeAnnotations::pasteAnnotationFromAnnotationClipboardAndChangeSpace(const MouseEvent& mouseEvent) { Annotation* newPastedAnnotation = AnnotationPasteDialog::pasteAnnotationOnClipboardChangeSpace(mouseEvent); if (newPastedAnnotation != NULL) { selectAnnotation(newPastedAnnotation); DisplayPropertiesAnnotation* dpa = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotation(); dpa->updateForNewAnnotation(newPastedAnnotation); } setMode(MODE_SELECT); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /* =============================================================================== */ /** * Constructor. * * @param annotationFile * File for annotation. * @param annotationSpace * Space for annotation being created. * @param annotationType * Type of annotation being created. * @param mouseEvent * Mouse event. */ UserInputModeAnnotations::NewMouseDragCreateAnnotation::NewMouseDragCreateAnnotation(AnnotationFile* annotationFile, const AnnotationCoordinateSpaceEnum::Enum annotationSpace, const AnnotationTypeEnum::Enum annotationType, const MouseEvent& mouseEvent) { BrainOpenGLViewportContent* vpContent = mouseEvent.getViewportContent(); CaretAssert(vpContent); if (vpContent == NULL) { CaretLogSevere("Viewport content is invalid."); return; } int32_t windowViewport[4]; vpContent->getWindowViewport(windowViewport); m_windowOriginX = windowViewport[0]; m_windowOriginY = windowViewport[1]; m_mousePressWindowX = mouseEvent.getX() - m_windowOriginX; m_mousePressWindowY = mouseEvent.getY() - m_windowOriginY; int viewport[4]; vpContent->getWindowViewport(viewport); m_windowWidth = viewport[2]; m_windowHeight = viewport[3]; m_annotationFile = annotationFile; m_annotation = Annotation::newAnnotationOfType(annotationType, AnnotationAttributesDefaultTypeEnum::USER); m_annotation->setCoordinateSpace(annotationSpace); CaretAssert(m_annotation); AnnotationOneDimensionalShape* oneDimShape = dynamic_cast(m_annotation); AnnotationTwoDimensionalShape* twoDimShape = dynamic_cast(m_annotation); if (oneDimShape != NULL) { setCoordinate(oneDimShape->getStartCoordinate(), m_mousePressWindowX, m_mousePressWindowY); setCoordinate(oneDimShape->getEndCoordinate(), m_mousePressWindowX, m_mousePressWindowY); } else if (twoDimShape != NULL) { setCoordinate(twoDimShape->getCoordinate(), m_mousePressWindowX, m_mousePressWindowY); twoDimShape->setWidth(1.0); twoDimShape->setHeight(1.0); } else { CaretAssert(0); } if ((m_annotation->getLineColor() == CaretColorEnum::NONE) && (m_annotation->getBackgroundColor() == CaretColorEnum::NONE)) { m_annotation->setLineColor(CaretColorEnum::RED); } } /** * Destructor. */ UserInputModeAnnotations::NewMouseDragCreateAnnotation::~NewMouseDragCreateAnnotation() { delete m_annotation; } /** * Update with current mouse location. * * @param mouseWindowX * Mouse window X-coordinate * @param mouseWindowY * Mouse window Y-coordinate */ void UserInputModeAnnotations::NewMouseDragCreateAnnotation::update(const int32_t mouseWindowXIn, const int32_t mouseWindowYIn) { int32_t mouseWindowX = mouseWindowXIn - m_windowOriginX; int32_t mouseWindowY = mouseWindowYIn - m_windowOriginY; AnnotationOneDimensionalShape* oneDimShape = dynamic_cast(m_annotation); AnnotationTwoDimensionalShape* twoDimShape = dynamic_cast(m_annotation); if (oneDimShape != NULL) { setCoordinate(oneDimShape->getEndCoordinate(), mouseWindowX, mouseWindowY); } else if (twoDimShape != NULL) { const float minX = std::min(m_mousePressWindowX, mouseWindowX); const float maxX = std::max(m_mousePressWindowX, mouseWindowX); const float minY = std::min(m_mousePressWindowY, mouseWindowY); const float maxY = std::max(m_mousePressWindowY, mouseWindowY); const float x = (minX + maxX) / 2.0; const float y = (minY + maxY) / 2.0; const float width = maxX - minX; const float height = maxY - minY; const float relativeWidth = 100.0 * ((m_windowWidth > 0.0) ? (width / static_cast(m_windowWidth)) : 0.01); const float relativeHeight = 100.0 * ((m_windowHeight > 0.0) ? (height / static_cast(m_windowHeight)) : 0.01); AnnotationCoordinate* coord = twoDimShape->getCoordinate(); setCoordinate(coord, x, y); twoDimShape->setWidth(relativeWidth); twoDimShape->setHeight(relativeHeight); } else { CaretAssert(0); } } /** * Set the given coordinate to the XY-location. * * @param coordinate * Coordinate that is set. * @param x * Mouse window X-coordinate * @param y * Mouse window Y-coordinate */ void UserInputModeAnnotations::NewMouseDragCreateAnnotation::setCoordinate(AnnotationCoordinate* coordinate, const int32_t x, const int32_t y) { const float relativeX = 100.0 * ((m_windowWidth > 0.0) ? (x / m_windowWidth) : 0.01); const float relativeY = 100.0 * ((m_windowHeight > 0.0) ? (y / m_windowHeight) : 0.01); coordinate->setXYZ(relativeX, relativeY, 0.0); } /** * @return New annotation being drawn by the user. */ const Annotation* UserInputModeAnnotations::NewMouseDragCreateAnnotation::getAnnotation() const { return m_annotation; } connectome-workbench-1.4.2/src/GuiQt/UserInputModeAnnotations.h000066400000000000000000000225531360521144700246140ustar00rootroot00000000000000#ifndef __USER_INPUT_MODE_ANNOTATIONS_H__ #define __USER_INPUT_MODE_ANNOTATIONS_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AnnotationCoordinateSpaceEnum.h" #include "AnnotationSizingHandleTypeEnum.h" #include "AnnotationSurfaceOffsetVectorTypeEnum.h" #include "AnnotationTypeEnum.h" #include "CaretPointer.h" #include "EventListenerInterface.h" #include "StructureEnum.h" #include "UserInputModeView.h" namespace caret { class Annotation; class AnnotationCoordinate; class AnnotationCoordinateInformation; class AnnotationFile; class AnnotationOneDimensionalShape; class AnnotationTwoDimensionalShape; class KeyEvent; class MouseEvent; class SelectionItemAnnotation; class UserInputModeAnnotationsWidget; class UserInputModeAnnotations : public UserInputModeView, EventListenerInterface { public: /** * Annotation mode */ enum Mode { /** Mouse creates an annotation by clicking */ MODE_NEW_WITH_CLICK, /** Mouse creates an annotation by draggin from one point to another */ MODE_NEW_WITH_DRAG, /** User selected Paste from Edit Menu, user may need to click mouse to paste the annotation */ MODE_PASTE, /** User selected Paste Special from Edit Menu, user may need to click mouse to paste the annotation */ MODE_PASTE_SPECIAL, /** Mouse selects annotation */ MODE_SELECT, /** Set coordinate one in annotation*/ MODE_SET_COORDINATE_ONE, /** Set coordinate two in annotation*/ MODE_SET_COORDINATE_TWO }; UserInputModeAnnotations(const int32_t windowIndex); virtual ~UserInputModeAnnotations(); virtual void receiveEvent(Event* event); virtual void initialize(); virtual void finish(); virtual void update(); Mode getMode() const; virtual bool keyPressEvent(const KeyEvent& /*keyEvent*/) override; virtual void mouseLeftDoubleClick(const MouseEvent& mouseEvent); virtual void mouseLeftClick(const MouseEvent& mouseEvent); virtual void mouseLeftClickWithShift(const MouseEvent& mouseEvent); virtual void mouseLeftDrag(const MouseEvent& mouseEvent); virtual void mouseLeftDragWithAlt(const MouseEvent& mouseEvent); virtual void mouseLeftDragWithCtrl(const MouseEvent& mouseEvent); virtual void mouseLeftDragWithCtrlShift(const MouseEvent& mouseEvent); virtual void mouseLeftDragWithShift(const MouseEvent& mouseEvent); virtual void mouseLeftPress(const MouseEvent& mouseEvent); virtual void mouseLeftRelease(const MouseEvent& mouseEvent); virtual void mouseMove(const MouseEvent& mouseEvent); virtual void mouseMoveWithShift(const MouseEvent& mouseEvent); virtual void showContextMenu(const MouseEvent& mouseEvent, const QPoint& menuPosition, BrainOpenGLWidget* openGLWidget); virtual CursorEnum::Enum getCursor() const; virtual AString toString() const; virtual void processEditMenuItemSelection(const BrainBrowserWindowEditMenuItemEnum::Enum editMenuItem); virtual void getEnabledEditMenuItems(std::vector& enabledEditMenuItemsOut, AString& redoMenuItemSuffixTextOut, AString& undoMenuItemSuffixTextOut, AString& pasteTextOut, AString& pasteSpecialTextOut); // ADD_NEW_METHODS_HERE private: class NewMouseDragCreateAnnotation { public: NewMouseDragCreateAnnotation(AnnotationFile* annotationFile, const AnnotationCoordinateSpaceEnum::Enum annotationSpace, const AnnotationTypeEnum::Enum annotationType, const MouseEvent& mousePressEvent); ~NewMouseDragCreateAnnotation(); void update(const int32_t mouseWindowX, const int32_t mouseWindowY); void setCoordinate(AnnotationCoordinate* coordinate, const int32_t x, const int32_t y); const Annotation* getAnnotation() const; private: AnnotationFile* m_annotationFile; Annotation* m_annotation; int32_t m_mousePressWindowX; int32_t m_mousePressWindowY; int32_t m_windowOriginX; int32_t m_windowOriginY; float m_windowWidth; float m_windowHeight; }; class NewAnnotationFileSpaceAndType { public: NewAnnotationFileSpaceAndType(AnnotationFile* annotationFile, AnnotationCoordinateSpaceEnum::Enum annotationSpace, AnnotationTypeEnum::Enum annotationType) : m_annotationFile(annotationFile), m_annotationSpace(annotationSpace), m_annotationType(annotationType) { } AnnotationFile* m_annotationFile; AnnotationCoordinateSpaceEnum::Enum m_annotationSpace; AnnotationTypeEnum::Enum m_annotationType; }; UserInputModeAnnotations(const UserInputModeAnnotations&); UserInputModeAnnotations& operator=(const UserInputModeAnnotations&); void setMode(const Mode mode); void processModeNewMouseLeftClick(const MouseEvent& mouseEvent); void processMouseSelectAnnotation(const MouseEvent& mouseEvent, const bool shiftKeyDownFlag); void processModeSetCoordinate(const MouseEvent& mouseEvent); void setAnnotationUnderMouse(const MouseEvent& mouseEvent, SelectionItemAnnotation* annotationIDIn); void createNewAnnotationFromMouseDrag(const MouseEvent& mouseEvent); void userDrawingAnnotationFromMouseDrag(const MouseEvent& mouseEvent); void selectAnnotation(Annotation* annotation); Annotation* getSingleSelectedAnnotation(); void cutAnnotation(); void deleteSelectedAnnotations(); void processSelectAllAnnotations(); void resetAnnotationUnderMouse(); bool isEditMenuValid() const; void pasteAnnotationFromAnnotationClipboard(const MouseEvent& mouseEvent); void pasteAnnotationFromAnnotationClipboardAndChangeSpace(const MouseEvent& mouseEvent); // bool pasteOneDimensionalShape(AnnotationOneDimensionalShape* oneDimShape, // AnnotationCoordinateInformation& coordInfo); UserInputModeAnnotationsWidget* m_annotationToolsWidget; Mode m_mode; const int32_t m_browserWindowIndex; Annotation* m_annotationUnderMouse; AnnotationSizingHandleTypeEnum::Enum m_annotationUnderMouseSizeHandleType; Annotation* m_annotationBeingDragged; AnnotationSizingHandleTypeEnum::Enum m_annotationBeingDraggedHandleType; CaretPointer m_modeNewAnnotationFileSpaceAndType; CaretPointer m_newAnnotationCreatingWithMouseDrag; bool m_allowMultipleSelectionModeFlag; //static const AString s_pasteSpecialMenuItemText; // ADD_NEW_MEMBERS_HERE /* * Some private methods are accessed by this friend class */ friend class UserInputModeAnnotationsContextMenu; friend class UserInputModeAnnotationsWidget; }; #ifdef __USER_INPUT_MODE_ANNOTATIONS_DECLARE__ //const AString UserInputModeAnnotations::s_pasteSpecialMenuItemText = "Paste and Change Space"; #endif // __USER_INPUT_MODE_ANNOTATIONS_DECLARE__ } // namespace #endif //__USER_INPUT_MODE_ANNOTATIONS_H__ connectome-workbench-1.4.2/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx000066400000000000000000000526331360521144700273630ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __USER_INPUT_MODE_ANNOTATIONS_CONTEXT_MENU_DECLARE__ #include "UserInputModeAnnotationsContextMenu.h" #undef __USER_INPUT_MODE_ANNOTATIONS_CONTEXT_MENU_DECLARE__ #include #include #include "AnnotationCoordinate.h" #include "AnnotationCreateDialog.h" #include "AnnotationFile.h" #include "AnnotationManager.h" #include "AnnotationOneDimensionalShape.h" #include "AnnotationRedoUndoCommand.h" #include "AnnotationText.h" #include "AnnotationTextEditorDialog.h" #include "Brain.h" #include "BrainOpenGLWidget.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "DisplayPropertiesAnnotation.h" #include "EventBrowserTabGetAll.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "MathFunctions.h" #include "SelectionItemAnnotation.h" #include "SelectionManager.h" #include "UserInputModeAnnotations.h" #include "WuQDataEntryDialog.h" #include "WuQMessageBox.h" using namespace caret; /** * \class caret::UserInputModeAnnotationsContextMenu * \brief Context (pop-up) menu for User Input Annotations Mode. * \ingroup GuiQt */ /** * Constructor. * * @param mouseEvent * The mouse event that caused display of this menu. * @param selectionManager * The selection manager, provides data under the cursor. * @param browserTabContent * Content of browser tab. * @param parentOpenGLWidget * Parent OpenGL Widget on which the menu is displayed. */ UserInputModeAnnotationsContextMenu::UserInputModeAnnotationsContextMenu(UserInputModeAnnotations* userInputModeAnnotations, const MouseEvent& mouseEvent, SelectionManager* selectionManager, BrowserTabContent* browserTabContent, BrainOpenGLWidget* parentOpenGLWidget) : QMenu(parentOpenGLWidget), m_userInputModeAnnotations(userInputModeAnnotations), m_mouseEvent(mouseEvent), m_selectionManager(selectionManager), m_browserTabContent(browserTabContent), m_parentOpenGLWidget(parentOpenGLWidget), m_newAnnotationCreatedByContextMenu(NULL) { CaretAssert(m_userInputModeAnnotations); const int32_t browserWindexIndex = m_mouseEvent.getBrowserWindowIndex(); std::vector > selectedAnnotations; AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); annotationManager->getAnnotationsSelectedForEditingIncludingLabels(browserWindexIndex, selectedAnnotations); m_annotationFile = NULL; m_annotation = NULL; bool allSelectedAnnotationsDeletableFlag = true; if (selectedAnnotations.empty()) { allSelectedAnnotationsDeletableFlag = false; } m_threeDimCoordAnnotations.clear(); for (std::vector >::iterator iter = selectedAnnotations.begin(); iter != selectedAnnotations.end(); iter++) { Annotation* ann = iter->first; CaretAssert(ann); bool threeDimCoordFlag = false; switch (ann->getCoordinateSpace()) { case AnnotationCoordinateSpaceEnum::CHART: threeDimCoordFlag = true; break; case AnnotationCoordinateSpaceEnum::SPACER: break; case AnnotationCoordinateSpaceEnum::STEREOTAXIC: threeDimCoordFlag = true; break; case AnnotationCoordinateSpaceEnum::SURFACE: threeDimCoordFlag = true; break; case AnnotationCoordinateSpaceEnum::TAB: break; case AnnotationCoordinateSpaceEnum::VIEWPORT: break; case AnnotationCoordinateSpaceEnum::WINDOW: break; } if (threeDimCoordFlag) { m_threeDimCoordAnnotations.push_back(ann); } if ( ! ann->testProperty(Annotation::Property::DELETION)) { allSelectedAnnotationsDeletableFlag = false; } } const bool haveThreeDimCoordAnnotationsFlag = ( ! m_threeDimCoordAnnotations.empty()); bool oneDeletableAnnotationSelectedFlag = false; if (selectedAnnotations.size() == 1) { CaretAssertVectorIndex(selectedAnnotations, 0); m_annotationFile = selectedAnnotations[0].second; m_annotation = selectedAnnotations[0].first; if (m_annotation->testProperty(Annotation::Property::DELETION)) { oneDeletableAnnotationSelectedFlag = true; } } m_textAnnotation = NULL; if (m_annotation != NULL) { m_textAnnotation = dynamic_cast(m_annotation); } std::vector editMenuItemsEnabled; AString redoMenuItemSuffix; AString undoMenuItemSuffix; AString pasteText; AString pasteSpecialText; userInputModeAnnotations->getEnabledEditMenuItems(editMenuItemsEnabled, redoMenuItemSuffix, undoMenuItemSuffix, pasteText, pasteSpecialText); /* * Cut */ QAction* cutAction = addAction(BrainBrowserWindowEditMenuItemEnum::toGuiName(BrainBrowserWindowEditMenuItemEnum::CUT), this, SLOT(cutAnnnotation())); cutAction->setEnabled(oneDeletableAnnotationSelectedFlag); /* * Copy */ QAction* copyAction = addAction(BrainBrowserWindowEditMenuItemEnum::toGuiName(BrainBrowserWindowEditMenuItemEnum::COPY), this, SLOT(copyAnnotationToAnnotationClipboard())); copyAction->setEnabled(oneDeletableAnnotationSelectedFlag); /* * Delete */ QAction* deleteAction = addAction(BrainBrowserWindowEditMenuItemEnum::toGuiName(BrainBrowserWindowEditMenuItemEnum::DELETER), this, SLOT(deleteAnnotations())); deleteAction->setEnabled(allSelectedAnnotationsDeletableFlag); /* * Duplicate tab space annotation */ QMenu* duplicateMenu = createDuplicateTabSpaceAnnotationMenu(); if (duplicateMenu != NULL) { addMenu(duplicateMenu); } /* * Paste */ QAction* pasteAction = addAction(pasteText, this, SLOT(pasteAnnotationFromAnnotationClipboard())); pasteAction->setEnabled(annotationManager->isAnnotationOnClipboardValid()); /* * Paste Special */ QAction* pasteSpecialAction = addAction(pasteSpecialText, this, SLOT(pasteSpecialAnnotationFromAnnotationClipboard())); pasteSpecialAction->setEnabled(annotationManager->isAnnotationOnClipboardValid()); /* * Separator */ addSeparator(); /* * Select All annotations */ addAction(BrainBrowserWindowEditMenuItemEnum::toGuiName(BrainBrowserWindowEditMenuItemEnum::SELECT_ALL), this, SLOT(selectAllAnnotations())); /* * Separator */ addSeparator(); /* * Edit Text */ QAction* editTextAction = addAction("Edit Text...", this, SLOT(setAnnotationText())); editTextAction->setEnabled(m_textAnnotation != NULL); /* * Separator */ addSeparator(); /* * Turn off display in tabs */ QAction* turnOffTabDisplayAction = addAction("Turn Off Chart/Stereotaxic/Surface Annotation Display in Other Tabs", this, SLOT(turnOffDisplayInOtherTabs())); /* * Separator */ addSeparator(); /* * Turn on display in tabs */ QAction* turnOnTabDisplayAction = addAction("Turn On Chart/Stereotaxic/Surface Annotation Display in All Tabs", this, SLOT(turnOnDisplayInAllTabs())); turnOffTabDisplayAction->setEnabled(haveThreeDimCoordAnnotationsFlag); turnOnTabDisplayAction->setEnabled(haveThreeDimCoordAnnotationsFlag); /* * Turn on/off display in groups */ QAction* turnOnGroupDisplayAction = addAction("Turn On Chart/Stereotaxic/Surface Annotation Display in All Groups", this, SLOT(turnOnDisplayInAllGroups())); turnOnGroupDisplayAction->setEnabled(haveThreeDimCoordAnnotationsFlag); QMenu* turnOnInDisplayGroupMenu = createTurnOnInDisplayGroupMenu(); turnOnInDisplayGroupMenu->setEnabled(haveThreeDimCoordAnnotationsFlag); addMenu(turnOnInDisplayGroupMenu); /* * Separator */ addSeparator(); /* * Group annotations */ QAction* groupAction = addAction(AnnotationGroupingModeEnum::toGuiName(AnnotationGroupingModeEnum::GROUP), this, SLOT(applyGroupingGroup())); groupAction->setEnabled(annotationManager->isGroupingModeValid(browserWindexIndex, AnnotationGroupingModeEnum::GROUP)); /* * Ungroup annotations */ QAction* ungroupAction = addAction(AnnotationGroupingModeEnum::toGuiName(AnnotationGroupingModeEnum::UNGROUP), this, SLOT(applyGroupingUngroup())); ungroupAction->setEnabled(annotationManager->isGroupingModeValid(browserWindexIndex, AnnotationGroupingModeEnum::UNGROUP)); /* * Regroup annotations */ QAction* regroupAction = addAction(AnnotationGroupingModeEnum::toGuiName(AnnotationGroupingModeEnum::REGROUP), this, SLOT(applyGroupingRegroup())); regroupAction->setEnabled(annotationManager->isGroupingModeValid(browserWindexIndex, AnnotationGroupingModeEnum::REGROUP)); } /** * Destructor. */ UserInputModeAnnotationsContextMenu::~UserInputModeAnnotationsContextMenu() { } Annotation* UserInputModeAnnotationsContextMenu::getNewAnnotationCreatedByContextMenu() { return m_newAnnotationCreatedByContextMenu; } /** * Copy the annotation to the annotation clipboard. */ void UserInputModeAnnotationsContextMenu::copyAnnotationToAnnotationClipboard() { CaretAssert(m_annotationFile); CaretAssert(m_annotation); AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); annotationManager->copyAnnotationToClipboard(m_annotationFile, m_annotation); } /** * Cut the selected annotation. */ void UserInputModeAnnotationsContextMenu::cutAnnnotation() { m_userInputModeAnnotations->cutAnnotation(); } /** * Delete the annotation. */ void UserInputModeAnnotationsContextMenu::deleteAnnotations() { /* * Delete the annotation that is under the mouse */ AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); std::vector selectedAnnotations = annotationManager->getAnnotationsSelectedForEditing(m_mouseEvent.getBrowserWindowIndex()); if ( ! selectedAnnotations.empty()) { AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeDeleteAnnotations(selectedAnnotations); AString errorMessage; if ( ! annotationManager->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } /** * Paste the annotation from the annotation clipboard. */ void UserInputModeAnnotationsContextMenu::pasteAnnotationFromAnnotationClipboard() { m_userInputModeAnnotations->pasteAnnotationFromAnnotationClipboard(m_mouseEvent); } /** * Paste special the annotation from the annotation clipboard. */ void UserInputModeAnnotationsContextMenu::pasteSpecialAnnotationFromAnnotationClipboard() { m_userInputModeAnnotations->pasteAnnotationFromAnnotationClipboardAndChangeSpace(m_mouseEvent); } /** * Select all annotations in the window. */ void UserInputModeAnnotationsContextMenu::selectAllAnnotations() { m_userInputModeAnnotations->processSelectAllAnnotations(); } /** * Set the text for an annotation. */ void UserInputModeAnnotationsContextMenu::setAnnotationText() { CaretAssert(m_textAnnotation); AnnotationTextEditorDialog ted(m_textAnnotation, this); /* * Note: Y==0 is at top for widget. * Y==0 is at bottom for OpenGL mouse x,y */ QPoint diaglogPos(this->pos().x(), this->pos().y() + 20); ted.move(diaglogPos); ted.exec(); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** * Turn off display of annotation in other tabs. */ void UserInputModeAnnotationsContextMenu::turnOffDisplayInOtherTabs() { for (std::vector::iterator iter = m_threeDimCoordAnnotations.begin(); iter != m_threeDimCoordAnnotations.end(); iter++) { (*iter)->setItemDisplaySelectedInOneTab(m_browserTabContent->getTabNumber()); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Turn on display of annotation in all tabs. */ void UserInputModeAnnotationsContextMenu::turnOnDisplayInAllTabs() { for (std::vector::iterator iter = m_threeDimCoordAnnotations.begin(); iter != m_threeDimCoordAnnotations.end(); iter++) { (*iter)->setItemDisplaySelectedInAllTabs(); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Turn on display of annotation in all groups. */ void UserInputModeAnnotationsContextMenu::turnOnDisplayInAllGroups() { for (std::vector::iterator iter = m_threeDimCoordAnnotations.begin(); iter != m_threeDimCoordAnnotations.end(); iter++) { (*iter)->setItemDisplaySelectedInAllGroups(); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Turn on display of annotation in a group and off in other groups * * @param action * Menu action that was selected. */ void UserInputModeAnnotationsContextMenu::turnOnDisplayInGroup(QAction* action) { const int intValue = action->data().toInt(); bool validFlag = false; DisplayGroupEnum::Enum displayGroup = DisplayGroupEnum::fromIntegerCode(intValue, &validFlag); if ( ! validFlag) { CaretAssert(0); return; } if (displayGroup == DisplayGroupEnum::DISPLAY_GROUP_TAB) { CaretAssert(0); // TAB NOT ALLOWED return; } for (std::vector::iterator iter = m_threeDimCoordAnnotations.begin(); iter != m_threeDimCoordAnnotations.end(); iter++) { (*iter)->setItemDisplaySelectedInOneGroup(displayGroup); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * @return New menu for turning on in display group */ QMenu* UserInputModeAnnotationsContextMenu::createTurnOnInDisplayGroupMenu() { QMenu* menu = new QMenu("Turn On Chart/Stereotaxic/Surface Annotation Only in Group"); QObject::connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(turnOnDisplayInGroup(QAction*))); std::vector groupEnums; DisplayGroupEnum::getAllEnumsExceptTab(groupEnums); for (std::vector::iterator iter = groupEnums.begin(); iter != groupEnums.end(); iter++) { const DisplayGroupEnum::Enum dg = *iter; QAction* action = menu->addAction(DisplayGroupEnum::toGuiName(dg)); action->setData((int)DisplayGroupEnum::toIntegerCode(dg)); } return menu; } /** * @return New menu for duplicating a tab annotation. * NULL is returned if no other tabs. */ QMenu* UserInputModeAnnotationsContextMenu::createDuplicateTabSpaceAnnotationMenu() { if (m_annotation == NULL) { return NULL; } EventBrowserTabGetAll tabIndicesEvent; EventManager::get()->sendEvent(tabIndicesEvent.getPointer()); const std::vector allTabs = tabIndicesEvent.getAllBrowserTabs(); bool menuValidFlag = false; if (m_annotation->getCoordinateSpace() == AnnotationCoordinateSpaceEnum::TAB) { if (allTabs.size() > 1) { menuValidFlag = true; } } QMenu* menu = new QMenu("Duplicate to Tab"); QObject::connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(duplicateAnnotationSelected(QAction*))); if (menuValidFlag) { for (BrowserTabContent* tabContent : allTabs) { if (tabContent->getTabNumber() != m_annotation->getTabIndex()) { QAction* action = menu->addAction(tabContent->getTabName()); action->setData((int)tabContent->getTabNumber()); } } } else { menu->setEnabled(false); } return menu; } /** * Gets called when a selection is made from Duplicate Tab Annotation menu * * @param action * Action selected from Duplicate menu */ void UserInputModeAnnotationsContextMenu::duplicateAnnotationSelected(QAction* action) { CaretAssert(action); CaretAssert(m_annotationFile); CaretAssert(m_annotation); AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); const int32_t tabIndex = action->data().toInt(); Annotation* annCopy = m_annotation->clone(); annCopy->setTabIndex(tabIndex); DisplayPropertiesAnnotation* dpa = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotation(); dpa->updateForNewAnnotation(annCopy); AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeDuplicateAnnotation(m_annotationFile, annCopy); AString errorMessage; if ( ! annotationManager->applyCommand(undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } annotationManager->selectAnnotationForEditing(m_mouseEvent.getBrowserWindowIndex(), AnnotationManager::SELECTION_MODE_SINGLE, false, annCopy); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** * Group annotations. */ void UserInputModeAnnotationsContextMenu::applyGroupingGroup() { applyGrouping(AnnotationGroupingModeEnum::GROUP); } /** * Ungroup annotations. */ void UserInputModeAnnotationsContextMenu::applyGroupingRegroup() { applyGrouping(AnnotationGroupingModeEnum::REGROUP); } /** * Regroup annotations. */ void UserInputModeAnnotationsContextMenu::applyGroupingUngroup() { applyGrouping(AnnotationGroupingModeEnum::UNGROUP); } /** * Apply grouping selection. * * @param grouping * Selected grouping. */ void UserInputModeAnnotationsContextMenu::applyGrouping(const AnnotationGroupingModeEnum::Enum grouping) { AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; if ( ! annMan->applyGroupingMode(m_mouseEvent.getBrowserWindowIndex(), grouping, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } connectome-workbench-1.4.2/src/GuiQt/UserInputModeAnnotationsContextMenu.h000066400000000000000000000100031360521144700267710ustar00rootroot00000000000000#ifndef __USER_INPUT_MODE_ANNOTATIONS_CONTEXT_MENU_H__ #define __USER_INPUT_MODE_ANNOTATIONS_CONTEXT_MENU_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AnnotationGroupingModeEnum.h" #include "MouseEvent.h" namespace caret { class Annotation; class AnnotationFile; class AnnotationText; class BrainOpenGLWidget; class BrowserTabContent; class SelectionManager; class UserInputModeAnnotations; class UserInputModeAnnotationsContextMenu : public QMenu { Q_OBJECT public: UserInputModeAnnotationsContextMenu(UserInputModeAnnotations* userInputModeAnnotations, const MouseEvent& mouseEvent, SelectionManager* selectionManager, BrowserTabContent* browserTabContent, BrainOpenGLWidget* parentOpenGLWidget); virtual ~UserInputModeAnnotationsContextMenu(); Annotation* getNewAnnotationCreatedByContextMenu(); // ADD_NEW_METHODS_HERE private slots: void copyAnnotationToAnnotationClipboard(); void cutAnnnotation(); void deleteAnnotations(); void pasteAnnotationFromAnnotationClipboard(); void pasteSpecialAnnotationFromAnnotationClipboard(); void selectAllAnnotations(); void setAnnotationText(); void turnOffDisplayInOtherTabs(); void turnOnDisplayInAllTabs(); void turnOnDisplayInAllGroups(); void turnOnDisplayInGroup(QAction*); void applyGroupingGroup(); void applyGroupingRegroup(); void applyGroupingUngroup(); void duplicateAnnotationSelected(QAction*); private: UserInputModeAnnotationsContextMenu(const UserInputModeAnnotationsContextMenu&); UserInputModeAnnotationsContextMenu& operator=(const UserInputModeAnnotationsContextMenu&); void applyGrouping(const AnnotationGroupingModeEnum::Enum grouping); QMenu* createTurnOnInDisplayGroupMenu(); QMenu* createDuplicateTabSpaceAnnotationMenu(); UserInputModeAnnotations* m_userInputModeAnnotations; /* * NOT a reference. Need to COPY as its source may be deleted. */ const MouseEvent m_mouseEvent; SelectionManager* m_selectionManager; BrowserTabContent* m_browserTabContent; BrainOpenGLWidget* m_parentOpenGLWidget; AnnotationFile* m_annotationFile; std::vector m_threeDimCoordAnnotations; Annotation* m_annotation; AnnotationText* m_textAnnotation; Annotation* m_newAnnotationCreatedByContextMenu; // ADD_NEW_MEMBERS_HERE }; #ifdef __USER_INPUT_MODE_ANNOTATIONS_CONTEXT_MENU_DECLARE__ // #endif // __USER_INPUT_MODE_ANNOTATIONS_CONTEXT_MENU_DECLARE__ } // namespace #endif //__USER_INPUT_MODE_ANNOTATIONS_CONTEXT_MENU_H__ connectome-workbench-1.4.2/src/GuiQt/UserInputModeAnnotationsWidget.cxx000066400000000000000000000335611360521144700263340ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __USER_INPUT_MODE_ANNOTATIONS_WIDGET_DECLARE__ #include "UserInputModeAnnotationsWidget.h" #undef __USER_INPUT_MODE_ANNOTATIONS_WIDGET_DECLARE__ #include #include #include #include #include #include #include "AnnotationCoordinateSpaceWidget.h" #include "AnnotationCoordinateWidget.h" #include "AnnotationColorWidget.h" #include "AnnotationDeleteWidget.h" #include "AnnotationFontWidget.h" #include "AnnotationFormatWidget.h" #include "AnnotationInsertNewWidget.h" #include "AnnotationLine.h" #include "AnnotationLineArrowTipsWidget.h" #include "AnnotationManager.h" #include "AnnotationOneDimensionalShape.h" #include "AnnotationRedoUndoWidget.h" #include "AnnotationRotationWidget.h" #include "AnnotationText.h" #include "AnnotationTextAlignmentWidget.h" #include "AnnotationTextEditorWidget.h" #include "AnnotationTextOrientationWidget.h" #include "AnnotationWidthHeightWidget.h" #include "Brain.h" #include "CaretAssert.h" #include "EventAnnotationCreateNewType.h" #include "EventBrainReset.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "UserInputModeAnnotations.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::UserInputModeAnnotationsWidget * \brief Toolbar widget for annotations. * \ingroup GuiQt */ /** * Constructor. * * @param inputModeAnnotations * Annotation mode input processor. * @param browserWindowIndex * Index of browser window using this widget. */ UserInputModeAnnotationsWidget::UserInputModeAnnotationsWidget(UserInputModeAnnotations* inputModeAnnotations, const int32_t browserWindowIndex) : QWidget(), m_browserWindowIndex(browserWindowIndex), m_inputModeAnnotations(inputModeAnnotations) { CaretAssert(inputModeAnnotations); m_textEditorWidget = new AnnotationTextEditorWidget(m_browserWindowIndex); m_lineArrowTipsWidget = new AnnotationLineArrowTipsWidget(m_browserWindowIndex); m_fontWidget = new AnnotationFontWidget(AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, m_browserWindowIndex); m_colorWidget = new AnnotationColorWidget(AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, m_browserWindowIndex); m_textAlignmentWidget = new AnnotationTextAlignmentWidget(m_browserWindowIndex); m_textOrientationWidget = new AnnotationTextOrientationWidget(m_browserWindowIndex); m_coordinateSpaceWidget = new AnnotationCoordinateSpaceWidget(m_browserWindowIndex); m_coordinateOneWidget = new AnnotationCoordinateWidget(AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, AnnotationCoordinateWidget::COORDINATE_ONE, m_browserWindowIndex); m_coordinateTwoWidget = new AnnotationCoordinateWidget(AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, AnnotationCoordinateWidget::COORDINATE_TWO, m_browserWindowIndex); m_widthHeightWidget = new AnnotationWidthHeightWidget(AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, m_browserWindowIndex); m_rotationWidget = new AnnotationRotationWidget(m_browserWindowIndex); m_formatWidget = new AnnotationFormatWidget(m_browserWindowIndex); m_insertDeleteWidget = new AnnotationInsertNewWidget(m_browserWindowIndex); m_deleteWidget = new AnnotationDeleteWidget(m_browserWindowIndex); m_redoUndoWidget = new AnnotationRedoUndoWidget(m_browserWindowIndex); /* * Connect signals for setting a coordinate with the mouse. */ QObject::connect(m_coordinateOneWidget, SIGNAL(signalSelectCoordinateWithMouse()), this, SLOT(selectCoordinateOneWithMouse())); QObject::connect(m_coordinateTwoWidget, SIGNAL(signalSelectCoordinateWithMouse()), this, SLOT(selectCoordinateTwoWithMouse())); /* * Layout top row of widgets */ QWidget* topRowWidget = new QWidget(); QHBoxLayout* topRowLayout = new QHBoxLayout(topRowWidget); WuQtUtilities::setLayoutSpacingAndMargins(topRowLayout, 2, 2); topRowLayout->addWidget(m_colorWidget, 0, Qt::AlignTop); topRowLayout->addWidget(WuQtUtilities::createVerticalLineWidget()); topRowLayout->addWidget(m_lineArrowTipsWidget, 0, Qt::AlignTop); topRowLayout->addWidget(WuQtUtilities::createVerticalLineWidget()); topRowLayout->addWidget(m_textEditorWidget, 100, Qt::AlignTop); topRowLayout->addWidget(WuQtUtilities::createVerticalLineWidget()); topRowLayout->addWidget(m_fontWidget, 0, Qt::AlignTop); topRowLayout->addWidget(WuQtUtilities::createVerticalLineWidget()); topRowLayout->addWidget(m_textAlignmentWidget, 0, Qt::AlignTop); topRowLayout->addWidget(WuQtUtilities::createVerticalLineWidget()); topRowLayout->addWidget(m_textOrientationWidget, 0, Qt::AlignTop); topRowLayout->addWidget(WuQtUtilities::createVerticalLineWidget()); topRowLayout->addWidget(m_insertDeleteWidget, 0, Qt::AlignTop); topRowLayout->addWidget(WuQtUtilities::createVerticalLineWidget()); topRowLayout->addWidget(m_deleteWidget, 0, Qt::AlignTop); topRowLayout->addWidget(WuQtUtilities::createVerticalLineWidget()); topRowLayout->addWidget(m_formatWidget, 0, Qt::AlignTop); topRowLayout->addWidget(WuQtUtilities::createVerticalLineWidget()); topRowLayout->addWidget(m_redoUndoWidget, 0, Qt::AlignTop); topRowLayout->addStretch(); topRowWidget->setFixedHeight(topRowWidget->sizeHint().height()); /* * Layout bottom row of widgets */ QHBoxLayout* bottomRowLayout = new QHBoxLayout(); WuQtUtilities::setLayoutSpacingAndMargins(bottomRowLayout, 2, 2); bottomRowLayout->addWidget(m_coordinateSpaceWidget); bottomRowLayout->addWidget(WuQtUtilities::createVerticalLineWidget()); bottomRowLayout->addWidget(m_coordinateOneWidget); bottomRowLayout->addWidget(WuQtUtilities::createVerticalLineWidget()); bottomRowLayout->addWidget(m_coordinateTwoWidget); bottomRowLayout->addWidget(WuQtUtilities::createVerticalLineWidget()); bottomRowLayout->addWidget(m_widthHeightWidget); bottomRowLayout->addWidget(WuQtUtilities::createVerticalLineWidget()); bottomRowLayout->addWidget(m_rotationWidget); bottomRowLayout->addStretch(); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 2); layout->addWidget(topRowWidget); layout->addWidget(WuQtUtilities::createHorizontalLineWidget()); layout->addLayout(bottomRowLayout); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BRAIN_RESET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_CREATE_NEW_TYPE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); setFixedHeight(sizeHint().height()); } /** * Destructor. */ UserInputModeAnnotationsWidget::~UserInputModeAnnotationsWidget() { EventManager::get()->removeAllEventsFromListener(this); } /** * Receive an event. * * @param event * The event that the receive can respond to. */ void UserInputModeAnnotationsWidget::receiveEvent(Event* event) { bool updateAnnotationWidgetsFlag = false; if (event->getEventType() == EventTypeEnum::EVENT_BRAIN_RESET) { EventBrainReset* brainEvent = dynamic_cast(event); CaretAssert(brainEvent); updateAnnotationWidgetsFlag = true; brainEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_CREATE_NEW_TYPE) { EventAnnotationCreateNewType* annotationEvent = dynamic_cast(event); CaretAssert(annotationEvent); updateAnnotationWidgetsFlag = true; annotationEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* updateEvent = dynamic_cast(event); CaretAssert(updateEvent); updateAnnotationWidgetsFlag = true; updateEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE) { updateAnnotationWidgetsFlag = true; } else { return; } if (! updateAnnotationWidgetsFlag) { return; } updateWidget(); } /** * Select coordinate one with the mouse. */ void UserInputModeAnnotationsWidget::selectCoordinateOneWithMouse() { m_inputModeAnnotations->setMode(UserInputModeAnnotations::MODE_SET_COORDINATE_ONE); } /** * Select coordinate two with the mouse. */ void UserInputModeAnnotationsWidget::selectCoordinateTwoWithMouse() { m_inputModeAnnotations->setMode(UserInputModeAnnotations::MODE_SET_COORDINATE_TWO); } /** * Update the widget. */ void UserInputModeAnnotationsWidget::updateWidget() { /* * Show the proper widget */ switch (m_inputModeAnnotations->getMode()) { case UserInputModeAnnotations::MODE_NEW_WITH_CLICK: break; case UserInputModeAnnotations::MODE_NEW_WITH_DRAG: break; case UserInputModeAnnotations::MODE_PASTE: break; case UserInputModeAnnotations::MODE_PASTE_SPECIAL: break; case UserInputModeAnnotations::MODE_SELECT: break; case UserInputModeAnnotations::MODE_SET_COORDINATE_ONE: break; case UserInputModeAnnotations::MODE_SET_COORDINATE_TWO: break; } AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); std::vector selectedAnnotations = annotationManager->getAnnotationsSelectedForEditing(m_browserWindowIndex); std::vector lineAnnotations; std::vector textAnnotations; std::vector fontStyleAnnotations; std::vector twoDimAnnotations; std::vector oneDimAnnotations; for (std::vector::iterator iter = selectedAnnotations.begin(); iter != selectedAnnotations.end(); iter++) { Annotation* ann = *iter; CaretAssert(ann); AnnotationText* annText = dynamic_cast(ann); if (annText != NULL) { textAnnotations.push_back(annText); } AnnotationFontAttributesInterface* annFontStyle = dynamic_cast(ann); if (annFontStyle != NULL) { fontStyleAnnotations.push_back(annFontStyle); } AnnotationOneDimensionalShape* annOne = dynamic_cast(ann); if (annOne != NULL) { oneDimAnnotations.push_back(annOne); } AnnotationTwoDimensionalShape* annTwo= dynamic_cast(ann); if (annTwo != NULL) { twoDimAnnotations.push_back(annTwo); } AnnotationLine* annLine = dynamic_cast(ann); if (annLine != NULL) { lineAnnotations.push_back(annLine); } } m_coordinateSpaceWidget->updateContent(selectedAnnotations); m_fontWidget->updateContent(fontStyleAnnotations); m_textEditorWidget->updateContent(textAnnotations); m_colorWidget->updateContent(selectedAnnotations); m_lineArrowTipsWidget->updateContent(lineAnnotations); m_textAlignmentWidget->updateContent(textAnnotations); m_textOrientationWidget->updateContent(textAnnotations); m_widthHeightWidget->updateContent(twoDimAnnotations); m_rotationWidget->updateContent(selectedAnnotations); //twoDimAnnotations); m_insertDeleteWidget->updateContent(); m_deleteWidget->updateContent(); Annotation* coordEditAnnotation = NULL; AnnotationOneDimensionalShape* coordEditOneDimAnnotation = NULL; if (selectedAnnotations.size() == 1) { coordEditAnnotation = selectedAnnotations[0]; coordEditOneDimAnnotation = dynamic_cast(coordEditAnnotation); } m_coordinateOneWidget->updateContent(coordEditAnnotation); if (coordEditOneDimAnnotation != NULL) { m_coordinateTwoWidget->updateContent(coordEditOneDimAnnotation); m_coordinateTwoWidget->setVisible(true); } else { m_coordinateTwoWidget->setVisible(false); } m_redoUndoWidget->updateContent(); } connectome-workbench-1.4.2/src/GuiQt/UserInputModeAnnotationsWidget.h000066400000000000000000000075201360521144700257550ustar00rootroot00000000000000#ifndef __USER_INPUT_MODE_ANNOTATIONS_WIDGET_H__ #define __USER_INPUT_MODE_ANNOTATIONS_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "EventListenerInterface.h" class QComboBox; namespace caret { class Annotation; class AnnotationColorWidget; class AnnotationCoordinateSpaceWidget; class AnnotationCoordinateWidget; class AnnotationDeleteWidget; class AnnotationFontWidget; class AnnotationFormatWidget; class AnnotationInsertNewWidget; class AnnotationLineArrowTipsWidget; class AnnotationRedoUndoWidget; class AnnotationRotationWidget; class AnnotationTextAlignmentWidget; class AnnotationTextEditorWidget; class AnnotationTextOrientationWidget; class AnnotationWidthHeightWidget; class UserInputModeAnnotations; class UserInputModeAnnotationsWidget : public QWidget, public EventListenerInterface { Q_OBJECT public: UserInputModeAnnotationsWidget(UserInputModeAnnotations* inputModeAnnotations, const int32_t browserWindowIndex); virtual ~UserInputModeAnnotationsWidget(); virtual void receiveEvent(Event* event); void updateWidget(); // ADD_NEW_METHODS_HERE private slots: void selectCoordinateOneWithMouse(); void selectCoordinateTwoWithMouse(); private: UserInputModeAnnotationsWidget(const UserInputModeAnnotationsWidget&); UserInputModeAnnotationsWidget& operator=(const UserInputModeAnnotationsWidget&); QWidget* createInsertMenuToolButton(); QWidget* createTextEditorWidget(); const int32_t m_browserWindowIndex; UserInputModeAnnotations* m_inputModeAnnotations; AnnotationCoordinateSpaceWidget* m_coordinateSpaceWidget; AnnotationCoordinateWidget* m_coordinateOneWidget; AnnotationCoordinateWidget* m_coordinateTwoWidget; AnnotationWidthHeightWidget* m_widthHeightWidget; AnnotationRotationWidget* m_rotationWidget; AnnotationLineArrowTipsWidget* m_lineArrowTipsWidget; AnnotationFontWidget* m_fontWidget; AnnotationColorWidget* m_colorWidget; AnnotationTextAlignmentWidget* m_textAlignmentWidget; AnnotationFormatWidget* m_formatWidget; AnnotationTextEditorWidget* m_textEditorWidget; AnnotationTextOrientationWidget* m_textOrientationWidget; AnnotationInsertNewWidget* m_insertDeleteWidget; AnnotationDeleteWidget* m_deleteWidget; AnnotationRedoUndoWidget* m_redoUndoWidget; // ADD_NEW_MEMBERS_HERE }; #ifdef __USER_INPUT_MODE_ANNOTATIONS_WIDGET_DECLARE__ // #endif // __USER_INPUT_MODE_ANNOTATIONS_WIDGET_DECLARE__ } // namespace #endif //__USER_INPUT_MODE_ANNOTATIONS_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/UserInputModeBorders.cxx000066400000000000000000000374711360521144700242770ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __USER_INPUT_MODE_BORDERS_DECLARE__ #include "UserInputModeBorders.h" #undef __USER_INPUT_MODE_BORDERS_DECLARE__ #include "Border.h" #include "BorderFile.h" #include "BorderPropertiesEditorDialog.h" #include "Brain.h" #include "BrainBrowserWindow.h" #include "BrainOpenGLWidget.h" #include "BrainOpenGLViewportContent.h" #include "BrowserTabContent.h" #include "CaretLogger.h" #include "CursorManager.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventUserInterfaceUpdate.h" #include "EventManager.h" #include "GuiManager.h" #include "SelectionItemBorderSurface.h" #include "SelectionManager.h" #include "Model.h" #include "ModelSurface.h" #include "MouseEvent.h" #include "Surface.h" #include "SurfaceProjectedItem.h" #include "SurfaceProjectionBarycentric.h" #include "UserInputModeBordersWidget.h" #include "UserInputModeView.h" #include "WuQMessageBox.h" using namespace caret; /** * \class caret::UserInputModeBorders * \brief Processing user input for Borders mode. * * Processes user input in Border mode which includes * drawing and editing borders. */ /** * Constructor. * * @param borderBeingDrawnByOpenGL * Border that is displayed in OpenGL area when a border is being drawn * @param windowIndex * Index of the browser window using this border processing. */ UserInputModeBorders::UserInputModeBorders(Border* borderBeingDrawnByOpenGL, const int32_t windowIndex) : UserInputModeView(UserInputModeEnum::BORDERS) { this->borderBeingDrawnByOpenGL = borderBeingDrawnByOpenGL; this->windowIndex = windowIndex; this->mode = MODE_DRAW; this->drawOperation = DRAW_OPERATION_CREATE; this->editOperation = EDIT_OPERATION_PROPERTIES; this->borderToolsWidget = new UserInputModeBordersWidget(this); setWidgetForToolBar(this->borderToolsWidget); } /** * Destructor. */ UserInputModeBorders::~UserInputModeBorders() { } /** * Draw a border point at the mouse coordinates. */ void UserInputModeBorders::drawPointAtMouseXY(BrainOpenGLWidget* openGLWidget, const int32_t mouseX, const int32_t mouseY) { SurfaceProjectedItem projectedItem; openGLWidget->performProjection(mouseX, mouseY, projectedItem); SurfaceProjectedItem* spi = new SurfaceProjectedItem(); AString txt; // if (projectedItem.isStereotaxicXYZValid()) { // spi->setStereotaxicXYZ(projectedItem.getStereotaxicXYZ()); // // txt += ("Projected Position: " // + AString::fromNumbers(projectedItem.getStereotaxicXYZ(), 3, ",")); // } if (projectedItem.getBarycentricProjection()->isValid()) { SurfaceProjectionBarycentric* bp = projectedItem.getBarycentricProjection(); txt += ("\nBarycentric Position: " + AString::fromNumbers(bp->getTriangleAreas(), 3, ",") + " " + AString::fromNumbers(bp->getTriangleNodes(), 3, ",")); SurfaceProjectionBarycentric* spb = spi->getBarycentricProjection(); spb->setProjectionSurfaceNumberOfNodes(bp->getProjectionSurfaceNumberOfNodes()); spb->setTriangleAreas(bp->getTriangleAreas()); spb->setTriangleNodes(bp->getTriangleNodes()); spb->setSignedDistanceAboveSurface(0.0); spb->setValid(true); } if (spi->isStereotaxicXYZValid() || spi->getBarycentricProjection()->isValid()) { if (borderBeingDrawnByOpenGL->getNumberOfPoints() == 0 || borderBeingDrawnByOpenGL->getStructure() == projectedItem.getStructure()) { spi->setStructure(projectedItem.getStructure()); this->borderBeingDrawnByOpenGL->addPoint(spi); } else { const AString prevName(StructureEnum::toGuiName(borderBeingDrawnByOpenGL->getStructure())); const AString newName(StructureEnum::toGuiName(projectedItem.getStructure())); WuQMessageBox::errorOk(borderToolsWidget, ("The last point added is on " + newName + " but all previous point(s) are on " + prevName + ". Either resume drawing on " + prevName + " or press the Reset button to remove all previous point(s) " "from " + prevName + " and draw on " + newName)); delete spi; } } else { delete spi; } CaretLogFiner(txt); } /** * Called when 'this' user input receiver is set * to receive events. */ void UserInputModeBorders::initialize() { this->borderToolsWidget->updateWidget(); } /** * Called when 'this' user input receiver is no * longer set to receive events. */ void UserInputModeBorders::finish() { } /** * Called to update the input receiver for various events. */ void UserInputModeBorders::update() { } /** * Update after borders changed. */ void UserInputModeBorders::updateAfterBordersChanged() { /* * Need to update all graphics windows and all border controllers. */ EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().addBorder().getPointer()); } /** * Get a description of this object's content. * @return String describing this object's content. */ AString UserInputModeBorders::toString() const { return "UserInputModeBorders"; } /** * @return the mode. */ UserInputModeBorders::Mode UserInputModeBorders::getMode() const { return this->mode; } /** * Set the mode. * @param mode * New value for mode. */ void UserInputModeBorders::setMode(const Mode mode) { if (this->mode != mode) { this->mode = mode; this->borderBeingDrawnByOpenGL->clear(); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(this->windowIndex).getPointer()); } this->borderToolsWidget->updateWidget(); } /** * @return the create operation. */ UserInputModeBorders::DrawOperation UserInputModeBorders::getDrawOperation() const { return this->drawOperation; } /** * Set the create operation. * @param createOperation * New value for create operation. */ void UserInputModeBorders::setDrawOperation(const DrawOperation drawOperation) { this->drawOperation = drawOperation; this->borderToolsWidget->updateWidget(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * @return True if the border endpoints should be highlighted, else false. */ bool UserInputModeBorders::isHighlightBorderEndPoints() const { if (getMode() == MODE_DRAW) { if (getDrawOperation() != DRAW_OPERATION_CREATE) { return true; } } return false; } /** * Finish the border that the user was drawing. */ void UserInputModeBorders::drawOperationFinish() { this->borderBeingDrawnByOpenGL->clear(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().addBorder().getPointer()); } /** * Undo (remove last point) from border being drawn. */ void UserInputModeBorders::drawOperationUndo() { this->borderBeingDrawnByOpenGL->removeLastPoint(); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(this->windowIndex).getPointer()); } /** * Reset the border being drawn. */ void UserInputModeBorders::drawOperationReset() { this->borderBeingDrawnByOpenGL->clear(); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(this->windowIndex).getPointer()); } /** * @return The edit operation. */ UserInputModeBorders::EditOperation UserInputModeBorders::getEditOperation() const { return this->editOperation; } /** * Set the edit operation. * @param editOperation * New edit operation. */ void UserInputModeBorders::setEditOperation(const EditOperation editOperation) { this->editOperation = editOperation; } /** * @return The cursor for display in the OpenGL widget. */ CursorEnum::Enum UserInputModeBorders::getCursor() const { CursorEnum::Enum cursor = CursorEnum::CURSOR_DEFAULT; switch (this->mode) { case MODE_DRAW: cursor = CursorEnum::CURSOR_DRAWING_PEN; break; case MODE_EDIT: cursor = CursorEnum::CURSOR_POINTING_HAND; break; case MODE_ROI: cursor = CursorEnum::CURSOR_POINTING_HAND; break; } return cursor; } /** * Process a mouse left click event. * * @param mouseEvent * Mouse event information. */ void UserInputModeBorders::mouseLeftClick(const MouseEvent& mouseEvent) { BrainOpenGLWidget* openGLWidget = mouseEvent.getOpenGLWidget(); const int mouseX = mouseEvent.getX(); const int mouseY = mouseEvent.getY(); switch (this->mode) { case MODE_DRAW: this->drawPointAtMouseXY(openGLWidget, mouseX, mouseY); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(this->windowIndex).getPointer()); break; case MODE_EDIT: { SelectionManager* idManager = openGLWidget->performIdentification(mouseX, mouseY, true); SelectionItemBorderSurface* idBorder = idManager->getSurfaceBorderIdentification(); if (idBorder->isValid()) { BorderFile* borderFile = idBorder->getBorderFile(); if (borderFile->isSingleStructure()) { switch (this->editOperation) { case EDIT_OPERATION_DELETE: { Border* border = idBorder->getBorder(); borderFile->removeBorder(border); this->updateAfterBordersChanged(); } break; case EDIT_OPERATION_PROPERTIES: { Border* border = idBorder->getBorder(); std::unique_ptr editBorderDialog( BorderPropertiesEditorDialog::newInstanceEditBorder(borderFile, border, openGLWidget)); if (editBorderDialog->exec() == BorderPropertiesEditorDialog::Accepted) { this->updateAfterBordersChanged(); } } break; } } else { WuQMessageBox::errorOk(this->borderToolsWidget, borderFile->getObsoleteMultiStructureFormatMessage()); } } } break; case MODE_ROI: { SelectionManager* idManager = openGLWidget->performIdentification(mouseX, mouseY, true); SelectionItemBorderSurface* idBorder = idManager->getSurfaceBorderIdentification(); if (idBorder->isValid()) { Brain* brain = idBorder->getBrain(); Surface* surface = idBorder->getSurface(); //BorderFile* borderFile = idBorder->getBorderFile(); Border* border = idBorder->getBorder(); this->borderToolsWidget->executeRoiInsideSelectedBorderOperation(brain, surface, border); } } break; } } /** * Process a mouse left click with Shift key event. * * @param mouseEvent * Mouse event information. */ void UserInputModeBorders::mouseLeftClickWithShift(const MouseEvent& /*mouseEvent*/) { switch (this->mode) { case MODE_DRAW: this->borderToolsWidget->executeFinishOperation(); break; case MODE_EDIT: break; case MODE_ROI: break; } } /** * Process a mouse left click with ctrl and shift keys down event. * * @param mouseEvent * Mouse event information. */ void UserInputModeBorders::mouseLeftClickWithCtrlShift(const MouseEvent& mouseEvent) { BrainOpenGLWidget* openGLWidget = mouseEvent.getOpenGLWidget(); const int mouseX = mouseEvent.getX(); const int mouseY = mouseEvent.getY(); switch (this->mode) { case MODE_DRAW: this->drawPointAtMouseXY(openGLWidget, mouseX, mouseY); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(this->windowIndex).getPointer()); break; case MODE_EDIT: break; case MODE_ROI: break; } } /** * Process a mouse left drag with ctrl and shift keys down event. * * @param mouseEvent * Mouse event information. */ void UserInputModeBorders::mouseLeftDragWithCtrlShift(const MouseEvent& mouseEvent) { BrainOpenGLWidget* openGLWidget = mouseEvent.getOpenGLWidget(); const int mouseX = mouseEvent.getX(); const int mouseY = mouseEvent.getY(); switch (this->mode) { case MODE_DRAW: this->drawPointAtMouseXY(openGLWidget, mouseX, mouseY); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(this->windowIndex).getPointer()); break; case MODE_EDIT: break; case MODE_ROI: break; } } /** * Show a context menu (pop-up menu at mouse location) * * @param mouseEvent * Mouse event information. * @param menuPosition * Point at which menu is displayed (passed to QMenu::exec()) * @param openGLWidget * OpenGL widget in which context menu is requested */ void UserInputModeBorders::showContextMenu(const MouseEvent& mouseEvent, const QPoint& menuPosition, BrainOpenGLWidget* openGLWidget) { UserInputModeView::showContextMenu(mouseEvent, menuPosition, openGLWidget); } connectome-workbench-1.4.2/src/GuiQt/UserInputModeBorders.h000066400000000000000000000101241360521144700237060ustar00rootroot00000000000000#ifndef __USER_INPUT_MODE_BORDERS__H_ #define __USER_INPUT_MODE_BORDERS__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "UserInputModeView.h" namespace caret { class Border; class UserInputModeBordersWidget; class UserInputModeBorders : public UserInputModeView { public: enum Mode { MODE_DRAW, MODE_EDIT, MODE_ROI }; enum DrawOperation { DRAW_OPERATION_CREATE, DRAW_OPERATION_ERASE, DRAW_OPERATION_EXTEND, DRAW_OPERATION_OPTIMIZE, DRAW_OPERATION_REPLACE }; enum EditOperation { EDIT_OPERATION_DELETE, EDIT_OPERATION_PROPERTIES }; UserInputModeBorders(Border* borderBeingDrawnByOpenGL, const int32_t windowIndex); virtual ~UserInputModeBorders(); virtual void initialize(); virtual void finish(); virtual void update(); Mode getMode() const; virtual void mouseLeftClick(const MouseEvent& mouseEvent); virtual void mouseLeftClickWithShift(const MouseEvent& mouseEvent); virtual void mouseLeftClickWithCtrlShift(const MouseEvent& mouseEvent); virtual void mouseLeftDragWithCtrlShift(const MouseEvent& mouseEvent); virtual void showContextMenu(const MouseEvent& mouseEvent, const QPoint& menuPosition, BrainOpenGLWidget* openGLWidget); virtual CursorEnum::Enum getCursor() const; virtual AString toString() const; bool isHighlightBorderEndPoints() const; private: /* * Some private methods are accessed by this friend class */ friend class UserInputModeBordersWidget; UserInputModeBorders(const UserInputModeBorders&); UserInputModeBorders& operator=(const UserInputModeBorders&); void setMode(const Mode mode); DrawOperation getDrawOperation() const; void setDrawOperation(const DrawOperation drawOperation); EditOperation getEditOperation() const; void setEditOperation(const EditOperation editOperation); void drawPointAtMouseXY(BrainOpenGLWidget* openGLWidget, const int32_t mouseX, const int32_t mouseY); void drawOperationFinish(); void drawOperationUndo(); void drawOperationReset(); void updateAfterBordersChanged(); UserInputModeBordersWidget* borderToolsWidget; Mode mode; DrawOperation drawOperation; EditOperation editOperation; /** * Pointer to border drawn by OpenGL. Since owned * by OpenGL, DO NOT delete this!!! */ Border* borderBeingDrawnByOpenGL; int32_t windowIndex; }; #ifdef __USER_INPUT_MODE_BORDERS_DECLARE__ // #endif // __USER_INPUT_MODE_BORDERS_DECLARE__ } // namespace #endif //__USER_INPUT_MODE_BORDERS__H_ connectome-workbench-1.4.2/src/GuiQt/UserInputModeBordersWidget.cxx000066400000000000000000001365451360521144700254450ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #define __USER_INPUT_MODE_BORDERS_WIDGET_DECLARE__ #include "UserInputModeBordersWidget.h" #undef __USER_INPUT_MODE_BORDERS_WIDGET_DECLARE__ #include "AlgorithmException.h" #include "AlgorithmNodesInsideBorder.h" #include "Border.h" #include "BorderEditingSelectionDialog.h" #include "BorderFile.h" #include "BorderOptimizeDialog.h" #include "BorderPointFromSearch.h" #include "BorderPropertiesEditorDialog.h" #include "Brain.h" #include "BrainBrowserWindow.h" #include "BrainStructure.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "DisplayPropertiesBorders.h" #include "EventBrainReset.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "LabelFile.h" #include "MetricFile.h" #include "ModelSurface.h" #include "ModelSurfaceMontage.h" #include "ModelWholeBrain.h" #include "RegionOfInterestCreateFromBorderDialog.h" #include "Surface.h" #include "UserInputModeBorders.h" #include "WuQDataEntryDialog.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::UserInputModeBordersWidget * \brief Controls for when the user input mode is border operations */ /** * Constructor. * * @param inputModeBorders * Mouse processing for border operations. * @param parent * Optional parent widget. */ UserInputModeBordersWidget::UserInputModeBordersWidget(UserInputModeBorders* inputModeBorders, QWidget* parent) : QWidget(parent) { m_transformToolTipText = ("\n\n" "At any time, the view of the surface may be changed by\n" " PAN: Move the mouse with the left mouse button down while " "holding down the Shift key.\n" " ROTATE: Move the mouse with the left mouse button down.\n" " ZOOM: Move the mouse with the left mouse button down while " "holding down the Ctrl key (Apple key on Macs)." ); m_borderOptimizeDialog = NULL; this->inputModeBorders = inputModeBorders; QLabel* nameLabel = new QLabel("Borders "); this->widgetMode = this->createModeWidget(); resetLastEditedBorder(); this->widgetDrawOperation = this->createDrawOperationWidget(); this->widgetEditOperation = this->createEditOperationWidget(); this->widgetRoiOperation = this->createRoiOperationWidget(); this->operationStackedWidget = new QStackedWidget(); this->operationStackedWidget->addWidget(this->widgetDrawOperation); this->operationStackedWidget->addWidget(this->widgetEditOperation); this->operationStackedWidget->addWidget(this->widgetRoiOperation); QHBoxLayout* layout = new QHBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 0); layout->addWidget(nameLabel); layout->addWidget(this->widgetMode); layout->addSpacing(10); layout->addWidget(this->operationStackedWidget); layout->addStretch(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BRAIN_RESET); } /** * Destructor. */ UserInputModeBordersWidget::~UserInputModeBordersWidget() { EventManager::get()->removeAllEventsFromListener(this); } /** * Receive an event. * * @param event * The event that the receive can respond to. */ void UserInputModeBordersWidget::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_BRAIN_RESET) { EventBrainReset* brainEvent = dynamic_cast(event); CaretAssert(brainEvent); if (m_borderOptimizeDialog != NULL) { delete m_borderOptimizeDialog; m_borderOptimizeDialog = NULL; } brainEvent->setEventProcessed(); } } /** * Update the contents of the widget. */ void UserInputModeBordersWidget::updateWidget() { /* * Show the proper widget */ switch (this->inputModeBorders->getMode()) { case UserInputModeBorders::MODE_DRAW: this->operationStackedWidget->setCurrentWidget(this->widgetDrawOperation); this->setActionGroupByActionData(this->drawOperationActionGroup, inputModeBorders->getDrawOperation()); resetLastEditedBorder(); break; case UserInputModeBorders::MODE_EDIT: this->operationStackedWidget->setCurrentWidget(this->widgetEditOperation); this->setActionGroupByActionData(this->editOperationActionGroup, inputModeBorders->getEditOperation()); break; case UserInputModeBorders::MODE_ROI: this->operationStackedWidget->setCurrentWidget(this->widgetRoiOperation); resetLastEditedBorder(); break; } const int selectedModeInteger = (int)this->inputModeBorders->getMode(); const int modeComboBoxIndex = this->modeComboBox->findData(selectedModeInteger); CaretAssert(modeComboBoxIndex >= 0); this->modeComboBox->blockSignals(true); this->modeComboBox->setCurrentIndex(modeComboBoxIndex); this->modeComboBox->blockSignals(false); } /** * Set the action with its data value of the given integer * as the active action. * @param actionGroup * Action group for which action is selected. * @param dataInteger * Integer value for data attribute. */ void UserInputModeBordersWidget::setActionGroupByActionData(QActionGroup* actionGroup, const int dataInteger) { actionGroup->blockSignals(true); const QList actionList = actionGroup->actions(); QListIterator iter(actionList); while (iter.hasNext()) { QAction* action = iter.next(); const int actionDataInteger = action->data().toInt(); if (dataInteger == actionDataInteger) { action->setChecked(true); break; } } actionGroup->blockSignals(false); } /** * @return The mode widget. */ QWidget* UserInputModeBordersWidget::createModeWidget() { this->modeComboBox = new QComboBox(); this->modeComboBox->addItem("Draw", (int)UserInputModeBorders::MODE_DRAW); this->modeComboBox->addItem("Edit", (int)UserInputModeBorders::MODE_EDIT); this->modeComboBox->addItem("ROI", (int)UserInputModeBorders::MODE_ROI); QObject::connect(this->modeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(modeComboBoxSelection(int))); QWidget* widget = new QWidget(); QHBoxLayout* layout = new QHBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 0); layout->addWidget(this->modeComboBox); widget->setFixedWidth(widget->sizeHint().width()); return widget; } /** * Called when a mode is selected from the mode combo box. * @param indx * Index of item selected. */ void UserInputModeBordersWidget::modeComboBoxSelection(int indx) { const int modeInteger = this->modeComboBox->itemData(indx).toInt(); const UserInputModeBorders::Mode mode = (UserInputModeBorders::Mode)modeInteger; this->inputModeBorders->setMode(mode); resetLastEditedBorder(); } /** * @return The draw operation widget. */ QWidget* UserInputModeBordersWidget::createDrawOperationWidget() { /* * Draw */ const AString drawToolTipText = ("To draw a new border segment either click the mouse " "to discretely add border points or hold down the CTRL (Apple key on Mac) and SHIFT keys " "and move the mouse with the left mouse button down to continuously " "add points. " "When the border is complete, either press the Finish button " "or hold down the Shift key and click the mouse to display a " "dialog for assigning the borders attributes (name and color). " + m_transformToolTipText); QAction* drawAction = WuQtUtilities::createAction("New", WuQtUtilities::createWordWrappedToolTipText(drawToolTipText), this); drawAction->setCheckable(true); drawAction->setData(static_cast(UserInputModeBorders::DRAW_OPERATION_CREATE)); QToolButton* drawToolButton = new QToolButton(); drawToolButton->setDefaultAction(drawAction); WuQtUtilities::setToolButtonStyleForQt5Mac(drawToolButton); /* * Erase */ const AString eraseToolTipText = ("To erase a section of a border, click the mouse twice, once " "at the beginning of the section that is to be removed and a " "second time at the end of the section. " "Press the Finish button or hold down the Shift key and click the " "mouse remove the border section." + m_transformToolTipText); QAction* eraseAction = WuQtUtilities::createAction("Erase", WuQtUtilities::createWordWrappedToolTipText(eraseToolTipText), this); eraseAction->setCheckable(true); eraseAction->setData(static_cast(UserInputModeBorders::DRAW_OPERATION_ERASE)); QToolButton* eraseToolButton = new QToolButton(); eraseToolButton->setDefaultAction(eraseAction); WuQtUtilities::setToolButtonStyleForQt5Mac(eraseToolButton); /* * Extend */ const AString extendToolTipText = ("To extend a border, move the mouse ANY point in the border and " "either click the mouse to discretely add points or hold down the CTRL (Apple key on Mac) and SHIFT keys " "and move the mouse with the left mouse button down to continuously add points. " "Press the Finish button or hold down the Shift key and click the " "mouse add the extension to the border." "\n\n" "If the segment starts at a point within the border (not an end point), points will be removed " "from that point to the nearest end point in the border and then the extension " "will be added." + m_transformToolTipText); QAction* extendAction = WuQtUtilities::createAction("Extend", WuQtUtilities::createWordWrappedToolTipText(extendToolTipText), this); extendAction->setCheckable(true); extendAction->setData(static_cast(UserInputModeBorders::DRAW_OPERATION_EXTEND)); QToolButton* extendToolButton = new QToolButton(); extendToolButton->setDefaultAction(extendAction); WuQtUtilities::setToolButtonStyleForQt5Mac(extendToolButton); /* * Replace */ const AString replaceToolTipText = ("To replace a section of a border, move the mouse to the " "start of the section that is being replaced. Either click " "the mouse to discretely add points in the new section or hold down the CTRL (Apple key on Mac) and SHIFT keys " "and move the mouse with the left mouse button down to continuously add points. " "Press the Finish button or hold down the Shift key and click the " "mouse to conclude replacing the section in the border." "\n\n" "Both the first point and the last point in the segment must " "overlap points in the border." + m_transformToolTipText); QAction* replaceAction = WuQtUtilities::createAction("Replace", WuQtUtilities::createWordWrappedToolTipText(replaceToolTipText), this); replaceAction->setCheckable(true); replaceAction->setData(static_cast(UserInputModeBorders::DRAW_OPERATION_REPLACE)); QToolButton* replaceToolButton = new QToolButton(); replaceToolButton->setDefaultAction(replaceAction); WuQtUtilities::setToolButtonStyleForQt5Mac(replaceToolButton); /* * Optimize */ const AString optimizeToolTipText("A new border optimization process automatically repositions a manually drawn " "border segment to follow the most probable path based on spatial gradients of " "a set of user-selected feature maps (useful for cortical parcellation)."); QAction* optimizeAction = WuQtUtilities::createAction("Optimize", WuQtUtilities::createWordWrappedToolTipText(optimizeToolTipText), this); optimizeAction->setCheckable(true); optimizeAction->setData(static_cast(UserInputModeBorders::DRAW_OPERATION_OPTIMIZE)); QToolButton* optimizeToolButton = new QToolButton(); optimizeToolButton->setDefaultAction(optimizeAction); WuQtUtilities::setToolButtonStyleForQt5Mac(optimizeToolButton); /* * Finish */ const AString finishToolTipText = ("The finish button must be pressed (holding down the Shift key " "and clicking the mouse is a shortcut to clicking the Finish " "button) to complete any of the border drawing operations."); QAction* finishAction = WuQtUtilities::createAction("Finish", WuQtUtilities::createWordWrappedToolTipText(finishToolTipText), this, this, SLOT(drawFinishButtonClicked())); QToolButton* finishToolButton = new QToolButton(); finishToolButton->setDefaultAction(finishAction); WuQtUtilities::setToolButtonStyleForQt5Mac(finishToolButton); /* * Undo */ QAction* undoAction = WuQtUtilities::createAction("Undo", "Remove (undo) the last point in the\n" "drawn border segment. If the button\n" "is held down, it will repeat removal\n" "of points until the button is released.", this, this, SLOT(drawUndoButtonClicked())); QToolButton* undoToolButton = new QToolButton(); undoToolButton->setDefaultAction(undoAction); undoToolButton->setAutoRepeat(true); undoToolButton->setAutoRepeatDelay(500); // 500ms = 1/2 second undoToolButton->setAutoRepeatInterval(100); // 100ms = 1/10 second WuQtUtilities::setToolButtonStyleForQt5Mac(undoToolButton); QAction* undoFinishAction = WuQtUtilities::createAction("Undo Finish", "Undo the last Erase/Extend/Replace\n" "performed on a border.", this, this, SLOT(drawUndoLastEditButtonClicked())); m_undoFinishToolButton = new QToolButton(); m_undoFinishToolButton->setDefaultAction(undoFinishAction); WuQtUtilities::setToolButtonStyleForQt5Mac(m_undoFinishToolButton); /* * Reset */ QAction* resetAction = WuQtUtilities::createAction("Reset", "Remove all points in the unfinished border", this, this, SLOT(drawResetButtonClicked())); QToolButton* resetToolButton = new QToolButton(); resetToolButton->setDefaultAction(resetAction); WuQtUtilities::setToolButtonStyleForQt5Mac(resetToolButton); this->drawOperationActionGroup = new QActionGroup(this); this->drawOperationActionGroup->addAction(drawAction); this->drawOperationActionGroup->addAction(eraseAction); this->drawOperationActionGroup->addAction(extendAction); this->drawOperationActionGroup->addAction(optimizeAction); this->drawOperationActionGroup->addAction(replaceAction); this->drawOperationActionGroup->setExclusive(true); QObject::connect(this->drawOperationActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(drawOperationActionTriggered(QAction*))); QWidget* widget = new QWidget(); QHBoxLayout* layout = new QHBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 0); layout->addWidget(drawToolButton); layout->addWidget(eraseToolButton); layout->addWidget(extendToolButton); layout->addWidget(optimizeToolButton); layout->addWidget(replaceToolButton); layout->addSpacing(10); layout->addWidget(finishToolButton); layout->addWidget(m_undoFinishToolButton); layout->addSpacing(10); layout->addWidget(undoToolButton); layout->addWidget(resetToolButton); widget->setFixedWidth(widget->sizeHint().width()); return widget; } /** * Called when draw border reset button clicked. */ void UserInputModeBordersWidget::drawResetButtonClicked() { this->inputModeBorders->drawOperationReset(); } /** * Called when draw border undo button clicked. */ void UserInputModeBordersWidget::drawUndoButtonClicked() { this->inputModeBorders->drawOperationUndo(); } /** * Undo editing (erase/extend/replace) of last border. */ void UserInputModeBordersWidget::drawUndoLastEditButtonClicked() { for (std::vector::iterator iter = m_undoFinishBorders.begin(); iter != m_undoFinishBorders.end(); iter++) { BorderFile* undoBorderFile = iter->m_borderFile; Border* undoBorder = iter->m_border; bool foundBorderFlag = false; Brain* brain = GuiManager::get()->getBrain(); const int32_t numBorderFiles = brain->getNumberOfBorderFiles(); for (int32_t i = 0; i < numBorderFiles; i++) { BorderFile* bf = brain->getBorderFile(i); if (bf == undoBorderFile) { foundBorderFlag = true; break; } } if (foundBorderFlag) { foundBorderFlag = false; const int32_t numBorders = undoBorderFile->getNumberOfBorders(); for (int32_t i = 0; i < numBorders; i++) { if (undoBorderFile->getBorder(i) == undoBorder) { foundBorderFlag = true; break; } } } if (foundBorderFlag) { if (undoBorder->isUndoBorderValid()) { if (WuQMessageBox::warningOkCancel(m_undoFinishToolButton, ("Undo changes to " + undoBorder->getName()))) { undoBorder->undoLastBorderEditing(); } } else { WuQMessageBox::errorOk(m_undoFinishToolButton, ("Cannot undo border " + undoBorder->getName())); } } else { WuQMessageBox::errorOk(m_undoFinishToolButton, "Cannot undo last edited border. " "Did not find border for undoing."); } } resetLastEditedBorder(); } /** * Publicly accessible method for initiating * an operation as if the Finish button was * pressed. */ void UserInputModeBordersWidget::executeFinishOperation() { this->drawFinishButtonClicked(); } /** * Called when draw border finish button clicked. */ void UserInputModeBordersWidget::drawFinishButtonClicked() { BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->inputModeBorders->windowIndex); if (browserWindow == NULL) { return; } BrowserTabContent* btc = browserWindow->getBrowserTabContent(); if (btc == NULL) { return; } const int32_t browserTabIndex = btc->getTabNumber(); if (this->inputModeBorders->borderBeingDrawnByOpenGL->verifyAllPointsOnSameStructure() == false) { WuQMessageBox::errorOk(this, "Error: Border points are on more than one structure."); return; } AString modeText; int32_t minimumNumberOfBorderPoints = 2; switch (this->inputModeBorders->getDrawOperation()) { case UserInputModeBorders::DRAW_OPERATION_CREATE: modeText = "creating a border."; minimumNumberOfBorderPoints = 2; break; case UserInputModeBorders::DRAW_OPERATION_OPTIMIZE: modeText = "optimizing borders."; minimumNumberOfBorderPoints = 3; break; case UserInputModeBorders::DRAW_OPERATION_ERASE: modeText = "erasing a segment in a border."; minimumNumberOfBorderPoints = 2; break; case UserInputModeBorders::DRAW_OPERATION_EXTEND: modeText = "extending a border."; minimumNumberOfBorderPoints = 2; break; case UserInputModeBorders::DRAW_OPERATION_REPLACE: modeText = "replacing points in a border."; minimumNumberOfBorderPoints = 2; break; } if (this->inputModeBorders->borderBeingDrawnByOpenGL->getNumberOfPoints() < minimumNumberOfBorderPoints) { WuQMessageBox::errorOk(this, ("There must be at least " + AString::number(minimumNumberOfBorderPoints) + " points when " + modeText)); return; } ModelSurface* surfaceController = btc->getDisplayedSurfaceModel(); ModelWholeBrain* wholeBrainController = btc->getDisplayedWholeBrainModel(); ModelSurfaceMontage* surfaceMontageController = btc->getDisplayedSurfaceMontageModel(); Brain* brain = NULL; Surface* surface = NULL; if (surfaceController != NULL) { brain = surfaceController->getBrain(); surface = surfaceController->getSurface(); } else if (wholeBrainController != NULL) { brain = wholeBrainController->getBrain(); const StructureEnum::Enum structure = this->inputModeBorders->borderBeingDrawnByOpenGL->getStructure(); surface = wholeBrainController->getSelectedSurface(structure, btc->getTabNumber()); } else if (surfaceMontageController != NULL) { brain = surfaceMontageController->getBrain(); const StructureEnum::Enum structure = this->inputModeBorders->borderBeingDrawnByOpenGL->getStructure(); surface = surfaceMontageController->getSelectedSurface(structure, btc->getTabNumber()); } if (surface == NULL) { AString tabsMessage; if (browserWindow->isTileTabsSelected()) { tabsMessage = "Verify that points are added in the SELECTED tab."; } WuQMessageBox::errorOk(this, "Borders may only be drawn on surface models. " + tabsMessage); return; } if (brain == NULL) { CaretLogSevere("PROGRAM ERROR: Cannot find brain for border drawing."); return; } DisplayPropertiesBorders* dpb = GuiManager::get()->getBrain()->getDisplayPropertiesBorders(); const DisplayGroupEnum::Enum displayGroup = dpb->getDisplayGroupForTab(btc->getTabNumber()); dpb->setDisplayed(displayGroup, browserTabIndex, true); switch (this->inputModeBorders->getDrawOperation()) { case UserInputModeBorders::DRAW_OPERATION_CREATE: { std::unique_ptr finishBorderDialog( BorderPropertiesEditorDialog::newInstanceFinishBorder(this->inputModeBorders->borderBeingDrawnByOpenGL, surface, this)); if (finishBorderDialog->exec() == BorderPropertiesEditorDialog::Accepted) { this->inputModeBorders->drawOperationFinish(); } } break; case UserInputModeBorders::DRAW_OPERATION_OPTIMIZE: processBorderOptimization(displayGroup, browserTabIndex, surface, this->inputModeBorders->borderBeingDrawnByOpenGL); break; case UserInputModeBorders::DRAW_OPERATION_ERASE: case UserInputModeBorders::DRAW_OPERATION_EXTEND: case UserInputModeBorders::DRAW_OPERATION_REPLACE: { const float nearestTolerance = 10; std::vector allNearbyBorders; const int32_t numBorderFiles = brain->getNumberOfBorderFiles(); for (int32_t ibf = 0; ibf < numBorderFiles; ibf++) { const BorderFile* borderFile = brain->getBorderFile(ibf); std::vector bordersFoundFromFile; switch (this->inputModeBorders->getDrawOperation()) { case UserInputModeBorders::DRAW_OPERATION_CREATE: CaretAssert(0); break; case UserInputModeBorders::DRAW_OPERATION_ERASE: borderFile->findAllBordersWithPointsNearBothSegmentEndPoints(displayGroup, browserTabIndex, surface, this->inputModeBorders->borderBeingDrawnByOpenGL, nearestTolerance, bordersFoundFromFile); break; case UserInputModeBorders::DRAW_OPERATION_EXTEND: borderFile->findAllBordersWithAnyPointNearSegmentFirstPoint(displayGroup, browserTabIndex, surface, this->inputModeBorders->borderBeingDrawnByOpenGL, nearestTolerance, bordersFoundFromFile); // borderFile->findAllBordersWithEndPointNearSegmentFirstPoint(displayGroup, // browserTabIndex, // surface, // this->inputModeBorders->borderBeingDrawnByOpenGL, // nearestTolerance, // bordersFoundFromFile); break; case UserInputModeBorders::DRAW_OPERATION_OPTIMIZE: CaretAssert(0); break; case UserInputModeBorders::DRAW_OPERATION_REPLACE: borderFile->findAllBordersWithPointsNearBothSegmentEndPoints(displayGroup, browserTabIndex, surface, this->inputModeBorders->borderBeingDrawnByOpenGL, nearestTolerance, bordersFoundFromFile); break; } allNearbyBorders.insert(allNearbyBorders.end(), bordersFoundFromFile.begin(), bordersFoundFromFile.end()); } if (allNearbyBorders.empty()) { WuQMessageBox::errorOk(this, "No borders were found near the border editing points"); return; } else { std::sort(allNearbyBorders.begin(), allNearbyBorders.end()); const int32_t numBorders = static_cast(allNearbyBorders.size()); AString modeMessage; switch (this->inputModeBorders->getDrawOperation()) { case UserInputModeBorders::DRAW_OPERATION_CREATE: CaretAssert(0); break; case UserInputModeBorders::DRAW_OPERATION_ERASE: modeMessage = "Erase segement in"; break; case UserInputModeBorders::DRAW_OPERATION_EXTEND: modeMessage = "Extend"; break; case UserInputModeBorders::DRAW_OPERATION_OPTIMIZE: CaretAssert(0); break; case UserInputModeBorders::DRAW_OPERATION_REPLACE: modeMessage = "Replace segment in"; break; } std::vector borderNames; for (int32_t i = 0; i < numBorders; i++) { BorderPointFromSearch& bpfs = allNearbyBorders[i]; borderNames.push_back(bpfs.border()->getName() + " (" + AString::number(bpfs.distance(), 'f', 6) + " mm)"); } BorderEditingSelectionDialog selDialog(modeMessage, borderNames, this); if (selDialog.exec() == BorderEditingSelectionDialog::Accepted) { AString errorMessage; std::vector undoBorders; for (int32_t i = 0; i < numBorders; i++) { if (selDialog.isBorderNameSelected(i)) { BorderPointFromSearch& bpfs = allNearbyBorders[i]; BorderFile* borderFile = bpfs.borderFile(); Border* border = bpfs.border(); int32_t borderPointIndex = bpfs.borderPointIndex(); CaretAssert(borderFile); CaretAssert(border); try { switch (this->inputModeBorders->getDrawOperation()) { case UserInputModeBorders::DRAW_OPERATION_CREATE: CaretAssert(0); break; case UserInputModeBorders::DRAW_OPERATION_ERASE: border->reviseEraseFromEnd(surface, this->inputModeBorders->borderBeingDrawnByOpenGL); break; case UserInputModeBorders::DRAW_OPERATION_EXTEND: border->reviseExtendFromPointIndex(surface, borderPointIndex, this->inputModeBorders->borderBeingDrawnByOpenGL); //border->reviseExtendFromEnd(surface, // this->inputModeBorders->borderBeingDrawnByOpenGL); break; case UserInputModeBorders::DRAW_OPERATION_OPTIMIZE: CaretAssert(0); break; case UserInputModeBorders::DRAW_OPERATION_REPLACE: border->reviseReplaceSegment(surface, this->inputModeBorders->borderBeingDrawnByOpenGL); break; } undoBorders.push_back(BorderFileAndBorderMemento(borderFile, border)); } catch (BorderException& e) { errorMessage.appendWithNewLine(e.whatString()); } } } if ( ! errorMessage.isEmpty()) { WuQMessageBox::errorOk(this, errorMessage); } else { setLastEditedBorder(undoBorders); this->inputModeBorders->borderBeingDrawnByOpenGL->clear(); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } } break; } } /** * Process the border optimization operation. * * @param surface * Surface on which border is drawn. * @param borderDrawnByUser * Border drawn by the user. */ void UserInputModeBordersWidget::processBorderOptimization(const DisplayGroupEnum::Enum displayGroup, const int32_t browserTabIndex, Surface* surface, Border* borderDrawnByUser) { std::vector nodesInsideBorder; try { ProgressObject* myProgObj = NULL; const bool inverseSelectionFlag = false; /* * Find nodes inside border */ AlgorithmNodesInsideBorder nib(myProgObj, surface, borderDrawnByUser, inverseSelectionFlag, nodesInsideBorder); } catch (const AlgorithmException& e) { WuQMessageBox::errorOk(this, e.whatString()); return; } if (nodesInsideBorder.empty()) { WuQMessageBox::errorOk(this, ("No nodes were found inside the drawn border " + borderDrawnByUser->getName())); return; } Brain* brain = GuiManager::get()->getBrain(); const StructureEnum::Enum surfaceStructure = surface->getStructure(); const BrainStructure* brainStructure = brain->getBrainStructure(surfaceStructure, false); if (brainStructure == NULL) { WuQMessageBox::errorOk(this, "No files for surface structure " + StructureEnum::toGuiName(surfaceStructure)); return; } std::vector optimizeDataFileTypes; optimizeDataFileTypes.push_back(DataFileTypeEnum::CONNECTIVITY_DENSE); optimizeDataFileTypes.push_back(DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR); optimizeDataFileTypes.push_back(DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES); optimizeDataFileTypes.push_back(DataFileTypeEnum::METRIC); std::vector optimizeDataFiles; brain->getAllMappableDataFileWithDataFileTypes(optimizeDataFileTypes, optimizeDataFiles); /* * Create a bool vector that indicates nodes inside border * from the node index. */ const int32_t numberOfSurfaceNodes = surface->getNumberOfNodes(); std::vector nodeInROI(numberOfSurfaceNodes, false); for (std::vector::const_iterator iter = nodesInsideBorder.begin(); iter != nodesInsideBorder.end(); iter++) { const int32_t nodeIndex = *iter; CaretAssertVectorIndex(nodeInROI, nodeIndex); nodeInROI[nodeIndex] = true; } /* * Find borders inside region of interest */ std::map borderToBorderFileMap; std::vector > bordersInsideRegionOfInterest; const int32_t numberOfBorderFiles = brain->getNumberOfBorderFiles(); for (int32_t iFile = 0; iFile < numberOfBorderFiles; iFile++) { BorderFile* borderFile = brain->getBorderFile(iFile); std::vector > nodeCountAndBordersFromFileInROI; borderFile->findBordersInsideRegionOfInterest(displayGroup, browserTabIndex, surface, nodeInROI, nodeCountAndBordersFromFileInROI); for (std::vector > ::iterator bi = nodeCountAndBordersFromFileInROI.begin(); bi != nodeCountAndBordersFromFileInROI.end(); bi++) { Border* border = bi->second; borderToBorderFileMap.insert(std::make_pair(border, borderFile)); bordersInsideRegionOfInterest.push_back(*bi); } } if (bordersInsideRegionOfInterest.empty()) { WuQMessageBox::errorOk(this, "No borders were found inside the drawn border."); return; } std::sort(bordersInsideRegionOfInterest.begin(), bordersInsideRegionOfInterest.end()); if (m_borderOptimizeDialog == NULL) { m_borderOptimizeDialog = new BorderOptimizeDialog(this); } m_borderOptimizeDialog->updateDialog(browserTabIndex, surface, bordersInsideRegionOfInterest, const_cast(borderDrawnByUser), nodesInsideBorder); if (m_borderOptimizeDialog->exec() == BorderOptimizeDialog::Accepted) { std::vector modifiedBorders; m_borderOptimizeDialog->getModifiedBorders(modifiedBorders); /* * Track modified borders so that changes can be 'undone' by * the user. */ std::vector undoBorders; for (std::vector::iterator mbi = modifiedBorders.begin(); mbi != modifiedBorders.end(); mbi++) { Border* border = *mbi; std::map::iterator mapIter = borderToBorderFileMap.find(border); if (mapIter != borderToBorderFileMap.end()) { BorderFile* borderFile = mapIter->second; undoBorders.push_back(BorderFileAndBorderMemento(borderFile, border)); } else { CaretAssertMessage(0, "PROGRAM ERROR: border file not found for border."); } } setLastEditedBorder(undoBorders); if ( ! m_borderOptimizeDialog->isKeepBoundaryBorderSelected()) { this->inputModeBorders->borderBeingDrawnByOpenGL->clear(); } } /* * Update all graphics windows to displayed changed borders */ EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); adjustViewActionTriggered(); } /** * Called when Adjust View button is pressed. */ void UserInputModeBordersWidget::adjustViewActionTriggered() { EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called when a draw mode button is clicked. * @param action * Action that was triggered. */ void UserInputModeBordersWidget::drawOperationActionTriggered(QAction* action) { const int drawModeInteger = action->data().toInt(); const UserInputModeBorders::DrawOperation drawOperation = static_cast(drawModeInteger); this->inputModeBorders->setDrawOperation(drawOperation); } /** * @return The edit widget. */ QWidget* UserInputModeBordersWidget::createEditOperationWidget() { const AString deleteToolTipText = ("Delete a border by clicking the mouse over " "any point in the border." + m_transformToolTipText); QAction* deleteAction = WuQtUtilities::createAction("Delete", WuQtUtilities::createWordWrappedToolTipText(deleteToolTipText), this); deleteAction->setCheckable(true); deleteAction->setData(static_cast(UserInputModeBorders::EDIT_OPERATION_DELETE)); QToolButton* deleteToolButton = new QToolButton(); deleteToolButton->setDefaultAction(deleteAction); WuQtUtilities::setToolButtonStyleForQt5Mac(deleteToolButton); const AString propertiesToolTipText = ("A dialog for editing a border's properties is displayed by " "clicking any point in a border." + m_transformToolTipText); QAction* propertiesAction = WuQtUtilities::createAction("Properties", WuQtUtilities::createWordWrappedToolTipText(propertiesToolTipText), this); propertiesAction->setCheckable(true); propertiesAction->setData(static_cast(UserInputModeBorders::EDIT_OPERATION_PROPERTIES)); QToolButton* propertiesToolButton = new QToolButton(); propertiesToolButton->setDefaultAction(propertiesAction); WuQtUtilities::setToolButtonStyleForQt5Mac(propertiesToolButton); this->editOperationActionGroup = new QActionGroup(this); this->editOperationActionGroup->addAction(deleteAction); this->editOperationActionGroup->addAction(propertiesAction); this->editOperationActionGroup->setExclusive(true); QObject::connect(this->editOperationActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(editOperationActionTriggered(QAction*))); QWidget* widget = new QWidget(); QHBoxLayout* layout = new QHBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 0); layout->addWidget(deleteToolButton); layout->addWidget(propertiesToolButton); widget->setFixedWidth(widget->sizeHint().width()); return widget; } /** * Called when a edit button is clicked. * @param action * Action that was triggered. */ void UserInputModeBordersWidget::editOperationActionTriggered(QAction* action) { const int editModeInteger = action->data().toInt(); const UserInputModeBorders::EditOperation editOperation = static_cast(editModeInteger); this->inputModeBorders->setEditOperation(editOperation); } /** * @return The ROI widget. */ QWidget* UserInputModeBordersWidget::createRoiOperationWidget() { QWidget* widget = new QWidget(); // QHBoxLayout* layout = new QHBoxLayout(widget); // WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 0); // // widget->setFixedWidth(widget->sizeHint().width()); return widget; } /** * Called when the user selects a border in ROI opeation. * * @param brain * Brain on which identification occurred. * @param surfaceFile * Surface on which border is located. * @param border * Border for which nodes are found inside. */ void UserInputModeBordersWidget::executeRoiInsideSelectedBorderOperation(Brain* /*brain*/, Surface* surface, Border* border) { if (border->verifyAllPointsOnSameStructure() == false) { WuQMessageBox::errorOk(this, "Error: Border points are on more than one structure."); return; } RegionOfInterestCreateFromBorderDialog createRoiDialog(border, surface, this); createRoiDialog.exec(); } /** * Reset the last edited border. */ void UserInputModeBordersWidget::resetLastEditedBorder() { m_undoFinishBorders.clear(); } /** * Set the last edited border. * * @param undoFinishBorders * Borders that were changed by the last border edit operation. */ void UserInputModeBordersWidget::setLastEditedBorder(std::vector& undoFinishBorders) { m_undoFinishBorders = undoFinishBorders; } connectome-workbench-1.4.2/src/GuiQt/UserInputModeBordersWidget.h000066400000000000000000000107731360521144700250640ustar00rootroot00000000000000#ifndef __USER_INPUT_MODE_BORDERS_WIDGET__H_ #define __USER_INPUT_MODE_BORDERS_WIDGET__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "DisplayGroupEnum.h" #include "EventListenerInterface.h" class QAction; class QActionGroup; class QComboBox; class QStackedWidget; class QToolButton; namespace caret { class BorderFile; class BorderOptimizeDialog; class Border; class Brain; class Surface; class UserInputModeBorders; class UserInputModeBordersWidget : public QWidget, public EventListenerInterface { Q_OBJECT public: UserInputModeBordersWidget(UserInputModeBorders* inputModeBorders, QWidget* parent = 0); virtual ~UserInputModeBordersWidget(); virtual void receiveEvent(Event* event); void updateWidget(); void executeFinishOperation(); void executeRoiInsideSelectedBorderOperation(Brain* brain, Surface* surface, Border* border); private slots: void adjustViewActionTriggered(); void drawOperationActionTriggered(QAction*); void editOperationActionTriggered(QAction*); void modeComboBoxSelection(int); void drawResetButtonClicked(); void drawUndoButtonClicked(); void drawUndoLastEditButtonClicked(); void drawFinishButtonClicked(); private: class BorderFileAndBorderMemento { public: BorderFileAndBorderMemento(BorderFile* borderFile, Border* border) { m_borderFile = borderFile; m_border = border; } BorderFile* m_borderFile; Border* m_border; }; UserInputModeBordersWidget(const UserInputModeBordersWidget&); UserInputModeBordersWidget& operator=(const UserInputModeBordersWidget&); void setActionGroupByActionData(QActionGroup* actionGroup, const int dataInteger); QActionGroup* drawOperationActionGroup; QActionGroup* editOperationActionGroup; QWidget* createModeWidget(); QWidget* createDrawOperationWidget(); QWidget* createEditOperationWidget(); QWidget* createRoiOperationWidget(); void setLastEditedBorder(std::vector& undoFinishBorders); void resetLastEditedBorder(); void processBorderOptimization(const DisplayGroupEnum::Enum displayGroup, const int32_t browserTabIndex, Surface* surface, Border* borderDrawnByUser); QComboBox* modeComboBox; QWidget* widgetMode; QWidget* widgetDrawOperation; QWidget* widgetEditOperation; QWidget* widgetRoiOperation; QStackedWidget* operationStackedWidget; UserInputModeBorders* inputModeBorders; QString m_transformToolTipText; QToolButton* m_undoFinishToolButton; BorderOptimizeDialog* m_borderOptimizeDialog; std::vector m_undoFinishBorders; }; #ifdef __USER_INPUT_MODE_BORDERS_WIDGET_DECLARE__ // #endif // __USER_INPUT_MODE_BORDERS_WIDGET_DECLARE__ } // namespace #endif //__USER_INPUT_MODE_BORDERS_WIDGET__H_ connectome-workbench-1.4.2/src/GuiQt/UserInputModeFoci.cxx000066400000000000000000000250231360521144700235450ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __USER_INPUT_MODE_FOCI_DECLARE__ #include "UserInputModeFoci.h" #undef __USER_INPUT_MODE_FOCI_DECLARE__ #include "Brain.h" #include "BrainOpenGLViewportContent.h" #include "BrainOpenGLWidget.h" #include "BrainStructure.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "FociFile.h" #include "FociPropertiesEditorDialog.h" #include "Focus.h" #include "GuiManager.h" #include "SelectionItemFocusSurface.h" #include "SelectionItemFocusVolume.h" #include "SelectionItemSurfaceNode.h" #include "SelectionItemVoxel.h" #include "SelectionManager.h" #include "MouseEvent.h" #include "Surface.h" #include "UserInputModeFociWidget.h" #include "UserInputModeView.h" #include "VolumeFile.h" using namespace caret; /** * \class caret::UserInputModeFoci * \brief Processes user input for foci. */ /** * Constructor. */ UserInputModeFoci::UserInputModeFoci(const int32_t windowIndex) : UserInputModeView(UserInputModeEnum::FOCI), m_windowIndex(windowIndex) { m_inputModeFociWidget = new UserInputModeFociWidget(this, windowIndex); m_mode = MODE_CREATE; m_editOperation = EDIT_OPERATION_PROPERTIES; setWidgetForToolBar(m_inputModeFociWidget); } /** * Destructor. */ UserInputModeFoci::~UserInputModeFoci() { } /** * @return the mode. */ UserInputModeFoci::Mode UserInputModeFoci::getMode() const { return m_mode; } /** * Set the mode. * @param mode * New value for mode. */ void UserInputModeFoci::setMode(const Mode mode) { if (m_mode != mode) { m_mode = mode; EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(m_windowIndex).getPointer()); } this->m_inputModeFociWidget->updateWidget(); } /** * @return The edit operation. */ UserInputModeFoci::EditOperation UserInputModeFoci::getEditOperation() const { return m_editOperation; } /** * Set the edit operation. * @param editOperation * New edit operation. */ void UserInputModeFoci::setEditOperation(const EditOperation editOperation) { m_editOperation = editOperation; } /** * Called when 'this' user input receiver is set * to receive events. */ void UserInputModeFoci::initialize() { m_inputModeFociWidget->updateWidget(); } /** * Called when 'this' user input receiver is no * longer set to receive events. */ void UserInputModeFoci::finish() { } /** * Called to update the input receiver for various events. */ void UserInputModeFoci::update() { } /** * @return The cursor for display in the OpenGL widget. */ CursorEnum::Enum UserInputModeFoci::getCursor() const { CursorEnum::Enum cursor = CursorEnum::CURSOR_DEFAULT; switch (m_mode) { case MODE_CREATE: break; case MODE_EDIT: cursor = CursorEnum::CURSOR_POINTING_HAND; switch (m_editOperation) { case EDIT_OPERATION_DELETE: cursor = CursorEnum::CURSOR_CROSS; break; case EDIT_OPERATION_PROPERTIES: cursor = CursorEnum::CURSOR_WHATS_THIS; break; } break; case MODE_OPERATIONS: cursor = CursorEnum::CURSOR_POINTING_HAND; break; } return cursor; } void UserInputModeFoci::updateAfterFociChanged() { /* * Need to update all graphics windows and all border controllers. */ EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().addFoci().getPointer()); } /** * Determine the structure for the given surface. Find the primary anatomical * surface for the structure and return it. If no primary anatomical surface * is found, the return the surface that was passed in. */ Surface* UserInputModeFoci::getAnatomicalSurfaceForSurface(Surface* surface) { Brain* brain = GuiManager::get()->getBrain(); const StructureEnum::Enum structure = surface->getStructure(); BrainStructure* bs = brain->getBrainStructure(structure, false); Surface* anatSurf = bs->getPrimaryAnatomicalSurface(); if (anatSurf != NULL) { return anatSurf; } return surface; } /** * Process a mouse left click event. * * @param mouseEvent * Mouse event information. */ void UserInputModeFoci::mouseLeftClick(const MouseEvent& mouseEvent) { BrainOpenGLViewportContent* viewportContent = mouseEvent.getViewportContent(); if (viewportContent == NULL) { return; } BrainOpenGLWidget* openGLWidget = mouseEvent.getOpenGLWidget(); BrowserTabContent* browserTabContent = viewportContent->getBrowserTabContent(); SelectionManager* idManager = openGLWidget->performIdentification(mouseEvent.getX(), mouseEvent.getY(), true); switch (m_mode) { case MODE_CREATE: { SelectionItemSurfaceNode* idNode = idManager->getSurfaceNodeIdentification(); SelectionItemVoxel* idVoxel = idManager->getVoxelIdentification(); if (idNode->isValid()) { Surface* surfaceViewed = idNode->getSurface(); CaretAssert(surfaceViewed); const Surface* anatSurface = getAnatomicalSurfaceForSurface(surfaceViewed); const StructureEnum::Enum anatStructure = anatSurface->getStructure(); const int32_t nodeIndex = idNode->getNodeNumber(); const AString focusName = (StructureEnum::toGuiName(anatStructure) + " Vertex " + AString::number(nodeIndex)); const float* xyz = anatSurface->getCoordinate(nodeIndex); const AString comment = ("Created from " + focusName); Focus* focus = new Focus(); focus->setName(focusName); focus->getProjection(0)->setStereotaxicXYZ(xyz); focus->setComment(comment); FociPropertiesEditorDialog::createFocus(focus, browserTabContent, m_inputModeFociWidget); } else if (idVoxel->isValid()) { const VolumeMappableInterface* vf = idVoxel->getVolumeFile(); const CaretMappableDataFile* cmdf = dynamic_cast(vf); int64_t ijk[3]; idVoxel->getVoxelIJK(ijk); float xyz[3]; vf->indexToSpace(ijk, xyz); const AString focusName = (cmdf->getFileNameNoPath() + " IJK (" + AString::fromNumbers(ijk, 3, ",") + ")"); const AString comment = ("Created from " + focusName); Focus* focus = new Focus(); focus->setName(focusName); focus->getProjection(0)->setStereotaxicXYZ(xyz); focus->setComment(comment); FociPropertiesEditorDialog::createFocus(focus, browserTabContent, m_inputModeFociWidget); } } break; case MODE_EDIT: { FociFile* fociFile = NULL; Focus* focus = NULL; SelectionItemFocusVolume* idVolFocus = idManager->getVolumeFocusIdentification(); if (idVolFocus->isValid()) { fociFile = idVolFocus->getFociFile(); CaretAssert(fociFile); focus = idVolFocus->getFocus(); CaretAssert(focus); } SelectionItemFocusSurface* idFocus = idManager->getSurfaceFocusIdentification(); if (idFocus->isValid()) { fociFile = idFocus->getFociFile(); CaretAssert(fociFile); focus = idFocus->getFocus(); CaretAssert(focus); } if ((fociFile != NULL) && (focus != NULL)) { switch (m_editOperation) { case EDIT_OPERATION_DELETE: fociFile->removeFocus(focus); updateAfterFociChanged(); break; case EDIT_OPERATION_PROPERTIES: { FociPropertiesEditorDialog::editFocus(fociFile, focus, openGLWidget); } } } } break; case MODE_OPERATIONS: break; } } /** * Show a context menu (pop-up menu at mouse location) * * @param mouseEvent * Mouse event information. * @param menuPosition * Point at which menu is displayed (passed to QMenu::exec()) * @param openGLWidget * OpenGL widget in which context menu is requested */ void UserInputModeFoci::showContextMenu(const MouseEvent& /*mouseEvent*/, const QPoint& /*menuPosition*/, BrainOpenGLWidget* /*openGLWidget*/) { /* no context menu */ } connectome-workbench-1.4.2/src/GuiQt/UserInputModeFoci.h000066400000000000000000000060541360521144700231750ustar00rootroot00000000000000#ifndef __USER_INPUT_MODE_FOCI__H_ #define __USER_INPUT_MODE_FOCI__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "UserInputModeView.h" namespace caret { class BrainOpenGLViewportContent; class BrainOpenGLWidget; class MouseEvent; class Surface; class UserInputModeFociWidget; class UserInputModeFoci : public UserInputModeView { public: enum Mode { MODE_CREATE, MODE_EDIT, MODE_OPERATIONS }; enum EditOperation { EDIT_OPERATION_DELETE, EDIT_OPERATION_PROPERTIES }; UserInputModeFoci(const int32_t windowIndex); virtual ~UserInputModeFoci(); virtual void initialize(); virtual void finish(); virtual void update(); virtual CursorEnum::Enum getCursor() const; virtual void mouseLeftClick(const MouseEvent& mouseEvent); virtual void showContextMenu(const MouseEvent& mouseEvent, const QPoint& menuPosition, BrainOpenGLWidget* openGLWidget); private: /* * Note some private methods are accessed by the * friend UserInputModeFociWidget. */ friend class UserInputModeFociWidget; UserInputModeFoci(const UserInputModeFoci&); UserInputModeFoci& operator=(const UserInputModeFoci&); Mode getMode() const; void setMode(const Mode mode); EditOperation getEditOperation() const; void setEditOperation(const EditOperation editOperation); void updateAfterFociChanged(); Surface* getAnatomicalSurfaceForSurface(Surface* surface); // ADD_NEW_MEMBERS_HERE const int32_t m_windowIndex; UserInputModeFociWidget* m_inputModeFociWidget; Mode m_mode; EditOperation m_editOperation; }; #ifdef __USER_INPUT_MODE_FOCI_DECLARE__ // #endif // __USER_INPUT_MODE_FOCI_DECLARE__ } // namespace #endif //__USER_INPUT_MODE_FOCI__H_ connectome-workbench-1.4.2/src/GuiQt/UserInputModeFociWidget.cxx000066400000000000000000000433361360521144700247200ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #define __USER_INPUT_MODE_FOCI_WIDGET_DECLARE__ #include "UserInputModeFociWidget.h" #undef __USER_INPUT_MODE_FOCI_WIDGET_DECLARE__ #include "Brain.h" #include "BrainBrowserWindow.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "DisplayPropertiesFoci.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "FociFile.h" #include "FociPropertiesEditorDialog.h" #include "Focus.h" #include "GuiManager.h" #include "SelectionManager.h" #include "SelectionItemSurfaceNode.h" #include "SelectionItemVoxel.h" #include "ModelSurface.h" #include "ModelWholeBrain.h" #include "Surface.h" #include "UserInputModeFoci.h" #include "VolumeFile.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::UserInputModeFociWidget * \brief Foci controls shown at bottom of toolbar */ /** * Constructor. * @param inputModeFoci * Process of mouse input for foci * @param windowIndex * Index of browser window * @param parent * Parent widget */ UserInputModeFociWidget::UserInputModeFociWidget(UserInputModeFoci* inputModeFoci, const int32_t windowIndex, QWidget* parent) : QWidget(parent), m_windowIndex(windowIndex) { m_transformToolTipText = ("\n\n" "At any time, the view of the surface may be changed by\n" " PAN: Move the mouse with the left mouse button down while " "holding down the Shift key.\n" " ROTATE: Move the mouse with the left mouse button down.\n" " ZOOM: Move the mouse with the left mouse button down while " "holding down the Ctrl key (Apple key on Macs)." ); m_inputModeFoci = inputModeFoci; QLabel* nameLabel = new QLabel("Foci "); QWidget* modeWidget = createModeWidget(); m_createOperationWidget = createCreateOperationWidget(); m_editOperationWidget = createEditOperationWidget(); m_taskOperationWidget = createTaskOperationWidget(); m_operationStackedWidget = new QStackedWidget(); m_operationStackedWidget->addWidget(m_createOperationWidget); m_operationStackedWidget->addWidget(m_editOperationWidget); //m_operationStackedWidget->addWidget(m_taskOperationWidget); QHBoxLayout* layout = new QHBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 0); layout->addWidget(nameLabel); layout->addWidget(modeWidget); layout->addSpacing(10); layout->addWidget(m_operationStackedWidget); layout->addStretch(); } /** * Destructor. */ UserInputModeFociWidget::~UserInputModeFociWidget() { } /** * Update the contents of the widget. */ void UserInputModeFociWidget::updateWidget() { /* * Show the proper widget */ switch (m_inputModeFoci->getMode()) { case UserInputModeFoci::MODE_CREATE: m_operationStackedWidget->setCurrentWidget(m_createOperationWidget); // setActionGroupByActionData(m_createOperationActionGroup, // m_inputModeFoci->getCreateOperation()); break; case UserInputModeFoci::MODE_EDIT: m_operationStackedWidget->setCurrentWidget(m_editOperationWidget); setActionGroupByActionData(m_editOperationActionGroup, m_inputModeFoci->getEditOperation()); break; case UserInputModeFoci::MODE_OPERATIONS: m_operationStackedWidget->setCurrentWidget(m_taskOperationWidget); break; } const int selectedModeInteger = (int)m_inputModeFoci->getMode(); const int modeComboBoxIndex = m_modeComboBox->findData(selectedModeInteger); CaretAssert(modeComboBoxIndex >= 0); m_modeComboBox->blockSignals(true); m_modeComboBox->setCurrentIndex(modeComboBoxIndex); m_modeComboBox->blockSignals(false); } /** * Set the action with its data value of the given integer * as the active action. * @param actionGroup * Action group for which action is selected. * @param dataInteger * Integer value for data attribute. */ void UserInputModeFociWidget::setActionGroupByActionData(QActionGroup* actionGroup, const int dataInteger) { actionGroup->blockSignals(true); const QList actionList = actionGroup->actions(); QListIterator iter(actionList); while (iter.hasNext()) { QAction* action = iter.next(); const int actionDataInteger = action->data().toInt(); if (dataInteger == actionDataInteger) { action->setChecked(true); break; } } actionGroup->blockSignals(false); } /** * @return The mode widget. */ QWidget* UserInputModeFociWidget::createModeWidget() { m_modeComboBox = new QComboBox(); m_modeComboBox->addItem("Create", (int)UserInputModeFoci::MODE_CREATE); m_modeComboBox->addItem("Edit", (int)UserInputModeFoci::MODE_EDIT); // m_modeComboBox->addItem("Tasks", (int)UserInputModeFoci::MODE_OPERATIONS); QObject::connect(m_modeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(modeComboBoxSelection(int))); QWidget* widget = new QWidget(); QHBoxLayout* layout = new QHBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 0); layout->addWidget(m_modeComboBox); widget->setFixedWidth(widget->sizeHint().width()); return widget; } /** * Called when a mode is selected from the mode combo box. * @param indx * Index of item selected. */ void UserInputModeFociWidget::modeComboBoxSelection(int indx) { const int modeInteger = m_modeComboBox->itemData(indx).toInt(); const UserInputModeFoci::Mode mode = (UserInputModeFoci::Mode)modeInteger; m_inputModeFoci->setMode(mode); } /** * @return The draw operation widget. */ QWidget* UserInputModeFociWidget::createCreateOperationWidget() { const AString newToolTipText = ("Press this button to display a dialog for creating a new focus. " "If the mouse is clicked over a model, the dialog for creating a focus is " "displayed with the focus' coordinates set to the stereotaxic coordinates at " "the location of the mouse click." + m_transformToolTipText); QAction* newFocusAction = WuQtUtilities::createAction("New...", WuQtUtilities::createWordWrappedToolTipText(newToolTipText), this, this, SLOT(createNewFocusActionTriggered())); QToolButton* newFocusToolButton = new QToolButton(); newFocusToolButton->setDefaultAction(newFocusAction); WuQtUtilities::setToolButtonStyleForQt5Mac(newFocusToolButton); const AString lastIDToolTipText = ("Press this button to display a dialog for creating a new focus " "with the focus' coordinates set to the stereotaxic location of the " "last identification operation. While in focus mode, an identification " "is performed by holding down the Shift key and clicking the mouse." + m_transformToolTipText); QAction* lastIdFocusAction = WuQtUtilities::createAction("Last ID", WuQtUtilities::createWordWrappedToolTipText(lastIDToolTipText), this, this, SLOT(createLastIdentificationFocusActionTriggered())); QToolButton* lastIdFocusToolButton = new QToolButton(); lastIdFocusToolButton->setDefaultAction(lastIdFocusAction); WuQtUtilities::setToolButtonStyleForQt5Mac(lastIdFocusToolButton); QWidget* widget = new QWidget(); QHBoxLayout* layout = new QHBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 0); layout->addWidget(newFocusToolButton); layout->addSpacing(5); layout->addWidget(lastIdFocusToolButton); widget->setFixedWidth(widget->sizeHint().width()); return widget; } /** * Called when new focus button is triggered * @param action * Action that was selected. */ void UserInputModeFociWidget::createNewFocusActionTriggered() { BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(m_windowIndex); if (browserWindow == NULL) { return; } BrowserTabContent* btc = browserWindow->getBrowserTabContent(); if (btc == NULL) { return; } const int32_t browserTabIndex = btc->getTabNumber(); DisplayPropertiesFoci* dpf = GuiManager::get()->getBrain()->getDisplayPropertiesFoci(); const DisplayGroupEnum::Enum displayGroup = dpf->getDisplayGroupForTab(btc->getTabNumber()); dpf->setDisplayed(displayGroup, browserTabIndex, true); FociPropertiesEditorDialog::createFocus(new Focus(), btc, this); } /** * Called when last ID focus button is triggered * @param action * Action that was selected. */ void UserInputModeFociWidget::createLastIdentificationFocusActionTriggered() { Brain* brain = GuiManager::get()->getBrain(); const SelectionManager* idManager = brain->getSelectionManager(); const SelectionItem* idItem = idManager->getLastSelectedItem(); if (idItem != NULL) { const SelectionItemSurfaceNode* nodeID = dynamic_cast(idItem); const SelectionItemVoxel* voxelID = dynamic_cast(idItem); BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(m_windowIndex); BrowserTabContent* browserTabContent = NULL; if (browserWindow != NULL) { browserTabContent = browserWindow->getBrowserTabContent(); } if (nodeID != NULL) { if (nodeID->isValid()) { const Surface* idSurface = nodeID->getSurface(); if (brain->isFileValid(idSurface)) { CaretAssert(idSurface); const StructureEnum::Enum structure = idSurface->getStructure(); const Surface* surface = brain->getPrimaryAnatomicalSurfaceForStructure(structure); if (surface != NULL) { const int32_t nodeIndex = nodeID->getNodeNumber(); const AString focusName = ("Last ID " + StructureEnum::toGuiName(structure) + " Node " + AString::number(nodeIndex)); const float* xyz = surface->getCoordinate(nodeIndex); const AString comment = ("Created from " + focusName); Focus* focus = new Focus(); focus->setName(focusName); focus->getProjection(0)->setStereotaxicXYZ(xyz); focus->setComment(comment); FociPropertiesEditorDialog::createFocus(focus, browserTabContent, this); } else { WuQMessageBox::errorOk(this, ("No anatomical surface found for " + StructureEnum::toGuiName(structure))); } } } } else if (voxelID != NULL) { if (voxelID->isValid()) { const VolumeMappableInterface* volumeFile = voxelID->getVolumeFile(); const CaretMappableDataFile* cmdf = dynamic_cast(volumeFile); if (brain->isFileValid(cmdf)) { CaretAssert(volumeFile); int64_t ijk[3]; voxelID->getVoxelIJK(ijk); float xyz[3]; volumeFile->indexToSpace(ijk, xyz); const AString focusName = ("Last ID " + cmdf->getFileNameNoPath() + " IJK (" + AString::fromNumbers(ijk, 3, ",") + ")"); const AString comment = ("Created from " + focusName); Focus* focus = new Focus(); focus->setName(focusName); focus->getProjection(0)->setStereotaxicXYZ(xyz); focus->setComment(comment); FociPropertiesEditorDialog::createFocus(focus, browserTabContent, this); } } } } } /** * @return The edit widget. */ QWidget* UserInputModeFociWidget::createEditOperationWidget() { const AString deleteToolTipText = ("Delete a focus by clicking the mouse over the focus." + m_transformToolTipText); QAction* deleteAction = WuQtUtilities::createAction("Delete", WuQtUtilities::createWordWrappedToolTipText(deleteToolTipText), this); deleteAction->setCheckable(true); deleteAction->setData(static_cast(UserInputModeFoci::EDIT_OPERATION_DELETE)); QToolButton* deleteToolButton = new QToolButton(); deleteToolButton->setDefaultAction(deleteAction); WuQtUtilities::setToolButtonStyleForQt5Mac(deleteToolButton); const AString propertiesToolTipText = ("Click the mouse over a focus to display a dialog " "for editing the focus' properties." + m_transformToolTipText); QAction* propertiesAction = WuQtUtilities::createAction("Properties", WuQtUtilities::createWordWrappedToolTipText(propertiesToolTipText), this); propertiesAction->setCheckable(true); propertiesAction->setData(static_cast(UserInputModeFoci::EDIT_OPERATION_PROPERTIES)); QToolButton* propertiesToolButton = new QToolButton(); propertiesToolButton->setDefaultAction(propertiesAction); WuQtUtilities::setToolButtonStyleForQt5Mac(propertiesToolButton); m_editOperationActionGroup = new QActionGroup(this); m_editOperationActionGroup->addAction(deleteAction); m_editOperationActionGroup->addAction(propertiesAction); m_editOperationActionGroup->setExclusive(true); QObject::connect(m_editOperationActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(editOperationActionTriggered(QAction*))); QWidget* widget = new QWidget(); QHBoxLayout* layout = new QHBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 0); layout->addWidget(deleteToolButton); layout->addWidget(propertiesToolButton); widget->setFixedWidth(widget->sizeHint().width()); return widget; } /** * @return The task operation widget. */ QWidget* UserInputModeFociWidget::createTaskOperationWidget() { QWidget* widget = new QWidget(); QHBoxLayout* layout = new QHBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 0); widget->setFixedWidth(widget->sizeHint().width()); return widget; } /** * Called when an edit operation button is selected. * @param action * Action that was selected. */ void UserInputModeFociWidget::editOperationActionTriggered(QAction* action) { const int editModeInteger = action->data().toInt(); const UserInputModeFoci::EditOperation editOperation = static_cast(editModeInteger); m_inputModeFoci->setEditOperation(editOperation); } connectome-workbench-1.4.2/src/GuiQt/UserInputModeFociWidget.h000066400000000000000000000057341360521144700243450ustar00rootroot00000000000000#ifndef __USER_INPUT_MODE_FOCI_WIDGET__H_ #define __USER_INPUT_MODE_FOCI_WIDGET__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" class QAction; class QActionGroup; class QComboBox; class QStackedWidget; namespace caret { class Focus; class FociFile; class UserInputModeFoci; class UserInputModeFociWidget : public QWidget { Q_OBJECT public: UserInputModeFociWidget(UserInputModeFoci* inputModeFoci, const int32_t windowIndex, QWidget* parent = 0); virtual ~UserInputModeFociWidget(); void updateWidget(); // ADD_NEW_METHODS_HERE private slots: void createNewFocusActionTriggered(); void createLastIdentificationFocusActionTriggered(); void editOperationActionTriggered(QAction*); void modeComboBoxSelection(int); private: UserInputModeFociWidget(const UserInputModeFociWidget&); UserInputModeFociWidget& operator=(const UserInputModeFociWidget&); QWidget* createModeWidget(); QWidget* createCreateOperationWidget(); QWidget* createEditOperationWidget(); QWidget* createTaskOperationWidget(); void setActionGroupByActionData(QActionGroup* actionGroup, const int dataInteger); // ADD_NEW_MEMBERS_HERE UserInputModeFoci* m_inputModeFoci; const int32_t m_windowIndex; QComboBox* m_modeComboBox; QActionGroup* m_editOperationActionGroup; QWidget* m_createOperationWidget; QWidget* m_editOperationWidget; QWidget* m_taskOperationWidget; QStackedWidget* m_operationStackedWidget; QString m_transformToolTipText; friend class UserInputModeFoci; }; #ifdef __USER_INPUT_MODE_FOCI_WIDGET_DECLARE__ #endif // __USER_INPUT_MODE_FOCI_WIDGET_DECLARE__ } // namespace #endif //__USER_INPUT_MODE_FOCI_WIDGET__H_ connectome-workbench-1.4.2/src/GuiQt/UserInputModeImage.cxx000066400000000000000000000235151360521144700237130ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __USER_INPUT_MODE_IMAGE_DECLARE__ #include "UserInputModeImage.h" #undef __USER_INPUT_MODE_IMAGE_DECLARE__ #include #include "Brain.h" #include "BrainOpenGLViewportContent.h" #include "BrainOpenGLWidget.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "ControlPoint3D.h" #include "ControlPointFile.h" #include "DisplayPropertiesImages.h" #include "EventBrowserWindowDrawingContent.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "ImageFile.h" #include "SelectionItemImage.h" #include "SelectionItemImageControlPoint.h" #include "SelectionItemVoxel.h" #include "SelectionManager.h" #include "MouseEvent.h" #include "UserInputModeImageWidget.h" #include "UserInputModeView.h" #include "VolumeFile.h" #include "WuQTimedMessageDisplay.h" using namespace caret; /** * \class caret::UserInputModeImage * \brief Processes user input for images. */ /** * Constructor. */ UserInputModeImage::UserInputModeImage(const int32_t windowIndex) : UserInputModeView(UserInputModeEnum::IMAGE), m_windowIndex(windowIndex) { m_inputModeImageWidget = new UserInputModeImageWidget(this, windowIndex); m_editOperation = EDIT_OPERATION_ADD; setWidgetForToolBar(m_inputModeImageWidget); } /** * Destructor. */ UserInputModeImage::~UserInputModeImage() { } /** * @return The edit operation. */ UserInputModeImage::EditOperation UserInputModeImage::getEditOperation() const { return m_editOperation; } /** * Set the edit operation. * @param editOperation * New edit operation. */ void UserInputModeImage::setEditOperation(const EditOperation editOperation) { m_editOperation = editOperation; } /** * Called when 'this' user input receiver is set * to receive events. */ void UserInputModeImage::initialize() { m_inputModeImageWidget->updateWidget(); } /** * Called when 'this' user input receiver is no * longer set to receive events. */ void UserInputModeImage::finish() { } /** * Called to update the input receiver for various events. */ void UserInputModeImage::update() { } /** * @return The cursor for display in the OpenGL widget. */ CursorEnum::Enum UserInputModeImage::getCursor() const { CursorEnum::Enum cursor = CursorEnum::CURSOR_DEFAULT; cursor = CursorEnum::CURSOR_POINTING_HAND; switch (m_editOperation) { case EDIT_OPERATION_ADD: cursor = CursorEnum::CURSOR_DEFAULT; break; case EDIT_OPERATION_DELETE: cursor = CursorEnum::CURSOR_CROSS; break; } return cursor; } /** * Updates after any changes to control points */ void UserInputModeImage::updateAfterControlPointsChanged() { /* * Need to update all graphics windows and all border controllers. */ EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** * Process a mouse left click event. * * @param mouseEvent * Mouse event information. */ void UserInputModeImage::mouseLeftClick(const MouseEvent& mouseEvent) { BrainOpenGLViewportContent* viewportContent = mouseEvent.getViewportContent(); if (viewportContent == NULL) { return; } BrainOpenGLWidget* openGLWidget = mouseEvent.getOpenGLWidget(); //BrowserTabContent* browserTabContent = viewportContent->getBrowserTabContent(); SelectionManager* idManager = openGLWidget->performIdentification(mouseEvent.getX(), mouseEvent.getY(), true); SelectionItemImage* idImage = idManager->getImageIdentification(); CaretAssert(idImage); SelectionItemVoxel* idVoxel = idManager->getVoxelIdentification(); CaretAssert(idVoxel); SelectionItemImageControlPoint* idImageControlPoint = idManager->getImageControlPointIdentification(); CaretAssert(idImageControlPoint); AString toolTipMessage; switch (m_editOperation) { case EDIT_OPERATION_ADD: if (idImage->isValid() && idVoxel->isValid()) { addControlPoint(idImage, idVoxel); } else if (idImage->isValid()) { toolTipMessage = "Mouse click is over image but must also be over volume slice"; } else if (idVoxel->isValid()) { toolTipMessage = "Mouse click is over volume slice but must also be over an image"; } else { toolTipMessage = "Mouse click must be over both an image and a volume slice"; } break; case EDIT_OPERATION_DELETE: if (idImageControlPoint->isValid()) { deleteControlPoint(idImageControlPoint); } else { toolTipMessage = "Mouse click must be over an image control point"; } break; } updateAfterControlPointsChanged(); if ( ! toolTipMessage.isEmpty()) { WuQTimedMessageDisplay::showModal(openGLWidget, mouseEvent.getX(), mouseEvent.getY(), 2, toolTipMessage); } } /** * Create a control point for the given image and voxel coordinates. * * @param imageSelection * The image selection. * @param voxelSelection * The voxel selection. */ void UserInputModeImage::addControlPoint(SelectionItemImage* imageSelection, const SelectionItemVoxel* voxelSelection) { ImageFile* imageFile = imageSelection->getImageFile(); CaretAssert(imageFile); ControlPointFile* controlPointFile = imageFile->getControlPointFile(); CaretAssert(controlPointFile); const float pixelX = imageSelection->getPixelI(); const float pixelY = imageSelection->getPixelJ(); const float pixelZ = 0.0; double voxelXYZ[3] = { 0.0, 0.0, 0.0 }; voxelSelection->getModelXYZ(voxelXYZ); controlPointFile->addControlPoint(ControlPoint3D(pixelX, pixelY, pixelZ, voxelXYZ[0], voxelXYZ[1], voxelXYZ[2])); } /** * Delete the selection control point. * * @param idImageControlPoint * Control point identification. */ void UserInputModeImage::deleteControlPoint(SelectionItemImageControlPoint* idImageControlPoint) { ControlPointFile* controlPointFile = idImageControlPoint->getControlPointFile(); CaretAssert(controlPointFile); const int32_t controlPointIndex = idImageControlPoint->getControlPointIndexInFile(); CaretAssert(controlPointIndex >= 0); controlPointFile->removeControlPointAtIndex(controlPointIndex); } /** * Delete all control points */ void UserInputModeImage::deleteAllControlPoints() { ImageFile* imageFile = getImageFile(); if (imageFile != NULL) { imageFile->getControlPointFile()->removeAllControlPoints(); } updateAfterControlPointsChanged(); } /** * @return The selected image file in the window (NULL if not valid) */ ImageFile* UserInputModeImage::getImageFile() const { EventBrowserWindowDrawingContent windowGet(m_windowIndex); EventManager::get()->sendEvent(windowGet.getPointer()); DisplayPropertiesImages* dpi = GuiManager::get()->getBrain()->getDisplayPropertiesImages(); BrowserTabContent* tabContent = windowGet.getSelectedBrowserTabContent(); if (tabContent == NULL) { return NULL; } const DisplayGroupEnum::Enum displayGroup = dpi->getDisplayGroupForTab(tabContent->getTabNumber()); ImageFile* imageFile = dpi->getSelectedImageFile(displayGroup, tabContent->getTabNumber()); return imageFile; } /** * @return The tab index (negative if invalid). */ int32_t UserInputModeImage::getTabIndex() const { int32_t tabIndex = -1; EventBrowserWindowDrawingContent windowGet(m_windowIndex); EventManager::get()->sendEvent(windowGet.getPointer()); //DisplayPropertiesImages* dpi = GuiManager::get()->getBrain()->getDisplayPropertiesImages(); BrowserTabContent* tabContent = windowGet.getSelectedBrowserTabContent(); if (tabContent != NULL) { tabIndex = tabContent->getTabNumber(); } return tabIndex; } /** * Show a context menu (pop-up menu at mouse location) * * @param mouseEvent * Mouse event information. * @param menuPosition * Point at which menu is displayed (passed to QMenu::exec()) * @param openGLWidget * OpenGL widget in which context menu is requested */ void UserInputModeImage::showContextMenu(const MouseEvent& /*mouseEvent*/, const QPoint& /*menuPosition*/, BrainOpenGLWidget* /*openGLWidget*/) { /* no context menu */ } connectome-workbench-1.4.2/src/GuiQt/UserInputModeImage.h000066400000000000000000000062321360521144700233350ustar00rootroot00000000000000#ifndef __USER_INPUT_MODE_IMAGE__H_ #define __USER_INPUT_MODE_IMAGE__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "UserInputModeView.h" namespace caret { class ImageFile; class SelectionItemImage; class SelectionItemImageControlPoint; class SelectionItemVoxel; class UserInputModeImageWidget; class UserInputModeImage : public UserInputModeView { public: enum EditOperation { EDIT_OPERATION_ADD, EDIT_OPERATION_DELETE }; UserInputModeImage(const int32_t windowIndex); virtual ~UserInputModeImage(); virtual void initialize(); virtual void finish(); virtual void update(); virtual CursorEnum::Enum getCursor() const; virtual void mouseLeftClick(const MouseEvent& mouseEvent); virtual void showContextMenu(const MouseEvent& mouseEvent, const QPoint& menuPosition, BrainOpenGLWidget* openGLWidget); private: /* * Note some private methods are accessed by the * friend UserInputModeImageWidget. */ friend class UserInputModeImageWidget; UserInputModeImage(const UserInputModeImage&); UserInputModeImage& operator=(const UserInputModeImage&); EditOperation getEditOperation() const; void setEditOperation(const EditOperation editOperation); void updateAfterControlPointsChanged(); void addControlPoint(SelectionItemImage* imageSelection, const SelectionItemVoxel* voxelSelection); void deleteControlPoint(SelectionItemImageControlPoint* idImageControlPoint); void deleteAllControlPoints(); ImageFile* getImageFile() const; int32_t getTabIndex() const; // ADD_NEW_MEMBERS_HERE const int32_t m_windowIndex; UserInputModeImageWidget* m_inputModeImageWidget; EditOperation m_editOperation; }; #ifdef __USER_INPUT_MODE_IMAGE_DECLARE__ // #endif // __USER_INPUT_MODE_IMAGE_DECLARE__ } // namespace #endif //__USER_INPUT_MODE_IMAGE__H_ connectome-workbench-1.4.2/src/GuiQt/UserInputModeImageWidget.cxx000066400000000000000000000241111360521144700250500ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #define __USER_INPUT_MODE_IMAGE_WIDGET_DECLARE__ #include "UserInputModeImageWidget.h" #undef __USER_INPUT_MODE_IMAGE_WIDGET_DECLARE__ #include "Brain.h" #include "BrainBrowserWindow.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "ControlPointFile.h" #include "DisplayPropertiesFoci.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "FociFile.h" #include "FociPropertiesEditorDialog.h" #include "Focus.h" #include "GuiManager.h" #include "ImageFile.h" #include "ImageFileConvertToVolumeFileDialog.h" #include "Matrix4x4.h" #include "SelectionManager.h" #include "SelectionItemSurfaceNode.h" #include "SelectionItemVoxel.h" #include "ModelSurface.h" #include "ModelWholeBrain.h" #include "Surface.h" #include "UserInputModeImage.h" #include "VolumeFile.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::UserInputModeImageWidget * \brief Foci controls shown at bottom of toolbar */ /** * Constructor. * @param inputModeImage * Process of mouse input for image * @param windowIndex * Index of browser window * @param parent * Parent widget */ UserInputModeImageWidget::UserInputModeImageWidget(UserInputModeImage* inputModeImage, const int32_t windowIndex, QWidget* parent) : QWidget(parent), m_windowIndex(windowIndex) { m_transformToolTipText = ("\n\n" "At any time, the view of the surface may be changed by\n" " PAN: Move the mouse with the left mouse button down while " "holding down the Shift key.\n" " ROTATE: Move the mouse with the left mouse button down.\n" " ZOOM: Move the mouse with the left mouse button down while " "holding down the Ctrl key (Apple key on Macs)." ); m_inputModeImage = inputModeImage; QLabel* nameLabel = new QLabel("Image Control Points "); m_editOperationWidget = createEditOperationWidget(); QHBoxLayout* layout = new QHBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 0, 0); layout->addWidget(nameLabel); layout->addSpacing(10); layout->addWidget(m_editOperationWidget); layout->addStretch(); } /** * Destructor. */ UserInputModeImageWidget::~UserInputModeImageWidget() { } /** * Update the contents of the widget. */ void UserInputModeImageWidget::updateWidget() { setActionGroupByActionData(m_editOperationActionGroup, (int)m_inputModeImage->getEditOperation()); } /** * Set the action with its data value of the given integer * as the active action. * @param actionGroup * Action group for which action is selected. * @param dataInteger * Integer value for data attribute. */ void UserInputModeImageWidget::setActionGroupByActionData(QActionGroup* actionGroup, const int dataInteger) { actionGroup->blockSignals(true); const QList actionList = actionGroup->actions(); QListIterator iter(actionList); while (iter.hasNext()) { QAction* action = iter.next(); const int actionDataInteger = action->data().toInt(); if (dataInteger == actionDataInteger) { action->setChecked(true); break; } } actionGroup->blockSignals(false); } /** * @return The edit widget. */ QWidget* UserInputModeImageWidget::createEditOperationWidget() { /* * Add button */ const AString addToolTipText = ("Click the mouse over an image and volume slice " "to add a control point." + m_transformToolTipText); QAction* addAction = WuQtUtilities::createAction("Add", WuQtUtilities::createWordWrappedToolTipText(addToolTipText), this); addAction->setCheckable(true); addAction->setData(static_cast(UserInputModeImage::EDIT_OPERATION_ADD)); QToolButton* addToolButton = new QToolButton(); addToolButton->setDefaultAction(addAction); WuQtUtilities::setToolButtonStyleForQt5Mac(addToolButton); /* * Delete button */ const AString deleteToolTipText = ("Delete a control point by clicking the mouse over the control point." + m_transformToolTipText); QAction* deleteAction = WuQtUtilities::createAction("Delete", WuQtUtilities::createWordWrappedToolTipText(deleteToolTipText), this); deleteAction->setCheckable(true); deleteAction->setData(static_cast(UserInputModeImage::EDIT_OPERATION_DELETE)); QToolButton* deleteToolButton = new QToolButton(); deleteToolButton->setDefaultAction(deleteAction); WuQtUtilities::setToolButtonStyleForQt5Mac(deleteToolButton); /* * Action group to make add/delete actions mutually exclusive */ m_editOperationActionGroup = new QActionGroup(this); m_editOperationActionGroup->addAction(deleteAction); m_editOperationActionGroup->addAction(addAction); m_editOperationActionGroup->setExclusive(true); QObject::connect(m_editOperationActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(editOperationActionTriggered(QAction*))); /* * Convert button */ const AString convertToolTipText = ("Convert image to volume"); QAction* convertAction = WuQtUtilities::createAction("Convert...", WuQtUtilities::createWordWrappedToolTipText(convertToolTipText), this, this, SLOT(convertActionTriggered())); convertAction->setCheckable(false); m_convertToolButton = new QToolButton(); m_convertToolButton->setDefaultAction(convertAction); WuQtUtilities::setToolButtonStyleForQt5Mac(m_convertToolButton); /* * Delete all button */ const AString deleteAllToolTipText = ("Delete all control points"); QAction* deleteAllAction = WuQtUtilities::createAction("Delete All", WuQtUtilities::createWordWrappedToolTipText(deleteAllToolTipText), this, this, SLOT(deleteAllActionTriggered())); deleteAllAction->setCheckable(false); m_deleteAllToolButton = new QToolButton(); m_deleteAllToolButton->setDefaultAction(deleteAllAction); WuQtUtilities::setToolButtonStyleForQt5Mac(m_deleteAllToolButton); QWidget* widget = new QWidget(); QHBoxLayout* layout = new QHBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 0); layout->addWidget(addToolButton); layout->addWidget(deleteToolButton); layout->addSpacing(15); layout->addWidget(m_deleteAllToolButton); layout->addSpacing(35); layout->addWidget(m_convertToolButton); layout->addStretch(); // widget->setFixedWidth(widget->sizeHint().width()); return widget; } /** * Called when convert action is triggered. */ void UserInputModeImageWidget::convertActionTriggered() { ImageFile* imageFile = m_inputModeImage->getImageFile(); const int32_t tabIndex = m_inputModeImage->getTabIndex(); if ((imageFile != NULL) && (tabIndex >= 0)) { ControlPointFile* controlPointFile = imageFile->getControlPointFile(); AString errorMessage; if ( ! controlPointFile->updateLandmarkTransformationMatrix(errorMessage)) { WuQMessageBox::errorOk(m_convertToolButton, errorMessage); return; } ImageFileConvertToVolumeFileDialog convertDialog(this, tabIndex, imageFile); convertDialog.exec(); } } /** * Called when convert action is triggered. */ void UserInputModeImageWidget::deleteAllActionTriggered() { if (WuQMessageBox::warningOkCancel(m_deleteAllToolButton, "Delete all control points?")) { m_inputModeImage->deleteAllControlPoints(); } } /** * Called when an edit operation button is selected. * @param action * Action that was selected. */ void UserInputModeImageWidget::editOperationActionTriggered(QAction* action) { const int editModeInteger = action->data().toInt(); const UserInputModeImage::EditOperation editOperation = static_cast(editModeInteger); m_inputModeImage->setEditOperation(editOperation); } connectome-workbench-1.4.2/src/GuiQt/UserInputModeImageWidget.h000066400000000000000000000051301360521144700244750ustar00rootroot00000000000000#ifndef __USER_INPUT_MODE_IMAGE_WIDGET__H_ #define __USER_INPUT_MODE_IMAGE_WIDGET__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" class QActionGroup; class QToolButton; namespace caret { class UserInputModeImage; class UserInputModeImageWidget : public QWidget { Q_OBJECT public: UserInputModeImageWidget(UserInputModeImage* inputModeImage, const int32_t windowIndex, QWidget* parent = 0); virtual ~UserInputModeImageWidget(); void updateWidget(); // ADD_NEW_METHODS_HERE private slots: void convertActionTriggered(); void deleteAllActionTriggered(); void editOperationActionTriggered(QAction*); private: UserInputModeImageWidget(const UserInputModeImageWidget&); UserInputModeImageWidget& operator=(const UserInputModeImageWidget&); QWidget* createEditOperationWidget(); void setActionGroupByActionData(QActionGroup* actionGroup, const int dataInteger); // ADD_NEW_MEMBERS_HERE UserInputModeImage* m_inputModeImage; const int32_t m_windowIndex; QActionGroup* m_editOperationActionGroup; QToolButton* m_deleteAllToolButton; QToolButton* m_convertToolButton; QWidget* m_editOperationWidget; QString m_transformToolTipText; friend class UserInputModeImage; }; #ifdef __USER_INPUT_MODE_IMAGE_WIDGET_DECLARE__ #endif // __USER_INPUT_MODE_IMAGE_WIDGET_DECLARE__ } // namespace #endif //__USER_INPUT_MODE_IMAGE_WIDGET__H_ connectome-workbench-1.4.2/src/GuiQt/UserInputModeView.cxx000066400000000000000000000335131360521144700236020ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __USER_INPUT_MODE_VIEW_DECLARE__ #include "UserInputModeView.h" #undef __USER_INPUT_MODE_VIEW_DECLARE__ #include "Brain.h" #include "BrainOpenGLViewportContent.h" #include "BrainOpenGLWidget.h" #include "BrowserTabContent.h" #include "ChartTwoCartesianAxis.h" #include "ChartTwoOverlaySet.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventUpdateYokedWindows.h" #include "EventUserInterfaceUpdate.h" #include "EventManager.h" #include "GuiManager.h" #include "MouseEvent.h" #include "SelectionItemChartTwoLabel.h" #include "SelectionManager.h" #include "UserInputModeViewContextMenu.h" #include "WuQDataEntryDialog.h" using namespace caret; /** * \class caret::UserInputModeView * \brief Processing user input for VIEW mode. * * Processes user input in VIEW mode which includes * viewing transformation of brain models and * identification operations. */ /** * Constructor. */ UserInputModeView::UserInputModeView() : UserInputModeAbstract(UserInputModeEnum::VIEW) { } /** * Constructor for subclasses. * * @param inputMode * Subclass' input mode. */ UserInputModeView::UserInputModeView(const UserInputModeEnum::Enum inputMode) : UserInputModeAbstract(inputMode) { } /** * Destructor. */ UserInputModeView::~UserInputModeView() { } /** * Process identification.. * * @param mouseEvent * The mouse event. * @param browserTabContent * Content of the browser window's tab. * @param openGLWidget * OpenGL Widget in which mouse event occurred. * @param mouseClickX * Location of where mouse was clicked. * @param mouseClickY * Location of where mouse was clicked. */ void UserInputModeView::processModelViewIdentification(BrainOpenGLViewportContent* viewportContent, BrainOpenGLWidget* openGLWidget, const int32_t mouseClickX, const int32_t mouseClickY) { SelectionManager* selectionManager = openGLWidget->performIdentification(mouseClickX, mouseClickY, false); BrowserTabContent* btc = viewportContent->getBrowserTabContent(); if (btc != NULL) { const int32_t tabIndex = btc->getTabNumber(); GuiManager::get()->processIdentification(tabIndex, selectionManager, openGLWidget); /* * Keep the main window as the active window NOT the identification window. * This does not work correctly on Linux as the identication window * may hide behind the main window. */ #ifdef CARET_OS_MACOSX openGLWidget->parentWidget()->activateWindow(); #endif } } /** * Called when 'this' user input receiver is set * to receive events. */ void UserInputModeView::initialize() { } /** * Called when 'this' user input receiver is no * longer set to receive events. */ void UserInputModeView::finish() { } /** * Called to update the input receiver for various events. */ void UserInputModeView::update() { } /** * @return The cursor for display in the OpenGL widget. */ CursorEnum::Enum UserInputModeView::getCursor() const { return CursorEnum::CURSOR_DEFAULT; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString UserInputModeView::toString() const { return "UserInputModeView"; } /** * Process a mouse left double-click event. * * @param mouseEvent * Mouse event information. */ void UserInputModeView::mouseLeftDoubleClick(const MouseEvent& mouseEvent) { const bool allowDoubleClickToEditChartLabel = false; if (allowDoubleClickToEditChartLabel) { const int32_t mouseX = mouseEvent.getX(); const int32_t mouseY = mouseEvent.getY(); BrainOpenGLWidget* openGLWidget = mouseEvent.getOpenGLWidget(); SelectionManager* idManager = openGLWidget->performIdentification(mouseX, mouseY, false); CaretAssert(idManager); SelectionItemChartTwoLabel* labelID = idManager->getChartTwoLabelIdentification(); if (labelID->isValid()) { ChartTwoCartesianAxis* axis = labelID->getChartTwoCartesianAxis(); ChartTwoOverlaySet* chartOverlaySet = labelID->getChartOverlaySet(); if ((axis != NULL) && (chartOverlaySet != NULL)) { WuQDataEntryDialog newNameDialog("Axis Label", openGLWidget); QLineEdit* lineEdit = newNameDialog.addLineEditWidget("Label"); lineEdit->setText(chartOverlaySet->getAxisLabel(axis)); if (newNameDialog.exec() == WuQDataEntryDialog::Accepted) { const AString name = lineEdit->text().trimmed(); chartOverlaySet->setAxisLabel(axis, name); /* * Update graphics. */ updateGraphics(mouseEvent); } } } } } /** * Process a mouse left click event. * * @param mouseEvent * Mouse event information. */ void UserInputModeView::mouseLeftClick(const MouseEvent& mouseEvent) { if (mouseEvent.getViewportContent() == NULL) { return; } processModelViewIdentification(mouseEvent.getViewportContent(), mouseEvent.getOpenGLWidget(), mouseEvent.getX(), mouseEvent.getY()); } /** * Process a mouse left click with shift key down event. * * @param mouseEvent * Mouse event information. */ void UserInputModeView::mouseLeftClickWithShift(const MouseEvent& mouseEvent) { if (mouseEvent.getViewportContent() == NULL) { return; } } /** * Process a mouse left click with ctrl and shift keys down event. * * @param mouseEvent * Mouse event information. */ void UserInputModeView::mouseLeftClickWithCtrlShift(const MouseEvent& mouseEvent) { /* * Perform identification same as a left click */ mouseLeftClick(mouseEvent); } /** * Process a mouse left drag with no keys down event. * * @param mouseEvent * Mouse event information. */ void UserInputModeView::mouseLeftDrag(const MouseEvent& mouseEvent) { BrainOpenGLViewportContent* viewportContent = mouseEvent.getViewportContent(); if (viewportContent == NULL) { return; } BrowserTabContent* browserTabContent = viewportContent->getBrowserTabContent(); if (browserTabContent == NULL) { return; } bool scrollVolumeSlicesFlag(false); if (browserTabContent->isVolumeSlicesDisplayed()) { switch (browserTabContent->getSliceProjectionType()) { case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL: scrollVolumeSlicesFlag = true; break; } } if (scrollVolumeSlicesFlag) { browserTabContent->applyMouseVolumeSliceIncrement(viewportContent, mouseEvent.getPressedX(), mouseEvent.getPressedY(), mouseEvent.getDy()); EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_UPDATE_VOLUME_SLICE_INDICES_COORDS_TOOLBAR); } else { browserTabContent->applyMouseRotation(viewportContent, mouseEvent.getPressedX(), mouseEvent.getPressedY(), mouseEvent.getX(), mouseEvent.getY(), mouseEvent.getDx(), mouseEvent.getDy()); } /* * Update graphics. */ updateGraphics(mouseEvent); } /** * Process a mouse left drag with only the alt key down event. * * @param mouseEvent * Mouse event information. */ void UserInputModeView::mouseLeftDragWithAlt(const MouseEvent& mouseEvent) { if (mouseEvent.getViewportContent() == NULL) { return; } } /** * Process a mouse left drag with ctrl key down event. * * @param mouseEvent * Mouse event information. */ void UserInputModeView::mouseLeftDragWithCtrl(const MouseEvent& mouseEvent) { BrainOpenGLViewportContent* viewportContent = mouseEvent.getViewportContent(); if (viewportContent == NULL) { return; } BrowserTabContent* browserTabContent = viewportContent->getBrowserTabContent(); if (browserTabContent == NULL) { return; } browserTabContent->applyMouseScaling(mouseEvent.getDx(), mouseEvent.getDy()); updateGraphics(mouseEvent); } /** * Process a mouse left drag with shift key down event. * * @param mouseEvent * Mouse event information. */ void UserInputModeView::mouseLeftDragWithShift(const MouseEvent& mouseEvent) { BrainOpenGLViewportContent* viewportContent = mouseEvent.getViewportContent(); if (viewportContent == NULL) { return; } BrowserTabContent* browserTabContent = viewportContent->getBrowserTabContent(); if (browserTabContent == NULL) { return; } browserTabContent->applyMouseTranslation(viewportContent, mouseEvent.getPressedX(), mouseEvent.getPressedY(), mouseEvent.getDx(), mouseEvent.getDy()); updateGraphics(mouseEvent); } /** * Show a context menu (pop-up menu at mouse location) * * @param mouseEvent * Mouse event information. * @param menuPosition * Point at which menu is displayed (passed to QMenu::exec()) * @param openGLWidget * OpenGL widget in which context menu is requested */ void UserInputModeView::showContextMenu(const MouseEvent& mouseEvent, const QPoint& menuPosition, BrainOpenGLWidget* openGLWidget) { BrainOpenGLViewportContent* viewportContent = mouseEvent.getViewportContent(); BrowserTabContent* tabContent = viewportContent->getBrowserTabContent(); if (tabContent == NULL) { return; } const int32_t mouseX = mouseEvent.getX(); const int32_t mouseY = mouseEvent.getY(); SelectionManager* idManager = openGLWidget->performIdentification(mouseX, mouseY, false); UserInputModeViewContextMenu contextMenu(viewportContent, idManager, openGLWidget); contextMenu.exec(menuPosition); } /** * If this windows is yoked, issue an event to update other * windows that are using the same yoking. */ void UserInputModeView::updateGraphics(const MouseEvent& mouseEvent) { bool issuedYokeEvent = false; if (mouseEvent.getViewportContent() != NULL) { BrowserTabContent* browserTabContent = mouseEvent.getViewportContent()->getBrowserTabContent(); const int32_t browserWindowIndex = mouseEvent.getBrowserWindowIndex(); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(browserWindowIndex).getPointer()); YokingGroupEnum::Enum brainYokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; YokingGroupEnum::Enum chartYokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; if (browserTabContent != NULL) { if (browserTabContent->isBrainModelYoked()) { brainYokingGroup = browserTabContent->getBrainModelYokingGroup(); issuedYokeEvent = true; } if (browserTabContent->isChartModelYoked()) { chartYokingGroup = browserTabContent->getChartModelYokingGroup(); issuedYokeEvent = true; } if (issuedYokeEvent) { EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendEvent(EventUpdateYokedWindows(brainYokingGroup, chartYokingGroup).getPointer()); } } } /* * If not yoked, just need to update graphics. */ if ( ! issuedYokeEvent) { EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(mouseEvent.getBrowserWindowIndex()).getPointer()); } } connectome-workbench-1.4.2/src/GuiQt/UserInputModeView.h000066400000000000000000000057721360521144700232350ustar00rootroot00000000000000#ifndef __USER_INPUT_MODE_VIEW__H_ #define __USER_INPUT_MODE_VIEW__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "UserInputModeAbstract.h" namespace caret { class UserInputModeView : public UserInputModeAbstract { public: UserInputModeView(); virtual ~UserInputModeView(); virtual void initialize(); virtual void finish(); virtual void update(); virtual CursorEnum::Enum getCursor() const; virtual void mouseLeftDoubleClick(const MouseEvent& mouseEvent); virtual void mouseLeftClick(const MouseEvent& mouseEvent); virtual void mouseLeftClickWithShift(const MouseEvent& mouseEvent); virtual void mouseLeftClickWithCtrlShift(const MouseEvent& mouseEvent); virtual void mouseLeftDrag(const MouseEvent& mouseEvent); virtual void mouseLeftDragWithAlt(const MouseEvent& mouseEvent); virtual void mouseLeftDragWithCtrl(const MouseEvent& mouseEvent); virtual void mouseLeftDragWithShift(const MouseEvent& mouseEvent); virtual void showContextMenu(const MouseEvent& mouseEvent, const QPoint& menuPosition, BrainOpenGLWidget* openGLWidget); protected: UserInputModeView(const UserInputModeEnum::Enum inputMode); private: UserInputModeView(const UserInputModeView&); UserInputModeView& operator=(const UserInputModeView&); void updateGraphics(const MouseEvent& mouseEvent); void processModelViewIdentification(BrainOpenGLViewportContent* viewportContent, BrainOpenGLWidget* openGLWidget, const int32_t mouseClickX, const int32_t mouseClickY); public: virtual AString toString() const; }; #ifdef __USER_INPUT_MODE_VIEW_DECLARE__ // #endif // __USER_INPUT_MODE_VIEW_DECLARE__ } // namespace #endif //__USER_INPUT_MODE_VIEW__H_ connectome-workbench-1.4.2/src/GuiQt/UserInputModeViewContextMenu.cxx000066400000000000000000002225561360521144700260030ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __USER_INPUT_MODE_VIEW_CONTEXT_MENU_DECLARE__ #include "UserInputModeViewContextMenu.h" #undef __USER_INPUT_MODE_VIEW_CONTEXT_MENU_DECLARE__ #include "AlgorithmException.h" #include "AlgorithmNodesInsideBorder.h" #include "Border.h" #include "Brain.h" #include "BrainBrowserWindow.h" #include "BrainOpenGLViewportContent.h" #include "BrainOpenGLWidget.h" #include "BrainStructure.h" #include "BrowserTabContent.h" #include "CaretLogger.h" #include "ChartableLineSeriesBrainordinateInterface.h" #include "ChartingDataManager.h" #include "ChartTwoCartesianAxis.h" #include "ChartTwoOverlaySet.h" #include "CiftiBrainordinateLabelFile.h" #include "CiftiConnectivityMatrixDataFileManager.h" #include "CiftiFiberTrajectoryFile.h" #include "CiftiFiberTrajectoryManager.h" #include "CiftiMappableConnectivityMatrixDataFile.h" #include "CursorDisplayScoped.h" #include "EventCaretMappableDataFilesAndMapsInDisplayedOverlays.h" #include "EventManager.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventUpdateInformationWindows.h" #include "EventUserInterfaceUpdate.h" #include "FociPropertiesEditorDialog.h" #include "Focus.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "GuiManager.h" #include "IdentifiedItemNode.h" #include "IdentificationManager.h" #include "LabelFile.h" #include "MapFileDataSelector.h" #include "Overlay.h" #include "OverlaySet.h" #include "MetricDynamicConnectivityFile.h" #include "Model.h" #include "ProgressReportingDialog.h" #include "SelectionItemBorderSurface.h" #include "SelectionItemChartTwoLabel.h" #include "SelectionItemFocusSurface.h" #include "SelectionItemFocusVolume.h" #include "SelectionItemSurfaceNode.h" #include "SelectionItemSurfaceNodeIdentificationSymbol.h" #include "SelectionItemVoxel.h" #include "SelectionManager.h" #include "SessionManager.h" #include "Surface.h" #include "UserInputModeFociWidget.h" #include "UserInputTileTabsContextMenu.h" #include "VolumeDynamicConnectivityFile.h" #include "VolumeFile.h" #include "WuQDataEntryDialog.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::UserInputModeViewContextMenu * \brief Context (pop-up) menu for User Input View Mode * * Displays a menu in the BrainOpenGLWidget. Content of menu * is dependent upon data under the cursor. */ /** * Constructor. * * @param viewportContent * Content of the viewport. * @param selectionManager * The selection manager, provides data under the cursor. * @param parentOpenGLWidget * Parent OpenGL Widget on which the menu is displayed. */ UserInputModeViewContextMenu::UserInputModeViewContextMenu(BrainOpenGLViewportContent* viewportContent, SelectionManager* selectionManager, BrainOpenGLWidget* parentOpenGLWidget) : QMenu(parentOpenGLWidget) { this->viewportContent = viewportContent; CaretAssert(this->viewportContent); this->parentOpenGLWidget = parentOpenGLWidget; this->selectionManager = selectionManager; this->browserTabContent = viewportContent->getBrowserTabContent(); CaretAssert(this->browserTabContent); UserInputTileTabsContextMenu* tabMenu = new UserInputTileTabsContextMenu(this->parentOpenGLWidget, this->viewportContent); if (tabMenu->isValid()) { addSubMenuToMenu(tabMenu, true); } else { delete tabMenu; tabMenu = NULL; } /* * Add the identification actions. */ addIdentificationActions(); /* * Add the border options. */ addBorderRegionOfInterestActions(); /* * Add the chart actions */ addChartActions(); /* * Add the foci actions. */ addFociActions(); /* * Show Label ROI operations only for surfaces */ addLabelRegionOfInterestActions(); const SelectionItemSurfaceNodeIdentificationSymbol* idSymbol = selectionManager->getSurfaceNodeIdentificationSymbol(); bool showRemoveVertexSymbolsFlag = false; if (this->browserTabContent != NULL) { switch (this->browserTabContent->getSelectedModelType()) { case ModelTypeEnum::MODEL_TYPE_CHART: break; case ModelTypeEnum::MODEL_TYPE_CHART_TWO: break; case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: showRemoveVertexSymbolsFlag = true; break; case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: showRemoveVertexSymbolsFlag = true; break; case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: showRemoveVertexSymbolsFlag = true; break; case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: showRemoveVertexSymbolsFlag = true; break; } } if (showRemoveVertexSymbolsFlag) { if (this->actions().count() > 0) { this->addSeparator(); } this->addAction("Remove All Vertex Identification Symbols", this, SLOT(removeAllNodeIdentificationSymbolsSelected())); } if (idSymbol->isValid()) { const AString text = ("Remove Identification of Vertices " + AString::number(idSymbol->getNodeNumber())); this->addAction(WuQtUtilities::createAction(text, "", this, this, SLOT(removeNodeIdentificationSymbolSelected()))); } } /** * Destructor. */ UserInputModeViewContextMenu::~UserInputModeViewContextMenu() { for (std::vector::iterator parcelIter = this->parcelConnectivities.begin(); parcelIter != this->parcelConnectivities.end(); parcelIter++) { delete *parcelIter; } } /** * Add the actions to this context menu. * * @param actionsToAdd * Actions to add to the menu. * @param addSeparatorBeforeActions * If true and there are actions presently in the menu, a separator * (horizontal bar) is added prior to adding the given actions. */ void UserInputModeViewContextMenu::addActionsToMenu(QList& actionsToAdd, const bool addSeparatorBeforeActions) { if (actionsToAdd.empty() == false) { if (addSeparatorBeforeActions) { if (actions().isEmpty() == false) { addSeparator(); } } addActions(actionsToAdd); } } /** * Add a submenu to this menu. * * @param menu * Menu that is added. * @param addSeparatorBeforeMenu * If true and the menu is not empty, add a separator before * adding the sub menu. */ void UserInputModeViewContextMenu::addSubMenuToMenu(QMenu* menu, const bool addSeparatorBeforeMenu) { CaretAssert(menu); if (addSeparatorBeforeMenu) { if (actions().isEmpty() == false) { addSeparator(); } addMenu(menu); } } /** * Add the identification actions to the menu. */ void UserInputModeViewContextMenu::addIdentificationActions() { /* * Accumlate identification actions */ QList identificationActions; /* * Identify Border */ SelectionItemBorderSurface* borderID = this->selectionManager->getSurfaceBorderIdentification(); if (borderID->isValid()) { const QString text = ("Identify Border (" + borderID->getBorder()->getName() + ") Under Mouse"); identificationActions.push_back(WuQtUtilities::createAction(text, "", this, this, SLOT(identifySurfaceBorderSelected()))); } /* * Identify Surface Focus */ SelectionItemFocusSurface* focusID = this->selectionManager->getSurfaceFocusIdentification(); if (focusID->isValid()) { const QString text = ("Identify Surface Focus (" + focusID->getFocus()->getName() + ") Under Mouse"); identificationActions.push_back(WuQtUtilities::createAction(text, "", this, this, SLOT(identifySurfaceFocusSelected()))); } /* * Identify Node */ SelectionItemSurfaceNode* surfaceID = this->selectionManager->getSurfaceNodeIdentification(); if (surfaceID->isValid()) { const int32_t nodeIndex = surfaceID->getNodeNumber(); const Surface* surface = surfaceID->getSurface(); const QString text = ("Identify Vertex " + QString::number(nodeIndex) + " (" + AString::fromNumbers(surface->getCoordinate(nodeIndex), 3, ",") + ") Under Mouse"); identificationActions.push_back(WuQtUtilities::createAction(text, "", this, this, SLOT(identifySurfaceNodeSelected()))); } /* * Identify Voxel */ SelectionItemVoxel* idVoxel = this->selectionManager->getVoxelIdentification(); if (idVoxel->isValid()) { int64_t ijk[3]; idVoxel->getVoxelIJK(ijk); const AString text = ("Identify Voxel (" + AString::fromNumbers(ijk, 3, ",") + ")"); identificationActions.push_back(WuQtUtilities::createAction(text, "", this, this, SLOT(identifyVoxelSelected()))); } /* * Identify Volume Focus */ SelectionItemFocusVolume* focusVolID = this->selectionManager->getVolumeFocusIdentification(); if (focusVolID->isValid()) { const QString text = ("Identify Volume Focus (" + focusVolID->getFocus()->getName() + ") Under Mouse"); identificationActions.push_back(WuQtUtilities::createAction(text, "", this, this, SLOT(identifyVolumeFocusSelected()))); } addActionsToMenu(identificationActions, true); } /** * Add the border region of interest actions to the menu. */ void UserInputModeViewContextMenu::addBorderRegionOfInterestActions() { SelectionItemBorderSurface* borderID = this->selectionManager->getSurfaceBorderIdentification(); QList borderActions; if (borderID->isValid()) { Brain* brain = borderID->getBrain(); std::vector ciftiMatrixFiles; brain->getAllCiftiConnectivityMatrixFiles(ciftiMatrixFiles); bool hasConnectivityFile = (ciftiMatrixFiles.empty() == false); std::vector metricDynConnFiles; brain->getMetricDynamicConnectivityFiles(metricDynConnFiles); for (auto mdc : metricDynConnFiles) { if (mdc->isDataLoadingEnabled()) { hasConnectivityFile = true; } } /* * Connectivity actions for borders */ if (hasConnectivityFile) { const QString text = ("Show Connectivity for Vertices Inside Border " + borderID->getBorder()->getName()); QAction* action = WuQtUtilities::createAction(text, "", this, this, SLOT(borderCiftiConnectivitySelected())); borderActions.push_back(action); } std::vector chartableFiles; brain->getAllChartableBrainordinateDataFiles(chartableFiles); if (chartableFiles.empty() == false) { const QString text = ("Show Charts for Vertices Inside Border " + borderID->getBorder()->getName()); QAction* action = WuQtUtilities::createAction(text, "", this, this, SLOT(borderDataSeriesSelected())); borderActions.push_back(action); } } addActionsToMenu(borderActions, true); } /** * Create the parcel (label) information. It finds * ALL label files and uses the label from every map * in the file that is associated withe the selected * brainordinate. */ void UserInputModeViewContextMenu::createParcelConnectivities() { Brain* brain = NULL; /* * Note that in an 'ALL' view there may be both * an identified surface node and an identified voxel */ float voxelXYZ[3] = { 0.0, 0.0, 0.0 }; SelectionItemVoxel* idVoxel = this->selectionManager->getVoxelIdentification(); if (idVoxel->isValid()) { double voxelXYZDouble[3]; idVoxel->getModelXYZ(voxelXYZDouble); voxelXYZ[0] = voxelXYZDouble[0]; voxelXYZ[1] = voxelXYZDouble[1]; voxelXYZ[2] = voxelXYZDouble[2]; brain = idVoxel->getBrain(); } Surface* surface = NULL; int32_t surfaceNodeIndex = -1; int32_t surfaceNumberOfNodes = -1; StructureEnum::Enum surfaceStructure = StructureEnum::INVALID; SelectionItemSurfaceNode* idNode = this->selectionManager->getSurfaceNodeIdentification(); if (idNode->isValid()) { surface = idNode->getSurface(); surfaceNodeIndex = idNode->getNodeNumber(); surfaceNumberOfNodes = surface->getNumberOfNodes(); surfaceStructure = surface->getStructure(); brain = idNode->getBrain(); } if (brain == NULL) { return; } if (idNode->isValid() && idVoxel->isValid()) { std::cout << "Have both surface and volume ID" << std::endl; } /* * If true, only labels in file in the selected tab * are available. */ const bool limitToFilesInSelectedTabFlag(true); std::vector mapFiles; if (limitToFilesInSelectedTabFlag) { CaretAssert(this->browserTabContent); std::vector dataFiles; this->browserTabContent->getFilesDisplayedInTab(dataFiles); for (auto df : dataFiles) { CaretMappableDataFile* cmdf = dynamic_cast(df); if (cmdf != NULL) { mapFiles.push_back(cmdf); } } } else { brain->getAllMappableDataFiles(mapFiles); } for (auto mapFile : mapFiles) { if (mapFile->isMappedWithLabelTable()) { const int32_t numberOfMaps = mapFile->getNumberOfMaps(); for (int32_t mapIndex = 0; mapIndex < numberOfMaps; mapIndex++) { Surface* labelSurface = NULL; int32_t labelNodeNumber = -1; int32_t labelKey = -1; AString labelName; int64_t volumeDimensions[3] = { -1, -1, -1 }; ParcelType parcelType = ParcelType::PARCEL_TYPE_INVALID; AString mapName = AString::number(mapIndex + 1); if (mapFile->getMapName(mapIndex).isEmpty()) { mapName.append(": "); } else { mapName.append(": " + mapFile->getMapName(mapIndex)); } /* * Is this a volume label file, if so, find the * label for this 'mapIndex' */ if (mapFile->isVolumeMappable()) { CiftiBrainordinateLabelFile* ciftiLabelFile = dynamic_cast(mapFile); VolumeFile* volumeLabelFile = dynamic_cast(mapFile); VolumeMappableInterface* volumeInterface = dynamic_cast(mapFile); if (volumeInterface != NULL) { int64_t voxelIJK[3]; float voxelValue; bool voxelValueValid; AString textValue; if (ciftiLabelFile != NULL) { if (ciftiLabelFile->getMapVolumeVoxelValue(mapIndex, voxelXYZ, voxelIJK, voxelValue, voxelValueValid, textValue)) { if (voxelValueValid) { labelKey = static_cast(voxelValue); const GiftiLabelTable* labelTable = ciftiLabelFile->getMapLabelTable(mapIndex); labelName = labelTable->getLabelName(labelKey); if (labelName.isEmpty() == false) { parcelType = ParcelType::PARCEL_TYPE_VOLUME_VOXELS; } } } } else if (volumeLabelFile != NULL) { int64_t voxelIJK[3]; volumeLabelFile->enclosingVoxel(voxelXYZ, voxelIJK); if (volumeLabelFile->indexValid(voxelIJK)) { const float voxelValue = volumeLabelFile->getValue(voxelIJK[0], voxelIJK[1], voxelIJK[2], mapIndex); const GiftiLabelTable* labelTable = volumeLabelFile->getMapLabelTable(mapIndex); labelKey = static_cast(voxelValue); labelName = labelTable->getLabelName(voxelValue); if (labelName.isEmpty() == false) { parcelType = ParcelType::PARCEL_TYPE_VOLUME_VOXELS; } } } else { CaretAssertMessage(0, "Should never get here, new or invalid label file type"); } std::vector dims; volumeInterface->getDimensions(dims); if (dims.size() >= 3) { volumeDimensions[0] = dims[0]; volumeDimensions[1] = dims[1]; volumeDimensions[2] = dims[2]; } /* * Create the parcel connectivity */ if (labelName == "???") { parcelType = ParcelType::PARCEL_TYPE_INVALID; } if (parcelType != ParcelType::PARCEL_TYPE_INVALID) { ParcelConnectivity* parcelConnectivity = new ParcelConnectivity(brain, parcelType, mapFile, mapIndex, mapName, labelKey, labelName, labelSurface, labelNodeNumber, volumeDimensions, brain->getChartingDataManager(), SessionManager::get()->getCiftiConnectivityMatrixDataFileManager(), SessionManager::get()->getCiftiFiberTrajectoryManager()); this->parcelConnectivities.push_back(parcelConnectivity); } } } /* * Is this a surface mapped label file, if so, * find the label for this 'mapIndex' */ if (mapFile->isSurfaceMappable()) { if (labelName.isEmpty()) { if (idNode->isValid()) { labelSurface = idNode->getSurface(); labelNodeNumber = idNode->getNodeNumber(); LabelFile* labelFile = dynamic_cast(mapFile); CiftiBrainordinateLabelFile* ciftiLabelFile = dynamic_cast(mapFile); if (labelFile != NULL) { labelKey = labelFile->getLabelKey(labelNodeNumber, mapIndex); const GiftiLabelTable* labelTable = labelFile->getMapLabelTable(mapIndex); labelName = labelTable->getLabelName(labelKey); if (labelName.isEmpty() == false) { parcelType = ParcelType::PARCEL_TYPE_SURFACE_NODES; } } else if (ciftiLabelFile != NULL) { float nodeValue = 0.0; bool nodeValueValid = false; AString stringValue; if (ciftiLabelFile->getMapSurfaceNodeValue(mapIndex, surfaceStructure, surfaceNodeIndex, surfaceNumberOfNodes, nodeValue, nodeValueValid, stringValue)) { if (nodeValueValid) { labelKey = nodeValue; const GiftiLabelTable* labelTable = ciftiLabelFile->getMapLabelTable(mapIndex); labelName = labelTable->getLabelName(labelKey); if (labelName.isEmpty() == false) { parcelType = ParcelType::PARCEL_TYPE_SURFACE_NODES; } } } } /* * Create the parcel connectivity */ if (labelName == "???") { parcelType = ParcelType::PARCEL_TYPE_INVALID; } if (parcelType != ParcelType::PARCEL_TYPE_INVALID) { ParcelConnectivity* parcelConnectivity = new ParcelConnectivity(brain, parcelType, mapFile, mapIndex, mapName, labelKey, labelName, labelSurface, labelNodeNumber, volumeDimensions, brain->getChartingDataManager(), SessionManager::get()->getCiftiConnectivityMatrixDataFileManager(), SessionManager::get()->getCiftiFiberTrajectoryManager()); this->parcelConnectivities.push_back(parcelConnectivity); } } } } } } } } /** * Add all label region of interest options to the menu */ void UserInputModeViewContextMenu::addLabelRegionOfInterestActions() { createParcelConnectivities(); /* * File types of interest */ std::vector ciftiMatrixFiles; std::vector ciftiFiberTrajectoryFiles; std::vector chartableFiles; std::vector metricDynConnFiles; std::vector volDynConnFiles; /* * Get all files in displayed overlays */ EventCaretMappableDataFilesAndMapsInDisplayedOverlays allOverlayDisplayedFilesEvent; EventManager::get()->sendEvent(allOverlayDisplayedFilesEvent.getPointer()); auto mapFilesAndIndices = allOverlayDisplayedFilesEvent.getFilesAndMaps(); /* * Find matrix, fiber trajectory, and line-series files that are displayed */ for (auto mapFileAndIndex : mapFilesAndIndices) { CaretMappableDataFile* mapFile = mapFileAndIndex.m_mapFile; CaretAssert(mapFile); CiftiMappableConnectivityMatrixDataFile* matrixFile = dynamic_cast(mapFile); if (matrixFile != NULL) { ciftiMatrixFiles.push_back(matrixFile); } CiftiFiberTrajectoryFile* fiberTrajFile = dynamic_cast(mapFile); if (fiberTrajFile != NULL) { ciftiFiberTrajectoryFiles.push_back(fiberTrajFile); } ChartableLineSeriesBrainordinateInterface* lineSeriesFile = dynamic_cast(mapFile); if (lineSeriesFile != NULL) { chartableFiles.push_back(lineSeriesFile); } MetricDynamicConnectivityFile* metricDynConnFile = dynamic_cast(mapFile); if (metricDynConnFile != NULL) { metricDynConnFiles.push_back(metricDynConnFile); } VolumeDynamicConnectivityFile* volDynnFile = dynamic_cast(mapFile); if (volDynnFile != NULL) { volDynConnFiles.push_back(volDynnFile); } } const bool hasDynamicConnectivity = ( ( ! ciftiMatrixFiles.empty()) || ( ! metricDynConnFiles.empty()) || ( ! volDynConnFiles.empty()) ); const bool haveCiftiFiberTrajectoryFiles = ( ! ciftiFiberTrajectoryFiles.empty()); const bool haveChartableFiles = ( ! chartableFiles.empty()); /* * Actions for each file type */ QList connectivityActions; QActionGroup* connectivityActionGroup = new QActionGroup(this); QObject::connect(connectivityActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(connectivityActionSelected(QAction*))); QList ciftiFiberTrajectoryActions; QActionGroup* ciftiFiberTrajectoryActionGroup = new QActionGroup(this); QObject::connect(ciftiFiberTrajectoryActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(parcelCiftiFiberTrajectoryActionSelected(QAction*))); QList chartableDataActions; QActionGroup* chartableDataActionGroup = new QActionGroup(this); QObject::connect(chartableDataActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(parcelChartableDataActionSelected(QAction*))); for (auto parcelConnectivity : this->parcelConnectivities) { const ParcelType parcelType = parcelConnectivity->parcelType; const AString sourceLabelName("Region \"" + parcelConnectivity->labelName + "\" from map \"" + parcelConnectivity->mapName + "\""); if (hasDynamicConnectivity) { bool matchFlag = false; if (parcelType == ParcelType::PARCEL_TYPE_SURFACE_NODES) { matchFlag = true; } else if (parcelType == ParcelType::PARCEL_TYPE_VOLUME_VOXELS) { for (std::vector::iterator iter = ciftiMatrixFiles.begin(); iter != ciftiMatrixFiles.end(); iter++) { const CiftiMappableConnectivityMatrixDataFile* ciftiFile = *iter; if (ciftiFile->matchesDimensions(parcelConnectivity->volumeDimensions[0], parcelConnectivity->volumeDimensions[1], parcelConnectivity->volumeDimensions[2])) { matchFlag = true; break; } } for (auto volDynFile : volDynConnFiles) { if (volDynFile->matchesDimensions(parcelConnectivity->volumeDimensions[0], parcelConnectivity->volumeDimensions[1], parcelConnectivity->volumeDimensions[2])) { matchFlag = true; break; } } } if (matchFlag) { const AString actionName("Show Connectivity for " + sourceLabelName); QAction* action = connectivityActionGroup->addAction(actionName); action->setData(qVariantFromValue((void*)parcelConnectivity)); connectivityActions.push_back(action); } } if (haveCiftiFiberTrajectoryFiles) { const AString fiberTrajActionName("Show Average Fiber Trajectory for " + sourceLabelName); QAction* fiberTrajAction = ciftiFiberTrajectoryActionGroup->addAction(fiberTrajActionName); fiberTrajAction->setData(qVariantFromValue((void*)parcelConnectivity)); ciftiFiberTrajectoryActions.push_back(fiberTrajAction); } if (haveChartableFiles) { bool matchFlag = false; if (parcelType == ParcelType::PARCEL_TYPE_SURFACE_NODES) { matchFlag = true; } else if (parcelType == ParcelType::PARCEL_TYPE_VOLUME_VOXELS) { for (std::vector::iterator iter = chartableFiles.begin(); iter != chartableFiles.end(); iter++) { const ChartableLineSeriesBrainordinateInterface* chartFile = *iter; const CaretMappableDataFile* mapDataFile = chartFile->getLineSeriesChartCaretMappableDataFile(); if (mapDataFile != NULL){ if (mapDataFile->isVolumeMappable()) { const VolumeMappableInterface* volMap = dynamic_cast(mapDataFile); if (volMap->matchesDimensions(parcelConnectivity->volumeDimensions[0], parcelConnectivity->volumeDimensions[1], parcelConnectivity->volumeDimensions[2])) { matchFlag = true; break; } } } } } if (matchFlag) { const AString tsActionName("Show Data/Time Series Graph For " + sourceLabelName); QAction* tsAction = chartableDataActionGroup->addAction(tsActionName); tsAction->setData(qVariantFromValue((void*)parcelConnectivity)); chartableDataActions.push_back(tsAction); } } } addActionsToMenu(connectivityActions, true); addActionsToMenu(ciftiFiberTrajectoryActions, true); addActionsToMenu(chartableDataActions, true); } /** * Add chart options to the menu */ void UserInputModeViewContextMenu::addChartActions() { QList chartActions; SelectionItemChartTwoLabel* labelID = this->selectionManager->getChartTwoLabelIdentification(); if (labelID->isValid()) { chartActions.push_back(WuQtUtilities::createAction("Edit Chart Axis Label...", "", this, this, SLOT(editChartLabelSelected()))); } addActionsToMenu(chartActions, true); } /** * Called to edit the chart label. */ void UserInputModeViewContextMenu::editChartLabelSelected() { SelectionItemChartTwoLabel* labelID = this->selectionManager->getChartTwoLabelIdentification(); if (labelID->isValid()) { ChartTwoCartesianAxis* axis = labelID->getChartTwoCartesianAxis(); ChartTwoOverlaySet* chartOverlaySet = labelID->getChartOverlaySet(); if ((axis != NULL) && (chartOverlaySet != NULL)) { WuQDataEntryDialog newNameDialog("Axis Label", this); QLineEdit* lineEdit = newNameDialog.addLineEditWidget("Label"); lineEdit->setText(chartOverlaySet->getAxisLabel(axis)); if (newNameDialog.exec() == WuQDataEntryDialog::Accepted) { const AString name = lineEdit->text().trimmed(); chartOverlaySet->setAxisLabel(axis, name); /* * Update graphics. */ EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } } } /** * Add the foci options to the menu. */ void UserInputModeViewContextMenu::addFociActions() { QList fociCreateActions; const SelectionItemSurfaceNodeIdentificationSymbol* idSymbol = selectionManager->getSurfaceNodeIdentificationSymbol(); SelectionItemFocusSurface* focusID = this->selectionManager->getSurfaceFocusIdentification(); SelectionItemSurfaceNode* surfaceID = this->selectionManager->getSurfaceNodeIdentification(); SelectionItemVoxel* idVoxel = this->selectionManager->getVoxelIdentification(); SelectionItemFocusVolume* focusVolID = this->selectionManager->getVolumeFocusIdentification(); /* * Create focus at surface node or at ID symbol */ if (surfaceID->isValid() && (focusID->isValid() == false)) { const int32_t nodeIndex = surfaceID->getNodeNumber(); const Surface* surface = surfaceID->getSurface(); const QString text = ("Create Focus at Vertex " + QString::number(nodeIndex) + " (" + AString::fromNumbers(surface->getCoordinate(nodeIndex), 3, ",") + ")..."); fociCreateActions.push_back(WuQtUtilities::createAction(text, "", this, this, SLOT(createSurfaceFocusSelected()))); } else if (idSymbol->isValid() && (focusID->isValid() == false)) { const int32_t nodeIndex = idSymbol->getNodeNumber(); const Surface* surface = idSymbol->getSurface(); const QString text = ("Create Focus at Selected Vertex " + QString::number(nodeIndex) + " (" + AString::fromNumbers(surface->getCoordinate(nodeIndex), 3, ",") + ")..."); fociCreateActions.push_back(WuQtUtilities::createAction(text, "", this, this, SLOT(createSurfaceIDSymbolFocusSelected()))); } /* * Create focus at voxel as long as there is no volume focus ID */ if (idVoxel->isValid() && (focusVolID->isValid() == false)) { int64_t ijk[3]; idVoxel->getVoxelIJK(ijk); float xyz[3]; const VolumeMappableInterface* vf = idVoxel->getVolumeFile(); vf->indexToSpace(ijk, xyz); const AString text = ("Create Focus at Voxel IJK (" + AString::fromNumbers(ijk, 3, ",") + ") XYZ (" + AString::fromNumbers(xyz, 3, ",") + ")..."); fociCreateActions.push_back(WuQtUtilities::createAction(text, "", this, this, SLOT(createVolumeFocusSelected()))); } addActionsToMenu(fociCreateActions, true); /* * Actions for editing */ QList fociEditActions; /* * Edit Surface Focus */ if (focusID->isValid()) { const QString text = ("Edit Surface Focus (" + focusID->getFocus()->getName() + ")"); fociEditActions.push_back(WuQtUtilities::createAction(text, "", this, this, SLOT(editSurfaceFocusSelected()))); } /* * Edit volume focus */ if (focusVolID->isValid()) { const QString text = ("Edit Volume Focus (" + focusVolID->getFocus()->getName() + ")"); fociEditActions.push_back(WuQtUtilities::createAction(text, "", this, this, SLOT(editVolumeFocusSelected()))); } addActionsToMenu(fociEditActions, true); } /** * Called when a cifti connectivity action is selected. * @param action * Action that was selected. */ void UserInputModeViewContextMenu::connectivityActionSelected(QAction* action) { void* pointer = action->data().value(); ParcelConnectivity* pc = (ParcelConnectivity*)pointer; std::vector nodeIndices; std::vector voxelIndices; switch (pc->parcelType) { case ParcelType::PARCEL_TYPE_INVALID: break; case ParcelType::PARCEL_TYPE_SURFACE_NODES: pc->getNodeIndices(nodeIndices); if (nodeIndices.empty()) { WuQMessageBox::errorOk(this, "No vertices match label " + pc->labelName); return; } if (pc->ciftiConnectivityManager->hasNetworkFiles(pc->brain)) { if (warnIfNetworkBrainordinateCountIsLarge(nodeIndices.size()) == false) { return; } } break; case ParcelType::PARCEL_TYPE_VOLUME_VOXELS: pc->getVoxelIndices(voxelIndices); if (voxelIndices.empty()) { WuQMessageBox::errorOk(this, "No voxels match label " + pc->labelName); return; } if (pc->ciftiConnectivityManager->hasNetworkFiles(pc->brain)) { if (warnIfNetworkBrainordinateCountIsLarge(voxelIndices.size()) == false) { return; } } break; } CursorDisplayScoped cursor; cursor.showWaitCursor(); try { ProgressReportingDialog progressDialog("Connectivity Within Parcel", "", this); progressDialog.setValue(0); switch (pc->parcelType) { case ParcelType::PARCEL_TYPE_INVALID: break; case ParcelType::PARCEL_TYPE_SURFACE_NODES: pc->ciftiConnectivityManager->loadAverageDataForSurfaceNodes(pc->brain, pc->surface, nodeIndices); { std::vector metricDynConnFiles; pc->brain->getMetricDynamicConnectivityFiles(metricDynConnFiles); for (auto mdcf : metricDynConnFiles) { mdcf->loadAverageDataForSurfaceNodes(pc->surface->getNumberOfNodes(), pc->surface->getStructure(), nodeIndices); } } break; case ParcelType::PARCEL_TYPE_VOLUME_VOXELS: pc->ciftiConnectivityManager->loadAverageDataForVoxelIndices(pc->brain, pc->volumeDimensions, voxelIndices); { std::vector volDynConnFiles; pc->brain->getVolumeDynamicConnectivityFiles(volDynConnFiles); for (auto vdcf : volDynConnFiles) { vdcf->loadMapAverageDataForVoxelIndices(pc->volumeDimensions, voxelIndices); } } break; } } catch (const DataFileException& e) { cursor.restoreCursor(); WuQMessageBox::errorOk(this, e.whatString()); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called when a cifti connectivity action is selected. * @param action * Action that was selected. */ void UserInputModeViewContextMenu::parcelCiftiFiberTrajectoryActionSelected(QAction* action) { void* pointer = action->data().value(); ParcelConnectivity* pc = (ParcelConnectivity*)pointer; std::vector nodeIndices; switch (pc->parcelType) { case ParcelType::PARCEL_TYPE_INVALID: break; case ParcelType::PARCEL_TYPE_SURFACE_NODES: pc->getNodeIndices(nodeIndices); if (nodeIndices.empty()) { WuQMessageBox::errorOk(this, "No vertices match label " + pc->labelName); return; } break; case ParcelType::PARCEL_TYPE_VOLUME_VOXELS: break; } CursorDisplayScoped cursor; cursor.showWaitCursor(); try { ProgressReportingDialog progressDialog("Trajectory Within Parcel", "", this); progressDialog.setValue(0); switch (pc->parcelType) { case ParcelType::PARCEL_TYPE_INVALID: break; case ParcelType::PARCEL_TYPE_SURFACE_NODES: pc->ciftiFiberTrajectoryManager->loadDataAverageForSurfaceNodes(pc->brain, pc->surface, nodeIndices); break; case ParcelType::PARCEL_TYPE_VOLUME_VOXELS: std::vector voxelIndices; pc->getVoxelIndices(voxelIndices); pc->ciftiFiberTrajectoryManager->loadAverageDataForVoxelIndices(pc->brain, pc->volumeDimensions, voxelIndices); break; } } catch (const DataFileException& e) { cursor.restoreCursor(); WuQMessageBox::errorOk(this, e.whatString()); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called when border cifti connectivity is selected. */ void UserInputModeViewContextMenu::borderCiftiConnectivitySelected() { SelectionItemBorderSurface* borderID = this->selectionManager->getSurfaceBorderIdentification(); Border* border = borderID->getBorder(); Surface* surface = borderID->getSurface(); const int32_t numberOfNodes = surface->getNumberOfNodes(); LabelFile labelFile; labelFile.setNumberOfNodesAndColumns(numberOfNodes, 1); const int32_t labelKey = labelFile.getLabelTable()->addLabel("TempLabel", 1.0f, 1.0f, 1.0f, 1.0f); const int32_t mapIndex = 0; try { AlgorithmNodesInsideBorder algorithmInsideBorder(NULL, surface, border, false, mapIndex, labelKey, &labelFile); std::vector nodeIndices; nodeIndices.reserve(numberOfNodes); for (int32_t i = 0; i < numberOfNodes; i++) { if (labelFile.getLabelKey(i, mapIndex) == labelKey) { nodeIndices.push_back(i); } } if (nodeIndices.empty()) { WuQMessageBox::errorOk(this, "No vertices found inside border " + border->getName()); return; } if (borderID->getBrain()->getChartingDataManager()->hasNetworkFiles()) { if (warnIfNetworkBrainordinateCountIsLarge(nodeIndices.size()) == false) { return; } } CursorDisplayScoped cursor; cursor.showWaitCursor(); try { ProgressReportingDialog progressDialog("Connectivity Within Border", "", this); progressDialog.setValue(0); CiftiConnectivityMatrixDataFileManager* ciftiConnMann = SessionManager::get()->getCiftiConnectivityMatrixDataFileManager(); ciftiConnMann->loadAverageDataForSurfaceNodes(borderID->getBrain(), surface, nodeIndices); { Brain* brain = GuiManager::get()->getBrain(); std::vector metricDynConnFiles; brain->getMetricDynamicConnectivityFiles(metricDynConnFiles); for (auto mdcf : metricDynConnFiles) { mdcf->loadAverageDataForSurfaceNodes(surface->getNumberOfNodes(), surface->getStructure(), nodeIndices); } } } catch (const DataFileException& e) { cursor.restoreCursor(); WuQMessageBox::errorOk(this, e.whatString()); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } catch (const AlgorithmException& e) { WuQMessageBox::errorOk(this, e.whatString()); } } /** * Called when a connectivity action is selected. * @param action * Action that was selected. */ void UserInputModeViewContextMenu::parcelChartableDataActionSelected(QAction* action) { void* pointer = action->data().value(); ParcelConnectivity* pc = (ParcelConnectivity*)pointer; std::vector nodeIndices; std::vector voxelIndices; switch (pc->parcelType) { case ParcelType::PARCEL_TYPE_INVALID: break; case ParcelType::PARCEL_TYPE_SURFACE_NODES: pc->getNodeIndices(nodeIndices); if (nodeIndices.empty()) { WuQMessageBox::errorOk(this, "No vertices match label " + pc->labelName); return; } if (pc->chartingDataManager->hasNetworkFiles()) { if (warnIfNetworkBrainordinateCountIsLarge(nodeIndices.size()) == false) { return; } } break; case ParcelType::PARCEL_TYPE_VOLUME_VOXELS: pc->getVoxelIndices(voxelIndices); if (voxelIndices.empty()) { WuQMessageBox::errorOk(this, "No voxels match label " + pc->labelName); return; } if (pc->chartingDataManager->hasNetworkFiles()) { if (warnIfNetworkBrainordinateCountIsLarge(voxelIndices.size()) == false) { return; } } break; } CursorDisplayScoped cursor; cursor.showWaitCursor(); try { ProgressReportingDialog progressDialog("Data Series Within Parcel", "", this); progressDialog.setValue(0); switch (pc->parcelType) { case ParcelType::PARCEL_TYPE_INVALID: break; case ParcelType::PARCEL_TYPE_SURFACE_NODES: pc->chartingDataManager->loadAverageChartForSurfaceNodes(pc->surface, nodeIndices); break; case ParcelType::PARCEL_TYPE_VOLUME_VOXELS: cursor.restoreCursor(); WuQMessageBox::errorOk(this, "Charting of voxel average has not been implemented."); break; } } catch (const DataFileException& e) { cursor.restoreCursor(); WuQMessageBox::errorOk(this, e.whatString()); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called when border timeseries is selected. */ void UserInputModeViewContextMenu::borderDataSeriesSelected() { SelectionItemBorderSurface* borderID = this->selectionManager->getSurfaceBorderIdentification(); Border* border = borderID->getBorder(); Surface* surface = borderID->getSurface(); const int32_t numberOfNodes = surface->getNumberOfNodes(); LabelFile labelFile; labelFile.setNumberOfNodesAndColumns(numberOfNodes, 1); const int32_t labelKey = labelFile.getLabelTable()->addLabel("TempLabel", 1.0f, 1.0f, 1.0f, 1.0f); const int32_t mapIndex = 0; try { AlgorithmNodesInsideBorder algorithmInsideBorder(NULL, surface, border, false, mapIndex, labelKey, &labelFile); std::vector nodeIndices; nodeIndices.reserve(numberOfNodes); for (int32_t i = 0; i < numberOfNodes; i++) { if (labelFile.getLabelKey(i, mapIndex) == labelKey) { nodeIndices.push_back(i); } } if (nodeIndices.empty()) { WuQMessageBox::errorOk(this, "No vertices found inside border " + border->getName()); return; } if (borderID->getBrain()->getChartingDataManager()->hasNetworkFiles()) { if (warnIfNetworkBrainordinateCountIsLarge(nodeIndices.size()) == false) { return; } } CursorDisplayScoped cursor; cursor.showWaitCursor(); try { ProgressReportingDialog progressDialog("Data Series Within Border", "", this); progressDialog.setValue(0); ChartingDataManager* chartingDataManager = borderID->getBrain()->getChartingDataManager(); chartingDataManager->loadAverageChartForSurfaceNodes(surface, nodeIndices); } catch (const DataFileException& e) { cursor.restoreCursor(); WuQMessageBox::errorOk(this, e.whatString()); } } catch (const AlgorithmException& e) { WuQMessageBox::errorOk(this, e.whatString()); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * @return If no data series graphs are enabled, enable all of them and return * true. Else, return false. */ bool UserInputModeViewContextMenu::enableDataSeriesGraphsIfNoneEnabled() { Brain* brain = GuiManager::get()->getBrain(); std::vector chartFiles; brain->getAllChartableBrainordinateDataFiles(chartFiles); if (chartFiles.empty()) { return false; } const int32_t tabIndex = this->browserTabContent->getTabNumber(); /* * Exit if any data series graph is enabled. */ for (std::vector::iterator iter = chartFiles.begin(); iter != chartFiles.end(); iter++) { ChartableLineSeriesBrainordinateInterface* chartFile = *iter; if (chartFile->isLineSeriesChartingEnabled(tabIndex)) { return false; } } /* * Enable and display all data series graphs. */ for (std::vector::iterator iter = chartFiles.begin(); iter != chartFiles.end(); iter++) { ChartableLineSeriesBrainordinateInterface* chartFile = *iter; chartFile->setLineSeriesChartingEnabled(tabIndex, true); } return true; } /** * Called to display identication information on the surface border. */ void UserInputModeViewContextMenu::identifySurfaceBorderSelected() { SelectionItemBorderSurface* borderID = this->selectionManager->getSurfaceBorderIdentification(); Brain* brain = borderID->getBrain(); this->selectionManager->clearOtherSelectedItems(borderID); const AString idMessage = this->selectionManager->getIdentificationText(brain); IdentificationManager* idManager = brain->getIdentificationManager(); idManager->addIdentifiedItem(new IdentifiedItem(idMessage)); EventManager::get()->sendEvent(EventUpdateInformationWindows().getPointer()); } /** * Called to create a focus at a node location */ void UserInputModeViewContextMenu::createSurfaceFocusSelected() { SelectionItemSurfaceNode* surfaceID = this->selectionManager->getSurfaceNodeIdentification(); const Surface* surface = surfaceID->getSurface(); const int32_t nodeIndex = surfaceID->getNodeNumber(); const float* xyz = surface->getCoordinate(nodeIndex); const AString focusName = (StructureEnum::toGuiName(surface->getStructure()) + " Vertex " + AString::number(nodeIndex)); const AString comment = ("Created from " + focusName); Focus* focus = new Focus(); focus->setName(focusName); focus->getProjection(0)->setStereotaxicXYZ(xyz); focus->setComment(comment); FociPropertiesEditorDialog::createFocus(focus, this->browserTabContent, this->parentOpenGLWidget); } /** * Called to create a focus at a node location */ void UserInputModeViewContextMenu::createSurfaceIDSymbolFocusSelected() { SelectionItemSurfaceNodeIdentificationSymbol* nodeSymbolID = this->selectionManager->getSurfaceNodeIdentificationSymbol(); const Surface* surface = nodeSymbolID->getSurface(); const int32_t nodeIndex = nodeSymbolID->getNodeNumber(); const float* xyz = surface->getCoordinate(nodeIndex); const AString focusName = (StructureEnum::toGuiName(surface->getStructure()) + " Vertex " + AString::number(nodeIndex)); const AString comment = ("Created from " + focusName); Focus* focus = new Focus(); focus->setName(focusName); focus->getProjection(0)->setStereotaxicXYZ(xyz); focus->setComment(comment); FociPropertiesEditorDialog::createFocus(focus, this->browserTabContent, this->parentOpenGLWidget); } /** * Called to create a focus at a voxel location */ void UserInputModeViewContextMenu::createVolumeFocusSelected() { SelectionItemVoxel* voxelID = this->selectionManager->getVoxelIdentification(); const VolumeMappableInterface* vf = voxelID->getVolumeFile(); int64_t ijk[3]; voxelID->getVoxelIJK(ijk); float xyz[3]; vf->indexToSpace(ijk, xyz); const CaretMappableDataFile* cmdf = dynamic_cast(vf); const AString focusName = (cmdf->getFileNameNoPath() + " IJK (" + AString::fromNumbers(ijk, 3, ",") + ")"); const AString comment = ("Created from " + focusName); Focus* focus = new Focus(); focus->setName(focusName); focus->getProjection(0)->setStereotaxicXYZ(xyz); focus->setComment(comment); FociPropertiesEditorDialog::createFocus(focus, this->browserTabContent, this->parentOpenGLWidget); } /** * Called to display identication information on the surface focus. */ void UserInputModeViewContextMenu::identifySurfaceFocusSelected() { SelectionItemFocusSurface* focusID = this->selectionManager->getSurfaceFocusIdentification(); Brain* brain = focusID->getBrain(); this->selectionManager->clearOtherSelectedItems(focusID); const AString idMessage = this->selectionManager->getIdentificationText(brain); IdentificationManager* idManager = brain->getIdentificationManager(); idManager->addIdentifiedItem(new IdentifiedItem(idMessage)); EventManager::get()->sendEvent(EventUpdateInformationWindows().getPointer()); } /** * Called to display identication information on the volume focus. */ void UserInputModeViewContextMenu::identifyVolumeFocusSelected() { SelectionItemFocusVolume* focusID = this->selectionManager->getVolumeFocusIdentification(); Brain* brain = focusID->getBrain(); this->selectionManager->clearOtherSelectedItems(focusID); const AString idMessage = this->selectionManager->getIdentificationText(brain); IdentificationManager* idManager = brain->getIdentificationManager(); idManager->addIdentifiedItem(new IdentifiedItem(idMessage)); EventManager::get()->sendEvent(EventUpdateInformationWindows().getPointer()); } /** * Called to edit the surface focus. */ void UserInputModeViewContextMenu::editSurfaceFocusSelected() { SelectionItemFocusSurface* focusID = this->selectionManager->getSurfaceFocusIdentification(); Focus* focus = focusID->getFocus(); FociFile* fociFile = focusID->getFociFile(); FociPropertiesEditorDialog::editFocus(fociFile, focus, this->parentOpenGLWidget); } /** * Called to edit the volume focus. */ void UserInputModeViewContextMenu::editVolumeFocusSelected() { SelectionItemFocusVolume* focusID = this->selectionManager->getVolumeFocusIdentification(); Focus* focus = focusID->getFocus(); FociFile* fociFile = focusID->getFociFile(); FociPropertiesEditorDialog::editFocus(fociFile, focus, this->parentOpenGLWidget); } /** * Called to display identication information on the surface border. */ void UserInputModeViewContextMenu::identifySurfaceNodeSelected() { GuiManager::get()->processIdentification(this->browserTabContent->getTabNumber(), this->selectionManager, this->parentOpenGLWidget); } /** * Called to display identication information on the surface border. */ void UserInputModeViewContextMenu::identifyVoxelSelected() { SelectionItemVoxel* voxelID = this->selectionManager->getVoxelIdentification(); Brain* brain = voxelID->getBrain(); this->selectionManager->clearOtherSelectedItems(voxelID); const AString idMessage = this->selectionManager->getIdentificationText(brain); IdentificationManager* idManager = brain->getIdentificationManager(); idManager->addIdentifiedItem(new IdentifiedItem(idMessage)); EventManager::get()->sendEvent(EventUpdateInformationWindows().getPointer()); } /** * Called to remove all node identification symbols. */ void UserInputModeViewContextMenu::removeAllNodeIdentificationSymbolsSelected() { IdentificationManager* idManager = GuiManager::get()->getBrain()->getIdentificationManager(); idManager->removeAllIdentifiedItems(); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Called to remove node identification symbol from node. */ void UserInputModeViewContextMenu::removeNodeIdentificationSymbolSelected() { SelectionItemSurfaceNodeIdentificationSymbol* idSymbol = selectionManager->getSurfaceNodeIdentificationSymbol(); if (idSymbol->isValid()) { Surface* surface = idSymbol->getSurface(); IdentificationManager* idManager = GuiManager::get()->getBrain()->getIdentificationManager(); idManager->removeIdentifiedNodeItem(surface->getStructure(), surface->getNumberOfNodes(), idSymbol->getNodeNumber()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } } /** * This is called when the data file is on the network to warn users if the * query is very large and may take a long time. * * @param numberOfBrainordinatesInROI * Number of brainordinates in the ROI. */ bool UserInputModeViewContextMenu::warnIfNetworkBrainordinateCountIsLarge(const int64_t numberOfBrainordinatesInROI) { if (numberOfBrainordinatesInROI < 200) { return true; } const QString msg = ("There are " + QString::number(numberOfBrainordinatesInROI) + " brainordinates in the selected region. Loading data from the network for " + "this quantity of brainordinates may take a very long time."); const bool result = WuQMessageBox::warningYesNo(this, "Do you want to continue?", msg); return result; } /* ------------------------------------------------------------------------- */ /** * Constructor. */ UserInputModeViewContextMenu::ParcelConnectivity::ParcelConnectivity(Brain* brain, const ParcelType parcelType, CaretMappableDataFile* mappableLabelFile, const int32_t labelFileMapIndex, const AString& mapName, const int32_t labelKey, const QString& labelName, Surface* surface, const int32_t nodeNumber, const int64_t volumeDimensions[3], ChartingDataManager* chartingDataManager, CiftiConnectivityMatrixDataFileManager* ciftiConnectivityManager, CiftiFiberTrajectoryManager* ciftiFiberTrajectoryManager) { this->brain = brain; this->parcelType = parcelType; this->mappableLabelFile = mappableLabelFile; this->labelFileMapIndex = labelFileMapIndex; this->mapName = mapName; this->labelKey = labelKey; this->labelName = labelName; this->surface = surface; this->nodeNumber = nodeNumber; this->volumeDimensions[0] = volumeDimensions[0]; this->volumeDimensions[1] = volumeDimensions[1]; this->volumeDimensions[2] = volumeDimensions[2]; this->chartingDataManager = chartingDataManager; this->ciftiConnectivityManager = ciftiConnectivityManager; this->ciftiFiberTrajectoryManager = ciftiFiberTrajectoryManager; } /** * Destructor. */ UserInputModeViewContextMenu::ParcelConnectivity::~ParcelConnectivity() { } /** * Get the node indices comprising the parcel. * * @param nodeIndicesOut * Contains node indices upon exit. */ void UserInputModeViewContextMenu::ParcelConnectivity::getNodeIndices(std::vector& nodeIndicesOut) const { nodeIndicesOut.clear(); if (this->parcelType != ParcelType::PARCEL_TYPE_SURFACE_NODES) { return; } CiftiBrainordinateLabelFile* ciftiLabelFile = dynamic_cast(mappableLabelFile); LabelFile* labelFile = dynamic_cast(mappableLabelFile); if (ciftiLabelFile != NULL) { ciftiLabelFile->getNodeIndicesWithLabelKey(surface->getStructure(), surface->getNumberOfNodes(), labelFileMapIndex, labelKey, nodeIndicesOut); } else if (labelFile != NULL) { labelFile->getNodeIndicesWithLabelKey(labelFileMapIndex, labelKey, nodeIndicesOut); } else { CaretAssertMessage(0, "Should never get here, new or invalid label file type for surface nodes"); } } /** * Get the voxel indices comprising the parcel * * @param voxelIndicesOut * Contains voxel indices upon exit. */ void UserInputModeViewContextMenu::ParcelConnectivity::getVoxelIndices(std::vector& voxelIndicesOut) const { voxelIndicesOut.clear(); if (this->parcelType != ParcelType::PARCEL_TYPE_VOLUME_VOXELS) { return; } CiftiBrainordinateLabelFile* ciftiLabelFile = dynamic_cast(mappableLabelFile); VolumeFile* volumeLabelFile = dynamic_cast(mappableLabelFile); if (ciftiLabelFile != NULL) { ciftiLabelFile->getVoxelIndicesWithLabelKey(labelFileMapIndex, labelKey, voxelIndicesOut); } else if (volumeLabelFile != NULL) { volumeLabelFile->getVoxelIndicesWithLabelKey(labelFileMapIndex, labelKey, voxelIndicesOut); } else { CaretAssertMessage(0, "Should never get here, new or invalid label file type for volume voxels"); } } connectome-workbench-1.4.2/src/GuiQt/UserInputModeViewContextMenu.h000066400000000000000000000140271360521144700254200ustar00rootroot00000000000000#ifndef __USER_INPUT_MODE_VIEW_CONTEXT_MENU_H__ #define __USER_INPUT_MODE_VIEW_CONTEXT_MENU_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "StructureEnum.h" #include "VolumeSliceViewPlaneEnum.h" #include "VoxelIJK.h" class QAction; namespace caret { class Brain; class BrainOpenGLViewportContent; class BrainOpenGLWidget; class BrowserTabContent; class CaretMappableDataFile; class CiftiConnectivityMatrixDataFileManager; class CiftiFiberTrajectoryManager; class ChartingDataManager; class SelectionManager; class LabelFile; class Surface; class UserInputModeViewContextMenu : public QMenu { Q_OBJECT public: UserInputModeViewContextMenu(BrainOpenGLViewportContent* viewportContent, SelectionManager* selectionManager, BrainOpenGLWidget* parentOpenGLWidget); virtual ~UserInputModeViewContextMenu(); private slots: void createSurfaceFocusSelected(); void createSurfaceIDSymbolFocusSelected(); void createVolumeFocusSelected(); void editSurfaceFocusSelected(); void editVolumeFocusSelected(); void removeAllNodeIdentificationSymbolsSelected(); void removeNodeIdentificationSymbolSelected(); void identifySurfaceBorderSelected(); void identifySurfaceFocusSelected(); void identifyVolumeFocusSelected(); void identifySurfaceNodeSelected(); void identifyVoxelSelected(); void parcelCiftiFiberTrajectoryActionSelected(QAction* action); void connectivityActionSelected(QAction* action); void parcelChartableDataActionSelected(QAction* action); void borderCiftiConnectivitySelected(); void borderDataSeriesSelected(); void editChartLabelSelected(); private: enum class ParcelType { PARCEL_TYPE_INVALID, PARCEL_TYPE_SURFACE_NODES, PARCEL_TYPE_VOLUME_VOXELS }; class ParcelConnectivity { public: ParcelConnectivity(Brain* brain, const ParcelType parcelType, CaretMappableDataFile* mappableLabelFile, const int32_t labelFileMapIndex, const AString& mapName, const int32_t labelKey, const QString& labelName, Surface* surface, const int32_t nodeNumber, const int64_t volumeDimensions[3], ChartingDataManager* chartingDataManager, CiftiConnectivityMatrixDataFileManager* ciftiConnectivityManager, CiftiFiberTrajectoryManager* ciftiFiberTrajectoryManager); virtual ~ParcelConnectivity(); void getNodeIndices(std::vector& nodeIndicesOut) const; void getVoxelIndices(std::vector& voxelIndicesOut) const; Brain* brain; ParcelType parcelType; CaretMappableDataFile* mappableLabelFile; int32_t labelFileMapIndex; AString mapName; int32_t labelKey; QString labelName; Surface* surface; int32_t nodeNumber; int64_t volumeDimensions[3]; CiftiConnectivityMatrixDataFileManager* ciftiConnectivityManager; ChartingDataManager* chartingDataManager; CiftiFiberTrajectoryManager* ciftiFiberTrajectoryManager; }; UserInputModeViewContextMenu(const UserInputModeViewContextMenu&); UserInputModeViewContextMenu& operator=(const UserInputModeViewContextMenu&); bool warnIfNetworkBrainordinateCountIsLarge(const int64_t numberOfBrainordinatesInROI); bool enableDataSeriesGraphsIfNoneEnabled(); void addIdentificationActions(); void addBorderRegionOfInterestActions(); void addChartActions(); void addFociActions(); void addLabelRegionOfInterestActions(); void addSubMenuToMenu(QMenu* menu, const bool addSeparatorBeforeMenu); void addActionsToMenu(QList& actionsToAdd, const bool addSeparatorBeforeActions); void createParcelConnectivities(); BrainOpenGLWidget* parentOpenGLWidget; std::vector parcelConnectivities; BrainOpenGLViewportContent* viewportContent; SelectionManager* selectionManager; BrowserTabContent* browserTabContent; }; #ifdef __USER_INPUT_MODE_VIEW_CONTEXT_MENU_DECLARE__ // #endif // __USER_INPUT_MODE_VIEW_CONTEXT_MENU_DECLARE__ } // namespace #endif //__USER_INPUT_MODE_VIEW_CONTEXT_MENU_H__ connectome-workbench-1.4.2/src/GuiQt/UserInputModeVolumeEdit.cxx000066400000000000000000000310521360521144700247410ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __USER_INPUT_MODE_VOLUME_EDIT_DECLARE__ #include "UserInputModeVolumeEdit.h" #undef __USER_INPUT_MODE_VOLUME_EDIT_DECLARE__ #include "Brain.h" #include "BrainOpenGLWidget.h" #include "BrainOpenGLViewportContent.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "EventBrowserWindowDrawingContent.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "GuiManager.h" #include "MouseEvent.h" #include "Overlay.h" #include "OverlaySet.h" #include "SelectionItemVoxelEditing.h" #include "SelectionManager.h" #include "UserInputModeVolumeEditWidget.h" #include "VolumeFile.h" #include "VolumeFileEditorDelegate.h" #include "VolumeSliceViewPlaneEnum.h" #include "WuQMessageBox.h" using namespace caret; /** * \class caret::UserInputModeVolumeEdit * \brief User input processor for editing volume voxels * \ingroup GuiQt */ /** * Constructor. * * Index of window using this volume editor input handler. */ UserInputModeVolumeEdit::UserInputModeVolumeEdit(const int32_t windowIndex) : UserInputModeView(UserInputModeEnum::VOLUME_EDIT), m_windowIndex(windowIndex) { m_inputModeVolumeEditWidget = new UserInputModeVolumeEditWidget(this, windowIndex); setWidgetForToolBar(m_inputModeVolumeEditWidget); } /** * Destructor. */ UserInputModeVolumeEdit::~UserInputModeVolumeEdit() { } /** * Called when 'this' user input receiver is set * to receive events. */ void UserInputModeVolumeEdit::initialize() { m_inputModeVolumeEditWidget->updateWidget(); } /** * Called when 'this' user input receiver is no * longer set to receive events. */ void UserInputModeVolumeEdit::finish() { } /** * Called to update the input receiver for various events. */ void UserInputModeVolumeEdit::update() { m_inputModeVolumeEditWidget->updateWidget(); } /** * Process a mouse event for editing the voxels. * * @param mouseEvent * Mouse event information. */ void UserInputModeVolumeEdit::processEditCommandFromMouse(const MouseEvent& mouseEvent) { if (mouseEvent.getViewportContent() == NULL) { return; } VolumeEditInfo volumeEditInfo; if ( ! getVolumeEditInfo(volumeEditInfo)) { return; } BrainOpenGLWidget* openGLWidget = mouseEvent.getOpenGLWidget(); const int mouseX = mouseEvent.getX(); const int mouseY = mouseEvent.getY(); SelectionManager* idManager = GuiManager::get()->getBrain()->getSelectionManager(); SelectionItemVoxelEditing* idEditVoxel = idManager->getVoxelEditingIdentification(); idEditVoxel->setVolumeFileForEditing(volumeEditInfo.m_volumeFile); idManager = openGLWidget->performIdentificationVoxelEditing(volumeEditInfo.m_volumeFile, mouseX, mouseY); if ((volumeEditInfo.m_volumeFile == idEditVoxel->getVolumeFile()) && idEditVoxel->isValid()) { int64_t ijk[3]; idEditVoxel->getVoxelIJK(ijk); VolumeEditingModeEnum::Enum editMode = VolumeEditingModeEnum::VOLUME_EDITING_MODE_ON; int32_t brushSizes[3] = { 0, 0, 0 }; float paletteMappedValue = 0; AString labelMappedName; m_inputModeVolumeEditWidget->getEditingParameters(editMode, brushSizes, paletteMappedValue, labelMappedName); const int64_t brushSizesInt64[3] = { brushSizes[0], brushSizes[1], brushSizes[2] }; VolumeFileEditorDelegate* editor = volumeEditInfo.m_volumeFileEditorDelegate; CaretAssert(editor); const VolumeSliceViewPlaneEnum::Enum slicePlane = volumeEditInfo.m_sliceViewPlane; const VolumeSliceProjectionTypeEnum::Enum sliceProjectionType = volumeEditInfo.m_sliceProjectionType; const Matrix4x4 obliqueRotationMatrix = volumeEditInfo.m_obliqueRotationMatrix; bool successFlag = true; AString errorMessage; float voxelValueOn = paletteMappedValue; float voxelValueOff = 0.0; float voxelDiffXYZ[3]; idEditVoxel->getVoxelDiffXYZ(voxelDiffXYZ); if (volumeEditInfo.m_volumeFile->isMappedWithLabelTable()) { const GiftiLabelTable* labelTable = volumeEditInfo.m_volumeFile->getMapLabelTable(volumeEditInfo.m_mapIndex); const GiftiLabel* label = labelTable->getLabel(labelMappedName); if (label != NULL) { voxelValueOn = label->getKey(); } else { errorMessage = ("Label name " + labelMappedName + " is not in label table."); successFlag = false; } const GiftiLabel* unassignedLabel = labelTable->getLabel(labelTable->getUnassignedLabelKey()); if (unassignedLabel != NULL) { voxelValueOff = unassignedLabel->getKey(); } } if (successFlag) { successFlag = editor->performEditingOperation(volumeEditInfo.m_mapIndex, editMode, slicePlane, sliceProjectionType, obliqueRotationMatrix, voxelDiffXYZ, ijk, brushSizesInt64, voxelValueOn, voxelValueOff, errorMessage); } if ( ! successFlag) { WuQMessageBox::errorOk(m_inputModeVolumeEditWidget, errorMessage); } updateGraphicsAfterEditing(volumeEditInfo.m_volumeFile, volumeEditInfo.m_mapIndex); } } /** * Process a mouse left click event. * * @param mouseEvent * Mouse event information. */ void UserInputModeVolumeEdit::mouseLeftClick(const MouseEvent& mouseEvent) { processEditCommandFromMouse(mouseEvent); } /** * Process a mouse left drag with ctrl and shift keys down event. * * @param mouseEvent * Mouse event information. */ void UserInputModeVolumeEdit::mouseLeftDragWithCtrlShift(const MouseEvent& mouseEvent) { processEditCommandFromMouse(mouseEvent); } /** * Show a context menu (pop-up menu at mouse location) * * @param mouseEvent * Mouse event information. * @param menuPosition * Point at which menu is displayed (passed to QMenu::exec()) * @param openGLWidget * OpenGL widget in which context menu is requested */ void UserInputModeVolumeEdit::showContextMenu(const MouseEvent& /*mouseEvent*/, const QPoint& /*menuPosition*/, BrainOpenGLWidget* /*openGLWidget*/) { /* no context menu */ } /** * Update the graphics after editing. * * @param volumeFile * Volume file that needs coloring update. * @param mapIndex * Index of the map. */ void UserInputModeVolumeEdit::updateGraphicsAfterEditing(VolumeFile* volumeFile, const int32_t mapIndex) { CaretAssert(volumeFile); CaretAssert((mapIndex >= 0) && (mapIndex < volumeFile->getNumberOfMaps())); volumeFile->clearVoxelColoringForMap(mapIndex); volumeFile->updateScalarColoringForMap(mapIndex); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * @return The cursor for display in the OpenGL widget. */ CursorEnum::Enum UserInputModeVolumeEdit::getCursor() const { CursorEnum::Enum cursor = CursorEnum::CURSOR_DEFAULT; // switch (m_mode) { // case MODE_CREATE: // break; // case MODE_EDIT: // cursor = CursorEnum::CURSOR_POINTING_HAND; // switch (m_editOperation) { // case EDIT_OPERATION_DELETE: // cursor = CursorEnum::CURSOR_CROSS; // break; // case EDIT_OPERATION_PROPERTIES: // cursor = CursorEnum::CURSOR_WHATS_THIS; // break; // } // break; // case MODE_OPERATIONS: // cursor = CursorEnum::CURSOR_POINTING_HAND; // break; // } return cursor; } /** * Get information about volume data being edited. * * @param volumeEditInfo * Loaded with editing information upon sucess. * @return * True if all ofvolumeEditInfo is valid, else false. Even * if false the overlay and model volume MAY be valid (non-NULL). */ bool UserInputModeVolumeEdit::getVolumeEditInfo(VolumeEditInfo& volumeEditInfo) { volumeEditInfo.m_overlaySet = NULL; volumeEditInfo.m_topOverlay = NULL; volumeEditInfo.m_volumeOverlay = NULL; volumeEditInfo.m_volumeFile = NULL; volumeEditInfo.m_mapIndex = -1; volumeEditInfo.m_sliceViewPlane = VolumeSliceViewPlaneEnum::ALL; volumeEditInfo.m_sliceProjectionType = VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL; volumeEditInfo.m_obliqueRotationMatrix.identity(); EventBrowserWindowDrawingContent windowEvent(m_windowIndex); EventManager::get()->sendEvent(windowEvent.getPointer()); BrowserTabContent* tabContent = windowEvent.getSelectedBrowserTabContent(); if (tabContent != NULL) { ModelVolume* modelVolume = tabContent->getDisplayedVolumeModel(); ModelWholeBrain* modelWholeBrain = tabContent->getDisplayedWholeBrainModel(); if ((modelVolume != NULL) || (modelWholeBrain != NULL)) { OverlaySet* overlaySet = tabContent->getOverlaySet(); const int32_t numOverlays = overlaySet->getNumberOfDisplayedOverlays(); for (int32_t i = 0; i < numOverlays; i++) { Overlay* overlay = overlaySet->getOverlay(i); if (i == 0) { volumeEditInfo.m_topOverlay = overlay; } if (overlay->isEnabled()) { CaretMappableDataFile* mapFile = NULL; int32_t mapIndex; overlay->getSelectionData(mapFile, mapIndex); if (mapFile != NULL) { VolumeFile* vf = dynamic_cast(mapFile); if (vf != NULL) { volumeEditInfo.m_overlaySet = overlaySet; volumeEditInfo.m_volumeOverlay = overlay; volumeEditInfo.m_volumeFile = vf; volumeEditInfo.m_mapIndex = mapIndex; volumeEditInfo.m_sliceViewPlane = tabContent->getSliceViewPlane(); volumeEditInfo.m_sliceProjectionType = tabContent->getSliceProjectionType(); volumeEditInfo.m_volumeFileEditorDelegate = vf->getVolumeFileEditorDelegate(); volumeEditInfo.m_obliqueRotationMatrix = tabContent->getObliqueVolumeRotationMatrix(); return true; } } } } } } return false; } connectome-workbench-1.4.2/src/GuiQt/UserInputModeVolumeEdit.h000066400000000000000000000100271360521144700243650ustar00rootroot00000000000000#ifndef __USER_INPUT_MODE_VOLUME_EDIT_H__ #define __USER_INPUT_MODE_VOLUME_EDIT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "Matrix4x4.h" #include "UserInputModeView.h" #include "VolumeSliceViewPlaneEnum.h" #include "VolumeSliceProjectionTypeEnum.h" namespace caret { class ModelVolume; class Overlay; class OverlaySet; class VolumeFile; class VolumeFileEditorDelegate; class UserInputModeVolumeEditWidget; class UserInputModeVolumeEdit : public UserInputModeView { public: /** * Contains information regarding the volume file that is * being edited. */ struct VolumeEditInfo { /** The overlay set in the tab */ OverlaySet* m_overlaySet; /** The top-most overlay in the tab */ Overlay* m_topOverlay; /** The overlay containing the volume file */ Overlay* m_volumeOverlay; /** The volume file being edited */ VolumeFile* m_volumeFile; /** Index of the map in the volume file being edited */ int32_t m_mapIndex; /** The current slice view plane */ VolumeSliceViewPlaneEnum::Enum m_sliceViewPlane; /** Slice projection type (orthogonal/oblique) */ VolumeSliceProjectionTypeEnum::Enum m_sliceProjectionType; /** The volume's editor delegate */ VolumeFileEditorDelegate* m_volumeFileEditorDelegate; /** The oblique projection rotation matrix */ Matrix4x4 m_obliqueRotationMatrix; }; UserInputModeVolumeEdit(const int32_t windowIndex); virtual ~UserInputModeVolumeEdit(); virtual void initialize(); virtual void finish(); virtual void update(); virtual CursorEnum::Enum getCursor() const; virtual void mouseLeftClick(const MouseEvent& mouseEvent); virtual void mouseLeftDragWithCtrlShift(const MouseEvent& mouseEvent); virtual void showContextMenu(const MouseEvent& mouseEvent, const QPoint& menuPosition, BrainOpenGLWidget* openGLWidget); bool getVolumeEditInfo(VolumeEditInfo& volumeEditInfo); void updateGraphicsAfterEditing(VolumeFile* volumeFile, const int32_t mapIndex); // ADD_NEW_METHODS_HERE private: UserInputModeVolumeEdit(const UserInputModeVolumeEdit&); UserInputModeVolumeEdit& operator=(const UserInputModeVolumeEdit&); void processEditCommandFromMouse(const MouseEvent& mouseEvent); const int32_t m_windowIndex; UserInputModeVolumeEditWidget* m_inputModeVolumeEditWidget; friend class UserInputModeVolumeEditWidget; // ADD_NEW_MEMBERS_HERE }; #ifdef __USER_INPUT_MODE_VOLUME_EDIT_DECLARE__ // #endif // __USER_INPUT_MODE_VOLUME_EDIT_DECLARE__ } // namespace #endif //__USER_INPUT_MODE_VOLUME_EDIT_H__ connectome-workbench-1.4.2/src/GuiQt/UserInputModeVolumeEditWidget.cxx000066400000000000000000000634221360521144700261130ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __USER_INPUT_MODE_VOLUME_EDIT_WIDGET_DECLARE__ #include "UserInputModeVolumeEditWidget.h" #undef __USER_INPUT_MODE_VOLUME_EDIT_WIDGET_DECLARE__ #include #include #include #include #include #include #include #include #include "Brain.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "EventDataFileAdd.h" #include "EventManager.h" #include "EventUpdateVolumeEditingToolBar.h" #include "EventUserInterfaceUpdate.h" #include "GiftiLabel.h" #include "GiftiLabelTableEditor.h" #include "GuiManager.h" #include "Overlay.h" #include "OverlaySet.h" #include "VolumeFile.h" #include "VolumeFileEditorDelegate.h" #include "VolumeFileCreateDialog.h" #include "WuQDataEntryDialog.h" #include "WuQFactory.h" #include "WuQMessageBox.h" #include "WuQSpinBoxOddValue.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::UserInputModeVolumeEditWidget * \brief User input widget for volume editing. * \ingroup GuiQt */ /** * Constructor. * @param inputModeVolumeEdit * Process of mouse input for volume editing * @param windowIndex * Index of browser window * @param parent * Parent widget */ UserInputModeVolumeEditWidget::UserInputModeVolumeEditWidget(UserInputModeVolumeEdit* inputModeVolumeEdit, const int32_t windowIndex, QWidget* parent) : QWidget(parent), EventListenerInterface(), m_inputModeVolumeEdit(inputModeVolumeEdit), m_windowIndex(windowIndex) { CaretAssert(inputModeVolumeEdit); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 0); layout->addWidget(createSelectionToolBar()); layout->addWidget(createModeToolBar()); setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_UPDATE_VOLUME_EDITING_TOOLBAR); } /** * Destructor. */ UserInputModeVolumeEditWidget::~UserInputModeVolumeEditWidget() { EventManager::get()->removeAllEventsFromListener(this); } /** * Receive an event * * @param event * The event. */ void UserInputModeVolumeEditWidget::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_UPDATE_VOLUME_EDITING_TOOLBAR) { EventUpdateVolumeEditingToolBar* editVolEvent = dynamic_cast(event); CaretAssert(editVolEvent); editVolEvent->setEventProcessed(); updateWidget(); } } /** * Update the widget. */ void UserInputModeVolumeEditWidget::updateWidget() { bool isValid = false; UserInputModeVolumeEdit::VolumeEditInfo volumeEditInfo; if (m_inputModeVolumeEdit->getVolumeEditInfo(volumeEditInfo)) { m_lockAction->setChecked(volumeEditInfo.m_volumeFileEditorDelegate->isLocked(volumeEditInfo.m_mapIndex)); if (volumeEditInfo.m_volumeFile != NULL) { if (volumeEditInfo.m_volumeFile->isMappedWithLabelTable()) { m_voxelLabelValueToolButton->setVisible(true); m_voxelFloatValueSpinBox->setVisible(false); AString buttonText = m_voxelLabelValueAction->text(); GiftiLabelTable* labelTable = volumeEditInfo.m_volumeFile->getMapLabelTable(volumeEditInfo.m_mapIndex); if (labelTable != NULL) { GiftiLabel* label = labelTable->getLabel(buttonText); /* * Is there a label in the label table whose name * matches the name in the button's actoin? */ if (label == NULL) { /* * Default to the unassigned label */ const int32_t unassignedKey = labelTable->getUnassignedLabelKey(); GiftiLabel* unassignedLabel = labelTable->getLabel(unassignedKey); if (unassignedLabel != NULL) { buttonText = unassignedLabel->getName(); } /* * Find the first label that is not the unassigned * label */ const std::set keys = labelTable->getKeys(); for (std::set::iterator iter = keys.begin(); iter != keys.end(); iter++) { const int32_t key = *iter; if (key != unassignedKey) { GiftiLabel* keyLabel = labelTable->getLabel(key); if (keyLabel != NULL) { buttonText = keyLabel->getName(); break; } } } } } m_voxelLabelValueAction->setText(buttonText); isValid = true; } else if (volumeEditInfo.m_volumeFile->isMappedWithPalette()) { m_voxelLabelValueToolButton->setVisible(false); m_voxelFloatValueSpinBox->setVisible(true); isValid = true; } else if (volumeEditInfo.m_volumeFile->isMappedWithRGBA()) { /* nothing */ } else { CaretAssert(0); } m_addMapsToolButton->defaultAction()->setEnabled(isValid); const bool orthogonalFlag = (volumeEditInfo.m_sliceProjectionType == VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_ORTHOGONAL); QList modeActions = m_volumeEditModeActionGroup->actions(); const int32_t numModeActions = modeActions.size(); for (int32_t i = 0; i < numModeActions; i++) { QAction* action = modeActions.at(i); const int modeInt = action->data().toInt(); bool validFlag = false; VolumeEditingModeEnum::Enum mode = VolumeEditingModeEnum::fromIntegerCode(modeInt, &validFlag); CaretAssert(validFlag); bool modeEnabledFlag = false; if (orthogonalFlag) { modeEnabledFlag = true; } else { modeEnabledFlag = VolumeEditingModeEnum::isObliqueEditingAllowed(mode); } action->setEnabled(modeEnabledFlag); } } } this->setEnabled(isValid); } /** * @return Create and return the selection toolbar. */ QWidget* UserInputModeVolumeEditWidget::createSelectionToolBar() { QLabel* volumeLabel = new QLabel("Volume:"); m_newFileToolButton = new QToolButton(); m_newFileToolButton->setDefaultAction(WuQtUtilities::createAction("New", "Create a new volume file that will become the top-most overlay", this, this, SLOT(newFileActionTriggered()))); WuQtUtilities::setToolButtonStyleForQt5Mac(m_newFileToolButton); m_addMapsToolButton = new QToolButton(); m_addMapsToolButton->setDefaultAction(WuQtUtilities::createAction("Add", ("Add maps to the selected volume file.\n" "First new map will become the top-most overlay."), this, this, SLOT(addMapsActionTriggered()))); WuQtUtilities::setToolButtonStyleForQt5Mac(m_addMapsToolButton); m_lockAction = WuQtUtilities::createAction("Lock", "Lock/unlock volume file to disallow/allow editing", this, this, SLOT(lockFileActionTriggered())); m_lockAction->setCheckable(true); QToolButton* lockFileToolButton = new QToolButton(); lockFileToolButton->setDefaultAction(m_lockAction); WuQtUtilities::setToolButtonStyleForQt5Mac(lockFileToolButton); QLabel* editLabel = new QLabel("Edit:"); QToolButton* undoToolButton = new QToolButton(); undoToolButton->setDefaultAction(WuQtUtilities::createAction("Undo", "Undo the last volume edit", this, this, SLOT(undoActionTriggered()))); WuQtUtilities::setToolButtonStyleForQt5Mac(undoToolButton); QToolButton* redoToolButton = new QToolButton(); redoToolButton->setDefaultAction(WuQtUtilities::createAction("Redo", "Redo (or is it undo) the last undo", this, this, SLOT(redoActionTriggered()))); WuQtUtilities::setToolButtonStyleForQt5Mac(redoToolButton); QToolButton* resetToolButton = new QToolButton(); resetToolButton->setDefaultAction(WuQtUtilities::createAction("Reset", "Reset all edting of the volume", this, this, SLOT(resetActionTriggered()))); WuQtUtilities::setToolButtonStyleForQt5Mac(resetToolButton); QLabel* brushSizeLabel = new QLabel("Brush Size:"); const int MIN_BRUSH_SIZE = 1; const int MAX_BRUSH_SIZE = 999; m_xBrushSizeSpinBox = new WuQSpinBoxOddValue(this); m_xBrushSizeSpinBox->setRange(MIN_BRUSH_SIZE, MAX_BRUSH_SIZE); QObject::connect(m_xBrushSizeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(xBrushSizeValueChanged(int))); m_xBrushSizeSpinBox->getWidget()->setToolTip("Parasagittal brush size (voxels).\n" "Must be an odd value."); m_yBrushSizeSpinBox = new WuQSpinBoxOddValue(this); m_yBrushSizeSpinBox->setRange(MIN_BRUSH_SIZE, MAX_BRUSH_SIZE); QObject::connect(m_yBrushSizeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(yBrushSizeValueChanged(int))); m_yBrushSizeSpinBox->getWidget()->setToolTip("Coronal brush size (voxels).\n" "Must be an odd value."); m_zBrushSizeSpinBox = new WuQSpinBoxOddValue(this); m_zBrushSizeSpinBox->setRange(MIN_BRUSH_SIZE, MAX_BRUSH_SIZE); QObject::connect(m_zBrushSizeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(zBrushSizeValueChanged(int))); m_zBrushSizeSpinBox->getWidget()->setToolTip("Axial brush size (voxels).\n" "Must be an odd value."); m_voxelValueLabel = new QLabel("Value:"); m_voxelFloatValueSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(-1000.0, 1000.0, 1.0, 1, this, SLOT(voxelValueChanged(double))); m_voxelFloatValueSpinBox->setValue(1.0); m_voxelLabelValueAction = WuQtUtilities::createAction("XXX", "Choose Label for Voxels", this, this, SLOT(labelValueActionTriggered())); m_voxelLabelValueToolButton = new QToolButton(); m_voxelLabelValueToolButton->setDefaultAction(m_voxelLabelValueAction); WuQtUtilities::setToolButtonStyleForQt5Mac(m_voxelLabelValueToolButton); const int SPACE = 10; QWidget* widget = new QWidget(); QHBoxLayout* layout = new QHBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 0); layout->addWidget(volumeLabel); layout->addWidget(m_newFileToolButton); layout->addWidget(m_addMapsToolButton); layout->addWidget(lockFileToolButton); layout->addSpacing(SPACE); layout->addWidget(editLabel); layout->addWidget(undoToolButton); layout->addWidget(redoToolButton); layout->addWidget(resetToolButton); layout->addSpacing(SPACE); layout->addWidget(brushSizeLabel); layout->addWidget(m_xBrushSizeSpinBox->getWidget()); layout->addWidget(m_yBrushSizeSpinBox->getWidget()); layout->addWidget(m_zBrushSizeSpinBox->getWidget()); layout->addSpacing(SPACE); layout->addWidget(m_voxelValueLabel); layout->addWidget(m_voxelFloatValueSpinBox); layout->addWidget(m_voxelLabelValueToolButton); layout->addStretch(); return widget; } /** * @return Create and return the mode toolbar. */ QWidget* UserInputModeVolumeEditWidget::createModeToolBar() { QWidget* widget = new QWidget(); QHBoxLayout* layout = new QHBoxLayout(widget); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 0); QLabel* modeLabel = new QLabel("Mode:"); layout->addWidget(modeLabel); m_volumeEditModeActionGroup = new QActionGroup(this); m_volumeEditModeActionGroup->setExclusive(true); QObject::connect(m_volumeEditModeActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(editingModeActionTriggered(QAction*))); std::vector editModes; VolumeEditingModeEnum::getAllEnums(editModes); bool firstActionFlag = true; for (std::vector::iterator iter = editModes.begin(); iter != editModes.end(); iter++) { const VolumeEditingModeEnum::Enum mode = *iter; const int modeInt = VolumeEditingModeEnum::toIntegerCode(mode); const AString modeName = VolumeEditingModeEnum::toGuiName(mode); const AString toolTip = WuQtUtilities::createWordWrappedToolTipText(VolumeEditingModeEnum::toToolTip(mode)); QAction* action = new QAction(modeName, this); action->setData(modeInt); action->setToolTip(toolTip); action->setCheckable(true); if (firstActionFlag) { firstActionFlag = false; action->setChecked(true); } m_volumeEditModeActionGroup->addAction(action); QToolButton* toolButton = new QToolButton(); toolButton->setDefaultAction(action); WuQtUtilities::setToolButtonStyleForQt5Mac(toolButton); layout->addWidget(toolButton); } layout->addStretch(); return widget; } /** * Get the editing parameters from the toolbar. * * @param editingModeOut * Output containing the selected editing mode. * @param brushSizeOut * Brush IJK/XYZ sizes. * @param floatValueOut * Float value for palette mapped volume files. * @param labelNameOut * Label name for label mapped volume files. */ void UserInputModeVolumeEditWidget::getEditingParameters(VolumeEditingModeEnum::Enum& editingModeOut, int32_t brushSizesOut[3], float& floatValueOut, AString& labelNameOut) const { editingModeOut = getEditingMode(); brushSizesOut[0] = m_xBrushSizeSpinBox->value(); brushSizesOut[1] = m_yBrushSizeSpinBox->value(); brushSizesOut[2] = m_zBrushSizeSpinBox->value(); floatValueOut = m_voxelFloatValueSpinBox->value(); labelNameOut = m_voxelLabelValueAction->text(); } /** * @return The volume editing mode. */ VolumeEditingModeEnum::Enum UserInputModeVolumeEditWidget::getEditingMode() const { QAction* action = m_volumeEditModeActionGroup->checkedAction(); CaretAssert(action); const int modeInt = action->data().toInt(); bool validFlag = false; const VolumeEditingModeEnum::Enum editMode = VolumeEditingModeEnum::fromIntegerCode(modeInt, &validFlag); CaretAssert(validFlag); return editMode; } /** * Called when new volume file button is clicked. */ void UserInputModeVolumeEditWidget::newFileActionTriggered() { VolumeFileCreateDialog newVolumeDialog(m_newFileToolButton); if (newVolumeDialog.exec() == VolumeFileCreateDialog::Accepted) { VolumeFile* vf = newVolumeDialog.getVolumeFile(); if (vf != NULL) { for (int32_t i = 0; i < vf->getNumberOfMaps(); i++) { vf->getVolumeFileEditorDelegate()->setLocked(i, false); } EventDataFileAdd addFileEvent(vf); EventManager::get()->sendEvent(addFileEvent.getPointer()); viewVolumeInNewOverlay(vf, 0); } } } /** * View the volume in a new overlay at the top of the overlays * * @param vf * The volume file. * @param mapIndex * Select this map index in overlay. */ void UserInputModeVolumeEditWidget::viewVolumeInNewOverlay(VolumeFile* vf, const int32_t mapIndex) { UserInputModeVolumeEdit::VolumeEditInfo volumeEditInfo; m_inputModeVolumeEdit->getVolumeEditInfo(volumeEditInfo); if (volumeEditInfo.m_topOverlay != NULL) { /* * Add new overlay and place new volume file in the top most overlay */ volumeEditInfo.m_overlaySet->insertOverlayAbove(0); volumeEditInfo.m_topOverlay = volumeEditInfo.m_overlaySet->getPrimaryOverlay(); CaretAssert((mapIndex >= 0) && (mapIndex < vf->getNumberOfMaps())); volumeEditInfo.m_topOverlay->setSelectionData(vf, mapIndex); volumeEditInfo.m_topOverlay->setEnabled(true); volumeEditInfo.m_topOverlay->setMapYokingGroup(MapYokingGroupEnum::MAP_YOKING_GROUP_OFF); m_inputModeVolumeEdit->updateGraphicsAfterEditing(vf, mapIndex); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); updateWidget(); } /** * Called when the add maps action is triggered. */ void UserInputModeVolumeEditWidget::addMapsActionTriggered() { UserInputModeVolumeEdit::VolumeEditInfo volumeEditInfo; if (m_inputModeVolumeEdit->getVolumeEditInfo(volumeEditInfo)) { VolumeFile* vf = volumeEditInfo.m_volumeFile; WuQDataEntryDialog ded("Add Map", m_addMapsToolButton); ded.setTextAtTop(("Add Map to Volume File: " + vf->getFileNameNoPath()), true); const int32_t newMapIndex = vf->getNumberOfMaps(); QLineEdit* nameLineEdit = ded.addLineEditWidget("Map Name"); nameLineEdit->setText("Map " + AString::number(newMapIndex + 1)); if (ded.exec() == WuQDataEntryDialog::Accepted) { /* * Add map, set the map name, * set the selected map to the new map, * update graphics, update user interface. */ vf->addSubvolumes(1); vf->setMapName(newMapIndex, nameLineEdit->text().trimmed()); vf->getVolumeFileEditorDelegate()->setLocked(newMapIndex, false); viewVolumeInNewOverlay(vf, newMapIndex); } } } /** * Called when lock button is clicked. */ void UserInputModeVolumeEditWidget::lockFileActionTriggered() { UserInputModeVolumeEdit::VolumeEditInfo volumeEditInfo; if (m_inputModeVolumeEdit->getVolumeEditInfo(volumeEditInfo)) { volumeEditInfo.m_volumeFileEditorDelegate->setLocked(volumeEditInfo.m_mapIndex, m_lockAction->isChecked()); } } /** * Called when undo button is clicked. */ void UserInputModeVolumeEditWidget::undoActionTriggered() { UserInputModeVolumeEdit::VolumeEditInfo volumeEditInfo; if (m_inputModeVolumeEdit->getVolumeEditInfo(volumeEditInfo)) { AString errorMessage; if ( ! volumeEditInfo.m_volumeFileEditorDelegate->undo(volumeEditInfo.m_mapIndex, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } m_inputModeVolumeEdit->updateGraphicsAfterEditing(volumeEditInfo.m_volumeFile, volumeEditInfo.m_mapIndex); } } /** * Called when redo button is clicked. */ void UserInputModeVolumeEditWidget::redoActionTriggered() { UserInputModeVolumeEdit::VolumeEditInfo volumeEditInfo; if (m_inputModeVolumeEdit->getVolumeEditInfo(volumeEditInfo)) { AString errorMessage; if ( ! volumeEditInfo.m_volumeFileEditorDelegate->redo(volumeEditInfo.m_mapIndex, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } m_inputModeVolumeEdit->updateGraphicsAfterEditing(volumeEditInfo.m_volumeFile, volumeEditInfo.m_mapIndex); } } /** * Called when reset button is clicked. */ void UserInputModeVolumeEditWidget::resetActionTriggered() { UserInputModeVolumeEdit::VolumeEditInfo volumeEditInfo; if (m_inputModeVolumeEdit->getVolumeEditInfo(volumeEditInfo)) { AString errorMessage; if ( ! volumeEditInfo.m_volumeFileEditorDelegate->reset(volumeEditInfo.m_mapIndex, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } m_inputModeVolumeEdit->updateGraphicsAfterEditing(volumeEditInfo.m_volumeFile, volumeEditInfo.m_mapIndex); } } /** * Called when X-size brush value is changed. */ void UserInputModeVolumeEditWidget::xBrushSizeValueChanged(int) { } /** * Called when X-size brush value is changed. */ void UserInputModeVolumeEditWidget::yBrushSizeValueChanged(int) { } /** * Called when X-size brush value is changed. */ void UserInputModeVolumeEditWidget::zBrushSizeValueChanged(int) { } /** * Called when voxel value is changed. */ void UserInputModeVolumeEditWidget::voxelValueChanged(double) { } /** * Called when voxel label value action is triggered. */ void UserInputModeVolumeEditWidget::labelValueActionTriggered() { UserInputModeVolumeEdit::VolumeEditInfo volumeEditInfo; if (m_inputModeVolumeEdit->getVolumeEditInfo(volumeEditInfo)) { if (volumeEditInfo.m_volumeFile != NULL) { GiftiLabelTableEditor lte(volumeEditInfo.m_volumeFile, volumeEditInfo.m_mapIndex, "Select Label", GiftiLabelTableEditor::OPTION_NONE, m_voxelLabelValueToolButton); const AString defaultLabelName = m_voxelLabelValueAction->text(); if ( ! defaultLabelName.isEmpty()) { lte.selectLabelWithName(defaultLabelName); } if (lte.exec() == GiftiLabelTableEditor::Accepted) { const AString selectedName = lte.getLastSelectedLabelName(); m_voxelLabelValueAction->setText(selectedName); } } } } /** * Called when an editing mode is selected. * * @param action * Editing action that was selected. */ void UserInputModeVolumeEditWidget::editingModeActionTriggered(QAction* action) { CaretAssert(action); const int modeInt = action->data().toInt(); bool validFlag = false; (void)VolumeEditingModeEnum::fromIntegerCode(modeInt, &validFlag); CaretAssert(validFlag); } connectome-workbench-1.4.2/src/GuiQt/UserInputModeVolumeEditWidget.h000066400000000000000000000103341360521144700255320ustar00rootroot00000000000000#ifndef __USER_INPUT_MODE_VOLUME_EDIT_WIDGET_H__ #define __USER_INPUT_MODE_VOLUME_EDIT_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "EventListenerInterface.h" #include "UserInputModeVolumeEdit.h" #include "VolumeEditingModeEnum.h" class QAction; class QActionGroup; class QDoubleSpinBox; class QLabel; class QSpinBox; class QToolButton; namespace caret { class UserInputModeVolumeEdit; class WuQSpinBoxOddValue; class UserInputModeVolumeEditWidget : public QWidget, public EventListenerInterface { Q_OBJECT public: UserInputModeVolumeEditWidget(UserInputModeVolumeEdit* inputModeVolumeEdit, const int32_t windowIndex, QWidget* parent = 0); virtual ~UserInputModeVolumeEditWidget(); void receiveEvent(Event* event); void updateWidget(); void getEditingParameters(VolumeEditingModeEnum::Enum& editingModeOut, int32_t brushSizesOut[3], float& floatValueOut, AString& labelNameOut) const; VolumeEditingModeEnum::Enum getEditingMode() const; // ADD_NEW_METHODS_HERE private slots: void newFileActionTriggered(); void lockFileActionTriggered(); void undoActionTriggered(); void redoActionTriggered(); void resetActionTriggered(); void xBrushSizeValueChanged(int); void yBrushSizeValueChanged(int); void zBrushSizeValueChanged(int); void voxelValueChanged(double); void labelValueActionTriggered(); void editingModeActionTriggered(QAction*); void addMapsActionTriggered(); private: UserInputModeVolumeEditWidget(const UserInputModeVolumeEditWidget&); UserInputModeVolumeEditWidget& operator=(const UserInputModeVolumeEditWidget&); QWidget* createSelectionToolBar(); QWidget* createModeToolBar(); void viewVolumeInNewOverlay(VolumeFile* vf, const int32_t mapIndex); QAction* m_lockAction; UserInputModeVolumeEdit* m_inputModeVolumeEdit; const int32_t m_windowIndex; QActionGroup* m_volumeEditModeActionGroup; QToolButton* m_newFileToolButton; WuQSpinBoxOddValue* m_xBrushSizeSpinBox; WuQSpinBoxOddValue* m_yBrushSizeSpinBox; WuQSpinBoxOddValue* m_zBrushSizeSpinBox; QLabel* m_voxelValueLabel; QAction* m_voxelLabelValueAction; QToolButton* m_voxelLabelValueToolButton; QDoubleSpinBox* m_voxelFloatValueSpinBox; QToolButton* m_addMapsToolButton; // ADD_NEW_MEMBERS_HERE }; #ifdef __USER_INPUT_MODE_VOLUME_EDIT_WIDGET_DECLARE__ // #endif // __USER_INPUT_MODE_VOLUME_EDIT_WIDGET_DECLARE__ } // namespace #endif //__USER_INPUT_MODE_VOLUME_EDIT_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/UserInputTileTabsContextMenu.cxx000066400000000000000000000107731360521144700257670ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __USER_INPUT_TILE_TABS_CONTEXT_MENU_DECLARE__ #include "UserInputTileTabsContextMenu.h" #undef __USER_INPUT_TILE_TABS_CONTEXT_MENU_DECLARE__ #include "BrainBrowserWindow.h" #include "BrainOpenGLViewportContent.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "EventBrowserTabGet.h" #include "EventBrowserWindowTileTabOperation.h" #include "EventManager.h" #include "GuiManager.h" using namespace caret; /** * \class caret::UserInputTileTabsContextMenu * \brief Menu for tile tabs operations in a window context menu * \ingroup GuiQt */ /** * Constructor. * * @param parentWidget * Parent widget on which error message dialogs are displayed * @param viewportContent * Content of the viewport under the mouse. */ UserInputTileTabsContextMenu::UserInputTileTabsContextMenu(QWidget* parentWidget, BrainOpenGLViewportContent* viewportContent) : QMenu("Tabs"), m_parentWidget(parentWidget), m_windowIndex(viewportContent->getWindowIndex()), m_tabIndex(viewportContent->getTabIndex()) { BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(m_windowIndex); CaretAssert(bbw); CaretAssert(m_windowIndex >= 0); CaretAssert(m_tabIndex >= 0); EventBrowserTabGet tabContentEvent(m_tabIndex); EventManager::get()->sendEvent(tabContentEvent.getPointer()); BrowserTabContent* tabContent = tabContentEvent.getBrowserTab(); if (tabContent != NULL) { const AString tabNumberText(AString::number(m_tabIndex + 1)); if (bbw->isTileTabsSelected()) { m_createNewTabBeforeAction = addAction("Create New Tab Before This Tab"); m_createNewTabAfterAction = addAction("Create New Tab After This Tab"); m_selectTabAction = addAction("Select This Tab"); } QObject::connect(this, &QMenu::triggered, this, &UserInputTileTabsContextMenu::actionTriggered); } } /** * Destructor. */ UserInputTileTabsContextMenu::~UserInputTileTabsContextMenu() { } /** * @return Is this menu valid? */ bool UserInputTileTabsContextMenu::isValid() const { return (actions().size() > 0); } /** * Gets called when an action is selected from the menu. * * @param action * Action selected by user. */ void UserInputTileTabsContextMenu::actionTriggered(QAction* action) { EventBrowserWindowTileTabOperation::Operation operation = EventBrowserWindowTileTabOperation::OPERATION_SELECT_TAB; bool validOperationFlag = false; if (action == m_createNewTabBeforeAction) { operation = EventBrowserWindowTileTabOperation::OPERATION_NEW_TAB_BEFORE; validOperationFlag = true; } else if (action == m_createNewTabAfterAction) { operation = EventBrowserWindowTileTabOperation::OPERATION_NEW_TAB_AFTER; validOperationFlag = true; } else if (action == m_selectTabAction) { operation = EventBrowserWindowTileTabOperation::OPERATION_SELECT_TAB; validOperationFlag = true; } else if (action != NULL) { CaretAssertMessage(0, "Invalid menu action. Has a new menu action been added?"); } if (validOperationFlag) { std::vector emptyBrowserTabs; EventBrowserWindowTileTabOperation tileTabOperation(operation, m_parentWidget, m_windowIndex, m_tabIndex, emptyBrowserTabs); EventManager::get()->sendEvent(tileTabOperation.getPointer()); } } connectome-workbench-1.4.2/src/GuiQt/UserInputTileTabsContextMenu.h000066400000000000000000000043171360521144700254110ustar00rootroot00000000000000#ifndef __USER_INPUT_TILE_TABS_CONTEXT_MENU_H__ #define __USER_INPUT_TILE_TABS_CONTEXT_MENU_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include class QWidget; namespace caret { class BrainOpenGLViewportContent; class UserInputTileTabsContextMenu : public QMenu { Q_OBJECT public: UserInputTileTabsContextMenu(QWidget* parentWidget, BrainOpenGLViewportContent* viewportContent); virtual ~UserInputTileTabsContextMenu(); bool isValid() const; // ADD_NEW_METHODS_HERE private slots: void actionTriggered(QAction* action); private: UserInputTileTabsContextMenu(const UserInputTileTabsContextMenu&); UserInputTileTabsContextMenu& operator=(const UserInputTileTabsContextMenu&); QWidget* m_parentWidget; const int32_t m_windowIndex; const int32_t m_tabIndex; QAction* m_createNewTabBeforeAction = nullptr; QAction* m_createNewTabAfterAction = nullptr; QAction* m_selectTabAction = nullptr; // ADD_NEW_MEMBERS_HERE }; #ifdef __USER_INPUT_TILE_TABS_CONTEXT_MENU_DECLARE__ // #endif // __USER_INPUT_TILE_TABS_CONTEXT_MENU_DECLARE__ } // namespace #endif //__USER_INPUT_TILE_TABS_CONTEXT_MENU_H__ connectome-workbench-1.4.2/src/GuiQt/UsernamePasswordWidget.cxx000066400000000000000000000173321360521144700246530ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __USERNAME_PASSWORD_WIDGET_DECLARE__ #include "UsernamePasswordWidget.h" #undef __USERNAME_PASSWORD_WIDGET_DECLARE__ #include #include #include #include #include "CaretAssert.h" #include "CaretPreferences.h" #include "SessionManager.h" #include "WuQDialogModal.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::UsernamePasswordWidget * \brief Widget for username and password with saving to preferences. * \ingroup GuiQt */ /** * Constructor. * * @param parent * Parent widget. */ UsernamePasswordWidget::UsernamePasswordWidget(QWidget* parent) : QWidget(parent) { QLabel* usernameLabel = new QLabel("User Name: "); m_usernameLineEdit = new QLineEdit(); m_usernameLineEdit->setFixedWidth(200); QLabel* passwordLabel = new QLabel("Password: "); m_passwordLineEdit = new QLineEdit(); m_passwordLineEdit->setFixedWidth(200); m_passwordLineEdit->setEchoMode(QLineEdit::Password); m_savePasswordToPreferencesCheckBox = new QCheckBox("Save Password to Preferences"); QObject::connect(m_savePasswordToPreferencesCheckBox, SIGNAL(clicked(bool)), this, SLOT(savePasswordToPreferencesClicked(bool))); int row = 0; QGridLayout* loginGridLayout = new QGridLayout(this); loginGridLayout->setColumnStretch(0, 0); loginGridLayout->setColumnStretch(1, 100); loginGridLayout->addWidget(usernameLabel, row, 0); loginGridLayout->addWidget(m_usernameLineEdit, row, 1); row++; loginGridLayout->addWidget(passwordLabel, row, 0); loginGridLayout->addWidget(m_passwordLineEdit, row, 1); row++; loginGridLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), row, 0, 1, 2); row++; loginGridLayout->addWidget(m_savePasswordToPreferencesCheckBox, row, 0, 1, 2, Qt::AlignLeft); row++; CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); if (s_previousUsernamePassword.m_firstTime) { s_previousUsernamePassword.m_firstTime = false; AString userName; AString password; prefs->getRemoteFileUserNameAndPassword(userName, password); s_previousUsernamePassword.m_username = userName; if (prefs->isRemoteFilePasswordSaved()) { s_previousUsernamePassword.m_password = password; } else { s_previousUsernamePassword.m_password = ""; } } m_usernameLineEdit->setText(s_previousUsernamePassword.m_username); m_passwordLineEdit->setText(s_previousUsernamePassword.m_password); m_savePasswordToPreferencesCheckBox->setChecked(prefs->isRemoteFilePasswordSaved()); } /** * Destructor. */ UsernamePasswordWidget::~UsernamePasswordWidget() { } /** * Popup a modal dialog for the username and password. * * @param parent * Parent on which dialog is displayed. * @param title * Title of dialog. * @param message * Optional message shown in dialog. * @param usernameOut * The username. * @param passwordOut * The password. * @return * True if the user pressed the OK button, else false. */ bool UsernamePasswordWidget::getUserNameAndPasswordInDialog(QWidget* parent, const AString& title, const AString& message, AString& usernameOut, AString& passwordOut) { WuQDialogModal dialog(title, parent); dialog.setWindowTitle(title); QWidget* dialogWidget = new QWidget(); QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); if (message.isEmpty() == false) { QLabel* messageLabel = new QLabel(message); messageLabel->setWordWrap(true); dialogLayout->addWidget(messageLabel); } UsernamePasswordWidget* userNameAndPasswordWidget = new UsernamePasswordWidget(); dialogLayout->addWidget(userNameAndPasswordWidget); dialog.setCentralWidget(dialogWidget, WuQDialog::SCROLL_AREA_NEVER); if (dialog.exec() == WuQDialogModal::Accepted) { userNameAndPasswordWidget->getUsernameAndPassword(usernameOut, passwordOut); return true; } return false; } /** * Get the username and password. If the both the username and password * are valid (returns true) and "Save Password to Preferences" is checked, * the username and password are written to the user's preferences. If it is * not checked, only user username is written to preferences. * * @param usernameOut * The username. * @param passwordOut * The password. * @return * True if both the username and password are non-empty, else false. */ bool UsernamePasswordWidget::getUsernameAndPassword(AString& usernameOut, AString& passwordOut) { usernameOut = m_usernameLineEdit->text().trimmed(); passwordOut = m_passwordLineEdit->text().trimmed(); if (usernameOut.isEmpty()) { return false; } else if (passwordOut.isEmpty()) { return false; } const bool savePassword = m_savePasswordToPreferencesCheckBox->isChecked(); CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->setRemoteFilePasswordSaved(savePassword); if (savePassword) { prefs->setRemoteFileUserNameAndPassword(usernameOut, passwordOut); } else { prefs->setRemoteFileUserNameAndPassword(usernameOut, ""); } s_previousUsernamePassword.m_username = usernameOut; s_previousUsernamePassword.m_password = passwordOut; return true; } /** * Called when save password to preferences checkbox value is changed * by the user. * * @param status * New status of save password to preferences checkbox. */ void UsernamePasswordWidget::savePasswordToPreferencesClicked(bool status) { if (status) { const QString msg = ("The Workbench preferences are stored in a file somewhere in your " "home directory and the location depends upon your operating " "system. This is not a secure file and it may be possible " "other users to access this file and find your " "open location password. Unchceck the box if you do not want " "your password saved within your preferences."); WuQMessageBox::informationOk(m_savePasswordToPreferencesCheckBox, WuQtUtilities::createWordWrappedToolTipText(msg)); } } connectome-workbench-1.4.2/src/GuiQt/UsernamePasswordWidget.h000066400000000000000000000055001360521144700242720ustar00rootroot00000000000000#ifndef __USERNAME_PASSWORD_WIDGET_H__ #define __USERNAME_PASSWORD_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "AString.h" class QLineEdit; class QCheckBox; namespace caret { class UsernamePasswordWidget : public QWidget { Q_OBJECT public: UsernamePasswordWidget(QWidget* parent = 0); virtual ~UsernamePasswordWidget(); bool getUsernameAndPassword(AString& usernameOut, AString& passwordOut); static bool getUserNameAndPasswordInDialog(QWidget* parent, const AString& title, const AString& message, AString& usernameOut, AString& passwordOut); private: UsernamePasswordWidget(const UsernamePasswordWidget&); UsernamePasswordWidget& operator=(const UsernamePasswordWidget&); private slots: void savePasswordToPreferencesClicked(bool); public: // ADD_NEW_METHODS_HERE private: class PreviousUsernamePassword { public: PreviousUsernamePassword() { m_username = ""; m_password = ""; m_firstTime = true; } AString m_username; AString m_password; bool m_firstTime; }; // ADD_NEW_MEMBERS_HERE QLineEdit* m_usernameLineEdit; QLineEdit* m_passwordLineEdit; QCheckBox* m_savePasswordToPreferencesCheckBox; static PreviousUsernamePassword s_previousUsernamePassword; }; #ifdef __USERNAME_PASSWORD_WIDGET_DECLARE__ UsernamePasswordWidget::PreviousUsernamePassword UsernamePasswordWidget::s_previousUsernamePassword; #endif // __USERNAME_PASSWORD_WIDGET_DECLARE__ } // namespace #endif //__USERNAME_PASSWORD_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/ViewModeEnum.cxx000066400000000000000000000140461360521144700225500ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __VIEW_MODE_DECLARE__ #include "ViewModeEnum.h" #undef __VIEW_MODE_DECLARE__ using namespace caret; /** * Constructor. * * @param e * An enumerated value. * @param name * Name of enumberated value. */ ViewModeEnum::ViewModeEnum(const Enum e, const int32_t integerCode, const QString& name, const QString& guiName) { this->e = e; this->integerCode = integerCode; this->name = name; this->guiName = guiName; } /** * Destructor. */ ViewModeEnum::~ViewModeEnum() { } /** * Initialize the enumerated metadata. */ void ViewModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(ViewModeEnum(VIEW_MODE_INVALID, 0, "VIEW_MODE_INVALID", "Invalid")); enumData.push_back(ViewModeEnum(VIEW_MODE_SURFACE, 1, "VIEW_MODE_SURFACE", "Surface")); enumData.push_back(ViewModeEnum(VIEW_MODE_VOLUME_SLICES, 2, "VIEW_MODE_VOLUME_SLICES", "Volume")); enumData.push_back(ViewModeEnum(VIEW_MODE_WHOLE_BRAIN, 3, "VIEW_MODE_WHOLE_BRAIN", "Whole Brain")); } /** * Find the data for and enumerated value. * @param e * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const ViewModeEnum* ViewModeEnum::findData(const Enum e) { initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const ViewModeEnum* d = &enumData[i]; if (d->e == e) { return d; } } return &enumData[0]; } /** * Get a string representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ QString ViewModeEnum::toName(Enum e) { initialize(); const ViewModeEnum* gaio = findData(e); return gaio->name; } /** * Get an enumerated value corresponding to its name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ViewModeEnum::Enum ViewModeEnum::fromName(const QString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = VIEW_MODE_INVALID; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ViewModeEnum& d = *iter; if (d.name == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } /** * Get a GUI string representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ QString ViewModeEnum::toGuiName(Enum e) { initialize(); const ViewModeEnum* gaio = findData(e); return gaio->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ ViewModeEnum::Enum ViewModeEnum::fromGuiName(const QString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = VIEW_MODE_INVALID; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ViewModeEnum& d = *iter; if (d.guiName == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t ViewModeEnum::toIntegerCode(Enum e) { initialize(); const ViewModeEnum* ndt = findData(e); return ndt->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ ViewModeEnum::Enum ViewModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = VIEW_MODE_INVALID; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const ViewModeEnum& ndt = *iter; if (ndt.integerCode == integerCode) { e = ndt.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } return e; } connectome-workbench-1.4.2/src/GuiQt/ViewModeEnum.h000066400000000000000000000044151360521144700221740ustar00rootroot00000000000000#ifndef __VIEW_MODE_ENUM_H__ #define __VIEW_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include namespace caret { /** * View Mode Types. */ class ViewModeEnum { public: /** View Mode Types. */ enum Enum { /** Invalid */ VIEW_MODE_INVALID, /** View Surface */ VIEW_MODE_SURFACE, /** View Volume Slices */ VIEW_MODE_VOLUME_SLICES, /** View Whole Brain */ VIEW_MODE_WHOLE_BRAIN }; ~ViewModeEnum(); static QString toName(Enum e); static Enum fromName(const QString& s, bool* isValidOut); static QString toGuiName(Enum e); static Enum fromGuiName(const QString& s, bool* isValidOut); static int32_t toIntegerCode(Enum e); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); private: ViewModeEnum(const Enum e, const int32_t integerCode, const QString& name, const QString& guiName); static const ViewModeEnum* findData(const Enum e); static std::vector enumData; static void initialize(); static bool initializedFlag; Enum e; int32_t integerCode; QString name; QString guiName; }; #ifdef __VIEW_MODE_DECLARE__ std::vector ViewModeEnum::enumData; bool ViewModeEnum::initializedFlag = false; #endif // __VIEW_MODE_DECLARE__ } // namespace #endif // __VIEW_MODE_ENUM_H__ connectome-workbench-1.4.2/src/GuiQt/VolumeFileCreateDialog.cxx000066400000000000000000000571241360521144700245230ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __VOLUME_FILE_CREATE_DIALOG_DECLARE__ #include "VolumeFileCreateDialog.h" #undef __VOLUME_FILE_CREATE_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include #include "Brain.h" #include "CaretAssert.h" #include "CaretFileDialog.h" #include "CiftiMappableDataFile.h" #include "CaretVolumeExtension.h" #include "GuiManager.h" #include "VolumeFile.h" #include "WuQDataEntryDialog.h" #include "WuQFactory.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::VolumeFileCreateDialog * \brief Dialog for creating volume file or adding map to volume file * \ingroup GuiQt */ /** * Constructor. */ VolumeFileCreateDialog::VolumeFileCreateDialog(QWidget* parent) : WuQDialogModal("Create Volume", parent) { if ( ! s_previousVolumeSettingsValid) { s_previousVolumeSettings.m_dimensions.clear(); s_previousVolumeSettings.m_dimensions.push_back(182); s_previousVolumeSettings.m_dimensions.push_back(218); s_previousVolumeSettings.m_dimensions.push_back(182); s_previousVolumeSettings.m_dimensions.push_back(1); std::vector row1; row1.push_back(-1); row1.push_back(0); row1.push_back(0); row1.push_back(90); std::vector row2; row2.push_back(0); row2.push_back(1); row2.push_back(0); row2.push_back(-126); std::vector row3; row3.push_back(0); row3.push_back(0); row3.push_back(1); row3.push_back(-72); std::vector row4; row4.push_back(0); row4.push_back(0); row4.push_back(0); row4.push_back(1); s_previousVolumeSettings.m_indexToSpace.clear(); s_previousVolumeSettings.m_indexToSpace.push_back(row1); s_previousVolumeSettings.m_indexToSpace.push_back(row2); s_previousVolumeSettings.m_indexToSpace.push_back(row3); s_previousVolumeSettings.m_indexToSpace.push_back(row4); s_previousVolumeSettings.m_volumeType = SubvolumeAttributes::FUNCTIONAL; s_previousVolumeSettingsValid = true; } m_volumeFile = NULL; QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(createNewVolumeFileWidget()); setCentralWidget(widget, WuQDialog::SCROLL_AREA_NEVER); } /** * Destructor. */ VolumeFileCreateDialog::~VolumeFileCreateDialog() { } /** * @return Create and return the add map to volume file widget */ QWidget* VolumeFileCreateDialog::addMapToVolumeFileWidget() { QWidget* widget = new QWidget(); return widget; } /** * @return Create and return the create new volume file widget */ QWidget* VolumeFileCreateDialog::createNewVolumeFileWidget() { const AString defaultFileName = ("File_" + AString::number(s_fileNameCounter) + ".nii.gz"); s_fileNameCounter++; QLabel* newFileNameLabel = new QLabel("Name:"); m_newFileNameLineEdit = new QLineEdit(); m_newFileNameLineEdit->setText(defaultFileName); QPushButton* newFileNamePushButton = new QPushButton("Select..."); QObject::connect(newFileNamePushButton, SIGNAL(clicked()), this, SLOT(newFileNamePushButtonClicked())); QLabel* newFileTypeLabel = new QLabel("Type:"); m_newFileTypeComboBox = new QComboBox(); m_newFileTypeComboBox->addItem("Functional (Scalar)", SubvolumeAttributes::FUNCTIONAL); m_newFileTypeComboBox->addItem("Label", SubvolumeAttributes::LABEL); QLabel* newFileNumberOfMapsLabel = new QLabel("Maps:"); m_newFileNumberOfMapsSpinBox = WuQFactory::newSpinBoxWithMinMaxStep(1, s_maximumNumberOfMaps, 1); m_newFileNumberOfMapsSpinBox->setFixedWidth(50); QObject::connect(m_newFileNumberOfMapsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(numberOfMapsSpinBoxValueChanged(int))); for (int32_t iMap = 0; iMap < s_maximumNumberOfMaps; iMap++) { const AString mapNumText("Map " + AString::number(iMap + 1) + " "); QLabel* label = new QLabel(mapNumText + "Name"); m_mapNameLabels.push_back(label); QLineEdit* lineEdit = new QLineEdit(); lineEdit->setText(mapNumText); m_mapNameLineEdits.push_back(lineEdit); } QGroupBox* fileGroupBox = new QGroupBox("File"); QGridLayout* nameTypeLayout = new QGridLayout(fileGroupBox); int nameTypeRow = 0; nameTypeLayout->setColumnStretch(0, 0); nameTypeLayout->setColumnStretch(1, 0); nameTypeLayout->setColumnStretch(2, 100); nameTypeLayout->setColumnStretch(3, 0); nameTypeLayout->addWidget(newFileNameLabel, nameTypeRow, 0); nameTypeLayout->addWidget(m_newFileNameLineEdit, nameTypeRow, 1, 1, 2); nameTypeLayout->addWidget(newFileNamePushButton, nameTypeRow, 4); nameTypeRow++; nameTypeLayout->addWidget(newFileTypeLabel, nameTypeRow, 0); nameTypeLayout->addWidget(m_newFileTypeComboBox, nameTypeRow, 1); nameTypeRow++; nameTypeLayout->addWidget(newFileNumberOfMapsLabel, nameTypeRow, 0); nameTypeLayout->addWidget(m_newFileNumberOfMapsSpinBox, nameTypeRow, 1, Qt::AlignLeft); nameTypeRow++; for (int32_t iMap = 0; iMap < s_maximumNumberOfMaps; iMap++) { CaretAssertVectorIndex(m_mapNameLabels, iMap); CaretAssertVectorIndex(m_mapNameLineEdits, iMap); nameTypeLayout->addWidget(m_mapNameLabels[iMap], nameTypeRow, 0); nameTypeLayout->addWidget(m_mapNameLineEdits[iMap], nameTypeRow, 1, 1, 2); nameTypeRow++; } const int SPIN_BOX_WIDTH = 80; QLabel* dimensionsLabel = new QLabel("Dimensions:"); m_newDimXSpinBox = WuQFactory::newSpinBoxWithMinMaxStep(1, 100000, 1); m_newDimYSpinBox = WuQFactory::newSpinBoxWithMinMaxStep(1, 100000, 1); m_newDimZSpinBox = WuQFactory::newSpinBoxWithMinMaxStep(1, 100000, 1); m_newDimXSpinBox->setFixedWidth(SPIN_BOX_WIDTH); m_newDimYSpinBox->setFixedWidth(SPIN_BOX_WIDTH); m_newDimZSpinBox->setFixedWidth(SPIN_BOX_WIDTH); const double bigDouble = 100000000.0; QLabel* originLabel = new QLabel("Origin:"); m_newOriginXSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(-bigDouble, bigDouble, 1.0, 1); m_newOriginYSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(-bigDouble, bigDouble, 1.0, 1); m_newOriginZSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(-bigDouble, bigDouble, 1.0, 1); m_newOriginXSpinBox->setFixedWidth(SPIN_BOX_WIDTH); m_newOriginYSpinBox->setFixedWidth(SPIN_BOX_WIDTH); m_newOriginZSpinBox->setFixedWidth(SPIN_BOX_WIDTH); QLabel* spacingLabel = new QLabel("Spacing:"); m_newSpacingXSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(-bigDouble, bigDouble, 1.0, 1); m_newSpacingYSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(-bigDouble, bigDouble, 1.0, 1); m_newSpacingZSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(-bigDouble, bigDouble, 1.0, 1); m_newSpacingXSpinBox->setValue(1.0); m_newSpacingYSpinBox->setValue(1.0); m_newSpacingZSpinBox->setValue(1.0); m_newSpacingXSpinBox->setFixedWidth(SPIN_BOX_WIDTH); m_newSpacingYSpinBox->setFixedWidth(SPIN_BOX_WIDTH); m_newSpacingZSpinBox->setFixedWidth(SPIN_BOX_WIDTH); QLabel* xLabel = new QLabel("X"); QLabel* yLabel = new QLabel("Y"); QLabel* zLabel = new QLabel("Z"); QLabel* loadFromLabel = new QLabel("Load From"); m_paramFromFilePushButton = new QPushButton("File..."); QObject::connect(m_paramFromFilePushButton, SIGNAL(clicked()), this, SLOT(loadVolumeParametersFromFilePushButtonClicked())); const int COL_LABEL = 0; const int COL_X = COL_LABEL + 1; const int COL_Y = COL_X + 1; const int COL_Z = COL_Y + 1; const int COL_LOAD = COL_Z + 1; QGroupBox* paramGroupBox = new QGroupBox("Voxels"); QGridLayout* paramsLayout = new QGridLayout(paramGroupBox); int paramsRow = 0; paramsLayout->addWidget(xLabel, paramsRow, COL_X, Qt::AlignHCenter); paramsLayout->addWidget(yLabel, paramsRow, COL_Y, Qt::AlignHCenter); paramsLayout->addWidget(zLabel, paramsRow, COL_Z, Qt::AlignHCenter); paramsLayout->addWidget(loadFromLabel, paramsRow, COL_LOAD, Qt::AlignHCenter); paramsRow++; paramsLayout->addWidget(dimensionsLabel, paramsRow, COL_LABEL); paramsLayout->addWidget(m_newDimXSpinBox, paramsRow, COL_X); paramsLayout->addWidget(m_newDimYSpinBox, paramsRow, COL_Y); paramsLayout->addWidget(m_newDimZSpinBox, paramsRow, COL_Z); paramsLayout->addWidget(m_paramFromFilePushButton, paramsRow, COL_LOAD); paramsRow++; paramsLayout->addWidget(originLabel, paramsRow, COL_LABEL); paramsLayout->addWidget(m_newOriginXSpinBox, paramsRow, COL_X); paramsLayout->addWidget(m_newOriginYSpinBox, paramsRow, COL_Y); paramsLayout->addWidget(m_newOriginZSpinBox, paramsRow, COL_Z); paramsRow++; paramsLayout->addWidget(spacingLabel, paramsRow, COL_LABEL); paramsLayout->addWidget(m_newSpacingXSpinBox, paramsRow, COL_X); paramsLayout->addWidget(m_newSpacingYSpinBox, paramsRow, COL_Y); paramsLayout->addWidget(m_newSpacingZSpinBox, paramsRow, COL_Z); paramsRow++; QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addWidget(fileGroupBox); layout->addWidget(paramGroupBox); if (s_previousVolumeSettingsValid) { m_newDimXSpinBox->setValue(s_previousVolumeSettings.m_dimensions[0]); m_newDimYSpinBox->setValue(s_previousVolumeSettings.m_dimensions[1]); m_newDimZSpinBox->setValue(s_previousVolumeSettings.m_dimensions[2]); m_newFileNumberOfMapsSpinBox->setValue(s_previousVolumeSettings.m_dimensions[3]); const int typeIndex = m_newFileTypeComboBox->findData(static_cast(s_previousVolumeSettings.m_volumeType)); if (typeIndex >= 0) { m_newFileTypeComboBox->setCurrentIndex(typeIndex); } std::vector > m = s_previousVolumeSettings.m_indexToSpace; m_newSpacingXSpinBox->setValue(m[0][0]); m_newSpacingYSpinBox->setValue(m[1][1]); m_newSpacingZSpinBox->setValue(m[2][2]); m_newOriginXSpinBox->setValue(m[0][3]); m_newOriginYSpinBox->setValue(m[1][3]); m_newOriginZSpinBox->setValue(m[2][3]); } m_newFileNameLineEdit->selectAll(); numberOfMapsSpinBoxValueChanged(m_newFileNumberOfMapsSpinBox->value()); return widget; } /** * @return Volume file that was created (NULL if error). */ VolumeFile* VolumeFileCreateDialog::getVolumeFile() { return m_volumeFile; } /** * Called to create a new file name via the file selection dialog. */ void VolumeFileCreateDialog::newFileNamePushButtonClicked() { const AString filename = CaretFileDialog::getChooseFileNameDialog(DataFileTypeEnum::VOLUME, ""); if ( ! filename.isEmpty()) { m_newFileNameLineEdit->setText(filename); } } /** * Called when the number of maps is changed. * * @param value * New value for number of maps. */ void VolumeFileCreateDialog::numberOfMapsSpinBoxValueChanged(int value) { for (int32_t iMap = 0; iMap < s_maximumNumberOfMaps; iMap++) { CaretAssertVectorIndex(m_mapNameLabels, iMap); CaretAssertVectorIndex(m_mapNameLineEdits, iMap); const bool enabledFlag = (iMap < value); m_mapNameLabels[iMap]->setEnabled(enabledFlag); m_mapNameLineEdits[iMap]->setEnabled(enabledFlag); } } /** * Gets called when the ok button is clicked. */ void VolumeFileCreateDialog::okButtonClicked() { AString filename = m_newFileNameLineEdit->text().trimmed(); if (filename.isEmpty()) { WuQMessageBox::errorOk(this, "Filename is empty."); return; } if (! DataFileTypeEnum::isValidFileExtension(filename, DataFileTypeEnum::VOLUME)) { AString validExtensions; const std::vector allExts = DataFileTypeEnum::getAllFileExtensions(DataFileTypeEnum::VOLUME); const int32_t numExts = static_cast(allExts.size()); WuQDataEntryDialog ded("Invalid Volume File Extension", m_newFileNameLineEdit); ded.setTextAtTop("Filename extension is invalid. Choose one " "of the extensions below and press OK. Otherwise, " "press Cancel to change the name of the file.", true); std::vector extButtons; for (int32_t i = 0; i < numExts; i++) { QRadioButton* rb = ded.addRadioButton("." + allExts[i]); if (allExts[i] == "nii.gz") { rb->setChecked(true); } extButtons.push_back(rb); } bool extValid = false; if (ded.exec() == WuQDataEntryDialog::Accepted) { for (int32_t i = 0; i < numExts; i++) { QRadioButton* rb = extButtons[i]; if (rb->isChecked()) { filename += rb->text(); extValid = true; break; } } } if ( ! extValid) { return; } } const int typeIndex = m_newFileTypeComboBox->currentIndex(); const SubvolumeAttributes::VolumeType volumeType = static_cast(m_newFileTypeComboBox->itemData(typeIndex).toInt()); const int32_t numMaps = m_newFileNumberOfMapsSpinBox->value(); std::vector dimensions; dimensions.push_back(m_newDimXSpinBox->value()); dimensions.push_back(m_newDimYSpinBox->value()); dimensions.push_back(m_newDimZSpinBox->value()); dimensions.push_back(numMaps); const float xOrigin = m_newOriginXSpinBox->value(); const float yOrigin = m_newOriginYSpinBox->value(); const float zOrigin = m_newOriginZSpinBox->value(); const float xSpacing = m_newSpacingXSpinBox->value(); const float ySpacing = m_newSpacingYSpinBox->value(); const float zSpacing = m_newSpacingZSpinBox->value(); if ((xSpacing == 0.0) || (ySpacing == 0.0) || (zSpacing == 0.0)) { WuQMessageBox::errorOk(this, "Spacing values must be non-zero."); return; } std::vector rowOne(4, 0.0); rowOne[0] = xSpacing; rowOne[3] = xOrigin; std::vector rowTwo(4, 0.0); rowTwo[1] = ySpacing; rowTwo[3] = yOrigin; std::vector rowThree(4, 0.0); rowThree[2] = zSpacing; rowThree[3] = zOrigin; std::vector rowFour(4, 0.0); rowFour[3] = 1.0; std::vector > indexToSpace; indexToSpace.push_back(rowOne); indexToSpace.push_back(rowTwo); indexToSpace.push_back(rowThree); indexToSpace.push_back(rowFour); m_volumeFile = new VolumeFile(dimensions, indexToSpace, 1, volumeType); m_volumeFile->setFileName(filename); m_volumeFile->setType(volumeType); s_previousVolumeSettings.m_dimensions = dimensions; s_previousVolumeSettings.m_indexToSpace = indexToSpace; s_previousVolumeSettings.m_volumeType = volumeType; s_previousVolumeSettingsValid = true; float defaultValue = 0.0; if (numMaps > 0) { switch (volumeType) { case SubvolumeAttributes::ANATOMY: break; case SubvolumeAttributes::FUNCTIONAL: break; case SubvolumeAttributes::LABEL: defaultValue = m_volumeFile->getMapLabelTable(0)->getUnassignedLabelKey(); break; case SubvolumeAttributes::RGB: CaretAssert(0); break; case SubvolumeAttributes::SEGMENTATION: break; case SubvolumeAttributes::UNKNOWN: CaretAssert(0); break; case SubvolumeAttributes::VECTOR: CaretAssert(0); break; } } m_volumeFile->setValueAllVoxels(defaultValue); m_volumeFile->updateScalarColoringForAllMaps(); for (int32_t iMap = 0; iMap < numMaps; iMap++) { CaretAssertVectorIndex(m_mapNameLineEdits, iMap); m_volumeFile->setMapName(iMap, m_mapNameLineEdits[iMap]->text().trimmed()); } WuQDialog::okButtonClicked(); } /** * Set the volume parameters from a loaded file. */ void VolumeFileCreateDialog::loadVolumeParametersFromFilePushButtonClicked() { Brain* brain = GuiManager::get()->getBrain(); std::vector allMappableFiles; brain->getAllMappableDataFiles(allMappableFiles); std::vector volumeMappableFiles; for (std::vector::iterator allIter = allMappableFiles.begin(); allIter != allMappableFiles.end(); allIter++) { CaretMappableDataFile* mapFile = *allIter; if (mapFile->isVolumeMappable()) { volumeMappableFiles.push_back(mapFile); } } const int32_t numberOfVolumeMappableFiles = static_cast(volumeMappableFiles.size()); if (numberOfVolumeMappableFiles <= 0) { WuQMessageBox::errorOk(m_paramFromFilePushButton, "No volume mappable files are loaded."); } std::vector volumeRadioButtons; WuQDataEntryDialog dialog("Select File For Volume Parameters", m_paramFromFilePushButton); for (int32_t i = 0; i < numberOfVolumeMappableFiles; i++) { CaretAssertVectorIndex(volumeMappableFiles, i); QRadioButton* rb = dialog.addRadioButton(volumeMappableFiles[i]->getFileNameNoPath()); volumeRadioButtons.push_back(rb); if (i == 0) { rb->setChecked(true); } } if (dialog.exec() == WuQDataEntryDialog::Accepted) { for (int32_t i = 0; i < numberOfVolumeMappableFiles; i++) { CaretAssertVectorIndex(volumeRadioButtons, i); if (volumeRadioButtons[i]->isChecked()) { CaretAssertVectorIndex(volumeMappableFiles, i); CaretMappableDataFile* volMapFile = volumeMappableFiles[i]; CiftiMappableDataFile* ciftiFile = dynamic_cast(volMapFile); VolumeFile* volumeFile = dynamic_cast(volMapFile); int64_t dimensions[5] = { 0, 0, 0, 0, 0 }; float origin[3] = { 0.0, 0.0, 0.0 }; float spacing[3] = { 0.0, 0.0, 0.0 }; int32_t numberOfMaps = 1; SubvolumeAttributes::VolumeType volumeType = SubvolumeAttributes::FUNCTIONAL; if (ciftiFile != NULL) { int64_t dimI, dimJ, dimK, dimTime, dimComponents; ciftiFile->getDimensions(dimI, dimJ, dimK, dimTime, dimComponents); dimensions[0] = dimI; dimensions[1] = dimJ; dimensions[2] = dimK; ciftiFile->indexToSpace(0, 0, 0, origin); float oneOneOneVoxelXYZ[3]; ciftiFile->indexToSpace(1, 1, 1, oneOneOneVoxelXYZ); spacing[0] = oneOneOneVoxelXYZ[0] - origin[0]; spacing[1] = oneOneOneVoxelXYZ[1] - origin[1]; spacing[2] = oneOneOneVoxelXYZ[2] - origin[2]; numberOfMaps = volMapFile->getNumberOfMaps(); if (volMapFile->isMappedWithLabelTable()) { volumeType = SubvolumeAttributes::LABEL; } else if (volMapFile->isMappedWithPalette()) { volumeType = SubvolumeAttributes::FUNCTIONAL; } } else if (volumeFile != NULL) { const VolumeSpace volumeSpace = volumeFile->getVolumeSpace(); const int64_t* dimArray = volumeSpace.getDims(); dimensions[0] = dimArray[0]; dimensions[1] = dimArray[1]; dimensions[2] = dimArray[2]; VolumeSpace::OrientTypes orientation[3]; volumeSpace.getOrientAndSpacingForPlumb(orientation, spacing, origin); numberOfMaps = volumeFile->getNumberOfMaps(); volumeType = volumeFile->getType(); } else { AString msg = ("Program Error: " + volMapFile->getFileNameNoPath() + " is volume mappable but neither a volume nor a CIFTI file."); WuQMessageBox::errorOk(m_paramFromFilePushButton, msg); return; } const bool includeTypeAndNumberOfMapsFlag = false; if (includeTypeAndNumberOfMapsFlag) { const int typeIndex = m_newFileTypeComboBox->findData(static_cast(volumeType)); if (typeIndex >= 0) { m_newFileTypeComboBox->setCurrentIndex(typeIndex); } m_newFileNumberOfMapsSpinBox->setValue(numberOfMaps); } m_newDimXSpinBox->setValue(dimensions[0]); m_newDimYSpinBox->setValue(dimensions[1]); m_newDimZSpinBox->setValue(dimensions[2]); m_newOriginXSpinBox->setValue(origin[0]); m_newOriginYSpinBox->setValue(origin[1]); m_newOriginZSpinBox->setValue(origin[2]); m_newSpacingXSpinBox->setValue(spacing[0]); m_newSpacingYSpinBox->setValue(spacing[1]); m_newSpacingZSpinBox->setValue(spacing[2]); break; } } } } connectome-workbench-1.4.2/src/GuiQt/VolumeFileCreateDialog.h000066400000000000000000000071521360521144700241440ustar00rootroot00000000000000#ifndef __VOLUME_FILE_CREATE_DIALOG_H__ #define __VOLUME_FILE_CREATE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "VolumeFile.h" #include "WuQDialogModal.h" class QComboBox; class QDoubleSpinBox; class QLabel; class QLineEdit; class QPushButton; class QSpinBox; namespace caret { class VolumeFileCreateDialog : public WuQDialogModal { Q_OBJECT public: VolumeFileCreateDialog(QWidget* parent); virtual ~VolumeFileCreateDialog(); VolumeFile* getVolumeFile(); // ADD_NEW_METHODS_HERE private slots: void newFileNamePushButtonClicked(); void loadVolumeParametersFromFilePushButtonClicked(); void numberOfMapsSpinBoxValueChanged(int); protected: virtual void okButtonClicked(); private: VolumeFileCreateDialog(const VolumeFileCreateDialog&); VolumeFileCreateDialog& operator=(const VolumeFileCreateDialog&); struct PreviousVolumeSettings { std::vector m_dimensions; std::vector > m_indexToSpace; SubvolumeAttributes::VolumeType m_volumeType; }; QWidget* createNewVolumeFileWidget(); QWidget* addMapToVolumeFileWidget(); QLineEdit* m_newFileNameLineEdit; QComboBox* m_newFileTypeComboBox; QSpinBox* m_newFileNumberOfMapsSpinBox; std::vector m_mapNameLabels; std::vector m_mapNameLineEdits; QSpinBox* m_newDimXSpinBox; QSpinBox* m_newDimYSpinBox; QSpinBox* m_newDimZSpinBox; QDoubleSpinBox* m_newSpacingXSpinBox; QDoubleSpinBox* m_newSpacingYSpinBox; QDoubleSpinBox* m_newSpacingZSpinBox; QDoubleSpinBox* m_newOriginXSpinBox; QDoubleSpinBox* m_newOriginYSpinBox; QDoubleSpinBox* m_newOriginZSpinBox; QPushButton* m_paramFromFilePushButton; VolumeFile* m_volumeFile; static int32_t s_maximumNumberOfMaps; static int32_t s_fileNameCounter; static PreviousVolumeSettings s_previousVolumeSettings; static bool s_previousVolumeSettingsValid; // ADD_NEW_MEMBERS_HERE }; #ifdef __VOLUME_FILE_CREATE_DIALOG_DECLARE__ int32_t VolumeFileCreateDialog::s_maximumNumberOfMaps = 5; int32_t VolumeFileCreateDialog::s_fileNameCounter = 1; VolumeFileCreateDialog::PreviousVolumeSettings VolumeFileCreateDialog::s_previousVolumeSettings; bool VolumeFileCreateDialog::s_previousVolumeSettingsValid = false; #endif // __VOLUME_FILE_CREATE_DIALOG_DECLARE__ } // namespace #endif //__VOLUME_FILE_CREATE_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/VolumePropertiesEditorDialog.cxx000066400000000000000000000127641360521144700260240ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __VOLUME_PROPERTIES_EDITOR_DIALOG_DECLARE__ #include "VolumePropertiesEditorDialog.h" #undef __VOLUME_PROPERTIES_EDITOR_DIALOG_DECLARE__ #include #include #include #include using namespace caret; #include "Brain.h" #include "CaretAssert.h" #include "DisplayPropertiesVolume.h" #include "GuiManager.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "SceneClass.h" #include "SceneWindowGeometry.h" #include "WuQFactory.h" #include "WuQtUtilities.h" /** * \class caret::VolumePropertiesEditorDialog * \brief Dialog for adjusting volume display properties. * \ingroup GuitQt */ /** * Constructor. */ VolumePropertiesEditorDialog::VolumePropertiesEditorDialog(QWidget* parent) : WuQDialogNonModal("Volume Properties", parent) { QLabel* opacityLabel = new QLabel("Opacity: "); m_opacitySpinBox = WuQFactory::newDoubleSpinBox(); m_opacitySpinBox->setRange(0.0, 1.0); m_opacitySpinBox->setSingleStep(0.1); m_opacitySpinBox->setDecimals(2); QObject::connect(m_opacitySpinBox, SIGNAL(valueChanged(double)), this, SLOT(displayPropertyChanged())); QWidget* w = new QWidget(); QGridLayout* gridLayout = new QGridLayout(w); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 2, 2); int row = gridLayout->rowCount(); gridLayout->addWidget(opacityLabel, row, 0); gridLayout->addWidget(m_opacitySpinBox, row, 1); row++; setCentralWidget(w, WuQDialog::SCROLL_AREA_NEVER); updateDialog(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); /* * No apply button */ setApplyButtonText(""); } /** * Destructor. */ VolumePropertiesEditorDialog::~VolumePropertiesEditorDialog() { EventManager::get()->removeAllEventsFromListener(this); } /** * Called when a display property is changed. */ void VolumePropertiesEditorDialog::displayPropertyChanged() { DisplayPropertiesVolume* dps = GuiManager::get()->getBrain()->getDisplayPropertiesVolume(); dps->setOpacity(m_opacitySpinBox->value()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } /** * Update the properties editor. */ void VolumePropertiesEditorDialog::updateDialog() { const DisplayPropertiesVolume* dpv = GuiManager::get()->getBrain()->getDisplayPropertiesVolume(); QSignalBlocker blocker(m_opacitySpinBox); m_opacitySpinBox->setValue(dpv->getOpacity()); } /** * Receive events from the event manager. * * @param event * Event sent by event manager. */ void VolumePropertiesEditorDialog::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { CaretAssert(dynamic_cast(event) != NULL); updateDialog(); } } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* VolumePropertiesEditorDialog::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "VolumePropertiesEditorDialog", 1); /* * Position and size */ SceneWindowGeometry swg(this); sceneClass->addClass(swg.saveToScene(sceneAttributes, "geometry")); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void VolumePropertiesEditorDialog::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } /* * Position and size */ SceneWindowGeometry swg(this); swg.restoreFromScene(sceneAttributes, sceneClass->getClass("geometry")); } connectome-workbench-1.4.2/src/GuiQt/VolumePropertiesEditorDialog.h000066400000000000000000000044341360521144700254440ustar00rootroot00000000000000#ifndef __VOLUME_PROPERTIES_EDITOR_DIALOG__H_ #define __VOLUME_PROPERTIES_EDITOR_DIALOG__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "EventListenerInterface.h" #include "SceneableInterface.h" #include "WuQDialogNonModal.h" class QDoubleSpinBox; namespace caret { class VolumePropertiesEditorDialog : public WuQDialogNonModal, public EventListenerInterface, public SceneableInterface { Q_OBJECT public: VolumePropertiesEditorDialog(QWidget* parent = 0); virtual ~VolumePropertiesEditorDialog(); void receiveEvent(Event* event); void updateDialog(); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); private slots: void displayPropertyChanged(); private: VolumePropertiesEditorDialog(const VolumePropertiesEditorDialog&); VolumePropertiesEditorDialog& operator=(const VolumePropertiesEditorDialog&); QDoubleSpinBox* m_opacitySpinBox; // ADD_NEW_MEMBERS_HERE }; #ifdef __VOLUME_PROPERTIES_EDITOR_DIALOG_DECLARE__ // #endif // __VOLUME_PROPERTIES_EDITOR_DIALOG_DECLARE__ } // namespace #endif //__VOLUME_PROPERTIES_EDITOR_DIALOG__H_ connectome-workbench-1.4.2/src/GuiQt/VolumeSurfaceOutlineColorOrTabViewController.cxx000066400000000000000000000070711360521144700311520ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __VOLUME_SURFACE_OUTLINE_COLOR_OR_TAB_VIEW_CONTROLLER_DECLARE__ #include "VolumeSurfaceOutlineColorOrTabViewController.h" #undef __VOLUME_SURFACE_OUTLINE_COLOR_OR_TAB_VIEW_CONTROLLER_DECLARE__ #include #include "WuQFactory.h" using namespace caret; /** * \class caret::VolumeSurfaceOutlineColorOrTabViewController * \brief View Controller for VolumeSurfaceOutlineColorOrTabModel * */ /** * Constructor. */ VolumeSurfaceOutlineColorOrTabViewController::VolumeSurfaceOutlineColorOrTabViewController(QObject* parent) : WuQWidget(parent) { this->colorOrTabModel = NULL; this->modelComboBox = WuQFactory::newComboBox(); QObject::connect(this->modelComboBox, SIGNAL(activated(int)), this, SLOT(itemActivated(int))); } /** * Destructor. */ VolumeSurfaceOutlineColorOrTabViewController::~VolumeSurfaceOutlineColorOrTabViewController() { } /** * Update this view controller. */ void VolumeSurfaceOutlineColorOrTabViewController::updateViewController(VolumeSurfaceOutlineColorOrTabModel* model) { this->colorOrTabModel = model; this->modelComboBox->blockSignals(true); this->modelComboBox->clear(); VolumeSurfaceOutlineColorOrTabModel::Item* selectedItem = this->colorOrTabModel->getSelectedItem(); int32_t selectedItemIndex = -1; std::vector validItems = this->colorOrTabModel->getValidItems(); const int32_t numItems = static_cast(validItems.size()); for (int32_t i = 0; i < numItems; i++) { VolumeSurfaceOutlineColorOrTabModel::Item* item = validItems[i]; if (selectedItem == item) { selectedItemIndex = i; } this->modelComboBox->addItem(item->getName(), qVariantFromValue((void*)item)); } if (selectedItemIndex >= 0) { this->modelComboBox->setCurrentIndex(selectedItemIndex); } this->modelComboBox->blockSignals(false); } /** * @return The widget for this view controller. */ QWidget* VolumeSurfaceOutlineColorOrTabViewController::getWidget() { return this->modelComboBox; } /** * Called when the user selects an item. * @param indx * Index of item selected by the user. */ void VolumeSurfaceOutlineColorOrTabViewController::itemActivated(int indx) { if (this->colorOrTabModel == NULL) { return; } if (indx >= 0) { void* pointer = this->modelComboBox->itemData(indx).value(); VolumeSurfaceOutlineColorOrTabModel::Item* item = (VolumeSurfaceOutlineColorOrTabModel::Item*)pointer; this->colorOrTabModel->setSelectedItem(item); emit modelSelected(item); } } connectome-workbench-1.4.2/src/GuiQt/VolumeSurfaceOutlineColorOrTabViewController.h000066400000000000000000000046261360521144700306020ustar00rootroot00000000000000#ifndef __VOLUME_SURFACE_OUTLINE_COLOR_OR_TAB_VIEW_CONTROLLER__H_ #define __VOLUME_SURFACE_OUTLINE_COLOR_OR_TAB_VIEW_CONTROLLER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "VolumeSurfaceOutlineColorOrTabModel.h" #include "WuQWidget.h" class QComboBox; namespace caret { class VolumeSurfaceOutlineColorOrTabModel; class VolumeSurfaceOutlineColorOrTabViewController : public WuQWidget { Q_OBJECT public: VolumeSurfaceOutlineColorOrTabViewController(QObject* parent); virtual ~VolumeSurfaceOutlineColorOrTabViewController(); QWidget* getWidget(); void updateViewController(VolumeSurfaceOutlineColorOrTabModel* model); signals: /** * Emitted when the user selects a model. * @param pointer to model selected. */ void modelSelected(VolumeSurfaceOutlineColorOrTabModel::Item*); private slots: void itemActivated(int indx); private: VolumeSurfaceOutlineColorOrTabViewController(const VolumeSurfaceOutlineColorOrTabViewController&); VolumeSurfaceOutlineColorOrTabViewController& operator=(const VolumeSurfaceOutlineColorOrTabViewController&); QComboBox* modelComboBox; VolumeSurfaceOutlineColorOrTabModel* colorOrTabModel; }; #ifdef __VOLUME_SURFACE_OUTLINE_COLOR_OR_TAB_VIEW_CONTROLLER_DECLARE__ // #endif // __VOLUME_SURFACE_OUTLINE_COLOR_OR_TAB_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__VOLUME_SURFACE_OUTLINE_COLOR_OR_TAB_VIEW_CONTROLLER__H_ connectome-workbench-1.4.2/src/GuiQt/VolumeSurfaceOutlineSetViewController.cxx000066400000000000000000000214071360521144700276760ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #define __VOLUME_SURFACE_OUTLINE_SET_VIEW_CONTROLLER_DECLARE__ #include "VolumeSurfaceOutlineSetViewController.h" #undef __VOLUME_SURFACE_OUTLINE_SET_VIEW_CONTROLLER_DECLARE__ #include "BrowserTabContent.h" #include "CaretAssert.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "VolumeSurfaceOutlineSetModel.h" #include "VolumeSurfaceOutlineViewController.h" #include "WuQFactory.h" #include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::VolumeSurfaceOutlineSetViewController * \brief View Controller for VolumeSurfaceOutlineSetModel */ /** * Constructor. * * @param orientation * Orientation for layout * @param browserWindowIndex * Index of browser window that contains this view controller. * @param parentObjectNamePrefix * Name of parent object for macros * @param descriptivePrefix * Descriptive prefix for macros * @param parent * Parent widget. */ VolumeSurfaceOutlineSetViewController::VolumeSurfaceOutlineSetViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, const QString& parentObjectNamePrefix, const QString& descriptivePrefix, QWidget* parent) : QWidget(parent) { this->browserWindowIndex = browserWindowIndex; QWidget* gridWidget = new QWidget(); QGridLayout* gridLayout = new QGridLayout(gridWidget); WuQtUtilities::setLayoutSpacingAndMargins(gridLayout, 4, 2); if (orientation == Qt::Horizontal) { gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 0); gridLayout->setColumnStretch(2, 0); gridLayout->setColumnStretch(3, 100); QLabel* onLabel = new QLabel("On"); QLabel* colorLabel = new QLabel("Color Source"); QLabel* thicknessLabel = new QLabel("Thickness"); QLabel* fileLabel = new QLabel("File"); const int row = gridLayout->rowCount(); gridLayout->addWidget(onLabel, row, 0, Qt::AlignHCenter); gridLayout->addWidget(colorLabel, row, 1, Qt::AlignHCenter); gridLayout->addWidget(thicknessLabel, row, 2, Qt::AlignHCenter); gridLayout->addWidget(fileLabel, row, 3, Qt::AlignHCenter); } else { gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 0); gridLayout->setColumnStretch(2, 100); } for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES; i++) { const QString name = QString(parentObjectNamePrefix + ":VolumeSurfaceOutline%1").arg((int)(i + 1), 2, 10, QLatin1Char('0')); VolumeSurfaceOutlineViewController* ovc = new VolumeSurfaceOutlineViewController(orientation, gridLayout, name, descriptivePrefix + " " + QString::number(i + 1)); this->outlineViewControllers.push_back(ovc); } QLabel* outlineCountLabel = new QLabel("Number of Outlines: "); this->outlineCountSpinBox = WuQFactory::newSpinBox(); this->outlineCountSpinBox->setRange(BrainConstants::MINIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES, BrainConstants::MAXIMUM_NUMBER_OF_VOLUME_SURFACE_OUTLINES); this->outlineCountSpinBox->setSingleStep(1); QObject::connect(this->outlineCountSpinBox, SIGNAL(valueChanged(int)), this, SLOT(outlineCountSpinBoxValueChanged(int))); this->outlineCountSpinBox->setObjectName(parentObjectNamePrefix + ":VolumeSurfaceOutlineNumberOfOutlines"); this->outlineCountSpinBox->setToolTip("Number of volume surface outlines"); WuQMacroManager::instance()->addMacroSupportToObject(this->outlineCountSpinBox, "Set number of displayed volume/surface outlines for " + descriptivePrefix); QHBoxLayout* overlayCountLayout = new QHBoxLayout(); overlayCountLayout->addWidget(outlineCountLabel); overlayCountLayout->addWidget(this->outlineCountSpinBox); overlayCountLayout->addStretch(); QVBoxLayout* layout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); layout->addWidget(gridWidget); layout->addLayout(overlayCountLayout); layout->addStretch(); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); } /** * Destructor. */ VolumeSurfaceOutlineSetViewController::~VolumeSurfaceOutlineSetViewController() { EventManager::get()->removeAllEventsFromListener(this); for (size_t i = 0; i < outlineViewControllers.size(); ++i) { delete outlineViewControllers[i]; } } /** * Called when outline count spin box value changed. * @param value * New value. */ void VolumeSurfaceOutlineSetViewController::outlineCountSpinBoxValueChanged(int value) { VolumeSurfaceOutlineSetModel* outlineSet = this->getOutlineSet(); if (outlineSet != NULL) { outlineSet->setNumberOfDisplayedVolumeSurfaceOutlines(value); this->updateViewController(); } } /** * @return The outline set in this view controller. */ VolumeSurfaceOutlineSetModel* VolumeSurfaceOutlineSetViewController::getOutlineSet() { VolumeSurfaceOutlineSetModel* outlineSet = NULL; BrowserTabContent* browserTabContent = GuiManager::get()->getBrowserTabContentForBrowserWindow(this->browserWindowIndex, true); if (browserTabContent != NULL) { outlineSet = browserTabContent->getVolumeSurfaceOutlineSet(); } return outlineSet; } /** * Update this overlay set view controller using the given overlay set. */ void VolumeSurfaceOutlineSetViewController::updateViewController() { VolumeSurfaceOutlineSetModel* outlineSet = this->getOutlineSet(); if (outlineSet == NULL) { return; } const int32_t numberOfOutlines = static_cast(this->outlineViewControllers.size()); const int32_t numberOfDisplayedOutline = outlineSet->getNumberOfDislayedVolumeSurfaceOutlines(); this->outlineCountSpinBox->blockSignals(true); this->outlineCountSpinBox->setValue(numberOfDisplayedOutline); this->outlineCountSpinBox->blockSignals(false); for (int32_t i = 0; i < numberOfOutlines; i++) { VolumeSurfaceOutlineModel* outlineModel = NULL; if (outlineSet != NULL) { outlineModel = outlineSet->getVolumeSurfaceOutlineModel(i); } this->outlineViewControllers[i]->updateViewController(outlineModel); bool displayOutline = (outlineModel != NULL); if (i >= numberOfDisplayedOutline) { displayOutline = false; } this->outlineViewControllers[i]->setVisible(displayOutline); } } /** * Receive events from the event manager. * * @param event * Event sent by event manager. */ void VolumeSurfaceOutlineSetViewController::receiveEvent(Event* event) { if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { EventUserInterfaceUpdate* uiEvent = dynamic_cast(event); CaretAssert(uiEvent); if (uiEvent->isUpdateForWindow(this->browserWindowIndex)) { if (uiEvent->isSurfaceUpdate() || uiEvent->isToolBoxUpdate()) { this->updateViewController(); uiEvent->setEventProcessed(); } } } } connectome-workbench-1.4.2/src/GuiQt/VolumeSurfaceOutlineSetViewController.h000066400000000000000000000051521360521144700273220ustar00rootroot00000000000000#ifndef __VOLUME_SURFACE_OUTLINE_SET_VIEW_CONTROLLER__H_ #define __VOLUME_SURFACE_OUTLINE_SET_VIEW_CONTROLLER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "EventListenerInterface.h" class QSpinBox; namespace caret { class VolumeSurfaceOutlineSetModel; class VolumeSurfaceOutlineViewController; class VolumeSurfaceOutlineSetViewController : public QWidget, public EventListenerInterface { Q_OBJECT public: VolumeSurfaceOutlineSetViewController(const Qt::Orientation orientation, const int32_t browserWindowIndex, const QString& parentObjectNamePrefix, const QString& descriptivePrefix, QWidget* parent = 0); virtual ~VolumeSurfaceOutlineSetViewController(); void receiveEvent(Event* event); private slots: void outlineCountSpinBoxValueChanged(int); private: VolumeSurfaceOutlineSetViewController(const VolumeSurfaceOutlineSetViewController&); VolumeSurfaceOutlineSetViewController& operator=(const VolumeSurfaceOutlineSetViewController&); VolumeSurfaceOutlineSetModel* getOutlineSet(); void updateViewController(); QSpinBox* outlineCountSpinBox; int32_t browserWindowIndex; std::vector outlineViewControllers; }; #ifdef __VOLUME_SURFACE_OUTLINE_SET_VIEW_CONTROLLER_DECLARE__ // #endif // __VOLUME_SURFACE_OUTLINE_SET_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__VOLUME_SURFACE_OUTLINE_SET_VIEW_CONTROLLER__H_ connectome-workbench-1.4.2/src/GuiQt/VolumeSurfaceOutlineViewController.cxx000066400000000000000000000234311360521144700272210ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #define __VOLUME_SURFACE_OUTLINE_VIEW_CONTROLLER_DECLARE__ #include "VolumeSurfaceOutlineViewController.h" #undef __VOLUME_SURFACE_OUTLINE_VIEW_CONTROLLER_DECLARE__ #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "SurfaceSelectionModel.h" #include "SurfaceSelectionViewController.h" #include "VolumeSurfaceOutlineColorOrTabViewController.h" #include "VolumeSurfaceOutlineModel.h" #include "WuQDoubleSpinBox.h" #include "WuQFactory.h" #include "WuQGridLayoutGroup.h" #include "WuQMacroManager.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::VolumeSurfaceOutlineViewController * \brief View controller for volume surface outline * */ /** * Constructor. * * @param orientation * Orientation for controller * @param gridLayout * Layout for widgets * @param objectNamePrefix * Object name prefix for macros * @param descriptivePrefix * Descriptive name prefix for macros */ VolumeSurfaceOutlineViewController::VolumeSurfaceOutlineViewController(const Qt::Orientation orientation, QGridLayout* gridLayout, const QString& objectNamePrefix, const QString& descriptivePrefix, QObject* parent) : QObject(parent) { WuQMacroManager* macroManager = WuQMacroManager::instance(); this->outlineModel = NULL; this->enabledCheckBox = new QCheckBox(" "); QObject::connect(this->enabledCheckBox, &QCheckBox::clicked, this, &VolumeSurfaceOutlineViewController::enabledCheckBoxChecked); this->enabledCheckBox->setToolTip("Enables display of this volume surface outline"); this->enabledCheckBox->setObjectName(objectNamePrefix + ":Enable"); macroManager->addMacroSupportToObject(this->enabledCheckBox, "Enable volume surface outline for " + descriptivePrefix); this->surfaceSelectionViewController = new SurfaceSelectionViewController(this, (objectNamePrefix + ":Surface"), "Select volume surface outline surface for " + descriptivePrefix); QObject::connect(this->surfaceSelectionViewController, SIGNAL(surfaceSelected(Surface*)), this, SLOT(surfaceSelected(Surface*))); this->surfaceSelectionViewController->getWidget()->setToolTip("Select surface drawn as outline over volume slices"); this->colorOrTabSelectionControl = new VolumeSurfaceOutlineColorOrTabViewController(this); QObject::connect(this->colorOrTabSelectionControl, SIGNAL(modelSelected(VolumeSurfaceOutlineColorOrTabModel::Item*)), this, SLOT(colorTabSelected(VolumeSurfaceOutlineColorOrTabModel::Item*))); this->colorOrTabSelectionControl->getWidget()->setToolTip("Select coloring for surface outline.\n" "If tab, coloring assigned to selected surface\n" "in the selected tab is used.\n"); this->colorOrTabSelectionControl->getWidget()->setObjectName(objectNamePrefix + ":ColorSource"); macroManager->addMacroSupportToObject(this->colorOrTabSelectionControl->getWidget(), "Set surface outline color for " + descriptivePrefix); this->thicknessSpinBox = new WuQDoubleSpinBox(this); this->thicknessSpinBox->setRange(0.0, 100.0); this->thicknessSpinBox->setSingleStep(0.10); this->thicknessSpinBox->setSuffix("%"); QObject::connect(this->thicknessSpinBox, static_cast(&WuQDoubleSpinBox::valueChanged), this, &VolumeSurfaceOutlineViewController::thicknessSpinBoxValueChanged); this->thicknessSpinBox->getWidget()->setToolTip("Thickness of surface outline as percentage of viewport height"); this->thicknessSpinBox->getWidget()->setObjectName(objectNamePrefix + ":Thickness"); macroManager->addMacroSupportToObject(this->thicknessSpinBox->getWidget(), "Set thickness for volume surface outline for " + descriptivePrefix); if (orientation == Qt::Horizontal) { this->gridLayoutGroup = new WuQGridLayoutGroup(gridLayout, this); int row = this->gridLayoutGroup->rowCount(); this->gridLayoutGroup->addWidget(this->enabledCheckBox, row, 0); this->gridLayoutGroup->addWidget(this->colorOrTabSelectionControl->getWidget(), row, 1); this->gridLayoutGroup->addWidget(this->thicknessSpinBox->getWidget(), row, 2); this->gridLayoutGroup->addWidget(this->surfaceSelectionViewController->getWidget(), row, 3); } else { QFrame* bottomHorizontalLineWidget = new QFrame(); bottomHorizontalLineWidget->setLineWidth(0); bottomHorizontalLineWidget->setMidLineWidth(1); bottomHorizontalLineWidget->setFrameStyle(QFrame::HLine | QFrame::Raised); this->gridLayoutGroup = new WuQGridLayoutGroup(gridLayout, this); int row = this->gridLayoutGroup->rowCount(); this->gridLayoutGroup->addWidget(this->enabledCheckBox, row, 0, 2, 1, Qt::AlignCenter); this->gridLayoutGroup->addWidget(this->surfaceSelectionViewController->getWidget(), row, 1, 1, 2); row++; this->gridLayoutGroup->addWidget(this->colorOrTabSelectionControl->getWidget(), row, 1); this->gridLayoutGroup->addWidget(this->thicknessSpinBox->getWidget(), row, 2, Qt::AlignLeft); row++; this->gridLayoutGroup->addWidget(bottomHorizontalLineWidget, row, 0, 1, -1); } } /** * Destructor. */ VolumeSurfaceOutlineViewController::~VolumeSurfaceOutlineViewController() { } /** * Set the visibility of widgets in this view controller. */ void VolumeSurfaceOutlineViewController::setVisible(bool visible) { this->gridLayoutGroup->setVisible(visible); } /** * Called when a surface is selected. * @param surface * Surface that was selected. */ void VolumeSurfaceOutlineViewController::surfaceSelected(Surface* surface) { if (this->outlineModel != NULL) { this->outlineModel->getSurfaceSelectionModel()->setSurface(surface); } this->updateGraphics(); } /** * Called when a color/tab is selected. * @param colorTab * Value that was selected. */ void VolumeSurfaceOutlineViewController::colorTabSelected(VolumeSurfaceOutlineColorOrTabModel::Item* /*colorTab*/) { this->updateGraphics(); } /** * Called when enabled checkbox is selected. * @param checked * New state of checkbox. */ void VolumeSurfaceOutlineViewController::enabledCheckBoxChecked(bool checked) { if (this->outlineModel != NULL) { this->outlineModel->setDisplayed(checked); } this->updateGraphics(); } /** * Called when thickness value is changed. * @param value * Value that was selected. */ void VolumeSurfaceOutlineViewController::thicknessSpinBoxValueChanged(double value) { if (this->outlineModel != NULL) { this->outlineModel->setThicknessPercentageViewportHeight(value); } this->updateGraphics(); } /** * Update this view controller. * @param outlineModel * Outline model for use in this view controller. */ void VolumeSurfaceOutlineViewController::updateViewController(VolumeSurfaceOutlineModel* outlineModel) { this->outlineModel = outlineModel; if (this->outlineModel != NULL) { this->enabledCheckBox->setChecked(this->outlineModel->isDisplayed()); this->thicknessSpinBox->blockSignals(true); float thickness = outlineModel->getThicknessPercentageViewportHeight(); if (thickness < 0.0f) { /* old scenes will have negative for mm thickness */ thickness = VolumeSurfaceOutlineModel::DEFAULT_LINE_THICKNESS_PERCENTAGE_VIEWPORT_HEIGHT; } this->thicknessSpinBox->setValue(thickness); this->thicknessSpinBox->blockSignals(false); this->surfaceSelectionViewController->updateControl(outlineModel->getSurfaceSelectionModel()); this->colorOrTabSelectionControl->updateViewController(outlineModel->getColorOrTabModel()); } } /** * Update the graphics. */ void VolumeSurfaceOutlineViewController::updateGraphics() { EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } connectome-workbench-1.4.2/src/GuiQt/VolumeSurfaceOutlineViewController.h000066400000000000000000000060321360521144700266440ustar00rootroot00000000000000#ifndef __VOLUME_SURFACE_OUTLINE_VIEW_CONTROLLER__H_ #define __VOLUME_SURFACE_OUTLINE_VIEW_CONTROLLER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "VolumeSurfaceOutlineColorOrTabModel.h" class QCheckBox; class QGridLayout; namespace caret { class Surface; class SurfaceSelectionViewController; class VolumeSurfaceOutlineModel; class VolumeSurfaceOutlineColorOrTabViewController; class WuQDoubleSpinBox; class WuQGridLayoutGroup; class VolumeSurfaceOutlineViewController : public QObject { Q_OBJECT public: VolumeSurfaceOutlineViewController(const Qt::Orientation orientation, QGridLayout* gridLayout, const QString& objectNamePrefix, const QString& descriptivePrefix, QObject* parent = 0); virtual ~VolumeSurfaceOutlineViewController(); void setVisible(bool visible); void updateViewController(VolumeSurfaceOutlineModel* outlineModel); private slots: void enabledCheckBoxChecked(bool checked); void thicknessSpinBoxValueChanged(double); void surfaceSelected(Surface*); void colorTabSelected(VolumeSurfaceOutlineColorOrTabModel::Item*); private: VolumeSurfaceOutlineViewController(const VolumeSurfaceOutlineViewController&); VolumeSurfaceOutlineViewController& operator=(const VolumeSurfaceOutlineViewController&); void updateGraphics(); VolumeSurfaceOutlineModel* outlineModel; WuQGridLayoutGroup* gridLayoutGroup; QCheckBox* enabledCheckBox; VolumeSurfaceOutlineColorOrTabViewController* colorOrTabSelectionControl; WuQDoubleSpinBox* thicknessSpinBox; SurfaceSelectionViewController* surfaceSelectionViewController; }; #ifdef __VOLUME_SURFACE_OUTLINE_VIEW_CONTROLLER_DECLARE__ // #endif // __VOLUME_SURFACE_OUTLINE_VIEW_CONTROLLER_DECLARE__ } // namespace #endif //__VOLUME_SURFACE_OUTLINE_VIEW_CONTROLLER__H_ connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomDataInfo.cxx000066400000000000000000000073241360521144700243400ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WB_MACRO_CUSTOM_DATA_INFO_DECLARE__ #include "WbMacroCustomDataInfo.h" #undef __WB_MACRO_CUSTOM_DATA_INFO_DECLARE__ #include #include "CaretAssert.h" using namespace caret; /** * \class caret::WbMacroCustomDataInfo * \brief Information about custom data such as valid data range * \ingroup GuiQt */ /** * Constructor. */ WbMacroCustomDataInfo::WbMacroCustomDataInfo(const WuQMacroDataValueTypeEnum::Enum dataType) : CaretObject(), m_dataType(dataType) { m_integerRange[0] = std::numeric_limits::min(); m_integerRange[1] = std::numeric_limits::max(); m_floatRange[0] = -std::numeric_limits::max(); m_floatRange[1] = std::numeric_limits::max(); } /** * Destructor. */ WbMacroCustomDataInfo::~WbMacroCustomDataInfo() { } /** * Copy constructor. * @param obj * Object that is copied. */ WbMacroCustomDataInfo::WbMacroCustomDataInfo(const WbMacroCustomDataInfo& obj) : CaretObject(obj) { this->copyHelperWbMacroCustomDataInfo(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ WbMacroCustomDataInfo& WbMacroCustomDataInfo::operator=(const WbMacroCustomDataInfo& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperWbMacroCustomDataInfo(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void WbMacroCustomDataInfo::copyHelperWbMacroCustomDataInfo(const WbMacroCustomDataInfo& obj) { m_dataType = obj.m_dataType; m_floatRange = obj.m_floatRange; m_integerRange = obj.m_integerRange; m_stringListValues = obj.m_stringListValues; } /** * @return The data type */ WuQMacroDataValueTypeEnum::Enum WbMacroCustomDataInfo::getDataType() const { return m_dataType; } /** * @return Range for float data */ std::array WbMacroCustomDataInfo::getFloatRange() const { return m_floatRange; } /** * Set the range of float data * * @param range * Range of the float data */ void WbMacroCustomDataInfo::setFloatRange(const std::array& range) { m_floatRange = range; } /** * @return Range for integer data */ std::array WbMacroCustomDataInfo::getIntegerRange() const { return m_integerRange; } /** * Set the range of integer data * * @param range * Range of the integer data */ void WbMacroCustomDataInfo::setIntegerRange(const std::array& range) { m_integerRange = range; } /** * @return List of string values */ std::vector WbMacroCustomDataInfo::getStringListValues() const { return m_stringListValues; } /** * Set the list of string values * * @param range * List of string values */ void WbMacroCustomDataInfo::setStringListValues(const std::vector& values) { m_stringListValues = values; } connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomDataInfo.h000066400000000000000000000046711360521144700237670ustar00rootroot00000000000000#ifndef __WB_MACRO_CUSTOM_DATA_INFO_H__ #define __WB_MACRO_CUSTOM_DATA_INFO_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretObject.h" #include "WuQMacroDataValueTypeEnum.h" namespace caret { class WbMacroCustomDataInfo : public CaretObject { public: WbMacroCustomDataInfo(const WuQMacroDataValueTypeEnum::Enum dataType); virtual ~WbMacroCustomDataInfo(); WbMacroCustomDataInfo(const WbMacroCustomDataInfo& obj); WbMacroCustomDataInfo& operator=(const WbMacroCustomDataInfo& obj); WuQMacroDataValueTypeEnum::Enum getDataType() const; std::array getFloatRange() const; void setFloatRange(const std::array& range); std::array getIntegerRange() const; void setIntegerRange(const std::array& range); std::vector getStringListValues() const; void setStringListValues(const std::vector& values); // ADD_NEW_METHODS_HERE private: void copyHelperWbMacroCustomDataInfo(const WbMacroCustomDataInfo& obj); WuQMacroDataValueTypeEnum::Enum m_dataType; std::array m_floatRange; std::array m_integerRange; std::vector m_stringListValues; // ADD_NEW_MEMBERS_HERE }; #ifdef __WB_MACRO_CUSTOM_DATA_INFO_DECLARE__ // #endif // __WB_MACRO_CUSTOM_DATA_INFO_DECLARE__ } // namespace #endif //__WB_MACRO_CUSTOM_DATA_INFO_H__ connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomDataTypeEnum.cxx000066400000000000000000000263571360521144700252220ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __WB_MACRO_CUSTOM_DATA_TYPE_ENUM_DECLARE__ #include "WbMacroCustomDataTypeEnum.h" #undef __WB_MACRO_CUSTOM_DATA_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::WbMacroCustomDataTypeEnum * \brief Enumerated type for a user defined macro data type * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_WbMacroCustomDataTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void WbMacroCustomDataTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "WbMacroCustomDataTypeEnum.h" * * Instatiate: * m_WbMacroCustomDataTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_WbMacroCustomDataTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_WbMacroCustomDataTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(WbMacroCustomDataTypeEnumComboBoxItemActivated())); * * Update the selection: * m_WbMacroCustomDataTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const WbMacroCustomDataTypeEnum::Enum VARIABLE = m_WbMacroCustomDataTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ WbMacroCustomDataTypeEnum::WbMacroCustomDataTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ WbMacroCustomDataTypeEnum::~WbMacroCustomDataTypeEnum() { } /** * Initialize the enumerated metadata. */ void WbMacroCustomDataTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(WbMacroCustomDataTypeEnum(OVERLAY_INDEX, "OVERLAY_INDEX", "Overlay Index")); enumData.push_back(WbMacroCustomDataTypeEnum(OVERLAY_FILE_NAME_OR_FILE_INDEX, "OVERLAY_FILE_NAME_OR_FILE_INDEX", "Overlay File or File Index")); enumData.push_back(WbMacroCustomDataTypeEnum(OVERLAY_MAP_NAME_OR_MAP_INDEX, "OVERLAY_MAP_NAME_OR_MAP_INDEX", "Overlay Map Name or Index")); enumData.push_back(WbMacroCustomDataTypeEnum(SURFACE, "SURFACE", "Surface")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const WbMacroCustomDataTypeEnum* WbMacroCustomDataTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const WbMacroCustomDataTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WbMacroCustomDataTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const WbMacroCustomDataTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WbMacroCustomDataTypeEnum::Enum WbMacroCustomDataTypeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WbMacroCustomDataTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WbMacroCustomDataTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WbMacroCustomDataTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WbMacroCustomDataTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const WbMacroCustomDataTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WbMacroCustomDataTypeEnum::Enum WbMacroCustomDataTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WbMacroCustomDataTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WbMacroCustomDataTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WbMacroCustomDataTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t WbMacroCustomDataTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const WbMacroCustomDataTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ WbMacroCustomDataTypeEnum::Enum WbMacroCustomDataTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WbMacroCustomDataTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WbMacroCustomDataTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WbMacroCustomDataTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void WbMacroCustomDataTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WbMacroCustomDataTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(WbMacroCustomDataTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WbMacroCustomDataTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(WbMacroCustomDataTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomDataTypeEnum.h000066400000000000000000000065251360521144700246420ustar00rootroot00000000000000#ifndef __WB_MACRO_CUSTOM_DATA_TYPE_ENUM_H__ #define __WB_MACRO_CUSTOM_DATA_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class WbMacroCustomDataTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Index of an overlay */ OVERLAY_INDEX, /** Name of file in overlay or index of file */ OVERLAY_FILE_NAME_OR_FILE_INDEX, /** Name of map or index of map */ OVERLAY_MAP_NAME_OR_MAP_INDEX, /** Surface selection */ SURFACE }; ~WbMacroCustomDataTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: WbMacroCustomDataTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const WbMacroCustomDataTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __WB_MACRO_CUSTOM_DATA_TYPE_ENUM_DECLARE__ std::vector WbMacroCustomDataTypeEnum::enumData; bool WbMacroCustomDataTypeEnum::initializedFlag = false; int32_t WbMacroCustomDataTypeEnum::integerCodeCounter = 0; #endif // __WB_MACRO_CUSTOM_DATA_TYPE_ENUM_DECLARE__ } // namespace #endif //__WB_MACRO_CUSTOM_DATA_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationAnimateOverlayCrossFade.cxx000066400000000000000000000605071360521144700312500ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WB_MACRO_CUSTOM_OPERATION_ANIMATE_OVERLAY_CROSS_FADE_DECLARE__ #include "WbMacroCustomOperationAnimateOverlayCrossFade.h" #undef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_OVERLAY_CROSS_FADE_DECLARE__ #include "BrainBrowserWindow.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretMappableDataFile.h" #include "GuiManager.h" #include "Overlay.h" #include "OverlaySet.h" #include "WbMacroCustomDataTypeEnum.h" #include "WbMacroCustomOperationTypeEnum.h" #include "WuQMacroCommand.h" #include "WuQMacroCommandParameter.h" #include "WuQMacroExecutorMonitor.h" using namespace caret; /** * \class caret::WbMacroCustomOperationAnimateOverlayCrossFade * \brief Custom Macro Command for Overlay Crossfade * \ingroup GuiQt */ /** * Constructor. */ WbMacroCustomOperationAnimateOverlayCrossFade::WbMacroCustomOperationAnimateOverlayCrossFade() : WbMacroCustomOperationBase(WbMacroCustomOperationTypeEnum::ANIMATE_OVERLAY_CROSS_FADE) { } /** * Destructor. */ WbMacroCustomOperationAnimateOverlayCrossFade::~WbMacroCustomOperationAnimateOverlayCrossFade() { } /** * Get a new instance of the macro command * * @return * Pointer to command or NULL if not valid * Use getErrorMessage() for error information if NULL returned */ WuQMacroCommand* WbMacroCustomOperationAnimateOverlayCrossFade::createCommand() { WuQMacroCommand* command(NULL); const int32_t versionNumber(2); switch (versionNumber) { case 1: command = createCommandVersionOne(); break; case 2: command = createCommandVersionTwo(); break; } CaretAssert(command); return command; } /** * Get a new instance of the macro command for version one * * @return * Pointer to command or NULL if not valid * Use getErrorMessage() for error information if NULL returned */ WuQMacroCommand* WbMacroCustomOperationAnimateOverlayCrossFade::createCommandVersionOne() { const int32_t versionOne(1); const QString description("Crossfade (blend) from one overlay to another:\n" "(1) The opacity of the \"Fade to Overlay\" is set to zero;\n" "(2) The opacity of the \"Fade from Overlay\" is set to one;\n" "(3) The opacity of the \"Fade to Overlay\" increases until it is one\n" " and simultaneously, the opacity of the \"Face from Overlay\"\n" " decreases until it reaches zero.\n"); QString errorMessage; WuQMacroCommand* command = WuQMacroCommand::newInstanceCustomCommand(WbMacroCustomOperationTypeEnum::toName(getOperationType()), versionOne, "none", "Overlay CrossFade", description, 1.0, errorMessage); if (command != NULL) { command->addParameter(WuQMacroDataValueTypeEnum::INTEGER, "Fade to Overlay", (int)1); command->addParameter(WuQMacroDataValueTypeEnum::INTEGER, "Fade from Overlay", (int)2); command->addParameter(WuQMacroDataValueTypeEnum::FLOAT, "Duration (secs)", (float)10.0); } else { appendToErrorMessage(errorMessage); } return command; } /** * Get a new instance of the macro command for version two * * @return * Pointer to command or NULL if not valid * Use getErrorMessage() for error information if NULL returned */ WuQMacroCommand* WbMacroCustomOperationAnimateOverlayCrossFade::createCommandVersionTwo() { const int32_t versionTwo(2); const QString description("Crossfade (blend) from file in overlay to selected file/map:\n" "(1) A copy of the selected overlay is inserted below it; \n" "(2) Selected file/map is placed in new the overlay;\n" "(3) The opacity of selected overlay is decreased until it\n" " becomes 0.0 revealing the selected file/map;\n" "(4) The selected overlay is removed;\n" "(5) The selected file/map remains displayed in its overlay\n"); WuQMacroCommandParameter* paramSurfaceOne = new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::INTEGER, "Overlay Number", 1); paramSurfaceOne->setCustomDataType(WbMacroCustomDataTypeEnum::toName(WbMacroCustomDataTypeEnum::OVERLAY_INDEX)); WuQMacroCommandParameter* paramSurfaceTwo = new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING_LIST, "Fade to File", ""); paramSurfaceTwo->setCustomDataType(WbMacroCustomDataTypeEnum::toName(WbMacroCustomDataTypeEnum::OVERLAY_FILE_NAME_OR_FILE_INDEX)); WuQMacroCommandParameter* paramSurfaceThree = new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING_LIST, "Fade to Map", ""); paramSurfaceThree->setCustomDataType(WbMacroCustomDataTypeEnum::toName(WbMacroCustomDataTypeEnum::OVERLAY_MAP_NAME_OR_MAP_INDEX)); QString errorMessage; WuQMacroCommand* command = WuQMacroCommand::newInstanceCustomCommand(WbMacroCustomOperationTypeEnum::toName(getOperationType()), versionTwo, "none", WbMacroCustomOperationTypeEnum::toGuiName(getOperationType()), description, 1.0, errorMessage); if (command != NULL) { command->addParameter(paramSurfaceOne); command->addParameter(paramSurfaceTwo); command->addParameter(paramSurfaceThree); command->addParameter(WuQMacroDataValueTypeEnum::FLOAT, "Duration (secs)", (float)2.0); } else { appendToErrorMessage(errorMessage); } return command; } /** * Execute the macro command * * @param parent * Parent widget for any dialogs * @param executorMonitor * the macro executor monitor * @param executorOptions * the executor options * @param macroCommand * macro command to run * @return * True if command executed successfully, else false * Use getErrorMessage() for error information if false returned */ bool WbMacroCustomOperationAnimateOverlayCrossFade::executeCommand(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand) { CaretAssert(parent); CaretAssert(macroCommand); bool resultFlag(false); switch (macroCommand->getVersion()) { case 1: resultFlag = executeCommandVersionOne(parent, executorOptions, macroCommand); break; case 2: resultFlag = executeCommandVersionTwo(parent, executorMonitor, executorOptions, macroCommand); break; default: appendUnsupportedVersionToErrorMessage(macroCommand->getVersion()); break; } return resultFlag; } /** * Execute the macro command * * @param parent * Parent widget for any dialogs * @param executorMonitor * The macro executor's monitor * @param executorOptions * The executor options, * @param macroCommand * macro command to run * @return * True if command executed successfully, else false * Use getErrorMessage() for error information if false returned */ bool WbMacroCustomOperationAnimateOverlayCrossFade::executeCommandVersionTwo(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand) { CaretAssert(parent); CaretAssert(macroCommand); if ( ! validateCorrectNumberOfParameters(macroCommand, 4)) { return false; } /* * Get overlay indices and subtract one from them since they stat at 1 */ const int32_t overlayIndex(macroCommand->getParameterAtIndex(0)->getValue().toInt() - 1); const QString mapFileName(macroCommand->getParameterAtIndex(1)->getValue().toString()); const QString mapName(macroCommand->getParameterAtIndex(2)->getValue().toString()); const float durationSeconds(macroCommand->getParameterAtIndex(3)->getValue().toFloat()); BrainBrowserWindow* bbw = qobject_cast(parent); if (bbw == NULL) { appendToErrorMessage("Parent for running surface macro is not a browser window"); return false; } BrowserTabContent* tabContent = bbw->getBrowserTabContent(); if (tabContent == NULL) { appendToErrorMessage("No tab is selected in browser window"); return false; } Model* model = tabContent->getModelForDisplay(); if (model == NULL) { appendToErrorMessage("No model is displayed"); return false; } bool validModelTypeFlag(false); switch (model->getModelType()) { case ModelTypeEnum::MODEL_TYPE_CHART: case ModelTypeEnum::MODEL_TYPE_CHART_TWO: case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: validModelTypeFlag = true; break; } if ( ! validModelTypeFlag) { appendToErrorMessage("For Overlay CrossFace, model must be a brain model"); return false; } OverlaySet* overlaySet = tabContent->getOverlaySet(); CaretAssert(overlaySet); const int32_t numberOfOverlays = overlaySet->getNumberOfDisplayedOverlays(); if ((overlayIndex < 0) || (overlayIndex >= numberOfOverlays)) { appendToErrorMessage("Overlay index is invalid."); } if (overlayIndex == (BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS - 1)) { appendToErrorMessage("Selected overlay cannot be the last (bottom-most) overlay"); } if (mapFileName.isEmpty()) { appendToErrorMessage("Map File Name is empty."); } if (mapName.isEmpty()) { appendToErrorMessage("Map Name is empty."); } if ( ! getErrorMessage().isEmpty()) { return false; } Overlay* overlay = overlaySet->getOverlay(overlayIndex); if ( ! overlay->isEnabled()) { overlay->setEnabled(true); } std::vector mapFiles; CaretMappableDataFile* selectedMapFile(NULL); int32_t selectedMapIndex(-1); overlay->getSelectionData(mapFiles, selectedMapFile, selectedMapIndex); CaretMappableDataFile* fadeToMapFile(NULL); for (auto mf : mapFiles) { if (mf->getFileName().endsWith(mapFileName)) { fadeToMapFile = mf; break; } } if (fadeToMapFile == NULL) { appendToErrorMessage("Unable to find data file with name " + mapFileName); return false; } int32_t fadeToMapIndex(-1); const int32_t numMaps = fadeToMapFile->getNumberOfMaps(); for (int32_t i = 0; i < numMaps; i++) { if (mapName == fadeToMapFile->getMapName(i)) { fadeToMapIndex = i; break; } } if (fadeToMapIndex < 0) { appendToErrorMessage("Unable to find map named " + mapName); return false; } const bool successFlag = performCrossFadeVersionTwo(executorMonitor, executorOptions, overlaySet, overlayIndex, fadeToMapFile, fadeToMapIndex, durationSeconds); return successFlag; } /** * Perform crossfade version two * * @param executorMonitor * The macro executor's monitor * @param executorOptions * The executor options * @param overlaySet * OverlaySet for the in the tab * @param overlayIndex * Index of the overlay that fades off * @param fadeToMapFile * File that is fades on * @param fadeToMapIndex * Index of map in file that fades on * @param durationSeconds * Total duration for cross fade * @return * True if successful, else false */ bool WbMacroCustomOperationAnimateOverlayCrossFade::performCrossFadeVersionTwo(const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, OverlaySet* overlaySet, const int32_t overlayIndex, CaretMappableDataFile* fadeToMapFile, const int32_t fadeToMapIndex, const float durationSeconds) { CaretAssert(overlaySet); CaretAssert(fadeToMapFile); CaretAssert((fadeToMapIndex >= 0) && (fadeToMapIndex < fadeToMapFile->getNumberOfMaps())); /* * Insert a new overlay below the fade-from overlay */ overlaySet->insertOverlayBelow(overlayIndex); /* * Copy content of fade-from overlay to the new fade-to overlay */ Overlay* fadeFromOverlay = overlaySet->getOverlay(overlayIndex); const int32_t nextOverlayIndex = overlayIndex + 1; Overlay* fadeToOverlay = overlaySet->getOverlay(nextOverlayIndex); fadeToOverlay->copyData(fadeFromOverlay); /* * Load fade-to file and map into the new overlay */ fadeToOverlay->setSelectionData(fadeToMapFile, fadeToMapIndex); const float defaultNumberOfSteps(25.0); float numberOfSteps(0.0); float iterationSleepTime(0.0); getNumberOfStepsAndSleepTime(executorOptions, defaultNumberOfSteps, durationSeconds, numberOfSteps, iterationSleepTime); float fadeFromOpacity(fadeFromOverlay->getOpacity()); const float opacityDelta = fadeFromOpacity / numberOfSteps; fadeToOverlay->setEnabled(true); fadeFromOverlay->setEnabled(true); /* * Iterate while decreasing the opacity of the fade-from overlay */ for (int iStep = 0; iStep < numberOfSteps; iStep++) { fadeFromOverlay->setOpacity(fadeFromOpacity); updateSurfaceColoring(); updateUserInterface(); updateGraphics(); fadeFromOpacity -= opacityDelta; if (fadeFromOpacity < 0.0) { fadeFromOpacity = 0.0; } if (executorMonitor->testForStop()) { appendToErrorMessage(executorMonitor->getStoppedByUserMessage()); return false; } sleepForSecondsAtEndOfIteration(iterationSleepTime); } fadeFromOverlay->setOpacity(0.0); /* * Remove the fade-from overlay so that the fade-to overlay is visible */ overlaySet->removeDisplayedOverlay(overlayIndex); updateSurfaceColoring(); updateUserInterface(); updateGraphics(); return true; } /** * Execute the macro command * * @param parent * Parent widget for any dialogs * @param executorOptions * The executor options * @param macroCommand * macro command to run * @return * True if command executed successfully, else false * Use getErrorMessage() for error information if false returned */ bool WbMacroCustomOperationAnimateOverlayCrossFade::executeCommandVersionOne(QWidget* parent, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand) { CaretAssert(parent); CaretAssert(macroCommand); if ( ! validateCorrectNumberOfParameters(macroCommand, 3)) { return false; } /* * Get overlay indices and subtract one from them since they stat at 1 */ const int32_t fadeToOverlayIndex(macroCommand->getParameterAtIndex(0)->getValue().toInt() - 1); const int32_t fadeFromOverlayIndex(macroCommand->getParameterAtIndex(1)->getValue().toInt() - 1); const float durationSeconds(macroCommand->getParameterAtIndex(2)->getValue().toFloat()); BrainBrowserWindow* bbw = qobject_cast(parent); if (bbw == NULL) { appendToErrorMessage("Parent for running surface macro is not a browser window"); return false; } BrowserTabContent* tabContent = bbw->getBrowserTabContent(); if (tabContent == NULL) { appendToErrorMessage("No tab is selected in browser window"); return false; } Model* model = tabContent->getModelForDisplay(); if (model == NULL) { appendToErrorMessage("No model is displayed"); return false; } bool validModelTypeFlag(false); switch (model->getModelType()) { case ModelTypeEnum::MODEL_TYPE_CHART: case ModelTypeEnum::MODEL_TYPE_CHART_TWO: case ModelTypeEnum::MODEL_TYPE_INVALID: break; case ModelTypeEnum::MODEL_TYPE_SURFACE: case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: validModelTypeFlag = true; break; } if ( ! validModelTypeFlag) { appendToErrorMessage("For Overlay CrossFace, model must be a brain model"); return false; } OverlaySet* overlaySet = tabContent->getOverlaySet(); CaretAssert(overlaySet); const int32_t numberOfOverlays = overlaySet->getNumberOfDisplayedOverlays(); if ((fadeToOverlayIndex < 0) || (fadeToOverlayIndex >= numberOfOverlays)) { appendToErrorMessage("Fade To Overlay Index is not a valid overlay"); } if ((fadeFromOverlayIndex < 0) || (fadeFromOverlayIndex >= numberOfOverlays)) { appendToErrorMessage("Fade From Overlay Index is not a valid overlay"); } if ( ! getErrorMessage().isEmpty()) { return false; } Overlay* fadeToOverlay = overlaySet->getOverlay(fadeToOverlayIndex); if ( ! fadeToOverlay->isEnabled()) { appendToErrorMessage("Fade To Overlay is not enabled"); } Overlay* fadeFromOverlay = overlaySet->getOverlay(fadeFromOverlayIndex); if ( ! fadeFromOverlay->isEnabled()) { appendToErrorMessage("Fade From Overlay is not enabled"); } if ( ! getErrorMessage().isEmpty()) { return false; } CaretMappableDataFile* fadeToMapFile(NULL); int32_t fadeToMapIndex(-1); fadeToOverlay->getSelectionData(fadeToMapFile, fadeToMapIndex); if (fadeToMapFile == NULL) { appendToErrorMessage("Fade To Overlay does not contain a valid data file"); } CaretMappableDataFile* fadeFromMapFile(NULL); int32_t fadeFromMapIndex(-1); fadeToOverlay->getSelectionData(fadeFromMapFile, fadeFromMapIndex); if (fadeFromMapFile == NULL) { appendToErrorMessage("Fade From Overlay does not contain a valid data file"); } if ( ! getErrorMessage().isEmpty()) { return false; } bool successFlag = performCrossFadeVersionOne(executorOptions, fadeToOverlay, fadeFromOverlay, durationSeconds); return successFlag; } /** * Perform crossfade version one * * @param executorOptions * The executor options * @param fadeToOverlay * Overlay that starts with opacity zero and increases to one * @param fadeFromOverlay * Overlay that starts with opacity one and decreases to zero * @param durationSeconds * Total duration for cross fade * @return * True if successful, else false */ bool WbMacroCustomOperationAnimateOverlayCrossFade::performCrossFadeVersionOne(const WuQMacroExecutorOptions* executorOptions, Overlay* fadeToOverlay, Overlay* fadeFromOverlay, const float durationSeconds) { CaretAssert(fadeToOverlay); CaretAssert(fadeFromOverlay); const float defaultNumberOfSteps(25.0); float numberOfSteps(0.0); float iterationSleepTime(0.0); getNumberOfStepsAndSleepTime(executorOptions, defaultNumberOfSteps, durationSeconds, numberOfSteps, iterationSleepTime); const float opacityDelta = 1.0 / numberOfSteps; float fadeToOpacity(0.0); float fadeFromOpacity(1.0); /* * Initialize the opacities */ for (int iStep = 0; iStep < numberOfSteps; iStep++) { fadeToOverlay->setOpacity(fadeToOpacity); fadeFromOverlay->setOpacity(fadeFromOpacity); updateSurfaceColoring(); updateUserInterface(); updateGraphics(); fadeToOpacity += opacityDelta; if (fadeToOpacity > 1.0) { fadeToOpacity = 1.0; } fadeFromOpacity -= opacityDelta; if (fadeFromOpacity < 0.0) { fadeFromOpacity = 0.0; } sleepForSecondsAtEndOfIteration(iterationSleepTime); } fadeToOverlay->setOpacity(1.0); fadeFromOverlay->setOpacity(0.0); updateSurfaceColoring(); updateUserInterface(); updateGraphics(); return true; } connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationAnimateOverlayCrossFade.h000066400000000000000000000075661360521144700307030ustar00rootroot00000000000000#ifndef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_OVERLAY_CROSS_FADE_H__ #define __WB_MACRO_CUSTOM_OPERATION_ANIMATE_OVERLAY_CROSS_FADE_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "WbMacroCustomOperationBase.h" namespace caret { class CaretMappableDataFile; class Overlay; class OverlaySet; class WbMacroCustomOperationAnimateOverlayCrossFade : public WbMacroCustomOperationBase { public: WbMacroCustomOperationAnimateOverlayCrossFade(); virtual ~WbMacroCustomOperationAnimateOverlayCrossFade(); WbMacroCustomOperationAnimateOverlayCrossFade(const WbMacroCustomOperationAnimateOverlayCrossFade&) = delete; WbMacroCustomOperationAnimateOverlayCrossFade& operator=(const WbMacroCustomOperationAnimateOverlayCrossFade&) = delete; virtual bool executeCommand(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand) override; virtual WuQMacroCommand* createCommand() override; // ADD_NEW_METHODS_HERE private: WuQMacroCommand* createCommandVersionOne(); WuQMacroCommand* createCommandVersionTwo(); virtual bool executeCommandVersionTwo(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand); bool performCrossFadeVersionTwo(const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, OverlaySet* overlaySet, const int32_t overlayIndex, CaretMappableDataFile* fadeToMapFile, const int32_t fadeToMapIndex, const float durationSeconds); virtual bool executeCommandVersionOne(QWidget* parent, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand); bool performCrossFadeVersionOne(const WuQMacroExecutorOptions* executorOptions, Overlay* fadeToOverlay, Overlay* fadeFromOverlay, const float durationSeconds); // ADD_NEW_MEMBERS_HERE }; #ifdef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_OVERLAY_CROSS_FADE_DECLARE__ // #endif // __WB_MACRO_CUSTOM_OPERATION_ANIMATE_OVERLAY_CROSS_FADE_DECLARE__ } // namespace #endif //__WB_MACRO_CUSTOM_OPERATION_ANIMATE_OVERLAY_CROSS_FADE_H__ connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationAnimateRotation.cxx000066400000000000000000000212331360521144700276250ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WB_MACRO_CUSTOM_OPERATION_ANIMATE_ROTATION_DECLARE__ #include "WbMacroCustomOperationAnimateRotation.h" #undef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_ROTATION_DECLARE__ #include "BrainBrowserWindow.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "Matrix4x4.h" #include "Model.h" #include "SystemUtilities.h" #include "WbMacroCustomDataTypeEnum.h" #include "WbMacroCustomOperationTypeEnum.h" #include "WuQMacroCommand.h" #include "WuQMacroCommandParameter.h" #include "WuQMacroExecutorMonitor.h" using namespace caret; /** * \class caret::WbMacroCustomOperationAnimateRotation * \brief Macro custom operation for model rotation * \ingroup GuiQt */ /** * Constructor. */ WbMacroCustomOperationAnimateRotation::WbMacroCustomOperationAnimateRotation() : WbMacroCustomOperationBase(WbMacroCustomOperationTypeEnum::ANIMATE_ROTATION) { } /** * Destructor. */ WbMacroCustomOperationAnimateRotation::~WbMacroCustomOperationAnimateRotation() { } /** * Get a new instance of the macro command * * @return * Pointer to command or NULL if not valid * Use getErrorMessage() for error information if NULL returned */ WuQMacroCommand* WbMacroCustomOperationAnimateRotation::createCommand() { const int32_t versionOne(1); WuQMacroCommandParameter* paramOne = new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::AXIS, "Screen Axis", "Y"); QString errorMessage; WuQMacroCommand* command = WuQMacroCommand::newInstanceCustomCommand(WbMacroCustomOperationTypeEnum::toName(WbMacroCustomOperationTypeEnum::ANIMATE_ROTATION), versionOne, "none", WbMacroCustomOperationTypeEnum::toGuiName(getOperationType()), "Rotate the Brain Model About a Screen Axis", 1.0, errorMessage); if (command != NULL) { command->addParameter(paramOne); command->addParameter(WuQMacroDataValueTypeEnum::FLOAT, "Total Rotation (Degrees)", (float)360.0); command->addParameter(WuQMacroDataValueTypeEnum::FLOAT, "Duration (secs)", (float)15.0); } else { appendToErrorMessage(errorMessage); } return command; } /** * Execute the macro command * * @param parent * Parent widget for any dialogs * @param executorMonitor * the macro executor monitor * @param executorOptions * Options for executor * @param macroCommand * macro command to run * @return * True if command executed successfully, else false * Use getErrorMessage() for error information if false returned */ bool WbMacroCustomOperationAnimateRotation::executeCommand(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand) { CaretAssert(parent); CaretAssert(macroCommand); if ( ! validateCorrectNumberOfParameters(macroCommand, 3)) { return false; } const QString axisName(macroCommand->getParameterAtIndex(0)->getValue().toString().toUpper()); const float totalRotation = macroCommand->getParameterAtIndex(1)->getValue().toFloat(); const float durationSeconds = macroCommand->getParameterAtIndex(2)->getValue().toFloat(); BrainBrowserWindow* bbw = qobject_cast(parent); if (bbw == NULL) { appendToErrorMessage("Parent for running surface macro is not a browser window."); return false; } BrowserTabContent* tabContent = bbw->getBrowserTabContent(); if (tabContent == NULL) { appendToErrorMessage("No tab is selected in browser window."); return false; } Axis axis = Axis::X; if (axisName == "X") { axis = Axis::X; } else if (axisName == "Y") { axis = Axis::Y; } else if (axisName == "Z") { axis = Axis::Z; } else { appendToErrorMessage("Axis named \"" + axisName + "\" is invalid. Use X, Y, or Z."); } if (totalRotation < 0.0) { appendToErrorMessage("Total Rotation must be greater than zero."); } if (durationSeconds < 0.0) { appendToErrorMessage("Duration must be greater than zero."); } if ( ! getErrorMessage().isEmpty()) { return false; } Model* model = tabContent->getModelForDisplay(); if (model != NULL) { } const bool successFlag = performRotation(executorMonitor, executorOptions, tabContent, axis, totalRotation, durationSeconds); return successFlag; } /** * Perform the rotation * * @param executorMonitor * the macro executor monitor * @param executorOptions * executor options * @param tabContent * Content of the tab * @param axis * The screen axis of rotation * @param totalRotation * Total amount of rotation * @param durationSeconds * To time for command to run * */ bool WbMacroCustomOperationAnimateRotation::performRotation(const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, BrowserTabContent* tabContent, const Axis axis, const float totalRotation, const float durationSeconds) { const float defaultNumberOfSteps(60.0); float numberOfSteps(0.0); float iterationSleepTime(0.0); getNumberOfStepsAndSleepTime(executorOptions, defaultNumberOfSteps, durationSeconds, numberOfSteps, iterationSleepTime); // const double rotationIncrement = 1.0; // const int32_t rotationStepCount = static_cast(totalRotation / rotationIncrement); // const float sleepTimeSeconds = durationSeconds / rotationStepCount; const int32_t rotationStepCount = numberOfSteps; const float rotationIncrement = totalRotation / numberOfSteps; for (int32_t i = 0; i < rotationStepCount; i++) { Matrix4x4 rotationMatrix = tabContent->getRotationMatrix(); switch (axis) { case Axis::X: rotationMatrix.rotateX(rotationIncrement); break; case Axis::Y: rotationMatrix.rotateY(rotationIncrement); break; case Axis::Z: rotationMatrix.rotateZ(rotationIncrement); break; } tabContent->setRotationMatrix(rotationMatrix); updateGraphics(); if (executorMonitor->testForStop()) { appendToErrorMessage(executorMonitor->getStoppedByUserMessage()); return false; } sleepForSecondsAtEndOfIteration(iterationSleepTime); } return true; } connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationAnimateRotation.h000066400000000000000000000052361360521144700272570ustar00rootroot00000000000000#ifndef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_ROTATION_H__ #define __WB_MACRO_CUSTOM_OPERATION_ANIMATE_ROTATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "WbMacroCustomOperationBase.h" namespace caret { class BrowserTabContent; class WbMacroCustomOperationAnimateRotation : public WbMacroCustomOperationBase { public: WbMacroCustomOperationAnimateRotation(); virtual ~WbMacroCustomOperationAnimateRotation(); WbMacroCustomOperationAnimateRotation(const WbMacroCustomOperationAnimateRotation&) = delete; WbMacroCustomOperationAnimateRotation& operator=(const WbMacroCustomOperationAnimateRotation&) = delete; virtual bool executeCommand(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand) override; virtual WuQMacroCommand* createCommand() override; // ADD_NEW_METHODS_HERE private: enum class Axis { X, Y, Z }; bool performRotation(const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, BrowserTabContent* tabContent, const Axis axis, const float totalRotation, const float durationSeconds); // ADD_NEW_MEMBERS_HERE }; #ifdef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_ROTATION_DECLARE__ // #endif // __WB_MACRO_CUSTOM_OPERATION_ANIMATE_ROTATION_DECLARE__ } // namespace #endif //__WB_MACRO_CUSTOM_OPERATION_ANIMATE_ROTATION_H__ connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationAnimateSurfaceInterpolation.cxx000066400000000000000000000347371360521144700322030ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WB_MACRO_CUSTOM_OPERATION_ANIMATE_SURFACE_INTERPOLATION_DECLARE__ #include "WbMacroCustomOperationAnimateSurfaceInterpolation.h" #undef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_SURFACE_INTERPOLATION_DECLARE__ #include "BrainBrowserWindow.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "EventDataFileAdd.h" #include "EventDataFileDelete.h" #include "EventCaretDataFilesGet.h" #include "FileInformation.h" #include "GuiManager.h" #include "MathFunctions.h" #include "ModelSurface.h" #include "ModelWholeBrain.h" #include "SpecFile.h" #include "Surface.h" #include "WbMacroCustomDataTypeEnum.h" #include "WbMacroCustomOperationTypeEnum.h" #include "WuQMacroCommand.h" #include "WuQMacroCommandParameter.h" #include "WuQMacroExecutorMonitor.h" using namespace caret; /** * \class caret::WbMacroCustomOperationAnimateSurfaceInterpolation * \brief Custom Macro Command for Surface Interpolation * \ingroup GuiQt */ /** * Constructor. */ WbMacroCustomOperationAnimateSurfaceInterpolation::WbMacroCustomOperationAnimateSurfaceInterpolation() : WbMacroCustomOperationBase(WbMacroCustomOperationTypeEnum::ANIMATE_SURFACE_INTERPOLATION) { } /** * Destructor. */ WbMacroCustomOperationAnimateSurfaceInterpolation::~WbMacroCustomOperationAnimateSurfaceInterpolation() { } /** * Get a new instance of the macro command * * @return * Pointer to command or NULL if not valid * Use getErrorMessage() for error information if NULL returned */ WuQMacroCommand* WbMacroCustomOperationAnimateSurfaceInterpolation::createCommand() { const int32_t versionOne(1); WuQMacroCommandParameter* paramSurfaceOne = new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING_LIST, "Starting Surface", ""); paramSurfaceOne->setCustomDataType(WbMacroCustomDataTypeEnum::toName(WbMacroCustomDataTypeEnum::SURFACE)); WuQMacroCommandParameter* paramSurfaceTwo = new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING_LIST, "Ending Surface", ""); paramSurfaceTwo->setCustomDataType(WbMacroCustomDataTypeEnum::toName(WbMacroCustomDataTypeEnum::SURFACE)); QString errorMessage; WuQMacroCommand* command = WuQMacroCommand::newInstanceCustomCommand(WbMacroCustomOperationTypeEnum::toName(WbMacroCustomOperationTypeEnum::ANIMATE_SURFACE_INTERPOLATION), versionOne, "none", WbMacroCustomOperationTypeEnum::toGuiName(getOperationType()), "Interpolate Between Two Surfaces", 1.0, errorMessage); if (command != NULL) { command->addParameter(paramSurfaceOne); command->addParameter(paramSurfaceTwo); command->addParameter(WuQMacroDataValueTypeEnum::FLOAT, "Duration (secs)", (float)5.0); } else { appendToErrorMessage(errorMessage); } return command; } /** * Execute the macro command * * @param parent * Parent widget for any dialogs * @param executorMonitor * the macro executor monitor * @param executorOptions * Options for executor * @param macroCommand * macro command to run * @return * True if command executed successfully, else false * Use getErrorMessage() for error information if false returned */ bool WbMacroCustomOperationAnimateSurfaceInterpolation::executeCommand(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand) { CaretAssert(parent); CaretAssert(macroCommand); if ( ! validateCorrectNumberOfParameters(macroCommand, 3)) { return false; } const QString startSurfaceName(macroCommand->getParameterAtIndex(0)->getValue().toString()); Surface* startSurface = findSurface(startSurfaceName, "Starting surface"); const QString endSurfaceName(macroCommand->getParameterAtIndex(1)->getValue().toString()); Surface* endSurface = findSurface(endSurfaceName, "Ending surface"); const float durationSeconds = macroCommand->getParameterAtIndex(2)->getValue().toFloat(); BrainBrowserWindow* bbw = qobject_cast(parent); if (bbw == NULL) { appendToErrorMessage("Parent for running surface macro is not a browser window"); return false; } BrowserTabContent* tabContent = bbw->getBrowserTabContent(); if (tabContent == NULL) { appendToErrorMessage("No tab is selected in browser window"); return false; } ModelWholeBrain* wholeBrainModel = tabContent->getDisplayedWholeBrainModel(); if (wholeBrainModel == NULL) { appendToErrorMessage("View selected is not ALL view"); return false; } if ((startSurface != NULL) && (endSurface != NULL)) { if (startSurface == endSurface) { appendToErrorMessage("Starting and ending surfaces are the same surfaces"); } if (startSurface->getStructure() != endSurface->getStructure()) { appendToErrorMessage("The surfaces' structures are different"); } if (startSurface->getNumberOfNodes() != endSurface->getNumberOfNodes()) { appendToErrorMessage("The surfaces contain a different number of vertices"); } switch (startSurface->getStructure()) { case StructureEnum::CEREBELLUM: case StructureEnum::CORTEX_LEFT: case StructureEnum::CORTEX_RIGHT: break; default: appendToErrorMessage("Supported surface structures are: " + StructureEnum::toGuiName(StructureEnum::CEREBELLUM) + ", " + StructureEnum::toGuiName(StructureEnum::CORTEX_LEFT) + ", " + StructureEnum::toGuiName(StructureEnum::CORTEX_RIGHT)); break; } } if ( ! getErrorMessage().isEmpty()) { return false; } bool successFlag = interpolateSurface(executorMonitor, executorOptions, tabContent->getTabNumber(), wholeBrainModel, startSurface, endSurface, durationSeconds); return successFlag; } /** * Interpolate from starting to ending surface * * @param executorMonitor * The macro executor's monitor * @param executorOptions * The executor options * @param tabIndex * Index of selected tab * @param wholeBrainModel * The whole brain model * @param startSurface * The starting surface * @param endSurface * The ending surface * @param durationSeconds * Total duration for surface interpolation * @return * True if successful, else false */ bool WbMacroCustomOperationAnimateSurfaceInterpolation::interpolateSurface(const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const int32_t tabIndex, ModelWholeBrain* wholeBrainModel, const Surface* startSurface, const Surface* endSurface, const float durationSeconds) { CaretAssert(wholeBrainModel); CaretAssert(startSurface); CaretAssert(endSurface); const float defaultNumberOfSteps(50.0); float numberOfSteps(0.0); float iterationSleepTime(0.0); getNumberOfStepsAndSleepTime(executorOptions, defaultNumberOfSteps, durationSeconds, numberOfSteps, iterationSleepTime); const StructureEnum::Enum structure = startSurface->getStructure(); createInterpolationSurface(startSurface); CaretAssert(m_interpolationSurface); const float* startingXYZ = startSurface->getCoordinateData(); const float* endingXYZ = endSurface->getCoordinateData(); /* * XYZ that will be interpolated */ const int32_t numberOfVertices = endSurface->getNumberOfNodes(); const int32_t numberOfComponents = numberOfVertices * 3; /* * Initialize with starting coordinates */ std::vector xyz(startingXYZ, startingXYZ + numberOfComponents); /* * Amount to move each interpolation iteration */ std::vector deltaXYZ(numberOfComponents); for (int32_t i = 0; i < numberOfComponents; i++) { const float distance = endingXYZ[i] - startingXYZ[i]; const float stepDistance = distance / numberOfSteps; CaretAssertVectorIndex(deltaXYZ, i); deltaXYZ[i] = stepDistance; } /* * Put interpolation surface into view */ wholeBrainModel->setSelectedSurfaceType(tabIndex, m_interpolationSurface->getSurfaceType()); wholeBrainModel->setSelectedSurface(structure, tabIndex, m_interpolationSurface); updateUserInterface(); updateGraphics(); for (int iStep = 0; iStep < numberOfSteps; iStep++) { /* * Move coordinate components */ for (int32_t i = 0; i < numberOfComponents; i++) { CaretAssertVectorIndex(xyz, i); CaretAssertVectorIndex(deltaXYZ, i); xyz[i] += deltaXYZ[i]; } /* * Update surface coordinates */ for (int32_t i = 0; i < numberOfVertices; i++) { const int32_t i3 = i * 3; m_interpolationSurface->setCoordinate(i, &xyz[i3]); } m_interpolationSurface->invalidateNormals(); m_interpolationSurface->computeNormals(); const bool debugFlag(false); if (debugFlag) { const int32_t vertexIndex = 16764; const float* p = endSurface->getCoordinate(vertexIndex); std::cout << "XYZ " << iStep << ": " << AString::number(p[0]) << " " << AString::number(p[1]) << " " << AString::number(p[2]) << std::endl; } updateGraphics(); if (executorMonitor->testForStop()) { appendToErrorMessage(executorMonitor->getStoppedByUserMessage()); return false; } sleepForSecondsAtEndOfIteration(iterationSleepTime); } /* * View ending surface */ /* * Put interpolation surface into view */ wholeBrainModel->setSelectedSurfaceType(tabIndex, endSurface->getSurfaceType()); wholeBrainModel->setSelectedSurface(structure, tabIndex, const_cast(endSurface)); updateGraphics(); updateUserInterface(); deleteInterpolationSurface(); return true; } /** * Create the interpolation surface * * @param surface * Surface that is copied to create the interpolation surface */ void WbMacroCustomOperationAnimateSurfaceInterpolation::createInterpolationSurface(const Surface* surface) { CaretAssert(surface); std::vector specFileVector = EventCaretDataFilesGet::getCaretDataFilesForType(DataFileTypeEnum::SPECIFICATION); if ( ! specFileVector.empty()) { m_specFile = dynamic_cast(specFileVector[0]); m_specFileModificationStatus = m_specFile->isModified(); } m_interpolationSurface = new Surface(*surface); CaretAssert(m_interpolationSurface); FileInformation fileInfo(m_interpolationSurface->getFileName()); AString path, name, ext; fileInfo.getFileComponents(path, name, ext); const AString newName = FileInformation::assembleFileComponents(path, "Interpolation", ext); m_interpolationSurface->setFileName(newName); EventDataFileAdd addSurfaceEvent(m_interpolationSurface); EventManager::get()->sendEvent(addSurfaceEvent.getPointer()); } /** * Delete the interpolation surface */ void WbMacroCustomOperationAnimateSurfaceInterpolation::deleteInterpolationSurface() { if (m_interpolationSurface != NULL) { EventDataFileDelete deleteFileEvent(m_interpolationSurface); EventManager::get()->sendEvent(deleteFileEvent.getPointer()); } if (m_specFile != NULL) { if ( ! m_specFileModificationStatus) { m_specFile->clearModified(); } } } connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationAnimateSurfaceInterpolation.h000066400000000000000000000062471360521144700316230ustar00rootroot00000000000000#ifndef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_SURFACE_INTERPOLATION_H__ #define __WB_MACRO_CUSTOM_OPERATION_ANIMATE_SURFACE_INTERPOLATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "WbMacroCustomOperationBase.h" namespace caret { class ModelSurface; class ModelWholeBrain; class SpecFile; class Surface; class WbMacroCustomOperationAnimateSurfaceInterpolation : public WbMacroCustomOperationBase { public: WbMacroCustomOperationAnimateSurfaceInterpolation(); virtual ~WbMacroCustomOperationAnimateSurfaceInterpolation(); WbMacroCustomOperationAnimateSurfaceInterpolation(const WbMacroCustomOperationAnimateSurfaceInterpolation&) = delete; WbMacroCustomOperationAnimateSurfaceInterpolation& operator=(const WbMacroCustomOperationAnimateSurfaceInterpolation&) = delete; virtual bool executeCommand(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand) override; virtual WuQMacroCommand* createCommand() override; // ADD_NEW_METHODS_HERE private: bool interpolateSurface(const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const int32_t tabIndex, ModelWholeBrain* wholeBrainModel, const Surface* startSurface, const Surface* endSurface, const float durationSeconds); void createInterpolationSurface(const Surface* surface); void deleteInterpolationSurface(); Surface* m_interpolationSurface = NULL; SpecFile* m_specFile = NULL; bool m_specFileModificationStatus = false; // ADD_NEW_MEMBERS_HERE }; #ifdef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_SURFACE_INTERPOLATION_DECLARE__ // #endif // __WB_MACRO_CUSTOM_OPERATION_ANIMATE_SURFACE_INTERPOLATION_DECLARE__ } // namespace #endif //__WB_MACRO_CUSTOM_OPERATION_ANIMATE_SURFACE_INTERPOLATION_H__ connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationAnimateVolumeSliceSequence.cxx000066400000000000000000000263501360521144700317530ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_SLICE_DECLARE__ #include "WbMacroCustomOperationAnimateVolumeSliceSequence.h" #undef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_SLICE_DECLARE__ #include "BrainBrowserWindow.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "Matrix4x4.h" #include "Model.h" #include "ModelVolume.h" #include "ModelWholeBrain.h" #include "Overlay.h" #include "OverlaySet.h" #include "SystemUtilities.h" #include "VolumeMappableInterface.h" #include "WbMacroCustomDataTypeEnum.h" #include "WbMacroCustomOperationTypeEnum.h" #include "WuQMacroCommand.h" #include "WuQMacroCommandParameter.h" #include "WuQMacroExecutorMonitor.h" using namespace caret; /** * \class caret::WbMacroCustomOperationAnimateVolumeSliceSequence * \brief Macro custom operation incrementing volume slices * \ingroup GuiQt */ /** * Constructor. */ WbMacroCustomOperationAnimateVolumeSliceSequence::WbMacroCustomOperationAnimateVolumeSliceSequence() : WbMacroCustomOperationBase(WbMacroCustomOperationTypeEnum::ANIMATE_VOLUME_SLICE_SEQUENCE) { } /** * Destructor. */ WbMacroCustomOperationAnimateVolumeSliceSequence::~WbMacroCustomOperationAnimateVolumeSliceSequence() { } /** * Get a new instance of the macro command * * @return * Pointer to command or NULL if not valid * Use getErrorMessage() for error information if NULL returned */ WuQMacroCommand* WbMacroCustomOperationAnimateVolumeSliceSequence::createCommand() { const int32_t versionOne(1); const QString description("Sequence through the volume slices: \n" "(1) start at the \"selected slice\"; \n" "(2) decrement the slice index to the first slice; \n" "(3) increment the slice index to the last slice; \n" "(4) decrement the slice index returning to the \"selected slice\""); QString errorMessage; WuQMacroCommand* command = WuQMacroCommand::newInstanceCustomCommand(WbMacroCustomOperationTypeEnum::toName(getOperationType()), versionOne, "none", WbMacroCustomOperationTypeEnum::toGuiName(getOperationType()), description, 1.0, errorMessage); if (command != NULL) { WuQMacroCommandParameter* paramOne = new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::AXIS, "Volume Axis", "Z"); command->addParameter(paramOne); command->addParameter(WuQMacroDataValueTypeEnum::FLOAT, "Duration (secs)", (float)20.0); } else { appendToErrorMessage(errorMessage); } return command; } /** * Execute the macro command * * @param parent * Parent widget for any dialogs * @param executorMonitor * the macro executor monitor * @param executorOptions * Options for executor * @param macroCommand * macro command to run * @return * True if command executed successfully, else false * Use getErrorMessage() for error information if false returned */ bool WbMacroCustomOperationAnimateVolumeSliceSequence::executeCommand(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand) { CaretAssert(parent); CaretAssert(macroCommand); if ( ! validateCorrectNumberOfParameters(macroCommand, 2)) { return false; } const QString axisName(macroCommand->getParameterAtIndex(0)->getValue().toString().toUpper()); const float durationSeconds = macroCommand->getParameterAtIndex(1)->getValue().toFloat(); BrainBrowserWindow* bbw = qobject_cast(parent); if (bbw == NULL) { appendToErrorMessage("Parent for running surface macro is not a browser window."); return false; } BrowserTabContent* tabContent = bbw->getBrowserTabContent(); if (tabContent == NULL) { appendToErrorMessage("No tab is selected in browser window."); return false; } Axis axis = Axis::X; if (axisName == "X") { axis = Axis::X; } else if (axisName == "Y") { axis = Axis::Y; } else if (axisName == "Z") { axis = Axis::Z; } else { appendToErrorMessage("Axis named \"" + axisName + "\" is invalid. Use X, Y, or Z."); } if (durationSeconds < 0.0) { appendToErrorMessage("Duration must be greater than zero."); } Model* model = tabContent->getModelForDisplay(); if (model == NULL) { appendToErrorMessage("No model for surface rotation"); } if ( ! getErrorMessage().isEmpty()) { return false; } const bool successFlag = performSliceIncrement(executorMonitor, executorOptions, tabContent, axis, durationSeconds); return successFlag; } /** * @param executorMonitor * The macro executor's monitor * @param executorOptions * The executor options * @param tabContent * Content in the selected tab * @param axis * Axis for viewing * @param durationSecondes * Duration of time for command to run */ bool WbMacroCustomOperationAnimateVolumeSliceSequence::performSliceIncrement(const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, BrowserTabContent* tabContent, const Axis axis, const float durationSeconds) { ModelVolume* volumeModel(tabContent->getDisplayedVolumeModel()); ModelWholeBrain* wholeBrainModel(tabContent->getDisplayedWholeBrainModel()); if ((volumeModel == NULL) && (wholeBrainModel == NULL)) { appendToErrorMessage("For slice increment, View must be All or Volume"); return false; } const VolumeMappableInterface* vmi = tabContent->getOverlaySet()->getUnderlayVolume(); if (vmi == NULL) { appendToErrorMessage("No volume is selected as an overlay"); return false; } std::vector dims; vmi->getDimensions(dims); if (dims.size() < 3) { appendToErrorMessage("Dimensions are invalid for underlay volume"); } int32_t numberOfSlices(0); int32_t startingSliceIndex(0); switch (axis) { case Axis::X: numberOfSlices = dims[0]; startingSliceIndex = tabContent->getSliceIndexParasagittal(vmi); break; case Axis::Y: numberOfSlices = dims[1]; startingSliceIndex = tabContent->getSliceIndexCoronal(vmi); break; case Axis::Z: numberOfSlices = dims[2]; startingSliceIndex = tabContent->getSliceIndexAxial(vmi); break; } if (numberOfSlices <= 0) { appendToErrorMessage("No slices in underlay volume for selected dimension"); } const float defaultNumberOfSteps(numberOfSlices); float numberOfSteps(0.0); float iterationSleepTime(0.0); getNumberOfStepsAndSleepTime(executorOptions, defaultNumberOfSteps, durationSeconds, numberOfSteps, iterationSleepTime); enum SliceMode { DECREMENT_TO_ZERO, INCREMENT_TO_LAST, DECREMENT_TO_START }; SliceMode sliceMode = DECREMENT_TO_ZERO; float sliceIndex = startingSliceIndex; float sliceIncrement = numberOfSlices / (numberOfSteps / 2); bool doneFlag(false); while ( ! doneFlag) { switch (axis) { case Axis::X: tabContent->setSliceIndexParasagittal(vmi, sliceIndex); break; case Axis::Y: tabContent->setSliceIndexCoronal(vmi, sliceIndex); break; case Axis::Z: tabContent->setSliceIndexAxial(vmi, sliceIndex); break; } switch (sliceMode) { case DECREMENT_TO_START: sliceIndex -= sliceIncrement; if (sliceIndex <= startingSliceIndex) { doneFlag = true; } break; case DECREMENT_TO_ZERO: sliceIndex -= sliceIncrement; if (sliceIndex <= 0.0) { sliceIndex = 0; sliceMode = INCREMENT_TO_LAST; } break; case INCREMENT_TO_LAST: sliceIndex += sliceIncrement; if (sliceIndex >= (numberOfSlices - 1)) { sliceIndex = (numberOfSlices - 1); sliceMode = DECREMENT_TO_START; } break; } updateGraphics(); if (executorMonitor->testForStop()) { appendToErrorMessage(executorMonitor->getStoppedByUserMessage()); return false; } sleepForSecondsAtEndOfIteration(iterationSleepTime); } switch (axis) { case Axis::X: tabContent->setSliceIndexParasagittal(vmi, startingSliceIndex); break; case Axis::Y: tabContent->setSliceIndexCoronal(vmi, startingSliceIndex); break; case Axis::Z: tabContent->setSliceIndexAxial(vmi, startingSliceIndex); break; } updateGraphics(); return true; } connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationAnimateVolumeSliceSequence.h000066400000000000000000000053701360521144700313770ustar00rootroot00000000000000#ifndef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_SLICE_SEQUENCE_H__ #define __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_SLICE_SEQUENCE_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "WbMacroCustomOperationBase.h" namespace caret { class BrowserTabContent; class WbMacroCustomOperationAnimateVolumeSliceSequence : public WbMacroCustomOperationBase { public: WbMacroCustomOperationAnimateVolumeSliceSequence(); virtual ~WbMacroCustomOperationAnimateVolumeSliceSequence(); WbMacroCustomOperationAnimateVolumeSliceSequence(const WbMacroCustomOperationAnimateVolumeSliceSequence&) = delete; WbMacroCustomOperationAnimateVolumeSliceSequence& operator=(const WbMacroCustomOperationAnimateVolumeSliceSequence&) = delete; virtual bool executeCommand(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand) override; virtual WuQMacroCommand* createCommand() override; // ADD_NEW_METHODS_HERE private: enum class Axis { X, Y, Z }; bool performSliceIncrement(const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, BrowserTabContent* tabContent, const Axis axis, const float durationSeconds); // ADD_NEW_MEMBERS_HERE }; #ifdef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_SLICE_DECLARE__ // #endif // __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_SLICE_DECLARE__ } // namespace #endif //__WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_SLICE_SEQUENCE_H__ connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade.cxx000066400000000000000000000215641360521144700327120ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE_DECLARE__ #include "WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade.h" #undef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE_DECLARE__ #include "Brain.h" #include "BrainBrowserWindow.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "DisplayPropertiesSurface.h" #include "DisplayPropertiesVolume.h" #include "GuiManager.h" #include "ModelWholeBrain.h" #include "Overlay.h" #include "OverlaySet.h" #include "WbMacroCustomDataTypeEnum.h" #include "WbMacroCustomOperationTypeEnum.h" #include "WuQMacroCommand.h" #include "WuQMacroCommandParameter.h" #include "WuQMacroExecutorMonitor.h" using namespace caret; /** * \class caret::WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade * \brief Custom Macro Command for Surface Interpolation * \ingroup GuiQt */ /** * Constructor. */ WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade::WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade() : WbMacroCustomOperationBase(WbMacroCustomOperationTypeEnum::ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE) { } /** * Destructor. */ WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade::~WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade() { } /** * Get a new instance of the macro command * * @return * Pointer to command or NULL if not valid * Use getErrorMessage() for error information if NULL returned */ WuQMacroCommand* WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade::createCommand() { const int32_t versionOne(1); const QString description("Crossfade (blend) from volume to surface:\n" "ALL View must be selected.\n" "(1) The opacity of the surface is set to zero;\n" "(2) The opacity of the volume overlay is set to one\n" "(3) The opacity of the surface increases until it is one\n" " and simultaneously, the opacity of the volume\n" " decreases until it reaches zero.\n"); QString errorMessage; WuQMacroCommand* command = WuQMacroCommand::newInstanceCustomCommand(WbMacroCustomOperationTypeEnum::toName(getOperationType()), versionOne, "none", WbMacroCustomOperationTypeEnum::toGuiName(getOperationType()), description, 1.0, errorMessage); if (command != NULL) { // command->addParameter(WuQMacroDataValueTypeEnum::INTEGER, // "Fade from Overlay", // (int)2); command->addParameter(WuQMacroDataValueTypeEnum::FLOAT, "Duration (secs)", (float)10.0); } else { appendToErrorMessage(errorMessage); } return command; } /** * Execute the macro command * * @param parent * Parent widget for any dialogs * @param executorMonitor * the macro executor monitor * @param executorOptions * Options for executor * @param macroCommand * macro command to run * @return * True if command executed successfully, else false * Use getErrorMessage() for error information if false returned */ bool WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade::executeCommand(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand) { CaretAssert(parent); CaretAssert(macroCommand); if ( ! validateCorrectNumberOfParameters(macroCommand, 1)) { return false; } const float durationSeconds(macroCommand->getParameterAtIndex(0)->getValue().toFloat()); BrainBrowserWindow* bbw = qobject_cast(parent); if (bbw == NULL) { appendToErrorMessage("Parent for running surface macro is not a browser window"); return false; } BrowserTabContent* tabContent = bbw->getBrowserTabContent(); if (tabContent == NULL) { appendToErrorMessage("No tab is selected in browser window"); return false; } ModelWholeBrain* wholeBrainModel = tabContent->getDisplayedWholeBrainModel(); if (wholeBrainModel == NULL) { appendToErrorMessage("All view must be selected"); return false; } OverlaySet* overlaySet = tabContent->getOverlaySet(); CaretAssert(overlaySet); Overlay* volumeOverlay = overlaySet->getUnderlayContainingVolume(); if (volumeOverlay == NULL) { appendToErrorMessage("An overlay must contain a volume"); return false; } if ( ! getErrorMessage().isEmpty()) { return false; } bool successFlag = performCrossFade(executorMonitor, executorOptions, volumeOverlay, durationSeconds); return successFlag; } /** * Interpolate from starting to ending surface * * @param executorMonitor * The macro executor's monitor * @param executorOptions * The executor options * @param volumeOverlay * Overlay that contains the volume * @param durationSeconds * Total duration for cross fade * @return * True if successful, else false */ bool WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade::performCrossFade(const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, Overlay* volumeOverlay, const float durationSeconds) { CaretAssert(volumeOverlay); const float defaultNumberOfSteps(25.0); float numberOfSteps(0.0); float iterationSleepTime(0.0); getNumberOfStepsAndSleepTime(executorOptions, defaultNumberOfSteps, durationSeconds, numberOfSteps, iterationSleepTime); const float opacityDelta = 1.0 / numberOfSteps; float surfaceOpacity(0.0); float volumeOpacity(1.0); DisplayPropertiesSurface* surfaceProperties = GuiManager::get()->getBrain()->getDisplayPropertiesSurface(); CaretAssert(surfaceProperties); DisplayPropertiesVolume* volumeProperties = GuiManager::get()->getBrain()->getDisplayPropertiesVolume(); CaretAssert(volumeProperties); /* * Initialize the opacities */ for (int iStep = 0; iStep < numberOfSteps; iStep++) { surfaceProperties->setOpacity(surfaceOpacity); volumeProperties->setOpacity(volumeOpacity); volumeOverlay->setOpacity(volumeOpacity); updateSurfaceColoring(); updateUserInterface(); updateGraphics(); surfaceOpacity += opacityDelta; if (surfaceOpacity > 1.0) { surfaceOpacity = 1.0; } volumeOpacity -= opacityDelta; if (volumeOpacity < 0.0) { volumeOpacity = 0.0; } if (executorMonitor->testForStop()) { appendToErrorMessage(executorMonitor->getStoppedByUserMessage()); return false; } sleepForSecondsAtEndOfIteration(iterationSleepTime); } surfaceProperties->setOpacity(1.0); volumeProperties->setOpacity(0.0); volumeOverlay->setOpacity(0.0); updateSurfaceColoring(); updateUserInterface(); updateGraphics(); return true; } connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade.h000066400000000000000000000053051360521144700323320ustar00rootroot00000000000000#ifndef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE_H__ #define __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "WbMacroCustomOperationBase.h" namespace caret { class Overlay; class WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade : public WbMacroCustomOperationBase { public: WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade(); virtual ~WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade(); WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade(const WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade&) = delete; WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade& operator=(const WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade&) = delete; virtual bool executeCommand(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand) override; virtual WuQMacroCommand* createCommand() override; // ADD_NEW_METHODS_HERE private: bool performCrossFade(const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, Overlay* volumeOverlay, const float durationSeconds); // ADD_NEW_MEMBERS_HERE }; #ifdef __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE_DECLARE__ // #endif // __WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE_DECLARE__ } // namespace #endif //__WB_MACRO_CUSTOM_OPERATION_ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE_H__ connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationBase.cxx000066400000000000000000000204211360521144700253770ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WB_MACRO_CUSTOM_OPERATION_BASE_DECLARE__ #include "WbMacroCustomOperationBase.h" #undef __WB_MACRO_CUSTOM_OPERATION_BASE_DECLARE__ #include #include "CaretAssert.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "EventSurfaceColoringInvalidate.h" #include "EventSurfacesGet.h" #include "EventUserInterfaceUpdate.h" #include "MovieRecorder.h" #include "SessionManager.h" #include "Surface.h" #include "SystemUtilities.h" #include "WuQMacroCommand.h" #include "WuQMacroExecutorOptions.h" using namespace caret; /** * \class caret::WbMacroCustomOperationBase * \brief Base class for all macro custom operations * \ingroup GuiQt */ /** * Constructor * * @param operationTye * Type of custom command operation */ WbMacroCustomOperationBase::WbMacroCustomOperationBase(const WbMacroCustomOperationTypeEnum::Enum operationType) : m_operationType(operationType) { } /** * Destructor */ WbMacroCustomOperationBase::~WbMacroCustomOperationBase() { } /** * @return The custom operation type */ WbMacroCustomOperationTypeEnum::Enum WbMacroCustomOperationBase::getOperationType() const { return m_operationType; } /** * @return The error message */ QString WbMacroCustomOperationBase::getErrorMessage() const { return m_errorMessage; } /** * Validate that the command contains the correct number of parameters * * @param command * The command * @param correctNumberOfParameters * The correct number of parameters (this must be passed in since a command * may change its number of parameters in a new version of the command) */ bool WbMacroCustomOperationBase::validateCorrectNumberOfParameters(const WuQMacroCommand* command, const int32_t correctNumberOfParameters) { const int32_t paramCount = command->getNumberOfParameters(); if (paramCount < correctNumberOfParameters) { appendToErrorMessage("Command " + command->getDescriptiveName() + " should contain " + QString::number(correctNumberOfParameters) + " parameters but contains " + QString::number(paramCount) + " parameters"); return false; } return true; } /** * Append text to the error message. If the current error message * is not empty, a newline is added prior to the text. * * @param text * Text to append to error message */ void WbMacroCustomOperationBase::appendToErrorMessage(const QString& text) { if ( m_errorMessage.isEmpty()) { m_errorMessage.append("\n"); } m_errorMessage.append(text); } /** * Create a unsupported version messagge and append it to the error message. * * @param unsupportedVersionNumber * Verson not supported */ void WbMacroCustomOperationBase::appendUnsupportedVersionToErrorMessage(const int32_t unsupportedVersionNumber) { QString msg("Version " + QString::number(unsupportedVersionNumber) + " is not supported for " + getOperationName() + ". You may need to update your version of wb_view"); appendToErrorMessage(msg); } /** * Find the surface with the given name * * @param name * Name of surface * @param errorMessagePrefix * Prefix inserted into error message if an error occurs * @return * Pointer to surface or NULL if not found. * If not found getErrorMessage() explains why */ Surface* WbMacroCustomOperationBase::findSurface(const QString& name, const QString& errorMessagePrefix) { if (name.isEmpty()) { appendToErrorMessage(errorMessagePrefix + " name is empty"); return NULL; } EventSurfacesGet eventSurfaces; EventManager::get()->sendEvent(eventSurfaces.getPointer()); std::vector allSurfaces = eventSurfaces.getSurfaces(); for (auto s : allSurfaces) { if (s->getFileName().endsWith(name)) { return s; } } appendToErrorMessage(errorMessagePrefix + " with name \"" + name + "\" not found."); return NULL; } /** * Update graphics */ void WbMacroCustomOperationBase::updateGraphics() { /* * Passing 'true' indicate do a repaint(). A 'repaint' is performed immediately. * Otherwise, the graphics update is scheduled for a later time. */ EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows(true).getPointer()); /* * Qt needs time to update stuff */ QApplication::processEvents(); } /** * Update the user-interface */ void WbMacroCustomOperationBase::updateUserInterface() { EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** * Update surface coloring */ void WbMacroCustomOperationBase::updateSurfaceColoring() { EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); } /** * Get number of steps and sleep time. If a movie is being recorded, the number of * steps is set so that the command will run for the requested duration using the * frame rate of the movie recorder. If a movie * is NOT being recorded, the number of steps out is the default number of steps and * the sleep time is set so that the command will run for approximately the duration. * * @param defaultNumberOfSteps * The default number of steps used when a movie is not being recorded * @param durationSeconds * The number of seconds for which the command should run * @param numberOfStepsOut * Output with number of steps for the command * @param sleepTimeOut * Output with time command should sleep at the end of each iteration * when a movie is not being recorded */ void WbMacroCustomOperationBase::getNumberOfStepsAndSleepTime(const WuQMacroExecutorOptions* executorOptions, const float defaultNumberOfSteps, const float durationSeconds, float& numberOfStepsOut, float& sleepTimeOut) { numberOfStepsOut = defaultNumberOfSteps; sleepTimeOut = 0.0; const MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); switch (movieRecorder->getRecordingMode()) { case MovieRecorderModeEnum::MANUAL: sleepTimeOut = durationSeconds / numberOfStepsOut; break; case MovieRecorderModeEnum::AUTOMATIC: numberOfStepsOut = (durationSeconds * movieRecorder->getFramesRate()); break; } if (executorOptions->isIgnoreDelaysAndDurations()) { sleepTimeOut = 0.0; numberOfStepsOut = 2; } } /** * Sleep for the given number of seconds at the end of an iteration * * @param seconds * Seconds to sleep */ void WbMacroCustomOperationBase::sleepForSecondsAtEndOfIteration(const float seconds) { if (seconds > 0.0) { SystemUtilities::sleepSeconds(seconds); } } /** * @return User friendly name for command * Sub-classes may override to provide more descriptive name */ QString WbMacroCustomOperationBase::getOperationName() const { return WbMacroCustomOperationTypeEnum::toGuiName(m_operationType); } connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationBase.h000066400000000000000000000103501360521144700250240ustar00rootroot00000000000000#ifndef __WB_MACRO_CUSTOM_OPERATION_BASE_H__ #define __WB_MACRO_CUSTOM_OPERATION_BASE_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "WbMacroCustomOperationTypeEnum.h" class QString; class QWidget; namespace caret { class Surface; class WuQMacroExecutorMonitor; class WuQMacroExecutorOptions; class WuQMacroCommand; class WbMacroCustomOperationBase : public CaretObject { public: ~WbMacroCustomOperationBase(); WbMacroCustomOperationBase(const WbMacroCustomOperationBase&) = delete; WbMacroCustomOperationBase& operator=(const WbMacroCustomOperationBase&) = delete; WbMacroCustomOperationTypeEnum::Enum getOperationType() const; /** * Execute the macro command * * @param parent * Parent widget for any dialogs * @param executorMonitor * the macro executor monitor * @param executorOptions, * Options for the executor * @param macroCommand * macro command to run * @return * True if command executed successfully, else false * Use getErrorMessage() for error information if false returned */ virtual bool executeCommand(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand) = 0; /** * Get a new instance of the macro command * * @return * Pointer to command or NULL if not valid * Use getErrorMessage() for error information if NULL returned */ virtual WuQMacroCommand* createCommand() = 0; QString getErrorMessage() const; void sleepForSecondsAtEndOfIteration(const float seconds); virtual QString getOperationName() const; protected: WbMacroCustomOperationBase(const WbMacroCustomOperationTypeEnum::Enum operationType); void getNumberOfStepsAndSleepTime(const WuQMacroExecutorOptions* executorOptions, const float defaultNumberOfSteps, const float durationSeconds, float& numberOfStepsOut, float& sleepTimeOut); bool validateCorrectNumberOfParameters(const WuQMacroCommand* command, const int32_t correctNumberOfParameters); Surface* findSurface(const QString& surfaceName, const QString& errorMessagePrefix); void appendToErrorMessage(const QString& text); void appendUnsupportedVersionToErrorMessage(const int32_t unsupportedVersionNumber); void updateGraphics(); void updateSurfaceColoring(); void updateUserInterface(); const WbMacroCustomOperationTypeEnum::Enum m_operationType; QString m_errorMessage; }; #ifdef __WB_MACRO_CUSTOM_OPERATION_BASE_DECLARE__ // #endif // __WB_MACRO_CUSTOM_OPERATION_BASE_DECLARE__ } // namespace #endif //__WB_MACRO_CUSTOM_OPERATION_BASE_H__ connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationDelay.cxx000066400000000000000000000065701360521144700255740ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WB_MACRO_CUSTOM_OPERATION_DELAY_DECLARE__ #include "WbMacroCustomOperationDelay.h" #undef __WB_MACRO_CUSTOM_OPERATION_DELAY_DECLARE__ #include "CaretAssert.h" #include "WbMacroCustomOperationTypeEnum.h" #include "WuQMacroCommand.h" #include "WuQMacroCommandParameter.h" using namespace caret; /** * \class caret::WbMacroCustomOperationDelay * \brief Custom Macro Command for Delay * \ingroup GuiQt */ /** * Constructor. */ WbMacroCustomOperationDelay::WbMacroCustomOperationDelay() : WbMacroCustomOperationBase(WbMacroCustomOperationTypeEnum::DELAY) { } /** * Destructor. */ WbMacroCustomOperationDelay::~WbMacroCustomOperationDelay() { } /** * Get a new instance of the macro command * * @return * Pointer to command or NULL if not valid * Use getErrorMessage() for error information if NULL returned */ WuQMacroCommand* WbMacroCustomOperationDelay::createCommand() { const int32_t versionOne(1); /* * No parameters are needed as the base command's delay value is used */ QString errorMessage; WuQMacroCommand* command = WuQMacroCommand::newInstanceCustomCommand(WbMacroCustomOperationTypeEnum::toName(WbMacroCustomOperationTypeEnum::DELAY), versionOne, "none", "Delay", "Delay for Seconds", 5.0, errorMessage); return command; } /** * Execute the macro command * * @param parent * Parent widget for any dialogs * @param executorMonitor * the macro executor monitor * @param executorOptions * Options for executor * @param macroCommand * macro command to run * @return * True if command executed successfully, else false * Use getErrorMessage() for error information if false returned */ bool WbMacroCustomOperationDelay::executeCommand(QWidget* /*parent*/, const WuQMacroExecutorMonitor* /*executorMonitor*/, const WuQMacroExecutorOptions* /*executorOptions*/, const WuQMacroCommand* /*macroCommand*/) { /* * Nothing to do since the base command's delay time performs the delay */ return true; } connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationDelay.h000066400000000000000000000040521360521144700252120ustar00rootroot00000000000000#ifndef __WB_MACRO_CUSTOM_OPERATION_DELAY_H__ #define __WB_MACRO_CUSTOM_OPERATION_DELAY_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "WbMacroCustomOperationBase.h" namespace caret { class WbMacroCustomOperationDelay : public WbMacroCustomOperationBase { public: WbMacroCustomOperationDelay(); virtual ~WbMacroCustomOperationDelay(); WbMacroCustomOperationDelay(const WbMacroCustomOperationDelay&) = delete; WbMacroCustomOperationDelay& operator=(const WbMacroCustomOperationDelay&) = delete; virtual bool executeCommand(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand) override; virtual WuQMacroCommand* createCommand() override; // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE }; #ifdef __WB_MACRO_CUSTOM_OPERATION_DELAY_DECLARE__ // #endif // __WB_MACRO_CUSTOM_OPERATION_DELAY_DECLARE__ } // namespace #endif //__WB_MACRO_CUSTOM_OPERATION_DELAY_H__ connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationIncrementRotation.cxx000066400000000000000000000165771360521144700302120ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WB_MACRO_CUSTOM_OPERATION_INCREMENT_ROTATION_DECLARE__ #include "WbMacroCustomOperationIncrementRotation.h" #undef __WB_MACRO_CUSTOM_OPERATION_INCREMENT_ROTATION_DECLARE__ #include "BrainBrowserWindow.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "Matrix4x4.h" #include "Model.h" #include "SystemUtilities.h" #include "ViewingTransformations.h" #include "WbMacroCustomDataTypeEnum.h" #include "WbMacroCustomOperationTypeEnum.h" #include "WuQMacroCommand.h" #include "WuQMacroCommandParameter.h" #include "WuQMacroExecutorMonitor.h" using namespace caret; /** * \class caret::WbMacroCustomOperationIncrementRotation * \brief Macro custom operation for incremental rotation * \ingroup GuiQt */ /** * Constructor. */ WbMacroCustomOperationIncrementRotation::WbMacroCustomOperationIncrementRotation() : WbMacroCustomOperationBase(WbMacroCustomOperationTypeEnum::INCREMENTAL_ROTATION) { } /** * Destructor. */ WbMacroCustomOperationIncrementRotation::~WbMacroCustomOperationIncrementRotation() { } /** * Get a new instance of the macro command * * @return * Pointer to command or NULL if not valid * Use getErrorMessage() for error information if NULL returned */ WuQMacroCommand* WbMacroCustomOperationIncrementRotation::createCommand() { const int32_t versionOne(1); QString errorMessage; WuQMacroCommand* command = WuQMacroCommand::newInstanceCustomCommand(WbMacroCustomOperationTypeEnum::toName(getOperationType()), versionOne, "none", WbMacroCustomOperationTypeEnum::toGuiName(getOperationType()), "Incremental Rotation (degrees) About Screen Axis", 1.0, errorMessage); if (command != NULL) { command->addParameter(WuQMacroDataValueTypeEnum::AXIS, "Screen Axis", "Y"); command->addParameter(WuQMacroDataValueTypeEnum::FLOAT, "Rotation (Degrees)", (float)360.0); } else { appendToErrorMessage(errorMessage); } return command; } /** * Execute the macro command * * @param parent * Parent widget for any dialogs * @param executorMonitor * the macro executor monitor * @param executorOptions * Options for executor * @param macroCommand * macro command to run * @return * True if command executed successfully, else false * Use getErrorMessage() for error information if false returned */ bool WbMacroCustomOperationIncrementRotation::executeCommand(QWidget* parent, const WuQMacroExecutorMonitor* /*executorMonitor*/, const WuQMacroExecutorOptions* /*executorOptions*/, const WuQMacroCommand* macroCommand) { CaretAssert(parent); CaretAssert(macroCommand); if ( ! validateCorrectNumberOfParameters(macroCommand, 2)) { return false; } const QString axisName(macroCommand->getParameterAtIndex(0)->getValue().toString().toUpper()); const float incrementalRotation = macroCommand->getParameterAtIndex(1)->getValue().toFloat(); BrainBrowserWindow* bbw = qobject_cast(parent); if (bbw == NULL) { appendToErrorMessage("Parent for running surface macro is not a browser window."); return false; } BrowserTabContent* tabContent = bbw->getBrowserTabContent(); if (tabContent == NULL) { appendToErrorMessage("No tab is selected in browser window."); return false; } Axis axis = Axis::X; if (axisName == "X") { axis = Axis::X; } else if (axisName == "Y") { axis = Axis::Y; } else if (axisName == "Z") { axis = Axis::Z; } else { appendToErrorMessage("Axis named \"" + axisName + "\" is invalid. Use X, Y, or Z."); return false; } Model* model = tabContent->getModelForDisplay(); if (model == NULL) { appendToErrorMessage("No model is displayed that can be rotated"); return false; } int32_t mousePressX(0); int32_t mousePressY(0); int32_t mouseX(0); int32_t mouseY(0); int32_t mouseDeltaX(0); int32_t mouseDeltaY(0); bool doMouseFlag(false); bool doZFlag(false); switch (axis) { case Axis::X: doMouseFlag = true; mousePressX = 50; mouseX = 50; mouseDeltaY = incrementalRotation; if (mouseDeltaY >= 0.0) { mousePressY = 1; mouseY = mouseDeltaY + mousePressY; } else { mouseY = 1; mousePressY = 1 - mouseDeltaY; } break; case Axis::Y: doMouseFlag = true; mousePressY = 50; mouseY = 50; mouseDeltaX = incrementalRotation; if (mouseDeltaX >= 0.0) { mousePressX = 1; mouseX = mouseDeltaX + mousePressX; } else { mouseX = 1; mousePressX = 1 - mouseDeltaX; } break; case Axis::Z: if (incrementalRotation != 0.0) { doZFlag = true; } break; } if (doMouseFlag) { BrainOpenGLViewportContent* viewportContent(NULL); tabContent->applyMouseRotation(viewportContent, mousePressX, mousePressY, mouseX, mouseY, mouseDeltaX, mouseDeltaY); } else if (doZFlag) { ViewingTransformations* viewingTransform = tabContent->getViewingTransformation(); Matrix4x4 rotationMatrix = viewingTransform->getRotationMatrix(); rotationMatrix.rotateZ(incrementalRotation); viewingTransform->setRotationMatrix(rotationMatrix); } updateGraphics(); updateUserInterface(); return true; } connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationIncrementRotation.h000066400000000000000000000044771360521144700276330ustar00rootroot00000000000000#ifndef __WB_MACRO_CUSTOM_OPERATION_INCREMENT_ROTATION_H__ #define __WB_MACRO_CUSTOM_OPERATION_INCREMENT_ROTATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "WbMacroCustomOperationBase.h" namespace caret { class BrowserTabContent; class WbMacroCustomOperationIncrementRotation : public WbMacroCustomOperationBase { public: WbMacroCustomOperationIncrementRotation(); virtual ~WbMacroCustomOperationIncrementRotation(); WbMacroCustomOperationIncrementRotation(const WbMacroCustomOperationIncrementRotation&) = delete; WbMacroCustomOperationIncrementRotation& operator=(const WbMacroCustomOperationIncrementRotation&) = delete; virtual bool executeCommand(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand) override; virtual WuQMacroCommand* createCommand() override; // ADD_NEW_METHODS_HERE private: enum class Axis { X, Y, Z }; // ADD_NEW_MEMBERS_HERE }; #ifdef __WB_MACRO_CUSTOM_OPERATION_INCREMENT_ROTATION_DECLARE__ // #endif // __WB_MACRO_CUSTOM_OPERATION_INCREMENT_ROTATION_DECLARE__ } // namespace #endif //__WB_MACRO_CUSTOM_OPERATION_INCREMENT_ROTATION_H__ connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationIncrementVolumeSlice.cxx000066400000000000000000000152151360521144700306260ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WB_MACRO_CUSTOM_OPERATION_INCREMENT_VOLUME_SLICE_DECLARE__ #include "WbMacroCustomOperationIncrementVolumeSlice.h" #undef __WB_MACRO_CUSTOM_OPERATION_INCREMENT_VOLUME_SLICE_DECLARE__ #include "BrainBrowserWindow.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "Matrix4x4.h" #include "Model.h" #include "ModelVolume.h" #include "ModelWholeBrain.h" #include "SystemUtilities.h" #include "ViewingTransformations.h" #include "WbMacroCustomDataTypeEnum.h" #include "WbMacroCustomOperationTypeEnum.h" #include "WuQMacroCommand.h" #include "WuQMacroCommandParameter.h" #include "WuQMacroExecutorMonitor.h" using namespace caret; /** * \class caret::WbMacroCustomOperationIncrementVolumeSlice * \brief Macro custom operation for incremental rotation * \ingroup GuiQt */ /** * Constructor. */ WbMacroCustomOperationIncrementVolumeSlice::WbMacroCustomOperationIncrementVolumeSlice() : WbMacroCustomOperationBase(WbMacroCustomOperationTypeEnum::INCREMENTAL_VOLUME_SLICE) { } /** * Destructor. */ WbMacroCustomOperationIncrementVolumeSlice::~WbMacroCustomOperationIncrementVolumeSlice() { } /** * Get a new instance of the macro command * * @return * Pointer to command or NULL if not valid * Use getErrorMessage() for error information if NULL returned */ WuQMacroCommand* WbMacroCustomOperationIncrementVolumeSlice::createCommand() { const int32_t versionOne(1); QString errorMessage; WuQMacroCommand* command = WuQMacroCommand::newInstanceCustomCommand(WbMacroCustomOperationTypeEnum::toName(getOperationType()), versionOne, "none", WbMacroCustomOperationTypeEnum::toGuiName(getOperationType()), "Increment Volume Slice", 1.0, errorMessage); if (command != NULL) { command->addParameter(WuQMacroDataValueTypeEnum::INTEGER, "Increment Slice Index By", (int)1); } else { appendToErrorMessage(errorMessage); } return command; } /** * Execute the macro command * * @param parent * Parent widget for any dialogs * @param executorMonitor * the macro executor monitor * @param executorOptions * Options for executor * @param macroCommand * macro command to run * @return * True if command executed successfully, else false * Use getErrorMessage() for error information if false returned */ bool WbMacroCustomOperationIncrementVolumeSlice::executeCommand(QWidget* parent, const WuQMacroExecutorMonitor* /*executorMonitor*/, const WuQMacroExecutorOptions* /*executorOptions*/, const WuQMacroCommand* macroCommand) { CaretAssert(parent); CaretAssert(macroCommand); if ( ! validateCorrectNumberOfParameters(macroCommand, 1)) { return false; } const float incrementSlice = macroCommand->getParameterAtIndex(0)->getValue().toFloat(); BrainBrowserWindow* bbw = qobject_cast(parent); if (bbw == NULL) { appendToErrorMessage("Parent for running macro is not a browser window."); return false; } BrowserTabContent* tabContent = bbw->getBrowserTabContent(); if (tabContent == NULL) { appendToErrorMessage("No tab is selected in browser window."); return false; } const int32_t tabIndex = tabContent->getTabNumber(); VolumeMappableInterface* underlayVolumeFile(NULL); ModelVolume* volumeModel = tabContent->getDisplayedVolumeModel(); if (volumeModel != NULL) { underlayVolumeFile = volumeModel->getUnderlayVolumeFile(tabIndex); } ModelWholeBrain* wholeBrainModel = tabContent->getDisplayedWholeBrainModel(); if (wholeBrainModel != NULL) { underlayVolumeFile = wholeBrainModel->getUnderlayVolumeFile(tabIndex); } if (underlayVolumeFile == NULL) { appendToErrorMessage("Must have ALL or Volume view for slice increment or no volume is displayed."); return false; } int32_t sliceIndexAxial = tabContent->getSliceIndexAxial(underlayVolumeFile); int32_t sliceIndexCoronal = tabContent->getSliceIndexCoronal(underlayVolumeFile); int32_t sliceIndexParasagittal = tabContent->getSliceIndexParasagittal(underlayVolumeFile); VolumeSliceViewPlaneEnum::Enum slicePlane = tabContent->getSliceViewPlane(); switch (slicePlane) { case VolumeSliceViewPlaneEnum::ALL: sliceIndexAxial += incrementSlice; sliceIndexCoronal += incrementSlice; sliceIndexParasagittal += incrementSlice; break; case VolumeSliceViewPlaneEnum::AXIAL: sliceIndexAxial += incrementSlice; break; case VolumeSliceViewPlaneEnum::CORONAL: sliceIndexCoronal += incrementSlice; break; case VolumeSliceViewPlaneEnum::PARASAGITTAL: sliceIndexParasagittal += incrementSlice; break; } tabContent->setSliceIndexAxial(underlayVolumeFile, sliceIndexAxial); tabContent->setSliceIndexCoronal(underlayVolumeFile, sliceIndexCoronal); tabContent->setSliceIndexParasagittal(underlayVolumeFile, sliceIndexParasagittal); updateGraphics(); updateUserInterface(); return true; } connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationIncrementVolumeSlice.h000066400000000000000000000045501360521144700302530ustar00rootroot00000000000000#ifndef __WB_MACRO_CUSTOM_OPERATION_INCREMENT_VOLUME_SLICE_H__ #define __WB_MACRO_CUSTOM_OPERATION_INCREMENT_VOLUME_SLICE_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "WbMacroCustomOperationBase.h" namespace caret { class BrowserTabContent; class WbMacroCustomOperationIncrementVolumeSlice : public WbMacroCustomOperationBase { public: WbMacroCustomOperationIncrementVolumeSlice(); virtual ~WbMacroCustomOperationIncrementVolumeSlice(); WbMacroCustomOperationIncrementVolumeSlice(const WbMacroCustomOperationIncrementVolumeSlice&) = delete; WbMacroCustomOperationIncrementVolumeSlice& operator=(const WbMacroCustomOperationIncrementVolumeSlice&) = delete; virtual bool executeCommand(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand) override; virtual WuQMacroCommand* createCommand() override; // ADD_NEW_METHODS_HERE private: enum class Axis { X, Y, Z }; // ADD_NEW_MEMBERS_HERE }; #ifdef __WB_MACRO_CUSTOM_OPERATION_INCREMENT_VOLUME_SLICE_DECLARE__ // #endif // __WB_MACRO_CUSTOM_OPERATION_INCREMENT_VOLUME_SLICE_DECLARE__ } // namespace #endif //__WB_MACRO_CUSTOM_OPERATION_INCREMENT_VOLUME_SLICE_H__ connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationManager.cxx000066400000000000000000000707651360521144700261170ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WB_MACRO_CUSTOM_OPERATION_MANAGER_DECLARE__ #include "WbMacroCustomOperationManager.h" #undef __WB_MACRO_CUSTOM_OPERATION_MANAGER_DECLARE__ #include #include "BrainBrowserWindow.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretMappableDataFile.h" #include "EventCaretMappableDataFilesGet.h" #include "EventManager.h" #include "EventSurfacesGet.h" #include "GuiManager.h" #include "Overlay.h" #include "OverlaySet.h" #include "Surface.h" #include "WbMacroCustomDataTypeEnum.h" #include "WbMacroCustomOperationDelay.h" #include "WbMacroCustomOperationAnimateRotation.h" #include "WbMacroCustomOperationAnimateOverlayCrossFade.h" #include "WbMacroCustomOperationAnimateSurfaceInterpolation.h" #include "WbMacroCustomOperationTypeEnum.h" #include "WbMacroCustomOperationAnimateVolumeSliceSequence.h" #include "WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade.h" #include "WbMacroCustomOperationIncrementRotation.h" #include "WbMacroCustomOperationIncrementVolumeSlice.h" #include "WbMacroCustomDataInfo.h" #include "WuQMacroCommand.h" #include "WuQMacroCommandParameter.h" #include "WuQMessageBox.h" using namespace caret; /** * \class caret::WbMacroCustomOperationManager * \brief Mananager for macro custom operations * \ingroup GuiQt */ /** * Constructor. */ WbMacroCustomOperationManager::WbMacroCustomOperationManager() : CaretObject() { } /** * Destructor. */ WbMacroCustomOperationManager::~WbMacroCustomOperationManager() { } /** * Get a description of this object's content. * @return String describing this object's content. */ AString WbMacroCustomOperationManager::toString() const { return "WbMacroCustomOperationManager"; } /** * Get names of all surfaces * * @param surfaceNamesOut * Output with names of surfaces * @param errorMessageOut * Ouput with error messages * @return * True if surface names are valid, else false */ bool WbMacroCustomOperationManager::getSurfaceNames(std::vector& surfaceNamesOut, QString& errorMessageOut) { surfaceNamesOut.clear(); EventSurfacesGet surfacesEvent; EventManager::get()->sendEvent(surfacesEvent.getPointer()); std::vector surfaces = surfacesEvent.getSurfaces(); bool okFlag(false); if (surfaces.empty()) { errorMessageOut = "There are no surfaces available"; } else { for (const auto s : surfaces) { surfaceNamesOut.push_back(s->getFileNameNoPath()); } okFlag = true; } return okFlag; } /** * Get mappable files selection info * * @param macroCommand * Macro command containing parameter being edited * @param overlayFileParameter * Parameter for overlay file selection * @param mapNameParameter * Parameter for map name selection * @param mapFileNamesOut * Output with map file names * @param selectedFileNameOut * Output with name of selected file * @param mapNamesOut * Output with name of maps in selected file * @param selectedMapNameOut * Name of selected map * @param errorMessageOut * Output error message if finding map files fails * @return * True if map file names valid */ bool WbMacroCustomOperationManager::getMappableFilesSelection(WuQMacroCommand* macroCommand, WuQMacroCommandParameter* overlayFileParameterIn, WuQMacroCommandParameter* mapParameterIn, std::vector& mapFileNamesOut, QString& selectedFileNameOut, std::vector& mapNamesOut, QString& selectedMapNameOut, QString& errorMessageOut) { CaretAssert(macroCommand); mapFileNamesOut.clear(); selectedFileNameOut.clear(); mapNamesOut.clear(); selectedMapNameOut.clear(); errorMessageOut.clear(); WuQMacroCommandParameter* fileParameter = overlayFileParameterIn; WuQMacroCommandParameter* mapParameter = mapParameterIn; if ((fileParameter != NULL) && (mapParameter != NULL)) { /* OK, have both */ } else { /* * Map selection parameter should be immediately after file selection parameter */ int32_t fileParameterIndex(-1); int32_t mapParameterIndex(-1); if (fileParameter != NULL) { fileParameterIndex = macroCommand->getIndexOfParameter(fileParameter); mapParameterIndex = fileParameterIndex + 1; } else if (mapParameter != NULL) { mapParameterIndex = macroCommand->getIndexOfParameter(mapParameter); fileParameterIndex = mapParameterIndex - 1; } else { errorMessageOut = "Both overlay file and map parameter are NULL, one must be valid"; return false; } if ((fileParameterIndex < 0) || (fileParameterIndex >= macroCommand->getNumberOfParameters())) { errorMessageOut.append("Unable to find file parameter. "); } if ((mapParameterIndex < 0) || (mapParameterIndex >= macroCommand->getNumberOfParameters())) { errorMessageOut.append("Unable to find map parameter. "); } if ( ! errorMessageOut.isEmpty()) { return false; } fileParameter = macroCommand->getParameterAtIndex(fileParameterIndex); mapParameter = macroCommand->getParameterAtIndex(mapParameterIndex); } CaretAssert(fileParameter); CaretAssert(mapParameter); bool validFileParamFlag(false); const WbMacroCustomDataTypeEnum::Enum overlayParamType = WbMacroCustomDataTypeEnum::fromName(fileParameter->getCustomDataType(), &validFileParamFlag); if (overlayParamType != WbMacroCustomDataTypeEnum::OVERLAY_FILE_NAME_OR_FILE_INDEX) { errorMessageOut.append("Overlay file parameter is not of type OVERLAY_FILE_NAME_OR_FILE_INDEX. "); } bool validMapNameParamFlag(false); const WbMacroCustomDataTypeEnum::Enum mapParamType = WbMacroCustomDataTypeEnum::fromName(mapParameter->getCustomDataType(), &validMapNameParamFlag); if (mapParamType != WbMacroCustomDataTypeEnum::OVERLAY_MAP_NAME_OR_MAP_INDEX) { errorMessageOut.append("Overlay map parameter is not of type OVERLAY_MAP_NAME_OR_MAP_INDEX. "); } if ( ! errorMessageOut.isEmpty()) { return false; } const QString selectedFileName = fileParameter->getValue().toString(); const QString selectedMapName = mapParameter->getValue().toString(); CaretMappableDataFile* selectedFile(NULL); EventCaretMappableDataFilesGet mapFilesEvent; EventManager::get()->sendEvent(mapFilesEvent.getPointer()); std::vector allFiles; mapFilesEvent.getAllFiles(allFiles); if ( ! allFiles.empty()) { for (auto mf : allFiles) { CaretAssert(mf); const QString name(mf->getFileNameNoPath()); if ( ! selectedFileName.isEmpty()) { if (name == selectedFileName) { selectedFile = mf; } } mapFileNamesOut.push_back(name); } if (selectedFile == NULL) { CaretAssertVectorIndex(allFiles, 0); selectedFile = allFiles[0]; } CaretAssert(selectedFile); selectedFileNameOut = selectedFile->getFileNameNoPath(); bool selectedMapNameFoundFlag(false); const int32_t numMaps = selectedFile->getNumberOfMaps(); for (int32_t i = 0; i < numMaps; i++) { const QString name(selectedFile->getMapName(i)); if ( ! selectedMapName.isEmpty()) { if (selectedMapName == name) { selectedMapNameFoundFlag = true; } } mapNamesOut.push_back(name); } if (selectedMapNameFoundFlag) { selectedMapNameOut = selectedMapName; } else { if (selectedFile->getNumberOfMaps() > 0) { selectedMapNameOut = selectedFile->getMapName(0); } } } /** * Selection may change. For example, if the selected overlay file * is changed, the selected map name is likely to change so that * it is a map that is in the new file and was not in the previous file */ if (selectedFileNameOut != fileParameter->getValue().toString()) { fileParameter->setValue(selectedFileNameOut); } if (selectedMapNameOut != mapParameter->getValue().toString()) { mapParameter->setValue(selectedMapNameOut); } return true; } /** * Get the map file in the overlay for this command * * @param browserWindowIndex * Index of browser window * @param macroCommand * Macro command containing parameter being edited * @param overlayFileParameter * Parameter for overlay file. Note that index of the overlay * will be obtained from the most previous parameter that is of * type OVERLAY_INDEX. * @param mapFileNamesOut * Output with map file names * @param selectedMapFileOut * Map file selected in overlay or NULL if none selected * @param selectedMapFileMapNamesOut * Names of maps in selected map file, empty if no map file * @param errorMessageOut * Output error message if finding map files fails * @return * True if map file names valid */ bool WbMacroCustomOperationManager::getOverlayContents(const int32_t browserWindowIndex, const WuQMacroCommand* macroCommand, const WuQMacroCommandParameter* overlayFileParameter, std::vector& mapFileNamesOut, CaretMappableDataFile* &selectedMapFileOut, std::vector& selectedMapFileMapNamesOut, QString& errorMessageOut) { CaretAssert(macroCommand); CaretAssert(overlayFileParameter); mapFileNamesOut.clear(); selectedMapFileOut = NULL; selectedMapFileMapNamesOut.clear(); /* * Find the overlay index parameter that should be before this parameter */ const int32_t parameterIndex = macroCommand->getIndexOfParameter(overlayFileParameter); if (parameterIndex < 0) { errorMessageOut = "Parameter is invalid for command"; return false; } int32_t overlayIndex(-1); for (int32_t ip = (parameterIndex - 1); ip >= 0; --ip) { const WuQMacroCommandParameter* p = macroCommand->getParameterAtIndex(ip); if (p->getDataType() == WuQMacroDataValueTypeEnum::INTEGER) { bool valid(false); WbMacroCustomDataTypeEnum::Enum customType = WbMacroCustomDataTypeEnum::fromName(p->getCustomDataType(), &valid); if (valid) { if (customType == WbMacroCustomDataTypeEnum::OVERLAY_INDEX) { overlayIndex = p->getValue().toInt(); break; } } } } /* * Overlay index is 1..N for user so need to decrement */ if (overlayIndex < 1) { errorMessageOut = "Unable to find overlay index"; return false; } --overlayIndex; BrowserTabContent* tabContent = getTabContent(browserWindowIndex, errorMessageOut); if (tabContent == NULL) { errorMessageOut = "Unable to find tab content"; return false; } Overlay* overlay = tabContent->getOverlaySet()->getOverlay(overlayIndex); if (overlay == NULL) { errorMessageOut = ("Overlay " + AString::number(overlayIndex) + " not found"); return false; } int32_t selectedMapIndex(-1); std::vector mapFiles; CaretMappableDataFile* selectedMapFile(NULL); overlay->getSelectionData(mapFiles, selectedMapFile, selectedMapIndex); if (mapFiles.empty()) { errorMessageOut = "The overlay does not contain any files"; return false; } selectedMapFileOut = selectedMapFile; for (const auto mf : mapFiles) { mapFileNamesOut.push_back(mf->getFileNameNoPath()); } if (selectedMapFileOut != NULL) { const int32_t numMaps = selectedMapFileOut->getNumberOfMaps(); for (int32_t i = 0; i < numMaps; i++) { selectedMapFileMapNamesOut.push_back(selectedMapFileOut->getMapName(i)); } } return true; } /** * Get info for data in a custom parameter * * @param browserWindowIndex * Index of browser window * @param macroCommand * Macro command that contains the parameter * @param parameter * Parameter for info * @param dataInfo * Updated with data info in this method * @return * True if the data info is valid */ bool WbMacroCustomOperationManager::getCustomParameterDataInfo(const int32_t /*browserWindowIndex*/, WuQMacroCommand* macroCommand, WuQMacroCommandParameter* parameter, WbMacroCustomDataInfo& dataInfoOut) { CaretAssert(macroCommand); CaretAssert(parameter); const QString customTypeName(parameter->getCustomDataType()); bool customTypeNameValid(false); const WbMacroCustomDataTypeEnum::Enum userType = WbMacroCustomDataTypeEnum::fromName(customTypeName, &customTypeNameValid); if ( ! customTypeNameValid) { CaretLogSevere("\"" + customTypeName + "\" is not a valid name for a custom parameter"); return false; } const QString dataTypeName(WuQMacroDataValueTypeEnum::toName(dataInfoOut.getDataType())); bool unsupportedFlag(false); switch (dataInfoOut.getDataType()) { case WuQMacroDataValueTypeEnum::AXIS: unsupportedFlag = true; break; case WuQMacroDataValueTypeEnum::BOOLEAN: unsupportedFlag = true; break; case WuQMacroDataValueTypeEnum::FLOAT: break; case WuQMacroDataValueTypeEnum::INTEGER: break; case WuQMacroDataValueTypeEnum::INVALID: unsupportedFlag = true; break; case WuQMacroDataValueTypeEnum::MOUSE: unsupportedFlag = true; break; case WuQMacroDataValueTypeEnum::NONE: unsupportedFlag = true; break; case WuQMacroDataValueTypeEnum::STRING: unsupportedFlag = true; break; case WuQMacroDataValueTypeEnum::STRING_LIST: break; } if (unsupportedFlag) { CaretLogSevere("Unsupported data type for parameter info " + WuQMacroDataValueTypeEnum::toName(dataInfoOut.getDataType())); return false; } bool validFlag(false); QString errorMessage("Unknown error"); QString invalidTypeName; switch (userType) { case WbMacroCustomDataTypeEnum::OVERLAY_INDEX: if (dataInfoOut.getDataType() == WuQMacroDataValueTypeEnum::INTEGER) { std::array dataRange { 1, BrainConstants::MAXIMUM_NUMBER_OF_OVERLAYS }; dataInfoOut.setIntegerRange(dataRange); validFlag = true; } else { invalidTypeName = WuQMacroDataValueTypeEnum::toName(WuQMacroDataValueTypeEnum::INTEGER); } break; case WbMacroCustomDataTypeEnum::OVERLAY_FILE_NAME_OR_FILE_INDEX: if (dataInfoOut.getDataType() == WuQMacroDataValueTypeEnum::STRING_LIST) { std::vector filenames; std::vector mapNames; QString selectedFileName; QString selectedMapName; if (getMappableFilesSelection(macroCommand, parameter, NULL, filenames, selectedFileName, mapNames, selectedMapName, errorMessage)) { dataInfoOut.setStringListValues(filenames); validFlag = true; } } else { invalidTypeName = WuQMacroDataValueTypeEnum::toName(WuQMacroDataValueTypeEnum::STRING_LIST); } break; case WbMacroCustomDataTypeEnum::OVERLAY_MAP_NAME_OR_MAP_INDEX: if (dataInfoOut.getDataType() == WuQMacroDataValueTypeEnum::STRING_LIST) { std::vector filenames; std::vector mapNames; QString selectedFileName; QString selectedMapName; if (getMappableFilesSelection(macroCommand, NULL, parameter, filenames, selectedFileName, mapNames, selectedMapName, errorMessage)) { dataInfoOut.setStringListValues(mapNames); validFlag = true; } } else { invalidTypeName = WuQMacroDataValueTypeEnum::toName(WuQMacroDataValueTypeEnum::STRING_LIST); } break; case WbMacroCustomDataTypeEnum::SURFACE: if (dataInfoOut.getDataType() == WuQMacroDataValueTypeEnum::STRING_LIST) { std::vector surfaceNames; if (getSurfaceNames(surfaceNames, errorMessage)) { dataInfoOut.setStringListValues(surfaceNames); validFlag = true; } } else { invalidTypeName = WuQMacroDataValueTypeEnum::toName(WuQMacroDataValueTypeEnum::STRING_LIST); } break; } if ( ! validFlag) { if ( ! invalidTypeName.isEmpty()) { errorMessage = ("Custom parameter " + customTypeName + " data type should be " + invalidTypeName + " but is " + dataTypeName); } CaretLogSevere(errorMessage); } return validFlag; } /** * Run a custom-defined macro command * * @param parent * Parent widget for any dialogs * @param executorMonitor * The executor monitor * @param executorOptions * Options for the executor * @param customMacroCommand * Custom macro command to run * @param errorMessageOut * Contains any error information or empty if no error * @return * True if command executed successfully, else false */ bool WbMacroCustomOperationManager::executeCustomOperationMacroCommand(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* customMacroCommand, QString& errorMessageOut) { CaretAssert(parent); CaretAssert(customMacroCommand); errorMessageOut.clear(); if (customMacroCommand->getCommandType() != WuQMacroCommandTypeEnum::CUSTOM_OPERATION) { errorMessageOut = "Requesting non-custom command execution in user-executor"; return false; } const QString customCommandName(customMacroCommand->getCustomOperationTypeName()); bool nameValid(false); const WbMacroCustomOperationTypeEnum::Enum commandType = WbMacroCustomOperationTypeEnum::fromName(customCommandName, &nameValid); if ( ! nameValid) { errorMessageOut = ("\"" + customCommandName + "\" is not a valid name for a custom macro command"); return false; } std::unique_ptr customOperation; customOperation.reset(createCommand(commandType)); bool successFlag(false); if (customOperation) { successFlag = customOperation->executeCommand(parent, executorMonitor, executorOptions, customMacroCommand); if ( ! successFlag) { errorMessageOut = customOperation->getErrorMessage(); } } else { errorMessageOut = "Custom Operation is missing"; CaretLogSevere(errorMessageOut); } return successFlag; } /** * @return Names of custom operation defined macro commands */ std::vector WbMacroCustomOperationManager::getNamesOfCustomOperationMacroCommands() { std::vector names; WbMacroCustomOperationTypeEnum::getAllNames(names, true); std::vector namesOut(names.begin(), names.end()); return namesOut; } /** * @return All custom operation commands. Caller is responsible for deleting * all content of the returned vector. */ std::vector WbMacroCustomOperationManager::getAllCustomOperationMacroCommands() { std::vector customCommandTypes; WbMacroCustomOperationTypeEnum::getAllEnums(customCommandTypes); std::vector customCommands; for (auto cct : customCommandTypes) { if (cct == WbMacroCustomOperationTypeEnum::ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE) { continue; } std::unique_ptr customOperation(createCommand(cct)); customCommands.push_back(customOperation->createCommand()); } return customCommands; } /** * Get a new instance of a custom operation for the given macro command name * * @param customMacroCommandName * Name of custom macro command * @param errorMessageOut * Contains any error information or empty if no error * @return * Pointer to command or NULL if not valid */ WuQMacroCommand* WbMacroCustomOperationManager::newInstanceOfCustomOperationMacroCommand(const QString& customMacroCommandName, QString& errorMessageOut) { errorMessageOut.clear(); bool nameValid(false); const WbMacroCustomOperationTypeEnum::Enum commandType = WbMacroCustomOperationTypeEnum::fromName(customMacroCommandName, &nameValid); if ( ! nameValid) { errorMessageOut = ("\"" + customMacroCommandName + "\" is not a valid name for a custom macro command"); return NULL; } WuQMacroCommand* command(NULL); std::unique_ptr customOperation; customOperation.reset(createCommand(commandType)); if (customOperation) { command = customOperation->createCommand(); if (command == NULL) { errorMessageOut = customOperation->getErrorMessage(); } } else { errorMessageOut = "Custom Operation is missing"; CaretLogSevere(errorMessageOut); } return command; } /** * Create a custom operation of the given type * * @param operationType * The operation type * @return * New instance of command caller is responsible for destroying */ WbMacroCustomOperationBase* WbMacroCustomOperationManager::createCommand(const WbMacroCustomOperationTypeEnum::Enum operationType) { WbMacroCustomOperationBase* operationOut(NULL); switch (operationType) { case WbMacroCustomOperationTypeEnum::DELAY: operationOut = new WbMacroCustomOperationDelay(); break; case WbMacroCustomOperationTypeEnum::ANIMATE_ROTATION: operationOut = new WbMacroCustomOperationAnimateRotation(); break; case WbMacroCustomOperationTypeEnum::ANIMATE_OVERLAY_CROSS_FADE: operationOut = new WbMacroCustomOperationAnimateOverlayCrossFade(); break; case WbMacroCustomOperationTypeEnum::ANIMATE_SURFACE_INTERPOLATION: operationOut = new WbMacroCustomOperationAnimateSurfaceInterpolation(); break; case WbMacroCustomOperationTypeEnum::ANIMATE_VOLUME_SLICE_SEQUENCE: operationOut = new WbMacroCustomOperationAnimateVolumeSliceSequence(); break; case WbMacroCustomOperationTypeEnum::ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE: operationOut = new WbMacroCustomOperationAnimateVolumeToSurfaceCrossFade(); break; case WbMacroCustomOperationTypeEnum::INCREMENTAL_ROTATION: operationOut = new WbMacroCustomOperationIncrementRotation(); break; case WbMacroCustomOperationTypeEnum::INCREMENTAL_VOLUME_SLICE: operationOut = new WbMacroCustomOperationIncrementVolumeSlice(); break; } CaretAssert(operationOut); return operationOut; } /** * Get the active tab content in the active window. If there is more * than one window open, the user is prompted to select a window * * @param browserWindowIndex * Widget for any dialogs * @param errorMessageOut * Output with error information if failure * @return * Pointer to active tab content or none found */ BrowserTabContent* WbMacroCustomOperationManager::getTabContent(const int32_t browserWindowIndex, QString& errorMessageOut) { errorMessageOut.clear(); const std::vector allWindows = GuiManager::get()->getAllOpenBrainBrowserWindows(); if (allWindows.empty()) { errorMessageOut = "No window are open. This should never happen."; return NULL; } BrowserTabContent* tabContent(NULL); BrainBrowserWindow* bbw(NULL); if (allWindows.size() == 1) { CaretAssertVectorIndex(allWindows, 0); bbw = allWindows[0]; } else { for (auto w : allWindows) { if (w->getBrowserWindowIndex() == browserWindowIndex) { bbw = w; break; } } } if (bbw != NULL) { tabContent = bbw->getBrowserTabContent(); } else { errorMessageOut = "Failed to find window selected by user"; } return tabContent; } connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationManager.h000066400000000000000000000113171360521144700255300ustar00rootroot00000000000000#ifndef __WB_MACRO_CUSTOM_OPERATION_MANAGER_H__ #define __WB_MACRO_CUSTOM_OPERATION_MANAGER_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" #include "WbMacroCustomOperationTypeEnum.h" #include "WuQMacroCustomOperationManagerInterface.h" class QWidget; namespace caret { class BrowserTabContent; class CaretMappableDataFile; class WbMacroCustomOperationBase; class WuQMacroCommand; class WuQMacroCommandParameter; class WbMacroCustomOperationManager : public CaretObject, public WuQMacroCustomOperationManagerInterface { public: WbMacroCustomOperationManager(); virtual ~WbMacroCustomOperationManager(); WbMacroCustomOperationManager(const WbMacroCustomOperationManager&) = delete; WbMacroCustomOperationManager& operator=(const WbMacroCustomOperationManager&) = delete; virtual bool getCustomParameterDataInfo(const int32_t browserWindowIndex, WuQMacroCommand* macroCommand, WuQMacroCommandParameter* parameter, WbMacroCustomDataInfo& dataInfoOut) override; virtual bool executeCustomOperationMacroCommand(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand, QString& errorMessageOut) override; virtual std::vector getNamesOfCustomOperationMacroCommands() override; virtual std::vector getAllCustomOperationMacroCommands() override; virtual WuQMacroCommand* newInstanceOfCustomOperationMacroCommand(const QString& customMacroCommandName, QString& errorMessageOut) override; // ADD_NEW_METHODS_HERE virtual AString toString() const; private: WbMacroCustomOperationBase* createCommand(const WbMacroCustomOperationTypeEnum::Enum operationType); bool getSurfaceNames(std::vector& surfaceNamesOut, QString& errorMessageOut); bool getOverlayContents(const int32_t browserWindowIndex, const WuQMacroCommand* macroCommand, const WuQMacroCommandParameter* overlayFileParameter, std::vector& mapFileNamesOut, CaretMappableDataFile* &selectedMapFileOut, std::vector& selectedMapFileMapNamesOut, QString& errorMessageOut); bool getMappableFilesSelection(WuQMacroCommand* macroCommand, WuQMacroCommandParameter* overlayFileParameter, WuQMacroCommandParameter* mapParameter, std::vector& mapFileNamesOut, QString& selectedFileNameOut, std::vector& mapNamesOut, QString& selectedMapNameOut, QString& errorMessageOut); BrowserTabContent* getTabContent(const int32_t browserWindowIndex, QString& errorMessageOut); // ADD_NEW_MEMBERS_HERE }; #ifdef __WB_MACRO_CUSTOM_OPERATION_MANAGER_DECLARE__ // #endif // __WB_MACRO_CUSTOM_OPERATION_MANAGER_DECLARE__ } // namespace #endif //__WB_MACRO_CUSTOM_OPERATION_MANAGER_H__ connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationTypeEnum.cxx000066400000000000000000000330441360521144700263000ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __WB_MACRO_CUSTOM_OPERATION_TYPE_ENUM_DECLARE__ #include "WbMacroCustomOperationTypeEnum.h" #undef __WB_MACRO_CUSTOM_OPERATION_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::WbMacroCustomOperationTypeEnum * \brief Enumerated type for a user defined macro command * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_WbMacroCustomOperationTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void WbMacroCustomOperationTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "WbMacroCustomOperationTypeEnum.h" * * Instatiate: * m_WbMacroCustomOperationTypeEnumComboBox = new EnumComboBoxTemplate(this); * m_WbMacroCustomOperationTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_WbMacroCustomOperationTypeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(WbMacroCustomOperationTypeEnumComboBoxItemActivated())); * * Update the selection: * m_WbMacroCustomOperationTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const WbMacroCustomOperationTypeEnum::Enum VARIABLE = m_WbMacroCustomOperationTypeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ WbMacroCustomOperationTypeEnum::WbMacroCustomOperationTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ WbMacroCustomOperationTypeEnum::~WbMacroCustomOperationTypeEnum() { } /** * Initialize the enumerated metadata. */ void WbMacroCustomOperationTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(WbMacroCustomOperationTypeEnum(ANIMATE_ROTATION, "ANIMATE_ROTATION", "Animate Rotation")); enumData.push_back(WbMacroCustomOperationTypeEnum(ANIMATE_OVERLAY_CROSS_FADE, "ANIMATE_OVERLAY_CROSS_FADE", "Animate Overlay CrossFade")); enumData.push_back(WbMacroCustomOperationTypeEnum(ANIMATE_SURFACE_INTERPOLATION, "ANIMATE_SURFACE_INTERPOLATION", "Animate Surface Interpolation")); enumData.push_back(WbMacroCustomOperationTypeEnum(ANIMATE_VOLUME_SLICE_SEQUENCE, "ANIMATE_VOLUME_SLICE_SEQUENCE", "Animate Volume Slice Sequence")); enumData.push_back(WbMacroCustomOperationTypeEnum(ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE, "ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE", "Animate Volume to Surface Cross Fade")); enumData.push_back(WbMacroCustomOperationTypeEnum(DELAY, "DELAY", "Delay")); enumData.push_back(WbMacroCustomOperationTypeEnum(INCREMENTAL_ROTATION, "INCREMENTAL_ROTATION", "Incremental Rotation")); enumData.push_back(WbMacroCustomOperationTypeEnum(INCREMENTAL_VOLUME_SLICE, "INCREMENTAL_VOLUME_SLICE", "Increment Volume Slice")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const WbMacroCustomOperationTypeEnum* WbMacroCustomOperationTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const WbMacroCustomOperationTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WbMacroCustomOperationTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const WbMacroCustomOperationTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WbMacroCustomOperationTypeEnum::Enum WbMacroCustomOperationTypeEnum::fromName(const AString& nameIn, bool* isValidOut) { if (initializedFlag == false) initialize(); AString name(nameIn); /* * Convert old names for operations that were renamed */ if (nameIn == "MODEL_ROTATION") { name = WbMacroCustomOperationTypeEnum::toName(WbMacroCustomOperationTypeEnum::ANIMATE_ROTATION); } else if (nameIn == "OVERLAY_CROSS_FADE") { name = WbMacroCustomOperationTypeEnum::toName(WbMacroCustomOperationTypeEnum::ANIMATE_OVERLAY_CROSS_FADE); } else if (nameIn == "SURFACE_INTERPOLATION") { name = WbMacroCustomOperationTypeEnum::toName(WbMacroCustomOperationTypeEnum::ANIMATE_SURFACE_INTERPOLATION); } else if (nameIn == "VOLUME_SLICE_INCREMENT") { name = WbMacroCustomOperationTypeEnum::toName(WbMacroCustomOperationTypeEnum::ANIMATE_VOLUME_SLICE_SEQUENCE); } else if (nameIn == "VOLUME_TO_SURFACE_CROSS_FADE") { name = WbMacroCustomOperationTypeEnum::toName(WbMacroCustomOperationTypeEnum::ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE); } bool validFlag = false; Enum enumValue = WbMacroCustomOperationTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WbMacroCustomOperationTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type WbMacroCustomOperationTypeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString WbMacroCustomOperationTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const WbMacroCustomOperationTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ WbMacroCustomOperationTypeEnum::Enum WbMacroCustomOperationTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WbMacroCustomOperationTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WbMacroCustomOperationTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type WbMacroCustomOperationTypeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t WbMacroCustomOperationTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const WbMacroCustomOperationTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ WbMacroCustomOperationTypeEnum::Enum WbMacroCustomOperationTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = WbMacroCustomOperationTypeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const WbMacroCustomOperationTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type WbMacroCustomOperationTypeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void WbMacroCustomOperationTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WbMacroCustomOperationTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(WbMacroCustomOperationTypeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void WbMacroCustomOperationTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(WbMacroCustomOperationTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/GuiQt/WbMacroCustomOperationTypeEnum.h000066400000000000000000000073201360521144700257230ustar00rootroot00000000000000#ifndef __WB_MACRO_CUSTOM_OPERATION_TYPE_ENUM_H__ #define __WB_MACRO_CUSTOM_OPERATION_TYPE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class WbMacroCustomOperationTypeEnum { public: /** * Enumerated values. */ enum Enum { /** Animate rotation of viewed model */ ANIMATE_ROTATION, /** Animate CrossFade of overlays */ ANIMATE_OVERLAY_CROSS_FADE, /** Animate Surface Interpolation */ ANIMATE_SURFACE_INTERPOLATION, /** Animate Volume slice sequence */ ANIMATE_VOLUME_SLICE_SEQUENCE, /** Animate Volume to surface cross fade */ ANIMATE_VOLUME_TO_SURFACE_CROSS_FADE, /** Delay **/ DELAY, /** Incremental Rotation */ INCREMENTAL_ROTATION, /** Increment volume slice */ INCREMENTAL_VOLUME_SLICE }; ~WbMacroCustomOperationTypeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: WbMacroCustomOperationTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const WbMacroCustomOperationTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __WB_MACRO_CUSTOM_OPERATION_TYPE_ENUM_DECLARE__ std::vector WbMacroCustomOperationTypeEnum::enumData; bool WbMacroCustomOperationTypeEnum::initializedFlag = false; int32_t WbMacroCustomOperationTypeEnum::integerCodeCounter = 0; #endif // __WB_MACRO_CUSTOM_OPERATION_TYPE_ENUM_DECLARE__ } // namespace #endif //__WB_MACRO_CUSTOM_OPERATION_TYPE_ENUM_H__ connectome-workbench-1.4.2/src/GuiQt/WbMacroHelper.cxx000066400000000000000000000347741360521144700227100ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WB_MACRO_HELPER_DECLARE__ #include "WbMacroHelper.h" #undef __WB_MACRO_HELPER_DECLARE__ #include "Brain.h" #include "BrainBrowserWindow.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPreferences.h" #include "DisplayPropertiesSurface.h" #include "EventCaretDataFilesGet.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventManager.h" #include "EventMovieManualModeRecording.h" #include "EventSceneActive.h" #include "EventSurfaceColoringInvalidate.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "MovieRecorder.h" #include "MovieRecordingDialog.h" #include "Scene.h" #include "SceneFile.h" #include "SceneInfo.h" #include "SessionManager.h" #include "WbMacroCustomOperationTypeEnum.h" #include "WbMacroCustomDataTypeEnum.h" #include "WbMacroWidgetActionsManager.h" #include "WuQMacro.h" #include "WuQMacroCommand.h" #include "WuQMacroCommandParameter.h" #include "WuQMacroExecutorMonitor.h" #include "WuQMacroExecutorOptions.h" #include "WuQMacroGroup.h" #include "WuQMacroManager.h" #include "WuQMessageBox.h" #include "WuQMacroWidgetAction.h" using namespace caret; /** * \class caret::WbMacroHelper * \brief Implementation of WuQMacroHelperInterface that provides macro groups * \ingroup GuiQt */ /** * Constructor. */ WbMacroHelper::WbMacroHelper(QObject* parent) : WuQMacroHelperInterface(parent) { EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); } /** * Destructor. */ WbMacroHelper::~WbMacroHelper() { EventManager::get()->removeAllEventsFromListener(this); } /** * Receive an event * * @param event * The event. */ void WbMacroHelper::receiveEvent(Event* event) { CaretAssert(event); if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { event->setEventProcessed(); emit requestDialogsUpdate(); } } /** * @return All 'active' available macro groups. * Macros groups that are editible. Other macro * groups are exluded. */ std::vector WbMacroHelper::getActiveMacroGroups() { std::vector macroGroups; const bool includePreferencesFlag(false); if (includePreferencesFlag) { CaretPreferences* preferences = SessionManager::get()->getCaretPreferences(); CaretAssert(preferences); macroGroups.push_back(preferences->getMacros()); } EventSceneActive activeSceneEvent(EventSceneActive::MODE_GET); EventManager::get()->sendEvent(activeSceneEvent.getPointer()); if ( ! activeSceneEvent.isError()) { Scene* activeScene = activeSceneEvent.getScene(); if (activeScene != NULL) { macroGroups.push_back(activeScene->getMacroGroup()); } } return macroGroups; } /** * @return All macro groups including those that are * be valid (editable) at this time. */ std::vector WbMacroHelper::getAllMacroGroups() const { std::vector macroGroups; const bool includePreferencesFlag(false); if (includePreferencesFlag) { CaretPreferences* preferences = SessionManager::get()->getCaretPreferences(); CaretAssert(preferences); macroGroups.push_back(preferences->getMacros()); } const auto sceneFiles = EventCaretDataFilesGet::getCaretDataFilesForType(DataFileTypeEnum::SCENE); for (const auto dataFile : sceneFiles) { const SceneFile* sceneFile = dynamic_cast(dataFile); CaretAssert(sceneFile); const int32_t numberOfScenes = sceneFile->getNumberOfScenes(); for (int32_t i = 0; i < numberOfScenes; i++) { macroGroups.push_back(sceneFile->getSceneAtIndex(i)->getMacroGroup()); } } return macroGroups; } /** * Is called when the given macro is modified * * @param macro * Macro that is modified */ void WbMacroHelper::macroWasModified(WuQMacro* macro) { /* * Need to write to preferences if macro is from preferences */ CaretPreferences* preferences = SessionManager::get()->getCaretPreferences(); CaretAssert(preferences); WuQMacroGroup* prefMacroGroup = preferences->getMacros(); if (prefMacroGroup->containsMacro(macro)) { preferences->writeMacros(); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** * Is called when the given macro group is modified * * @param macroGroup * Macro Group that is modified */ void WbMacroHelper::macroGroupWasModified(WuQMacroGroup* macroGroup) { /** * Need to write to preferences if macro group is from preferences */ CaretPreferences* preferences = SessionManager::get()->getCaretPreferences(); CaretAssert(preferences); if (macroGroup == preferences->getMacros()) { preferences->writeMacros(); } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** * @return Identifiers of all available windows in which macros may be run */ std::vector WbMacroHelper::getMainWindowIdentifiers() { std::vector identifiers; std::vector windows = GuiManager::get()->getAllOpenBrainBrowserWindows(); for (auto w : windows) { identifiers.push_back(QString::number(w->getBrowserWindowIndex() + 1)); } return identifiers; } /** * Get the main window with the given identifier * * @param identifier * Window identifier * @return * Window with the given identifier or NULL if not available */ QMainWindow* WbMacroHelper::getMainWindowWithIdentifier(const QString& identifier) { const int32_t windowIndex(identifier.toInt() - 1); QMainWindow* window = GuiManager::get()->getBrowserWindowByWindowIndex(windowIndex); return window; } /** * Called just before executing the macro * * @param macro * Macro that is run * @param window * Widget for parent * @param executorOptions * Executor options */ void WbMacroHelper::macroExecutionStarting(const WuQMacro* /*macro*/, QWidget* /*window*/, const WuQMacroExecutorOptions* executorOptions) { MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); m_savedRecordingMode = movieRecorder->getRecordingMode(); if (executorOptions->isRecordMovieDuringExecution()) { movieRecorder->setRecordingMode(MovieRecorderModeEnum::AUTOMATIC); } EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_MOVIE_RECORDING_DIALOG_UPDATE); } /** * Called just after executing the macro * * @param macro * Macro that is run * @param window * Widget for parent * @param executorOptions * Executor options */ void WbMacroHelper::macroExecutionEnding(const WuQMacro* /*macro*/, QWidget* window, const WuQMacroExecutorOptions* executorOptions) { MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); movieRecorder->setRecordingMode(m_savedRecordingMode); EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_MOVIE_RECORDING_DIALOG_UPDATE); if (executorOptions->isCreateMovieAfterMacroExecution()) { MovieRecordingDialog::createMovie(window); } } /** * Reset the macro to its beginning state * * @param macro * Macro that is run * @param window * Widget for parent * @return * Pointer to current macro. May be different than the macro * passsed in. */ WuQMacro* WbMacroHelper::resetMacroStateToBeginning(const WuQMacro* macro, QWidget* window) { CaretAssert(macro); WuQMacro* macroOut = const_cast(macro); BrainBrowserWindow* bbw = dynamic_cast(window); EventSceneActive sceneEvent(EventSceneActive::MODE_GET); EventManager::get()->sendEvent(sceneEvent.getPointer()); Scene* scene = sceneEvent.getScene(); if (scene != NULL) { WuQMacroGroup* macroGroup = scene->getMacroGroup(); CaretAssert(macroGroup); const QString macroName = macroOut->getName(); const int32_t macroIndex = macroGroup->getIndexOfMacro(macroOut); /* * Reload scene */ SceneFile* invalidSceneFile(NULL); const bool showSceneDialogFlag(false); GuiManager::get()->processShowSceneDialogAndScene(bbw, invalidSceneFile, scene, showSceneDialogFlag); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); macroOut = NULL; /* * Find macro that was previously selected */ EventManager::get()->sendEvent(sceneEvent.getPointer()); scene = sceneEvent.getScene(); if (scene != NULL) { macroGroup = scene->getMacroGroup(); CaretAssert(macroGroup); if ((macroIndex >= 0) && (macroIndex < macroGroup->getNumberOfMacros())) { macroOut = macroGroup->getMacroAtIndex(macroIndex); if (macroOut->getName() != macroName) { for (int32_t i = 0; i < macroGroup->getNumberOfMacros(); i++) { WuQMacro* m = macroGroup->getMacroAtIndex(i); if (m->getName() == macroName) { macroOut = m; break; } } } } } } return macroOut; } /** * Called by macro executor just after a command has completed execution * * @param window * Widget for parent * @param command * Command that has just finished * @param allowDelayFlagOut * Output indicating if delay after command is enabled */ void WbMacroHelper::macroCommandHasCompleted(QWidget* window, const WuQMacroCommand* command, const WuQMacroExecutorOptions* executorOptions, bool& allowDelayFlagOut) { bool doDelayAfterCommandFlag(false); /* change value to enable/disable delays after command */ if (executorOptions->isIgnoreDelaysAndDurations()) { doDelayAfterCommandFlag = false; } allowDelayFlagOut = doDelayAfterCommandFlag; if (doDelayAfterCommandFlag) { recordImagesForDelay(window, command, allowDelayFlagOut); } } /** * If movie recording is on, capture images for the command's delay time * * @param window * Widget for parent * @param command * The command * @param executorOptions * Executor options * @param delay * The delay in seconds */ void WbMacroHelper::recordImagesForDelay(QWidget* window, const WuQMacroCommand* command, bool& allowDelayFlagOut) const { MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); CaretAssert(movieRecorder); if (command->getCommandType() != WuQMacroCommandTypeEnum::MOUSE) { if (command->getDelayInSeconds() > 0.0) { switch (movieRecorder->getRecordingMode()) { case MovieRecorderModeEnum::AUTOMATIC: { BrainBrowserWindow* bbw = dynamic_cast(window); const int32_t windowIndex = ((bbw != NULL) ? bbw->getBrowserWindowIndex() : -1); EventMovieManualModeRecording movieEvent(windowIndex, command->getDelayInSeconds()); EventManager::get()->sendEvent(movieEvent.getPointer()); allowDelayFlagOut = false; } break; case MovieRecorderModeEnum::MANUAL: break; } } } } /** * Called by macro executor just before starting execution of a command * * @param window * Widget for parent * @param command * Command that is about to start * @param executorOptions * Executor options * @param allowDelayFlagOut * Output indicating if delay before command is enabled */ void WbMacroHelper::macroCommandAboutToStart(QWidget* window, const WuQMacroCommand* command, const WuQMacroExecutorOptions* executorOptions, bool& allowDelayFlagOut) { bool doDelayBeforeCommandFlag(true); if (executorOptions->isIgnoreDelaysAndDurations()) { doDelayBeforeCommandFlag = false; } allowDelayFlagOut = doDelayBeforeCommandFlag; if (doDelayBeforeCommandFlag) { recordImagesForDelay(window, command, allowDelayFlagOut); } } /** * Called by macro manager to get macro widget actions typically * used by modal dialogs. * * Override to provide macro widget actions. * * @return Vector containing the macro widget actions. */ std::vector WbMacroHelper::getMacroWidgetActions() { if (m_macroWidgetActionsManager == NULL) { m_macroWidgetActionsManager = new WbMacroWidgetActionsManager(this); } CaretAssert(m_macroWidgetActionsManager); return m_macroWidgetActionsManager->getMacroWidgetActions(); } connectome-workbench-1.4.2/src/GuiQt/WbMacroHelper.h000066400000000000000000000076501360521144700223260ustar00rootroot00000000000000#ifndef __WB_MACRO_HELPER_H__ #define __WB_MACRO_HELPER_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "EventListenerInterface.h" #include "MovieRecorderModeEnum.h" #include "WuQMacroHelperInterface.h" class QWidget; namespace caret { class WbMacroWidgetActionsManager; class WbMacroHelper : public WuQMacroHelperInterface, public EventListenerInterface { Q_OBJECT public: WbMacroHelper(QObject* parent); virtual ~WbMacroHelper(); WbMacroHelper(const WbMacroHelper&) = delete; WbMacroHelper& operator=(const WbMacroHelper&) = delete; void receiveEvent(Event* event) override; virtual std::vector getActiveMacroGroups(); virtual std::vector getAllMacroGroups() const; virtual void macroWasModified(WuQMacro* macro) override; virtual void macroGroupWasModified(WuQMacroGroup* macroGroup) override; virtual std::vector getMainWindowIdentifiers() override; virtual QMainWindow* getMainWindowWithIdentifier(const QString& identifier) override; virtual void macroExecutionStarting(const WuQMacro* macro, QWidget* window, const WuQMacroExecutorOptions* executorOptions) override; virtual void macroExecutionEnding(const WuQMacro* macro, QWidget* window, const WuQMacroExecutorOptions* executorOptions) override; virtual WuQMacro* resetMacroStateToBeginning(const WuQMacro* macro, QWidget* window) override; virtual void macroCommandHasCompleted(QWidget* window, const WuQMacroCommand* command, const WuQMacroExecutorOptions* executorOptions, bool& allowDelayFlagOut) override; virtual void macroCommandAboutToStart(QWidget* window, const WuQMacroCommand* command, const WuQMacroExecutorOptions* executorOptions, bool& allowDelayFlagOut) override; virtual std::vector getMacroWidgetActions(); // ADD_NEW_METHODS_HERE private: void recordImagesForDelay(QWidget* window, const WuQMacroCommand* command, bool& allowDelayFlagOut) const; MovieRecorderModeEnum::Enum m_savedRecordingMode = MovieRecorderModeEnum::MANUAL; WbMacroWidgetActionsManager* m_macroWidgetActionsManager = NULL; // ADD_NEW_MEMBERS_HERE }; #ifdef __WB_MACRO_HELPER_DECLARE__ // #endif // __WB_MACRO_HELPER_DECLARE__ } // namespace #endif //__WB_MACRO_HELPER_H__ connectome-workbench-1.4.2/src/GuiQt/WbMacroWidgetActionNames.h000066400000000000000000000044251360521144700244510ustar00rootroot00000000000000#ifndef __WB_MACRO_WIDGET_ACTION_NAMES_H__ #define __WB_MACRO_WIDGET_ACTION_NAMES_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include namespace caret { class WbMacroWidgetActionNames { public: /* * NOTE: These names are saved into scene and changing the names will break scenes */ static QString getSurfacePropertiesOpacityName() { return "SurfaceProperties:surfaceOpacity"; } static QString getSurfacePropertiesLinkDiameterName() { return "SurfaceProperties:linkDiameter"; } static QString getSurfacePropertiesVertexDiameterName() { return "SurfaceProperties:vertexDiameter"; } static QString getSurfacePropertiesDisplayNormalVectorsName() { return "SurfaceProperties:displayNormalVectors"; } static QString getSurfacePropertiesDrawingTypeName() { return "SurfaceProperties:drawingType"; } WbMacroWidgetActionNames() = delete; virtual ~WbMacroWidgetActionNames() = delete; WbMacroWidgetActionNames(const WbMacroWidgetActionNames&) = delete; WbMacroWidgetActionNames& operator=(const WbMacroWidgetActionNames&) = delete; // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE }; #ifdef __WB_MACRO_WIDGET_ACTION_NAMES_DECLARE__ // #endif // __WB_MACRO_WIDGET_ACTION_NAMES_DECLARE__ } // namespace #endif //__WB_MACRO_WIDGET_ACTION_NAMES_H__ connectome-workbench-1.4.2/src/GuiQt/WbMacroWidgetActionsManager.cxx000066400000000000000000000260371360521144700255210ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WB_MACRO_WIDGET_ACTIONS_MANAGER_DECLARE__ #include "WbMacroWidgetActionsManager.h" #undef __WB_MACRO_WIDGET_ACTIONS_MANAGER_DECLARE__ #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "Brain.h" #include "DisplayPropertiesSurface.h" #include "GuiManager.h" #include "WbMacroWidgetActionNames.h" #include "WuQMacroWidgetAction.h" using namespace caret; /** * \class caret::WbMacroWidgetActionsManager * \brief Manager for macro widget actions used by workbench * \ingroup GuiQt */ /** * Constructor. * * @param parent * The parent object */ WbMacroWidgetActionsManager::WbMacroWidgetActionsManager(QObject* parent) : QObject(parent) { } /** * Destructor. */ WbMacroWidgetActionsManager::~WbMacroWidgetActionsManager() { } /** * @return All macro widget actions used by workbench */ std::vector WbMacroWidgetActionsManager::getMacroWidgetActions() { if (m_macroWidgetActions.empty()) { m_macroWidgetActions.push_back(getSurfacePropertiesLinkDiameterWidgetAction()); m_macroWidgetActions.push_back(getSurfacePropertiesOpacityWidgetAction()); m_macroWidgetActions.push_back(getSurfacePropertiesVertexDiameterWidgetAction()); m_macroWidgetActions.push_back(getSurfacePropertiesDisplayNormalVectorsWidgetAction()); m_macroWidgetActions.push_back(getSurfacePropertiesSurfaceDrawingTypeWidgetAction()); } return m_macroWidgetActions; } /** * @return The surface opacity widget action */ WuQMacroWidgetAction* WbMacroWidgetActionsManager::getSurfacePropertiesOpacityWidgetAction() { if (m_surfacePropertiesOpacityWidgetAction == NULL) { m_surfacePropertiesOpacityWidgetAction = new WuQMacroWidgetAction(WuQMacroWidgetAction::WidgetType::SPIN_BOX_FLOAT, WbMacroWidgetActionNames::getSurfacePropertiesOpacityName(), "Set the surface opacity", this); m_surfacePropertiesOpacityWidgetAction->setDoubleSpinBoxMinMaxStepDecimals(0.0, 1.0, 0.1, 2); DisplayPropertiesSurface* dsp = GuiManager::get()->getBrain()->getDisplayPropertiesSurface(); QObject::connect(m_surfacePropertiesOpacityWidgetAction, &WuQMacroWidgetAction::getModelValue, this, [=](QVariant& value) { value = dsp->getOpacity(); }); QObject::connect(m_surfacePropertiesOpacityWidgetAction, &WuQMacroWidgetAction::setModelValue, this, [=](const QVariant& value) { dsp->setOpacity(value.toFloat()); GuiManager::updateSurfaceColoring(); GuiManager::updateGraphicsAllWindows(); }); } CaretAssert(m_surfacePropertiesOpacityWidgetAction); return m_surfacePropertiesOpacityWidgetAction; } /** * @return The surface link diameter widget action */ WuQMacroWidgetAction* WbMacroWidgetActionsManager::getSurfacePropertiesLinkDiameterWidgetAction() { if (m_surfacePropertiesLinkDiameterWidgetAction == NULL) { m_surfacePropertiesLinkDiameterWidgetAction = new WuQMacroWidgetAction(WuQMacroWidgetAction::WidgetType::SPIN_BOX_FLOAT, WbMacroWidgetActionNames::getSurfacePropertiesLinkDiameterName(), "Set the link (edge) diameter", this); m_surfacePropertiesLinkDiameterWidgetAction->setDoubleSpinBoxMinMaxStepDecimals(0.0, std::numeric_limits::max(), 1.0, 1); DisplayPropertiesSurface* dsp = GuiManager::get()->getBrain()->getDisplayPropertiesSurface(); QObject::connect(m_surfacePropertiesLinkDiameterWidgetAction, &WuQMacroWidgetAction::getModelValue, this, [=](QVariant& value) { value = dsp->getLinkSize(); }); QObject::connect(m_surfacePropertiesLinkDiameterWidgetAction, &WuQMacroWidgetAction::setModelValue, this, [=](const QVariant& value) { dsp->setLinkSize(value.toFloat()); GuiManager::updateGraphicsAllWindows(); }); } return m_surfacePropertiesLinkDiameterWidgetAction; } /** * @return The surface link diameter widget action */ WuQMacroWidgetAction* WbMacroWidgetActionsManager::getSurfacePropertiesVertexDiameterWidgetAction() { if (m_surfacePropertiesVertexDiameterWidgetAction == NULL) { m_surfacePropertiesVertexDiameterWidgetAction = new WuQMacroWidgetAction(WuQMacroWidgetAction::WidgetType::SPIN_BOX_FLOAT, WbMacroWidgetActionNames::getSurfacePropertiesVertexDiameterName(), "Set the vertex diameter", this); m_surfacePropertiesVertexDiameterWidgetAction->setDoubleSpinBoxMinMaxStepDecimals(0.0, std::numeric_limits::max(), 1.0, 1); DisplayPropertiesSurface* dsp = GuiManager::get()->getBrain()->getDisplayPropertiesSurface(); QObject::connect(m_surfacePropertiesVertexDiameterWidgetAction, &WuQMacroWidgetAction::getModelValue, this, [=](QVariant& value) { value = dsp->getNodeSize(); }); QObject::connect(m_surfacePropertiesVertexDiameterWidgetAction, &WuQMacroWidgetAction::setModelValue, this, [=](const QVariant& value) { dsp->setNodeSize(value.toFloat()); GuiManager::updateGraphicsAllWindows(); }); } return m_surfacePropertiesVertexDiameterWidgetAction; } /** * @return Get (and in needed create) the surface properties display normal vectors widget action */ WuQMacroWidgetAction* WbMacroWidgetActionsManager::getSurfacePropertiesDisplayNormalVectorsWidgetAction() { if (m_surfacePropertiesDisplayNormalVectorsWidgetAction == NULL) { m_surfacePropertiesDisplayNormalVectorsWidgetAction = new WuQMacroWidgetAction(WuQMacroWidgetAction::WidgetType::CHECK_BOX_BOOLEAN, WbMacroWidgetActionNames::getSurfacePropertiesDisplayNormalVectorsName(), "Display normal vectors on a surface", this); DisplayPropertiesSurface* dsp = GuiManager::get()->getBrain()->getDisplayPropertiesSurface(); QObject::connect(m_surfacePropertiesDisplayNormalVectorsWidgetAction, &WuQMacroWidgetAction::getModelValue, this, [=](QVariant& value) { value = dsp->isDisplayNormalVectors(); }); QObject::connect(m_surfacePropertiesDisplayNormalVectorsWidgetAction, &WuQMacroWidgetAction::setModelValue, this, [=](const QVariant& value) { dsp->setDisplayNormalVectors(value.toBool()); GuiManager::updateGraphicsAllWindows(); }); } return m_surfacePropertiesDisplayNormalVectorsWidgetAction; } /** * @return Get (and in needed create) the surface properties surface drawing type widget action */ WuQMacroWidgetAction* WbMacroWidgetActionsManager::getSurfacePropertiesSurfaceDrawingTypeWidgetAction() { if (m_surfacePropertiesSurfaceDrawingTypeWidgetAction == NULL) { m_surfacePropertiesSurfaceDrawingTypeWidgetAction = new WuQMacroWidgetAction(WuQMacroWidgetAction::WidgetType::COMBO_BOX_STRING_LIST, WbMacroWidgetActionNames::getSurfacePropertiesDrawingTypeName(), "Drawing type for surface", this); std::vector drawTypeNames; const bool sortNamesFlag(false); SurfaceDrawingTypeEnum::getAllGuiNames(drawTypeNames, sortNamesFlag); std::vector qsDrawTypeNames(drawTypeNames.begin(), drawTypeNames.end()); m_surfacePropertiesSurfaceDrawingTypeWidgetAction->setComboBoxStringList(qsDrawTypeNames); DisplayPropertiesSurface* dsp = GuiManager::get()->getBrain()->getDisplayPropertiesSurface(); QObject::connect(m_surfacePropertiesSurfaceDrawingTypeWidgetAction, &WuQMacroWidgetAction::getModelValue, this, [=](QVariant& value) { const SurfaceDrawingTypeEnum::Enum sdt = dsp->getSurfaceDrawingType(); value = SurfaceDrawingTypeEnum::toGuiName(sdt); }); QObject::connect(m_surfacePropertiesSurfaceDrawingTypeWidgetAction, &WuQMacroWidgetAction::setModelValue, this, [=](const QVariant& value) { bool validFlag(false); const SurfaceDrawingTypeEnum::Enum std = SurfaceDrawingTypeEnum::fromGuiName(value.toString(), &validFlag); if (validFlag) { dsp->setSurfaceDrawingType(std); } else { CaretLogSevere("Failed to convert to surface drawing type: " + value.toString()); } GuiManager::updateGraphicsAllWindows(); }); } return m_surfacePropertiesSurfaceDrawingTypeWidgetAction; } connectome-workbench-1.4.2/src/GuiQt/WbMacroWidgetActionsManager.h000066400000000000000000000053651360521144700251470ustar00rootroot00000000000000#ifndef __WB_MACRO_WIDGET_ACTIONS_MANAGER_H__ #define __WB_MACRO_WIDGET_ACTIONS_MANAGER_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include namespace caret { class WuQMacroWidgetAction; class WbMacroWidgetActionsManager : public QObject { Q_OBJECT public: WbMacroWidgetActionsManager(QObject* parent); virtual ~WbMacroWidgetActionsManager(); WbMacroWidgetActionsManager(const WbMacroWidgetActionsManager&) = delete; WbMacroWidgetActionsManager& operator=(const WbMacroWidgetActionsManager&) = delete; std::vector getMacroWidgetActions(); WuQMacroWidgetAction* getSurfacePropertiesLinkDiameterWidgetAction(); WuQMacroWidgetAction* getSurfacePropertiesOpacityWidgetAction(); WuQMacroWidgetAction* getSurfacePropertiesVertexDiameterWidgetAction(); WuQMacroWidgetAction* getSurfacePropertiesDisplayNormalVectorsWidgetAction(); WuQMacroWidgetAction* getSurfacePropertiesSurfaceDrawingTypeWidgetAction(); // ADD_NEW_METHODS_HERE private: std::vector m_macroWidgetActions; WuQMacroWidgetAction* m_surfacePropertiesOpacityWidgetAction = NULL; WuQMacroWidgetAction* m_surfacePropertiesLinkDiameterWidgetAction = NULL; WuQMacroWidgetAction* m_surfacePropertiesVertexDiameterWidgetAction = NULL; WuQMacroWidgetAction* m_surfacePropertiesDisplayNormalVectorsWidgetAction = NULL; WuQMacroWidgetAction* m_surfacePropertiesSurfaceDrawingTypeWidgetAction = NULL; // ADD_NEW_MEMBERS_HERE }; #ifdef __WB_MACRO_WIDGET_ACTIONS_MANAGER_DECLARE__ // #endif // __WB_MACRO_WIDGET_ACTIONS_MANAGER_DECLARE__ } // namespace #endif //__WB_MACRO_WIDGET_ACTIONS_MANAGER_H__ connectome-workbench-1.4.2/src/GuiQt/WuQCollapsibleWidget.cxx000066400000000000000000000116031360521144700242320ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #define __WU_Q_COLLAPSIBLE_WIDGET_DECLARE__ #include "WuQCollapsibleWidget.h" #undef __WU_Q_COLLAPSIBLE_WIDGET_DECLARE__ #include "CaretAssert.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::WuQCollapsibleWidget * \brief A container widget with multiple collapsible sections * * A container widget with multiple collapsible sections in * a vertical orientation. Each section is independent of * the other sections so that multiple sections may be open * at one time. */ /** * Constructor. */ WuQCollapsibleWidget::WuQCollapsibleWidget(QWidget* parent) : QWidget(parent) { this->showHideActionGroup = new QActionGroup(this); QObject::connect(this->showHideActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(showHideActionGroupTriggered(QAction*))); this->collapsibleLayout = new QVBoxLayout(); WuQtUtilities::setLayoutSpacingAndMargins(this->collapsibleLayout, 2, 2); QWidget* widget = new QWidget(); QVBoxLayout* widgetLayout = new QVBoxLayout(widget); widgetLayout->addLayout(this->collapsibleLayout); widgetLayout->addStretch(); QScrollArea* scrollArea = new QScrollArea(); scrollArea->setWidgetResizable(true); scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); scrollArea->setWidget(widget); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(scrollArea); //layout->addStretch(); Using this will result in the widget too small vertically } /** * Destructor. */ WuQCollapsibleWidget::~WuQCollapsibleWidget() { } /** * @return The recommended size for this widget. */ QSize WuQCollapsibleWidget::sizeHint() const { //QSize minSize = this->minimumSize(); //std::cout << "Collapse Min Size: " //<< minSize.width() << ", " << minSize.width() << std::endl; QSize sz = QWidget::sizeHint(); sz.setHeight(500); return sz; } /** * Add a widget to this collapsible widget with the * given label in the titlebar. * @param widget * Widget that is added. * @param text * Text displayed for collapsing/expanding view * of widget. */ void WuQCollapsibleWidget::addItem(QWidget* widget, const QString& text) { CaretAssert(widget); QLabel* label = new QLabel(text); QAction* showHideAction = this->showHideActionGroup->addAction("-"); showHideAction->setData(qVariantFromValue((void*)widget)); QToolButton* showHideToolButton = new QToolButton(); showHideToolButton->setDefaultAction(showHideAction); QHBoxLayout* controlLayout = new QHBoxLayout(); WuQtUtilities::setLayoutSpacingAndMargins(controlLayout, 2, 2); controlLayout->addWidget(showHideToolButton); controlLayout->addSpacing(15); controlLayout->addWidget(label); controlLayout->addStretch(); QFrame* controlFrame = new QFrame(); controlFrame->setLineWidth(1); controlFrame->setMidLineWidth(2); controlFrame->setFrameStyle(QFrame::Box | QFrame::Plain); controlFrame->setLayout(controlLayout); controlFrame->setFixedHeight(controlFrame->sizeHint().height()); this->collapsibleLayout->addWidget(controlFrame); this->collapsibleLayout->addWidget(widget); this->widgets.push_back(widget); } /** * Called when a show/hide tool button is triggered */ void WuQCollapsibleWidget::showHideActionGroupTriggered(QAction* action) { if (action != NULL) { void* pointer = action->data().value(); CaretAssert(pointer); QWidget* widget = (QWidget*)pointer; QString collapseExpandText = ""; if (widget->isVisible()) { widget->setVisible(false); collapseExpandText = "+"; } else { widget->setVisible(true); collapseExpandText = "-"; } action->setText(collapseExpandText); } } connectome-workbench-1.4.2/src/GuiQt/WuQCollapsibleWidget.h000066400000000000000000000036301360521144700236600ustar00rootroot00000000000000#ifndef __WU_Q_COLLAPSIBLE_WIDGET__H_ #define __WU_Q_COLLAPSIBLE_WIDGET__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include class QAction; class QActionGroup; class QVBoxLayout; namespace caret { class WuQCollapsibleWidget : public QWidget { Q_OBJECT public: WuQCollapsibleWidget(QWidget* parent = 0); virtual ~WuQCollapsibleWidget(); void addItem(QWidget* widget, const QString& text); virtual QSize sizeHint() const; private slots: void showHideActionGroupTriggered(QAction*); private: WuQCollapsibleWidget(const WuQCollapsibleWidget&); WuQCollapsibleWidget& operator=(const WuQCollapsibleWidget&); QVBoxLayout* collapsibleLayout; QActionGroup* showHideActionGroup; QVector widgets; }; #ifdef __WU_Q_COLLAPSIBLE_WIDGET_DECLARE__ // #endif // __WU_Q_COLLAPSIBLE_WIDGET_DECLARE__ } // namespace #endif //__WU_Q_COLLAPSIBLE_WIDGET__H_ connectome-workbench-1.4.2/src/GuiQt/WuQDataEntryDialog.cxx000066400000000000000000000346431360521144700236610ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "CaretColorEnumComboBox.h" #include "StructureEnumComboBox.h" #include "SurfaceSelectionViewController.h" #include "WuQDataEntryDialog.h" #include "WuQFactory.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" using namespace caret; /** * constructor. * * @param title * Title for dialog. * @param parent * Parent of the dialog. * @param addScrollBarsFlag * If true, add scrollbars to the dialog (typically true when the dialog * will contain many items. * @param f * Qt's Window flags. * */ WuQDataEntryDialog::WuQDataEntryDialog(const QString& title, QWidget* parent, const bool addScrollBarsFlag, Qt::WindowFlags f) : WuQDialogModal(title, parent, f) { WuQDialog::ScrollAreaStatus scrollBarStatus = WuQDialog::SCROLL_AREA_NEVER; if (addScrollBarsFlag) { scrollBarStatus = WuQDialog::SCROLL_AREA_ALWAYS; } constructDialog(scrollBarStatus); } /** * constructor. * * @param title * Title for dialog. * @param parent * Parent of the dialog. * @param scrollBarStatus * Add scrollbars (never, as needed, always). * @param f * Qt's Window flags. * */ WuQDataEntryDialog::WuQDataEntryDialog(const QString& title, QWidget* parent, const WuQDialog::ScrollAreaStatus scrollBarStatus, Qt::WindowFlags f) : WuQDialogModal(title, parent, f) { constructDialog(scrollBarStatus); } /** * destructor. */ WuQDataEntryDialog::~WuQDataEntryDialog() { } /** * Hide the cancel button. */ void WuQDataEntryDialog::hideCancelButton() { setCancelButtonText(""); } /** * Finish construction of the dialog. * * @param scrollBarStatus * Status for scroll bars. */ void WuQDataEntryDialog::constructDialog(const WuQDialog::ScrollAreaStatus scrollBarStatus) { // // Widget and Layout for user's widgets // QWidget* widgetForGridLayout = new QWidget; widgetGridLayout = new QGridLayout(widgetForGridLayout); // // Labels for text at top, hidden until set by user // textAtTopLabel = new QLabel; textAtTopLabel->setHidden(true); // // ButtonGroup for radio buttons // radioButtonGroup = new QButtonGroup(this); // // Layout for dialog // const int NO_STRETCH = 0; const int BIG_STRETCH = 100; QWidget* widget = new QWidget(); QVBoxLayout* dialogLayout = new QVBoxLayout(widget); dialogLayout->setSpacing(0); dialogLayout->addWidget(textAtTopLabel, NO_STRETCH); dialogLayout->addWidget(widgetForGridLayout, BIG_STRETCH); this->setCentralWidget(widget, scrollBarStatus); } /** * Called when the OK button is pressed. * If needed should override this to process * data when the OK button is pressed and then * call this to issue the accept signal. */ void WuQDataEntryDialog::okButtonClicked() { m_isDataValid = true; m_dataInvalidErrorMessage = ""; emit validateData(this); if (m_isDataValid) { // if (dataEnteredIsValid()) { // accept(); // } WuQDialogModal::okButtonClicked(); } else { if (m_dataInvalidErrorMessage.isEmpty()) { m_dataInvalidErrorMessage = "Data is not valid."; } WuQMessageBox::errorOk(this, m_dataInvalidErrorMessage); } } /** * This method is used to set the validity of the data * widgets that were added by the user. To use this, * connect to the validateData() signal and then call * this to indicate the validity of the data widgets. * getDataWidgetWithName() can be used to get widgets * but only will work if the user sets the name of * the widgets. * @param isValid * True if the data is valid, else false. * @param dataInvalidErrorMessage * If data is invalid, message describing why data is invalid. */ void WuQDataEntryDialog::setDataValid(const bool isValid, const QString& dataInvalidErrorMessage) { m_isDataValid = isValid; m_dataInvalidErrorMessage = dataInvalidErrorMessage; } /** * Get the data widget that was added by user with the * given name. For this method to return the correct * widget, the user must call setObjectName() on a * widget after it is added to the dialog. * * @param name * Name of the widget. * @return * Pointer to widget with the given name or NULL * if the widget is not found. */ QWidget* WuQDataEntryDialog::getDataWidgetWithName(const QString& name) { const int numWidgets = widgets.size(); for (int i = 0; i < numWidgets; i++) { if (widgets[i]->objectName() == name) { return widgets[i]; } } return NULL; } ///** // * override to verify data after OK button pressed. // */ //bool //WuQDataEntryDialog::dataEnteredIsValid() //{ // return true; //} /** * set text at top of dialog (text is automatically wrapped). */ void WuQDataEntryDialog::setTextAtTop(const QString& s, const bool wrapTheText) { textAtTopLabel->setText(s); textAtTopLabel->setWordWrap(wrapTheText); if (s.isEmpty()) { textAtTopLabel->setHidden(true); } else { textAtTopLabel->setHidden(false); } } /** * add widgets to the next available row in the dialog. */ void WuQDataEntryDialog::addWidgetsToNextRow(QWidget* leftColumnWidget, QWidget* rightColumnWidget) { // // add widgets to the next row // const int rowNumber = widgetGridLayout->rowCount(); if (leftColumnWidget != NULL) { widgetGridLayout->addWidget(leftColumnWidget, rowNumber, 0); } if (rightColumnWidget != NULL) { widgetGridLayout->addWidget(rightColumnWidget, rowNumber, 1); } } /** * add widget to next available row in the dialog. */ QWidget* WuQDataEntryDialog::addWidget(const QString& labelText, QWidget* widget) { // // Create the label // QLabel* label = new QLabel(labelText); // // Keep pointer to widget // widgets.push_back(widget); // // add widget to layout // addWidgetsToNextRow(label, widget); return widget; } /** * add widget that spans both the label and widget columns to next available row in the dialog. */ QWidget* WuQDataEntryDialog::addWidget(QWidget* widget) { // // Keep pointer to widget // widgets.push_back(widget); // // add widget to layout // const int rowNumber = widgetGridLayout->rowCount(); widgetGridLayout->addWidget(widget, rowNumber, 0, 1, 2); return widget; } /** * add a check box. */ QCheckBox* WuQDataEntryDialog::addCheckBox(const QString& text, const bool defaultValue) { // // Create check box // QCheckBox* cb = new QCheckBox(text); cb->setChecked(defaultValue); // // Keep pointer to widget // widgets.push_back(cb); // // add widget to both columns of layout // const int rowNumber = widgetGridLayout->rowCount(); widgetGridLayout->addWidget(cb, rowNumber, 0, 1, 2, Qt::AlignLeft); return cb; } /** * get radio button selected (-1 if none, value is sequence added). */ int WuQDataEntryDialog::getRadioButtonSelected() const { return radioButtonGroup->checkedId(); } /** * add a radio button (all radio buttons will be mutually exclusive). */ QRadioButton* WuQDataEntryDialog::addRadioButton(const QString& text, const bool defaultValue) { // // Create radio button // QRadioButton* rb = new QRadioButton(text); rb->setChecked(defaultValue); // // Add to radio button group // const int buttNum = radioButtonGroup->buttons().count(); radioButtonGroup->addButton(rb, buttNum); // // Keep pointer to widget // widgets.push_back(rb); // // add widget to both columns of layout // const int rowNumber = widgetGridLayout->rowCount(); widgetGridLayout->addWidget(rb, rowNumber, 0, 1, 2, Qt::AlignLeft); return rb; } /** * add a combo box. */ QComboBox* WuQDataEntryDialog::addComboBox(const QString& labelText, const QStringList& comboBoxItems, const QList* comboBoxItemsUserData) { // // Create combo box // QComboBox* comboBox = WuQFactory::newComboBox(); for (int i = 0; i < comboBoxItems.size(); i++) { QVariant userData; if (comboBoxItemsUserData != NULL) { if (i < comboBoxItemsUserData->size()) { userData = (*comboBoxItemsUserData).at(i); } } comboBox->addItem(comboBoxItems.at(i), userData); } // // Add to dialog // addWidget(labelText, comboBox); return comboBox; } /** * add line edit. */ QLineEdit* WuQDataEntryDialog::addLineEditWidget(const QString& labelText, const QString& defaultText) { // // Create line edit // QLineEdit* le = new QLineEdit; le->setText(defaultText); // // Add to dialog // addWidget(labelText, le); return le; } /* * add list box. */ QListWidget* WuQDataEntryDialog::addListWidget(const QString& labelText, const QStringList& listBoxItems) { // // Create and populate list widget // QListWidget* lw = new QListWidget; lw->addItems(listBoxItems); if (listBoxItems.count() > 0) { lw->setCurrentRow(0); } // // Add to dialog // addWidget(labelText, lw); return lw; } /** * add spin box. */ QSpinBox* WuQDataEntryDialog::addSpinBox(const QString& labelText, const int defaultValue, const int minimumValue, const int maximumValue, const int singleStep) { // // Create spin box // QSpinBox* sb = WuQFactory::newSpinBox(); sb->setMinimum(minimumValue); sb->setMaximum(maximumValue); sb->setSingleStep(singleStep); sb->setValue(defaultValue); // // Add to dialog // addWidget(labelText, sb); return sb; } /** * add double spin box. */ QDoubleSpinBox* WuQDataEntryDialog::addDoubleSpinBox(const QString& labelText, const float defaultValue, const float minimumValue, const float maximumValue, const float singleStep, const int numberOfDecimals) { // // Create spin box // QDoubleSpinBox* sb = WuQFactory::newDoubleSpinBox(); sb->setMinimum(minimumValue); sb->setMaximum(maximumValue); sb->setSingleStep(singleStep); sb->setValue(defaultValue); sb->setDecimals(numberOfDecimals); // // Add to dialog // addWidget(labelText, sb); return sb; } /** * add a text edit. */ QTextEdit* WuQDataEntryDialog::addTextEdit(const QString& labelText, const QString& defaultText, const bool readOnlyFlag) { // // Create text edit // QTextEdit* te = new QTextEdit; te->setReadOnly(readOnlyFlag); te->setPlainText(defaultText); // // add to dialog // addWidget(labelText, te); return te; } /** * Add a caret color selection control. */ CaretColorEnumComboBox* WuQDataEntryDialog::addCaretColorEnumComboBox(const QString& labelText, const CaretColorEnum::Enum defaultColor) { CaretColorEnumComboBox* caretColorComboBox = new CaretColorEnumComboBox(this); caretColorComboBox->setSelectedColor(defaultColor); this->addWidget(labelText, caretColorComboBox->getWidget()); return caretColorComboBox; } /** * Add a structure selection control. */ StructureEnumComboBox* WuQDataEntryDialog::addStructureEnumComboBox(const QString& labelText, const StructureEnum::Enum defaultStructure) { StructureEnumComboBox* structureEnumComboBox = new StructureEnumComboBox(this); structureEnumComboBox->setSelectedStructure(defaultStructure); this->addWidget(labelText, structureEnumComboBox->getWidget()); return structureEnumComboBox; } /** * Add a surface selection control */ SurfaceSelectionViewController* WuQDataEntryDialog::addSurfaceSelectionViewController(const QString& labelText, BrainStructure* brainStructure) { SurfaceSelectionViewController* surfaceSelectionViewController = new SurfaceSelectionViewController(this, brainStructure, "DataEntryDialogSurfaceComboBox", "Data Entry"); this->addWidget(labelText, surfaceSelectionViewController->getWidget()); return surfaceSelectionViewController; } connectome-workbench-1.4.2/src/GuiQt/WuQDataEntryDialog.h000066400000000000000000000155071360521144700233040ustar00rootroot00000000000000 #ifndef __WU_Q_DATA_ENTRY_DIALOG_H__ #define __WU_Q_DATA_ENTRY_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretColorEnum.h" #include "StructureEnum.h" #include "WuQDialogModal.h" class QButtonGroup; class QCheckBox; class QComboBox; class QDialogButtonBox; class QDoubleSpinBox; class QGridLayout; class QLabel; class QLineEdit; class QListWidget; class QRadioButton; class QSpinBox; class QTextEdit; namespace caret { class BrainStructure; class CaretColorEnumComboBox; class StructureEnumComboBox; class SurfaceSelectionViewController; /// class for a modal data entry dialog class WuQDataEntryDialog : public WuQDialogModal { Q_OBJECT public: // constructor WuQDataEntryDialog(const QString& title, QWidget* parent, const bool addScrollBarsFlag = false, Qt::WindowFlags f = 0); WuQDataEntryDialog(const QString& title, QWidget* parent, const WuQDialog::ScrollAreaStatus scrollBarStatus, Qt::WindowFlags f = 0); void hideCancelButton(); // destructor ~WuQDataEntryDialog(); // add widget to next available row in the dialog QWidget* addWidget(const QString& labelText, QWidget* widget); QWidget* addWidget(QWidget* widget); // add widgets to the next available row in the dialog void addWidgetsToNextRow(QWidget* leftColumnWidget, QWidget* rightColumnWidget); // add a check box QCheckBox* addCheckBox(const QString& text, const bool defaultValue = false); // add a combo box QComboBox* addComboBox(const QString& labelText, const QStringList& comboBoxItems, const QList* comboBoxItemsUserData = NULL); // add line edit QLineEdit* addLineEditWidget(const QString& labelText, const QString& defaultText = ""); // add list box QListWidget* addListWidget(const QString& labelText, const QStringList& listBoxItems); // add a radio button (all radio buttons will be mutually exclusive) QRadioButton* addRadioButton(const QString& text, const bool defaultValue = false); // get radio button selected (-1 if none, value is sequence added) int getRadioButtonSelected() const; // add spin box QSpinBox* addSpinBox(const QString& labelText, const int defaultValue, const int minimumValue = -10000, const int maximumValue = 10000, const int singleStep = 1); // add double spin box QDoubleSpinBox* addDoubleSpinBox(const QString& labelText, const float defaultValue, const float minimumValue = -10000000.0, const float maximumValue = 10000000.0, const float singleStep = 1.0, const int numberOfDecimals = 3); // add a text edit QTextEdit* addTextEdit(const QString& labelText, const QString& defaultText, const bool readOnlyFlag); // add a structure selection control StructureEnumComboBox* addStructureEnumComboBox(const QString& labelText, const StructureEnum::Enum defaultStructure = StructureEnum::INVALID); // add a caret color selection control CaretColorEnumComboBox* addCaretColorEnumComboBox(const QString& labelText, const CaretColorEnum::Enum defaultColor = CaretColorEnum::BLACK); SurfaceSelectionViewController* addSurfaceSelectionViewController(const QString& labelText, BrainStructure* brainStructure); // set text at top of dialog void setTextAtTop(const QString& s, const bool wrapTheText); void setDataValid(const bool isValid, const QString& dataInvalidErrorMessage); QWidget* getDataWidgetWithName(const QString& name); signals: /** * This signal is emitted when the user presses the OK button. * The user of the dialog can then examine the widgets that were * added to the dialog for validity and then pass the validity * status back to this dialog via setDataValid(). */ void validateData(WuQDataEntryDialog* dataEntryDialog); protected: virtual void okButtonClicked(); // // override to verify data after OK button pressed if subclassing this dialog // virtual bool dataEnteredIsValid(); private: void constructDialog(const WuQDialog::ScrollAreaStatus scrollBarStatus); /// widgets in dialog QVector widgets; /// layout for widgets in dialog QGridLayout* widgetGridLayout; /// label for text at dialog top QLabel* textAtTopLabel; /// button group for radio buttons QButtonGroup* radioButtonGroup; /** Indicates validity of data */ bool m_isDataValid; /** Error message displayed when data is invalid */ QString m_dataInvalidErrorMessage; }; } // namespace #endif // __WU_Q_DATA_ENTRY_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/WuQDialog.cxx000066400000000000000000000656601360521144700220500ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /* * Some code in keyPressEvent copied from QT4, original license follows */ /**************************************************************************** ** ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #define __WU_QDIALOG_DECLARE__ #include "WuQDialog.h" #undef __WU_QDIALOG_DECLARE__ #include "WuQtUtilities.h" using namespace caret; /** * \class caret::WuQDialog * \brief Base class for dialogs. * * A base class for dialogs. */ /** * constructor. * * @param dialogTitle * Title for dialog. * @param parent * Parent widget on which this dialog is displayed. * @param f * optional Qt::WindowFlags */ WuQDialog::WuQDialog(const AString& dialogTitle, QWidget* parent, Qt::WindowFlags f) : QDialog(parent, f) { m_placeCentralWidgetInScrollAreaStatus = SCROLL_AREA_NEVER; m_topWidget = NULL; m_centralWidget = NULL; m_bottomWidget = NULL; m_firstTimeInShowMethodFlag = true; m_centralWidgetLayoutIndex = -1; m_sizeHintWidth = -1; m_sizeHintHeight = -1; this->autoDefaultProcessingEnabledFlag = true; this->setAttribute(Qt::WA_DeleteOnClose, false); this->setWindowTitle(dialogTitle); this->setFocusPolicy(Qt::ClickFocus); this->userWidgetLayout = new QVBoxLayout(); WuQtUtilities::setLayoutSpacingAndMargins(this->userWidgetLayout, 0, 0); m_layoutLeftOfButtonBox = new QHBoxLayout(); m_layoutLeftOfButtonBox->setContentsMargins(0, 0, 0, 0); this->buttonBox = new QDialogButtonBox(Qt::Horizontal, this); QObject::connect(this->buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(clicked(QAbstractButton*))); QHBoxLayout* bottomLayout = new QHBoxLayout(); bottomLayout->addLayout(m_layoutLeftOfButtonBox, 0); bottomLayout->addWidget(this->buttonBox, 1000); QVBoxLayout* dialogLayout = new QVBoxLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(dialogLayout, 0, 0); dialogLayout->addLayout(this->userWidgetLayout); dialogLayout->addLayout(bottomLayout); } /** * destructor. */ WuQDialog::~WuQDialog() { } ///** // * Set the size hint for the dialog to the given width and height. // * // * NOTE: If there are scrollbars added to the dialog, this size hint // * may be ignored. // */ //void //WuQDialog::setDialogSizeHint(const int32_t width, // const int32_t height) //{ // m_sizeHintWidth = width; // m_sizeHintHeight = height; //} /** * Add a widget to the left of the buttons at the bottom of the dialog. * More than one widget can be added and the first widget will be on * the left-most side. * * @param widget * Widget to add. */ void WuQDialog::addWidgetToLeftOfButtons(QWidget* widget) { m_layoutLeftOfButtonBox->addWidget(widget); } /** * Allows deletion of the dialog by the windowing * system when the dialog is closed. This should only * be true if the dialog is dynamically allocated (with * new) and not explicitly delete'ed by the user's code. * * @param deleteFlag * If true, dialog will be deleted by the windowing system. */ void WuQDialog::setDeleteWhenClosed(bool deleteFlag) { this->setAttribute(Qt::WA_DeleteOnClose, deleteFlag); } /** * Set the text of a standard button. If the * text is an empty string, the button is removed. * * @param button * Standard button enum identifying button. * @param text * Text for the button. */ void WuQDialog::setStandardButtonText(QDialogButtonBox::StandardButton button, const AString& text) { QPushButton* pushButton = this->buttonBox->button(button); if (text.isEmpty()) { if (pushButton != NULL) { this->buttonBox->removeButton(pushButton); } } else { if (pushButton == NULL) { pushButton = this->buttonBox->addButton(button); } pushButton->setText(text); } } /** * Set the enabled status of a standard button. * If the button is invalid, a sever message is logged. * * @param button * Standard button enum identifying button. * @param enabled * New enabled status for button. */ void WuQDialog::setStandardButtonEnabled(QDialogButtonBox::StandardButton button, const bool enabled) { QPushButton* pushButton = this->buttonBox->button(button); if (pushButton != NULL) { pushButton->setEnabled(enabled); } else { CaretLogSevere("PROGRAM ERROR: Attempted to set enabled status for an invalid Dialog Standard Button, id=" + AString::number((int)button)); } } /** * called to capture image after timeout so nothing obscures window. */ void WuQDialog::slotCaptureImageAfterTimeOut() { QImage image = QPixmap::grabWindow(this->winId()).toImage(); if (image.isNull() == false) { QClipboard* clipboard = QApplication::clipboard(); clipboard->setImage(image); QMessageBox::information(this, "Information", "An image of this dialog has been placed onto the computer's clipboard."); } } /** * called to capture image of window and place it on the clipboard */ void WuQDialog::slotMenuCaptureImageOfWindowToClipboard() { // // Need to delay capture so that the context sensistive // menu closes or else the menu will be in the captured image. // QApplication::processEvents(); QTimer::singleShot(1000, this, SLOT(slotCaptureImageAfterTimeOut())); } /** * add a capture image of window menu item to the menu. */ void WuQDialog::addImageCaptureToMenu(QMenu* menu) { menu->addAction("Capture Image to Clipboard", this, SLOT(slotMenuCaptureImageOfWindowToClipboard())); } /** * called by parent when context menu event occurs. */ void WuQDialog::contextMenuEvent(QContextMenuEvent* cme) { const bool enableCaptureMenu = false; if (enableCaptureMenu) { // // Popup menu for selection of pages // QMenu menu(this); // // Add menu item for image capture // addImageCaptureToMenu(&menu); // // Popup the menu // menu.exec(cme->globalPos()); } } /** * Called by parent when a key press event occurs * * This code is taken from QDialog::keyPressEvent. * so it may need to be updated with new version of * Qt. * * It is used to disable the AutoDault button * property which triggers a button click when * the return key is pressed on a dialog. */ void WuQDialog::keyPressEvent(QKeyEvent* e) { if (autoDefaultProcessingEnabledFlag) { QDialog::keyPressEvent(e); return; } bool acceptedEvent = false; // Calls reject() if Escape is pressed. Simulates a button // click for the default button if Enter is pressed. Move focus // for the arrow keys. Ignore the rest. #ifdef Q_OS_MAC if(e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Period) { } else #endif if (!e->modifiers() || (e->modifiers() & Qt::KeypadModifier && e->key() == Qt::Key_Enter)) { switch (e->key()) { case Qt::Key_Enter: case Qt::Key_Return: e->accept(); acceptedEvent = true; break; case Qt::Key_Escape: break; default: return; } } if (acceptedEvent == false) { QDialog::keyPressEvent(e); } } /** * ring the bell. */ void WuQDialog::beep() { QApplication::beep(); } /** * show the watch cursor. */ void WuQDialog::showWaitCursor() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); } /** * normal cursor. */ void WuQDialog::showNormalCursor() { QApplication::restoreOverrideCursor(); } /** * called to close. */ bool WuQDialog::close() { return QDialog::close(); } /** * @return The dialog button box for adding buttons. */ QDialogButtonBox* WuQDialog::getDialogButtonBox() { return this->buttonBox; } /** * Sets the given widgets to be the window's top and central widget. * Note: WuQDialog takes ownership of the widget pointer * and deletes it at the appropriate time. * * This should be called ONE and ONLY one time. * * Unless prohibited by the second parameter, the central widget * will be automatically placed into a scroll area if the * widget makes the dialog too big for the screen. * * @param topWidget * The optional widget displayed at top (may be NULL). * @param centralWidget * The central widget. * @param bottomWidget * The optional widget displayed at bottom (may be NULL). * @param placeCentralWidgetInScrollAreaStatus * Status of using a scroll area for the central widget */ void WuQDialog::setTopBottomAndCentralWidgets(QWidget* topWidget, QWidget* centralWidget, QWidget* bottomWidget, const ScrollAreaStatus placeCentralWidgetInScrollAreaStatus) { CaretAssert(centralWidget); this->setTopBottomAndCentralWidgetsInternal(topWidget, centralWidget, bottomWidget, placeCentralWidgetInScrollAreaStatus); } /** * Sets the give widget to be the window's central widget. * Note: WuQDialog takes ownership of the widget pointer * and deletes it at the appropriate time. * * This should be called ONE and ONLY one time. * * Unless prohibited by the second parameter, the central widget * will be automatically placed into a scroll area if the * widget makes the dialog too big for the screen. * * @param centralWidget * The central widget. * @param placeCentralWidgetInScrollAreaStatus * Status of using a scroll area for the central widget */ void WuQDialog::setCentralWidget(QWidget* centralWidget, const ScrollAreaStatus placeCentralWidgetInScrollAreaStatus) { CaretAssert(centralWidget); this->setTopBottomAndCentralWidgetsInternal(NULL, centralWidget, NULL, placeCentralWidgetInScrollAreaStatus); } /** * Sets the given widgets to be the window's top and central widget. * Note: WuQDialog takes ownership of the widget pointer * and deletes it at the appropriate time. * * This should be called ONE and ONLY one time. * * Unless prohibited by the second parameter, the central widget * will be automatically placed into a scroll area if the * widget makes the dialog too big for the screen. * * @param topWidget * The widget display at top. * @param centralWidget * The central widget. * @param topWidget * The widget display at top. * @param placeCentralWidgetInScrollAreaStatus * Status of using a scroll area for the central widget */ void WuQDialog::setTopBottomAndCentralWidgetsInternal(QWidget* topWidget, QWidget* centralWidget, QWidget* bottomWidget, const ScrollAreaStatus placeCentralWidgetInScrollAreaStatus) { m_topWidget = topWidget; m_centralWidget = centralWidget; m_bottomWidget = bottomWidget; m_placeCentralWidgetInScrollAreaStatus = placeCentralWidgetInScrollAreaStatus; if (topWidget != NULL) { this->userWidgetLayout->addWidget(topWidget); } m_centralWidgetLayoutIndex = userWidgetLayout->count(); this->userWidgetLayout->addWidget(centralWidget); if (bottomWidget != NULL) { this->userWidgetLayout->addWidget(bottomWidget); } } /** * Enable auto default button processing. * Often it is very annoying so use this method * withe enable == false, to disable it. * * @param enabled * New status for auto default processing. */ void WuQDialog::setAutoDefaultButtonProcessing(bool enabled) { this->autoDefaultProcessingEnabledFlag = enabled; } /** * Disable the auto default property for ANY buttons * in this dialog. This method must be called after * the subclass has added its widget(s) to the dialog. */ void WuQDialog::disableAutoDefaultForAllPushButtons() { /* * Disable auto default for all push buttons */ QList allChildPushButtons = findChildren(QRegExp(".*")); QListIterator allChildPushButtonsIterator(allChildPushButtons); while (allChildPushButtonsIterator.hasNext()) { QPushButton* pushButton = allChildPushButtonsIterator.next(); pushButton->setAutoDefault(false); pushButton->setDefault(false); } } /** * Called when a help button has been added to the dialog. * User must override this method when adding a help button. */ void WuQDialog::helpButtonClicked() { CaretAssertMessage(0, "Help button was added to dialog but WuQDialog::helpButtonClicked() was not overriden"); } /** * Called for focus events. Since this dialog stores a pointer * to the overlay, we need to be aware that the overlay's parameters * may change or the overlay may even be deleted. So, when * this dialog gains focus, validate the overlay and then update * the dialog. * * @param event * The focus event. */ void WuQDialog::focusInEvent(QFocusEvent* event) { if (event->reason() == Qt::PopupFocusReason) { /* * This occurs when a combo box is popped up Mac, * causes a problem, and can be ignored. */ return; } focusGained(); } /** * Will be called when dialog gains focus. User may override this * method to receive focus in events. */ void WuQDialog::focusGained() { /* nothing - intended to be overridden by users */ } /** * Gets called when the dialog is to be displayed. */ void WuQDialog::showEvent(QShowEvent* event) { int32_t resizedDialogWidth = -1; int32_t resizedDialogHeight = -1; if (m_firstTimeInShowMethodFlag) { const int32_t dialogWidth = sizeHint().width(); const int32_t dialogHeight = sizeHint().height(); /* * Maximum size is the size of the smallest screen. */ const QSize maxSize = WuQtUtilities::getMinimumScreenSize(); const int32_t margin = 100; const int32_t maximumDialogWidth = maxSize.width() - margin; const int32_t maximumDialogHeight = maxSize.height() - (margin * 2); // allow space top/bottom //const int32_t maximumDialogHeight = (maxSize.height() / 2) - margin; bool putCentralWidgetIntoScrollAreaFlag = false; bool testCentralWidgetForTooBig = false; switch (m_placeCentralWidgetInScrollAreaStatus) { case SCROLL_AREA_ALWAYS: putCentralWidgetIntoScrollAreaFlag = true; break; case SCROLL_AREA_AS_NEEDED_VERT_NO_HORIZ: putCentralWidgetIntoScrollAreaFlag = true; break; case SCROLL_AREA_AS_NEEDED: testCentralWidgetForTooBig = true; break; case SCROLL_AREA_NEVER: break; } if (testCentralWidgetForTooBig) { /* * Are contents too big for window? */ if ((dialogWidth > maximumDialogWidth) || (dialogHeight > maximumDialogHeight)) { putCentralWidgetIntoScrollAreaFlag = true; resizedDialogWidth = std::min(dialogWidth, maximumDialogWidth); resizedDialogHeight = std::min(dialogHeight, maximumDialogHeight); } } if (putCentralWidgetIntoScrollAreaFlag) { /* * Remove the central widget, * place it into a scroll area, * and insert the scroll area into the layout */ userWidgetLayout->removeWidget(m_centralWidget); QScrollArea* scrollArea = new QScrollArea(); scrollArea->setWidgetResizable(true); scrollArea->setWidget(m_centralWidget); if (m_placeCentralWidgetInScrollAreaStatus == SCROLL_AREA_AS_NEEDED_VERT_NO_HORIZ) { scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); } userWidgetLayout->insertWidget(m_centralWidgetLayoutIndex, scrollArea); /* * Resize the dialog. */ if ((resizedDialogWidth > 0) && (resizedDialogHeight > 0)) { m_sizeHintWidth = resizedDialogWidth; m_sizeHintHeight = resizedDialogHeight; adjustSize(); } } } QDialog::showEvent(event); m_firstTimeInShowMethodFlag = false; } /** * @return The size hint. * * Overriding the size hint is the best way to set the size of a dialog. */ QSize WuQDialog::sizeHint () const { QSize sh = QDialog::sizeHint(); if ((m_sizeHintWidth > 0) && (m_sizeHintHeight > 0)) { sh.setWidth(m_sizeHintWidth); sh.setHeight(m_sizeHintHeight); /* * Reset the size hint so that the user can resize the dialog * without it reverting to this size hint. */ m_sizeHintWidth = -1; m_sizeHintHeight = -1; } return sh; } /** * Set the size of the dialog for next time it is displayed. * This must be called BEFORE displayng the dialog. */ void WuQDialog::setSizeOfDialogWhenDisplayed(const QSize& size) { const int32_t w = size.width(); const int32_t h = size.height(); if ((w > 0) && (h > 0)) { m_sizeHintWidth = w; m_sizeHintHeight = h; } } /** * A scroll area's size hint is often larger than its content widget and in * this case the dialog will be too large with blank space in the scroll area. * This method will adjust the size of the dialog which in turn will shrink * the size of the scroll area to better fit its content. This should only * be called once for a dialog so that the user can adjust the size of the * dialog, if desired. * * @param dialog * Dialog whose size is adjusted. * @param scrollArea * The scroll area in the dialog. */ void WuQDialog::adjustSizeOfDialogWithScrollArea(QDialog* dialog, QScrollArea* scrollArea) { /* * The content region of a scroll area is often too large vertically * so adjust the size of the dialog which will cause the scroll area * to approximately fit its content. */ QWidget* scrollAreaContentWidget = scrollArea->widget(); if (scrollAreaContentWidget != NULL) { int32_t contentHeight = scrollAreaContentWidget->sizeHint().height(); int32_t scrollHeight = scrollArea->sizeHint().height(); int32_t scrollBarHeight = scrollArea->horizontalScrollBar()->sizeHint().height(); int32_t diff = (scrollHeight - (contentHeight + scrollBarHeight + 10)); if (diff > 0) { QSize dialogSizeHint = dialog->sizeHint(); dialogSizeHint.setHeight(dialogSizeHint.height() - diff); dialog->resize(dialogSizeHint); } } } /** * Adds a button to the dialog. When the button is * pressed, userButtonPressed(QPushButton*) will be * called with the button that was created and returned * by this method. The subclass of the dialog MUST * override userButtonPressed(QPushButton*). * * @param text * Text for the pushbutton. * @param buttonRole * Role of button. NOTE: This is used for placement of buttons in * the appropriate location for the operating system. Any action, * such as closing the dialog will not occur because of this button * push. * @return * QPushButton that was created. */ QPushButton* WuQDialog::addUserPushButton(const AString& text, const QDialogButtonBox::ButtonRole buttonRole) { QPushButton* pushButton = getDialogButtonBox()->addButton(text, buttonRole); return pushButton; } /** * Called when a push button was added using addUserPushButton(). * Subclasses MUST override this if user push buttons were * added using addUserPushButton(). * * @param userPushButton * User push button that was pressed. * @return * The result that indicates action that should be taken * as a result of the button being pressed. */ WuQDialog::DialogUserButtonResult WuQDialog::userButtonPressed(QPushButton* userPushButton) { const AString msg = ("Subclass of WuQDialog added a user pushbutton but failed to override userButtonPressed for button labeled \"" + userPushButton->text() + "\""); CaretAssertMessage(0, msg); CaretLogSevere(msg); return RESULT_NONE; } /** * Called when the OK button is clicked. * If needed should override this to process * data when the OK button is clicked and then * call this to issue the accept signal. */ void WuQDialog::okButtonClicked() { if (! isModal()) { CaretAssertMessage(0, "WuQDialog::okButtonClicked() should never be called for a NON-modal dialog."); } accept(); } /** * Called when the Cancel button is clicked. * If needed should override this to process * data when the Cancel button is clicked. * Call this to issue the reject signal. */ void WuQDialog::cancelButtonClicked() { if (! isModal()) { CaretAssertMessage(0, "WuQDialog::cancelButtonClicked() should never be called for a NON-modal dialog."); } reject(); } /** * Called when the Apply button is pressed. * If needed should override this to process * data when the Apply button is pressed. */ void WuQDialog::applyButtonClicked() { if (isModal()) { CaretAssertMessage(0, "WuQDialog::applyButtonClicked() should never be called for a MODAL dialog."); } } /** * Called when the Close button is pressed. * If needed should override this to process * data when the Close button is pressed. */ void WuQDialog::closeButtonClicked() { if (isModal()) { CaretAssertMessage(0, "WuQDialog::closeButtonClicked() should never be called for a MODAL dialog."); } close(); } /** * Called when a button is pressed. */ void WuQDialog::clicked(QAbstractButton* button) { QDialogButtonBox::StandardButton standardButton = this->getDialogButtonBox()->standardButton(button); if (standardButton == QDialogButtonBox::Ok) { button->setEnabled(false); okButtonClicked(); button->setEnabled(true); } else if (standardButton == QDialogButtonBox::Cancel) { cancelButtonClicked(); } else if (standardButton == QDialogButtonBox::Apply) { applyButtonClicked(); } else if (standardButton == QDialogButtonBox::Close) { closeButtonClicked(); } else if (standardButton == QDialogButtonBox::Help) { this->helpButtonClicked(); } else { QPushButton* pushButton = qobject_cast(button); CaretAssert(pushButton); const DialogUserButtonResult result = this->userButtonPressed(pushButton); switch (result) { case RESULT_MODAL_ACCEPT: accept(); break; case RESULT_MODAL_REJECT: reject(); break; case RESULT_NON_MODAL_CLOSE: close(); break; case RESULT_NONE: break; }; } } connectome-workbench-1.4.2/src/GuiQt/WuQDialog.h000066400000000000000000000132301360521144700214570ustar00rootroot00000000000000#ifndef __WU_QDIALOG_H__ #define __WU_QDIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "AString.h" class QFocusEvent; class QHBoxLayout; class QKeyEvent; class QMenu; class QScrollArea; class QVBoxLayout; namespace caret { class WuQDialog : public QDialog { Q_OBJECT protected: WuQDialog(const AString& dialogTitle, QWidget* parent, Qt::WindowFlags f = 0); public: /** * Status of scroll area displayed */ enum ScrollAreaStatus { SCROLL_AREA_ALWAYS, SCROLL_AREA_AS_NEEDED, SCROLL_AREA_AS_NEEDED_VERT_NO_HORIZ, SCROLL_AREA_NEVER }; /** * Result of user button pressed. */ enum DialogUserButtonResult { /** MODAL accept which means OK pressed and dialog closes */ RESULT_MODAL_ACCEPT, /** MODAL reject which means Cancel pressed and dialog closes */ RESULT_MODAL_REJECT, /** NON-MODAL close dialog. */ RESULT_NON_MODAL_CLOSE, /** none which means no action is taken and dialog remains open */ RESULT_NONE }; virtual ~WuQDialog(); void setCentralWidget(QWidget* centralWidget, const ScrollAreaStatus placeCentralWidgetInScrollAreaStatus); void setTopBottomAndCentralWidgets(QWidget* topWidget, QWidget* centralWidget, QWidget* bottomWidget, const ScrollAreaStatus placeCentralWidgetInScrollAreaStatus); void setStandardButtonText(QDialogButtonBox::StandardButton button, const AString& text); void setStandardButtonEnabled(QDialogButtonBox::StandardButton button, const bool enabled); QPushButton* addUserPushButton(const AString& text, const QDialogButtonBox::ButtonRole buttonRole); void setDeleteWhenClosed(bool deleteFlag); void setAutoDefaultButtonProcessing(bool enabled); void disableAutoDefaultForAllPushButtons(); void addWidgetToLeftOfButtons(QWidget* widget); static void beep(); static void showWaitCursor(); static void showNormalCursor(); static void adjustSizeOfDialogWithScrollArea(QDialog* dialog, QScrollArea* scrollArea); virtual QSize sizeHint() const; void setSizeOfDialogWhenDisplayed(const QSize& size); public slots: virtual bool close(); protected slots: void slotMenuCaptureImageOfWindowToClipboard(); void slotCaptureImageAfterTimeOut(); protected: QDialogButtonBox* getDialogButtonBox(); virtual DialogUserButtonResult userButtonPressed(QPushButton* userPushButton); void addImageCaptureToMenu(QMenu* menu); virtual void okButtonClicked(); virtual void cancelButtonClicked(); virtual void applyButtonClicked(); virtual void closeButtonClicked(); virtual void keyPressEvent(QKeyEvent* e); virtual void contextMenuEvent(QContextMenuEvent*); virtual void focusInEvent(QFocusEvent* event); virtual void helpButtonClicked(); virtual void focusGained(); virtual void showEvent(QShowEvent* event); private slots: void clicked(QAbstractButton* button); private: void setTopBottomAndCentralWidgetsInternal(QWidget* topWidget, QWidget* centralWidget, QWidget* bottomWidget, const ScrollAreaStatus placeCentralWidgetInScrollAreaStatus); QVBoxLayout* userWidgetLayout; QDialogButtonBox* buttonBox; QHBoxLayout* m_layoutLeftOfButtonBox; bool autoDefaultProcessingEnabledFlag; bool m_firstTimeInShowMethodFlag; ScrollAreaStatus m_placeCentralWidgetInScrollAreaStatus; int32_t m_centralWidgetLayoutIndex; QWidget* m_topWidget; QWidget* m_centralWidget; QWidget* m_bottomWidget; mutable int32_t m_sizeHintWidth; mutable int32_t m_sizeHintHeight; }; #ifdef __WU_QDIALOG_DECLARE__ #endif // __WU_QDIALOG_DECLARE__ } #endif // __WU_QDIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/WuQDialogModal.cxx000066400000000000000000000160161360521144700230140ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __WU_Q_DIALOG_MODAL_DECLARE__ #include "WuQDialogModal.h" #undef __WU_Q_DIALOG_MODAL_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" using namespace caret; /** * \class caret::WuQDialogModal * \brief Base class for modal dialogs. * * A base class for modal dialogs. */ /** * Constructs a modal dialog. After construction, * use exec() to display the dialog. * * @param dialogTitle * Title for dialog. * @param parent * Parent widget on which this dialog is displayed. * @param f * optional Qt::WindowFlags */ WuQDialogModal::WuQDialogModal(const AString& dialogTitle, QWidget* parent, Qt::WindowFlags f) : WuQDialog(dialogTitle, parent, f) { m_isSaveDialogPosition = false; this->getDialogButtonBox()->addButton(QDialogButtonBox::Ok); this->getDialogButtonBox()->addButton(QDialogButtonBox::Cancel); // QObject::connect(this->getDialogButtonBox(), SIGNAL(clicked(QAbstractButton*)), // this, SLOT(clicked(QAbstractButton*))); this->getDialogButtonBox()->button(QDialogButtonBox::Ok)->setDefault(true); //this->getDialogButtonBox()->button(QDialogButtonBox::Ok)->setAutoDefault(true); } /** * Constructs a modal dialog. After construction, * use exec() to display the dialog. * * @param dialogTitle * Title for dialog. * @param centralWidget, * Central widget that is displayed in the dialog. * @param parent * Parent widget on which this dialog is displayed. * @param f * optional Qt::WindowFlags */ WuQDialogModal::WuQDialogModal(const AString& dialogTitle, QWidget* centralWidget, QWidget* parent, Qt::WindowFlags f) : WuQDialog(dialogTitle, parent, f) { this->getDialogButtonBox()->addButton(QDialogButtonBox::Ok); this->getDialogButtonBox()->addButton(QDialogButtonBox::Cancel); QObject::connect(this->getDialogButtonBox(), SIGNAL(clicked(QAbstractButton*)), this, SLOT(clicked(QAbstractButton*))); this->setCentralWidget(centralWidget, WuQDialog::SCROLL_AREA_NEVER); } /** * Destructor. */ WuQDialogModal::~WuQDialogModal() { } /** * Set the OK button to the given text. If the text * is zero length, the OK button is removed. * * @text * Text for OK button. */ void WuQDialogModal::setOkButtonText(const AString& text) { this->setStandardButtonText(QDialogButtonBox::Ok, text); /* if (text.isEmpty()) { this->getDialogButtonBox()->button(QDialogButtonBox::Cancel)->setDefault(true); this->getDialogButtonBox()->button(QDialogButtonBox::Cancel)->setAutoDefault(true); } else { this->getDialogButtonBox()->button(QDialogButtonBox::Ok)->setDefault(true); this->getDialogButtonBox()->button(QDialogButtonBox::Ok)->setAutoDefault(true); } */ } /** * Set the enabled status for the OK button. * * @param enabled * New enabled status for the button. */ void WuQDialogModal::setOkButtonEnabled(const bool enabled) { this->setStandardButtonEnabled(QDialogButtonBox::Ok, enabled); } /** * Set the Cancel button to the given text. If the text * is zero length, the Cancel button is removed. * * @text * Text for OK button. */ void WuQDialogModal::setCancelButtonText(const AString& text) { this->setStandardButtonText(QDialogButtonBox::Cancel, text); } /** * If this method is called, each time the dialog is closed, it will * save the position of the dialog and restore the dialog to that * position when the dialog is reopened. * * @param savePositionName * Name used for saving the dialog's position. If the default value * (an empty string), the dialog's title is used for saving the * dialog's position. Note that is there is more than one dialog * with the same name positions may not be correctly restored. */ void WuQDialogModal::setSaveWindowPositionForNextTime(const AString& savePositionName) { m_isSaveDialogPosition = true; m_saveDialogPositionName = savePositionName; if (m_saveDialogPositionName.isEmpty()) { m_saveDialogPositionName = windowTitle(); if (m_saveDialogPositionName.isEmpty()) { m_isSaveDialogPosition = false; } } } /** * Shows/hides a widget. * Override to optionally place dialog via values passed to setDisplayedXY. */ void WuQDialogModal::setVisible(bool visible) { WuQDialog::setVisible(visible); if (m_isSaveDialogPosition) { /* * Find previous position of dialog. */ std::map::iterator iter = s_savedDialogPositions.find(m_saveDialogPositionName); if (visible) { if (iter != s_savedDialogPositions.end()) { /* * Restore dialog position */ SavedPosition savedPosition = iter->second; if ((savedPosition.x > 0) && (savedPosition.y > 0)) { move(savedPosition.x, savedPosition.y); } if ((savedPosition.w > 0) && (savedPosition.h > 0)) { resize(savedPosition.w, savedPosition.h); } } } else { /* * Save position of dialog. */ SavedPosition savedPosition; savedPosition.x = x(); savedPosition.y = y(); savedPosition.w = width(); savedPosition.h = height(); if (iter != s_savedDialogPositions.end()) { /* * Replace dialog position */ iter->second = savedPosition; } else { /* * Insert dialog position */ s_savedDialogPositions.insert(std::make_pair(m_saveDialogPositionName, savedPosition)); } } } } connectome-workbench-1.4.2/src/GuiQt/WuQDialogModal.h000066400000000000000000000047621360521144700224460ustar00rootroot00000000000000#ifndef __WU_Q_DIALOG_MODAL__H_ #define __WU_Q_DIALOG_MODAL__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WuQDialog.h" namespace caret { class WuQDialogModal : public WuQDialog { Q_OBJECT public: WuQDialogModal(const AString& dialogTitle, QWidget* parent, Qt::WindowFlags f = 0); WuQDialogModal(const AString& dialogTitle, QWidget* centralWidget, QWidget* parent, Qt::WindowFlags f = 0); virtual ~WuQDialogModal(); void setOkButtonText(const AString& text); void setOkButtonEnabled(const bool enabled); void setCancelButtonText(const AString& text); void setSaveWindowPositionForNextTime(const AString& savePositionName = ""); public slots: virtual void setVisible(bool); private: WuQDialogModal(const WuQDialogModal&); WuQDialogModal& operator=(const WuQDialogModal&); private: bool m_isSaveDialogPosition; AString m_saveDialogPositionName; struct SavedPosition { SavedPosition() { x = -1; y = -1; w = -1; h = -1; } int x; int y; int w; int h; }; static std::map s_savedDialogPositions; }; #ifdef __WU_Q_DIALOG_MODAL_DECLARE__ std::map WuQDialogModal::s_savedDialogPositions; #endif // __WU_Q_DIALOG_MODAL_DECLARE__ } // namespace #endif //__WU_Q_DIALOG_MODAL__H_ connectome-workbench-1.4.2/src/GuiQt/WuQDialogNonModal.cxx000066400000000000000000000135351360521144700234720ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __WU_Q_DIALOG_NON_MODAL_DECLARE__ #include "WuQDialogNonModal.h" #undef __WU_Q_DIALOG_NON_MODAL_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" using namespace caret; /** * \class caret::WuQDialogNonModal * \brief Base class for non-modal dialogs. * * A base class for non-modal dialogs. */ /** * Constructs a modal dialog. After construction, * use exec() to display the dialog. * * @param dialogTitle * Title for dialog. * @param parent * Parent widget on which this dialog is displayed. * @param f * optional Qt::WindowFlags */ WuQDialogNonModal::WuQDialogNonModal(const AString& dialogTitle, QWidget* parent, Qt::WindowFlags f) : WuQDialog(dialogTitle, parent, f) { this->getDialogButtonBox()->addButton(QDialogButtonBox::Apply); this->getDialogButtonBox()->addButton(QDialogButtonBox::Close); // QObject::connect(this->getDialogButtonBox(), SIGNAL(clicked(QAbstractButton*)), // this, SLOT(clicked(QAbstractButton*))); this->getDialogButtonBox()->button(QDialogButtonBox::Apply)->setDefault(false); this->getDialogButtonBox()->button(QDialogButtonBox::Apply)->setAutoDefault(false); this->getDialogButtonBox()->button(QDialogButtonBox::Close)->setDefault(false); this->getDialogButtonBox()->button(QDialogButtonBox::Close)->setAutoDefault(false); m_isPositionRestoredWhenReopened = false; m_positionWhenClosedValid = false; } /** * Destructor. */ WuQDialogNonModal::~WuQDialogNonModal() { } /** * Show the dialog. * * There are a number of methods for 'showing' a Qt dialog. * Some of them will show the dialog for the first time. * If the dialog is 'behind' the main window, not all * of the methods put the dialog in front of the window. * This methods uses several of the Qt methods to ensure * that the dialog is moved in front of a main window. */ void WuQDialogNonModal::showDialog() { this->setVisible(true); this->show(); this->activateWindow(); this->raise(); } /** * May be called requesting the dialog to update its content * Subclasses should override. */ void WuQDialogNonModal::updateDialog() { #ifdef DEBUG QString text(getObjectName() + " should override updateDialog"); CaretLogWarning(text); #endif } /** * Gets called when the dialog is closing. * Overriden so that position of dialog * can be saved. */ void WuQDialogNonModal::closeEvent(QCloseEvent* /*event*/) { // if (m_isPositionRestoredWhenReopened) { // /* // * Save position and size of dialog so that // * when it is shown next time, it will be // * in the position and size as when it was // * closed. // */ // m_positionWhenClosedValid = true; // m_positionWhenClosed = this->pos(); // m_sizeWhenClosed = this->size(); // } // // WuQDialog::closeEvent(event); emit dialogWasClosed(); } /** * Gets called when the dialog is to be displayed. */ void WuQDialogNonModal::showEvent(QShowEvent* event) { // if (m_isPositionRestoredWhenReopened) { // if (m_positionWhenClosedValid) { // /* // * Restore the dialog in the position and size that it // * was in when closed. Use move() for position and // * the size hint for the size. // */ // this->move(m_positionWhenClosed); // this->resize(m_sizeWhenClosed); //// const int32_t w = m_sizeWhenClosed.width(); //// const int32_t h = m_sizeWhenClosed.height(); //// if ((w > 0) //// && (h > 0)) { //// this->setDialogSizeHint(w, //// h); //// adjustSize(); //// } // } // } WuQDialog::showEvent(event); } /** * This slot can be called and it simply calls * applyButtonClicked. This slot can be connected * to GUI components. */ void WuQDialogNonModal::apply() { this->applyButtonClicked(); } /** * Set the Apply button to the given text. If the text * is zero length, the Apply button is removed. * * @text * Text for OK button. */ void WuQDialogNonModal::setApplyButtonText(const AString& text) { this->setStandardButtonText(QDialogButtonBox::Apply, text); } /** * Set the Close button to the given text. If the text * is zero length, the Close button is removed. * * @text * Text for OK button. */ void WuQDialogNonModal::setCloseButtonText(const AString& text) { this->setStandardButtonText(QDialogButtonBox::Close, text); } /** * If the given parameter is true, save the position of this * dialog when it is closed. Next time window is displayed * in the current session, use the position at the time the * dialog was closed. * @param saveIt * If true save the position for next time. */ void WuQDialogNonModal::setSaveWindowPositionForNextTime(const bool saveIt) { m_isPositionRestoredWhenReopened = saveIt; } connectome-workbench-1.4.2/src/GuiQt/WuQDialogNonModal.h000066400000000000000000000045531360521144700231170ustar00rootroot00000000000000#ifndef __WU_Q_DIALOG_NON_MODAL__H_ #define __WU_Q_DIALOG_NON_MODAL__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WuQDialog.h" namespace caret { class WuQDialogNonModal : public WuQDialog { Q_OBJECT public: WuQDialogNonModal(const AString& dialogTitle, QWidget* parent = 0, Qt::WindowFlags f = 0); virtual ~WuQDialogNonModal(); void setApplyButtonText(const AString& text); void setCloseButtonText(const AString& text); void showDialog(); virtual void updateDialog(); //virtual void updateDialog() = 0; void setSaveWindowPositionForNextTime(const bool saveIt); signals: /** * This signal is emitted when the dialog is closed (hidden). */ void dialogWasClosed(); protected slots: void apply(); protected: virtual void closeEvent(QCloseEvent* event); virtual void showEvent(QShowEvent* event); private: WuQDialogNonModal(const WuQDialogNonModal&); WuQDialogNonModal& operator=(const WuQDialogNonModal&); QPoint m_positionWhenClosed; QSize m_sizeWhenClosed; bool m_positionWhenClosedValid; bool m_isPositionRestoredWhenReopened; }; #ifdef __WU_Q_DIALOG_NON_MODAL_DECLARE__ // #endif // __WU_Q_DIALOG_NON_MODAL_DECLARE__ } // namespace #endif //__WU_Q_DIALOG_NON_MODAL__H_ connectome-workbench-1.4.2/src/GuiQt/WuQDoubleSlider.cxx000066400000000000000000000101501360521144700232060ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_DOUBLE_SLIDER_DECLARE__ #include "WuQDoubleSlider.h" #undef __WU_Q_DOUBLE_SLIDER_DECLARE__ #include using namespace caret; /** * \class caret::WuQDoubleSlider * \brief A slider for real values. * * Creates a slider for real values by encapsulating * a QSlider that operates only on integer values. */ /** * Constructor. * * @param orientation * horizontal or vertical * @param parent * optional parent */ WuQDoubleSlider::WuQDoubleSlider(Qt::Orientation orientation, QObject* parent) : WuQWidget(parent) { this->slider = new QSlider(orientation); this->slider->setRange(0, 1000); QObject::connect(this->slider, SIGNAL(valueChanged(int)), this, SLOT(qSliderValueChanged(int))); this->setRange(-100.0, 100.0); this->setValue(0); } /** * Destructor. */ WuQDoubleSlider::~WuQDoubleSlider() { } /** * Called when the encapsulated QSlider * value is changed. * @param value * New value. */ void WuQDoubleSlider::qSliderValueChanged(int value) { const double dSlider = this->slider->maximum() - this->slider->minimum(); const double parametricValue = (static_cast(value) - this->slider->minimum()) / dSlider; double dRange = this->maximum - this->minimum; if (dRange == 0.0) { dRange = 1.0; } this->sliderValue = dRange * parametricValue + this->minimum; emit valueChanged(this->sliderValue); } /** * @return The widget that is enapsulated. */ QWidget* WuQDoubleSlider::getWidget() { return this->slider; } /** * Set range of values. * @param minValue * New value for minimum. * @param maxValue * New value for maximum. */ void WuQDoubleSlider::setRange(double minValue, double maxValue) { this->minimum = minValue; this->maximum = maxValue; if (this->minimum > this->maximum) { this->maximum = this->minimum; } this->updateSlider(); } /** * @return The minimum value of the slider. */ double WuQDoubleSlider::minimumValue() const { return this->minimum;; } /** * @return The maximum value of the slider. */ double WuQDoubleSlider::maximumValue() const { return this->maximum;; } /** * @return The value of the slider. */ double WuQDoubleSlider::value() const { return this->sliderValue; } /** * Set the value for the slider. * @param d * New value. */ void WuQDoubleSlider::setValue(double valueIn) { this->sliderValue = valueIn; this->updateSlider(); emit valueChanged(this->sliderValue); } /** * Update the encapsulated slider. */ void WuQDoubleSlider::updateSlider() { double dRange = this->maximum - this->minimum; if (dRange == 0.0) { dRange = 1.0; } if (this->sliderValue > this->maximum) { this->sliderValue = this->maximum; } if (this->sliderValue < this->minimum) { this->sliderValue = this->minimum; } const double parametricValue = (this->sliderValue - this->minimum) / dRange; const int dSlider = this->slider->maximum() - this->slider->minimum(); const int qSliderValue = static_cast(dSlider * parametricValue);;// + this->minimum; this->slider->blockSignals(true); this->slider->setValue(qSliderValue); this->slider->blockSignals(false); } connectome-workbench-1.4.2/src/GuiQt/WuQDoubleSlider.h000066400000000000000000000040641360521144700226420ustar00rootroot00000000000000#ifndef __WU_Q_DOUBLE_SLIDER__H_ #define __WU_Q_DOUBLE_SLIDER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WuQWidget.h" class QSlider; namespace caret { class WuQDoubleSlider : public WuQWidget { Q_OBJECT public: WuQDoubleSlider(Qt::Orientation orientation, QObject* parent); virtual ~WuQDoubleSlider(); QWidget* getWidget(); void setRange(double minValue, double maxValue); double minimumValue() const; double maximumValue() const; double value() const; signals: void valueChanged(double); public slots: void setValue(double); private slots: void qSliderValueChanged(int); private: WuQDoubleSlider(const WuQDoubleSlider&); WuQDoubleSlider& operator=(const WuQDoubleSlider&); void updateSlider(); QSlider* slider; double minimum; double maximum; double sliderValue; }; #ifdef __WU_Q_DOUBLE_SLIDER_DECLARE__ // #endif // __WU_Q_DOUBLE_SLIDER_DECLARE__ } // namespace #endif //__WU_Q_DOUBLE_SLIDER__H_ connectome-workbench-1.4.2/src/GuiQt/WuQDoubleSpinBox.cxx000066400000000000000000000510241360521144700233530ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_DOUBLE_SPIN_BOX_DECLARE__ #include "WuQDoubleSpinBox.h" #undef __WU_Q_DOUBLE_SPIN_BOX_DECLARE__ #include #include #include #include "AString.h" #include "CaretAssert.h" #include "NumericTextFormatting.h" using namespace caret; /** * \class caret::WuQDoubleSpinBox * \brief Customizable double spin box * \ingroup GuiQt * * An 'extension' of QDoubleSpinBox. There are methods in * QDoubleSpinBox that we would like to override but the methods * are not virtual. So, extend WuQWidget (which extends QObject), * encapsulate QDoubleSpinbox, and implement needed methods. * * Added features are: * (1) Ability to automatically compute digits right of decimal * based upon the range of the data. * * (2) Ablity to set increment/decrement values as a percentage * of the range of data. * * (3) Ability to set an "exceedable" range. A QDoubleSpinBox * will NOT emit a 'valueChanged' signal if the user tries to * exceed the minimum or maximum value. 'setRangeExceedable()' * will allow the minimum and maximum values to be exceeded * but any auto formatting (decimals, step size) is based * only on the minimum and maximum values specified. * * (4) if 'QDoubleSpinBox::setValue()' is called, it will * emit the 'valueChanged()' signal which can be problematic * when updating the value in the spin box. This implementation * DOES NOT emit the 'valueChanged()' signal when 'setValue()' * is called. */ /** * Constructs a spin box with 0.0 as minimum value and 99.99 as maximum value, * a step value of 1.0 and a precision of 2 decimal places. * The value is initially set to 0.00. The spin box has the given parent. * * @param parent * The parent widget. */ WuQDoubleSpinBox::WuQDoubleSpinBox(QObject* parent) : WuQWidget(parent) { /* * Create the spin box and initialize it * Note that most members are initialized in the header file */ m_spinBox = new QDoubleSpinBox(); m_spinBox->setRange(m_minimumValue, m_maximumValue); m_spinBox->setSingleStep(1.0); m_spinBox->setDecimals(2); m_spinBox->setValue(0.0); QObject::connect(m_spinBox, static_cast(&QDoubleSpinBox::valueChanged), this, &WuQDoubleSpinBox::valueChangedPrivate); } /** * Destructor. */ WuQDoubleSpinBox::~WuQDoubleSpinBox() { } /** * @return The encapsulated widget. Usually used to * add the widget to a layout. */ QWidget* WuQDoubleSpinBox::getWidget() { return m_spinBox; } ///** // * Copy all setting from the given spin box // * // * @param copyFromSpinBox // * Spinbox from which settings are copied to 'this' instance // */ //void //WuQDoubleSpinBox::copySettings(const WuQDoubleSpinBox* copyFromSpinBox) //{ // CaretAssert(copyFromSpinBox); // // switch (m_rangeMode) { // case RangeMode::EXCEEDABLE: // setRangeExceedable(m_minimumValue, m_maximumValue, m_exceedRangeMultiplier); // break; // case RangeMode::INCLUSIVE: // setRange(m_minimumValue, m_maximumValue); // } // m_decimalsMode = copyFromSpinBox->m_decimalsMode; // switch (copyFromSpinBox->m_decimalsMode) { // case DecimalsMode::AUTO: // setDecimalsModeAuto(); // break; // case DecimalsMode::FIXED: // setDecimals(copyFromSpinBox->decimals()); // break; // } // // setPrefix(copyFromSpinBox->prefix()); // setSuffix(copyFromSpinBox->suffix()); // // setSingleStep(copyFromSpinBox->singleStep()); // m_singleStepPercentage = copyFromSpinBox->m_singleStepPercentage; // m_singleStepMode = copyFromSpinBox->m_singleStepMode; // switch (m_singleStepMode) { // case SingleStepMode::FIXED: // break; // case SingleStepMode::PERCENTAGE: // setSingleStepPercentage(copyFromSpinBox->singleStepPercentage()); // break; // } //} ///** // * Explicit conversion to QWidget // */ //WuQDoubleSpinBox::operator //QWidget*() const //{ // return m_spinBox; //} /** * @return The decimals mode. */ WuQDoubleSpinBox::DecimalsMode WuQDoubleSpinBox::decimalsMode() const { return m_decimalsMode; } /** * Set the decimals mode to auto. To exit auto use setDecimals(int). */ void WuQDoubleSpinBox::setDecimalsModeAuto() { m_decimalsMode = DecimalsMode::AUTO; updateDecimalsForAutoMode(); } /** * @return Digits right of decimal point */ int WuQDoubleSpinBox::decimals() const { return m_spinBox->decimals(); } /** * Sets fixed number of decimals the spinbox will use for displaying and interpreting doubles. * * Also sets the DecimalMode to a fixed number of digits right of the decimal. * * @param prec * Number of digits right of decimal */ void WuQDoubleSpinBox::setDecimals(int prec) { m_decimalsMode = DecimalsMode::FIXED; m_spinBox->setDecimals(prec); } /** * Compute the number of digits right of the decimal point for * the given range of data. * * @param range * Range of the data. * @return * Number of digits right of decimal point. */ int32_t WuQDoubleSpinBox::computeDigitsRightOfDecimal(const double dataRange) { const double range = ((dataRange >=0) ? dataRange : -dataRange); int32_t numDecimals = 3; if (range > 0.0) { int32_t logValue = static_cast(std::log10(range)); if (logValue == 0) { numDecimals = 3; } else if (logValue > 0) { // range > 1 numDecimals = 4 - logValue; } else if (logValue < 0) { // 0 < range < 1 numDecimals = 3 - logValue; } if (numDecimals < 1) { numDecimals = 1; } else if (numDecimals > 15) { numDecimals = 15; } } return numDecimals; } /** * Compute a reasonable 'exceed range' which is used * for setting the acceptable values in the spin box * to the range of data plus a reasonable amount * above and below. * * @param minValue * The minimum data value. * @param maxValue * The maximum data value. * @param * Exceed amount for increased range. */ double WuQDoubleSpinBox::computeExceedRange(const double minValue, const double maxValue) { double exceedRange = 10.0; const double range = maxValue - minValue; if (range >= 1.0) { const double logVal = std::log10(range); const double exponent = logVal + 2; exceedRange = std::pow(10.0, exponent); } return exceedRange; } /** * Testing of the exceed ragne. */ void WuQDoubleSpinBox::testExceedRange() { { const double value = 0.0; const double exceedRange = computeExceedRange(0.0, value); AString s = QString("Range: %1 execeedRange: %2").arg(value, 10).arg(exceedRange); std::cout << s << std::endl; } for (int32_t exponent = -10; exponent <= 10; exponent++) { const double value = std::pow(10.0, exponent); const double exceedRange = computeExceedRange(0.0, value); AString s = QString("Range: %1 exceedRange: %2 lo10: %3").arg(value, 10).arg(exceedRange).arg((int)std::log10(value)); std::cout << s << std::endl; } std::cout << std::endl << std::endl; } /** * Used for testing computation of digits right of decimal point. */ void WuQDoubleSpinBox::testDigitsRightOfDecimal() { { const double value = 0.0; const int32_t decimals = computeDigitsRightOfDecimal(value); AString s = QString("Range: %1 decimals: %2").arg(value, 10).arg(decimals, 5); std::cout << s << std::endl; } for (int32_t exponent = -10; exponent <= 10; exponent++) { const double value = std::pow(10.0, exponent); const int32_t decimals = computeDigitsRightOfDecimal(value); AString s = QString("Range: %1 decimals: %2 lo10: %3").arg(value, 10).arg(decimals, 5).arg((int)std::log10(value)); std::cout << s << std::endl; } std::cout << std::endl << std::endl; } /** * Update the decimals for AUTO mode */ void WuQDoubleSpinBox::updateDecimalsForAutoMode() { static bool decimalsTestFlag = false; if (decimalsTestFlag) { testDigitsRightOfDecimal(); testExceedRange(); decimalsTestFlag = false; } switch (m_decimalsMode) { case DecimalsMode::AUTO: m_spinBox->setDecimals(computeDigitsRightOfDecimal(m_maximumValue - m_minimumValue)); break; case DecimalsMode::FIXED: break; } } /** * @return Minimum DISPLAYED value. */ double WuQDoubleSpinBox::minimum() const { return m_spinBox->minimum(); } /** * @return Maximum DISPLAYED value. */ double WuQDoubleSpinBox::maximum() const { return m_spinBox->maximum(); } /** * @return Prefix prepended to start of displayed value. */ QString WuQDoubleSpinBox::prefix() const { return m_spinBox->prefix(); } /** * Set the prefix is prepended to the start of the displayed value. * Typical use is to display a unit of measurement or a currency symbol. * * @param prefix * New prefix */ void WuQDoubleSpinBox::setPrefix(const QString &prefix) { m_spinBox->setPrefix(prefix); } /** * Set the minimum and maximum values for this spin box. * * @param minimum * New minimum value. * @param maximum * New maximum value. */ void WuQDoubleSpinBox::setRange(double minimum, double maximum) { m_minimumValue = minimum; m_maximumValue = maximum; m_rangeMode = RangeMode::INCLUSIVE; m_spinBox->setRange(m_minimumValue, m_maximumValue); updateDecimalsForAutoMode(); updateSingleStepPercentage(); setDataRangeToolTip(); } /** * Set range with an automatically calculated 'exceedAmount', typically * 100 times the range and a power of 10. * * Any automatic formatting or decimals excludes the "exceed amount". * * @param minimum * New minimum value. * @param maximum * New maximum value. */ void WuQDoubleSpinBox::setRangeExceedable(double minimum, double maximum) { const double exceedAmount = computeExceedRange(minimum, maximum); const double exceedMin = makePowerOfTen(minimum - exceedAmount); const double exceedMax = makePowerOfTen(maximum + exceedAmount); setRangeExceedable(minimum, maximum, exceedMin, exceedMax); } /** * Set the range of the data and the spin box. * All formating is based upon the data minimum and maximum. * * @param dataMinimum * Data minimum value. * @param dataMaximum * Data maximum value. * @param spinBoxMinimum * Spinbox minimum value. * @param spinBoxMaximum * Spinbox maximum value. */ void WuQDoubleSpinBox::setRangeExceedable(const double dataMinimum, const double dataMaximum, const double spinBoxMinimum, const double spinBoxMaximum) { m_minimumValue = dataMinimum; m_maximumValue = dataMaximum; m_rangeMode = RangeMode::EXCEEDABLE; m_spinBox->setRange(spinBoxMinimum, spinBoxMaximum); updateDecimalsForAutoMode(); updateSingleStepPercentage(); setDataRangeToolTip(); } /** * Increase the value to the next power of ten. * Example: 8500 becomes 10000 * * @param value * The value. * @return * Value increased to next power of ten. */ double WuQDoubleSpinBox::makePowerOfTen(const double value) const { const bool negativeFlag = (value < 0.0); double valuePositive = std::fabs(value); const int64_t logVal = static_cast(std::log10(valuePositive) + 1); double powerTenValue = std::pow(10.0, logVal); if (negativeFlag) { powerTenValue = -powerTenValue; } return powerTenValue; } /** * Set range with a specified 'exceedAmount'. * Selected value is allowed to exceed minimum and maximum by exceedAmount. * Any automatic formatting or decimals excludes the "exceed amount". * * @param minimum * New minimum value. * @param maximum * New maximum value. * @param exceedAmount * The fixed exceed amount. */ void WuQDoubleSpinBox::setRangeExceedable(double minimum, double maximum, double exceedAmount) { setRangeExceedable(minimum, maximum, minimum - exceedAmount, maximum + exceedAmount); } /** * Set range for percentage values. Percentage range * [0.0, 100], with 2 digits right of decimal, * a single step of 0.1, and a '%' suffix. * * @param minimumPercentage * Minimum percentage (must be in range [0.0, 100.0] * @param maximumPercentage * Maximum percentage (must be in range [0.0, 100.0] */ void WuQDoubleSpinBox::setRangePercentage(const double minimumPercentage, const double maximumPercentage) { setRange(minimumPercentage, maximumPercentage); setDecimals(2); setSingleStepPercentage(0.1); setSuffix("%"); setDataRangeToolTip(); } /** * Set the step value. When the user uses the arrows to change the * spin box's value the value will be incremented/decremented by the * amount of the given value. * * NOTE: When this method is called, the SingleStepMode is set * to FIXED * * @param value * New step value. */ void WuQDoubleSpinBox::setSingleStep(double value) { CaretAssert(value >= 0.0); m_spinBox->setSingleStep(value); m_singleStepMode = SingleStepMode::FIXED; } /** * Set the step value. When the user uses the arrows to change the * spin box's value the value will be incremented/decremented by a * percentage of the minimum and maximum values. * * NOTE: When this method is called, the SingleStepMode is set * to PERCENTAGE. * * @param percentage * The step percentage that ranges (0.0, 100.0]. */ void WuQDoubleSpinBox::setSingleStepPercentage(double percentage) { CaretAssert(percentage > 0.0); CaretAssert(percentage <= 100.0); m_singleStepPercentage = percentage; m_singleStepMode = SingleStepMode::PERCENTAGE; updateSingleStepPercentage(); } /** * Update the single step percentage when the minimum value, * maximum value, or step percentage is changed. */ void WuQDoubleSpinBox::updateSingleStepPercentage() { switch (m_singleStepMode) { case SingleStepMode::FIXED: break; case SingleStepMode::PERCENTAGE: { const double minValue = m_minimumValue; const double maxValue = m_maximumValue; const double dataRange = maxValue - minValue; double stepValue = 0.0; if (dataRange > 0.0) { stepValue = dataRange * (m_singleStepPercentage / 100.0); } m_spinBox->setSingleStep(stepValue); } break; } } /** * Set the suffix is append to the start of the displayed value. * Typical use is to display a unit of measurement or a currency symbol. * * @param suffix * New suffix */ void WuQDoubleSpinBox::setSuffix(const QString &suffix) { m_spinBox->setSuffix(suffix); } /** * @return The single step value. */ double WuQDoubleSpinBox::singleStep() const { return m_spinBox->singleStep(); } /** * @return The single step mode. */ WuQDoubleSpinBox::SingleStepMode WuQDoubleSpinBox::singleStepMode() const { return m_singleStepMode; } /** * @return The single step percentage value. */ double WuQDoubleSpinBox::singleStepPercentage() const { return m_singleStepPercentage; } /** * @return The suffix. */ QString WuQDoubleSpinBox::suffix() const { return m_spinBox->suffix(); } /** * This virtual function is used by the spin box whenever it needs to * display the given value. The default implementation returns a * string containing value printed using QWidget::locale().toString(value, QLatin1Char('f'), * decimals()) and will remove the thousand separator unless setGroupSeparatorShown() is set. * Reimplementations may return anything. * * @return Text representation of current value. */ QString WuQDoubleSpinBox::textFromValue(double value) const { return m_spinBox->textFromValue(value); } /** * @return Current value as double. */ double WuQDoubleSpinBox::value() const { return m_spinBox->value(); } /** * This virtual function is used by the spin box whenever it needs to * interpret text entered by the user as a value. * Subclasses that need to display spin box values in a non-numeric way * need to reimplement this function. * * @return double value from the given text value. */ double WuQDoubleSpinBox::valueFromText(const QString &text) const { return m_spinBox->valueFromText(text); } /** * Slot to set the value. Unlike QDoubleSpinBox::setValue() * this method DOES NOT cause the valueChanged() signal to * be emitted. * * @param val * New value for spin box. */ void WuQDoubleSpinBox::setValue(double val) { if (m_blockValueUpdateFlag) { return; } QSignalBlocker blocker(m_spinBox); m_spinBox->setValue(val); } /** * Called when the enapsulated spin box's value changed signal is emitted. * Use 'this' instance of signal blocking to prevent a signal from * being emitted. This allows user to use WuQDoubleSpinBox::blockSignals(). * * @param d * Value contained in the spin box. */ void WuQDoubleSpinBox::valueChangedPrivate(double d) { if (m_spinBox->signalsBlocked()) { return; } if (signalsBlocked()) { return; } /* * Emitting the signal may cause a call to the 'setValue()' method. * We need to prevent this. Otherwise, the spin box will get updated * with only the first character that was typed by user. * For example, without this, if the user tried to enter 9.3, * setValue gets called with only 9 and the user cannot enter the .3. */ m_blockValueUpdateFlag = true; emit valueChanged(d); m_blockValueUpdateFlag = false; } /** * Set the tooltip for this spin box. After this * tooltip, the range of data is displayed. * * @param tooltip * Text for the tooltip. */ void WuQDoubleSpinBox::setToolTip(const QString& tooltip) { m_userToolTip = tooltip; setDataRangeToolTip(); } /** * @return Text for a tooltip indicating range of data. */ void WuQDoubleSpinBox::setDataRangeToolTip() const { AString s; if ( ! m_userToolTip.isEmpty()) { s += (m_userToolTip + "\n"); } s += QString("Data min/max: %1 %2").arg(doubleToString(m_minimumValue)).arg(doubleToString(m_maximumValue)); switch (m_rangeMode) { case RangeMode::EXCEEDABLE: { const double minVal = m_spinBox->minimum(); const double maxVal = m_spinBox->maximum(); s += (+ "\n" + QString("Acceptable min/max: %1 %2").arg(doubleToString(minVal)).arg(doubleToString(maxVal))); } break; case RangeMode::INCLUSIVE: break; } m_spinBox->setToolTip(s); } /** * Convert the double to a string. If the value * exceeds maximum float list as 'infinity'. * * @param value * The double value. * @return * The string representation. */ QString WuQDoubleSpinBox::doubleToString(const double value) const { QString s; if (value >= std::numeric_limits::max()) { s = "+infinity"; } else if (value <= -std::numeric_limits::max()) { s = "-infinity"; } else { s = QString("%1").arg(value, 0, 'f'); s = NumericTextFormatting::cleanZerosInValueText(s); s += m_spinBox->suffix(); } return s; } // ADD_NEW_METHODS_HERE connectome-workbench-1.4.2/src/GuiQt/WuQDoubleSpinBox.h000066400000000000000000000142031360521144700227760ustar00rootroot00000000000000#ifndef __WU_Q_DOUBLE_SPIN_BOX_H__ #define __WU_Q_DOUBLE_SPIN_BOX_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "WuQWidget.h" class QDoubleSpinBox; namespace caret { class WuQDoubleSpinBox : public WuQWidget { Q_OBJECT public: /** * Mode for decimals (digits right of decimal) */ enum class DecimalsMode { /** * Number of decimals is calculated from the range of data */ AUTO, /** * Number of decimals is fixed by calling setDecimals(int) * (Normal spin box functionality) */ FIXED }; /** * Mode for single step (increment/decrement) arrows */ enum class SingleStepMode { /** * Step by a fixed amount (normal spin box functionality) */ FIXED, /** * Step by a percentage of data range */ PERCENTAGE }; /** * Mode for data range */ enum class RangeMode { /** * Normal spin box behavior, values limited inclusively to minimum and maximum */ INCLUSIVE, /** * May exceed minimum and maximum values. * Formatted for specified minimum and maximum. */ EXCEEDABLE }; WuQDoubleSpinBox(QObject* parent); virtual ~WuQDoubleSpinBox(); virtual QWidget* getWidget(); //void copySettings(const WuQDoubleSpinBox* copyFromSpinBox); QString cleanText() const; int decimals() const; double maximum() const; double minimum() const; QString prefix() const; DecimalsMode decimalsMode() const; void setDecimals(int prec); void setDecimalsModeAuto(); void setPrefix(const QString &prefix); void setRange(double minimum, double maximum); void setRangeExceedable(double minimum, double maximum, double exceedAmount); void setRangeExceedable(double minimum, double maximum); void setRangePercentage(const double minimumPercentage, const double maximumPercentage); void setSingleStep(double value); void setSingleStepPercentage(double percentage); void setSuffix(const QString &suffix); double singleStep() const; SingleStepMode singleStepMode() const; double singleStepPercentage() const; QString suffix() const; virtual QString textFromValue(double value) const; double value() const; virtual double valueFromText(const QString &text) const; virtual void setToolTip(const QString& tooltip); // ADD_NEW_METHODS_HERE public slots: void setValue(double val); signals: /** * This signal is emitted when the value changes. * * Example of signal connection: * QObject::connect(m_spinBox, static_cast(&QDoubleSpinBox::valueChanged), * this, &WuQDoubleSpinBox::valueChanged); * * @param d * New value. */ void valueChanged(double d); private slots: void valueChangedPrivate(double d); private: WuQDoubleSpinBox(const WuQDoubleSpinBox&); WuQDoubleSpinBox& operator=(const WuQDoubleSpinBox&); void updateSingleStepPercentage(); void updateDecimalsForAutoMode(); int32_t computeDigitsRightOfDecimal(const double dataRange); void testDigitsRightOfDecimal(); double computeExceedRange(const double minValue, const double maxValue); QString doubleToString(const double value) const; void testExceedRange(); void setRangeExceedable(const double dataMinimum, const double dataMaximum, const double spinBoxMinimum, const double spinBoxMaximum); double makePowerOfTen(const double value) const; void setDataRangeToolTip() const; QDoubleSpinBox* m_spinBox; RangeMode m_rangeMode = RangeMode::INCLUSIVE; DecimalsMode m_decimalsMode = DecimalsMode::FIXED; SingleStepMode m_singleStepMode = SingleStepMode::FIXED; double m_singleStepPercentage = 1.0; double m_minimumValue = 0.0; double m_maximumValue = 99.0; bool m_blockValueUpdateFlag = false; QString m_userToolTip; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_DOUBLE_SPIN_BOX_DECLARE__ // #endif // __WU_Q_DOUBLE_SPIN_BOX_DECLARE__ } // namespace #endif //__WU_Q_DOUBLE_SPIN_BOX_H__ connectome-workbench-1.4.2/src/GuiQt/WuQEventBlockingFilter.cxx000066400000000000000000000110661360521144700245400ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_EVENT_BLOCKING_FILTER_DECLARE__ #include "WuQEventBlockingFilter.h" #undef __WU_Q_EVENT_BLOCKING_FILTER_DECLARE__ #include #include using namespace caret; /** * \class caret::WuQEventBlockingFilter * \brief A QEvent Filter * * A QEvent Filter. There are cases in which one wants to * block a specific event from being processed by widgets. * For example, on Mac, dragging the mouse over a combo box * causes a wheel event that unintentionally changes the * value of the combo box. * * To use an instance of this blocking filter, (1) Create * an instance of this class, (2) call setEventBlocked() which * the event enumerated type that is to be blocked, (3) pass * the instance of this class to the widget's * installEventFilter() method. */ /** * Constructor. * @param object * Parent that will own this event filter. The parent * will handle destruction of this event filter. */ WuQEventBlockingFilter::WuQEventBlockingFilter(QObject* parent) : QObject(parent) { } /** * Add a wheel blocking filter to a combo box (on mac only). On a Mac, * if the mouse pointer is moved across a combo box (particularly when * the user is using a Track Pad), Qt will get this event and apply it * as a wheel event to the combo box changing the selection in the * combo box. * * @param comboBox * Combo box that has its wheel event blocked. */ #ifdef CARET_OS_MACOSX void WuQEventBlockingFilter::blockMouseWheelEventInMacComboBox(QComboBox* comboBox) { /* * Attach an event filter that blocks wheel events in the combo box if Mac */ WuQEventBlockingFilter* comboBoxWheelEventBlockingFilter = new WuQEventBlockingFilter(comboBox); comboBoxWheelEventBlockingFilter->setEventBlocked(QEvent::Wheel, true); comboBox->installEventFilter(comboBoxWheelEventBlockingFilter); } #else void WuQEventBlockingFilter::blockMouseWheelEventInMacComboBox(QComboBox*) { } #endif // CARET_OS_MACOSX /** * Destructor. */ WuQEventBlockingFilter::~WuQEventBlockingFilter() { } /** * Set the blocking status for the given event type. * @param eventType * Type of event to block. * @param blockedStatus * New status for blocking. */ void WuQEventBlockingFilter::setEventBlocked(const QEvent::Type eventType, const bool blockedStatus) { const int eventAsInt = static_cast(eventType); this->blockedEventsHashTable.insert(eventAsInt, blockedStatus); } /** * Is the given event blocked? * @param eventType * Type of event. * @return * True if event is being blocked, else false. */ bool WuQEventBlockingFilter::isEventBlocked(const QEvent::Type eventType) const { const int eventAsInt = static_cast(eventType); return this->blockedEventsHashTable.value(eventAsInt, false); } /** * Filters events for the given object. * @param object * Object for which events are being filtered. * @param event * Event that is examined for blocking. * @ @return * True, meaning that this event will not receive * any furthere processing. Or false, meaning * that the processing has been passed to the * parent class of the object. */ bool WuQEventBlockingFilter::eventFilter(QObject* object, QEvent* event) { const int eventAsInt = static_cast(event->type()); if (this->blockedEventsHashTable.value(eventAsInt, false)) { return true; } /* * Let parent do the filtering */ return QObject::eventFilter(object, event); } connectome-workbench-1.4.2/src/GuiQt/WuQEventBlockingFilter.h000066400000000000000000000042511360521144700241630ustar00rootroot00000000000000#ifndef __WU_Q_EVENT_BLOCKING_FILTER__H_ #define __WU_Q_EVENT_BLOCKING_FILTER__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include class QComboBox; namespace caret { class WuQEventBlockingFilter : public QObject { Q_OBJECT public: static void blockMouseWheelEventInMacComboBox(QComboBox* comboBox); WuQEventBlockingFilter(QObject* parent); virtual ~WuQEventBlockingFilter(); void setEventBlocked(const QEvent::Type eventType, const bool blockedStatus); bool isEventBlocked(const QEvent::Type eventType) const; protected: bool eventFilter(QObject* object, QEvent* event); private: WuQEventBlockingFilter(const WuQEventBlockingFilter&); WuQEventBlockingFilter& operator=(const WuQEventBlockingFilter&); /** * Hash Table is probably fastest way to track multiple events * that can be blocked. Key is int (QEvent::Type) and value * is blocked status. */ QHash blockedEventsHashTable; }; #ifdef __WU_Q_EVENT_BLOCKING_FILTER_DECLARE__ // #endif // __WU_Q_EVENT_BLOCKING_FILTER_DECLARE__ } // namespace #endif //__WU_Q_EVENT_BLOCKING_FILTER__H_ connectome-workbench-1.4.2/src/GuiQt/WuQFactory.cxx000066400000000000000000000424701360521144700222520ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __WU_Q_FACTORY_DECLARE__ #include "WuQFactory.h" #undef __WU_Q_FACTORY_DECLARE__ #include "CaretLogger.h" using namespace caret; /** * \class caret::WuQFactory * \brief A factory for creating Qt Widgets with desired attributes. * \ingroup GuiQt * * This factory creates Qt Widgets with some attributes set to desired * values. For QSpinBox, by default, issues value changed events as * each character is entered into the spin box. So, if the user enters * five numbers, five events are issued, which at times, can cause * undesired updates to the user-interface. In addition, the methods in * this factory can simplify the creation of new widgets. *

    * Qt3 contained overloaded constructors that contained parameters for * widget attributes but these were removed in Qt4 most likely because * there was no way to clearly indicate the purpose of the parameters other * than the documentation. Thus, in Qt4 a widget must be created and then * methods called to set the widget's attributes. Using the a naming * convention in these factory methods removes the ambiguity about any * parameters. *

    * Rules for the method naming:
    *

    1. use the pattern "new[OptionalParameterNames][WithSignal[Type]]
      *
        *
      • A method name always begins with new *
      • WidgetType is the name of the Qt widget without the Q *
      • OptionalParameterNames describe any additional parameters *
      • WithSignal is at the end of the method name for those methods * that connect a value changed signal to a receiving class and slot. If a parameter * is passed, the type should also be indicated (WithSignalInt, WithSignalString, etc.). * Keep in mind that the receiving slot does not need to contain any parameters even * if the signal does contain parameters. In most cases, the signal is only issued * if the user changes the value. However, some widgets issue a signal when either the * user changes the value or the value is changed programmatically and this should be * noted in the documentation. *
      *
    2. Do not use default parameters. *
    3. Do not overload method names (identically named methods containing different parameters). *
    4. This naming convention may result in long names. However, the names will make the usage fairly obvious. *
    5. These naming patterns is based off that for Objective-C. *
    */ #include #include #include #include #include #include #include "WuQEventBlockingFilter.h" /** * Constructor. */ WuQFactory::WuQFactory() { } /** * Destructor. */ WuQFactory::~WuQFactory() { } /** * Create a combo box. * * On Apple computers, the mouse wheel can cause unintended changes * to a combo box even if the combo box does not have focus. So, * block the wheel event on Apple computers. In addition, on Apple * computers, every item that is in the combo box is displayed in * the pop-up menu (as large as the vertical size of the screen) * so use a Windows Style combo box to improve the usability. * * @return * A combo box. */ QComboBox* WuQFactory::newComboBox() { QComboBox* cb = new QComboBox(); #ifdef CARET_OS_MACOSX /* * Attach an event filter that blocks wheel events in the combo box if Mac */ WuQEventBlockingFilter* comboBoxWheelEventBlockingFilter = new WuQEventBlockingFilter(cb); comboBoxWheelEventBlockingFilter->setEventBlocked(QEvent::Wheel, true); cb->installEventFilter(comboBoxWheelEventBlockingFilter); //setWindowsStyleForApple(cb); #endif // CARET_OS_MACOSX return cb; } /** * Create a combo box. * * On Apple computers, the mouse wheel can cause unintended changes * to a combo box even if the combo box does not have focus. So, * block the wheel event on Apple computers. In addition, on Apple * computers, every item that is in the combo box is displayed in * the pop-up menu (as large as the vertical size of the screen) * so use a Windows Style combo box to improve the usability. * * @param receiver * Object that received the signal when the value is changed by the user. * @param method * Method that is connected to the spin box's valueChanged(int) * signal. * @return * A combo box. */ QComboBox* WuQFactory::newComboBoxSignalInt(QObject* receiver, const char* method) { QComboBox* cb = newComboBox(); QObject::connect(cb, SIGNAL(activated(int)), receiver, method); return cb; } /** * Create a spin box. * * The minimum value is the most negative 32-bit integer, the maximum * values is the most positive 32-bit integer, step size is one, and * the default value is zero. * Keyboard tracking is disabled so that signal are NOT issued when * the user changes the text contained in the spin box. * * @return * A QSpinBox initialized with the default parameters. */ QSpinBox* WuQFactory::newSpinBox() { QSpinBox* sb = newSpinBoxWithMinMaxStep(std::numeric_limits::min(), std::numeric_limits::max(), 1); return sb; } /** * Create a spin box. * * The minimum value is the most negative 32-bit integer, the maximum * values is the most positive 32-bit integer, step size is one, and * the default value is zero. * Keyboard tracking is disabled so that signal are NOT issued when * the user changes the text contained in the spin box. *

    * NOTE: The signal contains an integer parameters that is the new value * contained in the spin box. The signal is emitted when the user * changes the value AND when the value is changed programatically. * * @param receiver * Object that received the signal when the value is changed. * @param method * Method that is connected to the spin box's valueChanged(int) * signal. * @return * A QSpinBox initialized with the default parameters. */ QSpinBox* WuQFactory::newSpinBoxWithSignalInt(QObject* receiver, const char* method) { QSpinBox* sb = newSpinBoxWithMinMaxStepSignalInt(std::numeric_limits::min(), std::numeric_limits::max(), 1, receiver, method); return sb; } /** * Create a spin box with the given minimum, maximum, and step values. * Keyboard tracking is disabled so that signal are NOT issued when * the user changes the text contained in the spin box. *

    * The default value is zero. If zero is not within the given * minimum and maximum values, the default value is the minimum value. * * @param minimumValue * Minimum value for spin box. * @param maximumValue * Maximum value for spin box. * @param stepSize * Step (change in value) when the user increments the spin box. * @return * A QSpinBox initialized with the given parameters. */ QSpinBox* WuQFactory::newSpinBoxWithMinMaxStep(const int minimumValue, const int maximumValue, const int stepSize) { QSpinBox* sb = new QSpinBox(); sb->setMinimum(minimumValue); sb->setMaximum(maximumValue); sb->setSingleStep(stepSize); sb->setKeyboardTracking(false); if ((0 >= minimumValue) && (0 <= maximumValue)) { sb->setValue(0); } else { sb->setValue(minimumValue); } return sb; } /** * Create a spin box with the given minimum, maximum, and step values. * Keyboard tracking is disabled so that signal are NOT issued when * the user changes the text contained in the spin box. *

    * The default value is zero. If zero is not within the given * minimum and maximum values, the default value is the minimum value. *

    * NOTE: The signal contains an integer parameters that is the new value * contained in the spin box. The signal is emitted when the user * changes the value AND when the value is changed programatically. * * @param minimumValue * Minimum value for spin box. * @param maximumValue * Maximum value for spin box. * @param stepSize * Step (change in value) when the user increments the spin box. * @param receiver * Object that received the signal when the value is changed. * @param method * Method that is connected to the spin box's valueChanged(int) * signal. * @return * A QSpinBox initialized with the given parameters. */ QSpinBox* WuQFactory::newSpinBoxWithMinMaxStepSignalInt(const int minimumValue, const int maximumValue, const int stepSize, QObject* receiver, const char* method) { QSpinBox* sb = newSpinBoxWithMinMaxStep(minimumValue, maximumValue, stepSize); QObject::connect(sb, SIGNAL(valueChanged(int)), receiver, method); return sb; } /** * Create a double spin box with the minimum value set to the most negative * float (not double) value, the maximum value set to the most positive * float (not double) value, the step size set to one and the number of * digits right of the decimal set to two. The default value is zero. * Keyboard tracking is disabled so that signal are NOT issued when * the user changes the text contained in the spin box. *

    * Since workbench stores most data as 32-bit floats, the default minimum and * maximum values are those for float, not double. * * @return * A QDoubleSpinBox initialized with the default parameters. */ QDoubleSpinBox* WuQFactory::newDoubleSpinBox() { QDoubleSpinBox* sb = newDoubleSpinBoxWithMinMaxStepDecimals(-std::numeric_limits::max(), std::numeric_limits::max(), 1.0, 2); return sb; } /** * Create a double spin box with the minimum value set to the most negative * float (not double) value, the maximum value set to the most positive * float (not double) value, the step size set to one and the number of * digits right of the decimal set to two. The default value is zero. * Keyboard tracking is disabled so that signal are NOT issued when * the user changes the text contained in the spin box. *

    * Since workbench stores most data as 32-bit floats, the default minimum and * maximum values are those for float, not double. * *

    * NOTE: The signal contains an double parameter that is the new value * contained in the spin box. The signal is emitted when the user * changes the value AND when the value is changed programatically. * * @param receiver * Object that received the signal when the value is changed. * @param method * Method that is connected to the spin box's valueChanged(double) * signal. * @return * A QDoubleSpinBox initialized with the default parameters. */ QDoubleSpinBox* WuQFactory::newDoubleSpinBoxWithSignalDouble(QObject* receiver, const char* method) { QDoubleSpinBox* sb = newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(-std::numeric_limits::max(), std::numeric_limits::max(), 1.0, 2, receiver, method); return sb; } /** * Create a double spin box with the given minimum, maximum, step, and * digits right of decimal values. * Keyboard tracking is disabled so that signal are NOT issued when * the user changes the text contained in the spin box. *

    * The default value is zero. If zero is not within the given * minimum and maximum values, the default value is the minimum value. * * @param minimumValue * Minimum value for spin box. * @param maximumValue * Maximum value for spin box. * @param stepSize * Step (change in value) when the user increments the spin box. * @param digitsRightOfDecimal * Number of digits to right of decimal shown in the spin box. * @return * A QDoubleSpinBox initialized with the given parameters. */ QDoubleSpinBox* WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimals(const double minimumValue, const double maximumValue, const double stepSize, const int digitsRightOfDecimal) { QDoubleSpinBox* sb = new QDoubleSpinBox(); sb->setMinimum(minimumValue); sb->setMaximum(maximumValue); sb->setSingleStep(stepSize); sb->setDecimals(digitsRightOfDecimal); sb->setKeyboardTracking(false); if ((0 >= minimumValue) && (0 <= maximumValue)) { sb->setValue(0); } else { sb->setValue(minimumValue); } return sb; } /** * Create a double spin box with the given minimum, maximum, step, and * digits right of decimal values. * Keyboard tracking is disabled so that signal are NOT issued when * the user changes the text contained in the spin box. *

    * The default value is zero. If zero is not within the given * minimum and maximum values, the default value is the minimum value. *

    * NOTE: The signal contains an double parameter that is the new value * contained in the spin box. The signal is emitted when the user * changes the value AND when the value is changed programatically. * * @param minimumValue * Minimum value for spin box. * @param maximumValue * Maximum value for spin box. * @param stepSize * Step (change in value) when the user increments the spin box. * @param digitsRightOfDecimal * Number of digits to right of decimal shown in the spin box. * @param receiver * Object that received the signal when the value is changed. * @param method * Method that is connected to the spin box's valueChanged(double) * signal. * @return * A QDoubleSpinBox initialized with the given parameters. */ QDoubleSpinBox* WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(const double minimumValue, const double maximumValue, const double stepSize, const int digitsRightOfDecimal, QObject* receiver, const char* method) { QDoubleSpinBox* sb = newDoubleSpinBoxWithMinMaxStepDecimals(minimumValue, maximumValue, stepSize, digitsRightOfDecimal); QObject::connect(sb, SIGNAL(valueChanged(double)), receiver, method); return sb; } /** * Sets the style of the given windows to windows. */ void WuQFactory::setWindowsStyleForApple(QWidget* w) { // w->setStyle(new WorkbenchMacStyle()); // return; /* * Only try creating once */ if (s_windowsStyleForAppleWasCreated == false) { s_windowsStyleForAppleWasCreated = true; s_windowsStyleForApple = QStyleFactory::create("Windows"); if (s_windowsStyleForApple == NULL) { CaretLogSevere("Failed to create Windows Style"); } } if (s_windowsStyleForApple != NULL) { w->setStyle(s_windowsStyleForApple); } } //int //WorkbenchMacStyle::styleHint ( StyleHint sh, const QStyleOption * opt, const QWidget * w, QStyleHintReturn * hret) const //{ // int value = QMacStyle::styleHint(sh, opt, w, hret); // // if (sh == QStyle::SH_ComboBox_Popup) { // value = 0; // } // // return value; //} connectome-workbench-1.4.2/src/GuiQt/WuQFactory.h000066400000000000000000000104011360521144700216640ustar00rootroot00000000000000#ifndef __WU_Q_FACTORY_H__ #define __WU_Q_FACTORY_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ class QComboBox; class QDoubleSpinBox; class QObject; class QSpinBox; class QStyle; class QWidget; namespace caret { class WuQFactory { public: static QComboBox* newComboBox(); static QComboBox* newComboBoxSignalInt(QObject* receiver, const char* method); static QSpinBox* newSpinBox(); static QSpinBox* newSpinBoxWithSignalInt(QObject* receiver, const char* method); static QSpinBox* newSpinBoxWithMinMaxStep(const int minimumValue, const int maximumValue, const int stepSize); static QSpinBox* newSpinBoxWithMinMaxStepSignalInt(const int minimumValue, const int maximumValue, const int stepSize, QObject* receiver, const char* method); static QDoubleSpinBox* newDoubleSpinBox(); static QDoubleSpinBox* newDoubleSpinBoxWithSignalDouble(QObject* receiver, const char* method); static QDoubleSpinBox* newDoubleSpinBoxWithMinMaxStepDecimals(const double minimumValue, const double maximumValue, const double stepSize, const int digitsRightOfDecimal); static QDoubleSpinBox* newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(const double minimumValue, const double maximumValue, const double stepSize, const int digitsRightOfDecimal, QObject* receiver, const char* method); private: WuQFactory(); virtual ~WuQFactory(); WuQFactory(const WuQFactory&); WuQFactory& operator=(const WuQFactory&); static void setWindowsStyleForApple(QWidget* w); static QStyle* s_windowsStyleForApple; static bool s_windowsStyleForAppleWasCreated; public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE }; // class WorkbenchMacStyle : public QMacStyle { // public: // WorkbenchMacStyle() {} // // virtual ~WorkbenchMacStyle() {} // virtual int styleHint ( StyleHint sh, const QStyleOption * opt = 0, const QWidget * w = 0, QStyleHintReturn * hret = 0 ) const; // }; #ifdef __WU_Q_FACTORY_DECLARE__ QStyle* WuQFactory::s_windowsStyleForApple = NULL; bool WuQFactory::s_windowsStyleForAppleWasCreated; #endif // __WU_Q_FACTORY_DECLARE__ } // namespace #endif //__WU_Q_FACTORY_H__ connectome-workbench-1.4.2/src/GuiQt/WuQGridLayoutGroup.cxx000066400000000000000000000141341360521144700237370ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __WU_Q_GRID_LAYOUT_GROUP_DECLARE__ #include "WuQGridLayoutGroup.h" #undef __WU_Q_GRID_LAYOUT_GROUP_DECLARE__ using namespace caret; /** * \class caret::WuQGridLayoutGroup * \brief Controls display of a group of widgets in a QGridLayout * * When displaying QWidgets in a QGridLayout one may want to * hide the widgets in a row. However, even though the widgets * are hidden and QGridLayout removes the space occupied by * the widgets, it seems to keep the spacing around the widgets * and the layout does not full shrink. * * This group will remove and add the widgets as the group * is set visible or hidden. This seems to remove the extra * spacing and allows the QGridLayout to fully shrink. */ /** * Constructor. * @param gridLayout * Grid layout of the widgets. * @param parent * Parent object. */ WuQGridLayoutGroup::WuQGridLayoutGroup(QGridLayout* gridLayout, QObject* parent) : QObject(parent) { this->gridLayout = gridLayout; this->areWidgetsInLayout = true; } /** * Destructor. */ WuQGridLayoutGroup::~WuQGridLayoutGroup() { const int numItems = this->layoutItems.size(); for (int i = 0; i < numItems; i++) { delete this->layoutItems[i]; } this->layoutItems.clear(); } /** * Add a widget to the group. * @param widget * Widget added to the layout * @param row * Row for widget. * @param column * Column for widget. * @param alignment * Alignment of widget. */ void WuQGridLayoutGroup::addWidget(QWidget* widget, int row, int column, Qt::Alignment alignment) { this->addWidget(widget, row, column, 1, 1, alignment); } /** * Add a widget to the group. * @param widget * Widget added to the layout * @param fromRow * Row for widget. * @param fromColumn * Column for widget. * @param rowSpan * Rows for widget. * @param columnSpan * Columns for widget. * @param alignment * Alignment of widget. */ void WuQGridLayoutGroup::addWidget(QWidget* widget, int fromRow, int fromColumn, int rowSpan, int columnSpan, Qt::Alignment alignment) { ItemRowCol* irc = new ItemRowCol(widget, fromRow, fromColumn, rowSpan, columnSpan, alignment); this->layoutItems.push_back(irc); this->gridLayout->addWidget(irc->widget, irc->fromRow, irc->fromColumn, irc->rowSpan, irc->columnSpan, irc->alignment); } /** * Set the visibility of the widgets in the group. */ void WuQGridLayoutGroup::setVisible(bool visible) { if (visible) { if (this->areWidgetsInLayout) { return; } const int numItems = this->layoutItems.size(); for (int i = 0; i < numItems; i++) { ItemRowCol* irc = this->layoutItems[i]; this->gridLayout->addWidget(irc->widget, irc->fromRow, irc->fromColumn, irc->rowSpan, irc->columnSpan, irc->alignment); irc->widget->setVisible(true); } this->areWidgetsInLayout = true; } else { if (this->areWidgetsInLayout) { const int numItems = this->layoutItems.size(); for (int i = 0; i < numItems; i++) { ItemRowCol* irc = this->layoutItems[i]; irc->widget->setVisible(false); this->gridLayout->removeWidget(irc->widget); } this->areWidgetsInLayout = false; } } } /** * Constructor for widget. * * @param widget * Widget added to the layout * @param fromRow * Row for widget. * @param fromColumn * Column for widget. * @param rowSpan * Rows for widget. * @param columnSpan * Columns for widget. * @param alignment * Alignment of widget. */ WuQGridLayoutGroup::ItemRowCol::ItemRowCol(QWidget *widget, int fromRow, int fromColumn, int rowSpan, int columnSpan, Qt::Alignment alignment) { this->widget = widget; this->fromRow = fromRow; this->fromColumn = fromColumn; this->rowSpan = rowSpan; this->columnSpan = columnSpan; this->alignment = alignment; } /** * @return Number of rows in grid layout. */ int WuQGridLayoutGroup::rowCount() const { return this->gridLayout->rowCount(); } /** * @return Number of columns in grid layout. */ int WuQGridLayoutGroup::columnCount() const { return this->gridLayout->columnCount(); } connectome-workbench-1.4.2/src/GuiQt/WuQGridLayoutGroup.h000066400000000000000000000052741360521144700233710ustar00rootroot00000000000000#ifndef __WU_Q_GRID_LAYOUT_GROUP__H_ #define __WU_Q_GRID_LAYOUT_GROUP__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include class QGridLayout; namespace caret { class WuQGridLayoutGroup : public QObject { Q_OBJECT public: WuQGridLayoutGroup(QGridLayout* gridLayout, QObject* parent = 0); virtual ~WuQGridLayoutGroup(); void addWidget(QWidget* widget, int row, int column, Qt::Alignment alignment = 0); void addWidget(QWidget* widget, int fromRow, int fromColumn, int rowSpan, int columnSpan, Qt::Alignment alignment = 0); int rowCount() const; int columnCount() const; void setVisible(bool visible); private: WuQGridLayoutGroup(const WuQGridLayoutGroup&); WuQGridLayoutGroup& operator=(const WuQGridLayoutGroup&); class ItemRowCol { public: ItemRowCol(QWidget *widget, int fromRow, int fromColumn, int rowSpan, int columnSpan, Qt::Alignment alignment); QWidget* widget; int fromRow; int fromColumn; int rowSpan; int columnSpan; Qt::Alignment alignment; }; QGridLayout* gridLayout; bool areWidgetsInLayout; QVector layoutItems; }; #ifdef __WU_Q_GRID_LAYOUT_GROUP_DECLARE__ // #endif // __WU_Q_GRID_LAYOUT_GROUP_DECLARE__ } // namespace #endif //__WU_Q_GRID_LAYOUT_GROUP__H_ connectome-workbench-1.4.2/src/GuiQt/WuQGroupBoxExclusiveWidget.cxx000066400000000000000000000234551360521144700254460ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_GROUP_BOX_EXCLUSIVE_WIDGET_DECLARE__ #include "WuQGroupBoxExclusiveWidget.h" #undef __WU_Q_GROUP_BOX_EXCLUSIVE_WIDGET_DECLARE__ #include #include #include #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::WuQGroupBoxExclusiveWidget * \brief A vertical layout with only one active item. * \ingroup GuiQt * * The items are layout out vertically inside an outline box * with each item containing a name an radio button for * mutual selection. Sort of a list of group boxes where * only one item is enabled at a time. */ /** * Constructor. * * @param parent * The parent widget. */ WuQGroupBoxExclusiveWidget::WuQGroupBoxExclusiveWidget(QWidget* parent) : QWidget(parent) { m_currentWidgetIndex = -1; m_widgetsGridLayout = new QGridLayout(this); m_widgetsGridLayout->setVerticalSpacing(10); m_widgetsGridLayout->setColumnMinimumWidth(0, 10); m_widgetsGridLayout->setColumnStretch(0, 0); m_widgetsGridLayout->setColumnStretch(1, 100); m_radioButtonGroup = new QButtonGroup(this); m_radioButtonGroup->setExclusive(true); QObject::connect(m_radioButtonGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(radioButtonClicked(QAbstractButton*))); } /** * Destructor. */ WuQGroupBoxExclusiveWidget::~WuQGroupBoxExclusiveWidget() { } /** * Called when a group's radio button is clicked. Will emit the * currentChanged() signal. * * @param button * Button that was clicked. */ void WuQGroupBoxExclusiveWidget::radioButtonClicked(QAbstractButton* button) { int32_t itemIndex = -1; QRadioButton* selectedRadioButton = qobject_cast(button); const int32_t num = count(); for (int32_t i = 0; i < num; i++) { CaretAssertVectorIndex(m_widgetDatas, i); if (m_widgetDatas[i].m_radioButton == selectedRadioButton) { itemIndex = i; m_widgetDatas[i].m_widget->setEnabled(true); } else { m_widgetDatas[i].m_widget->setEnabled(false); } } if (itemIndex >= 0) { m_currentWidgetIndex = itemIndex; updateSelectionWithValidWidget(); emit currentChanged(itemIndex); } else { m_currentWidgetIndex = -1; } } /** * Appends the given widget and returns its index. * * @param widget * Widget that is added. * @param textLabel * Text label displayed next to radio button. * @return * Index of the widget. */ int32_t WuQGroupBoxExclusiveWidget::addWidget(QWidget* widget, const QString& textLabel) { QRadioButton* radioButton = new QRadioButton(textLabel); m_radioButtonGroup->addButton(radioButton); QFrame* frameBox = new QFrame(); frameBox->setFrameStyle(QFrame::StyledPanel | QFrame::Plain); frameBox->setLineWidth(1); frameBox->setMidLineWidth(1); QHBoxLayout* frameBoxLayout = new QHBoxLayout(frameBox); frameBoxLayout->setContentsMargins(2, 2, 2, 2); frameBoxLayout->addWidget(widget, 100, Qt::AlignLeft); int row = m_widgetsGridLayout->rowCount(); m_widgetsGridLayout->addWidget(radioButton, row, 0, 1, 2, Qt::AlignLeft); row++; m_widgetsGridLayout->addWidget(frameBox, row, 1); WidgetData widgetData; widgetData.m_frameBox = frameBox; widgetData.m_radioButton = radioButton; widgetData.m_widget = widget; m_widgetDatas.push_back(widgetData); updateSelectionWithValidWidget(); return (m_widgetDatas.size() - 1); } /** * @return Number of widgets in container. */ int32_t WuQGroupBoxExclusiveWidget::count() const { return m_widgetDatas.size(); } /** * @return Index of widget that is selected. -1 if no widgets have been added. */ int32_t WuQGroupBoxExclusiveWidget::currentIndex() const { if (m_widgetDatas.empty()) { return -1; } CaretAssertVectorIndex(m_widgetDatas, m_currentWidgetIndex); return m_currentWidgetIndex; } void WuQGroupBoxExclusiveWidget::updateSelectionWithValidWidget() { if (m_widgetDatas.empty()) { m_currentWidgetIndex = -1; return; } if (m_currentWidgetIndex < 0) { m_currentWidgetIndex = 0; } else if (m_currentWidgetIndex >= count()) { m_currentWidgetIndex = count() - 1; } CaretAssertVectorIndex(m_widgetDatas, m_currentWidgetIndex); if ( ! isWidgetEnabled(m_currentWidgetIndex)) { m_currentWidgetIndex = -1; const int32_t num = count(); for (int32_t i = 0; i < num; i++) { if (isWidgetEnabled(i)) { m_currentWidgetIndex = i; break; } } } if (m_currentWidgetIndex >= 0) { CaretAssertVectorIndex(m_widgetDatas, m_currentWidgetIndex); m_radioButtonGroup->blockSignals(true); m_widgetDatas[m_currentWidgetIndex].m_radioButton->setChecked(true); m_radioButtonGroup->blockSignals(false); } const int32_t num = count(); for (int32_t i = 0; i < num; i++) { m_widgetDatas[i].m_widget->setEnabled(m_widgetDatas[i].m_radioButton->isChecked()); } } /** * @return The current widget or NULL is no widgets have been added. */ QWidget* WuQGroupBoxExclusiveWidget::currentWidget() const { const int32_t index = currentIndex(); if (index >= 0) { CaretAssertVectorIndex(m_widgetDatas, index); return m_widgetDatas[index].m_widget; } return NULL; } /** * @param widget * Widget for its index. * @return * Index of the given widget or -1 if the widget was never added. */ int32_t WuQGroupBoxExclusiveWidget::indexOf(QWidget* widget) const { const int32_t numWidgets = count(); for (int32_t i = 0; i < numWidgets; i++) { CaretAssertVectorIndex(m_widgetDatas, i); if (m_widgetDatas[i].m_widget == widget) { return i; } } return -1; } /** * @param index * Index of widget that is returned. * * @return * The widget at the given index or NULL if index is invalid. */ QWidget* WuQGroupBoxExclusiveWidget::widget(int32_t index) const { if ((index < 0) || (index >= count())) { const QString msg("Request with invalid widget index=" + QString::number(index)); CaretLogWarning(msg); CaretAssertMessage(0, msg); return NULL; } CaretAssertVectorIndex(m_widgetDatas, index); return m_widgetDatas[index].m_widget; } /** * Sets the current widget to the widget at the given index. * * @param index * Index of the widget. */ void WuQGroupBoxExclusiveWidget::setCurrentIndex(int32_t index) { if ((index < 0) || (index >= count())) { const QString msg("Attemp to set invalid current widget index=" + QString::number(index)); CaretLogWarning(msg); CaretAssertMessage(0, msg); return; } m_currentWidgetIndex = index; updateSelectionWithValidWidget(); } /** * Sets the current widget to the widget at the given widget. * * @param widget * Widget that is selected. */ void WuQGroupBoxExclusiveWidget::setCurrentWidget(QWidget* widget) { if (m_widgetDatas.empty()) { return; } const int32_t index = indexOf(widget); if (index >= 0) { m_currentWidgetIndex = index; } else { const QString msg("Widget was not found"); CaretLogWarning(msg); CaretAssertMessage(0, msg); } updateSelectionWithValidWidget(); } /** * Set the widget at given index enabled. * * @param index * Index of the widget. * @param enabled * New enabled status. */ void WuQGroupBoxExclusiveWidget::setWidgetEnabled(const int32_t index, const bool enabled) { if ((index < 0) || (index >= count())) { const QString msg("Attemp to set invalid widget enabled index=" + QString::number(index)); CaretLogWarning(msg); CaretAssertMessage(0, msg); return; } CaretAssertVectorIndex(m_widgetDatas, index); m_widgetDatas[index].m_radioButton->setEnabled(enabled); updateSelectionWithValidWidget(); } /** * @return Is the widget at the given index enabled? * * @param index * Index of the widget. */ bool WuQGroupBoxExclusiveWidget::isWidgetEnabled(const int32_t index) const { if ((index < 0) || (index >= count())) { const QString msg("Attemp to query invalid widget enabled index=" + QString::number(index)); CaretLogWarning(msg); CaretAssertMessage(0, msg); return false; } CaretAssertVectorIndex(m_widgetDatas, index); return m_widgetDatas[index].m_radioButton->isEnabled(); } connectome-workbench-1.4.2/src/GuiQt/WuQGroupBoxExclusiveWidget.h000066400000000000000000000061711360521144700250670ustar00rootroot00000000000000#ifndef __WU_Q_GROUP_BOX_EXCLUSIVE_WIDGET_H__ #define __WU_Q_GROUP_BOX_EXCLUSIVE_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include class QAbstractButton; class QButtonGroup; class QFrame; class QGridLayout; class QRadioButton; namespace caret { class WuQGroupBoxExclusiveWidget : public QWidget { Q_OBJECT public: WuQGroupBoxExclusiveWidget(QWidget* parent = 0); virtual ~WuQGroupBoxExclusiveWidget(); int32_t addWidget(QWidget* widget, const QString& textLabel); int32_t count() const; int32_t currentIndex() const; QWidget* currentWidget() const; int32_t indexOf(QWidget* widget) const; QWidget* widget(int32_t index) const; void setWidgetEnabled(int32_t index, const bool enabled); bool isWidgetEnabled(const int32_t index) const; // ADD_NEW_METHODS_HERE signals: /** * Emitted when the user changes the selected widget. * * @param * Index of the selected widget. */ void currentChanged(int32_t index); public slots: void setCurrentIndex(int32_t index); void setCurrentWidget(QWidget* widget); private slots: void radioButtonClicked(QAbstractButton* button); private: WuQGroupBoxExclusiveWidget(const WuQGroupBoxExclusiveWidget&); WuQGroupBoxExclusiveWidget& operator=(const WuQGroupBoxExclusiveWidget&); void updateSelectionWithValidWidget(); // ADD_NEW_MEMBERS_HERE struct WidgetData { QWidget* m_widget; QFrame* m_frameBox; QRadioButton* m_radioButton; }; std::vector m_widgetDatas; QButtonGroup* m_radioButtonGroup; QGridLayout* m_widgetsGridLayout; mutable int32_t m_currentWidgetIndex; }; #ifdef __WU_Q_GROUP_BOX_EXCLUSIVE_WIDGET_DECLARE__ // #endif // __WU_Q_GROUP_BOX_EXCLUSIVE_WIDGET_DECLARE__ } // namespace #endif //__WU_Q_GROUP_BOX_EXCLUSIVE_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/WuQImageLabel.cxx000066400000000000000000000125771360521144700226320ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __WU_Q_IMAGE_LABEL_DECLARE__ #include "WuQImageLabel.h" #undef __WU_Q_IMAGE_LABEL_DECLARE__ using namespace caret; /** * \class caret::WuQImageLabel * \brief Displays an icon in a pixmap and issues clicked signal. * \ingroup GuiQt * * Displays an icon in a QLabel. If the icon is clicked by the user * the clicked signal is emitted. This ImageLabel is intended use is * within a QTableWidget cell as a QButton'ish class would have a * background. * */ #include #include #include #include /** * Default constructor creates a label with no image nor text. */ WuQImageLabel::WuQImageLabel() : QLabel() { setAlignment(Qt::AlignCenter); } /** * Constructor constructs an image label with either the given image if the * image is valid (not NULL). If the image is invalid (NULL), the text * will be displayed. * * @param image * Image that is displayed. * @param text * Text that is displayed if image is not valid (NULL). */ WuQImageLabel::WuQImageLabel(const QImage* image, const QString& text) : QLabel() { updateImageText(image, text); setAlignment(Qt::AlignCenter); } /** * Constructor constructs an image label with either the given icon if the * icon is valid (not NULL). If the icon is invalid (NULL), the text * will be displayed. * * @param icon * Icon that is displayed. * @param text * Text that is displayed if icon is not valid (NULL). */ WuQImageLabel::WuQImageLabel(const QIcon* icon, const QString& text) : QLabel() { updateIconText(icon, text); setAlignment(Qt::AlignCenter); } /** * Constructor constructs an image label with either the given icon if the * icon is valid (not NULL). If the icon is invalid (NULL), the text * will be displayed. * * @param icon * Icon that is displayed. * @param text * Text that is displayed if icon is not valid (NULL). */ WuQImageLabel::WuQImageLabel(const QIcon& icon, const QString& text) : QLabel() { updateIconText(&icon, text); setAlignment(Qt::AlignCenter); } /** * Destructor. */ WuQImageLabel::~WuQImageLabel() { } /* * Update image label with either the given icon if the * icon is valid (not NULL). If the icon is invalid (NULL), the text * will be displayed. * * @param icon * Icon that is displayed. * @param text * Text that is displayed if icon is not valid (NULL). */ void WuQImageLabel::updateIconText(const QIcon* icon, const QString& text) { if (icon != NULL) { setPixmap(icon->pixmap(16)); } else { setText(text); } } /* * Update image label with either the given image if the * image is valid (not NULL). If the image is invalid (NULL), the text * will be displayed. * * @param image * Image that is displayed. * @param text * Text that is displayed if icon is not valid (NULL). */ void WuQImageLabel::updateImageText(const QImage* image, const QString& text) { if (image != NULL) { setPixmap(QPixmap::fromImage(*image)); } else { setPixmap(QPixmap()); } setText(text); } /** * Called when the mouse is moved. * * @param ev * The mouse event. */ void WuQImageLabel::mouseMoveEvent(QMouseEvent* ev) { if (ev->button() == Qt::NoButton) { if (ev->buttons() == Qt::LeftButton) { const int x = ev->x(); const int y = ev->y(); if (x < m_mouseMinX) m_mouseMinX = x; if (x > m_mouseMaxX) m_mouseMaxX = x; if (y < m_mouseMinY) m_mouseMinY = y; if (y > m_mouseMaxY) m_mouseMaxY = y; } } } /** * Called when the mouse button is pressed. * * @param ev * The mouse event. */ void WuQImageLabel::mousePressEvent(QMouseEvent* ev) { if (ev->button() == Qt::LeftButton) { m_mouseMinX = ev->x(); m_mouseMaxX = ev->x(); m_mouseMinY = ev->y(); m_mouseMaxY = ev->y(); } } /** * Called when the mouse button is released. * * @param ev * The mouse event. */ void WuQImageLabel::mouseReleaseEvent(QMouseEvent* ev) { if (ev->button() == Qt::LeftButton) { const int dx = std::abs(m_mouseMaxX - m_mouseMinX); const int dy = std::abs(m_mouseMaxY - m_mouseMinY); const int tolerance = 5; if ((dx < tolerance) && (dy < tolerance)) { emit clicked(); } } } connectome-workbench-1.4.2/src/GuiQt/WuQImageLabel.h000066400000000000000000000046601360521144700222510ustar00rootroot00000000000000#ifndef __WU_Q_IMAGE_LABEL_H__ #define __WU_Q_IMAGE_LABEL_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include class QIcon; class QImage; namespace caret { class WuQImageLabel : public QLabel { Q_OBJECT public: WuQImageLabel(); WuQImageLabel(const QImage* image, const QString& text); WuQImageLabel(const QIcon* icon, const QString& text); WuQImageLabel(const QIcon& icon, const QString& text); virtual ~WuQImageLabel(); void updateImageText(const QImage* icon, const QString& text); void updateIconText(const QIcon* icon, const QString& text); virtual void mouseMoveEvent(QMouseEvent* ev); virtual void mousePressEvent(QMouseEvent* ev); virtual void mouseReleaseEvent(QMouseEvent* ev); // ADD_NEW_METHODS_HERE signals: /** * Emitted if the mouse button is clicked over * this widget. */ void clicked(); private: WuQImageLabel(const WuQImageLabel&); WuQImageLabel& operator=(const WuQImageLabel&); int m_mouseMinX; int m_mouseMaxX; int m_mouseMinY; int m_mouseMaxY; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_IMAGE_LABEL_DECLARE__ // #endif // __WU_Q_IMAGE_LABEL_DECLARE__ } // namespace #endif //__WU_Q_IMAGE_LABEL_H__ connectome-workbench-1.4.2/src/GuiQt/WuQListWidget.cxx000066400000000000000000000040771360521144700227230ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_LIST_WIDGET_DECLARE__ #include "WuQListWidget.h" #undef __WU_Q_LIST_WIDGET_DECLARE__ using namespace caret; /** * \class caret::WuQListWidget * \brief List widget that allows drag and drop to itself. * * QListWidget supports drag and drop but also requires * that one subclass QListWidget to receive the drop event. * This derivation of QListWidget receives the drop event * and emits a signal to indicate an item has been dropped. * * This class can be used instead of QListWidget so that * one can be notified, via a signal, that an item has been * dropped without having to subclass QListWidget. */ /** * Constructor. * @param parent * The optional parent widget. */ WuQListWidget::WuQListWidget(QWidget* parent) : QListWidget(parent) { /* * Enable dragging and dropping within this list widget. */ setSelectionMode(QListWidget::SingleSelection); setDragEnabled(true); setDragDropMode(QListWidget::InternalMove); } /** * Destructor. */ WuQListWidget::~WuQListWidget() { } /** * Receives drop events then emits the itemWasDropped signal. * @param e * The drop event. */ void WuQListWidget::dropEvent(QDropEvent* e) { QListWidget::dropEvent(e); emit itemWasDropped(); } connectome-workbench-1.4.2/src/GuiQt/WuQListWidget.h000066400000000000000000000032561360521144700223460ustar00rootroot00000000000000#ifndef __WU_Q_LIST_WIDGET__H_ #define __WU_Q_LIST_WIDGET__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include namespace caret { class WuQListWidget : public QListWidget { Q_OBJECT public: WuQListWidget(QWidget* parent = 0); virtual ~WuQListWidget(); signals: /** Is emitted when an item has been dropped. */ void itemWasDropped(); protected: virtual void dropEvent(QDropEvent*); private: WuQListWidget(const WuQListWidget&); WuQListWidget& operator=(const WuQListWidget&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_LIST_WIDGET_DECLARE__ // #endif // __WU_Q_LIST_WIDGET_DECLARE__ } // namespace #endif //__WU_Q_LIST_WIDGET__H_ connectome-workbench-1.4.2/src/GuiQt/WuQMacroCommandParameterWidget.cxx000066400000000000000000000366701360521144700262150ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_COMMAND_PARAMETER_WIDGET_DECLARE__ #include "WuQMacroCommandParameterWidget.h" #undef __WU_Q_MACRO_COMMAND_PARAMETER_WIDGET_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include #include #include "CaretAssert.h" #include "WbMacroCustomDataInfo.h" #include "WuQMacroCommand.h" #include "WuQMacroCommandParameter.h" #include "WuQMacroManager.h" using namespace caret; /** * \class caret::WuQMacroCommandParameterWidget * \brief Widget for display and editing a macro command parameter value * \ingroup GuiQt */ /** * Constructor for command parameter widgets * * @param index * Index of the parameter * @param gridLayout * Layout containing the widgets * @param parent * The parent widget */ WuQMacroCommandParameterWidget::WuQMacroCommandParameterWidget(const int32_t index, QGridLayout* gridLayout, QWidget* parent) : QObject(parent), m_index(index) { m_nameLabel = new QLabel(); modifySizePolicy(m_nameLabel); m_booleanOnAction = new QAction("On"); m_booleanOnAction->setCheckable(true); QObject::connect(m_booleanOnAction, &QAction::triggered, this, &WuQMacroCommandParameterWidget::booleanOnActionTriggered); QToolButton* booleanOnToolButton = new QToolButton(); booleanOnToolButton->setDefaultAction(m_booleanOnAction); m_booleanOffAction = new QAction("Off"); m_booleanOffAction->setCheckable(true); QObject::connect(m_booleanOffAction, &QAction::triggered, this, &WuQMacroCommandParameterWidget::booleanOffActionTriggered); QToolButton* booleanOffToolButton = new QToolButton(); booleanOffToolButton->setDefaultAction(m_booleanOffAction); QActionGroup* booleanActionGroup = new QActionGroup(this); booleanActionGroup->addAction(m_booleanOffAction); booleanActionGroup->addAction(m_booleanOnAction); booleanActionGroup->setExclusive(true); m_comboBox = new QComboBox(); m_comboBox->setFixedHeight(m_comboBox->sizeHint().height()); m_comboBox->setEditable(true); QObject::connect(m_comboBox, QOverload::of(&QComboBox::activated), this, &WuQMacroCommandParameterWidget::comboBoxActivated); m_doubleSpinBox = new QDoubleSpinBox(); m_doubleSpinBox->setFixedWidth(120); m_doubleSpinBox->setFixedHeight(m_doubleSpinBox->sizeHint().height()); QObject::connect(m_doubleSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), this, &WuQMacroCommandParameterWidget::doubleSpinBoxValueChanged); m_lineEdit = new QLineEdit(); m_lineEdit->setFixedHeight(m_lineEdit->sizeHint().height()); QObject::connect(m_lineEdit, &QLineEdit::textEdited, this, &WuQMacroCommandParameterWidget::lineEditTextEdited); m_spinBox = new QSpinBox(); m_spinBox->setFixedWidth(120); m_spinBox->setFixedHeight(m_spinBox->sizeHint().height()); QObject::connect(m_spinBox, QOverload::of(&QSpinBox::valueChanged), this, &WuQMacroCommandParameterWidget::spinBoxValueChanged); m_noValueWidget = new QWidget(); m_noValueWidget->setFixedWidth(50); m_noValueWidget->setFixedHeight(10); m_booleanWidget = new QWidget(); QHBoxLayout* booleanLayout = new QHBoxLayout(m_booleanWidget); booleanLayout->setContentsMargins(0, 0, 0, 0); booleanLayout->addWidget(booleanOnToolButton); booleanLayout->addWidget(booleanOffToolButton); booleanLayout->addStretch(); m_booleanWidget->setFixedHeight(m_booleanWidget->sizeHint().height()); m_stackedWidget = new QStackedWidget(); m_stackedWidget->addWidget(m_booleanWidget); m_stackedWidget->addWidget(m_comboBox); m_stackedWidget->addWidget(m_doubleSpinBox); m_stackedWidget->addWidget(m_lineEdit); m_stackedWidget->addWidget(m_spinBox); m_stackedWidget->addWidget(m_noValueWidget); const int numWidgets = m_stackedWidget->count(); for (int32_t i = 0; i < numWidgets; i++) { modifySizePolicy(m_stackedWidget->widget(i)); } modifySizePolicy(m_stackedWidget); /* * Note: A QStackedWidget aligns its current widget at the top. * So, align the label at the top so that the label and widget * are approximately aligned */ const int32_t row = gridLayout->rowCount(); gridLayout->addWidget(m_nameLabel, row, 0, Qt::AlignTop); gridLayout->addWidget(m_stackedWidget, row, 1); } /** * Destructor. */ WuQMacroCommandParameterWidget::~WuQMacroCommandParameterWidget() { } /** * Modify the size policy so that widget does not retain * size when hidden * * @param w * The widget */ void WuQMacroCommandParameterWidget::modifySizePolicy(QWidget* w) { CaretAssert(w); QSizePolicy sp = w->sizePolicy(); sp.setRetainSizeWhenHidden(false); w->setSizePolicy(sp); } /** * Update content of a command parameter * * @param windowIndex * Index of window * @param macroCommand * Macro command containing the parameter * @param parameter * The parameter */ void WuQMacroCommandParameterWidget::updateContent(int32_t windowIndex, WuQMacroCommand* macroCommand, WuQMacroCommandParameter* parameter) { m_windowIndex = windowIndex; m_macroCommand = macroCommand; m_parameter = parameter; QWidget* activeWidget(m_noValueWidget); const bool validFlag(m_parameter != NULL); if (validFlag) { CaretAssert(m_macroCommand); CaretAssert(m_parameter); m_nameLabel->setText(m_parameter->getName()); const QString customDataTypeName = parameter->getCustomDataType(); const bool customDataFlag( ! customDataTypeName.isEmpty()); switch (parameter->getDataType()) { case WuQMacroDataValueTypeEnum::AXIS: { m_comboBox->clear(); m_comboBox->setEditable(false); std::vector axisValues { "X", "Y", "Z" }; int32_t defaultIndex(-1); const QString value = m_parameter->getValue().toString(); const int32_t numAxes = static_cast(axisValues.size()); for (int32_t i = 0; i < numAxes; i++) { CaretAssertVectorIndex(axisValues, i); if (value == axisValues[i]) { defaultIndex = i; } m_comboBox->addItem(axisValues[i]); } if (defaultIndex < 0) { if ( ! value.isEmpty()) { defaultIndex = m_comboBox->count(); m_comboBox->addItem(value); } } if (defaultIndex >= 0) { m_comboBox->setCurrentIndex(defaultIndex); } activeWidget = m_comboBox; } break; case WuQMacroDataValueTypeEnum::BOOLEAN: { if (parameter->getValue().toBool()) { m_booleanOnAction->setChecked(true); } else { m_booleanOffAction->setChecked(true); } activeWidget = m_booleanWidget; } break; case WuQMacroDataValueTypeEnum::FLOAT: { std::array floatRange { -1.0e6, 1.0e6 }; if (customDataFlag) { WbMacroCustomDataInfo customDataInfo(WuQMacroDataValueTypeEnum::FLOAT); WuQMacroManager::instance()->getCustomParameterDataInfo(windowIndex, macroCommand, parameter, customDataInfo); floatRange = customDataInfo.getFloatRange(); } QSignalBlocker blocker(m_doubleSpinBox); m_doubleSpinBox->setRange(floatRange[0], floatRange[1]); m_doubleSpinBox->setValue(m_parameter->getValue().toFloat()); activeWidget = m_doubleSpinBox; } break; case WuQMacroDataValueTypeEnum::INTEGER: { std::array intRange { -100000, 100000 }; if (customDataFlag) { WbMacroCustomDataInfo customDataInfo(WuQMacroDataValueTypeEnum::INTEGER); WuQMacroManager::instance()->getCustomParameterDataInfo(windowIndex, macroCommand, parameter, customDataInfo); intRange = customDataInfo.getIntegerRange(); } QSignalBlocker blocker(m_spinBox); m_spinBox->setRange(intRange[0], intRange[1]); m_spinBox->setValue(m_parameter->getValue().toInt()); activeWidget = m_spinBox; } break; case WuQMacroDataValueTypeEnum::INVALID: break; case WuQMacroDataValueTypeEnum::MOUSE: break; case WuQMacroDataValueTypeEnum::NONE: break; case WuQMacroDataValueTypeEnum::STRING: m_lineEdit->setText(m_parameter->getValue().toString()); activeWidget = m_lineEdit; break; case WuQMacroDataValueTypeEnum::STRING_LIST: { m_comboBox->clear(); std::vector stringValues; if (customDataFlag) { WbMacroCustomDataInfo customDataInfo(WuQMacroDataValueTypeEnum::STRING_LIST); WuQMacroManager::instance()->getCustomParameterDataInfo(windowIndex, macroCommand, parameter, customDataInfo); stringValues = customDataInfo.getStringListValues(); } int32_t defaultIndex(-1); const QString selectedValue = m_parameter->getValue().toString(); const int32_t numValues = static_cast(stringValues.size()); if (numValues > 0) { for (int32_t i = 0; i < numValues; i++) { CaretAssertVectorIndex(stringValues, i); if (selectedValue == stringValues[i]) { defaultIndex = i; } m_comboBox->addItem(stringValues[i]); } bool editableFlag(false); if (editableFlag) { m_comboBox->setEditable(true); if (defaultIndex < 0) { if ( ! selectedValue.isEmpty()) { defaultIndex = m_comboBox->count(); m_comboBox->addItem(selectedValue); } } } else { m_comboBox->setEditable(false); } } else { if ( ! selectedValue.isEmpty()) { defaultIndex = m_comboBox->count(); m_comboBox->addItem(selectedValue); } m_comboBox->setEditable(true); } if (defaultIndex >= 0) { m_comboBox->setCurrentIndex(defaultIndex); } activeWidget = m_comboBox; } break; } } m_stackedWidget->setCurrentWidget(activeWidget); m_nameLabel->setVisible(validFlag); m_stackedWidget->setVisible(validFlag); // std::cout << "Stacked " << m_index << " height " << m_stackedWidget->sizeHint().height() << std::endl; // for (int32_t i = 0; i < m_stackedWidget->count(); i++) { // QWidget* w = m_stackedWidget->widget(i); // std::cout << " " << i << " height " << w->sizeHint().height() << " " << w->metaObject()->className() << std::endl; // } } /** * Called when boolean OFF action is triggered */ void WuQMacroCommandParameterWidget::booleanOffActionTriggered(bool) { CaretAssert(m_parameter); m_parameter->setValue(false); emit dataChanged(m_index); } /** * Called when boolean ON action is triggered */ void WuQMacroCommandParameterWidget::booleanOnActionTriggered(bool) { CaretAssert(m_parameter); m_parameter->setValue(true); emit dataChanged(m_index); } /** * Called when combo box is activated * * @param index * index of item selecteed */ void WuQMacroCommandParameterWidget::comboBoxActivated(int /*index*/) { CaretAssert(m_parameter); m_parameter->setValue(m_comboBox->currentText()); emit dataChanged(m_index); } /** * Called when value of double spin box is changed * * @param value * The new value */ void WuQMacroCommandParameterWidget::doubleSpinBoxValueChanged(double value) { CaretAssert(m_parameter); m_parameter->setValue(static_cast(value)); emit dataChanged(m_index); } /** * Called when value of the line edit is changed * * @param text * The new text value */ void WuQMacroCommandParameterWidget::lineEditTextEdited(const QString& text) { CaretAssert(m_parameter); m_parameter->setValue(text); emit dataChanged(m_index); } /** * Called when value of double spin box is changed * * @param value * The new value */ void WuQMacroCommandParameterWidget::spinBoxValueChanged(int value) { CaretAssert(m_parameter); m_parameter->setValue(value); emit dataChanged(m_index); } connectome-workbench-1.4.2/src/GuiQt/WuQMacroCommandParameterWidget.h000066400000000000000000000063571360521144700256410ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_COMMAND_PARAMETER_WIDGET_H__ #define __WU_Q_MACRO_COMMAND_PARAMETER_WIDGET_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include class QComboBox; class QDoubleSpinBox; class QGridLayout; class QLabel; class QLineEdit; class QSpinBox; class QStackedWidget; namespace caret { class WuQMacroCommand; class WuQMacroCommandParameter; class WuQMacroCommandParameterWidget : public QObject { Q_OBJECT public: WuQMacroCommandParameterWidget(const int32_t index, QGridLayout* gridLayout, QWidget* parent); virtual ~WuQMacroCommandParameterWidget(); WuQMacroCommandParameterWidget(const WuQMacroCommandParameterWidget&) = delete; WuQMacroCommandParameterWidget& operator=(const WuQMacroCommandParameterWidget&) = delete; void updateContent(int32_t windowIndex, WuQMacroCommand* macroCommand, WuQMacroCommandParameter* parameter); // ADD_NEW_METHODS_HERE signals: void dataChanged(const int index); private slots: void booleanOffActionTriggered(bool); void booleanOnActionTriggered(bool); void comboBoxActivated(int); void doubleSpinBoxValueChanged(double); void lineEditTextEdited(const QString&); void spinBoxValueChanged(int); private: void modifySizePolicy(QWidget* w); QLabel* m_nameLabel; const int32_t m_index; int32_t m_windowIndex = -1; WuQMacroCommand* m_macroCommand = NULL; WuQMacroCommandParameter* m_parameter = NULL; QStackedWidget* m_stackedWidget; QAction* m_booleanOnAction; QAction* m_booleanOffAction; QWidget* m_booleanWidget; QComboBox* m_comboBox; QDoubleSpinBox* m_doubleSpinBox; QLineEdit* m_lineEdit; QSpinBox* m_spinBox; QWidget* m_noValueWidget; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_MACRO_COMMAND_PARAMETER_WIDGET_DECLARE__ // #endif // __WU_Q_MACRO_COMMAND_PARAMETER_WIDGET_DECLARE__ } // namespace #endif //__WU_Q_MACRO_COMMAND_PARAMETER_WIDGET_H__ connectome-workbench-1.4.2/src/GuiQt/WuQMacroCopyDialog.cxx000066400000000000000000000165651360521144700236650ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_COPY_DIALOG_DECLARE__ #include "WuQMacroCopyDialog.h" #undef __WU_Q_MACRO_COPY_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "WuQMacro.h" #include "WuQMacroGroup.h" #include "WuQMacroManager.h" using namespace caret; /** * \class caret::WuQMacroCopyDialog * \brief Dialog for creating a new macro * \ingroup WuQMacro */ /** * Constructor. * * @param parent * The parent widget */ WuQMacroCopyDialog::WuQMacroCopyDialog(QWidget* parent) : QDialog(parent) { setWindowTitle("Copy Macro"); m_macroGroups = WuQMacroManager::instance()->getAllMacroGroups(); QLabel* nameLabel = new QLabel("Macro:"); QLabel* descriptionLabel = new QLabel("Description:"); QLabel* macroGroupLabel = new QLabel("Macro From:"); m_macroDescriptionTextEdit = new QPlainTextEdit(); m_macroDescriptionTextEdit->setFixedHeight(100); m_macroDescriptionTextEdit->setReadOnly(true); int32_t selectedMacroGroupIndex(-1); m_macroGroupComboBox = new QComboBox(); QObject::connect(m_macroGroupComboBox, QOverload::of(&QComboBox::activated), this, &WuQMacroCopyDialog::macroGroupComboBoxItemActivated); for (auto mg : m_macroGroups) { if ( ! mg->isEmpty()) { if (mg->getUniqueIdentifier() == s_lastSelectedMacroGroupIdentifier) { selectedMacroGroupIndex = m_macroGroupComboBox->count(); } m_macroGroupComboBox->addItem(mg->getName()); } } if (selectedMacroGroupIndex < 0) { selectedMacroGroupIndex = m_macroGroupComboBox->count() - 1; } if ((selectedMacroGroupIndex >= 0) && (selectedMacroGroupIndex < m_macroGroupComboBox->count())) { m_macroGroupComboBox->setCurrentIndex(selectedMacroGroupIndex); } m_macroNameComboBox = new QComboBox(); QObject::connect(m_macroNameComboBox, QOverload::of(&QComboBox::activated), this, &WuQMacroCopyDialog::macroComboBoxItemActivated); QGridLayout* gridLayout = new QGridLayout(); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 0); gridLayout->setColumnStretch(2, 0); gridLayout->setColumnStretch(3, 100); int row = 0; gridLayout->addWidget(macroGroupLabel, row, 0); gridLayout->addWidget(m_macroGroupComboBox, row, 1, 1, 3); row++; gridLayout->addWidget(nameLabel, row, 0); gridLayout->addWidget(m_macroNameComboBox, row, 1, 1, 3); row++; gridLayout->addWidget(descriptionLabel, row, 0); gridLayout->addWidget(m_macroDescriptionTextEdit, row, 1, 1, 3); row++; m_dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QObject::connect(m_dialogButtonBox, &QDialogButtonBox::accepted, this, &WuQMacroCopyDialog::accept); QObject::connect(m_dialogButtonBox, &QDialogButtonBox::rejected, this, &WuQMacroCopyDialog::reject); QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addLayout(gridLayout, 100); dialogLayout->addWidget(m_dialogButtonBox); setFixedHeight(sizeHint().height()); macroGroupComboBoxItemActivated(m_macroGroupComboBox->currentIndex()); } /** * Destructor. */ WuQMacroCopyDialog::~WuQMacroCopyDialog() { } /** * Called when macro group is selected from combo box * * @param index * Index of item selected */ void WuQMacroCopyDialog::macroGroupComboBoxItemActivated(int /*index*/) { m_macroNameComboBox->clear(); const WuQMacroGroup* mg = getMacroGroup(); if (mg != NULL) { const int32_t numMacros = mg->getNumberOfMacros(); for (int32_t i = 0; i < numMacros; i++) { m_macroNameComboBox->addItem(mg->getMacroAtIndex(i)->getName()); } } macroComboBoxItemActivated(m_macroNameComboBox->currentIndex()); } /** * Called when macro group is selected from combo box * * @param index * Index of item selected */ void WuQMacroCopyDialog::macroComboBoxItemActivated(int /*index*/) { QString text; const WuQMacro* macro = getMacroToCopy(); if (macro != NULL) { text = macro->getDescription(); } m_macroDescriptionTextEdit->setPlainText(text); } /** * Called when user clicks OK or Cancel * * @param r * The dialog code (Accepted or Rejected) */ void WuQMacroCopyDialog::done(int r) { if (r == QDialog::Accepted) { // const QString name(m_macroNameLineEdit->text().trimmed()); // if (name.isEmpty()) { // QMessageBox::critical(this, // "Error", // "Name is missing", // QMessageBox::Ok, // QMessageBox::Ok); // return; // } // // m_macro = new WuQMacro(); // m_macro->setName(name); // m_macro->setDescription(m_macroDescriptionTextEdit->toPlainText()); // // const int32_t groupIndex = m_macroGroupComboBox->currentIndex(); // if (groupIndex >= 0) { // WuQMacroGroup* macroGroup = m_macroGroups[groupIndex]; // macroGroup->addMacro(m_macro); // s_lastSelectedMacroGroupIdentifier = macroGroup->getUniqueIdentifier(); // } } QDialog::done(r); } /** * @return Pointer to selected macro group or NULL if none available */ const WuQMacroGroup* WuQMacroCopyDialog::getMacroGroup() const { const WuQMacroGroup* macroGroup(NULL); const int32_t groupIndex = m_macroGroupComboBox->currentIndex(); if ((groupIndex >= 0) && (groupIndex < static_cast(m_macroGroups.size()))) { CaretAssertVectorIndex(m_macroGroups, groupIndex); macroGroup = m_macroGroups[groupIndex]; CaretAssert(macroGroup); } return macroGroup; } /** * @return Pointer to macro that was selected and should be copied. * NULL if no macro to copy. */ const WuQMacro* WuQMacroCopyDialog::getMacroToCopy() const { const WuQMacro* macro(NULL); const WuQMacroGroup* mg = getMacroGroup(); if (mg != NULL) { const int32_t macroIndex = m_macroNameComboBox->currentIndex(); if ((macroIndex >= 0) && (macroIndex < mg->getNumberOfMacros())) { macro = mg->getMacroAtIndex(macroIndex); CaretAssert(macro); } } return macro; } connectome-workbench-1.4.2/src/GuiQt/WuQMacroCopyDialog.h000066400000000000000000000045471360521144700233070ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_COPY_DIALOG_H__ #define __WU_Q_MACRO_COPY_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include class QComboBox; class QDialogButtonBox; class QLineEdit; class QPlainTextEdit; namespace caret { class WuQMacro; class WuQMacroGroup; class WuQMacroShortCutKeyComboBox; class WuQMacroCopyDialog : public QDialog { Q_OBJECT public: WuQMacroCopyDialog(QWidget* parent = 0); virtual ~WuQMacroCopyDialog(); WuQMacroCopyDialog(const WuQMacroCopyDialog&) = delete; WuQMacroCopyDialog& operator=(const WuQMacroCopyDialog&) = delete; const WuQMacro* getMacroToCopy() const; // ADD_NEW_METHODS_HERE public slots: virtual void done(int r) override; private slots: void macroGroupComboBoxItemActivated(int); void macroComboBoxItemActivated(int); private: const WuQMacroGroup* getMacroGroup() const; std::vector m_macroGroups; QComboBox* m_macroGroupComboBox; QComboBox* m_macroNameComboBox; QPlainTextEdit* m_macroDescriptionTextEdit; QDialogButtonBox* m_dialogButtonBox; static QString s_lastSelectedMacroGroupIdentifier; }; #ifdef __WU_Q_MACRO_COPY_DIALOG_DECLARE__ QString WuQMacroCopyDialog::s_lastSelectedMacroGroupIdentifier = ""; #endif // __WU_Q_MACRO_COPY_DIALOG_DECLARE__ } // namespace #endif //__WU_Q_MACRO_COPY_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/WuQMacroCreateDialog.cxx000066400000000000000000000174301360521144700241460ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_CREATE_DIALOG_DECLARE__ #include "WuQMacroCreateDialog.h" #undef __WU_Q_MACRO_CREATE_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "WuQMacro.h" #include "WuQMacroGroup.h" #include "WuQMacroManager.h" #include "WuQMacroShortCutKeyComboBox.h" using namespace caret; /** * \class caret::WuQMacroCreateDialog * \brief Dialog for creating a new macro * \ingroup WuQMacro */ /** * Constructor. * * @param insertIntoMacroGroup * If not NULL, do not show group selection and insert new macro * into this group * @param insertMacroAfter * Used when inserting macro into a specific group * @param parent * The parent widget */ WuQMacroCreateDialog::WuQMacroCreateDialog(WuQMacroGroup* insertIntoMacroGroup, WuQMacro* insertAfterMacro, QWidget* parent) : QDialog(parent), m_insertIntoMacroGroup(insertIntoMacroGroup), m_insertAfterMacro(insertAfterMacro) { setWindowTitle("Record Macro"); m_macroGroups = WuQMacroManager::instance()->getActiveMacroGroups(); QLabel* nameLabel = new QLabel("Macro name:"); QLabel* shortCutKeyLabel = new QLabel("Short Cut Key:"); QLabel* shortCutKeyMaskLabel = new QLabel(WuQMacroManager::getShortCutKeysMask()); QLabel* descriptionLabel = new QLabel("Description:"); QLabel* macroGroupLabel = new QLabel("Store macro in:"); m_macroNameLineEdit = new QLineEdit(); m_macroNameLineEdit->setText(WuQMacroManager::instance()->getNewMacroDefaultName()); m_macroShortCutKeyComboBox = new WuQMacroShortCutKeyComboBox(this); m_macroDescriptionTextEdit = new QPlainTextEdit(); m_macroDescriptionTextEdit->setFixedHeight(100); bool insertIntoMacroGroupMatchFlag(false); int32_t selectedMacroGroupIndex(-1); m_macroGroupComboBox = new QComboBox(); for (auto mg : m_macroGroups) { if (insertIntoMacroGroup != NULL) { if (mg == insertIntoMacroGroup) { insertIntoMacroGroupMatchFlag = true; selectedMacroGroupIndex = m_macroGroupComboBox->count(); } } else if (mg->getUniqueIdentifier() == s_lastSelectedMacroGroupIdentifier) { selectedMacroGroupIndex = m_macroGroupComboBox->count(); } m_macroGroupComboBox->addItem(mg->getName()); } if (selectedMacroGroupIndex < 0) { selectedMacroGroupIndex = m_macroGroupComboBox->count() - 1; } if ((selectedMacroGroupIndex >= 0) && (selectedMacroGroupIndex < m_macroGroupComboBox->count())) { m_macroGroupComboBox->setCurrentIndex(selectedMacroGroupIndex); } if (insertIntoMacroGroupMatchFlag) { m_macroGroupComboBox->setEnabled(false); } QGridLayout* gridLayout = new QGridLayout(); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 0); gridLayout->setColumnStretch(2, 0); gridLayout->setColumnStretch(3, 100); int row = 0; gridLayout->addWidget(macroGroupLabel, row, 0); gridLayout->addWidget(m_macroGroupComboBox, row, 1, 1, 3); row++; gridLayout->addWidget(nameLabel, row, 0); gridLayout->addWidget(m_macroNameLineEdit, row, 1, 1, 3); row++; gridLayout->addWidget(shortCutKeyLabel, row, 0); gridLayout->addWidget(shortCutKeyMaskLabel, row, 1); gridLayout->addWidget(m_macroShortCutKeyComboBox->getWidget(), row, 2); row++; gridLayout->addWidget(descriptionLabel, row, 0); gridLayout->addWidget(m_macroDescriptionTextEdit, row, 1, 1, 3); row++; m_dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QObject::connect(m_dialogButtonBox, &QDialogButtonBox::accepted, this, &WuQMacroCreateDialog::accept); QObject::connect(m_dialogButtonBox, &QDialogButtonBox::rejected, this, &WuQMacroCreateDialog::reject); QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addLayout(gridLayout, 100); dialogLayout->addWidget(m_dialogButtonBox); setFixedHeight(sizeHint().height()); } /** * Constructor. * * @param parent * The parent widget */ WuQMacroCreateDialog::WuQMacroCreateDialog(QWidget* parent) : WuQMacroCreateDialog(NULL, NULL, parent) { /* delegating constructor does the work */ } /** * Destructor. */ WuQMacroCreateDialog::~WuQMacroCreateDialog() { } /** * Called when user clicks OK or Cancel * * @param r * The dialog code (Accepted or Rejected) */ void WuQMacroCreateDialog::done(int r) { if (r == QDialog::Accepted) { const QString name(m_macroNameLineEdit->text().trimmed()); if (name.isEmpty()) { QMessageBox::critical(this, "Error", "Name is missing", QMessageBox::Ok, QMessageBox::Ok); return; } m_macro = new WuQMacro(); m_macro->setName(name); m_macro->setShortCutKey(m_macroShortCutKeyComboBox->getSelectedShortCutKey()); m_macro->setDescription(m_macroDescriptionTextEdit->toPlainText()); const int32_t groupIndex = m_macroGroupComboBox->currentIndex(); if (groupIndex >= 0) { WuQMacroGroup* macroGroup = m_macroGroups[groupIndex]; if (macroGroup == m_insertIntoMacroGroup) { int32_t insertAtIndex = 0; if (m_insertAfterMacro != NULL) { insertAtIndex = macroGroup->getIndexOfMacro(m_insertAfterMacro) + 1; } if (insertAtIndex >= 0) { macroGroup->insertMacroAtIndex(insertAtIndex, m_macro); } else { macroGroup->addMacro(m_macro); } } else { macroGroup->addMacro(m_macro); } s_lastSelectedMacroGroupIdentifier = macroGroup->getUniqueIdentifier(); } } QDialog::done(r); } /** * @return Pointer to new macro. Macro has been added to a group. * Do not delete the pointer. */ WuQMacro* WuQMacroCreateDialog::getNewMacro() const { return m_macro; } /** * @return Create a combo box with valid function keys. * Method is static so that other classes may use it. */ QComboBox* WuQMacroCreateDialog::createFunctionKeyComboBox() { QComboBox* comboBox = new QComboBox(); comboBox->addItem(" "); const char firstChar = 'A'; const char lastChar = 'Z'; for (char ch = firstChar; ch <= lastChar; ch++) { comboBox->addItem(QString(ch)); } return comboBox; } connectome-workbench-1.4.2/src/GuiQt/WuQMacroCreateDialog.h000066400000000000000000000052001360521144700235630ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_CREATE_DIALOG_H__ #define __WU_Q_MACRO_CREATE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include class QComboBox; class QDialogButtonBox; class QLineEdit; class QPlainTextEdit; namespace caret { class WuQMacro; class WuQMacroGroup; class WuQMacroShortCutKeyComboBox; class WuQMacroCreateDialog : public QDialog { Q_OBJECT public: WuQMacroCreateDialog(QWidget* parent = 0); WuQMacroCreateDialog(WuQMacroGroup* insertIntoMacroGroup, WuQMacro* insertAfterMacro, QWidget* parent = 0); virtual ~WuQMacroCreateDialog(); WuQMacroCreateDialog(const WuQMacroCreateDialog&) = delete; WuQMacroCreateDialog& operator=(const WuQMacroCreateDialog&) = delete; WuQMacro* getNewMacro() const; // ADD_NEW_METHODS_HERE static QComboBox* createFunctionKeyComboBox(); public slots: virtual void done(int r) override; private: std::vector m_macroGroups; QComboBox* m_macroGroupComboBox; QLineEdit* m_macroNameLineEdit; WuQMacroShortCutKeyComboBox* m_macroShortCutKeyComboBox; QPlainTextEdit* m_macroDescriptionTextEdit; QDialogButtonBox* m_dialogButtonBox; WuQMacro* m_macro = NULL; WuQMacroGroup* m_insertIntoMacroGroup = NULL; WuQMacro* m_insertAfterMacro = NULL; static QString s_lastSelectedMacroGroupIdentifier; }; #ifdef __WU_Q_MACRO_CREATE_DIALOG_DECLARE__ QString WuQMacroCreateDialog::s_lastSelectedMacroGroupIdentifier = ""; #endif // __WU_Q_MACRO_CREATE_DIALOG_DECLARE__ } // namespace #endif //__WU_Q_MACRO_CREATE_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/WuQMacroCustomOperationManagerInterface.h000066400000000000000000000113461360521144700275170ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_CUSTOM_OPERATION_MANAGER_INTERFACE_H__ #define __WU_Q_MACRO_CUSTOM_OPERATION_MANAGER_INTERFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ class QString; class QWidget; namespace caret { class WuQMacroCommand; class WuQMacroCommandParameter; class WbMacroCustomDataInfo; class WuQMacroExecutorMonitor; class WuQMacroExecutorOptions; class WuQMacroCustomOperationManagerInterface { public: WuQMacroCustomOperationManagerInterface() { } virtual ~WuQMacroCustomOperationManagerInterface() { } WuQMacroCustomOperationManagerInterface(const WuQMacroCustomOperationManagerInterface&) = delete; WuQMacroCustomOperationManagerInterface& operator=(const WuQMacroCustomOperationManagerInterface&) = delete; /** * Get info for data in a custom parameter * * @param browserWindowIndex * Index of browser window * @param macroCommand * Macro command that contains the parameter * @param parameter * Parameter for info * @param dataInfo * Updated with data info in this method * @return * True if the data info is valid */ virtual bool getCustomParameterDataInfo(const int32_t browserWindowIndex, WuQMacroCommand* macroCommand, WuQMacroCommandParameter* parameter, WbMacroCustomDataInfo& dataInfoOut) = 0; /** * Run a custom-defined macro command * * @param parent * Parent widget for any dialogs * @param executorMonitor * The executor monitor * @param executorOptions * Options for the executor * @param customMacroCommand * Custom macro command to run * @param errorMessageOut * Contains any error information or empty if no error * @return * True if command executed successfully, else false */ virtual bool executeCustomOperationMacroCommand(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand, QString& errorMessageOut) = 0; /** * @return Names of custom operation defined macro commands */ virtual std::vector getNamesOfCustomOperationMacroCommands() = 0; /** * @return All custom operation commands. Caller is responsible for deleting * all content of the returned vector. */ virtual std::vector getAllCustomOperationMacroCommands() = 0; /** * Get a new instance of a custom operation for the given macro command name * * @param customMacroCommandName * Name of custom macro command * @param errorMessageOut * Contains any error information or empty if no error * @return * Pointer to command or NULL if not valid */ virtual WuQMacroCommand* newInstanceOfCustomOperationMacroCommand(const QString& customMacroCommandName, QString& errorMessageOut) = 0; // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_MACRO_CUSTOM_OPERATION_MANAGER_INTERFACE_DECLARE__ // #endif // __WU_Q_MACRO_CUSTOM_OPERATION_MANAGER_INTERFACE_DECLARE__ } // namespace #endif //__WU_Q_MACRO_CUSTOM_OPERATION_MANAGER_INTERFACE_H__ connectome-workbench-1.4.2/src/GuiQt/WuQMacroDialog.cxx000066400000000000000000002465441360521144700230340ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_DIALOG_DECLARE__ #include "WuQMacroDialog.h" #undef __WU_Q_MACRO_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "ElapsedTimer.h" #include "MovieRecorder.h" #include "MovieRecordingDialog.h" #include "SessionManager.h" #include "WuQMacro.h" #include "WuQMacroCopyDialog.h" #include "WuQMacroCommand.h" #include "WuQMacroCommandParameterWidget.h" #include "WuQMacroGroup.h" #include "WuQMacroExecutor.h" #include "WuQMacroExecutorMonitor.h" #include "WuQMacroManager.h" #include "WuQMacroMouseEventInfo.h" #include "WuQMacroNewCommandSelectionDialog.h" #include "WuQMacroShortCutKeyComboBox.h" #include "WuQMacroStandardItemTypeEnum.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::WuQMacroDialog * \brief Dialog for managing macros * \ingroup WuQMacro */ /** * Constructor. * * @param defaultMacroName * Default name for new macro * @param parent * The dialog's parent widget. */ WuQMacroDialog::WuQMacroDialog(QWidget* parent) : QDialog(parent) { setWindowTitle("Macros"); this->setAttribute(Qt::WA_DeleteOnClose, false); m_macroGroups = WuQMacroManager::instance()->getActiveMacroGroups(); QLabel* macroGroupLabel = new QLabel("Macros in:"); m_macroGroupComboBox = new QComboBox(); QObject::connect(m_macroGroupComboBox, static_cast(&QComboBox::activated), this, &WuQMacroDialog::macroGroupComboBoxActivated); m_resetMacroGroupToolButton = new QToolButton(); m_resetMacroGroupToolButton->setText(""); m_resetMacroGroupToolButton->setToolTip("Reload current scene"); QPixmap resetPixmap = createEditingToolButtonPixmap(m_resetMacroGroupToolButton, EditButton::RESET); m_resetMacroGroupToolButton->setIcon(resetPixmap); QObject::connect(m_resetMacroGroupToolButton, &QToolButton::clicked, this, &WuQMacroDialog::macroGroupResetToolButtonClicked); m_macroGroupToolButton = new QToolButton(); m_macroGroupToolButton->setText("..."); m_macroGroupToolButton->setToolTip("Export and import macro groups"); QObject::connect(m_macroGroupToolButton, &QToolButton::clicked, this, &WuQMacroDialog::macroGroupToolButtonClicked); QSize buttonSize(std::max(m_resetMacroGroupToolButton->sizeHint().width(), m_macroGroupToolButton->sizeHint().width()), std::max(m_resetMacroGroupToolButton->sizeHint().height(), m_macroGroupToolButton->sizeHint().height())); m_resetMacroGroupToolButton->setFixedSize(buttonSize); m_macroGroupToolButton->setFixedSize(buttonSize); QGridLayout* gridLayout = new QGridLayout(); gridLayout->setContentsMargins(0, 0, 0, 0); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); gridLayout->setColumnStretch(2, 0); gridLayout->setColumnStretch(3, 0); int row = 0; gridLayout->addWidget(macroGroupLabel, row, 0); gridLayout->addWidget(m_macroGroupComboBox, row, 1); gridLayout->addWidget(m_resetMacroGroupToolButton, row, 2); gridLayout->addWidget(m_macroGroupToolButton, row, 3); row++; gridLayout->addWidget(createHorizontalLine(), row, 0, 1, 4); row++; gridLayout->addWidget(createMacroRunAndEditingToolButtons(), row, 0, 1, 4); row++; for (int32_t iRow = 0; iRow < gridLayout->rowCount(); iRow++) { gridLayout->setRowStretch(iRow, 0); } QWidget* macroSelectionWidget = createMacroAndCommandSelectionWidget(); m_macroWidget = createMacroDisplayWidget(); m_commandWidget = createCommandDisplayWidget(); m_emptyWidget = new QWidget(); m_stackedWidget = new QStackedWidget(); m_stackedWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); m_stackedWidget->addWidget(m_macroWidget); m_stackedWidget->addWidget(m_commandWidget); m_stackedWidget->addWidget(m_emptyWidget); m_stackedWidget->setCurrentWidget(m_emptyWidget); QScrollArea* stackedScrollArea = new QScrollArea(); stackedScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); stackedScrollArea->setWidget(m_stackedWidget); stackedScrollArea->setWidgetResizable(true); m_dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Close); QObject::connect(m_dialogButtonBox, &QDialogButtonBox::rejected, this, &WuQMacroDialog::close); QObject::connect(m_dialogButtonBox, &QDialogButtonBox::clicked, this, &WuQMacroDialog::buttonBoxButtonClicked); const bool splitterFlag(false); if (splitterFlag) { /* * Use a splitter between the list widget (macro/command selection) * and the parameters (macro/command editing). * Splitter allows user to allocate space between the two. */ QSplitter* splitter = new QSplitter(); splitter->setOrientation(Qt::Vertical); macroSelectionWidget->setMinimumHeight(50); splitter->addWidget(macroSelectionWidget); splitter->addWidget(stackedScrollArea); splitter->setStretchFactor(0, 35); splitter->setStretchFactor(1, 65); QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addLayout(gridLayout); dialogLayout->addWidget(splitter); dialogLayout->addWidget(m_dialogButtonBox); } else { /* * Stretch the list widget (macro/command selection) * but no stretch for the parameters (macro/command editing) */ QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addLayout(gridLayout); dialogLayout->addWidget(macroSelectionWidget, 100); dialogLayout->addWidget(stackedScrollArea, 0); dialogLayout->addWidget(m_dialogButtonBox, 0); } updateDialogContents(); /* * Disable auto default for all push buttons */ QList allChildPushButtons = findChildren(QRegExp(".*")); QListIterator allChildPushButtonsIterator(allChildPushButtons); while (allChildPushButtonsIterator.hasNext()) { QPushButton* pushButton = allChildPushButtonsIterator.next(); pushButton->setAutoDefault(false); pushButton->setDefault(false); } } /** * Destructor. */ WuQMacroDialog::~WuQMacroDialog() { } /** * Called when close event is issuedf * * @param event * The close event */ void WuQMacroDialog::closeEvent(QCloseEvent* event) { s_previousDialogGeometry = saveGeometry(); QDialog::closeEvent(event); } void WuQMacroDialog::restorePositionAndSize() { if ( ! s_previousDialogGeometry.isEmpty()) { restoreGeometry(s_previousDialogGeometry); } } /** * @return Widget with run and editing buttons */ QWidget* WuQMacroDialog::createMacroRunAndEditingToolButtons() { m_runMacroToolButton = new QToolButton(); m_runMacroToolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); m_runMacroToolButton->setText("Run"); QPixmap runPixmap = createEditingToolButtonPixmap(m_runMacroToolButton, EditButton::RUN); m_runMacroToolButton->setIcon(runPixmap); m_runMacroToolButton->setToolTip("Runs the selected macro. If a command is selected, " "the macro containing the command is run."); QObject::connect(m_runMacroToolButton, &QToolButton::clicked, this, &WuQMacroDialog::runMacroToolButtonClicked); m_pauseMacroToolButton = new QToolButton(); m_pauseMacroToolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); m_pauseMacroToolButton->setText("Pause"); QPixmap pausePixmap = createEditingToolButtonPixmap(m_pauseMacroToolButton, EditButton::PAUSE); m_pauseMacroToolButton->setIcon(pausePixmap); m_pauseMacroToolButton->setToolTip("Pause or continue a macro. Button is highlighted " "when a macro is paused."); m_pauseMacroToolButton->setCheckable(true); QObject::connect(m_pauseMacroToolButton, &QToolButton::clicked, this, &WuQMacroDialog::pauseContinueMacroToolButtonClicked); m_stopMacroToolButton = new QToolButton(); m_stopMacroToolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); m_stopMacroToolButton->setText("Stop"); QPixmap stopPixmap = createEditingToolButtonPixmap(m_stopMacroToolButton, EditButton::STOP); m_stopMacroToolButton->setIcon(stopPixmap); m_stopMacroToolButton->setToolTip("Stop the currently running macro. Response may not be immediate."); QObject::connect(m_stopMacroToolButton, &QToolButton::clicked, this, &WuQMacroDialog::stopMacroToolButtonClicked); m_recordMacroToolButton = new QToolButton(); m_recordMacroToolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); m_recordMacroToolButton->setText("Record"); m_recordMacroToolButtonIconOff = createEditingToolButtonPixmap(m_recordMacroToolButton, EditButton::RECORD_OFF); m_recordMacroToolButtonIconOn = createEditingToolButtonPixmap(m_recordMacroToolButton, EditButton::RECORD_ON); m_recordMacroToolButton->setIcon(m_recordMacroToolButtonIconOff); m_recordMacroToolButton->setToolTip("Record a new macro or record new commands"); QObject::connect(m_recordMacroToolButton, &QToolButton::clicked, this, &WuQMacroDialog::recordMacroToolButtonClicked); m_editingMoveUpToolButton = new QToolButton(); QPixmap moveUpPixmap = createEditingToolButtonPixmap(m_editingMoveUpToolButton, EditButton::MOVE_UP); m_editingMoveUpToolButton->setIcon(moveUpPixmap); m_editingMoveUpToolButton->setToolTip("Move selected macro/command up"); QObject::connect(m_editingMoveUpToolButton, &QToolButton::clicked, this, &WuQMacroDialog::editingMoveUpToolButtonClicked); m_editingMoveDownToolButton = new QToolButton(); QPixmap moveDownPixmap = createEditingToolButtonPixmap(m_editingMoveDownToolButton, EditButton::MOVE_DOWN); m_editingMoveDownToolButton->setIcon(moveDownPixmap); m_editingMoveDownToolButton->setToolTip("Move selected macro/command down"); QObject::connect(m_editingMoveDownToolButton, &QToolButton::clicked, this, &WuQMacroDialog::editingMoveDownToolButtonClicked); m_editingDeleteToolButton = new QToolButton(); QPixmap deletePixmap = createEditingToolButtonPixmap(m_editingDeleteToolButton, EditButton::DELETER); m_editingDeleteToolButton->setIcon(deletePixmap); m_editingDeleteToolButton->setToolTip("Delete the selected macro/command"); QObject::connect(m_editingDeleteToolButton, &QToolButton::clicked, this, &WuQMacroDialog::editingDeleteToolButtonClicked); m_editingInsertToolButton = new QToolButton(); QPixmap insertPixmap = createEditingToolButtonPixmap(m_editingInsertToolButton, EditButton::INSERTER); m_editingInsertToolButton->setIcon(insertPixmap); m_editingInsertToolButton->setToolTip("Insert a new macro or macro command below the selected item"); QObject::connect(m_editingInsertToolButton, &QToolButton::clicked, this, &WuQMacroDialog::editingInsertToolButtonClicked); const int spaceAmount(7); QWidget* widget = new QWidget(); QHBoxLayout* toolButtonLayout = new QHBoxLayout(widget); toolButtonLayout->setContentsMargins(0, 0, 0, 0); toolButtonLayout->addWidget(m_stopMacroToolButton); toolButtonLayout->addWidget(m_runMacroToolButton); toolButtonLayout->addWidget(m_pauseMacroToolButton); toolButtonLayout->addWidget(m_recordMacroToolButton); toolButtonLayout->addSpacing(3 * spaceAmount); toolButtonLayout->addStretch(); toolButtonLayout->addWidget(m_editingInsertToolButton); toolButtonLayout->addSpacing(spaceAmount); toolButtonLayout->addWidget(m_editingMoveUpToolButton); toolButtonLayout->addWidget(m_editingMoveDownToolButton); toolButtonLayout->addSpacing(spaceAmount); toolButtonLayout->addWidget(m_editingDeleteToolButton); return widget; } /** * @return the macro and command selection widget */ QWidget* WuQMacroDialog::createMacroAndCommandSelectionWidget() { m_treeView = new QTreeView(); m_treeView->setHeaderHidden(true); QObject::connect(m_treeView, &QTreeView::clicked, this, &WuQMacroDialog::treeViewItemClicked); m_treeView->setContextMenuPolicy(Qt::CustomContextMenu); QObject::connect(m_treeView, &QTreeView::customContextMenuRequested, this, &WuQMacroDialog::treeViewCustomContextMenuRequested); return m_treeView; } /** * @return The widget displayed when a macro is selected */ QWidget* WuQMacroDialog::createMacroDisplayWidget() { QLabel* macroNameLabel = new QLabel("Name:"); m_macroNameLineEdit = new QLineEdit(); QObject::connect(m_macroNameLineEdit, &QLineEdit::textEdited, this, &WuQMacroDialog::macroNameLineEditTextEdited); QLabel* shortCutKeyLabel = new QLabel("Short Cut Key:"); QLabel* shortCutKeyMaskLabel = new QLabel(WuQMacroManager::getShortCutKeysMask()); m_macroShortCutKeyComboBox = new WuQMacroShortCutKeyComboBox(this); QObject::connect(m_macroShortCutKeyComboBox, &WuQMacroShortCutKeyComboBox::shortCutKeySelected, this, &WuQMacroDialog::macroShortCutKeySelected); QLabel* descriptionLabel = new QLabel("Description:"); m_macroDescriptionTextEdit = new QPlainTextEdit(); m_macroDescriptionTextEdit->setFixedHeight(100); QObject::connect(m_macroDescriptionTextEdit, &QPlainTextEdit::textChanged, this, &WuQMacroDialog::macroDescriptionTextEditChanged); QGridLayout* gridLayout = new QGridLayout(); gridLayout->setContentsMargins(0, 0, 0, 0); gridLayout->setVerticalSpacing(5); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 0); gridLayout->setColumnStretch(2, 100); int row = 0; gridLayout->addWidget(macroNameLabel, row, 0); gridLayout->addWidget(m_macroNameLineEdit, row, 1, 1, 2); row++; gridLayout->addWidget(shortCutKeyLabel, row, 0); gridLayout->addWidget(shortCutKeyMaskLabel, row, 1); gridLayout->addWidget(m_macroShortCutKeyComboBox->getWidget(), row, 2, Qt::AlignLeft); row++; gridLayout->addWidget(descriptionLabel, row, 0, Qt::AlignTop); gridLayout->addWidget(m_macroDescriptionTextEdit, row, 1, 1, 2); row++; QHBoxLayout* titleLayout = new QHBoxLayout(); titleLayout->setContentsMargins(0, 0, 0, 0); titleLayout->addWidget(new QLabel("Macro ")); titleLayout->addWidget(createHorizontalLine(), 100); QHBoxLayout* runOptionsTitleLayout = new QHBoxLayout(); runOptionsTitleLayout->setContentsMargins(0, 0, 0, 0); runOptionsTitleLayout->addWidget(new QLabel("Run Macro Options ")); runOptionsTitleLayout->addWidget(createHorizontalLine(), 100); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->setSpacing(layout->spacing() / 2); layout->addLayout(titleLayout); layout->addLayout(gridLayout); layout->addLayout(runOptionsTitleLayout); layout->addWidget(createRunOptionsWidget()); layout->addStretch(); return widget; } /** * Called when macro name line edit text changed * @param text */ void WuQMacroDialog::macroNameLineEditTextEdited(const QString& text) { WuQMacro* macro = getSelectedMacro(); if (macro != NULL) { macro->setName(text); m_macroNameLineEditBlockUpdateFlag = true; WuQMacroManager::instance()->macroWasModified(macro); m_macroNameLineEditBlockUpdateFlag = false; } } /** * Called when macro short cut key is selected * * @param shortCutKey * Shortcut key that was selected */ void WuQMacroDialog::macroShortCutKeySelected(const WuQMacroShortCutKeyEnum::Enum shortCutKey) { WuQMacro* macro = getSelectedMacro(); if (macro != NULL) { macro->setShortCutKey(shortCutKey); WuQMacroManager::instance()->macroWasModified(macro); updateMacroWidget(macro); } } /** * Called when macro description text edit is changed */ void WuQMacroDialog::macroDescriptionTextEditChanged() { WuQMacro* macro = getSelectedMacro(); if (macro != NULL) { const QString text = m_macroDescriptionTextEdit->toPlainText(); macro->setDescription(text); m_macroDescriptionTextEditBlockUpdateFlag = true; WuQMacroManager::instance()->macroWasModified(macro); m_macroDescriptionTextEditBlockUpdateFlag = false; } } /** * @return New instance of widget containing macro run options */ QWidget* WuQMacroDialog::createRunOptionsWidget() { QWidget* widget = new QWidget(); QLabel* windowLabel = new QLabel("Window"); m_runOptionsWindowComboBox = new QComboBox(); m_runOptionsWindowComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); m_runOptionLoopCheckBox = new QCheckBox("Loop"); m_runOptionLoopCheckBox->setChecked(false); m_runOptionLoopCheckBox->setToolTip("Run macro in a loop until stopped by user"); QObject::connect(m_runOptionLoopCheckBox, &QCheckBox::clicked, this, &WuQMacroDialog::runOptionLoopCheckBoxClicked); m_runOptionMoveMouseCheckBox = new QCheckBox("Move mouse to to highlight controls"); m_runOptionMoveMouseCheckBox->setChecked(true); m_runOptionMoveMouseCheckBox->setToolTip("As macro runs, the mouse is moved to\n" "highlight user-interface controls"); QObject::connect(m_runOptionMoveMouseCheckBox, &QCheckBox::clicked, this, &WuQMacroDialog::runOptionMoveMouseCheckBoxClicked); m_runOptionRecordMovieWhileMacroRunsCheckBox = new QCheckBox("Record movie while macro runs"); m_runOptionRecordMovieWhileMacroRunsCheckBox->setChecked(false); m_runOptionRecordMovieWhileMacroRunsCheckBox->setToolTip("While the macro runs, add images to Movie Recorder"); QObject::connect(m_runOptionRecordMovieWhileMacroRunsCheckBox, &QCheckBox::clicked, this, &WuQMacroDialog::runOptionRecordMovieCheckBoxClicked); m_runOptionCreateMovieAfterMacroRunsCheckBox = new QCheckBox("Create movie after macro finishes"); m_runOptionCreateMovieAfterMacroRunsCheckBox->setChecked(false); m_runOptionCreateMovieAfterMacroRunsCheckBox->setToolTip("After macro finishes, create the movie"); QObject::connect(m_runOptionCreateMovieAfterMacroRunsCheckBox, &QCheckBox::clicked, this, &WuQMacroDialog::runOptionCreateMovieCheckBoxClicked); m_ignoreDelaysAndDurationsCheckBox = new QCheckBox("Ignore delays and durations"); const QString ignoreToolTip("Ignore delays and durations and minimize iterations " "to quickly execute macro (for debugging)"); m_ignoreDelaysAndDurationsCheckBox->setToolTip(ignoreToolTip); QObject::connect(m_ignoreDelaysAndDurationsCheckBox, &QCheckBox::clicked, this, &WuQMacroDialog::runOptionIgnoreDelaysAndDurationsCheckBoxClicked); QHBoxLayout* windowLayout = new QHBoxLayout(); windowLayout->setContentsMargins(0, 0, 0, 0); windowLayout->addWidget(windowLabel); windowLayout->addWidget(m_runOptionsWindowComboBox); windowLayout->addStretch(); /* * In layout, create movie option is indented */ QGridLayout* runOptionsLayout = new QGridLayout(widget); runOptionsLayout->setColumnMinimumWidth(0, 15); runOptionsLayout->setColumnStretch(0, 0); runOptionsLayout->setColumnStretch(1, 100); int row = 0; runOptionsLayout->addLayout(windowLayout, row, 0, 1, 2, Qt::AlignLeft); row++; runOptionsLayout->addWidget(m_runOptionLoopCheckBox, row, 0, 1, 2, Qt::AlignLeft); row++; runOptionsLayout->addWidget(m_ignoreDelaysAndDurationsCheckBox, row, 0, 1, 2, Qt::AlignLeft); row++; runOptionsLayout->addWidget(m_runOptionMoveMouseCheckBox, row, 0, 1, 2, Qt::AlignLeft); row++; runOptionsLayout->addWidget(m_runOptionRecordMovieWhileMacroRunsCheckBox, row, 0, 1, 2, Qt::AlignLeft); row++; runOptionsLayout->addWidget(m_runOptionCreateMovieAfterMacroRunsCheckBox, row, 1, Qt::AlignLeft); row++; return widget; } /** * Called when run options move mouse checkbox is changed * * @param checked * New checked status. */ void WuQMacroDialog::runOptionMoveMouseCheckBoxClicked(bool checked) { WuQMacroExecutorOptions* options = WuQMacroManager::instance()->getExecutorOptions(); CaretAssert(options); options->setShowMouseMovement(checked); } /** * Called when run options loop checkbox is changed * * @param checked * New checked status. */ void WuQMacroDialog::runOptionLoopCheckBoxClicked(bool checked) { WuQMacroExecutorOptions* options = WuQMacroManager::instance()->getExecutorOptions(); CaretAssert(options); options->setLooping(checked); } /** * Called when run options record movie checkbox is changed * * @param checked * New checked status. */ void WuQMacroDialog::runOptionRecordMovieCheckBoxClicked(bool checked) { WuQMacroExecutorOptions* options = WuQMacroManager::instance()->getExecutorOptions(); CaretAssert(options); options->setRecordMovieDuringExecution(checked); updateCreateMovieCheckBox(); } /** * Called when run options create movie checkbox is changed * * @param checked * New checked status. */ void WuQMacroDialog::runOptionCreateMovieCheckBoxClicked(bool checked) { WuQMacroExecutorOptions* options = WuQMacroManager::instance()->getExecutorOptions(); CaretAssert(options); /* * If transitioning from OFF to ON, verify file name */ if (checked && ( ! options->isCreateMovieAfterMacroExecution())) { MovieRecorder* movieRecorder = SessionManager::get()->getMovieRecorder(); const QString filename = MovieRecordingDialog::getMovieFileNameFromFileDialog(m_runOptionCreateMovieAfterMacroRunsCheckBox); if (filename.isEmpty()) { return; } movieRecorder->setMovieFileName(filename); } options->setCreateMovieAfterMacroExecution(checked); } /** * Called when run options ignore delays and durations checkbox is changed * * @param checked * New checked status. */ void WuQMacroDialog::runOptionIgnoreDelaysAndDurationsCheckBoxClicked(bool checked) { WuQMacroExecutorOptions* options = WuQMacroManager::instance()->getExecutorOptions(); CaretAssert(options); options->setIgnoreDelaysAndDurations(checked); } /** * Called when a button in dialog is clicked * * @param button * Button that was clicked. */ void WuQMacroDialog::buttonBoxButtonClicked(QAbstractButton* /*button*/) { } /** * @return The widget displayed when a commnand is selected */ QWidget* WuQMacroDialog::createCommandDisplayWidget() { QLabel* titleLabel = new QLabel("Title:"); m_commandTitleLabel = new QLabel(); QLabel* nameLabel = new QLabel("GUI Name:"); m_commandNameLabel = new QLabel(); QLabel* typeLabel = new QLabel("GUI Type:"); m_commandTypeLabel = new QLabel(); QLabel* delayLabel = new QLabel("Delay:"); m_commandDelaySpinBox = new QDoubleSpinBox(); m_commandDelaySpinBox->setMinimum(0.0); m_commandDelaySpinBox->setMaximum(1000.0); m_commandDelaySpinBox->setSingleStep(1.0); m_commandDelaySpinBox->setDecimals(1); m_commandDelaySpinBox->setToolTip("Delay, in seconds, before running command"); m_commandDelaySpinBox->setSizePolicy(QSizePolicy::Fixed, m_commandDelaySpinBox->sizePolicy().verticalPolicy()); QObject::connect(m_commandDelaySpinBox, static_cast(&QDoubleSpinBox::valueChanged), this, &WuQMacroDialog::macroCommandDelaySpinBoxValueChanged); QLabel* delayTwoLabel = new QLabel("seconds before command"); QLabel* descriptionLabel = new QLabel("Description:"); m_commandDescriptionTextEdit = new QPlainTextEdit(); m_commandDescriptionTextEdit->setMaximumHeight(100); QObject::connect(m_commandDescriptionTextEdit, &QPlainTextEdit::textChanged, this, &WuQMacroDialog::macroCommandDescriptionTextEditChanged); QWidget* commandInfoWidget = new QWidget(); commandInfoWidget->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed)); QGridLayout* commandInfoLayout = new QGridLayout(commandInfoWidget); commandInfoLayout->setContentsMargins(0, 0, 0, 0); commandInfoLayout->setColumnStretch(0, 0); commandInfoLayout->setColumnStretch(1, 0); commandInfoLayout->setColumnStretch(2, 100); int row = 0; commandInfoLayout->addWidget(titleLabel, row, 0); commandInfoLayout->addWidget(m_commandTitleLabel, row, 1, 1, 2, Qt::AlignLeft); row++; commandInfoLayout->addWidget(nameLabel, row, 0); commandInfoLayout->addWidget(m_commandNameLabel, row, 1, 1, 2, Qt::AlignLeft); row++; commandInfoLayout->addWidget(typeLabel, row, 0); commandInfoLayout->addWidget(m_commandTypeLabel, row, 1, 1, 2, Qt::AlignLeft); row++; commandInfoLayout->addWidget(delayLabel, row, 0); commandInfoLayout->addWidget(m_commandDelaySpinBox, row, 1); commandInfoLayout->addWidget(delayTwoLabel, row, 2, Qt::AlignLeft); row++; commandInfoLayout->addWidget(descriptionLabel, row, 0, (Qt::AlignLeft | Qt::AlignTop)); commandInfoLayout->addWidget(m_commandDescriptionTextEdit, row, 1, 1, 2); row++; QWidget* parametersWidget = new QWidget(); parametersWidget->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed)); m_parameterWidgetsGridLayout = new QGridLayout(parametersWidget); m_parameterWidgetsGridLayout->setContentsMargins(0, 0, 0, 0); m_parameterWidgetsGridLayout->setVerticalSpacing(2); m_parameterWidgetsGridLayout->setColumnStretch(0, 0); m_parameterWidgetsGridLayout->setColumnStretch(1, 100); QHBoxLayout* parametersLayout = new QHBoxLayout(); parametersLayout->setContentsMargins(0, 0, 0, 0); parametersLayout->addWidget(new QLabel("Parameters")); parametersLayout->addWidget(createHorizontalLine(), 100); QWidget* widget = new QWidget(); QVBoxLayout* widgetLayout = new QVBoxLayout(widget); widgetLayout->addWidget(commandInfoWidget); widgetLayout->addLayout(parametersLayout); widgetLayout->addWidget(parametersWidget); widgetLayout->addSpacing(6); widgetLayout->addStretch(); return widget; } /** * Update content of the dialog */ void WuQMacroDialog::updateDialogContents() { QString selectedUniqueIdentifer; const QVariant dataSelected = m_macroGroupComboBox->currentData(); if (dataSelected.isValid()) { if (dataSelected.type() == QVariant::String) { selectedUniqueIdentifer = dataSelected.toString(); } } m_macroGroups = WuQMacroManager::instance()->getActiveMacroGroups(); m_macroGroupComboBox->clear(); for (auto mg : m_macroGroups) { m_macroGroupComboBox->addItem(mg->getName(), mg->getUniqueIdentifier()); } int32_t selectedIndex = m_macroGroupComboBox->findData(selectedUniqueIdentifer); if (selectedIndex < 0) { selectedIndex = m_macroGroupComboBox->count() - 1; } if ((selectedIndex >= 0) && (selectedIndex < m_macroGroupComboBox->count())) { m_macroGroupComboBox->setCurrentIndex(selectedIndex); } m_macroGroupToolButton->setEnabled(m_macroGroupComboBox->count() > 0); const QString windowText = m_runOptionsWindowComboBox->currentText(); m_runOptionsWindowComboBox->clear(); const std::vector windowIDs = WuQMacroManager::instance()->getMainWindowIdentifiers(); for (const auto id : windowIDs) { m_runOptionsWindowComboBox->addItem(id); } m_runOptionsWindowComboBox->setCurrentText(windowText); const WuQMacroExecutorOptions* runOptions = WuQMacroManager::instance()->getExecutorOptions(); CaretAssert(runOptions); m_runOptionMoveMouseCheckBox->setChecked(runOptions->isShowMouseMovement()); m_runOptionLoopCheckBox->setChecked(runOptions->isLooping()); m_runOptionRecordMovieWhileMacroRunsCheckBox->setChecked(runOptions->isRecordMovieDuringExecution()); m_ignoreDelaysAndDurationsCheckBox->setChecked(runOptions->isIgnoreDelaysAndDurations()); updateCreateMovieCheckBox(); macroGroupComboBoxActivated(selectedIndex); } /** * Update the create movie checkbox status */ void WuQMacroDialog::updateCreateMovieCheckBox() { const WuQMacroExecutorOptions* runOptions = WuQMacroManager::instance()->getExecutorOptions(); CaretAssert(runOptions); m_runOptionCreateMovieAfterMacroRunsCheckBox->setChecked(runOptions->isCreateMovieAfterMacroExecution()); m_runOptionCreateMovieAfterMacroRunsCheckBox->setEnabled(runOptions->isRecordMovieDuringExecution()); } /** * Called when an item in the tree view is clicked by user * * @param modelIndex * Model index of item selected */ void WuQMacroDialog::treeViewItemClicked(const QModelIndex& /*modelIndex*/) { /* * Unused at this time. The signal only works when user * click's an item and not when an arrow key is used * to select an item. Replacement is for the selection * model to connect to selectionModelRowChanged(). */ } /** * Called to display custom context menu for the tree view */ void WuQMacroDialog::treeViewCustomContextMenuRequested(const QPoint& pos) { QModelIndex modelIndex = m_treeView->indexAt(pos); if (modelIndex.isValid()) { WuQMacroCommand* command = getSelectedMacroCommand(); if (command != NULL) { QMenu menu(this); menu.addAction("Run this Command", this, &WuQMacroDialog::runOnlySelectedCommandMenuItemSelected); menu.addSeparator(); menu.addAction("Run Macro and Start With this Command", this, &WuQMacroDialog::runAndStartWithSelectedCommandMenuItemSelected); menu.addAction("Run Macro and Start With this Command Without Delays/Durations", this, &WuQMacroDialog::runAndStartWithNoDelayDurationSelectedCommandMenuItemSelected); menu.addSeparator(); menu.addAction("Run Macro and Stop After this Command", this, &WuQMacroDialog::runAndStopAfterSelectedCommandMenuItemSelected); menu.addAction("Run Macro and Stop After this Command Without Delays/Durations", this, &WuQMacroDialog::runAndStopAfterWithNoDelayDurationSelectedCommandMenuItemSelected); menu.exec(m_treeView->mapToGlobal(pos)); } } } /** * Called when 'run and start with...' is selected from * context (pop-up) menu. Runs macro starting with selected command. */ void WuQMacroDialog::runAndStartWithSelectedCommandMenuItemSelected() { WuQMacroCommand* command = getSelectedMacroCommand(); if (command != NULL) { runSelectedMacro(command, NULL); } else { QMessageBox::warning(this, "Error", "No macro command is selected"); } } /** * Called when 'run this command only...' is selected from * context (pop-up) menu. Runs macro to selected command. */ void WuQMacroDialog::runOnlySelectedCommandMenuItemSelected() { WuQMacroCommand* command = getSelectedMacroCommand(); if (command != NULL) { runSelectedMacro(command, command); } else { QMessageBox::warning(this, "Error", "No macro command is selected"); } } /** * Called when 'run and start with without delay duration...' is selected from * context (pop-up) menu. Runs macro to selected command. */ void WuQMacroDialog::runAndStartWithNoDelayDurationSelectedCommandMenuItemSelected() { WuQMacroCommand* command = getSelectedMacroCommand(); if (command != NULL) { WuQMacroManager* macroManager = WuQMacroManager::instance(); WuQMacroExecutorOptions* runOptions = macroManager->getExecutorOptions(); const bool savedIgnoreDelaysFlag = runOptions->isIgnoreDelaysAndDurations(); runOptions->setIgnoreDelaysAndDurations(true); runSelectedMacro(command, NULL); runOptions->setIgnoreDelaysAndDurations(savedIgnoreDelaysFlag); } else { QMessageBox::warning(this, "Error", "No macro command is selected"); } } /** * Called when 'run and stop after...' is selected from * context (pop-up) menu. Runs macro to selected command. */ void WuQMacroDialog::runAndStopAfterSelectedCommandMenuItemSelected() { WuQMacroCommand* command = getSelectedMacroCommand(); if (command != NULL) { WuQMacroManager* macroManager = WuQMacroManager::instance(); WuQMacroExecutorOptions* runOptions = macroManager->getExecutorOptions(); const bool savedStopAfterOptionFlag = runOptions->isStopAfterSelectedCommand(); runOptions->setStopAfterSelectedCommand(true); runSelectedMacro(NULL, command); runOptions->setStopAfterSelectedCommand(savedStopAfterOptionFlag); } else { QMessageBox::warning(this, "Error", "No macro command is selected"); } } /** * Called when 'run and stop after without delay duration...' is selected from * context (pop-up) menu. Runs macro to selected command. */ void WuQMacroDialog::runAndStopAfterWithNoDelayDurationSelectedCommandMenuItemSelected() { WuQMacroCommand* command = getSelectedMacroCommand(); if (command != NULL) { WuQMacroManager* macroManager = WuQMacroManager::instance(); WuQMacroExecutorOptions* runOptions = macroManager->getExecutorOptions(); const bool savedStopAfterOptionFlag = runOptions->isStopAfterSelectedCommand(); const bool savedIgnoreDelaysFlag = runOptions->isIgnoreDelaysAndDurations(); runOptions->setStopAfterSelectedCommand(true); runOptions->setIgnoreDelaysAndDurations(true); runSelectedMacro(NULL, command); runOptions->setStopAfterSelectedCommand(savedStopAfterOptionFlag); runOptions->setIgnoreDelaysAndDurations(savedIgnoreDelaysFlag); } else { QMessageBox::warning(this, "Error", "No macro command is selected"); } } /** * Called when an item in the tree is selected in some way * (mouse click, arrow key, etc) * * @param modelIndex * Model index of item selected */ void WuQMacroDialog::treeItemSelected(const QModelIndex& modelIndex) { QStandardItemModel* selectedModel = NULL; if (modelIndex.isValid()) { const QAbstractItemModel* abstractModel = modelIndex.model(); if (abstractModel != NULL) { const QStandardItemModel* constModel = qobject_cast(abstractModel); if (constModel != NULL) { selectedModel = const_cast(constModel); } } } WuQMacro* macro(NULL); WuQMacroCommand* macroCommand(NULL); if (selectedModel != NULL) { QStandardItem* selectedItem = selectedModel->itemFromIndex(modelIndex); bool validFlag(false); const WuQMacroStandardItemTypeEnum::Enum itemType = WuQMacroStandardItemTypeEnum::fromIntegerCode(selectedItem->type(), &validFlag); if (validFlag) { switch (itemType) { case WuQMacroStandardItemTypeEnum::INVALID: CaretAssertMessage(0, "Type should never be invalid"); break; case WuQMacroStandardItemTypeEnum::MACRO: macro = dynamic_cast(selectedItem); CaretAssert(macro); m_stackedWidget->setCurrentWidget(m_macroWidget); break; case WuQMacroStandardItemTypeEnum::MACRO_COMMAND: macroCommand = dynamic_cast(selectedItem); CaretAssert(macroCommand); m_stackedWidget->setCurrentWidget(m_commandWidget); break; } } else { m_stackedWidget->setCurrentWidget(m_emptyWidget); CaretAssertMessage(0, ("Invalid StandardItemModel type=" + AString::number(selectedItem->type()))); } } else { m_stackedWidget->setCurrentWidget(m_emptyWidget); } updateMacroWidget(macro); updateCommandWidget(macroCommand); updateEditingToolButtons(); } /** * Called when macro group combo box selection is made */ void WuQMacroDialog::macroGroupComboBoxActivated(int) { WuQMacroGroup* selectedGroup = getSelectedMacroGroup(); if (selectedGroup != NULL) { QModelIndex selectedIndex; if (m_treeView->model() != selectedGroup) { /* * Model has changed, select first macro */ if (selectedGroup->getNumberOfMacros() > 0) { selectedIndex = selectedGroup->indexFromItem(selectedGroup->getMacroAtIndex(0)); } } else { selectedIndex = m_treeView->currentIndex(); } m_blockSelectionModelRowChangedFlag = true; m_treeView->setModel(selectedGroup); { /* * Need to (re)connect the selection model's row changed signal * since setModel() was called. * * From the Qt Documentation for QAbstractItemView::setSelectionModel(): * Note that, if you call setModel() after this function, the given * selectionModel will be replaced by one created by the view. */ QItemSelectionModel* selectionModel = m_treeView->selectionModel(); if (selectionModel != NULL) { /* * Use the option Qt::UniqueConnection to avoid creating * a duplicate connection */ QObject::connect(selectionModel, &QItemSelectionModel::currentRowChanged, this, &WuQMacroDialog::selectionModelRowChanged, Qt::UniqueConnection); } } m_blockSelectionModelRowChangedFlag = false; if (selectedIndex.isValid()) { m_treeView->setCurrentIndex(selectedIndex); } treeItemSelected(m_treeView->currentIndex()); } else { m_treeView->setModel(new QStandardItemModel()); treeItemSelected(QModelIndex()); } } /** * Called when selection model's row is changed * * @param current * Model index of current item * @parm previous * Model index of previous item */ void WuQMacroDialog::selectionModelRowChanged(const QModelIndex& current, const QModelIndex& /*previous*/) { if (m_blockSelectionModelRowChangedFlag) { return; } treeItemSelected(current); } /** * Update the macro widget with the given macro * * @param macro * The macro (may be NULL) */ void WuQMacroDialog::updateMacroWidget(WuQMacro* macro) { QString name; WuQMacroShortCutKeyEnum::Enum shortCutKey = WuQMacroShortCutKeyEnum::Key_None; QString text; if (macro != NULL) { name = macro->getName(); text = macro->getDescription(); shortCutKey = macro->getShortCutKey(); } if ( ! m_macroNameLineEditBlockUpdateFlag) { m_macroNameLineEdit->setText(name); } m_macroShortCutKeyComboBox->setSelectedShortCutKey(shortCutKey); if ( ! m_macroDescriptionTextEditBlockUpdateFlag) { QSignalBlocker DescriptionBlocker(m_macroDescriptionTextEdit); m_macroDescriptionTextEdit->setPlainText(text); } } /** * Update the command widget with the given macommandcro * * @param command * The command (may be NULL) */ void WuQMacroDialog::updateCommandWidget(WuQMacroCommand* command) { QString title; QString name; QString type; QString toolTip; float delay(0.0f); if (command != NULL) { title = command->text(); name = command->getObjectName(); switch (command->getCommandType()) { case WuQMacroCommandTypeEnum::CUSTOM_OPERATION: { const QString operationName = command->getCustomOperationTypeName(); type = operationName; } break; case WuQMacroCommandTypeEnum::MOUSE: { WuQMacroMouseEventInfo* mouseInfo = command->getMouseEventInfo(); CaretAssert(mouseInfo); WuQMacroMouseEventTypeEnum::Enum mouseEventType = mouseInfo->getMouseEventType(); type = WuQMacroMouseEventTypeEnum::toGuiName(mouseEventType); } break; case WuQMacroCommandTypeEnum::WIDGET: type = WuQMacroWidgetTypeEnum::toGuiName(command->getWidgetType()); break; } toolTip = command->getObjectToolTip(); delay = command->getDelayInSeconds(); } m_commandTitleLabel->setText(title); m_commandNameLabel->setText(name); m_commandTypeLabel->setText(type); QSignalBlocker delayBlocker(m_commandDelaySpinBox); m_commandDelaySpinBox->setValue(delay); if ( ! m_macroDescriptionCommandTextEditBlockUpdateFlag) { QSignalBlocker descriptionBlocker(m_commandDescriptionTextEdit); m_commandDescriptionTextEdit->setPlainText(toolTip); } /** * Update the parameter widgets */ const int32_t numParams = ((command != NULL) ? command->getNumberOfParameters() : 0); int32_t numWidgets = static_cast(m_parameterWidgets.size()); for (int32_t i = numWidgets; i < numParams; i++) { WuQMacroCommandParameterWidget* cpw = new WuQMacroCommandParameterWidget(i, m_parameterWidgetsGridLayout, this); QObject::connect(cpw, &WuQMacroCommandParameterWidget::dataChanged, this, &WuQMacroDialog::commandParamaterDataChanged); m_parameterWidgets.push_back(cpw); } const QString windowID = m_runOptionsWindowComboBox->currentText(); int32_t windowIndex = windowID.toInt(); if (windowIndex > 0) { --windowIndex; /* Range 1..N but need 0..N-1 */ } for (int32_t i = 0; i < numParams; i++) { m_parameterWidgets[i]->updateContent(windowIndex, command, command->getParameterAtIndex(i)); } numWidgets = static_cast(m_parameterWidgets.size()); for (int32_t i = numParams; i < numWidgets; i++) { m_parameterWidgets[i]->updateContent(-1, NULL, NULL); } } /** * Called when a command parameter is changed * * @param index * Index of the parameter */ void WuQMacroDialog::commandParamaterDataChanged(int) { WuQMacro* macro = getSelectedMacro(); if (macro != NULL) { WuQMacroManager::instance()->macroWasModified(macro); } updateDialogContents(); } /** * @return Pointer to selected macro group or NULL if none available. */ WuQMacroGroup* WuQMacroDialog::getSelectedMacroGroup() { const int32_t selectedGroupIndex = m_macroGroupComboBox->currentIndex(); if ((selectedGroupIndex >= 0) && (selectedGroupIndex < m_macroGroupComboBox->count())) { CaretAssertVectorIndex(m_macroGroups, selectedGroupIndex); WuQMacroGroup* group = m_macroGroups[selectedGroupIndex]; return group; } return NULL; } /** * @return Pointer to selected macro. If a macro command is selected, its parent * macro is returned (NULL if no macro is selected) */ WuQMacro* WuQMacroDialog::getSelectedMacro() { WuQMacro* macro(NULL); QStandardItem* selectedItem = getSelectedItem(); if (selectedItem != NULL) { bool validFlag(false); const WuQMacroStandardItemTypeEnum::Enum itemType = WuQMacroStandardItemTypeEnum::fromIntegerCode(selectedItem->type(), &validFlag); if (validFlag) { switch (itemType) { case WuQMacroStandardItemTypeEnum::INVALID: CaretAssertMessage(0, "Type should never be invalid"); break; case WuQMacroStandardItemTypeEnum::MACRO_COMMAND: { /* * Parent should be WuQMacro */ QStandardItem* selectedItemParent = selectedItem->parent(); CaretAssert(selectedItemParent); macro = dynamic_cast(selectedItemParent); CaretAssert(macro); } break; case WuQMacroStandardItemTypeEnum::MACRO: macro = dynamic_cast(selectedItem); CaretAssert(macro); break; } } else { CaretAssertMessage(0, ("Invalid StandardItemModel type=" + AString::number(selectedItem->type()))); } } return macro; } /** * @return Pointer to selected macro command (NULL if no macro command is selected) */ WuQMacroCommand* WuQMacroDialog::getSelectedMacroCommand() { WuQMacroCommand* macroCommand(NULL); QStandardItem* selectedItem = getSelectedItem(); if (selectedItem != NULL) { bool validFlag(false); const WuQMacroStandardItemTypeEnum::Enum itemType = WuQMacroStandardItemTypeEnum::fromIntegerCode(selectedItem->type(), &validFlag); if (validFlag) { switch (itemType) { case WuQMacroStandardItemTypeEnum::INVALID: CaretAssertMessage(0, "Type should never be invalid"); break; case WuQMacroStandardItemTypeEnum::MACRO_COMMAND: macroCommand = dynamic_cast(selectedItem); CaretAssert(macroCommand); break; case WuQMacroStandardItemTypeEnum::MACRO: break; } } else { CaretAssertMessage(0, ("Invalid StandardItemModel type=" + AString::number(selectedItem->type()))); } } return macroCommand; } /** * @return The selected item (NULL if invalid) */ QStandardItem* WuQMacroDialog::getSelectedItem() const { QModelIndex modelIndex = m_treeView->currentIndex(); if (modelIndex.isValid()) { QAbstractItemModel* abstractModel = m_treeView->model(); if (abstractModel != NULL) { QStandardItemModel* model = qobject_cast(abstractModel); if (model != NULL) { QStandardItem* item = model->itemFromIndex(modelIndex); return item; } } } return NULL; } /** * @return The selected item type */ WuQMacroStandardItemTypeEnum::Enum WuQMacroDialog::getSelectedItemType() const { WuQMacroStandardItemTypeEnum::Enum itemType = WuQMacroStandardItemTypeEnum::INVALID; QStandardItem* item = getSelectedItem(); if (item != NULL) { bool validFlag(false); itemType = WuQMacroStandardItemTypeEnum::fromIntegerCode(item->type(), &validFlag); } return itemType; } /** * Called to pause/continue a macro */ void WuQMacroDialog::pauseContinueMacroToolButtonClicked() { WuQMacroManager::instance()->pauseContinueMacro(); updateEditingToolButtons(); } /** * Called when run button is clicked */ void WuQMacroDialog::runMacroToolButtonClicked() { runSelectedMacro(NULL, NULL); } /** * Called when run button is clicked * * @param macroCommandToStartAt * Macro command at which execution should begin. If NULL, start * with the first command in the macro * @param macroCommandToStopAfter * Macro command that the executor may stop after, depending upon options */ void WuQMacroDialog::runSelectedMacro(const WuQMacroCommand* macroCommandToStartAt, const WuQMacroCommand* macroCommandToStopAfter) { switch (WuQMacroManager::instance()->getMode()) { case WuQMacroModeEnum::OFF: break; case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: case WuQMacroModeEnum::RECORDING_NEW_MACRO: { QMessageBox::critical(m_runMacroToolButton, "Error", "A macro is being recorded. Finish recording of macro.", QMessageBox::Ok, QMessageBox::NoButton); return; } break; case WuQMacroModeEnum::RUNNING: break; } WuQMacro* macro = getSelectedMacro(); if (macro == NULL) { return; } if (macro->getNumberOfMacroCommands() <= 0) { QMessageBox::critical(m_runMacroToolButton, "Error", "Macro does not contain any commands", QMessageBox::Ok, QMessageBox::NoButton); return; } QWidget* window = getWindow(); /* * While macro runs, edit buttons are disabled */ m_macroIsRunningFlag = true; updateEditingToolButtons(); QApplication::processEvents(); ElapsedTimer timer; timer.start(); WuQMacro* lastMacroRun = WuQMacroManager::instance()->runMacro(window, macro, macroCommandToStartAt, macroCommandToStopAfter); // may use this later when testing std::cout << "Time to run macro: " << timer.getElapsedTimeSeconds() << std::endl; m_macroIsRunningFlag = false; if (lastMacroRun != getSelectedMacro()) { QModelIndex modelIndex = macro->index(); m_treeView->setCurrentIndex(modelIndex); treeItemSelected(modelIndex); } updateEditingToolButtons(); } /** * @return the parent main window */ QWidget* WuQMacroDialog::getWindow() { const QString windowID = m_runOptionsWindowComboBox->currentText(); QWidget* window = WuQMacroManager::instance()->getMainWindowWithIdentifier(windowID); if (window == NULL) { window = this; while (window != NULL) { if (qobject_cast(window) != NULL) { break; } else { window = window->parentWidget(); } } if (window == NULL) { window = parentWidget(); } } return window; } /** * Called when stop button is clicked */ void WuQMacroDialog::stopMacroToolButtonClicked() { /* * If recording, STOP button stops recording */ switch (WuQMacroManager::instance()->getMode()) { case WuQMacroModeEnum::OFF: break; case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: case WuQMacroModeEnum::RECORDING_NEW_MACRO: recordMacroToolButtonClicked(); return; break; case WuQMacroModeEnum::RUNNING: break; } WuQMacroManager::instance()->stopMacro(); updateEditingToolButtons(); } /** * Called when record button is clicked */ void WuQMacroDialog::recordMacroToolButtonClicked() { bool startRecordingValid(false); bool stopRecordingValid(false); switch (WuQMacroManager::instance()->getMode()) { case WuQMacroModeEnum::OFF: startRecordingValid = true; break; case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: case WuQMacroModeEnum::RECORDING_NEW_MACRO: stopRecordingValid = true; break; case WuQMacroModeEnum::RUNNING: break; } if (startRecordingValid) { QMenu menu(m_editingInsertToolButton); QAction* newCommandAction = menu.addAction("Record and Insert New Commands Below", this, &WuQMacroDialog::insertMenuRecordNewMacroCommandSelected); newCommandAction->setEnabled(getSelectedMacro() != NULL); menu.addSeparator(); QAction* newMacroAction = menu.addAction("Record and Insert New Macro Below...", this, &WuQMacroDialog::recordAndInsertNewMacroSelected); newMacroAction->setEnabled(getSelectedMacroGroup() != NULL); menu.exec(m_recordMacroToolButton->mapToGlobal(QPoint(0, 0))); } else if (stopRecordingValid) { stopRecordingSelected(); } } /** * Called when import item is selected */ void WuQMacroDialog::importMacroGroupActionTriggered() { WuQMacroGroup* macroGroup = getSelectedMacroGroup(); if (macroGroup != NULL) { if (WuQMacroManager::instance()->importMacros(m_macroGroupToolButton, macroGroup)) { updateDialogContents(); } } } /** * Called when export item is selected */ void WuQMacroDialog::exportMacroGroupActionTriggered() { WuQMacroGroup* macroGroup = getSelectedMacroGroup(); WuQMacro* macro = getSelectedMacro(); if (macro != NULL) { if (WuQMacroManager::instance()->exportMacros(m_macroGroupToolButton, macroGroup, macro)) { updateDialogContents(); } } } /** * Called when macro command description text edit is changed */ void WuQMacroDialog::macroCommandDescriptionTextEditChanged() { WuQMacroCommand* command = getSelectedMacroCommand(); if (command != NULL) { command->setObjectToolTip(m_commandDescriptionTextEdit->toPlainText()); m_macroDescriptionCommandTextEditBlockUpdateFlag = true; WuQMacroManager::instance()->macroWasModified(getSelectedMacro()); m_macroDescriptionCommandTextEditBlockUpdateFlag = false; } } /** * Called when macro commands delay value is changed * * @param value * New value */ void WuQMacroDialog::macroCommandDelaySpinBoxValueChanged(double value) { WuQMacroCommand* command = getSelectedMacroCommand(); CaretAssert(command); command->setDelayInSeconds(value); WuQMacro* macro = getSelectedMacro(); if (macro != NULL) { WuQMacroManager::instance()->macroWasModified(macro); } } /** * @return a horizontal line */ QWidget* WuQMacroDialog::createHorizontalLine() const { QFrame* horizontalLine = new QFrame(); horizontalLine->setMidLineWidth(1); horizontalLine->setLineWidth(1); horizontalLine->setFrameStyle(QFrame::HLine | QFrame::Sunken); return horizontalLine; } /** * Called when macro group tool button is clicked */ void WuQMacroDialog::macroGroupToolButtonClicked() { QMenu* menu = new QMenu(this); QAction* importAction = menu->addAction("Import..."); QObject::connect(importAction, &QAction::triggered, this, &WuQMacroDialog::importMacroGroupActionTriggered); QAction* exportAction = menu->addAction("Export..."); QObject::connect(exportAction, &QAction::triggered, this, &WuQMacroDialog::exportMacroGroupActionTriggered); menu->exec(mapToGlobal(m_macroGroupToolButton->pos())); delete menu; } /** * Called when macro group reset tool button is clicked */ void WuQMacroDialog::macroGroupResetToolButtonClicked() { /* * Save expanded status of selected macro */ bool expandedFlag = false; WuQMacro* selectedMacro = getSelectedMacro(); if (selectedMacro != NULL) { QModelIndex modelIndex = selectedMacro->index(); if (modelIndex.isValid()) { expandedFlag = m_treeView->isExpanded(modelIndex); } } /* * If expanded, a command may be selected */ int32_t selectedCommandIndex = -1; if (expandedFlag) { WuQMacroCommand* selectedCommand = getSelectedMacroCommand(); if (selectedCommand != NULL) { if (selectedMacro != NULL) { selectedCommandIndex = selectedMacro->getIndexOfMacroCommand(selectedCommand); } } } /* * Reload the macro */ WuQMacro* macro = WuQMacroManager::instance()->resetMacro(getWindow(), getSelectedMacro()); updateDialogContents(); if (macro != NULL) { /* * Restore expanded status of macro */ QModelIndex modelIndex = macro->index(); treeItemSelected(macro->index()); m_treeView->setExpanded(modelIndex, expandedFlag); /* * May restore selection of command */ if (selectedCommandIndex >= 0) { if (selectedCommandIndex < macro->getNumberOfMacroCommands()) { modelIndex = macro->getMacroCommandAtIndex(selectedCommandIndex)->index(); } } /* * Select macro or command that was selected before reset */ m_treeView->setCurrentIndex(modelIndex); } updateDialogContents(); } /** * Called when editing move up button clicked */ void WuQMacroDialog::editingMoveUpToolButtonClicked() { WuQMacroGroup* macroGroup = getSelectedMacroGroup(); WuQMacro* macro = getSelectedMacro(); WuQMacroCommand* command = getSelectedMacroCommand(); switch (getSelectedItemType()) { case WuQMacroStandardItemTypeEnum::INVALID: break; case WuQMacroStandardItemTypeEnum::MACRO: if (macroGroup != NULL) { if (macro != NULL) { macroGroup->moveMacroUp(macro); m_treeView->setCurrentIndex(macro->index()); treeItemSelected(macro->index()); } } break; case WuQMacroStandardItemTypeEnum::MACRO_COMMAND: if ((macro != NULL) && (command != NULL)) { macro->moveMacroCommandUp(command); m_treeView->setCurrentIndex(command->index()); treeItemSelected(command->index()); } break; } } /** * Called when editing move down button clicked */ void WuQMacroDialog::editingMoveDownToolButtonClicked() { WuQMacroGroup* macroGroup = getSelectedMacroGroup(); WuQMacro* macro = getSelectedMacro(); WuQMacroCommand* command = getSelectedMacroCommand(); switch (getSelectedItemType()) { case WuQMacroStandardItemTypeEnum::INVALID: break; case WuQMacroStandardItemTypeEnum::MACRO: if (macroGroup != NULL) { if (macro != NULL) { macroGroup->moveMacroDown(macro); m_treeView->setCurrentIndex(macro->index()); treeItemSelected(macro->index()); } } break; case WuQMacroStandardItemTypeEnum::MACRO_COMMAND: if ((macro != NULL) && (command != NULL)) { macro->moveMacroCommandDown(command); m_treeView->setCurrentIndex(command->index()); treeItemSelected(command->index()); } break; } } /** * Called when editing delete button clicked */ void WuQMacroDialog::editingDeleteToolButtonClicked() { WuQMacroGroup* macroGroup = getSelectedMacroGroup(); WuQMacro* macro = getSelectedMacro(); WuQMacroCommand* command = getSelectedMacroCommand(); switch (getSelectedItemType()) { case WuQMacroStandardItemTypeEnum::INVALID: break; case WuQMacroStandardItemTypeEnum::MACRO: if ((macroGroup != NULL) && (macro != NULL)) { int32_t macroIndex = macroGroup->getIndexOfMacro(macro); if (WuQMacroManager::instance()->deleteMacro(m_editingDeleteToolButton, macroGroup, macro)) { updateDialogContents(); CaretAssert(macroIndex >= 0); if (macroIndex >= macroGroup->getNumberOfMacros()) { macroIndex = macroGroup->getNumberOfMacros() - 1; } if ((macroIndex >= 0) && (macroIndex < macroGroup->getNumberOfMacros())) { QModelIndex modelIndex = macroGroup->getMacroAtIndex(macroIndex)->index(); m_treeView->setCurrentIndex(modelIndex); treeItemSelected(modelIndex); } } } break; case WuQMacroStandardItemTypeEnum::MACRO_COMMAND: if ((macro != NULL) && (command != NULL)) { if (WuQMacroManager::instance()->deleteMacroCommand(m_editingDeleteToolButton, macroGroup, macro, command)) { updateDialogContents(); } } break; } } /** * Called when editing insert button clicked */ void WuQMacroDialog::editingInsertToolButtonClicked() { WuQMacroGroup* macroGroup = getSelectedMacroGroup(); if (macroGroup == NULL) { return; } const WuQMacro* selectedMacro = getSelectedMacro(); WuQMacroManager* macroManager = WuQMacroManager::instance(); /* * Copy is valid when there is at least one macro, in any macro group * and the macro is not the selected macro */ bool copyValidFlag(false); const std::vector allGroups = macroManager->getAllMacroGroups(); for (const auto mg : allGroups) { const int32_t nm = mg->getNumberOfMacros(); for (int32_t i = 0; i < nm; i++) { if (mg->getMacroAtIndex(i) != selectedMacro) { copyValidFlag = true; } } } bool insertMacroValidFlag(false); bool insertMacroCommandValidFlag(false); switch (getSelectedItemType()) { case WuQMacroStandardItemTypeEnum::INVALID: insertMacroValidFlag = true; break; case WuQMacroStandardItemTypeEnum::MACRO: insertMacroValidFlag = true; insertMacroCommandValidFlag = true; break; case WuQMacroStandardItemTypeEnum::MACRO_COMMAND: insertMacroValidFlag = true; insertMacroCommandValidFlag = true; break; } switch (macroManager->getMode()) { case WuQMacroModeEnum::OFF: break; case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: case WuQMacroModeEnum::RECORDING_NEW_MACRO: insertMacroValidFlag = false; copyValidFlag = false; insertMacroCommandValidFlag = false; break; case WuQMacroModeEnum::RUNNING: insertMacroValidFlag = false; copyValidFlag = false; insertMacroCommandValidFlag = false; break; } const bool showRecordItemsFlag(false); QMenu menu(m_editingInsertToolButton); /* * Macro command items */ QAction* insertNewCommandAction = menu.addAction("Insert New Command Below...", this, &WuQMacroDialog::insertMenuNewMacroCommandSelected); insertNewCommandAction->setEnabled(insertMacroCommandValidFlag); if (showRecordItemsFlag) { QAction* insertRecordNewCommandAction = menu.addAction("Record and Insert New Commands Below", this, &WuQMacroDialog::insertMenuRecordNewMacroCommandSelected); insertRecordNewCommandAction->setEnabled(insertMacroCommandValidFlag); } /* * Macro items */ if (menu.actions().count() > 0) { menu.addSeparator(); } QAction* copyMacroAction = menu.addAction("Copy and Insert Macro Below...", this, &WuQMacroDialog::insertMenuCopyMacroSelected); copyMacroAction->setEnabled(copyValidFlag && insertMacroValidFlag); QAction* insertMenuAction = menu.addAction("Insert New Macro Below...", this, &WuQMacroDialog::insertMenuNewMacroSelected); insertMenuAction->setEnabled(insertMacroValidFlag); if (showRecordItemsFlag) { QAction* recordNewMacroAction = menu.addAction("Record and Insert Macro Below...", this, &WuQMacroDialog::recordAndInsertNewMacroSelected); recordNewMacroAction->setEnabled(insertMacroValidFlag); } menu.exec(m_editingInsertToolButton->mapToGlobal(QPoint(0, 0))); } /** * Called to stop recording */ void WuQMacroDialog::stopRecordingSelected() { WuQMacroManager::instance()->stopRecordingNewMacro(); } /** * Called when copy and insert macro menu item is selected */ void WuQMacroDialog::insertMenuCopyMacroSelected() { WuQMacroCopyDialog dialog(this); if (dialog.exec() == WuQMacroCopyDialog::Accepted) { const WuQMacro* macro = dialog.getMacroToCopy(); if (macro != NULL) { WuQMacro* newMacro = new WuQMacro(*macro); newMacro->setName("Copy of " + macro->getName()); insertNewMacro(newMacro); } } } /** * Called when copy and record and insert macro menu item is selected */ void WuQMacroDialog::recordAndInsertNewMacroSelected() { WuQMacroGroup* macroGroup = getSelectedMacroGroup(); CaretAssert(macroGroup); WuQMacro* newMacro = WuQMacroManager::instance()->startRecordingNewMacro(m_editingInsertToolButton, macroGroup, getSelectedMacro()); if (newMacro != NULL) { const QModelIndex modelIndex = newMacro->index(); m_treeView->setCurrentIndex(modelIndex); treeItemSelected(modelIndex); } } /** * Insert a new macro * * @param macro * Macro to insert, must be valid */ void WuQMacroDialog::insertNewMacro(WuQMacro* macro) { CaretAssert(macro); const WuQMacro* selectedMacro = getSelectedMacro(); WuQMacroGroup* macroGroup = getSelectedMacroGroup(); CaretAssert(macroGroup); if (selectedMacro != NULL) { const int32_t index = macroGroup->getIndexOfMacro(selectedMacro); macroGroup->insertMacroAtIndex(index + 1, macro); } else { macroGroup->addMacro(macro); } updateDialogContents(); QModelIndex selectedIndex = macroGroup->indexFromItem(macro); if (selectedIndex.isValid()) { m_treeView->setCurrentIndex(selectedIndex); updateDialogContents(); } WuQMacroManager::instance()->macroWasModified(macro); } /** * Called when insert new macro menu item selected */ void WuQMacroDialog::insertMenuNewMacroSelected() { bool okFlag(false); const QString defaultName = WuQMacroManager::instance()->getNewMacroDefaultName(); const QString macroName = QInputDialog::getText(m_editingInsertToolButton, "Create Macro", "New Macro Name", QLineEdit::Normal, defaultName, &okFlag); if (okFlag) { if ( ! macroName.isEmpty()) { WuQMacro* macro = new WuQMacro(); macro->setName(macroName); insertNewMacro(macro); } } } /** * Called when insert new macro command menu item selected */ void WuQMacroDialog::insertMenuNewMacroCommandSelected() { WuQMacroNewCommandSelectionDialog dialog(this); QObject::connect(&dialog, &WuQMacroNewCommandSelectionDialog::signalNewMacroCommandCreated, this, &WuQMacroDialog::addNewMacroCommand); if (dialog.exec() == WuQMacroNewCommandSelectionDialog::Accepted) { } } /** * Called when insert and record a new macro command menu item selected */ void WuQMacroDialog::insertMenuRecordNewMacroCommandSelected() { WuQMacro* macro = getSelectedMacro(); if (macro == NULL) { QMessageBox::warning(m_editingInsertToolButton, "Error", "No macro is selected for recording new commands"); return; } WuQMacroManager::instance()->startRecordingNewCommandInsertion(macro, getSelectedMacroCommand()); } /** * Select the given command (if it is not NULL) or the macro (if it is not NULL) * * @param macro * The macro * @param command * The macro command */ void WuQMacroDialog::selectMacroCommand(const WuQMacro* macro, const WuQMacroCommand* command) { QModelIndex selectedIndex; if (command != NULL) { selectedIndex = command->index(); } else if (macro != NULL) { if (macro != NULL) { m_treeView->setExpanded(macro->index(), true); } selectedIndex = macro->index(); } if (selectedIndex.isValid()) { m_treeView->setCurrentIndex(selectedIndex); } } /** * Add a new macro command */ void WuQMacroDialog::addNewMacroCommand(WuQMacroCommand* command) { if (command == NULL) { return; } WuQMacro* macro(NULL); switch (getSelectedItemType()) { case WuQMacroStandardItemTypeEnum::INVALID: CaretAssert(0); break; case WuQMacroStandardItemTypeEnum::MACRO: { macro = getSelectedMacro(); CaretAssert(macro); macro->insertMacroCommandAtIndex(0, command); } break; case WuQMacroStandardItemTypeEnum::MACRO_COMMAND: { macro = getSelectedMacro(); CaretAssert(macro); const WuQMacroCommand* selectedCommand = getSelectedMacroCommand(); CaretAssert(selectedCommand); const int32_t selectedIndex = macro->getIndexOfMacroCommand(selectedCommand); macro->insertMacroCommandAtIndex(selectedIndex + 1, command); } } WuQMacroGroup* selectedGroup = getSelectedMacroGroup(); CaretAssert(selectedGroup); QModelIndex selectedIndex = selectedGroup->indexFromItem(command); m_treeView->setCurrentIndex(selectedIndex); updateDialogContents(); if (macro != NULL) { WuQMacroManager::instance()->macroWasModified(macro); } } /** * Update editing buttons after item selected * in macro/command tree view */ void WuQMacroDialog::updateEditingToolButtons() { WuQMacroGroup* macroGroup = getSelectedMacroGroup(); WuQMacro* macro = getSelectedMacro(); WuQMacroCommand* command = getSelectedMacroCommand(); bool resetValid(false); bool runValid(false); bool stopValid(false); bool insertValid(false); bool deleteValid(false); bool moveUpValid(false); bool moveDownValid(false); bool pauseValid(false); bool pauseChecked(false); bool recordValid(false); if (m_macroIsRunningFlag) { pauseValid = true; switch (WuQMacroManager::instance()->getMacroExecutorMonitor()->getMode()) { case WuQMacroExecutorMonitor::Mode::PAUSE: pauseChecked = true; break; case WuQMacroExecutorMonitor::Mode::RUN: break; case WuQMacroExecutorMonitor::Mode::STOP: break; } stopValid = true; } else { insertValid = (macroGroup != NULL); recordValid = (macroGroup != NULL); resetValid = (macroGroup != NULL); switch (getSelectedItemType()) { case WuQMacroStandardItemTypeEnum::INVALID: break; case WuQMacroStandardItemTypeEnum::MACRO: if (macroGroup != NULL) { if (macro != NULL) { const int32_t macroIndex = macroGroup->getIndexOfMacro(macro); deleteValid = true; moveUpValid = (macroIndex > 0); moveDownValid = (macroIndex < (macroGroup->getNumberOfMacros() - 1)); runValid = true; } } break; case WuQMacroStandardItemTypeEnum::MACRO_COMMAND: { if ((macro != NULL) && (command != NULL)) { const int32_t commandIndex = macro->getIndexOfMacroCommand(command); deleteValid = true; moveUpValid = (commandIndex > 0); moveDownValid = (commandIndex < (macro->getNumberOfMacroCommands() - 1)); runValid = true; } } break; } } bool recordingFlag(false); switch (WuQMacroManager::instance()->getMode()) { case WuQMacroModeEnum::OFF: break; case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: recordingFlag = true; break; case WuQMacroModeEnum::RECORDING_NEW_MACRO: recordingFlag = true; break; case WuQMacroModeEnum::RUNNING: break; } if (recordingFlag) { m_recordMacroToolButton->setIcon(m_recordMacroToolButtonIconOn); runValid = false; stopValid = true; } else { m_recordMacroToolButton->setIcon(m_recordMacroToolButtonIconOff); } m_pauseMacroToolButton->setEnabled(pauseValid); m_pauseMacroToolButton->setChecked(pauseChecked); m_resetMacroGroupToolButton->setEnabled(resetValid); m_macroGroupToolButton->setEnabled(resetValid); m_runMacroToolButton->setEnabled(runValid); m_stopMacroToolButton->setEnabled(stopValid); m_recordMacroToolButton->setEnabled(recordValid); m_editingDeleteToolButton->setEnabled(deleteValid); m_editingInsertToolButton->setEnabled(insertValid); m_editingMoveDownToolButton->setEnabled(moveDownValid); m_editingMoveUpToolButton->setEnabled(moveUpValid); } /** * Create a pixmap for the given editing tool button * * @param editButton * The edit button identifier * @return * Pixmap for the given button */ QPixmap WuQMacroDialog::createEditingToolButtonPixmap(const QWidget* widget, const EditButton editButton) { CaretAssert(widget); const qreal pixmapSize = 22.0; const qreal maxValue = pixmapSize / 2.0 - 1.0; const qreal arrowTip = maxValue * (2.0 / 3.0); uint32_t pixmapOptions(static_cast(WuQtUtilities::PixMapCreationOptions::TransparentBackground)); switch (editButton) { case EditButton::DELETER: break; case EditButton::INSERTER: break; case EditButton::MOVE_DOWN: break; case EditButton::MOVE_UP: break; case EditButton::PAUSE: break; case EditButton::RECORD_OFF: break; case EditButton::RECORD_ON: /* allow background */ pixmapOptions = 0; break; case EditButton::RESET: /* allow background */ pixmapOptions = 0; break; case EditButton::RUN: /* allow background */ pixmapOptions = 0; break; case EditButton::STOP: /* allow background */ pixmapOptions = 0; break; } QPixmap pixmap(static_cast(pixmapSize), static_cast(pixmapSize)); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginCenter(widget, pixmap, pixmapOptions); QPen pen(painter->pen()); pen.setWidth(3); painter->setPen(pen); switch (editButton) { case EditButton::DELETER: /* * 'X' symbol */ pen.setColor(Qt::red); painter->setPen(pen); painter->drawLine(QPointF(-maxValue, maxValue), QPointF(maxValue, -maxValue)); painter->drawLine(QPointF(-maxValue, -maxValue), QPointF(maxValue, maxValue)); break; case EditButton::INSERTER: /* * Plus symbol */ painter->drawLine(QPointF(0, maxValue), QPointF(0, -maxValue)); painter->drawLine(QPointF(-maxValue, 0), QPointF(maxValue, 0)); break; case EditButton::MOVE_DOWN: /* * Down arrow */ painter->drawLine(QPointF(0, maxValue), QPointF(0, -maxValue)); painter->drawLine(QPointF(0, -maxValue), QPointF(arrowTip, -maxValue + arrowTip)); painter->drawLine(QPointF(0, -maxValue), QPointF(-arrowTip, -maxValue + arrowTip)); break; case EditButton::MOVE_UP: /* * Up arrow */ painter->drawLine(QPointF(0, maxValue), QPointF(0, -maxValue)); painter->drawLine(QPointF(0, maxValue), QPointF(arrowTip, maxValue - arrowTip)); painter->drawLine(QPointF(0, maxValue), QPointF(-arrowTip, maxValue - arrowTip)); break; case EditButton::PAUSE: { const qreal x = maxValue / 3; const qreal y = maxValue * 0.667; /* * Parallel vertical lines */ painter->drawLine(QPointF(-x, y), QPointF(-x, -y)); painter->drawLine(QPointF( x, y), QPointF( x, -y)); } break; case EditButton::RECORD_OFF: { painter->setPen(Qt::red); painter->drawEllipse(QPointF(0, 0), maxValue, maxValue); } break; case EditButton::RECORD_ON: { painter->setPen(Qt::red); painter->setBrush(Qt::red); painter->drawEllipse(QPointF(0, 0), maxValue, maxValue); } break; case EditButton::RESET: { QPen pen = painter->pen(); pen.setWidth(2); painter->setPen(pen); /* * From drawArc() documentation * Zero is at 3 o'clock * Units are 1/16th of a degree * Positive is counter-clockwise * BUT perhaps due to us transforming coordinate system positive is clockwise */ const int sz(4); const int widthHeight(maxValue * 2 - sz); QRect rectangle(-maxValue, -maxValue, widthHeight, widthHeight); const int startAngle(0); const int spanAngle(270 * 16); painter->drawArc(rectangle, startAngle, spanAngle); const int ts(sz + 2); const int x(-maxValue + widthHeight/2); const int y(-maxValue + widthHeight); QPoint trianglePoints[3] = { { x, y + ts }, { x + ts, y }, { x, y - ts } }; painter->setBrush(pen.color()); painter->drawPolygon(trianglePoints, 3); } break; case EditButton::RUN: { /* * Triangle */ const qreal y = maxValue * 0.85; painter->setBrush(pen.color()); const qreal p = pixmapSize / 3; const QPointF points[3] = { QPointF(-p, -y), QPointF( p, 0.0), QPointF(-p, y) }; painter->drawConvexPolygon(points, 3); } break; case EditButton::STOP: { /* * Square */ painter->setBrush(pen.color()); const qreal a = maxValue * 0.85; const QPointF points[4] = { QPointF(-a, -a), QPointF( a, -a), QPointF( a, a), QPointF(-a, a) }; painter->drawConvexPolygon(points, 4); } break; } return pixmap; } connectome-workbench-1.4.2/src/GuiQt/WuQMacroDialog.h000066400000000000000000000217101360521144700224430ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_DIALOG_H__ #define __WU_Q_MACRO_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "WuQMacroCommandParameter.h" #include "WuQMacroShortCutKeyEnum.h" #include "WuQMacroStandardItemTypeEnum.h" class QAbstractButton; class QCheckBox; class QComboBox; class QDialogButtonBox; class QDoubleSpinBox; class QGridLayout; class QLabel; class QLineEdit; class QMenu; class QPlainTextEdit; class QStackedWidget; class QStandardItem; class QTreeView; class QToolButton; namespace caret { class CommandParameterWidget; class WuQMacro; class WuQMacroCommand; class WuQMacroCommandParameterWidget; class WuQMacroGroup; class WuQMacroShortCutKeyComboBox; class WuQMacroDialog : public QDialog { Q_OBJECT public: WuQMacroDialog(QWidget* parent = 0); virtual ~WuQMacroDialog(); WuQMacroDialog(const WuQMacroDialog&) = delete; WuQMacroDialog& operator=(const WuQMacroDialog&) = delete; void updateDialogContents(); void restorePositionAndSize(); // ADD_NEW_METHODS_HERE public slots: void selectMacroCommand(const WuQMacro* macro, const WuQMacroCommand* command); private slots: void treeViewItemClicked(const QModelIndex& modelIndex); void treeViewCustomContextMenuRequested(const QPoint& pos); void runOnlySelectedCommandMenuItemSelected(); void runAndStartWithSelectedCommandMenuItemSelected(); void runAndStartWithNoDelayDurationSelectedCommandMenuItemSelected(); void runAndStopAfterSelectedCommandMenuItemSelected(); void runAndStopAfterWithNoDelayDurationSelectedCommandMenuItemSelected(); void macroGroupComboBoxActivated(int); void buttonBoxButtonClicked(QAbstractButton* button); void importMacroGroupActionTriggered(); void exportMacroGroupActionTriggered(); void macroGroupToolButtonClicked(); void macroGroupResetToolButtonClicked(); void macroNameLineEditTextEdited(const QString& text); void macroDescriptionTextEditChanged(); void macroShortCutKeySelected(const WuQMacroShortCutKeyEnum::Enum); void runOptionMoveMouseCheckBoxClicked(bool); void runOptionLoopCheckBoxClicked(bool); void runOptionRecordMovieCheckBoxClicked(bool); void runOptionCreateMovieCheckBoxClicked(bool); void updateCreateMovieCheckBox(); void runOptionIgnoreDelaysAndDurationsCheckBoxClicked(bool); void editingMoveUpToolButtonClicked(); void editingMoveDownToolButtonClicked(); void editingDeleteToolButtonClicked(); void editingInsertToolButtonClicked(); void pauseContinueMacroToolButtonClicked(); void runMacroToolButtonClicked(); void stopMacroToolButtonClicked(); void recordMacroToolButtonClicked(); void macroCommandDelaySpinBoxValueChanged(double); void macroCommandDescriptionTextEditChanged(); void commandParamaterDataChanged(int); void insertMenuCopyMacroSelected(); void recordAndInsertNewMacroSelected(); void insertMenuNewMacroSelected(); void insertMenuNewMacroCommandSelected(); void insertMenuRecordNewMacroCommandSelected(); void stopRecordingSelected(); void addNewMacroCommand(WuQMacroCommand* command); void selectionModelRowChanged(const QModelIndex& current, const QModelIndex& previous); protected: virtual void closeEvent(QCloseEvent* event) override; private: enum class ValueIndex { ONE, TWO }; enum class EditButton { DELETER, /* "DELETE" does not compile on an operating system */ INSERTER, MOVE_DOWN, MOVE_UP, PAUSE, RECORD_OFF, RECORD_ON, RESET, RUN, STOP }; QWidget* createMacroAndCommandSelectionWidget(); QWidget* createRunOptionsWidget(); QWidget* createMacroDisplayWidget(); QWidget* createCommandDisplayWidget(); void updateMacroWidget(WuQMacro* macro); void updateCommandWidget(WuQMacroCommand* command); WuQMacroGroup* getSelectedMacroGroup(); WuQMacro* getSelectedMacro(); WuQMacroCommand* getSelectedMacroCommand(); WuQMacroStandardItemTypeEnum::Enum getSelectedItemType() const; QStandardItem* getSelectedItem() const; QWidget* createHorizontalLine() const; QWidget* createMacroRunAndEditingToolButtons(); QPixmap createEditingToolButtonPixmap(const QWidget* widget, const EditButton editButton); void updateEditingToolButtons(); void treeItemSelected(const QModelIndex& modelIndex); void insertNewMacro(WuQMacro* macro); QWidget* getWindow(); void runSelectedMacro(const WuQMacroCommand* macroCommandToStartAt, const WuQMacroCommand* macroCommandToStopAfter); std::vector m_macroGroups; QComboBox* m_macroGroupComboBox; QToolButton* m_resetMacroGroupToolButton; QToolButton* m_macroGroupToolButton; QTreeView* m_treeView; QLineEdit* m_macroNameLineEdit; bool m_macroNameLineEditBlockUpdateFlag = false; WuQMacroShortCutKeyComboBox* m_macroShortCutKeyComboBox; QPlainTextEdit* m_macroDescriptionTextEdit; bool m_macroDescriptionTextEditBlockUpdateFlag = false; QWidget* m_macroWidget; QWidget* m_commandWidget; QWidget* m_emptyWidget; QStackedWidget* m_stackedWidget; QDialogButtonBox* m_dialogButtonBox; QComboBox* m_runOptionsWindowComboBox; QCheckBox* m_runOptionLoopCheckBox; QCheckBox* m_runOptionMoveMouseCheckBox; QCheckBox* m_runOptionRecordMovieWhileMacroRunsCheckBox; QCheckBox* m_runOptionCreateMovieAfterMacroRunsCheckBox; QCheckBox* m_ignoreDelaysAndDurationsCheckBox; QLabel* m_commandTitleLabel; QLabel* m_commandTypeLabel; QLabel* m_commandNameLabel; QDoubleSpinBox* m_commandDelaySpinBox; QPlainTextEdit* m_commandDescriptionTextEdit; bool m_macroDescriptionCommandTextEditBlockUpdateFlag = false; std::vector m_parameterWidgets; QGridLayout* m_parameterWidgetsGridLayout; QToolButton* m_pauseMacroToolButton; QToolButton* m_runMacroToolButton; QToolButton* m_stopMacroToolButton; QToolButton* m_recordMacroToolButton; QIcon m_recordMacroToolButtonIconOff; QIcon m_recordMacroToolButtonIconOn; QToolButton* m_editingMoveUpToolButton; QToolButton* m_editingMoveDownToolButton; QToolButton* m_editingDeleteToolButton; QToolButton* m_editingInsertToolButton; bool m_macroIsRunningFlag = false; bool m_blockSelectionModelRowChangedFlag = false; static QByteArray s_previousDialogGeometry; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_MACRO_DIALOG_DECLARE__ QByteArray WuQMacroDialog::s_previousDialogGeometry; #endif // __WU_Q_MACRO_DIALOG_DECLARE__ } // namespace #endif //__WU_Q_MACRO_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/WuQMacroExecutor.cxx000066400000000000000000001674241360521144700234320ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_EXECUTOR_DECLARE__ #include "WuQMacroExecutor.h" #undef __WU_Q_MACRO_EXECUTOR_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "WuQMacro.h" #include "WuQMacroCommand.h" #include "WuQMacroCommandParameter.h" #include "WuQMacroExecutorMonitor.h" #include "WuQMacroManager.h" #include "WuQMacroMouseEventInfo.h" #include "WuQMacroMouseEventWidgetInterface.h" #include "WuQMacroSignalEmitter.h" #include "WuQMacroWidgetAction.h" using namespace caret; /** * \class caret::WuQMacroExecutor * \brief Executes a macro * \ingroup WuQMacro */ /** * Constructor. */ WuQMacroExecutor::WuQMacroExecutor() : QObject() { } /** * Destructor. */ WuQMacroExecutor::~WuQMacroExecutor() { } /** * Move the mouse to the tab bar's tab with the given tab index * * @param tabBar * The tab bar * @param tabIndex * Index of the tab */ void WuQMacroExecutor::moveMouseToTabBarTab(QTabBar* tabBar, const int32_t tabIndex) const { QRect tabRect = tabBar->tabRect(tabIndex); if (tabRect.isNull()) { moveMouseToWidget(tabBar); } else { moveMouseToWidgetImplementation(tabBar, -1, -1, &tabRect, true); } } /** * Move the mouse around the given widget * * @param moveToObject * Object to where mouse should be moved * @param highlightFlag * If true, highlight mouse location by moving mouse in * a circular orientation */ void WuQMacroExecutor::moveMouseToWidget(QObject* moveToObject, const bool highlightFlag) const { moveMouseToWidgetImplementation(moveToObject, -1, -1, NULL, highlightFlag); } /** * Move the mouse to and around the given widget * at the given X/Y * * @param moveToObject * Object to where mouse should be moved * @param x * Move to this X in widget * @param y * Move to this Y in widget * @param highlightFlag * If true, highlight mouse location by moving mouse in * a circular orientation */ void WuQMacroExecutor::moveMouseToWidgetXY(QObject* moveToObject, const int x, const int y, const bool highlightFlag) const { moveMouseToWidgetImplementation(moveToObject, x, y, NULL, highlightFlag); } /** * Move the mouse around the given widget. If the given X/Y are * non-negative, mouse is moved to that location instead of center * of widget * * @param moveToObject * Object to where mouse should be moved * @param x * Move to this X in widget * @param y * Move to this Y in widget * @param objectRect * Optional, if not NULL, rectangle of object used for positioning mouse * @param highlightFlag * If true, highlight mouse location by moving mouse in * a circular orientation */ void WuQMacroExecutor::moveMouseToWidgetImplementation(QObject* moveToObject, const int x, const int y, const QRect* objectRect, const bool highlightFlag) const { if ( ! m_runOptions.isShowMouseMovement()) { return; } CaretAssert(moveToObject); const QString objectName = moveToObject->objectName(); /* * Object may not be a widget so find ancestor * that is a widget */ QWidget* moveToWidget(NULL); while ((moveToWidget == NULL) && (moveToObject != NULL)) { moveToWidget = qobject_cast(moveToObject); if (moveToWidget == NULL) { moveToObject = moveToObject->parent(); } } if (moveToWidget == NULL) { return; } /* * Test visibility of widget. * Note: Cannot use isHidden(), see Qt documentation. */ if ( ! moveToWidget->isVisible()) { return; } CaretAssert(moveToWidget); const QRect widgetRect = ((objectRect != NULL) ? *objectRect : moveToWidget->rect()); QPoint widgetPoint = widgetRect.center(); if ((x >= 0) && (y >= 0)) { widgetPoint.setX(x); widgetPoint.setY(y); } const QPoint windowPoint = moveToWidget->mapToGlobal(widgetPoint); QCursor::setPos(windowPoint); SystemUtilities::sleepSeconds(0.025); if (highlightFlag) { const float radius = 15.0; for (float angle = 0.0; angle < 6.28; angle += 0.314) { const float x = windowPoint.x() + (std::cos(angle) * radius); const float y = windowPoint.y() + (std::sin(angle) * radius); QCursor::setPos(x, y); SystemUtilities::sleepSeconds(0.025); } } QCursor::setPos(windowPoint); } /** * Find an object, by name, in the parent objects * * @param objectName * Name of object * @return * Pointer to object with name or NULL if not found */ QObject* WuQMacroExecutor::findObjectByName(const QString& objectName) const { QObject* object(NULL); for (auto po : m_parentObjects) { object = po->findChild(objectName); if (object != NULL) { break; } } return object; } /** * Run the commands in the given macro. * * @param macro * Macro that is run * @param macroCommandToStartAt * Macro command at which execution should begin. If NULL, start * with the first command in the macro * @param macroCommandToStopAfter * Macro command that the executor may stop after, depending upon options * @param window * Widget for parent * @param otherObjectParents * Additional objects that are searched for objects contained * in the macro commands * @param executorMonitor * The executor monitor * @param executorOptions * Executor options * @param errorMessageOut * Output containing any error messages * @return * True if the macro completed without errors, else false. */ bool WuQMacroExecutor::runMacro(const WuQMacro* macro, const WuQMacroCommand* macroCommandToStartAt, const WuQMacroCommand* macroCommandToStopAfter, QWidget* window, std::vector& otherObjectParents, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, QString& errorMessageOut) const { const bool result = runMacroPrivate(macro, macroCommandToStartAt, macroCommandToStopAfter, window, otherObjectParents, executorMonitor, executorOptions, errorMessageOut); return result; } /** * Run the commands in the given macro. * * @param macro * Macro that is run * @param macroCommandToStartAt * Macro command at which execution should begin. If NULL, start * with the first command in the macro * @param macroCommandToStopAfter * Macro command that the executor may stop after, depending upon options * @param window * Widget for parent * @param otherObjectParents * Additional objects that are searched for objects contained * in the macro commands * @param executorMonitor * The executor monitor * @param executorOptions * Executor options * @param errorMessageOut * Output containing any error messages * @return * True if the macro completed without errors, else false. */ bool WuQMacroExecutor::runMacroPrivate(const WuQMacro* macro, const WuQMacroCommand* macroCommandToStartAt, const WuQMacroCommand* macroCommandToStopAfter, QWidget* window, std::vector& otherObjectParents, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, QString& errorMessageOut) const { CaretAssert(macro); CaretAssert(executorOptions); m_parentObjects.clear(); m_parentObjects.push_back(window); m_parentObjects.insert(m_parentObjects.end(), otherObjectParents.begin(), otherObjectParents.end()); m_runOptions = *executorOptions; errorMessageOut.clear(); int32_t startCommandIndex(0); if (macroCommandToStartAt != NULL) { const int32_t commandIndex = macro->getIndexOfMacroCommand(macroCommandToStartAt); if (commandIndex < 0) { errorMessageOut = ("Macro command to start at not found in macro \"" + macroCommandToStartAt->getDescriptiveName() + "\""); return false; } startCommandIndex = commandIndex; } const int32_t numberOfMacroCommands = macro->getNumberOfMacroCommands(); for (int32_t i = startCommandIndex; i < numberOfMacroCommands; i++) { const WuQMacroCommand* mc = macro->getMacroCommandAtIndex(i); CaretAssert(mc); emit macroCommandStarting(macro, mc); const QString objectName(mc->getObjectName()); bool requiresObjectFlag(false); switch (mc->getCommandType()) { case WuQMacroCommandTypeEnum::CUSTOM_OPERATION: break; case WuQMacroCommandTypeEnum::MOUSE: requiresObjectFlag = true; break; case WuQMacroCommandTypeEnum::WIDGET: requiresObjectFlag = true; break; } QObject* object = findObjectByName(objectName); if (requiresObjectFlag) { if (object == NULL) { errorMessageOut.append("Unable to find object named " + objectName + "\n"); if (m_runOptions.isStopOnError()) { return false; } continue; } if (object->signalsBlocked()) { errorMessageOut.append("Object named " + objectName + " has signals blocked"); if (m_runOptions.isStopOnError()) { return false; } continue; } } bool allowDelayBeforeCommandFlag(false); emit macroCommandAboutToStart(window, mc, executorOptions, allowDelayBeforeCommandFlag); /* * May get stopped by user in macroCommandAboutToStart() */ switch (executorMonitor->getMode()) { case WuQMacroExecutorMonitor::Mode::PAUSE: break; case WuQMacroExecutorMonitor::Mode::RUN: break; case WuQMacroExecutorMonitor::Mode::STOP: errorMessageOut = executorMonitor->getStoppedByUserMessage(); return false; break; } if (executorOptions->isIgnoreDelaysAndDurations()) { allowDelayBeforeCommandFlag = false; } if (allowDelayBeforeCommandFlag) { performCommandDelay(mc); } QString commandErrorMessage; bool successFlag(false); switch (mc->getCommandType()) { case WuQMacroCommandTypeEnum::CUSTOM_OPERATION: successFlag = WuQMacroManager::instance()->executeCustomOperationMacroCommand(window, executorMonitor, executorOptions, mc, commandErrorMessage); break; case WuQMacroCommandTypeEnum::MOUSE: { CaretAssert(object); bool notFoundFlag(false); successFlag = runMouseCommand(mc, object, commandErrorMessage, notFoundFlag); } break; case WuQMacroCommandTypeEnum::WIDGET: CaretAssert(object); successFlag = runMacroCommand(window, executorMonitor, mc, object, commandErrorMessage); break; } if ( ! successFlag) { errorMessageOut.append(commandErrorMessage + "\n"); if (m_runOptions.isStopOnError()) { return false; } } QGuiApplication::processEvents(); if (m_stopFlag) { errorMessageOut = "OBSOLETE: Macro stopped at request of user"; return false; } bool allowDelayAfterCommandFlag(false); emit macroCommandHasCompleted(window, mc, executorOptions, allowDelayAfterCommandFlag); QGuiApplication::processEvents(); if (mc == macroCommandToStopAfter) { errorMessageOut = ("Macro stopped after " + mc->getDescriptiveName()); return false; } const bool stopFlag = executorMonitor->testForStop(); if (stopFlag) { errorMessageOut = executorMonitor->getStoppedByUserMessage(); return false; } if (executorOptions->isIgnoreDelaysAndDurations()) { allowDelayAfterCommandFlag = false; } if (allowDelayAfterCommandFlag) { performCommandDelay(mc); } QGuiApplication::processEvents(); } macroCommandStarting(macro, NULL); return (errorMessageOut.isEmpty()); } /** * Perform delay for the given macro command * * @param mc * The macro command */ void WuQMacroExecutor::performCommandDelay(const WuQMacroCommand* mc) const { if (mc->getCommandType() != WuQMacroCommandTypeEnum::MOUSE) { if (mc->getDelayInSeconds() > 0.0) { SystemUtilities::sleepSeconds(mc->getDelayInSeconds()); } } } /** * Stop the macro that is executing */ void WuQMacroExecutor::stopMacro() { m_stopFlag = true; } /** * Run the commands in the given macro. * * @param parentWidget * Parent widget for dialogs * @param executorMonitor * The executor monitor * @param macroCommand * Macro command that is run * @param object * Object on which command is run * @param errorMessageOut * Output containing any error messages * @return * True if the macro completed without errors, else false. */ bool WuQMacroExecutor::runMacroCommand(QWidget* /*parentWidget*/, const WuQMacroExecutorMonitor* /*executorMonitor*/, const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut) const { errorMessageOut.clear(); CaretAssert(macroCommand); CaretAssert(object); const WuQMacroWidgetTypeEnum::Enum classType = macroCommand->getWidgetType(); QString objectErrorMessage; bool notFoundFlag(false); switch (classType) { case WuQMacroWidgetTypeEnum::ACTION: runActionCommand(macroCommand, object, objectErrorMessage, notFoundFlag); break; case WuQMacroWidgetTypeEnum::ACTION_CHECKABLE: runActionCheckableCommand(macroCommand, object, objectErrorMessage, notFoundFlag); break; case WuQMacroWidgetTypeEnum::ACTION_GROUP: runActionGroupCommand(macroCommand, object, objectErrorMessage, notFoundFlag); break; case WuQMacroWidgetTypeEnum::BUTTON_GROUP: runButtonGroupCommand(macroCommand, object, objectErrorMessage, notFoundFlag); break; case WuQMacroWidgetTypeEnum::CHECK_BOX: runCheckBoxCommand(macroCommand, object, objectErrorMessage, notFoundFlag); break; case WuQMacroWidgetTypeEnum::COMBO_BOX: runComboBoxCommand(macroCommand, object, objectErrorMessage, notFoundFlag); break; case WuQMacroWidgetTypeEnum::DOUBLE_SPIN_BOX: runDoubleSpinBoxCommand(macroCommand, object, objectErrorMessage, notFoundFlag); break; case WuQMacroWidgetTypeEnum::INVALID: CaretAssert(0); break; case WuQMacroWidgetTypeEnum::LINE_EDIT: runLineEditCommand(macroCommand, object, objectErrorMessage, notFoundFlag); break; case WuQMacroWidgetTypeEnum::LIST_WIDGET: runListWidgetCommand(macroCommand, object, objectErrorMessage, notFoundFlag); break; case WuQMacroWidgetTypeEnum::MACRO_WIDGET_ACTION: runMacroWidgetActionCommand(macroCommand, object, objectErrorMessage, notFoundFlag); break; case WuQMacroWidgetTypeEnum::MENU: runMenuCommand(macroCommand, object, objectErrorMessage, notFoundFlag); break; case WuQMacroWidgetTypeEnum::PUSH_BUTTON: runPushButtonCommand(macroCommand, object, objectErrorMessage, notFoundFlag); break; case WuQMacroWidgetTypeEnum::PUSH_BUTTON_CHECKABLE: runPushButtonCheckableCommand(macroCommand, object, objectErrorMessage, notFoundFlag); break; case WuQMacroWidgetTypeEnum::RADIO_BUTTON: runRadioButtonCommand(macroCommand, object, objectErrorMessage, notFoundFlag); break; case WuQMacroWidgetTypeEnum::SLIDER: runSliderCommand(macroCommand, object, objectErrorMessage, notFoundFlag); break; case WuQMacroWidgetTypeEnum::SPIN_BOX: runSpinBoxCommand(macroCommand, object, objectErrorMessage, notFoundFlag); break; case WuQMacroWidgetTypeEnum::TAB_BAR: runTabBarCommand(macroCommand, object, objectErrorMessage, notFoundFlag); break; case WuQMacroWidgetTypeEnum::TAB_WIDGET: runTabWidgetCommand(macroCommand, object, objectErrorMessage, notFoundFlag); break; case WuQMacroWidgetTypeEnum::TOOL_BUTTON: runToolButtonCommand(macroCommand, object, objectErrorMessage, notFoundFlag); break; case WuQMacroWidgetTypeEnum::TOOL_BUTTON_CHECKABLE: runToolButtonCheckableCommand(macroCommand, object, objectErrorMessage, notFoundFlag); break; } if (notFoundFlag) { errorMessageOut = ("ERROR: Unable to cast object named " + object->objectName() + " to " + WuQMacroWidgetTypeEnum::toGuiName(classType)); return false; } else if ( ! objectErrorMessage.isEmpty()) { errorMessageOut = objectErrorMessage; return false; } return true; } /** * Run a non-checkable QAction selection command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type */ void WuQMacroExecutor::runActionCommand(const WuQMacroCommand* /*macroCommand*/, QObject* object, QString& /*errorMessageOut*/, bool& castFailureFlagOut) const { QAction* action = qobject_cast(object); if (action != NULL) { moveMouseToWidget(action); /* * Always emit true for a non-checkable action */ WuQMacroSignalEmitter signalEmitter; signalEmitter.emitQActionSignal(action, true); } else { castFailureFlagOut = true; } } /** * Run a checkable QAction selection command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type */ void WuQMacroExecutor::runActionCheckableCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& /*errorMessageOut*/, bool& castFailureFlagOut) const { QAction* action = qobject_cast(object); if (action != NULL) { moveMouseToWidget(action); CaretAssert(macroCommand->getNumberOfParameters() > 0); const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); CaretAssert(parameterOne); CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::BOOLEAN); WuQMacroSignalEmitter signalEmitter; signalEmitter.emitQActionSignal(action, parameterOne->getValue().toBool()); } else { castFailureFlagOut = true; } } /** * Run a action group selection command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type */ void WuQMacroExecutor::runActionGroupCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const { QActionGroup* actionGroup = qobject_cast(object); if (actionGroup != NULL) { moveMouseToWidget(actionGroup); CaretAssert(macroCommand->getNumberOfParameters() > 1); const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); CaretAssert(parameterOne); const WuQMacroCommandParameter* parameterTwo = macroCommand->getParameterAtIndex(1); CaretAssert(parameterTwo); CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::STRING); CaretAssert(parameterTwo->getDataType() == WuQMacroDataValueTypeEnum::INTEGER); QAction* textAction(NULL); QAction* indexAction(NULL); QList actions = actionGroup->actions(); for (int32_t i = 0; i < actions.size(); i++) { QAction* actionAtIndex = actions.at(i); if (actionAtIndex->text() == parameterOne->getValue().toString()) { textAction = actionAtIndex; } if (parameterTwo->getValue().toInt() == i) { indexAction = actionAtIndex; } } WuQMacroSignalEmitter signalEmitter; if (textAction != NULL) { signalEmitter.emitActionGroupSignal(actionGroup, textAction->text()); } else if (indexAction != NULL) { signalEmitter.emitActionGroupSignal(actionGroup, indexAction->text()); } else { errorMessageOut = ("For QActionGroup \"" + object->objectName() + "\", unable to find action with text \"" + parameterOne->getValue().toString() + "\" or index=" + parameterTwo->getValue().toInt()); } } else { castFailureFlagOut = true; } } /** * Run a button group selection command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type */ void WuQMacroExecutor::runButtonGroupCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const { QButtonGroup* buttonGroup = qobject_cast(object); if (buttonGroup != NULL) { CaretAssert(macroCommand->getNumberOfParameters() > 1); const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); CaretAssert(parameterOne); const WuQMacroCommandParameter* parameterTwo = macroCommand->getParameterAtIndex(1); CaretAssert(parameterTwo); CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::STRING); CaretAssert(parameterTwo->getDataType() == WuQMacroDataValueTypeEnum::INTEGER); const QVariant dataValue = parameterOne->getValue(); const QVariant dataValueTwo = parameterTwo->getValue(); QAbstractButton* textButton(NULL); QAbstractButton* indexButton(NULL); QList buttons = buttonGroup->buttons(); for (int32_t i = 0; i < buttons.size(); i++) { QAbstractButton* buttonAtIndex = buttons.at(i); if (buttonAtIndex->text() == dataValue.toString()) { textButton = buttonAtIndex; } if (dataValueTwo.toInt() == i) { indexButton = buttonAtIndex; } } WuQMacroSignalEmitter signalEmitter; if (textButton != NULL) { moveMouseToWidget(textButton); signalEmitter.emitQButtonGroupSignal(buttonGroup, textButton->text()); } else if (indexButton != NULL) { moveMouseToWidget(indexButton); signalEmitter.emitQButtonGroupSignal(buttonGroup, indexButton->text()); } else { errorMessageOut = ("For QButtonGroup \"" + object->objectName() + "\", unable to find button with text \"" + dataValue.toString() + "\" or index=" + dataValueTwo.toInt()); } } else { castFailureFlagOut = true; } } /** * Run a check box selection command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type */ void WuQMacroExecutor::runCheckBoxCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& /*errorMessageOut*/, bool& castFailureFlagOut) const { QCheckBox* checkBox = qobject_cast(object); if (checkBox != NULL) { moveMouseToWidget(checkBox); CaretAssert(macroCommand->getNumberOfParameters() > 0); const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); CaretAssert(parameterOne); CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::BOOLEAN); WuQMacroSignalEmitter signalEmitter; signalEmitter.emitQCheckBoxSignal(checkBox, parameterOne->getValue().toBool()); } else { castFailureFlagOut = true; } } /** * Run a combo box selection command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type */ void WuQMacroExecutor::runComboBoxCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const { QComboBox* comboBox = qobject_cast(object); if (comboBox != NULL) { CaretAssert(macroCommand->getNumberOfParameters() > 1); const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); CaretAssert(parameterOne); const WuQMacroCommandParameter* parameterTwo = macroCommand->getParameterAtIndex(1); CaretAssert(parameterTwo); const QVariant dataValue = parameterOne->getValue(); const QVariant dataValueTwo = parameterTwo->getValue(); CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::STRING); CaretAssert(parameterTwo->getDataType() == WuQMacroDataValueTypeEnum::INTEGER); int textIndex(-1); int indexIndex(-1); for (int32_t i = 0; i < comboBox->count(); i++) { if (comboBox->itemText(i) == dataValue.toString()) { textIndex = i; } else if (i == dataValueTwo.toInt()) { indexIndex = i; } } moveMouseToWidget(comboBox); WuQMacroSignalEmitter signalEmitter; if (textIndex >= 0) { signalEmitter.emitQComboBoxSignal(comboBox, textIndex); } else if (indexIndex >= 0) { signalEmitter.emitQComboBoxSignal(comboBox, indexIndex); } else { errorMessageOut = ("For ComboBox \"" + object->objectName() + "\", unable to find item with text \"" + dataValue.toString() + "\" or index=" + dataValueTwo.toInt()); } } else { castFailureFlagOut = true; } } /** * Run a double spin box selection command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type */ void WuQMacroExecutor::runDoubleSpinBoxCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& /*errorMessageOut*/, bool& castFailureFlagOut) const { QDoubleSpinBox* doubleSpinBox = qobject_cast(object); if (doubleSpinBox != NULL) { CaretAssert(macroCommand->getNumberOfParameters() > 0); const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); CaretAssert(parameterOne); CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::FLOAT); const QVariant dataValue = parameterOne->getValue(); moveMouseToWidget(doubleSpinBox); WuQMacroSignalEmitter signalEmitter; signalEmitter.emitQDoubleSpinBoxSignal(doubleSpinBox, dataValue.toDouble()); } else { castFailureFlagOut = true; } } /** * Run a line edit selection command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type */ void WuQMacroExecutor::runLineEditCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& /*errorMessageOut*/, bool& castFailureFlagOut) const { QLineEdit* lineEdit = qobject_cast(object); if (lineEdit != NULL) { CaretAssert(macroCommand->getNumberOfParameters() > 0); const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); CaretAssert(parameterOne); CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::STRING); const QVariant dataValue = parameterOne->getValue(); moveMouseToWidget(lineEdit); WuQMacroSignalEmitter signalEmitter; signalEmitter.emitQLineEditSignal(lineEdit, dataValue.toString()); } else { castFailureFlagOut = true; } } /** * Run a list widget selection command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type */ void WuQMacroExecutor::runListWidgetCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const { QListWidget* listWidget = qobject_cast(object); if (listWidget != NULL) { CaretAssert(macroCommand->getNumberOfParameters() > 1); const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); CaretAssert(parameterOne); const WuQMacroCommandParameter* parameterTwo = macroCommand->getParameterAtIndex(1); CaretAssert(parameterTwo); CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::STRING); CaretAssert(parameterTwo->getDataType() == WuQMacroDataValueTypeEnum::INTEGER); const QVariant dataValue = parameterOne->getValue(); const QVariant dataValueTwo = parameterTwo->getValue(); QListWidgetItem* textItem(NULL); QListWidgetItem* indexItem(NULL); for (int32_t i = 0; i < listWidget->count(); i++) { QListWidgetItem* itemAtIndex = listWidget->item(i); if (itemAtIndex->text() == dataValue.toString()) { textItem = itemAtIndex; } if (dataValueTwo.toInt() == i) { indexItem = itemAtIndex; } } moveMouseToWidget(listWidget); WuQMacroSignalEmitter signalEmitter; if (textItem != NULL) { signalEmitter.emitQListWidgetSignal(listWidget, textItem->text()); } else if (indexItem != NULL) { signalEmitter.emitQListWidgetSignal(listWidget, indexItem->text()); } else { errorMessageOut = ("For QListWidget \"" + object->objectName() + "\", unable to find item with text \"" + dataValue.toString() + "\" or index=" + dataValueTwo.toInt()); } } else { castFailureFlagOut = true; } } /** * Run a menu selection selection command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type */ void WuQMacroExecutor::runMacroWidgetActionCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& /*errorMessageOut*/, bool& castFailureFlagOut) const { WuQMacroWidgetAction* macroWidgetAction = qobject_cast(object); if (macroWidgetAction != NULL) { CaretAssert(macroCommand->getNumberOfParameters() > 0); const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); CaretAssert(parameterOne); CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::STRING); const QVariant dataValue = parameterOne->getValue(); WuQMacroSignalEmitter signalEmitter; signalEmitter.emitMacroWidgetActionSignal(macroWidgetAction, dataValue); } else { castFailureFlagOut = true; } } /** * Run a menu selection selection command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type */ void WuQMacroExecutor::runMenuCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const { QMenu* menu = qobject_cast(object); if (menu != NULL) { CaretAssert(macroCommand->getNumberOfParameters() > 1); const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); CaretAssert(parameterOne); const WuQMacroCommandParameter* parameterTwo = macroCommand->getParameterAtIndex(1); CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::STRING); CaretAssert(parameterTwo->getDataType() == WuQMacroDataValueTypeEnum::INTEGER); const QVariant dataValue = parameterOne->getValue(); const QVariant dataValueTwo = parameterTwo->getValue(); QAction* textAction(NULL); QAction* indexAction(NULL); QList actions = menu->actions(); for (int32_t i = 0; i < actions.size(); i++) { QAction* actionAtIndex = actions.at(i); if (actionAtIndex->text() == dataValue.toString()) { textAction = actionAtIndex; } if (dataValueTwo.toInt() == i) { indexAction = actionAtIndex; } } moveMouseToWidget(menu); WuQMacroSignalEmitter signalEmitter; if (textAction != NULL) { signalEmitter.emitQMenuSignal(menu, textAction->text()); } else if (indexAction != NULL) { signalEmitter.emitQMenuSignal(menu, indexAction->text()); } else { errorMessageOut = ("For QMenu \"" + object->objectName() + "\", unable to find action with text \"" + dataValue.toString() + "\" or index=" + dataValueTwo.toInt()); } } else { castFailureFlagOut = true; } } /** * Run a mouse command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type * @return * True if mouse command was successful */ bool WuQMacroExecutor::runMouseCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& /*castFailureFlagOut*/) const { QWidget* widget = qobject_cast(object); if (widget != NULL) { WuQMacroMouseEventWidgetInterface* mouseInterface = dynamic_cast(widget); if (mouseInterface != NULL) { const QSize currentWidgetSize = widget->size(); const WuQMacroMouseEventInfo* mouseEventInfo = macroCommand->getMouseEventInfo(); CaretAssert(mouseEventInfo); const int32_t numXY = mouseEventInfo->getNumberOfLocalXY(); for (int32_t i = 0; i < numXY; i++) { int32_t adjustedLocalX(0); int32_t adjustedLocalY(0); mouseEventInfo->getLocalPositionRescaledToWidgetSize(currentWidgetSize.width(), currentWidgetSize.height(), mouseEventInfo->getLocalX(i), mouseEventInfo->getLocalY(i), adjustedLocalX, adjustedLocalY); QEvent::Type qtEventType = QEvent::None; switch (mouseEventInfo->getMouseEventType()) { case WuQMacroMouseEventTypeEnum::BUTTON_PRESS: qtEventType = QEvent::MouseButtonPress; break; case WuQMacroMouseEventTypeEnum::BUTTON_RELEASE: qtEventType = QEvent::MouseButtonRelease; break; case WuQMacroMouseEventTypeEnum::DOUBLE_CLICKED: qtEventType = QEvent::MouseButtonDblClick; break; case WuQMacroMouseEventTypeEnum::MOVE: qtEventType = QEvent::MouseMove; break; } moveMouseToWidgetXY(widget, adjustedLocalX, adjustedLocalY, false); QMouseEvent qtMouseEvent(qtEventType, QPointF(adjustedLocalX, adjustedLocalY), static_cast(mouseEventInfo->getMouseButton()), static_cast(mouseEventInfo->getMouseButtonsMask()), static_cast(mouseEventInfo->getKeyboardModifiersMask())); mouseInterface->processMouseEventFromMacro(&qtMouseEvent); QGuiApplication::processEvents(); } } else { errorMessageOut = ("ERROR: Unable to cast object named " + object->objectName() + " to WuQMacroMouseEventWidgetInterface"); return false; } } else { errorMessageOut = ("ERROR: Unable to cast object named " + object->objectName() + " to QWidget"); return false; } return true; } /** * Run a pushbutton selection command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type */ void WuQMacroExecutor::runPushButtonCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& /*errorMessageOut*/, bool& castFailureFlagOut) const { QPushButton* pushButton = qobject_cast(object); if (pushButton != NULL) { CaretAssert(macroCommand->getNumberOfParameters() > 0); const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); CaretAssert(parameterOne); CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::NONE); const QVariant dataValue = parameterOne->getValue(); moveMouseToWidget(pushButton); WuQMacroSignalEmitter signalEmitter; signalEmitter.emitQPushButtonSignal(pushButton, true); } else { castFailureFlagOut = true; } } /** * Run a checkable pushbutton selection command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type */ void WuQMacroExecutor::runPushButtonCheckableCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& /*errorMessageOut*/, bool& castFailureFlagOut) const { QPushButton* pushButton = qobject_cast(object); if (pushButton != NULL) { CaretAssert(macroCommand->getNumberOfParameters() > 0); const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); CaretAssert(parameterOne); CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::BOOLEAN); const QVariant dataValue = parameterOne->getValue(); moveMouseToWidget(pushButton); WuQMacroSignalEmitter signalEmitter; signalEmitter.emitQPushButtonSignal(pushButton, dataValue.toBool()); } else { castFailureFlagOut = true; } } /** * Run a radio button selection command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type */ void WuQMacroExecutor::runRadioButtonCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& /*errorMessageOut*/, bool& castFailureFlagOut) const { QRadioButton* radioButton = qobject_cast(object); if (radioButton != NULL) { CaretAssert(macroCommand->getNumberOfParameters() > 0); const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); CaretAssert(parameterOne); /* Type=NONE since radio button is ALWAYS TRUE */ CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::NONE); const QVariant dataValue = parameterOne->getValue(); moveMouseToWidget(radioButton); WuQMacroSignalEmitter signalEmitter; /* Note: Radio buttons are always exclusive so always use a true value */ signalEmitter.emitQRadioButtonSignal(radioButton, true); } else { castFailureFlagOut = true; } } /** * Run a slider selection command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type */ void WuQMacroExecutor::runSliderCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& /*errorMessageOut*/, bool& castFailureFlagOut) const { QSlider* slider = qobject_cast(object); if (slider != NULL) { CaretAssert(macroCommand->getNumberOfParameters() > 0); const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); CaretAssert(parameterOne); CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::INTEGER); const QVariant dataValue = parameterOne->getValue(); moveMouseToWidget(slider); WuQMacroSignalEmitter signalEmitter; signalEmitter.emitQSliderSignal(slider, dataValue.toInt()); } else { castFailureFlagOut = true; } } /** * Run a spin box selection command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type */ void WuQMacroExecutor::runSpinBoxCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& /*errorMessageOut*/, bool& castFailureFlagOut) const { QSpinBox* spinBox = qobject_cast(object); if (spinBox != NULL) { CaretAssert(macroCommand->getNumberOfParameters() > 0); const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); CaretAssert(parameterOne); CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::INTEGER); const QVariant dataValue = parameterOne->getValue(); moveMouseToWidget(spinBox); WuQMacroSignalEmitter signalEmitter; signalEmitter.emitQSpinBoxSignal(spinBox, dataValue.toInt()); } else { castFailureFlagOut = true; } } /** * Run a tab bar selection command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type */ void WuQMacroExecutor::runTabBarCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const { QTabBar* tabBar = qobject_cast(object); if (tabBar != NULL) { CaretAssert(macroCommand->getNumberOfParameters() > 1); const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); CaretAssert(parameterOne); const WuQMacroCommandParameter* parameterTwo = macroCommand->getParameterAtIndex(1); CaretAssert(parameterTwo->getDataType() == WuQMacroDataValueTypeEnum::INTEGER); const QVariant dataValue = parameterOne->getValue(); const WuQMacroDataValueTypeEnum::Enum dataValueType = parameterOne->getDataType(); const QVariant dataValueTwo = parameterTwo->getValue(); int32_t tabIndex = dataValueTwo.toInt(); if (dataValueType == WuQMacroDataValueTypeEnum::STRING) { /* * Allow tab name to override tab index */ const QString tabName = dataValue.toString(); if ( ! tabName.isEmpty()) { for (int32_t i = 0; i < tabBar->count(); i++) { if (tabName == tabBar->tabText(i)) { tabIndex = i; break; } } } } if (tabBar->isTabEnabled(tabIndex)) { moveMouseToTabBarTab(tabBar, tabIndex); WuQMacroSignalEmitter signalEmitter; signalEmitter.emitQTabBarSignal(tabBar, tabIndex); } else { errorMessageOut = ("QTabWidget \"" + object->objectName() + "\", tab \"" + QString::number(tabIndex + 1) + "\" with text \"" + tabBar->tabText(tabIndex) + "\" is disabled"); } } else { castFailureFlagOut = true; } } /** * Run a tab widget selection command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type */ void WuQMacroExecutor::runTabWidgetCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const { QTabWidget* tabWidget = qobject_cast(object); if (tabWidget != NULL) { CaretAssert(macroCommand->getNumberOfParameters() > 1); const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); CaretAssert(parameterOne); const WuQMacroCommandParameter* parameterTwo = macroCommand->getParameterAtIndex(1); CaretAssert(parameterTwo->getDataType() == WuQMacroDataValueTypeEnum::INTEGER); const QVariant dataValue = parameterOne->getValue(); const WuQMacroDataValueTypeEnum::Enum dataValueType = parameterOne->getDataType(); const QVariant dataValueTwo = parameterTwo->getValue(); QTabBar* tabBar = tabWidget->tabBar(); CaretAssert(tabBar); int32_t tabIndex = dataValueTwo.toInt(); if (dataValueType == WuQMacroDataValueTypeEnum::STRING) { /* * Allow tab name to override tab index */ const QString tabName = dataValue.toString(); if ( ! tabName.isEmpty()) { for (int32_t i = 0; i < tabWidget->count(); i++) { if (tabName == tabWidget->tabText(i)) { tabIndex = i; break; } } } } if (tabWidget->isTabEnabled(tabIndex)) { moveMouseToTabBarTab(tabBar, tabIndex); WuQMacroSignalEmitter signalEmitter; signalEmitter.emitQTabWidgetSignal(tabWidget, tabIndex); } else { errorMessageOut = ("QTabWidget \"" + object->objectName() + "\", tab \"" + QString::number(tabIndex + 1) + "\" with text \"" + tabWidget->tabText(tabIndex) + "\" is disabled"); } } else { castFailureFlagOut = true; } } /** * Run a toolbutton selection command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type */ void WuQMacroExecutor::runToolButtonCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& /*errorMessageOut*/, bool& castFailureFlagOut) const { QToolButton* toolButton = qobject_cast(object); if (toolButton != NULL) { CaretAssert(macroCommand->getNumberOfParameters() > 0); const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); CaretAssert(parameterOne); CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::NONE); const QVariant dataValue = parameterOne->getValue(); moveMouseToWidget(toolButton); WuQMacroSignalEmitter signalEmitter; signalEmitter.emitQToolButtonSignal(toolButton, true); } else { castFailureFlagOut = true; } } /** * Run a checkable toolbutton selection command * * @param macroCommand * Macro command that is run * @param object * The object that is cast to specific object/widget * @param errorMessageOut * Error message from execution * @param castFailureFlagOut * Set to true if unable to cast object to widget type */ void WuQMacroExecutor::runToolButtonCheckableCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& /*errorMessageOut*/, bool& castFailureFlagOut) const { QToolButton* toolButton = qobject_cast(object); if (toolButton != NULL) { CaretAssert(macroCommand->getNumberOfParameters() > 0); const WuQMacroCommandParameter* parameterOne = macroCommand->getParameterAtIndex(0); CaretAssert(parameterOne); CaretAssert(parameterOne->getDataType() == WuQMacroDataValueTypeEnum::BOOLEAN); const QVariant dataValue = parameterOne->getValue(); moveMouseToWidget(toolButton); WuQMacroSignalEmitter signalEmitter; signalEmitter.emitQToolButtonSignal(toolButton, dataValue.toBool()); } else { castFailureFlagOut = true; } } connectome-workbench-1.4.2/src/GuiQt/WuQMacroExecutor.h000066400000000000000000000242741360521144700230520ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_EXECUTOR_H__ #define __WU_Q_MACRO_EXECUTOR_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "WuQMacroExecutorOptions.h" class QTabBar; class QWidget; namespace caret { class WuQMacro; class WuQMacroCommand; class WuQMacroExecutorMonitor; class WuQMacroExecutorOptions; class WuQMacroExecutor : public QObject { Q_OBJECT public: WuQMacroExecutor(); virtual ~WuQMacroExecutor(); WuQMacroExecutor(const WuQMacroExecutor&) = delete; WuQMacroExecutor& operator=(const WuQMacroExecutor&) = delete; bool runMacro(const WuQMacro* macro, const WuQMacroCommand* macroCommandToStartAt, const WuQMacroCommand* macroCommandToStopAfter, QWidget* window, std::vector& otherObjectParents, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, QString& errorMessageOut) const; void stopMacro(); // ADD_NEW_METHODS_HERE signals: void macroCommandAboutToStart(QWidget* window, const WuQMacroCommand* command, const WuQMacroExecutorOptions* executorOptions, bool& allowDelayFlagOut) const; void macroCommandHasCompleted(QWidget* window, const WuQMacroCommand* command, const WuQMacroExecutorOptions* executorOptions, bool& allowDelayFlagOut) const; void macroCommandStarting(const WuQMacro* macro, const WuQMacroCommand* command) const; private: void moveMouseToTabBarTab(QTabBar* tabBar, const int32_t tabIndex) const; void moveMouseToWidget(QObject* moveToObject, const bool highlightFlag = true) const; void moveMouseToWidgetXY(QObject* moveToObject, const int x, const int y, const bool highlightFlag = true) const; void moveMouseToWidgetImplementation(QObject* moveToObject, const int x, const int y, const QRect* objectRect = NULL, const bool hightlightFlag = false) const; void performCommandDelay(const WuQMacroCommand* mc) const; bool runMacroPrivate(const WuQMacro* macro, const WuQMacroCommand* macroCommandToStartAt, const WuQMacroCommand* macroCommandToStopAfter, QWidget* window, std::vector& otherObjectParents, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, QString& errorMessageOut) const; bool runMacroCommand(QWidget* parentWidget, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut) const; QObject* findObjectByName(const QString& objectName) const; void runActionCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; void runActionCheckableCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; void runActionGroupCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; void runButtonGroupCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; void runCheckBoxCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; void runComboBoxCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; void runDoubleSpinBoxCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; void runLineEditCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; void runListWidgetCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; void runMacroWidgetActionCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; void runMenuCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; bool runMouseCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; void runPushButtonCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; void runPushButtonCheckableCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; void runRadioButtonCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; void runSliderCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; void runSpinBoxCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; void runTabBarCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; void runTabWidgetCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; void runToolButtonCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; void runToolButtonCheckableCommand(const WuQMacroCommand* macroCommand, QObject* object, QString& errorMessageOut, bool& castFailureFlagOut) const; mutable WuQMacroExecutorOptions m_runOptions; mutable std::vector m_parentObjects; bool m_stopFlag = false; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_MACRO_EXECUTOR_DECLARE__ // #endif // __WU_Q_MACRO_EXECUTOR_DECLARE__ } // namespace #endif //__WU_Q_MACRO_EXECUTOR_H__ connectome-workbench-1.4.2/src/GuiQt/WuQMacroExecutorMonitor.cxx000066400000000000000000000063761360521144700250000ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_EXECUTOR_MONITOR_DECLARE__ #include "WuQMacroExecutorMonitor.h" #undef __WU_Q_MACRO_EXECUTOR_MONITOR_DECLARE__ #include #include #include #include "CaretAssert.h" using namespace caret; /** * \class caret::WuQMacroExecutorMonitor * \brief Allows interuption to pause or stop a macro * \ingroup GuiQt */ /** * Constructor. * * @param parent * The parent object */ WuQMacroExecutorMonitor::WuQMacroExecutorMonitor(QObject* parent) : QObject(parent) { } /** * Destructor. */ WuQMacroExecutorMonitor::~WuQMacroExecutorMonitor() { } /** * @return Error message indicating macro stopped by * user. Use this method for error message so that it * is consistent. */ QString WuQMacroExecutorMonitor::getStoppedByUserMessage() const { return "Execution stopped by user"; } /** * @return The mode */ WuQMacroExecutorMonitor::Mode WuQMacroExecutorMonitor::getMode() const { QMutexLocker locker(&m_modeMutex); return m_mode; } /** * Set the mode * * @param mode * New mode */ void WuQMacroExecutorMonitor::setMode(const Mode mode) { QMutexLocker locker(&m_modeMutex); m_mode = mode; switch (m_mode) { case Mode::PAUSE: break; case Mode::RUN: break; case Mode::STOP: break; } } /** * @return True if execution should stop and the command * should cleanup and return */ bool WuQMacroExecutorMonitor::testForStop() const { bool stopFlag(false); switch (getMode()) { case Mode::PAUSE: stopFlag = doPause(); break; case Mode::RUN: break; case Mode::STOP: stopFlag = true; break; } return stopFlag; } /** * Pause execution and return when mode changes to run or stop. * @return True if execution should stop and the command * should cleanup and return. */ bool WuQMacroExecutorMonitor::doPause() const { bool stopFlag(false); bool waitFlag(true); while (waitFlag) { QApplication::processEvents(); switch (getMode()) { case Mode::PAUSE: break; case Mode::RUN: stopFlag = false; waitFlag = false; break; case Mode::STOP: stopFlag = true; waitFlag = false; break; } } return stopFlag; } connectome-workbench-1.4.2/src/GuiQt/WuQMacroExecutorMonitor.h000066400000000000000000000041421360521144700244120ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_EXECUTOR_MONITOR_H__ #define __WU_Q_MACRO_EXECUTOR_MONITOR_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include namespace caret { class WuQMacroExecutorMonitor : public QObject { Q_OBJECT public: enum class Mode { RUN, PAUSE, STOP }; WuQMacroExecutorMonitor(QObject* parent); virtual ~WuQMacroExecutorMonitor(); WuQMacroExecutorMonitor(const WuQMacroExecutorMonitor&) = delete; WuQMacroExecutorMonitor& operator=(const WuQMacroExecutorMonitor&) = delete; QString getStoppedByUserMessage() const; Mode getMode() const; bool testForStop() const; void setMode(const Mode mode); bool doPause() const; mutable Mode m_mode = Mode::STOP; mutable QMutex m_modeMutex; // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE friend class WuQMacroExecutor; friend class WuQMacroManager; }; #ifdef __WU_Q_MACRO_EXECUTOR_MONITOR_DECLARE__ // #endif // __WU_Q_MACRO_EXECUTOR_MONITOR_DECLARE__ } // namespace #endif //__WU_Q_MACRO_EXECUTOR_MONITOR_H__ connectome-workbench-1.4.2/src/GuiQt/WuQMacroExecutorOptions.cxx000066400000000000000000000130711360521144700247720ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_EXECUTOR_OPTIONS_DECLARE__ #include "WuQMacroExecutorOptions.h" #undef __WU_Q_MACRO_EXECUTOR_OPTIONS_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::WuQMacroExecutorOptions * \brief Options for execution of macros * \ingroup GuiQt */ /** * Constructor. */ WuQMacroExecutorOptions::WuQMacroExecutorOptions() : CaretObject() { /* members initialized in header file */ } /** * Destructor. */ WuQMacroExecutorOptions::~WuQMacroExecutorOptions() { } /** * Copy constructor. * @param obj * Object that is copied. */ WuQMacroExecutorOptions::WuQMacroExecutorOptions(const WuQMacroExecutorOptions& obj) : CaretObject(obj) { this->copyHelperWuQMacroExecutorOptions(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ WuQMacroExecutorOptions& WuQMacroExecutorOptions::operator=(const WuQMacroExecutorOptions& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperWuQMacroExecutorOptions(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void WuQMacroExecutorOptions::copyHelperWuQMacroExecutorOptions(const WuQMacroExecutorOptions& obj) { m_loopingFlag = obj.m_loopingFlag; m_stopOnErrorFlag = obj.m_stopOnErrorFlag; m_showMouseMovementFlag = obj.m_showMouseMovementFlag; m_recordMovieDuringExecutionFlag = obj.m_recordMovieDuringExecutionFlag; m_createMovieAfterMacroExecutionFlag = obj.m_createMovieAfterMacroExecutionFlag; m_stopAfterSelectedCommandFlag = obj.m_stopAfterSelectedCommandFlag; m_ignoreDelaysAndDurationsFlag = obj.m_ignoreDelaysAndDurationsFlag; } /** * Get a description of this object's content. * @return String describing this object's content. */ AString WuQMacroExecutorOptions::toString() const { return "WuQMacroExecutorOptions"; } /** * @return Show mouse movement while running macro */ bool WuQMacroExecutorOptions::isShowMouseMovement() const { return m_showMouseMovementFlag; } /** * Set show mouse movement activity that was recorded in the macro * * @param status * New status */ void WuQMacroExecutorOptions::setShowMouseMovement(const bool status) { m_showMouseMovementFlag = status; } /** * @return True if exector should stop macro if an error occurs */ bool WuQMacroExecutorOptions::isStopOnError() const { return m_stopOnErrorFlag; } /** * Stop runningh of macro if there is an error while running the macro * * @param status * New status */ void WuQMacroExecutorOptions::setStopOnError(const bool status) { m_stopOnErrorFlag = status; } /** * @return True if looping is on. */ bool WuQMacroExecutorOptions::isLooping() const { return m_loopingFlag; } /** * Set looping on/off * * @param status * New status */ void WuQMacroExecutorOptions::setLooping(const bool status) { m_loopingFlag = status; } /** * @return True if record movie while macro executes is on. */ bool WuQMacroExecutorOptions::isRecordMovieDuringExecution() const { return m_recordMovieDuringExecutionFlag; } /** * Set record movie during macro execution * * @param status * New status */ void WuQMacroExecutorOptions::setRecordMovieDuringExecution(const bool status) { m_recordMovieDuringExecutionFlag = status; } /** * @return True if create movie after macro executes is on. */ bool WuQMacroExecutorOptions::isCreateMovieAfterMacroExecution() const { return m_createMovieAfterMacroExecutionFlag; } /** * Set create movie after macro execution * * @param status * New status */ void WuQMacroExecutorOptions::setCreateMovieAfterMacroExecution(const bool status) { m_createMovieAfterMacroExecutionFlag = status; } /** * @return True if execution should stop after the command selected in macro dialog */ bool WuQMacroExecutorOptions::isStopAfterSelectedCommand() const { return m_stopAfterSelectedCommandFlag; } /** * Set execution should stop after selected command in macro dialog * * @param status * New status */ void WuQMacroExecutorOptions::setStopAfterSelectedCommand(const bool status) { m_stopAfterSelectedCommandFlag = status; } /** * @return True if delays and durations should be ignored, * usually for editing and debugging macros. */ bool WuQMacroExecutorOptions::isIgnoreDelaysAndDurations() const { return m_ignoreDelaysAndDurationsFlag; } /** * Set delays and durations should be ignored, * usually for editing and debugging macros * * @param status * New status */ void WuQMacroExecutorOptions::setIgnoreDelaysAndDurations(const bool status) { m_ignoreDelaysAndDurationsFlag = status; } connectome-workbench-1.4.2/src/GuiQt/WuQMacroExecutorOptions.h000066400000000000000000000056311360521144700244220ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_EXECUTOR_OPTIONS_H__ #define __WU_Q_MACRO_EXECUTOR_OPTIONS_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretObject.h" namespace caret { class WuQMacroExecutorOptions : public CaretObject { public: WuQMacroExecutorOptions(); virtual ~WuQMacroExecutorOptions(); WuQMacroExecutorOptions(const WuQMacroExecutorOptions& obj); WuQMacroExecutorOptions& operator=(const WuQMacroExecutorOptions& obj); bool isShowMouseMovement() const; void setShowMouseMovement(const bool status); bool isStopOnError() const; void setStopOnError(const bool status); bool isLooping() const; void setLooping(const bool status); bool isRecordMovieDuringExecution() const; void setRecordMovieDuringExecution(const bool status); bool isCreateMovieAfterMacroExecution() const; void setCreateMovieAfterMacroExecution(const bool status); bool isStopAfterSelectedCommand() const; void setStopAfterSelectedCommand(const bool status); bool isIgnoreDelaysAndDurations() const; void setIgnoreDelaysAndDurations(const bool status); // ADD_NEW_METHODS_HERE virtual AString toString() const; private: void copyHelperWuQMacroExecutorOptions(const WuQMacroExecutorOptions& obj); bool m_showMouseMovementFlag = false; bool m_stopOnErrorFlag = true; bool m_loopingFlag = false; bool m_recordMovieDuringExecutionFlag = false; bool m_createMovieAfterMacroExecutionFlag = false; bool m_stopAfterSelectedCommandFlag = false; bool m_ignoreDelaysAndDurationsFlag = false; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_MACRO_EXECUTOR_OPTIONS_DECLARE__ // #endif // __WU_Q_MACRO_EXECUTOR_OPTIONS_DECLARE__ } // namespace #endif //__WU_Q_MACRO_EXECUTOR_OPTIONS_H__ connectome-workbench-1.4.2/src/GuiQt/WuQMacroHelperInterface.h000066400000000000000000000154731360521144700243150ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_HELPER_INTERFACE_H__ #define __WU_Q_MACRO_HELPER_INTERFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /** * \class caret::WuQMacroHelperInterface * \brief Interface that provides Macro Groups and is used by WuQMacroManager * \ingroup GuiQt */ #include #include class QMainWindow; class QWidget; namespace caret { class WuQMacro; class WuQMacroCommand; class WuQMacroExecutorOptions; class WuQMacroGroup; class WuQMacroWidgetAction; class WuQMacroHelperInterface : public QObject { Q_OBJECT public: WuQMacroHelperInterface(QObject* parent) : QObject(parent) { } virtual ~WuQMacroHelperInterface() { } WuQMacroHelperInterface(const WuQMacroHelperInterface&) = delete; WuQMacroHelperInterface& operator=(const WuQMacroHelperInterface&) = delete; /** * @return All 'active' available macro groups. * Macros groups that are editible. Other macro * groups are exluded. */ virtual std::vector getActiveMacroGroups() = 0; /** * @return All macro groups including those that are * be valid (editable) at this time. */ virtual std::vector getAllMacroGroups() const = 0; /** * Is called when the given macro is modified * * @param macro * Macro that is modified */ virtual void macroWasModified(WuQMacro* macro) = 0; /** * Is called when the given macro group is modified * * @param macroGroup * Macro Group that is modified */ virtual void macroGroupWasModified(WuQMacroGroup* macroGroup) = 0; /** * @return Identifiers of all available windows in which macros may be run */ virtual std::vector getMainWindowIdentifiers() = 0; /** * Get the main window with the given identifier * * @param identifier * Window identifier * @return * Window with the given identifier or NULL if not available */ virtual QMainWindow* getMainWindowWithIdentifier(const QString& identifier) = 0; /** * Called by macro executor just before executing the macro * * @param macro * Macro that is run * @param window * Widget for parent * @param executorOptions * Executor options */ virtual void macroExecutionStarting(const WuQMacro* macro, QWidget* window, const WuQMacroExecutorOptions* executorOptions) = 0; /** * Called by macro executor just after executing the macro * * @param macro * Macro that is run * @param window * Widget for parent * @param executorOptions * Executor options */ virtual void macroExecutionEnding(const WuQMacro* macro, QWidget* window, const WuQMacroExecutorOptions* executorOptions) = 0; /** * Reset the macro to its beginning state * * @param macro * Macro that is run * @param window * Widget for parent * @return * Pointer to current macro. May be different than the macro * passsed in. */ virtual WuQMacro* resetMacroStateToBeginning(const WuQMacro* macro, QWidget* window) = 0; /** * Called by macro executor just after a command has completed execution * * @param window * Widget for parent * @param command * Command that has just finished * @param executorOptions * Executor options * @param allowDelayFlagOut * Output indicating if delay after command is enabled */ virtual void macroCommandHasCompleted(QWidget* window, const WuQMacroCommand* command, const WuQMacroExecutorOptions* executorOptions, bool& allowDelayFlagOut) = 0; /** * Called by macro executor just before starting execution of a command * * @param window * Widget for parent * @param command * Command that is about to start * @param executorOptions * Executor options * @param allowDelayFlagOut * Output indicating if delay before command is enabled */ virtual void macroCommandAboutToStart(QWidget* window, const WuQMacroCommand* command, const WuQMacroExecutorOptions* executorOptions, bool& allowDelayFlagOut) = 0; /** * Called by macro manager to get macro widget actions typically * used by modal dialogs. * * Override to provide macro widget actions. * * @return Vector containing the macro widget actions. */ virtual std::vector getMacroWidgetActions() { std::vector emptyActions; return emptyActions; } // ADD_NEW_METHODS_HERE signals: void requestDialogsUpdate(); private: // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_MACRO_HELPER_INTERFACE_DECLARE__ // #endif // __WU_Q_MACRO_HELPER_INTERFACE_DECLARE__ } // namespace #endif //__WU_Q_MACRO_HELPER_INTERFACE_H__ connectome-workbench-1.4.2/src/GuiQt/WuQMacroManager.cxx000066400000000000000000001434031360521144700231750ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_MANAGER_DECLARE__ #include "WuQMacroManager.h" #undef __WU_Q_MACRO_MANAGER_DECLARE__ #include #include #include #include #include #include #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "DataFileException.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "WuQMacro.h" #include "WuQMacroCommand.h" #include "WuQMacroCreateDialog.h" #include "WuQMacroCustomOperationManagerInterface.h" #include "WuQMacroDialog.h" #include "WuQMacroExecutor.h" #include "WuQMacroExecutorMonitor.h" #include "WuQMacroFile.h" #include "WuQMacroGroup.h" #include "WuQMacroMouseEventInfo.h" #include "WuQMacroHelperInterface.h" #include "WuQMacroExecutorOptions.h" #include "WuQMacroSignalWatcher.h" #include "WuQMacroWidgetAction.h" using namespace caret; /** * \class caret::WuQMacroManager * \brief Manages the macro system. * \ingroup WuQMacro */ /** * Constructor. * * @param name * Name for the macro manager. */ WuQMacroManager::WuQMacroManager(const QString& name, QObject* parent) : QObject(parent), m_name(name) { setObjectName(name); m_macroExecutorMonitor = new WuQMacroExecutorMonitor(this); m_executorOptions.reset(new WuQMacroExecutorOptions()); } /** * Destructor. */ WuQMacroManager::~WuQMacroManager() { /* * Note: Do not delete the executor monitor as it is a QObject * with 'this' as a parent so Qt will take of of deleting it */ /* * Do not delete the WuQMacroSignalWatcher instances in * m_signalWatchers. This WuQMacroManager is set as the * parent object of the WuQMacroSignalWatcher's so Qt * will destroy them. */ m_signalWatchers.clear(); if (m_customCommandManager != NULL) { delete m_customCommandManager; m_customCommandManager = NULL; } /* * If an instance is being deleted it MUST be the * singleton so make it NULL. */ if (s_singletonMacroManager != NULL) { s_singletonMacroManager = NULL; } } /** * @return The instance of the Macro Manager. Before calling this method, * the createMacroManagerSingleton() must have been called to create the * singleton Macro Manager. If the singleton is not valid this method * will cause the application to abort. */ WuQMacroManager* WuQMacroManager::instance() { if (s_singletonMacroManager == NULL) { /* * 'qApp' is macro in QApplication that points to the QApplication instance */ s_singletonMacroManager = new WuQMacroManager("MacroManager", qApp); } return s_singletonMacroManager; } /** * Set the macro helper that provides the macro groups * * @param macroHelper * The macro helper. Ownership will be taken of macro helper * and it will be destoryed when this instance is destroyed. */ void WuQMacroManager::setMacroHelper(WuQMacroHelperInterface* macroHelper) { m_macroHelper = macroHelper; if (macroHelper != NULL) { QObject::connect(macroHelper, &WuQMacroHelperInterface::requestDialogsUpdate, this, &WuQMacroManager::updateNonModalDialogs); m_macroWidgetActions = macroHelper->getMacroWidgetActions(); for (auto mwa : m_macroWidgetActions) { addMacroSupportToObject(mwa, mwa->getToolTip()); } } } /** * Set the custom command manager for editing custom command parameters and * running custom commands * * @param customCommandManager * Pointer to custom command manager */ void WuQMacroManager::setCustomCommandManager(WuQMacroCustomOperationManagerInterface* customCommandManager) { m_customCommandManager = customCommandManager; } /** * @return Name of this macro manager */ QString WuQMacroManager::getName() const { return m_name; } /** * @return The current macro mode. */ WuQMacroModeEnum::Enum WuQMacroManager::getMode() const { return m_mode; } /** * Set the macro mode * * @param mode * New mode */ void WuQMacroManager::setMode(const WuQMacroModeEnum::Enum mode) { m_mode = mode; } /** * Add macro support to the given object. When recording, * The object's 'value changed' signal will be monitored so * that the new value can be part of a macro command. * * @param object * Object that is monitored. * @param descriptiveName * Descriptive name for user * @param toolTipTextOverride * Override of object's tooltip. This is primarily used when * an object of a particular class does not support a tooltip * such as a QButtonGroup. This can also be empty to avoid * the "no tooltip" message. */ bool WuQMacroManager::addMacroSupportToObjectWithToolTip(QObject* object, const QString& descriptiveName, const QString& toolTipOverride) { CaretAssert(object); const QString name = object->objectName(); if (name.isEmpty()) { CaretLogSevere("Object name is empty, will be ignored for macros\n" + SystemUtilities::getBackTrace()); return false; } if (descriptiveName.isEmpty()) { CaretLogSevere("Descriptive name is empty for " + name + "\n" + SystemUtilities::getBackTrace()); } auto existingWatcher = m_signalWatchers.find(name); if (existingWatcher != m_signalWatchers.end()) { CaretLogSevere("Object named \"" + name + "\" has already been connected for macros\n" + SystemUtilities::getBackTrace() + "\n"); return false; } AString errorMessage; WuQMacroSignalWatcher* widgetWatcher = WuQMacroSignalWatcher::newInstance(this, object, descriptiveName, toolTipOverride, errorMessage); if (widgetWatcher != NULL) { widgetWatcher->setParent(this); m_signalWatchers.insert(std::make_pair(name, widgetWatcher)); return true; } else { CaretLogWarning(errorMessage); return false; } } /** * Add macro support to the given object. When recording, * The object's 'value changed' signal will be monitored so * that the new value can be part of a macro command. * * @param object * Object that is monitored. * @param descriptiveName * Descriptive name for user */ bool WuQMacroManager::addMacroSupportToObject(QObject* object, const QString& descriptiveName) { CaretAssert(object); QString toolTipText; QAction* action = qobject_cast(object); if (action != NULL) { toolTipText = action->toolTip(); } QWidget* widget = qobject_cast(object); if (widget != NULL) { toolTipText = widget->toolTip(); } WuQMacroWidgetAction* macroWidgetAction = qobject_cast(object); if (macroWidgetAction != NULL) { toolTipText = macroWidgetAction->getToolTip(); } const bool resultFlag = addMacroSupportToObjectWithToolTip(object, descriptiveName, toolTipText); if (resultFlag) { if (toolTipText.isEmpty()) { CaretLogWarning("Object named \"" + object->objectName() + "\" is missing a tooltip"); } } return resultFlag; } /** * Adds the given macro comand to the macro that is currently being * recorded. If no macro is being recorded, no action is taken. * * @param macroCommand * Command to add to the current macro * @return * True if recording is on and command was added to the macro. * Ownership of command will be by the macro * False if recording off in which case caller is responsible * to delete the macro command */ bool WuQMacroManager::addMacroCommandToRecording(WuQMacroCommand* macroCommand) { CaretAssert(macroCommand); switch (getMode()) { case WuQMacroModeEnum::OFF: break; case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: CaretAssert(m_macroInsertCommandBeingRecorded); m_macroInsertCommandBeingRecorded->insertRow(m_macroInsertCommandBeingRecordedOffset, macroCommand); m_macroInsertCommandBeingRecordedOffset++; return true; break; case WuQMacroModeEnum::RECORDING_NEW_MACRO: CaretAssert(m_macroBeingRecorded); m_macroBeingRecorded->appendMacroCommand(macroCommand); return true; break; case WuQMacroModeEnum::RUNNING: break; } return false; } /** * Adds a mouse event to the macro that is currently being * recorded. If no macro is being recorded, no action is taken. * * @param widget * Widget where mouse event occurred * @param descriptiveName * Descriptive name for user * @param me * The Qt Mouse Event * @return * True if the mouse event was recorded or false if there is an error. */ bool WuQMacroManager::addMouseEventToRecording(QWidget* widget, const QString& descriptiveName, const QMouseEvent* me) { CaretAssert(widget); CaretAssert(me); WuQMacro* recordingMacro(NULL); switch (getMode()) { case WuQMacroModeEnum::OFF: break; case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: CaretAssert(m_macroInsertCommandBeingRecorded); recordingMacro = m_macroInsertCommandBeingRecorded; break; case WuQMacroModeEnum::RECORDING_NEW_MACRO: CaretAssert(m_macroBeingRecorded); recordingMacro = m_macroBeingRecorded; break; case WuQMacroModeEnum::RUNNING: break; } if (recordingMacro != NULL) { const QString name(widget->objectName()); if (name.isEmpty()) { CaretLogSevere("Widget name is empty for recording of mouse event\n" + SystemUtilities::getBackTrace()); return false; } if (descriptiveName.isEmpty()) { CaretLogSevere("Descriptive name is empty for " + name + "\n" + SystemUtilities::getBackTrace()); } bool validMouseEventFlag(true); WuQMacroMouseEventTypeEnum::Enum mouseEventType = WuQMacroMouseEventTypeEnum::MOVE; switch (me->type()) { case QEvent::MouseButtonPress: mouseEventType = WuQMacroMouseEventTypeEnum::BUTTON_PRESS; break; case QEvent::MouseButtonRelease: mouseEventType = WuQMacroMouseEventTypeEnum::BUTTON_RELEASE; break; case QEvent::MouseButtonDblClick: mouseEventType = WuQMacroMouseEventTypeEnum::DOUBLE_CLICKED; break; case QEvent::MouseMove: mouseEventType = WuQMacroMouseEventTypeEnum::MOVE; /* * Only track move events if a button is down * Note: Use "buttons()" mask, not button() */ if (me->buttons() == Qt::NoButton) { validMouseEventFlag = false; } break; default: CaretAssertMessage(0, ("Unknown mouse event type integer cast=" + QString::number(static_cast(me->type())))); break; } if (validMouseEventFlag) { WuQMacroMouseEventInfo* mouseInfo = new WuQMacroMouseEventInfo(mouseEventType, static_cast(me->button()), static_cast(me->buttons()), static_cast(me->modifiers()), widget->width(), widget->height()); mouseInfo->addLocalXY(me->localPos().x(), me->localPos().y()); const int32_t versionNumber(1); QString errorMessage; WuQMacroCommand* command = WuQMacroCommand::newInstanceMouseCommand(mouseInfo, versionNumber, name, descriptiveName, "mouse operation", 1.0, errorMessage); recordingMacro->appendMacroCommand(command); return true; } } return false; } /** * @return All 'active' available macro groups. * Macros groups that are editible. Other macro * groups are exluded. */ std::vector WuQMacroManager::getActiveMacroGroups() const { std::vector macroGroups; if (m_macroHelper) { macroGroups = m_macroHelper->getActiveMacroGroups(); } return macroGroups; } /** * @return All macro groups including those that are * be valid (editable) at this time. */ std::vector WuQMacroManager::getAllMacroGroups() const { std::vector macroGroups; if (m_macroHelper) { macroGroups = m_macroHelper->getAllMacroGroups(); } return macroGroups; } /** * Start recording a new macro using the New Macro dialog. * * @param parent * Parent for dialog. */ void WuQMacroManager::startRecordingNewMacro(QWidget* parent) { startRecordingNewMacro(parent, NULL, NULL); } /** * Start recording a new macro using the New Macro dialog. * New macro inserted into the given macro group and after the given macro. * * @param parent * Parent for dialog. * @param insertIntoMacroGroup * Insert new macro into this macro group * @param insertAfterMacro * Insert new macro after this macro (if NULL * new macro is inserted at beginning of group) * @return * Pointer to new macro or NULL if user cancelled */ WuQMacro* WuQMacroManager::startRecordingNewMacro(QWidget* parent, WuQMacroGroup* insertIntoMacroGroup, WuQMacro* insertAfterMacro) { CaretAssert(m_mode == WuQMacroModeEnum::OFF); WuQMacroCreateDialog createMacroDialog(insertIntoMacroGroup, insertAfterMacro, parent); if (createMacroDialog.exec() == WuQMacroCreateDialog::Accepted) { m_mode = WuQMacroModeEnum::RECORDING_NEW_MACRO; m_macroBeingRecorded = createMacroDialog.getNewMacro(); CaretAssert(m_macroBeingRecorded); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } else { m_macroBeingRecorded = NULL; } return m_macroBeingRecorded; } /** * Start recording commands and insert them into the given macro after * the given macro command. * * @param insertIntoMacro * Macro into which new commands are inserted. * @param insertAfterMacroCommand * New commands are inserted after this command or at beginning * if this command is NULL. */ void WuQMacroManager::startRecordingNewCommandInsertion(WuQMacro* insertIntoMacro, WuQMacroCommand* insertAfterMacroCommand) { CaretAssert(m_mode == WuQMacroModeEnum::OFF); CaretAssert(insertIntoMacro); m_mode = WuQMacroModeEnum::RECORDING_INSERT_COMMANDS; m_macroInsertCommandBeingRecorded = insertIntoMacro; m_macroInsertCommandBeingRecordedOffset = 0; if (insertAfterMacroCommand != NULL) { const int32_t index = insertIntoMacro->getIndexOfMacroCommand(insertAfterMacroCommand) + 1; CaretAssert(index >= 0); m_macroInsertCommandBeingRecordedOffset = index; } EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); } /** * Stop recording the macro. */ void WuQMacroManager::stopRecordingNewMacro() { switch (m_mode) { case WuQMacroModeEnum::OFF: CaretAssert(0); break; case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: CaretAssert(m_macroInsertCommandBeingRecorded); if (m_macroHelper) { m_macroHelper->macroWasModified(m_macroInsertCommandBeingRecorded); } break; case WuQMacroModeEnum::RECORDING_NEW_MACRO: CaretAssert(m_macroBeingRecorded); if (m_macroHelper) { m_macroHelper->macroWasModified(m_macroBeingRecorded); } break; case WuQMacroModeEnum::RUNNING: CaretAssert(0); break; } m_mode = WuQMacroModeEnum::OFF; m_macroBeingRecorded = NULL; m_macroInsertCommandBeingRecorded = NULL; m_macroInsertCommandBeingRecordedOffset = -1; EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); updateNonModalDialogs(); } /** * Show the macros dialog * * @param parent * Parent for dialog */ void WuQMacroManager::showMacrosDialog(QWidget* parent) { if (m_macrosDialog == NULL) { m_macrosDialog = new WuQMacroDialog(parent); } m_macrosDialog->updateDialogContents(); m_macrosDialog->show(); m_macrosDialog->raise(); m_macrosDialog->restorePositionAndSize(); } /** * @return Vector containing all non-modal dialogs used by Macro Manager. * This may be useful if the parent window is closed but other parent * windows are available. */ std::vector WuQMacroManager::getNonModalDialogs() { std::vector nonModalDialogs; if (m_macrosDialog != NULL) { nonModalDialogs.push_back(m_macrosDialog); } return nonModalDialogs; } /** * Update non-modal dialogs in macro manager */ void WuQMacroManager::updateNonModalDialogs() { if (m_macrosDialog != NULL) { m_macrosDialog->updateDialogContents(); } } /** * Run the given macro * * @param widget * Widget used for parent of dialogs * @param macroToRun * Macro that is run * @param macroCommandToStartAt * Macro command at which execution should begin. If NULL, start * with the first command in the macro * @param macroCommandToStopAfter * Macro command that the executor may stop after, depending upon options. * If NULL, end after last command is executed. * @return * Pointer to macro that was last run. The selected macro could change * when looping is enabled. */ WuQMacro* WuQMacroManager::runMacro(QWidget* widget, const WuQMacro* macroToRun, const WuQMacroCommand* macroCommandToStartAt, const WuQMacroCommand* macroCommandToStopAfter) { CaretAssert(widget); CaretAssert(macroToRun); WuQMacro* macro(const_cast(macroToRun)); bool dialogWasDisplayed(false); bool resultFlag(false); bool loopFlag(true); while (loopFlag) { loopFlag = m_executorOptions->isLooping(); QString errorMessage; m_macroExecutor = new WuQMacroExecutor(); QObject::connect(m_macroExecutor, &WuQMacroExecutor::macroCommandAboutToStart, this, &WuQMacroManager::macroCommandStartingExecution); QObject::connect(m_macroExecutor, &WuQMacroExecutor::macroCommandHasCompleted, this, &WuQMacroManager::macroCommandCompletedExecution); if (m_macrosDialog != NULL) { QObject::connect(m_macroExecutor, &WuQMacroExecutor::macroCommandStarting, m_macrosDialog, &WuQMacroDialog::selectMacroCommand); } m_macroExecutorMonitor->setMode(WuQMacroExecutorMonitor::Mode::RUN); if (m_macroHelper != NULL) { m_macroHelper->macroExecutionStarting(macro, widget, m_executorOptions.get()); } resultFlag = m_macroExecutor->runMacro(macro, macroCommandToStartAt, macroCommandToStopAfter, widget, m_parentObjects, m_macroExecutorMonitor, m_executorOptions.get(), errorMessage); if (m_macroHelper != NULL) { m_macroHelper->macroExecutionEnding(macro, widget, m_executorOptions.get()); } m_macroExecutorMonitor->setMode(WuQMacroExecutorMonitor::Mode::STOP); if ( ! resultFlag) { QMessageBox::information(widget, "Macro Done", errorMessage, QMessageBox::Ok, QMessageBox::NoButton); loopFlag = false; dialogWasDisplayed = true; } /* * Mutex needed so stop() method does not try * to access an invalid pointer to executor. */ QMutexLocker locker(&m_macroExecutorMutex); delete m_macroExecutor; m_macroExecutor = NULL; locker.unlock(); if (loopFlag) { if (m_macroHelper != NULL) { QMessageBox* msgBox = new QMessageBox(QMessageBox::Information, "Wait", "Reloading scene", QMessageBox::Ok, widget); msgBox->button(QMessageBox::Ok)->setVisible(false); msgBox->show(); WuQMacro* newMacro = resetMacro(widget, macro); if (newMacro != NULL) { macro = newMacro; } else { loopFlag = false; } msgBox->hide(); msgBox->deleteLater(); } } } if ( ! dialogWasDisplayed) { QApplication::beep(); } return macro; } /** * If a macro is running, stop it */ void WuQMacroManager::stopMacro() { m_macroExecutorMonitor->setMode(WuQMacroExecutorMonitor::Mode::STOP); } /** * Pause or continue a macro */ void WuQMacroManager::pauseContinueMacro() { switch (m_macroExecutorMonitor->getMode()) { case WuQMacroExecutorMonitor::Mode::PAUSE: m_macroExecutorMonitor->setMode(WuQMacroExecutorMonitor::Mode::RUN); break; case WuQMacroExecutorMonitor::Mode::RUN: m_macroExecutorMonitor->setMode(WuQMacroExecutorMonitor::Mode::PAUSE); break; case WuQMacroExecutorMonitor::Mode::STOP: break; } } /** * Called by macro executor when a macro command has completed * * @param window * Window in which command is running * @param command * Command that just finished execution * @param allowDelayFlagOut * Allow delay for after command has completed */ void WuQMacroManager::macroCommandCompletedExecution(QWidget* window, const WuQMacroCommand* command, const WuQMacroExecutorOptions* executorOptions, bool& allowDelayFlagOut) { CaretAssert(command); if (m_macroHelper != NULL) { m_macroHelper->macroCommandHasCompleted(window, command, executorOptions, allowDelayFlagOut); } } /** * Called by macro executor when a macro command is about to start * * @param window * Window in which command is running * @param command * Command that about to start execution * @param allowDelayFlagOut * Allow delay for after command has completed */ void WuQMacroManager::macroCommandStartingExecution(QWidget* window, const WuQMacroCommand* command, const WuQMacroExecutorOptions* executorOptions, bool& allowDelayFlagOut) { CaretAssert(command); if (m_macroHelper != NULL) { m_macroHelper->macroCommandAboutToStart(window, command, executorOptions, allowDelayFlagOut); } } /** * Reset the given macro * * @param parentg * Parent for any dialogs * @param macro * Macro that is reset to beginning state */ WuQMacro* WuQMacroManager::resetMacro(QWidget* parent, WuQMacro* macro) { WuQMacro* newMacro(macro); if (m_macroHelper != NULL) { newMacro = m_macroHelper->resetMacroStateToBeginning(macro, parent); } return newMacro; } /** * Add a parent object that will be searched during macro * execution to find objects by name that are contained * in a macro command * * @param parentObject * Object used to find objects */ void WuQMacroManager::addParentObject(QObject* parentObject) { CaretAssert(parentObject); m_parentObjects.push_back(parentObject); } /** * Can be called to indicate that a macro was modified * * @param macro * Macro that was modified */ void WuQMacroManager::macroWasModified(WuQMacro* macro) { if (m_macroHelper) { m_macroHelper->macroWasModified(macro); } } /** * Delete a macro * * @param parent * Parent widget for dialog * @param macroGroup * Group containing macro for deletion * @param macro * Macro to delete * @return * True if macro was deleted. */ bool WuQMacroManager::deleteMacro(QWidget* parent, WuQMacroGroup* macroGroup, WuQMacro* macro) { CaretAssert(macroGroup); CaretAssert(macro); if (QMessageBox::warning(parent, "Warning", ("Delete the macro: " + macro->getName()), QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok) == QMessageBox::Ok) { macroGroup->deleteMacro(macro); if (m_macroHelper) { m_macroHelper->macroGroupWasModified(macroGroup); } return true; } return false; } /** * Delete a macro command * * @param parent * Parent widget for dialog * @param macroGroup * Group containing macro * @param macro * Macro containing command to be deleted * @param macroCommand * Macro command for deletion * @return * True if macro was deleted. */ bool WuQMacroManager::deleteMacroCommand(QWidget* parent, WuQMacroGroup* macroGroup, WuQMacro* macro, WuQMacroCommand* macroCommand) { CaretAssert(macroGroup); CaretAssert(macro); CaretAssert(macroCommand); bool deleteFlag(true); const bool confirmDeleteFlag(false); if (confirmDeleteFlag) { deleteFlag = (QMessageBox::warning(parent, "Warning", ("Delete the macro command: " + macroCommand->getDescriptiveName()), QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok) == QMessageBox::Ok); } if (deleteFlag) { macro->deleteMacroCommand(macroCommand); if (m_macroHelper) { m_macroHelper->macroGroupWasModified(macroGroup); } return true; } return false; } /** * Import macros from a file * * @param parent * Parent widget for dialog * @param macroGroup * Group to which macros are appended * @return * True if macro(s) were successfully imported */ bool WuQMacroManager::importMacros(QWidget* parent, WuQMacroGroup* appendToMacroGroup) { QString fileFilterString(WuQMacroFile::getFileDialogFilter()); const QString filename = QFileDialog::getOpenFileName(parent, "Import Macros", s_importExportMacroFileDirectory, fileFilterString, &fileFilterString, QFileDialog::DontUseNativeDialog); if ( ! filename.isEmpty()) { WuQMacroFile macroFile; try { macroFile.readFile(filename); QFileInfo fileInfo(filename); s_importExportMacroFileDirectory = fileInfo.absolutePath(); const WuQMacroGroup* fileMacroGroup = macroFile.getMacroGroup(); if (fileMacroGroup->getNumberOfMacros() > 0) { appendToMacroGroup->appendMacroGroup(fileMacroGroup); if (m_macroHelper) { m_macroHelper->macroGroupWasModified(appendToMacroGroup); } return true; } else { throw DataFileException("File is empty, no macros to import"); } } catch (const DataFileException& dfe) { QMessageBox::critical(parent, "File Error", dfe.whatString(), QMessageBox::Ok, QMessageBox::Ok); } } return false; } /** * Export macro(s) * * @param parent * Parent widget for dialog * @param macroGroup * Group for export (if non-NULL) * @param macro * Macro for export (if non-NULL) * @return * True if macro was successfully exported */ bool WuQMacroManager::exportMacros(QWidget* parent, WuQMacroGroup* macroGroup, WuQMacro* macro) { QString fileFilterString(WuQMacroFile::getFileDialogFilter()); const QString filename = QFileDialog::getSaveFileName(parent, "Export Macros", s_importExportMacroFileDirectory, fileFilterString, &fileFilterString, (QFileDialog::DontUseNativeDialog | QFileDialog::DontConfirmOverwrite)); if ( ! filename.isEmpty()) { try { WuQMacroFile macroFile; if (macroGroup != NULL) { macroFile.appendMacroGroup(macroGroup); } else if (macro != NULL) { macroFile.addMacro(new WuQMacro(*macro)); } else { throw DataFileException("No macro group or macro for export"); } QString filenameToWrite(filename); if ( ! filenameToWrite.endsWith(WuQMacroFile::getFileExtension())) { filenameToWrite.append(WuQMacroFile::getFileExtension()); } macroFile.writeFile(filenameToWrite); QFileInfo fileInfo(filenameToWrite); s_importExportMacroFileDirectory = fileInfo.absolutePath(); return true; } catch (const DataFileException& dfe) { QMessageBox::critical(parent, "File Error", dfe.whatString(), QMessageBox::Ok, QMessageBox::Ok); } } return false; } /** * Get all signal watchers * * @param enabledItemsOnly * Only valid signal watchers whose object currently exists are included. * An object may cease to exists with something is closed (such as a window) * * @return * All signal watchers */ std::vector WuQMacroManager::getAllWidgetSignalWatchers(const bool enabledItemsOnly) const { std::vector allWatchers; allWatchers.reserve(m_signalWatchers.size()); for (auto iter : m_signalWatchers) { WuQMacroSignalWatcher* watcher = iter.second; bool validFlag(true); if (enabledItemsOnly) { validFlag = false; for (auto po : m_parentObjects) { QObject* object = po->findChild(watcher->getObjectName()); if (object != NULL) { validFlag = true; break; } } } if (validFlag) { allWatchers.push_back(watcher); } } return allWatchers; } /** * Get names of all signal watchers * * @param enabledItemsOnly * Only valid signal watches are returned * @return * All signal watchers */ std::vector WuQMacroManager::getAllWidgetSignalWatcherNames(const bool enabledItemsOnly) const { std::vector allWatchers = getAllWidgetSignalWatchers(enabledItemsOnly); std::vector names; names.reserve(m_signalWatchers.size()); for (auto iter : allWatchers) { names.push_back(iter->getObjectName()); } return names; } /** * Get the widget signal watcher with the given name * * @param name * Name of widget signal watcher * @retrurn * Pointer to watcher or NULL if not valid. */ WuQMacroSignalWatcher* WuQMacroManager::getWidgetSignalWatcherWithName(const QString& name) { auto watcher = m_signalWatchers.find(name); if (watcher != m_signalWatchers.end()) { return watcher->second; } return NULL; } /** * Print supported widgets to the terminal window. */ void WuQMacroManager::printSupportedWidgetsToTerminal() { std::set allList; std::set duplicateList; for (auto iter : m_signalWatchers) { const QString s(iter.second->toString()); const auto existIter = allList.find(s); if (existIter != allList.end()) { duplicateList.insert(s); } else { allList.insert(s); } } for (auto& iter : allList) { std::cout << iter << std::endl; } for (auto& iter : duplicateList) { std::cout << "DUPLICTE: " << iter << std::endl; } } /** * Print top level widgets */ void WuQMacroManager::printToLevelWidgetsToTerminal() { std::cout << "Top Level Widgets: " << std::endl; QWidgetList widgetList = qApp->topLevelWidgets(); foreach (QWidget* widget, widgetList) { std::cout << " " << widget->objectName() << ", " << widget->metaObject()->className() << std::endl; } std::cout << std::endl; } /** * Get the tooltip for the object with the given name * * @param objectName * Name of object * @return * Tooltip for object or empty if not found. */ QString WuQMacroManager::getToolTipForObjectName(const QString& objectName) const { QString tooltip; const auto existingWatcher = m_signalWatchers.find(objectName); if (existingWatcher != m_signalWatchers.end()) { tooltip = existingWatcher->second->getToolTip(); } return tooltip; } /** * @return Pointer to the executor's run options (const method) */ const WuQMacroExecutorOptions* WuQMacroManager::getExecutorOptions() const { return m_executorOptions.get(); } /** * @return Pointer to the executor's run options */ WuQMacroExecutorOptions* WuQMacroManager::getExecutorOptions() { return m_executorOptions.get(); } /** * @return Pointer to the executor monitor. * Always returns valid pointer, even if macro is not running. */ const WuQMacroExecutorMonitor* WuQMacroManager::getMacroExecutorMonitor() const { return m_macroExecutorMonitor; } /** * Process a key press event for macro shortcut * * @param keyEvent * Key event information. * @return * True if the input process recognized the key event * and the key event SHOULD NOT be propagated to parent * widgets */ bool WuQMacroManager::runMacroWithShortCutKeyEvent(QWidget* window, const QKeyEvent* keyEvent) { CaretAssert(keyEvent); /* * On Mac, SHIFT, CONTROL, COMMANDS * On Linux/Windows: SHIFT CTRL META */ Qt::KeyboardModifiers mods; #ifdef CARET_OS_MACOSX mods.setFlag(Qt::ShiftModifier); mods.setFlag(Qt::MetaModifier); mods.setFlag(Qt::ControlModifier); #else mods.setFlag(Qt::ShiftModifier); mods.setFlag(Qt::ControlModifier); mods.setFlag(Qt::AltModifier); #endif if (keyEvent->modifiers() == mods) { const int qtKeyCode = keyEvent->key(); const WuQMacroShortCutKeyEnum::Enum shortCutKey = WuQMacroShortCutKeyEnum::fromQtKeyEnum(qtKeyCode); if (shortCutKey != WuQMacroShortCutKeyEnum::Key_None) { const WuQMacro* macro = getMacroWithShortCutKey(shortCutKey); if (macro != NULL) { runMacro(window, macro, NULL, NULL); return true; } } } return false; } /** * @return the macro with the given short cut key or NULL if not found * * @param shortCutKey * The short cut key */ WuQMacro* WuQMacroManager::getMacroWithShortCutKey(const WuQMacroShortCutKeyEnum::Enum shortCutKey) const { WuQMacro* macro(NULL); const auto macroGroups = getActiveMacroGroups(); for (const auto mg : macroGroups) { macro = mg->getMacroWithShortCutKey(shortCutKey); if (macro != NULL) { break; } } return macro; } QString WuQMacroManager::getShortCutKeysMask() { QString mask; #ifdef CARET_OS_MACOSX mask = "shift/control/command"; #else mask = "shift/ctrl/alt"; #endif return mask; } /** * Get information about a custom parameter that may be a range or * a list of valid values * * @param browserWindowIndex * Index of window * @param macroCommand * Macro command that contains the parameter for editing * @param parameter * Parameter for editing * @param dataInfoOut * Information about the data * @return * True if the parameter was modified */ bool WuQMacroManager::getCustomParameterDataInfo(const int32_t browserWindowIndex, WuQMacroCommand* macroCommand, WuQMacroCommandParameter* parameter, WbMacroCustomDataInfo& dataInfoOut) { bool validFlag(false); if (m_customCommandManager != NULL) { validFlag = m_customCommandManager->getCustomParameterDataInfo(browserWindowIndex, macroCommand, parameter, dataInfoOut); } else { CaretLogSevere("No Macro Helper available for editing custom values in a macro parameter"); } return validFlag; } /** * Run a custom-defined macro command * * @param parent * Parent widget for any dialogs * @param executorMonitor * The executor monitor * @param executorOptions * Options for the executor * @param macroCommand * Custom macro command to run * @param errorMessageOut * Contains any error information or empty if no error */ bool WuQMacroManager::executeCustomOperationMacroCommand(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand, QString& errorMessageOut) { CaretAssert(parent); CaretAssert(macroCommand); errorMessageOut.clear(); bool successFlag(false); if (m_customCommandManager != NULL) { successFlag = m_customCommandManager->executeCustomOperationMacroCommand(parent, executorMonitor, executorOptions, macroCommand, errorMessageOut); } else { CaretLogSevere("No Macro Helper available for running custom macro commands"); } return successFlag; } /** * @return All custom operation commands. Caller is responsible for deleting * all content of the returned vector. */ std::vector WuQMacroManager::getAllCustomOperationMacroCommands() { std::vector customCommands; if (m_customCommandManager != NULL) { customCommands = m_customCommandManager->getAllCustomOperationMacroCommands(); } return customCommands; } /** * @return Names of custom operation defined macro commands */ std::vector WuQMacroManager::getNamesOfCustomOperationMacroCommands() { std::vector names; if (m_customCommandManager != NULL) { names = m_customCommandManager->getNamesOfCustomOperationMacroCommands(); } return names; } /** * Get a new instance of a custom operation for the given macro command name * * @param customMacroCommandName * Name of custom macro command * @param errorMessageOut * Contains any error information or empty if no error * @return * Pointer to command or NULL if not valid */ WuQMacroCommand* WuQMacroManager::newInstanceOfCustomOperationMacroCommand(const QString& macroCommandName, QString& errorMessageOut) { errorMessageOut.clear(); WuQMacroCommand* command(NULL); if (m_customCommandManager != NULL) { command = m_customCommandManager->newInstanceOfCustomOperationMacroCommand(macroCommandName, errorMessageOut); } else { errorMessageOut = "No Custom Operation Manager is available for creating custom commands"; } return command; } /** * @return Identifiers of all available windows in which macros may be run */ std::vector WuQMacroManager::getMainWindowIdentifiers() { std::vector identifiers; if (m_macroHelper != NULL) { identifiers = m_macroHelper->getMainWindowIdentifiers(); } return identifiers; } /** * Get the main window with the given identifier * * @param identifier * Window identifier * @return * Window with the given identifier or NULL if not available */ QMainWindow* WuQMacroManager::getMainWindowWithIdentifier(const QString& identifier) { if (m_macroHelper != NULL) { return m_macroHelper->getMainWindowWithIdentifier(identifier); } return NULL; } /** * @return A default name for a macro */ QString WuQMacroManager::getNewMacroDefaultName() const { QString name(""); bool foundFlag(false); static int32_t minimumIndex = 1; const std::vector macroGroups = getAllMacroGroups(); for (int32_t i = minimumIndex; i < 10000; i++) { name = ("Macro " + QString::number(i)); foundFlag = false; for (auto mg : macroGroups) { if (mg->getMacroByName(name) != NULL) { foundFlag = true; break; } } if ( ! foundFlag) { /* * If a default name was created, do not allow a "lower-numbered" * default name. Start with same index since user may not use it. */ minimumIndex = i; break; } } return name; } /** * @return The macro widget action with the given name or * NULL if not found * * @param name * Name of macro widget action */ WuQMacroWidgetAction* WuQMacroManager::getMacroWidgetActionByName(const QString& name) { for (auto mwa : m_macroWidgetActions) { if (mwa->getName() == name) { return mwa; } } return NULL; } /** * Get a widget for the macro widget action with the given name * * @param name * Name of the macro widget action * @param parentWidget * Optional parent widget for the returned widget * @return * Widget associated with the widget macro action or NULL if failure. */ QWidget* WuQMacroManager::getWidgetForMacroWidgetActionByName(const QString& name, QWidget* parentWidget) { QWidget* widget(NULL); WuQMacroWidgetAction* mwa = getMacroWidgetActionByName(name); if (mwa != NULL) { widget = mwa->requestWidget(parentWidget); if (widget == NULL) { const QString msg("Failed to create widget for macro widget action with name \"" + name + "."); CaretAssertMessage(0, msg); CaretLogSevere(msg); } } else { const QString msg("No macro widget action with name \"" + name + "\" was found."); CaretAssertMessage(0, msg); CaretLogSevere(msg); } return widget; } /** * Release the widget from its associated macro widget action. * Note: The widget is NOT destroyed as that is the responsibility * of the widget owner (typically a dialog). */ void WuQMacroManager::releaseWidgetFromMacroWidgetAction(QWidget* widget, QWidget* widget2, QWidget* widget3, QWidget* widget4, QWidget* widget5, QWidget* widget6) { std::vector allWidgets { widget, widget2, widget3, widget4, widget5, widget6 }; for (auto widget : allWidgets) { if (widget != NULL) { for (auto mwa : m_macroWidgetActions) { mwa->releaseWidget(widget); } } } } /** * Update the value of a widget from its macro widget action. * * @param widget * Widget that gets its value update */ void WuQMacroManager::updateValueInWidgetFromMacroWidgetAction(QWidget* widget, QWidget* widget2, QWidget* widget3, QWidget* widget4, QWidget* widget5, QWidget* widget6) { std::vector allWidgets { widget, widget2, widget3, widget4, widget5, widget6 }; for (auto widget : allWidgets) { if (widget != NULL) { for (auto mwa : m_macroWidgetActions) { if (mwa->updateWidgetWithModelValue(widget)) { return; } } } } } connectome-workbench-1.4.2/src/GuiQt/WuQMacroManager.h000066400000000000000000000245521360521144700226250ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_MANAGER_H__ #define __WU_Q_MACRO_MANAGER_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include "WuQMacroExecutor.h" #include "WuQMacroModeEnum.h" #include "WuQMacroShortCutKeyEnum.h" class QKeyEvent; class QMainWindow; class QMouseEvent; class QWidget; namespace caret { class WbMacroCustomDataInfo; class WuQMacro; class WuQMacroCommand; class WuQMacroCommandParameter; class WuQMacroCustomOperationManagerInterface; class WuQMacroDialog; class WuQMacroExecutor; class WuQMacroExecutorMonitor; class WuQMacroExecutorOptions; class WuQMacroGroup; class WuQMacroHelperInterface; class WuQMacroSignalWatcher; class WuQMacroWidgetAction; class WuQMacroManager : public QObject { Q_OBJECT public: static WuQMacroManager* instance(); virtual ~WuQMacroManager(); WuQMacroManager(const WuQMacroManager&) = delete; WuQMacroManager& operator=(const WuQMacroManager&) = delete; void setMacroHelper(WuQMacroHelperInterface* macroHelper); void setCustomCommandManager(WuQMacroCustomOperationManagerInterface* customCommandManager); QString getName() const; bool addMacroSupportToObject(QObject* object, const QString& descriptiveName); bool addMacroSupportToObjectWithToolTip(QObject* object, const QString& descriptiveName, const QString& toolTipOverride); bool addMacroCommandToRecording(WuQMacroCommand* macroCommand); bool addMouseEventToRecording(QWidget* widget, const QString& descriptiveName, const QMouseEvent* me); WuQMacroModeEnum::Enum getMode() const; void setMode(const WuQMacroModeEnum::Enum mode); std::vector getActiveMacroGroups() const; std::vector getAllMacroGroups() const; void startRecordingNewMacro(QWidget* parent); WuQMacro* startRecordingNewMacro(QWidget* parent, WuQMacroGroup* insertIntoMacroGroup, WuQMacro* insertAfterMacro); void startRecordingNewCommandInsertion(WuQMacro* insertIntoMacro, WuQMacroCommand* insertAfterMacroCommand); void stopRecordingNewMacro(); void showMacrosDialog(QWidget* parent); std::vector getNonModalDialogs(); WuQMacroExecutorOptions* getExecutorOptions(); const WuQMacroExecutorOptions* getExecutorOptions() const; const WuQMacroExecutorMonitor* getMacroExecutorMonitor() const; bool deleteMacro(QWidget* parent, WuQMacroGroup* macroGroup, WuQMacro* macro); bool deleteMacroCommand(QWidget* parent, WuQMacroGroup* macroGroup, WuQMacro* macro, WuQMacroCommand* macroCommand); bool importMacros(QWidget* parent, WuQMacroGroup* appendToMacroGroup); bool exportMacros(QWidget* parent, WuQMacroGroup* macroGroup, WuQMacro* macro); WuQMacro* runMacro(QWidget* window, const WuQMacro* macro, const WuQMacroCommand* macroCommandToStartAt, const WuQMacroCommand* macroCommandToStopAfter); WuQMacro* resetMacro(QWidget* parent, WuQMacro* macro); void stopMacro(); void pauseContinueMacro(); bool runMacroWithShortCutKeyEvent(QWidget* window, const QKeyEvent* keyEvent); void printSupportedWidgetsToTerminal(); void printToLevelWidgetsToTerminal(); void addParentObject(QObject* parentObject); QString getToolTipForObjectName(const QString& objectName) const; WuQMacro* getMacroWithShortCutKey(const WuQMacroShortCutKeyEnum::Enum shortCutKey) const; static QString getShortCutKeysMask(); void macroWasModified(WuQMacro* macro); bool getCustomParameterDataInfo(const int32_t browserWindowIndex, WuQMacroCommand* macroCommand, WuQMacroCommandParameter* parameter, WbMacroCustomDataInfo& dataInfoOut); bool executeCustomOperationMacroCommand(QWidget* parent, const WuQMacroExecutorMonitor* executorMonitor, const WuQMacroExecutorOptions* executorOptions, const WuQMacroCommand* macroCommand, QString& errorMessageOut); virtual std::vector getAllCustomOperationMacroCommands(); virtual std::vector getNamesOfCustomOperationMacroCommands(); virtual WuQMacroCommand* newInstanceOfCustomOperationMacroCommand(const QString& macroCommandName, QString& errorMessageOut); std::vector getMainWindowIdentifiers(); QMainWindow* getMainWindowWithIdentifier(const QString& identifier); std::vector getAllWidgetSignalWatchers(const bool enabledItemsOnly) const; std::vector getAllWidgetSignalWatcherNames(const bool enabledItemsOnly) const; WuQMacroSignalWatcher* getWidgetSignalWatcherWithName(const QString& name); QString getNewMacroDefaultName() const; WuQMacroWidgetAction* getMacroWidgetActionByName(const QString& name); QWidget* getWidgetForMacroWidgetActionByName(const QString& name, QWidget* parentWidget = 0); void releaseWidgetFromMacroWidgetAction(QWidget* widget, QWidget* widget2 = NULL, QWidget* widget3 = NULL, QWidget* widget4 = NULL, QWidget* widget5 = NULL, QWidget* widget6 = NULL); void updateValueInWidgetFromMacroWidgetAction(QWidget* widget, QWidget* widget2 = NULL, QWidget* widget3 = NULL, QWidget* widget4 = NULL, QWidget* widget5 = NULL, QWidget* widget6 = NULL); // ADD_NEW_METHODS_HERE public slots: void updateNonModalDialogs(); void macroCommandCompletedExecution(QWidget* window, const WuQMacroCommand* command, const WuQMacroExecutorOptions* executorOptions, bool& allowDelayFlagOut); void macroCommandStartingExecution(QWidget* window, const WuQMacroCommand* command, const WuQMacroExecutorOptions* executorOptions, bool& allowDelayFlagOut); private: WuQMacroManager(const QString& name, QObject* parent = NULL); std::vector m_parentObjects; const QString m_name; WuQMacroModeEnum::Enum m_mode = WuQMacroModeEnum::OFF; std::map m_signalWatchers; WuQMacro* m_macroBeingRecorded = NULL; WuQMacro* m_macroInsertCommandBeingRecorded = NULL; int32_t m_macroInsertCommandBeingRecordedOffset = -1; WuQMacroDialog* m_macrosDialog = NULL; static WuQMacroManager* s_singletonMacroManager; std::unique_ptr m_executorOptions; WuQMacroHelperInterface* m_macroHelper = NULL; WuQMacroCustomOperationManagerInterface* m_customCommandManager = NULL; std::vector m_macroWidgetActions; WuQMacroExecutor* m_macroExecutor = NULL; WuQMacroExecutorMonitor* m_macroExecutorMonitor = NULL; QMutex m_macroExecutorMutex; static QString s_importExportMacroFileDirectory; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_MACRO_MANAGER_DECLARE__ WuQMacroManager* WuQMacroManager::s_singletonMacroManager = NULL; QString WuQMacroManager::s_importExportMacroFileDirectory; #endif // __WU_Q_MACRO_MANAGER_DECLARE__ } // namespace #endif //__WU_Q_MACRO_MANAGER_H__ connectome-workbench-1.4.2/src/GuiQt/WuQMacroMenu.cxx000066400000000000000000000126261360521144700225310ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_MENU_DECLARE__ #include "WuQMacroMenu.h" #undef __WU_Q_MACRO_MENU_DECLARE__ #include "CaretAssert.h" #include "WuQMacroManager.h" using namespace caret; /** * \class caret::WuQMacroMenu * \brief Menu for accessing and interacting with the Macro System. * \ingroup WuQMacro */ /** * Constructor. * * @param windowParent * Window used as parent for dialogs * @param parent * Parent of the menu */ WuQMacroMenu::WuQMacroMenu(QWidget* windowParent, QWidget* parent) : QMenu(parent), m_windowParent(windowParent) { CaretAssert(windowParent); setTitle("Macro"); m_macroDialogAction = addAction("Macros..."); QObject::connect(m_macroDialogAction, &QAction::triggered, this, &WuQMacroMenu::macroDialogSelected); m_recordMacroAction = addAction("Start Recording New Macro..."); QObject::connect(m_recordMacroAction, &QAction::triggered, this, &WuQMacroMenu::macroRecordSelected); m_stopMacroAction = addAction("Stop Recording New Macro"); QObject::connect(m_stopMacroAction, &QAction::triggered, this, &WuQMacroMenu::macroStopSelected); { QMenu* developmentMenu = new QMenu("Development"); QAction* printAction = developmentMenu->addAction("Print Supported Widgets"); QObject::connect(printAction, &QAction::triggered, this, &WuQMacroMenu::macroPrintAllSelected); QAction* printTopLevelWidgetsAction = developmentMenu->addAction("Print Top-Level Widgets"); QObject::connect(printTopLevelWidgetsAction, &QAction::triggered, this, &WuQMacroMenu::macroPrintTopLevelWidgets); addSeparator(); addMenu(developmentMenu); } QObject::connect(this, &QMenu::aboutToShow, this, &WuQMacroMenu::macroMenuAboutToShow); } /** * Destructor. */ WuQMacroMenu::~WuQMacroMenu() { } /** * Called when the macro menu is about to show. */ void WuQMacroMenu::macroMenuAboutToShow() { WuQMacroManager* macroManager = WuQMacroManager::instance(); CaretAssert(macroManager); const bool hasMacroGroupFlag = ( ! macroManager->getActiveMacroGroups().empty()); bool editValidFlag(false); bool recordValidFlag(false); bool stopValidFlag(false); switch (macroManager->getMode()) { case WuQMacroModeEnum::OFF: editValidFlag = true; recordValidFlag = hasMacroGroupFlag; break; case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: case WuQMacroModeEnum::RECORDING_NEW_MACRO: stopValidFlag = true; break; case WuQMacroModeEnum::RUNNING: break; } m_macroDialogAction->setEnabled(editValidFlag); m_recordMacroAction->setEnabled(recordValidFlag); m_stopMacroAction->setEnabled(stopValidFlag); } /** * Called to start macro recording. */ void WuQMacroMenu::macroRecordSelected() { WuQMacroManager* macroManager = WuQMacroManager::instance(); CaretAssert(macroManager); switch (macroManager->getMode()) { case WuQMacroModeEnum::OFF: macroManager->startRecordingNewMacro(m_windowParent); break; case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: CaretAssert(0); break; case WuQMacroModeEnum::RECORDING_NEW_MACRO: CaretAssert(0); break; case WuQMacroModeEnum::RUNNING: CaretAssert(0); break; } } /** * Called to stop macro recording. */ void WuQMacroMenu::macroStopSelected() { WuQMacroManager* macroManager = WuQMacroManager::instance(); CaretAssert(macroManager); switch (macroManager->getMode()) { case WuQMacroModeEnum::OFF: CaretAssert(0); break; case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: case WuQMacroModeEnum::RECORDING_NEW_MACRO: macroManager->stopRecordingNewMacro(); break; case WuQMacroModeEnum::RUNNING: CaretAssert(0); break; } } /** * Called to display the macro editor dialog. */ void WuQMacroMenu::macroDialogSelected() { WuQMacroManager::instance()->showMacrosDialog(m_windowParent); } /** * Print all watched widgets to terminal */ void WuQMacroMenu::macroPrintAllSelected() { WuQMacroManager::instance()->printSupportedWidgetsToTerminal(); } /** * Print all top level widgets name and class name */ void WuQMacroMenu::macroPrintTopLevelWidgets() { WuQMacroManager::instance()->printToLevelWidgetsToTerminal(); } connectome-workbench-1.4.2/src/GuiQt/WuQMacroMenu.h000066400000000000000000000037451360521144700221600ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_MENU_H__ #define __WU_Q_MACRO_MENU_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include namespace caret { class WuQMacroMenu : public QMenu { Q_OBJECT public: WuQMacroMenu(QWidget* windowParent, QWidget* parent = 0); virtual ~WuQMacroMenu(); WuQMacroMenu(const WuQMacroMenu&) = delete; WuQMacroMenu& operator=(const WuQMacroMenu&) = delete; // ADD_NEW_METHODS_HERE private slots: void macroMenuAboutToShow(); void macroRecordSelected(); void macroStopSelected(); void macroDialogSelected(); void macroPrintAllSelected(); void macroPrintTopLevelWidgets(); private: // ADD_NEW_MEMBERS_HERE QWidget* m_windowParent; QAction* m_macroDialogAction; QAction* m_recordMacroAction; QAction* m_stopMacroAction; }; #ifdef __WU_Q_MACRO_MENU_DECLARE__ // #endif // __WU_Q_MACRO_MENU_DECLARE__ } // namespace #endif //__WU_Q_MACRO_MENU_H__ connectome-workbench-1.4.2/src/GuiQt/WuQMacroMouseEventWidgetInterface.h000066400000000000000000000033451360521144700263270ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_MOUSE_EVENT_WIDGET_INTERFACE_H__ #define __WU_Q_MACRO_MOUSE_EVENT_WIDGET_INTERFACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ class QMouseEvent; namespace caret { class WuQMacroMouseEventWidgetInterface { public: WuQMacroMouseEventWidgetInterface() { } virtual ~WuQMacroMouseEventWidgetInterface() { } WuQMacroMouseEventWidgetInterface(const WuQMacroMouseEventWidgetInterface&) = delete; WuQMacroMouseEventWidgetInterface& operator=(const WuQMacroMouseEventWidgetInterface&) = delete; virtual void processMouseEventFromMacro(QMouseEvent* me) = 0; private: // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_MACRO_MOUSE_EVENT_WIDGET_INTERFACE_DECLARE__ // #endif // __WU_Q_MACRO_MOUSE_EVENT_WIDGET_INTERFACE_DECLARE__ } // namespace #endif //__WU_Q_MACRO_MOUSE_EVENT_WIDGET_INTERFACE_H__ connectome-workbench-1.4.2/src/GuiQt/WuQMacroNewCommandSelectionDialog.cxx000066400000000000000000000377171360521144700266530ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_NEW_COMMAND_SELECTION_DIALOG_DECLARE__ #include "WuQMacroNewCommandSelectionDialog.h" #undef __WU_Q_MACRO_NEW_COMMAND_SELECTION_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "EnumComboBoxTemplate.h" #include "WuQMacro.h" #include "WuQMacroCommand.h" #include "WuQMacroGroup.h" #include "WuQMacroManager.h" #include "WuQMacroShortCutKeyComboBox.h" #include "WuQMacroSignalWatcher.h" using namespace caret; /** * \class caret::WuQMacroNewCommandSelectionDialog * \brief Dialog for creating a new macro * \ingroup WuQMacro */ /** * Constructor. * * @param parent * The parent widget */ WuQMacroNewCommandSelectionDialog::WuQMacroNewCommandSelectionDialog(QWidget* parent) : QDialog(parent) { setWindowTitle("Add Macro Command"); QLabel* commandTypeLabel = new QLabel("Command Type:"); QLabel* commandsLabel = new QLabel("Commands:"); QLabel* descriptionLabel = new QLabel("Description:"); std::vector commandTypes; commandTypes.push_back(WuQMacroCommandTypeEnum::CUSTOM_OPERATION); commandTypes.push_back(WuQMacroCommandTypeEnum::WIDGET); m_commandTypeComboBox = new EnumComboBoxTemplate(this); m_commandTypeComboBox->setupWithItems(commandTypes); m_commandTypeComboBox->setSelectedItem(s_lastCommandTypeSelected); QObject::connect(m_commandTypeComboBox, &EnumComboBoxTemplate::itemActivated, this, &WuQMacroNewCommandSelectionDialog::commandTypeComboBoxActivated); QWidget* typeWidget = new QWidget(); QHBoxLayout* typeLayout = new QHBoxLayout(typeWidget); typeLayout->setContentsMargins(0, 0, 0, 0); typeLayout->addWidget(commandTypeLabel, 0); typeLayout->addWidget(m_commandTypeComboBox->getWidget(), 100); m_customCommandListWidget = new QListWidget(); QObject::connect(m_customCommandListWidget, &QListWidget::currentItemChanged, this, &WuQMacroNewCommandSelectionDialog::customCommandListWidgetCurrentItemChanged); m_widgetCommandListWidget = new QListWidget(); QObject::connect(m_widgetCommandListWidget, &QListWidget::currentItemChanged, this, &WuQMacroNewCommandSelectionDialog::widgetCommandListWidgetCurrentItemChanged); m_stackedWidget = new QStackedWidget(); m_stackedWidget->addWidget(m_customCommandListWidget); m_stackedWidget->addWidget(m_widgetCommandListWidget); QWidget* commandsWidget = new QWidget(); QHBoxLayout* commandsLayout = new QHBoxLayout(commandsWidget); commandsLayout->setContentsMargins(0, 0, 0, 0); commandsLayout->addWidget(commandsLabel, 0); commandsLayout->addWidget(m_stackedWidget, 100); m_macroDescriptionTextEdit = new QPlainTextEdit(); QWidget* descriptionWidget = new QWidget(); QHBoxLayout* descriptionLayout = new QHBoxLayout(descriptionWidget); descriptionLayout->setContentsMargins(0, 0, 0, 0); descriptionLayout->addWidget(descriptionLabel, 0); descriptionLayout->addWidget(m_macroDescriptionTextEdit, 100); m_splitter = new QSplitter(); m_splitter->setOrientation(Qt::Vertical); m_splitter->addWidget(commandsWidget); m_splitter->addWidget(descriptionWidget); m_splitter->setStretchFactor(0, 75); m_splitter->setStretchFactor(1, 25); m_splitter->setChildrenCollapsible(false); m_dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); const bool allowApplyButtonFlag(false); if (allowApplyButtonFlag) { m_dialogButtonBox->addButton(QDialogButtonBox::Apply); } QObject::connect(m_dialogButtonBox, &QDialogButtonBox::clicked, this, &WuQMacroNewCommandSelectionDialog::otherButtonClicked); QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(typeWidget); dialogLayout->addWidget(m_splitter); dialogLayout->addWidget(m_dialogButtonBox); loadCustomCommandListWidget(); loadWidgetCommandListWidget(); commandTypeComboBoxActivated(); if ( ! s_previousDialogGeometry.isEmpty()) { restoreGeometry(s_previousDialogGeometry); } if ( ! s_previousSplitterState.isEmpty()) { m_splitter->restoreState(s_previousSplitterState); } } /** * Destructor. */ WuQMacroNewCommandSelectionDialog::~WuQMacroNewCommandSelectionDialog() { s_previousDialogGeometry = saveGeometry(); s_previousSplitterState = m_splitter->saveState(); for (auto cc : m_customCommands) { delete cc; } m_customCommands.clear(); } /** * Called when a selection is made from command type combo box */ void WuQMacroNewCommandSelectionDialog::commandTypeComboBoxActivated() { s_lastCommandTypeSelected = m_commandTypeComboBox->getSelectedItem(); m_macroDescriptionTextEdit->clear(); switch (s_lastCommandTypeSelected) { case WuQMacroCommandTypeEnum::CUSTOM_OPERATION: { m_stackedWidget->setCurrentWidget(m_customCommandListWidget); QListWidgetItem* item = m_customCommandListWidget->currentItem(); if (item == NULL) { if (m_customCommandListWidget->count() > 0) { item = m_customCommandListWidget->item(0); } } if (item != NULL) { m_customCommandListWidget->setCurrentItem(item); customCommandListWidgetCurrentItemChanged(item); } } break; case WuQMacroCommandTypeEnum::MOUSE: CaretAssert(0); break; case WuQMacroCommandTypeEnum::WIDGET: { m_stackedWidget->setCurrentWidget(m_widgetCommandListWidget); QListWidgetItem* item = m_widgetCommandListWidget->currentItem(); if (item == NULL) { if (m_widgetCommandListWidget->count() > 0) { item = m_widgetCommandListWidget->item(0); } } if (item != NULL) { m_widgetCommandListWidget->setCurrentItem(item); widgetCommandListWidgetCurrentItemChanged(item); } } break; } m_commandSelectionChangedSinceApplyClickedFlag = true; } /** * Load the custom commands into the list widget */ void WuQMacroNewCommandSelectionDialog::loadCustomCommandListWidget() { m_customCommands = WuQMacroManager::instance()->getAllCustomOperationMacroCommands(); for (auto cc : m_customCommands) { const QString name = cc->getDescriptiveName(); const QString customTypeName = cc->getCustomOperationTypeName(); QListWidgetItem* item = new QListWidgetItem(name); item->setData(Qt::UserRole, customTypeName); m_customCommandListWidget->addItem(item); } } /** * Load the widget commands into the list widget */ void WuQMacroNewCommandSelectionDialog::loadWidgetCommandListWidget() { m_widgetCommands = WuQMacroManager::instance()->getAllWidgetSignalWatchers(false); for (auto wc : m_widgetCommands) { const QString name = wc->getObjectName(); QListWidgetItem *item = new QListWidgetItem(name); m_widgetCommandListWidget->addItem(item); } } /** * Called when an item in the custom list widget is clicked * * @param item * Item that was clicked */ void WuQMacroNewCommandSelectionDialog::customCommandListWidgetCurrentItemChanged(QListWidgetItem* item) { QString description; if (item != NULL) { const QString customTypeName = item->data(Qt::UserRole).toString(); for (auto cc : m_customCommands) { if (customTypeName == cc->getCustomOperationTypeName()) { description = cc->getObjectToolTip(); } } } m_macroDescriptionTextEdit->setPlainText(description); m_commandSelectionChangedSinceApplyClickedFlag = true; } /** * Called when an item in the custom list widget is clicked * * @param item * Item that was clicked */ void WuQMacroNewCommandSelectionDialog::widgetCommandListWidgetCurrentItemChanged(QListWidgetItem* /*item*/) { QString description; const int index = m_widgetCommandListWidget->currentRow(); if ((index >= 0) && (index < static_cast(m_widgetCommands.size()))) { description = m_widgetCommands[index]->getToolTip(); } m_macroDescriptionTextEdit->setPlainText(description); m_commandSelectionChangedSinceApplyClickedFlag = true; } /** * Called when a dialog button is clicked */ void WuQMacroNewCommandSelectionDialog::otherButtonClicked(QAbstractButton* button) { switch (m_dialogButtonBox->standardButton(button)) { case QDialogButtonBox::Apply: processApplyButtonClicked(false); break; case QDialogButtonBox::Ok: accept(); break; case QDialogButtonBox::Cancel: reject(); break; default: CaretAssertMessage(0, ("Unknown button clicked with text \"" + button->text() + "\"")); break; } } /** * Called to process the apply button. * * @return True if apply button process was successful, else false. */ bool WuQMacroNewCommandSelectionDialog::processApplyButtonClicked(const bool okButtonClicked) { bool validFlag(false); switch (s_lastCommandTypeSelected) { case WuQMacroCommandTypeEnum::CUSTOM_OPERATION: validFlag = (m_customCommandListWidget->currentItem() != NULL); break; case WuQMacroCommandTypeEnum::MOUSE: CaretAssert(0); validFlag = false; break; case WuQMacroCommandTypeEnum::WIDGET: validFlag = (m_widgetCommandListWidget->currentItem() != NULL); break; } if (validFlag) { bool addCommandFlag = true; if (okButtonClicked) { /* * Both Apply and Ok add a command to the macro. If the user adds a command * using apply and then clicks Ok without changing the selected command, * warn the user to avoid unintentionally adding the command twice. */ if ( ! m_commandSelectionChangedSinceApplyClickedFlag) { const QString msg("Selected command has not changed since Apply button was clicked. " "Add command to macro again?"); switch (QMessageBox::warning(this, "Warning", msg, (QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel), QMessageBox::No)) { case QMessageBox::Yes: addCommandFlag = true; break; case QMessageBox::No: addCommandFlag = false; break; case QMessageBox::Cancel: addCommandFlag = false; validFlag = false; break; default: break; } } } QString errorMessage; if (addCommandFlag) { WuQMacroCommand* command = NULL; command = getNewInstanceOfSelectedCommand(errorMessage); if (command != NULL) { emit signalNewMacroCommandCreated(command); if ( ! okButtonClicked) { m_commandSelectionChangedSinceApplyClickedFlag = false; } } else { validFlag = false; QMessageBox::critical(this, "Error", errorMessage, QMessageBox::Ok, QMessageBox::Ok); } } } else { QMessageBox::critical(this, "Error", "No command is selected", QMessageBox::Ok, QMessageBox::Ok); } return validFlag; } /** * Called when user clicks OK or Cancel * * @param r * The dialog code (Accepted or Rejected) */ void WuQMacroNewCommandSelectionDialog::done(int r) { if (r == QDialog::Accepted) { const bool validFlag = processApplyButtonClicked(true); if ( ! validFlag) { return; } } QDialog::done(r); } /** * Get new instance of the command selected * * @param errorMessageOut * Output with error information. * @return Pointer to new command or NULL if it failed. */ WuQMacroCommand* WuQMacroNewCommandSelectionDialog::getNewInstanceOfSelectedCommand(QString& errorMessageOut) { errorMessageOut.clear(); WuQMacroCommand* commandOut(NULL); switch (s_lastCommandTypeSelected) { case WuQMacroCommandTypeEnum::CUSTOM_OPERATION: { QListWidgetItem* item = m_customCommandListWidget->currentItem(); if (item != NULL) { const QString customTypeName = item->data(Qt::UserRole).toString(); QString errorMessage; commandOut = WuQMacroManager::instance()->newInstanceOfCustomOperationMacroCommand(customTypeName, errorMessage); if (commandOut == NULL) { errorMessageOut = ("New instance of custom command \"" + customTypeName + "\" failed"); } } } break; case WuQMacroCommandTypeEnum::MOUSE: errorMessageOut = "Mouse commands not supported for new instances"; CaretAssert(0); break; case WuQMacroCommandTypeEnum::WIDGET: { QListWidgetItem* item = m_widgetCommandListWidget->currentItem(); if (item != NULL) { const QString widgetName = item->text(); WuQMacroSignalWatcher* watcher = WuQMacroManager::instance()->getWidgetSignalWatcherWithName(widgetName); if (watcher != NULL) { commandOut = watcher->createMacroCommandWithDefaultParameters(errorMessageOut); } else { errorMessageOut = ("Unable to find widget watcher with name \"" + widgetName + "\""); } } } break; } return commandOut; } connectome-workbench-1.4.2/src/GuiQt/WuQMacroNewCommandSelectionDialog.h000066400000000000000000000076111360521144700262660ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_NEW_COMMAND_SELECTION_DIALOG_H__ #define __WU_Q_MACRO_NEW_COMMAND_SELECTION_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "WuQMacroCommandTypeEnum.h" class QAbstractButton; class QComboBox; class QDialogButtonBox; class QLineEdit; class QListWidget; class QListWidgetItem; class QPlainTextEdit; class QSplitter; class QStackedWidget; namespace caret { class EnumComboBoxTemplate; class WuQMacro; class WuQMacroCommand; class WuQMacroGroup; class WuQMacroShortCutKeyComboBox; class WuQMacroSignalWatcher; class WuQMacroNewCommandSelectionDialog : public QDialog { Q_OBJECT public: WuQMacroNewCommandSelectionDialog(QWidget* parent = 0); virtual ~WuQMacroNewCommandSelectionDialog(); WuQMacroNewCommandSelectionDialog(const WuQMacroNewCommandSelectionDialog&) = delete; WuQMacroNewCommandSelectionDialog& operator=(const WuQMacroNewCommandSelectionDialog&) = delete; // ADD_NEW_METHODS_HERE signals: void signalNewMacroCommandCreated(WuQMacroCommand* command); public slots: void commandTypeComboBoxActivated(); void customCommandListWidgetCurrentItemChanged(QListWidgetItem* item); void widgetCommandListWidgetCurrentItemChanged(QListWidgetItem* item); virtual void done(int r) override; void otherButtonClicked(QAbstractButton* button); private: WuQMacroCommand* getNewInstanceOfSelectedCommand(QString& errorMessageOut); void loadCustomCommandListWidget(); void loadWidgetCommandListWidget(); bool processApplyButtonClicked(const bool okButtonClicked); EnumComboBoxTemplate* m_commandTypeComboBox; QStackedWidget* m_stackedWidget; QSplitter* m_splitter; QListWidget* m_customCommandListWidget; QListWidget* m_widgetCommandListWidget; QPlainTextEdit* m_macroDescriptionTextEdit; QDialogButtonBox* m_dialogButtonBox; std::vector m_customCommands; std::vector m_widgetCommands; WuQMacroCommand* m_lastCustomCommandAdded = NULL; bool m_commandSelectionChangedSinceApplyClickedFlag = false; static WuQMacroCommandTypeEnum::Enum s_lastCommandTypeSelected; static QByteArray s_previousDialogGeometry; static QByteArray s_previousSplitterState; }; #ifdef __WU_Q_MACRO_NEW_COMMAND_SELECTION_DIALOG_DECLARE__ WuQMacroCommandTypeEnum::Enum WuQMacroNewCommandSelectionDialog::s_lastCommandTypeSelected = WuQMacroCommandTypeEnum::CUSTOM_OPERATION; QByteArray WuQMacroNewCommandSelectionDialog::s_previousDialogGeometry; QByteArray WuQMacroNewCommandSelectionDialog::s_previousSplitterState; #endif // __WU_Q_MACRO_NEW_COMMAND_SELECTION_DIALOG_DECLARE__ } // namespace #endif //__WU_Q_MACRO_NEW_COMMAND_SELECTION_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/WuQMacroShortCutKeyComboBox.cxx000066400000000000000000000100301360521144700254650ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WUQ_MACRO_SHORT_CUT_COMBOBOX_DECLARE__ #include "WuQMacroShortCutKeyComboBox.h" #undef __WUQ_MACRO_SHORT_CUT_COMBOBOX_DECLARE__ using namespace caret; /** * \class caret::WuQMacroShortCutKeyComboBox * \brief Control for selection of a macro short cut key. * \ingroup GuiQt */ /** * Constructor. * @param parent * The parent. */ WuQMacroShortCutKeyComboBox::WuQMacroShortCutKeyComboBox(QObject* parent) : WuQWidget(parent) { std::vector allShortCutKeys; WuQMacroShortCutKeyEnum::getAllEnums(allShortCutKeys); const int32_t numShortCutKeys = static_cast(allShortCutKeys.size()); m_shortCutKeyComboBox = new QComboBox(); for (int32_t i = 0; i < numShortCutKeys; i++) { m_shortCutKeyComboBox->addItem(WuQMacroShortCutKeyEnum::toGuiName(allShortCutKeys[i])); m_shortCutKeyComboBox->setItemData(i, WuQMacroShortCutKeyEnum::toIntegerCode(allShortCutKeys[i])); } QObject::connect(m_shortCutKeyComboBox, SIGNAL(activated(int)), this, SLOT(shortCutKeyComboBoxSelection(int))); } /** * Destructor. */ WuQMacroShortCutKeyComboBox::~WuQMacroShortCutKeyComboBox() { } /** * Called to set the selected short cut key. * @param shortCutKey * New value for short cut key. */ void WuQMacroShortCutKeyComboBox::setSelectedShortCutKey(const WuQMacroShortCutKeyEnum::Enum shortCutKey) { const int32_t shortCutIntegerCode = WuQMacroShortCutKeyEnum::toIntegerCode(shortCutKey); const int numShortCutKeys = m_shortCutKeyComboBox->count(); for (int32_t i = 0; i < numShortCutKeys; i++) { if (shortCutIntegerCode == m_shortCutKeyComboBox->itemData(i).toInt()) { if (this->signalsBlocked()) { m_shortCutKeyComboBox->blockSignals(true); } m_shortCutKeyComboBox->setCurrentIndex(i); if (this->signalsBlocked()) { m_shortCutKeyComboBox->blockSignals(false); } break; } } } /** * @return The selected short cut key. */ WuQMacroShortCutKeyEnum::Enum WuQMacroShortCutKeyComboBox::getSelectedShortCutKey() const { WuQMacroShortCutKeyEnum::Enum shortCutKey = WuQMacroShortCutKeyEnum::Key_None; const int32_t indx = m_shortCutKeyComboBox->currentIndex(); if (indx >= 0) { const int32_t integerCode = m_shortCutKeyComboBox->itemData(indx).toInt(); shortCutKey = WuQMacroShortCutKeyEnum::fromIntegerCode(integerCode, NULL); } return shortCutKey; } /** * @return The widget for this control. */ QWidget* WuQMacroShortCutKeyComboBox::getWidget() { return m_shortCutKeyComboBox; } /** * Called when a short cut key is selected * @param indx * Index of selection. */ void WuQMacroShortCutKeyComboBox::shortCutKeyComboBoxSelection(int indx) { if (this->signalsBlocked() == false) { if ((indx >= 0) && (indx < m_shortCutKeyComboBox->count())) { const int32_t integerCode = m_shortCutKeyComboBox->itemData(indx).toInt(); WuQMacroShortCutKeyEnum::Enum shortCutKey = WuQMacroShortCutKeyEnum::fromIntegerCode(integerCode, NULL); emit shortCutKeySelected(shortCutKey); } } } connectome-workbench-1.4.2/src/GuiQt/WuQMacroShortCutKeyComboBox.h000066400000000000000000000041341360521144700251220ustar00rootroot00000000000000#ifndef __WUQ_MACRO_SHORT_CUT_COMBOBOX__H_ #define __WUQ_MACRO_SHORT_CUT_COMBOBOX__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "WuQMacroShortCutKeyEnum.h" #include "WuQWidget.h" namespace caret { class Surface; class WuQMacroShortCutKeyComboBox : public WuQWidget { Q_OBJECT public: WuQMacroShortCutKeyComboBox(QObject* parent); virtual ~WuQMacroShortCutKeyComboBox(); WuQMacroShortCutKeyEnum::Enum getSelectedShortCutKey() const; QWidget* getWidget(); public slots: void setSelectedShortCutKey(const WuQMacroShortCutKeyEnum::Enum shortCutKey); signals: void shortCutKeySelected(const WuQMacroShortCutKeyEnum::Enum); private slots: void shortCutKeyComboBoxSelection(int); private: WuQMacroShortCutKeyComboBox(const WuQMacroShortCutKeyComboBox&); WuQMacroShortCutKeyComboBox& operator=(const WuQMacroShortCutKeyComboBox&); QComboBox* m_shortCutKeyComboBox; public: private: }; #ifdef __WUQ_MACRO_SHORT_CUT_COMBOBOX_DECLARE__ // #endif // __WUQ_MACRO_SHORT_CUT_COMBOBOX_DECLARE__ } // namespace #endif //__WUQ_MACRO_SHORT_CUT_COMBOBOX__H_ connectome-workbench-1.4.2/src/GuiQt/WuQMacroSignalEmitter.cxx000066400000000000000000000405111360521144700243660ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_SIGNAL_EMITTER_DECLARE__ #include "WuQMacroSignalEmitter.h" #undef __WU_Q_MACRO_SIGNAL_EMITTER_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "WuQMacroWidgetAction.h" using namespace caret; /** * \class caret::WuQMacroSignalEmitter * \brief Causes the emission of a signal from a QObject instance * \ingroup WuQMacro */ /** * Constructor. */ WuQMacroSignalEmitter::WuQMacroSignalEmitter() : QObject() { } /** * Destructor. */ WuQMacroSignalEmitter::~WuQMacroSignalEmitter() { } /** * Update a QAction's checked status and cause emission * of its triggered() signal * * @param action * The QAction * @param checked * New checked status */ void WuQMacroSignalEmitter::emitQActionSignal(QAction* action, const bool checked) { CaretAssert(action); action->setChecked(checked); QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, action, &QAction::triggered); emit valueChangedSignalBool(checked); QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, 0, 0); } /** * Update a QActionGroup's selected action and cause emission * of its triggered() signal * * @param actionGroup * The QActionGroup * @param text * Text of selected action */ void WuQMacroSignalEmitter::emitActionGroupSignal(QActionGroup* actionGroup, const QString& text) { CaretAssert(actionGroup); QList actions = actionGroup->actions(); if (actions.isEmpty()) { CaretLogWarning("Menu " + actionGroup->objectName() + " does not contain any actions when trying to select menu item with text: " + text); return; } QAction* actionSelected = NULL; const int32_t numActions = actions.size(); for (int32_t i = 0; i < numActions; i++) { if (actions.at(i)->text() == text) { actionSelected = actions.at(i); } } if (actionSelected == NULL) { CaretLogWarning("Unable to find QAction with text \"" + text + "\" for menu " + actionGroup->objectName()); return; } QSignalBlocker blocker(actionGroup); actionSelected->trigger(); blocker.unblock(); QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalActionGroupAction, actionGroup, &QActionGroup::triggered); emit valueChangeSignalMenuAction(actionSelected); QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalActionGroupAction, 0, 0); } /** * Update a QButtonGroup and cause emission * of its buttonClicked() signal * * @param buttonGroup * The QButtonGroup * @param text * Text of button */ void WuQMacroSignalEmitter::emitQButtonGroupSignal(QButtonGroup* buttonGroup, const QString& text) { CaretAssert(buttonGroup); QAbstractButton* buttonSelected = NULL; QList allButtons = buttonGroup->buttons(); if (allButtons.isEmpty()) { CaretLogWarning("ButtonGroup " + buttonGroup->objectName() + " does not contain any buttons when trying to select button item with text: " + text); return; } for (auto b : allButtons) { if (b->text() == text) { buttonSelected = b; break; } } if (buttonSelected == NULL) { CaretLogWarning("Unable to find QAbstactButton with text \"" + text + "\" for button group " + buttonGroup->objectName()); return; } QSignalBlocker blocker(buttonGroup); buttonSelected->click(); blocker.unblock(); QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalAbstractButton, buttonGroup, static_cast(&QButtonGroup::buttonClicked)); emit valueChangedSignalAbstractButton(buttonSelected); QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, 0, 0); } /** * Update a QCheckBox's checked status and cause emission * of its clicked() signal * * @param checkBox * The QCheckBox * @param checked * New checked status */ void WuQMacroSignalEmitter::emitQCheckBoxSignal(QCheckBox* checkBox, const bool checked) { CaretAssert(checkBox); checkBox->setChecked(checked); QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, checkBox, &QCheckBox::clicked); emit valueChangedSignalBool(checked); QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, 0, 0); } /** * Update a QComboBox's index and cause emission * of its triggered() signal * * @param comboBox * The QComboBox * @param index * New index */ void WuQMacroSignalEmitter::emitQComboBoxSignal(QComboBox* comboBox, const int32_t index) { CaretAssert(comboBox); comboBox->setCurrentIndex(index); QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalInt, comboBox, static_cast(&QComboBox::activated)); emit valueChangedSignalInt(index); QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalInt, 0, 0); } /** * Update a QDoubleSpinBox value and cause emission * of its valueChanged() signal * * @param doubleSpinBox * The QDoubleSpinBox * @param value * New value */ void WuQMacroSignalEmitter::emitQDoubleSpinBoxSignal(QDoubleSpinBox* doubleSpinBox, const double value) { CaretAssert(doubleSpinBox); QSignalBlocker blocker(doubleSpinBox); doubleSpinBox->setValue(value); blocker.unblock(); QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalDouble, doubleSpinBox, static_cast(&QDoubleSpinBox::valueChanged)); emit valueChangedSignalDouble(value); QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalDouble, 0, 0); } /** * Update a QListWidget's item and cause emission * of its itemActivated() signal * * @param lineEdit * The QLineEdit * @param text * New text */ void WuQMacroSignalEmitter::emitQListWidgetSignal(QListWidget* listWidget, const QString& text) { CaretAssert(listWidget); QList items = listWidget->findItems(text, Qt::MatchExactly); if (items.isEmpty()) { CaretLogWarning("Unable to find QListWidgetItem with text \"" + text + "\" for " + listWidget->objectName()); return; } QListWidgetItem* newItem = items.at(0); listWidget->setCurrentItem(newItem); QObject::connect(this, &WuQMacroSignalEmitter::valueChangeSignalListWidgetItem, listWidget, &QListWidget::itemActivated); emit valueChangeSignalListWidgetItem(newItem); QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangeSignalListWidgetItem, 0, 0); } /** * Update a QLineEdit's text and cause emission * of its textChanged() signal * * @param lineEdit * The QLineEdit * @param text * New text */ void WuQMacroSignalEmitter::emitQLineEditSignal(QLineEdit* lineEdit, const QString& text) { CaretAssert(lineEdit); lineEdit->setText(text); QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalString, lineEdit, &QLineEdit::textChanged); emit valueChangedSignalString(text); QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalString, 0, 0); } /** * Update a Macro Widget Action's value and cause emission * of its valueChanged() signal * * @param macroWidgetAction * The Macro Widget Action * @param value * New value */ void WuQMacroSignalEmitter::emitMacroWidgetActionSignal(WuQMacroWidgetAction* macroWidgetAction, const QVariant& value) { CaretAssert(macroWidgetAction); macroWidgetAction->setDataValue(value); QObject::connect(this, & WuQMacroSignalEmitter::valueChangedSignalVariant, macroWidgetAction, &WuQMacroWidgetAction::setModelValue); emit valueChangedSignalVariant(value); QObject::disconnect(this, & WuQMacroSignalEmitter::valueChangedSignalVariant, 0, 0); } /** * Select an item from a menu using the item's text * * @param lineEdit * The QLineEdit * @param menuActionText * Text of menu item for selection */ void WuQMacroSignalEmitter::emitQMenuSignal(QMenu* menu, const QString& menuActionText) { CaretAssert(menu); QList actions = menu->actions(); if (actions.isEmpty()) { CaretLogWarning("Menu " + menu->objectName() + " does not contain any actions when trying to select menu item with text: " + menuActionText); return; } QAction* actionSelected = NULL; const int32_t numActions = actions.size(); for (int32_t i = 0; i < numActions; i++) { if (actions.at(i)->text() == menuActionText) { actionSelected = actions.at(i); } } if (actionSelected == NULL) { CaretLogWarning("Unable to find QAction with text \"" + menuActionText + "\" for menu " + menu->objectName()); return; } QObject::connect(this, &WuQMacroSignalEmitter::valueChangeSignalMenuAction, menu, &QMenu::triggered); emit valueChangeSignalMenuAction(actionSelected); QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangeSignalMenuAction, 0, 0); } /** * Update a QPushButton's checked status and cause emission * of its clicked() signal * * @param pushButton * The QPushButton * @param checked * New checked status */ void WuQMacroSignalEmitter::emitQPushButtonSignal(QPushButton* pushButton, const bool checked) { CaretAssert(pushButton); pushButton->setChecked(checked); QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, pushButton, &QPushButton::clicked); emit valueChangedSignalBool(checked); QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, 0, 0); } /** * Update a RadioButton's checked status and cause emission * of its checked() signal * * @param radioButton * The QRadioButton * @param checked * New checked status */ void WuQMacroSignalEmitter::emitQRadioButtonSignal(QRadioButton* radioButton, const bool checked) { CaretAssert(radioButton); QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, radioButton, &QRadioButton::clicked); const bool useClickFlag(true); if (useClickFlag) { QSignalBlocker blocker(radioButton); radioButton->setChecked( !checked); blocker.unblock(); radioButton->click(); } else { /* * This does not work for a radio button in a button group * as either click() or animateClick() is needed for the * button group to emit a signal */ radioButton->setChecked(checked); emit valueChangedSignalBool(checked); } QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, 0, 0); } /** * Update a QSlider's value and cause emission * of its valueChanged signal * * @param slider * The QSlider * @param value * New value */ void WuQMacroSignalEmitter::emitQSliderSignal(QSlider* slider, const int32_t value) { CaretAssert(slider); QSignalBlocker blocker(slider); slider->setValue(value); blocker.unblock(); QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalInt, slider, &QSlider::valueChanged); emit valueChangedSignalInt(value); QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalInt, 0, 0); } /** * Update a spin box's value and cause emission * of its valueChanged signal * * @param spinBox * The QSpinBox * @param value * New value */ void WuQMacroSignalEmitter::emitQSpinBoxSignal(QSpinBox* spinBox, const int32_t value) { CaretAssert(spinBox); QSignalBlocker blocker(spinBox); spinBox->setValue(value); blocker.unblock(); QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalInt, spinBox, static_cast(&QSpinBox::valueChanged)); emit valueChangedSignalInt(value); QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalInt, 0, 0); } /** * Update a TabBar's index and cause emission * of its currentChanged() signal * * @param tabBar * The QTabBar * @param index * New index */ void WuQMacroSignalEmitter::emitQTabBarSignal(QTabBar* tabBar, const int32_t index) { CaretAssert(tabBar); tabBar->setCurrentIndex(index); QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalInt, tabBar, &QTabBar::currentChanged); emit valueChangedSignalInt(index); QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalInt, 0, 0); } /** * Update a TabWidget's index and cause emission * of its currentChanged() signal * * @param tabWidget * The QTabWidget * @param index * New index */ void WuQMacroSignalEmitter::emitQTabWidgetSignal(QTabWidget* tabWidget, const int32_t index) { CaretAssert(tabWidget); tabWidget->setCurrentIndex(index); QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalInt, tabWidget, &QTabWidget::currentChanged); emit valueChangedSignalInt(index); QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalInt, 0, 0); } /** * Update a QToolButton checked status and cause emission * of its checked() signal * * @param toolButton * The QToolButton * @param checked * New checked status */ void WuQMacroSignalEmitter::emitQToolButtonSignal(QToolButton* toolButton, const bool checked) { CaretAssert(toolButton); toolButton->setChecked(checked); QObject::connect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, toolButton, &QToolButton::clicked); emit valueChangedSignalBool(checked); QObject::disconnect(this, &WuQMacroSignalEmitter::valueChangedSignalBool, 0, 0); } connectome-workbench-1.4.2/src/GuiQt/WuQMacroSignalEmitter.h000066400000000000000000000110141360521144700240070ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_SIGNAL_EMITTER_H__ #define __WU_Q_MACRO_SIGNAL_EMITTER_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include class QAction; class QActionGroup; class QAbstractButton; class QButtonGroup; class QCheckBox; class QComboBox; class QDoubleSpinBox; class QLineEdit; class QListWidget; class QListWidgetItem; class QMenu; class QPushButton; class QRadioButton; class QSlider; class QSpinBox; class QTabBar; class QTabWidget; class QToolButton; namespace caret { class WuQMacroWidgetAction; class WuQMacroSignalEmitter : public QObject { Q_OBJECT public: WuQMacroSignalEmitter(); virtual ~WuQMacroSignalEmitter(); WuQMacroSignalEmitter(const WuQMacroSignalEmitter&) = delete; WuQMacroSignalEmitter& operator=(const WuQMacroSignalEmitter&) = delete; void emitQActionSignal(QAction* action, const bool checked); void emitActionGroupSignal(QActionGroup* actionGroup, const QString& text); void emitQCheckBoxSignal(QCheckBox* checkBox, const bool checked); void emitQButtonGroupSignal(QButtonGroup* buttonGroup, const QString& text); void emitQComboBoxSignal(QComboBox* comboBox, const int32_t index); void emitQDoubleSpinBoxSignal(QDoubleSpinBox* doubleSpinBox, const double value); void emitQLineEditSignal(QLineEdit* lineEdit, const QString& text); void emitQListWidgetSignal(QListWidget* listWidget, const QString& text); void emitMacroWidgetActionSignal(WuQMacroWidgetAction* macroWidgetAction, const QVariant& value); void emitQMenuSignal(QMenu* menu, const QString& text); void emitQPushButtonSignal(QPushButton* pushButton, const bool checked); void emitQRadioButtonSignal(QRadioButton* radioButton, const bool checked); void emitQSliderSignal(QSlider* slider, const int32_t value); void emitQSpinBoxSignal(QSpinBox* spinBox, const int32_t value); void emitQTabBarSignal(QTabBar* tabBar, const int32_t value); void emitQTabWidgetSignal(QTabWidget* tabWidget, const int32_t value); void emitQToolButtonSignal(QToolButton* toolButton, const bool checked); // ADD_NEW_METHODS_HERE signals: void valueChangedSignalActionGroupAction(QAction*); void valueChangeSignalMenuAction(QAction*); void valueChangedSignalBool(bool); void valueChangedSignalAbstractButton(QAbstractButton* button); void valueChangedSignalInt(int); void valueChangedSignalDouble(double); void valueChangedSignalString(QString); void valueChangeSignalListWidgetItem(QListWidgetItem*); void valueChangedSignalVariant(QVariant); private: // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_MACRO_SIGNAL_EMITTER_DECLARE__ // #endif // __WU_Q_MACRO_SIGNAL_EMITTER_DECLARE__ } // namespace #endif //__WU_Q_MACRO_SIGNAL_EMITTER_H__ connectome-workbench-1.4.2/src/GuiQt/WuQMacroSignalWatcher.cxx000066400000000000000000001155101360521144700243540ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_SIGNAL_WATCHER_DECLARE__ #include "WuQMacroSignalWatcher.h" #undef __WU_Q_MACRO_SIGNAL_WATCHER_DECLARE__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "WuQMacroCommand.h" #include "WuQMacroCommandParameter.h" #include "WuQMacroManager.h" #include "WuQMacroWidgetAction.h" using namespace caret; /** * \class caret::WuQMacroSignalWatcher * \brief Watches a QObject instance to observe its "value changed" signal * \ingroup WuQMacro */ /** * Constructor. * * @param parentMacroManager * Parent macro manager. * @param object * Object that is watched for a "value changed" signal * @param objectType * The type of the object. * @param descriptiveName * Descriptive name shown to user in macro command * @param toolTipTextOverride * Used to override tool tip or for when object does not * support a tool tip. */ WuQMacroSignalWatcher::WuQMacroSignalWatcher(WuQMacroManager* parentMacroManager, QObject* object, const WuQMacroWidgetTypeEnum::Enum objectType, const QString& descriptiveName, const QString& toolTipTextOverride) : QObject(), m_parentMacroManager(parentMacroManager), m_object(object), m_objectType(objectType), m_descriptiveName(descriptiveName), m_objectName(object->objectName()) { CaretAssert(m_parentMacroManager); CaretAssert(m_object); QWidget* widget = qobject_cast(m_object); if (widget != NULL) { m_toolTipText = widget->toolTip(); } switch (m_objectType) { case WuQMacroWidgetTypeEnum::ACTION: { QAction* action = qobject_cast(m_object); CaretAssert(action); QObject::connect(action, &QAction::triggered, this, &WuQMacroSignalWatcher::actionTriggered); m_toolTipText = action->toolTip(); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::NONE, "Click/Select", "")); } break; case WuQMacroWidgetTypeEnum::ACTION_CHECKABLE: { QAction* action = qobject_cast(m_object); CaretAssert(action); QObject::connect(action, &QAction::triggered, this, &WuQMacroSignalWatcher::actionCheckableTriggered); m_toolTipText = action->toolTip(); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::BOOLEAN, "On/Off", true)); } break; case WuQMacroWidgetTypeEnum::ACTION_GROUP: { QActionGroup* actionGroup = qobject_cast(m_object); CaretAssert(actionGroup); QObject::connect(actionGroup, &QActionGroup::triggered, this, &WuQMacroSignalWatcher::actionGroupTriggered); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING, "Select name", "")); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::INTEGER, "Select index", 1)); } break; case WuQMacroWidgetTypeEnum::BUTTON_GROUP: { QButtonGroup* buttonGroup = qobject_cast(m_object); CaretAssert(buttonGroup); QObject::connect(buttonGroup, static_cast(&QButtonGroup::buttonClicked), this, &WuQMacroSignalWatcher::buttonGroupButtonClicked); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING, "Select button with name", "")); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::INTEGER, "Select button at index", 1)); } break; case WuQMacroWidgetTypeEnum::CHECK_BOX: { QCheckBox* checkBox = qobject_cast(m_object); CaretAssert(checkBox); QObject::connect(checkBox, &QCheckBox::clicked, this, &WuQMacroSignalWatcher::checkBoxClicked); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::BOOLEAN, "On/Off", true)); } break; case WuQMacroWidgetTypeEnum::COMBO_BOX: { QComboBox* comboBox = qobject_cast(m_object); CaretAssert(comboBox); QObject::connect(comboBox, static_cast(&QComboBox::activated), this, &WuQMacroSignalWatcher::comboBoxActivated); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING, "Select item with name", "")); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::INTEGER, "Select item at index", 1)); } break; case WuQMacroWidgetTypeEnum::DOUBLE_SPIN_BOX: { QDoubleSpinBox* spinBox = qobject_cast(m_object); CaretAssert(spinBox); QObject::connect(spinBox, static_cast(&QDoubleSpinBox::valueChanged), this, &WuQMacroSignalWatcher::doubleSpinBoxValueChanged); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::FLOAT, "New value", spinBox->minimum())); } break; case WuQMacroWidgetTypeEnum::INVALID: CaretAssert(0); break; case WuQMacroWidgetTypeEnum::LINE_EDIT: { QLineEdit* lineEdit = qobject_cast(m_object); CaretAssert(lineEdit); QObject::connect(lineEdit, &QLineEdit::textEdited, this, &WuQMacroSignalWatcher::lineEditTextEdited); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING, "New text", "")); } break; case WuQMacroWidgetTypeEnum::LIST_WIDGET: { QListWidget* listWidget = qobject_cast(m_object); CaretAssert(listWidget); QObject::connect(listWidget, &QListWidget::itemActivated, this, &WuQMacroSignalWatcher::listWidgetItemActivated); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING, "Select item with name", "")); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::INTEGER, "Select item at index", 1)); } break; case WuQMacroWidgetTypeEnum::MACRO_WIDGET_ACTION: { WuQMacroWidgetAction* macroWidgetAction = qobject_cast(m_object); CaretAssert(macroWidgetAction); QObject::connect(macroWidgetAction, &WuQMacroWidgetAction::valueChanged, this, &WuQMacroSignalWatcher::macroWidgetActionValueChanged); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING, "Data Value", "")); } break; case WuQMacroWidgetTypeEnum::MENU: { QMenu* menu = qobject_cast(m_object); CaretAssert(menu); QObject::connect(menu, &QMenu::triggered, this, &WuQMacroSignalWatcher::menuTriggered); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING, "Select item with name", "")); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::INTEGER, "Select item at index", 1)); } break; case WuQMacroWidgetTypeEnum::PUSH_BUTTON: { QPushButton* pushButton = qobject_cast(m_object); CaretAssert(pushButton); QObject::connect(pushButton, &QPushButton::clicked, this, &WuQMacroSignalWatcher::pushButtonClicked); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::NONE, "Click button", "")); } break; case WuQMacroWidgetTypeEnum::PUSH_BUTTON_CHECKABLE: { QPushButton* pushButton = qobject_cast(m_object); CaretAssert(pushButton); QObject::connect(pushButton, &QPushButton::clicked, this, &WuQMacroSignalWatcher::pushButtonClicked); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::BOOLEAN, "On/Off", true)); } break; case WuQMacroWidgetTypeEnum::RADIO_BUTTON: { QRadioButton* radioButton = qobject_cast(m_object); CaretAssert(radioButton); QObject::connect(radioButton, &QRadioButton::clicked, this, &WuQMacroSignalWatcher::radioButtonClicked); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::NONE, /* type=NONE - RADIO BUTTON ALWAYS TRUE !!! */ "Select button", true)); } break; case WuQMacroWidgetTypeEnum::SLIDER: { QSlider* slider = qobject_cast(m_object); CaretAssert(slider); QObject::connect(slider, &QSlider::valueChanged, this, &WuQMacroSignalWatcher::sliderValueChanged); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::INTEGER, "Move slider to", slider->minimum())); } break; case WuQMacroWidgetTypeEnum::SPIN_BOX: { QSpinBox* spinBox = qobject_cast(m_object); CaretAssert(spinBox); QObject::connect(spinBox, static_cast(&QSpinBox::valueChanged), this, &WuQMacroSignalWatcher::spinBoxValueChanged); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::INTEGER, "Enter value", spinBox->minimum())); } break; case WuQMacroWidgetTypeEnum::TAB_BAR: { QTabBar* tabBar = qobject_cast(m_object); CaretAssert(tabBar); QObject::connect(tabBar, &QTabBar::tabBarClicked, this, &WuQMacroSignalWatcher::tabBarCurrentChanged); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING, "Select tab with name", "")); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::INTEGER, "Select tab at index", 0)); } break; case WuQMacroWidgetTypeEnum::TAB_WIDGET: { QTabWidget* tabWidget = qobject_cast(m_object); CaretAssert(tabWidget); QObject::connect(tabWidget, &QTabWidget::tabBarClicked, this, &WuQMacroSignalWatcher::tabWidgetCurrentChanged); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::STRING, "Select tab with name", "")); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::INTEGER, "Select tab at index", 0)); } break; case WuQMacroWidgetTypeEnum::TOOL_BUTTON: { QToolButton* toolButton = qobject_cast(m_object); CaretAssert(toolButton); QObject::connect(toolButton, &QCheckBox::clicked, this, &WuQMacroSignalWatcher::toolButtonClicked); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::NONE, "Select button", true)); } break; case WuQMacroWidgetTypeEnum::TOOL_BUTTON_CHECKABLE: { QToolButton* toolButton = qobject_cast(m_object); CaretAssert(toolButton); QObject::connect(toolButton, &QCheckBox::clicked, this, &WuQMacroSignalWatcher::toolButtonClicked); m_objectParameters.push_back(new WuQMacroCommandParameter(WuQMacroDataValueTypeEnum::BOOLEAN, "On/Off", true)); } break; } /* * Override the tool tip text */ if ( ! toolTipTextOverride.isEmpty()) { m_toolTipText = toolTipTextOverride; } QObject::connect(m_object, &QObject::destroyed, this, &WuQMacroSignalWatcher::objectWasDestroyed); QObject::connect(m_object, &QObject::objectNameChanged, this, &WuQMacroSignalWatcher::objectNameWasChanged); } /** * Destructor. */ WuQMacroSignalWatcher::~WuQMacroSignalWatcher() { for (auto p : m_objectParameters) { delete p; } m_objectParameters.clear(); } /** * Called if the object whose signal is being monitored is destroyed * * @obj * Pointer to object that was destroyed */ void WuQMacroSignalWatcher::objectWasDestroyed(QObject* /*obj*/) { /* * Log object destroyed only when NOT debug */ #ifndef NDEBUG /* disable as need way to disallow this while a window is closing or application exiting */ const bool allowMessageFlag(false); if (allowMessageFlag) { CaretLogWarning("Object was destroyed: " + m_objectName); } #endif } /** * Called if the object whose signal is being monitored * has its name changed * * @name * New name */ void WuQMacroSignalWatcher::objectNameWasChanged(const QString& name) { std::cout << "Object name changed from " << m_objectName << " to " << name << std::endl; } /** * Create an new instance of a widget signal watcher for * the given object. * * @param parentMacroManager * Parent macro manager. * @param object * Object that will have a widget signal watcher. * @param descriptiveName * Descriptive name shown to user in macro command * @param toolTipTextOverride * Used to override tool tip or for when object does not * support a tool tip. * @param errorMessageOut * Output containing error information if failure. * @return * Pointer to widget watcher or NULL if there was an error. */ WuQMacroSignalWatcher* WuQMacroSignalWatcher::newInstance(WuQMacroManager* parentMacroManager, QObject* object, const QString& descriptiveName, const QString& toolTipTextOverride, QString& errorMessageOut) { errorMessageOut.clear(); QString objectClassName = object->metaObject()->className(); bool validFlag(false); WuQMacroWidgetTypeEnum::Enum objectType = WuQMacroWidgetTypeEnum::fromGuiName(objectClassName, &validFlag); /* * Some Qt Widgets may have a 'checkable' state * and the 'checkable' and 'non-checkable' states * must be handled differently. */ switch (objectType) { case WuQMacroWidgetTypeEnum::ACTION: { /* * Actions may have a 'checkable' status enabled * Actions may also be in a QActionGroup and the * QActionGroup may have an 'exclusive' status. * * NOTE: For this logic to work, the actions must have * macro support added after the actions are placed * in an exclusive action group */ QAction* action = qobject_cast(object); CaretAssert(action); if (action->isCheckable()) { /* * Probably checkable */ objectType = WuQMacroWidgetTypeEnum::ACTION_CHECKABLE; const QActionGroup* actionGroup = action->actionGroup(); if (actionGroup != NULL) { if (actionGroup->isExclusive()) { /* * In an exclusive group, actions CANNOT be * uchecked so treat as non-checkable action */ objectType = WuQMacroWidgetTypeEnum::ACTION; } } } } break; case WuQMacroWidgetTypeEnum::ACTION_CHECKABLE: CaretAssertMessage(0, "ACTION_CHECKABLE is created by ACTION above"); break; case WuQMacroWidgetTypeEnum::ACTION_GROUP: break; case WuQMacroWidgetTypeEnum::BUTTON_GROUP: break; case WuQMacroWidgetTypeEnum::CHECK_BOX: break; case WuQMacroWidgetTypeEnum::COMBO_BOX: break; case WuQMacroWidgetTypeEnum::DOUBLE_SPIN_BOX: break; case WuQMacroWidgetTypeEnum::INVALID: break; case WuQMacroWidgetTypeEnum::LINE_EDIT: break; case WuQMacroWidgetTypeEnum::LIST_WIDGET: break; case WuQMacroWidgetTypeEnum::MACRO_WIDGET_ACTION: break; case WuQMacroWidgetTypeEnum::MENU: break; case WuQMacroWidgetTypeEnum::PUSH_BUTTON: { /* * Buttons may have a 'checkable' status enabled * Buttons may also be in a QButtonGroup and the * QButtonGroup may have an 'exclusive' status. * * NOTE: For this logic to work, the buttons must have * macro support added after the buttons are placed * in an exclusive button group */ QAbstractButton* button = qobject_cast(object); CaretAssert(button); if (button->isCheckable()) { /* * Probably checkable */ objectType = WuQMacroWidgetTypeEnum::PUSH_BUTTON_CHECKABLE; const QButtonGroup* buttonGroup = button->group(); if (buttonGroup != NULL) { if (buttonGroup->exclusive()) { /* * In an exclusive group, buttons CANNOT be * uchecked so treat as non-checkable button */ objectType = WuQMacroWidgetTypeEnum::PUSH_BUTTON; } } } } break; case WuQMacroWidgetTypeEnum::PUSH_BUTTON_CHECKABLE: CaretAssertMessage(0, "PUSH_BUTTON_CHECKABLE is created by PUSH_BUTTON case above"); break; case WuQMacroWidgetTypeEnum::RADIO_BUTTON: break; case WuQMacroWidgetTypeEnum::SLIDER: break; case WuQMacroWidgetTypeEnum::SPIN_BOX: break; case WuQMacroWidgetTypeEnum::TAB_BAR: break; case WuQMacroWidgetTypeEnum::TAB_WIDGET: break; case WuQMacroWidgetTypeEnum::TOOL_BUTTON: { /* * Buttons may have a 'checkable' status enabled * Buttons may also be in a QButtonGroup and the * QButtonGroup may have an 'exclusive' status. * * NOTE: For this logic to work, the buttons must have * macro support added after the buttons are placed * in an exclusive button group */ QAbstractButton* button = qobject_cast(object); CaretAssert(button); if (button->isCheckable()) { /* * Probably checkable */ objectType = WuQMacroWidgetTypeEnum::TOOL_BUTTON_CHECKABLE; const QButtonGroup* buttonGroup = button->group(); if (buttonGroup != NULL) { if (buttonGroup->exclusive()) { /* * In an exclusive group, buttons CANNOT be * uchecked so treat as non-checkable button */ objectType = WuQMacroWidgetTypeEnum::TOOL_BUTTON; } } } } break; case WuQMacroWidgetTypeEnum::TOOL_BUTTON_CHECKABLE: CaretAssertMessage(0, "TOOL_BUTTON_CHECKABLE is created by TOOL_BUTTON case above"); break; } if ((objectType == WuQMacroWidgetTypeEnum::INVALID) || ( ! validFlag)) { errorMessageOut = ("Widget named \"" + object->objectName() + "\" of class \"" + object->metaObject()->className() + "\" is not supported for macros"); return NULL; } WuQMacroSignalWatcher* ww = new WuQMacroSignalWatcher(parentMacroManager, object, objectType, descriptiveName, toolTipTextOverride); return ww; } /** * @return Name of the object */ QString WuQMacroSignalWatcher::getObjectName() const { return m_objectName; } /** * @return Tooltip for this signal watcher */ QString WuQMacroSignalWatcher::getToolTip() const { return m_toolTipText; } /** * Create a macro command for this widget watcher with default * (essentially unset) parameters that need to be set by user * * @param errorMessageOut * Contains error information if failure. * @return * Pointer to new command or NULL if failure. Caller * is responsible for destroying returned command */ WuQMacroCommand* WuQMacroSignalWatcher::createMacroCommandWithDefaultParameters(QString& errorMessageOut) const { const int32_t versionNumber(1); WuQMacroCommand* mc = WuQMacroCommand::newInstanceWidgetCommand(m_objectType, versionNumber, m_objectName, m_descriptiveName, m_toolTipText, 1.0, errorMessageOut); if (mc != NULL) { std::vector parameters = getCopyOfObjectParameters(); for (auto p : parameters) { mc->addParameter(p); } } return mc; } /** * If recording mode is enabled, create and send a macro command * to the macro manager. * * @param parameters * Parameters for the command */ void WuQMacroSignalWatcher::createAndSendMacroCommand(std::vector& parameters) { bool recordingFlag(false); switch (m_parentMacroManager->getMode()) { case WuQMacroModeEnum::OFF: break; case WuQMacroModeEnum::RECORDING_INSERT_COMMANDS: case WuQMacroModeEnum::RECORDING_NEW_MACRO: recordingFlag = true; break; case WuQMacroModeEnum::RUNNING: break; } if (recordingFlag) { const int32_t versionNumber(1); QString errorMessage; WuQMacroCommand* mc = WuQMacroCommand::newInstanceWidgetCommand(m_objectType, versionNumber, m_objectName, m_descriptiveName, m_toolTipText, 1.0, errorMessage); if (mc != NULL) { for (auto p : parameters) { mc->addParameter(p); } if ( ! m_parentMacroManager->addMacroCommandToRecording(mc)) { delete mc; } } else { for (auto p : parameters) { delete p; } parameters.clear(); CaretLogSevere(errorMessage); } } else { for (auto p : parameters) { delete p; } parameters.clear(); } } /** * Called when a action group has an item triggered * * @param action * ActionGroup action that was triggered */ void WuQMacroSignalWatcher::actionGroupTriggered(QAction* action) { QActionGroup* actionGroup = qobject_cast(m_object); CaretAssert(actionGroup); int actionIndex(-1); QList actionList = actionGroup->actions(); for (int32_t i = 0; i < actionList.size(); i++) { if (actionList.at(i) == action) { actionIndex = i; break; } } const QString actionText((action != NULL) ? action->text() : ""); std::vector params = getCopyOfObjectParameters(); CaretAssert(params.size() >= 2); params[0]->setValue(actionText); params[1]->setValue(actionIndex); createAndSendMacroCommand(params); } /** * Called when an action is triggered * * @param checked * New checked status */ void WuQMacroSignalWatcher::actionTriggered(bool /*checked*/) { std::vector params = getCopyOfObjectParameters(); CaretAssert(params.size() >= 1); params[0]->setValue(""); createAndSendMacroCommand(params); } /** * Called when a checkable action is triggered * * @param checked * New checked status */ void WuQMacroSignalWatcher::actionCheckableTriggered(bool checked) { std::vector params = getCopyOfObjectParameters(); CaretAssert(params.size() >= 1); params[0]->setValue(checked); createAndSendMacroCommand(params); } /** * Called when a button group button is clicked * * @param button * Button that was clicked */ void WuQMacroSignalWatcher::buttonGroupButtonClicked(QAbstractButton* button) { QButtonGroup* buttonGroup = qobject_cast(m_object); CaretAssert(buttonGroup); int buttonIndex(-1); QList buttonList = buttonGroup->buttons(); for (int32_t i = 0; i < buttonList.size(); i++) { if (buttonList.at(i) == button) { buttonIndex = i; break; } } const QString buttonText((button != NULL) ? button->text() : ""); std::vector params = getCopyOfObjectParameters(); CaretAssert(params.size() >= 2); params[0]->setValue(buttonText); params[1]->setValue(buttonIndex); createAndSendMacroCommand(params); } /** * Called when a check box is clicked * * @param checked * New checked status */ void WuQMacroSignalWatcher::checkBoxClicked(bool checked) { std::vector params = getCopyOfObjectParameters(); CaretAssert(params.size() >= 1); params[0]->setValue(checked); createAndSendMacroCommand(params); } /** * Called when a combo box is activated * * @param index * Index of activated item */ void WuQMacroSignalWatcher::comboBoxActivated(int index) { QComboBox* comboBox = qobject_cast(m_object); CaretAssert(comboBox); QString text; if ((index >= 0) && (index < comboBox->count())) { text = comboBox->itemText(index); } std::vector params = getCopyOfObjectParameters(); CaretAssert(params.size() >= 2); params[0]->setValue(text); params[1]->setValue(index); createAndSendMacroCommand(params); } /** * Called when a spin box value is changed * * @param value * New value in double spin box */ void WuQMacroSignalWatcher::doubleSpinBoxValueChanged(double value) { std::vector params = getCopyOfObjectParameters(); CaretAssert(params.size() >= 1); params[0]->setValue(value); createAndSendMacroCommand(params); } /** * Called when a line edit has text edited * * @param text * New value of text in the line edit */ void WuQMacroSignalWatcher::lineEditTextEdited(const QString& text) { std::vector params = getCopyOfObjectParameters(); CaretAssert(params.size() >= 1); params[0]->setValue(text); createAndSendMacroCommand(params); } /** * Called when a macro widget action value is changed * * @param value * New value */ void WuQMacroSignalWatcher::macroWidgetActionValueChanged(const QVariant& value) { std::vector params = getCopyOfObjectParameters(); CaretAssert(params.size() >= 1); params[0]->setValue(value); createAndSendMacroCommand(params); } /** * Called when a list widget item is activated * * @param item * List widget item that was selected */ void WuQMacroSignalWatcher::listWidgetItemActivated(QListWidgetItem* item) { QListWidget* listWidget = qobject_cast(m_object); CaretAssert(listWidget); const int rowIndex = listWidget->row(item); const QString text((item != NULL) ? item->text() : ""); std::vector params = getCopyOfObjectParameters(); CaretAssert(params.size() >= 2); params[0]->setValue(text); params[1]->setValue(rowIndex); createAndSendMacroCommand(params); } /** * Called when a menu has an item triggered * * @param action * Menu action that was triggered */ void WuQMacroSignalWatcher::menuTriggered(QAction* action) { QMenu* menu = qobject_cast(m_object); CaretAssert(menu); int actionIndex(-1); QList actionList = menu->actions(); for (int32_t i = 0; i < actionList.size(); i++) { if (actionList.at(i) == action) { actionIndex = i; break; } } const QString text((action != NULL) ? action->text() : ""); std::vector params = getCopyOfObjectParameters(); CaretAssert(params.size() >= 2); params[0]->setValue(text); params[1]->setValue(actionIndex); createAndSendMacroCommand(params); } /** * Called when a push button is clicked * * @param checked * New checked status */ void WuQMacroSignalWatcher::pushButtonClicked(bool /*checked*/) { std::vector params = getCopyOfObjectParameters(); CaretAssert(params.size() >= 1); params[0]->setValue(""); createAndSendMacroCommand(params); } /** * Called when a checkable push button is clicked * * @param checked * New checked status */ void WuQMacroSignalWatcher::pushButtonCheckableClicked(bool checked) { std::vector params = getCopyOfObjectParameters(); CaretAssert(params.size() >= 1); params[0]->setValue(checked); createAndSendMacroCommand(params); } /** * Called when a radio button is clicked * * @param checked * New checked status */ void WuQMacroSignalWatcher::radioButtonClicked(bool checked) { std::vector params = getCopyOfObjectParameters(); CaretAssert(params.size() >= 1); params[0]->setValue(checked); createAndSendMacroCommand(params); } /** * Called when a slider value is changed * * @param value * New value */ void WuQMacroSignalWatcher::sliderValueChanged(int value) { std::vector params = getCopyOfObjectParameters(); CaretAssert(params.size() >= 1); params[0]->setValue(value); createAndSendMacroCommand(params); } /** * Called when a spin box value is changed * * @param value * New value */ void WuQMacroSignalWatcher::spinBoxValueChanged(int value) { std::vector params = getCopyOfObjectParameters(); CaretAssert(params.size() >= 1); params[0]->setValue(value); createAndSendMacroCommand(params); } /** * Called when a tab bar current tab is changed * * @param index * Index of the new selected tab */ void WuQMacroSignalWatcher::tabBarCurrentChanged(int index) { QTabBar* tabBar = qobject_cast(m_object); CaretAssert(tabBar); const QString tabText = tabBar->tabText(index); std::vector params = getCopyOfObjectParameters(); CaretAssert(params.size() >= 2); params[0]->setValue(tabText); params[1]->setValue(index); createAndSendMacroCommand(params); } /** * Called when a tab widget current tab is changed * * @param index * Index of the new selected tab */ void WuQMacroSignalWatcher::tabWidgetCurrentChanged(int index) { QTabWidget* tabWidget = qobject_cast(m_object); CaretAssert(tabWidget); const QString tabText = tabWidget->tabText(index); std::vector params = getCopyOfObjectParameters(); CaretAssert(params.size() >= 2); params[0]->setValue(tabText); params[1]->setValue(index); createAndSendMacroCommand(params); } /** * Called when a tool button is clicked * * @param checked * New check status */ void WuQMacroSignalWatcher::toolButtonClicked(bool /*checked*/) { std::vector params = getCopyOfObjectParameters(); CaretAssert(params.size() >= 1); params[0]->setValue(""); createAndSendMacroCommand(params); } /** * Called when a tool button is clicked * * @param checked * New check status */ void WuQMacroSignalWatcher::toolButtonCheckableClicked(bool checked) { std::vector params = getCopyOfObjectParameters(); CaretAssert(params.size() >= 1); params[0]->setValue(checked); createAndSendMacroCommand(params); } /** * @return String containing description of this signal watcher */ QString WuQMacroSignalWatcher::toString() const { QString s(m_objectName + " type=" + WuQMacroWidgetTypeEnum::toGuiName(m_objectType)); return s; } /** * @return A copy of the object's parameters */ std::vector WuQMacroSignalWatcher::getCopyOfObjectParameters() const { std::vector paramsCopy; for(auto p : m_objectParameters) { paramsCopy.push_back(new WuQMacroCommandParameter(*p)); } return paramsCopy; } connectome-workbench-1.4.2/src/GuiQt/WuQMacroSignalWatcher.h000066400000000000000000000106301360521144700237760ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_SIGNAL_WATCHER_H__ #define __WU_Q_MACRO_SIGNAL_WATCHER_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "WuQMacroWidgetTypeEnum.h" class QAbstractButton; class QAction; class QListWidgetItem; namespace caret { class WuQMacroCommand; class WuQMacroCommandParameter; class WuQMacroManager; class WuQMacroSignalWatcher : public QObject { Q_OBJECT public: static WuQMacroSignalWatcher* newInstance(WuQMacroManager* parentMacroManager, QObject* object, const QString& descriptiveName, const QString& toolTipTextOverride, QString& errorMessageOut); virtual ~WuQMacroSignalWatcher(); WuQMacroSignalWatcher(const WuQMacroSignalWatcher&) = delete; WuQMacroSignalWatcher& operator=(const WuQMacroSignalWatcher&) = delete; WuQMacroCommand* createMacroCommandWithDefaultParameters(QString& errorMessageOut) const; QString getObjectName() const; QString toString() const; QString getToolTip() const; private slots: void actionTriggered(bool); void actionCheckableTriggered(bool); void actionGroupTriggered(QAction* action); void buttonGroupButtonClicked(QAbstractButton* button); void checkBoxClicked(bool); void comboBoxActivated(int); void doubleSpinBoxValueChanged(double); void lineEditTextEdited(const QString&); void listWidgetItemActivated(QListWidgetItem*); void macroWidgetActionValueChanged(const QVariant& value); void menuTriggered(QAction* action); void pushButtonClicked(bool); void pushButtonCheckableClicked(bool); void radioButtonClicked(bool); void sliderValueChanged(int); void spinBoxValueChanged(int); void tabBarCurrentChanged(int); void tabWidgetCurrentChanged(int); void toolButtonClicked(bool); void toolButtonCheckableClicked(bool); void objectWasDestroyed(QObject* obj); void objectNameWasChanged(const QString& name); // ADD_NEW_METHODS_HERE private: WuQMacroSignalWatcher(WuQMacroManager* parentMacroManager, QObject* object, const WuQMacroWidgetTypeEnum::Enum objectType, const QString& descriptiveName, const QString& toolTipTextOverride); WuQMacroManager* m_parentMacroManager; void createAndSendMacroCommand(std::vector& parameters); std::vector getCopyOfObjectParameters() const; QObject* m_object; const WuQMacroWidgetTypeEnum::Enum m_objectType; const QString m_descriptiveName; const QString m_objectName; QString m_toolTipText; std::vector m_objectParameters; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_MACRO_SIGNAL_WATCHER_DECLARE__ // #endif // __WU_Q_MACRO_SIGNAL_WATCHER_DECLARE__ } // namespace #endif //__WU_Q_MACRO_SIGNAL_WATCHER_H__ connectome-workbench-1.4.2/src/GuiQt/WuQMacroWidgetAction.cxx000066400000000000000000000273311360521144700242050ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_MACRO_WIDGET_ACTION_DECLARE__ #include "WuQMacroWidgetAction.h" #undef __WU_Q_MACRO_WIDGET_ACTION_DECLARE__ #include #include #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "EventManager.h" using namespace caret; /** * \class caret::WuQMacroWidgetAction * \brief Like QWidgetAction but for use with widgets monitored by macro system but in dialogs * \ingroup GuiQt * * Widgets in modal dialogs exist only while the dialog is active. Widgets in non-modal * dialogs do not exist until the dialog is created. This presents a problem * when the macro executor wants to trigger the widget's signal but the widget does not * exist. This class is used by the macro system and an instance contains a signal corresponding * to a widget in a modal dialog. */ /** * Constructor. * * @param widgetType * Type of widget * @param objectName * Name of this object * @param objectToolTip * Tooltip for object * @param parent * Parent for object */ WuQMacroWidgetAction::WuQMacroWidgetAction(const WidgetType widgetType, const QString& objectName, const QString& objectToolTip, QObject* parent) : QObject(parent), m_widgetType(widgetType), m_toolTip(objectToolTip) { setObjectName(objectName); QObject::connect(this, &WuQMacroWidgetAction::valueChanged, this, &WuQMacroWidgetAction::setValuePrivate); // EventManager::get()->addEventListener(this, EventTypeEnum::); } /** * Destructor. */ WuQMacroWidgetAction::~WuQMacroWidgetAction() { EventManager::get()->removeAllEventsFromListener(this); } /** * @return The type of data value */ WuQMacroWidgetAction::WidgetType WuQMacroWidgetAction::getWidgetType() const { return m_widgetType; } /** * @return A widget the represents the action with the given parent. * Caller is responsibled for deleting the widget and must call * releaseWidget() prior to deleting the widget. * * @param Parent for the returned widget */ QWidget* WuQMacroWidgetAction::requestWidget(QWidget* parent) { QWidget* w(NULL); /* * Create widget and attach to signal */ switch (m_widgetType) { case WidgetType::CHECK_BOX_BOOLEAN: { QCheckBox* cb = new QCheckBox(parent); QObject::connect(cb, &QCheckBox::clicked, this, [=](bool checked) { emit valueChanged(checked); }); w = cb; } break; case WidgetType::COMBO_BOX_STRING_LIST: { QComboBox* cb = new QComboBox(parent); for (auto s : m_comboBoxStringListItems) { cb->addItem(s); } QObject::connect(cb, QOverload::of(&QComboBox::activated), this, [=](const QString& value) { emit valueChanged(value); } ); w = cb; } break; case WidgetType::LINE_EDIT_STRING: { QLineEdit* le = new QLineEdit(parent); QObject::connect(le, QOverload::of(&QLineEdit::textEdited), this, [=](const QString& value) { emit valueChanged(value); } ); w = le; } break; case WidgetType::SPIN_BOX_FLOAT: { QDoubleSpinBox* sb = new QDoubleSpinBox(parent); sb->setMinimum(m_spinBoxFloatMinMaxStep.m_minValue); sb->setMaximum(m_spinBoxFloatMinMaxStep.m_maxValue); sb->setSingleStep(m_spinBoxFloatMinMaxStep.m_step); sb->setDecimals(m_spinBoxFloatMinMaxStep.m_decimals); sb->setValue(sb->minimum()); QObject::connect(sb, QOverload::of(&QDoubleSpinBox::valueChanged), this, [=](const double value) { emit valueChanged(static_cast(value)); } ); w = sb; } break; case WidgetType::SPIN_BOX_INTEGER: { QSpinBox* sb = new QSpinBox(parent); sb->setMinimum(m_spinBoxIntegerMinMaxStep.m_minValue); sb->setMaximum(m_spinBoxIntegerMinMaxStep.m_maxValue); sb->setSingleStep(m_spinBoxIntegerMinMaxStep.m_step); sb->setValue(sb->minimum()); QObject::connect(sb, QOverload::of(&QSpinBox::valueChanged), this, [=](const int value) { emit valueChanged(value); } ); w = sb; } break; } CaretAssert(w); w->setToolTip(m_toolTip); w->setObjectName(objectName() + ":" + w->metaObject()->className()); m_widgets.insert(w); updateWidgetWithModelValue(w); return w; } /** * Release the specified widget. Any signals are disconnected * and this widget is no longer updated. The caller is * responsible for deleting the widget. * * It is okay to call this method with a widget * that belongs to another macro widget action * and in this case no action is taken. * * @return * True if the widget was monitored by this * macro widget action, otherwise false. */ bool WuQMacroWidgetAction::releaseWidget(QWidget* widget) { CaretAssert(widget); if (m_widgets.find(widget) != m_widgets.end()) { /* * Disconnect all signals in widget from 'this' */ QObject::disconnect(widget, 0, this, 0); m_widgets.erase(widget); //std::cout << "Released widget: " << widget->objectName() << std::endl; return true; } /* * If here, widget was not in this macro widget action */ return false; } /** * @return The tooltip */ QString WuQMacroWidgetAction::getToolTip() const { return m_toolTip; } /** * @return The name of the widget action */ QString WuQMacroWidgetAction::getName() const { return objectName(); } /** * Set the data value but DOES NOT emit valueChanged() signal * * @param value * New data value for widget action */ void WuQMacroWidgetAction::setDataValue(const QVariant& value) { for (auto w : m_widgets) { setWidgetValue(w, value); } } /** * Set the value and will emit the valueChanged signal * * @param value * New value. */ void WuQMacroWidgetAction::setValuePrivate(const QVariant& value) { for (auto w : m_widgets) { setWidgetValue(w, value); } emit setModelValue(value); } /** * Set a widget's value * * @param widget * The widget * @param value * Value for the widget */ void WuQMacroWidgetAction::setWidgetValue(QWidget* widget, const QVariant& value) { /* * Some widgets, such as spin box, will emit a signal * when its value is changed so block its signals */ QSignalBlocker sb(widget); switch (m_widgetType) { case WidgetType::CHECK_BOX_BOOLEAN: { QCheckBox* cb = qobject_cast(widget); CaretAssert(cb); cb->setChecked(value.toBool()); } break; case WidgetType::COMBO_BOX_STRING_LIST: { QComboBox* cb = qobject_cast(widget); CaretAssert(cb); cb->setCurrentText(value.toString()); } break; case WidgetType::LINE_EDIT_STRING: { QLineEdit* le = qobject_cast(widget); CaretAssert(le); le->setText(value.toString()); } break; case WidgetType::SPIN_BOX_FLOAT: { QDoubleSpinBox* sb = qobject_cast(widget); CaretAssert(sb); sb->setValue(value.toFloat()); } break; case WidgetType::SPIN_BOX_INTEGER: { QSpinBox* sb = qobject_cast(widget); CaretAssert(sb); sb->setValue(value.toInt()); } break; } } /** * May be called when a dialog is created or updated * to update the model value in the given widget * * @param widget * The widget * @return * True if widget was updated with model value */ bool WuQMacroWidgetAction::updateWidgetWithModelValue(QWidget* widget) { CaretAssert(widget); if (m_widgets.find(widget) != m_widgets.end()) { QVariant value; emit getModelValue(value); if (value.isNull()) { const QString msg("Value was not updated by model, need to connect getModelValue() signal"); CaretAssertMessage(0, msg); CaretLogSevere(msg); } else { setWidgetValue(widget, value); return true; } } return false; } /** * Receive an event. * * @param event * An event for which this instance is listening. */ void WuQMacroWidgetAction::receiveEvent(Event* /*event*/) { // if (event->getEventType() == EventTypeEnum::) { // eventName = dynamic_cast(event); // CaretAssert(eventName); // // event->setEventProcessed(); // } } /** * Setup widget that will be provided by the macro widget action * * @param comboBoxTextItems * Text items for combo box */ void WuQMacroWidgetAction::setComboBoxStringList(std::vector& comboBoxTextItems) { m_comboBoxStringListItems = comboBoxTextItems; } /** * Setup widget that will be provided by the macro widget action * * @param minValue * Minimum value for spin box * @param maxValue * Maximum value for spin box * @param step * Step value for spin box */ void WuQMacroWidgetAction::setSpinBoxMinMaxStep(const int32_t minValue, const int32_t maxValue, const int32_t step) { m_spinBoxIntegerMinMaxStep.m_minValue = minValue; m_spinBoxIntegerMinMaxStep.m_maxValue = maxValue; m_spinBoxIntegerMinMaxStep.m_step = step; } /** * Setup widget that will be provided by the macro widget action * * @param minValue * Minimum value for spin box * @param maxValue * Maximum value for spin box * @param step * Step value for spin box * @param decimals * Number of decimals right of decimal point */ void WuQMacroWidgetAction::setDoubleSpinBoxMinMaxStepDecimals(const double minValue, const double maxValue, const double step, const int32_t decimals) { m_spinBoxFloatMinMaxStep.m_minValue = minValue; m_spinBoxFloatMinMaxStep.m_maxValue = maxValue; m_spinBoxFloatMinMaxStep.m_step = step; m_spinBoxFloatMinMaxStep.m_decimals = decimals; } connectome-workbench-1.4.2/src/GuiQt/WuQMacroWidgetAction.h000066400000000000000000000120431360521144700236240ustar00rootroot00000000000000#ifndef __WU_Q_MACRO_WIDGET_ACTION_H__ #define __WU_Q_MACRO_WIDGET_ACTION_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "EventListenerInterface.h" #include "WuQMacroDataValueTypeEnum.h" namespace caret { // class ModelPropertySetGet { // public: // virtual QVariant getValue() const = 0; // virtual void setValue(const QVariant& value) = 0; // }; class WuQMacroWidgetAction : public QObject, public EventListenerInterface { Q_OBJECT public: /** * Type of widget */ enum class WidgetType { /** CheckBox for boolean value */ CHECK_BOX_BOOLEAN, /** Combo Box for string list selection */ COMBO_BOX_STRING_LIST, /** Line edit for text */ LINE_EDIT_STRING, /** Spin box for float value */ SPIN_BOX_FLOAT, /** Spin box for integer value */ SPIN_BOX_INTEGER }; WuQMacroWidgetAction(const WidgetType widgetType, const QString& objectName, const QString& objectToolTip, QObject* parent); static void initialize(std::map& namesAndTypes); static void destroy(); virtual ~WuQMacroWidgetAction(); WuQMacroWidgetAction(const WuQMacroWidgetAction&) = delete; WuQMacroWidgetAction& operator=(const WuQMacroWidgetAction&) = delete; QWidget* requestWidget(QWidget* parent); bool releaseWidget(QWidget* widget); WidgetType getWidgetType() const; QString getName() const; QString getToolTip() const; // ADD_NEW_METHODS_HERE virtual void receiveEvent(Event* event); void setDataValue(const QVariant& value); bool updateWidgetWithModelValue(QWidget* widget); void setComboBoxStringList(std::vector& comboBoxTextItems); void setSpinBoxMinMaxStep(const int32_t minValue, const int32_t maxValue, const int32_t step); void setDoubleSpinBoxMinMaxStepDecimals(const double minValue, const double maxValue, const double step, const int32_t decimals); signals: /** * Emitted when the value changes. Used by macro signal watcher. * * @param value * The new value */ void valueChanged(const QVariant& value); /** * Connect this signal to get the model's data value * * @param valueOut * Reference for signal receiver to set with model's data value */ void getModelValue(QVariant& valueOut); /** * Connect this signal to set the model's data value * * @param value * New value for model */ void setModelValue(const QVariant& value); private slots: void setValuePrivate(const QVariant& value); private: void setWidgetValue(QWidget* widget, const QVariant& value); const WidgetType m_widgetType; const QString m_toolTip; std::set m_widgets; std::vector m_comboBoxStringListItems; struct { int32_t m_minValue = 0; int32_t m_maxValue = 32000; int32_t m_step = 1; } m_spinBoxIntegerMinMaxStep; struct { double m_minValue = 0.0; double m_maxValue = 32000.0; double m_step = 1.0; int32_t m_decimals = 2; } m_spinBoxFloatMinMaxStep; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_MACRO_WIDGET_ACTION_DECLARE__ // #endif // __WU_Q_MACRO_WIDGET_ACTION_DECLARE__ } // namespace #endif //__WU_Q_MACRO_WIDGET_ACTION_H__ connectome-workbench-1.4.2/src/GuiQt/WuQMessageBox.cxx000066400000000000000000000650511360521144700227000ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretMappableDataFile.h" #include "FileInformation.h" #define __WU_QMESSAGE_DEFINE__ #include "WuQMessageBox.h" #undef __WU_QMESSAGE_DEFINE__ using namespace caret; /** * Constructor. * * @param parent * Parent on which message box is displayed. */ WuQMessageBox::WuQMessageBox(QWidget* parent) : QMessageBox(parent) { } /** * Destructor. */ WuQMessageBox::~WuQMessageBox() { } /** * Display a message box with the buttons Save, Discard, * and Cancel. Pressing the enter key is the equivalent of * pressing the Save button. * * @param parent * Parent on which message box is displayed. * @param text * Message that is displayed. * @param informativeText * Displayed below 'text' if this is not empty. * @return * QMessageBox::Save, QMessageBox::Discard, or QMessageBox::Cancel. */ QMessageBox::StandardButton WuQMessageBox::saveDiscardCancel(QWidget* parent, const QString& text, const QString& informativeText) { QMessageBox msgBox(parent); msgBox.setIcon(QMessageBox::Warning); msgBox.setWindowTitle(""); msgBox.setText(text); if (informativeText.isEmpty() == false) { msgBox.setInformativeText(informativeText); } msgBox.addButton(QMessageBox::Save); msgBox.addButton(QMessageBox::Discard); msgBox.addButton(QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Save); msgBox.setEscapeButton(QMessageBox::Cancel); QMessageBox::StandardButton buttonPressed = static_cast(msgBox.exec()); switch (buttonPressed) { case QMessageBox::Save: case QMessageBox::Discard: case QMessageBox::Cancel: break; default: CaretAssert(0); } return buttonPressed; } /** * Display a warning message box with Close and Cancel * buttons. Pressing the enter key is the equivalent * of pressing the Close button. * * @param parent * Parent on which message box is displayed. * @param text * Message that is displayed. * @param informativeText * Displayed below 'text' if this is not empty. * @return * true if the Close button was pressed else false * if the cancel button was pressed. */ bool WuQMessageBox::warningCloseCancel(QWidget* parent, const QString& text, const QString& informativeText) { QMessageBox msgBox(parent); msgBox.setIcon(QMessageBox::Warning); msgBox.setWindowTitle(""); msgBox.setText(text); if (informativeText.isEmpty() == false) { msgBox.setInformativeText(informativeText); } msgBox.addButton(QMessageBox::Close); msgBox.addButton(QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Close); msgBox.setEscapeButton(QMessageBox::Cancel); QMessageBox::StandardButton buttonPressed = static_cast(msgBox.exec()); bool closePressed = false; switch (buttonPressed) { case QMessageBox::Close: closePressed = true; break; case QMessageBox::Cancel: break; default: CaretAssert(0); break; } return closePressed; } /** * Display a warning message box with Ok and Cancel * buttons. Pressing the enter key is the equivalent * of pressing the Ok button. * * @param parent * Parent on which message box is displayed. * @param text * Message that is displayed. * @param informativeText * Displayed below 'text' if this is not empty. * @return * true if the Ok button was pressed else false * if the cancel button was pressed. */ bool WuQMessageBox::warningOkCancel(QWidget* parent, const QString& text, const QString& informativeText) { QMessageBox msgBox(parent); msgBox.setIcon(QMessageBox::Warning); msgBox.setWindowTitle(""); msgBox.setText(text); if (informativeText.isEmpty() == false) { msgBox.setInformativeText(informativeText); } msgBox.addButton(QMessageBox::Ok); msgBox.addButton(QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Ok); msgBox.setEscapeButton(QMessageBox::Cancel); QMessageBox::StandardButton buttonPressed = static_cast(msgBox.exec()); bool okPressed = false; switch (buttonPressed) { case QMessageBox::Ok: okPressed = true; break; case QMessageBox::Cancel: break; default: CaretAssert(0); break; } return okPressed; } /** * Display a warning message box with Yes and No * buttons. Pressing the enter key is the equivalent * of pressing the Yes button. * * @param parent * Parent on which message box is displayed. * @param text * Message that is displayed. * @param informativeText * Displayed below 'text' if this is not empty. * @return * true if the Yes button was pressed else false * if the No button was pressed. */ bool WuQMessageBox::warningYesNo(QWidget* parent, const QString& text, const QString& informativeText) { QMessageBox msgBox(parent); msgBox.setIcon(QMessageBox::Warning); msgBox.setWindowTitle(""); msgBox.setText(text); if (informativeText.isEmpty() == false) { msgBox.setInformativeText(informativeText); } msgBox.addButton(QMessageBox::Yes); msgBox.addButton(QMessageBox::No); msgBox.setDefaultButton(QMessageBox::Yes); msgBox.setEscapeButton(QMessageBox::No); QMessageBox::StandardButton buttonPressed = static_cast(msgBox.exec()); bool yesPressed = false; switch (buttonPressed) { case QMessageBox::Yes: yesPressed = true; break; case QMessageBox::No: break; default: CaretAssert(0); break; } return yesPressed; } /** * Display an error message box with the * given text and an OK button. * * @param parent * Parent on which message box is displayed. * @param text * Message that is displayed. */ void WuQMessageBox::warningOk(QWidget* parent, const QString& text) { QMessageBox msgBox(parent); msgBox.setIcon(QMessageBox::Warning); msgBox.setWindowTitle(""); msgBox.setText(text); msgBox.addButton(QMessageBox::Ok); msgBox.setDefaultButton(QMessageBox::Ok); msgBox.setEscapeButton(QMessageBox::Ok); msgBox.exec(); } /** * Display an error message box with the * given text and an OK button and a checkbox with * the text "Remember my choice and do not show this dialog". * * If the user closes the dialog with the "Do not show * again" box checked, the next time this function is * called with the dialog will not be displayed. * * @param parent * Parent on which message box is displayed. * @param uniqueIdentifier * Unique identifier used for associating of * "do not show" status * @param text * Message that is displayed. */ void WuQMessageBox::warningOkWithDoNotShowAgain(QWidget* parent, const QString& uniqueIdentifier, const QString& text) { /* * See if user previously selected "do not show again". * If so, do not display dialog and return. */ auto doNotShowStatus = s_doNotShowAgainButtonSelection.find(uniqueIdentifier); if (doNotShowStatus != s_doNotShowAgainButtonSelection.end()) { return; } QMessageBox msgBox(parent); msgBox.setIcon(QMessageBox::Warning); msgBox.setWindowTitle(""); msgBox.setText(text); msgBox.addButton(QMessageBox::Ok); msgBox.setDefaultButton(QMessageBox::Ok); msgBox.setEscapeButton(QMessageBox::Ok); QCheckBox* checkBox = addDoNotShowAgainCheckBox(msgBox); msgBox.exec(); /* * If the "do not show again" checkbox was checked, * save to do not show status. */ const bool doNotShowAgainFlag = checkBox->isChecked(); if (doNotShowAgainFlag) { s_doNotShowAgainButtonSelection.insert(std::make_pair(uniqueIdentifier, QMessageBox::NoButton)); } } /** * Add a "do not show again" checkbox to the given message checkbox. * * @param messageBox * Message box to which "do not show again" checkbox is added. * @return * Pointer to the checkbox (do not destroy as dialog closing * will handle checkbox destruction). */ QCheckBox* WuQMessageBox::addDoNotShowAgainCheckBox(QMessageBox& messageBox) { QCheckBox* checkBox = new QCheckBox("Remember my choice and do not show this dialog again"); messageBox.setCheckBox(checkBox); checkBox->setToolTip("Do not show again for this session (until wb_view is exited)"); return checkBox; } /** * Display a warning message box with Ok and Cancel * buttons. Pressing the enter key is the equivalent * of pressing the Ok button. * * @param parent * Parent on which message box is displayed. * @param text * Message that is displayed. * @return * true if the Ok button was pressed else false * if the cancel button was pressed. */ bool WuQMessageBox::warningOkCancel(QWidget* parent, const QString& text) { return WuQMessageBox::warningOkCancel(parent, text, ""); } /** * Display a "large file size" warning message box with Ok and Cancel * buttons. Some operations may be slow and this dialog is used * so that user can choose to cancel the operation. * * Pressing the enter key is the equivalent of pressing the Ok button. * * @param parent * Parent on which message box is displayed. * @return * true if the file is smaller than the "large size" and no dialog is displayed * true if the Ok button was pressed else false * if the cancel button was pressed. */ bool WuQMessageBox::warningLargeFileSizeOkCancel(QWidget* parent, const CaretMappableDataFile* caretMappableDataFile) { CaretAssert(caretMappableDataFile); /* * When files are "large", using all file data may take * a very long time so allow the user to cancel. */ const int64_t megabyte = 1000000; /* 10e6 */ const int64_t warningDataSize = 100 * megabyte; const int64_t dataSize = caretMappableDataFile->getDataSizeUncompressedInBytes(); bool resultFlag = true; if (dataSize > warningDataSize) { const int64_t gigabyte = 1000000000; /* 10e9 */ const int64_t numReallys = std::min(dataSize / gigabyte, (int64_t)10); AString veryString; if (numReallys > 0) { veryString = ("very" + QString(", very").repeated(numReallys - 1) + " "); } const AString message("File size is " + veryString + "large (" + FileInformation::fileSizeToStandardUnits(dataSize) + "). This operation may take a " + veryString + "long time."); resultFlag = WuQMessageBox::warningOkCancel(parent, message); } return resultFlag; } /** * Display a warning message box with Ok and Cancel * buttons and a checkbox. Pressing the enter key is * the equivalent of pressing the Ok button. * * @param parent * Parent on which message box is displayed. * @param text * Message that is displayed. * @param checkBoxText * Text for display in the checkbox. * @param checkBoxStatusInOut * Default status for checkbox and status of * checkbox upon exit * @return * true if the Ok button was pressed else false * if the cancel button was pressed. */ bool WuQMessageBox::warningYesNoWithDoNotShowAgain(QWidget* parent, const QString& uniqueIdentifier, const QString& text) { return WuQMessageBox::warningYesNoWithDoNotShowAgain(parent, uniqueIdentifier, text, ""); } /** * Display a warning message box with Yes and No * buttons and a checkbox with the text * "Remember my choice and do not show this dialog". * * If the user closes the dialog with the "Do not show * again" box checked, the next time this function is * called with the same "uniqueIdentifier" the dialog * will not be displayed and return the selection made * when the user last closed the dialog. * * @param parent * Parent on which message box is displayed. * @param uniqueIdentifier * Unique identifier used for associating of * "do not show" status * @param text * Message that is displayed. * @param informativeText * Displayed below 'text' if this is not empty. * @return * true if the Yes button was pressed false if * the NO button was pressed. */ bool WuQMessageBox::warningYesNoWithDoNotShowAgain(QWidget* parent, const QString& uniqueIdentifier, const QString& text, const QString& informativeText) { /* * See if user previously selected "do not show again". * If so, return the button that the user last clicked. */ QMessageBox::StandardButton doNotShowAgainButton = QMessageBox::NoButton; auto doNotShowStatus = s_doNotShowAgainButtonSelection.find(uniqueIdentifier); if (doNotShowStatus != s_doNotShowAgainButtonSelection.end()) { doNotShowAgainButton = doNotShowStatus->second; bool yesPressedFlag = false; switch (doNotShowAgainButton) { case QMessageBox::Yes: yesPressedFlag = true; break; case QMessageBox::No: yesPressedFlag = false; break; default: CaretAssert(0); break; } return yesPressedFlag; } /* * Display a message box dialog to the user */ QMessageBox msgBox(parent); msgBox.setIcon(QMessageBox::Warning); msgBox.setWindowTitle(""); msgBox.setText(text); if (informativeText.isEmpty() == false) { msgBox.setInformativeText(informativeText); } msgBox.addButton(QMessageBox::Yes); msgBox.addButton(QMessageBox::No); msgBox.setDefaultButton(QMessageBox::No); msgBox.setEscapeButton(QMessageBox::No); QCheckBox* checkBox = addDoNotShowAgainCheckBox(msgBox); const QMessageBox::StandardButton buttonClicked = static_cast(msgBox.exec()); bool yesPressedFlag = false; switch (buttonClicked) { case QMessageBox::Yes: yesPressedFlag = true; break; case QMessageBox::No: break; default: CaretAssert(0); break; } /* * If the "do not show again" checkbox was checked, * save the button that the user clicked. */ const bool doNotShowAgainFlag = checkBox->isChecked(); if (doNotShowAgainFlag) { if (doNotShowStatus != s_doNotShowAgainButtonSelection.end()) { doNotShowStatus->second = buttonClicked; } else { s_doNotShowAgainButtonSelection.insert(std::make_pair(uniqueIdentifier, buttonClicked)); } } return yesPressedFlag; } /** * Display an information dialog with two buttons, both of which * will close the dialog. * * @param parent * The parent dialog. * @param text * Text for the dialog. * @param buttonOneText * Text for the first button. * @param buttonTwoText * Text for the second button. * @return * 1 if button one clicked, 2 if button two clicked. */ int32_t WuQMessageBox::informationTwoButtons(QWidget* parent, const QString& text, const QString& buttonOneText, const QString& buttonTwoText) { QMessageBox msgBox(parent); msgBox.setIcon(QMessageBox::Information); msgBox.setWindowTitle(""); msgBox.setText(text); msgBox.addButton(QMessageBox::YesToAll); msgBox.addButton(QMessageBox::Yes); msgBox.setDefaultButton(QMessageBox::Yes); WuQMessageBox::updateButtonText(msgBox, QMessageBox::YesToAll, buttonOneText); WuQMessageBox::updateButtonText(msgBox, QMessageBox::Yes, buttonTwoText); QMessageBox::StandardButton buttonPressed = static_cast(msgBox.exec()); int32_t buttonClicked = 0; switch (buttonPressed) { case QMessageBox::YesToAll: buttonClicked = 1; break; case QMessageBox::Yes: buttonClicked = 2; break; default: CaretAssert(0); break; } return buttonClicked; } /** * Display a Yes to All, Yes, No, button dialog. * * @param parent * Parent on which message box is displayed. * @param yesToAllButtonText * Text for Yes to All button. If empty, * "Yes to All" is displayed in button. * @param yesButtonText * Text for Yes button. If empty, * "Yes" is displayed in button. * @param noButtonText * Text for No button. If empty, * "No" is displayed in button. * @param text * Message that is displayed. * @param informativeText * Displayed below 'text' if this is not empty. * @return * One of QMessageBox::YesToAll * QMessageBox::Yes * QMessageBox::No */ WuQMessageBox::YesToAllYesNoResult WuQMessageBox::warningYesToAllYesNo(QWidget* parent, const QString& yesToAllButtonText, const QString& yesButtonText, const QString& noButtonText, const QString& text, const QString& informativeText) { QMessageBox msgBox(parent); msgBox.setIcon(QMessageBox::Warning); msgBox.setWindowTitle(""); msgBox.setText(text); if (informativeText.isEmpty() == false) { msgBox.setInformativeText(informativeText); } msgBox.addButton(QMessageBox::YesToAll); msgBox.addButton(QMessageBox::Yes); msgBox.addButton(QMessageBox::No); msgBox.setDefaultButton(QMessageBox::Yes); msgBox.setEscapeButton(QMessageBox::No); WuQMessageBox::updateButtonText(msgBox, QMessageBox::YesToAll, yesToAllButtonText); WuQMessageBox::updateButtonText(msgBox, QMessageBox::Yes, yesButtonText); WuQMessageBox::updateButtonText(msgBox, QMessageBox::No, noButtonText); QMessageBox::StandardButton buttonPressed = static_cast(msgBox.exec()); YesToAllYesNoResult result = YesToAllYesNoResult::NO; switch (buttonPressed) { case QMessageBox::YesToAll: result = YesToAllYesNoResult::YES_TO_ALL; break; case QMessageBox::Yes: result = YesToAllYesNoResult::YES; break; case QMessageBox::No: result = YesToAllYesNoResult::NO; break; default: CaretAssert(0); break; } return result; } /** * Display a warning message box with the given * text and content for accept/reject buttons. * Pressing the enter key is the equivalent of * pressing the Ok button. * * @param parent * Parent on which message box is displayed. * @param text * Message that is displayed. * @param acceptButtonText * Text for "accept" button. * @param rejectButtonText * Text for "reject" button. * @return * true if the "accept" button was pressed or false * if the "reject" button was pressed. */ bool WuQMessageBox::warningAcceptReject(QWidget* parent, const QString& text, const QString& acceptButtonText, const QString& rejectButtonText) { QMessageBox msgBox(parent); msgBox.setIcon(QMessageBox::Warning); msgBox.setWindowTitle(""); msgBox.setText(text); msgBox.addButton(QMessageBox::Ok); msgBox.addButton(QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Ok); msgBox.setEscapeButton(QMessageBox::Cancel); updateButtonText(msgBox, QMessageBox::Ok, acceptButtonText); updateButtonText(msgBox, QMessageBox::Cancel, rejectButtonText); QMessageBox::StandardButton buttonPressed = static_cast(msgBox.exec()); bool acceptPressed = false; switch (buttonPressed) { case QMessageBox::Ok: acceptPressed = true; break; case QMessageBox::Cancel: break; default: CaretAssert(0); break; } return acceptPressed; } /** * Update the text for the standard button in the given message box. * * @param messageBox * The message box. * @param standardButton * The standard button type. * @param text * Text for the standard button. If empty, no action is taken. */ void WuQMessageBox::updateButtonText(QMessageBox& messageBox, const QMessageBox::StandardButton standardButton, const QString& text) { if (text.isEmpty()) { return; } QAbstractButton* button = messageBox.button(standardButton); CaretAssert(button); if (button == NULL) { CaretLogSevere("Invalid QMessageBox::StandardButton integer value: " + QString::number(static_cast(standardButton))); return; } button->setText(text); } /** * Display a warning message box with Yes and No * buttons. Pressing the enter key is the equivalent * of pressing the Yes button. * * @param parent * Parent on which message box is displayed. * @param text * Message that is displayed. * @return * true if the Yes button was pressed else false * if the No button was pressed. */ bool WuQMessageBox::warningYesNo(QWidget* parent, const QString& text) { return WuQMessageBox::warningYesNo(parent, text, ""); } /** * Display a warning message box with Yes, No, and Cancel * buttons. Pressing the enter key is the equivalent * of pressing the Yes button. * * @param parent * Parent on which message box is displayed. * @param text * Message that is displayed. * @return * true if the Yes button was pressed else false * if the No button was pressed. */ WuQMessageBox::YesNoCancelResult WuQMessageBox::warningYesNoCancel(QWidget* parent, const QString& text, const QString& informativeText) { QMessageBox msgBox(parent); msgBox.setIcon(QMessageBox::Warning); msgBox.setWindowTitle(""); msgBox.setText(text); if (informativeText.isEmpty() == false) { msgBox.setInformativeText(informativeText); } msgBox.addButton(QMessageBox::Yes); msgBox.addButton(QMessageBox::No); msgBox.addButton(QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Yes); msgBox.setEscapeButton(QMessageBox::No); QMessageBox::StandardButton buttonPressed = static_cast(msgBox.exec()); YesNoCancelResult result = RESULT_CANCEL; switch (buttonPressed) { case QMessageBox::Yes: result = RESULT_YES; break; case QMessageBox::No: result = RESULT_NO; break; case QMessageBox::Cancel: result = RESULT_CANCEL; break; default: CaretAssert(0); break; } return result; } /** * Display an information message box with the * given text and an OK button. * * @param parent * Parent on which message box is displayed. * @param text * Message that is displayed. */ void WuQMessageBox::informationOk(QWidget* parent, const QString& text) { QMessageBox msgBox(parent); msgBox.setIcon(QMessageBox::Information); msgBox.setWindowTitle(""); msgBox.setText(text); msgBox.addButton(QMessageBox::Ok); msgBox.setDefaultButton(QMessageBox::Ok); msgBox.setEscapeButton(QMessageBox::Ok); msgBox.exec(); } /** * Display an error message box with the * given text and an OK button. * * @param parent * Parent on which message box is displayed. * @param text * Message that is displayed. */ void WuQMessageBox::errorOk(QWidget* parent, const QString& text) { QMessageBox msgBox(parent); msgBox.setIcon(QMessageBox::Critical); msgBox.setWindowTitle(""); msgBox.setText(text); msgBox.addButton(QMessageBox::Ok); msgBox.setDefaultButton(QMessageBox::Ok); msgBox.setEscapeButton(QMessageBox::Ok); msgBox.exec(); } connectome-workbench-1.4.2/src/GuiQt/WuQMessageBox.h000066400000000000000000000136611360521144700223250ustar00rootroot00000000000000 #ifndef __WU_QMESSAGE_BOX_H__ #define __WU_QMESSAGE_BOX_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include class QCheckBox; namespace caret { class CaretMappableDataFile; class WuQMessageBox : public QMessageBox { Q_OBJECT public: enum YesNoCancelResult { RESULT_YES, RESULT_NO, RESULT_CANCEL }; enum class YesToAllYesNoResult { YES_TO_ALL, YES, NO }; static void errorOk(QWidget* parent, const QString& text); static void informationOk(QWidget* parent, const QString& text); static int32_t informationTwoButtons(QWidget* parent, const QString& text, const QString& buttonOneText, const QString& buttonTwoText); static void warningOk(QWidget* parent, const QString& text); static void warningOkWithDoNotShowAgain(QWidget* parent, const QString& uniqueIdentifier, const QString& text); static bool warningOkCancel(QWidget* parent, const QString& text); static bool warningYesNoWithDoNotShowAgain(QWidget* parent, const QString& uniqueIdentifier, const QString& text); static bool warningYesNo(QWidget* parent, const QString& text); static bool warningOkCancel(QWidget* parent, const QString& text, const QString& informativeText); static bool warningYesNoWithDoNotShowAgain(QWidget* parent, const QString& uniqueIdentifier, const QString& text, const QString& informativeText); static bool warningYesNo(QWidget* parent, const QString& text, const QString& informativeText); static YesNoCancelResult warningYesNoCancel(QWidget* parent, const QString& text, const QString& informativeText); static bool warningCloseCancel(QWidget* parent, const QString& text, const QString& informativeText); static QMessageBox::StandardButton saveDiscardCancel(QWidget* parent, const QString& text, const QString& informativeText); static YesToAllYesNoResult warningYesToAllYesNo(QWidget* parent, const QString& yesToAllButtonText, const QString& yesButtonText, const QString& noButtonText, const QString& text, const QString& informativeText); static bool warningAcceptReject(QWidget* parent, const QString& text, const QString& acceptButtonText, const QString& rejectButtonText); static bool warningLargeFileSizeOkCancel(QWidget* parent, const CaretMappableDataFile* caretMappableDataFile); private: WuQMessageBox(QWidget* parent = 0); ~WuQMessageBox(); WuQMessageBox(const WuQMessageBox&); WuQMessageBox& operator=(const WuQMessageBox&); static QCheckBox* addDoNotShowAgainCheckBox(QMessageBox& messageBox); static void updateButtonText(QMessageBox& messageBox, const QMessageBox::StandardButton standardButton, const QString& text); /* * Maintains "do not show again selections. * Key is unique identifier supplied by caller to a dialog. * Value is the button that was clicked. */ static std::map s_doNotShowAgainButtonSelection; }; #ifdef __WU_QMESSAGE_DEFINE__ std::map WuQMessageBox::s_doNotShowAgainButtonSelection; #endif // __WU_QMESSAGE_DEFINE__ } #endif // __WU_QMESSAGE_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/WuQSpecialIncrementDoubleSpinBox.cxx000066400000000000000000000061701360521144700265230ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __WU_Q_SPECIAL_INCREMENT_DOUBLE_SPIN_BOX_DECLARE__ #include "WuQSpecialIncrementDoubleSpinBox.h" #undef __WU_Q_SPECIAL_INCREMENT_DOUBLE_SPIN_BOX_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::WuQSpecialIncrementDoubleSpinBox * \brief A double spin box that allows customized processing of increment/decrement using a function object. * \ingroup GuiQt */ /** * Constructor. * * @param stepFunctionObject * Function object that processes increment and decrement requests. */ WuQSpecialIncrementDoubleSpinBox::WuQSpecialIncrementDoubleSpinBox(StepFunctionObject* stepFunctionObject) : QDoubleSpinBox(), m_stepFunctionObject(stepFunctionObject) { CaretAssert(stepFunctionObject); } /** * Destructor. */ WuQSpecialIncrementDoubleSpinBox::~WuQSpecialIncrementDoubleSpinBox() { } /** * Virtual function that is called whenever the user triggers a step. * The steps parameter indicates how many steps were taken, e.g. * Pressing Qt::Key_Down will trigger a call to stepBy(-1), whereas * pressing Qt::Key_Prior will trigger a call to stepBy(10). * * If you subclass QAbstractSpinBox you must reimplement this function. * Note that this function is called even if the resulting value will * be outside the bounds of minimum and maximum. It's this function's * job to handle these situations. * * @param steps * Number of steps */ void WuQSpecialIncrementDoubleSpinBox::stepBy(int steps) { const double previousValue = value(); // QString msg("Step " // + QString::number(steps) // + " current value " // + QString::number(previousValue)); double newValue = m_stepFunctionObject->getNewValue(previousValue, steps); newValue = std::min(newValue, maximum()); newValue = std::max(newValue, minimum()); if (newValue != previousValue) { blockSignals(true); setValue(newValue); blockSignals(false); // msg += (" new value " // + QString::number(value())); // std::cout << qPrintable(msg) << std::endl; emit valueChanged(newValue); emit valueChanged(text()); } } connectome-workbench-1.4.2/src/GuiQt/WuQSpecialIncrementDoubleSpinBox.h000066400000000000000000000040451360521144700261470ustar00rootroot00000000000000#ifndef __WU_Q_SPECIAL_INCREMENT_DOUBLE_SPIN_BOX_H__ #define __WU_Q_SPECIAL_INCREMENT_DOUBLE_SPIN_BOX_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include namespace caret { class WuQSpecialIncrementDoubleSpinBox : public QDoubleSpinBox { Q_OBJECT public: class StepFunctionObject { public: virtual double getNewValue(const double currentValue, const int steps) const = 0; }; WuQSpecialIncrementDoubleSpinBox(StepFunctionObject* stepFunctionObject); virtual ~WuQSpecialIncrementDoubleSpinBox(); virtual void stepBy(int steps); // ADD_NEW_METHODS_HERE private: WuQSpecialIncrementDoubleSpinBox(const WuQSpecialIncrementDoubleSpinBox&); WuQSpecialIncrementDoubleSpinBox& operator=(const WuQSpecialIncrementDoubleSpinBox&); StepFunctionObject* m_stepFunctionObject; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_SPECIAL_INCREMENT_DOUBLE_SPIN_BOX_DECLARE__ // #endif // __WU_Q_SPECIAL_INCREMENT_DOUBLE_SPIN_BOX_DECLARE__ } // namespace #endif //__WU_Q_SPECIAL_INCREMENT_DOUBLE_SPIN_BOX_H__ connectome-workbench-1.4.2/src/GuiQt/WuQSpinBox.cxx000066400000000000000000000026601360521144700222220ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_SPIN_BOX_DECLARE__ #include "WuQSpinBox.h" #undef __WU_Q_SPIN_BOX_DECLARE__ #include #include "CaretAssert.h" using namespace caret; #include /** * \class caret::WuQSpinBox * \brief Emits a signal when the return key is pressed * \ingroup GuiQt */ /** * Constructor. */ WuQSpinBox::WuQSpinBox() : QSpinBox() { } /** * Destructor. */ WuQSpinBox::~WuQSpinBox() { } void WuQSpinBox::keyPressEvent(QKeyEvent* event) { if (event->key() == Qt::Key_Return) { emit signalReturnPressed(); return; } QSpinBox::keyPressEvent(event); } connectome-workbench-1.4.2/src/GuiQt/WuQSpinBox.h000066400000000000000000000031241360521144700216430ustar00rootroot00000000000000#ifndef __WU_Q_SPIN_BOX_H__ #define __WU_Q_SPIN_BOX_H__ /*LICENSE_START*/ /* * Copyright (C) 2019 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include namespace caret { class WuQSpinBox : public QSpinBox { Q_OBJECT public: WuQSpinBox(); virtual ~WuQSpinBox(); WuQSpinBox(const WuQSpinBox&) = delete; WuQSpinBox& operator=(const WuQSpinBox&) = delete; // ADD_NEW_METHODS_HERE signals: void signalReturnPressed(); protected: void keyPressEvent(QKeyEvent* event) override; private: // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_SPIN_BOX_DECLARE__ // #endif // __WU_Q_SPIN_BOX_DECLARE__ } // namespace #endif //__WU_Q_SPIN_BOX_H__ connectome-workbench-1.4.2/src/GuiQt/WuQSpinBoxGroup.cxx000066400000000000000000000075021360521144700232370ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_SPIN_BOX_GROUP_DECLARE__ #include "WuQSpinBoxGroup.h" #undef __WU_Q_SPIN_BOX_GROUP_DECLARE__ #include #include using namespace caret; /** * \class caret::WuQSpinBoxGroup * \brief Container that organizes a group of spin boxes. * * Container that organizes a group of spin boxes. */ /** * Constructor. * @param parent * Parent of this container. */ WuQSpinBoxGroup::WuQSpinBoxGroup(QObject* parent) : QObject(parent) { } /** * Destructor. */ WuQSpinBoxGroup::~WuQSpinBoxGroup() { for (std::vector::iterator iter = this->spinBoxReceivers.begin(); iter != this->spinBoxReceivers.end(); iter++) { delete *iter; } this->spinBoxReceivers.clear(); } /** * Add a spin box to this spin box group. * @param abstractSpinBox * Spin box that is added. */ void WuQSpinBoxGroup::addSpinBox(QAbstractSpinBox* abstractSpinBox) { SpinBoxReceiver* sbr = new SpinBoxReceiver(this, abstractSpinBox, this->spinBoxReceivers.size()); this->spinBoxReceivers.push_back(sbr); } /** * Called when double spin box value is changed. * @param doubleSpinBox * Double spin box that had its value changed. * @param d * New value. */ void WuQSpinBoxGroup::doubleSpinBoxChangeReceiver(QDoubleSpinBox* doubleSpinBox, const double d) { emit doubleSpinBoxValueChanged(doubleSpinBox, d); } /** * Called when spin box value is changed. * @param spinBox * Spin box that had its value changed. * @param i * New value. */ void WuQSpinBoxGroup::spinBoxChangeReceiver(QSpinBox* spinBox, const int i) { emit spinBoxValueChanged(spinBox, i); } //------------------------------------------------------------ SpinBoxReceiver::SpinBoxReceiver(WuQSpinBoxGroup* spinBoxGroup, QAbstractSpinBox* abstractSpinBox, const int spinBoxIndex) { this->spinBoxGroup = spinBoxGroup; this->spinBoxIndex = spinBoxIndex; this->spinBox = qobject_cast(abstractSpinBox); if (this->spinBox != NULL) { QObject::connect(this->spinBox, SIGNAL(valueChanged(int)), this, SLOT(valueChangedSlot(int))); } this->doubleSpinBox = qobject_cast(abstractSpinBox); if (this->doubleSpinBox != NULL) { QObject::connect(this->doubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(valueChangedSlot(double))); } } SpinBoxReceiver::~SpinBoxReceiver() { } void SpinBoxReceiver::valueChangedSlot(int i) { this->spinBoxGroup->spinBoxChangeReceiver(this->spinBox, i); } void SpinBoxReceiver::valueChangedSlot(double d) { this->spinBoxGroup->doubleSpinBoxChangeReceiver(this->doubleSpinBox, d); } connectome-workbench-1.4.2/src/GuiQt/WuQSpinBoxGroup.h000066400000000000000000000067031360521144700226660ustar00rootroot00000000000000#ifndef __WU_Q_SPIN_BOX_GROUP__H_ #define __WU_Q_SPIN_BOX_GROUP__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include class QAbstractSpinBox; class QDoubleSpinBox; class QSpinBox; namespace caret { class AString; class SpinBoxReceiver; class WuQSpinBoxGroup : public QObject { Q_OBJECT public: WuQSpinBoxGroup(QObject* parent); virtual ~WuQSpinBoxGroup(); void addSpinBox(QAbstractSpinBox* abstractSpinBox); signals: /** * Emitted when a QSpinBox has its value changed. * @param spinBox * Spin box that had its value changed. * @param i * New value from spin box. */ void spinBoxValueChanged(QSpinBox* spinBox, const int i); /** * Emitted when a QDoubleSpinBox has its value changed. * @param doubleSpinBox * Double spin box that had its value changed. * @param d * New value from spin box. */ void doubleSpinBoxValueChanged(QDoubleSpinBox* doubleSpinBox, const double d); //void valueChanged(const AString& text); private: WuQSpinBoxGroup(const WuQSpinBoxGroup&); WuQSpinBoxGroup& operator=(const WuQSpinBoxGroup&); std::vector spinBoxReceivers; void doubleSpinBoxChangeReceiver(QDoubleSpinBox* doubleSpinBox, const double d); void spinBoxChangeReceiver(QSpinBox* spinBox, const int i); friend class SpinBoxReceiver; }; class SpinBoxReceiver : public QObject { Q_OBJECT public: SpinBoxReceiver(WuQSpinBoxGroup* spinBoxGroup, QAbstractSpinBox* abstractSpinBox, const int indx); ~SpinBoxReceiver(); private slots: void valueChangedSlot(int i); void valueChangedSlot(double d); private: SpinBoxReceiver(const SpinBoxReceiver&); SpinBoxReceiver& operator=(const SpinBoxReceiver&); WuQSpinBoxGroup* spinBoxGroup; QSpinBox* spinBox; QDoubleSpinBox* doubleSpinBox; int spinBoxIndex; }; #ifdef __WU_Q_SPIN_BOX_GROUP_DECLARE__ // #endif // __WU_Q_SPIN_BOX_GROUP_DECLARE__ } // namespace #endif //__WU_Q_SPIN_BOX_GROUP__H_ connectome-workbench-1.4.2/src/GuiQt/WuQSpinBoxOddValue.cxx000066400000000000000000000175351360521144700236550ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /* Qt License is included since the API is copied from QSpinBox */ /**************************************************************************** ** ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #define __WU_Q_SPIN_BOX_ODD_VALUE_DECLARE__ #include "WuQSpinBoxOddValue.h" #undef __WU_Q_SPIN_BOX_ODD_VALUE_DECLARE__ #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "MathFunctions.h" using namespace caret; /** * \class caret::WuQSpinBoxOddValue * \brief Spin box that allows only odd values * \ingroup GuiQt * * Creates a spin box that allows only odd values. * Any attempts to set the value to an event value * or any attempts to set other parameters that * would cause an even value are ignored. To * ensure only odd values, enter of text is disabled. */ /** * Constructor. */ WuQSpinBoxOddValue::WuQSpinBoxOddValue(QObject* parent) : WuQWidget(parent) { m_spinBox = new WuQSpinBoxOddValueSpinBox(); m_spinBox->setMinimum(-99999999); m_spinBox->setMaximum( 99999999); m_spinBox->setSingleStep(2); } /** * Destructor. */ WuQSpinBoxOddValue::~WuQSpinBoxOddValue() { } /** * Return the enapsulated widget so that it can be added * to a layout */ QWidget* WuQSpinBoxOddValue::getWidget() { return m_spinBox; } /** * @return The minimum value allowed in the spin box. */ int WuQSpinBoxOddValue::minimum() const { return m_spinBox->minimum(); } /** * @return The maximum value allowed in the spin box. */ int WuQSpinBoxOddValue::maximum() const { return m_spinBox->maximum(); } /** * Set the minimum value. If the value is even, no action is taken. * * @param min * New minimum value. */ void WuQSpinBoxOddValue::setMinimum(int min) { if (MathFunctions::isEvenNumber(min)) { const AString msg = "Value passed to WuQSpinBoxOddValue::setMinimum MUST BE AN ODD NUMBER"; CaretAssertMessage(0, msg); CaretLogSevere(msg); return; } m_spinBox->setMinimum(min); } /** * Set the maximum value. If the value is even, no action is taken. * * @param min * New maximum value. */ void WuQSpinBoxOddValue::setMaximum(int max) { if (MathFunctions::isEvenNumber(max)) { const AString msg = "Value passed to WuQSpinBoxOddValue::setMaximum MUST BE AN ODD NUMBER"; CaretAssertMessage(0, msg); CaretLogSevere(msg); return; } m_spinBox->setMaximum(max); } /** * Set the range of values. * * @param minimum * New minimum value. If the value is even, no action is taken. * @param maximum * New maximum value. If the value is even, no action is taken. */ void WuQSpinBoxOddValue::setRange(int minimum, int maximum) { setMinimum(minimum); setMaximum(maximum); } /** * @return The step value when the user presses the up or down arrow. */ int WuQSpinBoxOddValue::singleStep() const { return m_spinBox->singleStep(); } /** * Set the step value for when the up or down arrow is pressed. * If the value is odd, no action is taken since the spin box * must change value by 2 so that the value remains odd. * * @param val * New step value. */ void WuQSpinBoxOddValue::setSingleStep(int val) { if (MathFunctions::isOddNumber(val)) { const AString msg = ("Value passed to WuQSpinBoxOddValue::setMaximum MUST BE AN EVEN NUMBER " "so that incrementing and decrementing preserves an odd value in the " "spin box."); CaretAssertMessage(0, msg); CaretLogSevere(msg); return; } m_spinBox->setSingleStep(val); } /** * @return The value in the spin box. */ int WuQSpinBoxOddValue::value() const { return m_spinBox->value(); } /** * Set the value. If the value is even, no action is taken. * * @param val * New value. */ void WuQSpinBoxOddValue::setValue(int val) { if (MathFunctions::isEvenNumber(val)) { const AString msg = "Value passed to WuQSpinBoxOddValue::setValue MUST BE AN ODD NUMBER"; CaretAssertMessage(0, msg); CaretLogSevere(msg); return; } m_spinBox->setValue(val); } /* -----------------------------------------------------------------------*/ /** * \class caret::WuQSpinBoxOddValueSpinBox * \brief Spin Box used by WuQSpinBoxOddValue * \ingroup GuiQt * * Spin Box used by WuQSpinBoxOddValue. * This is intended only for use by WuQSpinBoxOddValue * and it is simply a QSpinBox with its line edit * disabled. Disabling the line edit is a protected * functions in QSpinBox and that is the only reason * this class exists. */ /** * Constructor. * * @param parent * Optional parent widget. */ WuQSpinBoxOddValueSpinBox::WuQSpinBoxOddValueSpinBox(QWidget* parent) : QSpinBox(parent) { lineEdit()->setEnabled(false); } /** * Destructor. */ WuQSpinBoxOddValueSpinBox::~WuQSpinBoxOddValueSpinBox() { } int WuQSpinBoxOddValueSpinBox::valueFromText(const QString& text) const { bool validFlag = false; int value = text.toInt(&validFlag); if (MathFunctions::isEvenNumber(value)) { if (value > 0) { value = value - 1; } else if (value < 0) { value = value + 1; } } return value; } connectome-workbench-1.4.2/src/GuiQt/WuQSpinBoxOddValue.h000066400000000000000000000106031360521144700232670ustar00rootroot00000000000000#ifndef __WU_Q_SPIN_BOX_ODD_VALUE_H__ #define __WU_Q_SPIN_BOX_ODD_VALUE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /* Qt License is included since the API is copied from QSpinBox */ /**************************************************************************** ** ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "WuQWidget.h" #include namespace caret { class WuQSpinBoxOddValueSpinBox : public QSpinBox { public: WuQSpinBoxOddValueSpinBox(QWidget* parent = 0); virtual ~WuQSpinBoxOddValueSpinBox(); protected: virtual int valueFromText(const QString& text) const; }; class WuQSpinBoxOddValue : public WuQWidget { Q_OBJECT public: WuQSpinBoxOddValue(QObject* parent); virtual ~WuQSpinBoxOddValue(); virtual QWidget* getWidget(); int minimum() const; int maximum() const; void setMinimum(int min); void setMaximum(int max); void setRange(int minimum, int maximum); int singleStep() const; void setSingleStep(int val); int value() const; // ADD_NEW_METHODS_HERE signals: void valueChanged(int i); public slots: void setValue(int val); private: WuQSpinBoxOddValue(const WuQSpinBoxOddValue&); WuQSpinBoxOddValue& operator=(const WuQSpinBoxOddValue&); QSpinBox* m_spinBox; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_SPIN_BOX_ODD_VALUE_DECLARE__ // #endif // __WU_Q_SPIN_BOX_ODD_VALUE_DECLARE__ } // namespace #endif //__WU_Q_SPIN_BOX_ODD_VALUE_H__ connectome-workbench-1.4.2/src/GuiQt/WuQTabBar.cxx000066400000000000000000000032771360521144700220000ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_TAB_BAR_DECLARE__ #include "WuQTabBar.h" #undef __WU_Q_TAB_BAR_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::WuQTabBar * \brief Overrides and adds capabilities to QTabBar * \ingroup GuiQt */ /** * Constructor. */ WuQTabBar::WuQTabBar(QWidget* parent) : QTabBar(parent) { } /** * Destructor. */ WuQTabBar::~WuQTabBar() { } /** * Overrides parent widget's method to emit mousePressedSignal. * * @param event * The mouse event. */ void WuQTabBar::mousePressEvent(QMouseEvent* event) { emit mousePressedSignal(); QTabBar::mousePressEvent(event); } /** * Overrides parent widget's method to emit mouseReleaseSignal. * * @param event * The mouse event. */ void WuQTabBar::mouseReleaseEvent(QMouseEvent* event) { emit mouseReleasedSignal(); QTabBar::mouseReleaseEvent(event); } connectome-workbench-1.4.2/src/GuiQt/WuQTabBar.h000066400000000000000000000033371360521144700214220ustar00rootroot00000000000000#ifndef __WU_Q_TAB_BAR_H__ #define __WU_Q_TAB_BAR_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include namespace caret { class WuQTabBar : public QTabBar { Q_OBJECT public: WuQTabBar(QWidget* parent = 0); virtual ~WuQTabBar(); WuQTabBar(const WuQTabBar&) = delete; WuQTabBar& operator=(const WuQTabBar&) = delete; // ADD_NEW_METHODS_HERE signals: void mousePressedSignal(); void mouseReleasedSignal(); protected: virtual void mousePressEvent(QMouseEvent* event) override; virtual void mouseReleaseEvent(QMouseEvent* event) override; private: // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_TAB_BAR_DECLARE__ // #endif // __WU_Q_TAB_BAR_DECLARE__ } // namespace #endif //__WU_Q_TAB_BAR_H__ connectome-workbench-1.4.2/src/GuiQt/WuQTabWidget.cxx000066400000000000000000000164371360521144700225210ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #define __WU_Q_TAB_WIDGET_DECLARE__ #include "WuQTabWidget.h" #undef __WU_Q_TAB_WIDGET_DECLARE__ #include "SceneClass.h" using namespace caret; /** * \class caret::WuQTabWidget * \brief Replaces QTabWidget and allows the tab to be aligned. * * On some platforms, the tabs are centered, and when the tab widget * is wide an in a scrollable area it is sometimes difficult to find the * tabs. So, this tab widget allows the tab bar placed at a defined * alignment. */ /** * Constructor. * @param alignment * Aligment of the tab. * @param parent * Parent of this instance. */ WuQTabWidget::WuQTabWidget(const TabAlignment alignment, QObject* parent) : WuQWidget(parent) { m_tabBar = new QTabBar(); QObject::connect(m_tabBar, SIGNAL(currentChanged(int)), this, SLOT(tabBarCurrentIndexChanged(int))); m_stackedWidget = new QStackedWidget(); QHBoxLayout* tabBarLayout = new QHBoxLayout(); Qt::Alignment tabBarAlignment = Qt::AlignLeft; switch (alignment) { case TAB_ALIGN_CENTER: tabBarAlignment = Qt::AlignHCenter; break; case TAB_ALIGN_LEFT: tabBarAlignment = Qt::AlignLeft; break; case TAB_ALIGN_RIGHT: tabBarAlignment = Qt::AlignRight; break; } tabBarLayout->addWidget(m_tabBar, 100, tabBarAlignment); tabBarLayout->setMargin(0); QGroupBox* stackedWidgetGroupBox = new QGroupBox(); QVBoxLayout* groupBoxLayout = new QVBoxLayout(stackedWidgetGroupBox); groupBoxLayout->addWidget(m_stackedWidget); m_widget = new QWidget(); QVBoxLayout* verticalLayout = new QVBoxLayout(m_widget); QMargins margins = verticalLayout->contentsMargins(); margins.setLeft(0); margins.setRight(0); verticalLayout->setContentsMargins(margins); verticalLayout->setSpacing(3); verticalLayout->addLayout(tabBarLayout, 0); verticalLayout->addWidget(stackedWidgetGroupBox, 0, tabBarAlignment); verticalLayout->addStretch(); } /** * Destructor. */ WuQTabWidget::~WuQTabWidget() { } /** * @return The embedded widget. */ QWidget* WuQTabWidget::getWidget() { return m_widget; } /** * @return The embedded tab bar */ QTabBar* WuQTabWidget::getTabBar() const { return m_tabBar; } /** * Adds a tab with the given page and label to the tab widget, and returns * the index of the tab in the tab bar. If the tab's label contains an * ampersand, the letter following the ampersand is used as a shortcut * for the tab, e.g. if the label is "Bro&wse" then Alt+W becomes a * shortcut which will move the focus to this tab. * * @param page * New page that is added (must not be NULL). * @param label * Label displayed in the page's tab. */ void WuQTabWidget::addTab(QWidget* page, const QString& label) { m_tabBar->addTab(label); m_stackedWidget->addWidget(page); } /** * Called when the tab bar changes the current widget. * @param index * Index of selected widget. */ void WuQTabWidget::tabBarCurrentIndexChanged(int index) { setCurrentIndex(index); emit currentChanged(index); } /** * @return Returns the index position of the current tab page. * The current index is -1 if there is no current widget. */ int WuQTabWidget::currentIndex() const { return m_tabBar->currentIndex(); } /** * @return Returns a pointer to the page currently being displayed by the * tab dialog. The tab dialog does its best to make sure that this value * is never 0 (but if you try hard enough, it can be). */ QWidget* WuQTabWidget::currentWidget() const { return m_stackedWidget->currentWidget(); } //signals: //void currentChanged(int index); /** * Makes widget at the given index the current widget. The widget used must * be a page in this tab widget. */ void WuQTabWidget::setCurrentIndex(int index) { m_tabBar->blockSignals(true); m_tabBar->setCurrentIndex(index); m_tabBar->blockSignals(false); m_stackedWidget->setCurrentIndex(index); } /** * Makes widget the current widget. The widget used must be a page in * this tab widget. */ void WuQTabWidget::setCurrentWidget(QWidget* widget) { const int indx = m_stackedWidget->indexOf(widget); if (indx > 0) { m_tabBar->blockSignals(true); m_tabBar->setCurrentIndex(indx); m_tabBar->blockSignals(false); } } /** * Create a scene for an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @return Pointer to SceneClass object representing the state of * this object. Under some circumstances a NULL pointer may be * returned. Caller will take ownership of returned object. */ SceneClass* WuQTabWidget::saveToScene(const SceneAttributes* /*sceneAttributes*/, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "WuQTabWidget", 1); AString tabName; const int32_t selectedTabIndex = currentIndex(); if (selectedTabIndex >= 0) { tabName = m_tabBar->tabText(selectedTabIndex); } sceneClass->addString("selectedTabName", tabName); return sceneClass; } /** * Restore the state of an instance of a class. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * SceneClass containing the state that was previously * saved and should be restored. */ void WuQTabWidget::restoreFromScene(const SceneAttributes* /*sceneAttributes*/, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } const AString tabName = sceneClass->getStringValue("selectedTabName"); const int32_t numTabs = m_tabBar->count(); for (int32_t i = 0; i < numTabs; i++) { if (m_tabBar->tabText(i) == tabName) { setCurrentIndex(i); break; } } } connectome-workbench-1.4.2/src/GuiQt/WuQTabWidget.h000066400000000000000000000052151360521144700221360ustar00rootroot00000000000000#ifndef __WU_Q_TAB_WIDGET__H_ #define __WU_Q_TAB_WIDGET__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WuQWidget.h" #include "SceneableInterface.h" class QTabBar; class QStackedWidget; namespace caret { class WuQTabWidget : public WuQWidget, public SceneableInterface { Q_OBJECT public: enum TabAlignment { TAB_ALIGN_LEFT, TAB_ALIGN_CENTER, TAB_ALIGN_RIGHT }; WuQTabWidget(const TabAlignment alignment, QObject* parent); virtual ~WuQTabWidget(); QWidget* getWidget(); void addTab(QWidget* page, const QString& label); int currentIndex() const; QWidget* currentWidget() const; QTabBar* getTabBar() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); signals: void currentChanged(int index); public slots: void setCurrentIndex(int index); void setCurrentWidget(QWidget* widget); private slots: void tabBarCurrentIndexChanged(int index); private: WuQTabWidget(const WuQTabWidget&); WuQTabWidget& operator=(const WuQTabWidget&); QTabBar* m_tabBar; QStackedWidget* m_stackedWidget; QWidget* m_widget; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_TAB_WIDGET_DECLARE__ // #endif // __WU_Q_TAB_WIDGET_DECLARE__ } // namespace #endif //__WU_Q_TAB_WIDGET__H_ connectome-workbench-1.4.2/src/GuiQt/WuQTabWidgetWithSizeHint.cxx000066400000000000000000000042561360521144700250270ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_TAB_WIDGET_WITH_SIZE_HINT_DECLARE__ #include "WuQTabWidgetWithSizeHint.h" #undef __WU_Q_TAB_WIDGET_WITH_SIZE_HINT_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::WuQTabWidgetWithSizeHint * \brief A QTabWidget that allows user to set size hint width or height * \ingroup GuiQt */ /** * Constructor. * * @param parent * Optional parent widget. */ WuQTabWidgetWithSizeHint::WuQTabWidgetWithSizeHint(QWidget* parent) : QTabWidget(parent) { } /** * Destructor. */ WuQTabWidgetWithSizeHint::~WuQTabWidgetWithSizeHint() { } /** * Set the size hint width (non-positive uses default size hint for width) * * @param width * Width for size hint. */ void WuQTabWidgetWithSizeHint::setSizeHintWidth(const int width) { m_sizeHintWidth = width; } /** * Set the size hint height (non-positive uses default size hint for height) * * @param height * Height for size hint. */ void WuQTabWidgetWithSizeHint::setSizeHintHeight(const int height) { m_sizeHintHeight = height; } /** * @return Recommended size for this widget. */ QSize WuQTabWidgetWithSizeHint::sizeHint() const { QSize sh = QTabWidget::sizeHint(); if (m_sizeHintWidth > 0) { sh.setWidth(m_sizeHintWidth); } if (m_sizeHintHeight > 0) { sh.setHeight(m_sizeHintHeight); } return sh; } connectome-workbench-1.4.2/src/GuiQt/WuQTabWidgetWithSizeHint.h000066400000000000000000000036361360521144700244550ustar00rootroot00000000000000#ifndef __WU_Q_TAB_WIDGET_WITH_SIZE_HINT_H__ #define __WU_Q_TAB_WIDGET_WITH_SIZE_HINT_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include namespace caret { class WuQTabWidgetWithSizeHint : public QTabWidget { Q_OBJECT public: WuQTabWidgetWithSizeHint(QWidget* parent = 0); virtual ~WuQTabWidgetWithSizeHint(); void setSizeHintWidth(const int width); void setSizeHintHeight(const int height); virtual QSize sizeHint() const override; WuQTabWidgetWithSizeHint(const WuQTabWidgetWithSizeHint&) = delete; WuQTabWidgetWithSizeHint& operator=(const WuQTabWidgetWithSizeHint&) = delete; // ADD_NEW_METHODS_HERE private: int m_sizeHintWidth = -1; int m_sizeHintHeight = -1; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_TAB_WIDGET_WITH_SIZE_HINT_DECLARE__ // #endif // __WU_Q_TAB_WIDGET_WITH_SIZE_HINT_DECLARE__ } // namespace #endif //__WU_Q_TAB_WIDGET_WITH_SIZE_HINT_H__ connectome-workbench-1.4.2/src/GuiQt/WuQTextEditorDialog.cxx000066400000000000000000000120671360521144700240550ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_TEXT_EDITOR_DIALOG_DECLARE__ #include "WuQTextEditorDialog.h" #undef __WU_Q_TEXT_EDITOR_DIALOG_DECLARE__ #include #include #include #include #include "CaretAssert.h" #include "WuQtUtilities.h" using namespace caret; /** * \class caret::WuQTextEditorDialog * \brief Dialog that shows a text editor. * \ingroup GuiQt */ /** * Run the dialog in non-modal (non-blocking) mode. * Since non-modal and no way to retrieve text, the * text is not editable. * * @param dialogTitle * Title for dialog. * @param text * Text displayed in text editor. * @param textMode * Text mode (html or plain) * @param wrapMode * Text wrapping (no, yes) * @param parent * The parent widget on which dialog is displayed. */ void WuQTextEditorDialog::runNonModal(const QString& dialogTitle, const QString& text, const TextMode textMode, const WrapMode wrapMode, QWidget* parent) { WuQTextEditorDialog* dialog = new WuQTextEditorDialog(dialogTitle, text, TextReadOnlyMode::YES, textMode, wrapMode, parent); /* * Since dialog is non-modal, setting this attribute * will destroy the dialog when the dialog is closed * and prevent a memory leak. */ dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->setVisible(true); dialog->show(); dialog->activateWindow(); dialog->raise(); } /** * Constructor. * * @param dialogTitle * Title for dialog. * @param text * Text displayed in text editor. * @param readOnlyMode * Read only mode (no, yes) * @param textMode * Text mode (html or plain) * @param wrapMode * Text wrapping (no, yes) * @param parent * The parent widget on which dialog is displayed. */ WuQTextEditorDialog::WuQTextEditorDialog(const QString& dialogTitle, const QString& text, const TextReadOnlyMode readOnlyMode, const TextMode textMode, const WrapMode wrapMode, QWidget* parent) : QDialog(parent) { setWindowTitle(dialogTitle); m_textEdit = new QTextEdit(); switch (textMode) { case TextMode::HTML: m_textEdit->setHtml(text); break; case TextMode::PLAIN: m_textEdit->setPlainText(text); break; } switch (readOnlyMode) { case TextReadOnlyMode::NO: m_textEdit->setReadOnly(false); break; case TextReadOnlyMode::YES: m_textEdit->setReadOnly(true); break; } QPushButton* closeButton = new QPushButton("Close"); QObject::connect(closeButton, &QPushButton::clicked, this, &QDialog::accept); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(m_textEdit, 100); layout->addWidget(closeButton, 0, Qt::AlignCenter); QTextDocument* document = m_textEdit->document(); QTextOption textOption = document->defaultTextOption(); switch (wrapMode) { case WrapMode::NO: textOption.setWrapMode(QTextOption::NoWrap); break; case WrapMode::YES: textOption.setWrapMode(QTextOption::WordWrap); break; } document->setDefaultTextOption(textOption); document->adjustSize(); m_textEdit->adjustSize(); int32_t dialogWidth = document->size().width() + 70; if (dialogWidth < 300) { dialogWidth = 300; } const int32_t dialogHeight = document->size().height() + 100; WuQtUtilities::resizeWindow(this, dialogWidth, dialogHeight); } /** * Destructor. */ WuQTextEditorDialog::~WuQTextEditorDialog() { } connectome-workbench-1.4.2/src/GuiQt/WuQTextEditorDialog.h000066400000000000000000000046371360521144700235060ustar00rootroot00000000000000#ifndef __WU_Q_TEXT_EDITOR_DIALOG_H__ #define __WU_Q_TEXT_EDITOR_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include class QTextEdit; namespace caret { class WuQTextEditorDialog : public QDialog { Q_OBJECT public: enum class TextMode { HTML, PLAIN }; enum class WrapMode { NO, YES }; enum class TextReadOnlyMode { NO, YES }; static void runNonModal(const QString& dialogTitle, const QString& text, const TextMode textMode, const WrapMode wrapMode, QWidget* parent); WuQTextEditorDialog(const QString& dialogTitle, const QString& text, const TextReadOnlyMode readOnlyMode, const TextMode textMode, const WrapMode wrapMode, QWidget* parent = 0); virtual ~WuQTextEditorDialog(); // ADD_NEW_METHODS_HERE private: WuQTextEditorDialog(const WuQTextEditorDialog&); WuQTextEditorDialog& operator=(const WuQTextEditorDialog&); QTextEdit* m_textEdit; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_TEXT_EDITOR_DIALOG_DECLARE__ // #endif // __WU_Q_TEXT_EDITOR_DIALOG_DECLARE__ } // namespace #endif //__WU_Q_TEXT_EDITOR_DIALOG_H__ connectome-workbench-1.4.2/src/GuiQt/WuQTimedMessageDisplay.cxx000066400000000000000000000144461360521144700245420ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #define __WU_Q_TIMED_MESSAGE_DISPLAY_DECLARE__ #include "WuQTimedMessageDisplay.h" #undef __WU_Q_TIMED_MESSAGE_DISPLAY_DECLARE__ #include "AString.h" #include "CaretAssert.h" using namespace caret; /** * \class caret::WuQTimedMessageDisplay * \brief Timed message display. * * Displays a buttonless dialog for a period of time. * * Use the static show() method to display a timed message display. */ /** * Constructor. * * Display a message containing the given message for the given amount * of time. * * @param parent * Parent on which message is displayed. * @param displayForSeconds * Message is displayed for this amount of time, in milliseconds. * @param message * Message that is displayed. * @param modalFlag * If true dialog is modal. */ WuQTimedMessageDisplay::WuQTimedMessageDisplay(QWidget* parent, const float displayForSeconds, const QString& message, const bool modalFlag) : QDialog(parent, Qt::FramelessWindowHint) { CaretAssertMessage(displayForSeconds > 0.0, "Display time must be greater than zero."); /* * Modal so it blocks until done. */ setModal(modalFlag); /* * Delete self when done. */ this->setAttribute(Qt::WA_DeleteOnClose, true); /* * Put message in window. */ QLabel* label = new QLabel(message); label->setFrameStyle(QFrame::Panel | QFrame::Plain); label->setLineWidth(2); label->setWordWrap(true); QVBoxLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(3, 3, 3, 3); layout->addWidget(label); /* * Setup a timer to call the accept(() slot when done. * accept() will close the dialog. */ QTimer* timer = new QTimer(this); timer->setSingleShot(true); if (modalFlag) { QObject::connect(timer, SIGNAL(timeout()), this, SLOT(accept())); } else { QObject::connect(timer, SIGNAL(timeout()), this, SLOT(close())); } timer->start(displayForSeconds * 1000.0); /* * Display directly over the parent */ QPoint pos = parent->mapToGlobal(parent->pos()); move(pos); } /** * Display a message containing the given message for the given amount * of time. This method will not return until the message window closes. * * @param parent * Parent on which message is displayed. * @param displayForSeconds * Message is displayed for this amount of time, in milliseconds. * @param message * Message that is displayed. */ void WuQTimedMessageDisplay::showModal(QWidget* parent, const float displayForSeconds, const QString& message) { WuQTimedMessageDisplay* md = new WuQTimedMessageDisplay(parent, displayForSeconds, message, true); md->exec(); } /** * Display a message containing the given message for the given amount * of time. This method will return IMMEDIATELY and the message will * delete its self when closed. * * @param parent * Parent on which message is displayed. * @param displayForSeconds * Message is displayed for this amount of time, in milliseconds. * @param message * Message that is displayed. */ void WuQTimedMessageDisplay::showNonModal(QWidget* parent, const float displayForSeconds, const QString& message) { WuQTimedMessageDisplay* md = new WuQTimedMessageDisplay(parent, displayForSeconds, message, false); md->show(); md->raise(); } /** * Display a message containing the given message for the given amount * of time. This method will not return until the message window closes. * * @param parent * Parent on which message is displayed. * @param x * X-coordinate of parent for display of message. * @param y * Y-coordinate of parent for display of message (origin at bottom). * @param displayForSeconds * Message is displayed for this amount of time, in milliseconds. * @param message * Message that is displayed. */ void WuQTimedMessageDisplay::showModal(QWidget* parent, const int32_t x, const int32_t y, const float displayForSeconds, const QString& message) { WuQTimedMessageDisplay* md = new WuQTimedMessageDisplay(parent, displayForSeconds, message, true); const int32_t originAtTopWindowY = parent->height() - y; QPoint globalXY = parent->mapToGlobal(QPoint(x, originAtTopWindowY)); md->move(globalXY); md->exec(); } /** * Destructor. */ WuQTimedMessageDisplay::~WuQTimedMessageDisplay() { } connectome-workbench-1.4.2/src/GuiQt/WuQTimedMessageDisplay.h000066400000000000000000000046361360521144700241670ustar00rootroot00000000000000#ifndef __WU_Q_TIMED_MESSAGE_DISPLAY_H__ #define __WU_Q_TIMED_MESSAGE_DISPLAY_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include namespace caret { class WuQTimedMessageDisplay : public QDialog { Q_OBJECT private: WuQTimedMessageDisplay(QWidget* parent, const float displayForSeconds, const QString& message, const bool modalFlag); public: static void showModal(QWidget* parent, const float displayForSeconds, const QString& message); static void showNonModal(QWidget* parent, const float displayForSeconds, const QString& message); static void showModal(QWidget* parent, const int32_t x, const int32_t y, const float displayForSeconds, const QString& message); virtual ~WuQTimedMessageDisplay(); private: WuQTimedMessageDisplay(const WuQTimedMessageDisplay&); WuQTimedMessageDisplay& operator=(const WuQTimedMessageDisplay&); public: // ADD_NEW_METHODS_HERE private: // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_TIMED_MESSAGE_DISPLAY_DECLARE__ // #endif // __WU_Q_TIMED_MESSAGE_DISPLAY_DECLARE__ } // namespace #endif //__WU_Q_TIMED_MESSAGE_DISPLAY_H__ connectome-workbench-1.4.2/src/GuiQt/WuQTreeWidget.cxx000066400000000000000000000076631360521144700227130ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #define __WU_Q_TREE_WIDGET_DECLARE__ #include "WuQTreeWidget.h" #undef __WU_Q_TREE_WIDGET_DECLARE__ using namespace caret; /** * \class caret::WuQTreeWidget * \brief Tree Widget that can size to its content's size. * * A QTreeWidget normally gets a size hint of (256, 256) and * does not increase in size when the scroll bars are turned * off. If fitToContentSizeWithoutScrollBars() is called * this tree widget will resize to the size of its content. */ /** * Constructor. */ WuQTreeWidget::WuQTreeWidget(QWidget* parent) : QTreeWidget(parent) { this->setHeaderHidden(true); this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); this->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); QObject::connect(this, SIGNAL(itemCollapsed(QTreeWidgetItem*)), this, SLOT(itemExpandedOrCollapsed(QTreeWidgetItem*))); QObject::connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(itemExpandedOrCollapsed(QTreeWidgetItem*))); } /** * Destructor. */ WuQTreeWidget::~WuQTreeWidget() { } /** * Called when an item is expanded or collapsed to * update the fixed size. */ void WuQTreeWidget::itemExpandedOrCollapsed(QTreeWidgetItem*) { this->resizeToFitContent(); } /** * Size the widget so that it is the size of * its content's without any scroll bars. */ void WuQTreeWidget::resizeToFitContent() { const int height = this->calculateHeight() + 6; this->setFixedHeight(height); int totalColumnWidths = 20; // space for arrows const int numCols = this->columnCount(); for (int i = 0; i < numCols; i++) { totalColumnWidths += this->sizeHintForColumn(i); } if (totalColumnWidths < 256) { totalColumnWidths = 256; } this->setFixedWidth(totalColumnWidths); } /* * From http://qt-project.org/forums/viewthread/2533 */ int WuQTreeWidget::calculateHeight() const { int h = 0; int topLevelCount = this->topLevelItemCount(); for (int i = 0;i < topLevelCount;i++) { QTreeWidgetItem * item = topLevelItem(i); h += this->calculateHeightRec(item); } if (h != 0) { h += header()->sizeHint().height(); } return h; } /* * */ int WuQTreeWidget::calculateHeightRec(QTreeWidgetItem * item) const { if (item == NULL) return 0; QModelIndex index = indexFromItem(item); if (item->isExpanded() == false) { int h = rowHeight(index); return h; } /* int h = 0; for (int j = 0; j < item->columnCount(); j++) { const int itemHeight = item->sizeHint(j).height() + 2; if (itemHeight > h) { h = itemHeight; } } */ //int h = item->sizeHint(0).height() + 2; //std::cout << "EXPANDED h=" << h << " rowSizeHint=" << indexRowSizeHint(index); int h = indexRowSizeHint(index); int childCount = item->childCount(); for (int i = 0; i < childCount;i++) { h += this->calculateHeightRec(item->child(i)); } return h; } connectome-workbench-1.4.2/src/GuiQt/WuQTreeWidget.h000066400000000000000000000032051360521144700223240ustar00rootroot00000000000000#ifndef __WU_Q_TREE_WIDGET__H_ #define __WU_Q_TREE_WIDGET__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include namespace caret { class WuQTreeWidget : public QTreeWidget { Q_OBJECT public: WuQTreeWidget(QWidget* parent = 0); virtual ~WuQTreeWidget(); void resizeToFitContent(); private slots: void itemExpandedOrCollapsed(QTreeWidgetItem*); private: WuQTreeWidget(const WuQTreeWidget&); WuQTreeWidget& operator=(const WuQTreeWidget&); int calculateHeight() const; int calculateHeightRec(QTreeWidgetItem* treeItem) const; }; #ifdef __WU_Q_TREE_WIDGET_DECLARE__ // #endif // __WU_Q_TREE_WIDGET_DECLARE__ } // namespace #endif //__WU_Q_TREE_WIDGET__H_ connectome-workbench-1.4.2/src/GuiQt/WuQTrueFalseComboBox.cxx000066400000000000000000000060661360521144700241670ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_TRUE_FALSE_COMBO_BOX_DECLARE__ #include "WuQTrueFalseComboBox.h" #undef __WU_Q_TRUE_FALSE_COMBO_BOX_DECLARE__ using namespace caret; /** * \class caret::WuQTrueFalseComboBox * \brief Combo box for true/false type values. */ /** * Constructor. */ WuQTrueFalseComboBox::WuQTrueFalseComboBox(const QString& trueText, const QString& falseText, QObject* parent) : WuQWidget(parent) { this->createComboBox(trueText, falseText); } /** * Constructor. */ WuQTrueFalseComboBox::WuQTrueFalseComboBox(QObject* parent) : WuQWidget(parent) { this->createComboBox("true", "false"); } /** * Destructor. */ WuQTrueFalseComboBox::~WuQTrueFalseComboBox() { } /** * Create the combo box. * @param trueText * Text for 'true' value. * @param falseText * Text for 'false' value. */ void WuQTrueFalseComboBox::createComboBox(const QString& trueText, const QString& falseText) { this->comboBox = new QComboBox(); this->comboBox->addItem(trueText); this->comboBox->addItem(falseText); QObject::connect(this->comboBox, SIGNAL(activated(int)), this, SLOT(comboBoxValueChanged(int))); } /** * Called when value is changed. */ void WuQTrueFalseComboBox::comboBoxValueChanged(int indx) { bool boolValue = (indx == 0); emit statusChanged(boolValue); } /** * @return The embedded widget. */ QWidget* WuQTrueFalseComboBox::getWidget() { return this->comboBox; } /** * @return If true is selected. */ bool WuQTrueFalseComboBox::isTrue() { const int indx = this->comboBox->currentIndex(); const bool boolValue = (indx == 0); return boolValue; } /** * @return If false is selected. */ bool WuQTrueFalseComboBox::isFalse() { const int indx = this->comboBox->currentIndex(); const bool boolValue = (indx == 1); return boolValue; } /** * Set the new true/false status. * @parma status * New status. */ void WuQTrueFalseComboBox::setStatus(const bool status) { if (status) { this->comboBox->setCurrentIndex(0); } else { this->comboBox->setCurrentIndex(1); } } connectome-workbench-1.4.2/src/GuiQt/WuQTrueFalseComboBox.h000066400000000000000000000041761360521144700236140ustar00rootroot00000000000000#ifndef __WU_Q_TRUE_FALSE_COMBO_BOX__H_ #define __WU_Q_TRUE_FALSE_COMBO_BOX__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "WuQWidget.h" namespace caret { class WuQTrueFalseComboBox : public WuQWidget { Q_OBJECT public: WuQTrueFalseComboBox(const QString& trueText, const QString& falseText, QObject* parent); WuQTrueFalseComboBox(QObject* parent); virtual ~WuQTrueFalseComboBox(); QWidget* getWidget(); bool isTrue(); bool isFalse(); void setStatus(const bool status); signals: /** Emitted when user makes a selection */ void statusChanged(bool); private slots: void comboBoxValueChanged(int indx); private: WuQTrueFalseComboBox(const WuQTrueFalseComboBox&); WuQTrueFalseComboBox& operator=(const WuQTrueFalseComboBox&); void createComboBox(const QString& trueText, const QString& falseText); QComboBox* comboBox; }; #ifdef __WU_Q_TRUE_FALSE_COMBO_BOX_DECLARE__ // #endif // __WU_Q_TRUE_FALSE_COMBO_BOX_DECLARE__ } // namespace #endif //__WU_Q_TRUE_FALSE_COMBO_BOX__H_ connectome-workbench-1.4.2/src/GuiQt/WuQWebView.cxx000066400000000000000000000026721360521144700222130ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WuQWebView.h" #include #include #include WuQWebView::WuQWebView(QWidget *parent) : QWebView(parent) { connect(page()->networkAccessManager(), SIGNAL(sslErrors(QNetworkReply*, const QList & )), this, SLOT(handleSslErrors(QNetworkReply*, const QList & ))); } void WuQWebView::handleSslErrors(QNetworkReply* reply, const QList &/*errors*/) { /*qDebug() << "handleSslErrors: "; foreach (QSslError e, errors) { qDebug() << "ssl error: " << e; }*/ reply->ignoreSslErrors(); } connectome-workbench-1.4.2/src/GuiQt/WuQWebView.h000066400000000000000000000021641360521144700216340ustar00rootroot00000000000000#ifndef WUQWEBVIEW_H #define WUQWEBVIEW_H /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include class WuQWebView : public QWebView { Q_OBJECT public: WuQWebView(QWidget *parent = 0); private slots: void handleSslErrors(QNetworkReply* reply, const QList &/*errors*/); }; #endif // WUQWEBVIEW_H connectome-workbench-1.4.2/src/GuiQt/WuQWidget.cxx000066400000000000000000000067061360521144700220700ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_WIDGET_DECLARE__ #include "WuQWidget.h" #undef __WU_Q_WIDGET_DECLARE__ #include #include "CaretAssert.h" using namespace caret; /** * \class caret::WuQWidget * \brief Class for extending Qt GUI Widgets through encapsulation * * It is often desirable to extend a Qt GUI widget but one does * not want to directly subclass a QWidget. For example, a * QComboBox is a useful control for selection of an enumerated * type. It is desirable to allow the user of the class to only * access the combo box by setting and getting the enumerated type. * However, if one directly subclasses QComboBox, it allows access * to many methods including those that get and set via an index * or name which could allow the insertion of invalid values. So, * by encapsualting, one can provide accessor methods using the * enumerated types. Protected inheritance is not a viable solution * because it prevents the connection of signals and slots. * * This class is not derived from QWidget since that would require. * the additional of a layout to hold the actual widget. Instead, * this class is derived from QObject so that there are no 'widget' * methods available to the user and so that the signal and slot * mechanism is available. Subclasses can define, signals and slots * that are appropriate, such as those that use an enumerated type * as a parameter. * * The parent of derived classes must be passed to the contructor. * The parent is typically some deriviative of QWidget such as * QDialog. By using a parent, Qt will destroy an instance of * this class when the parent is destroyed. * * An instance of this class is never added to a layout. Instead, * deriving classes implement the getWidget() method to provide * the enapsulated widget for insertion into a layout. * * Since the encapsulated QWidget is added to a layout, never * delete the encapsulated widget since it will have a Qt parent * which will destroy it. */ /** * Constructor. */ WuQWidget::WuQWidget(QObject* parent) : QObject(parent) { CaretAssert(parent); } /** * Destructor. */ WuQWidget::~WuQWidget() { } /** * Sets both the minimum and maximum width of the widget to w without changing the heights. * * @param width * Width value. */ void WuQWidget::setFixedWidth(int width) { QWidget* widget = getWidget(); CaretAssert(widget); widget->setFixedWidth(width); } /** * Set the tooltip for this spin box. * * @param tooltip * Text for the tooltip. */ void WuQWidget::setToolTip(const QString& tooltip) { QWidget* widget = getWidget(); CaretAssert(widget); widget->setToolTip(tooltip); } connectome-workbench-1.4.2/src/GuiQt/WuQWidget.h000066400000000000000000000030371360521144700215070ustar00rootroot00000000000000#ifndef __WU_Q_WIDGET__H_ #define __WU_Q_WIDGET__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include class QWidget; namespace caret { class WuQWidget : public QObject { Q_OBJECT public: WuQWidget(QObject* parent); virtual ~WuQWidget(); virtual QWidget* getWidget() = 0; virtual void setToolTip(const QString& tooltip); void setFixedWidth(int w); private: WuQWidget(const WuQWidget&); WuQWidget& operator=(const WuQWidget&); public: private: }; #ifdef __WU_Q_WIDGET_DECLARE__ // #endif // __WU_Q_WIDGET_DECLARE__ } // namespace #endif //__WU_Q_WIDGET__H_ connectome-workbench-1.4.2/src/GuiQt/WuQWidgetDisabler.cxx000066400000000000000000000100521360521144700235230ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_Q_WIDGET_DISABLER_DECLARE__ #include "WuQWidgetDisabler.h" #undef __WU_Q_WIDGET_DISABLER_DECLARE__ #include #include "CaretAssert.h" using namespace caret; /** * \class caret::WuQWidgetDisabler * \brief Simplifies disabling of QWidget instance within a scope * \ingroup GuiQt * * WuQWidgetDisabler can be used whereever you would otherwise * use a pair of calls to setEnabled(). It disables the * QWidget in its constructor and in the destructor it resets * the enabled state to what it was before the constructor * ran. * * An example for usage of this class is in the method * that receives a QPushButton:clicked signal. User cannot * push the button until the method completes. * * The design of this class is modeled after QSignalBlocker * so Qt license is below. * */ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWidgets module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ /** * Constructor. * Calls widget->setEnabled(false) * * @param widget * The QWidget */ WuQWidgetDisabler::WuQWidgetDisabler(QWidget* widget) : CaretObject(), m_widget(widget) { CaretAssert(m_widget); m_savedEnabledState = m_widget->isEnabled(); m_widget->setEnabled(false); } /** * Destructor. Restores enabled status of the QObject * to what it was before the constructor rang. */ WuQWidgetDisabler::~WuQWidgetDisabler() { m_widget->setEnabled(m_savedEnabledState); } connectome-workbench-1.4.2/src/GuiQt/WuQWidgetDisabler.h000066400000000000000000000031521360521144700231530ustar00rootroot00000000000000#ifndef __WU_Q_WIDGET_DISABLER_H__ #define __WU_Q_WIDGET_DISABLER_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" class QWidget; namespace caret { class WuQWidgetDisabler : public CaretObject { public: WuQWidgetDisabler(QWidget* widget); virtual ~WuQWidgetDisabler(); // ADD_NEW_METHODS_HERE private: WuQWidgetDisabler(const WuQWidgetDisabler&); WuQWidgetDisabler& operator=(const WuQWidgetDisabler&); QWidget* m_widget; bool m_savedEnabledState = true; // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_Q_WIDGET_DISABLER_DECLARE__ // #endif // __WU_Q_WIDGET_DISABLER_DECLARE__ } // namespace #endif //__WU_Q_WIDGET_DISABLER_H__ connectome-workbench-1.4.2/src/GuiQt/WuQWidgetObjectGroup.cxx000066400000000000000000000107441360521144700242310ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "WuQWidgetObjectGroup.h" using namespace caret; /** * constructor. * WuQWidgetObjectGroup::WuQWidgetObjectGroup(QWidget* parent) : QObject(parent) { } */ /** * constructor. */ WuQWidgetObjectGroup::WuQWidgetObjectGroup(QObject* parent) : QObject(parent) { } /** * destructor. */ WuQWidgetObjectGroup::~WuQWidgetObjectGroup() { this->clear(); } /** * Remove all objects from this group. The objects are NOT deleted * since widgets are typically 'owned' by their parents. */ void WuQWidgetObjectGroup::clear() { this->objects.clear(); } /** * add a QObject (QWidget is descendent of QObject) to the group. */ void WuQWidgetObjectGroup::add(QObject* o) { this->objects.push_back(o); } /** * enable the group's widgets. */ void WuQWidgetObjectGroup::setEnabled(bool enable) { for (int i = 0; i < this->objects.size(); i++) { QWidget* widget = qobject_cast(this->objects[i]); if (widget != NULL) { widget->setEnabled(enable); } } } /** * disable the group's widgets. */ void WuQWidgetObjectGroup::setDisabled(bool disable) { for (int i = 0; i < this->objects.size(); i++) { QWidget* widget = qobject_cast(this->objects[i]); if (widget != NULL) { widget->setDisabled(disable); } } } /** * @return true if any of the widgets are visible. */ bool WuQWidgetObjectGroup::isVisible() const { for (int i = 0; i < this->objects.size(); i++) { QWidget* widget = qobject_cast(this->objects[i]); if (widget != NULL) { if (widget->isVisible()) { return true; } } } return false; } /** * make the group's widgets visible. */ void WuQWidgetObjectGroup::setVisible(bool makeVisible) { for (int i = 0; i < this->objects.size(); i++) { QWidget* widget = qobject_cast(this->objects[i]); if (widget != NULL) { widget->setVisible(makeVisible); } } } /** * make the group's widgets hidden. */ void WuQWidgetObjectGroup::setHidden(bool hidden) { setVisible(! hidden); } /** * block signals. */ void WuQWidgetObjectGroup::blockAllSignals(bool blockTheSignals) { for (int i = 0; i < this->objects.size(); i++) { this->objects.at(i)->blockSignals(blockTheSignals); } } /** * set status of all checkboxes. */ void WuQWidgetObjectGroup::setAllCheckBoxesChecked(const bool b) { for (int i = 0; i < this->objects.size(); i++) { QCheckBox* cb = qobject_cast(this->objects.at(i)); if (cb != NULL) { cb->setChecked(b); } } } /** * make all of the widgets in the group the same size as size hint * of largest widget. */ void WuQWidgetObjectGroup::resizeAllToLargestSizeHint() { int largestWidth = -1; int largestHeight = -1; for (int i = 0; i < this->objects.size(); i++) { QWidget* widget = qobject_cast(this->objects[i]); if (widget == NULL) { continue; } const QSize size = widget->sizeHint(); if (size.width() > largestWidth) { largestWidth = size.width(); } if (size.height() > largestHeight) { largestHeight = size.height(); } } if ((largestWidth > 0) && (largestHeight > 0)) { QSize newSize(largestWidth, largestHeight); for (int i = 0; i < this->objects.size(); i++) { QWidget* widget = qobject_cast(this->objects[i]); if (widget != NULL) { widget->setFixedSize(newSize); } } } } connectome-workbench-1.4.2/src/GuiQt/WuQWidgetObjectGroup.h000066400000000000000000000042171360521144700236540ustar00rootroot00000000000000 #ifndef __QT_WIDGET_OBJECT_GROUP_H__ #define __QT_WIDGET_OBJECT_GROUP_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include class QLayout; class QObject; namespace caret { /** * Groups QWidget and/or QObjects for applying operations to * all such as blocking signals and setting visibility. */ class WuQWidgetObjectGroup : public QObject { Q_OBJECT public: //WuQWidgetObjectGroup(QWidget* parent); WuQWidgetObjectGroup(QObject* parent); ~WuQWidgetObjectGroup(); void add(QObject* w); void clear(); QObject* getObject() { return qobject_cast(this); } bool isVisible() const; public slots: void blockAllSignals(bool blockTheSignals); void setEnabled(bool enable); void setDisabled(bool disable); void setVisible(bool makeVisible); void setHidden(bool hidden); void resizeAllToLargestSizeHint(); void setAllCheckBoxesChecked(const bool b); protected: QVector objects; private: // prevent access to QObject's blockSignals() method bool blockSignals(bool); }; } // namespace #endif // __QT_WIDGET_OBJECT_GROUP_H__ connectome-workbench-1.4.2/src/GuiQt/WuQtUtilities.cxx000066400000000000000000001471551360521144700230100ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include #include #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "WuQtUtilities.h" using namespace caret; /** * Create an action with the specified text. * * @param text * Text for the action. * @param toolAndStatusTipText * Text for both tool and status tips. * @param parent * Owner of the created action. * @return * Action that was created. */ QAction* WuQtUtilities::createAction(const QString& text, const QString& toolAndStatusTipText, QObject* parent) { QAction* action = new QAction(parent); action->setText(text); if (toolAndStatusTipText.isEmpty() == false) { action->setStatusTip(toolAndStatusTipText); action->setToolTip(toolAndStatusTipText); } return action; } /** * Create an action with the specified text. * * @param text * Text for the action. * @param toolAndStatusTipText * Text for both tool and status tips. * @param shortcut * Keyboard shortcut. * @param parent * Owner of the created action. * @return * Action that was created. */ QAction* WuQtUtilities::createAction(const QString& text, const QString& toolAndStatusTipText, const QKeySequence& shortcut, QObject* parent) { QAction* action = new QAction(parent); action->setText(text); if (toolAndStatusTipText.isEmpty() == false) { action->setStatusTip(toolAndStatusTipText); action->setToolTip(toolAndStatusTipText); } action->setShortcut(shortcut); return action; } /** * Create an action with the specified text, shortcut, * and calls the specified slot. * * @param text * Text for the action. * @param toolAndStatusTipText * Text for both tool and status tips. * @param shortcut * Keyboard shortcut. * @param parent * Owner of the created action. * @param receiver * Owner of method that is called when action is triggered. * @param method * method in receiver that is called when action is triggered. * @return * Action that was created. */ QAction* WuQtUtilities::createAction(const QString& text, const QString& toolAndStatusTipText, const QKeySequence& shortcut, QObject* parent, QObject* receiver, const char* method) { QAction* action = WuQtUtilities::createAction(text, toolAndStatusTipText, parent, receiver, method); action->setShortcut(shortcut); return action; } /** * Create an action with the specified text and calls * the specified slot. * * @param text * Text for the action. * @param toolAndStatusTipText * Text for both tool and status tips. * @param parent * Owner of the created action. * @param receiver * Owner of method that is called when action is triggered. * @param method * method in receiver that is called when action is triggered. * @return * Action that was created. */ QAction* WuQtUtilities::createAction(const QString& text, const QString& toolAndStatusTipText, QObject* parent, QObject* receiver, const char* method) { QAction* action = WuQtUtilities::createAction(text, toolAndStatusTipText, parent); QObject::connect(action, SIGNAL(triggered(bool)), receiver, method); return action; } /** * Create a pushbutton. * * @param text * Text for the pushbutton. * @param toolAndStatusTipText * Text for both tool and status tips. * @param receiver * Owner of method that is called when button is clicked. * @param method * method in receiver that is called when button is clicked. * @return * Pushbutton that was created. */ QPushButton* WuQtUtilities::createPushButton(const QString& text, const QString& toolAndStatusTipText, QObject* receiver, const char* method) { QPushButton* pb = new QPushButton(text); if (toolAndStatusTipText.isEmpty() == false) { pb->setStatusTip(toolAndStatusTipText); pb->setToolTip(toolAndStatusTipText); } QObject::connect(pb, SIGNAL(clicked()), receiver, method); return pb; } /** * Create a tool button with the specified text, icon, * tooltip and slot. * * @param text * Text for the action. * @param iconFileName * Name of file containing the icon. * @param tooltip * Tooltip for the button * @param receiver * Owner of method that is called when button is clicked. * @param method * method in receiver that is called when button is clicked. * @return * Toolbutton that was created. */ QToolButton* WuQtUtilities::createToolButtonWithIcon(const QString& text, const QString& iconFileName, const QString& toolTip, QObject* receiver, const char* method) { QIcon icon; const bool iconValid = WuQtUtilities::loadIcon(iconFileName, icon); QToolButton* toolButton = new QToolButton(); if (iconValid) { toolButton->setIcon(icon); } else { toolButton->setText(text); } toolButton->setToolTip(toolTip); QObject::connect(toolButton, SIGNAL(clicked(bool)), receiver, method); return toolButton; } /** * Create a horizontal line widget used as a separator. * * @return A horizontal line widget used as a separator. */ QWidget* WuQtUtilities::createHorizontalLineWidget() { QFrame* frame = new QFrame(); frame->setMidLineWidth(1); frame->setLineWidth(1); frame->setFrameStyle(QFrame::HLine | QFrame::Sunken); return frame; } /** * Create a vertical line widget used as a separator. * * @return A vertical line widget used as a separator. */ QWidget* WuQtUtilities::createVerticalLineWidget() { QFrame* frame = new QFrame(); frame->setMidLineWidth(0); frame->setLineWidth(2); frame->setFrameStyle(QFrame::VLine | QFrame::Sunken); return frame; } /** * Move a window relative to its parent window * but do not let the window move off the screen. * X is left to right, Y is top to bottom. * * @param parentWindow * The parent window of the window being moved. * @param window * The window. * @param xOffset * Offset widget from parent by this X amount. * @param yOffset * Offset widget from parent by this Y amount. */ void WuQtUtilities::moveWindowToOffset(QWidget* parentWindow, QWidget* window, const int xOffset, const int yOffset) { int x = parentWindow->x() + xOffset; int y = parentWindow->y() + yOffset; QDesktopWidget* dw = QApplication::desktop(); const QRect geometry = dw->availableGeometry(parentWindow); const int margin = 20; const int maxX = geometry.width() - margin; const int maxY = geometry.height() - margin; if (x > maxX) x = maxX; if (x < margin) x = margin; if (y > maxY) y = maxY; if (y < margin) y = margin; window->move(x, y); } /** * Place a dialog next to its parent. May not work correctly with * multi-screen systems. * * MUST BE CALLED after a window is displayed since the given window * may not have its geometry (size) set until AFTER it is displayed. * * It will stop after the first one of these actions that is successful: * 1) Put window on right of parent if all of window will be visible. * 2) Put window on left of parent if all of window will be visible. * 3) Put window on right of parent if more space to right of window. * 4) Put window on left of parent. * @param parent * The parent. * @param window * The window. */ void WuQtUtilities::moveWindowToSideOfParent(QWidget* parent, QWidget* window) { const QRect parentGeometry = parent->geometry(); const int px = parentGeometry.x(); const int py = parentGeometry.y(); const int pw = parentGeometry.width(); const int ph = parentGeometry.height(); const int parentMaxX = px + pw; //int x = px + pw + 1; int y = py + ph - window->height() - 20; // int y = py; const int windowWidth = window->width(); QDesktopWidget* dw = QApplication::desktop(); const QRect geometry = dw->availableGeometry(parent); const int screenMinX = geometry.x(); const int screenWidth = geometry.width(); const int screenMaxX = screenMinX + screenWidth; const int screenMaxY = geometry.x() + geometry.height(); const int spaceOnLeft = px -screenMinX; const int spaceOnRight = screenMaxX - parentMaxX; int x = screenMinX; if (spaceOnRight > windowWidth) { x = parentMaxX; } else if (spaceOnLeft > windowWidth) { x = px - windowWidth; } else if (spaceOnRight > spaceOnLeft) { x = screenMaxX - windowWidth; } // else { // x = screenMinX; // } if ((x + windowWidth) > screenMaxX) { x = screenMaxX - windowWidth; } if (x < screenMinX) { x = screenMinX; } const int maxY = screenMaxY - window->height() - 50; if (y > maxY) { y = maxY; } if (y < 50) { y = 50; } window->move(x, y); } /** * Move and size a window limiting window so that * it fits within the screen. * @param x * X-coordinate of window. * @param y * Y-coordinate of window. * @param w * Width of window. * @param h * Height of window. * @param xywhOut * On exit contains 4 values that are the actual * x, y, width, and height of the window after * any needed adjustments for screen sizes. */ void WuQtUtilities::moveAndSizeWindow(QWidget* window, const int32_t x, const int32_t y, const int32_t w, const int32_t h, int32_t* xywhOut) { QDesktopWidget* dw = QApplication::desktop(); /* * Get available geometry where window is to be placed * This geometry is all screens together as one large screen */ QPoint pXY(x, y); #if QT_VERSION >= 0x050000 const QRect availableRect = dw->availableGeometry(); #else /* * Note 23 September 2016: * Calling geometry is likely the WRONG method to call * but since it is not causing a problem in in Qt 4.x * we will continuing using to avoid the risk of * breaking scenes. */ const QRect availableRect = dw->screen()->geometry(); #endif const int32_t screenSizeX = availableRect.width(); const int32_t screenSizeY = availableRect.height(); /* * Limit width/height in desktop */ int32_t width = std::min(w, screenSizeX); int32_t height = std::min(h, screenSizeY); /* * Limit window position in desktop */ int32_t xPos = x; if (xPos < availableRect.x()) { xPos = availableRect.x(); } const int32_t maxX = screenSizeX - 200; if (xPos >= maxX) { xPos = maxX; } int32_t yPos = y; if (yPos < availableRect.y()) { yPos = availableRect.y(); } const int32_t maxY = screenSizeY - 200; if (yPos >= maxY) { yPos = maxY; } /* * Make sure visible in closest screen */ pXY.setX(xPos); pXY.setY(yPos); const int32_t nearestScreen = dw->screenNumber(pXY); if (nearestScreen >= 0) { const QRect screenRect = dw->availableGeometry(nearestScreen); if (xPos < screenRect.x()) { xPos = screenRect.x(); } const int32_t maxX = screenRect.right() - 200; if (xPos > maxX) { xPos = maxX; } if (yPos < screenRect.y()) { yPos = screenRect.y(); } const int32_t maxY = screenRect.bottom() - 200; if (yPos > maxY) { yPos = maxY; } /* * ScreenRect width/height is size of screen * reduced by menu bars, docks and other items * that reduce available screen space */ const int32_t maxWidth = screenRect.width(); if (width > maxWidth) { width = maxWidth; } const int32_t maxHeight = screenRect.height(); if (height > maxHeight) { height = maxHeight; } const QRect geom = dw->screenGeometry(nearestScreen); CaretLogInfo(QString("Window Available width/height: %1, %2 \n Screen width/height: %3, %4" ).arg(maxWidth).arg(maxHeight).arg(geom.width()).arg(geom.height())); } /* * Move and size window */ window->move(xPos, yPos); window->resize(width, height); if (xywhOut != NULL) { xywhOut[0] = window->x(); xywhOut[1] = window->y(); xywhOut[2] = window->width(); xywhOut[3] = window->height(); } } /** * Resize a window but limit maximum size of window * to an area less than the full size of the display. * Has no effect on position of the window so part * of window may end up being outside the display. * * @param window * Window that is resized. * @param width * Desired width of the window. * @param height * Desired width of the window. */ void WuQtUtilities::resizeWindow(QWidget* window, const int32_t width, const int32_t height) { QDesktopWidget* dw = QApplication::desktop(); QPoint pXY(window->x(), window->y()); const int32_t nearestScreen = dw->screenNumber(pXY); if (nearestScreen >= 0) { const QRect screenRect = dw->availableGeometry(nearestScreen); const int32_t screenWidth = screenRect.width() - 100; const int32_t screenHeight = screenRect.height() - 100; const int windowWidth = std::min(width, screenWidth); const int windowHeight = std::min(height, screenHeight); window->resize(windowWidth, windowHeight); } } /** * Limit a window's size to a percentage of the maximum size. * * @param window * Window that is resized. * @param widthMaximumPercentage * Maximum width percentage [0, 100] * @param heightMaximumPercentage * Maximum height percentage [0, 100] */ void WuQtUtilities::limitWindowSizePercentageOfMaximum(QWidget* window, const float widthMaximumPercentage, const float heightMaximumPercentage) { AString message; if ((widthMaximumPercentage < 0.0) || (widthMaximumPercentage > 100.0)) { message.appendWithNewLine("Percentage width must range [0, 100]: value -> " + AString::number(widthMaximumPercentage)); } if ((heightMaximumPercentage < 0.0) || (heightMaximumPercentage > 100.0)) { message.appendWithNewLine("Percentage height must range [0, 100]: value -> " + AString::number(heightMaximumPercentage)); } if ( ! message.isEmpty()) { CaretLogSevere(message); return; } QDesktopWidget* dw = QApplication::desktop(); QPoint pXY(window->x(), window->y()); const int32_t nearestScreen = dw->screenNumber(pXY); if (nearestScreen >= 0) { const QRect screenRect = dw->availableGeometry(nearestScreen); const int32_t screenWidth = screenRect.width(); const int32_t screenHeight = screenRect.height(); const float maxWidth = ((widthMaximumPercentage / 100.0) * screenWidth); const float maxHeight = ((heightMaximumPercentage / 100.0) * screenHeight); window->setMaximumSize(maxWidth, maxHeight); window->adjustSize(); } } /** * Table widget has a default size of 640 x 480. * Estimate the size of the dialog with the table fully expanded. * * @param tableWidget * Table widget whose size is estimated. */ QSize WuQtUtilities::estimateTableWidgetSize(QTableWidget* tableWidget) { QSize tableSize(0, 0); /* * Table widget has a default size of 640 x 480. * So estimate the size of the dialog with the table fully * expanded. */ const int numRows = tableWidget->rowCount(); const int numCols = tableWidget->columnCount(); const int cellGap = (tableWidget->showGrid() ? 3 : 0); if ((numRows > 0) && (numCols > 0)) { int tableWidth = 10; // start out with a little extra space int tableHeight = 0; if (tableWidget->horizontalHeader()->isHidden() == false) { QHeaderView* columnHeader = tableWidget->horizontalHeader(); const int columnHeaderHeight = columnHeader->sizeHint().height(); tableHeight += columnHeaderHeight; } if (tableWidget->verticalHeader()->isHidden() == false) { QHeaderView* rowHeader = tableWidget->verticalHeader(); const int rowHeaderHeight = rowHeader->sizeHint().width(); tableHeight += rowHeaderHeight; } std::vector columnWidths(numCols, 0); std::vector rowHeights(numRows, 0); for (int iCol = 0; iCol < numCols; iCol++) { columnWidths[iCol] = tableWidget->columnWidth(iCol) + cellGap; } for (int jRow = 0; jRow < numRows; jRow++) { rowHeights[jRow]= (tableWidget->rowHeight(jRow) + cellGap); } for (int iCol = 0; iCol < numCols; iCol++) { for (int jRow = 0; jRow < numRows; jRow++) { QWidget* widget = tableWidget->cellWidget(jRow, iCol); if (widget != NULL) { const QSize widgetSizeHint = widget->sizeHint(); columnWidths[iCol] = std::max(columnWidths[iCol], widgetSizeHint.width()); rowHeights[jRow] = std::max(rowHeights[jRow], widgetSizeHint.height()); } QTableWidgetItem* item = tableWidget->item(jRow, iCol); if (item != NULL) { int itemWidth = 0; int itemHeight = 0; if (item->flags() & Qt::ItemIsUserCheckable) { itemWidth += 12; } QFont font = item->font(); const QString text = item->text(); if (text.isEmpty() == false) { QFont font = item->font(); QFontMetrics fontMetrics(font); const int textWidth = fontMetrics.width(text); const int textHeight = fontMetrics.height(); itemWidth += textWidth; itemHeight = std::max(itemHeight, textHeight); } columnWidths[iCol] = std::max(columnWidths[iCol], itemWidth); rowHeights[jRow] = std::max(rowHeights[jRow], itemHeight); } } } for (int iCol = 0; iCol < numCols; iCol++) { tableWidth += columnWidths[iCol]; } for (int jRow = 0; jRow < numRows; jRow++) { tableHeight += (rowHeights[jRow] - 2); } tableSize.setWidth(tableWidth); tableSize.setHeight(tableHeight); } return tableSize; } /** * Set the tool tip and status tip for a widget. * * @param widget * Widget that has its tool and status tip set. * @param text * Text for the tool and status tip. */ void WuQtUtilities::setToolTipAndStatusTip(QWidget* widget, const QString& text) { widget->setToolTip(text); widget->setStatusTip(text); } /** * Set the tool tip and status tip for an action. * * @param action * Action that has its tool and status tip set. * @param text * Text for the tool and status tip. */ void WuQtUtilities::setToolTipAndStatusTip(QAction* action, const QString& text) { action->setToolTip(text); action->setStatusTip(text); } /** * Print a list of resources to the Caret Logger. */ void WuQtUtilities::sendListOfResourcesToCaretLogger() { QString msg = "Resources loaded:\n"; QDir dir(":/"); QFileInfoList infoList = dir.entryInfoList(); for (int i = 0; i < infoList.count(); i++) { msg += " "; msg += infoList.at(i).filePath(); } CaretLogInfo(msg); } /** * Load an icon. * * @param filename * Name of file (or resource) containing the icon. * @param iconOut * Output that will contain the desired icon. * @return * True if the icon is valid, else false. */ bool WuQtUtilities::loadIcon(const QString& filename, QIcon& iconOut) { QPixmap pixmap; const bool valid = WuQtUtilities::loadPixmap(filename, pixmap); if (valid) { iconOut.addPixmap(pixmap); } return valid; } /** * Load an icon. * @param filename * Name of file containing the icon. * @return Pointer to icon (call must delete it) or NULL * if there was a failure to load the icon. */ QIcon* WuQtUtilities::loadIcon(const QString& filename) { QPixmap pixmap; const bool valid = WuQtUtilities::loadPixmap(filename, pixmap); QIcon* icon = NULL; if (valid) { icon = new QIcon(pixmap); } return icon; } /** * Load an pixmap. * * @param filename * Name of file (or resource) containing the pixmap. * @param pixmapOut * Output that will contain the desired pixmap. * @return * True if the pixmap is valid, else false. */ bool WuQtUtilities::loadPixmap(const QString& filename, QPixmap& pixmapOut) { bool valid = pixmapOut.load(filename); if (valid == false) { QString msg = "Failed to load Pixmap \"" + filename + "\"."; CaretLogSevere(msg); } else if ((pixmapOut.width() <= 0) || (pixmapOut.height() <= 0)) { QString msg = "Pixmap \"" + filename + "\" has invalid size."; CaretLogSevere(msg); valid = false; } return valid; } /** * Get the maximum height from the given widgets. * * @param w1 Required widget. * @param w2 Required widget. * @param w3 Optional widget. * @param w4 Optional widget. * @param w5 Optional widget. * @param w6 Optional widget. * @param w7 Optional widget. * @param w8 Optional widget. * @param w9 Optional widget. * @param w10 Optional widget. * @return * Maximum height of the widgets. */ int WuQtUtilities::getMaximumWidgetHeight(QWidget* w1, QWidget* w2, QWidget* w3, QWidget* w4, QWidget* w5, QWidget* w6, QWidget* w7, QWidget* w8, QWidget* w9, QWidget* w10) { QVector widgets; if (w1 != NULL) widgets.push_back(w1); if (w2 != NULL) widgets.push_back(w2); if (w3 != NULL) widgets.push_back(w3); if (w4 != NULL) widgets.push_back(w4); if (w5 != NULL) widgets.push_back(w5); if (w6 != NULL) widgets.push_back(w6); if (w7 != NULL) widgets.push_back(w7); if (w8 != NULL) widgets.push_back(w8); if (w9 != NULL) widgets.push_back(w9); if (w10 != NULL) widgets.push_back(w10); int maxHeight = 0; const int num = widgets.size(); for (int i = 0; i < num; i++) { const int h = widgets[i]->sizeHint().height(); if (h > maxHeight) { maxHeight = h; } } return maxHeight; } /** * Find the widget with the maximum height in its * size hint. Apply this height to all of the widgets. * * @param w1 Required widget. * @param w2 Required widget. * @param w3 Optional widget. * @param w4 Optional widget. * @param w5 Optional widget. * @param w6 Optional widget. * @param w7 Optional widget. * @param w8 Optional widget. * @param w9 Optional widget. * @param w10 Optional widget. */ void WuQtUtilities::matchWidgetHeights(QWidget* w1, QWidget* w2, QWidget* w3, QWidget* w4, QWidget* w5, QWidget* w6, QWidget* w7, QWidget* w8, QWidget* w9, QWidget* w10) { const int maxHeight = getMaximumWidgetHeight(w1, w2, w3, w4, w5, w6, w7, w8, w9, w10); if (maxHeight > 0) { w1->setFixedHeight(maxHeight); w2->setFixedHeight(maxHeight); if (w3 != NULL) w3->setFixedHeight(maxHeight); if (w4 != NULL) w4->setFixedHeight(maxHeight); if (w5 != NULL) w5->setFixedHeight(maxHeight); if (w6 != NULL) w6->setFixedHeight(maxHeight); if (w7 != NULL) w7->setFixedHeight(maxHeight); if (w8 != NULL) w8->setFixedHeight(maxHeight); if (w9 != NULL) w9->setFixedHeight(maxHeight); if (w10 != NULL) w10->setFixedHeight(maxHeight); } } /** * Find the widget with the maximum width in its * size hint. Apply this width to all of the widgets. * * @param w1 Required widget. * @param w2 Required widget. * @param w3 Optional widget. * @param w4 Optional widget. * @param w5 Optional widget. * @param w6 Optional widget. * @param w7 Optional widget. * @param w8 Optional widget. * @param w9 Optional widget. * @param w10 Optional widget. */ void WuQtUtilities::matchWidgetWidths(QWidget* w1, QWidget* w2, QWidget* w3, QWidget* w4, QWidget* w5, QWidget* w6, QWidget* w7, QWidget* w8, QWidget* w9, QWidget* w10) { QVector widgets; if (w1 != NULL) widgets.push_back(w1); if (w2 != NULL) widgets.push_back(w2); if (w3 != NULL) widgets.push_back(w3); if (w4 != NULL) widgets.push_back(w4); if (w5 != NULL) widgets.push_back(w5); if (w6 != NULL) widgets.push_back(w6); if (w7 != NULL) widgets.push_back(w7); if (w8 != NULL) widgets.push_back(w8); if (w9 != NULL) widgets.push_back(w9); if (w10 != NULL) widgets.push_back(w10); int maxWidth = 0; const int num = widgets.size(); for (int i = 0; i < num; i++) { const int w = widgets[i]->sizeHint().width(); if (w > maxWidth) { maxWidth = w; } } if (maxWidth > 0) { for (int i = 0; i < num; i++) { widgets[i]->setFixedWidth(maxWidth); } } } /** * Set the margins and spacing for a layout. * @param layout * Layout that has margins and spacings set. * @param spacing * Spacing between widgets within layout. * @param contentsMargin * Margin around the layout. */ void WuQtUtilities::setLayoutSpacingAndMargins(QLayout* layout, const int spacing, const int contentsMargin) { layout->setSpacing(spacing); layout->setContentsMargins(contentsMargin, contentsMargin, contentsMargin, contentsMargin); } /** * Set the content margins around a layout. * * @param contentsMargin * Margin around the layout. */ void WuQtUtilities::setLayoutMargins(QLayout* layout, const int contentsMargin) { layout->setContentsMargins(contentsMargin, contentsMargin, contentsMargin, contentsMargin); } /** * @return The minimum size (width/height) of all screens. */ QSize WuQtUtilities::getMinimumScreenSize() { int minWidth = std::numeric_limits::max(); int minHeight = std::numeric_limits::max(); QDesktopWidget* dw = QApplication::desktop(); const int numScreens = dw->screenCount(); for (int i = 0; i < numScreens; i++) { const QRect rect = dw->availableGeometry(i); const int w = rect.width(); const int h = rect.height(); minWidth = std::min(minWidth, w); minHeight = std::min(minHeight, h); } const QSize size(minWidth, minHeight); return size; } /** * Is the user's display small? This is loosely * defined as a vertical resolution of 800 or less. * @return true if resolution is 800 or less, * else false. */ bool WuQtUtilities::isSmallDisplay() { QDesktopWidget* dw = QApplication::desktop(); QRect screenRect = dw->screenGeometry(); const int verticalSize = screenRect.height(); if (verticalSize <= 800) { return true; } return false; } /** * Get a String containing information about a layout' content. * @param layout * The layout * @return * String with info. */ QString WuQtUtilities::getLayoutContentDescription(QLayout* layout) { QString s; s.reserve(25000); s += ("Layout type : " + QString(typeid(*layout).name()) + "\n"); const int itemCount = layout->count(); for (int32_t i = 0; i < itemCount; i++) { s += " "; QLayoutItem* layoutItem = layout->itemAt(i); QLayout* layout = layoutItem->layout(); if (layout != NULL) { s += QString(typeid(*layout).name()); } QWidget* widget = layoutItem->widget(); if (widget != NULL) { s += QString(typeid(*widget).name()); } QSpacerItem* spacerItem = layoutItem->spacerItem(); if (spacerItem != NULL) { s += "QSpacerItem"; } } return s; } ///** // * Play a sound file. The sound file MUST be in the distribution's // * "resources/sounds" directory. // * // * Note that sound files, as of Qt 4.8, do not support Qt's resource // * system. // * // * @param soundFileName // * Name of sound file (with no path, just the filename). // */ //void //WuQtUtilities::playSound(const QString& soundFileName) //{ // const QString workbenchDir = SystemUtilities::getWorkbenchHome(); // const QString soundFilePath = (workbenchDir // + "/../resources/sounds/" // + soundFileName); // // if (QFile::exists(soundFilePath)) { // QSound::play(soundFilePath); // } // else { // CaretLogSevere("Sound file \"" // + soundFilePath // + "\" does not exist."); // } //} /** * Create the text for a tooltip so that long lines are * wrapped and the tooltip is not one giant line * that is the width of the display. * * This is accomplished by placing the text into a * QTextDocument and then retrieving the text with * HTML formatting. * * @param tooltipText * Text for the tooltip. * @return * Text reformatted for display in a tool tip. */ QString WuQtUtilities::createWordWrappedToolTipText(const QString& tooltipText) { if (tooltipText.isEmpty()) { return ""; } QTextDocument textDocument(tooltipText); QString html = textDocument.toHtml(); return html; } /** * Set the text for a tooltip so that long lines are * wrapped and the tooltip is not one giant line * that is the width of the display. * * This is accomplished by placing the text into a * QTextDocument and then retrieving the text with * HTML formatting. * * @param widget * Widget on which tooltip is set. * @param tooltipText * Text for the widget's tooltip. */ void WuQtUtilities::setWordWrappedToolTip(QWidget* widget, const QString& tooltipText) { widget->setToolTip(createWordWrappedToolTipText(tooltipText)); } /** * Set the text for a tooltip so that long lines are * wrapped and the tooltip is not one giant line * that is the width of the display. * * This is accomplished by placing the text into a * QTextDocument and then retrieving the text with * HTML formatting. * * @param action * Action on which tooltip is set. * @param tooltipText * Text for the widget's tooltip. */ void WuQtUtilities::setWordWrappedToolTip(QAction* action, const QString& tooltipText) { action->setToolTip(createWordWrappedToolTipText(tooltipText)); } /** * Convert a Qt::CheckState to a boolean value. * * @param checkState * The check state value. * @return * true if checked or partially checked, else false. */ bool WuQtUtilities::checkStateToBool(const Qt::CheckState checkState) { if (checkState == Qt::Unchecked) { return false; } return true; } /** * Convert a boolean value to a Qt::CheckState * * @param value * The boolean value. * @return * Check state indicating checked or not checked. */ Qt::CheckState WuQtUtilities::boolToCheckState(const bool value) { if (value) { return Qt::Checked; } return Qt::Unchecked; } /** * Create a pixmap with the given color. * * @param widget * Widget that will contain pixmap. It used for getting the widget's * foreground and background colors. * @param pixmapWidth * Width for the pixmap. * @param pixmapHeight * Height for the pixmap. * @param caretColor * The Caret Color Enum value. * @param rgba * RGBA color for the pixmap. If the alpha component is zero, a * outline box with an 'X' symbol is drawn using the widget's * foreground color. * @param outlineFlag * If true, drawn an outline with the given color and the background * using the widget's background color. * @return * The pixmap. */ QPixmap WuQtUtilities::createCaretColorEnumPixmap(const QWidget* widget, const int32_t pixmapWidth, const int32_t pixmapHeight, const CaretColorEnum::Enum caretColor, const float customColorRGBA[4], const bool outlineFlag) { bool noneColorFlag = false; bool validColorFlag = false; float colorRGBA[4]; switch (caretColor) { case CaretColorEnum::NONE: noneColorFlag = true; break; case CaretColorEnum::CUSTOM: if (customColorRGBA[3] > 0.0) { colorRGBA[0] = customColorRGBA[0]; colorRGBA[1] = customColorRGBA[1]; colorRGBA[2] = customColorRGBA[2]; colorRGBA[3] = customColorRGBA[3]; validColorFlag = true; } break; case CaretColorEnum::AQUA: case CaretColorEnum::BLACK: case CaretColorEnum::BLUE: case CaretColorEnum::FUCHSIA: case CaretColorEnum::GRAY: case CaretColorEnum::GREEN: case CaretColorEnum::LIME: case CaretColorEnum::MAROON: case CaretColorEnum::NAVY: case CaretColorEnum::OLIVE: case CaretColorEnum::PURPLE: case CaretColorEnum::RED: case CaretColorEnum::SILVER: case CaretColorEnum::TEAL: case CaretColorEnum::WHITE: case CaretColorEnum::YELLOW: CaretColorEnum::toRGBAFloat(caretColor, colorRGBA); colorRGBA[3] = 1.0; validColorFlag = true; break; } /* * Create a small pixmap that will contain * the foreground color around the pixmap's perimeter. */ QPixmap pixmap(pixmapWidth, pixmapHeight); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainter(widget, pixmap, 0); if (noneColorFlag) { /* * Draw lines (rectangle) around the perimeter of the pixmap * and an 'X' in the widget's foreground color. */ for (int32_t i = 0; i < 1; i++) { painter->drawRect(i, i, pixmapWidth - 1 - i * 2, pixmapHeight - 1 - i * 2); } painter->drawLine(0, 0, pixmapWidth - 1, pixmapHeight - 1); painter->drawLine(0, pixmapHeight - 1, pixmapWidth - 1, 0); } else if (validColorFlag) { if (outlineFlag) { /* * Draw lines (rectangle) around the perimeter of the pixmap */ painter->setPen(QColor::fromRgbF(colorRGBA[0], colorRGBA[1], colorRGBA[2])); for (int32_t i = 0; i < 3; i++) { painter->drawRect(i, i, pixmapWidth - 1 - i * 2, pixmapHeight - 1 - i * 2); } } else { /* * Fill the pixmap with the RGBA color. */ pixmap.fill(QColor::fromRgbF(colorRGBA[0], colorRGBA[1], colorRGBA[2])); } } return pixmap; } /** * Create a painter for the given pixmap that will be placed * into the given widget. The pixmap's background is painted * with the widget's background color, the painter's pen is set * to the widget's foreground color, and then the painter is * returned. * * Origin of the painter will be in the center with the * coordinates, both X and Y, ranging -100 to 100. * * @param widget * Widget used for coloring. * @param pixmap * The Pixmap must be square (width == height). * @param pixmapOptions * Options for creation of pixmap. * @return * Shared pointer containing QPainter for drawing to the pixmap. */ QSharedPointer WuQtUtilities::createPixmapWidgetPainterOriginCenter100x100(const QWidget* widget, QPixmap& pixmap, const uint32_t pixmapOptions) { CaretAssert(pixmap.width() == pixmap.height()); QSharedPointer painter = createPixmapWidgetPainter(widget, pixmap, pixmapOptions); /* * Note: QPainter has its origin at the top left. * Using a negative for the Y-scale value will * move the origin to the bottom. */ painter->translate(pixmap.width() / 2.0, pixmap.height() / 2.0); painter->scale(pixmap.width() / 200.0, -(pixmap.height() / 200.0)); return painter; } /** * Create a painter for the given pixmap that will be placed * into the given widget. The pixmap's background is painted * with the widget's background color, the painter's pen is set * to the widget's foreground color, and then the painter is * returned. * * Origin of the painter will be in the center with the * coordinates, both X and Y, ranging -100 to 100. * * @param widget * Widget used for coloring. * @param pixmap * The Pixmap must be square (width == height). * @param pixmapOptions * Options for creation of pixmap. * @return * Shared pointer containing QPainter for drawing to the pixmap. */ QSharedPointer WuQtUtilities::createPixmapWidgetPainterOriginCenter(const QWidget* widget, QPixmap& pixmap, const uint32_t pixmapOptions) { CaretAssert(pixmap.width() == pixmap.height()); QSharedPointer painter = createPixmapWidgetPainterPrivate(widget, pixmap, pixmapOptions); /* * Note: QPainter has its origin at the top left. * Using a negative for the Y-scale value will * move the origin to the bottom. */ painter->translate(pixmap.width() / 2.0, pixmap.height() / 2.0); painter->scale(1.0, -1.0); return painter; } /** * Create a painter for the given pixmap that will be placed * into the given widget. The pixmap's background is painted * with the widget's background color, the painter's pen is set * to the widget's foreground color, and then the painter is * returned. * * Origin of painter will be in the BOTTOM LEFT corner. * * @param widget * Widget used for coloring. * @param pixmap * The Pixmap. * @param pixmapOptions * Options for creation of pixmap. * @return * Shared pointer containing QPainter for drawing to the pixmap. */ QSharedPointer WuQtUtilities::createPixmapWidgetPainterOriginBottomLeft(const QWidget* widget, QPixmap& pixmap, const uint32_t pixmapOptions) { QSharedPointer painter = createPixmapWidgetPainter(widget, pixmap, pixmapOptions); /* * Note: QPainter has its origin at the top left. * Using a negative for the Y-scale value will * move the origin to the bottom. */ painter->translate(0.0, pixmap.height() - 1); painter->scale(1.0, -1.0); return painter; } /** * Create a painter for the given pixmap that will be placed * into the given widget. The pixmap's background is painted * with the widget's background color, the painter's pen is set * to the widget's foreground color, and then the painter is * returned. * * Origin of painter will be in the TOP LEFT corner. * * @param widget * Widget used for coloring. * @param pixmap * The Pixmap. * @param pixmapOptions * Options for creation of pixmap. * @return * Shared pointer containing QPainter for drawing to the pixmap. */ QSharedPointer WuQtUtilities::createPixmapWidgetPainter(const QWidget* widget, QPixmap& pixmap, const uint32_t pixmapOptions) { return createPixmapWidgetPainterPrivate(widget, pixmap, pixmapOptions); } /** * Create a painter for the given pixmap that will be placed * into the given widget. The pixmap's background is painted * with the widget's background color, the painter's pen is set * to the widget's foreground color, and then the painter is * returned. * * Origin of painter will be in the TOP LEFT corner. * * @param widget * Widget used for coloring. * @param pixmap * The Pixmap. * @param pixmapOptions * Options for creation of the pixmap. * @return * Shared pointer containing QPainter for drawing to the pixmap. */ QSharedPointer WuQtUtilities::createPixmapWidgetPainterPrivate(const QWidget* widget, QPixmap& pixmap, const uint32_t pixmapOptions) { CaretAssert(widget); CaretAssert(pixmap.width() > 0); CaretAssert(pixmap.height() > 0); /* * Get the widget's background and foreground color */ const QPalette palette = widget->palette(); const QPalette::ColorRole backgroundRole = widget->backgroundRole(); const QBrush backgroundBrush = palette.brush(backgroundRole); const QColor backgroundColor = backgroundBrush.color(); const QPalette::ColorRole foregroundRole = widget->foregroundRole(); const QBrush foregroundBrush = palette.brush(foregroundRole); const QColor foregroundColor = foregroundBrush.color(); const bool transparentBackgroundFlag = (pixmapOptions & static_cast(PixMapCreationOptions::TransparentBackground)); if (transparentBackgroundFlag) { /* * It is not possible to create a pixmap with alpha using Qt. * So, create a QImage filled with alpha = 0 and then * let the pixmap copy from the QImage. */ QImage image(pixmap.width(), pixmap.height(), QImage::Format_RGBA8888_Premultiplied); image.fill(QColor(0, 0, 0, 0)); const bool succssFlag = pixmap.convertFromImage(image); if ( ! succssFlag) { CaretLogSevere("Failed to convert image to pixmap"); } } /* * Create a painter and fill the pixmap with * the background color */ QSharedPointer painter(new QPainter(&pixmap)); painter->setRenderHint(QPainter::Antialiasing, true); if (transparentBackgroundFlag) { painter->setBackgroundMode(Qt::TransparentMode); } else { painter->setBackgroundMode(Qt::OpaqueMode); painter->fillRect(pixmap.rect(), backgroundColor); } painter->setPen(foregroundColor); return painter; } /** * With Qt5, a toolbutton placed into a toolbar uses the * background of the toolbar with no border and appears * similar to a label. Use a stylesheet so that * the button appears similar to Qt4. * * @param toolButton * toolButton ToolButton that needs style updated. */ #ifdef CARET_OS_MACOSX #if QT_VERSION >= 0x050000 void WuQtUtilities::setToolButtonStyleForQt5Mac(QToolButton* toolButton) { CaretAssert(toolButton); bool hasMenuFlag = false; bool hasCheckableFlag = false; QAction* action = toolButton->defaultAction(); if (action != NULL) { if (action->menu() != NULL) { hasMenuFlag = true; } if (action->isCheckable()) { hasCheckableFlag = true; } } const QPalette palette = toolButton->palette(); const QPalette::ColorRole backgroundRole = toolButton->backgroundRole(); const QBrush backgroundBrush = palette.brush(backgroundRole); const QColor backgroundColor = backgroundBrush.color(); const QColor lighterColor = backgroundColor.lighter(100); const QColor darkerColor = backgroundColor.darker(125); const QColor slightlyDarkerColor = backgroundColor.darker(115); /* * Use a stylesheet to: * (1) Make the background of the button lighter * (2) Add a border around the button that is slightly * darker than the background. */ QString toolButtonStyleSheet(" QToolButton { " " background: " + lighterColor.name() + "; "); if (hasMenuFlag) { // toolButtonStyleSheet.append(" border-style: solid; " // " border-width: 1px; " // " border-color: " + darkerColor.name() + "; " // " padding-top: 6px; " // " padding-bottom: 6px; " // " padding-right: 4px; " // " padding-left: 3px; "); } else { toolButtonStyleSheet.append(" border-style: solid; " " border-width: 1px; " " border-color: " + darkerColor.name() + "; " " padding-top: 2px; " " padding-bottom: 2px; " " padding-right: 3px; " " padding-left: 3px; "); } toolButtonStyleSheet.append(" } "); if (hasCheckableFlag) { /* * Background color when button is "checked" */ toolButtonStyleSheet.append(" QToolButton:checked { " " background-color: " + slightlyDarkerColor.name() + "; " " } "); } else { /* * Background color when button is "pressed" */ toolButtonStyleSheet.append(" QToolButton:pressed { " " background-color: " + slightlyDarkerColor.name() + "; " " } "); } toolButton->setStyleSheet(toolButtonStyleSheet); } #else void WuQtUtilities::setToolButtonStyleForQt5Mac(QToolButton*) { } #endif #else void WuQtUtilities::setToolButtonStyleForQt5Mac(QToolButton*) { } #endif connectome-workbench-1.4.2/src/GuiQt/WuQtUtilities.h000066400000000000000000000250301360521144700224200ustar00rootroot00000000000000 #ifndef __WU_QT_UTILITIES_H__ #define __WU_QT_UTILITIES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include #include #include "CaretColorEnum.h" class QAction; class QBoxLayout; class QDialog; class QIcon; class QKeySequence; class QLayout; class QObject; class QPixmap; class QPushButton; class QString; class QTableWidget; class QToolButton; class QWidget; namespace caret { /** * Utilities for use with Qt. */ class WuQtUtilities { public: /* * Options for creating pixmaps */ enum PixMapCreationOptions { /* * Create pixmap with transparent background. * Useful for pixmaps used in toolbar toggle buttons so that selection is shaded * in the entire button not just around the pixmap */ TransparentBackground = 1 }; static QToolButton* createToolButtonWithIcon(const QString& text, const QString& iconFileName, const QString& toolTip, QObject* receiver, const char* method); static QAction* createAction(const QString& text, const QString& toolAndStatusTipText, const QKeySequence& shortcut, QObject* parent, QObject* receiver, const char* method); static QAction* createAction(const QString& text, const QString& toolAndStatusTipText, QObject* parent, QObject* receiver, const char* method); static QAction* createAction(const QString& text, const QString& toolAndStatusTipText, QObject* parent); static QAction* createAction(const QString& text, const QString& toolAndStatusTipText, const QKeySequence& shortcut, QObject* parent); static QPushButton* createPushButton(const QString& text, const QString& toolAndStatusTipText, QObject* receiver, const char* method); static QWidget* createVerticalLineWidget(); static QWidget* createHorizontalLineWidget(); static QPixmap createCaretColorEnumPixmap(const QWidget* widget, const int32_t pixmapWidth, const int32_t pixmapHeight, const CaretColorEnum::Enum caretColor, const float customColorRGBA[4], const bool outlineFlag); static QSharedPointer createPixmapWidgetPainter(const QWidget* widget, QPixmap& pixmap, const uint32_t pixmapOptions = 0); static QSharedPointer createPixmapWidgetPainterOriginBottomLeft(const QWidget* widget, QPixmap& pixmap, const uint32_t pixmapOptions = 0); static QSharedPointer createPixmapWidgetPainterOriginCenter(const QWidget* widget, QPixmap& pixmap, const uint32_t pixmapOptions = 0); static QSharedPointer createPixmapWidgetPainterOriginCenter100x100(const QWidget* widget, QPixmap& pixmap, const uint32_t pixmapOptions = 0); static void moveWindowToOffset(QWidget* parentWidget, QWidget* window, const int xOffset, const int yOffset); static void setToolTipAndStatusTip(QWidget* widget, const QString& text); static void setToolTipAndStatusTip(QAction* action, const QString& text); static void sendListOfResourcesToCaretLogger(); static bool loadIcon(const QString& filename, QIcon& iconOut); static QIcon* loadIcon(const QString& filename); static bool loadPixmap(const QString& filename, QPixmap& pixmapOut); static void moveWindowToSideOfParent(QWidget* parent, QWidget* window); static void moveAndSizeWindow(QWidget* window, const int32_t x, const int32_t y, const int32_t w, const int32_t h, int32_t* xywhOut); static void resizeWindow(QWidget* window, const int32_t width, const int32_t height); static void limitWindowSizePercentageOfMaximum(QWidget* window, const float widthMaximumPercentage, const float heightMaximumPercentage); static int getMaximumWidgetHeight(QWidget* w1, QWidget* w2, QWidget* w3 = 0, QWidget* w4 = 0, QWidget* w5 = 0, QWidget* w6 = 0, QWidget* w7 = 0, QWidget* w8 = 0, QWidget* w9 = 0, QWidget* w10 = 0); static void matchWidgetHeights(QWidget* w1, QWidget* w2, QWidget* w3 = 0, QWidget* w4 = 0, QWidget* w5 = 0, QWidget* w6 = 0, QWidget* w7 = 0, QWidget* w8 = 0, QWidget* w9 = 0, QWidget* w10 = 0); static void matchWidgetWidths(QWidget* w1, QWidget* w2, QWidget* w3 = 0, QWidget* w4 = 0, QWidget* w5 = 0, QWidget* w6 = 0, QWidget* w7 = 0, QWidget* w8 = 0, QWidget* w9 = 0, QWidget* w10 = 0); static void setLayoutSpacingAndMargins(QLayout* layout, const int spacing, const int contentsMargin); static void setLayoutMargins(QLayout* layout, const int contentsMargin); static QSize estimateTableWidgetSize(QTableWidget* tableWidget); static QSize getMinimumScreenSize(); static bool isSmallDisplay(); static QString getLayoutContentDescription(QLayout* layout); //static void playSound(const QString& soundFileName); static QString createWordWrappedToolTipText(const QString& tooltipText); static void setWordWrappedToolTip(QWidget* widget, const QString& tooltipText); static void setWordWrappedToolTip(QAction* action, const QString& tooltipText); static bool checkStateToBool(const Qt::CheckState checkState); static Qt::CheckState boolToCheckState(const bool value); static void setToolButtonStyleForQt5Mac(QToolButton* toolButton); private: static QSharedPointer createPixmapWidgetPainterPrivate(const QWidget* widget, QPixmap& pixmap, const uint32_t pixmapOptions = 0); WuQtUtilities(); ~WuQtUtilities(); WuQtUtilities(const WuQtUtilities&); WuQtUtilities& operator=(const WuQtUtilities&); }; } #endif // __WU_QT_UTILITIES_H__ connectome-workbench-1.4.2/src/GuiQt/WuQwtPlot.cxx000066400000000000000000000042041360521144700221250ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __WU_QWT_PLOT_DECLARE__ #include "WuQwtPlot.h" #undef __WU_QWT_PLOT_DECLARE__ #include #include #include "qwt_plot_canvas.h" #include "CaretAssert.h" using namespace caret; /** * \class caret::WuQwtPlot * \brief Extends QwtPlot * \ingroup GuiQt * * Extends QwtPlot by adding a context menu with graph coordinates */ /** * Constructor. */ WuQwtPlot::WuQwtPlot(QWidget* w) : QwtPlot(w) { } /** * Destructor. */ WuQwtPlot::~WuQwtPlot() { } /** * Receives the context menu event. * * @param event * The context menu event. */ void WuQwtPlot::contextMenuEvent(QContextMenuEvent* event) { QPoint canvasPos = canvas()->mapFromGlobal(event->globalPos()); const QPointF plotPos = inverseTransform(canvasPos); emit contextMenuDisplay(event, plotPos.x(), plotPos.y()); } /*! Translate a point from pixel into plot coordinates \return Point in plot coordinates \sa transform() */ QPointF WuQwtPlot::inverseTransform( const QPoint &pos ) const { QwtScaleMap xMap = canvasMap( QwtPlot::xBottom ); QwtScaleMap yMap = canvasMap( QwtPlot::yLeft ); return QPointF( xMap.invTransform( pos.x() ), yMap.invTransform( pos.y() ) ); } connectome-workbench-1.4.2/src/GuiQt/WuQwtPlot.h000066400000000000000000000033251360521144700215550ustar00rootroot00000000000000#ifndef __WU_QWT_PLOT_H__ #define __WU_QWT_PLOT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "qwt_plot.h" namespace caret { class WuQwtPlot : public QwtPlot { Q_OBJECT public: WuQwtPlot(QWidget* w = 0); virtual ~WuQwtPlot(); virtual void contextMenuEvent(QContextMenuEvent* event); // ADD_NEW_METHODS_HERE QPointF inverseTransform( const QPoint &pos ) const; signals: void contextMenuDisplay(QContextMenuEvent* event, float graphX, float graphY); private: WuQwtPlot(const WuQwtPlot&); WuQwtPlot& operator=(const WuQwtPlot&); // ADD_NEW_MEMBERS_HERE }; #ifdef __WU_QWT_PLOT_DECLARE__ // #endif // __WU_QWT_PLOT_DECLARE__ } // namespace #endif //__WU_QWT_PLOT_H__ connectome-workbench-1.4.2/src/GuiQt/ZipSceneFileDialog.cxx000066400000000000000000000263021360521144700236420ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __ZIP_SCENE_FILE_DIALOG_DECLARE__ #include "ZipSceneFileDialog.h" #undef __ZIP_SCENE_FILE_DIALOG_DECLARE__ #include #include #include #include #include #include #include #include #include "BalsaDatabaseManager.h" #include "Brain.h" #include "CaretAssert.h" #include "CaretFileDialog.h" #include "CaretLogger.h" #include "CursorDisplayScoped.h" #include "DataFileException.h" #include "FileInformation.h" #include "GuiManager.h" #include "SceneBasePathWidget.h" #include "SceneFile.h" #include "SystemUtilities.h" #include "WuQMessageBox.h" using namespace caret; /** * \class caret::ZipSceneFileDialog * \brief Dialog for zipping a scene file. * \ingroup GuiQt */ /** * Constructor. * * @param sceneFile * Scene file that will be uploaded. * @param parent * Parent of this dialog. */ ZipSceneFileDialog::ZipSceneFileDialog(SceneFile* sceneFile, QWidget* parent) : WuQDialogModal("Zip Scene File", parent), m_sceneFile(sceneFile) { const int minimumLineEditWidth = 400; AString defaultExtractToDirectoryName("ext_dir"); AString zipFileName("file.zip"); FileInformation fileInfo(sceneFile->getFileName()); AString sceneFileDirectory = fileInfo.getAbsolutePath(); if ( ! sceneFileDirectory.isEmpty()) { QDir dir(sceneFileDirectory); if (dir.exists()) { const AString dirName = dir.dirName(); if ( ! dirName.isEmpty()) { if (dirName != ".") { defaultExtractToDirectoryName = dirName; } } } } else { sceneFileDirectory = GuiManager::get()->getBrain()->getCurrentDirectory(); } if ( ! sceneFileDirectory.isEmpty()) { zipFileName = FileInformation::assembleFileComponents(sceneFileDirectory, sceneFile->getFileNameNoPathNoExtension(), "zip"); } /* * ZIP file */ m_zipFileNameLabel = new QLabel("Zip File Name"); m_zipFileNameLineEdit = new QLineEdit; m_zipFileNameLineEdit->setToolTip("Name of the ZIP file"); m_zipFileNameLineEdit->setMinimumWidth(minimumLineEditWidth); m_zipFileNameLineEdit->setText(zipFileName); m_zipFileNameLineEdit->setValidator(createValidator(LabelName::ZIP_FILE)); QObject::connect(m_zipFileNameLineEdit, &QLineEdit::textEdited, this, [=] { this->validateData(); }); /* * Zip file button */ QPushButton* chooseZipFileButton = new QPushButton("Browse..."); QObject::connect(chooseZipFileButton, SIGNAL(clicked()), this, SLOT(chooseZipFileButtonClicked())); /* * Extract to directory */ m_extractDirectoryLabel = new QLabel("Extract to Directory"); m_extractDirectoryNameLineEdit = new QLineEdit(); m_extractDirectoryNameLineEdit->setToolTip("Directory that is created when user unzips the ZIP file"); m_extractDirectoryNameLineEdit->setMinimumWidth(minimumLineEditWidth); m_extractDirectoryNameLineEdit->setValidator(createValidator(LabelName::EXTRACT_DIRECTORY)); QObject::connect(m_extractDirectoryNameLineEdit, &QLineEdit::textEdited, this, [=] { this->validateData(); }); /* * Base Directory */ m_basePathWidget = new SceneBasePathWidget(); QGroupBox* zipFileGroupBox = new QGroupBox("Zip File"); QGridLayout* zipFileLayout = new QGridLayout(zipFileGroupBox); zipFileLayout->setSpacing(2); zipFileLayout->setColumnStretch(0, 0); zipFileLayout->setColumnStretch(1, 100); zipFileLayout->setColumnStretch(2, 0); int row = 0; zipFileLayout->addWidget(m_zipFileNameLabel, row, 0); zipFileLayout->addWidget(m_zipFileNameLineEdit, row, 1); zipFileLayout->addWidget(chooseZipFileButton, row, 2); row++; zipFileLayout->addWidget(m_extractDirectoryLabel, row, 0); zipFileLayout->addWidget(m_extractDirectoryNameLineEdit, row, 1); row++; QWidget* dialogWidget = new QWidget(); QVBoxLayout* dialogLayout = new QVBoxLayout(dialogWidget); dialogLayout->addWidget(zipFileGroupBox); dialogLayout->addWidget(m_basePathWidget); row++; AString extractDirectory = m_sceneFile->getBalsaExtractToDirectoryName(); if (extractDirectory.isEmpty()) { extractDirectory = m_sceneFile->getDefaultExtractToDirectoryName(); } m_extractDirectoryNameLineEdit->setText(extractDirectory); setCentralWidget(dialogWidget, WuQDialogModal::SCROLL_AREA_NEVER); m_basePathWidget->updateWithSceneFile(m_sceneFile); validateData(); } /** * Destructor. */ ZipSceneFileDialog::~ZipSceneFileDialog() { } void ZipSceneFileDialog::validateData() { setLabelText(LabelName::EXTRACT_DIRECTORY); setLabelText(LabelName::ZIP_FILE); } /** * Choose the zip file name with a file browser dialog. */ void ZipSceneFileDialog::chooseZipFileButtonClicked() { /* * Let user choose a different path/name */ AString newZipFileName = CaretFileDialog::getSaveFileNameDialog(this, "Choose Zip File Name", m_zipFileNameLineEdit->text().trimmed(), "Zip File (*.zip)"); /* * If user cancels, delete the new scene file and return */ if (newZipFileName.isEmpty()) { return; } m_zipFileNameLineEdit->setText(newZipFileName); } /** * Gets called when the OK button is clicked. */ void ZipSceneFileDialog::okButtonClicked() { const AString zipFileName = m_zipFileNameLineEdit->text().trimmed(); const AString extractToDirectoryName = m_extractDirectoryNameLineEdit->text().trimmed(); AString errorMessage; if (zipFileName.isEmpty()) { errorMessage.appendWithNewLine("Zip file name is missing"); } if ( ! m_extractDirectoryNameLineEdit->hasAcceptableInput()) { errorMessage.appendWithNewLine("Extract to Directory is invalid.

    "); } AString basePathErrorMessage; if ( ! m_basePathWidget->isValid(basePathErrorMessage)) { errorMessage.appendWithNewLine(basePathErrorMessage); } if (errorMessage.isEmpty()) { m_sceneFile->setBalsaExtractToDirectoryName(extractToDirectoryName); if (m_sceneFile->isModified()) { const QString msg("The scene file is modified and must be saved before continuing. Would you like " "to save the scene file using its current name and continue?"); if (WuQMessageBox::warningYesNo(this, msg)) { try { Brain* brain = GuiManager::get()->getBrain(); brain->writeDataFile(m_sceneFile); } catch (const DataFileException& e) { WuQMessageBox::errorOk(this, e.whatString()); return; } } else { return; } } CursorDisplayScoped cursor; cursor.showWaitCursor(); const bool successFlag = BalsaDatabaseManager::zipSceneAndDataFiles(m_sceneFile, extractToDirectoryName, zipFileName, errorMessage); if ( ! successFlag) { if (errorMessage.isEmpty()) { errorMessage = "Zipping scene file failed with unknown error."; } } cursor.restoreCursor(); } if (errorMessage.isEmpty()) { WuQMessageBox::informationOk(this, "Zip file was successfully created"); } else { WuQMessageBox::errorOk(this, errorMessage); return; } WuQDialogModal::okButtonClicked(); } /** * Create a regular expression validatory for the give label/data. * * @param labelName * 'Name' of label. */ QRegularExpressionValidator* ZipSceneFileDialog::createValidator(const LabelName labelName) { QRegularExpression regEx; switch (labelName) { case LabelName::EXTRACT_DIRECTORY: regEx.setPattern(".+"); break; case LabelName::ZIP_FILE: regEx.setPattern(".+\\.zip$"); break; } CaretAssert(regEx.isValid()); QRegularExpressionValidator* validator = new QRegularExpressionValidator(regEx, this); return validator; } /** * Set the label's text. * * @param label * The label * @param labelName * 'Name' of the label */ void ZipSceneFileDialog::setLabelText(const LabelName labelName) { QLabel* label = NULL; AString labelText; bool validFlag = false; switch (labelName) { case LabelName::EXTRACT_DIRECTORY: label = m_extractDirectoryLabel; labelText = "Extract to Directory"; validFlag = m_extractDirectoryNameLineEdit->hasAcceptableInput(); break; case LabelName::ZIP_FILE: label = m_zipFileNameLabel; labelText = "Zip File Name"; validFlag = m_zipFileNameLineEdit->hasAcceptableInput(); break; } const bool textRedIfInvalid = true; AString coloredText; if (validFlag) { if (textRedIfInvalid) { coloredText = (labelText + ": "); } else { coloredText = (" " + labelText + ": "); } } else { if (textRedIfInvalid) { coloredText = ("" + labelText + ": "); } else { coloredText = ("" + labelText + "*" ": "); } } CaretAssert(label); label->setText(coloredText); } connectome-workbench-1.4.2/src/GuiQt/ZipSceneFileDialog.h000066400000000000000000000046711360521144700232740ustar00rootroot00000000000000#ifndef __ZIP_SCENE_FILE_DIALOG_H__ #define __ZIP_SCENE_FILE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "WuQDialogModal.h" class QLabel; class QLineEdit; class QPushButton; class QRegularExpressionValidator; namespace caret { class SceneFile; class SceneBasePathWidget; class ZipSceneFileDialog : public WuQDialogModal { Q_OBJECT public: ZipSceneFileDialog(SceneFile* sceneFile, QWidget* parent); virtual ~ZipSceneFileDialog(); // ADD_NEW_METHODS_HERE protected: virtual void okButtonClicked(); private slots: void chooseZipFileButtonClicked(); void validateData(); private: enum class LabelName { EXTRACT_DIRECTORY, ZIP_FILE }; ZipSceneFileDialog(const ZipSceneFileDialog&); ZipSceneFileDialog& operator=(const ZipSceneFileDialog&); QRegularExpressionValidator* createValidator(const LabelName labelName); void setLabelText(const LabelName labelName); SceneFile* m_sceneFile; QLabel* m_zipFileNameLabel; QLineEdit* m_zipFileNameLineEdit; QLabel* m_extractDirectoryLabel; QLineEdit* m_extractDirectoryNameLineEdit; SceneBasePathWidget* m_basePathWidget; // ADD_NEW_MEMBERS_HERE }; #ifdef __ZIP_SCENE_FILE_DIALOG_DECLARE__ // #endif // __ZIP_SCENE_FILE_DIALOG_DECLARE__ } // namespace #endif //__ZIP_SCENE_FILE_DIALOG_H__ connectome-workbench-1.4.2/src/Nifti/000077500000000000000000000000001360521144700174735ustar00rootroot00000000000000connectome-workbench-1.4.2/src/Nifti/CMakeLists.txt000066400000000000000000000012601360521144700222320ustar00rootroot00000000000000# # The NIFTI Project # project (Nifti) # # Need XML from Qt # # # Add QT for includes # if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) endif() IF (QT4_FOUND) SET(QT_DONT_USE_QTGUI) INCLUDE(${QT_USE_FILE}) ENDIF () # # Create the NIFTI library # ADD_LIBRARY(Nifti ControlPoint3D.h Matrix4x4.h NiftiHeader.h NiftiIO.h ControlPoint3D.cxx Matrix4x4.cxx NiftiHeader.cxx NiftiIO.cxx ) TARGET_LINK_LIBRARIES(Nifti ${CARET_QT5_LINK}) # # Find Headers # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Nifti ${CMAKE_SOURCE_DIR}/FilesBase ${CMAKE_SOURCE_DIR}/Common ${CMAKE_SOURCE_DIR}/Palette ${CMAKE_SOURCE_DIR}/Cifti ${CMAKE_SOURCE_DIR}/Scenes ${CMAKE_SOURCE_DIR}/Xml ) connectome-workbench-1.4.2/src/Nifti/ControlPoint3D.cxx000066400000000000000000000266331360521144700230520ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __CONTROL_POINT3_D_DECLARE__ #include "ControlPoint3D.h" #undef __CONTROL_POINT3_D_DECLARE__ #include "CaretAssert.h" #include "CaretLogger.h" #include "MathFunctions.h" #include "SceneClass.h" #include "SceneClassAssistant.h" using namespace caret; /** * \class caret::ControlPoint3D * \brief 3D control point with source and target coordinates. * \ingroup Common */ /** * Constructor. * * @param sourceXYZ * The source coordinate. * @param targetXYZ * The target coordinate. */ ControlPoint3D::ControlPoint3D(const float sourceXYZ[3], const float targetXYZ[3]) : CaretObjectTracksModification(), SceneableInterface(), m_sourceX(sourceXYZ[0]), m_sourceY(sourceXYZ[1]), m_sourceZ(sourceXYZ[2]), m_targetX(targetXYZ[0]), m_targetY(targetXYZ[1]), m_targetZ(targetXYZ[2]), m_transformedX(0.0), m_transformedY(0.0), m_transformedZ(0.0) { initializeInstance(); setModified(); } /** * Constructor. * * @param sourceX * The source X-coordinate. * @param sourceY * The source Y-coordinate. * @param sourceZ * The source Z-coordinate. * @param targetX * The target X-coordinate. * @param targetY * The target Y-coordinate. * @param targetZ * The target Z-coordinate. */ ControlPoint3D::ControlPoint3D(const float sourceX, const float sourceY, const float sourceZ, const float targetX, const float targetY, const float targetZ) : CaretObjectTracksModification(), SceneableInterface(), m_sourceX(sourceX), m_sourceY(sourceY), m_sourceZ(sourceZ), m_targetX(targetX), m_targetY(targetY), m_targetZ(targetZ), m_transformedX(0.0), m_transformedY(0.0), m_transformedZ(0.0) { initializeInstance(); setModified(); } /** * Destructor. */ ControlPoint3D::~ControlPoint3D() { delete m_sceneAssistant; } /** * Copy constructor. * @param obj * Object that is copied. */ ControlPoint3D::ControlPoint3D(const ControlPoint3D& obj) : CaretObjectTracksModification(obj), SceneableInterface(obj) { initializeInstance(); this->copyHelperControlPoint3D(obj); } /** * Assignment operator. * @param obj * Data copied from obj to this. * @return * Reference to this object. */ ControlPoint3D& ControlPoint3D::operator=(const ControlPoint3D& obj) { if (this != &obj) { CaretObject::operator=(obj); this->copyHelperControlPoint3D(obj); } return *this; } /** * Helps with copying an object of this type. * @param obj * Object that is copied. */ void ControlPoint3D::copyHelperControlPoint3D(const ControlPoint3D& obj) { m_sourceX = obj.m_sourceX; m_sourceY = obj.m_sourceY; m_sourceZ = obj.m_sourceZ; m_targetX = obj.m_targetX; m_targetY = obj.m_targetY; m_targetZ = obj.m_targetZ; m_transformedX = obj.m_transformedX; m_transformedY = obj.m_transformedY; m_transformedZ = obj.m_transformedZ; setModified(); } /** * Initialize an instance of a control point */ void ControlPoint3D::initializeInstance() { m_sceneAssistant = new SceneClassAssistant(); m_sceneAssistant->add("m_sourceX", &m_sourceX); m_sceneAssistant->add("m_sourceY", &m_sourceY); m_sceneAssistant->add("m_sourceZ", &m_sourceZ); m_sceneAssistant->add("m_targetX", &m_targetX); m_sceneAssistant->add("m_targetY", &m_targetY); m_sceneAssistant->add("m_targetZ", &m_targetZ); m_sceneAssistant->add("m_transformedX", &m_transformedX); m_sceneAssistant->add("m_transformedY", &m_transformedY); m_sceneAssistant->add("m_transformedZ", &m_transformedZ); } /** * Get the source coordinate. * * @param pt * Output with source coordinate. */ void ControlPoint3D::getSourceXYZ(double pt[3]) const { pt[0] = m_sourceX; pt[1] = m_sourceY; pt[2] = m_sourceZ; } /** * Get the target coordinate. * * @param pt * Output with target coordinate. */ void ControlPoint3D::getTargetXYZ(double pt[3]) const { pt[0] = m_targetX; pt[1] = m_targetY; pt[2] = m_targetZ; } /** * Get the transformed coordinate that is * source coordinate multiplied by * the landmard transformation matrix. * Can be compared with target coordinate * for error measurement. * * @param pt * Output with transformed coordinate. */ void ControlPoint3D::getTransformedXYZ(double pt[3]) const { pt[0] = m_transformedX; pt[1] = m_transformedY; pt[2] = m_transformedZ; } /** * Set the transformed coordinate that is * source coordinate multiplied by * the landmard transformation matrix. * Can be compared with target coordinate * for error measurement. * * @param pt * Output with transformed coordinate. */ void ControlPoint3D::setTransformedXYZ(const double pt[3]) { m_transformedX = pt[0]; m_transformedY = pt[1]; m_transformedZ = pt[2]; } /** * Get the transformed coordinate that is * source coordinate multiplied by * the landmard transformation matrix. * Can be compared with target coordinate * for error measurement. * * @param pt * Output with transformed coordinate. */ void ControlPoint3D::getTransformedXYZ(float pt[3]) const { pt[0] = m_transformedX; pt[1] = m_transformedY; pt[2] = m_transformedZ; } /** * Set the transformed coordinate that is * source coordinate multiplied by * the landmard transformation matrix. * Can be compared with target coordinate * for error measurement. * * @param pt * Output with transformed coordinate. */ void ControlPoint3D::setTransformedXYZ(const float pt[3]) { m_transformedX = pt[0]; m_transformedY = pt[1]; m_transformedZ = pt[2]; } /** * Get the source coordinate. * * @param pt * Output with source coordinate. */ void ControlPoint3D::getSourceXYZ(float pt[3]) const { pt[0] = m_sourceX; pt[1] = m_sourceY; pt[2] = m_sourceZ; } /** * Get the target coordinate. * * @param pt * Output with target coordinate. */ void ControlPoint3D::getTargetXYZ(float pt[3]) const { pt[0] = m_targetX; pt[1] = m_targetY; pt[2] = m_targetZ; } /** * @return The source X-coordinate */ float ControlPoint3D::getSourceX() const { return m_sourceX; } /** * @return The source Y-coordinate */ float ControlPoint3D::getSourceY() const { return m_sourceY; } /** * @return The source Z-coordinate */ float ControlPoint3D::getSourceZ() const { return m_sourceZ; } /** * @return The target X-coordinate */ float ControlPoint3D::getTargetX() const { return m_targetX; } /** * @return The target Y-coordinate */ float ControlPoint3D::getTargetY() const { return m_targetY; } /** @return * The target Z-coordinate */ float ControlPoint3D::getTargetZ() const { return m_targetZ; } /** * Get the error measurements. Error is difference * between target and transformed coordinates. * * @param xyzTotalErrorOut * 4 elements error in x, y, z, and total error. */ void ControlPoint3D::getErrorMeasurements(float xyzTotalErrorOut[4]) const { xyzTotalErrorOut[0] = std::fabs(m_targetX - m_transformedX); xyzTotalErrorOut[1] = std::fabs(m_targetY - m_transformedY); xyzTotalErrorOut[2] = std::fabs(m_targetZ - m_transformedZ); xyzTotalErrorOut[3] = std::sqrt((xyzTotalErrorOut[0] * xyzTotalErrorOut[0]) + (xyzTotalErrorOut[1] * xyzTotalErrorOut[1]) + (xyzTotalErrorOut[2] * xyzTotalErrorOut[2])); } /** * @return String containing control point coordinates. */ AString ControlPoint3D::toString() const { const AString s("Source: (" + AString::number(m_sourceX) + ", " + AString::number(m_sourceY) + ", " + AString::number(m_sourceZ) + ") Target: (" + AString::number(m_targetX) + ", " + AString::number(m_targetY) + ", " + AString::number(m_targetZ) + ") Transformed: (" + AString::number(m_transformedX) + ", " + AString::number(m_transformedY) + ", " + AString::number(m_transformedZ) + ")"); return s; } /** * Get the normal vector for the source coordinates of the first three * control points. If there are less than three control points, * a unit vector is returned. * * @param controlPoints * The control points. * @param sourceNormalVectorOut * Output unit normal vector for source points. */ void ControlPoint3D::getSourceNormalVector(const std::vector& controlPoints, float sourceNormalVectorOut[3]) { if (controlPoints.size() < 3) { sourceNormalVectorOut[0] = 0.0; sourceNormalVectorOut[1] = 0.0; sourceNormalVectorOut[2] = 1.0; CaretLogSevere("Cannot compute normal vector for fewer than three control points."); } CaretAssertVectorIndex(controlPoints, 2); float s1[3]; controlPoints[0].getSourceXYZ(s1); float s2[3]; controlPoints[1].getSourceXYZ(s2); float s3[3]; controlPoints[2].getSourceXYZ(s3); MathFunctions::normalVector(s1, s2, s3, sourceNormalVectorOut); } /** * Save information specific to this type of model to the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * saving the scene. * * @param instanceName * Name of instance in the scene. */ SceneClass* ControlPoint3D::saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName) { SceneClass* sceneClass = new SceneClass(instanceName, "ControlPoint", 1); m_sceneAssistant->saveMembers(sceneAttributes, sceneClass); return sceneClass; } /** * Restore information specific to the type of model from the scene. * * @param sceneAttributes * Attributes for the scene. Scenes may be of different types * (full, generic, etc) and the attributes should be checked when * restoring the scene. * * @param sceneClass * sceneClass from which model specific information is obtained. */ void ControlPoint3D::restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass) { if (sceneClass == NULL) { return; } m_sceneAssistant->restoreMembers(sceneAttributes, sceneClass); } connectome-workbench-1.4.2/src/Nifti/ControlPoint3D.h000066400000000000000000000073041360521144700224710ustar00rootroot00000000000000#ifndef __CONTROL_POINT3_D_H__ #define __CONTROL_POINT3_D_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObjectTracksModification.h" #include "SceneableInterface.h" namespace caret { class SceneClassAssistant; class ControlPoint3D : public CaretObjectTracksModification, public SceneableInterface { public: ControlPoint3D(const float sourceXYZ[3], const float targetXYZ[3]); ControlPoint3D(const float sourceX, const float sourceY, const float sourceZ, const float targetX, const float targetY, const float targetZ); virtual ~ControlPoint3D(); ControlPoint3D(const ControlPoint3D& obj); ControlPoint3D& operator=(const ControlPoint3D& obj); void getSourceXYZ(double pt[3]) const; void getTargetXYZ(double pt[3]) const; void getTransformedXYZ(double pt[3]) const; void setTransformedXYZ(const double pt[3]); void getSourceXYZ(float pt[3]) const; void getTargetXYZ(float pt[3]) const; void getTransformedXYZ(float pt[3]) const; void setTransformedXYZ(const float pt[3]); float getSourceX() const; float getSourceY() const; float getSourceZ() const; float getTargetX() const; float getTargetY() const; float getTargetZ() const; void getErrorMeasurements(float xyzTotalErrorOut[4]) const; virtual AString toString() const; static void getSourceNormalVector(const std::vector& controlPoints, float sourceNormalVectorOut[3]); virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); virtual void restoreFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); // ADD_NEW_METHODS_HERE private: void copyHelperControlPoint3D(const ControlPoint3D& obj); void initializeInstance(); // ADD_NEW_MEMBERS_HERE SceneClassAssistant* m_sceneAssistant; float m_sourceX; float m_sourceY; float m_sourceZ; float m_targetX; float m_targetY; float m_targetZ; float m_transformedX; float m_transformedY; float m_transformedZ; }; #ifdef __CONTROL_POINT3_D_DECLARE__ // #endif // __CONTROL_POINT3_D_DECLARE__ } // namespace #endif //__CONTROL_POINT3_D_H__ connectome-workbench-1.4.2/src/Nifti/Matrix4x4.cxx000066400000000000000000002102121360521144700220210ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkBase64Utilities.h,v $ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. Program: Visualization Toolkit Module: $RCSfile: vtkMatrix4x4.cxx,v $ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "ControlPoint3D.h" #include "MathFunctions.h" #include "Matrix4x4.h" #include "NiftiEnums.h" #include "XmlWriter.h" using namespace caret; //static const bool INFO = false; //static const bool DEBUG = false; //static const float iDF = 1.0f; static const double SMALL_POSITIVE_NUMBER = 0.000001; static const double SMALL_NEGATIVE_NUMBER = -0.000001; /** * * constructor that creates an identity matrix. * */ Matrix4x4::Matrix4x4() : CaretObject() { this->initializeMembersMatrix4x4(); } /** * Destructor */ Matrix4x4::~Matrix4x4() { } /** * Copy Constructor * @param Object that is copied. */ Matrix4x4::Matrix4x4(const Matrix4x4& o) : CaretObject(o) { this->initializeMembersMatrix4x4(); this->copyHelper(o); } /** * Assignment operator. */ Matrix4x4& Matrix4x4::operator=(const Matrix4x4& o) { if (this != &o) { CaretObject::operator=(o); this->copyHelper(o); }; return *this; } /** * Helps with copy constructor and assignment operator. */ void Matrix4x4::copyHelper(const Matrix4x4& o) { this->setMatrix(o); this->dataSpaceName = o.dataSpaceName; this->transformedSpaceName = o.transformedSpaceName; } void Matrix4x4::initializeMembersMatrix4x4() { this->identity(); this->dataSpaceName = NiftiTransformEnum::toName(NiftiTransformEnum::NIFTI_XFORM_TALAIRACH); this->transformedSpaceName = NiftiTransformEnum::toName(NiftiTransformEnum::NIFTI_XFORM_TALAIRACH); this->clearModified(); } /** * Set the matrix to the identity matrix. * */ void Matrix4x4::identity() { matrix[0][0] = 1.0; matrix[0][1] = 0.0; matrix[0][2] = 0.0; matrix[0][3] = 0.0; matrix[1][0] = 0.0; matrix[1][1] = 1.0; matrix[1][2] = 0.0; matrix[1][3] = 0.0; matrix[2][0] = 0.0; matrix[2][1] = 0.0; matrix[2][2] = 1.0; matrix[2][3] = 0.0; matrix[3][0] = 0.0; matrix[3][1] = 0.0; matrix[3][2] = 0.0; matrix[3][3] = 1.0; this->setModified(); } /** * Get the translation from the matrix. * * param The translation as an array of three floats. * */ void Matrix4x4::getTranslation(float translatationOut[3]) const { translatationOut[0] = matrix[0][3]; translatationOut[1] = matrix[1][3]; translatationOut[2] = matrix[2][3]; } /** * Set (replace) the matrix's translation. * * @param t An array of three float containing the translation. * */ void Matrix4x4::setTranslation(const float t[3]) { matrix[0][3] = t[0]; matrix[1][3] = t[1]; matrix[2][3] = t[2]; this->setModified(); } /** * Set (replace) the matrix's translation. * * @param tx The translation along the X-Axis. * @param ty The translation along the Y-Axis. * @param tz The translation along the Z-Axis. * */ void Matrix4x4::setTranslation( const double tx, const double ty, const double tz) { matrix[0][3] = tx; matrix[1][3] = ty; matrix[2][3] = tz; this->setModified(); } /** * * Apply a translation by multiplying the matrix by a matrix * containing the specified translation. Translates in the * screen' coordinate system. * * @param tx The translation along the X-Axis. * @param ty The translation along the Y-Axis. * @param tz The translation along the Z-Axis. * */ void Matrix4x4::translate( const double tx, const double ty, const double tz) { Matrix4x4 cm; cm.setTranslation(tx, ty, tz); postmultiply(cm); this->setModified(); } /** * * Apply a translation by multiplying the matrix by a matrix * containing the specified translation. Translates in the * screen' coordinate system. * * @param txyz The translation along the XYZ-Axis. */ void Matrix4x4::translate(const double txyz[3]) { translate(txyz[0], txyz[1], txyz[2]); } /** * Apply scaling by multiplying the matrix by a matrix * containing the specified scaling. Translates in the * screen' coordinate system. * * @param sx The scaling along the X-Axis. * @param sy The scaling along the Y-Axis. * @param sz The scaling along the Z-Axis. * */ void Matrix4x4::scale( const double sx, const double sy, const double sz) { Matrix4x4 cm; cm.matrix[0][0] = sx; cm.matrix[1][1] = sy; cm.matrix[2][2] = sz; postmultiply(cm); this->setModified(); } /** * Get the scaling from the matrix. * @param scaleOutX * X scaling output. * @param scaleOutY * Y scaling output. * @param scaleOutZ * Z scaling output. */ void Matrix4x4::getScale(double& scaleOutX, double& scaleOutY, double& scaleOutZ) const { double U[3][3], VT[3][3]; for (int i = 0; i < 3; i++) { U[0][i] = matrix[0][i]; U[1][i] = matrix[1][i]; U[2][i] = matrix[2][i]; } double scale[3]; Matrix4x4::SingularValueDecomposition3x3(U, U, scale, VT); scaleOutX = scale[0]; scaleOutY = scale[1]; scaleOutZ = scale[2]; } //---------------------------------------------------------------------------- // Perform singular value decomposition on the matrix A: // A = U * W * VT // where U and VT are orthogonal W is diagonal (the diagonal elements // are returned in vector w). // The matrices U and VT will both have positive determinants. // The scale factors w are ordered according to how well the // corresponding eigenvectors (in VT) match the x, y and z axes // respectively. // // The singular value decomposition is used to decompose a linear // transformation into a rotation, followed by a scale, followed // by a second rotation. The scale factors w will be negative if // the determinant of matrix A is negative. // // Contributed by David Gobbi (dgobbi@irus.rri.on.ca) void Matrix4x4::SingularValueDecomposition3x3(const double A[3][3], double U[3][3], double w[3], double VT[3][3]) { int i; double B[3][3]; // copy so that A can be used for U or VT without risk for (i = 0; i < 3; i++) { B[0][i] = A[0][i]; B[1][i] = A[1][i]; B[2][i] = A[2][i]; } // temporarily flip if determinant is negative double d = Determinant3x3(B); if (d < 0) { for (i = 0; i < 3; i++) { B[0][i] = -B[0][i]; B[1][i] = -B[1][i]; B[2][i] = -B[2][i]; } } // orthogonalize, diagonalize, etc. Orthogonalize3x3(B, U); Transpose3x3(B, B); Multiply3x3(B, U, VT); Diagonalize3x3(VT, w, VT); Multiply3x3(U, VT, U); Transpose3x3(VT, VT); // re-create the flip if (d < 0) { w[0] = -w[0]; w[1] = -w[1]; w[2] = -w[2]; } /* paranoia check: recombine to ensure that the SVD is correct vtkMath::Transpose3x3(B, B); if (d < 0) { for (i = 0; i < 3; i++) { B[0][i] = -B[0][i]; B[1][i] = -B[1][i]; B[2][i] = -B[2][i]; } } int j; T2 maxerr = 0; T2 tmp; T2 M[3][3]; T2 W[3][3]; vtkMath::Identity3x3(W); W[0][0] = w[0]; W[1][1] = w[1]; W[2][2] = w[2]; vtkMath::Identity3x3(M); vtkMath::Multiply3x3(M, U, M); vtkMath::Multiply3x3(M, W, M); vtkMath::Multiply3x3(M, VT, M); for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { if ((tmp = fabs(B[i][j] - M[i][j])) > maxerr) { maxerr = tmp; } } } vtkGenericWarningMacro("SingularValueDecomposition max error = " << maxerr); */ } void Matrix4x4::Diagonalize3x3(const double A[3][3], double w[3], double V[3][3]) { int i,j,k,maxI; double tmp, maxVal; // do the matrix[3][3] to **matrix conversion for Jacobi double C[3][3]; double *ATemp[3],*VTemp[3]; for (i = 0; i < 3; i++) { C[i][0] = A[i][0]; C[i][1] = A[i][1]; C[i][2] = A[i][2]; ATemp[i] = C[i]; VTemp[i] = V[i]; } // diagonalize using Jacobi Matrix4x4::JacobiN(ATemp,3,w,VTemp); // if all the eigenvalues are the same, return identity matrix if (w[0] == w[1] && w[0] == w[2]) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { V[i][j] = 0.0; } } return; } // transpose temporarily, it makes it easier to sort the eigenvectors Transpose3x3(V,V); // if two eigenvalues are the same, re-orthogonalize to optimally line // up the eigenvectors with the x, y, and z axes for (i = 0; i < 3; i++) { if (w[(i+1)%3] == w[(i+2)%3]) // two eigenvalues are the same { // find maximum element of the independant eigenvector maxVal = fabs(V[i][0]); maxI = 0; for (j = 1; j < 3; j++) { if (maxVal < (tmp = fabs(V[i][j]))) { maxVal = tmp; maxI = j; } } // swap the eigenvector into its proper position if (maxI != i) { tmp = w[maxI]; w[maxI] = w[i]; w[i] = tmp; SwapVectors3(V[i],V[maxI]); } // maximum element of eigenvector should be positive if (V[maxI][maxI] < 0) { V[maxI][0] = -V[maxI][0]; V[maxI][1] = -V[maxI][1]; V[maxI][2] = -V[maxI][2]; } // re-orthogonalize the other two eigenvectors j = (maxI+1)%3; k = (maxI+2)%3; V[j][0] = 0.0; V[j][1] = 0.0; V[j][2] = 0.0; V[j][j] = 1.0; MathFunctions::crossProduct(V[maxI],V[j],V[k]); MathFunctions::normalizeVector(V[k]); MathFunctions::crossProduct(V[k],V[maxI],V[j]); // transpose vectors back to columns Transpose3x3(V,V); return; } } // the three eigenvalues are different, just sort the eigenvectors // to align them with the x, y, and z axes // find the vector with the largest x element, make that vector // the first vector maxVal = fabs(V[0][0]); maxI = 0; for (i = 1; i < 3; i++) { if (maxVal < (tmp = fabs(V[i][0]))) { maxVal = tmp; maxI = i; } } // swap eigenvalue and eigenvector if (maxI != 0) { tmp = w[maxI]; w[maxI] = w[0]; w[0] = tmp; SwapVectors3(V[maxI],V[0]); } // do the same for the y element if (fabs(V[1][1]) < fabs(V[2][1])) { tmp = w[2]; w[2] = w[1]; w[1] = tmp; SwapVectors3(V[2],V[1]); } // ensure that the sign of the eigenvectors is correct for (i = 0; i < 2; i++) { if (V[i][i] < 0) { V[i][0] = -V[i][0]; V[i][1] = -V[i][1]; V[i][2] = -V[i][2]; } } // set sign of final eigenvector to ensure that determinant is positive if (Determinant3x3(V) < 0) { V[2][0] = -V[2][0]; V[2][1] = -V[2][1]; V[2][2] = -V[2][2]; } // transpose the eigenvectors back again Transpose3x3(V,V); } #define VTK_ROTATE(a,i,j,k,l) g=a[i][j];h=a[k][l];a[i][j]=g-s*(h+g*tau);\ a[k][l]=h+s*(g-h*tau) // Jacobi iteration for the solution of eigenvectors/eigenvalues of a nxn // real symmetric matrix. Square nxn matrix a; size of matrix in n; // output eigenvalues in w; and output eigenvectors in v. Resulting // eigenvalues/vectors are sorted in decreasing order; eigenvectors are // normalized. int Matrix4x4::JacobiN(double **a, int n, double *w, double **v) { const int VTK_MAX_ROTATIONS = 20; int i, j, k, iq, ip, numPos; double tresh, theta, tau, t, sm, s, h, g, c, tmp; double bspace[4], zspace[4]; double *b = bspace; double *z = zspace; // only allocate memory if the matrix is large if (n > 4) { b = new double[n]; z = new double[n]; } // initialize for (ip=0; ip 3 && (fabs(w[ip])+g) == fabs(w[ip]) && (fabs(w[iq])+g) == fabs(w[iq])) { a[ip][iq] = 0.0; } else if (fabs(a[ip][iq]) > tresh) { h = w[iq] - w[ip]; if ( (fabs(h)+g) == fabs(h)) { t = (a[ip][iq]) / h; } else { theta = 0.5*h / (a[ip][iq]); t = 1.0 / (fabs(theta)+sqrt(1.0+theta*theta)); if (theta < 0.0) { t = -t; } } c = 1.0 / sqrt(1+t*t); s = t*c; tau = s/(1.0+c); h = t*a[ip][iq]; z[ip] -= h; z[iq] += h; w[ip] -= h; w[iq] += h; a[ip][iq]=0.0; // ip already shifted left by 1 unit for (j = 0;j <= ip-1;j++) { VTK_ROTATE(a,j,ip,j,iq); } // ip and iq already shifted left by 1 unit for (j = ip+1;j <= iq-1;j++) { VTK_ROTATE(a,ip,j,j,iq); } // iq already shifted left by 1 unit for (j=iq+1; j= VTK_MAX_ROTATIONS ) { CaretLogWarning("Matrix4x4::Jacobi: Error extracting eigenfunctions"); return 0; } // sort eigenfunctions these changes do not affect accuracy for (j=0; j= tmp) // why exchage if same? { k = i; tmp = w[k]; } } if (k != j) { w[k] = w[j]; w[j] = tmp; for (i=0; i> 1) + (n & 1); for (j=0; j= 0.0 ) { numPos++; } } // if ( numPos < ceil(double(n)/double(2.0)) ) if ( numPos < ceil_half_n) { for(i=0; i 4) { delete [] b; delete [] z; } return 1; } #undef VTK_ROTATE void Matrix4x4::Multiply3x3(const double A[3][3], const double B[3][3], double C[3][3]) { double D[3][3]; for (int i = 0; i < 3; i++) { D[0][i] = A[0][0]*B[0][i] + A[0][1]*B[1][i] + A[0][2]*B[2][i]; D[1][i] = A[1][0]*B[0][i] + A[1][1]*B[1][i] + A[1][2]*B[2][i]; D[2][i] = A[2][0]*B[0][i] + A[2][1]*B[1][i] + A[2][2]*B[2][i]; } for (int j = 0; j < 3; j++) { C[j][0] = D[j][0]; C[j][1] = D[j][1]; C[j][2] = D[j][2]; } } //---------------------------------------------------------------------------- void Matrix4x4::Transpose3x3(const double A[3][3], double AT[3][3]) { double tmp; tmp = A[1][0]; AT[1][0] = A[0][1]; AT[0][1] = tmp; tmp = A[2][0]; AT[2][0] = A[0][2]; AT[0][2] = tmp; tmp = A[2][1]; AT[2][1] = A[1][2]; AT[1][2] = tmp; AT[0][0] = A[0][0]; AT[1][1] = A[1][1]; AT[2][2] = A[2][2]; } /** * Apply a rotation about the X-axis. Rotates in the * screen's coordinate system. * * @param degrees Amount to rotate in degrees. * */ void Matrix4x4::rotateX(const double degrees) { rotate(degrees, 1.0, 0.0, 0.0); } /** * Apply a rotation about the Y-axis. Rotates in the * screen's coordinate system. * * @param degrees Amount to rotate in degrees. * */ void Matrix4x4::rotateY(const double degrees) { rotate(degrees, 0.0, 1.0, 0.0); } /** * Apply a rotation about the Z-axis. Rotates in the * screen's coordinate system. * * @param degrees Amount to rotate in degrees. * */ void Matrix4x4::rotateZ(const double degrees) { rotate(degrees, 0.0, 0.0, 1.0); } /** * Rotate angle degrees about the vector. * @param angle - Angle of rotation. * @param vector - Vector about which rotation occurs. * */ void Matrix4x4::rotate( const double angle, const double vector[4]) { this->rotate(angle, vector[0], vector[1], vector[2]); this->setModified(); } /** * Rotate angle degrees about the vector (x,y,z). * * @param angle Amount to rotate in degrees. * @param xin X-component of the vector. * @param yin Y-component of the vector. * @param zin Z-component of the vector. * */ void Matrix4x4::rotate( const double angleIn, const double xin, const double yin, const double zin) { /// from vtkTransformConcatenation::Rotate() float angle = angleIn; if (angle == 0.0 || (xin == 0.0 && yin == 0.0 && zin == 0.0)) { return; } // convert to radians angle = MathFunctions::toRadians(angle); // make a normalized quaternion double w = std::cos(0.5*angle); double f = std::sin(0.5*angle) / std::sqrt(xin*xin+yin*yin+zin*zin); double x = xin * f; double y = yin * f; double z = zin * f; double ww = w*w; double wx = w*x; double wy = w*y; double wz = w*z; double xx = x*x; double yy = y*y; double zz = z*z; double xy = x*y; double xz = x*z; double yz = y*z; double s = ww - xx - yy - zz; // convert the quaternion to a matrix Matrix4x4 m; m.matrix[0][0] = xx*2.0 + s; m.matrix[1][0] = (xy + wz)*2; m.matrix[2][0] = (xz - wy)*2; m.matrix[0][1] = (xy - wz)*2; m.matrix[1][1] = yy*2.0 + s; m.matrix[2][1] = (yz + wx)*2; m.matrix[0][2] = (xz + wy)*2; m.matrix[1][2] = (yz - wx)*2; m.matrix[2][2] = zz*2.0 + s; postmultiply(m); this->setModified(); } /* * Set the rotation matrix using the given angles. * WARNING: Any scaling or translation is will be removed!!! * * @rotationX * The X-rotation angle. * @rotationY * The Y-rotation angle. * @rotationZ * The Z-rotation angle. */ void Matrix4x4::setRotation(const double rotationX, const double rotationY, const double rotationZ) { identity(); rotateY(rotationY); rotateX(rotationX); rotateZ(rotationZ); } /* * Get the rotation angles from the matrix. * * From vktTransform::GetOrientation() * * @rotationOutX * Output containing X-rotation from matrix. * @rotationOutY * Output containing X-rotation from matrix. * @rotationOutZ * Output containing X-rotation from matrix. */ void Matrix4x4::getRotation(double& rotationOutX, double& rotationOutY, double& rotationOutZ) const { #define VTK_AXIS_EPSILON 0.001 int i; // convenient access to matrix // double (*matrix)[4] = amatrix->Element; double ortho[3][3]; for (i = 0; i < 3; i++) { ortho[0][i] = matrix[0][i]; ortho[1][i] = matrix[1][i]; ortho[2][i] = matrix[2][i]; } if (Determinant3x3(ortho) < 0) { ortho[0][2] = -ortho[0][2]; ortho[1][2] = -ortho[1][2]; ortho[2][2] = -ortho[2][2]; } Matrix4x4::Orthogonalize3x3(ortho, ortho); // first rotate about y axis double x2 = ortho[2][0]; double y2 = ortho[2][1]; double z2 = ortho[2][2]; double x3 = ortho[1][0]; double y3 = ortho[1][1]; double z3 = ortho[1][2]; double d1 = sqrt(x2*x2 + z2*z2); double cosTheta, sinTheta; if (d1 < VTK_AXIS_EPSILON) { cosTheta = 1.0; sinTheta = 0.0; } else { cosTheta = z2/d1; sinTheta = x2/d1; } double theta = std::atan2(sinTheta, cosTheta); rotationOutY = - MathFunctions::toDegrees(theta ); // now rotate about x axis double d = std::sqrt(x2*x2 + y2*y2 + z2*z2); double sinPhi, cosPhi; if (d < VTK_AXIS_EPSILON) { sinPhi = 0.0; cosPhi = 1.0; } else if (d1 < VTK_AXIS_EPSILON) { sinPhi = y2/d; cosPhi = z2/d; } else { sinPhi = y2/d; cosPhi = (x2*x2 + z2*z2)/(d1*d); } double phi = std::atan2(sinPhi, cosPhi); rotationOutX = MathFunctions::toDegrees(phi); // finally, rotate about z double x3p = x3*cosTheta - z3*sinTheta; double y3p = - sinPhi*sinTheta*x3 + cosPhi*y3 - sinPhi*cosTheta*z3; double d2 = std::sqrt(x3p*x3p + y3p*y3p); double cosAlpha, sinAlpha; if (d2 < VTK_AXIS_EPSILON) { cosAlpha = 1.0; sinAlpha = 0.0; } else { cosAlpha = y3p/d2; sinAlpha = x3p/d2; } double alpha = std::atan2(sinAlpha, cosAlpha); rotationOutZ = MathFunctions::toDegrees(alpha); if (MathFunctions::isNaN(rotationOutX)) { rotationOutX = 0.0; } if (MathFunctions::isNaN(rotationOutY)) { rotationOutY = 0.0; } if (MathFunctions::isNaN(rotationOutZ)) { rotationOutZ = 0.0; } } void Matrix4x4::Orthogonalize3x3(const double A[3][3], double B[3][3]) { int i; // copy the matrix for (i = 0; i < 3; i++) { B[0][i] = A[0][i]; B[1][i] = A[1][i]; B[2][i] = A[2][i]; } // Pivot the matrix to improve accuracy double scale[3]; int index[3]; double tmp, largest; // Loop over rows to get implicit scaling information for (i = 0; i < 3; i++) { largest = fabs(B[i][0]); if ((tmp = fabs(B[i][1])) > largest) { largest = tmp; } if ((tmp = fabs(B[i][2])) > largest) { largest = tmp; } scale[i] = 1.0; if (largest != 0) { scale[i] = double(1.0)/largest; } } // first column index[0] = 0; largest = scale[0]*fabs(B[0][0]); if ((tmp = scale[1]*fabs(B[1][0])) >= largest) { largest = tmp; index[0] = 1; } if ((tmp = scale[2]*fabs(B[2][0])) >= largest) { index[0] = 2; } if (index[0] != 0) { SwapVectors3(B[index[0]],B[0]); scale[index[0]] = scale[0]; } // second column index[1] = 1; largest = scale[1]*fabs(B[1][1]); if ((tmp = scale[2]*fabs(B[2][1])) >= largest) { index[1] = 2; SwapVectors3(B[2],B[1]); } // third column index[2] = 2; // A quaternian can only describe a pure rotation, not // a rotation with a flip, therefore the flip must be // removed before the matrix is converted to a quaternion. double d = Matrix4x4::Determinant3x3(B); if (d < 0) { for (i = 0; i < 3; i++) { B[0][i] = -B[0][i]; B[1][i] = -B[1][i]; B[2][i] = -B[2][i]; } } // Do orthogonalization using a quaternion intermediate // (this, essentially, does the orthogonalization via // diagonalization of an appropriately constructed symmetric // 4x4 matrix rather than by doing SVD of the 3x3 matrix) double quat[4]; MathFunctions::matrixToQuatern(B,quat); MathFunctions::quaternToMatrix(quat,B); // Put the flip back into the orthogonalized matrix. if (d < 0) { for (i = 0; i < 3; i++) { B[0][i] = -B[0][i]; B[1][i] = -B[1][i]; B[2][i] = -B[2][i]; } } // Undo the pivoting if (index[1] != 1) { SwapVectors3(B[index[1]],B[1]); } if (index[0] != 0) { SwapVectors3(B[index[0]],B[0]); } } /** * Swap elements in vectors. * @param v1 * First vector. * @param v2 * Second vector. */ void Matrix4x4::SwapVectors3(double v1[3], double v2[3]) { double x[3] = { v1[0], v1[1], v1[2] }; v1[0] = v2[0]; v1[1] = v2[1]; v1[2] = v2[2]; v2[0] = x[0]; v2[1] = x[1]; v2[2] = x[2]; } /** * Premultiply by a matrix. * * @param tm Matrix that is used for pre-multiplication. * */ void Matrix4x4::premultiply(const Matrix4x4& tm) { double matrixOut[4][4]; for (int row = 0; row < 4; row++) { matrixOut[row][0] = matrix[row][0] * tm.matrix[0][0] + matrix[row][1] * tm.matrix[1][0] + matrix[row][2] * tm.matrix[2][0] + matrix[row][3] * tm.matrix[3][0]; matrixOut[row][1] = matrix[row][0] * tm.matrix[0][1] + matrix[row][1] * tm.matrix[1][1] + matrix[row][2] * tm.matrix[2][1] + matrix[row][3] * tm.matrix[3][1]; matrixOut[row][2] = matrix[row][0] * tm.matrix[0][2] + matrix[row][1] * tm.matrix[1][2] + matrix[row][2] * tm.matrix[2][2] + matrix[row][3] * tm.matrix[3][2]; matrixOut[row][3] = matrix[row][0] * tm.matrix[0][3] + matrix[row][1] * tm.matrix[1][3] + matrix[row][2] * tm.matrix[2][3] + matrix[row][3] * tm.matrix[3][3]; } setMatrix(matrixOut); this->setModified(); } /** * Postmultiply by a matrix. * * @param tm Matrix that is used for post-multiplication. * */ void Matrix4x4::postmultiply(const Matrix4x4& tm) { double matrixOut[4][4]; for (int row = 0; row < 4; row++) { matrixOut[row][0] = tm.matrix[row][0] * matrix[0][0] + tm.matrix[row][1] * matrix[1][0] + tm.matrix[row][2] * matrix[2][0] + tm.matrix[row][3] * matrix[3][0]; matrixOut[row][1] = tm.matrix[row][0] * matrix[0][1] + tm.matrix[row][1] * matrix[1][1] + tm.matrix[row][2] * matrix[2][1] + tm.matrix[row][3] * matrix[3][1]; matrixOut[row][2] = tm.matrix[row][0] * matrix[0][2] + tm.matrix[row][1] * matrix[1][2] + tm.matrix[row][2] * matrix[2][2] + tm.matrix[row][3] * matrix[3][2]; matrixOut[row][3] = tm.matrix[row][0] * matrix[0][3] + tm.matrix[row][1] * matrix[1][3] + tm.matrix[row][2] * matrix[2][3] + tm.matrix[row][3] * matrix[3][3]; } setMatrix(matrixOut); this->setModified(); } /** * Get the matrix as 16 element one-dimensional array for use by OpenGL. * * @param m A 16-element array of double. * */ void Matrix4x4::getMatrixForOpenGL(double m[16]) const { m[0] = this->matrix[0][0]; m[1] = this->matrix[1][0]; m[2] = this->matrix[2][0]; m[3] = this->matrix[3][0]; m[4] = this->matrix[0][1]; m[5] = this->matrix[1][1]; m[6] = this->matrix[2][1]; m[7] = this->matrix[3][1]; m[8] = this->matrix[0][2]; m[9] = this->matrix[1][2]; m[10] = this->matrix[2][2]; m[11] = this->matrix[3][2]; m[12] = this->matrix[0][3]; m[13] = this->matrix[1][3]; m[14] = this->matrix[2][3]; m[15] = this->matrix[3][3]; } /** * Set the matrix from a one-dimensional OpenGL Matrix as 16 elements. * * @param m A 16-element array of double containing OpenGL Matrix. * */ void Matrix4x4::setMatrixFromOpenGL(const double m[16]) { this->matrix[0][0] = m[0]; this->matrix[1][0] = m[1]; this->matrix[2][0] = m[2]; this->matrix[3][0] = m[3]; this->matrix[0][1] = m[4]; this->matrix[1][1] = m[5]; this->matrix[2][1] = m[6]; this->matrix[3][1] = m[7]; this->matrix[0][2] = m[8]; this->matrix[1][2] = m[9]; this->matrix[2][2] = m[10]; this->matrix[3][2] = m[11]; this->matrix[0][3] = m[12]; this->matrix[1][3] = m[13]; this->matrix[2][3] = m[14]; this->matrix[3][3] = m[15]; this->setModified(); } /** * Get the matrix as 16 element one-dimensional array for use by OpenGL. * * @param m A 16-element array of double. * */ void Matrix4x4::getMatrixForOpenGL(float m[16]) const { m[0] = this->matrix[0][0]; m[1] = this->matrix[1][0]; m[2] = this->matrix[2][0]; m[3] = this->matrix[3][0]; m[4] = this->matrix[0][1]; m[5] = this->matrix[1][1]; m[6] = this->matrix[2][1]; m[7] = this->matrix[3][1]; m[8] = this->matrix[0][2]; m[9] = this->matrix[1][2]; m[10] = this->matrix[2][2]; m[11] = this->matrix[3][2]; m[12] = this->matrix[0][3]; m[13] = this->matrix[1][3]; m[14] = this->matrix[2][3]; m[15] = this->matrix[3][3]; } /** * Set the matrix from a one-dimensional OpenGL Matrix as 16 elements. * * @param m A 16-element array of double containing OpenGL Matrix. * */ void Matrix4x4::setMatrixFromOpenGL(const float m[16]) { this->matrix[0][0] = m[0]; this->matrix[1][0] = m[1]; this->matrix[2][0] = m[2]; this->matrix[3][0] = m[3]; this->matrix[0][1] = m[4]; this->matrix[1][1] = m[5]; this->matrix[2][1] = m[6]; this->matrix[3][1] = m[7]; this->matrix[0][2] = m[8]; this->matrix[1][2] = m[9]; this->matrix[2][2] = m[10]; this->matrix[3][2] = m[11]; this->matrix[0][3] = m[12]; this->matrix[1][3] = m[13]; this->matrix[2][3] = m[14]; this->matrix[3][3] = m[15]; this->setModified(); } /** * Convert the given vector to an OpenGL rotation matrix. * "This" matrix is set to the identity matrix before createing * the rotation matrix. Use Matrix4x4::getMatrixForOpenGL() * to get the matrix after calling this method and then pass * array to glMultMatrixd(). * * http://lifeofaprogrammergeek.blogspot.com/2008/07/rendering-cylinder-between-two-points.html * * @param vector * The vector. MUST be a unit vector. */ void Matrix4x4::setMatrixToOpenGLRotationFromVector(const float vector[3]) { float vx = vector[0]; float vy = vector[1]; float vz = vector[2]; float z = (float)std::sqrt( vx*vx + vy*vy + vz*vz ); double ax = 0.0f; double zero = 1.0e-3; if (std::abs(vz) < zero) { ax = 57.2957795*std::acos( vx/z ); // rotation angle in x-y plane if ( vx <= 0.0f ) ax = -ax; } else { ax = 57.2957795*std::acos( vz/z ); // rotation angle if ( vz <= 0.0f ) ax = -ax; } float rx = -vy*vz; float ry = vx*vz; if ((std::abs(vx) < zero) && (std::fabs(vz) < zero)) { if (vy > 0) { ax = 90; } } identity(); if (std::abs(vz) < zero) { rotateY(90.0); // Rotate & align with x axis rotateX(-ax); // Rotate to point 2 in x-y plane } else { rotate(ax, rx, ry, 0.0); // Rotate about rotation vector } } /** * Transpose the matrix. * */ void Matrix4x4::transpose() { double m[4][4]; m[0][0] = matrix[0][0]; m[0][1] = matrix[1][0]; m[0][2] = matrix[2][0]; m[0][3] = matrix[3][0]; m[1][0] = matrix[0][1]; m[1][1] = matrix[1][1]; m[1][2] = matrix[2][1]; m[1][3] = matrix[3][1]; m[2][0] = matrix[0][2]; m[2][1] = matrix[1][2]; m[2][2] = matrix[2][2]; m[2][3] = matrix[3][2]; m[3][0] = matrix[0][3]; m[3][1] = matrix[1][3]; m[3][2] = matrix[2][3]; m[3][3] = matrix[3][3]; setMatrix(m); this->setModified(); } /** * Set the matrix. * * @param m A 4x4 array of doubles. * */ void Matrix4x4::setMatrix(const double m[4][4]) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { matrix[i][j] = m[i][j]; } } this->setModified(); } /** * Get the matrix. * * @param m A 4x4 array of doubles. * */ void Matrix4x4::getMatrix(double m[4][4]) const { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { m[i][j] = matrix[i][j]; } } } /** * Set the matrix. * * @param m A 4x4 array of float. * */ void Matrix4x4::setMatrix(const float m[4][4]) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { matrix[i][j] = m[i][j]; } } this->setModified(); } /** * Get the matrix. * * @param m A 4x4 array of floats. * */ void Matrix4x4::getMatrix(float m[4][4]) const { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { m[i][j] = matrix[i][j]; } } } /** * Set the matrix. * * @param cm A Matrix. * */ void Matrix4x4::setMatrix(const Matrix4x4& cm) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { matrix[i][j] = cm.matrix[i][j]; } } this->setModified(); } void Matrix4x4::multiplyPoint3(float p[3]) const { float pout[3] = { 0.0f, 0.0f, 0.0f }; for (int row = 0; row < 3; row++) { pout[row] = (float)(this->matrix[row][0] * p[0] + this->matrix[row][1] * p[1] + this->matrix[row][2] * p[2] + this->matrix[row][3]); } p[0] = pout[0]; p[1] = pout[1]; p[2] = pout[2]; } void Matrix4x4::multiplyPoint3(double p[3]) const { double pout[3] = { 0.0f, 0.0f, 0.0f }; for (int row = 0; row < 3; row++) { pout[row] = (this->matrix[row][0] * p[0] + this->matrix[row][1] * p[1] + this->matrix[row][2] * p[2] + this->matrix[row][3]); } p[0] = pout[0]; p[1] = pout[1]; p[2] = pout[2]; } void Matrix4x4::multiplyPoint4(float p[4]) const { float pout[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; for (int row = 0; row < 4; row++) { pout[row] = (float)(this->matrix[row][0] * p[0] + this->matrix[row][1] * p[1] + this->matrix[row][2] * p[2] + this->matrix[row][3] * p[3]); } p[0] = pout[0]; p[1] = pout[1]; p[2] = pout[2]; p[3] = pout[3]; } void Matrix4x4::multiplyPoint3X3(float p[3]) const { float pout[3] = { 0.0f, 0.0f, 0.0f }; for (int row = 0; row < 3; row++) { pout[row] = (float)(this->matrix[row][0] * p[0] + this->matrix[row][1] * p[1] + this->matrix[row][2] * p[2]); } p[0] = pout[0]; p[1] = pout[1]; p[2] = pout[2]; } /** * Get the data space name (used by GIFTI). * * @return Name of data space. * */ AString Matrix4x4::getDataSpaceName() const { return dataSpaceName; } /** * Set the data space name (used by GIFTI). * * @param name Name of data space. * */ void Matrix4x4::setDataSpaceName(const AString& name) { dataSpaceName = name; this->setModified(); } /** * Get the transformed space name (used by GIFTI). * * @return Name of transformed space. * */ AString Matrix4x4::getTransformedSpaceName() const { return transformedSpaceName; } /** * Set the transformed space name (used by GIFTI). * * @param name Name of transformed space. * */ void Matrix4x4::setTransformedSpaceName(const AString& name) { transformedSpaceName = name; this->setModified(); } /** * Set a matrix element. * @param i Row * @param j Column * @return value at [i][j] * */ double Matrix4x4::getMatrixElement( const int32_t i, const int32_t j) const { return this->matrix[i][j]; } /** * Set a matrix element. * @param i Row * @param j Column * @param e New Value * */ void Matrix4x4::setMatrixElement( const int32_t i, const int32_t j, const double e) { this->matrix[i][j] = e; this->setModified(); } /** * Determine if two matrices are approximately equal. * @param m - matrix to compare. * @param error - Maximum difference between a matrix element. * @return true if all corresponding elements differ by less than "error", * else false. * */ bool Matrix4x4::compare( const Matrix4x4& m, const float error) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { float diff = (float)std::abs(this->matrix[i][j] - m.matrix[i][j]); if (diff > error) { return false; } } } return true; } double Matrix4x4::fixZero(const double f) { if (f > SMALL_POSITIVE_NUMBER) { return f; } else if (f < SMALL_NEGATIVE_NUMBER) { return f; } return 0.0; } /** * Fix numerical error such as very tiny numbers and "negative zeros". * */ void Matrix4x4::fixNumericalError() { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { double f = fixZero(this->matrix[i][j]); this->matrix[i][j] = f; } } this->setModified(); } /** * Invert a matrix. * @return true if inversion of matrix is successful, * else false. * */ bool Matrix4x4::invert() { double m[4][4]; const bool valid = Matrix4x4::Inverse(this->matrix, m); if (valid) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { this->matrix[i][j] = m[i][j]; } } this->setModified(); return true; } else { CaretLogWarning("Matrix inversion failed for " + this->toString()); return false; } } /** * Inverse from VTK */ bool Matrix4x4::Inverse(const double a[4][4], double matrixOut[4][4]) const { /////SqMatPtr outElem = (SqMatPtr)outElements; // inverse( original_matrix, inverse_matrix ) // calculate the inverse of a 4x4 matrix // // -1 // A = ___1__ adjoint A // det A // // calculate the 4x4 determinent // if the determinent is zero, // then the inverse matrix is not unique. const double det = Determinant4x4(a); if ( det == 0.0 ) { return false; } // calculate the adjoint matrix Adjoint(a, matrixOut); //vtkMatrix4x4::Adjoint(inElements, outElements ); // scale the adjoint matrix to get the inverse for (int i=0; i<4; i++) { for(int j=0; j<4; j++) { matrixOut[i][j] = matrixOut[i][j] / det; } } return true; } /** * Adjoint from vtkMatrix4x4::Adjoint */ void Matrix4x4::Adjoint(const double inputMatrix[4][4], double outputMatrix[4][4]) const { // // adjoint( original_matrix, inverse_matrix ) // // calculate the adjoint of a 4x4 matrix // // Let a denote the minor determinant of matrix A obtained by // ij // // deleting the ith row and jth column from A. // // i+j // Let b = (-1) a // ij ji // // The matrix B = (b ) is the adjoint of A // ij // double a1, a2, a3, a4, b1, b2, b3, b4; double c1, c2, c3, c4, d1, d2, d3, d4; // assign to individual variable names to aid // selecting correct values a1 = inputMatrix[0][0]; b1 = inputMatrix[0][1]; c1 = inputMatrix[0][2]; d1 = inputMatrix[0][3]; a2 = inputMatrix[1][0]; b2 = inputMatrix[1][1]; c2 = inputMatrix[1][2]; d2 = inputMatrix[1][3]; a3 = inputMatrix[2][0]; b3 = inputMatrix[2][1]; c3 = inputMatrix[2][2]; d3 = inputMatrix[2][3]; a4 = inputMatrix[3][0]; b4 = inputMatrix[3][1]; c4 = inputMatrix[3][2]; d4 = inputMatrix[3][3]; // row column labeling reversed since we transpose rows & columns outputMatrix[0][0] = Matrix4x4::Determinant3x3( b2, b3, b4, c2, c3, c4, d2, d3, d4); outputMatrix[1][0] = - Matrix4x4::Determinant3x3( a2, a3, a4, c2, c3, c4, d2, d3, d4); outputMatrix[2][0] = Matrix4x4::Determinant3x3( a2, a3, a4, b2, b3, b4, d2, d3, d4); outputMatrix[3][0] = - Matrix4x4::Determinant3x3( a2, a3, a4, b2, b3, b4, c2, c3, c4); outputMatrix[0][1] = - Matrix4x4::Determinant3x3( b1, b3, b4, c1, c3, c4, d1, d3, d4); outputMatrix[1][1] = Matrix4x4::Determinant3x3( a1, a3, a4, c1, c3, c4, d1, d3, d4); outputMatrix[2][1] = - Matrix4x4::Determinant3x3( a1, a3, a4, b1, b3, b4, d1, d3, d4); outputMatrix[3][1] = Matrix4x4::Determinant3x3( a1, a3, a4, b1, b3, b4, c1, c3, c4); outputMatrix[0][2] = Matrix4x4::Determinant3x3( b1, b2, b4, c1, c2, c4, d1, d2, d4); outputMatrix[1][2] = - Matrix4x4::Determinant3x3( a1, a2, a4, c1, c2, c4, d1, d2, d4); outputMatrix[2][2] = Matrix4x4::Determinant3x3( a1, a2, a4, b1, b2, b4, d1, d2, d4); outputMatrix[3][2] = - Matrix4x4::Determinant3x3( a1, a2, a4, b1, b2, b4, c1, c2, c4); outputMatrix[0][3] = - Matrix4x4::Determinant3x3( b1, b2, b3, c1, c2, c3, d1, d2, d3); outputMatrix[1][3] = Matrix4x4::Determinant3x3( a1, a2, a3, c1, c2, c3, d1, d2, d3); outputMatrix[2][3] = - Matrix4x4::Determinant3x3( a1, a2, a3, b1, b2, b3, d1, d2, d3); outputMatrix[3][3] = Matrix4x4::Determinant3x3( a1, a2, a3, b1, b2, b3, c1, c2, c3); } /** * From vtkMatrix4x4::Determinant */ double Matrix4x4::Determinant4x4(const double matrixIn[4][4]) const { double a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4; // assign to individual variable names to aid selecting // correct elements a1 = matrixIn[0][0]; b1 = matrixIn[0][1]; c1 = matrixIn[0][2]; d1 = matrixIn[0][3]; a2 = matrixIn[1][0]; b2 = matrixIn[1][1]; c2 = matrixIn[1][2]; d2 = matrixIn[1][3]; a3 = matrixIn[2][0]; b3 = matrixIn[2][1]; c3 = matrixIn[2][2]; d3 = matrixIn[2][3]; a4 = matrixIn[3][0]; b4 = matrixIn[3][1]; c4 = matrixIn[3][2]; d4 = matrixIn[3][3]; const double result = a1 * Matrix4x4::Determinant3x3( b2, b3, b4, c2, c3, c4, d2, d3, d4) - b1 * Matrix4x4::Determinant3x3( a2, a3, a4, c2, c3, c4, d2, d3, d4) + c1 * Matrix4x4::Determinant3x3( a2, a3, a4, b2, b3, b4, d2, d3, d4) - d1 * Matrix4x4::Determinant3x3( a2, a3, a4, b2, b3, b4, c2, c3, c4); return result; } double Matrix4x4::Determinant3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3) { return ( a1 * Matrix4x4::Determinant2x2( b2, b3, c2, c3 ) - b1 * Matrix4x4::Determinant2x2( a2, a3, c2, c3 ) + c1 * Matrix4x4::Determinant2x2( a2, a3, b2, b3 ) ); } double Matrix4x4::Determinant2x2(double a, double b, double c, double d) { return (a * d - b * c); }; double Matrix4x4::Determinant3x3(double A[3][3]) { return A[0][0] * A[1][1] * A[2][2] + A[1][0] * A[2][1] * A[0][2] + A[2][0] * A[0][1] * A[1][2] - A[0][0] * A[2][1] * A[1][2] - A[1][0] * A[0][1] * A[2][2] - A[2][0] * A[1][1] * A[0][2]; } /** * Set this matrix to a landmark transform that maps from the source * to the target space as defined by the control points. * Replaces the current matrix. * * @param controlPoints * The control points (pair of source and target coordinates). * @param errorMessageOut * Contains error message. * @return * True if output matrix is valid, else false. If false, this * matrix will be the identity matrix. */ bool Matrix4x4::createLandmarkTransformMatrix(const std::vector& controlPoints, AString& errorMessageOut) { const bool debugFlag = false; identity(); errorMessageOut.clear(); if (controlPoints.size() < 3) { errorMessageOut = "There must be at least three control points."; return false; } float s1[3]; controlPoints[0]->getSourceXYZ(s1); float s2[3]; controlPoints[1]->getSourceXYZ(s2); float s3[3]; controlPoints[2]->getSourceXYZ(s3); float sourceNormalVector[3] = { 0.0, 0.0, 0.0 }; MathFunctions::normalVector(s1, s2, s3, sourceNormalVector); const float tinyValue = 0.00001; if ((sourceNormalVector[2] < tinyValue) && (sourceNormalVector[2] > -tinyValue)) { errorMessageOut = ("First three control points are along a line. Edit control points to that " "the first three control points form a triangular shape."); return false; } // if (sourceNormalVector[2] < 0.0) { // CaretLogWarning("Control points are orientated clockwise; unknown if this causes a problem."); // } double leastError = std::numeric_limits::max(); Matrix4x4 leastErrorMatrix; bool leastErrorMatrixValid = false; const bool testAllTransformTypesFlag = true; if (testAllTransformTypesFlag) { for (int32_t j = 0; j < 3; j++) { LANDMARK_TRANSFORM_MODE mode = LANDMARK_TRANSFORM_AFFINE; AString modeName; switch (j) { case 0: mode = LANDMARK_TRANSFORM_AFFINE; modeName = "LANDMARK_TRANSFORM_AFFINE"; break; case 1: mode = LANDMARK_TRANSFORM_RIGIDBODY; modeName = "LANDMARK_TRANSFORM_RIGIDBODY"; break; case 2: mode = LANDMARK_TRANSFORM_SIMILARITY; modeName = "LANDMARK_TRANSFORM_SIMILARITY"; break; } Matrix4x4 matrix; if (matrix.createLandmarkTransformMatrixPrivate(controlPoints, mode, errorMessageOut)) { if (debugFlag) { std::cout << std::endl; std::cout << "Mode: " << qPrintable(modeName) << std::endl; std::cout << "Matrix: " << qPrintable(matrix.toFormattedString(" ")) << std::endl; } const int32_t numcp = static_cast(controlPoints.size()); double sum = 0.0; for (int32_t i = 0; i < numcp; i++) { double source[3]; controlPoints[i]->getSourceXYZ(source); double predicted[3] = { source[0], source[1], source[2] }; matrix.multiplyPoint3(predicted); double target[3]; controlPoints[i]->getTargetXYZ(target); const double error = MathFunctions::distance3D(predicted, target); sum += error; if (debugFlag) { std::cout << "CP("<< i << ") Source: (" << qPrintable(AString::fromNumbers(source, 3, ",")) << ") Target: (" << qPrintable(AString::fromNumbers(target, 3, ",")) << ") Predicted: (" << qPrintable(AString::fromNumbers(predicted, 3, ",")) << ") Error: " << error << std::endl; } } const double error = (sum /= static_cast(numcp)); if (debugFlag) { std::cout << " Average error per control point: " << error << std::endl; } if (error < leastError) { leastError = error; leastErrorMatrix = matrix; leastErrorMatrixValid = true; } } } } *this = leastErrorMatrix; const float averageError = measureTransformError(controlPoints, *this); // const bool result = createLandmarkTransformMatrixPrivate(controlPoints, // LANDMARK_TRANSFORM_AFFINE, // errorMessageOut); if (debugFlag) { std::cout << std::endl; std::cout << "Transform Error: " << averageError << std::endl; } return leastErrorMatrixValid; } /** * Set this matrix to a landmark transform that maps from the source * to the target space as defined by the control points. * Replaces the current matrix. * * Code Copied From vtkLandmarkTransform * Program: Visualization Toolkit * Module: vtkLandmarkTransform.cxx * * Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen * All rights reserved. * See Copyright.txt or http://www.kitware.com/Copyright.htm for details. * * This software is distributed WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the above copyright notice for more information. * * @param controlPoints * The control points (pair of source and target coordinates). * @param mode * Mode for transformation. * @param errorMessageOut * Contains error message. * @return * True if output matrix is valid, else false. If false, this * matrix will be the identity matrix. */ bool Matrix4x4::createLandmarkTransformMatrixPrivate(const std::vector& controlPoints, const LANDMARK_TRANSFORM_MODE mode, AString& errorMessageOut) { identity(); errorMessageOut.clear(); //vtkIdType i; int32_t i; int32_t j; //if (this->SourceLandmarks == NULL || this->TargetLandmarks == NULL) if (controlPoints.empty()) { identity(); errorMessageOut = "Control points are empty."; return false; } // --- compute the necessary transform to match the two sets of landmarks --- /* The solution is based on Berthold K. P. Horn (1987), "Closed-form solution of absolute orientation using unit quaternions," Journal of the Optical Society of America A, 4:629-642 */ // Original python implementation by David G. Gobbi //const vtkIdType N_PTS = this->SourceLandmarks->GetNumberOfPoints(); int32_t N_PTS = static_cast(controlPoints.size()); if (mode == LANDMARK_TRANSFORM_AFFINE) { if (N_PTS > 3) { N_PTS = 3; } } // if(N_PTS != this->TargetLandmarks->GetNumberOfPoints()) // { // vtkErrorMacro("Update: Source and Target Landmarks contain a different number of points"); // return; // } // -- if no points, stop here if (N_PTS == 0) { identity(); return false; } // -- find the centroid of each set -- double source_centroid[3]={0,0,0}; double target_centroid[3]={0,0,0}; double p[3]; for(i=0;iSourceLandmarks->GetPoint(i, p); controlPoints[i]->getSourceXYZ(p); source_centroid[0] += p[0]; source_centroid[1] += p[1]; source_centroid[2] += p[2]; //this->TargetLandmarks->GetPoint(i, p); controlPoints[i]->getTargetXYZ(p); target_centroid[0] += p[0]; target_centroid[1] += p[1]; target_centroid[2] += p[2]; } source_centroid[0] /= N_PTS; source_centroid[1] /= N_PTS; source_centroid[2] /= N_PTS; target_centroid[0] /= N_PTS; target_centroid[1] /= N_PTS; target_centroid[2] /= N_PTS; double matrixArray[4][4]; getMatrix(matrixArray); // -- if only one point, stop right here if (N_PTS == 1) { //this->Matrix->Identity(); matrixArray[0][3] = target_centroid[0] - source_centroid[0]; matrixArray[1][3] = target_centroid[1] - source_centroid[1]; matrixArray[2][3] = target_centroid[2] - source_centroid[2]; return true; } // -- build the 3x3 matrix M -- double M[3][3]; double AAT[3][3]; for(i=0;i<3;i++) { AAT[i][0] = M[i][0]=0.0F; // fill M with zeros AAT[i][1] = M[i][1]=0.0F; AAT[i][2] = M[i][2]=0.0F; } //vtkIdType pt; int32_t pt; double a[3],b[3]; double sa=0.0F,sb=0.0F; for(pt=0;ptSourceLandmarks->GetPoint(pt,a); CaretAssertVectorIndex(controlPoints, pt); controlPoints[pt]->getSourceXYZ(a); a[0] -= source_centroid[0]; a[1] -= source_centroid[1]; a[2] -= source_centroid[2]; // get the origin-centred point (b) in the target set //this->TargetLandmarks->GetPoint(pt,b); controlPoints[pt]->getTargetXYZ(b); b[0] -= target_centroid[0]; b[1] -= target_centroid[1]; b[2] -= target_centroid[2]; // accumulate the products a*T(b) into the matrix M for(i=0;i<3;i++) { M[i][0] += a[i]*b[0]; M[i][1] += a[i]*b[1]; M[i][2] += a[i]*b[2]; // for the affine transform, compute ((a.a^t)^-1 . a.b^t)^t. // a.b^t is already in M. here we put a.a^t in AAT. if (mode == LANDMARK_TRANSFORM_AFFINE) { AAT[i][0] += a[i]*a[0]; AAT[i][1] += a[i]*a[1]; AAT[i][2] += a[i]*a[2]; } } // accumulate scale factors (if desired) sa += a[0]*a[0]+a[1]*a[1]+a[2]*a[2]; sb += b[0]*b[0]+b[1]*b[1]+b[2]*b[2]; /* * If source points all have same value for 'k', * it will cause element [2][2] to be zero * and the matrix cannot be inverted. */ if (AAT[2][2] == 0.0) { AAT[2][2] = 1.0; } } if(mode == LANDMARK_TRANSFORM_AFFINE) { // AAT = (a.a^t)^-1 MathFunctions::vtkInvert3x3(AAT,AAT); // M = (a.a^t)^-1 . a.b^t MathFunctions::vtkMultiply3x3(AAT,M,M); // this->Matrix = M^t for(i=0;i<3;++i) { for(j=0;j<3;++j) { matrixArray[i][j] = M[j][i]; } } } else { // compute required scaling factor (if desired) double scale = (double)std::sqrt(sb/sa); // -- build the 4x4 matrix N -- double Ndata[4][4]; double *N[4]; for(i=0;i<4;i++) { N[i] = Ndata[i]; N[i][0]=0.0F; // fill N with zeros N[i][1]=0.0F; N[i][2]=0.0F; N[i][3]=0.0F; } // on-diagonal elements N[0][0] = M[0][0]+M[1][1]+M[2][2]; N[1][1] = M[0][0]-M[1][1]-M[2][2]; N[2][2] = -M[0][0]+M[1][1]-M[2][2]; N[3][3] = -M[0][0]-M[1][1]+M[2][2]; // off-diagonal elements N[0][1] = N[1][0] = M[1][2]-M[2][1]; N[0][2] = N[2][0] = M[2][0]-M[0][2]; N[0][3] = N[3][0] = M[0][1]-M[1][0]; N[1][2] = N[2][1] = M[0][1]+M[1][0]; N[1][3] = N[3][1] = M[2][0]+M[0][2]; N[2][3] = N[3][2] = M[1][2]+M[2][1]; // -- eigen-decompose N (is symmetric) -- double eigenvectorData[4][4]; double *eigenvectors[4],eigenvalues[4]; eigenvectors[0] = eigenvectorData[0]; eigenvectors[1] = eigenvectorData[1]; eigenvectors[2] = eigenvectorData[2]; eigenvectors[3] = eigenvectorData[3]; MathFunctions::vtkJacobiN(N,4,eigenvalues,eigenvectors); // the eigenvector with the largest eigenvalue is the quaternion we want // (they are sorted in decreasing order for us by JacobiN) double w,x,y,z; // first: if points are collinear, choose the quaternion that // results in the smallest rotation. if (eigenvalues[0] == eigenvalues[1] || N_PTS == 2) { double s0[3],t0[3],s1[3],t1[3]; // this->SourceLandmarks->GetPoint(0,s0); // this->TargetLandmarks->GetPoint(0,t0); // this->SourceLandmarks->GetPoint(1,s1); // this->TargetLandmarks->GetPoint(1,t1); CaretAssertVectorIndex(controlPoints, 1); controlPoints[0]->getSourceXYZ(s0); controlPoints[0]->getTargetXYZ(t0); controlPoints[1]->getSourceXYZ(s1); controlPoints[1]->getTargetXYZ(t1); double ds[3],dt[3]; double rs = 0, rt = 0; for (i = 0; i < 3; i++) { ds[i] = s1[i] - s0[i]; // vector between points rs += ds[i]*ds[i]; dt[i] = t1[i] - t0[i]; rt += dt[i]*dt[i]; } // normalize the two vectors rs = sqrt(rs); ds[0] /= rs; ds[1] /= rs; ds[2] /= rs; rt = sqrt(rt); dt[0] /= rt; dt[1] /= rt; dt[2] /= rt; // take dot & cross product w = ds[0]*dt[0] + ds[1]*dt[1] + ds[2]*dt[2]; x = ds[1]*dt[2] - ds[2]*dt[1]; y = ds[2]*dt[0] - ds[0]*dt[2]; z = ds[0]*dt[1] - ds[1]*dt[0]; double r = sqrt(x*x + y*y + z*z); double theta = atan2(r,w); // construct quaternion w = cos(theta/2); if (r != 0) { r = sin(theta/2)/r; x = x*r; y = y*r; z = z*r; } else // rotation by 180 degrees: special case { // rotate around a vector perpendicular to ds MathFunctions::vtkPerpendiculars(ds,dt,0,0); r = sin(theta/2); x = dt[0]*r; y = dt[1]*r; z = dt[2]*r; } } else // points are not collinear { w = eigenvectors[0][0]; x = eigenvectors[1][0]; y = eigenvectors[2][0]; z = eigenvectors[3][0]; } // convert quaternion to a rotation matrix double ww = w*w; double wx = w*x; double wy = w*y; double wz = w*z; double xx = x*x; double yy = y*y; double zz = z*z; double xy = x*y; double xz = x*z; double yz = y*z; matrixArray[0][0] = ww + xx - yy - zz; matrixArray[1][0] = 2.0*(wz + xy); matrixArray[2][0] = 2.0*(-wy + xz); matrixArray[0][1] = 2.0*(-wz + xy); matrixArray[1][1] = ww - xx + yy - zz; matrixArray[2][1] = 2.0*(wx + yz); matrixArray[0][2] = 2.0*(wy + xz); matrixArray[1][2] = 2.0*(-wx + yz); matrixArray[2][2] = ww - xx - yy + zz; if (mode != LANDMARK_TRANSFORM_RIGIDBODY) { // add in the scale factor (if desired) for(i=0;i<3;i++) { matrixArray[i][0] *= scale; matrixArray[i][1] *= scale; matrixArray[i][2] *= scale; } } } // the translation is given by the difference in the transformed source // centroid and the target centroid double sx, sy, sz; sx = matrixArray[0][0] * source_centroid[0] + matrixArray[0][1] * source_centroid[1] + matrixArray[0][2] * source_centroid[2]; sy = matrixArray[1][0] * source_centroid[0] + matrixArray[1][1] * source_centroid[1] + matrixArray[1][2] * source_centroid[2]; sz = matrixArray[2][0] * source_centroid[0] + matrixArray[2][1] * source_centroid[1] + matrixArray[2][2] * source_centroid[2]; matrixArray[0][3] = target_centroid[0] - sx; matrixArray[1][3] = target_centroid[1] - sy; matrixArray[2][3] = target_centroid[2] - sz; // fill the bottom row of the 4x4 matrix matrixArray[3][0] = 0.0; matrixArray[3][1] = 0.0; matrixArray[3][2] = 0.0; matrixArray[3][3] = 1.0; /* * Can get zero for a scale factor if planes of the * source and target are parallel */ for (int32_t i = 0; i < 3; i++) { if (matrixArray[i][i] == 0.0) { matrixArray[i][i] = 1.0; } } setMatrix(matrixArray); //this->Matrix->Modified(); return true; } /** * Measure the average error for control points using transform matrix. * Error is straight line distance between ([source] * [matrix]) and * (target). * * @param controlProints * The control points * @param matrix * The transform matrix. */ float Matrix4x4::measureTransformError(const std::vector& controlPoints, const Matrix4x4& matrix) const { const int32_t numcp = static_cast(controlPoints.size()); if (numcp <= 0) { return 0.0; } double sum = 0.0; for (int32_t i = 0; i < numcp; i++) { ControlPoint3D* cp = controlPoints[i]; double pt[3]; cp->getSourceXYZ(pt); matrix.multiplyPoint3(pt); cp->setTransformedXYZ(pt); double target[3]; controlPoints[i]->getTargetXYZ(target); const double totalError = MathFunctions::distance3D(pt, target); sum += totalError; } const double error = (sum /= static_cast(numcp)); return error; } /** * Write the matrix as a GIFTI matrix using the given XML tags. * * @param xmlWriter * The XML writer * @param xmlMatrixTag * XML tag for for the matrix and its components. * @param xmlDataSpaceTag * XML tag for for the data space name. * @param xmlTransformedSpaceTag * XML tag for for the transformed space name. * @param xmlMatrixDataTag * XML tag for the matrix data. * * @throws XmlException * If an error occurs while writing. */ void Matrix4x4::writeAsGiftiXML(XmlWriter& xmlWriter, const AString& xmlMatrixTag, const AString& xmlDataSpaceTag, const AString& xmlTransformedSpaceTag, const AString& xmlMatrixDataTag) { xmlWriter.writeStartElement(xmlMatrixTag); xmlWriter.writeElementCData(xmlDataSpaceTag, this->dataSpaceName); xmlWriter.writeElementCData(xmlTransformedSpaceTag, this->transformedSpaceName); /* * Note: Matrix4x4 is column major order but GIFTI uses * row major order so transpose matrix as values are * written. */ xmlWriter.writeStartElement(xmlMatrixDataTag); for (int32_t iRow = 0; iRow < 4; iRow++) { for (int32_t jCol = 0; jCol < 4; jCol++) { /* * Transpose indices */ const int32_t i = jCol; const int32_t j = iRow; const AString txt = (AString::number(this->matrix[i][j]) + " "); if (jCol == 0) { xmlWriter.writeCharactersWithIndent(txt); } else { xmlWriter.writeCharacters(txt); } if (jCol == 3) { xmlWriter.writeCharacters("\n"); } } } xmlWriter.writeEndElement(); xmlWriter.writeEndElement(); } /** * Convert the matrix into a string representation. * * @return String representation of the matrix. * */ AString Matrix4x4::toString() const { return toFormattedString(" "); } /** * Get a nicely formatted string for printing. * * @param indentation - use as indentation. * @return String containing label information. * */ AString Matrix4x4::toFormattedString(const AString& indentation) const { float translation[3]; getTranslation(translation); double rotation[3]; getRotation(rotation[0], rotation[1], rotation[2]); double scale[3]; getScale(scale[0], scale[1], scale[2]); AString elements; for (int32_t iRow = 0; iRow < 4; iRow++) { elements.append(indentation); for (int32_t iCol = 0; iCol < 4; iCol++) { elements.append(AString::number(matrix[iRow][iCol]) + " "); } elements.append("\n"); } const AString s("Matrix4x4: \n" + elements + indentation + "Translation: " + AString::fromNumbers(translation, 3, ", ") + "\n" + indentation + "Rotation: " + AString::fromNumbers(rotation, 3, ", ") + "\n" + indentation + "Scale: " + AString::fromNumbers(scale, 3, ", ")); return s; } /** * Set this object has been modified. * */ void Matrix4x4::setModified() { this->modifiedFlag = true; } /** * Set this object as not modified. Object should also * clear the modification status of its children. * */ void Matrix4x4::clearModified() { this->modifiedFlag = false; } /** * Get the modification status. Returns true if this object or * any of its children have been modified. * @return - The modification status. * */ bool Matrix4x4::isModified() const { return this->modifiedFlag; } connectome-workbench-1.4.2/src/Nifti/Matrix4x4.h000066400000000000000000000157761360521144700214700ustar00rootroot00000000000000#ifndef __MATRIX4X4_H__ #define __MATRIX4X4_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include #include namespace caret { class ControlPoint3D; class XmlWriter; /** * A 4x4 homogeneous transformation matrix. */ class Matrix4x4 : public CaretObject { public: Matrix4x4(); public: Matrix4x4(const Matrix4x4& o); Matrix4x4& operator=(const Matrix4x4& o); virtual ~Matrix4x4(); private: void copyHelper(const Matrix4x4& o); void initializeMembersMatrix4x4(); public: void identity(); void getTranslation(float translatationOut[3]) const; void setTranslation(const float t[]); void setTranslation( const double tx, const double ty, const double tz); void translate( const double tx, const double ty, const double tz); void translate(const double txyz[3]); void scale( const double sx, const double sy, const double sz); void getScale(double& scaleOutX, double& scaleOutY, double& scaleOutZ) const; void rotateX(const double degrees); void rotateY(const double degrees); void rotateZ(const double degrees); void rotate( const double angle, const double vector[]); void rotate( const double angle, const double x, const double y, const double z); void getRotation(double& rotationOutX, double& rotationOutY, double& rotationOutZ) const; void setRotation(const double rotationX, const double rotationY, const double rotationZ); void premultiply(const Matrix4x4& tm); void postmultiply(const Matrix4x4& tm); void getMatrixForOpenGL(double m[16]) const; void setMatrixFromOpenGL(const double m[16]); void getMatrixForOpenGL(float m[16]) const; void setMatrixFromOpenGL(const float m[16]); void setMatrixToOpenGLRotationFromVector(const float vector[3]); void transpose(); void setMatrix(const double m[4][4]); void getMatrix(double m[4][4]) const; void setMatrix(const float m[4][4]); void getMatrix(float m[4][4]) const; void setMatrix(const Matrix4x4& cm); void multiplyPoint4(float p[4]) const; void multiplyPoint3(float p[3]) const; void multiplyPoint3(double p[3]) const; void multiplyPoint3X3(float p[3]) const; AString getDataSpaceName() const; void setDataSpaceName(const AString& name); AString getTransformedSpaceName() const; void setTransformedSpaceName(const AString& name); double getMatrixElement( const int32_t i, const int32_t j) const; void setMatrixElement( const int32_t i, const int32_t j, const double e); bool compare( const Matrix4x4& m, const float error); bool invert(); bool createLandmarkTransformMatrix(const std::vector& controlPoints, AString& errorMessageOut); AString toString() const; AString toFormattedString(const AString& indentation) const; void setModified(); void clearModified(); bool isModified() const; void writeAsGiftiXML(XmlWriter& xmlWriter, const AString& xmlMatrixTag, const AString& xmlDataSpaceTag, const AString& xmlTransformedSpaceTag, const AString& xmlMatrixDataTag); private: enum LANDMARK_TRANSFORM_MODE { LANDMARK_TRANSFORM_AFFINE, LANDMARK_TRANSFORM_RIGIDBODY, LANDMARK_TRANSFORM_SIMILARITY }; double fixZero(const double f); void fixNumericalError(); void Transpose(const double input[4][4], double output[4][4]) const; bool Inverse(const double inputMatrix[4][4], double outputMatrix[4][4]) const; void Adjoint(const double inputMatrix[4][4], double outputMatrix[4][4]) const; void UpperTriangle4(const double inputMatrix[4][4], double outputMatrix[4][4]) const; void UpperTriangle3(const double inputMatrix[3][3], double outputMatrix[3][3]) const; double Determinant4x4(const double matrix[4][4]) const; static double Determinant3x3(double A[3][3]); double Determinant3(const double matrix[3][3]) const; static double Determinant3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3); static double Determinant2x2(double a, double b, double c, double d); static void Orthogonalize3x3(const double A[3][3], double B[3][3]); static void SwapVectors3(double v1[3], double v2[3]); static void SingularValueDecomposition3x3(const double A[3][3], double U[3][3], double w[3], double VT[3][3]); static void Transpose3x3(const double A[3][3], double AT[3][3]); static void Multiply3x3(const double A[3][3], const double B[3][3], double C[3][3]); static void Diagonalize3x3(const double A[3][3], double w[3], double V[3][3]); static int JacobiN(double **a, int n, double *w, double **v); bool createLandmarkTransformMatrixPrivate(const std::vector& controlPoints, const LANDMARK_TRANSFORM_MODE mode, AString& errorMessageOut); float measureTransformError(const std::vector& controlPoints, const Matrix4x4& matrix) const; protected: /**the 4x4 matrix */ double matrix[4][4]; /**data space name (used by GIFTI) */ AString dataSpaceName; /**transformed space name (used by GIFTI) */ AString transformedSpaceName; private: /**data modification status (DO NOT CLONE) */ bool modifiedFlag; }; } // namespace #endif // __MATRIX4X4_H__ connectome-workbench-1.4.2/src/Nifti/NiftiHeader.cxx000066400000000000000000001230421360521144700224030ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "NiftiHeader.h" #include "ByteSwapping.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "DataFileException.h" #include "FloatMatrix.h" #include "MathFunctions.h" #include #include #include #include "stdint.h" using namespace std; using namespace caret; NiftiHeader::NiftiHeader() { if (sizeof(nifti_1_header) != 348 || sizeof(nifti_2_header) != 540)//these should be made into static asserts when we move to c++11 or decide to use boost { throw DataFileException("internal error: nifti header structs are the wrong size");//this is not a runtime assert, because we want this checked in release builds too } memset(&m_header, 0, sizeof(m_header)); for (int i = 0; i < 8; ++i) { m_header.dim[i] = 1;//we maintain 1s on unused dimensions to make some stupid nifti readers happy m_header.pixdim[i] = 1.0f;//also set pixdims to 1 by default, to make some other nifti readers happy when reading cifti headers }//note that we still warn when asking for spacing info and qform and sform codes are both 0, so this doesn't prevent us from catching non-volume files loaded as volumes m_header.xyzt_units = SPACE_TIME_TO_XYZT(NIFTI_UNITS_MM, NIFTI_UNITS_SEC); m_header.scl_slope = 1.0;//default to identity scaling m_header.scl_inter = 0.0; m_header.datatype = NIFTI_TYPE_FLOAT32; m_header.bitpix = typeToNumBits(m_header.datatype); m_version = 0; m_isSwapped = false; } AbstractHeader* NiftiHeader::clone() const { return new NiftiHeader(*this); } NiftiHeader::NiftiHeader(const NiftiHeader& rhs) { m_header = rhs.m_header; m_isSwapped = rhs.m_isSwapped; m_version = rhs.m_version; m_extensions.reserve(rhs.m_extensions.size()); for (size_t i = 0; i < rhs.m_extensions.size(); ++i) { m_extensions.push_back(CaretPointer(new NiftiExtension(*(rhs.m_extensions[i])))); } } NiftiHeader& NiftiHeader::operator=(const NiftiHeader& rhs) { if (this == &rhs) return *this; m_header = rhs.m_header; m_isSwapped = rhs.m_isSwapped; m_version = rhs.m_version; m_extensions.clear(); m_extensions.reserve(rhs.m_extensions.size()); for (size_t i = 0; i < rhs.m_extensions.size(); ++i) { m_extensions.push_back(CaretPointer(new NiftiExtension(*(rhs.m_extensions[i])))); } return *this; } bool NiftiHeader::canWriteVersion(const int& version) const { if (computeVoxOffset(version) < 0) return false;//error condition, can happen if an extension is longer than 2^31 if (version == 2) return true;//our internal state is nifti-2, return early if (version != 1) return false;//we can only write 1 and 2 vector dims = getDimensions(); for (int i = 0; i < (int)dims.size(); ++i) { if (dims[i] > numeric_limits::max()) return false; } if (m_header.intent_code > numeric_limits::max() || m_header.intent_code < numeric_limits::min()) return false; if (m_header.slice_code > numeric_limits::max() || m_header.slice_code < numeric_limits::min()) return false; if (m_header.xyzt_units > numeric_limits::max() || m_header.xyzt_units < numeric_limits::min()) return false; if (m_header.qform_code > numeric_limits::max() || m_header.qform_code < numeric_limits::min()) return false; if (m_header.sform_code > numeric_limits::max() || m_header.sform_code < numeric_limits::min()) return false; return true; } int64_t NiftiHeader::computeVoxOffset(const int& version) const { int64_t ret; switch (version) { case 1: ret = 4 + sizeof(nifti_1_header);//the 4 is the extender bytes break; case 2: ret = 4 + sizeof(nifti_2_header); break; default: return -1; } int numExtensions = (int)m_extensions.size(); for (int i = 0; i < numExtensions; ++i) { CaretAssert(m_extensions[i] != NULL); int64_t thisSize = 8 + m_extensions[i]->m_bytes.size();//8 is for the int32_t size and ecode for nifti-1 style extensions if (thisSize % 16 != 0)//round up to nearest multiple of 16 { int paddingBytes = 16 - (thisSize % 16); thisSize += paddingBytes; } if (thisSize > numeric_limits::max()) return -1;//since we don't have nifti-2 style extensions yet, always fail ret += thisSize; } if (version == 1)//need to put it into a float exactly (yes, really) { float temp = ret; if (ret != (int64_t)temp) return -1;//for now, just fail, until it actually becomes a problem } return ret; } bool NiftiHeader::getDataScaling(double& mult, double& offset) const { if (m_header.datatype == NIFTI_TYPE_RGB24 || m_header.scl_slope == 0.0 || (m_header.scl_slope == 1.0 && m_header.scl_inter == 0.0))//the "if slope is zero" case is in the nifti spec { mult = 1.0;//in case someone ignores the boolean offset = 0.0; return false; } mult = m_header.scl_slope; offset = m_header.scl_inter; return true; } vector NiftiHeader::getDimensions() const { CaretAssert(m_header.dim[0] >= 0 && m_header.dim[0] <= 7);//because storage is private and initialized to zero, so it should never be invalid vector ret(m_header.dim[0]); for (int i = 0; i < m_header.dim[0]; ++i) { ret[i] = m_header.dim[i + 1]; } return ret; } vector > NiftiHeader::getFSLSpace() const {//don't look at me, blame analyze and flirt vector dimensions = getDimensions(); if (dimensions.size() < 3) throw DataFileException("NiftiHeaderIO has less than 3 dimensions, can't generate the FSL space for it"); FloatMatrix ret; vector > sform = getSForm(); float determinant = sform[0][0] * sform[1][1] * sform[2][2] + sform[0][1] * sform[1][2] * sform[2][0] + sform[0][2] * sform[1][0] * sform[2][1] - sform[0][2] * sform[1][1] * sform[2][0] - sform[0][0] * sform[1][2] * sform[2][1] - sform[0][1] * sform[1][0] * sform[2][2];//just write out the 3x3 determinant rather than packing it into a FloatMatrix first - and I haven't put a determinant function in yet ret = FloatMatrix::identity(4);//generate a 4x4 with 0 0 0 1 last row via FloatMatrix for convenience if (determinant > 0.0f) { ret[0][0] = -m_header.pixdim[1];//yes, they really use pixdim, despite checking the SForm/QForm for flipping - ask them, not me ret[0][3] = (dimensions[0] - 1) * m_header.pixdim[1];//note - pixdim[1] is for i, pixdim[0] is qfac } else { ret[0][0] = m_header.pixdim[1]; } ret[1][1] = m_header.pixdim[2]; ret[2][2] = m_header.pixdim[3]; int32_t spaceUnit = XYZT_TO_SPACE(m_header.xyzt_units); switch (spaceUnit) { case NIFTI_UNITS_METER: ret *= 1000.0f; ret[3][3] = 1.0f; break; case NIFTI_UNITS_MICRON: ret *= 0.001f; ret[3][3] = 1.0f; break; case 0://will already have warned in getSForm() case NIFTI_UNITS_MM: break; default: break;//will already have warned in getSForm() } return ret.getMatrix(); } bool NiftiHeader::operator==(const NiftiHeader& rhs) const { if (m_version != rhs.m_version) return false;//this is to test for consistency, not to test if two headers mean the same thing if (m_isSwapped != rhs.m_isSwapped) return false; return memcmp(&m_header, &(rhs.m_header), sizeof(m_header)) == 0; } vector > NiftiHeader::getSForm() const { FloatMatrix ret = FloatMatrix::zeros(4, 4); ret[3][3] = 1.0f;//force 0 0 0 1 last row if (m_header.sform_code != 0)//prefer sform { for(int i = 0; i < 4; i++) { ret[0][i] = m_header.srow_x[i]; ret[1][i] = m_header.srow_y[i]; ret[2][i] = m_header.srow_z[i]; } } else if (m_header.qform_code != 0) {//fall back to qform float rotmat[3][3], quat[4]; quat[1] = m_header.quatern_b; quat[2] = m_header.quatern_c; quat[3] = m_header.quatern_d; float checkquat = quat[1] * quat[1] + quat[2] * quat[2] + quat[3] * quat[3]; if (checkquat <= 1.01f)//make sure qform is sane { if (checkquat > 1.0f) { quat[0] = 0.0f; } else { quat[0] = sqrt(1.0f - checkquat); } MathFunctions::quaternToMatrix(quat, rotmat); for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { rotmat[i][j] *= m_header.pixdim[j + 1]; } } if (m_header.pixdim[0] < 0.0f)//left handed coordinate system, flip the kvec { rotmat[0][2] = -rotmat[0][2]; rotmat[1][2] = -rotmat[1][2]; rotmat[2][2] = -rotmat[2][2]; } for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { ret[i][j] = rotmat[i][j]; } } ret[0][3] = m_header.qoffset_x; ret[1][3] = m_header.qoffset_y; ret[2][3] = m_header.qoffset_z; } else { CaretLogWarning("found quaternion with length greater than 1 in nifti header, using ANALYZE coordinates!"); ret[0][0] = m_header.pixdim[1]; ret[1][1] = m_header.pixdim[2]; ret[2][2] = m_header.pixdim[3]; } } else {//fall back to analyze and complain CaretLogWarning("no sform or qform code found, using ANALYZE coordinates!"); ret[0][0] = m_header.pixdim[1]; ret[1][1] = m_header.pixdim[2]; ret[2][2] = m_header.pixdim[3]; } int32_t spaceUnit = XYZT_TO_SPACE(m_header.xyzt_units); switch (spaceUnit) { case NIFTI_UNITS_METER: ret *= 1000.0f; ret[3][3] = 1.0f; break; case NIFTI_UNITS_MICRON: ret *= 0.001f; ret[3][3] = 1.0f; break; case 0: CaretLogFine("found spatial unit of '0' in nifti header, assuming millimeters"); case NIFTI_UNITS_MM: break; default: CaretLogWarning("unrecognized spatial unit in nifti header"); } return ret.getMatrix(); } double NiftiHeader::getTimeStep() const { int timeUnit = XYZT_TO_TIME(m_header.xyzt_units); double ret = m_header.pixdim[4]; switch (timeUnit) { case NIFTI_UNITS_USEC: ret /= 1000000.0; break; case NIFTI_UNITS_MSEC: ret /= 1000.0; break; default: CaretLogWarning("non-time units code " + AString::number(timeUnit) + " used in nifti header, pretending units are seconds"); case NIFTI_UNITS_SEC: break; } return ret; } QString NiftiHeader::toString() const { QString ret; if (isSwapped()) { ret += "native endian: false\n"; } else { ret += "native endian: true\n"; } ret += "sizeof_hdr: " + QString::number(m_header.sizeof_hdr) + "\n";//skip the fields that aren't important, like intent_p1, cal_max, etc ret += "magic: " + QByteArray(m_header.magic, 8);//quirk: QByteArray supports embedded nulls, so adding "\n" here doesn't result in a newline in the string ret += "\ndatatype: " + QString::number(m_header.datatype) + "\n"; ret += "bitpix: " + QString::number(m_header.bitpix) + "\n"; CaretAssert(m_header.dim[0] < 8); for (int i = 0; i <= m_header.dim[0]; ++i) { ret += "dim[" + QString::number(i) + "]: " + QString::number(m_header.dim[i]) + "\n"; } for (int i = 0; i <= m_header.dim[0]; ++i) { ret += "pixdim[" + QString::number(i) + "]: " + QString::number(m_header.pixdim[i]) + "\n"; } ret += "vox_offset: " + QString::number(m_header.vox_offset) + "\n"; ret += "scl_slope: " + QString::number(m_header.scl_slope) + "\n"; ret += "scl_inter: " + QString::number(m_header.scl_inter) + "\n"; ret += "sform_code: " + QString::number(m_header.sform_code) + "\n"; if (m_header.sform_code != NIFTI_XFORM_UNKNOWN) { ret += "srow_x:"; for (int i = 0; i < 4; ++i) { ret += " " + QString::number(m_header.srow_x[i]); } ret += "\nsrow_y:"; for (int i = 0; i < 4; ++i) { ret += " " + QString::number(m_header.srow_y[i]); } ret += "\nsrow_z:"; for (int i = 0; i < 4; ++i) { ret += " " + QString::number(m_header.srow_z[i]); } ret += "\n"; } ret += "qform_code: " + QString::number(m_header.qform_code) + "\n"; if (m_header.qform_code != NIFTI_XFORM_UNKNOWN) { ret += "quatern_b: " + QString::number(m_header.quatern_b) + "\n"; ret += "quatern_c: " + QString::number(m_header.quatern_c) + "\n"; ret += "quatern_d: " + QString::number(m_header.quatern_d) + "\n"; ret += "qoffset_x: " + QString::number(m_header.qoffset_x) + "\n"; ret += "qoffset_y: " + QString::number(m_header.qoffset_y) + "\n"; ret += "qoffset_z: " + QString::number(m_header.qoffset_z) + "\n"; } ret += "effective sform:\n"; vector > tempSform = getSForm(); for (int i = 0; i < 3; ++i) { for (int j = 0; j < 4; ++j) { ret += " " + QString::number(tempSform[i][j]); } ret += "\n"; } ret += "xyzt_units: " + QString::number(m_header.xyzt_units) + "\n"; ret += "intent_code: " + QString::number(m_header.intent_code) + "\n"; ret += "intent_name: " + QByteArray(m_header.intent_name, 16);//same quirk ret += "\n"; int numExts = (int)m_extensions.size(); ret += QString::number(numExts) + " extension"; if (numExts != 1) ret += "s"; if (numExts == 0) { ret += "\n"; } else { ret += ":\n"; for (int i = 0; i < numExts; ++i) { CaretAssert(m_extensions[i] != NULL); ret += "\n"; ret += "code: " + QString::number(m_extensions[i]->m_ecode) + "\n"; ret += "length: " + QString::number(m_extensions[i]->m_bytes.size()) + "\n"; } } return ret; } void NiftiHeader::setDataType(const int16_t& type) { m_header.bitpix = typeToNumBits(m_header.datatype);//to check for errors m_header.datatype = type; } void NiftiHeader::setDimensions(const vector& dimsIn) { if (dimsIn.size() > 7 || dimsIn.empty()) throw DataFileException("Number of dimensions must be between 1 and 7, inclusive."); m_header.dim[0] = dimsIn.size(); int i = 0; for(; i < (int)dimsIn.size(); i++) { if (dimsIn[i] < 1) throw DataFileException("all dimension lengths must be positive");//maybe these should be asserts? m_header.dim[i + 1] = dimsIn[i]; } for (; i < 7; ++i) { m_header.dim[i + 1] = 1;//we maintain 1s on unused dimensions to make some stupid nifti readers happy } } void NiftiHeader::setIntent(const int32_t& code, const char name[16]) { m_header.intent_code = code; int i;//custom strncpy-like code to fill nulls to the end for (i = 0; i < 16 && name[i] != '\0'; ++i) m_header.intent_name[i] = name[i]; for (; i < 16; ++i) m_header.intent_name[i] = '\0'; } void NiftiHeader::setDescription(const char descrip[80]) { int i;//custom strncpy-like code to fill nulls to the end for (i = 0; i < 80 && descrip[i] != '\0'; ++i) m_header.descrip[i] = descrip[i]; for (; i < 80; ++i) m_header.descrip[i] = '\0'; } void NiftiHeader::setSForm(const vector >& sForm) { CaretAssert(sForm.size() >= 3);//programmer error to pass badly sized matrix if (sForm.size() < 3) throw DataFileException("internal error: setSForm matrix badly sized");//but make release also throw for (int i = 0; i < (int)sForm.size(); i++) { CaretAssert(sForm[i].size() >= 4);//ditto if (sForm[i].size() < 4) throw DataFileException("internal error: setSForm matrix badly sized"); } int timeUnit = XYZT_TO_TIME(m_header.xyzt_units); m_header.xyzt_units = SPACE_TIME_TO_XYZT(NIFTI_UNITS_MM, timeUnit);//overwrite whatever spatial unit we read in for (int i = 0; i < 4; i++) { m_header.srow_x[i] = sForm[0][i]; m_header.srow_y[i] = sForm[1][i]; m_header.srow_z[i] = sForm[2][i]; } m_header.sform_code = NIFTI_XFORM_MNI_152; Vector3D ivec, jvec, kvec; ivec[0] = sForm[0][0]; ivec[1] = sForm[1][0]; ivec[2] = sForm[2][0]; jvec[0] = sForm[0][1]; jvec[1] = sForm[1][1]; jvec[2] = sForm[2][1]; kvec[0] = sForm[0][2]; kvec[1] = sForm[1][2]; kvec[2] = sForm[2][2]; m_header.pixdim[0] = 1.0f; m_header.pixdim[1] = ivec.length(); m_header.pixdim[2] = jvec.length(); m_header.pixdim[3] = kvec.length(); ivec = ivec.normal(); jvec = jvec.normal(); kvec = kvec.normal(); if (kvec.dot(ivec.cross(jvec)) < 0.0f)//left handed sform! { m_header.pixdim[0] = -1.0f; kvec = -kvec;//because to nifti, "left handed" apparently means "up is down", not "left is right" } float rotmat[3][3]; rotmat[0][0] = ivec[0]; rotmat[1][0] = ivec[1]; rotmat[2][0] = ivec[2]; rotmat[0][1] = jvec[0]; rotmat[1][1] = jvec[1]; rotmat[2][1] = jvec[2]; rotmat[0][2] = kvec[0]; rotmat[1][2] = kvec[1]; rotmat[2][2] = kvec[2]; float quat[4]; if (!MathFunctions::matrixToQuatern(rotmat, quat)) { m_header.qform_code = NIFTI_XFORM_UNKNOWN;//0, implies that there is no qform m_header.quatern_b = 0.0;//set dummy values anyway m_header.quatern_c = 0.0; m_header.quatern_d = 0.0; m_header.qoffset_x = sForm[0][3]; m_header.qoffset_y = sForm[1][3]; m_header.qoffset_z = sForm[2][3]; } else { m_header.qform_code = NIFTI_XFORM_MNI_152; m_header.quatern_b = quat[1]; m_header.quatern_c = quat[2]; m_header.quatern_d = quat[3]; m_header.qoffset_x = sForm[0][3]; m_header.qoffset_y = sForm[1][3]; m_header.qoffset_z = sForm[2][3]; } } void NiftiHeader::setTimeStep(const double& seconds) { int spaceUnit = XYZT_TO_SPACE(m_header.xyzt_units);//save the current space units so we don't clobber it... m_header.xyzt_units = SPACE_TIME_TO_XYZT(spaceUnit, NIFTI_UNITS_SEC);//overwrite the time part of the units with seconds m_header.pixdim[4] = seconds; } void NiftiHeader::clearDataScaling() { m_header.scl_slope = 1.0; m_header.scl_inter = 0.0; } void NiftiHeader::setDataScaling(const double& mult, const double& offset) { m_header.scl_slope = mult; m_header.scl_inter = offset; } namespace { template struct Scaling { double mult, offset; Scaling(const double& minval, const double& maxval) { typedef std::numeric_limits mylimits; double mymin = mylimits::lowest(); mult = (maxval - minval) / ((double)mylimits::max() - mymin);//multiplying is the first step of decoding (after byteswap), so start with the range offset = minval - mymin * mult;//offset is added after multiplying the encoded value by mult } }; } void NiftiHeader::setDataTypeAndScaleRange(const int16_t& type, const double& minval, const double& maxval) { setDataType(type); switch (type) { case NIFTI_TYPE_RGB24: clearDataScaling();//RGB ignores scaling fields break; case DT_BINARY://currently not supported in read/write functions anyway setDataScaling(maxval - minval, minval);//make the two possible decoded values equal to the min and max break; case NIFTI_TYPE_INT8: { Scaling myscale(minval, maxval); setDataScaling(myscale.mult, myscale.offset); break; } case NIFTI_TYPE_UINT8: { Scaling myscale(minval, maxval); setDataScaling(myscale.mult, myscale.offset); break; } case NIFTI_TYPE_INT16: { Scaling myscale(minval, maxval); setDataScaling(myscale.mult, myscale.offset); break; } case NIFTI_TYPE_UINT16: { Scaling myscale(minval, maxval); setDataScaling(myscale.mult, myscale.offset); break; } case NIFTI_TYPE_INT32: { Scaling myscale(minval, maxval); setDataScaling(myscale.mult, myscale.offset); break; } case NIFTI_TYPE_UINT32: { Scaling myscale(minval, maxval); setDataScaling(myscale.mult, myscale.offset); break; } case NIFTI_TYPE_INT64: { Scaling myscale(minval, maxval); setDataScaling(myscale.mult, myscale.offset); break; } case NIFTI_TYPE_UINT64: { Scaling myscale(minval, maxval); setDataScaling(myscale.mult, myscale.offset); break; } case NIFTI_TYPE_FLOAT32: case NIFTI_TYPE_COMPLEX64: { Scaling myscale(minval, maxval); setDataScaling(myscale.mult, myscale.offset); break; } case NIFTI_TYPE_FLOAT64: case NIFTI_TYPE_COMPLEX128: { Scaling myscale(minval, maxval); setDataScaling(myscale.mult, myscale.offset); break; } case NIFTI_TYPE_FLOAT128: case NIFTI_TYPE_COMPLEX256: { Scaling myscale(minval, maxval); setDataScaling(myscale.mult, myscale.offset); break; } default: CaretAssert(0); throw CaretException("internal error, report what you did to the developers"); } } int NiftiHeader::getNumComponents() const { switch (getDataType()) { case NIFTI_TYPE_RGB24: return 3; break; case NIFTI_TYPE_COMPLEX64: case NIFTI_TYPE_COMPLEX128: case NIFTI_TYPE_COMPLEX256: return 2; break; case DT_BINARY: case NIFTI_TYPE_INT8: case NIFTI_TYPE_UINT8: case NIFTI_TYPE_INT16: case NIFTI_TYPE_UINT16: case NIFTI_TYPE_INT32: case NIFTI_TYPE_UINT32: case NIFTI_TYPE_FLOAT32: case NIFTI_TYPE_INT64: case NIFTI_TYPE_UINT64: case NIFTI_TYPE_FLOAT64: case NIFTI_TYPE_FLOAT128: return 1; break; default: CaretAssert(0); throw CaretException("internal error, report what you did to the developers"); } } bool NiftiHeader::hasGoodSpatialInformation() const { return (m_header.sform_code != 0 || m_header.qform_code != 0); } void NiftiHeader::read(CaretBinaryFile& inFile) { nifti_1_header buffer1; nifti_2_header buffer2; inFile.read(&buffer1, sizeof(nifti_1_header)); int version = NIFTI2_VERSION(buffer1); bool swapped = false; Quirks myquirks; try { if (version == 2) { memcpy(&buffer2, &buffer1, sizeof(nifti_1_header)); inFile.read(((char*)&buffer2) + sizeof(nifti_1_header), sizeof(nifti_2_header) - sizeof(nifti_1_header)); if (NIFTI2_NEEDS_SWAP(buffer2)) { swapped = true; swapHeaderBytes(buffer2); } myquirks = setupFrom(buffer2, inFile.getFilename()); } else if (version == 1) { if (NIFTI2_NEEDS_SWAP(buffer1))//yes, this works on nifti-1 also { swapped = true; swapHeaderBytes(buffer1); } myquirks = setupFrom(buffer1, inFile.getFilename()); } else { throw DataFileException(inFile.getFilename() + " is not a valid NIfTI file"); } } catch (DataFileException& e) {//catch and throw in order to add filename info throw DataFileException("error reading NIfTI file " + inFile.getFilename() + ": " + e.whatString()); } m_extensions.clear(); if (myquirks.no_extender) { int min_offset = 352; if (version == 2) min_offset = 544; CaretLogWarning("in file '" + inFile.getFilename() + "', vox_offset is " + AString::number(m_header.vox_offset) + ", nifti standard specifies that it should be at least " + AString::number(min_offset) + ", assuming malformed file with no extender"); } else { char extender[4]; inFile.read(extender, 4); int extensions = 0;//if it has extensions in a format we don't know about, don't try to read them if (version == 1 && extender[0] != 0) extensions = 1;//sadly, this is the only thing nifti-1 says about the extender bytes if (version == 2 && extender[0] == 1 && extender[1] == 0 && extender[2] == 0 && extender[3] == 0) extensions = 1;//from http://nifti.nimh.nih.gov/nifti-2 as of 4/4/2014: if (extensions == 1)//"extentions match those of NIfTI-1.1 when the extender bytes are 1 0 0 0" { int64_t extStart; if (version == 1) { extStart = 352; } else { CaretAssert(version == 2); extStart = 544; } CaretAssert(inFile.pos() == extStart); while(extStart + 2 * sizeof(int32_t) <= (size_t)m_header.vox_offset) { int32_t esize, ecode; inFile.read(&esize, sizeof(int32_t)); if (swapped) ByteSwapping::swap(esize); inFile.read(&ecode, sizeof(int32_t)); if (swapped) ByteSwapping::swap(ecode); if (esize < 8 || esize + extStart > m_header.vox_offset) break; CaretPointer tempExtension(new NiftiExtension()); if ((size_t)esize > 2 * sizeof(int32_t))//don't try to read 0 bytes { tempExtension->m_bytes.resize(esize - 2 * sizeof(int32_t)); inFile.read(tempExtension->m_bytes.data(), esize - 2 * sizeof(int32_t)); } tempExtension->m_ecode = ecode; m_extensions.push_back(tempExtension); extStart += esize;//esize includes the two int32_ts } } } m_isSwapped = swapped;//now that we know there were no errors (because they throw), complete the internal state m_version = version; } NiftiHeader::Quirks NiftiHeader::setupFrom(const nifti_1_header& header, const AString& filename) { Quirks ret; if (header.sizeof_hdr != sizeof(nifti_1_header)) throw DataFileException(filename, "incorrect sizeof_hdr"); const char magic[] = "n+1\0";//only support single-file nifti if (strncmp(header.magic, magic, 4) != 0) throw DataFileException(filename, "incorrect magic"); if (header.dim[0] < 1 || header.dim[0] > 7) throw DataFileException(filename, "incorrect dim[0]"); for (int i = 0; i < header.dim[0]; ++i) { if (header.dim[i + 1] < 1) throw DataFileException(filename, "dim[" + QString::number(i + 1) + "] < 1"); } if (header.vox_offset < 352) { if (header.vox_offset < 348) { throw DataFileException(filename, "invalid vox_offset: " + AString::number(header.vox_offset)); } ret.no_extender = true; } int numBits = typeToNumBits(header.datatype); if (header.bitpix != numBits) CaretLogWarning("datatype disagrees with bitpix in file '" + filename + "'"); m_header.sizeof_hdr = header.sizeof_hdr;//copy in everything, so we don't have to fake anything to print the header as read for (int i = 0; i < 4; ++i)//mostly using nifti-2 field order to make it easier to find if things are missed { m_header.magic[i] = header.magic[i]; m_header.srow_x[i] = header.srow_x[i];//slight hack - nifti-1 magic and srows both happen to be 4 long m_header.srow_y[i] = header.srow_y[i]; m_header.srow_z[i] = header.srow_z[i]; } m_header.datatype = header.datatype; m_header.bitpix = header.bitpix; for (int i = 0; i < 8; ++i) { m_header.dim[i] = header.dim[i]; m_header.pixdim[i] = header.pixdim[i]; } m_header.intent_p1 = header.intent_p1; m_header.intent_p2 = header.intent_p2; m_header.intent_p3 = header.intent_p3; m_header.vox_offset = header.vox_offset;//technically, this could result in integer overflow, if the header extensions total exabytes in size m_header.scl_slope = header.scl_slope; m_header.scl_inter = header.scl_inter; m_header.cal_max = header.cal_max; m_header.cal_min = header.cal_min; m_header.slice_duration = header.slice_duration; m_header.toffset = header.toffset; m_header.slice_start = header.slice_start; m_header.slice_end = header.slice_end; for (int i = 0; i < 80; ++i) m_header.descrip[i] = header.descrip[i]; for (int i = 0; i < 24; ++i) m_header.aux_file[i] = header.aux_file[i]; m_header.qform_code = header.qform_code; m_header.sform_code = header.sform_code; m_header.quatern_b = header.quatern_b; m_header.quatern_c = header.quatern_c; m_header.quatern_d = header.quatern_d; m_header.qoffset_x = header.qoffset_x; m_header.qoffset_y = header.qoffset_y; m_header.qoffset_z = header.qoffset_z; m_header.slice_code = header.slice_code; m_header.xyzt_units = header.xyzt_units; m_header.intent_code = header.intent_code; for (int i = 0; i < 16; ++i) m_header.intent_name[i] = header.intent_name[i]; m_header.dim_info = header.dim_info; return ret; } NiftiHeader::Quirks NiftiHeader::setupFrom(const nifti_2_header& header, const AString& filename) { Quirks ret; if (header.sizeof_hdr != sizeof(nifti_2_header)) throw DataFileException(filename, "incorrect sizeof_hdr"); const char magic[] = "n+2\0\r\n\032\n";//only support single-file nifti for (int i = 0; i < 8; ++i) { if (header.magic[i] != magic[i]) throw DataFileException(filename, "incorrect magic"); } if (header.dim[0] < 1 || header.dim[0] > 7) throw DataFileException(filename, "incorrect dim[0]"); for (int i = 0; i < header.dim[0]; ++i) { if (header.dim[i + 1] < 1) throw DataFileException(filename, "dim[" + QString::number(i + 1) + "] < 1"); } if (header.vox_offset < 544) throw DataFileException(filename, "incorrect vox_offset");//haven't noticed any nifti-2 with bad vox_offset yet, and all cifti files have a big extension, so they have to have used it correctly if (header.bitpix != typeToNumBits(header.datatype)) CaretLogWarning("datatype disagrees with bitpix in file '" + filename + "'"); memcpy(&m_header, &header, sizeof(nifti_2_header)); return ret; } int NiftiHeader::typeToNumBits(const int64_t& type) { switch (type) { case DT_BINARY: return 1; break; case NIFTI_TYPE_INT8: case NIFTI_TYPE_UINT8: return 8; break; case NIFTI_TYPE_INT16: case NIFTI_TYPE_UINT16: return 16; break; case NIFTI_TYPE_RGB24: return 24; break; case NIFTI_TYPE_INT32: case NIFTI_TYPE_UINT32: case NIFTI_TYPE_FLOAT32: return 32; break; case NIFTI_TYPE_INT64: case NIFTI_TYPE_UINT64: case NIFTI_TYPE_FLOAT64: case NIFTI_TYPE_COMPLEX64: return 64; break; case NIFTI_TYPE_FLOAT128: case NIFTI_TYPE_COMPLEX128: return 128; break; case NIFTI_TYPE_COMPLEX256: return 256; break; default: throw DataFileException("incorrect nifti datatype code"); } } void NiftiHeader::swapHeaderBytes(nifti_1_header& header) { ByteSwapping::swap(header.sizeof_hdr);//by order of fields in nifti-1 header, skip unused because we don't store their data ByteSwapping::swapArray(header.dim, 8); ByteSwapping::swap(header.intent_p1); ByteSwapping::swap(header.intent_p2); ByteSwapping::swap(header.intent_p3); ByteSwapping::swap(header.intent_code); ByteSwapping::swap(header.datatype); ByteSwapping::swap(header.bitpix); ByteSwapping::swap(header.slice_start); ByteSwapping::swapArray(header.pixdim, 8); ByteSwapping::swap(header.vox_offset); ByteSwapping::swap(header.scl_slope); ByteSwapping::swap(header.scl_inter); ByteSwapping::swap(header.slice_end); ByteSwapping::swap(header.cal_max); ByteSwapping::swap(header.cal_min); ByteSwapping::swap(header.slice_duration); ByteSwapping::swap(header.toffset); ByteSwapping::swap(header.qform_code); ByteSwapping::swap(header.sform_code); ByteSwapping::swap(header.quatern_b); ByteSwapping::swap(header.quatern_c); ByteSwapping::swap(header.quatern_d); ByteSwapping::swap(header.qoffset_x); ByteSwapping::swap(header.qoffset_y); ByteSwapping::swap(header.qoffset_z); ByteSwapping::swapArray(header.srow_x, 4); ByteSwapping::swapArray(header.srow_y, 4); ByteSwapping::swapArray(header.srow_z, 4); } void NiftiHeader::swapHeaderBytes(nifti_2_header& header) { ByteSwapping::swap(header.sizeof_hdr);//by order of fields in nifti-2 header ByteSwapping::swap(header.datatype); ByteSwapping::swap(header.bitpix); ByteSwapping::swapArray(header.dim, 8); ByteSwapping::swap(header.intent_p1); ByteSwapping::swap(header.intent_p2); ByteSwapping::swap(header.intent_p3); ByteSwapping::swapArray(header.pixdim, 8); ByteSwapping::swap(header.vox_offset); ByteSwapping::swap(header.scl_slope); ByteSwapping::swap(header.scl_inter); ByteSwapping::swap(header.cal_max); ByteSwapping::swap(header.cal_min); ByteSwapping::swap(header.slice_duration); ByteSwapping::swap(header.toffset); ByteSwapping::swap(header.slice_start); ByteSwapping::swap(header.slice_end); ByteSwapping::swap(header.qform_code); ByteSwapping::swap(header.sform_code); ByteSwapping::swap(header.quatern_b); ByteSwapping::swap(header.quatern_c); ByteSwapping::swap(header.quatern_d); ByteSwapping::swap(header.qoffset_x); ByteSwapping::swap(header.qoffset_y); ByteSwapping::swap(header.qoffset_z); ByteSwapping::swapArray(header.srow_x, 4); ByteSwapping::swapArray(header.srow_y, 4); ByteSwapping::swapArray(header.srow_z, 4); ByteSwapping::swap(header.slice_code); ByteSwapping::swap(header.xyzt_units); ByteSwapping::swap(header.intent_code); } void NiftiHeader::write(CaretBinaryFile& outFile, const int& version, const bool& swapEndian) { if (!canWriteVersion(version)) throw DataFileException("unable to write NIfTI version " + QString::number(version) + " for file " + outFile.getFilename()); double junk1, junk2; int16_t datatype = getDataType(); if (getDataScaling(junk1, junk2) && ((datatype & 0x70) > 0 || datatype >= 1536)) {//that hacky expression is to detect 16, 32, 64, 1536, 1792, and 2048 CaretLogWarning("writing nifti file with scaling factor and floating point datatype"); } const char padding[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int64_t voxOffset; if (version == 2) { nifti_2_header outHeader; prepareHeader(outHeader); voxOffset = outHeader.vox_offset; if (swapEndian) swapHeaderBytes(outHeader); outFile.write(&outHeader, sizeof(nifti_2_header)); } else if (version == 1) { nifti_1_header outHeader; prepareHeader(outHeader); voxOffset = outHeader.vox_offset; if (swapEndian) swapHeaderBytes(outHeader); outFile.write(&outHeader, sizeof(nifti_1_header)); } else { CaretAssert(0);//canWriteVersion should have said no throw DataFileException("internal error: NiftiHeader::canWriteVersion() returned true for unimplemented writing version"); } char extender[] = { 0, 0, 0, 0 };//at least until nifti-2 gets a new extension format, use the same code for both int numExtensions = (int)m_extensions.size(); if (numExtensions != 0) extender[0] = 1; outFile.write(extender, 4); for (int i = 0; i < numExtensions; ++i) { CaretAssert(m_extensions[i] != NULL); int64_t thisSize = 8 + m_extensions[i]->m_bytes.size();//8 is for the int32_t size and ecode for nifti-1 style extensions int paddingBytes = 0; if (thisSize % 16 != 0)//round up to nearest multiple of 16 { paddingBytes = 16 - (thisSize % 16); thisSize += paddingBytes; } CaretAssert(thisSize <= numeric_limits::max()); CaretAssert(thisSize + outFile.pos() <= voxOffset); int32_t outSize = thisSize; int32_t outEcode = m_extensions[i]->m_ecode; if (swapEndian) { ByteSwapping::swap(outSize); ByteSwapping::swap(outEcode); } outFile.write(&outSize, sizeof(int32_t)); outFile.write(&outEcode, sizeof(int32_t)); outFile.write(m_extensions[i]->m_bytes.data(), m_extensions[i]->m_bytes.size()); if (paddingBytes != 0) outFile.write(padding, paddingBytes); } CaretAssert(outFile.pos() == voxOffset); m_header.vox_offset = voxOffset;//update internal state to reflect the state that was written to the file m_version = version; m_isSwapped = swapEndian; } void NiftiHeader::prepareHeader(nifti_1_header& header) const { CaretAssert(canWriteVersion(1));//programmer error to call this if it isn't possible header.sizeof_hdr = sizeof(nifti_1_header);//do static things first const char magic[] = "n+1\0";//only support single-file nifti for (int i = 0; i < 4; ++i) header.magic[i] = magic[i]; for (int i = 0; i < 10; ++i) header.data_type[i] = 0;//then zero unused things for (int i = 0; i < 18; ++i) header.db_name[i] = 0; header.extents = 0; header.session_error = 0; header.regular = 0; header.glmax = 0; header.glmin = 0; header.dim_info = m_header.dim_info;//by order of fields in nifti-1 header, skipping unused and static for (int i = 0; i < 8; ++i) header.dim[i] = m_header.dim[i];//canWriteVersion should have already checked that this is okay, first in write(), then asserted above header.intent_p1 = m_header.intent_p1;//theoretically, this could be a problem wih large exponents, or if extremely high precision is required header.intent_p2 = m_header.intent_p2;//but we don't use them at all currently, so we don't care header.intent_p3 = m_header.intent_p3; header.intent_code = m_header.intent_code; header.datatype = m_header.datatype; header.bitpix = typeToNumBits(m_header.datatype);//in case we ever accept wrong bitpix with a warning, NEVER write wrong bitpix header.slice_start = m_header.slice_start; for (int i = 0; i < 8; ++i) header.pixdim[i] = m_header.pixdim[i];//more double to float conversion header.vox_offset = computeVoxOffset(1);//again, canWriteVersion should have checked that this, and later conversions, are okay CaretAssert(header.vox_offset >= 352); header.scl_slope = m_header.scl_slope; header.scl_inter = m_header.scl_inter; header.slice_end = m_header.slice_end; header.slice_code = m_header.slice_code; header.xyzt_units = m_header.xyzt_units; header.cal_min = m_header.cal_min; header.cal_max = m_header.cal_max; header.slice_duration = m_header.slice_duration; header.toffset = m_header.toffset; for (int i = 0; i < 80; ++i) header.descrip[i] = m_header.descrip[i]; for (int i = 0; i < 24; ++i) header.aux_file[i] = m_header.aux_file[i]; header.qform_code = m_header.qform_code; header.sform_code = m_header.sform_code; header.quatern_b = m_header.quatern_b; header.quatern_c = m_header.quatern_c; header.quatern_d = m_header.quatern_d; header.qoffset_x = m_header.qoffset_x; header.qoffset_y = m_header.qoffset_y; header.qoffset_z = m_header.qoffset_z; for (int i = 0; i < 4; ++i) { header.srow_x[i] = m_header.srow_x[i]; header.srow_y[i] = m_header.srow_y[i]; header.srow_z[i] = m_header.srow_z[i]; } for (int i = 0; i < 16; ++i) header.intent_name[i] = m_header.intent_name[i]; } void NiftiHeader::prepareHeader(nifti_2_header& header) const { CaretAssert(canWriteVersion(2)); memcpy(&header, &m_header, sizeof(nifti_2_header));//first copy everything, then fix static and computed fields header.sizeof_hdr = sizeof(nifti_2_header); const char magic[] = "n+2\0\r\n\032\n"; for (int i = 0; i < 8; ++i) header.magic[i] = magic[i]; header.bitpix = typeToNumBits(header.datatype); header.vox_offset = computeVoxOffset(2); for (int i = 0; i < 15; ++i) header.unused_str[i] = 0;//in case we read in a header where these bytes weren't zero } connectome-workbench-1.4.2/src/Nifti/NiftiHeader.h000066400000000000000000000106121360521144700220260ustar00rootroot00000000000000#ifndef __NIFTI_HEADER_H__ #define __NIFTI_HEADER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretBinaryFile.h" #include "VolumeBase.h" //for AbstractHeader, AbstravtVolumeExtension #include "nifti1.h" #include "nifti2.h" #include namespace caret { struct NiftiExtension { int32_t m_ecode; std::vector m_bytes; }; struct NiftiHeader : public AbstractHeader { std::vector > m_extensions;//allow direct access to the extensions NiftiHeader(); NiftiHeader(const NiftiHeader& rhs); NiftiHeader& operator=(const NiftiHeader& rhs); void read(CaretBinaryFile& inFile); void write(CaretBinaryFile& outFile, const int& version = 1, const bool& swapEndian = false); bool canWriteVersion(const int& version) const; bool isSwapped() const { return m_isSwapped; } int version() const { return m_version; } HeaderType getType() const { return NIFTI; } AbstractHeader* clone() const; std::vector getDimensions() const; std::vector > getSForm() const; double getTimeStep() const;//seconds int64_t getDataOffset() const { return m_header.vox_offset; } int16_t getDataType() const { return m_header.datatype; } int32_t getIntentCode() const { return m_header.intent_code; } const char* getIntentName() const { return m_header.intent_name; }//NOTE: 16 BYTES, MAY NOT HAVE A NULL TERMINATOR const char* getDescription() const { return m_header.descrip; }//NOTE: 80 BYTES, MAY NOT HAVE A NULL TERMINATOR bool getDataScaling(double& mult, double& offset) const;//returns false if scaling not needed int getNumComponents() const; bool hasGoodSpatialInformation() const; QString toString() const; void setDimensions(const std::vector& dimsIn); void setSForm(const std::vector > &sForm); void setTimeStep(const double& seconds); void setIntent(const int32_t& code, const char name[16]); void setDescription(const char descrip[80]); void setDataType(const int16_t& type); void clearDataScaling(); void setDataScaling(const double& mult, const double& offset); void setDataTypeAndScaleRange(const int16_t& type, const double& minval, const double& maxval); ///get the FSL "scale" space std::vector > getFSLSpace() const; bool operator==(const NiftiHeader& rhs) const;//for testing purposes bool operator!=(const NiftiHeader& rhs) const { return !((*this) == rhs); } private: struct Quirks { bool no_extender; Quirks() { no_extender = false; } }; nifti_2_header m_header;//storage for header values regardless of version int m_version; bool m_isSwapped; static void swapHeaderBytes(nifti_1_header &header); static void swapHeaderBytes(nifti_2_header &header); void prepareHeader(nifti_1_header& header) const;//transform internal state into ready to write header struct void prepareHeader(nifti_2_header& header) const; Quirks setupFrom(const nifti_1_header& header, const AString& filename);//error check provided header, and populate members from it Quirks setupFrom(const nifti_2_header& header, const AString& filename); static int typeToNumBits(const int64_t& type); int64_t computeVoxOffset(const int& version) const; }; } #endif //__NIFTI_HEADER_H__ connectome-workbench-1.4.2/src/Nifti/NiftiIO.cxx000066400000000000000000000064401360521144700215240ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "NiftiIO.h" #include "DataFileException.h" using namespace std; using namespace caret; void NiftiIO::openRead(const QString& filename) { m_file.open(filename); m_header.read(m_file); if (m_header.getDataType() == DT_BINARY) { throw DataFileException("file uses the binary datatype, which is unsupported: " + filename); } m_dims = m_header.getDimensions(); int64_t filesize = m_file.size();//returns -1 if it can't efficiently determine size int64_t elemCount = getNumComponents(); for (int i = 0; i < (int)m_dims.size(); ++i) { elemCount *= m_dims[i]; } if (filesize >= 0 && filesize < m_header.getDataOffset() + numBytesPerElem() * elemCount) { throw DataFileException("nifti file is truncated: " + filename); } } void NiftiIO::writeNew(const QString& filename, const NiftiHeader& header, const int& version, const bool& withRead, const bool& swapEndian) { if (header.getDataType() == DT_BINARY) { throw DataFileException("writing NIFTI with binary datatype is unsupported"); } if (withRead) { m_file.open(filename, CaretBinaryFile::READ_WRITE_TRUNCATE);//for cifti on-disk writing, replace structure with along row needs to RMW } else { m_file.open(filename, CaretBinaryFile::WRITE_TRUNCATE); } m_header = header; m_header.write(m_file, version, swapEndian); m_dims = m_header.getDimensions(); } void NiftiIO::close() { m_file.close(); m_dims.clear(); } int NiftiIO::getNumComponents() const { return m_header.getNumComponents(); } int NiftiIO::numBytesPerElem() { switch (m_header.getDataType()) { case NIFTI_TYPE_INT8: case NIFTI_TYPE_UINT8: case NIFTI_TYPE_RGB24: return 1; break; case NIFTI_TYPE_INT16: case NIFTI_TYPE_UINT16: return 2; break; case NIFTI_TYPE_INT32: case NIFTI_TYPE_UINT32: case NIFTI_TYPE_FLOAT32: case NIFTI_TYPE_COMPLEX64: return 4; break; case NIFTI_TYPE_INT64: case NIFTI_TYPE_UINT64: case NIFTI_TYPE_FLOAT64: case NIFTI_TYPE_COMPLEX128: return 8; break; case NIFTI_TYPE_FLOAT128: case NIFTI_TYPE_COMPLEX256: return 16; break; default: CaretAssert(0); throw DataFileException("internal error, report what you did to the developers"); } } connectome-workbench-1.4.2/src/Nifti/NiftiIO.h000066400000000000000000000331471360521144700211550ustar00rootroot00000000000000#ifndef __NIFTI_IO_H__ #define __NIFTI_IO_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "ByteSwapping.h" #include "CaretAssert.h" #include "CaretBinaryFile.h" #include "CaretMutex.h" #include "DataFileException.h" #include "NiftiHeader.h" #include #include #include #include namespace caret { class NiftiIO { CaretBinaryFile m_file; NiftiHeader m_header; std::vector m_dims; std::vector m_scratch;//scratch memory for byteswapping, type conversion, etc CaretMutex m_mutex;//protect multithreaded calls from each other int numBytesPerElem();//for resizing scratch template void convertRead(TO* out, FROM* in, const int64_t& count);//for reading from file template void convertWrite(TO* out, const FROM* in, const int64_t& count);//for writing to file template static TO clamp(const FROM& in);//deal with integer cast being undefined when converting from outside range public: void openRead(const QString& filename); void writeNew(const QString& filename, const NiftiHeader& header, const int& version = 1, const bool& withRead = false, const bool& swapEndian = false); QString getFilename() const { return m_file.getFilename(); } void overrideDimensions(const std::vector& newDims) { m_dims = newDims; }//HACK: deal with reading/writing CIFTI-1's broken headers void close(); const NiftiHeader& getHeader() const { return m_header; } void dropExtensions() { m_header.m_extensions.clear(); } const std::vector& getDimensions() const { return m_dims; } int getNumComponents() const; //to read/write 1 frame of a standard volume file, call with fullDims = 3, indexSelect containing indexes for any of dims 4-7 that exist //NOTE: you need to provide storage for all components within the range, if getNumComponents() == 3 and fullDims == 0, you need 3 elements allocated template void readData(T* dataOut, const int& fullDims, const std::vector& indexSelect, const bool& tolerateShortRead = false); template void writeData(const T* dataIn, const int& fullDims, const std::vector& indexSelect); }; template void NiftiIO::readData(T* dataOut, const int& fullDims, const std::vector& indexSelect, const bool& tolerateShortRead) { CaretAssert(fullDims >= 0 && fullDims <= (int)m_dims.size()); CaretAssert((size_t)fullDims + indexSelect.size() == m_dims.size());//could be >=, but should catch more stupid mistakes as == int64_t numElems = getNumComponents();//for now, calculate read size on the fly, as the read call will be the slowest part int curDim; for (curDim = 0; curDim < fullDims; ++curDim) { numElems *= m_dims[curDim]; } int64_t numDimSkip = numElems, numSkip = 0; for (; curDim < (int)m_dims.size(); ++curDim) { CaretAssert(indexSelect[curDim - fullDims] >= 0 && indexSelect[curDim - fullDims] < m_dims[curDim]); numSkip += indexSelect[curDim - fullDims] * numDimSkip; numDimSkip *= m_dims[curDim]; } CaretMutexLocker locked(&m_mutex);//protect starting with resizing until we are done converting, because we use an internal variable for scratch space //we can't guarantee that the output memory is enough to use as scratch space, as we might be doing a narrowing conversion //we are doing FILE ACCESS, so cpu performance isn't really something to worry about m_scratch.resize(numElems * numBytesPerElem()); m_file.seek(numSkip * numBytesPerElem() + m_header.getDataOffset()); int64_t numRead = 0; m_file.read(m_scratch.data(), m_scratch.size(), &numRead); if ((numRead != (int64_t)m_scratch.size() && !tolerateShortRead) || numRead < 0)//for now, assume read giving -1 is always a problem { throw DataFileException("error while reading from nifti file '" + m_file.getFilename() + "'"); } switch (m_header.getDataType()) { case NIFTI_TYPE_UINT8: case NIFTI_TYPE_RGB24://handled by components convertRead(dataOut, (uint8_t*)m_scratch.data(), numElems); break; case NIFTI_TYPE_INT8: convertRead(dataOut, (int8_t*)m_scratch.data(), numElems); break; case NIFTI_TYPE_UINT16: convertRead(dataOut, (uint16_t*)m_scratch.data(), numElems); break; case NIFTI_TYPE_INT16: convertRead(dataOut, (int16_t*)m_scratch.data(), numElems); break; case NIFTI_TYPE_UINT32: convertRead(dataOut, (uint32_t*)m_scratch.data(), numElems); break; case NIFTI_TYPE_INT32: convertRead(dataOut, (int32_t*)m_scratch.data(), numElems); break; case NIFTI_TYPE_UINT64: convertRead(dataOut, (uint64_t*)m_scratch.data(), numElems); break; case NIFTI_TYPE_INT64: convertRead(dataOut, (int64_t*)m_scratch.data(), numElems); break; case NIFTI_TYPE_FLOAT32: case NIFTI_TYPE_COMPLEX64://components convertRead(dataOut, (float*)m_scratch.data(), numElems); break; case NIFTI_TYPE_FLOAT64: case NIFTI_TYPE_COMPLEX128: convertRead(dataOut, (double*)m_scratch.data(), numElems); break; case NIFTI_TYPE_FLOAT128: case NIFTI_TYPE_COMPLEX256: convertRead(dataOut, (long double*)m_scratch.data(), numElems); break; default: CaretAssert(0); throw DataFileException("internal error, tell the developers what you just tried to do"); } } template void NiftiIO::writeData(const T* dataIn, const int& fullDims, const std::vector& indexSelect) { CaretAssert(fullDims >= 0 && fullDims <= (int)m_dims.size()); CaretAssert((size_t)fullDims + indexSelect.size() == m_dims.size());//could be >=, but should catch more stupid mistakes as == int64_t numElems = getNumComponents();//for now, calculate read size on the fly, as the read call will be the slowest part int curDim; for (curDim = 0; curDim < fullDims; ++curDim) { numElems *= m_dims[curDim]; } int64_t numDimSkip = numElems, numSkip = 0; for (; curDim < (int)m_dims.size(); ++curDim) { CaretAssert(indexSelect[curDim - fullDims] >= 0 && indexSelect[curDim - fullDims] < m_dims[curDim]); numSkip += indexSelect[curDim - fullDims] * numDimSkip; numDimSkip *= m_dims[curDim]; } CaretMutexLocker locked(&m_mutex);//protect starting with resizing until we are done writing, because we use an internal variable for scratch space //we are doing FILE ACCESS, so cpu performance isn't really something to worry about m_scratch.resize(numElems * numBytesPerElem()); m_file.seek(numSkip * numBytesPerElem() + m_header.getDataOffset()); switch (m_header.getDataType()) { case NIFTI_TYPE_UINT8: case NIFTI_TYPE_RGB24://handled by components convertWrite((uint8_t*)m_scratch.data(), dataIn, numElems); break; case NIFTI_TYPE_INT8: convertWrite((int8_t*)m_scratch.data(), dataIn, numElems); break; case NIFTI_TYPE_UINT16: convertWrite((uint16_t*)m_scratch.data(), dataIn, numElems); break; case NIFTI_TYPE_INT16: convertWrite((int16_t*)m_scratch.data(), dataIn, numElems); break; case NIFTI_TYPE_UINT32: convertWrite((uint32_t*)m_scratch.data(), dataIn, numElems); break; case NIFTI_TYPE_INT32: convertWrite((int32_t*)m_scratch.data(), dataIn, numElems); break; case NIFTI_TYPE_UINT64: convertWrite((uint64_t*)m_scratch.data(), dataIn, numElems); break; case NIFTI_TYPE_INT64: convertWrite((int64_t*)m_scratch.data(), dataIn, numElems); break; case NIFTI_TYPE_FLOAT32: case NIFTI_TYPE_COMPLEX64://components convertWrite((float*)m_scratch.data(), dataIn, numElems); break; case NIFTI_TYPE_FLOAT64: case NIFTI_TYPE_COMPLEX128: convertWrite((double*)m_scratch.data(), dataIn, numElems); break; case NIFTI_TYPE_FLOAT128: case NIFTI_TYPE_COMPLEX256: convertWrite((long double*)m_scratch.data(), dataIn, numElems); break; default: CaretAssert(0); throw DataFileException("internal error, tell the developers what you just tried to do"); } m_file.write(m_scratch.data(), m_scratch.size()); } template void NiftiIO::convertRead(TO* out, FROM* in, const int64_t& count) { if (m_header.isSwapped()) { ByteSwapping::swapArray(in, count); } double mult, offset; bool doScale = m_header.getDataScaling(mult, offset); if (std::numeric_limits::is_integer)//do round to nearest when integer output type { if (doScale) { for (int64_t i = 0; i < count; ++i) { out[i] = clamp(floor(0.5l + offset + mult * (long double)in[i]));//we don't always need that much precision, but it will still be faster than hard drives } } else { for (int64_t i = 0; i < count; ++i) { out[i] = clamp(floor(0.5 + in[i])); } } } else { if (doScale) { for (int64_t i = 0; i < count; ++i) { out[i] = (TO)(offset + mult * (long double)in[i]);//we don't always need that much precision, but it will still be faster than hard drives } } else { for (int64_t i = 0; i < count; ++i) { out[i] = (TO)in[i];//explicit cast to make sure the compiler doesn't squawk } } } } template void NiftiIO::convertWrite(TO* out, const FROM* in, const int64_t& count) { double mult, offset; bool doScale = m_header.getDataScaling(mult, offset); if (std::numeric_limits::is_integer)//do round to nearest when integer output type {//TODO: what about NaN? if (doScale) { for (int64_t i = 0; i < count; ++i) { out[i] = clamp(floor(0.5l + ((long double)in[i] - offset) / mult));//we don't always need that much precision, but it will still be faster than hard drives } } else { for (int64_t i = 0; i < count; ++i) { out[i] = clamp(floor(0.5 + in[i])); } } } else { if (doScale) { for (int64_t i = 0; i < count; ++i) { out[i] = (TO)(((long double)in[i] - offset) / mult);//we don't always need that much precision, but it will still be faster than hard drives } } else { for (int64_t i = 0; i < count; ++i) { out[i] = (TO)in[i];//explicit cast to make sure the compiler doesn't squawk } } } if (m_header.isSwapped()) ByteSwapping::swapArray(out, count); } template TO NiftiIO::clamp(const FROM& in) { typedef std::numeric_limits mylimits; if (mylimits::has_infinity && std::isinf(in)) return (TO)in;//in case we use this on float types at some point if (mylimits::max() < in) return mylimits::max(); if (mylimits::lowest() > in) return mylimits::lowest(); /*if (mylimits::is_integer)//here is a c++03 solution to missing ::lowest { if (mylimits::min() > in) return mylimits::min(); } else { if (-mylimits::max() > in) return -mylimits::max(); }//*/ return (TO)in; } } #endif //__NIFTI_IO_H__ connectome-workbench-1.4.2/src/OSMesaDummy/000077500000000000000000000000001360521144700205655ustar00rootroot00000000000000connectome-workbench-1.4.2/src/OSMesaDummy/CMakeLists.txt000066400000000000000000000006021360521144700233230ustar00rootroot00000000000000 # # Name of Project # PROJECT(OSMesaDummy) # # Need Qt for reading from resource file. # IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () # # Create a library # ADD_LIBRARY(OSMesaDummy OSMesaDummy.h OSMesaDummy.c ) TARGET_LINK_LIBRARIES(OSMesaDummy ${CARET_QT5_LINK}) # # Include directories # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Graphics ${CMAKE_SOURCE_DIR}/OSMesaDummy ) connectome-workbench-1.4.2/src/OSMesaDummy/OSMesaDummy.c000066400000000000000000000045121360521144700230760ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "assert.h" #define __O_S_MESA_DUMMY_DECLARE__ #include "OSMesaDummy.h" #undef __O_S_MESA_DUMMY_DECLARE__ /* * THESE ARE DUMMY METHODS. * * THE COMMAND LINE USES OSMESA FOR RENDERING IMAGES USING OPENG * WITHOUT A DISPLAY. HOWEVER, WITH THE GUI, IF THE OSMESA * LIBRARY IS LINKED, IT SOMEHOW RESULTS IN THE MESA GL (OPENGL) * LIBRARY BEING LINKED INSTEAD OF THE SYSTEM'S HARDWARE OPENGL * LIBRARY AND EVERYTHING IS SCREWED UP. * * IT IS THE DISPLAY OF HELP INFORMATION FOR COMMANDS THAT INCLUDES * THE SHOW SCENE COMMAND THAT REQUIRES OSMESA. */ /*GLAPI*/ OSMesaContext /*GLAPIENTRY*/ OSMesaCreateContextExt(GLenum format, GLint depthBits, GLint stencilBits, GLint accumBits, OSMesaContext sharelist) { /* * NOTE: These are "C" functions (NOT "C++") and so the names * of the parameters cannot be removed to avoid a compilation * warning as missing parameter names is a compiler error in "C". */ if (format || depthBits || stencilBits || accumBits || sharelist) { } assert(0); return 0; } /*GLAPI*/ void /*GLAPIENTRY*/ OSMesaDestroyContext( OSMesaContext ctx ) { if (ctx) { } assert(0); } /*GLAPI*/ GLboolean /*GLAPIENTRY*/ OSMesaMakeCurrent( OSMesaContext ctx, void * buffer, GLenum type, GLsizei width, GLsizei height ) { if (ctx || buffer || type || width || height) { } assert(0); return GL_FALSE; } connectome-workbench-1.4.2/src/OSMesaDummy/OSMesaDummy.h000066400000000000000000000027231360521144700231050ustar00rootroot00000000000000#ifndef __O_S_MESA_DUMMY_H__ #define __O_S_MESA_DUMMY_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretOpenGLInclude.h" typedef struct osmesa_context *OSMesaContext; /* * THESE ARE DUMMY METHODS. * * See the ".c" file for more info. */ /*GLAPI*/ OSMesaContext /*GLAPIENTRY*/ OSMesaCreateContextExt(GLenum format, GLint depthBits, GLint stencilBits, GLint accumBits, OSMesaContext sharelist); /*GLAPI*/ void /*GLAPIENTRY*/ OSMesaDestroyContext( OSMesaContext ctx ); /*GLAPI*/ GLboolean /*GLAPIENTRY*/ OSMesaMakeCurrent( OSMesaContext ctx, void *buffer, GLenum type, GLsizei width, GLsizei height ); #endif //__O_S_MESA_DUMMY_H__ connectome-workbench-1.4.2/src/Operations/000077500000000000000000000000001360521144700205455ustar00rootroot00000000000000connectome-workbench-1.4.2/src/Operations/CMakeLists.txt000066400000000000000000000144251360521144700233130ustar00rootroot00000000000000# # Name of project # PROJECT (Operations) # # Add QT for includes # if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) include_directories(${Qt5Gui_INCLUDE_DIRS}) endif() IF (QT4_FOUND) SET(QT_DONT_USE_QTGUI) INCLUDE(${QT_USE_FILE}) ENDIF () # # Create the helper library # ADD_LIBRARY(Operations OperationAddToSpecFile.h OperationBackendAverageDenseROI.h OperationBackendAverageROICorrelation.h OperationBorderExportColorTable.h OperationBorderFileExportToCaret5.h OperationBorderLength.h OperationBorderMerge.h OperationCiftiChangeMapping.h OperationCiftiChangeTimestep.h OperationCiftiConvert.h OperationCiftiConvertToScalar.h OperationCiftiCopyMapping.h OperationCiftiCreateDenseFromTemplate.h OperationCiftiCreateParcellatedFromTemplate.h OperationCiftiCreateScalarSeries.h OperationCiftiEstimateFWHM.h OperationCiftiExportDenseMapping.h OperationCiftiLabelExportTable.h OperationCiftiLabelImport.h OperationCiftiMath.h OperationCiftiMerge.h OperationCiftiPalette.h OperationCiftiResampleDconnMemory.h OperationCiftiROIAverage.h OperationCiftiSeparateAll.h OperationCiftiStats.h OperationCiftiWeightedStats.h OperationConvertAffine.h OperationConvertFiberOrientations.h OperationConvertMatrix4ToMatrix2.h OperationConvertMatrix4ToWorkbenchSparse.h OperationConvertWarpfield.h OperationEstimateFiberBinghams.h OperationException.h OperationFileConvert.h OperationFileInformation.h OperationFociCreate.h OperationFociGetProjectionVertex.h OperationFociListCoords.h OperationGiftiConvert.h OperationLabelExportTable.h OperationLabelMask.h OperationLabelMerge.h OperationMetadataRemoveProvenance.h OperationMetadataStringReplace.h OperationMetricConvert.h OperationMetricLabelImport.h OperationMetricMask.h OperationMetricMath.h OperationMetricMerge.h OperationMetricPalette.h OperationMetricStats.h OperationMetricVertexSum.h OperationMetricWeightedStats.h OperationNiftiInformation.h OperationProbtrackXDotConvert.h OperationSceneFileMerge.h OperationSceneFileRelocate.h OperationSetMapName.h OperationSetMapNames.h OperationSetStructure.h OperationShowScene.h OperationSpecFileMerge.h OperationSpecFileRelocate.h OperationSurfaceClosestVertex.h OperationSurfaceCoordinatesToMetric.h OperationSurfaceCutResample.h OperationSurfaceFlipNormals.h OperationSurfaceGeodesicDistance.h OperationSurfaceGeodesicDistanceAllToAll.h OperationSurfaceGeodesicROIs.h OperationSurfaceInformation.h OperationSurfaceNormals.h OperationSurfaceSetCoordinates.h OperationSurfaceVertexAreas.h OperationVolumeCapturePlane.h OperationVolumeCopyExtensions.h OperationVolumeCreate.h OperationVolumeLabelExportTable.h OperationVolumeLabelImport.h OperationVolumeMath.h OperationVolumeMerge.h OperationVolumePalette.h OperationVolumeReorient.h OperationVolumeSetSpace.h OperationVolumeStats.h OperationVolumeWeightedStats.h OperationWbsparseMergeDense.h OperationZipSceneFile.h OperationZipSpecFile.h OperationAddToSpecFile.cxx OperationBackendAverageDenseROI.cxx OperationBackendAverageROICorrelation.cxx OperationBorderExportColorTable.cxx OperationBorderFileExportToCaret5.cxx OperationBorderLength.cxx OperationBorderMerge.cxx OperationCiftiChangeMapping.cxx OperationCiftiChangeTimestep.cxx OperationCiftiConvert.cxx OperationCiftiConvertToScalar.cxx OperationCiftiCopyMapping.cxx OperationCiftiCreateDenseFromTemplate.cxx OperationCiftiCreateParcellatedFromTemplate.cxx OperationCiftiCreateScalarSeries.cxx OperationCiftiEstimateFWHM.cxx OperationCiftiExportDenseMapping.cxx OperationCiftiLabelExportTable.cxx OperationCiftiLabelImport.cxx OperationCiftiMath.cxx OperationCiftiMerge.cxx OperationCiftiPalette.cxx OperationCiftiResampleDconnMemory.cxx OperationCiftiROIAverage.cxx OperationCiftiSeparateAll.cxx OperationCiftiStats.cxx OperationCiftiWeightedStats.cxx OperationConvertAffine.cxx OperationConvertFiberOrientations.cxx OperationConvertMatrix4ToMatrix2.cxx OperationConvertMatrix4ToWorkbenchSparse.cxx OperationConvertWarpfield.cxx OperationException.cxx OperationEstimateFiberBinghams.cxx OperationFileConvert.cxx OperationFileInformation.cxx OperationFociCreate.cxx OperationFociGetProjectionVertex.cxx OperationFociListCoords.cxx OperationGiftiConvert.cxx OperationLabelExportTable.cxx OperationLabelMask.cxx OperationLabelMerge.cxx OperationMetadataRemoveProvenance.cxx OperationMetadataStringReplace.cxx OperationMetricConvert.cxx OperationMetricLabelImport.cxx OperationMetricMask.cxx OperationMetricMath.cxx OperationMetricMerge.cxx OperationMetricPalette.cxx OperationMetricStats.cxx OperationMetricVertexSum.cxx OperationMetricWeightedStats.cxx OperationNiftiInformation.cxx OperationProbtrackXDotConvert.cxx OperationSceneFileMerge.cxx OperationSceneFileRelocate.cxx OperationSetMapName.cxx OperationSetMapNames.cxx OperationSetStructure.cxx OperationShowScene.cxx OperationSpecFileMerge.cxx OperationSpecFileRelocate.cxx OperationSurfaceClosestVertex.cxx OperationSurfaceCoordinatesToMetric.cxx OperationSurfaceCutResample.cxx OperationSurfaceFlipNormals.cxx OperationSurfaceGeodesicDistance.cxx OperationSurfaceGeodesicDistanceAllToAll.cxx OperationSurfaceGeodesicROIs.cxx OperationSurfaceInformation.cxx OperationSurfaceNormals.cxx OperationSurfaceSetCoordinates.cxx OperationSurfaceVertexAreas.cxx OperationVolumeCapturePlane.cxx OperationVolumeCopyExtensions.cxx OperationVolumeCreate.cxx OperationVolumeLabelExportTable.cxx OperationVolumeLabelImport.cxx OperationVolumeMath.cxx OperationVolumeMerge.cxx OperationVolumePalette.cxx OperationVolumeReorient.cxx OperationVolumeSetSpace.cxx OperationVolumeStats.cxx OperationVolumeWeightedStats.cxx OperationWbsparseMergeDense.cxx OperationZipSceneFile.cxx OperationZipSpecFile.cxx ) TARGET_LINK_LIBRARIES(Operations ${CARET_QT5_LINK}) # # Find Headers # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Algorithms ${CMAKE_SOURCE_DIR}/Annotations ${CMAKE_SOURCE_DIR}/Operations ${CMAKE_SOURCE_DIR}/OperationsBase ${CMAKE_SOURCE_DIR}/Brain ${CMAKE_SOURCE_DIR}/Charting ${CMAKE_SOURCE_DIR}/Palette ${CMAKE_SOURCE_DIR}/FilesBase ${CMAKE_SOURCE_DIR}/Files ${CMAKE_SOURCE_DIR}/Gifti ${CMAKE_SOURCE_DIR}/Graphics ${CMAKE_SOURCE_DIR}/Cifti ${CMAKE_SOURCE_DIR}/Nifti ${QUAZIP_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/Scenes ${CMAKE_SOURCE_DIR}/Xml ${CMAKE_SOURCE_DIR}/Common ) # # Mesa Library used by show scene command # IF (OSMESA_FOUND) ADD_DEFINITIONS(${OSMESA_DEFINITION}) INCLUDE_DIRECTORIES(${OSMESA_INCLUDE_DIRECTORY}) ENDIF (OSMESA_FOUND) connectome-workbench-1.4.2/src/Operations/OperationAddToSpecFile.cxx000066400000000000000000000063061360521144700255650ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationAddToSpecFile.h" #include "OperationException.h" #include "SpecFile.h" #include "FileInformation.h" #include using namespace caret; using namespace std; AString OperationAddToSpecFile::getCommandSwitch() { return "-add-to-spec-file"; } AString OperationAddToSpecFile::getShortDescription() { return "ADD A FILE TO A SPECIFICATION FILE"; } OperationParameters* OperationAddToSpecFile::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "specfile", "the specification file to add to"); ret->addStringParameter(2, "structure", "the structure of the data file"); ret->addStringParameter(3, "filename", "the path to the file"); AString myText = AString("The resulting spec file overwrites the existing spec file. If the spec file doesn't exist, ") + "it is created with default metadata. The structure argument must be one of the following:\n\n"; vector myStructureEnums; StructureEnum::getAllEnums(myStructureEnums); for (int i = 0; i < (int)myStructureEnums.size(); ++i) { myText += StructureEnum::toName(myStructureEnums[i]) + "\n"; } ret->setHelpText(myText); return ret; } void OperationAddToSpecFile::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); bool ok = false; AString mySpecName = myParams->getString(1);//spec file AString myStructureName = myParams->getString(2);//file structure StructureEnum::Enum myStrucure = StructureEnum::fromName(myStructureName, &ok); if (!ok) { throw OperationException("unrecognized structure type"); } AString myDataFileName = myParams->getString(3);//file path FileInformation myDataFileInfo(myDataFileName); if (!myDataFileInfo.exists()) { throw OperationException("data file not found"); } DataFileTypeEnum::Enum myType = DataFileTypeEnum::fromFileExtension(myDataFileName, &ok); if (!ok) { throw OperationException("unrecognized data file type"); } SpecFile mySpec; FileInformation mySpecInfo(mySpecName); if (mySpecInfo.exists()) { mySpec.readFile(mySpecName); } else { mySpec.setFileName(mySpecName); } mySpec.addDataFile(myType, myStrucure, myDataFileName, true, false, true); mySpec.writeFile(mySpecName); } connectome-workbench-1.4.2/src/Operations/OperationAddToSpecFile.h000066400000000000000000000026251360521144700252120ustar00rootroot00000000000000#ifndef __OPERATION_ADD_TO_SPEC_FILE_H__ #define __OPERATION_ADD_TO_SPEC_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationAddToSpecFile : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationAddToSpecFile; } #endif //__OPERATION_ADD_TO_SPEC_FILE_H__ connectome-workbench-1.4.2/src/Operations/OperationBackendAverageDenseROI.cxx000066400000000000000000000132241360521144700273270ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AString.h" #include "ByteOrderEnum.h" #include "ByteSwapping.h" #include "CaretPointer.h" #include "CiftiFile.h" #include "FileInformation.h" #include "OperationBackendAverageDenseROI.h" #include "OperationException.h" #include #include #include using namespace caret; using namespace std; AString OperationBackendAverageDenseROI::getCommandSwitch() { return "-backend-average-dense-roi"; } AString OperationBackendAverageDenseROI::getShortDescription() { return "CONNECTOME DB BACKEND COMMAND FOR CIFTI AVERAGE DENSE ROI"; } OperationParameters* OperationBackendAverageDenseROI::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "index-list", "comma separated list of cifti indexes to average"); ret->addStringParameter(2, "out-file", "file to write the average row to"); ret->setHelpText( AString("This command is probably not the one you are looking for, try -cifti-average-dense-roi. ") + "It takes the list of cifti files to average from standard input, and writes its output as little endian, " + "32-bit integer of row size followed by the row as 32-bit floats." ); return ret; } void OperationBackendAverageDenseROI::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString indexListString, outfileName; indexListString = myParams->getString(1); outfileName = myParams->getString(2); CiftiXML baseXML; bool ok = false; vector indexList; QStringList indexStrings = indexListString.split(","); int numStrings = (int)indexStrings.size(); indexList.resize(numStrings); for (int i = 0; i < numStrings; ++i) { indexList[i] = indexStrings[i].toInt(&ok); if (!ok) { throw OperationException("failed to parse '" + indexStrings[i] + "' as integer"); } if (indexList[i] < 0) { throw OperationException("negative integers are not valid cifti indexes"); } } vector > ciftiList; string myLine; while (cin.good()) { if (!getline(cin, myLine)) { break; } if (myLine == "") { continue;//skip blank lines } FileInformation ciftiFileInfo(myLine.c_str()); if (!ciftiFileInfo.exists()) { throw OperationException(AString("file does not exist: ") + myLine.c_str()); } CaretPointer tempCifti(new CiftiFile(myLine.c_str()));//can't skip parsing XML, as different arguments could be different cifti versions, which results in different dimension order ciftiList.push_back(tempCifti); } int numCifti = (int)ciftiList.size(); if (numCifti > 0) { baseXML = ciftiList[0]->getCiftiXML(); if (baseXML.getNumberOfDimensions() != 2) throw OperationException("this command currently only supports 2D cifti"); int numRows = baseXML.getDimensionLength(CiftiXML::ALONG_COLUMN); int rowSize = baseXML.getDimensionLength(CiftiXML::ALONG_ROW); vector accum(rowSize, 0.0); vector rowScratch(rowSize); for (int i = 0; i < numCifti; ++i) { if (baseXML != ciftiList[i]->getCiftiXML())//equality testing is smart, compares mapping equivalence, despite multiple ways to specify some mappings { throw OperationException("error, cifti header of file #" + AString::number(i + 1) + " doesn't match"); } for (int j = 0; j < numStrings; ++j) { if (indexList[j] >= numRows) { throw OperationException("error, cifti index outside number of rows"); } ciftiList[i]->getRow(rowScratch.data(), indexList[j]); for (int k = 0; k < rowSize; ++k) { accum[k] += rowScratch[k]; } } } for (int k = 0; k < rowSize; ++k) { rowScratch[k] = accum[k] / numCifti / numStrings; } int32_t outSize = rowSize; if (ByteOrderEnum::isSystemBigEndian()) { ByteSwapping::swapBytes(rowScratch.data(), rowSize);//beware, we are doing the byteswapping in place ByteSwapping::swapBytes(&outSize, 1); } ofstream outfile(outfileName.toLocal8Bit().constData(), ios_base::out | ios_base::binary | ios_base::trunc); if (!outfile.write((char*)&outSize, 4)) { throw OperationException("error writing output"); } if (!outfile.write((char*)rowScratch.data(), rowSize * sizeof(float))) { throw OperationException("error writing output"); } outfile.close(); } } connectome-workbench-1.4.2/src/Operations/OperationBackendAverageDenseROI.h000066400000000000000000000027131360521144700267550ustar00rootroot00000000000000#ifndef __OPERATION_BACKEND_AVERAGE_DENSE_ROI_H__ #define __OPERATION_BACKEND_AVERAGE_DENSE_ROI_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationBackendAverageDenseROI : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationBackendAverageDenseROI; } #endif //__OPERATION_BACKEND_AVERAGE_DENSE_ROI_H__ connectome-workbench-1.4.2/src/Operations/OperationBackendAverageROICorrelation.cxx000066400000000000000000000173761360521144700305660ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AString.h" #include "ByteOrderEnum.h" #include "ByteSwapping.h" #include "CaretOMP.h" #include "CaretPointer.h" #include "CiftiFile.h" #include "FileInformation.h" #include "OperationBackendAverageROICorrelation.h" #include "OperationException.h" #include #include #include using namespace caret; using namespace std; AString OperationBackendAverageROICorrelation::getCommandSwitch() { return "-backend-average-roi-correlation"; } AString OperationBackendAverageROICorrelation::getShortDescription() { return "CONNECTOME DB BACKEND COMMAND FOR CIFTI AVERAGE ROI CORRELATION"; } OperationParameters* OperationBackendAverageROICorrelation::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "index-list", "comma separated list of cifti indexes to average and then correlate"); ret->addStringParameter(2, "out-file", "file to write the average row to"); ret->setHelpText( AString("This command is probably not the one you are looking for, try -cifti-average-roi-correlation. ") + "It takes the list of cifti files to average from standard input, and writes its output as little endian, " + "32-bit integer of row size followed by the row as 32-bit floats." ); return ret; } void OperationBackendAverageROICorrelation::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString indexListString, outfileName; indexListString = myParams->getString(1); outfileName = myParams->getString(2); CiftiXML baseXML;//TODO: remove when switching to raw reading bool ok = false; vector indexList; QStringList indexStrings = indexListString.split(","); int numStrings = (int)indexStrings.size(); indexList.resize(numStrings); for (int i = 0; i < numStrings; ++i) { indexList[i] = indexStrings[i].toInt(&ok); if (!ok) { throw OperationException("failed to parse '" + indexStrings[i] + "' as integer"); } if (indexList[i] < 0) { throw OperationException("negative integers are not valid cifti indexes"); } } vector > ciftiList; string myLine; while (cin.good()) { if (!getline(cin, myLine)) { break; } if (myLine == "") { continue;//skip blank lines } FileInformation ciftiFileInfo(myLine.c_str()); if (!ciftiFileInfo.exists()) { throw OperationException(AString("file does not exist: ") + myLine.c_str()); } CaretPointer tempCifti(new CiftiFile(myLine.c_str()));//can't skip parsing XML, as different arguments could be different cifti versions, which results in different dimension order ciftiList.push_back(tempCifti); } int numCifti = (int)ciftiList.size(); if (numCifti > 0) { baseXML = ciftiList[0]->getCiftiXML(); if (baseXML.getNumberOfDimensions() != 2) throw OperationException("operation only supports 2D cifti files"); int rowSize = baseXML.getDimensionLength(CiftiXML::ALONG_ROW); vector accum(rowSize, 0.0); vector rowScratch(rowSize); for (int i = 0; i < numCifti; ++i) { if (!baseXML.approximateMatch(ciftiList[i]->getCiftiXML()))//equality testing is smart, compares mapping equivalence, despite multiple ways to specify some mappings { throw OperationException("error, cifti header of file #" + AString::number(i + 1) + " doesn't match"); } processCifti(ciftiList[i], indexList, rowScratch); for (int k = 0; k < rowSize; ++k) { accum[k] += rowScratch[k]; } } for (int k = 0; k < rowSize; ++k) { rowScratch[k] = accum[k] / numCifti / numStrings; } int32_t outSize = rowSize; if (ByteOrderEnum::isSystemBigEndian()) { ByteSwapping::swapBytes(rowScratch.data(), rowSize);//beware, we are doing the byteswapping in place ByteSwapping::swapBytes(&outSize, 1); } ofstream outfile(outfileName.toLocal8Bit().constData(), ios_base::out | ios_base::binary | ios_base::trunc); if (!outfile.write((char*)&outSize, 4)) { throw OperationException("error writing output"); } if (!outfile.write((char*)rowScratch.data(), rowSize * sizeof(float))) { throw OperationException("error writing output"); } outfile.close(); } } void OperationBackendAverageROICorrelation::processCifti(const CiftiFile* myCifti, const vector& indexList, vector& output) { int rowSize = myCifti->getNumberOfColumns(); int colSize = myCifti->getNumberOfRows(); int listSize = (int)indexList.size(); vector accumarray(rowSize, 0.0); vector average(rowSize); for (int i = 0; i < listSize; ++i) { if (indexList[i] >= colSize)//we already checked for negatives { throw OperationException("cifti index too large"); } myCifti->getRow(average.data(), indexList[i]); for (int j = 0; j < rowSize; ++j) { accumarray[j] += average[j]; } } double accum = 0.0; for (int i = 0; i < rowSize; ++i) { average[i] = accumarray[i] / listSize; accum += average[i]; } float mean = accum / rowSize; accum = 0.0; for (int i = 0; i < rowSize; ++i) { average[i] -= mean; accum += average[i] * average[i]; } float rrs = sqrt(accum); int curRow = 0; #pragma omp CARET_PAR { vector rowscratch(rowSize); #pragma omp CARET_FOR schedule(dynamic) for (int i = 0; i < colSize; ++i) { int myRow; #pragma omp critical { myRow = curRow;//force sequential reading ++curRow; myCifti->getRow(rowscratch.data(), myRow);//but never read multiple rows at once from the same file } double tempaccum = 0.0;//compute mean of new row for (int j = 0; j < rowSize; ++j) { tempaccum += rowscratch[j]; } float thismean = tempaccum / rowSize; tempaccum = 0.0; double corraccum = 0.0;//correlate for (int j = 0; j < rowSize; ++j) { float tempf = rowscratch[j] - thismean; tempaccum += tempf * tempf;//compute rrs on the fly corraccum += tempf * average[j];//gather the correlation } corraccum /= rrs * sqrt(tempaccum); if (corraccum > 0.999999) corraccum = 0.999999; if (corraccum < -0.999999) corraccum = -0.999999; output[i] = 0.5 * log((1 + corraccum) / (1 - corraccum)); } } } connectome-workbench-1.4.2/src/Operations/OperationBackendAverageROICorrelation.h000066400000000000000000000031751360521144700302030ustar00rootroot00000000000000#ifndef __OPERATION_BACKEND_AVERAGE_ROI_CORRELATION_H__ #define __OPERATION_BACKEND_AVERAGE_ROI_CORRELATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" #include namespace caret { class OperationBackendAverageROICorrelation : public AbstractOperation { static void processCifti(const CiftiFile* myCifti, const std::vector& indexList, std::vector& output); public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationBackendAverageROICorrelation; } #endif //__OPERATION_BACKEND_AVERAGE_ROI_CORRELATION_H__ connectome-workbench-1.4.2/src/Operations/OperationBorderExportColorTable.cxx000066400000000000000000000076001360521144700275430ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationBorderExportColorTable.h" #include "OperationException.h" #include "Border.h" #include "BorderFile.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include #include using namespace caret; using namespace std; AString OperationBorderExportColorTable::getCommandSwitch() { return "-border-export-color-table"; } AString OperationBorderExportColorTable::getShortDescription() { return "WRITE BORDER NAMES AND COLORS AS TEXT"; } OperationParameters* OperationBorderExportColorTable::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addBorderParameter(1, "border-file", "the input border file"); ret->addStringParameter(2, "table-out", "output - the output text file");//fake output formatting ret->createOptionalParameter(3, "-class-colors", "use class colors instead of the name colors"); ret->setHelpText( AString("Takes the names and colors of each border, and writes it to the same format as -metric-label-import expects. ") + "By default, the borders are colored by border name, specify -class-colors to color them by class instead. " + "The key values start at 1 and follow the order of the borders in the file." ); return ret; } int OperationBorderExportColorTable::floatTo255(const float& in) { return (int)floor(in * 255.0f + 0.5f); } void OperationBorderExportColorTable::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); BorderFile* myFile = myParams->getBorder(1); AString outfileName = myParams->getString(2); bool useClassColors = myParams->getOptionalParameter(3)->m_present; ofstream outFile(outfileName.toLocal8Bit().constData()); if (!outFile) throw OperationException("failed to open output text file"); const GiftiLabelTable* tempTable = NULL; if (useClassColors) { tempTable = myFile->getClassColorTable(); } else { tempTable = myFile->getNameColorTable(); } int numBorders = myFile->getNumberOfBorders(); for (int i = 0; i < numBorders; ++i) { const Border* thisBorder = myFile->getBorder(i); outFile << thisBorder->getName() << endl; outFile << i + 1 << " ";//NOTE: NEVER use the label key const GiftiLabel* tempLabel = NULL; if (useClassColors) { tempLabel = tempTable->getLabelBestMatching(thisBorder->getClassName());//see BrainOpenGLFixedPipeline::drawSurfaceBorders(Surface* surface) } else { tempLabel = tempTable->getLabelBestMatching(thisBorder->getName()); } if (tempLabel == NULL) { outFile << "0 0 0 255" << endl; } else { outFile << floatTo255(tempLabel->getRed()) << " " << floatTo255(tempLabel->getGreen()) << " " << floatTo255(tempLabel->getBlue()) << " " << floatTo255(tempLabel->getAlpha()) << endl; } if (!outFile) throw OperationException("error writing to output text file"); } } connectome-workbench-1.4.2/src/Operations/OperationBorderExportColorTable.h000066400000000000000000000027731360521144700271760ustar00rootroot00000000000000#ifndef __OPERATION_BORDER_EXPORT_COLOR_TABLE_H__ #define __OPERATION_BORDER_EXPORT_COLOR_TABLE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationBorderExportColorTable : public AbstractOperation { static int floatTo255(const float& in); public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationBorderExportColorTable; } #endif //__OPERATION_BORDER_EXPORT_COLOR_TABLE_H__ connectome-workbench-1.4.2/src/Operations/OperationBorderFileExportToCaret5.cxx000066400000000000000000000125131360521144700277420ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "CaretLogger.h" #include "BorderFile.h" #include "DataFileException.h" #include "FileInformation.h" #include "OperationBorderFileExportToCaret5.h" #include "OperationException.h" #include "SurfaceFile.h" using namespace caret; /** * \class caret::OperationBorderFileExportToCaret5 * \brief Export border file to Caret5 file format */ /** * @return Command line switch */ AString OperationBorderFileExportToCaret5::getCommandSwitch() { return "-border-file-export-to-caret5"; } /** * @return Short description of operation */ AString OperationBorderFileExportToCaret5::getShortDescription() { return "EXPORT BORDER FILE TO CARET5 FILE FORMAT"; } /** * @return Parameters for operation */ OperationParameters* OperationBorderFileExportToCaret5::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "border-file", "workbench border file"); ret->addStringParameter(2, "output-file-prefix", "prefix for name of output caret5 border/borderproj/bordercolor files"); ParameterComponent* surfaceOpt = ret->createRepeatableParameter(3, "-surface", "specify an input surface"); surfaceOpt->addSurfaceParameter(1, "surface-in", "a surface file for unprojection of borders"); AString helpText("A Workbench border file may contain borders for multiple " "structures and borders that are both projected and " "unprojected. It also contains a color table for the borders. " "\n" "\n" "Caret5 has both border (unprojected) and border projection " "(projected) files. In addition, each Caret5 border or border " "projection file typically contains data for a single structure. " "Caret5 also uses a border color file that associates colors with " "the names of the borders. " "\n" "\n" "This command will try to output both Caret5 border and " "border projection files. Each output border/border projection " "file will contains data for one structure so there may be " "many files created. The structure name is included in the name of " "each border or border projection file that is created. " "\n" "\n" "One Caret5 border color file will also be produced by this " "command. " "\n" "\n" "Providing surface(s) as input parameters is optional, but recommended. " "Surfaces may be needed to create both projected and/or unprojected coordinates " "of borders. If there is a failure to produce an output border or " "border projection due to a missing surface with the matching structure, " "an error message will be displayed and some " "output files will not be created. " "\n" "\n" "When writing new files, this command will overwrite a file " "with the same name. " ""); ret->setHelpText(helpText); return ret; } /** * Use Parameters and perform operation */ void OperationBorderFileExportToCaret5::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString borderFileName = FileInformation(myParams->getString(1)).getAbsoluteFilePath(); AString outputCaret5FilePrefix = FileInformation(myParams->getString(2)).getAbsoluteFilePath(); std::vector allSurfaces; const std::vector& surfaceInputs = *(myParams->getRepeatableParameterInstances(3)); const int32_t numSurfaceInputs = static_cast(surfaceInputs.size()); for (int32_t iSurf = 0; iSurf < numSurfaceInputs; iSurf++) { SurfaceFile* sf = surfaceInputs[iSurf]->getSurface(1); allSurfaces.push_back(sf); } try { BorderFile borderFile; borderFile.readFile(borderFileName); borderFile.exportToCaret5Format(allSurfaces, outputCaret5FilePrefix); } catch (const DataFileException& dfe) { throw OperationException(dfe); } } connectome-workbench-1.4.2/src/Operations/OperationBorderFileExportToCaret5.h000066400000000000000000000030111360521144700273600ustar00rootroot00000000000000#ifndef __OPERATION_BORDER_FILE_EXPORT_TO_CARET5_H__ #define __OPERATION_BORDER_FILE_EXPORT_TO_CARET5_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationBorderFileExportToCaret5 : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationBorderFileExportToCaret5; } // namespace #endif //__OPERATION_BORDER_FILE_EXPORT_TO_CARET5_H__ connectome-workbench-1.4.2/src/Operations/OperationBorderLength.cxx000066400000000000000000000106251360521144700255350ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationBorderLength.h" #include "OperationException.h" #include "BorderFile.h" #include "BorderLengthHelper.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "Border.h" #include using namespace caret; using namespace std; AString OperationBorderLength::getCommandSwitch() { return "-border-length"; } AString OperationBorderLength::getShortDescription() { return "REPORT LENGTH OF BORDERS"; } OperationParameters* OperationBorderLength::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addBorderParameter(1, "border", "the input border file"); ret->addSurfaceParameter(2, "surface", "the surface to measure the borders on"); OptionalParameter* corrAreasOpt = ret->createOptionalParameter(3, "-corrected-areas", "vertex areas to use instead of computing them from the surface"); corrAreasOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); ret->createOptionalParameter(4, "-separate-pieces", "report lengths for multi-part borders as separate numbers"); ret->createOptionalParameter(5, "-hide-border-name", "don't print border name before each output"); ret->setHelpText( AString("For each border, print its length along the surface, in mm. ") + "If a border has multiple parts, their lengths are summed before printing, unless -separate-pieces is specified.\n\n" + "The -corrected-areas option is intended for when the length is not meaningfully measurable on individual surfaces, " + "it is only an approximate correction for the reduction in structure of a group average surface." ); return ret; } void OperationBorderLength::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); BorderFile* myBorderFile = myParams->getBorder(1); SurfaceFile* mySurface = myParams->getSurface(2); MetricFile* corrAreas = NULL; const float* corrAreaData = NULL; OptionalParameter* corrAreasOpt = myParams->getOptionalParameter(3); if (corrAreasOpt->m_present) { corrAreas = corrAreasOpt->getMetric(1); corrAreaData = corrAreas->getValuePointerForColumn(0); } bool separate = myParams->getOptionalParameter(4)->m_present; bool hideNames = myParams->getOptionalParameter(5)->m_present; checkStructureMatch(myBorderFile, mySurface->getStructure(), "border file", "surface file has"); checkStructureMatch(corrAreas, mySurface->getStructure(), "corrected areas metric", "surface file has"); BorderMultiPartHelper myMultiHelper(myBorderFile); BorderLengthHelper myLengthHelper(mySurface, corrAreaData); int numBorders = (int)myMultiHelper.borderPieceList.size(); for (int i = 0; i < numBorders; ++i) { if (!hideNames) { cout << myBorderFile->getBorder(myMultiHelper.borderPieceList[i][0])->getName() << ": "; } int numParts = (int)myMultiHelper.borderPieceList[i].size(); if (separate) { for (int j = 0; j < numParts; ++j) { if (j > 0) { cout << " "; } cout << myLengthHelper.length(myBorderFile->getBorder(myMultiHelper.borderPieceList[i][j])); } } else { float total = 0.0f; for (int j = 0; j < numParts; ++j) { total += myLengthHelper.length(myBorderFile->getBorder(myMultiHelper.borderPieceList[i][j])); } cout << total; } cout << endl; } } connectome-workbench-1.4.2/src/Operations/OperationBorderLength.h000066400000000000000000000026111360521144700251560ustar00rootroot00000000000000#ifndef __OPERATION_BORDER_LENGTH_H__ #define __OPERATION_BORDER_LENGTH_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationBorderLength : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationBorderLength; } #endif //__OPERATION_BORDER_LENGTH_H__ connectome-workbench-1.4.2/src/Operations/OperationBorderMerge.cxx000066400000000000000000000146641360521144700253620ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationBorderMerge.h" #include "OperationException.h" #include "Border.h" #include "BorderFile.h" #include "GiftiLabelTable.h" #include #include #include using namespace caret; using namespace std; AString OperationBorderMerge::getCommandSwitch() { return "-border-merge"; } AString OperationBorderMerge::getShortDescription() { return "MERGE BORDER FILES INTO A NEW FILE"; } OperationParameters* OperationBorderMerge::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addBorderOutputParameter(1, "border-file-out", "the output border file"); ParameterComponent* borderOpt = ret->createRepeatableParameter(2, "-border", "specify an input border file"); borderOpt->addBorderParameter(1, "border-file-in", "a border file to use borders from"); ParameterComponent* selectOpt = borderOpt->createRepeatableParameter(2, "-select", "select a single border to use"); selectOpt->addStringParameter(1, "border", "the border number or name"); OptionalParameter* upToOpt = selectOpt->createOptionalParameter(2, "-up-to", "use an inclusive range of borders"); upToOpt->addStringParameter(1, "last-border", "the number or name of the last column to include"); upToOpt->createOptionalParameter(2, "-reverse", "use the range in reverse order"); ret->setHelpText( AString("Takes one or more border files and makes a new border file from the borders in them.\n\n") + "Example: wb_command -border-merge out.border -border first.border -select 1 -border second.border\n\n" + "This example would take the first border from first.border, followed by all borders from second.border, " + "and write these to out.border." ); return ret; } void OperationBorderMerge::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); BorderFile* outFile = myParams->getOutputBorder(1); const vector& borderInst = *(myParams->getRepeatableParameterInstances(2)); int numInputs = (int)borderInst.size(); if (numInputs < 1) throw OperationException("no inputs specified"); for (int i = 0; i < numInputs; ++i) { BorderFile* input = borderInst[i]->getBorder(1); if (i != 0)//structure automatically gets set on empty file by added borders { if (outFile->getStructure() != input->getStructure()) throw OperationException("input files have different structures"); } if (input->getNumberOfNodes() != -1) { int outNodes = outFile->getNumberOfNodes(); if (outNodes != -1) { if (outNodes != input->getNumberOfNodes()) throw OperationException("input files have different number of surface vertices"); } else { outFile->setNumberOfNodes(input->getNumberOfNodes()); } } outFile->getClassColorTable()->append(*(input->getClassColorTable()));//let the append logic deal with conflicts outFile->getNameColorTable()->append(*(input->getNameColorTable()));//we don't need the return values, as the numbers in the label tables are meaningless int numBorderParts = input->getNumberOfBorders(); const vector& selectOpts = *(borderInst[i]->getRepeatableParameterInstances(2)); int numSelectOpts = (int)selectOpts.size(); if (numSelectOpts > 0) { BorderMultiPartHelper myHelp(input); for (int j = 0; j < numSelectOpts; ++j) { int initialBorder = myHelp.fromNumberOrName(selectOpts[j]->getString(1)); if (initialBorder < 0) throw OperationException("border '" + selectOpts[j]->getString(1) + "' not found in file '" + input->getFileName() + "'"); OptionalParameter* upToOpt = selectOpts[j]->getOptionalParameter(2); if (upToOpt->m_present) { int finalBorder = myHelp.fromNumberOrName(upToOpt->getString(1)); if (finalBorder < 0) throw OperationException("ending border '" + selectOpts[j]->getString(1) + "' not found in file '" + input->getFileName() + "'"); bool reverse = upToOpt->getOptionalParameter(2)->m_present; if (reverse) { for (int b = finalBorder; b >= initialBorder; --b) { for (int k = 0; k < (int)myHelp.borderPieceList[b].size(); ++k) { outFile->addBorder(new Border(*(input->getBorder(myHelp.borderPieceList[b][k])))); } } } else { for (int b = initialBorder; b <= finalBorder; ++b) { for (int k = 0; k < (int)myHelp.borderPieceList[b].size(); ++k) { outFile->addBorder(new Border(*(input->getBorder(myHelp.borderPieceList[b][k])))); } } } } else { for (int k = 0; k < (int)myHelp.borderPieceList[initialBorder].size(); ++k) { outFile->addBorder(new Border(*(input->getBorder(myHelp.borderPieceList[initialBorder][k])))); } } } } else { for (int j = 0; j < numBorderParts; ++j) { outFile->addBorder(new Border(*(input->getBorder(j)))); } } } } connectome-workbench-1.4.2/src/Operations/OperationBorderMerge.h000066400000000000000000000026031360521144700247750ustar00rootroot00000000000000#ifndef __OPERATION_BORDER_MERGE_H__ #define __OPERATION_BORDER_MERGE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationBorderMerge : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationBorderMerge; } #endif //__OPERATION_BORDER_MERGE_H__ connectome-workbench-1.4.2/src/Operations/OperationCiftiChangeMapping.cxx000066400000000000000000000175401360521144700266410ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationCiftiChangeMapping.h" #include "OperationException.h" #include "CaretLogger.h" #include "CiftiFile.h" #include "FileInformation.h" #include "MultiDimIterator.h" #include using namespace caret; using namespace std; AString OperationCiftiChangeMapping::getCommandSwitch() { return "-cifti-change-mapping"; } AString OperationCiftiChangeMapping::getShortDescription() { return "CONVERT TO SCALAR, COPY MAPPING, ETC"; } OperationParameters* OperationCiftiChangeMapping::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "data-cifti", "the cifti file to use the data from"); ret->addStringParameter(2, "direction", "which direction on to replace the mapping"); ret->addCiftiOutputParameter(3, "cifti-out", "the output cifti file"); OptionalParameter* seriesOpt = ret->createOptionalParameter(4, "-series", "set the mapping to series"); seriesOpt->addDoubleParameter(1, "step", "increment between series points");//this is the order in -cifti-create-from-template, roll with it seriesOpt->addDoubleParameter(2, "start", "start value of the series"); OptionalParameter* seriesUnitOpt = seriesOpt->createOptionalParameter(3, "-unit", "select unit for series (default SECOND)"); seriesUnitOpt->addStringParameter(1, "unit", "unit identifier"); OptionalParameter* scalarOpt = ret->createOptionalParameter(5, "-scalar", "set the mapping to scalar"); OptionalParameter* scalarNameFileOpt = scalarOpt->createOptionalParameter(1, "-name-file", "specify names for the maps"); scalarNameFileOpt->addStringParameter(1, "file", "text file containing map names, one per line"); OptionalParameter* fromCiftiOpt = ret->createOptionalParameter(6, "-from-cifti", "copy mapping from another cifti file"); fromCiftiOpt->addCiftiParameter(1, "template-cifti", "a cifti file containing the desired mapping"); fromCiftiOpt->addStringParameter(2, "direction", "which direction to copy the mapping from"); AString helpText = AString("Take an existing cifti file and change one of the mappings. ") + "Exactly one of -series, -scalar, or -from-cifti must be specified. " + CiftiXML::directionFromStringExplanation(); helpText += "\n\nThe argument to -unit must be one of the following:\n"; vector unitList = CiftiSeriesMap::getAllUnits(); for (int i = 0; i < (int)unitList.size(); ++i) { helpText += "\n" + CiftiSeriesMap::unitToString(unitList[i]); } ret->setHelpText(helpText); return ret; } void OperationCiftiChangeMapping::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); const CiftiFile* inputCifti = myParams->getCifti(1); AString dirString = myParams->getString(2); CiftiFile* outputCifti = myParams->getOutputCifti(3); int direction = CiftiXML::directionFromString(dirString); CiftiXML outXML = inputCifti->getCiftiXML(); if (direction >= outXML.getNumberOfDimensions()) { throw OperationException("specified direction does not exist in file"); } bool haveOption = false; OptionalParameter* seriesOpt = myParams->getOptionalParameter(4); if (seriesOpt->m_present) { haveOption = true; CiftiSeriesMap newMap(outXML.getDimensionLength(direction), seriesOpt->getDouble(2), seriesOpt->getDouble(1)); OptionalParameter* seriesUnitOpt = seriesOpt->getOptionalParameter(3); if (seriesUnitOpt->m_present) { bool ok = false; CiftiSeriesMap::Unit myUnit = CiftiSeriesMap::stringToUnit(seriesUnitOpt->getString(1), ok); if (!ok) { throw OperationException("unrecognized string for unit: '" + seriesUnitOpt->getString(1) + "'"); } newMap.setUnit(myUnit); } outXML.setMap(direction, newMap); } OptionalParameter* scalarOpt = myParams->getOptionalParameter(5); if (scalarOpt->m_present) { if (haveOption) { throw OperationException("only one of -series, -scalar, or -from-cifti may be specified"); } haveOption = true; CiftiScalarsMap newMap(outXML.getDimensionLength(direction)); OptionalParameter* scalarNameFileOpt = scalarOpt->getOptionalParameter(1); if (scalarNameFileOpt->m_present) { AString listfileName = scalarNameFileOpt->getString(1); FileInformation textFileInfo(listfileName); if (!textFileInfo.exists()) { throw OperationException("name list file doesn't exist"); } fstream nameListFile(listfileName.toLocal8Bit().constData(), fstream::in); if (!nameListFile.good()) { throw OperationException("error reading name list file"); } string mapName; for (int i = 0; i < newMap.getLength(); ++i) { getline(nameListFile, mapName); if (!nameListFile)//no, seriously, that is how you check if your input was good { CaretLogWarning("name file contained " + AString::number(i) + " names, expected " + AString::number(newMap.getLength())); break; } newMap.setMapName(i, mapName.c_str()); } } outXML.setMap(direction, newMap); } OptionalParameter* fromCiftiOpt = myParams->getOptionalParameter(6); if (fromCiftiOpt->m_present) { if (haveOption) { throw OperationException("only one of -series, -scalar, or -from-cifti may be specified"); } haveOption = true; const CiftiFile* templateCifti = fromCiftiOpt->getCifti(1); const CiftiXML& templateXML = templateCifti->getCiftiXML(); AString tempDirString = fromCiftiOpt->getString(2); int templateDir = CiftiXML::directionFromString(tempDirString); if (templateDir >= templateXML.getNumberOfDimensions()) { throw OperationException("specified direction does not exist in file"); } if (templateXML.getDimensionLength(templateDir) != outXML.getDimensionLength(direction)) { throw OperationException("selected direction on has different length than selected direction on "); } outXML.setMap(direction, *(templateXML.getMap(templateDir))); } if (!haveOption) { throw OperationException("you must specify one of -series, -scalar, or -from-cifti"); } outputCifti->setCiftiXML(outXML); vector outDims = outXML.getDimensions(); vector scratchrow(outDims[0]); for (MultiDimIterator iter(vector(outDims.begin() + 1, outDims.end())); !iter.atEnd(); ++iter) {//drop the first dimension, row length inputCifti->getRow(scratchrow.data(), *iter); outputCifti->setRow(scratchrow.data(), *iter); } } connectome-workbench-1.4.2/src/Operations/OperationCiftiChangeMapping.h000066400000000000000000000026601360521144700262630ustar00rootroot00000000000000#ifndef __OPERATION_CIFTI_CHANGE_MAPPING_H__ #define __OPERATION_CIFTI_CHANGE_MAPPING_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationCiftiChangeMapping : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationCiftiChangeMapping; } #endif //__OPERATION_CIFTI_CHANGE_MAPPING_H__ connectome-workbench-1.4.2/src/Operations/OperationCiftiChangeTimestep.cxx000066400000000000000000000107061360521144700270350ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationCiftiChangeTimestep.h" #include "OperationException.h" #include "CiftiFile.h" #include "CaretLogger.h" #include "MultiDimIterator.h" using namespace caret; using namespace std; AString OperationCiftiChangeTimestep::getCommandSwitch() { return "-cifti-change-timestep"; } AString OperationCiftiChangeTimestep::getShortDescription() { return "DEPRECATED: use -cifti-change-mapping"; } OperationParameters* OperationCiftiChangeTimestep::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "cifti", "the cifti file to modify"); OptionalParameter* rowTimestep = ret->createOptionalParameter(2, "-row-timestep", "set the timestep along rows"); rowTimestep->addDoubleParameter(1, "seconds", "seconds per timestep"); OptionalParameter* columnTimestep = ret->createOptionalParameter(3, "-column-timestep", "set the timestep along columns"); columnTimestep->addDoubleParameter(1, "seconds", "seconds per timestep"); ret->setHelpText( AString("DEPRECATED: this command may be removed in a future release, use -cifti-change-mapping.\n\n") + "Warns if a dimension specified is not timepoints, otherwise modifies the timestep, and finally writes the result to " + "the same filename if any dimensions were modified.\nNOTE: you probably want -row-timestep, as that matches the .dtseries.nii specification. " + "The other option is available just for completeness." ); return ret; } void OperationCiftiChangeTimestep::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString ciftiName = myParams->getString(1); OptionalParameter* rowTimestep = myParams->getOptionalParameter(2); OptionalParameter* columnTimestep = myParams->getOptionalParameter(3); if (!columnTimestep->m_present && !rowTimestep->m_present) { return; } CiftiFile myCifti; myCifti.openFile(ciftiName); CiftiXML tempXML = myCifti.getCiftiXML(); bool modified = false; if (rowTimestep->m_present) { float step = (float)rowTimestep->getDouble(1); if (tempXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::SERIES) { CiftiSeriesMap& myMap = tempXML.getSeriesMap(CiftiXML::ALONG_ROW); myMap.setStep(step);//TSC: leave units as-is, I guess modified = true; } else { CaretLogWarning("could not set row timestep"); } } if (columnTimestep->m_present) { float step = (float)columnTimestep->getDouble(1); if (tempXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::SERIES) { CiftiSeriesMap& myMap = tempXML.getSeriesMap(CiftiXML::ALONG_COLUMN); myMap.setStep(step);//TSC: leave units as-is, I guess modified = true; } else { CaretLogWarning("could not set row timestep"); } } if (modified) { myCifti.convertToInMemory();//because we are overwriting the input file CiftiFile outCifti; outCifti.setWritingFile(ciftiName);//starts on-disk writing outCifti.setCiftiXML(tempXML); const vector& dims = myCifti.getDimensions(); vector extraDims(dims.begin() + 1, dims.end()); vector scratchrow(dims[0]); for (MultiDimIterator iter(extraDims); !iter.atEnd(); ++iter) { myCifti.getRow(scratchrow.data(), *iter); outCifti.setRow(scratchrow.data(), *iter); } outCifti.writeFile(ciftiName);//superfluous, unless we aren't writing on-disk } } connectome-workbench-1.4.2/src/Operations/OperationCiftiChangeTimestep.h000066400000000000000000000026661360521144700264700ustar00rootroot00000000000000#ifndef __OPERATION_CIFTI_CHANGE_TIMESTEP_H__ #define __OPERATION_CIFTI_CHANGE_TIMESTEP_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationCiftiChangeTimestep : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationCiftiChangeTimestep; } #endif //__OPERATION_CIFTI_CHANGE_TIMESTEP_H__ connectome-workbench-1.4.2/src/Operations/OperationCiftiConvert.cxx000066400000000000000000000734711360521144700255650ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationCiftiConvert.h" #include "OperationException.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretPointer.h" #include "CiftiFile.h" #include "CiftiXML.h" #include "FloatMatrix.h" #include "GiftiFile.h" #include "VolumeFile.h" #include #include #include #include #include #include #include using namespace caret; using namespace std; AString OperationCiftiConvert::getCommandSwitch() { return "-cifti-convert"; } AString OperationCiftiConvert::getShortDescription() { return "DUMP CIFTI MATRIX INTO OTHER FORMATS"; } OperationParameters* OperationCiftiConvert::getParameters() { OperationParameters* ret = new OperationParameters(); OptionalParameter* toGiftiExt = ret->createOptionalParameter(1, "-to-gifti-ext", "convert to GIFTI external binary"); toGiftiExt->addCiftiParameter(1, "cifti-in", "the input cifti file"); toGiftiExt->addStringParameter(2, "gifti-out", "output - the output gifti file"); OptionalParameter* fromGiftiExt = ret->createOptionalParameter(2, "-from-gifti-ext", "convert a GIFTI made with this command back into a CIFTI"); fromGiftiExt->addStringParameter(1, "gifti-in", "the input gifti file"); fromGiftiExt->addCiftiOutputParameter(2, "cifti-out", "the output cifti file"); OptionalParameter* fgresetTimeOpt = fromGiftiExt->createOptionalParameter(3, "-reset-timepoints", "reset the mapping along rows to timepoints, taking length from the gifti file"); fgresetTimeOpt->addDoubleParameter(1, "timestep", "the desired time between frames"); fgresetTimeOpt->addDoubleParameter(2, "timestart", "the desired time offset of the initial frame"); OptionalParameter* fgresetTimeunitsOpt = fgresetTimeOpt->createOptionalParameter(3, "-unit", "use a unit other than time"); fgresetTimeunitsOpt->addStringParameter(1, "unit", "unit identifier (default SECOND)"); fromGiftiExt->createOptionalParameter(4, "-reset-scalars", "reset mapping along rows to scalars, taking length from the gifti file"); fromGiftiExt->createOptionalParameter(6, "-column-reset-scalars", "reset mapping along columns to scalar (useful for changing number of series in a sdseries file)"); OptionalParameter* fromGiftiReplace = fromGiftiExt->createOptionalParameter(5, "-replace-binary", "replace data with a binary file"); fromGiftiReplace->addStringParameter(1, "binary-in", "the binary file that contains replacement data"); fromGiftiReplace->createOptionalParameter(2, "-flip-endian", "byteswap the binary file"); fromGiftiReplace->createOptionalParameter(3, "-transpose", "transpose the binary file"); OptionalParameter* toNifti = ret->createOptionalParameter(3, "-to-nifti", "convert to NIFTI1"); toNifti->addCiftiParameter(1, "cifti-in", "the input cifti file"); toNifti->addVolumeOutputParameter(2, "nifti-out", "the output nifti file"); toNifti->createOptionalParameter(3, "-smaller-file", "use better-fitting dimension lengths"); toNifti->createOptionalParameter(4, "-smaller-dims", "minimize the largest dimension, for tools that don't like large indices"); OptionalParameter* fromNifti = ret->createOptionalParameter(4, "-from-nifti", "convert a NIFTI (1 or 2) file made with this command back into CIFTI"); fromNifti->addVolumeParameter(1, "nifti-in", "the input nifti file"); fromNifti->addCiftiParameter(2, "cifti-template", "a cifti file with the dimension(s) and mapping(s) that should be used"); fromNifti->addCiftiOutputParameter(3, "cifti-out", "the output cifti file"); OptionalParameter* fnresetTimeOpt = fromNifti->createOptionalParameter(4, "-reset-timepoints", "reset the mapping along rows to timepoints, taking length from the nifti file"); fnresetTimeOpt->addDoubleParameter(1, "timestep", "the desired time between frames"); fnresetTimeOpt->addDoubleParameter(2, "timestart", "the desired time offset of the initial frame"); OptionalParameter* fnresetTimeunitsOpt = fnresetTimeOpt->createOptionalParameter(3, "-unit", "use a unit other than time"); fnresetTimeunitsOpt->addStringParameter(1, "unit", "unit identifier (default SECOND)"); fromNifti->createOptionalParameter(5, "-reset-scalars", "reset mapping along rows to scalars, taking length from the nifti file"); OptionalParameter* toText = ret->createOptionalParameter(5, "-to-text", "convert to a plain text file"); toText->addCiftiParameter(1, "cifti-in", "the input cifti file"); toText->addStringParameter(2, "text-out", "output - the output text file"); OptionalParameter* toTextColDelimOpt = toText->createOptionalParameter(3, "-col-delim", "choose string to put between elements in a row"); toTextColDelimOpt->addStringParameter(1, "delim-string", "the string to use (default is a tab character)"); OptionalParameter* fromText = ret->createOptionalParameter(6, "-from-text", "convert from plain text to cifti"); fromText->addStringParameter(1, "text-in", "the input text file"); fromText->addCiftiParameter(2, "cifti-template", "a cifti file with the dimension(s) and mapping(s) that should be used"); fromText->addCiftiOutputParameter(3, "cifti-out", "the output cifti file"); OptionalParameter* fromTextColDelimOpt = fromText->createOptionalParameter(4, "-col-delim", "specify string that is between elements in a row"); fromTextColDelimOpt->addStringParameter(1, "delim-string", "the string to use (default is any whitespace)"); OptionalParameter* ftresetTimeOpt = fromText->createOptionalParameter(5, "-reset-timepoints", "reset the mapping along rows to timepoints, taking length from the text file"); ftresetTimeOpt->addDoubleParameter(1, "timestep", "the desired time between frames"); ftresetTimeOpt->addDoubleParameter(2, "timestart", "the desired time offset of the initial frame"); OptionalParameter* ftresetTimeunitsOpt = ftresetTimeOpt->createOptionalParameter(3, "-unit", "use a unit other than time"); ftresetTimeunitsOpt->addStringParameter(1, "unit", "unit identifier (default SECOND)"); fromText->createOptionalParameter(6, "-reset-scalars", "reset mapping along rows to scalars, taking length from the text file"); AString myText = AString("This command is used to convert a full CIFTI matrix to/from formats that can be used by programs that don't understand CIFTI. ") + "You must specify exactly one of -to-gifti-ext, -from-gifti-ext, -to-nifti, -from-nifti, -to-text, or -from-text.\n\n" + "If you want to write an existing CIFTI file with a different CIFTI version, see -file-convert, and its -cifti-version-convert option.\n\n" + "If you want part of the CIFTI file as a metric, label, or volume file, see -cifti-separate. " + "If you want to create a CIFTI file from metric and/or volume files, see the -cifti-create-* commands.\n\n" + "If you want to import a matrix that is restricted to an ROI, first create a template CIFTI file matching that ROI using a -cifti-create-* command. " + "After importing to CIFTI, you can then expand the file into a standard brainordinates space with -cifti-create-dense-from-template. " + "If you want to export only part of a CIFTI file, first create an roi-restricted CIFTI file with -cifti-restrict-dense-mapping.\n\n" + "The -transpose option to -from-gifti-ext is needed if the replacement binary file is in column-major order.\n\n" + "The -unit options accept these values:\n"; vector units = CiftiSeriesMap::getAllUnits(); for (int i = 0; i < (int)units.size(); ++i) { myText += "\n" + CiftiSeriesMap::unitToString(units[i]); } ret->setHelpText(myText); return ret; } namespace { bool haveWarned = false; float toFloat(const AString& input) { bool ok = false; double converted = input.toDouble(&ok); if (!ok) throw OperationException("failed to convert text to number: '" + input + "'"); float ret = float(converted);//this will turn some non-inf values into +/- inf, so let's fix that if (!std::isinf(converted) && (abs(converted) > numeric_limits::max() || abs(converted) < numeric_limits::denorm_min())) { if (!haveWarned) { CaretLogWarning("input number(s) changed to fit range of float32, first instance: '" + input + "'"); haveWarned = true; } if (std::isinf(ret)) { if (ret > 0.0f) { ret = numeric_limits::max(); } else { ret = -numeric_limits::max(); } } } return ret; } } void OperationCiftiConvert::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); int modes = 0; OptionalParameter* toGiftiExt = myParams->getOptionalParameter(1); OptionalParameter* fromGiftiExt = myParams->getOptionalParameter(2); OptionalParameter* toNifti = myParams->getOptionalParameter(3); OptionalParameter* fromNifti = myParams->getOptionalParameter(4); OptionalParameter* toText = myParams->getOptionalParameter(5); OptionalParameter* fromText = myParams->getOptionalParameter(6); if (toGiftiExt->m_present) ++modes; if (fromGiftiExt->m_present) ++modes; if (toNifti->m_present) ++modes; if (fromNifti->m_present) ++modes; if (toText->m_present) ++modes; if (fromText->m_present) ++modes; if (modes != 1) { throw OperationException("you must specify exactly one conversion mode"); } if (toGiftiExt->m_present) { CiftiFile* myInFile = toGiftiExt->getCifti(1); AString myGiftiName = toGiftiExt->getString(2); vector myDims; myDims.push_back(myInFile->getNumberOfRows()); myDims.push_back(myInFile->getNumberOfColumns()); const CiftiXML& myXML = myInFile->getCiftiXML();//soft of hack - metric files use "normal" when they really mean none, using the same thing as metric files means it should just work if (myXML.getNumberOfDimensions() != 2) throw OperationException("conversion only supported for 2D cifti"); GiftiDataArray* myArray = new GiftiDataArray(NiftiIntentEnum::NIFTI_INTENT_NORMAL, NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32, myDims, GiftiEncodingEnum::EXTERNAL_FILE_BINARY); float* myOutData = myArray->getDataPointerFloat(); for (int i = 0; i < myInFile->getNumberOfRows(); ++i) { myInFile->getRow(myOutData + i * myInFile->getNumberOfColumns(), i); } AString myCiftiXML = myXML.writeXMLToString(); myArray->getMetaData()->set("CiftiXML", myCiftiXML); GiftiFile myOutFile; myOutFile.setEncodingForWriting(GiftiEncodingEnum::EXTERNAL_FILE_BINARY); myOutFile.addDataArray(myArray); myOutFile.writeFile(myGiftiName); } if (fromGiftiExt->m_present) { AString myGiftiName = fromGiftiExt->getString(1); GiftiFile myInFile; myInFile.readFile(myGiftiName); if (myInFile.getNumberOfDataArrays() != 1) { throw OperationException("gifti file was not created by -cifti-convert, please use a -cifti-create-* command"); } GiftiDataArray* dataArrayRef = myInFile.getDataArray(0); if (!dataArrayRef->getMetaData()->exists("CiftiXML")) throw OperationException("gifti file was not created by -cifti-convert, please use a -cifti-create-* command"); if (dataArrayRef->getDataType() != NiftiDataTypeEnum::NIFTI_TYPE_FLOAT32)//this may not be needed { throw OperationException("input gifti has the wrong data type"); } CiftiFile* myOutFile = fromGiftiExt->getOutputCifti(2); CiftiXML myXML; myXML.readXML(dataArrayRef->getMetaData()->get("CiftiXML")); if (myXML.getNumberOfDimensions() != 2) throw OperationException("conversion only supported for 2D cifti"); int64_t numCols = dataArrayRef->getNumberOfComponents(); int64_t numRows = dataArrayRef->getNumberOfRows(); OptionalParameter* fgresetTimeOpt = fromGiftiExt->getOptionalParameter(3); if (fgresetTimeOpt->m_present) {//-reset-timepoints CiftiSeriesMap::Unit myUnit = CiftiSeriesMap::SECOND; OptionalParameter* fgresetTimeunitsOpt = fgresetTimeOpt->getOptionalParameter(3); if (fgresetTimeunitsOpt->m_present) { bool ok = false; myUnit = CiftiSeriesMap::stringToUnit(fgresetTimeunitsOpt->getString(1), ok); if (!ok) throw OperationException("unrecognized unit name: '" + fgresetTimeunitsOpt->getString(1) + "'"); } myXML.setMap(CiftiXML::ALONG_ROW, CiftiSeriesMap(numCols, fgresetTimeOpt->getDouble(2), fgresetTimeOpt->getDouble(1), myUnit)); } else { if (myXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::SERIES) { myXML.getSeriesMap(CiftiXML::ALONG_ROW).setLength(numCols); } } if (myXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::SERIES) { myXML.getSeriesMap(CiftiXML::ALONG_COLUMN).setLength(numRows); } if (fromGiftiExt->getOptionalParameter(4)->m_present) {//-reset-scalars if (fgresetTimeOpt->m_present) throw OperationException("only one of -reset-timepoints and -reset-scalars may be specified"); CiftiScalarsMap newMap; newMap.setLength(numCols); myXML.setMap(CiftiXML::ALONG_ROW, newMap); } if (fromGiftiExt->getOptionalParameter(6)->m_present) {//-column-reset-scalars CiftiScalarsMap newMap; newMap.setLength(numRows); myXML.setMap(CiftiXML::ALONG_COLUMN, newMap); } if (myXML.getDimensionLength(CiftiXML::ALONG_ROW) != numCols || myXML.getDimensionLength(CiftiXML::ALONG_COLUMN) != numRows) { throw OperationException("dimensions of input gifti array (" + AString::number(numRows) + " rows, " + AString::number(numCols) + " columns)" + " do not match dimensions of the Cifti XML (" + AString::number(myXML.getDimensionLength(CiftiXML::ALONG_COLUMN)) + " rows, " + AString::number(myXML.getDimensionLength(CiftiXML::ALONG_ROW)) + " columns)"); } myOutFile->setCiftiXML(myXML); OptionalParameter* fromGiftiReplace = fromGiftiExt->getOptionalParameter(5); if (fromGiftiReplace->m_present) { AString replaceFileName = fromGiftiReplace->getString(1); QFile replaceFile(replaceFileName); if (replaceFile.size() != (int64_t)(sizeof(float) * numCols * numRows)) { throw OperationException("replacement file is the wrong size, size is " + AString::number(replaceFile.size()) + ", needed " + AString::number(sizeof(float) * numCols * numRows)); } if (!replaceFile.open(QIODevice::ReadOnly)) { throw OperationException("unable to open replacement file for reading"); } OptionalParameter* swapBytes = fromGiftiReplace->getOptionalParameter(2); OptionalParameter* transpose = fromGiftiReplace->getOptionalParameter(3); int64_t readSize = numCols, numReads = numRows; if (transpose->m_present) { readSize = numRows; numReads = numCols; } CaretArray myScratch(readSize); for (int i = 0; i < numReads; ++i) { if (replaceFile.read((char*)(myScratch.getArray()), sizeof(float) * readSize) != (int64_t)(sizeof(float) * readSize)) { throw OperationException("short read from replacement file, aborting"); } float tempVal; char* tempValPointer = (char*)&tempVal;//copy method isn't as fast, but it is clean for (int j = 0; j < readSize; ++j) { if (swapBytes->m_present) { char* elemPointer = (char*)(myScratch.getArray() + j); for (int k = 0; k < (int)sizeof(float); ++k) { tempValPointer[k] = elemPointer[sizeof(float) - 1 - k]; } } else { tempVal = myScratch[j]; } if (transpose->m_present) { int32_t indices[] = {j, i}; dataArrayRef->setDataFloat32(indices, tempVal); } else { int32_t indices[] = {i, j}; dataArrayRef->setDataFloat32(indices, tempVal); } } } } vector scratchRow(numCols); for (int i = 0; i < numRows; ++i) { for (int j = 0; j < numCols; ++j) { int32_t indices[] = {i, j}; scratchRow[j] = dataArrayRef->getDataFloat32(indices); } myOutFile->setRow(scratchRow.data(), i); } } if (toNifti->m_present) { CiftiFile* myCiftiIn = toNifti->getCifti(1); if (myCiftiIn->getCiftiXML().getNumberOfDimensions() != 2) throw OperationException("conversion only supported for 2D cifti"); VolumeFile* myNiftiOut = toNifti->getOutputVolume(2); bool betterDims = toNifti->getOptionalParameter(3)->m_present; bool smallerDims = toNifti->getOptionalParameter(4)->m_present; if (betterDims && smallerDims) throw OperationException("-smaller-file and -smaller-dims may not be specified together"); vector outDims(4, 1); outDims[3] = myCiftiIn->getNumberOfColumns(); const int64_t SHORTMAX = numeric_limits::max();//less ugly than writing it out every time if (outDims[3] > SHORTMAX) throw OperationException("cifti rows are too long for nifti-1, failing"); int64_t numRows = myCiftiIn->getNumberOfRows(); if (smallerDims) { outDims[0] = int64_t(ceil(pow(numRows, 1.0f / 3.0f))) - 1;//deliberately start 1 below what floating point says for a cube while (outDims[0] * outDims[0] * outDims[0] < numRows) ++outDims[0];//use integer math to get the exact answer if (outDims[0] > SHORTMAX) throw OperationException("too many cifti rows for nifti-1 spatial dimensions, failing"); outDims[1] = outDims[0]; outDims[2] = outDims[0]; if (outDims[0] * outDims[0] * (outDims[0] - 1) >= numRows)//see whether we can subtract one from a different dimension { outDims[2] = outDims[0] - 1; if (outDims[0] * (outDims[0] - 1) * outDims[2] >= numRows) outDims[1] = outDims[0] - 1; } } else { if (betterDims) {//find the minimum needed third dimension, then compute from that how many elements the first two dimensions must encompass, etc outDims[2] = (numRows - 1) / (SHORTMAX * SHORTMAX) + 1;//round up if (outDims[2] > SHORTMAX) throw OperationException("too many cifti rows for nifti-1 spatial dimensions, failing"); int64_t temp = (numRows - 1) / outDims[2] + 1;//and again... outDims[1] = (temp - 1) / SHORTMAX + 1; outDims[0] = (temp - 1) / outDims[1] + 1; } else { int64_t temp = numRows; int index = 0; while (temp > SHORTMAX) { if (index > 1) throw OperationException("too many cifti rows for nifti-1 spatial dimensions, failing"); outDims[index] = SHORTMAX; temp = (temp - 1) / SHORTMAX + 1;//round up ++index; } outDims[index] = temp; } } CaretAssert(outDims[0] * outDims[1] * outDims[2] >= numRows);//make sure we didn't screw up the math myNiftiOut->reinitialize(outDims, FloatMatrix::identity(4).getMatrix()); myNiftiOut->setValueAllVoxels(0.0f); int64_t ijk[3] = { 0, 0, 0 }; vector rowscratch(outDims[3]); for (int64_t i = 0; i < numRows; ++i) { myCiftiIn->getRow(rowscratch.data(), i); for (int64_t j = 0; j < outDims[3]; ++j) { myNiftiOut->setValue(rowscratch[j], ijk, j); } ++ijk[0]; if (ijk[0] >= outDims[0]) { ijk[0] = 0; ++ijk[1]; if (ijk[1] >= outDims[1]) { ijk[1] = 0; ++ijk[2]; CaretAssert(i == numRows - 1 || ijk[2] < outDims[2]);//in case it divided exactly } } } } if (fromNifti->m_present) { VolumeFile* myNiftiIn = fromNifti->getVolume(1); CiftiFile* myTemplate = fromNifti->getCifti(2); CiftiFile* myCiftiOut = fromNifti->getOutputCifti(3); vector myDims; myNiftiIn->getDimensions(myDims); if (myDims[4] != 1) throw OperationException("input nifti has multiple components, aborting"); CiftiXML outXML = myTemplate->getCiftiXML(); if (outXML.getNumberOfDimensions() != 2) throw OperationException("conversion only supported for 2D cifti"); OptionalParameter* fnresetTimeOpt = fromNifti->getOptionalParameter(4); if (fnresetTimeOpt->m_present) {//-reset-timepoints CiftiSeriesMap::Unit myUnit = CiftiSeriesMap::SECOND; OptionalParameter* fnresetTimeunitsOpt = fnresetTimeOpt->getOptionalParameter(3); if (fnresetTimeunitsOpt->m_present) { bool ok = false; myUnit = CiftiSeriesMap::stringToUnit(fnresetTimeunitsOpt->getString(1), ok); if (!ok) throw OperationException("unrecognized unit name: '" + fnresetTimeunitsOpt->getString(1) + "'"); } outXML.setMap(CiftiXML::ALONG_ROW, CiftiSeriesMap(myDims[3], fnresetTimeOpt->getDouble(2), fnresetTimeOpt->getDouble(1), myUnit)); } if (fromNifti->getOptionalParameter(5)->m_present) {//-reset-scalars if (fnresetTimeOpt->m_present) throw OperationException("only one of -reset-timepoints and -reset-scalars may be specified"); CiftiScalarsMap newMap; newMap.setLength(myDims[3]); outXML.setMap(CiftiXML::ALONG_ROW, newMap); } int64_t numRows = outXML.getDimensionLength(CiftiXML::ALONG_COLUMN), numCols = outXML.getDimensionLength(CiftiXML::ALONG_ROW); if (myDims[3] != numCols) { throw OperationException("input nifti has the different size than cifti template for row length (nifti says " + AString::number(myDims[3]) + ", cifti XML says " + AString::number(numCols) + ")"); } if (numRows > myDims[0] * myDims[1] * myDims[2]) { throw OperationException("input nifti is too small for column length (need at least " + AString::number(numRows) + ", product of first three nifti dimensions is " + AString::number(myDims[0] * myDims[1] * myDims[2]) + ")"); } myCiftiOut->setCiftiXML(outXML); vector rowscratch(numCols); for (int64_t i = 0; i < numRows; ++i) { for (int64_t j = 0; j < numCols; ++j) { rowscratch[j] = myNiftiIn->getFrame(j)[i]; } myCiftiOut->setRow(rowscratch.data(), i); } } if (toText->m_present) { CiftiFile* ciftiIn = toText->getCifti(1); AString textOutName = toText->getString(2); AString delim = "\t"; OptionalParameter* colDelimOpt = toText->getOptionalParameter(3); if (colDelimOpt->m_present) { delim = colDelimOpt->getString(1); if (delim.isEmpty()) throw OperationException("delimiter string must not be empty");//catch some possible stupid mistakes } const CiftiXML& myXML = ciftiIn->getCiftiXML(); if (myXML.getNumberOfDimensions() != 2) throw OperationException("conversion only supported for 2D cifti"); if (myXML.getDimensionLength(0) < 1) throw OperationException("input cifti has zero-length rows"); vector dims = myXML.getDimensions(); vector scratchRow(dims[0]); fstream textOut(textOutName.toLocal8Bit().constData(), fstream::out | fstream::trunc | fstream::binary);//write the same file, no newline translation, regardless of OS for (int64_t i = 0; i < dims[1]; ++i) { ciftiIn->getRow(scratchRow.data(), i); textOut << AString::number(scratchRow[0]); for (int64_t j = 1; j < dims[0]; ++j) { textOut << delim << AString::number(scratchRow[j]); } textOut << "\n"; } } if (fromText->m_present) { AString textInName = fromText->getString(1); CiftiFile* ciftiTemplate = fromText->getCifti(2); CiftiFile* ciftiOut = fromText->getOutputCifti(3); AString delim = "";//empty is special value for "any whitespace" OptionalParameter* colDelimOpt = fromText->getOptionalParameter(4); if (colDelimOpt->m_present) { delim = colDelimOpt->getString(1); if (delim.isEmpty()) throw OperationException("delimiter string must not be empty"); } CiftiXML outXML = ciftiTemplate->getCiftiXML(); if (outXML.getNumberOfDimensions() != 2) throw OperationException("conversion only supported for 2D cifti"); int64_t numRows = outXML.getDimensionLength(CiftiXML::ALONG_COLUMN); fstream textIn(textInName.toLocal8Bit().constData(), fstream::in);//do newline translation on input string templine;//need to extract a row from the file first to set the row length if (!getline(textIn, templine)) throw OperationException("failed to read from input text file"); QStringList entries; if (delim.isEmpty()) { entries = QString(templine.c_str()).split(QRegExp("\\s+"), QString::SkipEmptyParts); } else { entries = QString(templine.c_str()).split(delim, QString::SkipEmptyParts); } if (numRows < 1) throw OperationException("template cifti file has no data");//this probably throws an exception in CiftiFile, but double check int textRowLength = entries.size(); OptionalParameter* ftresetTimeOpt = fromText->getOptionalParameter(5); if (ftresetTimeOpt->m_present) { CiftiSeriesMap::Unit myUnit = CiftiSeriesMap::SECOND; OptionalParameter* ftresetTimeunitsOpt = ftresetTimeOpt->getOptionalParameter(3); if (ftresetTimeunitsOpt->m_present) { bool ok = false; myUnit = CiftiSeriesMap::stringToUnit(ftresetTimeunitsOpt->getString(1), ok); if (!ok) throw OperationException("unrecognized unit name: '" + ftresetTimeunitsOpt->getString(1) + "'"); } outXML.setMap(CiftiXML::ALONG_ROW, CiftiSeriesMap(textRowLength, ftresetTimeOpt->getDouble(2), ftresetTimeOpt->getDouble(1), myUnit)); } if (fromText->getOptionalParameter(6)->m_present) { if (ftresetTimeOpt->m_present) throw OperationException("only one of -reset-timepoints and -reset-scalars may be specified"); CiftiScalarsMap newMap; newMap.setLength(textRowLength); outXML.setMap(CiftiXML::ALONG_ROW, newMap); } if (textRowLength != outXML.getDimensionLength(CiftiXML::ALONG_ROW)) { throw OperationException("text file has different row length than cifti template (text file says " + AString::number(textRowLength) + ", cifti XML says " + AString::number(outXML.getDimensionLength(CiftiXML::ALONG_ROW)) + ")"); } ciftiOut->setCiftiXML(outXML); vector temprow(textRowLength); for (int i = 0; i < textRowLength; ++i) { temprow[i] = toFloat(entries[i]); } ciftiOut->setRow(temprow.data(), 0); for (int64_t j = 1; j < numRows; ++j) { if (!getline(textIn, templine)) throw OperationException("failed to read from input text file (not enough rows)"); if (delim.isEmpty()) { entries = QString(templine.c_str()).split(QRegExp("\\s+"), QString::SkipEmptyParts); } else { entries = QString(templine.c_str()).split(delim, QString::SkipEmptyParts); } if (entries.size() != textRowLength) throw OperationException("text file has inconsistent line length"); for (int i = 0; i < textRowLength; ++i) { temprow[i] = toFloat(entries[i]); } ciftiOut->setRow(temprow.data(), j); } } } connectome-workbench-1.4.2/src/Operations/OperationCiftiConvert.h000066400000000000000000000026111360521144700251760ustar00rootroot00000000000000#ifndef __OPERATION_CIFTI_CONVERT_H__ #define __OPERATION_CIFTI_CONVERT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationCiftiConvert : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationCiftiConvert; } #endif //__OPERATION_CIFTI_CONVERT_H__ connectome-workbench-1.4.2/src/Operations/OperationCiftiConvertToScalar.cxx000066400000000000000000000124701360521144700272060ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretLogger.h" #include "CiftiFile.h" #include "FileInformation.h" #include "OperationCiftiConvertToScalar.h" #include "OperationException.h" #include #include using namespace caret; using namespace std; AString OperationCiftiConvertToScalar::getCommandSwitch() { return "-cifti-convert-to-scalar"; } AString OperationCiftiConvertToScalar::getShortDescription() { return "DEPRECATED: use -cifti-change-mapping"; } OperationParameters* OperationCiftiConvertToScalar::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-in", "input cifti file"); ret->addStringParameter(2, "direction", "which mapping to change to scalar maps, ROW or COLUMN"); ret->addCiftiOutputParameter(3, "cifti-out", "output cifti file"); OptionalParameter* nameFileOpt = ret->createOptionalParameter(4, "-name-file", "specify names for the maps"); nameFileOpt->addStringParameter(1, "file", "text file containing map names, one per line"); ret->setHelpText( AString("DEPRECATED: this command may be removed in a future release, use -cifti-change-mapping.\n\n") + "Creates a new cifti file with the same data as the input, but with one of the dimensions set to contain strings identifying each map. " + "Specifying ROW will convert a dtseries file to a dscalar file." ); return ret; } void OperationCiftiConvertToScalar::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); CiftiFile* ciftiIn = myParams->getCifti(1); AString direction = myParams->getString(2); int mydir = -1; if (direction == "ROW") mydir = 0; if (direction == "COLUMN") mydir = 1; if (mydir == -1) { throw OperationException(" must be 'ROW' or 'COLUMN'"); } CiftiFile* ciftiOut = myParams->getOutputCifti(3); OptionalParameter* nameFileOpt = myParams->getOptionalParameter(4); CiftiXMLOld myXML = ciftiIn->getCiftiXMLOld(); int rowSize = myXML.getNumberOfColumns(), colSize = myXML.getNumberOfRows(); if (mydir == 0) { myXML.resetRowsToScalars(rowSize); if (nameFileOpt->m_present) { AString listfileName = nameFileOpt->getString(1); FileInformation textFileInfo(listfileName); if (!textFileInfo.exists()) { throw OperationException("name list file doesn't exist"); } fstream nameListFile(listfileName.toLocal8Bit().constData(), fstream::in); if (!nameListFile.good()) { throw OperationException("error reading name list file"); } string mapName; for (int i = 0; i < rowSize; ++i) { getline(nameListFile, mapName); if (!nameListFile)//no, seriously, that is how you check if your input was good { CaretLogWarning("name file contained " + AString::number(i) + " names, expected " + AString::number(rowSize)); break; } myXML.setMapNameForRowIndex(i, mapName.c_str()); } } } else { myXML.resetColumnsToScalars(colSize); if (nameFileOpt->m_present) { AString listfileName = nameFileOpt->getString(1); FileInformation textFileInfo(listfileName); if (!textFileInfo.exists()) { throw OperationException("name list file doesn't exist"); } fstream nameListFile(listfileName.toLocal8Bit().constData(), fstream::in); if (!nameListFile.good()) { throw OperationException("error reading name list file"); } string mapName; for (int i = 0; i < colSize; ++i) { getline(nameListFile, mapName); if (!nameListFile)//no, seriously, that is how you check if your input was good { CaretLogWarning("warning, name file contained " + AString::number(i) + " names, expected " + AString::number(colSize)); break; } myXML.setMapNameForColumnIndex(i, mapName.c_str()); } } } ciftiOut->setCiftiXML(myXML); vector myrow(rowSize); for (int i = 0; i < colSize; ++i) { ciftiIn->getRow(myrow.data(), i); ciftiOut->setRow(myrow.data(), i); } } connectome-workbench-1.4.2/src/Operations/OperationCiftiConvertToScalar.h000066400000000000000000000026771360521144700266430ustar00rootroot00000000000000#ifndef __OPERATION_CIFTI_CONVERT_TO_SCALAR_H__ #define __OPERATION_CIFTI_CONVERT_TO_SCALAR_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationCiftiConvertToScalar : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationCiftiConvertToScalar; } #endif //__OPERATION_CIFTI_CONVERT_TO_SCALAR_H__ connectome-workbench-1.4.2/src/Operations/OperationCiftiCopyMapping.cxx000066400000000000000000000073031360521144700263620ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationCiftiCopyMapping.h" #include "OperationException.h" #include "CiftiFile.h" #include "MultiDimIterator.h" using namespace caret; using namespace std; AString OperationCiftiCopyMapping::getCommandSwitch() { return "-cifti-copy-mapping"; } AString OperationCiftiCopyMapping::getShortDescription() { return "DEPRECATED: use -cifti-change-mapping"; } OperationParameters* OperationCiftiCopyMapping::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "data-cifti", "the cifti file to use the data from"); ret->addStringParameter(2, "replace-dir", "which direction on to replace the mapping"); ret->addCiftiParameter(3, "template-cifti", "a cifti file containing the desired mapping"); ret->addStringParameter(4, "template-dir", "which direction on to use the mapping from"); ret->addCiftiOutputParameter(5, "cifti-out", "the output cifti file"); ret->setHelpText( AString("DEPRECATED: this command may be removed in a future release, use -cifti-change-mapping.\n\n") + " must have the same length along the replace direction as has along the template direction. " + CiftiXML::directionFromStringExplanation() ); return ret; } void OperationCiftiCopyMapping::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); const CiftiFile* dataCifti = myParams->getCifti(1); int dataDir = CiftiXML::directionFromString(myParams->getString(2)); const CiftiFile* templateCifti = myParams->getCifti(3); int templateDir = CiftiXML::directionFromString(myParams->getString(4)); CiftiFile* ciftiOut = myParams->getOutputCifti(5); CiftiXML outXML = dataCifti->getCiftiXML();//we need a copy of it so we can modify if (dataDir >= dataCifti->getCiftiXML().getNumberOfDimensions()) { throw OperationException("specified direction doesn't exist in data file"); } if (templateDir >= templateCifti->getCiftiXML().getNumberOfDimensions()) { throw OperationException("specified direction doesn't exist in template file"); } if (outXML.getDimensionLength(dataDir) != templateCifti->getCiftiXML().getDimensionLength(templateDir)) { throw OperationException("selected directions on files have different length"); } outXML.setMap(dataDir, *(templateCifti->getCiftiXML().getMap(templateDir))); ciftiOut->setCiftiXML(outXML); vector outDims = outXML.getDimensions(); vector scratchrow(outDims[0]); for (MultiDimIterator iter(vector(outDims.begin() + 1, outDims.end())); !iter.atEnd(); ++iter) {//drop the first dimension, row length dataCifti->getRow(scratchrow.data(), *iter); ciftiOut->setRow(scratchrow.data(), *iter); } } connectome-workbench-1.4.2/src/Operations/OperationCiftiCopyMapping.h000066400000000000000000000026441360521144700260120ustar00rootroot00000000000000#ifndef __OPERATION_CIFTI_COPY_MAPPING_H__ #define __OPERATION_CIFTI_COPY_MAPPING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationCiftiCopyMapping : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationCiftiCopyMapping; } #endif //__OPERATION_CIFTI_COPY_MAPPING_H__ connectome-workbench-1.4.2/src/Operations/OperationCiftiCreateDenseFromTemplate.cxx000066400000000000000000001006551360521144700306420ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationCiftiCreateDenseFromTemplate.h" #include "OperationException.h" #include "AlgorithmCiftiSeparate.h" #include "AlgorithmCiftiReplaceStructure.h" #include "CaretAssert.h" #include "CiftiFile.h" #include "GiftiLabelTable.h" #include "LabelFile.h" #include "MetricFile.h" #include "VolumeFile.h" #include using namespace caret; using namespace std; AString OperationCiftiCreateDenseFromTemplate::getCommandSwitch() { return "-cifti-create-dense-from-template"; } AString OperationCiftiCreateDenseFromTemplate::getShortDescription() { return "CREATE CIFTI WITH MATCHING DENSE MAP"; } OperationParameters* OperationCiftiCreateDenseFromTemplate::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "template-cifti", "file to match brainordinates of"); ret->addCiftiOutputParameter(2, "cifti-out", "the output cifti file"); OptionalParameter* seriesOpt = ret->createOptionalParameter(3, "-series", "make a dtseries file instead of a dscalar"); seriesOpt->addDoubleParameter(1, "step", "increment between series points"); seriesOpt->addDoubleParameter(2, "start", "start value of the series"); OptionalParameter* sUnitOpt = seriesOpt->createOptionalParameter(3, "-unit", "select unit for series (default SECOND)"); sUnitOpt->addStringParameter(1, "unit", "unit identifier"); OptionalParameter* volAllOpt = ret->createOptionalParameter(4, "-volume-all", "specify an input volume file for all voxel data"); volAllOpt->addVolumeParameter(1, "volume-in", "the input volume file"); volAllOpt->createOptionalParameter(2, "-from-cropped", "the input is cropped to the size of the voxel data in the template file"); ParameterComponent* ciftiOpt = ret->createRepeatableParameter(5, "-cifti", "use input data from a cifti file"); ciftiOpt->addCiftiParameter(1, "cifti-in", "cifti file containing input data"); ParameterComponent* metricOpt = ret->createRepeatableParameter(6, "-metric", "use input data from a metric file"); metricOpt->addStringParameter(1, "structure", "which structure to put the metric file into"); metricOpt->addMetricParameter(2, "metric-in", "input metric file"); ParameterComponent* labelOpt = ret->createRepeatableParameter(7, "-label", "use input data from surface label files"); labelOpt->addStringParameter(1, "structure", "which structure to put the label file into"); labelOpt->addLabelParameter(2, "label-in", "input label file"); ParameterComponent* volOpt = ret->createRepeatableParameter(8, "-volume", "use a volume file for a single volume structure's data"); volOpt->addStringParameter(1, "structure", "which structure to put the volume file into"); volOpt->addVolumeParameter(2, "volume-in", "the input volume file"); volOpt->createOptionalParameter(3, "-from-cropped", "the input is cropped to the size of the volume structure"); AString helpText = AString("This command helps you make a new dscalar, dtseries, or dlabel cifti file that matches the brainordinate space used in another cifti file. ") + "The template file must have the desired brainordinate space in the mapping along the column direction (for dtseries, dscalar, dlabel, and symmetric dconn this is always the case). " + "All input cifti files must have a brain models mapping along column and use the same volume space and/or surface vertex count as the template for structures that they contain. " + "If any input files contain label data, then input files with non-label data are not allowed, and the -series option may not be used.\n\n" + "Any structure that isn't covered by an input is filled with zeros or the unlabeled key.\n\n" + "The argument of -metric, -label or -volume must be one of the following:\n"; vector myStructureEnums; StructureEnum::getAllEnums(myStructureEnums); for (int i = 0; i < (int)myStructureEnums.size(); ++i) { helpText += "\n" + StructureEnum::toName(myStructureEnums[i]); } helpText += "\n\nThe argument to -unit must be one of the following:\n"; vector unitList = CiftiSeriesMap::getAllUnits(); for (int i = 0; i < (int)unitList.size(); ++i) { helpText += "\n" + CiftiSeriesMap::unitToString(unitList[i]); } ret->setHelpText(helpText); return ret; } namespace { enum DataSourceType { NONE,//fill with zeros CIFTI, LABEL, METRIC, VOLUME, VOLUME_ALL }; struct DataSourceInfo { DataSourceType type; int64_t index;//for repeatable options DataSourceInfo() { type = NONE; index = -1; }; }; } void OperationCiftiCreateDenseFromTemplate::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); const CiftiFile* templateCifti = myParams->getCifti(1); CiftiFile* ciftiOut = myParams->getOutputCifti(2); const CiftiXML& templateXML = templateCifti->getCiftiXML(); if (templateXML.getNumberOfDimensions() != 2) { throw OperationException("template cifti file must have exactly 2 dimensions"); } if (templateXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) { throw OperationException("template cifti file does not have brain models along column"); } CiftiXML outXML = templateXML; int labelMode = -1;//-1 not set, 0 set to false, 1 set to true int64_t numMaps = -1; const CaretMappableDataFile* nameFile = NULL; const CiftiFile* ciftiNameFile = NULL;//cifti doesn't inherit from CaretMappableDataFile, it is too different const CiftiBrainModelsMap& templateMap = templateXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); vector surfStructures = templateMap.getSurfaceStructureList(), volStructures = templateMap.getVolumeStructureList(); vector surfInfo(surfStructures.size()), volInfo(volStructures.size()); OptionalParameter* volAllOpt = myParams->getOptionalParameter(4); if (volAllOpt->m_present) { if (!templateMap.hasVolumeData()) { throw OperationException("-volume-all specified, but template cifti file does use any voxels"); } VolumeFile* allVolume = volAllOpt->getVolume(1); bool fromCropped = volAllOpt->getOptionalParameter(2)->m_present; const VolumeSpace& volAllSpace = allVolume->getVolumeSpace(); VolumeSpace templateSpace; if (fromCropped) { int64_t tempDims[3], tempOffset[3]; vector > tempSform; AlgorithmCiftiSeparate::getCroppedVolSpaceAll(templateCifti, CiftiXML::ALONG_COLUMN, tempDims, tempSform, tempOffset); templateSpace.setSpace(tempDims, tempSform); } else { templateSpace = templateMap.getVolumeSpace(); } if (!templateSpace.matches(volAllSpace)) { throw OperationException("-volume-all specifies a volume file that doesn't match the volume space of the template cifti file"); } numMaps = allVolume->getNumberOfMaps(); nameFile = allVolume; if (allVolume->getType() == SubvolumeAttributes::LABEL) { labelMode = 1; } else { labelMode = 0; } for (int i = 0; i < (int)volInfo.size(); ++i) { volInfo[i].type = VOLUME_ALL; } } const vector& ciftiInstances = *(myParams->getRepeatableParameterInstances(5)); for (int instance = 0; instance < (int)ciftiInstances.size(); ++instance) { const CiftiFile* thisCifti = ciftiInstances[instance]->getCifti(1); const CiftiXML& thisXML = thisCifti->getCiftiXML(); if (thisXML.getNumberOfDimensions() != 2) { throw OperationException("input cifti files must have exactly 2 dimensions"); } if (thisXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) { throw OperationException("input cifti files must have a brain models mapping along column"); } const CiftiBrainModelsMap& thisDenseMap = thisXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); bool isLabel = (thisXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::LABELS); if (labelMode == -1) { labelMode = isLabel ? 1 : 0; } else { if (isLabel) { if (labelMode == 0) { throw OperationException("cifti file '" + thisCifti->getFileName() + "' contains label data, but -volume-all contains non-label data"); } } else { if (labelMode == 1) { throw OperationException("cifti file '" + thisCifti->getFileName() + "' contains non-label data, but -volume-all contains label data"); } } } int64_t thisNumMaps = thisXML.getDimensionLength(CiftiXML::ALONG_ROW); if (numMaps == -1) { numMaps = thisNumMaps; } else { if (numMaps != thisNumMaps) { throw OperationException("cifti file '" + thisCifti->getFileName() + "' contains " + AString::number(thisNumMaps) + " maps, but -volume-all contains " + AString::number(numMaps) + " maps"); } } if (thisDenseMap.hasVolumeData() && templateMap.hasVolumeData() && !templateMap.getVolumeSpace().matches(thisDenseMap.getVolumeSpace())) { throw OperationException("cifti file '" + thisCifti->getFileName() + "' uses a different volume space than the template file"); } vector thisSurfStructs = thisDenseMap.getSurfaceStructureList(), thisVolStructs = thisDenseMap.getVolumeStructureList(); for (int whichStruct = 0; whichStruct < (int)thisSurfStructs.size(); ++whichStruct) { vector::const_iterator iter = std::find(surfStructures.begin(), surfStructures.end(), thisSurfStructs[whichStruct]); if (iter == surfStructures.end()) { cout << ("discarding surface structure " + StructureEnum::toName(thisSurfStructs[whichStruct]) + " from file '" + thisCifti->getFileName() + "'") << endl; } else { int outIndex = (int)(iter - surfStructures.begin()); int64_t templateNumNodes = templateMap.getSurfaceNumberOfNodes(thisSurfStructs[whichStruct]); int64_t thisNumNodes = thisDenseMap.getSurfaceNumberOfNodes(thisSurfStructs[whichStruct]); if (thisNumNodes != templateNumNodes) { throw OperationException("cifti file '" + thisCifti->getFileName() + "' contains surface data for " + StructureEnum::toName(thisSurfStructs[whichStruct]) + ", but uses a surface with " + AString::number(thisNumNodes) + " vertices, while template needs " + AString::number(templateNumNodes)); } if (surfInfo[outIndex].type != NONE) { throw OperationException("cifti file '" + thisCifti->getFileName() + "' contains data for structure " + StructureEnum::toName(thisSurfStructs[whichStruct]) + ", but data for this structure also exists in an another -cifti option's file"); } surfInfo[outIndex].type = CIFTI; surfInfo[outIndex].index = instance; } } if (templateMap.hasVolumeData()) { for (int whichStruct = 0; whichStruct < (int)thisVolStructs.size(); ++whichStruct) { vector::const_iterator iter = std::find(volStructures.begin(), volStructures.end(), thisVolStructs[whichStruct]); if (iter == volStructures.end()) { cout << ("discarding volume structure " + StructureEnum::toName(thisVolStructs[whichStruct]) + " from file '" + thisCifti->getFileName() + "'") << endl; } else { int outIndex = (int)(iter - volStructures.begin()); if (volInfo[outIndex].type != NONE) { throw OperationException("cifti file '" + thisCifti->getFileName() + "' contains data for structure " + StructureEnum::toName(thisVolStructs[whichStruct]) + ", but data for this structure also exists in an another option's file"); } volInfo[outIndex].type = CIFTI; volInfo[outIndex].index = instance; } } } else { if (thisDenseMap.hasVolumeData()) { cout << ("discarding volume structures from file '" + thisCifti->getFileName() + "'") << endl; } } if (ciftiNameFile == NULL && (isLabel || thisXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::SCALARS || thisXML.getMappingType(CiftiXML::ALONG_ROW) == CiftiMappingType::PARCELS)) { ciftiNameFile = thisCifti;//cifti trumps everything, if it has scalar or label or parcels } } const vector& metricInstances = *(myParams->getRepeatableParameterInstances(6)); for (int instance = 0; instance < (int)metricInstances.size(); ++instance) { if (labelMode == 1) throw OperationException("-metric option specified when other inputs are label-type files"); labelMode = 0; AString structString = metricInstances[instance]->getString(1); const MetricFile* thisMetric = metricInstances[instance]->getMetric(2); bool ok = false; StructureEnum::Enum thisStruct = StructureEnum::fromName(structString, &ok); if (!ok) throw OperationException("unrecognized structure string in -metric option: " + structString); vector::const_iterator iter = std::find(surfStructures.begin(), surfStructures.end(), thisStruct); if (iter == surfStructures.end()) { throw OperationException("-metric option specified for structure " + structString + ", but template cifti file does not contain this surface structure"); } int outIndex = (int)(iter - surfStructures.begin()); if (thisMetric->getNumberOfNodes() != templateMap.getSurfaceNumberOfNodes(thisStruct)) { throw OperationException("metric file '" + thisMetric->getFileName() + "' has " + AString::number(thisMetric->getNumberOfNodes()) + " vertices, but template cifti requires " + AString::number(templateMap.getSurfaceNumberOfNodes(thisStruct)) + " for structure " + structString); } if (surfInfo[outIndex].type != NONE) { throw OperationException("-metric specified with structure " + structString + ", but data for this structure also exists in an another option"); } int64_t thisNumMaps = thisMetric->getNumberOfMaps(); if (numMaps == -1) { numMaps = thisNumMaps; } else { if (numMaps != thisNumMaps) { throw OperationException("metric file '" + thisMetric->getFileName() + "' contains " + AString::number(thisNumMaps) + " maps, but other file(s) contain " + AString::number(numMaps) + " maps"); } } checkStructureMatch(thisMetric, thisStruct, "metric file '" + thisMetric->getFileName() + "'", "the -metric option specified"); surfInfo[outIndex].type = METRIC; surfInfo[outIndex].index = instance; if (instance == 0) nameFile = thisMetric;//-metric trumps -volume-all for names, but use the first -metric } const vector& labelInstances = *(myParams->getRepeatableParameterInstances(7)); for (int instance = 0; instance < (int)labelInstances.size(); ++instance) { if (labelMode == 0) throw OperationException("-label option specified when other inputs are real-valued files"); labelMode = 1; AString structString = labelInstances[instance]->getString(1); const LabelFile* thisLabel = labelInstances[instance]->getLabel(2); bool ok = false; StructureEnum::Enum thisStruct = StructureEnum::fromName(structString, &ok); if (!ok) throw OperationException("unrecognized structure string in -label option: " + structString); vector::const_iterator iter = std::find(surfStructures.begin(), surfStructures.end(), thisStruct); if (iter == surfStructures.end()) { throw OperationException("-label option specified for structure " + structString + ", but template cifti file does not contain this surface structure"); } int outIndex = (int)(iter - surfStructures.begin()); if (thisLabel->getNumberOfNodes() != templateMap.getSurfaceNumberOfNodes(thisStruct)) { throw OperationException("label file '" + thisLabel->getFileName() + "' has " + AString::number(thisLabel->getNumberOfNodes()) + " vertices, but template cifti requires " + AString::number(templateMap.getSurfaceNumberOfNodes(thisStruct)) + " for structure " + structString); } if (surfInfo[outIndex].type != NONE) { throw OperationException("-label specified with structure " + structString + ", but data for this structure also exists in an another option"); } int64_t thisNumMaps = thisLabel->getNumberOfMaps(); if (numMaps == -1) { numMaps = thisNumMaps; } else { if (numMaps != thisNumMaps) { throw OperationException("label file '" + thisLabel->getFileName() + "' contains " + AString::number(thisNumMaps) + " maps, but other file(s) contain " + AString::number(numMaps) + " maps"); } } checkStructureMatch(thisLabel, thisStruct, "label file '" + thisLabel->getFileName() + "'", "the -label option specified"); surfInfo[outIndex].type = LABEL; surfInfo[outIndex].index = instance; if (instance == 0) nameFile = thisLabel;//-label trumps -volume-all for names, but use the first -label } const vector& volumeInstances = *(myParams->getRepeatableParameterInstances(8)); for (int instance = 0; instance < (int)volumeInstances.size(); ++instance) { AString structString = volumeInstances[instance]->getString(1); const VolumeFile* thisVol = volumeInstances[instance]->getVolume(2); bool fromCropped = volumeInstances[instance]->getOptionalParameter(3)->m_present; bool ok = false; StructureEnum::Enum thisStruct = StructureEnum::fromName(structString, &ok); if (!ok) throw OperationException("unrecognized structure string in -volume option: " + structString); vector::const_iterator iter = std::find(volStructures.begin(), volStructures.end(), thisStruct); if (iter == volStructures.end()) { throw OperationException("-volume option specified for structure " + structString + ", but template cifti file does not contain this volume structure"); } int outIndex = (int)(iter - volStructures.begin()); bool isLabel = (thisVol->getType() == SubvolumeAttributes::LABEL); if (labelMode == -1) { labelMode = isLabel ? 1 : 0; } else { if (isLabel) { if (labelMode == 0) { throw OperationException("volume file '" + thisVol->getFileName() + "' contains label data, but other file(s) contain non-label data"); } } else { if (labelMode == 1) { throw OperationException("volume file '" + thisVol->getFileName() + "' contains non-label data, but other file(s) contain label data"); } } } VolumeSpace templateSpace; if (fromCropped) { int64_t tempDims[3], tempOffset[3]; vector > tempSform; AlgorithmCiftiSeparate::getCroppedVolSpace(templateCifti, CiftiXML::ALONG_COLUMN, thisStruct, tempDims, tempSform, tempOffset); templateSpace.setSpace(tempDims, tempSform); } else { templateSpace = templateMap.getVolumeSpace(); } if (!thisVol->matchesVolumeSpace(templateSpace)) { throw OperationException("volume file '" + thisVol->getFileName() + "' does not match volume space of template cifti file"); } if (volInfo[outIndex].type != NONE) { throw OperationException("-volume specified with structure " + structString + ", but data for this structure also exists in an another option"); } int64_t thisNumMaps = thisVol->getNumberOfMaps(); if (numMaps == -1) { numMaps = thisNumMaps; } else { if (numMaps != thisNumMaps) { throw OperationException("volume file '" + thisVol->getFileName() + "' contains " + AString::number(thisNumMaps) + " maps, but other file(s) contain " + AString::number(numMaps) + " maps"); } } volInfo[outIndex].type = VOLUME; volInfo[outIndex].index = instance; if (nameFile == NULL) nameFile = thisVol;//-volume is the lowest priority for names } if (numMaps == -1) { throw OperationException("you must specify at least one input option"); } OptionalParameter* seriesOpt = myParams->getOptionalParameter(3); if (seriesOpt->m_present) { if (labelMode == 1) { throw OperationException("-series option cannot be used when input is label data"); } CiftiSeriesMap outMap; outMap.setLength(numMaps); outMap.setStep(seriesOpt->getDouble(1)); outMap.setStart(seriesOpt->getDouble(2)); OptionalParameter* unitOpt = seriesOpt->getOptionalParameter(3); if (unitOpt->m_present) { AString unitString = unitOpt->getString(1); bool ok = false; CiftiSeriesMap::Unit myUnit = CiftiSeriesMap::stringToUnit(unitString, ok); if (!ok) throw OperationException("unrecognized unit string '" + unitString + "'"); outMap.setUnit(myUnit); } outXML.setMap(CiftiXML::ALONG_ROW, outMap); } else { if (labelMode == 1) { CiftiLabelsMap outMap; outMap.setLength(numMaps); if (ciftiNameFile != NULL) { const CiftiMappingType& nameMap = *(ciftiNameFile->getCiftiXML().getMap(CiftiXML::ALONG_ROW)); for (int64_t i = 0; i < numMaps; ++i) { outMap.setMapName(i, nameMap.getIndexName(i)); } } else { if (nameFile != NULL)//if only input is cifti dtseries, there are no names to use { for (int64_t i = 0; i < numMaps; ++i) { outMap.setMapName(i, nameFile->getMapName(i)); } } } outXML.setMap(CiftiXML::ALONG_ROW, outMap); } else { CiftiScalarsMap outMap; outMap.setLength(numMaps); if (ciftiNameFile != NULL) { const CiftiMappingType& nameMap = *(ciftiNameFile->getCiftiXML().getMap(CiftiXML::ALONG_ROW)); for (int64_t i = 0; i < numMaps; ++i) { outMap.setMapName(i, nameMap.getIndexName(i)); } } else { if (nameFile != NULL) { for (int64_t i = 0; i < numMaps; ++i) { outMap.setMapName(i, nameFile->getMapName(i)); } } } outXML.setMap(CiftiXML::ALONG_ROW, outMap); } } ciftiOut->setCiftiXML(outXML); for (int whichStruct = 0; whichStruct < (int)surfStructures.size(); ++whichStruct) { switch (surfInfo[whichStruct].type) { case CIFTI: { const CiftiFile* toUse = ciftiInstances[surfInfo[whichStruct].index]->getCifti(1); if (labelMode == 1) { LabelFile tempLabel; AlgorithmCiftiSeparate(NULL, toUse, CiftiXML::ALONG_COLUMN, surfStructures[whichStruct], &tempLabel); AlgorithmCiftiReplaceStructure(NULL, ciftiOut, CiftiXML::ALONG_COLUMN, surfStructures[whichStruct], &tempLabel); } else { MetricFile tempMetric; AlgorithmCiftiSeparate(NULL, toUse, CiftiXML::ALONG_COLUMN, surfStructures[whichStruct], &tempMetric); AlgorithmCiftiReplaceStructure(NULL, ciftiOut, CiftiXML::ALONG_COLUMN, surfStructures[whichStruct], &tempMetric); } break; } case METRIC: { const MetricFile* toUse = metricInstances[surfInfo[whichStruct].index]->getMetric(2); AlgorithmCiftiReplaceStructure(NULL, ciftiOut, CiftiXML::ALONG_COLUMN, surfStructures[whichStruct], toUse); break; } case LABEL: { const LabelFile* toUse = labelInstances[surfInfo[whichStruct].index]->getLabel(2); AlgorithmCiftiReplaceStructure(NULL, ciftiOut, CiftiXML::ALONG_COLUMN, surfStructures[whichStruct], toUse); break; } case NONE: { int numNodes = templateMap.getSurfaceNumberOfNodes(surfStructures[whichStruct]); if (labelMode == 1) { LabelFile tempLabel; tempLabel.setNumberOfNodesAndColumns(numNodes, numMaps); int32_t unlabeledKey = tempLabel.getLabelTable()->getUnassignedLabelKey(); vector scratchCol(numNodes, unlabeledKey); for (int64_t i = 0; i < numMaps; ++i) { tempLabel.setLabelKeysForColumn(i, scratchCol.data()); } AlgorithmCiftiReplaceStructure(NULL, ciftiOut, CiftiXML::ALONG_COLUMN, surfStructures[whichStruct], &tempLabel); } else { MetricFile tempMetric; tempMetric.setNumberOfNodesAndColumns(numNodes, numMaps); vector scratchCol(numNodes, 0.0f); for (int64_t i = 0; i < numMaps; ++i) { tempMetric.setValuesForColumn(i, scratchCol.data()); } AlgorithmCiftiReplaceStructure(NULL, ciftiOut, CiftiXML::ALONG_COLUMN, surfStructures[whichStruct], &tempMetric); } break; } default: CaretAssert(false); throw OperationException("internal error, invalid source type for surface data, tell the developers what you did"); } } if (volStructures.size() > 0 && volInfo[0].type == VOLUME_ALL)//NOTE: if one structure is VOLUME_ALL, all are, and the cropped space is different than per-structure, so DO NOT enter the structure loop { const VolumeFile* toUse = volAllOpt->getVolume(1); bool fromCropped = volAllOpt->getOptionalParameter(2)->m_present; AlgorithmCiftiReplaceStructure(NULL, ciftiOut, CiftiXML::ALONG_COLUMN, toUse, fromCropped); } else { for (int whichStruct = 0; whichStruct < (int)volStructures.size(); ++whichStruct) { switch (volInfo[whichStruct].type) { case CIFTI: { const CiftiFile* toUse = ciftiInstances[volInfo[whichStruct].index]->getCifti(1); VolumeFile tempVol; int64_t dims1[3], dims2[3], off1[3], off2[3];//check if the cropped space matches, if so we can save memory easily by using the crop argument (and this is also the common case) vector > sform1, sform2; AlgorithmCiftiSeparate::getCroppedVolSpace(toUse, CiftiXML::ALONG_COLUMN, volStructures[whichStruct], dims1, sform1, off1); AlgorithmCiftiSeparate::getCroppedVolSpace(templateCifti, CiftiXML::ALONG_COLUMN, volStructures[whichStruct], dims2, sform2, off2); VolumeSpace space1(dims1, sform1), space2(dims2, sform2); if (space1.matches(space2)) { AlgorithmCiftiSeparate(NULL, toUse, CiftiXML::ALONG_COLUMN, volStructures[whichStruct], &tempVol, off1, NULL, true); AlgorithmCiftiReplaceStructure(NULL, ciftiOut, CiftiXML::ALONG_COLUMN, volStructures[whichStruct], &tempVol, true); } else { AlgorithmCiftiSeparate(NULL, toUse, CiftiXML::ALONG_COLUMN, volStructures[whichStruct], &tempVol, off1, NULL, false); AlgorithmCiftiReplaceStructure(NULL, ciftiOut, CiftiXML::ALONG_COLUMN, volStructures[whichStruct], &tempVol, false); } break; } case VOLUME: { const VolumeFile* toUse = volumeInstances[volInfo[whichStruct].index]->getVolume(2); bool fromCropped = volumeInstances[volInfo[whichStruct].index]->getOptionalParameter(3)->m_present; AlgorithmCiftiReplaceStructure(NULL, ciftiOut, CiftiXML::ALONG_COLUMN, volStructures[whichStruct], toUse, fromCropped); break; } case NONE: { VolumeFile tempVol; int64_t offset[3]; vector dims(3); vector > sform; AlgorithmCiftiSeparate::getCroppedVolSpace(templateCifti, CiftiXML::ALONG_COLUMN, volStructures[whichStruct], dims.data(), sform, offset); dims.push_back(numMaps); if (labelMode == 1) { int64_t frameSize = dims[0] * dims[1] * dims[2]; tempVol.reinitialize(dims, sform, 1, SubvolumeAttributes::LABEL); for (int64_t i = 0; i < numMaps; ++i) { int32_t unlabeledKey = tempVol.getMapLabelTable(i)->getUnassignedLabelKey(); vector scratchFrame(frameSize, unlabeledKey); tempVol.setFrame(scratchFrame.data(), i); } } else { tempVol.reinitialize(dims, sform); tempVol.setValueAllVoxels(0.0f); } AlgorithmCiftiReplaceStructure(NULL, ciftiOut, CiftiXML::ALONG_COLUMN, volStructures[whichStruct], &tempVol, true); break; } default: CaretAssert(false); throw OperationException("internal error, invalid source type for volume structure data, tell the developers what you did"); } } } } connectome-workbench-1.4.2/src/Operations/OperationCiftiCreateDenseFromTemplate.h000066400000000000000000000027621360521144700302670ustar00rootroot00000000000000#ifndef __OPERATION_CIFTI_CREATE_DENSE_FROM_TEMPLATE_H__ #define __OPERATION_CIFTI_CREATE_DENSE_FROM_TEMPLATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationCiftiCreateDenseFromTemplate : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationCiftiCreateDenseFromTemplate; } #endif //__OPERATION_CIFTI_CREATE_DENSE_FROM_TEMPLATE_H__ connectome-workbench-1.4.2/src/Operations/OperationCiftiCreateParcellatedFromTemplate.cxx000066400000000000000000000220301360521144700320120ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationCiftiCreateParcellatedFromTemplate.h" #include "OperationException.h" #include "CaretLogger.h" #include "CiftiFile.h" #include "MultiDimIterator.h" #include using namespace caret; using namespace std; AString OperationCiftiCreateParcellatedFromTemplate::getCommandSwitch() { return "-cifti-create-parcellated-from-template"; } AString OperationCiftiCreateParcellatedFromTemplate::getShortDescription() { return "MATCH PARCELS TO TEMPLATE BY NAME"; } OperationParameters* OperationCiftiCreateParcellatedFromTemplate::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-template", "a cifti file with the template parcel mapping along column"); ret->addStringParameter(2, "modify-direction", "which dimension of the output file should match the template (integer, 'ROW', or 'COLUMN')"); ret->addCiftiOutputParameter(3, "cifti-out", "the output cifti file"); OptionalParameter* fillOpt = ret->createOptionalParameter(4, "-fill-value", "specify value to be used in parcels that don't match"); fillOpt->addDoubleParameter(1, "value", "value to use (default 0)"); ParameterComponent* ciftiOpt = ret->createRepeatableParameter(5, "-cifti", "specify an input cifti file"); ciftiOpt->addCiftiParameter(1, "cifti-in", "the input parcellated cifti file"); ret->setHelpText( AString("For each parcel name in the template mapping, find that name in an input cifti file and use its data in the output file. ") + "All input cifti files must have a parcels mapping along and matching mappings along other dimensions. " + CiftiXML::directionFromStringExplanation() ); return ret; } void OperationCiftiCreateParcellatedFromTemplate::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); CiftiFile* templateCifti = myParams->getCifti(1); int direction = CiftiXML::directionFromString(myParams->getString(2)); CiftiFile* ciftiOut = myParams->getOutputCifti(3); OptionalParameter* fillOpt = myParams->getOptionalParameter(4); float fillValue = 0.0f; if (fillOpt->m_present) { fillValue = (float)fillOpt->getDouble(1); } const vector& inputInstances = *(myParams->getRepeatableParameterInstances(5)); const CiftiXML& templateXML = templateCifti->getCiftiXML(); if (templateXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::PARCELS) { throw OperationException("template file does not have a parcel mapping along column"); } int numInstances = (int)inputInstances.size(); if (numInstances < 1) { throw OperationException("at least one input cifti file must be specified"); } const CiftiXML& firstXML = inputInstances[0]->getCifti(1)->getCiftiXML(); int numDims = firstXML.getNumberOfDimensions(); if (direction >= numDims) { throw OperationException("input file '" + inputInstances[0]->getCifti(1)->getFileName() + "' does not contain the specified dimension"); } for (int i = 0; i < numInstances; ++i) { const CiftiFile* thisInput = inputInstances[i]->getCifti(1); const CiftiXML& thisXML = thisInput->getCiftiXML(); if (numDims != thisXML.getNumberOfDimensions()) { throw OperationException("input '" + thisInput->getFileName() + "' has different number of dimensions"); } for (int j = 0; j < numDims; ++j) { if (j == direction) { if (thisXML.getMappingType(j) != CiftiMappingType::PARCELS) { throw OperationException("input '" + thisInput->getFileName() + "' does not contain parcels mapping along specified direction"); } } else { if (!thisXML.getMap(j)->approximateMatch(*(firstXML.getMap(j)))) { throw OperationException("input '" + thisInput->getFileName() + "' has non-matching mapping along other direction(s)"); } } } } const CiftiParcelsMap& myTemplateMap = templateXML.getParcelsMap(CiftiXML::ALONG_COLUMN); int numOutParcels = myTemplateMap.getLength(); map nameMatcher; for (int i = 0; i < numOutParcels; ++i) { if (nameMatcher.find(myTemplateMap.getIndexName(i)) != nameMatcher.end()) { throw OperationException("template parcel mapping reuses a parcel name"); } nameMatcher[myTemplateMap.getIndexName(i)] = i; } vector sourceInput(numOutParcels, -1), sourceParcel(numOutParcels); for (int i = 0; i < numInstances; ++i) { const CiftiFile* thisInput = inputInstances[i]->getCifti(1); const CiftiXML& thisXML = thisInput->getCiftiXML(); const CiftiParcelsMap& thisParcelMap = thisXML.getParcelsMap(direction); int thisNumParcels = thisParcelMap.getLength(); bool match = false; for (int j = 0; j < thisNumParcels; ++j) { map::const_iterator result = nameMatcher.find(thisParcelMap.getIndexName(j)); if (result != nameMatcher.end()) { match = true; if (sourceInput[result->second] != -1) { throw OperationException("multiple input parcels match output parcel '" + result->first + "'"); } sourceInput[result->second] = i; sourceParcel[result->second] = j; } } if (!match) { CaretLogWarning("input '" + thisInput->getFileName() + "' does not match any template parcels"); } } CiftiXML outXML = firstXML; outXML.setMap(direction, myTemplateMap); ciftiOut->setCiftiXML(outXML); if (direction == CiftiXML::ALONG_ROW) { vector outRow(numOutParcels, fillValue); vector > inputRows(numInstances); for (int i = 0; i < numInstances; ++i) { const CiftiFile* thisInput = inputInstances[i]->getCifti(1); const CiftiXML& thisXML = thisInput->getCiftiXML(); inputRows[i].resize(thisXML.getDimensionLength(CiftiXML::ALONG_ROW)); } vector iterDims = firstXML.getDimensions(); iterDims.erase(iterDims.begin());//remove row dimension for (MultiDimIterator iter(iterDims); !iter.atEnd(); ++iter) { for (int i = 0; i < numInstances; ++i) { const CiftiFile* thisInput = inputInstances[i]->getCifti(1); thisInput->getRow(inputRows[i].data(), *iter); } for (int i = 0; i < numOutParcels; ++i) { if (sourceInput[i] != -1) { outRow[i] = inputRows[sourceInput[i]][sourceParcel[i]]; } } ciftiOut->setRow(outRow.data(), *iter); } } else { vector fillRow(firstXML.getDimensionLength(CiftiXML::ALONG_ROW), fillValue); vector scratchRow = fillRow; vector iterDims = firstXML.getDimensions(); iterDims.erase(iterDims.begin() + direction);//remove remapped dimension iterDims.erase(iterDims.begin());//remove row dimension for (MultiDimIterator iter(iterDims); !iter.atEnd(); ++iter) { vector restoreDims = *iter; restoreDims.insert(restoreDims.begin() + (direction - 1), -1);//deliberately invalid placeholder for (int i = 0; i < numOutParcels; ++i) { if (sourceInput[i] == -1) { restoreDims[direction - 1] = i; ciftiOut->setRow(fillRow.data(), restoreDims); } else { restoreDims[direction - 1] = sourceParcel[i]; const CiftiFile* thisInput = inputInstances[sourceInput[i]]->getCifti(1); thisInput->getRow(scratchRow.data(), restoreDims); restoreDims[direction - 1] = i; ciftiOut->setRow(scratchRow.data(), restoreDims); } } } } } connectome-workbench-1.4.2/src/Operations/OperationCiftiCreateParcellatedFromTemplate.h000066400000000000000000000030261360521144700314430ustar00rootroot00000000000000#ifndef __OPERATION_CIFTI_CREATE_PARCELLATED_FROM_TEMPLATE_H__ #define __OPERATION_CIFTI_CREATE_PARCELLATED_FROM_TEMPLATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationCiftiCreateParcellatedFromTemplate : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationCiftiCreateParcellatedFromTemplate; } #endif //__OPERATION_CIFTI_CREATE_PARCELLATED_FROM_TEMPLATE_H__ connectome-workbench-1.4.2/src/Operations/OperationCiftiCreateScalarSeries.cxx000066400000000000000000000140311360521144700276340ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationCiftiCreateScalarSeries.h" #include "OperationException.h" #include "CaretLogger.h" #include "CiftiFile.h" #include "FloatMatrix.h" #include #include #include #include using namespace caret; using namespace std; AString OperationCiftiCreateScalarSeries::getCommandSwitch() { return "-cifti-create-scalar-series"; } AString OperationCiftiCreateScalarSeries::getShortDescription() { return "IMPORT SERIES DATA INTO CIFTI"; } OperationParameters* OperationCiftiCreateScalarSeries::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "input", "input file"); ret->addCiftiOutputParameter(2, "cifti-out", "output cifti file"); ret->createOptionalParameter(3, "-transpose", "use if the rows of the text file are along the scalar dimension"); OptionalParameter* nameFileOpt = ret->createOptionalParameter(4, "-name-file", "use a text file to set names on scalar dimension"); nameFileOpt->addStringParameter(1, "file", "text file containing names, one per line"); OptionalParameter* seriesOpt = ret->createOptionalParameter(5, "-series", "set the units and values of the series"); seriesOpt->addStringParameter(1, "unit", "the unit to use"); seriesOpt->addDoubleParameter(2, "start", "the value at the first series point"); seriesOpt->addDoubleParameter(3, "step", "the interval between series points"); AString myHelp = AString("Convert a text file containing series of equal length into a cifti file. ") + "The text file should have lines made up of numbers separated by whitespace, with no extra newlines between lines.\n\n" + "The argument must be one of the following:\n"; vector units = CiftiSeriesMap::getAllUnits(); for (int i = 0; i < (int)units.size(); ++i) { myHelp += "\n" + CiftiSeriesMap::unitToString(units[i]); } ret->setHelpText(myHelp); return ret; } void OperationCiftiCreateScalarSeries::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString inFileName = myParams->getString(1); CiftiFile* outFile = myParams->getOutputCifti(2); bool transpose = myParams->getOptionalParameter(3)->m_present; ifstream nameFile; OptionalParameter* nameFileOpt = myParams->getOptionalParameter(4); if (nameFileOpt->m_present) { nameFile.open(nameFileOpt->getString(1).toLocal8Bit().constData()); if (!nameFile) throw OperationException("failed to open name file"); } ifstream inputFile(inFileName.toLocal8Bit().constData()); vector > inFileData; if (!inputFile.good()) throw OperationException("failed to open input file '" + inFileName + "'"); string inputLine; while (inputFile) { getline(inputFile, inputLine); QStringList tokens = QString(inputLine.c_str()).split(QRegExp("\\s+"), QString::SkipEmptyParts); if (tokens.empty()) break;//in case there are extra newlines on the end if (!inFileData.empty() && (int)inFileData.back().size() != tokens.size()) throw OperationException("input file is not a rectangular matrix, starting at line " + AString::number(inFileData.size() + 2));//1 for 0-indexing, 1 for line not added to matrix yet inFileData.push_back(vector()); for (int i = 0; i < tokens.size(); ++i) { bool ok = false; inFileData.back().push_back(tokens[i].toFloat(&ok)); if (!ok) throw OperationException("input file contains non-number '" + tokens[i] + "'"); } } if (inFileData.empty() || inFileData[0].empty()) throw OperationException("input file contains no data"); if (transpose) { inFileData = FloatMatrix(inFileData).transpose().getMatrix(); } CiftiScalarsMap colMap; colMap.setLength(inFileData.size()); if (nameFileOpt->m_present) { for (int i = 0; i < (int)inFileData.size(); ++i) { getline(nameFile, inputLine); if (!nameFile) { CaretLogWarning("name file contained " + AString::number(i) + " names, expected " + AString::number(inFileData.size())); break; } colMap.setMapName(i, inputLine.c_str()); } } CiftiSeriesMap rowMap; rowMap.setLength(inFileData[0].size()); OptionalParameter* seriesOpt = myParams->getOptionalParameter(5); if (seriesOpt->m_present) { AString unitName = seriesOpt->getString(1); bool ok = false; CiftiSeriesMap::Unit myUnit = CiftiSeriesMap::stringToUnit(unitName, ok); if (!ok) { throw OperationException("unrecognized unit name: '" + unitName + "'"); } rowMap.setUnit(myUnit); rowMap.setStart(seriesOpt->getDouble(2)); rowMap.setStep(seriesOpt->getDouble(3)); } CiftiXML outXML; outXML.setNumberOfDimensions(2); outXML.setMap(CiftiXML::ALONG_ROW, rowMap); outXML.setMap(CiftiXML::ALONG_COLUMN, colMap); outFile->setCiftiXML(outXML); for (int i = 0; i < (int)inFileData.size(); ++i) { outFile->setRow(inFileData[i].data(), i); } } connectome-workbench-1.4.2/src/Operations/OperationCiftiCreateScalarSeries.h000066400000000000000000000027211360521144700272640ustar00rootroot00000000000000#ifndef __OPERATION_CIFTI_CREATE_SCALAR_SERIES_H__ #define __OPERATION_CIFTI_CREATE_SCALAR_SERIES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationCiftiCreateScalarSeries : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationCiftiCreateScalarSeries; } #endif //__OPERATION_CIFTI_CREATE_SCALAR_SERIES_H__ connectome-workbench-1.4.2/src/Operations/OperationCiftiEstimateFWHM.cxx000066400000000000000000000226561360521144700264010ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationCiftiEstimateFWHM.h" #include "OperationException.h" #include "AlgorithmCiftiSeparate.h" #include "AlgorithmMetricEstimateFWHM.h" #include "AlgorithmVolumeEstimateFWHM.h" #include "CaretPointer.h" #include "CiftiFile.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "VolumeFile.h" using namespace caret; using namespace std; AString OperationCiftiEstimateFWHM::getCommandSwitch() { return "-cifti-estimate-fwhm"; } AString OperationCiftiEstimateFWHM::getShortDescription() { return "ESTIMATE FWHM SMOOTHNESS OF A CIFTI FILE"; } OperationParameters* OperationCiftiEstimateFWHM::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti", "the input cifti file"); ret->createOptionalParameter(2, "-merged-volume", "treat volume components as if they were a single component"); OptionalParameter* columnOpt = ret->createOptionalParameter(3, "-column", "only output estimates for one column"); columnOpt->addIntegerParameter(1, "column", "the column number"); ParameterComponent* surfOpt = ret->createRepeatableParameter(4, "-surface", "specify an input surface"); surfOpt->addStringParameter(1, "structure", "what structure to use this surface for"); surfOpt->addSurfaceParameter(2, "surface", "the surface file"); OptionalParameter* wholeFileOpt = ret->createOptionalParameter(5, "-whole-file", "estimate for the whole file at once, not each column separately"); wholeFileOpt->createOptionalParameter(1, "-demean", "subtract the mean image before estimating smoothness"); AString myText = AString("Estimate the smoothness of the components of the cifti file, printing the estimates to standard output. ") + "If -merged-volume is used, all voxels are used as a single component, rather than separated by structure.\n\n" + " must be one of the following:\n"; vector myStructureEnums; StructureEnum::getAllEnums(myStructureEnums); for (int i = 0; i < (int)myStructureEnums.size(); ++i) { myText += "\n" + StructureEnum::toName(myStructureEnums[i]); } ret->setHelpText(myText); return ret; } struct VolParams { AString name; CaretPointer data, roi;//prevent copy in vector expansion }; struct SurfParams { AString name; SurfaceFile* surf; CaretPointer data, roi; }; void OperationCiftiEstimateFWHM::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); CiftiFile* myCifti = myParams->getCifti(1); bool mergedVol = myParams->getOptionalParameter(2)->m_present; int column = -1; OptionalParameter* columnOpt = myParams->getOptionalParameter(3); if (columnOpt->m_present) { column = columnOpt->getInteger(1) - 1;//compensate for 1-based UI indices if (column < 0 || column >= myCifti->getNumberOfColumns()) throw OperationException("invalid column index"); } const vector& surfInstances = *(myParams->getRepeatableParameterInstances(4)); int numInstances = (int)surfInstances.size(); for (int i = 0; i < numInstances; ++i) { bool ok = false; StructureEnum::fromName(surfInstances[i]->getString(1), &ok); if (!ok) throw OperationException("unrecognized structure name: " + surfInstances[i]->getString(1)); } bool wholeFile = false, demean = false; OptionalParameter* wholeFileOpt = myParams->getOptionalParameter(5); if (wholeFileOpt->m_present) { if (columnOpt->m_present) throw OperationException("specifying both -column and -whole-file is not allowed"); wholeFile = true; demean = wholeFileOpt->getOptionalParameter(1)->m_present; } vector volProcess; vector surfProcess; const CiftiXML& myXML = myCifti->getCiftiXML(); if (myXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) { throw OperationException("mapping type along column must be brain models"); } const CiftiBrainModelsMap& myMap = myXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); vector surfStructs = myMap.getSurfaceStructureList(), volStructs = myMap.getVolumeStructureList(); int numSurf = (int)surfStructs.size(); surfProcess.resize(numSurf); for (int i = 0; i < numSurf; ++i) { surfProcess[i].surf = NULL; for (int j = 0; j < numInstances; ++j) { StructureEnum::Enum myStruct = StructureEnum::fromName(surfInstances[j]->getString(1), NULL);//we already checked that this is a structure name if (myStruct == surfStructs[i]) { surfProcess[i].surf = surfInstances[j]->getSurface(2); break; } } if (surfProcess[i].surf == NULL) throw OperationException("missing surface for structure '" + StructureEnum::toName(surfStructs[i]) + "'"); surfProcess[i].name = StructureEnum::toName(surfStructs[i]); surfProcess[i].data.grabNew(new MetricFile()); surfProcess[i].roi.grabNew(new MetricFile()); AlgorithmCiftiSeparate(NULL, myCifti, CiftiXML::ALONG_COLUMN, surfStructs[i], surfProcess[i].data, surfProcess[i].roi); if (surfProcess[i].surf->getNumberOfNodes() != surfProcess[i].data->getNumberOfNodes()) { throw OperationException("input surface for structure '" + StructureEnum::toName(surfStructs[i]) + "' has different number of nodes than the cifti file"); } } if (mergedVol) { volProcess.resize(1); volProcess[0].name = "Voxels"; volProcess[0].data.grabNew(new VolumeFile()); volProcess[0].roi.grabNew(new VolumeFile()); int64_t offset[3]; AlgorithmCiftiSeparate(NULL, myCifti, CiftiXML::ALONG_COLUMN, volProcess[0].data, offset, volProcess[0].roi, true); } else { int numVol = (int)volStructs.size(); volProcess.resize(numVol); for (int i = 0; i < numVol; ++i) { volProcess[i].name = StructureEnum::toName(volStructs[i]); volProcess[i].data.grabNew(new VolumeFile()); volProcess[i].roi.grabNew(new VolumeFile()); int64_t offset[3]; AlgorithmCiftiSeparate(NULL, myCifti, CiftiXML::ALONG_COLUMN, volStructs[i], volProcess[i].data, offset, volProcess[i].roi, true); } } if (wholeFile) { for (int j = 0; j < (int)surfProcess.size(); ++j) { float fwhm = AlgorithmMetricEstimateFWHM::estimateFWHMAllColumns(surfProcess[j].surf, surfProcess[j].data, surfProcess[j].roi, demean); cout << surfProcess[j].name << " FWHM: " << fwhm << endl; } for (int j = 0; j < (int)volProcess.size(); ++j) { Vector3D fwhm = AlgorithmVolumeEstimateFWHM::estimateFWHMAllFrames(volProcess[j].data, volProcess[j].roi, demean); cout << volProcess[j].name << " FWHM: " << fwhm[0] << ", " << fwhm[1] << ", " << fwhm[2] << endl; } } else { if (column == -1) { int rowLength = (int)myCifti->getNumberOfColumns(); for (int i = 0; i < rowLength; ++i) { if (rowLength > 1) cout << "Column " << i + 1 << ":" << endl; for (int j = 0; j < (int)surfProcess.size(); ++j) { float fwhm = AlgorithmMetricEstimateFWHM::estimateFWHM(surfProcess[j].surf, surfProcess[j].data, surfProcess[j].roi, i); cout << surfProcess[j].name << " FWHM: " << fwhm << endl; } for (int j = 0; j < (int)volProcess.size(); ++j) { Vector3D fwhm = AlgorithmVolumeEstimateFWHM::estimateFWHM(volProcess[j].data, volProcess[j].roi, i); cout << volProcess[j].name << " FWHM: " << fwhm[0] << ", " << fwhm[1] << ", " << fwhm[2] << endl; } } } else { cout << "Column " << column + 1 << ":" << endl; for (int j = 0; j < (int)surfProcess.size(); ++j) { float fwhm = AlgorithmMetricEstimateFWHM::estimateFWHM(surfProcess[j].surf, surfProcess[j].data, surfProcess[j].roi, column); cout << surfProcess[j].name << " FWHM: " << fwhm << endl; } for (int j = 0; j < (int)volProcess.size(); ++j) { Vector3D fwhm = AlgorithmVolumeEstimateFWHM::estimateFWHM(volProcess[j].data, volProcess[j].roi, column); cout << volProcess[j].name << " FWHM: " << fwhm[0] << ", " << fwhm[1] << ", " << fwhm[2] << endl; } } } } connectome-workbench-1.4.2/src/Operations/OperationCiftiEstimateFWHM.h000066400000000000000000000026521360521144700260200ustar00rootroot00000000000000#ifndef __OPERATION_CIFTI_ESTIMATE_FWHM_H__ #define __OPERATION_CIFTI_ESTIMATE_FWHM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationCiftiEstimateFWHM : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationCiftiEstimateFWHM; } #endif //__OPERATION_CIFTI_ESTIMATE_FWHM_H__ connectome-workbench-1.4.2/src/Operations/OperationCiftiExportDenseMapping.cxx000066400000000000000000000210561360521144700277110ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationCiftiExportDenseMapping.h" #include "OperationException.h" #include "CiftiFile.h" #include "CiftiXML.h" #include using namespace caret; using namespace std; AString OperationCiftiExportDenseMapping::getCommandSwitch() { return "-cifti-export-dense-mapping"; } AString OperationCiftiExportDenseMapping::getShortDescription() { return "WRITE INDEX TO ELEMENT MAPPING AS TEXT"; } OperationParameters* OperationCiftiExportDenseMapping::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti", "the cifti file"); ret->addStringParameter(2, "direction", "which direction to export the mapping from, ROW or COLUMN");//TODO: 3rd+ dimension ParameterComponent* surfOpt = ret->createRepeatableParameter(3, "-surface", "export the the mapping of one surface structure"); surfOpt->addStringParameter(1, "structure", "the structure to output"); surfOpt->addStringParameter(2, "text-out", "output - the output text file");//fake the output formatting surfOpt->createOptionalParameter(3, "-no-cifti-index", "don't write the cifti index in the output file"); ParameterComponent* volOpt = ret->createRepeatableParameter(4, "-volume", "export the the mapping of one volume structure"); volOpt->addStringParameter(1, "structure", "the structure to output"); volOpt->addStringParameter(2, "text-out", "output - the output text file");//fake the output formatting volOpt->createOptionalParameter(3, "-no-cifti-index", "don't write the cifti index in the output file"); OptionalParameter* volAllOpt = ret->createOptionalParameter(5, "-volume-all", "export the the mapping of all voxels");//repeatable, for different options? volAllOpt->addStringParameter(1, "text-out", "output - the output text file");//fake the output formatting volAllOpt->createOptionalParameter(2, "-no-cifti-index", "don't write the cifti index in the output file"); volAllOpt->createOptionalParameter(3, "-structure", "write the structure each voxel belongs to in the output file"); //-surface-all? -all? AString helpText = AString("This command produces text files that describe the mapping from cifti indices to surface vertices or voxels. ") + "All indices are zero-based. " + "The default format for -surface is lines of the form:\n\n" + " \n\n" + "The default format for -volume and -volume-all is lines of the form:\n\n" + " \n\n" + "For each argument, use one of the following strings:\n"; vector myStructureEnums; StructureEnum::getAllEnums(myStructureEnums); for (int i = 0; i < (int)myStructureEnums.size(); ++i) { helpText += "\n" + StructureEnum::toName(myStructureEnums[i]); } ret->setHelpText(helpText); return ret; } void OperationCiftiExportDenseMapping::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); CiftiFile* myCifti = myParams->getCifti(1); AString dirString = myParams->getString(2); int myDir; if (dirString == "ROW") { myDir = CiftiXML::ALONG_ROW; } else if (dirString == "COLUMN") { myDir = CiftiXML::ALONG_COLUMN; } else { throw OperationException("incorrect string for direction, use ROW or COLUMN"); } const vector& surfOpts = *(myParams->getRepeatableParameterInstances(3)); const vector& volOpts = *(myParams->getRepeatableParameterInstances(4)); OptionalParameter* volAllOpt = myParams->getOptionalParameter(5); const CiftiXML& myXML = myCifti->getCiftiXML(); if (myXML.getMappingType(myDir) != CiftiMappingType::BRAIN_MODELS) throw OperationException("specified direction in cifti file does not have BRAIN_MODELS mapping"); const CiftiBrainModelsMap& myDenseMap = myXML.getBrainModelsMap(myDir); for (int i = 0; i < (int)surfOpts.size(); ++i) { AString structName = surfOpts[i]->getString(1); bool ok = false; StructureEnum::Enum myStruct = StructureEnum::fromName(structName, &ok); if (!ok) throw OperationException("invalid structure name: '" + structName + "'"); if (!myDenseMap.hasSurfaceData(myStruct)) throw OperationException("no surface mapping found in specified direction for structure '" + structName + "'"); AString outName = surfOpts[i]->getString(2); bool writeCiftiIndex = !(surfOpts[i]->getOptionalParameter(3)->m_present); ofstream outFile(outName.toLocal8Bit().constData()); if (!outFile) throw OperationException("failed to open output text file"); vector myMap = myDenseMap.getSurfaceMap(myStruct); for (int j = 0; j < (int)myMap.size(); ++j) { if (writeCiftiIndex) outFile << myMap[j].m_ciftiIndex << " "; outFile << myMap[j].m_surfaceNode << "\n";//avoid endl so it doesn't constantly flush } outFile.flush(); if (!outFile) throw OperationException("failed to write to output text file"); } for (int i = 0; i < (int)volOpts.size(); ++i) { AString structName = volOpts[i]->getString(1); bool ok = false; StructureEnum::Enum myStruct = StructureEnum::fromName(structName, &ok); if (!ok) throw OperationException("invalid structure name: '" + structName + "'"); if (!myDenseMap.hasVolumeData(myStruct)) throw OperationException("no volume mapping found in specified direction for structure '" + structName + "'"); AString outName = volOpts[i]->getString(2); bool writeCiftiIndex = !(volOpts[i]->getOptionalParameter(3)->m_present); ofstream outFile(outName.toLocal8Bit().constData()); if (!outFile) throw OperationException("failed to open output text file"); vector myMap = myDenseMap.getVolumeStructureMap(myStruct); for (int j = 0; j < (int)myMap.size(); ++j) { if (writeCiftiIndex) outFile << myMap[j].m_ciftiIndex << " "; outFile << myMap[j].m_ijk[0] << " " << myMap[j].m_ijk[1] << " " << myMap[j].m_ijk[2] << "\n";//avoid endl so it doesn't constantly flush } outFile.flush(); if (!outFile) throw OperationException("failed to write to output text file"); } if (volAllOpt->m_present) { if (!myDenseMap.hasVolumeData()) throw OperationException("no volume data found in specified direction"); AString outName = volAllOpt->getString(1); bool writeCiftiIndex = !(volAllOpt->getOptionalParameter(2)->m_present); bool writeStructure = volAllOpt->getOptionalParameter(3)->m_present; ofstream outFile(outName.toLocal8Bit().constData()); if (!outFile) throw OperationException("failed to open output text file"); vector volStructs = myDenseMap.getVolumeStructureList();//NOTE: CiftiBrainModelsMap guarantees this is in cifti index order for (int j = 0; j < (int)volStructs.size(); ++j) { vector myMap = myDenseMap.getVolumeStructureMap(volStructs[j]); AString structName = StructureEnum::toName(volStructs[j]); for (int k = 0; k < (int)myMap.size(); ++k) { if (writeCiftiIndex) outFile << myMap[k].m_ciftiIndex << " "; if (writeStructure) outFile << structName << " "; outFile << myMap[k].m_ijk[0] << " " << myMap[k].m_ijk[1] << " " << myMap[k].m_ijk[2] << "\n";//avoid endl so it doesn't constantly flush } } outFile.flush(); if (!outFile) throw OperationException("failed to write to output text file"); } } connectome-workbench-1.4.2/src/Operations/OperationCiftiExportDenseMapping.h000066400000000000000000000027211360521144700273340ustar00rootroot00000000000000#ifndef __OPERATION_CIFTI_EXPORT_DENSE_MAPPING_H__ #define __OPERATION_CIFTI_EXPORT_DENSE_MAPPING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationCiftiExportDenseMapping : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationCiftiExportDenseMapping; } #endif //__OPERATION_CIFTI_EXPORT_DENSE_MAPPING_H__ connectome-workbench-1.4.2/src/Operations/OperationCiftiLabelExportTable.cxx000066400000000000000000000074131360521144700273270ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationCiftiLabelExportTable.h" #include "OperationException.h" #include "CiftiFile.h" #include "GiftiLabel.h" //we should rename these to not imply that they are gifti-specific #include "GiftiLabelTable.h" #include #include using namespace caret; using namespace std; AString OperationCiftiLabelExportTable::getCommandSwitch() { return "-cifti-label-export-table"; } AString OperationCiftiLabelExportTable::getShortDescription() { return "EXPORT LABEL TABLE FROM CIFTI AS TEXT"; } OperationParameters* OperationCiftiLabelExportTable::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "label-in", "the input cifti label file"); ret->addStringParameter(2, "map", "the number or name of the label map to use"); ret->addStringParameter(3, "table-out", "output - the output text file");//fake output formatting ret->setHelpText( AString("Takes the label table from the cifti label map, and writes it to a text format matching what is expected by -cifti-label-import.") ); return ret; } int OperationCiftiLabelExportTable::floatTo255(const float& in) { return (int)floor(in * 255.0f + 0.5f); } void OperationCiftiLabelExportTable::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); CiftiFile* myCifti = myParams->getCifti(1); AString mapString = myParams->getString(2); AString outfileName = myParams->getString(3); const CiftiXML& myXML = myCifti->getCiftiXML(); if (myXML.getMappingType(CiftiXML::ALONG_ROW) != CiftiMappingType::LABELS) throw OperationException("cifti file must have LABELS mapping along row"); const CiftiLabelsMap& myLabelsMap = myXML.getLabelsMap(CiftiXML::ALONG_ROW); int64_t mapIndex = myLabelsMap.getIndexFromNumberOrName(mapString); if (mapIndex == -1) throw OperationException("map '" + mapString + "' not found in label map"); ofstream outFile(outfileName.toLocal8Bit().constData()); if (!outFile) throw OperationException("failed to open output text file"); const GiftiLabelTable* myTable = myLabelsMap.getMapLabelTable(mapIndex); set allKeys = myTable->getKeys(); int32_t unassignedKey = myTable->getUnassignedLabelKey(); for (set::iterator iter = allKeys.begin(); iter != allKeys.end(); ++iter) { if (*iter == unassignedKey) continue;//don't output the unused key, because import doesn't want it in the text file const GiftiLabel* thisLabel = myTable->getLabel(*iter); outFile << thisLabel->getName() << endl; outFile << thisLabel->getKey() << " " << floatTo255(thisLabel->getRed()) << " " << floatTo255(thisLabel->getGreen()) << " " << floatTo255(thisLabel->getBlue()) << " " << floatTo255(thisLabel->getAlpha()) << endl; if (!outFile) throw OperationException("error writing to output text file"); } } connectome-workbench-1.4.2/src/Operations/OperationCiftiLabelExportTable.h000066400000000000000000000027651360521144700267610ustar00rootroot00000000000000#ifndef __OPERATION_CIFTI_LABEL_EXPORT_TABLE_H__ #define __OPERATION_CIFTI_LABEL_EXPORT_TABLE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationCiftiLabelExportTable : public AbstractOperation { static int floatTo255(const float& in); public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationCiftiLabelExportTable; } #endif //__OPERATION_CIFTI_LABEL_EXPORT_TABLE_H__ connectome-workbench-1.4.2/src/Operations/OperationCiftiLabelImport.cxx000066400000000000000000000317671360521144700263610ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationCiftiLabelImport.h" #include "OperationException.h" #include "CaretLogger.h" #include "CiftiFile.h" #include "FileInformation.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include #include #include #include #include #include #include #include using namespace caret; using namespace std; AString OperationCiftiLabelImport::getCommandSwitch() { return "-cifti-label-import"; } AString OperationCiftiLabelImport::getShortDescription() { return "MAKE A CIFTI LABEL FILE FROM A CIFTI FILE"; } OperationParameters* OperationCiftiLabelImport::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "input", "the input cifti file"); ret->addStringParameter(2, "label-list-file", "text file containing the values and names for labels"); ret->addCiftiOutputParameter(3, "output", "the output cifti label file"); ret->createOptionalParameter(4, "-discard-others", "set any values not mentioned in the label list to the ??? label"); OptionalParameter* unlabeledOption = ret->createOptionalParameter(5, "-unlabeled-value", "set the value that will be interpreted as unlabeled"); unlabeledOption->addIntegerParameter(1, "value", "the numeric value for unlabeled (default 0)"); ret->createOptionalParameter(6, "-drop-unused-labels", "remove any unused label values from the label table"); ret->setHelpText( AString("Creates a cifti label file from a cifti file with label-like values. ") + "You may specify the empty string (use \"\") for , which will be treated as if it is an empty file. " + "The label list file must have the following format (2 lines per label):\n\n" + "\n \n...\n\n" + "Label names are specified on a separate line from their value and color, in order to let label names contain spaces. " + "Whitespace is trimmed from both ends of the label name, but is kept if it is in the middle of a label. " + "Do not specify the \"unlabeled\" key in the file, it is assumed that 0 means not labeled unless -unlabeled-value is specified. " + "The value of specifies what value in the imported file should be used as this label. " + "The values of , , and must be integers from 0 to 255, and will specify the color the label is drawn as " + "(alpha of 255 means fully opaque, which is probably what you want).\n\n" + "By default, it will create new label names with names like LABEL_5 for any values encountered that are not mentioned in the " + "list file, specify -discard-others to instead set these values to the \"unlabeled\" key." ); return ret; } void OperationCiftiLabelImport::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); CiftiFile* ciftiIn = myParams->getCifti(1); AString listfileName = myParams->getString(2); CiftiFile* ciftiOut = myParams->getOutputCifti(3); bool discardOthers = myParams->getOptionalParameter(4)->m_present; int32_t unlabeledValue = 0; OptionalParameter* unlabeledOption = myParams->getOptionalParameter(5); if (unlabeledOption->m_present) { unlabeledValue = (int32_t)unlabeledOption->getInteger(1); } bool dropUnused = myParams->getOptionalParameter(6)->m_present; map translate; GiftiLabelTable myTable; if (listfileName != "") { AString temp; FileInformation textFileInfo(listfileName); if (!textFileInfo.exists()) { throw OperationException("label list file doesn't exist"); } fstream labelListFile(listfileName.toLocal8Bit().constData(), fstream::in); if (!labelListFile.good()) { throw OperationException("error reading label list file"); } string labelName; int32_t value, red, green, blue, alpha; int labelCount = 0; translate[unlabeledValue] = 0;//placeholder, we don't know the correct translated value yet while (labelListFile.good()) { ++labelCount;//just for error messages, so start at 1 getline(labelListFile, labelName); labelListFile >> value; if (labelListFile.eof() && labelName == "") break;//if end of file trying to read an int, and label name is empty, its really just end of file labelListFile >> red; labelListFile >> green; labelListFile >> blue; if (!(labelListFile >> alpha))//yes, that is seriously the correct way to check if input was successfully extracted...so much fail { throw OperationException("label list file is malformed for entry #" + AString::number(labelCount) + ": " + AString(labelName.c_str())); } if (red < 0 || red > 255) { throw OperationException("bad value for red for entry #" + AString::number(labelCount) + ", " + AString(labelName.c_str()) + ": " + AString::number(red)); } if (green < 0 || green > 255) { throw OperationException("bad value for green for entry #" + AString::number(labelCount) + ", " + AString(labelName.c_str()) + ": " + AString::number(green)); } if (blue < 0 || blue > 255) { throw OperationException("bad value for blue for entry #" + AString::number(labelCount) + ", " + AString(labelName.c_str()) + ": " + AString::number(blue)); } if (alpha < 0 || alpha > 255) { throw OperationException("bad value for alpha for entry #" + AString::number(labelCount) + ", " + AString(labelName.c_str()) + ": " + AString::number(alpha)); } if (value == GiftiLabel::getInvalidLabelKey()) { throw OperationException("entry #" + AString::number(labelCount) + ", " + AString(labelName.c_str()) + " specifies unusable key value: " + value); } while (isspace(labelListFile.peek())) { labelListFile.ignore();//drop the newline, possible carriage return or other whitespace so that getline doesn't get nothing, and cause int extraction to fail } temp = AString(labelName.c_str()).trimmed();//drop errant CR or other whitespace from beginning and end of lines if (translate.find(value) != translate.end()) { if (value == unlabeledValue) { throw OperationException("the unlabeled value must not be specified in label list file"); } else { throw OperationException(AString("label key ") + AString::number(value) + " specified more than once"); } } GiftiLabel myLabel(value, temp, red, green, blue, alpha); if (myTable.getLabelKeyFromName(temp) != GiftiLabel::getInvalidLabelKey()) { AString nameBase = temp, newName;//resolve collision by generating a name with an additional number on it bool success = false; for (int extra = 1; extra < 100; ++extra)//but stop at 100, because really... { newName = nameBase + "_" + AString::number(extra); if (myTable.getLabelKeyFromName(newName) == GiftiLabel::getInvalidLabelKey()) { success = true; break; } } if (success) { CaretLogWarning("name collision in input name '" + nameBase + "', changing one to '" + newName + "'"); } else { throw OperationException("giving up on resolving name collision for input name '" + nameBase + "'"); } myLabel.setName(newName); } int32_t newValue; if (value == 0)//because label 0 exists in the default constructed table { myTable.insertLabel(&myLabel);//but we do want to be able to overwrite the default 0 label newValue = 0;//if value 0 is specified twice, or once without specifying a different unlabeled value, the check versus the translate map will catch it } else { newValue = myTable.addLabel(&myLabel);//we don't want to overwrite relocated labels } translate[value] = newValue; } } int32_t unusedLabel = myTable.getUnassignedLabelKey(); translate[unlabeledValue] = unusedLabel; const CiftiXMLOld& xmlIn = ciftiIn->getCiftiXMLOld(); int rowSize = xmlIn.getNumberOfColumns(), colSize = xmlIn.getNumberOfRows(); CiftiXMLOld xmlOut = xmlIn; xmlOut.resetRowsToLabels(rowSize); vector > usedArray(rowSize); vector rowScratch(rowSize); vector > matrixOut(colSize, vector(rowSize));//because the label table gets modified as we scan values, store the translated values instead of going back for a second pass for (int row = 0; row < colSize; ++row) { ciftiIn->getRow(rowScratch.data(), row); for (int col = 0; col < rowSize; ++col) { int32_t labelval = (int32_t)floor(rowScratch[col] + 0.5f);//just in case it somehow got poorly encoded, round to nearest if (dropUnused) { usedArray[col].insert(labelval); } map::iterator myiter = translate.find(labelval); if (myiter == translate.end()) { if (discardOthers) { matrixOut[row][col] = unusedLabel; } else {//use a random color, but fully opaque for the label GiftiLabel myLabel(labelval, AString("LABEL_") + AString::number(labelval), rand() & 255, rand() & 255, rand() & 255, 255); if (myTable.getLabelKeyFromName(myLabel.getName()) != GiftiLabel::getInvalidLabelKey()) { AString nameBase = myLabel.getName(), newName;//resolve collision by generating a name with an additional number on it bool success = false; for (int extra = 1; extra < 100; ++extra)//but stop at 100, because really... { newName = nameBase + "_" + AString::number(extra); if (myTable.getLabelKeyFromName(newName) == GiftiLabel::getInvalidLabelKey()) { success = true; break; } } if (success) { CaretLogWarning("name collision in auto-generated name '" + nameBase + "', changed to '" + newName + "'"); } else { throw OperationException("giving up on resolving name collision for auto-generated name '" + nameBase + "'"); } myLabel.setName(newName); } int32_t newValue = myTable.addLabel(&myLabel);//don't overwrite any values in the table translate[labelval] = newValue; matrixOut[row][col] = newValue; } } else { matrixOut[row][col] = myiter->second; } } } for (int i = 0; i < rowSize; ++i) { xmlOut.setMapNameForIndex(CiftiXMLOld::ALONG_ROW, i, xmlIn.getMapName(CiftiXMLOld::ALONG_ROW, i)); if (dropUnused) { GiftiLabelTable colTable = myTable; colTable.deleteUnusedLabels(usedArray[i]); *(xmlOut.getMapLabelTable(CiftiXMLOld::ALONG_ROW, i)) = colTable; } else { *(xmlOut.getMapLabelTable(CiftiXMLOld::ALONG_ROW, i)) = myTable; } } ciftiOut->setCiftiXML(xmlOut); for (int row = 0; row < colSize; ++row) { ciftiOut->setRow(matrixOut[row].data(), row); } } connectome-workbench-1.4.2/src/Operations/OperationCiftiLabelImport.h000066400000000000000000000026441360521144700257760ustar00rootroot00000000000000#ifndef __OPERATION_CIFTI_LABEL_IMPORT_H__ #define __OPERATION_CIFTI_LABEL_IMPORT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationCiftiLabelImport : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationCiftiLabelImport; } #endif //__OPERATION_CIFTI_LABEL_IMPORT_H__ connectome-workbench-1.4.2/src/Operations/OperationCiftiMath.cxx000066400000000000000000000352461360521144700250340ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationCiftiMath.h" #include "OperationException.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretMathExpression.h" #include "CiftiFile.h" #include "CiftiXML.h" #include "MultiDimIterator.h" #include using namespace caret; using namespace std; AString OperationCiftiMath::getCommandSwitch() { return "-cifti-math"; } AString OperationCiftiMath::getShortDescription() { return "EVALUATE EXPRESSION ON CIFTI FILES"; } OperationParameters* OperationCiftiMath::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "expression", "the expression to evaluate, in quotes"); ret->addCiftiOutputParameter(2, "cifti-out", "the output cifti file"); ParameterComponent* varOpt = ret->createRepeatableParameter(3, "-var", "a cifti file to use as a variable"); varOpt->addStringParameter(1, "name", "the name of the variable, as used in the expression"); varOpt->addCiftiParameter(2, "cifti", "the cifti file to use as this variable"); ParameterComponent* selectOpt = varOpt->createRepeatableParameter(3, "-select", "select a single index from a dimension");//repeatable option to repeatable option selectOpt->addIntegerParameter(1, "dim", "the dimension to select from (1-based)"); selectOpt->addIntegerParameter(2, "index", "the index to use (1-based)"); selectOpt->createOptionalParameter(3, "-repeat", "repeat the selected values for each index of output in this dimension");//with a repeat option OptionalParameter* fixNanOpt = ret->createOptionalParameter(4, "-fixnan", "replace NaN results with a value"); fixNanOpt->addDoubleParameter(1, "replace", "value to replace NaN with"); ret->createOptionalParameter(5, "-override-mapping-check", "don't check the mappings for compatibility, only check length"); AString myText = AString("This command evaluates at each matrix element independently. ") + "There must be at least one -var option (to get the output layout from), even if the specified in it isn't used in .\n\n" + "To select a single column from a 2D file (most cifti files are 2D), use -select 1 , where is 1-based. " + "To select a single row from a 2D file, use -select 2 . " + "Where -select is not used, the cifti files must have compatible mappings (e.g., brain models and parcels mappings must match exactly except for parcel names). " + "Use -override-mapping-check to skip this checking.\n\n" + "Filenames are not valid in , use a variable name and a -var option with matching to specify an input file. " + "The format of is as follows:\n\n"; myText += CaretMathExpression::getExpressionHelpInfo(); ret->setHelpText(myText); return ret; } void OperationCiftiMath::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString expression = myParams->getString(1); CaretMathExpression myExpr(expression); cout << "parsed '" + expression + "' as '" + myExpr.toString() + "'" << endl; vector myVarNames = myExpr.getVarNames(); CiftiFile* myCiftiOut = myParams->getOutputCifti(2); const vector& myVarOpts = *(myParams->getRepeatableParameterInstances(3)); OptionalParameter* fixNanOpt = myParams->getOptionalParameter(4); bool nanfix = false; float nanfixval = 0; if (fixNanOpt->m_present) { nanfix = true; nanfixval = (float)fixNanOpt->getDouble(1); } bool overrideMapCheck = myParams->getOptionalParameter(5)->m_present; int numInputs = myVarOpts.size(); int numVars = myVarNames.size(); vector varCiftiFiles(numVars, (CiftiFile*)NULL); if (numInputs == 0 && numVars == 0) throw OperationException("you must specify at least one input file (-var), even if the expression doesn't use a variable"); CiftiXML outXML; QString xmlText; vector outDims;//don't even assume 2 dimensions, in case someone makes a 1-d cifti vector > selectInfo(numVars); for (int i = 0; i < numInputs; ++i) { AString varName = myVarOpts[i]->getString(1); double constVal; if (CaretMathExpression::getNamedConstant(varName, constVal)) { throw OperationException("'" + varName + "' is a named constant equal to " + AString::number(constVal, 'g', 15) + ", please use a different variable name"); } const CiftiXML& tempXML = myVarOpts[i]->getCifti(2)->getCiftiXML(); int thisNumDims = tempXML.getNumberOfDimensions(); vector thisSelectInfo(thisNumDims, -1); vector thisRepeat(thisNumDims, false); const vector& thisSelectOpts = *(myVarOpts[i]->getRepeatableParameterInstances(3)); for (int j = 0; j < (int)thisSelectOpts.size(); ++j) { int dim = (int)thisSelectOpts[j]->getInteger(1) - 1; int64_t thisIndex = thisSelectOpts[j]->getInteger(2) - 1; if (dim >= (int)thisSelectInfo.size()) { if (thisIndex != 0) throw OperationException("-select used for variable '" + varName + "' with index other than 1 on nonexistent dimension"); thisSelectInfo.resize(dim + 1, -1); thisRepeat.resize(dim + 1, false); } thisSelectInfo[dim] = thisIndex; thisRepeat[dim] = thisSelectOpts[j]->getOptionalParameter(3)->m_present; } bool found = false; for (int j = 0; j < numVars; ++j) { if (varName == myVarNames[j]) { if (varCiftiFiles[j] != NULL) throw OperationException("variable '" + varName + "' specified more than once"); found = true; varCiftiFiles[j] = myVarOpts[i]->getCifti(2); selectInfo[j] = thisSelectInfo;//copy selection info break; } } if (!found && (numVars != 0 || numInputs != 1))//supress warning when a single -var is used with a constant expression, as required per help { CaretLogWarning("variable '" + varName + "' not used in expression"); } int newNumDims = (int)max(thisSelectInfo.size(), outDims.size());//now, to figure out the output dimensions with -select and -repeat for (int j = 0; j < newNumDims; ++j) { if (j >= (int)outDims.size())//need to expand output dimensions { outXML.setNumberOfDimensions(j + 1);//does not clear existing mappings outDims.push_back(-1);//unknown length } if (j >= (int)thisSelectInfo.size())//need to expand input info { thisSelectInfo.push_back(-1);//use "all" indices, but there is only 1 (virtual) index, pushing 0 should have same effect thisRepeat.push_back(false);//repeat not specified } if (outDims[j] == -1)//if we don't know the output length yet, put it in if we have it (-repeat not specified) { if (thisSelectInfo[j] == -1)//no -select for this dimension, use all maps { if (j < thisNumDims) { outDims[j] = tempXML.getDimensionLength(j); outXML.setMap(j, *(tempXML.getMap(j)));//copy the mapping type, since this input defines this dimension } else {//if higher dimension than the file has, transparently say it is of length 1, and don't use the mapping outDims[j] = 1; } } else {//-select was used if (!thisRepeat[j])//if -repeat wasn't used, output length is 1 { outDims[j] = 1; } } } else { if (thisSelectInfo[j] == -1)//-select was not used { if (j < thisNumDims) { if (outDims[j] != tempXML.getDimensionLength(j)) { throw OperationException("variable '" + varName + "' has length " + AString::number(tempXML.getDimensionLength(j)) + " for dimension " + AString::number(j + 1) + " while previous -var options require a length of " + AString::number(outDims[j])); } if (outXML.getMap(j) == NULL)//dimension was set to 1 by -select, but didn't set a mapping, so borrow from here { outXML.setMap(j, *(tempXML.getMap(j))); } else {//test mapping types for compatibility since -select wasn't used AString explanation; if (!overrideMapCheck && !outXML.getMap(j)->approximateMatch(*(tempXML.getMap(j)), &explanation)) { throw OperationException("variable " + varName + "'s " + CiftiMappingType::mappingTypeToName(tempXML.getMap(j)->getType()) + " mapping on dimension " + AString::number(j + 1) + " doesn't match mappings from earlier -var options: '" + explanation + "'"); } } } else { if (outDims[j] != 1) { throw OperationException(AString("variable '" + varName + "' is of lower dimensionality than output, ") + "and the length of output dimension " + AString::number(j + 1) + " is " + AString::number(outDims[j]) + ", you might want to use -select with -repeat"); } } } else { if (!thisRepeat[j]) { if (outDims[j] != 1) { throw OperationException("variable '" + varName + "' uses -select for dimension " + AString::number(j + 1) + ", but previous -var options require a length of " + AString::number(outDims[j])); } } } } } } for (int i = 0; i < numVars; ++i) { if (varCiftiFiles[i] == NULL) throw OperationException("no -var option specified for variable '" + myVarNames[i] + "'"); } CiftiScalarsMap dummyMap;//make an empty length-1 scalar map for dimensions we don't have a mapping for dummyMap.setLength(1); for (int i = 0; i < outXML.getNumberOfDimensions(); ++i) { if (outDims[i] == -1) throw OperationException("all -var options used -select and -repeat for dimension " + AString::number(i + 1) + ", there is no file to get the dimension length from"); if (outXML.getMap(i) == NULL)//-select was used in all variables for this dimension, so we don't have a mapping { outXML.setMap(i, dummyMap);//so, make it a length-1 scalar with no name and empty metadata } CaretAssert(outDims[i] == outXML.getDimensionLength(i)); } if (outXML.getNumberOfDimensions() < 1) throw OperationException("output must have at least 1 dimension"); myCiftiOut->setCiftiXML(outXML); vector values(numVars), scratchRow(outDims[0]); vector > inputRows(numVars); vector > loadedRow(numVars);//to detect and prevent rereading the same row for (int v = 0; v < numVars; ++v) { inputRows[v].resize(varCiftiFiles[v]->getCiftiXML().getDimensionLength(CiftiXML::ALONG_ROW)); loadedRow[v].resize(varCiftiFiles[v]->getCiftiXML().getNumberOfDimensions() - 1, -1);//we always load a full row, so ignore first dim } for (MultiDimIterator iter(vector(outDims.begin() + 1, outDims.end())); !iter.atEnd(); ++iter) { for (int v = 0; v < numVars; ++v)//first, retrieve whichever rows are needed { bool needToLoad = false; for (int dim = 0; dim < (int)loadedRow[v].size(); ++dim) { int64_t indexNeeded = -1; if (selectInfo[v][dim + 1] == -1) { CaretAssert(dim + 1 < (int)outDims.size());//"match to output index" can't work past output dimensionality indexNeeded = (*iter)[dim];//NOTE: iter also doesn't include the first dim } else { indexNeeded = selectInfo[v][dim + 1]; } if (indexNeeded != loadedRow[v][dim]) { needToLoad = true; loadedRow[v][dim] = indexNeeded; } } if (needToLoad) { varCiftiFiles[v]->getRow(inputRows[v].data(), loadedRow[v]); } } for (int j = 0; j < outDims[0]; ++j) { for (int v = 0; v < numVars; ++v)//now we check for select along row { if (selectInfo[v][0] == -1) { values[v] = inputRows[v][j]; } else { values[v] = inputRows[v][selectInfo[v][0]]; } } scratchRow[j] = (float)myExpr.evaluate(values); if (nanfix && scratchRow[j] != scratchRow[j]) { scratchRow[j] = nanfixval; } } myCiftiOut->setRow(scratchRow.data(), *iter); } } connectome-workbench-1.4.2/src/Operations/OperationCiftiMath.h000066400000000000000000000025671360521144700244610ustar00rootroot00000000000000#ifndef __OPERATION_CIFTI_MATH_H__ #define __OPERATION_CIFTI_MATH_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationCiftiMath : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationCiftiMath; } #endif //__OPERATION_CIFTI_MATH_H__ connectome-workbench-1.4.2/src/Operations/OperationCiftiMerge.cxx000066400000000000000000000410301360521144700251660ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationCiftiMerge.h" #include "OperationException.h" #include "CaretAssert.h" #include "CaretPointer.h" #include "CiftiFile.h" #include using namespace caret; using namespace std; AString OperationCiftiMerge::getCommandSwitch() { return "-cifti-merge"; } AString OperationCiftiMerge::getShortDescription() { return "MERGE CIFTI TIMESERIES, SCALAR, OR LABEL FILES"; } OperationParameters* OperationCiftiMerge::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiOutputParameter(1, "cifti-out", "output cifti file"); ParameterComponent* ciftiOpt = ret->createRepeatableParameter(2, "-cifti", "specify an input cifti file"); ciftiOpt->addStringParameter(1, "cifti-in", "a cifti file to use columns from"); ParameterComponent* columnOpt = ciftiOpt->createRepeatableParameter(2, "-column", "select a single column to use"); columnOpt->addStringParameter(1, "column", "the column number (starting from 1) or name"); OptionalParameter* upToOpt = columnOpt->createOptionalParameter(2, "-up-to", "use an inclusive range of columns"); upToOpt->addStringParameter(1, "last-column", "the number or name of the last column to include"); upToOpt->createOptionalParameter(2, "-reverse", "use the range in reverse order"); ret->setHelpText( AString("Given input CIFTI files which have matching mappings along columns, and for which mappings along rows ") + "are the same type, all either series, scalars, or labels, this command concatenates the specified columns horizontally (rows become longer).\n\n" + "Example: wb_command -cifti-merge out.dtseries.nii -cifti first.dtseries.nii -column 1 -cifti second.dtseries.nii\n\n" + "This example would take the first column from first.dtseries.nii, followed by all columns from second.dtseries.nii, " + "and write these columns to out.dtseries.nii." ); return ret; } void OperationCiftiMerge::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); CiftiFile* ciftiOut = myParams->getOutputCifti(1); const vector& myInputs = *(myParams->getRepeatableParameterInstances(2)); int numInputs = (int)myInputs.size(); if (numInputs == 0) throw OperationException("no inputs specified"); vector ciftiList(numInputs); ciftiList[0].openFile(myInputs[0]->getString(1)); const CiftiFile* firstCifti = &(ciftiList[0]); const CiftiXML& baseXML = firstCifti->getCiftiXML(); if (baseXML.getNumberOfDimensions() != 2) throw OperationException("only 2D cifti are supported"); const CiftiMappingType& baseColMapping = *(baseXML.getMap(CiftiXML::ALONG_COLUMN)), &baseRowMapping = *(baseXML.getMap(CiftiXML::ALONG_ROW)); switch (baseRowMapping.getType()) { case CiftiMappingType::SCALARS: case CiftiMappingType::LABELS: case CiftiMappingType::SERIES: break; default: throw OperationException("row mapping type must be series, scalars, or labels"); } int64_t numOutColumns = 0;//output row length for (int i = 0; i < numInputs; ++i) { if (i != 0) { ciftiList[i].openFile(myInputs[i]->getString(1)); } const CiftiFile* ciftiIn = &(ciftiList[i]); vector thisDims = ciftiIn->getDimensions(); const CiftiXML& thisXML = ciftiIn->getCiftiXML(); if (thisXML.getNumberOfDimensions() != 2) throw OperationException("only 2D cifti are supported"); if (!thisXML.getMap(CiftiXML::ALONG_COLUMN)->approximateMatch(baseColMapping)) throw OperationException("file '" + ciftiIn->getFileName() + "' has non-matching mapping along columns"); if (thisXML.getMappingType(CiftiXML::ALONG_ROW) != baseRowMapping.getType()) throw OperationException("file '" + ciftiIn->getFileName() + "' has different mapping type along rows"); const vector& columnOpts = *(myInputs[i]->getRepeatableParameterInstances(2)); int numColumnOpts = (int)columnOpts.size(); if (numColumnOpts > 0) { for (int j = 0; j < numColumnOpts; ++j) { int64_t initialColumn = thisXML.getMap(CiftiXML::ALONG_ROW)->getIndexFromNumberOrName(columnOpts[j]->getString(1));//this function has the 1-indexing convention built in if (initialColumn < 0 || initialColumn >= thisDims[0]) throw OperationException("column '" + columnOpts[j]->getString(1) + "' not valid in file '" + ciftiIn->getFileName() + "'"); OptionalParameter* upToOpt = columnOpts[j]->getOptionalParameter(2); if (upToOpt->m_present) { int finalColumn = thisXML.getMap(CiftiXML::ALONG_ROW)->getIndexFromNumberOrName(upToOpt->getString(1));//ditto if (finalColumn < 0 || finalColumn >= thisDims[0]) throw OperationException("ending column '" + columnOpts[j]->getString(1) + "' not valid in file '" + ciftiIn->getFileName() + "'"); if (finalColumn < initialColumn) throw OperationException("ending column occurs before starting column in file '" + ciftiIn->getFileName() + "'"); numOutColumns += finalColumn - initialColumn + 1;//inclusive - we don't need to worry about reversing for counting, though } else { numOutColumns += 1; } } } else { numOutColumns += thisDims[0]; } if (i != 0)//don't mess with the first file, we use its mapping for the output file { ciftiList[i].forgetMapping(CiftiXML::ALONG_COLUMN);//HACK: release the memory being used to store the dense or parcel mapping, to deal with thousands of inputs } } CiftiScalarsMap outScalarMap;//we only use one of these CiftiLabelsMap outLabelMap; CiftiSeriesMap outSeriesMap; bool isLabel = false, doLoop = true;//whether we need to set attributes on each column switch (baseRowMapping.getType()) { case CiftiMappingType::SCALARS: outScalarMap.setLength(numOutColumns); break; case CiftiMappingType::LABELS: outLabelMap.setLength(numOutColumns); isLabel = true; break; case CiftiMappingType::SERIES: outSeriesMap.setLength(numOutColumns); outSeriesMap.setUnit(((const CiftiSeriesMap&)baseRowMapping).getUnit()); outSeriesMap.setStart(((const CiftiSeriesMap&)baseRowMapping).getStart()); outSeriesMap.setStep(((const CiftiSeriesMap&)baseRowMapping).getStep()); doLoop = false; break; default: CaretAssert(false); } int64_t curCol = 0, scratchRowLength = 0; for (int i = 0; i < numInputs; ++i) { const CiftiFile* ciftiIn = &(ciftiList[i]); vector thisDims = ciftiIn->getDimensions(); const CiftiXML& thisXML = ciftiIn->getCiftiXML(); const vector& columnOpts = *(myInputs[i]->getRepeatableParameterInstances(2)); int numColumnOpts = (int)columnOpts.size(); if (numColumnOpts > 0) { scratchRowLength = max(scratchRowLength, thisXML.getDimensionLength(CiftiXML::ALONG_ROW));//if we use the entire row, we don't need a separate scratch row for it if (doLoop) { for (int j = 0; j < numColumnOpts; ++j) { int64_t initialColumn = thisXML.getMap(CiftiXML::ALONG_ROW)->getIndexFromNumberOrName(columnOpts[j]->getString(1));//this function has the 1-indexing convention built in OptionalParameter* upToOpt = columnOpts[j]->getOptionalParameter(2);//we already checked that these strings give a valid column if (upToOpt->m_present) { int finalColumn = thisXML.getMap(CiftiXML::ALONG_ROW)->getIndexFromNumberOrName(upToOpt->getString(1));//ditto bool reverse = upToOpt->getOptionalParameter(2)->m_present; if (reverse) { for (int c = finalColumn; c >= initialColumn; --c) { if (isLabel) { const CiftiLabelsMap& thisLabelMap = thisXML.getLabelsMap(CiftiXML::ALONG_ROW); outLabelMap.setMapName(curCol, thisLabelMap.getMapName(c)); *(outLabelMap.getMapLabelTable(curCol)) = *(thisLabelMap.getMapLabelTable(c)); *(outLabelMap.getMapMetadata(curCol)) = *(thisLabelMap.getMapMetadata(c)); } else { const CiftiScalarsMap& thisScalarMap = thisXML.getScalarsMap(CiftiXML::ALONG_ROW); outScalarMap.setMapName(curCol, thisScalarMap.getMapName(c)); *(outScalarMap.getMapPalette(curCol)) = *(thisScalarMap.getMapPalette(c)); *(outScalarMap.getMapMetadata(curCol)) = *(thisScalarMap.getMapMetadata(c)); } ++curCol; } } else { for (int c = initialColumn; c <= finalColumn; ++c) { if (isLabel) { const CiftiLabelsMap& thisLabelMap = thisXML.getLabelsMap(CiftiXML::ALONG_ROW); outLabelMap.setMapName(curCol, thisLabelMap.getMapName(c)); *(outLabelMap.getMapLabelTable(curCol)) = *(thisLabelMap.getMapLabelTable(c)); *(outLabelMap.getMapMetadata(curCol)) = *(thisLabelMap.getMapMetadata(c)); } else { const CiftiScalarsMap& thisScalarMap = thisXML.getScalarsMap(CiftiXML::ALONG_ROW); outScalarMap.setMapName(curCol, thisScalarMap.getMapName(c)); *(outScalarMap.getMapPalette(curCol)) = *(thisScalarMap.getMapPalette(c)); *(outScalarMap.getMapMetadata(curCol)) = *(thisScalarMap.getMapMetadata(c)); } ++curCol; } } } else { if (isLabel) { const CiftiLabelsMap& thisLabelMap = thisXML.getLabelsMap(CiftiXML::ALONG_ROW); outLabelMap.setMapName(curCol, thisLabelMap.getMapName(initialColumn)); *(outLabelMap.getMapLabelTable(curCol)) = *(thisLabelMap.getMapLabelTable(initialColumn)); *(outLabelMap.getMapMetadata(curCol)) = *(thisLabelMap.getMapMetadata(initialColumn)); } else { const CiftiScalarsMap& thisScalarMap = thisXML.getScalarsMap(CiftiXML::ALONG_ROW); outScalarMap.setMapName(curCol, thisScalarMap.getMapName(initialColumn)); *(outScalarMap.getMapPalette(curCol)) = *(thisScalarMap.getMapPalette(initialColumn)); *(outScalarMap.getMapMetadata(curCol)) = *(thisScalarMap.getMapMetadata(initialColumn)); } ++curCol; } } } } else { if (doLoop) { for (int64_t j = 0; j < thisDims[0]; ++j) { if (isLabel) { const CiftiLabelsMap& thisLabelMap = thisXML.getLabelsMap(CiftiXML::ALONG_ROW); outLabelMap.setMapName(curCol, thisLabelMap.getMapName(j)); *(outLabelMap.getMapLabelTable(curCol)) = *(thisLabelMap.getMapLabelTable(j)); *(outLabelMap.getMapMetadata(curCol)) = *(thisLabelMap.getMapMetadata(j)); } else { const CiftiScalarsMap& thisScalarMap = thisXML.getScalarsMap(CiftiXML::ALONG_ROW); outScalarMap.setMapName(curCol, thisScalarMap.getMapName(j)); *(outScalarMap.getMapPalette(curCol)) = *(thisScalarMap.getMapPalette(j)); *(outScalarMap.getMapMetadata(curCol)) = *(thisScalarMap.getMapMetadata(j)); } ++curCol; } } } } CaretAssert(!doLoop || curCol == numOutColumns); CiftiXML outXML; outXML.setNumberOfDimensions(2); outXML.setMap(CiftiXML::ALONG_COLUMN, baseColMapping); switch (baseRowMapping.getType()) { case CiftiMappingType::LABELS: outXML.setMap(CiftiXML::ALONG_ROW, outLabelMap); break; case CiftiMappingType::SCALARS: outXML.setMap(CiftiXML::ALONG_ROW, outScalarMap); break; case CiftiMappingType::SERIES: outXML.setMap(CiftiXML::ALONG_ROW, outSeriesMap); break; default: CaretAssert(false); } ciftiOut->setCiftiXML(outXML); int64_t numRows = baseColMapping.getLength(); vector outRow(numOutColumns), scratchRow(scratchRowLength); for (int64_t row = 0; row < numRows; ++row) { curCol = 0; for (int i = 0; i < numInputs; ++i) { const CiftiFile* ciftiIn = &(ciftiList[i]); vector thisDims = ciftiIn->getDimensions(); const CiftiXML& thisXML = ciftiIn->getCiftiXML(); const vector& columnOpts = *(myInputs[i]->getRepeatableParameterInstances(2)); int numColumnOpts = (int)columnOpts.size(); if (numColumnOpts > 0) { ciftiIn->getRow(scratchRow.data(), row); for (int j = 0; j < numColumnOpts; ++j) { int64_t initialColumn = thisXML.getMap(CiftiXML::ALONG_ROW)->getIndexFromNumberOrName(columnOpts[j]->getString(1));//this function has the 1-indexing convention built in OptionalParameter* upToOpt = columnOpts[j]->getOptionalParameter(2);//we already checked that these strings give a valid column if (upToOpt->m_present) { int finalColumn = thisXML.getMap(CiftiXML::ALONG_ROW)->getIndexFromNumberOrName(upToOpt->getString(1));//ditto bool reverse = upToOpt->getOptionalParameter(2)->m_present; if (reverse) { for (int c = finalColumn; c >= initialColumn; --c) { outRow[curCol] = scratchRow[c]; ++curCol; } } else { for (int c = initialColumn; c <= finalColumn; ++c) { outRow[curCol] = scratchRow[c]; ++curCol; } } } else { outRow[curCol] = scratchRow[initialColumn]; ++curCol; } } } else { ciftiIn->getRow(outRow.data() + curCol, row); curCol += thisDims[0]; } } CaretAssert(curCol == numOutColumns); ciftiOut->setRow(outRow.data(), row); } } connectome-workbench-1.4.2/src/Operations/OperationCiftiMerge.h000066400000000000000000000025751360521144700246260ustar00rootroot00000000000000#ifndef __OPERATION_CIFTI_MERGE_H__ #define __OPERATION_CIFTI_MERGE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationCiftiMerge : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationCiftiMerge; } #endif //__OPERATION_CIFTI_MERGE_H__ connectome-workbench-1.4.2/src/Operations/OperationCiftiPalette.cxx000066400000000000000000000313031360521144700255270ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationCiftiPalette.h" #include "CiftiFile.h" #include "OperationException.h" #include "Palette.h" #include "PaletteColorMapping.h" #include "PaletteFile.h" #include using namespace caret; using namespace std; AString OperationCiftiPalette::getCommandSwitch() { return "-cifti-palette"; } AString OperationCiftiPalette::getShortDescription() { return "SET PALETTE ON A CIFTI FILE"; } OperationParameters* OperationCiftiPalette::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-in", "the cifti input"); ret->addStringParameter(2, "mode", "the mapping mode"); ret->addCiftiOutputParameter(3, "cifti-out", "the output cifti file"); OptionalParameter* columnSelect = ret->createOptionalParameter(4, "-column", "select a single column for scalar maps"); columnSelect->addStringParameter(1, "column", "the column number or name"); OptionalParameter* posMinMaxPercent = ret->createOptionalParameter(5, "-pos-percent", "percentage min/max for positive data coloring"); posMinMaxPercent->addDoubleParameter(1, "pos-min-%", "the percentile for the least positive data"); posMinMaxPercent->addDoubleParameter(2, "pos-max-%", "the percentile for the most positive data"); OptionalParameter* negMinMaxPercent = ret->createOptionalParameter(6, "-neg-percent", "percentage min/max for negative data coloring"); negMinMaxPercent->addDoubleParameter(1, "neg-min-%", "the percentile for the least negative data"); negMinMaxPercent->addDoubleParameter(2, "neg-max-%", "the percentile for the most negative data"); OptionalParameter* posMinMaxValue = ret->createOptionalParameter(7, "-pos-user", "user min/max values for positive data coloring"); posMinMaxValue->addDoubleParameter(1, "pos-min-user", "the value for the least positive data"); posMinMaxValue->addDoubleParameter(2, "pos-max-user", "the value for the most positive data"); OptionalParameter* negMinMaxValue = ret->createOptionalParameter(8, "-neg-user", "user min/max values for negative data coloring"); negMinMaxValue->addDoubleParameter(1, "neg-min-user", "the value for the least negative data"); negMinMaxValue->addDoubleParameter(2, "neg-max-user", "the value for the most negative data"); OptionalParameter* interpolate = ret->createOptionalParameter(9, "-interpolate", "interpolate colors"); interpolate->addBooleanParameter(1, "interpolate", "boolean, whether to interpolate"); OptionalParameter* displayPositive = ret->createOptionalParameter(10, "-disp-pos", "display positive data"); displayPositive->addBooleanParameter(1, "display", "boolean, whether to display"); OptionalParameter* displayNegative = ret->createOptionalParameter(11, "-disp-neg", "display positive data"); displayNegative->addBooleanParameter(1, "display", "boolean, whether to display"); OptionalParameter* displayZero = ret->createOptionalParameter(12, "-disp-zero", "display data closer to zero than the min cutoff"); displayZero->addBooleanParameter(1, "display", "boolean, whether to display"); OptionalParameter* paletteName = ret->createOptionalParameter(13, "-palette-name", "set the palette used"); paletteName->addStringParameter(1, "name", "the name of the palette"); OptionalParameter* thresholdOpt = ret->createOptionalParameter(14, "-thresholding", "set the thresholding"); thresholdOpt->addStringParameter(1, "type", "thresholding setting"); thresholdOpt->addStringParameter(2, "test", "show values inside or outside thresholds"); thresholdOpt->addDoubleParameter(3, "min", "lower threshold"); thresholdOpt->addDoubleParameter(4, "max", "upper threshold"); OptionalParameter* inversionOpt = ret->createOptionalParameter(15, "-inversion", "specify palette inversion"); inversionOpt->addStringParameter(1, "type", "the type of inversion"); AString myText = AString("NOTE: The output file must be a different file than the input file.\n\n") + "For scalar maps, by default the palette is changed for every map, specify -column to change only one map. Palette settings not specified will be taken from the first column " + "for scalar maps, and from the existing file palette for other mapping types. " + "The argument must be one of the following:\n\n"; vector myEnums; PaletteScaleModeEnum::getAllEnums(myEnums); for (int i = 0; i < (int)myEnums.size(); ++i) { myText += PaletteScaleModeEnum::toName(myEnums[i]) + "\n"; } myText += "\nThe argument to -palette-name must be one of the following:\n\n"; PaletteFile myPF; int32_t numPalettes = myPF.getNumberOfPalettes(); for (int i = 0; i < numPalettes; ++i) { myText += myPF.getPalette(i)->getName() + "\n"; } myText += "\nThe argument to -thresholding must be one of the following:\n\n"; vector myEnums2; PaletteThresholdTypeEnum::getAllEnums(myEnums2); for (int i = 0; i < (int)myEnums2.size(); ++i) { myText += PaletteThresholdTypeEnum::toName(myEnums2[i]) + "\n"; } myText += "\nThe argument to -thresholding must be one of the following:\n\n"; vector myEnums3; PaletteThresholdTestEnum::getAllEnums(myEnums3); for (int i = 0; i < (int)myEnums3.size(); ++i) { myText += PaletteThresholdTestEnum::toName(myEnums3[i]) + "\n"; } myText += "\nThe argument to -inversion must be one of the following:\n\n"; vector myEnums4; PaletteInvertModeEnum::getAllEnums(myEnums4); for (int i = 0; i < (int)myEnums4.size(); ++i) { myText += PaletteInvertModeEnum::toName(myEnums4[i]) + "\n"; } ret->setHelpText(myText); return ret; } void OperationCiftiPalette::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); CiftiFile* ciftiIn = myParams->getCifti(1); CiftiXMLOld myOutXML = ciftiIn->getCiftiXMLOld(); int64_t numRows = myOutXML.getNumberOfRows(), numCols = myOutXML.getNumberOfColumns(); if (numRows < 1 || numCols < 1) { throw OperationException("cifti file has invalid dimensions"); } PaletteColorMapping myMapping; if (myOutXML.getRowMappingType() == CIFTI_INDEX_TYPE_SCALARS) { myMapping = *(myOutXML.getMapPalette(CiftiXMLOld::ALONG_ROW, 0)); } else { myMapping = *(myOutXML.getFilePalette()); } AString myModeName = myParams->getString(2); bool ok = false; PaletteScaleModeEnum::Enum myMode = PaletteScaleModeEnum::fromName(myModeName, &ok); if (!ok) { throw OperationException("unknown mapping mode"); } CiftiFile* ciftiOut = myParams->getOutputCifti(3); int myColumn = -1; OptionalParameter* columnOpt = myParams->getOptionalParameter(4); if (columnOpt->m_present) { if (myOutXML.getRowMappingType() != CIFTI_INDEX_TYPE_SCALARS) { throw OperationException("-column option can only be used on scalar maps"); } AString columnIdentifier = columnOpt->getString(1); bool ok = false; myColumn = columnIdentifier.toInt(&ok) - 1; if (ok) { if (myColumn < 0 || myColumn >= numCols) { throw OperationException("invalid column specified"); } } else { int i = 0; for (; i < numCols; ++i) { if (myOutXML.getMapNameForRowIndex(i) == columnIdentifier)//index along a row - we need to fix these function names { myColumn = i; break; } } if (i >= numCols) { throw OperationException("invalid column specified"); } } } myMapping.setScaleMode(myMode); OptionalParameter* posMinMaxPercent = myParams->getOptionalParameter(5); if (posMinMaxPercent->m_present) { myMapping.setAutoScalePercentagePositiveMinimum(posMinMaxPercent->getDouble(1)); myMapping.setAutoScalePercentagePositiveMaximum(posMinMaxPercent->getDouble(2)); } OptionalParameter* negMinMaxPercent = myParams->getOptionalParameter(6); if (negMinMaxPercent->m_present) { myMapping.setAutoScalePercentageNegativeMinimum(negMinMaxPercent->getDouble(1)); myMapping.setAutoScalePercentageNegativeMaximum(negMinMaxPercent->getDouble(2)); } OptionalParameter* posMinMaxValue = myParams->getOptionalParameter(7); if (posMinMaxValue->m_present) { myMapping.setUserScalePositiveMinimum(posMinMaxValue->getDouble(1)); myMapping.setUserScalePositiveMaximum(posMinMaxValue->getDouble(2)); } OptionalParameter* negMinMaxValue = myParams->getOptionalParameter(8); if (negMinMaxValue->m_present) { myMapping.setUserScaleNegativeMinimum(negMinMaxValue->getDouble(1)); myMapping.setUserScaleNegativeMaximum(negMinMaxValue->getDouble(2)); } OptionalParameter* interpolate = myParams->getOptionalParameter(9); if (interpolate->m_present) { myMapping.setInterpolatePaletteFlag(interpolate->getBoolean(1)); } OptionalParameter* displayPositive = myParams->getOptionalParameter(10); if (displayPositive->m_present) { myMapping.setDisplayPositiveDataFlag(displayPositive->getBoolean(1)); } OptionalParameter* displayNegative = myParams->getOptionalParameter(11); if (displayNegative->m_present) { myMapping.setDisplayNegativeDataFlag(displayNegative->getBoolean(1)); } OptionalParameter* displayZero = myParams->getOptionalParameter(12); if (displayZero->m_present) { myMapping.setDisplayZeroDataFlag(displayZero->getBoolean(1)); } OptionalParameter* paletteName = myParams->getOptionalParameter(13); if (paletteName->m_present) { myMapping.setSelectedPaletteName(paletteName->getString(1)); } OptionalParameter* thresholdOpt = myParams->getOptionalParameter(14); if (thresholdOpt->m_present) { bool ok = false; PaletteThresholdTypeEnum::Enum mytype = PaletteThresholdTypeEnum::fromName(thresholdOpt->getString(1), &ok); if (!ok) throw OperationException("unrecognized threshold type string: " + thresholdOpt->getString(1)); PaletteThresholdTestEnum::Enum mytest = PaletteThresholdTestEnum::fromName(thresholdOpt->getString(2), &ok); if (!ok) throw OperationException("unrecognized threshold test string: " + thresholdOpt->getString(2)); myMapping.setThresholdType(mytype); myMapping.setThresholdTest(mytest); myMapping.setThresholdMinimum(mytype, thresholdOpt->getDouble(3)); myMapping.setThresholdMaximum(mytype, thresholdOpt->getDouble(4)); } OptionalParameter* inversionOpt = myParams->getOptionalParameter(15); if (inversionOpt->m_present) { bool ok = false; PaletteInvertModeEnum::Enum inversionType = PaletteInvertModeEnum::fromName(inversionOpt->getString(1), &ok); if (!ok) throw OperationException("unrecognized palette inversion type: " + inversionOpt->getString(1)); myMapping.setInvertedMode(inversionType); } if (myOutXML.getRowMappingType() == CIFTI_INDEX_TYPE_SCALARS) { if (myColumn == -1) { for (int i = 0; i < numCols; ++i) { *(myOutXML.getMapPalette(CiftiXMLOld::ALONG_ROW, i)) = myMapping; } } else { *(myOutXML.getMapPalette(CiftiXMLOld::ALONG_ROW, myColumn)) = myMapping; } } else { *(myOutXML.getFilePalette()) = myMapping; } ciftiOut->setCiftiXML(myOutXML); vector scratchRow(numCols); for (int64_t i = 0; i < numRows; ++i) { ciftiIn->getRow(scratchRow.data(), i); ciftiOut->setRow(scratchRow.data(), i); } } connectome-workbench-1.4.2/src/Operations/OperationCiftiPalette.h000066400000000000000000000026111360521144700251540ustar00rootroot00000000000000#ifndef __OPERATION_CIFTI_PALETTE_H__ #define __OPERATION_CIFTI_PALETTE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationCiftiPalette : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationCiftiPalette; } #endif //__OPERATION_CIFTI_PALETTE_H__ connectome-workbench-1.4.2/src/Operations/OperationCiftiROIAverage.cxx000066400000000000000000000214701360521144700260610ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationCiftiROIAverage.h" #include "AlgorithmCiftiSeparate.h" #include "CiftiFile.h" #include "MetricFile.h" #include "OperationException.h" #include "VolumeFile.h" #include using namespace caret; using namespace std; AString OperationCiftiROIAverage::getCommandSwitch() { return "-cifti-roi-average"; } AString OperationCiftiROIAverage::getShortDescription() { return "AVERAGE ROWS IN A SINGLE CIFTI FILE"; } OperationParameters* OperationCiftiROIAverage::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-in", "the cifti file to average rows from"); ret->addStringParameter(2, "text-out", "output text file of the average values"); OptionalParameter* ciftiRoiOpt = ret->createOptionalParameter(3, "-cifti-roi", "cifti file containing combined rois"); ciftiRoiOpt->addCiftiParameter(1, "roi-cifti", "the rois as a cifti file"); OptionalParameter* leftRoiOpt = ret->createOptionalParameter(4, "-left-roi", "vertices to use from left hemisphere"); leftRoiOpt->addMetricParameter(1, "roi-metric", "the left roi as a metric file"); OptionalParameter* rightRoiOpt = ret->createOptionalParameter(5, "-right-roi", "vertices to use from right hemisphere"); rightRoiOpt->addMetricParameter(1, "roi-metric", "the right roi as a metric file"); OptionalParameter* cerebRoiOpt = ret->createOptionalParameter(6, "-cerebellum-roi", "vertices to use from cerebellum"); cerebRoiOpt->addMetricParameter(1, "roi-metric", "the cerebellum roi as a metric file"); OptionalParameter* volRoiOpt = ret->createOptionalParameter(7, "-vol-roi", "voxels to use"); volRoiOpt->addVolumeParameter(1, "roi-vol", "the roi volume file"); ret->setHelpText( AString("Average the rows that are within the specified ROIs, and write the resulting average row to a text file, separated by newlines. ") + "If -cifti-roi is specified, -left-roi, -right-roi, -cerebellum-roi, and -vol-roi must not be specified." ); return ret; } void OperationCiftiROIAverage::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); CiftiFile* myCifti = myParams->getCifti(1); if (myCifti->getCiftiXML().getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) { throw OperationException("input cifti file does not have a brain models mapping along column"); } AString textFileName = myParams->getString(2); fstream textFile(textFileName.toLocal8Bit().constData(), fstream::out | fstream::trunc); if (!textFile.good()) { throw OperationException("error opening output file for writing"); } int numCols = myCifti->getNumberOfColumns(); vector accum(numCols, 0.0); int accumCount = 0; CiftiFile* ciftiROI = NULL; OptionalParameter* ciftiRoiOpt = myParams->getOptionalParameter(3); if (ciftiRoiOpt->m_present) { ciftiROI = ciftiRoiOpt->getCifti(1); } OptionalParameter* leftRoiOpt = myParams->getOptionalParameter(4); if (leftRoiOpt->m_present) { if (ciftiROI != NULL) throw OperationException("-cifti-roi cannot be used with any other ROI option"); MetricFile* tempMetric = leftRoiOpt->getMetric(1); processSurfaceComponent(myCifti, StructureEnum::CORTEX_LEFT, tempMetric, accum, accumCount); } OptionalParameter* rightRoiOpt = myParams->getOptionalParameter(5); if (rightRoiOpt->m_present) { if (ciftiROI != NULL) throw OperationException("-cifti-roi cannot be used with any other ROI option"); MetricFile* tempMetric = rightRoiOpt->getMetric(1); processSurfaceComponent(myCifti, StructureEnum::CORTEX_RIGHT, tempMetric, accum, accumCount); } OptionalParameter* cerebRoiOpt = myParams->getOptionalParameter(6); if (cerebRoiOpt->m_present) { if (ciftiROI != NULL) throw OperationException("-cifti-roi cannot be used with any other ROI option"); MetricFile* tempMetric = cerebRoiOpt->getMetric(1); processSurfaceComponent(myCifti, StructureEnum::CEREBELLUM, tempMetric, accum, accumCount); } OptionalParameter* volRoiOpt = myParams->getOptionalParameter(7); if (volRoiOpt->m_present) { if (ciftiROI != NULL) throw OperationException("-cifti-roi cannot be used with any other ROI option"); VolumeFile* tempVol = volRoiOpt->getVolume(1); processVolume(myCifti, tempVol, accum, accumCount); } if (ciftiROI != NULL) { const CiftiXML& roiXML = ciftiROI->getCiftiXML(); const CiftiXML& inputXML = myCifti->getCiftiXML(); if (!(roiXML.getMap(CiftiXML::ALONG_COLUMN)->approximateMatch(*inputXML.getMap(CiftiXML::ALONG_COLUMN)))) { throw OperationException("dense mappings of input and roi cifti files don't match"); } const CiftiBrainModelsMap& roiDense = roiXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); if (roiDense.hasVolumeData()) { VolumeFile roiVol; int64_t offset[3]; AlgorithmCiftiSeparate(NULL, ciftiROI, CiftiXML::ALONG_COLUMN, &roiVol, offset, NULL, false);//don't crop because there should be only one map, and processVolume doesn't currently accept cropped processVolume(myCifti, &roiVol, accum, accumCount); } vector surfStructs = roiDense.getSurfaceStructureList(); for (int i = 0; i < (int)surfStructs.size(); ++i) { MetricFile roiMetric; AlgorithmCiftiSeparate(NULL, ciftiROI, CiftiXML::ALONG_COLUMN, surfStructs[i], &roiMetric); processSurfaceComponent(myCifti, surfStructs[i], &roiMetric, accum, accumCount); } } if (accumCount == 0) { throw OperationException("ROI(s) don't match any data"); } for (int i = 0; i < numCols; ++i) { textFile << accum[i] / accumCount << endl; } } void OperationCiftiROIAverage::processSurfaceComponent(const CiftiFile* myCifti, const StructureEnum::Enum& myStruct, const MetricFile* myRoi, vector& accum, int& accumCount) { int numCols = myCifti->getNumberOfColumns(); int numNodes = myRoi->getNumberOfNodes(); const CiftiBrainModelsMap& myDenseMap = myCifti->getCiftiXML().getBrainModelsMap(CiftiXML::ALONG_COLUMN); if (myDenseMap.getSurfaceNumberOfNodes(myStruct) != numNodes) { throw OperationException("roi number of vertices doesn't match for structure " + StructureEnum::toName(myStruct)); } vector scratch(numCols); vector myMap = myDenseMap.getSurfaceMap(myStruct); int mapSize = myMap.size(); for (int i = 0; i < mapSize; ++i) { if (myRoi->getValue(myMap[i].m_surfaceNode, 0) > 0.0f) { ++accumCount; myCifti->getRow(scratch.data(), myMap[i].m_ciftiIndex); for (int j = 0; j < numCols; ++j) { accum[j] += scratch[j]; } } } } void OperationCiftiROIAverage::processVolume(const CiftiFile* myCifti, const VolumeFile* myRoi, vector& accum, int& accumCount) { int numCols = myCifti->getNumberOfColumns(); const CiftiXMLOld& myXml = myCifti->getCiftiXMLOld(); int64_t dims[3]; vector > sform; if (!myXml.getVolumeDimsAndSForm(dims, sform)) { throw OperationException("no volume data in cifti file"); } if (!myRoi->matchesVolumeSpace(dims, sform)) { throw OperationException("volume roi doesn't match cifti volume space"); } vector scratch(numCols); vector myMap; myXml.getVolumeMapForColumns(myMap); int mapSize = myMap.size(); for (int i = 0; i < mapSize; ++i) { if (myRoi->getValue(myMap[i].m_ijk) > 0.0f) { ++accumCount; myCifti->getRow(scratch.data(), myMap[i].m_ciftiIndex); for (int j = 0; j < numCols; ++j) { accum[j] += scratch[j]; } } } } connectome-workbench-1.4.2/src/Operations/OperationCiftiROIAverage.h000066400000000000000000000035061360521144700255060ustar00rootroot00000000000000#ifndef __OPERATION_CIFTI_ROI_AVERAGE_H__ #define __OPERATION_CIFTI_ROI_AVERAGE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" #include "StructureEnum.h" #include namespace caret { class CiftiFile; class MetricFile; class VolumeFile; class OperationCiftiROIAverage : public AbstractOperation { static void processSurfaceComponent(const CiftiFile* myCifti, const StructureEnum::Enum& myStruct, const MetricFile* myRoi, std::vector& accum, int& accumCount); static void processVolume(const CiftiFile* myCifti, const VolumeFile* myRoi, std::vector& accum, int& accumCount); public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationCiftiROIAverage; } #endif //__OPERATION_CIFTI_ROI_AVERAGE_H__ connectome-workbench-1.4.2/src/Operations/OperationCiftiResampleDconnMemory.cxx000066400000000000000000000627131360521144700300650ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationCiftiResampleDconnMemory.h" #include "OperationException.h" #include "AffineFile.h" #include "AlgorithmCiftiResample.h" #include "CiftiFile.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "WarpfieldFile.h" using namespace caret; using namespace std; AString OperationCiftiResampleDconnMemory::getCommandSwitch() { return "-cifti-resample-dconn-memory"; } AString OperationCiftiResampleDconnMemory::getShortDescription() { return "USE LOTS OF MEMORY TO RESAMPLE DCONN"; } OperationParameters* OperationCiftiResampleDconnMemory::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-in", "the cifti file to resample"); ret->addCiftiParameter(3, "cifti-template", "a cifti file containing the cifti space to resample to"); ret->addStringParameter(4, "template-direction", "the direction of the template to use as the resampling space, ROW or COLUMN"); ret->addStringParameter(5, "surface-method", "specify a surface resampling method"); ret->addStringParameter(6, "volume-method", "specify a volume interpolation method"); ret->addCiftiOutputParameter(7, "cifti-out", "the output cifti file"); ret->createOptionalParameter(8, "-surface-largest", "use largest weight instead of weighted average when doing surface resampling"); OptionalParameter* volDilateOpt = ret->createOptionalParameter(9, "-volume-predilate", "dilate the volume components before resampling"); volDilateOpt->addDoubleParameter(1, "dilate-mm", "distance, in mm, to dilate"); volDilateOpt->createOptionalParameter(2, "-nearest", "use nearest value dilation"); OptionalParameter* volDilateWeightedOpt = volDilateOpt->createOptionalParameter(3, "-weighted", "use weighted dilation (default)"); OptionalParameter* volDilateExpOpt = volDilateWeightedOpt->createOptionalParameter(1, "-exponent", "specify exponent in weighting function"); volDilateExpOpt->addDoubleParameter(1, "exponent", "exponent 'n' to use in (1 / (distance ^ n)) as the weighting function (default 7)"); volDilateWeightedOpt->createOptionalParameter(2, "-legacy-cutoff", "use v1.3.2 logic for the kernel cutoff"); OptionalParameter* surfDilateOpt = ret->createOptionalParameter(10, "-surface-postdilate", "dilate the surface components after resampling"); surfDilateOpt->addDoubleParameter(1, "dilate-mm", "distance, in mm, to dilate"); surfDilateOpt->createOptionalParameter(2, "-nearest", "use nearest value dilation"); surfDilateOpt->createOptionalParameter(3, "-linear", "use linear dilation"); OptionalParameter* surfDilateWeightedOpt = surfDilateOpt->createOptionalParameter(4, "-weighted", "use weighted dilation (default)"); OptionalParameter* surfDilateExpOpt = surfDilateWeightedOpt->createOptionalParameter(1, "-exponent", "specify exponent in weighting function"); surfDilateExpOpt->addDoubleParameter(1, "exponent", "exponent 'n' to use in (area / (distance ^ n)) as the weighting function (default 6)"); surfDilateWeightedOpt->createOptionalParameter(2, "-legacy-cutoff", "use v1.3.2 logic for the kernel cutoff"); OptionalParameter* affineOpt = ret->createOptionalParameter(11, "-affine", "use an affine transformation on the volume components"); affineOpt->addStringParameter(1, "affine-file", "the affine file to use"); OptionalParameter* flirtOpt = affineOpt->createOptionalParameter(2, "-flirt", "MUST be used if affine is a flirt affine"); flirtOpt->addStringParameter(1, "source-volume", "the source volume used when generating the affine"); flirtOpt->addStringParameter(2, "target-volume", "the target volume used when generating the affine"); OptionalParameter* warpfieldOpt = ret->createOptionalParameter(12, "-warpfield", "use a warpfield on the volume components"); warpfieldOpt->addStringParameter(1, "warpfield", "the warpfield to use"); OptionalParameter* fnirtOpt = warpfieldOpt->createOptionalParameter(2, "-fnirt", "MUST be used if using a fnirt warpfield"); fnirtOpt->addStringParameter(1, "source-volume", "the source volume used when generating the warpfield"); OptionalParameter* leftSpheresOpt = ret->createOptionalParameter(13, "-left-spheres", "specify spheres for left surface resampling"); leftSpheresOpt->addSurfaceParameter(1, "current-sphere", "a sphere with the same mesh as the current left surface"); leftSpheresOpt->addSurfaceParameter(2, "new-sphere", "a sphere with the new left mesh that is in register with the current sphere"); OptionalParameter* leftAreaSurfsOpt = leftSpheresOpt->createOptionalParameter(3, "-left-area-surfs", "specify left surfaces to do vertex area correction based on"); leftAreaSurfsOpt->addSurfaceParameter(1, "current-area", "a relevant left anatomical surface with current mesh"); leftAreaSurfsOpt->addSurfaceParameter(2, "new-area", "a relevant left anatomical surface with new mesh"); OptionalParameter* leftAreaMetricsOpt = leftSpheresOpt->createOptionalParameter(4, "-left-area-metrics", "specify left vertex area metrics to do area correction based on"); leftAreaMetricsOpt->addMetricParameter(1, "current-area", "a metric file with vertex areas for the current mesh"); leftAreaMetricsOpt->addMetricParameter(2, "new-area", "a metric file with vertex areas for the new mesh"); OptionalParameter* rightSpheresOpt = ret->createOptionalParameter(14, "-right-spheres", "specify spheres for right surface resampling"); rightSpheresOpt->addSurfaceParameter(1, "current-sphere", "a sphere with the same mesh as the current right surface"); rightSpheresOpt->addSurfaceParameter(2, "new-sphere", "a sphere with the new right mesh that is in register with the current sphere"); OptionalParameter* rightAreaSurfsOpt = rightSpheresOpt->createOptionalParameter(3, "-right-area-surfs", "specify right surfaces to do vertex area correction based on"); rightAreaSurfsOpt->addSurfaceParameter(1, "current-area", "a relevant right anatomical surface with current mesh"); rightAreaSurfsOpt->addSurfaceParameter(2, "new-area", "a relevant right anatomical surface with new mesh"); OptionalParameter* rightAreaMetricsOpt = rightSpheresOpt->createOptionalParameter(4, "-right-area-metrics", "specify right vertex area metrics to do area correction based on"); rightAreaMetricsOpt->addMetricParameter(1, "current-area", "a metric file with vertex areas for the current mesh"); rightAreaMetricsOpt->addMetricParameter(2, "new-area", "a metric file with vertex areas for the new mesh"); OptionalParameter* cerebSpheresOpt = ret->createOptionalParameter(15, "-cerebellum-spheres", "specify spheres for cerebellum surface resampling"); cerebSpheresOpt->addSurfaceParameter(1, "current-sphere", "a sphere with the same mesh as the current cerebellum surface"); cerebSpheresOpt->addSurfaceParameter(2, "new-sphere", "a sphere with the new cerebellum mesh that is in register with the current sphere"); OptionalParameter* cerebAreaSurfsOpt = cerebSpheresOpt->createOptionalParameter(3, "-cerebellum-area-surfs", "specify cerebellum surfaces to do vertex area correction based on"); cerebAreaSurfsOpt->addSurfaceParameter(1, "current-area", "a relevant cerebellum anatomical surface with current mesh"); cerebAreaSurfsOpt->addSurfaceParameter(2, "new-area", "a relevant cerebellum anatomical surface with new mesh"); OptionalParameter* cerebAreaMetricsOpt = cerebSpheresOpt->createOptionalParameter(4, "-cerebellum-area-metrics", "specify cerebellum vertex area metrics to do area correction based on"); cerebAreaMetricsOpt->addMetricParameter(1, "current-area", "a metric file with vertex areas for the current mesh"); cerebAreaMetricsOpt->addMetricParameter(2, "new-area", "a metric file with vertex areas for the new mesh"); AString myHelpText = AString("This command does the same thing as running -cifti-resample twice, but uses memory up to approximately 2x the size that the intermediate file would be. ") + "This is because the intermediate dconn is kept in memory, rather than written to disk, " + "and the components before and after resampling/dilation have to be in memory at the same time during the relevant computation. " + "The argument should usually be COLUMN, as dtseries, dscalar, and dlabel all have brainordinates on that direction. " + "If spheres are not specified for a surface structure which exists in the cifti files, its data is copied without resampling or dilation. " + "Dilation is done with the 'nearest' method, and is done on for surface data. " + "Volume components are padded before dilation so that dilation doesn't run into the edge of the component bounding box.\n\n" + "To get the v1.3.2 and earlier behavior of weighted dilation, specify exponent of 2 for surface and volume, and -legacy-cutoff for both surface and volume.\n\n" + "The argument must be one of the following:\n\n" + "CUBIC\nENCLOSING_VOXEL\nTRILINEAR\n\n" + "The argument must be one of the following:\n\n"; vector allEnums; SurfaceResamplingMethodEnum::getAllEnums(allEnums); for (int i = 0; i < (int)allEnums.size(); ++i) { myHelpText += SurfaceResamplingMethodEnum::toName(allEnums[i]) + "\n"; } ret->setHelpText(myHelpText); return ret; } void OperationCiftiResampleDconnMemory::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); CiftiFile* myCiftiIn = myParams->getCifti(1); CiftiFile* myTemplate = myParams->getCifti(3); AString myTemplDirString = myParams->getString(4); int templateDir = -1; if (myTemplDirString == "ROW") { templateDir = CiftiXML::ALONG_ROW; } else { if (myTemplDirString == "COLUMN") { templateDir = CiftiXML::ALONG_COLUMN; } else { throw OperationException("unrecognized template direction string, use ROW or COLUMN"); } } bool ok = false; SurfaceResamplingMethodEnum::Enum mySurfMethod = SurfaceResamplingMethodEnum::fromName(myParams->getString(5), &ok); if (!ok) { throw OperationException("invalid surface resampling method name"); } AString myVolMethodString = myParams->getString(6); VolumeFile::InterpType myVolMethod = VolumeFile::CUBIC; if (myVolMethodString == "CUBIC") { myVolMethod = VolumeFile::CUBIC; } else if (myVolMethodString == "TRILINEAR") { myVolMethod = VolumeFile::TRILINEAR; } else if (myVolMethodString == "ENCLOSING_VOXEL") { myVolMethod = VolumeFile::ENCLOSING_VOXEL; } else { throw OperationException("unrecognized volume interpolation method"); } CiftiFile* myCiftiOut = myParams->getOutputCifti(7); bool surfLargest = myParams->getOptionalParameter(8)->m_present; float voldilatemm = -1.0f, surfdilatemm = -1.0f; bool isLabelData = false;//dilation method arguments checking needs to know if it is label data const CiftiXML& inputXML = myCiftiIn->getCiftiXML(); for (int i = 0; i < inputXML.getNumberOfDimensions(); ++i) { if (inputXML.getMappingType(i) == CiftiMappingType::LABELS) { isLabelData = true; break; } } AlgorithmVolumeDilate::Method volDilateMethod = AlgorithmVolumeDilate::WEIGHTED; float volDilateExponent = 2.0f; AlgorithmMetricDilate::Method surfDilateMethod = AlgorithmMetricDilate::WEIGHTED;//label dilate doesn't support multiple methods float surfDilateExponent = 2.0f;//label dilate currently only supports nearest, so in order to accept a default in the algorithm, it currently ignores this on label data, no warning bool surfLegacyCutoff = false, volLegacyCutoff = false; OptionalParameter* volDilateOpt = myParams->getOptionalParameter(9); if (volDilateOpt->m_present) { bool methodSpecified = false; voldilatemm = (float)volDilateOpt->getDouble(1); if (voldilatemm <= 0.0f) throw OperationException("dilation amount must be positive"); if (volDilateOpt->getOptionalParameter(2)->m_present) { methodSpecified = true; volDilateMethod = AlgorithmVolumeDilate::NEAREST; } OptionalParameter* volDilateWeightedOpt = volDilateOpt->getOptionalParameter(3); if (volDilateWeightedOpt->m_present) { if (methodSpecified) throw OperationException("cannot specify multiple volume dilation methods"); methodSpecified = true; volDilateMethod = AlgorithmVolumeDilate::WEIGHTED; OptionalParameter* volDilateExpOpt = volDilateWeightedOpt->getOptionalParameter(1); if (volDilateExpOpt->m_present) { volDilateExponent = (float)volDilateExpOpt->getDouble(1); } volLegacyCutoff = volDilateWeightedOpt->getOptionalParameter(2)->m_present; } } OptionalParameter* surfDilateOpt = myParams->getOptionalParameter(10); if (surfDilateOpt->m_present) { bool methodSpecified = false; surfdilatemm = (float)surfDilateOpt->getDouble(1); if (surfdilatemm <= 0.0f) throw OperationException("dilation amount must be positive"); if (surfDilateOpt->getOptionalParameter(2)->m_present) { methodSpecified = true; surfDilateMethod = AlgorithmMetricDilate::NEAREST; } if (surfDilateOpt->getOptionalParameter(3)->m_present) { if (methodSpecified) throw OperationException("cannot specify multiple surface dilation methods"); methodSpecified = true; if (isLabelData) throw OperationException("cannot do linear surface dilation on label data"); surfDilateMethod = AlgorithmMetricDilate::LINEAR; } OptionalParameter* surfDilateWeightedOpt = surfDilateOpt->getOptionalParameter(4); if (surfDilateWeightedOpt->m_present) { if (methodSpecified) throw OperationException("cannot specify multiple surface dilation methods"); methodSpecified = true; if (isLabelData) throw OperationException("cannot do weighted surface dilation on label data"); surfDilateMethod = AlgorithmMetricDilate::WEIGHTED; OptionalParameter* surfDilateExpOpt = surfDilateWeightedOpt->getOptionalParameter(1); if (surfDilateExpOpt->m_present) { surfDilateExponent = (float)surfDilateExpOpt->getDouble(1); } surfLegacyCutoff = surfDilateWeightedOpt->getOptionalParameter(2)->m_present; } } OptionalParameter* affineOpt = myParams->getOptionalParameter(11); OptionalParameter* warpfieldOpt = myParams->getOptionalParameter(12); if (affineOpt->m_present && warpfieldOpt->m_present) throw OperationException("you cannot specify both -affine and -warpfield"); AffineFile myAffine; WarpfieldFile myWarpfield; if (affineOpt->m_present) { OptionalParameter* flirtOpt = affineOpt->getOptionalParameter(2); if (flirtOpt->m_present) { myAffine.readFlirt(affineOpt->getString(1), flirtOpt->getString(1), flirtOpt->getString(2)); } else { myAffine.readWorld(affineOpt->getString(1)); } } if (warpfieldOpt->m_present) { OptionalParameter* fnirtOpt = warpfieldOpt->getOptionalParameter(2); if (fnirtOpt->m_present) { myWarpfield.readFnirt(warpfieldOpt->getString(1), fnirtOpt->getString(1)); } else { myWarpfield.readWorld(warpfieldOpt->getString(1)); } } SurfaceFile* curLeftSphere = NULL, *newLeftSphere = NULL; MetricFile* curLeftAreas = NULL, *newLeftAreas = NULL; MetricFile curLeftAreasTemp, newLeftAreasTemp; OptionalParameter* leftSpheresOpt = myParams->getOptionalParameter(13); if (leftSpheresOpt->m_present) { curLeftSphere = leftSpheresOpt->getSurface(1); newLeftSphere = leftSpheresOpt->getSurface(2); OptionalParameter* leftAreaSurfsOpt = leftSpheresOpt->getOptionalParameter(3); if (leftAreaSurfsOpt->m_present) { SurfaceFile* curAreaSurf = leftAreaSurfsOpt->getSurface(1); SurfaceFile* newAreaSurf = leftAreaSurfsOpt->getSurface(2); vector nodeAreasTemp; curAreaSurf->computeNodeAreas(nodeAreasTemp); curLeftAreasTemp.setNumberOfNodesAndColumns(curAreaSurf->getNumberOfNodes(), 1); curLeftAreasTemp.setValuesForColumn(0, nodeAreasTemp.data()); curLeftAreas = &curLeftAreasTemp; newAreaSurf->computeNodeAreas(nodeAreasTemp); newLeftAreasTemp.setNumberOfNodesAndColumns(newAreaSurf->getNumberOfNodes(), 1); newLeftAreasTemp.setValuesForColumn(0, nodeAreasTemp.data()); newLeftAreas = &newLeftAreasTemp; } OptionalParameter* leftAreaMetricsOpt = leftSpheresOpt->getOptionalParameter(4); if (leftAreaMetricsOpt->m_present) { if (leftAreaSurfsOpt->m_present) { throw OperationException("only one of -left-area-surfs and -left-area-metrics can be specified"); } curLeftAreas = leftAreaMetricsOpt->getMetric(1); newLeftAreas = leftAreaMetricsOpt->getMetric(2); } } SurfaceFile* curRightSphere = NULL, *newRightSphere = NULL; MetricFile* curRightAreas = NULL, *newRightAreas = NULL; MetricFile curRightAreasTemp, newRightAreasTemp; OptionalParameter* rightSpheresOpt = myParams->getOptionalParameter(14); if (rightSpheresOpt->m_present) { curRightSphere = rightSpheresOpt->getSurface(1); newRightSphere = rightSpheresOpt->getSurface(2); OptionalParameter* rightAreaSurfsOpt = rightSpheresOpt->getOptionalParameter(3); if (rightAreaSurfsOpt->m_present) { SurfaceFile* curAreaSurf = rightAreaSurfsOpt->getSurface(1); SurfaceFile* newAreaSurf = rightAreaSurfsOpt->getSurface(2); vector nodeAreasTemp; curAreaSurf->computeNodeAreas(nodeAreasTemp); curRightAreasTemp.setNumberOfNodesAndColumns(curAreaSurf->getNumberOfNodes(), 1); curRightAreasTemp.setValuesForColumn(0, nodeAreasTemp.data()); curRightAreas = &curRightAreasTemp; newAreaSurf->computeNodeAreas(nodeAreasTemp); newRightAreasTemp.setNumberOfNodesAndColumns(newAreaSurf->getNumberOfNodes(), 1); newRightAreasTemp.setValuesForColumn(0, nodeAreasTemp.data()); newRightAreas = &newRightAreasTemp; } OptionalParameter* rightAreaMetricsOpt = rightSpheresOpt->getOptionalParameter(4); if (rightAreaMetricsOpt->m_present) { if (rightAreaSurfsOpt->m_present) { throw OperationException("only one of -right-area-surfs and -right-area-metrics can be specified"); } curRightAreas = rightAreaMetricsOpt->getMetric(1); newRightAreas = rightAreaMetricsOpt->getMetric(2); } } SurfaceFile* curCerebSphere = NULL, *newCerebSphere = NULL; MetricFile* curCerebAreas = NULL, *newCerebAreas = NULL; MetricFile curCerebAreasTemp, newCerebAreasTemp; OptionalParameter* cerebSpheresOpt = myParams->getOptionalParameter(15); if (cerebSpheresOpt->m_present) { curCerebSphere = cerebSpheresOpt->getSurface(1); newCerebSphere = cerebSpheresOpt->getSurface(2); OptionalParameter* cerebAreaSurfsOpt = cerebSpheresOpt->getOptionalParameter(3); if (cerebAreaSurfsOpt->m_present) { SurfaceFile* curAreaSurf = cerebAreaSurfsOpt->getSurface(1); SurfaceFile* newAreaSurf = cerebAreaSurfsOpt->getSurface(2); vector nodeAreasTemp; curAreaSurf->computeNodeAreas(nodeAreasTemp); curCerebAreasTemp.setNumberOfNodesAndColumns(curAreaSurf->getNumberOfNodes(), 1); curCerebAreasTemp.setValuesForColumn(0, nodeAreasTemp.data()); curCerebAreas = &curCerebAreasTemp; newAreaSurf->computeNodeAreas(nodeAreasTemp); newCerebAreasTemp.setNumberOfNodesAndColumns(newAreaSurf->getNumberOfNodes(), 1); newCerebAreasTemp.setValuesForColumn(0, nodeAreasTemp.data()); newCerebAreas = &newCerebAreasTemp; } OptionalParameter* cerebAreaMetricsOpt = cerebSpheresOpt->getOptionalParameter(4); if (cerebAreaMetricsOpt->m_present) { if (cerebAreaSurfsOpt->m_present) { throw OperationException("only one of -cerebellum-area-surfs and -cerebellum-area-metrics can be specified"); } curCerebAreas = cerebAreaMetricsOpt->getMetric(1); newCerebAreas = cerebAreaMetricsOpt->getMetric(2); } } pair colErrors = AlgorithmCiftiResample::checkForErrors(myCiftiIn, CiftiXML::ALONG_COLUMN, myTemplate, templateDir, mySurfMethod, curLeftSphere, newLeftSphere, curLeftAreas, newLeftAreas, curRightSphere, newRightSphere, curRightAreas, newRightAreas, curCerebSphere, newCerebSphere, curCerebAreas, newCerebAreas); pair rowErrors = AlgorithmCiftiResample::checkForErrors(myCiftiIn, CiftiXML::ALONG_ROW, myTemplate, templateDir, mySurfMethod, curLeftSphere, newLeftSphere, curLeftAreas, newLeftAreas, curRightSphere, newRightSphere, curRightAreas, newRightAreas, curCerebSphere, newCerebSphere, curCerebAreas, newCerebAreas); ok = true; AString message; if (rowErrors.first) { message += "Error in resampling along row: " + rowErrors.second; ok = false; } if (colErrors.first) { if (!ok) message += "\n"; message = "Error in resampling along column: " + colErrors.second; ok = false; } if (!ok) { throw OperationException(message); } CiftiFile tempCifti; //TSC: resampling along column first causes it to hit peak memory usage earlier if (warpfieldOpt->m_present) { AlgorithmCiftiResample(myProgObj, myCiftiIn, CiftiXML::ALONG_COLUMN, myTemplate, templateDir, mySurfMethod, myVolMethod, &tempCifti, surfLargest, voldilatemm, surfdilatemm, myWarpfield.getWarpfield(), curLeftSphere, newLeftSphere, curLeftAreas, newLeftAreas, curRightSphere, newRightSphere, curRightAreas, newRightAreas, curCerebSphere, newCerebSphere, curCerebAreas, newCerebAreas, volDilateMethod, volDilateExponent, surfDilateMethod, surfDilateExponent, volLegacyCutoff, surfLegacyCutoff); AlgorithmCiftiResample(myProgObj, &tempCifti, CiftiXML::ALONG_ROW, myTemplate, templateDir, mySurfMethod, myVolMethod, myCiftiOut, surfLargest, voldilatemm, surfdilatemm, myWarpfield.getWarpfield(), curLeftSphere, newLeftSphere, curLeftAreas, newLeftAreas, curRightSphere, newRightSphere, curRightAreas, newRightAreas, curCerebSphere, newCerebSphere, curCerebAreas, newCerebAreas, volDilateMethod, volDilateExponent, surfDilateMethod, surfDilateExponent, volLegacyCutoff, surfLegacyCutoff); } else {//rely on AffineFile() being the identity transform for if neither option is specified AlgorithmCiftiResample(myProgObj, myCiftiIn, CiftiXML::ALONG_COLUMN, myTemplate, templateDir, mySurfMethod, myVolMethod, &tempCifti, surfLargest, voldilatemm, surfdilatemm, myAffine.getMatrix(), curLeftSphere, newLeftSphere, curLeftAreas, newLeftAreas, curRightSphere, newRightSphere, curRightAreas, newRightAreas, curCerebSphere, newCerebSphere, curCerebAreas, newCerebAreas, volDilateMethod, volDilateExponent, surfDilateMethod, surfDilateExponent, volLegacyCutoff, surfLegacyCutoff); AlgorithmCiftiResample(myProgObj, &tempCifti, CiftiXML::ALONG_ROW, myTemplate, templateDir, mySurfMethod, myVolMethod, myCiftiOut, surfLargest, voldilatemm, surfdilatemm, myAffine.getMatrix(), curLeftSphere, newLeftSphere, curLeftAreas, newLeftAreas, curRightSphere, newRightSphere, curRightAreas, newRightAreas, curCerebSphere, newCerebSphere, curCerebAreas, newCerebAreas, volDilateMethod, volDilateExponent, surfDilateMethod, surfDilateExponent, volLegacyCutoff, surfLegacyCutoff); } } connectome-workbench-1.4.2/src/Operations/OperationCiftiResampleDconnMemory.h000066400000000000000000000027271360521144700275110ustar00rootroot00000000000000#ifndef __OPERATION_CIFTI_RESAMPLE_DCONN_MEMORY_H__ #define __OPERATION_CIFTI_RESAMPLE_DCONN_MEMORY_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationCiftiResampleDconnMemory : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationCiftiResampleDconnMemory; } #endif //__OPERATION_CIFTI_RESAMPLE_DCONN_MEMORY_H__ connectome-workbench-1.4.2/src/Operations/OperationCiftiSeparateAll.cxx000066400000000000000000000156741360521144700263430ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AlgorithmCiftiSeparate.h" #include "CiftiFile.h" #include "MetricFile.h" #include "OperationCiftiSeparateAll.h" #include "OperationException.h" #include "VolumeFile.h" using namespace caret; using namespace std; AString OperationCiftiSeparateAll::getCommandSwitch() { return "-cifti-separate-all"; } AString OperationCiftiSeparateAll::getShortDescription() { return "DEPRECATED: use -cifti-separate"; } OperationParameters* OperationCiftiSeparateAll::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-in", "the cifti to split"); OptionalParameter* leftOpt = ret->createOptionalParameter(2, "-left", "output the left surface data"); leftOpt->addMetricOutputParameter(1, "left-metric", "the output metric for the left surface"); OptionalParameter* leftRoiOpt = leftOpt->createOptionalParameter(2, "-left-roi", "output the ROI for the left surface data"); leftRoiOpt->addMetricOutputParameter(1, "left-roi-metric", "output metric for the left ROI"); OptionalParameter* rightOpt = ret->createOptionalParameter(3, "-right", "output the right surface data"); rightOpt->addMetricOutputParameter(1, "right-metric", "the output metric for the right surface"); OptionalParameter* rightRoiOpt = rightOpt->createOptionalParameter(2, "-right-roi", "output the ROI for the right surface data"); rightRoiOpt->addMetricOutputParameter(1, "right-roi-metric", "output metric for the right ROI"); OptionalParameter* cerebOpt = ret->createOptionalParameter(4, "-cerebellum", "output the cerebellum surface data"); cerebOpt->addMetricOutputParameter(1, "cerebellum-metric", "the output metric for the cerebellum surface"); OptionalParameter* cerebRoiOpt = cerebOpt->createOptionalParameter(2, "-cerebellum-roi", "output the ROI for the cerebellum surface data"); cerebRoiOpt->addMetricOutputParameter(1, "cerebellum-roi-metric", "output metric for the cerebellum ROI"); OptionalParameter* volOpt = ret->createOptionalParameter(5, "-volume", "output the voxel data"); volOpt->addVolumeOutputParameter(1, "volume-out", "output volume file"); OptionalParameter* volRoiOpt = volOpt->createOptionalParameter(2, "-volume-roi", "output the combined ROI for the volume data"); volRoiOpt->addVolumeOutputParameter(1, "volume-roi-out", "output volume for ROI"); OptionalParameter* dirOpt = ret->createOptionalParameter(6, "-direction", "choose the direction to separate (default COLUMN)"); dirOpt->addStringParameter(1, "direction", "which direction to separate into components, ROW or COLUMN"); ret->setHelpText( AString("DEPRECATED: this command may be removed in a future release, use -cifti-separate.\n\n") + "All volume components are put together into one volume, the boundaries between volume components are not output by this command. " + "The COLUMN direction (default) is usually what you want, ROW will only work for dconn. " + "Using this command with -volume will usually take (much) more memory than the cifti file, since it must create the whole volume, rather than just the included voxels." ); return ret; } void OperationCiftiSeparateAll::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); CiftiFile* myCifti = myParams->getCifti(1); int myDir = CiftiXMLOld::ALONG_COLUMN; OptionalParameter* dirOpt = myParams->getOptionalParameter(6); if (dirOpt->m_present) { AString dirName = dirOpt->getString(1); if (dirName == "ROW") { myDir = CiftiXMLOld::ALONG_ROW; } else { if (dirName != "COLUMN") { throw OperationException("direction must be 'ROW' or 'COLUMN'"); } } } OptionalParameter* leftOpt = myParams->getOptionalParameter(2); if (leftOpt->m_present) { MetricFile* outData = leftOpt->getOutputMetric(1); MetricFile* outRoi = NULL; OptionalParameter* roiOpt = leftOpt->getOptionalParameter(2); if (roiOpt->m_present) { outRoi = roiOpt->getOutputMetric(1); } processSurfaceComponent(myCifti, StructureEnum::CORTEX_LEFT, myDir, outData, outRoi); } OptionalParameter* rightOpt = myParams->getOptionalParameter(3); if (rightOpt->m_present) { MetricFile* outData = rightOpt->getOutputMetric(1); MetricFile* outRoi = NULL; OptionalParameter* roiOpt = rightOpt->getOptionalParameter(2); if (roiOpt->m_present) { outRoi = roiOpt->getOutputMetric(1); } processSurfaceComponent(myCifti, StructureEnum::CORTEX_RIGHT, myDir, outData, outRoi); } OptionalParameter* cerebOpt = myParams->getOptionalParameter(4); if (cerebOpt->m_present) { MetricFile* outData = cerebOpt->getOutputMetric(1); MetricFile* outRoi = NULL; OptionalParameter* roiOpt = cerebOpt->getOptionalParameter(2); if (roiOpt->m_present) { outRoi = roiOpt->getOutputMetric(1); } processSurfaceComponent(myCifti, StructureEnum::CEREBELLUM, myDir, outData, outRoi); } OptionalParameter* volOpt = myParams->getOptionalParameter(5); if (volOpt->m_present) { VolumeFile* outData = volOpt->getOutputVolume(1); VolumeFile* outRoi = NULL; OptionalParameter* roiOpt = volOpt->getOptionalParameter(2); if (roiOpt->m_present) { outRoi = roiOpt->getOutputVolume(1); } processVolume(myCifti, myDir, outData, outRoi); } } void OperationCiftiSeparateAll::processSurfaceComponent(const CiftiFile* myCifti, const StructureEnum::Enum& myStruct, const int& myDir, MetricFile* outData, MetricFile* outROI) { AlgorithmCiftiSeparate(NULL, myCifti, myDir, myStruct, outData, outROI); } void OperationCiftiSeparateAll::processVolume(const CiftiFile* myCifti, const int& myDir, VolumeFile* outData, VolumeFile* outROI) { int64_t offset[3]; AlgorithmCiftiSeparate(NULL, myCifti, myDir, outData, offset, outROI, false); } connectome-workbench-1.4.2/src/Operations/OperationCiftiSeparateAll.h000066400000000000000000000033541360521144700257600ustar00rootroot00000000000000#ifndef __OPERATION_CIFTI_SEPARATE_ALL_H__ #define __OPERATION_CIFTI_SEPARATE_ALL_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" #include "StructureEnum.h" namespace caret { class OperationCiftiSeparateAll : public AbstractOperation { static void processSurfaceComponent(const CiftiFile* myCifti, const StructureEnum::Enum& myStruct, const int& myDir, MetricFile* outData, MetricFile* outROI = NULL); static void processVolume(const CiftiFile* myCifti, const int& myDir, VolumeFile* outData, VolumeFile* outROI = NULL); public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationCiftiSeparateAll; } #endif //__OPERATION_CIFTI_SEPARATE_ALL_H__ connectome-workbench-1.4.2/src/Operations/OperationCiftiStats.cxx000066400000000000000000000236001360521144700252300ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationCiftiStats.h" #include "OperationException.h" #include "CiftiFile.h" #include "ReductionOperation.h" #include #include #include #include #include #include using namespace caret; using namespace std; AString OperationCiftiStats::getCommandSwitch() { return "-cifti-stats"; } AString OperationCiftiStats::getShortDescription() { return "STATISTICS ALONG CIFTI COLUMNS"; } OperationParameters* OperationCiftiStats::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-in", "the input cifti"); OptionalParameter* reduceOpt = ret->createOptionalParameter(2, "-reduce", "use a reduction operation"); reduceOpt->addStringParameter(1, "operation", "the reduction operation"); OptionalParameter* percentileOpt = ret->createOptionalParameter(3, "-percentile", "give the value at a percentile"); percentileOpt->addDoubleParameter(1, "percent", "the percentile to find"); OptionalParameter* columnOpt = ret->createOptionalParameter(4, "-column", "only display output for one column"); columnOpt->addIntegerParameter(1, "column", "the column index (starting from 1)"); OptionalParameter* roiOpt = ret->createOptionalParameter(5, "-roi", "only consider data inside an roi"); roiOpt->addCiftiParameter(1, "roi-cifti", "the roi, as a cifti file"); roiOpt->createOptionalParameter(2, "-match-maps", "each column of input uses the corresponding column from the roi file"); ret->createOptionalParameter(6, "-show-map-name", "print column index and name before each output"); ret->setHelpText( AString("For each column of the input, a row of text is printed, resulting from the specified reduction or percentile operation. ") + "If -roi is specified without -match-maps, then each row contains as many numbers as there are maps in the ROI file, separated by tab characters. " + "Use -column to only give output for a single data column. " + "Exactly one of -reduce or -percentile must be specified.\n\n" + "The argument to the -reduce option must be one of the following:\n\n" + ReductionOperation::getHelpInfo()); return ret; } namespace { float reduce(const vector& data, const ReductionEnum::Enum& myop, const vector& roiData) { if (roiData.empty()) { return ReductionOperation::reduce(data.data(), data.size(), myop); } else { int64_t numElems = (int64_t)data.size(); CaretAssert(numElems == (int64_t)roiData.size()); vector toUse; toUse.reserve(numElems); for (int64_t i = 0; i < numElems; ++i) { if (roiData[i] > 0.0f) { toUse.push_back(data[i]); } } if (toUse.empty()) throw OperationException("roi column is empty"); return ReductionOperation::reduce(toUse.data(), toUse.size(), myop); } } float percentile(const vector& data, const float& percent, const vector& roiData) { CaretAssert(percent >= 0.0f && percent <= 100.0f); vector toUse; if (roiData.empty()) { toUse = data; } else { int64_t numElems = (int64_t)data.size(); CaretAssert(numElems == (int64_t)roiData.size()); toUse.reserve(numElems); for (int i = 0; i < numElems; ++i) { if (roiData[i] > 0.0f) { toUse.push_back(data[i]); } } } if (toUse.empty()) throw OperationException("roi is empty"); sort(toUse.begin(), toUse.end()); const float index = percent / 100.0f * (toUse.size() - 1); if (index <= 0) return toUse[0]; if (index >= toUse.size() - 1) return toUse.back(); float ipart, fpart; fpart = modf(index, &ipart); return (1.0f - fpart) * toUse[(int)ipart] + fpart * toUse[((int)ipart) + 1]; } } void OperationCiftiStats::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); CiftiFile* myInput = myParams->getCifti(1); const CiftiXML& myXML = myInput->getCiftiXML(); if (myXML.getNumberOfDimensions() != 2) throw OperationException("only 2D cifti are supported in this command"); int64_t numCols = myXML.getDimensionLength(CiftiXML::ALONG_ROW); int64_t colLength = myXML.getDimensionLength(CiftiXML::ALONG_COLUMN); OptionalParameter* reduceOpt = myParams->getOptionalParameter(2); OptionalParameter* percentileOpt = myParams->getOptionalParameter(3); if (reduceOpt->m_present == percentileOpt->m_present)//use == as logical xor { throw OperationException("you must use exactly one of -reduce or -percentile"); } ReductionEnum::Enum myop = ReductionEnum::INVALID; if (reduceOpt->m_present) { bool ok = false; myop = ReductionEnum::fromName(reduceOpt->getString(1), &ok); if (!ok) throw OperationException("unrecognized reduction operation: " + reduceOpt->getString(1)); } float percent = 0.0f; if (percentileOpt->m_present) { percent = (float)percentileOpt->getDouble(1);//use not within range to trap NaNs, just in case if (!(percent >= 0.0f && percent <= 100.0f)) throw OperationException("percentile must be between 0 and 100"); } int useColumn = -1; OptionalParameter* columnOpt = myParams->getOptionalParameter(4); if (columnOpt->m_present) { useColumn = columnOpt->getInteger(1) - 1; if (useColumn < 0 || useColumn >= numCols) throw OperationException("invalid column specified"); } vector roiData; bool matchColumnMode = false; CiftiFile* roiCifti = NULL; int64_t numRois = 1;//trick: pretend we have 1 roi map when we don't have an roi file, for fewer special cases OptionalParameter* roiOpt = myParams->getOptionalParameter(5); if (roiOpt->m_present) { roiCifti = roiOpt->getCifti(1); if (!roiCifti->getCiftiXML().getMap(CiftiXML::ALONG_COLUMN)->approximateMatch(*(myXML.getMap(CiftiXML::ALONG_COLUMN)))) { throw OperationException("roi cifti does not match input cifti along columns"); } roiData.resize(colLength); if (roiOpt->getOptionalParameter(2)->m_present) { if (myXML.getMap(CiftiXML::ALONG_ROW)->getLength() != roiCifti->getCiftiXML().getMap(CiftiXML::ALONG_ROW)->getLength()) { throw OperationException("-match-maps specified, but roi has different number of columns than input"); } matchColumnMode = true; } numRois = roiCifti->getCiftiXML().getDimensionLength(CiftiXML::ALONG_ROW); } bool showMapName = myParams->getOptionalParameter(6)->m_present; const CiftiMappingType* rowMap = myXML.getMap(CiftiXML::ALONG_ROW); vector colScratch(colLength); int64_t columnStart, columnEnd; if (useColumn == -1) { myInput->convertToInMemory();//we will be getting all columns, so read it all in first if (roiCifti != NULL) roiCifti->convertToInMemory();//ditto columnStart = 0; columnEnd = numCols; } else { if (roiCifti != NULL && !matchColumnMode) roiCifti->convertToInMemory();//matching maps with one column selected is the only time we don't need the whole ROI file columnStart = useColumn; columnEnd = useColumn + 1; } for (int i = columnStart; i < columnEnd; ++i) { myInput->getColumn(colScratch.data(), i); if (showMapName) { cout << AString::number(i + 1) << ":\t" << rowMap->getIndexName(i) << ":\t"; } if (matchColumnMode) {//trick: matchColumn is only true when we have an roi roiCifti->getColumn(roiData.data(), i); float result; if (reduceOpt->m_present) { result = reduce(colScratch, myop, roiData); } else { CaretAssert(percentileOpt->m_present); result = percentile(colScratch, percent, roiData); } stringstream resultsstr; resultsstr << setprecision(7) << result; cout << resultsstr.str() << endl; } else { for (int64_t j = 0; j < numRois; ++j) { if (roiCifti != NULL) roiCifti->getColumn(roiData.data(), j); float result; if (reduceOpt->m_present) { result = reduce(colScratch, myop, roiData); } else { CaretAssert(percentileOpt->m_present); result = percentile(colScratch, percent, roiData); } stringstream resultsstr; resultsstr << setprecision(7) << result; if (j != 0) cout << "\t"; cout << resultsstr.str(); } cout << endl; } } } connectome-workbench-1.4.2/src/Operations/OperationCiftiStats.h000066400000000000000000000025751360521144700246650ustar00rootroot00000000000000#ifndef __OPERATION_CIFTI_STATS_H__ #define __OPERATION_CIFTI_STATS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationCiftiStats : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationCiftiStats; } #endif //__OPERATION_CIFTI_STATS_H__ connectome-workbench-1.4.2/src/Operations/OperationCiftiWeightedStats.cxx000066400000000000000000000657011360521144700267210ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationCiftiWeightedStats.h" #include "OperationException.h" #include "CaretHeap.h" #include "CiftiFile.h" #include "MetricFile.h" #include "SurfaceFile.h" #include #include #include #include #include using namespace caret; using namespace std; AString OperationCiftiWeightedStats::getCommandSwitch() { return "-cifti-weighted-stats"; } AString OperationCiftiWeightedStats::getShortDescription() { return "WEIGHTED STATISTICS ALONG CIFTI COLUMNS"; } OperationParameters* OperationCiftiWeightedStats::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addCiftiParameter(1, "cifti-in", "the input cifti"); OptionalParameter* spatialWeightOpt = ret->createOptionalParameter(2, "-spatial-weights", "use vertex area and voxel volume as weights"); OptionalParameter* leftAreaSurfOpt = spatialWeightOpt->createOptionalParameter(1, "-left-area-surf", "use a surface for left vertex areas"); leftAreaSurfOpt->addSurfaceParameter(1, "left-surf", "the left surface to use, areas are in mm^2"); OptionalParameter* rightAreaSurfOpt = spatialWeightOpt->createOptionalParameter(2, "-right-area-surf", "use a surface for right vertex areas"); rightAreaSurfOpt->addSurfaceParameter(1, "right-surf", "the right surface to use, areas are in mm^2"); OptionalParameter* cerebAreaSurfOpt = spatialWeightOpt->createOptionalParameter(3, "-cerebellum-area-surf", "use a surface for cerebellum vertex areas"); cerebAreaSurfOpt->addSurfaceParameter(1, "cerebellum-surf", "the cerebellum surface to use, areas are in mm^2"); OptionalParameter* leftAreaMetricOpt = spatialWeightOpt->createOptionalParameter(4, "-left-area-metric", "use a metric file for left vertex areas"); leftAreaMetricOpt->addMetricParameter(1, "left-metric", "metric file containing left vertex areas"); OptionalParameter* rightAreaMetricOpt = spatialWeightOpt->createOptionalParameter(5, "-right-area-metric", "use a metric file for right vertex areas"); rightAreaMetricOpt->addMetricParameter(1, "right-metric", "metric file containing right vertex areas"); OptionalParameter* cerebAreaMetricOpt = spatialWeightOpt->createOptionalParameter(6, "-cerebellum-area-metric", "use a metric file for cerebellum vertex areas"); cerebAreaMetricOpt->addMetricParameter(1, "cerebellum-metric", "metric file containing cerebellum vertex areas"); OptionalParameter* ciftiWeightOpt = ret->createOptionalParameter(3, "-cifti-weights", "use a cifti file containing weights"); ciftiWeightOpt->addCiftiParameter(1, "weight-cifti", "the weights to use, as a cifti file"); OptionalParameter* columnOpt = ret->createOptionalParameter(4, "-column", "only display output for one column"); columnOpt->addIntegerParameter(1, "column", "the column to use (1-based)"); OptionalParameter* roiOpt = ret->createOptionalParameter(5, "-roi", "only consider data inside an roi"); roiOpt->addCiftiParameter(1, "roi-cifti", "the roi, as a cifti file"); roiOpt->createOptionalParameter(2, "-match-maps", "each column of input uses the corresponding column from the roi file"); ret->createOptionalParameter(6, "-mean", "compute weighted mean"); OptionalParameter* stdevOpt = ret->createOptionalParameter(7, "-stdev", "compute weighted standard deviation"); stdevOpt->createOptionalParameter(1, "-sample", "estimate population stdev from the sample"); OptionalParameter* percentileOpt = ret->createOptionalParameter(8, "-percentile", "compute weighted percentile"); percentileOpt->addDoubleParameter(1, "percent", "the percentile to find"); ret->createOptionalParameter(9, "-sum", "compute weighted sum"); ret->createOptionalParameter(10, "-show-map-name", "print map index and name before each output"); ret->setHelpText( AString("If the mapping along column is brain models, for each column of the input, the specified operation is done on each surface and across all voxels, and the results are printed separately. ") + "For other mapping types, the operation is done on each column, and one number per map is printed. " + "Exactly one of -spatial-weights or -cifti-weights must be specified. " + "Use -column to only give output for a single column. " + "Use -roi to consider only the data within a region. " + "Exactly one of -mean, -stdev, -percentile or -sum must be specified.\n\n" + "Using -sum with -spatial-weights (or with -cifti-weights and a cifti containing weights of similar meaning) is equivalent to integrating with respect to area and volume. " + "When the input is binary ROIs, this will therefore output the area or volume of each ROI." ); return ret; } namespace { enum OperationType { MEAN, STDEV, SAMPSTDEV, PERCENTILE, SUM }; float doOperation(const float* data, const float* weights, const int64_t& numElements, const OperationType& myop, const float* roiData, const float& argument) {//argument is only used for percentile currently if (roiData != NULL) { bool haveData = false; for (int64_t i = 0; i < numElements; ++i) { if (weights[i] > 0.0f) { haveData = true; break; } } if (!haveData) throw OperationException("roi column is empty"); } switch(myop) { case SUM: case MEAN: case STDEV: case SAMPSTDEV://these all start the same way { double accum = 0.0, weightsum = 0.0; for (int64_t i = 0; i < numElements; ++i) { if (roiData == NULL || roiData[i] > 0.0f) { accum += data[i] * weights[i]; weightsum += weights[i]; } } if (myop == SUM) return accum; const float mean = accum / weightsum; if (myop == MEAN) return mean; accum = 0.0; double weightsum2 = 0.0;//for weighted sample stdev for (int64_t i = 0; i < numElements; ++i) { if (roiData == NULL || roiData[i] > 0.0f) { float tempf = data[i] - mean; accum += weights[i] * tempf * tempf; weightsum2 += weights[i] * weights[i]; } } if (myop == STDEV) return sqrt(accum / weightsum); CaretAssert(myop == SAMPSTDEV); return sqrt(accum / (weightsum - weightsum2 / weightsum));//http://en.wikipedia.org/wiki/Weighted_arithmetic_mean#Weighted_sample_variance } case PERCENTILE: { CaretAssert(argument >= 0.0f && argument <= 100.0f); CaretSimpleMinHeap sorter; double weightaccum = 0.0;//double will usually prevent adding weights in a different order from getting a different answer for (int64_t i = 0; i < numElements; ++i) { if (roiData == NULL || roiData[i] > 0.0f) { if (weights[i] < 0.0f) throw OperationException("negative weights not allowed in weighted percentile"); weightaccum += weights[i]; sorter.push(weights[i], data[i]);//sort by value, so the key is the data } } int64_t numUse = sorter.size(); if (numUse == 1)//would need special handling anyway, so get it early { float ret; sorter.top(&ret); return ret; } float targetWeight = argument / 100.0f * weightaccum; float lastData, nextData; float lastWeight = sorter.pop(&lastData); weightaccum = lastWeight; float nextWeight = sorter.top(&nextData); int64_t position = 1;//because the first and last sections get special treatment to not have flat ends on the function while (weightaccum + nextWeight * 0.5f < targetWeight && sorter.size() > 1) { ++position; sorter.pop(); weightaccum += nextWeight; lastWeight = nextWeight; lastData = nextData; nextWeight = sorter.top(&nextData); } if (targetWeight < weightaccum) { if (position == 1) {//stretch interpolation at first position to the edge return lastData + (nextData - lastData) * 0.5f * ((targetWeight - weightaccum) / lastWeight + 1.0f); } else { return lastData + (nextData - lastData) * 0.5f * ((targetWeight - weightaccum) / (lastWeight * 0.5f) + 1.0f); } } else { if (position == numUse - 1) {//ditto return (lastData + nextData) * 0.5f + (nextData - lastData) * 0.5f * (targetWeight - weightaccum) / nextWeight; } else { return (lastData + nextData) * 0.5f + (nextData - lastData) * 0.5f * (targetWeight - weightaccum) / (nextWeight * 0.5f); } } } } CaretAssert(false);//make sure execution never actually reaches end of function throw OperationException("internal error in weighted stats"); } } void OperationCiftiWeightedStats::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); CiftiFile* myInput = myParams->getCifti(1); const CiftiXML& myXML = myInput->getCiftiXML(); if (myXML.getNumberOfDimensions() != 2) throw OperationException("only 2D cifti are supported in this command"); int64_t numCols = myXML.getDimensionLength(CiftiXML::ALONG_ROW); int64_t colLength = myXML.getDimensionLength(CiftiXML::ALONG_COLUMN); OptionalParameter* spatialWeightOpt = myParams->getOptionalParameter(2); OptionalParameter* ciftiWeightOpt = myParams->getOptionalParameter(3); if (spatialWeightOpt->m_present == ciftiWeightOpt->m_present)//use == as logical xnor { throw OperationException("you must use exactly one of -spatial-weights or -cifti-weights"); } vector combinedWeights(colLength); if (spatialWeightOpt->m_present) { if (myXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) throw OperationException("spatial weights require a brain models mapping"); CiftiBrainModelsMap myDenseMap = myXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); OptionalParameter* leftSurfOpt = spatialWeightOpt->getOptionalParameter(1); OptionalParameter* rightSurfOpt = spatialWeightOpt->getOptionalParameter(2); OptionalParameter* cerebSurfOpt = spatialWeightOpt->getOptionalParameter(3); OptionalParameter* leftMetricOpt = spatialWeightOpt->getOptionalParameter(4); OptionalParameter* rightMetricOpt = spatialWeightOpt->getOptionalParameter(5); OptionalParameter* cerebMetricOpt = spatialWeightOpt->getOptionalParameter(6); if (leftSurfOpt->m_present && leftMetricOpt->m_present) throw OperationException("only one of -left-area-surf and -left-area-metric may be specified"); if (rightSurfOpt->m_present && rightMetricOpt->m_present) throw OperationException("only one of -right-area-surf and -right-area-metric may be specified"); if (cerebSurfOpt->m_present && cerebMetricOpt->m_present) throw OperationException("only one of -cerebellum-area-surf and -cerebellum-area-metric may be specified"); vector surfStructs = myDenseMap.getSurfaceStructureList(); int numSurf = (int)surfStructs.size(); for (int i = 0; i < numSurf; ++i) { OptionalParameter* surfOpt = NULL, *metricOpt = NULL; AString structName; switch (surfStructs[i]) { case StructureEnum::CORTEX_LEFT: surfOpt = leftSurfOpt; metricOpt = leftMetricOpt; structName = "left"; break; case StructureEnum::CORTEX_RIGHT: surfOpt = rightSurfOpt; metricOpt = rightMetricOpt; structName = "right"; break; case StructureEnum::CEREBELLUM: surfOpt = cerebSurfOpt; metricOpt = cerebMetricOpt; structName = "cerebellum"; break; default: throw OperationException("unsupported surface structure: " + StructureEnum::toName(surfStructs[i])); } vector myMap = myDenseMap.getSurfaceMap(surfStructs[i]); int mapSize = (int)myMap.size(); if (surfOpt->m_present) { SurfaceFile* mySurf = surfOpt->getSurface(1); if (mySurf->getNumberOfNodes() != myDenseMap.getSurfaceNumberOfNodes(surfStructs[i])) { throw OperationException(structName + " area surface has different number of vertices than cifti file"); } vector surfAreas; mySurf->computeNodeAreas(surfAreas); for (int i = 0; i < mapSize; ++i) { combinedWeights[myMap[i].m_ciftiIndex] = surfAreas[myMap[i].m_surfaceNode]; } } else if (metricOpt->m_present) { MetricFile* myMetric = metricOpt->getMetric(1); if (myMetric->getNumberOfNodes() != myDenseMap.getSurfaceNumberOfNodes(surfStructs[i])) { throw OperationException(structName + " area metric has different number of vertices than cifti file"); } for (int i = 0; i < mapSize; ++i) { combinedWeights[myMap[i].m_ciftiIndex] = myMetric->getValue(myMap[i].m_surfaceNode, 0); } } else { throw OperationException("no area data specified for " + structName + " surface"); } } if (myDenseMap.hasVolumeData()) { float voxelVolume = myDenseMap.getVolumeSpace().getVoxelVolume(); vector volMap = myDenseMap.getFullVolumeMap(); int64_t volMapSize = (int64_t)volMap.size(); for (int64_t i = 0; i < volMapSize; ++i) { combinedWeights[volMap[i].m_ciftiIndex] = voxelVolume; } } } if (ciftiWeightOpt->m_present) { CiftiFile* weightCifti = ciftiWeightOpt->getCifti(1); if (!myXML.getMap(CiftiXML::ALONG_COLUMN)->approximateMatch(*(weightCifti->getCiftiXML().getMap(CiftiXML::ALONG_COLUMN)))) { throw OperationException("weighting cifti has incompatible mapping along column"); } weightCifti->getColumn(combinedWeights.data(), 0);//since we are only using one column, go ahead and call getColumn while it is on disk } int64_t useColumn = -1; OptionalParameter* columnOpt = myParams->getOptionalParameter(4); if (columnOpt->m_present) { useColumn = columnOpt->getInteger(1) - 1;//1-based indexing convention if (useColumn < 0 || useColumn >= numCols) throw OperationException("invalid column specified"); } vector roiData; bool matchColumnMode = false; CiftiFile* myRoi = NULL; int64_t numRoiCols = -1; OptionalParameter* roiOpt = myParams->getOptionalParameter(5); if (roiOpt->m_present) { myRoi = roiOpt->getCifti(1); if (!myXML.getMap(CiftiXML::ALONG_COLUMN)->approximateMatch(*(myRoi->getCiftiXML().getMap(CiftiXML::ALONG_COLUMN)))) { throw OperationException("roi cifti has incompatible mapping along column"); } roiData.resize(colLength); if (roiOpt->getOptionalParameter(2)->m_present) { if (myXML.getMap(CiftiXML::ALONG_ROW)->getLength() != myRoi->getCiftiXML().getMap(CiftiXML::ALONG_ROW)->getLength()) { throw OperationException("-match-maps specified, but roi has different number of columns than input"); } matchColumnMode = true; } numRoiCols = myRoi->getCiftiXML().getDimensionLength(CiftiXML::ALONG_ROW); } bool haveOp = false; OperationType myop; if (myParams->getOptionalParameter(6)->m_present) { haveOp = true; myop = MEAN; } OptionalParameter* stdevOpt = myParams->getOptionalParameter(7); if (stdevOpt->m_present) { if (haveOp) throw OperationException("you may only specify one operation"); haveOp = true; if (stdevOpt->getOptionalParameter(1)->m_present) { myop = SAMPSTDEV; } else { myop = STDEV; } } float argument = -1.0f; OptionalParameter* percentileOpt = myParams->getOptionalParameter(8); if (percentileOpt->m_present) { if (haveOp) throw OperationException("you may only specify one operation"); haveOp = true; myop = PERCENTILE; argument = percentileOpt->getDouble(1); if (!(argument >= 0.0f && argument <= 100.0f)) throw OperationException("percentile must be between 0 and 100"); } if (myParams->getOptionalParameter(9)->m_present) { if (haveOp) throw OperationException("you may only specify one operation"); haveOp = true; myop = SUM; } if (!haveOp) throw OperationException("you must specify an operation"); bool showMapName = myParams->getOptionalParameter(10)->m_present; const CiftiMappingType* rowMap = myXML.getMap(CiftiXML::ALONG_ROW); vector inColumn(colLength); int64_t columnStart, columnEnd; if (useColumn == -1) { myInput->convertToInMemory();//we will be getting all columns, so read it all in first if (myRoi != NULL) myRoi->convertToInMemory();//ditto columnStart = 0; columnEnd = numCols; } else { if (!matchColumnMode && myRoi != NULL) myRoi->convertToInMemory();//matching maps with one column selected is the only time we don't need the whole ROI file columnStart = useColumn; columnEnd = useColumn + 1; } if (myXML.getMappingType(CiftiXML::ALONG_COLUMN) == CiftiMappingType::BRAIN_MODELS) { const CiftiBrainModelsMap& myDenseMap = myXML.getBrainModelsMap(CiftiXML::ALONG_COLUMN); vector myModels = myDenseMap.getModelInfo();//use this so that we get the start and end indices, so we don't have to use cifti separate int numModels = (int)myModels.size(); for (int64_t i = columnStart; i < columnEnd; ++i) { myInput->getColumn(inColumn.data(), i); if (showMapName) { cout << AString::number(i + 1) << ":\t" << rowMap->getIndexName(i) << ":" << endl; } if (matchColumnMode) { myRoi->getColumn(roiData.data(), i);//retrieve the roi data once per map with match maps } for (int j = 0; j < numModels; ++j) {//first, do the surfaces individually if (myModels[j].m_type == CiftiBrainModelsMap::SURFACE) { cout << StructureEnum::toName(myModels[j].m_structure) << ":\t"; if (roiOpt->m_present) { if (matchColumnMode) { float result = doOperation(inColumn.data() + myModels[j].m_indexStart, combinedWeights.data() + myModels[j].m_indexStart, myModels[j].m_indexCount, myop, roiData.data() + myModels[j].m_indexStart, argument); stringstream resultsstr; resultsstr << setprecision(7) << result; cout << resultsstr.str(); } else { for (int k = 0; k < numRoiCols; ++k) { myRoi->getColumn(roiData.data(), k); float result = doOperation(inColumn.data() + myModels[j].m_indexStart, combinedWeights.data() + myModels[j].m_indexStart, myModels[j].m_indexCount, myop, roiData.data() + myModels[j].m_indexStart, argument); stringstream resultsstr; resultsstr << setprecision(7) << result; if (k != 0) cout << "\t"; cout << resultsstr.str(); } } } else { float result = doOperation(inColumn.data() + myModels[j].m_indexStart, combinedWeights.data() + myModels[j].m_indexStart, myModels[j].m_indexCount, myop, NULL, argument); stringstream resultsstr; resultsstr << setprecision(7) << result; cout << resultsstr.str(); } cout << endl; } }//now do volume as one chunk vector volMap = myDenseMap.getFullVolumeMap(); int64_t mapSize = (int64_t)volMap.size(); if (mapSize > 0) { vector volData(mapSize), weightVolData(mapSize); for (int64_t j = 0; j < mapSize; ++j) { volData[j] = inColumn[volMap[j].m_ciftiIndex]; weightVolData[j] = combinedWeights[volMap[j].m_ciftiIndex]; } cout << "VOLUME:\t"; if (roiOpt->m_present) { vector roiVolData(mapSize); if (matchColumnMode) { for (int64_t j = 0; j < mapSize; ++j) { roiVolData[j] = roiData[volMap[j].m_ciftiIndex]; } float result = doOperation(volData.data(), weightVolData.data(), mapSize, myop, roiVolData.data(), argument); stringstream resultsstr; resultsstr << setprecision(7) << result; cout << resultsstr.str(); } else { for (int k = 0; k < numRoiCols; ++k) { myRoi->getColumn(roiData.data(), k); for (int64_t j = 0; j < mapSize; ++j) { roiVolData[j] = roiData[volMap[j].m_ciftiIndex]; } float result = doOperation(volData.data(), weightVolData.data(), mapSize, myop, roiVolData.data(), argument); stringstream resultsstr; resultsstr << setprecision(7) << result; if (k != 0) cout << "\t"; cout << resultsstr.str(); } } } else { float result = doOperation(volData.data(), weightVolData.data(), mapSize, myop, NULL, argument); stringstream resultsstr; resultsstr << setprecision(7) << result; cout << resultsstr.str(); } cout << endl; } } } else { for (int64_t i = columnStart; i < columnEnd; ++i) { myInput->getColumn(inColumn.data(), i); if (showMapName) { cout << AString::number(i + 1) << ":\t" << rowMap->getIndexName(i) << ":\t"; } if (roiOpt->m_present) { if (matchColumnMode) { myRoi->getColumn(roiData.data(), i);//retrieve the roi data once per map with match maps float result = doOperation(inColumn.data(), combinedWeights.data(), colLength, myop, roiData.data(), argument); stringstream resultsstr; resultsstr << setprecision(7) << result; cout << resultsstr.str(); } else { for (int k = 0; k < numRoiCols; ++k) { myRoi->getColumn(roiData.data(), k); float result = doOperation(inColumn.data(), combinedWeights.data(), colLength, myop, roiData.data(), argument); stringstream resultsstr; resultsstr << setprecision(7) << result; if (k != 0) cout << "\t"; cout << resultsstr.str(); } } } else { float result = doOperation(inColumn.data(), combinedWeights.data(), colLength, myop, NULL, argument); stringstream resultsstr; resultsstr << setprecision(7) << result; cout << resultsstr.str(); } cout << endl; } } } connectome-workbench-1.4.2/src/Operations/OperationCiftiWeightedStats.h000066400000000000000000000026601360521144700263410ustar00rootroot00000000000000#ifndef __OPERATION_CIFTI_WEIGHTED_STATS_H__ #define __OPERATION_CIFTI_WEIGHTED_STATS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationCiftiWeightedStats : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationCiftiWeightedStats; } #endif //__OPERATION_CIFTI_WEIGHTED_STATS_H__ connectome-workbench-1.4.2/src/Operations/OperationConvertAffine.cxx000066400000000000000000000133561360521144700257130ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AffineFile.h" #include "OperationConvertAffine.h" #include "OperationException.h" using namespace caret; using namespace std; AString OperationConvertAffine::getCommandSwitch() { return "-convert-affine"; } AString OperationConvertAffine::getShortDescription() { return "CONVERT AN AFFINE FILE BETWEEN CONVENTIONS"; } OperationParameters* OperationConvertAffine::getParameters() { OperationParameters* ret = new OperationParameters(); OptionalParameter* fromWorld = ret->createOptionalParameter(1, "-from-world", "input is a NIFTI 'world' affine"); fromWorld->addStringParameter(1, "input", "the input affine"); fromWorld->createOptionalParameter(2, "-inverse", "for files that use 'target to source' convention"); OptionalParameter* fromITK = ret->createOptionalParameter(5, "-from-itk", "input is an ITK matrix"); fromITK->addStringParameter(1, "input", "the input affine"); OptionalParameter* fromFlirt = ret->createOptionalParameter(2, "-from-flirt", "input is a flirt matrix"); fromFlirt->addStringParameter(1, "input", "the input affine"); fromFlirt->addStringParameter(2, "source-volume", "the source volume used when generating the input affine"); fromFlirt->addStringParameter(3, "target-volume", "the target volume used when generating the input affine"); OptionalParameter* toWorld = ret->createOptionalParameter(3, "-to-world", "write output as a NIFTI 'world' affine"); toWorld->addStringParameter(1, "output", "output - the output affine");//HACK: fake the output formatting, since we don't have a parameter for affine file (hard to do due to multiple on-disk formats) toWorld->createOptionalParameter(2, "-inverse", "write file using 'target to source' convention"); OptionalParameter* toITK = ret->createOptionalParameter(6, "-to-itk", "write output as an ITK affine"); toITK->addStringParameter(1, "output", "output - the output affine"); ParameterComponent* toFlirt = ret->createRepeatableParameter(4, "-to-flirt", "write output as a flirt matrix"); toFlirt->addStringParameter(1, "output", "output - the output affine"); toFlirt->addStringParameter(2, "source-volume", "the volume you want to apply the transform to"); toFlirt->addStringParameter(3, "target-volume", "the target space you want the transformed volume to match"); ret->setHelpText( AString("NIFTI world matrices can be used directly on mm coordinates via matrix multiplication, they use the NIFTI coordinate system, that is, ") + "positive X is right, positive Y is anterior, and positive Z is superior. " + "Note that wb_command assumes that world matrices transform source coordinates to target coordinates, " + "while other tools may use affines that transform target coordinates to source coordinates.\n\n" + "The ITK format is used by ANTS.\n\n" + "You must specify exactly one -from option, but you may specify multiple -to options, and -to-flirt may be specified more than once." ); return ret; } void OperationConvertAffine::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AffineFile myAffine; bool haveInput = false; OptionalParameter* fromWorld = myParams->getOptionalParameter(1); if (fromWorld->m_present) { haveInput = true; myAffine.readWorld(fromWorld->getString(1), fromWorld->getOptionalParameter(2)->m_present); } OptionalParameter* fromFlirt = myParams->getOptionalParameter(2); if (fromFlirt->m_present) { if (haveInput) throw OperationException("only one -from option may be specified"); haveInput = true; myAffine.readFlirt(fromFlirt->getString(1), fromFlirt->getString(2), fromFlirt->getString(3)); } OptionalParameter* fromITK = myParams->getOptionalParameter(5); if (fromITK->m_present) { if (haveInput) throw OperationException("only one -from option may be specified"); haveInput = true; myAffine.readITK(fromITK->getString(1)); } if (!haveInput) throw OperationException("you must specify a -from option"); OptionalParameter* toWorld = myParams->getOptionalParameter(3); if (toWorld->m_present) { myAffine.writeWorld(toWorld->getString(1), toWorld->getOptionalParameter(2)->m_present); } const vector& toFlirt = *(myParams->getRepeatableParameterInstances(4));//the return of this is a pointer so that it can return NULL if the key is wrong, after asserting int numFlirt = (int)toFlirt.size();//so, dereference immediately since it should be caught in debug via assert for (int i = 0; i < numFlirt; ++i) { myAffine.writeFlirt(toFlirt[i]->getString(1), toFlirt[i]->getString(2), toFlirt[i]->getString(3)); } OptionalParameter* toITK = myParams->getOptionalParameter(6); if (toITK->m_present) { myAffine.writeITK(toITK->getString(1)); } } connectome-workbench-1.4.2/src/Operations/OperationConvertAffine.h000066400000000000000000000026171360521144700253360ustar00rootroot00000000000000#ifndef __OPERATION_CONVERT_AFFINE_H__ #define __OPERATION_CONVERT_AFFINE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationConvertAffine : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationConvertAffine; } #endif //__OPERATION_CONVERT_AFFINE_H__ connectome-workbench-1.4.2/src/Operations/OperationConvertFiberOrientations.cxx000066400000000000000000000223621360521144700301460ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationConvertFiberOrientations.h" #include "OperationException.h" #include "CiftiFile.h" #include "VolumeFile.h" using namespace caret; using namespace std; AString OperationConvertFiberOrientations::getCommandSwitch() { return "-convert-fiber-orientations"; } AString OperationConvertFiberOrientations::getShortDescription() { return "CONVERT BINGHAM PARAMETER VOLUMES TO FIBER ORIENTATION FILE"; } OperationParameters* OperationConvertFiberOrientations::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "label-volume", "volume of cifti structure labels"); ret->addCiftiOutputParameter(2, "fiber-out", "the output fiber orientation file"); ParameterComponent* fiberOpt = ret->createRepeatableParameter(3, "-fiber", "specify the parameter volumes for a fiber"); fiberOpt->addVolumeParameter(1, "mean-f", "mean fiber strength"); fiberOpt->addVolumeParameter(2, "stdev-f", "standard deviation of fiber strength"); fiberOpt->addVolumeParameter(3, "theta", "theta angle"); fiberOpt->addVolumeParameter(4, "phi", "phi angle"); fiberOpt->addVolumeParameter(5, "psi", "psi angle"); fiberOpt->addVolumeParameter(6, "ka", "ka bingham parameter"); fiberOpt->addVolumeParameter(7, "kb", "kb bingham parameter"); AString myText = AString("Takes precomputed bingham parameters from volume files and converts them to the format workbench uses for display. ") + "The argument must be a label volume, where the labels use these strings:\n\n"; vector myStructureEnums; StructureEnum::getAllEnums(myStructureEnums); for (int i = 0; i < (int)myStructureEnums.size(); ++i) { myText += "\n" + StructureEnum::toName(myStructureEnums[i]); } ret->setHelpText(myText); return ret; } void OperationConvertFiberOrientations::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); VolumeFile* labelVol = myParams->getVolume(1); if (labelVol->getType() != SubvolumeAttributes::LABEL) { throw OperationException(" must have a label table, see -volume-label-import"); } CiftiFile* ciftiOut = myParams->getOutputCifti(2); const vector& myInstances = *(myParams->getRepeatableParameterInstances(3)); int numFibers = (int)myInstances.size(); if (numFibers < 1) throw OperationException("must specify -fiber at least once"); if (numFibers > 3) throw OperationException("only three fibers are supported at this time"); for (int i = 0; i < numFibers; ++i) { VolumeFile* meanfvol = myInstances[i]->getVolume(1); VolumeFile* stdevfvol = myInstances[i]->getVolume(2); VolumeFile* thetavol = myInstances[i]->getVolume(3); VolumeFile* phivol = myInstances[i]->getVolume(4); VolumeFile* psivol = myInstances[i]->getVolume(5); VolumeFile* kavol = myInstances[i]->getVolume(6); VolumeFile* kbvol = myInstances[i]->getVolume(7); if (!labelVol->matchesVolumeSpace(meanfvol) || !labelVol->matchesVolumeSpace(stdevfvol) || !labelVol->matchesVolumeSpace(thetavol) || !labelVol->matchesVolumeSpace(phivol) || !labelVol->matchesVolumeSpace(psivol) || !labelVol->matchesVolumeSpace(kavol) || !labelVol->matchesVolumeSpace(kbvol)) { throw OperationException("all inputs must be in the same volume space"); } } map labelMap;//maps label values to structures vector > voxelLists;//voxel lists for each volume component map componentMap;//maps structures to indexes in voxelLists const GiftiLabelTable* myLabelTable = labelVol->getMapLabelTable(0); vector labelKeys; myLabelTable->getKeys(labelKeys); int count = 0; for (int i = 0; i < (int)labelKeys.size(); ++i) { bool ok = false; StructureEnum::Enum thisStructure = StructureEnum::fromName(myLabelTable->getLabelName(labelKeys[i]), &ok); if (ok) { if (componentMap.find(thisStructure) == componentMap.end())//make sure we don't already have this structure from another label { labelMap[labelKeys[i]] = thisStructure; componentMap[thisStructure] = count; ++count; } } } voxelLists.resize(count); vector mydims; labelVol->getDimensions(mydims); for (int64_t k = 0; k < mydims[2]; ++k) { for (int64_t j = 0; j < mydims[1]; ++j) { for (int64_t i = 0; i < mydims[0]; ++i) { int myval = (int)floor(labelVol->getValue(i, j, k) + 0.5f); map::iterator myiter = labelMap.find(myval); if (myiter != labelMap.end()) { int whichList = componentMap.find(myiter->second)->second;//this should always find one, so we don't need to check for being end voxelLists[whichList].push_back(i); voxelLists[whichList].push_back(j); voxelLists[whichList].push_back(k); } } } } int64_t ciftiVolDims[3]; ciftiVolDims[0] = mydims[0]; ciftiVolDims[1] = mydims[1]; ciftiVolDims[2] = mydims[2]; CiftiXMLOld myXML; myXML.resetColumnsToBrainModels(); myXML.setVolumeDimsAndSForm(ciftiVolDims, labelVol->getSform()); for (map::iterator myiter = componentMap.begin(); myiter != componentMap.end(); ++myiter) { myXML.addVolumeModelToColumns(voxelLists[myiter->second], myiter->first); } myXML.resetRowsToScalars(24); myXML.setMapNameForRowIndex(0, "x coord"); myXML.setMapNameForRowIndex(1, "y coord"); myXML.setMapNameForRowIndex(2, "z coord"); myXML.setMapNameForRowIndex(3, "mean f1"); myXML.setMapNameForRowIndex(4, "stdev f1"); myXML.setMapNameForRowIndex(5, "theta1"); myXML.setMapNameForRowIndex(6, "phi1"); myXML.setMapNameForRowIndex(7, "ka1"); myXML.setMapNameForRowIndex(8, "kb1"); myXML.setMapNameForRowIndex(9, "psi1"); myXML.setMapNameForRowIndex(10, "mean f2"); myXML.setMapNameForRowIndex(11, "stdev f2"); myXML.setMapNameForRowIndex(12, "theta2"); myXML.setMapNameForRowIndex(13, "phi2"); myXML.setMapNameForRowIndex(14, "ka2"); myXML.setMapNameForRowIndex(15, "kb2"); myXML.setMapNameForRowIndex(16, "psi2"); myXML.setMapNameForRowIndex(17, "mean f3"); myXML.setMapNameForRowIndex(18, "stdev f3"); myXML.setMapNameForRowIndex(19, "theta3"); myXML.setMapNameForRowIndex(20, "phi3"); myXML.setMapNameForRowIndex(21, "ka3"); myXML.setMapNameForRowIndex(22, "kb3"); myXML.setMapNameForRowIndex(23, "psi3"); ciftiOut->setCiftiXML(myXML); vector volMap; CaretArray temprow(24, 0.0f); temprow[14] = 1.0f;//do not put zeros in ka and kb, ever temprow[15] = 1.0f; temprow[21] = 1.0f; temprow[22] = 1.0f; myXML.getVolumeMapForColumns(volMap);//we don't need to know which voxel is from which parcel int64_t end = (int64_t)volMap.size(); for (int64_t i = 0; i < end; ++i) { labelVol->indexToSpace(volMap[i].m_ijk, temprow);//first three elements are the coordinates for (int j = 0; j < numFibers; ++j) { int base = 7 * j + 3; VolumeFile* meanfvol = myInstances[j]->getVolume(1); VolumeFile* stdevfvol = myInstances[j]->getVolume(2); VolumeFile* thetavol = myInstances[j]->getVolume(3); VolumeFile* phivol = myInstances[j]->getVolume(4); VolumeFile* psivol = myInstances[j]->getVolume(5); VolumeFile* kavol = myInstances[j]->getVolume(6); VolumeFile* kbvol = myInstances[j]->getVolume(7); temprow[base] = meanfvol->getValue(volMap[i].m_ijk); temprow[base + 1] = stdevfvol->getValue(volMap[i].m_ijk); temprow[base + 2] = thetavol->getValue(volMap[i].m_ijk); temprow[base + 3] = phivol->getValue(volMap[i].m_ijk); temprow[base + 4] = kavol->getValue(volMap[i].m_ijk); temprow[base + 5] = kbvol->getValue(volMap[i].m_ijk); temprow[base + 6] = psivol->getValue(volMap[i].m_ijk); } ciftiOut->setRow(temprow, volMap[i].m_ciftiIndex); } } connectome-workbench-1.4.2/src/Operations/OperationConvertFiberOrientations.h000066400000000000000000000027241360521144700275730ustar00rootroot00000000000000#ifndef __OPERATION_CONVERT_FIBER_ORIENTATIONS_H__ #define __OPERATION_CONVERT_FIBER_ORIENTATIONS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationConvertFiberOrientations : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationConvertFiberOrientations; } #endif //__OPERATION_CONVERT_FIBER_ORIENTATIONS_H__ connectome-workbench-1.4.2/src/Operations/OperationConvertMatrix4ToMatrix2.cxx000066400000000000000000000121521360521144700276160ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationConvertMatrix4ToMatrix2.h" #include "OperationException.h" #include "CiftiFile.h" #include "CaretSparseFile.h" using namespace caret; using namespace std; AString OperationConvertMatrix4ToMatrix2::getCommandSwitch() { return "-convert-matrix4-to-matrix2"; } AString OperationConvertMatrix4ToMatrix2::getShortDescription() { return "GENERATES A MATRIX2 CIFTI FROM MATRIX4 WBSPARSE"; } OperationParameters* OperationConvertMatrix4ToMatrix2::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "matrix4-wbsparse", "a wbsparse matrix4 file"); ret->addCiftiOutputParameter(2, "counts-out", "the total fiber counts, as a cifti file"); OptionalParameter* distanceOpt = ret->createOptionalParameter(3, "-distances", "output average trajectory distance"); distanceOpt->addCiftiOutputParameter(1, "distance-out", "the distances, as a cifti file"); OptionalParameter* fibersOpt = ret->createOptionalParameter(4, "-individual-fibers", "output files for each fiber direction"); fibersOpt->addCiftiOutputParameter(1, "fiber-1", "output file for first fiber"); fibersOpt->addCiftiOutputParameter(2, "fiber-2", "output file for second fiber"); fibersOpt->addCiftiOutputParameter(3, "fiber-3", "output file for third fiber"); ret->setHelpText( AString("This command makes a cifti file from the fiber counts in a matrix4 wbsparse file, and optionally a second cifti file from the distances. ") + "Note that while the total count is stored exactly, the per-fiber counts are stored as approximate fractions, so the output of -individual-fibers will contain nonintegers." ); return ret; } void OperationConvertMatrix4ToMatrix2::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString matrix4Name = myParams->getString(1); CiftiFile* myCountsOut = myParams->getOutputCifti(2); CiftiFile* myDistOut = NULL; OptionalParameter* distanceOpt = myParams->getOptionalParameter(3); if (distanceOpt->m_present) { myDistOut = distanceOpt->getOutputCifti(1); } CiftiFile* fiber1 = NULL, *fiber2 = NULL, *fiber3 = NULL; OptionalParameter* fibersOpt = myParams->getOptionalParameter(4); if (fibersOpt->m_present) { fiber1 = fibersOpt->getOutputCifti(1); fiber2 = fibersOpt->getOutputCifti(2); fiber3 = fibersOpt->getOutputCifti(3); } CaretSparseFile matrix4(matrix4Name); const CiftiXML& myXML = matrix4.getCiftiXML(); myCountsOut->setCiftiXML(myXML); if (myDistOut != NULL) myDistOut->setCiftiXML(myXML); if (fiber1 != NULL) { fiber1->setCiftiXML(myXML); fiber2->setCiftiXML(myXML); fiber3->setCiftiXML(myXML); } int rowSize = myXML.getDimensionLength(CiftiXML::ALONG_ROW), numRows = myXML.getDimensionLength(CiftiXML::ALONG_COLUMN); for (int i = 0; i < numRows; ++i) { vector scratchRow(rowSize, 0.0f); vector scratchFiber1 = scratchRow, scratchFiber2 = scratchRow, scratchFiber3 = scratchRow; vector indices; vector fibers; matrix4.getFibersRowSparse(i, indices, fibers); int numIndices = (int)indices.size(); for (int j = 0; j < numIndices; ++j) { scratchRow[indices[j]] = fibers[j].totalCount; if (fiber1 != NULL) { CaretAssert(fibers[j].fiberFractions.size() == 3); scratchFiber1[indices[j]] = fibers[j].totalCount * fibers[j].fiberFractions[0]; scratchFiber2[indices[j]] = fibers[j].totalCount * fibers[j].fiberFractions[1]; scratchFiber3[indices[j]] = fibers[j].totalCount * fibers[j].fiberFractions[2]; } } myCountsOut->setRow(scratchRow.data(), i); if (fiber1 != NULL) { fiber1->setRow(scratchFiber1.data(), i); fiber2->setRow(scratchFiber2.data(), i); fiber3->setRow(scratchFiber3.data(), i); } if (myDistOut != NULL) { for (int j = 0; j < numIndices; ++j) { scratchRow[indices[j]] = fibers[j].distance; } myDistOut->setRow(scratchRow.data(), i); } } } connectome-workbench-1.4.2/src/Operations/OperationConvertMatrix4ToMatrix2.h000066400000000000000000000027211360521144700272440ustar00rootroot00000000000000#ifndef __OPERATION_CONVERT_MATRIX4_TO_MATRIX2_H__ #define __OPERATION_CONVERT_MATRIX4_TO_MATRIX2_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationConvertMatrix4ToMatrix2 : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationConvertMatrix4ToMatrix2; } #endif //__OPERATION_CONVERT_MATRIX4_TO_MATRIX2_H__ connectome-workbench-1.4.2/src/Operations/OperationConvertMatrix4ToWorkbenchSparse.cxx000066400000000000000000000236621360521144700314000ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationConvertMatrix4ToWorkbenchSparse.h" #include "OperationException.h" #include "CaretHeap.h" #include "CaretSparseFile.h" #include "CiftiFile.h" #include "OxfordSparseThreeFile.h" #include "MetricFile.h" #include "VolumeFile.h" #include #include #include #include #include using namespace caret; using namespace std; AString OperationConvertMatrix4ToWorkbenchSparse::getCommandSwitch() { return "-convert-matrix4-to-workbench-sparse"; } AString OperationConvertMatrix4ToWorkbenchSparse::getShortDescription() { return "CONVERT A 3-FILE MATRIX4 TO A WORKBENCH SPARSE FILE"; } OperationParameters* OperationConvertMatrix4ToWorkbenchSparse::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "matrix4_1", "the first matrix4 file"); ret->addStringParameter(2, "matrix4_2", "the second matrix4 file"); ret->addStringParameter(3, "matrix4_3", "the third matrix4 file"); ret->addCiftiParameter(4, "orientation-file", "the .fiberTEMP.nii file this trajectory file applies to"); ret->addStringParameter(5, "voxel-list", "list of white matter voxel index triplets as used in the trajectory matrix"); ret->addStringParameter(6, "wb-sparse-out", "output - the output workbench sparse file"); OptionalParameter* surfaceOpt = ret->createOptionalParameter(7, "-surface-seeds", "specify the surface seed space"); surfaceOpt->addMetricParameter(1, "seed-roi", "metric roi file of all vertices used in the seed space"); OptionalParameter* volumeOpt = ret->createOptionalParameter(8, "-volume-seeds", "specify the volume seed space"); volumeOpt->addCiftiParameter(1, "cifti-template", "cifti file to use the volume mappings from"); volumeOpt->addStringParameter(2, "direction", "dimension along the cifti file to take the mapping from, ROW or COLUMN"); ret->setHelpText( AString("Converts the matrix 4 output of probtrackx to workbench sparse file format. ") + "Exactly one of -surface-seeds and -volume-seeds must be specified." ); return ret; } void OperationConvertMatrix4ToWorkbenchSparse::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString inFile1 = myParams->getString(1); AString inFile2 = myParams->getString(2); AString inFile3 = myParams->getString(3); AString voxelFileName = myParams->getString(5); CiftiFile* orientationFile = myParams->getCifti(4); AString outFileName = myParams->getString(6); OxfordSparseThreeFile inFile(inFile1, inFile2, inFile3); const int64_t* sparseDims = inFile.getDimensions(); OptionalParameter* surfaceOpt = myParams->getOptionalParameter(7); OptionalParameter* volumeOpt = myParams->getOptionalParameter(8); if (surfaceOpt->m_present == volumeOpt->m_present) throw OperationException("you must specify exactly one of -surface-seeds and -volume-seeds");//use == on booleans as xnor const CiftiXML& orientXML = orientationFile->getCiftiXML(); if (orientXML.getMappingType(CiftiXML::ALONG_COLUMN) != CiftiMappingType::BRAIN_MODELS) throw OperationException("orientation file must have brain models mapping along column"); CiftiXML myXML; myXML.setNumberOfDimensions(2); myXML.setMap(CiftiXML::ALONG_ROW, *(orientXML.getMap(CiftiXML::ALONG_COLUMN))); if (surfaceOpt->m_present) { MetricFile* myROI = surfaceOpt->getMetric(1); const float* roiData = myROI->getValuePointerForColumn(0); CiftiBrainModelsMap tempMap; tempMap.addSurfaceModel(myROI->getNumberOfNodes(), myROI->getStructure(), roiData); if (tempMap.getLength() != sparseDims[1]) { throw OperationException("roi has a different number of selected vertices than the input matrix"); } myXML.setMap(CiftiXML::ALONG_COLUMN, tempMap); } if (volumeOpt->m_present) { CiftiFile* myTemplate = volumeOpt->getCifti(1); AString directionName = volumeOpt->getString(2); int myDir = -1; if (directionName == "ROW") { myDir = CiftiXML::ALONG_ROW; } else if (directionName == "COLUMN") { myDir = CiftiXML::ALONG_COLUMN; } else { throw OperationException("direction must be ROW or COLUMN"); } const CiftiXML& templateXML = myTemplate->getCiftiXML(); if (templateXML.getMappingType(myDir) != CiftiMappingType::BRAIN_MODELS) throw OperationException("template cifti file must have brain models along specified direction"); const CiftiBrainModelsMap& templateMap = templateXML.getBrainModelsMap(myDir); if (!templateMap.hasVolumeData()) throw OperationException("template cifti file has no volume data"); vector surfList = templateMap.getSurfaceStructureList(), volList = templateMap.getVolumeStructureList();//since we only need the volume models, we don't need to loop through all models CiftiBrainModelsMap tempMap; tempMap.setVolumeSpace(templateMap.getVolumeSpace()); for (int i = 0; i < (int)volList.size(); ++i) { vector myMap = templateMap.getVolumeStructureMap(volList[i]); int64_t mapSize = (int64_t)myMap.size(); vector ijkList; for (int64_t j = 0; j < mapSize; ++j) { ijkList.push_back(myMap[j].m_ijk[0]); ijkList.push_back(myMap[j].m_ijk[1]); ijkList.push_back(myMap[j].m_ijk[2]); } tempMap.addVolumeModel(volList[i], ijkList); } if (tempMap.getLength() != sparseDims[1]) throw OperationException("volume models in template cifti file do not match the dimension of the input file"); myXML.setMap(CiftiXML::ALONG_COLUMN, tempMap); } CaretAssert(myXML.getDimensionLength(CiftiXML::ALONG_COLUMN) == sparseDims[1]); fstream voxelFile(voxelFileName.toLocal8Bit().constData(), fstream::in); if (!voxelFile.good()) { throw OperationException("failed to open voxel list file for reading"); } const CiftiBrainModelsMap& rowMap = myXML.getBrainModelsMap(CiftiXML::ALONG_ROW);//tested above, as orientationXML const int64_t* volDims = rowMap.getVolumeSpace().getDims(); vector voxelIndices; int64_t ind1, ind2, ind3; while (voxelFile >> ind1 >> ind2 >> ind3) { if (min(min(ind1, ind2), ind3) < 0) throw OperationException("negative voxel index found in voxel list"); if (ind1 >= volDims[0] || ind2 >= volDims[1] || ind3 >= volDims[2]) throw OperationException("found voxel index that exceeds dimension in voxel list"); voxelIndices.push_back(ind1); voxelIndices.push_back(ind2); voxelIndices.push_back(ind3); } if (!voxelFile.eof()) { voxelFile.clear(); string mystring; while (getline(voxelFile, mystring)) { if (AString(mystring.c_str()).trimmed() != "") { throw OperationException("found non-digit, non-whitespace characters: " + AString(mystring.c_str())); } } } if ((int64_t)voxelIndices.size() != sparseDims[0] * 3) throw OperationException("voxel list file contains the wrong number of voxels, expected " + AString::number(sparseDims[0] * 3) + " integers, read " + AString::number(voxelIndices.size())); vector rowReorder(sparseDims[0], -1); for (int64_t i = 0; i < (int64_t)voxelIndices.size(); i += 3) { int64_t tempInd = rowMap.getIndexForVoxel(voxelIndices.data() + i); if (tempInd != -1) { rowReorder[i / 3] = tempInd; } } CaretSparseFileWriter mywriter(outFileName, myXML);//NOTE: CaretSparseFile has a different encoding of fibers, ALWAYS use getFibersRow, etc vector indicesIn, indicesOut;//this method knows about sparseness, does sorting of indexes in order to avoid scanning full rows vector fibersIn, fibersOut;//can be slower if matrix isn't very sparse, but that is a problem for other reasons anyway CaretMinHeap myHeap;//use our heap to do heapsort, rather than coding a struct for stl sort for (int64_t i = 0; i < sparseDims[1]; ++i) { inFile.getFibersRowSparse(i, indicesIn, fibersIn); size_t numNonzero = indicesIn.size(); myHeap.reserve(numNonzero); for (size_t j = 0; j < numNonzero; ++j) { int64_t newIndex = rowReorder[indicesIn[j]];//reorder if (newIndex != -1) { myHeap.push(fibersIn[j], newIndex);//heapify } } indicesOut.resize(myHeap.size()); fibersOut.resize(myHeap.size()); int64_t curIndex = 0; while (!myHeap.isEmpty()) { int64_t newIndex; fibersOut[curIndex] = myHeap.pop(&newIndex); indicesOut[curIndex] = newIndex; ++curIndex; } mywriter.writeFibersRowSparse(i, indicesOut, fibersOut); } mywriter.finish(); } connectome-workbench-1.4.2/src/Operations/OperationConvertMatrix4ToWorkbenchSparse.h000066400000000000000000000030041360521144700310110ustar00rootroot00000000000000#ifndef __OPERATION_CONVERT_MATRIX4_TO_WORKBENCH_SPARSE_H__ #define __OPERATION_CONVERT_MATRIX4_TO_WORKBENCH_SPARSE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationConvertMatrix4ToWorkbenchSparse : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationConvertMatrix4ToWorkbenchSparse; } #endif //__OPERATION_CONVERT_MATRIX4_TO_WORKBENCH_SPARSE_H__ connectome-workbench-1.4.2/src/Operations/OperationConvertWarpfield.cxx000066400000000000000000000133131360521144700264310ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationConvertWarpfield.h" #include "OperationException.h" #include "WarpfieldFile.h" using namespace caret; using namespace std; AString OperationConvertWarpfield::getCommandSwitch() { return "-convert-warpfield"; } AString OperationConvertWarpfield::getShortDescription() { return "CONVERT A WARPFIELD BETWEEN CONVENTIONS"; } OperationParameters* OperationConvertWarpfield::getParameters() { OperationParameters* ret = new OperationParameters(); OptionalParameter* fromWorld = ret->createOptionalParameter(1, "-from-world", "input is a NIFTI 'world' warpfield"); fromWorld->addStringParameter(1, "input", "the input warpfield"); OptionalParameter* fromITK = ret->createOptionalParameter(5, "-from-itk", "input is an ITK warpfield"); fromITK->addStringParameter(1, "input", "the input warpfield"); OptionalParameter* fromFnirt = ret->createOptionalParameter(2, "-from-fnirt", "input is a fnirt warpfield"); fromFnirt->addStringParameter(1, "input", "the input warpfield"); fromFnirt->addStringParameter(2, "source-volume", "the source volume used when generating the input warpfield"); fromFnirt->createOptionalParameter(3, "-absolute", "warpfield was written in absolute convention, rather than relative"); OptionalParameter* toWorld = ret->createOptionalParameter(3, "-to-world", "write output as a NIFTI 'world' warpfield"); toWorld->addStringParameter(1, "output", "output - the output warpfield");//HACK: fake the output formatting, since the warpfield uses separate calls for writing each output type, and by design doesn't give access to the raw with-quirks volume file OptionalParameter* toITK = ret->createOptionalParameter(6, "-to-itk", "write output as an ITK warpfield"); toITK->addStringParameter(1, "output", "output - the output warpfield"); ParameterComponent* toFnirt = ret->createRepeatableParameter(4, "-to-fnirt", "write output as a fnirt warpfield"); toFnirt->addStringParameter(1, "output", "output - the output warpfield");//this argument order is different than other commands, yes - but don't change it, so scripts will still work toFnirt->addStringParameter(2, "source-volume", "the volume you want to apply the warpfield to"); ret->setHelpText( AString("NIFTI world warpfields can be used directly on mm coordinates via sampling the three subvolumes at the coordinate ") + "and adding the sampled values to the coordinate vector. " + "They use the NIFTI coordinate system, that is, X is left to right, Y is posterior to anterior, and Z is inferior to superior.\n\n" + "NOTE: this command does not invert the warpfield, and to warp a surface, you must use the inverse of the warpfield that warps the corresponding volume.\n\n" + "The ITK format is used by ANTS.\n\n" + "You must specify exactly one -from option, but you may specify multiple -to options, and -to-fnirt may be specified more than once." ); return ret; } void OperationConvertWarpfield::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); WarpfieldFile myWarp; bool haveInput = false; OptionalParameter* fromWorld = myParams->getOptionalParameter(1); OptionalParameter* fromITK = myParams->getOptionalParameter(5); OptionalParameter* fromFnirt = myParams->getOptionalParameter(2); if (fromWorld->m_present) { haveInput = true; } if (fromITK->m_present) { if (haveInput) throw OperationException("only one -from option may be specified"); haveInput = true; } if (fromFnirt->m_present) { if (haveInput) throw OperationException("only one -from option may be specified"); haveInput = true; } if (!haveInput) throw OperationException("you must specify a -from option"); if (fromWorld->m_present) { myWarp.readWorld(fromWorld->getString(1)); } if (fromITK->m_present) { myWarp.readITK(fromITK->getString(1)); } if (fromFnirt->m_present) { myWarp.readFnirt(fromFnirt->getString(1), fromFnirt->getString(2), fromFnirt->getOptionalParameter(3)->m_present); } OptionalParameter* toWorld = myParams->getOptionalParameter(3); OptionalParameter* toITK = myParams->getOptionalParameter(6); if (toWorld->m_present) { myWarp.writeWorld(toWorld->getString(1)); } if (toITK->m_present) { myWarp.writeITK(toITK->getString(1)); } const vector& toFnirt = *(myParams->getRepeatableParameterInstances(4));//the return of this is a pointer so that it can return NULL if the key is wrong, after asserting int numFnirt = (int)toFnirt.size();//so, dereference immediately since it should be caught in debug via assert for (int i = 0; i < numFnirt; ++i) { myWarp.writeFnirt(toFnirt[i]->getString(1), toFnirt[i]->getString(2)); } } connectome-workbench-1.4.2/src/Operations/OperationConvertWarpfield.h000066400000000000000000000026411360521144700260600ustar00rootroot00000000000000#ifndef __OPERATION_CONVERT_WARPFIELD_H__ #define __OPERATION_CONVERT_WARPFIELD_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationConvertWarpfield : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationConvertWarpfield; } #endif //__OPERATION_CONVERT_WARPFIELD_H__ connectome-workbench-1.4.2/src/Operations/OperationEstimateFiberBinghams.cxx000066400000000000000000000343211360521144700273510ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationEstimateFiberBinghams.h" #include "OperationException.h" #include "CiftiFile.h" #include "MathFunctions.h" #include "StructureEnum.h" #include "Vector3D.h" #include "VolumeFile.h" #include #include using namespace caret; using namespace std; AString OperationEstimateFiberBinghams::getCommandSwitch() { return "-estimate-fiber-binghams"; } AString OperationEstimateFiberBinghams::getShortDescription() { return "ESTIMATE FIBER ORIENTATION DISTRIBUTIONS FROM BEDPOSTX SAMPLES"; } OperationParameters* OperationEstimateFiberBinghams::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "merged_f1samples", "fiber 1 strength samples"); ret->addVolumeParameter(2, "merged_th1samples", "fiber 1 theta samples"); ret->addVolumeParameter(3, "merged_ph1samples", "fiber 1 phi samples"); ret->addVolumeParameter(4, "merged_f2samples", "fiber 2 strength samples"); ret->addVolumeParameter(5, "merged_th2samples", "fiber 2 theta samples"); ret->addVolumeParameter(6, "merged_ph2samples", "fiber 2 phi samples"); ret->addVolumeParameter(7, "merged_f3samples", "fiber 3 strength samples"); ret->addVolumeParameter(8, "merged_th3samples", "fiber 3 theta samples"); ret->addVolumeParameter(9, "merged_ph3samples", "fiber 3 phi samples"); ret->addVolumeParameter(10, "label-volume", "volume of cifti structure labels"); ret->addCiftiOutputParameter(11, "cifti-out", "output cifti fiber distributons file"); AString myText = AString("This command does an estimation of a bingham distribution for each fiber orientation in each voxel which is ") + "labeled a structure identifier. These labelings come from the argument, which must have labels that match the following strings:\n"; vector myStructureEnums; StructureEnum::getAllEnums(myStructureEnums); for (int i = 0; i < (int)myStructureEnums.size(); ++i) { myText += "\n" + StructureEnum::toName(myStructureEnums[i]); } ret->setHelpText(myText); return ret; } void OperationEstimateFiberBinghams::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); const VolumeFile* f1_samples = myParams->getVolume(1); const VolumeFile* th1_samples = myParams->getVolume(2); const VolumeFile* ph1_samples = myParams->getVolume(3); const VolumeFile* f2_samples = myParams->getVolume(4); const VolumeFile* th2_samples = myParams->getVolume(5); const VolumeFile* ph2_samples = myParams->getVolume(6); const VolumeFile* f3_samples = myParams->getVolume(7); const VolumeFile* th3_samples = myParams->getVolume(8); const VolumeFile* ph3_samples = myParams->getVolume(9); const VolumeFile* myVolLabel = myParams->getVolume(10); if (myVolLabel->getType() != SubvolumeAttributes::LABEL) { throw OperationException(" must have a label table, see -volume-label-import"); } if (!(myVolLabel->matchesVolumeSpace(f1_samples) && myVolLabel->matchesVolumeSpace(th1_samples) && myVolLabel->matchesVolumeSpace(ph1_samples) && myVolLabel->matchesVolumeSpace(f2_samples) && myVolLabel->matchesVolumeSpace(th2_samples) && myVolLabel->matchesVolumeSpace(ph2_samples) && myVolLabel->matchesVolumeSpace(f3_samples) && myVolLabel->matchesVolumeSpace(th3_samples) && myVolLabel->matchesVolumeSpace(ph3_samples))) { throw OperationException("all inputs must be in the same volume space"); } int64_t junk, numfsamp, numthsamp, numphsamp; f1_samples->getDimensions(junk, junk, junk, numfsamp, junk); th1_samples->getDimensions(junk, junk, junk, numthsamp, junk); ph1_samples->getDimensions(junk, junk, junk, numphsamp, junk); if (numfsamp != numthsamp || numfsamp != numphsamp) { throw OperationException("fiber 1 volumes have different numbers of samples"); } f2_samples->getDimensions(junk, junk, junk, numfsamp, junk); th2_samples->getDimensions(junk, junk, junk, numthsamp, junk); ph2_samples->getDimensions(junk, junk, junk, numphsamp, junk); if (numfsamp != numthsamp || numfsamp != numphsamp) { throw OperationException("fiber 2 volumes have different numbers of samples"); } f3_samples->getDimensions(junk, junk, junk, numfsamp, junk); th3_samples->getDimensions(junk, junk, junk, numthsamp, junk); ph3_samples->getDimensions(junk, junk, junk, numphsamp, junk); if (numfsamp != numthsamp || numfsamp != numphsamp) { throw OperationException("fiber 3 volumes have different numbers of samples"); } map labelMap;//maps label values to structures vector > voxelLists;//voxel lists for each volume component map componentMap;//maps structures to indexes in voxelLists const GiftiLabelTable* myLabelTable = myVolLabel->getMapLabelTable(0); vector labelKeys; myLabelTable->getKeys(labelKeys); int count = 0; for (int i = 0; i < (int)labelKeys.size(); ++i) { bool ok = false; StructureEnum::Enum thisStructure = StructureEnum::fromName(myLabelTable->getLabelName(labelKeys[i]), &ok); if (ok) { if (componentMap.find(thisStructure) == componentMap.end())//make sure we don't already have this structure from another label { labelMap[labelKeys[i]] = thisStructure; componentMap[thisStructure] = count; ++count; } } } voxelLists.resize(count); vector mydims; myVolLabel->getDimensions(mydims); for (int64_t k = 0; k < mydims[2]; ++k) { for (int64_t j = 0; j < mydims[1]; ++j) { for (int64_t i = 0; i < mydims[0]; ++i) { int myval = (int)floor(myVolLabel->getValue(i, j, k) + 0.5f); map::iterator myiter = labelMap.find(myval); if (myiter != labelMap.end()) { int whichList = componentMap.find(myiter->second)->second;//this should always find one, so we don't need to check for being end voxelLists[whichList].push_back(i); voxelLists[whichList].push_back(j); voxelLists[whichList].push_back(k); } } } } int64_t ciftiVolDims[3]; ciftiVolDims[0] = mydims[0]; ciftiVolDims[1] = mydims[1]; ciftiVolDims[2] = mydims[2]; CiftiXMLOld myXML; myXML.resetColumnsToBrainModels(); myXML.setVolumeDimsAndSForm(ciftiVolDims, myVolLabel->getSform()); for (map::iterator myiter = componentMap.begin(); myiter != componentMap.end(); ++myiter) { myXML.addVolumeModelToColumns(voxelLists[myiter->second], myiter->first); } myXML.resetRowsToScalars(24); myXML.setMapNameForRowIndex(0, "x coord"); myXML.setMapNameForRowIndex(1, "y coord"); myXML.setMapNameForRowIndex(2, "z coord"); myXML.setMapNameForRowIndex(3, "mean f1"); myXML.setMapNameForRowIndex(4, "stdev f1"); myXML.setMapNameForRowIndex(5, "theta1"); myXML.setMapNameForRowIndex(6, "phi1"); myXML.setMapNameForRowIndex(7, "ka1"); myXML.setMapNameForRowIndex(8, "kb1"); myXML.setMapNameForRowIndex(9, "psi1"); myXML.setMapNameForRowIndex(10, "mean f2"); myXML.setMapNameForRowIndex(11, "stdev f2"); myXML.setMapNameForRowIndex(12, "theta2"); myXML.setMapNameForRowIndex(13, "phi2"); myXML.setMapNameForRowIndex(14, "ka2"); myXML.setMapNameForRowIndex(15, "kb2"); myXML.setMapNameForRowIndex(16, "psi2"); myXML.setMapNameForRowIndex(17, "mean f3"); myXML.setMapNameForRowIndex(18, "stdev f3"); myXML.setMapNameForRowIndex(19, "theta3"); myXML.setMapNameForRowIndex(20, "phi3"); myXML.setMapNameForRowIndex(21, "ka3"); myXML.setMapNameForRowIndex(22, "kb3"); myXML.setMapNameForRowIndex(23, "psi3"); CiftiFile* myCifti = myParams->getOutputCifti(11); myCifti->setCiftiXML(myXML); vector volMap; CaretArray temprow(24); myXML.getVolumeMapForColumns(volMap);//we don't need to know which voxel is from which parcel int64_t end = (int64_t)volMap.size(); for (int64_t i = 0; i < end; ++i) { myVolLabel->indexToSpace(volMap[i].m_ijk, temprow);//first three elements are the coordinates estimateBingham(temprow.getArray() + 3, volMap[i].m_ijk, f1_samples, th1_samples, ph1_samples); estimateBingham(temprow.getArray() + 10, volMap[i].m_ijk, f2_samples, th2_samples, ph2_samples); estimateBingham(temprow.getArray() + 17, volMap[i].m_ijk, f3_samples, th3_samples, ph3_samples); myCifti->setRow(temprow, volMap[i].m_ciftiIndex); } } void OperationEstimateFiberBinghams::estimateBingham(float* binghamOut, const int64_t ijk[3], const VolumeFile* f_samples, const VolumeFile* theta_samples, const VolumeFile* phi_samples) { vector fdims; f_samples->getDimensions(fdims); vector samples(fdims[3]); vector fsamplearray(fdims[3]);//to do two-pass mean/stdev without using the VolumeFile function twice per sample double accum = 0.0; Vector3D accumvec;//initializes to the zero vector for (int i = 0; i < fdims[3]; ++i) { fsamplearray[i] = f_samples->getValue(ijk, i); accum += fsamplearray[i]; float theta = theta_samples->getValue(ijk, i);//these have already been checked to have the same number of bricks float phi = phi_samples->getValue(ijk, i); samples[i][0] = -sin(theta) * cos(phi);//NOTE: theta, phi are polar coordinates for a RADIOLOGICAL volume, so flip x so that +x = right samples[i][1] = sin(theta) * sin(phi);//ignore the f values for directionality testing samples[i][2] = cos(theta);//beware, samples may be the negative of other samples, BAS model doesn't care, and they may have restricted the samples to +z or something if (i != 0) { if (accumvec.dot(samples[i]) < 0.0f)//invert the ones that have a negative dot product with the current accumulated vector, and hope the first samples don't have a spread of more than 90 degrees { samples[i] = -samples[i]; } } accumvec += samples[i]; } accumvec = accumvec.normal();//normalize the average direction, trust this to make all components in [-1, 1] binghamOut[0] = accum / fdims[3];//the mean value of f accum = 0.0; for (int i = 0; i < fdims[3]; ++i) { float temp = fsamplearray[i] - binghamOut[0]; accum += temp * temp; } binghamOut[1] = sqrt(accum / (fdims[3] - 1));//sample standard deviation float theta = acos(accumvec[2]);//[0, pi] float phi = atan2(accumvec[1], -accumvec[0]);//[-pi, pi] - NOTE: radiological polar strikes again if (phi < 0.0f) phi += 2 * 3.14159265358979;//[0, 2pi] binghamOut[2] = theta; binghamOut[3] = phi; Vector3D xhat, yhat;//vectors to project to the normal plane of the average direction, assuming psi=0 xhat[0] = cos(theta) * cos(phi);//more radiological polar to neurological euclidean stuff xhat[1] = -cos(theta) * sin(phi); xhat[2] = sin(theta); yhat[0] = sin(phi); yhat[1] = cos(phi); yhat[2] = 0.0f; vector x_samples(fdims[3]), y_samples(fdims[3]); float dist = -1.0f; int end1 = -1, end2 = -1; for (int i = 0; i < fdims[3]; ++i)//first endpoint is farthest from mean direction { x_samples[i] = samples[i].dot(xhat); y_samples[i] = samples[i].dot(yhat); float tempf = x_samples[i] * x_samples[i] + y_samples[i] * y_samples[i]; if (tempf > dist) { end1 = i; dist = tempf; } } dist = -1.0f; for (int i = 0; i < fdims[3]; ++i)//second endpoint is farthest from first endpoint { float xdiff = x_samples[i] - x_samples[end1]; float ydiff = y_samples[i] - y_samples[end1]; float tempf = xdiff * xdiff + ydiff * ydiff; if (tempf > dist) { end2 = i; dist = tempf; } }//NOTE: the MAJOR axis of fanning is along y when psi = 0! ka > kb means kb is in the direction of more fanning float psi = atan((x_samples[end2] - x_samples[end1]) / (y_samples[end2] - y_samples[end1]));//[-pi/2, pi/2] - TODO: check radiological psi orientation if (!MathFunctions::isNumeric(psi)) { const float LARGE_K = 1800.0f;//stdev of 1/60, typical maximum ka in a voxel is around 200 binghamOut[4] = LARGE_K; binghamOut[5] = LARGE_K; binghamOut[6] = 0; return; } if (psi < 0) psi += 3.14159265358979;//[0, pi] binghamOut[6] = psi; double accumx = 0.0, accumy = 0.0; for (int i = 0; i < fdims[3]; ++i) {//rotate the samples through -psi on the plane to orient them to the axes float newx = x_samples[i] * cos(psi) + y_samples[i] * -sin(psi);//NOTE: again, radiological psi? float newy = x_samples[i] * sin(psi) + y_samples[i] * cos(psi); accumx += newx * newx;//assume mean of zero, because we already chose the center of the distribution accumy += newy * newy; } float ka = (fdims[3] - 1) / (2 * accumx);//convert variance to concentrations float kb = (fdims[3] - 1) / (2 * accumy);//but they aren't negative binghamOut[4] = ka; binghamOut[5] = kb; } connectome-workbench-1.4.2/src/Operations/OperationEstimateFiberBinghams.h000066400000000000000000000032021360521144700267700ustar00rootroot00000000000000#ifndef __OPERATION_ESTIMATE_FIBER_BINGHAMS_H__ #define __OPERATION_ESTIMATE_FIBER_BINGHAMS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationEstimateFiberBinghams : public AbstractOperation { static void estimateBingham(float* binghamOut, const int64_t ijk[3], const caret::VolumeFile* f_samples, const caret::VolumeFile* theta_samples, const caret::VolumeFile* phi_samples); public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationEstimateFiberBinghams; } #endif //__OPERATION_ESTIMATE_FIBER_BINGHAMS_H__ connectome-workbench-1.4.2/src/Operations/OperationException.cxx000066400000000000000000000042431360521144700251130ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationException.h" #include using namespace caret; /** * Constructor. * */ OperationException::OperationException() : CaretException() { this->initializeMembersOperationException(); } /** * Constructor that uses stack trace from the exception * passed in as a parameter. * * @param e Any exception whose stack trace becomes * this exception's stack trace. * */ OperationException::OperationException( const CaretException& e) : CaretException(e) { this->initializeMembersOperationException(); } /** * Constructor. * * @param s Description of the exception. * */ OperationException::OperationException(const AString& s) : CaretException(s) { this->initializeMembersOperationException(); } /** * Copy Constructor. * @param e * Exception that is copied. */ OperationException::OperationException(const OperationException& e) : CaretException(e) { } /** * Assignment operator. * @param e * Exception that is copied. * @return * Copy of the exception. */ OperationException& OperationException::operator=(const OperationException& e) { if (this != &e) { CaretException::operator=(e); } return *this; } /** * Destructor */ OperationException::~OperationException() throw() { } void OperationException::initializeMembersOperationException() { } connectome-workbench-1.4.2/src/Operations/OperationException.h000066400000000000000000000027421360521144700245420ustar00rootroot00000000000000#ifndef __OPERATION_EXCEPTION_H__ #define __OPERATION_EXCEPTION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretException.h" namespace caret { /// An exception thrown during command processing. class OperationException : public CaretException { public: OperationException(); OperationException(const CaretException& e); OperationException(const AString& s); OperationException(const OperationException& e); OperationException& operator=(const OperationException& e); virtual ~OperationException() throw(); private: void initializeMembersOperationException(); }; } // namespace #endif // __OPERATION_EXCEPTION_H__ connectome-workbench-1.4.2/src/Operations/OperationFileConvert.cxx000066400000000000000000000276231360521144700254040ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationFileConvert.h" #include "OperationException.h" #include "BorderFile.h" #include "Border.h" #include "CaretLogger.h" #include "CiftiFile.h" #include "FileInformation.h" #include "MultiDimIterator.h" #include "NiftiIO.h" #include "SurfaceFile.h" using namespace caret; using namespace std; AString OperationFileConvert::getCommandSwitch() { return "-file-convert"; } AString OperationFileConvert::getShortDescription() { return "CHANGE VERSION OF FILE FORMAT"; } OperationParameters* OperationFileConvert::getParameters() { OperationParameters* ret = new OperationParameters(); OptionalParameter* borderConv = ret->createOptionalParameter(1, "-border-version-convert", "write a border file with a different version"); borderConv->addBorderParameter(1, "border-in", "the input border file"); borderConv->addIntegerParameter(2, "out-version", "the format version to write as, 1 or 3 (2 doesn't exist)"); borderConv->addStringParameter(3, "border-out", "output - the output border file");//fake the output formatting, the auto-output code will use whatever version it wants OptionalParameter* borderSurfOpt = borderConv->createOptionalParameter(4, "-surface", "must be specified if the input is version 1"); borderSurfOpt->addSurfaceParameter(1, "surface", "use this surface file for structure and number of vertices, ignore borders on other structures"); OptionalParameter* niftiConv = ret->createOptionalParameter(2, "-nifti-version-convert", "write a nifti file with a different version"); niftiConv->addStringParameter(1, "input", "the input nifti file");//VolumeFile isn't "generic nifti", so we use NiftiIO directly niftiConv->addIntegerParameter(2, "version", "the nifti version to write as"); niftiConv->addStringParameter(3, "output", "output - the output nifti file");//fake the output formatting, we don't have a "generic nifti" type OptionalParameter* ciftiConv = ret->createOptionalParameter(3, "-cifti-version-convert", "write a cifti file with a different version"); ciftiConv->addCiftiParameter(1, "cifti-in", "the input cifti file"); ciftiConv->addStringParameter(2, "version", "the cifti version to write as"); ciftiConv->addStringParameter(3, "cifti-out", "output - the output cifti file");//fake the output formatting so we can just call writeFile and be done with it (and also not add a layer of provenance) ret->setHelpText( AString("You may only specify one top-level option.") ); return ret; } namespace //hide helpers in a file-specific namespace { //hidden templated function to do generic nifti reading and writing template void niftiConvertHelper(NiftiIO& inputIO, const AString& outFileName, const int64_t& maxMem, const int& outVer, const bool& collision) { const vector dims = inputIO.getDimensions();//DO NOT make this a reference if (collision) { int64_t totalBytes = (int)sizeof(T) * inputIO.getNumComponents(), totalElems = inputIO.getNumComponents();//compute memory usage to check whether to warn for (int fullDims = 0; fullDims < (int)dims.size(); ++fullDims) { totalBytes *= dims[fullDims]; totalElems *= dims[fullDims]; } if (totalBytes > maxMem) { CaretLogInfo("collision between input and output filenames, reading input file into memory"); } else { CaretLogFine("collision between input and output filenames, reading input file into memory"); } vector scratchmem(totalElems); inputIO.readData(scratchmem.data(), dims.size(), vector()); inputIO.close();//don't have it try to close after being overwritten NiftiIO outputIO;//now we can open the output file outputIO.writeNew(outFileName, inputIO.getHeader(), outVer);//NOTE: this keeps data scaling fields, data type, extensions, header fields we ignore, etc outputIO.writeData(scratchmem.data(), dims.size(), vector()); } else { NiftiIO outputIO; outputIO.writeNew(outFileName, inputIO.getHeader(), outVer);//NOTE: this keeps data scaling fields, data type, extensions, header fields we ignore, etc int64_t totalBytes = (int)sizeof(T) * inputIO.getNumComponents(), totalElems = inputIO.getNumComponents(); int fullDims = 0; for (; fullDims < (int)dims.size() && totalBytes * dims[fullDims] < maxMem; ++fullDims) { totalBytes *= dims[fullDims]; totalElems *= dims[fullDims]; } vector remainDims(dims.begin() + fullDims, dims.end()); vector scratchmem(totalElems);//this is the main purpose of the template... for (MultiDimIterator myiter(remainDims); !myiter.atEnd(); ++myiter) { inputIO.readData(scratchmem.data(), fullDims, *myiter);//...which results in these templating over the desired type outputIO.writeData(scratchmem.data(), fullDims, *myiter); } } } } void OperationFileConvert::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); OptionalParameter* borderConv = myParams->getOptionalParameter(1); OptionalParameter* niftiConv = myParams->getOptionalParameter(2); OptionalParameter* ciftiConv = myParams->getOptionalParameter(3); int numChosen = 0; if (borderConv->m_present) ++numChosen; if (niftiConv->m_present) ++numChosen; if (ciftiConv->m_present) ++numChosen; if (numChosen != 1) throw OperationException("you must choose exactly one top level option"); if (borderConv->m_present) { const BorderFile* borderIn = borderConv->getBorder(1); int outVersion = (int)borderConv->getInteger(2); AString outFilename = borderConv->getString(3); BorderFile borderOut; int numBorders = borderIn->getNumberOfBorders(); if (borderIn->getNumberOfNodes() < 1)//version 1 border file { OptionalParameter* surfOpt = borderConv->getOptionalParameter(4); if (!surfOpt->m_present) throw OperationException("version 1 border files require the -surface suboption for conversion"); SurfaceFile* convSurf = surfOpt->getSurface(1); StructureEnum::Enum myStructure = convSurf->getStructure(); borderOut.setStructure(myStructure); borderOut.setNumberOfNodes(convSurf->getNumberOfNodes()); for (int i = 0; i < numBorders; ++i) { const Border* thisBorder = borderIn->getBorder(i); if (thisBorder->getStructure() == myStructure) { borderOut.addBorder(new Border(*thisBorder));//takes ownership of RAW POINTER } } } else { borderOut.setStructure(borderIn->getStructure()); borderOut.setNumberOfNodes(borderIn->getNumberOfNodes()); for (int i = 0; i < numBorders; ++i) { borderOut.addBorder(new Border(*borderIn->getBorder(i)));//ditto } } borderOut.writeFile(outFilename, outVersion); } if (niftiConv->m_present) { AString inFileName = niftiConv->getString(1); int outVer = (int)niftiConv->getInteger(2); AString outFileName = niftiConv->getString(3); const int64_t maxMem = 1<<29;//half gigabyte - will usually be much less, could be an option NiftiIO inputIO; inputIO.openRead(inFileName); const NiftiHeader& inHeader = inputIO.getHeader(); FileInformation outInfo(outFileName), inInfo(inFileName); bool collision = false; if (outInfo.getCanonicalFilePath() != "" && outInfo.getCanonicalFilePath() == inInfo.getCanonicalFilePath()) {//collision! can't do on-disk reading during writing collision = true; } double mult, offset;//if the offset is large compared to the scale, it is nontrivial to deduce a suitable type to preserve sufficient precision to round back to the unscaled input values if (inHeader.getDataScaling(mult, offset))//we can't use the on-disk type because we don't provide access to the unscaled (wrong) values {//alternatively, we could give read/write access to the unscaled values, but that is distasteful niftiConvertHelper(inputIO, outFileName, maxMem, outVer, collision);//so, always use long double to reduce rounding problems, even if it is often massive overkill } else { switch (inHeader.getDataType()) { case NIFTI_TYPE_UINT8: case NIFTI_TYPE_RGB24: niftiConvertHelper(inputIO, outFileName, maxMem, outVer, collision); break; case NIFTI_TYPE_INT8: niftiConvertHelper(inputIO, outFileName, maxMem, outVer, collision); break; case NIFTI_TYPE_UINT16: niftiConvertHelper(inputIO, outFileName, maxMem, outVer, collision); break; case NIFTI_TYPE_INT16: niftiConvertHelper(inputIO, outFileName, maxMem, outVer, collision); break; case NIFTI_TYPE_UINT32: niftiConvertHelper(inputIO, outFileName, maxMem, outVer, collision); break; case NIFTI_TYPE_INT32: niftiConvertHelper(inputIO, outFileName, maxMem, outVer, collision); break; case NIFTI_TYPE_UINT64: niftiConvertHelper(inputIO, outFileName, maxMem, outVer, collision); break; case NIFTI_TYPE_INT64: niftiConvertHelper(inputIO, outFileName, maxMem, outVer, collision); break; case NIFTI_TYPE_FLOAT32: case NIFTI_TYPE_COMPLEX64: niftiConvertHelper(inputIO, outFileName, maxMem, outVer, collision); break; case NIFTI_TYPE_FLOAT64: case NIFTI_TYPE_COMPLEX128: niftiConvertHelper(inputIO, outFileName, maxMem, outVer, collision); break; case NIFTI_TYPE_FLOAT128: case NIFTI_TYPE_COMPLEX256: niftiConvertHelper(inputIO, outFileName, maxMem, outVer, collision); break; default: throw OperationException("unsupported nifti datatype"); } } } if (ciftiConv->m_present) { CiftiFile* ciftiIn = ciftiConv->getCifti(1); AString versionString = ciftiConv->getString(2); AString outFileName = ciftiConv->getString(3); ciftiIn->writeFile(outFileName, CiftiVersion(versionString));//also handles complications like writing to the same file as it is set to read on-disk from } } connectome-workbench-1.4.2/src/Operations/OperationFileConvert.h000066400000000000000000000026031360521144700250200ustar00rootroot00000000000000#ifndef __OPERATION_FILE_CONVERT_H__ #define __OPERATION_FILE_CONVERT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationFileConvert : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationFileConvert; } #endif //__OPERATION_FILE_CONVERT_H__ connectome-workbench-1.4.2/src/Operations/OperationFileInformation.cxx000066400000000000000000000224561360521144700262500ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretDataFile.h" #include "CaretDataFileHelper.h" #include "CaretMappableDataFile.h" #include "CaretPointer.h" #include "CiftiMappableDataFile.h" #include "CiftiFile.h" #include "CiftiXML.h" #include "DataFileContentInformation.h" #include "DataFileException.h" #include "GiftiMetaData.h" #include "OperationFileInformation.h" #include "OperationException.h" using namespace caret; using namespace std; /** * \class caret::OperationFileInformation * \brief List information about a file's content */ /** * @return Command line switch */ AString OperationFileInformation::getCommandSwitch() { return "-file-information"; } /** * @return Short description of operation */ AString OperationFileInformation::getShortDescription() { return "LIST INFORMATION ABOUT A FILE'S CONTENT"; } /** * @return Parameters for operation */ OperationParameters* OperationFileInformation::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "data-file", "data file"); ret->createOptionalParameter(2, "-no-map-info", "do not show map information for files that support maps"); ret->createOptionalParameter(3, "-only-step-interval", "suppress normal output, print the interval between maps"); ret->createOptionalParameter(4, "-only-number-of-maps", "suppress normal output, print the number of maps"); ret->createOptionalParameter(5, "-only-map-names", "suppress normal output, print the names of all maps"); OptionalParameter* metadataOpt = ret->createOptionalParameter(6, "-only-metadata", "suppress normal output, print file metadata"); OptionalParameter* mdKeyOpt = metadataOpt->createOptionalParameter(1, "-key", "only print the metadata for one key, with no formatting"); mdKeyOpt->addStringParameter(1, "key", "the metadata key"); ret->createOptionalParameter(7, "-only-cifti-xml", "suppress normal output, print the cifti xml if the file type has it"); AString helpText("List information about the content of a data file. " "Only one -only option may be specified. " "The information listed when no -only option is present is dependent upon the type of data file."); ret->setHelpText(helpText); return ret; } /** * Use Parameters and perform operation */ void OperationFileInformation::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); const AString dataFileName = myParams->getString(1); const bool showMapInformationFlag = ! (myParams->getOptionalParameter(2)->m_present); int countOnlys = 0; bool onlyTimestep = myParams->getOptionalParameter(3)->m_present; if (onlyTimestep) ++countOnlys; bool onlyNumMaps = myParams->getOptionalParameter(4)->m_present; if (onlyNumMaps) ++countOnlys; bool onlyMapNames = myParams->getOptionalParameter(5)->m_present; if (onlyMapNames) ++countOnlys; OptionalParameter* metadataOpt = myParams->getOptionalParameter(6); bool onlyMetadata = metadataOpt->m_present; AString mdKey = ""; if (onlyMetadata) { ++countOnlys; OptionalParameter* mdKeyOpt = metadataOpt->getOptionalParameter(1); if (mdKeyOpt->m_present) { mdKey = mdKeyOpt->getString(1); if (mdKey == "") { throw OperationException(" must not be empty"); } } } bool onlyCiftiXML = myParams->getOptionalParameter(7)->m_present; if (onlyCiftiXML) ++countOnlys; if (countOnlys > 1) throw OperationException("only one -only-* option may be specified"); bool preferOnDisk = (!showMapInformationFlag || countOnlys != 0); CaretPointer caretDataFile; CiftiFile nonstandardCifti; const GiftiMetaData* nonstandardMD = NULL; DataFileContentInformation nonstandardInfo; try { caretDataFile.grabNew(CaretDataFileHelper::readAnyCaretDataFile(dataFileName, preferOnDisk)); } catch (...) {//still fails if the Cifti XML has a nonstandard mapping combination try { CiftiMappableDataFile::getDataFileContentInformationForGenericCiftiFile(dataFileName, nonstandardInfo); nonstandardCifti.openFile(dataFileName); nonstandardMD = nonstandardCifti.getCiftiXML().getFileMetaData(); } catch (...) { throw OperationException("unable to open file '" + dataFileName + "', check the format and file extension"); } } //readAnyCaretDataFile now handles cifti files with the wrong extension //FIXME: does not handle cifti files with unusual mappings if (onlyTimestep) { CaretMappableDataFile* mappableFile = dynamic_cast(caretDataFile.getPointer()); if (mappableFile == NULL) throw OperationException("file does not support maps");//TODO: also give error on things that it doesn't make sense on? if (mappableFile->getMapIntervalUnits() == NiftiTimeUnitsEnum::NIFTI_UNITS_UNKNOWN) throw OperationException("file does not support series data"); float start, step; mappableFile->getMapIntervalStartAndStep(start, step); cout << step << endl; } if (onlyNumMaps) { CaretMappableDataFile* mappableFile = dynamic_cast(caretDataFile.getPointer()); if (mappableFile == NULL) throw OperationException("file does not support maps");//TODO: also give error on things that it doesn't make sense on? int numMaps = mappableFile->getNumberOfMaps(); if (numMaps < 1) throw OperationException("file does not support maps"); cout << numMaps << endl; } if (onlyMapNames) { CaretMappableDataFile* mappableFile = dynamic_cast(caretDataFile.getPointer()); if (mappableFile == NULL) throw OperationException("file does not support maps");//TODO: also give error on things that it doesn't make sense on? int numMaps = mappableFile->getNumberOfMaps(); if (numMaps < 1) throw OperationException("file does not support maps"); for (int i = 0; i < numMaps; ++i) { cout << mappableFile->getMapName(i) << endl; } } if (onlyMetadata) { const GiftiMetaData* myMD = NULL; if (caretDataFile != NULL) { myMD = caretDataFile->getFileMetaData(); } else { myMD = nonstandardMD; } CaretAssert(myMD != NULL); if (mdKey == "") { const map mdMap = myMD->getAsMap(); for (map::const_iterator iter = mdMap.begin(); iter != mdMap.end(); ++iter) { cout << " " << iter->first << ":" << endl; cout << iter->second << endl << endl; } } else { if (!myMD->exists(mdKey)) { throw OperationException("specified metadata key is not present in the file"); } cout << myMD->get(mdKey) << endl; } } if (onlyCiftiXML) { const CiftiXML* myXML = NULL; CiftiXML tempXML;//because CaretMappableDataFile doesn't return the XML as a pointer if (caretDataFile == NULL) { myXML = &(nonstandardCifti.getCiftiXML()); } else { CaretMappableDataFile* mappableFile = dynamic_cast(caretDataFile.getPointer()); if (mappableFile != NULL && mappableFile->hasCiftiXML()) { tempXML = mappableFile->getCiftiXML(); myXML = &tempXML; } } if (myXML != NULL) { cout << myXML->writeXMLToString(myXML->getParsedVersion()) << endl; } } if (countOnlys == 0) { if (caretDataFile != NULL) { DataFileContentInformation dataFileContentInformation; dataFileContentInformation.setOptionFlag(DataFileContentInformation::OPTION_SHOW_MAP_INFORMATION, showMapInformationFlag); caretDataFile->addToDataFileContentInformation(dataFileContentInformation); cout << qPrintable(dataFileContentInformation.getInformationInString()) << endl; } else { cout << qPrintable(nonstandardInfo.getInformationInString()) << endl; } } } connectome-workbench-1.4.2/src/Operations/OperationFileInformation.h000066400000000000000000000027131360521144700256670ustar00rootroot00000000000000#ifndef __OPERATION_FILE_INFORMATION_H__ #define __OPERATION_FILE_INFORMATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationFileInformation : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationFileInformation; } // namespace #endif //__OPERATION_FILE_INFORMATION_H__ connectome-workbench-1.4.2/src/Operations/OperationFociCreate.cxx000066400000000000000000000171601360521144700251630ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationFociCreate.h" #include "OperationException.h" #include "CaretLogger.h" #include "FileInformation.h" #include "FociFile.h" #include "Focus.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "SurfaceProjector.h" #include #include #include #include #include using namespace caret; using namespace std; AString OperationFociCreate::getCommandSwitch() { return "-foci-create"; } AString OperationFociCreate::getShortDescription() { return "CREATE A FOCI FILE"; } OperationParameters* OperationFociCreate::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addFociOutputParameter(1, "output", "the output foci file"); ParameterComponent* fociOpt = ret->createRepeatableParameter(2, "-class", "specify class input data"); fociOpt->addStringParameter(1, "class-name", "name of class"); fociOpt->addStringParameter(2, "foci-list-file", "text file containing foci names, coordinates, and colors"); fociOpt->addSurfaceParameter(3, "surface", "surface file for projection of foci list file"); ret->setHelpText( AString("Creates a foci file from names, coordinates, and RGB values in a text file. ") + "The text file must have the following format (2 lines per focus):\n\n" + "\n" " \n...\n\n" + "Foci names are specified on a separate line from their coordinates and color, in order to let foci names contain spaces. " + "Whitespace is trimmed from both ends of the foci name, but is kept if it is in the middle of a name. " + "The values of , , and must be integers from 0 to 255, and will specify the color the foci is drawn as.\n\n" + "Foci are grouped into classes and the name for the class is specified using the parameter.\n\n" + "All foci within one text file must be associated with the structure contained in the " "parameter and are projected to that surface." ); return ret; } void OperationFociCreate::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); FociFile* outputFociFile = myParams->getOutputFoci(1); const vector& myInputs = *(myParams->getRepeatableParameterInstances(2)); int numInputs = (int)myInputs.size(); if (numInputs == 0) { throw OperationException("no inputs specified"); } for (int32_t i = 0; i < numInputs; i++) { const AString className = myInputs[i]->getString(1).trimmed(); if (className.isEmpty()) { throw OperationException("Class name may not be empty"); } const AString listFileName = myInputs[i]->getString(2).trimmed(); if (listFileName.isEmpty()) { throw OperationException("Foci list (text) file name may not be empty"); } const SurfaceFile* surfaceFile = myInputs[i]->getSurface(3); SurfaceProjector projector(surfaceFile); FileInformation textFileInfo(listFileName); if (!textFileInfo.exists()) { throw OperationException("foci list file doesn't exist: " + listFileName); } fstream fociListFile(listFileName.toLocal8Bit().constData(), fstream::in); if (!fociListFile.good()) { throw OperationException("error reading foci list file:" + listFileName); } string focusName; float x, y, z; int32_t red, green, blue; int fociCount = 0; while (fociListFile.good()) { ++fociCount;//just for error messages, so start at 1 getline(fociListFile, focusName); if (fociListFile.eof() && focusName == "") break;//if end of file trying to read an int, and label name is empty, its really just end of file fociListFile >> red; fociListFile >> green; fociListFile >> blue; fociListFile >> x; fociListFile >> y; if (!(fociListFile >> z))//yes, that is seriously the correct way to check if input was successfully extracted...so much fail { throw OperationException("foci list file is malformed for entry #" + AString::number(fociCount) + ": " + AString(focusName.c_str())); } if (red < 0 || red > 255) { throw OperationException("bad value for red for entry #" + AString::number(fociCount) + ", " + AString(focusName.c_str()) + ": " + AString::number(red)); } if (green < 0 || green > 255) { throw OperationException("bad value for green for entry #" + AString::number(fociCount) + ", " + AString(focusName.c_str()) + ": " + AString::number(green)); } if (blue < 0 || blue > 255) { throw OperationException("bad value for blue for entry #" + AString::number(fociCount) + ", " + AString(focusName.c_str()) + ": " + AString::number(blue)); } while (isspace(fociListFile.peek())) { fociListFile.ignore();//drop the newline, possible carriage return or other whitespace so that getline doesn't get nothing, and cause int extraction to fail } Focus* focus = new Focus(); focus->setClassName(className); focus->setName(AString(focusName.c_str()).trimmed()); const float xyz[3] = { x, y, z }; CaretAssert(focus->getNumberOfProjections() > 0); focus->getProjection(0)->setStereotaxicXYZ(xyz); const int32_t dummyFocusIndex(-1); projector.projectFocus(dummyFocusIndex, focus); const GiftiLabel* colorLabel = outputFociFile->getNameColorTable()->getLabel(focus->getName()); if (colorLabel != NULL) { if ((colorLabel->getRed() != red) || (colorLabel->getGreen() != green) || (colorLabel->getBlue() != blue)) { CaretLogWarning("More than one color for focus named \"" + focus->getName() + "\". (All foci with same name use same color)"); } } outputFociFile->getNameColorTable()->addLabel(focus->getName(), red, green, blue); outputFociFile->addFocus(focus); } } if (outputFociFile->getNumberOfFoci() <= 0) { throw OperationException("No foci were successfully read/projected."); } } connectome-workbench-1.4.2/src/Operations/OperationFociCreate.h000066400000000000000000000025751360521144700246140ustar00rootroot00000000000000#ifndef __OPERATION_FOCI_CREATE_H__ #define __OPERATION_FOCI_CREATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationFociCreate : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationFociCreate; } #endif //__OPERATION_FOCI_CREATE_H__ connectome-workbench-1.4.2/src/Operations/OperationFociGetProjectionVertex.cxx000066400000000000000000000136321360521144700277320ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationFociGetProjectionVertex.h" #include "OperationException.h" #include "FociFile.h" #include "Focus.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "SurfaceProjectedItem.h" #include "SurfaceProjectionBarycentric.h" #include "SurfaceProjectionVanEssen.h" using namespace caret; using namespace std; AString OperationFociGetProjectionVertex::getCommandSwitch() { return "-foci-get-projection-vertex"; } AString OperationFociGetProjectionVertex::getShortDescription() { return "GET PROJECTION VERTEX FOR FOCI"; } OperationParameters* OperationFociGetProjectionVertex::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addFociParameter(1, "foci", "the foci file"); ret->addSurfaceParameter(2, "surface", "the surface related to the foci file"); ret->addMetricOutputParameter(3, "metric-out", "the output metric file"); OptionalParameter* nameOpt = ret->createOptionalParameter(4, "-name", "select a focus by name"); nameOpt->addStringParameter(1, "name", "the name of the focus"); ret->setHelpText( AString("For each focus, a column is created in , and the vertex with the most influence on its projection ") + "is assigned a value of 1 in that column, with all other vertices 0. " + "If -name is used, only one focus will be used." ); return ret; } void OperationFociGetProjectionVertex::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); const FociFile* myFoci = myParams->getFoci(1); const SurfaceFile* mySurf = myParams->getSurface(2); MetricFile* myMetricOut = myParams->getOutputMetric(3); OptionalParameter* nameOpt = myParams->getOptionalParameter(4); int numFoci = myFoci->getNumberOfFoci(); if (numFoci < 1) throw OperationException("Foci file has no foci"); int numNodes = mySurf->getNumberOfNodes(); if (nameOpt->m_present) { AString name = nameOpt->getString(1); myMetricOut->setNumberOfNodesAndColumns(numNodes, 1); myMetricOut->setStructure(mySurf->getStructure()); bool found = false; for (int i = 0; i < numFoci; ++i) { const Focus* myFocus = myFoci->getFocus(i); if (name == myFocus->getName()) { found = true; if (myFocus->getNumberOfProjections() < 1) throw OperationException("matching focus has no projections"); const SurfaceProjectedItem* firstItem = myFocus->getProjection(0); int whichNode = -1; if (firstItem->getBarycentricProjection()->isValid()) { const float* areas = firstItem->getBarycentricProjection()->getTriangleAreas(); const int32_t* nodes = firstItem->getBarycentricProjection()->getTriangleNodes(); int pos = 0; for (int i = 1; i < 3; ++i) { if (areas[i] > areas[pos]) pos = i; } whichNode = nodes[pos]; } else { throw OperationException("barycentric projection not valid");//someone else can worry about van essen projection, if it is needed } if (whichNode >= numNodes) throw OperationException("foci file has larger node numbers than surface"); myMetricOut->initializeColumn(0, 0.0f); myMetricOut->setColumnName(0, myFocus->getName()); myMetricOut->setValue(whichNode, 0, 1.0f); break; } } if (!found) throw OperationException("specified name did not match any foci"); } else { myMetricOut->setNumberOfNodesAndColumns(numNodes, numFoci); myMetricOut->setStructure(mySurf->getStructure()); for (int i = 0; i < numFoci; ++i) { const Focus* myFocus = myFoci->getFocus(i); if (myFocus->getNumberOfProjections() < 1) throw OperationException("matching focus has no projections"); const SurfaceProjectedItem* firstItem = myFocus->getProjection(0); int whichNode = -1; if (firstItem->getBarycentricProjection()->isValid()) { const float* areas = firstItem->getBarycentricProjection()->getTriangleAreas(); const int32_t* nodes = firstItem->getBarycentricProjection()->getTriangleNodes(); int pos = 0; for (int i = 1; i < 3; ++i) { if (areas[i] > areas[pos]) pos = i; } whichNode = nodes[pos]; } else { throw OperationException("barycentric projection not valid");//someone else can worry about van essen projection, if it is needed } if (whichNode >= numNodes) throw OperationException("foci file has larger node numbers than surface"); myMetricOut->initializeColumn(i, 0.0f); myMetricOut->setColumnName(i, myFocus->getName()); myMetricOut->setValue(whichNode, i, 1.0f); } } } connectome-workbench-1.4.2/src/Operations/OperationFociGetProjectionVertex.h000066400000000000000000000027211360521144700273540ustar00rootroot00000000000000#ifndef __OPERATION_FOCI_GET_PROJECTION_VERTEX_H__ #define __OPERATION_FOCI_GET_PROJECTION_VERTEX_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationFociGetProjectionVertex : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationFociGetProjectionVertex; } #endif //__OPERATION_FOCI_GET_PROJECTION_VERTEX_H__ connectome-workbench-1.4.2/src/Operations/OperationFociListCoords.cxx000066400000000000000000000062341360521144700260450ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationFociListCoords.h" #include "OperationException.h" #include "FociFile.h" #include "Focus.h" #include using namespace caret; using namespace std; AString OperationFociListCoords::getCommandSwitch() { return "-foci-list-coords"; } AString OperationFociListCoords::getShortDescription() { return "OUTPUT FOCI COORDINATES IN A TEXT FILE"; } OperationParameters* OperationFociListCoords::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addFociParameter(1, "foci-file", "input foci file"); ret->addStringParameter(2, "coord-file-out", "output - the output coordinate text file"); OptionalParameter* namesOpt = ret->createOptionalParameter(3, "-names-out", "output the foci names"); namesOpt->addStringParameter(1, "names-file-out", "output - text file to put foci names in"); ret->setHelpText( AString("Output the coordinates for every focus in the foci file, and optionally the focus names in a second text file.") ); return ret; } void OperationFociListCoords::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); FociFile* myFoci = myParams->getFoci(1);//gets the surface with key 1 AString coordFileName = myParams->getString(2); OptionalParameter* namesOpt = myParams->getOptionalParameter(3); bool outputNames = false; AString nameFileName; if (namesOpt->m_present) { outputNames = true; nameFileName = namesOpt->getString(1); } ofstream coordFile(coordFileName.toLocal8Bit().constData()); if (!coordFile.good()) { throw OperationException("failed to open coordinate output file for writing"); } fstream nameFile; if (outputNames) { nameFile.open(nameFileName.toLocal8Bit().constData(), fstream::out); if (!nameFile.good()) { throw OperationException("failed to open name output file for writing"); } } int numFoci = myFoci->getNumberOfFoci(); for (int i = 0; i < numFoci; ++i) { const Focus* myFocus = myFoci->getFocus(i); const float* coords = myFocus->getSearchXYZ(); coordFile << coords[0] << " " << coords[1] << " " << coords[2] << endl; if (outputNames) { nameFile << myFocus->getName() << endl; } } } connectome-workbench-1.4.2/src/Operations/OperationFociListCoords.h000066400000000000000000000026301360521144700254660ustar00rootroot00000000000000#ifndef __OPERATION_FOCI_LIST_COORDS_H__ #define __OPERATION_FOCI_LIST_COORDS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationFociListCoords : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationFociListCoords; } #endif //__OPERATION_FOCI_LIST_COORDS_H__ connectome-workbench-1.4.2/src/Operations/OperationGiftiConvert.cxx000066400000000000000000000051661360521144700255650ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationGiftiConvert.h" #include "OperationException.h" #include "GiftiFile.h" using namespace caret; using namespace std; AString OperationGiftiConvert::getCommandSwitch() { return "-gifti-convert"; } AString OperationGiftiConvert::getShortDescription() { return "CONVERT A GIFTI FILE TO A DIFFERENT ENCODING"; } OperationParameters* OperationGiftiConvert::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "gifti-encoding", "what the output encoding should be"); ret->addStringParameter(2, "input-gifti-file", "the input gifti file"); ret->addStringParameter(3, "output-gifti-file", "output - the output gifti file");//HACK: fake the output formatting ret->setHelpText( AString("The value of must be one of the following:\n\n") + "ASCII\nBASE64_BINARY\nGZIP_BASE64_BINARY\nEXTERNAL_FILE_BINARY" ); return ret; } void OperationGiftiConvert::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString encodingStr = myParams->getString(1); AString inputName = myParams->getString(2); AString outputName = myParams->getString(3); bool isValidEncoding = false; GiftiEncodingEnum::Enum encoding = GiftiEncodingEnum::fromName(encodingStr, &isValidEncoding); if (isValidEncoding == false) { throw OperationException("Specified GIFTI Encoding is invalid."); } if (inputName.isEmpty()) { throw OperationException("Input GIFTI file name is empty."); } if (outputName.isEmpty()) { throw OperationException("Output GIFTI file name is empty."); } GiftiFile gf; gf.readFile(inputName); gf.setEncodingForWriting(encoding); gf.writeFile(outputName); } connectome-workbench-1.4.2/src/Operations/OperationGiftiConvert.h000066400000000000000000000026111360521144700252020ustar00rootroot00000000000000#ifndef __OPERATION_GIFTI_CONVERT_H__ #define __OPERATION_GIFTI_CONVERT_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationGiftiConvert : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationGiftiConvert; } #endif //__OPERATION_GIFTI_CONVERT_H__ connectome-workbench-1.4.2/src/Operations/OperationLabelExportTable.cxx000066400000000000000000000060721360521144700263500ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationLabelExportTable.h" #include "OperationException.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "LabelFile.h" #include #include using namespace caret; using namespace std; AString OperationLabelExportTable::getCommandSwitch() { return "-label-export-table"; } AString OperationLabelExportTable::getShortDescription() { return "EXPORT LABEL TABLE FROM GIFTI AS TEXT"; } OperationParameters* OperationLabelExportTable::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addLabelParameter(1, "label-in", "the input label file"); ret->addStringParameter(2, "table-out", "output - the output text file");//fake output formatting ret->setHelpText( AString("Takes the label table from the gifti label file, and writes it to a text format matching what is expected by -metric-label-import.") ); return ret; } int OperationLabelExportTable::floatTo255(const float& in) { return (int)floor(in * 255.0f + 0.5f); } void OperationLabelExportTable::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); LabelFile* myLabel = myParams->getLabel(1); AString outName = myParams->getString(2); ofstream outFile(outName.toLocal8Bit().constData()); if (!outFile) throw OperationException("failed to open output text file"); const GiftiLabelTable* myTable = myLabel->getLabelTable(); set allKeys = myTable->getKeys(); int32_t unassignedKey = myTable->getUnassignedLabelKey(); for (set::iterator iter = allKeys.begin(); iter != allKeys.end(); ++iter) { if (*iter == unassignedKey) continue;//don't output the unused key, because import doesn't want it in the text file const GiftiLabel* thisLabel = myTable->getLabel(*iter); outFile << thisLabel->getName() << endl; outFile << thisLabel->getKey() << " " << floatTo255(thisLabel->getRed()) << " " << floatTo255(thisLabel->getGreen()) << " " << floatTo255(thisLabel->getBlue()) << " " << floatTo255(thisLabel->getAlpha()) << endl; if (!outFile) throw OperationException("error writing to output text file"); } } connectome-workbench-1.4.2/src/Operations/OperationLabelExportTable.h000066400000000000000000000027241360521144700257750ustar00rootroot00000000000000#ifndef __OPERATION_LABEL_EXPORT_TABLE_H__ #define __OPERATION_LABEL_EXPORT_TABLE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationLabelExportTable : public AbstractOperation { static int floatTo255(const float& in); public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationLabelExportTable; } #endif //__OPERATION_LABEL_EXPORT_TABLE_H__ connectome-workbench-1.4.2/src/Operations/OperationLabelMask.cxx000066400000000000000000000112261360521144700250070ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationLabelMask.h" #include "OperationException.h" #include "GiftiLabelTable.h" #include "LabelFile.h" #include "MetricFile.h" using namespace caret; using namespace std; AString OperationLabelMask::getCommandSwitch() { return "-label-mask"; } AString OperationLabelMask::getShortDescription() { return "MASK A LABEL FILE"; } OperationParameters* OperationLabelMask::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addLabelParameter(1, "label", "the label file to mask"); ret->addMetricParameter(2, "mask", "the mask metric"); ret->addLabelOutputParameter(3, "label-out", "the output label file"); OptionalParameter* columnSelect = ret->createOptionalParameter(4, "-column", "select a single column"); columnSelect->addStringParameter(1, "column", "the column number or name"); ret->setHelpText( AString("By default, the output label is a copy of the input label, but with the 'unused' label wherever the mask metric is zero or negative. ") + "if -column is specified, the output contains only one column, the masked version of the specified input column." ); return ret; } void OperationLabelMask::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); LabelFile* myLabel = myParams->getLabel(1); MetricFile* myMask = myParams->getMetric(2); int32_t numNodes = myLabel->getNumberOfNodes(), numCols = myLabel->getNumberOfColumns(); if (myMask->getNumberOfNodes() != numNodes) { throw OperationException("mask metric must have the same number of vertices"); } LabelFile* myLabelOut = myParams->getOutputLabel(3);//gets the output metric with key 2 OptionalParameter* columnSelect = myParams->getOptionalParameter(4);//gets optional parameter with key 3 int columnNum = -1; if (columnSelect->m_present) {//set up to use the single column columnNum = (int)myLabel->getMapIndexFromNameOrNumber(columnSelect->getString(1)); if (columnNum < 0 || columnNum >= numCols) { throw OperationException("invalid column specified"); } } vector columnScratch(numNodes); int32_t unusedKey = myLabel->getLabelTable()->getUnassignedLabelKey(); if (columnNum == -1) { myLabelOut->setNumberOfNodesAndColumns(numNodes, numCols); myLabelOut->setStructure(myLabel->getStructure()); *(myLabelOut->getLabelTable()) = *(myLabel->getLabelTable()); const float* roiColumn = myMask->getValuePointerForColumn(0); for (int i = 0; i < numCols; ++i) { myLabelOut->setColumnName(i, myLabel->getColumnName(i)); const int32_t* keyColumn = myLabel->getLabelKeyPointerForColumn(i); for (int j = 0; j < numNodes; ++j) { if (roiColumn[j] > 0.0f) { columnScratch[j] = keyColumn[j]; } else { columnScratch[j] = unusedKey; } } myLabelOut->setLabelKeysForColumn(i, columnScratch.data()); } } else { myLabelOut->setNumberOfNodesAndColumns(numNodes, 1); myLabelOut->setStructure(myLabel->getStructure()); *(myLabelOut->getLabelTable()) = *(myLabel->getLabelTable()); myLabelOut->setColumnName(0, myLabel->getColumnName(columnNum)); const float* roiColumn = myMask->getValuePointerForColumn(0); const int32_t* keyColumn = myLabel->getLabelKeyPointerForColumn(columnNum); for (int j = 0; j < numNodes; ++j) { if (roiColumn[j] > 0.0f) { columnScratch[j] = keyColumn[j]; } else { columnScratch[j] = unusedKey; } } myLabelOut->setLabelKeysForColumn(0, columnScratch.data()); } } connectome-workbench-1.4.2/src/Operations/OperationLabelMask.h000066400000000000000000000025671360521144700244440ustar00rootroot00000000000000#ifndef __OPERATION_LABEL_MASK_H__ #define __OPERATION_LABEL_MASK_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationLabelMask : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationLabelMask; } #endif //__OPERATION_LABEL_MASK_H__ connectome-workbench-1.4.2/src/Operations/OperationLabelMerge.cxx000066400000000000000000000221301360521144700251470ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationLabelMerge.h" #include "OperationException.h" #include "GiftiLabelTable.h" #include "LabelFile.h" #include #include using namespace caret; using namespace std; AString OperationLabelMerge::getCommandSwitch() { return "-label-merge"; } AString OperationLabelMerge::getShortDescription() { return "MERGE LABEL FILES INTO A NEW FILE"; } OperationParameters* OperationLabelMerge::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addLabelOutputParameter(1, "label-out", "the output label"); ParameterComponent* labelOpt = ret->createRepeatableParameter(2, "-label", "specify an input label"); labelOpt->addLabelParameter(1, "label-in", "a label file to use columns from"); ParameterComponent* columnOpt = labelOpt->createRepeatableParameter(2, "-column", "select a single column to use"); columnOpt->addStringParameter(1, "column", "the column number or name"); OptionalParameter* upToOpt = columnOpt->createOptionalParameter(2, "-up-to", "use an inclusive range of columns"); upToOpt->addStringParameter(1, "last-column", "the number or name of the last column to include"); upToOpt->createOptionalParameter(2, "-reverse", "use the range in reverse order"); ret->setHelpText( AString("Takes one or more label files and constructs a new label file by concatenating columns from them. ") + "The input files must have the same number of vertices and the same structure.\n\n" + "Example: wb_command -label-merge out.label.gii -label first.label.gii -column 1 -label second.label.gii\n\n" + "This example would take the first column from first.label.gii and all subvolumes from second.label.gii, " + "and write these to out.label.gii." ); return ret; } namespace {//private namespace for helper functions void doRemap(const int32_t* input, const map& remap, const int numElems, const int32_t& unlabeledValue, int32_t* output) { for (int i = 0; i < numElems; ++i) { map::const_iterator iter = remap.find(input[i]); if (iter != remap.end()) { output[i] = iter->second; } else {//values that have no key output[i] = unlabeledValue; } } } } void OperationLabelMerge::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); LabelFile* myLabelOut = myParams->getOutputLabel(1); const vector& myInputs = *(myParams->getRepeatableParameterInstances(2)); int numInputs = (int)myInputs.size(); if (numInputs == 0) throw OperationException("no inputs specified"); const LabelFile* firstLabel = myInputs[0]->getLabel(1); int numOutColumns = 0; int numNodes = firstLabel->getNumberOfNodes(); StructureEnum::Enum myStruct = firstLabel->getStructure(); GiftiLabelTable outTable; vector > fileRemap(numInputs); for (int i = 0; i < numInputs; ++i) { LabelFile* inputLabel = myInputs[i]->getLabel(1); fileRemap[i] = outTable.append(*(inputLabel->getLabelTable()));//NOTE: does (and must) include identity mappings - anything that doesn't match was invalid in the original file if (numNodes != inputLabel->getNumberOfNodes()) throw OperationException("file '" + inputLabel->getFileName() + "' has a different number of nodes than the first"); if (myStruct != inputLabel->getStructure()) throw OperationException("file '" + inputLabel->getFileName() + "' has a different structure than the first"); const vector& columnOpts = *(myInputs[i]->getRepeatableParameterInstances(2)); int numColumnOpts = (int)columnOpts.size(); if (numColumnOpts > 0) { for (int j = 0; j < numColumnOpts; ++j) { int initialColumn = inputLabel->getMapIndexFromNameOrNumber(columnOpts[j]->getString(1)); if (initialColumn < 0) throw OperationException("column '" + columnOpts[j]->getString(1) + "' not found in file '" + inputLabel->getFileName() + "'"); OptionalParameter* upToOpt = columnOpts[j]->getOptionalParameter(2); if (upToOpt->m_present) { int finalColumn = inputLabel->getMapIndexFromNameOrNumber(upToOpt->getString(1)); if (finalColumn < 0) throw OperationException("ending column '" + upToOpt->getString(1) + "' not found in file '" + inputLabel->getFileName() + "'"); if (finalColumn < initialColumn) throw OperationException("ending column '" + upToOpt->getString(1) + "' occurs before starting column '" + columnOpts[j]->getString(1) + "' in file '" + inputLabel->getFileName() + "'"); numOutColumns += finalColumn - initialColumn + 1;//inclusive - we don't need to worry about reversing for counting, though } else { numOutColumns += 1; } } } else { numOutColumns += inputLabel->getNumberOfColumns(); } } myLabelOut->setNumberOfNodesAndColumns(numNodes, numOutColumns); myLabelOut->setStructure(myStruct); *(myLabelOut->getLabelTable()) = outTable; vector scratchCol(numNodes); int curColumn = 0; for (int i = 0; i < numInputs; ++i) { const LabelFile* inputLabel = myInputs[i]->getLabel(1); const vector& columnOpts = *(myInputs[i]->getRepeatableParameterInstances(2)); int numColumnOpts = (int)columnOpts.size(); if (numColumnOpts > 0) { for (int j = 0; j < numColumnOpts; ++j) { int initialColumn = inputLabel->getMapIndexFromNameOrNumber(columnOpts[j]->getString(1)); OptionalParameter* upToOpt = columnOpts[j]->getOptionalParameter(2); if (upToOpt->m_present) { int finalColumn = inputLabel->getMapIndexFromNameOrNumber(upToOpt->getString(1)); bool reverse = upToOpt->getOptionalParameter(2)->m_present; if (reverse) { for (int c = finalColumn; c >= initialColumn; --c) { doRemap(inputLabel->getLabelKeyPointerForColumn(c), fileRemap[i], numNodes, outTable.getUnassignedLabelKey(), scratchCol.data()); myLabelOut->setLabelKeysForColumn(curColumn, scratchCol.data()); myLabelOut->setColumnName(curColumn, inputLabel->getColumnName(c)); ++curColumn; } } else { for (int c = initialColumn; c <= finalColumn; ++c) { doRemap(inputLabel->getLabelKeyPointerForColumn(c), fileRemap[i], numNodes, outTable.getUnassignedLabelKey(), scratchCol.data()); myLabelOut->setLabelKeysForColumn(curColumn, scratchCol.data()); myLabelOut->setColumnName(curColumn, inputLabel->getColumnName(c)); ++curColumn; } } } else { doRemap(inputLabel->getLabelKeyPointerForColumn(initialColumn), fileRemap[i], numNodes, outTable.getUnassignedLabelKey(), scratchCol.data()); myLabelOut->setLabelKeysForColumn(curColumn, scratchCol.data()); myLabelOut->setColumnName(curColumn, inputLabel->getColumnName(initialColumn)); ++curColumn; } } } else { int numColumns = inputLabel->getNumberOfColumns(); for (int j = 0; j < numColumns; ++j) { doRemap(inputLabel->getLabelKeyPointerForColumn(j), fileRemap[i], numNodes, outTable.getUnassignedLabelKey(), scratchCol.data()); myLabelOut->setLabelKeysForColumn(curColumn, scratchCol.data()); myLabelOut->setColumnName(curColumn, inputLabel->getColumnName(j)); ++curColumn; } } } CaretAssert(curColumn == numOutColumns); } connectome-workbench-1.4.2/src/Operations/OperationLabelMerge.h000066400000000000000000000025751360521144700246070ustar00rootroot00000000000000#ifndef __OPERATION_LABEL_MERGE_H__ #define __OPERATION_LABEL_MERGE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationLabelMerge : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationLabelMerge; } #endif //__OPERATION_LABEL_MERGE_H__ connectome-workbench-1.4.2/src/Operations/OperationMetadataRemoveProvenance.cxx000066400000000000000000000127171360521144700301010ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationMetadataRemoveProvenance.h" #include "OperationException.h" #include "CiftiFile.h" #include "DataFileTypeEnum.h" #include "LabelFile.h" #include "MetricFile.h" #include "VolumeFile.h" #include "FileInformation.h" using namespace caret; using namespace std; AString OperationMetadataRemoveProvenance::getCommandSwitch() { return "-metadata-remove-provenance"; } AString OperationMetadataRemoveProvenance::getShortDescription() { return "REMOVE PROVENANCE INFORMATION FROM FILE METADATA"; } OperationParameters* OperationMetadataRemoveProvenance::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "input-file", "the file to remove provenance information from"); ret->addStringParameter(2, "output-file", "output - the name to save the modified file as");//HACK: fake the output format, since it doesn't know what kind of file it is ret->setHelpText( AString("Removes the provenance metadata fields added by workbench during processing.") ); return ret; } void OperationMetadataRemoveProvenance::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString inFileName = myParams->getString(1); AString outFileName = myParams->getString(2); bool ok = false; DataFileTypeEnum::Enum myType = DataFileTypeEnum::fromFileExtension(inFileName, &ok); if (!ok) { throw OperationException("unrecognized data file type"); } switch (myType) { case DataFileTypeEnum::METRIC: { MetricFile myMetric; myMetric.readFile(inFileName); removeProvenance(myMetric.getFileMetaData()); myMetric.writeFile(outFileName); break; } case DataFileTypeEnum::LABEL: { LabelFile myLabel; myLabel.readFile(inFileName); removeProvenance(myLabel.getFileMetaData()); myLabel.writeFile(outFileName); break; } case DataFileTypeEnum::VOLUME: { VolumeFile myVol; myVol.readFile(inFileName); removeProvenance(myVol.getFileMetaData()); myVol.writeFile(outFileName); break; } case DataFileTypeEnum::CONNECTIVITY_DENSE: case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: case DataFileTypeEnum::CONNECTIVITY_PARCEL: case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: { CiftiFile myCifti; FileInformation myInfo1(inFileName), myInfo2(outFileName); myCifti.openFile(inFileName); if (myInfo1.getCanonicalFilePath() == myInfo2.getCanonicalFilePath()) { myCifti.convertToInMemory(); } CiftiXMLOld myXML = myCifti.getCiftiXMLOld(); CiftiFile myOutCifti; myOutCifti.setWritingFile(outFileName); int numRows = myXML.getNumberOfRows(), rowSize = myXML.getNumberOfColumns(); removeProvenance(myXML.getFileMetaData()); myOutCifti.setCiftiXML(myXML, false); vector scratchRow(rowSize); for (int i = 0; i < numRows; ++i) { myCifti.getRow(scratchRow.data(), i); myOutCifti.setRow(scratchRow.data(), i); } myOutCifti.writeFile(outFileName); break; } default: throw OperationException("file type not supported in metadata remove provenance"); } } void OperationMetadataRemoveProvenance::removeProvenance(GiftiMetaData* toModify) { if (toModify == NULL) return; set provenanceNames = getProvenanceKeys(); for (set::iterator iter = provenanceNames.begin(); iter != provenanceNames.end(); ++iter) { toModify->remove(*iter); } } void OperationMetadataRemoveProvenance::removeProvenance(map* toModify) { if (toModify == NULL) return; set provenanceNames = getProvenanceKeys(); for (set::iterator iter = provenanceNames.begin(); iter != provenanceNames.end(); ++iter) { toModify->erase(*iter); } } set OperationMetadataRemoveProvenance::getProvenanceKeys() { set ret; ret.insert("Provenance");//these should really be in a common location somewhere ret.insert("ParentProvenance"); ret.insert("ProgramProvenance"); ret.insert("WorkingDirectory"); return ret; } connectome-workbench-1.4.2/src/Operations/OperationMetadataRemoveProvenance.h000066400000000000000000000033221360521144700275160ustar00rootroot00000000000000#ifndef __OPERATION_METADATA_REMOVE_PROVENANCE_H__ #define __OPERATION_METADATA_REMOVE_PROVENANCE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" #include #include namespace caret { class GiftiMetaData; class OperationMetadataRemoveProvenance : public AbstractOperation { static void removeProvenance(GiftiMetaData* toModify); static void removeProvenance(std::map* toModify); static std::set getProvenanceKeys(); public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationMetadataRemoveProvenance; } #endif //__OPERATION_METADATA_REMOVE_PROVENANCE_H__ connectome-workbench-1.4.2/src/Operations/OperationMetadataStringReplace.cxx000066400000000000000000000205541360521144700273630ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationMetadataStringReplace.h" #include "OperationException.h" #include "CiftiFile.h" #include "DataFileTypeEnum.h" #include "LabelFile.h" #include "MetricFile.h" #include "VolumeFile.h" #include "FileInformation.h" using namespace caret; using namespace std; AString OperationMetadataStringReplace::getCommandSwitch() { return "-metadata-string-replace"; } AString OperationMetadataStringReplace::getShortDescription() { return "REPLACE A STRING IN ALL METADATA OF A FILE"; } OperationParameters* OperationMetadataStringReplace::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "input-file", "the file to replace metadata in"); ret->addStringParameter(2, "find-string", "the string to find"); ret->addStringParameter(3, "replace-string", "the string to replace with"); ret->addStringParameter(4, "output-file", "output - the name to save the modified file as");//HACK: fake the output format, since it doesn't know what kind of file it is ret->createOptionalParameter(5, "-case-insensitive", "match with case variation also"); ret->setHelpText( AString("Replaces all occurrences of in the metadata and map names of with .") ); return ret; } void OperationMetadataStringReplace::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString inFileName = myParams->getString(1); AString findString = myParams->getString(2); AString replString = myParams->getString(3); AString outFileName = myParams->getString(4); Qt::CaseSensitivity myCS = Qt::CaseSensitive; if (myParams->getOptionalParameter(5)->m_present) { myCS = Qt::CaseInsensitive; } bool ok = false; DataFileTypeEnum::Enum myType = DataFileTypeEnum::fromFileExtension(inFileName, &ok); if (!ok) { throw OperationException("unrecognized data file type"); } switch (myType) { case DataFileTypeEnum::METRIC: { MetricFile myMetric; myMetric.readFile(inFileName); replaceInMetaData(myMetric.getFileMetaData(), findString, replString, myCS); int32_t numMaps = myMetric.getNumberOfMaps(); for (int32_t map = 0; map < numMaps; ++map) { replaceInMetaData(myMetric.getMapMetaData(map), findString, replString, myCS); AString mapName = myMetric.getMapName(map); myMetric.setMapName(map, mapName.replace(findString, replString, myCS)); } myMetric.writeFile(outFileName); break; } case DataFileTypeEnum::LABEL: { LabelFile myLabel; myLabel.readFile(inFileName); replaceInMetaData(myLabel.getFileMetaData(), findString, replString, myCS); int32_t numMaps = myLabel.getNumberOfMaps(); for (int32_t map = 0; map < numMaps; ++map) { replaceInMetaData(myLabel.getMapMetaData(map), findString, replString, myCS); AString mapName = myLabel.getMapName(map); myLabel.setMapName(map, mapName.replace(findString, replString, myCS)); } myLabel.writeFile(outFileName); break; } case DataFileTypeEnum::VOLUME: { VolumeFile myVol; myVol.readFile(inFileName); replaceInMetaData(myVol.getFileMetaData(), findString, replString, myCS); int32_t numMaps = myVol.getNumberOfMaps(); for (int32_t map = 0; map < numMaps; ++map) { replaceInMetaData(myVol.getMapMetaData(map), findString, replString, myCS); AString mapName = myVol.getMapName(map); myVol.setMapName(map, mapName.replace(findString, replString, myCS)); } myVol.writeFile(outFileName); break; } case DataFileTypeEnum::CONNECTIVITY_DENSE: case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: case DataFileTypeEnum::CONNECTIVITY_DENSE_PARCEL: case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: case DataFileTypeEnum::CONNECTIVITY_PARCEL: case DataFileTypeEnum::CONNECTIVITY_PARCEL_DENSE: { CiftiFile myCifti; FileInformation myInfo1(inFileName), myInfo2(outFileName); myCifti.openFile(inFileName); if (myInfo1.getCanonicalFilePath() == myInfo2.getCanonicalFilePath()) { myCifti.convertToInMemory(); } CiftiXMLOld myXML = myCifti.getCiftiXMLOld(); CiftiFile myOutCifti; myOutCifti.setWritingFile(outFileName); int numRows = myXML.getNumberOfRows(), rowSize = myXML.getNumberOfColumns(); replaceInMetaData(myXML.getFileMetaData(), findString, replString, myCS); if (myXML.getMappingType(CiftiXMLOld::ALONG_ROW) == CIFTI_INDEX_TYPE_SCALARS || myXML.getMappingType(CiftiXMLOld::ALONG_ROW) == CIFTI_INDEX_TYPE_LABELS) { for (int row = 0; row < numRows; ++row) { AString mapName = myXML.getMapName(CiftiXMLOld::ALONG_ROW, row); myXML.setMapNameForIndex(CiftiXMLOld::ALONG_ROW, row, mapName.replace(findString, replString, myCS)); replaceInMetaData(myXML.getMapMetadata(CiftiXMLOld::ALONG_ROW, row), findString, replString, myCS); } } if (myXML.getMappingType(CiftiXMLOld::ALONG_COLUMN) == CIFTI_INDEX_TYPE_SCALARS || myXML.getMappingType(CiftiXMLOld::ALONG_COLUMN) == CIFTI_INDEX_TYPE_LABELS) { for (int col = 0; col < rowSize; ++col) { AString mapName = myXML.getMapName(CiftiXMLOld::ALONG_COLUMN, col); myXML.setMapNameForIndex(CiftiXMLOld::ALONG_COLUMN, col, mapName.replace(findString, replString, myCS)); replaceInMetaData(myXML.getMapMetadata(CiftiXMLOld::ALONG_COLUMN, col), findString, replString, myCS); } } myOutCifti.setCiftiXML(myXML, false); vector scratchRow(rowSize); for (int i = 0; i < numRows; ++i) { myCifti.getRow(scratchRow.data(), i); myOutCifti.setRow(scratchRow.data(), i); } myOutCifti.writeFile(outFileName); break; } default: throw OperationException("file type not supported in metadata string replace"); } } void OperationMetadataStringReplace::replaceInMetaData(GiftiMetaData* toModify, const AString& findStr, const AString& replStr, const Qt::CaseSensitivity& myCS) { if (toModify == NULL) return; vector metaNames = toModify->getAllMetaDataNames(); int64_t numNames = (int64_t)metaNames.size(); for (int64_t i = 0; i < numNames; ++i) { AString value = toModify->get(metaNames[i]); toModify->set(metaNames[i], value.replace(findStr, replStr, myCS)); } } void OperationMetadataStringReplace::replaceInMetaData(map* toModify, const AString& findStr, const AString& replStr, const Qt::CaseSensitivity& myCS) { if (toModify == NULL) return; for (map::iterator iter = toModify->begin(); iter != toModify->end(); ++iter) { iter->second.replace(findStr, replStr, myCS);//replace actually modifies the string itself } } connectome-workbench-1.4.2/src/Operations/OperationMetadataStringReplace.h000066400000000000000000000034371360521144700270110ustar00rootroot00000000000000#ifndef __OPERATION_METADATA_STRING_REPLACE_H__ #define __OPERATION_METADATA_STRING_REPLACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" #include namespace caret { class GiftiMetaData; class OperationMetadataStringReplace : public AbstractOperation { static void replaceInMetaData(GiftiMetaData* toModify, const AString& findStr, const AString& replStr, const Qt::CaseSensitivity& myCS); static void replaceInMetaData(std::map* toModify, const AString& findStr, const AString& replStr, const Qt::CaseSensitivity& myCS); public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationMetadataStringReplace; } #endif //__OPERATION_METADATA_STRING_REPLACE_H__ connectome-workbench-1.4.2/src/Operations/OperationMetricConvert.cxx000066400000000000000000000126611360521144700257440ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationMetricConvert.h" #include "OperationException.h" #include "CaretLogger.h" #include "FloatMatrix.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "VolumeFile.h" #include using namespace caret; using namespace std; AString OperationMetricConvert::getCommandSwitch() { return "-metric-convert"; } AString OperationMetricConvert::getShortDescription() { return "CONVERT METRIC FILE TO FAKE NIFTI"; } OperationParameters* OperationMetricConvert::getParameters() { OperationParameters* ret = new OperationParameters(); OptionalParameter* toNifti = ret->createOptionalParameter(1, "-to-nifti", "convert metric to nifti"); toNifti->addMetricParameter(1, "metric-in", "the metric to convert"); toNifti->addVolumeOutputParameter(2, "nifti-out", "the output nifti file");//we can use VolumeFile because it is 4D, though some spatial dimensions may be singular OptionalParameter* fromNifti = ret->createOptionalParameter(2, "-from-nifti", "convert nifti to metric"); fromNifti->addVolumeParameter(1, "nifti-in", "the nifti file to convert"); fromNifti->addSurfaceParameter(2, "surface-in", "surface file to use number of vertices and structure from"); fromNifti->addMetricOutputParameter(3, "metric-out", "the output metric file"); ret->setHelpText( AString("The purpose of this command is to convert between metric files and nifti1 so that gifti-unaware programs can operate on the data. ") + "You must specify exactly one of the options." ); return ret; } void OperationMetricConvert::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); int modes = 0; OptionalParameter* toNifti = myParams->getOptionalParameter(1); if (toNifti->m_present) ++modes; OptionalParameter* fromNifti = myParams->getOptionalParameter(2); if (fromNifti->m_present) ++modes; if (modes != 1) { throw OperationException("you must specify exactly one conversion mode"); } if (toNifti->m_present) { MetricFile* myMetric = toNifti->getMetric(1); VolumeFile* outVolume = toNifti->getOutputVolume(2); int numNodes = myMetric->getNumberOfNodes(), numCols = myMetric->getNumberOfColumns(); if (numCols > 32767)//max of short { throw OperationException("number of metric columns exceeds nifti1 limit, failing"); } vector myDims(4, 1); myDims[3] = numCols; if (numNodes > 32767) { myDims[0] = 32767; int temp = (numNodes - 1) / 32767 + 1;//round up instead of down if (temp > 32767)//should be rare to the point of nonexistence, but technically possible { myDims[1] = 32767; myDims[2] = (temp - 1) / 32767 + 1; if (myDims[2] > 32767) throw OperationException("number of vertices too large for nifti1 spatial dimensions, failing"); } else { myDims[1] = temp; } } else { myDims[0] = numNodes; } int frameSize = myDims[0] * myDims[1] * myDims[2]; vector scratchFrame(frameSize, 0.0f); FloatMatrix mySpace = FloatMatrix::identity(4); mySpace[0][0] = -1;//use radiological sform so FSL doesn't do stupid stuff outVolume->reinitialize(myDims, mySpace.getMatrix()); for (int i = 0; i < numCols; ++i) { const float* myCol = myMetric->getValuePointerForColumn(i); for (int j = 0; j < numNodes; ++j) { scratchFrame[j] = myCol[j]; } outVolume->setFrame(scratchFrame.data(), i); } } if (fromNifti->m_present) { VolumeFile* myNifti = fromNifti->getVolume(1); SurfaceFile* mySurf = fromNifti->getSurface(2); MetricFile* outMetric = fromNifti->getOutputMetric(3); vector myDims = myNifti->getDimensions(); int numNodes = mySurf->getNumberOfNodes(); int64_t frameSize = myDims[0] * myDims[1] * myDims[2]; if (frameSize < numNodes) { throw OperationException("nifti file does not have dimensions large enough to satisfy specified number of nodes"); } int numCols = (int)myDims[3];//if someone manages over 2 billion timepoints, reward them with truncation outMetric->setNumberOfNodesAndColumns(numNodes, numCols); outMetric->setStructure(mySurf->getStructure()); for (int i = 0; i < numCols; ++i) { outMetric->setValuesForColumn(i, myNifti->getFrame(i)); } } } connectome-workbench-1.4.2/src/Operations/OperationMetricConvert.h000066400000000000000000000026171360521144700253710ustar00rootroot00000000000000#ifndef __OPERATION_METRIC_CONVERT_H__ #define __OPERATION_METRIC_CONVERT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationMetricConvert : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationMetricConvert; } #endif //__OPERATION_METRIC_CONVERT_H__ connectome-workbench-1.4.2/src/Operations/OperationMetricLabelImport.cxx000066400000000000000000000336461360521144700265440ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationMetricLabelImport.h" #include "OperationException.h" #include "CaretLogger.h" #include "FileInformation.h" #include "GiftiLabel.h" #include "GiftiLabelTable.h" #include "LabelFile.h" #include "MetricFile.h" #include #include #include #include #include #include using namespace caret; using namespace std; AString OperationMetricLabelImport::getCommandSwitch() { return "-metric-label-import"; } AString OperationMetricLabelImport::getShortDescription() { return "IMPORT A GIFTI LABEL FILE FROM A METRIC FILE"; } OperationParameters* OperationMetricLabelImport::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addMetricParameter(1, "input", "the input metric file"); ret->addStringParameter(2, "label-list-file", "text file containing the values and names for labels"); ret->addLabelOutputParameter(3, "output", "the output gifti label file"); ret->createOptionalParameter(4, "-discard-others", "set any values not mentioned in the label list to the ??? label"); OptionalParameter* unlabeledOption = ret->createOptionalParameter(5, "-unlabeled-value", "set the value that will be interpreted as unlabeled"); unlabeledOption->addIntegerParameter(1, "value", "the numeric value for unlabeled (default 0)"); OptionalParameter* columnSelect = ret->createOptionalParameter(6, "-column", "select a single column to import"); columnSelect->addStringParameter(1, "column", "the column number or name"); ret->createOptionalParameter(7, "-drop-unused-labels", "remove any unused label values from the label table"); ret->setHelpText( AString("Creates a gifti label file from a metric file with label-like values. ") + "You may specify the empty string (use \"\") for , which will be treated as if it is an empty file. " + "The label list file must have the following format (2 lines per label):\n\n" + "\n \n...\n\n" + "Label names are specified on a separate line from their value and color, in order to let label names contain spaces. " + "Whitespace is trimmed from both ends of the label name, but is kept if it is in the middle of a label. " + "Do not specify the \"unlabeled\" key in the file, it is assumed that 0 means not labeled unless -unlabeled-value is specified. " + "The value of specifies what value in the imported file should be used as this label. " + "The values of , , and must be integers from 0 to 255, and will specify the color the label is drawn as " + "(alpha of 255 means fully opaque, which is probably what you want).\n\n" + "By default, it will create new label names with names like LABEL_5 for any values encountered that are not mentioned in the " + "list file, specify -discard-others to instead set these values to the \"unlabeled\" key." ); return ret; } void OperationMetricLabelImport::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); MetricFile* myMetric = myParams->getMetric(1); AString listfileName = myParams->getString(2); LabelFile* myLabelOut = myParams->getOutputLabel(3); bool discardOthers = myParams->getOptionalParameter(4)->m_present; int32_t unlabeledValue = 0; OptionalParameter* unlabeledOption = myParams->getOptionalParameter(5); if (unlabeledOption->m_present) { unlabeledValue = (int32_t)unlabeledOption->getInteger(1); } OptionalParameter* columnSelect = myParams->getOptionalParameter(6); int columnNum = -1; if (columnSelect->m_present) { columnNum = (int)myMetric->getMapIndexFromNameOrNumber(columnSelect->getString(1)); if (columnNum < 0 || columnNum >= myMetric->getNumberOfMaps()) { throw OperationException("invalid column specified"); } } bool dropUnused = myParams->getOptionalParameter(7)->m_present; map translate; GiftiLabelTable myTable; if (listfileName != "")//maybe this should be a function of GiftiLabelTable { AString temp; FileInformation textFileInfo(listfileName); if (!textFileInfo.exists()) { throw OperationException("label list file doesn't exist"); } fstream labelListFile(listfileName.toLocal8Bit().constData(), fstream::in); if (!labelListFile.good()) { throw OperationException("error reading label list file"); } string labelName; int32_t value, red, green, blue, alpha; int labelCount = 0; translate[unlabeledValue] = 0;//placeholder, we don't know the correct translated value yet while (labelListFile.good()) { ++labelCount;//just for error messages, so start at 1 getline(labelListFile, labelName); labelListFile >> value; if (labelListFile.eof() && labelName == "") break;//if end of file trying to read an int, and label name is empty, its really just end of file labelListFile >> red; labelListFile >> green; labelListFile >> blue; if (!(labelListFile >> alpha))//yes, that is seriously the correct way to check if input was successfully extracted...so much fail { throw OperationException("label list file is malformed for entry #" + AString::number(labelCount) + ": " + AString(labelName.c_str())); } if (red < 0 || red > 255) { throw OperationException("bad value for red for entry #" + AString::number(labelCount) + ", " + AString(labelName.c_str()) + ": " + AString::number(red)); } if (green < 0 || green > 255) { throw OperationException("bad value for green for entry #" + AString::number(labelCount) + ", " + AString(labelName.c_str()) + ": " + AString::number(green)); } if (blue < 0 || blue > 255) { throw OperationException("bad value for blue for entry #" + AString::number(labelCount) + ", " + AString(labelName.c_str()) + ": " + AString::number(blue)); } if (alpha < 0 || alpha > 255) { throw OperationException("bad value for alpha for entry #" + AString::number(labelCount) + ", " + AString(labelName.c_str()) + ": " + AString::number(alpha)); } if (value == GiftiLabel::getInvalidLabelKey()) { throw OperationException("entry #" + AString::number(labelCount) + ", " + AString(labelName.c_str()) + " specifies unusable key value: " + value); } while (isspace(labelListFile.peek())) { labelListFile.ignore();//drop the newline, possible carriage return or other whitespace so that getline doesn't get nothing, and cause int extraction to fail } temp = AString(labelName.c_str()).trimmed();//drop errant CR or other whitespace from beginning and end of lines if (translate.find(value) != translate.end()) { if (value == unlabeledValue) { throw OperationException("the unlabeled value must not be specified in label list file"); } else { throw OperationException(AString("label key ") + AString::number(value) + " specified more than once"); } } GiftiLabel myLabel(value, temp, red, green, blue, alpha); if (myTable.getLabelKeyFromName(temp) != GiftiLabel::getInvalidLabelKey()) { AString nameBase = temp, newName;//resolve collision by generating a name with an additional number on it bool success = false; for (int extra = 1; extra < 100; ++extra)//but stop at 100, because really... { newName = nameBase + "_" + AString::number(extra); if (myTable.getLabelKeyFromName(newName) == GiftiLabel::getInvalidLabelKey()) { success = true; break; } } if (success) { CaretLogWarning("name collision in input name '" + nameBase + "', changing one to '" + newName + "'"); } else { throw OperationException("giving up on resolving name collision for input name '" + nameBase + "'"); } myLabel.setName(newName); } int32_t newValue; if (value == 0)//because label 0 exists in the default constructed table { myTable.insertLabel(&myLabel);//but we do want to be able to overwrite the default 0 label newValue = 0;//if value 0 is specified twice, or once without specifying a different unlabeled value, the check versus the translate map will catch it } else { newValue = myTable.addLabel(&myLabel);//we don't want to overwrite relocated labels } translate[value] = newValue; } } int32_t unusedLabel = myTable.getUnassignedLabelKey(); translate[unlabeledValue] = unusedLabel; const int numNodes = myMetric->getNumberOfNodes(); vector colScratch(numNodes); if (columnNum == -1) { const int numCols = myMetric->getNumberOfColumns(); myLabelOut->setNumberOfNodesAndColumns(numNodes, numCols); myLabelOut->setStructure(myMetric->getStructure()); set usedValues; for (int col = 0; col < numCols; ++col) { translateLabels(myMetric->getValuePointerForColumn(col), colScratch.data(), numNodes, myTable, translate, usedValues, dropUnused, discardOthers, unusedLabel); myLabelOut->setLabelKeysForColumn(col, colScratch.data()); } if (dropUnused) { myTable.deleteUnusedLabels(usedValues); } *(myLabelOut->getLabelTable()) = myTable; } else { myLabelOut->setNumberOfNodesAndColumns(numNodes, 1); myLabelOut->setStructure(myMetric->getStructure()); set usedValues; translateLabels(myMetric->getValuePointerForColumn(columnNum), colScratch.data(), numNodes, myTable, translate, usedValues, dropUnused, discardOthers, unusedLabel); myLabelOut->setLabelKeysForColumn(0, colScratch.data()); if (dropUnused) { myTable.deleteUnusedLabels(usedValues); } *(myLabelOut->getLabelTable()) = myTable; } } void OperationMetricLabelImport::translateLabels(const float* valuesIn, int32_t* labelsOut, const int& numNodes, GiftiLabelTable& myTable, map& translate, set& usedValues, const bool& dropUnused, const bool& discardOthers, const int32_t& unusedLabel) { for (int node = 0; node < numNodes; ++node) { int32_t labelval = (int32_t)floor(valuesIn[node] + 0.5f);//just in case it somehow got poorly encoded, round to nearest if (dropUnused) { usedValues.insert(labelval); } map::iterator myiter = translate.find(labelval); if (myiter == translate.end()) { if (discardOthers) { labelsOut[node] = unusedLabel; } else {//use a random color, but fully opaque for the label GiftiLabel myLabel(labelval, AString("LABEL_") + AString::number(labelval), rand() & 255, rand() & 255, rand() & 255, 255); if (myTable.getLabelKeyFromName(myLabel.getName()) != GiftiLabel::getInvalidLabelKey()) { AString nameBase = myLabel.getName(), newName;//resolve collision by generating a name with an additional number on it bool success = false; for (int extra = 1; extra < 100; ++extra)//but stop at 100, because really... { newName = nameBase + "_" + AString::number(extra); if (myTable.getLabelKeyFromName(newName) == GiftiLabel::getInvalidLabelKey()) { success = true; break; } } if (success) { CaretLogWarning("name collision in auto-generated name '" + nameBase + "', changed to '" + newName + "'"); } else { throw OperationException("giving up on resolving name collision for auto-generated name '" + nameBase + "'"); } myLabel.setName(newName); } int32_t newValue = myTable.addLabel(&myLabel);//don't overwrite any values in the table translate[labelval] = newValue; labelsOut[node] = newValue; } } else { labelsOut[node] = myiter->second; } } } connectome-workbench-1.4.2/src/Operations/OperationMetricLabelImport.h000066400000000000000000000034321360521144700261570ustar00rootroot00000000000000#ifndef __OPERATION_METRIC_LABEL_IMPORT_H__ #define __OPERATION_METRIC_LABEL_IMPORT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" #include #include namespace caret { class GiftiLabelTable; class OperationMetricLabelImport : public AbstractOperation { static void translateLabels(const float* valuesIn, int32_t* labelsOut, const int& numNodes, GiftiLabelTable& myTable, std::map& translate, std::set& usedValues, const bool& dropUnused, const bool& discardOthers, const int32_t& unusedLabel); public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationMetricLabelImport; } #endif //__OPERATION_METRIC_LABEL_IMPORT_H__ connectome-workbench-1.4.2/src/Operations/OperationMetricMask.cxx000066400000000000000000000114041360521144700252110ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationMetricMask.h" #include "OperationException.h" #include "MetricFile.h" #include "PaletteColorMapping.h" using namespace caret; using namespace std; AString OperationMetricMask::getCommandSwitch() { return "-metric-mask"; } AString OperationMetricMask::getShortDescription() { return "MASK A METRIC FILE"; } OperationParameters* OperationMetricMask::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addMetricParameter(1, "metric", "the input metric"); ret->addMetricParameter(2, "mask", "the mask metric"); ret->addMetricOutputParameter(3, "metric-out", "the output metric"); OptionalParameter* columnSelect = ret->createOptionalParameter(4, "-column", "select a single column"); columnSelect->addStringParameter(1, "column", "the column number or name"); ret->setHelpText( AString("By default, the output metric is a copy of the input metric, but with zeros wherever the mask metric is zero or negative. ") + "if -column is specified, the output contains only one column, the masked version of the specified input column." ); return ret; } void OperationMetricMask::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); MetricFile* myMetric = myParams->getMetric(1); MetricFile* myMask = myParams->getMetric(2); int32_t numNodes = myMetric->getNumberOfNodes(); if (myMask->getNumberOfNodes() != numNodes) { throw OperationException("mask metric must have the same number of vertices"); } MetricFile* myMetricOut = myParams->getOutputMetric(3);//gets the output metric with key 2 OptionalParameter* columnSelect = myParams->getOptionalParameter(4);//gets optional parameter with key 3 int columnNum = -1; if (columnSelect->m_present) {//set up to use the single column columnNum = (int)myMetric->getMapIndexFromNameOrNumber(columnSelect->getString(1)); if (columnNum < 0 || columnNum >= myMetric->getNumberOfColumns()) { throw OperationException("invalid column specified"); } } CaretArray myColumnOut(numNodes); if (columnNum == -1) { int32_t numCols = myMetric->getNumberOfColumns(); myMetricOut->setNumberOfNodesAndColumns(numNodes, numCols); myMetricOut->setStructure(myMetric->getStructure()); const float* maskVals = myMask->getValuePointerForColumn(0); for (int32_t col = 0; col < numCols; ++col) { const float* metricVals = myMetric->getValuePointerForColumn(col); *(myMetricOut->getPaletteColorMapping(col)) = *(myMetric->getPaletteColorMapping(col));//copy the palette settings for (int32_t node = 0; node < numNodes; ++node) { if (maskVals[node] > 0.0f) { myColumnOut[node] = metricVals[node]; } else { myColumnOut[node] = 0.0f; } } myMetricOut->setValuesForColumn(col, myColumnOut.getArray()); myMetricOut->setColumnName(col, myMetric->getColumnName(col)); } } else { myMetricOut->setNumberOfNodesAndColumns(numNodes, 1); myMetricOut->setStructure(myMetric->getStructure()); const float* maskVals = myMask->getValuePointerForColumn(0); const float* metricVals = myMetric->getValuePointerForColumn(columnNum); *(myMetricOut->getPaletteColorMapping(0)) = *(myMetric->getPaletteColorMapping(columnNum));//copy the palette settings for (int32_t node = 0; node < numNodes; ++node) { if (maskVals[node] > 0.0f) { myColumnOut[node] = metricVals[node]; } else { myColumnOut[node] = 0.0f; } } myMetricOut->setValuesForColumn(0, myColumnOut.getArray()); myMetricOut->setColumnName(0, myMetric->getColumnName(columnNum)); } } connectome-workbench-1.4.2/src/Operations/OperationMetricMask.h000066400000000000000000000025371360521144700246450ustar00rootroot00000000000000#ifndef __METRIC_MASK_H__ #define __METRIC_MASK_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationMetricMask : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationMetricMask; } #endif //__METRIC_MASK_H__ connectome-workbench-1.4.2/src/Operations/OperationMetricMath.cxx000066400000000000000000000233031360521144700252100ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationMetricMath.h" #include "OperationException.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretMathExpression.h" #include "MetricFile.h" #include using namespace caret; using namespace std; AString OperationMetricMath::getCommandSwitch() { return "-metric-math"; } AString OperationMetricMath::getShortDescription() { return "EVALUATE EXPRESSION ON METRIC FILES"; } OperationParameters* OperationMetricMath::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "expression", "the expression to evaluate, in quotes"); ret->addMetricOutputParameter(2, "metric-out", "the output metric"); ParameterComponent* varOpt = ret->createRepeatableParameter(3, "-var", "a metric to use as a variable"); varOpt->addStringParameter(1, "name", "the name of the variable, as used in the expression"); varOpt->addMetricParameter(2, "metric", "the metric file to use as this variable"); OptionalParameter* columnSelect = varOpt->createOptionalParameter(3, "-column", "select a single column"); columnSelect->addStringParameter(1, "column", "the column number or name"); varOpt->createOptionalParameter(4, "-repeat", "reuse a single column for each column of calculation"); OptionalParameter* fixNanOpt = ret->createOptionalParameter(4, "-fixnan", "replace NaN results with a value"); fixNanOpt->addDoubleParameter(1, "replace", "value to replace NaN with"); AString myText = AString("This command evaluates at each surface vertex independently. ") + "There must be at least one -var option (to get the structure, number of vertices, and number of columns from), even if the specified in it isn't used in . " + "All metrics must have the same number of vertices. " + "Filenames are not valid in , use a variable name and a -var option with matching to specify an input file. " + "If the -column option is given to any -var option, only one column is used from that file. " + "If -repeat is specified, the file must either have only one column, or have the -column option specified. " + "All files that don't use -repeat must have the same number of columns requested to be used. " + "The format of is as follows:\n\n"; myText += CaretMathExpression::getExpressionHelpInfo(); ret->setHelpText(myText); return ret; } void OperationMetricMath::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString expression = myParams->getString(1); CaretMathExpression myExpr(expression); cout << "parsed '" + expression + "' as '" + myExpr.toString() + "'" << endl; vector myVarNames = myExpr.getVarNames(); MetricFile* myMetricOut = myParams->getOutputMetric(2); const vector& myVarOpts = *(myParams->getRepeatableParameterInstances(3)); OptionalParameter* fixNanOpt = myParams->getOptionalParameter(4); bool nanfix = false; float nanfixval = 0; if (fixNanOpt->m_present) { nanfix = true; nanfixval = (float)fixNanOpt->getDouble(1); } int numInputs = myVarOpts.size(); int numVars = myVarNames.size(); vector varMetrics(numVars, NULL); vector metricColumns(numVars, -1); if (numInputs == 0 && numVars == 0) throw OperationException("you must specify at least one input metric (-var), even if the expression doesn't use a variable"); const MetricFile* namefile = NULL; int numNodes = -1; StructureEnum::Enum myStructure; int numColumns = -1; for (int i = 0; i < numInputs; ++i) { if (i == 0) { numNodes = myVarOpts[0]->getMetric(2)->getNumberOfNodes(); myStructure = myVarOpts[0]->getMetric(2)->getStructure(); } AString varName = myVarOpts[i]->getString(1); double constVal; if (CaretMathExpression::getNamedConstant(varName, constVal)) { throw OperationException("'" + varName + "' is a named constant equal to " + AString::number(constVal, 'g', 15) + ", please use a different variable name"); } MetricFile* thisMetric = myVarOpts[i]->getMetric(2); int thisColumns = thisMetric->getNumberOfColumns(); OptionalParameter* columnSelect = myVarOpts[i]->getOptionalParameter(3); int useColumn = -1; if (columnSelect->m_present) { thisColumns = 1; useColumn = thisMetric->getMapIndexFromNameOrNumber(columnSelect->getString(1)); if (useColumn == -1) throw OperationException("could not find map '" + columnSelect->getString(1) + "' in metric file for '" + varName + "'"); } bool repeat = myVarOpts[i]->getOptionalParameter(4)->m_present; if (thisMetric->getNumberOfNodes() != numNodes) { throw OperationException("metric file for variable '" + varName + "' has different number of vertices than the first metric file"); } if (repeat) { if (thisColumns != 1) { throw OperationException("-repeat specified without -column for variable '" + varName + "', but metric file has " + AString::number(thisColumns) + " columns"); } if (useColumn == -1) useColumn = 0;//-1 means use same input column as current output column, so we need to fix the special case of -repeat on single column file without -column } else { if (numColumns == -1)//then this is the first one that doesn't use -repeat { numColumns = thisColumns; if (useColumn == -1) { namefile = thisMetric;//if it also doesn't use -column, take map names from it } } else { if (numColumns != thisColumns) { if (useColumn == -1) { throw OperationException("metric file for variable '" + varName + "' has " + AString::number(thisColumns) + " column(s), but previous metric files have " + AString::number(numColumns) + " column(s) requested to be used"); } else { throw OperationException("-column specified without -repeat for variable '" + varName + "', but previous metric files have have " + AString::number(numColumns) + " columns requested to be used"); } } } } bool found = false; for (int j = 0; j < numVars; ++j) { if (varName == myVarNames[j]) { if (varMetrics[j] != NULL) throw OperationException("variable '" + varName + "' specified more than once"); varMetrics[j] = thisMetric; metricColumns[j] = useColumn; found = true; break; } } if (!found && (numVars != 0 || numInputs != 1))//supress warning when a single -var is used with a constant expression, as required per help { CaretLogWarning("variable '" + varName + "' not used in expression"); } } for (int i = 0; i < numVars; ++i) { if (varMetrics[i] == NULL) throw OperationException("no -var option specified for variable '" + myVarNames[i] + "'"); } if (numColumns == -1) { throw OperationException("all -var options used -repeat, there is no file to get number of desired output columns from"); } vector values(numVars), colScratch(numNodes); vector columnPointers(numVars); myMetricOut->setNumberOfNodesAndColumns(numNodes, numColumns); myMetricOut->setStructure(myStructure); for (int j = 0; j < numColumns; ++j) { if (namefile != NULL) myMetricOut->setMapName(j, namefile->getMapName(j)); for (int v = 0; v < numVars; ++v) { if (metricColumns[v] == -1) { columnPointers[v] = varMetrics[v]->getValuePointerForColumn(j); } else { columnPointers[v] = varMetrics[v]->getValuePointerForColumn(metricColumns[v]); } } for (int i = 0; i < numNodes; ++i) { for (int v = 0; v < numVars; ++v) { values[v] = columnPointers[v][i]; } colScratch[i] = (float)myExpr.evaluate(values); if (nanfix && colScratch[i] != colScratch[i]) { colScratch[i] = nanfixval; } } myMetricOut->setValuesForColumn(j, colScratch.data()); } } connectome-workbench-1.4.2/src/Operations/OperationMetricMath.h000066400000000000000000000025751360521144700246450ustar00rootroot00000000000000#ifndef __OPERATION_METRIC_MATH_H__ #define __OPERATION_METRIC_MATH_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationMetricMath : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationMetricMath; } #endif //__OPERATION_METRIC_MATH_H__ connectome-workbench-1.4.2/src/Operations/OperationMetricMerge.cxx000066400000000000000000000204231360521144700253560ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationMetricMerge.h" #include "OperationException.h" #include "CaretLogger.h" #include "MetricFile.h" #include "PaletteColorMapping.h" #include using namespace caret; using namespace std; AString OperationMetricMerge::getCommandSwitch() { return "-metric-merge"; } AString OperationMetricMerge::getShortDescription() { return "MERGE METRIC FILES INTO A NEW FILE"; } OperationParameters* OperationMetricMerge::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addMetricOutputParameter(1, "metric-out", "the output metric"); ParameterComponent* metricOpt = ret->createRepeatableParameter(2, "-metric", "specify an input metric"); metricOpt->addMetricParameter(1, "metric-in", "a metric file to use columns from"); ParameterComponent* columnOpt = metricOpt->createRepeatableParameter(2, "-column", "select a single column to use"); columnOpt->addStringParameter(1, "column", "the column number or name"); OptionalParameter* upToOpt = columnOpt->createOptionalParameter(2, "-up-to", "use an inclusive range of columns"); upToOpt->addStringParameter(1, "last-column", "the number or name of the last column to include"); upToOpt->createOptionalParameter(2, "-reverse", "use the range in reverse order"); ret->setHelpText( AString("Takes one or more metric files and constructs a new metric file by concatenating columns from them. ") + "The input metric files must have the same number of vertices and same structure.\n\n" + "Example: wb_command -metric-merge out.func.gii -metric first.func.gii -column 1 -metric second.func.gii\n\n" + "This example would take the first column from first.func.gii, followed by all columns from second.func.gii, " + "and write these columns to out.func.gii." ); return ret; } void OperationMetricMerge::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); MetricFile* myMetricOut = myParams->getOutputMetric(1); const vector& myInputs = *(myParams->getRepeatableParameterInstances(2)); int numInputs = (int)myInputs.size(); if (numInputs == 0) throw OperationException("no inputs specified"); const MetricFile* firstMetric = myInputs[0]->getMetric(1); int numOutColumns = 0; int numNodes = firstMetric->getNumberOfNodes(); StructureEnum::Enum myStruct = firstMetric->getStructure(); for (int i = 0; i < numInputs; ++i) { const MetricFile* inputMetric = myInputs[i]->getMetric(1); if (numNodes != inputMetric->getNumberOfNodes()) throw OperationException("file '" + inputMetric->getFileName() + "' has a different number of nodes than the first"); if (myStruct != inputMetric->getStructure()) throw OperationException("file '" + inputMetric->getFileName() + "' has a different structure than the first"); const vector& columnOpts = *(myInputs[i]->getRepeatableParameterInstances(2)); int numColumnOpts = (int)columnOpts.size(); if (numColumnOpts > 0) { for (int j = 0; j < numColumnOpts; ++j) { int initialColumn = inputMetric->getMapIndexFromNameOrNumber(columnOpts[j]->getString(1)); if (initialColumn < 0) throw OperationException("column '" + columnOpts[j]->getString(1) + "' not found in file '" + inputMetric->getFileName() + "'"); OptionalParameter* upToOpt = columnOpts[j]->getOptionalParameter(2); if (upToOpt->m_present) { int finalColumn = inputMetric->getMapIndexFromNameOrNumber(upToOpt->getString(1)); if (finalColumn < 0) throw OperationException("ending column '" + upToOpt->getString(1) + "' not found in file '" + inputMetric->getFileName() + "'"); if (finalColumn < initialColumn) throw OperationException("ending column '" + upToOpt->getString(1) + "' occurs before starting column '" + columnOpts[j]->getString(1) + "' in file '" + inputMetric->getFileName() + "'"); numOutColumns += finalColumn - initialColumn + 1;//inclusive - we don't need to worry about reversing for counting, though } else { numOutColumns += 1; } } } else { numOutColumns += inputMetric->getNumberOfColumns(); } } myMetricOut->setNumberOfNodesAndColumns(numNodes, numOutColumns); myMetricOut->setStructure(myStruct); int curColumn = 0; for (int i = 0; i < numInputs; ++i) { const MetricFile* inputMetric = myInputs[i]->getMetric(1); const vector& columnOpts = *(myInputs[i]->getRepeatableParameterInstances(2)); int numColumnOpts = (int)columnOpts.size(); if (numColumnOpts > 0) { for (int j = 0; j < numColumnOpts; ++j) { int initialColumn = inputMetric->getMapIndexFromNameOrNumber(columnOpts[j]->getString(1)); OptionalParameter* upToOpt = columnOpts[j]->getOptionalParameter(2); if (upToOpt->m_present) { int finalColumn = inputMetric->getMapIndexFromNameOrNumber(upToOpt->getString(1)); bool reverse = upToOpt->getOptionalParameter(2)->m_present; if (reverse) { for (int c = finalColumn; c >= initialColumn; --c) { myMetricOut->setValuesForColumn(curColumn, inputMetric->getValuePointerForColumn(c)); myMetricOut->setColumnName(curColumn, inputMetric->getColumnName(c)); *(myMetricOut->getMapPaletteColorMapping(curColumn)) = *(inputMetric->getMapPaletteColorMapping(c)); ++curColumn; } } else { for (int c = initialColumn; c <= finalColumn; ++c) { myMetricOut->setValuesForColumn(curColumn, inputMetric->getValuePointerForColumn(c)); myMetricOut->setColumnName(curColumn, inputMetric->getColumnName(c)); *(myMetricOut->getMapPaletteColorMapping(curColumn)) = *(inputMetric->getMapPaletteColorMapping(c)); ++curColumn; } } } else { myMetricOut->setValuesForColumn(curColumn, inputMetric->getValuePointerForColumn(initialColumn)); myMetricOut->setColumnName(curColumn, inputMetric->getColumnName(initialColumn)); *(myMetricOut->getMapPaletteColorMapping(curColumn)) = *(inputMetric->getMapPaletteColorMapping(initialColumn)); ++curColumn; } } } else { int numColumns = inputMetric->getNumberOfColumns(); for (int j = 0; j < numColumns; ++j) { myMetricOut->setValuesForColumn(curColumn, inputMetric->getValuePointerForColumn(j)); myMetricOut->setColumnName(curColumn, inputMetric->getColumnName(j)); *(myMetricOut->getMapPaletteColorMapping(curColumn)) = *(inputMetric->getMapPaletteColorMapping(j)); ++curColumn; } } } CaretAssert(curColumn == numOutColumns); } connectome-workbench-1.4.2/src/Operations/OperationMetricMerge.h000066400000000000000000000026031360521144700250030ustar00rootroot00000000000000#ifndef __OPERATION_METRIC_MERGE_H__ #define __OPERATION_METRIC_MERGE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationMetricMerge : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationMetricMerge; } #endif //__OPERATION_METRIC_MERGE_H__ connectome-workbench-1.4.2/src/Operations/OperationMetricPalette.cxx000066400000000000000000000263031360521144700257200ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationMetricPalette.h" #include "OperationException.h" #include "MetricFile.h" #include "Palette.h" #include "PaletteColorMapping.h" #include "PaletteFile.h" #include using namespace caret; using namespace std; AString OperationMetricPalette::getCommandSwitch() { return "-metric-palette"; } AString OperationMetricPalette::getShortDescription() { return "SET THE PALETTE OF A METRIC FILE"; } OperationParameters* OperationMetricPalette::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "metric", "the metric to modify"); ret->addStringParameter(2, "mode", "the mapping mode"); OptionalParameter* columnSelect = ret->createOptionalParameter(3, "-column", "select a single column"); columnSelect->addStringParameter(1, "column", "the column number or name"); OptionalParameter* posMinMaxPercent = ret->createOptionalParameter(4, "-pos-percent", "percentage min/max for positive data coloring"); posMinMaxPercent->addDoubleParameter(1, "pos-min-%", "the percentile for the least positive data"); posMinMaxPercent->addDoubleParameter(2, "pos-max-%", "the percentile for the most positive data"); OptionalParameter* negMinMaxPercent = ret->createOptionalParameter(5, "-neg-percent", "percentage min/max for negative data coloring"); negMinMaxPercent->addDoubleParameter(1, "neg-min-%", "the percentile for the least negative data"); negMinMaxPercent->addDoubleParameter(2, "neg-max-%", "the percentile for the most negative data"); OptionalParameter* posMinMaxValue = ret->createOptionalParameter(11, "-pos-user", "user min/max values for positive data coloring"); posMinMaxValue->addDoubleParameter(1, "pos-min-user", "the value for the least positive data"); posMinMaxValue->addDoubleParameter(2, "pos-max-user", "the value for the most positive data"); OptionalParameter* negMinMaxValue = ret->createOptionalParameter(12, "-neg-user", "user min/max values for negative data coloring"); negMinMaxValue->addDoubleParameter(1, "neg-min-user", "the value for the least negative data"); negMinMaxValue->addDoubleParameter(2, "neg-max-user", "the value for the most negative data"); OptionalParameter* interpolate = ret->createOptionalParameter(9, "-interpolate", "interpolate colors"); interpolate->addBooleanParameter(1, "interpolate", "boolean, whether to interpolate"); OptionalParameter* displayPositive = ret->createOptionalParameter(6, "-disp-pos", "display positive data"); displayPositive->addBooleanParameter(1, "display", "boolean, whether to display"); OptionalParameter* displayNegative = ret->createOptionalParameter(7, "-disp-neg", "display positive data"); displayNegative->addBooleanParameter(1, "display", "boolean, whether to display"); OptionalParameter* displayZero = ret->createOptionalParameter(8, "-disp-zero", "display data closer to zero than the min cutoff"); displayZero->addBooleanParameter(1, "display", "boolean, whether to display"); OptionalParameter* paletteName = ret->createOptionalParameter(10, "-palette-name", "set the palette used"); paletteName->addStringParameter(1, "name", "the name of the palette"); OptionalParameter* thresholdOpt = ret->createOptionalParameter(13, "-thresholding", "set the thresholding"); thresholdOpt->addStringParameter(1, "type", "thresholding setting"); thresholdOpt->addStringParameter(2, "test", "show values inside or outside thresholds"); thresholdOpt->addDoubleParameter(3, "min", "lower threshold"); thresholdOpt->addDoubleParameter(4, "max", "upper threshold"); OptionalParameter* inversionOpt = ret->createOptionalParameter(15, "-inversion", "specify palette inversion"); inversionOpt->addStringParameter(1, "type", "the type of inversion"); AString myText = AString("The original metric file is overwritten with the modified version. By default, all columns of the metric file are adjusted ") + "to the new settings, use the -column option to change only one column. Mapping settings not specified in options will be taken from the first column. " + "The argument must be one of the following:\n\n"; vector myEnums; PaletteScaleModeEnum::getAllEnums(myEnums); for (int i = 0; i < (int)myEnums.size(); ++i) { myText += PaletteScaleModeEnum::toName(myEnums[i]) + "\n"; } myText += "\nThe argument to -palette-name must be one of the following:\n\n"; PaletteFile myPF; int32_t numPalettes = myPF.getNumberOfPalettes(); for (int i = 0; i < numPalettes; ++i) { myText += myPF.getPalette(i)->getName() + "\n"; } myText += "\nThe argument to -thresholding must be one of the following:\n\n"; vector myEnums2; PaletteThresholdTypeEnum::getAllEnums(myEnums2); for (int i = 0; i < (int)myEnums2.size(); ++i) { myText += PaletteThresholdTypeEnum::toName(myEnums2[i]) + "\n"; } myText += "\nThe argument to -thresholding must be one of the following:\n\n"; vector myEnums3; PaletteThresholdTestEnum::getAllEnums(myEnums3); for (int i = 0; i < (int)myEnums3.size(); ++i) { myText += PaletteThresholdTestEnum::toName(myEnums3[i]) + "\n"; } myText += "\nThe argument to -inversion must be one of the following:\n\n"; vector myEnums4; PaletteInvertModeEnum::getAllEnums(myEnums4); for (int i = 0; i < (int)myEnums4.size(); ++i) { myText += PaletteInvertModeEnum::toName(myEnums4[i]) + "\n"; } ret->setHelpText(myText); return ret; } void OperationMetricPalette::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString myMetricName = myParams->getString(1); AString myModeName = myParams->getString(2); bool ok = false; PaletteScaleModeEnum::Enum myMode = PaletteScaleModeEnum::fromName(myModeName, &ok); if (!ok) { throw OperationException("unknown mapping mode"); } MetricFile myMetric; myMetric.readFile(myMetricName); int myColumn = -1; OptionalParameter* columnSelect = myParams->getOptionalParameter(3); if (columnSelect->m_present) { myColumn = (int)myMetric.getMapIndexFromNameOrNumber(columnSelect->getString(1)); if (myColumn < 0 || myColumn >= myMetric.getNumberOfColumns()) { throw OperationException("invalid column specified"); } } PaletteColorMapping myMapping = *(myMetric.getMapPaletteColorMapping(0));//create the mapping, then use operator= to set for all requested columns, take defaults from first map myMapping.setScaleMode(myMode); OptionalParameter* posMinMaxPercent = myParams->getOptionalParameter(4); if (posMinMaxPercent->m_present) { myMapping.setAutoScalePercentagePositiveMinimum(posMinMaxPercent->getDouble(1)); myMapping.setAutoScalePercentagePositiveMaximum(posMinMaxPercent->getDouble(2)); } OptionalParameter* negMinMaxPercent = myParams->getOptionalParameter(5); if (negMinMaxPercent->m_present) { myMapping.setAutoScalePercentageNegativeMinimum(negMinMaxPercent->getDouble(1)); myMapping.setAutoScalePercentageNegativeMaximum(negMinMaxPercent->getDouble(2)); } OptionalParameter* posMinMaxValue = myParams->getOptionalParameter(11); if (posMinMaxValue->m_present) { myMapping.setUserScalePositiveMinimum(posMinMaxValue->getDouble(1)); myMapping.setUserScalePositiveMaximum(posMinMaxValue->getDouble(2)); } OptionalParameter* negMinMaxValue = myParams->getOptionalParameter(12); if (negMinMaxValue->m_present) { myMapping.setUserScaleNegativeMinimum(negMinMaxValue->getDouble(1)); myMapping.setUserScaleNegativeMaximum(negMinMaxValue->getDouble(2)); } OptionalParameter* displayPositive = myParams->getOptionalParameter(6); if (displayPositive->m_present) { myMapping.setDisplayPositiveDataFlag(displayPositive->getBoolean(1)); } OptionalParameter* displayNegative = myParams->getOptionalParameter(7); if (displayNegative->m_present) { myMapping.setDisplayNegativeDataFlag(displayNegative->getBoolean(1)); } OptionalParameter* displayZero = myParams->getOptionalParameter(8); if (displayZero->m_present) { myMapping.setDisplayZeroDataFlag(displayZero->getBoolean(1)); } OptionalParameter* interpolate = myParams->getOptionalParameter(9); if (interpolate->m_present) { myMapping.setInterpolatePaletteFlag(interpolate->getBoolean(1)); } OptionalParameter* paletteName = myParams->getOptionalParameter(10); if (paletteName->m_present) { myMapping.setSelectedPaletteName(paletteName->getString(1)); } OptionalParameter* thresholdOpt = myParams->getOptionalParameter(13); if (thresholdOpt->m_present) { bool ok = false; PaletteThresholdTypeEnum::Enum mytype = PaletteThresholdTypeEnum::fromName(thresholdOpt->getString(1), &ok); if (!ok) throw OperationException("unrecognized threshold type string: " + thresholdOpt->getString(1)); PaletteThresholdTestEnum::Enum mytest = PaletteThresholdTestEnum::fromName(thresholdOpt->getString(2), &ok); if (!ok) throw OperationException("unrecognized threshold test string: " + thresholdOpt->getString(2)); myMapping.setThresholdType(mytype); myMapping.setThresholdTest(mytest); myMapping.setThresholdMinimum(mytype, thresholdOpt->getDouble(3)); myMapping.setThresholdMaximum(mytype, thresholdOpt->getDouble(4)); } OptionalParameter* inversionOpt = myParams->getOptionalParameter(15); if (inversionOpt->m_present) { bool ok = false; PaletteInvertModeEnum::Enum inversionType = PaletteInvertModeEnum::fromName(inversionOpt->getString(1), &ok); if (!ok) throw OperationException("unrecognized palette inversion type: " + inversionOpt->getString(1)); myMapping.setInvertedMode(inversionType); } if (myColumn == -1) { for (int i = 0; i < myMetric.getNumberOfMaps(); ++i) { *(myMetric.getMapPaletteColorMapping(i)) = myMapping; } } else { *(myMetric.getMapPaletteColorMapping(myColumn)) = myMapping; } myMetric.writeFile(myMetricName); } connectome-workbench-1.4.2/src/Operations/OperationMetricPalette.h000066400000000000000000000026171360521144700253470ustar00rootroot00000000000000#ifndef __OPERATION_METRIC_PALETTE_H__ #define __OPERATION_METRIC_PALETTE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationMetricPalette : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationMetricPalette; } #endif //__OPERATION_METRIC_PALETTE_H__ connectome-workbench-1.4.2/src/Operations/OperationMetricStats.cxx000066400000000000000000000214301360521144700254140ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationMetricStats.h" #include "OperationException.h" #include "MetricFile.h" #include "ReductionOperation.h" #include #include #include #include #include #include using namespace caret; using namespace std; AString OperationMetricStats::getCommandSwitch() { return "-metric-stats"; } AString OperationMetricStats::getShortDescription() { return "SPATIAL STATISTICS ON A METRIC FILE"; } OperationParameters* OperationMetricStats::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addMetricParameter(1, "metric-in", "the input metric"); OptionalParameter* reduceOpt = ret->createOptionalParameter(2, "-reduce", "use a reduction operation"); reduceOpt->addStringParameter(1, "operation", "the reduction operation"); OptionalParameter* percentileOpt = ret->createOptionalParameter(3, "-percentile", "give the value at a percentile"); percentileOpt->addDoubleParameter(1, "percent", "the percentile to find"); OptionalParameter* columnOpt = ret->createOptionalParameter(4, "-column", "only display output for one column"); columnOpt->addStringParameter(1, "column", "the column number or name"); OptionalParameter* roiOpt = ret->createOptionalParameter(5, "-roi", "only consider data inside an roi"); roiOpt->addMetricParameter(1, "roi-metric", "the roi, as a metric file"); roiOpt->createOptionalParameter(2, "-match-maps", "each column of input uses the corresponding column from the roi file"); ret->createOptionalParameter(6, "-show-map-name", "print map index and name before each output"); ret->setHelpText( AString("For each column of the input, a single number is printed, resulting from the specified reduction or percentile operation. ") + "Use -column to only give output for a single column. " + "Use -roi to consider only the data within a region. " + "Exactly one of -reduce or -percentile must be specified.\n\n" + "The argument to the -reduce option must be one of the following:\n\n" + ReductionOperation::getHelpInfo()); return ret; } namespace { float reduce(const float* data, const int& numNodes, const ReductionEnum::Enum& myop, const float* roiData) { if (roiData == NULL) { return ReductionOperation::reduce(data, numNodes, myop); } else { vector toUse; toUse.reserve(numNodes); for (int i = 0; i < numNodes; ++i) { if (roiData[i] > 0.0f) { toUse.push_back(data[i]); } } if (toUse.empty()) throw OperationException("roi contains no vertices"); return ReductionOperation::reduce(toUse.data(), toUse.size(), myop); } } float percentile(const float* data, const int& numNodes, const float& percent, const float* roiData) { CaretAssert(percent >= 0.0f && percent <= 100.0f); vector toUse; if (roiData == NULL) { toUse = vector(data, data + numNodes); } else { toUse.reserve(numNodes); for (int i = 0; i < numNodes; ++i) { if (roiData[i] > 0.0f) { toUse.push_back(data[i]); } } } if (toUse.empty()) throw OperationException("roi contains no vertices"); sort(toUse.begin(), toUse.end()); const float index = percent / 100.0f * (toUse.size() - 1); if (index <= 0) return toUse[0]; if (index >= toUse.size() - 1) return toUse.back(); float ipart, fpart; fpart = modf(index, &ipart); return (1.0f - fpart) * toUse[(int)ipart] + fpart * toUse[((int)ipart) + 1]; } } void OperationMetricStats::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); MetricFile* input = myParams->getMetric(1); int numNodes = input->getNumberOfNodes(); int numCols = input->getNumberOfColumns(); OptionalParameter* reduceOpt = myParams->getOptionalParameter(2); OptionalParameter* percentileOpt = myParams->getOptionalParameter(3); if (reduceOpt->m_present == percentileOpt->m_present)//use == as logical xor { throw OperationException("you must use exactly one of -reduce or -percentile"); } ReductionEnum::Enum myop = ReductionEnum::INVALID; if (reduceOpt->m_present) { bool ok = false; myop = ReductionEnum::fromName(reduceOpt->getString(1), &ok); if (!ok) throw OperationException("unrecognized reduction operation: " + reduceOpt->getString(1)); } float percent = 0.0f; if (percentileOpt->m_present) { percent = (float)percentileOpt->getDouble(1);//use not within range to trap NaNs, just in case if (!(percent >= 0.0f && percent <= 100.0f)) throw OperationException("percentile must be between 0 and 100"); } int column = -1; OptionalParameter* columnOpt = myParams->getOptionalParameter(4); if (columnOpt->m_present) { column = input->getMapIndexFromNameOrNumber(columnOpt->getString(1)); if (column < 0) throw OperationException("invalid column specified"); } bool matchColumnMode = false; MetricFile* myRoi = NULL; int32_t numRoiCols = 1;//trick: pretend we have 1 roi map when we have no ROI file OptionalParameter* roiOpt = myParams->getOptionalParameter(5); if (roiOpt->m_present) { myRoi = roiOpt->getMetric(1); numRoiCols = myRoi->getNumberOfColumns(); if (myRoi->getNumberOfNodes() != numNodes) throw OperationException("roi doesn't match input in number of vertices"); if (roiOpt->getOptionalParameter(2)->m_present) { if (numRoiCols != numCols) { throw OperationException("-match-maps specified, but roi has different number of columns than input"); } matchColumnMode = true; } } bool showMapName = myParams->getOptionalParameter(6)->m_present; int32_t columnStart, columnEnd; if (column == -1) { columnStart = 0; columnEnd = numCols; } else { CaretAssert(column >= 0 && column < numCols); columnStart = column; columnEnd = column + 1; } for (int i = columnStart; i < columnEnd; ++i) { if (showMapName) cout << AString::number(i + 1) << ":\t" << input->getMapName(i) << ":\t"; if (matchColumnMode) {//trick: matchColumn is only true when we have an roi const float* roiData = myRoi->getValuePointerForColumn(i); float result; if (reduceOpt->m_present) { result = reduce(input->getValuePointerForColumn(i), numNodes, myop, roiData); } else { CaretAssert(percentileOpt->m_present); result = percentile(input->getValuePointerForColumn(i), numNodes, percent, roiData); } stringstream resultsstr; resultsstr << setprecision(7) << result; cout << resultsstr.str(); } else { for (int j = 0; j < numRoiCols; ++j) { const float* roiData = NULL; if (myRoi != NULL) roiData = myRoi->getValuePointerForColumn(j); float result; if (reduceOpt->m_present) { result = reduce(input->getValuePointerForColumn(i), numNodes, myop, roiData); } else { CaretAssert(percentileOpt->m_present); result = percentile(input->getValuePointerForColumn(i), numNodes, percent, roiData); } stringstream resultsstr; resultsstr << setprecision(7) << result; if (j != 0) cout << "\t"; cout << resultsstr.str(); } } cout << endl; } } connectome-workbench-1.4.2/src/Operations/OperationMetricStats.h000066400000000000000000000026031360521144700250420ustar00rootroot00000000000000#ifndef __OPERATION_METRIC_STATS_H__ #define __OPERATION_METRIC_STATS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationMetricStats : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationMetricStats; } #endif //__OPERATION_METRIC_STATS_H__ connectome-workbench-1.4.2/src/Operations/OperationMetricVertexSum.cxx000066400000000000000000000162611360521144700262660ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationMetricVertexSum.h" #include "OperationException.h" #include "MetricFile.h" #include "SurfaceFile.h" #include #include #include using namespace caret; using namespace std; AString OperationMetricVertexSum::getCommandSwitch() { return "-metric-vertex-sum"; } AString OperationMetricVertexSum::getShortDescription() { return "DEPRECATED: use -metric-stats or -metric-weighted-stats"; } OperationParameters* OperationMetricVertexSum::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addMetricParameter(1, "metric-in", "the metric to sum"); OptionalParameter* integrateOpt = ret->createOptionalParameter(2, "-integrate", "integrate across a surface, rather than summing"); integrateOpt->addSurfaceParameter(1, "surface", "the surface to integrate on"); OptionalParameter* integrateMetricOpt = ret->createOptionalParameter(3, "-integrate-metric", "integrate using vertex areas from a metric file"); integrateMetricOpt->addMetricParameter(1, "area-metric", "metric file containing vertex areas"); OptionalParameter* roiOpt = ret->createOptionalParameter(4, "-roi", "only use data inside an roi"); roiOpt->addMetricParameter(1, "roi-metric", "the roi, as a metric file"); OptionalParameter* columnOpt = ret->createOptionalParameter(5, "-column", "select a single column"); columnOpt->addStringParameter(1, "column", "the column number or name"); ret->setHelpText( AString("DEPRECATED: this command may be removed in a future release, use -metric-stats or -metric-weighted-stats.\n\n") + "For each column in , sum the values across all vertices, then print the sum on standard output. " + "-integrate and -integrate-metric multiply each vertex value by the vertex area before doing the sum. " + "Only one of -integrate and -integrate-metric may be specified. " + "Use -roi to only sum within a specific area. " + "Use -column to only report for one column. " ); return ret; } void OperationMetricVertexSum::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); MetricFile* myMetric = myParams->getMetric(1); int numNodes = myMetric->getNumberOfNodes(); const float* integrateData = NULL; vector surfNodeAreas; OptionalParameter* integrateOpt = myParams->getOptionalParameter(2); if (integrateOpt->m_present) { SurfaceFile* integrateSurf = integrateOpt->getSurface(1); if (integrateSurf->getNumberOfNodes() != numNodes) throw OperationException("integration surface has the wrong number of vertices"); integrateSurf->computeNodeAreas(surfNodeAreas); integrateData = surfNodeAreas.data(); } OptionalParameter* integrateMetricOpt = myParams->getOptionalParameter(3); if (integrateMetricOpt->m_present) { if (integrateOpt->m_present) throw OperationException("only one of -integrate and -integrate-metric can be specified"); MetricFile* integrateMetric = integrateMetricOpt->getMetric(1);//we don't need to keep a pointer to it if (integrateMetric->getNumberOfNodes() != numNodes) throw OperationException("integration metric has the wrong number of vertices"); integrateData = integrateMetric->getValuePointerForColumn(0);//just its data } MetricFile* myRoi = NULL; OptionalParameter* roiOpt = myParams->getOptionalParameter(4); if (roiOpt->m_present) { myRoi = roiOpt->getMetric(1); if (myRoi->getNumberOfNodes() != numNodes) throw OperationException("roi-metric has the wrong number of vertices"); } int myColumn = -1; OptionalParameter* columnOpt = myParams->getOptionalParameter(5); if (columnOpt->m_present) { myColumn = myMetric->getMapIndexFromNameOrNumber(columnOpt->getString(1)); if (myColumn < 0 || myColumn >= myMetric->getNumberOfMaps()) { throw OperationException("invalid column specified"); } } const float* roiData = NULL; if (myRoi != NULL) roiData = myRoi->getValuePointerForColumn(0); if (integrateData != NULL) { if (myColumn == -1) { int numCols = myMetric->getNumberOfColumns(); for (int j = 0; j < numCols; ++j) { double accum = 0.0; const float* data = myMetric->getValuePointerForColumn(j); for (int i = 0; i < numNodes; ++i) { if (roiData == NULL || roiData[i] > 0.0f) { accum += data[i] * integrateData[i]; } } stringstream s; s << std::setprecision(7) << accum; cout << s.str() << endl; } } else { double accum = 0.0; const float* data = myMetric->getValuePointerForColumn(myColumn); for (int i = 0; i < numNodes; ++i) { if (roiData == NULL || roiData[i] > 0.0f) { accum += data[i] * integrateData[i]; } } stringstream s; s << std::setprecision(7) << accum; cout << s.str() << endl; } } else { if (myColumn == -1) { int numCols = myMetric->getNumberOfColumns(); for (int j = 0; j < numCols; ++j) { double accum = 0.0; const float* data = myMetric->getValuePointerForColumn(j); for (int i = 0; i < numNodes; ++i) { if (roiData == NULL || roiData[i] > 0.0f) { accum += data[i]; } } stringstream s; s << std::setprecision(7) << accum; cout << s.str() << endl; } } else { double accum = 0.0; const float* data = myMetric->getValuePointerForColumn(myColumn); for (int i = 0; i < numNodes; ++i) { if (roiData == NULL || roiData[i] > 0.0f) { accum += data[i]; } } stringstream s; s << std::setprecision(7) << accum; cout << s.str() << endl; } } } connectome-workbench-1.4.2/src/Operations/OperationMetricVertexSum.h000066400000000000000000000026361360521144700257140ustar00rootroot00000000000000#ifndef __OPERATION_METRIC_VERTEX_SUM_H__ #define __OPERATION_METRIC_VERTEX_SUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationMetricVertexSum : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationMetricVertexSum; } #endif //__OPERATION_METRIC_VERTEX_SUM_H__ connectome-workbench-1.4.2/src/Operations/OperationMetricWeightedStats.cxx000066400000000000000000000337331360521144700271060ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationMetricWeightedStats.h" #include "OperationException.h" #include "CaretHeap.h" #include "MetricFile.h" #include "SurfaceFile.h" #include #include #include #include #include using namespace caret; using namespace std; AString OperationMetricWeightedStats::getCommandSwitch() { return "-metric-weighted-stats"; } AString OperationMetricWeightedStats::getShortDescription() { return "WEIGHTED SPATIAL STATISTICS ON A METRIC FILE"; } OperationParameters* OperationMetricWeightedStats::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addMetricParameter(1, "metric-in", "the input metric"); OptionalParameter* areaSurfOpt = ret->createOptionalParameter(2, "-area-surface", "use vertex areas as weights"); areaSurfOpt->addSurfaceParameter(1, "area-surface", "the surface to use for vertex areas"); OptionalParameter* weightMetricOpt = ret->createOptionalParameter(3, "-weight-metric", "use weights from a metric file"); weightMetricOpt->addMetricParameter(1, "weight-metric", "metric file containing the weights"); OptionalParameter* columnOpt = ret->createOptionalParameter(4, "-column", "only display output for one column"); columnOpt->addStringParameter(1, "column", "the column number or name"); OptionalParameter* roiOpt = ret->createOptionalParameter(5, "-roi", "only consider data inside an roi"); roiOpt->addMetricParameter(1, "roi-metric", "the roi, as a metric file"); roiOpt->createOptionalParameter(2, "-match-maps", "each column of input uses the corresponding column from the roi file"); ret->createOptionalParameter(6, "-mean", "compute weighted mean"); OptionalParameter* stdevOpt = ret->createOptionalParameter(7, "-stdev", "compute weighted standard deviation"); stdevOpt->createOptionalParameter(1, "-sample", "estimate population stdev from the sample"); OptionalParameter* percentileOpt = ret->createOptionalParameter(8, "-percentile", "compute weighted percentile"); percentileOpt->addDoubleParameter(1, "percent", "the percentile to find"); ret->createOptionalParameter(9, "-sum", "compute weighted sum"); ret->createOptionalParameter(10, "-show-map-name", "print map index and name before each output"); ret->setHelpText( AString("For each column of the input, a single number is printed, resulting from the specified operation. ") + "You must specify exactly one of -area-surface or -weight-metric. " + "Use -column to only give output for a single column. " + "Use -roi to consider only the data within a region. " + "Exactly one of -mean, -stdev, -percentile or -sum must be specified.\n\n" + "Using -sum with -area-surface (or -weight-metric with a metric containing similar data) is equivalent to integrating with respect to surface area. " + "For example, if you want to find the surface area within an roi, do this:\n\n" + "$ wb_command -metric-weighted-stats roi.func.gii -sum -area-surface midthickness.surf.gii" ); return ret; } namespace { enum OperationType { MEAN, STDEV, SAMPSTDEV, PERCENTILE, SUM }; float doOperation(const float* data, const float* weights, const int& numNodes, const OperationType& myop, const float* roiData, const float& argument) {//argument is only used for percentile currently const float* useData = data, *useWeights = weights; int numUse = numNodes; vector dataScratch, weightScratch;//for when we have an ROI if (roiData != NULL) { dataScratch.reserve(numNodes); weightScratch.reserve(numNodes); for (int i = 0; i < numNodes; ++i) { if (roiData[i] > 0.0f) { dataScratch.push_back(data[i]); weightScratch.push_back(weights[i]); } } if (dataScratch.size() < 1) throw OperationException("roi contains no vertices"); useData = dataScratch.data(); useWeights = weightScratch.data(); numUse = (int)dataScratch.size(); } switch(myop) { case SUM: case MEAN: case STDEV: case SAMPSTDEV://these all start the same way { double accum = 0.0, weightsum = 0.0; for (int i = 0; i < numUse; ++i) { accum += useData[i] * useWeights[i]; weightsum += useWeights[i]; } if (myop == SUM) return accum; const float mean = accum / weightsum; if (myop == MEAN) return mean; accum = 0.0; double weightsum2 = 0.0;//for weighted sample stdev for (int i = 0; i < numUse; ++i) { float tempf = useData[i] - mean; accum += useWeights[i] * tempf * tempf; weightsum2 += useWeights[i] * useWeights[i]; } if (myop == STDEV) return sqrt(accum / weightsum); CaretAssert(myop == SAMPSTDEV); if (numUse < 2) throw OperationException("sample standard deviation requires at least 2 elements in the roi"); return sqrt(accum / (weightsum - weightsum2 / weightsum));//http://en.wikipedia.org/wiki/Weighted_arithmetic_mean#Weighted_sample_variance } case PERCENTILE: { CaretAssert(argument >= 0.0f && argument <= 100.0f); if (numUse == 1) return useData[0];//would need special handling anyway, so get it early CaretSimpleMinHeap sorter; double weightaccum = 0.0;//double will usually prevent adding weights in a different order from getting a different answer for (int i = 0; i < numUse; ++i) { if (useWeights[i] < 0.0f) throw OperationException("negative weights not allowed in weighted percentile"); weightaccum += useWeights[i]; sorter.push(useWeights[i], useData[i]);//sort by value } float targetWeight = argument / 100.0f * weightaccum; float lastData, nextData; float lastWeight = sorter.pop(&lastData); weightaccum = lastWeight; float nextWeight = sorter.top(&nextData); int position = 1;//because the first and last sections get special treatment to not have flat ends on the function while (weightaccum + nextWeight * 0.5f < targetWeight && sorter.size() > 1) { ++position; sorter.pop(); weightaccum += nextWeight; lastWeight = nextWeight; lastData = nextData; nextWeight = sorter.top(&nextData); } if (targetWeight < weightaccum) { if (position == 1) {//stretch interpolation at first position to the edge return lastData + (nextData - lastData) * 0.5f * ((targetWeight - weightaccum) / lastWeight + 1.0f); } else { return lastData + (nextData - lastData) * 0.5f * ((targetWeight - weightaccum) / (lastWeight * 0.5f) + 1.0f); } } else { if (position == numUse - 1) {//ditto return (lastData + nextData) * 0.5f + (nextData - lastData) * 0.5f * (targetWeight - weightaccum) / nextWeight; } else { return (lastData + nextData) * 0.5f + (nextData - lastData) * 0.5f * (targetWeight - weightaccum) / (nextWeight * 0.5f); } } } } CaretAssert(false);//make sure execution never actually reaches end of function throw OperationException("internal error in weighted stats"); } } void OperationMetricWeightedStats::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); MetricFile* input = myParams->getMetric(1); int numNodes = input->getNumberOfNodes(); int numCols = input->getNumberOfColumns(); vector areaData; const float* useWeights = NULL; OptionalParameter* areaSurfOpt = myParams->getOptionalParameter(2); if (areaSurfOpt->m_present) { SurfaceFile* mySurf = areaSurfOpt->getSurface(1); if (mySurf->getNumberOfNodes() != numNodes) throw OperationException("area surface has different number of vertices than input metric"); mySurf->computeNodeAreas(areaData); useWeights = areaData.data(); } OptionalParameter* weightMetricOpt = myParams->getOptionalParameter(3); if (weightMetricOpt->m_present) { if (useWeights != NULL) throw OperationException("you may not specify both -area-surface and -weight-metric"); MetricFile* myWeights = weightMetricOpt->getMetric(1); if (myWeights->getNumberOfNodes() != numNodes) throw OperationException("weight metric has different number of vertices than input metric"); useWeights = myWeights->getValuePointerForColumn(0); } if (useWeights == NULL) throw OperationException("you must specify either -area-surface or -weight-metric"); int column = -1; OptionalParameter* columnOpt = myParams->getOptionalParameter(4); if (columnOpt->m_present) { column = input->getMapIndexFromNameOrNumber(columnOpt->getString(1)); if (column < 0) throw OperationException("invalid column specified"); } bool matchColumnMode = false; MetricFile* myRoi = NULL; int32_t numRoiCols = 1;//trick: pretend 1 roi column exists when there is no roi to get the inner loop to do the right thing OptionalParameter* roiOpt = myParams->getOptionalParameter(5); if (roiOpt->m_present) { myRoi = roiOpt->getMetric(1); numRoiCols = myRoi->getNumberOfColumns(); if (myRoi->getNumberOfNodes() != numNodes) throw OperationException("roi doesn't match input in number of vertices"); if (roiOpt->getOptionalParameter(2)->m_present) { if (numRoiCols != numCols) { throw OperationException("-match-maps specified, but roi has different number of columns than input"); } matchColumnMode = true; } } bool haveOp = false; OperationType myop; if (myParams->getOptionalParameter(6)->m_present) { haveOp = true; myop = MEAN; } OptionalParameter* stdevOpt = myParams->getOptionalParameter(7); if (stdevOpt->m_present) { if (haveOp) throw OperationException("you may only specify one operation"); haveOp = true; if (stdevOpt->getOptionalParameter(1)->m_present) { myop = SAMPSTDEV; } else { myop = STDEV; } } float argument = -1.0f; OptionalParameter* percentileOpt = myParams->getOptionalParameter(8); if (percentileOpt->m_present) { if (haveOp) throw OperationException("you may only specify one operation"); haveOp = true; myop = PERCENTILE; argument = percentileOpt->getDouble(1); if (!(argument >= 0.0f && argument <= 100.0f)) throw OperationException("percentile must be between 0 and 100"); } if (myParams->getOptionalParameter(9)->m_present) { if (haveOp) throw OperationException("you may only specify one operation"); haveOp = true; myop = SUM; } if (!haveOp) throw OperationException("you must specify an operation"); bool showMapName = myParams->getOptionalParameter(10)->m_present; int32_t columnStart, columnEnd; if (column == -1) { columnStart = 0; columnEnd = numCols; } else { columnStart = column; columnEnd = column + 1; } for (int i = columnStart; i < columnEnd; ++i) { if (showMapName) cout << AString::number(i + 1) << ":\t" << input->getMapName(i) << ":\t"; if (matchColumnMode) {//trick: matchColumn is only true when we have an roi const float* roiData = myRoi->getValuePointerForColumn(i); const float result = doOperation(input->getValuePointerForColumn(i), useWeights, numNodes, myop, roiData, argument); stringstream resultsstr; resultsstr << setprecision(7) << result; cout << resultsstr.str(); } else { for (int j = 0; j < numRoiCols; ++j) { const float* roiData = NULL; if (myRoi != NULL) roiData = myRoi->getValuePointerForColumn(j); const float result = doOperation(input->getValuePointerForColumn(i), useWeights, numNodes, myop, roiData, argument); stringstream resultsstr; resultsstr << setprecision(7) << result; if (j != 0) cout << "\t"; cout << resultsstr.str(); } } cout << endl; } } connectome-workbench-1.4.2/src/Operations/OperationMetricWeightedStats.h000066400000000000000000000026661360521144700265340ustar00rootroot00000000000000#ifndef __OPERATION_METRIC_WEIGHTED_STATS_H__ #define __OPERATION_METRIC_WEIGHTED_STATS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationMetricWeightedStats : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationMetricWeightedStats; } #endif //__OPERATION_METRIC_WEIGHTED_STATS_H__ connectome-workbench-1.4.2/src/Operations/OperationNiftiInformation.cxx000066400000000000000000000145241360521144700264370ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationNiftiInformation.h" #include "OperationException.h" #include "CaretBinaryFile.h" #include "CiftiFile.h" #include "NiftiIO.h" #include "CiftiXML.h" #include "DataFileTypeEnum.h" #include using namespace caret; using namespace std; AString OperationNiftiInformation::getCommandSwitch() { return "-nifti-information"; } AString OperationNiftiInformation::getShortDescription() { return "DISPLAY INFORMATION ABOUT A NIFTI/CIFTI FILE"; } OperationParameters* OperationNiftiInformation::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "nifti-file", "the nifti/cifti file to examine"); OptionalParameter* headerOpt = ret->createOptionalParameter(2, "-print-header", "display the header contents"); headerOpt->createOptionalParameter(1, "-allow-truncated", "print the header even if the data is truncated"); ret->createOptionalParameter(3, "-print-matrix", "output the values in the matrix (cifti only)"); OptionalParameter* printXmlOpt = ret->createOptionalParameter(4, "-print-xml", "print the cifti XML (cifti only)"); OptionalParameter* pxVersionOpt = printXmlOpt->createOptionalParameter(1, "-version", "convert the XML to a specific CIFTI version (default is the file's cifti version)"); pxVersionOpt->addStringParameter(1, "version", "the CIFTI version to use"); ret->setHelpText( AString("You must specify at least one -print-* option.") ); return ret; } void OperationNiftiInformation::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); const AString fileName = myParams->getString(1); OptionalParameter* headerOpt = myParams->getOptionalParameter(2); bool printHeader = headerOpt->m_present; bool printMatrix = myParams->getOptionalParameter(3)->m_present; OptionalParameter* printXmlOpt = myParams->getOptionalParameter(4); bool printXml = printXmlOpt->m_present; if (!printHeader && !printMatrix && !printXml) throw OperationException("you must specify a -print-* option"); if(!QFile::exists(fileName)) throw OperationException("File '" + fileName + "' does not exist."); if(printHeader) { if (!headerOpt->getOptionalParameter(1)->m_present) {//NiftiIO contains the file length check NiftiIO myIO; myIO.openRead(fileName); cout << myIO.getHeader().toString() << endl; cout << getMemorySizeAsString(myIO.getDimensions()) << endl; } else {//NiftiHeader doesn't CaretBinaryFile myFile(fileName); NiftiHeader myHeader; myHeader.read(myFile); cout << myHeader.toString() << endl; cout << getMemorySizeAsString(myHeader.getDimensions()) << endl; } } if(printXml) { CiftiFile cf(fileName); const CiftiXML& xml = cf.getCiftiXML(); CiftiVersion printVersion = xml.getParsedVersion();//by default, rewrite with the same version that it was read with OptionalParameter* pxVersionOpt = printXmlOpt->getOptionalParameter(1); if (pxVersionOpt->m_present) { printVersion = CiftiVersion(pxVersionOpt->getString(1)); } AString xmlString = xml.writeXMLToString(printVersion); cout << xmlString << endl; } if(printMatrix) { CiftiFile cf(fileName); if (cf.getCiftiXML().getNumberOfDimensions() != 2) throw OperationException("-print-matrix only supports 2D cifti"); int64_t dim0 = cf.getNumberOfRows(); int64_t dim1 = cf.getNumberOfColumns(); vector row(dim1); AString rowString; for(int64_t i = 0;i& dimensions) { AString str; int64_t numVoxelComponents = 0; const int64_t numDims = static_cast(dimensions.size()); if (numDims > 0) { numVoxelComponents = 1; for (int64_t i = 0; i < numDims; i++) { CaretAssertVectorIndex(dimensions, i); numVoxelComponents *= dimensions[i]; } } const int64_t numberOfBytes = sizeof(float) * numVoxelComponents; str += ("Data Size in (float) memory, Bytes: " + AString::number(numberOfBytes)); const double oneKilobyte = 1024.0; const double kilobytes = numberOfBytes / oneKilobyte; const double oneMegabyte = 1048576.0; const double megabytes = numberOfBytes / oneMegabyte; const double oneGigabyte = 1073741824.0; const double gigabytes = numberOfBytes / oneGigabyte; const double oneTerabyte = 1099511627776.0; const double terabytes = numberOfBytes / oneTerabyte; if (terabytes >= 1.0) { str += (" Terabytes: " + AString::number(terabytes)); } else if (gigabytes >= 1.0) { str += (" Gigabytes: " + AString::number(gigabytes)); } else if (megabytes >= 1.0) { str += (" Megabytes: " + AString::number(megabytes)); } else if (kilobytes >= 1.0) { str += (" Kilobytes: " + AString::number(kilobytes)); } return str; } connectome-workbench-1.4.2/src/Operations/OperationNiftiInformation.h000066400000000000000000000030041360521144700260530ustar00rootroot00000000000000#ifndef __OPERATION_NIFTI_INFORMATION_H__ #define __OPERATION_NIFTI_INFORMATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationNiftiInformation : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); private: static AString getMemorySizeAsString(const std::vector& dimensions); }; typedef TemplateAutoOperation AutoOperationNiftiInformation; } #endif //__OPERATION_NIFTI_INFORMATION_H__ connectome-workbench-1.4.2/src/Operations/OperationProbtrackXDotConvert.cxx000066400000000000000000000516241360521144700272510ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationProbtrackXDotConvert.h" #include "OperationException.h" #include "CaretLogger.h" #include "CiftiFile.h" #include "MetricFile.h" #include "StructureEnum.h" #include "VolumeFile.h" #include #include #include #include using namespace caret; using namespace std; //specifically for the purpose of sorting the input .dot file to the order required, in case it isn't initially ordered correctly struct SparseValue { int32_t index[2];//save some memory float value; bool operator<(const SparseValue& rhs) const { return (index[1] < rhs.index[1]);//NOTE: this specifically avoids minor ordering by the other index to make the sort faster (less swapping because more "equals" cases) } }; AString OperationProbtrackXDotConvert::getCommandSwitch() { return "-probtrackx-dot-convert"; } AString OperationProbtrackXDotConvert::getShortDescription() { return "CONVERT A .DOT FILE FROM PROBTRACKX TO CIFTI"; } OperationParameters* OperationProbtrackXDotConvert::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "dot-file", "input .dot file"); ret->addCiftiOutputParameter(2, "cifti-out", "output cifti file"); OptionalParameter* rowVoxelOpt = ret->createOptionalParameter(3, "-row-voxels", "the output mapping along a row will be voxels"); rowVoxelOpt->addStringParameter(1, "voxel-list-file", "a text file containing IJK indices for the voxels used"); rowVoxelOpt->addVolumeParameter(2, "label-vol", "a label volume with the dimensions and sform used, with structure labels"); OptionalParameter* rowSurfaceOpt = ret->createOptionalParameter(4, "-row-surface", "the output mapping along a row will be surface vertices"); rowSurfaceOpt->addMetricParameter(1, "roi-metric", "a metric file with positive values on all vertices used"); OptionalParameter* rowCiftiOpt = ret->createOptionalParameter(9, "-row-cifti", "take the mapping along a row from a cifti file"); rowCiftiOpt->addCiftiParameter(1, "cifti", "the cifti file to take the mapping from"); rowCiftiOpt->addStringParameter(2, "direction", "which dimension to take the mapping along, ROW or COLUMN"); OptionalParameter* colVoxelOpt = ret->createOptionalParameter(5, "-col-voxels", "the output mapping along a column will be voxels"); colVoxelOpt->addStringParameter(1, "voxel-list-file", "a text file containing IJK indices for the voxels used"); colVoxelOpt->addVolumeParameter(2, "label-vol", "a label volume with the dimensions and sform used, with structure labels"); OptionalParameter* colSurfaceOpt = ret->createOptionalParameter(6, "-col-surface", "the output mapping along a column will be surface vertices"); colSurfaceOpt->addMetricParameter(1, "roi-metric", "a metric file with positive values on all vertices used"); OptionalParameter* colCiftiOpt = ret->createOptionalParameter(10, "-col-cifti", "take the mapping along a column from a cifti file"); colCiftiOpt->addCiftiParameter(1, "cifti", "the cifti file to take the mapping from"); colCiftiOpt->addStringParameter(2, "direction", "which dimension to take the mapping along, ROW or COLUMN"); ret->createOptionalParameter(7, "-transpose", "transpose the input matrix"); ret->createOptionalParameter(8, "-make-symmetric", "transform half-square input into full matrix output"); AString myText = AString("NOTE: exactly one -row option and one -col option must be used.\n\n") + "If the input file does not have its indexes sorted in the correct ordering, this command may take longer than expected. " + "Specifying -transpose will transpose the input matrix before trying to put its values into the cifti file, which is currently needed for at least matrix2 " + "in order to display it as intended. " + "How the cifti file is displayed is based on which -row option is specified: if -row-voxels is specified, then it will display data on volume slices. " + "The label names in the label volume(s) must have the following names, other names are ignored:\n\n"; vector myStructureEnums; StructureEnum::getAllEnums(myStructureEnums); for (int i = 0; i < (int)myStructureEnums.size(); ++i) { myText += "\n" + StructureEnum::toName(myStructureEnums[i]); } ret->setHelpText(myText); return ret; } void OperationProbtrackXDotConvert::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString dotFileName = myParams->getString(1); CiftiFile* myCiftiOut = myParams->getOutputCifti(2); OptionalParameter* rowVoxelOpt = myParams->getOptionalParameter(3); OptionalParameter* rowSurfaceOpt = myParams->getOptionalParameter(4); OptionalParameter* rowCiftiOpt = myParams->getOptionalParameter(9); OptionalParameter* colVoxelOpt = myParams->getOptionalParameter(5); OptionalParameter* colSurfaceOpt = myParams->getOptionalParameter(6); OptionalParameter* colCiftiOpt = myParams->getOptionalParameter(10); bool transpose = myParams->getOptionalParameter(7)->m_present; bool halfMatrix = myParams->getOptionalParameter(8)->m_present; int numRowOpts = 0, numColOpts = 0; if (rowVoxelOpt->m_present) ++numRowOpts; if (rowSurfaceOpt->m_present) ++numRowOpts; if (rowCiftiOpt->m_present) ++numRowOpts; if (colVoxelOpt->m_present) ++numColOpts; if (colSurfaceOpt->m_present) ++numColOpts; if (colCiftiOpt->m_present) ++numColOpts; if (numRowOpts != 1)//if both false or both true, basically using equals as a quick hack for xnor { throw OperationException("you must specify exactly one of -row-voxels, -row-surface, and -row-cifti"); } if (numColOpts != 1) { throw OperationException("you must specify exactly one of -col-voxels, -col-surface, and -col-cifti"); } CiftiXMLOld myXML; myXML.resetRowsToBrainModels(); myXML.resetColumnsToBrainModels(); vector rowReorderMap, colReorderMap; if (rowVoxelOpt->m_present) { addVoxelMapping(rowVoxelOpt->getVolume(2), rowVoxelOpt->getString(1), myXML, rowReorderMap, CiftiXMLOld::ALONG_ROW); } if (rowSurfaceOpt->m_present) { MetricFile* myMetric = rowSurfaceOpt->getMetric(1); myXML.addSurfaceModelToRows(myMetric->getNumberOfNodes(), myMetric->getStructure(), myMetric->getValuePointerForColumn(0)); } if (rowCiftiOpt->m_present) { AString directionName = rowCiftiOpt->getString(2); int myDir; if (directionName == "ROW") { myDir = CiftiXMLOld::ALONG_ROW; } else if (directionName == "COLUMN") { myDir = CiftiXMLOld::ALONG_COLUMN; } else { throw OperationException("incorrect string for direction, use ROW or COLUMN"); } myXML.copyMapping(CiftiXMLOld::ALONG_ROW, rowCiftiOpt->getCifti(1)->getCiftiXMLOld(), myDir); } if (colVoxelOpt->m_present) { addVoxelMapping(colVoxelOpt->getVolume(2), colVoxelOpt->getString(1), myXML, colReorderMap, CiftiXMLOld::ALONG_COLUMN); } if (colSurfaceOpt->m_present) { MetricFile* myMetric = colSurfaceOpt->getMetric(1); myXML.addSurfaceModelToColumns(myMetric->getNumberOfNodes(), myMetric->getStructure(), myMetric->getValuePointerForColumn(0)); } if (colCiftiOpt->m_present) { AString directionName = colCiftiOpt->getString(2); int myDir; if (directionName == "ROW") { myDir = CiftiXMLOld::ALONG_ROW; } else if (directionName == "COLUMN") { myDir = CiftiXMLOld::ALONG_COLUMN; } else { throw OperationException("incorrect string for direction, use ROW or COLUMN"); } myXML.copyMapping(CiftiXMLOld::ALONG_COLUMN, colCiftiOpt->getCifti(1)->getCiftiXMLOld(), myDir); } fstream dotFile(dotFileName.toLatin1().constData(), fstream::in); if (!dotFile.good()) { throw OperationException("error opening text file '" + dotFileName + "'"); } SparseValue tempValue; vector dotFileContents; int32_t rowSize = myXML.getNumberOfColumns(), colSize = myXML.getNumberOfRows(); if (halfMatrix && rowSize != colSize) { throw OperationException("-make-symmetric was specified, but the matrix is not square"); } if (halfMatrix && transpose) { CaretLogInfo("-transpose is not needed with -make-symmetric"); } int64_t numZeros = 0; bool afterZero = false; if (transpose) { while (dotFile >> tempValue.index[1] >> tempValue.index[0] >> tempValue.value)//this is the only line that is different for transpose { if (tempValue.value == 0.0f) { if (tempValue.index[0] != rowSize || tempValue.index[1] != colSize) { throw OperationException("dimensions line in .dot file doesn't agree with provided row/column spaces"); } ++numZeros;//ignore, we expect one line (last in file) to have this } else { if (tempValue.index[0] < 1 || tempValue.index[0] > rowSize || tempValue.index[1] < 1 || tempValue.index[1] > colSize) { throw OperationException("found invalid index pair in dot file: " + AString::number(tempValue.index[0]) + ", " + AString::number(tempValue.index[1]) + ", perhaps you need to remove -transpose"); } if (numZeros != 0) afterZero = true; tempValue.index[0] -= 1;//fix for 1-indexing tempValue.index[1] -= 1; dotFileContents.push_back(tempValue); if (halfMatrix && tempValue.index[0] != tempValue.index[1]) { int32_t tempIndex = tempValue.index[0]; tempValue.index[0] = tempValue.index[1]; tempValue.index[1] = tempIndex; dotFileContents.push_back(tempValue); } } } } else { while (dotFile >> tempValue.index[0] >> tempValue.index[1] >> tempValue.value) { if (tempValue.value == 0.0f) { if (tempValue.index[0] != rowSize || tempValue.index[1] != colSize) { throw OperationException("dimensions line in .dot file doesn't agree with provided row/column spaces"); } ++numZeros; } else { if (tempValue.index[0] < 1 || tempValue.index[0] > rowSize || tempValue.index[1] < 1 || tempValue.index[1] > colSize) { throw OperationException("found invalid index pair in dot file: " + AString::number(tempValue.index[0]) + ", " + AString::number(tempValue.index[1]) + ", perhaps you need to use -transpose"); } if (numZeros != 0) afterZero = true; tempValue.index[0] -= 1;//fix for 1-indexing tempValue.index[1] -= 1; dotFileContents.push_back(tempValue); if (halfMatrix && tempValue.index[0] != tempValue.index[1]) { int32_t tempIndex = tempValue.index[0]; tempValue.index[0] = tempValue.index[1]; tempValue.index[1] = tempIndex; dotFileContents.push_back(tempValue); } } } } if (numZeros != 1) { CaretLogWarning("found (and ignored) " + AString::number(numZeros) + " lines with zero for value, expected 1"); } if (afterZero) { CaretLogWarning("found data lines after dimensionality line (which should be the last line of the file)"); } bool sorted = true; int64_t numValues = (int64_t)dotFileContents.size(); for (int64_t i = 1; i < numValues; ++i) { if (dotFileContents[i - 1].index[1] > dotFileContents[i].index[1]) { sorted = false; if (!halfMatrix) { CaretLogInfo("dot file indexes are not correctly sorted, sorting them may take a minute or so..."); } break; } } if (!sorted) sort(dotFileContents.begin(), dotFileContents.end()); if (!sorted && !halfMatrix) { CaretLogInfo("sorting finished"); } myCiftiOut->setCiftiXML(myXML); int64_t cur = 0, end = (int64_t)dotFileContents.size(); vector scratchRow(myXML.getNumberOfColumns(), 0.0f); vector checkDuplicate(myXML.getNumberOfColumns(), false); int64_t whichRow = 0;//set all rows, in case initial allocation doesn't give a zeroed matrix while (whichRow < myXML.getNumberOfRows()) { int64_t next = cur; while (next < end && dotFileContents[next].index[1] == whichRow) ++next; if (rowVoxelOpt->m_present) { for (int64_t i = cur; i < next; ++i) { int64_t outIndex = rowReorderMap[dotFileContents[i].index[0]]; if (checkDuplicate[outIndex]) { AString elemString; if (transpose) { elemString = AString::number(dotFileContents[i].index[1] + 1) + ", " + AString::number(dotFileContents[i].index[0] + 1); } else { elemString = AString::number(dotFileContents[i].index[0] + 1) + ", " + AString::number(dotFileContents[i].index[1] + 1); } if (halfMatrix) { throw OperationException("element specified more than once: " + elemString + ", perhaps you should not use -make-symmetric"); } else { throw OperationException("duplicate element found: " + elemString); } } scratchRow[outIndex] = dotFileContents[i].value; checkDuplicate[outIndex] = true; } } else { for (int64_t i = cur; i < next; ++i) { int64_t outIndex = dotFileContents[i].index[0]; if (checkDuplicate[outIndex]) { AString elemString; if (transpose) { elemString = AString::number(dotFileContents[i].index[1] + 1) + ", " + AString::number(dotFileContents[i].index[0] + 1); } else { elemString = AString::number(dotFileContents[i].index[0] + 1) + ", " + AString::number(dotFileContents[i].index[1] + 1); } if (halfMatrix) { throw OperationException("element specified more than once: " + elemString + ", perhaps you should not use -make-symmetric"); } else { throw OperationException("duplicate element found: " + elemString); } } scratchRow[outIndex] = dotFileContents[i].value; checkDuplicate[outIndex] = true; } } if (colVoxelOpt->m_present) { myCiftiOut->setRow(scratchRow.data(), colReorderMap[whichRow]); } else { myCiftiOut->setRow(scratchRow.data(), whichRow); } if (rowVoxelOpt->m_present) { for (int64_t i = cur; i < next; ++i) { int64_t outIndex = rowReorderMap[dotFileContents[i].index[0]]; scratchRow[outIndex] = 0.0f; checkDuplicate[outIndex] = false; } } else { for (int64_t i = cur; i < next; ++i) { int64_t outIndex = dotFileContents[i].index[0]; scratchRow[outIndex] = 0.0f; checkDuplicate[outIndex] = false; } } cur = next; ++whichRow; } } void OperationProbtrackXDotConvert::addVoxelMapping(const VolumeFile* myLabelVol, const AString& textFileName, CiftiXMLOld& myXML, vector& reorderMapping, const int& direction) { if (myLabelVol->getType() != SubvolumeAttributes::LABEL) { throw OperationException("specified volume for row voxels is not a label volume"); } vector myDims; myLabelVol->getDimensions(myDims); myXML.setVolumeDimsAndSForm(myDims.data(), myLabelVol->getSform()); const GiftiLabelTable* myLabelTable = myLabelVol->getMapLabelTable(0); map labelMap;//maps label values to structures vector > voxelLists;//voxel lists for each volume component vector > inputIndices;//index from the input space, matched to voxelLists map componentMap;//maps structures to indexes in voxelLists vector labelKeys; myLabelTable->getKeys(labelKeys); int64_t count = 0; for (int i = 0; i < (int)labelKeys.size(); ++i) { bool ok = false; StructureEnum::Enum thisStructure = StructureEnum::fromName(myLabelTable->getLabelName(labelKeys[i]), &ok); if (ok) { labelMap[labelKeys[i]] = thisStructure; if (componentMap.find(thisStructure) == componentMap.end())//make sure we don't already have this structure from another label { componentMap[thisStructure] = (int)count; ++count; } } } if (labelMap.empty()) { throw OperationException("label volume doesn't contain any structure labels"); } voxelLists.resize(count); inputIndices.resize(count); voxelIndexType vi, vj, vk; fstream myTextFile(textFileName.toLatin1().constData(), fstream::in); if (!myTextFile.good()) { throw OperationException("error opening text file '" + textFileName + "'"); } count = 0; while (myTextFile >> vi >> vj >> vk) { if (!myLabelVol->indexValid(vi, vj, vk)) { throw OperationException("invalid voxel index found in text file: " + AString::number(vi) + ", " + AString::number(vj) + ", " + AString::number(vk)); } int myKey = (int)floor(myLabelVol->getValue(vi, vj, vk) + 0.5f); map::const_iterator myIter = labelMap.find(myKey); if (myIter == labelMap.end()) { throw OperationException("voxel index in list file did not match a structure: " + AString::number(vi) + ", " + AString::number(vj) + ", " + AString::number(vk)); } int myListIndex = componentMap[myIter->second];//will always exist voxelLists[myListIndex].push_back(vi); voxelLists[myListIndex].push_back(vj); voxelLists[myListIndex].push_back(vk); inputIndices[myListIndex].push_back(count); ++count; } vector forwardMap; for (map::const_iterator iter = componentMap.begin(); iter != componentMap.end(); ++iter) { int i = iter->second; int64_t listSize = voxelLists[i].size(); if (listSize != 0) { forwardMap.insert(forwardMap.end(), inputIndices[i].begin(), inputIndices[i].end());//append the structure's input index list, building lookup of new index->input index if (direction == CiftiXMLOld::ALONG_ROW) { myXML.addVolumeModelToRows(voxelLists[i], iter->first); } else { myXML.addVolumeModelToColumns(voxelLists[i], iter->first); } } } int64_t reorderSize = (int64_t)forwardMap.size(); reorderMapping.resize(reorderSize); for (int i = 0; i < reorderSize; ++i) { reorderMapping[forwardMap[i]] = i;//reverse it, building lookup from input index->new index } } connectome-workbench-1.4.2/src/Operations/OperationProbtrackXDotConvert.h000066400000000000000000000032351360521144700266710ustar00rootroot00000000000000#ifndef __OPERATION_PROBTRACK_X_DOT_CONVERT_H__ #define __OPERATION_PROBTRACK_X_DOT_CONVERT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" #include namespace caret { class CiftiXMLOld; class OperationProbtrackXDotConvert : public AbstractOperation { static void addVoxelMapping(const VolumeFile* myLabelVol, const AString& textFileName, CiftiXMLOld& myXML, std::vector& reorderMapping, const int& direction); public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationProbtrackXDotConvert; } #endif //__OPERATION_PROBTRACK_X_DOT_CONVERT_H__ connectome-workbench-1.4.2/src/Operations/OperationSceneFileMerge.cxx000066400000000000000000000127241360521144700257750ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationSceneFileMerge.h" #include "OperationException.h" #include "Scene.h" #include "SceneFile.h" using namespace caret; using namespace std; AString OperationSceneFileMerge::getCommandSwitch() { return "-scene-file-merge"; } AString OperationSceneFileMerge::getShortDescription() { return "REARRANGE SCENES INTO A NEW FILE"; } OperationParameters* OperationSceneFileMerge::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "scene-file-out", "output - the output scene file");//HACK: fake the output formatting ParameterComponent* sceneFileOpt = ret->createRepeatableParameter(2, "-scene-file", "specify a scene file to use scenes from"); sceneFileOpt->addStringParameter(1, "scene-file", "the input scene file"); ParameterComponent* sceneOpt = sceneFileOpt->createRepeatableParameter(2, "-scene", "specify a scene to use"); sceneOpt->addStringParameter(1, "scene", "the scene number or name"); OptionalParameter* upToOpt = sceneOpt->createOptionalParameter(2, "-up-to", "use an inclusive range of scenes"); upToOpt->addStringParameter(1, "last-column", "the number or name of the last scene to include"); upToOpt->createOptionalParameter(2, "-reverse", "use the range in reverse order"); ret->setHelpText( AString("Takes one or more scene files and constructs a new scene file by concatenating specified scenes from them.\n\n") + "Example: wb_command -scene-file-merge out.scene -scene-file first.scene -scene 1 -scene-file second.scene\n\n" + "This example would take the first scene from first.scene, followed by all scenes from second.scene, and write these scenes to out.scene." ); return ret; } void OperationSceneFileMerge::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); SceneFile outSceneFile; const vector& myInputs = *(myParams->getRepeatableParameterInstances(2)); int numInputs = (int)myInputs.size(); if (numInputs == 0) throw OperationException("no inputs specified"); for (int i = 0; i < numInputs; ++i) { ParameterComponent* thisInput = myInputs[i]; SceneFile inputScene; inputScene.readFile(thisInput->getString(1)); const vector& selectOpts = *(thisInput->getRepeatableParameterInstances(2)); int numSelect = (int)selectOpts.size(); if (numSelect > 0) { for (int j = 0; j < numSelect; ++j) { ParameterComponent* thisSelect = selectOpts[j]; int firstInd = inputScene.getSceneIndexFromNumberOrName(thisSelect->getString(1)); if (firstInd < 0) { throw OperationException("scene '" + thisSelect->getString(1) + "' not found in file '" + thisInput->getString(1) + "'"); } OptionalParameter* upToOpt = thisSelect->getOptionalParameter(2); if (upToOpt->m_present) { int lastInd = inputScene.getSceneIndexFromNumberOrName(upToOpt->getString(1)); if (lastInd < 0) { throw OperationException("scene '" + upToOpt->getString(1) + "' not found in file '" + thisInput->getString(1) + "'"); } if (lastInd < firstInd) { throw OperationException("ending scene '" + upToOpt->getString(1) + "' occurs before starting scene '" + thisSelect->getString(1) + "'"); } if (upToOpt->getOptionalParameter(2)->m_present)//reverse { for (int s = lastInd; s >= firstInd; --s) { outSceneFile.addScene(new Scene(*inputScene.getSceneAtIndex(s))); } } else { for (int s = firstInd; s <= lastInd; ++s) { outSceneFile.addScene(new Scene(*inputScene.getSceneAtIndex(s))); } } } else { outSceneFile.addScene(new Scene(*inputScene.getSceneAtIndex(firstInd))); } } } else {//no select options means select all in order int numScenes = inputScene.getNumberOfScenes(); for (int s = 0; s < numScenes; ++s) { outSceneFile.addScene(new Scene(*inputScene.getSceneAtIndex(s))); } } } outSceneFile.writeFile(myParams->getString(1)); } connectome-workbench-1.4.2/src/Operations/OperationSceneFileMerge.h000066400000000000000000000026301360521144700254150ustar00rootroot00000000000000#ifndef __OPERATION_SCENE_FILE_MERGE_H__ #define __OPERATION_SCENE_FILE_MERGE_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationSceneFileMerge : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationSceneFileMerge; } #endif //__OPERATION_SCENE_FILE_MERGE_H__ connectome-workbench-1.4.2/src/Operations/OperationSceneFileRelocate.cxx000066400000000000000000000041341360521144700264700ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationSceneFileRelocate.h" #include "OperationException.h" #include "SceneFile.h" using namespace caret; using namespace std; AString OperationSceneFileRelocate::getCommandSwitch() { return "-scene-file-relocate"; } AString OperationSceneFileRelocate::getShortDescription() { return "RECREATE SCENE FILE IN NEW LOCATION"; } OperationParameters* OperationSceneFileRelocate::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "input-scene", "the scene file to use"); ret->addStringParameter(2, "output-scene", "output - the new scene file to create");//fake the output formatting ret->setHelpText( AString("Scene files contain internal relative paths, such that moving or copying a scene file will cause it to lose track of the files it refers to. ") + "This command makes a modified copy of the scene file, changing the relative paths to refer to the new relative locations of the files." ); return ret; } void OperationSceneFileRelocate::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); SceneFile myScene; myScene.readFile(myParams->getString(1)); myScene.writeFile(myParams->getString(2)); } connectome-workbench-1.4.2/src/Operations/OperationSceneFileRelocate.h000066400000000000000000000026521360521144700261200ustar00rootroot00000000000000#ifndef __OPERATION_SCENE_FILE_RELOCATE_H__ #define __OPERATION_SCENE_FILE_RELOCATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationSceneFileRelocate : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationSceneFileRelocate; } #endif //__OPERATION_SCENE_FILE_RELOCATE_H__ connectome-workbench-1.4.2/src/Operations/OperationSetMapName.cxx000066400000000000000000000115511360521144700251470ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationSetMapName.h" #include "OperationException.h" #include "DataFileTypeEnum.h" #include "CiftiFile.h" #include "LabelFile.h" #include "MetricFile.h" #include "VolumeFile.h" #include using namespace caret; using namespace std; AString OperationSetMapName::getCommandSwitch() { return "-set-map-name"; } AString OperationSetMapName::getShortDescription() { return "DEPRECATED: use -set-map-names"; } OperationParameters* OperationSetMapName::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "data-file", "the file to set a map name of"); ret->addIntegerParameter(2, "index", "the map index to set the name of"); ret->addStringParameter(3, "name", "the name to set for the map"); ret->setHelpText( AString("DEPRECATED: this command may be removed in a future release, use -set-map-names.\n\n") + "Sets the name of a map for metric, shape, label, volume, cifti scalar or cifti label files." ); return ret; } void OperationSetMapName::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString fileName = myParams->getString(1); int mapIndex = (int)myParams->getInteger(2) - 1; if (mapIndex < 0) throw OperationException("invalid map index specified, indexes are 1-based"); AString mapName = myParams->getString(3); bool ok = false; DataFileTypeEnum::Enum myType = DataFileTypeEnum::fromFileExtension(fileName, &ok); if (!ok) { throw OperationException("unrecognized data file type"); } switch (myType) { case DataFileTypeEnum::METRIC: { MetricFile myMetric; myMetric.readFile(fileName); if (mapIndex >= myMetric.getNumberOfMaps()) throw OperationException("metric file doesn't have enough columns for specified map index"); myMetric.setMapName(mapIndex, mapName); myMetric.writeFile(fileName); break; } case DataFileTypeEnum::LABEL: { LabelFile myLabel; myLabel.readFile(fileName); if (mapIndex >= myLabel.getNumberOfMaps()) throw OperationException("label file doesn't have enough columns for specified map index"); myLabel.setMapName(mapIndex, mapName); myLabel.writeFile(fileName); break; } case DataFileTypeEnum::VOLUME: { VolumeFile myVol; myVol.readFile(fileName); if (mapIndex >= myVol.getNumberOfMaps()) throw OperationException("volume file doesn't have enough subvolumes for specified map index"); myVol.setMapName(mapIndex, mapName); myVol.writeFile(fileName); break; } case DataFileTypeEnum::CONNECTIVITY_DENSE_SCALAR: case DataFileTypeEnum::CONNECTIVITY_DENSE_TIME_SERIES: case DataFileTypeEnum::CONNECTIVITY_DENSE_LABEL: { CiftiFile myCifti; myCifti.openFile(fileName); myCifti.convertToInMemory(); CiftiXMLOld myXML = myCifti.getCiftiXMLOld(); if (mapIndex >= myXML.getNumberOfColumns()) throw OperationException("cifti file doesn't have enough columns for specified map index"); if (!myXML.setMapNameForIndex(CiftiXMLOld::ALONG_ROW, mapIndex, mapName)) throw OperationException("failed to set map name, check the type of the cifti file"); CiftiFile myOutCifti; myOutCifti.setWritingFile(fileName); myOutCifti.setCiftiXML(myXML); int numRows = myXML.getNumberOfRows(), rowSize = myXML.getNumberOfColumns(); vector scratchRow(rowSize); for (int i = 0; i < numRows; ++i) { myCifti.getRow(scratchRow.data(), i); myOutCifti.setRow(scratchRow.data(), i); } myOutCifti.writeFile(fileName); break; } default: throw OperationException("cannot set map name on this file type"); } } connectome-workbench-1.4.2/src/Operations/OperationSetMapName.h000066400000000000000000000026001360521144700245670ustar00rootroot00000000000000#ifndef __OPERATION_SET_MAP_NAME_H__ #define __OPERATION_SET_MAP_NAME_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationSetMapName : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationSetMapName; } #endif //__OPERATION_SET_MAP_NAME_H__ connectome-workbench-1.4.2/src/Operations/OperationSetMapNames.cxx000066400000000000000000000116151360521144700253330ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationSetMapNames.h" #include "OperationException.h" #include "CaretDataFile.h" #include "CaretDataFileHelper.h" #include "CaretMappableDataFile.h" #include "CaretPointer.h" #include "CaretLogger.h" #include #include using namespace caret; using namespace std; AString OperationSetMapNames::getCommandSwitch() { return "-set-map-names"; } AString OperationSetMapNames::getShortDescription() { return "SET THE NAME OF ONE OR MORE MAPS IN A FILE"; } OperationParameters* OperationSetMapNames::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "data-file", "the file to set the map names of"); OptionalParameter* fileOpt = ret->createOptionalParameter(2, "-name-file", "use a text file to replace all map names"); fileOpt->addStringParameter(1, "file", "text file containing map names, one per line"); ParameterComponent* mapOpt = ret->createRepeatableParameter(3, "-map", "specify a map to set the name of"); mapOpt->addIntegerParameter(1, "index", "the map index to change the name of"); mapOpt->addStringParameter(2, "new-name", "the name to set for the map"); ret->setHelpText( AString("Sets the name of one or more maps for metric, shape, label, volume, cifti scalar or cifti label files. ") + "If the -name-file option is not specified, the -map option must be specified at least once. " + "The -map option cannot be used when -name-file is specified." ); return ret; } void OperationSetMapNames::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString fileName = myParams->getString(1); OptionalParameter* fileOpt = myParams->getOptionalParameter(2); const vector& mapOpts = *(myParams->getRepeatableParameterInstances(3)); CaretPointer caretDataFile(CaretDataFileHelper::readAnyCaretDataFile(fileName)); CaretMappableDataFile* mappableFile = dynamic_cast(caretDataFile.getPointer()); if (mappableFile == NULL) throw OperationException("cannot set map names on this file type"); if (fileOpt->m_present) { if (!mapOpts.empty()) throw OperationException("-map may not be specified when using -name-file"); AString listfileName = fileOpt->getString(1); ifstream nameListFile(listfileName.toLocal8Bit().constData()); if (!nameListFile.good()) { throw OperationException("error reading name list file"); } string mapName; int numMaps = mappableFile->getNumberOfMaps(); for (int i = 0; i < numMaps; ++i) { getline(nameListFile, mapName); if (!nameListFile) { throw OperationException("name file contained " + AString::number(i) + " names, expected " + AString::number(numMaps)); break; } mappableFile->setMapName(i, mapName.c_str()); } if (getline(nameListFile, mapName) && mapName != "") {//accept a blank line as not being another name throw OperationException("name file contains more names than can be used on the file"); } if (getline(nameListFile, mapName)) {//don't accept two or more additional lines, period throw OperationException("name file contains more names than can be used on the file"); } } else { if (mapOpts.empty()) throw OperationException("you must specify at least one option that sets a map name"); for (int i = 0; i < (int)mapOpts.size(); ++i) { int mapIndex = (int)mapOpts[i]->getInteger(1) - 1; if (mapIndex < 0) throw OperationException("invalid map index, indices are 1-based"); if (mapIndex >= mappableFile->getNumberOfMaps()) throw OperationException("invalid map index, file doesn't have enough maps"); AString newName = mapOpts[i]->getString(2); mappableFile->setMapName(mapIndex, newName); } } mappableFile->writeFile(fileName); } connectome-workbench-1.4.2/src/Operations/OperationSetMapNames.h000066400000000000000000000026061360521144700247600ustar00rootroot00000000000000#ifndef __OPERATION_SET_MAP_NAMES_H__ #define __OPERATION_SET_MAP_NAMES_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationSetMapNames : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationSetMapNames; } #endif //__OPERATION_SET_MAP_NAMES_H__ connectome-workbench-1.4.2/src/Operations/OperationSetStructure.cxx000066400000000000000000000154341360521144700256350ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationSetStructure.h" #include "OperationException.h" #include "BorderFile.h" #include "CaretLogger.h" #include "DataFileTypeEnum.h" #include "LabelFile.h" #include "MetricFile.h" #include "StructureEnum.h" #include "SurfaceFile.h" using namespace caret; using namespace std; AString OperationSetStructure::getCommandSwitch() { return "-set-structure"; } AString OperationSetStructure::getShortDescription() { return "SET STRUCTURE OF A DATA FILE"; } OperationParameters* OperationSetStructure::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "data-file", "the file to set the structure of"); ret->addStringParameter(2, "structure", "the structure to set the file to"); OptionalParameter* surfType = ret->createOptionalParameter(3, "-surface-type", "set the type of a surface (only used if file is a surface file)"); surfType->addStringParameter(1, "type", "name of surface type"); OptionalParameter* secondaryType = ret->createOptionalParameter(4, "-surface-secondary-type", "set the secondary type of a surface (only used if file is a surface file)"); secondaryType->addStringParameter(1, "secondary type", "name of surface secondary type"); AString myText = AString("The existing file is modified and rewritten to the same filename. Valid values for the structure name are:\n\n"); vector myStructureEnums; StructureEnum::getAllEnums(myStructureEnums); for (int i = 0; i < (int)myStructureEnums.size(); ++i) { myText += StructureEnum::toName(myStructureEnums[i]) + "\n"; } myText += "\nValid names for the surface type are:\n\n"; vector mySurfTypeEnums; SurfaceTypeEnum::getAllEnums(mySurfTypeEnums); for (int i = 0; i < (int)mySurfTypeEnums.size(); ++i) { myText += SurfaceTypeEnum::toName(mySurfTypeEnums[i]) + "\n"; } myText += "\nValid names for the surface secondary type are:\n\n"; vector mySecondaryTypeEnums; SecondarySurfaceTypeEnum::getAllEnums(mySecondaryTypeEnums); for (int i = 0; i < (int)mySecondaryTypeEnums.size(); ++i) { myText += SecondarySurfaceTypeEnum::toName(mySecondaryTypeEnums[i]) + "\n"; } ret->setHelpText(myText); return ret; } void OperationSetStructure::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString fileName = myParams->getString(1); AString structureName = myParams->getString(2); OptionalParameter* surfType = myParams->getOptionalParameter(3); OptionalParameter* secondaryType = myParams->getOptionalParameter(4); bool ok = false; SurfaceTypeEnum::Enum mySurfType = SurfaceTypeEnum::UNKNOWN;//so compilers won't complain about uninitialized if (surfType->m_present) { AString mySurfTypeName = surfType->getString(1); mySurfType = SurfaceTypeEnum::fromName(mySurfTypeName, &ok); if (!ok) { throw OperationException("unrecognized surface type"); } } SecondarySurfaceTypeEnum::Enum mySecondType = SecondarySurfaceTypeEnum::INVALID; if (secondaryType->m_present) { AString mySecondaryName = secondaryType->getString(1); mySecondType = SecondarySurfaceTypeEnum::fromName(mySecondaryName, &ok); if (!ok) { throw OperationException("unrecognized secondary surface type"); } } StructureEnum::Enum myStructure = StructureEnum::fromName(structureName, &ok); if (!ok) { throw OperationException("unrecognized structure type"); } DataFileTypeEnum::Enum myType = DataFileTypeEnum::fromFileExtension(fileName, &ok); if (!ok) { throw OperationException("unrecognized data file type"); } switch (myType) { case DataFileTypeEnum::SURFACE: { SurfaceFile mySurf; mySurf.readFile(fileName); mySurf.setStructure(myStructure); if (surfType->m_present) { mySurf.setSurfaceType(mySurfType); } if (secondaryType->m_present) { mySurf.setSecondaryType(mySecondType); } mySurf.writeFile(fileName); } break; case DataFileTypeEnum::LABEL: { if (surfType->m_present) CaretLogInfo("the -surface-type option is ignored with this file type"); if (secondaryType->m_present) CaretLogInfo("the -surface-secondary-type option is ignored with this file type"); LabelFile myLabel; myLabel.readFile(fileName); myLabel.setStructure(myStructure); myLabel.writeFile(fileName); } break; case DataFileTypeEnum::METRIC: { if (surfType->m_present) CaretLogInfo("the -surface-type option is ignored with this file type"); if (secondaryType->m_present) CaretLogInfo("the -surface-secondary-type option is ignored with this file type"); MetricFile myMetric; myMetric.readFile(fileName); myMetric.setStructure(myStructure); myMetric.writeFile(fileName); } break; case DataFileTypeEnum::BORDER: { if (surfType->m_present) CaretLogInfo("the -surface-type option is ignored with this file type"); if (secondaryType->m_present) CaretLogInfo("the -surface-secondary-type option is ignored with this file type"); BorderFile myBorder; myBorder.readFile(fileName); myBorder.setStructure(myStructure); myBorder.writeFile(fileName); } break; default: throw OperationException("cannot set the structure of this file type"); }; } connectome-workbench-1.4.2/src/Operations/OperationSetStructure.h000066400000000000000000000026111360521144700252530ustar00rootroot00000000000000#ifndef __OPERATION_SET_STRUCTURE_H__ #define __OPERATION_SET_STRUCTURE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationSetStructure : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationSetStructure; } #endif //__OPERATION_SET_STRUCTURE_H__ connectome-workbench-1.4.2/src/Operations/OperationShowScene.cxx000066400000000000000000001022451360521144700250540ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #ifdef HAVE_GLEW #include #endif #ifdef HAVE_OSMESA #include #endif // HAVE_OSMESA #include #include #include "Brain.h" #include "BrainOpenGLFixedPipeline.h" #include "BrainOpenGLViewportContent.h" #include "BrainOpenGLWindowContent.h" #include "BrowserWindowContent.h" #include "CaretAssert.h" #include "CaretPreferences.h" #include "CaretLogger.h" #include "DataFileException.h" #include "EventBrowserTabGet.h" #include "EventBrowserWindowContent.h" #include "EventMapYokingSelectMap.h" #include "EventManager.h" #include "FileInformation.h" #include "DummyFontTextRenderer.h" #include "FtglFontTextRenderer.h" #include "ImageFile.h" #include "MapYokingGroupEnum.h" #include "OperationShowScene.h" #include "OperationException.h" #include "Scene.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneFile.h" #include "ScenePrimitiveArray.h" #include "SessionManager.h" #include "TileTabsConfiguration.h" #include "VolumeFile.h" //#include "workbench_png.h" using namespace caret; /** * \class caret::OperationShowScene * \brief Offscreen rendering of scene to an image file * * Render a scene into an image file using the Offscreen Mesa Library */ /** * @return Command line switch */ AString OperationShowScene::getCommandSwitch() { return "-show-scene"; } /** * @return Short description of operation */ AString OperationShowScene::getShortDescription() { return ("OFFSCREEN RENDERING OF SCENE TO AN IMAGE FILE"); } /** * @return Parameters for operation */ OperationParameters* OperationShowScene::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "scene-file", "scene file"); ret->addStringParameter(2, "scene-name-or-number", "name or number (starting at one) of the scene in the scene file"); ret->addStringParameter(3, "image-file-name", "output image file name"); ret->addIntegerParameter(4, "image-width", "width of output image(s), in pixels"); ret->addIntegerParameter(5, "image-height", "height of output image(s), in pixels"); const QString windowSizeSwitch("-use-window-size"); ret->createOptionalParameter(6, windowSizeSwitch, "Override image size with window size"); ret->createOptionalParameter(7, "-no-scene-colors", "Do not use background and foreground colors in scene"); OptionalParameter* mapYokeOpt = ret->createOptionalParameter(8, "-set-map-yoke", "Override selected map index for a map yoking group."); mapYokeOpt->addStringParameter(1, "Map Yoking Roman Numeral", "Roman numeral identifying the map yoking group (I, II, III, IV, V, VI, VII, VIII, IX, X)"); mapYokeOpt->addIntegerParameter(2, "Map Index", "Map index for yoking group. Indices start at 1 (one)"); OptionalParameter* connDbOpt = ret->createOptionalParameter(9, "-conn-db-login", "Login for scenes with files in Connectome Database"); connDbOpt->addStringParameter(1, "Username", "Connectome DB Username"); connDbOpt->addStringParameter(2, "Password", "Connectome DB Password"); AString helpText("Render content of browser windows displayed in a scene " "into image file(s). The image file name should be " "similar to \"capture.png\". If there is only one image " "to render, the image name will not change. If there is " "more than one image to render, an index will be inserted " "into the image name: \"capture_01.png\", \"capture_02.png\" " "etc.\n" "\n" "If the scene references files in the Connectome Database,\n" "the \"-conn-db-login\" option is available for providing the \n" "username and password. If this options is not specified, \n" "the username and password stored in the user's preferences\n" "is used.\n" "\n" "The image format is determined by the image file extension.\n" "The available image formats may vary by operating system.\n" "Image formats available on this system are:\n" ); std::vector imageFileExtensions; AString defaultExtension; ImageFile::getImageFileExtensions(imageFileExtensions, defaultExtension); for (std::vector::iterator iter = imageFileExtensions.begin(); iter != imageFileExtensions.end(); iter++) { const AString ext = *iter; helpText += (" " + ext + "\n"); } helpText += ("\n" "The result of using the \"" + windowSizeSwitch + "\" option\n" "is dependent upon the version used to create the scene.\n" " * Versions 1.2 and newer contain the width and \n" " height of the graphics region. The output image \n" " will be the width and height from the scene and\n" " the image width and height specified on the command\n" " line is ignored.\n" " * If the scene does not contain the width and height\n" " of the graphics region, the width and height specified\n" " on the command line is used for the size of the \n" " output image.\n" ); ret->setHelpText(helpText); return ret; } /** * Use Parameters and perform operation */ #ifndef HAVE_OSMESA void OperationShowScene::useParameters(OperationParameters* /*myParams*/, ProgressObject* /*myProgObj*/) { throw OperationException("Show scene command not available due to this software version " "not being built with the Mesa OffScreen Library"); } #else // HAVE_OSMESA void OperationShowScene::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString sceneFileName = FileInformation(myParams->getString(1)).getAbsoluteFilePath(); AString sceneNameOrNumber = myParams->getString(2); AString imageFileName = FileInformation(myParams->getString(3)).getAbsoluteFilePath(); const int32_t userImageWidth = myParams->getInteger(4); const int32_t userImageHeight = myParams->getInteger(5); OptionalParameter* useWindowSizeParam = myParams->getOptionalParameter(6); const bool useWindowSizeForImageSizeFlag = useWindowSizeParam->m_present; const bool doNotUseSceneColorsFlag = myParams->getOptionalParameter(7)->m_present; MapYokingGroupEnum::Enum mapYokingGroup = MapYokingGroupEnum::MAP_YOKING_GROUP_OFF; int32_t mapYokingMapIndex = -1; OptionalParameter* mapYokeOpt = myParams->getOptionalParameter(8); if (mapYokeOpt->m_present) { const AString romanNumeral = mapYokeOpt->getString(1); bool validFlag = false; mapYokingGroup = MapYokingGroupEnum::fromGuiName(romanNumeral, &validFlag); if ( ! validFlag) { throw OperationException(romanNumeral + " does not identify a valid Map Yoking Group. "); } mapYokingMapIndex = mapYokeOpt->getInteger(2); if (mapYokingMapIndex < 1) { throw OperationException("Map yoking map index must be one or greater."); } /* * Map indice in code start at zero */ mapYokingMapIndex--; } if ( ! useWindowSizeForImageSizeFlag) { if ((userImageWidth <= 0) || (userImageHeight <= 0)) { throw OperationException("Invalid image size width=" + QString::number(userImageWidth) + " height=" + QString::number(userImageHeight)); } } /* * Need to set username/password for files in ConnectomeDB */ AString username; AString password; OptionalParameter* connDbOpt = myParams->getOptionalParameter(9); if (connDbOpt->m_present) { username = connDbOpt->getString(1); password = connDbOpt->getString(2); } else { CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); prefs->getRemoteFileUserNameAndPassword(username, password); } CaretDataFile::setFileReadingUsernameAndPassword(username, password); /* * Read the scene file and load the scene */ SceneFile sceneFile; sceneFile.readFile(sceneFileName); Scene* scene = sceneFile.getSceneWithName(sceneNameOrNumber); if (scene == NULL) { bool valid = false; const int32_t sceneIndexStartAtOne = sceneNameOrNumber.toInt(&valid); if (valid) { const int32_t sceneIndex = sceneIndexStartAtOne - 1; if ((sceneIndex >= 0) && (sceneIndex < sceneFile.getNumberOfScenes())) { scene = sceneFile.getSceneAtIndex(sceneIndex); } else { throw OperationException("Scene index is invalid"); } } else { throw OperationException("Scene name is invalid"); } } /* * Enable voxel coloring since it is defaulted off for commands */ VolumeFile::setVoxelColoringEnabled(true); SceneAttributes sceneAttributes(SceneTypeEnum::SCENE_TYPE_FULL, scene); if (doNotUseSceneColorsFlag) { sceneAttributes.setUseSceneForegroundAndBackgroundColors(false); } /* * Restore the scene */ const SceneClass* guiManagerClass = scene->getClassWithName("guiManager"); if (guiManagerClass->getName() != "guiManager") { throw OperationException("Top level scene class should be guiManager but it is: " + guiManagerClass->getName()); } SessionManager* sessionManager = SessionManager::get(); sessionManager->restoreFromScene(&sceneAttributes, guiManagerClass->getClass("m_sessionManager")); /* * Get the error message but continue processing since the error * may not affect the scene. Print error message later. */ const AString sceneErrorMessage = sceneAttributes.getErrorMessage(); if (sessionManager->getNumberOfBrains() <= 0) { throw OperationException("Scene loading failure, SessionManager contains no Brains"); } Brain* brain = SessionManager::get()->getBrain(0); const GapsAndMargins* gapsAndMargins = brain->getGapsAndMargins(); bool missingWindowMessageHasBeenDisplayed = false; /* * Apply map yoking */ if (mapYokingGroup != MapYokingGroupEnum::MAP_YOKING_GROUP_OFF) { MapYokingGroupEnum::setSelectedMapIndex(mapYokingGroup, mapYokingMapIndex); EventMapYokingSelectMap yokeEvent(mapYokingGroup, NULL, NULL, mapYokingMapIndex, true); EventManager::get()->sendEvent(yokeEvent.getPointer()); } std::vector allBrowserWindowContent; for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS; i++) { std::unique_ptr browserContentEvent = EventBrowserWindowContent::getWindowContent(i); EventManager::get()->sendEvent(browserContentEvent->getPointer()); BrowserWindowContent* bwc = browserContentEvent->getBrowserWindowContent(); CaretAssert(bwc); if (bwc->isValid()) { allBrowserWindowContent.push_back(bwc); } } const int32_t numberOfWindows = static_cast(allBrowserWindowContent.size()); if (numberOfWindows <= 0) { throw OperationException("No BrowserWindowContent was found for showing as scene"); } /* * Restore windows */ for (int32_t iWindow = 0; iWindow < numberOfWindows; iWindow++) { CaretAssertVectorIndex(allBrowserWindowContent, iWindow); auto bwc = allBrowserWindowContent[iWindow]; const bool restoreToTabTiles = bwc->isTileTabsEnabled(); const int32_t windowIndex = bwc->getWindowIndex(); int32_t imageWidth = userImageWidth; int32_t imageHeight = userImageHeight; if (useWindowSizeForImageSizeFlag) { /* * Requires version AFTER 1.2.0-pre1 */ const float geomWidth = bwc->getSceneGraphicsWidth(); const float geomHeight = bwc->getSceneGraphicsHeight(); if ((geomWidth > 0) && (geomHeight > 0)) { imageWidth = geomWidth; imageHeight = geomHeight; } else { if ((imageWidth <= 0) || (imageHeight <= 0)) { const QString msg("Option " + useWindowSizeParam->m_optionSwitch + " is used but window size not found in scene and width=" + QString::number(imageWidth) + " height=" + QString::number(imageWidth) + " on command line is invalid."); throw OperationException(msg); } if ( ! missingWindowMessageHasBeenDisplayed) { const QString msg("Option \"" + useWindowSizeParam->m_optionSwitch + "\" is used but window size not found in scene.\n" " Scene was created prior to implementation of this option.\n" " Image size will be width=" + QString::number(imageWidth) + " and height=" + QString::number(imageHeight) + " as specified on command line.\n" " Recreating the scene will allow use of the option.\n"); CaretLogWarning(msg); /* * Avoid message being displayed more than once when * there are more than one windows. */ missingWindowMessageHasBeenDisplayed = true; } } } if ((imageWidth <= 0) || (imageHeight <= 0)) { throw OperationException("Invalid image size width=" + QString::number(imageWidth) + " height=" + QString::number(imageHeight)); } int windowViewport[4] = { 0, 0, imageWidth, imageHeight }; const int windowWidth = windowViewport[2]; const int windowHeight = windowViewport[3]; // // Create the Mesa Context // const int depthBits = 16; const int stencilBits = 0; const int accumBits = 0; OSMesaContext mesaContext = OSMesaCreateContextExt(OSMESA_RGBA, depthBits, stencilBits, accumBits, NULL); if (mesaContext == 0) { throw ("Creating Mesa Context failed."); } // // Allocate image buffer // const int32_t imageBufferSize =imageWidth * imageHeight * 4 * sizeof(unsigned char); unsigned char* imageBuffer = new unsigned char[imageBufferSize]; if (imageBuffer == 0) { throw OperationException("Allocating image buffer size=" + QString::number(imageBufferSize) + " failed."); } // // Assign buffer to Mesa Context and make current // if (OSMesaMakeCurrent(mesaContext, imageBuffer, GL_UNSIGNED_BYTE, imageWidth, imageHeight) == 0) { throw OperationException("Assigning buffer to context and make current failed."); } /* * If tile tabs was saved to the scene, restore it as the scenes tile tabs configuration */ if (restoreToTabTiles) { CaretPointer brainOpenGL(createBrainOpenGL()); TileTabsConfiguration* tileTabsConfiguration = bwc->getSelectedTileTabsConfiguration(); CaretAssert(tileTabsConfiguration); const std::vector tabIndices = bwc->getSceneTabIndices(); if ( ! tabIndices.empty()) { std::vector allTabContent; const int32_t numTabs = static_cast(tabIndices.size()); for (int32_t iTab = 0; iTab < numTabs; iTab++) { CaretAssertVectorIndex(tabIndices, iTab); const int32_t tabIndex = tabIndices[iTab]; EventBrowserTabGet getTabContent(tabIndex); EventManager::get()->sendEvent(getTabContent.getPointer()); BrowserTabContent* tabContent = getTabContent.getBrowserTab(); if (tabContent == NULL) { throw OperationException("Failed to obtain tab number " + AString::number(tabIndex + 1) + " for window " + AString::number(windowIndex + 1)); } allTabContent.push_back(tabContent); } const int32_t numTabContent = static_cast(allTabContent.size()); if (numTabContent <= 0) { throw OperationException("Failed to find any tab content"); } std::vector rowHeights; std::vector columnWidths; if ( ! tileTabsConfiguration->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, windowHeight, numTabContent, bwc->getTileTabsConfigurationMode(), rowHeights, columnWidths)) { throw OperationException("Tile Tabs Row/Column sizing failed !!!"); } const int32_t tabIndexToHighlight = -1; std::vector viewports = BrainOpenGLViewportContent::createViewportContentForTileTabs(allTabContent, bwc, gapsAndMargins, windowViewport, windowIndex, tabIndexToHighlight); std::vector constViewports(viewports.begin(), viewports.end()); brainOpenGL->drawModels(windowIndex, UserInputModeEnum::VIEW, brain, mesaContext, constViewports); const int32_t outputImageIndex = ((numberOfWindows > 1) ? iWindow : -1); writeImage(imageFileName, outputImageIndex, imageBuffer, imageWidth, imageHeight); for (std::vector::iterator vpIter = viewports.begin(); vpIter != viewports.end(); vpIter++) { delete *vpIter; } viewports.clear(); } } else { CaretPointer brainOpenGL(createBrainOpenGL()); const int32_t selectedTabIndex = bwc->getSceneSelectedTabIndex(); EventBrowserTabGet getTabContent(selectedTabIndex); EventManager::get()->sendEvent(getTabContent.getPointer()); BrowserTabContent* tabContent = getTabContent.getBrowserTab(); if (tabContent == NULL) { throw OperationException("Failed to obtain tab number " + AString::number(selectedTabIndex + 1) + " for window " + AString::number(iWindow + 1)); } CaretPointer content(NULL); std::vector allTabs; allTabs.push_back(tabContent); content.grabNew(BrainOpenGLViewportContent::createViewportForSingleTab(allTabs, tabContent, gapsAndMargins, windowIndex, windowViewport)); std::vector viewportContents; viewportContents.push_back(content); brainOpenGL->drawModels(windowIndex, UserInputModeEnum::VIEW, brain, mesaContext, viewportContents); const int32_t outputImageIndex = ((numberOfWindows > 1) ? iWindow : -1); writeImage(imageFileName, outputImageIndex, imageBuffer, imageWidth, imageHeight); } /* * Free image memory and Mesa context */ delete[] imageBuffer; OSMesaDestroyContext(mesaContext); } /* * Print error messages */ if ( ! sceneErrorMessage.isEmpty()) { std::cerr << "ERRORS loading scene, output image may be incorrect." << std::endl; std::cerr << sceneErrorMessage << std::endl; } } /** * Estimate the size of the graphics region from scenes that lack * an explicit entry for the graphics region size. Scenes in version * 1.2.0-pre1 did not contain graphics window size. * * @param windowSceneClass * Scene class for the window. * @param estimatedWidthOut * Estimated width of graphics region (greater than zero if valid). * @param estimatedHeightOut * Estimated height of graphics region (greater than zero if valid). */ void OperationShowScene::estimateGraphicsSize(const SceneClass* windowSceneClass, float& estimatedWidthOut, float& estimatedHeightOut) { estimatedWidthOut = 0; estimatedHeightOut = 0; float winWidth = -1.0; float winHeight = -1.0; const SceneClass* winGeometry = windowSceneClass->getClass("geometry"); if (winGeometry != NULL) { winWidth = winGeometry->getIntegerValue("geometryWidth", -1); winHeight = winGeometry->getIntegerValue("geometryHeight", -1); } else { return; } float tbHeight = -1.0; bool tbHeightValid = false; const SceneClass* tb = windowSceneClass->getClass("m_toolbar"); if (tb != NULL) { if (tb->getBooleanValue("toolBarVisible")) { tbHeight = 165.0; tbHeightValid = true; } } if ( ! tbHeightValid) { return; } float overlayToolBoxWidth = 0; float overlayToolBoxHeight = 0; QString overlayToolBoxOrientation; bool overlayToolBoxValid = getToolBoxSize(windowSceneClass->getClass("overlayToolBox"), windowSceneClass->getClass("m_overlayActiveToolBox"), overlayToolBoxWidth, overlayToolBoxHeight, overlayToolBoxOrientation); float featureToolBoxWidth = 0; float featureToolBoxHeight = 0; QString featureToolBoxOrientation; bool featureToolBoxValid = getToolBoxSize(windowSceneClass->getClass("featureToolBox"), windowSceneClass->getClass("m_featuresToolBox"), featureToolBoxWidth, featureToolBoxHeight, featureToolBoxOrientation); if (overlayToolBoxValid && featureToolBoxValid) { estimatedWidthOut = winWidth - overlayToolBoxWidth - featureToolBoxWidth; estimatedHeightOut = winHeight - tbHeight - overlayToolBoxHeight - featureToolBoxHeight; } } /** * Get the size of a toolbox. * * @param toolBoxClass * The toolbox scene class. * @param overlayToolBoxWidthOut * Output with width of toolbox. * @param overlayToolBoxHeightOut * Output with height of toolbox. * @param overlayToolBoxOrientationOut * Output with orientation of toolbox. * @return * True if the toolbox outputs are valid, else false. */ bool OperationShowScene::getToolBoxSize(const SceneClass* toolBoxClass, const SceneClass* activeToolBoxClass, float& overlayToolBoxWidthOut, float& overlayToolBoxHeightOut, QString& overlayToolBoxOrientationOut) { if (toolBoxClass == NULL) { return false; } if (activeToolBoxClass == NULL) { return false; } overlayToolBoxWidthOut = 0; overlayToolBoxHeightOut = 0; bool overlayToolBoxValid = false; if (toolBoxClass != NULL) { overlayToolBoxValid = true; if (toolBoxClass->getBooleanValue("visible")) { overlayToolBoxValid = false; if ( ! toolBoxClass->getBooleanValue("floating")) { overlayToolBoxOrientationOut = toolBoxClass->getStringValue("orientation"); overlayToolBoxWidthOut = activeToolBoxClass->getIntegerValue("toolboxWidth"); overlayToolBoxHeightOut = activeToolBoxClass->getIntegerValue("toolboxHeight"); if ((overlayToolBoxWidthOut > 0) && (overlayToolBoxHeightOut > 0)) { if (overlayToolBoxOrientationOut == "horizontal") { /* * Toolbar is on bottom so only need height */ overlayToolBoxWidthOut = 0; overlayToolBoxValid = true; } else if (overlayToolBoxOrientationOut == "vertical") { /* * Toolbar is on left side so only need width */ overlayToolBoxHeightOut = 0; overlayToolBoxValid = true; } } } } } return overlayToolBoxValid; } /** * Create OpenGL Rendering. * * @return * BrainOpenGL. */ BrainOpenGLFixedPipeline* OperationShowScene::createBrainOpenGL() { /* * The OpenGL rendering takes ownership of the text renderer * and will delete the text renderer when OpenGL itself * is deleted. */ BrainOpenGLTextRenderInterface* textRenderer = NULL; if (textRenderer == NULL) { #ifdef HAVE_FREETYPE textRenderer = new FtglFontTextRenderer(); if (! textRenderer->isValid()) { delete textRenderer; textRenderer = NULL; CaretLogWarning("Unable to create FTGL Font Renderer.\n" "No text will be available in graphics window."); } #else CaretLogWarning("Unable to create FTGL Font Renderer due to FreeType not found during configuration.\n" "No text will be available in graphics window."); #endif } if (textRenderer == NULL) { textRenderer = new DummyFontTextRenderer(); } /* * Performs OpenGL Rendering * Allocated dynamically so that it can be destroyed prior to OSMesa being * destroyed. Otherwise, if OpenGL is destroyed after OSMesa, errors * will occur as the OpenGL context is invalid when things such as * display lists or buffers are deleted. */ BrainOpenGLFixedPipeline* brainOpenGL = new BrainOpenGLFixedPipeline(textRenderer); brainOpenGL->initializeOpenGL(); return brainOpenGL; } #endif // HAVE_OSMESA /** * Write the image data to a Image File. * * @param imageFileName * Name of image file. * @param imageIndex * Index of image. * @param imageContent * content of image. * @param imageWidth * width of image. * @param imageHeight * height of image. */ void OperationShowScene::writeImage(const AString& imageFileName, const int32_t imageIndex, const unsigned char* imageContent, const int32_t imageWidth, const int32_t imageHeight) { /* * Create name of image */ QString outputName(imageFileName); if (imageIndex >= 0) { const AString imageNumber = QString("_%1").arg((int)(imageIndex + 1), 2, // width 10, // base QChar('0')); // fill character const int dotOffset = outputName.lastIndexOf("."); if (dotOffset >= 0) { outputName.insert(dotOffset, imageNumber); } else { outputName += (imageNumber + ".png"); } } try { ImageFile imageFile(imageContent, imageWidth, imageHeight, ImageFile::IMAGE_DATA_ORIGIN_AT_BOTTOM); imageFile.writeFile(outputName); } catch (const DataFileException& dfe) { throw OperationException(dfe); } } /** * Is the show scene command available? */ bool OperationShowScene::isShowSceneCommandAvailable() { #ifdef HAVE_OSMESA return true; #else // HAVE_OSMESA return false; #endif // HAVE_OSMESA } connectome-workbench-1.4.2/src/Operations/OperationShowScene.h000066400000000000000000000047341360521144700245050ustar00rootroot00000000000000#ifndef __OPERATION_SHOW_SCENE_H__ #define __OPERATION_SHOW_SCENE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class BrainOpenGLFixedPipeline; class OperationShowScene : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); static bool isShowSceneCommandAvailable(); private: static BrainOpenGLFixedPipeline* createBrainOpenGL(); static void writeImage(const AString& imageFileName, const int32_t imageIndex, const unsigned char* imageContent, const int32_t imageWidth, const int32_t imageHeight); static void estimateGraphicsSize(const SceneClass* windowSceneClass, float& estimatedWidthOut, float& estimatedHeightOut); static bool getToolBoxSize(const SceneClass* toolBoxClass, const SceneClass* activeToolBoxClass, float& overlayToolBoxWidthOut, float& overlayToolBoxHeightOut, QString& overlayToolBoxOrientationOut); }; typedef TemplateAutoOperation AutoOperationShowScene; } // namespace #endif //__OPERATION_SHOW_SCENE_H__ connectome-workbench-1.4.2/src/Operations/OperationSpecFileMerge.cxx000066400000000000000000000045441360521144700256330ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "FileInformation.h" #include "OperationSpecFileMerge.h" #include "OperationException.h" #include "SpecFile.h" using namespace caret; using namespace std; AString OperationSpecFileMerge::getCommandSwitch() { return "-spec-file-merge"; } AString OperationSpecFileMerge::getShortDescription() { return "MERGE TWO SPEC FILES INTO ONE"; } OperationParameters* OperationSpecFileMerge::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "spec-1", "first spec file to merge"); ret->addStringParameter(2, "spec-2", "second spec file to merge"); ret->addStringParameter(3, "out-spec", "output - output spec file");//fake the "output" formatting, could make a spec file parameter type ret->setHelpText(AString("The output spec file contains every file that is in either of the input spec files.")); return ret; } void OperationSpecFileMerge::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString spec1Name = FileInformation(myParams->getString(1)).getAbsoluteFilePath();//since opening a spec file may change the current directory, we must convert all paths to absolute first AString spec2Name = FileInformation(myParams->getString(2)).getAbsoluteFilePath(); AString outSpecName = FileInformation(myParams->getString(3)).getAbsoluteFilePath(); SpecFile spec1, spec2; spec1.readFile(spec1Name); spec2.readFile(spec2Name); spec1.appendSpecFile(spec2); spec1.writeFile(outSpecName); } connectome-workbench-1.4.2/src/Operations/OperationSpecFileMerge.h000066400000000000000000000026221360521144700252530ustar00rootroot00000000000000#ifndef __OPERATION_SPEC_FILE_MERGE_H__ #define __OPERATION_SPEC_FILE_MERGE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationSpecFileMerge : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationSpecFileMerge; } #endif //__OPERATION_SPEC_FILE_MERGE_H__ connectome-workbench-1.4.2/src/Operations/OperationSpecFileRelocate.cxx000066400000000000000000000041111360521144700263200ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationSpecFileRelocate.h" #include "OperationException.h" #include "SpecFile.h" using namespace caret; using namespace std; AString OperationSpecFileRelocate::getCommandSwitch() { return "-spec-file-relocate"; } AString OperationSpecFileRelocate::getShortDescription() { return "RECREATE SPEC FILE IN NEW LOCATION"; } OperationParameters* OperationSpecFileRelocate::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "input-spec", "the spec file to use"); ret->addStringParameter(2, "output-spec", "output - the new spec file to create");//fake the output formatting ret->setHelpText( AString("Spec files contain internal relative paths, such that moving or copying a spec file will cause it to lose track of the files it refers to. ") + "This command makes a modified copy of the spec file, changing the relative paths to refer to the new relative locations of the files." ); return ret; } void OperationSpecFileRelocate::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); SpecFile mySpec; mySpec.readFile(myParams->getString(1)); mySpec.writeFile(myParams->getString(2)); } connectome-workbench-1.4.2/src/Operations/OperationSpecFileRelocate.h000066400000000000000000000026441360521144700257560ustar00rootroot00000000000000#ifndef __OPERATION_SPEC_FILE_RELOCATE_H__ #define __OPERATION_SPEC_FILE_RELOCATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationSpecFileRelocate : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationSpecFileRelocate; } #endif //__OPERATION_SPEC_FILE_RELOCATE_H__ connectome-workbench-1.4.2/src/Operations/OperationSurfaceClosestVertex.cxx000066400000000000000000000070601360521144700273000ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationSurfaceClosestVertex.h" #include "OperationException.h" #include "SurfaceFile.h" #include using namespace caret; using namespace std; AString OperationSurfaceClosestVertex::getCommandSwitch() { return "-surface-closest-vertex"; } AString OperationSurfaceClosestVertex::getShortDescription() { return "FIND CLOSEST SURFACE VERTEX TO COORDINATES"; } OperationParameters* OperationSurfaceClosestVertex::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to use"); ret->addStringParameter(2, "coord-list-file", "text file with coordinates"); ret->addStringParameter(3, "vertex-list-out", "output - the output text file with vertex numbers");//HACK: we don't currently have an "output text file" parameter type, fake the formatting ret->setHelpText( AString("For each coordinate XYZ triple, find the closest vertex in the surface, and output its vertex number into a text file. ") + "The input file should only use whitespace to separate coordinates (spaces, newlines, tabs), for instance:\n\n" + "20 30 25\n30 -20 10" ); return ret; } void OperationSurfaceClosestVertex::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); SurfaceFile* mySurf = myParams->getSurface(1); AString coordFileName = myParams->getString(2); fstream coordFile(coordFileName.toLocal8Bit().constData(), fstream::in); if (!coordFile.good()) { throw OperationException("error opening coordinate list file for reading"); } AString nodeFileName = myParams->getString(3); fstream nodeFile(nodeFileName.toLocal8Bit().constData(), fstream::out); if (!nodeFile.good()) { throw OperationException("error opening output file for writing"); } vector coords; float x, y, z; while (coordFile >> x)//yes, really, thats how they intended it to be used, more or less { if (!(coordFile >> y >> z))//if we fail to read the rest of the triple, error { throw OperationException("read incomplete coordinate triple, would have been coordinate number " + AString::number(coords.size() / 3 + 1)); } coords.push_back(x); coords.push_back(y); coords.push_back(z); }//because of how we parse the file, we know that coords contains a multiple of 3 if (coords.empty()) { throw OperationException("did not find any coordinates in file, make sure you use only whitespace to separate numbers"); } for (int i = 0; i < (int)coords.size(); i += 3) { int node = mySurf->closestNode(coords.data() + i); nodeFile << node << endl; } } connectome-workbench-1.4.2/src/Operations/OperationSurfaceClosestVertex.h000066400000000000000000000026741360521144700267330ustar00rootroot00000000000000#ifndef __OPERATION_SURFACE_CLOSEST_VERTEX_H__ #define __OPERATION_SURFACE_CLOSEST_VERTEX_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationSurfaceClosestVertex : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationSurfaceClosestVertex; } #endif //__OPERATION_SURFACE_CLOSEST_VERTEX_H__ connectome-workbench-1.4.2/src/Operations/OperationSurfaceCoordinatesToMetric.cxx000066400000000000000000000047271360521144700304160ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationSurfaceCoordinatesToMetric.h" #include "OperationException.h" #include "MetricFile.h" #include "SurfaceFile.h" using namespace caret; using namespace std; AString OperationSurfaceCoordinatesToMetric::getCommandSwitch() { return "-surface-coordinates-to-metric"; } AString OperationSurfaceCoordinatesToMetric::getShortDescription() { return "MAKE METRIC FILE OF SURFACE COORDINATES"; } OperationParameters* OperationSurfaceCoordinatesToMetric::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to use the coordinates of"); ret->addMetricOutputParameter(2, "metric-out", "the output metric"); ret->setHelpText( AString("Puts the coordinates of the surface into a 3-map metric file, as x, y, z.") ); return ret; } void OperationSurfaceCoordinatesToMetric::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); SurfaceFile* mySurf = myParams->getSurface(1); MetricFile* myMetricOut = myParams->getOutputMetric(2); int numNodes = mySurf->getNumberOfNodes(); myMetricOut->setNumberOfNodesAndColumns(numNodes, 3); myMetricOut->setStructure(mySurf->getStructure()); myMetricOut->setMapName(0, "x coordinate"); myMetricOut->setMapName(1, "y coordinate"); myMetricOut->setMapName(2, "z coordinate"); for (int i = 0; i < numNodes; ++i) { const float* coord = mySurf->getCoordinate(i); myMetricOut->setValue(i, 0, coord[0]); myMetricOut->setValue(i, 1, coord[1]); myMetricOut->setValue(i, 2, coord[2]); } } connectome-workbench-1.4.2/src/Operations/OperationSurfaceCoordinatesToMetric.h000066400000000000000000000027431360521144700300370ustar00rootroot00000000000000#ifndef __OPERATION_SURFACE_COORDINATES_TO_METRIC_H__ #define __OPERATION_SURFACE_COORDINATES_TO_METRIC_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationSurfaceCoordinatesToMetric : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationSurfaceCoordinatesToMetric; } #endif //__OPERATION_SURFACE_COORDINATES_TO_METRIC_H__ connectome-workbench-1.4.2/src/Operations/OperationSurfaceCutResample.cxx000066400000000000000000000047541360521144700267210ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationSurfaceCutResample.h" #include "OperationException.h" #include "SurfaceResamplingHelper.h" using namespace caret; using namespace std; AString OperationSurfaceCutResample::getCommandSwitch() { return "-surface-cut-resample"; } AString OperationSurfaceCutResample::getShortDescription() { return "RESAMPLE A CUT SURFACE"; } OperationParameters* OperationSurfaceCutResample::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface-in", "the surface file to resample"); ret->addSurfaceParameter(2, "current-sphere", "a sphere surface with the mesh that the input surface is currently on"); ret->addSurfaceParameter(3, "new-sphere", "a sphere surface that is in register with and has the desired output mesh"); ret->addSurfaceOutputParameter(4, "surface-out", "the output surface file"); ret->setHelpText( AString("Resamples a surface file, given two spherical surfaces that are in register. ") + "Barycentric resampling is used, because it is usually better for resampling surfaces, and because it is needed to figure out the new topology anyway." ); return ret; } void OperationSurfaceCutResample::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); SurfaceFile* surfaceIn = myParams->getSurface(1); SurfaceFile* curSphere = myParams->getSurface(2); SurfaceFile* newSphere = myParams->getSurface(3); SurfaceFile* surfaceOut = myParams->getOutputSurface(4); SurfaceResamplingHelper::resampleCutSurface(surfaceIn, curSphere, newSphere, surfaceOut); } connectome-workbench-1.4.2/src/Operations/OperationSurfaceCutResample.h000066400000000000000000000026601360521144700263400ustar00rootroot00000000000000#ifndef __OPERATION_SURFACE_CUT_RESAMPLE_H__ #define __OPERATION_SURFACE_CUT_RESAMPLE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationSurfaceCutResample : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationSurfaceCutResample; } #endif //__OPERATION_SURFACE_CUT_RESAMPLE_H__ connectome-workbench-1.4.2/src/Operations/OperationSurfaceFlipNormals.cxx000066400000000000000000000043601360521144700267140ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationSurfaceFlipNormals.h" #include "OperationException.h" #include "SurfaceFile.h" using namespace caret; using namespace std; AString OperationSurfaceFlipNormals::getCommandSwitch() { return "-surface-flip-normals"; } AString OperationSurfaceFlipNormals::getShortDescription() { return "FLIP ALL TILES ON A SURFACE"; } OperationParameters* OperationSurfaceFlipNormals::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to flip the normals of"); ret->addSurfaceOutputParameter(2, "surface-out", "the output surface"); ret->setHelpText( AString("Flips all triangles on a surface, resulting in surface normals being flipped the other direction (inward vs outward). ") + "If you transform a surface with an affine that has negative determinant, or a warpfield that similarly flips the surface, you may end up " + "with a surface that has normals pointing inwards, which may have display problems. " + "Using this command will solve that problem." ); return ret; } void OperationSurfaceFlipNormals::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); SurfaceFile* mySurf = myParams->getSurface(1); SurfaceFile* mySurfOut = myParams->getOutputSurface(2); *mySurfOut = *mySurf; mySurfOut->flipNormals(); } connectome-workbench-1.4.2/src/Operations/OperationSurfaceFlipNormals.h000066400000000000000000000026601360521144700263420ustar00rootroot00000000000000#ifndef __OPERATION_SURFACE_FLIP_NORMALS_H__ #define __OPERATION_SURFACE_FLIP_NORMALS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationSurfaceFlipNormals : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationSurfaceFlipNormals; } #endif //__OPERATION_SURFACE_FLIP_NORMALS_H__ connectome-workbench-1.4.2/src/Operations/OperationSurfaceGeodesicDistance.cxx000066400000000000000000000120541360521144700276620ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationSurfaceGeodesicDistance.h" #include "OperationException.h" #include "CaretAssert.h" #include "GeodesicHelper.h" #include "MetricFile.h" #include "SurfaceFile.h" using namespace caret; using namespace std; AString OperationSurfaceGeodesicDistance::getCommandSwitch() { return "-surface-geodesic-distance"; } AString OperationSurfaceGeodesicDistance::getShortDescription() { return "COMPUTE GEODESIC DISTANCE FROM ONE VERTEX TO THE ENTIRE SURFACE"; } OperationParameters* OperationSurfaceGeodesicDistance::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to compute on"); ret->addIntegerParameter(2, "vertex", "the vertex to compute geodesic distance from"); ret->addMetricOutputParameter(3, "metric-out", "the output metric"); ret->createOptionalParameter(4, "-naive", "use only neighbors, don't crawl triangles (not recommended)"); OptionalParameter* limitOpt = ret->createOptionalParameter(5, "-limit", "stop at a certain distance"); limitOpt->addDoubleParameter(1, "limit-mm", "distance in mm to stop at"); OptionalParameter* corrAreaOpt = ret->createOptionalParameter(6, "-corrected-areas", "vertex areas to use instead of computing them from the surface"); corrAreaOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); ret->setHelpText( AString("Unless -limit is specified, computes the geodesic distance from the specified vertex to all others. ") + "The result is output as a single column metric file, with a value of -1 for vertices that the distance was not computed for.\n\n" + "The -corrected-areas option should be used when the input is a group average surface - group average surfaces have " + "significantly less surface area than individual surfaces do, and therefore distances measured on them would be smaller than measuring them on individual surfaces. " + "In this case, the input to this option should be a group average of the output of -surface-vertex-areas for each subject.\n\n" + "If -naive is not specified, the algorithm uses not just immediate neighbors, but also neighbors derived from crawling across pairs of triangles that share an edge." ); return ret; } void OperationSurfaceGeodesicDistance::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); SurfaceFile* mySurf = myParams->getSurface(1); int myVertex = (int)myParams->getInteger(2); MetricFile* myMetricOut = myParams->getOutputMetric(3); bool smooth = !(myParams->getOptionalParameter(4)->m_present); OptionalParameter* limitOpt = myParams->getOptionalParameter(5); CaretPointer myHelp; CaretPointer myBase; OptionalParameter* corrAreaOpt = myParams->getOptionalParameter(6); if (corrAreaOpt->m_present) { MetricFile* corrAreas = corrAreaOpt->getMetric(1); if (corrAreas->getNumberOfNodes() != mySurf->getNumberOfNodes()) throw OperationException("corrected vertex areas metric does not match surface number of vertices"); myBase.grabNew(new GeodesicHelperBase(mySurf, corrAreas->getValuePointerForColumn(0))); myHelp.grabNew(new GeodesicHelper(myBase)); } else { myHelp = mySurf->getGeodesicHelper(); } vector scratch(mySurf->getNumberOfNodes(), -1.0f);//use -1 to specify invalid if (limitOpt->m_present) { vector nodes; vector dists; myHelp->getNodesToGeoDist(myVertex, limitOpt->getDouble(1), nodes, dists, smooth); for (int i = 0; i < (int)nodes.size(); ++i) { CaretAssertVectorIndex(dists, i); scratch[nodes[i]] = dists[i]; } } else { myHelp->getGeoFromNode(myVertex, scratch, smooth); if (scratch.size() == 0) throw OperationException("invalid vertex specified"); } myMetricOut->setNumberOfNodesAndColumns(mySurf->getNumberOfNodes(), 1); myMetricOut->setStructure(mySurf->getStructure()); myMetricOut->setColumnName(0, "vertex " + AString::number(myVertex) + " distance"); myMetricOut->setValuesForColumn(0, scratch.data()); } connectome-workbench-1.4.2/src/Operations/OperationSurfaceGeodesicDistance.h000066400000000000000000000027161360521144700273130ustar00rootroot00000000000000#ifndef __OPERATION_SURFACE_GEODESIC_DISTANCE_H__ #define __OPERATION_SURFACE_GEODESIC_DISTANCE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationSurfaceGeodesicDistance : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationSurfaceGeodesicDistance; } #endif //__OPERATION_SURFACE_GEODESIC_DISTANCE_H__ connectome-workbench-1.4.2/src/Operations/OperationSurfaceGeodesicDistanceAllToAll.cxx000066400000000000000000000156621360521144700312570ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationSurfaceGeodesicDistanceAllToAll.h" #include "OperationException.h" #include "CaretOMP.h" #include "CiftiFile.h" #include "GeodesicHelper.h" #include "MetricFile.h" #include "SurfaceFile.h" using namespace caret; using namespace std; AString OperationSurfaceGeodesicDistanceAllToAll::getCommandSwitch() { return "-surface-geodesic-distance-all-to-all"; } AString OperationSurfaceGeodesicDistanceAllToAll::getShortDescription() { return "COMPUTE GEODESIC DISTANCES FROM ALL VERTICES"; } OperationParameters* OperationSurfaceGeodesicDistanceAllToAll::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to compute on"); ret->addCiftiOutputParameter(2, "cifti-out", "single-hemisphere dconn containing the distances"); OptionalParameter* roiOpt = ret->createOptionalParameter(3, "-roi", "only output distances for vertices inside an ROI"); roiOpt->addMetricParameter(1, "roi-metric", "the ROI as a metric file"); OptionalParameter* limitOpt = ret->createOptionalParameter(4, "-limit", "stop at a specified distance"); limitOpt->addDoubleParameter(1, "limit-mm", "distance in mm to stop at"); OptionalParameter* corrAreaOpt = ret->createOptionalParameter(5, "-corrected-areas", "vertex areas to use instead of computing them from the surface"); corrAreaOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); ret->createOptionalParameter(6, "-naive", "use only neighbors, don't crawl triangles (not recommended)"); ret->setHelpText( AString("Computes geodesic distance from every vertex to every vertex, outputting a single-hemisphere dconn file. ") + "If you are only interested in a few vertices, see -surface-geodesic-distance. " + "When -limit is specified, any vertex beyond the limit is assigned the value -1.\n\n" + "The -roi option makes the output file smaller by not outputting distances to or from vertices outside the ROI, but paths are still allowed to go outside the ROI when finding distances to other vertices.\n\n" + "The -corrected-areas option should be used when the input is a group average surface - group average surfaces have " + "significantly less surface area than individual surfaces do, and therefore distances measured on them would be smaller than measuring them on individual surfaces. " + "In this case, the input to this option should be a group average of the output of -surface-vertex-areas for each subject.\n\n" + "If -naive is not specified, the algorithm uses not just immediate neighbors, but also neighbors derived from crawling across pairs of triangles that share an edge." ); return ret; } void OperationSurfaceGeodesicDistanceAllToAll::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); SurfaceFile* mySurf = myParams->getSurface(1); CiftiFile* ciftiOut = myParams->getOutputCifti(2); const float* roiData = NULL; OptionalParameter* roiOpt = myParams->getOptionalParameter(3); if (roiOpt->m_present) { MetricFile* roiMetric = roiOpt->getMetric(1); if (roiMetric->getNumberOfNodes() != mySurf->getNumberOfNodes()) throw OperationException("corrected vertex areas metric does not match surface number of vertices"); roiData = roiMetric->getValuePointerForColumn(0); } float distLimit = -1.0f; OptionalParameter* limitOpt = myParams->getOptionalParameter(4); if (limitOpt->m_present) { distLimit = limitOpt->getDouble(1); if (!(distLimit > 0.0f)) throw OperationException(" must be positive"); } CaretPointer myHelp; CaretPointer myBase; OptionalParameter* corrAreaOpt = myParams->getOptionalParameter(5); if (corrAreaOpt->m_present) { MetricFile* corrAreas = corrAreaOpt->getMetric(1); if (corrAreas->getNumberOfNodes() != mySurf->getNumberOfNodes()) throw OperationException("corrected vertex areas metric does not match surface number of vertices"); myBase.grabNew(new GeodesicHelperBase(mySurf, corrAreas->getValuePointerForColumn(0))); myHelp.grabNew(new GeodesicHelper(myBase)); } else { myHelp = mySurf->getGeodesicHelper(); } bool naive = myParams->getOptionalParameter(6)->m_present; CiftiBrainModelsMap myMap; StructureEnum::Enum structure = mySurf->getStructure(); myMap.addSurfaceModel(mySurf->getNumberOfNodes(), structure, roiData); int64_t mapLength = myMap.getLength(); vector surfMap = myMap.getSurfaceMap(structure); CiftiXML myXML; myXML.setNumberOfDimensions(2); myXML.setMap(CiftiXML::ALONG_ROW, myMap); myXML.setMap(CiftiXML::ALONG_COLUMN, myMap); ciftiOut->setCiftiXML(myXML); #pragma omp CARET_PAR { CaretPointer privHelper; if (corrAreaOpt->m_present) { privHelper.grabNew(new GeodesicHelper(myBase)); } else { privHelper = mySurf->getGeodesicHelper(); } #pragma omp CARET_FOR schedule(dynamic) for (int64_t i = 0; i < mapLength; ++i) { vector outRow(mapLength, -1.0f), outDists; vector outNodes; if (distLimit > 0.0f) { privHelper->getNodesToGeoDist(surfMap[i].m_surfaceNode, distLimit, outNodes, outDists, !naive); for (int j = 0; j < int(outNodes.size()); ++j) { int64_t index = myMap.getIndexForNode(outNodes[j], structure);//-1 if outside ROI if (index >= 0) outRow[index] = outDists[j]; } } else { privHelper->getGeoFromNode(surfMap[i].m_surfaceNode, outDists, !naive); for (int64_t j = 0; j < mapLength; ++j) { outRow[j] = outDists[surfMap[j].m_surfaceNode]; } } #pragma omp critical { ciftiOut->setRow(outRow.data(), i); } } } } connectome-workbench-1.4.2/src/Operations/OperationSurfaceGeodesicDistanceAllToAll.h000066400000000000000000000030071360521144700306720ustar00rootroot00000000000000#ifndef __OPERATION_SURFACE_GEODESIC_DISTANCE_ALL_TO_ALL_H__ #define __OPERATION_SURFACE_GEODESIC_DISTANCE_ALL_TO_ALL_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationSurfaceGeodesicDistanceAllToAll : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationSurfaceGeodesicDistanceAllToAll; } #endif //__OPERATION_SURFACE_GEODESIC_DISTANCE_ALL_TO_ALL_H__ connectome-workbench-1.4.2/src/Operations/OperationSurfaceGeodesicROIs.cxx000066400000000000000000000261031360521144700267440ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationSurfaceGeodesicROIs.h" #include "OperationException.h" #include "GeodesicHelper.h" #include "MetricFile.h" #include "SurfaceFile.h" #include #include #include using namespace caret; using namespace std; AString OperationSurfaceGeodesicROIs::getCommandSwitch() { return "-surface-geodesic-rois"; } AString OperationSurfaceGeodesicROIs::getShortDescription() { return "DRAW GEODESIC LIMITED ROIS AT VERTICES"; } OperationParameters* OperationSurfaceGeodesicROIs::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to draw on"); ret->addDoubleParameter(2, "limit", "geodesic distance limit from vertex, in mm"); ret->addStringParameter(3, "vertex-list-file", "a text file containing the vertices to draw ROIs around"); ret->addMetricOutputParameter(4, "metric-out", "the output metric"); OptionalParameter* gaussOpt = ret->createOptionalParameter(5, "-gaussian", "generate a gaussian kernel instead of a flat ROI"); gaussOpt->addDoubleParameter(1, "sigma", "the sigma for the gaussian kernel, in mm"); OptionalParameter* overlapOpt = ret->createOptionalParameter(6, "-overlap-logic", "how to handle overlapping ROIs, default ALLOW"); overlapOpt->addStringParameter(1, "method", "the method of resolving overlaps"); OptionalParameter* namesOpt = ret->createOptionalParameter(7, "-names", "name the columns from text file"); namesOpt->addStringParameter(1, "name-list-file", "a text file containing column names, one per line"); OptionalParameter* corrAreaOpt = ret->createOptionalParameter(8, "-corrected-areas", "vertex areas to use instead of computing them from the surface"); corrAreaOpt->addMetricParameter(1, "area-metric", "the corrected vertex areas, as a metric"); ret->setHelpText( AString("For each vertex in the list file, a column in the output metric is created, and an ROI around that vertex is drawn in that column. ") + "Each metric column will have zeros outside the geodesic distance spacified by , and by default will have a value of 1.0 inside it. " + "If the -gaussian option is specified, the values inside the ROI will instead form a gaussian with the specified value of sigma, normalized " + "so that the sum of the nonzero values in the metric column is 1.0. The argument to -overlap-logic must be one of ALLOW, CLOSEST, or EXCLUDE. " + "ALLOW is the default, and means that ROIs are treated independently and may overlap. " + "CLOSEST means that ROIs may not overlap, and that no ROI contains vertices that are closer to a different seed vertex. " + "EXCLUDE means that ROIs may not overlap, and that any vertex within range of more than one ROI does not belong to any ROI." ); return ret; } void OperationSurfaceGeodesicROIs::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); SurfaceFile* mySurf = myParams->getSurface(1); float limit = (float)myParams->getDouble(2); AString nodeFileName = myParams->getString(3); MetricFile* myMetricOut = myParams->getOutputMetric(4); OptionalParameter* gaussOpt = myParams->getOptionalParameter(5); float sigma = -1.0f; if (gaussOpt->m_present) {//set up to use a gaussian function sigma = (float)gaussOpt->getDouble(1); if (sigma <= 0.0f) { throw OperationException("invalid sigma specified"); } } fstream textFile(nodeFileName.toLocal8Bit().constData(), fstream::in); if (!textFile.good()) { throw OperationException("error opening list file for reading"); } int nodenum, numNodes = mySurf->getNumberOfNodes(); vector nodelist; textFile >> nodenum; while (textFile) { if (nodenum < 0 || nodenum >= numNodes) { throw OperationException("invalid vertex number: " + AString::number(nodenum)); } nodelist.push_back(nodenum); textFile >> nodenum; } int overlapType = 1;//ALLOW OptionalParameter* overlapOpt = myParams->getOptionalParameter(6); if (overlapOpt->m_present) { AString overlapString = overlapOpt->getString(1); if (overlapString == "ALLOW") { overlapType = 1; } else if (overlapString == "CLOSEST") { overlapType = 2; } else if (overlapString == "EXCLUDE") { overlapType = 3; } else { throw OperationException("unrecognized overlap method: " + overlapString); } } vector namesList; OptionalParameter* namesOpt = myParams->getOptionalParameter(7); if (namesOpt->m_present) { AString namesFileName = namesOpt->getString(1); fstream namesfile(namesFileName.toLocal8Bit().constData(), fstream::in); if (!namesfile.good()) { throw OperationException("error opening names file for reading"); } int i = 0; string inputline; getline(namesfile, inputline); while (namesfile && i < (int)nodelist.size()) { namesList.push_back(inputline.c_str()); getline(namesfile, inputline); ++i; } } MetricFile* corrAreas = NULL; OptionalParameter* corrAreaOpt = myParams->getOptionalParameter(8); if (corrAreaOpt->m_present) { corrAreas = corrAreaOpt->getMetric(1); if (corrAreas->getNumberOfNodes() != numNodes) { throw OperationException("corrected areas metric does not match surface in number of vertices"); } } myMetricOut->setNumberOfNodesAndColumns(numNodes, (int)nodelist.size()); myMetricOut->setStructure(mySurf->getStructure()); float invneg2sigmasqr = -0.5f / (sigma * sigma); for (int i = 0; i < (int)nodelist.size(); ++i) { myMetricOut->initializeColumn(i); if (i < (int)namesList.size()) { myMetricOut->setColumnName(i, namesList[i]); } else { const float* myCoord = mySurf->getCoordinate(i); myMetricOut->setColumnName(i, "Vertex " + AString::number(nodelist[i]) + " (" + AString::number(myCoord[0], 'f', 1) + ", " + AString::number(myCoord[1], 'f', 1) + ", " + AString::number(myCoord[2], 'f', 1) + ")"); } } CaretPointer myhelp; CaretPointer mygeobase; if (corrAreas == NULL) { myhelp = mySurf->getGeodesicHelper(); } else { mygeobase.grabNew(new GeodesicHelperBase(mySurf, corrAreas->getValuePointerForColumn(0))); myhelp.grabNew(new GeodesicHelper(mygeobase)); } switch (overlapType) { case 1://ALLOW for (int i = 0; i < (int)nodelist.size(); ++i) { vector roinodes; vector dists; myhelp->getNodesToGeoDist(nodelist[i], limit, roinodes, dists); if (sigma > 0.0f) { double accum = 0.0; for (int j = 0; j < (int)dists.size(); ++j) { dists[j] = exp(dists[j] * dists[j] * invneg2sigmasqr);//reuse the vector for weights accum += dists[j]; } for (int j = 0; j < (int)dists.size(); ++j) { dists[j] /= accum; myMetricOut->setValue(roinodes[j], i, dists[j]); } } else { for (int j = 0; j < (int)roinodes.size(); ++j) { myMetricOut->setValue(roinodes[j], i, 1.0f); } } } break; case 2: case 3: { vector useCounts(numNodes, 0); vector closestSeed(numNodes, -1); vector bestDists(numNodes, -1.0f); for (int i = 0; i < (int)nodelist.size(); ++i) { vector roinodes; vector dists; myhelp->getNodesToGeoDist(nodelist[i], limit, roinodes, dists); for (int j = 0; j < (int)roinodes.size(); ++j) { ++useCounts[roinodes[j]]; if (bestDists[roinodes[j]] < 0.0f || dists[j] < bestDists[roinodes[j]]) { bestDists[roinodes[j]] = dists[j]; closestSeed[roinodes[j]] = i;//nodelist array index, not node number } } } if (sigma > 0.0f) { vector accums(nodelist.size(), 0.0); vector > roinodelists(nodelist.size()); vector > weightlists(nodelist.size()); for (int i = 0; i < numNodes; ++i) { if (closestSeed[i] != -1 && (overlapType == 2 || useCounts[i] == 1)) { roinodelists[closestSeed[i]].push_back(i); float weight = exp(bestDists[i] * bestDists[i] * invneg2sigmasqr); weightlists[closestSeed[i]].push_back(weight); accums[closestSeed[i]] += weight; } } for (int i = 0; i < (int)nodelist.size(); ++i) { for (int j = 0; j < (int)roinodelists[i].size(); ++j) { myMetricOut->setValue(roinodelists[i][j], i, weightlists[i][j] / accums[i]); } } } else { for (int i = 0; i < numNodes; ++i) { if (closestSeed[i] != -1 && (overlapType == 2 || useCounts[i] == 1)) { myMetricOut->setValue(i, closestSeed[i], 1.0f); } } } break; } default: throw OperationException("something very bad happened, notify the developers"); } } connectome-workbench-1.4.2/src/Operations/OperationSurfaceGeodesicROIs.h000066400000000000000000000026661360521144700264010ustar00rootroot00000000000000#ifndef __OPERATION_SURFACE_GEODESIC_ROIS_H__ #define __OPERATION_SURFACE_GEODESIC_ROIS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationSurfaceGeodesicROIs : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationSurfaceGeodesicROIs; } #endif //__OPERATION_SURFACE_GEODESIC_ROIS_H__ connectome-workbench-1.4.2/src/Operations/OperationSurfaceInformation.cxx000066400000000000000000000046071360521144700267570ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretAssert.h" #include "CaretLogger.h" #include "OperationSurfaceInformation.h" #include "OperationException.h" #include "DataFileException.h" #include "SurfaceFile.h" using namespace caret; /** * \class caret::OperationSurfaceInformation * \brief Display information about a surface */ /** * @return Command line switch */ AString OperationSurfaceInformation::getCommandSwitch() { return "-surface-information"; } /** * @return Short description of operation */ AString OperationSurfaceInformation::getShortDescription() { return "DISPLAY INFORMATION ABOUT A SURFACE"; } /** * @return Parameters for operation */ OperationParameters* OperationSurfaceInformation::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "Surface File", "Surface for which information is displayed"); AString helpText = ("Information about surface is displayed including vertices, \n" "triangles, bounding box, and spacing."); ret->setHelpText(helpText); return ret; } /** * Use Parameters and perform operation */ void OperationSurfaceInformation::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); try { SurfaceFile* surfaceFile = myParams->getSurface(1); std::cout << qPrintable(surfaceFile->getInformation()) << std::endl; } catch (const DataFileException& dfe) { throw OperationException(dfe); } } connectome-workbench-1.4.2/src/Operations/OperationSurfaceInformation.h000066400000000000000000000027351360521144700264040ustar00rootroot00000000000000#ifndef __OPERATION_SURFACE_INFORMATION_H__ #define __OPERATION_SURFACE_INFORMATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationSurfaceInformation : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationSurfaceInformation; } // namespace #endif //__OPERATION_SURFACE_INFORMATION_H__ connectome-workbench-1.4.2/src/Operations/OperationSurfaceNormals.cxx000066400000000000000000000050571360521144700261050ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationSurfaceNormals.h" #include "OperationException.h" #include "MetricFile.h" #include "SurfaceFile.h" using namespace caret; using namespace std; AString OperationSurfaceNormals::getCommandSwitch() { return "-surface-normals"; } AString OperationSurfaceNormals::getShortDescription() { return "OUTPUT VERTEX NORMALS AS METRIC FILE"; } OperationParameters* OperationSurfaceNormals::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to output the normals of"); ret->addMetricOutputParameter(2, "metric-out", "the normal vectors"); ret->setHelpText( AString("Computes the normal vectors of the surface file, and outputs them as a 3 column metric file.") ); return ret; } void OperationSurfaceNormals::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); SurfaceFile* mySurf = myParams->getSurface(1); MetricFile* myMetricOut = myParams->getOutputMetric(2); int numNodes = mySurf->getNumberOfNodes(); myMetricOut->setNumberOfNodesAndColumns(numNodes, 3); myMetricOut->setStructure(mySurf->getStructure()); myMetricOut->setColumnName(0, "normal x-component"); myMetricOut->setColumnName(1, "normal y-component"); myMetricOut->setColumnName(2, "normal z-component"); mySurf->computeNormals(); const float* normalData = mySurf->getNormalData(); vector colScratch(numNodes); for (int axis = 0; axis < 3; ++axis) { for (int i = 0; i < numNodes; ++i) { colScratch[i] = normalData[i * 3 + axis]; } myMetricOut->setValuesForColumn(axis, colScratch.data()); } } connectome-workbench-1.4.2/src/Operations/OperationSurfaceNormals.h000066400000000000000000000026251360521144700255300ustar00rootroot00000000000000#ifndef __OPERATION_SURFACE_NORMALS_H__ #define __OPERATION_SURFACE_NORMALS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationSurfaceNormals : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationSurfaceNormals; } #endif //__OPERATION_SURFACE_NORMALS_H__ connectome-workbench-1.4.2/src/Operations/OperationSurfaceSetCoordinates.cxx000066400000000000000000000057521360521144700274220ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationSurfaceSetCoordinates.h" #include "OperationException.h" #include "MetricFile.h" #include "SurfaceFile.h" using namespace caret; using namespace std; AString OperationSurfaceSetCoordinates::getCommandSwitch() { return "-surface-set-coordinates"; } AString OperationSurfaceSetCoordinates::getShortDescription() { return "MODIFY COORDINATES OF A SURFACE"; } OperationParameters* OperationSurfaceSetCoordinates::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface-in", "the surface to use for the topology"); ret->addMetricParameter(2, "coord-metric", "the new coordinates, as a 3-column metric file"); ret->addSurfaceOutputParameter(3, "surface-out", "the new surface"); ret->setHelpText( AString("Takes the topology from an existing surface file, and uses values from a metric file as coordinates to construct a new surface file.\n\n") + "See -surface-coordinates-to-metric for how to get surface coordinates as a metric file, such that you can then modify them via metric commands, etc." ); return ret; } void OperationSurfaceSetCoordinates::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); SurfaceFile* inSurf = myParams->getSurface(1); MetricFile* coordsIn = myParams->getMetric(2); SurfaceFile* outSurf = myParams->getOutputSurface(3); int numNodes = inSurf->getNumberOfNodes(); if (coordsIn->getNumberOfNodes() != numNodes) { throw OperationException("coordinate metric file must have the same number of vertices as the input surface"); } if (coordsIn->getNumberOfColumns() != 3) { throw OperationException("coordinate metric file must have exactly 3 columns: x, y, and z"); } *outSurf = *inSurf; vector combinedCoords(numNodes * 3); for (int i = 0; i < 3; ++i) { const float* colData = coordsIn->getValuePointerForColumn(i); for (int j = 0; j < numNodes; ++j) { combinedCoords[j * 3 + i] = colData[j]; } } outSurf->setCoordinates(combinedCoords.data()); } connectome-workbench-1.4.2/src/Operations/OperationSurfaceSetCoordinates.h000066400000000000000000000027021360521144700270370ustar00rootroot00000000000000#ifndef __OPERATION_SURFACE_SET_COORDINATES_H__ #define __OPERATION_SURFACE_SET_COORDINATES_H__ /*LICENSE_START*/ /* * Copyright (C) 2016 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationSurfaceSetCoordinates : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationSurfaceSetCoordinates; } #endif //__OPERATION_SURFACE_SET_COORDINATES_H__ connectome-workbench-1.4.2/src/Operations/OperationSurfaceVertexAreas.cxx000066400000000000000000000043441360521144700267210ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationSurfaceVertexAreas.h" #include "OperationException.h" #include "MetricFile.h" #include "SurfaceFile.h" #include using namespace caret; using namespace std; AString OperationSurfaceVertexAreas::getCommandSwitch() { return "-surface-vertex-areas"; } AString OperationSurfaceVertexAreas::getShortDescription() { return "MEASURE SURFACE AREA EACH VERTEX IS RESPONSIBLE FOR"; } OperationParameters* OperationSurfaceVertexAreas::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addSurfaceParameter(1, "surface", "the surface to measure"); ret->addMetricOutputParameter(2, "metric", "the output metric"); ret->setHelpText( AString("Each vertex gets one third of the area of each triangle it is a part of. ") + "Units are mm^2." ); return ret; } void OperationSurfaceVertexAreas::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); SurfaceFile* mySurf = myParams->getSurface(1); MetricFile* myMetricOut = myParams->getOutputMetric(2); int numNodes = mySurf->getNumberOfNodes(); vector areas; mySurf->computeNodeAreas(areas); myMetricOut->setNumberOfNodesAndColumns(numNodes, 1); myMetricOut->setStructure(mySurf->getStructure()); myMetricOut->setColumnName(0, "vertex areas"); myMetricOut->setValuesForColumn(0, areas.data()); } connectome-workbench-1.4.2/src/Operations/OperationSurfaceVertexAreas.h000066400000000000000000000026601360521144700263450ustar00rootroot00000000000000#ifndef __OPERATION_SURFACE_VERTEX_AREAS_H__ #define __OPERATION_SURFACE_VERTEX_AREAS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationSurfaceVertexAreas : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationSurfaceVertexAreas; } #endif //__OPERATION_SURFACE_VERTEX_AREAS_H__ connectome-workbench-1.4.2/src/Operations/OperationTemplate.cxx.txt000066400000000000000000000056611360521144700255530ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationName.h" #include "OperationException.h" using namespace caret; using namespace std; AString OperationName::getCommandSwitch() { return "-command-switch"; } AString OperationName::getShortDescription() { return "SHORT DESCRIPTION"; } OperationParameters* OperationName::getParameters() { OperationParameters* ret = new OperationParameters(); //ret->addSurfaceParameter(1, "surface", "the surface to compute on"); //ret->addMetricOutputParameter(2, "metric-out", "the output metric"); //OptionalParameter* columnSelect = ret->createOptionalParameter(3, "-column", "select a single column"); //columnSelect->addStringParameter(1, "column", "the column number or name"); ret->setHelpText( AString("This is where you set the help text. ") + "DO NOT add the info about what the command line format is, and do not give the command switch, " + "short description, or the short descriptions of parameters. " + "Do not indent, manually break long lines, or format the text in any way " + "other than to separate paragraphs within the help text prose, usually with two newlines." ); return ret; } void OperationName::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); //SurfaceFile* mySurf = myParams->getSurface(1);//gets the surface with key 1 //MetricFile* myMetricOut = myParams->getOutputMetric(2);//gets the output metric with key 2 //OptionalParameter* columnSelect = myParams->getOptionalParameter(3);//gets optional parameter with key 3 /*int columnNum = -1; if (columnSelect->m_present) {//set up to use the single column columnNum = (int)myMetric->getMapIndexFromNameOrNumber(columnSelect->getString(1)); if (columnNum < 0 || columnNum >= myMetric->getNumberOfMaps()) { throw OperationException("invalid column specified"); } }//*/ //do the work here //myProgress.reportProgress(0.5f);//this is how you would report being half finished, if the operation takes a while (probably not) } connectome-workbench-1.4.2/src/Operations/OperationTemplate.h.txt000066400000000000000000000050571360521144700251770ustar00rootroot00000000000000#ifndef __OPERATION_NAME_H__ #define __OPERATION_NAME_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ /* INSTRUCTIONS: file->save as... and enter what you will name the class, plus .h find and replace these strings in plain text mode (not "whole word only"): OperationName : operation name, in CamelCase, with initial capital, same as what you saved the header file to OPERATION_NAME : uppercase of operation name, with underscore between words, used in #ifdef guards next, make OperationName.cxx from OperationTemplate.cxx.txt via one of the following (depending on working directory): cat OperationTemplate.cxx.txt | sed 's/[O]perationName/OperationName/g' > OperationName.cxx cat Operations/OperationTemplate.cxx.txt | sed 's/[O]perationName/OperationName/g' > Operations/OperationName.cxx cat src/Operations/OperationTemplate.cxx.txt | sed 's/[O]perationName/OperationName/g' > src/Operations/OperationName.cxx or manually copy and replace next, implement its functions add these to Operations/CMakeLists.txt: OperationName.h OperationName.cxx place the following lines into Commands/CommandOperationManager.cxx: #include "OperationName.h" //near the top this->commandOperations.push_back(new CommandParser(new AutoOperationName())); //in CommandOperationManager() finally, remove this block comment */ #include "AbstractOperation.h" namespace caret { class OperationName : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationName; } #endif //__OPERATION_NAME_H__ connectome-workbench-1.4.2/src/Operations/OperationVolumeCapturePlane.cxx000066400000000000000000000150311360521144700267250ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationVolumeCapturePlane.h" #include "OperationException.h" #include "CaretLogger.h" #include "ImageFile.h" #include "Vector3D.h" #include "VolumeFile.h" #include using namespace caret; using namespace std; AString OperationVolumeCapturePlane::getCommandSwitch() { return "-volume-capture-plane"; } AString OperationVolumeCapturePlane::getShortDescription() { return "INTERPOLATE IMAGE FROM PLANE THROUGH VOLUME"; } OperationParameters* OperationVolumeCapturePlane::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume", "the volume file to interpolate from"); ret->addStringParameter(2, "subvolume", "the name or number of the subvolume to use"); ret->addStringParameter(3, "interp", "interpolation type"); ret->addIntegerParameter(4, "h-dim", "width of output image, in pixels"); ret->addIntegerParameter(5, "v-dim", "height of output image, in pixels"); ret->addDoubleParameter(6, "scale-min", "value to render as black"); ret->addDoubleParameter(7, "scale-max", "value to render as white"); int key = 8; char xyz[] = "xyz"; for (int i = 0; i < 3; ++i) { ret->addDoubleParameter(key, AString("bottom-left-") + xyz[i], xyz[i] + AString("-coordinate of the bottom left of the output image")); ++key; }//8 9 10 for (int i = 0; i < 3; ++i) { ret->addDoubleParameter(key, AString("bottom-right-") + xyz[i], xyz[i] + AString("-coordinate of the bottom right of the output image")); ++key; }//11 12 13 for (int i = 0; i < 3; ++i) { ret->addDoubleParameter(key, AString("top-left-") + xyz[i], xyz[i] + AString("-coordinate of the top left of the output image")); ++key; }//14 15 16 ret->addStringParameter(17, "image", "output - the output image");//fake the output formatting ret->setHelpText( AString("NOTE: If you want to generate an image with all of the capabilities of the GUI rendering, see -show-scene.\n\n") + "Renders an image of an arbitrary plane through the volume file, with a simple linear grayscale palette. " + "The parameter must be one of:\n\n" + "CUBIC\nENCLOSING_VOXEL\nTRILINEAR" ); return ret; } void OperationVolumeCapturePlane::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); VolumeFile* myVol = myParams->getVolume(1); AString subvolName = myParams->getString(2); int subvol = myVol->getMapIndexFromNameOrNumber(subvolName); if (subvol < 0 || subvol >= myVol->getNumberOfMaps()) { throw OperationException("invalid subvolume"); } AString interp = myParams->getString(3); VolumeFile::InterpType myMethod = VolumeFile::CUBIC; if (interp == "CUBIC") { myMethod = VolumeFile::CUBIC; } else if (interp == "TRILINEAR") { myMethod = VolumeFile::TRILINEAR; } else if (interp == "ENCLOSING_VOXEL") { myMethod = VolumeFile::ENCLOSING_VOXEL; } else { throw OperationException("unrecognized interpolation method"); } int width = (int)myParams->getInteger(4); int height = (int)myParams->getInteger(5); if (width < 2 || height < 2) { throw OperationException("output image dimensions must be 2 or greater");//to avoid divide by zero } float scalemin = (float)myParams->getDouble(6); float scalemax = (float)myParams->getDouble(7); Vector3D blvec, brvec, tlvec; int key = 8; for (int i = 0; i < 3; ++i) { blvec[i] = (float)myParams->getDouble(key); ++key; } for (int i = 0; i < 3; ++i) { brvec[i] = (float)myParams->getDouble(key); ++key; } for (int i = 0; i < 3; ++i) { tlvec[i] = (float)myParams->getDouble(key); ++key; } AString outName = myParams->getString(17); Vector3D rightTraverse = brvec - blvec, upTraverse = tlvec - blvec; if (abs(rightTraverse.normal().dot(upTraverse.normal())) > 0.001f) { CaretLogWarning("corner points describe non-orthogonal directions, image will be skewed"); } float aspectRatio = (rightTraverse.length() / width) / (upTraverse.length() / height); if (aspectRatio > 1.001f || aspectRatio < 0.999f) { CaretLogWarning("corner points and image dimensions are different aspect ratios, image will be stretched"); } vector imageData(width * height * 4); for (int h = 0; h < height; ++h) { Vector3D rowStart = blvec + ((float)h) / (height - 1) * upTraverse; for (int w = 0; w < width; ++w) { Vector3D sample = rowStart + ((float)w) / (width - 1) * rightTraverse; bool valid = false; float value = myVol->interpolateValue(sample, myMethod, &valid, subvol); float normalized; if (valid) { if (value <= scalemin) { normalized = 0.0f; } else { if (value >= scalemax) { normalized = 1.0f; } else { normalized = (value - scalemin) / (scalemax - scalemin); } } } else { normalized = 0.0f; } uint8_t intensity = (uint8_t)(normalized * 255 + 0.5f); uint8_t* pixel = imageData.data() + (w + h * width) * 4; for (int i = 0; i < 4; ++i) { pixel[i] = intensity; } } } ImageFile outFile(imageData.data(), width, height, ImageFile::IMAGE_DATA_ORIGIN_AT_BOTTOM); outFile.writeFile(outName); } connectome-workbench-1.4.2/src/Operations/OperationVolumeCapturePlane.h000066400000000000000000000026601360521144700263560ustar00rootroot00000000000000#ifndef __OPERATION_VOLUME_CAPTURE_PLANE_H__ #define __OPERATION_VOLUME_CAPTURE_PLANE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationVolumeCapturePlane : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationVolumeCapturePlane; } #endif //__OPERATION_VOLUME_CAPTURE_PLANE_H__ connectome-workbench-1.4.2/src/Operations/OperationVolumeCopyExtensions.cxx000066400000000000000000000105061360521144700273360ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationVolumeCopyExtensions.h" #include "OperationException.h" #include "GiftiLabelTable.h" #include "GiftiMetaData.h" #include "NiftiHeader.h" //for NiftiExtension #include "PaletteColorMapping.h" #include "VolumeFile.h" using namespace caret; using namespace std; AString OperationVolumeCopyExtensions::getCommandSwitch() { return "-volume-copy-extensions"; } AString OperationVolumeCopyExtensions::getShortDescription() { return "COPY EXTENDED DATA TO ANOTHER VOLUME FILE"; } OperationParameters* OperationVolumeCopyExtensions::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "data-volume", "the volume file containing the voxel data to use"); ret->addVolumeParameter(2, "extension-volume", "the volume file containing the extensions to use"); ret->addVolumeOutputParameter(3, "volume-out", "the output volume"); ret->createOptionalParameter(4, "-drop-unknown", "don't copy extensions that workbench doesn't understand"); ret->setHelpText( AString("This command copies the information in a volume file that isn't a critical part of the standard header or data matrix, ") + "e.g. map names, palette settings, label tables. " + "If -drop-unknown is not specified, it also copies similar kinds of information set by other software." ); return ret; } void OperationVolumeCopyExtensions::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); VolumeFile* dataVol = myParams->getVolume(1); VolumeFile* extVol = myParams->getVolume(2); VolumeFile* outVol = myParams->getOutputVolume(3); bool dropUnknown = myParams->getOptionalParameter(4)->m_present; if (!dataVol->getVolumeSpace().matches(extVol->getVolumeSpace())) throw OperationException("volume spaces do not match"); vector dataDims = dataVol->getDimensions(); vector extDims = extVol->getDimensions(); if (dataDims[4] != extDims[4]) throw OperationException("number of components (rgb or complex datatypes) does not match"); if (dataVol->getOriginalDimensions() != extVol->getOriginalDimensions()) throw OperationException("non-spatial dimensions do not match"); outVol->reinitialize(dataVol->getOriginalDimensions(), dataVol->getSform(), dataDims[4], extVol->getType()); outVol->m_header.grabNew(extVol->m_header->clone());//copy all standard header fields, too if (dropUnknown) { switch (outVol->m_header->getType()) { case AbstractHeader::NIFTI: ((NiftiHeader*)outVol->m_header.getPointer())->m_extensions.clear(); break; } } if (outVol->getFileMetaData() != NULL) { *(outVol->getFileMetaData()) = *(extVol->getFileMetaData()); } for (int64_t c = 0; c < dataDims[4]; ++c) { for (int64_t b = 0; b < dataDims[3]; ++b) { if (c == 0)//map names, etc { outVol->setMapName(b, extVol->getMapName(b)); *(outVol->getMapMetaData(b)) = *(extVol->getMapMetaData(b)); if (extVol->getType() == SubvolumeAttributes::LABEL) { *(outVol->getMapLabelTable(b)) = *(extVol->getMapLabelTable(b)); } else { *(outVol->getMapPaletteColorMapping(b)) = *(extVol->getMapPaletteColorMapping(b)); } } outVol->setFrame(dataVol->getFrame(b, c), b, c); } } } connectome-workbench-1.4.2/src/Operations/OperationVolumeCopyExtensions.h000066400000000000000000000026741360521144700267720ustar00rootroot00000000000000#ifndef __OPERATION_VOLUME_COPY_EXTENSIONS_H__ #define __OPERATION_VOLUME_COPY_EXTENSIONS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationVolumeCopyExtensions : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationVolumeCopyExtensions; } #endif //__OPERATION_VOLUME_COPY_EXTENSIONS_H__ connectome-workbench-1.4.2/src/Operations/OperationVolumeCreate.cxx000066400000000000000000000137561360521144700255610ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationVolumeCreate.h" #include "OperationException.h" #include "FloatMatrix.h" #include "VolumeFile.h" using namespace caret; using namespace std; AString OperationVolumeCreate::getCommandSwitch() { return "-volume-create"; } AString OperationVolumeCreate::getShortDescription() { return "CREATE A BLANK VOLUME FILE"; } OperationParameters* OperationVolumeCreate::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addIntegerParameter(1, "i-dim", "length of first dimension"); ret->addIntegerParameter(2, "j-dim", "length of second dimension"); ret->addIntegerParameter(3, "k-dim", "length of third dimension"); ret->addVolumeOutputParameter(4, "volume-out", "the output volume"); OptionalParameter* plumbOpt = ret->createOptionalParameter(5, "-plumb", "set via axis order and spacing/offset"); plumbOpt->addStringParameter(1, "axis-order", "a string like 'XYZ' that specifies which index is along which spatial dimension"); plumbOpt->addDoubleParameter(2, "x-spacing", "change in x-coordinate from incrementing the relevant index"); plumbOpt->addDoubleParameter(3, "y-spacing", "change in y-coordinate from incrementing the relevant index"); plumbOpt->addDoubleParameter(4, "z-spacing", "change in z-coordinate from incrementing the relevant index"); plumbOpt->addDoubleParameter(5, "x-offset", "the x-coordinate of the center of the first voxel"); plumbOpt->addDoubleParameter(6, "y-offset", "the y-coordinate of the center of the first voxel"); plumbOpt->addDoubleParameter(7, "z-offset", "the z-coordinate of the center of the first voxel"); OptionalParameter* sformOpt = ret->createOptionalParameter(6, "-sform", "set via a nifti sform"); char axisNames[] = "xyz", indexNames[] = "ijk"; for (int axis = 0; axis < 3; ++axis) { for (int index = 0; index < 3; ++index) { sformOpt->addDoubleParameter(axis * 4 + index, AString(axisNames[axis]) + indexNames[index] + "-spacing", "increase in " + AString(axisNames[axis]) + " coordinate from incrementing the " + indexNames[index] + " index"); } sformOpt->addDoubleParameter(axis * 4 + 3, AString(axisNames[axis]) + "-offset", AString(axisNames[axis]) + " coordinate of first voxel"); } ret->setHelpText( AString("Creates a volume file full of zeros. ") + "Exactly one of -plumb or -sform must be specified." ); return ret; } void OperationVolumeCreate::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); vector dims(3); dims[0] = myParams->getInteger(1); dims[1] = myParams->getInteger(2); dims[2] = myParams->getInteger(3); VolumeFile* output = myParams->getOutputVolume(4); FloatMatrix newSform = FloatMatrix::zeros(4, 4); newSform[3][3] = 1.0f;//not needed, but just for sanity bool haveSpace = false; OptionalParameter* plumbOpt = myParams->getOptionalParameter(5); if (plumbOpt->m_present) { haveSpace = true; bool used[3] = {false, false, false}; int revorder[3] = {-1, -1, -1}; AString orient = plumbOpt->getString(1); if (orient.size() < 3) throw OperationException(" must have 3 characters"); for (int i = 0; i < 3; ++i) { int dir = -1; switch (orient[i].toLatin1()) { case 'X': case 'x': dir = 0; break; case 'Y': case 'y': dir = 1; break; case 'Z': case 'z': dir = 2; break; default: throw OperationException(" must use the characters X, Y, and Z"); } if (used[dir]) throw OperationException(" may not repeat an axis"); used[dir] = true; revorder[dir] = i;//construct the reversed order, because thats what we need } newSform[0][revorder[0]] = (float)plumbOpt->getDouble(2); newSform[0][3] = (float)plumbOpt->getDouble(5); newSform[1][revorder[1]] = (float)plumbOpt->getDouble(3); newSform[1][3] = (float)plumbOpt->getDouble(6); newSform[2][revorder[2]] = (float)plumbOpt->getDouble(4); newSform[2][3] = (float)plumbOpt->getDouble(7); } OptionalParameter* sformOpt = myParams->getOptionalParameter(6); if (sformOpt->m_present) { if (haveSpace) throw OperationException("only one of -plumb and -sform may be specified"); haveSpace = true; for (int axis = 0; axis < 3; ++axis) { for (int index = 0; index < 3; ++index) { newSform[axis][index] = (float)sformOpt->getDouble(axis * 4 + index); } newSform[axis][3] = (float)sformOpt->getDouble(axis * 4 + 3); } } if (!haveSpace) throw OperationException("you must specify -plumb or -sform"); output->reinitialize(dims, newSform.getMatrix()); output->setValueAllVoxels(0.0f); } connectome-workbench-1.4.2/src/Operations/OperationVolumeCreate.h000066400000000000000000000026111360521144700251720ustar00rootroot00000000000000#ifndef __OPERATION_VOLUME_CREATE_H__ #define __OPERATION_VOLUME_CREATE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationVolumeCreate : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationVolumeCreate; } #endif //__OPERATION_VOLUME_CREATE_H__ connectome-workbench-1.4.2/src/Operations/OperationVolumeLabelExportTable.cxx000066400000000000000000000071511360521144700275370ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationVolumeLabelExportTable.h" #include "OperationException.h" #include "GiftiLabel.h" //we should rename these to not imply that they are gifti-specific #include "GiftiLabelTable.h" #include "VolumeFile.h" #include #include using namespace caret; using namespace std; AString OperationVolumeLabelExportTable::getCommandSwitch() { return "-volume-label-export-table"; } AString OperationVolumeLabelExportTable::getShortDescription() { return "EXPORT LABEL TABLE FROM VOLUME AS TEXT"; } OperationParameters* OperationVolumeLabelExportTable::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "label-in", "the input volume label file"); ret->addStringParameter(2, "map", "the number or name of the label map to use"); ret->addStringParameter(3, "table-out", "output - the output text file");//fake output formatting ret->setHelpText( AString("Takes the label table from the volume label map, and writes it to a text format matching what is expected by -volume-label-import.") ); return ret; } int OperationVolumeLabelExportTable::floatTo255(const float& in) { return (int)floor(in * 255.0f + 0.5f); } void OperationVolumeLabelExportTable::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); VolumeFile* myVolume = myParams->getVolume(1); AString mapString = myParams->getString(2); AString outfileName = myParams->getString(3); if (myVolume->getType() != SubvolumeAttributes::LABEL) throw OperationException("volume file must be a label volume"); int64_t mapIndex = myVolume->getMapIndexFromNameOrNumber(mapString); if (mapIndex == -1) throw OperationException("map '" + mapString + "' not found"); ofstream outFile(outfileName.toLocal8Bit().constData()); if (!outFile) throw OperationException("failed to open output text file"); const GiftiLabelTable* myTable = myVolume->getMapLabelTable(mapIndex); set allKeys = myTable->getKeys(); int32_t unassignedKey = myTable->getUnassignedLabelKey(); for (set::iterator iter = allKeys.begin(); iter != allKeys.end(); ++iter) { if (*iter == unassignedKey) continue;//don't output the unused key, because import doesn't want it in the text file const GiftiLabel* thisLabel = myTable->getLabel(*iter); outFile << thisLabel->getName() << endl; outFile << thisLabel->getKey() << " " << floatTo255(thisLabel->getRed()) << " " << floatTo255(thisLabel->getGreen()) << " " << floatTo255(thisLabel->getBlue()) << " " << floatTo255(thisLabel->getAlpha()) << endl; if (!outFile) throw OperationException("error writing to output text file"); } } connectome-workbench-1.4.2/src/Operations/OperationVolumeLabelExportTable.h000066400000000000000000000027731360521144700271710ustar00rootroot00000000000000#ifndef __OPERATION_VOLUME_LABEL_EXPORT_TABLE_H__ #define __OPERATION_VOLUME_LABEL_EXPORT_TABLE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationVolumeLabelExportTable : public AbstractOperation { static int floatTo255(const float& in); public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationVolumeLabelExportTable; } #endif //__OPERATION_VOLUME_LABEL_EXPORT_TABLE_H__ connectome-workbench-1.4.2/src/Operations/OperationVolumeLabelImport.cxx000066400000000000000000000430721360521144700265620ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationVolumeLabelImport.h" #include "OperationException.h" #include "CaretLogger.h" #include "FileInformation.h" #include "GiftiLabel.h" #include "VolumeFile.h" #include #include #include #include #include #include #include using namespace caret; using namespace std; AString OperationVolumeLabelImport::getCommandSwitch() { return "-volume-label-import"; } AString OperationVolumeLabelImport::getShortDescription() { return "IMPORT A LABEL VOLUME TO WORKBENCH FORMAT"; } OperationParameters* OperationVolumeLabelImport::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "input", "the input volume file"); ret->addStringParameter(2, "label-list-file", "text file containing the values and names for labels"); ret->addVolumeOutputParameter(3, "output", "the output workbench label volume"); ret->createOptionalParameter(4, "-discard-others", "set any voxels with values not mentioned in the label list to the ??? label"); OptionalParameter* unlabeledOption = ret->createOptionalParameter(5, "-unlabeled-value", "set the value that will be interpreted as unlabeled"); unlabeledOption->addIntegerParameter(1, "value", "the numeric value for unlabeled (default 0)"); OptionalParameter* subvolumeSelect = ret->createOptionalParameter(6, "-subvolume", "select a single subvolume to import"); subvolumeSelect->addStringParameter(1, "subvol", "the subvolume number or name"); ret->createOptionalParameter(7, "-drop-unused-labels", "remove any unused label values from the label table"); ret->setHelpText( AString("Creates a label volume from an integer-valued volume file. ") + "The label name and color information is stored in the volume header in a nifti extension, with a similar format as in caret5, see -volume-help. " + "You may specify the empty string (use \"\") for , which will be treated as if it is an empty file. " + "The label list file must have the following format (2 lines per label):\n\n" + "\n \n...\n\n" + "Label names are specified on a separate line from their value and color, in order to let label names contain spaces. " + "Whitespace is trimmed from both ends of the label name, but is kept if it is in the middle of a label. " + "Do not specify the \"unlabeled\" key in the file, it is assumed that 0 means not labeled unless -unlabeled-value is specified. " + "The value of specifies what value in the imported file should be used as this label. " + "The values of , , and must be integers from 0 to 255, and will specify the color the label is drawn as " + "(alpha of 255 means fully opaque, which is probably what you want).\n\n" + "By default, it will create new label names with names like LABEL_5 for any values encountered that are not mentioned in the " + "list file, specify -discard-others to instead set these values to the \"unlabeled\" key." ); return ret; } void OperationVolumeLabelImport::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { AString temp; LevelProgress myProgress(myProgObj); VolumeFile* myVol = myParams->getVolume(1); AString listfileName = myParams->getString(2); VolumeFile* outVol = myParams->getOutputVolume(3); bool discardOthers = false; OptionalParameter* discardOption = myParams->getOptionalParameter(4); if (discardOption->m_present) { discardOthers = true; } int32_t unlabeledValue = 0; OptionalParameter* unlabeledOption = myParams->getOptionalParameter(5); if (unlabeledOption->m_present) { unlabeledValue = (int32_t)unlabeledOption->getInteger(1); } OptionalParameter* subvolumeSelect = myParams->getOptionalParameter(6); int subvol = -1; if (subvolumeSelect->m_present) {//set up to use the single column subvol = (int)myVol->getMapIndexFromNameOrNumber(subvolumeSelect->getString(1)); if (subvol < 0 || subvol >= myVol->getNumberOfMaps()) { throw OperationException("invalid column specified"); } } bool dropUnused = myParams->getOptionalParameter(7)->m_present; GiftiLabelTable myTable; map translate; if (listfileName != "") { FileInformation textFileInfo(listfileName); if (!textFileInfo.exists()) { throw OperationException("label list file doesn't exist"); } fstream labelListFile(listfileName.toLocal8Bit().constData(), fstream::in); if (!labelListFile.good()) { throw OperationException("error reading label list file"); } string labelName; int32_t value, red, green, blue, alpha; int labelCount = 0; translate[unlabeledValue] = 0;//placeholder, we don't know the correct translated value yet while (labelListFile.good()) { ++labelCount;//just for error messages, so start at 1 getline(labelListFile, labelName); labelListFile >> value; if (labelListFile.eof() && labelName == "") break;//if end of file trying to read an int, and label name is empty, its really just end of file labelListFile >> red; labelListFile >> green; labelListFile >> blue; if (!(labelListFile >> alpha))//yes, that is seriously the correct way to check if input was successfully extracted...so much fail { throw OperationException("label list file is malformed for entry #" + AString::number(labelCount) + ": " + AString(labelName.c_str())); } if (red < 0 || red > 255) { throw OperationException("bad value for red for entry #" + AString::number(labelCount) + ", " + AString(labelName.c_str()) + ": " + AString::number(red)); } if (green < 0 || green > 255) { throw OperationException("bad value for green for entry #" + AString::number(labelCount) + ", " + AString(labelName.c_str()) + ": " + AString::number(green)); } if (blue < 0 || blue > 255) { throw OperationException("bad value for blue for entry #" + AString::number(labelCount) + ", " + AString(labelName.c_str()) + ": " + AString::number(blue)); } if (alpha < 0 || alpha > 255) { throw OperationException("bad value for alpha for entry #" + AString::number(labelCount) + ", " + AString(labelName.c_str()) + ": " + AString::number(alpha)); } if (value == GiftiLabel::getInvalidLabelKey()) { throw OperationException("entry #" + AString::number(labelCount) + ", " + AString(labelName.c_str()) + " specifies unusable key value: " + value); } while (isspace(labelListFile.peek())) { labelListFile.ignore();//drop the newline, possible carriage return or other whitespace so that getline doesn't get nothing, and cause int extraction to fail } temp = AString(labelName.c_str()).trimmed();//drop errant CR or other whitespace from beginning and end of lines if (translate.find(value) != translate.end()) { if (value == unlabeledValue) { throw OperationException("the unlabeled value must not be specified in label list file"); } else { throw OperationException(AString("label key ") + AString::number(value) + " specified more than once"); } } GiftiLabel myLabel(value, temp, red, green, blue, alpha); if (myTable.getLabelKeyFromName(temp) != GiftiLabel::getInvalidLabelKey()) { AString nameBase = temp, newName;//resolve collision by generating a name with an additional number on it bool success = false; for (int extra = 1; extra < 100; ++extra)//but stop at 100, because really... { newName = nameBase + "_" + AString::number(extra); if (myTable.getLabelKeyFromName(newName) == GiftiLabel::getInvalidLabelKey()) { success = true; break; } } if (success) { CaretLogWarning("name collision in input name '" + nameBase + "', changing one to '" + newName + "'"); } else { throw OperationException("giving up on resolving name collision for input name '" + nameBase + "'"); } myLabel.setName(newName); } int32_t newValue; if (value == 0)//because label 0 exists in the default constructed table { myTable.insertLabel(&myLabel);//but we do want to be able to overwrite the default 0 label newValue = 0;//if value 0 is specified twice, or once without specifying a different unlabeled value, the check versus the translate map will catch it } else { newValue = myTable.addLabel(&myLabel);//we don't want to overwrite relocated labels } translate[value] = newValue; } } vector myDims; myVol->getDimensions(myDims); const int64_t FRAMESIZE = myDims[0] * myDims[1] * myDims[2]; CaretArray frameOut(FRAMESIZE); int32_t unusedLabel = myTable.getUnassignedLabelKey(); translate[unlabeledValue] = unusedLabel; if (subvol == -1) { outVol->reinitialize(myVol->getOriginalDimensions(), myVol->getSform(), myDims[4], SubvolumeAttributes::LABEL); for (int s = 0; s < myDims[3]; ++s) { set usedValues;//track used values if we have dropUnused for (int c = 0; c < myDims[4]; ++c)//hopefully noone wants a multi-component label volume, that would be silly, but do it anyway { const float* frameIn = myVol->getFrame(s, c);//TODO: rework this when support is added for VolumeFile to handle non-float data for (int i = 0; i < FRAMESIZE; ++i) { int32_t labelval = (int32_t)floor(frameIn[i] + 0.5f);//just in case it somehow got poorly encoded, round to nearest if (dropUnused) { usedValues.insert(labelval); } map::iterator myiter = translate.find(labelval); if (myiter == translate.end()) { if (discardOthers) { frameOut[i] = unusedLabel; } else {//use a random color, but fully opaque for the label GiftiLabel myLabel(labelval, AString("LABEL_") + AString::number(labelval), rand() & 255, rand() & 255, rand() & 255, 255); if (myTable.getLabelKeyFromName(myLabel.getName()) != GiftiLabel::getInvalidLabelKey()) { AString nameBase = myLabel.getName(), newName;//resolve collision by generating a name with an additional number on it bool success = false; for (int extra = 1; extra < 100; ++extra)//but stop at 100, because really... { newName = nameBase + "_" + AString::number(extra); if (myTable.getLabelKeyFromName(newName) == GiftiLabel::getInvalidLabelKey()) { success = true; break; } } if (success) { CaretLogWarning("name collision in auto-generated name '" + nameBase + "', changed to '" + newName + "'"); } else { throw OperationException("giving up on resolving name collision for auto-generated name '" + nameBase + "'"); } myLabel.setName(newName); } int32_t newValue = myTable.addLabel(&myLabel);//don't overwrite any values in the table translate[labelval] = newValue; frameOut[i] = newValue; } } else { frameOut[i] = myiter->second; } } outVol->setFrame(frameOut, s, c); } if (dropUnused) { GiftiLabelTable frameTable = myTable; frameTable.deleteUnusedLabels(usedValues); *(outVol->getMapLabelTable(s)) = frameTable; } else { *(outVol->getMapLabelTable(s)) = myTable;//set the label table AFTER doing the frame, because we may make new labels while scanning } } } else { vector newDims = myDims; newDims.resize(3);//spatial only outVol->reinitialize(newDims, myVol->getSform(), myDims[4], SubvolumeAttributes::LABEL); set usedValues;//track used values if we have dropUnused for (int c = 0; c < myDims[4]; ++c)//hopefully noone wants a multi-component label volume, that would be silly, but do it anyway { const float* frameIn = myVol->getFrame(subvol, c);//TODO: rework this when support is added for VolumeFile to handle non-float data for (int i = 0; i < FRAMESIZE; ++i) { int32_t labelval = (int32_t)floor(frameIn[i] + 0.5f);//just in case it somehow got poorly encoded, round to nearest if (dropUnused) { usedValues.insert(labelval); } map::iterator myiter = translate.find(labelval); if (myiter == translate.end()) { if (discardOthers) { frameOut[i] = unusedLabel; } else {//use a random color, but fully opaque for the label GiftiLabel myLabel(labelval, AString("LABEL_") + AString::number(labelval), rand() & 255, rand() & 255, rand() & 255, 255); if (myTable.getLabelKeyFromName(myLabel.getName()) != GiftiLabel::getInvalidLabelKey()) { AString nameBase = myLabel.getName(), newName;//resolve collision by generating a name with an additional number on it bool success = false; for (int extra = 1; extra < 100; ++extra)//but stop at 100, because really... { newName = nameBase + "_" + AString::number(extra); if (myTable.getLabelKeyFromName(newName) == GiftiLabel::getInvalidLabelKey()) { success = true; break; } } if (success) { CaretLogWarning("name collision in auto-generated name '" + nameBase + "', changed to '" + newName + "'"); } else { throw OperationException("giving up on resolving name collision for auto-generated name '" + nameBase + "'"); } myLabel.setName(newName); } int32_t newValue = myTable.addLabel(&myLabel);//don't overwrite any values in the table translate[labelval] = newValue; frameOut[i] = newValue; } } else { frameOut[i] = myiter->second; } } outVol->setFrame(frameOut, 0, c); } if (dropUnused) { GiftiLabelTable frameTable = myTable; frameTable.deleteUnusedLabels(usedValues); *(outVol->getMapLabelTable(0)) = frameTable; } else { *(outVol->getMapLabelTable(0)) = myTable;//set the label table AFTER doing the frame, because we may make new labels while scanning } } } connectome-workbench-1.4.2/src/Operations/OperationVolumeLabelImport.h000066400000000000000000000026521360521144700262060ustar00rootroot00000000000000#ifndef __OPERATION_VOLUME_LABEL_IMPORT_H__ #define __OPERATION_VOLUME_LABEL_IMPORT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationVolumeLabelImport : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationVolumeLabelImport; } #endif //__OPERATION_VOLUME_LABEL_IMPORT_H__ connectome-workbench-1.4.2/src/Operations/OperationVolumeMath.cxx000066400000000000000000000263241360521144700252420ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationVolumeMath.h" #include "OperationException.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "CaretMathExpression.h" #include "VolumeFile.h" #include using namespace caret; using namespace std; AString OperationVolumeMath::getCommandSwitch() { return "-volume-math"; } AString OperationVolumeMath::getShortDescription() { return "EVALUATE EXPRESSION ON VOLUME FILES"; } OperationParameters* OperationVolumeMath::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "expression", "the expression to evaluate, in quotes"); ret->addVolumeOutputParameter(2, "volume-out", "the output volume"); ParameterComponent* varOpt = ret->createRepeatableParameter(3, "-var", "a volume file to use as a variable"); varOpt->addStringParameter(1, "name", "the name of the variable, as used in the expression"); varOpt->addVolumeParameter(2, "volume", "the volume file to use as this variable"); OptionalParameter* subvolSelect = varOpt->createOptionalParameter(3, "-subvolume", "select a single subvolume"); subvolSelect->addStringParameter(1, "subvol", "the subvolume number or name"); varOpt->createOptionalParameter(4, "-repeat", "reuse a single subvolume for each subvolume of calculation"); OptionalParameter* fixNanOpt = ret->createOptionalParameter(4, "-fixnan", "replace NaN results with a value"); fixNanOpt->addDoubleParameter(1, "replace", "value to replace NaN with"); AString myText = AString("This command evaluates at each voxel independently. ") + "There must be at least one -var option (to get the volume space from), even if the specified in it isn't used in . " + "All volumes must have the same volume space. " + "Filenames are not valid in , use a variable name and a -var option with matching to specify an input file. " + "If the -subvolume option is given to any -var option, only one subvolume is used from that file. " + "If -repeat is specified, the file must either have only one subvolume, or have the -subvolume option specified. " + "All files that don't use -repeat must have the same number of subvolumes requested to be used. " + "The format of is as follows:\n\n"; myText += CaretMathExpression::getExpressionHelpInfo(); ret->setHelpText(myText); return ret; } void OperationVolumeMath::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString expression = myParams->getString(1); CaretMathExpression myExpr(expression); cout << "parsed '" + expression + "' as '" + myExpr.toString() + "'" << endl; vector myVarNames = myExpr.getVarNames(); VolumeFile* myVolOut = myParams->getOutputVolume(2); const vector& myVarOpts = *(myParams->getRepeatableParameterInstances(3)); OptionalParameter* fixNanOpt = myParams->getOptionalParameter(4); bool nanfix = false; float nanfixval = 0; if (fixNanOpt->m_present) { nanfix = true; nanfixval = (float)fixNanOpt->getDouble(1); } int numInputs = myVarOpts.size(); int numVars = myVarNames.size(); vector varVolumes(numVars, NULL); vector varSubvolumes(numVars, -1); if (numInputs == 0 && numVars == 0) throw OperationException("you must specify at least one input volume (-var), even if the expression doesn't use a variable"); VolumeFile* first = NULL, *namefile = NULL; VolumeSpace mySpace; vector outDims; int numSubvols = -1; VolumeFile* toClone = NULL; float headerScore = -1.0f;//used to prioritize which input file to clone the header from for (int i = 0; i < numInputs; ++i) { float thisHeaderScore = 3.0f;//default to high priority, -select and -repeat reduce priority if (i == 0) { first = myVarOpts[0]->getVolume(2); mySpace = first->getVolumeSpace(); } AString varName = myVarOpts[i]->getString(1); double constVal; if (CaretMathExpression::getNamedConstant(varName, constVal)) { throw OperationException("'" + varName + "' is a named constant equal to " + AString::number(constVal, 'g', 15) + ", please use a different variable name"); } VolumeFile* thisVolume = myVarOpts[i]->getVolume(2); if (thisVolume->getNumberOfComponents() != 1) { throw OperationException("volume file for variable '" + varName + "' has multiple components, this is not currently supported in -volume-math"); } int thisSubvols = thisVolume->getNumberOfMaps(); OptionalParameter* subvolSelect = myVarOpts[i]->getOptionalParameter(3); int useSubvolume = -1; if (subvolSelect->m_present) { thisSubvols = 1; useSubvolume = thisVolume->getMapIndexFromNameOrNumber(subvolSelect->getString(1)); if (useSubvolume == -1) throw OperationException("could not find map '" + subvolSelect->getString(1) + "' in volume file for '" + varName + "'"); thisHeaderScore = 2.0f;//give -select more priority over -repeat? may not matter... } bool repeat = myVarOpts[i]->getOptionalParameter(4)->m_present; if (repeat) thisHeaderScore = 1.0f; if (!thisVolume->matchesVolumeSpace(mySpace)) { throw OperationException("volume file for variable '" + varName + "' has different volume space than the first volume file"); } if (repeat) { if (thisSubvols != 1) { throw OperationException("-repeat specified without -subvolume for variable '" + varName + "', but volume file has " + AString::number(thisSubvols) + " subvolumes"); } if (useSubvolume == -1) useSubvolume = 0;//-1 means use same input subvolume as current output subvolume, so we need to fix the special case of -repeat on single subvolume file without -subvolume } else { if (numSubvols == -1)//then this is the first one that doesn't use -repeat { numSubvols = thisSubvols; outDims = thisVolume->getOriginalDimensions(); if (useSubvolume == -1) { namefile = thisVolume;//if it also doesn't use -subvolume, take map names from it } else { outDims.resize(3);//change to output only one subvolume in the simplest way } } else { if (numSubvols != thisSubvols) { if (useSubvolume == -1) { throw OperationException("volume file for variable '" + varName + "' has " + AString::number(thisSubvols) + " subvolume(s), but previous volume files have " + AString::number(numSubvols) + " subvolume(s) requested to be used"); } else { throw OperationException("-subvolume specified without -repeat for variable '" + varName + "', but previous volume files have have " + AString::number(numSubvols) + " subvolumes requested to be used"); } } } } bool found = false; for (int j = 0; j < numVars; ++j) { if (varName == myVarNames[j]) { if (varVolumes[j] != NULL) throw OperationException("variable '" + varName + "' specified more than once"); varVolumes[j] = thisVolume; varSubvolumes[j] = useSubvolume; found = true; break; } } if (!found && (numVars != 0 || numInputs != 1))//supress warning when a single -var is used with a constant expression, as required per help {//don't reduce header score for not being used, less confusion, and allows the file that sets the length of output to also set the timestep CaretLogWarning("variable '" + varName + "' not used in expression"); } if (thisVolume->m_header == NULL) thisHeaderScore = 0.1f;//very small priority if it doesn't even have a header somehow (for instance, if we ever add GUI use of these things) if (thisHeaderScore > headerScore) { headerScore = thisHeaderScore; toClone = thisVolume; } } for (int i = 0; i < numVars; ++i) { if (varVolumes[i] == NULL) throw OperationException("no -var option specified for variable '" + myVarNames[i] + "'"); } if (numSubvols == -1) { throw OperationException("all -var options used -repeat, there is no file to get number of desired output subvolumes from"); } int64_t frameSize = outDims[0] * outDims[1] * outDims[2]; vector values(numVars), outFrame(frameSize); vector inputFrames(numVars); if (toClone != NULL) {//don't take volume type from the selected volume, because we don't check for or copy label tables, nor do we want to (might be changing all the label keys, splitting label by roi...) myVolOut->reinitialize(outDims, first->getSform(), 1, SubvolumeAttributes::SubvolumeAttributes::ANATOMY, toClone->m_header); } else { myVolOut->reinitialize(outDims, first->getSform()); } for (int s = 0; s < numSubvols; ++s) { if (namefile != NULL) myVolOut->setMapName(s, namefile->getMapName(s)); for (int v = 0; v < numVars; ++v) { if (varSubvolumes[v] == -1) { inputFrames[v] = varVolumes[v]->getFrame(s); } else { inputFrames[v] = varVolumes[v]->getFrame(varSubvolumes[v]); } } for (int64_t i = 0; i < frameSize; ++i) { for (int v = 0; v < numVars; ++v) { values[v] = inputFrames[v][i]; } float tempf = (float)myExpr.evaluate(values); if (nanfix && tempf != tempf) { tempf = nanfixval; } outFrame[i] = tempf; } myVolOut->setFrame(outFrame.data(), s); } } connectome-workbench-1.4.2/src/Operations/OperationVolumeMath.h000066400000000000000000000025751360521144700246710ustar00rootroot00000000000000#ifndef __OPERATION_VOLUME_MATH_H__ #define __OPERATION_VOLUME_MATH_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationVolumeMath : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationVolumeMath; } #endif //__OPERATION_VOLUME_MATH_H__ connectome-workbench-1.4.2/src/Operations/OperationVolumeMerge.cxx000066400000000000000000000233751360521144700254130ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationVolumeMerge.h" #include "OperationException.h" #include "CaretAssert.h" #include "GiftiLabelTable.h" #include "PaletteColorMapping.h" #include "VolumeFile.h" using namespace caret; using namespace std; AString OperationVolumeMerge::getCommandSwitch() { return "-volume-merge"; } AString OperationVolumeMerge::getShortDescription() { return "MERGE VOLUME FILES INTO A NEW FILE"; } OperationParameters* OperationVolumeMerge::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeOutputParameter(1, "volume-out", "the output volume file"); ParameterComponent* volumeOpt = ret->createRepeatableParameter(2, "-volume", "specify an input volume file"); volumeOpt->addVolumeParameter(1, "volume-in", "a volume file to use subvolumes from"); ParameterComponent* subvolOpt = volumeOpt->createRepeatableParameter(2, "-subvolume", "select a single subvolume to use"); subvolOpt->addStringParameter(1, "subvol", "the subvolume number or name"); OptionalParameter* upToOpt = subvolOpt->createOptionalParameter(2, "-up-to", "use an inclusive range of subvolumes"); upToOpt->addStringParameter(1, "last-subvol", "the number or name of the last subvolume to include"); upToOpt->createOptionalParameter(2, "-reverse", "use the range in reverse order"); ret->setHelpText( AString("Takes one or more volume files and constructs a new volume file by concatenating subvolumes from them. ") + "The input volume files must have the same volume space.\n\n" + "Example: wb_command -volume-merge out.nii -volume first.nii -subvolume 1 -volume second.nii\n\n" + "This example would take the first subvolume from first.nii, followed by all subvolumes from second.nii, " + "and write these to out.nii." ); return ret; } void OperationVolumeMerge::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); VolumeFile* volumeOut = myParams->getOutputVolume(1); const vector& myInputs = *(myParams->getRepeatableParameterInstances(2)); int numInputs = (int)myInputs.size(); if (numInputs < 1) throw OperationException("no inputs specified"); int64_t subvolCount = 0; const VolumeFile* firstVol = myInputs[0]->getVolume(1); vector firstDims = firstVol->getDimensions(); bool isLabel = (firstVol->getType() == SubvolumeAttributes::LABEL); for (int i = 0; i < numInputs; ++i) { const VolumeFile* myVol = myInputs[i]->getVolume(1); if (!myVol->matchesVolumeSpace(firstVol)) { throw OperationException("volume file '" + myVol->getFileName() + "' has a different volume space"); } if (isLabel != (myVol->getType() == SubvolumeAttributes::LABEL)) { throw OperationException("only some volumes are label volumes, first mismatch is '" + myVol->getFileName() + "'"); } vector thisDims = myVol->getDimensions(); if (thisDims[4] != firstDims[4]) throw ("volume file '" + myVol->getFileName() + "' has a different number of components"); const vector& subvolOpts = *(myInputs[i]->getRepeatableParameterInstances(2)); int numSubvolOpts = (int)subvolOpts.size(); if (numSubvolOpts > 0) { for (int j = 0; j < numSubvolOpts; ++j) { int64_t initialFrame = myVol->getMapIndexFromNameOrNumber(subvolOpts[j]->getString(1)); if (initialFrame < 0) throw OperationException("subvolume '" + subvolOpts[j]->getString(1) + "' not found in file '" + myVol->getFileName() + "'"); OptionalParameter* upToOpt = subvolOpts[j]->getOptionalParameter(2); if (upToOpt->m_present) { int64_t finalFrame = myVol->getMapIndexFromNameOrNumber(upToOpt->getString(1)); if (finalFrame < 0) throw OperationException("ending subvolume '" + upToOpt->getString(1) + "' not found in file '" + myVol->getFileName() + "'"); if (finalFrame < initialFrame) throw OperationException("ending subvolume '" + upToOpt->getString(1) + "' occurs before starting subvolume '" + subvolOpts[j]->getString(1) + "' in file '" + myVol->getFileName() + "'"); subvolCount += finalFrame - initialFrame + 1;//inclusive - we don't need to worry about reversing for counting, though } else { subvolCount += 1; } } } else { subvolCount += myVol->getNumberOfMaps(); } } vector outDims = firstVol->getOriginalDimensions(); outDims.resize(4); outDims[3] = subvolCount; volumeOut->reinitialize(outDims, firstVol->getSform(), firstDims[4], firstVol->getType(), firstVol->m_header); int64_t curOutVol = 0; for (int i = 0; i < numInputs; ++i) { const VolumeFile* myVol = myInputs[i]->getVolume(1); const vector& subvolOpts = *(myInputs[i]->getRepeatableParameterInstances(2)); int numSubvolOpts = (int)subvolOpts.size(); if (numSubvolOpts > 0) { for (int j = 0; j < numSubvolOpts; ++j) { int64_t initialFrame = myVol->getMapIndexFromNameOrNumber(subvolOpts[j]->getString(1)); OptionalParameter* upToOpt = subvolOpts[j]->getOptionalParameter(2); if (upToOpt->m_present) { int64_t finalFrame = myVol->getMapIndexFromNameOrNumber(upToOpt->getString(1)); bool reverse = upToOpt->getOptionalParameter(2)->m_present; if (reverse) { for (int64_t b = finalFrame; b >= initialFrame; --b) { for (int64_t c = 0; c < firstDims[4]; ++c) { volumeOut->setFrame(myVol->getFrame(b, c), curOutVol, c); } volumeOut->setMapName(curOutVol, myVol->getMapName(b)); if (isLabel) { *(volumeOut->getMapLabelTable(curOutVol)) = *(myVol->getMapLabelTable(b)); } else { *(volumeOut->getMapPaletteColorMapping(curOutVol)) = *(myVol->getMapPaletteColorMapping(b)); } ++curOutVol; } } else { for (int64_t b = initialFrame; b <= finalFrame; ++b) { for (int64_t c = 0; c < firstDims[4]; ++c) { volumeOut->setFrame(myVol->getFrame(b, c), curOutVol, c); } volumeOut->setMapName(curOutVol, myVol->getMapName(b)); if (isLabel) { *(volumeOut->getMapLabelTable(curOutVol)) = *(myVol->getMapLabelTable(b)); } else { *(volumeOut->getMapPaletteColorMapping(curOutVol)) = *(myVol->getMapPaletteColorMapping(b)); } ++curOutVol; } } } else { for (int64_t c = 0; c < firstDims[4]; ++c) { volumeOut->setFrame(myVol->getFrame(initialFrame, c), curOutVol, c); } volumeOut->setMapName(curOutVol, myVol->getMapName(initialFrame)); if (isLabel) { *(volumeOut->getMapLabelTable(curOutVol)) = *(myVol->getMapLabelTable(initialFrame)); } else { *(volumeOut->getMapPaletteColorMapping(curOutVol)) = *(myVol->getMapPaletteColorMapping(initialFrame)); } ++curOutVol; } } } else { vector myDims = myVol->getDimensions(); for (int64_t b = 0; b < myDims[3]; ++b) { for (int64_t c = 0; c < firstDims[4]; ++c) { volumeOut->setFrame(myVol->getFrame(b, c), curOutVol, c); } volumeOut->setMapName(curOutVol, myVol->getMapName(b)); if (isLabel) { *(volumeOut->getMapLabelTable(curOutVol)) = *(myVol->getMapLabelTable(b)); } else { *(volumeOut->getMapPaletteColorMapping(curOutVol)) = *(myVol->getMapPaletteColorMapping(b)); } ++curOutVol; } } } CaretAssert(curOutVol == subvolCount); } connectome-workbench-1.4.2/src/Operations/OperationVolumeMerge.h000066400000000000000000000026031360521144700250270ustar00rootroot00000000000000#ifndef __OPERATION_VOLUME_MERGE_H__ #define __OPERATION_VOLUME_MERGE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationVolumeMerge : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationVolumeMerge; } #endif //__OPERATION_VOLUME_MERGE_H__ connectome-workbench-1.4.2/src/Operations/OperationVolumePalette.cxx000066400000000000000000000263511360521144700257470ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationVolumePalette.h" #include "OperationException.h" #include "Palette.h" #include "PaletteColorMapping.h" #include "PaletteFile.h" #include "VolumeFile.h" using namespace caret; using namespace std; AString OperationVolumePalette::getCommandSwitch() { return "-volume-palette"; } AString OperationVolumePalette::getShortDescription() { return "SET THE PALETTE OF A VOLUME FILE"; } OperationParameters* OperationVolumePalette::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "volume", "the volume file to modify"); ret->addStringParameter(2, "mode", "the mapping mode"); OptionalParameter* subvolumeSelect = ret->createOptionalParameter(3, "-subvolume", "select a single subvolume"); subvolumeSelect->addStringParameter(1, "subvolume", "the subvolume number or name"); OptionalParameter* posMinMaxPercent = ret->createOptionalParameter(4, "-pos-percent", "percentage min/max for positive data coloring"); posMinMaxPercent->addDoubleParameter(1, "pos-min-%", "the percentile for the least positive data"); posMinMaxPercent->addDoubleParameter(2, "pos-max-%", "the percentile for the most positive data"); OptionalParameter* negMinMaxPercent = ret->createOptionalParameter(5, "-neg-percent", "percentage min/max for negative data coloring"); negMinMaxPercent->addDoubleParameter(1, "neg-min-%", "the percentile for the least negative data"); negMinMaxPercent->addDoubleParameter(2, "neg-max-%", "the percentile for the most negative data"); OptionalParameter* posMinMaxValue = ret->createOptionalParameter(11, "-pos-user", "user min/max values for positive data coloring"); posMinMaxValue->addDoubleParameter(1, "pos-min-user", "the value for the least positive data"); posMinMaxValue->addDoubleParameter(2, "pos-max-user", "the value for the most positive data"); OptionalParameter* negMinMaxValue = ret->createOptionalParameter(12, "-neg-user", "user min/max values for negative data coloring"); negMinMaxValue->addDoubleParameter(1, "neg-min-user", "the value for the least negative data"); negMinMaxValue->addDoubleParameter(2, "neg-max-user", "the value for the most negative data"); OptionalParameter* interpolate = ret->createOptionalParameter(9, "-interpolate", "interpolate colors"); interpolate->addBooleanParameter(1, "interpolate", "boolean, whether to interpolate"); OptionalParameter* displayPositive = ret->createOptionalParameter(6, "-disp-pos", "display positive data"); displayPositive->addBooleanParameter(1, "display", "boolean, whether to display"); OptionalParameter* displayNegative = ret->createOptionalParameter(7, "-disp-neg", "display positive data"); displayNegative->addBooleanParameter(1, "display", "boolean, whether to display"); OptionalParameter* displayZero = ret->createOptionalParameter(8, "-disp-zero", "display data closer to zero than the min cutoff"); displayZero->addBooleanParameter(1, "display", "boolean, whether to display"); OptionalParameter* paletteName = ret->createOptionalParameter(10, "-palette-name", "set the palette used"); paletteName->addStringParameter(1, "name", "the name of the palette"); OptionalParameter* thresholdOpt = ret->createOptionalParameter(13, "-thresholding", "set the thresholding"); thresholdOpt->addStringParameter(1, "type", "thresholding setting"); thresholdOpt->addStringParameter(2, "test", "show values inside or outside thresholds"); thresholdOpt->addDoubleParameter(3, "min", "lower threshold"); thresholdOpt->addDoubleParameter(4, "max", "upper threshold"); OptionalParameter* inversionOpt = ret->createOptionalParameter(15, "-inversion", "specify palette inversion"); inversionOpt->addStringParameter(1, "type", "the type of inversion"); AString myText = AString("The original volume file is overwritten with the modified version. By default, all columns of the volume file are adjusted ") + "to the new settings, use the -subvolume option to change only one subvolume. Mapping settings not specified in options will be taken from the first subvolume. " + "The argument must be one of the following:\n\n"; vector myEnums; PaletteScaleModeEnum::getAllEnums(myEnums); for (int i = 0; i < (int)myEnums.size(); ++i) { myText += PaletteScaleModeEnum::toName(myEnums[i]) + "\n"; } myText += "\nThe argument to -palette-name must be one of the following:\n\n"; PaletteFile myPF; int32_t numPalettes = myPF.getNumberOfPalettes(); for (int i = 0; i < numPalettes; ++i) { myText += myPF.getPalette(i)->getName() + "\n"; } myText += "\nThe argument to -thresholding must be one of the following:\n\n"; vector myEnums2; PaletteThresholdTypeEnum::getAllEnums(myEnums2); for (int i = 0; i < (int)myEnums2.size(); ++i) { myText += PaletteThresholdTypeEnum::toName(myEnums2[i]) + "\n"; } myText += "\nThe argument to -thresholding must be one of the following:\n\n"; vector myEnums3; PaletteThresholdTestEnum::getAllEnums(myEnums3); for (int i = 0; i < (int)myEnums3.size(); ++i) { myText += PaletteThresholdTestEnum::toName(myEnums3[i]) + "\n"; } myText += "\nThe argument to -inversion must be one of the following:\n\n"; vector myEnums4; PaletteInvertModeEnum::getAllEnums(myEnums4); for (int i = 0; i < (int)myEnums4.size(); ++i) { myText += PaletteInvertModeEnum::toName(myEnums4[i]) + "\n"; } ret->setHelpText(myText); return ret; } void OperationVolumePalette::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString myVolumeName = myParams->getString(1); AString myModeName = myParams->getString(2); bool ok = false; PaletteScaleModeEnum::Enum myMode = PaletteScaleModeEnum::fromName(myModeName, &ok); if (!ok) { throw OperationException("unknown mapping mode"); } VolumeFile myVolume; myVolume.readFile(myVolumeName); int mySubvolume = -1; OptionalParameter* subvolumeSelect = myParams->getOptionalParameter(3); if (subvolumeSelect->m_present) { mySubvolume = (int)myVolume.getMapIndexFromNameOrNumber(subvolumeSelect->getString(1)); if (mySubvolume < 0 || mySubvolume >= myVolume.getNumberOfMaps()) { throw OperationException("invalid column specified"); } } PaletteColorMapping myMapping = *(myVolume.getMapPaletteColorMapping(0));//create the mapping, then use operator= to set for all requested columns, take defaults from first map myMapping.setScaleMode(myMode); OptionalParameter* posMinMaxPercent = myParams->getOptionalParameter(4); if (posMinMaxPercent->m_present) { myMapping.setAutoScalePercentagePositiveMinimum(posMinMaxPercent->getDouble(1)); myMapping.setAutoScalePercentagePositiveMaximum(posMinMaxPercent->getDouble(2)); } OptionalParameter* negMinMaxPercent = myParams->getOptionalParameter(5); if (negMinMaxPercent->m_present) { myMapping.setAutoScalePercentageNegativeMinimum(negMinMaxPercent->getDouble(1)); myMapping.setAutoScalePercentageNegativeMaximum(negMinMaxPercent->getDouble(2)); } OptionalParameter* posMinMaxValue = myParams->getOptionalParameter(11); if (posMinMaxValue->m_present) { myMapping.setUserScalePositiveMinimum(posMinMaxValue->getDouble(1)); myMapping.setUserScalePositiveMaximum(posMinMaxValue->getDouble(2)); } OptionalParameter* negMinMaxValue = myParams->getOptionalParameter(12); if (negMinMaxValue->m_present) { myMapping.setUserScaleNegativeMinimum(negMinMaxValue->getDouble(1)); myMapping.setUserScaleNegativeMaximum(negMinMaxValue->getDouble(2)); } OptionalParameter* displayPositive = myParams->getOptionalParameter(6); if (displayPositive->m_present) { myMapping.setDisplayPositiveDataFlag(displayPositive->getBoolean(1)); } OptionalParameter* displayNegative = myParams->getOptionalParameter(7); if (displayNegative->m_present) { myMapping.setDisplayNegativeDataFlag(displayNegative->getBoolean(1)); } OptionalParameter* displayZero = myParams->getOptionalParameter(8); if (displayZero->m_present) { myMapping.setDisplayZeroDataFlag(displayZero->getBoolean(1)); } OptionalParameter* interpolate = myParams->getOptionalParameter(9); if (interpolate->m_present) { myMapping.setInterpolatePaletteFlag(interpolate->getBoolean(1)); } OptionalParameter* paletteName = myParams->getOptionalParameter(10); if (paletteName->m_present) { myMapping.setSelectedPaletteName(paletteName->getString(1)); } OptionalParameter* thresholdOpt = myParams->getOptionalParameter(13); if (thresholdOpt->m_present) { bool ok = false; PaletteThresholdTypeEnum::Enum mytype = PaletteThresholdTypeEnum::fromName(thresholdOpt->getString(1), &ok); if (!ok) throw OperationException("unrecognized threshold type string: " + thresholdOpt->getString(1)); PaletteThresholdTestEnum::Enum mytest = PaletteThresholdTestEnum::fromName(thresholdOpt->getString(2), &ok); if (!ok) throw OperationException("unrecognized threshold test string: " + thresholdOpt->getString(2)); myMapping.setThresholdType(mytype); myMapping.setThresholdTest(mytest); myMapping.setThresholdMinimum(mytype, thresholdOpt->getDouble(3)); myMapping.setThresholdMaximum(mytype, thresholdOpt->getDouble(4)); } OptionalParameter* inversionOpt = myParams->getOptionalParameter(15); if (inversionOpt->m_present) { bool ok = false; PaletteInvertModeEnum::Enum inversionType = PaletteInvertModeEnum::fromName(inversionOpt->getString(1), &ok); if (!ok) throw OperationException("unrecognized palette inversion type: " + inversionOpt->getString(1)); myMapping.setInvertedMode(inversionType); } if (mySubvolume == -1) { for (int i = 0; i < myVolume.getNumberOfMaps(); ++i) { *(myVolume.getMapPaletteColorMapping(i)) = myMapping; } } else { *(myVolume.getMapPaletteColorMapping(mySubvolume)) = myMapping; } myVolume.writeFile(myVolumeName); } connectome-workbench-1.4.2/src/Operations/OperationVolumePalette.h000066400000000000000000000026171360521144700253730ustar00rootroot00000000000000#ifndef __OPERATION_VOLUME_PALETTE_H__ #define __OPERATION_VOLUME_PALETTE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationVolumePalette : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationVolumePalette; } #endif //__OPERATION_VOLUME_PALETTE_H__ connectome-workbench-1.4.2/src/Operations/OperationVolumeReorient.cxx000066400000000000000000000106361360521144700261370ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationVolumeReorient.h" #include "OperationException.h" #include "VolumeFile.h" using namespace caret; using namespace std; AString OperationVolumeReorient::getCommandSwitch() { return "-volume-reorient"; } AString OperationVolumeReorient::getShortDescription() { return "CHANGE VOXEL ORDER OF A VOLUME FILE"; } OperationParameters* OperationVolumeReorient::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume", "the volume to reorient"); ret->addStringParameter(2, "orient-string", "the desired orientation"); ret->addStringParameter(3, "volume-out", "out - the reoriented volume");//fake the "out" parameter formatting, because copying a volume file in memory is currently a problem ret->setHelpText( AString("Changes the voxel order and the header spacing/origin information such that the value of any spatial point is unchanged. ") + "Orientation strings look like 'LPI', which means first index is left to right, second is posterior to anterior, and third is inferior to superior. " + "The valid characters are:\n\nL left to right\nR right to left\nP posterior to anterior\nA anterior to posterior\nI inferior to superior\nS superior to inferior" ); return ret; } void OperationVolumeReorient::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); VolumeFile* myVol = myParams->getVolume(1); AString orientString = myParams->getString(2); AString outName = myParams->getString(3); if (orientString.length() < 3) { throw OperationException("orient-string must have 3 characters"); } bool used[3] = {false, false, false}; VolumeSpace::OrientTypes orient[3]; for (int i = 0; i < 3; ++i) { char id = orientString[i].toLatin1(); switch (id) { case 'L': case 'l': if (used[0]) throw OperationException("X axis (L, R) specified more than once"); used[0] = true; orient[i] = VolumeSpace::LEFT_TO_RIGHT; break; case 'R': case 'r': if (used[0]) throw OperationException("X axis (L, R) specified more than once"); used[0] = true; orient[i] = VolumeSpace::RIGHT_TO_LEFT; break; case 'P': case 'p': if (used[1]) throw OperationException("Y axis (P, A) specified more than once"); used[1] = true; orient[i] = VolumeSpace::POSTERIOR_TO_ANTERIOR; break; case 'A': case 'a': if (used[1]) throw OperationException("Y axis (P, A) specified more than once"); used[1] = true; orient[i] = VolumeSpace::ANTERIOR_TO_POSTERIOR; break; case 'I': case 'i': if (used[2]) throw OperationException("Z axis (I, S) specified more than once"); used[2] = true; orient[i] = VolumeSpace::INFERIOR_TO_SUPERIOR; break; case 'S': case 's': if (used[2]) throw OperationException("Z axis (I, S) specified more than once"); used[2] = true; orient[i] = VolumeSpace::SUPERIOR_TO_INFERIOR; break; default: throw OperationException(AString("unrecognized character '") + id + "'"); } } myVol->reorient(orient); myVol->writeFile(outName); } connectome-workbench-1.4.2/src/Operations/OperationVolumeReorient.h000066400000000000000000000026251360521144700255630ustar00rootroot00000000000000#ifndef __OPERATION_VOLUME_REORIENT_H__ #define __OPERATION_VOLUME_REORIENT_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationVolumeReorient : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationVolumeReorient; } #endif //__OPERATION_VOLUME_REORIENT_H__ connectome-workbench-1.4.2/src/Operations/OperationVolumeSetSpace.cxx000066400000000000000000000161771360521144700260650ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationVolumeSetSpace.h" #include "OperationException.h" #include "FloatMatrix.h" #include "NiftiIO.h" #include "VolumeFile.h" using namespace caret; using namespace std; AString OperationVolumeSetSpace::getCommandSwitch() { return "-volume-set-space"; } AString OperationVolumeSetSpace::getShortDescription() { return "CHANGE VOLUME SPACE INFORMATION"; } OperationParameters* OperationVolumeSetSpace::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume-in", "the input volume"); ret->addStringParameter(2, "volume-out", "output - the output volume");//fake the "out" parameter formatting, because copying a volume file in memory is currently a problem OptionalParameter* plumbOpt = ret->createOptionalParameter(3, "-plumb", "set via axis order and spacing/offset"); plumbOpt->addStringParameter(1, "axis-order", "a string like 'XYZ' that specifies which index is along which spatial dimension"); plumbOpt->addDoubleParameter(2, "x-spacing", "change in x-coordinate from incrementing the relevant index"); plumbOpt->addDoubleParameter(3, "y-spacing", "change in y-coordinate from incrementing the relevant index"); plumbOpt->addDoubleParameter(4, "z-spacing", "change in z-coordinate from incrementing the relevant index"); plumbOpt->addDoubleParameter(5, "x-offset", "the x-coordinate of the first voxel"); plumbOpt->addDoubleParameter(6, "y-offset", "the y-coordinate of the first voxel"); plumbOpt->addDoubleParameter(7, "z-offset", "the z-coordinate of the first voxel"); OptionalParameter* sformOpt = ret->createOptionalParameter(4, "-sform", "set via a nifti sform"); char axisNames[] = "xyz", indexNames[] = "ijk"; for (int axis = 0; axis < 3; ++axis) { for (int index = 0; index < 3; ++index) { sformOpt->addDoubleParameter(axis * 4 + index, AString(axisNames[axis]) + indexNames[index] + "-spacing", "increase in " + AString(axisNames[axis]) + " coordinate from incrementing the " + indexNames[index] + " index"); } sformOpt->addDoubleParameter(axis * 4 + 3, AString(axisNames[axis]) + "-offset", AString(axisNames[axis]) + " coordinate of first voxel"); } OptionalParameter* fileOpt = ret->createOptionalParameter(5, "-file", "copy spacing info from volume file with matching dimensions"); fileOpt->addStringParameter(1, "volume-ref", "volume file to use for reference space"); fileOpt->createOptionalParameter(2, "-ignore-dims", "copy the spacing info even if the dimensions don't match"); ret->setHelpText( AString("Writes a copy of the volume file, with the spacing information changed as specified. ") + "No reordering of the voxel data occurs, see -volume-reorient to change the volume indexing order and reorder the voxels to match. " + "Exactly one of -plumb, -sform, or -file must be specified." ); return ret; } void OperationVolumeSetSpace::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); VolumeFile* orig = myParams->getVolume(1); FloatMatrix newSform = FloatMatrix::zeros(4, 4); newSform[3][3] = 1.0f;//not needed, but just for sanity bool haveSpace = false; OptionalParameter* plumbOpt = myParams->getOptionalParameter(3); if (plumbOpt->m_present) { haveSpace = true; bool used[3] = {false, false, false}; int revorder[3] = {-1, -1, -1}; AString orient = plumbOpt->getString(1); if (orient.size() < 3) throw OperationException(" must have 3 characters"); for (int i = 0; i < 3; ++i) { int dir = -1; switch (orient[i].toLatin1()) { case 'X': case 'x': dir = 0; break; case 'Y': case 'y': dir = 1; break; case 'Z': case 'z': dir = 2; break; default: throw OperationException(" must use the characters X, Y, and Z"); } if (used[dir]) throw OperationException(" may not repeat an axis"); used[dir] = true; revorder[dir] = i;//construct the reversed order, because thats what we need } newSform[0][revorder[0]] = (float)plumbOpt->getDouble(2); newSform[0][3] = (float)plumbOpt->getDouble(5); newSform[1][revorder[1]] = (float)plumbOpt->getDouble(3); newSform[1][3] = (float)plumbOpt->getDouble(6); newSform[2][revorder[2]] = (float)plumbOpt->getDouble(4); newSform[2][3] = (float)plumbOpt->getDouble(7); } OptionalParameter* sformOpt = myParams->getOptionalParameter(4); if (sformOpt->m_present) { if (haveSpace) throw OperationException("only one of -plumb, -sform, or -file may be specified"); haveSpace = true; for (int axis = 0; axis < 3; ++axis) { for (int index = 0; index < 3; ++index) { newSform[axis][index] = (float)sformOpt->getDouble(axis * 4 + index); } newSform[axis][3] = (float)sformOpt->getDouble(axis * 4 + 3); } } OptionalParameter* fileOpt = myParams->getOptionalParameter(5); if (fileOpt->m_present) { if (haveSpace) throw OperationException("only one of -plumb, -sform, or -file may be specified"); haveSpace = true; NiftiIO myIO; myIO.openRead(fileOpt->getString(1)); newSform = myIO.getHeader().getSForm(); if (!fileOpt->getOptionalParameter(2)->m_present) { //check dimensions and throw vector origDims = orig->getDimensions(), templateDims = myIO.getDimensions(); origDims.resize(3, 1); templateDims.resize(3, 1); if (origDims != templateDims) throw OperationException("template has different dimensions than input file, use -ignore-dims to copy the volume space info anyway"); } } if (!haveSpace) throw OperationException("you must specify -plumb, -sform, or -file"); orig->setVolumeSpace(newSform.getMatrix()); orig->writeFile(myParams->getString(2)); } connectome-workbench-1.4.2/src/Operations/OperationVolumeSetSpace.h000066400000000000000000000026301360521144700254770ustar00rootroot00000000000000#ifndef __OPERATION_VOLUME_SET_SPACE_H__ #define __OPERATION_VOLUME_SET_SPACE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationVolumeSetSpace : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationVolumeSetSpace; } #endif //__OPERATION_VOLUME_SET_SPACE_H__ connectome-workbench-1.4.2/src/Operations/OperationVolumeStats.cxx000066400000000000000000000216121360521144700254420ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationVolumeStats.h" #include "OperationException.h" #include "ReductionOperation.h" #include "VolumeFile.h" #include #include #include #include #include #include using namespace caret; using namespace std; AString OperationVolumeStats::getCommandSwitch() { return "-volume-stats"; } AString OperationVolumeStats::getShortDescription() { return "SPATIAL STATISTICS ON A VOLUME FILE"; } OperationParameters* OperationVolumeStats::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume-in", "the input volume"); OptionalParameter* reduceOpt = ret->createOptionalParameter(2, "-reduce", "use a reduction operation"); reduceOpt->addStringParameter(1, "operation", "the reduction operation"); OptionalParameter* percentileOpt = ret->createOptionalParameter(3, "-percentile", "give the value at a percentile"); percentileOpt->addDoubleParameter(1, "percent", "the percentile to find"); OptionalParameter* subvolOpt = ret->createOptionalParameter(4, "-subvolume", "only display output for one subvolume"); subvolOpt->addStringParameter(1, "subvolume", "the subvolume number or name"); OptionalParameter* roiOpt = ret->createOptionalParameter(5, "-roi", "only consider data inside an roi"); roiOpt->addVolumeParameter(1, "roi-volume", "the roi, as a volume file"); roiOpt->createOptionalParameter(2, "-match-maps", "each subvolume of input uses the corresponding subvolume from the roi file"); ret->createOptionalParameter(6, "-show-map-name", "print map index and name before each output"); ret->setHelpText( AString("For each subvolume of the input, a single number is printed, resulting from the specified reduction or percentile operation. ") + "Use -subvolume to only give output for a single subvolume. " + "Use -roi to consider only the data within a region. " + "Exactly one of -reduce or -percentile must be specified.\n\n" + "The argument to the -reduce option must be one of the following:\n\n" + ReductionOperation::getHelpInfo()); return ret; } namespace { float reduce(const float* data, const int64_t& numElements, const ReductionEnum::Enum& myop, const float* roiData) { if (roiData == NULL) { return ReductionOperation::reduce(data, numElements, myop); } else { vector toUse; toUse.reserve(numElements); for (int64_t i = 0; i < numElements; ++i) { if (roiData[i] > 0.0f) { toUse.push_back(data[i]); } } if (toUse.empty()) throw OperationException("roi contains no voxels"); return ReductionOperation::reduce(toUse.data(), toUse.size(), myop); } } float percentile(const float* data, const int64_t& numElements, const float& percent, const float* roiData) { CaretAssert(percent >= 0.0f && percent <= 100.0f); vector toUse; if (roiData == NULL) { toUse = vector(data, data + numElements); } else { toUse.reserve(numElements); for (int64_t i = 0; i < numElements; ++i) { if (roiData[i] > 0.0f) { toUse.push_back(data[i]); } } } if (toUse.empty()) throw OperationException("roi contains no voxels"); sort(toUse.begin(), toUse.end()); const double index = percent / 100.0f * (toUse.size() - 1); if (index <= 0) return toUse[0]; if (index >= toUse.size() - 1) return toUse.back(); double ipart, fpart; fpart = modf(index, &ipart); return (1.0f - fpart) * toUse[(int64_t)ipart] + fpart * toUse[((int64_t)ipart) + 1]; } } void OperationVolumeStats::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); VolumeFile* input = myParams->getVolume(1); vector dims = input->getDimensions(); const int64_t frameSize = dims[0] * dims[1] * dims[2]; if (input->getNumberOfComponents() != 1) throw OperationException("multi-component volumes are not supported in -volume-stats"); OptionalParameter* reduceOpt = myParams->getOptionalParameter(2); OptionalParameter* percentileOpt = myParams->getOptionalParameter(3); if (reduceOpt->m_present == percentileOpt->m_present)//use == as logical xnor { throw OperationException("you must use exactly one of -reduce or -percentile"); } ReductionEnum::Enum myop = ReductionEnum::INVALID; if (reduceOpt->m_present) { bool ok = false; myop = ReductionEnum::fromName(reduceOpt->getString(1), &ok); if (!ok) throw OperationException("unrecognized reduction operation: " + reduceOpt->getString(1)); } float percent = 0.0f; if (percentileOpt->m_present) { percent = (float)percentileOpt->getDouble(1);//use not within range to trap NaNs, just in case if (!(percent >= 0.0f && percent <= 100.0f)) throw OperationException("percentile must be between 0 and 100"); } int subvol = -1; OptionalParameter* subvolOpt = myParams->getOptionalParameter(4); if (subvolOpt->m_present) { subvol = input->getMapIndexFromNameOrNumber(subvolOpt->getString(1)); if (subvol < 0) throw OperationException("invalid column specified"); } bool matchSubvolMode = false; VolumeFile* myRoi = NULL; int numRoiMaps = 1;//trick: pretend there is one ROI map with no ROI file OptionalParameter* roiOpt = myParams->getOptionalParameter(5); if (roiOpt->m_present) { myRoi = roiOpt->getVolume(1); numRoiMaps = myRoi->getNumberOfMaps(); if (!input->matchesVolumeSpace(myRoi)) throw OperationException("roi doesn't match volume space of input"); if (roiOpt->getOptionalParameter(2)->m_present) { if (myRoi->getDimensions()[3] != dims[3]) { throw OperationException("-match-maps specified, but roi has different number of subvolumes than input"); } matchSubvolMode = true; } } bool showMapName = myParams->getOptionalParameter(6)->m_present; int numMaps = input->getNumberOfMaps(); int startSubvol, endSubvol; if (subvol == -1) { startSubvol = 0; endSubvol = numMaps; } else { startSubvol = subvol; endSubvol = subvol + 1; } for (int i = startSubvol; i < endSubvol; ++i) { if (showMapName) cout << AString::number(i + 1) << ":\t" << input->getMapName(i) << ":\t"; if (matchSubvolMode) {//trick: matchSubvolMode is only true when we have an roi const float* roiData = myRoi->getFrame(i); float result; if (reduceOpt->m_present) { result = reduce(input->getFrame(i), frameSize, myop, roiData); } else { CaretAssert(percentileOpt->m_present); result = percentile(input->getFrame(i), frameSize, percent, roiData); } stringstream resultsstr; resultsstr << setprecision(7) << result; cout << resultsstr.str(); } else { const float* roiData = NULL; for (int j = 0; j < numRoiMaps; ++j) { if (myRoi != NULL) roiData = myRoi->getFrame(j); float result; if (reduceOpt->m_present) { result = reduce(input->getFrame(i), frameSize, myop, roiData); } else { CaretAssert(percentileOpt->m_present); result = percentile(input->getFrame(i), frameSize, percent, roiData); } stringstream resultsstr; resultsstr << setprecision(7) << result; if (j != 0) cout << "\t"; cout << resultsstr.str(); } } cout << endl; } } connectome-workbench-1.4.2/src/Operations/OperationVolumeStats.h000066400000000000000000000026031360521144700250660ustar00rootroot00000000000000#ifndef __OPERATION_VOLUME_STATS_H__ #define __OPERATION_VOLUME_STATS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationVolumeStats : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationVolumeStats; } #endif //__OPERATION_VOLUME_STATS_H__ connectome-workbench-1.4.2/src/Operations/OperationVolumeWeightedStats.cxx000066400000000000000000000417341360521144700271320ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationVolumeWeightedStats.h" #include "OperationException.h" #include "CaretHeap.h" #include "VolumeFile.h" #include #include #include #include #include using namespace caret; using namespace std; AString OperationVolumeWeightedStats::getCommandSwitch() { return "-volume-weighted-stats"; } AString OperationVolumeWeightedStats::getShortDescription() { return "WEIGHTED SPATIAL STATISTICS ON A VOLUME FILE"; } OperationParameters* OperationVolumeWeightedStats::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addVolumeParameter(1, "volume-in", "the input volume"); OptionalParameter* weightVolumeOpt = ret->createOptionalParameter(2, "-weight-volume", "use weights from a volume file"); weightVolumeOpt->addVolumeParameter(1, "weight-volume", "volume file containing the weights"); weightVolumeOpt->createOptionalParameter(2, "-match-maps", "each subvolume of input uses the corresponding subvolume from the weights file"); OptionalParameter* subvolOpt = ret->createOptionalParameter(3, "-subvolume", "only display output for one subvolume"); subvolOpt->addStringParameter(1, "subvolume", "the subvolume number or name"); OptionalParameter* roiOpt = ret->createOptionalParameter(4, "-roi", "only consider data inside an roi"); roiOpt->addVolumeParameter(1, "roi-volume", "the roi, as a volume file"); roiOpt->createOptionalParameter(2, "-match-maps", "each subvolume of input uses the corresponding subvolume from the roi file"); ret->createOptionalParameter(5, "-mean", "compute weighted mean"); OptionalParameter* stdevOpt = ret->createOptionalParameter(6, "-stdev", "compute weighted standard deviation"); stdevOpt->createOptionalParameter(1, "-sample", "estimate population stdev from the sample"); OptionalParameter* percentileOpt = ret->createOptionalParameter(7, "-percentile", "compute weighted percentile"); percentileOpt->addDoubleParameter(1, "percent", "the percentile to find"); ret->createOptionalParameter(8, "-sum", "compute weighted sum"); ret->createOptionalParameter(9, "-show-map-name", "print map index and name before each output"); ret->setHelpText( AString("For each subvolume of the input, a single number is printed, resulting from the specified operation. ") + "If -weight-volume is not specified, each voxel's volume is used. " + "Use -subvolume to only give output for a single subvolume. " + "Use -roi to consider only the data within a region. " + "Exactly one of -mean, -stdev, -percentile or -sum must be specified.\n\n" + "Using -sum without -weight-volume is equivalent to integrating with respect to volume." ); return ret; } namespace { enum OperationType { MEAN, STDEV, SAMPSTDEV, PERCENTILE, SUM }; float doOperation(const float* data, const float* weights, const int64_t& numElements, const OperationType& myop, const float* roiData, const float& argument) {//argument is only used for percentile currently if (roiData != NULL) { bool haveData = false; for (int64_t i = 0; i < numElements; ++i) { if (weights[i] > 0.0f) { haveData = true; break; } } if (!haveData) throw OperationException("roi contains no voxels"); } switch(myop) { case SUM: case MEAN: case STDEV: case SAMPSTDEV://these all start the same way { double accum = 0.0, weightsum = 0.0; for (int64_t i = 0; i < numElements; ++i) { if (roiData == NULL || roiData[i] > 0.0f) { accum += data[i] * weights[i]; weightsum += weights[i]; } } if (myop == SUM) return accum; const float mean = accum / weightsum; if (myop == MEAN) return mean; accum = 0.0; double weightsum2 = 0.0;//for weighted sample stdev for (int64_t i = 0; i < numElements; ++i) { if (roiData == NULL || roiData[i] > 0.0f) { float tempf = data[i] - mean; accum += weights[i] * tempf * tempf; weightsum2 += weights[i] * weights[i]; } } if (myop == STDEV) return sqrt(accum / weightsum); CaretAssert(myop == SAMPSTDEV); return sqrt(accum / (weightsum - weightsum2 / weightsum));//http://en.wikipedia.org/wiki/Weighted_arithmetic_mean#Weighted_sample_variance } case PERCENTILE: { CaretAssert(argument >= 0.0f && argument <= 100.0f); CaretSimpleMinHeap sorter; double weightaccum = 0.0;//double will usually prevent adding weights in a different order from getting a different answer for (int64_t i = 0; i < numElements; ++i) { if (roiData == NULL || roiData[i] > 0.0f) { if (weights[i] < 0.0f) throw OperationException("negative weights not allowed in weighted percentile"); weightaccum += weights[i]; sorter.push(weights[i], data[i]);//sort by value, so the key is the data } } int64_t numUse = sorter.size(); if (numUse == 1)//would need special handling anyway, so get it early { float ret; sorter.top(&ret); return ret; } float targetWeight = argument / 100.0f * weightaccum; float lastData, nextData; float lastWeight = sorter.pop(&lastData); weightaccum = lastWeight; float nextWeight = sorter.top(&nextData); int64_t position = 1;//because the first and last sections get special treatment to not have flat ends on the function while (weightaccum + nextWeight * 0.5f < targetWeight && sorter.size() > 1) { ++position; sorter.pop(); weightaccum += nextWeight; lastWeight = nextWeight; lastData = nextData; nextWeight = sorter.top(&nextData); } if (targetWeight < weightaccum) { if (position == 1) {//stretch interpolation at first position to the edge return lastData + (nextData - lastData) * 0.5f * ((targetWeight - weightaccum) / lastWeight + 1.0f); } else { return lastData + (nextData - lastData) * 0.5f * ((targetWeight - weightaccum) / (lastWeight * 0.5f) + 1.0f); } } else { if (position == numUse - 1) {//ditto return (lastData + nextData) * 0.5f + (nextData - lastData) * 0.5f * (targetWeight - weightaccum) / nextWeight; } else { return (lastData + nextData) * 0.5f + (nextData - lastData) * 0.5f * (targetWeight - weightaccum) / (nextWeight * 0.5f); } } } } CaretAssert(false);//make sure execution never actually reaches end of function throw OperationException("internal error in weighted stats"); } float doOperationSingleWeight(const float* data, const float& weight, const int64_t& numElements, const OperationType& myop, const float* roiData, const float& argument) {//argument is only used for percentile currently const float* useData = data; int64_t numUse = numElements; vector dataScratch;//for when we have an ROI if (roiData != NULL) { dataScratch.reserve(numElements); for (int64_t i = 0; i < numElements; ++i) { if (roiData[i] > 0.0f) { dataScratch.push_back(data[i]); } } if (dataScratch.size() < 1) throw OperationException("roi contains no voxels"); useData = dataScratch.data(); numUse = (int64_t)dataScratch.size(); } switch(myop) { case SUM: case MEAN: case STDEV: case SAMPSTDEV://these all start the same way { double accum = 0.0; for (int64_t i = 0; i < numUse; ++i) { accum += useData[i]; } if (myop == SUM) return accum * weight;//this is the only operation that needs the weight when it is the same at every location const float mean = accum / numUse; if (myop == MEAN) return mean; accum = 0.0; for (int64_t i = 0; i < numUse; ++i) { float tempf = useData[i] - mean; accum += tempf * tempf; } if (myop == STDEV) return sqrt(accum / numUse); CaretAssert(myop == SAMPSTDEV); if (numUse < 2) throw OperationException("sample standard deviation requires at least 2 elements in the roi"); return sqrt(accum / (numUse - 1)); } case PERCENTILE: { CaretAssert(argument >= 0.0f && argument <= 100.0f);//same as unweighted vector sortCopy(useData, useData + numUse); sort(sortCopy.begin(), sortCopy.end()); const double index = argument / 100.0f * (sortCopy.size() - 1); if (index <= 0) return sortCopy[0]; if (index >= sortCopy.size() - 1) return sortCopy.back(); double ipart, fpart; fpart = modf(index, &ipart); return (1.0f - fpart) * sortCopy[(int64_t)ipart] + fpart * sortCopy[((int64_t)ipart) + 1]; } } CaretAssert(false);//make sure execution never actually reaches end of function throw OperationException("internal error in weighted stats"); } } void OperationVolumeWeightedStats::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); VolumeFile* input = myParams->getVolume(1); const float constWeight = input->getVolumeSpace().getVoxelVolume();//even if we don't need it vector dims = input->getDimensions(); const int64_t frameSize = dims[0] * dims[1] * dims[2]; if (input->getNumberOfComponents() != 1) throw OperationException("multi-component volumes are not supported in -volume-weighted-stats"); OptionalParameter* weightVolumeOpt = myParams->getOptionalParameter(2); VolumeFile* myWeights = NULL; const float* weightData = NULL; bool matchSubvolWeights = false; if (weightVolumeOpt->m_present) { myWeights = weightVolumeOpt->getVolume(1); if (!myWeights->matchesVolumeSpace(input)) throw OperationException("weight volume doesn't match volume space of input"); if (weightVolumeOpt->getOptionalParameter(2)->m_present) { if (myWeights->getDimensions()[3] != dims[3]) { throw OperationException("-match-maps specified, but weights file has different number of subvolumes than input"); } matchSubvolWeights = true; } else { weightData = myWeights->getFrame(); } } int subvol = -1; OptionalParameter* subvolOpt = myParams->getOptionalParameter(3); if (subvolOpt->m_present) { subvol = input->getMapIndexFromNameOrNumber(subvolOpt->getString(1)); if (subvol < 0) throw OperationException("invalid column specified"); } bool matchSubvolMode = false; VolumeFile* myRoi = NULL; int numRoiMaps = 1;//trick: pretend there is one ROI map with no ROI file OptionalParameter* roiOpt = myParams->getOptionalParameter(4); if (roiOpt->m_present) { myRoi = roiOpt->getVolume(1); numRoiMaps = myRoi->getNumberOfMaps(); if (!input->matchesVolumeSpace(myRoi)) throw OperationException("roi doesn't match volume space of input"); if (roiOpt->getOptionalParameter(2)->m_present) { if (myRoi->getDimensions()[3] != dims[3]) { throw OperationException("-match-maps specified, but roi file has different number of subvolumes than input"); } matchSubvolMode = true; } } bool haveOp = false; OperationType myop; if (myParams->getOptionalParameter(5)->m_present) { haveOp = true; myop = MEAN; } OptionalParameter* stdevOpt = myParams->getOptionalParameter(6); if (stdevOpt->m_present) { if (haveOp) throw OperationException("you may only specify one operation"); haveOp = true; if (stdevOpt->getOptionalParameter(1)->m_present) { myop = SAMPSTDEV; } else { myop = STDEV; } } float argument = -1.0f; OptionalParameter* percentileOpt = myParams->getOptionalParameter(7); if (percentileOpt->m_present) { if (haveOp) throw OperationException("you may only specify one operation"); haveOp = true; myop = PERCENTILE; argument = percentileOpt->getDouble(1); if (!(argument >= 0.0f && argument <= 100.0f)) throw OperationException("percentile must be between 0 and 100"); } if (myParams->getOptionalParameter(8)->m_present) { if (haveOp) throw OperationException("you may only specify one operation"); haveOp = true; myop = SUM; } if (!haveOp) throw OperationException("you must specify an operation"); bool showMapName = myParams->getOptionalParameter(9)->m_present; int numMaps = input->getNumberOfMaps(); int startSubvol, endSubvol; if (subvol == -1) { startSubvol = 0; endSubvol = numMaps; } else { startSubvol = subvol; endSubvol = subvol + 1; } const float* roiData = NULL; for (int i = startSubvol; i < endSubvol; ++i) { if (showMapName) cout << AString::number(i + 1) << ":\t" << input->getMapName(i) << ":\t"; if (matchSubvolMode) {//trick: matchSubvolMode is only true when we have an roi roiData = myRoi->getFrame(i); if (matchSubvolWeights) { weightData = myWeights->getFrame(i); } float result; if (weightData != NULL) { result = doOperation(input->getFrame(i), weightData, frameSize, myop, roiData, argument); } else { result = doOperationSingleWeight(input->getFrame(i), constWeight, frameSize, myop, roiData, argument); } stringstream resultsstr; resultsstr << setprecision(7) << result; cout << resultsstr.str(); } else { if (matchSubvolWeights) { weightData = myWeights->getFrame(i); } for (int j = 0; j < numRoiMaps; ++j) { if (myRoi != NULL) roiData = myRoi->getFrame(j); float result; if (weightData != NULL) { result = doOperation(input->getFrame(i), weightData, frameSize, myop, roiData, argument); } else { result = doOperationSingleWeight(input->getFrame(i), constWeight, frameSize, myop, roiData, argument); } stringstream resultsstr; resultsstr << setprecision(7) << result; if (j != 0) cout << "\t"; cout << resultsstr.str(); } } cout << endl; } } connectome-workbench-1.4.2/src/Operations/OperationVolumeWeightedStats.h000066400000000000000000000026661360521144700265600ustar00rootroot00000000000000#ifndef __OPERATION_VOLUME_WEIGHTED_STATS_H__ #define __OPERATION_VOLUME_WEIGHTED_STATS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationVolumeWeightedStats : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationVolumeWeightedStats; } #endif //__OPERATION_VOLUME_WEIGHTED_STATS_H__ connectome-workbench-1.4.2/src/Operations/OperationWbsparseMergeDense.cxx000066400000000000000000000324321360521144700267030ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationWbsparseMergeDense.h" #include "OperationException.h" #include "CaretSparseFile.h" using namespace caret; using namespace std; AString OperationWbsparseMergeDense::getCommandSwitch() { return "-wbsparse-merge-dense"; } AString OperationWbsparseMergeDense::getShortDescription() { return "MERGE WBSPARSE FILES ALONG DENSE DIMENSION"; } OperationParameters* OperationWbsparseMergeDense::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "direction", "which dimension to merge along, ROW or COLUMN"); ret->addStringParameter(2, "wbsparse-out", "output - the output wbsparse file");//HACK: fake the output format since we don't have a wbsparse parameter type (or file type, really) ParameterComponent* wbsparseOpt = ret->createRepeatableParameter(3, "-wbsparse", "specify an input wbsparse file"); wbsparseOpt->addStringParameter(1, "wbsparse-in", "a wbsparse file to merge"); ret->setHelpText( AString("The input wbsparse files must have matching mappings along the direction not specified, and the mapping along the specified direction must be brain models.") ); return ret; } void OperationWbsparseMergeDense::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString directionName = myParams->getString(1); int myDir; if (directionName == "ROW") { myDir = CiftiXML::ALONG_ROW; } else if (directionName == "COLUMN") { myDir = CiftiXML::ALONG_COLUMN; } else { throw OperationException("incorrect string for direction, use ROW or COLUMN"); } AString outputName = myParams->getString(2); const vector& myInstances = *(myParams->getRepeatableParameterInstances(3)); vector > wbsparseList; int numCifti = (int)myInstances.size(); for (int i = 0; i < numCifti; ++i) { wbsparseList.push_back(CaretPointer(new CaretSparseFile(myInstances[i]->getString(1)))); } if (wbsparseList.size() == 0) throw OperationException("no files specified"); if (myDir != CiftiXML::ALONG_ROW && myDir != CiftiXML::ALONG_COLUMN) throw OperationException("direction not supported by wbsparse merge dense"); int otherDir = 1 - myDir;//find the other direction const CiftiXML& baseXML = wbsparseList[0]->getCiftiXML(); if (baseXML.getMappingType(myDir) != CiftiMappingType::BRAIN_MODELS) throw OperationException("mapping type along specified dimension is not brain models"); if (baseXML.getMappingType(otherDir) == CiftiMappingType::LABELS)throw OperationException("labels not supported in wbsparse merge dense"); CiftiXML outXML = baseXML; VolumeSpace baseSpace; const CiftiBrainModelsMap& baseDenseMap = baseXML.getBrainModelsMap(myDir); CiftiBrainModelsMap newDenseMap = baseDenseMap; bool haveVolSpace = false; if (baseDenseMap.hasVolumeData()) { haveVolSpace = true; baseSpace = baseDenseMap.getVolumeSpace(); } vector sourceWbsparse(baseDenseMap.getModelInfo().size(), 0); for (int i = 1; i < (int)wbsparseList.size(); ++i) { const CiftiXML& otherXML = wbsparseList[i]->getCiftiXML(); if (*(baseXML.getMap(otherDir)) != *(otherXML.getMap(otherDir))) { throw OperationException("mappings along other dimension do not match"); } if (otherXML.getMappingType(myDir) != CiftiMappingType::BRAIN_MODELS) throw OperationException("input files do not have brain models mapping on merge dimension"); const CiftiBrainModelsMap& otherDenseMap = otherXML.getBrainModelsMap(myDir); if (otherDenseMap.hasVolumeData()) { if (haveVolSpace) { if (!baseSpace.matches(otherDenseMap.getVolumeSpace())) throw OperationException("input files have non-matching volume spaces"); } else { haveVolSpace = true; baseSpace = otherDenseMap.getVolumeSpace(); newDenseMap.setVolumeSpace(baseSpace);//need to set the output vol space if the first input didn't have volume data } } vector otherModels = otherDenseMap.getModelInfo(); int numModels = (int)otherModels.size(); for (int j = 0; j < numModels; ++j) { sourceWbsparse.push_back(i); const CiftiBrainModelsMap::ModelInfo& myInfo = otherModels[j]; switch (myInfo.m_type) { case CiftiBrainModelsMap::SURFACE: { vector myMap = otherDenseMap.getSurfaceMap(myInfo.m_structure); vector nodeList(myMap.size()); for (int64_t k = 0; k < (int64_t)myMap.size(); ++k) { nodeList[k] = myMap[k].m_surfaceNode; } newDenseMap.addSurfaceModel(otherDenseMap.getSurfaceNumberOfNodes(myInfo.m_structure), myInfo.m_structure, nodeList); break; } case CiftiBrainModelsMap::VOXELS: { vector myMap = otherDenseMap.getVolumeStructureMap(myInfo.m_structure); vector voxelList(myMap.size() * 3); for (int64_t k = 0; k < (int64_t)myMap.size(); ++k) { int64_t k3 = k * 3; voxelList[k3] = myMap[k].m_ijk[0]; voxelList[k3 + 1] = myMap[k].m_ijk[1]; voxelList[k3 + 2] = myMap[k].m_ijk[2]; } newDenseMap.addVolumeModel(myInfo.m_structure, voxelList); break; } default: throw OperationException("encountered unknown model type in cifti merge dense"); } } } outXML.setMap(myDir, newDenseMap); int numOutModels = (int)sourceWbsparse.size(); CaretAssert(numOutModels == (int)newDenseMap.getModelInfo().size()); int64_t outColSize = outXML.getDimensionLength(CiftiXML::ALONG_COLUMN); CaretSparseFileWriter myWriter(outputName, outXML); vector outModelInfo = newDenseMap.getModelInfo(); switch (myDir) { case CiftiXML::ALONG_ROW: { for (int64_t i = 0; i < outColSize; ++i) { int64_t curOffset = 0; vector outIndices, outValues, inIndices, inValues; int loaded = -1; for (int j = 0; j < numOutModels; ++j)//we could just do the entire row for each file, but doing it by structure could allow structure selection in the future { const CiftiBrainModelsMap::ModelInfo& myInfo = outModelInfo[j]; const CiftiXML& thisXML = wbsparseList[sourceWbsparse[j]]->getCiftiXML(); const CiftiBrainModelsMap& thisDenseMap = thisXML.getBrainModelsMap(myDir); int64_t startIndex = -1, endIndex = -1; switch (myInfo.m_type) { case CiftiBrainModelsMap::SURFACE: { vector tempMap = thisDenseMap.getSurfaceMap(myInfo.m_structure); if (tempMap.size() > 0) { startIndex = tempMap[0].m_ciftiIndex;//NOTE: CiftiXML guarantees these are ordered by cifti index and contiguous endIndex = startIndex + tempMap.size(); } else { startIndex = 0; endIndex = 0; } break; } case CiftiBrainModelsMap::VOXELS: { vector tempMap = thisDenseMap.getVolumeStructureMap(myInfo.m_structure); if (tempMap.size() > 0) { startIndex = tempMap[0].m_ciftiIndex;//NOTE: CiftiXML guarantees these are ordered by cifti index and contiguous endIndex = startIndex + tempMap.size(); } else { startIndex = 0; endIndex = 0; } break; } default: CaretAssert(false); break; } if (endIndex > startIndex) { if (loaded != sourceWbsparse[j]) { wbsparseList[sourceWbsparse[j]]->getRowSparse(i, inIndices, inValues); loaded = sourceWbsparse[j]; } int64_t numSparse = (int64_t)inIndices.size(); for (int64_t k = 0; k < numSparse; ++k) { if (inIndices[k] >= startIndex && inIndices[k] < endIndex) { outIndices.push_back(inIndices[k] + curOffset); outValues.push_back(inValues[k]); } } curOffset += endIndex - startIndex; } } myWriter.writeRowSparse(i, outIndices, outValues); outIndices.clear();//reset for next row outValues.clear(); } break; } case CiftiXML::ALONG_COLUMN: { vector inIndices, inValues; for (int j = 0; j < numOutModels; ++j) { const CiftiBrainModelsMap::ModelInfo& myInfo = outModelInfo[j]; const CiftiXML& thisXML = wbsparseList[sourceWbsparse[j]]->getCiftiXML(); const CiftiBrainModelsMap& thisDenseMap = thisXML.getBrainModelsMap(myDir); switch (myInfo.m_type) { case CiftiBrainModelsMap::SURFACE: { vector tempMap = thisDenseMap.getSurfaceMap(myInfo.m_structure), outMap = newDenseMap.getSurfaceMap(myInfo.m_structure); int64_t mapSize = (int64_t)tempMap.size(); CaretAssert(mapSize == (int64_t)outMap.size()); for (int64_t k = 0; k < mapSize; ++k) { CaretAssert(tempMap[k].m_surfaceNode == outMap[k].m_surfaceNode); wbsparseList[sourceWbsparse[j]]->getRowSparse(tempMap[k].m_ciftiIndex, inIndices, inValues); myWriter.writeRowSparse(outMap[k].m_ciftiIndex, inIndices, inValues); } break; } case CiftiBrainModelsMap::VOXELS: { vector tempMap = thisDenseMap.getVolumeStructureMap(myInfo.m_structure), outMap = newDenseMap.getVolumeStructureMap(myInfo.m_structure); int64_t mapSize = (int64_t)tempMap.size(); CaretAssert(mapSize == (int64_t)outMap.size()); for (int64_t k = 0; k < mapSize; ++k) { CaretAssert(tempMap[k].m_ijk[0] == outMap[k].m_ijk[0]); CaretAssert(tempMap[k].m_ijk[1] == outMap[k].m_ijk[1]); CaretAssert(tempMap[k].m_ijk[2] == outMap[k].m_ijk[2]); wbsparseList[sourceWbsparse[j]]->getRowSparse(tempMap[k].m_ciftiIndex, inIndices, inValues); myWriter.writeRowSparse(outMap[k].m_ciftiIndex, inIndices, inValues); } break; } default: CaretAssert(false); break; } } break; } default: CaretAssert(false); break; } myWriter.finish(); } connectome-workbench-1.4.2/src/Operations/OperationWbsparseMergeDense.h000066400000000000000000000026601360521144700263300ustar00rootroot00000000000000#ifndef __OPERATION_WBSPARSE_MERGE_DENSE_H__ #define __OPERATION_WBSPARSE_MERGE_DENSE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationWbsparseMergeDense : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationWbsparseMergeDense; } #endif //__OPERATION_WBSPARSE_MERGE_DENSE_H__ connectome-workbench-1.4.2/src/Operations/OperationZipSceneFile.cxx000066400000000000000000000346141360521144700255020ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretLogger.h" #include "DataFile.h" #include "EventManager.h" #include "EventProgressUpdate.h" #include "FileInformation.h" #include "OperationZipSceneFile.h" #include "OperationException.h" #include "Scene.h" #include "SceneAttributes.h" #include "SceneClass.h" #include "SceneClassArray.h" #include "SceneFile.h" #include "SpecFile.h" #include "quazip.h" #include "quazipfile.h" #include #include #include using namespace caret; using namespace std; AString OperationZipSceneFile::getCommandSwitch() { return "-zip-scene-file"; } AString OperationZipSceneFile::getShortDescription() { return "ZIP A SCENE FILE AND ITS DATA FILES"; } OperationParameters* OperationZipSceneFile::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "scene-file", "the scene file to make the zip file from"); ret->addStringParameter(2, "extract-folder", "the name of the folder created when the zip file is unzipped"); ret->addStringParameter(3, "zip-file", "out - the zip file that will be created"); OptionalParameter* baseOpt = ret->createOptionalParameter(4, "-base-dir", "specify a directory that all data files are somewhere within, this will become the root of the zipfile's directory structure"); baseOpt->addStringParameter(1, "directory", "the directory"); ret->createOptionalParameter(5, "-skip-missing", "any missing files will generate only warnings, and the zip file will be created anyway"); ret->setHelpText("If zip-file already exists, it will be overwritten. " "If -base-dir is not specified, the base directory will be automatically set to the lowest level directory containing all files. " "The scene file must contain only relative paths, and no data files may be outside the base directory."); return ret; } void OperationZipSceneFile::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { AString sceneFileName = myParams->getString(1); AString outputSubDirectory = myParams->getString(2); AString zipFileName = myParams->getString(3); OptionalParameter* baseOpt = myParams->getOptionalParameter(4); AString myBaseDir; if (baseOpt->m_present) { myBaseDir = QDir::cleanPath(QDir(baseOpt->getString(1)).absolutePath()); } bool skipMissing = myParams->getOptionalParameter(5)->m_present; OperationZipSceneFile::createZipFile(myProgObj, sceneFileName, outputSubDirectory, zipFileName, myBaseDir, PROGRESS_COMMAND_LINE, skipMissing); } void OperationZipSceneFile::createZipFile(ProgressObject* myProgObj, const AString& sceneFileName, const AString& outputSubDirectory, const AString& zipFileName, const AString& baseDirectory, const ProgressMode progressMode, const bool skipMissing) { LevelProgress myProgress(myProgObj); FileInformation sceneFileInfo(sceneFileName); if (outputSubDirectory.isEmpty()) { throw OperationException("extract-dir must contain characters"); } if (FileInformation(outputSubDirectory).isAbsolute()) { CaretLogWarning("You have specified that the zip file should extract to an absolute path, this is generally frowned on. " "The parameter should generally be a string without '/' or '\\' in it."); } else { if (outputSubDirectory.indexOfAnyChar("/\\") != -1)//assume backslashes work too { CaretLogWarning("You have specified that the zipfile should create multiple levels of otherwise empty directories " "before the file paths starting from the base directory, this is probably going to be inconvenient. " "The parameter should generally be a string without '/' or '\\' in it."); } } SceneFile sceneFile; sceneFile.readFile(sceneFileName); AString myBaseDir; if ( ! baseDirectory.isEmpty()) { myBaseDir = QDir::cleanPath(QDir(baseDirectory).absolutePath()); } else { AString baseDirectoryName; std::vector missingFileNames; AString errorMessage; const bool validBasePathFlag = sceneFile.findBaseDirectoryForDataFiles(baseDirectoryName, missingFileNames, errorMessage); if ( ! validBasePathFlag) { throw OperationException("Automatic Base Directory Failed: " + errorMessage); } myBaseDir = QDir::cleanPath(baseDirectoryName); } if (!myBaseDir.endsWith('/'))//root is a special case, if we didn't handle it differently it would end up looking for "//somefile" {//this is actually because the path function strips the final "/" from the path, but not when it is just "/" myBaseDir += "/";//so, add the trailing slash to the path } AString sceneFilePath = QDir::cleanPath(sceneFileInfo.getAbsoluteFilePath());//resolve filenames to open from the spec file's location, NOT from current directory if (!sceneFilePath.startsWith(myBaseDir)) { throw OperationException("scene file lies outside the base directory"); } set allFiles; allFiles.insert(sceneFilePath); const int numScenes = sceneFile.getNumberOfScenes(); for (int i = 0; i < numScenes; ++i) { Scene* thisScene = sceneFile.getSceneAtIndex(i); SceneAttributes* myAttrs = thisScene->getAttributes(); const SceneClass* guiMgrClass = thisScene->getClassWithName("guiManager"); if (guiMgrClass == NULL) { throw OperationException("scene '" + thisScene->getName() + "' is missing guiManager class"); } const SceneClass* sessMgrClass = guiMgrClass->getClass("m_sessionManager"); if (sessMgrClass == NULL) { throw OperationException("scene '" + thisScene->getName() + "' is missing m_sessionManager class"); } const SceneClassArray* brainArray = sessMgrClass->getClassArray("m_brains"); if (brainArray == NULL) { throw OperationException("scene '" + thisScene->getName() + "' is missing m_brains class array"); } const int numBrainClasses = brainArray->getNumberOfArrayElements(); for (int j = 0; j < numBrainClasses; ++j) { const SceneClass* brainClass = brainArray->getClassAtIndex(j); const SceneClass* specClass = brainClass->getClass("specFile"); if (specClass == NULL) { throw OperationException("scene '" + thisScene->getName() + "' is missing specFile class in m_brains element " + AString::number(j)); } SpecFile tempSpec; tempSpec.restoreFromScene(myAttrs, specClass); vector tempNames = tempSpec.getAllDataFileNamesSelectedForLoading(); int numNames = (int)tempNames.size(); for (int k = 0; k < numNames; ++k) { if (DataFile::isFileOnNetwork(tempNames[k])) { switch (progressMode) { case PROGRESS_COMMAND_LINE: cout << "skipping network file '" << tempNames[k] << "'" << endl; break; case PROGRESS_GUI_EVENT: break; } continue; } AString thisName = QDir::cleanPath(tempNames[k]); if (allFiles.insert(thisName).second) { if (FileInformation(thisName).isRelative()) { throw OperationException("scene '" + thisScene->getName() + "' contains an unresolved relative path: '" + tempNames[k] + "'"); } if (!thisName.startsWith(myBaseDir)) { throw OperationException("scene '" + thisScene->getName() + "' contains a file outside the base directory: '" + thisName + "', try using -base-dir"); } } } } } EventProgressUpdate progressEvent(0, allFiles.size(), 0, "Creating ZIP File"); EventManager::get()->sendEvent(progressEvent.getPointer()); QFile zipFileObject(zipFileName); zipFileObject.remove();//delete it if it exists, to play better with file symlinks QuaZip zipFile(&zipFileObject); if (!zipFile.open(QuaZip::mdCreate)) { throw OperationException("Unable to open ZIP File \"" + zipFileName + "\" for writing."); } int32_t fileIndex = 1; static const char *myUnits[9] = {" B ", " KB", " MB", " GB", " TB", " PB", " EB", " ZB", " YB"}; int goodFileCount = 0; for (set::iterator iter = allFiles.begin(); iter != allFiles.end(); ++iter, ++fileIndex) { AString dataFileName = *iter; AString unzippedDataFileName = outputSubDirectory + "/" + dataFileName.mid(myBaseDir.size());//we know the string matches to the length of myBaseDir, and is cleaned, so we can just chop the right number of characters off QFile dataFileIn(dataFileName); if (!dataFileIn.open(QFile::ReadOnly)) { if (skipMissing) { CaretLogWarning("Skipping unreadable file '" + dataFileName + "'"); continue; } else { throw OperationException("Unable to open \"" + dataFileName + "\" for reading: " + dataFileIn.errorString()); } } float fileSize = (float)dataFileIn.size(); int unit = 0; while (unit < 8 && fileSize >= 1000.0f)//don't let there be 4 digits to the left of decimal point { ++unit; fileSize /= 1000.0f;//use GB and friends, not GiB } switch (progressMode) { case PROGRESS_COMMAND_LINE: if (unit > 0) { cout << AString::number(fileSize, 'f', 2); } else { cout << AString::number(fileSize); } cout << myUnits[unit] << " \t" << unzippedDataFileName; cout.flush();//don't endl until it finishes break; case PROGRESS_GUI_EVENT: progressEvent.setProgress(fileIndex, ("Adding " + (QString::number(fileIndex) + " of " + QString::number(allFiles.size()) + " (") + ((unit > 0) ? AString::number(fileSize, 'f', 2) : AString::number(fileSize)) + myUnits[unit] + ") " + FileInformation(unzippedDataFileName).getFileName())); EventManager::get()->sendEvent(progressEvent.getPointer()); break; } QuaZipNewInfo zipNewInfo(unzippedDataFileName, dataFileName); zipNewInfo.externalAttr |= (6 << 22L) | (6 << 19L) | (4 << 16L);//make permissions 664 QuaZipFile dataFileOut(&zipFile); if (!dataFileOut.open(QIODevice::WriteOnly, zipNewInfo)) { throw OperationException("Unable to open zip output for \"" + dataFileName + "\""); } const qint64 BUFFER_SIZE = 1024 * 1024; vector buffer(BUFFER_SIZE); while (dataFileIn.atEnd() == false) { const qint64 numRead = dataFileIn.read(buffer.data(), BUFFER_SIZE); if (numRead < 0) throw OperationException("Error reading from data file"); if (numRead > 0) { qint64 result = dataFileOut.write(buffer.data(), numRead); if (result != numRead) throw OperationException("Error writing to zip file"); } } dataFileIn.close(); dataFileOut.close(); switch (progressMode) { case PROGRESS_COMMAND_LINE: cout << endl; break; case PROGRESS_GUI_EVENT: break; } ++goodFileCount; } zipFile.close(); switch (progressMode) { case PROGRESS_COMMAND_LINE: if (goodFileCount != int(allFiles.size())) { CaretLogWarning("Zip creation skipped " + AString::number(allFiles.size() - goodFileCount) + " unreadable files"); } break; case PROGRESS_GUI_EVENT: if (goodFileCount == int(allFiles.size())) { progressEvent.setProgress(allFiles.size(), "Zip created successfully"); } else { progressEvent.setProgress(allFiles.size(), "Zip creation skipped " + AString::number(allFiles.size() - goodFileCount) + " unreadable files"); } EventManager::get()->sendEvent(progressEvent.getPointer()); break; } } connectome-workbench-1.4.2/src/Operations/OperationZipSceneFile.h000066400000000000000000000037041360521144700251230ustar00rootroot00000000000000#ifndef __OPERATION_ZIP_SCENE_FILE_H__ #define __OPERATION_ZIP_SCENE_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationZipSceneFile : public AbstractOperation { public: enum ProgressMode { PROGRESS_COMMAND_LINE, PROGRESS_GUI_EVENT }; static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); static void createZipFile(ProgressObject* myProgObj, const AString& sceneFileName, const AString& outputSubDirectory, const AString& zipFileName, const AString& baseDirectory, const ProgressMode progressMode, const bool skipMissing = false); }; typedef TemplateAutoOperation AutoOperationZipSceneFile; } #endif //__OPERATION_ZIP_SCENE_FILE_H__ connectome-workbench-1.4.2/src/Operations/OperationZipSpecFile.cxx000066400000000000000000000250151360521144700253320ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretLogger.h" #include "DataFile.h" #include "FileInformation.h" #include "OperationZipSpecFile.h" #include "OperationException.h" #include "SpecFile.h" #include "quazip.h" #include "quazipfile.h" //for cleanPath #include //to print file sizes as it makes the zip #include #include using namespace caret; using namespace std; AString OperationZipSpecFile::getCommandSwitch() { return "-zip-spec-file"; } AString OperationZipSpecFile::getShortDescription() { return "ZIP A SPEC FILE AND ITS DATA FILES"; } OperationParameters* OperationZipSpecFile::getParameters() { OperationParameters* ret = new OperationParameters(); ret->addStringParameter(1, "spec-file", "the specification file to add to zip file"); ret->addStringParameter(2, "extract-folder", "the name of the folder created when the zip file is unzipped"); ret->addStringParameter(3, "zip-file", "out - the zip file that will be created"); OptionalParameter* baseOpt = ret->createOptionalParameter(4, "-base-dir", "specify a directory that all data files are somewhere within, this will become the root of the zipfile's directory structure"); baseOpt->addStringParameter(1, "directory", "the directory"); ret->createOptionalParameter(5, "-skip-missing", "any missing files will generate only warnings, and the zip file will be created anyway"); ret->setHelpText(AString("If zip-file already exists, it will be overwritten. ") + "If -base-dir is not specified, the directory containing the spec file is used for the base directory. " + "The spec file must contain only relative paths, and no data files may be outside the base directory. " + "Scene files inside spec files are not checked for what files they reference, ensure that all data files referenced by the scene files are also referenced by the spec file."); return ret; } void OperationZipSpecFile::useParameters(OperationParameters* myParams, ProgressObject* myProgObj) { LevelProgress myProgress(myProgObj); AString specFileName = FileInformation(myParams->getString(1)).getAbsoluteFilePath(); AString outputSubDirectory = myParams->getString(2); AString zipFileName = FileInformation(myParams->getString(3)).getAbsoluteFilePath(); OptionalParameter* baseOpt = myParams->getOptionalParameter(4); AString myBaseDir; if (baseOpt->m_present) { myBaseDir = QDir::cleanPath(QDir(baseOpt->getString(1)).absolutePath()); } else { FileInformation specFileInfo(specFileName); myBaseDir = QDir::cleanPath(specFileInfo.getAbsolutePath()); } if (!myBaseDir.endsWith('/'))//root is a special case, if we didn't handle it differently it would end up looking for "//somefile" {//this is actually because the path function strips the final "/" from the path, but not when it is just "/" myBaseDir += "/";//so, add the trailing slash to the path } bool skipMissing = myParams->getOptionalParameter(5)->m_present; if (outputSubDirectory.isEmpty()) { throw OperationException("extract-dir must contain characters"); } if (FileInformation(outputSubDirectory).isAbsolute()) { CaretLogWarning("You have specified that the zip file should extract to an absolute path, this is generally frowned on. " "The parameter should generally be a string without '/' or '\\' in it."); } else { if (outputSubDirectory.indexOfAnyChar("/\\") != -1)//assume backslashes work too { CaretLogWarning("You have specified that the zipfile should create multiple levels of otherwise empty directories " "before the file paths starting from the base directory, this is probably going to be inconvenient. " "The parameter should generally be a string without '/' or '\\' in it."); } } /* * Read the spec file and get the names of its data files. * Look for any files that are missing (name in spec file * but file not found). */ FileInformation specFileInfo(specFileName); AString specPath = QDir::cleanPath(specFileInfo.getAbsolutePath()); if (!specPath.endsWith('/')) { specPath += "/"; } SpecFile specFile; specFile.readFile(specFileName); std::vector allDataFileNames = specFile.getAllDataFileNames(); allDataFileNames.push_back(specFileName); /* * Verify that all data files exist */ AString missingDataFileNames; AString outsideBaseDirFiles; const int32_t numberOfDataFiles = static_cast(allDataFileNames.size()); for (int32_t i = 0; i < numberOfDataFiles; i++) { AString dataFileName = allDataFileNames[i]; if (DataFile::isFileOnNetwork(dataFileName)) { cout << "skipping network file '" << dataFileName << "'" << endl; allDataFileNames.erase(allDataFileNames.begin() + i);//remove it from the list --i;//decrement i in order not to skip anything continue; } FileInformation tempInfo(dataFileName); if (tempInfo.isRelative()) { dataFileName = specPath + dataFileName; } FileInformation dataFileInfo(dataFileName); AString absName = QDir::cleanPath(dataFileInfo.getAbsoluteFilePath()); if (!absName.startsWith(myBaseDir)) { outsideBaseDirFiles += absName + "\n"; } if (dataFileInfo.exists() == false) { missingDataFileNames += absName + "\n"; } allDataFileNames[i] = absName;//so we don't have to do this again } if (!missingDataFileNames.isEmpty()) { if (skipMissing) { CaretLogWarning("These data files do not exist and will be skipped:\n" + missingDataFileNames); } else { throw OperationException("These data files do not exist:\n" + missingDataFileNames); } } if (!outsideBaseDirFiles.isEmpty()) { throw OperationException("These data files lie outside the base directiory:\n" + outsideBaseDirFiles + "Try using -base-dir."); } /* * Create the ZIP file */ QFile zipFileObject(zipFileName); zipFileObject.remove();//delete it if it exists, to play better with file symlinks QuaZip zipFile(&zipFileObject); if (zipFile.open(QuaZip::mdCreate) == false) { throw OperationException("Unable to open ZIP File \"" + zipFileName + "\" for writing."); } /* * Compress each of the files and add them to the zip file */ AString errorMessage; static const char *myUnits[9] = {" B ", " KB", " MB", " GB", " TB", " PB", " EB", " ZB", " YB"}; for (int32_t i = 0; i < numberOfDataFiles; i++) { AString dataFileName = allDataFileNames[i]; AString unzippedDataFileName = outputSubDirectory + "/" + dataFileName.mid(myBaseDir.size());//we know the string matches to the length of myBaseDir, and is cleaned, so we can just chop the right number of characters off QFile dataFileIn(dataFileName); if (dataFileIn.open(QFile::ReadOnly) == false) { if (skipMissing) { continue; } else { errorMessage = "Unable to open \"" + dataFileName + "\" for reading: " + dataFileIn.errorString(); break; } } float fileSize = (float)dataFileIn.size(); int unit = 0; while (unit < 8 && fileSize >= 1000.0f)//don't let there be 4 digits to the left of decimal point { ++unit; fileSize /= 1000.0f;//use GB and friends, not GiB } if (unit > 0) { cout << AString::number(fileSize, 'f', 2); } else { cout << AString::number(fileSize); } cout << myUnits[unit] << " \t" << unzippedDataFileName; cout.flush();//don't endl until it finishes QuaZipNewInfo zipNewInfo(unzippedDataFileName, dataFileName); zipNewInfo.externalAttr |= (6 << 22L) | (6 << 19L) | (4 << 16L);//make permissions 664 QuaZipFile dataFileOut(&zipFile); if (dataFileOut.open(QIODevice::WriteOnly, zipNewInfo) == false) { errorMessage = "Unable to open zip output for \"" + dataFileName + "\""; break; } const qint64 BUFFER_SIZE = 1024 * 1024; vector buffer(BUFFER_SIZE); while (dataFileIn.atEnd() == false) { const qint64 numRead = dataFileIn.read(buffer.data(), BUFFER_SIZE); if (numRead < 0) { errorMessage = "Error reading from data file"; break; } if (numRead > 0) { qint64 result = dataFileOut.write(buffer.data(), numRead); if (result != numRead) { errorMessage = "Error writing to zip file"; break; } } } if (!errorMessage.isEmpty()) break; dataFileIn.close(); dataFileOut.close(); cout << endl; } /* * Close the zip file */ zipFile.close(); /* * If there are errors, remove the ZIP file and * indicate an error has occurred. */ if (errorMessage.isEmpty() == false) { QFile::remove(zipFileName); throw OperationException(errorMessage); } } connectome-workbench-1.4.2/src/Operations/OperationZipSpecFile.h000066400000000000000000000026061360521144700247600ustar00rootroot00000000000000#ifndef __OPERATION_ZIP_SPEC_FILE_H__ #define __OPERATION_ZIP_SPEC_FILE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" namespace caret { class OperationZipSpecFile : public AbstractOperation { public: static OperationParameters* getParameters(); static void useParameters(OperationParameters* myParams, ProgressObject* myProgObj); static AString getCommandSwitch(); static AString getShortDescription(); }; typedef TemplateAutoOperation AutoOperationZipSpecFile; } #endif //__OPERATION_ZIP_SPEC_FILE_H__ connectome-workbench-1.4.2/src/OperationsBase/000077500000000000000000000000001360521144700213405ustar00rootroot00000000000000connectome-workbench-1.4.2/src/OperationsBase/AbstractOperation.cxx000066400000000000000000000032131360521144700255070ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AbstractOperation.h" #include "CaretDataFile.h" #include "CaretLogger.h" using namespace std; using namespace caret; void AbstractOperation::checkStructureMatch(const CaretDataFile* toCheck, const StructureEnum::Enum& correctStruct, const AString& fileDescrip, const AString& basisDescrip) { if (toCheck != NULL && toCheck->getStructure() != correctStruct) { CaretLogWarning(fileDescrip + " has structure '" + StructureEnum::toName(toCheck->getStructure()) + "', while " + basisDescrip + " structure '" + StructureEnum::toName(correctStruct) + "'"); } } AbstractOperation::AbstractOperation() { } AbstractOperation::~AbstractOperation() { } OperationParserInterface::~OperationParserInterface() { delete m_autoOper; } AutoOperationInterface::~AutoOperationInterface() { } connectome-workbench-1.4.2/src/OperationsBase/AbstractOperation.h000066400000000000000000000101701360521144700251340ustar00rootroot00000000000000#ifndef __ABSTRACT_OPERATION_H__ #define __ABSTRACT_OPERATION_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ //make it easy to use these in an algorithm class, don't just forward declare them #include "ProgressObject.h" #include "CaretAssert.h" #include "OperationParameters.h" #include "StructureEnum.h" namespace caret { class CaretDataFile; class AbstractOperation { protected: AbstractOperation(); virtual ~AbstractOperation(); public: ///override these to allow operation parsers to use your operation without writing an explicit command class static OperationParameters* getParameters() { CaretAssert(false); return NULL; } ///override these to allow operation parsers to use your operation without writing an explicit command class static void useParameters(OperationParameters*, ProgressObject*) { CaretAssert(false); } ///override this to set the command switch static AString getCommandSwitch() { CaretAssert(false); return ""; } ///override this to set the short description static AString getShortDescription() { CaretAssert(false); return ""; } ///override this if the operation doesn't take parameters static bool takesParameters() { return true; } ///convenience method for checking structures of input files static void checkStructureMatch(const CaretDataFile* toCheck, const StructureEnum::Enum& correctStruct, const AString& fileDescrip, const AString& basisDescrip); }; ///interface class for use by operation parsers - used because the above interface has only static methods, so to avoid neededing to instantiate the operation or template the parser code struct AutoOperationInterface { virtual OperationParameters* getParameters() = 0; virtual void useParameters(OperationParameters* a, ProgressObject* b) = 0; virtual AString getCommandSwitch() = 0; virtual AString getShortDescription() = 0; virtual bool takesParameters() = 0; virtual ~AutoOperationInterface(); }; ///templated interface class to pass through to something that inherits from AbstractOperation (or implements equivalent functions) ///this makes it easier to create a bridge between the static methods of the operation and an interface pointer that a parser can store template struct TemplateAutoOperation : public AutoOperationInterface { TemplateAutoOperation() { } OperationParameters* getParameters() { return T::getParameters(); } void useParameters(OperationParameters* a, ProgressObject* b) { T::useParameters(a, b); } AString getCommandSwitch() { return T::getCommandSwitch(); } AString getShortDescription() { return T::getShortDescription(); } bool takesParameters() { return T::takesParameters(); } }; ///interface class for parsers to inherit from class OperationParserInterface { OperationParserInterface();//must take an interface object, for its vtable to the real operation, so deny default construction protected: AutoOperationInterface* m_autoOper; public: OperationParserInterface(AutoOperationInterface* myAutoOper) : m_autoOper(myAutoOper) { } virtual ~OperationParserInterface(); }; } #endif //__ABSTRACT_OPERATION_H__ connectome-workbench-1.4.2/src/OperationsBase/CMakeLists.txt000066400000000000000000000016261360521144700241050ustar00rootroot00000000000000# # Name of project # PROJECT (OperationsBase) # # Add QT for includes # if(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) #include_directories(${Qt5Network_INCLUDE_DIRS}) endif() IF (QT4_FOUND) SET(QT_DONT_USE_QTGUI) INCLUDE(${QT_USE_FILE}) ENDIF () # # Create the helper library # ADD_LIBRARY(OperationsBase AbstractOperation.h OperationParameters.h OperationParametersEnum.h AbstractOperation.cxx OperationParameters.cxx OperationParametersEnum.cxx ) TARGET_LINK_LIBRARIES(OperationsBase ${CARET_QT5_LINK}) # # Find Headers # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Annotations ${CMAKE_SOURCE_DIR}/OperationsBase ${CMAKE_SOURCE_DIR}/Charting ${CMAKE_SOURCE_DIR}/FilesBase ${CMAKE_SOURCE_DIR}/Files ${CMAKE_SOURCE_DIR}/Gifti ${CMAKE_SOURCE_DIR}/Cifti ${CMAKE_SOURCE_DIR}/Palette ${CMAKE_SOURCE_DIR}/Nifti ${CMAKE_SOURCE_DIR}/Scenes ${CMAKE_SOURCE_DIR}/Xml ${CMAKE_SOURCE_DIR}/Common ) connectome-workbench-1.4.2/src/OperationsBase/OperationParameters.cxx000066400000000000000000000452631360521144700260620ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "OperationParameters.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "AnnotationFile.h" #include "BorderFile.h" #include "CiftiFile.h" #include "FociFile.h" #include "LabelFile.h" #include "MetricFile.h" #include "SurfaceFile.h" #include "VolumeFile.h" using namespace std; using namespace caret; ParameterComponent::ParameterComponent() { } ParameterComponent::~ParameterComponent() { for (size_t i = 0; i < m_paramList.size(); ++i) { delete m_paramList[i]; } for (size_t i = 0; i < m_outputList.size(); ++i) { delete m_outputList[i]; } for (size_t i = 0; i < m_optionList.size(); ++i) { delete m_optionList[i]; } for (size_t i = 0; i < m_repeatableOptions.size(); ++i) { delete m_repeatableOptions[i]; } } RepeatableOption::~RepeatableOption() { for (size_t i = 0; i < m_instances.size(); ++i) { delete m_instances[i]; } } OperationParameters::OperationParameters() { } ParameterComponent::ParameterComponent(const ParameterComponent& rhs) { m_paramList.resize(rhs.m_paramList.size()); for (size_t i = 0; i < m_paramList.size(); ++i) { m_paramList[i] = rhs.m_paramList[i]->cloneAbstractParameter(); } m_outputList.resize(rhs.m_outputList.size()); for (size_t i = 0; i < m_outputList.size(); ++i) { m_outputList[i] = rhs.m_outputList[i]->cloneAbstractParameter(); } m_optionList.resize(rhs.m_optionList.size()); for (size_t i = 0; i < m_optionList.size(); ++i) { m_optionList[i] = new OptionalParameter(*(rhs.m_optionList[i])); } m_repeatableOptions.resize(rhs.m_repeatableOptions.size()); for (size_t i = 0; i < m_repeatableOptions.size(); ++i) { m_repeatableOptions[i] = new RepeatableOption(*(rhs.m_repeatableOptions[i])); } } OptionalParameter* ParameterComponent::createOptionalParameter(const int32_t key, const AString& optionSwitch, const AString& description) { CaretAssertMessage(checkUniqueOption(key), "optional parameter created with previously used key"); if (optionSwitch.isEmpty() || optionSwitch[0] != '-') CaretLogWarning("developer warning: option '" + optionSwitch + "' created, but does not start with dash"); OptionalParameter* ret = new OptionalParameter(key, optionSwitch, description); m_optionList.push_back(ret); return ret; } ParameterComponent* ParameterComponent::createRepeatableParameter(const int32_t key, const AString& optionSwitch, const AString& description) { CaretAssertMessage(checkUniqueRepeatable(key), "repeatable parameter created with previously used key"); if (optionSwitch.isEmpty() || optionSwitch[0] != '-') CaretLogWarning("developer warning: repeatable option '" + optionSwitch + "' created, but does not start with dash"); RepeatableOption* newOpt = new RepeatableOption(key, optionSwitch, description); m_repeatableOptions.push_back(newOpt); return &(newOpt->m_template); } bool ParameterComponent::checkUniqueInput(const int32_t& key, const OperationParametersEnum::Enum& type) { for (size_t i = 0; i < m_paramList.size(); ++i) { if (m_paramList[i]->m_key == key && type == m_paramList[i]->getType()) { return false; } } return true; } bool ParameterComponent::checkUniqueOption(const int32_t& key) { for (size_t i = 0; i < m_optionList.size(); ++i) { if (m_optionList[i]->m_key == key) { return false; } } return true; } bool ParameterComponent::checkUniqueRepeatable(const int32_t& key) { for (size_t i = 0; i < m_repeatableOptions.size(); ++i) { if (m_repeatableOptions[i]->m_key == key) { return false; } } return true; } bool ParameterComponent::checkUniqueOutput(const int32_t& key, const OperationParametersEnum::Enum& type) { for (size_t i = 0; i < m_outputList.size(); ++i) { if (m_outputList[i]->m_key == key && type == m_outputList[i]->getType()) { return false; } } return true; } vector ParameterComponent::findUncheckedParams(const AString& contextString) const { vector ret; for (size_t i = 0; i < m_paramList.size(); ++i) { if (!m_paramList[i]->m_operationUsed) { ret.push_back("parameter '" + m_paramList[i]->m_shortName + "' of " + contextString + " was not checked by the operation"); } } for (size_t i = 0; i < m_outputList.size(); ++i) { if (!m_outputList[i]->m_operationUsed) { ret.push_back("parameter '" + m_outputList[i]->m_shortName + "' of " + contextString + " was not checked by the operation"); } } for (size_t i = 0; i < m_optionList.size(); ++i) { if (!m_optionList[i]->m_operationUsed) { ret.push_back("option '" + m_optionList[i]->m_optionSwitch + "' of " + contextString + " was not checked by the operation"); } if (m_optionList[i]->m_present) { vector temp = m_optionList[i]->findUncheckedParams("option '" + m_optionList[i]->m_optionSwitch + "'"); ret.insert(ret.end(), temp.begin(), temp.end()); } } for (size_t i = 0; i < m_repeatableOptions.size(); ++i) { if (!m_repeatableOptions[i]->m_operationUsed) { ret.push_back("option '" + m_repeatableOptions[i]->m_optionSwitch + "' of " + contextString + " was not checked by the operation"); } for (size_t j = 0; j < m_repeatableOptions[i]->m_instances.size(); ++j) { vector temp = m_repeatableOptions[i]->m_instances[j]->findUncheckedParams("option '" + m_repeatableOptions[i]->m_optionSwitch + "'"); ret.insert(ret.end(), temp.begin(), temp.end()); } } return ret; } AbstractParameter* ParameterComponent::getInputParameter(const int32_t key, const OperationParametersEnum::Enum type) { for (size_t i = 0; i < m_paramList.size(); ++i) { if (m_paramList[i]->m_key == key && type == m_paramList[i]->getType()) { m_paramList[i]->m_operationUsed = true; return m_paramList[i]; } } CaretAssertMessage(false, "Algorithm asked for parameter it didn't specify, or of wrong type"); return NULL; } OptionalParameter* ParameterComponent::getOptionalParameter(const int32_t key) { for (size_t i = 0; i < m_optionList.size(); ++i) { if (m_optionList[i]->m_key == key) { m_optionList[i]->m_operationUsed = true; return m_optionList[i]; } } CaretAssertMessage(false, "Algorithm asked for option it didn't specify"); return NULL; } const vector* ParameterComponent::getRepeatableParameterInstances(const int32_t key) { for (size_t i = 0; i < m_repeatableOptions.size(); ++i) { if (m_repeatableOptions[i]->m_key == key) { m_repeatableOptions[i]->m_operationUsed = true; return &(m_repeatableOptions[i]->m_instances); } } CaretAssertMessage(false, "Algorithm asked for option it didn't specify"); return NULL; } AbstractParameter* ParameterComponent::getOutputParameter(const int32_t key, const OperationParametersEnum::Enum type) { for (size_t i = 0; i < m_outputList.size(); ++i) { if (m_outputList[i]->m_key == key && type == m_outputList[i]->getType()) { m_outputList[i]->m_operationUsed = true; return m_outputList[i]; } } CaretAssertMessage(false, "Algorithm asked for output it didn't specify, or of wrong type"); return NULL; } //sadly, lots of boilerplate for convenience functions void ParameterComponent::addBooleanParameter(const int32_t key, const caret::AString& name, const caret::AString& description) { CaretAssertMessage(checkUniqueInput(key, OperationParametersEnum::BOOL), "input boolean parameter created with previously used key"); m_paramList.push_back(new BooleanParameter(key, name, description)); } void ParameterComponent::addCiftiParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueInput(key, OperationParametersEnum::CIFTI), "input cifti parameter created with previously used key"); m_paramList.push_back(new CiftiParameter(key, name, description)); } void ParameterComponent::addFociParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueInput(key, OperationParametersEnum::FOCI), "input foci parameter created with previously used key"); m_paramList.push_back(new FociParameter(key, name, description)); } void ParameterComponent::addBorderParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueInput(key, OperationParametersEnum::BORDER), "input border parameter created with previously used key"); m_paramList.push_back(new BorderParameter(key, name, description)); } void ParameterComponent::addDoubleParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueInput(key, OperationParametersEnum::DOUBLE), "input double parameter created with previously used key"); m_paramList.push_back(new DoubleParameter(key, name, description)); } void ParameterComponent::addAnnotationParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueInput(key, OperationParametersEnum::ANNOTATION), "input annotation parameter created with previously used key"); m_paramList.push_back(new AnnotationParameter(key, name, description)); } void ParameterComponent::addMetricParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueInput(key, OperationParametersEnum::METRIC), "input metric parameter created with previously used key"); m_paramList.push_back(new MetricParameter(key, name, description)); } void ParameterComponent::addIntegerParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueInput(key, OperationParametersEnum::INT), "input integer parameter created with previously used key"); m_paramList.push_back(new IntegerParameter(key, name, description)); } void ParameterComponent::addLabelParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueInput(key, OperationParametersEnum::LABEL), "input label parameter created with previously used key"); m_paramList.push_back(new LabelParameter(key, name, description)); } void ParameterComponent::addStringParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueInput(key, OperationParametersEnum::STRING), "input string parameter created with previously used key"); m_paramList.push_back(new StringParameter(key, name, description)); } void ParameterComponent::addSurfaceParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueInput(key, OperationParametersEnum::SURFACE), "input surface parameter created with previously used key"); m_paramList.push_back(new SurfaceParameter(key, name, description)); } void ParameterComponent::addVolumeParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueInput(key, OperationParametersEnum::VOLUME), "input volume parameter created with previously used key"); m_paramList.push_back(new VolumeParameter(key, name, description)); } void OperationParameters::setHelpText(const AString& textIn) { m_helpText = textIn; } void ParameterComponent::addCiftiOutputParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueOutput(key, OperationParametersEnum::CIFTI), "output cifti parameter created with previously used key"); m_outputList.push_back(new CiftiParameter(key, name, description)); } void ParameterComponent::addFociOutputParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueOutput(key, OperationParametersEnum::FOCI), "output foci parameter created with previously used key"); m_outputList.push_back(new FociParameter(key, name, description)); } void ParameterComponent::addBorderOutputParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueOutput(key, OperationParametersEnum::BORDER), "output foci parameter created with previously used key"); m_outputList.push_back(new BorderParameter(key, name, description)); } void ParameterComponent::addAnnotationOutputParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueOutput(key, OperationParametersEnum::ANNOTATION), "output annotation parameter created with previously used key"); m_outputList.push_back(new AnnotationParameter(key, name, description)); } void ParameterComponent::addMetricOutputParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueOutput(key, OperationParametersEnum::METRIC), "output metric parameter created with previously used key"); m_outputList.push_back(new MetricParameter(key, name, description)); } void ParameterComponent::addLabelOutputParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueOutput(key, OperationParametersEnum::LABEL), "output label parameter created with previously used key"); m_outputList.push_back(new LabelParameter(key, name, description)); } void ParameterComponent::addSurfaceOutputParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueOutput(key, OperationParametersEnum::SURFACE), "output surface parameter created with previously used key"); m_outputList.push_back(new SurfaceParameter(key, name, description)); } void ParameterComponent::addVolumeOutputParameter(const int32_t key, const AString& name, const AString& description) { CaretAssertMessage(checkUniqueOutput(key, OperationParametersEnum::VOLUME), "output volume parameter created with previously used key"); m_outputList.push_back(new VolumeParameter(key, name, description)); } AString& OperationParameters::getHelpText() { return m_helpText; } AbstractParameter::~AbstractParameter() { } bool ParameterComponent::getBoolean(const int32_t key) { return ((BooleanParameter*)getInputParameter(key, OperationParametersEnum::BOOL))->m_parameter; } CiftiFile* ParameterComponent::getCifti(const int32_t key) { return ((CiftiParameter*)getInputParameter(key, OperationParametersEnum::CIFTI))->m_parameter.getPointer(); } FociFile* ParameterComponent::getFoci(const int32_t key) { return ((FociParameter*)getInputParameter(key, OperationParametersEnum::FOCI))->m_parameter.getPointer(); } BorderFile* ParameterComponent::getBorder(const int32_t key) { return ((BorderParameter*)getInputParameter(key, OperationParametersEnum::BORDER))->m_parameter.getPointer(); } double ParameterComponent::getDouble(const int32_t key) { return ((DoubleParameter*)getInputParameter(key, OperationParametersEnum::DOUBLE))->m_parameter; } int64_t ParameterComponent::getInteger(const int32_t key) { return ((IntegerParameter*)getInputParameter(key, OperationParametersEnum::INT))->m_parameter; } LabelFile* ParameterComponent::getLabel(const int32_t key) { return ((LabelParameter*)getInputParameter(key, OperationParametersEnum::LABEL))->m_parameter.getPointer(); } AnnotationFile* ParameterComponent::getAnnotation(const int32_t key) { return ((AnnotationParameter*)getInputParameter(key, OperationParametersEnum::ANNOTATION))->m_parameter.getPointer(); } MetricFile* ParameterComponent::getMetric(const int32_t key) { return ((MetricParameter*)getInputParameter(key, OperationParametersEnum::METRIC))->m_parameter.getPointer(); } const AString& ParameterComponent::getString(const int32_t key) { return ((StringParameter*)getInputParameter(key, OperationParametersEnum::STRING))->m_parameter; } SurfaceFile* ParameterComponent::getSurface(const int32_t key) { return ((SurfaceParameter*)getInputParameter(key, OperationParametersEnum::SURFACE))->m_parameter.getPointer(); } VolumeFile* ParameterComponent::getVolume(const int32_t key) { return ((VolumeParameter*)getInputParameter(key, OperationParametersEnum::VOLUME))->m_parameter.getPointer(); } CiftiFile* ParameterComponent::getOutputCifti(const int32_t key) { return ((CiftiParameter*)getOutputParameter(key, OperationParametersEnum::CIFTI))->m_parameter.getPointer(); } FociFile* ParameterComponent::getOutputFoci(const int32_t key) { return ((FociParameter*)getOutputParameter(key, OperationParametersEnum::FOCI))->m_parameter.getPointer(); } BorderFile* ParameterComponent::getOutputBorder(const int32_t key) { return ((BorderParameter*)getOutputParameter(key, OperationParametersEnum::BORDER))->m_parameter.getPointer(); } LabelFile* ParameterComponent::getOutputLabel(const int32_t key) { return ((LabelParameter*)getOutputParameter(key, OperationParametersEnum::LABEL))->m_parameter.getPointer(); } SurfaceFile* ParameterComponent::getOutputSurface(const int32_t key) { return ((SurfaceParameter*)getOutputParameter(key, OperationParametersEnum::SURFACE))->m_parameter.getPointer(); } VolumeFile* ParameterComponent::getOutputVolume(const int32_t key) { return ((VolumeParameter*)getOutputParameter(key, OperationParametersEnum::VOLUME))->m_parameter.getPointer(); } AnnotationFile* ParameterComponent::getOutputAnnotation(const int32_t key) { return ((AnnotationParameter*)getOutputParameter(key, OperationParametersEnum::ANNOTATION))->m_parameter.getPointer(); } MetricFile* ParameterComponent::getOutputMetric(const int32_t key) { return ((MetricParameter*)getOutputParameter(key, OperationParametersEnum::METRIC))->m_parameter.getPointer(); } connectome-workbench-1.4.2/src/OperationsBase/OperationParameters.h000066400000000000000000000370441360521144700255050ustar00rootroot00000000000000#ifndef __OPERATION_PARAMETERS_H__ #define __OPERATION_PARAMETERS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "AString.h" #include #include "stdint.h" #include "CaretPointer.h" #include "OperationParametersEnum.h" namespace caret { class AnnotationFile; class BorderFile; class CiftiFile; class FociFile; class LabelFile; class MetricFile; class SurfaceFile; class VolumeFile; struct OptionalParameter; struct RepeatableOption; struct AbstractParameter { int32_t m_key;//identifies this parameter uniquely for this algorithm AString m_shortName, m_description; bool m_operationUsed;//check if the operation called get...() for this parameter virtual OperationParametersEnum::Enum getType() = 0; virtual AbstractParameter* cloneAbstractParameter() = 0; AbstractParameter(int32_t key, const AString& shortName, const AString& description) : m_key(key), m_shortName(shortName), m_description(description), m_operationUsed(false) { }; virtual ~AbstractParameter(); }; struct ParameterComponent {//sadly, inheriting from a friend class doesn't give you access to private members, so these are entirely public so parsers can use them std::vector m_paramList;//mandatory arguments std::vector m_outputList;//should this be a different type? input and output parameters are very similar, just pointers to files std::vector m_optionList;//optional arguments std::vector m_repeatableOptions;//repeatable options ///constructor ParameterComponent(); ///destructor virtual ~ParameterComponent(); ///copy constructor so RepeatableOption can copy its template to a new instance ParameterComponent(const ParameterComponent& rhs); //convenience methods for algorithms to use to easily specify parameters ///add a parameter to get next item as a string void addStringParameter(const int32_t key, const AString& name, const AString& description); ///get a string with a key const AString& getString(const int32_t key); ///add a parameter to get next item as a string void addBooleanParameter(const int32_t key, const AString& name, const AString& description); ///get a string with a key bool getBoolean(const int32_t key); ///add a parameter to get next item as an int32 void addIntegerParameter(const int32_t key, const AString& name, const AString& description); ///get an integer with a key int64_t getInteger(const int32_t key); ///add a parameter to get next item as a double void addDoubleParameter(const int32_t key, const AString& name, const AString& description); ///get a double with a key double getDouble(const int32_t key); ///add a parameter to get next item as a surface void addSurfaceParameter(const int32_t key, const AString& name, const AString& description); ///get a surface with a key SurfaceFile* getSurface(const int32_t key); ///add a parameter to get next item as a volume void addVolumeParameter(const int32_t key, const AString& name, const AString& description); ///get a volume with a key VolumeFile* getVolume(const int32_t key); ///add a parameter to get next item as an annotation file void addAnnotationParameter(const int32_t key, const AString& name, const AString& description); ///get an annotation with a key AnnotationFile* getAnnotation(const int32_t key); ///add a parameter to get next item as a functional file (metric) void addMetricParameter(const int32_t key, const AString& name, const AString& description); ///get a metric with a key MetricFile* getMetric(const int32_t key); ///add a parameter to get next item as a label file void addLabelParameter(const int32_t key, const AString& name, const AString& description); ///get a label with a key LabelFile* getLabel(const int32_t key); ///add a parameter to get next item as a cifti file - TODO: make methods for different cifti types? void addCiftiParameter(const int32_t key, const AString& name, const AString& description); ///get a cifti with a key CiftiFile* getCifti(const int32_t key); ///add a parameter to get next item as a foci file void addFociParameter(const int32_t key, const AString& name, const AString& description); ///get a foci file with a key FociFile* getFoci(const int32_t key); ///add a parameter to get next item as a border file void addBorderParameter(const int32_t key, const AString& name, const AString& description); ///get a border file with a key BorderFile* getBorder(const int32_t key); ///add a parameter to get next item as a surface void addSurfaceOutputParameter(const int32_t key, const AString& name, const AString& description); ///get a surface with a key SurfaceFile* getOutputSurface(const int32_t key); ///add a parameter to get next item as a volume void addVolumeOutputParameter(const int32_t key, const AString& name, const AString& description); ///get a volume with a key VolumeFile* getOutputVolume(const int32_t key); ///add a parameter to get next item as an annotation file void addAnnotationOutputParameter(const int32_t key, const AString& name, const AString& description); ///get an annotation with a key AnnotationFile* getOutputAnnotation(const int32_t key); ///add a parameter to get next item as a functional file (metric) void addMetricOutputParameter(const int32_t key, const AString& name, const AString& description); ///get a metric with a key MetricFile* getOutputMetric(const int32_t key); ///add a parameter to get next item as a label file void addLabelOutputParameter(const int32_t key, const AString& name, const AString& description); ///get a label with a key LabelFile* getOutputLabel(const int32_t key); ///add a parameter to get next item as a cifti file - TODO: make methods for different cifti types? void addCiftiOutputParameter(const int32_t key, const AString& name, const AString& description); ///get a cifti with a key CiftiFile* getOutputCifti(const int32_t key); ///add a parameter to get next item as a foci file void addFociOutputParameter(const int32_t key, const AString& name, const AString& description); ///get a foci file with a key FociFile* getOutputFoci(const int32_t key); ///add a parameter to get next item as a border file void addBorderOutputParameter(const int32_t key, const AString& name, const AString& description); ///get a border file with a key BorderFile* getOutputBorder(const int32_t key); ///convenience method to create, add, and return an optional parameter OptionalParameter* createOptionalParameter(const int32_t key, const AString& optionSwitch, const AString& description); ///convenience method to create, add, and return an optional parameter ParameterComponent* createRepeatableParameter(const int32_t key, const AString& optionSwitch, const AString& description); ///return pointer to an input parameter AbstractParameter* getInputParameter(const int32_t key, const OperationParametersEnum::Enum type); ///return pointer to an output AbstractParameter* getOutputParameter(const int32_t key, const OperationParametersEnum::Enum type); ///return pointer to an option OptionalParameter* getOptionalParameter(const int32_t key); ///return instances of a repeatable option const std::vector* getRepeatableParameterInstances(const int32_t key); ///functions to check for key/type uniqueness - used only in asserts bool checkUniqueInput(const int32_t& key, const OperationParametersEnum::Enum& type); bool checkUniqueOutput(const int32_t& key, const OperationParametersEnum::Enum& type); bool checkUniqueOption(const int32_t& key); bool checkUniqueRepeatable(const int32_t& key); ///helper for checking that all parameters have been checked by the operation, returns warning strings std::vector findUncheckedParams(const AString& contextString) const; }; struct OptionalParameter : public ParameterComponent { int32_t m_key;//uniquely identifies this option AString m_optionSwitch, m_description; bool m_present;//to be filled by parser bool m_operationUsed;//check if the operation called get...() for this parameter OptionalParameter(const OptionalParameter& rhs) ://copy constructor is used by cloning in RepeatableParameter ParameterComponent(rhs), m_key(rhs.m_key), m_optionSwitch(rhs.m_optionSwitch), m_description(rhs.m_description), m_present(false), m_operationUsed(false) { } OptionalParameter(int32_t key, const AString& optionSwitch, const AString& description) : m_key(key), m_optionSwitch(optionSwitch), m_description(description), m_present(false), m_operationUsed(false) { } private: OptionalParameter();//no default construction }; struct RepeatableOption { int32_t m_key;//uniquely identifies this option AString m_optionSwitch, m_description; ParameterComponent m_template; bool m_operationUsed;//check if the operation called get...() for this parameter std::vector m_instances;//to be filled by parser RepeatableOption(const RepeatableOption& rhs) : m_key(rhs.m_key), m_optionSwitch(rhs.m_optionSwitch), m_description(rhs.m_description), m_template(rhs.m_template), m_operationUsed(false) { } RepeatableOption(int32_t key, const AString& optionSwitch, const AString& description) : m_key(key), m_optionSwitch(optionSwitch), m_description(description), m_operationUsed(false) { } ~RepeatableOption(); }; struct OperationParameters : public ParameterComponent { AString m_helpText;//to be formatted by the parser object for display in terminal or modal window ///constructor OperationParameters(); ///set the help text of the algorithm - you DO NOT need to add newlines within paragraphs or list the parameters, or give a description of each parameter! describe ONLY what it does, plus any quirks void setHelpText(const AString& textIn); ///get the unformatted help text, without command or arguments descriptions, to be formatted by the argument parser AString& getHelpText(); }; //templates for the common cases template struct PointerTemplateParameter : public AbstractParameter { virtual OperationParametersEnum::Enum getType() { return TYPE; } virtual AbstractParameter* cloneAbstractParameter() { AbstractParameter* ret = new PointerTemplateParameter(m_key, m_shortName, m_description); return ret; } CaretPointer m_parameter;//so the GUI parser and the commandline parser don't need to do different things to delete the parameter info PointerTemplateParameter(const int32_t key, const AString& shortName, const AString& description) : AbstractParameter(key, shortName, description) {//CaretPointer self-initializes to NULL, so don't need to do anything } }; template struct PrimitiveTemplateParameter : public AbstractParameter { virtual OperationParametersEnum::Enum getType() { return TYPE; } T m_parameter; virtual AbstractParameter* cloneAbstractParameter() { PrimitiveTemplateParameter* ret = new PrimitiveTemplateParameter(m_key, m_shortName, m_description); ret->m_parameter = 0; return ret; } PrimitiveTemplateParameter(const int32_t key, const AString& shortName, const AString& description) : AbstractParameter(key, shortName, description) { m_parameter = 0; } }; struct StringParameter : public AbstractParameter { virtual OperationParametersEnum::Enum getType() { return OperationParametersEnum::STRING; } virtual AbstractParameter* cloneAbstractParameter() { AbstractParameter* ret = new StringParameter(m_key, m_shortName, m_description); return ret; } AString m_parameter; StringParameter(int32_t key, const AString& shortName, const AString& description) : AbstractParameter(key, shortName, description) {//AString self-initializes to "", so don't need to do anything } }; //some friendlier names typedef PointerTemplateParameter SurfaceParameter; typedef PointerTemplateParameter VolumeParameter; typedef PointerTemplateParameter AnnotationParameter; typedef PointerTemplateParameter MetricParameter; typedef PointerTemplateParameter LabelParameter; typedef PointerTemplateParameter CiftiParameter; typedef PointerTemplateParameter FociParameter; typedef PointerTemplateParameter BorderParameter; typedef PrimitiveTemplateParameter DoubleParameter; typedef PrimitiveTemplateParameter IntegerParameter; typedef PrimitiveTemplateParameter BooleanParameter; } #endif //__OPERATION_PARAMETERS_H__ connectome-workbench-1.4.2/src/OperationsBase/OperationParametersEnum.cxx000066400000000000000000000263531360521144700267060ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "OperationParametersEnum.h" #include "CaretAssert.h" using namespace caret; std::vector OperationParametersEnum::enumData; bool OperationParametersEnum::initializedFlag = false; /** * \class AlgorithmParametersEnum * \brief enum for parameter types * * enum for parameter types */ /** * Constructor. * * @param enumValue * An enumerated value. * @param integerCode * Integer code for this enumerated value. * * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ OperationParametersEnum::OperationParametersEnum(const Enum enumValue, const int32_t integerCode, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCode; this->name = name; this->guiName = guiName; } /** * Destructor. */ OperationParametersEnum::~OperationParametersEnum() { } /** * Initialize the enumerated metadata. */ void OperationParametersEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(OperationParametersEnum(SURFACE, 0, "Surface File", "Surface")); enumData.push_back(OperationParametersEnum(VOLUME, 1, "Volume File", "Volume")); enumData.push_back(OperationParametersEnum(METRIC, 2, "Metric File", "Metric")); enumData.push_back(OperationParametersEnum(LABEL, 3, "Label File", "Label")); enumData.push_back(OperationParametersEnum(CIFTI, 4, "Cifti File", "Cifti")); enumData.push_back(OperationParametersEnum(FOCI, 5, "Foci File", "Foci File")); enumData.push_back(OperationParametersEnum(BORDER, 6, "Border File", "Border File")); enumData.push_back(OperationParametersEnum(DOUBLE, 7, "Floating Point", "Floating Point")); enumData.push_back(OperationParametersEnum(INT, 8, "Integer", "Integer")); enumData.push_back(OperationParametersEnum(STRING, 9, "String", "String")); enumData.push_back(OperationParametersEnum(BOOL, 10, "Boolean", "Boolean")); enumData.push_back(OperationParametersEnum(ANNOTATION, 11, "Annotation File", "Annotation")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const OperationParametersEnum* OperationParametersEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const OperationParametersEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString OperationParametersEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const OperationParametersEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ OperationParametersEnum::Enum OperationParametersEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = SURFACE; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const OperationParametersEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type AlgorithmParametersEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString OperationParametersEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const OperationParametersEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ OperationParametersEnum::Enum OperationParametersEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = SURFACE; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const OperationParametersEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type AlgorithmParametersEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t OperationParametersEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const OperationParametersEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ OperationParametersEnum::Enum OperationParametersEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = SURFACE; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const OperationParametersEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type AlgorithmParametersEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void OperationParametersEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void OperationParametersEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(OperationParametersEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void OperationParametersEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(OperationParametersEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/OperationsBase/OperationParametersEnum.h000066400000000000000000000056141360521144700263300ustar00rootroot00000000000000#ifndef __OPERATION_PARAMETERS_ENUM__H_ #define __OPERATION_PARAMETERS_ENUM__H_ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class OperationParametersEnum { public: /** * Enumerated values. */ enum Enum { SURFACE, VOLUME, METRIC, LABEL, CIFTI, FOCI, BORDER, DOUBLE, INT, STRING, BOOL, ANNOTATION }; ~OperationParametersEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: OperationParametersEnum(const Enum enumValue, const int32_t integerCode, const AString& name, const AString& guiName); static const OperationParametersEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; } // namespace #endif //__OPERATION_PARAMETERS_ENUM__H_ connectome-workbench-1.4.2/src/Palette/000077500000000000000000000000001360521144700200205ustar00rootroot00000000000000connectome-workbench-1.4.2/src/Palette/CMakeLists.txt000066400000000000000000000022671360521144700225670ustar00rootroot00000000000000# # The NIFTI Project # project (Palette) # # Add QT for includes # if(Qt5_FOUND) SET(QT_DONT_USE_QTGUI) include_directories(${Qt5Core_INCLUDE_DIRS}) endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () # # Create the NIFTI library # ADD_LIBRARY(Palette Palette.h PaletteColorBarValuesModeEnum.h PaletteColorMapping.h PaletteColorMappingSaxReader.h PaletteColorMappingXmlElements.h PaletteEnums.h PaletteHistogramRangeModeEnum.h PaletteInvertModeEnum.h PaletteModifiedStatusEnum.h PaletteNormalizationModeEnum.h PaletteScalarAndColor.h PaletteThresholdOutlineDrawingModeEnum.h PaletteThresholdRangeModeEnum.h Palette.cxx PaletteColorBarValuesModeEnum.cxx PaletteColorMapping.cxx PaletteColorMappingSaxReader.cxx PaletteEnums.cxx PaletteHistogramRangeModeEnum.cxx PaletteInvertModeEnum.cxx PaletteModifiedStatusEnum.cxx PaletteNormalizationModeEnum.cxx PaletteScalarAndColor.cxx PaletteThresholdOutlineDrawingModeEnum.cxx PaletteThresholdRangeModeEnum.cxx ) TARGET_LINK_LIBRARIES(Palette ${CARET_QT5_LINK}) # # Find Headers # INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Annotations ${CMAKE_SOURCE_DIR}/Common ${CMAKE_SOURCE_DIR}/Palette ${CMAKE_SOURCE_DIR}/Scenes ${CMAKE_SOURCE_DIR}/Xml ) connectome-workbench-1.4.2/src/Palette/Palette.cxx000066400000000000000000000631131360521144700221460ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretAssert.h" #define __PALETTE_DEFINE__ #include "Palette.h" #undef __PALETTE_DEFINE__ #include "PaletteScalarAndColor.h" using namespace caret; /** * Constructor. * */ Palette::Palette() : CaretObject() { this->initializeMembersPalette(); } /** * Destructor */ Palette::~Palette() { uint64_t num = this->paletteScalars.size(); for (uint64_t i = 0; i < num; i++) { delete this->paletteScalars[i]; this->paletteScalars[i] = NULL; } this->paletteScalars.clear(); } /** * Copy Constructor * @param Object that is copied. */ Palette::Palette(const Palette& o) : CaretObject(o), TracksModificationInterface() { this->initializeMembersPalette(); this->copyHelper(o); } /** * Assignment operator. */ Palette& Palette::operator=(const Palette& o) { if (this != &o) { CaretObject::operator=(o); this->copyHelper(o); }; return *this; } /** * Helps with copy constructor and assignment operator. */ void Palette::copyHelper(const Palette& o) { this->name = o.name; this->paletteScalars.clear(); uint64_t num = o.paletteScalars.size(); for (uint64_t i = 0; i < num; i++) { this->paletteScalars.push_back(new PaletteScalarAndColor(*o.paletteScalars[i])); } } void Palette::initializeMembersPalette() { this->modifiedFlag = false; this->name = ""; } /** * Get string representation for debugging. * * @return String containing info. * */ AString Palette::toString() const { AString s; s += "name=" + this->name + "\n"; uint64_t num = this->paletteScalars.size(); for (uint64_t i = 0; i < num; i++) { s += (" " + this->paletteScalars[i]->toString() + "\n"); } s += "\n"; return s; } /** * Get the name of the palette. * * @return - name of palette. * */ AString Palette::getName() const { return this->name; } /** * Set the name of this palette. * * @param name - new value for name. * */ void Palette::setName(const AString& name) { if (this->name != name) { this->name = name; this->setModified(); } } /** * Add a scalar and color to the palette. * * @param scalar - scalar value. * @param colorName - color name. * */ void Palette::addScalarAndColor(const float scalar, const AString& colorName) { CaretAssert(paletteScalars.size() == 0 || scalar <= paletteScalars.back()->getScalar());//die in debug if a palette is constructed incorrectly this->paletteScalars.push_back(new PaletteScalarAndColor(scalar, colorName)); this->setModified(); } /** * Insert a scalar/color pair. * * @param psac - item to add. * @param insertAfterIndex - Insert after this index. * */ void Palette::insertScalarAndColor( const PaletteScalarAndColor& psac, const int32_t insertAfterIndex) { CaretAssertVectorIndex(this->paletteScalars, insertAfterIndex); this->paletteScalars.insert(this->paletteScalars.begin() + insertAfterIndex, new PaletteScalarAndColor(psac)); this->setModified(); } /** * Remove the scalar and color at index. * * @param index - index of scalar and color to remove. * */ void Palette::removeScalarAndColor(const int32_t indx) { CaretAssertVectorIndex(this->paletteScalars, indx); this->paletteScalars.erase(this->paletteScalars.begin() + indx); this->setModified(); } /** * * Get the minimum and maximum scalar values in this palette. * * @return two-dimensional float array with min and max values. * */ void Palette::getMinMax(float& minOut, float& maxOut) const { minOut = std::numeric_limits::max(); maxOut = -std::numeric_limits::max(); uint64_t num = this->paletteScalars.size(); for (uint64_t i = 0; i < num; i++) { const float f = this->paletteScalars[i]->getScalar(); if (f < minOut) minOut = f; if (f > maxOut) maxOut = f; } } ///** // * Get the RGBA (4) colors in the range of zero to one. // * // * @param scalar - scalar for which color is sought. // * @param interpolateColorFlag - interpolate the color between scalars. // * @return Array of 4 containing color components ranging zero to one. // * // */ //void //Palette::getPaletteColor( // const float scalarIn, // const bool interpolateColorFlagIn, // float rgbaOut[4]) const //{ // rgbaOut[0] = 0.0f; // rgbaOut[1] = 0.0f; // rgbaOut[2] = 0.0f; // rgbaOut[3] = 1.0f; // // bool interpolateColorFlag = interpolateColorFlagIn; // // float scalar = scalarIn; // if (scalar < -1.0) scalar = -1.0; // if (scalar > 1.0) scalar = 1.0; // // int numScalarColors = this->getNumberOfScalarsAndColors(); // if (numScalarColors > 0) { // // int paletteIndex = -1; // if (numScalarColors == 1) { // paletteIndex = 0; // interpolateColorFlag = false; // } // else { // if (scalar >= this->getScalarAndColor(0)->getScalar()) { // paletteIndex = 0; // interpolateColorFlag = false; // } // else if (scalar <= // this->getScalarAndColor(numScalarColors - 1)->getScalar()) { // paletteIndex = numScalarColors - 1; // interpolateColorFlag = false; // } // else { // for (int i = 1; i < numScalarColors; i++) { // const PaletteScalarAndColor* psac = this->getScalarAndColor(i); // if (scalar > psac->getScalar()) { // paletteIndex = i - 1; // break; // } // } // // /* // * Always interpolate if there are only two colors // */ // if (numScalarColors == 2) { // interpolateColorFlag = true; // } // } // } // if (paletteIndex >= 0) { // const PaletteScalarAndColor* psac = this->getScalarAndColor(paletteIndex); // psac->getColor(rgbaOut); // if (interpolateColorFlag && // (paletteIndex < (numScalarColors - 1))) { // const PaletteScalarAndColor* psacBelow = // this->getScalarAndColor(paletteIndex + 1); // float totalDiff = psac->getScalar() - psacBelow->getScalar(); // if (totalDiff != 0.0) { // float offset = scalar - psacBelow->getScalar(); // float percentAbove = offset / totalDiff; // float percentBelow = 1.0f - percentAbove; // if ( ! psacBelow->isNoneColor()) { // const float* rgbaAbove = psac->getColor(); // const float* rgbaBelow = psacBelow->getColor(); // // rgbaOut[0] = (percentAbove * rgbaAbove[0] // + percentBelow * rgbaBelow[0]); // rgbaOut[1] = (percentAbove * rgbaAbove[1] // + percentBelow * rgbaBelow[1]); // rgbaOut[2] = (percentAbove * rgbaAbove[2] // + percentBelow * rgbaBelow[2]); // } // } // } // else if (psac->isNoneColor()) { // rgbaOut[3] = 0.0f; // } // } // } //} /** * Get the RGBA (4) colors in the range of zero to one. * * @param scalar - scalar for which color is sought. * @param interpolateColorFlag - interpolate the color between scalars. * @return Array of 4 containing color components ranging zero to one. * */ void Palette::getPaletteColor( const float scalarIn, const bool interpolateColorFlagIn, float rgbaOut[4]) const { /* * When the number of colors in a palette is small, the * binary search algorithm may be slower than the linear * algorithm. It is moderately faster for large palettes * such as those from FSL with 256 colors. * * TSC: The FSL palettes now just interpolate between two colors, * and don't have 256 entries. Could reorganize the palette * storage to be a vector of structs, rather than of pointers, * to remove cost of indirection. * Also notable is that typical volume files color faster with * methods that color near-zero faster than other values. * I compared performance on the simplified palettes with a simplified * binary search (that doesn't test against the next value after * each guess) and with an interpolation search, with no benefit. * Another possibility would be to prebuild a lookup from rounded * normalized value to min and max possible reference color to * search between (so, values between 0 and 0.01 are always between * the middle and previous point, same for 0.01 to 0.02, etc). This * could take some substantial reorganization of palette code. * For now, only activate binary search when number of points is large. * * The linear search could be improved by starting at the bottom * when the data value is negative. * * N Log2(N) * 1 0 * 2 1 * 3 1.6 * 4 2 * 5 2.3 * 6 2.6 * 7 2.8 * 8 3 * 9 3.2 */ int numScalarColors = this->getNumberOfScalarsAndColors(); const bool doBinarySearchFlag = numScalarColors > 50; rgbaOut[0] = 0.0f; rgbaOut[1] = 0.0f; rgbaOut[2] = 0.0f; rgbaOut[3] = 1.0f; bool interpolateColorFlag = interpolateColorFlagIn; float scalar = scalarIn; if (scalar < -1.0) scalar = -1.0; if (scalar > 1.0) scalar = 1.0; if (numScalarColors > 0) { int32_t highDataIndex = 0; int32_t lowDataIndex = numScalarColors - 1; int32_t paletteIndex = -1; if (numScalarColors == 1) { paletteIndex = 0; interpolateColorFlag = false; } else { if (scalar >= this->getScalarAndColor(highDataIndex)->getScalar()) { paletteIndex = 0; interpolateColorFlag = false; } else if (scalar <= this->getScalarAndColor(lowDataIndex)->getScalar()) { paletteIndex = numScalarColors - 1; interpolateColorFlag = false; } else if (numScalarColors == 2) { paletteIndex = 0; interpolateColorFlag = true; } else { if (doBinarySearchFlag) { /* * Binary Search * NOTE: The palette orders the scalars in DESCENDING ORDER */ int32_t binaryPaletteIndex = -1; const int32_t maximumIndex = numScalarColors - 1; bool loopFlag = true; while (loopFlag) { int32_t midIndex = (lowDataIndex + highDataIndex) / 2; if (midIndex <= 0) { binaryPaletteIndex = 0; loopFlag = false; } else if (midIndex >= maximumIndex) { binaryPaletteIndex = maximumIndex; loopFlag = false; } else { const float midScalar = this->getScalarAndColor(midIndex)->getScalar(); if (scalar <= midScalar) { const float nextScalar = this->getScalarAndColor(midIndex + 1)->getScalar(); if (scalar > nextScalar) { binaryPaletteIndex = midIndex; loopFlag = false; } else { highDataIndex = midIndex; } } else { lowDataIndex = midIndex; } } } paletteIndex = binaryPaletteIndex; } else { /* * Linear Search */ for (int32_t i = 1; i < numScalarColors; i++) { const PaletteScalarAndColor* psac = this->getScalarAndColor(i); if (scalar > psac->getScalar()) { paletteIndex = i - 1; break; } } } } } if (paletteIndex >= 0) { const PaletteScalarAndColor* psac = this->getScalarAndColor(paletteIndex); if (psac->isNoneColor()) { rgbaOut[3] = 0.0; } else { psac->getColor(rgbaOut); // color assigned here if (interpolateColorFlag && (paletteIndex < (numScalarColors - 1))) { const PaletteScalarAndColor* psacBelow = this->getScalarAndColor(paletteIndex + 1); float totalDiff = psac->getScalar() - psacBelow->getScalar(); if (totalDiff != 0.0) { float offset = scalar - psacBelow->getScalar(); float percentAbove = offset / totalDiff; float percentBelow = 1.0f - percentAbove; if ( ! psacBelow->isNoneColor()) { const float* rgbaAbove = psac->getColor(); const float* rgbaBelow = psacBelow->getColor(); rgbaOut[0] = (percentAbove * rgbaAbove[0] + percentBelow * rgbaBelow[0]); rgbaOut[1] = (percentAbove * rgbaAbove[1] + percentBelow * rgbaBelow[1]); rgbaOut[2] = (percentAbove * rgbaAbove[2] + percentBelow * rgbaBelow[2]); } } } } } } } /** * Set this object has been modified. * */ void Palette::setModified() { this->modifiedFlag = true; } /** * Set this object as not modified. Object should also * clear the modification status of its children. * */ void Palette::clearModified() { this->modifiedFlag = false; } /** * Get the modification status. Returns true if this object or * any of its children have been modified. * @return - The modification status. * */ bool Palette::isModified() const { return this->modifiedFlag; } /** * @return An sign separate inverted version of this palette. * The positive and negative sections are separately inverted. * * For the POSITIVE region, the conversion formula is: * IS = -S + (Min + Max) * Where: * IS => Inverted Scalar * S => Scalar * Min => Minimum positive value * Max => Maximum positive value * * The formula was derived by charting: * Plot (x=Min, y=Max) and (x=Max, y=Min) * The slope is negative one [dx = (max - min); dy = (min-max)] * So Y = -(dy/dx) * X + C * Y = -X + C * C = X + Y * C = (Min + Max) * And finally: * Y = -X + (Min + Max) * * Example: (1.0, Red), (0.4, Yellow), (0, Black), (-0.3, Green), (-1.0, Blue) * becomes (1.0, Black), (0.6, Yellow), (1.0, Red), (0, Blue), (-0.7, Green), (-1.0, Black) */ const Palette* Palette::getSignSeparateInvertedPalette() const { if ( ! m_signSeparateInvertedPalette) { m_signSeparateInvertedPalette.reset(createSignSeparateInvertedPalette()); } return m_signSeparateInvertedPalette.get(); } /** * @return New instance of sign separate palette */ Palette* Palette::createSignSeparateInvertedPalette() const { float leastPositiveScalar = 1000.0f; float mostPositiveScalar = -1000.0f; float leastNegativeScalar = -1000.0f; float mostNegativeScalar = 1000.0f; bool havePositivesFlag = false; bool haveNegativesFlag = false; for (const auto ps : paletteScalars) { const float scalar = ps->getScalar(); if (scalar >= 0.0) { if (scalar > mostPositiveScalar) mostPositiveScalar = scalar; if (scalar < leastPositiveScalar) leastPositiveScalar = scalar; if (scalar > 0.0) { havePositivesFlag = true; } } if (scalar <= 0.0) { if (scalar > leastNegativeScalar) leastNegativeScalar = scalar; if (scalar < mostNegativeScalar) mostNegativeScalar = scalar; if (scalar < 0.0) { haveNegativesFlag = true; } } } std::deque positives; std::deque negatives; for (const auto ps : paletteScalars) { const float scalar = ps->getScalar(); if (havePositivesFlag) { if (scalar >= 0.0) { PaletteScalarAndColor* psc = new PaletteScalarAndColor(*ps); psc->setScalar((leastPositiveScalar + mostPositiveScalar) - scalar); positives.push_front(psc); } } if (haveNegativesFlag) { if (scalar <= 0.0) { PaletteScalarAndColor* psc = new PaletteScalarAndColor(*ps); psc->setScalar((leastNegativeScalar + mostNegativeScalar) - scalar); negatives.push_front(psc); } } } Palette* palette = new Palette(); palette->setName(getName()); palette->paletteScalars.insert(palette->paletteScalars.end(), positives.begin(), positives.end()); palette->paletteScalars.insert(palette->paletteScalars.end(), negatives.begin(), negatives.end()); palette->clearModified(); return palette; } /** * @return An inverted version of this palette. An inverted * palette may be useful when data is all negative and the * palette is for positive data. * * Example: (1.0, Red), (0.4, Yellow), (-0.3, Green), (-1.0, Blue) * becomes (1.0, Blue), (0.3, Green), (-0.4, Yellow), (-1.0, Red) */ const Palette* Palette::getInvertedPalette() const { if ( ! m_invertedPalette) { Palette* palette = new Palette(*this); std::reverse(palette->paletteScalars.begin(), palette->paletteScalars.end()); /* * Reverse colors and then flip sign of scalars so * that it is still negative to positive */ for (auto scalar : palette->paletteScalars) { scalar->setScalar( - scalar->getScalar()); } palette->clearModified(); m_invertedPalette.reset(palette); } return m_invertedPalette.get(); } /** * @return Name of the default palette. */ AString Palette::getDefaultPaletteName() { return ROY_BIG_BL_PALETTE_NAME; } /** * @return An NONE separate inverted version of this palette. * The positive and negative sections are separately inverted * around the NONE color. If the palette contains zero it MUST * be the NONE color. * * If the palette DOES NOT have NONE or if it has both * NONE and zero, the sign separate palette is created and returned. * * For the POSITIVE region, the conversion formula is: * IS = -S + (Min + Max) * Where: * IS => Inverted Scalar * S => Scalar * Min => Minimum positive value * Max => Maximum positive value * * The formula was derived by charting: * Plot (x=Min, y=Max) and (x=Max, y=Min) * The slope is negative one [dx = (max - min); dy = (min-max)] * So Y = -(dy/dx) * X + C * Y = -X + C * C = X + Y * C = (Min + Max) * And finally: * Y = -X + (Min + Max) * * Example: (1.0, Red), (0.4, Yellow), (0, Black), (-0.3, Green), (-1.0, Blue) * becomes (1.0, Black), (0.6, Yellow), (1.0, Red), (0, Blue), (-0.7, Green), (-1.0, Black) */ const Palette* Palette::getNoneSeparateInvertedPalette() const { if ( ! m_noneSeparateInvertedPalette) { float leastPositiveScalar = 1000.0f; float mostPositiveScalar = -1000.0f; float leastNegativeScalar = -1000.0f; float mostNegativeScalar = 1000.0f; int32_t noneColorIndex = -1; int32_t zeroIndex = -1; const int32_t numScalars = static_cast(this->paletteScalars.size()); for (int32_t i = 0; i < numScalars; i++) { CaretAssertVectorIndex(this->paletteScalars, i); const float scalar = this->paletteScalars[i]->getScalar(); if (this->paletteScalars[i]->isNoneColor()) { noneColorIndex = i; } else { if (scalar == 0.0) { zeroIndex = i; } if (scalar >= 0.0) { if (scalar > mostPositiveScalar) mostPositiveScalar = scalar; if (scalar < leastPositiveScalar) leastPositiveScalar = scalar; } if (scalar <= 0.0) { if (scalar > leastNegativeScalar) leastNegativeScalar = scalar; if (scalar < mostNegativeScalar) mostNegativeScalar = scalar; } } } bool badNoneLocationFlag = false; if (noneColorIndex >= 0) { CaretAssertVectorIndex(this->paletteScalars, noneColorIndex); const float noneValue = this->paletteScalars[noneColorIndex]->getScalar(); if ((noneValue >= leastPositiveScalar) && (noneValue <= mostPositiveScalar)) { badNoneLocationFlag = true; } else if ((noneValue >= mostNegativeScalar) && (noneValue <= leastNegativeScalar)) { badNoneLocationFlag = true; } } bool validNoneInvertFlag = true; if (badNoneLocationFlag) { const AString msg("Palette named " + getName() + " has NONE within the positive or negative range."); CaretAssertMessage(0, msg); validNoneInvertFlag = false; } else if (noneColorIndex < 0) { /* no NONE so same as sign separate palette */ validNoneInvertFlag = false; } else if (zeroIndex >= 0) { /* both none and zero not allowed */ const AString msg("Palette named " + getName() + " has both NONE and zero so NONE separated palette cannot be created."); CaretAssertMessage(0, msg); validNoneInvertFlag = false; } if ( ! validNoneInvertFlag) { m_noneSeparateInvertedPalette.reset(createSignSeparateInvertedPalette()); return m_noneSeparateInvertedPalette.get(); } std::deque positives; std::deque negatives; for (int32_t i = 0; i < numScalars; i++) { CaretAssertVectorIndex(this->paletteScalars, i); const PaletteScalarAndColor* ps = this->paletteScalars[i]; const float scalar = ps->getScalar(); if (i < noneColorIndex) { PaletteScalarAndColor* psc = new PaletteScalarAndColor(*ps); psc->setScalar((leastPositiveScalar + mostPositiveScalar) - scalar); positives.push_front(psc); } else if (i > noneColorIndex) { PaletteScalarAndColor* psc = new PaletteScalarAndColor(*ps); psc->setScalar((leastNegativeScalar + mostNegativeScalar) - scalar); negatives.push_front(psc); } } Palette* palette = new Palette(); palette->setName(getName()); palette->paletteScalars.insert(palette->paletteScalars.end(), positives.begin(), positives.end()); CaretAssertVectorIndex(this->paletteScalars, noneColorIndex); palette->paletteScalars.push_back(new PaletteScalarAndColor(*this->paletteScalars[noneColorIndex])); palette->paletteScalars.insert(palette->paletteScalars.end(), negatives.begin(), negatives.end()); palette->clearModified(); m_noneSeparateInvertedPalette.reset(palette); } return m_noneSeparateInvertedPalette.get(); } connectome-workbench-1.4.2/src/Palette/Palette.h000066400000000000000000000115711360521144700215740ustar00rootroot00000000000000#ifndef __PALETTE_H__ #define __PALETTE_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "CaretAssert.h" #include "CaretObject.h" #include "TracksModificationInterface.h" namespace caret { class PaletteScalarAndColor; /** * A color palette. */ class Palette : public CaretObject, TracksModificationInterface { public: Palette(); Palette(const Palette& p); Palette& operator=(const Palette& o); virtual ~Palette(); private: void copyHelper(const Palette& o); void initializeMembersPalette(); public: AString toString() const; AString getName() const; void setName(const AString& name); /** * Get the number of scalars and colors. * * @return - number of scalars and colors. * */ inline int32_t getNumberOfScalarsAndColors() const { return this->paletteScalars.size(); } /** * Get a scalar and color for the specified index. * * @param index - index of scalar and color. * @return Reference to item at index or null if invalid index. * */ inline PaletteScalarAndColor* getScalarAndColor(const int32_t indx) const { CaretAssertVectorIndex(this->paletteScalars, indx); return this->paletteScalars[indx]; } void addScalarAndColor(const float scalar, const AString& colorName); void insertScalarAndColor( const PaletteScalarAndColor& psac, const int32_t insertAfterIndex); void removeScalarAndColor(const int32_t index); void getMinMax(float& minOut, float& maxOut) const; void getPaletteColor(const float scalar, const bool interpolateColorFlag, float rgbaOut[4]) const; void setModified(); void clearModified(); bool isModified() const; const Palette* getInvertedPalette() const; const Palette* getSignSeparateInvertedPalette() const; const Palette* getNoneSeparateInvertedPalette() const; static AString getDefaultPaletteName(); public: /**Name of gray interpolate palette */ static const AString GRAY_INTERP_PALETTE_NAME; /**Name of gray interpolate palette for positive data */ static const AString GRAY_INTERP_POSITIVE_PALETTE_NAME; /**"none" color name. */ static const AString NONE_COLOR_NAME; /** "ROY-BIG-BL" palette */ static const AString ROY_BIG_BL_PALETTE_NAME; private: Palette* createSignSeparateInvertedPalette() const; /**has this object been modified. (DO NOT CLONE) */ bool modifiedFlag; /**Name of the palette. */ AString name; /**The scalars in the palette. */ std::vector paletteScalars; /** The inverted palette is lazily initialized */ mutable std::unique_ptr m_invertedPalette; /** The inverted palette with negative inverted separate from positive */ mutable std::unique_ptr m_signSeparateInvertedPalette; /** The inverted palette with negative inverted separate from positive */ mutable std::unique_ptr m_noneSeparateInvertedPalette; }; #ifdef __PALETTE_DEFINE__ const AString Palette::GRAY_INTERP_PALETTE_NAME = "Gray_Interp"; const AString Palette::GRAY_INTERP_POSITIVE_PALETTE_NAME = "Gray_Interp_Positive"; //const AString Palette::NONE_COLOR_NAME = "none"; const AString Palette::ROY_BIG_BL_PALETTE_NAME = "ROY-BIG-BL"; #endif // __PALETTE_DEFINE__ } // namespace #endif // __PALETTE_H__ connectome-workbench-1.4.2/src/Palette/PaletteColorBarValuesModeEnum.cxx000066400000000000000000000261441360521144700264070ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __PALETTE_COLOR_BAR_VALUES_MODE_ENUM_DECLARE__ #include "PaletteColorBarValuesModeEnum.h" #undef __PALETTE_COLOR_BAR_VALUES_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::PaletteColorBarValuesModeEnum * \brief Enumerated type for palette color values mode * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_paletteColorBarValuesModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void paletteColorBarValuesModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "PaletteColorBarValuesModeEnum.h" * * Instatiate: * m_paletteColorBarValuesModeEnumComboBox = new EnumComboBoxTemplate(this); * m_paletteColorBarValuesModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_paletteColorBarValuesModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(paletteColorBarValuesModeEnumComboBoxItemActivated())); * * Update the selection: * m_paletteColorBarValuesModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const PaletteColorBarValuesModeEnum::Enum VARIABLE = m_paletteColorBarValuesModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ PaletteColorBarValuesModeEnum::PaletteColorBarValuesModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ PaletteColorBarValuesModeEnum::~PaletteColorBarValuesModeEnum() { } /** * Initialize the enumerated metadata. */ void PaletteColorBarValuesModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(PaletteColorBarValuesModeEnum(DATA, "DATA", "Data")); enumData.push_back(PaletteColorBarValuesModeEnum(PERCENTILE, "PERCENTILE", "Percentile")); enumData.push_back(PaletteColorBarValuesModeEnum(SIGN_ONLY, "SIGN_ONLY", "Sign Only")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const PaletteColorBarValuesModeEnum* PaletteColorBarValuesModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const PaletteColorBarValuesModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString PaletteColorBarValuesModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteColorBarValuesModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ PaletteColorBarValuesModeEnum::Enum PaletteColorBarValuesModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PaletteColorBarValuesModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteColorBarValuesModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type PaletteColorBarValuesModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString PaletteColorBarValuesModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteColorBarValuesModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ PaletteColorBarValuesModeEnum::Enum PaletteColorBarValuesModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PaletteColorBarValuesModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteColorBarValuesModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type PaletteColorBarValuesModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t PaletteColorBarValuesModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteColorBarValuesModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ PaletteColorBarValuesModeEnum::Enum PaletteColorBarValuesModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PaletteColorBarValuesModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteColorBarValuesModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type PaletteColorBarValuesModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void PaletteColorBarValuesModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void PaletteColorBarValuesModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(PaletteColorBarValuesModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void PaletteColorBarValuesModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(PaletteColorBarValuesModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Palette/PaletteColorBarValuesModeEnum.h000066400000000000000000000063221360521144700260300ustar00rootroot00000000000000#ifndef __PALETTE_COLOR_BAR_VALUES_MODE_ENUM_H__ #define __PALETTE_COLOR_BAR_VALUES_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class PaletteColorBarValuesModeEnum { public: /** * Enumerated values. */ enum Enum { /** */ DATA, /** */ PERCENTILE, /** */ SIGN_ONLY }; ~PaletteColorBarValuesModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: PaletteColorBarValuesModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const PaletteColorBarValuesModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __PALETTE_COLOR_BAR_VALUES_MODE_ENUM_DECLARE__ std::vector PaletteColorBarValuesModeEnum::enumData; bool PaletteColorBarValuesModeEnum::initializedFlag = false; int32_t PaletteColorBarValuesModeEnum::integerCodeCounter = 0; #endif // __PALETTE_COLOR_BAR_VALUES_MODE_ENUM_DECLARE__ } // namespace #endif //__PALETTE_COLOR_BAR_VALUES_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Palette/PaletteColorMapping.cxx000066400000000000000000003106711360521144700244650ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AnnotationColorBar.h" #include "AnnotationColorBarNumericText.h" #include "CaretLogger.h" #include "CaretOMP.h" #include "DeveloperFlagsEnum.h" #include "EventManager.h" #include "EventPaletteGetByName.h" #include "FastStatistics.h" #include "MathFunctions.h" #include "NumericTextFormatting.h" //because the ROY_BIG_BL palette name is a constant defined in Palette.h #include "Palette.h" #define __PALETTE_COLOR_MAPPING_DECLARE__ #include "PaletteColorMapping.h" #undef __PALETTE_COLOR_MAPPING_DECLARE__ #include "PaletteColorMappingSaxReader.h" #include "PaletteColorMappingXmlElements.h" #include "PaletteScalarAndColor.h" #include "XmlSaxParser.h" #include "XmlUtilities.h" #include "XmlWriter.h" #include using namespace caret; /** * Constructor. * */ PaletteColorMapping::PaletteColorMapping() : CaretObject() { this->initializeMembersPaletteColorMapping(); } /** * Destructor */ PaletteColorMapping::~PaletteColorMapping() { } /** * Copy Constructor * @param Object that is copied. */ PaletteColorMapping::PaletteColorMapping(const PaletteColorMapping& o) : CaretObject(o) { this->initializeMembersPaletteColorMapping(); this->copyHelper(o, true); } /** * Assignment operator. */ PaletteColorMapping& PaletteColorMapping::operator=(const PaletteColorMapping& o) { if (this != &o) { CaretObject::operator=(o); this->copyHelper(o, true); }; return *this; } /** * Copy the palette color mapping from the given palette * color mapping. * @param pcm * Color mapping that is copied to this. * @param copyHistogramAttributesFlag * If true copy histogram attributes. */ void PaletteColorMapping::copy(const PaletteColorMapping& pcm, const bool copyHistogramAttributesFlag) { this->copyHelper(pcm, copyHistogramAttributesFlag); setModified(); } /** * Helps with copy constructor and assignment operator. * * @param pcm * Color mapping that is copied to this. * @param copyHistogramAttributesFlag * If true copy histogram attributes. */ void PaletteColorMapping::copyHelper(const PaletteColorMapping& pcm, const bool copyHistogramAttributesFlag) { this->autoScalePercentageNegativeMaximum = pcm.autoScalePercentageNegativeMaximum; this->autoScalePercentageNegativeMinimum = pcm.autoScalePercentageNegativeMinimum; this->autoScalePercentagePositiveMaximum = pcm.autoScalePercentagePositiveMaximum; this->autoScalePercentagePositiveMinimum = pcm.autoScalePercentagePositiveMinimum; this->autoScaleAbsolutePercentageMaximum = pcm.autoScaleAbsolutePercentageMaximum; this->autoScaleAbsolutePercentageMinimum = pcm.autoScaleAbsolutePercentageMinimum; this->displayNegativeDataFlag = pcm.displayNegativeDataFlag; this->displayPositiveDataFlag = pcm.displayPositiveDataFlag; this->displayZeroDataFlag = pcm.displayZeroDataFlag; this->interpolatePaletteFlag = pcm.interpolatePaletteFlag; this->invertedMode = pcm.invertedMode; this->scaleMode = pcm.scaleMode; this->selectedPaletteName = pcm.selectedPaletteName; this->userScaleNegativeMaximum = pcm.userScaleNegativeMaximum; this->userScaleNegativeMinimum = pcm.userScaleNegativeMinimum; this->userScalePositiveMaximum = pcm.userScalePositiveMaximum; this->userScalePositiveMinimum = pcm.userScalePositiveMinimum; this->thresholdType = pcm.thresholdType; this->thresholdTest = pcm.thresholdTest; this->thresholdNormalMinimum = pcm.thresholdNormalMinimum; this->thresholdNormalMaximum = pcm.thresholdNormalMaximum; this->thresholdMappedMinimum= pcm.thresholdMappedMinimum; this->thresholdMappedMaximum = pcm.thresholdMappedMaximum; this->thresholdMappedAverageAreaMinimum = pcm.thresholdMappedAverageAreaMinimum; this->thresholdMappedAverageAreaMaximum = pcm.thresholdMappedAverageAreaMaximum; this->thresholdDataName = pcm.thresholdDataName; this->thresholdShowFailureInGreen = pcm.thresholdShowFailureInGreen; this->thresholdRangeMode = pcm.thresholdRangeMode; this->thresholdNegMinPosMaxLinked = pcm.thresholdNegMinPosMaxLinked; if (copyHistogramAttributesFlag) { this->histogramRangeMode = pcm.histogramRangeMode; this->histogramBarsVisible = pcm.histogramBarsVisible; this->histogramEnvelopeVisible = pcm.histogramEnvelopeVisible; this->histogramBarsColor = pcm.histogramBarsColor; this->histogramEnvelopeColor = pcm.histogramEnvelopeColor; this->histogramEnvelopeLineWidthPercentage = pcm.histogramEnvelopeLineWidthPercentage; this->histogramNumberOfBuckets = pcm.histogramNumberOfBuckets; } this->colorBarNumericFormatMode = pcm.colorBarNumericFormatMode; this->colorBarPrecisionDigits = pcm.colorBarPrecisionDigits; this->colorBarNumericSubdivisionCount = pcm.colorBarNumericSubdivisionCount; this->colorBarValuesMode = pcm.colorBarValuesMode; this->colorBarShowTickMarksSelected = pcm.colorBarShowTickMarksSelected; this->thresholdOutlineDrawingMode = pcm.thresholdOutlineDrawingMode; this->thresholdOutlineDrawingColor = pcm.thresholdOutlineDrawingColor; this->clearModified(); } /** * Equality operator. * @param pcm * Palette color mapping compared to 'this' palette color mapping. * @return * True if their members are the same. */ bool PaletteColorMapping::operator==(const PaletteColorMapping& pcm) const { bool allMatchFlag = false; if ((this->autoScalePercentageNegativeMaximum == pcm.autoScalePercentageNegativeMaximum) && (this->autoScalePercentageNegativeMinimum == pcm.autoScalePercentageNegativeMinimum) && (this->autoScalePercentagePositiveMaximum == pcm.autoScalePercentagePositiveMaximum) && (this->autoScalePercentagePositiveMinimum == pcm.autoScalePercentagePositiveMinimum) && (this->autoScaleAbsolutePercentageMaximum == pcm.autoScaleAbsolutePercentageMaximum) && (this->autoScaleAbsolutePercentageMinimum == pcm.autoScaleAbsolutePercentageMinimum) && (this->displayNegativeDataFlag == pcm.displayNegativeDataFlag) && (this->displayPositiveDataFlag == pcm.displayPositiveDataFlag) && (this->displayZeroDataFlag == pcm.displayZeroDataFlag) && (this->interpolatePaletteFlag == pcm.interpolatePaletteFlag) && (this->invertedMode == pcm.invertedMode) && (this->scaleMode == pcm.scaleMode) && (this->selectedPaletteName == pcm.selectedPaletteName) && (this->userScaleNegativeMaximum == pcm.userScaleNegativeMaximum) && (this->userScaleNegativeMinimum == pcm.userScaleNegativeMinimum) && (this->userScalePositiveMaximum == pcm.userScalePositiveMaximum) && (this->userScalePositiveMinimum == pcm.userScalePositiveMinimum) && (this->thresholdType == pcm.thresholdType) && (this->thresholdTest == pcm.thresholdTest) && (this->thresholdNormalMinimum == pcm.thresholdNormalMinimum) && (this->thresholdNormalMaximum == pcm.thresholdNormalMaximum) && (this->thresholdMappedMinimum== pcm.thresholdMappedMinimum) && (this->thresholdMappedMaximum == pcm.thresholdMappedMaximum) && (this->thresholdMappedAverageAreaMinimum == pcm.thresholdMappedAverageAreaMinimum) && (this->thresholdMappedAverageAreaMaximum == pcm.thresholdMappedAverageAreaMaximum) && (this->thresholdDataName == pcm.thresholdDataName) && (this->thresholdShowFailureInGreen == pcm.thresholdShowFailureInGreen) && (this->thresholdRangeMode == pcm.thresholdRangeMode) && (this->thresholdNegMinPosMaxLinked == pcm.thresholdNegMinPosMaxLinked) && (this->colorBarNumericFormatMode == pcm.colorBarNumericFormatMode) && (this->colorBarPrecisionDigits == pcm.colorBarPrecisionDigits) && (this->colorBarNumericSubdivisionCount == pcm.colorBarNumericSubdivisionCount) && (this->colorBarValuesMode == pcm.colorBarValuesMode) && (this->colorBarShowTickMarksSelected == pcm.colorBarShowTickMarksSelected) && (this->thresholdOutlineDrawingMode == pcm.thresholdOutlineDrawingMode) && (this->thresholdOutlineDrawingColor == pcm.thresholdOutlineDrawingColor)) { allMatchFlag = true; const bool includeHistogramAttributesFlag = false; if (includeHistogramAttributesFlag) { if ((this->histogramRangeMode == pcm.histogramRangeMode) && (this->histogramBarsVisible == pcm.histogramBarsVisible) && (this->histogramEnvelopeVisible == pcm.histogramEnvelopeVisible) && (this->histogramBarsColor == pcm.histogramBarsColor) && (this->histogramEnvelopeColor == pcm.histogramEnvelopeColor) && (this->histogramEnvelopeLineWidthPercentage == pcm.histogramEnvelopeLineWidthPercentage) && (this->histogramNumberOfBuckets == pcm.histogramNumberOfBuckets)) { allMatchFlag = true; } else { allMatchFlag = false; } } } return allMatchFlag; } void PaletteColorMapping::initializeMembersPaletteColorMapping() { this->scaleMode = PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE; this->autoScalePercentageNegativeMaximum = 98.0f; this->autoScalePercentageNegativeMinimum = 2.0f; this->autoScalePercentagePositiveMinimum = 2.0f; this->autoScalePercentagePositiveMaximum = 98.0f; this->autoScaleAbsolutePercentageMaximum = 98.0f; this->autoScaleAbsolutePercentageMinimum = 2.0f; this->userScaleNegativeMaximum = -100.0f; this->userScaleNegativeMinimum = 0.0f; this->userScalePositiveMinimum = 0.0f; this->userScalePositiveMaximum = 100.0f; this->selectedPaletteName = Palette::ROY_BIG_BL_PALETTE_NAME; this->interpolatePaletteFlag = true; this->invertedMode = PaletteInvertModeEnum::OFF; this->displayPositiveDataFlag = true; this->displayZeroDataFlag = false; this->displayNegativeDataFlag = true; this->thresholdType = PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF; this->thresholdTest = PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE; this->thresholdNormalMinimum = -1.0f; this->thresholdNormalMaximum = 1.0f; this->thresholdMappedMinimum = -1.0f; this->thresholdMappedMaximum = 1.0f; this->thresholdMappedAverageAreaMinimum = -1.0f; this->thresholdMappedAverageAreaMaximum = 1.0f; this->thresholdDataName = ""; this->thresholdShowFailureInGreen = false; this->thresholdRangeMode = PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_FILE; this->thresholdNegMinPosMaxLinked = false; this->histogramRangeMode = PaletteHistogramRangeModeEnum::PALETTE_HISTOGRAM_RANGE_ALL; this->histogramBarsVisible = true; this->histogramEnvelopeVisible = false; this->histogramBarsColor = CaretColorEnum::CUSTOM; // CUSTOM is color with palette this->histogramEnvelopeColor = CaretColorEnum::RED; this->histogramEnvelopeLineWidthPercentage = 0.5f; this->histogramNumberOfBuckets = 100; this->colorBarNumericFormatMode = NumericFormatModeEnum::AUTO; this->colorBarPrecisionDigits = 2; this->colorBarNumericSubdivisionCount = 0; this->colorBarValuesMode = PaletteColorBarValuesModeEnum::DATA; this->colorBarShowTickMarksSelected = false; this->thresholdOutlineDrawingMode = PaletteThresholdOutlineDrawingModeEnum::OFF; this->thresholdOutlineDrawingColor = CaretColorEnum::WHITE; this->modifiedStatus = PaletteModifiedStatusEnum::UNMODIFIED; } /** * Write the object as XML. * @param xmlWriter - write to this-> * @throws XmlException - If an error occurs. * */ void PaletteColorMapping::writeAsXML(XmlWriter& xmlWriter) { XmlAttributes attributes; attributes.addAttribute( PaletteColorMappingXmlElements::XML_ATTRIBUTE_VERSION_NUMBER, PaletteColorMappingXmlElements::XML_VERSION_NUMBER); xmlWriter.writeStartElement( PaletteColorMappingXmlElements::XML_TAG_PALETTE_COLOR_MAPPING, attributes); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_SCALE_MODE, PaletteScaleModeEnum::toName(this->scaleMode)); float autoScaleValues[4] = { this->autoScalePercentageNegativeMaximum, this->autoScalePercentageNegativeMinimum, this->autoScalePercentagePositiveMinimum, this->autoScalePercentagePositiveMaximum }; xmlWriter.writeElementCharacters( PaletteColorMappingXmlElements::XML_TAG_AUTO_SCALE_PERCENTAGE_VALUES, autoScaleValues, 4); float autoScaleAbsolutePercentageValues[2] = { this->autoScaleAbsolutePercentageMinimum, this->autoScaleAbsolutePercentageMaximum }; xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_AUTO_SCALE_ABSOLUTE_PERCENTAGE_VALUES, autoScaleAbsolutePercentageValues, 2); float userScaleValues[4] = { this->userScaleNegativeMaximum, this->userScaleNegativeMinimum, this->userScalePositiveMinimum, this->userScalePositiveMaximum }; xmlWriter.writeElementCharacters( PaletteColorMappingXmlElements::XML_TAG_USER_SCALE_VALUES, userScaleValues, 4); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_PALETTE_NAME, XmlUtilities::encodeXmlSpecialCharacters(this->selectedPaletteName)); xmlWriter.writeElementCharacters( PaletteColorMappingXmlElements::XML_TAG_INTERPOLATE, this->interpolatePaletteFlag); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_INVERT, PaletteInvertModeEnum::toName(this->invertedMode)); xmlWriter.writeElementCharacters( PaletteColorMappingXmlElements::XML_TAG_DISPLAY_POSITIVE, this->displayPositiveDataFlag); xmlWriter.writeElementCharacters( PaletteColorMappingXmlElements::XML_TAG_DISPLAY_ZERO, this->displayZeroDataFlag); xmlWriter.writeElementCharacters( PaletteColorMappingXmlElements::XML_TAG_DISPLAY_NEGATIVE, this->displayNegativeDataFlag); xmlWriter.writeElementCharacters( PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_TEST, PaletteThresholdTestEnum::toName(this->thresholdTest)); xmlWriter.writeElementCharacters( PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_TYPE, PaletteThresholdTypeEnum::toName(this->thresholdType)); xmlWriter.writeElementCharacters( PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_FAILURE_IN_GREEN, this->thresholdShowFailureInGreen); float normalValues[2] = { this->thresholdNormalMinimum, this->thresholdNormalMaximum }; xmlWriter.writeElementCharacters( PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_NORMAL_VALUES, normalValues, 2); float mappedValues[2] = { this->thresholdMappedMinimum, this->thresholdMappedMaximum }; xmlWriter.writeElementCharacters( PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_MAPPED_VALUES, mappedValues, 2); float mappedAvgAreaValues[2] = { this->thresholdMappedAverageAreaMinimum, this->thresholdMappedAverageAreaMaximum }; xmlWriter.writeElementCharacters( PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_MAPPED_AVG_AREA_VALUES, mappedAvgAreaValues, 2); xmlWriter.writeElementCharacters( PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_DATA_NAME, XmlUtilities::encodeXmlSpecialCharacters(this->thresholdDataName)); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_RANGE_MODE, PaletteThresholdRangeModeEnum::toName(this->thresholdRangeMode)); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_NEG_MIN_POS_MAX_LINKED, this->thresholdNegMinPosMaxLinked); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_OUTLINE_DRAWING_MODE, PaletteThresholdOutlineDrawingModeEnum::toName(this->thresholdOutlineDrawingMode)); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_OUTLINE_DRAWING_COLOR, CaretColorEnum::toName(this->thresholdOutlineDrawingColor)); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_RANGE_MODE, PaletteHistogramRangeModeEnum::toName(this->histogramRangeMode)); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_BARS_VISIBLE, this->histogramBarsVisible); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_ENVELOPE_VISIBLE, this->histogramEnvelopeVisible); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_BARS_COLOR, CaretColorEnum::toName(this->histogramBarsColor)); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_ENVELOPE_COLOR, CaretColorEnum::toName(this->histogramEnvelopeColor)); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_ENVELOPE_LINE_WIDTH_PERCENTAGE, this->histogramEnvelopeLineWidthPercentage); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_NUMBER_OF_BUCKETS, this->histogramNumberOfBuckets); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_NUMERIC_FORMAT_MODE, NumericFormatModeEnum::toName(this->colorBarNumericFormatMode)); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_PRECISION_DIGITS, this->colorBarPrecisionDigits); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_NUMERIC_SUBDIVISIONS, this->colorBarNumericSubdivisionCount); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_COLOR_BAR_VALUES_MODE, PaletteColorBarValuesModeEnum::toName(this->colorBarValuesMode)); xmlWriter.writeElementCharacters(PaletteColorMappingXmlElements::XML_TAG_SHOW_TICK_MARKS, this->colorBarShowTickMarksSelected); xmlWriter.writeEndElement(); } /** * Returns the XML representation of this object in a String. * * @return String containing XML. * @throws XmlException if an error occurs. * */ AString PaletteColorMapping::encodeInXML() { std::ostringstream str; XmlWriter xmlWriter(str); this->writeAsXML(xmlWriter); AString s = AString::fromStdString(str.str()); return s; } /** * Decode this object from a String containing XML. * @param xml - String containing XML. * @throws XmlException If an error occurs. * */ void PaletteColorMapping::decodeFromStringXML(const AString& xml) { PaletteColorMappingSaxReader saxReader(this); CaretPointer parser(XmlSaxParser::createXmlParser()); try { parser->parseString(xml, &saxReader); } catch (XmlSaxParserException& e) { int lineNum = e.getLineNumber(); int colNum = e.getColumnNumber(); std::ostringstream str; str << "Parse Error while reading PaletteColorMapping XML"; if ((lineNum >= 0) && (colNum >= 0)) { str << " line/col (" << e.getLineNumber() << "/" << e.getColumnNumber() << ")"; } str << ": " << e.whatString().toStdString(); throw XmlException(AString::fromStdString(str.str())); } } /** * Setup an annotation color bar with its color sections. * * @param statistics * Statistics of data for colorbar. * @param colorBar * The annotation colorbar that has its color sections set. */ void PaletteColorMapping::setupAnnotationColorBar(const FastStatistics* statistics, AnnotationColorBar* colorBar) { CaretAssert(statistics); CaretAssert(colorBar); colorBar->clearSections(); const Palette* palette = getPalette(); CaretAssert(palette); /* * Types of values for display */ float xMinimum = 0.0; float xMaximum = 0.0; if (this->displayPositiveDataFlag) { xMaximum = 1.0; } if (this->displayNegativeDataFlag) { xMinimum = -1.0; } /* * Always interpolate if the palette has only two colors */ bool interpolateColor = this->interpolatePaletteFlag; if (palette->getNumberOfScalarsAndColors() <= 2) { interpolateColor = true; } float zeroRGBA[4] = { 0.0, 0.0, 0.0, 0.0 }; if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_FLIP_PALETTE_NOT_DATA)) { /* * Palettes start with most positive scalar value that in on right side of palette */ const int32_t numberOfColors = palette->getNumberOfScalarsAndColors(); const bool interpolationOnFlag = interpolateColor; const int32_t lastColorIndex = numberOfColors - 1; for (int32_t index = 0; index < numberOfColors; index++) { const PaletteScalarAndColor* rightSideScalarColor = palette->getScalarAndColor(index); if (rightSideScalarColor->isNoneColor()) { /* * No drawing for "none" color; skip to next color */ continue; } /* * Add vertices for right side of quad */ float rightSideScalar = rightSideScalarColor->getScalar(); if (index == 0) { rightSideScalar = xMaximum; // First color extends to right side } float rightSideRGBA[4]; rightSideScalarColor->getColor(rightSideRGBA); /* * Default left side of palette subsection to far left side * and same color as right side of palette subsection */ float leftSideScalar = xMinimum; float leftSideRGBA[4] = { rightSideRGBA[0], rightSideRGBA[1], rightSideRGBA[2], rightSideRGBA[3] }; /* * Determine the next scalar and color index for left side of quad * Left side color is same color as right if: * # At last color in palette * # Next color is "none" * # Interpolation is OFF */ int32_t nextIndex = index + 1; if (nextIndex <= lastColorIndex) { /* * Set scalar value for left side of subsection of palette */ const PaletteScalarAndColor* leftSideScalarColor = palette->getScalarAndColor(nextIndex); leftSideScalar = leftSideScalarColor->getScalar(); if (palette->getScalarAndColor(nextIndex)->isNoneColor()) { /* * No interpolation if left side of subsection is "none" color */ } else if (interpolationOnFlag) { /* * Set color for left side of subsection of palette */ leftSideScalarColor->getColor(leftSideRGBA); } } if ((rightSideScalar >= 0.0) && (leftSideScalar <= 0.0)) { /* * Used for special case when zero is one but both * negative and postive are off */ const float diff = rightSideScalar - leftSideScalar; if (diff > 0.0) { const float rightWeight = rightSideScalar; const float leftWeight = -leftSideScalar; for (int32_t m = 0; m < 4; m++) { zeroRGBA[m] = ((leftSideRGBA[m] * leftWeight) + (rightSideRGBA[m] * rightWeight)); } } else { for (int32_t m = 0; m < 4; m++) { zeroRGBA[m] = rightSideRGBA[m]; } } } /* * Add a section to the color bar */ leftSideScalar = MathFunctions::limitRange(leftSideScalar, xMinimum, xMaximum); rightSideScalar = MathFunctions::limitRange(rightSideScalar, xMinimum, xMaximum); if (rightSideScalar > leftSideScalar) { colorBar->addSection(leftSideScalar, rightSideScalar, leftSideRGBA, rightSideRGBA); } } } else {//flip the control point values, like the palette inversion code - would be a lot simpler to just draw a lot of boxes and approximate it, but now that this is working... bool invert_pos_neg = false;//draw the sections from the palette control points, invert their positions as needed bool invert_min_max = false;//use same size of zero range for display as is specified for the zero range hack in the palette definitions int inv_min_max_zero_maps_to = 0; bool displayPosColors = this->displayPositiveDataFlag, displayNegColors = this->displayNegativeDataFlag; //convert the inversion settings into the orthogonal inversions that could be applied simultaneously, if desired switch (this->invertedMode) { case PaletteInvertModeEnum::OFF: break; case PaletteInvertModeEnum::POSITIVE_NEGATIVE_SEPARATE: invert_min_max = true; break; case PaletteInvertModeEnum::POSITIVE_WITH_NEGATIVE: invert_pos_neg = true; displayPosColors = this->displayNegativeDataFlag; displayNegColors = this->displayPositiveDataFlag; break; } if (invert_min_max && (inv_min_max_zero_maps_to > 1 || inv_min_max_zero_maps_to < -1)) { CaretLogWarning("invalid 'inv_min_max_zero_maps_to' setting '" + AString::number(inv_min_max_zero_maps_to) + "' for min/max palette inversion, resetting to 0"); inv_min_max_zero_maps_to = 0; } if (invert_min_max) { if (invert_pos_neg)//when both apply, the positive data range uses negative colors, so it should map to the most negative color instead { palette->getPaletteColor(-inv_min_max_zero_maps_to, interpolateColor, zeroRGBA); } else { palette->getPaletteColor(inv_min_max_zero_maps_to, interpolateColor, zeroRGBA); } } else { palette->getPaletteColor(0.0f, interpolateColor, zeroRGBA);//palette should give the right answer for 0 color } const int32_t numberOfColors = palette->getNumberOfScalarsAndColors(); //take two, now that I know where the skeletons are: single loop, always insert virtual zero point, because it is also needed for turning off positive or negative range cleanly for (int i = -1; i < numberOfColors; ++i)//also insert virtual points at 1 and -1 if they don't exist { PaletteScalarAndColor* highSideScalarColor = NULL, *lowSideScalarColor = NULL; if (i > 0) highSideScalarColor = palette->getScalarAndColor(i); if (i < numberOfColors - 1) lowSideScalarColor = palette->getScalarAndColor(i + 1); float highScalar = 1.0f, lowScalar = -1.0f; if (highSideScalarColor != NULL) highScalar = highSideScalarColor->getScalar(); if (lowSideScalarColor != NULL) lowScalar = lowSideScalarColor->getScalar(); if (lowScalar == highScalar) continue;//all special cases of extra virtual pieces of the noninverted palette are handled at this point, we just need to color them, split at zero, and reposition for inversion bool colorIsNone = (highSideScalarColor != NULL && highSideScalarColor->isNoneColor()); bool interpolateSection = (interpolateColor && (lowSideScalarColor == NULL || !lowSideScalarColor->isNoneColor())); if (displayPosColors && highScalar > PALETTE_ZERO_COLOR_ZONE) { float highPosition = highScalar, lowPosition = lowScalar; if (lowPosition < -PALETTE_ZERO_COLOR_ZONE) lowPosition = 0.0f;//don't draw across zero float highRGBA[4], lowRGBA[4]; if (colorIsNone) { colorBar->getBackgroundColorRGBA(highRGBA);//drawing a section in background color makes sure it doesn't get shifted around colorBar->getBackgroundColorRGBA(lowRGBA); } else { palette->getPaletteColor(highScalar, interpolateColor, highRGBA);//palette should always give the right answer as long as point isn't none, allows easier treatment of splitting for 0 and added end bar if (interpolateSection)//when exactly on the control point, it should consider it in the range between that and the lower point, and give the equivalent of the PSAC { palette->getPaletteColor(lowPosition, interpolateColor, lowRGBA);//NOTE: this uses Position because it could be a virtual inserted zero point } else { palette->getPaletteColor(highScalar, interpolateColor, lowRGBA); } } if (invert_min_max)//doing this manually here means that the normalization code can't introduce a discontinuity { highPosition = 1.0f - highPosition + PALETTE_ZERO_COLOR_ZONE;//for consistency, keep them in the same range lowPosition = 1.0f - lowPosition + PALETTE_ZERO_COLOR_ZONE;//could instead stretch them to 0 to 1 when converting from scalar to position if (lowPosition > 1.0f) lowPosition = 1.0f; } if (invert_pos_neg) { highPosition = -highPosition; lowPosition = -lowPosition; } if (highPosition < lowPosition) {//color bar section drawing has normals test enabled, for whatever reason, so make sure these are the right way round colorBar->addSection(highPosition, lowPosition, highRGBA, lowRGBA);//trust that palettes are sanity checked to not have control points outside [-1, 1] } else { colorBar->addSection(lowPosition, highPosition, lowRGBA, highRGBA);//trust that palettes are sanity checked to not have control points outside [-1, 1] } } if (displayNegColors && lowScalar < -PALETTE_ZERO_COLOR_ZONE) { float highPosition = highScalar, lowPosition = lowScalar; if (highPosition > PALETTE_ZERO_COLOR_ZONE) highPosition = 0.0f;//don't draw across zero float highRGBA[4], lowRGBA[4]; if (colorIsNone) { colorBar->getBackgroundColorRGBA(highRGBA);//drawing a section in background color makes sure it doesn't get shifted around colorBar->getBackgroundColorRGBA(lowRGBA); } else { if (interpolateSection) { palette->getPaletteColor(highPosition, interpolateColor, highRGBA);//NOTE: this uses Position because it could be a virtual inserted zero point palette->getPaletteColor(lowScalar, interpolateColor, lowRGBA); } else { palette->getPaletteColor(highScalar, interpolateColor, highRGBA); palette->getPaletteColor(highScalar, interpolateColor, lowRGBA); } } if (invert_min_max)//doing this manually here means that the normalization code can't introduce a discontinuity { highPosition = -1.0f - highPosition - PALETTE_ZERO_COLOR_ZONE; lowPosition = -1.0f - lowPosition - PALETTE_ZERO_COLOR_ZONE; if (highPosition < -1.0f) highPosition = -1.0f; } if (invert_pos_neg) { highPosition = -highPosition; lowPosition = -lowPosition; } if (highPosition < lowPosition) {//color bar section drawing has normals test enabled, for whatever reason, so make sure these are the right way round colorBar->addSection(highPosition, lowPosition, highRGBA, lowRGBA);//trust that palettes are sanity checked to not have control points outside [-1, 1] } else { colorBar->addSection(lowPosition, highPosition, lowRGBA, highRGBA);//trust that palettes are sanity checked to not have control points outside [-1, 1] } } }//so much cleaner, and handles edge cases the other didn't //zero: use the color that exact zeros should get colored as by asking the palette, after applying zero mapping setting //draw it last so any discontinuity is visible if (this->displayZeroDataFlag) { colorBar->addSection(0.0f, 0.0f, zeroRGBA, zeroRGBA);//NOTE: zero-width ranges are treated specially, drawn as lines, which will be thicker than the palette special zero range } } float backgroundRGBA[4]; colorBar->getBackgroundColorRGBA(backgroundRGBA); /* * Draw over thresholded regions with background color */ bool thresholdSelfFlag = false; switch (thresholdType) { case PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF: break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_NORMAL: thresholdSelfFlag = true; break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_FILE: break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED: break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED_AVERAGE_AREA: break; } if (thresholdSelfFlag) { const float minMaxThresholds[2] = { getThresholdMinimum(thresholdType), getThresholdMaximum(thresholdType) }; float normalizedThresholds[2]; if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_FLIP_PALETTE_NOT_DATA)) { mapDataToPaletteNormalizedValues(statistics, minMaxThresholds, normalizedThresholds, 2); } else {//this assumes the same zero size in palette display as is reserved in the palette definitions PaletteColorMapping normalize_noinv = *this; normalize_noinv.setInvertedMode(PaletteInvertModeEnum::OFF); normalize_noinv.mapDataToPaletteNormalizedValues(statistics, minMaxThresholds, normalizedThresholds, 2); } switch (this->thresholdTest) { case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_INSIDE: if (normalizedThresholds[0] >= xMinimum) { colorBar->addSection(xMinimum, normalizedThresholds[0], backgroundRGBA, backgroundRGBA); } if (normalizedThresholds[1] < xMaximum) { colorBar->addSection(normalizedThresholds[1], xMaximum, backgroundRGBA, backgroundRGBA); } break; case PaletteThresholdTestEnum::THRESHOLD_TEST_SHOW_OUTSIDE: { const float xMin = MathFunctions::limitRange(normalizedThresholds[0], xMinimum, xMaximum); const float xMax = MathFunctions::limitRange(normalizedThresholds[1], xMinimum, xMaximum); if (xMin < xMax) { colorBar->addSection(xMin, xMax, backgroundRGBA, backgroundRGBA); } } break; } } /* * If zeros are not displayed, draw a line in the * background color at zero in the palette. */ if ( ! this->displayZeroDataFlag) { colorBar->addSection(0.0, 0.0, backgroundRGBA, backgroundRGBA);//NOTE: zero-width ranges are treated specially, drawn as lines } /* * If only zero is displayed */ if (this->displayZeroDataFlag && ( ! this->displayPositiveDataFlag) && ( ! this->displayNegativeDataFlag)) { if (zeroRGBA[3] > 0.0) { colorBar->addSection(-1.0, 0.0, backgroundRGBA, backgroundRGBA); colorBar->addSection( 0.0, 1.0, backgroundRGBA, backgroundRGBA);//TSC: fix the reversed drawing of the positive section, and place zero last so that it shows colorBar->addSection( 0.0, 0.0, zeroRGBA, zeroRGBA); } } /** * Add numeric text to the color bar. */ setupAnnotationColorBarNumericText(statistics, colorBar); } /** * Get auto scale percentage negative maximum. * @return Its value. * */ float PaletteColorMapping::getAutoScalePercentageNegativeMaximum() const { return autoScalePercentageNegativeMaximum; } /** * Set auto scale percentage negative maximum. * @param autoScalePercentageNegativeMaximum - new value. * */ void PaletteColorMapping::setAutoScalePercentageNegativeMaximum(const float autoScalePercentageNegativeMaximum) { if (this->autoScalePercentageNegativeMaximum != autoScalePercentageNegativeMaximum) { this->autoScalePercentageNegativeMaximum = autoScalePercentageNegativeMaximum; this->setModified(); } } /** * Get auto scale percentage negative minimum. * @return Its value. * */ float PaletteColorMapping::getAutoScalePercentageNegativeMinimum() const { return autoScalePercentageNegativeMinimum; } /** * Set auto scale percentage negative minimum. * @param autoScalePercentageNegativeMinimum - new value. * */ void PaletteColorMapping::setAutoScalePercentageNegativeMinimum(const float autoScalePercentageNegativeMinimum) { if (this->autoScalePercentageNegativeMinimum != autoScalePercentageNegativeMinimum) { this->autoScalePercentageNegativeMinimum = autoScalePercentageNegativeMinimum; this->setModified(); } } /** * Get auto scale percentage positive maximum. * @return Its value. * */ float PaletteColorMapping::getAutoScalePercentagePositiveMaximum() const { return autoScalePercentagePositiveMaximum; } /** * Set auto scale percentage positive maximum. * @param autoScalePercentagePositiveMaximum - new value. * */ void PaletteColorMapping::setAutoScalePercentagePositiveMaximum(const float autoScalePercentagePositiveMaximum) { if (this->autoScalePercentagePositiveMaximum != autoScalePercentagePositiveMaximum) { this->autoScalePercentagePositiveMaximum = autoScalePercentagePositiveMaximum; this->setModified(); } } /** * Get auto scale percentage positive minimum. * @return Its value. * */ float PaletteColorMapping::getAutoScalePercentagePositiveMinimum() const { return autoScalePercentagePositiveMinimum; } /** * Set auto scale percentage positive minimum. * @param autoScalePercentagePositiveMinimum - new value. * */ void PaletteColorMapping::setAutoScalePercentagePositiveMinimum(const float autoScalePercentagePositiveMinimum) { if (this->autoScalePercentagePositiveMinimum != autoScalePercentagePositiveMinimum) { this->autoScalePercentagePositiveMinimum = autoScalePercentagePositiveMinimum; this->setModified(); } } /** * @return The auto scale absolute percentage minimum. */ float PaletteColorMapping::getAutoScaleAbsolutePercentageMinimum() const { return this->autoScaleAbsolutePercentageMinimum; } /** * Set the auto scale absolute percentage minimum. * * @param autoScaleAbsolutePercentageMinimum * New value for auto scale absolute percentage minimum. */ void PaletteColorMapping::setAutoScaleAbsolutePercentageMinimum(const float autoScaleAbsolutePercentageMinimum) { if (this->autoScaleAbsolutePercentageMinimum != autoScaleAbsolutePercentageMinimum) { this->autoScaleAbsolutePercentageMinimum = autoScaleAbsolutePercentageMinimum; this->setModified(); } } /** * @return The auto scale absolute percentage maximum. */ float PaletteColorMapping::getAutoScaleAbsolutePercentageMaximum() const { return this->autoScaleAbsolutePercentageMaximum; } /** * Set the auto scale absolute percentage maximum. * * @param autoScaleAbsolutePercentageMaximum * New value for auto scale absolute percentage maximum. */ void PaletteColorMapping::setAutoScaleAbsolutePercentageMaximum(const float autoScaleAbsolutePercentageMaximum) { if (this->autoScaleAbsolutePercentageMaximum != autoScaleAbsolutePercentageMaximum) { this->autoScaleAbsolutePercentageMaximum = autoScaleAbsolutePercentageMaximum; this->setModified(); } } /** * See if negative data should be displayed. * @return true if negative data displayed, else false. * */ bool PaletteColorMapping::isDisplayNegativeDataFlag() const { return displayNegativeDataFlag; } /** * Set negative data should be displayed. * @param displayNegativeDataFlag - true to display negative data, else false * */ void PaletteColorMapping::setDisplayNegativeDataFlag(const bool displayNegativeDataFlag) { if (this->displayNegativeDataFlag != displayNegativeDataFlag) { this->displayNegativeDataFlag = displayNegativeDataFlag; this->setModified(); } } /** * See if positive data should be displayed. * @return true if positive data displayed, else false. * */ bool PaletteColorMapping::isDisplayPositiveDataFlag() const { return displayPositiveDataFlag; } /** * Set positive data should be displayed. * @param displayPositiveDataFlag - true to display positive data, else false * */ void PaletteColorMapping::setDisplayPositiveDataFlag(const bool displayPositiveDataFlag) { if (this->displayPositiveDataFlag != displayPositiveDataFlag) { this->displayPositiveDataFlag = displayPositiveDataFlag; this->setModified(); } } /** * See if zero data should be displayed. * @return true if zero data displayed, else false. * */ bool PaletteColorMapping::isDisplayZeroDataFlag() const { return displayZeroDataFlag; } /** * Set zero data should be displayed. * @param displayZeroDataFlag - true to display zero data, else false * */ void PaletteColorMapping::setDisplayZeroDataFlag(const bool displayZeroDataFlag) { if (this->displayZeroDataFlag != displayZeroDataFlag) { this->displayZeroDataFlag = displayZeroDataFlag; this->setModified(); } } /** * Interpolate palette colors when displaying data? * @return true to interpolate data, else false. * */ bool PaletteColorMapping::isInterpolatePaletteFlag() const { return interpolatePaletteFlag; } /** * Set palette colors should be interpolated when displaying data. * @param interpolatePaletteFlag - true to interpolate, else false. * */ void PaletteColorMapping::setInterpolatePaletteFlag(const bool interpolatePaletteFlag) { if (this->interpolatePaletteFlag != interpolatePaletteFlag) { this->interpolatePaletteFlag = interpolatePaletteFlag; this->setModified(); } } /** * @return The inverted mode. */ PaletteInvertModeEnum::Enum PaletteColorMapping::getInvertedMode() const { return this->invertedMode; } /** * Set the inverted mode * * @param invertedMode * New inverted mode. */ void PaletteColorMapping::setInvertedMode(const PaletteInvertModeEnum::Enum invertedMode) { if (this->invertedMode != invertedMode) { this->invertedMode = invertedMode; setModified(); } } /** * Get how the data is scaled to the palette. * @return Enumerated type indicating how data is scaled to the palette. * */ PaletteScaleModeEnum::Enum PaletteColorMapping::getScaleMode() const { return scaleMode; } /** * Set how the data is scaled to the palette. * @param scaleMode - Enumerated type indicating how data is scaled * to the palette. * */ void PaletteColorMapping::setScaleMode(const PaletteScaleModeEnum::Enum scaleMode) { if (this->scaleMode != scaleMode) { this->scaleMode = scaleMode; this->setModified(); } } /** * @return The palette used by this palette color mapping. * This method should always return a valid palette. * * If the inverted palette flag is set, this will return * the inverted version of the palette. * * The palette is set by calling setSelectedPaletteName(). * * If the palette name does not match a valid palette, * the default palette (ROY-BIG-BL) is returned. */ const Palette* PaletteColorMapping::getPalette() const { const AString paletteName = getSelectedPaletteName(); EventPaletteGetByName paletteEvent(paletteName); EventManager::get()->sendEvent(paletteEvent.getPointer()); Palette* palette = paletteEvent.getPalette(); if (palette == NULL) { if (s_missingPaletteNames.find(paletteName) == s_missingPaletteNames.end()) { s_missingPaletteNames.insert(paletteName); CaretLogSevere("Palette named " + paletteName + " is not a valid palette name."); } /* * Use the "default" palette */ EventPaletteGetByName paletteEvent(Palette::getDefaultPaletteName()); EventManager::get()->sendEvent(paletteEvent.getPointer()); palette = paletteEvent.getPalette(); CaretAssert(palette); } if (DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_FLIP_PALETTE_NOT_DATA)) { switch (this->invertedMode) { case PaletteInvertModeEnum::OFF: break; case PaletteInvertModeEnum::POSITIVE_WITH_NEGATIVE: return palette->getInvertedPalette(); break; case PaletteInvertModeEnum::POSITIVE_NEGATIVE_SEPARATE: return palette->getNoneSeparateInvertedPalette(); //return palette->getSignSeparateInvertedPalette(); break; } } return palette; } /** * Get the name of the selected palette. * @return Name of the selected palette. * */ AString PaletteColorMapping::getSelectedPaletteName() const { return selectedPaletteName; } /** * Set the name of the selected palette. * @param selectedPaletteName - Name of selected palette. * */ void PaletteColorMapping::setSelectedPaletteName(const AString& selectedPaletteName) { if (this->selectedPaletteName != selectedPaletteName) { this->selectedPaletteName = selectedPaletteName; this->setModified(); } } /** * Set the selected palette to PSYCH. * */ void PaletteColorMapping::setSelectedPaletteToPsych() { this->setSelectedPaletteName("PSYCH"); } /** * Set the selected palette to PSYCH-NO-NONE * */ void PaletteColorMapping::setSelectedPaletteToPsychNoNone() { this->setSelectedPaletteName("PSYCH-NO-NONE"); } /** * Set the selected palette to Orange-Yellow. * */ void PaletteColorMapping::setSelectedPaletteToOrangeYellow() { this->setSelectedPaletteName("Orange-Yellow"); } /** * Set the selected palette to Gray Interpolated. * */ void PaletteColorMapping::setSelectedPaletteToGrayInterpolated() { this->setSelectedPaletteName("Gray_Interp"); } /** * Get auto user scale negative maximum. * @return Its value. * */ float PaletteColorMapping::getUserScaleNegativeMaximum() const { return userScaleNegativeMaximum; } /** * Set user scale negative maximum. * @param userScaleNegativeMaximum - new value. * */ void PaletteColorMapping::setUserScaleNegativeMaximum(const float userScaleNegativeMaximum) { if (this->userScaleNegativeMaximum != userScaleNegativeMaximum) { this->userScaleNegativeMaximum = userScaleNegativeMaximum; this->setModified(); } } /** * Get auto user scale negative minimum. * @return Its value. * */ float PaletteColorMapping::getUserScaleNegativeMinimum() const { return userScaleNegativeMinimum; } /** * Set user scale negative minimum. * @param userScaleNegativeMinimum - new value. * */ void PaletteColorMapping::setUserScaleNegativeMinimum(const float userScaleNegativeMinimum) { if (this->userScaleNegativeMinimum != userScaleNegativeMinimum) { this->userScaleNegativeMinimum = userScaleNegativeMinimum; this->setModified(); } } /** * Get auto user scale positive maximum. * @return Its value. * */ float PaletteColorMapping::getUserScalePositiveMaximum() const { return userScalePositiveMaximum; } /** * Set user scale positive maximum. * @param userScalePositiveMaximum - new value. * */ void PaletteColorMapping::setUserScalePositiveMaximum(const float userScalePositiveMaximum) { if (this->userScalePositiveMaximum != userScalePositiveMaximum) { this->userScalePositiveMaximum = userScalePositiveMaximum; this->setModified(); } } /** * Get auto user scale positive maximum. * @return Its value. * */ float PaletteColorMapping::getUserScalePositiveMinimum() const { return userScalePositiveMinimum; } /** * Set user scale positive minimum. * @param userScalePositiveMinimum - new value. * */ void PaletteColorMapping::setUserScalePositiveMinimum(const float userScalePositiveMinimum) { if (this->userScalePositiveMinimum != userScalePositiveMinimum) { this->userScalePositiveMinimum = userScalePositiveMinimum; this->setModified(); } } /** * Get the minimum threshold for the given threshold type. * * @param thresholdType * The threshold type. * @return the threshold's value. * */ float PaletteColorMapping::getThresholdMinimum(const PaletteThresholdTypeEnum::Enum thresholdType) const { float value = 0.0; switch (thresholdType) { case PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF: break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_NORMAL: value = this->thresholdNormalMinimum; break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_FILE: value = this->thresholdNormalMinimum; break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED: value = this->thresholdMappedMinimum; break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED_AVERAGE_AREA: value = this->thresholdMappedAverageAreaMinimum; break; } return value; } /** * Get the minimum threshold for the given threshold type. * * @param thresholdType * The threshold type. * @return the threshold's value. * */ float PaletteColorMapping::getThresholdMaximum(const PaletteThresholdTypeEnum::Enum thresholdType) const { float value = 0.0; switch (thresholdType) { case PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF: break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_NORMAL: value = this->thresholdNormalMaximum; break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_FILE: value = this->thresholdNormalMaximum; break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED: value = this->thresholdMappedMaximum; break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED_AVERAGE_AREA: value = this->thresholdMappedAverageAreaMaximum; break; } return value; } /** * Set the minimum threshold for the given threshold type. * * @param thresholdType * The threshold type. * param thresholdMinimum the threshold's new value. * */ void PaletteColorMapping::setThresholdMinimum(const PaletteThresholdTypeEnum::Enum thresholdType, const float thresholdMinimum) { switch (thresholdType) { case PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF: break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_NORMAL: setThresholdNormalMinimum(thresholdMinimum); break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_FILE: setThresholdNormalMinimum(thresholdMinimum); break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED: setThresholdMappedMinimum(thresholdMinimum); break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED_AVERAGE_AREA: setThresholdMappedAverageAreaMinimum(thresholdMinimum); break; } } /** * Set the maximum threshold for the given threshold type. * * @param thresholdType * The threshold type. * param thresholdMaximum the threshold's new value. * */ void PaletteColorMapping::setThresholdMaximum(const PaletteThresholdTypeEnum::Enum thresholdType, const float thresholdMaximum) { switch (thresholdType) { case PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF: break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_NORMAL: setThresholdNormalMaximum(thresholdMaximum); break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_FILE: setThresholdNormalMaximum(thresholdMaximum); break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED: setThresholdMappedMaximum(thresholdMaximum); break; case PaletteThresholdTypeEnum::THRESHOLD_TYPE_MAPPED_AVERAGE_AREA: setThresholdMappedAverageAreaMaximum(thresholdMaximum); break; } } /** * Get mapped average area minimum threshold * * @return the threshold's value. * */ float PaletteColorMapping::getThresholdMappedAverageAreaMinimum() const { return thresholdMappedAverageAreaMinimum; } /** * Set the mapped average area minimum threshold. * * @param thresholdMappedAverageAreaNegative - new value. * */ void PaletteColorMapping::setThresholdMappedAverageAreaMinimum(const float thresholdMappedAverageAreaMinimum) { if (this->thresholdMappedAverageAreaMinimum != thresholdMappedAverageAreaMinimum) { this->thresholdMappedAverageAreaMinimum = thresholdMappedAverageAreaMinimum; this->setModified(); } } /** * Get mapped average area maximum threshold * * @return the threshold's value. * */ float PaletteColorMapping::getThresholdMappedAverageAreaMaximum() const { return thresholdMappedAverageAreaMaximum; } /** * Set the mapped average area maximum threshold. * * @param thresholdMappedAverageAreaPositive - new value. * */ void PaletteColorMapping::setThresholdMappedAverageAreaMaximum(const float thresholdMappedAverageAreaMaximum) { if (this->thresholdMappedAverageAreaMaximum != thresholdMappedAverageAreaMaximum) { this->thresholdMappedAverageAreaMaximum = thresholdMappedAverageAreaMaximum; this->setModified(); } } /** * Get mapped minimum threshold * * @return the threshold's value. * */ float PaletteColorMapping::getThresholdMappedMinimum() const { return thresholdMappedMinimum; } /** * Set the mapped minimum threshold. * * @param thresholdMappedNegative - new value. * */ void PaletteColorMapping::setThresholdMappedMinimum(const float thresholdMappedMinimum) { if (this->thresholdMappedMinimum != thresholdMappedMinimum) { this->thresholdMappedMinimum = thresholdMappedMinimum; this->setModified(); } } /** * Get mapped maximum threshold * * @return the threshold's value. * */ float PaletteColorMapping::getThresholdMappedMaximum() const { return thresholdMappedMaximum; } /** * Set the mapped maximum threshold. * * @param thresholdMappedPositive - new value. * */ void PaletteColorMapping::setThresholdMappedMaximum(const float thresholdMappedMaximum) { if (this->thresholdMappedMaximum != thresholdMappedMaximum) { this->thresholdMappedMaximum = thresholdMappedMaximum; this->setModified(); } } /** * Get normal minimum threshold * * @return the threshold's value. * */ float PaletteColorMapping::getThresholdNormalMinimum() const { return thresholdNormalMinimum; } /** * Set the normal minimum threshold. * * @param thresholdNormalNegative - new value. * */ void PaletteColorMapping::setThresholdNormalMinimum(const float thresholdNormalMinimum) { if (this->thresholdNormalMinimum != thresholdNormalMinimum) { this->thresholdNormalMinimum = thresholdNormalMinimum; this->setModified(); } } /** * Get normal maximum threshold * * @return the threshold's value. * */ float PaletteColorMapping::getThresholdNormalMaximum() const { return thresholdNormalMaximum; } /** * Set the normal maximum threshold. * * @param thresholdNormalPositive - new value. * */ void PaletteColorMapping::setThresholdNormalMaximum(const float thresholdNormalMaximum) { if (this->thresholdNormalMaximum != thresholdNormalMaximum) { this->thresholdNormalMaximum = thresholdNormalMaximum; this->setModified(); } } /** * Get the threshold test. * @return Threshold test. * */ PaletteThresholdTestEnum::Enum PaletteColorMapping::getThresholdTest() const { return thresholdTest; } /** * Set the threshold test. * @param thresholdTest - The threshold test. * */ void PaletteColorMapping::setThresholdTest(const PaletteThresholdTestEnum::Enum thresholdTest) { if (this->thresholdTest != thresholdTest) { this->thresholdTest = thresholdTest; this->setModified(); } } /** * Get the threshold type. * @return Threshold type. * */ PaletteThresholdTypeEnum::Enum PaletteColorMapping::getThresholdType() const { return thresholdType; } /** * Set the threshold type. * * @param thresholdType - The threshold type. */ void PaletteColorMapping::setThresholdType(const PaletteThresholdTypeEnum::Enum thresholdType) { if (this->thresholdType != thresholdType) { this->thresholdType = thresholdType; this->setModified(); } } /** * @return The threshold range mode. */ PaletteThresholdRangeModeEnum::Enum PaletteColorMapping::getThresholdRangeMode() const { return this->thresholdRangeMode; } /** * Set the threshold range mode. * * @param rangeMode * New value for range mode. */ void PaletteColorMapping::setThresholdRangeMode(const PaletteThresholdRangeModeEnum::Enum rangeMode) { if (this->thresholdRangeMode != rangeMode) { this->thresholdRangeMode = rangeMode; setModified(); } } /** * Get the name of the threshold data which may be the name of a * functional volume or a metric column. * @return Name of data used as a threshold. * */ AString PaletteColorMapping::getThresholdDataName() const { return thresholdDataName; } /** * Set the name of the threshold data which may be the name of a * functional volume or a metric column. * @param thresholdDataName - name of data used as a threshold. * */ void PaletteColorMapping::setThresholdDataName(const AString& thresholdDataName) { if (this->thresholdDataName != thresholdDataName) { this->thresholdDataName = thresholdDataName; this->setModified(); } } /** * Display non-zero data that fails the threshold test in green? * @return true if displayed, else false. * */ bool PaletteColorMapping::isShowThresholdFailureInGreen() const { return this->thresholdShowFailureInGreen; } /** * Set display non-zero data that fails the threshold test in green? * @param showInGreenFlag - true if displayed, else false. * */ void PaletteColorMapping::setShowThresholdFailureInGreen(const bool showInGreenFlag) { if (this->thresholdShowFailureInGreen != showInGreenFlag) { this->thresholdShowFailureInGreen = showInGreenFlag; setModified(); } } /** * Set this object has been modified. * */ void PaletteColorMapping::setModified() { this->modifiedStatus = PaletteModifiedStatusEnum::MODIFIED; } /** * Set this object as not modified. Object should also * clear the modification status of its children. * */ void PaletteColorMapping::clearModified() { this->modifiedStatus = PaletteModifiedStatusEnum::UNMODIFIED; } /** * Get the modification status. Returns true if this object * or any of its children have been modified. * @return - The modification status. * */ bool PaletteColorMapping::isModified() const { return (this->modifiedStatus == PaletteModifiedStatusEnum::MODIFIED); } /** * @return Modified status enumerated type that indicates specific type of modification */ PaletteModifiedStatusEnum::Enum PaletteColorMapping::getModifiedStatus() const { return this->modifiedStatus; } /** * When restored from a scene, need to set the * 'scene modified' status to both avoid 'file modified' warnings * but need to save palette to any new scenes */ void PaletteColorMapping::setSceneModified() { this->modifiedStatus = PaletteModifiedStatusEnum::MODIFIED_BY_SHOW_SCENE; } /** * Map data values to palette normalized values using the * settings in this palette color mapping. * * @param statistics * Statistics containing min.max values. * @param data * The data values. * @param normalizedValuesOut * Result of mapping data values to palette normalized * values which range [-1.0, 1.0]. This array MUST contain * the same number of values as 'data'. * @param numberOfData * Number of values in both data and normalizedValuesOut. */ void PaletteColorMapping::mapDataToPaletteNormalizedValues(const FastStatistics* statistics, const float* dataValues, float* normalizedValuesOut, const int64_t numberOfData) const { bool enable_normalization_flipping = ( ! DeveloperFlagsEnum::isFlag(DeveloperFlagsEnum::DEVELOPER_FLAG_FLIP_PALETTE_NOT_DATA)); //temporary debug/developer variable: use this to trigger the flipping code in this function if (numberOfData <= 0) { return; } bool invert_pos_neg = false; bool invert_min_max = false; int inv_min_max_zero_maps_to = 0; if (enable_normalization_flipping) { //convert the inversion settings into the orthogonal inversions that could be applied simultaneously, if desired switch (this->invertedMode) { case PaletteInvertModeEnum::OFF: break; case PaletteInvertModeEnum::POSITIVE_NEGATIVE_SEPARATE: invert_min_max = true; break; case PaletteInvertModeEnum::POSITIVE_WITH_NEGATIVE: invert_pos_neg = true; break; } if (invert_min_max && (inv_min_max_zero_maps_to > 1 || inv_min_max_zero_maps_to < -1)) { CaretLogWarning("invalid 'inv_min_max_zero_maps_to' setting '" + AString::number(inv_min_max_zero_maps_to) + "' for min/max palette inversion, resetting to 0"); inv_min_max_zero_maps_to = 0; } } /* * Minimum and maximum values used when mapping scalar into color palette. */ float mappingMostNegative = 0.0; float mappingLeastNegative = 0.0; float mappingLeastPositive = 0.0; float mappingMostPositive = 0.0; switch (this->getScaleMode()) { case PaletteScaleModeEnum::MODE_AUTO_SCALE: statistics->getNonzeroRanges(mappingMostNegative, mappingLeastNegative, mappingLeastPositive, mappingMostPositive); break; case PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE: { const float mostPercentage = this->getAutoScaleAbsolutePercentageMaximum(); const float leastPercentage = this->getAutoScaleAbsolutePercentageMinimum(); mappingMostNegative = -statistics->getApproxAbsolutePercentile(mostPercentage); mappingLeastNegative = -statistics->getApproxAbsolutePercentile(leastPercentage); mappingLeastPositive = statistics->getApproxAbsolutePercentile(leastPercentage); mappingMostPositive = statistics->getApproxAbsolutePercentile(mostPercentage); } break; case PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE: { const float mostNegativePercentage = this->getAutoScalePercentageNegativeMaximum(); const float leastNegativePercentage = this->getAutoScalePercentageNegativeMinimum(); const float leastPositivePercentage = this->getAutoScalePercentagePositiveMinimum(); const float mostPositivePercentage = this->getAutoScalePercentagePositiveMaximum(); mappingMostNegative = statistics->getApproxNegativePercentile(mostNegativePercentage); mappingLeastNegative = statistics->getApproxNegativePercentile(leastNegativePercentage); mappingLeastPositive = statistics->getApproxPositivePercentile(leastPositivePercentage); mappingMostPositive = statistics->getApproxPositivePercentile(mostPositivePercentage); } break; case PaletteScaleModeEnum::MODE_USER_SCALE: mappingMostNegative = this->getUserScaleNegativeMaximum(); mappingLeastNegative = this->getUserScaleNegativeMinimum(); mappingLeastPositive = this->getUserScalePositiveMinimum(); mappingMostPositive = this->getUserScalePositiveMaximum(); break; } //TSC: hack to do the min/max inversion without extra conditionals: swap most and least if (enable_normalization_flipping && invert_min_max) { float temp = mappingMostPositive; mappingMostPositive = mappingLeastPositive; mappingLeastPositive = temp; temp = mappingMostNegative; mappingMostNegative = mappingLeastNegative; mappingLeastNegative = temp; } bool settingsValidPos = true, settingsValidNeg = true; float mappingPositiveDenominator = (mappingMostPositive - mappingLeastPositive) / (1.0f - PALETTE_ZERO_COLOR_ZONE);//this correction prevents normalization from assigning most positive a normalized value greater than 1 if (mappingPositiveDenominator == 0.0f) {//needs to be "== 0.0f", so that we can swap most/least to do min/max inversion settingsValidPos = false; } float mappingNegativeDenominator = (mappingMostNegative - mappingLeastNegative) / (-1.0f + PALETTE_ZERO_COLOR_ZONE);//ditto, but most negative maps to -1 if (mappingNegativeDenominator == 0.0f) { settingsValidNeg = false; } for (int64_t i = 0; i < numberOfData; i++) { float scalar = dataValues[i]; /* * Color scalar using palette */ float normalized = 0.0f; if (scalar > 0.0f) { if (settingsValidPos) { normalized = (scalar - mappingLeastPositive) / mappingPositiveDenominator + PALETTE_ZERO_COLOR_ZONE; } else { if (scalar >= mappingMostPositive) { normalized = 1.0f; } } if (normalized > 1.0f)//don't allow zero from nonzero, even when coloring range is 0 { normalized = 1.0f; } else if (normalized < PALETTE_ZERO_COLOR_ZONE) { normalized = PALETTE_ZERO_COLOR_ZONE; } } else if (scalar < 0.0f) { if (settingsValidNeg) { normalized = (scalar - mappingLeastNegative) / mappingNegativeDenominator - PALETTE_ZERO_COLOR_ZONE; } else { if (scalar <= mappingMostNegative) { normalized = -1.0f; } } if (normalized < -1.0f) { normalized = -1.0f; } else if (normalized > -PALETTE_ZERO_COLOR_ZONE) { normalized = -PALETTE_ZERO_COLOR_ZONE; } } else if (enable_normalization_flipping && scalar == 0.0f && invert_min_max) {//don't apply the replacement to NaN, only to 0 normalized = inv_min_max_zero_maps_to; } if (enable_normalization_flipping && invert_pos_neg) { normalizedValuesOut[i] = -normalized; } else { normalizedValuesOut[i] = normalized; } } } /** * Setup the numeric text for the annotation colorbar. * * @param statistics * Statistics for the data. * @param colorBar * Colorbar that receives the numeric text. */ void PaletteColorMapping::setupAnnotationColorBarNumericText(const FastStatistics* statistics, AnnotationColorBar* colorBar) { colorBar->clearNumericText(); std::vector colorBarNumericText; getPaletteColorBarScaleText(statistics, colorBarNumericText); for (std::vector::iterator iter = colorBarNumericText.begin(); iter != colorBarNumericText.end(); iter++) { const AnnotationColorBarNumericText* nt = *iter; colorBar->addNumericText(nt->getScalar(), nt->getNumericText(), nt->getHorizontalAlignment(), nt->isDrawTickMarkAtScalar()); delete nt; } colorBar->setShowTickMarksSelected(this->colorBarShowTickMarksSelected); } /** * Get the text characters for drawing the scale above the palette * color bar. * * @param statistics * Statistics for the data. * @param colorBarNumericTextOut, * Contains attributes for numeric text displayed above color bar. */ void PaletteColorMapping::getPaletteColorBarScaleText(const FastStatistics* statistics, std::vector& colorBarNumericTextOut) const { colorBarNumericTextOut.clear(); /* * Processing for Sign Only Mode */ switch (this->colorBarValuesMode) { case PaletteColorBarValuesModeEnum::DATA: break; case PaletteColorBarValuesModeEnum::PERCENTILE: break; case PaletteColorBarValuesModeEnum::SIGN_ONLY: { const int emDash = 0x2014; const AString positive("(+)"); const AString zero("0"); const AString negative("(" + QString(QChar(emDash)) + ")"); if (isDisplayPositiveDataFlag() && isDisplayNegativeDataFlag()) { colorBarNumericTextOut.push_back(new AnnotationColorBarNumericText(0.0, negative, AnnotationTextAlignHorizontalEnum::LEFT, true)); colorBarNumericTextOut.push_back(new AnnotationColorBarNumericText(0.5, zero, AnnotationTextAlignHorizontalEnum::CENTER, true)); colorBarNumericTextOut.push_back(new AnnotationColorBarNumericText(1.0, positive, AnnotationTextAlignHorizontalEnum::RIGHT, true)); } else if (isDisplayPositiveDataFlag()) { colorBarNumericTextOut.push_back(new AnnotationColorBarNumericText(0.0, zero, AnnotationTextAlignHorizontalEnum::LEFT, true)); colorBarNumericTextOut.push_back(new AnnotationColorBarNumericText(1.0, positive, AnnotationTextAlignHorizontalEnum::RIGHT, true)); } else if (isDisplayNegativeDataFlag()) { colorBarNumericTextOut.push_back(new AnnotationColorBarNumericText(0.0, negative, AnnotationTextAlignHorizontalEnum::LEFT, true)); colorBarNumericTextOut.push_back(new AnnotationColorBarNumericText(1.0, zero, AnnotationTextAlignHorizontalEnum::CENTER, true)); } else if (isDisplayZeroDataFlag()) { colorBarNumericTextOut.push_back(new AnnotationColorBarNumericText(0.5, zero, AnnotationTextAlignHorizontalEnum::CENTER, true)); } return; } break; } float negMax = -1.0; float negMin = 0.0; float posMin = 0.0; float posMax = 1.0; switch (getScaleMode()) { case PaletteScaleModeEnum::MODE_AUTO_SCALE: { float dummy; statistics->getNonzeroRanges(negMax, dummy, dummy, posMax); } break; case PaletteScaleModeEnum::MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE: { const float maxPct = getAutoScaleAbsolutePercentageMaximum(); const float minPct = getAutoScaleAbsolutePercentageMinimum(); negMax = -statistics->getApproxAbsolutePercentile(maxPct); negMin = -statistics->getApproxAbsolutePercentile(minPct); posMin = statistics->getApproxAbsolutePercentile(minPct); posMax = statistics->getApproxAbsolutePercentile(maxPct); } break; case PaletteScaleModeEnum::MODE_AUTO_SCALE_PERCENTAGE: { const float negMaxPct = getAutoScalePercentageNegativeMaximum(); const float negMinPct = getAutoScalePercentageNegativeMinimum(); const float posMinPct = getAutoScalePercentagePositiveMinimum(); const float posMaxPct = getAutoScalePercentagePositiveMaximum(); negMax = statistics->getApproxNegativePercentile(negMaxPct); negMin = statistics->getApproxNegativePercentile(negMinPct); posMin = statistics->getApproxPositivePercentile(posMinPct); posMax = statistics->getApproxPositivePercentile(posMaxPct); } break; case PaletteScaleModeEnum::MODE_USER_SCALE: negMax = getUserScaleNegativeMaximum(); negMin = getUserScaleNegativeMinimum(); posMin = getUserScalePositiveMinimum(); posMax = getUserScalePositiveMaximum(); break; } /* * Types of values for display */ const bool positiveDataDisplayedFlag = isDisplayPositiveDataFlag(); const bool negativeDataDisplayedFlag = isDisplayNegativeDataFlag(); /* * numeric values displayed for negative data */ std::vector negativeValues; if (negativeDataDisplayedFlag) { negativeValues.push_back(negMax); if (this->colorBarNumericSubdivisionCount > 0) { const float range = negMin - negMax; const float interval = range / (this->colorBarNumericSubdivisionCount + 1); for (int32_t i = 0; i < this->colorBarNumericSubdivisionCount; i++) { negativeValues.push_back(negMax + (interval * (i + 1))); } } negativeValues.push_back(negMin); } /* * numeric values displayed for positive data */ std::vector positiveValues; if (positiveDataDisplayedFlag) { positiveValues.push_back(posMin); if (this->colorBarNumericSubdivisionCount > 0) { const float range = posMax - posMin; const float interval = range / (this->colorBarNumericSubdivisionCount + 1); for (int32_t i = 0; i < this->colorBarNumericSubdivisionCount; i++) { positiveValues.push_back(posMin + (interval * (i + 1))); } } positiveValues.push_back(posMax); } /* * Will need to override these values when percentile */ NumericFormatModeEnum::Enum numericFormatModeForTextFormatting = this->colorBarNumericFormatMode; int32_t precisionDigitsForTextFormatting = this->colorBarPrecisionDigits; /* * Processing for percentile mode * Convert numeric values to percentiles */ switch (this->colorBarValuesMode) { case PaletteColorBarValuesModeEnum::DATA: break; case PaletteColorBarValuesModeEnum::PERCENTILE: for (std::vector::iterator iter = positiveValues.begin(); iter != positiveValues.end(); iter++) { const float percentile = statistics->getPositiveValuePercentile(*iter); *iter = percentile; } for (std::vector::iterator iter = negativeValues.begin(); iter != negativeValues.end(); iter++) { const float percentile = statistics->getNegativeValuePercentile(*iter); *iter = percentile; } break; case PaletteColorBarValuesModeEnum::SIGN_ONLY: CaretAssertMessage(0, "Should never get here. Sign only handled above"); break; } /* * Create text representations for negative values */ const int32_t numberOfNegValues = static_cast(negativeValues.size()); std::vector negativeValuesText(numberOfNegValues); /* * Create text representations for positive values */ const int32_t numberOfPosValues = static_cast(positiveValues.size()); std::vector positiveValuesText(numberOfPosValues); NumericTextFormatting::formatValueRangeNegPos(numericFormatModeForTextFormatting, precisionDigitsForTextFormatting, &negativeValues[0], &negativeValuesText[0], numberOfNegValues, &positiveValues[0], &positiveValuesText[0], numberOfPosValues); CaretAssert(negativeValues.size() == negativeValuesText.size()); CaretAssert(positiveValues.size() == positiveValuesText.size()); /* * Are both negative and positive values displayed? */ AString zeroValueText; if (negativeDataDisplayedFlag && positiveDataDisplayedFlag) { CaretAssert(negativeValuesText.size() > 0); AString negMinText = negativeValuesText.back(); CaretAssert(positiveValuesText.size() > 0); const AString posMinText = positiveValuesText.front(); if (negMinText == posMinText) { /* * When the negative min and positive min values are the * same, there is no need to display both of them. */ zeroValueText = negMinText; if (isZeroNumericText(zeroValueText)) { zeroValueText = "0"; } } else if (isZeroNumericText(negMinText) && (isZeroNumericText(posMinText))) { zeroValueText = "0"; } else { /* * When the negative min and positive min values are the * different, display both an separate with a slash */ zeroValueText = negMinText + "/" + posMinText; } /* * Since the negative min and positive min text values * are dislayed together by above code, remove these * values from their respective text values. */ negativeValuesText.resize(negativeValuesText.size() - 1); negativeValues.resize(negativeValues.size() - 1); CaretAssert(negativeValues.size() == negativeValuesText.size()); positiveValuesText.erase(positiveValuesText.begin()); positiveValues.erase(positiveValues.begin()); CaretAssert(positiveValues.size() == positiveValuesText.size()); } /* * The positions of the text are normalized in the range zero * to one where zero is at the left side of the color bar * and one is at the right side of the color bar. */ float negPositionStart = 0.0; float negPositionInterval = 0.0; float posPositionStart = 0.0; float posPositionInterval = 0.0; if (negativeDataDisplayedFlag && positiveDataDisplayedFlag) { negPositionStart = 0.0; CaretAssert(negativeValuesText.size() > 0); negPositionInterval = (0.5 / negativeValuesText.size()); CaretAssert(positiveValuesText.size() > 0); posPositionInterval = (0.5 / positiveValuesText.size()); posPositionStart = 0.5 + posPositionInterval; } else if (negativeDataDisplayedFlag) { negPositionStart = 0.0; negPositionInterval = 1.0; if (negativeValuesText.size() > 1) { CaretAssert(negativeValuesText.size() > 0); negPositionInterval = (1.0 / (negativeValuesText.size() - 1)); } } else if (positiveDataDisplayedFlag) { posPositionStart = 0.0; posPositionInterval = 1.0; if (positiveValuesText.size() > 1) { CaretAssert(positiveValuesText.size() > 0); posPositionInterval = (1.0 / (positiveValuesText.size() - 1)); } } /* * Output the negative values text */ if (negativeDataDisplayedFlag) { const int32_t numValues = static_cast(negativeValuesText.size()); for (int32_t i = 0; i < numValues; i++) { CaretAssertVectorIndex(negativeValuesText, i); const float value = (negPositionStart + (i * negPositionInterval)); AnnotationTextAlignHorizontalEnum::Enum alignment = AnnotationTextAlignHorizontalEnum::CENTER; if (i == 0) { alignment = AnnotationTextAlignHorizontalEnum::LEFT; } else if (i == (numValues - 1)) { if ( ! positiveDataDisplayedFlag) { alignment = AnnotationTextAlignHorizontalEnum::RIGHT; } } colorBarNumericTextOut.push_back(new AnnotationColorBarNumericText(value, negativeValuesText[i], alignment, true)); } } /* * Add the zero value text */ if (negativeDataDisplayedFlag && positiveDataDisplayedFlag) { colorBarNumericTextOut.push_back(new AnnotationColorBarNumericText(0.5, zeroValueText, AnnotationTextAlignHorizontalEnum::CENTER, true)); } /* * When zero only */ if (isDisplayZeroDataFlag()) { if (( ! negativeDataDisplayedFlag) && ( ! positiveDataDisplayedFlag)) { colorBarNumericTextOut.push_back(new AnnotationColorBarNumericText(0.0, "", AnnotationTextAlignHorizontalEnum::CENTER, true)); colorBarNumericTextOut.push_back(new AnnotationColorBarNumericText(0.5, "0.0", AnnotationTextAlignHorizontalEnum::CENTER, true)); colorBarNumericTextOut.push_back(new AnnotationColorBarNumericText(1.0, "", AnnotationTextAlignHorizontalEnum::CENTER, true)); } } /* * Add the positive values text */ if (positiveDataDisplayedFlag) { const int32_t numValues = static_cast(positiveValuesText.size()); for (int32_t i = 0; i < numValues; i++) { CaretAssertVectorIndex(positiveValuesText, i); const float value = (posPositionStart + (i * posPositionInterval)); AnnotationTextAlignHorizontalEnum::Enum alignment = AnnotationTextAlignHorizontalEnum::CENTER; if (i == (numValues - 1)) { alignment = AnnotationTextAlignHorizontalEnum::RIGHT; } else if (i == 0) { if ( ! negativeDataDisplayedFlag) { alignment = AnnotationTextAlignHorizontalEnum::LEFT; } } colorBarNumericTextOut.push_back(new AnnotationColorBarNumericText(value, positiveValuesText[i], alignment, true)); } } /* * Add percentage signs when percentile is selected */ switch (this->colorBarValuesMode) { case PaletteColorBarValuesModeEnum::DATA: break; case PaletteColorBarValuesModeEnum::PERCENTILE: for (std::vector::iterator iter = colorBarNumericTextOut.begin(); iter != colorBarNumericTextOut.end(); iter++) { AnnotationColorBarNumericText* nt = *iter; nt->setNumericText(nt->getNumericText() + "%"); } break; case PaletteColorBarValuesModeEnum::SIGN_ONLY: break; } const bool debugFlag = false; if (debugFlag) { const int numItems = static_cast(colorBarNumericTextOut.size()); std::cout << "Colorbar: " << std::endl; for (int32_t i = 0; i < numItems; i++) { const AnnotationColorBarNumericText* nt = colorBarNumericTextOut[i]; std::cout << " " << qPrintable(QString::number(nt->getScalar()) + ": " + nt->getNumericText() + " " + AnnotationTextAlignHorizontalEnum::toGuiName(nt->getHorizontalAlignment()) + " show-tick=" + AString::fromBool(nt->isDrawTickMarkAtScalar())) << std::endl; // std::cout << " " << qPrintable(QString::number(normalizedPositionAndTextOut[i].first) // + ": " // + normalizedPositionAndTextOut[i].second) << std::endl; } std::cout << std::endl; } } /** * Is the numeric value of the text zero? * * Examples: 0, -0.0, 0.00, etc * * @param numericText * The text with a numeric value * @return * True if the text represents zero, else false */ bool PaletteColorMapping::isZeroNumericText(const AString& numericText) const { /* * While a regular expression could be used, it may * be faster just to test for valid characters */ const int32_t numChars = numericText.length(); for (int32_t i = 0; i < numChars; i++) { QChar c = numericText[i]; if ((c == '+') || (c == '-') || (c == '0') || (c == '.')) { /* ok */ } else { return false; } } return true; } /** * @return True if thresholding is linked meaning * that the high threshold is restricted to a positive value * the low threshold = -high. * * This is just a status and it is up to the user of this class * to properly set the threshold values. */ bool PaletteColorMapping::isThresholdNegMinPosMaxLinked() const { return this->thresholdNegMinPosMaxLinked; } /** * Set thresholding is linked meaning * that the high threshold is restricted to a positive value * the low threshold = -high. * * This is just a status and it is up to the user of this class * to properly set the threshold values. * * @param linked * New status of low/high linked thresholding. */ void PaletteColorMapping::setThresholdNegMinPosMaxLinked(const bool linked) { if (this->thresholdNegMinPosMaxLinked != linked) { this->thresholdNegMinPosMaxLinked = linked; setModified(); } } /** * @return The histogram range mode. */ PaletteHistogramRangeModeEnum::Enum PaletteColorMapping::getHistogramRangeMode() const { return this->histogramRangeMode; } /** * Set the histogram range mode. * * @param histogramRangeMode * New value for histogram range mode. */ void PaletteColorMapping::setHistogramRangeMode(const PaletteHistogramRangeModeEnum::Enum histogramRangeMode) { if (histogramRangeMode != this->histogramRangeMode) { this->histogramRangeMode = histogramRangeMode; setModified(); } } /** * @return show histogram bars */ bool PaletteColorMapping::isHistogramBarsVisible() const { return this->histogramBarsVisible; } /** * Set show histogram bars * * @param histogramBarsVisible * New value for show histogram bars */ void PaletteColorMapping::setHistogramBarsVisible(const bool histogramBarsVisible) { if (histogramBarsVisible != this->histogramBarsVisible) { this->histogramBarsVisible = histogramBarsVisible; setModified(); } } /** * @return show histogram envelope */ bool PaletteColorMapping::isHistogramEnvelopeVisible() const { return this->histogramEnvelopeVisible; } /** * Set show histogram envelope * * @param histogramEnvelopeVisible * New value for show histogram envelope */ void PaletteColorMapping::setHistogramEnvelopeVisible(const bool histogramEnvelopeVisible) { if (histogramEnvelopeVisible != this->histogramEnvelopeVisible) { this->histogramEnvelopeVisible = histogramEnvelopeVisible; setModified(); } } /** * @return Color for drawing histogram bars */ CaretColorEnum::Enum PaletteColorMapping::getHistogramBarsColor() const { return histogramBarsColor; } /** * Set the color for drawing the histogram bars * * @param histogramBarsColor * New color for the histogram bars */ void PaletteColorMapping::setHistogramBarsColor(const CaretColorEnum::Enum histogramBarsColor) { if (histogramBarsColor != this->histogramBarsColor) { this->histogramBarsColor = histogramBarsColor; setModified(); } } /** * @return Color for drawing histogram envelope */ CaretColorEnum::Enum PaletteColorMapping::getHistogramEnvelopeColor() const { return histogramEnvelopeColor; } /** * Set the color for drawing the histogram envelope * * @param histogramEnvelopeColor * New color for the histogram envelope. */ void PaletteColorMapping::setHistogramEnvelopeColor(const CaretColorEnum::Enum histogramEnvelopeColor) { if (histogramEnvelopeColor != this->histogramEnvelopeColor) { this->histogramEnvelopeColor = histogramEnvelopeColor; setModified(); } } /** * @return The line width percentage for drawing histogram as envelope. */ float PaletteColorMapping::getHistogramEnvelopeLineWidthPercentage() const { return histogramEnvelopeLineWidthPercentage; } /** * Set line width percentage for drawing histogram as envelope. * * @param lineWidthPercentage * New value for line width percentage. */ void PaletteColorMapping::setHistogramEnvelopeLineWidthPercentage(const float lineWidthPercentage) { if (lineWidthPercentage != this->histogramEnvelopeLineWidthPercentage) { this->histogramEnvelopeLineWidthPercentage = lineWidthPercentage; setModified(); } } /** * @return Histogram number of buckets. */ int32_t PaletteColorMapping::getHistogramNumberOfBuckets() const { return this->histogramNumberOfBuckets; } /** * Set the histogram number of buckets. * * @param histogramNumberOfBuckets * Number of buckets for the histogram. */ void PaletteColorMapping::setHistogramNumberOfBuckets(const int32_t histogramNumberOfBuckets) { if (histogramNumberOfBuckets != this->histogramNumberOfBuckets) { this->histogramNumberOfBuckets = histogramNumberOfBuckets; setModified(); } } /** * @return The color bar numeric format mode. */ NumericFormatModeEnum::Enum PaletteColorMapping::getColorBarNumericFormatMode() const { return this->colorBarNumericFormatMode; } /** * Set the color bar numeric format mode. * * @param colorBarNumericFormatMode * New value for color bar numberic format mode */ void PaletteColorMapping::setColorBarNumericFormatMode(const NumericFormatModeEnum::Enum colorBarNumericFormatMode) { if (colorBarNumericFormatMode != this->colorBarNumericFormatMode) { this->colorBarNumericFormatMode = colorBarNumericFormatMode; setModified(); } } /** * @return The color bar precision digits (right of decimal). */ int32_t PaletteColorMapping::getColorBarPrecisionDigits() const { return this->colorBarPrecisionDigits; } /** * Set the color bar precision digits (right of decimal) * * @param colorBarPrecisionDigits * New value for number of digits right of decimal. */ void PaletteColorMapping::setColorBarPrecisionDigits(const int32_t colorBarPrecisionDigits) { if (colorBarPrecisionDigits != this->colorBarPrecisionDigits) { this->colorBarPrecisionDigits = colorBarPrecisionDigits; setModified(); } } /** * @return The color bar numeric subdivision count which is the number of * numeric values uniformly spaced between zero and the maximum * value. */ int32_t PaletteColorMapping::getColorBarNumericSubdivisionCount() const { return this->colorBarNumericSubdivisionCount; } /** * Set the color bar numeric subdivision count which is the number of * numeric values uniformly spaced between zero and the maximum * value. * * @param colorBarNumericSubdivisionCount * New value for subdivision count. */ void PaletteColorMapping::setColorBarNumericSubdivisionCount(const int32_t colorBarNumericSubdivisionCount) { if (colorBarNumericSubdivisionCount != this->colorBarNumericSubdivisionCount) { this->colorBarNumericSubdivisionCount = colorBarNumericSubdivisionCount; setModified(); } } /** * @return The color bar values mode. */ PaletteColorBarValuesModeEnum::Enum PaletteColorMapping::getColorBarValuesMode() const { return this->colorBarValuesMode; } /** * Set the color bar values mode. * * @param colorBarValuesMode * New value for color bar values mode. */ void PaletteColorMapping::setColorBarValuesMode(const PaletteColorBarValuesModeEnum::Enum colorBarValuesMode) { if (colorBarValuesMode != this->colorBarValuesMode) { this->colorBarValuesMode = colorBarValuesMode; setModified(); } } /** * @param Is show tick marks selected? */ bool PaletteColorMapping::isColorBarShowTickMarksSelected() const { return this->colorBarShowTickMarksSelected; } /** * Set show tick marks selected. * * @param selected * New selection status. */ void PaletteColorMapping::setColorBarShowTickMarksSelected(const bool selected) { if (selected != this->colorBarShowTickMarksSelected) { this->colorBarShowTickMarksSelected = selected; setModified(); } } /** * @return The threshold outline drawing mode. */ PaletteThresholdOutlineDrawingModeEnum::Enum PaletteColorMapping::getThresholdOutlineDrawingMode() const { return this->thresholdOutlineDrawingMode; } /** * Set the threshold outline drawing mode. * * @param drawingMode * New drawing mode for threshold outline. */ void PaletteColorMapping::setThresholdOutlineDrawingMode(const PaletteThresholdOutlineDrawingModeEnum::Enum drawingMode) { if (this->thresholdOutlineDrawingMode != drawingMode) { this->thresholdOutlineDrawingMode = drawingMode; setModified(); } } /** * @return The threshold outline drawing color. */ CaretColorEnum::Enum PaletteColorMapping::getThresholdOutlineDrawingColor() const { return this->thresholdOutlineDrawingColor; } /** * Set the threshold outline drawing color. * * @param color * New color for threshold outline. */ void PaletteColorMapping::setThresholdOutlineDrawingColor(const CaretColorEnum::Enum color) { if (this->thresholdOutlineDrawingColor != color) { this->thresholdOutlineDrawingColor = color; setModified(); } } connectome-workbench-1.4.2/src/Palette/PaletteColorMapping.h000066400000000000000000000352051360521144700241070ustar00rootroot00000000000000#ifndef __PALETTECOLORMAPPING_H__ #define __PALETTECOLORMAPPING_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "CaretObject.h" #include "AnnotationColorBarNumericText.h" #include "CaretColorEnum.h" #include "NumericFormatModeEnum.h" #include "PaletteColorBarValuesModeEnum.h" #include "PaletteEnums.h" #include "PaletteHistogramRangeModeEnum.h" #include "PaletteInvertModeEnum.h" #include "PaletteModifiedStatusEnum.h" #include "PaletteThresholdOutlineDrawingModeEnum.h" #include "PaletteThresholdRangeModeEnum.h" #include "XmlException.h" namespace caret { class AnnotationColorBar; class FastStatistics; class Palette; class XmlWriter; /** * Controls color mapping using a palette. */ class PaletteColorMapping : public CaretObject { public: PaletteColorMapping(); PaletteColorMapping(const PaletteColorMapping& o); PaletteColorMapping& operator=(const PaletteColorMapping& o); bool operator==(const PaletteColorMapping& pcm) const; bool operator!=(const PaletteColorMapping& pcm) const { return !((*this) == pcm); } virtual ~PaletteColorMapping(); void copy(const PaletteColorMapping& pcm, const bool copyHistogramAttributesFlag); private: void copyHelper(const PaletteColorMapping& o, const bool copyHistogramAttributesFlag); void initializeMembersPaletteColorMapping(); public: void setupAnnotationColorBar(const FastStatistics* statistics, AnnotationColorBar* colorBar); void setupAnnotationColorBarNumericText(const FastStatistics* statistics, AnnotationColorBar* colorBar); void writeAsXML(XmlWriter& xmlWriter); AString encodeInXML(); void decodeFromStringXML(const AString& xml); float getAutoScalePercentageNegativeMaximum() const; void setAutoScalePercentageNegativeMaximum(const float autoScalePercentageNegativeMaximum); float getAutoScalePercentageNegativeMinimum() const; void setAutoScalePercentageNegativeMinimum(const float autoScalePercentageNegativeMinimum); float getAutoScalePercentagePositiveMaximum() const; void setAutoScalePercentagePositiveMaximum(const float autoScalePercentagePositiveMaximum); float getAutoScalePercentagePositiveMinimum() const; void setAutoScalePercentagePositiveMinimum(const float autoScalePercentagePositiveMinimum); float getAutoScaleAbsolutePercentageMinimum() const; void setAutoScaleAbsolutePercentageMinimum(const float autoScaleAbsolutePercentageMinimum); float getAutoScaleAbsolutePercentageMaximum() const; void setAutoScaleAbsolutePercentageMaximum(const float autoScaleAbsolutePercentageMaximum); bool isDisplayNegativeDataFlag() const; void setDisplayNegativeDataFlag(const bool displayNegativeDataFlag); bool isDisplayPositiveDataFlag() const; void setDisplayPositiveDataFlag(const bool displayPositiveDataFlag); bool isDisplayZeroDataFlag() const; void setDisplayZeroDataFlag(const bool displayZeroDataFlag); bool isInterpolatePaletteFlag() const; void setInterpolatePaletteFlag(const bool interpolatePaletteFlag); PaletteInvertModeEnum::Enum getInvertedMode() const; void setInvertedMode(const PaletteInvertModeEnum::Enum invertedMode); PaletteScaleModeEnum::Enum getScaleMode() const; void setScaleMode(const PaletteScaleModeEnum::Enum scaleMode); AString getSelectedPaletteName() const; void setSelectedPaletteName(const AString& selectedPaletteName); const Palette* getPalette() const; void setSelectedPaletteToPsych(); void setSelectedPaletteToPsychNoNone(); void setSelectedPaletteToOrangeYellow(); void setSelectedPaletteToGrayInterpolated(); float getUserScaleNegativeMaximum() const; void setUserScaleNegativeMaximum(const float userScaleNegativeMaximum); float getUserScaleNegativeMinimum() const; void setUserScaleNegativeMinimum(const float userScaleNegativeMinimum); float getUserScalePositiveMaximum() const; void setUserScalePositiveMaximum(const float userScalePositiveMaximum); float getUserScalePositiveMinimum() const; void setUserScalePositiveMinimum(const float userScalePositiveMinimum); float getThresholdMappedAverageAreaMinimum() const; void setThresholdMappedAverageAreaMinimum(const float thresholdMappedAverageAreaMinimum); float getThresholdMappedAverageAreaMaximum() const; void setThresholdMappedAverageAreaMaximum(const float thresholdMappedAverageAreaPositive); float getThresholdMappedMinimum() const; void setThresholdMappedMinimum(const float thresholdMappedMinimum); float getThresholdMappedMaximum() const; void setThresholdMappedMaximum(const float thresholdMappedPositive); float getThresholdNormalMinimum() const; void setThresholdNormalMinimum(const float thresholdNormalMinimum); float getThresholdNormalMaximum() const; void setThresholdNormalMaximum(const float thresholdNormalPositive); float getThresholdMinimum(const PaletteThresholdTypeEnum::Enum thresholdType) const; float getThresholdMaximum(const PaletteThresholdTypeEnum::Enum thresholdType) const; void setThresholdMinimum(const PaletteThresholdTypeEnum::Enum thresholdType, const float thresholdMinimum); void setThresholdMaximum(const PaletteThresholdTypeEnum::Enum thresholdType, const float thresholdMaximum); PaletteThresholdTestEnum::Enum getThresholdTest() const; void setThresholdTest(const PaletteThresholdTestEnum::Enum thresholdTest); PaletteThresholdTypeEnum::Enum getThresholdType() const; void setThresholdType(const PaletteThresholdTypeEnum::Enum thresholdType); PaletteThresholdRangeModeEnum::Enum getThresholdRangeMode() const; void setThresholdRangeMode(const PaletteThresholdRangeModeEnum::Enum rangeMode); AString getThresholdDataName() const; void setThresholdDataName(const AString& thresholdDataName); bool isShowThresholdFailureInGreen() const; void setShowThresholdFailureInGreen(const bool showInGreenFlag); bool isThresholdNegMinPosMaxLinked() const; void setThresholdNegMinPosMaxLinked(const bool linked); PaletteHistogramRangeModeEnum::Enum getHistogramRangeMode() const; void setHistogramRangeMode(const PaletteHistogramRangeModeEnum::Enum histogramRangeMode); bool isHistogramBarsVisible() const; void setHistogramBarsVisible(const bool histogramBarsVisible); bool isHistogramEnvelopeVisible() const; void setHistogramEnvelopeVisible(const bool histogramEnvelopeVisible); CaretColorEnum::Enum getHistogramBarsColor() const; void setHistogramBarsColor(const CaretColorEnum::Enum histogramBarsColor); CaretColorEnum::Enum getHistogramEnvelopeColor() const; void setHistogramEnvelopeColor(const CaretColorEnum::Enum histogramEnvelopeColor); float getHistogramEnvelopeLineWidthPercentage() const; void setHistogramEnvelopeLineWidthPercentage(const float lineWidthPercentage); int32_t getHistogramNumberOfBuckets() const; void setHistogramNumberOfBuckets(const int32_t histogramNumberOfBuckets); NumericFormatModeEnum::Enum getColorBarNumericFormatMode() const; int32_t getColorBarPrecisionDigits() const; int32_t getColorBarNumericSubdivisionCount() const; void setColorBarNumericFormatMode(const NumericFormatModeEnum::Enum colorBarNumericFormatMode); void setColorBarPrecisionDigits(const int32_t colorBarPrecisionDigits); void setColorBarNumericSubdivisionCount(const int32_t colroBarNumericSubdivisionCount); PaletteColorBarValuesModeEnum::Enum getColorBarValuesMode() const; void setColorBarValuesMode(const PaletteColorBarValuesModeEnum::Enum colorBarValuesMode); bool isColorBarShowTickMarksSelected() const; void setColorBarShowTickMarksSelected(const bool selected); PaletteThresholdOutlineDrawingModeEnum::Enum getThresholdOutlineDrawingMode() const; void setThresholdOutlineDrawingMode(const PaletteThresholdOutlineDrawingModeEnum::Enum drawingMode); CaretColorEnum::Enum getThresholdOutlineDrawingColor() const; void setThresholdOutlineDrawingColor(const CaretColorEnum::Enum color); void setModified(); void clearModified(); bool isModified() const; void setSceneModified(); PaletteModifiedStatusEnum::Enum getModifiedStatus() const; void mapDataToPaletteNormalizedValues(const FastStatistics* statistics, const float* dataValues, float* normalizedValuesOut, const int64_t numberOfData) const; void getPaletteColorBarScaleText(const FastStatistics* statistics, std::vector& colorBarNumericTextOut) const; /** A positive value near zero - may be zero! */ static const float SMALL_POSITIVE; /** A negative value near zero - may be zero! */ static const float SMALL_NEGATIVE; /** TSC: the excluded zone of normalization is a separate issue to zero detection in the data * specifically, it is a HACK, in order for palettes to be able to specify a special color for data that is 0, which is not involved in color interpolation */ static const float PALETTE_ZERO_COLOR_ZONE; private: bool isZeroNumericText(const AString& numericText) const; PaletteScaleModeEnum::Enum scaleMode; float autoScalePercentageNegativeMaximum; float autoScalePercentageNegativeMinimum; float autoScalePercentagePositiveMinimum; float autoScalePercentagePositiveMaximum; float autoScaleAbsolutePercentageMinimum; float autoScaleAbsolutePercentageMaximum; float userScaleNegativeMaximum; float userScaleNegativeMinimum; float userScalePositiveMinimum; float userScalePositiveMaximum; AString selectedPaletteName; bool interpolatePaletteFlag; PaletteInvertModeEnum::Enum invertedMode = PaletteInvertModeEnum::OFF; bool displayPositiveDataFlag; bool displayZeroDataFlag; bool displayNegativeDataFlag; PaletteThresholdTypeEnum::Enum thresholdType; PaletteThresholdTestEnum::Enum thresholdTest; PaletteThresholdRangeModeEnum::Enum thresholdRangeMode; float thresholdNormalMinimum; float thresholdNormalMaximum; float thresholdMappedMinimum; float thresholdMappedMaximum; float thresholdMappedAverageAreaMinimum; float thresholdMappedAverageAreaMaximum; AString thresholdDataName; bool thresholdShowFailureInGreen; bool thresholdNegMinPosMaxLinked; PaletteHistogramRangeModeEnum::Enum histogramRangeMode; bool histogramBarsVisible; bool histogramEnvelopeVisible; CaretColorEnum::Enum histogramBarsColor; CaretColorEnum::Enum histogramEnvelopeColor; float histogramEnvelopeLineWidthPercentage; int32_t histogramNumberOfBuckets; NumericFormatModeEnum::Enum colorBarNumericFormatMode; int32_t colorBarPrecisionDigits; int32_t colorBarNumericSubdivisionCount; PaletteColorBarValuesModeEnum::Enum colorBarValuesMode; bool colorBarShowTickMarksSelected; PaletteThresholdOutlineDrawingModeEnum::Enum thresholdOutlineDrawingMode; CaretColorEnum::Enum thresholdOutlineDrawingColor; /**Tracks modification, DO NOT copy */ PaletteModifiedStatusEnum::Enum modifiedStatus; /** keeps missing palettes from being logged more than once */ static std::set s_missingPaletteNames; }; #ifdef __PALETTE_COLOR_MAPPING_DECLARE__ const float PaletteColorMapping::SMALL_POSITIVE = 0.0; const float PaletteColorMapping::SMALL_NEGATIVE = 0.0; const float PaletteColorMapping::PALETTE_ZERO_COLOR_ZONE = 0.00001f; std::set PaletteColorMapping::s_missingPaletteNames; #endif // __PALETTE_COLOR_MAPPING_DECLARE__ } // namespace #endif // __PALETTECOLORMAPPING_H__ connectome-workbench-1.4.2/src/Palette/PaletteColorMappingSaxReader.cxx000066400000000000000000000536131360521144700262640ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include "CaretAssert.h" #include "CaretLogger.h" #include "PaletteColorMapping.h" #include "PaletteColorMappingSaxReader.h" #include "PaletteColorMappingXmlElements.h" #include "XmlAttributes.h" #include "XmlException.h" using namespace caret; /** * constructor. */ PaletteColorMappingSaxReader::PaletteColorMappingSaxReader(PaletteColorMapping* paletteColorMapping) { CaretAssert(paletteColorMapping); this->state = STATE_NONE; this->stateStack.push(state); this->elementText = ""; this->paletteColorMapping = paletteColorMapping; this->paletteColorMapping->setInvertedMode(PaletteInvertModeEnum::OFF); } /** * destructor. */ PaletteColorMappingSaxReader::~PaletteColorMappingSaxReader() { } /** * start an element. */ void PaletteColorMappingSaxReader::startElement(const AString& /* namespaceURI */, const AString& /* localName */, const AString& qName, const XmlAttributes& attributes) { const STATE previousState = this->state; switch (this->state) { case STATE_NONE: if (qName == PaletteColorMappingXmlElements::XML_TAG_PALETTE_COLOR_MAPPING) { this->state = STATE_READING_ELEMENTS; int32_t version = attributes.getValueAsInt(PaletteColorMappingXmlElements::XML_ATTRIBUTE_VERSION_NUMBER); if (version > PaletteColorMappingXmlElements::XML_VERSION_NUMBER) { std::ostringstream str; str << "Version of PaletteColorMapping (" << version << ") is greater than version(s) supported (" << PaletteColorMappingXmlElements::XML_VERSION_NUMBER << ")."; throw XmlSaxParserException(AString::fromStdString(str.str())); } } else { std::ostringstream str; str << "Root element is \"" << qName.toStdString() << "\" but should be " << PaletteColorMappingXmlElements::XML_TAG_PALETTE_COLOR_MAPPING.toStdString(); throw XmlSaxParserException(AString::fromStdString(str.str())); } break; case STATE_READING_ELEMENTS: break; } // // Save previous state // this->stateStack.push(previousState); this->elementText = ""; } /** * Convert the string representation of a bool to a bool. * @param s * String containing boolean value. * @return * The bool value. */ bool toBool(const AString& s) { if ((s == "true") || (s == "TRUE") || (s == "True") || (s == "T") || (s == "t") || (s == "1")) { return true; } return false; } /** * Split up a string containing float values. * * @param s * String containing float values. * @return * float vector containing values extracted from string. */ std::vector toFloatVector(const AString& s) { std::vector fv; std::istringstream str(s.toStdString()); while ((str.eof() == false) && (str.fail() == false)) { float value; str >> value; fv.push_back(value); } return fv; } /** * end an element. */ void PaletteColorMappingSaxReader::endElement(const AString& /* namspaceURI */, const AString& /* localName */, const AString& qName) { switch (state) { case STATE_NONE: break; case STATE_READING_ELEMENTS: if (qName == PaletteColorMappingXmlElements::XML_TAG_AUTO_SCALE_PERCENTAGE_VALUES) { std::vector values = toFloatVector(this->elementText); if (values.size() >= 4) { this->paletteColorMapping->setAutoScalePercentageNegativeMaximum(values[0]); this->paletteColorMapping->setAutoScalePercentageNegativeMinimum(values[1]); this->paletteColorMapping->setAutoScalePercentagePositiveMinimum(values[2]); this->paletteColorMapping->setAutoScalePercentagePositiveMaximum(values[3]); } else { throw XmlSaxParserException("PaletteColorMappingXmlElements::auto scale percenter does not contain four values."); } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_AUTO_SCALE_ABSOLUTE_PERCENTAGE_VALUES) { std::vector values = toFloatVector(this->elementText); if (values.size() >= 2) { this->paletteColorMapping->setAutoScaleAbsolutePercentageMinimum(values[0]); this->paletteColorMapping->setAutoScaleAbsolutePercentageMaximum(values[1]); } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_DISPLAY_NEGATIVE) { this->paletteColorMapping->setDisplayNegativeDataFlag(toBool(this->elementText)); } else if (qName == PaletteColorMappingXmlElements::XML_TAG_DISPLAY_POSITIVE) { this->paletteColorMapping->setDisplayPositiveDataFlag(toBool(this->elementText)); } else if (qName == PaletteColorMappingXmlElements::XML_TAG_DISPLAY_ZERO) { this->paletteColorMapping->setDisplayZeroDataFlag(toBool(this->elementText)); } else if (qName == PaletteColorMappingXmlElements::XML_TAG_INTERPOLATE) { this->paletteColorMapping->setInterpolatePaletteFlag(toBool(this->elementText)); } else if (qName == PaletteColorMappingXmlElements::XML_TAG_INVERT) { bool isValid = false; PaletteInvertModeEnum::Enum invertMode = PaletteInvertModeEnum::fromName(this->elementText, &isValid); if (isValid) { this->paletteColorMapping->setInvertedMode(invertMode); } else { if (this->elementText == "true") { this->paletteColorMapping->setInvertedMode(PaletteInvertModeEnum::POSITIVE_WITH_NEGATIVE); } else if (this->elementText == "false") { this->paletteColorMapping->setInvertedMode(PaletteInvertModeEnum::OFF); } else { this->paletteColorMapping->setInvertedMode(PaletteInvertModeEnum::OFF); CaretLogWarning("Invalid PaletteInvertModeEnum::Enum value \"" + this->elementText + "\""); } } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_PALETTE_NAME) { this->paletteColorMapping->setSelectedPaletteName(this->elementText); } else if (qName == PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_DATA_NAME) { this->paletteColorMapping->setThresholdDataName(this->elementText); } else if (qName == PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_FAILURE_IN_GREEN) { /* ??? */ } else if (qName == PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_MAPPED_AVG_AREA_VALUES) { std::vector values = toFloatVector(this->elementText); if (values.size() >= 2) { this->paletteColorMapping->setThresholdMappedAverageAreaMinimum(values[0]); this->paletteColorMapping->setThresholdMappedAverageAreaMaximum(values[1]); } else { throw XmlSaxParserException("PaletteColorMappingXmlElements::threshild mapped average area does not contain two values."); } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_MAPPED_VALUES) { std::vector values = toFloatVector(this->elementText); if (values.size() >= 2) { this->paletteColorMapping->setThresholdMappedMinimum(values[0]); this->paletteColorMapping->setThresholdMappedMaximum(values[1]); } else { throw XmlSaxParserException("PaletteColorMappingXmlElements::threshild mapped does not contain two values."); } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_NORMAL_VALUES) { std::vector values = toFloatVector(this->elementText); if (values.size() >= 2) { this->paletteColorMapping->setThresholdNormalMinimum(values[0]); this->paletteColorMapping->setThresholdNormalMaximum(values[1]); } else { throw XmlSaxParserException("PaletteColorMappingXmlElements::threshild mapped normal does not contain two values."); } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_TEST) { bool isValid = false; PaletteThresholdTestEnum::Enum thresoldTest = PaletteThresholdTestEnum::fromName(this->elementText, &isValid); if (isValid) { this->paletteColorMapping->setThresholdTest(thresoldTest); } else { throw XmlSaxParserException("Invalid PaletteColorMapping::thresoldTest " + this->elementText); } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_TYPE) { bool isValid = false; PaletteThresholdTypeEnum::Enum thresholdType = PaletteThresholdTypeEnum::fromName(this->elementText, &isValid); if (isValid) { this->paletteColorMapping->setThresholdType(thresholdType); } else { throw XmlSaxParserException("Invalid PaletteColorMapping::thresholdType: " + this->elementText); } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_SCALE_MODE) { bool isValid = false; PaletteScaleModeEnum::Enum scaleMode = PaletteScaleModeEnum::fromName(this->elementText, &isValid); if (isValid) { this->paletteColorMapping->setScaleMode(scaleMode); } else { throw XmlSaxParserException("Invalid PaletteColorMapping::scaleMode: " + this->elementText); } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_USER_SCALE_VALUES) { std::vector values = toFloatVector(this->elementText); if (values.size() >= 4) { this->paletteColorMapping->setUserScaleNegativeMaximum(values[0]); this->paletteColorMapping->setUserScaleNegativeMinimum(values[1]); this->paletteColorMapping->setUserScalePositiveMinimum(values[2]); this->paletteColorMapping->setUserScalePositiveMaximum(values[3]); } else { throw XmlSaxParserException("PaletteColorMappingXmlElements::auto scale percenter does not contain four values."); } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_RANGE_MODE) { bool isValid = false; PaletteThresholdRangeModeEnum::Enum rangeMode = PaletteThresholdRangeModeEnum::fromName(this->elementText, &isValid); if (isValid) { this->paletteColorMapping->setThresholdRangeMode(rangeMode); } else { throw XmlSaxParserException("Invalid PaletteThresholdRangeModeEnum::Enum: " + this->elementText); } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_NEG_MIN_POS_MAX_LINKED) { this->paletteColorMapping->setThresholdNegMinPosMaxLinked(toBool(this->elementText)); } else if (qName == PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_OUTLINE_DRAWING_MODE) { bool valid = false; PaletteThresholdOutlineDrawingModeEnum::Enum drawMode = PaletteThresholdOutlineDrawingModeEnum::fromName(this->elementText, &valid); if (valid) { this->paletteColorMapping->setThresholdOutlineDrawingMode(drawMode); } else { warning(XmlSaxParserException("Invalid PaletteThresholdOutlineDrawingModeEnum::Enum " + this->elementText)); } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_THRESHOLD_OUTLINE_DRAWING_COLOR) { bool valid = false; CaretColorEnum::Enum color = CaretColorEnum::fromName(this->elementText, &valid); if (valid) { this->paletteColorMapping->setThresholdOutlineDrawingColor(color); } else { warning(XmlSaxParserException("Invalid CaretColorEnum::Enum for palette outline color " + this->elementText)); } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_PALETTE_COLOR_MAPPING) { /* WB- * We want to default the range mode to 'FILE'. While we do that in the constructor * for PaletteColorMapping, most files contain PaletteColorMapping in the XML for * each map and when the file is read, the default values are replaced. So, * to avoid breaking older scenes, only change the range mode from 'MAP' to 'FILE' * if thresholding is off when reading palette color mapping from XML. */ if (this->paletteColorMapping->getThresholdType() == PaletteThresholdTypeEnum::THRESHOLD_TYPE_OFF) { this->paletteColorMapping->setThresholdRangeMode(PaletteThresholdRangeModeEnum::PALETTE_THRESHOLD_RANGE_MODE_FILE); } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_RANGE_MODE) { bool isValid = false; PaletteHistogramRangeModeEnum::Enum histogramRangeMode = PaletteHistogramRangeModeEnum::fromName(this->elementText, &isValid); if (isValid) { this->paletteColorMapping->setHistogramRangeMode(histogramRangeMode); } else { throw XmlSaxParserException("Invalid PaletteHistogramRangeModeEnum::Enum: " + this->elementText); } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_BARS_VISIBLE) { this->paletteColorMapping->setHistogramBarsVisible(toBool(this->elementText)); } else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_ENVELOPE_VISIBLE) { this->paletteColorMapping->setHistogramEnvelopeVisible(toBool(this->elementText)); } else if ((qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_BARS_COLOR) || (qName == "HistogramColor")) { bool isValid = false; CaretColorEnum::Enum histogramBarsColor = CaretColorEnum::fromName(this->elementText, &isValid); if (isValid) { this->paletteColorMapping->setHistogramBarsColor(histogramBarsColor); } else { throw XmlSaxParserException("Invalid CaretColorEnum::Enum: " + this->elementText); } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_ENVELOPE_COLOR) { bool isValid = false; CaretColorEnum::Enum histogramEnvelopeColor = CaretColorEnum::fromName(this->elementText, &isValid); if (isValid) { this->paletteColorMapping->setHistogramEnvelopeColor(histogramEnvelopeColor); } else { throw XmlSaxParserException("Invalid CaretColorEnum::Enum: " + this->elementText); } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_ENVELOPE_LINE_WIDTH_PERCENTAGE) { this->paletteColorMapping->setHistogramEnvelopeLineWidthPercentage(this->elementText.toFloat()); } else if (qName == PaletteColorMappingXmlElements::XML_TAG_HISTOGRAM_NUMBER_OF_BUCKETS) { this->paletteColorMapping->setHistogramNumberOfBuckets(this->elementText.toInt()); } else if (qName == PaletteColorMappingXmlElements::XML_TAG_NUMERIC_FORMAT_MODE) { bool isValid = false; NumericFormatModeEnum::Enum numericFormatMode = NumericFormatModeEnum::fromName(this->elementText, &isValid); if (isValid) { this->paletteColorMapping->setColorBarNumericFormatMode(numericFormatMode); } else { throw XmlSaxParserException("Invalid NumericFormatModeEnum::Enum: " + this->elementText); } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_PRECISION_DIGITS) { this->paletteColorMapping->setColorBarPrecisionDigits(this->elementText.toInt()); } else if (qName == PaletteColorMappingXmlElements::XML_TAG_NUMERIC_SUBDIVISIONS) { this->paletteColorMapping->setColorBarNumericSubdivisionCount(this->elementText.toInt()); } else if (qName == PaletteColorMappingXmlElements::XML_TAG_COLOR_BAR_VALUES_MODE) { bool isValid = false; PaletteColorBarValuesModeEnum::Enum colorBarMode = PaletteColorBarValuesModeEnum::fromName(this->elementText, &isValid); if (isValid) { this->paletteColorMapping->setColorBarValuesMode(colorBarMode); } else { throw XmlSaxParserException("Invalid PaletteColorBarValuesModeEnum::Enum: " + this->elementText); } } else if (qName == PaletteColorMappingXmlElements::XML_TAG_SHOW_TICK_MARKS) { this->paletteColorMapping->setColorBarShowTickMarksSelected(toBool(this->elementText)); } else { std::ostringstream str; str << "Unrecognized (perhaps new) palette color mapping element ignored \"" << qName.toStdString() << "\" with content: " << this->elementText.toStdString(); CaretLogFine(AString::fromStdString(str.str())); } break; } // // Clear out for new elements // this->elementText = ""; // // Go to previous state // if (this->stateStack.empty()) { throw XmlSaxParserException("State stack is empty while reading PaletteColorMapping."); } this->state = stateStack.top(); this->stateStack.pop(); } /** * get characters in an element. */ void PaletteColorMappingSaxReader::characters(const char* ch) { this->elementText += ch; } /** * a fatal error occurs. */ void PaletteColorMappingSaxReader::fatalError(const XmlSaxParserException& e) { throw e; } /** * A warning occurs */ void PaletteColorMappingSaxReader::warning(const XmlSaxParserException& e) { CaretLogWarning("XML Parser Warning: " + e.whatString()); } // an error occurs void PaletteColorMappingSaxReader::error(const XmlSaxParserException& e) { CaretLogSevere("XML Parser Error: " + e.whatString()); throw e; } void PaletteColorMappingSaxReader::startDocument() { } void PaletteColorMappingSaxReader::endDocument() { } connectome-workbench-1.4.2/src/Palette/PaletteColorMappingSaxReader.h000066400000000000000000000067701360521144700257130ustar00rootroot00000000000000 #ifndef __PALETTE_COLOR_MAPPING_SAX_READER_H__ #define __PALETTE_COLOR_MAPPING_SAX_READER_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "XmlSaxParserException.h" #include "XmlSaxParserHandlerInterface.h" namespace caret { class PaletteColorMapping; class XmlAttributes; /** * Class for reading a PaletteColorMapping object with a SAX Parser */ class PaletteColorMappingSaxReader : public CaretObject, public XmlSaxParserHandlerInterface { public: PaletteColorMappingSaxReader(PaletteColorMapping* paletteColorMapping); virtual ~PaletteColorMappingSaxReader(); private: PaletteColorMappingSaxReader(const PaletteColorMappingSaxReader&); PaletteColorMappingSaxReader& operator=(const PaletteColorMappingSaxReader&); public: void startElement(const AString& namespaceURI, const AString& localName, const AString& qName, const XmlAttributes& attributes); void endElement(const AString& namspaceURI, const AString& localName, const AString& qName); void characters(const char* ch); void fatalError(const XmlSaxParserException& e); void warning(const XmlSaxParserException& e); void error(const XmlSaxParserException& e); void startDocument(); void endDocument(); protected: /// file reading states enum STATE { /// no state STATE_NONE, /// reading elements STATE_READING_ELEMENTS }; /// file reading state STATE state; /// the state stack used when reading a file std::stack stateStack; /// the error message AString errorMessage; /// element text AString elementText; /// GIFTI label table being read PaletteColorMapping* paletteColorMapping; /// label index int labelIndex; /// label color component float labelRed; /// label color component float labelGreen; /// label color component float labelBlue; /// label color component float labelAlpha; /// label's X-coordinate float labelX; /// label's Y-coordinate float labelY; /// label's Z-coordinate float labelZ; }; } // namespace #endif // __PALETTE_COLOR_MAPPING_SAX_READER_H__ connectome-workbench-1.4.2/src/Palette/PaletteColorMappingXmlElements.h000066400000000000000000000075741360521144700262750ustar00rootroot00000000000000#ifndef __PALETTE_COLOR_MAPPING_XML_ELEMENTS_H__ #define __PALETTE_COLOR_MAPPING_XML_ELEMENTS_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include using namespace caret; namespace PaletteColorMappingXmlElements { static const AString XML_TAG_PALETTE_COLOR_MAPPING = "PaletteColorMapping"; static const AString XML_TAG_SCALE_MODE = "ScaleMode"; static const AString XML_TAG_AUTO_SCALE_PERCENTAGE_VALUES = "AutoScalePercentageValues"; static const AString XML_TAG_AUTO_SCALE_ABSOLUTE_PERCENTAGE_VALUES = "AutoScaleAbsolutePercentageValues"; static const AString XML_TAG_USER_SCALE_VALUES = "UserScaleValues"; static const AString XML_TAG_PALETTE_NAME = "PaletteName"; static const AString XML_TAG_INTERPOLATE = "InterpolatePalette"; static const AString XML_TAG_INVERT = "InvertPalette"; static const AString XML_TAG_DISPLAY_POSITIVE = "DisplayPositiveData"; static const AString XML_TAG_DISPLAY_NEGATIVE = "DisplayNegativeData"; static const AString XML_TAG_DISPLAY_ZERO = "DisplayZeroData"; static const AString XML_TAG_THRESHOLD_TEST = "ThresholdTest"; static const AString XML_TAG_THRESHOLD_TYPE = "ThresholdType"; static const AString XML_TAG_THRESHOLD_NORMAL_VALUES = "ThresholdNormalValues"; static const AString XML_TAG_THRESHOLD_MAPPED_VALUES = "ThresholdMappedValues"; static const AString XML_TAG_THRESHOLD_MAPPED_AVG_AREA_VALUES = "ThresholdMappedAvgAreaValues"; static const AString XML_TAG_THRESHOLD_DATA_NAME = "ThresholdDataName"; static const AString XML_TAG_THRESHOLD_FAILURE_IN_GREEN = "ThresholdFailureInGreen"; static const AString XML_TAG_THRESHOLD_RANGE_MODE = "ThresholdRangeMode"; static const AString XML_TAG_THRESHOLD_NEG_MIN_POS_MAX_LINKED = "ThresholdLowHighLinked"; static const AString XML_TAG_THRESHOLD_OUTLINE_DRAWING_MODE = "ThresholdOutlineDrawingMode"; static const AString XML_TAG_THRESHOLD_OUTLINE_DRAWING_COLOR = "ThresholdOutlineDrawingColor"; static const AString XML_TAG_HISTOGRAM_RANGE_MODE = "HistogramRangeMode"; static const AString XML_TAG_HISTOGRAM_BARS_VISIBLE = "HistogramBarsVisible"; static const AString XML_TAG_HISTOGRAM_ENVELOPE_VISIBLE = "HistogramEnvelopeVisible"; static const AString XML_TAG_HISTOGRAM_BARS_COLOR = "HistogramBarsColor"; static const AString XML_TAG_HISTOGRAM_ENVELOPE_COLOR = "HistogramEnvelopeColor"; static const AString XML_TAG_HISTOGRAM_ENVELOPE_LINE_WIDTH_PERCENTAGE = "HistogramEnvelopeLineWidthPercentage"; static const AString XML_TAG_HISTOGRAM_NUMBER_OF_BUCKETS = "HistogramNumberOfBuckets"; static const AString XML_TAG_NUMERIC_FORMAT_MODE = "NumericFormatMode"; static const AString XML_TAG_PRECISION_DIGITS = "PrecisionDigits"; static const AString XML_TAG_NUMERIC_SUBDIVISIONS = "NumericSubivisions"; static const AString XML_TAG_COLOR_BAR_VALUES_MODE = "ColorBarValuesMode"; static const AString XML_TAG_SHOW_TICK_MARKS = "ShowTickMarksSelected"; static const AString XML_ATTRIBUTE_VERSION_NUMBER = "Version"; static const int XML_VERSION_NUMBER = 1; } // namespace #endif // __PALETTE_COLOR_MAPPING_XML_ELEMENTS_H__ connectome-workbench-1.4.2/src/Palette/PaletteEnums.cxx000066400000000000000000000471601360521144700231620ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #define __PALETTE_ENUMS_DECLARE__ #include "PaletteEnums.h" #undef __PALETTE_ENUMS_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * Constructor. * * @param e * An enumerated value. * @param name * Name of enumberated value. */ PaletteScaleModeEnum::PaletteScaleModeEnum( const Enum e, const int32_t integerCode, const AString& name, const AString& guiName) { this->e = e; this->integerCode = integerCode; this->name = name; this->guiName = guiName; } /** * Destructor. */ PaletteScaleModeEnum::~PaletteScaleModeEnum() { } void PaletteScaleModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(PaletteScaleModeEnum(MODE_AUTO_SCALE, 0, "MODE_AUTO_SCALE", "Auto Scale")); enumData.push_back(PaletteScaleModeEnum(MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE, 1, "MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE", "Auto Scale - Absolute Percentage")); enumData.push_back(PaletteScaleModeEnum(MODE_AUTO_SCALE_PERCENTAGE, 2, "MODE_AUTO_SCALE_PERCENTAGE", "Auto Scale - Percentage")); enumData.push_back(PaletteScaleModeEnum(MODE_USER_SCALE, 3, "MODE_USER_SCALE", "User Scale")); } /** * Find the data for and enumerated value. * @param e * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const PaletteScaleModeEnum* PaletteScaleModeEnum::findData(const Enum e) { initialize(); int64_t num = enumData.size(); for (int64_t i = 0; i < num; i++) { const PaletteScaleModeEnum* d = &enumData[i]; if (d->e == e) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString PaletteScaleModeEnum::toName(Enum e) { initialize(); const PaletteScaleModeEnum* psm = findData(e); return psm->name; } /** * Get an enumerated value corresponding to its name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ PaletteScaleModeEnum::Enum PaletteScaleModeEnum::fromName(const AString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = MODE_AUTO_SCALE; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteScaleModeEnum& d = *iter; if (d.name == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("name \"" + s + " \"failed to match enumerated value for type PaletteScaleModeEnum")); } return e; } /** * Get a gui name representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString PaletteScaleModeEnum::toGuiName(Enum e) { initialize(); const PaletteScaleModeEnum* psm = findData(e); return psm->guiName; } /** * Get an enumerated value corresponding to its gui name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ PaletteScaleModeEnum::Enum PaletteScaleModeEnum::fromGuiName(const AString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = MODE_AUTO_SCALE; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteScaleModeEnum& d = *iter; if (d.guiName == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName \"" + s + " \"failed to match enumerated value for type PaletteScaleModeEnum")); } return e; } /** * Get the integer code associated with a scale mode. * @param e * The enum. * @return * Integer code associated with a scale mode. */ int32_t PaletteScaleModeEnum::toIntegerCode(Enum e) { initialize(); const PaletteScaleModeEnum* nsu = findData(e); return nsu->integerCode; } /** * Find enum corresponding to integer code. * @param integerCode * The integer code. * @param isValidOut * If not NULL, on exit it indicates valid integer code. * @return * Enum corresponding to integer code. */ PaletteScaleModeEnum::Enum PaletteScaleModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = MODE_AUTO_SCALE; for (std::vector::const_iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteScaleModeEnum& nsu = *iter; if (nsu.integerCode == integerCode) { e = nsu.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("integerCode \"" + AString::number(integerCode) + " \"failed to match enumerated value for type PaletteScaleModeEnum")); } return e; } /** * Get all enums for the data type. * @param enumsOut * Loaded with all enums for this data type. */ void PaletteScaleModeEnum::getAllEnums(std::vector< PaletteScaleModeEnum::Enum >& enumsOut) { initialize(); enumsOut.resize(enumData.size()); for (int i = 0; i < (int)enumData.size(); ++i) { enumsOut[i] = enumData[i].e; } } /** * Constructor. * * @param e * An enumerated value. * @param name * Name of enumberated value. */ PaletteThresholdTestEnum::PaletteThresholdTestEnum( const Enum e, const int32_t integerCode, const AString& name, const AString& guiName) { this->e = e; this->integerCode = integerCode; this->name = name; this->guiName = guiName; } /** * Destructor. */ PaletteThresholdTestEnum::~PaletteThresholdTestEnum() { } void PaletteThresholdTestEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(PaletteThresholdTestEnum(THRESHOLD_TEST_SHOW_OUTSIDE, 0, "THRESHOLD_TEST_SHOW_OUTSIDE", "Show Data Outside Thresholds")); enumData.push_back(PaletteThresholdTestEnum(THRESHOLD_TEST_SHOW_INSIDE, 1, "THRESHOLD_TEST_SHOW_INSIDE", "Show Data Below Threshold")); } /** * Find the data for and enumerated value. * @param e * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const PaletteThresholdTestEnum* PaletteThresholdTestEnum::findData(const Enum e) { initialize(); int64_t num = enumData.size(); for (int64_t i = 0; i < num; i++) { const PaletteThresholdTestEnum* d = &enumData[i]; if (d->e == e) { return d; } } CaretAssertMessage(0, "Threshold Test enum failed to match."); return NULL; } /** * Get a string representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString PaletteThresholdTestEnum::toName(Enum e) { initialize(); const PaletteThresholdTestEnum* ptt = findData(e); return ptt->name; } /** * Get an enumerated value corresponding to its name. * @param sin * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ PaletteThresholdTestEnum::Enum PaletteThresholdTestEnum::fromName(const AString& sin, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = THRESHOLD_TEST_SHOW_OUTSIDE; AString s = sin; if (s == "THRESHOLD_TEST_SHOW_ABOVE") { s = "THRESHOLD_TEST_SHOW_OUTSIDE"; } else if (s == "THRESHOLD_TEST_SHOW_BELOW") { s = "THRESHOLD_TEST_SHOW_INSIDE"; } for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteThresholdTestEnum& d = *iter; if (d.name == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("name \"" + s + " \"failed to match enumerated value for type PaletteThresholdTestEnum")); } return e; } /** * Get a gui name representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString PaletteThresholdTestEnum::toGuiName(Enum e) { initialize(); const PaletteThresholdTestEnum* psm = findData(e); return psm->guiName; } /** * Get an enumerated value corresponding to its gui name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ PaletteThresholdTestEnum::Enum PaletteThresholdTestEnum::fromGuiName(const AString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = THRESHOLD_TEST_SHOW_OUTSIDE; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteThresholdTestEnum& d = *iter; if (d.guiName == s) { e = d.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName \"" + s + " \"failed to match enumerated value for type PaletteThresholdTestEnum")); } return e; } /** * Get the integer code associated with a scale mode. * @param e * The enum. * @return * Integer code associated with a scale mode. */ int32_t PaletteThresholdTestEnum::toIntegerCode(Enum e) { initialize(); const PaletteThresholdTestEnum* nsu = findData(e); return nsu->integerCode; } /** * Find enum corresponding to integer code. * @param integerCode * The integer code. * @param isValidOut * If not NULL, on exit it indicates valid integer code. * @return * Enum corresponding to integer code. */ PaletteThresholdTestEnum::Enum PaletteThresholdTestEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = THRESHOLD_TEST_SHOW_OUTSIDE; for (std::vector::const_iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteThresholdTestEnum& nsu = *iter; if (nsu.integerCode == integerCode) { e = nsu.e; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("integerCode \"" + AString::number(integerCode) + " \"failed to match enumerated value for type PaletteThresholdTestEnum")); } return e; } /** * Constructor. * * @param e * An enumerated value. * @param name * Name of enumberated value. */ PaletteThresholdTypeEnum::PaletteThresholdTypeEnum( const Enum e, const int32_t integerCode, const AString& name, const AString& guiName) { this->e = e; this->integerCode = integerCode; this->name = name; this->guiName = guiName; } /** * Destructor. */ PaletteThresholdTypeEnum::~PaletteThresholdTypeEnum() { } void PaletteThresholdTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(PaletteThresholdTypeEnum(THRESHOLD_TYPE_OFF, 0, "THRESHOLD_TYPE_OFF", "Off")); if (PaletteThresholdTypeEnum::mappedThresholdsEnabled) { enumData.push_back(PaletteThresholdTypeEnum(THRESHOLD_TYPE_NORMAL, 1, "THRESHOLD_TYPE_NORMAL", "Normal")); enumData.push_back(PaletteThresholdTypeEnum(THRESHOLD_TYPE_MAPPED, 2, "THRESHOLD_TYPE_MAPPED", "Mapped")); enumData.push_back(PaletteThresholdTypeEnum(THRESHOLD_TYPE_MAPPED_AVERAGE_AREA, 3, "THRESHOLD_TYPE_MAPPED_AVERAGE_AREA", "Mapped Average Area")); } else { enumData.push_back(PaletteThresholdTypeEnum(THRESHOLD_TYPE_NORMAL, 1, "THRESHOLD_TYPE_NORMAL", "Self")); enumData.push_back(PaletteThresholdTypeEnum(THRESHOLD_TYPE_FILE, 2, "THRESHOLD_TYPE_FILE", "File")); } } /** * Find the data for and enumerated value. * @param e * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const PaletteThresholdTypeEnum* PaletteThresholdTypeEnum::findData(const Enum e) { initialize(); int64_t num = enumData.size(); for (int64_t i = 0; i < num; i++) { const PaletteThresholdTypeEnum* d = &enumData[i]; if (d->e == e) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString PaletteThresholdTypeEnum::toName(Enum e) { initialize(); const PaletteThresholdTypeEnum* ptt = findData(e); return ptt->name; } /** * Get an enumerated value corresponding to its name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ PaletteThresholdTypeEnum::Enum PaletteThresholdTypeEnum::fromName(const AString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = THRESHOLD_TYPE_OFF; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteThresholdTypeEnum& d = *iter; if (d.name == s) { e = d.e; validFlag = true; break; } } PaletteThresholdTypeEnum::handleDisabledThresholdTypes(e); if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("name \"" + s + " \"failed to match enumerated value for type PaletteThresholdTypeEnum")); } return e; } /** * If the mapped threshold types are disabled, convert * them to normal thresholding. * @param e * Thresholding type that may be changed. */ void PaletteThresholdTypeEnum::handleDisabledThresholdTypes(Enum& e) { if (PaletteThresholdTypeEnum::mappedThresholdsEnabled == false) { if ((e == THRESHOLD_TYPE_MAPPED) || (e == THRESHOLD_TYPE_MAPPED_AVERAGE_AREA)) { e = THRESHOLD_TYPE_NORMAL; } } } /** * Get a gui name representation of the enumerated type. * @param e * Enumerated value. * @return * String representing enumerated value. */ AString PaletteThresholdTypeEnum::toGuiName(Enum e) { initialize(); const PaletteThresholdTypeEnum* psm = findData(e); return psm->guiName; } /** * Get an enumerated value corresponding to its gui name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ PaletteThresholdTypeEnum::Enum PaletteThresholdTypeEnum::fromGuiName(const AString& s, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = THRESHOLD_TYPE_OFF; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteThresholdTypeEnum& d = *iter; if (d.guiName == s) { e = d.e; validFlag = true; break; } } PaletteThresholdTypeEnum::handleDisabledThresholdTypes(e); if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName \"" + s + " \"failed to match enumerated value for type PaletteThresholdTypeEnum")); } return e; } /** * Get the integer code associated with a threshold type. * @param e * The enum. * @return * Integer code associated with a threshold type. */ int32_t PaletteThresholdTypeEnum::toIntegerCode(Enum e) { initialize(); const PaletteThresholdTypeEnum* nsu = findData(e); return nsu->integerCode; } /** * Find enum corresponding to integer code. * @param integerCode * The integer code. * @param isValidOut * If not NULL, on exit it indicates valid integer code. * @return * Enum corresponding to integer code. */ PaletteThresholdTypeEnum::Enum PaletteThresholdTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { initialize(); bool validFlag = false; Enum e = THRESHOLD_TYPE_OFF; for (std::vector::const_iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteThresholdTypeEnum& nsu = *iter; if (nsu.integerCode == integerCode) { e = nsu.e; validFlag = true; break; } } PaletteThresholdTypeEnum::handleDisabledThresholdTypes(e); if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("integerCode \"" + AString::number(integerCode) + " \"failed to match enumerated value for type PaletteThresholdTypeEnum")); } return e; } /** * Get all enums for the data type. * @param enumsOut * Loaded with all enums for this data type. */ void PaletteThresholdTestEnum::getAllEnums(std::vector& enumsOut) { initialize(); enumsOut.resize(enumData.size()); for (int i = 0; i < (int)enumData.size(); ++i) { enumsOut[i] = enumData[i].e; } } /** * Get all enums for the data type. * @param enumsOut * Loaded with all enums for this data type. */ void PaletteThresholdTypeEnum::getAllEnums(std::vector& enumsOut) { initialize(); enumsOut.resize(enumData.size()); for (int i = 0; i < (int)enumData.size(); ++i) { enumsOut[i] = enumData[i].e; } } connectome-workbench-1.4.2/src/Palette/PaletteEnums.h000066400000000000000000000126001360521144700225760ustar00rootroot00000000000000#ifndef __PALETTE_ENUMS_H #define __PALETTE_ENUMS_H /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include #include "CaretAssert.h" namespace caret { /** * Palette Scale Mode. */ class PaletteScaleModeEnum { public: /** Palette Scale Mode. */ enum Enum { /** Auto Scale */ MODE_AUTO_SCALE, /** Auto Scale Absolute Percentage */ MODE_AUTO_SCALE_ABSOLUTE_PERCENTAGE, /** Auto Scale Percentage */ MODE_AUTO_SCALE_PERCENTAGE, /** User Scale */ MODE_USER_SCALE }; ~PaletteScaleModeEnum(); static AString toName(Enum e); static Enum fromName(const AString& s, bool* isValidOut); static AString toGuiName(Enum e); static Enum fromGuiName(const AString& s, bool* isValidOut); static int32_t toIntegerCode(Enum e); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& enumsOut); private: PaletteScaleModeEnum(const Enum e, const int32_t integerCode, const AString& name, const AString& guiName); static const PaletteScaleModeEnum* findData(const Enum e); static std::vector enumData; static void initialize(); static bool initializedFlag; Enum e; int32_t integerCode; AString name; AString guiName; }; /** * Palette Threshold Test. */ class PaletteThresholdTestEnum { public: /** Palette Threshold Test. */ enum Enum { /** show data when value is outside the threshold values */ THRESHOLD_TEST_SHOW_OUTSIDE, /** show data when value is inside the threshold values */ THRESHOLD_TEST_SHOW_INSIDE }; ~PaletteThresholdTestEnum(); static AString toName(Enum e); static Enum fromName(const AString& s, bool* isValidOut); static AString toGuiName(Enum e); static Enum fromGuiName(const AString& s, bool* isValidOut); static int32_t toIntegerCode(Enum e); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& enumsOut); private: PaletteThresholdTestEnum(const Enum e, const int32_t integerCode, const AString& name, const AString& guiName); static const PaletteThresholdTestEnum* findData(const Enum e); static std::vector enumData; static void initialize(); static bool initializedFlag; Enum e; int32_t integerCode; AString name; AString guiName; }; /** * Palette Threshold Type. */ class PaletteThresholdTypeEnum { public: /** Palette Threshold Type. */ enum Enum { /** thresholding is off */ THRESHOLD_TYPE_OFF, /** normal thresholding */ THRESHOLD_TYPE_NORMAL, /** threshold with another file */ THRESHOLD_TYPE_FILE, /** threshold from mapping of volume */ THRESHOLD_TYPE_MAPPED, /** threshold from mapping to PALS average area */ THRESHOLD_TYPE_MAPPED_AVERAGE_AREA }; ~PaletteThresholdTypeEnum(); static AString toName(Enum e); static Enum fromName(const AString& s, bool* isValidOut); static AString toGuiName(Enum e); static Enum fromGuiName(const AString& s, bool* isValidOut); static int32_t toIntegerCode(Enum e); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& enumsOut); private: PaletteThresholdTypeEnum(const Enum e, const int32_t integerCode, const AString& name, const AString& guiName); static const PaletteThresholdTypeEnum* findData(const Enum e); static std::vector enumData; static void initialize(); static bool initializedFlag; static void handleDisabledThresholdTypes(Enum& e); Enum e; int32_t integerCode; AString name; AString guiName; static const bool mappedThresholdsEnabled; }; #ifdef __PALETTE_ENUMS_DECLARE__ std::vector PaletteScaleModeEnum::enumData; bool PaletteScaleModeEnum::initializedFlag = false; std::vector PaletteThresholdTestEnum::enumData; bool PaletteThresholdTestEnum::initializedFlag = false; std::vector PaletteThresholdTypeEnum::enumData; bool PaletteThresholdTypeEnum::initializedFlag = false; const bool PaletteThresholdTypeEnum::mappedThresholdsEnabled = false; #endif // __PALETTE_ENUMS_DECLARE__ } // namespace #endif // __PALETTE_ENUMS_H connectome-workbench-1.4.2/src/Palette/PaletteHistogramRangeModeEnum.cxx000066400000000000000000000260561360521144700264400ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __PALETTE_HISTOGRAM_RANGE_MODE_ENUM_DECLARE__ #include "PaletteHistogramRangeModeEnum.h" #undef __PALETTE_HISTOGRAM_RANGE_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::PaletteHistogramRangeModeEnum * \brief Controls whether histogram shows all data or data using map statistics * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_paletteHistogramRangeModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void paletteHistogramRangeModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "PaletteHistogramRangeModeEnum.h" * * Instatiate: * m_paletteHistogramRangeModeEnumComboBox = new EnumComboBoxTemplate(this); * m_paletteHistogramRangeModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_paletteHistogramRangeModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(paletteHistogramRangeModeEnumComboBoxItemActivated())); * * Update the selection: * m_paletteHistogramRangeModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const PaletteHistogramRangeModeEnum::Enum VARIABLE = m_paletteHistogramRangeModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ PaletteHistogramRangeModeEnum::PaletteHistogramRangeModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ PaletteHistogramRangeModeEnum::~PaletteHistogramRangeModeEnum() { } /** * Initialize the enumerated metadata. */ void PaletteHistogramRangeModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(PaletteHistogramRangeModeEnum(PALETTE_HISTOGRAM_RANGE_ALL, "PALETTE_HISTOGRAM_RANGE_ALL", "All")); enumData.push_back(PaletteHistogramRangeModeEnum(PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE, "PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE", "Palette")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const PaletteHistogramRangeModeEnum* PaletteHistogramRangeModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const PaletteHistogramRangeModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString PaletteHistogramRangeModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteHistogramRangeModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ PaletteHistogramRangeModeEnum::Enum PaletteHistogramRangeModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PaletteHistogramRangeModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteHistogramRangeModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type PaletteHistogramRangeModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString PaletteHistogramRangeModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteHistogramRangeModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ PaletteHistogramRangeModeEnum::Enum PaletteHistogramRangeModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PaletteHistogramRangeModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteHistogramRangeModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type PaletteHistogramRangeModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t PaletteHistogramRangeModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteHistogramRangeModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ PaletteHistogramRangeModeEnum::Enum PaletteHistogramRangeModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PaletteHistogramRangeModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteHistogramRangeModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type PaletteHistogramRangeModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void PaletteHistogramRangeModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void PaletteHistogramRangeModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(PaletteHistogramRangeModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void PaletteHistogramRangeModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(PaletteHistogramRangeModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Palette/PaletteHistogramRangeModeEnum.h000066400000000000000000000064421360521144700260620ustar00rootroot00000000000000#ifndef __PALETTE_HISTOGRAM_RANGE_MODE_ENUM_H__ #define __PALETTE_HISTOGRAM_RANGE_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2017 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class PaletteHistogramRangeModeEnum { public: /** * Enumerated values. */ enum Enum { /** Use all data for histogram plot */ PALETTE_HISTOGRAM_RANGE_ALL, /** Use data matching palette selections */ PALETTE_HISTOGRAM_RANGE_MATCH_PALETTE }; ~PaletteHistogramRangeModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: PaletteHistogramRangeModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const PaletteHistogramRangeModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __PALETTE_HISTOGRAM_RANGE_MODE_ENUM_DECLARE__ std::vector PaletteHistogramRangeModeEnum::enumData; bool PaletteHistogramRangeModeEnum::initializedFlag = false; int32_t PaletteHistogramRangeModeEnum::integerCodeCounter = 0; #endif // __PALETTE_HISTOGRAM_RANGE_MODE_ENUM_DECLARE__ } // namespace #endif //__PALETTE_HISTOGRAM_RANGE_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Palette/PaletteInvertModeEnum.cxx000066400000000000000000000257721360521144700250010ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __PALETTE_INVERT_MODE_ENUM_DECLARE__ #include "PaletteInvertModeEnum.h" #undef __PALETTE_INVERT_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::PaletteInvertModeEnum * \brief Inversion mode for palettes. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_paletteInvertModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void paletteInvertModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "PaletteInvertModeEnum.h" * * Instatiate: * m_paletteInvertModeEnumComboBox = new EnumComboBoxTemplate(this); * m_paletteInvertModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_paletteInvertModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(paletteInvertModeEnumComboBoxItemActivated())); * * Update the selection: * m_paletteInvertModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const PaletteInvertModeEnum::Enum VARIABLE = m_paletteInvertModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ PaletteInvertModeEnum::PaletteInvertModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ PaletteInvertModeEnum::~PaletteInvertModeEnum() { } /** * Initialize the enumerated metadata. */ void PaletteInvertModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(PaletteInvertModeEnum(OFF, "OFF", "Off")); enumData.push_back(PaletteInvertModeEnum(POSITIVE_WITH_NEGATIVE, "POSITIVE_WITH_NEGATIVE", "Swap Pos with Neg")); enumData.push_back(PaletteInvertModeEnum(POSITIVE_NEGATIVE_SEPARATE, "POSITIVE_NEGATIVE_SEPARATE", "Swap Pos/Neg Separate")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const PaletteInvertModeEnum* PaletteInvertModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const PaletteInvertModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString PaletteInvertModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteInvertModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ PaletteInvertModeEnum::Enum PaletteInvertModeEnum::fromName(const AString& nameIn, bool* isValidOut) { if (initializedFlag == false) initialize(); /* * Fix misspelled name that may be in some files * and test for obsolete "NONE separate" */ AString name = nameIn; if (name == "POSITIVE_NEGATIVE_SEPARATE NONE") { name = "POSITIVE_NEGATIVE_SEPARATE_NONE"; } if (name == "POSITIVE_NEGATIVE_SEPARATE_NONE") { name = "POSITIVE_NEGATIVE_SEPARATE"; } bool validFlag = false; Enum enumValue = PaletteInvertModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteInvertModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type PaletteInvertModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString PaletteInvertModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteInvertModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ PaletteInvertModeEnum::Enum PaletteInvertModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PaletteInvertModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteInvertModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type PaletteInvertModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t PaletteInvertModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteInvertModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ PaletteInvertModeEnum::Enum PaletteInvertModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PaletteInvertModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteInvertModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type PaletteInvertModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void PaletteInvertModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void PaletteInvertModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(PaletteInvertModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void PaletteInvertModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(PaletteInvertModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Palette/PaletteInvertModeEnum.h000066400000000000000000000063441360521144700244200ustar00rootroot00000000000000#ifndef __PALETTE_INVERT_MODE_ENUM_H__ #define __PALETTE_INVERT_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class PaletteInvertModeEnum { public: /** * Enumerated values. */ enum Enum { /** Off */ OFF, /** Invert entire palette flipping colors and sign of scalars */ POSITIVE_WITH_NEGATIVE, /** Invert within negative separately within positive */ POSITIVE_NEGATIVE_SEPARATE }; ~PaletteInvertModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: PaletteInvertModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const PaletteInvertModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __PALETTE_INVERT_MODE_ENUM_DECLARE__ std::vector PaletteInvertModeEnum::enumData; bool PaletteInvertModeEnum::initializedFlag = false; int32_t PaletteInvertModeEnum::integerCodeCounter = 0; #endif // __PALETTE_INVERT_MODE_ENUM_DECLARE__ } // namespace #endif //__PALETTE_INVERT_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Palette/PaletteModifiedStatusEnum.cxx000066400000000000000000000256211360521144700256420ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __PALETTE_MODIFIED_STATUS_ENUM_DECLARE__ #include "PaletteModifiedStatusEnum.h" #undef __PALETTE_MODIFIED_STATUS_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::PaletteModifiedStatusEnum * \brief Enumerated type for palette modified status * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_paletteModifiedStatusEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void paletteModifiedStatusEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "PaletteModifiedStatusEnum.h" * * Instatiate: * m_paletteModifiedStatusEnumComboBox = new EnumComboBoxTemplate(this); * m_paletteModifiedStatusEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_paletteModifiedStatusEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(paletteModifiedStatusEnumComboBoxItemActivated())); * * Update the selection: * m_paletteModifiedStatusEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const PaletteModifiedStatusEnum::Enum VARIABLE = m_paletteModifiedStatusEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ PaletteModifiedStatusEnum::PaletteModifiedStatusEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ PaletteModifiedStatusEnum::~PaletteModifiedStatusEnum() { } /** * Initialize the enumerated metadata. */ void PaletteModifiedStatusEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(PaletteModifiedStatusEnum(MODIFIED, "MODIFIED", "Modified")); enumData.push_back(PaletteModifiedStatusEnum(MODIFIED_BY_SHOW_SCENE, "MODIFIED_BY_SHOW_SCENE", "Modified By Show Scene")); enumData.push_back(PaletteModifiedStatusEnum(UNMODIFIED, "UNMODIFIED", "Unmodified")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const PaletteModifiedStatusEnum* PaletteModifiedStatusEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const PaletteModifiedStatusEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString PaletteModifiedStatusEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteModifiedStatusEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ PaletteModifiedStatusEnum::Enum PaletteModifiedStatusEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PaletteModifiedStatusEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteModifiedStatusEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type PaletteModifiedStatusEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString PaletteModifiedStatusEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteModifiedStatusEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ PaletteModifiedStatusEnum::Enum PaletteModifiedStatusEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PaletteModifiedStatusEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteModifiedStatusEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type PaletteModifiedStatusEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t PaletteModifiedStatusEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteModifiedStatusEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ PaletteModifiedStatusEnum::Enum PaletteModifiedStatusEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PaletteModifiedStatusEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteModifiedStatusEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type PaletteModifiedStatusEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void PaletteModifiedStatusEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void PaletteModifiedStatusEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(PaletteModifiedStatusEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void PaletteModifiedStatusEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(PaletteModifiedStatusEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Palette/PaletteModifiedStatusEnum.h000066400000000000000000000063211360521144700252630ustar00rootroot00000000000000#ifndef __PALETTE_MODIFIED_STATUS_ENUM_H__ #define __PALETTE_MODIFIED_STATUS_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class PaletteModifiedStatusEnum { public: /** * Enumerated values. */ enum Enum { /** Modified */ MODIFIED, /** Modified by showing a scene */ MODIFIED_BY_SHOW_SCENE, /** Unmodified */ UNMODIFIED }; ~PaletteModifiedStatusEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: PaletteModifiedStatusEnum(const Enum enumValue, const AString& name, const AString& guiName); static const PaletteModifiedStatusEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __PALETTE_MODIFIED_STATUS_ENUM_DECLARE__ std::vector PaletteModifiedStatusEnum::enumData; bool PaletteModifiedStatusEnum::initializedFlag = false; int32_t PaletteModifiedStatusEnum::integerCodeCounter = 0; #endif // __PALETTE_MODIFIED_STATUS_ENUM_DECLARE__ } // namespace #endif //__PALETTE_MODIFIED_STATUS_ENUM_H__ connectome-workbench-1.4.2/src/Palette/PaletteNormalizationModeEnum.cxx000066400000000000000000000277501360521144700263560ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __PALETTE_NORMALIZATION_MODE_ENUM_DECLARE__ #include "PaletteNormalizationModeEnum.h" #undef __PALETTE_NORMALIZATION_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::PaletteNormalizationModeEnum * \brief Enumerated type for normalization of file/map data. * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_paletteNormalizationModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void paletteNormalizationModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "PaletteNormalizationModeEnum.h" * * Instatiate: * m_paletteNormalizationModeEnumComboBox = new EnumComboBoxTemplate(this); * m_paletteNormalizationModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_paletteNormalizationModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(paletteNormalizationModeEnumComboBoxItemActivated())); * * Update the selection: * m_paletteNormalizationModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const PaletteNormalizationModeEnum::Enum VARIABLE = m_paletteNormalizationModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ PaletteNormalizationModeEnum::PaletteNormalizationModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ PaletteNormalizationModeEnum::~PaletteNormalizationModeEnum() { } /** * Initialize the enumerated metadata. */ void PaletteNormalizationModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(PaletteNormalizationModeEnum(NORMALIZATION_ALL_MAP_DATA, "NORMALIZATION_ALL_MAP_DATA", "All Maps In File")); enumData.push_back(PaletteNormalizationModeEnum(NORMALIZATION_SELECTED_MAP_DATA, "NORMALIZATION_SELECTED_MAP_DATA", "Selected Map In File")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const PaletteNormalizationModeEnum* PaletteNormalizationModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const PaletteNormalizationModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString PaletteNormalizationModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteNormalizationModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ PaletteNormalizationModeEnum::Enum PaletteNormalizationModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PaletteNormalizationModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteNormalizationModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type PaletteNormalizationModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString PaletteNormalizationModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteNormalizationModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ PaletteNormalizationModeEnum::Enum PaletteNormalizationModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PaletteNormalizationModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteNormalizationModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type PaletteNormalizationModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t PaletteNormalizationModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteNormalizationModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ PaletteNormalizationModeEnum::Enum PaletteNormalizationModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PaletteNormalizationModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteNormalizationModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type PaletteNormalizationModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void PaletteNormalizationModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void PaletteNormalizationModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(PaletteNormalizationModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void PaletteNormalizationModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(PaletteNormalizationModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } AString PaletteNormalizationModeEnum::getEnumToolTopInHTML() { const AString msg("" "Normalization controls how data values are mapped to the color palette. " "The data's most negative, zero, and most positive values are mapped to " "the palette's -1.0, 0.0, and 1.0 colors.

    " "" + toGuiName(PaletteNormalizationModeEnum::NORMALIZATION_ALL_MAP_DATA) + "
    " + " Uses data from all maps within the file and results in identical data " "values from any map in the file receiving identical coloring.

    " "" + toGuiName(PaletteNormalizationModeEnum::NORMALIZATION_SELECTED_MAP_DATA) + "
    " + " Uses data from the selected map and so identical data values " " in different maps may receive different coloring.
    " ""); return msg; } connectome-workbench-1.4.2/src/Palette/PaletteNormalizationModeEnum.h000066400000000000000000000065211360521144700257740ustar00rootroot00000000000000#ifndef __PALETTE_NORMALIZATION_MODE_ENUM_H__ #define __PALETTE_NORMALIZATION_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2015 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class PaletteNormalizationModeEnum { public: /** * Enumerated values. */ enum Enum { /** Use data from all maps in file for normalization */ NORMALIZATION_ALL_MAP_DATA, /** Use data from selected map for normalization */ NORMALIZATION_SELECTED_MAP_DATA }; ~PaletteNormalizationModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); static AString getEnumToolTopInHTML(); private: PaletteNormalizationModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const PaletteNormalizationModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __PALETTE_NORMALIZATION_MODE_ENUM_DECLARE__ std::vector PaletteNormalizationModeEnum::enumData; bool PaletteNormalizationModeEnum::initializedFlag = false; int32_t PaletteNormalizationModeEnum::integerCodeCounter = 0; #endif // __PALETTE_NORMALIZATION_MODE_ENUM_DECLARE__ } // namespace #endif //__PALETTE_NORMALIZATION_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Palette/PaletteScalarAndColor.cxx000066400000000000000000000113711360521144700247150ustar00rootroot00000000000000/*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "PaletteScalarAndColor.h" using namespace caret; /** * Constructor. * * @param scalar - the scalar value * @param colorIndex - the scalar's color index * */ PaletteScalarAndColor::PaletteScalarAndColor( const float scalar, const AString& colorName) : CaretObject() { this->initializeMembersPaletteScalarAndColor(); this->scalar = scalar; setColorName(colorName); } /** * Destructor */ PaletteScalarAndColor::~PaletteScalarAndColor() { } /** * Copy Constructor * @param Object that is copied. */ PaletteScalarAndColor::PaletteScalarAndColor(const PaletteScalarAndColor& o) : CaretObject(o), TracksModificationInterface() { this->initializeMembersPaletteScalarAndColor(); this->copyHelper(o); } /** * Assignment operator. */ PaletteScalarAndColor& PaletteScalarAndColor::operator=(const PaletteScalarAndColor& o) { if (this != &o) { CaretObject::operator=(o); this->copyHelper(o); }; return *this; } /** * Helps with copy constructor and assignment operator. */ void PaletteScalarAndColor::copyHelper(const PaletteScalarAndColor& o) { this->scalar = o.scalar; this->colorName = o.colorName; this->noneColorFlag = o.noneColorFlag; this->rgba[0] = o.rgba[0]; this->rgba[1] = o.rgba[1]; this->rgba[2] = o.rgba[2]; this->rgba[3] = o.rgba[3]; this->clearModified(); } void PaletteScalarAndColor::initializeMembersPaletteScalarAndColor() { this->modifiedFlag = false; this->scalar = 0.0f; this->colorName = ""; this->noneColorFlag = false; this->rgba[0] = 1.0f; this->rgba[1] = 1.0f; this->rgba[2] = 1.0f; this->rgba[3] = 1.0f; } /** * Set the scalar. * * @param scalar - new value for scalar. * */ void PaletteScalarAndColor::setScalar(const float scalar) { if (this->scalar != scalar) { this->scalar = scalar; this->setModified(); } } /** * Set the name of the color for this scalar. * @param colorName * New name for color. */ void PaletteScalarAndColor::setColorName(const AString& colorName) { if (this->colorName != colorName) { this->colorName = colorName; this->noneColorFlag = (colorName == "none"); this->setModified(); } } /** * Get the RGBA components of the color. * @param rgbaOut * float array with red, green, blue, alpha * components ranging 0 to 1 are loaded into. */ void PaletteScalarAndColor::getColor(float rgbaOut[4]) const { rgbaOut[0] = this->rgba[0]; rgbaOut[1] = this->rgba[1]; rgbaOut[2] = this->rgba[2]; rgbaOut[3] = this->rgba[3]; } /** * Set the color's RGBA components. * @param rgba * New components for RGBA color. */ void PaletteScalarAndColor::setColor(const float rgba[4]) { if ((this->rgba[0] != rgba[0]) || (this->rgba[1] != rgba[1]) || (this->rgba[2] != rgba[2]) || (this->rgba[3] != rgba[3])) { this->rgba[0] = rgba[0]; this->rgba[1] = rgba[1]; this->rgba[2] = rgba[2]; this->rgba[3] = rgba[3]; this->setModified(); } } /** * Get string representation for debugging. * * @return A string. * */ AString PaletteScalarAndColor::toString() const { AString s = "[colorName=" + this->colorName + ", scale=" + AString::number(this->scalar) + ", rgba=" + AString::fromNumbers(rgba, 4, ",") + "]"; return s; } /** * Set this object has been modified. * */ void PaletteScalarAndColor::setModified() { this->modifiedFlag = true; } /** * Set this object as not modified. Object should also * clear the modification status of its children. * */ void PaletteScalarAndColor::clearModified() { this->modifiedFlag = false; } /** * Get the modification status. Returns true if this object or * any of its children have been modified. * @return - The modification status. * */ bool PaletteScalarAndColor::isModified() const { return this->modifiedFlag; } connectome-workbench-1.4.2/src/Palette/PaletteScalarAndColor.h000066400000000000000000000057121360521144700243440ustar00rootroot00000000000000#ifndef __PALETTESCALARANDCOLOR_H__ #define __PALETTESCALARANDCOLOR_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include "CaretObject.h" #include "TracksModificationInterface.h" #include #include namespace caret { /** * Contains information about the color assigned to the scalar * value. A palette contains a set of these objects. */ class PaletteScalarAndColor : public CaretObject, TracksModificationInterface { public: PaletteScalarAndColor(const float scalar, const AString& colorName); PaletteScalarAndColor(const PaletteScalarAndColor& o); PaletteScalarAndColor& operator=(const PaletteScalarAndColor& o); virtual ~PaletteScalarAndColor(); private: void copyHelper(const PaletteScalarAndColor& o); void initializeMembersPaletteScalarAndColor(); public: /** * @return The scalar */ inline float getScalar() const { return this->scalar; } void setScalar(const float scalar); /** * Get the name of the color. * @return * Name of the color assigned to the scalar. */ inline const AString& getColorName() const { return this->colorName; } void setColorName(const AString& colorName); /** * @return float array with red, green, blue, alpha color components ranging 0 to 1. */ inline const float* getColor() const { return rgba; } void getColor(float rgbaOut[4]) const; void setColor(const float rgba[4]); AString toString() const; void setModified(); void clearModified(); bool isModified() const; /** * @return Is the color the 'none' color meaning * that no coloring is applied? */ inline bool isNoneColor() const { return this->noneColorFlag; } private: /** has this object been modified. (DO NOT CLONE) */ bool modifiedFlag; /** the scalar value */ float scalar; /** the color's name, use the setName() method so that none color flag is updated */ AString colorName; /** the color's rgba components */ float rgba[4]; bool noneColorFlag; }; } // namespace #endif // __PALETTESCALARANDCOLOR_H__ connectome-workbench-1.4.2/src/Palette/PaletteThresholdOutlineDrawingModeEnum.cxx000066400000000000000000000272411360521144700303330ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __PALETTE_THRESHOLD_OUTLINE_DRAWING_MODE_ENUM_DECLARE__ #include "PaletteThresholdOutlineDrawingModeEnum.h" #undef __PALETTE_THRESHOLD_OUTLINE_DRAWING_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::PaletteThresholdOutlineDrawingModeEnum * \brief Threshold outline drawing modes * * Using this enumerated type in the GUI with an EnumComboBoxTemplate * * Header File (.h) * Forward declare the data type: * class EnumComboBoxTemplate; * * Declare the member: * EnumComboBoxTemplate* m_paletteThresholdOutlineDrawingModeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: * void paletteThresholdOutlineDrawingModeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" * #include "PaletteThresholdOutlineDrawingModeEnum.h" * * Instatiate: * m_paletteThresholdOutlineDrawingModeEnumComboBox = new EnumComboBoxTemplate(this); * m_paletteThresholdOutlineDrawingModeEnumComboBox->setup(); * * Get notified when the user changes the selection: * QObject::connect(m_paletteThresholdOutlineDrawingModeEnumComboBox, SIGNAL(itemActivated()), * this, SLOT(paletteThresholdOutlineDrawingModeEnumComboBoxItemActivated())); * * Update the selection: * m_paletteThresholdOutlineDrawingModeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: * const PaletteThresholdOutlineDrawingModeEnum::Enum VARIABLE = m_paletteThresholdOutlineDrawingModeEnumComboBox->getSelectedItem(); * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ PaletteThresholdOutlineDrawingModeEnum::PaletteThresholdOutlineDrawingModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ PaletteThresholdOutlineDrawingModeEnum::~PaletteThresholdOutlineDrawingModeEnum() { } /** * Initialize the enumerated metadata. */ void PaletteThresholdOutlineDrawingModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(PaletteThresholdOutlineDrawingModeEnum(OFF, "OFF", "Off")); enumData.push_back(PaletteThresholdOutlineDrawingModeEnum(OUTLINE, "OUTLINE", "Outline Only")); enumData.push_back(PaletteThresholdOutlineDrawingModeEnum(OUTLINE_AND_DATA, "OUTLINE_AND_DATA", "Outline Around Data")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const PaletteThresholdOutlineDrawingModeEnum* PaletteThresholdOutlineDrawingModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const PaletteThresholdOutlineDrawingModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString PaletteThresholdOutlineDrawingModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteThresholdOutlineDrawingModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ PaletteThresholdOutlineDrawingModeEnum::Enum PaletteThresholdOutlineDrawingModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PaletteThresholdOutlineDrawingModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteThresholdOutlineDrawingModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type PaletteThresholdOutlineDrawingModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString PaletteThresholdOutlineDrawingModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteThresholdOutlineDrawingModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ PaletteThresholdOutlineDrawingModeEnum::Enum PaletteThresholdOutlineDrawingModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PaletteThresholdOutlineDrawingModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteThresholdOutlineDrawingModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type PaletteThresholdOutlineDrawingModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t PaletteThresholdOutlineDrawingModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteThresholdOutlineDrawingModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ PaletteThresholdOutlineDrawingModeEnum::Enum PaletteThresholdOutlineDrawingModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PaletteThresholdOutlineDrawingModeEnum::enumData[0].enumValue; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteThresholdOutlineDrawingModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type PaletteThresholdOutlineDrawingModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void PaletteThresholdOutlineDrawingModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void PaletteThresholdOutlineDrawingModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(PaletteThresholdOutlineDrawingModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void PaletteThresholdOutlineDrawingModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(PaletteThresholdOutlineDrawingModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Palette/PaletteThresholdOutlineDrawingModeEnum.h000066400000000000000000000065601360521144700277610ustar00rootroot00000000000000#ifndef __PALETTE_THRESHOLD_OUTLINE_DRAWING_MODE_ENUM_H__ #define __PALETTE_THRESHOLD_OUTLINE_DRAWING_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2018 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class PaletteThresholdOutlineDrawingModeEnum { public: /** * Enumerated values. */ enum Enum { /** Off */ OFF, /** Outline */ OUTLINE, /** Outline and data */ OUTLINE_AND_DATA }; ~PaletteThresholdOutlineDrawingModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: PaletteThresholdOutlineDrawingModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const PaletteThresholdOutlineDrawingModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __PALETTE_THRESHOLD_OUTLINE_DRAWING_MODE_ENUM_DECLARE__ std::vector PaletteThresholdOutlineDrawingModeEnum::enumData; bool PaletteThresholdOutlineDrawingModeEnum::initializedFlag = false; int32_t PaletteThresholdOutlineDrawingModeEnum::integerCodeCounter = 0; #endif // __PALETTE_THRESHOLD_OUTLINE_DRAWING_MODE_ENUM_DECLARE__ } // namespace #endif //__PALETTE_THRESHOLD_OUTLINE_DRAWING_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Palette/PaletteThresholdRangeModeEnum.cxx000066400000000000000000000233751360521144700264400ustar00rootroot00000000000000 /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #define __PALETTE_THRESHOLD_RANGE_MODE_ENUM_DECLARE__ #include "PaletteThresholdRangeModeEnum.h" #undef __PALETTE_THRESHOLD_RANGE_MODE_ENUM_DECLARE__ #include "CaretAssert.h" using namespace caret; /** * \class caret::PaletteThresholdRangeModeEnum * \brief * * */ /** * Constructor. * * @param enumValue * An enumerated value. * @param name * Name of enumerated value. * * @param guiName * User-friendly name for use in user-interface. */ PaletteThresholdRangeModeEnum::PaletteThresholdRangeModeEnum(const Enum enumValue, const AString& name, const AString& guiName) { this->enumValue = enumValue; this->integerCode = integerCodeCounter++; this->name = name; this->guiName = guiName; } /** * Destructor. */ PaletteThresholdRangeModeEnum::~PaletteThresholdRangeModeEnum() { } /** * Initialize the enumerated metadata. */ void PaletteThresholdRangeModeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; enumData.push_back(PaletteThresholdRangeModeEnum(PALETTE_THRESHOLD_RANGE_MODE_FILE, "PALETTE_THRESHOLD_RANGE_MODE_FILE", "File")); enumData.push_back(PaletteThresholdRangeModeEnum(PALETTE_THRESHOLD_RANGE_MODE_MAP, "PALETTE_THRESHOLD_RANGE_MODE_MAP", "Map")); enumData.push_back(PaletteThresholdRangeModeEnum(PALETTE_THRESHOLD_RANGE_MODE_UNLIMITED, "PALETTE_THRESHOLD_RANGE_MODE_UNLIMITED", "Unlimited")); } /** * Find the data for and enumerated value. * @param enumValue * The enumerated value. * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ const PaletteThresholdRangeModeEnum* PaletteThresholdRangeModeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { const PaletteThresholdRangeModeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } } return NULL; } /** * Get a string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString PaletteThresholdRangeModeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteThresholdRangeModeEnum* enumInstance = findData(enumValue); return enumInstance->name; } /** * Get an enumerated value corresponding to its name. * @param name * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ PaletteThresholdRangeModeEnum::Enum PaletteThresholdRangeModeEnum::fromName(const AString& name, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PALETTE_THRESHOLD_RANGE_MODE_MAP; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteThresholdRangeModeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type PaletteThresholdRangeModeEnum")); } return enumValue; } /** * Get a GUI string representation of the enumerated type. * @param enumValue * Enumerated value. * @return * String representing enumerated value. */ AString PaletteThresholdRangeModeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteThresholdRangeModeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } /** * Get an enumerated value corresponding to its GUI name. * @param s * Name of enumerated value. * @param isValidOut * If not NULL, it is set indicating that a * enum value exists for the input name. * @return * Enumerated value. */ PaletteThresholdRangeModeEnum::Enum PaletteThresholdRangeModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PALETTE_THRESHOLD_RANGE_MODE_MAP; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteThresholdRangeModeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type PaletteThresholdRangeModeEnum")); } return enumValue; } /** * Get the integer code for a data type. * * @return * Integer code for data type. */ int32_t PaletteThresholdRangeModeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); const PaletteThresholdRangeModeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } /** * Find the data type corresponding to an integer code. * * @param integerCode * Integer code for enum. * @param isValidOut * If not NULL, on exit isValidOut will indicate if * integer code is valid. * @return * Enum for integer code. */ PaletteThresholdRangeModeEnum::Enum PaletteThresholdRangeModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; Enum enumValue = PALETTE_THRESHOLD_RANGE_MODE_MAP; for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { const PaletteThresholdRangeModeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; break; } } if (isValidOut != 0) { *isValidOut = validFlag; } else if (validFlag == false) { CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type PaletteThresholdRangeModeEnum")); } return enumValue; } /** * Get all of the enumerated type values. The values can be used * as parameters to toXXX() methods to get associated metadata. * * @param allEnums * A vector that is OUTPUT containing all of the enumerated values. */ void PaletteThresholdRangeModeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); } } /** * Get all of the names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void PaletteThresholdRangeModeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allNames.push_back(PaletteThresholdRangeModeEnum::toName(iter->enumValue)); } if (isSorted) { std::sort(allNames.begin(), allNames.end()); } } /** * Get all of the GUI names of the enumerated type values. * * @param allNames * A vector that is OUTPUT containing all of the GUI names of the enumerated values. * @param isSorted * If true, the names are sorted in alphabetical order. */ void PaletteThresholdRangeModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allGuiNames.push_back(PaletteThresholdRangeModeEnum::toGuiName(iter->enumValue)); } if (isSorted) { std::sort(allGuiNames.begin(), allGuiNames.end()); } } connectome-workbench-1.4.2/src/Palette/PaletteThresholdRangeModeEnum.h000066400000000000000000000067161360521144700260650ustar00rootroot00000000000000#ifndef __PALETTE_THRESHOLD_RANGE_MODE_ENUM_H__ #define __PALETTE_THRESHOLD_RANGE_MODE_ENUM_H__ /*LICENSE_START*/ /* * Copyright (C) 2014 Washington University School of Medicine * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*LICENSE_END*/ #include #include #include "AString.h" namespace caret { class PaletteThresholdRangeModeEnum { public: /** * Enumerated values. */ enum Enum { /** Threshold range is minimum and maximum values from file */ PALETTE_THRESHOLD_RANGE_MODE_FILE, /** Threshold range is minimum and maximum values from map */ PALETTE_THRESHOLD_RANGE_MODE_MAP, /** Threshold range is unlimited (minimum and maximum float values) */ PALETTE_THRESHOLD_RANGE_MODE_UNLIMITED, }; ~PaletteThresholdRangeModeEnum(); static AString toName(Enum enumValue); static Enum fromName(const AString& name, bool* isValidOut); static AString toGuiName(Enum enumValue); static Enum fromGuiName(const AString& guiName, bool* isValidOut); static int32_t toIntegerCode(Enum enumValue); static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); static void getAllEnums(std::vector& allEnums); static void getAllNames(std::vector& allNames, const bool isSorted); static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: PaletteThresholdRangeModeEnum(const Enum enumValue, const AString& name, const AString& guiName); static const PaletteThresholdRangeModeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); /** Indicates instance of enum values and metadata have been initialized */ static bool initializedFlag; /** Auto generated integer codes */ static int32_t integerCodeCounter; /** The enumerated type value for an instance */ Enum enumValue; /** The integer code associated with an enumerated value */ int32_t integerCode; /** The name, a text string that is identical to the enumerated value */ AString name; /** A user-friendly name that is displayed in the GUI */ AString guiName; }; #ifdef __PALETTE_THRESHOLD_RANGE_MODE_ENUM_DECLARE__ std::vector PaletteThresholdRangeModeEnum::enumData; bool PaletteThresholdRangeModeEnum::initializedFlag = false; int32_t PaletteThresholdRangeModeEnum::integerCodeCounter = 0; #endif // __PALETTE_THRESHOLD_RANGE_MODE_ENUM_DECLARE__ } // namespace #endif //__PALETTE_THRESHOLD_RANGE_MODE_ENUM_H__ connectome-workbench-1.4.2/src/Quazip/000077500000000000000000000000001360521144700176735ustar00rootroot00000000000000connectome-workbench-1.4.2/src/Quazip/CMakeLists.txt000066400000000000000000000031071360521144700224340ustar00rootroot00000000000000# # Name of project # PROJECT(Quazip) IF(Qt5_FOUND) include_directories(${Qt5Core_INCLUDE_DIRS}) ENDIF() IF (QT4_FOUND) SET(QT_DONT_USE_QTGUI TRUE) INCLUDE(${QT_USE_FILE}) ENDIF () # # With AUTOMOC, do not need to specify files # that contain Q_OBJECT macro for Qt to process with 'moc' # (meta-object compiler). # IF(WORKBENCH_USE_CMAKE_AUTOMOC) SET(CMAKE_AUTOMOC ON) ELSE() SET(MOC_INPUT_HEADER_FILES quazipfile.h ) IF(Qt5_FOUND) QT5_WRAP_CPP(MOC_SOURCE_FILES ${MOC_INPUT_HEADER_FILES}) ENDIF() IF (QT4_FOUND) QT4_WRAP_CPP(MOC_SOURCE_FILES ${MOC_INPUT_HEADER_FILES}) ENDIF () ENDIF() # # Prevents dll linkage errors on windows # #IF(WIN32) # ADD_DEFINITIONS(-DQUAZIP_STATIC) # IF(MSVC) # ADD_DEFINITIONS(-DQUAZIP_STATIC) # #ADD_DEFINITIONS(-DQUAZIP_BUILD) # ENDIF(MSVC) #ELSE(WIN32) # ADD_DEFINITIONS(-DQUAZIP_STATIC) #ENDIF(WIN32) # # Create a library # ADD_LIBRARY(Quazip JlCompress.h crypt.h ioapi.h quaadler32.h quachecksum32.h quacrc32.h quagzipfile.h quaziodevice.h quazip.h quazip_global.h quazipdir.h quazipfile.h quazipfileinfo.h quazipnewinfo.h unzip.h zip.h ${MOC_SOURCE_FILES} JlCompress.cpp qioapi.cpp quaadler32.cpp quacrc32.cpp quagzipfile.cpp quaziodevice.cpp quazip.cpp quazipdir.cpp quazipfile.cpp quazipfileinfo.cpp quazipnewinfo.cpp unzip.c zip.c ) TARGET_LINK_LIBRARIES(Quazip ${CARET_QT5_LINK}) SET(QUAZIP_LIBRARIES Quazip PARENT_SCOPE) SET(QUAZIP_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE) connectome-workbench-1.4.2/src/Quazip/COPYING000066400000000000000000000604201360521144700207300ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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 with this License. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS connectome-workbench-1.4.2/src/Quazip/JlCompress.cpp000066400000000000000000000352311360521144700224640ustar00rootroot00000000000000#include "JlCompress.h" #include static bool copyData(QIODevice &inFile, QIODevice &outFile) { while (!inFile.atEnd()) { char buf[4096]; qint64 readLen = inFile.read(buf, 4096); if (readLen <= 0) return false; if (outFile.write(buf, readLen) != readLen) return false; } return true; } /**OK * Comprime il file fileName, nell'oggetto zip, con il nome fileDest. * * La funzione fallisce se: * * zip==NULL; * * l'oggetto zip e stato aperto in una modalita non compatibile con l'aggiunta di file; * * non e possibile aprire il file d'origine; * * non e possibile creare il file all'interno dell'oggetto zip; * * si e rilevato un errore nella copia dei dati; * * non e stato possibile chiudere il file all'interno dell'oggetto zip; */ bool JlCompress::compressFile(QuaZip* zip, QString fileName, QString fileDest) { // zip: oggetto dove aggiungere il file // fileName: nome del file reale // fileDest: nome del file all'interno del file compresso // Controllo l'apertura dello zip if (!zip) return false; if (zip->getMode()!=QuaZip::mdCreate && zip->getMode()!=QuaZip::mdAppend && zip->getMode()!=QuaZip::mdAdd) return false; // Apro il file originale QFile inFile; inFile.setFileName(fileName); if(!inFile.open(QIODevice::ReadOnly)) return false; // Apro il file risulato QuaZipFile outFile(zip); if(!outFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileDest, inFile.fileName()))) return false; // Copio i dati if (!copyData(inFile, outFile) || outFile.getZipError()!=UNZ_OK) { return false; } // Chiudo i file outFile.close(); if (outFile.getZipError()!=UNZ_OK) return false; inFile.close(); return true; } /**OK * Comprime la cartella dir nel file fileCompressed, se recursive e true allora * comprime anche le sotto cartelle. I nomi dei file preceduti dal path creato * togliendo il pat della cartella origDir al path della cartella dir. * Se la funzione fallisce restituisce false e cancella il file che si e tentato * di creare. * * La funzione fallisce se: * * zip==NULL; * * l'oggetto zip e stato aperto in una modalita non compatibile con l'aggiunta di file; * * la cartella dir non esiste; * * la compressione di una sotto cartella fallisce (1); * * la compressione di un file fallisce; * (1) La funzione si richiama in maniera ricorsiva per comprimere le sotto cartelle * dunque gli errori di compressione di una sotto cartella sono gli stessi di questa * funzione. */ bool JlCompress::compressSubDir(QuaZip* zip, QString dir, QString origDir, bool recursive) { // zip: oggetto dove aggiungere il file // dir: cartella reale corrente // origDir: cartella reale originale // (path(dir)-path(origDir)) = path interno all'oggetto zip // Controllo l'apertura dello zip if (!zip) return false; if (zip->getMode()!=QuaZip::mdCreate && zip->getMode()!=QuaZip::mdAppend && zip->getMode()!=QuaZip::mdAdd) return false; // Controllo la cartella QDir directory(dir); if (!directory.exists()) return false; QDir origDirectory(origDir); if (dir != origDir) { QuaZipFile dirZipFile(zip); if (!dirZipFile.open(QIODevice::WriteOnly, QuaZipNewInfo(origDirectory.relativeFilePath(dir) + "/", dir), 0, 0, 0)) { return false; } dirZipFile.close(); } // Se comprimo anche le sotto cartelle if (recursive) { // Per ogni sotto cartella QFileInfoList files = directory.entryInfoList(QDir::AllDirs|QDir::NoDotAndDotDot); Q_FOREACH (QFileInfo file, files) { // Comprimo la sotto cartella if(!compressSubDir(zip,file.absoluteFilePath(),origDir,recursive)) return false; } } // Per ogni file nella cartella QFileInfoList files = directory.entryInfoList(QDir::Files); Q_FOREACH (QFileInfo file, files) { // Se non e un file o e il file compresso che sto creando if(!file.isFile()||file.absoluteFilePath()==zip->getZipName()) continue; // Creo il nome relativo da usare all'interno del file compresso QString filename = origDirectory.relativeFilePath(file.absoluteFilePath()); // Comprimo il file if (!compressFile(zip,file.absoluteFilePath(),filename)) return false; } return true; } /**OK * Estrae il file fileName, contenuto nell'oggetto zip, con il nome fileDest. * Se la funzione fallisce restituisce false e cancella il file che si e tentato di estrarre. * * La funzione fallisce se: * * zip==NULL; * * l'oggetto zip e stato aperto in una modalita non compatibile con l'estrazione di file; * * non e possibile aprire il file all'interno dell'oggetto zip; * * non e possibile creare il file estratto; * * si e rilevato un errore nella copia dei dati (1); * * non e stato possibile chiudere il file all'interno dell'oggetto zip (1); * * (1): prima di uscire dalla funzione cancella il file estratto. */ bool JlCompress::extractFile(QuaZip* zip, QString fileName, QString fileDest) { // zip: oggetto dove aggiungere il file // filename: nome del file reale // fileincompress: nome del file all'interno del file compresso // Controllo l'apertura dello zip if (!zip) return false; if (zip->getMode()!=QuaZip::mdUnzip) return false; // Apro il file compresso if (!fileName.isEmpty()) zip->setCurrentFile(fileName); QuaZipFile inFile(zip); if(!inFile.open(QIODevice::ReadOnly) || inFile.getZipError()!=UNZ_OK) return false; // Controllo esistenza cartella file risultato QDir curDir; if (!curDir.mkpath(QFileInfo(fileDest).absolutePath())) { return false; } QuaZipFileInfo info; if (!zip->getCurrentFileInfo(&info)) return false; if (fileDest.endsWith('/') && QFileInfo(fileDest).isDir()) { QFile(fileDest).setPermissions(info.getPermissions()); return true; } // Apro il file risultato QFile outFile; outFile.setFileName(fileDest); if(!outFile.open(QIODevice::WriteOnly)) return false; // Copio i dati if (!copyData(inFile, outFile) || inFile.getZipError()!=UNZ_OK) { outFile.close(); removeFile(QStringList(fileDest)); return false; } outFile.close(); // Chiudo i file inFile.close(); if (inFile.getZipError()!=UNZ_OK) { removeFile(QStringList(fileDest)); return false; } outFile.setPermissions(info.getPermissions()); return true; } /** * Rimuove i file il cui nome e specificato all'interno di listFile. * Restituisce true se tutti i file sono stati cancellati correttamente, attenzione * perche puo restituire false anche se alcuni file non esistevano e si e tentato * di cancellarli. */ bool JlCompress::removeFile(QStringList listFile) { bool ret = true; // Per ogni file for (int i=0; iopen(QuaZip::mdUnzip)) { delete zip; return QStringList(); } // Estraggo i nomi dei file QStringList lst; QuaZipFileInfo info; for(bool more=zip->goToFirstFile(); more; more=zip->goToNextFile()) { if(!zip->getCurrentFileInfo(&info)) { delete zip; return QStringList(); } lst << info.name; //info.name.toLocal8Bit().constData() } // Chiudo il file zip zip->close(); if(zip->getZipError()!=0) { delete zip; return QStringList(); } delete zip; return lst; } connectome-workbench-1.4.2/src/Quazip/JlCompress.h000066400000000000000000000103351360521144700221270ustar00rootroot00000000000000#ifndef JLCOMPRESSFOLDER_H_ #define JLCOMPRESSFOLDER_H_ #include "quazip.h" #include "quazipfile.h" #include "quazipfileinfo.h" #include #include #include #include /// Utility class for typical operations. /** This class contains a number of useful static functions to perform simple operations, such as mass ZIP packing or extraction. */ class QUAZIP_EXPORT JlCompress { private: /// Compress a single file. /** \param zip Opened zip to compress the file to. \param fileName The full path to the source file. \param fileDest The full name of the file inside the archive. \return true if success, false otherwise. */ static bool compressFile(QuaZip* zip, QString fileName, QString fileDest); /// Compress a subdirectory. /** \param parentZip Opened zip containing the parent directory. \param dir The full path to the directory to pack. \param parentDir The full path to the directory corresponding to the root of the ZIP. \param recursive Whether to pack sub-directories as well or only files. \return true if success, false otherwise. */ static bool compressSubDir(QuaZip* parentZip, QString dir, QString parentDir, bool recursive = true); /// Extract a single file. /** \param zip The opened zip archive to extract from. \param fileName The full name of the file to extract. \param fileDest The full path to the destination file. \return true if success, false otherwise. */ static bool extractFile(QuaZip* zip, QString fileName, QString fileDest); /// Remove some files. /** \param listFile The list of files to remove. \return true if success, false otherwise. */ static bool removeFile(QStringList listFile); public: /// Compress a single file. /** \param fileCompressed The name of the archive. \param file The file to compress. \return true if success, false otherwise. */ static bool compressFile(QString fileCompressed, QString file); /// Compress a list of files. /** \param fileCompressed The name of the archive. \param files The file list to compress. \return true if success, false otherwise. */ static bool compressFiles(QString fileCompressed, QStringList files); /// Compress a whole directory. /** \param fileCompressed The name of the archive. \param dir The directory to compress. \param recursive Whether to pack the subdirectories as well, or just regular files. \return true if success, false otherwise. */ static bool compressDir(QString fileCompressed, QString dir = QString(), bool recursive = true); public: /// Extract a single file. /** \param fileCompressed The name of the archive. \param fileName The file to extract. \param fileDest The destination file, assumed to be identical to \a file if left empty. \return The list of the full paths of the files extracted, empty on failure. */ static QString extractFile(QString fileCompressed, QString fileName, QString fileDest = QString()); /// Extract a list of files. /** \param fileCompressed The name of the archive. \param files The file list to extract. \param dir The directory to put the files to, the current directory if left empty. \return The list of the full paths of the files extracted, empty on failure. */ static QStringList extractFiles(QString fileCompressed, QStringList files, QString dir = QString()); /// Extract a whole archive. /** \param fileCompressed The name of the archive. \param dir The directory to extract to, the current directory if left empty. \return The list of the full paths of the files extracted, empty on failure. */ static QStringList extractDir(QString fileCompressed, QString dir = QString()); /// Get the file list. /** \return The list of the files in the archive, or, more precisely, the list of the entries, including both files and directories if they are present separately. */ static QStringList getFileList(QString fileCompressed); }; #endif /* JLCOMPRESSFOLDER_H_ */ connectome-workbench-1.4.2/src/Quazip/NEWS.txt000066400000000000000000000125551360521144700212200ustar00rootroot00000000000000QuaZIP changes * 2014-01-22 0.6 * Minizip updated to 1.1 (with all the necessary modifications re-done), and that means that... * the long-awaited zip64 support is now available! * A few rather minor fixes. * 2014-01-19 0.5.2 * Some minor bug fixes. * API to access file permissions subfield of the external attributes. * MS VS 2012 Express support. * API to set the default codec used to encode/decode file names (mainly for use by various wrappers such as JlCompress, when you don't have direct access to the underlying QuaZip instance). * 2013-03-02 0.5.1 * Lots of QuaZipDir fixes, thanks to all bug reporters. * Full Qt Creator support. * MS VS 2010 Express support. * Qt5 support (didn't need any source code changes anyway). * Lots of minor bug fixes. * 2012-09-07 0.5 * Added run_moc.bat files for building under Windows in case Qt integration is not available (e. g. VS 2008 Express). * Added the QuaZipDir class to simplify ZIP navigation in terms of directories. * Added the QuaGzipFile class for working with GZIP archives. It was added as a bonus since it has nothing to do with the main purpose of the library. It probably won't get any major improvements, although minor bug fixes are possible. * Added the QuaZIODevice class for working with zlib compression. It has nothing to do with the ZIP format, and therefore the same notice as for the QuaGzipFile applies. * The global comment is no longer erased when adding files to an archive. * Many bug fixes. * 2012-01-14 0.4.4 * Fixed isSequential() test that was causing open() failures on Unix. * Fixed sub-directory compressing in JlCompress. * Added MS VS 2008 solution, compatible with the binary Qt distribution (tested on MS VS 2008 Express, had to run MOC manually due to the lack of plugin in Express). * Fixed extracting directories in JlCompress. * Fixed JlCompress.h includes in the test suite, which used lowercase names thus breaking on case-sensitive systems. * Implemented missing QuaZipFile::getZip() that was only declared. * Fixed reopening closed files. * Fixed possible memory leak in case of open error. * 2011-09-09 0.4.3 * New test suite using QTestLib. * Fixed bytesAvailable(), pos() and atEnd(). * Added ZIP v1.0 support and disabling data descriptor for compatibility with some older software. * Fixed DLL export/import issues for some symbols. * Added QUAZIP_STATIC macro for compiling as a static library or directly including the source. * Added getFileNameList() and getFileInfoList() convenience functions. * Added some buffering to JlCompress to improve performance. * 2011-08-10 0.4.2 * Cmake patch (thanks to Bernhard Rosenkraenzer). * Symbian patch (thanks to Hamish Willee). * Documented the multiple files limitation of QuaZipFile. * Fixed relative paths handling in JlCompress. * Fixed linking to MinGW zlib. * 2011-05-26 0.4.1 * License statement updated to avoid confusion. GPL license removed for the very same reason. * Parts of original package are now clearly marked as modified, just as their license requires. * 2011-05-23 0.4 * QuaZip and QuaZipFile classes now use the Pimpl idiom. This means that future releases will probably be binary compatible with this one, but it also means that this one is binary incompatible with the old ones. * IO API has been rewritten using QIODevice instead of standard C library. Among other things it means that QuaZip now supports files up to 4 GB in size instead of 2 GB. * Added QuaZip methods allowing access to ZIP files represented by any seekable QIODevice implementation (QBuffer is a good example). * 2010-07-23 0.3 * Fixed getComment() for global comments. * Added some useful classes for calculating checksums (thanks to Adam Walczak). * Added some utility classes for working with whole directories (thanks to Roberto Pompermaier). It would be nice if someone documents these in English, though. * Probably fixed some problems with passwords (thanks to Vasiliy Sorokin). I didn't test it, though. * 2008-09-17 0.2.3 * Fixed license notices in sources. * SVN * Fixed a small bug in QuaZipFile::atEnd(). * 2007-01-16 0.2.2 * Added LGPL as alternative license. * Added FAQ documentation page. * 2006-03-21 0.2.1 * Fixed setCommentCodec() bug. * Fixed bug that set month 1-12 instead of 0-11, as specified in zip.h. * Added workaround for Qt's bug that caused wrong timestamps. * Few documentation fixes and cosmetic changes. * 2005-07-08 0.2 * Write support. * Extended QuaZipFile API, including size(), *pos() functions. * Support for comments encoding/decoding. * 2005-07-01 0.1 * Initial version. connectome-workbench-1.4.2/src/Quazip/README.txt000066400000000000000000000045021360521144700213720ustar00rootroot00000000000000QuaZIP is the C++ wrapper for Gilles Vollant's ZIP/UNZIP package (AKA minizip) using Trolltech's Qt library. It uses existing ZIP/UNZIP package C code and therefore depends on the zlib library. Also, it depends on Qt 4. To compile it on UNIX dialect: $ cd quazip $ qmake $ make You must make sure that: * You have Qt 4 properly and fully installed (including tools and headers, not just library) * "qmake" command runs Qt 4's qmake, not some other version (you'll have to type full path to qmake otherwise). To install compiled shared library, just type: $ make install By default, it installs in /usr/local, but you may change it using $ qmake PREFIX=/wherever/you/want/to/install You do not have to compile and install QuaZIP to use it. You can just (and sometimes it may be the best way) add QuaZIP's source files to your project and use them. See doc/html or, if you do not have a browser, quazip/*.h and quazip/doc/* files for the more detailed documentation. For Windows, it's essentially the same, but you may have to adjust settings for different environments. If you want to include QuaZIP sources directly in your project or if you want to use QuaZIP compiled as a static library using "qmake CONFIG+=statliclib", you have to define the QUAZIP_STATIC macro, otherwise you're likely to run into problems as QuaZIP symbols will be marked as dllimported. Copyright notice: Copyright (C) 2005-2012 Sergey A. Tachenov This program 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 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser 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 See COPYING file for the full LGPL text. Original ZIP package is copyrighted by Gilles Vollant, see quazip/(un)zip.h files for details, basically it's zlib license. connectome-workbench-1.4.2/src/Quazip/crypt.h000066400000000000000000000115171360521144700212120ustar00rootroot00000000000000/* crypt.h -- base code for crypt/uncrypt ZIPfile Version 1.01e, February 12th, 2005 Copyright (C) 1998-2005 Gilles Vollant This code is a modified version of crypting code in Infozip distribution The encryption/decryption parts of this source code (as opposed to the non-echoing password parts) were originally written in Europe. The whole source package can be freely distributed, including from the USA. (Prior to January 2000, re-export from the US was a violation of US law.) This encryption code is a direct transcription of the algorithm from Roger Schlafly, described by Phil Katz in the file appnote.txt. This file (appnote.txt) is distributed with the PKZIP program (even in the version without encryption capabilities). If you don't need crypting in your application, just define symbols NOCRYPT and NOUNCRYPT. This code support the "Traditional PKWARE Encryption". The new AES encryption added on Zip format by Winzip (see the page http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong Encryption is not supported. */ #include "quazip_global.h" #define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) /*********************************************************************** * Return the next byte in the pseudo-random sequence */ static int decrypt_byte(unsigned long* pkeys, const z_crc_t FAR * pcrc_32_tab UNUSED) { //(void) pcrc_32_tab; /* avoid "unused parameter" warning */ unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an * unpredictable manner on 16-bit systems; not a problem * with any known compiler so far, though */ temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); } /*********************************************************************** * Update the encryption keys with the next byte of plain text */ static int update_keys(unsigned long* pkeys,const z_crc_t FAR * pcrc_32_tab,int c) { (*(pkeys+0)) = CRC32((*(pkeys+0)), c); (*(pkeys+1)) += (*(pkeys+0)) & 0xff; (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; { register int keyshift = (int)((*(pkeys+1)) >> 24); (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); } return c; } /*********************************************************************** * Initialize the encryption keys and the random header according to * the given password. */ static void init_keys(const char* passwd,unsigned long* pkeys,const z_crc_t FAR * pcrc_32_tab) { *(pkeys+0) = 305419896L; *(pkeys+1) = 591751049L; *(pkeys+2) = 878082192L; while (*passwd != '\0') { update_keys(pkeys,pcrc_32_tab,(int)*passwd); passwd++; } } #define zdecode(pkeys,pcrc_32_tab,c) \ (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) #define zencode(pkeys,pcrc_32_tab,c,t) \ (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) #ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED #define RAND_HEAD_LEN 12 /* "last resort" source for second part of crypt seed pattern */ # ifndef ZCR_SEED2 # define ZCR_SEED2 3141592654UL /* use PI as default pattern */ # endif static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting) const char *passwd; /* password string */ unsigned char *buf; /* where to write header */ int bufSize; unsigned long* pkeys; const z_crc_t FAR * pcrc_32_tab; unsigned long crcForCrypting; { int n; /* index in random header */ int t; /* temporary */ int c; /* random byte */ unsigned char header[RAND_HEAD_LEN-2]; /* random header */ static unsigned calls = 0; /* ensure different random header each time */ if (bufSize> 7) & 0xff; header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); } /* Encrypt random header (last two bytes is high word of crc) */ init_keys(passwd, pkeys, pcrc_32_tab); for (n = 0; n < RAND_HEAD_LEN-2; n++) { buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); } buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); return n; } #endif connectome-workbench-1.4.2/src/Quazip/ioapi.h000066400000000000000000000157301360521144700211530ustar00rootroot00000000000000/* ioapi.h -- IO base function header for compress/uncompress .zip part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications for Zip64 support Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) Modified by Sergey A. Tachenov to allow QIODevice API usage. For more info read MiniZip_info.txt Changes Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. More if/def section may be needed to support other platforms Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. (but you should use iowin32.c for windows instead) */ #ifndef _ZLIBIOAPI64_H #define _ZLIBIOAPI64_H #if (!defined(_WIN32)) && (!defined(WIN32)) // Linux needs this to support file operation on files larger then 4+GB // But might need better if/def to select just the platforms that needs them. #ifndef __USE_FILE_OFFSET64 #define __USE_FILE_OFFSET64 #endif #ifndef __USE_LARGEFILE64 #define __USE_LARGEFILE64 #endif #ifndef _LARGEFILE64_SOURCE #define _LARGEFILE64_SOURCE #endif #ifndef _FILE_OFFSET_BIT #define _FILE_OFFSET_BIT 64 #endif #endif #include #include #include "zlib.h" #if defined(USE_FILE32API) #define fopen64 fopen #define ftello64 ftell #define fseeko64 fseek #else #ifdef _MSC_VER #define fopen64 fopen #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) #define ftello64 _ftelli64 #define fseeko64 _fseeki64 #else // old MSC #define ftello64 ftell #define fseeko64 fseek #endif #endif #endif /* #ifndef ZPOS64_T #ifdef _WIN32 #define ZPOS64_T fpos_t #else #include #define ZPOS64_T uint64_t #endif #endif */ #ifdef HAVE_MINIZIP64_CONF_H #include "mz64conf.h" #endif /* a type choosen by DEFINE */ #ifdef HAVE_64BIT_INT_CUSTOM typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; #else #ifdef HAS_STDINT_H #include "stdint.h" typedef uint64_t ZPOS64_T; #else #if defined(_MSC_VER) || defined(__BORLANDC__) typedef unsigned __int64 ZPOS64_T; #else typedef unsigned long long int ZPOS64_T; #endif #endif #endif #ifdef __cplusplus extern "C" { #endif #ifndef OF #define OF _Z_OF #endif #define ZLIB_FILEFUNC_SEEK_CUR (1) #define ZLIB_FILEFUNC_SEEK_END (2) #define ZLIB_FILEFUNC_SEEK_SET (0) #define ZLIB_FILEFUNC_MODE_READ (1) #define ZLIB_FILEFUNC_MODE_WRITE (2) #define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) #define ZLIB_FILEFUNC_MODE_EXISTING (4) #define ZLIB_FILEFUNC_MODE_CREATE (8) #ifndef ZCALLBACK #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) #define ZCALLBACK CALLBACK #else #define ZCALLBACK #endif #endif typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, voidpf file, int mode)); typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); typedef uLong (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); typedef int (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); /* here is the "old" 32 bits structure structure */ typedef struct zlib_filefunc_def_s { open_file_func zopen_file; read_file_func zread_file; write_file_func zwrite_file; tell_file_func ztell_file; seek_file_func zseek_file; close_file_func zclose_file; testerror_file_func zerror_file; voidpf opaque; } zlib_filefunc_def; typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); typedef int (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, voidpf file, int mode)); typedef struct zlib_filefunc64_def_s { open64_file_func zopen64_file; read_file_func zread_file; write_file_func zwrite_file; tell64_file_func ztell64_file; seek64_file_func zseek64_file; close_file_func zclose_file; testerror_file_func zerror_file; voidpf opaque; } zlib_filefunc64_def; void fill_qiodevice64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); void fill_qiodevice_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); /* now internal definition, only for zip.c and unzip.h */ typedef struct zlib_filefunc64_32_def_s { zlib_filefunc64_def zfile_func64; open_file_func zopen32_file; tell_file_func ztell32_file; seek_file_func zseek32_file; } zlib_filefunc64_32_def; #define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) #define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) //#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) //#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) #define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) #define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf file,int mode)); int call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); #define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) #define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) #define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) #ifdef __cplusplus } #endif #endif connectome-workbench-1.4.2/src/Quazip/qioapi.cpp000066400000000000000000000164541360521144700216730ustar00rootroot00000000000000/* ioapi.c -- IO base function header for compress/uncompress .zip files using zlib + zip or unzip API Version 1.01e, February 12th, 2005 Copyright (C) 1998-2005 Gilles Vollant Modified by Sergey A. Tachenov to integrate with Qt. */ #include #include #include #include "zlib.h" #include "ioapi.h" #include "quazip_global.h" #include /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ #ifndef SEEK_CUR #define SEEK_CUR 1 #endif #ifndef SEEK_END #define SEEK_END 2 #endif #ifndef SEEK_SET #define SEEK_SET 0 #endif voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,voidpf file,int mode) { if (pfilefunc->zfile_func64.zopen64_file != NULL) return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,file,mode); else { return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,file,mode); } } int call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) { if (pfilefunc->zfile_func64.zseek64_file != NULL) return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); else { uLong offsetTruncated = (uLong)offset; if (offsetTruncated != offset) return -1; else return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); } } ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) { if (pfilefunc->zfile_func64.zseek64_file != NULL) return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); else { uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); if ((tell_uLong) == ((uLong)-1)) return (ZPOS64_T)-1; else return tell_uLong; } } voidpf ZCALLBACK qiodevice_open_file_func ( voidpf /*opaque UNUSED*/, voidpf file, int mode) { QIODevice *iodevice = reinterpret_cast(file); if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) iodevice->open(QIODevice::ReadOnly); else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) iodevice->open(QIODevice::ReadWrite); else if (mode & ZLIB_FILEFUNC_MODE_CREATE) iodevice->open(QIODevice::WriteOnly); if (iodevice->isOpen()) { if (iodevice->isSequential()) { iodevice->close(); return NULL; } else { return iodevice; } } else return NULL; } uLong ZCALLBACK qiodevice_read_file_func ( voidpf /*opaque UNUSED*/, voidpf stream, void* buf, uLong size) { uLong ret; ret = (uLong)((QIODevice*)stream)->read((char*)buf,size); return ret; } uLong ZCALLBACK qiodevice_write_file_func ( voidpf /*opaque UNUSED*/, voidpf stream, const void* buf, uLong size) { uLong ret; ret = (uLong)((QIODevice*)stream)->write((char*)buf,size); return ret; } uLong ZCALLBACK qiodevice_tell_file_func ( voidpf /*opaque UNUSED*/, voidpf stream) { uLong ret; ret = ((QIODevice*)stream)->pos(); return ret; } ZPOS64_T ZCALLBACK qiodevice64_tell_file_func ( voidpf /*opaque UNUSED*/, voidpf stream) { qint64 ret; ret = ((QIODevice*)stream)->pos(); return static_cast(ret); } int ZCALLBACK qiodevice_seek_file_func ( voidpf /*opaque UNUSED*/, voidpf stream, uLong offset, int origin) { uLong qiodevice_seek_result=0; int ret; switch (origin) { case ZLIB_FILEFUNC_SEEK_CUR : qiodevice_seek_result = ((QIODevice*)stream)->pos() + offset; break; case ZLIB_FILEFUNC_SEEK_END : qiodevice_seek_result = ((QIODevice*)stream)->size() - offset; break; case ZLIB_FILEFUNC_SEEK_SET : qiodevice_seek_result = offset; break; default: return -1; } ret = !((QIODevice*)stream)->seek(qiodevice_seek_result); return ret; } int ZCALLBACK qiodevice64_seek_file_func ( voidpf /*opaque UNUSED*/, voidpf stream, ZPOS64_T offset, int origin) { qint64 qiodevice_seek_result=0; int ret; switch (origin) { case ZLIB_FILEFUNC_SEEK_CUR : qiodevice_seek_result = ((QIODevice*)stream)->pos() + offset; break; case ZLIB_FILEFUNC_SEEK_END : qiodevice_seek_result = ((QIODevice*)stream)->size() - offset; break; case ZLIB_FILEFUNC_SEEK_SET : qiodevice_seek_result = offset; break; default: return -1; } ret = !((QIODevice*)stream)->seek(qiodevice_seek_result); return ret; } int ZCALLBACK qiodevice_close_file_func ( voidpf /*opaque UNUSED*/, voidpf stream) { ((QIODevice*)stream)->close(); return 0; } int ZCALLBACK qiodevice_error_file_func ( voidpf /*opaque UNUSED*/, voidpf /*stream UNUSED*/) { // can't check for error due to the QIODevice API limitation return 0; } void fill_qiodevice_filefunc ( zlib_filefunc_def* pzlib_filefunc_def) { pzlib_filefunc_def->zopen_file = qiodevice_open_file_func; pzlib_filefunc_def->zread_file = qiodevice_read_file_func; pzlib_filefunc_def->zwrite_file = qiodevice_write_file_func; pzlib_filefunc_def->ztell_file = qiodevice_tell_file_func; pzlib_filefunc_def->zseek_file = qiodevice_seek_file_func; pzlib_filefunc_def->zclose_file = qiodevice_close_file_func; pzlib_filefunc_def->zerror_file = qiodevice_error_file_func; pzlib_filefunc_def->opaque = NULL; } void fill_qiodevice64_filefunc ( zlib_filefunc64_def* pzlib_filefunc_def) { // Open functions are the same for Qt. pzlib_filefunc_def->zopen64_file = qiodevice_open_file_func; pzlib_filefunc_def->zread_file = qiodevice_read_file_func; pzlib_filefunc_def->zwrite_file = qiodevice_write_file_func; pzlib_filefunc_def->ztell64_file = qiodevice64_tell_file_func; pzlib_filefunc_def->zseek64_file = qiodevice64_seek_file_func; pzlib_filefunc_def->zclose_file = qiodevice_close_file_func; pzlib_filefunc_def->zerror_file = qiodevice_error_file_func; pzlib_filefunc_def->opaque = NULL; } void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) { p_filefunc64_32->zfile_func64.zopen64_file = NULL; p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; p_filefunc64_32->zfile_func64.ztell64_file = NULL; p_filefunc64_32->zfile_func64.zseek64_file = NULL; p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; } connectome-workbench-1.4.2/src/Quazip/quaadler32.cpp000066400000000000000000000007211360521144700223420ustar00rootroot00000000000000#include "quaadler32.h" #include "zlib.h" QuaAdler32::QuaAdler32() { reset(); } quint32 QuaAdler32::calculate(const QByteArray &data) { return adler32( adler32(0L, Z_NULL, 0), (const Bytef*)data.data(), data.size() ); } void QuaAdler32::reset() { checksum = adler32(0L, Z_NULL, 0); } void QuaAdler32::update(const QByteArray &buf) { checksum = adler32( checksum, (const Bytef*)buf.data(), buf.size() ); } quint32 QuaAdler32::value() { return checksum; } connectome-workbench-1.4.2/src/Quazip/quaadler32.h000066400000000000000000000010351360521144700220060ustar00rootroot00000000000000#ifndef QUAADLER32_H #define QUAADLER32_H #include #include "quachecksum32.h" /// Adler32 checksum /** \class QuaAdler32 quaadler32.h * This class wrappers the adler32 function with the QuaChecksum32 interface. * See QuaChecksum32 for more info. */ class QUAZIP_EXPORT QuaAdler32 : public QuaChecksum32 { public: QuaAdler32(); quint32 calculate(const QByteArray &data); void reset(); void update(const QByteArray &buf); quint32 value(); private: quint32 checksum; }; #endif //QUAADLER32_H connectome-workbench-1.4.2/src/Quazip/quachecksum32.h000066400000000000000000000025701360521144700225260ustar00rootroot00000000000000#ifndef QUACHECKSUM32_H #define QUACHECKSUM32_H #include #include "quazip_global.h" /// Checksum interface. /** \class QuaChecksum32 quachecksum32.h * This is an interface for 32 bit checksums. * Classes implementing this interface can calcunate a certin * checksum in a single step: * \code * QChecksum32 *crc32 = new QuaCrc32(); * rasoult = crc32->calculate(data); * \endcode * or by streaming the data: * \code * QChecksum32 *crc32 = new QuaCrc32(); * while(!fileA.atEnd()) * crc32->update(fileA.read(bufSize)); * resoultA = crc32->value(); * crc32->reset(); * while(!fileB.atEnd()) * crc32->update(fileB.read(bufSize)); * resoultB = crc32->value(); * \endcode */ class QUAZIP_EXPORT QuaChecksum32 { public: ///Calculates the checksum for data. /** \a data source data * \return data checksum * * This function has no efect on the value returned by value(). */ virtual quint32 calculate(const QByteArray &data) = 0; ///Resets the calculation on a checksun for a stream. virtual void reset() = 0; ///Updates the calculated checksum for the stream /** \a buf next portion of data from the stream */ virtual void update(const QByteArray &buf) = 0; ///Value of the checksum calculated for the stream passed throw update(). /** \return checksum */ virtual quint32 value() = 0; }; #endif //QUACHECKSUM32_H connectome-workbench-1.4.2/src/Quazip/quacrc32.cpp000066400000000000000000000006731360521144700220300ustar00rootroot00000000000000#include "quacrc32.h" #include "zlib.h" QuaCrc32::QuaCrc32() { reset(); } quint32 QuaCrc32::calculate(const QByteArray &data) { return crc32( crc32(0L, Z_NULL, 0), (const Bytef*)data.data(), data.size() ); } void QuaCrc32::reset() { checksum = crc32(0L, Z_NULL, 0); } void QuaCrc32::update(const QByteArray &buf) { checksum = crc32( checksum, (const Bytef*)buf.data(), buf.size() ); } quint32 QuaCrc32::value() { return checksum; } connectome-workbench-1.4.2/src/Quazip/quacrc32.h000066400000000000000000000007561360521144700214770ustar00rootroot00000000000000#ifndef QUACRC32_H #define QUACRC32_H #include "quachecksum32.h" ///CRC32 checksum /** \class QuaCrc32 quacrc32.h * This class wrappers the crc32 function with the QuaChecksum32 interface. * See QuaChecksum32 for more info. */ class QUAZIP_EXPORT QuaCrc32 : public QuaChecksum32 { public: QuaCrc32(); quint32 calculate(const QByteArray &data); void reset(); void update(const QByteArray &buf); quint32 value(); private: quint32 checksum; }; #endif //QUACRC32_H connectome-workbench-1.4.2/src/Quazip/quagzipfile.cpp000066400000000000000000000067641360521144700227340ustar00rootroot00000000000000#include #include "quagzipfile.h" /// \cond internal class QuaGzipFilePrivate { friend class QuaGzipFile; QString fileName; gzFile gzd; inline QuaGzipFilePrivate(): gzd(NULL) {} inline QuaGzipFilePrivate(const QString &fileName): fileName(fileName), gzd(NULL) {} template bool open(FileId id, QIODevice::OpenMode mode, QString &error); gzFile open(int fd, const char *modeString); gzFile open(const QString &name, const char *modeString); }; gzFile QuaGzipFilePrivate::open(const QString &name, const char *modeString) { return gzopen(QFile::encodeName(name).constData(), modeString); } gzFile QuaGzipFilePrivate::open(int fd, const char *modeString) { return gzdopen(fd, modeString); } template bool QuaGzipFilePrivate::open(FileId id, QIODevice::OpenMode mode, QString &error) { char modeString[2]; modeString[0] = modeString[1] = '\0'; if ((mode & QIODevice::Append) != 0) { error = QuaGzipFile::trUtf8("QIODevice::Append is not " "supported for GZIP"); return false; } if ((mode & QIODevice::ReadOnly) != 0 && (mode & QIODevice::WriteOnly) != 0) { error = QuaGzipFile::trUtf8("Opening gzip for both reading" " and writing is not supported"); return false; } else if ((mode & QIODevice::ReadOnly) != 0) { modeString[0] = 'r'; } else if ((mode & QIODevice::WriteOnly) != 0) { modeString[0] = 'w'; } else { error = QuaGzipFile::trUtf8("You can open a gzip either for reading" " or for writing. Which is it?"); return false; } gzd = open(id, modeString); if (gzd == NULL) { error = QuaGzipFile::trUtf8("Could not gzopen() file"); return false; } return true; } /// \endcond QuaGzipFile::QuaGzipFile(): d(new QuaGzipFilePrivate()) { } QuaGzipFile::QuaGzipFile(QObject *parent): QIODevice(parent), d(new QuaGzipFilePrivate()) { } QuaGzipFile::QuaGzipFile(const QString &fileName, QObject *parent): QIODevice(parent), d(new QuaGzipFilePrivate(fileName)) { } QuaGzipFile::~QuaGzipFile() { if (isOpen()) { close(); } delete d; } void QuaGzipFile::setFileName(const QString& fileName) { d->fileName = fileName; } QString QuaGzipFile::getFileName() const { return d->fileName; } bool QuaGzipFile::isSequential() const { return true; } bool QuaGzipFile::open(QIODevice::OpenMode mode) { QString error; if (!d->open(d->fileName, mode, error)) { setErrorString(error); return false; } return QIODevice::open(mode); } bool QuaGzipFile::open(int fd, QIODevice::OpenMode mode) { QString error; if (!d->open(fd, mode, error)) { setErrorString(error); return false; } return QIODevice::open(mode); } bool QuaGzipFile::flush() { return gzflush(d->gzd, Z_SYNC_FLUSH) == Z_OK; } void QuaGzipFile::close() { QIODevice::close(); gzclose(d->gzd); } qint64 QuaGzipFile::readData(char *data, qint64 maxSize) { return gzread(d->gzd, (voidp)data, (unsigned)maxSize); } qint64 QuaGzipFile::writeData(const char *data, qint64 maxSize) { if (maxSize == 0) return 0; int written = gzwrite(d->gzd, (voidp)data, (unsigned)maxSize); if (written == 0) return -1; else return written; } connectome-workbench-1.4.2/src/Quazip/quagzipfile.h000066400000000000000000000055011360521144700223650ustar00rootroot00000000000000#ifndef QUAZIP_QUAGZIPFILE_H #define QUAZIP_QUAGZIPFILE_H #include #include "quazip_global.h" #include class QuaGzipFilePrivate; /// GZIP file /** This class is a wrapper around GZIP file access functions in zlib. Unlike QuaZip classes, it doesn't allow reading from a GZIP file opened as QIODevice, for example, if your GZIP file is in QBuffer. It only provides QIODevice access to a GZIP file contents, but the GZIP file itself must be identified by its name on disk or by descriptor id. */ class QUAZIP_EXPORT QuaGzipFile: public QIODevice { Q_OBJECT public: /// Empty constructor. /** Must call setFileName() before trying to open. */ QuaGzipFile(); /// Empty constructor with a parent. /** Must call setFileName() before trying to open. \param parent The parent object, as per QObject logic. */ QuaGzipFile(QObject *parent); /// Constructor. /** \param fileName The name of the GZIP file. \param parent The parent object, as per QObject logic. */ QuaGzipFile(const QString &fileName, QObject *parent = NULL); /// Destructor. virtual ~QuaGzipFile(); /// Sets the name of the GZIP file to be opened. void setFileName(const QString& fileName); /// Returns the name of the GZIP file. QString getFileName() const; /// Returns true. /** Strictly speaking, zlib supports seeking for GZIP files, but it is poorly implemented, because there is no way to implement it properly. For reading, seeking backwards is very slow, and for writing, it is downright impossible. Therefore, QuaGzipFile does not support seeking at all. */ virtual bool isSequential() const; /// Opens the file. /** \param mode Can be either QIODevice::Write or QIODevice::Read. ReadWrite and Append aren't supported. */ virtual bool open(QIODevice::OpenMode mode); /// Opens the file. /** \overload \param fd The file descriptor to read/write the GZIP file from/to. \param mode Can be either QIODevice::Write or QIODevice::Read. ReadWrite and Append aren't supported. */ virtual bool open(int fd, QIODevice::OpenMode mode); /// Flushes data to file. /** The data is written using Z_SYNC_FLUSH mode. Doesn't make any sense when reading. */ virtual bool flush(); /// Closes the file. virtual void close(); protected: /// Implementation of QIODevice::readData(). virtual qint64 readData(char *data, qint64 maxSize); /// Implementation of QIODevice::writeData(). virtual qint64 writeData(const char *data, qint64 maxSize); private: // not implemented by design to disable copy QuaGzipFile(const QuaGzipFile &that); QuaGzipFile& operator=(const QuaGzipFile &that); QuaGzipFilePrivate *d; }; #endif // QUAZIP_QUAGZIPFILE_H connectome-workbench-1.4.2/src/Quazip/quaziodevice.cpp000066400000000000000000000175201360521144700230740ustar00rootroot00000000000000#include "quaziodevice.h" #define QUAZIO_INBUFSIZE 4096 #define QUAZIO_OUTBUFSIZE 4096 /// \cond internal class QuaZIODevicePrivate { friend class QuaZIODevice; QuaZIODevicePrivate(QIODevice *io); ~QuaZIODevicePrivate(); QIODevice *io; z_stream zins; z_stream zouts; char *inBuf; int inBufPos; int inBufSize; char *outBuf; int outBufPos; int outBufSize; bool zBufError; int doFlush(QString &error); }; QuaZIODevicePrivate::QuaZIODevicePrivate(QIODevice *io): io(io), inBuf(NULL), inBufPos(0), inBufSize(0), outBuf(NULL), outBufPos(0), outBufSize(0), zBufError(false) { zins.zalloc = (alloc_func) NULL; zins.zfree = (free_func) NULL; zins.opaque = NULL; zouts.zalloc = (alloc_func) NULL; zouts.zfree = (free_func) NULL; zouts.opaque = NULL; inBuf = new char[QUAZIO_INBUFSIZE]; outBuf = new char[QUAZIO_OUTBUFSIZE]; #ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT debug.setFileName("debug.out"); debug.open(QIODevice::WriteOnly); #endif #ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT indebug.setFileName("debug.in"); indebug.open(QIODevice::WriteOnly); #endif } QuaZIODevicePrivate::~QuaZIODevicePrivate() { #ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT debug.close(); #endif #ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT indebug.close(); #endif if (inBuf != NULL) delete[] inBuf; if (outBuf != NULL) delete[] outBuf; } int QuaZIODevicePrivate::doFlush(QString &error) { int flushed = 0; while (outBufPos < outBufSize) { int more = io->write(outBuf + outBufPos, outBufSize - outBufPos); if (more == -1) { error = io->errorString(); return -1; } if (more == 0) break; outBufPos += more; flushed += more; } if (outBufPos == outBufSize) { outBufPos = outBufSize = 0; } return flushed; } /// \endcond // #define QUAZIP_ZIODEVICE_DEBUG_OUTPUT // #define QUAZIP_ZIODEVICE_DEBUG_INPUT #ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT #include static QFile debug; #endif #ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT #include static QFile indebug; #endif QuaZIODevice::QuaZIODevice(QIODevice *io, QObject *parent): QIODevice(parent), d(new QuaZIODevicePrivate(io)) { connect(io, SIGNAL(readyRead()), SIGNAL(readyRead())); } QuaZIODevice::~QuaZIODevice() { if (isOpen()) close(); delete d; } QIODevice *QuaZIODevice::getIoDevice() const { return d->io; } bool QuaZIODevice::open(QIODevice::OpenMode mode) { if ((mode & QIODevice::Append) != 0) { setErrorString(trUtf8("QIODevice::Append is not supported for" " QuaZIODevice")); return false; } if ((mode & QIODevice::ReadWrite) == QIODevice::ReadWrite) { setErrorString(trUtf8("QIODevice::ReadWrite is not supported for" " QuaZIODevice")); return false; } if ((mode & QIODevice::ReadOnly) != 0) { if (inflateInit(&d->zins) != Z_OK) { setErrorString(d->zins.msg); return false; } } if ((mode & QIODevice::WriteOnly) != 0) { if (deflateInit(&d->zouts, Z_DEFAULT_COMPRESSION) != Z_OK) { setErrorString(d->zouts.msg); return false; } } return QIODevice::open(mode); } void QuaZIODevice::close() { if ((openMode() & QIODevice::ReadOnly) != 0) { if (inflateEnd(&d->zins) != Z_OK) { setErrorString(d->zins.msg); } } if ((openMode() & QIODevice::WriteOnly) != 0) { flush(); if (deflateEnd(&d->zouts) != Z_OK) { setErrorString(d->zouts.msg); } } QIODevice::close(); } qint64 QuaZIODevice::readData(char *data, qint64 maxSize) { int read = 0; while (read < maxSize) { if (d->inBufPos == d->inBufSize) { d->inBufPos = 0; d->inBufSize = d->io->read(d->inBuf, QUAZIO_INBUFSIZE); if (d->inBufSize == -1) { d->inBufSize = 0; setErrorString(d->io->errorString()); return -1; } if (d->inBufSize == 0) break; } while (read < maxSize && d->inBufPos < d->inBufSize) { d->zins.next_in = (Bytef *) (d->inBuf + d->inBufPos); d->zins.avail_in = d->inBufSize - d->inBufPos; d->zins.next_out = (Bytef *) (data + read); d->zins.avail_out = (uInt) (maxSize - read); // hope it's less than 2GB int more = 0; switch (inflate(&d->zins, Z_SYNC_FLUSH)) { case Z_OK: read = (char *) d->zins.next_out - data; d->inBufPos = (char *) d->zins.next_in - d->inBuf; break; case Z_STREAM_END: read = (char *) d->zins.next_out - data; d->inBufPos = (char *) d->zins.next_in - d->inBuf; return read; case Z_BUF_ERROR: // this should never happen, but just in case if (!d->zBufError) { qWarning("Z_BUF_ERROR detected with %d/%d in/out, weird", d->zins.avail_in, d->zins.avail_out); d->zBufError = true; } memmove(d->inBuf, d->inBuf + d->inBufPos, d->inBufSize - d->inBufPos); d->inBufSize -= d->inBufPos; d->inBufPos = 0; more = d->io->read(d->inBuf + d->inBufSize, QUAZIO_INBUFSIZE - d->inBufSize); if (more == -1) { setErrorString(d->io->errorString()); return -1; } if (more == 0) return read; d->inBufSize += more; break; default: setErrorString(QString::fromLocal8Bit(d->zins.msg)); return -1; } } } #ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT indebug.write(data, read); #endif return read; } qint64 QuaZIODevice::writeData(const char *data, qint64 maxSize) { int written = 0; QString error; if (d->doFlush(error) == -1) { setErrorString(error); return -1; } while (written < maxSize) { // there is some data waiting in the output buffer if (d->outBufPos < d->outBufSize) return written; d->zouts.next_in = (Bytef *) (data + written); d->zouts.avail_in = (uInt) (maxSize - written); // hope it's less than 2GB d->zouts.next_out = (Bytef *) d->outBuf; d->zouts.avail_out = QUAZIO_OUTBUFSIZE; switch (deflate(&d->zouts, Z_NO_FLUSH)) { case Z_OK: written = (char *) d->zouts.next_in - data; d->outBufSize = (char *) d->zouts.next_out - d->outBuf; break; default: setErrorString(QString::fromLocal8Bit(d->zouts.msg)); return -1; } if (d->doFlush(error) == -1) { setErrorString(error); return -1; } } #ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT debug.write(data, written); #endif return written; } bool QuaZIODevice::flush() { QString error; if (d->doFlush(error) < 0) { setErrorString(error); return false; } // can't flush buffer, some data is still waiting if (d->outBufPos < d->outBufSize) return true; Bytef c = 0; d->zouts.next_in = &c; // fake input buffer d->zouts.avail_in = 0; // of zero size do { d->zouts.next_out = (Bytef *) d->outBuf; d->zouts.avail_out = QUAZIO_OUTBUFSIZE; switch (deflate(&d->zouts, Z_SYNC_FLUSH)) { case Z_OK: d->outBufSize = (char *) d->zouts.next_out - d->outBuf; if (d->doFlush(error) < 0) { setErrorString(error); return false; } if (d->outBufPos < d->outBufSize) return true; break; case Z_BUF_ERROR: // nothing to write? return true; default: setErrorString(QString::fromLocal8Bit(d->zouts.msg)); return false; } } while (d->zouts.avail_out == 0); return true; } bool QuaZIODevice::isSequential() const { return true; } connectome-workbench-1.4.2/src/Quazip/quaziodevice.h000066400000000000000000000045651360521144700225460ustar00rootroot00000000000000#ifndef QUAZIP_QUAZIODEVICE_H #define QUAZIP_QUAZIODEVICE_H #include #include "quazip_global.h" #include class QuaZIODevicePrivate; /// A class to compress/decompress QIODevice. /** This class can be used to compress any data written to QIODevice or decompress it back. Compressing data sent over a QTcpSocket is a good example. */ class QUAZIP_EXPORT QuaZIODevice: public QIODevice { Q_OBJECT public: /// Constructor. /** \param io The QIODevice to read/write. \param parent The parent object, as per QObject logic. */ QuaZIODevice(QIODevice *io, QObject *parent = NULL); /// Destructor. ~QuaZIODevice(); /// Flushes data waiting to be written. /** Unfortunately, as QIODevice doesn't support flush() by itself, the only thing this method does is write the compressed data into the device using Z_SYNC_FLUSH mode. If you need the compressed data to actually be flushed from the buffer of the underlying QIODevice, you need to call its flush() method as well, providing it supports it (like QTcpSocket does). Example: \code QuaZIODevice dev(&sock); dev.open(QIODevice::Write); dev.write(yourDataGoesHere); dev.flush(); sock->flush(); // this actually sends data to network \endcode This may change in the future versions of QuaZIP by implementing an ugly hack: trying to cast the QIODevice using qobject_cast to known flush()-supporting subclasses, and calling flush if the resulting pointer is not zero. */ virtual bool flush(); /// Opens the device. /** \param mode Neither QIODevice::ReadWrite nor QIODevice::Append are not supported. */ virtual bool open(QIODevice::OpenMode mode); /// Closes this device, but not the underlying one. /** The underlying QIODevice is not closed in case you want to write something else to it. */ virtual void close(); /// Returns the underlying device. QIODevice *getIoDevice() const; /// Returns true. virtual bool isSequential() const; protected: /// Implementation of QIODevice::readData(). virtual qint64 readData(char *data, qint64 maxSize); /// Implementation of QIODevice::writeData(). virtual qint64 writeData(const char *data, qint64 maxSize); private: QuaZIODevicePrivate *d; }; #endif // QUAZIP_QUAZIODEVICE_H connectome-workbench-1.4.2/src/Quazip/quazip.cpp000066400000000000000000000507201360521144700217140ustar00rootroot00000000000000/* Copyright (C) 2005-2011 Sergey A. Tachenov This program 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 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser 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 See COPYING file for the full LGPL text. Original ZIP package is copyrighted by Gilles Vollant, see quazip/(un)zip.h files for details, basically it's zlib license. **/ #include #include #include #include "quazip.h" /// All the internal stuff for the QuaZip class. /** \internal This class keeps all the private stuff for the QuaZip class so it can be changed without breaking binary compatibility, according to the Pimpl idiom. */ class QuaZipPrivate { friend class QuaZip; private: /// The pointer to the corresponding QuaZip instance. QuaZip *q; /// The codec for file names. QTextCodec *fileNameCodec; /// The codec for comments. QTextCodec *commentCodec; /// The archive file name. QString zipName; /// The device to access the archive. QIODevice *ioDevice; /// The global comment. QString comment; /// The open mode. QuaZip::Mode mode; union { /// The internal handle for UNZIP modes. unzFile unzFile_f; /// The internal handle for ZIP modes. zipFile zipFile_f; }; /// Whether a current file is set. bool hasCurrentFile_f; /// The last error. int zipError; /// Whether \ref QuaZip::setDataDescriptorWritingEnabled() "the data descriptor writing mode" is enabled. bool dataDescriptorWritingEnabled; /// The zip64 mode. bool zip64; inline QTextCodec *getDefaultFileNameCodec() { if (defaultFileNameCodec == NULL) { return QTextCodec::codecForLocale(); } else { return defaultFileNameCodec; } } /// The constructor for the corresponding QuaZip constructor. inline QuaZipPrivate(QuaZip *q): q(q), fileNameCodec(getDefaultFileNameCodec()), commentCodec(QTextCodec::codecForLocale()), ioDevice(NULL), mode(QuaZip::mdNotOpen), hasCurrentFile_f(false), zipError(UNZ_OK), dataDescriptorWritingEnabled(true), zip64(false) { lastMappedDirectoryEntry.num_of_file = 0; lastMappedDirectoryEntry.pos_in_zip_directory = 0; } /// The constructor for the corresponding QuaZip constructor. inline QuaZipPrivate(QuaZip *q, const QString &zipName): q(q), fileNameCodec(getDefaultFileNameCodec()), commentCodec(QTextCodec::codecForLocale()), zipName(zipName), ioDevice(NULL), mode(QuaZip::mdNotOpen), hasCurrentFile_f(false), zipError(UNZ_OK), dataDescriptorWritingEnabled(true), zip64(false) { lastMappedDirectoryEntry.num_of_file = 0; lastMappedDirectoryEntry.pos_in_zip_directory = 0; } /// The constructor for the corresponding QuaZip constructor. inline QuaZipPrivate(QuaZip *q, QIODevice *ioDevice): q(q), fileNameCodec(getDefaultFileNameCodec()), commentCodec(QTextCodec::codecForLocale()), ioDevice(ioDevice), mode(QuaZip::mdNotOpen), hasCurrentFile_f(false), zipError(UNZ_OK), dataDescriptorWritingEnabled(true), zip64(false) { lastMappedDirectoryEntry.num_of_file = 0; lastMappedDirectoryEntry.pos_in_zip_directory = 0; } /// Returns either a list of file names or a list of QuaZipFileInfo. template bool getFileInfoList(QList *result) const; /// Stores map of filenames and file locations for unzipping inline void clearDirectoryMap(); inline void addCurrentFileToDirectoryMap(const QString &fileName); bool goToFirstUnmappedFile(); QHash directoryCaseSensitive; QHash directoryCaseInsensitive; unz64_file_pos lastMappedDirectoryEntry; static QTextCodec *defaultFileNameCodec; }; QTextCodec *QuaZipPrivate::defaultFileNameCodec = NULL; void QuaZipPrivate::clearDirectoryMap() { directoryCaseInsensitive.clear(); directoryCaseSensitive.clear(); lastMappedDirectoryEntry.num_of_file = 0; lastMappedDirectoryEntry.pos_in_zip_directory = 0; } void QuaZipPrivate::addCurrentFileToDirectoryMap(const QString &fileName) { if (!hasCurrentFile_f || fileName.isEmpty()) { return; } // Adds current file to filename map as fileName unz64_file_pos fileDirectoryPos; unzGetFilePos64(unzFile_f, &fileDirectoryPos); directoryCaseSensitive.insert(fileName, fileDirectoryPos); // Only add lowercase to directory map if not already there // ensures only map the first one seen QString lower = fileName.toLower(); if (!directoryCaseInsensitive.contains(lower)) directoryCaseInsensitive.insert(lower, fileDirectoryPos); // Mark last one if (fileDirectoryPos.pos_in_zip_directory > lastMappedDirectoryEntry.pos_in_zip_directory) lastMappedDirectoryEntry = fileDirectoryPos; } bool QuaZipPrivate::goToFirstUnmappedFile() { zipError = UNZ_OK; if (mode != QuaZip::mdUnzip) { qWarning("QuaZipPrivate::goToNextUnmappedFile(): ZIP is not open in mdUnzip mode"); return false; } // If not mapped anything, go to beginning if (lastMappedDirectoryEntry.pos_in_zip_directory == 0) { unzGoToFirstFile(unzFile_f); } else { // Goto the last one mapped, plus one unzGoToFilePos64(unzFile_f, &lastMappedDirectoryEntry); unzGoToNextFile(unzFile_f); } hasCurrentFile_f=zipError==UNZ_OK; if(zipError==UNZ_END_OF_LIST_OF_FILE) zipError=UNZ_OK; return hasCurrentFile_f; } QuaZip::QuaZip(): p(new QuaZipPrivate(this)) { } QuaZip::QuaZip(const QString& zipName): p(new QuaZipPrivate(this, zipName)) { } QuaZip::QuaZip(QIODevice *ioDevice): p(new QuaZipPrivate(this, ioDevice)) { } QuaZip::~QuaZip() { if(isOpen()) close(); delete p; } bool QuaZip::open(Mode mode, zlib_filefunc_def* ioApi) { p->zipError=UNZ_OK; if(isOpen()) { qWarning("QuaZip::open(): ZIP already opened"); return false; } QIODevice *ioDevice = p->ioDevice; if (ioDevice == NULL) { if (p->zipName.isEmpty()) { qWarning("QuaZip::open(): set either ZIP file name or IO device first"); return false; } else { ioDevice = new QFile(p->zipName); } } switch(mode) { case mdUnzip: if (ioApi == NULL) { p->unzFile_f=unzOpen2_64(ioDevice, NULL); } else { // QuaZIP pre-zip64 compatibility mode p->unzFile_f=unzOpen2(ioDevice, ioApi); } if(p->unzFile_f!=NULL) { p->mode=mode; p->ioDevice = ioDevice; return true; } else { p->zipError=UNZ_OPENERROR; if (!p->zipName.isEmpty()) delete ioDevice; return false; } case mdCreate: case mdAppend: case mdAdd: if (ioApi == NULL) { p->zipFile_f=zipOpen2_64(ioDevice, mode==mdCreate?APPEND_STATUS_CREATE: mode==mdAppend?APPEND_STATUS_CREATEAFTER: APPEND_STATUS_ADDINZIP, NULL, NULL); } else { // QuaZIP pre-zip64 compatibility mode p->zipFile_f=zipOpen2(ioDevice, mode==mdCreate?APPEND_STATUS_CREATE: mode==mdAppend?APPEND_STATUS_CREATEAFTER: APPEND_STATUS_ADDINZIP, NULL, ioApi); } if(p->zipFile_f!=NULL) { p->mode=mode; p->ioDevice = ioDevice; return true; } else { p->zipError=UNZ_OPENERROR; if (!p->zipName.isEmpty()) delete ioDevice; return false; } default: qWarning("QuaZip::open(): unknown mode: %d", (int)mode); if (!p->zipName.isEmpty()) delete ioDevice; return false; break; } } void QuaZip::close() { p->zipError=UNZ_OK; switch(p->mode) { case mdNotOpen: qWarning("QuaZip::close(): ZIP is not open"); return; case mdUnzip: p->zipError=unzClose(p->unzFile_f); break; case mdCreate: case mdAppend: case mdAdd: p->zipError=zipClose(p->zipFile_f, p->comment.isNull() ? NULL : p->commentCodec->fromUnicode(p->comment).constData()); break; default: qWarning("QuaZip::close(): unknown mode: %d", (int)p->mode); return; } // opened by name, need to delete the internal IO device if (!p->zipName.isEmpty()) { delete p->ioDevice; p->ioDevice = NULL; } p->clearDirectoryMap(); if(p->zipError==UNZ_OK) p->mode=mdNotOpen; } void QuaZip::setZipName(const QString& zipName) { if(isOpen()) { qWarning("QuaZip::setZipName(): ZIP is already open!"); return; } p->zipName=zipName; p->ioDevice = NULL; } void QuaZip::setIoDevice(QIODevice *ioDevice) { if(isOpen()) { qWarning("QuaZip::setIoDevice(): ZIP is already open!"); return; } p->ioDevice = ioDevice; p->zipName = QString(); } int QuaZip::getEntriesCount()const { QuaZip *fakeThis=(QuaZip*)this; // non-const fakeThis->p->zipError=UNZ_OK; if(p->mode!=mdUnzip) { qWarning("QuaZip::getEntriesCount(): ZIP is not open in mdUnzip mode"); return -1; } unz_global_info64 globalInfo; if((fakeThis->p->zipError=unzGetGlobalInfo64(p->unzFile_f, &globalInfo))!=UNZ_OK) return p->zipError; return (int)globalInfo.number_entry; } QString QuaZip::getComment()const { QuaZip *fakeThis=(QuaZip*)this; // non-const fakeThis->p->zipError=UNZ_OK; if(p->mode!=mdUnzip) { qWarning("QuaZip::getComment(): ZIP is not open in mdUnzip mode"); return QString(); } unz_global_info64 globalInfo; QByteArray comment; if((fakeThis->p->zipError=unzGetGlobalInfo64(p->unzFile_f, &globalInfo))!=UNZ_OK) return QString(); comment.resize(globalInfo.size_comment); if((fakeThis->p->zipError=unzGetGlobalComment(p->unzFile_f, comment.data(), comment.size())) < 0) return QString(); fakeThis->p->zipError = UNZ_OK; return p->commentCodec->toUnicode(comment); } bool QuaZip::setCurrentFile(const QString& fileName, CaseSensitivity cs) { p->zipError=UNZ_OK; if(p->mode!=mdUnzip) { qWarning("QuaZip::setCurrentFile(): ZIP is not open in mdUnzip mode"); return false; } if(fileName.isEmpty()) { p->hasCurrentFile_f=false; return true; } // Unicode-aware reimplementation of the unzLocateFile function if(p->unzFile_f==NULL) { p->zipError=UNZ_PARAMERROR; return false; } if(fileName.length()>MAX_FILE_NAME_LENGTH) { p->zipError=UNZ_PARAMERROR; return false; } // Find the file by name bool sens = convertCaseSensitivity(cs) == Qt::CaseSensitive; QString lower, current; if(!sens) lower=fileName.toLower(); p->hasCurrentFile_f=false; // Check the appropriate Map unz64_file_pos fileDirPos; fileDirPos.pos_in_zip_directory = 0; if (sens) { if (p->directoryCaseSensitive.contains(fileName)) fileDirPos = p->directoryCaseSensitive.value(fileName); } else { if (p->directoryCaseInsensitive.contains(lower)) fileDirPos = p->directoryCaseInsensitive.value(lower); } if (fileDirPos.pos_in_zip_directory != 0) { p->zipError = unzGoToFilePos64(p->unzFile_f, &fileDirPos); p->hasCurrentFile_f = p->zipError == UNZ_OK; } if (p->hasCurrentFile_f) return p->hasCurrentFile_f; // Not mapped yet, start from where we have got to so far for(bool more=p->goToFirstUnmappedFile(); more; more=goToNextFile()) { current=getCurrentFileName(); if(current.isEmpty()) return false; if(sens) { if(current==fileName) break; } else { if(current.toLower()==lower) break; } } return p->hasCurrentFile_f; } bool QuaZip::goToFirstFile() { p->zipError=UNZ_OK; if(p->mode!=mdUnzip) { qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode"); return false; } p->zipError=unzGoToFirstFile(p->unzFile_f); p->hasCurrentFile_f=p->zipError==UNZ_OK; return p->hasCurrentFile_f; } bool QuaZip::goToNextFile() { p->zipError=UNZ_OK; if(p->mode!=mdUnzip) { qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode"); return false; } p->zipError=unzGoToNextFile(p->unzFile_f); p->hasCurrentFile_f=p->zipError==UNZ_OK; if(p->zipError==UNZ_END_OF_LIST_OF_FILE) p->zipError=UNZ_OK; return p->hasCurrentFile_f; } bool QuaZip::getCurrentFileInfo(QuaZipFileInfo *info)const { QuaZipFileInfo64 info64; if (info == NULL) { // Very unlikely because of the overloads return false; } if (getCurrentFileInfo(&info64)) { info->versionCreated=info64.versionCreated; info->versionNeeded=info64.versionNeeded; info->flags=info64.flags; info->method=info64.method; info->crc=info64.crc; info->compressedSize=static_cast(info64.compressedSize); info->uncompressedSize=static_cast(info64.uncompressedSize); info->diskNumberStart=info64.diskNumberStart; info->internalAttr=info64.internalAttr; info->externalAttr=info64.externalAttr; info->name=info64.name; info->comment=info64.comment; info->extra=info64.extra; info->dateTime=info64.dateTime; return true; } else { return false; } } bool QuaZip::getCurrentFileInfo(QuaZipFileInfo64 *info)const { QuaZip *fakeThis=(QuaZip*)this; // non-const fakeThis->p->zipError=UNZ_OK; if(p->mode!=mdUnzip) { qWarning("QuaZip::getCurrentFileInfo(): ZIP is not open in mdUnzip mode"); return false; } unz_file_info64 info_z; QByteArray fileName; QByteArray extra; QByteArray comment; if(info==NULL) return false; if(!isOpen()||!hasCurrentFile()) return false; if((fakeThis->p->zipError=unzGetCurrentFileInfo64(p->unzFile_f, &info_z, NULL, 0, NULL, 0, NULL, 0))!=UNZ_OK) return false; fileName.resize(info_z.size_filename); extra.resize(info_z.size_file_extra); comment.resize(info_z.size_file_comment); if((fakeThis->p->zipError=unzGetCurrentFileInfo64(p->unzFile_f, NULL, fileName.data(), fileName.size(), extra.data(), extra.size(), comment.data(), comment.size()))!=UNZ_OK) return false; info->versionCreated=info_z.version; info->versionNeeded=info_z.version_needed; info->flags=info_z.flag; info->method=info_z.compression_method; info->crc=info_z.crc; info->compressedSize=info_z.compressed_size; info->uncompressedSize=info_z.uncompressed_size; info->diskNumberStart=info_z.disk_num_start; info->internalAttr=info_z.internal_fa; info->externalAttr=info_z.external_fa; info->name=p->fileNameCodec->toUnicode(fileName); info->comment=p->commentCodec->toUnicode(comment); info->extra=extra; info->dateTime=QDateTime( QDate(info_z.tmu_date.tm_year, info_z.tmu_date.tm_mon+1, info_z.tmu_date.tm_mday), QTime(info_z.tmu_date.tm_hour, info_z.tmu_date.tm_min, info_z.tmu_date.tm_sec)); // Add to directory map p->addCurrentFileToDirectoryMap(info->name); return true; } QString QuaZip::getCurrentFileName()const { QuaZip *fakeThis=(QuaZip*)this; // non-const fakeThis->p->zipError=UNZ_OK; if(p->mode!=mdUnzip) { qWarning("QuaZip::getCurrentFileName(): ZIP is not open in mdUnzip mode"); return QString(); } if(!isOpen()||!hasCurrentFile()) return QString(); QByteArray fileName(MAX_FILE_NAME_LENGTH, 0); if((fakeThis->p->zipError=unzGetCurrentFileInfo64(p->unzFile_f, NULL, fileName.data(), fileName.size(), NULL, 0, NULL, 0))!=UNZ_OK) return QString(); QString result = p->fileNameCodec->toUnicode(fileName.constData()); if (result.isEmpty()) return result; // Add to directory map p->addCurrentFileToDirectoryMap(result); return result; } void QuaZip::setFileNameCodec(QTextCodec *fileNameCodec) { p->fileNameCodec=fileNameCodec; } void QuaZip::setFileNameCodec(const char *fileNameCodecName) { p->fileNameCodec=QTextCodec::codecForName(fileNameCodecName); } QTextCodec *QuaZip::getFileNameCodec()const { return p->fileNameCodec; } void QuaZip::setCommentCodec(QTextCodec *commentCodec) { p->commentCodec=commentCodec; } void QuaZip::setCommentCodec(const char *commentCodecName) { p->commentCodec=QTextCodec::codecForName(commentCodecName); } QTextCodec *QuaZip::getCommentCodec()const { return p->commentCodec; } QString QuaZip::getZipName() const { return p->zipName; } QIODevice *QuaZip::getIoDevice() const { if (!p->zipName.isEmpty()) // opened by name, using an internal QIODevice return NULL; return p->ioDevice; } QuaZip::Mode QuaZip::getMode()const { return p->mode; } bool QuaZip::isOpen()const { return p->mode!=mdNotOpen; } int QuaZip::getZipError() const { return p->zipError; } void QuaZip::setComment(const QString& comment) { p->comment=comment; } bool QuaZip::hasCurrentFile()const { return p->hasCurrentFile_f; } unzFile QuaZip::getUnzFile() { return p->unzFile_f; } zipFile QuaZip::getZipFile() { return p->zipFile_f; } void QuaZip::setDataDescriptorWritingEnabled(bool enabled) { p->dataDescriptorWritingEnabled = enabled; } bool QuaZip::isDataDescriptorWritingEnabled() const { return p->dataDescriptorWritingEnabled; } template TFileInfo QuaZip_getFileInfo(QuaZip *zip, bool *ok); template<> QuaZipFileInfo QuaZip_getFileInfo(QuaZip *zip, bool *ok) { QuaZipFileInfo info; *ok = zip->getCurrentFileInfo(&info); return info; } template<> QString QuaZip_getFileInfo(QuaZip *zip, bool *ok) { QString name = zip->getCurrentFileName(); *ok = !name.isEmpty(); return name; } template bool QuaZipPrivate::getFileInfoList(QList *result) const { QuaZipPrivate *fakeThis=const_cast(this); fakeThis->zipError=UNZ_OK; if (mode!=QuaZip::mdUnzip) { qWarning("QuaZip::getFileNameList/getFileInfoList(): " "ZIP is not open in mdUnzip mode"); return false; } QString currentFile; if (q->hasCurrentFile()) { currentFile = q->getCurrentFileName(); } if (q->goToFirstFile()) { do { bool ok; result->append(QuaZip_getFileInfo(q, &ok)); if (!ok) return false; } while (q->goToNextFile()); } if (zipError != UNZ_OK) return false; if (currentFile.isEmpty()) { if (!q->goToFirstFile()) return false; } else { if (!q->setCurrentFile(currentFile)) return false; } return true; } QStringList QuaZip::getFileNameList() const { QStringList list; if (p->getFileInfoList(&list)) return list; else return QStringList(); } QList QuaZip::getFileInfoList() const { QList list; if (p->getFileInfoList(&list)) return list; else return QList(); } Qt::CaseSensitivity QuaZip::convertCaseSensitivity(QuaZip::CaseSensitivity cs) { if (cs == csDefault) { #ifdef Q_WS_WIN return Qt::CaseInsensitive; #else return Qt::CaseSensitive; #endif } else { return cs == csSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive; } } void QuaZip::setDefaultFileNameCodec(QTextCodec *codec) { QuaZipPrivate::defaultFileNameCodec = codec; } void QuaZip::setDefaultFileNameCodec(const char *codecName) { setDefaultFileNameCodec(QTextCodec::codecForName(codecName)); } void QuaZip::setZip64Enabled(bool zip64) { p->zip64 = zip64; } bool QuaZip::isZip64Enabled() const { return p->zip64; } connectome-workbench-1.4.2/src/Quazip/quazip.h000066400000000000000000000532231360521144700213620ustar00rootroot00000000000000#ifndef QUA_ZIP_H #define QUA_ZIP_H /* Copyright (C) 2005-2011 Sergey A. Tachenov This program 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 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser 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 See COPYING file for the full LGPL text. Original ZIP package is copyrighted by Gilles Vollant, see quazip/(un)zip.h files for details, basically it's zlib license. **/ #include #include #include #include "zip.h" #include "unzip.h" #include "quazip_global.h" #include "quazipfileinfo.h" // just in case it will be defined in the later versions of the ZIP/UNZIP #ifndef UNZ_OPENERROR // define additional error code #define UNZ_OPENERROR -1000 #endif class QuaZipPrivate; /// ZIP archive. /** \class QuaZip quazip.h * This class implements basic interface to the ZIP archive. It can be * used to read table contents of the ZIP archive and retreiving * information about the files inside it. * * You can also use this class to open files inside archive by passing * pointer to the instance of this class to the constructor of the * QuaZipFile class. But see QuaZipFile::QuaZipFile(QuaZip*, QObject*) * for the possible pitfalls. * * This class is indended to provide interface to the ZIP subpackage of * the ZIP/UNZIP package as well as to the UNZIP subpackage. But * currently it supports only UNZIP. * * The use of this class is simple - just create instance using * constructor, then set ZIP archive file name using setFile() function * (if you did not passed the name to the constructor), then open() and * then use different functions to work with it! Well, if you are * paranoid, you may also wish to call close before destructing the * instance, to check for errors on close. * * You may also use getUnzFile() and getZipFile() functions to get the * ZIP archive handle and use it with ZIP/UNZIP package API directly. * * This class supports localized file names inside ZIP archive, but you * have to set up proper codec with setCodec() function. By default, * locale codec will be used, which is probably ok for UNIX systems, but * will almost certainly fail with ZIP archives created in Windows. This * is because Windows ZIP programs have strange habit of using DOS * encoding for file names in ZIP archives. For example, ZIP archive * with cyrillic names created in Windows will have file names in \c * IBM866 encoding instead of \c WINDOWS-1251. I think that calling one * function is not much trouble, but for true platform independency it * would be nice to have some mechanism for file name encoding auto * detection using locale information. Does anyone know a good way to do * it? **/ class QUAZIP_EXPORT QuaZip { friend class QuaZipPrivate; public: /// Useful constants. enum Constants { MAX_FILE_NAME_LENGTH=256 /**< Maximum file name length. Taken from \c UNZ_MAXFILENAMEINZIP constant in unzip.c. */ }; /// Open mode of the ZIP file. enum Mode { mdNotOpen, ///< ZIP file is not open. This is the initial mode. mdUnzip, ///< ZIP file is open for reading files inside it. mdCreate, ///< ZIP file was created with open() call. mdAppend, /**< ZIP file was opened in append mode. This refers to * \c APPEND_STATUS_CREATEAFTER mode in ZIP/UNZIP package * and means that zip is appended to some existing file * what is useful when that file contains * self-extractor code. This is obviously \em not what * you whant to use to add files to the existing ZIP * archive. **/ mdAdd ///< ZIP file was opened for adding files in the archive. }; /// Case sensitivity for the file names. /** This is what you specify when accessing files in the archive. * Works perfectly fine with any characters thanks to Qt's great * unicode support. This is different from ZIP/UNZIP API, where * only US-ASCII characters was supported. **/ enum CaseSensitivity { csDefault=0, ///< Default for platform. Case sensitive for UNIX, not for Windows. csSensitive=1, ///< Case sensitive. csInsensitive=2 ///< Case insensitive. }; /// Returns the actual case sensitivity for the specified QuaZIP one. /** \param cs The value to convert. \returns If CaseSensitivity::csDefault, then returns the default file name case sensitivity for the platform. Otherwise, just returns the appropriate value from the Qt::CaseSensitivity enum. */ static Qt::CaseSensitivity convertCaseSensitivity( CaseSensitivity cs); private: QuaZipPrivate *p; // not (and will not be) implemented QuaZip(const QuaZip& that); // not (and will not be) implemented QuaZip& operator=(const QuaZip& that); public: /// Constructs QuaZip object. /** Call setName() before opening constructed object. */ QuaZip(); /// Constructs QuaZip object associated with ZIP file \a zipName. QuaZip(const QString& zipName); /// Constructs QuaZip object associated with ZIP file represented by \a ioDevice. /** The IO device must be seekable, otherwise an error will occur when opening. */ QuaZip(QIODevice *ioDevice); /// Destroys QuaZip object. /** Calls close() if necessary. */ ~QuaZip(); /// Opens ZIP file. /** * Argument \a mode specifies open mode of the ZIP archive. See Mode * for details. Note that there is zipOpen2() function in the * ZIP/UNZIP API which accepts \a globalcomment argument, but it * does not use it anywhere, so this open() function does not have this * argument. See setComment() if you need to set global comment. * * If the ZIP file is accessed via explicitly set QIODevice, then * this device is opened in the necessary mode. If the device was * already opened by some other means, then the behaviour is defined by * the device implementation, but generally it is not a very good * idea. For example, QFile will at least issue a warning. * * \return \c true if successful, \c false otherwise. * * \note ZIP/UNZIP API open calls do not return error code - they * just return \c NULL indicating an error. But to make things * easier, quazip.h header defines additional error code \c * UNZ_ERROROPEN and getZipError() will return it if the open call * of the ZIP/UNZIP API returns \c NULL. * * Argument \a ioApi specifies IO function set for ZIP/UNZIP * package to use. See unzip.h, zip.h and ioapi.h for details. Note * that IO API for QuaZip is different from the original package. * The file path argument was changed to be of type \c voidpf, and * QuaZip passes a QIODevice pointer there. This QIODevice is either * set explicitly via setIoDevice() or the QuaZip(QIODevice*) * constructor, or it is created internally when opening the archive * by its file name. The default API (qioapi.cpp) just delegates * everything to the QIODevice API. Not only this allows to use a * QIODevice instead of file name, but also has a nice side effect * of raising the file size limit from 2G to 4G (in non-zip64 archives). * * \note If the zip64 support is needed, the ioApi argument \em must be NULL * because due to the backwards compatibility issues it can be used to * provide a 32-bit API only. * * In short: just forget about the \a ioApi argument and you'll be * fine. **/ bool open(Mode mode, zlib_filefunc_def *ioApi =NULL); /// Closes ZIP file. /** Call getZipError() to determine if the close was successful. The * underlying QIODevice is also closed, regardless of whether it was * set explicitly or not. */ void close(); /// Sets the codec used to encode/decode file names inside archive. /** This is necessary to access files in the ZIP archive created * under Windows with non-latin characters in file names. For * example, file names with cyrillic letters will be in \c IBM866 * encoding. **/ void setFileNameCodec(QTextCodec *fileNameCodec); /// Sets the codec used to encode/decode file names inside archive. /** \overload * Equivalent to calling setFileNameCodec(QTextCodec::codecForName(codecName)); **/ void setFileNameCodec(const char *fileNameCodecName); /// Returns the codec used to encode/decode comments inside archive. QTextCodec* getFileNameCodec() const; /// Sets the codec used to encode/decode comments inside archive. /** This codec defaults to locale codec, which is probably ok. **/ void setCommentCodec(QTextCodec *commentCodec); /// Sets the codec used to encode/decode comments inside archive. /** \overload * Equivalent to calling setCommentCodec(QTextCodec::codecForName(codecName)); **/ void setCommentCodec(const char *commentCodecName); /// Returns the codec used to encode/decode comments inside archive. QTextCodec* getCommentCodec() const; /// Returns the name of the ZIP file. /** Returns null string if no ZIP file name has been set, for * example when the QuaZip instance is set up to use a QIODevice * instead. * \sa setZipName(), setIoDevice(), getIoDevice() **/ QString getZipName() const; /// Sets the name of the ZIP file. /** Does nothing if the ZIP file is open. * * Does not reset error code returned by getZipError(). * \sa setIoDevice(), getIoDevice(), getZipName() **/ void setZipName(const QString& zipName); /// Returns the device representing this ZIP file. /** Returns null string if no device has been set explicitly, for * example when opening a ZIP file by name. * \sa setIoDevice(), getZipName(), setZipName() **/ QIODevice *getIoDevice() const; /// Sets the device representing the ZIP file. /** Does nothing if the ZIP file is open. * * Does not reset error code returned by getZipError(). * \sa getIoDevice(), getZipName(), setZipName() **/ void setIoDevice(QIODevice *ioDevice); /// Returns the mode in which ZIP file was opened. Mode getMode() const; /// Returns \c true if ZIP file is open, \c false otherwise. bool isOpen() const; /// Returns the error code of the last operation. /** Returns \c UNZ_OK if the last operation was successful. * * Error code resets to \c UNZ_OK every time you call any function * that accesses something inside ZIP archive, even if it is \c * const (like getEntriesCount()). open() and close() calls reset * error code too. See documentation for the specific functions for * details on error detection. **/ int getZipError() const; /// Returns number of the entries in the ZIP central directory. /** Returns negative error code in the case of error. The same error * code will be returned by subsequent getZipError() call. **/ int getEntriesCount() const; /// Returns global comment in the ZIP file. QString getComment() const; /// Sets the global comment in the ZIP file. /** The comment will be written to the archive on close operation. * QuaZip makes a distinction between a null QByteArray() comment * and an empty "" comment in the QuaZip::mdAdd mode. * A null comment is the default and it means "don't change * the comment". An empty comment removes the original comment. * * \sa open() **/ void setComment(const QString& comment); /// Sets the current file to the first file in the archive. /** Returns \c true on success, \c false otherwise. Call * getZipError() to get the error code. **/ bool goToFirstFile(); /// Sets the current file to the next file in the archive. /** Returns \c true on success, \c false otherwise. Call * getZipError() to determine if there was an error. * * Should be used only in QuaZip::mdUnzip mode. * * \note If the end of file was reached, getZipError() will return * \c UNZ_OK instead of \c UNZ_END_OF_LIST_OF_FILE. This is to make * things like this easier: * \code * for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) { * // do something * } * if(zip.getZipError()==UNZ_OK) { * // ok, there was no error * } * \endcode **/ bool goToNextFile(); /// Sets current file by its name. /** Returns \c true if successful, \c false otherwise. Argument \a * cs specifies case sensitivity of the file name. Call * getZipError() in the case of a failure to get error code. * * This is not a wrapper to unzLocateFile() function. That is * because I had to implement locale-specific case-insensitive * comparison. * * Here are the differences from the original implementation: * * - If the file was not found, error code is \c UNZ_OK, not \c * UNZ_END_OF_LIST_OF_FILE (see also goToNextFile()). * - If this function fails, it unsets the current file rather than * resetting it back to what it was before the call. * * If \a fileName is null string then this function unsets the * current file and return \c true. Note that you should close the * file first if it is open! See * QuaZipFile::QuaZipFile(QuaZip*,QObject*) for the details. * * Should be used only in QuaZip::mdUnzip mode. * * \sa setFileNameCodec(), CaseSensitivity **/ bool setCurrentFile(const QString& fileName, CaseSensitivity cs =csDefault); /// Returns \c true if the current file has been set. bool hasCurrentFile() const; /// Retrieves information about the current file. /** Fills the structure pointed by \a info. Returns \c true on * success, \c false otherwise. In the latter case structure pointed * by \a info remains untouched. If there was an error, * getZipError() returns error code. * * Should be used only in QuaZip::mdUnzip mode. * * Does nothing and returns \c false in any of the following cases. * - ZIP is not open; * - ZIP does not have current file. * * In both cases getZipError() returns \c UNZ_OK since there * is no ZIP/UNZIP API call. * * This overload doesn't support zip64. * * \sa getCurrentFileInfo(QuaZipFileInfo64* info)const **/ bool getCurrentFileInfo(QuaZipFileInfo* info)const; /// Retrieves information about the current file. /** \overload * * This function supports zip64. If the archive doesn't use zip64, it is * completely equivalent to getCurrentFileInfo(QuaZipFileInfo* info) * except for the argument type. * * \sa **/ bool getCurrentFileInfo(QuaZipFileInfo64* info)const; /// Returns the current file name. /** Equivalent to calling getCurrentFileInfo() and then getting \c * name field of the QuaZipFileInfo structure, but faster and more * convenient. * * Should be used only in QuaZip::mdUnzip mode. **/ QString getCurrentFileName()const; /// Returns \c unzFile handle. /** You can use this handle to directly call UNZIP part of the * ZIP/UNZIP package functions (see unzip.h). * * \warning When using the handle returned by this function, please * keep in mind that QuaZip class is unable to detect any changes * you make in the ZIP file state (e. g. changing current file, or * closing the handle). So please do not do anything with this * handle that is possible to do with the functions of this class. * Or at least return the handle in the original state before * calling some another function of this class (including implicit * destructor calls and calls from the QuaZipFile objects that refer * to this QuaZip instance!). So if you have changed the current * file in the ZIP archive - then change it back or you may * experience some strange behavior or even crashes. **/ unzFile getUnzFile(); /// Returns \c zipFile handle. /** You can use this handle to directly call ZIP part of the * ZIP/UNZIP package functions (see zip.h). Warnings about the * getUnzFile() function also apply to this function. **/ zipFile getZipFile(); /// Changes the data descriptor writing mode. /** According to the ZIP format specification, a file inside archive may have a data descriptor immediately following the file data. This is reflected by a special flag in the local file header and in the central directory. By default, QuaZIP sets this flag and writes the data descriptor unless both method and level were set to 0, in which case it operates in 1.0-compatible mode and never writes data descriptors. By setting this flag to false, it is possible to disable data descriptor writing, thus increasing compatibility with archive readers that don't understand this feature of the ZIP file format. Setting this flag affects all the QuaZipFile instances that are opened after this flag is set. The data descriptor writing mode is enabled by default. \param enabled If \c true, enable local descriptor writing, disable it otherwise. \sa QuaZipFile::setDataDescriptorWritingEnabled() */ void setDataDescriptorWritingEnabled(bool enabled); /// Returns the data descriptor default writing mode. /** \sa setDataDescriptorWritingEnabled() */ bool isDataDescriptorWritingEnabled() const; /// Returns a list of files inside the archive. /** \return A list of file names or an empty list if there was an error or if the archive is empty (call getZipError() to figure out which). \sa getFileInfoList() */ QStringList getFileNameList() const; /// Returns information list about all files inside the archive. /** \return A list of QuaZipFileInfo objects or an empty list if there was an error or if the archive is empty (call getZipError() to figure out which). \sa getFileNameList() */ QList getFileInfoList() const; /// Enables the zip64 mode. /** * @param zip64 If \c true, the zip64 mode is enabled, disabled otherwise. * * Once this is enabled, all new files (until the mode is disabled again) * will be created in the zip64 mode, thus enabling the ability to write * files larger than 4 GB. By default, the zip64 mode is off due to * compatibility reasons. * * \sa isZip64Enabled() */ void setZip64Enabled(bool zip64); /// Returns whether the zip64 mode is enabled. /** * @return \c true if and only if the zip64 mode is enabled. * * \sa setZip64Enabled() */ bool isZip64Enabled() const; /// Sets the default file name codec to use. /** * The default codec is used by the constructors, so calling this function * won't affect the QuaZip instances already created at that moment. * * The codec specified here can be overriden by calling setFileNameCodec(). * If neither function is called, QTextCodec::codecForLocale() will be used * to decode or encode file names. Use this function with caution if * the application uses other libraries that depend on QuaZIP. Those * libraries can either call this function by themselves, thus overriding * your setting or can rely on the default encoding, thus failing * mysteriously if you change it. For these reasons, it isn't recommended * to use this function if you are developing a library, not an application. * Instead, ask your library users to call it in case they need specific * encoding. * * In most cases, using setFileNameCodec() instead is the right choice. * However, if you depend on third-party code that uses QuaZIP, then the * reasons stated above can actually become a reason to use this function * in case the third-party code in question fails because it doesn't * understand the encoding you need and doesn't provide a way to specify it. * This applies to the JlCompress class as well, as it was contributed and * doesn't support explicit encoding parameters. * * In short: use setFileNameCodec() when you can, resort to * setDefaultFileNameCodec() when you don't have access to the QuaZip * instance. * * @param codec The codec to use by default. If NULL, resets to default. */ static void setDefaultFileNameCodec(QTextCodec *codec); /** * @overload * Equivalent to calling * setDefltFileNameCodec(QTextCodec::codecForName(codecName)). */ static void setDefaultFileNameCodec(const char *codecName); }; #endif connectome-workbench-1.4.2/src/Quazip/quazip_global.h000066400000000000000000000032201360521144700226720ustar00rootroot00000000000000/** Copyright (C) 2005-2011 Sergey A. Tachenov This program 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 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser 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 See COPYING file for the full LGPL text. Original ZIP package is copyrighted by Gilles Vollant, see quazip/(un)zip.h files for details, basically it's zlib license. */ #ifndef QUAZIP_GLOBAL_H #define QUAZIP_GLOBAL_H #include /** This is automatically defined when building a static library, but when including QuaZip sources directly into a project, QUAZIP_STATIC should be defined explicitly to avoid possible troubles with unnecessary importing/exporting. */ #ifdef QUAZIP_STATIC #define QUAZIP_EXPORT #else /** * When building a DLL with MSVC, QUAZIP_BUILD must be defined. * qglobal.h takes care of defining Q_DECL_* correctly for msvc/gcc. */ #if defined(QUAZIP_BUILD) #define QUAZIP_EXPORT Q_DECL_EXPORT #else #define QUAZIP_EXPORT Q_DECL_IMPORT #endif #endif // QUAZIP_STATIC #ifdef __GNUC__ #define UNUSED __attribute__((__unused__)) #else #define UNUSED #endif #endif // QUAZIP_GLOBAL_H connectome-workbench-1.4.2/src/Quazip/quazipdir.cpp000066400000000000000000000356441360521144700224230ustar00rootroot00000000000000#include #include "quazipdir.h" #include #include /// \cond internal class QuaZipDirPrivate: public QSharedData { friend class QuaZipDir; private: QuaZipDirPrivate(QuaZip *zip, const QString &dir = QString()): zip(zip), dir(dir), caseSensitivity(QuaZip::csDefault), filter(QDir::NoFilter), sorting(QDir::NoSort) {} QuaZip *zip; QString dir; QuaZip::CaseSensitivity caseSensitivity; QDir::Filters filter; QStringList nameFilters; QDir::SortFlags sorting; template bool entryInfoList(QStringList nameFilters, QDir::Filters filter, QDir::SortFlags sort, TFileInfoList &result) const; inline QString simplePath() const {return QDir::cleanPath(dir);} }; /// \endcond QuaZipDir::QuaZipDir(const QuaZipDir &that): d(that.d) { } QuaZipDir::QuaZipDir(QuaZip *zip, const QString &dir): d(new QuaZipDirPrivate(zip, dir)) { if (d->dir.startsWith('/')) d->dir = d->dir.mid(1); } QuaZipDir::~QuaZipDir() { } bool QuaZipDir::operator==(const QuaZipDir &that) { return d->zip == that.d->zip && d->dir == that.d->dir; } QuaZipDir& QuaZipDir::operator=(const QuaZipDir &that) { this->d = that.d; return *this; } QString QuaZipDir::operator[](int pos) const { return entryList().at(pos); } QuaZip::CaseSensitivity QuaZipDir::caseSensitivity() const { return d->caseSensitivity; } bool QuaZipDir::cd(const QString &directoryName) { if (directoryName == "/") { d->dir = ""; return true; } QString dirName = directoryName; if (dirName.endsWith('/')) dirName.chop(1); if (dirName.contains('/')) { QuaZipDir dir(*this); if (dirName.startsWith('/')) { #ifdef QUAZIP_QUAZIPDIR_DEBUG qDebug("QuaZipDir::cd(%s): going to /", dirName.toUtf8().constData()); #endif if (!dir.cd("/")) return false; } QStringList path = dirName.split('/', QString::SkipEmptyParts); for (QStringList::const_iterator i = path.constBegin(); i != path.end(); ++i) { const QString &step = *i; #ifdef QUAZIP_QUAZIPDIR_DEBUG qDebug("QuaZipDir::cd(%s): going to %s", dirName.toUtf8().constData(), step.toUtf8().constData()); #endif if (!dir.cd(step)) return false; } d->dir = dir.path(); return true; } else { // no '/' if (dirName == ".") { return true; } else if (dirName == "..") { if (isRoot()) { return false; } else { int slashPos = d->dir.lastIndexOf('/'); if (slashPos == -1) { d->dir = ""; } else { d->dir = d->dir.left(slashPos); } return true; } } else { // a simple subdirectory if (exists(dirName)) { if (isRoot()) d->dir = dirName; else d->dir += "/" + dirName; return true; } else { return false; } } } } bool QuaZipDir::cdUp() { return cd(".."); } uint QuaZipDir::count() const { return entryList().count(); } QString QuaZipDir::dirName() const { return QDir(d->dir).dirName(); } QuaZipFileInfo QuaZipDir_getFileInfo(QuaZip *zip, bool *ok, const QString &relativeName, bool isReal) { QuaZipFileInfo info; if (isReal) { *ok = zip->getCurrentFileInfo(&info); } else { *ok = true; info.compressedSize = 0; info.crc = 0; info.diskNumberStart = 0; info.externalAttr = 0; info.flags = 0; info.internalAttr = 0; info.method = 0; info.uncompressedSize = 0; info.versionCreated = info.versionNeeded = 0; } info.name = relativeName; return info; } template void QuaZipDir_convertInfoList(const QList &from, TFileInfoList &to); template<> void QuaZipDir_convertInfoList(const QList &from, QList &to) { to = from; } template<> void QuaZipDir_convertInfoList(const QList &from, QStringList &to) { to.clear(); for (QList::const_iterator i = from.constBegin(); i != from.constEnd(); ++i) { to.append(i->name); } } /// \cond internal /** An utility class to restore the current file. */ class QuaZipDirRestoreCurrent { public: inline QuaZipDirRestoreCurrent(QuaZip *zip): zip(zip), currentFile(zip->getCurrentFileName()) {} inline ~QuaZipDirRestoreCurrent() { zip->setCurrentFile(currentFile); } private: QuaZip *zip; QString currentFile; }; /// \endcond /// \cond internal class QuaZipDirComparator { private: QDir::SortFlags sort; static QString getExtension(const QString &name); int compareStrings(const QString &string1, const QString &string2); public: inline QuaZipDirComparator(QDir::SortFlags sort): sort(sort) {} bool operator()(const QuaZipFileInfo &info1, const QuaZipFileInfo &info2); }; QString QuaZipDirComparator::getExtension(const QString &name) { if (name.endsWith('.') || name.indexOf('.', 1) == -1) { return ""; } else { return name.mid(name.lastIndexOf('.') + 1); } } int QuaZipDirComparator::compareStrings(const QString &string1, const QString &string2) { if (sort & QDir::LocaleAware) { if (sort & QDir::IgnoreCase) { return string1.toLower().localeAwareCompare(string2.toLower()); } else { return string1.localeAwareCompare(string2); } } else { return string1.compare(string2, (sort & QDir::IgnoreCase) ? Qt::CaseInsensitive : Qt::CaseSensitive); } } bool QuaZipDirComparator::operator()(const QuaZipFileInfo &info1, const QuaZipFileInfo &info2) { QDir::SortFlags order = sort & (QDir::Name | QDir::Time | QDir::Size | QDir::Type); if ((sort & QDir::DirsFirst) == QDir::DirsFirst || (sort & QDir::DirsLast) == QDir::DirsLast) { if (info1.name.endsWith('/') && !info2.name.endsWith('/')) return (sort & QDir::DirsFirst) == QDir::DirsFirst; else if (!info1.name.endsWith('/') && info2.name.endsWith('/')) return (sort & QDir::DirsLast) == QDir::DirsLast; } bool result; int extDiff; switch (order) { case QDir::Name: result = compareStrings(info1.name, info2.name) < 0; break; case QDir::Type: extDiff = compareStrings(getExtension(info1.name), getExtension(info2.name)); if (extDiff == 0) { result = compareStrings(info1.name, info2.name) < 0; } else { result = extDiff < 0; } break; case QDir::Size: if (info1.uncompressedSize == info2.uncompressedSize) { result = compareStrings(info1.name, info2.name) < 0; } else { result = info1.uncompressedSize < info2.uncompressedSize; } break; case QDir::Time: if (info1.dateTime == info2.dateTime) { result = compareStrings(info1.name, info2.name) < 0; } else { result = info1.dateTime < info2.dateTime; } break; default: qWarning("QuaZipDirComparator(): Invalid sort mode 0x%2X", static_cast(sort)); return false; } return (sort & QDir::Reversed) ? !result : result; } template bool QuaZipDirPrivate::entryInfoList(QStringList nameFilters, QDir::Filters filter, QDir::SortFlags sort, TFileInfoList &result) const { QString basePath = simplePath(); if (!basePath.isEmpty()) basePath += "/"; int baseLength = basePath.length(); result.clear(); QuaZipDirRestoreCurrent saveCurrent(zip); if (!zip->goToFirstFile()) { return zip->getZipError() == UNZ_OK; } QDir::Filters fltr = filter; if (fltr == QDir::NoFilter) fltr = this->filter; if (fltr == QDir::NoFilter) fltr = QDir::AllEntries; QStringList nmfltr = nameFilters; if (nmfltr.isEmpty()) nmfltr = this->nameFilters; QSet dirsFound; QList list; do { QString name = zip->getCurrentFileName(); if (!name.startsWith(basePath)) continue; QString relativeName = name.mid(baseLength); if (relativeName.isEmpty()) continue; bool isDir = false; bool isReal = true; if (relativeName.contains('/')) { int indexOfSlash = relativeName.indexOf('/'); // something like "subdir/" isReal = indexOfSlash == relativeName.length() - 1; relativeName = relativeName.left(indexOfSlash + 1); if (dirsFound.contains(relativeName)) continue; isDir = true; } dirsFound.insert(relativeName); if ((fltr & QDir::Dirs) == 0 && isDir) continue; if ((fltr & QDir::Files) == 0 && !isDir) continue; if (!nmfltr.isEmpty() && !QDir::match(nmfltr, relativeName)) continue; bool ok; QuaZipFileInfo info = QuaZipDir_getFileInfo(zip, &ok, relativeName, isReal); if (!ok) { return false; } list.append(info); } while (zip->goToNextFile()); QDir::SortFlags srt = sort; if (srt == QDir::NoSort) srt = sorting; #ifdef QUAZIP_QUAZIPDIR_DEBUG qDebug("QuaZipDirPrivate::entryInfoList(): before sort:"); foreach (QuaZipFileInfo info, list) { qDebug("%s\t%s", info.name.toUtf8().constData(), info.dateTime.toString(Qt::ISODate).toUtf8().constData()); } #endif if (srt != QDir::NoSort && (srt & QDir::Unsorted) != QDir::Unsorted) { if (QuaZip::convertCaseSensitivity(caseSensitivity) == Qt::CaseInsensitive) srt |= QDir::IgnoreCase; QuaZipDirComparator lessThan(srt); #ifdef WORKBENCH_REPLACE_QT_DEPRECATED std::sort(list.begin(), list.end(), lessThan); #else qSort(list.begin(), list.end(), lessThan); #endif } QuaZipDir_convertInfoList(list, result); return true; } /// \endcond QList QuaZipDir::entryInfoList(const QStringList &nameFilters, QDir::Filters filters, QDir::SortFlags sort) const { QList result; if (d->entryInfoList(nameFilters, filters, sort, result)) return result; else return QList(); } QList QuaZipDir::entryInfoList(QDir::Filters filters, QDir::SortFlags sort) const { return entryInfoList(QStringList(), filters, sort); } QStringList QuaZipDir::entryList(const QStringList &nameFilters, QDir::Filters filters, QDir::SortFlags sort) const { QStringList result; if (d->entryInfoList(nameFilters, filters, sort, result)) return result; else return QStringList(); } QStringList QuaZipDir::entryList(QDir::Filters filters, QDir::SortFlags sort) const { return entryList(QStringList(), filters, sort); } bool QuaZipDir::exists(const QString &filePath) const { if (filePath == "/") return true; QString fileName = filePath; if (fileName.endsWith('/')) fileName.chop(1); if (fileName.contains('/')) { QFileInfo fileInfo(fileName); #ifdef QUAZIP_QUAZIPDIR_DEBUG qDebug("QuaZipDir::exists(): fileName=%s, fileInfo.fileName()=%s, " "fileInfo.path()=%s", fileName.toUtf8().constData(), fileInfo.fileName().toUtf8().constData(), fileInfo.path().toUtf8().constData()); #endif QuaZipDir dir(*this); return dir.cd(fileInfo.path()) && dir.exists(fileInfo.fileName()); } else { if (fileName == "..") { return !isRoot(); } else if (fileName == ".") { return true; } else { QStringList entries = entryList(QDir::AllEntries, QDir::NoSort); #ifdef QUAZIP_QUAZIPDIR_DEBUG qDebug("QuaZipDir::exists(): looking for %s", fileName.toUtf8().constData()); for (QStringList::const_iterator i = entries.constBegin(); i != entries.constEnd(); ++i) { qDebug("QuaZipDir::exists(): entry: %s", i->toUtf8().constData()); } #endif Qt::CaseSensitivity cs = QuaZip::convertCaseSensitivity( d->caseSensitivity); if (filePath.endsWith('/')) { return entries.contains(filePath, cs); } else { return entries.contains(fileName, cs) || entries.contains(fileName + "/", cs); } } } } bool QuaZipDir::exists() const { QDir thisDir(d->dir); return QuaZipDir(d->zip, thisDir.filePath("..")).exists(thisDir.dirName()); } QString QuaZipDir::filePath(const QString &fileName) const { return QDir(d->dir).filePath(fileName); } QDir::Filters QuaZipDir::filter() { return d->filter; } bool QuaZipDir::isRoot() const { return d->simplePath().isEmpty(); } QStringList QuaZipDir::nameFilters() const { return d->nameFilters; } QString QuaZipDir::path() const { return d->dir; } QString QuaZipDir::relativeFilePath(const QString &fileName) const { return QDir(d->dir).relativeFilePath(fileName); } void QuaZipDir::setCaseSensitivity(QuaZip::CaseSensitivity caseSensitivity) { d->caseSensitivity = caseSensitivity; } void QuaZipDir::setFilter(QDir::Filters filters) { d->filter = filters; } void QuaZipDir::setNameFilters(const QStringList &nameFilters) { d->nameFilters = nameFilters; } void QuaZipDir::setPath(const QString &path) { QString newDir = path; if (newDir == "/") { d->dir = ""; } else { if (newDir.endsWith('/')) newDir.chop(1); if (newDir.startsWith('/')) newDir = newDir.mid(1); d->dir = newDir; } } void QuaZipDir::setSorting(QDir::SortFlags sort) { d->sorting = sort; } QDir::SortFlags QuaZipDir::sorting() const { return d->sorting; } connectome-workbench-1.4.2/src/Quazip/quazipdir.h000066400000000000000000000145341360521144700220630ustar00rootroot00000000000000#ifndef QUAZIP_QUAZIPDIR_H #define QUAZIP_QUAZIPDIR_H class QuaZipDirPrivate; #include "quazip.h" #include "quazipfileinfo.h" #include #include #include /// Provides ZIP archive navigation. /** * This class is modelled after QDir, and is designed to provide similar * features for ZIP archives. * * The only significant difference from QDir is that the root path is not * '/', but an empty string since that's how the file paths are stored in * the archive. However, QuaZipDir understands the paths starting with * '/'. It is important in a few places: * * - In the cd() function. * - In the constructor. * - In the exists() function. * * Note that since ZIP uses '/' on all platforms, the '\' separator is * not supported. */ class QUAZIP_EXPORT QuaZipDir { private: QSharedDataPointer d; public: /// The copy constructor. QuaZipDir(const QuaZipDir &that); /// Constructs a QuaZipDir instance pointing to the specified directory. /** If \a dir is not specified, points to the root of the archive. The same happens if the \a dir is "/". */ QuaZipDir(QuaZip *zip, const QString &dir = QString()); /// Destructor. ~QuaZipDir(); /// The assignment operator. bool operator==(const QuaZipDir &that); /// operator!= /** \return \c true if either this and \a that use different QuaZip instances or if they point to different directories. */ inline bool operator!=(const QuaZipDir &that) {return !operator==(that);} /// operator== /** \return \c true if both this and \a that use the same QuaZip instance and point to the same directory. */ QuaZipDir& operator=(const QuaZipDir &that); /// Returns the name of the entry at the specified position. QString operator[](int pos) const; /// Returns the current case sensitivity mode. QuaZip::CaseSensitivity caseSensitivity() const; /// Changes the 'current' directory. /** * If the path starts with '/', it is interpreted as an absolute * path from the root of the archive. Otherwise, it is interpreted * as a path relative to the current directory as was set by the * previous cd() or the constructor. * * Note that the subsequent path() call will not return a path * starting with '/' in all cases. */ bool cd(const QString &dirName); /// Goes up. bool cdUp(); /// Returns the number of entries in the directory. uint count() const; /// Returns the current directory name. /** The name doesn't include the path. */ QString dirName() const; /// Returns the list of the entries in the directory. /** \param nameFilters The list of file patterns to list, uses the same syntax as QDir. \param filters The entry type filters, only Files and Dirs are accepted. \param sort Sorting mode (not supported yet). */ QList entryInfoList(const QStringList &nameFilters, QDir::Filters filters = QDir::NoFilter, QDir::SortFlags sort = QDir::NoSort) const; /// Returns the list of the entries in the directory. /** \overload The same as entryInfoList(QStringList(), filters, sort). */ QList entryInfoList(QDir::Filters filters = QDir::NoFilter, QDir::SortFlags sort = QDir::NoSort) const; /// Returns the list of the entry names in the directory. /** The same as entryInfoList(nameFilters, filters, sort), but only returns entry names. */ QStringList entryList(const QStringList &nameFilters, QDir::Filters filters = QDir::NoFilter, QDir::SortFlags sort = QDir::NoSort) const; /// Returns the list of the entry names in the directory. /** \overload The same as entryList(QStringList(), filters, sort). */ QStringList entryList(QDir::Filters filters = QDir::NoFilter, QDir::SortFlags sort = QDir::NoSort) const; /// Returns \c true if the entry with the specified name exists. /** The ".." is considered to exist if the current directory is not root. The "." and "/" are considered to always exist. Paths starting with "/" are relative to the archive root, other paths are relative to the current dir. */ bool exists(const QString &fileName) const; /// Return \c true if the directory pointed by this QuaZipDir exists. bool exists() const; /// Returns the full path to the specified file. /** Doesn't check if the file actually exists. */ QString filePath(const QString &fileName) const; /// Returns the default filter. QDir::Filters filter(); /// Returns if the QuaZipDir points to the root of the archive. /** Not that the root path is the empty string, not '/'. */ bool isRoot() const; /// Return the default name filter. QStringList nameFilters() const; /// Returns the path to the current dir. /** The path never starts with '/', and the root path is an empty string. */ QString path() const; /// Returns the path to the specified file relative to the current dir. QString relativeFilePath(const QString &fileName) const; /// Sets the default case sensitivity mode. void setCaseSensitivity(QuaZip::CaseSensitivity caseSensitivity); /// Sets the default filter. void setFilter(QDir::Filters filters); /// Sets the default name filter. void setNameFilters(const QStringList &nameFilters); /// Goes to the specified path. /** The difference from cd() is that this function never checks if the path actually exists and doesn't use relative paths, so it's possible to go to the root directory with setPath(""). Note that this function still chops the trailing and/or leading '/' and treats a single '/' as the root path (path() will still return an empty string). */ void setPath(const QString &path); /// Sets the default sorting mode. void setSorting(QDir::SortFlags sort); /// Returns the default sorting mode. QDir::SortFlags sorting() const; }; #endif // QUAZIP_QUAZIPDIR_H connectome-workbench-1.4.2/src/Quazip/quazipfile.cpp000066400000000000000000000341321360521144700225530ustar00rootroot00000000000000/* Copyright (C) 2005-2011 Sergey A. Tachenov This program 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 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser 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 See COPYING file for the full LGPL text. Original ZIP package is copyrighted by Gilles Vollant, see quazip/(un)zip.h files for details, basically it's zlib license. **/ #include "quazipfile.h" using namespace std; /// The implementation class for QuaZip. /** \internal This class contains all the private stuff for the QuaZipFile class, thus allowing to preserve binary compatibility between releases, the technique known as the Pimpl (private implementation) idiom. */ class QuaZipFilePrivate { friend class QuaZipFile; private: /// The pointer to the associated QuaZipFile instance. QuaZipFile *q; /// The QuaZip object to work with. QuaZip *zip; /// The file name. QString fileName; /// Case sensitivity mode. QuaZip::CaseSensitivity caseSensitivity; /// Whether this file is opened in the raw mode. bool raw; /// Write position to keep track of. /** QIODevice::pos() is broken for non-seekable devices, so we need our own position. */ qint64 writePos; /// Uncompressed size to write along with a raw file. quint64 uncompressedSize; /// CRC to write along with a raw file. quint32 crc; /// Whether \ref zip points to an internal QuaZip instance. /** This is true if the archive was opened by name, rather than by supplying an existing QuaZip instance. */ bool internal; /// The last error. int zipError; /// Resets \ref zipError. inline void resetZipError() const {setZipError(UNZ_OK);} /// Sets the zip error. /** This function is marked as const although it changes one field. This allows to call it from const functions that don't change anything by themselves. */ void setZipError(int zipError) const; /// The constructor for the corresponding QuaZipFile constructor. inline QuaZipFilePrivate(QuaZipFile *q): q(q), zip(NULL), internal(true), zipError(UNZ_OK) {} /// The constructor for the corresponding QuaZipFile constructor. inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName): q(q), internal(true), zipError(UNZ_OK) { zip=new QuaZip(zipName); } /// The constructor for the corresponding QuaZipFile constructor. inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName, const QString &fileName, QuaZip::CaseSensitivity cs): q(q), internal(true), zipError(UNZ_OK) { zip=new QuaZip(zipName); this->fileName=fileName; if (this->fileName.startsWith('/')) this->fileName = this->fileName.mid(1); this->caseSensitivity=cs; } /// The constructor for the QuaZipFile constructor accepting a file name. inline QuaZipFilePrivate(QuaZipFile *q, QuaZip *zip): q(q), zip(zip), internal(false), zipError(UNZ_OK) {} /// The destructor. inline ~QuaZipFilePrivate() { if (internal) delete zip; } }; QuaZipFile::QuaZipFile(): p(new QuaZipFilePrivate(this)) { } QuaZipFile::QuaZipFile(QObject *parent): QIODevice(parent), p(new QuaZipFilePrivate(this)) { } QuaZipFile::QuaZipFile(const QString& zipName, QObject *parent): QIODevice(parent), p(new QuaZipFilePrivate(this, zipName)) { } QuaZipFile::QuaZipFile(const QString& zipName, const QString& fileName, QuaZip::CaseSensitivity cs, QObject *parent): QIODevice(parent), p(new QuaZipFilePrivate(this, zipName, fileName, cs)) { } QuaZipFile::QuaZipFile(QuaZip *zip, QObject *parent): QIODevice(parent), p(new QuaZipFilePrivate(this, zip)) { } QuaZipFile::~QuaZipFile() { if (isOpen()) close(); delete p; } QString QuaZipFile::getZipName() const { return p->zip==NULL ? QString() : p->zip->getZipName(); } QuaZip *QuaZipFile::getZip() const { return p->internal ? NULL : p->zip; } QString QuaZipFile::getActualFileName()const { p->setZipError(UNZ_OK); if (p->zip == NULL || (openMode() & WriteOnly)) return QString(); QString name=p->zip->getCurrentFileName(); if(name.isNull()) p->setZipError(p->zip->getZipError()); return name; } void QuaZipFile::setZipName(const QString& zipName) { if(isOpen()) { qWarning("QuaZipFile::setZipName(): file is already open - can not set ZIP name"); return; } if(p->zip!=NULL && p->internal) delete p->zip; p->zip=new QuaZip(zipName); p->internal=true; } void QuaZipFile::setZip(QuaZip *zip) { if(isOpen()) { qWarning("QuaZipFile::setZip(): file is already open - can not set ZIP"); return; } if(p->zip!=NULL && p->internal) delete p->zip; p->zip=zip; p->fileName=QString(); p->internal=false; } void QuaZipFile::setFileName(const QString& fileName, QuaZip::CaseSensitivity cs) { if(p->zip==NULL) { qWarning("QuaZipFile::setFileName(): call setZipName() first"); return; } if(!p->internal) { qWarning("QuaZipFile::setFileName(): should not be used when not using internal QuaZip"); return; } if(isOpen()) { qWarning("QuaZipFile::setFileName(): can not set file name for already opened file"); return; } p->fileName=fileName; if (p->fileName.startsWith('/')) p->fileName = p->fileName.mid(1); p->caseSensitivity=cs; } void QuaZipFilePrivate::setZipError(int zipError) const { QuaZipFilePrivate *fakeThis = const_cast(this); // non-const fakeThis->zipError=zipError; if(zipError==UNZ_OK) q->setErrorString(QString()); else q->setErrorString(QuaZipFile::tr("ZIP/UNZIP API error %1").arg(zipError)); } bool QuaZipFile::open(OpenMode mode) { return open(mode, NULL); } bool QuaZipFile::open(OpenMode mode, int *method, int *level, bool raw, const char *password) { p->resetZipError(); if(isOpen()) { qWarning("QuaZipFile::open(): already opened"); return false; } if(mode&Unbuffered) { qWarning("QuaZipFile::open(): Unbuffered mode is not supported"); return false; } if((mode&ReadOnly)&&!(mode&WriteOnly)) { if(p->internal) { if(!p->zip->open(QuaZip::mdUnzip)) { p->setZipError(p->zip->getZipError()); return false; } if(!p->zip->setCurrentFile(p->fileName, p->caseSensitivity)) { p->setZipError(p->zip->getZipError()); p->zip->close(); return false; } } else { if(p->zip==NULL) { qWarning("QuaZipFile::open(): zip is NULL"); return false; } if(p->zip->getMode()!=QuaZip::mdUnzip) { qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d", (int)mode, (int)p->zip->getMode()); return false; } if(!p->zip->hasCurrentFile()) { qWarning("QuaZipFile::open(): zip does not have current file"); return false; } } p->setZipError(unzOpenCurrentFile3(p->zip->getUnzFile(), method, level, (int)raw, password)); if(p->zipError==UNZ_OK) { setOpenMode(mode); p->raw=raw; return true; } else return false; } qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode); return false; } bool QuaZipFile::open(OpenMode mode, const QuaZipNewInfo& info, const char *password, quint32 crc, int method, int level, bool raw, int windowBits, int memLevel, int strategy) { zip_fileinfo info_z; p->resetZipError(); if(isOpen()) { qWarning("QuaZipFile::open(): already opened"); return false; } if((mode&WriteOnly)&&!(mode&ReadOnly)) { if(p->internal) { qWarning("QuaZipFile::open(): write mode is incompatible with internal QuaZip approach"); return false; } if(p->zip==NULL) { qWarning("QuaZipFile::open(): zip is NULL"); return false; } if(p->zip->getMode()!=QuaZip::mdCreate&&p->zip->getMode()!=QuaZip::mdAppend&&p->zip->getMode()!=QuaZip::mdAdd) { qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d", (int)mode, (int)p->zip->getMode()); return false; } info_z.tmz_date.tm_year=info.dateTime.date().year(); info_z.tmz_date.tm_mon=info.dateTime.date().month() - 1; info_z.tmz_date.tm_mday=info.dateTime.date().day(); info_z.tmz_date.tm_hour=info.dateTime.time().hour(); info_z.tmz_date.tm_min=info.dateTime.time().minute(); info_z.tmz_date.tm_sec=info.dateTime.time().second(); info_z.dosDate = 0; info_z.internal_fa=(uLong)info.internalAttr; info_z.external_fa=(uLong)info.externalAttr; if (!p->zip->isDataDescriptorWritingEnabled()) zipClearFlags(p->zip->getZipFile(), ZIP_WRITE_DATA_DESCRIPTOR); p->setZipError(zipOpenNewFileInZip3_64(p->zip->getZipFile(), p->zip->getFileNameCodec()->fromUnicode(info.name).constData(), &info_z, info.extraLocal.constData(), info.extraLocal.length(), info.extraGlobal.constData(), info.extraGlobal.length(), p->zip->getCommentCodec()->fromUnicode(info.comment).constData(), method, level, (int)raw, windowBits, memLevel, strategy, password, (uLong)crc, p->zip->isZip64Enabled())); if(p->zipError==UNZ_OK) { p->writePos=0; setOpenMode(mode); p->raw=raw; if(raw) { p->crc=crc; p->uncompressedSize=info.uncompressedSize; } return true; } else return false; } qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode); return false; } bool QuaZipFile::isSequential()const { return true; } qint64 QuaZipFile::pos()const { if(p->zip==NULL) { qWarning("QuaZipFile::pos(): call setZipName() or setZip() first"); return -1; } if(!isOpen()) { qWarning("QuaZipFile::pos(): file is not open"); return -1; } if(openMode()&ReadOnly) // QIODevice::pos() is broken for sequential devices, // but thankfully bytesAvailable() returns the number of // bytes buffered, so we know how far ahead we are. return unztell(p->zip->getUnzFile()) - QIODevice::bytesAvailable(); else return p->writePos; } bool QuaZipFile::atEnd()const { if(p->zip==NULL) { qWarning("QuaZipFile::atEnd(): call setZipName() or setZip() first"); return false; } if(!isOpen()) { qWarning("QuaZipFile::atEnd(): file is not open"); return false; } if(openMode()&ReadOnly) // the same problem as with pos() return QIODevice::bytesAvailable() == 0 && unzeof(p->zip->getUnzFile())==1; else return true; } qint64 QuaZipFile::size()const { if(!isOpen()) { qWarning("QuaZipFile::atEnd(): file is not open"); return -1; } if(openMode()&ReadOnly) return p->raw?csize():usize(); else return p->writePos; } qint64 QuaZipFile::csize()const { unz_file_info64 info_z; p->setZipError(UNZ_OK); if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1; p->setZipError(unzGetCurrentFileInfo64(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0)); if(p->zipError!=UNZ_OK) return -1; return info_z.compressed_size; } qint64 QuaZipFile::usize()const { unz_file_info64 info_z; p->setZipError(UNZ_OK); if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1; p->setZipError(unzGetCurrentFileInfo64(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0)); if(p->zipError!=UNZ_OK) return -1; return info_z.uncompressed_size; } bool QuaZipFile::getFileInfo(QuaZipFileInfo *info) { if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return false; p->zip->getCurrentFileInfo(info); p->setZipError(p->zip->getZipError()); return p->zipError==UNZ_OK; } void QuaZipFile::close() { p->resetZipError(); if(p->zip==NULL||!p->zip->isOpen()) return; if(!isOpen()) { qWarning("QuaZipFile::close(): file isn't open"); return; } if(openMode()&ReadOnly) p->setZipError(unzCloseCurrentFile(p->zip->getUnzFile())); else if(openMode()&WriteOnly) if(isRaw()) p->setZipError(zipCloseFileInZipRaw64(p->zip->getZipFile(), p->uncompressedSize, p->crc)); else p->setZipError(zipCloseFileInZip(p->zip->getZipFile())); else { qWarning("Wrong open mode: %d", (int)openMode()); return; } if(p->zipError==UNZ_OK) setOpenMode(QIODevice::NotOpen); else return; if(p->internal) { p->zip->close(); p->setZipError(p->zip->getZipError()); } } qint64 QuaZipFile::readData(char *data, qint64 maxSize) { p->setZipError(UNZ_OK); qint64 bytesRead=unzReadCurrentFile(p->zip->getUnzFile(), data, (unsigned)maxSize); if (bytesRead < 0) { p->setZipError((int) bytesRead); return -1; } return bytesRead; } qint64 QuaZipFile::writeData(const char* data, qint64 maxSize) { p->setZipError(ZIP_OK); p->setZipError(zipWriteInFileInZip(p->zip->getZipFile(), data, (uint)maxSize)); if(p->zipError!=ZIP_OK) return -1; else { p->writePos+=maxSize; return maxSize; } } QString QuaZipFile::getFileName() const { return p->fileName; } QuaZip::CaseSensitivity QuaZipFile::getCaseSensitivity() const { return p->caseSensitivity; } bool QuaZipFile::isRaw() const { return p->raw; } int QuaZipFile::getZipError() const { return p->zipError; } qint64 QuaZipFile::bytesAvailable() const { return size() - pos(); } connectome-workbench-1.4.2/src/Quazip/quazipfile.h000066400000000000000000000471061360521144700222250ustar00rootroot00000000000000#ifndef QUA_ZIPFILE_H #define QUA_ZIPFILE_H /* Copyright (C) 2005-2011 Sergey A. Tachenov This program 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 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser 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 See COPYING file for the full LGPL text. Original ZIP package is copyrighted by Gilles Vollant, see quazip/(un)zip.h files for details, basically it's zlib license. **/ #include #include "quazip_global.h" #include "quazip.h" #include "quazipnewinfo.h" class QuaZipFilePrivate; /// A file inside ZIP archive. /** \class QuaZipFile quazipfile.h * This is the most interesting class. Not only it provides C++ * interface to the ZIP/UNZIP package, but also integrates it with Qt by * subclassing QIODevice. This makes possible to access files inside ZIP * archive using QTextStream or QDataStream, for example. Actually, this * is the main purpose of the whole QuaZIP library. * * You can either use existing QuaZip instance to create instance of * this class or pass ZIP archive file name to this class, in which case * it will create internal QuaZip object. See constructors' descriptions * for details. Writing is only possible with the existing instance. * * Note that due to the underlying library's limitation it is not * possible to use multiple QuaZipFile instances to open several files * in the same archive at the same time. If you need to write to * multiple files in parallel, then you should write to temporary files * first, then pack them all at once when you have finished writing. If * you need to read multiple files inside the same archive in parallel, * you should extract them all into a temporary directory first. * * \section quazipfile-sequential Sequential or random-access? * * At the first thought, QuaZipFile has fixed size, the start and the * end and should be therefore considered random-access device. But * there is one major obstacle to making it random-access: ZIP/UNZIP API * does not support seek() operation and the only way to implement it is * through reopening the file and re-reading to the required position, * but this is prohibitively slow. * * Therefore, QuaZipFile is considered to be a sequential device. This * has advantage of availability of the ungetChar() operation (QIODevice * does not implement it properly for non-sequential devices unless they * support seek()). Disadvantage is a somewhat strange behaviour of the * size() and pos() functions. This should be kept in mind while using * this class. * **/ class QUAZIP_EXPORT QuaZipFile: public QIODevice { friend class QuaZipFilePrivate; Q_OBJECT private: QuaZipFilePrivate *p; // these are not supported nor implemented QuaZipFile(const QuaZipFile& that); QuaZipFile& operator=(const QuaZipFile& that); protected: /// Implementation of the QIODevice::readData(). qint64 readData(char *data, qint64 maxSize); /// Implementation of the QIODevice::writeData(). qint64 writeData(const char *data, qint64 maxSize); public: /// Constructs a QuaZipFile instance. /** You should use setZipName() and setFileName() or setZip() before * trying to call open() on the constructed object. **/ QuaZipFile(); /// Constructs a QuaZipFile instance. /** \a parent argument specifies this object's parent object. * * You should use setZipName() and setFileName() or setZip() before * trying to call open() on the constructed object. **/ QuaZipFile(QObject *parent); /// Constructs a QuaZipFile instance. /** \a parent argument specifies this object's parent object and \a * zipName specifies ZIP archive file name. * * You should use setFileName() before trying to call open() on the * constructed object. * * QuaZipFile constructed by this constructor can be used for read * only access. Use QuaZipFile(QuaZip*,QObject*) for writing. **/ QuaZipFile(const QString& zipName, QObject *parent =NULL); /// Constructs a QuaZipFile instance. /** \a parent argument specifies this object's parent object, \a * zipName specifies ZIP archive file name and \a fileName and \a cs * specify a name of the file to open inside archive. * * QuaZipFile constructed by this constructor can be used for read * only access. Use QuaZipFile(QuaZip*,QObject*) for writing. * * \sa QuaZip::setCurrentFile() **/ QuaZipFile(const QString& zipName, const QString& fileName, QuaZip::CaseSensitivity cs =QuaZip::csDefault, QObject *parent =NULL); /// Constructs a QuaZipFile instance. /** \a parent argument specifies this object's parent object. * * \a zip is the pointer to the existing QuaZip object. This * QuaZipFile object then can be used to read current file in the * \a zip or to write to the file inside it. * * \warning Using this constructor for reading current file can be * tricky. Let's take the following example: * \code * QuaZip zip("archive.zip"); * zip.open(QuaZip::mdUnzip); * zip.setCurrentFile("file-in-archive"); * QuaZipFile file(&zip); * file.open(QIODevice::ReadOnly); * // ok, now we can read from the file * file.read(somewhere, some); * zip.setCurrentFile("another-file-in-archive"); // oops... * QuaZipFile anotherFile(&zip); * anotherFile.open(QIODevice::ReadOnly); * anotherFile.read(somewhere, some); // this is still ok... * file.read(somewhere, some); // and this is NOT * \endcode * So, what exactly happens here? When we change current file in the * \c zip archive, \c file that references it becomes invalid * (actually, as far as I understand ZIP/UNZIP sources, it becomes * closed, but QuaZipFile has no means to detect it). * * Summary: do not close \c zip object or change its current file as * long as QuaZipFile is open. Even better - use another constructors * which create internal QuaZip instances, one per object, and * therefore do not cause unnecessary trouble. This constructor may * be useful, though, if you already have a QuaZip instance and do * not want to access several files at once. Good example: * \code * QuaZip zip("archive.zip"); * zip.open(QuaZip::mdUnzip); * // first, we need some information about archive itself * QByteArray comment=zip.getComment(); * // and now we are going to access files inside it * QuaZipFile file(&zip); * for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) { * file.open(QIODevice::ReadOnly); * // do something cool with file here * file.close(); // do not forget to close! * } * zip.close(); * \endcode **/ QuaZipFile(QuaZip *zip, QObject *parent =NULL); /// Destroys a QuaZipFile instance. /** Closes file if open, destructs internal QuaZip object (if it * exists and \em is internal, of course). **/ virtual ~QuaZipFile(); /// Returns the ZIP archive file name. /** If this object was created by passing QuaZip pointer to the * constructor, this function will return that QuaZip's file name * (or null string if that object does not have file name yet). * * Otherwise, returns associated ZIP archive file name or null * string if there are no name set yet. * * \sa setZipName() getFileName() **/ QString getZipName()const; /// Returns a pointer to the associated QuaZip object. /** Returns \c NULL if there is no associated QuaZip or it is * internal (so you will not mess with it). **/ QuaZip* getZip()const; /// Returns file name. /** This function returns file name you passed to this object either * by using * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*) * or by calling setFileName(). Real name of the file may differ in * case if you used case-insensitivity. * * Returns null string if there is no file name set yet. This is the * case when this QuaZipFile operates on the existing QuaZip object * (constructor QuaZipFile(QuaZip*,QObject*) or setZip() was used). * * \sa getActualFileName **/ QString getFileName() const; /// Returns case sensitivity of the file name. /** This function returns case sensitivity argument you passed to * this object either by using * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*) * or by calling setFileName(). * * Returns unpredictable value if getFileName() returns null string * (this is the case when you did not used setFileName() or * constructor above). * * \sa getFileName **/ QuaZip::CaseSensitivity getCaseSensitivity() const; /// Returns the actual file name in the archive. /** This is \em not a ZIP archive file name, but a name of file inside * archive. It is not necessary the same name that you have passed * to the * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*), * setFileName() or QuaZip::setCurrentFile() - this is the real file * name inside archive, so it may differ in case if the file name * search was case-insensitive. * * Equivalent to calling getCurrentFileName() on the associated * QuaZip object. Returns null string if there is no associated * QuaZip object or if it does not have a current file yet. And this * is the case if you called setFileName() but did not open the * file yet. So this is perfectly fine: * \code * QuaZipFile file("somezip.zip"); * file.setFileName("somefile"); * QString name=file.getName(); // name=="somefile" * QString actual=file.getActualFileName(); // actual is null string * file.open(QIODevice::ReadOnly); * QString actual=file.getActualFileName(); // actual can be "SoMeFiLe" on Windows * \endcode * * \sa getZipName(), getFileName(), QuaZip::CaseSensitivity **/ QString getActualFileName()const; /// Sets the ZIP archive file name. /** Automatically creates internal QuaZip object and destroys * previously created internal QuaZip object, if any. * * Will do nothing if this file is already open. You must close() it * first. **/ void setZipName(const QString& zipName); /// Returns \c true if the file was opened in raw mode. /** If the file is not open, the returned value is undefined. * * \sa open(OpenMode,int*,int*,bool,const char*) **/ bool isRaw() const; /// Binds to the existing QuaZip instance. /** This function destroys internal QuaZip object, if any, and makes * this QuaZipFile to use current file in the \a zip object for any * further operations. See QuaZipFile(QuaZip*,QObject*) for the * possible pitfalls. * * Will do nothing if the file is currently open. You must close() * it first. **/ void setZip(QuaZip *zip); /// Sets the file name. /** Will do nothing if at least one of the following conditions is * met: * - ZIP name has not been set yet (getZipName() returns null * string). * - This QuaZipFile is associated with external QuaZip. In this * case you should call that QuaZip's setCurrentFile() function * instead! * - File is already open so setting the name is meaningless. * * \sa QuaZip::setCurrentFile **/ void setFileName(const QString& fileName, QuaZip::CaseSensitivity cs =QuaZip::csDefault); /// Opens a file for reading. /** Returns \c true on success, \c false otherwise. * Call getZipError() to get error code. * * \note Since ZIP/UNZIP API provides buffered reading only, * QuaZipFile does not support unbuffered reading. So do not pass * QIODevice::Unbuffered flag in \a mode, or open will fail. **/ virtual bool open(OpenMode mode); /// Opens a file for reading. /** \overload * Argument \a password specifies a password to decrypt the file. If * it is NULL then this function behaves just like open(OpenMode). **/ inline bool open(OpenMode mode, const char *password) {return open(mode, NULL, NULL, false, password);} /// Opens a file for reading. /** \overload * Argument \a password specifies a password to decrypt the file. * * An integers pointed by \a method and \a level will receive codes * of the compression method and level used. See unzip.h. * * If raw is \c true then no decompression is performed. * * \a method should not be \c NULL. \a level can be \c NULL if you * don't want to know the compression level. **/ bool open(OpenMode mode, int *method, int *level, bool raw, const char *password =NULL); /// Opens a file for writing. /** \a info argument specifies information about file. It should at * least specify a correct file name. Also, it is a good idea to * specify correct timestamp (by default, current time will be * used). See QuaZipNewInfo. * * The \a password argument specifies the password for crypting. Pass NULL * if you don't need any crypting. The \a crc argument was supposed * to be used for crypting too, but then it turned out that it's * false information, so you need to set it to 0 unless you want to * use the raw mode (see below). * * Arguments \a method and \a level specify compression method and * level. The only method supported is Z_DEFLATED, but you may also * specify 0 for no compression. If all of the files in the archive * use both method 0 and either level 0 is explicitly specified or * data descriptor writing is disabled with * QuaZip::setDataDescriptorWritingEnabled(), then the * resulting archive is supposed to be compatible with the 1.0 ZIP * format version, should you need that. Except for this, \a level * has no other effects with method 0. * * If \a raw is \c true, no compression is performed. In this case, * \a crc and uncompressedSize field of the \a info are required. * * Arguments \a windowBits, \a memLevel, \a strategy provide zlib * algorithms tuning. See deflateInit2() in zlib. **/ bool open(OpenMode mode, const QuaZipNewInfo& info, const char *password =NULL, quint32 crc =0, int method =Z_DEFLATED, int level =Z_DEFAULT_COMPRESSION, bool raw =false, int windowBits =-MAX_WBITS, int memLevel =DEF_MEM_LEVEL, int strategy =Z_DEFAULT_STRATEGY); /// Returns \c true, but \ref quazipfile-sequential "beware"! virtual bool isSequential()const; /// Returns current position in the file. /** Implementation of the QIODevice::pos(). When reading, this * function is a wrapper to the ZIP/UNZIP unztell(), therefore it is * unable to keep track of the ungetChar() calls (which is * non-virtual and therefore is dangerous to reimplement). So if you * are using ungetChar() feature of the QIODevice, this function * reports incorrect value until you get back characters which you * ungot. * * When writing, pos() returns number of bytes already written * (uncompressed unless you use raw mode). * * \note Although * \ref quazipfile-sequential "QuaZipFile is a sequential device" * and therefore pos() should always return zero, it does not, * because it would be misguiding. Keep this in mind. * * This function returns -1 if the file or archive is not open. * * Error code returned by getZipError() is not affected by this * function call. **/ virtual qint64 pos()const; /// Returns \c true if the end of file was reached. /** This function returns \c false in the case of error. This means * that you called this function on either not open file, or a file * in the not open archive or even on a QuaZipFile instance that * does not even have QuaZip instance associated. Do not do that * because there is no means to determine whether \c false is * returned because of error or because end of file was reached. * Well, on the other side you may interpret \c false return value * as "there is no file open to check for end of file and there is * no end of file therefore". * * When writing, this function always returns \c true (because you * are always writing to the end of file). * * Error code returned by getZipError() is not affected by this * function call. **/ virtual bool atEnd()const; /// Returns file size. /** This function returns csize() if the file is open for reading in * raw mode, usize() if it is open for reading in normal mode and * pos() if it is open for writing. * * Returns -1 on error, call getZipError() to get error code. * * \note This function returns file size despite that * \ref quazipfile-sequential "QuaZipFile is considered to be sequential device", * for which size() should return bytesAvailable() instead. But its * name would be very misguiding otherwise, so just keep in mind * this inconsistence. **/ virtual qint64 size()const; /// Returns compressed file size. /** Equivalent to calling getFileInfo() and then getting * compressedSize field, but more convenient and faster. * * File must be open for reading before calling this function. * * Returns -1 on error, call getZipError() to get error code. **/ qint64 csize()const; /// Returns uncompressed file size. /** Equivalent to calling getFileInfo() and then getting * uncompressedSize field, but more convenient and faster. See * getFileInfo() for a warning. * * File must be open for reading before calling this function. * * Returns -1 on error, call getZipError() to get error code. **/ qint64 usize()const; /// Gets information about current file. /** This function does the same thing as calling * QuaZip::getCurrentFileInfo() on the associated QuaZip object, * but you can not call getCurrentFileInfo() if the associated * QuaZip is internal (because you do not have access to it), while * you still can call this function in that case. * * File must be open for reading before calling this function. * * Returns \c false in the case of an error. **/ bool getFileInfo(QuaZipFileInfo *info); /// Closes the file. /** Call getZipError() to determine if the close was successful. **/ virtual void close(); /// Returns the error code returned by the last ZIP/UNZIP API call. int getZipError() const; /// Returns the number of bytes available for reading. virtual qint64 bytesAvailable() const; }; #endif connectome-workbench-1.4.2/src/Quazip/quazipfileinfo.cpp000066400000000000000000000017731360521144700234340ustar00rootroot00000000000000#include "quazipfileinfo.h" static QFile::Permissions permissionsFromExternalAttr(quint32 externalAttr) { quint32 uPerm = (externalAttr & 0xFFFF0000u) >> 16; QFile::Permissions perm = 0; if ((uPerm & 0400) != 0) perm |= QFile::ReadOwner; if ((uPerm & 0200) != 0) perm |= QFile::WriteOwner; if ((uPerm & 0100) != 0) perm |= QFile::ExeOwner; if ((uPerm & 0040) != 0) perm |= QFile::ReadGroup; if ((uPerm & 0020) != 0) perm |= QFile::WriteGroup; if ((uPerm & 0010) != 0) perm |= QFile::ExeGroup; if ((uPerm & 0004) != 0) perm |= QFile::ReadOther; if ((uPerm & 0002) != 0) perm |= QFile::WriteOther; if ((uPerm & 0001) != 0) perm |= QFile::ExeOther; return perm; } QFile::Permissions QuaZipFileInfo::getPermissions() const { return permissionsFromExternalAttr(externalAttr); } QFile::Permissions QuaZipFileInfo64::getPermissions() const { return permissionsFromExternalAttr(externalAttr); } connectome-workbench-1.4.2/src/Quazip/quazipfileinfo.h000066400000000000000000000062771360521144700231050ustar00rootroot00000000000000#ifndef QUA_ZIPFILEINFO_H #define QUA_ZIPFILEINFO_H /* Copyright (C) 2005-2011 Sergey A. Tachenov This program 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 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser 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 See COPYING file for the full LGPL text. Original ZIP package is copyrighted by Gilles Vollant, see quazip/(un)zip.h files for details, basically it's zlib license. **/ #include #include #include #include "quazip_global.h" /// Information about a file inside archive. /** Call QuaZip::getCurrentFileInfo() or QuaZipFile::getFileInfo() to * fill this structure. */ struct QUAZIP_EXPORT QuaZipFileInfo { /// File name. QString name; /// Version created by. quint16 versionCreated; /// Version needed to extract. quint16 versionNeeded; /// General purpose flags. quint16 flags; /// Compression method. quint16 method; /// Last modification date and time. QDateTime dateTime; /// CRC. quint32 crc; /// Compressed file size. quint32 compressedSize; /// Uncompressed file size. quint32 uncompressedSize; /// Disk number start. quint16 diskNumberStart; /// Internal file attributes. quint16 internalAttr; /// External file attributes. quint32 externalAttr; /// Comment. QString comment; /// Extra field. QByteArray extra; /// Get the file permissions. /** Returns the high 16 bits of external attributes converted to QFile::Permissions. */ QFile::Permissions getPermissions() const; }; /// Information about a file inside archive (with zip64 support). /** Call QuaZip::getCurrentFileInfo() or QuaZipFile::getFileInfo() to * fill this structure. */ struct QUAZIP_EXPORT QuaZipFileInfo64 { /// File name. QString name; /// Version created by. quint16 versionCreated; /// Version needed to extract. quint16 versionNeeded; /// General purpose flags. quint16 flags; /// Compression method. quint16 method; /// Last modification date and time. QDateTime dateTime; /// CRC. quint32 crc; /// Compressed file size. quint64 compressedSize; /// Uncompressed file size. quint64 uncompressedSize; /// Disk number start. quint16 diskNumberStart; /// Internal file attributes. quint16 internalAttr; /// External file attributes. quint32 externalAttr; /// Comment. QString comment; /// Extra field. QByteArray extra; /// Get the file permissions. /** Returns the high 16 bits of external attributes converted to QFile::Permissions. */ QFile::Permissions getPermissions() const; }; #endif connectome-workbench-1.4.2/src/Quazip/quazipnewinfo.cpp000066400000000000000000000055021360521144700233000ustar00rootroot00000000000000/* Copyright (C) 2005-2011 Sergey A. Tachenov This program 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 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser 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 See COPYING file for the full LGPL text. Original ZIP package is copyrighted by Gilles Vollant, see quazip/(un)zip.h files for details, basically it's zlib license. */ #include #include "quazipnewinfo.h" static void QuaZipNewInfo_setPermissions(QuaZipNewInfo *info, QFile::Permissions perm, bool isDir) { quint32 uPerm = isDir ? 0040000 : 0100000; if ((perm & QFile::ReadOwner) != 0) uPerm |= 0400; if ((perm & QFile::WriteOwner) != 0) uPerm |= 0200; if ((perm & QFile::ExeOwner) != 0) uPerm |= 0100; if ((perm & QFile::ReadGroup) != 0) uPerm |= 0040; if ((perm & QFile::WriteGroup) != 0) uPerm |= 0020; if ((perm & QFile::ExeGroup) != 0) uPerm |= 0010; if ((perm & QFile::ReadOther) != 0) uPerm |= 0004; if ((perm & QFile::WriteOther) != 0) uPerm |= 0002; if ((perm & QFile::ExeOther) != 0) uPerm |= 0001; info->externalAttr = (info->externalAttr & ~0xFFFF0000u) | (uPerm << 16); } QuaZipNewInfo::QuaZipNewInfo(const QString& name): name(name), dateTime(QDateTime::currentDateTime()), internalAttr(0), externalAttr(0) { } QuaZipNewInfo::QuaZipNewInfo(const QString& name, const QString& file): name(name), internalAttr(0), externalAttr(0) { QFileInfo info(file); QDateTime lm = info.lastModified(); if (!info.exists()) { dateTime = QDateTime::currentDateTime(); } else { dateTime = lm; QuaZipNewInfo_setPermissions(this, info.permissions(), info.isDir()); } } void QuaZipNewInfo::setFileDateTime(const QString& file) { QFileInfo info(file); QDateTime lm = info.lastModified(); if (info.exists()) dateTime = lm; } void QuaZipNewInfo::setFilePermissions(const QString &file) { QFileInfo info = QFileInfo(file); QFile::Permissions perm = info.permissions(); QuaZipNewInfo_setPermissions(this, perm, info.isDir()); } void QuaZipNewInfo::setPermissions(QFile::Permissions permissions) { QuaZipNewInfo_setPermissions(this, permissions, name.endsWith('/')); } connectome-workbench-1.4.2/src/Quazip/quazipnewinfo.h000066400000000000000000000117151360521144700227500ustar00rootroot00000000000000#ifndef QUA_ZIPNEWINFO_H #define QUA_ZIPNEWINFO_H /* Copyright (C) 2005-2011 Sergey A. Tachenov This program 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 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser 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 See COPYING file for the full LGPL text. Original ZIP package is copyrighted by Gilles Vollant, see quazip/(un)zip.h files for details, basically it's zlib license. **/ #include #include #include #include "quazip_global.h" /// Information about a file to be created. /** This structure holds information about a file to be created inside * ZIP archive. At least name should be set to something correct before * passing this structure to * QuaZipFile::open(OpenMode,const QuaZipNewInfo&,int,int,bool). * * Zip64 support of this structure is slightly limited: in the raw mode (when * a pre-compressed file is written into a ZIP file as-is), it is necessary * to specify the uncompressed file size and the appropriate field is 32 bit. * Since the raw mode is used extremely rare, there is no real need to have * a separate QuaZipNewInfo64 structure like QuaZipFileInfo64. It may be added * in the future though, if there is a demand for the raw mode with zip64 * archives. **/ struct QUAZIP_EXPORT QuaZipNewInfo { /// File name. /** This field holds file name inside archive, including path relative * to archive root. **/ QString name; /// File timestamp. /** This is the last file modification date and time. Will be stored * in the archive central directory. It is a good practice to set it * to the source file timestamp instead of archive creating time. Use * setFileDateTime() or QuaZipNewInfo(const QString&, const QString&). **/ QDateTime dateTime; /// File internal attributes. quint16 internalAttr; /// File external attributes. /** The highest 16 bits contain Unix file permissions and type (dir or file). The constructor QuaZipNewInfo(const QString&, const QString&) takes permissions from the provided file. */ quint32 externalAttr; /// File comment. /** Will be encoded using QuaZip::getCommentCodec(). **/ QString comment; /// File local extra field. QByteArray extraLocal; /// File global extra field. QByteArray extraGlobal; /// Uncompressed file size. /** This is only needed if you are using raw file zipping mode, i. e. * adding precompressed file in the zip archive. **/ ulong uncompressedSize; /// Constructs QuaZipNewInfo instance. /** Initializes name with \a name, dateTime with current date and * time. Attributes are initialized with zeros, comment and extra * field with null values. **/ QuaZipNewInfo(const QString& name); /// Constructs QuaZipNewInfo instance. /** Initializes name with \a name. Timestamp and permissions are taken * from the specified file. If the \a file does not exists or its timestamp * is inaccessible (e. g. you do not have read permission for the * directory file in), uses current time and zero permissions. Other attributes are * initialized with zeros, comment and extra field with null values. * * \sa setFileDateTime() **/ QuaZipNewInfo(const QString& name, const QString& file); /// Sets the file timestamp from the existing file. /** Use this function to set the file timestamp from the existing * file. Use it like this: * \code * QuaZipFile zipFile(&zip); * QFile file("file-to-add"); * file.open(QIODevice::ReadOnly); * QuaZipNewInfo info("file-name-in-archive"); * info.setFileDateTime("file-to-add"); // take the timestamp from file * zipFile.open(QIODevice::WriteOnly, info); * \endcode * * This function does not change dateTime if some error occured (e. g. * file is inaccessible). **/ void setFileDateTime(const QString& file); /// Sets the file permissions from the existing file. /** Takes permissions from the file and sets the high 16 bits of external attributes. Uses QFileInfo to get permissions on all platforms. */ void setFilePermissions(const QString &file); /// Sets the file permissions. /** Modifies the highest 16 bits of external attributes. The type part is set to dir if the name ends with a slash, and to regular file otherwise. */ void setPermissions(QFile::Permissions permissions); }; #endif connectome-workbench-1.4.2/src/Quazip/unzip.c000066400000000000000000002171151360521144700212130ustar00rootroot00000000000000/* unzip.c -- IO for uncompress .zip files using zlib Version 1.1, February 14h, 2010 part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications of Unzip for Zip64 Copyright (C) 2007-2008 Even Rouault Modifications for Zip64 support on both zip and unzip Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) For more info read MiniZip_info.txt ------------------------------------------------------------------------------------ Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of compatibility with older software. The following is from the original crypt.c. Code woven in by Terry Thorsen 1/2003. Copyright (c) 1990-2000 Info-ZIP. All rights reserved. See the accompanying file LICENSE, version 2000-Apr-09 or later (the contents of which are also included in zip.h) for terms of use. If, for some reason, all these files are missing, the Info-ZIP license also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] The encryption/decryption parts of this source code (as opposed to the non-echoing password parts) were originally written in Europe. The whole source package can be freely distributed, including from the USA. (Prior to January 2000, re-export from the US was a violation of US law.) This encryption code is a direct transcription of the algorithm from Roger Schlafly, described by Phil Katz in the file appnote.txt. This file (appnote.txt) is distributed with the PKZIP program (even in the version without encryption capabilities). ------------------------------------------------------------------------------------ Changes in unzip.c 2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz* 2007-2008 - Even Rouault - Remove old C style function prototypes 2007-2008 - Even Rouault - Add unzip support for ZIP64 Copyright (C) 2007-2008 Even Rouault Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G should only read the compressed/uncompressed size from the Zip64 format if the size from normal header was 0xFFFFFFFF Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required) Patch created by Daniel Borca Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson */ #include #include #include #include "zlib.h" #if (ZLIB_VERNUM < 0x1270) typedef uLongf z_crc_t; #endif #include "unzip.h" #ifdef STDC # include # include # include #endif #ifdef NO_ERRNO_H extern int errno; #else # include #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ #ifndef CASESENSITIVITYDEFAULT_NO # if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) # define CASESENSITIVITYDEFAULT_NO # endif #endif #ifndef UNZ_BUFSIZE #define UNZ_BUFSIZE (16384) #endif #ifndef UNZ_MAXFILENAMEINZIP #define UNZ_MAXFILENAMEINZIP (256) #endif #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif #ifndef TRYFREE # define TRYFREE(p) {if (p) free(p);} #endif #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) const char unz_copyright[] = " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; /* unz_file_info_interntal contain internal info about a file in zipfile*/ typedef struct unz_file_info64_internal_s { ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */ } unz_file_info64_internal; /* file_in_zip_read_info_s contain internal information about a file in zipfile, when reading and decompress it */ typedef struct { char *read_buffer; /* internal buffer for compressed data */ z_stream stream; /* zLib stream structure for inflate */ #ifdef HAVE_BZIP2 bz_stream bstream; /* bzLib stream structure for bziped */ #endif ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ uLong stream_initialised; /* flag set if stream structure is initialised*/ ZPOS64_T offset_local_extrafield;/* offset of the local extra field */ uInt size_local_extrafield;/* size of the local extra field */ ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/ ZPOS64_T total_out_64; uLong crc32; /* crc32 of all data uncompressed */ uLong crc32_wait; /* crc32 we must obtain after decompress all */ ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ zlib_filefunc64_32_def z_filefunc; voidpf filestream; /* io structore of the zipfile */ uLong compression_method; /* compression method (0==store) */ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ int raw; } file_in_zip64_read_info_s; /* unz64_s contain internal information about the zipfile */ typedef struct { zlib_filefunc64_32_def z_filefunc; int is64bitOpenFunction; voidpf filestream; /* io structore of the zipfile */ unz_global_info64 gi; /* public global information */ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ ZPOS64_T num_file; /* number of the current file in the zipfile*/ ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ ZPOS64_T central_pos; /* position of the beginning of the central dir*/ ZPOS64_T size_central_dir; /* size of the central directory */ ZPOS64_T offset_central_dir; /* offset of start of central directory with respect to the starting disk number */ unz_file_info64 cur_file_info; /* public info about the current file in zip*/ unz_file_info64_internal cur_file_info_internal; /* private info about it*/ file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current file if we are decompressing it */ int encrypted; int isZip64; # ifndef NOUNCRYPT unsigned long keys[3]; /* keys defining the pseudo-random sequence */ const z_crc_t FAR * pcrc_32_tab; # endif } unz64_s; #ifndef NOUNCRYPT #include "crypt.h" #endif /* =========================================================================== Read a byte from a gz_stream; update next_in and avail_in. Return EOF for end of file. IN assertion: the stream s has been sucessfully opened for reading. */ local int unz64local_getByte OF(( const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)); local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) { unsigned char c; int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); if (err==1) { *pi = (int)c; return UNZ_OK; } else { if (ZERROR64(*pzlib_filefunc_def,filestream)) return UNZ_ERRNO; else return UNZ_EOF; } } /* =========================================================================== Reads a long in LSB order from the given gz_stream. Sets */ local int unz64local_getShort OF(( const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX) { uLong x ; int i = 0; int err; err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((uLong)i)<<8; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } local int unz64local_getLong OF(( const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX) { uLong x ; int i = 0; int err; err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((uLong)i)<<8; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((uLong)i)<<16; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<24; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } local int unz64local_getLong64 OF(( const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) { ZPOS64_T x ; int i = 0; int err; err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x = (ZPOS64_T)i; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<8; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<16; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<24; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<32; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<40; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<48; if (err==UNZ_OK) err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); x |= ((ZPOS64_T)i)<<56; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } /* My own strcmpi / strcasecmp */ local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) { for (;;) { char c1=*(fileName1++); char c2=*(fileName2++); if ((c1>='a') && (c1<='z')) c1 -= 0x20; if ((c2>='a') && (c2<='z')) c2 -= 0x20; if (c1=='\0') return ((c2=='\0') ? 0 : -1); if (c2=='\0') return 1; if (c1c2) return 1; } } #ifdef CASESENSITIVITYDEFAULT_NO #define CASESENSITIVITYDEFAULTVALUE 2 #else #define CASESENSITIVITYDEFAULTVALUE 1 #endif #ifndef STRCMPCASENOSENTIVEFUNCTION #define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal #endif /* Compare two filename (fileName1,fileName2). If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi or strcasecmp) If iCaseSenisivity = 0, case sensitivity is defaut of your operating system (like 1 on Unix, 2 on Windows) */ extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, const char* fileName2, int iCaseSensitivity) { if (iCaseSensitivity==0) iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; if (iCaseSensitivity==1) return strcmp(fileName1,fileName2); return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); } #ifndef BUFREADCOMMENT #define BUFREADCOMMENT (0x400) #endif /* Locate the Central directory of a zipfile (at the end, just before the global comment) */ local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ ZPOS64_T uPosFound=0; if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) return 0; uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return 0; uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) break; if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) { uPosFound = uReadPos+i; break; } if (uPosFound!=0) break; } TRYFREE(buf); return uPosFound; } /* Locate the Central directory 64 of a zipfile (at the end, just before the global comment) */ local ZPOS64_T unz64local_SearchCentralDir64 OF(( const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ ZPOS64_T uPosFound=0; uLong uL; ZPOS64_T relativeOffset; if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) return 0; uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return 0; uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) break; if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) { uPosFound = uReadPos+i; break; } if (uPosFound!=0) break; } TRYFREE(buf); if (uPosFound == 0) return 0; /* Zip64 end of central directory locator */ if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) return 0; /* the signature, already checked */ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) return 0; /* number of the disk with the start of the zip64 end of central directory */ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) return 0; if (uL != 0) return 0; /* relative offset of the zip64 end of central directory record */ if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK) return 0; /* total number of disks */ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) return 0; if (uL != 1) return 0; /* Goto end of central directory record */ if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) return 0; /* the signature */ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) return 0; if (uL != 0x06064b50) return 0; return relativeOffset; } /* Open a Zip file. path contain the full pathname (by example, on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer "zlib/zlib114.zip". If the zipfile cannot be opened (file doesn't exist or in not valid), the return value is NULL. Else, the return value is a unzFile Handle, usable with other function of this unzip package. */ local unzFile unzOpenInternal (voidpf file, zlib_filefunc64_32_def* pzlib_filefunc64_32_def, int is64bitOpenFunction) { unz64_s us; unz64_s *s; ZPOS64_T central_pos; uLong uL; uLong number_disk; /* number of the current dist, used for spaning ZIP, unsupported, always 0*/ uLong number_disk_with_CD; /* number the the disk with central dir, used for spaning ZIP, unsupported, always 0*/ ZPOS64_T number_entry_CD; /* total number of entries in the central dir (same than number_entry on nospan) */ int err=UNZ_OK; if (unz_copyright[0]!=' ') return NULL; us.z_filefunc.zseek32_file = NULL; us.z_filefunc.ztell32_file = NULL; if (pzlib_filefunc64_32_def==NULL) fill_qiodevice64_filefunc(&us.z_filefunc.zfile_func64); else us.z_filefunc = *pzlib_filefunc64_32_def; us.is64bitOpenFunction = is64bitOpenFunction; us.filestream = ZOPEN64(us.z_filefunc, file, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING); if (us.filestream==NULL) return NULL; central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream); if (central_pos) { uLong uS; ZPOS64_T uL64; us.isZip64 = 1; if (ZSEEK64(us.z_filefunc, us.filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) err=UNZ_ERRNO; /* the signature, already checked */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; /* size of zip64 end of central directory record */ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK) err=UNZ_ERRNO; /* version made by */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) err=UNZ_ERRNO; /* version needed to extract */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) err=UNZ_ERRNO; /* number of this disk */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) err=UNZ_ERRNO; /* number of the disk with the start of the central directory */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) err=UNZ_ERRNO; /* total number of entries in the central directory on this disk */ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) err=UNZ_ERRNO; /* total number of entries in the central directory */ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) err=UNZ_ERRNO; if ((number_entry_CD!=us.gi.number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=UNZ_BADZIPFILE; /* size of the central directory */ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) err=UNZ_ERRNO; /* offset of start of central directory with respect to the starting disk number */ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) err=UNZ_ERRNO; us.gi.size_comment = 0; } else { central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream); if (central_pos==0) err=UNZ_ERRNO; us.isZip64 = 0; if (ZSEEK64(us.z_filefunc, us.filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) err=UNZ_ERRNO; /* the signature, already checked */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; /* number of this disk */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) err=UNZ_ERRNO; /* number of the disk with the start of the central directory */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) err=UNZ_ERRNO; /* total number of entries in the central dir on this disk */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; us.gi.number_entry = uL; /* total number of entries in the central dir */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; number_entry_CD = uL; if ((number_entry_CD!=us.gi.number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=UNZ_BADZIPFILE; /* size of the central directory */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; us.size_central_dir = uL; /* offset of start of central directory with respect to the starting disk number */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; us.offset_central_dir = uL; /* zipfile comment length */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) err=UNZ_ERRNO; } if ((central_pospfile_in_zip_read!=NULL) unzCloseCurrentFile(file); ZCLOSE64(s->z_filefunc, s->filestream); TRYFREE(s); return UNZ_OK; } /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info) { unz64_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; *pglobal_info=s->gi; return UNZ_OK; } extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32) { unz64_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; /* to do : check if number_entry is not truncated */ pglobal_info32->number_entry = (uLong)s->gi.number_entry; pglobal_info32->size_comment = s->gi.size_comment; return UNZ_OK; } /* Translate date/time from Dos format to tm_unz (readable more easilty) */ local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) { ZPOS64_T uDate; uDate = (ZPOS64_T)(ulDosDate>>16); ptm->tm_mday = (uInt)(uDate&0x1f) ; ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; } /* Get Info about the current file in the zipfile, with internal only info */ local int unz64local_GetCurrentFileInfoInternal OF((unzFile file, unz_file_info64 *pfile_info, unz_file_info64_internal *pfile_info_internal, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize)); local int unz64local_GetCurrentFileInfoInternal (unzFile file, unz_file_info64 *pfile_info, unz_file_info64_internal *pfile_info_internal, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize) { unz64_s* s; unz_file_info64 file_info; unz_file_info64_internal file_info_internal; int err=UNZ_OK; uLong uMagic; ZPOS64_T llSeek=0; uLong uL; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; if (ZSEEK64(s->z_filefunc, s->filestream, s->pos_in_central_dir+s->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET)!=0) err=UNZ_ERRNO; /* we check the magic */ if (err==UNZ_OK) { if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) err=UNZ_ERRNO; else if (uMagic!=0x02014b50) err=UNZ_BADZIPFILE; } if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) err=UNZ_ERRNO; unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) err=UNZ_ERRNO; file_info.compressed_size = uL; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) err=UNZ_ERRNO; file_info.uncompressed_size = uL; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) err=UNZ_ERRNO; /* relative offset of local header */ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) err=UNZ_ERRNO; file_info_internal.offset_curfile = uL; llSeek+=file_info.size_filename; if ((err==UNZ_OK) && (szFileName!=NULL)) { uLong uSizeRead ; if (file_info.size_filename0) && (fileNameBufferSize>0)) if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) err=UNZ_ERRNO; llSeek -= uSizeRead; } /* Read extrafield */ if ((err==UNZ_OK) && (extraField!=NULL)) { ZPOS64_T uSizeRead ; if (file_info.size_file_extraz_filefunc, s->filestream,llSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) llSeek=0; else err=UNZ_ERRNO; } if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead) err=UNZ_ERRNO; llSeek += file_info.size_file_extra - (uLong)uSizeRead; } else llSeek += file_info.size_file_extra; if ((err==UNZ_OK) && (file_info.size_file_extra != 0)) { uLong acc = 0; /* since lSeek now points to after the extra field we need to move back */ llSeek -= file_info.size_file_extra; if (llSeek!=0) { if (ZSEEK64(s->z_filefunc, s->filestream,llSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) llSeek=0; else err=UNZ_ERRNO; } while(acc < file_info.size_file_extra) { uLong headerId; uLong dataSize; if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK) err=UNZ_ERRNO; /* ZIP64 extra fields */ if (headerId == 0x0001) { uLong uL; if(file_info.uncompressed_size == (ZPOS64_T)(unsigned long)-1) { if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) err=UNZ_ERRNO; } if(file_info.compressed_size == (ZPOS64_T)(unsigned long)-1) { if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) err=UNZ_ERRNO; } if(file_info_internal.offset_curfile == (ZPOS64_T)(unsigned long)-1) { /* Relative Header offset */ if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) err=UNZ_ERRNO; } if(file_info.disk_num_start == (unsigned long)-1) { /* Disk Start Number */ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) err=UNZ_ERRNO; } } else { if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0) err=UNZ_ERRNO; } acc += 2 + 2 + dataSize; } } if ((err==UNZ_OK) && (szComment!=NULL)) { uLong uSizeRead ; if (file_info.size_file_commentz_filefunc, s->filestream,llSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) llSeek=0; else err=UNZ_ERRNO; } if ((file_info.size_file_comment>0) && (commentBufferSize>0)) if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) err=UNZ_ERRNO; llSeek+=file_info.size_file_comment - uSizeRead; } else llSeek+=file_info.size_file_comment; if ((err==UNZ_OK) && (pfile_info!=NULL)) *pfile_info=file_info; if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) *pfile_info_internal=file_info_internal; return err; } /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file, unz_file_info64 * pfile_info, char * szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char* szComment, uLong commentBufferSize) { return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, szFileName,fileNameBufferSize, extraField,extraFieldBufferSize, szComment,commentBufferSize); } extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, unz_file_info * pfile_info, char * szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char* szComment, uLong commentBufferSize) { int err; unz_file_info64 file_info64; err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, szFileName,fileNameBufferSize, extraField,extraFieldBufferSize, szComment,commentBufferSize); if (err==UNZ_OK && pfile_info != NULL) { pfile_info->version = file_info64.version; pfile_info->version_needed = file_info64.version_needed; pfile_info->flag = file_info64.flag; pfile_info->compression_method = file_info64.compression_method; pfile_info->dosDate = file_info64.dosDate; pfile_info->crc = file_info64.crc; pfile_info->size_filename = file_info64.size_filename; pfile_info->size_file_extra = file_info64.size_file_extra; pfile_info->size_file_comment = file_info64.size_file_comment; pfile_info->disk_num_start = file_info64.disk_num_start; pfile_info->internal_fa = file_info64.internal_fa; pfile_info->external_fa = file_info64.external_fa; pfile_info->tmu_date = file_info64.tmu_date, pfile_info->compressed_size = (uLong)file_info64.compressed_size; pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; } return err; } /* Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ extern int ZEXPORT unzGoToFirstFile (unzFile file) { int err=UNZ_OK; unz64_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; s->pos_in_central_dir=s->offset_central_dir; s->num_file=0; err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } /* Set the current file of the zipfile to the next file. return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ extern int ZEXPORT unzGoToNextFile (unzFile file) { unz64_s* s; int err; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ if (s->num_file+1==s->gi.number_entry) return UNZ_END_OF_LIST_OF_FILE; s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; s->num_file++; err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } /* Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzipStringFileNameCompare return value : UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found */ extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) { unz64_s* s; int err; /* We remember the 'current' position in the file so that we can jump * back there if we fail. */ unz_file_info64 cur_file_infoSaved; unz_file_info64_internal cur_file_info_internalSaved; ZPOS64_T num_fileSaved; ZPOS64_T pos_in_central_dirSaved; if (file==NULL) return UNZ_PARAMERROR; if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) return UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; /* Save the current state */ num_fileSaved = s->num_file; pos_in_central_dirSaved = s->pos_in_central_dir; cur_file_infoSaved = s->cur_file_info; cur_file_info_internalSaved = s->cur_file_info_internal; err = unzGoToFirstFile(file); while (err == UNZ_OK) { char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; err = unzGetCurrentFileInfo64(file,NULL, szCurrentFileName,sizeof(szCurrentFileName)-1, NULL,0,NULL,0); if (err == UNZ_OK) { if (unzStringFileNameCompare(szCurrentFileName, szFileName,iCaseSensitivity)==0) return UNZ_OK; err = unzGoToNextFile(file); } } /* We failed, so restore the state of the 'current file' to where we * were. */ s->num_file = num_fileSaved ; s->pos_in_central_dir = pos_in_central_dirSaved ; s->cur_file_info = cur_file_infoSaved; s->cur_file_info_internal = cur_file_info_internalSaved; return err; } /* /////////////////////////////////////////// // Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) // I need random access // // Further optimization could be realized by adding an ability // to cache the directory in memory. The goal being a single // comprehensive file read to put the file I need in a memory. */ /* typedef struct unz_file_pos_s { ZPOS64_T pos_in_zip_directory; // offset in file ZPOS64_T num_of_file; // # of file } unz_file_pos; */ extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) { unz64_s* s; if (file==NULL || file_pos==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; file_pos->pos_in_zip_directory = s->pos_in_central_dir; file_pos->num_of_file = s->num_file; return UNZ_OK; } extern int ZEXPORT unzGetFilePos( unzFile file, unz_file_pos* file_pos) { unz64_file_pos file_pos64; int err = unzGetFilePos64(file,&file_pos64); if (err==UNZ_OK) { file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; file_pos->num_of_file = (uLong)file_pos64.num_of_file; } return err; } extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) { unz64_s* s; int err; if (file==NULL || file_pos==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; /* jump to the right spot */ s->pos_in_central_dir = file_pos->pos_in_zip_directory; s->num_file = file_pos->num_of_file; /* set the current file */ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); /* return results */ s->current_file_ok = (err == UNZ_OK); return err; } extern int ZEXPORT unzGoToFilePos( unzFile file, unz_file_pos* file_pos) { unz64_file_pos file_pos64; if (file_pos == NULL) return UNZ_PARAMERROR; file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; file_pos64.num_of_file = file_pos->num_of_file; return unzGoToFilePos64(file,&file_pos64); } /* Unzip Helper Functions - should be here? */ /*///////////////////////////////////////// */ /* Read the local header of the current zipfile Check the coherency of the local header and info in the end of central directory about this file store in *piSizeVar the size of extra info in local header (filename and size of extra field data) */ local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar, ZPOS64_T * poffset_local_extrafield, uInt * psize_local_extrafield) { uLong uMagic,uData,uFlags; uLong size_filename; uLong size_extra_field; int err=UNZ_OK; *piSizeVar = 0; *poffset_local_extrafield = 0; *psize_local_extrafield = 0; if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (err==UNZ_OK) { if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) err=UNZ_ERRNO; else if (uMagic!=0x04034b50) err=UNZ_BADZIPFILE; } if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) err=UNZ_ERRNO; /* else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) err=UNZ_BADZIPFILE; */ if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) err=UNZ_BADZIPFILE; if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && /* #ifdef HAVE_BZIP2 */ (s->cur_file_info.compression_method!=Z_BZIP2ED) && /* #endif */ (s->cur_file_info.compression_method!=Z_DEFLATED)) err=UNZ_BADZIPFILE; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ err=UNZ_ERRNO; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ err=UNZ_ERRNO; else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ err=UNZ_ERRNO; else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) err=UNZ_ERRNO; else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) err=UNZ_BADZIPFILE; *piSizeVar += (uInt)size_filename; if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) err=UNZ_ERRNO; *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename; *psize_local_extrafield = (uInt)size_extra_field; *piSizeVar += (uInt)size_extra_field; return err; } /* Open for reading data the current file in the zipfile. If there is no error and the file is opened, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, int* level, int raw, const char* password) { int err=UNZ_OK; uInt iSizeVar; unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ uInt size_local_extrafield; /* size of the local extra field */ # ifndef NOUNCRYPT char source[12]; # else if (password != NULL) return UNZ_PARAMERROR; # endif if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) return UNZ_PARAMERROR; if (s->pfile_in_zip_read != NULL) unzCloseCurrentFile(file); if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) return UNZ_BADZIPFILE; pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s)); if (pfile_in_zip_read_info==NULL) return UNZ_INTERNALERROR; pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; pfile_in_zip_read_info->pos_local_extrafield=0; pfile_in_zip_read_info->raw=raw; if (pfile_in_zip_read_info->read_buffer==NULL) { TRYFREE(pfile_in_zip_read_info); return UNZ_INTERNALERROR; } pfile_in_zip_read_info->stream_initialised=0; if (method!=NULL) *method = (int)s->cur_file_info.compression_method; if (level!=NULL) { *level = 6; switch (s->cur_file_info.flag & 0x06) { case 6 : *level = 1; break; case 4 : *level = 2; break; case 2 : *level = 9; break; } } if ((s->cur_file_info.compression_method!=0) && /* #ifdef HAVE_BZIP2 */ (s->cur_file_info.compression_method!=Z_BZIP2ED) && /* #endif */ (s->cur_file_info.compression_method!=Z_DEFLATED)) err=UNZ_BADZIPFILE; pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; pfile_in_zip_read_info->crc32=0; pfile_in_zip_read_info->total_out_64=0; pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; pfile_in_zip_read_info->filestream=s->filestream; pfile_in_zip_read_info->z_filefunc=s->z_filefunc; pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; pfile_in_zip_read_info->stream.total_out = 0; if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw)) { #ifdef HAVE_BZIP2 pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; pfile_in_zip_read_info->bstream.bzfree = (free_func)0; pfile_in_zip_read_info->bstream.opaque = (voidpf)0; pfile_in_zip_read_info->bstream.state = (voidpf)0; pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; pfile_in_zip_read_info->stream.zfree = (free_func)0; pfile_in_zip_read_info->stream.opaque = (voidpf)0; pfile_in_zip_read_info->stream.next_in = (voidpf)0; pfile_in_zip_read_info->stream.avail_in = 0; err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); if (err == Z_OK) pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; else { TRYFREE(pfile_in_zip_read_info); return err; } #else pfile_in_zip_read_info->raw=1; #endif } else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) { pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; pfile_in_zip_read_info->stream.zfree = (free_func)0; pfile_in_zip_read_info->stream.opaque = (voidpf)0; pfile_in_zip_read_info->stream.next_in = 0; pfile_in_zip_read_info->stream.avail_in = 0; err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); if (err == Z_OK) pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; else { TRYFREE(pfile_in_zip_read_info); return err; } /* windowBits is passed < 0 to tell that there is no zlib header. * Note that in this case inflate *requires* an extra "dummy" byte * after the compressed stream in order to complete decompression and * return Z_STREAM_END. * In unzip, i don't wait absolutely Z_STREAM_END because I known the * size of both compressed and uncompressed data */ } pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size ; pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size ; pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar; pfile_in_zip_read_info->stream.avail_in = (uInt)0; s->pfile_in_zip_read = pfile_in_zip_read_info; s->encrypted = 0; # ifndef NOUNCRYPT if (password != NULL) { int i; s->pcrc_32_tab = get_crc_table(); init_keys(password,s->keys,s->pcrc_32_tab); if (ZSEEK64(s->z_filefunc, s->filestream, s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile, SEEK_SET)!=0) return UNZ_INTERNALERROR; if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12) return UNZ_INTERNALERROR; for (i = 0; i<12; i++) zdecode(s->keys,s->pcrc_32_tab,source[i]); s->pfile_in_zip_read->pos_in_zipfile+=12; s->encrypted=1; } # endif return UNZ_OK; } extern int ZEXPORT unzOpenCurrentFile (unzFile file) { return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); } extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password) { return unzOpenCurrentFile3(file, NULL, NULL, 0, password); } extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw) { return unzOpenCurrentFile3(file, method, level, raw, NULL); } /** Addition for GDAL : START */ extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; s=(unz64_s*)file; if (file==NULL) return 0; /*UNZ_PARAMERROR; */ pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return 0; /*UNZ_PARAMERROR; */ return pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile; } /** Addition for GDAL : END */ /* Read bytes from the current file. buf contain buffer where data must be copied len the size of buf. return the number of byte copied if somes bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) { int err=UNZ_OK; uInt iRead = 0; unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->read_buffer == NULL) return UNZ_END_OF_LIST_OF_FILE; if (len==0) return 0; pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; pfile_in_zip_read_info->stream.avail_out = (uInt)len; if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && (!(pfile_in_zip_read_info->raw))) pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_uncompressed; if ((len>pfile_in_zip_read_info->rest_read_compressed+ pfile_in_zip_read_info->stream.avail_in) && (pfile_in_zip_read_info->raw)) pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_compressed+ pfile_in_zip_read_info->stream.avail_in; while (pfile_in_zip_read_info->stream.avail_out>0) { if ((pfile_in_zip_read_info->stream.avail_in==0) && (pfile_in_zip_read_info->rest_read_compressed>0)) { uInt uReadThis = UNZ_BUFSIZE; if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; if (uReadThis == 0) return UNZ_EOF; if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (ZREAD64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->read_buffer, uReadThis)!=uReadThis) return UNZ_ERRNO; # ifndef NOUNCRYPT if(s->encrypted) { uInt i; for(i=0;iread_buffer[i] = zdecode(s->keys,s->pcrc_32_tab, pfile_in_zip_read_info->read_buffer[i]); } # endif pfile_in_zip_read_info->pos_in_zipfile += uReadThis; pfile_in_zip_read_info->rest_read_compressed-=uReadThis; pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->read_buffer; pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; } if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) { uInt uDoCopy,i ; if ((pfile_in_zip_read_info->stream.avail_in == 0) && (pfile_in_zip_read_info->rest_read_compressed == 0)) return (iRead==0) ? UNZ_EOF : iRead; if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in) uDoCopy = pfile_in_zip_read_info->stream.avail_out ; else uDoCopy = pfile_in_zip_read_info->stream.avail_in ; for (i=0;istream.next_out+i) = *(pfile_in_zip_read_info->stream.next_in+i); pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy; pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, pfile_in_zip_read_info->stream.next_out, uDoCopy); pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; pfile_in_zip_read_info->stream.avail_in -= uDoCopy; pfile_in_zip_read_info->stream.avail_out -= uDoCopy; pfile_in_zip_read_info->stream.next_out += uDoCopy; pfile_in_zip_read_info->stream.next_in += uDoCopy; pfile_in_zip_read_info->stream.total_out += uDoCopy; iRead += uDoCopy; } else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) { #ifdef HAVE_BZIP2 uLong uTotalOutBefore,uTotalOutAfter; const Bytef *bufBefore; uLong uOutThis; pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in; pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; pfile_in_zip_read_info->bstream.total_in_hi32 = 0; pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out; pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; pfile_in_zip_read_info->bstream.total_out_hi32 = 0; uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32; bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out; err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32; uOutThis = uTotalOutAfter-uTotalOutBefore; pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in; pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out; pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; if (err==BZ_STREAM_END) return (iRead==0) ? UNZ_EOF : iRead; if (err!=BZ_OK) break; #endif } /* end Z_BZIP2ED */ else { ZPOS64_T uTotalOutBefore,uTotalOutAfter; const Bytef *bufBefore; ZPOS64_T uOutThis; int flush=Z_SYNC_FLUSH; uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; bufBefore = pfile_in_zip_read_info->stream.next_out; /* if ((pfile_in_zip_read_info->rest_read_uncompressed == pfile_in_zip_read_info->stream.avail_out) && (pfile_in_zip_read_info->rest_read_compressed == 0)) flush = Z_FINISH; */ err=inflate(&pfile_in_zip_read_info->stream,flush); if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) err = Z_DATA_ERROR; uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; uOutThis = uTotalOutAfter-uTotalOutBefore; pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); if (err==Z_STREAM_END) return (iRead==0) ? UNZ_EOF : iRead; if (err!=Z_OK) break; } } if (err==Z_OK) return iRead; return err; } /* Give the current position in uncompressed data */ extern z_off_t ZEXPORT unztell (unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; return (z_off_t)pfile_in_zip_read_info->stream.total_out; } extern ZPOS64_T ZEXPORT unztell64 (unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return (ZPOS64_T)-1; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return (ZPOS64_T)-1; return pfile_in_zip_read_info->total_out_64; } /* return 1 if the end of file was reached, 0 elsewhere */ extern int ZEXPORT unzeof (unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->rest_read_uncompressed == 0) return 1; else return 0; } /* Read extra field from the current file (opened by unzOpenCurrentFile) This is the local-header version of the extra field (sometimes, there is more info in the local-header version than in the central-header) if buf==NULL, it return the size of the local extra field that can be read if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. the return value is the number of bytes copied in buf, or (if <0) the error code */ extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; uInt read_now; ZPOS64_T size_to_read; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; size_to_read = (pfile_in_zip_read_info->size_local_extrafield - pfile_in_zip_read_info->pos_local_extrafield); if (buf==NULL) return (int)size_to_read; if (len>size_to_read) read_now = (uInt)size_to_read; else read_now = (uInt)len ; if (read_now==0) return 0; if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->offset_local_extrafield + pfile_in_zip_read_info->pos_local_extrafield, ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (ZREAD64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, buf,read_now)!=read_now) return UNZ_ERRNO; return (int)read_now; } /* Close the file in zip opened with unzipOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ extern int ZEXPORT unzCloseCurrentFile (unzFile file) { int err=UNZ_OK; unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && (!pfile_in_zip_read_info->raw)) { if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) err=UNZ_CRCERROR; } TRYFREE(pfile_in_zip_read_info->read_buffer); pfile_in_zip_read_info->read_buffer = NULL; if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) inflateEnd(&pfile_in_zip_read_info->stream); #ifdef HAVE_BZIP2 else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); #endif pfile_in_zip_read_info->stream_initialised = 0; TRYFREE(pfile_in_zip_read_info); s->pfile_in_zip_read=NULL; return err; } /* Get the global comment string of the ZipFile, in the szComment buffer. uSizeBuf is the size of the szComment buffer. return the number of byte copied or an error code <0 */ extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf) { unz64_s* s; uLong uReadThis ; if (file==NULL) return (int)UNZ_PARAMERROR; s=(unz64_s*)file; uReadThis = uSizeBuf; if (uReadThis>s->gi.size_comment) uReadThis = s->gi.size_comment; if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (uReadThis>0) { *szComment='\0'; if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) return UNZ_ERRNO; } if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) *(szComment+s->gi.size_comment)='\0'; return (int)uReadThis; } /* Additions by RX '2004 */ extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) { unz64_s* s; if (file==NULL) return 0; /*UNZ_PARAMERROR; */ s=(unz64_s*)file; if (!s->current_file_ok) return 0; if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) if (s->num_file==s->gi.number_entry) return 0; return s->pos_in_central_dir; } extern uLong ZEXPORT unzGetOffset (unzFile file) { ZPOS64_T offset64; if (file==NULL) return 0; /*UNZ_PARAMERROR; */ offset64 = unzGetOffset64(file); return (uLong)offset64; } extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) { unz64_s* s; int err; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; s->pos_in_central_dir = pos; s->num_file = s->gi.number_entry; /* hack */ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) { return unzSetOffset64(file,pos); } connectome-workbench-1.4.2/src/Quazip/unzip.h000066400000000000000000000406071360521144700212200ustar00rootroot00000000000000/* unzip.h -- IO for uncompress .zip files using zlib Version 1.1, February 14h, 2010 part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications of Unzip for Zip64 Copyright (C) 2007-2008 Even Rouault Modifications for Zip64 support on both zip and unzip Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) For more info read MiniZip_info.txt --------------------------------------------------------------------------------- Condition of use and distribution are the same than zlib : This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. --------------------------------------------------------------------------------- Changes See header of unzip64.c */ #ifndef _unz64_H #define _unz64_H #ifdef __cplusplus extern "C" { #endif #ifndef _ZLIB_H #include "zlib.h" #endif #ifndef _ZLIBIOAPI_H #include "ioapi.h" #endif #ifdef HAVE_BZIP2 #include "bzlib.h" #endif #define Z_BZIP2ED 12 #if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) /* like the STRICT of WIN32, we define a pointer that cannot be converted from (void*) without cast */ typedef struct TagunzFile__ { int unused; } unzFile__; typedef unzFile__ *unzFile; #else typedef voidp unzFile; #endif #define UNZ_OK (0) #define UNZ_END_OF_LIST_OF_FILE (-100) #define UNZ_ERRNO (Z_ERRNO) #define UNZ_EOF (0) #define UNZ_PARAMERROR (-102) #define UNZ_BADZIPFILE (-103) #define UNZ_INTERNALERROR (-104) #define UNZ_CRCERROR (-105) /* tm_unz contain date/time info */ typedef struct tm_unz_s { uInt tm_sec; /* seconds after the minute - [0,59] */ uInt tm_min; /* minutes after the hour - [0,59] */ uInt tm_hour; /* hours since midnight - [0,23] */ uInt tm_mday; /* day of the month - [1,31] */ uInt tm_mon; /* months since January - [0,11] */ uInt tm_year; /* years - [1980..2044] */ } tm_unz; /* unz_global_info structure contain global data about the ZIPfile These data comes from the end of central dir */ typedef struct unz_global_info64_s { ZPOS64_T number_entry; /* total number of entries in the central dir on this disk */ uLong size_comment; /* size of the global comment of the zipfile */ } unz_global_info64; typedef struct unz_global_info_s { uLong number_entry; /* total number of entries in the central dir on this disk */ uLong size_comment; /* size of the global comment of the zipfile */ } unz_global_info; /* unz_file_info contain information about a file in the zipfile */ typedef struct unz_file_info64_s { uLong version; /* version made by 2 bytes */ uLong version_needed; /* version needed to extract 2 bytes */ uLong flag; /* general purpose bit flag 2 bytes */ uLong compression_method; /* compression method 2 bytes */ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ uLong crc; /* crc-32 4 bytes */ ZPOS64_T compressed_size; /* compressed size 8 bytes */ ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ uLong size_filename; /* filename length 2 bytes */ uLong size_file_extra; /* extra field length 2 bytes */ uLong size_file_comment; /* file comment length 2 bytes */ uLong disk_num_start; /* disk number start 2 bytes */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ tm_unz tmu_date; } unz_file_info64; typedef struct unz_file_info_s { uLong version; /* version made by 2 bytes */ uLong version_needed; /* version needed to extract 2 bytes */ uLong flag; /* general purpose bit flag 2 bytes */ uLong compression_method; /* compression method 2 bytes */ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ uLong crc; /* crc-32 4 bytes */ uLong compressed_size; /* compressed size 4 bytes */ uLong uncompressed_size; /* uncompressed size 4 bytes */ uLong size_filename; /* filename length 2 bytes */ uLong size_file_extra; /* extra field length 2 bytes */ uLong size_file_comment; /* file comment length 2 bytes */ uLong disk_num_start; /* disk number start 2 bytes */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ tm_unz tmu_date; } unz_file_info; extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, const char* fileName2, int iCaseSensitivity)); /* Compare two filename (fileName1,fileName2). If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi or strcasecmp) If iCaseSenisivity = 0, case sensitivity is defaut of your operating system (like 1 on Unix, 2 on Windows) */ extern unzFile ZEXPORT unzOpen OF((voidpf file)); extern unzFile ZEXPORT unzOpen64 OF((voidpf file)); /* Open a Zip file. path contain the full pathname (by example, on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". If the zipfile cannot be opened (file don't exist or in not valid), the return value is NULL. Else, the return value is a unzFile Handle, usable with other function of this unzip package. the "64" function take a const void* pointer, because the path is just the value passed to the open64_file_func callback. Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* does not describe the reality */ extern unzFile ZEXPORT unzOpen2 OF((voidpf file, zlib_filefunc_def* pzlib_filefunc_def)); /* Open a Zip file, like unzOpen, but provide a set of file low level API for read/write the zip file (see ioapi.h) */ extern unzFile ZEXPORT unzOpen2_64 OF((voidpf file, zlib_filefunc64_def* pzlib_filefunc_def)); /* Open a Zip file, like unz64Open, but provide a set of file low level API for read/write the zip file (see ioapi.h) */ extern int ZEXPORT unzClose OF((unzFile file)); /* Close a ZipFile opened with unzipOpen. If there is files inside the .Zip opened with unzOpenCurrentFile (see later), these files MUST be closed with unzipCloseCurrentFile before call unzipClose. return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, unz_global_info *pglobal_info)); extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, unz_global_info64 *pglobal_info)); /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalComment OF((unzFile file, char *szComment, uLong uSizeBuf)); /* Get the global comment string of the ZipFile, in the szComment buffer. uSizeBuf is the size of the szComment buffer. return the number of byte copied or an error code <0 */ /***************************************************************************/ /* Unzip package allow you browse the directory of the zipfile */ extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); /* Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ extern int ZEXPORT unzGoToNextFile OF((unzFile file)); /* Set the current file of the zipfile to the next file. return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ extern int ZEXPORT unzLocateFile OF((unzFile file, const char *szFileName, int iCaseSensitivity)); /* Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzStringFileNameCompare return value : UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found */ /* ****************************************** */ /* Ryan supplied functions */ /* unz_file_info contain information about a file in the zipfile */ typedef struct unz_file_pos_s { uLong pos_in_zip_directory; /* offset in zip file directory */ uLong num_of_file; /* # of file */ } unz_file_pos; extern int ZEXPORT unzGetFilePos( unzFile file, unz_file_pos* file_pos); extern int ZEXPORT unzGoToFilePos( unzFile file, unz_file_pos* file_pos); typedef struct unz64_file_pos_s { ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ ZPOS64_T num_of_file; /* # of file */ } unz64_file_pos; extern int ZEXPORT unzGetFilePos64( unzFile file, unz64_file_pos* file_pos); extern int ZEXPORT unzGoToFilePos64( unzFile file, const unz64_file_pos* file_pos); /* ****************************************** */ extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, unz_file_info64 *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize)); extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, unz_file_info *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize)); /* Get Info about the current file if pfile_info!=NULL, the *pfile_info structure will contain somes info about the current file if szFileName!=NULL, the filemane string will be copied in szFileName (fileNameBufferSize is the size of the buffer) if extraField!=NULL, the extra field information will be copied in extraField (extraFieldBufferSize is the size of the buffer). This is the Central-header version of the extra field if szComment!=NULL, the comment string of the file will be copied in szComment (commentBufferSize is the size of the buffer) */ /** Addition for GDAL : START */ extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); /** Addition for GDAL : END */ /***************************************************************************/ /* for reading the content of the current zipfile, you can open it, read data from it, and close it (you can close it before reading all the file) */ extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); /* Open for reading data the current file in the zipfile. If there is no error, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, const char* password)); /* Open for reading data the current file in the zipfile. password is a crypting password If there is no error, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, int* method, int* level, int raw)); /* Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 *method will receive method of compression, *level will receive level of compression note : you can set level parameter as NULL (if you did not want known level, but you CANNOT set method parameter as NULL */ extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, int* method, int* level, int raw, const char* password)); /* Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 *method will receive method of compression, *level will receive level of compression note : you can set level parameter as NULL (if you did not want known level, but you CANNOT set method parameter as NULL */ extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); /* Close the file in zip opened with unzOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ extern int ZEXPORT unzReadCurrentFile OF((unzFile file, voidp buf, unsigned len)); /* Read bytes from the current file (opened by unzOpenCurrentFile) buf contain buffer where data must be copied len the size of buf. return the number of byte copied if somes bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ extern z_off_t ZEXPORT unztell OF((unzFile file)); extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); /* Give the current position in uncompressed data */ extern int ZEXPORT unzeof OF((unzFile file)); /* return 1 if the end of file was reached, 0 elsewhere */ extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, voidp buf, unsigned len)); /* Read extra field from the current file (opened by unzOpenCurrentFile) This is the local-header version of the extra field (sometimes, there is more info in the local-header version than in the central-header) if buf==NULL, it return the size of the local extra field if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. the return value is the number of bytes copied in buf, or (if <0) the error code */ /***************************************************************************/ /* Get the current file offset */ extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); extern uLong ZEXPORT unzGetOffset (unzFile file); /* Set the current file offset */ extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); #ifdef __cplusplus } #endif #endif /* _unz64_H */ connectome-workbench-1.4.2/src/Quazip/zip.c000066400000000000000000002111131360521144700206400ustar00rootroot00000000000000/* zip.c -- IO on .zip files using zlib Version 1.1, February 14h, 2010 part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications for Zip64 support Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) For more info read MiniZip_info.txt Changes Oct-2009 - Mathias Svensson - Remove old C style function prototypes Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions. Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data It is used when recreting zip archive with RAW when deleting items from a zip. ZIP64 data is automaticly added to items that needs it, and existing ZIP64 data need to be removed. Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required) Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer */ #include #include #include #include #include "zlib.h" #if (ZLIB_VERNUM < 0x1270) typedef uLongf z_crc_t; #endif #include "zip.h" #ifdef STDC # include # include # include #endif #ifdef NO_ERRNO_H extern int errno; #else # include #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ #ifndef VERSIONMADEBY # define VERSIONMADEBY (0x031e) /* best for standard pkware crypt */ #endif #ifndef Z_BUFSIZE #define Z_BUFSIZE (64*1024) /* (16384) */ #endif #ifndef Z_MAXFILENAMEINZIP #define Z_MAXFILENAMEINZIP (256) #endif #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif #ifndef TRYFREE # define TRYFREE(p) {if (p) free(p);} #endif /* #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) */ /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ /* NOT sure that this work on ALL platform */ #define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32)) #ifndef SEEK_CUR #define SEEK_CUR 1 #endif #ifndef SEEK_END #define SEEK_END 2 #endif #ifndef SEEK_SET #define SEEK_SET 0 #endif #ifndef DEF_MEM_LEVEL #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif #endif const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; #define SIZEDATA_INDATABLOCK (4096-(4*4)) #define LOCALHEADERMAGIC (0x04034b50) #define DESCRIPTORHEADERMAGIC (0x08074b50) #define CENTRALHEADERMAGIC (0x02014b50) #define ENDHEADERMAGIC (0x06054b50) #define ZIP64ENDHEADERMAGIC (0x6064b50) #define ZIP64ENDLOCHEADERMAGIC (0x7064b50) #define FLAG_LOCALHEADER_OFFSET (0x06) #define CRC_LOCALHEADER_OFFSET (0x0e) #define SIZECENTRALHEADER (0x2e) /* 46 */ typedef struct linkedlist_datablock_internal_s { struct linkedlist_datablock_internal_s* next_datablock; uLong avail_in_this_block; uLong filled_in_this_block; uLong unused; /* for future use and alignement */ unsigned char data[SIZEDATA_INDATABLOCK]; } linkedlist_datablock_internal; typedef struct linkedlist_data_s { linkedlist_datablock_internal* first_block; linkedlist_datablock_internal* last_block; } linkedlist_data; typedef struct { z_stream stream; /* zLib stream structure for inflate */ #ifdef HAVE_BZIP2 bz_stream bstream; /* bzLib stream structure for bziped */ #endif int stream_initialised; /* 1 is stream is initialised */ uInt pos_in_buffered_data; /* last written byte in buffered_data */ ZPOS64_T pos_local_header; /* offset of the local header of the file currenty writing */ char* central_header; /* central header data for the current file */ uLong size_centralExtra; uLong size_centralheader; /* size of the central header for cur file */ uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */ uLong flag; /* flag of the file currently writing */ int method; /* compression method of file currenty wr.*/ int raw; /* 1 for directly writing raw data */ Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ uLong dosDate; uLong crc32; int encrypt; int zip64; /* Add ZIP64 extened information in the extra field */ ZPOS64_T pos_zip64extrainfo; ZPOS64_T totalCompressedData; ZPOS64_T totalUncompressedData; #ifndef NOCRYPT unsigned long keys[3]; /* keys defining the pseudo-random sequence */ const z_crc_t FAR * pcrc_32_tab; int crypt_header_size; #endif } curfile64_info; typedef struct { zlib_filefunc64_32_def z_filefunc; voidpf filestream; /* io structore of the zipfile */ linkedlist_data central_dir;/* datablock with central dir in construction*/ int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ curfile64_info ci; /* info on the file curretly writing */ ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ ZPOS64_T add_position_when_writting_offset; ZPOS64_T number_entry; #ifndef NO_ADDFILEINEXISTINGZIP char *globalcomment; #endif unsigned flags; } zip64_internal; #ifndef NOCRYPT #define INCLUDECRYPTINGCODE_IFCRYPTALLOWED #include "crypt.h" #endif local linkedlist_datablock_internal* allocate_new_datablock() { linkedlist_datablock_internal* ldi; ldi = (linkedlist_datablock_internal*) ALLOC(sizeof(linkedlist_datablock_internal)); if (ldi!=NULL) { ldi->next_datablock = NULL ; ldi->filled_in_this_block = 0 ; ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; } return ldi; } local void free_datablock(linkedlist_datablock_internal* ldi) { while (ldi!=NULL) { linkedlist_datablock_internal* ldinext = ldi->next_datablock; TRYFREE(ldi); ldi = ldinext; } } local void init_linkedlist(linkedlist_data* ll) { ll->first_block = ll->last_block = NULL; } local void free_linkedlist(linkedlist_data* ll) { free_datablock(ll->first_block); ll->first_block = ll->last_block = NULL; } local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) { linkedlist_datablock_internal* ldi; const unsigned char* from_copy; if (ll==NULL) return ZIP_INTERNALERROR; if (ll->last_block == NULL) { ll->first_block = ll->last_block = allocate_new_datablock(); if (ll->first_block == NULL) return ZIP_INTERNALERROR; } ldi = ll->last_block; from_copy = (unsigned char*)buf; while (len>0) { uInt copy_this; uInt i; unsigned char* to_copy; if (ldi->avail_in_this_block==0) { ldi->next_datablock = allocate_new_datablock(); if (ldi->next_datablock == NULL) return ZIP_INTERNALERROR; ldi = ldi->next_datablock ; ll->last_block = ldi; } if (ldi->avail_in_this_block < len) copy_this = (uInt)ldi->avail_in_this_block; else copy_this = (uInt)len; to_copy = &(ldi->data[ldi->filled_in_this_block]); for (i=0;ifilled_in_this_block += copy_this; ldi->avail_in_this_block -= copy_this; from_copy += copy_this ; len -= copy_this; } return ZIP_OK; } /****************************************************************************/ #ifndef NO_ADDFILEINEXISTINGZIP /* =========================================================================== Inputs a long in LSB order to the given file nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) */ local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)); local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte) { unsigned char buf[8]; int n; for (n = 0; n < nbByte; n++) { buf[n] = (unsigned char)(x & 0xff); x >>= 8; } if (x != 0) { /* data overflow - hack for ZIP64 (X Roche) */ for (n = 0; n < nbByte; n++) { buf[n] = 0xff; } } if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) return ZIP_ERRNO; else return ZIP_OK; } local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte)); local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte) { unsigned char* buf=(unsigned char*)dest; int n; for (n = 0; n < nbByte; n++) { buf[n] = (unsigned char)(x & 0xff); x >>= 8; } if (x != 0) { /* data overflow - hack for ZIP64 */ for (n = 0; n < nbByte; n++) { buf[n] = 0xff; } } } /****************************************************************************/ local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) { uLong year = (uLong)ptm->tm_year; if (year>=1980) year-=1980; else if (year>=80) year-=80; return (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); } /****************************************************************************/ local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)); local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi) { unsigned char c; int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); if (err==1) { *pi = (int)c; return ZIP_OK; } else { if (ZERROR64(*pzlib_filefunc_def,filestream)) return ZIP_ERRNO; else return ZIP_EOF; } } /* =========================================================================== Reads a long in LSB order from the given gz_stream. Sets */ local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) { uLong x ; int i = 0; int err; err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<8; if (err==ZIP_OK) *pX = x; else *pX = 0; return err; } local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) { uLong x ; int i = 0; int err; err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<8; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<16; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<24; if (err==ZIP_OK) *pX = x; else *pX = 0; return err; } local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) { ZPOS64_T x; int i = 0; int err; err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x = (ZPOS64_T)i; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<8; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<16; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<24; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<32; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<40; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<48; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<56; if (err==ZIP_OK) *pX = x; else *pX = 0; return err; } #ifndef BUFREADCOMMENT #define BUFREADCOMMENT (0x400) #endif /* Locate the Central directory of a zipfile (at the end, just before the global comment) */ local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ ZPOS64_T uPosFound=0; if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) return 0; uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return 0; uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) break; if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) { uPosFound = uReadPos+i; break; } if (uPosFound!=0) break; } TRYFREE(buf); return uPosFound; } /* Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before the global comment) */ local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ ZPOS64_T uPosFound=0; uLong uL; ZPOS64_T relativeOffset; if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) return 0; uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return 0; uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) break; if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) { /* Signature "0x07064b50" Zip64 end of central directory locater */ if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) { uPosFound = uReadPos+i; break; } } if (uPosFound!=0) break; } TRYFREE(buf); if (uPosFound == 0) return 0; /* Zip64 end of central directory locator */ if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) return 0; /* the signature, already checked */ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) return 0; /* number of the disk with the start of the zip64 end of central directory */ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) return 0; if (uL != 0) return 0; /* relative offset of the zip64 end of central directory record */ if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK) return 0; /* total number of disks */ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) return 0; if (uL != 1) return 0; /* Goto Zip64 end of central directory record */ if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) return 0; /* the signature */ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) return 0; if (uL != 0x06064b50) /* signature of 'Zip64 end of central directory' */ return 0; return relativeOffset; } int LoadCentralDirectoryRecord(zip64_internal* pziinit) { int err=ZIP_OK; ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ ZPOS64_T size_central_dir; /* size of the central directory */ ZPOS64_T offset_central_dir; /* offset of start of central directory */ ZPOS64_T central_pos; uLong uL; uLong number_disk; /* number of the current dist, used for spaning ZIP, unsupported, always 0*/ uLong number_disk_with_CD; /* number the the disk with central dir, used for spaning ZIP, unsupported, always 0*/ ZPOS64_T number_entry; ZPOS64_T number_entry_CD; /* total number of entries in the central dir (same than number_entry on nospan) */ uLong VersionMadeBy; uLong VersionNeeded; uLong size_comment; int hasZIP64Record = 0; /* check first if we find a ZIP64 record */ central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream); if(central_pos > 0) { hasZIP64Record = 1; } else if(central_pos == 0) { central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream); } /* disable to allow appending to empty ZIP archive if (central_pos==0) err=ZIP_ERRNO; */ if(hasZIP64Record) { ZPOS64_T sizeEndOfCentralDirectory; if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) err=ZIP_ERRNO; /* the signature, already checked */ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) err=ZIP_ERRNO; /* size of zip64 end of central directory record */ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK) err=ZIP_ERRNO; /* version made by */ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK) err=ZIP_ERRNO; /* version needed to extract */ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK) err=ZIP_ERRNO; /* number of this disk */ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) err=ZIP_ERRNO; /* number of the disk with the start of the central directory */ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) err=ZIP_ERRNO; /* total number of entries in the central directory on this disk */ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK) err=ZIP_ERRNO; /* total number of entries in the central directory */ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&number_entry_CD)!=ZIP_OK) err=ZIP_ERRNO; if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=ZIP_BADZIPFILE; /* size of the central directory */ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK) err=ZIP_ERRNO; /* offset of start of central directory with respect to the starting disk number */ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK) err=ZIP_ERRNO; /* TODO.. */ /* read the comment from the standard central header. */ size_comment = 0; } else { /* Read End of central Directory info */ if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) err=ZIP_ERRNO; /* the signature, already checked */ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) err=ZIP_ERRNO; /* number of this disk */ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) err=ZIP_ERRNO; /* number of the disk with the start of the central directory */ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) err=ZIP_ERRNO; /* total number of entries in the central dir on this disk */ number_entry = 0; if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) err=ZIP_ERRNO; else number_entry = uL; /* total number of entries in the central dir */ number_entry_CD = 0; if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) err=ZIP_ERRNO; else number_entry_CD = uL; if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=ZIP_BADZIPFILE; /* size of the central directory */ size_central_dir = 0; if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) err=ZIP_ERRNO; else size_central_dir = uL; /* offset of start of central directory with respect to the starting disk number */ offset_central_dir = 0; if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) err=ZIP_ERRNO; else offset_central_dir = uL; /* zipfile global comment length */ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK) err=ZIP_ERRNO; } if ((central_posz_filefunc, pziinit->filestream); return ZIP_ERRNO; } if (size_comment>0) { pziinit->globalcomment = (char*)ALLOC(size_comment+1); if (pziinit->globalcomment) { size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment); pziinit->globalcomment[size_comment]=0; } } byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir); pziinit->add_position_when_writting_offset = byte_before_the_zipfile; { ZPOS64_T size_central_dir_to_read = size_central_dir; size_t buf_size = SIZEDATA_INDATABLOCK; void* buf_read = (void*)ALLOC(buf_size); if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) err=ZIP_ERRNO; while ((size_central_dir_to_read>0) && (err==ZIP_OK)) { ZPOS64_T read_this = SIZEDATA_INDATABLOCK; if (read_this > size_central_dir_to_read) read_this = size_central_dir_to_read; if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,(uLong)read_this) != read_this) err=ZIP_ERRNO; if (err==ZIP_OK) err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this); size_central_dir_to_read-=read_this; } TRYFREE(buf_read); } pziinit->begin_pos = byte_before_the_zipfile; pziinit->number_entry = number_entry_CD; if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0) err=ZIP_ERRNO; return err; } #endif /* !NO_ADDFILEINEXISTINGZIP*/ /************************************************************/ extern zipFile ZEXPORT zipOpen3 (voidpf file, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) { zip64_internal ziinit; zip64_internal* zi; int err=ZIP_OK; ziinit.z_filefunc.zseek32_file = NULL; ziinit.z_filefunc.ztell32_file = NULL; if (pzlib_filefunc64_32_def==NULL) fill_qiodevice64_filefunc(&ziinit.z_filefunc.zfile_func64); else ziinit.z_filefunc = *pzlib_filefunc64_32_def; ziinit.filestream = ZOPEN64(ziinit.z_filefunc, file, (append == APPEND_STATUS_CREATE) ? (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); if (ziinit.filestream == NULL) return NULL; if (append == APPEND_STATUS_CREATEAFTER) ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END); ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream); ziinit.in_opened_file_inzip = 0; ziinit.ci.stream_initialised = 0; ziinit.number_entry = 0; ziinit.add_position_when_writting_offset = 0; ziinit.flags = ZIP_WRITE_DATA_DESCRIPTOR; init_linkedlist(&(ziinit.central_dir)); zi = (zip64_internal*)ALLOC(sizeof(zip64_internal)); if (zi==NULL) { ZCLOSE64(ziinit.z_filefunc,ziinit.filestream); return NULL; } /* now we add file in a zipfile */ # ifndef NO_ADDFILEINEXISTINGZIP ziinit.globalcomment = NULL; if (append == APPEND_STATUS_ADDINZIP) { /* Read and Cache Central Directory Records */ err = LoadCentralDirectoryRecord(&ziinit); } if (globalcomment) { *globalcomment = ziinit.globalcomment; } # endif /* !NO_ADDFILEINEXISTINGZIP*/ if (err != ZIP_OK) { # ifndef NO_ADDFILEINEXISTINGZIP TRYFREE(ziinit.globalcomment); # endif /* !NO_ADDFILEINEXISTINGZIP*/ TRYFREE(zi); return NULL; } else { *zi = ziinit; return (zipFile)zi; } } extern zipFile ZEXPORT zipOpen2 (voidpf file, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) { if (pzlib_filefunc32_def != NULL) { zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); return zipOpen3(file, append, globalcomment, &zlib_filefunc64_32_def_fill); } else return zipOpen3(file, append, globalcomment, NULL); } extern zipFile ZEXPORT zipOpen2_64 (voidpf file, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) { if (pzlib_filefunc_def != NULL) { zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; zlib_filefunc64_32_def_fill.ztell32_file = NULL; zlib_filefunc64_32_def_fill.zseek32_file = NULL; return zipOpen3(file, append, globalcomment, &zlib_filefunc64_32_def_fill); } else return zipOpen3(file, append, globalcomment, NULL); } extern zipFile ZEXPORT zipOpen (voidpf file, int append) { return zipOpen3(file,append,NULL,NULL); } extern zipFile ZEXPORT zipOpen64 (voidpf file, int append) { return zipOpen3(file,append,NULL,NULL); } int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local, uLong version_to_extract) { /* write the local header */ int err; uInt size_filename = (uInt)strlen(filename); uInt size_extrafield = size_extrafield_local; err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4); if (err==ZIP_OK) { if(zi->ci.zip64) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);/* version needed to extract */ else err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)version_to_extract,2); } if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); /* CRC / Compressed size / Uncompressed size will be filled in later and rewritten later */ if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ if (err==ZIP_OK) { if(zi->ci.zip64) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* compressed size, unknown */ else err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ } if (err==ZIP_OK) { if(zi->ci.zip64) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* uncompressed size, unknown */ else err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ } if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); if(zi->ci.zip64) { size_extrafield += 20; } if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield,2); if ((err==ZIP_OK) && (size_filename > 0)) { if (ZWRITE64(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) err = ZIP_ERRNO; } if ((err==ZIP_OK) && (size_extrafield_local > 0)) { if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local) err = ZIP_ERRNO; } if ((err==ZIP_OK) && (zi->ci.zip64)) { /* write the Zip64 extended info */ short HeaderID = 1; short DataSize = 16; ZPOS64_T CompressedSize = 0; ZPOS64_T UncompressedSize = 0; /* Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) */ zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8); } return err; } /* NOTE. When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped before calling this function it can be done with zipRemoveExtraInfoBlock It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize unnecessary allocations. */ extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits,int memLevel, int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase, int zip64) { zip64_internal* zi; uInt size_filename; uInt size_comment; uInt i; int err = ZIP_OK; uLong version_to_extract; # ifdef NOCRYPT if (password != NULL) return ZIP_PARAMERROR; # endif if (file == NULL) return ZIP_PARAMERROR; #ifdef HAVE_BZIP2 if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED)) return ZIP_PARAMERROR; #else if ((method!=0) && (method!=Z_DEFLATED)) return ZIP_PARAMERROR; #endif zi = (zip64_internal*)file; if (zi->in_opened_file_inzip == 1) { err = zipCloseFileInZip (file); if (err != ZIP_OK) return err; } if (method == 0 && (level == 0 || (zi->flags & ZIP_WRITE_DATA_DESCRIPTOR) == 0)) { version_to_extract = 10; } else { version_to_extract = 20; } if (filename==NULL) filename="-"; if (comment==NULL) size_comment = 0; else size_comment = (uInt)strlen(comment); size_filename = (uInt)strlen(filename); if (zipfi == NULL) zi->ci.dosDate = 0; else { if (zipfi->dosDate != 0) zi->ci.dosDate = zipfi->dosDate; else zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date); } zi->ci.flag = flagBase; if ((level==8) || (level==9)) zi->ci.flag |= 2; if (level==2) zi->ci.flag |= 4; if (level==1) zi->ci.flag |= 6; if (password != NULL) zi->ci.flag |= 1; if (version_to_extract >= 20 && (zi->flags & ZIP_WRITE_DATA_DESCRIPTOR) != 0) zi->ci.flag |= 8; zi->ci.crc32 = 0; zi->ci.method = method; zi->ci.encrypt = 0; zi->ci.stream_initialised = 0; zi->ci.pos_in_buffered_data = 0; zi->ci.raw = raw; zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream); zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment; zi->ci.size_centralExtraFree = 32; /* Extra space we have reserved in case we need to add ZIP64 extra info data */ zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree); zi->ci.size_centralExtra = size_extrafield_global; zip64local_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); /* version info */ zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2); zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)version_to_extract,2); zip64local_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); zip64local_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); zip64local_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); zip64local_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ zip64local_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ zip64local_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ zip64local_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); zip64local_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); zip64local_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ if (zipfi==NULL) zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); else zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); if (zipfi==NULL) zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); else zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); if(zi->ci.pos_local_header >= 0xffffffff) zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4); else zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset,4); for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = *(((const char*)extrafield_global)+i); for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ size_extrafield_global+i) = *(comment+i); if (zi->ci.central_header == NULL) return ZIP_INTERNALERROR; zi->ci.zip64 = zip64; zi->ci.totalCompressedData = 0; zi->ci.totalUncompressedData = 0; zi->ci.pos_zip64extrainfo = 0; err = Write_LocalFileHeader(zi, filename, size_extrafield_local, extrafield_local, version_to_extract); #ifdef HAVE_BZIP2 zi->ci.bstream.avail_in = (uInt)0; zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; zi->ci.bstream.total_in_hi32 = 0; zi->ci.bstream.total_in_lo32 = 0; zi->ci.bstream.total_out_hi32 = 0; zi->ci.bstream.total_out_lo32 = 0; #endif zi->ci.stream.avail_in = (uInt)0; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; zi->ci.stream.total_in = 0; zi->ci.stream.total_out = 0; zi->ci.stream.data_type = Z_BINARY; #ifdef HAVE_BZIP2 if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED || zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) #else if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) #endif { if(zi->ci.method == Z_DEFLATED) { zi->ci.stream.zalloc = (alloc_func)0; zi->ci.stream.zfree = (free_func)0; zi->ci.stream.opaque = (voidpf)0; if (windowBits>0) windowBits = -windowBits; err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy); if (err==Z_OK) zi->ci.stream_initialised = Z_DEFLATED; } else if(zi->ci.method == Z_BZIP2ED) { #ifdef HAVE_BZIP2 /* Init BZip stuff here */ zi->ci.bstream.bzalloc = 0; zi->ci.bstream.bzfree = 0; zi->ci.bstream.opaque = (voidpf)0; err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0,35); if(err == BZ_OK) zi->ci.stream_initialised = Z_BZIP2ED; #endif } } # ifndef NOCRYPT zi->ci.crypt_header_size = 0; if ((err==Z_OK) && (password != NULL)) { unsigned char bufHead[RAND_HEAD_LEN]; unsigned int sizeHead; zi->ci.encrypt = 1; zi->ci.pcrc_32_tab = get_crc_table(); /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ if (crcForCrypting == 0) { crcForCrypting = (uLong)zi->ci.dosDate << 16; /* ATTANTION! Without this row, you don't unpack your password protected archive in other app. */ } sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); zi->ci.crypt_header_size = sizeHead; if (ZWRITE64(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) err = ZIP_ERRNO; } # endif if (err==Z_OK) zi->in_opened_file_inzip = 1; return err; } extern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits,int memLevel, int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, strategy, password, crcForCrypting, versionMadeBy, flagBase, 0); } extern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits,int memLevel, int strategy, const char* password, uLong crcForCrypting) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, strategy, password, crcForCrypting, VERSIONMADEBY, 0, 0); } extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits,int memLevel, int strategy, const char* password, uLong crcForCrypting, int zip64) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, strategy, password, crcForCrypting, VERSIONMADEBY, 0, zip64); } extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, 0); } extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int zip64) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, zip64); } extern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void*extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int zip64) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, zip64); } extern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void*extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level) { return zipOpenNewFileInZip4_64 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, 0); } local int zip64FlushWriteBuffer(zip64_internal* zi) { int err=ZIP_OK; if (zi->ci.encrypt != 0) { #ifndef NOCRYPT uInt i; int t; for (i=0;ici.pos_in_buffered_data;i++) zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t); #endif } if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data) err = ZIP_ERRNO; zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data; #ifdef HAVE_BZIP2 if(zi->ci.method == Z_BZIP2ED) { zi->ci.totalUncompressedData += zi->ci.bstream.total_in_lo32; zi->ci.bstream.total_in_lo32 = 0; zi->ci.bstream.total_in_hi32 = 0; } else #endif { zi->ci.totalUncompressedData += zi->ci.stream.total_in; zi->ci.stream.total_in = 0; } zi->ci.pos_in_buffered_data = 0; return err; } extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len) { zip64_internal* zi; int err=ZIP_OK; if (file == NULL) return ZIP_PARAMERROR; zi = (zip64_internal*)file; if (zi->in_opened_file_inzip == 0) return ZIP_PARAMERROR; zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len); #ifdef HAVE_BZIP2 if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw)) { zi->ci.bstream.next_in = (void*)buf; zi->ci.bstream.avail_in = len; err = BZ_RUN_OK; while ((err==BZ_RUN_OK) && (zi->ci.bstream.avail_in>0)) { if (zi->ci.bstream.avail_out == 0) { if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; } if(err != BZ_RUN_OK) break; if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) { uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32; /* uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; */ err=BZ2_bzCompress(&zi->ci.bstream, BZ_RUN); zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ; } } if(err == BZ_RUN_OK) err = ZIP_OK; } else #endif { zi->ci.stream.next_in = (Bytef*)buf; zi->ci.stream.avail_in = len; while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) { if (zi->ci.stream.avail_out == 0) { if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; } if(err != ZIP_OK) break; if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) { uLong uTotalOutBefore = zi->ci.stream.total_out; err=deflate(&zi->ci.stream, Z_NO_FLUSH); if(uTotalOutBefore > zi->ci.stream.total_out) { int bBreak = 0; bBreak++; } zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; } else { uInt copy_this,i; if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) copy_this = zi->ci.stream.avail_in; else copy_this = zi->ci.stream.avail_out; for (i = 0; i < copy_this; i++) *(((char*)zi->ci.stream.next_out)+i) = *(((const char*)zi->ci.stream.next_in)+i); { zi->ci.stream.avail_in -= copy_this; zi->ci.stream.avail_out-= copy_this; zi->ci.stream.next_in+= copy_this; zi->ci.stream.next_out+= copy_this; zi->ci.stream.total_in+= copy_this; zi->ci.stream.total_out+= copy_this; zi->ci.pos_in_buffered_data += copy_this; } } }/* while(...) */ } return err; } extern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32) { return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32); } extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32) { zip64_internal* zi; ZPOS64_T compressed_size; uLong invalidValue = 0xffffffff; short datasize = 0; int err=ZIP_OK; if (file == NULL) return ZIP_PARAMERROR; zi = (zip64_internal*)file; if (zi->in_opened_file_inzip == 0) return ZIP_PARAMERROR; zi->ci.stream.avail_in = 0; if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) { while (err==ZIP_OK) { uLong uTotalOutBefore; if (zi->ci.stream.avail_out == 0) { if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; } uTotalOutBefore = zi->ci.stream.total_out; err=deflate(&zi->ci.stream, Z_FINISH); zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; } } else if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) { #ifdef HAVE_BZIP2 err = BZ_FINISH_OK; while (err==BZ_FINISH_OK) { uLong uTotalOutBefore; if (zi->ci.bstream.avail_out == 0) { if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; } uTotalOutBefore = zi->ci.bstream.total_out_lo32; err=BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH); if(err == BZ_STREAM_END) err = Z_STREAM_END; zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore); } if(err == BZ_FINISH_OK) err = ZIP_OK; #endif } if (err==Z_STREAM_END) err=ZIP_OK; /* this is normal */ if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) { if (zip64FlushWriteBuffer(zi)==ZIP_ERRNO) err = ZIP_ERRNO; } if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) { int tmp_err = deflateEnd(&zi->ci.stream); if (err == ZIP_OK) err = tmp_err; zi->ci.stream_initialised = 0; } #ifdef HAVE_BZIP2 else if((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) { int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream); if (err==ZIP_OK) err = tmperr; zi->ci.stream_initialised = 0; } #endif if (!zi->ci.raw) { crc32 = (uLong)zi->ci.crc32; uncompressed_size = zi->ci.totalUncompressedData; } compressed_size = zi->ci.totalCompressedData; # ifndef NOCRYPT compressed_size += zi->ci.crypt_header_size; # endif /* update Current Item crc and sizes, */ if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff) { /*version Made by*/ zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)45,2); /*version needed*/ zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)45,2); } zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ if(compressed_size >= 0xffffffff) zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/ else zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/ /* set internal file attributes field */ if (zi->ci.stream.data_type == Z_ASCII) zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); if(uncompressed_size >= 0xffffffff) zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/ else zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/ /* Add ZIP64 extra info field for uncompressed size */ if(uncompressed_size >= 0xffffffff) datasize += 8; /* Add ZIP64 extra info field for compressed size */ if(compressed_size >= 0xffffffff) datasize += 8; /* Add ZIP64 extra info field for relative offset to local file header of current file */ if(zi->ci.pos_local_header >= 0xffffffff) datasize += 8; if(datasize > 0) { char* p = NULL; if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree) { /* we can not write more data to the buffer that we have room for. */ return ZIP_BADZIPFILE; } p = zi->ci.central_header + zi->ci.size_centralheader; /* Add Extra Information Header for 'ZIP64 information' */ zip64local_putValue_inmemory(p, 0x0001, 2); /* HeaderID */ p += 2; zip64local_putValue_inmemory(p, datasize, 2); /* DataSize */ p += 2; if(uncompressed_size >= 0xffffffff) { zip64local_putValue_inmemory(p, uncompressed_size, 8); p += 8; } if(compressed_size >= 0xffffffff) { zip64local_putValue_inmemory(p, compressed_size, 8); p += 8; } if(zi->ci.pos_local_header >= 0xffffffff) { zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8); p += 8; } /* Update how much extra free space we got in the memory buffer */ /* and increase the centralheader size so the new ZIP64 fields are included */ /* ( 4 below is the size of HeaderID and DataSize field ) */ zi->ci.size_centralExtraFree -= datasize + 4; zi->ci.size_centralheader += datasize + 4; /* Update the extra info size field */ zi->ci.size_centralExtra += datasize + 4; zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2); } if (err==ZIP_OK) err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader); free(zi->ci.central_header); if (err==ZIP_OK) { /* Update the LocalFileHeader with the new values. */ ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) err = ZIP_ERRNO; if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ if(uncompressed_size >= 0xffffffff || compressed_size >= 0xffffffff) { if(zi->ci.pos_zip64extrainfo > 0) { /* Update the size in the ZIP64 extended field. */ if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0) err = ZIP_ERRNO; if (err==ZIP_OK) /* compressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8); if (err==ZIP_OK) /* uncompressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8); } } else { if (err==ZIP_OK) /* compressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); if (err==ZIP_OK) /* uncompressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); } if (ZSEEK64(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) err = ZIP_ERRNO; if ((zi->ci.flag & 8) != 0) { /* Write local Descriptor after file data */ if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)DESCRIPTORHEADERMAGIC,4); if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ if (zi->ci.zip64) { if (err==ZIP_OK) /* compressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,8); if (err==ZIP_OK) /* uncompressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,8); } else { if (err==ZIP_OK) /* compressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); if (err==ZIP_OK) /* uncompressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); } } } zi->number_entry ++; zi->in_opened_file_inzip = 0; return err; } extern int ZEXPORT zipCloseFileInZip (zipFile file) { return zipCloseFileInZipRaw (file,0,0); } int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip) { int err = ZIP_OK; ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset; err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4); /*num disks*/ if (err==ZIP_OK) /* number of the disk with the start of the central directory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /*relative offset*/ if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8); /*total disks*/ /* Do not support spawning of disk so always say 1 here*/ if (err==ZIP_OK) /* number of the disk with the start of the central directory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4); return err; } int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) { int err = ZIP_OK; uLong Zip64DataSize = 44; err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4); if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); /* why ZPOS64_T of this ? */ if (err==ZIP_OK) /* version made by */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); if (err==ZIP_OK) /* version needed */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); if (err==ZIP_OK) /* number of this disk */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); if (err==ZIP_OK) /* number of the disk with the start of the central directory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); if (err==ZIP_OK) /* total number of entries in the central dir */ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); if (err==ZIP_OK) /* size of the central directory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)size_centraldir,8); if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ { ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8); } return err; } int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) { int err = ZIP_OK; /*signature*/ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); if (err==ZIP_OK) /* number of this disk */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); if (err==ZIP_OK) /* number of the disk with the start of the central directory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ { { if(zi->number_entry >= 0xFFFF) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); /* use value in ZIP64 record */ else err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); } } if (err==ZIP_OK) /* total number of entries in the central dir */ { if(zi->number_entry >= 0xFFFF) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); /* use value in ZIP64 record */ else err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); } if (err==ZIP_OK) /* size of the central directory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ { ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; if(pos >= 0xffffffff) { err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4); } else err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); } return err; } int Write_GlobalComment(zip64_internal* zi, const char* global_comment) { int err = ZIP_OK; uInt size_global_comment = 0; if(global_comment != NULL) size_global_comment = (uInt)strlen(global_comment); err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); if (err == ZIP_OK && size_global_comment > 0) { if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment) err = ZIP_ERRNO; } return err; } extern int ZEXPORT zipClose (zipFile file, const char* global_comment) { zip64_internal* zi; int err = 0; uLong size_centraldir = 0; ZPOS64_T centraldir_pos_inzip; ZPOS64_T pos; if (file == NULL) return ZIP_PARAMERROR; zi = (zip64_internal*)file; if (zi->in_opened_file_inzip == 1) { err = zipCloseFileInZip (file); } #ifndef NO_ADDFILEINEXISTINGZIP if (global_comment==NULL) global_comment = zi->globalcomment; #endif centraldir_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); if (err==ZIP_OK) { linkedlist_datablock_internal* ldi = zi->central_dir.first_block; while (ldi!=NULL) { if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) { if (ZWRITE64(zi->z_filefunc,zi->filestream, ldi->data, ldi->filled_in_this_block) != ldi->filled_in_this_block) err = ZIP_ERRNO; } size_centraldir += ldi->filled_in_this_block; ldi = ldi->next_datablock; } } free_linkedlist(&(zi->central_dir)); pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; if(pos >= 0xffffffff) { ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream); Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos); } if (err==ZIP_OK) err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); if(err == ZIP_OK) err = Write_GlobalComment(zi, global_comment); if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0) if (err == ZIP_OK) err = ZIP_ERRNO; #ifndef NO_ADDFILEINEXISTINGZIP TRYFREE(zi->globalcomment); #endif TRYFREE(zi); return err; } extern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader) { char* p = pData; int size = 0; char* pNewHeader; char* pTmp; short header; short dataSize; int retVal = ZIP_OK; if(pData == NULL || *dataLen < 4) return ZIP_PARAMERROR; pNewHeader = (char*)ALLOC(*dataLen); pTmp = pNewHeader; while(p < (pData + *dataLen)) { header = *(short*)p; dataSize = *(((short*)p)+1); if( header == sHeader ) /* Header found. */ { p += dataSize + 4; /* skip it. do not copy to temp buffer */ } else { /* Extra Info block should not be removed, So copy it to the temp buffer. */ memcpy(pTmp, p, dataSize + 4); p += dataSize + 4; size += dataSize + 4; } } if(size < *dataLen) { /* clean old extra info block. */ memset(pData,0, *dataLen); /* copy the new extra info block over the old */ if(size > 0) memcpy(pData, pNewHeader, size); /* set the new extra info size */ *dataLen = size; retVal = ZIP_OK; } else retVal = ZIP_ERRNO; TRYFREE(pNewHeader); return retVal; } int ZEXPORT zipSetFlags(zipFile file, unsigned flags) { zip64_internal* zi; if (file == NULL) return ZIP_PARAMERROR; zi = (zip64_internal*)file; zi->flags |= flags; return ZIP_OK; } int ZEXPORT zipClearFlags(zipFile file, unsigned flags) { zip64_internal* zi; if (file == NULL) return ZIP_PARAMERROR; zi = (zip64_internal*)file; zi->flags &= ~flags; return ZIP_OK; } connectome-workbench-1.4.2/src/Quazip/zip.h000066400000000000000000000370321360521144700206530ustar00rootroot00000000000000/* zip.h -- IO on .zip files using zlib Version 1.1, February 14h, 2010 part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications for Zip64 support Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) For more info read MiniZip_info.txt --------------------------------------------------------------------------- Condition of use and distribution are the same than zlib : This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. --------------------------------------------------------------------------- Changes See header of zip.h */ #ifndef _zip12_H #define _zip12_H #ifdef __cplusplus extern "C" { #endif //#define HAVE_BZIP2 #ifndef _ZLIB_H #include "zlib.h" #endif #ifndef _ZLIBIOAPI_H #include "ioapi.h" #endif #ifdef HAVE_BZIP2 #include "bzlib.h" #endif #define Z_BZIP2ED 12 #if defined(STRICTZIP) || defined(STRICTZIPUNZIP) /* like the STRICT of WIN32, we define a pointer that cannot be converted from (void*) without cast */ typedef struct TagzipFile__ { int unused; } zipFile__; typedef zipFile__ *zipFile; #else typedef voidp zipFile; #endif #define ZIP_OK (0) #define ZIP_EOF (0) #define ZIP_ERRNO (Z_ERRNO) #define ZIP_PARAMERROR (-102) #define ZIP_BADZIPFILE (-103) #define ZIP_INTERNALERROR (-104) #define ZIP_WRITE_DATA_DESCRIPTOR 0x8u #ifndef DEF_MEM_LEVEL # if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 # else # define DEF_MEM_LEVEL MAX_MEM_LEVEL # endif #endif /* default memLevel */ /* tm_zip contain date/time info */ typedef struct tm_zip_s { uInt tm_sec; /* seconds after the minute - [0,59] */ uInt tm_min; /* minutes after the hour - [0,59] */ uInt tm_hour; /* hours since midnight - [0,23] */ uInt tm_mday; /* day of the month - [1,31] */ uInt tm_mon; /* months since January - [0,11] */ uInt tm_year; /* years - [1980..2044] */ } tm_zip; typedef struct { tm_zip tmz_date; /* date in understandable format */ uLong dosDate; /* if dos_date == 0, tmu_date is used */ /* uLong flag; */ /* general purpose bit flag 2 bytes */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ } zip_fileinfo; typedef const char* zipcharpc; #define APPEND_STATUS_CREATE (0) #define APPEND_STATUS_CREATEAFTER (1) #define APPEND_STATUS_ADDINZIP (2) extern zipFile ZEXPORT zipOpen OF((voidpf file, int append)); extern zipFile ZEXPORT zipOpen64 OF((voidpf file, int append)); /* Create a zipfile. the file argument depends on the API used, for QuaZIP it's a QIODevice pointer. if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip will be created at the end of the file. (useful if the file contain a self extractor code) if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will add files in existing zip (be sure you don't add file that doesn't exist) If the zipfile cannot be opened, the return value is NULL. Else, the return value is a zipFile Handle, usable with other function of this zip package. */ /* Note : there is no delete function into a zipfile. If you want delete file into a zipfile, you must open a zipfile, and create another Of couse, you can use RAW reading and writing to copy the file you did not want delte */ extern zipFile ZEXPORT zipOpen2 OF((voidpf file, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc_def)); extern zipFile ZEXPORT zipOpen2_64 OF((voidpf file, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def)); extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level)); extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int zip64)); /* Open a file in the ZIP for writing. filename : the filename in zip (if NULL, '-' without quote will be used *zipfi contain supplemental information if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local contains the extrafield data the the local header if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global contains the extrafield data the the local header if comment != NULL, comment contain the comment string method contain the compression method (0 for store, Z_DEFLATED for deflate) level contain the level of compression (can be Z_DEFAULT_COMPRESSION) zip64 is set to 1 if a zip64 extended information block should be added to the local file header. this MUST be '1' if the uncompressed size is >= 0xffffffff. */ extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw)); extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int zip64)); /* Same than zipOpenNewFileInZip, except if raw=1, we write raw file */ extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting)); extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting, int zip64 )); /* Same than zipOpenNewFileInZip2, except windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 password : crypting password (NULL for no crypting) crcForCrypting : crc of file to compress (needed for crypting) */ extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase )); extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase, int zip64 )); /* Same than zipOpenNewFileInZip4, except versionMadeBy : value for Version made by field flag : value for flag field (compression level info will be added) */ extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, const void* buf, unsigned len)); /* Write data in the zipfile */ extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); /* Close the current file in the zipfile */ extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, uLong uncompressed_size, uLong crc32)); extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, ZPOS64_T uncompressed_size, uLong crc32)); /* Close the current file in the zipfile, for file opened with parameter raw=1 in zipOpenNewFileInZip2 uncompressed_size and crc32 are value for the uncompressed size */ extern int ZEXPORT zipClose OF((zipFile file, const char* global_comment)); /* Close the zipfile */ extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader)); /* zipRemoveExtraInfoBlock - Added by Mathias Svensson Remove extra information block from a extra information data for the local file header or central directory header It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode. 0x0001 is the signature header for the ZIP64 extra information blocks usage. Remove ZIP64 Extra information from a central director extra field data zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001); Remove ZIP64 Extra information from a Local File Header extra field data zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001); */ /* Added by Sergey A. Tachenov to tweak zipping behaviour. */ extern int ZEXPORT zipSetFlags(zipFile file, unsigned flags); extern int ZEXPORT zipClearFlags(zipFile file, unsigned flags); #ifdef __cplusplus } #endif #endif /* _zip64_H */ connectome-workbench-1.4.2/src/Qwt/000077500000000000000000000000001360521144700171755ustar00rootroot00000000000000connectome-workbench-1.4.2/src/Qwt/CHANGES-6.1000066400000000000000000000063431360521144700205000ustar00rootroot00000000000000Qwt 6.1.2 ========= 1) Qt 5.4 compatibility - QT_STATIC_CONST "QT_STATIC_CONST" replaced by "static const" 2) build environment - QMAKELIBDIRFLAGS using QMAKELIBDIRFLAGS to avoid conflicts with already installed linux distro packages 3) color maps - QwtLinearColorMap handling of alpha values added - QwtAlphaColorMap basic functinality fixed - QwtPainter QwtPainter::drawColorBar() fixed for semi transparent colors. 4) QwtPlot and friends - QwtLegend layout issue fixed - QwtLogScaleEngine tick duplicates fixed - QwtPainter internal chunk size for drawing polylines with the raster paint engine reduced from 20 to 6 ( faster ). Qwt 6.1.1 ========= 1) build environment - Shadow builds qmake project files to allow shadow builds - pkg-config QwtPkgConfig config option added to qwtconfig.pri to enable generation of pkg-config files ( default setting is: disabled ) 2) scales - QwtDateScaleEngine Aligning/Autoscaling improved. - QwtLinearScaleEngines Trying to avoid overruns for huge intervals ( > max double ) in divideScale(). - QwtAbstractScaleDraw/QwtScaleDraw Layout issues fixed. - QwtRoundScaleDraw Performance for specific use cases improved. 3) controls - QwtAbstractSlider/QwtCounter Fixes for tiny step sizes. - QwtDial/QwtKnob Rounding instead of flooring, when translating values to angles. - QwtKnob/QwtThermo Missing updates, when changing the scale draw. - QwtWheel Aligning of values improved. 4) QwtPlot and friends - QwtPlot Disabling auto-replot in the destructor. QwtPlot::setPlotLayout() fixed. Calculation in QwtPlot::canvasMap fixed for disabled axes. QwtPlot::autoRefresh() when attaching/detaching a plot item. - QwtLegend Clipping code fixed in QwtLegend::renderLegend(). - QwtPlotRenderer Order of setting printer properties changed to work around a Qt 4.8 bug. - QwtGraphic Handling of RenderPensUnscaled flag fixed to respect initial painter transformations ( non cosmetic pens on legend icons will be scaled according to paint device resolution - f.e high dpi printouts - now ). - QwtPainter Painter transformation for simple rich texts fixed. Applying alpha values, when drawing color bars. - QwtPicker Work around a Qt bug when creating an event filter inside of an event filter ( calling the event filter twice ). - QwtPickerMachine Ignoring autorepeated key events. - QwtPlotCurve Paint order of curve pen and brush inverted ( pen on top of brush ). - QwtPlotAbstractBarChart Using layoutHint() as minimum sample width in AutoAdjustSamples mode. - QwtPlotBarChart/QwtPlotMultiBarChart Caluclation of boundingRect() fixed. - QwtPlotScaleItem Internal cache removed to avoid out of sync situations - QwtPlotSpectroCurve Losing alpha values from the color map fixed. - QwtPlotTextLabel No internal caches for record/replay paint devices ( QPicture/QwtGraphic ). - QwtRasterData Handling of NaN values added, when calculating contour lines. - QwtSymbol Pin point translations fixed. connectome-workbench-1.4.2/src/Qwt/CMakeLists.txt000066400000000000000000000124311360521144700217360ustar00rootroot00000000000000################################################################ # Qwt Widget Library # Copyright (C) 1997 Josef Wilgen # Copyright (C) 2002 Uwe Rathmann # # This library is free software; you can redistribute it and/or # modify it under the terms of the Qwt License, Version 1.0 ################################################################ # # Name of project # PROJECT (Qwt) # # QT include files # if(Qt5_FOUND) include_directories(${Qt5Concurrent_INCLUDE_DIRS}) include_directories(${Qt5Core_INCLUDE_DIRS}) include_directories(${Qt5Widgets_INCLUDE_DIRS}) endif() IF (QT4_FOUND) INCLUDE(${QT_USE_FILE}) ENDIF () add_definitions(-DQWT_NO_SVG -DQWT_NO_OPENGL) # # With AUTOMOC, do not need to specify files # that contain Q_OBJECT macro for Qt to process with 'moc' # (meta-object compiler). # IF(WORKBENCH_USE_CMAKE_AUTOMOC) SET(CMAKE_AUTOMOC ON) ELSE() SET(MOC_INPUT_HEADER_FILES qwt_abstract_legend.h qwt_dyngrid_layout.h qwt_legend.h qwt_legend_label.h qwt_magnifier.h qwt_panner.h qwt_picker.h qwt_plot_canvas.h qwt_plot.h qwt_plot_magnifier.h qwt_plot_panner.h qwt_plot_picker.h qwt_plot_renderer.h qwt_plot_zoomer.h qwt_sampling_thread.h qwt_scale_widget.h qwt_text_label.h ) IF(Qt5_FOUND) QT5_WRAP_CPP(MOC_SOURCE_FILES ${MOC_INPUT_HEADER_FILES}) ENDIF() IF (QT4_FOUND) QT4_WRAP_CPP(MOC_SOURCE_FILES ${MOC_INPUT_HEADER_FILES}) ENDIF () ENDIF() # # Header files # SET(SOURCE_FILES qwt_abstract_legend.h qwt_abstract_scale_draw.h qwt_clipper.h qwt_color_map.h qwt_column_symbol.h qwt_compat.h qwt_curve_fitter.h qwt_date.h qwt_date_scale_draw.h qwt_date_scale_engine.h qwt_dyngrid_layout.h qwt_event_pattern.h qwt_global.h qwt_graphic.h qwt.h qwt_interval.h qwt_interval_symbol.h qwt_legend_data.h qwt_legend.h qwt_legend_label.h qwt_magnifier.h qwt_math.h qwt_matrix_raster_data.h qwt_null_paintdevice.h qwt_painter_command.h qwt_painter.h qwt_panner.h qwt_picker.h qwt_picker_machine.h qwt_pixel_matrix.h qwt_plot_abstract_barchart.h qwt_plot_barchart.h qwt_plot_canvas.h qwt_plot_curve.h qwt_plot_dict.h qwt_plot_directpainter.h qwt_plot_grid.h qwt_plot.h qwt_plot_histogram.h qwt_plot_intervalcurve.h qwt_plot_item.h qwt_plot_layout.h qwt_plot_legenditem.h qwt_plot_magnifier.h qwt_plot_marker.h qwt_plot_multi_barchart.h qwt_plot_panner.h qwt_plot_picker.h qwt_plot_rasteritem.h qwt_plot_renderer.h qwt_plot_rescaler.h qwt_plot_scaleitem.h qwt_plot_seriesitem.h qwt_plot_shapeitem.h qwt_plot_spectrocurve.h qwt_plot_spectrogram.h qwt_plot_textlabel.h qwt_plot_tradingcurve.h qwt_plot_zoneitem.h qwt_plot_zoomer.h qwt_point_3d.h qwt_point_data.h qwt_point_mapper.h qwt_point_polar.h qwt_raster_data.h qwt_round_scale_draw.h qwt_samples.h qwt_sampling_thread.h qwt_scale_div.h qwt_scale_draw.h qwt_scale_engine.h qwt_scale_map.h qwt_scale_widget.h qwt_series_data.h qwt_series_store.h qwt_spline.h qwt_symbol.h qwt_system_clock.h qwt_text_engine.h qwt_text.h qwt_text_label.h qwt_transform.h qwt_widget_overlay.h qwt_abstract_legend.cpp qwt_abstract_scale_draw.cpp qwt_clipper.cpp qwt_color_map.cpp qwt_column_symbol.cpp qwt_curve_fitter.cpp qwt_date.cpp qwt_date_scale_draw.cpp qwt_date_scale_engine.cpp qwt_dyngrid_layout.cpp qwt_event_pattern.cpp qwt_graphic.cpp qwt_interval.cpp qwt_interval_symbol.cpp qwt_legend.cpp qwt_legend_data.cpp qwt_legend_label.cpp qwt_magnifier.cpp qwt_math.cpp qwt_matrix_raster_data.cpp qwt_null_paintdevice.cpp qwt_painter_command.cpp qwt_painter.cpp qwt_panner.cpp qwt_picker.cpp qwt_picker_machine.cpp qwt_pixel_matrix.cpp qwt_plot_abstract_barchart.cpp qwt_plot_axis.cpp qwt_plot_barchart.cpp qwt_plot_canvas.cpp qwt_plot.cpp qwt_plot_curve.cpp qwt_plot_dict.cpp qwt_plot_directpainter.cpp qwt_plot_grid.cpp qwt_plot_histogram.cpp qwt_plot_intervalcurve.cpp qwt_plot_item.cpp qwt_plot_layout.cpp qwt_plot_legenditem.cpp qwt_plot_magnifier.cpp qwt_plot_marker.cpp qwt_plot_multi_barchart.cpp qwt_plot_panner.cpp qwt_plot_picker.cpp qwt_plot_rasteritem.cpp qwt_plot_renderer.cpp qwt_plot_rescaler.cpp qwt_plot_scaleitem.cpp qwt_plot_seriesitem.cpp qwt_plot_shapeitem.cpp qwt_plot_spectrocurve.cpp qwt_plot_spectrogram.cpp qwt_plot_textlabel.cpp qwt_plot_tradingcurve.cpp qwt_plot_xml.cpp qwt_plot_zoneitem.cpp qwt_plot_zoomer.cpp qwt_point_3d.cpp qwt_point_data.cpp qwt_point_mapper.cpp qwt_point_polar.cpp qwt_raster_data.cpp qwt_round_scale_draw.cpp qwt_sampling_thread.cpp qwt_scale_div.cpp qwt_scale_draw.cpp qwt_scale_engine.cpp qwt_scale_map.cpp qwt_scale_widget.cpp qwt_series_data.cpp qwt_spline.cpp qwt_symbol.cpp qwt_system_clock.cpp qwt_text.cpp qwt_text_engine.cpp qwt_text_label.cpp qwt_transform.cpp qwt_widget_overlay.cpp ) # # Process the header files with moc producing moc_*.cpp files # INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) # # Create the GUI library # ADD_LIBRARY(Qwt ${SOURCE_FILES} ${MOC_SOURCE_FILES} ) TARGET_LINK_LIBRARIES(Qwt ${CARET_QT5_LINK}) SET(Qwt_LIBRARIES Qwt PARENT_SCOPE) SET(Qwt_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE) connectome-workbench-1.4.2/src/Qwt/COPYING000066400000000000000000000664521360521144700202450ustar00rootroot00000000000000 Qwt License Version 1.0, January 1, 2003 The Qwt library and included programs are provided under the terms of the GNU LESSER GENERAL PUBLIC LICENSE (LGPL) with the following exceptions: 1. Widgets that are subclassed from Qwt widgets do not constitute a derivative work. 2. Static linking of applications and widgets to the Qwt library does not constitute a derivative work and does not require the author to provide source code for the application or widget, use the shared Qwt libraries, or link their applications or widgets against a user-supplied version of Qwt. If you link the application or widget to a modified version of Qwt, then the changes to Qwt must be provided under the terms of the LGPL in sections 1, 2, and 4. 3. You do not have to provide a copy of the Qwt license with programs that are linked to the Qwt library, nor do you have to identify the Qwt license in your program or documentation as required by section 6 of the LGPL. However, programs must still identify their use of Qwt. The following example statement can be included in user documentation to satisfy this requirement: [program/widget] is based in part on the work of the Qwt project (http://qwt.sf.net). ---------------------------------------------------------------------- GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 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. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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 with this License. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. 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 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.1 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 Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! connectome-workbench-1.4.2/src/Qwt/README000066400000000000000000000016221360521144700200560ustar00rootroot00000000000000 The Qwt Widget Library ---------------------- Qwt is an extension to the libraries of the Qt Project. The Qwt library contains widgets and components which are primarily useful for technical and scientifical purposes. It includes a 2-D plotting widget, different kinds of sliders, and much more. Qwt is hosted at http://qwt.sf.net Installation ------------ Read INSTALL how to build and install Qwt. Copyright --------- Qwt Widget Library Copyright (C) 1997 Josef Wilgen Copyright (C) 2002 Uwe Rathmann Qwt is published under the Qwt License, Version 1.0. You should have received a copy of this licence in the file COPYING. 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. connectome-workbench-1.4.2/src/Qwt/README_MODIFY_QWT_FOR_WORKBENCH000066400000000000000000000027651360521144700240010ustar00rootroot00000000000000Setting up QWT for use with workbench In QWT's 'src' directory: Examine src.pro A configuration item (QWT_CONFIG) allow selective building of items. There are some HEADERS and SOURCES that we need. These are the HEADERS and SOURCES not controlled with QWT_CONFIG, and QwtPlot. QwtSvg and QwtWidgets are NOT needed to copy part of the src.pro file to create a command for deleting these unneeded files. Something like this: #!/bin/sh rm \ qwt_plot_svgitem.h \ qwt_plot_svgitem.cpp rm \ qwt_abstract_slider.h \ qwt_abstract_scale.h \ qwt_arrow_button.h \ qwt_analog_clock.h \ qwt_compass.h \ qwt_compass_rose.h \ qwt_counter.h \ qwt_dial.h \ qwt_dial_needle.h \ qwt_double_range.h \ qwt_knob.h \ qwt_slider.h \ qwt_thermo.h \ qwt_wheel.h rm \ qwt_abstract_slider.cpp \ qwt_abstract_scale.cpp \ qwt_arrow_button.cpp \ qwt_analog_clock.cpp \ qwt_compass.cpp \ qwt_compass_rose.cpp \ qwt_counter.cpp \ qwt_dial.cpp \ qwt_dial_needle.cpp \ qwt_double_range.cpp \ qwt_knob.cpp \ qwt_slider.cpp \ qwt_thermo.cpp \ qwt_wheel.cpp Next, copy the src.pro to CMakeLists.txt. Run "grep --files-with-matches Q_OBJECT *.h" to find the files that need to go in the MOC_INPUT_HEADER_FILES section of the CMakeLists.txt file. Next place all headers and CPP files into the SOURCE_FILES section. connectome-workbench-1.4.2/src/Qwt/qwt.h000066400000000000000000000007761360521144700201730ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_H #define QWT_H #include "qwt_global.h" /*! Some constants for use within Qwt. */ namespace Qwt { } #endif connectome-workbench-1.4.2/src/Qwt/qwt_abstract_legend.cpp000066400000000000000000000016411360521144700237170ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_abstract_legend.h" /*! Constructor \param parent Parent widget */ QwtAbstractLegend::QwtAbstractLegend( QWidget *parent ): QFrame( parent ) { } //! Destructor QwtAbstractLegend::~QwtAbstractLegend() { } /*! Return the extent, that is needed for elements to scroll the legend ( usually scrollbars ), \param orientation Orientation \return Extent of the corresponding scroll element */ int QwtAbstractLegend::scrollExtent( Qt::Orientation orientation ) const { Q_UNUSED( orientation ); return 0; } connectome-workbench-1.4.2/src/Qwt/qwt_abstract_legend.h000066400000000000000000000037631360521144700233730ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_ABSTRACT_LEGEND_H #define QWT_ABSTRACT_LEGEND_H #include "qwt_global.h" #include "qwt_legend_data.h" #include #include class QVariant; /*! \brief Abstract base class for legend widgets Legends, that need to be under control of the QwtPlot layout system need to be derived from QwtAbstractLegend. \note Other type of legends can be implemented by connecting to the QwtPlot::legendDataChanged() signal. But as these legends are unknown to the plot layout system the layout code ( on screen and for QwtPlotRenderer ) need to be organized in application code. \sa QwtLegend */ class QWT_EXPORT QwtAbstractLegend : public QFrame { Q_OBJECT public: explicit QwtAbstractLegend( QWidget *parent = NULL ); virtual ~QwtAbstractLegend(); /*! Render the legend into a given rectangle. \param painter Painter \param rect Bounding rectangle \param fillBackground When true, fill rect with the widget background \sa renderLegend() is used by QwtPlotRenderer */ virtual void renderLegend( QPainter *painter, const QRectF &rect, bool fillBackground ) const = 0; //! \return True, when no plot item is inserted virtual bool isEmpty() const = 0; virtual int scrollExtent( Qt::Orientation ) const; public Q_SLOTS: /*! \brief Update the entries for a plot item \param itemInfo Info about an item \param data List of legend entry attributes for the item */ virtual void updateLegend( const QVariant &itemInfo, const QList &data ) = 0; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_abstract_scale_draw.cpp000066400000000000000000000231241360521144700245650ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_abstract_scale_draw.h" #include "qwt_math.h" #include "qwt_text.h" #include "qwt_painter.h" #include "qwt_scale_map.h" #include #include #include #include class QwtAbstractScaleDraw::PrivateData { public: PrivateData(): spacing( 4.0 ), penWidth( 0 ), minExtent( 0.0 ) { components = QwtAbstractScaleDraw::Backbone | QwtAbstractScaleDraw::Ticks | QwtAbstractScaleDraw::Labels; tickLength[QwtScaleDiv::MinorTick] = 4.0; tickLength[QwtScaleDiv::MediumTick] = 6.0; tickLength[QwtScaleDiv::MajorTick] = 8.0; } ScaleComponents components; QwtScaleMap map; QwtScaleDiv scaleDiv; double spacing; double tickLength[QwtScaleDiv::NTickTypes]; int penWidth; double minExtent; QMap labelCache; }; /*! \brief Constructor The range of the scale is initialized to [0, 100], The spacing (distance between ticks and labels) is set to 4, the tick lengths are set to 4,6 and 8 pixels */ QwtAbstractScaleDraw::QwtAbstractScaleDraw() { d_data = new QwtAbstractScaleDraw::PrivateData; } //! Destructor QwtAbstractScaleDraw::~QwtAbstractScaleDraw() { delete d_data; } /*! En/Disable a component of the scale \param component Scale component \param enable On/Off \sa hasComponent() */ void QwtAbstractScaleDraw::enableComponent( ScaleComponent component, bool enable ) { if ( enable ) d_data->components |= component; else d_data->components &= ~component; } /*! Check if a component is enabled \param component Component type \return true, when component is enabled \sa enableComponent() */ bool QwtAbstractScaleDraw::hasComponent( ScaleComponent component ) const { return ( d_data->components & component ); } /*! Change the scale division \param scaleDiv New scale division */ void QwtAbstractScaleDraw::setScaleDiv( const QwtScaleDiv &scaleDiv ) { d_data->scaleDiv = scaleDiv; d_data->map.setScaleInterval( scaleDiv.lowerBound(), scaleDiv.upperBound() ); d_data->labelCache.clear(); } /*! Change the transformation of the scale \param transformation New scale transformation */ void QwtAbstractScaleDraw::setTransformation( QwtTransform *transformation ) { d_data->map.setTransformation( transformation ); } //! \return Map how to translate between scale and pixel values const QwtScaleMap &QwtAbstractScaleDraw::scaleMap() const { return d_data->map; } //! \return Map how to translate between scale and pixel values QwtScaleMap &QwtAbstractScaleDraw::scaleMap() { return d_data->map; } //! \return scale division const QwtScaleDiv& QwtAbstractScaleDraw::scaleDiv() const { return d_data->scaleDiv; } /*! \brief Specify the width of the scale pen \param width Pen width \sa penWidth() */ void QwtAbstractScaleDraw::setPenWidth( int width ) { if ( width < 0 ) width = 0; if ( width != d_data->penWidth ) d_data->penWidth = width; } /*! \return Scale pen width \sa setPenWidth() */ int QwtAbstractScaleDraw::penWidth() const { return d_data->penWidth; } /*! \brief Draw the scale \param painter The painter \param palette Palette, text color is used for the labels, foreground color for ticks and backbone */ void QwtAbstractScaleDraw::draw( QPainter *painter, const QPalette& palette ) const { painter->save(); QPen pen = painter->pen(); pen.setWidth( d_data->penWidth ); pen.setCosmetic( false ); painter->setPen( pen ); if ( hasComponent( QwtAbstractScaleDraw::Labels ) ) { painter->save(); painter->setPen( palette.color( QPalette::Text ) ); // ignore pen style const QList &majorTicks = d_data->scaleDiv.ticks( QwtScaleDiv::MajorTick ); for ( int i = 0; i < majorTicks.count(); i++ ) { const double v = majorTicks[i]; if ( d_data->scaleDiv.contains( v ) ) drawLabel( painter, v ); } painter->restore(); } if ( hasComponent( QwtAbstractScaleDraw::Ticks ) ) { painter->save(); QPen pen = painter->pen(); pen.setColor( palette.color( QPalette::WindowText ) ); pen.setCapStyle( Qt::FlatCap ); painter->setPen( pen ); for ( int tickType = QwtScaleDiv::MinorTick; tickType < QwtScaleDiv::NTickTypes; tickType++ ) { const double tickLen = d_data->tickLength[tickType]; if ( tickLen <= 0.0 ) continue; const QList &ticks = d_data->scaleDiv.ticks( tickType ); for ( int i = 0; i < ticks.count(); i++ ) { const double v = ticks[i]; if ( d_data->scaleDiv.contains( v ) ) drawTick( painter, v, tickLen ); } } painter->restore(); } if ( hasComponent( QwtAbstractScaleDraw::Backbone ) ) { painter->save(); QPen pen = painter->pen(); pen.setColor( palette.color( QPalette::WindowText ) ); pen.setCapStyle( Qt::FlatCap ); painter->setPen( pen ); drawBackbone( painter ); painter->restore(); } painter->restore(); } /*! \brief Set the spacing between tick and labels The spacing is the distance between ticks and labels. The default spacing is 4 pixels. \param spacing Spacing \sa spacing() */ void QwtAbstractScaleDraw::setSpacing( double spacing ) { if ( spacing < 0 ) spacing = 0; d_data->spacing = spacing; } /*! \brief Get the spacing The spacing is the distance between ticks and labels. The default spacing is 4 pixels. \return Spacing \sa setSpacing() */ double QwtAbstractScaleDraw::spacing() const { return d_data->spacing; } /*! \brief Set a minimum for the extent The extent is calculated from the components of the scale draw. In situations, where the labels are changing and the layout depends on the extent (f.e scrolling a scale), setting an upper limit as minimum extent will avoid jumps of the layout. \param minExtent Minimum extent \sa extent(), minimumExtent() */ void QwtAbstractScaleDraw::setMinimumExtent( double minExtent ) { if ( minExtent < 0.0 ) minExtent = 0.0; d_data->minExtent = minExtent; } /*! Get the minimum extent \return Minimum extent \sa extent(), setMinimumExtent() */ double QwtAbstractScaleDraw::minimumExtent() const { return d_data->minExtent; } /*! Set the length of the ticks \param tickType Tick type \param length New length \warning the length is limited to [0..1000] */ void QwtAbstractScaleDraw::setTickLength( QwtScaleDiv::TickType tickType, double length ) { if ( tickType < QwtScaleDiv::MinorTick || tickType > QwtScaleDiv::MajorTick ) { return; } if ( length < 0.0 ) length = 0.0; const double maxTickLen = 1000.0; if ( length > maxTickLen ) length = maxTickLen; d_data->tickLength[tickType] = length; } /*! \return Length of the ticks \sa setTickLength(), maxTickLength() */ double QwtAbstractScaleDraw::tickLength( QwtScaleDiv::TickType tickType ) const { if ( tickType < QwtScaleDiv::MinorTick || tickType > QwtScaleDiv::MajorTick ) { return 0; } return d_data->tickLength[tickType]; } /*! \return Length of the longest tick Useful for layout calculations \sa tickLength(), setTickLength() */ double QwtAbstractScaleDraw::maxTickLength() const { double length = 0.0; for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ ) length = qMax( length, d_data->tickLength[i] ); return length; } /*! \brief Convert a value into its representing label The value is converted to a plain text using QLocale().toString(value). This method is often overloaded by applications to have individual labels. \param value Value \return Label string. */ QwtText QwtAbstractScaleDraw::label( double value ) const { return QLocale().toString( value ); } /*! \brief Convert a value into its representing label and cache it. The conversion between value and label is called very often in the layout and painting code. Unfortunately the calculation of the label sizes might be slow (really slow for rich text in Qt4), so it's necessary to cache the labels. \param font Font \param value Value \return Tick label */ const QwtText &QwtAbstractScaleDraw::tickLabel( const QFont &font, double value ) const { QMap::const_iterator it = d_data->labelCache.find( value ); if ( it == d_data->labelCache.end() ) { QwtText lbl = label( value ); lbl.setRenderFlags( 0 ); lbl.setLayoutAttribute( QwtText::MinimumLayout ); ( void )lbl.textSize( font ); // initialize the internal cache it = d_data->labelCache.insert( value, lbl ); } return ( *it ); } /*! Invalidate the cache used by tickLabel() The cache is invalidated, when a new QwtScaleDiv is set. If the labels need to be changed. while the same QwtScaleDiv is set, invalidateCache() needs to be called manually. */ void QwtAbstractScaleDraw::invalidateCache() { d_data->labelCache.clear(); } connectome-workbench-1.4.2/src/Qwt/qwt_abstract_scale_draw.h000066400000000000000000000070361360521144700242360ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_ABSTRACT_SCALE_DRAW_H #define QWT_ABSTRACT_SCALE_DRAW_H #include "qwt_global.h" #include "qwt_scale_div.h" #include "qwt_text.h" class QPalette; class QPainter; class QFont; class QwtTransform; class QwtScaleMap; /*! \brief A abstract base class for drawing scales QwtAbstractScaleDraw can be used to draw linear or logarithmic scales. After a scale division has been specified as a QwtScaleDiv object using setScaleDiv(), the scale can be drawn with the draw() member. */ class QWT_EXPORT QwtAbstractScaleDraw { public: /*! Components of a scale \sa enableComponent(), hasComponent */ enum ScaleComponent { //! Backbone = the line where the ticks are located Backbone = 0x01, //! Ticks Ticks = 0x02, //! Labels Labels = 0x04 }; //! Scale components typedef QFlags ScaleComponents; QwtAbstractScaleDraw(); virtual ~QwtAbstractScaleDraw(); void setScaleDiv( const QwtScaleDiv &s ); const QwtScaleDiv& scaleDiv() const; void setTransformation( QwtTransform * ); const QwtScaleMap &scaleMap() const; QwtScaleMap &scaleMap(); void enableComponent( ScaleComponent, bool enable = true ); bool hasComponent( ScaleComponent ) const; void setTickLength( QwtScaleDiv::TickType, double length ); double tickLength( QwtScaleDiv::TickType ) const; double maxTickLength() const; void setSpacing( double margin ); double spacing() const; void setPenWidth( int width ); int penWidth() const; virtual void draw( QPainter *, const QPalette & ) const; virtual QwtText label( double ) const; /*! Calculate the extent The extent is the distance from the baseline to the outermost pixel of the scale draw in opposite to its orientation. It is at least minimumExtent() pixels. \param font Font used for drawing the tick labels \return Number of pixels \sa setMinimumExtent(), minimumExtent() */ virtual double extent( const QFont &font ) const = 0; void setMinimumExtent( double ); double minimumExtent() const; protected: /*! Draw a tick \param painter Painter \param value Value of the tick \param len Length of the tick \sa drawBackbone(), drawLabel() */ virtual void drawTick( QPainter *painter, double value, double len ) const = 0; /*! Draws the baseline of the scale \param painter Painter \sa drawTick(), drawLabel() */ virtual void drawBackbone( QPainter *painter ) const = 0; /*! Draws the label for a major scale tick \param painter Painter \param value Value \sa drawTick(), drawBackbone() */ virtual void drawLabel( QPainter *painter, double value ) const = 0; void invalidateCache(); const QwtText &tickLabel( const QFont &, double value ) const; private: QwtAbstractScaleDraw( const QwtAbstractScaleDraw & ); QwtAbstractScaleDraw &operator=( const QwtAbstractScaleDraw & ); class PrivateData; PrivateData *d_data; }; Q_DECLARE_OPERATORS_FOR_FLAGS( QwtAbstractScaleDraw::ScaleComponents ) #endif connectome-workbench-1.4.2/src/Qwt/qwt_clipper.cpp000066400000000000000000000312021360521144700222300ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include #include "qwt_clipper.h" #include "qwt_point_polar.h" #include #include #include #if QT_VERSION < 0x040601 #define qAtan(x) ::atan(x) #endif namespace QwtClip { // some templates used for inlining template class LeftEdge; template class RightEdge; template class TopEdge; template class BottomEdge; template class PointBuffer; } template class QwtClip::LeftEdge { public: inline LeftEdge( Value x1, Value, Value, Value ): d_x1( x1 ) { } inline bool isInside( const Point &p ) const { return p.x() >= d_x1; } inline Point intersection( const Point &p1, const Point &p2 ) const { double dy = ( p1.y() - p2.y() ) / double( p1.x() - p2.x() ); return Point( d_x1, static_cast< Value >( p2.y() + ( d_x1 - p2.x() ) * dy ) ); } private: const Value d_x1; }; template class QwtClip::RightEdge { public: inline RightEdge( Value, Value x2, Value, Value ): d_x2( x2 ) { } inline bool isInside( const Point &p ) const { return p.x() <= d_x2; } inline Point intersection( const Point &p1, const Point &p2 ) const { double dy = ( p1.y() - p2.y() ) / double( p1.x() - p2.x() ); return Point( d_x2, static_cast( p2.y() + ( d_x2 - p2.x() ) * dy ) ); } private: const Value d_x2; }; template class QwtClip::TopEdge { public: inline TopEdge( Value, Value, Value y1, Value ): d_y1( y1 ) { } inline bool isInside( const Point &p ) const { return p.y() >= d_y1; } inline Point intersection( const Point &p1, const Point &p2 ) const { double dx = ( p1.x() - p2.x() ) / double( p1.y() - p2.y() ); return Point( static_cast( p2.x() + ( d_y1 - p2.y() ) * dx ), d_y1 ); } private: const Value d_y1; }; template class QwtClip::BottomEdge { public: inline BottomEdge( Value, Value, Value, Value y2 ): d_y2( y2 ) { } inline bool isInside( const Point &p ) const { return p.y() <= d_y2; } inline Point intersection( const Point &p1, const Point &p2 ) const { double dx = ( p1.x() - p2.x() ) / double( p1.y() - p2.y() ); return Point( static_cast( p2.x() + ( d_y2 - p2.y() ) * dx ), d_y2 ); } private: const Value d_y2; }; template class QwtClip::PointBuffer { public: PointBuffer( int capacity = 0 ): m_capacity( 0 ), m_size( 0 ), m_buffer( NULL ) { if ( capacity > 0 ) reserve( capacity ); } ~PointBuffer() { if ( m_buffer ) ::free( m_buffer ); } inline void setPoints( int numPoints, const Point *points ) { reserve( numPoints ); m_size = numPoints; ::memcpy( m_buffer, points, m_size * sizeof( Point ) ); } inline void reset() { m_size = 0; } inline int size() const { return m_size; } inline Point *data() const { return m_buffer; } inline Point &operator[]( int i ) { return m_buffer[i]; } inline const Point &operator[]( int i ) const { return m_buffer[i]; } inline void add( const Point &point ) { if ( m_capacity <= m_size ) reserve( m_size + 1 ); m_buffer[m_size++] = point; } private: inline void reserve( int size ) { if ( m_capacity == 0 ) m_capacity = 1; while ( m_capacity < size ) m_capacity *= 2; m_buffer = static_cast( ::realloc( m_buffer, m_capacity * sizeof( Point ) ) ); } int m_capacity; int m_size; Point *m_buffer; }; using namespace QwtClip; template class QwtPolygonClipper { public: QwtPolygonClipper( const Rect &clipRect ): d_clipRect( clipRect ) { } Polygon clipPolygon( const Polygon &polygon, bool closePolygon ) const { #if 0 if ( d_clipRect.contains( polygon.boundingRect() ) ) return polygon; #endif PointBuffer points1; PointBuffer points2( qMin( 256, polygon.size() ) ); points1.setPoints( polygon.size(), polygon.data() ); clipEdge< LeftEdge >( closePolygon, points1, points2 ); clipEdge< RightEdge >( closePolygon, points2, points1 ); clipEdge< TopEdge >( closePolygon, points1, points2 ); clipEdge< BottomEdge >( closePolygon, points2, points1 ); Polygon p; p.resize( points1.size() ); ::memcpy( p.data(), points1.data(), points1.size() * sizeof( Point ) ); return p; } private: template inline void clipEdge( bool closePolygon, PointBuffer &points, PointBuffer &clippedPoints ) const { clippedPoints.reset(); if ( points.size() < 2 ) { if ( points.size() == 1 ) clippedPoints.add( points[0] ); return; } const Edge edge( d_clipRect.x(), d_clipRect.x() + d_clipRect.width(), d_clipRect.y(), d_clipRect.y() + d_clipRect.height() ); int lastPos, start; if ( closePolygon ) { start = 0; lastPos = points.size() - 1; } else { start = 1; lastPos = 0; if ( edge.isInside( points[0] ) ) clippedPoints.add( points[0] ); } const uint nPoints = points.size(); for ( uint i = start; i < nPoints; i++ ) { const Point &p1 = points[i]; const Point &p2 = points[lastPos]; if ( edge.isInside( p1 ) ) { if ( edge.isInside( p2 ) ) { clippedPoints.add( p1 ); } else { clippedPoints.add( edge.intersection( p1, p2 ) ); clippedPoints.add( p1 ); } } else { if ( edge.isInside( p2 ) ) { clippedPoints.add( edge.intersection( p1, p2 ) ); } } lastPos = i; } } const Rect d_clipRect; }; class QwtCircleClipper { public: QwtCircleClipper( const QRectF &r ); QVector clipCircle( const QPointF &, double radius ) const; private: enum Edge { Left, Top, Right, Bottom, NEdges }; QList cuttingPoints( Edge, const QPointF &pos, double radius ) const; double toAngle( const QPointF &, const QPointF & ) const; const QRectF d_rect; }; QwtCircleClipper::QwtCircleClipper( const QRectF &r ): d_rect( r ) { } QVector QwtCircleClipper::clipCircle( const QPointF &pos, double radius ) const { QList points; for ( int edge = 0; edge < NEdges; edge++ ) points += cuttingPoints( static_cast(edge), pos, radius ); QVector intv; if ( points.size() <= 0 ) { QRectF cRect( 0, 0, 2 * radius, 2 * radius ); cRect.moveCenter( pos ); if ( d_rect.contains( cRect ) ) intv += QwtInterval( 0.0, 2 * M_PI ); } else { QList angles; for ( int i = 0; i < points.size(); i++ ) angles += toAngle( pos, points[i] ); #ifdef WORKBENCH_REPLACE_QT_DEPRECATED std::sort(angles.begin(), angles.end()); #else qSort( angles ); #endif const int in = d_rect.contains( qwtPolar2Pos( pos, radius, angles[0] + ( angles[1] - angles[0] ) / 2 ) ); if ( in ) { for ( int i = 0; i < angles.size() - 1; i += 2 ) intv += QwtInterval( angles[i], angles[i+1] ); } else { for ( int i = 1; i < angles.size() - 1; i += 2 ) intv += QwtInterval( angles[i], angles[i+1] ); intv += QwtInterval( angles.last(), angles.first() ); } } return intv; } double QwtCircleClipper::toAngle( const QPointF &from, const QPointF &to ) const { if ( from.x() == to.x() ) return from.y() <= to.y() ? M_PI / 2.0 : 3 * M_PI / 2.0; const double m = qAbs( ( to.y() - from.y() ) / ( to.x() - from.x() ) ); double angle = qAtan( m ); if ( to.x() > from.x() ) { if ( to.y() > from.y() ) angle = 2 * M_PI - angle; } else { if ( to.y() > from.y() ) angle = M_PI + angle; else angle = M_PI - angle; } return angle; } QList QwtCircleClipper::cuttingPoints( Edge edge, const QPointF &pos, double radius ) const { QList points; if ( edge == Left || edge == Right ) { const double x = ( edge == Left ) ? d_rect.left() : d_rect.right(); if ( qAbs( pos.x() - x ) < radius ) { const double off = qSqrt( qwtSqr( radius ) - qwtSqr( pos.x() - x ) ); const double m_y1 = pos.y() + off; if ( m_y1 >= d_rect.top() && m_y1 <= d_rect.bottom() ) points += QPointF( x, m_y1 ); const double m_y2 = pos.y() - off; if ( m_y2 >= d_rect.top() && m_y2 <= d_rect.bottom() ) points += QPointF( x, m_y2 ); } } else { const double y = ( edge == Top ) ? d_rect.top() : d_rect.bottom(); if ( qAbs( pos.y() - y ) < radius ) { const double off = qSqrt( qwtSqr( radius ) - qwtSqr( pos.y() - y ) ); const double x1 = pos.x() + off; if ( x1 >= d_rect.left() && x1 <= d_rect.right() ) points += QPointF( x1, y ); const double m_x2 = pos.x() - off; if ( m_x2 >= d_rect.left() && m_x2 <= d_rect.right() ) points += QPointF( m_x2, y ); } } return points; } /*! Sutherland-Hodgman polygon clipping \param clipRect Clip rectangle \param polygon Polygon \param closePolygon True, when the polygon is closed \return Clipped polygon */ QPolygon QwtClipper::clipPolygon( const QRectF &clipRect, const QPolygon &polygon, bool closePolygon ) { const int minX = qCeil( clipRect.left() ); const int maxX = qFloor( clipRect.right() ); const int minY = qCeil( clipRect.top() ); const int maxY = qFloor( clipRect.bottom() ); const QRect r( minX, minY, maxX - minX, maxY - minY ); QwtPolygonClipper clipper( r ); return clipper.clipPolygon( polygon, closePolygon ); } /*! Sutherland-Hodgman polygon clipping \param clipRect Clip rectangle \param polygon Polygon \param closePolygon True, when the polygon is closed \return Clipped polygon */ QPolygon QwtClipper::clipPolygon( const QRect &clipRect, const QPolygon &polygon, bool closePolygon ) { QwtPolygonClipper clipper( clipRect ); return clipper.clipPolygon( polygon, closePolygon ); } /*! Sutherland-Hodgman polygon clipping \param clipRect Clip rectangle \param polygon Polygon \param closePolygon True, when the polygon is closed \return Clipped polygon */ QPolygonF QwtClipper::clipPolygonF( const QRectF &clipRect, const QPolygonF &polygon, bool closePolygon ) { QwtPolygonClipper clipper( clipRect ); return clipper.clipPolygon( polygon, closePolygon ); } /*! Circle clipping clipCircle() divides a circle into intervals of angles representing arcs of the circle. When the circle is completely inside the clip rectangle an interval [0.0, 2 * M_PI] is returned. \param clipRect Clip rectangle \param center Center of the circle \param radius Radius of the circle \return Arcs of the circle */ QVector QwtClipper::clipCircle( const QRectF &clipRect, const QPointF ¢er, double radius ) { QwtCircleClipper clipper( clipRect ); return clipper.clipCircle( center, radius ); } connectome-workbench-1.4.2/src/Qwt/qwt_clipper.h000066400000000000000000000020511360521144700216750ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_CLIPPER_H #define QWT_CLIPPER_H #include "qwt_global.h" #include "qwt_interval.h" #include #include class QRect; class QRectF; /*! \brief Some clipping algorithms */ class QWT_EXPORT QwtClipper { public: static QPolygon clipPolygon( const QRect &, const QPolygon &, bool closePolygon = false ); static QPolygon clipPolygon( const QRectF &, const QPolygon &, bool closePolygon = false ); static QPolygonF clipPolygonF( const QRectF &, const QPolygonF &, bool closePolygon = false ); static QVector clipCircle( const QRectF &, const QPointF &, double radius ); }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_color_map.cpp000066400000000000000000000265451360521144700225630ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_color_map.h" #include "qwt_math.h" #include "qwt_interval.h" #include class QwtLinearColorMap::ColorStops { public: ColorStops(): d_doAlpha( false ) { d_stops.reserve( 256 ); } void insert( double pos, const QColor &color ); QRgb rgb( QwtLinearColorMap::Mode, double pos ) const; QVector stops() const; private: class ColorStop { public: ColorStop(): pos( 0.0 ), rgb( 0 ) { }; ColorStop( double p, const QColor &c ): pos( p ), rgb( c.rgba() ) { r = qRed( rgb ); g = qGreen( rgb ); b = qBlue( rgb ); a = qAlpha( rgb ); /* when mapping a value to rgb we will have to calcualate: - const int v = int( ( s1.v0 + ratio * s1.vStep ) + 0.5 ); Thus adding 0.5 ( for rounding ) can be done in advance */ r0 = r + 0.5; g0 = g + 0.5; b0 = b + 0.5; a0 = a + 0.5; rStep = gStep = bStep = aStep = 0.0; posStep = 0.0; } void updateSteps( const ColorStop &nextStop ) { rStep = nextStop.r - r; gStep = nextStop.g - g; bStep = nextStop.b - b; aStep = nextStop.a - a; posStep = nextStop.pos - pos; } double pos; QRgb rgb; int r, g, b, a; // precalculated values double rStep, gStep, bStep, aStep; double r0, g0, b0, a0; double posStep; }; inline int findUpper( double pos ) const; QVector d_stops; bool d_doAlpha; }; void QwtLinearColorMap::ColorStops::insert( double pos, const QColor &color ) { // Lookups need to be very fast, insertions are not so important. // Anyway, a balanced tree is what we need here. TODO ... if ( pos < 0.0 || pos > 1.0 ) return; int index; if ( d_stops.size() == 0 ) { index = 0; d_stops.resize( 1 ); } else { index = findUpper( pos ); if ( index == d_stops.size() || qAbs( d_stops[index].pos - pos ) >= 0.001 ) { d_stops.resize( d_stops.size() + 1 ); for ( int i = d_stops.size() - 1; i > index; i-- ) d_stops[i] = d_stops[i-1]; } } d_stops[index] = ColorStop( pos, color ); if ( color.alpha() != 255 ) d_doAlpha = true; if ( index > 0 ) d_stops[index-1].updateSteps( d_stops[index] ); if ( index < d_stops.size() - 1 ) d_stops[index].updateSteps( d_stops[index+1] ); } inline QVector QwtLinearColorMap::ColorStops::stops() const { QVector positions( d_stops.size() ); for ( int i = 0; i < d_stops.size(); i++ ) positions[i] = d_stops[i].pos; return positions; } inline int QwtLinearColorMap::ColorStops::findUpper( double pos ) const { int index = 0; int n = d_stops.size(); const ColorStop *stops = d_stops.data(); while ( n > 0 ) { const int half = n >> 1; const int middle = index + half; if ( stops[middle].pos <= pos ) { index = middle + 1; n -= half + 1; } else n = half; } return index; } inline QRgb QwtLinearColorMap::ColorStops::rgb( QwtLinearColorMap::Mode mode, double pos ) const { if ( pos <= 0.0 ) return d_stops[0].rgb; if ( pos >= 1.0 ) return d_stops[ d_stops.size() - 1 ].rgb; const int index = findUpper( pos ); if ( mode == FixedColors ) { return d_stops[index-1].rgb; } else { const ColorStop &s1 = d_stops[index-1]; const double ratio = ( pos - s1.pos ) / ( s1.posStep ); const int r = int( s1.r0 + ratio * s1.rStep ); const int g = int( s1.g0 + ratio * s1.gStep ); const int b = int( s1.b0 + ratio * s1.bStep ); if ( d_doAlpha ) { if ( s1.aStep ) { const int a = int( s1.a0 + ratio * s1.aStep ); return qRgba( r, g, b, a ); } else { return qRgba( r, g, b, s1.a ); } } else { return qRgb( r, g, b ); } } } //! Constructor QwtColorMap::QwtColorMap( Format format ): d_format( format ) { } //! Destructor QwtColorMap::~QwtColorMap() { } /*! Build and return a color map of 256 colors The color table is needed for rendering indexed images in combination with using colorIndex(). \param interval Range for the values \return A color table, that can be used for a QImage */ QVector QwtColorMap::colorTable( const QwtInterval &interval ) const { QVector table( 256 ); if ( interval.isValid() ) { const double step = interval.width() / ( table.size() - 1 ); for ( int i = 0; i < table.size(); i++ ) table[i] = rgb( interval, interval.minValue() + step * i ); } return table; } class QwtLinearColorMap::PrivateData { public: ColorStops colorStops; QwtLinearColorMap::Mode mode; }; /*! Build a color map with two stops at 0.0 and 1.0. The color at 0.0 is Qt::blue, at 1.0 it is Qt::yellow. \param format Preferred format of the color map */ QwtLinearColorMap::QwtLinearColorMap( QwtColorMap::Format format ): QwtColorMap( format ) { d_data = new PrivateData; d_data->mode = ScaledColors; setColorInterval( Qt::blue, Qt::yellow ); } /*! Build a color map with two stops at 0.0 and 1.0. \param color1 Color used for the minimum value of the value interval \param color2 Color used for the maximum value of the value interval \param format Preferred format for the color map */ QwtLinearColorMap::QwtLinearColorMap( const QColor &color1, const QColor &color2, QwtColorMap::Format format ): QwtColorMap( format ) { d_data = new PrivateData; d_data->mode = ScaledColors; setColorInterval( color1, color2 ); } //! Destructor QwtLinearColorMap::~QwtLinearColorMap() { delete d_data; } /*! \brief Set the mode of the color map FixedColors means the color is calculated from the next lower color stop. ScaledColors means the color is calculated by interpolating the colors of the adjacent stops. \sa mode() */ void QwtLinearColorMap::setMode( Mode mode ) { d_data->mode = mode; } /*! \return Mode of the color map \sa setMode() */ QwtLinearColorMap::Mode QwtLinearColorMap::mode() const { return d_data->mode; } /*! Set the color range Add stops at 0.0 and 1.0. \param color1 Color used for the minimum value of the value interval \param color2 Color used for the maximum value of the value interval \sa color1(), color2() */ void QwtLinearColorMap::setColorInterval( const QColor &color1, const QColor &color2 ) { d_data->colorStops = ColorStops(); d_data->colorStops.insert( 0.0, color1 ); d_data->colorStops.insert( 1.0, color2 ); } /*! Add a color stop The value has to be in the range [0.0, 1.0]. F.e. a stop at position 17.0 for a range [10.0,20.0] must be passed as: (17.0 - 10.0) / (20.0 - 10.0) \param value Value between [0.0, 1.0] \param color Color stop */ void QwtLinearColorMap::addColorStop( double value, const QColor& color ) { if ( value >= 0.0 && value <= 1.0 ) d_data->colorStops.insert( value, color ); } /*! \return Positions of color stops in increasing order */ QVector QwtLinearColorMap::colorStops() const { return d_data->colorStops.stops(); } /*! \return the first color of the color range \sa setColorInterval() */ QColor QwtLinearColorMap::color1() const { return QColor( d_data->colorStops.rgb( d_data->mode, 0.0 ) ); } /*! \return the second color of the color range \sa setColorInterval() */ QColor QwtLinearColorMap::color2() const { return QColor( d_data->colorStops.rgb( d_data->mode, 1.0 ) ); } /*! Map a value of a given interval into a RGB value \param interval Range for all values \param value Value to map into a RGB value \return RGB value for value */ QRgb QwtLinearColorMap::rgb( const QwtInterval &interval, double value ) const { if ( qIsNaN(value) ) return 0u; const double width = interval.width(); if ( width <= 0.0 ) return 0u; const double ratio = ( value - interval.minValue() ) / width; return d_data->colorStops.rgb( d_data->mode, ratio ); } /*! \brief Map a value of a given interval into a color index \param interval Range for all values \param value Value to map into a color index \return Index, between 0 and 255 */ unsigned char QwtLinearColorMap::colorIndex( const QwtInterval &interval, double value ) const { const double width = interval.width(); if ( qIsNaN(value) || width <= 0.0 || value <= interval.minValue() ) return 0; if ( value >= interval.maxValue() ) return 255; const double ratio = ( value - interval.minValue() ) / width; unsigned char index; if ( d_data->mode == FixedColors ) index = static_cast( ratio * 255 ); // always floor else index = static_cast( ratio * 255 + 0.5 ); return index; } class QwtAlphaColorMap::PrivateData { public: QColor color; QRgb rgb; QRgb rgbMax; }; /*! Constructor \param color Color of the map */ QwtAlphaColorMap::QwtAlphaColorMap( const QColor &color ): QwtColorMap( QwtColorMap::RGB ) { d_data = new PrivateData; setColor( color ); } //! Destructor QwtAlphaColorMap::~QwtAlphaColorMap() { delete d_data; } /*! Set the color \param color Color \sa color() */ void QwtAlphaColorMap::setColor( const QColor &color ) { d_data->color = color; d_data->rgb = color.rgb() & qRgba( 255, 255, 255, 0 ); d_data->rgbMax = d_data->rgb | ( 255 << 24 ); } /*! \return the color \sa setColor() */ QColor QwtAlphaColorMap::color() const { return d_data->color; } /*! \brief Map a value of a given interval into a alpha value alpha := (value - interval.minValue()) / interval.width(); \param interval Range for all values \param value Value to map into a RGB value \return RGB value, with an alpha value */ QRgb QwtAlphaColorMap::rgb( const QwtInterval &interval, double value ) const { if ( qIsNaN(value) ) return 0u; const double width = interval.width(); if ( width <= 0.0 ) return 0u; if ( value <= interval.minValue() ) return d_data->rgb; if ( value >= interval.maxValue() ) return d_data->rgbMax; const double ratio = ( value - interval.minValue() ) / width; return d_data->rgb | ( qRound( 255 * ratio ) << 24 ); } /*! Dummy function, needed to be implemented as it is pure virtual in QwtColorMap. Color indices make no sense in combination with an alpha channel. \return Always 0 */ unsigned char QwtAlphaColorMap::colorIndex( const QwtInterval &, double ) const { return 0; } connectome-workbench-1.4.2/src/Qwt/qwt_color_map.h000066400000000000000000000116751360521144700222260ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_COLOR_MAP_H #define QWT_COLOR_MAP_H #include "qwt_global.h" #include "qwt_interval.h" #include #include /*! \brief QwtColorMap is used to map values into colors. For displaying 3D data on a 2D plane the 3rd dimension is often displayed using colors, like f.e in a spectrogram. Each color map is optimized to return colors for only one of the following image formats: - QImage::Format_Indexed8\n - QImage::Format_ARGB32\n \sa QwtPlotSpectrogram, QwtScaleWidget */ class QWT_EXPORT QwtColorMap { public: /*! Format for color mapping \sa rgb(), colorIndex(), colorTable() */ enum Format { //! The map is intended to map into RGB values. RGB, /*! The map is intended to map into 8 bit values, that are indices into the color table. */ Indexed }; QwtColorMap( Format = QwtColorMap::RGB ); virtual ~QwtColorMap(); Format format() const; /*! Map a value of a given interval into a RGB value. \param interval Range for the values \param value Value \return RGB value, corresponding to value */ virtual QRgb rgb( const QwtInterval &interval, double value ) const = 0; /*! Map a value of a given interval into a color index \param interval Range for the values \param value Value \return color index, corresponding to value */ virtual unsigned char colorIndex( const QwtInterval &interval, double value ) const = 0; QColor color( const QwtInterval &, double value ) const; virtual QVector colorTable( const QwtInterval & ) const; private: Format d_format; }; /*! \brief QwtLinearColorMap builds a color map from color stops. A color stop is a color at a specific position. The valid range for the positions is [0.0, 1.0]. When mapping a value into a color it is translated into this interval according to mode(). */ class QWT_EXPORT QwtLinearColorMap: public QwtColorMap { public: /*! Mode of color map \sa setMode(), mode() */ enum Mode { //! Return the color from the next lower color stop FixedColors, //! Interpolating the colors of the adjacent stops. ScaledColors }; QwtLinearColorMap( QwtColorMap::Format = QwtColorMap::RGB ); QwtLinearColorMap( const QColor &from, const QColor &to, QwtColorMap::Format = QwtColorMap::RGB ); virtual ~QwtLinearColorMap(); void setMode( Mode ); Mode mode() const; void setColorInterval( const QColor &color1, const QColor &color2 ); void addColorStop( double value, const QColor& ); QVector colorStops() const; QColor color1() const; QColor color2() const; virtual QRgb rgb( const QwtInterval &, double value ) const; virtual unsigned char colorIndex( const QwtInterval &, double value ) const; class ColorStops; private: // Disabled copy constructor and operator= QwtLinearColorMap( const QwtLinearColorMap & ); QwtLinearColorMap &operator=( const QwtLinearColorMap & ); class PrivateData; PrivateData *d_data; }; /*! \brief QwtAlphaColorMap varies the alpha value of a color */ class QWT_EXPORT QwtAlphaColorMap: public QwtColorMap { public: QwtAlphaColorMap( const QColor & = QColor( Qt::gray ) ); virtual ~QwtAlphaColorMap(); void setColor( const QColor & ); QColor color() const; virtual QRgb rgb( const QwtInterval &, double value ) const; private: QwtAlphaColorMap( const QwtAlphaColorMap & ); QwtAlphaColorMap &operator=( const QwtAlphaColorMap & ); virtual unsigned char colorIndex( const QwtInterval &, double value ) const; class PrivateData; PrivateData *d_data; }; /*! Map a value into a color \param interval Valid interval for values \param value Value \return Color corresponding to value \warning This method is slow for Indexed color maps. If it is necessary to map many values, its better to get the color table once and find the color using colorIndex(). */ inline QColor QwtColorMap::color( const QwtInterval &interval, double value ) const { if ( d_format == RGB ) { return QColor::fromRgba( rgb( interval, value ) ); } else { const unsigned int index = colorIndex( interval, value ); return colorTable( interval )[index]; // slow } } /*! \return Intended format of the color map \sa Format */ inline QwtColorMap::Format QwtColorMap::format() const { return d_format; } #endif connectome-workbench-1.4.2/src/Qwt/qwt_column_symbol.cpp000066400000000000000000000152761360521144700234710ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_column_symbol.h" #include "qwt_math.h" #include "qwt_painter.h" #include #include static void qwtDrawBox( QPainter *p, const QRectF &rect, const QPalette &pal, double lw ) { if ( lw > 0.0 ) { if ( rect.width() == 0.0 ) { p->setPen( pal.dark().color() ); p->drawLine( rect.topLeft(), rect.bottomLeft() ); return; } if ( rect.height() == 0.0 ) { p->setPen( pal.dark().color() ); p->drawLine( rect.topLeft(), rect.topRight() ); return; } lw = qMin( lw, rect.height() / 2.0 - 1.0 ); lw = qMin( lw, rect.width() / 2.0 - 1.0 ); const QRectF outerRect = rect.adjusted( 0, 0, 1, 1 ); QPolygonF polygon( outerRect ); if ( outerRect.width() > 2 * lw && outerRect.height() > 2 * lw ) { const QRectF innerRect = outerRect.adjusted( lw, lw, -lw, -lw ); polygon = polygon.subtracted( innerRect ); } p->setPen( Qt::NoPen ); p->setBrush( pal.dark() ); p->drawPolygon( polygon ); } const QRectF windowRect = rect.adjusted( lw, lw, -lw + 1, -lw + 1 ); if ( windowRect.isValid() ) p->fillRect( windowRect, pal.window() ); } static void qwtDrawPanel( QPainter *painter, const QRectF &rect, const QPalette &pal, double lw ) { if ( lw > 0.0 ) { if ( rect.width() == 0.0 ) { painter->setPen( pal.window().color() ); painter->drawLine( rect.topLeft(), rect.bottomLeft() ); return; } if ( rect.height() == 0.0 ) { painter->setPen( pal.window().color() ); painter->drawLine( rect.topLeft(), rect.topRight() ); return; } lw = qMin( lw, rect.height() / 2.0 - 1.0 ); lw = qMin( lw, rect.width() / 2.0 - 1.0 ); const QRectF outerRect = rect.adjusted( 0, 0, 1, 1 ); const QRectF innerRect = outerRect.adjusted( lw, lw, -lw, -lw ); QPolygonF lines[2]; lines[0] += outerRect.bottomLeft(); lines[0] += outerRect.topLeft(); lines[0] += outerRect.topRight(); lines[0] += innerRect.topRight(); lines[0] += innerRect.topLeft(); lines[0] += innerRect.bottomLeft(); lines[1] += outerRect.topRight(); lines[1] += outerRect.bottomRight(); lines[1] += outerRect.bottomLeft(); lines[1] += innerRect.bottomLeft(); lines[1] += innerRect.bottomRight(); lines[1] += innerRect.topRight(); painter->setPen( Qt::NoPen ); painter->setBrush( pal.light() ); painter->drawPolygon( lines[0] ); painter->setBrush( pal.dark() ); painter->drawPolygon( lines[1] ); } painter->fillRect( rect.adjusted( lw, lw, -lw + 1, -lw + 1 ), pal.window() ); } class QwtColumnSymbol::PrivateData { public: PrivateData(): style( QwtColumnSymbol::Box ), frameStyle( QwtColumnSymbol::Raised ), lineWidth( 2 ) { palette = QPalette( Qt::gray ); } QwtColumnSymbol::Style style; QwtColumnSymbol::FrameStyle frameStyle; QPalette palette; int lineWidth; }; /*! Constructor \param style Style of the symbol \sa setStyle(), style(), Style */ QwtColumnSymbol::QwtColumnSymbol( Style style ) { d_data = new PrivateData(); d_data->style = style; } //! Destructor QwtColumnSymbol::~QwtColumnSymbol() { delete d_data; } /*! Specify the symbol style \param style Style \sa style(), setPalette() */ void QwtColumnSymbol::setStyle( Style style ) { d_data->style = style; } /*! \return Current symbol style \sa setStyle() */ QwtColumnSymbol::Style QwtColumnSymbol::style() const { return d_data->style; } /*! Assign a palette for the symbol \param palette Palette \sa palette(), setStyle() */ void QwtColumnSymbol::setPalette( const QPalette &palette ) { d_data->palette = palette; } /*! \return Current palette \sa setPalette() */ const QPalette& QwtColumnSymbol::palette() const { return d_data->palette; } /*! Set the frame, that is used for the Box style. \param frameStyle Frame style \sa frameStyle(), setLineWidth(), setStyle() */ void QwtColumnSymbol::setFrameStyle( FrameStyle frameStyle ) { d_data->frameStyle = frameStyle; } /*! \return Current frame style, that is used for the Box style. \sa setFrameStyle(), lineWidth(), setStyle() */ QwtColumnSymbol::FrameStyle QwtColumnSymbol::frameStyle() const { return d_data->frameStyle; } /*! Set the line width of the frame, that is used for the Box style. \param width Width \sa lineWidth(), setFrameStyle() */ void QwtColumnSymbol::setLineWidth( int width ) { if ( width < 0 ) width = 0; d_data->lineWidth = width; } /*! \return Line width of the frame, that is used for the Box style. \sa setLineWidth(), frameStyle(), setStyle() */ int QwtColumnSymbol::lineWidth() const { return d_data->lineWidth; } /*! Draw the symbol depending on its style. \param painter Painter \param rect Directed rectangle \sa drawBox() */ void QwtColumnSymbol::draw( QPainter *painter, const QwtColumnRect &rect ) const { painter->save(); switch ( d_data->style ) { case QwtColumnSymbol::Box: { drawBox( painter, rect ); break; } default:; } painter->restore(); } /*! Draw the symbol when it is in Box style. \param painter Painter \param rect Directed rectangle \sa draw() */ void QwtColumnSymbol::drawBox( QPainter *painter, const QwtColumnRect &rect ) const { QRectF r = rect.toRect(); if ( QwtPainter::roundingAlignment( painter ) ) { r.setLeft( qRound( r.left() ) ); r.setRight( qRound( r.right() ) ); r.setTop( qRound( r.top() ) ); r.setBottom( qRound( r.bottom() ) ); } switch ( d_data->frameStyle ) { case QwtColumnSymbol::Raised: { qwtDrawPanel( painter, r, d_data->palette, d_data->lineWidth ); break; } case QwtColumnSymbol::Plain: { qwtDrawBox( painter, r, d_data->palette, d_data->lineWidth ); break; } default: { painter->fillRect( r, d_data->palette.window() ); } } } connectome-workbench-1.4.2/src/Qwt/qwt_column_symbol.h000066400000000000000000000073601360521144700231310ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_COLUMN_SYMBOL_H #define QWT_COLUMN_SYMBOL_H #include "qwt_global.h" #include "qwt_interval.h" #include #include #include class QPainter; class QPalette; class QRect; class QwtText; /*! \brief Directed rectangle representing bounding rectangle and orientation of a column. */ class QWT_EXPORT QwtColumnRect { public: //! Direction of the column enum Direction { //! From left to right LeftToRight, //! From right to left RightToLeft, //! From bottom to top BottomToTop, //! From top to bottom TopToBottom }; //! Build an rectangle with invalid intervals directed BottomToTop. QwtColumnRect(): direction( BottomToTop ) { } //! \return A normalized QRect built from the intervals QRectF toRect() const { QRectF r( hInterval.minValue(), vInterval.minValue(), hInterval.maxValue() - hInterval.minValue(), vInterval.maxValue() - vInterval.minValue() ); r = r.normalized(); if ( hInterval.borderFlags() & QwtInterval::ExcludeMinimum ) r.adjust( 1, 0, 0, 0 ); if ( hInterval.borderFlags() & QwtInterval::ExcludeMaximum ) r.adjust( 0, 0, -1, 0 ); if ( vInterval.borderFlags() & QwtInterval::ExcludeMinimum ) r.adjust( 0, 1, 0, 0 ); if ( vInterval.borderFlags() & QwtInterval::ExcludeMaximum ) r.adjust( 0, 0, 0, -1 ); return r; } //! \return Orientation Qt::Orientation orientation() const { if ( direction == LeftToRight || direction == RightToLeft ) return Qt::Horizontal; return Qt::Vertical; } //! Interval for the horizontal coordinates QwtInterval hInterval; //! Interval for the vertical coordinates QwtInterval vInterval; //! Direction Direction direction; }; //! A drawing primitive for columns class QWT_EXPORT QwtColumnSymbol { public: /*! Style \sa setStyle(), style() */ enum Style { //! No Style, the symbol draws nothing NoStyle = -1, /*! The column is painted with a frame depending on the frameStyle() and lineWidth() using the palette(). */ Box, /*! Styles >= QwtColumnSymbol::UserStyle are reserved for derived classes of QwtColumnSymbol that overload draw() with additional application specific symbol types. */ UserStyle = 1000 }; /*! Frame Style used in Box style(). \sa Style, setFrameStyle(), frameStyle(), setStyle(), setPalette() */ enum FrameStyle { //! No frame NoFrame, //! A plain frame style Plain, //! A raised frame style Raised }; public: QwtColumnSymbol( Style = NoStyle ); virtual ~QwtColumnSymbol(); void setFrameStyle( FrameStyle style ); FrameStyle frameStyle() const; void setLineWidth( int width ); int lineWidth() const; void setPalette( const QPalette & ); const QPalette &palette() const; void setStyle( Style ); Style style() const; virtual void draw( QPainter *, const QwtColumnRect & ) const; protected: void drawBox( QPainter *, const QwtColumnRect & ) const; private: class PrivateData; PrivateData* d_data; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_compat.h000066400000000000000000000020501360521144700215210ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef _QWT_COMPAT_H_ #define _QWT_COMPAT_H_ #include "qwt_global.h" #include "qwt_interval.h" #include "qwt_point_3d.h" #include #include #include #include #include #include // A couple of definition for Qwt5 compatibility #define qwtMax qMax #define qwtMin qMin #define qwtAbs qAbs #define qwtRound qRound #define QwtArray QVector typedef QList QwtValueList; typedef QPointF QwtDoublePoint; typedef QSizeF QwtDoubleSize; typedef QRectF QwtDoubleRect; typedef QPolygon QwtPolygon; typedef QPolygonF QwtPolygonF; typedef QwtInterval QwtDoubleInterval; typedef QwtPoint3D QwtDoublePoint3D; #endif connectome-workbench-1.4.2/src/Qwt/qwt_curve_fitter.cpp000066400000000000000000000240711360521144700233010ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_curve_fitter.h" #include "qwt_math.h" #include "qwt_spline.h" #include #include #if QT_VERSION < 0x040601 #define qFabs(x) ::fabs(x) #endif //! Constructor QwtCurveFitter::QwtCurveFitter() { } //! Destructor QwtCurveFitter::~QwtCurveFitter() { } class QwtSplineCurveFitter::PrivateData { public: PrivateData(): fitMode( QwtSplineCurveFitter::Auto ), splineSize( 250 ) { } QwtSpline spline; QwtSplineCurveFitter::FitMode fitMode; int splineSize; }; //! Constructor QwtSplineCurveFitter::QwtSplineCurveFitter() { d_data = new PrivateData; } //! Destructor QwtSplineCurveFitter::~QwtSplineCurveFitter() { delete d_data; } /*! Select the algorithm used for building the spline \param mode Mode representing a spline algorithm \sa fitMode() */ void QwtSplineCurveFitter::setFitMode( FitMode mode ) { d_data->fitMode = mode; } /*! \return Mode representing a spline algorithm \sa setFitMode() */ QwtSplineCurveFitter::FitMode QwtSplineCurveFitter::fitMode() const { return d_data->fitMode; } /*! Assign a spline \param spline Spline \sa spline() */ void QwtSplineCurveFitter::setSpline( const QwtSpline &spline ) { d_data->spline = spline; d_data->spline.reset(); } /*! \return Spline \sa setSpline() */ const QwtSpline &QwtSplineCurveFitter::spline() const { return d_data->spline; } /*! \return Spline \sa setSpline() */ QwtSpline &QwtSplineCurveFitter::spline() { return d_data->spline; } /*! Assign a spline size ( has to be at least 10 points ) \param splineSize Spline size \sa splineSize() */ void QwtSplineCurveFitter::setSplineSize( int splineSize ) { d_data->splineSize = qMax( splineSize, 10 ); } /*! \return Spline size \sa setSplineSize() */ int QwtSplineCurveFitter::splineSize() const { return d_data->splineSize; } /*! Find a curve which has the best fit to a series of data points \param points Series of data points \return Curve points */ QPolygonF QwtSplineCurveFitter::fitCurve( const QPolygonF &points ) const { const int size = points.size(); if ( size <= 2 ) return points; FitMode fitMode = d_data->fitMode; if ( fitMode == Auto ) { fitMode = Spline; const QPointF *p = points.data(); for ( int i = 1; i < size; i++ ) { if ( p[i].x() <= p[i-1].x() ) { fitMode = ParametricSpline; break; } }; } if ( fitMode == ParametricSpline ) return fitParametric( points ); else return fitSpline( points ); } QPolygonF QwtSplineCurveFitter::fitSpline( const QPolygonF &points ) const { d_data->spline.setPoints( points ); if ( !d_data->spline.isValid() ) return points; QPolygonF fittedPoints( d_data->splineSize ); const double x1 = points[0].x(); const double x2 = points[int( points.size() - 1 )].x(); const double dx = x2 - x1; const double delta = dx / ( d_data->splineSize - 1 ); for ( int i = 0; i < d_data->splineSize; i++ ) { QPointF &p = fittedPoints[i]; const double v = x1 + i * delta; const double sv = d_data->spline.value( v ); p.setX( v ); p.setY( sv ); } d_data->spline.reset(); return fittedPoints; } QPolygonF QwtSplineCurveFitter::fitParametric( const QPolygonF &points ) const { int i; const int size = points.size(); QPolygonF fittedPoints( d_data->splineSize ); QPolygonF splinePointsX( size ); QPolygonF splinePointsY( size ); const QPointF *p = points.data(); QPointF *spX = splinePointsX.data(); QPointF *spY = splinePointsY.data(); double param = 0.0; for ( i = 0; i < size; i++ ) { const double x = p[i].x(); const double y = p[i].y(); if ( i > 0 ) { const double delta = qSqrt( qwtSqr( x - spX[i-1].y() ) + qwtSqr( y - spY[i-1].y() ) ); param += qMax( delta, 1.0 ); } spX[i].setX( param ); spX[i].setY( x ); spY[i].setX( param ); spY[i].setY( y ); } d_data->spline.setPoints( splinePointsX ); if ( !d_data->spline.isValid() ) return points; const double deltaX = splinePointsX[size - 1].x() / ( d_data->splineSize - 1 ); for ( i = 0; i < d_data->splineSize; i++ ) { const double dtmp = i * deltaX; fittedPoints[i].setX( d_data->spline.value( dtmp ) ); } d_data->spline.setPoints( splinePointsY ); if ( !d_data->spline.isValid() ) return points; const double deltaY = splinePointsY[size - 1].x() / ( d_data->splineSize - 1 ); for ( i = 0; i < d_data->splineSize; i++ ) { const double dtmp = i * deltaY; fittedPoints[i].setY( d_data->spline.value( dtmp ) ); } return fittedPoints; } class QwtWeedingCurveFitter::PrivateData { public: PrivateData(): tolerance( 1.0 ), chunkSize( 0 ) { } double tolerance; uint chunkSize; }; class QwtWeedingCurveFitter::Line { public: Line( int i1 = 0, int i2 = 0 ): from( i1 ), to( i2 ) { } int from; int to; }; /*! Constructor \param tolerance Tolerance \sa setTolerance(), tolerance() */ QwtWeedingCurveFitter::QwtWeedingCurveFitter( double tolerance ) { d_data = new PrivateData; setTolerance( tolerance ); } //! Destructor QwtWeedingCurveFitter::~QwtWeedingCurveFitter() { delete d_data; } /*! Assign the tolerance The tolerance is the maximum distance, that is acceptable between the original curve and the smoothed curve. Increasing the tolerance will reduce the number of the resulting points. \param tolerance Tolerance \sa tolerance() */ void QwtWeedingCurveFitter::setTolerance( double tolerance ) { d_data->tolerance = qMax( tolerance, 0.0 ); } /*! \return Tolerance \sa setTolerance() */ double QwtWeedingCurveFitter::tolerance() const { return d_data->tolerance; } /*! Limit the number of points passed to a run of the algorithm The runtime of the Douglas Peucker algorithm increases non linear with the number of points. For a chunk size > 0 the polygon is split into pieces passed to the algorithm one by one. \param numPoints Maximum for the number of points passed to the algorithm \sa chunkSize() */ void QwtWeedingCurveFitter::setChunkSize( uint numPoints ) { if ( numPoints > 0 ) numPoints = qMax( numPoints, 3U ); d_data->chunkSize = numPoints; } /*! \return Maximum for the number of points passed to a run of the algorithm - or 0, when unlimited \sa setChunkSize() */ uint QwtWeedingCurveFitter::chunkSize() const { return d_data->chunkSize; } /*! \param points Series of data points \return Curve points */ QPolygonF QwtWeedingCurveFitter::fitCurve( const QPolygonF &points ) const { QPolygonF fittedPoints; if ( d_data->chunkSize == 0 ) { fittedPoints = simplify( points ); } else { for ( int i = 0; i < points.size(); i += d_data->chunkSize ) { const QPolygonF p = points.mid( i, d_data->chunkSize ); fittedPoints += simplify( p ); } } return fittedPoints; } QPolygonF QwtWeedingCurveFitter::simplify( const QPolygonF &points ) const { const double toleranceSqr = d_data->tolerance * d_data->tolerance; QStack stack; stack.reserve( 500 ); const QPointF *p = points.data(); const int nPoints = points.size(); QVector usePoint( nPoints, false ); stack.push( Line( 0, nPoints - 1 ) ); while ( !stack.isEmpty() ) { const Line r = stack.pop(); // initialize line segment const double vecX = p[r.to].x() - p[r.from].x(); const double vecY = p[r.to].y() - p[r.from].y(); const double vecLength = qSqrt( vecX * vecX + vecY * vecY ); const double unitVecX = ( vecLength != 0.0 ) ? vecX / vecLength : 0.0; const double unitVecY = ( vecLength != 0.0 ) ? vecY / vecLength : 0.0; double maxDistSqr = 0.0; int nVertexIndexMaxDistance = r.from + 1; for ( int i = r.from + 1; i < r.to; i++ ) { //compare to anchor const double fromVecX = p[i].x() - p[r.from].x(); const double fromVecY = p[i].y() - p[r.from].y(); double distToSegmentSqr; if ( fromVecX * unitVecX + fromVecY * unitVecY < 0.0 ) { distToSegmentSqr = fromVecX * fromVecX + fromVecY * fromVecY; } else { const double toVecX = p[i].x() - p[r.to].x(); const double toVecY = p[i].y() - p[r.to].y(); const double toVecLength = toVecX * toVecX + toVecY * toVecY; const double s = toVecX * ( -unitVecX ) + toVecY * ( -unitVecY ); if ( s < 0.0 ) { distToSegmentSqr = toVecLength; } else { distToSegmentSqr = qFabs( toVecLength - s * s ); } } if ( maxDistSqr < distToSegmentSqr ) { maxDistSqr = distToSegmentSqr; nVertexIndexMaxDistance = i; } } if ( maxDistSqr <= toleranceSqr ) { usePoint[r.from] = true; usePoint[r.to] = true; } else { stack.push( Line( r.from, nVertexIndexMaxDistance ) ); stack.push( Line( nVertexIndexMaxDistance, r.to ) ); } } QPolygonF stripped; for ( int i = 0; i < nPoints; i++ ) { if ( usePoint[i] ) stripped += p[i]; } return stripped; } connectome-workbench-1.4.2/src/Qwt/qwt_curve_fitter.h000066400000000000000000000072701360521144700227500ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_CURVE_FITTER_H #define QWT_CURVE_FITTER_H #include "qwt_global.h" #include #include class QwtSpline; /*! \brief Abstract base class for a curve fitter */ class QWT_EXPORT QwtCurveFitter { public: virtual ~QwtCurveFitter(); /*! Find a curve which has the best fit to a series of data points \param polygon Series of data points \return Curve points */ virtual QPolygonF fitCurve( const QPolygonF &polygon ) const = 0; protected: QwtCurveFitter(); private: QwtCurveFitter( const QwtCurveFitter & ); QwtCurveFitter &operator=( const QwtCurveFitter & ); }; /*! \brief A curve fitter using cubic splines */ class QWT_EXPORT QwtSplineCurveFitter: public QwtCurveFitter { public: /*! Spline type The default setting is Auto \sa setFitMode(), FitMode() */ enum FitMode { /*! Use the default spline algorithm for polygons with increasing x values ( p[i-1] < p[i] ), otherwise use a parametric spline algorithm. */ Auto, //! Use a default spline algorithm Spline, //! Use a parametric spline algorithm ParametricSpline }; QwtSplineCurveFitter(); virtual ~QwtSplineCurveFitter(); void setFitMode( FitMode ); FitMode fitMode() const; void setSpline( const QwtSpline& ); const QwtSpline &spline() const; QwtSpline &spline(); void setSplineSize( int size ); int splineSize() const; virtual QPolygonF fitCurve( const QPolygonF & ) const; private: QPolygonF fitSpline( const QPolygonF & ) const; QPolygonF fitParametric( const QPolygonF & ) const; class PrivateData; PrivateData *d_data; }; /*! \brief A curve fitter implementing Douglas and Peucker algorithm The purpose of the Douglas and Peucker algorithm is that given a 'curve' composed of line segments to find a curve not too dissimilar but that has fewer points. The algorithm defines 'too dissimilar' based on the maximum distance (tolerance) between the original curve and the smoothed curve. The runtime of the algorithm increases non linear ( worst case O( n*n ) ) and might be very slow for huge polygons. To avoid performance issues it might be useful to split the polygon ( setChunkSize() ) and to run the algorithm for these smaller parts. The disadvantage of having no interpolation at the borders is for most use cases irrelevant. The smoothed curve consists of a subset of the points that defined the original curve. In opposite to QwtSplineCurveFitter the Douglas and Peucker algorithm reduces the number of points. By adjusting the tolerance parameter according to the axis scales QwtSplineCurveFitter can be used to implement different level of details to speed up painting of curves of many points. */ class QWT_EXPORT QwtWeedingCurveFitter: public QwtCurveFitter { public: QwtWeedingCurveFitter( double tolerance = 1.0 ); virtual ~QwtWeedingCurveFitter(); void setTolerance( double ); double tolerance() const; void setChunkSize( uint ); uint chunkSize() const; virtual QPolygonF fitCurve( const QPolygonF & ) const; private: virtual QPolygonF simplify( const QPolygonF & ) const; class Line; class PrivateData; PrivateData *d_data; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_date.cpp000066400000000000000000000405031360521144700215130ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_date.h" #include #include #include #include #include #if QT_VERSION >= 0x050000 typedef qint64 QwtJulianDay; static const QwtJulianDay minJulianDayD = Q_INT64_C( -784350574879 ); static const QwtJulianDay maxJulianDayD = Q_INT64_C( 784354017364 ); #else // QDate stores the Julian day as unsigned int, but // but it is QDate::fromJulianDay( int ). That's why // we have the range [ 1, INT_MAX ] typedef int QwtJulianDay; static const QwtJulianDay minJulianDayD = 1; static const QwtJulianDay maxJulianDayD = std::numeric_limits::max(); #endif static inline Qt::DayOfWeek qwtFirstDayOfWeek() { #if QT_VERSION >= 0x040800 return QLocale().firstDayOfWeek(); #else switch( QLocale().country() ) { case QLocale::Maldives: return Qt::Friday; case QLocale::Afghanistan: case QLocale::Algeria: case QLocale::Bahrain: case QLocale::Djibouti: case QLocale::Egypt: case QLocale::Eritrea: case QLocale::Ethiopia: case QLocale::Iran: case QLocale::Iraq: case QLocale::Jordan: case QLocale::Kenya: case QLocale::Kuwait: case QLocale::LibyanArabJamahiriya: case QLocale::Morocco: case QLocale::Oman: case QLocale::Qatar: case QLocale::SaudiArabia: case QLocale::Somalia: case QLocale::Sudan: case QLocale::Tunisia: case QLocale::Yemen: return Qt::Saturday; case QLocale::AmericanSamoa: case QLocale::Argentina: case QLocale::Azerbaijan: case QLocale::Botswana: case QLocale::Canada: case QLocale::China: case QLocale::FaroeIslands: case QLocale::Georgia: case QLocale::Greenland: case QLocale::Guam: case QLocale::HongKong: case QLocale::Iceland: case QLocale::India: case QLocale::Ireland: case QLocale::Israel: case QLocale::Jamaica: case QLocale::Japan: case QLocale::Kyrgyzstan: case QLocale::Lao: case QLocale::Malta: case QLocale::MarshallIslands: case QLocale::Macau: case QLocale::Mongolia: case QLocale::NewZealand: case QLocale::NorthernMarianaIslands: case QLocale::Pakistan: case QLocale::Philippines: case QLocale::RepublicOfKorea: case QLocale::Singapore: case QLocale::SyrianArabRepublic: case QLocale::Taiwan: case QLocale::Thailand: case QLocale::TrinidadAndTobago: case QLocale::UnitedStates: case QLocale::UnitedStatesMinorOutlyingIslands: case QLocale::USVirginIslands: case QLocale::Uzbekistan: case QLocale::Zimbabwe: return Qt::Sunday; default: return Qt::Monday; } #endif } static inline void qwtFloorTime( QwtDate::IntervalType intervalType, QDateTime &dt ) { // when dt is inside the special hour where DST is ending // an hour is no unique. Therefore we have to // use UTC time. const Qt::TimeSpec timeSpec = dt.timeSpec(); if ( timeSpec == Qt::LocalTime ) dt = dt.toTimeSpec( Qt::UTC ); const QTime t = dt.time(); switch( intervalType ) { case QwtDate::Second: { dt.setTime( QTime( t.hour(), t.minute(), t.second() ) ); break; } case QwtDate::Minute: { dt.setTime( QTime( t.hour(), t.minute(), 0 ) ); break; } case QwtDate::Hour: { dt.setTime( QTime( t.hour(), 0, 0 ) ); break; } default: break; } if ( timeSpec == Qt::LocalTime ) dt = dt.toTimeSpec( Qt::LocalTime ); } static inline QDateTime qwtToTimeSpec( const QDateTime &dt, Qt::TimeSpec spec ) { if ( dt.timeSpec() == spec ) return dt; const qint64 jd = dt.date().toJulianDay(); if ( jd < 0 || jd >= INT_MAX ) { // the conversion between local time and UTC // is internally limited. To avoid // overflows we simply ignore the difference // for those dates QDateTime dt2 = dt; dt2.setTimeSpec( spec ); return dt2; } return dt.toTimeSpec( spec ); } //static inline double qwtToJulianDay( int year, int month, int day ) //{ // // code from QDate but using doubles to avoid overflows // // for large values // // const int m1 = ( month - 14 ) / 12; // const int m2 = ( 367 * ( month - 2 - 12 * m1 ) ) / 12; // const double y1 = ::floor( ( 4900.0 + year + m1 ) / 100 ); // // return ::floor( ( 1461.0 * ( year + 4800 + m1 ) ) / 4 ) + m2 // - ::floor( ( 3 * y1 ) / 4 ) + day - 32075; //} // //static inline qint64 qwtFloorDiv64( qint64 a, int b ) //{ // if ( a < 0 ) // a -= b - 1; // // return a / b; //} // //static inline qint64 qwtFloorDiv( int a, int b ) //{ // if ( a < 0 ) // a -= b - 1; // // return a / b; //} static inline QDate qwtToDate( int year, int month = 1, int day = 1 ) { #if QT_VERSION >= 0x050000 return QDate( year, month, day ); #else if ( year > 100000 ) { // code from QDate but using doubles to avoid overflows // for large values const int m1 = ( month - 14 ) / 12; const int m2 = ( 367 * ( month - 2 - 12 * m1 ) ) / 12; const double y1 = ::floor( ( 4900.0 + year + m1 ) / 100 ); const double jd = ::floor( ( 1461.0 * ( year + 4800 + m1 ) ) / 4 ) + m2 - ::floor( ( 3 * y1 ) / 4 ) + day - 32075; if ( jd > maxJulianDayD ) { qWarning() << "qwtToDate: overflow"; return QDate(); } return QDate::fromJulianDay( static_cast( jd ) ); } else { return QDate( year, month, day ); } #endif } /*! Translate from double to QDateTime \param value Number of milliseconds since the epoch, 1970-01-01T00:00:00 UTC \param timeSpec Time specification \return Datetime value \sa toDouble(), QDateTime::setMSecsSinceEpoch() \note The return datetime for Qt::OffsetFromUTC will be Qt::UTC */ QDateTime QwtDate::toDateTime( double value, Qt::TimeSpec timeSpec ) { const int msecsPerDay = 86400000; const double days = static_cast( ::floor( value / msecsPerDay ) ); const double jd = QwtDate::JulianDayForEpoch + days; if ( ( jd > maxJulianDayD ) || ( jd < minJulianDayD ) ) { qWarning() << "QwtDate::toDateTime: overflow"; return QDateTime(); } const QDate d = QDate::fromJulianDay( static_cast( jd ) ); const int msecs = static_cast( value - days * msecsPerDay ); static const QTime timeNull( 0, 0, 0, 0 ); QDateTime dt( d, timeNull.addMSecs( msecs ), Qt::UTC ); if ( timeSpec == Qt::LocalTime ) dt = qwtToTimeSpec( dt, timeSpec ); return dt; } /*! Translate from QDateTime to double \param dateTime Datetime value \return Number of milliseconds since 1970-01-01T00:00:00 UTC has passed. \sa toDateTime(), QDateTime::toMSecsSinceEpoch() \warning For values very far below or above 1970-01-01 UTC rounding errors will happen due to the limited significance of a double. */ double QwtDate::toDouble( const QDateTime &dateTime ) { const int msecsPerDay = 86400000; const QDateTime dt = qwtToTimeSpec( dateTime, Qt::UTC ); const double days = dt.date().toJulianDay() - QwtDate::JulianDayForEpoch; const QTime time = dt.time(); const double secs = 3600.0 * time.hour() + 60.0 * time.minute() + time.second(); return days * msecsPerDay + time.msec() + 1000.0 * secs; } /*! Ceil a datetime according the interval type \param dateTime Datetime value \param intervalType Interval type, how to ceil. F.e. when intervalType = QwtDate::Months, the result will be ceiled to the next beginning of a month \return Ceiled datetime \sa floor() */ QDateTime QwtDate::ceil( const QDateTime &dateTime, IntervalType intervalType ) { if ( dateTime.date() >= QwtDate::maxDate() ) return dateTime; QDateTime dt = dateTime; switch ( intervalType ) { case QwtDate::Millisecond: { break; } case QwtDate::Second: { qwtFloorTime( QwtDate::Second, dt ); if ( dt < dateTime ) dt = dt.addSecs( 1 ); break; } case QwtDate::Minute: { qwtFloorTime( QwtDate::Minute, dt ); if ( dt < dateTime ) dt = dt.addSecs( 60 ); break; } case QwtDate::Hour: { qwtFloorTime( QwtDate::Hour, dt ); if ( dt < dateTime ) dt = dt.addSecs( 3600 ); break; } case QwtDate::Day: { dt.setTime( QTime( 0, 0 ) ); if ( dt < dateTime ) dt = dt.addDays( 1 ); break; } case QwtDate::Week: { dt.setTime( QTime( 0, 0 ) ); if ( dt < dateTime ) dt = dt.addDays( 1 ); int days = qwtFirstDayOfWeek() - dt.date().dayOfWeek(); if ( days < 0 ) days += 7; dt = dt.addDays( days ); break; } case QwtDate::Month: { dt.setTime( QTime( 0, 0 ) ); dt.setDate( qwtToDate( dateTime.date().year(), dateTime.date().month() ) ); if ( dt < dateTime ) dt = dt.addMonths( 1 ); break; } case QwtDate::Year: { dt.setTime( QTime( 0, 0 ) ); const QDate d = dateTime.date(); int year = d.year(); if ( d.month() > 1 || d.day() > 1 || !dateTime.time().isNull() ) year++; if ( year == 0 ) year++; // there is no year 0 dt.setDate( qwtToDate( year ) ); break; } } return dt; } /*! Floor a datetime according the interval type \param dateTime Datetime value \param intervalType Interval type, how to ceil. F.e. when intervalType = QwtDate::Months, the result will be ceiled to the next beginning of a month \return Floored datetime \sa floor() */ QDateTime QwtDate::floor( const QDateTime &dateTime, IntervalType intervalType ) { if ( dateTime.date() <= QwtDate::minDate() ) return dateTime; QDateTime dt = dateTime; switch ( intervalType ) { case QwtDate::Millisecond: { break; } case QwtDate::Second: case QwtDate::Minute: case QwtDate::Hour: { qwtFloorTime( intervalType, dt ); break; } case QwtDate::Day: { dt.setTime( QTime( 0, 0 ) ); break; } case QwtDate::Week: { dt.setTime( QTime( 0, 0 ) ); int days = dt.date().dayOfWeek() - qwtFirstDayOfWeek(); if ( days < 0 ) days += 7; dt = dt.addDays( -days ); break; } case QwtDate::Month: { dt.setTime( QTime( 0, 0 ) ); const QDate date = qwtToDate( dt.date().year(), dt.date().month() ); dt.setDate( date ); break; } case QwtDate::Year: { dt.setTime( QTime( 0, 0 ) ); const QDate date = qwtToDate( dt.date().year() ); dt.setDate( date ); break; } } return dt; } /*! Minimum for the supported date range The range of valid dates depends on how QDate stores the Julian day internally. - For Qt4 it is "Tue Jan 2 -4713" - For Qt5 it is "Thu Jan 1 -2147483648" \return minimum of the date range \sa maxDate() */ QDate QwtDate::minDate() { static QDate date; if ( !date.isValid() ) date = QDate::fromJulianDay( minJulianDayD ); return date; } /*! Maximum for the supported date range The range of valid dates depends on how QDate stores the Julian day internally. - For Qt4 it is "Tue Jun 3 5874898" - For Qt5 it is "Tue Dec 31 2147483647" \return maximum of the date range \sa minDate() \note The maximum differs between Qt4 and Qt5 */ QDate QwtDate::maxDate() { static QDate date; if ( !date.isValid() ) date = QDate::fromJulianDay( maxJulianDayD ); return date; } /*! \brief Date of the first day of the first week for a year The first day of a week depends on the current locale ( QLocale::firstDayOfWeek() ). \param year Year \param type Option how to identify the first week \return First day of week 0 \sa QLocale::firstDayOfWeek(), weekNumber() */ QDate QwtDate::dateOfWeek0( int year, Week0Type type ) { const Qt::DayOfWeek firstDayOfWeek = qwtFirstDayOfWeek(); QDate dt0( year, 1, 1 ); // floor to the first day of the week int days = dt0.dayOfWeek() - firstDayOfWeek; if ( days < 0 ) days += 7; dt0 = dt0.addDays( -days ); if ( type == QwtDate::FirstThursday ) { // according to ISO 8601 the first week is defined // by the first thursday. int d = Qt::Thursday - firstDayOfWeek; if ( d < 0 ) d += 7; if ( dt0.addDays( d ).year() < year ) dt0 = dt0.addDays( 7 ); } return dt0; } /*! Find the week number of a date - QwtDate::FirstThursday\n Corresponding to ISO 8601 ( see QDate::weekNumber() ). - QwtDate::FirstDay\n Number of weeks that have begun since dateOfWeek0(). \param date Date \param type Option how to identify the first week \return Week number, starting with 1 */ int QwtDate::weekNumber( const QDate &date, Week0Type type ) { int weekNo; if ( type == QwtDate::FirstDay ) { const QDate day0 = dateOfWeek0( date.year(), type ); weekNo = day0.daysTo( date ) / 7 + 1; } else { weekNo = date.weekNumber(); } return weekNo; } /*! Offset in seconds from Coordinated Universal Time The offset depends on the time specification of dateTime: - Qt::UTC 0, dateTime has no offset - Qt::OffsetFromUTC returns dateTime.utcOffset() - Qt::LocalTime: number of seconds from the UTC For Qt::LocalTime the offset depends on the timezone and daylight savings. \param dateTime Datetime value \return Offset in seconds */ int QwtDate::utcOffset( const QDateTime &dateTime ) { int seconds = 0; switch( dateTime.timeSpec() ) { case Qt::UTC: { break; } case Qt::OffsetFromUTC: { #ifdef WORKBENCH_REPLACE_QT_DEPRECATED seconds = dateTime.offsetFromUtc(); #else seconds = dateTime.utcOffset(); #endif break; } default: { const QDateTime dt1( dateTime.date(), dateTime.time(), Qt::UTC ); seconds = dateTime.secsTo( dt1 ); } } return seconds; } /*! Translate a datetime into a string Beside the format expressions documented in QDateTime::toString() the following expressions are supported: - w\n week number: ( 1 - 53 ) - ww\n week number with a leading zero ( 01 - 53 ) \param dateTime Datetime value \param format Format string \param week0Type Specification of week 0 \return Datetime string \sa QDateTime::toString(), weekNumber(), QwtDateScaleDraw */ QString QwtDate::toString( const QDateTime &dateTime, const QString & format, Week0Type week0Type ) { QString weekNo; weekNo.setNum( QwtDate::weekNumber( dateTime.date(), week0Type ) ); QString weekNoWW; if ( weekNo.length() == 1 ) weekNoWW += "0"; weekNoWW += weekNo; QString fmt = format; fmt.replace( "ww", weekNoWW ); fmt.replace( "w", weekNo ); return dateTime.toString( fmt ); } connectome-workbench-1.4.2/src/Qwt/qwt_date.h000066400000000000000000000067321360521144700211660ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef _QWT_DATE_H_ #define _QWT_DATE_H_ #include "qwt_global.h" #include /*! \brief A collection of methods around date/time values Qt offers convenient classes for dealing with date/time values, but Qwt uses coordinate systems that are based on doubles. QwtDate offers methods to translate from QDateTime to double and v.v. A double is interpreted as the number of milliseconds since 1970-01-01T00:00:00 Universal Coordinated Time - also known as "The Epoch". While the range of the Julian day in Qt4 is limited to [0, MAX_INT], Qt5 stores it as qint64 offering a huge range of valid dates. As the significance of a double is below this ( assuming a fraction of 52 bits ) the translation is not bijective with rounding errors for dates very far from Epoch. For a resolution of 1 ms those start to happen for dates above the year 144683. An axis for a date/time interval is expected to be aligned and divided in time/date units like seconds, minutes, ... QwtDate offers several algorithms that are needed to calculate these axes. \sa QwtDateScaleEngine, QwtDateScaleDraw, QDate, QTime */ class QWT_EXPORT QwtDate { public: /*! How to identify the first week of year differs between countries. */ enum Week0Type { /*! According to ISO 8601 the first week of a year is defined as "the week with the year's first Thursday in it". FirstThursday corresponds to the numbering that is implemented in QDate::weekNumber(). */ FirstThursday, /*! "The week with January 1.1 in it." In the U.S. this definition is more common than FirstThursday. */ FirstDay }; /*! Classification of an time interval Time intervals needs to be classified to decide how to align and divide it. */ enum IntervalType { //! The interval is related to milliseconds Millisecond, //! The interval is related to seconds Second, //! The interval is related to minutes Minute, //! The interval is related to hours Hour, //! The interval is related to days Day, //! The interval is related to weeks Week, //! The interval is related to months Month, //! The interval is related to years Year }; enum { //! The Julian day of "The Epoch" JulianDayForEpoch = 2440588 }; static QDate minDate(); static QDate maxDate(); static QDateTime toDateTime( double value, Qt::TimeSpec = Qt::UTC ); static double toDouble( const QDateTime & ); static QDateTime ceil( const QDateTime &, IntervalType ); static QDateTime floor( const QDateTime &, IntervalType ); static QDate dateOfWeek0( int year, Week0Type ); static int weekNumber( const QDate &, Week0Type ); static int utcOffset( const QDateTime & ); static QString toString( const QDateTime &, const QString & format, Week0Type ); }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_date_scale_draw.cpp000066400000000000000000000161441360521144700237030ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_date_scale_draw.h" class QwtDateScaleDraw::PrivateData { public: PrivateData( Qt::TimeSpec spec ): timeSpec( spec ), utcOffset( 0 ), week0Type( QwtDate::FirstThursday ) { dateFormats[ QwtDate::Millisecond ] = "hh:mm:ss:zzz\nddd dd MMM yyyy"; dateFormats[ QwtDate::Second ] = "hh:mm:ss\nddd dd MMM yyyy"; dateFormats[ QwtDate::Minute ] = "hh:mm\nddd dd MMM yyyy"; dateFormats[ QwtDate::Hour ] = "hh:mm\nddd dd MMM yyyy"; dateFormats[ QwtDate::Day ] = "ddd dd MMM yyyy"; dateFormats[ QwtDate::Week ] = "Www yyyy"; dateFormats[ QwtDate::Month ] = "MMM yyyy"; dateFormats[ QwtDate::Year ] = "yyyy"; } Qt::TimeSpec timeSpec; int utcOffset; QwtDate::Week0Type week0Type; QString dateFormats[ QwtDate::Year + 1 ]; }; /*! \brief Constructor The default setting is to display tick labels for the given time specification. The first week of a year is defined like for QwtDate::FirstThursday. \param timeSpec Time specification \sa setTimeSpec(), setWeek0Type() */ QwtDateScaleDraw::QwtDateScaleDraw( Qt::TimeSpec timeSpec ) { d_data = new PrivateData( timeSpec ); } //! Destructor QwtDateScaleDraw::~QwtDateScaleDraw() { delete d_data; } /*! Set the time specification used for the tick labels \param timeSpec Time specification \sa timeSpec(), setUtcOffset(), toDateTime() */ void QwtDateScaleDraw::setTimeSpec( Qt::TimeSpec timeSpec ) { d_data->timeSpec = timeSpec; } /*! \return Time specification used for the tick labels \sa setTimeSpec(), utcOffset(), toDateTime() */ Qt::TimeSpec QwtDateScaleDraw::timeSpec() const { return d_data->timeSpec; } /*! Set the offset in seconds from Coordinated Universal Time \param seconds Offset in seconds \note The offset has no effect beside for the time specification Qt::OffsetFromUTC. \sa QDate::utcOffset(), setTimeSpec(), toDateTime() */ void QwtDateScaleDraw::setUtcOffset( int seconds ) { d_data->utcOffset = seconds; } /*! \return Offset in seconds from Coordinated Universal Time \note The offset has no effect beside for the time specification Qt::OffsetFromUTC. \sa QDate::setUtcOffset(), setTimeSpec(), toDateTime() */ int QwtDateScaleDraw::utcOffset() const { return d_data->utcOffset; } /*! Sets how to identify the first week of a year. \param week0Type Mode how to identify the first week of a year \sa week0Type(). \note week0Type has no effect beside for intervals classified as QwtDate::Week. */ void QwtDateScaleDraw::setWeek0Type( QwtDate::Week0Type week0Type ) { d_data->week0Type = week0Type; } /*! \return Setting how to identify the first week of a year. \sa setWeek0Type() */ QwtDate::Week0Type QwtDateScaleDraw::week0Type() const { return d_data->week0Type; } /*! Set the default format string for an datetime interval type \param intervalType Interval type \param format Default format string \sa dateFormat(), dateFormatOfDate(), QwtDate::toString() */ void QwtDateScaleDraw::setDateFormat( QwtDate::IntervalType intervalType, const QString &format ) { if ( intervalType >= QwtDate::Millisecond && intervalType <= QwtDate::Year ) { d_data->dateFormats[ intervalType ] = format; } } /*! \param intervalType Interval type \return Default format string for an datetime interval type \sa setDateFormat(), dateFormatOfDate() */ QString QwtDateScaleDraw::dateFormat( QwtDate::IntervalType intervalType ) const { if ( intervalType >= QwtDate::Millisecond && intervalType <= QwtDate::Year ) { return d_data->dateFormats[ intervalType ]; } return QString::null; } /*! Format string for the representation of a datetime dateFormatOfDate() is intended to be overloaded for situations, where formats are individual for specific datetime values. The default setting ignores dateTime and return the default format for the interval type. \param dateTime Datetime value \param intervalType Interval type \return Format string \sa setDateFormat(), QwtDate::toString() */ QString QwtDateScaleDraw::dateFormatOfDate( const QDateTime &dateTime, QwtDate::IntervalType intervalType ) const { Q_UNUSED( dateTime ) if ( intervalType >= QwtDate::Millisecond && intervalType <= QwtDate::Year ) { return d_data->dateFormats[ intervalType ]; } return d_data->dateFormats[ QwtDate::Second ]; } /*! \brief Convert a value into its representing label The value is converted to a datetime value using toDateTime() and converted to a plain text using QwtDate::toString(). \param value Value \return Label string. \sa dateFormatOfDate() */ QwtText QwtDateScaleDraw::label( double value ) const { const QDateTime dt = toDateTime( value ); const QString fmt = dateFormatOfDate( dt, intervalType( scaleDiv() ) ); return QwtDate::toString( dt, fmt, d_data->week0Type ); } /*! Find the less detailed datetime unit, where no rounding errors happen. \param scaleDiv Scale division \return Interval type \sa dateFormatOfDate() */ QwtDate::IntervalType QwtDateScaleDraw::intervalType( const QwtScaleDiv &scaleDiv ) const { int intvType = QwtDate::Year; bool alignedToWeeks = true; const QList ticks = scaleDiv.ticks( QwtScaleDiv::MajorTick ); for ( int i = 0; i < ticks.size(); i++ ) { const QDateTime dt = toDateTime( ticks[i] ); for ( int j = QwtDate::Second; j <= intvType; j++ ) { const QDateTime dt0 = QwtDate::floor( dt, static_cast( j ) ); if ( dt0 != dt ) { if ( j == QwtDate::Week ) { alignedToWeeks = false; } else { intvType = j - 1; break; } } } if ( intvType == QwtDate::Millisecond ) break; } if ( intvType == QwtDate::Week && !alignedToWeeks ) intvType = QwtDate::Day; return static_cast( intvType ); } /*! Translate a double value into a QDateTime object. \return QDateTime object initialized with timeSpec() and utcOffset(). \sa timeSpec(), utcOffset(), QwtDate::toDateTime() */ QDateTime QwtDateScaleDraw::toDateTime( double value ) const { QDateTime dt = QwtDate::toDateTime( value, d_data->timeSpec ); if ( d_data->timeSpec == Qt::OffsetFromUTC ) { dt = dt.addSecs( d_data->utcOffset ); #ifdef WORKBENCH_REPLACE_QT_DEPRECATED dt.setOffsetFromUtc( d_data->utcOffset ); #else dt.setUtcOffset( d_data->utcOffset ); #endif } return dt; } connectome-workbench-1.4.2/src/Qwt/qwt_date_scale_draw.h000066400000000000000000000042401360521144700233420ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef _QWT_DATE_SCALE_DRAW_H_ #define _QWT_DATE_SCALE_DRAW_H_ 1 #include "qwt_global.h" #include "qwt_scale_draw.h" #include "qwt_date.h" /*! \brief A class for drawing datetime scales QwtDateScaleDraw displays values as datetime labels. The format of the labels depends on the alignment of the major tick labels. The default format strings are: - Millisecond\n "hh:mm:ss:zzz\nddd dd MMM yyyy" - Second\n "hh:mm:ss\nddd dd MMM yyyy" - Minute\n "hh:mm\nddd dd MMM yyyy" - Hour\n "hh:mm\nddd dd MMM yyyy" - Day\n "ddd dd MMM yyyy" - Week\n "Www yyyy" - Month\n "MMM yyyy" - Year\n "yyyy" The format strings can be modified using setDateFormat() or individually for each tick label by overloading dateFormatOfDate(), Usually QwtDateScaleDraw is used in combination with QwtDateScaleEngine, that calculates scales for datetime intervals. \sa QwtDateScaleEngine, QwtPlot::setAxisScaleDraw() */ class QWT_EXPORT QwtDateScaleDraw: public QwtScaleDraw { public: QwtDateScaleDraw( Qt::TimeSpec = Qt::LocalTime ); virtual ~QwtDateScaleDraw(); void setDateFormat( QwtDate::IntervalType, const QString & ); QString dateFormat( QwtDate::IntervalType ) const; void setTimeSpec( Qt::TimeSpec ); Qt::TimeSpec timeSpec() const; void setUtcOffset( int seconds ); int utcOffset() const; void setWeek0Type( QwtDate::Week0Type ); QwtDate::Week0Type week0Type() const; virtual QwtText label( double ) const; QDateTime toDateTime( double ) const; protected: virtual QwtDate::IntervalType intervalType( const QwtScaleDiv & ) const; virtual QString dateFormatOfDate( const QDateTime &, QwtDate::IntervalType ) const; private: class PrivateData; PrivateData *d_data; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_date_scale_engine.cpp000066400000000000000000001072521360521144700242140ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_date_scale_engine.h" #include "qwt_math.h" #include "qwt_transform.h" #include #include static inline double qwtMsecsForType( QwtDate::IntervalType type ) { static const double msecs[] = { 1.0, 1000.0, 60.0 * 1000.0, 3600.0 * 1000.0, 24.0 * 3600.0 * 1000.0, 7.0 * 24.0 * 3600.0 * 1000.0, 30.0 * 24.0 * 3600.0 * 1000.0, 365.0 * 24.0 * 3600.0 * 1000.0, }; // eliminate compile time warning - JWH 9/16/2016 // if ( type < 0 || type >= static_cast( sizeof( msecs ) / sizeof( msecs[0] ) ) ) const int typeAsInt = static_cast(type); if ( typeAsInt < 0 || typeAsInt >= static_cast( sizeof( msecs ) / sizeof( msecs[0] ) ) ) return 1.0; return msecs[ type ]; } static inline int qwtAlignValue( double value, double stepSize, bool up ) { double d = value / stepSize; d = up ? ::ceil( d ) : ::floor( d ); return static_cast( d * stepSize ); } static double qwtIntervalWidth( const QDateTime &minDate, const QDateTime &maxDate, QwtDate::IntervalType intervalType ) { switch( intervalType ) { case QwtDate::Millisecond: { const double secsTo = minDate.secsTo( maxDate ); const double msecs = maxDate.time().msec() - minDate.time().msec(); return secsTo * 1000 + msecs; } case QwtDate::Second: { return minDate.secsTo( maxDate ); } case QwtDate::Minute: { const double secsTo = minDate.secsTo( maxDate ); return ::floor( secsTo / 60 ); } case QwtDate::Hour: { const double secsTo = minDate.secsTo( maxDate ); return ::floor( secsTo / 3600 ); } case QwtDate::Day: { return minDate.daysTo( maxDate ); } case QwtDate::Week: { return ::floor( minDate.daysTo( maxDate ) / 7.0 ); } case QwtDate::Month: { const double years = double( maxDate.date().year() ) - minDate.date().year(); int months = maxDate.date().month() - minDate.date().month(); if ( maxDate.date().day() < minDate.date().day() ) months--; return years * 12 + months; } case QwtDate::Year: { double years = double( maxDate.date().year() ) - minDate.date().year(); if ( maxDate.date().month() < minDate.date().month() ) years -= 1.0; return years; } } return 0.0; } static double qwtRoundedIntervalWidth( const QDateTime &minDate, const QDateTime &maxDate, QwtDate::IntervalType intervalType ) { const QDateTime minD = QwtDate::floor( minDate, intervalType ); const QDateTime maxD = QwtDate::ceil( maxDate, intervalType ); return qwtIntervalWidth( minD, maxD, intervalType ); } static inline int qwtStepCount( int intervalSize, int maxSteps, const int limits[], size_t numLimits ) { for ( uint i = 0; i < numLimits; i++ ) { const int numSteps = intervalSize / limits[ i ]; if ( numSteps > 1 && numSteps <= maxSteps && numSteps * limits[ i ] == intervalSize ) { return numSteps; } } return 0; } static int qwtStepSize( int intervalSize, int maxSteps, uint base ) { if ( maxSteps <= 0 ) return 0; if ( maxSteps > 2 ) { for ( int numSteps = maxSteps; numSteps > 1; numSteps-- ) { const double stepSize = double( intervalSize ) / numSteps; const double p = ::floor( ::log( stepSize ) / ::log( double( base ) ) ); const double fraction = qPow( base, p ); for ( uint n = base; n >= 1; n /= 2 ) { if ( qFuzzyCompare( stepSize, n * fraction ) ) return qRound( stepSize ); if ( n == 3 && ( base % 2 ) == 0 ) { if ( qFuzzyCompare( stepSize, 2 * fraction ) ) return qRound( stepSize ); } } } } return 0; } static int qwtDivideInterval( double intervalSize, int numSteps, const int limits[], size_t numLimits ) { const int v = qCeil( intervalSize / double( numSteps ) ); for ( uint i = 0; i < numLimits - 1; i++ ) { if ( v <= limits[i] ) return limits[i]; } return limits[ numLimits - 1 ]; } static double qwtDivideScale( double intervalSize, int numSteps, QwtDate::IntervalType intervalType ) { if ( intervalType != QwtDate::Day ) { if ( ( intervalSize > numSteps ) && ( intervalSize <= 2 * numSteps ) ) { return 2.0; } } double stepSize; switch( intervalType ) { case QwtDate::Second: case QwtDate::Minute: { static int limits[] = { 1, 2, 5, 10, 15, 20, 30, 60 }; stepSize = qwtDivideInterval( intervalSize, numSteps, limits, sizeof( limits ) / sizeof( int ) ); break; } case QwtDate::Hour: { static int limits[] = { 1, 2, 3, 4, 6, 12, 24 }; stepSize = qwtDivideInterval( intervalSize, numSteps, limits, sizeof( limits ) / sizeof( int ) ); break; } case QwtDate::Day: { const double v = intervalSize / double( numSteps ); if ( v <= 5.0 ) stepSize = qCeil( v ); else stepSize = qCeil( v / 7 ) * 7; break; } case QwtDate::Week: { static int limits[] = { 1, 2, 4, 8, 12, 26, 52 }; stepSize = qwtDivideInterval( intervalSize, numSteps, limits, sizeof( limits ) / sizeof( int ) ); break; } case QwtDate::Month: { static int limits[] = { 1, 2, 3, 4, 6, 12 }; stepSize = qwtDivideInterval( intervalSize, numSteps, limits, sizeof( limits ) / sizeof( int ) ); break; } case QwtDate::Year: case QwtDate::Millisecond: default: { stepSize = QwtScaleArithmetic::divideInterval( intervalSize, numSteps, 10 ); } } return stepSize; } static double qwtDivideMajorStep( double stepSize, int maxMinSteps, QwtDate::IntervalType intervalType ) { double minStepSize = 0.0; switch( intervalType ) { case QwtDate::Second: { minStepSize = qwtStepSize( stepSize, maxMinSteps, 10 ); if ( minStepSize == 0.0 ) minStepSize = 0.5 * stepSize; break; } case QwtDate::Minute: { static int limits[] = { 1, 2, 5, 10, 15, 20, 30, 60 }; int numSteps; if ( stepSize > maxMinSteps ) { numSteps = qwtStepCount( stepSize, maxMinSteps, limits, sizeof( limits ) / sizeof( int ) ); } else { numSteps = qwtStepCount( stepSize * 60, maxMinSteps, limits, sizeof( limits ) / sizeof( int ) ); } if ( numSteps > 0 ) minStepSize = double( stepSize ) / numSteps; break; } case QwtDate::Hour: { int numSteps = 0; if ( stepSize > maxMinSteps ) { static int limits[] = { 1, 2, 3, 4, 6, 12, 24, 48, 72 }; numSteps = qwtStepCount( stepSize, maxMinSteps, limits, sizeof( limits ) / sizeof( int ) ); } else { static int limits[] = { 1, 2, 5, 10, 15, 20, 30, 60 }; numSteps = qwtStepCount( stepSize * 60, maxMinSteps, limits, sizeof( limits ) / sizeof( int ) ); } if ( numSteps > 0 ) minStepSize = double( stepSize ) / numSteps; break; } case QwtDate::Day: { int numSteps = 0; if ( stepSize > maxMinSteps ) { static int limits[] = { 1, 2, 3, 7, 14, 28 }; numSteps = qwtStepCount( stepSize, maxMinSteps, limits, sizeof( limits ) / sizeof( int ) ); } else { static int limits[] = { 1, 2, 3, 4, 6, 12, 24, 48, 72 }; numSteps = qwtStepCount( stepSize * 24, maxMinSteps, limits, sizeof( limits ) / sizeof( int ) ); } if ( numSteps > 0 ) minStepSize = double( stepSize ) / numSteps; break; } case QwtDate::Week: { const int daysInStep = stepSize * 7; if ( maxMinSteps >= daysInStep ) { // we want to have one tick per day minStepSize = 1.0 / 7.0; } else { // when the stepSize is more than a week we want to // have a tick for each week const int stepSizeInWeeks = stepSize; if ( stepSizeInWeeks <= maxMinSteps ) { minStepSize = 1; } else { minStepSize = QwtScaleArithmetic::divideInterval( stepSizeInWeeks, maxMinSteps, 10 ); } } break; } case QwtDate::Month: { // fractions of months doesn't make any sense if ( stepSize < maxMinSteps ) maxMinSteps = static_cast( stepSize ); static int limits[] = { 1, 2, 3, 4, 6, 12 }; int numSteps = qwtStepCount( stepSize, maxMinSteps, limits, sizeof( limits ) / sizeof( int ) ); if ( numSteps > 0 ) minStepSize = double( stepSize ) / numSteps; break; } case QwtDate::Year: { if ( stepSize >= maxMinSteps ) { minStepSize = QwtScaleArithmetic::divideInterval( stepSize, maxMinSteps, 10 ); } else { // something in months static int limits[] = { 1, 2, 3, 4, 6, 12 }; int numSteps = qwtStepCount( 12 * stepSize, maxMinSteps, limits, sizeof( limits ) / sizeof( int ) ); if ( numSteps > 0 ) minStepSize = double( stepSize ) / numSteps; } break; } default: break; } if ( intervalType != QwtDate::Month && minStepSize == 0.0 ) { minStepSize = 0.5 * stepSize; } return minStepSize; } static QList qwtDstTicks( const QDateTime &dateTime, int secondsMajor, int secondsMinor ) { if ( secondsMinor <= 0 ) QList(); QDateTime minDate = dateTime.addSecs( -secondsMajor ); minDate = QwtDate::floor( minDate, QwtDate::Hour ); const double utcOffset = QwtDate::utcOffset( dateTime ); // find the hours where daylight saving time happens double dstMin = QwtDate::toDouble( minDate ); while ( minDate < dateTime && QwtDate::utcOffset( minDate ) != utcOffset ) { minDate = minDate.addSecs( 3600 ); dstMin += 3600 * 1000.0; } QList ticks; for ( int i = 0; i < 3600; i += secondsMinor ) ticks += dstMin + i * 1000.0; return ticks; } static QwtScaleDiv qwtDivideToSeconds( const QDateTime &minDate, const QDateTime &maxDate, double stepSize, int maxMinSteps, QwtDate::IntervalType intervalType ) { // calculate the min step size double minStepSize = 0; if ( maxMinSteps > 1 ) { minStepSize = qwtDivideMajorStep( stepSize, maxMinSteps, intervalType ); } bool daylightSaving = false; if ( minDate.timeSpec() == Qt::LocalTime ) { daylightSaving = intervalType > QwtDate::Hour; if ( intervalType == QwtDate::Hour ) { daylightSaving = stepSize > 1; } } const double s = qwtMsecsForType( intervalType ) / 1000; const int secondsMajor = static_cast( stepSize * s ); const double secondsMinor = minStepSize * s; // UTC excludes daylight savings. So from the difference // of a date and its UTC counterpart we can find out // the daylight saving hours const double utcOffset = QwtDate::utcOffset( minDate ); double dstOff = 0; QList majorTicks; QList mediumTicks; QList minorTicks; for ( QDateTime dt = minDate; dt <= maxDate; dt = dt.addSecs( secondsMajor ) ) { if ( !dt.isValid() ) break; double majorValue = QwtDate::toDouble( dt ); if ( daylightSaving ) { const double offset = utcOffset - QwtDate::utcOffset( dt ); majorValue += offset * 1000.0; if ( offset > dstOff ) { // we add some minor ticks for the DST hour, // otherwise the ticks will be unaligned: 0, 2, 3, 5 ... minorTicks += qwtDstTicks( dt, secondsMajor, qRound( secondsMinor ) ); } dstOff = offset; } if ( majorTicks.isEmpty() || majorTicks.last() != majorValue ) majorTicks += majorValue; if ( secondsMinor > 0.0 ) { const int numMinorSteps = qFloor( secondsMajor / secondsMinor ); for ( int i = 1; i < numMinorSteps; i++ ) { const QDateTime mt = dt.addMSecs( qRound64( i * secondsMinor * 1000 ) ); double minorValue = QwtDate::toDouble( mt ); if ( daylightSaving ) { const double offset = utcOffset - QwtDate::utcOffset( mt ); minorValue += offset * 1000.0; } if ( minorTicks.isEmpty() || minorTicks.last() != minorValue ) { const bool isMedium = ( numMinorSteps % 2 == 0 ) && ( i != 1 ) && ( i == numMinorSteps / 2 ); if ( isMedium ) mediumTicks += minorValue; else minorTicks += minorValue; } } } } QwtScaleDiv scaleDiv; scaleDiv.setInterval( QwtDate::toDouble( minDate ), QwtDate::toDouble( maxDate ) ); scaleDiv.setTicks( QwtScaleDiv::MajorTick, majorTicks ); scaleDiv.setTicks( QwtScaleDiv::MediumTick, mediumTicks ); scaleDiv.setTicks( QwtScaleDiv::MinorTick, minorTicks ); return scaleDiv; } static QwtScaleDiv qwtDivideToMonths( QDateTime &minDate, const QDateTime &maxDate, double stepSize, int maxMinSteps ) { // months are intervals with non // equidistant ( in ms ) steps: we have to build the // scale division manually int minStepDays = 0; int minStepSize = 0.0; if ( maxMinSteps > 1 ) { if ( stepSize == 1 ) { if ( maxMinSteps >= 30 ) minStepDays = 1; else if ( maxMinSteps >= 6 ) minStepDays = 5; else if ( maxMinSteps >= 3 ) minStepDays = 10; minStepDays = 15; } else { minStepSize = qwtDivideMajorStep( stepSize, maxMinSteps, QwtDate::Month ); } } QList majorTicks; QList mediumTicks; QList minorTicks; for ( QDateTime dt = minDate; dt <= maxDate; dt = dt.addMonths( stepSize ) ) { if ( !dt.isValid() ) break; majorTicks += QwtDate::toDouble( dt ); if ( minStepDays > 0 ) { for ( int days = minStepDays; days < 30; days += minStepDays ) { const double tick = QwtDate::toDouble( dt.addDays( days ) ); if ( days == 15 && minStepDays != 15 ) mediumTicks += tick; else minorTicks += tick; } } else if ( minStepSize > 0.0 ) { const int numMinorSteps = qRound( stepSize / (double) minStepSize ); for ( int i = 1; i < numMinorSteps; i++ ) { const double minorValue = QwtDate::toDouble( dt.addMonths( i * minStepSize ) ); if ( ( numMinorSteps % 2 == 0 ) && ( i == numMinorSteps / 2 ) ) mediumTicks += minorValue; else minorTicks += minorValue; } } } QwtScaleDiv scaleDiv; scaleDiv.setInterval( QwtDate::toDouble( minDate ), QwtDate::toDouble( maxDate ) ); scaleDiv.setTicks( QwtScaleDiv::MajorTick, majorTicks ); scaleDiv.setTicks( QwtScaleDiv::MediumTick, mediumTicks ); scaleDiv.setTicks( QwtScaleDiv::MinorTick, minorTicks ); return scaleDiv; } static QwtScaleDiv qwtDivideToYears( const QDateTime &minDate, const QDateTime &maxDate, double stepSize, int maxMinSteps ) { QList majorTicks; QList mediumTicks; QList minorTicks; double minStepSize = 0.0; if ( maxMinSteps > 1 ) { minStepSize = qwtDivideMajorStep( stepSize, maxMinSteps, QwtDate::Year ); } int numMinorSteps = 0; if ( minStepSize > 0.0 ) numMinorSteps = qFloor( stepSize / minStepSize ); bool dateBC = minDate.date().year() < -1; for ( QDateTime dt = minDate; dt <= maxDate; dt = dt.addYears( stepSize ) ) { if ( dateBC && dt.date().year() > 1 ) { // there is no year 0 in the Julian calendar dt = dt.addYears( -1 ); dateBC = false; } if ( !dt.isValid() ) break; majorTicks += QwtDate::toDouble( dt ); for ( int i = 1; i < numMinorSteps; i++ ) { QDateTime tickDate; const double years = qRound( i * minStepSize ); if ( years >= INT_MAX / 12 ) { tickDate = dt.addYears( years ); } else { tickDate = dt.addMonths( qRound( years * 12 ) ); } const bool isMedium = ( numMinorSteps > 2 ) && ( numMinorSteps % 2 == 0 ) && ( i == numMinorSteps / 2 ); const double minorValue = QwtDate::toDouble( tickDate ); if ( isMedium ) mediumTicks += minorValue; else minorTicks += minorValue; } if ( QwtDate::maxDate().addYears( -stepSize ) < dt.date() ) { break; } } QwtScaleDiv scaleDiv; scaleDiv.setInterval( QwtDate::toDouble( minDate ), QwtDate::toDouble( maxDate ) ); scaleDiv.setTicks( QwtScaleDiv::MajorTick, majorTicks ); scaleDiv.setTicks( QwtScaleDiv::MediumTick, mediumTicks ); scaleDiv.setTicks( QwtScaleDiv::MinorTick, minorTicks ); return scaleDiv; } class QwtDateScaleEngine::PrivateData { public: PrivateData( Qt::TimeSpec spec ): timeSpec( spec ), utcOffset( 0 ), week0Type( QwtDate::FirstThursday ), maxWeeks( 4 ) { } Qt::TimeSpec timeSpec; int utcOffset; QwtDate::Week0Type week0Type; int maxWeeks; }; /*! \brief Constructor The engine is initialized to build scales for the given time specification. It classifies intervals > 4 weeks as >= Qt::Month. The first week of a year is defined like for QwtDate::FirstThursday. \param timeSpec Time specification \sa setTimeSpec(), setMaxWeeks(), setWeek0Type() */ QwtDateScaleEngine::QwtDateScaleEngine( Qt::TimeSpec timeSpec ): QwtLinearScaleEngine( 10 ) { d_data = new PrivateData( timeSpec ); } //! Destructor QwtDateScaleEngine::~QwtDateScaleEngine() { delete d_data; } /*! Set the time specification used by the engine \param timeSpec Time specification \sa timeSpec(), setUtcOffset(), toDateTime() */ void QwtDateScaleEngine::setTimeSpec( Qt::TimeSpec timeSpec ) { d_data->timeSpec = timeSpec; } /*! \return Time specification used by the engine \sa setTimeSpec(), utcOffset(), toDateTime() */ Qt::TimeSpec QwtDateScaleEngine::timeSpec() const { return d_data->timeSpec; } /*! Set the offset in seconds from Coordinated Universal Time \param seconds Offset in seconds \note The offset has no effect beside for the time specification Qt::OffsetFromUTC. \sa QDate::utcOffset(), setTimeSpec(), toDateTime() */ void QwtDateScaleEngine::setUtcOffset( int seconds ) { d_data->utcOffset = seconds; } /*! \return Offset in seconds from Coordinated Universal Time \note The offset has no effect beside for the time specification Qt::OffsetFromUTC. \sa QDate::setUtcOffset(), setTimeSpec(), toDateTime() */ int QwtDateScaleEngine::utcOffset() const { return d_data->utcOffset; } /*! Sets how to identify the first week of a year. \param week0Type Mode how to identify the first week of a year \sa week0Type(), setMaxWeeks() \note week0Type has no effect beside for intervals classified as QwtDate::Week. */ void QwtDateScaleEngine::setWeek0Type( QwtDate::Week0Type week0Type ) { d_data->week0Type = week0Type; } /*! \return Setting how to identify the first week of a year. \sa setWeek0Type(), maxWeeks() */ QwtDate::Week0Type QwtDateScaleEngine::week0Type() const { return d_data->week0Type; } /*! Set a upper limit for the number of weeks, when an interval can be classified as Qt::Week. The default setting is 4 weeks. \param weeks Upper limit for the number of weeks \note In business charts a year is often devided into weeks [1-52] \sa maxWeeks(), setWeek0Type() */ void QwtDateScaleEngine::setMaxWeeks( int weeks ) { d_data->maxWeeks = qMax( weeks, 0 ); } /*! \return Upper limit for the number of weeks, when an interval can be classified as Qt::Week. \sa setMaxWeeks(), week0Type() */ int QwtDateScaleEngine::maxWeeks() const { return d_data->maxWeeks; } /*! Classification of a date/time interval division \param minDate Minimum ( = earlier ) of the interval \param maxDate Maximum ( = later ) of the interval \param maxSteps Maximum for the number of steps \return Interval classification */ QwtDate::IntervalType QwtDateScaleEngine::intervalType( const QDateTime &minDate, const QDateTime &maxDate, int maxSteps ) const { const double jdMin = minDate.date().toJulianDay(); const double jdMax = maxDate.date().toJulianDay(); if ( ( jdMax - jdMin ) / 365 > maxSteps ) return QwtDate::Year; const int months = qwtRoundedIntervalWidth( minDate, maxDate, QwtDate::Month ); if ( months > maxSteps * 6 ) return QwtDate::Year; const int days = qwtRoundedIntervalWidth( minDate, maxDate, QwtDate::Day ); const int weeks = qwtRoundedIntervalWidth( minDate, maxDate, QwtDate::Week ); if ( weeks > d_data->maxWeeks ) { if ( days > 4 * maxSteps * 7 ) return QwtDate::Month; } if ( days > maxSteps * 7 ) return QwtDate::Week; const int hours = qwtRoundedIntervalWidth( minDate, maxDate, QwtDate::Hour ); if ( hours > maxSteps * 24 ) return QwtDate::Day; const int seconds = qwtRoundedIntervalWidth( minDate, maxDate, QwtDate::Second ); if ( seconds >= maxSteps * 3600 ) return QwtDate::Hour; if ( seconds >= maxSteps * 60 ) return QwtDate::Minute; if ( seconds >= maxSteps ) return QwtDate::Second; return QwtDate::Millisecond; } /*! Align and divide an interval The algorithm aligns and divides the interval into steps. Datetime interval divisions are usually not equidistant and the calculated stepSize can only be used as an approximation for the steps calculated by divideScale(). \param maxNumSteps Max. number of steps \param x1 First limit of the interval (In/Out) \param x2 Second limit of the interval (In/Out) \param stepSize Step size (Out) \sa QwtScaleEngine::setAttribute() */ void QwtDateScaleEngine::autoScale( int maxNumSteps, double &x1, double &x2, double &stepSize ) const { stepSize = 0.0; QwtInterval interval( x1, x2 ); interval = interval.normalized(); interval.setMinValue( interval.minValue() - lowerMargin() ); interval.setMaxValue( interval.maxValue() + upperMargin() ); if ( testAttribute( QwtScaleEngine::Symmetric ) ) interval = interval.symmetrize( reference() ); if ( testAttribute( QwtScaleEngine::IncludeReference ) ) interval = interval.extend( reference() ); if ( interval.width() == 0.0 ) interval = buildInterval( interval.minValue() ); const QDateTime from = toDateTime( interval.minValue() ); const QDateTime to = toDateTime( interval.maxValue() ); if ( from.isValid() && to.isValid() ) { if ( maxNumSteps < 1 ) maxNumSteps = 1; const QwtDate::IntervalType intvType = intervalType( from, to, maxNumSteps ); const double width = qwtIntervalWidth( from, to, intvType ); const double stepWidth = qwtDivideScale( width, maxNumSteps, intvType ); if ( stepWidth != 0.0 && !testAttribute( QwtScaleEngine::Floating ) ) { const QDateTime d1 = alignDate( from, stepWidth, intvType, false ); const QDateTime d2 = alignDate( to, stepWidth, intvType, true ); interval.setMinValue( QwtDate::toDouble( d1 ) ); interval.setMaxValue( QwtDate::toDouble( d2 ) ); } stepSize = stepWidth * qwtMsecsForType( intvType ); } x1 = interval.minValue(); x2 = interval.maxValue(); if ( testAttribute( QwtScaleEngine::Inverted ) ) { qSwap( x1, x2 ); stepSize = -stepSize; } } /*! \brief Calculate a scale division for a date/time interval \param x1 First interval limit \param x2 Second interval limit \param maxMajorSteps Maximum for the number of major steps \param maxMinorSteps Maximum number of minor steps \param stepSize Step size. If stepSize == 0, the scaleEngine calculates one. \return Calculated scale division */ QwtScaleDiv QwtDateScaleEngine::divideScale( double x1, double x2, int maxMajorSteps, int maxMinorSteps, double stepSize ) const { if ( maxMajorSteps < 1 ) maxMajorSteps = 1; const double min = qMin( x1, x2 ); const double max = qMax( x1, x2 ); const QDateTime from = toDateTime( min ); const QDateTime to = toDateTime( max ); if ( from == to ) return QwtScaleDiv(); stepSize = qAbs( stepSize ); if ( stepSize > 0.0 ) { // as interval types above hours are not equidistant // ( even days might have 23/25 hours because of daylight saving ) // the stepSize is used as a hint only maxMajorSteps = qCeil( ( max - min ) / stepSize ); } const QwtDate::IntervalType intvType = intervalType( from, to, maxMajorSteps ); QwtScaleDiv scaleDiv; if ( intvType == QwtDate::Millisecond ) { // for milliseconds and below we can use the decimal system scaleDiv = QwtLinearScaleEngine::divideScale( min, max, maxMajorSteps, maxMinorSteps, stepSize ); } else { const QDateTime minDate = QwtDate::floor( from, intvType ); const QDateTime maxDate = QwtDate::ceil( to, intvType ); scaleDiv = buildScaleDiv( minDate, maxDate, maxMajorSteps, maxMinorSteps, intvType ); // scaleDiv has been calculated from an extended interval // adjusted to the step size. We have to shrink it again. scaleDiv = scaleDiv.bounded( min, max ); } if ( x1 > x2 ) scaleDiv.invert(); return scaleDiv; } QwtScaleDiv QwtDateScaleEngine::buildScaleDiv( const QDateTime &minDate, const QDateTime &maxDate, int maxMajorSteps, int maxMinorSteps, QwtDate::IntervalType intervalType ) const { // calculate the step size const double stepSize = qwtDivideScale( qwtIntervalWidth( minDate, maxDate, intervalType ), maxMajorSteps, intervalType ); // align minDate to the step size QDateTime dt0 = alignDate( minDate, stepSize, intervalType, false ); if ( !dt0.isValid() ) { // the floored date is out of the range of a // QDateTime - we ceil instead. dt0 = alignDate( minDate, stepSize, intervalType, true ); } QwtScaleDiv scaleDiv; if ( intervalType <= QwtDate::Week ) { scaleDiv = qwtDivideToSeconds( dt0, maxDate, stepSize, maxMinorSteps, intervalType ); } else { if( intervalType == QwtDate::Month ) { scaleDiv = qwtDivideToMonths( dt0, maxDate, stepSize, maxMinorSteps ); } else if ( intervalType == QwtDate::Year ) { scaleDiv = qwtDivideToYears( dt0, maxDate, stepSize, maxMinorSteps ); } } return scaleDiv; } /*! Align a date/time value for a step size For Qt::Day alignments there is no "natural day 0" - instead the first day of the year is used to avoid jumping major ticks positions when panning a scale. For other alignments ( f.e according to the first day of the month ) alignDate() has to be overloaded. \param dateTime Date/time value \param stepSize Step size \param intervalType Interval type \param up When true dateTime is ceiled - otherwise it is floored \return Aligned date/time value */ QDateTime QwtDateScaleEngine::alignDate( const QDateTime &dateTime, double stepSize, QwtDate::IntervalType intervalType, bool up ) const { // what about: (year == 1582 && month == 10 && day > 4 && day < 15) ?? QDateTime dt = dateTime; if ( dateTime.timeSpec() == Qt::OffsetFromUTC ) { dt = dt.addSecs( d_data->utcOffset ); #ifdef WORKBENCH_REPLACE_QT_DEPRECATED dt.setOffsetFromUtc( 0 ); #else dt.setUtcOffset( 0 ); #endif } switch( intervalType ) { case QwtDate::Millisecond: { const int ms = qwtAlignValue( dt.time().msec(), stepSize, up ) ; dt = QwtDate::floor( dateTime, QwtDate::Second ); dt = dt.addMSecs( ms ); break; } case QwtDate::Second: { int second = dt.time().second(); if ( up ) { if ( dt.time().msec() > 0 ) second++; } const int s = qwtAlignValue( second, stepSize, up ); dt = QwtDate::floor( dt, QwtDate::Minute ); dt = dt.addSecs( s ); break; } case QwtDate::Minute: { int minute = dt.time().minute(); if ( up ) { if ( dt.time().msec() > 0 || dt.time().second() > 0 ) minute++; } const int m = qwtAlignValue( minute, stepSize, up ); dt = QwtDate::floor( dt, QwtDate::Hour ); dt = dt.addSecs( m * 60 ); break; } case QwtDate::Hour: { int hour = dt.time().hour(); if ( up ) { if ( dt.time().msec() > 0 || dt.time().second() > 0 || dt.time().minute() > 0 ) { hour++; } } const int h = qwtAlignValue( hour, stepSize, up ); dt = QwtDate::floor( dt, QwtDate::Day ); dt = dt.addSecs( h * 3600 ); break; } case QwtDate::Day: { // What date do we expect f.e. from an alignment of 5 days ?? // Aligning them to the beginning of the year avoids at least // jumping major ticks when panning int day = dt.date().dayOfYear(); if ( up ) { if ( dt.time() > QTime( 0, 0 ) ) day++; } const int d = qwtAlignValue( day, stepSize, up ); dt = QwtDate::floor( dt, QwtDate::Year ); dt = dt.addDays( d - 1 ); break; } case QwtDate::Week: { const QDate date = QwtDate::dateOfWeek0( dt.date().year(), d_data->week0Type ); int numWeeks = date.daysTo( dt.date() ) / 7; if ( up ) { if ( dt.time() > QTime( 0, 0 ) || date.daysTo( dt.date() ) % 7 ) { numWeeks++; } } const int d = qwtAlignValue( numWeeks, stepSize, up ) * 7; dt = QwtDate::floor( dt, QwtDate::Day ); dt.setDate( date ); dt = dt.addDays( d ); break; } case QwtDate::Month: { int month = dt.date().month(); if ( up ) { if ( dt.date().day() > 1 || dt.time() > QTime( 0, 0 ) ) { month++; } } const int m = qwtAlignValue( month - 1, stepSize, up ); dt = QwtDate::floor( dt, QwtDate::Year ); dt = dt.addMonths( m ); break; } case QwtDate::Year: { int year = dateTime.date().year(); if ( up ) { if ( dateTime.date().dayOfYear() > 1 || dt.time() > QTime( 0, 0 ) ) { year++; } } const int y = qwtAlignValue( year, stepSize, up ); dt = QwtDate::floor( dt, QwtDate::Day ); if ( y == 0 ) { // there is no year 0 in the Julian calendar dt.setDate( QDate( stepSize, 1, 1 ).addYears( -stepSize ) ); } else { dt.setDate( QDate( y, 1, 1 ) ); } break; } } if ( dateTime.timeSpec() == Qt::OffsetFromUTC ) { dt = dt.addSecs( d_data->utcOffset ); #ifdef WORKBENCH_REPLACE_QT_DEPRECATED dt.setOffsetFromUtc( dateTime.offsetFromUtc() ); #else dt.setUtcOffset( dateTime.utcOffset() ); #endif } return dt; } /*! Translate a double value into a QDateTime object. For QDateTime result is bounded by QwtDate::minDate() and QwtDate::maxDate() \return QDateTime object initialized with timeSpec() and utcOffset(). \sa timeSpec(), utcOffset(), QwtDate::toDateTime() */ QDateTime QwtDateScaleEngine::toDateTime( double value ) const { QDateTime dt = QwtDate::toDateTime( value, d_data->timeSpec ); if ( !dt.isValid() ) { const QDate date = ( value <= 0.0 ) ? QwtDate::minDate() : QwtDate::maxDate(); dt = QDateTime( date, QTime( 0, 0 ), d_data->timeSpec ); } if ( d_data->timeSpec == Qt::OffsetFromUTC ) { dt = dt.addSecs( d_data->utcOffset ); dt = dt.addSecs( d_data->utcOffset ); #ifdef WORKBENCH_REPLACE_QT_DEPRECATED dt.setOffsetFromUtc( d_data->utcOffset ); #else dt.setUtcOffset( d_data->utcOffset ); #endif } return dt; } connectome-workbench-1.4.2/src/Qwt/qwt_date_scale_engine.h000066400000000000000000000051611360521144700236550ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef _QWT_DATE_SCALE_ENGINE_H_ #define _QWT_DATE_SCALE_ENGINE_H_ 1 #include "qwt_date.h" #include "qwt_scale_engine.h" /*! \brief A scale engine for date/time values QwtDateScaleEngine builds scales from a time intervals. Together with QwtDateScaleDraw it can be used for axes according to date/time values. Years, months, weeks, days, hours and minutes are organized in steps with non constant intervals. QwtDateScaleEngine classifies intervals and aligns the boundaries and tick positions according to this classification. QwtDateScaleEngine supports representations depending on Qt::TimeSpec specifications. The valid range for scales is limited by the range of QDateTime, that differs between Qt4 and Qt5. Datetime values are expected as the number of milliseconds since 1970-01-01T00:00:00 Universal Coordinated Time - also known as "The Epoch", that can be converted to QDateTime using QwtDate::toDateTime(). \sa QwtDate, QwtPlot::setAxisScaleEngine(), QwtAbstractScale::setScaleEngine() */ class QWT_EXPORT QwtDateScaleEngine: public QwtLinearScaleEngine { public: QwtDateScaleEngine( Qt::TimeSpec = Qt::LocalTime ); virtual ~QwtDateScaleEngine(); void setTimeSpec( Qt::TimeSpec ); Qt::TimeSpec timeSpec() const; void setUtcOffset( int seconds ); int utcOffset() const; void setWeek0Type( QwtDate::Week0Type ); QwtDate::Week0Type week0Type() const; void setMaxWeeks( int ); int maxWeeks() const; virtual void autoScale( int maxNumSteps, double &x1, double &x2, double &stepSize ) const; virtual QwtScaleDiv divideScale( double x1, double x2, int maxMajorSteps, int maxMinorSteps, double stepSize = 0.0 ) const; virtual QwtDate::IntervalType intervalType( const QDateTime &, const QDateTime &, int maxSteps ) const; QDateTime toDateTime( double ) const; protected: virtual QDateTime alignDate( const QDateTime &, double stepSize, QwtDate::IntervalType, bool up ) const; private: QwtScaleDiv buildScaleDiv( const QDateTime &, const QDateTime &, int maxMajorSteps, int maxMinorSteps, QwtDate::IntervalType ) const; private: class PrivateData; PrivateData *d_data; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_dyngrid_layout.cpp000066400000000000000000000342151360521144700236360ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_dyngrid_layout.h" #include "qwt_math.h" #include #include class QwtDynGridLayout::PrivateData { public: PrivateData(): isDirty( true ) { } void updateLayoutCache(); mutable QList itemList; uint maxColumns; uint numRows; uint numColumns; Qt::Orientations expanding; bool isDirty; QVector itemSizeHints; }; void QwtDynGridLayout::PrivateData::updateLayoutCache() { itemSizeHints.resize( itemList.count() ); int index = 0; for ( QList::iterator it = itemList.begin(); it != itemList.end(); ++it, index++ ) { itemSizeHints[ index ] = ( *it )->sizeHint(); } isDirty = false; } /*! \param parent Parent widget \param margin Margin \param spacing Spacing */ QwtDynGridLayout::QwtDynGridLayout( QWidget *parent, int margin, int spacing ): QLayout( parent ) { init(); setSpacing( spacing ); setMargin( margin ); } /*! \param spacing Spacing */ QwtDynGridLayout::QwtDynGridLayout( int spacing ) { init(); setSpacing( spacing ); } /*! Initialize the layout with default values. */ void QwtDynGridLayout::init() { d_data = new QwtDynGridLayout::PrivateData; d_data->maxColumns = d_data->numRows = d_data->numColumns = 0; d_data->expanding = 0; } //! Destructor QwtDynGridLayout::~QwtDynGridLayout() { for ( int i = 0; i < d_data->itemList.size(); i++ ) delete d_data->itemList[i]; delete d_data; } //! Invalidate all internal caches void QwtDynGridLayout::invalidate() { d_data->isDirty = true; QLayout::invalidate(); } /*! Limit the number of columns. \param maxColumns upper limit, 0 means unlimited \sa maxColumns() */ void QwtDynGridLayout::setMaxColumns( uint maxColumns ) { d_data->maxColumns = maxColumns; } /*! \brief Return the upper limit for the number of columns. 0 means unlimited, what is the default. \return Upper limit for the number of columns \sa setMaxColumns() */ uint QwtDynGridLayout::maxColumns() const { return d_data->maxColumns; } /*! \brief Add an item to the next free position. \param item Layout item */ void QwtDynGridLayout::addItem( QLayoutItem *item ) { d_data->itemList.append( item ); invalidate(); } /*! \return true if this layout is empty. */ bool QwtDynGridLayout::isEmpty() const { return d_data->itemList.isEmpty(); } /*! \return number of layout items */ uint QwtDynGridLayout::itemCount() const { return d_data->itemList.count(); } /*! Find the item at a specific index \param index Index \return Item at a specific index \sa takeAt() */ QLayoutItem *QwtDynGridLayout::itemAt( int index ) const { if ( index < 0 || index >= d_data->itemList.count() ) return NULL; return d_data->itemList.at( index ); } /*! Find the item at a specific index and remove it from the layout \param index Index \return Layout item, removed from the layout \sa itemAt() */ QLayoutItem *QwtDynGridLayout::takeAt( int index ) { if ( index < 0 || index >= d_data->itemList.count() ) return NULL; d_data->isDirty = true; return d_data->itemList.takeAt( index ); } //! \return Number of items in the layout int QwtDynGridLayout::count() const { return d_data->itemList.count(); } /*! Set whether this layout can make use of more space than sizeHint(). A value of Qt::Vertical or Qt::Horizontal means that it wants to grow in only one dimension, while Qt::Vertical | Qt::Horizontal means that it wants to grow in both dimensions. The default value is 0. \param expanding Or'd orientations \sa expandingDirections() */ void QwtDynGridLayout::setExpandingDirections( Qt::Orientations expanding ) { d_data->expanding = expanding; } /*! \brief Returns whether this layout can make use of more space than sizeHint(). A value of Qt::Vertical or Qt::Horizontal means that it wants to grow in only one dimension, while Qt::Vertical | Qt::Horizontal means that it wants to grow in both dimensions. \return Orientations, where the layout expands \sa setExpandingDirections() */ Qt::Orientations QwtDynGridLayout::expandingDirections() const { return d_data->expanding; } /*! Reorganizes columns and rows and resizes managed items within a rectangle. \param rect Layout geometry */ void QwtDynGridLayout::setGeometry( const QRect &rect ) { QLayout::setGeometry( rect ); if ( isEmpty() ) return; d_data->numColumns = columnsForWidth( rect.width() ); d_data->numRows = itemCount() / d_data->numColumns; if ( itemCount() % d_data->numColumns ) d_data->numRows++; QList itemGeometries = layoutItems( rect, d_data->numColumns ); int index = 0; for ( QList::iterator it = d_data->itemList.begin(); it != d_data->itemList.end(); ++it ) { ( *it )->setGeometry( itemGeometries[index] ); index++; } } /*! \brief Calculate the number of columns for a given width. The calculation tries to use as many columns as possible ( limited by maxColumns() ) \param width Available width for all columns \return Number of columns for a given width \sa maxColumns(), setMaxColumns() */ uint QwtDynGridLayout::columnsForWidth( int width ) const { if ( isEmpty() ) return 0; uint maxColumns = itemCount(); if ( d_data->maxColumns > 0 ) maxColumns = qMin( d_data->maxColumns, maxColumns ); if ( maxRowWidth( maxColumns ) <= width ) return maxColumns; for ( uint numColumns = 2; numColumns <= maxColumns; numColumns++ ) { const int rowWidth = maxRowWidth( numColumns ); if ( rowWidth > width ) return numColumns - 1; } return 1; // At least 1 column } /*! Calculate the width of a layout for a given number of columns. \param numColumns Given number of columns \param itemWidth Array of the width hints for all items */ int QwtDynGridLayout::maxRowWidth( int numColumns ) const { int col; QVector colWidth( numColumns ); for ( col = 0; col < numColumns; col++ ) colWidth[col] = 0; if ( d_data->isDirty ) d_data->updateLayoutCache(); for ( int index = 0; index < d_data->itemSizeHints.count(); index++ ) { col = index % numColumns; colWidth[col] = qMax( colWidth[col], d_data->itemSizeHints[int( index )].width() ); } int rowWidth = 2 * margin() + ( numColumns - 1 ) * spacing(); for ( col = 0; col < numColumns; col++ ) rowWidth += colWidth[col]; return rowWidth; } /*! \return the maximum width of all layout items */ int QwtDynGridLayout::maxItemWidth() const { if ( isEmpty() ) return 0; if ( d_data->isDirty ) d_data->updateLayoutCache(); int w = 0; for ( int i = 0; i < d_data->itemSizeHints.count(); i++ ) { const int itemW = d_data->itemSizeHints[i].width(); if ( itemW > w ) w = itemW; } return w; } /*! Calculate the geometries of the layout items for a layout with numColumns columns and a given rectangle. \param rect Rect where to place the items \param numColumns Number of columns \return item geometries */ QList QwtDynGridLayout::layoutItems( const QRect &rect, uint numColumns ) const { QList itemGeometries; if ( numColumns == 0 || isEmpty() ) return itemGeometries; uint numRows = itemCount() / numColumns; if ( numColumns % itemCount() ) numRows++; if ( numRows == 0 ) return itemGeometries; QVector rowHeight( numRows ); QVector colWidth( numColumns ); layoutGrid( numColumns, rowHeight, colWidth ); bool expandH, expandV; expandH = expandingDirections() & Qt::Horizontal; expandV = expandingDirections() & Qt::Vertical; if ( expandH || expandV ) stretchGrid( rect, numColumns, rowHeight, colWidth ); const int maxColumns = d_data->maxColumns; d_data->maxColumns = numColumns; const QRect alignedRect = alignmentRect( rect ); d_data->maxColumns = maxColumns; const int xOffset = expandH ? 0 : alignedRect.x(); const int yOffset = expandV ? 0 : alignedRect.y(); QVector colX( numColumns ); QVector rowY( numRows ); const int xySpace = spacing(); rowY[0] = yOffset + margin(); for ( uint r = 1; r < numRows; r++ ) rowY[r] = rowY[r-1] + rowHeight[r-1] + xySpace; colX[0] = xOffset + margin(); for ( uint c = 1; c < numColumns; c++ ) colX[c] = colX[c-1] + colWidth[c-1] + xySpace; const int itemCount = d_data->itemList.size(); for ( int i = 0; i < itemCount; i++ ) { const int row = i / numColumns; const int col = i % numColumns; QRect itemGeometry( colX[col], rowY[row], colWidth[col], rowHeight[row] ); itemGeometries.append( itemGeometry ); } return itemGeometries; } /*! Calculate the dimensions for the columns and rows for a grid of numColumns columns. \param numColumns Number of columns. \param rowHeight Array where to fill in the calculated row heights. \param colWidth Array where to fill in the calculated column widths. */ void QwtDynGridLayout::layoutGrid( uint numColumns, QVector& rowHeight, QVector& colWidth ) const { if ( numColumns <= 0 ) return; if ( d_data->isDirty ) d_data->updateLayoutCache(); for ( int index = 0; index < d_data->itemSizeHints.count(); index++ ) { const int row = index / numColumns; const int col = index % numColumns; const QSize &size = d_data->itemSizeHints[int( index )]; rowHeight[row] = ( col == 0 ) ? size.height() : qMax( rowHeight[row], size.height() ); colWidth[col] = ( row == 0 ) ? size.width() : qMax( colWidth[col], size.width() ); } } /*! \return true: QwtDynGridLayout implements heightForWidth(). \sa heightForWidth() */ bool QwtDynGridLayout::hasHeightForWidth() const { return true; } /*! \return The preferred height for this layout, given a width. \sa hasHeightForWidth() */ int QwtDynGridLayout::heightForWidth( int width ) const { if ( isEmpty() ) return 0; const uint numColumns = columnsForWidth( width ); uint numRows = itemCount() / numColumns; if ( itemCount() % numColumns ) numRows++; QVector rowHeight( numRows ); QVector colWidth( numColumns ); layoutGrid( numColumns, rowHeight, colWidth ); int h = 2 * margin() + ( numRows - 1 ) * spacing(); for ( uint row = 0; row < numRows; row++ ) h += rowHeight[row]; return h; } /*! Stretch columns in case of expanding() & QSizePolicy::Horizontal and rows in case of expanding() & QSizePolicy::Vertical to fill the entire rect. Rows and columns are stretched with the same factor. \param rect Bounding rectangle \param numColumns Number of columns \param rowHeight Array to be filled with the calculated row heights \param colWidth Array to be filled with the calculated column widths \sa setExpanding(), expanding() */ void QwtDynGridLayout::stretchGrid( const QRect &rect, uint numColumns, QVector& rowHeight, QVector& colWidth ) const { if ( numColumns == 0 || isEmpty() ) return; bool expandH, expandV; expandH = expandingDirections() & Qt::Horizontal; expandV = expandingDirections() & Qt::Vertical; if ( expandH ) { int xDelta = rect.width() - 2 * margin() - ( numColumns - 1 ) * spacing(); for ( uint col = 0; col < numColumns; col++ ) xDelta -= colWidth[col]; if ( xDelta > 0 ) { for ( uint col = 0; col < numColumns; col++ ) { const int space = xDelta / ( numColumns - col ); colWidth[col] += space; xDelta -= space; } } } if ( expandV ) { uint numRows = itemCount() / numColumns; if ( itemCount() % numColumns ) numRows++; int yDelta = rect.height() - 2 * margin() - ( numRows - 1 ) * spacing(); for ( uint row = 0; row < numRows; row++ ) yDelta -= rowHeight[row]; if ( yDelta > 0 ) { for ( uint row = 0; row < numRows; row++ ) { const int space = yDelta / ( numRows - row ); rowHeight[row] += space; yDelta -= space; } } } } /*! Return the size hint. If maxColumns() > 0 it is the size for a grid with maxColumns() columns, otherwise it is the size for a grid with only one row. \return Size hint \sa maxColumns(), setMaxColumns() */ QSize QwtDynGridLayout::sizeHint() const { if ( isEmpty() ) return QSize(); uint numColumns = itemCount(); if ( d_data->maxColumns > 0 ) numColumns = qMin( d_data->maxColumns, numColumns ); uint numRows = itemCount() / numColumns; if ( itemCount() % numColumns ) numRows++; QVector rowHeight( numRows ); QVector colWidth( numColumns ); layoutGrid( numColumns, rowHeight, colWidth ); int h = 2 * margin() + ( numRows - 1 ) * spacing(); for ( uint row = 0; row < numRows; row++ ) h += rowHeight[row]; int w = 2 * margin() + ( numColumns - 1 ) * spacing(); for ( uint col = 0; col < numColumns; col++ ) w += colWidth[col]; return QSize( w, h ); } /*! \return Number of rows of the current layout. \sa numColumns() \warning The number of rows might change whenever the geometry changes */ uint QwtDynGridLayout::numRows() const { return d_data->numRows; } /*! \return Number of columns of the current layout. \sa numRows() \warning The number of columns might change whenever the geometry changes */ uint QwtDynGridLayout::numColumns() const { return d_data->numColumns; } connectome-workbench-1.4.2/src/Qwt/qwt_dyngrid_layout.h000066400000000000000000000044501360521144700233010ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_DYNGRID_LAYOUT_H #define QWT_DYNGRID_LAYOUT_H #include "qwt_global.h" #include #include #include /*! \brief The QwtDynGridLayout class lays out widgets in a grid, adjusting the number of columns and rows to the current size. QwtDynGridLayout takes the space it gets, divides it up into rows and columns, and puts each of the widgets it manages into the correct cell(s). It lays out as many number of columns as possible (limited by maxColumns()). */ class QWT_EXPORT QwtDynGridLayout : public QLayout { Q_OBJECT public: explicit QwtDynGridLayout( QWidget *, int margin = 0, int space = -1 ); explicit QwtDynGridLayout( int space = -1 ); virtual ~QwtDynGridLayout(); virtual void invalidate(); void setMaxColumns( uint maxCols ); uint maxColumns() const; uint numRows () const; uint numColumns () const; virtual void addItem( QLayoutItem * ); virtual QLayoutItem *itemAt( int index ) const; virtual QLayoutItem *takeAt( int index ); virtual int count() const; void setExpandingDirections( Qt::Orientations ); virtual Qt::Orientations expandingDirections() const; QList layoutItems( const QRect &, uint numCols ) const; virtual int maxItemWidth() const; virtual void setGeometry( const QRect &rect ); virtual bool hasHeightForWidth() const; virtual int heightForWidth( int ) const; virtual QSize sizeHint() const; virtual bool isEmpty() const; uint itemCount() const; virtual uint columnsForWidth( int width ) const; protected: void layoutGrid( uint numCols, QVector& rowHeight, QVector& colWidth ) const; void stretchGrid( const QRect &rect, uint numCols, QVector& rowHeight, QVector& colWidth ) const; private: void init(); int maxRowWidth( int numCols ) const; class PrivateData; PrivateData *d_data; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_event_pattern.cpp000066400000000000000000000151221360521144700234530ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_event_pattern.h" #include /*! Constructor \sa MousePatternCode, KeyPatternCode */ QwtEventPattern::QwtEventPattern(): d_mousePattern( MousePatternCount ), d_keyPattern( KeyPatternCount ) { initKeyPattern(); initMousePattern( 3 ); } //! Destructor QwtEventPattern::~QwtEventPattern() { } /*! Set default mouse patterns, depending on the number of mouse buttons \param numButtons Number of mouse buttons ( <= 3 ) \sa MousePatternCode */ void QwtEventPattern::initMousePattern( int numButtons ) { d_mousePattern.resize( MousePatternCount ); switch ( numButtons ) { case 1: { setMousePattern( MouseSelect1, Qt::LeftButton ); setMousePattern( MouseSelect2, Qt::LeftButton, Qt::ControlModifier ); setMousePattern( MouseSelect3, Qt::LeftButton, Qt::AltModifier ); break; } case 2: { setMousePattern( MouseSelect1, Qt::LeftButton ); setMousePattern( MouseSelect2, Qt::RightButton ); setMousePattern( MouseSelect3, Qt::LeftButton, Qt::AltModifier ); break; } default: { setMousePattern( MouseSelect1, Qt::LeftButton ); setMousePattern( MouseSelect2, Qt::RightButton ); setMousePattern( MouseSelect3, Qt::MidButton ); } } setMousePattern( MouseSelect4, d_mousePattern[MouseSelect1].button, d_mousePattern[MouseSelect1].modifiers | Qt::ShiftModifier ); setMousePattern( MouseSelect5, d_mousePattern[MouseSelect2].button, d_mousePattern[MouseSelect2].modifiers | Qt::ShiftModifier ); setMousePattern( MouseSelect6, d_mousePattern[MouseSelect3].button, d_mousePattern[MouseSelect3].modifiers | Qt::ShiftModifier ); } /*! Set default mouse patterns. \sa KeyPatternCode */ void QwtEventPattern::initKeyPattern() { d_keyPattern.resize( KeyPatternCount ); setKeyPattern( KeySelect1, Qt::Key_Return ); setKeyPattern( KeySelect2, Qt::Key_Space ); setKeyPattern( KeyAbort, Qt::Key_Escape ); setKeyPattern( KeyLeft, Qt::Key_Left ); setKeyPattern( KeyRight, Qt::Key_Right ); setKeyPattern( KeyUp, Qt::Key_Up ); setKeyPattern( KeyDown, Qt::Key_Down ); setKeyPattern( KeyRedo, Qt::Key_Plus ); setKeyPattern( KeyUndo, Qt::Key_Minus ); setKeyPattern( KeyHome, Qt::Key_Escape ); } /*! Change one mouse pattern \param pattern Index of the pattern \param button Button \param modifiers Keyboard modifiers \sa QMouseEvent */ void QwtEventPattern::setMousePattern( MousePatternCode pattern, Qt::MouseButton button, Qt::KeyboardModifiers modifiers ) { if ( pattern >= 0 && pattern < MousePatternCount ) { d_mousePattern[ pattern ].button = button; d_mousePattern[ pattern ].modifiers = modifiers; } } /*! Change one key pattern \param pattern Index of the pattern \param key Key \param modifiers Keyboard modifiers \sa QKeyEvent */ void QwtEventPattern::setKeyPattern( KeyPatternCode pattern, int key, Qt::KeyboardModifiers modifiers ) { if ( pattern >= 0 && pattern < KeyPatternCount ) { d_keyPattern[ pattern ].key = key; d_keyPattern[ pattern ].modifiers = modifiers; } } //! Change the mouse event patterns void QwtEventPattern::setMousePattern( const QVector &pattern ) { d_mousePattern = pattern; } //! Change the key event patterns void QwtEventPattern::setKeyPattern( const QVector &pattern ) { d_keyPattern = pattern; } //! \return Mouse pattern const QVector & QwtEventPattern::mousePattern() const { return d_mousePattern; } //! \return Key pattern const QVector & QwtEventPattern::keyPattern() const { return d_keyPattern; } //! \return Mouse pattern QVector &QwtEventPattern::mousePattern() { return d_mousePattern; } //! \return Key pattern QVector &QwtEventPattern::keyPattern() { return d_keyPattern; } /*! \brief Compare a mouse event with an event pattern. A mouse event matches the pattern when both have the same button value and in the state value the same key flags(Qt::KeyButtonMask) are set. \param code Index of the event pattern \param event Mouse event \return true if matches \sa keyMatch() */ bool QwtEventPattern::mouseMatch( MousePatternCode code, const QMouseEvent *event ) const { if ( code >= 0 && code < MousePatternCount ) return mouseMatch( d_mousePattern[ code ], event ); return false; } /*! \brief Compare a mouse event with an event pattern. A mouse event matches the pattern when both have the same button value and in the state value the same key flags(Qt::KeyButtonMask) are set. \param pattern Mouse event pattern \param event Mouse event \return true if matches \sa keyMatch() */ bool QwtEventPattern::mouseMatch( const MousePattern &pattern, const QMouseEvent *event ) const { if ( event == NULL ) return false; const MousePattern mousePattern( event->button(), event->modifiers() ); return mousePattern == pattern; } /*! \brief Compare a key event with an event pattern. A key event matches the pattern when both have the same key value and in the state value the same key flags (Qt::KeyButtonMask) are set. \param code Index of the event pattern \param event Key event \return true if matches \sa mouseMatch() */ bool QwtEventPattern::keyMatch( KeyPatternCode code, const QKeyEvent *event ) const { if ( code >= 0 && code < KeyPatternCount ) return keyMatch( d_keyPattern[ code ], event ); return false; } /*! \brief Compare a key event with an event pattern. A key event matches the pattern when both have the same key value and in the state value the same key flags (Qt::KeyButtonMask) are set. \param pattern Key event pattern \param event Key event \return true if matches \sa mouseMatch() */ bool QwtEventPattern::keyMatch( const KeyPattern &pattern, const QKeyEvent *event ) const { if ( event == NULL ) return false; const KeyPattern keyPattern( event->key(), event->modifiers() ); return keyPattern == pattern; } connectome-workbench-1.4.2/src/Qwt/qwt_event_pattern.h000066400000000000000000000135171360521144700231260ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_EVENT_PATTERN #define QWT_EVENT_PATTERN 1 #include "qwt_global.h" #include #include class QMouseEvent; class QKeyEvent; /*! \brief A collection of event patterns QwtEventPattern introduces an level of indirection for mouse and keyboard inputs. Those are represented by symbolic names, so the application code can be configured by individual mappings. \sa QwtPicker, QwtPickerMachine, QwtPlotZoomer */ class QWT_EXPORT QwtEventPattern { public: /*! \brief Symbolic mouse input codes QwtEventPattern implements 3 different settings for mice with 1, 2, or 3 buttons that can be activated using initMousePattern(). The default setting is for 3 button mice. Individual settings can be configured using setMousePattern(). \sa initMousePattern(), setMousePattern(), setKeyPattern() */ enum MousePatternCode { /*! The default setting for 1, 2 and 3 button mice is: - Qt::LeftButton - Qt::LeftButton - Qt::LeftButton */ MouseSelect1, /*! The default setting for 1, 2 and 3 button mice is: - Qt::LeftButton + Qt::ControlModifier - Qt::RightButton - Qt::RightButton */ MouseSelect2, /*! The default setting for 1, 2 and 3 button mice is: - Qt::LeftButton + Qt::AltModifier - Qt::LeftButton + Qt::AltModifier - Qt::MidButton */ MouseSelect3, /*! The default setting for 1, 2 and 3 button mice is: - Qt::LeftButton + Qt::ShiftModifier - Qt::LeftButton + Qt::ShiftModifier - Qt::LeftButton + Qt::ShiftModifier */ MouseSelect4, /*! The default setting for 1, 2 and 3 button mice is: - Qt::LeftButton + Qt::ControlButton | Qt::ShiftModifier - Qt::RightButton + Qt::ShiftModifier - Qt::RightButton + Qt::ShiftModifier */ MouseSelect5, /*! The default setting for 1, 2 and 3 button mice is: - Qt::LeftButton + Qt::AltModifier + Qt::ShiftModifier - Qt::LeftButton + Qt::AltModifier | Qt::ShiftModifier - Qt::MidButton + Qt::ShiftModifier */ MouseSelect6, //! Number of mouse patterns MousePatternCount }; /*! \brief Symbolic keyboard input codes Individual settings can be configured using setKeyPattern() \sa setKeyPattern(), setMousePattern() */ enum KeyPatternCode { //! Qt::Key_Return KeySelect1, //! Qt::Key_Space KeySelect2, //! Qt::Key_Escape KeyAbort, //! Qt::Key_Left KeyLeft, //! Qt::Key_Right KeyRight, //! Qt::Key_Up KeyUp, //! Qt::Key_Down KeyDown, //! Qt::Key_Plus KeyRedo, //! Qt::Key_Minus KeyUndo, //! Qt::Key_Escape KeyHome, //! Number of key patterns KeyPatternCount }; //! A pattern for mouse events class MousePattern { public: //! Constructor MousePattern( Qt::MouseButton btn = Qt::NoButton, Qt::KeyboardModifiers modifierCodes = Qt::NoModifier ): button( btn ), modifiers( modifierCodes ) { } //! Button Qt::MouseButton button; //! Keyboard modifier Qt::KeyboardModifiers modifiers; }; //! A pattern for key events class KeyPattern { public: //! Constructor KeyPattern( int keyCode = Qt::Key_unknown, Qt::KeyboardModifiers modifierCodes = Qt::NoModifier ): key( keyCode ), modifiers( modifierCodes ) { } //! Key code int key; //! Modifiers Qt::KeyboardModifiers modifiers; }; QwtEventPattern(); virtual ~QwtEventPattern(); void initMousePattern( int numButtons ); void initKeyPattern(); void setMousePattern( MousePatternCode, Qt::MouseButton button, Qt::KeyboardModifiers = Qt::NoModifier ); void setKeyPattern( KeyPatternCode, int keyCode, Qt::KeyboardModifiers modifierCodes = Qt::NoModifier ); void setMousePattern( const QVector & ); void setKeyPattern( const QVector & ); const QVector &mousePattern() const; const QVector &keyPattern() const; QVector &mousePattern(); QVector &keyPattern(); bool mouseMatch( MousePatternCode, const QMouseEvent * ) const; bool keyMatch( KeyPatternCode, const QKeyEvent * ) const; protected: virtual bool mouseMatch( const MousePattern &, const QMouseEvent * ) const; virtual bool keyMatch( const KeyPattern &, const QKeyEvent * ) const; private: #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable: 4251) #endif QVector d_mousePattern; QVector d_keyPattern; #if defined(_MSC_VER) #pragma warning(pop) #endif }; //! Compare operator inline bool operator==( QwtEventPattern::MousePattern b1, QwtEventPattern::MousePattern b2 ) { return b1.button == b2.button && b1.modifiers == b2.modifiers; } //! Compare operator inline bool operator==( QwtEventPattern::KeyPattern b1, QwtEventPattern::KeyPattern b2 ) { return b1.key == b2.key && b1.modifiers == b2.modifiers; } #endif connectome-workbench-1.4.2/src/Qwt/qwt_global.h000066400000000000000000000020701360521144700215000ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_GLOBAL_H #define QWT_GLOBAL_H #include // QWT_VERSION is (major << 16) + (minor << 8) + patch. #define QWT_VERSION 0x060102 #define QWT_VERSION_STR "6.1.2" #if defined(_MSC_VER) /* MSVC Compiler */ /* template-class specialization 'identifier' is already instantiated */ #pragma warning(disable: 4660) /* inherits via dominance */ #pragma warning(disable: 4250) #endif // _MSC_VER #ifdef QWT_DLL #if defined(QWT_MAKEDLL) // create a Qwt DLL library #define QWT_EXPORT Q_DECL_EXPORT #else // use a Qwt DLL library #define QWT_EXPORT Q_DECL_IMPORT #endif #endif // QWT_DLL #ifndef QWT_EXPORT #define QWT_EXPORT #endif #endif connectome-workbench-1.4.2/src/Qwt/qwt_graphic.cpp000066400000000000000000000631231360521144700222160ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_graphic.h" #include "qwt_painter_command.h" #include #include #include #include #include #include #include static bool qwtHasScalablePen( const QPainter *painter ) { const QPen pen = painter->pen(); bool scalablePen = false; if ( pen.style() != Qt::NoPen && pen.brush().style() != Qt::NoBrush ) { scalablePen = !pen.isCosmetic(); if ( !scalablePen && pen.widthF() == 0.0 ) { const QPainter::RenderHints hints = painter->renderHints(); if ( hints.testFlag( QPainter::NonCosmeticDefaultPen ) ) scalablePen = true; } } return scalablePen; } static QRectF qwtStrokedPathRect( const QPainter *painter, const QPainterPath &path ) { QPainterPathStroker stroker; stroker.setWidth( painter->pen().widthF() ); stroker.setCapStyle( painter->pen().capStyle() ); stroker.setJoinStyle( painter->pen().joinStyle() ); stroker.setMiterLimit( painter->pen().miterLimit() ); QRectF rect; if ( qwtHasScalablePen( painter ) ) { QPainterPath stroke = stroker.createStroke(path); rect = painter->transform().map(stroke).boundingRect(); } else { QPainterPath mappedPath = painter->transform().map(path); mappedPath = stroker.createStroke( mappedPath ); rect = mappedPath.boundingRect(); } return rect; } static inline void qwtExecCommand( QPainter *painter, const QwtPainterCommand &cmd, QwtGraphic::RenderHints renderHints, const QTransform &transform, const QTransform *initialTransform ) { switch( cmd.type() ) { case QwtPainterCommand::Path: { bool doMap = false; if ( renderHints.testFlag( QwtGraphic::RenderPensUnscaled ) && painter->transform().isScaling() ) { bool isCosmetic = painter->pen().isCosmetic(); if ( isCosmetic && painter->pen().widthF() == 0.0 ) { QPainter::RenderHints hints = painter->renderHints(); if ( hints.testFlag( QPainter::NonCosmeticDefaultPen ) ) isCosmetic = false; } doMap = !isCosmetic; } if ( doMap ) { const QTransform tr = painter->transform(); painter->resetTransform(); QPainterPath path = tr.map( *cmd.path() ); if ( initialTransform ) { painter->setTransform( *initialTransform ); path = initialTransform->inverted().map( path ); } painter->drawPath( path ); painter->setTransform( tr ); } else { painter->drawPath( *cmd.path() ); } break; } case QwtPainterCommand::Pixmap: { const QwtPainterCommand::PixmapData *data = cmd.pixmapData(); painter->drawPixmap( data->rect, data->pixmap, data->subRect ); break; } case QwtPainterCommand::Image: { const QwtPainterCommand::ImageData *data = cmd.imageData(); painter->drawImage( data->rect, data->image, data->subRect, data->flags ); break; } case QwtPainterCommand::State: { const QwtPainterCommand::StateData *data = cmd.stateData(); if ( data->flags & QPaintEngine::DirtyPen ) painter->setPen( data->pen ); if ( data->flags & QPaintEngine::DirtyBrush ) painter->setBrush( data->brush ); if ( data->flags & QPaintEngine::DirtyBrushOrigin ) painter->setBrushOrigin( data->brushOrigin ); if ( data->flags & QPaintEngine::DirtyFont ) painter->setFont( data->font ); if ( data->flags & QPaintEngine::DirtyBackground ) { painter->setBackgroundMode( data->backgroundMode ); painter->setBackground( data->backgroundBrush ); } if ( data->flags & QPaintEngine::DirtyTransform ) { painter->setTransform( data->transform * transform ); } if ( data->flags & QPaintEngine::DirtyClipEnabled ) painter->setClipping( data->isClipEnabled ); if ( data->flags & QPaintEngine::DirtyClipRegion) { painter->setClipRegion( data->clipRegion, data->clipOperation ); } if ( data->flags & QPaintEngine::DirtyClipPath ) { painter->setClipPath( data->clipPath, data->clipOperation ); } if ( data->flags & QPaintEngine::DirtyHints) { const QPainter::RenderHints hints = data->renderHints; painter->setRenderHint( QPainter::Antialiasing, hints.testFlag( QPainter::Antialiasing ) ); painter->setRenderHint( QPainter::TextAntialiasing, hints.testFlag( QPainter::TextAntialiasing ) ); painter->setRenderHint( QPainter::SmoothPixmapTransform, hints.testFlag( QPainter::SmoothPixmapTransform ) ); painter->setRenderHint( QPainter::HighQualityAntialiasing, hints.testFlag( QPainter::HighQualityAntialiasing ) ); painter->setRenderHint( QPainter::NonCosmeticDefaultPen, hints.testFlag( QPainter::NonCosmeticDefaultPen ) ); } if ( data->flags & QPaintEngine::DirtyCompositionMode) painter->setCompositionMode( data->compositionMode ); if ( data->flags & QPaintEngine::DirtyOpacity) painter->setOpacity( data->opacity ); break; } default: break; } } class QwtGraphic::PathInfo { public: PathInfo(): d_scalablePen( false ) { // QVector needs a default constructor } PathInfo( const QRectF &pointRect, const QRectF &boundingRect, bool scalablePen ): d_pointRect( pointRect ), d_boundingRect( boundingRect ), d_scalablePen( scalablePen ) { } inline QRectF scaledBoundingRect( double sx, double sy, bool scalePens ) const { if ( sx == 1.0 && sy == 1.0 ) return d_boundingRect; QTransform transform; transform.scale( sx, sy ); QRectF rect; if ( scalePens && d_scalablePen ) { rect = transform.mapRect( d_boundingRect ); } else { rect = transform.mapRect( d_pointRect ); const double l = qAbs( d_pointRect.left() - d_boundingRect.left() ); const double r = qAbs( d_pointRect.right() - d_boundingRect.right() ); const double t = qAbs( d_pointRect.top() - d_boundingRect.top() ); const double b = qAbs( d_pointRect.bottom() - d_boundingRect.bottom() ); rect.adjust( -l, -t, r, b ); } return rect; } inline double scaleFactorX( const QRectF& pathRect, const QRectF &targetRect, bool scalePens ) const { if ( pathRect.width() <= 0.0 ) return 0.0; const QPointF p0 = d_pointRect.center(); const double l = qAbs( pathRect.left() - p0.x() ); const double r = qAbs( pathRect.right() - p0.x() ); const double w = 2.0 * qMin( l, r ) * targetRect.width() / pathRect.width(); double sx; if ( scalePens && d_scalablePen ) { sx = w / d_boundingRect.width(); } else { const double pw = qMax( qAbs( d_boundingRect.left() - d_pointRect.left() ), qAbs( d_boundingRect.right() - d_pointRect.right() ) ); sx = ( w - 2 * pw ) / d_pointRect.width(); } return sx; } inline double scaleFactorY( const QRectF& pathRect, const QRectF &targetRect, bool scalePens ) const { if ( pathRect.height() <= 0.0 ) return 0.0; const QPointF p0 = d_pointRect.center(); const double t = qAbs( pathRect.top() - p0.y() ); const double b = qAbs( pathRect.bottom() - p0.y() ); const double h = 2.0 * qMin( t, b ) * targetRect.height() / pathRect.height(); double sy; if ( scalePens && d_scalablePen ) { sy = h / d_boundingRect.height(); } else { const double pw = qMax( qAbs( d_boundingRect.top() - d_pointRect.top() ), qAbs( d_boundingRect.bottom() - d_pointRect.bottom() ) ); sy = ( h - 2 * pw ) / d_pointRect.height(); } return sy; } private: QRectF d_pointRect; QRectF d_boundingRect; bool d_scalablePen; }; class QwtGraphic::PrivateData { public: PrivateData(): boundingRect( 0.0, 0.0, -1.0, -1.0 ), pointRect( 0.0, 0.0, -1.0, -1.0 ), initialTransform( NULL ) { } QSizeF defaultSize; QVector commands; QVector pathInfos; QRectF boundingRect; QRectF pointRect; QwtGraphic::RenderHints renderHints; QTransform *initialTransform; }; /*! \brief Constructor Initializes a null graphic \sa isNull() */ QwtGraphic::QwtGraphic(): QwtNullPaintDevice() { setMode( QwtNullPaintDevice::PathMode ); d_data = new PrivateData; } /*! \brief Copy constructor \param other Source \sa operator=() */ QwtGraphic::QwtGraphic( const QwtGraphic &other ): QwtNullPaintDevice() { setMode( other.mode() ); d_data = new PrivateData( *other.d_data ); } //! Destructor QwtGraphic::~QwtGraphic() { delete d_data; } /*! \brief Assignment operator \param other Source \return A reference of this object */ QwtGraphic& QwtGraphic::operator=(const QwtGraphic &other) { setMode( other.mode() ); *d_data = *other.d_data; return *this; } /*! \brief Clear all stored commands \sa isNull() */ void QwtGraphic::reset() { d_data->commands.clear(); d_data->pathInfos.clear(); d_data->boundingRect = QRectF( 0.0, 0.0, -1.0, -1.0 ); d_data->pointRect = QRectF( 0.0, 0.0, -1.0, -1.0 ); d_data->defaultSize = QSizeF(); } /*! \return True, when no painter commands have been stored \sa isEmpty(), commands() */ bool QwtGraphic::isNull() const { return d_data->commands.isEmpty(); } /*! \return True, when the bounding rectangle is empty \sa boundingRect(), isNull() */ bool QwtGraphic::isEmpty() const { return d_data->boundingRect.isEmpty(); } /*! Toggle an render hint \param hint Render hint \param on true/false \sa testRenderHint(), RenderHint */ void QwtGraphic::setRenderHint( RenderHint hint, bool on ) { if ( on ) d_data->renderHints |= hint; else d_data->renderHints &= ~hint; } /*! Test a render hint \param hint Render hint \return true/false \sa setRenderHint(), RenderHint */ bool QwtGraphic::testRenderHint( RenderHint hint ) const { return d_data->renderHints.testFlag( hint ); } /*! The bounding rectangle is the controlPointRect() extended by the areas needed for rendering the outlines with unscaled pens. \return Bounding rectangle of the graphic \sa controlPointRect(), scaledBoundingRect() */ QRectF QwtGraphic::boundingRect() const { if ( d_data->boundingRect.width() < 0 ) return QRectF(); return d_data->boundingRect; } /*! The control point rectangle is the bounding rectangle of all control points of the paths and the target rectangles of the images/pixmaps. \return Control point rectangle \sa boundingRect(), scaledBoundingRect() */ QRectF QwtGraphic::controlPointRect() const { if ( d_data->pointRect.width() < 0 ) return QRectF(); return d_data->pointRect; } /*! \brief Calculate the target rectangle for scaling the graphic \param sx Horizontal scaling factor \param sy Vertical scaling factor \note In case of paths that are painted with a cosmetic pen ( see QPen::isCosmetic() ) the target rectangle is different to multiplying the bounding rectangle. \return Scaled bounding rectangle \sa boundingRect(), controlPointRect() */ QRectF QwtGraphic::scaledBoundingRect( double sx, double sy ) const { if ( sx == 1.0 && sy == 1.0 ) return d_data->boundingRect; QTransform transform; transform.scale( sx, sy ); QRectF rect = transform.mapRect( d_data->pointRect ); for ( int i = 0; i < d_data->pathInfos.size(); i++ ) { rect |= d_data->pathInfos[i].scaledBoundingRect( sx, sy, !d_data->renderHints.testFlag( RenderPensUnscaled ) ); } return rect; } //! \return Ceiled defaultSize() QSize QwtGraphic::sizeMetrics() const { const QSizeF sz = defaultSize(); return QSize( qCeil( sz.width() ), qCeil( sz.height() ) ); } /*! \brief Set a default size The default size is used in all methods rendering the graphic, where no size is explicitly specified. Assigning an empty size means, that the default size will be calculated from the bounding rectangle. The default setting is an empty size. \param size Default size \sa defaultSize(), boundingRect() */ void QwtGraphic::setDefaultSize( const QSizeF &size ) { const double w = qMax( qreal( 0.0 ), size.width() ); const double h = qMax( qreal( 0.0 ), size.height() ); d_data->defaultSize = QSizeF( w, h ); } /*! \brief Default size When a non empty size has been assigned by setDefaultSize() this size will be returned. Otherwise the default size is the size of the bounding rectangle. The default size is used in all methods rendering the graphic, where no size is explicitly specified. \return Default size \sa setDefaultSize(), boundingRect() */ QSizeF QwtGraphic::defaultSize() const { if ( !d_data->defaultSize.isEmpty() ) return d_data->defaultSize; return boundingRect().size(); } /*! \brief Replay all recorded painter commands \param painter Qt painter */ void QwtGraphic::render( QPainter *painter ) const { if ( isNull() ) return; const int numCommands = d_data->commands.size(); const QwtPainterCommand *commands = d_data->commands.constData(); const QTransform transform = painter->transform(); painter->save(); for ( int i = 0; i < numCommands; i++ ) { qwtExecCommand( painter, commands[i], d_data->renderHints, transform, d_data->initialTransform ); } painter->restore(); } /*! \brief Replay all recorded painter commands The graphic is scaled to fit into the rectangle of the given size starting at ( 0, 0 ). \param painter Qt painter \param size Size for the scaled graphic \param aspectRatioMode Mode how to scale - See Qt::AspectRatioMode */ void QwtGraphic::render( QPainter *painter, const QSizeF &size, Qt::AspectRatioMode aspectRatioMode ) const { const QRectF r( 0.0, 0.0, size.width(), size.height() ); render( painter, r, aspectRatioMode ); } /*! \brief Replay all recorded painter commands The graphic is scaled to fit into the given rectangle \param painter Qt painter \param rect Rectangle for the scaled graphic \param aspectRatioMode Mode how to scale - See Qt::AspectRatioMode */ void QwtGraphic::render( QPainter *painter, const QRectF &rect, Qt::AspectRatioMode aspectRatioMode ) const { if ( isEmpty() || rect.isEmpty() ) return; double sx = 1.0; double sy = 1.0; if ( d_data->pointRect.width() > 0.0 ) sx = rect.width() / d_data->pointRect.width(); if ( d_data->pointRect.height() > 0.0 ) sy = rect.height() / d_data->pointRect.height(); const bool scalePens = !d_data->renderHints.testFlag( RenderPensUnscaled ); for ( int i = 0; i < d_data->pathInfos.size(); i++ ) { const PathInfo info = d_data->pathInfos[i]; const double ssx = info.scaleFactorX( d_data->pointRect, rect, scalePens ); if ( ssx > 0.0 ) sx = qMin( sx, ssx ); const double ssy = info.scaleFactorY( d_data->pointRect, rect, scalePens ); if ( ssy > 0.0 ) sy = qMin( sy, ssy ); } if ( aspectRatioMode == Qt::KeepAspectRatio ) { const double s = qMin( sx, sy ); sx = s; sy = s; } else if ( aspectRatioMode == Qt::KeepAspectRatioByExpanding ) { const double s = qMax( sx, sy ); sx = s; sy = s; } QTransform tr; tr.translate( rect.center().x() - 0.5 * sx * d_data->pointRect.width(), rect.center().y() - 0.5 * sy * d_data->pointRect.height() ); tr.scale( sx, sy ); tr.translate( -d_data->pointRect.x(), -d_data->pointRect.y() ); const QTransform transform = painter->transform(); if ( !scalePens && transform.isScaling() ) { // we don't want to scale pens according to sx/sy, // but we want to apply the scaling from the // painter transformation later d_data->initialTransform = new QTransform(); d_data->initialTransform->scale( transform.m11(), transform.m22() ); } painter->setTransform( tr, true ); render( painter ); painter->setTransform( transform ); delete d_data->initialTransform; d_data->initialTransform = NULL; } /*! \brief Replay all recorded painter commands The graphic is scaled to the defaultSize() and aligned to a position. \param painter Qt painter \param pos Reference point, where to render \param alignment Flags how to align the target rectangle to pos. */ void QwtGraphic::render( QPainter *painter, const QPointF &pos, Qt::Alignment alignment ) const { QRectF r( pos, defaultSize() ); if ( alignment & Qt::AlignLeft ) { r.moveLeft( pos.x() ); } else if ( alignment & Qt::AlignHCenter ) { r.moveCenter( QPointF( pos.x(), r.center().y() ) ); } else if ( alignment & Qt::AlignRight ) { r.moveRight( pos.x() ); } if ( alignment & Qt::AlignTop ) { r.moveTop( pos.y() ); } else if ( alignment & Qt::AlignVCenter ) { r.moveCenter( QPointF( r.center().x(), pos.y() ) ); } else if ( alignment & Qt::AlignBottom ) { r.moveBottom( pos.y() ); } render( painter, r ); } /*! \brief Convert the graphic to a QPixmap All pixels of the pixmap get initialized by Qt::transparent before the graphic is scaled and rendered on it. The size of the pixmap is the default size ( ceiled to integers ) of the graphic. \return The graphic as pixmap in default size \sa defaultSize(), toImage(), render() */ QPixmap QwtGraphic::toPixmap() const { if ( isNull() ) return QPixmap(); const QSizeF sz = defaultSize(); const int w = qCeil( sz.width() ); const int h = qCeil( sz.height() ); QPixmap pixmap( w, h ); pixmap.fill( Qt::transparent ); const QRectF r( 0.0, 0.0, sz.width(), sz.height() ); QPainter painter( &pixmap ); render( &painter, r, Qt::KeepAspectRatio ); painter.end(); return pixmap; } /*! \brief Convert the graphic to a QPixmap All pixels of the pixmap get initialized by Qt::transparent before the graphic is scaled and rendered on it. \param size Size of the image \param aspectRatioMode Aspect ratio how to scale the graphic \return The graphic as pixmap \sa toImage(), render() */ QPixmap QwtGraphic::toPixmap( const QSize &size, Qt::AspectRatioMode aspectRatioMode ) const { QPixmap pixmap( size ); pixmap.fill( Qt::transparent ); const QRect r( 0, 0, size.width(), size.height() ); QPainter painter( &pixmap ); render( &painter, r, aspectRatioMode ); painter.end(); return pixmap; } /*! \brief Convert the graphic to a QImage All pixels of the image get initialized by 0 ( transparent ) before the graphic is scaled and rendered on it. The format of the image is QImage::Format_ARGB32_Premultiplied. \param size Size of the image \param aspectRatioMode Aspect ratio how to scale the graphic \return The graphic as image \sa toPixmap(), render() */ QImage QwtGraphic::toImage( const QSize &size, Qt::AspectRatioMode aspectRatioMode ) const { QImage image( size, QImage::Format_ARGB32_Premultiplied ); image.fill( 0 ); const QRect r( 0, 0, size.width(), size.height() ); QPainter painter( &image ); render( &painter, r, aspectRatioMode ); painter.end(); return image; } /*! \brief Convert the graphic to a QImage All pixels of the image get initialized by 0 ( transparent ) before the graphic is scaled and rendered on it. The format of the image is QImage::Format_ARGB32_Premultiplied. The size of the image is the default size ( ceiled to integers ) of the graphic. \return The graphic as image in default size \sa defaultSize(), toPixmap(), render() */ QImage QwtGraphic::toImage() const { if ( isNull() ) return QImage(); const QSizeF sz = defaultSize(); const int w = qCeil( sz.width() ); const int h = qCeil( sz.height() ); QImage image( w, h, QImage::Format_ARGB32 ); image.fill( 0 ); const QRect r( 0, 0, sz.width(), sz.height() ); QPainter painter( &image ); render( &painter, r, Qt::KeepAspectRatio ); painter.end(); return image; } /*! Store a path command in the command list \param path Painter path \sa QPaintEngine::drawPath() */ void QwtGraphic::drawPath( const QPainterPath &path ) { const QPainter *painter = paintEngine()->painter(); if ( painter == NULL ) return; d_data->commands += QwtPainterCommand( path ); if ( !path.isEmpty() ) { const QPainterPath scaledPath = painter->transform().map( path ); QRectF pointRect = scaledPath.boundingRect(); QRectF boundingRect = pointRect; if ( painter->pen().style() != Qt::NoPen && painter->pen().brush().style() != Qt::NoBrush ) { boundingRect = qwtStrokedPathRect( painter, path ); } updateControlPointRect( pointRect ); updateBoundingRect( boundingRect ); d_data->pathInfos += PathInfo( pointRect, boundingRect, qwtHasScalablePen( painter ) ); } } /*! \brief Store a pixmap command in the command list \param rect target rectangle \param pixmap Pixmap to be painted \param subRect Reactangle of the pixmap to be painted \sa QPaintEngine::drawPixmap() */ void QwtGraphic::drawPixmap( const QRectF &rect, const QPixmap &pixmap, const QRectF &subRect ) { const QPainter *painter = paintEngine()->painter(); if ( painter == NULL ) return; d_data->commands += QwtPainterCommand( rect, pixmap, subRect ); const QRectF r = painter->transform().mapRect( rect ); updateControlPointRect( r ); updateBoundingRect( r ); } /*! \brief Store a image command in the command list \param rect traget rectangle \param image Image to be painted \param subRect Reactangle of the pixmap to be painted \param flags Image conversion flags \sa QPaintEngine::drawImage() */ void QwtGraphic::drawImage( const QRectF &rect, const QImage &image, const QRectF &subRect, Qt::ImageConversionFlags flags) { const QPainter *painter = paintEngine()->painter(); if ( painter == NULL ) return; d_data->commands += QwtPainterCommand( rect, image, subRect, flags ); const QRectF r = painter->transform().mapRect( rect ); updateControlPointRect( r ); updateBoundingRect( r ); } /*! \brief Store a state command in the command list \param state State to be stored \sa QPaintEngine::updateState() */ void QwtGraphic::updateState( const QPaintEngineState &state) { d_data->commands += QwtPainterCommand( state ); } void QwtGraphic::updateBoundingRect( const QRectF &rect ) { QRectF br = rect; const QPainter *painter = paintEngine()->painter(); if ( painter && painter->hasClipping() ) { QRectF cr = painter->clipRegion().boundingRect(); cr = painter->transform().mapRect( br ); br &= cr; } if ( d_data->boundingRect.width() < 0 ) d_data->boundingRect = br; else d_data->boundingRect |= br; } void QwtGraphic::updateControlPointRect( const QRectF &rect ) { if ( d_data->pointRect.width() < 0.0 ) d_data->pointRect = rect; else d_data->pointRect |= rect; } /*! \return List of recorded paint commands \sa setCommands() */ const QVector< QwtPainterCommand > &QwtGraphic::commands() const { return d_data->commands; } /*! \brief Append paint commands \param commands Paint commands \sa commands() */ void QwtGraphic::setCommands( QVector< QwtPainterCommand > &commands ) { reset(); const int numCommands = commands.size(); if ( numCommands <= 0 ) return; // to calculate a proper bounding rectangle we don't simply copy // the commands. const QwtPainterCommand *cmds = commands.constData(); QPainter painter( this ); for ( int i = 0; i < numCommands; i++ ) qwtExecCommand( &painter, cmds[i], RenderHints(), QTransform(), NULL ); painter.end(); } connectome-workbench-1.4.2/src/Qwt/qwt_graphic.h000066400000000000000000000131441360521144700216610ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_GRAPHIC_H #define QWT_GRAPHIC_H #include "qwt_global.h" #include "qwt_null_paintdevice.h" #include #include #include class QwtPainterCommand; /*! \brief A paint device for scalable graphics QwtGraphic is the representation of a graphic that is tailored for scalability. Like QPicture it will be initialized by QPainter operations and can be replayed later to any target paint device. While the usual image representations QImage and QPixmap are not scalable Qt offers two paint devices, that might be candidates for representing a vector graphic: - QPicture\n Unfortunately QPicture had been forgotten, when Qt4 introduced floating point based render engines. Its API is still on integers, what make it unusable for proper scaling. - QSvgRenderer/QSvgGenerator\n Unfortunately QSvgRenderer hides to much information about its nodes in internal APIs, that are necessary for proper layout calculations. Also it is derived from QObject and can't be copied like QImage/QPixmap. QwtGraphic maps all scalable drawing primitives to a QPainterPath and stores them together with the painter state changes ( pen, brush, transformation ... ) in a list of QwtPaintCommands. For being a complete QPaintDevice it also stores pixmaps or images, what is somehow against the idea of the class, because these objects can't be scaled without a loss in quality. The main issue about scaling a QwtGraphic object are the pens used for drawing the outlines of the painter paths. While non cosmetic pens ( QPen::isCosmetic() ) are scaled with the same ratio as the path, cosmetic pens have a fixed width. A graphic might have paths with different pens - cosmetic and non-cosmetic. QwtGraphic caches 2 different rectangles: - control point rectangle\n The control point rectangle is the bounding rectangle of all control point rectangles of the painter paths, or the target rectangle of the pixmaps/images. - bounding rectangle\n The bounding rectangle extends the control point rectangle by what is needed for rendering the outline with an unscaled pen. Because the offset for drawing the outline depends on the shape of the painter path ( the peak of a triangle is different than the flat side ) scaling with a fixed aspect ratio always needs to be calculated from the control point rectangle. \sa QwtPainterCommand */ class QWT_EXPORT QwtGraphic: public QwtNullPaintDevice { public: /*! Hint how to render a graphic \sa setRenderHint(), testRenderHint() */ enum RenderHint { /*! When rendering a QwtGraphic a specific scaling between the controlPointRect() and the coordinates of the target rectangle is set up internally in render(). When RenderPensUnscaled is set this specific scaling is applied for the control points only, but not for the pens. All other painter transformations ( set up by application code ) are supposed to work like usual. \sa render(); */ RenderPensUnscaled = 0x1 }; /*! \brief Render hints The default setting is to disable all hints */ typedef QFlags RenderHints; QwtGraphic(); QwtGraphic( const QwtGraphic & ); virtual ~QwtGraphic(); QwtGraphic& operator=( const QwtGraphic & ); void reset(); bool isNull() const; bool isEmpty() const; void render( QPainter * ) const; void render( QPainter *, const QSizeF &, Qt::AspectRatioMode = Qt::IgnoreAspectRatio ) const; void render( QPainter *, const QRectF &, Qt::AspectRatioMode = Qt::IgnoreAspectRatio ) const; void render( QPainter *, const QPointF &, Qt::Alignment = Qt::AlignTop | Qt::AlignLeft ) const; QPixmap toPixmap() const; QPixmap toPixmap( const QSize &, Qt::AspectRatioMode = Qt::IgnoreAspectRatio ) const; QImage toImage() const; QImage toImage( const QSize &, Qt::AspectRatioMode = Qt::IgnoreAspectRatio ) const; QRectF scaledBoundingRect( double sx, double sy ) const; QRectF boundingRect() const; QRectF controlPointRect() const; const QVector< QwtPainterCommand > &commands() const; void setCommands( QVector< QwtPainterCommand > & ); void setDefaultSize( const QSizeF & ); QSizeF defaultSize() const; void setRenderHint( RenderHint, bool on = true ); bool testRenderHint( RenderHint ) const; protected: virtual QSize sizeMetrics() const; virtual void drawPath( const QPainterPath & ); virtual void drawPixmap( const QRectF &, const QPixmap &, const QRectF & ); virtual void drawImage( const QRectF &, const QImage &, const QRectF &, Qt::ImageConversionFlags ); virtual void updateState( const QPaintEngineState &state ); private: void updateBoundingRect( const QRectF & ); void updateControlPointRect( const QRectF & ); class PathInfo; class PrivateData; PrivateData *d_data; }; Q_DECLARE_OPERATORS_FOR_FLAGS( QwtGraphic::RenderHints ) Q_DECLARE_METATYPE( QwtGraphic ) #endif connectome-workbench-1.4.2/src/Qwt/qwt_interval.cpp000066400000000000000000000203701360521144700224220ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_interval.h" #include "qwt_math.h" #include /*! \brief Normalize the limits of the interval If maxValue() < minValue() the limits will be inverted. \return Normalized interval \sa isValid(), inverted() */ QwtInterval QwtInterval::normalized() const { if ( d_minValue > d_maxValue ) { return inverted(); } if ( d_minValue == d_maxValue && d_borderFlags == ExcludeMinimum ) { return inverted(); } return *this; } /*! Invert the limits of the interval \return Inverted interval \sa normalized() */ QwtInterval QwtInterval::inverted() const { BorderFlags borderFlags = IncludeBorders; if ( d_borderFlags & ExcludeMinimum ) borderFlags |= ExcludeMaximum; if ( d_borderFlags & ExcludeMaximum ) borderFlags |= ExcludeMinimum; return QwtInterval( d_maxValue, d_minValue, borderFlags ); } /*! Test if a value is inside an interval \param value Value \return true, if value >= minValue() && value <= maxValue() */ bool QwtInterval::contains( double value ) const { if ( !isValid() ) return false; if ( value < d_minValue || value > d_maxValue ) return false; if ( value == d_minValue && d_borderFlags & ExcludeMinimum ) return false; if ( value == d_maxValue && d_borderFlags & ExcludeMaximum ) return false; return true; } //! Unite 2 intervals QwtInterval QwtInterval::unite( const QwtInterval &other ) const { /* If one of the intervals is invalid return the other one. If both are invalid return an invalid default interval */ if ( !isValid() ) { if ( !other.isValid() ) return QwtInterval(); else return other; } if ( !other.isValid() ) return *this; QwtInterval united; BorderFlags flags = IncludeBorders; // minimum if ( d_minValue < other.minValue() ) { united.setMinValue( d_minValue ); flags &= d_borderFlags & ExcludeMinimum; } else if ( other.minValue() < d_minValue ) { united.setMinValue( other.minValue() ); flags &= other.borderFlags() & ExcludeMinimum; } else // d_minValue == other.minValue() { united.setMinValue( d_minValue ); flags &= ( d_borderFlags & other.borderFlags() ) & ExcludeMinimum; } // maximum if ( d_maxValue > other.maxValue() ) { united.setMaxValue( d_maxValue ); flags &= d_borderFlags & ExcludeMaximum; } else if ( other.maxValue() > d_maxValue ) { united.setMaxValue( other.maxValue() ); flags &= other.borderFlags() & ExcludeMaximum; } else // d_maxValue == other.maxValue() ) { united.setMaxValue( d_maxValue ); flags &= d_borderFlags & other.borderFlags() & ExcludeMaximum; } united.setBorderFlags( flags ); return united; } /*! \brief Intersect 2 intervals \param other Interval to be intersect with \return Intersection */ QwtInterval QwtInterval::intersect( const QwtInterval &other ) const { if ( !other.isValid() || !isValid() ) return QwtInterval(); QwtInterval i1 = *this; QwtInterval i2 = other; // swap i1/i2, so that the minimum of i1 // is smaller then the minimum of i2 if ( i1.minValue() > i2.minValue() ) { qSwap( i1, i2 ); } else if ( i1.minValue() == i2.minValue() ) { if ( i1.borderFlags() & ExcludeMinimum ) qSwap( i1, i2 ); } if ( i1.maxValue() < i2.minValue() ) { return QwtInterval(); } if ( i1.maxValue() == i2.minValue() ) { if ( i1.borderFlags() & ExcludeMaximum || i2.borderFlags() & ExcludeMinimum ) { return QwtInterval(); } } QwtInterval intersected; BorderFlags flags = IncludeBorders; intersected.setMinValue( i2.minValue() ); flags |= i2.borderFlags() & ExcludeMinimum; if ( i1.maxValue() < i2.maxValue() ) { intersected.setMaxValue( i1.maxValue() ); flags |= i1.borderFlags() & ExcludeMaximum; } else if ( i2.maxValue() < i1.maxValue() ) { intersected.setMaxValue( i2.maxValue() ); flags |= i2.borderFlags() & ExcludeMaximum; } else // i1.maxValue() == i2.maxValue() { intersected.setMaxValue( i1.maxValue() ); flags |= i1.borderFlags() & i2.borderFlags() & ExcludeMaximum; } intersected.setBorderFlags( flags ); return intersected; } /*! \brief Unite this interval with the given interval. \param other Interval to be united with \return This interval */ QwtInterval& QwtInterval::operator|=( const QwtInterval &other ) { *this = *this | other; return *this; } /*! \brief Intersect this interval with the given interval. \param other Interval to be intersected with \return This interval */ QwtInterval& QwtInterval::operator&=( const QwtInterval &other ) { *this = *this & other; return *this; } /*! \brief Test if two intervals overlap \param other Interval \return True, when the intervals are intersecting */ bool QwtInterval::intersects( const QwtInterval &other ) const { if ( !isValid() || !other.isValid() ) return false; QwtInterval i1 = *this; QwtInterval i2 = other; // swap i1/i2, so that the minimum of i1 // is smaller then the minimum of i2 if ( i1.minValue() > i2.minValue() ) { qSwap( i1, i2 ); } else if ( i1.minValue() == i2.minValue() && i1.borderFlags() & ExcludeMinimum ) { qSwap( i1, i2 ); } if ( i1.maxValue() > i2.minValue() ) { return true; } if ( i1.maxValue() == i2.minValue() ) { return !( ( i1.borderFlags() & ExcludeMaximum ) || ( i2.borderFlags() & ExcludeMinimum ) ); } return false; } /*! Adjust the limit that is closer to value, so that value becomes the center of the interval. \param value Center \return Interval with value as center */ QwtInterval QwtInterval::symmetrize( double value ) const { if ( !isValid() ) return *this; const double delta = qMax( qAbs( value - d_maxValue ), qAbs( value - d_minValue ) ); return QwtInterval( value - delta, value + delta ); } /*! Limit the interval, keeping the border modes \param lowerBound Lower limit \param upperBound Upper limit \return Limited interval */ QwtInterval QwtInterval::limited( double lowerBound, double upperBound ) const { if ( !isValid() || lowerBound > upperBound ) return QwtInterval(); double minValue = qMax( d_minValue, lowerBound ); minValue = qMin( minValue, upperBound ); double maxValue = qMax( d_maxValue, lowerBound ); maxValue = qMin( maxValue, upperBound ); return QwtInterval( minValue, maxValue, d_borderFlags ); } /*! \brief Extend the interval If value is below minValue(), value becomes the lower limit. If value is above maxValue(), value becomes the upper limit. extend() has no effect for invalid intervals \param value Value \return extended interval \sa isValid() */ QwtInterval QwtInterval::extend( double value ) const { if ( !isValid() ) return *this; return QwtInterval( qMin( value, d_minValue ), qMax( value, d_maxValue ), d_borderFlags ); } /*! Extend an interval \param value Value \return Reference of the extended interval \sa extend() */ QwtInterval& QwtInterval::operator|=( double value ) { *this = *this | value; return *this; } #ifndef QT_NO_DEBUG_STREAM QDebug operator<<( QDebug debug, const QwtInterval &interval ) { const int flags = interval.borderFlags(); debug.nospace() << "QwtInterval(" << ( ( flags & QwtInterval::ExcludeMinimum ) ? "]" : "[" ) << interval.minValue() << "," << interval.maxValue() << ( ( flags & QwtInterval::ExcludeMaximum ) ? "[" : "]" ) << ")"; return debug.space(); } #endif connectome-workbench-1.4.2/src/Qwt/qwt_interval.h000066400000000000000000000157761360521144700221050ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_INTERVAL_H #define QWT_INTERVAL_H #include "qwt_global.h" #include #ifndef QT_NO_DEBUG_STREAM #include #endif /*! \brief A class representing an interval The interval is represented by 2 doubles, the lower and the upper limit. */ class QWT_EXPORT QwtInterval { public: /*! Flag indicating if a border is included or excluded \sa setBorderFlags(), borderFlags() */ enum BorderFlag { //! Min/Max values are inside the interval IncludeBorders = 0x00, //! Min value is not included in the interval ExcludeMinimum = 0x01, //! Max value is not included in the interval ExcludeMaximum = 0x02, //! Min/Max values are not included in the interval ExcludeBorders = ExcludeMinimum | ExcludeMaximum }; //! Border flags typedef QFlags BorderFlags; QwtInterval(); QwtInterval( double minValue, double maxValue, BorderFlags = IncludeBorders ); void setInterval( double minValue, double maxValue, BorderFlags = IncludeBorders ); QwtInterval normalized() const; QwtInterval inverted() const; QwtInterval limited( double minValue, double maxValue ) const; bool operator==( const QwtInterval & ) const; bool operator!=( const QwtInterval & ) const; void setBorderFlags( BorderFlags ); BorderFlags borderFlags() const; double minValue() const; double maxValue() const; double width() const; void setMinValue( double ); void setMaxValue( double ); bool contains( double value ) const; bool intersects( const QwtInterval & ) const; QwtInterval intersect( const QwtInterval & ) const; QwtInterval unite( const QwtInterval & ) const; QwtInterval operator|( const QwtInterval & ) const; QwtInterval operator&( const QwtInterval & ) const; QwtInterval &operator|=( const QwtInterval & ); QwtInterval &operator&=( const QwtInterval & ); QwtInterval extend( double value ) const; QwtInterval operator|( double ) const; QwtInterval &operator|=( double ); bool isValid() const; bool isNull() const; void invalidate(); QwtInterval symmetrize( double value ) const; private: double d_minValue; double d_maxValue; BorderFlags d_borderFlags; }; Q_DECLARE_TYPEINFO(QwtInterval, Q_MOVABLE_TYPE); /*! \brief Default Constructor Creates an invalid interval [0.0, -1.0] \sa setInterval(), isValid() */ inline QwtInterval::QwtInterval(): d_minValue( 0.0 ), d_maxValue( -1.0 ), d_borderFlags( IncludeBorders ) { } /*! Constructor Build an interval with from min/max values \param minValue Minimum value \param maxValue Maximum value \param borderFlags Include/Exclude borders */ inline QwtInterval::QwtInterval( double minValue, double maxValue, BorderFlags borderFlags ): d_minValue( minValue ), d_maxValue( maxValue ), d_borderFlags( borderFlags ) { } /*! Assign the limits of the interval \param minValue Minimum value \param maxValue Maximum value \param borderFlags Include/Exclude borders */ inline void QwtInterval::setInterval( double minValue, double maxValue, BorderFlags borderFlags ) { d_minValue = minValue; d_maxValue = maxValue; d_borderFlags = borderFlags; } /*! Change the border flags \param borderFlags Or'd BorderMode flags \sa borderFlags() */ inline void QwtInterval::setBorderFlags( BorderFlags borderFlags ) { d_borderFlags = borderFlags; } /*! \return Border flags \sa setBorderFlags() */ inline QwtInterval::BorderFlags QwtInterval::borderFlags() const { return d_borderFlags; } /*! Assign the lower limit of the interval \param minValue Minimum value */ inline void QwtInterval::setMinValue( double minValue ) { d_minValue = minValue; } /*! Assign the upper limit of the interval \param maxValue Maximum value */ inline void QwtInterval::setMaxValue( double maxValue ) { d_maxValue = maxValue; } //! \return Lower limit of the interval inline double QwtInterval::minValue() const { return d_minValue; } //! \return Upper limit of the interval inline double QwtInterval::maxValue() const { return d_maxValue; } /*! A interval is valid when minValue() <= maxValue(). In case of QwtInterval::ExcludeBorders it is true when minValue() < maxValue() \return True, when the interval is valid */ inline bool QwtInterval::isValid() const { if ( ( d_borderFlags & ExcludeBorders ) == 0 ) return d_minValue <= d_maxValue; else return d_minValue < d_maxValue; } /*! \brief Return the width of an interval The width of invalid intervals is 0.0, otherwise the result is maxValue() - minValue(). \return Interval width \sa isValid() */ inline double QwtInterval::width() const { return isValid() ? ( d_maxValue - d_minValue ) : 0.0; } /*! \brief Intersection of two intervals \param other Interval to intersect with \return Intersection of this and other \sa intersect() */ inline QwtInterval QwtInterval::operator&( const QwtInterval &other ) const { return intersect( other ); } /*! Union of two intervals \param other Interval to unite with \return Union of this and other \sa unite() */ inline QwtInterval QwtInterval::operator|( const QwtInterval &other ) const { return unite( other ); } /*! \brief Compare two intervals \param other Interval to compare with \return True, when this and other are equal */ inline bool QwtInterval::operator==( const QwtInterval &other ) const { return ( d_minValue == other.d_minValue ) && ( d_maxValue == other.d_maxValue ) && ( d_borderFlags == other.d_borderFlags ); } /*! \brief Compare two intervals \param other Interval to compare with \return True, when this and other are not equal */ inline bool QwtInterval::operator!=( const QwtInterval &other ) const { return ( !( *this == other ) ); } /*! Extend an interval \param value Value \return Extended interval \sa extend() */ inline QwtInterval QwtInterval::operator|( double value ) const { return extend( value ); } //! \return true, if isValid() && (minValue() >= maxValue()) inline bool QwtInterval::isNull() const { return isValid() && d_minValue >= d_maxValue; } /*! Invalidate the interval The limits are set to interval [0.0, -1.0] \sa isValid() */ inline void QwtInterval::invalidate() { d_minValue = 0.0; d_maxValue = -1.0; } Q_DECLARE_OPERATORS_FOR_FLAGS( QwtInterval::BorderFlags ) Q_DECLARE_METATYPE( QwtInterval ) #ifndef QT_NO_DEBUG_STREAM QWT_EXPORT QDebug operator<<( QDebug, const QwtInterval & ); #endif #endif connectome-workbench-1.4.2/src/Qwt/qwt_interval_symbol.cpp000066400000000000000000000175471360521144700240230ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_interval_symbol.h" #include "qwt_painter.h" #include "qwt_math.h" #include #if QT_VERSION < 0x040601 #define qAtan2(y, x) ::atan2(y, x) #define qFastSin(x) qSin(x) #define qFastCos(x) qCos(x) #endif class QwtIntervalSymbol::PrivateData { public: PrivateData(): style( QwtIntervalSymbol::NoSymbol ), width( 6 ) { } bool operator==( const PrivateData &other ) const { return ( style == other.style ) && ( width == other.width ) && ( brush == other.brush ) && ( pen == other.pen ); } QwtIntervalSymbol::Style style; int width; QPen pen; QBrush brush; }; /*! Constructor \param style Style of the symbol \sa setStyle(), style(), Style */ QwtIntervalSymbol::QwtIntervalSymbol( Style style ) { d_data = new PrivateData(); d_data->style = style; } //! Copy constructor QwtIntervalSymbol::QwtIntervalSymbol( const QwtIntervalSymbol &other ) { d_data = new PrivateData(); *d_data = *other.d_data; } //! Destructor QwtIntervalSymbol::~QwtIntervalSymbol() { delete d_data; } //! \brief Assignment operator QwtIntervalSymbol &QwtIntervalSymbol::operator=( const QwtIntervalSymbol &other ) { *d_data = *other.d_data; return *this; } //! \brief Compare two symbols bool QwtIntervalSymbol::operator==( const QwtIntervalSymbol &other ) const { return *d_data == *other.d_data; } //! \brief Compare two symbols bool QwtIntervalSymbol::operator!=( const QwtIntervalSymbol &other ) const { return !( *d_data == *other.d_data ); } /*! Specify the symbol style \param style Style \sa style(), Style */ void QwtIntervalSymbol::setStyle( Style style ) { d_data->style = style; } /*! \return Current symbol style \sa setStyle() */ QwtIntervalSymbol::Style QwtIntervalSymbol::style() const { return d_data->style; } /*! Specify the width of the symbol It is used depending on the style. \param width Width \sa width(), setStyle() */ void QwtIntervalSymbol::setWidth( int width ) { d_data->width = width; } /*! \return Width of the symbol. \sa setWidth(), setStyle() */ int QwtIntervalSymbol::width() const { return d_data->width; } /*! \brief Assign a brush The brush is used for the Box style. \param brush Brush \sa brush() */ void QwtIntervalSymbol::setBrush( const QBrush &brush ) { d_data->brush = brush; } /*! \return Brush \sa setBrush() */ const QBrush& QwtIntervalSymbol::brush() const { return d_data->brush; } /*! Build and assign a pen In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it non cosmetic ( see QPen::isCosmetic() ). This method has been introduced to hide this incompatibility. \param color Pen color \param width Pen width \param style Pen style \sa pen(), brush() */ void QwtIntervalSymbol::setPen( const QColor &color, qreal width, Qt::PenStyle style ) { setPen( QPen( color, width, style ) ); } /*! Assign a pen \param pen Pen \sa pen(), setBrush() */ void QwtIntervalSymbol::setPen( const QPen &pen ) { d_data->pen = pen; } /*! \return Pen \sa setPen(), brush() */ const QPen& QwtIntervalSymbol::pen() const { return d_data->pen; } /*! Draw a symbol depending on its style \param painter Painter \param orientation Orientation \param from Start point of the interval in target device coordinates \param to End point of the interval in target device coordinates \sa setStyle() */ void QwtIntervalSymbol::draw( QPainter *painter, Qt::Orientation orientation, const QPointF &from, const QPointF &to ) const { const qreal pw = qMax( painter->pen().widthF(), qreal( 1.0 ) ); QPointF p1 = from; QPointF p2 = to; if ( QwtPainter::roundingAlignment( painter ) ) { p1 = p1.toPoint(); p2 = p2.toPoint(); } switch ( d_data->style ) { case QwtIntervalSymbol::Bar: { QwtPainter::drawLine( painter, p1, p2 ); if ( d_data->width > pw ) { if ( ( orientation == Qt::Horizontal ) && ( p1.y() == p2.y() ) ) { const double sw = d_data->width; const double y = p1.y() - sw / 2; QwtPainter::drawLine( painter, p1.x(), y, p1.x(), y + sw ); QwtPainter::drawLine( painter, p2.x(), y, p2.x(), y + sw ); } else if ( ( orientation == Qt::Vertical ) && ( p1.x() == p2.x() ) ) { const double sw = d_data->width; const double x = p1.x() - sw / 2; QwtPainter::drawLine( painter, x, p1.y(), x + sw, p1.y() ); QwtPainter::drawLine( painter, x, p2.y(), x + sw, p2.y() ); } else { const double sw = d_data->width; const double dx = p2.x() - p1.x(); const double dy = p2.y() - p1.y(); const double angle = qAtan2( dy, dx ) + M_PI_2; double dw2 = sw / 2.0; const double cx = qFastCos( angle ) * dw2; const double sy = qFastSin( angle ) * dw2; QwtPainter::drawLine( painter, p1.x() - cx, p1.y() - sy, p1.x() + cx, p1.y() + sy ); QwtPainter::drawLine( painter, p2.x() - cx, p2.y() - sy, p2.x() + cx, p2.y() + sy ); } } break; } case QwtIntervalSymbol::Box: { if ( d_data->width <= pw ) { QwtPainter::drawLine( painter, p1, p2 ); } else { if ( ( orientation == Qt::Horizontal ) && ( p1.y() == p2.y() ) ) { const double sw = d_data->width; const double y = p1.y() - d_data->width / 2; QwtPainter::drawRect( painter, p1.x(), y, p2.x() - p1.x(), sw ); } else if ( ( orientation == Qt::Vertical ) && ( p1.x() == p2.x() ) ) { const double sw = d_data->width; const double x = p1.x() - d_data->width / 2; QwtPainter::drawRect( painter, x, p1.y(), sw, p2.y() - p1.y() ); } else { const double sw = d_data->width; const double dx = p2.x() - p1.x(); const double dy = p2.y() - p1.y(); const double angle = qAtan2( dy, dx ) + M_PI_2; double dw2 = sw / 2.0; const double cx = qFastCos( angle ) * dw2; const double sy = qFastSin( angle ) * dw2; QPolygonF polygon; polygon += QPointF( p1.x() - cx, p1.y() - sy ); polygon += QPointF( p1.x() + cx, p1.y() + sy ); polygon += QPointF( p2.x() + cx, p2.y() + sy ); polygon += QPointF( p2.x() - cx, p2.y() - sy ); QwtPainter::drawPolygon( painter, polygon ); } } break; } default:; } } connectome-workbench-1.4.2/src/Qwt/qwt_interval_symbol.h000066400000000000000000000043141360521144700234540ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_INTERVAL_SYMBOL_H #define QWT_INTERVAL_SYMBOL_H #include "qwt_global.h" #include #include class QPainter; class QRect; class QPointF; /*! \brief A drawing primitive for displaying an interval like an error bar \sa QwtPlotIntervalCurve */ class QWT_EXPORT QwtIntervalSymbol { public: //! Symbol style enum Style { //! No Style. The symbol cannot be drawn. NoSymbol = -1, /*! The symbol displays a line with caps at the beginning/end. The size of the caps depends on the symbol width(). */ Bar, /*! The symbol displays a plain rectangle using pen() and brush(). The size of the rectangle depends on the translated interval and the width(), */ Box, /*! Styles >= UserSymbol are reserved for derived classes of QwtIntervalSymbol that overload draw() with additional application specific symbol types. */ UserSymbol = 1000 }; public: QwtIntervalSymbol( Style = NoSymbol ); QwtIntervalSymbol( const QwtIntervalSymbol & ); virtual ~QwtIntervalSymbol(); QwtIntervalSymbol &operator=( const QwtIntervalSymbol & ); bool operator==( const QwtIntervalSymbol & ) const; bool operator!=( const QwtIntervalSymbol & ) const; void setWidth( int ); int width() const; void setBrush( const QBrush& b ); const QBrush& brush() const; void setPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine ); void setPen( const QPen & ); const QPen& pen() const; void setStyle( Style ); Style style() const; virtual void draw( QPainter *, Qt::Orientation, const QPointF& from, const QPointF& to ) const; private: class PrivateData; PrivateData* d_data; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_legend.cpp000066400000000000000000000515371360521144700220450ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_legend.h" #include "qwt_legend_label.h" #include "qwt_dyngrid_layout.h" #include "qwt_math.h" #include "qwt_plot_item.h" #include "qwt_painter.h" #include #include #include #include #include #include class QwtLegendMap { public: inline bool isEmpty() const { return d_entries.isEmpty(); } void insert( const QVariant &, const QList & ); void remove( const QVariant & ); void removeWidget( const QWidget * ); QList legendWidgets( const QVariant & ) const; QVariant itemInfo( const QWidget * ) const; private: // we don't know anything about itemInfo and therefore don't have // any key that can be used for a map or hashtab. // But a simple linear list is o.k. here, as we will never have // more than a few entries. class Entry { public: QVariant itemInfo; QList widgets; }; QList< Entry > d_entries; }; void QwtLegendMap::insert( const QVariant &itemInfo, const QList &widgets ) { for ( int i = 0; i < d_entries.size(); i++ ) { Entry &entry = d_entries[i]; if ( entry.itemInfo == itemInfo ) { entry.widgets = widgets; return; } } Entry newEntry; newEntry.itemInfo = itemInfo; newEntry.widgets = widgets; d_entries += newEntry; } void QwtLegendMap::remove( const QVariant &itemInfo ) { for ( int i = 0; i < d_entries.size(); i++ ) { Entry &entry = d_entries[i]; if ( entry.itemInfo == itemInfo ) { d_entries.removeAt( i ); return; } } } void QwtLegendMap::removeWidget( const QWidget *widget ) { QWidget *w = const_cast( widget ); for ( int i = 0; i < d_entries.size(); i++ ) d_entries[ i ].widgets.removeAll( w ); } QVariant QwtLegendMap::itemInfo( const QWidget *widget ) const { if ( widget != NULL ) { QWidget *w = const_cast( widget ); for ( int i = 0; i < d_entries.size(); i++ ) { const Entry &entry = d_entries[i]; if ( entry.widgets.indexOf( w ) >= 0 ) return entry.itemInfo; } } return QVariant(); } QList QwtLegendMap::legendWidgets( const QVariant &itemInfo ) const { if ( itemInfo.isValid() ) { for ( int i = 0; i < d_entries.size(); i++ ) { const Entry &entry = d_entries[i]; if ( entry.itemInfo == itemInfo ) return entry.widgets; } } return QList(); } class QwtLegend::PrivateData { public: PrivateData(): itemMode( QwtLegendData::ReadOnly ), view( NULL ) { } QwtLegendData::Mode itemMode; QwtLegendMap itemMap; class LegendView; LegendView *view; }; class QwtLegend::PrivateData::LegendView: public QScrollArea { public: LegendView( QWidget *parent ): QScrollArea( parent ) { contentsWidget = new QWidget( this ); contentsWidget->setObjectName( "QwtLegendViewContents" ); setWidget( contentsWidget ); setWidgetResizable( false ); viewport()->setObjectName( "QwtLegendViewport" ); // QScrollArea::setWidget internally sets autoFillBackground to true // But we don't want a background. contentsWidget->setAutoFillBackground( false ); viewport()->setAutoFillBackground( false ); } virtual bool event( QEvent *event ) { if ( event->type() == QEvent::PolishRequest ) { setFocusPolicy( Qt::NoFocus ); } if ( event->type() == QEvent::Resize ) { // adjust the size to en/disable the scrollbars // before QScrollArea adjusts the viewport size const QRect cr = contentsRect(); int w = cr.width(); int h = contentsWidget->heightForWidth( cr.width() ); if ( h > w ) { w -= verticalScrollBar()->sizeHint().width(); h = contentsWidget->heightForWidth( w ); } contentsWidget->resize( w, h ); } return QScrollArea::event( event ); } virtual bool viewportEvent( QEvent *event ) { bool ok = QScrollArea::viewportEvent( event ); if ( event->type() == QEvent::Resize ) { layoutContents(); } return ok; } QSize viewportSize( int w, int h ) const { const int sbHeight = horizontalScrollBar()->sizeHint().height(); const int sbWidth = verticalScrollBar()->sizeHint().width(); const int cw = contentsRect().width(); const int ch = contentsRect().height(); int vw = cw; int vh = ch; if ( w > vw ) vh -= sbHeight; if ( h > vh ) { vw -= sbWidth; if ( w > vw && vh == ch ) vh -= sbHeight; } return QSize( vw, vh ); } void layoutContents() { const QwtDynGridLayout *tl = qobject_cast( contentsWidget->layout() ); if ( tl == NULL ) return; const QSize visibleSize = viewport()->contentsRect().size(); const int minW = int( tl->maxItemWidth() ) + 2 * tl->margin(); int w = qMax( visibleSize.width(), minW ); int h = qMax( tl->heightForWidth( w ), visibleSize.height() ); const int vpWidth = viewportSize( w, h ).width(); if ( w > vpWidth ) { w = qMax( vpWidth, minW ); h = qMax( tl->heightForWidth( w ), visibleSize.height() ); } contentsWidget->resize( w, h ); } QWidget *contentsWidget; }; /*! Constructor \param parent Parent widget */ QwtLegend::QwtLegend( QWidget *parent ): QwtAbstractLegend( parent ) { setFrameStyle( NoFrame ); d_data = new QwtLegend::PrivateData; d_data->view = new QwtLegend::PrivateData::LegendView( this ); d_data->view->setObjectName( "QwtLegendView" ); d_data->view->setFrameStyle( NoFrame ); QwtDynGridLayout *gridLayout = new QwtDynGridLayout( d_data->view->contentsWidget ); gridLayout->setAlignment( Qt::AlignHCenter | Qt::AlignTop ); d_data->view->contentsWidget->installEventFilter( this ); QVBoxLayout *layout = new QVBoxLayout( this ); layout->setContentsMargins( 0, 0, 0, 0 ); layout->addWidget( d_data->view ); } //! Destructor QwtLegend::~QwtLegend() { delete d_data; } /*! \brief Set the maximum number of entries in a row F.e when the maximum is set to 1 all items are aligned vertically. 0 means unlimited \param numColums Maximum number of entries in a row \sa maxColumns(), QwtDynGridLayout::setMaxColumns() */ void QwtLegend::setMaxColumns( uint numColums ) { QwtDynGridLayout *tl = qobject_cast( d_data->view->contentsWidget->layout() ); if ( tl ) tl->setMaxColumns( numColums ); } /*! \return Maximum number of entries in a row \sa setMaxColumns(), QwtDynGridLayout::maxColumns() */ uint QwtLegend::maxColumns() const { uint maxCols = 0; const QwtDynGridLayout *tl = qobject_cast( d_data->view->contentsWidget->layout() ); if ( tl ) maxCols = tl->maxColumns(); return maxCols; } /*! \brief Set the default mode for legend labels Legend labels will be constructed according to the attributes in a QwtLegendData object. When it doesn't contain a value for the QwtLegendData::ModeRole the label will be initialized with the default mode of the legend. \param mode Default item mode \sa itemMode(), QwtLegendData::value(), QwtPlotItem::legendData() \note Changing the mode doesn't have any effect on existing labels. */ void QwtLegend::setDefaultItemMode( QwtLegendData::Mode mode ) { d_data->itemMode = mode; } /*! \return Default item mode \sa setDefaultItemMode() */ QwtLegendData::Mode QwtLegend::defaultItemMode() const { return d_data->itemMode; } /*! The contents widget is the only child of the viewport of the internal QScrollArea and the parent widget of all legend items. \return Container widget of the legend items */ QWidget *QwtLegend::contentsWidget() { return d_data->view->contentsWidget; } /*! \return Horizontal scrollbar \sa verticalScrollBar() */ QScrollBar *QwtLegend::horizontalScrollBar() const { return d_data->view->horizontalScrollBar(); } /*! \return Vertical scrollbar \sa horizontalScrollBar() */ QScrollBar *QwtLegend::verticalScrollBar() const { return d_data->view->verticalScrollBar(); } /*! The contents widget is the only child of the viewport of the internal QScrollArea and the parent widget of all legend items. \return Container widget of the legend items */ const QWidget *QwtLegend::contentsWidget() const { return d_data->view->contentsWidget; } /*! \brief Update the entries for an item \param itemInfo Info for an item \param data List of legend entry attributes for the item */ void QwtLegend::updateLegend( const QVariant &itemInfo, const QList &data ) { QList widgetList = legendWidgets( itemInfo ); if ( widgetList.size() != data.size() ) { QLayout *contentsLayout = d_data->view->contentsWidget->layout(); while ( widgetList.size() > data.size() ) { QWidget *w = widgetList.takeLast(); contentsLayout->removeWidget( w ); // updates might be triggered by signals from the legend widget // itself. So we better don't delete it here. w->hide(); w->deleteLater(); } for ( int i = widgetList.size(); i < data.size(); i++ ) { QWidget *widget = createWidget( data[i] ); if ( contentsLayout ) contentsLayout->addWidget( widget ); if ( isVisible() ) { // QLayout does a delayed show, with the effect, that // the size hint will be wrong, when applications // call replot() right after changing the list // of plot items. So we better do the show now. widget->setVisible( true ); } widgetList += widget; } if ( widgetList.isEmpty() ) { d_data->itemMap.remove( itemInfo ); } else { d_data->itemMap.insert( itemInfo, widgetList ); } updateTabOrder(); } for ( int i = 0; i < data.size(); i++ ) updateWidget( widgetList[i], data[i] ); } /*! \brief Create a widget to be inserted into the legend The default implementation returns a QwtLegendLabel. \param data Attributes of the legend entry \return Widget representing data on the legend \note updateWidget() will called soon after createWidget() with the same attributes. */ QWidget *QwtLegend::createWidget( const QwtLegendData &data ) const { Q_UNUSED( data ); QwtLegendLabel *label = new QwtLegendLabel(); label->setItemMode( defaultItemMode() ); connect( label, SIGNAL( clicked() ), SLOT( itemClicked() ) ); connect( label, SIGNAL( checked( bool ) ), SLOT( itemChecked( bool ) ) ); return label; } /*! \brief Update the widget \param widget Usually a QwtLegendLabel \param data Attributes to be displayed \sa createWidget() \note When widget is no QwtLegendLabel updateWidget() does nothing. */ void QwtLegend::updateWidget( QWidget *widget, const QwtLegendData &data ) { QwtLegendLabel *label = qobject_cast( widget ); if ( label ) { label->setData( data ); if ( !data.value( QwtLegendData::ModeRole ).isValid() ) { // use the default mode, when there is no specific // hint from the legend data label->setItemMode( defaultItemMode() ); } } } void QwtLegend::updateTabOrder() { QLayout *contentsLayout = d_data->view->contentsWidget->layout(); if ( contentsLayout ) { // set tab focus chain QWidget *w = NULL; for ( int i = 0; i < contentsLayout->count(); i++ ) { QLayoutItem *item = contentsLayout->itemAt( i ); if ( w && item->widget() ) QWidget::setTabOrder( w, item->widget() ); w = item->widget(); } } } //! Return a size hint. QSize QwtLegend::sizeHint() const { QSize hint = d_data->view->contentsWidget->sizeHint(); hint += QSize( 2 * frameWidth(), 2 * frameWidth() ); return hint; } /*! \return The preferred height, for a width. \param width Width */ int QwtLegend::heightForWidth( int width ) const { width -= 2 * frameWidth(); int h = d_data->view->contentsWidget->heightForWidth( width ); if ( h >= 0 ) h += 2 * frameWidth(); return h; } /*! Handle QEvent::ChildRemoved andQEvent::LayoutRequest events for the contentsWidget(). \param object Object to be filtered \param event Event \return Forwarded to QwtAbstractLegend::eventFilter() */ bool QwtLegend::eventFilter( QObject *object, QEvent *event ) { if ( object == d_data->view->contentsWidget ) { switch ( event->type() ) { case QEvent::ChildRemoved: { const QChildEvent *ce = static_cast(event); if ( ce->child()->isWidgetType() ) { QWidget *w = static_cast< QWidget * >( ce->child() ); d_data->itemMap.removeWidget( w ); } break; } case QEvent::LayoutRequest: { d_data->view->layoutContents(); if ( parentWidget() && parentWidget()->layout() == NULL ) { /* We want the parent widget ( usually QwtPlot ) to recalculate its layout, when the contentsWidget has changed. But because of the scroll view we have to forward the LayoutRequest event manually. We don't use updateGeometry() because it doesn't post LayoutRequest events when the legend is hidden. But we want the parent widget notified, so it can show/hide the legend depending on its items. */ QApplication::postEvent( parentWidget(), new QEvent( QEvent::LayoutRequest ) ); } break; } default: break; } } return QwtAbstractLegend::eventFilter( object, event ); } /*! Called internally when the legend has been clicked on. Emits a clicked() signal. */ void QwtLegend::itemClicked() { QWidget *w = qobject_cast( sender() ); if ( w ) { const QVariant itemInfo = d_data->itemMap.itemInfo( w ); if ( itemInfo.isValid() ) { const QList widgetList = d_data->itemMap.legendWidgets( itemInfo ); const int index = widgetList.indexOf( w ); if ( index >= 0 ) Q_EMIT clicked( itemInfo, index ); } } } /*! Called internally when the legend has been checked Emits a checked() signal. */ void QwtLegend::itemChecked( bool on ) { QWidget *w = qobject_cast( sender() ); if ( w ) { const QVariant itemInfo = d_data->itemMap.itemInfo( w ); if ( itemInfo.isValid() ) { const QList widgetList = d_data->itemMap.legendWidgets( itemInfo ); const int index = widgetList.indexOf( w ); if ( index >= 0 ) Q_EMIT checked( itemInfo, on, index ); } } } /*! Render the legend into a given rectangle. \param painter Painter \param rect Bounding rectangle \param fillBackground When true, fill rect with the widget background \sa renderLegend() is used by QwtPlotRenderer - not by QwtLegend itself */ void QwtLegend::renderLegend( QPainter *painter, const QRectF &rect, bool fillBackground ) const { if ( d_data->itemMap.isEmpty() ) return; if ( fillBackground ) { if ( autoFillBackground() || testAttribute( Qt::WA_StyledBackground ) ) { QwtPainter::drawBackgound( painter, rect, this ); } } const QwtDynGridLayout *legendLayout = qobject_cast( contentsWidget()->layout() ); if ( legendLayout == NULL ) return; int left, right, top, bottom; getContentsMargins( &left, &top, &right, &bottom ); QRect layoutRect; layoutRect.setLeft( qCeil( rect.left() ) + left ); layoutRect.setTop( qCeil( rect.top() ) + top ); layoutRect.setRight( qFloor( rect.right() ) - right ); layoutRect.setBottom( qFloor( rect.bottom() ) - bottom ); uint numCols = legendLayout->columnsForWidth( layoutRect.width() ); QList itemRects = legendLayout->layoutItems( layoutRect, numCols ); int index = 0; for ( int i = 0; i < legendLayout->count(); i++ ) { QLayoutItem *item = legendLayout->itemAt( i ); QWidget *w = item->widget(); if ( w ) { painter->save(); painter->setClipRect( itemRects[index], Qt::IntersectClip ); renderItem( painter, w, itemRects[index], fillBackground ); index++; painter->restore(); } } } /*! Render a legend entry into a given rectangle. \param painter Painter \param widget Widget representing a legend entry \param rect Bounding rectangle \param fillBackground When true, fill rect with the widget background \note When widget is not derived from QwtLegendLabel renderItem does nothing beside the background */ void QwtLegend::renderItem( QPainter *painter, const QWidget *widget, const QRectF &rect, bool fillBackground ) const { if ( fillBackground ) { if ( widget->autoFillBackground() || widget->testAttribute( Qt::WA_StyledBackground ) ) { QwtPainter::drawBackgound( painter, rect, widget ); } } const QwtLegendLabel *label = qobject_cast( widget ); if ( label ) { // icon const QwtGraphic &icon = label->data().icon(); const QSizeF sz = icon.defaultSize(); const QRectF iconRect( rect.x() + label->margin(), rect.center().y() - 0.5 * sz.height(), sz.width(), sz.height() ); icon.render( painter, iconRect, Qt::KeepAspectRatio ); // title QRectF titleRect = rect; titleRect.setX( iconRect.right() + 2 * label->spacing() ); painter->setFont( label->font() ); painter->setPen( label->palette().color( QPalette::Text ) ); const_cast< QwtLegendLabel *>( label )->drawText( painter, titleRect ); } } /*! \return List of widgets associated to a item \param itemInfo Info about an item \sa legendWidget(), itemInfo(), QwtPlot::itemToInfo() */ QList QwtLegend::legendWidgets( const QVariant &itemInfo ) const { return d_data->itemMap.legendWidgets( itemInfo ); } /*! \return First widget in the list of widgets associated to an item \param itemInfo Info about an item \sa itemInfo(), QwtPlot::itemToInfo() \note Almost all types of items have only one widget */ QWidget *QwtLegend::legendWidget( const QVariant &itemInfo ) const { const QList list = d_data->itemMap.legendWidgets( itemInfo ); if ( list.isEmpty() ) return NULL; return list[0]; } /*! Find the item that is associated to a widget \param widget Widget on the legend \return Associated item info \sa legendWidget() */ QVariant QwtLegend::itemInfo( const QWidget *widget ) const { return d_data->itemMap.itemInfo( widget ); } //! \return True, when no item is inserted bool QwtLegend::isEmpty() const { return d_data->itemMap.isEmpty(); } /*! Return the extent, that is needed for the scrollbars \param orientation Orientation ( \return The width of the vertical scrollbar for Qt::Horizontal and v.v. */ int QwtLegend::scrollExtent( Qt::Orientation orientation ) const { int extent = 0; if ( orientation == Qt::Horizontal ) extent = verticalScrollBar()->sizeHint().width(); else extent = horizontalScrollBar()->sizeHint().height(); return extent; } connectome-workbench-1.4.2/src/Qwt/qwt_legend.h000066400000000000000000000065621360521144700215100ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_LEGEND_H #define QWT_LEGEND_H #include "qwt_global.h" #include "qwt_abstract_legend.h" #include class QScrollBar; /*! \brief The legend widget The QwtLegend widget is a tabular arrangement of legend items. Legend items might be any type of widget, but in general they will be a QwtLegendLabel. \sa QwtLegendLabel, QwtPlotItem, QwtPlot */ class QWT_EXPORT QwtLegend : public QwtAbstractLegend { Q_OBJECT public: explicit QwtLegend( QWidget *parent = NULL ); virtual ~QwtLegend(); void setMaxColumns( uint numColums ); uint maxColumns() const; void setDefaultItemMode( QwtLegendData::Mode ); QwtLegendData::Mode defaultItemMode() const; QWidget *contentsWidget(); const QWidget *contentsWidget() const; QWidget *legendWidget( const QVariant & ) const; QList legendWidgets( const QVariant & ) const; QVariant itemInfo( const QWidget * ) const; virtual bool eventFilter( QObject *, QEvent * ); virtual QSize sizeHint() const; virtual int heightForWidth( int w ) const; QScrollBar *horizontalScrollBar() const; QScrollBar *verticalScrollBar() const; virtual void renderLegend( QPainter *, const QRectF &, bool fillBackground ) const; virtual void renderItem( QPainter *, const QWidget *, const QRectF &, bool fillBackground ) const; virtual bool isEmpty() const; virtual int scrollExtent( Qt::Orientation ) const; Q_SIGNALS: /*! A signal which is emitted when the user has clicked on a legend label, which is in QwtLegendData::Clickable mode. \param itemInfo Info for the item item of the selected legend item \param index Index of the legend label in the list of widgets that are associated with the plot item \note clicks are disabled as default \sa setDefaultItemMode(), defaultItemMode(), QwtPlot::itemToInfo() */ void clicked( const QVariant &itemInfo, int index ); /*! A signal which is emitted when the user has clicked on a legend label, which is in QwtLegendData::Checkable mode \param itemInfo Info for the item of the selected legend label \param index Index of the legend label in the list of widgets that are associated with the plot item \param on True when the legend label is checked \note clicks are disabled as default \sa setDefaultItemMode(), defaultItemMode(), QwtPlot::itemToInfo() */ void checked( const QVariant &itemInfo, bool on, int index ); public Q_SLOTS: virtual void updateLegend( const QVariant &, const QList & ); protected Q_SLOTS: void itemClicked(); void itemChecked( bool ); protected: virtual QWidget *createWidget( const QwtLegendData & ) const; virtual void updateWidget( QWidget *widget, const QwtLegendData &data ); private: void updateTabOrder(); class PrivateData; PrivateData *d_data; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_legend_data.cpp000066400000000000000000000052521360521144700230270ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_legend_data.h" //! Constructor QwtLegendData::QwtLegendData() { } //! Destructor QwtLegendData::~QwtLegendData() { } /*! Set the legend attributes QwtLegendData actually is a QMap with some convenience interfaces \param map Values \sa values() */ void QwtLegendData::setValues( const QMap &map ) { d_map = map; } /*! \return Legend attributes \sa setValues() */ const QMap &QwtLegendData::values() const { return d_map; } /*! \param role Attribute role \return True, when the internal map has an entry for role */ bool QwtLegendData::hasRole( int role ) const { return d_map.contains( role ); } /*! Set an attribute value \param role Attribute role \param data Attribute value \sa value() */ void QwtLegendData::setValue( int role, const QVariant &data ) { d_map[role] = data; } /*! \param role Attribute role \return Attribute value for a specific role */ QVariant QwtLegendData::value( int role ) const { if ( !d_map.contains( role ) ) return QVariant(); return d_map[role]; } //! \return True, when the internal map is empty bool QwtLegendData::isValid() const { return !d_map.isEmpty(); } //! \return Value of the TitleRole attribute QwtText QwtLegendData::title() const { QwtText text; const QVariant titleValue = value( QwtLegendData::TitleRole ); if ( titleValue.canConvert() ) { text = qvariant_cast( titleValue ); } else if ( titleValue.canConvert() ) { text.setText( qvariant_cast( titleValue ) ); } return text; } //! \return Value of the IconRole attribute QwtGraphic QwtLegendData::icon() const { const QVariant iconValue = value( QwtLegendData::IconRole ); QwtGraphic graphic; if ( iconValue.canConvert() ) { graphic = qvariant_cast( iconValue ); } return graphic; } //! \return Value of the ModeRole attribute QwtLegendData::Mode QwtLegendData::mode() const { const QVariant modeValue = value( QwtLegendData::ModeRole ); if ( modeValue.canConvert() ) { const int mode = qvariant_cast( modeValue ); return static_cast( mode ); } return QwtLegendData::ReadOnly; } connectome-workbench-1.4.2/src/Qwt/qwt_legend_data.h000066400000000000000000000042231360521144700224710ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_LEGEND_DATA_H #define QWT_LEGEND_DATA_H #include "qwt_global.h" #include "qwt_text.h" #include "qwt_graphic.h" #include #include #include /*! \brief Attributes of an entry on a legend QwtLegendData is an abstract container ( like QAbstractModel ) to exchange attributes, that are only known between to the plot item and the legend. By overloading QwtPlotItem::legendData() any other set of attributes could be used, that can be handled by a modified ( or completely different ) implementation of a legend. \sa QwtLegend, QwtPlotLegendItem \note The stockchart example implements a legend as a tree with checkable items */ class QWT_EXPORT QwtLegendData { public: //! Mode defining how a legend entry interacts enum Mode { //! The legend item is not interactive, like a label ReadOnly, //! The legend item is clickable, like a push button Clickable, //! The legend item is checkable, like a checkable button Checkable }; //! Identifier how to interprete a QVariant enum Role { // The value is a Mode ModeRole, // The value is a title TitleRole, // The value is an icon IconRole, // Values < UserRole are reserved for internal use UserRole = 32 }; QwtLegendData(); ~QwtLegendData(); void setValues( const QMap & ); const QMap &values() const; void setValue( int role, const QVariant & ); QVariant value( int role ) const; bool hasRole( int role ) const; bool isValid() const; QwtGraphic icon() const; QwtText title() const; Mode mode() const; private: QMap d_map; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_legend_label.cpp000066400000000000000000000216421360521144700231760ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_legend_label.h" #include "qwt_legend_data.h" #include "qwt_math.h" #include "qwt_painter.h" #include "qwt_symbol.h" #include "qwt_graphic.h" #include #include #include #include #include #include #include static const int ButtonFrame = 2; static const int Margin = 2; static QSize buttonShift( const QwtLegendLabel *w ) { QStyleOption option; option.init( w ); const int ph = w->style()->pixelMetric( QStyle::PM_ButtonShiftHorizontal, &option, w ); const int pv = w->style()->pixelMetric( QStyle::PM_ButtonShiftVertical, &option, w ); return QSize( ph, pv ); } class QwtLegendLabel::PrivateData { public: PrivateData(): itemMode( QwtLegendData::ReadOnly ), isDown( false ), spacing( Margin ) { } QwtLegendData::Mode itemMode; QwtLegendData legendData; bool isDown; QPixmap icon; int spacing; }; /*! Set the attributes of the legend label \param legendData Attributes of the label \sa data() */ void QwtLegendLabel::setData( const QwtLegendData &legendData ) { d_data->legendData = legendData; const bool doUpdate = updatesEnabled(); setUpdatesEnabled( false ); setText( legendData.title() ); setIcon( legendData.icon().toPixmap() ); if ( legendData.hasRole( QwtLegendData::ModeRole ) ) setItemMode( legendData.mode() ); if ( doUpdate ) { setUpdatesEnabled( true ); update(); } } /*! \return Attributes of the label \sa setData(), QwtPlotItem::legendData() */ const QwtLegendData &QwtLegendLabel::data() const { return d_data->legendData; } /*! \param parent Parent widget */ QwtLegendLabel::QwtLegendLabel( QWidget *parent ): QwtTextLabel( parent ) { d_data = new PrivateData; setMargin( Margin ); setIndent( Margin ); } //! Destructor QwtLegendLabel::~QwtLegendLabel() { delete d_data; d_data = NULL; } /*! Set the text to the legend item \param text Text label \sa QwtTextLabel::text() */ void QwtLegendLabel::setText( const QwtText &text ) { const int flags = Qt::AlignLeft | Qt::AlignVCenter | Qt::TextExpandTabs | Qt::TextWordWrap; QwtText txt = text; txt.setRenderFlags( flags ); QwtTextLabel::setText( txt ); } /*! Set the item mode The default is QwtLegendData::ReadOnly \param mode Item mode \sa itemMode() */ void QwtLegendLabel::setItemMode( QwtLegendData::Mode mode ) { if ( mode != d_data->itemMode ) { d_data->itemMode = mode; d_data->isDown = false; setFocusPolicy( ( mode != QwtLegendData::ReadOnly ) ? Qt::TabFocus : Qt::NoFocus ); setMargin( ButtonFrame + Margin ); updateGeometry(); } } /*! \return Item mode \sa setItemMode() */ QwtLegendData::Mode QwtLegendLabel::itemMode() const { return d_data->itemMode; } /*! Assign the icon \param icon Pixmap representing a plot item \sa icon(), QwtPlotItem::legendIcon() */ void QwtLegendLabel::setIcon( const QPixmap &icon ) { d_data->icon = icon; int indent = margin() + d_data->spacing; if ( icon.width() > 0 ) indent += icon.width() + d_data->spacing; setIndent( indent ); } /*! \return Pixmap representing a plot item \sa setIcon() */ QPixmap QwtLegendLabel::icon() const { return d_data->icon; } /*! \brief Change the spacing between icon and text \param spacing Spacing \sa spacing(), QwtTextLabel::margin() */ void QwtLegendLabel::setSpacing( int spacing ) { spacing = qMax( spacing, 0 ); if ( spacing != d_data->spacing ) { d_data->spacing = spacing; int indent = margin() + d_data->spacing; if ( d_data->icon.width() > 0 ) indent += d_data->icon.width() + d_data->spacing; setIndent( indent ); } } /*! \return Spacing between icon and text \sa setSpacing(), QwtTextLabel::margin() */ int QwtLegendLabel::spacing() const { return d_data->spacing; } /*! Check/Uncheck a the item \param on check/uncheck \sa setItemMode() */ void QwtLegendLabel::setChecked( bool on ) { if ( d_data->itemMode == QwtLegendData::Checkable ) { const bool isBlocked = signalsBlocked(); blockSignals( true ); setDown( on ); blockSignals( isBlocked ); } } //! Return true, if the item is checked bool QwtLegendLabel::isChecked() const { return d_data->itemMode == QwtLegendData::Checkable && isDown(); } //! Set the item being down void QwtLegendLabel::setDown( bool down ) { if ( down == d_data->isDown ) return; d_data->isDown = down; update(); if ( d_data->itemMode == QwtLegendData::Clickable ) { if ( d_data->isDown ) Q_EMIT pressed(); else { Q_EMIT released(); Q_EMIT clicked(); } } if ( d_data->itemMode == QwtLegendData::Checkable ) Q_EMIT checked( d_data->isDown ); } //! Return true, if the item is down bool QwtLegendLabel::isDown() const { return d_data->isDown; } //! Return a size hint QSize QwtLegendLabel::sizeHint() const { QSize sz = QwtTextLabel::sizeHint(); sz.setHeight( qMax( sz.height(), d_data->icon.height() + 4 ) ); if ( d_data->itemMode != QwtLegendData::ReadOnly ) { sz += buttonShift( this ); sz = sz.expandedTo( QApplication::globalStrut() ); } return sz; } //! Paint event void QwtLegendLabel::paintEvent( QPaintEvent *e ) { const QRect cr = contentsRect(); QPainter painter( this ); painter.setClipRegion( e->region() ); if ( d_data->isDown ) { qDrawWinButton( &painter, 0, 0, width(), height(), palette(), true ); } painter.save(); if ( d_data->isDown ) { const QSize shiftSize = buttonShift( this ); painter.translate( shiftSize.width(), shiftSize.height() ); } painter.setClipRect( cr ); drawContents( &painter ); if ( !d_data->icon.isNull() ) { QRect iconRect = cr; iconRect.setX( iconRect.x() + margin() ); if ( d_data->itemMode != QwtLegendData::ReadOnly ) iconRect.setX( iconRect.x() + ButtonFrame ); iconRect.setSize( d_data->icon.size() ); iconRect.moveCenter( QPoint( iconRect.center().x(), cr.center().y() ) ); painter.drawPixmap( iconRect, d_data->icon ); } painter.restore(); } //! Handle mouse press events void QwtLegendLabel::mousePressEvent( QMouseEvent *e ) { if ( e->button() == Qt::LeftButton ) { switch ( d_data->itemMode ) { case QwtLegendData::Clickable: { setDown( true ); return; } case QwtLegendData::Checkable: { setDown( !isDown() ); return; } default:; } } QwtTextLabel::mousePressEvent( e ); } //! Handle mouse release events void QwtLegendLabel::mouseReleaseEvent( QMouseEvent *e ) { if ( e->button() == Qt::LeftButton ) { switch ( d_data->itemMode ) { case QwtLegendData::Clickable: { setDown( false ); return; } case QwtLegendData::Checkable: { return; // do nothing, but accept } default:; } } QwtTextLabel::mouseReleaseEvent( e ); } //! Handle key press events void QwtLegendLabel::keyPressEvent( QKeyEvent *e ) { if ( e->key() == Qt::Key_Space ) { switch ( d_data->itemMode ) { case QwtLegendData::Clickable: { if ( !e->isAutoRepeat() ) setDown( true ); return; } case QwtLegendData::Checkable: { if ( !e->isAutoRepeat() ) setDown( !isDown() ); return; } default:; } } QwtTextLabel::keyPressEvent( e ); } //! Handle key release events void QwtLegendLabel::keyReleaseEvent( QKeyEvent *e ) { if ( e->key() == Qt::Key_Space ) { switch ( d_data->itemMode ) { case QwtLegendData::Clickable: { if ( !e->isAutoRepeat() ) setDown( false ); return; } case QwtLegendData::Checkable: { return; // do nothing, but accept } default:; } } QwtTextLabel::keyReleaseEvent( e ); } connectome-workbench-1.4.2/src/Qwt/qwt_legend_label.h000066400000000000000000000036601360521144700226430ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_LEGEND_LABEL_H #define QWT_LEGEND_LABEL_H #include "qwt_global.h" #include "qwt_legend_data.h" #include "qwt_text.h" #include "qwt_text_label.h" #include class QwtLegendData; /*! \brief A widget representing something on a QwtLegend. */ class QWT_EXPORT QwtLegendLabel: public QwtTextLabel { Q_OBJECT public: explicit QwtLegendLabel( QWidget *parent = 0 ); virtual ~QwtLegendLabel(); void setData( const QwtLegendData & ); const QwtLegendData &data() const; void setItemMode( QwtLegendData::Mode ); QwtLegendData::Mode itemMode() const; void setSpacing( int spacing ); int spacing() const; virtual void setText( const QwtText & ); void setIcon( const QPixmap & ); QPixmap icon() const; virtual QSize sizeHint() const; bool isChecked() const; public Q_SLOTS: void setChecked( bool on ); Q_SIGNALS: //! Signal, when the legend item has been clicked void clicked(); //! Signal, when the legend item has been pressed void pressed(); //! Signal, when the legend item has been released void released(); //! Signal, when the legend item has been toggled void checked( bool ); protected: void setDown( bool ); bool isDown() const; virtual void paintEvent( QPaintEvent * ); virtual void mousePressEvent( QMouseEvent * ); virtual void mouseReleaseEvent( QMouseEvent * ); virtual void keyPressEvent( QKeyEvent * ); virtual void keyReleaseEvent( QKeyEvent * ); private: class PrivateData; PrivateData *d_data; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_magnifier.cpp000066400000000000000000000270471360521144700225470ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_magnifier.h" #include "qwt_math.h" #include #include class QwtMagnifier::PrivateData { public: PrivateData(): isEnabled( false ), wheelFactor( 0.9 ), wheelModifiers( Qt::NoModifier ), mouseFactor( 0.95 ), mouseButton( Qt::RightButton ), mouseButtonModifiers( Qt::NoModifier ), keyFactor( 0.9 ), zoomInKey( Qt::Key_Plus ), zoomInKeyModifiers( Qt::NoModifier ), zoomOutKey( Qt::Key_Minus ), zoomOutKeyModifiers( Qt::NoModifier ), mousePressed( false ) { } bool isEnabled; double wheelFactor; Qt::KeyboardModifiers wheelModifiers; double mouseFactor; Qt::MouseButton mouseButton; Qt::KeyboardModifiers mouseButtonModifiers; double keyFactor; int zoomInKey; Qt::KeyboardModifiers zoomInKeyModifiers; int zoomOutKey; Qt::KeyboardModifiers zoomOutKeyModifiers; bool mousePressed; bool hasMouseTracking; QPoint mousePos; }; /*! Constructor \param parent Widget to be magnified */ QwtMagnifier::QwtMagnifier( QWidget *parent ): QObject( parent ) { d_data = new PrivateData(); setEnabled( true ); } //! Destructor QwtMagnifier::~QwtMagnifier() { delete d_data; } /*! \brief En/disable the magnifier When enabled is true an event filter is installed for the observed widget, otherwise the event filter is removed. \param on true or false \sa isEnabled(), eventFilter() */ void QwtMagnifier::setEnabled( bool on ) { if ( d_data->isEnabled != on ) { d_data->isEnabled = on; QObject *o = parent(); if ( o ) { if ( d_data->isEnabled ) o->installEventFilter( this ); else o->removeEventFilter( this ); } } } /*! \return true when enabled, false otherwise \sa setEnabled(), eventFilter() */ bool QwtMagnifier::isEnabled() const { return d_data->isEnabled; } /*! \brief Change the wheel factor The wheel factor defines the ratio between the current range on the parent widget and the zoomed range for each step of the wheel. Use values > 1 for magnification (i.e. 2.0) and values < 1 for scaling down (i.e. 1/2.0 = 0.5). You can use this feature for inverting the direction of the wheel. The default value is 0.9. \param factor Wheel factor \sa wheelFactor(), setWheelButtonState(), setMouseFactor(), setKeyFactor() */ void QwtMagnifier::setWheelFactor( double factor ) { d_data->wheelFactor = factor; } /*! \return Wheel factor \sa setWheelFactor() */ double QwtMagnifier::wheelFactor() const { return d_data->wheelFactor; } /*! Assign keyboard modifiers for zooming in/out using the wheel. The default modifiers are Qt::NoModifiers. \param modifiers Keyboard modifiers \sa wheelModifiers() */ void QwtMagnifier::setWheelModifiers( Qt::KeyboardModifiers modifiers ) { d_data->wheelModifiers = modifiers; } /*! \return Wheel modifiers \sa setWheelModifiers() */ Qt::KeyboardModifiers QwtMagnifier::wheelModifiers() const { return d_data->wheelModifiers; } /*! \brief Change the mouse factor The mouse factor defines the ratio between the current range on the parent widget and the zoomed range for each vertical mouse movement. The default value is 0.95. \param factor Wheel factor \sa mouseFactor(), setMouseButton(), setWheelFactor(), setKeyFactor() */ void QwtMagnifier::setMouseFactor( double factor ) { d_data->mouseFactor = factor; } /*! \return Mouse factor \sa setMouseFactor() */ double QwtMagnifier::mouseFactor() const { return d_data->mouseFactor; } /*! Assign the mouse button, that is used for zooming in/out. The default value is Qt::RightButton. \param button Button \param modifiers Keyboard modifiers \sa getMouseButton() */ void QwtMagnifier::setMouseButton( Qt::MouseButton button, Qt::KeyboardModifiers modifiers ) { d_data->mouseButton = button; d_data->mouseButtonModifiers = modifiers; } //! \sa setMouseButton() void QwtMagnifier::getMouseButton( Qt::MouseButton &button, Qt::KeyboardModifiers &modifiers ) const { button = d_data->mouseButton; modifiers = d_data->mouseButtonModifiers; } /*! \brief Change the key factor The key factor defines the ratio between the current range on the parent widget and the zoomed range for each key press of the zoom in/out keys. The default value is 0.9. \param factor Key factor \sa keyFactor(), setZoomInKey(), setZoomOutKey(), setWheelFactor, setMouseFactor() */ void QwtMagnifier::setKeyFactor( double factor ) { d_data->keyFactor = factor; } /*! \return Key factor \sa setKeyFactor() */ double QwtMagnifier::keyFactor() const { return d_data->keyFactor; } /*! Assign the key, that is used for zooming in. The default combination is Qt::Key_Plus + Qt::NoModifier. \param key \param modifiers \sa getZoomInKey(), setZoomOutKey() */ void QwtMagnifier::setZoomInKey( int key, Qt::KeyboardModifiers modifiers ) { d_data->zoomInKey = key; d_data->zoomInKeyModifiers = modifiers; } /*! \brief Retrieve the settings of the zoom in key \param key Key code, see Qt::Key \param modifiers Keyboard modifiers \sa setZoomInKey() */ void QwtMagnifier::getZoomInKey( int &key, Qt::KeyboardModifiers &modifiers ) const { key = d_data->zoomInKey; modifiers = d_data->zoomInKeyModifiers; } /*! Assign the key, that is used for zooming out. The default combination is Qt::Key_Minus + Qt::NoModifier. \param key \param modifiers \sa getZoomOutKey(), setZoomOutKey() */ void QwtMagnifier::setZoomOutKey( int key, Qt::KeyboardModifiers modifiers ) { d_data->zoomOutKey = key; d_data->zoomOutKeyModifiers = modifiers; } /*! \brief Retrieve the settings of the zoom out key \param key Key code, see Qt::Key \param modifiers Keyboard modifiers \sa setZoomOutKey() */ void QwtMagnifier::getZoomOutKey( int &key, Qt::KeyboardModifiers &modifiers ) const { key = d_data->zoomOutKey; modifiers = d_data->zoomOutKeyModifiers; } /*! \brief Event filter When isEnabled() is true, the mouse events of the observed widget are filtered. \param object Object to be filtered \param event Event \return Forwarded to QObject::eventFilter() \sa widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent() widgetKeyReleaseEvent() */ bool QwtMagnifier::eventFilter( QObject *object, QEvent *event ) { if ( object && object == parent() ) { switch ( event->type() ) { case QEvent::MouseButtonPress: { widgetMousePressEvent( static_cast( event ) ); break; } case QEvent::MouseMove: { widgetMouseMoveEvent( static_cast( event ) ); break; } case QEvent::MouseButtonRelease: { widgetMouseReleaseEvent( static_cast( event ) ); break; } case QEvent::Wheel: { widgetWheelEvent( static_cast( event ) ); break; } case QEvent::KeyPress: { widgetKeyPressEvent( static_cast( event ) ); break; } case QEvent::KeyRelease: { widgetKeyReleaseEvent( static_cast( event ) ); break; } default:; } } return QObject::eventFilter( object, event ); } /*! Handle a mouse press event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMouseReleaseEvent(), widgetMouseMoveEvent() */ void QwtMagnifier::widgetMousePressEvent( QMouseEvent *mouseEvent ) { if ( parentWidget() == NULL ) return; if ( ( mouseEvent->button() != d_data->mouseButton ) || ( mouseEvent->modifiers() != d_data->mouseButtonModifiers ) ) { return; } d_data->hasMouseTracking = parentWidget()->hasMouseTracking(); parentWidget()->setMouseTracking( true ); d_data->mousePos = mouseEvent->pos(); d_data->mousePressed = true; } /*! Handle a mouse release event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseMoveEvent(), */ void QwtMagnifier::widgetMouseReleaseEvent( QMouseEvent *mouseEvent ) { Q_UNUSED( mouseEvent ); if ( d_data->mousePressed && parentWidget() ) { d_data->mousePressed = false; parentWidget()->setMouseTracking( d_data->hasMouseTracking ); } } /*! Handle a mouse move event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), */ void QwtMagnifier::widgetMouseMoveEvent( QMouseEvent *mouseEvent ) { if ( !d_data->mousePressed ) return; const int dy = mouseEvent->pos().y() - d_data->mousePos.y(); if ( dy != 0 ) { double f = d_data->mouseFactor; if ( dy < 0 ) f = 1 / f; rescale( f ); } d_data->mousePos = mouseEvent->pos(); } /*! Handle a wheel event for the observed widget. \param wheelEvent Wheel event \sa eventFilter() */ void QwtMagnifier::widgetWheelEvent( QWheelEvent *wheelEvent ) { if ( wheelEvent->modifiers() != d_data->wheelModifiers ) { return; } if ( d_data->wheelFactor != 0.0 ) { /* A positive delta indicates that the wheel was rotated forwards away from the user; a negative value indicates that the wheel was rotated backwards toward the user. Most mouse types work in steps of 15 degrees, in which case the delta value is a multiple of 120 (== 15 * 8). */ double f = qPow( d_data->wheelFactor, qAbs( wheelEvent->delta() / 120.0 ) ); if ( wheelEvent->delta() > 0 ) f = 1 / f; rescale( f ); } } /*! Handle a key press event for the observed widget. \param keyEvent Key event \sa eventFilter(), widgetKeyReleaseEvent() */ void QwtMagnifier::widgetKeyPressEvent( QKeyEvent *keyEvent ) { if ( keyEvent->key() == d_data->zoomInKey && keyEvent->modifiers() == d_data->zoomInKeyModifiers ) { rescale( d_data->keyFactor ); } else if ( keyEvent->key() == d_data->zoomOutKey && keyEvent->modifiers() == d_data->zoomOutKeyModifiers ) { rescale( 1.0 / d_data->keyFactor ); } } /*! Handle a key release event for the observed widget. \param keyEvent Key event \sa eventFilter(), widgetKeyReleaseEvent() */ void QwtMagnifier::widgetKeyReleaseEvent( QKeyEvent *keyEvent ) { Q_UNUSED( keyEvent ); } //! \return Parent widget, where the rescaling happens QWidget *QwtMagnifier::parentWidget() { return qobject_cast( parent() ); } //! \return Parent widget, where the rescaling happens const QWidget *QwtMagnifier::parentWidget() const { return qobject_cast( parent() ); } connectome-workbench-1.4.2/src/Qwt/qwt_magnifier.h000066400000000000000000000045721360521144700222120ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_MAGNIFIER_H #define QWT_MAGNIFIER_H 1 #include "qwt_global.h" #include class QWidget; class QMouseEvent; class QWheelEvent; class QKeyEvent; /*! \brief QwtMagnifier provides zooming, by magnifying in steps. Using QwtMagnifier a plot can be zoomed in/out in steps using keys, the mouse wheel or moving a mouse button in vertical direction. */ class QWT_EXPORT QwtMagnifier: public QObject { Q_OBJECT public: explicit QwtMagnifier( QWidget * ); virtual ~QwtMagnifier(); QWidget *parentWidget(); const QWidget *parentWidget() const; void setEnabled( bool ); bool isEnabled() const; // mouse void setMouseFactor( double ); double mouseFactor() const; void setMouseButton( Qt::MouseButton, Qt::KeyboardModifiers = Qt::NoModifier ); void getMouseButton( Qt::MouseButton &, Qt::KeyboardModifiers & ) const; // mouse wheel void setWheelFactor( double ); double wheelFactor() const; void setWheelModifiers( Qt::KeyboardModifiers ); Qt::KeyboardModifiers wheelModifiers() const; // keyboard void setKeyFactor( double ); double keyFactor() const; void setZoomInKey( int key, Qt::KeyboardModifiers = Qt::NoModifier ); void getZoomInKey( int &key, Qt::KeyboardModifiers & ) const; void setZoomOutKey( int key, Qt::KeyboardModifiers = Qt::NoModifier ); void getZoomOutKey( int &key, Qt::KeyboardModifiers & ) const; virtual bool eventFilter( QObject *, QEvent * ); protected: /*! Rescale the parent widget \param factor Scale factor */ virtual void rescale( double factor ) = 0; virtual void widgetMousePressEvent( QMouseEvent * ); virtual void widgetMouseReleaseEvent( QMouseEvent * ); virtual void widgetMouseMoveEvent( QMouseEvent * ); virtual void widgetWheelEvent( QWheelEvent * ); virtual void widgetKeyPressEvent( QKeyEvent * ); virtual void widgetKeyReleaseEvent( QKeyEvent * ); private: class PrivateData; PrivateData *d_data; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_math.cpp000066400000000000000000000031441360521144700215270ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_math.h" /*! \brief Find the smallest value in an array \param array Pointer to an array \param size Array size */ double qwtGetMin( const double *array, int size ) { if ( size <= 0 ) return 0.0; double rv = array[0]; for ( int i = 1; i < size; i++ ) rv = qMin( rv, array[i] ); return rv; } /*! \brief Find the largest value in an array \param array Pointer to an array \param size Array size */ double qwtGetMax( const double *array, int size ) { if ( size <= 0 ) return 0.0; double rv = array[0]; for ( int i = 1; i < size; i++ ) rv = qMax( rv, array[i] ); return rv; } /*! \brief Normalize an angle to be int the range [0.0, 2 * PI[ \param radians Angle in radians \return Normalized angle in radians */ double qwtNormalizeRadians( double radians ) { double a = ::fmod( radians, 2.0 * M_PI ); if ( a < 0.0 ) a += 2.0 * M_PI; return a; } /*! \brief Normalize an angle to be int the range [0.0, 360.0[ \param radians Angle in degrees \return Normalized angle in degrees */ double qwtNormalizeDegrees( double degrees ) { double a = ::fmod( degrees, 360.0 ); if ( a < 0.0 ) a += 360.0; return a; } connectome-workbench-1.4.2/src/Qwt/qwt_math.h000066400000000000000000000064551360521144700212040ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_MATH_H #define QWT_MATH_H #include "qwt_global.h" #if defined(_MSC_VER) /* Microsoft says: Define _USE_MATH_DEFINES before including math.h to expose these macro definitions for common math constants. These are placed under an #ifdef since these commonly-defined names are not part of the C/C++ standards. */ #define _USE_MATH_DEFINES 1 #endif #include #include "qwt_global.h" #ifndef M_PI_2 // For Qt <= 4.8.4 M_PI_2 is not known by MinGW-w64 // when compiling with -std=c++11 #define M_PI_2 (1.57079632679489661923) #endif #ifndef LOG_MIN //! Minimum value for logarithmic scales #define LOG_MIN 1.0e-100 #endif #ifndef LOG_MAX //! Maximum value for logarithmic scales #define LOG_MAX 1.0e100 #endif QWT_EXPORT double qwtGetMin( const double *array, int size ); QWT_EXPORT double qwtGetMax( const double *array, int size ); QWT_EXPORT double qwtNormalizeRadians( double radians ); QWT_EXPORT double qwtNormalizeDegrees( double degrees ); /*! \brief Compare 2 values, relative to an interval Values are "equal", when : \f$\cdot value2 - value1 <= abs(intervalSize * 10e^{-6})\f$ \param value1 First value to compare \param value2 Second value to compare \param intervalSize interval size \return 0: if equal, -1: if value2 > value1, 1: if value1 > value2 */ inline int qwtFuzzyCompare( double value1, double value2, double intervalSize ) { const double eps = qAbs( 1.0e-6 * intervalSize ); if ( value2 - value1 > eps ) return -1; if ( value1 - value2 > eps ) return 1; return 0; } inline bool qwtFuzzyGreaterOrEqual( double d1, double d2 ) { return ( d1 >= d2 ) || qFuzzyCompare( d1, d2 ); } inline bool qwtFuzzyLessOrEqual( double d1, double d2 ) { return ( d1 <= d2 ) || qFuzzyCompare( d1, d2 ); } //! Return the sign inline int qwtSign( double x ) { if ( x > 0.0 ) return 1; else if ( x < 0.0 ) return ( -1 ); else return 0; } //! Return the square of a number inline double qwtSqr( double x ) { return x * x; } //! Approximation of arc tangent ( error below 0,005 radians ) inline double qwtFastAtan( double x ) { if ( x < -1.0 ) return -M_PI_2 - x / ( x * x + 0.28 ); if ( x > 1.0 ) return M_PI_2 - x / ( x * x + 0.28 ); return x / ( 1.0 + x * x * 0.28 ); } //! Approximation of arc tangent ( error below 0,005 radians ) inline double qwtFastAtan2( double y, double x ) { if ( x > 0 ) return qwtFastAtan( y / x ); if ( x < 0 ) { const double d = qwtFastAtan( y / x ); return ( y >= 0 ) ? d + M_PI : d - M_PI; } if ( y < 0.0 ) return -M_PI_2; if ( y > 0.0 ) return M_PI_2; return 0.0; } //! Translate degrees into radians inline double qwtRadians( double degrees ) { return degrees * M_PI / 180.0; } //! Translate radians into degrees inline double qwtDegrees( double degrees ) { return degrees * 180.0 / M_PI; } #endif connectome-workbench-1.4.2/src/Qwt/qwt_matrix_raster_data.cpp000066400000000000000000000174771360521144700244710ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_matrix_raster_data.h" #include #include class QwtMatrixRasterData::PrivateData { public: PrivateData(): resampleMode(QwtMatrixRasterData::NearestNeighbour), numColumns(0) { } inline double value(int row, int col) const { return values.data()[ row * numColumns + col ]; } QwtMatrixRasterData::ResampleMode resampleMode; QVector values; int numColumns; int numRows; double dx; double dy; }; //! Constructor QwtMatrixRasterData::QwtMatrixRasterData() { d_data = new PrivateData(); update(); } //! Destructor QwtMatrixRasterData::~QwtMatrixRasterData() { delete d_data; } /*! \brief Set the resampling algorithm \param mode Resampling mode \sa resampleMode(), value() */ void QwtMatrixRasterData::setResampleMode( ResampleMode mode ) { d_data->resampleMode = mode; } /*! \return resampling algorithm \sa setResampleMode(), value() */ QwtMatrixRasterData::ResampleMode QwtMatrixRasterData::resampleMode() const { return d_data->resampleMode; } /*! \brief Assign the bounding interval for an axis Setting the bounding intervals for the X/Y axis is mandatory to define the positions for the values of the value matrix. The interval in Z direction defines the possible range for the values in the matrix, what is f.e used by QwtPlotSpectrogram to map values to colors. The Z-interval might be the bounding interval of the values in the matrix, but usually it isn't. ( f.e a interval of 0.0-100.0 for values in percentage ) \param axis X, Y or Z axis \param interval Interval \sa QwtRasterData::interval(), setValueMatrix() */ void QwtMatrixRasterData::setInterval( Qt::Axis axis, const QwtInterval &interval ) { QwtRasterData::setInterval( axis, interval ); update(); } /*! \brief Assign a value matrix The positions of the values are calculated by dividing the bounding rectangle of the X/Y intervals into equidistant rectangles ( pixels ). Each value corresponds to the center of a pixel. \param values Vector of values \param numColumns Number of columns \sa valueMatrix(), numColumns(), numRows(), setInterval()() */ void QwtMatrixRasterData::setValueMatrix( const QVector &values, int numColumns ) { d_data->values = values; d_data->numColumns = qMax( numColumns, 0 ); update(); } /*! \return Value matrix \sa setValueMatrix(), numColumns(), numRows(), setInterval() */ const QVector QwtMatrixRasterData::valueMatrix() const { return d_data->values; } /*! \brief Change a single value in the matrix \param row Row index \param col Column index \param value New value \sa value(), setValueMatrix() */ void QwtMatrixRasterData::setValue( int row, int col, double value ) { if ( row >= 0 && row < d_data->numRows && col >= 0 && col < d_data->numColumns ) { const int index = row * d_data->numColumns + col; d_data->values.data()[ index ] = value; } } /*! \return Number of columns of the value matrix \sa valueMatrix(), numRows(), setValueMatrix() */ int QwtMatrixRasterData::numColumns() const { return d_data->numColumns; } /*! \return Number of rows of the value matrix \sa valueMatrix(), numColumns(), setValueMatrix() */ int QwtMatrixRasterData::numRows() const { return d_data->numRows; } /*! \brief Calculate the pixel hint pixelHint() returns the geometry of a pixel, that can be used to calculate the resolution and alignment of the plot item, that is representing the data. - NearestNeighbour\n pixelHint() returns the surrounding pixel of the top left value in the matrix. - BilinearInterpolation\n Returns an empty rectangle recommending to render in target device ( f.e. screen ) resolution. \param area Requested area, ignored \return Calculated hint \sa ResampleMode, setMatrix(), setInterval() */ QRectF QwtMatrixRasterData::pixelHint( const QRectF &area ) const { Q_UNUSED( area ) QRectF rect; if ( d_data->resampleMode == NearestNeighbour ) { const QwtInterval intervalX = interval( Qt::XAxis ); const QwtInterval intervalY = interval( Qt::YAxis ); if ( intervalX.isValid() && intervalY.isValid() ) { rect = QRectF( intervalX.minValue(), intervalY.minValue(), d_data->dx, d_data->dy ); } } return rect; } /*! \return the value at a raster position \param x X value in plot coordinates \param y Y value in plot coordinates \sa ResampleMode */ double QwtMatrixRasterData::value( double x, double y ) const { const QwtInterval xInterval = interval( Qt::XAxis ); const QwtInterval yInterval = interval( Qt::YAxis ); if ( !( xInterval.contains(x) && yInterval.contains(y) ) ) return qQNaN(); double value; switch( d_data->resampleMode ) { case BilinearInterpolation: { int col1 = qRound( (x - xInterval.minValue() ) / d_data->dx ) - 1; int row1 = qRound( (y - yInterval.minValue() ) / d_data->dy ) - 1; int col2 = col1 + 1; int row2 = row1 + 1; if ( col1 < 0 ) col1 = col2; else if ( col2 >= static_cast( d_data->numColumns ) ) col2 = col1; if ( row1 < 0 ) row1 = row2; else if ( row2 >= static_cast( d_data->numRows ) ) row2 = row1; const double v11 = d_data->value( row1, col1 ); const double v21 = d_data->value( row1, col2 ); const double v12 = d_data->value( row2, col1 ); const double v22 = d_data->value( row2, col2 ); const double x2 = xInterval.minValue() + ( col2 + 0.5 ) * d_data->dx; const double y2 = yInterval.minValue() + ( row2 + 0.5 ) * d_data->dy; const double rx = ( x2 - x ) / d_data->dx; const double ry = ( y2 - y ) / d_data->dy; const double vr1 = rx * v11 + ( 1.0 - rx ) * v21; const double vr2 = rx * v12 + ( 1.0 - rx ) * v22; value = ry * vr1 + ( 1.0 - ry ) * vr2; break; } case NearestNeighbour: default: { int row = int( (y - yInterval.minValue() ) / d_data->dy ); int col = int( (x - xInterval.minValue() ) / d_data->dx ); // In case of intervals, where the maximum is included // we get out of bound for row/col, when the value for the // maximum is requested. Instead we return the value // from the last row/col if ( row >= d_data->numRows ) row = d_data->numRows - 1; if ( col >= d_data->numColumns ) col = d_data->numColumns - 1; value = d_data->value( row, col ); } } return value; } void QwtMatrixRasterData::update() { d_data->numRows = 0; d_data->dx = 0.0; d_data->dy = 0.0; if ( d_data->numColumns > 0 ) { d_data->numRows = d_data->values.size() / d_data->numColumns; const QwtInterval xInterval = interval( Qt::XAxis ); const QwtInterval yInterval = interval( Qt::YAxis ); if ( xInterval.isValid() ) d_data->dx = xInterval.width() / d_data->numColumns; if ( yInterval.isValid() ) d_data->dy = yInterval.width() / d_data->numRows; } } connectome-workbench-1.4.2/src/Qwt/qwt_matrix_raster_data.h000066400000000000000000000037331360521144700241240ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_MATRIX_RASTER_DATA_H #define QWT_MATRIX_RASTER_DATA_H 1 #include "qwt_global.h" #include "qwt_raster_data.h" #include /*! \brief A class representing a matrix of values as raster data QwtMatrixRasterData implements an interface for a matrix of equidistant values, that can be used by a QwtPlotRasterItem. It implements a couple of resampling algorithms, to provide values for positions, that or not on the value matrix. */ class QWT_EXPORT QwtMatrixRasterData: public QwtRasterData { public: /*! \brief Resampling algorithm The default setting is NearestNeighbour; */ enum ResampleMode { /*! Return the value from the matrix, that is nearest to the the requested position. */ NearestNeighbour, /*! Interpolate the value from the distances and values of the 4 surrounding values in the matrix, */ BilinearInterpolation }; QwtMatrixRasterData(); virtual ~QwtMatrixRasterData(); void setResampleMode(ResampleMode mode); ResampleMode resampleMode() const; virtual void setInterval( Qt::Axis, const QwtInterval & ); void setValueMatrix( const QVector &values, int numColumns ); const QVector valueMatrix() const; void setValue( int row, int col, double value ); int numColumns() const; int numRows() const; virtual QRectF pixelHint( const QRectF & ) const; virtual double value( double x, double y ) const; private: void update(); class PrivateData; PrivateData *d_data; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_null_paintdevice.cpp000066400000000000000000000320171360521144700241240ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_null_paintdevice.h" #include #include class QwtNullPaintDevice::PrivateData { public: PrivateData(): mode( QwtNullPaintDevice::NormalMode ) { } QwtNullPaintDevice::Mode mode; }; class QwtNullPaintDevice::PaintEngine: public QPaintEngine { public: PaintEngine(); virtual bool begin( QPaintDevice * ); virtual bool end(); virtual Type type () const; virtual void updateState(const QPaintEngineState &); virtual void drawRects(const QRect *, int ); virtual void drawRects(const QRectF *, int ); virtual void drawLines(const QLine *, int ); virtual void drawLines(const QLineF *, int ); virtual void drawEllipse(const QRectF &); virtual void drawEllipse(const QRect &); virtual void drawPath(const QPainterPath &); virtual void drawPoints(const QPointF *, int ); virtual void drawPoints(const QPoint *, int ); virtual void drawPolygon(const QPointF *, int , PolygonDrawMode ); virtual void drawPolygon(const QPoint *, int , PolygonDrawMode ); virtual void drawPixmap(const QRectF &, const QPixmap &, const QRectF &); virtual void drawTextItem(const QPointF &, const QTextItem &); virtual void drawTiledPixmap(const QRectF &, const QPixmap &, const QPointF &s); virtual void drawImage(const QRectF &, const QImage &, const QRectF &, Qt::ImageConversionFlags ); private: QwtNullPaintDevice *nullDevice(); }; QwtNullPaintDevice::PaintEngine::PaintEngine(): QPaintEngine( QPaintEngine::AllFeatures ) { } bool QwtNullPaintDevice::PaintEngine::begin( QPaintDevice * ) { setActive( true ); return true; } bool QwtNullPaintDevice::PaintEngine::end() { setActive( false ); return true; } QPaintEngine::Type QwtNullPaintDevice::PaintEngine::type() const { return QPaintEngine::User; } void QwtNullPaintDevice::PaintEngine::drawRects( const QRect *rects, int rectCount) { QwtNullPaintDevice *device = nullDevice(); if ( device == NULL ) return; if ( device->mode() != QwtNullPaintDevice::NormalMode ) { QPaintEngine::drawRects( rects, rectCount ); return; } device->drawRects( rects, rectCount ); } void QwtNullPaintDevice::PaintEngine::drawRects( const QRectF *rects, int rectCount) { QwtNullPaintDevice *device = nullDevice(); if ( device == NULL ) return; if ( device->mode() != QwtNullPaintDevice::NormalMode ) { QPaintEngine::drawRects( rects, rectCount ); return; } device->drawRects( rects, rectCount ); } void QwtNullPaintDevice::PaintEngine::drawLines( const QLine *lines, int lineCount) { QwtNullPaintDevice *device = nullDevice(); if ( device == NULL ) return; if ( device->mode() != QwtNullPaintDevice::NormalMode ) { QPaintEngine::drawLines( lines, lineCount ); return; } device->drawLines( lines, lineCount ); } void QwtNullPaintDevice::PaintEngine::drawLines( const QLineF *lines, int lineCount) { QwtNullPaintDevice *device = nullDevice(); if ( device == NULL ) return; if ( device->mode() != QwtNullPaintDevice::NormalMode ) { QPaintEngine::drawLines( lines, lineCount ); return; } device->drawLines( lines, lineCount ); } void QwtNullPaintDevice::PaintEngine::drawEllipse( const QRectF &rect) { QwtNullPaintDevice *device = nullDevice(); if ( device == NULL ) return; if ( device->mode() != QwtNullPaintDevice::NormalMode ) { QPaintEngine::drawEllipse( rect ); return; } device->drawEllipse( rect ); } void QwtNullPaintDevice::PaintEngine::drawEllipse( const QRect &rect) { QwtNullPaintDevice *device = nullDevice(); if ( device == NULL ) return; if ( device->mode() != QwtNullPaintDevice::NormalMode ) { QPaintEngine::drawEllipse( rect ); return; } device->drawEllipse( rect ); } void QwtNullPaintDevice::PaintEngine::drawPath( const QPainterPath &path) { QwtNullPaintDevice *device = nullDevice(); if ( device == NULL ) return; device->drawPath( path ); } void QwtNullPaintDevice::PaintEngine::drawPoints( const QPointF *points, int pointCount) { QwtNullPaintDevice *device = nullDevice(); if ( device == NULL ) return; if ( device->mode() != QwtNullPaintDevice::NormalMode ) { QPaintEngine::drawPoints( points, pointCount ); return; } device->drawPoints( points, pointCount ); } void QwtNullPaintDevice::PaintEngine::drawPoints( const QPoint *points, int pointCount) { QwtNullPaintDevice *device = nullDevice(); if ( device == NULL ) return; if ( device->mode() != QwtNullPaintDevice::NormalMode ) { QPaintEngine::drawPoints( points, pointCount ); return; } device->drawPoints( points, pointCount ); } void QwtNullPaintDevice::PaintEngine::drawPolygon( const QPointF *points, int pointCount, PolygonDrawMode mode) { QwtNullPaintDevice *device = nullDevice(); if ( device == NULL ) return; if ( device->mode() == QwtNullPaintDevice::PathMode ) { QPainterPath path; if ( pointCount > 0 ) { path.moveTo( points[0] ); for ( int i = 1; i < pointCount; i++ ) path.lineTo( points[i] ); if ( mode != PolylineMode ) path.closeSubpath(); } device->drawPath( path ); return; } device->drawPolygon( points, pointCount, mode ); } void QwtNullPaintDevice::PaintEngine::drawPolygon( const QPoint *points, int pointCount, PolygonDrawMode mode) { QwtNullPaintDevice *device = nullDevice(); if ( device == NULL ) return; if ( device->mode() == QwtNullPaintDevice::PathMode ) { QPainterPath path; if ( pointCount > 0 ) { path.moveTo( points[0] ); for ( int i = 1; i < pointCount; i++ ) path.lineTo( points[i] ); if ( mode != PolylineMode ) path.closeSubpath(); } device->drawPath( path ); return; } device->drawPolygon( points, pointCount, mode ); } void QwtNullPaintDevice::PaintEngine::drawPixmap( const QRectF &rect, const QPixmap &pm, const QRectF &subRect ) { QwtNullPaintDevice *device = nullDevice(); if ( device == NULL ) return; device->drawPixmap( rect, pm, subRect ); } void QwtNullPaintDevice::PaintEngine::drawTextItem( const QPointF &pos, const QTextItem &textItem) { QwtNullPaintDevice *device = nullDevice(); if ( device == NULL ) return; if ( device->mode() != QwtNullPaintDevice::NormalMode ) { QPaintEngine::drawTextItem( pos, textItem ); return; } device->drawTextItem( pos, textItem ); } void QwtNullPaintDevice::PaintEngine::drawTiledPixmap( const QRectF &rect, const QPixmap &pixmap, const QPointF &subRect) { QwtNullPaintDevice *device = nullDevice(); if ( device == NULL ) return; if ( device->mode() != QwtNullPaintDevice::NormalMode ) { QPaintEngine::drawTiledPixmap( rect, pixmap, subRect ); return; } device->drawTiledPixmap( rect, pixmap, subRect ); } void QwtNullPaintDevice::PaintEngine::drawImage( const QRectF &rect, const QImage &image, const QRectF &subRect, Qt::ImageConversionFlags flags) { QwtNullPaintDevice *device = nullDevice(); if ( device == NULL ) return; device->drawImage( rect, image, subRect, flags ); } void QwtNullPaintDevice::PaintEngine::updateState( const QPaintEngineState &state) { QwtNullPaintDevice *device = nullDevice(); if ( device == NULL ) return; device->updateState( state ); } inline QwtNullPaintDevice *QwtNullPaintDevice::PaintEngine::nullDevice() { if ( !isActive() ) return NULL; return static_cast( paintDevice() ); } //! Constructor QwtNullPaintDevice::QwtNullPaintDevice(): d_engine( NULL ) { d_data = new PrivateData; } //! Destructor QwtNullPaintDevice::~QwtNullPaintDevice() { delete d_engine; delete d_data; } /*! Set the render mode \param mode New mode \sa mode() */ void QwtNullPaintDevice::setMode( Mode mode ) { d_data->mode = mode; } /*! \return Render mode \sa setMode() */ QwtNullPaintDevice::Mode QwtNullPaintDevice::mode() const { return d_data->mode; } //! See QPaintDevice::paintEngine() QPaintEngine *QwtNullPaintDevice::paintEngine() const { if ( d_engine == NULL ) { QwtNullPaintDevice *that = const_cast< QwtNullPaintDevice * >( this ); that->d_engine = new PaintEngine(); } return d_engine; } /*! See QPaintDevice::metric() \param deviceMetric Type of metric \return Metric information for the given paint device metric. \sa sizeMetrics() */ int QwtNullPaintDevice::metric( PaintDeviceMetric deviceMetric ) const { int value; switch ( deviceMetric ) { case PdmWidth: { value = sizeMetrics().width(); break; } case PdmHeight: { value = sizeMetrics().height(); break; } case PdmNumColors: { value = 0xffffffff; break; } case PdmDepth: { value = 32; break; } case PdmPhysicalDpiX: case PdmPhysicalDpiY: case PdmDpiY: case PdmDpiX: { value = 72; break; } case PdmWidthMM: { value = qRound( metric( PdmWidth ) * 25.4 / metric( PdmDpiX ) ); break; } case PdmHeightMM: { value = qRound( metric( PdmHeight ) * 25.4 / metric( PdmDpiY ) ); break; } default: value = 0; } return value; } //! See QPaintEngine::drawRects() void QwtNullPaintDevice::drawRects( const QRect *rects, int rectCount) { Q_UNUSED(rects); Q_UNUSED(rectCount); } //! See QPaintEngine::drawRects() void QwtNullPaintDevice::drawRects( const QRectF *rects, int rectCount) { Q_UNUSED(rects); Q_UNUSED(rectCount); } //! See QPaintEngine::drawLines() void QwtNullPaintDevice::drawLines( const QLine *lines, int lineCount) { Q_UNUSED(lines); Q_UNUSED(lineCount); } //! See QPaintEngine::drawLines() void QwtNullPaintDevice::drawLines( const QLineF *lines, int lineCount) { Q_UNUSED(lines); Q_UNUSED(lineCount); } //! See QPaintEngine::drawEllipse() void QwtNullPaintDevice::drawEllipse( const QRectF &rect ) { Q_UNUSED(rect); } //! See QPaintEngine::drawEllipse() void QwtNullPaintDevice::drawEllipse( const QRect &rect ) { Q_UNUSED(rect); } //! See QPaintEngine::drawPath() void QwtNullPaintDevice::drawPath( const QPainterPath &path ) { Q_UNUSED(path); } //! See QPaintEngine::drawPoints() void QwtNullPaintDevice::drawPoints( const QPointF *points, int pointCount) { Q_UNUSED(points); Q_UNUSED(pointCount); } //! See QPaintEngine::drawPoints() void QwtNullPaintDevice::drawPoints( const QPoint *points, int pointCount) { Q_UNUSED(points); Q_UNUSED(pointCount); } //! See QPaintEngine::drawPolygon() void QwtNullPaintDevice::drawPolygon( const QPointF *points, int pointCount, QPaintEngine::PolygonDrawMode mode) { Q_UNUSED(points); Q_UNUSED(pointCount); Q_UNUSED(mode); } //! See QPaintEngine::drawPolygon() void QwtNullPaintDevice::drawPolygon( const QPoint *points, int pointCount, QPaintEngine::PolygonDrawMode mode) { Q_UNUSED(points); Q_UNUSED(pointCount); Q_UNUSED(mode); } //! See QPaintEngine::drawPixmap() void QwtNullPaintDevice::drawPixmap( const QRectF &rect, const QPixmap &pm, const QRectF &subRect ) { Q_UNUSED(rect); Q_UNUSED(pm); Q_UNUSED(subRect); } //! See QPaintEngine::drawTextItem() void QwtNullPaintDevice::drawTextItem( const QPointF &pos, const QTextItem &textItem) { Q_UNUSED(pos); Q_UNUSED(textItem); } //! See QPaintEngine::drawTiledPixmap() void QwtNullPaintDevice::drawTiledPixmap( const QRectF &rect, const QPixmap &pixmap, const QPointF &subRect) { Q_UNUSED(rect); Q_UNUSED(pixmap); Q_UNUSED(subRect); } //! See QPaintEngine::drawImage() void QwtNullPaintDevice::drawImage( const QRectF &rect, const QImage &image, const QRectF &subRect, Qt::ImageConversionFlags flags) { Q_UNUSED(rect); Q_UNUSED(image); Q_UNUSED(subRect); Q_UNUSED(flags); } //! See QPaintEngine::updateState() void QwtNullPaintDevice::updateState( const QPaintEngineState &state ) { Q_UNUSED(state); } connectome-workbench-1.4.2/src/Qwt/qwt_null_paintdevice.h000066400000000000000000000065431360521144700235760ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_NULL_PAINT_DEVICE_H #define QWT_NULL_PAINT_DEVICE_H 1 #include "qwt_global.h" #include #include /*! \brief A null paint device doing nothing Sometimes important layout/rendering geometries are not available or changeable from the public Qt class interface. ( f.e hidden in the style implementation ). QwtNullPaintDevice can be used to manipulate or filter out this information by analyzing the stream of paint primitives. F.e. QwtNullPaintDevice is used by QwtPlotCanvas to identify styled backgrounds with rounded corners. */ class QWT_EXPORT QwtNullPaintDevice: public QPaintDevice { public: /*! \brief Render mode \sa setMode(), mode() */ enum Mode { /*! All vector graphic primitives are painted by the corresponding draw methods */ NormalMode, /*! Vector graphic primitives ( beside polygons ) are mapped to a QPainterPath and are painted by drawPath. In PathMode mode only a few draw methods are called: - drawPath() - drawPixmap() - drawImage() - drawPolygon() */ PolygonPathMode, /*! Vector graphic primitives are mapped to a QPainterPath and are painted by drawPath. In PathMode mode only a few draw methods are called: - drawPath() - drawPixmap() - drawImage() */ PathMode }; QwtNullPaintDevice(); virtual ~QwtNullPaintDevice(); void setMode( Mode ); Mode mode() const; virtual QPaintEngine *paintEngine() const; virtual int metric( PaintDeviceMetric metric ) const; virtual void drawRects(const QRect *, int ); virtual void drawRects(const QRectF *, int ); virtual void drawLines(const QLine *, int ); virtual void drawLines(const QLineF *, int ); virtual void drawEllipse(const QRectF &); virtual void drawEllipse(const QRect &); virtual void drawPath(const QPainterPath &); virtual void drawPoints(const QPointF *, int ); virtual void drawPoints(const QPoint *, int ); virtual void drawPolygon( const QPointF *, int , QPaintEngine::PolygonDrawMode ); virtual void drawPolygon( const QPoint *, int , QPaintEngine::PolygonDrawMode ); virtual void drawPixmap(const QRectF &, const QPixmap &, const QRectF &); virtual void drawTextItem(const QPointF &, const QTextItem &); virtual void drawTiledPixmap(const QRectF &, const QPixmap &, const QPointF &s); virtual void drawImage(const QRectF &, const QImage &, const QRectF &, Qt::ImageConversionFlags ); virtual void updateState( const QPaintEngineState &state ); protected: //! \return Size needed to implement metric() virtual QSize sizeMetrics() const = 0; private: class PaintEngine; PaintEngine *d_engine; class PrivateData; PrivateData *d_data; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_painter.cpp000066400000000000000000001065031360521144700222430ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_painter.h" #include "qwt_math.h" #include "qwt_clipper.h" #include "qwt_color_map.h" #include "qwt_scale_map.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if QT_VERSION >= 0x050000 #include #endif #if QT_VERSION < 0x050000 #ifdef Q_WS_X11 #include #endif #endif bool QwtPainter::d_polylineSplitting = true; bool QwtPainter::d_roundingAlignment = true; static inline bool qwtIsClippingNeeded( const QPainter *painter, QRectF &clipRect ) { bool doClipping = false; const QPaintEngine *pe = painter->paintEngine(); if ( pe && pe->type() == QPaintEngine::SVG ) { // The SVG paint engine ignores any clipping, if ( painter->hasClipping() ) { doClipping = true; clipRect = painter->clipRegion().boundingRect(); } } return doClipping; } template static inline void qwtDrawPolyline( QPainter *painter, const T *points, int pointCount, bool polylineSplitting ) { bool doSplit = false; if ( polylineSplitting ) { const QPaintEngine *pe = painter->paintEngine(); if ( pe && pe->type() == QPaintEngine::Raster ) { /* The raster paint engine seems to use some algo with O(n*n). ( Qt 4.3 is better than Qt 4.2, but remains unacceptable) To work around this problem, we have to split the polygon into smaller pieces. */ doSplit = true; } } if ( doSplit ) { const int splitSize = 6; for ( int i = 0; i < pointCount; i += splitSize ) { const int n = qMin( splitSize + 1, pointCount - i ); painter->drawPolyline( points + i, n ); } } else { painter->drawPolyline( points, pointCount ); } } static inline QSize qwtScreenResolution() { static QSize screenResolution; if ( !screenResolution.isValid() ) { QDesktopWidget *desktop = QApplication::desktop(); if ( desktop ) { screenResolution.setWidth( desktop->logicalDpiX() ); screenResolution.setHeight( desktop->logicalDpiY() ); } } return screenResolution; } static inline void qwtUnscaleFont( QPainter *painter ) { if ( painter->font().pixelSize() >= 0 ) return; const QSize screenResolution = qwtScreenResolution(); const QPaintDevice *pd = painter->device(); if ( pd->logicalDpiX() != screenResolution.width() || pd->logicalDpiY() != screenResolution.height() ) { QFont pixelFont( painter->font(), QApplication::desktop() ); pixelFont.setPixelSize( QFontInfo( pixelFont ).pixelSize() ); painter->setFont( pixelFont ); } } /*! Check is the application is running with the X11 graphics system that has some special capabilities that can be used for incremental painting to a widget. \return True, when the graphics system is X11 */ bool QwtPainter::isX11GraphicsSystem() { static int onX11 = -1; if ( onX11 < 0 ) { QPixmap pm( 1, 1 ); QPainter painter( &pm ); onX11 = ( painter.paintEngine()->type() == QPaintEngine::X11 ) ? 1 : 0; } return onX11 == 1; } /*! Check if the painter is using a paint engine, that aligns coordinates to integers. Today these are all paint engines beside QPaintEngine::Pdf and QPaintEngine::SVG. If we have an integer based paint engine it is also checked if the painter has a transformation matrix, that rotates or scales. \param painter Painter \return true, when the painter is aligning \sa setRoundingAlignment() */ bool QwtPainter::isAligning( QPainter *painter ) { if ( painter && painter->isActive() ) { switch ( painter->paintEngine()->type() ) { case QPaintEngine::Pdf: case QPaintEngine::SVG: return false; default:; } const QTransform tr = painter->transform(); if ( tr.isRotating() || tr.isScaling() ) { // we might have to check translations too return false; } } return true; } /*! Enable whether coordinates should be rounded, before they are painted to a paint engine that floors to integer values. For other paint engines this ( PDF, SVG ), this flag has no effect. QwtPainter stores this flag only, the rounding itself is done in the painting code ( f.e the plot items ). The default setting is true. \sa roundingAlignment(), isAligning() */ void QwtPainter::setRoundingAlignment( bool enable ) { d_roundingAlignment = enable; } /*! \brief En/Disable line splitting for the raster paint engine In some Qt versions the raster paint engine paints polylines of many points much faster when they are split in smaller chunks: f.e all supported Qt versions >= Qt 5.0 when drawing an antialiased polyline with a pen width >=2. The default setting is true. \sa polylineSplitting() */ void QwtPainter::setPolylineSplitting( bool enable ) { d_polylineSplitting = enable; } //! Wrapper for QPainter::drawPath() void QwtPainter::drawPath( QPainter *painter, const QPainterPath &path ) { painter->drawPath( path ); } //! Wrapper for QPainter::drawRect() void QwtPainter::drawRect( QPainter *painter, double x, double y, double w, double h ) { drawRect( painter, QRectF( x, y, w, h ) ); } //! Wrapper for QPainter::drawRect() void QwtPainter::drawRect( QPainter *painter, const QRectF &rect ) { const QRectF r = rect; QRectF clipRect; const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect ); if ( deviceClipping ) { if ( !clipRect.intersects( r ) ) return; if ( !clipRect.contains( r ) ) { fillRect( painter, r & clipRect, painter->brush() ); painter->save(); painter->setBrush( Qt::NoBrush ); drawPolyline( painter, QPolygonF( r ) ); painter->restore(); return; } } painter->drawRect( r ); } //! Wrapper for QPainter::fillRect() void QwtPainter::fillRect( QPainter *painter, const QRectF &rect, const QBrush &brush ) { if ( !rect.isValid() ) return; QRectF clipRect; const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect ); /* Performance of Qt4 is horrible for a non trivial brush. Without clipping expect minutes or hours for repainting large rectangles (might result from zooming) */ if ( deviceClipping ) clipRect &= painter->window(); else clipRect = painter->window(); if ( painter->hasClipping() ) clipRect &= painter->clipRegion().boundingRect(); QRectF r = rect; if ( deviceClipping ) r = r.intersected( clipRect ); if ( r.isValid() ) painter->fillRect( r, brush ); } //! Wrapper for QPainter::drawPie() void QwtPainter::drawPie( QPainter *painter, const QRectF &rect, int a, int alen ) { QRectF clipRect; const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect ); if ( deviceClipping && !clipRect.contains( rect ) ) return; painter->drawPie( rect, a, alen ); } //! Wrapper for QPainter::drawEllipse() void QwtPainter::drawEllipse( QPainter *painter, const QRectF &rect ) { QRectF clipRect; const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect ); if ( deviceClipping && !clipRect.contains( rect ) ) return; painter->drawEllipse( rect ); } //! Wrapper for QPainter::drawText() void QwtPainter::drawText( QPainter *painter, double x, double y, const QString &text ) { drawText( painter, QPointF( x, y ), text ); } //! Wrapper for QPainter::drawText() void QwtPainter::drawText( QPainter *painter, const QPointF &pos, const QString &text ) { QRectF clipRect; const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect ); if ( deviceClipping && !clipRect.contains( pos ) ) return; painter->save(); qwtUnscaleFont( painter ); painter->drawText( pos, text ); painter->restore(); } //! Wrapper for QPainter::drawText() void QwtPainter::drawText( QPainter *painter, double x, double y, double w, double h, int flags, const QString &text ) { drawText( painter, QRectF( x, y, w, h ), flags, text ); } //! Wrapper for QPainter::drawText() void QwtPainter::drawText( QPainter *painter, const QRectF &rect, int flags, const QString &text ) { painter->save(); qwtUnscaleFont( painter ); painter->drawText( rect, flags, text ); painter->restore(); } #ifndef QT_NO_RICHTEXT /*! Draw a text document into a rectangle \param painter Painter \param rect Traget rectangle \param flags Alignments/Text flags, see QPainter::drawText() \param text Text document */ void QwtPainter::drawSimpleRichText( QPainter *painter, const QRectF &rect, int flags, const QTextDocument &text ) { QTextDocument *txt = text.clone(); painter->save(); QRectF unscaledRect = rect; if ( painter->font().pixelSize() < 0 ) { const QSize res = qwtScreenResolution(); const QPaintDevice *pd = painter->device(); if ( pd->logicalDpiX() != res.width() || pd->logicalDpiY() != res.height() ) { QTransform transform; transform.scale( res.width() / double( pd->logicalDpiX() ), res.height() / double( pd->logicalDpiY() )); painter->setWorldTransform( transform, true ); unscaledRect = transform.inverted().mapRect(rect); } } txt->setDefaultFont( painter->font() ); txt->setPageSize( QSizeF( unscaledRect.width(), QWIDGETSIZE_MAX ) ); QAbstractTextDocumentLayout* layout = txt->documentLayout(); const double height = layout->documentSize().height(); double y = unscaledRect.y(); if ( flags & Qt::AlignBottom ) y += ( unscaledRect.height() - height ); else if ( flags & Qt::AlignVCenter ) y += ( unscaledRect.height() - height ) / 2; QAbstractTextDocumentLayout::PaintContext context; context.palette.setColor( QPalette::Text, painter->pen().color() ); painter->translate( unscaledRect.x(), y ); layout->draw( painter, context ); painter->restore(); delete txt; } #endif // !QT_NO_RICHTEXT //! Wrapper for QPainter::drawLine() void QwtPainter::drawLine( QPainter *painter, const QPointF &p1, const QPointF &p2 ) { QRectF clipRect; const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect ); if ( deviceClipping && !( clipRect.contains( p1 ) && clipRect.contains( p2 ) ) ) { QPolygonF polygon; polygon += p1; polygon += p2; drawPolyline( painter, polygon ); return; } painter->drawLine( p1, p2 ); } //! Wrapper for QPainter::drawPolygon() void QwtPainter::drawPolygon( QPainter *painter, const QPolygonF &polygon ) { QRectF clipRect; const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect ); QPolygonF cpa = polygon; if ( deviceClipping ) cpa = QwtClipper::clipPolygonF( clipRect, polygon ); painter->drawPolygon( cpa ); } //! Wrapper for QPainter::drawPolyline() void QwtPainter::drawPolyline( QPainter *painter, const QPolygonF &polygon ) { QRectF clipRect; const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect ); QPolygonF cpa = polygon; if ( deviceClipping ) cpa = QwtClipper::clipPolygonF( clipRect, cpa ); qwtDrawPolyline( painter, cpa.constData(), cpa.size(), d_polylineSplitting ); } //! Wrapper for QPainter::drawPolyline() void QwtPainter::drawPolyline( QPainter *painter, const QPointF *points, int pointCount ) { QRectF clipRect; const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect ); if ( deviceClipping ) { QPolygonF polygon( pointCount ); ::memcpy( polygon.data(), points, pointCount * sizeof( QPointF ) ); polygon = QwtClipper::clipPolygonF( clipRect, polygon ); qwtDrawPolyline( painter, polygon.constData(), polygon.size(), d_polylineSplitting ); } else { qwtDrawPolyline( painter, points, pointCount, d_polylineSplitting ); } } //! Wrapper for QPainter::drawPolygon() void QwtPainter::drawPolygon( QPainter *painter, const QPolygon &polygon ) { QRectF clipRect; const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect ); QPolygon cpa = polygon; if ( deviceClipping ) cpa = QwtClipper::clipPolygon( clipRect, polygon ); painter->drawPolygon( cpa ); } //! Wrapper for QPainter::drawPolyline() void QwtPainter::drawPolyline( QPainter *painter, const QPolygon &polygon ) { QRectF clipRect; const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect ); QPolygon cpa = polygon; if ( deviceClipping ) cpa = QwtClipper::clipPolygon( clipRect, cpa ); qwtDrawPolyline( painter, cpa.constData(), cpa.size(), d_polylineSplitting ); } //! Wrapper for QPainter::drawPolyline() void QwtPainter::drawPolyline( QPainter *painter, const QPoint *points, int pointCount ) { QRectF clipRect; const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect ); if ( deviceClipping ) { QPolygon polygon( pointCount ); ::memcpy( polygon.data(), points, pointCount * sizeof( QPoint ) ); polygon = QwtClipper::clipPolygon( clipRect, polygon ); qwtDrawPolyline( painter, polygon.constData(), polygon.size(), d_polylineSplitting ); } else qwtDrawPolyline( painter, points, pointCount, d_polylineSplitting ); } //! Wrapper for QPainter::drawPoint() void QwtPainter::drawPoint( QPainter *painter, const QPointF &pos ) { QRectF clipRect; const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect ); if ( deviceClipping && !clipRect.contains( pos ) ) return; painter->drawPoint( pos ); } //! Wrapper for QPainter::drawPoint() void QwtPainter::drawPoint( QPainter *painter, const QPoint &pos ) { QRectF clipRect; const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect ); if ( deviceClipping ) { const int minX = qCeil( clipRect.left() ); const int maxX = qFloor( clipRect.right() ); const int minY = qCeil( clipRect.top() ); const int maxY = qFloor( clipRect.bottom() ); if ( pos.x() < minX || pos.x() > maxX || pos.y() < minY || pos.y() > maxY ) { return; } } painter->drawPoint( pos ); } //! Wrapper for QPainter::drawPoints() void QwtPainter::drawPoints( QPainter *painter, const QPoint *points, int pointCount ) { QRectF clipRect; const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect ); if ( deviceClipping ) { const int minX = qCeil( clipRect.left() ); const int maxX = qFloor( clipRect.right() ); const int minY = qCeil( clipRect.top() ); const int maxY = qFloor( clipRect.bottom() ); const QRect r( minX, minY, maxX - minX, maxY - minY ); QPolygon clippedPolygon( pointCount ); QPoint *clippedData = clippedPolygon.data(); int numClippedPoints = 0; for ( int i = 0; i < pointCount; i++ ) { if ( r.contains( points[i] ) ) clippedData[ numClippedPoints++ ] = points[i]; } painter->drawPoints( clippedData, numClippedPoints ); } else { painter->drawPoints( points, pointCount ); } } //! Wrapper for QPainter::drawPoints() void QwtPainter::drawPoints( QPainter *painter, const QPointF *points, int pointCount ) { QRectF clipRect; const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect ); if ( deviceClipping ) { QPolygonF clippedPolygon( pointCount ); QPointF *clippedData = clippedPolygon.data(); int numClippedPoints = 0; for ( int i = 0; i < pointCount; i++ ) { if ( clipRect.contains( points[i] ) ) clippedData[ numClippedPoints++ ] = points[i]; } painter->drawPoints( clippedData, numClippedPoints ); } else { painter->drawPoints( points, pointCount ); } } //! Wrapper for QPainter::drawImage() void QwtPainter::drawImage( QPainter *painter, const QRectF &rect, const QImage &image ) { const QRect alignedRect = rect.toAlignedRect(); if ( alignedRect != rect ) { const QRectF clipRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 ); painter->save(); painter->setClipRect( clipRect, Qt::IntersectClip ); painter->drawImage( alignedRect, image ); painter->restore(); } else { painter->drawImage( alignedRect, image ); } } //! Wrapper for QPainter::drawPixmap() void QwtPainter::drawPixmap( QPainter *painter, const QRectF &rect, const QPixmap &pixmap ) { const QRect alignedRect = rect.toAlignedRect(); if ( alignedRect != rect ) { const QRectF clipRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 ); painter->save(); painter->setClipRect( clipRect, Qt::IntersectClip ); painter->drawPixmap( alignedRect, pixmap ); painter->restore(); } else { painter->drawPixmap( alignedRect, pixmap ); } } //! Draw a focus rectangle on a widget using its style. void QwtPainter::drawFocusRect( QPainter *painter, const QWidget *widget ) { drawFocusRect( painter, widget, widget->rect() ); } //! Draw a focus rectangle on a widget using its style. void QwtPainter::drawFocusRect( QPainter *painter, const QWidget *widget, const QRect &rect ) { QStyleOptionFocusRect opt; opt.init( widget ); opt.rect = rect; opt.state |= QStyle::State_HasFocus; widget->style()->drawPrimitive( QStyle::PE_FrameFocusRect, &opt, painter, widget ); } /*! Draw a round frame \param painter Painter \param rect Frame rectangle \param palette QPalette::WindowText is used for plain borders QPalette::Dark and QPalette::Light for raised or sunken borders \param lineWidth Line width \param frameStyle bitwise OR´ed value of QFrame::Shape and QFrame::Shadow */ void QwtPainter::drawRoundFrame( QPainter *painter, const QRectF &rect, const QPalette &palette, int lineWidth, int frameStyle ) { enum Style { Plain, Sunken, Raised }; Style style = Plain; if ( (frameStyle & QFrame::Sunken) == QFrame::Sunken ) style = Sunken; else if ( (frameStyle & QFrame::Raised) == QFrame::Raised ) style = Raised; const double lw2 = 0.5 * lineWidth; QRectF r = rect.adjusted( lw2, lw2, -lw2, -lw2 ); QBrush brush; if ( style != Plain ) { QColor c1 = palette.color( QPalette::Light ); QColor c2 = palette.color( QPalette::Dark ); if ( style == Sunken ) qSwap( c1, c2 ); QLinearGradient gradient( r.topLeft(), r.bottomRight() ); gradient.setColorAt( 0.0, c1 ); #if 0 gradient.setColorAt( 0.3, c1 ); gradient.setColorAt( 0.7, c2 ); #endif gradient.setColorAt( 1.0, c2 ); brush = QBrush( gradient ); } else // Plain { brush = palette.brush( QPalette::WindowText ); } painter->save(); painter->setPen( QPen( brush, lineWidth ) ); painter->setBrush( Qt::NoBrush ); painter->drawEllipse( r ); painter->restore(); } /*! Draw a rectangular frame \param painter Painter \param rect Frame rectangle \param palette Palette \param foregroundRole Foreground role used for QFrame::Plain \param frameWidth Frame width \param midLineWidth Used for QFrame::Box \param frameStyle bitwise OR´ed value of QFrame::Shape and QFrame::Shadow */ void QwtPainter::drawFrame( QPainter *painter, const QRectF &rect, const QPalette &palette, QPalette::ColorRole foregroundRole, int frameWidth, int midLineWidth, int frameStyle ) { if ( frameWidth <= 0 || rect.isEmpty() ) return; const int shadow = frameStyle & QFrame::Shadow_Mask; painter->save(); if ( shadow == QFrame::Plain ) { const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 ); const QRectF innerRect = outerRect.adjusted( frameWidth, frameWidth, -frameWidth, -frameWidth ); QPainterPath path; path.addRect( outerRect ); path.addRect( innerRect ); painter->setPen( Qt::NoPen ); painter->setBrush( palette.color( foregroundRole ) ); painter->drawPath( path ); } else { const int shape = frameStyle & QFrame::Shape_Mask; if ( shape == QFrame::Box ) { const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 ); const QRectF midRect1 = outerRect.adjusted( frameWidth, frameWidth, -frameWidth, -frameWidth ); const QRectF midRect2 = midRect1.adjusted( midLineWidth, midLineWidth, -midLineWidth, -midLineWidth ); const QRectF innerRect = midRect2.adjusted( frameWidth, frameWidth, -frameWidth, -frameWidth ); QPainterPath path1; path1.moveTo( outerRect.bottomLeft() ); path1.lineTo( outerRect.topLeft() ); path1.lineTo( outerRect.topRight() ); path1.lineTo( midRect1.topRight() ); path1.lineTo( midRect1.topLeft() ); path1.lineTo( midRect1.bottomLeft() ); QPainterPath path2; path2.moveTo( outerRect.bottomLeft() ); path2.lineTo( outerRect.bottomRight() ); path2.lineTo( outerRect.topRight() ); path2.lineTo( midRect1.topRight() ); path2.lineTo( midRect1.bottomRight() ); path2.lineTo( midRect1.bottomLeft() ); QPainterPath path3; path3.moveTo( midRect2.bottomLeft() ); path3.lineTo( midRect2.topLeft() ); path3.lineTo( midRect2.topRight() ); path3.lineTo( innerRect.topRight() ); path3.lineTo( innerRect.topLeft() ); path3.lineTo( innerRect.bottomLeft() ); QPainterPath path4; path4.moveTo( midRect2.bottomLeft() ); path4.lineTo( midRect2.bottomRight() ); path4.lineTo( midRect2.topRight() ); path4.lineTo( innerRect.topRight() ); path4.lineTo( innerRect.bottomRight() ); path4.lineTo( innerRect.bottomLeft() ); QPainterPath path5; path5.addRect( midRect1 ); path5.addRect( midRect2 ); painter->setPen( Qt::NoPen ); QBrush brush1 = palette.dark().color(); QBrush brush2 = palette.light().color(); if ( shadow == QFrame::Raised ) qSwap( brush1, brush2 ); painter->setBrush( brush1 ); painter->drawPath( path1 ); painter->drawPath( path4 ); painter->setBrush( brush2 ); painter->drawPath( path2 ); painter->drawPath( path3 ); painter->setBrush( palette.mid() ); painter->drawPath( path5 ); } #if 0 // qDrawWinPanel doesn't result in something nice // on a scalable document like PDF. Better draw a // Panel. else if ( shape == QFrame::WinPanel ) { painter->setRenderHint( QPainter::NonCosmeticDefaultPen, true ); qDrawWinPanel ( painter, rect.toRect(), palette, frameStyle & QFrame::Sunken ); } else if ( shape == QFrame::StyledPanel ) { } #endif else { const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 ); const QRectF innerRect = outerRect.adjusted( frameWidth - 1.0, frameWidth - 1.0, -( frameWidth - 1.0 ), -( frameWidth - 1.0 ) ); QPainterPath path1; path1.moveTo( outerRect.bottomLeft() ); path1.lineTo( outerRect.topLeft() ); path1.lineTo( outerRect.topRight() ); path1.lineTo( innerRect.topRight() ); path1.lineTo( innerRect.topLeft() ); path1.lineTo( innerRect.bottomLeft() ); QPainterPath path2; path2.moveTo( outerRect.bottomLeft() ); path2.lineTo( outerRect.bottomRight() ); path2.lineTo( outerRect.topRight() ); path2.lineTo( innerRect.topRight() ); path2.lineTo( innerRect.bottomRight() ); path2.lineTo( innerRect.bottomLeft() ); painter->setPen( Qt::NoPen ); QBrush brush1 = palette.dark().color(); QBrush brush2 = palette.light().color(); if ( shadow == QFrame::Raised ) qSwap( brush1, brush2 ); painter->setBrush( brush1 ); painter->drawPath( path1 ); painter->setBrush( brush2 ); painter->drawPath( path2 ); } } painter->restore(); } /*! Draw a rectangular frame with rounded borders \param painter Painter \param rect Frame rectangle \param xRadius x-radius of the ellipses defining the corners \param yRadius y-radius of the ellipses defining the corners \param palette QPalette::WindowText is used for plain borders QPalette::Dark and QPalette::Light for raised or sunken borders \param lineWidth Line width \param frameStyle bitwise OR´ed value of QFrame::Shape and QFrame::Shadow */ void QwtPainter::drawRoundedFrame( QPainter *painter, const QRectF &rect, double xRadius, double yRadius, const QPalette &palette, int lineWidth, int frameStyle ) { painter->save(); painter->setRenderHint( QPainter::Antialiasing, true ); painter->setBrush( Qt::NoBrush ); double lw2 = lineWidth * 0.5; QRectF r = rect.adjusted( lw2, lw2, -lw2, -lw2 ); QPainterPath path; path.addRoundedRect( r, xRadius, yRadius ); enum Style { Plain, Sunken, Raised }; Style style = Plain; if ( (frameStyle & QFrame::Sunken) == QFrame::Sunken ) style = Sunken; else if ( (frameStyle & QFrame::Raised) == QFrame::Raised ) style = Raised; if ( style != Plain && path.elementCount() == 17 ) { // move + 4 * ( cubicTo + lineTo ) QPainterPath pathList[8]; for ( int i = 0; i < 4; i++ ) { const int j = i * 4 + 1; pathList[ 2 * i ].moveTo( path.elementAt(j - 1).x, path.elementAt( j - 1 ).y ); pathList[ 2 * i ].cubicTo( path.elementAt(j + 0).x, path.elementAt(j + 0).y, path.elementAt(j + 1).x, path.elementAt(j + 1).y, path.elementAt(j + 2).x, path.elementAt(j + 2).y ); pathList[ 2 * i + 1 ].moveTo( path.elementAt(j + 2).x, path.elementAt(j + 2).y ); pathList[ 2 * i + 1 ].lineTo( path.elementAt(j + 3).x, path.elementAt(j + 3).y ); } QColor c1( palette.color( QPalette::Dark ) ); QColor c2( palette.color( QPalette::Light ) ); if ( style == Raised ) qSwap( c1, c2 ); for ( int i = 0; i < 4; i++ ) { QRectF r = pathList[2 * i].controlPointRect(); QPen arcPen; arcPen.setCapStyle( Qt::FlatCap ); arcPen.setWidth( lineWidth ); QPen linePen; linePen.setCapStyle( Qt::FlatCap ); linePen.setWidth( lineWidth ); switch( i ) { case 0: { arcPen.setColor( c1 ); linePen.setColor( c1 ); break; } case 1: { QLinearGradient gradient; gradient.setStart( r.topLeft() ); gradient.setFinalStop( r.bottomRight() ); gradient.setColorAt( 0.0, c1 ); gradient.setColorAt( 1.0, c2 ); arcPen.setBrush( gradient ); linePen.setColor( c2 ); break; } case 2: { arcPen.setColor( c2 ); linePen.setColor( c2 ); break; } case 3: { QLinearGradient gradient; gradient.setStart( r.bottomRight() ); gradient.setFinalStop( r.topLeft() ); gradient.setColorAt( 0.0, c2 ); gradient.setColorAt( 1.0, c1 ); arcPen.setBrush( gradient ); linePen.setColor( c1 ); break; } } painter->setPen( arcPen ); painter->drawPath( pathList[ 2 * i] ); painter->setPen( linePen ); painter->drawPath( pathList[ 2 * i + 1] ); } } else { QPen pen( palette.color( QPalette::WindowText ), lineWidth ); painter->setPen( pen ); painter->drawPath( path ); } painter->restore(); } /*! Draw a color bar into a rectangle \param painter Painter \param colorMap Color map \param interval Value range \param scaleMap Scale map \param orientation Orientation \param rect Traget rectangle */ void QwtPainter::drawColorBar( QPainter *painter, const QwtColorMap &colorMap, const QwtInterval &interval, const QwtScaleMap &scaleMap, Qt::Orientation orientation, const QRectF &rect ) { QVector colorTable; if ( colorMap.format() == QwtColorMap::Indexed ) colorTable = colorMap.colorTable( interval ); QColor c; const QRect devRect = rect.toAlignedRect(); /* We paint to a pixmap first to have something scalable for printing ( f.e. in a Pdf document ) */ QPixmap pixmap( devRect.size() ); pixmap.fill( Qt::transparent ); QPainter pmPainter( &pixmap ); pmPainter.translate( -devRect.x(), -devRect.y() ); if ( orientation == Qt::Horizontal ) { QwtScaleMap sMap = scaleMap; sMap.setPaintInterval( rect.left(), rect.right() ); for ( int x = devRect.left(); x <= devRect.right(); x++ ) { const double value = sMap.invTransform( x ); if ( colorMap.format() == QwtColorMap::RGB ) c.setRgba( colorMap.rgb( interval, value ) ); else c = colorTable[colorMap.colorIndex( interval, value )]; pmPainter.setPen( c ); pmPainter.drawLine( x, devRect.top(), x, devRect.bottom() ); } } else // Vertical { QwtScaleMap sMap = scaleMap; sMap.setPaintInterval( rect.bottom(), rect.top() ); for ( int y = devRect.top(); y <= devRect.bottom(); y++ ) { const double value = sMap.invTransform( y ); if ( colorMap.format() == QwtColorMap::RGB ) c.setRgba( colorMap.rgb( interval, value ) ); else c = colorTable[colorMap.colorIndex( interval, value )]; pmPainter.setPen( c ); pmPainter.drawLine( devRect.left(), y, devRect.right(), y ); } } pmPainter.end(); drawPixmap( painter, rect, pixmap ); } static inline void qwtFillRect( const QWidget *widget, QPainter *painter, const QRect &rect, const QBrush &brush) { if ( brush.style() == Qt::TexturePattern ) { painter->save(); painter->setClipRect( rect ); painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft()); painter->restore(); } else if ( brush.gradient() ) { painter->save(); painter->setClipRect( rect ); painter->fillRect(0, 0, widget->width(), widget->height(), brush); painter->restore(); } else { painter->fillRect(rect, brush); } } /*! Fill a pixmap with the content of a widget In Qt >= 5.0 QPixmap::fill() is a nop, in Qt 4.x it is buggy for backgrounds with gradients. Thus fillPixmap() offers an alternative implementation. \param widget Widget \param pixmap Pixmap to be filled \param offset Offset \sa QPixmap::fill() */ void QwtPainter::fillPixmap( const QWidget *widget, QPixmap &pixmap, const QPoint &offset ) { const QRect rect( offset, pixmap.size() ); QPainter painter( &pixmap ); painter.translate( -offset ); const QBrush autoFillBrush = widget->palette().brush( widget->backgroundRole() ); if ( !( widget->autoFillBackground() && autoFillBrush.isOpaque() ) ) { const QBrush bg = widget->palette().brush( QPalette::Window ); qwtFillRect( widget, &painter, rect, bg); } if ( widget->autoFillBackground() ) qwtFillRect( widget, &painter, rect, autoFillBrush); if ( widget->testAttribute(Qt::WA_StyledBackground) ) { painter.setClipRegion( rect ); QStyleOption opt; opt.initFrom( widget ); widget->style()->drawPrimitive( QStyle::PE_Widget, &opt, &painter, widget ); } } /*! Fill rect with the background of a widget \param painter Painter \param rect Rectangle to be filled \param widget Widget \sa QStyle::PE_Widget, QWidget::backgroundRole() */ void QwtPainter::drawBackgound( QPainter *painter, const QRectF &rect, const QWidget *widget ) { if ( widget->testAttribute( Qt::WA_StyledBackground ) ) { QStyleOption opt; opt.initFrom( widget ); opt.rect = rect.toAlignedRect(); widget->style()->drawPrimitive( QStyle::PE_Widget, &opt, painter, widget); } else { const QBrush brush = widget->palette().brush( widget->backgroundRole() ); painter->fillRect( rect, brush ); } } /*! \return A pixmap that can be used as backing store \param widget Widget, for which the backinstore is intended \param size Size of the pixmap */ QPixmap QwtPainter::backingStore( QWidget *widget, const QSize &size ) { QPixmap pm; #define QWT_HIGH_DPI 1 #if QT_VERSION >= 0x050000 && QWT_HIGH_DPI qreal pixelRatio = 1.0; if ( widget && widget->windowHandle() ) { pixelRatio = widget->windowHandle()->devicePixelRatio(); } else { if ( qApp ) pixelRatio = qApp->devicePixelRatio(); } pm = QPixmap( size * pixelRatio ); pm.setDevicePixelRatio( pixelRatio ); #else Q_UNUSED( widget ) pm = QPixmap( size ); #endif #if QT_VERSION < 0x050000 #ifdef Q_WS_X11 if ( widget && isX11GraphicsSystem() ) { if ( pm.x11Info().screen() != widget->x11Info().screen() ) pm.x11SetScreen( widget->x11Info().screen() ); } #endif #endif return pm; } connectome-workbench-1.4.2/src/Qwt/qwt_painter.h000066400000000000000000000137641360521144700217160ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PAINTER_H #define QWT_PAINTER_H #include "qwt_global.h" #include #include #include #include #include class QPainter; class QBrush; class QColor; class QWidget; class QPolygonF; class QRectF; class QImage; class QPixmap; class QwtScaleMap; class QwtColorMap; class QwtInterval; class QTextDocument; class QPainterPath; /*! \brief A collection of QPainter workarounds */ class QWT_EXPORT QwtPainter { public: static void setPolylineSplitting( bool ); static bool polylineSplitting(); static void setRoundingAlignment( bool ); static bool roundingAlignment(); static bool roundingAlignment(QPainter *); static void drawText( QPainter *, double x, double y, const QString & ); static void drawText( QPainter *, const QPointF &, const QString & ); static void drawText( QPainter *, double x, double y, double w, double h, int flags, const QString & ); static void drawText( QPainter *, const QRectF &, int flags, const QString & ); #ifndef QT_NO_RICHTEXT static void drawSimpleRichText( QPainter *, const QRectF &, int flags, const QTextDocument & ); #endif static void drawRect( QPainter *, double x, double y, double w, double h ); static void drawRect( QPainter *, const QRectF &rect ); static void fillRect( QPainter *, const QRectF &, const QBrush & ); static void drawEllipse( QPainter *, const QRectF & ); static void drawPie( QPainter *, const QRectF & r, int a, int alen ); static void drawLine( QPainter *, double x1, double y1, double x2, double y2 ); static void drawLine( QPainter *, const QPointF &p1, const QPointF &p2 ); static void drawLine( QPainter *, const QLineF & ); static void drawPolygon( QPainter *, const QPolygonF & ); static void drawPolyline( QPainter *, const QPolygonF & ); static void drawPolyline( QPainter *, const QPointF *, int pointCount ); static void drawPolygon( QPainter *, const QPolygon & ); static void drawPolyline( QPainter *, const QPolygon & ); static void drawPolyline( QPainter *, const QPoint *, int pointCount ); static void drawPoint( QPainter *, const QPoint & ); static void drawPoints( QPainter *, const QPolygon & ); static void drawPoints( QPainter *, const QPoint *, int pointCount ); static void drawPoint( QPainter *, double x, double y ); static void drawPoint( QPainter *, const QPointF & ); static void drawPoints( QPainter *, const QPolygonF & ); static void drawPoints( QPainter *, const QPointF *, int pointCount ); static void drawPath( QPainter *, const QPainterPath & ); static void drawImage( QPainter *, const QRectF &, const QImage & ); static void drawPixmap( QPainter *, const QRectF &, const QPixmap & ); static void drawRoundFrame( QPainter *, const QRectF &, const QPalette &, int lineWidth, int frameStyle ); static void drawRoundedFrame( QPainter *, const QRectF &, double xRadius, double yRadius, const QPalette &, int lineWidth, int frameStyle ); static void drawFrame( QPainter *, const QRectF &rect, const QPalette &palette, QPalette::ColorRole foregroundRole, int lineWidth, int midLineWidth, int frameStyle ); static void drawFocusRect( QPainter *, const QWidget * ); static void drawFocusRect( QPainter *, const QWidget *, const QRect & ); static void drawColorBar( QPainter *painter, const QwtColorMap &, const QwtInterval &, const QwtScaleMap &, Qt::Orientation, const QRectF & ); static bool isAligning( QPainter *painter ); static bool isX11GraphicsSystem(); static void fillPixmap( const QWidget *, QPixmap &, const QPoint &offset = QPoint() ); static void drawBackgound( QPainter *painter, const QRectF &rect, const QWidget *widget ); static QPixmap backingStore( QWidget *, const QSize & ); private: static bool d_polylineSplitting; static bool d_roundingAlignment; }; //! Wrapper for QPainter::drawPoint() inline void QwtPainter::drawPoint( QPainter *painter, double x, double y ) { QwtPainter::drawPoint( painter, QPointF( x, y ) ); } //! Wrapper for QPainter::drawPoints() inline void QwtPainter::drawPoints( QPainter *painter, const QPolygon &polygon ) { drawPoints( painter, polygon.data(), polygon.size() ); } //! Wrapper for QPainter::drawPoints() inline void QwtPainter::drawPoints( QPainter *painter, const QPolygonF &polygon ) { drawPoints( painter, polygon.data(), polygon.size() ); } //! Wrapper for QPainter::drawLine() inline void QwtPainter::drawLine( QPainter *painter, double x1, double y1, double x2, double y2 ) { QwtPainter::drawLine( painter, QPointF( x1, y1 ), QPointF( x2, y2 ) ); } //! Wrapper for QPainter::drawLine() inline void QwtPainter::drawLine( QPainter *painter, const QLineF &line ) { QwtPainter::drawLine( painter, line.p1(), line.p2() ); } /*! \return True, when line splitting for the raster paint engine is enabled. \sa setPolylineSplitting() */ inline bool QwtPainter::polylineSplitting() { return d_polylineSplitting; } /*! Check whether coordinates should be rounded, before they are painted to a paint engine that rounds to integer values. For other paint engines ( PDF, SVG ), this flag has no effect. \return True, when rounding is enabled \sa setRoundingAlignment(), isAligning() */ inline bool QwtPainter::roundingAlignment() { return d_roundingAlignment; } /*! \return roundingAlignment() && isAligning(painter); \param painter Painter */ inline bool QwtPainter::roundingAlignment(QPainter *painter) { return d_roundingAlignment && isAligning(painter); } #endif connectome-workbench-1.4.2/src/Qwt/qwt_painter_command.cpp000066400000000000000000000130161360521144700237350ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_painter_command.h" //! Construct an invalid command QwtPainterCommand::QwtPainterCommand(): d_type( Invalid ) { } //! Copy constructor QwtPainterCommand::QwtPainterCommand( const QPainterPath &path ): d_type( Path ) { d_path = new QPainterPath( path ); } /*! Constructor for Pixmap paint operation \param rect Target rectangle \param pixmap Pixmap \param subRect Rectangle inside the pixmap \sa QPainter::drawPixmap() */ QwtPainterCommand::QwtPainterCommand( const QRectF &rect, const QPixmap &pixmap, const QRectF& subRect ): d_type( Pixmap ) { d_pixmapData = new PixmapData(); d_pixmapData->rect = rect; d_pixmapData->pixmap = pixmap; d_pixmapData->subRect = subRect; } /*! Constructor for Image paint operation \param rect Target rectangle \param image Image \param subRect Rectangle inside the image \param flags Conversion flags \sa QPainter::drawImage() */ QwtPainterCommand::QwtPainterCommand( const QRectF &rect, const QImage &image, const QRectF& subRect, Qt::ImageConversionFlags flags ): d_type( Image ) { d_imageData = new ImageData(); d_imageData->rect = rect; d_imageData->image = image; d_imageData->subRect = subRect; d_imageData->flags = flags; } /*! Constructor for State paint operation \param state Paint engine state */ QwtPainterCommand::QwtPainterCommand( const QPaintEngineState &state ): d_type( State ) { d_stateData = new StateData(); d_stateData->flags = state.state(); if ( d_stateData->flags & QPaintEngine::DirtyPen ) d_stateData->pen = state.pen(); if ( d_stateData->flags & QPaintEngine::DirtyBrush ) d_stateData->brush = state.brush(); if ( d_stateData->flags & QPaintEngine::DirtyBrushOrigin ) d_stateData->brushOrigin = state.brushOrigin(); if ( d_stateData->flags & QPaintEngine::DirtyFont ) d_stateData->font = state.font(); if ( d_stateData->flags & QPaintEngine::DirtyBackground ) { d_stateData->backgroundMode = state.backgroundMode(); d_stateData->backgroundBrush = state.backgroundBrush(); } if ( d_stateData->flags & QPaintEngine::DirtyTransform ) d_stateData->transform = state.transform(); if ( d_stateData->flags & QPaintEngine::DirtyClipEnabled ) d_stateData->isClipEnabled = state.isClipEnabled(); if ( d_stateData->flags & QPaintEngine::DirtyClipRegion ) { d_stateData->clipRegion = state.clipRegion(); d_stateData->clipOperation = state.clipOperation(); } if ( d_stateData->flags & QPaintEngine::DirtyClipPath ) { d_stateData->clipPath = state.clipPath(); d_stateData->clipOperation = state.clipOperation(); } if ( d_stateData->flags & QPaintEngine::DirtyHints ) d_stateData->renderHints = state.renderHints(); if ( d_stateData->flags & QPaintEngine::DirtyCompositionMode ) d_stateData->compositionMode = state.compositionMode(); if ( d_stateData->flags & QPaintEngine::DirtyOpacity ) d_stateData->opacity = state.opacity(); } /*! Copy constructor \param other Command to be copied */ QwtPainterCommand::QwtPainterCommand(const QwtPainterCommand &other) { copy( other ); } //! Destructor QwtPainterCommand::~QwtPainterCommand() { reset(); } /*! Assignment operator \param other Command to be copied \return Modified command */ QwtPainterCommand &QwtPainterCommand::operator=(const QwtPainterCommand &other) { reset(); copy( other ); return *this; } void QwtPainterCommand::copy( const QwtPainterCommand &other ) { d_type = other.d_type; switch( other.d_type ) { case Path: { d_path = new QPainterPath( *other.d_path ); break; } case Pixmap: { d_pixmapData = new PixmapData( *other.d_pixmapData ); break; } case Image: { d_imageData = new ImageData( *other.d_imageData ); break; } case State: { d_stateData = new StateData( *other.d_stateData ); break; } default: break; } } void QwtPainterCommand::reset() { switch( d_type ) { case Path: { delete d_path; break; } case Pixmap: { delete d_pixmapData; break; } case Image: { delete d_imageData; break; } case State: { delete d_stateData; break; } default: break; } d_type = Invalid; } //! \return Painter path to be painted QPainterPath *QwtPainterCommand::path() { return d_path; } //! \return Attributes how to paint a QPixmap QwtPainterCommand::PixmapData* QwtPainterCommand::pixmapData() { return d_pixmapData; } //! \return Attributes how to paint a QImage QwtPainterCommand::ImageData* QwtPainterCommand::imageData() { return d_imageData; } //! \return Attributes of a state change QwtPainterCommand::StateData* QwtPainterCommand::stateData() { return d_stateData; } connectome-workbench-1.4.2/src/Qwt/qwt_painter_command.h000066400000000000000000000073401360521144700234050ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PAINTER_COMMAND_H #define QWT_PAINTER_COMMAND_H #include "qwt_global.h" #include #include #include #include class QPainterPath; /*! QwtPainterCommand represents the attributes of a paint operation how it is used between QPainter and QPaintDevice It is used by QwtGraphic to record and replay paint operations \sa QwtGraphic::commands() */ class QWT_EXPORT QwtPainterCommand { public: //! Type of the paint command enum Type { //! Invalid command Invalid = -1, //! Draw a QPainterPath Path, //! Draw a QPixmap Pixmap, //! Draw a QImage Image, //! QPainter state change State }; //! Attributes how to paint a QPixmap struct PixmapData { QRectF rect; QPixmap pixmap; QRectF subRect; }; //! Attributes how to paint a QImage struct ImageData { QRectF rect; QImage image; QRectF subRect; Qt::ImageConversionFlags flags; }; //! Attributes of a state change struct StateData { QPaintEngine::DirtyFlags flags; QPen pen; QBrush brush; QPointF brushOrigin; QBrush backgroundBrush; Qt::BGMode backgroundMode; QFont font; QMatrix matrix; QTransform transform; Qt::ClipOperation clipOperation; QRegion clipRegion; QPainterPath clipPath; bool isClipEnabled; QPainter::RenderHints renderHints; QPainter::CompositionMode compositionMode; qreal opacity; }; QwtPainterCommand(); QwtPainterCommand(const QwtPainterCommand &); QwtPainterCommand( const QPainterPath & ); QwtPainterCommand( const QRectF &rect, const QPixmap &, const QRectF& subRect ); QwtPainterCommand( const QRectF &rect, const QImage &, const QRectF& subRect, Qt::ImageConversionFlags ); QwtPainterCommand( const QPaintEngineState & ); ~QwtPainterCommand(); QwtPainterCommand &operator=(const QwtPainterCommand & ); Type type() const; QPainterPath *path(); const QPainterPath *path() const; PixmapData* pixmapData(); const PixmapData* pixmapData() const; ImageData* imageData(); const ImageData* imageData() const; StateData* stateData(); const StateData* stateData() const; private: void copy( const QwtPainterCommand & ); void reset(); Type d_type; union { QPainterPath *d_path; PixmapData *d_pixmapData; ImageData *d_imageData; StateData *d_stateData; }; }; //! \return Type of the command inline QwtPainterCommand::Type QwtPainterCommand::type() const { return d_type; } //! \return Painter path to be painted inline const QPainterPath *QwtPainterCommand::path() const { return d_path; } //! \return Attributes how to paint a QPixmap inline const QwtPainterCommand::PixmapData* QwtPainterCommand::pixmapData() const { return d_pixmapData; } //! \return Attributes how to paint a QImage inline const QwtPainterCommand::ImageData * QwtPainterCommand::imageData() const { return d_imageData; } //! \return Attributes of a state change inline const QwtPainterCommand::StateData * QwtPainterCommand::stateData() const { return d_stateData; } #endif connectome-workbench-1.4.2/src/Qwt/qwt_panner.cpp000066400000000000000000000302271360521144700220630ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_panner.h" #include "qwt_picker.h" #include "qwt_painter.h" #include #include #include #include #include static QVector qwtActivePickers( QWidget *w ) { QVector pickers; QObjectList children = w->children(); for ( int i = 0; i < children.size(); i++ ) { QwtPicker *picker = qobject_cast( children[i] ); if ( picker && picker->isEnabled() ) pickers += picker; } return pickers; } class QwtPanner::PrivateData { public: PrivateData(): button( Qt::LeftButton ), buttonModifiers( Qt::NoModifier ), abortKey( Qt::Key_Escape ), abortKeyModifiers( Qt::NoModifier ), #ifndef QT_NO_CURSOR cursor( NULL ), restoreCursor( NULL ), hasCursor( false ), #endif isEnabled( false ) { orientations = Qt::Vertical | Qt::Horizontal; } ~PrivateData() { #ifndef QT_NO_CURSOR delete cursor; delete restoreCursor; #endif } Qt::MouseButton button; Qt::KeyboardModifiers buttonModifiers; int abortKey; Qt::KeyboardModifiers abortKeyModifiers; QPoint initialPos; QPoint pos; QPixmap pixmap; QBitmap contentsMask; #ifndef QT_NO_CURSOR QCursor *cursor; QCursor *restoreCursor; bool hasCursor; #endif bool isEnabled; Qt::Orientations orientations; }; /*! Creates an panner that is enabled for the left mouse button. \param parent Parent widget to be panned */ QwtPanner::QwtPanner( QWidget *parent ): QWidget( parent ) { d_data = new PrivateData(); setAttribute( Qt::WA_TransparentForMouseEvents ); setAttribute( Qt::WA_NoSystemBackground ); setFocusPolicy( Qt::NoFocus ); hide(); setEnabled( true ); } //! Destructor QwtPanner::~QwtPanner() { delete d_data; } /*! Change the mouse button and modifiers used for panning The defaults are Qt::LeftButton and Qt::NoModifier */ void QwtPanner::setMouseButton( Qt::MouseButton button, Qt::KeyboardModifiers modifiers ) { d_data->button = button; d_data->buttonModifiers = modifiers; } //! Get mouse button and modifiers used for panning void QwtPanner::getMouseButton( Qt::MouseButton &button, Qt::KeyboardModifiers &modifiers ) const { button = d_data->button; modifiers = d_data->buttonModifiers; } /*! Change the abort key The defaults are Qt::Key_Escape and Qt::NoModifiers \param key Key ( See Qt::Keycode ) \param modifiers Keyboard modifiers */ void QwtPanner::setAbortKey( int key, Qt::KeyboardModifiers modifiers ) { d_data->abortKey = key; d_data->abortKeyModifiers = modifiers; } //! Get the abort key and modifiers void QwtPanner::getAbortKey( int &key, Qt::KeyboardModifiers &modifiers ) const { key = d_data->abortKey; modifiers = d_data->abortKeyModifiers; } /*! Change the cursor, that is active while panning The default is the cursor of the parent widget. \param cursor New cursor \sa setCursor() */ #ifndef QT_NO_CURSOR void QwtPanner::setCursor( const QCursor &cursor ) { d_data->cursor = new QCursor( cursor ); } #endif /*! \return Cursor that is active while panning \sa setCursor() */ #ifndef QT_NO_CURSOR const QCursor QwtPanner::cursor() const { if ( d_data->cursor ) return *d_data->cursor; if ( parentWidget() ) return parentWidget()->cursor(); return QCursor(); } #endif /*! \brief En/disable the panner When enabled is true an event filter is installed for the observed widget, otherwise the event filter is removed. \param on true or false \sa isEnabled(), eventFilter() */ void QwtPanner::setEnabled( bool on ) { if ( d_data->isEnabled != on ) { d_data->isEnabled = on; QWidget *w = parentWidget(); if ( w ) { if ( d_data->isEnabled ) { w->installEventFilter( this ); } else { w->removeEventFilter( this ); hide(); } } } } /*! Set the orientations, where panning is enabled The default value is in both directions: Qt::Horizontal | Qt::Vertical /param o Orientation */ void QwtPanner::setOrientations( Qt::Orientations o ) { d_data->orientations = o; } //! Return the orientation, where paning is enabled Qt::Orientations QwtPanner::orientations() const { return d_data->orientations; } /*! \return True if an orientation is enabled \sa orientations(), setOrientations() */ bool QwtPanner::isOrientationEnabled( Qt::Orientation o ) const { return d_data->orientations & o; } /*! \return true when enabled, false otherwise \sa setEnabled, eventFilter() */ bool QwtPanner::isEnabled() const { return d_data->isEnabled; } /*! \brief Paint event Repaint the grabbed pixmap on its current position and fill the empty spaces by the background of the parent widget. \param pe Paint event */ void QwtPanner::paintEvent( QPaintEvent *pe ) { int dx = d_data->pos.x() - d_data->initialPos.x(); int dy = d_data->pos.y() - d_data->initialPos.y(); QRect r( 0, 0, d_data->pixmap.width(), d_data->pixmap.height() ); r.moveCenter( QPoint( r.center().x() + dx, r.center().y() + dy ) ); QPixmap pm( size() ); QwtPainter::fillPixmap( parentWidget(), pm ); QPainter painter( &pm ); if ( !d_data->contentsMask.isNull() ) { QPixmap masked = d_data->pixmap; masked.setMask( d_data->contentsMask ); painter.drawPixmap( r, masked ); } else { painter.drawPixmap( r, d_data->pixmap ); } painter.end(); if ( !d_data->contentsMask.isNull() ) pm.setMask( d_data->contentsMask ); painter.begin( this ); painter.setClipRegion( pe->region() ); painter.drawPixmap( 0, 0, pm ); } /*! \brief Calculate a mask for the contents of the panned widget Sometimes only parts of the contents of a widget should be panned. F.e. for a widget with a styled background with rounded borders only the area inside of the border should be panned. \return An empty bitmap, indicating no mask */ QBitmap QwtPanner::contentsMask() const { return QBitmap(); } /*! Grab the widget into a pixmap. \return Grabbed pixmap */ QPixmap QwtPanner::grab() const { #if QT_VERSION >= 0x050000 return parentWidget()->grab( parentWidget()->rect() ); #else return QPixmap::grabWidget( parentWidget() ); #endif } /*! \brief Event filter When isEnabled() is true mouse events of the observed widget are filtered. \param object Object to be filtered \param event Event \return Always false, beside for paint events for the parent widget. \sa widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseMoveEvent() */ bool QwtPanner::eventFilter( QObject *object, QEvent *event ) { if ( object == NULL || object != parentWidget() ) return false; switch ( event->type() ) { case QEvent::MouseButtonPress: { widgetMousePressEvent( static_cast( event ) ); break; } case QEvent::MouseMove: { widgetMouseMoveEvent( static_cast( event ) ); break; } case QEvent::MouseButtonRelease: { widgetMouseReleaseEvent( static_cast( event ) ); break; } case QEvent::KeyPress: { widgetKeyPressEvent( static_cast( event ) ); break; } case QEvent::KeyRelease: { widgetKeyReleaseEvent( static_cast( event ) ); break; } case QEvent::Paint: { if ( isVisible() ) return true; break; } default:; } return false; } /*! Handle a mouse press event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMouseReleaseEvent(), widgetMouseMoveEvent(), */ void QwtPanner::widgetMousePressEvent( QMouseEvent *mouseEvent ) { if ( ( mouseEvent->button() != d_data->button ) || ( mouseEvent->modifiers() != d_data->buttonModifiers ) ) { return; } QWidget *w = parentWidget(); if ( w == NULL ) return; #ifndef QT_NO_CURSOR showCursor( true ); #endif d_data->initialPos = d_data->pos = mouseEvent->pos(); setGeometry( parentWidget()->rect() ); // We don't want to grab the picker ! QVector pickers = qwtActivePickers( parentWidget() ); for ( int i = 0; i < pickers.size(); i++ ) pickers[i]->setEnabled( false ); d_data->pixmap = grab(); d_data->contentsMask = contentsMask(); for ( int i = 0; i < pickers.size(); i++ ) pickers[i]->setEnabled( true ); show(); } /*! Handle a mouse move event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent() */ void QwtPanner::widgetMouseMoveEvent( QMouseEvent *mouseEvent ) { if ( !isVisible() ) return; QPoint pos = mouseEvent->pos(); if ( !isOrientationEnabled( Qt::Horizontal ) ) pos.setX( d_data->initialPos.x() ); if ( !isOrientationEnabled( Qt::Vertical ) ) pos.setY( d_data->initialPos.y() ); if ( pos != d_data->pos && rect().contains( pos ) ) { d_data->pos = pos; update(); Q_EMIT moved( d_data->pos.x() - d_data->initialPos.x(), d_data->pos.y() - d_data->initialPos.y() ); } } /*! Handle a mouse release event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseMoveEvent(), */ void QwtPanner::widgetMouseReleaseEvent( QMouseEvent *mouseEvent ) { if ( isVisible() ) { hide(); #ifndef QT_NO_CURSOR showCursor( false ); #endif QPoint pos = mouseEvent->pos(); if ( !isOrientationEnabled( Qt::Horizontal ) ) pos.setX( d_data->initialPos.x() ); if ( !isOrientationEnabled( Qt::Vertical ) ) pos.setY( d_data->initialPos.y() ); d_data->pixmap = QPixmap(); d_data->contentsMask = QBitmap(); d_data->pos = pos; if ( d_data->pos != d_data->initialPos ) { Q_EMIT panned( d_data->pos.x() - d_data->initialPos.x(), d_data->pos.y() - d_data->initialPos.y() ); } } } /*! Handle a key press event for the observed widget. \param keyEvent Key event \sa eventFilter(), widgetKeyReleaseEvent() */ void QwtPanner::widgetKeyPressEvent( QKeyEvent *keyEvent ) { if ( ( keyEvent->key() == d_data->abortKey ) && ( keyEvent->modifiers() == d_data->abortKeyModifiers ) ) { hide(); #ifndef QT_NO_CURSOR showCursor( false ); #endif d_data->pixmap = QPixmap(); } } /*! Handle a key release event for the observed widget. \param keyEvent Key event \sa eventFilter(), widgetKeyReleaseEvent() */ void QwtPanner::widgetKeyReleaseEvent( QKeyEvent *keyEvent ) { Q_UNUSED( keyEvent ); } #ifndef QT_NO_CURSOR void QwtPanner::showCursor( bool on ) { if ( on == d_data->hasCursor ) return; QWidget *w = parentWidget(); if ( w == NULL || d_data->cursor == NULL ) return; d_data->hasCursor = on; if ( on ) { if ( w->testAttribute( Qt::WA_SetCursor ) ) { delete d_data->restoreCursor; d_data->restoreCursor = new QCursor( w->cursor() ); } w->setCursor( *d_data->cursor ); } else { if ( d_data->restoreCursor ) { w->setCursor( *d_data->restoreCursor ); delete d_data->restoreCursor; d_data->restoreCursor = NULL; } else w->unsetCursor(); } } #endif connectome-workbench-1.4.2/src/Qwt/qwt_panner.h000066400000000000000000000055741360521144700215370ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PANNER_H #define QWT_PANNER_H 1 #include "qwt_global.h" #include #include class QCursor; /*! \brief QwtPanner provides panning of a widget QwtPanner grabs the contents of a widget, that can be dragged in all directions. The offset between the start and the end position is emitted by the panned signal. QwtPanner grabs the content of the widget into a pixmap and moves the pixmap around, without initiating any repaint events for the widget. Areas, that are not part of content are not painted while panning. This makes panning fast enough for widgets, where repaints are too slow for mouse movements. For widgets, where repaints are very fast it might be better to implement panning manually by mapping mouse events into paint events. */ class QWT_EXPORT QwtPanner: public QWidget { Q_OBJECT public: QwtPanner( QWidget* parent ); virtual ~QwtPanner(); void setEnabled( bool ); bool isEnabled() const; void setMouseButton( Qt::MouseButton, Qt::KeyboardModifiers = Qt::NoModifier ); void getMouseButton( Qt::MouseButton &button, Qt::KeyboardModifiers & ) const; void setAbortKey( int key, Qt::KeyboardModifiers = Qt::NoModifier ); void getAbortKey( int &key, Qt::KeyboardModifiers & ) const; void setCursor( const QCursor & ); const QCursor cursor() const; void setOrientations( Qt::Orientations ); Qt::Orientations orientations() const; bool isOrientationEnabled( Qt::Orientation ) const; virtual bool eventFilter( QObject *, QEvent * ); Q_SIGNALS: /*! Signal emitted, when panning is done \param dx Offset in horizontal direction \param dy Offset in vertical direction */ void panned( int dx, int dy ); /*! Signal emitted, while the widget moved, but panning is not finished. \param dx Offset in horizontal direction \param dy Offset in vertical direction */ void moved( int dx, int dy ); protected: virtual void widgetMousePressEvent( QMouseEvent * ); virtual void widgetMouseReleaseEvent( QMouseEvent * ); virtual void widgetMouseMoveEvent( QMouseEvent * ); virtual void widgetKeyPressEvent( QKeyEvent * ); virtual void widgetKeyReleaseEvent( QKeyEvent * ); virtual void paintEvent( QPaintEvent * ); virtual QBitmap contentsMask() const; virtual QPixmap grab() const; private: #ifndef QT_NO_CURSOR void showCursor( bool ); #endif class PrivateData; PrivateData *d_data; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_picker.cpp000066400000000000000000001161471360521144700220630ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_picker.h" #include "qwt_picker_machine.h" #include "qwt_painter.h" #include "qwt_math.h" #include "qwt_widget_overlay.h" #include #include #include #include #include #include #include #include #include static inline QRegion qwtMaskRegion( const QRect &r, int penWidth ) { const int pw = qMax( penWidth, 1 ); const int pw2 = penWidth / 2; int x1 = r.left() - pw2; int x2 = r.right() + 1 + pw2 + ( pw % 2 ); int y1 = r.top() - pw2; int y2 = r.bottom() + 1 + pw2 + ( pw % 2 ); QRegion region; region += QRect( x1, y1, x2 - x1, pw ); region += QRect( x1, y1, pw, y2 - y1 ); region += QRect( x1, y2 - pw, x2 - x1, pw ); region += QRect( x2 - pw, y1, pw, y2 - y1 ); return region; } static inline QRegion qwtMaskRegion( const QLine &l, int penWidth ) { const int pw = qMax( penWidth, 1 ); const int pw2 = penWidth / 2; QRegion region; if ( l.x1() == l.x2() ) { region += QRect( l.x1() - pw2, l.y1(), pw, l.y2() ).normalized(); } else if ( l.y1() == l.y2() ) { region += QRect( l.x1(), l.y1() - pw2, l.x2(), pw ).normalized(); } return region; } class QwtPickerRubberband: public QwtWidgetOverlay { public: QwtPickerRubberband( QwtPicker *, QWidget * ); protected: virtual void drawOverlay( QPainter * ) const; virtual QRegion maskHint() const; QwtPicker *d_picker; }; class QwtPickerTracker: public QwtWidgetOverlay { public: QwtPickerTracker( QwtPicker *, QWidget * ); protected: virtual void drawOverlay( QPainter * ) const; virtual QRegion maskHint() const; QwtPicker *d_picker; }; class QwtPicker::PrivateData { public: PrivateData(): enabled( false ), stateMachine( NULL ), resizeMode( QwtPicker::Stretch ), rubberBand( QwtPicker::NoRubberBand ), trackerMode( QwtPicker::AlwaysOff ), isActive( false ), trackerPosition( -1, -1 ), mouseTracking( false ), openGL( false ) { } bool enabled; QwtPickerMachine *stateMachine; QwtPicker::ResizeMode resizeMode; QwtPicker::RubberBand rubberBand; QPen rubberBandPen; QwtPicker::DisplayMode trackerMode; QPen trackerPen; QFont trackerFont; QPolygon pickedPoints; bool isActive; QPoint trackerPosition; bool mouseTracking; // used to save previous value QPointer< QwtPickerRubberband > rubberBandOverlay; QPointer< QwtPickerTracker> trackerOverlay; bool openGL; }; QwtPickerRubberband::QwtPickerRubberband( QwtPicker *picker, QWidget *parent ): QwtWidgetOverlay( parent ), d_picker( picker ) { setMaskMode( QwtWidgetOverlay::MaskHint ); } QRegion QwtPickerRubberband::maskHint() const { return d_picker->rubberBandMask(); } void QwtPickerRubberband::drawOverlay( QPainter *painter ) const { painter->setPen( d_picker->rubberBandPen() ); d_picker->drawRubberBand( painter ); } QwtPickerTracker::QwtPickerTracker( QwtPicker *picker, QWidget *parent ): QwtWidgetOverlay( parent ), d_picker( picker ) { setMaskMode( QwtWidgetOverlay::MaskHint ); } QRegion QwtPickerTracker::maskHint() const { return d_picker->trackerRect( font() ); } void QwtPickerTracker::drawOverlay( QPainter *painter ) const { painter->setPen( d_picker->trackerPen() ); d_picker->drawTracker( painter ); } /*! Constructor Creates an picker that is enabled, but without a state machine. rubber band and tracker are disabled. \param parent Parent widget, that will be observed */ QwtPicker::QwtPicker( QWidget *parent ): QObject( parent ) { init( parent, NoRubberBand, AlwaysOff ); } /*! Constructor \param rubberBand Rubber band style \param trackerMode Tracker mode \param parent Parent widget, that will be observed */ QwtPicker::QwtPicker( RubberBand rubberBand, DisplayMode trackerMode, QWidget *parent ): QObject( parent ) { init( parent, rubberBand, trackerMode ); } //! Destructor QwtPicker::~QwtPicker() { setMouseTracking( false ); delete d_data->stateMachine; delete d_data->rubberBandOverlay; delete d_data->trackerOverlay; delete d_data; } //! Initialize the picker - used by the constructors void QwtPicker::init( QWidget *parent, RubberBand rubberBand, DisplayMode trackerMode ) { d_data = new PrivateData; d_data->rubberBand = rubberBand; if ( parent ) { if ( parent->focusPolicy() == Qt::NoFocus ) parent->setFocusPolicy( Qt::WheelFocus ); d_data->openGL = parent->inherits( "QGLWidget" ); d_data->trackerFont = parent->font(); d_data->mouseTracking = parent->hasMouseTracking(); setEnabled( true ); } setTrackerMode( trackerMode ); } /*! Set a state machine and delete the previous one \param stateMachine State machine \sa stateMachine() */ void QwtPicker::setStateMachine( QwtPickerMachine *stateMachine ) { if ( d_data->stateMachine != stateMachine ) { reset(); delete d_data->stateMachine; d_data->stateMachine = stateMachine; if ( d_data->stateMachine ) d_data->stateMachine->reset(); } } /*! \return Assigned state machine \sa setStateMachine() */ QwtPickerMachine *QwtPicker::stateMachine() { return d_data->stateMachine; } /*! \return Assigned state machine \sa setStateMachine() */ const QwtPickerMachine *QwtPicker::stateMachine() const { return d_data->stateMachine; } //! Return the parent widget, where the selection happens QWidget *QwtPicker::parentWidget() { QObject *obj = parent(); if ( obj && obj->isWidgetType() ) return static_cast( obj ); return NULL; } //! Return the parent widget, where the selection happens const QWidget *QwtPicker::parentWidget() const { QObject *obj = parent(); if ( obj && obj->isWidgetType() ) return static_cast< const QWidget *>( obj ); return NULL; } /*! Set the rubber band style \param rubberBand Rubber band style The default value is NoRubberBand. \sa rubberBand(), RubberBand, setRubberBandPen() */ void QwtPicker::setRubberBand( RubberBand rubberBand ) { d_data->rubberBand = rubberBand; } /*! \return Rubber band style \sa setRubberBand(), RubberBand, rubberBandPen() */ QwtPicker::RubberBand QwtPicker::rubberBand() const { return d_data->rubberBand; } /*! \brief Set the display mode of the tracker. A tracker displays information about current position of the cursor as a string. The display mode controls if the tracker has to be displayed whenever the observed widget has focus and cursor (AlwaysOn), never (AlwaysOff), or only when the selection is active (ActiveOnly). \param mode Tracker display mode \warning In case of AlwaysOn, mouseTracking will be enabled for the observed widget. \sa trackerMode(), DisplayMode */ void QwtPicker::setTrackerMode( DisplayMode mode ) { if ( d_data->trackerMode != mode ) { d_data->trackerMode = mode; setMouseTracking( d_data->trackerMode == AlwaysOn ); } } /*! \return Tracker display mode \sa setTrackerMode(), DisplayMode */ QwtPicker::DisplayMode QwtPicker::trackerMode() const { return d_data->trackerMode; } /*! \brief Set the resize mode. The resize mode controls what to do with the selected points of an active selection when the observed widget is resized. Stretch means the points are scaled according to the new size, KeepSize means the points remain unchanged. The default mode is Stretch. \param mode Resize mode \sa resizeMode(), ResizeMode */ void QwtPicker::setResizeMode( ResizeMode mode ) { d_data->resizeMode = mode; } /*! \return Resize mode \sa setResizeMode(), ResizeMode */ QwtPicker::ResizeMode QwtPicker::resizeMode() const { return d_data->resizeMode; } /*! \brief En/disable the picker When enabled is true an event filter is installed for the observed widget, otherwise the event filter is removed. \param enabled true or false \sa isEnabled(), eventFilter() */ void QwtPicker::setEnabled( bool enabled ) { if ( d_data->enabled != enabled ) { d_data->enabled = enabled; QWidget *w = parentWidget(); if ( w ) { if ( enabled ) w->installEventFilter( this ); else w->removeEventFilter( this ); } updateDisplay(); } } /*! \return true when enabled, false otherwise \sa setEnabled(), eventFilter() */ bool QwtPicker::isEnabled() const { return d_data->enabled; } /*! Set the font for the tracker \param font Tracker font \sa trackerFont(), setTrackerMode(), setTrackerPen() */ void QwtPicker::setTrackerFont( const QFont &font ) { if ( font != d_data->trackerFont ) { d_data->trackerFont = font; updateDisplay(); } } /*! \return Tracker font \sa setTrackerFont(), trackerMode(), trackerPen() */ QFont QwtPicker::trackerFont() const { return d_data->trackerFont; } /*! Set the pen for the tracker \param pen Tracker pen \sa trackerPen(), setTrackerMode(), setTrackerFont() */ void QwtPicker::setTrackerPen( const QPen &pen ) { if ( pen != d_data->trackerPen ) { d_data->trackerPen = pen; updateDisplay(); } } /*! \return Tracker pen \sa setTrackerPen(), trackerMode(), trackerFont() */ QPen QwtPicker::trackerPen() const { return d_data->trackerPen; } /*! Set the pen for the rubberband \param pen Rubber band pen \sa rubberBandPen(), setRubberBand() */ void QwtPicker::setRubberBandPen( const QPen &pen ) { if ( pen != d_data->rubberBandPen ) { d_data->rubberBandPen = pen; updateDisplay(); } } /*! \return Rubber band pen \sa setRubberBandPen(), rubberBand() */ QPen QwtPicker::rubberBandPen() const { return d_data->rubberBandPen; } /*! \brief Return the label for a position In case of HLineRubberBand the label is the value of the y position, in case of VLineRubberBand the value of the x position. Otherwise the label contains x and y position separated by a ',' . The format for the string conversion is "%d". \param pos Position \return Converted position as string */ QwtText QwtPicker::trackerText( const QPoint &pos ) const { QString label; switch ( rubberBand() ) { case HLineRubberBand: label.sprintf( "%d", pos.y() ); break; case VLineRubberBand: label.sprintf( "%d", pos.x() ); break; default: label.sprintf( "%d, %d", pos.x(), pos.y() ); } return label; } /*! Calculate the mask for the rubber band overlay \return Region for the mask \sa QWidget::setMask() */ QRegion QwtPicker::rubberBandMask() const { QRegion mask; if ( !isActive() || rubberBand() == NoRubberBand || rubberBandPen().style() == Qt::NoPen ) { return mask; } const QPolygon pa = adjustedPoints( d_data->pickedPoints ); QwtPickerMachine::SelectionType selectionType = QwtPickerMachine::NoSelection; if ( d_data->stateMachine ) selectionType = d_data->stateMachine->selectionType(); switch ( selectionType ) { case QwtPickerMachine::NoSelection: case QwtPickerMachine::PointSelection: { if ( pa.count() < 1 ) return mask; const QPoint pos = pa[0]; const int pw = rubberBandPen().width(); const QRect pRect = pickArea().boundingRect().toRect(); switch ( rubberBand() ) { case VLineRubberBand: { mask += qwtMaskRegion( QLine( pos.x(), pRect.top(), pos.x(), pRect.bottom() ), pw ); break; } case HLineRubberBand: { mask += qwtMaskRegion( QLine( pRect.left(), pos.y(), pRect.right(), pos.y() ), pw ); break; } case CrossRubberBand: { mask += qwtMaskRegion( QLine( pos.x(), pRect.top(), pos.x(), pRect.bottom() ), pw ); mask += qwtMaskRegion( QLine( pRect.left(), pos.y(), pRect.right(), pos.y() ), pw ); break; } default: break; } break; } case QwtPickerMachine::RectSelection: { if ( pa.count() < 2 ) return mask; const int pw = rubberBandPen().width(); switch ( rubberBand() ) { case RectRubberBand: { const QRect r = QRect( pa.first(), pa.last() ); mask = qwtMaskRegion( r.normalized(), pw ); break; } case EllipseRubberBand: { const QRect r = QRect( pa.first(), pa.last() ); mask += r.adjusted( -pw, -pw, pw, pw ); break; } default: break; } break; } case QwtPickerMachine::PolygonSelection: { const int pw = rubberBandPen().width(); if ( pw <= 1 ) { // because of the join style we better // return a mask for a pen width <= 1 only const int off = 2 * pw; const QRect r = pa.boundingRect(); mask += r.adjusted( -off, -off, off, off ); } break; } default: break; } return mask; } /*! Draw a rubber band, depending on rubberBand() \param painter Painter, initialized with a clip region \sa rubberBand(), RubberBand */ void QwtPicker::drawRubberBand( QPainter *painter ) const { if ( !isActive() || rubberBand() == NoRubberBand || rubberBandPen().style() == Qt::NoPen ) { return; } const QPolygon pa = adjustedPoints( d_data->pickedPoints ); QwtPickerMachine::SelectionType selectionType = QwtPickerMachine::NoSelection; if ( d_data->stateMachine ) selectionType = d_data->stateMachine->selectionType(); switch ( selectionType ) { case QwtPickerMachine::NoSelection: case QwtPickerMachine::PointSelection: { if ( pa.count() < 1 ) return; const QPoint pos = pa[0]; const QRect pRect = pickArea().boundingRect().toRect(); switch ( rubberBand() ) { case VLineRubberBand: { QwtPainter::drawLine( painter, pos.x(), pRect.top(), pos.x(), pRect.bottom() ); break; } case HLineRubberBand: { QwtPainter::drawLine( painter, pRect.left(), pos.y(), pRect.right(), pos.y() ); break; } case CrossRubberBand: { QwtPainter::drawLine( painter, pos.x(), pRect.top(), pos.x(), pRect.bottom() ); QwtPainter::drawLine( painter, pRect.left(), pos.y(), pRect.right(), pos.y() ); break; } default: break; } break; } case QwtPickerMachine::RectSelection: { if ( pa.count() < 2 ) return; const QRect rect = QRect( pa.first(), pa.last() ).normalized(); switch ( rubberBand() ) { case EllipseRubberBand: { QwtPainter::drawEllipse( painter, rect ); break; } case RectRubberBand: { QwtPainter::drawRect( painter, rect ); break; } default: break; } break; } case QwtPickerMachine::PolygonSelection: { if ( rubberBand() == PolygonRubberBand ) painter->drawPolyline( pa ); break; } default: break; } } /*! Draw the tracker \param painter Painter \sa trackerRect(), trackerText() */ void QwtPicker::drawTracker( QPainter *painter ) const { const QRect textRect = trackerRect( painter->font() ); if ( !textRect.isEmpty() ) { const QwtText label = trackerText( d_data->trackerPosition ); if ( !label.isEmpty() ) label.draw( painter, textRect ); } } /*! \brief Map the pickedPoints() into a selection() adjustedPoints() maps the points, that have been collected on the parentWidget() into a selection(). The default implementation simply returns the points unmodified. The reason, why a selection() differs from the picked points depends on the application requirements. F.e. : - A rectangular selection might need to have a specific aspect ratio only.\n - A selection could accept non intersecting polygons only.\n - ...\n The example below is for a rectangular selection, where the first point is the center of the selected rectangle. \par Example \verbatim QPolygon MyPicker::adjustedPoints(const QPolygon &points) const { QPolygon adjusted; if ( points.size() == 2 ) { const int width = qAbs(points[1].x() - points[0].x()); const int height = qAbs(points[1].y() - points[0].y()); QRect rect(0, 0, 2 * width, 2 * height); rect.moveCenter(points[0]); adjusted += rect.topLeft(); adjusted += rect.bottomRight(); } return adjusted; }\endverbatim\n \param points Selected points \return Selected points unmodified */ QPolygon QwtPicker::adjustedPoints( const QPolygon &points ) const { return points; } /*! \return Selected points \sa pickedPoints(), adjustedPoints() */ QPolygon QwtPicker::selection() const { return adjustedPoints( d_data->pickedPoints ); } //! \return Current position of the tracker QPoint QwtPicker::trackerPosition() const { return d_data->trackerPosition; } /*! Calculate the bounding rectangle for the tracker text from the current position of the tracker \param font Font of the tracker text \return Bounding rectangle of the tracker text \sa trackerPosition() */ QRect QwtPicker::trackerRect( const QFont &font ) const { if ( trackerMode() == AlwaysOff || ( trackerMode() == ActiveOnly && !isActive() ) ) { return QRect(); } if ( d_data->trackerPosition.x() < 0 || d_data->trackerPosition.y() < 0 ) return QRect(); QwtText text = trackerText( d_data->trackerPosition ); if ( text.isEmpty() ) return QRect(); const QSizeF textSize = text.textSize( font ); QRect textRect( 0, 0, qCeil( textSize.width() ), qCeil( textSize.height() ) ); const QPoint &pos = d_data->trackerPosition; int alignment = 0; if ( isActive() && d_data->pickedPoints.count() > 1 && rubberBand() != NoRubberBand ) { const QPoint last = d_data->pickedPoints[int( d_data->pickedPoints.count() ) - 2]; alignment |= ( pos.x() >= last.x() ) ? Qt::AlignRight : Qt::AlignLeft; alignment |= ( pos.y() > last.y() ) ? Qt::AlignBottom : Qt::AlignTop; } else alignment = Qt::AlignTop | Qt::AlignRight; const int margin = 5; int x = pos.x(); if ( alignment & Qt::AlignLeft ) x -= textRect.width() + margin; else if ( alignment & Qt::AlignRight ) x += margin; int y = pos.y(); if ( alignment & Qt::AlignBottom ) y += margin; else if ( alignment & Qt::AlignTop ) y -= textRect.height() + margin; textRect.moveTopLeft( QPoint( x, y ) ); const QRect pickRect = pickArea().boundingRect().toRect(); int right = qMin( textRect.right(), pickRect.right() - margin ); int bottom = qMin( textRect.bottom(), pickRect.bottom() - margin ); textRect.moveBottomRight( QPoint( right, bottom ) ); int left = qMax( textRect.left(), pickRect.left() + margin ); int top = qMax( textRect.top(), pickRect.top() + margin ); textRect.moveTopLeft( QPoint( left, top ) ); return textRect; } /*! \brief Event filter When isEnabled() is true all events of the observed widget are filtered. Mouse and keyboard events are translated into widgetMouse- and widgetKey- and widgetWheel-events. Paint and Resize events are handled to keep rubber band and tracker up to date. \param object Object to be filtered \param event Event \return Always false. \sa widgetEnterEvent(), widgetLeaveEvent(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent(), QObject::installEventFilter(), QObject::event() */ bool QwtPicker::eventFilter( QObject *object, QEvent *event ) { if ( object && object == parentWidget() ) { switch ( event->type() ) { case QEvent::Resize: { const QResizeEvent *re = static_cast( event ); /* Adding/deleting additional event filters inside of an event filter is not safe dues to the implementation in Qt ( changing alist while iterating ). So we create the overlays in a way, that they don't install en event filter ( parent set to NULL ) and do the resizing here. */ if ( d_data->trackerOverlay ) d_data->trackerOverlay->resize( re->size() ); if ( d_data->rubberBandOverlay ) d_data->rubberBandOverlay->resize( re->size() ); if ( d_data->resizeMode == Stretch ) stretchSelection( re->oldSize(), re->size() ); updateDisplay(); break; } case QEvent::Enter: { widgetEnterEvent( event ); break; } case QEvent::Leave: { widgetLeaveEvent( event ); break; } case QEvent::MouseButtonPress: { widgetMousePressEvent( static_cast( event ) ); break; } case QEvent::MouseButtonRelease: { widgetMouseReleaseEvent( static_cast( event ) ); break; } case QEvent::MouseButtonDblClick: { widgetMouseDoubleClickEvent( static_cast( event ) ); break; } case QEvent::MouseMove: { widgetMouseMoveEvent( static_cast( event ) ); break; } case QEvent::KeyPress: { widgetKeyPressEvent( static_cast( event ) ); break; } case QEvent::KeyRelease: { widgetKeyReleaseEvent( static_cast( event ) ); break; } case QEvent::Wheel: { widgetWheelEvent( static_cast( event ) ); break; } default: break; } } return false; } /*! Handle a mouse press event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetMousePressEvent( QMouseEvent *mouseEvent ) { transition( mouseEvent ); } /*! Handle a mouse move event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetMouseMoveEvent( QMouseEvent *mouseEvent ) { if ( pickArea().contains( mouseEvent->pos() ) ) d_data->trackerPosition = mouseEvent->pos(); else d_data->trackerPosition = QPoint( -1, -1 ); if ( !isActive() ) updateDisplay(); transition( mouseEvent ); } /*! Handle a enter event for the observed widget. \param event Qt event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetEnterEvent( QEvent *event ) { transition( event ); } /*! Handle a leave event for the observed widget. \param event Qt event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetLeaveEvent( QEvent *event ) { transition( event ); d_data->trackerPosition = QPoint( -1, -1 ); if ( !isActive() ) updateDisplay(); } /*! Handle a mouse release event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetMouseReleaseEvent( QMouseEvent *mouseEvent ) { transition( mouseEvent ); } /*! Handle mouse double click event for the observed widget. \param mouseEvent Mouse event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetMouseDoubleClickEvent( QMouseEvent *mouseEvent ) { transition( mouseEvent ); } /*! Handle a wheel event for the observed widget. Move the last point of the selection in case of isActive() == true \param wheelEvent Wheel event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(), widgetKeyPressEvent(), widgetKeyReleaseEvent() */ void QwtPicker::widgetWheelEvent( QWheelEvent *wheelEvent ) { if ( pickArea().contains( wheelEvent->pos() ) ) d_data->trackerPosition = wheelEvent->pos(); else d_data->trackerPosition = QPoint( -1, -1 ); updateDisplay(); transition( wheelEvent ); } /*! Handle a key press event for the observed widget. Selections can be completely done by the keyboard. The arrow keys move the cursor, the abort key aborts a selection. All other keys are handled by the current state machine. \param keyEvent Key event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyReleaseEvent(), stateMachine(), QwtEventPattern::KeyPatternCode */ void QwtPicker::widgetKeyPressEvent( QKeyEvent *keyEvent ) { int dx = 0; int dy = 0; int offset = 1; if ( keyEvent->isAutoRepeat() ) offset = 5; if ( keyMatch( KeyLeft, keyEvent ) ) dx = -offset; else if ( keyMatch( KeyRight, keyEvent ) ) dx = offset; else if ( keyMatch( KeyUp, keyEvent ) ) dy = -offset; else if ( keyMatch( KeyDown, keyEvent ) ) dy = offset; else if ( keyMatch( KeyAbort, keyEvent ) ) { reset(); } else transition( keyEvent ); if ( dx != 0 || dy != 0 ) { const QRect rect = pickArea().boundingRect().toRect(); const QPoint pos = parentWidget()->mapFromGlobal( QCursor::pos() ); int x = pos.x() + dx; x = qMax( rect.left(), x ); x = qMin( rect.right(), x ); int y = pos.y() + dy; y = qMax( rect.top(), y ); y = qMin( rect.bottom(), y ); QCursor::setPos( parentWidget()->mapToGlobal( QPoint( x, y ) ) ); } } /*! Handle a key release event for the observed widget. Passes the event to the state machine. \param keyEvent Key event \sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(), widgetMouseDoubleClickEvent(), widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent(), stateMachine() */ void QwtPicker::widgetKeyReleaseEvent( QKeyEvent *keyEvent ) { transition( keyEvent ); } /*! Passes an event to the state machine and executes the resulting commands. Append and Move commands use the current position of the cursor ( QCursor::pos() ). \param event Event */ void QwtPicker::transition( const QEvent *event ) { if ( !d_data->stateMachine ) return; const QList commandList = d_data->stateMachine->transition( *this, event ); QPoint pos; switch ( event->type() ) { case QEvent::MouseButtonDblClick: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseMove: { const QMouseEvent *me = static_cast< const QMouseEvent * >( event ); pos = me->pos(); break; } default: pos = parentWidget()->mapFromGlobal( QCursor::pos() ); } for ( int i = 0; i < commandList.count(); i++ ) { switch ( commandList[i] ) { case QwtPickerMachine::Begin: { begin(); break; } case QwtPickerMachine::Append: { append( pos ); break; } case QwtPickerMachine::Move: { move( pos ); break; } case QwtPickerMachine::Remove: { remove(); break; } case QwtPickerMachine::End: { end(); break; } } } } /*! Open a selection setting the state to active \sa isActive(), end(), append(), move() */ void QwtPicker::begin() { if ( d_data->isActive ) return; d_data->pickedPoints.resize( 0 ); d_data->isActive = true; Q_EMIT activated( true ); if ( trackerMode() != AlwaysOff ) { if ( d_data->trackerPosition.x() < 0 || d_data->trackerPosition.y() < 0 ) { QWidget *w = parentWidget(); if ( w ) d_data->trackerPosition = w->mapFromGlobal( QCursor::pos() ); } } updateDisplay(); setMouseTracking( true ); } /*! \brief Close a selection setting the state to inactive. The selection is validated and maybe fixed by accept(). \param ok If true, complete the selection and emit a selected signal otherwise discard the selection. \return true if the selection is accepted, false otherwise \sa isActive(), begin(), append(), move(), selected(), accept() */ bool QwtPicker::end( bool ok ) { if ( d_data->isActive ) { setMouseTracking( false ); d_data->isActive = false; Q_EMIT activated( false ); if ( trackerMode() == ActiveOnly ) d_data->trackerPosition = QPoint( -1, -1 ); if ( ok ) ok = accept( d_data->pickedPoints ); if ( ok ) Q_EMIT selected( d_data->pickedPoints ); else d_data->pickedPoints.resize( 0 ); updateDisplay(); } else ok = false; return ok; } /*! Reset the state machine and terminate ( end(false) ) the selection */ void QwtPicker::reset() { if ( d_data->stateMachine ) d_data->stateMachine->reset(); if ( isActive() ) end( false ); } /*! Append a point to the selection and update rubber band and tracker. The appended() signal is emitted. \param pos Additional point \sa isActive(), begin(), end(), move(), appended() */ void QwtPicker::append( const QPoint &pos ) { if ( d_data->isActive ) { const int idx = d_data->pickedPoints.count(); d_data->pickedPoints.resize( idx + 1 ); d_data->pickedPoints[idx] = pos; updateDisplay(); Q_EMIT appended( pos ); } } /*! Move the last point of the selection The moved() signal is emitted. \param pos New position \sa isActive(), begin(), end(), append() */ void QwtPicker::move( const QPoint &pos ) { if ( d_data->isActive ) { const int idx = d_data->pickedPoints.count() - 1; if ( idx >= 0 ) { if ( d_data->pickedPoints[idx] != pos ) { d_data->pickedPoints[idx] = pos; updateDisplay(); Q_EMIT moved( pos ); } } } } /*! Remove the last point of the selection The removed() signal is emitted. \sa isActive(), begin(), end(), append(), move() */ void QwtPicker::remove() { if ( d_data->isActive ) { const int idx = d_data->pickedPoints.count() - 1; if ( idx > 0 ) { const int idx = d_data->pickedPoints.count(); const QPoint pos = d_data->pickedPoints[idx - 1]; d_data->pickedPoints.resize( idx - 1 ); updateDisplay(); Q_EMIT removed( pos ); } } } /*! \brief Validate and fix up the selection Accepts all selections unmodified \param selection Selection to validate and fix up \return true, when accepted, false otherwise */ bool QwtPicker::accept( QPolygon &selection ) const { Q_UNUSED( selection ); return true; } /*! A picker is active between begin() and end(). \return true if the selection is active. */ bool QwtPicker::isActive() const { return d_data->isActive; } /*! Return the points, that have been collected so far. The selection() is calculated from the pickedPoints() in adjustedPoints(). \return Picked points */ const QPolygon &QwtPicker::pickedPoints() const { return d_data->pickedPoints; } /*! Scale the selection by the ratios of oldSize and newSize The changed() signal is emitted. \param oldSize Previous size \param newSize Current size \sa ResizeMode, setResizeMode(), resizeMode() */ void QwtPicker::stretchSelection( const QSize &oldSize, const QSize &newSize ) { if ( oldSize.isEmpty() ) { // avoid division by zero. But scaling for small sizes also // doesn't make much sense, because of rounding losses. TODO ... return; } const double xRatio = double( newSize.width() ) / double( oldSize.width() ); const double yRatio = double( newSize.height() ) / double( oldSize.height() ); for ( int i = 0; i < int( d_data->pickedPoints.count() ); i++ ) { QPoint &p = d_data->pickedPoints[i]; p.setX( qRound( p.x() * xRatio ) ); p.setY( qRound( p.y() * yRatio ) ); Q_EMIT changed( d_data->pickedPoints ); } } /*! Set mouse tracking for the observed widget. In case of enable is true, the previous value is saved, that is restored when enable is false. \warning Even when enable is false, mouse tracking might be restored to true. When mouseTracking for the observed widget has been changed directly by QWidget::setMouseTracking while mouse tracking has been set to true, this value can't be restored. */ void QwtPicker::setMouseTracking( bool enable ) { QWidget *widget = parentWidget(); if ( !widget ) return; if ( enable ) { d_data->mouseTracking = widget->hasMouseTracking(); widget->setMouseTracking( true ); } else { widget->setMouseTracking( d_data->mouseTracking ); } } /*! Find the area of the observed widget, where selection might happen. \return parentWidget()->contentsRect() */ QPainterPath QwtPicker::pickArea() const { QPainterPath path; const QWidget *widget = parentWidget(); if ( widget ) path.addRect( widget->contentsRect() ); return path; } //! Update the state of rubber band and tracker label void QwtPicker::updateDisplay() { QWidget *w = parentWidget(); bool showRubberband = false; bool showTracker = false; if ( w && w->isVisible() && d_data->enabled ) { if ( rubberBand() != NoRubberBand && isActive() && rubberBandPen().style() != Qt::NoPen ) { showRubberband = true; } if ( trackerMode() == AlwaysOn || ( trackerMode() == ActiveOnly && isActive() ) ) { if ( trackerPen() != Qt::NoPen && !trackerRect( QFont() ).isEmpty() ) { showTracker = true; } } } QPointer< QwtPickerRubberband > &rw = d_data->rubberBandOverlay; if ( showRubberband ) { if ( rw.isNull() ) { rw = new QwtPickerRubberband( this, NULL ); // NULL -> no extra event filter rw->setObjectName( "PickerRubberBand" ); rw->setParent( w ); rw->resize( w->size() ); } if ( d_data->rubberBand <= RectRubberBand ) rw->setMaskMode( QwtWidgetOverlay::MaskHint ); else rw->setMaskMode( QwtWidgetOverlay::AlphaMask ); rw->updateOverlay(); } else { if ( d_data->openGL ) { // Qt 4.8 crashes for a delete if ( !rw.isNull() ) { rw->hide(); rw->deleteLater(); rw = NULL; } } else { delete rw; } } QPointer< QwtPickerTracker > &tw = d_data->trackerOverlay; if ( showTracker ) { if ( tw.isNull() ) { tw = new QwtPickerTracker( this, NULL ); // NULL -> no extra event filter tw->setObjectName( "PickerTracker" ); tw->setParent( w ); tw->resize( w->size() ); } tw->setFont( d_data->trackerFont ); tw->updateOverlay(); } else { if ( d_data->openGL ) { // Qt 4.8 crashes for a delete if ( !tw.isNull() ) { tw->hide(); tw->deleteLater(); tw = NULL; } } else { delete tw; } } } //! \return Overlay displaying the rubber band const QwtWidgetOverlay *QwtPicker::rubberBandOverlay() const { return d_data->rubberBandOverlay; } //! \return Overlay displaying the tracker text const QwtWidgetOverlay *QwtPicker::trackerOverlay() const { return d_data->trackerOverlay; } connectome-workbench-1.4.2/src/Qwt/qwt_picker.h000066400000000000000000000224761360521144700215310ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PICKER #define QWT_PICKER 1 #include "qwt_global.h" #include "qwt_text.h" #include "qwt_event_pattern.h" #include #include #include #include #include class QWidget; class QMouseEvent; class QWheelEvent; class QKeyEvent; class QwtPickerMachine; class QwtWidgetOverlay; /*! \brief QwtPicker provides selections on a widget QwtPicker filters all enter, leave, mouse and keyboard events of a widget and translates them into an array of selected points. The way how the points are collected depends on type of state machine that is connected to the picker. Qwt offers a couple of predefined state machines for selecting: - Nothing\n QwtPickerTrackerMachine - Single points\n QwtPickerClickPointMachine, QwtPickerDragPointMachine - Rectangles\n QwtPickerClickRectMachine, QwtPickerDragRectMachine - Polygons\n QwtPickerPolygonMachine While these state machines cover the most common ways to collect points it is also possible to implement individual machines as well. QwtPicker translates the picked points into a selection using the adjustedPoints() method. adjustedPoints() is intended to be reimplemented to fix up the selection according to application specific requirements. (F.e. when an application accepts rectangles of a fixed aspect ratio only.) Optionally QwtPicker support the process of collecting points by a rubber band and tracker displaying a text for the current mouse position. \par Example \verbatim #include #include QwtPicker *picker = new QwtPicker(widget); picker->setStateMachine(new QwtPickerDragRectMachine); picker->setTrackerMode(QwtPicker::ActiveOnly); picker->setRubberBand(QwtPicker::RectRubberBand); \endverbatim\n The state machine triggers the following commands: - begin()\n Activate/Initialize the selection. - append()\n Add a new point - move() \n Change the position of the last point. - remove()\n Remove the last point. - end()\n Terminate the selection and call accept to validate the picked points. The picker is active (isActive()), between begin() and end(). In active state the rubber band is displayed, and the tracker is visible in case of trackerMode is ActiveOnly or AlwaysOn. The cursor can be moved using the arrow keys. All selections can be aborted using the abort key. (QwtEventPattern::KeyPatternCode) \warning In case of QWidget::NoFocus the focus policy of the observed widget is set to QWidget::WheelFocus and mouse tracking will be manipulated while the picker is active, or if trackerMode() is AlwayOn. */ class QWT_EXPORT QwtPicker: public QObject, public QwtEventPattern { Q_OBJECT Q_ENUMS( RubberBand DisplayMode ResizeMode ) Q_PROPERTY( bool isEnabled READ isEnabled WRITE setEnabled ) Q_PROPERTY( ResizeMode resizeMode READ resizeMode WRITE setResizeMode ) Q_PROPERTY( DisplayMode trackerMode READ trackerMode WRITE setTrackerMode ) Q_PROPERTY( QPen trackerPen READ trackerPen WRITE setTrackerPen ) Q_PROPERTY( QFont trackerFont READ trackerFont WRITE setTrackerFont ) Q_PROPERTY( RubberBand rubberBand READ rubberBand WRITE setRubberBand ) Q_PROPERTY( QPen rubberBandPen READ rubberBandPen WRITE setRubberBandPen ) public: /*! Rubber band style The default value is QwtPicker::NoRubberBand. \sa setRubberBand(), rubberBand() */ enum RubberBand { //! No rubberband. NoRubberBand = 0, //! A horizontal line ( only for QwtPickerMachine::PointSelection ) HLineRubberBand, //! A vertical line ( only for QwtPickerMachine::PointSelection ) VLineRubberBand, //! A crosshair ( only for QwtPickerMachine::PointSelection ) CrossRubberBand, //! A rectangle ( only for QwtPickerMachine::RectSelection ) RectRubberBand, //! An ellipse ( only for QwtPickerMachine::RectSelection ) EllipseRubberBand, //! A polygon ( only for QwtPickerMachine::PolygonSelection ) PolygonRubberBand, /*! Values >= UserRubberBand can be used to define additional rubber bands. */ UserRubberBand = 100 }; /*! \brief Display mode \sa setTrackerMode(), trackerMode(), isActive() */ enum DisplayMode { //! Display never AlwaysOff, //! Display always AlwaysOn, //! Display only when the selection is active ActiveOnly }; /*! Controls what to do with the selected points of an active selection when the observed widget is resized. The default value is QwtPicker::Stretch. \sa setResizeMode() */ enum ResizeMode { //! All points are scaled according to the new size, Stretch, //! All points remain unchanged. KeepSize }; explicit QwtPicker( QWidget *parent ); explicit QwtPicker( RubberBand rubberBand, DisplayMode trackerMode, QWidget * ); virtual ~QwtPicker(); void setStateMachine( QwtPickerMachine * ); const QwtPickerMachine *stateMachine() const; QwtPickerMachine *stateMachine(); void setRubberBand( RubberBand ); RubberBand rubberBand() const; void setTrackerMode( DisplayMode ); DisplayMode trackerMode() const; void setResizeMode( ResizeMode ); ResizeMode resizeMode() const; void setRubberBandPen( const QPen & ); QPen rubberBandPen() const; void setTrackerPen( const QPen & ); QPen trackerPen() const; void setTrackerFont( const QFont & ); QFont trackerFont() const; bool isEnabled() const; bool isActive() const; virtual bool eventFilter( QObject *, QEvent * ); QWidget *parentWidget(); const QWidget *parentWidget() const; virtual QPainterPath pickArea() const; virtual void drawRubberBand( QPainter * ) const; virtual void drawTracker( QPainter * ) const; virtual QRegion rubberBandMask() const; virtual QwtText trackerText( const QPoint &pos ) const; QPoint trackerPosition() const; virtual QRect trackerRect( const QFont & ) const; QPolygon selection() const; public Q_SLOTS: void setEnabled( bool ); Q_SIGNALS: /*! A signal indicating, when the picker has been activated. Together with setEnabled() it can be used to implement selections with more than one picker. \param on True, when the picker has been activated */ void activated( bool on ); /*! A signal emitting the selected points, at the end of a selection. \param polygon Selected points */ void selected( const QPolygon &polygon ); /*! A signal emitted when a point has been appended to the selection \param pos Position of the appended point. \sa append(). moved() */ void appended( const QPoint &pos ); /*! A signal emitted whenever the last appended point of the selection has been moved. \param pos Position of the moved last point of the selection. \sa move(), appended() */ void moved( const QPoint &pos ); /*! A signal emitted whenever the last appended point of the selection has been removed. \param pos Position of the point, that has been removed \sa remove(), appended() */ void removed( const QPoint &pos ); /*! A signal emitted when the active selection has been changed. This might happen when the observed widget is resized. \param selection Changed selection \sa stretchSelection() */ void changed( const QPolygon &selection ); protected: virtual QPolygon adjustedPoints( const QPolygon & ) const; virtual void transition( const QEvent * ); virtual void begin(); virtual void append( const QPoint & ); virtual void move( const QPoint & ); virtual void remove(); virtual bool end( bool ok = true ); virtual bool accept( QPolygon & ) const; virtual void reset(); virtual void widgetMousePressEvent( QMouseEvent * ); virtual void widgetMouseReleaseEvent( QMouseEvent * ); virtual void widgetMouseDoubleClickEvent( QMouseEvent * ); virtual void widgetMouseMoveEvent( QMouseEvent * ); virtual void widgetWheelEvent( QWheelEvent * ); virtual void widgetKeyPressEvent( QKeyEvent * ); virtual void widgetKeyReleaseEvent( QKeyEvent * ); virtual void widgetEnterEvent( QEvent * ); virtual void widgetLeaveEvent( QEvent * ); virtual void stretchSelection( const QSize &oldSize, const QSize &newSize ); virtual void updateDisplay(); const QwtWidgetOverlay *rubberBandOverlay() const; const QwtWidgetOverlay *trackerOverlay() const; const QPolygon &pickedPoints() const; private: void init( QWidget *, RubberBand rubberBand, DisplayMode trackerMode ); void setMouseTracking( bool ); class PrivateData; PrivateData *d_data; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_picker_machine.cpp000066400000000000000000000333731360521144700235460ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_picker_machine.h" #include "qwt_event_pattern.h" #include //! Constructor QwtPickerMachine::QwtPickerMachine( SelectionType type ): d_selectionType( type ), d_state( 0 ) { } //! Destructor QwtPickerMachine::~QwtPickerMachine() { } //! Return the selection type QwtPickerMachine::SelectionType QwtPickerMachine::selectionType() const { return d_selectionType; } //! Return the current state int QwtPickerMachine::state() const { return d_state; } //! Change the current state void QwtPickerMachine::setState( int state ) { d_state = state; } //! Set the current state to 0. void QwtPickerMachine::reset() { setState( 0 ); } //! Constructor QwtPickerTrackerMachine::QwtPickerTrackerMachine(): QwtPickerMachine( NoSelection ) { } //! Transition QList QwtPickerTrackerMachine::transition( const QwtEventPattern &, const QEvent *e ) { QList cmdList; switch ( e->type() ) { case QEvent::Enter: case QEvent::MouseMove: { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; setState( 1 ); } else { cmdList += Move; } break; } case QEvent::Leave: { cmdList += Remove; cmdList += End; setState( 0 ); } break; default: break; } return cmdList; } //! Constructor QwtPickerClickPointMachine::QwtPickerClickPointMachine(): QwtPickerMachine( PointSelection ) { } //! Transition QList QwtPickerClickPointMachine::transition( const QwtEventPattern &eventPattern, const QEvent *event ) { QList cmdList; switch ( event->type() ) { case QEvent::MouseButtonPress: { if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1, static_cast( event ) ) ) { cmdList += Begin; cmdList += Append; cmdList += End; } break; } case QEvent::KeyPress: { const QKeyEvent *keyEvent = static_cast ( event ); if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, keyEvent ) ) { if ( !keyEvent->isAutoRepeat() ) { cmdList += Begin; cmdList += Append; cmdList += End; } } break; } default: break; } return cmdList; } //! Constructor QwtPickerDragPointMachine::QwtPickerDragPointMachine(): QwtPickerMachine( PointSelection ) { } //! Transition QList QwtPickerDragPointMachine::transition( const QwtEventPattern &eventPattern, const QEvent *event ) { QList cmdList; switch ( event->type() ) { case QEvent::MouseButtonPress: { if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1, static_cast( event ) ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; setState( 1 ); } } break; } case QEvent::MouseMove: case QEvent::Wheel: { if ( state() != 0 ) cmdList += Move; break; } case QEvent::MouseButtonRelease: { if ( state() != 0 ) { cmdList += End; setState( 0 ); } break; } case QEvent::KeyPress: { const QKeyEvent *keyEvent = static_cast ( event ); if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, keyEvent ) ) { if ( !keyEvent->isAutoRepeat() ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; setState( 1 ); } else { cmdList += End; setState( 0 ); } } } break; } default: break; } return cmdList; } //! Constructor QwtPickerClickRectMachine::QwtPickerClickRectMachine(): QwtPickerMachine( RectSelection ) { } //! Transition QList QwtPickerClickRectMachine::transition( const QwtEventPattern &eventPattern, const QEvent *event ) { QList cmdList; switch ( event->type() ) { case QEvent::MouseButtonPress: { if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1, static_cast( event ) ) ) { switch ( state() ) { case 0: { cmdList += Begin; cmdList += Append; setState( 1 ); break; } case 1: { // Uh, strange we missed the MouseButtonRelease break; } default: { cmdList += End; setState( 0 ); } } } break; } case QEvent::MouseMove: case QEvent::Wheel: { if ( state() != 0 ) cmdList += Move; break; } case QEvent::MouseButtonRelease: { if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1, static_cast( event ) ) ) { if ( state() == 1 ) { cmdList += Append; setState( 2 ); } } break; } case QEvent::KeyPress: { const QKeyEvent *keyEvent = static_cast ( event ); if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, keyEvent ) ) { if ( !keyEvent->isAutoRepeat() ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; setState( 1 ); } else { if ( state() == 1 ) { cmdList += Append; setState( 2 ); } else if ( state() == 2 ) { cmdList += End; setState( 0 ); } } } } break; } default: break; } return cmdList; } //! Constructor QwtPickerDragRectMachine::QwtPickerDragRectMachine(): QwtPickerMachine( RectSelection ) { } //! Transition QList QwtPickerDragRectMachine::transition( const QwtEventPattern &eventPattern, const QEvent *event ) { QList cmdList; switch ( event->type() ) { case QEvent::MouseButtonPress: { if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1, static_cast( event ) ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; cmdList += Append; setState( 2 ); } } break; } case QEvent::MouseMove: case QEvent::Wheel: { if ( state() != 0 ) cmdList += Move; break; } case QEvent::MouseButtonRelease: { if ( state() == 2 ) { cmdList += End; setState( 0 ); } break; } case QEvent::KeyPress: { if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, static_cast ( event ) ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; cmdList += Append; setState( 2 ); } else { cmdList += End; setState( 0 ); } } break; } default: break; } return cmdList; } //! Constructor QwtPickerPolygonMachine::QwtPickerPolygonMachine(): QwtPickerMachine( PolygonSelection ) { } //! Transition QList QwtPickerPolygonMachine::transition( const QwtEventPattern &eventPattern, const QEvent *event ) { QList cmdList; switch ( event->type() ) { case QEvent::MouseButtonPress: { if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1, static_cast( event ) ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; cmdList += Append; setState( 1 ); } else { cmdList += Append; } } if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect2, static_cast( event ) ) ) { if ( state() == 1 ) { cmdList += End; setState( 0 ); } } break; } case QEvent::MouseMove: case QEvent::Wheel: { if ( state() != 0 ) cmdList += Move; break; } case QEvent::KeyPress: { const QKeyEvent *keyEvent = static_cast ( event ); if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, keyEvent ) ) { if ( !keyEvent->isAutoRepeat() ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; cmdList += Append; setState( 1 ); } else { cmdList += Append; } } } else if ( eventPattern.keyMatch( QwtEventPattern::KeySelect2, keyEvent ) ) { if ( !keyEvent->isAutoRepeat() ) { if ( state() == 1 ) { cmdList += End; setState( 0 ); } } } break; } default: break; } return cmdList; } //! Constructor QwtPickerDragLineMachine::QwtPickerDragLineMachine(): QwtPickerMachine( PolygonSelection ) { } //! Transition QList QwtPickerDragLineMachine::transition( const QwtEventPattern &eventPattern, const QEvent *event ) { QList cmdList; switch( event->type() ) { case QEvent::MouseButtonPress: { if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1, static_cast( event ) ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; cmdList += Append; setState( 1 ); } } break; } case QEvent::KeyPress: { if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, static_cast ( event ) ) ) { if ( state() == 0 ) { cmdList += Begin; cmdList += Append; cmdList += Append; setState( 1 ); } else { cmdList += End; setState( 0 ); } } break; } case QEvent::MouseMove: case QEvent::Wheel: { if ( state() != 0 ) cmdList += Move; break; } case QEvent::MouseButtonRelease: { if ( state() != 0 ) { cmdList += End; setState( 0 ); } break; } default: break; } return cmdList; } connectome-workbench-1.4.2/src/Qwt/qwt_picker_machine.h000066400000000000000000000131361360521144700232060ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PICKER_MACHINE #define QWT_PICKER_MACHINE 1 #include "qwt_global.h" #include class QEvent; class QwtEventPattern; /*! \brief A state machine for QwtPicker selections QwtPickerMachine accepts key and mouse events and translates them into selection commands. \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode */ class QWT_EXPORT QwtPickerMachine { public: /*! Type of a selection. \sa selectionType() */ enum SelectionType { //! The state machine not usable for any type of selection. NoSelection = -1, //! The state machine is for selecting a single point. PointSelection, //! The state machine is for selecting a rectangle (2 points). RectSelection, //! The state machine is for selecting a polygon (many points). PolygonSelection }; //! Commands - the output of a state machine enum Command { Begin, Append, Move, Remove, End }; QwtPickerMachine( SelectionType ); virtual ~QwtPickerMachine(); //! Transition virtual QList transition( const QwtEventPattern &, const QEvent * ) = 0; void reset(); int state() const; void setState( int ); SelectionType selectionType() const; private: const SelectionType d_selectionType; int d_state; }; /*! \brief A state machine for indicating mouse movements QwtPickerTrackerMachine supports displaying information corresponding to mouse movements, but is not intended for selecting anything. Begin/End are related to Enter/Leave events. */ class QWT_EXPORT QwtPickerTrackerMachine: public QwtPickerMachine { public: QwtPickerTrackerMachine(); virtual QList transition( const QwtEventPattern &, const QEvent * ); }; /*! \brief A state machine for point selections Pressing QwtEventPattern::MouseSelect1 or QwtEventPattern::KeySelect1 selects a point. \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode */ class QWT_EXPORT QwtPickerClickPointMachine: public QwtPickerMachine { public: QwtPickerClickPointMachine(); virtual QList transition( const QwtEventPattern &, const QEvent * ); }; /*! \brief A state machine for point selections Pressing QwtEventPattern::MouseSelect1 or QwtEventPattern::KeySelect1 starts the selection, releasing QwtEventPattern::MouseSelect1 or a second press of QwtEventPattern::KeySelect1 terminates it. */ class QWT_EXPORT QwtPickerDragPointMachine: public QwtPickerMachine { public: QwtPickerDragPointMachine(); virtual QList transition( const QwtEventPattern &, const QEvent * ); }; /*! \brief A state machine for rectangle selections Pressing QwtEventPattern::MouseSelect1 starts the selection, releasing it selects the first point. Pressing it again selects the second point and terminates the selection. Pressing QwtEventPattern::KeySelect1 also starts the selection, a second press selects the first point. A third one selects the second point and terminates the selection. \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode */ class QWT_EXPORT QwtPickerClickRectMachine: public QwtPickerMachine { public: QwtPickerClickRectMachine(); virtual QList transition( const QwtEventPattern &, const QEvent * ); }; /*! \brief A state machine for rectangle selections Pressing QwtEventPattern::MouseSelect1 selects the first point, releasing it the second point. Pressing QwtEventPattern::KeySelect1 also selects the first point, a second press selects the second point and terminates the selection. \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode */ class QWT_EXPORT QwtPickerDragRectMachine: public QwtPickerMachine { public: QwtPickerDragRectMachine(); virtual QList transition( const QwtEventPattern &, const QEvent * ); }; /*! \brief A state machine for line selections Pressing QwtEventPattern::MouseSelect1 selects the first point, releasing it the second point. Pressing QwtEventPattern::KeySelect1 also selects the first point, a second press selects the second point and terminates the selection. A common use case of QwtPickerDragLineMachine are pickers for distance measurements. \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode */ class QWT_EXPORT QwtPickerDragLineMachine: public QwtPickerMachine { public: QwtPickerDragLineMachine(); virtual QList transition( const QwtEventPattern &, const QEvent * ); }; /*! \brief A state machine for polygon selections Pressing QwtEventPattern::MouseSelect1 or QwtEventPattern::KeySelect1 starts the selection and selects the first point, or appends a point. Pressing QwtEventPattern::MouseSelect2 or QwtEventPattern::KeySelect2 appends the last point and terminates the selection. \sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode */ class QWT_EXPORT QwtPickerPolygonMachine: public QwtPickerMachine { public: QwtPickerPolygonMachine(); virtual QList transition( const QwtEventPattern &, const QEvent * ); }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_pixel_matrix.cpp000066400000000000000000000021331360521144700233000ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_pixel_matrix.h" /*! \brief Constructor \param rect Bounding rectangle for the matrix */ QwtPixelMatrix::QwtPixelMatrix( const QRect& rect ): QBitArray( qMax( rect.width() * rect.height(), 0 ) ), d_rect( rect ) { } //! Destructor QwtPixelMatrix::~QwtPixelMatrix() { } /*! Set the bounding rectangle of the matrix \param rect Bounding rectangle \note All bits are cleared */ void QwtPixelMatrix::setRect( const QRect& rect ) { if ( rect != d_rect ) { d_rect = rect; const int sz = qMax( rect.width() * rect.height(), 0 ); resize( sz ); } fill( false ); } //! \return Bounding rectangle QRect QwtPixelMatrix::rect() const { return d_rect; } connectome-workbench-1.4.2/src/Qwt/qwt_pixel_matrix.h000066400000000000000000000044311360521144700227500ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PIXEL_MATRIX_H #define QWT_PIXEL_MATRIX_H #include "qwt_global.h" #include #include /*! \brief A bit field corresponding to the pixels of a rectangle QwtPixelMatrix is intended to filter out duplicates in an unsorted array of points. */ class QWT_EXPORT QwtPixelMatrix: public QBitArray { public: QwtPixelMatrix( const QRect& rect ); ~QwtPixelMatrix(); void setRect( const QRect& rect ); QRect rect() const; bool testPixel( int x, int y ) const; bool testAndSetPixel( int x, int y, bool on ); int index( int x, int y ) const; private: QRect d_rect; }; /*! \brief Test if a pixel has been set \param x X-coordinate \param y Y-coordinate \return true, when pos is outside of rect(), or when the pixel has already been set. */ inline bool QwtPixelMatrix::testPixel( int x, int y ) const { const int idx = index( x, y ); return ( idx >= 0 ) ? testBit( idx ) : true; } /*! \brief Set a pixel and test if a pixel has been set before \param x X-coordinate \param y Y-coordinate \param on Set/Clear the pixel \return true, when pos is outside of rect(), or when the pixel was set before. */ inline bool QwtPixelMatrix::testAndSetPixel( int x, int y, bool on ) { const int idx = index( x, y ); if ( idx < 0 ) return true; const bool onBefore = testBit( idx ); setBit( idx, on ); return onBefore; } /*! \brief Calculate the index in the bit field corresponding to a position \param x X-coordinate \param y Y-coordinate \return Index, when rect() contains pos - otherwise -1. */ inline int QwtPixelMatrix::index( int x, int y ) const { const int dx = x - d_rect.x(); if ( dx < 0 || dx >= d_rect.width() ) return -1; const int dy = y - d_rect.y(); if ( dy < 0 || dy >= d_rect.height() ) return -1; return dy * d_rect.width() + dx; } #endif connectome-workbench-1.4.2/src/Qwt/qwt_plot.cpp000066400000000000000000000746731360521144700215730ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot.h" #include "qwt_plot_dict.h" #include "qwt_plot_layout.h" #include "qwt_scale_widget.h" #include "qwt_scale_engine.h" #include "qwt_text_label.h" #include "qwt_legend.h" #include "qwt_legend_data.h" #include "qwt_plot_canvas.h" #include #include #include #include #include #include static inline void qwtEnableLegendItems( QwtPlot *plot, bool on ) { if ( on ) { QObject::connect( plot, SIGNAL( legendDataChanged( const QVariant &, const QList & ) ), plot, SLOT( updateLegendItems( const QVariant &, const QList & ) ) ); } else { QObject::disconnect( plot, SIGNAL( legendDataChanged( const QVariant &, const QList & ) ), plot, SLOT( updateLegendItems( const QVariant &, const QList & ) ) ); } } static void qwtSetTabOrder( QWidget *first, QWidget *second, bool withChildren ) { QList tabChain; tabChain += first; tabChain += second; if ( withChildren ) { QList children = second->findChildren(); QWidget *w = second->nextInFocusChain(); while ( children.contains( w ) ) { children.removeAll( w ); tabChain += w; w = w->nextInFocusChain(); } } for ( int i = 0; i < tabChain.size() - 1; i++ ) { QWidget *from = tabChain[i]; QWidget *to = tabChain[i+1]; const Qt::FocusPolicy policy1 = from->focusPolicy(); const Qt::FocusPolicy policy2 = to->focusPolicy(); QWidget *proxy1 = from->focusProxy(); QWidget *proxy2 = to->focusProxy(); from->setFocusPolicy( Qt::TabFocus ); from->setFocusProxy( NULL); to->setFocusPolicy( Qt::TabFocus ); to->setFocusProxy( NULL); QWidget::setTabOrder( from, to ); from->setFocusPolicy( policy1 ); from->setFocusProxy( proxy1); to->setFocusPolicy( policy2 ); to->setFocusProxy( proxy2 ); } } class QwtPlot::PrivateData { public: QPointer titleLabel; QPointer footerLabel; QPointer canvas; QPointer legend; QwtPlotLayout *layout; bool autoReplot; }; /*! \brief Constructor \param parent Parent widget */ QwtPlot::QwtPlot( QWidget *parent ): QFrame( parent ) { initPlot( QwtText() ); } /*! \brief Constructor \param title Title text \param parent Parent widget */ QwtPlot::QwtPlot( const QwtText &title, QWidget *parent ): QFrame( parent ) { initPlot( title ); } //! Destructor QwtPlot::~QwtPlot() { setAutoReplot( false ); detachItems( QwtPlotItem::Rtti_PlotItem, autoDelete() ); delete d_data->layout; deleteAxesData(); delete d_data; } /*! \brief Initializes a QwtPlot instance \param title Title text */ void QwtPlot::initPlot( const QwtText &title ) { d_data = new PrivateData; d_data->layout = new QwtPlotLayout; d_data->autoReplot = false; // title d_data->titleLabel = new QwtTextLabel( this ); d_data->titleLabel->setObjectName( "QwtPlotTitle" ); d_data->titleLabel->setFont( QFont( fontInfo().family(), 14, QFont::Bold ) ); QwtText text( title ); text.setRenderFlags( Qt::AlignCenter | Qt::TextWordWrap ); d_data->titleLabel->setText( text ); // footer d_data->footerLabel = new QwtTextLabel( this ); d_data->footerLabel->setObjectName( "QwtPlotFooter" ); QwtText footer; footer.setRenderFlags( Qt::AlignCenter | Qt::TextWordWrap ); d_data->footerLabel->setText( footer ); // legend d_data->legend = NULL; // axis initAxesData(); // canvas d_data->canvas = new QwtPlotCanvas( this ); d_data->canvas->setObjectName( "QwtPlotCanvas" ); d_data->canvas->installEventFilter( this ); setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding ); resize( 200, 200 ); QList focusChain; focusChain << this << d_data->titleLabel << axisWidget( xTop ) << axisWidget( yLeft ) << d_data->canvas << axisWidget( yRight ) << axisWidget( xBottom ) << d_data->footerLabel; for ( int i = 0; i < focusChain.size() - 1; i++ ) qwtSetTabOrder( focusChain[i], focusChain[i+1], false ); qwtEnableLegendItems( this, true ); } /*! \brief Set the drawing canvas of the plot widget QwtPlot invokes methods of the canvas as meta methods ( see QMetaObject ). In opposite to using conventional C++ techniques like virtual methods they allow to use canvas implementations that are derived from QWidget or QGLWidget. The following meta methods could be implemented: - replot() When the canvas doesn't offer a replot method, QwtPlot calls update() instead. - borderPath() The border path is necessary to clip the content of the canvas When the canvas doesn't have any special border ( f.e rounded corners ) it is o.k. not to implement this method. The default canvas is a QwtPlotCanvas \param canvas Canvas Widget \sa canvas() */ void QwtPlot::setCanvas( QWidget *canvas ) { if ( canvas == d_data->canvas ) return; delete d_data->canvas; d_data->canvas = canvas; if ( canvas ) { canvas->setParent( this ); canvas->installEventFilter( this ); if ( isVisible() ) canvas->show(); } } /*! \brief Adds handling of layout requests \param event Event \return See QFrame::event() */ bool QwtPlot::event( QEvent *event ) { bool ok = QFrame::event( event ); switch ( event->type() ) { case QEvent::LayoutRequest: updateLayout(); break; case QEvent::PolishRequest: replot(); break; default:; } return ok; } /*! \brief Event filter The plot handles the following events for the canvas: - QEvent::Resize The canvas margins might depend on its size - QEvent::ContentsRectChange The layout needs to be recalculated \param object Object to be filtered \param event Event \return See QFrame::eventFilter() \sa updateCanvasMargins(), updateLayout() */ bool QwtPlot::eventFilter( QObject *object, QEvent *event ) { if ( object == d_data->canvas ) { if ( event->type() == QEvent::Resize ) { updateCanvasMargins(); } else if ( event->type() == QEvent::ContentsRectChange ) { updateLayout(); } } return QFrame::eventFilter( object, event ); } //! Replots the plot if autoReplot() is \c true. void QwtPlot::autoRefresh() { if ( d_data->autoReplot ) replot(); } /*! \brief Set or reset the autoReplot option If the autoReplot option is set, the plot will be updated implicitly by manipulating member functions. Since this may be time-consuming, it is recommended to leave this option switched off and call replot() explicitly if necessary. The autoReplot option is set to false by default, which means that the user has to call replot() in order to make changes visible. \param tf \c true or \c false. Defaults to \c true. \sa replot() */ void QwtPlot::setAutoReplot( bool tf ) { d_data->autoReplot = tf; } /*! \return true if the autoReplot option is set. \sa setAutoReplot() */ bool QwtPlot::autoReplot() const { return d_data->autoReplot; } /*! Change the plot's title \param title New title */ void QwtPlot::setTitle( const QString &title ) { if ( title != d_data->titleLabel->text().text() ) { d_data->titleLabel->setText( title ); updateLayout(); } } /*! Change the plot's title \param title New title */ void QwtPlot::setTitle( const QwtText &title ) { if ( title != d_data->titleLabel->text() ) { d_data->titleLabel->setText( title ); updateLayout(); } } //! \return Title of the plot QwtText QwtPlot::title() const { return d_data->titleLabel->text(); } //! \return Title label widget. QwtTextLabel *QwtPlot::titleLabel() { return d_data->titleLabel; } //! \return Title label widget. const QwtTextLabel *QwtPlot::titleLabel() const { return d_data->titleLabel; } /*! Change the text the footer \param text New text of the footer */ void QwtPlot::setFooter( const QString &text ) { if ( text != d_data->footerLabel->text().text() ) { d_data->footerLabel->setText( text ); updateLayout(); } } /*! Change the text the footer \param text New text of the footer */ void QwtPlot::setFooter( const QwtText &text ) { if ( text != d_data->footerLabel->text() ) { d_data->footerLabel->setText( text ); updateLayout(); } } //! \return Text of the footer QwtText QwtPlot::footer() const { return d_data->footerLabel->text(); } //! \return Footer label widget. QwtTextLabel *QwtPlot::footerLabel() { return d_data->footerLabel; } //! \return Footer label widget. const QwtTextLabel *QwtPlot::footerLabel() const { return d_data->footerLabel; } /*! \brief Assign a new plot layout \param layout Layout() \sa plotLayout() */ void QwtPlot::setPlotLayout( QwtPlotLayout *layout ) { if ( layout != d_data->layout ) { delete d_data->layout; d_data->layout = layout; updateLayout(); } } //! \return the plot's layout QwtPlotLayout *QwtPlot::plotLayout() { return d_data->layout; } //! \return the plot's layout const QwtPlotLayout *QwtPlot::plotLayout() const { return d_data->layout; } /*! \return the plot's legend \sa insertLegend() */ QwtAbstractLegend *QwtPlot::legend() { return d_data->legend; } /*! \return the plot's legend \sa insertLegend() */ const QwtAbstractLegend *QwtPlot::legend() const { return d_data->legend; } /*! \return the plot's canvas */ QWidget *QwtPlot::canvas() { return d_data->canvas; } /*! \return the plot's canvas */ const QWidget *QwtPlot::canvas() const { return d_data->canvas; } /*! \return Size hint for the plot widget \sa minimumSizeHint() */ QSize QwtPlot::sizeHint() const { int dw = 0; int dh = 0; for ( int axisId = 0; axisId < axisCnt; axisId++ ) { if ( axisEnabled( axisId ) ) { const int niceDist = 40; const QwtScaleWidget *scaleWidget = axisWidget( axisId ); const QwtScaleDiv &scaleDiv = scaleWidget->scaleDraw()->scaleDiv(); const int majCnt = scaleDiv.ticks( QwtScaleDiv::MajorTick ).count(); if ( axisId == yLeft || axisId == yRight ) { int hDiff = ( majCnt - 1 ) * niceDist - scaleWidget->minimumSizeHint().height(); if ( hDiff > dh ) dh = hDiff; } else { int wDiff = ( majCnt - 1 ) * niceDist - scaleWidget->minimumSizeHint().width(); if ( wDiff > dw ) dw = wDiff; } } } return minimumSizeHint() + QSize( dw, dh ); } /*! \brief Return a minimum size hint */ QSize QwtPlot::minimumSizeHint() const { QSize hint = d_data->layout->minimumSizeHint( this ); hint += QSize( 2 * frameWidth(), 2 * frameWidth() ); return hint; } /*! Resize and update internal layout \param e Resize event */ void QwtPlot::resizeEvent( QResizeEvent *e ) { QFrame::resizeEvent( e ); updateLayout(); } /*! \brief Redraw the plot If the autoReplot option is not set (which is the default) or if any curves are attached to raw data, the plot has to be refreshed explicitly in order to make changes visible. \sa updateAxes(), setAutoReplot() */ void QwtPlot::replot() { bool doAutoReplot = autoReplot(); setAutoReplot( false ); updateAxes(); /* Maybe the layout needs to be updated, because of changed axes labels. We need to process them here before painting to avoid that scales and canvas get out of sync. */ QApplication::sendPostedEvents( this, QEvent::LayoutRequest ); if ( d_data->canvas ) { const bool ok = QMetaObject::invokeMethod( d_data->canvas, "replot", Qt::DirectConnection ); if ( !ok ) { // fallback, when canvas has no a replot method d_data->canvas->update( d_data->canvas->contentsRect() ); } } setAutoReplot( doAutoReplot ); } /*! \brief Adjust plot content to its current size. \sa resizeEvent() */ void QwtPlot::updateLayout() { d_data->layout->activate( this, contentsRect() ); QRect titleRect = d_data->layout->titleRect().toRect(); QRect footerRect = d_data->layout->footerRect().toRect(); QRect scaleRect[QwtPlot::axisCnt]; for ( int axisId = 0; axisId < axisCnt; axisId++ ) scaleRect[axisId] = d_data->layout->scaleRect( axisId ).toRect(); QRect legendRect = d_data->layout->legendRect().toRect(); QRect canvasRect = d_data->layout->canvasRect().toRect(); // resize and show the visible widgets if ( !d_data->titleLabel->text().isEmpty() ) { d_data->titleLabel->setGeometry( titleRect ); if ( !d_data->titleLabel->isVisibleTo( this ) ) d_data->titleLabel->show(); } else d_data->titleLabel->hide(); if ( !d_data->footerLabel->text().isEmpty() ) { d_data->footerLabel->setGeometry( footerRect ); if ( !d_data->footerLabel->isVisibleTo( this ) ) d_data->footerLabel->show(); } else d_data->footerLabel->hide(); for ( int axisId = 0; axisId < axisCnt; axisId++ ) { if ( axisEnabled( axisId ) ) { axisWidget( axisId )->setGeometry( scaleRect[axisId] ); #if 1 if ( axisId == xBottom || axisId == xTop ) { // do we need this code any longer ??? QRegion r( scaleRect[axisId] ); if ( axisEnabled( yLeft ) ) r = r.subtracted( QRegion( scaleRect[yLeft] ) ); if ( axisEnabled( yRight ) ) r = r.subtracted( QRegion( scaleRect[yRight] ) ); r.translate( -scaleRect[ axisId ].x(), -scaleRect[axisId].y() ); axisWidget( axisId )->setMask( r ); } #endif if ( !axisWidget( axisId )->isVisibleTo( this ) ) axisWidget( axisId )->show(); } else axisWidget( axisId )->hide(); } if ( d_data->legend ) { if ( d_data->legend->isEmpty() ) { d_data->legend->hide(); } else { d_data->legend->setGeometry( legendRect ); d_data->legend->show(); } } d_data->canvas->setGeometry( canvasRect ); } /*! \brief Calculate the canvas margins \param maps QwtPlot::axisCnt maps, mapping between plot and paint device coordinates \param canvasRect Bounding rectangle where to paint \param left Return parameter for the left margin \param top Return parameter for the top margin \param right Return parameter for the right margin \param bottom Return parameter for the bottom margin Plot items might indicate, that they need some extra space at the borders of the canvas by the QwtPlotItem::Margins flag. updateCanvasMargins(), QwtPlotItem::getCanvasMarginHint() */ void QwtPlot::getCanvasMarginsHint( const QwtScaleMap maps[], const QRectF &canvasRect, double &left, double &top, double &right, double &bottom) const { left = top = right = bottom = -1.0; const QwtPlotItemList& itmList = itemList(); for ( QwtPlotItemIterator it = itmList.begin(); it != itmList.end(); ++it ) { const QwtPlotItem *item = *it; if ( item->testItemAttribute( QwtPlotItem::Margins ) ) { double m[ QwtPlot::axisCnt ]; item->getCanvasMarginHint( maps[ item->xAxis() ], maps[ item->yAxis() ], canvasRect, m[yLeft], m[xTop], m[yRight], m[xBottom] ); left = qMax( left, m[yLeft] ); top = qMax( top, m[xTop] ); right = qMax( right, m[yRight] ); bottom = qMax( bottom, m[xBottom] ); } } } /*! \brief Update the canvas margins Plot items might indicate, that they need some extra space at the borders of the canvas by the QwtPlotItem::Margins flag. getCanvasMarginsHint(), QwtPlotItem::getCanvasMarginHint() */ void QwtPlot::updateCanvasMargins() { QwtScaleMap maps[axisCnt]; for ( int axisId = 0; axisId < axisCnt; axisId++ ) maps[axisId] = canvasMap( axisId ); double margins[axisCnt]; getCanvasMarginsHint( maps, canvas()->contentsRect(), margins[yLeft], margins[xTop], margins[yRight], margins[xBottom] ); bool doUpdate = false; for ( int axisId = 0; axisId < axisCnt; axisId++ ) { if ( margins[axisId] >= 0.0 ) { const int m = qCeil( margins[axisId] ); plotLayout()->setCanvasMargin( m, axisId); doUpdate = true; } } if ( doUpdate ) updateLayout(); } /*! Redraw the canvas. \param painter Painter used for drawing \warning drawCanvas calls drawItems what is also used for printing. Applications that like to add individual plot items better overload drawItems() \sa drawItems() */ void QwtPlot::drawCanvas( QPainter *painter ) { QwtScaleMap maps[axisCnt]; for ( int axisId = 0; axisId < axisCnt; axisId++ ) maps[axisId] = canvasMap( axisId ); drawItems( painter, d_data->canvas->contentsRect(), maps ); } /*! Redraw the canvas items. \param painter Painter used for drawing \param canvasRect Bounding rectangle where to paint \param maps QwtPlot::axisCnt maps, mapping between plot and paint device coordinates \note Usually canvasRect is contentsRect() of the plot canvas. Due to a bug in Qt this rectangle might be wrong for certain frame styles ( f.e QFrame::Box ) and it might be necessary to fix the margins manually using QWidget::setContentsMargins() */ void QwtPlot::drawItems( QPainter *painter, const QRectF &canvasRect, const QwtScaleMap maps[axisCnt] ) const { const QwtPlotItemList& itmList = itemList(); for ( QwtPlotItemIterator it = itmList.begin(); it != itmList.end(); ++it ) { QwtPlotItem *item = *it; if ( item && item->isVisible() ) { painter->save(); painter->setRenderHint( QPainter::Antialiasing, item->testRenderHint( QwtPlotItem::RenderAntialiased ) ); painter->setRenderHint( QPainter::HighQualityAntialiasing, item->testRenderHint( QwtPlotItem::RenderAntialiased ) ); item->draw( painter, maps[item->xAxis()], maps[item->yAxis()], canvasRect ); painter->restore(); } } } /*! \param axisId Axis \return Map for the axis on the canvas. With this map pixel coordinates can translated to plot coordinates and vice versa. \sa QwtScaleMap, transform(), invTransform() */ QwtScaleMap QwtPlot::canvasMap( int axisId ) const { QwtScaleMap map; if ( !d_data->canvas ) return map; map.setTransformation( axisScaleEngine( axisId )->transformation() ); const QwtScaleDiv &sd = axisScaleDiv( axisId ); map.setScaleInterval( sd.lowerBound(), sd.upperBound() ); if ( axisEnabled( axisId ) ) { const QwtScaleWidget *s = axisWidget( axisId ); if ( axisId == yLeft || axisId == yRight ) { double y = s->y() + s->startBorderDist() - d_data->canvas->y(); double h = s->height() - s->startBorderDist() - s->endBorderDist(); map.setPaintInterval( y + h, y ); } else { double x = s->x() + s->startBorderDist() - d_data->canvas->x(); double w = s->width() - s->startBorderDist() - s->endBorderDist(); map.setPaintInterval( x, x + w ); } } else { const QRect &canvasRect = d_data->canvas->contentsRect(); if ( axisId == yLeft || axisId == yRight ) { int top = 0; if ( !plotLayout()->alignCanvasToScale( xTop ) ) top = plotLayout()->canvasMargin( xTop ); int bottom = 0; if ( !plotLayout()->alignCanvasToScale( xBottom ) ) bottom = plotLayout()->canvasMargin( xBottom ); map.setPaintInterval( canvasRect.bottom() - bottom, canvasRect.top() + top ); } else { int left = 0; if ( !plotLayout()->alignCanvasToScale( yLeft ) ) left = plotLayout()->canvasMargin( yLeft ); int right = 0; if ( !plotLayout()->alignCanvasToScale( yRight ) ) right = plotLayout()->canvasMargin( yRight ); map.setPaintInterval( canvasRect.left() + left, canvasRect.right() - right ); } } return map; } /*! \brief Change the background of the plotting area Sets brush to QPalette::Window of all color groups of the palette of the canvas. Using canvas()->setPalette() is a more powerful way to set these colors. \param brush New background brush \sa canvasBackground() */ void QwtPlot::setCanvasBackground( const QBrush &brush ) { QPalette pal = d_data->canvas->palette(); pal.setBrush( QPalette::Window, brush ); canvas()->setPalette( pal ); } /*! Nothing else than: canvas()->palette().brush( QPalette::Normal, QPalette::Window); \return Background brush of the plotting area. \sa setCanvasBackground() */ QBrush QwtPlot::canvasBackground() const { return canvas()->palette().brush( QPalette::Normal, QPalette::Window ); } /*! \return \c true if the specified axis exists, otherwise \c false \param axisId axis index */ bool QwtPlot::axisValid( int axisId ) { return ( ( axisId >= QwtPlot::yLeft ) && ( axisId < QwtPlot::axisCnt ) ); } /*! \brief Insert a legend If the position legend is \c QwtPlot::LeftLegend or \c QwtPlot::RightLegend the legend will be organized in one column from top to down. Otherwise the legend items will be placed in a table with a best fit number of columns from left to right. insertLegend() will set the plot widget as parent for the legend. The legend will be deleted in the destructor of the plot or when another legend is inserted. Legends, that are not inserted into the layout of the plot widget need to connect to the legendDataChanged() signal. Calling updateLegend() initiates this signal for an initial update. When the application code wants to implement its own layout this also needs to be done for rendering plots to a document ( see QwtPlotRenderer ). \param legend Legend \param pos The legend's position. For top/left position the number of columns will be limited to 1, otherwise it will be set to unlimited. \param ratio Ratio between legend and the bounding rectangle of title, canvas and axes. The legend will be shrunk if it would need more space than the given ratio. The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0 it will be reset to the default ratio. The default vertical/horizontal ratio is 0.33/0.5. \sa legend(), QwtPlotLayout::legendPosition(), QwtPlotLayout::setLegendPosition() */ void QwtPlot::insertLegend( QwtAbstractLegend *legend, QwtPlot::LegendPosition pos, double ratio ) { d_data->layout->setLegendPosition( pos, ratio ); if ( legend != d_data->legend ) { if ( d_data->legend && d_data->legend->parent() == this ) delete d_data->legend; d_data->legend = legend; if ( d_data->legend ) { connect( this, SIGNAL( legendDataChanged( const QVariant &, const QList & ) ), d_data->legend, SLOT( updateLegend( const QVariant &, const QList & ) ) ); if ( d_data->legend->parent() != this ) d_data->legend->setParent( this ); qwtEnableLegendItems( this, false ); updateLegend(); qwtEnableLegendItems( this, true ); QwtLegend *lgd = qobject_cast( legend ); if ( lgd ) { switch ( d_data->layout->legendPosition() ) { case LeftLegend: case RightLegend: { if ( lgd->maxColumns() == 0 ) lgd->setMaxColumns( 1 ); // 1 column: align vertical break; } case TopLegend: case BottomLegend: { lgd->setMaxColumns( 0 ); // unlimited break; } default: break; } } QWidget *previousInChain = NULL; switch ( d_data->layout->legendPosition() ) { case LeftLegend: { previousInChain = axisWidget( QwtPlot::xTop ); break; } case TopLegend: { previousInChain = this; break; } case RightLegend: { previousInChain = axisWidget( QwtPlot::yRight ); break; } case BottomLegend: { previousInChain = footerLabel(); break; } } if ( previousInChain ) qwtSetTabOrder( previousInChain, legend, true ); } } updateLayout(); } /*! Emit legendDataChanged() for all plot item \sa QwtPlotItem::legendData(), legendDataChanged() */ void QwtPlot::updateLegend() { const QwtPlotItemList& itmList = itemList(); for ( QwtPlotItemIterator it = itmList.begin(); it != itmList.end(); ++it ) { updateLegend( *it ); } } /*! Emit legendDataChanged() for a plot item \param plotItem Plot item \sa QwtPlotItem::legendData(), legendDataChanged() */ void QwtPlot::updateLegend( const QwtPlotItem *plotItem ) { if ( plotItem == NULL ) return; QList legendData; if ( plotItem->testItemAttribute( QwtPlotItem::Legend ) ) legendData = plotItem->legendData(); const QVariant itemInfo = itemToInfo( const_cast< QwtPlotItem *>( plotItem) ); Q_EMIT legendDataChanged( itemInfo, legendData ); } /*! \brief Update all plot items interested in legend attributes Call QwtPlotItem::updateLegend(), when the QwtPlotItem::LegendInterest flag is set. \param itemInfo Info about the plot item \param legendData Entries to be displayed for the plot item ( usually 1 ) \sa QwtPlotItem::LegendInterest, QwtPlotLegendItem, QwtPlotItem::updateLegend() */ void QwtPlot::updateLegendItems( const QVariant &itemInfo, const QList &legendData ) { QwtPlotItem *plotItem = infoToItem( itemInfo ); if ( plotItem ) { const QwtPlotItemList& itmList = itemList(); for ( QwtPlotItemIterator it = itmList.begin(); it != itmList.end(); ++it ) { QwtPlotItem *item = *it; if ( item->testItemInterest( QwtPlotItem::LegendInterest ) ) item->updateLegend( plotItem, legendData ); } } } /*! \brief Attach/Detach a plot item \param plotItem Plot item \param on When true attach the item, otherwise detach it */ void QwtPlot::attachItem( QwtPlotItem *plotItem, bool on ) { if ( plotItem->testItemInterest( QwtPlotItem::LegendInterest ) ) { // plotItem is some sort of legend const QwtPlotItemList& itmList = itemList(); for ( QwtPlotItemIterator it = itmList.begin(); it != itmList.end(); ++it ) { QwtPlotItem *item = *it; QList legendData; if ( on && item->testItemAttribute( QwtPlotItem::Legend ) ) { legendData = item->legendData(); plotItem->updateLegend( item, legendData ); } } } if ( on ) insertItem( plotItem ); else removeItem( plotItem ); Q_EMIT itemAttached( plotItem, on ); if ( plotItem->testItemAttribute( QwtPlotItem::Legend ) ) { // the item wants to be represented on the legend if ( on ) { updateLegend( plotItem ); } else { const QVariant itemInfo = itemToInfo( plotItem ); Q_EMIT legendDataChanged( itemInfo, QList() ); } } autoRefresh(); } /*! \brief Build an information, that can be used to identify a plot item on the legend. The default implementation simply wraps the plot item into a QVariant object. When overloading itemToInfo() usually infoToItem() needs to reimplemeted too. \code QVariant itemInfo; qVariantSetValue( itemInfo, plotItem ); \endcode \param plotItem Plot item \return Plot item embedded in a QVariant \sa infoToItem() */ QVariant QwtPlot::itemToInfo( QwtPlotItem *plotItem ) const { QVariant itemInfo; qVariantSetValue( itemInfo, plotItem ); return itemInfo; } /*! \brief Identify the plot item according to an item info object, that has bee generated from itemToInfo(). The default implementation simply tries to unwrap a QwtPlotItem pointer: \code if ( itemInfo.canConvert() ) return qvariant_cast( itemInfo ); \endcode \param itemInfo Plot item \return A plot item, when successful, otherwise a NULL pointer. \sa itemToInfo() */ QwtPlotItem *QwtPlot::infoToItem( const QVariant &itemInfo ) const { if ( itemInfo.canConvert() ) return qvariant_cast( itemInfo ); return NULL; } connectome-workbench-1.4.2/src/Qwt/qwt_plot.h000066400000000000000000000202521360521144700212200ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_H #define QWT_PLOT_H #include "qwt_global.h" #include "qwt_text.h" #include "qwt_plot_dict.h" #include "qwt_scale_map.h" #include "qwt_interval.h" #include #include #include class QwtPlotLayout; class QwtAbstractLegend; class QwtScaleWidget; class QwtScaleEngine; class QwtScaleDiv; class QwtScaleDraw; class QwtTextLabel; /*! \brief A 2-D plotting widget QwtPlot is a widget for plotting two-dimensional graphs. An unlimited number of plot items can be displayed on its canvas. Plot items might be curves (QwtPlotCurve), markers (QwtPlotMarker), the grid (QwtPlotGrid), or anything else derived from QwtPlotItem. A plot can have up to four axes, with each plot item attached to an x- and a y axis. The scales at the axes can be explicitly set (QwtScaleDiv), or are calculated from the plot items, using algorithms (QwtScaleEngine) which can be configured separately for each axis. The simpleplot example is a good starting point to see how to set up a plot widget. \image html plot.png \par Example The following example shows (schematically) the most simple way to use QwtPlot. By default, only the left and bottom axes are visible and their scales are computed automatically. \verbatim #include #include QwtPlot *myPlot = new QwtPlot("Two Curves", parent); // add curves QwtPlotCurve *curve1 = new QwtPlotCurve("Curve 1"); QwtPlotCurve *curve2 = new QwtPlotCurve("Curve 2"); // connect or copy the data to the curves curve1->setData(...); curve2->setData(...); curve1->attach(myPlot); curve2->attach(myPlot); // finally, refresh the plot myPlot->replot(); \endverbatim */ class QWT_EXPORT QwtPlot: public QFrame, public QwtPlotDict { Q_OBJECT Q_PROPERTY( QBrush canvasBackground READ canvasBackground WRITE setCanvasBackground ) Q_PROPERTY( bool autoReplot READ autoReplot WRITE setAutoReplot ) #if 0 // This property is intended to configure the plot // widget from a special dialog in the deigner plugin. // Disabled until such a dialog has been implemented. Q_PROPERTY( QString propertiesDocument READ grabProperties WRITE applyProperties ) #endif public: //! \brief Axis index enum Axis { //! Y axis left of the canvas yLeft, //! Y axis right of the canvas yRight, //! X axis below the canvas xBottom, //! X axis above the canvas xTop, //! Number of axes axisCnt }; /*! Position of the legend, relative to the canvas. \sa insertLegend() */ enum LegendPosition { //! The legend will be left from the QwtPlot::yLeft axis. LeftLegend, //! The legend will be right from the QwtPlot::yRight axis. RightLegend, //! The legend will be below the footer BottomLegend, //! The legend will be above the title TopLegend }; explicit QwtPlot( QWidget * = NULL ); explicit QwtPlot( const QwtText &title, QWidget * = NULL ); virtual ~QwtPlot(); void applyProperties( const QString & ); QString grabProperties() const; void setAutoReplot( bool = true ); bool autoReplot() const; // Layout void setPlotLayout( QwtPlotLayout * ); QwtPlotLayout *plotLayout(); const QwtPlotLayout *plotLayout() const; // Title void setTitle( const QString & ); void setTitle( const QwtText &t ); QwtText title() const; QwtTextLabel *titleLabel(); const QwtTextLabel *titleLabel() const; // Footer void setFooter( const QString & ); void setFooter( const QwtText &t ); QwtText footer() const; QwtTextLabel *footerLabel(); const QwtTextLabel *footerLabel() const; // Canvas void setCanvas( QWidget * ); QWidget *canvas(); const QWidget *canvas() const; void setCanvasBackground( const QBrush & ); QBrush canvasBackground() const; virtual QwtScaleMap canvasMap( int axisId ) const; double invTransform( int axisId, int pos ) const; double transform( int axisId, double value ) const; // Axes QwtScaleEngine *axisScaleEngine( int axisId ); const QwtScaleEngine *axisScaleEngine( int axisId ) const; void setAxisScaleEngine( int axisId, QwtScaleEngine * ); void setAxisAutoScale( int axisId, bool on = true ); bool axisAutoScale( int axisId ) const; void enableAxis( int axisId, bool tf = true ); bool axisEnabled( int axisId ) const; void setAxisFont( int axisId, const QFont &f ); QFont axisFont( int axisId ) const; void setAxisScale( int axisId, double min, double max, double step = 0 ); void setAxisScaleDiv( int axisId, const QwtScaleDiv & ); void setAxisScaleDraw( int axisId, QwtScaleDraw * ); double axisStepSize( int axisId ) const; QwtInterval axisInterval( int axisId ) const; const QwtScaleDiv &axisScaleDiv( int axisId ) const; const QwtScaleDraw *axisScaleDraw( int axisId ) const; QwtScaleDraw *axisScaleDraw( int axisId ); const QwtScaleWidget *axisWidget( int axisId ) const; QwtScaleWidget *axisWidget( int axisId ); void setAxisLabelAlignment( int axisId, Qt::Alignment ); void setAxisLabelRotation( int axisId, double rotation ); void setAxisTitle( int axisId, const QString & ); void setAxisTitle( int axisId, const QwtText & ); QwtText axisTitle( int axisId ) const; void setAxisMaxMinor( int axisId, int maxMinor ); int axisMaxMinor( int axisId ) const; void setAxisMaxMajor( int axisId, int maxMajor ); int axisMaxMajor( int axisId ) const; // Legend void insertLegend( QwtAbstractLegend *, LegendPosition = QwtPlot::RightLegend, double ratio = -1.0 ); QwtAbstractLegend *legend(); const QwtAbstractLegend *legend() const; void updateLegend(); void updateLegend( const QwtPlotItem * ); // Misc virtual QSize sizeHint() const; virtual QSize minimumSizeHint() const; virtual void updateLayout(); virtual void drawCanvas( QPainter * ); void updateAxes(); void updateCanvasMargins(); virtual void getCanvasMarginsHint( const QwtScaleMap maps[], const QRectF &canvasRect, double &left, double &top, double &right, double &bottom) const; virtual bool event( QEvent * ); virtual bool eventFilter( QObject *, QEvent * ); virtual void drawItems( QPainter *, const QRectF &, const QwtScaleMap maps[axisCnt] ) const; virtual QVariant itemToInfo( QwtPlotItem * ) const; virtual QwtPlotItem *infoToItem( const QVariant & ) const; Q_SIGNALS: /*! A signal indicating, that an item has been attached/detached \param plotItem Plot item \param on Attached/Detached */ void itemAttached( QwtPlotItem *plotItem, bool on ); /*! A signal with the attributes how to update the legend entries for a plot item. \param itemInfo Info about a plot item, build from itemToInfo() \param data Attributes of the entries ( usually <= 1 ) for the plot item. \sa itemToInfo(), infoToItem(), QwtAbstractLegend::updateLegend() */ void legendDataChanged( const QVariant &itemInfo, const QList &data ); public Q_SLOTS: virtual void replot(); void autoRefresh(); protected: static bool axisValid( int axisId ); virtual void resizeEvent( QResizeEvent *e ); private Q_SLOTS: void updateLegendItems( const QVariant &itemInfo, const QList &data ); private: friend class QwtPlotItem; void attachItem( QwtPlotItem *, bool ); void initAxesData(); void deleteAxesData(); void updateScaleDiv(); void initPlot( const QwtText &title ); class AxisData; AxisData *d_axisData[axisCnt]; class PrivateData; PrivateData *d_data; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_plot_abstract_barchart.cpp000066400000000000000000000221211360521144700253010ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_abstract_barchart.h" #include "qwt_scale_map.h" static inline double qwtTransformWidth( const QwtScaleMap &map, double value, double width ) { const double w2 = 0.5 * width; const double v1 = map.transform( value - w2 ); const double v2 = map.transform( value + w2 ); return qAbs( v2 - v1 ); } class QwtPlotAbstractBarChart::PrivateData { public: PrivateData(): layoutPolicy( QwtPlotAbstractBarChart::AutoAdjustSamples ), layoutHint( 0.5 ), spacing( 10 ), margin( 5 ), baseline( 0.0 ) { } QwtPlotAbstractBarChart::LayoutPolicy layoutPolicy; double layoutHint; int spacing; int margin; double baseline; }; /*! Constructor \param title Title of the chart */ QwtPlotAbstractBarChart::QwtPlotAbstractBarChart( const QwtText &title ): QwtPlotSeriesItem( title ) { d_data = new PrivateData; setItemAttribute( QwtPlotItem::Legend, true ); setItemAttribute( QwtPlotItem::AutoScale, true ); setItemAttribute( QwtPlotItem::Margins, true ); setZ( 19.0 ); } //! Destructor QwtPlotAbstractBarChart::~QwtPlotAbstractBarChart() { delete d_data; } /*! The combination of layoutPolicy() and layoutHint() define how the width of the bars is calculated \param policy Layout policy \sa layoutPolicy(), layoutHint() */ void QwtPlotAbstractBarChart::setLayoutPolicy( LayoutPolicy policy ) { if ( policy != d_data->layoutPolicy ) { d_data->layoutPolicy = policy; itemChanged(); } } /*! The combination of layoutPolicy() and layoutHint() define how the width of the bars is calculated \return Layout policy of the chart item \sa setLayoutPolicy(), layoutHint() */ QwtPlotAbstractBarChart::LayoutPolicy QwtPlotAbstractBarChart::layoutPolicy() const { return d_data->layoutPolicy; } /*! The combination of layoutPolicy() and layoutHint() define how the width of the bars is calculated \param hint Layout hint \sa LayoutPolicy, layoutPolicy(), layoutHint() */ void QwtPlotAbstractBarChart::setLayoutHint( double hint ) { hint = qMax( 0.0, hint ); if ( hint != d_data->layoutHint ) { d_data->layoutHint = hint; itemChanged(); } } /*! The combination of layoutPolicy() and layoutHint() define how the width of the bars is calculated \return Layout policy of the chart item \sa LayoutPolicy, setLayoutHint(), layoutPolicy() */ double QwtPlotAbstractBarChart::layoutHint() const { return d_data->layoutHint; } /*! \brief Set the spacing The spacing is the distance between 2 samples ( bars for QwtPlotBarChart or a group of bars for QwtPlotMultiBarChart ) in paint device coordinates. \sa spacing() */ void QwtPlotAbstractBarChart::setSpacing( int spacing ) { spacing = qMax( spacing, 0 ); if ( spacing != d_data->spacing ) { d_data->spacing = spacing; itemChanged(); } } /*! \return Spacing between 2 samples ( bars or groups of bars ) \sa setSpacing(), margin() */ int QwtPlotAbstractBarChart::spacing() const { return d_data->spacing; } /*! \brief Set the margin The margin is the distance between the outmost bars and the contentsRect() of the canvas. The default setting is 5 pixels. \param margin Margin \sa spacing(), margin() */ void QwtPlotAbstractBarChart::setMargin( int margin ) { margin = qMax( margin, 0 ); if ( margin != d_data->margin ) { d_data->margin = margin; itemChanged(); } } /*! \return Margin between the outmost bars and the contentsRect() of the canvas. \sa setMargin(), spacing() */ int QwtPlotAbstractBarChart::margin() const { return d_data->margin; } /*! \brief Set the baseline The baseline is the origin for the chart. Each bar is painted from the baseline in the direction of the sample value. In case of a horizontal orientation() the baseline is interpreted as x - otherwise as y - value. The default value for the baseline is 0. \param value Value for the baseline \sa baseline(), QwtPlotSeriesItem::orientation() */ void QwtPlotAbstractBarChart::setBaseline( double value ) { if ( value != d_data->baseline ) { d_data->baseline = value; itemChanged(); } } /*! \return Value for the origin of the bar chart \sa setBaseline(), QwtPlotSeriesItem::orientation() */ double QwtPlotAbstractBarChart::baseline() const { return d_data->baseline; } /*! Calculate the width for a sample in paint device coordinates \param map Scale map for the corresponding scale \param canvasSize Size of the canvas in paint device coordinates \param boundingSize Bounding size of the chart in plot coordinates ( used in AutoAdjustSamples mode ) \param value Value of the sample \return Sample width \sa layoutPolicy(), layoutHint() */ double QwtPlotAbstractBarChart::sampleWidth( const QwtScaleMap &map, double canvasSize, double boundingSize, double value ) const { double width; switch( d_data->layoutPolicy ) { case ScaleSamplesToAxes: { width = qwtTransformWidth( map, value, d_data->layoutHint ); break; } case ScaleSampleToCanvas: { width = canvasSize * d_data->layoutHint; break; } case FixedSampleSize: { width = d_data->layoutHint; break; } case AutoAdjustSamples: default: { const size_t numSamples = dataSize(); double w = 1.0; if ( numSamples > 1 ) { w = qAbs( boundingSize / ( numSamples - 1 ) ); } width = qwtTransformWidth( map, value, w ); width -= d_data->spacing; width = qMax( width, d_data->layoutHint ); } } return width; } /*! \brief Calculate a hint for the canvas margin Bar charts need to reserve some space for displaying the bars for the first and the last sample. The hint is calculated from the layoutHint() depending on the layoutPolicy(). The margins are in target device coordinates ( pixels on screen ) \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rectangle of the canvas in painter coordinates \param left Returns the left margin \param top Returns the top margin \param right Returns the right margin \param bottom Returns the bottom margin \return Margin \sa layoutPolicy(), layoutHint(), QwtPlotItem::Margins QwtPlot::getCanvasMarginsHint(), QwtPlot::updateCanvasMargins() */ void QwtPlotAbstractBarChart::getCanvasMarginHint( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, double &left, double &top, double &right, double &bottom ) const { double hint = -1.0; switch( layoutPolicy() ) { case ScaleSampleToCanvas: { if ( orientation() == Qt::Vertical ) hint = 0.5 * canvasRect.width() * d_data->layoutHint; else hint = 0.5 * canvasRect.height() * d_data->layoutHint; break; } case FixedSampleSize: { hint = 0.5 * d_data->layoutHint; break; } case AutoAdjustSamples: case ScaleSamplesToAxes: default: { const size_t numSamples = dataSize(); if ( numSamples <= 0 ) break; // doesn't work for nonlinear scales const QRectF br = dataRect(); double spacing = 0.0; double sampleWidthS = 1.0; if ( layoutPolicy() == ScaleSamplesToAxes ) { sampleWidthS = qMax( d_data->layoutHint, 0.0 ); } else { spacing = d_data->spacing; if ( numSamples > 1 ) { sampleWidthS = qAbs( br.width() / ( numSamples - 1 ) ); } } double ds, w; if ( orientation() == Qt::Vertical ) { ds = qAbs( xMap.sDist() ); w = canvasRect.width(); } else { ds = qAbs( yMap.sDist() ); w = canvasRect.height(); } const double sampleWidthP = ( w - spacing * ds ) * sampleWidthS / ( ds + sampleWidthS ); hint = 0.5 * sampleWidthP; hint += qMax( d_data->margin, 0 ); } } if ( orientation() == Qt::Vertical ) { left = right = hint; top = bottom = -1.0; // no hint } else { left = right = -1.0; // no hint top = bottom = hint; } } connectome-workbench-1.4.2/src/Qwt/qwt_plot_abstract_barchart.h000066400000000000000000000051111360521144700247460ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_ABSTRACT_BAR_CHART_H #define QWT_PLOT_ABSTRACT_BAR_CHART_H #include "qwt_global.h" #include "qwt_plot_seriesitem.h" #include "qwt_series_data.h" /*! \brief Abstract base class for bar chart items In opposite to almost all other plot items bar charts can't be displayed inside of their bounding rectangle and need a special API how to calculate the width of the bars and how they affect the layout of the attached plot. */ class QWT_EXPORT QwtPlotAbstractBarChart: public QwtPlotSeriesItem { public: /*! \brief Mode how to calculate the bar width setLayoutPolicy(), setLayoutHint(), barWidthHint() */ enum LayoutPolicy { /*! The sample width is calculated by dividing the bounding rectangle by the number of samples. The layoutHint() is used as a minimum width in paint device coordinates. \sa boundingRectangle() */ AutoAdjustSamples, /*! layoutHint() defines an interval in axis coordinates */ ScaleSamplesToAxes, /*! The bar width is calculated by multiplying layoutHint() with the height or width of the canvas. \sa boundingRectangle() */ ScaleSampleToCanvas, /*! layoutHint() defines a fixed width in paint device coordinates. */ FixedSampleSize }; explicit QwtPlotAbstractBarChart( const QwtText &title ); virtual ~QwtPlotAbstractBarChart(); void setLayoutPolicy( LayoutPolicy ); LayoutPolicy layoutPolicy() const; void setLayoutHint( double ); double layoutHint() const; void setSpacing( int ); int spacing() const; void setMargin( int ); int margin() const; void setBaseline( double ); double baseline() const; virtual void getCanvasMarginHint( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, double &left, double &top, double &right, double &bottom) const; protected: double sampleWidth( const QwtScaleMap &map, double canvasSize, double dataSize, double value ) const; private: class PrivateData; PrivateData *d_data; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_plot_axis.cpp000066400000000000000000000433271360521144700226070ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot.h" #include "qwt_math.h" #include "qwt_scale_widget.h" #include "qwt_scale_div.h" #include "qwt_scale_engine.h" class QwtPlot::AxisData { public: bool isEnabled; bool doAutoScale; double minValue; double maxValue; double stepSize; int maxMajor; int maxMinor; bool isValid; QwtScaleDiv scaleDiv; QwtScaleEngine *scaleEngine; QwtScaleWidget *scaleWidget; }; //! Initialize axes void QwtPlot::initAxesData() { int axisId; for ( axisId = 0; axisId < axisCnt; axisId++ ) d_axisData[axisId] = new AxisData; d_axisData[yLeft]->scaleWidget = new QwtScaleWidget( QwtScaleDraw::LeftScale, this ); d_axisData[yRight]->scaleWidget = new QwtScaleWidget( QwtScaleDraw::RightScale, this ); d_axisData[xTop]->scaleWidget = new QwtScaleWidget( QwtScaleDraw::TopScale, this ); d_axisData[xBottom]->scaleWidget = new QwtScaleWidget( QwtScaleDraw::BottomScale, this ); d_axisData[yLeft]->scaleWidget->setObjectName( "QwtPlotAxisYLeft" ); d_axisData[yRight]->scaleWidget->setObjectName( "QwtPlotAxisYRight" ); d_axisData[xTop]->scaleWidget->setObjectName( "QwtPlotAxisXTop" ); d_axisData[xBottom]->scaleWidget->setObjectName( "QwtPlotAxisXBottom" ); #if 1 // better find the font sizes from the application font QFont fscl( fontInfo().family(), 10 ); QFont fttl( fontInfo().family(), 12, QFont::Bold ); #endif for ( axisId = 0; axisId < axisCnt; axisId++ ) { AxisData &d = *d_axisData[axisId]; d.scaleEngine = new QwtLinearScaleEngine; d.scaleWidget->setTransformation( d.scaleEngine->transformation() ); d.scaleWidget->setFont( fscl ); d.scaleWidget->setMargin( 2 ); QwtText text = d.scaleWidget->title(); text.setFont( fttl ); d.scaleWidget->setTitle( text ); d.doAutoScale = true; d.minValue = 0.0; d.maxValue = 1000.0; d.stepSize = 0.0; d.maxMinor = 5; d.maxMajor = 8; d.isValid = false; } d_axisData[yLeft]->isEnabled = true; d_axisData[yRight]->isEnabled = false; d_axisData[xBottom]->isEnabled = true; d_axisData[xTop]->isEnabled = false; } void QwtPlot::deleteAxesData() { for ( int axisId = 0; axisId < axisCnt; axisId++ ) { delete d_axisData[axisId]->scaleEngine; delete d_axisData[axisId]; d_axisData[axisId] = NULL; } } /*! \return Scale widget of the specified axis, or NULL if axisId is invalid. \param axisId Axis index */ const QwtScaleWidget *QwtPlot::axisWidget( int axisId ) const { if ( axisValid( axisId ) ) return d_axisData[axisId]->scaleWidget; return NULL; } /*! \return Scale widget of the specified axis, or NULL if axisId is invalid. \param axisId Axis index */ QwtScaleWidget *QwtPlot::axisWidget( int axisId ) { if ( axisValid( axisId ) ) return d_axisData[axisId]->scaleWidget; return NULL; } /*! Change the scale engine for an axis \param axisId Axis index \param scaleEngine Scale engine \sa axisScaleEngine() */ void QwtPlot::setAxisScaleEngine( int axisId, QwtScaleEngine *scaleEngine ) { if ( axisValid( axisId ) && scaleEngine != NULL ) { AxisData &d = *d_axisData[axisId]; delete d.scaleEngine; d.scaleEngine = scaleEngine; d_axisData[axisId]->scaleWidget->setTransformation( scaleEngine->transformation() ); d.isValid = false; autoRefresh(); } } /*! \param axisId Axis index \return Scale engine for a specific axis */ QwtScaleEngine *QwtPlot::axisScaleEngine( int axisId ) { if ( axisValid( axisId ) ) return d_axisData[axisId]->scaleEngine; else return NULL; } /*! \param axisId Axis index \return Scale engine for a specific axis */ const QwtScaleEngine *QwtPlot::axisScaleEngine( int axisId ) const { if ( axisValid( axisId ) ) return d_axisData[axisId]->scaleEngine; else return NULL; } /*! \return \c True, if autoscaling is enabled \param axisId Axis index */ bool QwtPlot::axisAutoScale( int axisId ) const { if ( axisValid( axisId ) ) return d_axisData[axisId]->doAutoScale; else return false; } /*! \return \c True, if a specified axis is enabled \param axisId Axis index */ bool QwtPlot::axisEnabled( int axisId ) const { if ( axisValid( axisId ) ) return d_axisData[axisId]->isEnabled; else return false; } /*! \return The font of the scale labels for a specified axis \param axisId Axis index */ QFont QwtPlot::axisFont( int axisId ) const { if ( axisValid( axisId ) ) return axisWidget( axisId )->font(); else return QFont(); } /*! \return The maximum number of major ticks for a specified axis \param axisId Axis index \sa setAxisMaxMajor(), QwtScaleEngine::divideScale() */ int QwtPlot::axisMaxMajor( int axisId ) const { if ( axisValid( axisId ) ) return d_axisData[axisId]->maxMajor; else return 0; } /*! \return the maximum number of minor ticks for a specified axis \param axisId Axis index \sa setAxisMaxMinor(), QwtScaleEngine::divideScale() */ int QwtPlot::axisMaxMinor( int axisId ) const { if ( axisValid( axisId ) ) return d_axisData[axisId]->maxMinor; else return 0; } /*! \brief Return the scale division of a specified axis axisScaleDiv(axisId).lowerBound(), axisScaleDiv(axisId).upperBound() are the current limits of the axis scale. \param axisId Axis index \return Scale division \sa QwtScaleDiv, setAxisScaleDiv(), QwtScaleEngine::divideScale() */ const QwtScaleDiv &QwtPlot::axisScaleDiv( int axisId ) const { return d_axisData[axisId]->scaleDiv; } /*! \brief Return the scale draw of a specified axis \param axisId Axis index \return Specified scaleDraw for axis, or NULL if axis is invalid. */ const QwtScaleDraw *QwtPlot::axisScaleDraw( int axisId ) const { if ( !axisValid( axisId ) ) return NULL; return axisWidget( axisId )->scaleDraw(); } /*! \brief Return the scale draw of a specified axis \param axisId Axis index \return Specified scaleDraw for axis, or NULL if axis is invalid. */ QwtScaleDraw *QwtPlot::axisScaleDraw( int axisId ) { if ( !axisValid( axisId ) ) return NULL; return axisWidget( axisId )->scaleDraw(); } /*! \brief Return the step size parameter that has been set in setAxisScale. This doesn't need to be the step size of the current scale. \param axisId Axis index \return step size parameter value \sa setAxisScale(), QwtScaleEngine::divideScale() */ double QwtPlot::axisStepSize( int axisId ) const { if ( !axisValid( axisId ) ) return 0; return d_axisData[axisId]->stepSize; } /*! \brief Return the current interval of the specified axis This is only a convenience function for axisScaleDiv( axisId )->interval(); \param axisId Axis index \return Scale interval \sa QwtScaleDiv, axisScaleDiv() */ QwtInterval QwtPlot::axisInterval( int axisId ) const { if ( !axisValid( axisId ) ) return QwtInterval(); return d_axisData[axisId]->scaleDiv.interval(); } /*! \return Title of a specified axis \param axisId Axis index */ QwtText QwtPlot::axisTitle( int axisId ) const { if ( axisValid( axisId ) ) return axisWidget( axisId )->title(); else return QwtText(); } /*! \brief Enable or disable a specified axis When an axis is disabled, this only means that it is not visible on the screen. Curves, markers and can be attached to disabled axes, and transformation of screen coordinates into values works as normal. Only xBottom and yLeft are enabled by default. \param axisId Axis index \param tf \c true (enabled) or \c false (disabled) */ void QwtPlot::enableAxis( int axisId, bool tf ) { if ( axisValid( axisId ) && tf != d_axisData[axisId]->isEnabled ) { d_axisData[axisId]->isEnabled = tf; updateLayout(); } } /*! Transform the x or y coordinate of a position in the drawing region into a value. \param axisId Axis index \param pos position \return Position as axis coordinate \warning The position can be an x or a y coordinate, depending on the specified axis. */ double QwtPlot::invTransform( int axisId, int pos ) const { if ( axisValid( axisId ) ) return( canvasMap( axisId ).invTransform( pos ) ); else return 0.0; } /*! \brief Transform a value into a coordinate in the plotting region \param axisId Axis index \param value value \return X or Y coordinate in the plotting region corresponding to the value. */ double QwtPlot::transform( int axisId, double value ) const { if ( axisValid( axisId ) ) return( canvasMap( axisId ).transform( value ) ); else return 0.0; } /*! \brief Change the font of an axis \param axisId Axis index \param font Font \warning This function changes the font of the tick labels, not of the axis title. */ void QwtPlot::setAxisFont( int axisId, const QFont &font ) { if ( axisValid( axisId ) ) axisWidget( axisId )->setFont( font ); } /*! \brief Enable autoscaling for a specified axis This member function is used to switch back to autoscaling mode after a fixed scale has been set. Autoscaling is enabled by default. \param axisId Axis index \param on On/Off \sa setAxisScale(), setAxisScaleDiv(), updateAxes() \note The autoscaling flag has no effect until updateAxes() is executed ( called by replot() ). */ void QwtPlot::setAxisAutoScale( int axisId, bool on ) { if ( axisValid( axisId ) && ( d_axisData[axisId]->doAutoScale != on ) ) { d_axisData[axisId]->doAutoScale = on; autoRefresh(); } } /*! \brief Disable autoscaling and specify a fixed scale for a selected axis. In updateAxes() the scale engine calculates a scale division from the specified parameters, that will be assigned to the scale widget. So updates of the scale widget usually happen delayed with the next replot. \param axisId Axis index \param min Minimum of the scale \param max Maximum of the scale \param stepSize Major step size. If step == 0, the step size is calculated automatically using the maxMajor setting. \sa setAxisMaxMajor(), setAxisAutoScale(), axisStepSize(), QwtScaleEngine::divideScale() */ void QwtPlot::setAxisScale( int axisId, double min, double max, double stepSize ) { if ( axisValid( axisId ) ) { AxisData &d = *d_axisData[axisId]; d.doAutoScale = false; d.isValid = false; d.minValue = min; d.maxValue = max; d.stepSize = stepSize; autoRefresh(); } } /*! \brief Disable autoscaling and specify a fixed scale for a selected axis. The scale division will be stored locally only until the next call of updateAxes(). So updates of the scale widget usually happen delayed with the next replot. \param axisId Axis index \param scaleDiv Scale division \sa setAxisScale(), setAxisAutoScale() */ void QwtPlot::setAxisScaleDiv( int axisId, const QwtScaleDiv &scaleDiv ) { if ( axisValid( axisId ) ) { AxisData &d = *d_axisData[axisId]; d.doAutoScale = false; d.scaleDiv = scaleDiv; d.isValid = true; autoRefresh(); } } /*! \brief Set a scale draw \param axisId Axis index \param scaleDraw Object responsible for drawing scales. By passing scaleDraw it is possible to extend QwtScaleDraw functionality and let it take place in QwtPlot. Please note that scaleDraw has to be created with new and will be deleted by the corresponding QwtScale member ( like a child object ). \sa QwtScaleDraw, QwtScaleWidget \warning The attributes of scaleDraw will be overwritten by those of the previous QwtScaleDraw. */ void QwtPlot::setAxisScaleDraw( int axisId, QwtScaleDraw *scaleDraw ) { if ( axisValid( axisId ) ) { axisWidget( axisId )->setScaleDraw( scaleDraw ); autoRefresh(); } } /*! Change the alignment of the tick labels \param axisId Axis index \param alignment Or'd Qt::AlignmentFlags see \sa QwtScaleDraw::setLabelAlignment() */ void QwtPlot::setAxisLabelAlignment( int axisId, Qt::Alignment alignment ) { if ( axisValid( axisId ) ) axisWidget( axisId )->setLabelAlignment( alignment ); } /*! Rotate all tick labels \param axisId Axis index \param rotation Angle in degrees. When changing the label rotation, the label alignment might be adjusted too. \sa QwtScaleDraw::setLabelRotation(), setAxisLabelAlignment() */ void QwtPlot::setAxisLabelRotation( int axisId, double rotation ) { if ( axisValid( axisId ) ) axisWidget( axisId )->setLabelRotation( rotation ); } /*! Set the maximum number of minor scale intervals for a specified axis \param axisId Axis index \param maxMinor Maximum number of minor steps \sa axisMaxMinor() */ void QwtPlot::setAxisMaxMinor( int axisId, int maxMinor ) { if ( axisValid( axisId ) ) { maxMinor = qBound( 0, maxMinor, 100 ); AxisData &d = *d_axisData[axisId]; if ( maxMinor != d.maxMinor ) { d.maxMinor = maxMinor; d.isValid = false; autoRefresh(); } } } /*! Set the maximum number of major scale intervals for a specified axis \param axisId Axis index \param maxMajor Maximum number of major steps \sa axisMaxMajor() */ void QwtPlot::setAxisMaxMajor( int axisId, int maxMajor ) { if ( axisValid( axisId ) ) { maxMajor = qBound( 1, maxMajor, 10000 ); AxisData &d = *d_axisData[axisId]; if ( maxMajor != d.maxMajor ) { d.maxMajor = maxMajor; d.isValid = false; autoRefresh(); } } } /*! \brief Change the title of a specified axis \param axisId Axis index \param title axis title */ void QwtPlot::setAxisTitle( int axisId, const QString &title ) { if ( axisValid( axisId ) ) axisWidget( axisId )->setTitle( title ); } /*! \brief Change the title of a specified axis \param axisId Axis index \param title Axis title */ void QwtPlot::setAxisTitle( int axisId, const QwtText &title ) { if ( axisValid( axisId ) ) axisWidget( axisId )->setTitle( title ); } /*! \brief Rebuild the axes scales In case of autoscaling the boundaries of a scale are calculated from the bounding rectangles of all plot items, having the QwtPlotItem::AutoScale flag enabled ( QwtScaleEngine::autoScale() ). Then a scale division is calculated ( QwtScaleEngine::didvideScale() ) and assigned to scale widget. When the scale boundaries have been assigned with setAxisScale() a scale division is calculated ( QwtScaleEngine::didvideScale() ) for this interval and assigned to the scale widget. When the scale has been set explicitly by setAxisScaleDiv() the locally stored scale division gets assigned to the scale widget. The scale widget indicates modifications by emitting a QwtScaleWidget::scaleDivChanged() signal. updateAxes() is usually called by replot(). \sa setAxisAutoScale(), setAxisScale(), setAxisScaleDiv(), replot() QwtPlotItem::boundingRect() */ void QwtPlot::updateAxes() { // Find bounding interval of the item data // for all axes, where autoscaling is enabled QwtInterval intv[axisCnt]; const QwtPlotItemList& itmList = itemList(); QwtPlotItemIterator it; for ( it = itmList.begin(); it != itmList.end(); ++it ) { const QwtPlotItem *item = *it; if ( !item->testItemAttribute( QwtPlotItem::AutoScale ) ) continue; if ( !item->isVisible() ) continue; if ( axisAutoScale( item->xAxis() ) || axisAutoScale( item->yAxis() ) ) { const QRectF rect = item->boundingRect(); if ( rect.width() >= 0.0 ) intv[item->xAxis()] |= QwtInterval( rect.left(), rect.right() ); if ( rect.height() >= 0.0 ) intv[item->yAxis()] |= QwtInterval( rect.top(), rect.bottom() ); } } // Adjust scales for ( int axisId = 0; axisId < axisCnt; axisId++ ) { AxisData &d = *d_axisData[axisId]; double minValue = d.minValue; double maxValue = d.maxValue; double stepSize = d.stepSize; if ( d.doAutoScale && intv[axisId].isValid() ) { d.isValid = false; minValue = intv[axisId].minValue(); maxValue = intv[axisId].maxValue(); d.scaleEngine->autoScale( d.maxMajor, minValue, maxValue, stepSize ); } if ( !d.isValid ) { d.scaleDiv = d.scaleEngine->divideScale( minValue, maxValue, d.maxMajor, d.maxMinor, stepSize ); d.isValid = true; } QwtScaleWidget *scaleWidget = axisWidget( axisId ); scaleWidget->setScaleDiv( d.scaleDiv ); int startDist, endDist; scaleWidget->getBorderDistHint( startDist, endDist ); scaleWidget->setBorderDist( startDist, endDist ); } for ( it = itmList.begin(); it != itmList.end(); ++it ) { QwtPlotItem *item = *it; if ( item->testItemInterest( QwtPlotItem::ScaleInterest ) ) { item->updateScaleDiv( axisScaleDiv( item->xAxis() ), axisScaleDiv( item->yAxis() ) ); } } } connectome-workbench-1.4.2/src/Qwt/qwt_plot_barchart.cpp000066400000000000000000000264221360521144700234260ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_barchart.h" #include "qwt_scale_map.h" #include "qwt_column_symbol.h" #include "qwt_painter.h" #include class QwtPlotBarChart::PrivateData { public: PrivateData(): symbol( NULL ), legendMode( QwtPlotBarChart::LegendChartTitle ) { } ~PrivateData() { delete symbol; } QwtColumnSymbol *symbol; QwtPlotBarChart::LegendMode legendMode; }; /*! Constructor \param title Title of the curve */ QwtPlotBarChart::QwtPlotBarChart( const QwtText &title ): QwtPlotAbstractBarChart( title ) { init(); } /*! Constructor \param title Title of the curve */ QwtPlotBarChart::QwtPlotBarChart( const QString &title ): QwtPlotAbstractBarChart( QwtText( title ) ) { init(); } //! Destructor QwtPlotBarChart::~QwtPlotBarChart() { delete d_data; } void QwtPlotBarChart::init() { d_data = new PrivateData; setData( new QwtPointSeriesData() ); } //! \return QwtPlotItem::Rtti_PlotBarChart int QwtPlotBarChart::rtti() const { return QwtPlotItem::Rtti_PlotBarChart; } /*! Initialize data with an array of points \param samples Vector of points \note QVector is implicitly shared \note QPolygonF is derived from QVector */ void QwtPlotBarChart::setSamples( const QVector &samples ) { setData( new QwtPointSeriesData( samples ) ); } /*! Initialize data with an array of doubles The indices in the array are taken as x coordinate, while the doubles are interpreted as y values. \param samples Vector of y coordinates \note QVector is implicitly shared */ void QwtPlotBarChart::setSamples( const QVector &samples ) { QVector points; for ( int i = 0; i < samples.size(); i++ ) points += QPointF( i, samples[ i ] ); setData( new QwtPointSeriesData( points ) ); } /*! Assign a series of samples setSamples() is just a wrapper for setData() without any additional value - beside that it is easier to find for the developer. \param data Data \warning The item takes ownership of the data object, deleting it when its not used anymore. */ void QwtPlotBarChart::setSamples( QwtSeriesData *data ) { setData( data ); } /*! \brief Assign a symbol The bar chart will take the ownership of the symbol, hence the previously set symbol will be delete by setting a new one. If \p symbol is \c NULL no symbol will be drawn. \param symbol Symbol \sa symbol() */ void QwtPlotBarChart::setSymbol( QwtColumnSymbol *symbol ) { if ( symbol != d_data->symbol ) { delete d_data->symbol; d_data->symbol = symbol; legendChanged(); itemChanged(); } } /*! \return Current symbol or NULL, when no symbol has been assigned \sa setSymbol() */ const QwtColumnSymbol *QwtPlotBarChart::symbol() const { return d_data->symbol; } /*! Set the mode that decides what to display on the legend In case of LegendBarTitles barTitle() needs to be overloaded to return individual titles for each bar. \param mode New mode \sa legendMode(), legendData(), barTitle(), QwtPlotItem::ItemAttribute */ void QwtPlotBarChart::setLegendMode( LegendMode mode ) { if ( mode != d_data->legendMode ) { d_data->legendMode = mode; legendChanged(); } } /*! \return Legend mode \sa setLegendMode() */ QwtPlotBarChart::LegendMode QwtPlotBarChart::legendMode() const { return d_data->legendMode; } /*! \return Bounding rectangle of all samples. For an empty series the rectangle is invalid. */ QRectF QwtPlotBarChart::boundingRect() const { const size_t numSamples = dataSize(); if ( numSamples == 0 ) return QwtPlotSeriesItem::boundingRect(); QRectF rect = QwtPlotSeriesItem::boundingRect(); if ( rect.height() >= 0 ) { const double baseLine = baseline(); if ( rect.bottom() < baseLine ) rect.setBottom( baseLine ); if ( rect.top() > baseLine ) rect.setTop( baseLine ); } if ( orientation() == Qt::Horizontal ) rect.setRect( rect.y(), rect.x(), rect.height(), rect.width() ); return rect; } /*! Draw an interval of the bar chart \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rect of the canvas \param from Index of the first point to be painted \param to Index of the last point to be painted. If to < 0 the curve will be painted to its last point. \sa drawSymbols() */ void QwtPlotBarChart::drawSeries( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { if ( to < 0 ) to = dataSize() - 1; if ( from < 0 ) from = 0; if ( from > to ) return; const QRectF br = data()->boundingRect(); const QwtInterval interval( br.left(), br.right() ); painter->save(); for ( int i = from; i <= to; i++ ) { drawSample( painter, xMap, yMap, canvasRect, interval, i, sample( i ) ); } painter->restore(); } /*! Draw a sample \param painter Painter \param xMap x map \param yMap y map \param canvasRect Contents rect of the canvas \param boundingInterval Bounding interval of sample values \param index Index of the sample \param sample Value of the sample \sa drawSeries() */ void QwtPlotBarChart::drawSample( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, const QwtInterval &boundingInterval, int index, const QPointF &sample ) const { QwtColumnRect barRect; if ( orientation() == Qt::Horizontal ) { const double barHeight = sampleWidth( yMap, canvasRect.height(), boundingInterval.width(), sample.y() ); const double x1 = xMap.transform( baseline() ); const double x2 = xMap.transform( sample.y() ); const double y = yMap.transform( sample.x() ); const double y1 = y - 0.5 * barHeight; const double y2 = y + 0.5 * barHeight; barRect.direction = ( x1 < x2 ) ? QwtColumnRect::LeftToRight : QwtColumnRect::RightToLeft; barRect.hInterval = QwtInterval( x1, x2 ).normalized(); barRect.vInterval = QwtInterval( y1, y2 ); } else { const double barWidth = sampleWidth( xMap, canvasRect.width(), boundingInterval.width(), sample.y() ); const double x = xMap.transform( sample.x() ); const double x1 = x - 0.5 * barWidth; const double x2 = x + 0.5 * barWidth; const double y1 = yMap.transform( baseline() ); const double y2 = yMap.transform( sample.y() ); barRect.direction = ( y1 < y2 ) ? QwtColumnRect::TopToBottom : QwtColumnRect::BottomToTop; barRect.hInterval = QwtInterval( x1, x2 ); barRect.vInterval = QwtInterval( y1, y2 ).normalized(); } drawBar( painter, index, sample, barRect ); } /*! Draw a bar \param painter Painter \param sampleIndex Index of the sample represented by the bar \param sample Value of the sample \param rect Bounding rectangle of the bar */ void QwtPlotBarChart::drawBar( QPainter *painter, int sampleIndex, const QPointF &sample, const QwtColumnRect &rect ) const { const QwtColumnSymbol *specialSym = specialSymbol( sampleIndex, sample ); const QwtColumnSymbol *sym = specialSym; if ( sym == NULL ) sym = d_data->symbol; if ( sym ) { sym->draw( painter, rect ); } else { // we build a temporary default symbol QwtColumnSymbol sym( QwtColumnSymbol::Box ); sym.setLineWidth( 1 ); sym.setFrameStyle( QwtColumnSymbol::Plain ); sym.draw( painter, rect ); } delete specialSym; } /*! Needs to be overloaded to return a non default symbol for a specific sample \param sampleIndex Index of the sample represented by the bar \param sample Value of the sample \return NULL, indicating to use the default symbol */ QwtColumnSymbol *QwtPlotBarChart::specialSymbol( int sampleIndex, const QPointF &sample ) const { Q_UNUSED( sampleIndex ); Q_UNUSED( sample ); return NULL; } /*! \brief Return the title of a bar In LegendBarTitles mode the title is displayed on the legend entry corresponding to a bar. The default implementation is a dummy, that is intended to be overloaded. \param sampleIndex Index of the bar \return An empty text \sa LegendBarTitles */ QwtText QwtPlotBarChart::barTitle( int sampleIndex ) const { Q_UNUSED( sampleIndex ); return QwtText(); } /*! \brief Return all information, that is needed to represent the item on the legend In case of LegendBarTitles an entry for each bar is returned, otherwise the chart is represented like any other plot item from its title() and the legendIcon(). \return Information, that is needed to represent the item on the legend \sa title(), setLegendMode(), barTitle(), QwtLegend, QwtPlotLegendItem */ QList QwtPlotBarChart::legendData() const { QList list; if ( d_data->legendMode == LegendBarTitles ) { const size_t numSamples = dataSize(); for ( size_t i = 0; i < numSamples; i++ ) { QwtLegendData data; QVariant titleValue; qVariantSetValue( titleValue, barTitle( i ) ); data.setValue( QwtLegendData::TitleRole, titleValue ); if ( !legendIconSize().isEmpty() ) { QVariant iconValue; qVariantSetValue( iconValue, legendIcon( i, legendIconSize() ) ); data.setValue( QwtLegendData::IconRole, iconValue ); } list += data; } } else { return QwtPlotAbstractBarChart::legendData(); } return list; } /*! \return Icon representing a bar or the chart on the legend When the legendMode() is LegendBarTitles the icon shows the bar corresponding to index - otherwise the bar displays the default symbol. \param index Index of the legend entry \param size Icon size \sa setLegendMode(), drawBar(), QwtPlotItem::setLegendIconSize(), QwtPlotItem::legendData() */ QwtGraphic QwtPlotBarChart::legendIcon( int index, const QSizeF &size ) const { QwtColumnRect column; column.hInterval = QwtInterval( 0.0, size.width() - 1.0 ); column.vInterval = QwtInterval( 0.0, size.height() - 1.0 ); QwtGraphic icon; icon.setDefaultSize( size ); icon.setRenderHint( QwtGraphic::RenderPensUnscaled, true ); QPainter painter( &icon ); painter.setRenderHint( QPainter::Antialiasing, testRenderHint( QwtPlotItem::RenderAntialiased ) ); int barIndex = -1; if ( d_data->legendMode == QwtPlotBarChart::LegendBarTitles ) barIndex = index; drawBar( &painter, barIndex, QPointF(), column ); return icon; } connectome-workbench-1.4.2/src/Qwt/qwt_plot_barchart.h000066400000000000000000000067461360521144700231020ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_BAR_CHART_H #define QWT_PLOT_BAR_CHART_H #include "qwt_global.h" #include "qwt_plot_abstract_barchart.h" #include "qwt_series_data.h" class QwtColumnRect; class QwtColumnSymbol; /*! \brief QwtPlotBarChart displays a series of a values as bars. Each bar might be customized individually by implementing a specialSymbol(). Otherwise it is rendered using a default symbol. Depending on its orientation() the bars are displayed horizontally or vertically. The bars cover the interval between the baseline() and the value. By activating the LegendBarTitles mode each sample will have its own entry on the legend. The most common use case of a bar chart is to display a list of y coordinates, where the x coordinate is simply the index in the list. But for other situations ( f.e. when values are related to dates ) it is also possible to set x coordinates explicitly. \sa QwtPlotMultiBarChart, QwtPlotHistogram, QwtPlotCurve::Sticks, QwtPlotSeriesItem::orientation(), QwtPlotAbstractBarChart::baseline() */ class QWT_EXPORT QwtPlotBarChart: public QwtPlotAbstractBarChart, public QwtSeriesStore { public: /*! \brief Legend modes. The default setting is QwtPlotBarChart::LegendChartTitle. \sa setLegendMode(), legendMode() */ enum LegendMode { /*! One entry on the legend showing the default symbol and the title() of the chart \sa QwtPlotItem::title() */ LegendChartTitle, /*! One entry for each value showing the individual symbol of the corresponding bar and the bar title. \sa specialSymbol(), barTitle() */ LegendBarTitles }; explicit QwtPlotBarChart( const QString &title = QString::null ); explicit QwtPlotBarChart( const QwtText &title ); virtual ~QwtPlotBarChart(); virtual int rtti() const; void setSamples( const QVector & ); void setSamples( const QVector & ); void setSamples( QwtSeriesData *series ); void setSymbol( QwtColumnSymbol * ); const QwtColumnSymbol *symbol() const; void setLegendMode( LegendMode ); LegendMode legendMode() const; virtual void drawSeries( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; virtual QRectF boundingRect() const; virtual QwtColumnSymbol *specialSymbol( int sampleIndex, const QPointF& ) const; virtual QwtText barTitle( int sampleIndex ) const; protected: virtual void drawSample( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, const QwtInterval &boundingInterval, int index, const QPointF& sample ) const; virtual void drawBar( QPainter *, int sampleIndex, const QPointF& point, const QwtColumnRect & ) const; QList legendData() const; QwtGraphic legendIcon( int index, const QSizeF & ) const; private: void init(); class PrivateData; PrivateData *d_data; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_plot_canvas.cpp000066400000000000000000000676071360521144700231250ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_canvas.h" #include "qwt_painter.h" #include "qwt_null_paintdevice.h" #include "qwt_math.h" #include "qwt_plot.h" #include #include #include #include #include class QwtStyleSheetRecorder: public QwtNullPaintDevice { public: QwtStyleSheetRecorder( const QSize &size ): d_size( size ) { } virtual void updateState( const QPaintEngineState &state ) { if ( state.state() & QPaintEngine::DirtyPen ) { d_pen = state.pen(); } if ( state.state() & QPaintEngine::DirtyBrush ) { d_brush = state.brush(); } if ( state.state() & QPaintEngine::DirtyBrushOrigin ) { d_origin = state.brushOrigin(); } } virtual void drawRects(const QRectF *rects, int count ) { for ( int i = 0; i < count; i++ ) border.rectList += rects[i]; } virtual void drawPath( const QPainterPath &path ) { const QRectF rect( QPointF( 0.0, 0.0 ), d_size ); if ( path.controlPointRect().contains( rect.center() ) ) { setCornerRects( path ); alignCornerRects( rect ); background.path = path; background.brush = d_brush; background.origin = d_origin; } else { border.pathList += path; } } void setCornerRects( const QPainterPath &path ) { QPointF pos( 0.0, 0.0 ); for ( int i = 0; i < path.elementCount(); i++ ) { QPainterPath::Element el = path.elementAt(i); switch( el.type ) { case QPainterPath::MoveToElement: case QPainterPath::LineToElement: { pos.setX( el.x ); pos.setY( el.y ); break; } case QPainterPath::CurveToElement: { QRectF r( pos, QPointF( el.x, el.y ) ); clipRects += r.normalized(); pos.setX( el.x ); pos.setY( el.y ); break; } case QPainterPath::CurveToDataElement: { if ( clipRects.size() > 0 ) { QRectF r = clipRects.last(); r.setCoords( qMin( r.left(), el.x ), qMin( r.top(), el.y ), qMax( r.right(), el.x ), qMax( r.bottom(), el.y ) ); clipRects.last() = r.normalized(); } break; } } } } protected: virtual QSize sizeMetrics() const { return d_size; } private: void alignCornerRects( const QRectF &rect ) { for ( int i = 0; i < clipRects.size(); i++ ) { QRectF &r = clipRects[i]; if ( r.center().x() < rect.center().x() ) r.setLeft( rect.left() ); else r.setRight( rect.right() ); if ( r.center().y() < rect.center().y() ) r.setTop( rect.top() ); else r.setBottom( rect.bottom() ); } } public: QVector clipRects; struct Border { QList pathList; QList rectList; QRegion clipRegion; } border; struct Background { QPainterPath path; QBrush brush; QPointF origin; } background; private: const QSize d_size; QPen d_pen; QBrush d_brush; QPointF d_origin; }; static void qwtDrawBackground( QPainter *painter, QwtPlotCanvas *canvas ) { painter->save(); const QPainterPath borderClip = canvas->borderPath( canvas->rect() ); if ( !borderClip.isEmpty() ) painter->setClipPath( borderClip, Qt::IntersectClip ); const QBrush &brush = canvas->palette().brush( canvas->backgroundRole() ); if ( brush.style() == Qt::TexturePattern ) { QPixmap pm( canvas->size() ); QwtPainter::fillPixmap( canvas, pm ); painter->drawPixmap( 0, 0, pm ); } else if ( brush.gradient() ) { QVector rects; if ( brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode ) { rects += canvas->rect(); } else { rects = painter->clipRegion().rects(); } #if 1 bool useRaster = false; if ( painter->paintEngine()->type() == QPaintEngine::X11 ) { // Qt 4.7.1: gradients on X11 are broken ( subrects + // QGradient::StretchToDeviceMode ) and horrible slow. // As workaround we have to use the raster paintengine. // Even if the QImage -> QPixmap translation is slow // it is three times faster, than using X11 directly useRaster = true; } #endif if ( useRaster ) { QImage::Format format = QImage::Format_RGB32; const QGradientStops stops = brush.gradient()->stops(); for ( int i = 0; i < stops.size(); i++ ) { if ( stops[i].second.alpha() != 255 ) { // don't use Format_ARGB32_Premultiplied. It's // recommended by the Qt docs, but QPainter::drawImage() // is horrible slow on X11. format = QImage::Format_ARGB32; break; } } QImage image( canvas->size(), format ); QPainter p( &image ); p.setPen( Qt::NoPen ); p.setBrush( brush ); p.drawRects( rects ); p.end(); painter->drawImage( 0, 0, image ); } else { painter->setPen( Qt::NoPen ); painter->setBrush( brush ); painter->drawRects( rects ); } } else { painter->setPen( Qt::NoPen ); painter->setBrush( brush ); painter->drawRects( painter->clipRegion().rects() ); } painter->restore(); } static inline void qwtRevertPath( QPainterPath &path ) { if ( path.elementCount() == 4 ) { QPainterPath::Element el0 = path.elementAt(0); QPainterPath::Element el3 = path.elementAt(3); path.setElementPositionAt( 0, el3.x, el3.y ); path.setElementPositionAt( 3, el0.x, el0.y ); } } static QPainterPath qwtCombinePathList( const QRectF &rect, const QList &pathList ) { if ( pathList.isEmpty() ) return QPainterPath(); QPainterPath ordered[8]; // starting top left for ( int i = 0; i < pathList.size(); i++ ) { int index = -1; QPainterPath subPath = pathList[i]; const QRectF br = pathList[i].controlPointRect(); if ( br.center().x() < rect.center().x() ) { if ( br.center().y() < rect.center().y() ) { if ( qAbs( br.top() - rect.top() ) < qAbs( br.left() - rect.left() ) ) { index = 1; } else { index = 0; } } else { if ( qAbs( br.bottom() - rect.bottom() ) < qAbs( br.left() - rect.left() ) ) { index = 6; } else { index = 7; } } if ( subPath.currentPosition().y() > br.center().y() ) qwtRevertPath( subPath ); } else { if ( br.center().y() < rect.center().y() ) { if ( qAbs( br.top() - rect.top() ) < qAbs( br.right() - rect.right() ) ) { index = 2; } else { index = 3; } } else { if ( qAbs( br.bottom() - rect.bottom() ) < qAbs( br.right() - rect.right() ) ) { index = 5; } else { index = 4; } } if ( subPath.currentPosition().y() < br.center().y() ) qwtRevertPath( subPath ); } ordered[index] = subPath; } for ( int i = 0; i < 4; i++ ) { if ( ordered[ 2 * i].isEmpty() != ordered[2 * i + 1].isEmpty() ) { // we don't accept incomplete rounded borders return QPainterPath(); } } const QPolygonF corners( rect ); QPainterPath path; //path.moveTo( rect.topLeft() ); for ( int i = 0; i < 4; i++ ) { if ( ordered[2 * i].isEmpty() ) { path.lineTo( corners[i] ); } else { path.connectPath( ordered[2 * i] ); path.connectPath( ordered[2 * i + 1] ); } } path.closeSubpath(); #if 0 return path.simplified(); #else return path; #endif } static inline void qwtDrawStyledBackground( QWidget *w, QPainter *painter ) { QStyleOption opt; opt.initFrom(w); w->style()->drawPrimitive( QStyle::PE_Widget, &opt, painter, w); } static QWidget *qwtBackgroundWidget( QWidget *w ) { if ( w->parentWidget() == NULL ) return w; if ( w->autoFillBackground() ) { const QBrush brush = w->palette().brush( w->backgroundRole() ); if ( brush.color().alpha() > 0 ) return w; } if ( w->testAttribute( Qt::WA_StyledBackground ) ) { QImage image( 1, 1, QImage::Format_ARGB32 ); image.fill( Qt::transparent ); QPainter painter( &image ); painter.translate( -w->rect().center() ); qwtDrawStyledBackground( w, &painter ); painter.end(); if ( qAlpha( image.pixel( 0, 0 ) ) != 0 ) return w; } return qwtBackgroundWidget( w->parentWidget() ); } static void qwtFillBackground( QPainter *painter, QWidget *widget, const QVector &fillRects ) { if ( fillRects.isEmpty() ) return; QRegion clipRegion; if ( painter->hasClipping() ) clipRegion = painter->transform().map( painter->clipRegion() ); else clipRegion = widget->contentsRect(); // Try to find out which widget fills // the unfilled areas of the styled background QWidget *bgWidget = qwtBackgroundWidget( widget->parentWidget() ); for ( int i = 0; i < fillRects.size(); i++ ) { const QRect rect = fillRects[i].toAlignedRect(); if ( clipRegion.intersects( rect ) ) { QPixmap pm( rect.size() ); QwtPainter::fillPixmap( bgWidget, pm, widget->mapTo( bgWidget, rect.topLeft() ) ); painter->drawPixmap( rect, pm ); } } } static void qwtFillBackground( QPainter *painter, QwtPlotCanvas *canvas ) { QVector rects; if ( canvas->testAttribute( Qt::WA_StyledBackground ) ) { QwtStyleSheetRecorder recorder( canvas->size() ); QPainter p( &recorder ); qwtDrawStyledBackground( canvas, &p ); p.end(); if ( recorder.background.brush.isOpaque() ) rects = recorder.clipRects; else rects += canvas->rect(); } else { const QRectF r = canvas->rect(); const double radius = canvas->borderRadius(); if ( radius > 0.0 ) { QSizeF sz( radius, radius ); rects += QRectF( r.topLeft(), sz ); rects += QRectF( r.topRight() - QPointF( radius, 0 ), sz ); rects += QRectF( r.bottomRight() - QPointF( radius, radius ), sz ); rects += QRectF( r.bottomLeft() - QPointF( 0, radius ), sz ); } } qwtFillBackground( painter, canvas, rects); } class QwtPlotCanvas::PrivateData { public: PrivateData(): focusIndicator( NoFocusIndicator ), borderRadius( 0 ), paintAttributes( 0 ), backingStore( NULL ) { styleSheet.hasBorder = false; } ~PrivateData() { delete backingStore; } FocusIndicator focusIndicator; double borderRadius; QwtPlotCanvas::PaintAttributes paintAttributes; QPixmap *backingStore; struct StyleSheet { bool hasBorder; QPainterPath borderPath; QVector cornerRects; struct StyleSheetBackground { QBrush brush; QPointF origin; } background; } styleSheet; }; /*! \brief Constructor \param plot Parent plot widget \sa QwtPlot::setCanvas() */ QwtPlotCanvas::QwtPlotCanvas( QwtPlot *plot ): QFrame( plot ) { setFrameStyle( QFrame::Panel | QFrame::Sunken ); setLineWidth( 2 ); d_data = new PrivateData; #ifndef QT_NO_CURSOR setCursor( Qt::CrossCursor ); #endif setAutoFillBackground( true ); setPaintAttribute( QwtPlotCanvas::BackingStore, true ); setPaintAttribute( QwtPlotCanvas::Opaque, true ); setPaintAttribute( QwtPlotCanvas::HackStyledBackground, true ); } //! Destructor QwtPlotCanvas::~QwtPlotCanvas() { delete d_data; } //! Return parent plot widget QwtPlot *QwtPlotCanvas::plot() { return qobject_cast( parent() ); } //! Return parent plot widget const QwtPlot *QwtPlotCanvas::plot() const { return qobject_cast( parent() ); } /*! \brief Changing the paint attributes \param attribute Paint attribute \param on On/Off \sa testPaintAttribute(), backingStore() */ void QwtPlotCanvas::setPaintAttribute( PaintAttribute attribute, bool on ) { if ( bool( d_data->paintAttributes & attribute ) == on ) return; if ( on ) d_data->paintAttributes |= attribute; else d_data->paintAttributes &= ~attribute; switch ( attribute ) { case BackingStore: { if ( on ) { if ( d_data->backingStore == NULL ) d_data->backingStore = new QPixmap(); if ( isVisible() ) { #if QT_VERSION >= 0x050000 *d_data->backingStore = grab( rect() ); #else *d_data->backingStore = QPixmap::grabWidget( this, rect() ); #endif } } else { delete d_data->backingStore; d_data->backingStore = NULL; } break; } case Opaque: { if ( on ) setAttribute( Qt::WA_OpaquePaintEvent, true ); break; } case HackStyledBackground: case ImmediatePaint: { break; } } } /*! Test whether a paint attribute is enabled \param attribute Paint attribute \return true, when attribute is enabled \sa setPaintAttribute() */ bool QwtPlotCanvas::testPaintAttribute( PaintAttribute attribute ) const { return d_data->paintAttributes & attribute; } //! \return Backing store, might be null const QPixmap *QwtPlotCanvas::backingStore() const { return d_data->backingStore; } //! Invalidate the internal backing store void QwtPlotCanvas::invalidateBackingStore() { if ( d_data->backingStore ) *d_data->backingStore = QPixmap(); } /*! Set the focus indicator \sa FocusIndicator, focusIndicator() */ void QwtPlotCanvas::setFocusIndicator( FocusIndicator focusIndicator ) { d_data->focusIndicator = focusIndicator; } /*! \return Focus indicator \sa FocusIndicator, setFocusIndicator() */ QwtPlotCanvas::FocusIndicator QwtPlotCanvas::focusIndicator() const { return d_data->focusIndicator; } /*! Set the radius for the corners of the border frame \param radius Radius of a rounded corner \sa borderRadius() */ void QwtPlotCanvas::setBorderRadius( double radius ) { d_data->borderRadius = qMax( 0.0, radius ); } /*! \return Radius for the corners of the border frame \sa setBorderRadius() */ double QwtPlotCanvas::borderRadius() const { return d_data->borderRadius; } /*! Qt event handler for QEvent::PolishRequest and QEvent::StyleChange \param event Qt Event \return See QFrame::event() */ bool QwtPlotCanvas::event( QEvent *event ) { if ( event->type() == QEvent::PolishRequest ) { if ( testPaintAttribute( QwtPlotCanvas::Opaque ) ) { // Setting a style sheet changes the // Qt::WA_OpaquePaintEvent attribute, but we insist // on painting the background. setAttribute( Qt::WA_OpaquePaintEvent, true ); } } if ( event->type() == QEvent::PolishRequest || event->type() == QEvent::StyleChange ) { updateStyleSheetInfo(); } return QFrame::event( event ); } /*! Paint event \param event Paint event */ void QwtPlotCanvas::paintEvent( QPaintEvent *event ) { QPainter painter( this ); painter.setClipRegion( event->region() ); if ( testPaintAttribute( QwtPlotCanvas::BackingStore ) && d_data->backingStore != NULL ) { QPixmap &bs = *d_data->backingStore; if ( bs.size() != size() ) { bs = QwtPainter::backingStore( this, size() ); if ( testAttribute(Qt::WA_StyledBackground) ) { QPainter p( &bs ); qwtFillBackground( &p, this ); drawCanvas( &p, true ); } else { QPainter p; if ( d_data->borderRadius <= 0.0 ) { QwtPainter::fillPixmap( this, bs ); p.begin( &bs ); drawCanvas( &p, false ); } else { p.begin( &bs ); qwtFillBackground( &p, this ); drawCanvas( &p, true ); } if ( frameWidth() > 0 ) drawBorder( &p ); } } painter.drawPixmap( 0, 0, *d_data->backingStore ); } else { if ( testAttribute(Qt::WA_StyledBackground ) ) { if ( testAttribute( Qt::WA_OpaquePaintEvent ) ) { qwtFillBackground( &painter, this ); drawCanvas( &painter, true ); } else { drawCanvas( &painter, false ); } } else { if ( testAttribute( Qt::WA_OpaquePaintEvent ) ) { if ( autoFillBackground() ) { qwtFillBackground( &painter, this ); qwtDrawBackground( &painter, this ); } } else { if ( borderRadius() > 0.0 ) { QPainterPath clipPath; clipPath.addRect( rect() ); clipPath = clipPath.subtracted( borderPath( rect() ) ); painter.save(); painter.setClipPath( clipPath, Qt::IntersectClip ); qwtFillBackground( &painter, this ); qwtDrawBackground( &painter, this ); painter.restore(); } } drawCanvas( &painter, false ); if ( frameWidth() > 0 ) drawBorder( &painter ); } } if ( hasFocus() && focusIndicator() == CanvasFocusIndicator ) drawFocusIndicator( &painter ); } void QwtPlotCanvas::drawCanvas( QPainter *painter, bool withBackground ) { bool hackStyledBackground = false; if ( withBackground && testAttribute( Qt::WA_StyledBackground ) && testPaintAttribute( HackStyledBackground ) ) { // Antialiasing rounded borders is done by // inserting pixels with colors between the // border color and the color on the canvas, // When the border is painted before the plot items // these colors are interpolated for the canvas // and the plot items need to be clipped excluding // the anialiased pixels. In situations, where // the plot items fill the area at the rounded // borders this is noticeable. // The only way to avoid these annoying "artefacts" // is to paint the border on top of the plot items. if ( d_data->styleSheet.hasBorder && !d_data->styleSheet.borderPath.isEmpty() ) { // We have a border with at least one rounded corner hackStyledBackground = true; } } if ( withBackground ) { painter->save(); if ( testAttribute( Qt::WA_StyledBackground ) ) { if ( hackStyledBackground ) { // paint background without border painter->setPen( Qt::NoPen ); painter->setBrush( d_data->styleSheet.background.brush ); painter->setBrushOrigin( d_data->styleSheet.background.origin ); painter->setClipPath( d_data->styleSheet.borderPath ); painter->drawRect( contentsRect() ); } else { qwtDrawStyledBackground( this, painter ); } } else if ( autoFillBackground() ) { painter->setPen( Qt::NoPen ); painter->setBrush( palette().brush( backgroundRole() ) ); if ( d_data->borderRadius > 0.0 && ( rect() == frameRect() ) ) { if ( frameWidth() > 0 ) { painter->setClipPath( borderPath( rect() ) ); painter->drawRect( rect() ); } else { painter->setRenderHint( QPainter::Antialiasing, true ); painter->drawPath( borderPath( rect() ) ); } } else { painter->drawRect( rect() ); } } painter->restore(); } painter->save(); if ( !d_data->styleSheet.borderPath.isEmpty() ) { painter->setClipPath( d_data->styleSheet.borderPath, Qt::IntersectClip ); } else { if ( d_data->borderRadius > 0.0 ) painter->setClipPath( borderPath( frameRect() ), Qt::IntersectClip ); else painter->setClipRect( contentsRect(), Qt::IntersectClip ); } plot()->drawCanvas( painter ); painter->restore(); if ( withBackground && hackStyledBackground ) { // Now paint the border on top QStyleOptionFrame opt; opt.initFrom(this); style()->drawPrimitive( QStyle::PE_Frame, &opt, painter, this); } } /*! Draw the border of the plot canvas \param painter Painter \sa setBorderRadius() */ void QwtPlotCanvas::drawBorder( QPainter *painter ) { if ( d_data->borderRadius > 0 ) { if ( frameWidth() > 0 ) { QwtPainter::drawRoundedFrame( painter, QRectF( frameRect() ), d_data->borderRadius, d_data->borderRadius, palette(), frameWidth(), frameStyle() ); } } else { #if QT_VERSION >= 0x040500 //QStyleOptionFrameV3 opt; QStyleOptionFrame opt; // Note QStyleOptionFrameV3 is typedef to QStyleOptionFrame opt.init(this); int frameShape = frameStyle() & QFrame::Shape_Mask; int frameShadow = frameStyle() & QFrame::Shadow_Mask; opt.frameShape = QFrame::Shape( int( opt.frameShape ) | frameShape ); #if 0 opt.rect = frameRect(); #endif switch (frameShape) { case QFrame::Box: case QFrame::HLine: case QFrame::VLine: case QFrame::StyledPanel: case QFrame::Panel: { opt.lineWidth = lineWidth(); opt.midLineWidth = midLineWidth(); break; } default: { opt.lineWidth = frameWidth(); break; } } if ( frameShadow == Sunken ) opt.state |= QStyle::State_Sunken; else if ( frameShadow == Raised ) opt.state |= QStyle::State_Raised; style()->drawControl(QStyle::CE_ShapedFrame, &opt, painter, this); #else drawFrame( painter ); #endif } } /*! Resize event \param event Resize event */ void QwtPlotCanvas::resizeEvent( QResizeEvent *event ) { QFrame::resizeEvent( event ); updateStyleSheetInfo(); } /*! Draw the focus indication \param painter Painter */ void QwtPlotCanvas::drawFocusIndicator( QPainter *painter ) { const int margin = 1; QRect focusRect = contentsRect(); focusRect.setRect( focusRect.x() + margin, focusRect.y() + margin, focusRect.width() - 2 * margin, focusRect.height() - 2 * margin ); QwtPainter::drawFocusRect( painter, this, focusRect ); } /*! Invalidate the paint cache and repaint the canvas \sa invalidatePaintCache() */ void QwtPlotCanvas::replot() { invalidateBackingStore(); if ( testPaintAttribute( QwtPlotCanvas::ImmediatePaint ) ) repaint( contentsRect() ); else update( contentsRect() ); } //! Update the cached information about the current style sheet void QwtPlotCanvas::updateStyleSheetInfo() { if ( !testAttribute(Qt::WA_StyledBackground ) ) return; QwtStyleSheetRecorder recorder( size() ); QPainter painter( &recorder ); QStyleOption opt; opt.initFrom(this); style()->drawPrimitive( QStyle::PE_Widget, &opt, &painter, this); painter.end(); d_data->styleSheet.hasBorder = !recorder.border.rectList.isEmpty(); d_data->styleSheet.cornerRects = recorder.clipRects; if ( recorder.background.path.isEmpty() ) { if ( !recorder.border.rectList.isEmpty() ) { d_data->styleSheet.borderPath = qwtCombinePathList( rect(), recorder.border.pathList ); } } else { d_data->styleSheet.borderPath = recorder.background.path; d_data->styleSheet.background.brush = recorder.background.brush; d_data->styleSheet.background.origin = recorder.background.origin; } } /*! Calculate the painter path for a styled or rounded border When the canvas has no styled background or rounded borders the painter path is empty. \param rect Bounding rectangle of the canvas \return Painter path, that can be used for clipping */ QPainterPath QwtPlotCanvas::borderPath( const QRect &rect ) const { if ( testAttribute(Qt::WA_StyledBackground ) ) { QwtStyleSheetRecorder recorder( rect.size() ); QPainter painter( &recorder ); QStyleOption opt; opt.initFrom(this); opt.rect = rect; style()->drawPrimitive( QStyle::PE_Widget, &opt, &painter, this); painter.end(); if ( !recorder.background.path.isEmpty() ) return recorder.background.path; if ( !recorder.border.rectList.isEmpty() ) return qwtCombinePathList( rect, recorder.border.pathList ); } else if ( d_data->borderRadius > 0.0 ) { double fw2 = frameWidth() * 0.5; QRectF r = QRectF(rect).adjusted( fw2, fw2, -fw2, -fw2 ); QPainterPath path; path.addRoundedRect( r, d_data->borderRadius, d_data->borderRadius ); return path; } return QPainterPath(); } connectome-workbench-1.4.2/src/Qwt/qwt_plot_canvas.h000066400000000000000000000115301360521144700225520ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_CANVAS_H #define QWT_PLOT_CANVAS_H #include "qwt_global.h" #include #include class QwtPlot; class QPixmap; /*! \brief Canvas of a QwtPlot. Canvas is the widget where all plot items are displayed \sa QwtPlot::setCanvas(), QwtPlotGLCanvas */ class QWT_EXPORT QwtPlotCanvas : public QFrame { Q_OBJECT Q_PROPERTY( double borderRadius READ borderRadius WRITE setBorderRadius ) public: /*! \brief Paint attributes The default setting enables BackingStore and Opaque. \sa setPaintAttribute(), testPaintAttribute() */ enum PaintAttribute { /*! \brief Paint double buffered reusing the content of the pixmap buffer when possible. Using a backing store might improve the performance significantly, when working with widget overlays ( like rubber bands ). Disabling the cache might improve the performance for incremental paints (using QwtPlotDirectPainter ). \sa backingStore(), invalidateBackingStore() */ BackingStore = 1, /*! \brief Try to fill the complete contents rectangle of the plot canvas When using styled backgrounds Qt assumes, that the canvas doesn't fill its area completely ( f.e because of rounded borders ) and fills the area below the canvas. When this is done with gradients it might result in a serious performance bottleneck - depending on the size. When the Opaque attribute is enabled the canvas tries to identify the gaps with some heuristics and to fill those only. \warning Will not work for semitransparent backgrounds */ Opaque = 2, /*! \brief Try to improve painting of styled backgrounds QwtPlotCanvas supports the box model attributes for customizing the layout with style sheets. Unfortunately the design of Qt style sheets has no concept how to handle backgrounds with rounded corners - beside of padding. When HackStyledBackground is enabled the plot canvas tries to separate the background from the background border by reverse engineering to paint the background before and the border after the plot items. In this order the border gets perfectly antialiased and you can avoid some pixel artifacts in the corners. */ HackStyledBackground = 4, /*! When ImmediatePaint is set replot() calls repaint() instead of update(). \sa replot(), QWidget::repaint(), QWidget::update() */ ImmediatePaint = 8 }; //! Paint attributes typedef QFlags PaintAttributes; /*! \brief Focus indicator The default setting is NoFocusIndicator \sa setFocusIndicator(), focusIndicator(), paintFocus() */ enum FocusIndicator { //! Don't paint a focus indicator NoFocusIndicator, /*! The focus is related to the complete canvas. Paint the focus indicator using paintFocus() */ CanvasFocusIndicator, /*! The focus is related to an item (curve, point, ...) on the canvas. It is up to the application to display a focus indication using f.e. highlighting. */ ItemFocusIndicator }; explicit QwtPlotCanvas( QwtPlot * = NULL ); virtual ~QwtPlotCanvas(); QwtPlot *plot(); const QwtPlot *plot() const; void setFocusIndicator( FocusIndicator ); FocusIndicator focusIndicator() const; void setBorderRadius( double ); double borderRadius() const; void setPaintAttribute( PaintAttribute, bool on = true ); bool testPaintAttribute( PaintAttribute ) const; const QPixmap *backingStore() const; void invalidateBackingStore(); virtual bool event( QEvent * ); Q_INVOKABLE QPainterPath borderPath( const QRect & ) const; public Q_SLOTS: void replot(); protected: virtual void paintEvent( QPaintEvent * ); virtual void resizeEvent( QResizeEvent * ); virtual void drawFocusIndicator( QPainter * ); virtual void drawBorder( QPainter * ); void updateStyleSheetInfo(); private: void drawCanvas( QPainter *, bool withBackground ); class PrivateData; PrivateData *d_data; }; Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotCanvas::PaintAttributes ) #endif connectome-workbench-1.4.2/src/Qwt/qwt_plot_curve.cpp000066400000000000000000000745601360521144700227720ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_curve.h" #include "qwt_point_data.h" #include "qwt_math.h" #include "qwt_clipper.h" #include "qwt_painter.h" #include "qwt_scale_map.h" #include "qwt_plot.h" #include "qwt_curve_fitter.h" #include "qwt_symbol.h" #include "qwt_point_mapper.h" #include #include #include #include static void qwtUpdateLegendIconSize( QwtPlotCurve *curve ) { if ( curve->symbol() && curve->testLegendAttribute( QwtPlotCurve::LegendShowSymbol ) ) { QSize sz = curve->symbol()->boundingRect().size(); sz += QSize( 2, 2 ); // margin if ( curve->testLegendAttribute( QwtPlotCurve::LegendShowLine ) ) { // Avoid, that the line is completely covered by the symbol int w = qCeil( 1.5 * sz.width() ); if ( w % 2 ) w++; sz.setWidth( qMax( 8, w ) ); } curve->setLegendIconSize( sz ); } } static int qwtVerifyRange( int size, int &i1, int &i2 ) { if ( size < 1 ) return 0; i1 = qBound( 0, i1, size - 1 ); i2 = qBound( 0, i2, size - 1 ); if ( i1 > i2 ) qSwap( i1, i2 ); return ( i2 - i1 + 1 ); } class QwtPlotCurve::PrivateData { public: PrivateData(): style( QwtPlotCurve::Lines ), baseline( 0.0 ), symbol( NULL ), attributes( 0 ), paintAttributes( QwtPlotCurve::ClipPolygons | QwtPlotCurve::FilterPoints ), legendAttributes( 0 ) { pen = QPen( Qt::black ); curveFitter = new QwtSplineCurveFitter; } ~PrivateData() { delete symbol; delete curveFitter; } QwtPlotCurve::CurveStyle style; double baseline; const QwtSymbol *symbol; QwtCurveFitter *curveFitter; QPen pen; QBrush brush; QwtPlotCurve::CurveAttributes attributes; QwtPlotCurve::PaintAttributes paintAttributes; QwtPlotCurve::LegendAttributes legendAttributes; }; /*! Constructor \param title Title of the curve */ QwtPlotCurve::QwtPlotCurve( const QwtText &title ): QwtPlotSeriesItem( title ) { init(); } /*! Constructor \param title Title of the curve */ QwtPlotCurve::QwtPlotCurve( const QString &title ): QwtPlotSeriesItem( QwtText( title ) ) { init(); } //! Destructor QwtPlotCurve::~QwtPlotCurve() { delete d_data; } //! Initialize internal members void QwtPlotCurve::init() { setItemAttribute( QwtPlotItem::Legend ); setItemAttribute( QwtPlotItem::AutoScale ); d_data = new PrivateData; setData( new QwtPointSeriesData() ); setZ( 20.0 ); } //! \return QwtPlotItem::Rtti_PlotCurve int QwtPlotCurve::rtti() const { return QwtPlotItem::Rtti_PlotCurve; } /*! Specify an attribute how to draw the curve \param attribute Paint attribute \param on On/Off \sa testPaintAttribute() */ void QwtPlotCurve::setPaintAttribute( PaintAttribute attribute, bool on ) { if ( on ) d_data->paintAttributes |= attribute; else d_data->paintAttributes &= ~attribute; } /*! \return True, when attribute is enabled \sa setPaintAttribute() */ bool QwtPlotCurve::testPaintAttribute( PaintAttribute attribute ) const { return ( d_data->paintAttributes & attribute ); } /*! Specify an attribute how to draw the legend icon \param attribute Attribute \param on On/Off /sa testLegendAttribute(). legendIcon() */ void QwtPlotCurve::setLegendAttribute( LegendAttribute attribute, bool on ) { if ( on != testLegendAttribute( attribute ) ) { if ( on ) d_data->legendAttributes |= attribute; else d_data->legendAttributes &= ~attribute; qwtUpdateLegendIconSize( this ); legendChanged(); } } /*! \return True, when attribute is enabled \sa setLegendAttribute() */ bool QwtPlotCurve::testLegendAttribute( LegendAttribute attribute ) const { return ( d_data->legendAttributes & attribute ); } /*! Set the curve's drawing style \param style Curve style \sa style() */ void QwtPlotCurve::setStyle( CurveStyle style ) { if ( style != d_data->style ) { d_data->style = style; legendChanged(); itemChanged(); } } /*! \return Style of the curve \sa setStyle() */ QwtPlotCurve::CurveStyle QwtPlotCurve::style() const { return d_data->style; } /*! \brief Assign a symbol The curve will take the ownership of the symbol, hence the previously set symbol will be delete by setting a new one. If \p symbol is \c NULL no symbol will be drawn. \param symbol Symbol \sa symbol() */ void QwtPlotCurve::setSymbol( QwtSymbol *symbol ) { if ( symbol != d_data->symbol ) { delete d_data->symbol; d_data->symbol = symbol; qwtUpdateLegendIconSize( this ); legendChanged(); itemChanged(); } } /*! \return Current symbol or NULL, when no symbol has been assigned \sa setSymbol() */ const QwtSymbol *QwtPlotCurve::symbol() const { return d_data->symbol; } /*! Build and assign a pen In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it non cosmetic ( see QPen::isCosmetic() ). This method has been introduced to hide this incompatibility. \param color Pen color \param width Pen width \param style Pen style \sa pen(), brush() */ void QwtPlotCurve::setPen( const QColor &color, qreal width, Qt::PenStyle style ) { setPen( QPen( color, width, style ) ); } /*! Assign a pen \param pen New pen \sa pen(), brush() */ void QwtPlotCurve::setPen( const QPen &pen ) { if ( pen != d_data->pen ) { d_data->pen = pen; legendChanged(); itemChanged(); } } /*! \return Pen used to draw the lines \sa setPen(), brush() */ const QPen& QwtPlotCurve::pen() const { return d_data->pen; } /*! \brief Assign a brush. In case of brush.style() != QBrush::NoBrush and style() != QwtPlotCurve::Sticks the area between the curve and the baseline will be filled. In case !brush.color().isValid() the area will be filled by pen.color(). The fill algorithm simply connects the first and the last curve point to the baseline. So the curve data has to be sorted (ascending or descending). \param brush New brush \sa brush(), setBaseline(), baseline() */ void QwtPlotCurve::setBrush( const QBrush &brush ) { if ( brush != d_data->brush ) { d_data->brush = brush; legendChanged(); itemChanged(); } } /*! \return Brush used to fill the area between lines and the baseline \sa setBrush(), setBaseline(), baseline() */ const QBrush& QwtPlotCurve::brush() const { return d_data->brush; } /*! Draw an interval of the curve \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rectangle of the canvas \param from Index of the first point to be painted \param to Index of the last point to be painted. If to < 0 the curve will be painted to its last point. \sa drawCurve(), drawSymbols(), */ void QwtPlotCurve::drawSeries( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { const size_t numSamples = dataSize(); if ( !painter || numSamples <= 0 ) return; if ( to < 0 ) to = numSamples - 1; if ( qwtVerifyRange( numSamples, from, to ) > 0 ) { painter->save(); painter->setPen( d_data->pen ); /* Qt 4.0.0 is slow when drawing lines, but it's even slower when the painter has a brush. So we don't set the brush before we really need it. */ drawCurve( painter, d_data->style, xMap, yMap, canvasRect, from, to ); painter->restore(); if ( d_data->symbol && ( d_data->symbol->style() != QwtSymbol::NoSymbol ) ) { painter->save(); drawSymbols( painter, *d_data->symbol, xMap, yMap, canvasRect, from, to ); painter->restore(); } } } /*! \brief Draw the line part (without symbols) of a curve interval. \param painter Painter \param style curve style, see QwtPlotCurve::CurveStyle \param xMap x map \param yMap y map \param canvasRect Contents rectangle of the canvas \param from index of the first point to be painted \param to index of the last point to be painted \sa draw(), drawDots(), drawLines(), drawSteps(), drawSticks() */ void QwtPlotCurve::drawCurve( QPainter *painter, int style, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { switch ( style ) { case Lines: if ( testCurveAttribute( Fitted ) ) { // we always need the complete // curve for fitting from = 0; to = dataSize() - 1; } drawLines( painter, xMap, yMap, canvasRect, from, to ); break; case Sticks: drawSticks( painter, xMap, yMap, canvasRect, from, to ); break; case Steps: drawSteps( painter, xMap, yMap, canvasRect, from, to ); break; case Dots: drawDots( painter, xMap, yMap, canvasRect, from, to ); break; case NoCurve: default: break; } } /*! \brief Draw lines If the CurveAttribute Fitted is enabled a QwtCurveFitter tries to interpolate/smooth the curve, before it is painted. \param painter Painter \param xMap x map \param yMap y map \param canvasRect Contents rectangle of the canvas \param from index of the first point to be painted \param to index of the last point to be painted \sa setCurveAttribute(), setCurveFitter(), draw(), drawLines(), drawDots(), drawSteps(), drawSticks() */ void QwtPlotCurve::drawLines( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { if ( from > to ) return; const bool doAlign = QwtPainter::roundingAlignment( painter ); const bool doFit = ( d_data->attributes & Fitted ) && d_data->curveFitter; const bool doFill = ( d_data->brush.style() != Qt::NoBrush ) && ( d_data->brush.color().alpha() > 0 ); QRectF clipRect; if ( d_data->paintAttributes & ClipPolygons ) { qreal pw = qMax( qreal( 1.0 ), painter->pen().widthF()); clipRect = canvasRect.adjusted(-pw, -pw, pw, pw); } bool doIntegers = false; #if QT_VERSION < 0x040800 // For Qt <= 4.7 the raster paint engine is significantly faster // for rendering QPolygon than for QPolygonF. So let's // see if we can use it. if ( painter->paintEngine()->type() == QPaintEngine::Raster ) { // In case of filling or fitting performance doesn't count // because both operations are much more expensive // then drawing the polyline itself if ( !doFit && !doFill ) doIntegers = true; } #endif const bool noDuplicates = d_data->paintAttributes & FilterPoints; QwtPointMapper mapper; mapper.setFlag( QwtPointMapper::RoundPoints, doAlign ); mapper.setFlag( QwtPointMapper::WeedOutPoints, noDuplicates ); mapper.setBoundingRect( canvasRect ); if ( doIntegers ) { QPolygon polyline = mapper.toPolygon( xMap, yMap, data(), from, to ); if ( d_data->paintAttributes & ClipPolygons ) { polyline = QwtClipper::clipPolygon( clipRect.toAlignedRect(), polyline, false ); } QwtPainter::drawPolyline( painter, polyline ); } else { QPolygonF polyline = mapper.toPolygonF( xMap, yMap, data(), from, to ); if ( doFit ) polyline = d_data->curveFitter->fitCurve( polyline ); if ( doFill ) { if ( painter->pen().style() != Qt::NoPen ) { // here we are wasting memory for the filled copy, // do polygon clipping twice etc .. TODO QPolygonF filled = polyline; fillCurve( painter, xMap, yMap, canvasRect, filled ); filled.clear(); if ( d_data->paintAttributes & ClipPolygons ) { polyline = QwtClipper::clipPolygonF( clipRect, polyline, false ); } QwtPainter::drawPolyline( painter, polyline ); } else { fillCurve( painter, xMap, yMap, canvasRect, polyline ); } } else { if ( d_data->paintAttributes & ClipPolygons ) { polyline = QwtClipper::clipPolygonF( clipRect, polyline, false ); } QwtPainter::drawPolyline( painter, polyline ); } } } /*! Draw sticks \param painter Painter \param xMap x map \param yMap y map \param canvasRect Contents rectangle of the canvas \param from index of the first point to be painted \param to index of the last point to be painted \sa draw(), drawCurve(), drawDots(), drawLines(), drawSteps() */ void QwtPlotCurve::drawSticks( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &, int from, int to ) const { painter->save(); painter->setRenderHint( QPainter::Antialiasing, false ); const bool doAlign = QwtPainter::roundingAlignment( painter ); double x0 = xMap.transform( d_data->baseline ); double y0 = yMap.transform( d_data->baseline ); if ( doAlign ) { x0 = qRound( x0 ); y0 = qRound( y0 ); } const Qt::Orientation o = orientation(); const QwtSeriesData *series = data(); for ( int i = from; i <= to; i++ ) { const QPointF sample = series->sample( i ); double xi = xMap.transform( sample.x() ); double yi = yMap.transform( sample.y() ); if ( doAlign ) { xi = qRound( xi ); yi = qRound( yi ); } if ( o == Qt::Horizontal ) QwtPainter::drawLine( painter, x0, yi, xi, yi ); else QwtPainter::drawLine( painter, xi, y0, xi, yi ); } painter->restore(); } /*! Draw dots \param painter Painter \param xMap x map \param yMap y map \param canvasRect Contents rectangle of the canvas \param from index of the first point to be painted \param to index of the last point to be painted \sa draw(), drawCurve(), drawSticks(), drawLines(), drawSteps() */ void QwtPlotCurve::drawDots( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { const QColor color = painter->pen().color(); if ( painter->pen().style() == Qt::NoPen || color.alpha() == 0 ) { return; } const bool doFill = ( d_data->brush.style() != Qt::NoBrush ) && ( d_data->brush.color().alpha() > 0 ); const bool doAlign = QwtPainter::roundingAlignment( painter ); QwtPointMapper mapper; mapper.setBoundingRect( canvasRect ); mapper.setFlag( QwtPointMapper::RoundPoints, doAlign ); if ( d_data->paintAttributes & FilterPoints ) { if ( ( color.alpha() == 255 ) && !( painter->renderHints() & QPainter::Antialiasing ) ) { mapper.setFlag( QwtPointMapper::WeedOutPoints, true ); } } if ( doFill ) { mapper.setFlag( QwtPointMapper::WeedOutPoints, false ); QPolygonF points = mapper.toPointsF( xMap, yMap, data(), from, to ); QwtPainter::drawPoints( painter, points ); fillCurve( painter, xMap, yMap, canvasRect, points ); } else if ( d_data->paintAttributes & ImageBuffer ) { const QImage image = mapper.toImage( xMap, yMap, data(), from, to, d_data->pen, painter->testRenderHint( QPainter::Antialiasing ), renderThreadCount() ); painter->drawImage( canvasRect.toAlignedRect(), image ); } else if ( d_data->paintAttributes & MinimizeMemory ) { const QwtSeriesData *series = data(); for ( int i = from; i <= to; i++ ) { const QPointF sample = series->sample( i ); double xi = xMap.transform( sample.x() ); double yi = yMap.transform( sample.y() ); if ( doAlign ) { xi = qRound( xi ); yi = qRound( yi ); } QwtPainter::drawPoint( painter, QPointF( xi, yi ) ); } } else { if ( doAlign ) { const QPolygon points = mapper.toPoints( xMap, yMap, data(), from, to ); QwtPainter::drawPoints( painter, points ); } else { const QPolygonF points = mapper.toPointsF( xMap, yMap, data(), from, to ); QwtPainter::drawPoints( painter, points ); } } } /*! Draw step function The direction of the steps depends on Inverted attribute. \param painter Painter \param xMap x map \param yMap y map \param canvasRect Contents rectangle of the canvas \param from index of the first point to be painted \param to index of the last point to be painted \sa CurveAttribute, setCurveAttribute(), draw(), drawCurve(), drawDots(), drawLines(), drawSticks() */ void QwtPlotCurve::drawSteps( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { const bool doAlign = QwtPainter::roundingAlignment( painter ); QPolygonF polygon( 2 * ( to - from ) + 1 ); QPointF *points = polygon.data(); bool inverted = orientation() == Qt::Vertical; if ( d_data->attributes & Inverted ) inverted = !inverted; const QwtSeriesData *series = data(); int i, ip; for ( i = from, ip = 0; i <= to; i++, ip += 2 ) { const QPointF sample = series->sample( i ); double xi = xMap.transform( sample.x() ); double yi = yMap.transform( sample.y() ); if ( doAlign ) { xi = qRound( xi ); yi = qRound( yi ); } if ( ip > 0 ) { const QPointF &p0 = points[ip - 2]; QPointF &p = points[ip - 1]; if ( inverted ) { p.rx() = p0.x(); p.ry() = yi; } else { p.rx() = xi; p.ry() = p0.y(); } } points[ip].rx() = xi; points[ip].ry() = yi; } if ( d_data->paintAttributes & ClipPolygons ) { const QPolygonF clipped = QwtClipper::clipPolygonF( canvasRect, polygon, false ); QwtPainter::drawPolyline( painter, clipped ); } else { QwtPainter::drawPolyline( painter, polygon ); } if ( d_data->brush.style() != Qt::NoBrush ) fillCurve( painter, xMap, yMap, canvasRect, polygon ); } /*! Specify an attribute for drawing the curve \param attribute Curve attribute \param on On/Off /sa testCurveAttribute(), setCurveFitter() */ void QwtPlotCurve::setCurveAttribute( CurveAttribute attribute, bool on ) { if ( bool( d_data->attributes & attribute ) == on ) return; if ( on ) d_data->attributes |= attribute; else d_data->attributes &= ~attribute; itemChanged(); } /*! \return true, if attribute is enabled \sa setCurveAttribute() */ bool QwtPlotCurve::testCurveAttribute( CurveAttribute attribute ) const { return d_data->attributes & attribute; } /*! Assign a curve fitter The curve fitter "smooths" the curve points, when the Fitted CurveAttribute is set. setCurveFitter(NULL) also disables curve fitting. The curve fitter operates on the translated points ( = widget coordinates) to be functional for logarithmic scales. Obviously this is less performant for fitting algorithms, that reduce the number of points. For situations, where curve fitting is used to improve the performance of painting huge series of points it might be better to execute the fitter on the curve points once and to cache the result in the QwtSeriesData object. \param curveFitter() Curve fitter \sa Fitted */ void QwtPlotCurve::setCurveFitter( QwtCurveFitter *curveFitter ) { delete d_data->curveFitter; d_data->curveFitter = curveFitter; itemChanged(); } /*! Get the curve fitter. If curve fitting is disabled NULL is returned. \return Curve fitter \sa setCurveFitter(), Fitted */ QwtCurveFitter *QwtPlotCurve::curveFitter() const { return d_data->curveFitter; } /*! Fill the area between the curve and the baseline with the curve brush \param painter Painter \param xMap x map \param yMap y map \param canvasRect Contents rectangle of the canvas \param polygon Polygon - will be modified ! \sa setBrush(), setBaseline(), setStyle() */ void QwtPlotCurve::fillCurve( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, QPolygonF &polygon ) const { if ( d_data->brush.style() == Qt::NoBrush ) return; closePolyline( painter, xMap, yMap, polygon ); if ( polygon.count() <= 2 ) // a line can't be filled return; QBrush brush = d_data->brush; if ( !brush.color().isValid() ) brush.setColor( d_data->pen.color() ); if ( d_data->paintAttributes & ClipPolygons ) polygon = QwtClipper::clipPolygonF( canvasRect, polygon, true ); painter->save(); painter->setPen( Qt::NoPen ); painter->setBrush( brush ); QwtPainter::drawPolygon( painter, polygon ); painter->restore(); } /*! \brief Complete a polygon to be a closed polygon including the area between the original polygon and the baseline. \param painter Painter \param xMap X map \param yMap Y map \param polygon Polygon to be completed */ void QwtPlotCurve::closePolyline( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, QPolygonF &polygon ) const { if ( polygon.size() < 2 ) return; const bool doAlign = QwtPainter::roundingAlignment( painter ); double baseline = d_data->baseline; if ( orientation() == Qt::Vertical ) { if ( yMap.transformation() ) baseline = yMap.transformation()->bounded( baseline ); double refY = yMap.transform( baseline ); if ( doAlign ) refY = qRound( refY ); polygon += QPointF( polygon.last().x(), refY ); polygon += QPointF( polygon.first().x(), refY ); } else { if ( xMap.transformation() ) baseline = xMap.transformation()->bounded( baseline ); double refX = xMap.transform( baseline ); if ( doAlign ) refX = qRound( refX ); polygon += QPointF( refX, polygon.last().y() ); polygon += QPointF( refX, polygon.first().y() ); } } /*! Draw symbols \param painter Painter \param symbol Curve symbol \param xMap x map \param yMap y map \param canvasRect Contents rectangle of the canvas \param from Index of the first point to be painted \param to Index of the last point to be painted \sa setSymbol(), drawSeries(), drawCurve() */ void QwtPlotCurve::drawSymbols( QPainter *painter, const QwtSymbol &symbol, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { QwtPointMapper mapper; mapper.setFlag( QwtPointMapper::RoundPoints, QwtPainter::roundingAlignment( painter ) ); mapper.setFlag( QwtPointMapper::WeedOutPoints, testPaintAttribute( QwtPlotCurve::FilterPoints ) ); mapper.setBoundingRect( canvasRect ); const int chunkSize = 500; for ( int i = from; i <= to; i += chunkSize ) { const int n = qMin( chunkSize, to - i + 1 ); const QPolygonF points = mapper.toPointsF( xMap, yMap, data(), i, i + n - 1 ); if ( points.size() > 0 ) symbol.drawSymbols( painter, points ); } } /*! \brief Set the value of the baseline The baseline is needed for filling the curve with a brush or the Sticks drawing style. The interpretation of the baseline depends on the orientation(). With Qt::Horizontal, the baseline is interpreted as a horizontal line at y = baseline(), with Qt::Vertical, it is interpreted as a vertical line at x = baseline(). The default value is 0.0. \param value Value of the baseline \sa baseline(), setBrush(), setStyle(), QwtPlotAbstractSeriesItem::orientation() */ void QwtPlotCurve::setBaseline( double value ) { if ( d_data->baseline != value ) { d_data->baseline = value; itemChanged(); } } /*! \return Value of the baseline \sa setBaseline() */ double QwtPlotCurve::baseline() const { return d_data->baseline; } /*! Find the closest curve point for a specific position \param pos Position, where to look for the closest curve point \param dist If dist != NULL, closestPoint() returns the distance between the position and the closest curve point \return Index of the closest curve point, or -1 if none can be found ( f.e when the curve has no points ) \note closestPoint() implements a dumb algorithm, that iterates over all points */ int QwtPlotCurve::closestPoint( const QPoint &pos, double *dist ) const { const size_t numSamples = dataSize(); if ( plot() == NULL || numSamples <= 0 ) return -1; const QwtSeriesData *series = data(); const QwtScaleMap xMap = plot()->canvasMap( xAxis() ); const QwtScaleMap yMap = plot()->canvasMap( yAxis() ); int index = -1; double dmin = 1.0e10; for ( uint i = 0; i < numSamples; i++ ) { const QPointF sample = series->sample( i ); const double cx = xMap.transform( sample.x() ) - pos.x(); const double cy = yMap.transform( sample.y() ) - pos.y(); const double f = qwtSqr( cx ) + qwtSqr( cy ); if ( f < dmin ) { index = i; dmin = f; } } if ( dist ) *dist = qSqrt( dmin ); return index; } /*! \return Icon representing the curve on the legend \param index Index of the legend entry ( ignored as there is only one ) \param size Icon size \sa QwtPlotItem::setLegendIconSize(), QwtPlotItem::legendData() */ QwtGraphic QwtPlotCurve::legendIcon( int index, const QSizeF &size ) const { Q_UNUSED( index ); if ( size.isEmpty() ) return QwtGraphic(); QwtGraphic graphic; graphic.setDefaultSize( size ); graphic.setRenderHint( QwtGraphic::RenderPensUnscaled, true ); QPainter painter( &graphic ); painter.setRenderHint( QPainter::Antialiasing, testRenderHint( QwtPlotItem::RenderAntialiased ) ); if ( d_data->legendAttributes == 0 || d_data->legendAttributes & QwtPlotCurve::LegendShowBrush ) { QBrush brush = d_data->brush; if ( brush.style() == Qt::NoBrush && d_data->legendAttributes == 0 ) { if ( style() != QwtPlotCurve::NoCurve ) { brush = QBrush( pen().color() ); } else if ( d_data->symbol && ( d_data->symbol->style() != QwtSymbol::NoSymbol ) ) { brush = QBrush( d_data->symbol->pen().color() ); } } if ( brush.style() != Qt::NoBrush ) { QRectF r( 0, 0, size.width(), size.height() ); painter.fillRect( r, brush ); } } if ( d_data->legendAttributes & QwtPlotCurve::LegendShowLine ) { if ( pen() != Qt::NoPen ) { QPen pn = pen(); pn.setCapStyle( Qt::FlatCap ); painter.setPen( pn ); const double y = 0.5 * size.height(); QwtPainter::drawLine( &painter, 0.0, y, size.width(), y ); } } if ( d_data->legendAttributes & QwtPlotCurve::LegendShowSymbol ) { if ( d_data->symbol ) { QRectF r( 0, 0, size.width(), size.height() ); d_data->symbol->drawSymbol( &painter, r ); } } return graphic; } /*! Initialize data with an array of points. \param samples Vector of points \note QVector is implicitly shared \note QPolygonF is derived from QVector */ void QwtPlotCurve::setSamples( const QVector &samples ) { setData( new QwtPointSeriesData( samples ) ); } /*! Assign a series of points setSamples() is just a wrapper for setData() without any additional value - beside that it is easier to find for the developer. \param data Data \warning The item takes ownership of the data object, deleting it when its not used anymore. */ void QwtPlotCurve::setSamples( QwtSeriesData *data ) { setData( data ); } #ifndef QWT_NO_COMPAT /*! \brief Initialize the data by pointing to memory blocks which are not managed by QwtPlotCurve. setRawSamples is provided for efficiency. It is important to keep the pointers during the lifetime of the underlying QwtCPointerData class. \param xData pointer to x data \param yData pointer to y data \param size size of x and y \sa QwtCPointerData */ void QwtPlotCurve::setRawSamples( const double *xData, const double *yData, int size ) { setData( new QwtCPointerData( xData, yData, size ) ); } /*! Set data by copying x- and y-values from specified memory blocks. Contrary to setRawSamples(), this function makes a 'deep copy' of the data. \param xData pointer to x values \param yData pointer to y values \param size size of xData and yData \sa QwtPointArrayData */ void QwtPlotCurve::setSamples( const double *xData, const double *yData, int size ) { setData( new QwtPointArrayData( xData, yData, size ) ); } /*! \brief Initialize data with x- and y-arrays (explicitly shared) \param xData x data \param yData y data \sa QwtPointArrayData */ void QwtPlotCurve::setSamples( const QVector &xData, const QVector &yData ) { setData( new QwtPointArrayData( xData, yData ) ); } #endif // !QWT_NO_COMPAT connectome-workbench-1.4.2/src/Qwt/qwt_plot_curve.h000066400000000000000000000241151360521144700224260ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_CURVE_H #define QWT_PLOT_CURVE_H #include "qwt_global.h" #include "qwt_plot_seriesitem.h" #include "qwt_series_data.h" #include "qwt_text.h" #include #include class QPainter; class QPolygonF; class QwtScaleMap; class QwtSymbol; class QwtCurveFitter; /*! \brief A plot item, that represents a series of points A curve is the representation of a series of points in the x-y plane. It supports different display styles, interpolation ( f.e. spline ) and symbols. \par Usage

    a) Assign curve properties
    When a curve is created, it is configured to draw black solid lines with in QwtPlotCurve::Lines style and no symbols. You can change this by calling setPen(), setStyle() and setSymbol().
    b) Connect/Assign data.
    QwtPlotCurve gets its points using a QwtSeriesData object offering a bridge to the real storage of the points ( like QAbstractItemModel ). There are several convenience classes derived from QwtSeriesData, that also store the points inside ( like QStandardItemModel ). QwtPlotCurve also offers a couple of variations of setSamples(), that build QwtSeriesData objects from arrays internally.
    c) Attach the curve to a plot
    See QwtPlotItem::attach()
    \par Example: see examples/bode \sa QwtPointSeriesData, QwtSymbol, QwtScaleMap */ class QWT_EXPORT QwtPlotCurve: public QwtPlotSeriesItem, public QwtSeriesStore { public: /*! Curve styles. \sa setStyle(), style() */ enum CurveStyle { /*! Don't draw a curve. Note: This doesn't affect the symbols. */ NoCurve = -1, /*! Connect the points with straight lines. The lines might be interpolated depending on the 'Fitted' attribute. Curve fitting can be configured using setCurveFitter(). */ Lines, /*! Draw vertical or horizontal sticks ( depending on the orientation() ) from a baseline which is defined by setBaseline(). */ Sticks, /*! Connect the points with a step function. The step function is drawn from the left to the right or vice versa, depending on the QwtPlotCurve::Inverted attribute. */ Steps, /*! Draw dots at the locations of the data points. Note: This is different from a dotted line (see setPen()), and faster as a curve in QwtPlotCurve::NoStyle style and a symbol painting a point. */ Dots, /*! Styles >= QwtPlotCurve::UserCurve are reserved for derived classes of QwtPlotCurve that overload drawCurve() with additional application specific curve types. */ UserCurve = 100 }; /*! Attribute for drawing the curve \sa setCurveAttribute(), testCurveAttribute(), curveFitter() */ enum CurveAttribute { /*! For QwtPlotCurve::Steps only. Draws a step function from the right to the left. */ Inverted = 0x01, /*! Only in combination with QwtPlotCurve::Lines A QwtCurveFitter tries to interpolate/smooth the curve, before it is painted. \note Curve fitting requires temporary memory for calculating coefficients and additional points. If painting in QwtPlotCurve::Fitted mode is slow it might be better to fit the points, before they are passed to QwtPlotCurve. */ Fitted = 0x02 }; //! Curve attributes typedef QFlags CurveAttributes; /*! Attributes how to represent the curve on the legend \sa setLegendAttribute(), testLegendAttribute(), QwtPlotItem::legendData(), legendIcon() */ enum LegendAttribute { /*! QwtPlotCurve tries to find a color representing the curve and paints a rectangle with it. */ LegendNoAttribute = 0x00, /*! If the style() is not QwtPlotCurve::NoCurve a line is painted with the curve pen(). */ LegendShowLine = 0x01, /*! If the curve has a valid symbol it is painted. */ LegendShowSymbol = 0x02, /*! If the curve has a brush a rectangle filled with the curve brush() is painted. */ LegendShowBrush = 0x04 }; //! Legend attributes typedef QFlags LegendAttributes; /*! Attributes to modify the drawing algorithm. The default setting enables ClipPolygons | FilterPoints \sa setPaintAttribute(), testPaintAttribute() */ enum PaintAttribute { /*! Clip polygons before painting them. In situations, where points are far outside the visible area (f.e when zooming deep) this might be a substantial improvement for the painting performance */ ClipPolygons = 0x01, /*! Tries to reduce the data that has to be painted, by sorting out duplicates, or paintings outside the visible area. Might have a notable impact on curves with many close points. Only a couple of very basic filtering algorithms are implemented. */ FilterPoints = 0x02, /*! Minimize memory usage that is temporarily needed for the translated points, before they get painted. This might slow down the performance of painting */ MinimizeMemory = 0x04, /*! Render the points to a temporary image and paint the image. This is a very special optimization for Dots style, when having a huge amount of points. With a reasonable number of points QPainter::drawPoints() will be faster. */ ImageBuffer = 0x08 }; //! Paint attributes typedef QFlags PaintAttributes; explicit QwtPlotCurve( const QString &title = QString::null ); explicit QwtPlotCurve( const QwtText &title ); virtual ~QwtPlotCurve(); virtual int rtti() const; void setPaintAttribute( PaintAttribute, bool on = true ); bool testPaintAttribute( PaintAttribute ) const; void setLegendAttribute( LegendAttribute, bool on = true ); bool testLegendAttribute( LegendAttribute ) const; #ifndef QWT_NO_COMPAT void setRawSamples( const double *xData, const double *yData, int size ); void setSamples( const double *xData, const double *yData, int size ); void setSamples( const QVector &xData, const QVector &yData ); #endif void setSamples( const QVector & ); void setSamples( QwtSeriesData * ); int closestPoint( const QPoint &pos, double *dist = NULL ) const; double minXValue() const; double maxXValue() const; double minYValue() const; double maxYValue() const; void setCurveAttribute( CurveAttribute, bool on = true ); bool testCurveAttribute( CurveAttribute ) const; void setPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine ); void setPen( const QPen & ); const QPen &pen() const; void setBrush( const QBrush & ); const QBrush &brush() const; void setBaseline( double ); double baseline() const; void setStyle( CurveStyle style ); CurveStyle style() const; void setSymbol( QwtSymbol * ); const QwtSymbol *symbol() const; void setCurveFitter( QwtCurveFitter * ); QwtCurveFitter *curveFitter() const; virtual void drawSeries( QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; virtual QwtGraphic legendIcon( int index, const QSizeF & ) const; protected: void init(); virtual void drawCurve( QPainter *p, int style, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; virtual void drawSymbols( QPainter *p, const QwtSymbol &, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; virtual void drawLines( QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; virtual void drawSticks( QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; virtual void drawDots( QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; virtual void drawSteps( QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; virtual void fillCurve( QPainter *, const QwtScaleMap &, const QwtScaleMap &, const QRectF &canvasRect, QPolygonF & ) const; void closePolyline( QPainter *, const QwtScaleMap &, const QwtScaleMap &, QPolygonF & ) const; private: class PrivateData; PrivateData *d_data; }; //! boundingRect().left() inline double QwtPlotCurve::minXValue() const { return boundingRect().left(); } //! boundingRect().right() inline double QwtPlotCurve::maxXValue() const { return boundingRect().right(); } //! boundingRect().top() inline double QwtPlotCurve::minYValue() const { return boundingRect().top(); } //! boundingRect().bottom() inline double QwtPlotCurve::maxYValue() const { return boundingRect().bottom(); } Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotCurve::PaintAttributes ) Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotCurve::LegendAttributes ) Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotCurve::CurveAttributes ) #endif connectome-workbench-1.4.2/src/Qwt/qwt_plot_dict.cpp000066400000000000000000000111671360521144700225630ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include #include "qwt_plot_dict.h" class QwtPlotDict::PrivateData { public: class ItemList: public QList { public: void insertItem( QwtPlotItem *item ) { if ( item == NULL ) return; QList::iterator it = #ifdef WORKBENCH_REPLACE_QT_DEPRECATED std::upper_bound( begin(), end(), item, LessZThan() ); #else qUpperBound( begin(), end(), item, LessZThan() ); #endif insert( it, item ); } void removeItem( QwtPlotItem *item ) { if ( item == NULL ) return; QList::iterator it = #ifdef WORKBENCH_REPLACE_QT_DEPRECATED std::lower_bound( begin(), end(), item, LessZThan() ); #else qLowerBound( begin(), end(), item, LessZThan() ); #endif for ( ; it != end(); ++it ) { if ( item == *it ) { erase( it ); break; } } } private: class LessZThan { public: inline bool operator()( const QwtPlotItem *item1, const QwtPlotItem *item2 ) const { return item1->z() < item2->z(); } }; }; ItemList itemList; bool autoDelete; }; /*! Constructor Auto deletion is enabled. \sa setAutoDelete(), QwtPlotItem::attach() */ QwtPlotDict::QwtPlotDict() { d_data = new QwtPlotDict::PrivateData; d_data->autoDelete = true; } /*! Destructor If autoDelete() is on, all attached items will be deleted \sa setAutoDelete(), autoDelete(), QwtPlotItem::attach() */ QwtPlotDict::~QwtPlotDict() { detachItems( QwtPlotItem::Rtti_PlotItem, d_data->autoDelete ); delete d_data; } /*! En/Disable Auto deletion If Auto deletion is on all attached plot items will be deleted in the destructor of QwtPlotDict. The default value is on. \sa autoDelete(), insertItem() */ void QwtPlotDict::setAutoDelete( bool autoDelete ) { d_data->autoDelete = autoDelete; } /*! \return true if auto deletion is enabled \sa setAutoDelete(), insertItem() */ bool QwtPlotDict::autoDelete() const { return d_data->autoDelete; } /*! Insert a plot item \param item PlotItem \sa removeItem() */ void QwtPlotDict::insertItem( QwtPlotItem *item ) { d_data->itemList.insertItem( item ); } /*! Remove a plot item \param item PlotItem \sa insertItem() */ void QwtPlotDict::removeItem( QwtPlotItem *item ) { d_data->itemList.removeItem( item ); } /*! Detach items from the dictionary \param rtti In case of QwtPlotItem::Rtti_PlotItem detach all items otherwise only those items of the type rtti. \param autoDelete If true, delete all detached items */ void QwtPlotDict::detachItems( int rtti, bool autoDelete ) { PrivateData::ItemList list = d_data->itemList; QwtPlotItemIterator it = list.begin(); while ( it != list.end() ) { QwtPlotItem *item = *it; ++it; // increment before removing item from the list if ( rtti == QwtPlotItem::Rtti_PlotItem || item->rtti() == rtti ) { item->attach( NULL ); if ( autoDelete ) delete item; } } } /*! \brief A QwtPlotItemList of all attached plot items. Use caution when iterating these lists, as removing/detaching an item will invalidate the iterator. Instead you can place pointers to objects to be removed in a removal list, and traverse that list later. \return List of all attached plot items. */ const QwtPlotItemList &QwtPlotDict::itemList() const { return d_data->itemList; } /*! \return List of all attached plot items of a specific type. \param rtti See QwtPlotItem::RttiValues \sa QwtPlotItem::rtti() */ QwtPlotItemList QwtPlotDict::itemList( int rtti ) const { if ( rtti == QwtPlotItem::Rtti_PlotItem ) return d_data->itemList; QwtPlotItemList items; PrivateData::ItemList list = d_data->itemList; for ( QwtPlotItemIterator it = list.begin(); it != list.end(); ++it ) { QwtPlotItem *item = *it; if ( item->rtti() == rtti ) items += item; } return items; } connectome-workbench-1.4.2/src/Qwt/qwt_plot_dict.h000066400000000000000000000031701360521144700222230ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ /*! \file !*/ #ifndef QWT_PLOT_DICT #define QWT_PLOT_DICT #include "qwt_global.h" #include "qwt_plot_item.h" #include /// \var typedef QList< QwtPlotItem *> QwtPlotItemList /// \brief See QT 4.x assistant documentation for QList typedef QList QwtPlotItemList; typedef QList::ConstIterator QwtPlotItemIterator; /*! \brief A dictionary for plot items QwtPlotDict organizes plot items in increasing z-order. If autoDelete() is enabled, all attached items will be deleted in the destructor of the dictionary. QwtPlotDict can be used to get access to all QwtPlotItem items - or all items of a specific type - that are currently on the plot. \sa QwtPlotItem::attach(), QwtPlotItem::detach(), QwtPlotItem::z() */ class QWT_EXPORT QwtPlotDict { public: explicit QwtPlotDict(); virtual ~QwtPlotDict(); void setAutoDelete( bool ); bool autoDelete() const; const QwtPlotItemList& itemList() const; QwtPlotItemList itemList( int rtti ) const; void detachItems( int rtti = QwtPlotItem::Rtti_PlotItem, bool autoDelete = true ); protected: void insertItem( QwtPlotItem * ); void removeItem( QwtPlotItem * ); private: class PrivateData; PrivateData *d_data; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_plot_directpainter.cpp000066400000000000000000000203311360521144700244660ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_directpainter.h" #include "qwt_scale_map.h" #include "qwt_plot.h" #include "qwt_plot_canvas.h" #include "qwt_plot_seriesitem.h" #include #include #include #include static inline void qwtRenderItem( QPainter *painter, const QRect &canvasRect, QwtPlotSeriesItem *seriesItem, int from, int to ) { // A minor performance improvement is possible // with caching the maps. TODO ... QwtPlot *plot = seriesItem->plot(); const QwtScaleMap xMap = plot->canvasMap( seriesItem->xAxis() ); const QwtScaleMap yMap = plot->canvasMap( seriesItem->yAxis() ); painter->setRenderHint( QPainter::Antialiasing, seriesItem->testRenderHint( QwtPlotItem::RenderAntialiased ) ); seriesItem->drawSeries( painter, xMap, yMap, canvasRect, from, to ); } static inline bool qwtHasBackingStore( const QwtPlotCanvas *canvas ) { return canvas->testPaintAttribute( QwtPlotCanvas::BackingStore ) && canvas->backingStore() && !canvas->backingStore()->isNull(); } class QwtPlotDirectPainter::PrivateData { public: PrivateData(): attributes( 0 ), hasClipping(false), seriesItem( NULL ) { } QwtPlotDirectPainter::Attributes attributes; bool hasClipping; QRegion clipRegion; QPainter painter; QwtPlotSeriesItem *seriesItem; int from; int to; }; //! Constructor QwtPlotDirectPainter::QwtPlotDirectPainter( QObject *parent ): QObject( parent ) { d_data = new PrivateData; } //! Destructor QwtPlotDirectPainter::~QwtPlotDirectPainter() { delete d_data; } /*! Change an attribute \param attribute Attribute to change \param on On/Off \sa Attribute, testAttribute() */ void QwtPlotDirectPainter::setAttribute( Attribute attribute, bool on ) { if ( bool( d_data->attributes & attribute ) != on ) { if ( on ) d_data->attributes |= attribute; else d_data->attributes &= ~attribute; if ( ( attribute == AtomicPainter ) && on ) reset(); } } /*! \return True, when attribute is enabled \param attribute Attribute to be tested \sa Attribute, setAttribute() */ bool QwtPlotDirectPainter::testAttribute( Attribute attribute ) const { return d_data->attributes & attribute; } /*! En/Disables clipping \param enable Enables clipping is true, disable it otherwise \sa hasClipping(), clipRegion(), setClipRegion() */ void QwtPlotDirectPainter::setClipping( bool enable ) { d_data->hasClipping = enable; } /*! \return true, when clipping is enabled \sa setClipping(), clipRegion(), setClipRegion() */ bool QwtPlotDirectPainter::hasClipping() const { return d_data->hasClipping; } /*! \brief Assign a clip region and enable clipping Depending on the environment setting a proper clip region might improve the performance heavily. F.e. on Qt embedded only the clipped part of the backing store will be copied to a ( maybe unaccelerated ) frame buffer device. \param region Clip region \sa clipRegion(), hasClipping(), setClipping() */ void QwtPlotDirectPainter::setClipRegion( const QRegion ®ion ) { d_data->clipRegion = region; d_data->hasClipping = true; } /*! \return Currently set clip region. \sa setClipRegion(), setClipping(), hasClipping() */ QRegion QwtPlotDirectPainter::clipRegion() const { return d_data->clipRegion; } /*! \brief Draw a set of points of a seriesItem. When observing an measurement while it is running, new points have to be added to an existing seriesItem. drawSeries() can be used to display them avoiding a complete redraw of the canvas. Setting plot()->canvas()->setAttribute(Qt::WA_PaintOutsidePaintEvent, true); will result in faster painting, if the paint engine of the canvas widget supports this feature. \param seriesItem Item to be painted \param from Index of the first point to be painted \param to Index of the last point to be painted. If to < 0 the series will be painted to its last point. */ void QwtPlotDirectPainter::drawSeries( QwtPlotSeriesItem *seriesItem, int from, int to ) { if ( seriesItem == NULL || seriesItem->plot() == NULL ) return; QWidget *canvas = seriesItem->plot()->canvas(); const QRect canvasRect = canvas->contentsRect(); QwtPlotCanvas *plotCanvas = qobject_cast( canvas ); if ( plotCanvas && qwtHasBackingStore( plotCanvas ) ) { QPainter painter( const_cast( plotCanvas->backingStore() ) ); if ( d_data->hasClipping ) painter.setClipRegion( d_data->clipRegion ); qwtRenderItem( &painter, canvasRect, seriesItem, from, to ); if ( testAttribute( QwtPlotDirectPainter::FullRepaint ) ) { plotCanvas->repaint(); return; } } bool immediatePaint = true; if ( !canvas->testAttribute( Qt::WA_WState_InPaintEvent ) ) { #if QT_VERSION < 0x050000 if ( !canvas->testAttribute( Qt::WA_PaintOutsidePaintEvent ) ) #endif immediatePaint = false; } if ( immediatePaint ) { if ( !d_data->painter.isActive() ) { reset(); d_data->painter.begin( canvas ); canvas->installEventFilter( this ); } if ( d_data->hasClipping ) { d_data->painter.setClipRegion( QRegion( canvasRect ) & d_data->clipRegion ); } else { if ( !d_data->painter.hasClipping() ) d_data->painter.setClipRect( canvasRect ); } qwtRenderItem( &d_data->painter, canvasRect, seriesItem, from, to ); if ( d_data->attributes & QwtPlotDirectPainter::AtomicPainter ) { reset(); } else { if ( d_data->hasClipping ) d_data->painter.setClipping( false ); } } else { reset(); d_data->seriesItem = seriesItem; d_data->from = from; d_data->to = to; QRegion clipRegion = canvasRect; if ( d_data->hasClipping ) clipRegion &= d_data->clipRegion; canvas->installEventFilter( this ); canvas->repaint(clipRegion); canvas->removeEventFilter( this ); d_data->seriesItem = NULL; } } //! Close the internal QPainter void QwtPlotDirectPainter::reset() { if ( d_data->painter.isActive() ) { QWidget *w = static_cast( d_data->painter.device() ); if ( w ) w->removeEventFilter( this ); d_data->painter.end(); } } //! Event filter bool QwtPlotDirectPainter::eventFilter( QObject *, QEvent *event ) { if ( event->type() == QEvent::Paint ) { reset(); if ( d_data->seriesItem ) { const QPaintEvent *pe = static_cast< QPaintEvent *>( event ); QWidget *canvas = d_data->seriesItem->plot()->canvas(); QPainter painter( canvas ); painter.setClipRegion( pe->region() ); bool doCopyCache = testAttribute( CopyBackingStore ); if ( doCopyCache ) { QwtPlotCanvas *plotCanvas = qobject_cast( canvas ); if ( plotCanvas ) { doCopyCache = qwtHasBackingStore( plotCanvas ); if ( doCopyCache ) { painter.drawPixmap( plotCanvas->contentsRect().topLeft(), *plotCanvas->backingStore() ); } } } if ( !doCopyCache ) { qwtRenderItem( &painter, canvas->contentsRect(), d_data->seriesItem, d_data->from, d_data->to ); } return true; // don't call QwtPlotCanvas::paintEvent() } } return false; } connectome-workbench-1.4.2/src/Qwt/qwt_plot_directpainter.h000066400000000000000000000061271360521144700241420ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_DIRECT_PAINTER_H #define QWT_PLOT_DIRECT_PAINTER_H #include "qwt_global.h" #include class QRegion; class QwtPlotSeriesItem; /*! \brief Painter object trying to paint incrementally Often applications want to display samples while they are collected. When there are too many samples complete replots will be expensive to be processed in a collection cycle. QwtPlotDirectPainter offers an API to paint subsets ( f.e all additions points ) without erasing/repainting the plot canvas. On certain environments it might be important to calculate a proper clip region before painting. F.e. for Qt Embedded only the clipped part of the backing store will be copied to a ( maybe unaccelerated ) frame buffer. \warning Incremental painting will only help when no replot is triggered by another operation ( like changing scales ) and nothing needs to be erased. */ class QWT_EXPORT QwtPlotDirectPainter: public QObject { public: /*! \brief Paint attributes \sa setAttribute(), testAttribute(), drawSeries() */ enum Attribute { /*! Initializing a QPainter is an expensive operation. When AtomicPainter is set each call of drawSeries() opens/closes a temporary QPainter. Otherwise QwtPlotDirectPainter tries to use the same QPainter as long as possible. */ AtomicPainter = 0x01, /*! When FullRepaint is set the plot canvas is explicitly repainted after the samples have been rendered. */ FullRepaint = 0x02, /*! When QwtPlotCanvas::BackingStore is enabled the painter has to paint to the backing store and the widget. In certain situations/environments it might be faster to paint to the backing store only and then copy the backing store to the canvas. This flag can also be useful for settings, where Qt fills the the clip region with the widget background. */ CopyBackingStore = 0x04 }; //! Paint attributes typedef QFlags Attributes; QwtPlotDirectPainter( QObject *parent = NULL ); virtual ~QwtPlotDirectPainter(); void setAttribute( Attribute, bool on ); bool testAttribute( Attribute ) const; void setClipping( bool ); bool hasClipping() const; void setClipRegion( const QRegion & ); QRegion clipRegion() const; void drawSeries( QwtPlotSeriesItem *, int from, int to ); void reset(); virtual bool eventFilter( QObject *, QEvent * ); private: class PrivateData; PrivateData *d_data; }; Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotDirectPainter::Attributes ) #endif connectome-workbench-1.4.2/src/Qwt/qwt_plot_grid.cpp000066400000000000000000000231731360521144700225650ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_grid.h" #include "qwt_painter.h" #include "qwt_text.h" #include "qwt_scale_map.h" #include "qwt_scale_div.h" #include "qwt_math.h" #include #include class QwtPlotGrid::PrivateData { public: PrivateData(): xEnabled( true ), yEnabled( true ), xMinEnabled( false ), yMinEnabled( false ) { } bool xEnabled; bool yEnabled; bool xMinEnabled; bool yMinEnabled; QwtScaleDiv xScaleDiv; QwtScaleDiv yScaleDiv; QPen majorPen; QPen minorPen; }; //! Enables major grid, disables minor grid QwtPlotGrid::QwtPlotGrid(): QwtPlotItem( QwtText( "Grid" ) ) { d_data = new PrivateData; setItemInterest( QwtPlotItem::ScaleInterest, true ); setZ( 10.0 ); } //! Destructor QwtPlotGrid::~QwtPlotGrid() { delete d_data; } //! \return QwtPlotItem::Rtti_PlotGrid int QwtPlotGrid::rtti() const { return QwtPlotItem::Rtti_PlotGrid; } /*! \brief Enable or disable vertical grid lines \param on Enable (true) or disable \sa Minor grid lines can be enabled or disabled with enableXMin() */ void QwtPlotGrid::enableX( bool on ) { if ( d_data->xEnabled != on ) { d_data->xEnabled = on; legendChanged(); itemChanged(); } } /*! \brief Enable or disable horizontal grid lines \param on Enable (true) or disable \sa Minor grid lines can be enabled or disabled with enableYMin() */ void QwtPlotGrid::enableY( bool on ) { if ( d_data->yEnabled != on ) { d_data->yEnabled = on; legendChanged(); itemChanged(); } } /*! \brief Enable or disable minor vertical grid lines. \param on Enable (true) or disable \sa enableX() */ void QwtPlotGrid::enableXMin( bool on ) { if ( d_data->xMinEnabled != on ) { d_data->xMinEnabled = on; legendChanged(); itemChanged(); } } /*! \brief Enable or disable minor horizontal grid lines \param on Enable (true) or disable \sa enableY() */ void QwtPlotGrid::enableYMin( bool on ) { if ( d_data->yMinEnabled != on ) { d_data->yMinEnabled = on; legendChanged(); itemChanged(); } } /*! Assign an x axis scale division \param scaleDiv Scale division */ void QwtPlotGrid::setXDiv( const QwtScaleDiv &scaleDiv ) { if ( d_data->xScaleDiv != scaleDiv ) { d_data->xScaleDiv = scaleDiv; itemChanged(); } } /*! Assign a y axis division \param scaleDiv Scale division */ void QwtPlotGrid::setYDiv( const QwtScaleDiv &scaleDiv ) { if ( d_data->yScaleDiv != scaleDiv ) { d_data->yScaleDiv = scaleDiv; itemChanged(); } } /*! Build and assign a pen for both major and minor grid lines In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it non cosmetic ( see QPen::isCosmetic() ). This method has been introduced to hide this incompatibility. \param color Pen color \param width Pen width \param style Pen style \sa pen(), brush() */ void QwtPlotGrid::setPen( const QColor &color, qreal width, Qt::PenStyle style ) { setPen( QPen( color, width, style ) ); } /*! Assign a pen for both major and minor grid lines \param pen Pen \sa setMajorPen(), setMinorPen() */ void QwtPlotGrid::setPen( const QPen &pen ) { if ( d_data->majorPen != pen || d_data->minorPen != pen ) { d_data->majorPen = pen; d_data->minorPen = pen; legendChanged(); itemChanged(); } } /*! Build and assign a pen for both major grid lines In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it non cosmetic ( see QPen::isCosmetic() ). This method has been introduced to hide this incompatibility. \param color Pen color \param width Pen width \param style Pen style \sa pen(), brush() */ void QwtPlotGrid::setMajorPen( const QColor &color, qreal width, Qt::PenStyle style ) { setMajorPen( QPen( color, width, style ) ); } /*! Assign a pen for the major grid lines \param pen Pen \sa majorPen(), setMinorPen(), setPen() */ void QwtPlotGrid::setMajorPen( const QPen &pen ) { if ( d_data->majorPen != pen ) { d_data->majorPen = pen; legendChanged(); itemChanged(); } } /*! Build and assign a pen for the minor grid lines In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it non cosmetic ( see QPen::isCosmetic() ). This method has been introduced to hide this incompatibility. \param color Pen color \param width Pen width \param style Pen style \sa pen(), brush() */ void QwtPlotGrid::setMinorPen( const QColor &color, qreal width, Qt::PenStyle style ) { setMinorPen( QPen( color, width, style ) ); } /*! Assign a pen for the minor grid lines \param pen Pen \sa minorPen(), setMajorPen(), setPen() */ void QwtPlotGrid::setMinorPen( const QPen &pen ) { if ( d_data->minorPen != pen ) { d_data->minorPen = pen; legendChanged(); itemChanged(); } } /*! \brief Draw the grid The grid is drawn into the bounding rectangle such that grid lines begin and end at the rectangle's borders. The X and Y maps are used to map the scale divisions into the drawing region screen. \param painter Painter \param xMap X axis map \param yMap Y axis \param canvasRect Contents rectangle of the plot canvas */ void QwtPlotGrid::draw( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect ) const { // draw minor grid lines QPen minorPen = d_data->minorPen; minorPen.setCapStyle( Qt::FlatCap ); painter->setPen( minorPen ); if ( d_data->xEnabled && d_data->xMinEnabled ) { drawLines( painter, canvasRect, Qt::Vertical, xMap, d_data->xScaleDiv.ticks( QwtScaleDiv::MinorTick ) ); drawLines( painter, canvasRect, Qt::Vertical, xMap, d_data->xScaleDiv.ticks( QwtScaleDiv::MediumTick ) ); } if ( d_data->yEnabled && d_data->yMinEnabled ) { drawLines( painter, canvasRect, Qt::Horizontal, yMap, d_data->yScaleDiv.ticks( QwtScaleDiv::MinorTick ) ); drawLines( painter, canvasRect, Qt::Horizontal, yMap, d_data->yScaleDiv.ticks( QwtScaleDiv::MediumTick ) ); } // draw major grid lines QPen majorPen = d_data->majorPen; majorPen.setCapStyle( Qt::FlatCap ); painter->setPen( majorPen ); if ( d_data->xEnabled ) { drawLines( painter, canvasRect, Qt::Vertical, xMap, d_data->xScaleDiv.ticks( QwtScaleDiv::MajorTick ) ); } if ( d_data->yEnabled ) { drawLines( painter, canvasRect, Qt::Horizontal, yMap, d_data->yScaleDiv.ticks( QwtScaleDiv::MajorTick ) ); } } void QwtPlotGrid::drawLines( QPainter *painter, const QRectF &canvasRect, Qt::Orientation orientation, const QwtScaleMap &scaleMap, const QList &values ) const { const double x1 = canvasRect.left(); const double x2 = canvasRect.right() - 1.0; const double y1 = canvasRect.top(); const double y2 = canvasRect.bottom() - 1.0; const bool doAlign = QwtPainter::roundingAlignment( painter ); for ( int i = 0; i < values.count(); i++ ) { double value = scaleMap.transform( values[i] ); if ( doAlign ) value = qRound( value ); if ( orientation == Qt::Horizontal ) { if ( qwtFuzzyGreaterOrEqual( value, y1 ) && qwtFuzzyLessOrEqual( value, y2 ) ) { QwtPainter::drawLine( painter, x1, value, x2, value ); } } else { if ( qwtFuzzyGreaterOrEqual( value, x1 ) && qwtFuzzyLessOrEqual( value, x2 ) ) { QwtPainter::drawLine( painter, value, y1, value, y2 ); } } } } /*! \return the pen for the major grid lines \sa setMajorPen(), setMinorPen(), setPen() */ const QPen &QwtPlotGrid::majorPen() const { return d_data->majorPen; } /*! \return the pen for the minor grid lines \sa setMinorPen(), setMajorPen(), setPen() */ const QPen &QwtPlotGrid::minorPen() const { return d_data->minorPen; } /*! \return true if vertical grid lines are enabled \sa enableX() */ bool QwtPlotGrid::xEnabled() const { return d_data->xEnabled; } /*! \return true if minor vertical grid lines are enabled \sa enableXMin() */ bool QwtPlotGrid::xMinEnabled() const { return d_data->xMinEnabled; } /*! \return true if horizontal grid lines are enabled \sa enableY() */ bool QwtPlotGrid::yEnabled() const { return d_data->yEnabled; } /*! \return true if minor horizontal grid lines are enabled \sa enableYMin() */ bool QwtPlotGrid::yMinEnabled() const { return d_data->yMinEnabled; } /*! \return the scale division of the x axis */ const QwtScaleDiv &QwtPlotGrid::xScaleDiv() const { return d_data->xScaleDiv; } /*! \return the scale division of the y axis */ const QwtScaleDiv &QwtPlotGrid::yScaleDiv() const { return d_data->yScaleDiv; } /*! Update the grid to changes of the axes scale division \param xScaleDiv Scale division of the x-axis \param yScaleDiv Scale division of the y-axis \sa QwtPlot::updateAxes() */ void QwtPlotGrid::updateScaleDiv( const QwtScaleDiv& xScaleDiv, const QwtScaleDiv& yScaleDiv ) { setXDiv( xScaleDiv ); setYDiv( yScaleDiv ); } connectome-workbench-1.4.2/src/Qwt/qwt_plot_grid.h000066400000000000000000000046031360521144700222270ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_GRID_H #define QWT_PLOT_GRID_H #include "qwt_global.h" #include "qwt_plot_item.h" #include "qwt_scale_div.h" class QPainter; class QPen; class QwtScaleMap; class QwtScaleDiv; /*! \brief A class which draws a coordinate grid The QwtPlotGrid class can be used to draw a coordinate grid. A coordinate grid consists of major and minor vertical and horizontal grid lines. The locations of the grid lines are determined by the X and Y scale divisions which can be assigned with setXDiv() and setYDiv(). The draw() member draws the grid within a bounding rectangle. */ class QWT_EXPORT QwtPlotGrid: public QwtPlotItem { public: explicit QwtPlotGrid(); virtual ~QwtPlotGrid(); virtual int rtti() const; void enableX( bool tf ); bool xEnabled() const; void enableY( bool tf ); bool yEnabled() const; void enableXMin( bool tf ); bool xMinEnabled() const; void enableYMin( bool tf ); bool yMinEnabled() const; void setXDiv( const QwtScaleDiv &sx ); const QwtScaleDiv &xScaleDiv() const; void setYDiv( const QwtScaleDiv &sy ); const QwtScaleDiv &yScaleDiv() const; void setPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine ); void setPen( const QPen & ); void setMajorPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine ); void setMajorPen( const QPen & ); const QPen& majorPen() const; void setMinorPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine ); void setMinorPen( const QPen &p ); const QPen& minorPen() const; virtual void draw( QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &rect ) const; virtual void updateScaleDiv( const QwtScaleDiv &xMap, const QwtScaleDiv &yMap ); private: void drawLines( QPainter *painter, const QRectF &, Qt::Orientation orientation, const QwtScaleMap &, const QList & ) const; class PrivateData; PrivateData *d_data; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_plot_histogram.cpp000066400000000000000000000434171360521144700236400ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_histogram.h" #include "qwt_plot.h" #include "qwt_painter.h" #include "qwt_column_symbol.h" #include "qwt_scale_map.h" #include #include static inline bool qwtIsCombinable( const QwtInterval &d1, const QwtInterval &d2 ) { if ( d1.isValid() && d2.isValid() ) { if ( d1.maxValue() == d2.minValue() ) { if ( !( d1.borderFlags() & QwtInterval::ExcludeMaximum && d2.borderFlags() & QwtInterval::ExcludeMinimum ) ) { return true; } } } return false; } class QwtPlotHistogram::PrivateData { public: PrivateData(): baseline( 0.0 ), style( Columns ), symbol( NULL ) { } ~PrivateData() { delete symbol; } double baseline; QPen pen; QBrush brush; QwtPlotHistogram::HistogramStyle style; const QwtColumnSymbol *symbol; }; /*! Constructor \param title Title of the histogram. */ QwtPlotHistogram::QwtPlotHistogram( const QwtText &title ): QwtPlotSeriesItem( title ) { init(); } /*! Constructor \param title Title of the histogram. */ QwtPlotHistogram::QwtPlotHistogram( const QString &title ): QwtPlotSeriesItem( title ) { init(); } //! Destructor QwtPlotHistogram::~QwtPlotHistogram() { delete d_data; } //! Initialize data members void QwtPlotHistogram::init() { d_data = new PrivateData(); setData( new QwtIntervalSeriesData() ); setItemAttribute( QwtPlotItem::AutoScale, true ); setItemAttribute( QwtPlotItem::Legend, true ); setZ( 20.0 ); } /*! Set the histogram's drawing style \param style Histogram style \sa HistogramStyle, style() */ void QwtPlotHistogram::setStyle( HistogramStyle style ) { if ( style != d_data->style ) { d_data->style = style; legendChanged(); itemChanged(); } } /*! \return Style of the histogram \sa HistogramStyle, setStyle() */ QwtPlotHistogram::HistogramStyle QwtPlotHistogram::style() const { return d_data->style; } /*! Build and assign a pen In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it non cosmetic ( see QPen::isCosmetic() ). This method has been introduced to hide this incompatibility. \param color Pen color \param width Pen width \param style Pen style \sa pen(), brush() */ void QwtPlotHistogram::setPen( const QColor &color, qreal width, Qt::PenStyle style ) { setPen( QPen( color, width, style ) ); } /*! Assign a pen, that is used in a style() depending way. \param pen New pen \sa pen(), brush() */ void QwtPlotHistogram::setPen( const QPen &pen ) { if ( pen != d_data->pen ) { d_data->pen = pen; legendChanged(); itemChanged(); } } /*! \return Pen used in a style() depending way. \sa setPen(), brush() */ const QPen &QwtPlotHistogram::pen() const { return d_data->pen; } /*! Assign a brush, that is used in a style() depending way. \param brush New brush \sa pen(), brush() */ void QwtPlotHistogram::setBrush( const QBrush &brush ) { if ( brush != d_data->brush ) { d_data->brush = brush; legendChanged(); itemChanged(); } } /*! \return Brush used in a style() depending way. \sa setPen(), brush() */ const QBrush &QwtPlotHistogram::brush() const { return d_data->brush; } /*! \brief Assign a symbol In Column style an optional symbol can be assigned, that is responsible for displaying the rectangle that is defined by the interval and the distance between baseline() and value. When no symbol has been defined the area is displayed as plain rectangle using pen() and brush(). \sa style(), symbol(), drawColumn(), pen(), brush() \note In applications, where different intervals need to be displayed in a different way ( f.e different colors or even using different symbols) it is recommended to overload drawColumn(). */ void QwtPlotHistogram::setSymbol( const QwtColumnSymbol *symbol ) { if ( symbol != d_data->symbol ) { delete d_data->symbol; d_data->symbol = symbol; legendChanged(); itemChanged(); } } /*! \return Current symbol or NULL, when no symbol has been assigned \sa setSymbol() */ const QwtColumnSymbol *QwtPlotHistogram::symbol() const { return d_data->symbol; } /*! \brief Set the value of the baseline Each column representing an QwtIntervalSample is defined by its interval and the interval between baseline and the value of the sample. The default value of the baseline is 0.0. \param value Value of the baseline \sa baseline() */ void QwtPlotHistogram::setBaseline( double value ) { if ( d_data->baseline != value ) { d_data->baseline = value; itemChanged(); } } /*! \return Value of the baseline \sa setBaseline() */ double QwtPlotHistogram::baseline() const { return d_data->baseline; } /*! \return Bounding rectangle of all samples. For an empty series the rectangle is invalid. */ QRectF QwtPlotHistogram::boundingRect() const { QRectF rect = data()->boundingRect(); if ( !rect.isValid() ) return rect; if ( orientation() == Qt::Horizontal ) { rect = QRectF( rect.y(), rect.x(), rect.height(), rect.width() ); if ( rect.left() > d_data->baseline ) rect.setLeft( d_data->baseline ); else if ( rect.right() < d_data->baseline ) rect.setRight( d_data->baseline ); } else { if ( rect.bottom() < d_data->baseline ) rect.setBottom( d_data->baseline ); else if ( rect.top() > d_data->baseline ) rect.setTop( d_data->baseline ); } return rect; } //! \return QwtPlotItem::Rtti_PlotHistogram int QwtPlotHistogram::rtti() const { return QwtPlotItem::Rtti_PlotHistogram; } /*! Initialize data with an array of samples. \param samples Vector of points */ void QwtPlotHistogram::setSamples( const QVector &samples ) { setData( new QwtIntervalSeriesData( samples ) ); } /*! Assign a series of samples setSamples() is just a wrapper for setData() without any additional value - beside that it is easier to find for the developer. \param data Data \warning The item takes ownership of the data object, deleting it when its not used anymore. */ void QwtPlotHistogram::setSamples( QwtSeriesData *data ) { setData( data ); } /*! Draw a subset of the histogram samples \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rectangle of the canvas \param from Index of the first sample to be painted \param to Index of the last sample to be painted. If to < 0 the series will be painted to its last sample. \sa drawOutline(), drawLines(), drawColumns */ void QwtPlotHistogram::drawSeries( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &, int from, int to ) const { if ( !painter || dataSize() <= 0 ) return; if ( to < 0 ) to = dataSize() - 1; switch ( d_data->style ) { case Outline: drawOutline( painter, xMap, yMap, from, to ); break; case Lines: drawLines( painter, xMap, yMap, from, to ); break; case Columns: drawColumns( painter, xMap, yMap, from, to ); break; default: break; } } /*! Draw a histogram in Outline style() \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param from Index of the first sample to be painted \param to Index of the last sample to be painted. If to < 0 the histogram will be painted to its last point. \sa setStyle(), style() \warning The outline style requires, that the intervals are in increasing order and not overlapping. */ void QwtPlotHistogram::drawOutline( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, int from, int to ) const { const bool doAlign = QwtPainter::roundingAlignment( painter ); double v0 = ( orientation() == Qt::Horizontal ) ? xMap.transform( baseline() ) : yMap.transform( baseline() ); if ( doAlign ) v0 = qRound( v0 ); QwtIntervalSample previous; QPolygonF polygon; for ( int i = from; i <= to; i++ ) { const QwtIntervalSample sample = this->sample( i ); if ( !sample.interval.isValid() ) { flushPolygon( painter, v0, polygon ); previous = sample; continue; } if ( previous.interval.isValid() ) { if ( !qwtIsCombinable( previous.interval, sample.interval ) ) flushPolygon( painter, v0, polygon ); } if ( orientation() == Qt::Vertical ) { double x1 = xMap.transform( sample.interval.minValue() ); double x2 = xMap.transform( sample.interval.maxValue() ); double y = yMap.transform( sample.value ); if ( doAlign ) { x1 = qRound( x1 ); x2 = qRound( x2 ); y = qRound( y ); } if ( polygon.size() == 0 ) polygon += QPointF( x1, v0 ); polygon += QPointF( x1, y ); polygon += QPointF( x2, y ); } else { double y1 = yMap.transform( sample.interval.minValue() ); double y2 = yMap.transform( sample.interval.maxValue() ); double x = xMap.transform( sample.value ); if ( doAlign ) { y1 = qRound( y1 ); y2 = qRound( y2 ); x = qRound( x ); } if ( polygon.size() == 0 ) polygon += QPointF( v0, y1 ); polygon += QPointF( x, y1 ); polygon += QPointF( x, y2 ); } previous = sample; } flushPolygon( painter, v0, polygon ); } /*! Draw a histogram in Columns style() \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param from Index of the first sample to be painted \param to Index of the last sample to be painted. If to < 0 the histogram will be painted to its last point. \sa setStyle(), style(), setSymbol(), drawColumn() */ void QwtPlotHistogram::drawColumns( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, int from, int to ) const { painter->setPen( d_data->pen ); painter->setBrush( d_data->brush ); const QwtSeriesData *series = data(); for ( int i = from; i <= to; i++ ) { const QwtIntervalSample sample = series->sample( i ); if ( !sample.interval.isNull() ) { const QwtColumnRect rect = columnRect( sample, xMap, yMap ); drawColumn( painter, rect, sample ); } } } /*! Draw a histogram in Lines style() \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param from Index of the first sample to be painted \param to Index of the last sample to be painted. If to < 0 the histogram will be painted to its last point. \sa setStyle(), style(), setPen() */ void QwtPlotHistogram::drawLines( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, int from, int to ) const { const bool doAlign = QwtPainter::roundingAlignment( painter ); painter->setPen( d_data->pen ); painter->setBrush( Qt::NoBrush ); const QwtSeriesData *series = data(); for ( int i = from; i <= to; i++ ) { const QwtIntervalSample sample = series->sample( i ); if ( !sample.interval.isNull() ) { const QwtColumnRect rect = columnRect( sample, xMap, yMap ); QRectF r = rect.toRect(); if ( doAlign ) { r.setLeft( qRound( r.left() ) ); r.setRight( qRound( r.right() ) ); r.setTop( qRound( r.top() ) ); r.setBottom( qRound( r.bottom() ) ); } switch ( rect.direction ) { case QwtColumnRect::LeftToRight: { QwtPainter::drawLine( painter, r.topRight(), r.bottomRight() ); break; } case QwtColumnRect::RightToLeft: { QwtPainter::drawLine( painter, r.topLeft(), r.bottomLeft() ); break; } case QwtColumnRect::TopToBottom: { QwtPainter::drawLine( painter, r.bottomRight(), r.bottomLeft() ); break; } case QwtColumnRect::BottomToTop: { QwtPainter::drawLine( painter, r.topRight(), r.topLeft() ); break; } } } } } //! Internal, used by the Outline style. void QwtPlotHistogram::flushPolygon( QPainter *painter, double baseLine, QPolygonF &polygon ) const { if ( polygon.size() == 0 ) return; if ( orientation() == Qt::Horizontal ) polygon += QPointF( baseLine, polygon.last().y() ); else polygon += QPointF( polygon.last().x(), baseLine ); if ( d_data->brush.style() != Qt::NoBrush ) { painter->setPen( Qt::NoPen ); painter->setBrush( d_data->brush ); if ( orientation() == Qt::Horizontal ) { polygon += QPointF( polygon.last().x(), baseLine ); polygon += QPointF( polygon.first().x(), baseLine ); } else { polygon += QPointF( baseLine, polygon.last().y() ); polygon += QPointF( baseLine, polygon.first().y() ); } QwtPainter::drawPolygon( painter, polygon ); polygon.pop_back(); polygon.pop_back(); } if ( d_data->pen.style() != Qt::NoPen ) { painter->setBrush( Qt::NoBrush ); painter->setPen( d_data->pen ); QwtPainter::drawPolyline( painter, polygon ); } polygon.clear(); } /*! Calculate the area that is covered by a sample \param sample Sample \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \return Rectangle, that is covered by a sample */ QwtColumnRect QwtPlotHistogram::columnRect( const QwtIntervalSample &sample, const QwtScaleMap &xMap, const QwtScaleMap &yMap ) const { QwtColumnRect rect; const QwtInterval &iv = sample.interval; if ( !iv.isValid() ) return rect; if ( orientation() == Qt::Horizontal ) { const double x0 = xMap.transform( baseline() ); const double x = xMap.transform( sample.value ); const double y1 = yMap.transform( iv.minValue() ); const double y2 = yMap.transform( iv.maxValue() ); rect.hInterval.setInterval( x0, x ); rect.vInterval.setInterval( y1, y2, iv.borderFlags() ); rect.direction = ( x < x0 ) ? QwtColumnRect::RightToLeft : QwtColumnRect::LeftToRight; } else { const double x1 = xMap.transform( iv.minValue() ); const double x2 = xMap.transform( iv.maxValue() ); const double y0 = yMap.transform( baseline() ); const double y = yMap.transform( sample.value ); rect.hInterval.setInterval( x1, x2, iv.borderFlags() ); rect.vInterval.setInterval( y0, y ); rect.direction = ( y < y0 ) ? QwtColumnRect::BottomToTop : QwtColumnRect::TopToBottom; } return rect; } /*! Draw a column for a sample in Columns style(). When a symbol() has been set the symbol is used otherwise the column is displayed as plain rectangle using pen() and brush(). \param painter Painter \param rect Rectangle where to paint the column in paint device coordinates \param sample Sample to be displayed \note In applications, where different intervals need to be displayed in a different way ( f.e different colors or even using different symbols) it is recommended to overload drawColumn(). */ void QwtPlotHistogram::drawColumn( QPainter *painter, const QwtColumnRect &rect, const QwtIntervalSample &sample ) const { Q_UNUSED( sample ); if ( d_data->symbol && ( d_data->symbol->style() != QwtColumnSymbol::NoStyle ) ) { d_data->symbol->draw( painter, rect ); } else { QRectF r = rect.toRect(); if ( QwtPainter::roundingAlignment( painter ) ) { r.setLeft( qRound( r.left() ) ); r.setRight( qRound( r.right() ) ); r.setTop( qRound( r.top() ) ); r.setBottom( qRound( r.bottom() ) ); } QwtPainter::drawRect( painter, r ); } } /*! A plain rectangle without pen using the brush() \param index Index of the legend entry ( ignored as there is only one ) \param size Icon size \return A graphic displaying the icon \sa QwtPlotItem::setLegendIconSize(), QwtPlotItem::legendData() */ QwtGraphic QwtPlotHistogram::legendIcon( int index, const QSizeF &size ) const { Q_UNUSED( index ); return defaultIcon( d_data->brush, size ); } connectome-workbench-1.4.2/src/Qwt/qwt_plot_histogram.h000066400000000000000000000103071360521144700232750ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_HISTOGRAM_H #define QWT_PLOT_HISTOGRAM_H #include "qwt_global.h" #include "qwt_plot_seriesitem.h" #include "qwt_column_symbol.h" #include #include class QwtIntervalData; class QString; class QPolygonF; /*! \brief QwtPlotHistogram represents a series of samples, where an interval is associated with a value ( \f$y = f([x1,x2])\f$ ). The representation depends on the style() and an optional symbol() that is displayed for each interval. \note The term "histogram" is used in a different way in the areas of digital image processing and statistics. Wikipedia introduces the terms "image histogram" and "color histogram" to avoid confusions. While "image histograms" can be displayed by a QwtPlotCurve there is no applicable plot item for a "color histogram" yet. \sa QwtPlotBarChart, QwtPlotMultiBarChart */ class QWT_EXPORT QwtPlotHistogram: public QwtPlotSeriesItem, public QwtSeriesStore { public: /*! Histogram styles. The default style is QwtPlotHistogram::Columns. \sa setStyle(), style(), setSymbol(), symbol(), setBaseline() */ enum HistogramStyle { /*! Draw an outline around the area, that is build by all intervals using the pen() and fill it with the brush(). The outline style requires, that the intervals are in increasing order and not overlapping. */ Outline, /*! Draw a column for each interval. When a symbol() has been set the symbol is used otherwise the column is displayed as plain rectangle using pen() and brush(). */ Columns, /*! Draw a simple line using the pen() for each interval. */ Lines, /*! Styles >= UserStyle are reserved for derived classes that overload drawSeries() with additional application specific ways to display a histogram. */ UserStyle = 100 }; explicit QwtPlotHistogram( const QString &title = QString::null ); explicit QwtPlotHistogram( const QwtText &title ); virtual ~QwtPlotHistogram(); virtual int rtti() const; void setPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine ); void setPen( const QPen & ); const QPen &pen() const; void setBrush( const QBrush & ); const QBrush &brush() const; void setSamples( const QVector & ); void setSamples( QwtSeriesData * ); void setBaseline( double reference ); double baseline() const; void setStyle( HistogramStyle style ); HistogramStyle style() const; void setSymbol( const QwtColumnSymbol * ); const QwtColumnSymbol *symbol() const; virtual void drawSeries( QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; virtual QRectF boundingRect() const; virtual QwtGraphic legendIcon( int index, const QSizeF & ) const; protected: virtual QwtColumnRect columnRect( const QwtIntervalSample &, const QwtScaleMap &, const QwtScaleMap & ) const; virtual void drawColumn( QPainter *, const QwtColumnRect &, const QwtIntervalSample & ) const; void drawColumns( QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, int from, int to ) const; void drawOutline( QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, int from, int to ) const; void drawLines( QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, int from, int to ) const; private: void init(); void flushPolygon( QPainter *, double baseLine, QPolygonF & ) const; class PrivateData; PrivateData *d_data; }; #endif connectome-workbench-1.4.2/src/Qwt/qwt_plot_intervalcurve.cpp000066400000000000000000000362031360521144700245270ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_intervalcurve.h" #include "qwt_interval_symbol.h" #include "qwt_scale_map.h" #include "qwt_clipper.h" #include "qwt_painter.h" #include #include static inline bool qwtIsHSampleInside( const QwtIntervalSample &sample, double xMin, double xMax, double yMin, double yMax ) { const double y = sample.value; const double x1 = sample.interval.minValue(); const double x2 = sample.interval.maxValue(); const bool isOffScreen = ( y < yMin ) || ( y > yMax ) || ( x1 < xMin && x2 < xMin ) || ( x1 > xMax && x2 > xMax ); return !isOffScreen; } static inline bool qwtIsVSampleInside( const QwtIntervalSample &sample, double xMin, double xMax, double yMin, double yMax ) { const double x = sample.value; const double y1 = sample.interval.minValue(); const double y2 = sample.interval.maxValue(); const bool isOffScreen = ( x < xMin ) || ( x > xMax ) || ( y1 < yMin && y2 < yMin ) || ( y1 > yMax && y2 > yMax ); return !isOffScreen; } class QwtPlotIntervalCurve::PrivateData { public: PrivateData(): style( QwtPlotIntervalCurve::Tube ), symbol( NULL ), pen( Qt::black ), brush( Qt::white ) { paintAttributes = QwtPlotIntervalCurve::ClipPolygons; paintAttributes |= QwtPlotIntervalCurve::ClipSymbol; pen.setCapStyle( Qt::FlatCap ); } ~PrivateData() { delete symbol; } QwtPlotIntervalCurve::CurveStyle style; const QwtIntervalSymbol *symbol; QPen pen; QBrush brush; QwtPlotIntervalCurve::PaintAttributes paintAttributes; }; /*! Constructor \param title Title of the curve */ QwtPlotIntervalCurve::QwtPlotIntervalCurve( const QwtText &title ): QwtPlotSeriesItem( title ) { init(); } /*! Constructor \param title Title of the curve */ QwtPlotIntervalCurve::QwtPlotIntervalCurve( const QString &title ): QwtPlotSeriesItem( QwtText( title ) ) { init(); } //! Destructor QwtPlotIntervalCurve::~QwtPlotIntervalCurve() { delete d_data; } //! Initialize internal members void QwtPlotIntervalCurve::init() { setItemAttribute( QwtPlotItem::Legend, true ); setItemAttribute( QwtPlotItem::AutoScale, true ); d_data = new PrivateData; setData( new QwtIntervalSeriesData() ); setZ( 19.0 ); } //! \return QwtPlotItem::Rtti_PlotIntervalCurve int QwtPlotIntervalCurve::rtti() const { return QwtPlotIntervalCurve::Rtti_PlotIntervalCurve; } /*! Specify an attribute how to draw the curve \param attribute Paint attribute \param on On/Off \sa testPaintAttribute() */ void QwtPlotIntervalCurve::setPaintAttribute( PaintAttribute attribute, bool on ) { if ( on ) d_data->paintAttributes |= attribute; else d_data->paintAttributes &= ~attribute; } /*! \return True, when attribute is enabled \sa PaintAttribute, setPaintAttribute() */ bool QwtPlotIntervalCurve::testPaintAttribute( PaintAttribute attribute ) const { return ( d_data->paintAttributes & attribute ); } /*! Initialize data with an array of samples. \param samples Vector of samples */ void QwtPlotIntervalCurve::setSamples( const QVector &samples ) { setData( new QwtIntervalSeriesData( samples ) ); } /*! Assign a series of samples setSamples() is just a wrapper for setData() without any additional value - beside that it is easier to find for the developer. \param data Data \warning The item takes ownership of the data object, deleting it when its not used anymore. */ void QwtPlotIntervalCurve::setSamples( QwtSeriesData *data ) { setData( data ); } /*! Set the curve's drawing style \param style Curve style \sa CurveStyle, style() */ void QwtPlotIntervalCurve::setStyle( CurveStyle style ) { if ( style != d_data->style ) { d_data->style = style; legendChanged(); itemChanged(); } } /*! \return Style of the curve \sa setStyle() */ QwtPlotIntervalCurve::CurveStyle QwtPlotIntervalCurve::style() const { return d_data->style; } /*! Assign a symbol. \param symbol Symbol \sa symbol() */ void QwtPlotIntervalCurve::setSymbol( const QwtIntervalSymbol *symbol ) { if ( symbol != d_data->symbol ) { delete d_data->symbol; d_data->symbol = symbol; legendChanged(); itemChanged(); } } /*! \return Current symbol or NULL, when no symbol has been assigned \sa setSymbol() */ const QwtIntervalSymbol *QwtPlotIntervalCurve::symbol() const { return d_data->symbol; } /*! Build and assign a pen In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it non cosmetic ( see QPen::isCosmetic() ). This method has been introduced to hide this incompatibility. \param color Pen color \param width Pen width \param style Pen style \sa pen(), brush() */ void QwtPlotIntervalCurve::setPen( const QColor &color, qreal width, Qt::PenStyle style ) { setPen( QPen( color, width, style ) ); } /*! \brief Assign a pen \param pen New pen \sa pen(), brush() */ void QwtPlotIntervalCurve::setPen( const QPen &pen ) { if ( pen != d_data->pen ) { d_data->pen = pen; legendChanged(); itemChanged(); } } /*! \return Pen used to draw the lines \sa setPen(), brush() */ const QPen& QwtPlotIntervalCurve::pen() const { return d_data->pen; } /*! Assign a brush. The brush is used to fill the area in Tube style(). \param brush Brush \sa brush(), pen(), setStyle(), CurveStyle */ void QwtPlotIntervalCurve::setBrush( const QBrush &brush ) { if ( brush != d_data->brush ) { d_data->brush = brush; legendChanged(); itemChanged(); } } /*! \return Brush used to fill the area in Tube style() \sa setBrush(), setStyle(), CurveStyle */ const QBrush& QwtPlotIntervalCurve::brush() const { return d_data->brush; } /*! \return Bounding rectangle of all samples. For an empty series the rectangle is invalid. */ QRectF QwtPlotIntervalCurve::boundingRect() const { QRectF rect = QwtPlotSeriesItem::boundingRect(); if ( rect.isValid() && orientation() == Qt::Vertical ) rect.setRect( rect.y(), rect.x(), rect.height(), rect.width() ); return rect; } /*! Draw a subset of the samples \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rectangle of the canvas \param from Index of the first sample to be painted \param to Index of the last sample to be painted. If to < 0 the series will be painted to its last sample. \sa drawTube(), drawSymbols() */ void QwtPlotIntervalCurve::drawSeries( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { if ( to < 0 ) to = dataSize() - 1; if ( from < 0 ) from = 0; if ( from > to ) return; switch ( d_data->style ) { case Tube: drawTube( painter, xMap, yMap, canvasRect, from, to ); break; case NoCurve: default: break; } if ( d_data->symbol && ( d_data->symbol->style() != QwtIntervalSymbol::NoSymbol ) ) { drawSymbols( painter, *d_data->symbol, xMap, yMap, canvasRect, from, to ); } } /*! Draw a tube Builds 2 curves from the upper and lower limits of the intervals and draws them with the pen(). The area between the curves is filled with the brush(). \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rectangle of the canvas \param from Index of the first sample to be painted \param to Index of the last sample to be painted. If to < 0 the series will be painted to its last sample. \sa drawSeries(), drawSymbols() */ void QwtPlotIntervalCurve::drawTube( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { const bool doAlign = QwtPainter::roundingAlignment( painter ); painter->save(); const size_t size = to - from + 1; QPolygonF polygon( 2 * size ); QPointF *points = polygon.data(); for ( uint i = 0; i < size; i++ ) { QPointF &minValue = points[i]; QPointF &maxValue = points[2 * size - 1 - i]; const QwtIntervalSample intervalSample = sample( from + i ); if ( orientation() == Qt::Vertical ) { double x = xMap.transform( intervalSample.value ); double y1 = yMap.transform( intervalSample.interval.minValue() ); double y2 = yMap.transform( intervalSample.interval.maxValue() ); if ( doAlign ) { x = qRound( x ); y1 = qRound( y1 ); y2 = qRound( y2 ); } minValue.rx() = x; minValue.ry() = y1; maxValue.rx() = x; maxValue.ry() = y2; } else { double y = yMap.transform( intervalSample.value ); double x1 = xMap.transform( intervalSample.interval.minValue() ); double x2 = xMap.transform( intervalSample.interval.maxValue() ); if ( doAlign ) { y = qRound( y ); x1 = qRound( x1 ); x2 = qRound( x2 ); } minValue.rx() = x1; minValue.ry() = y; maxValue.rx() = x2; maxValue.ry() = y; } } if ( d_data->brush.style() != Qt::NoBrush ) { painter->setPen( QPen( Qt::NoPen ) ); painter->setBrush( d_data->brush ); if ( d_data->paintAttributes & ClipPolygons ) { const qreal m = 1.0; const QPolygonF p = QwtClipper::clipPolygonF( canvasRect.adjusted( -m, -m, m, m ), polygon, true ); QwtPainter::drawPolygon( painter, p ); } else { QwtPainter::drawPolygon( painter, polygon ); } } if ( d_data->pen.style() != Qt::NoPen ) { painter->setPen( d_data->pen ); painter->setBrush( Qt::NoBrush ); if ( d_data->paintAttributes & ClipPolygons ) { qreal pw = qMax( qreal( 1.0 ), painter->pen().widthF() ); const QRectF clipRect = canvasRect.adjusted( -pw, -pw, pw, pw ); QPolygonF p; p.resize( size ); ::memcpy( p.data(), points, size * sizeof( QPointF ) ); p = QwtClipper::clipPolygonF( clipRect, p ); QwtPainter::drawPolyline( painter, p ); p.resize( size ); ::memcpy( p.data(), points + size, size * sizeof( QPointF ) ); p = QwtClipper::clipPolygonF( clipRect, p ); QwtPainter::drawPolyline( painter, p ); } else { QwtPainter::drawPolyline( painter, points, size ); QwtPainter::drawPolyline( painter, points + size, size ); } } painter->restore(); } /*! Draw symbols for a subset of the samples \param painter Painter \param symbol Interval symbol \param xMap x map \param yMap y map \param canvasRect Contents rectangle of the canvas \param from Index of the first sample to be painted \param to Index of the last sample to be painted \sa setSymbol(), drawSeries(), drawTube() */ void QwtPlotIntervalCurve::drawSymbols( QPainter *painter, const QwtIntervalSymbol &symbol, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const { painter->save(); QPen pen = symbol.pen(); pen.setCapStyle( Qt::FlatCap ); painter->setPen( pen ); painter->setBrush( symbol.brush() ); const QRectF tr = QwtScaleMap::invTransform( xMap, yMap, canvasRect ); const double xMin = tr.left(); const double xMax = tr.right(); const double yMin = tr.top(); const double yMax = tr.bottom(); const bool doClip = d_data->paintAttributes & ClipSymbol; for ( int i = from; i <= to; i++ ) { const QwtIntervalSample s = sample( i ); if ( orientation() == Qt::Vertical ) { if ( !doClip || qwtIsVSampleInside( s, xMin, xMax, yMin, yMax ) ) { const double x = xMap.transform( s.value ); const double y1 = yMap.transform( s.interval.minValue() ); const double y2 = yMap.transform( s.interval.maxValue() ); symbol.draw( painter, orientation(), QPointF( x, y1 ), QPointF( x, y2 ) ); } } else { if ( !doClip || qwtIsHSampleInside( s, xMin, xMax, yMin, yMax ) ) { const double y = yMap.transform( s.value ); const double x1 = xMap.transform( s.interval.minValue() ); const double x2 = xMap.transform( s.interval.maxValue() ); symbol.draw( painter, orientation(), QPointF( x1, y ), QPointF( x2, y ) ); } } } painter->restore(); } /*! \return Icon for the legend In case of Tube style() the icon is a plain rectangle filled with the brush(). If a symbol is assigned it is scaled to size. \param index Index of the legend entry ( ignored as there is only one ) \param size Icon size \sa QwtPlotItem::setLegendIconSize(), QwtPlotItem::legendData() */ QwtGraphic QwtPlotIntervalCurve::legendIcon( int index, const QSizeF &size ) const { Q_UNUSED( index ); if ( size.isEmpty() ) return QwtGraphic(); QwtGraphic icon; icon.setDefaultSize( size ); icon.setRenderHint( QwtGraphic::RenderPensUnscaled, true ); QPainter painter( &icon ); painter.setRenderHint( QPainter::Antialiasing, testRenderHint( QwtPlotItem::RenderAntialiased ) ); if ( d_data->style == Tube ) { QRectF r( 0, 0, size.width(), size.height() ); painter.fillRect( r, d_data->brush ); } if ( d_data->symbol && ( d_data->symbol->style() != QwtIntervalSymbol::NoSymbol ) ) { QPen pen = d_data->symbol->pen(); pen.setWidthF( pen.widthF() ); pen.setCapStyle( Qt::FlatCap ); painter.setPen( pen ); painter.setBrush( d_data->symbol->brush() ); if ( orientation() == Qt::Vertical ) { const double x = 0.5 * size.width(); d_data->symbol->draw( &painter, orientation(), QPointF( x, 0 ), QPointF( x, size.height() - 1.0 ) ); } else { const double y = 0.5 * size.height(); d_data->symbol->draw( &painter, orientation(), QPointF( 0.0, y ), QPointF( size.width() - 1.0, y ) ); } } return icon; } connectome-workbench-1.4.2/src/Qwt/qwt_plot_intervalcurve.h000066400000000000000000000076401360521144700241770ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_INTERVAL_CURVE_H #define QWT_PLOT_INTERVAL_CURVE_H #include "qwt_global.h" #include "qwt_plot_seriesitem.h" #include "qwt_series_data.h" class QwtIntervalSymbol; /*! \brief QwtPlotIntervalCurve represents a series of samples, where each value is associated with an interval ( \f$[y1,y2] = f(x)\f$ ). The representation depends on the style() and an optional symbol() that is displayed for each interval. QwtPlotIntervalCurve might be used to display error bars or the area between 2 curves. */ class QWT_EXPORT QwtPlotIntervalCurve: public QwtPlotSeriesItem, public QwtSeriesStore { public: /*! \brief Curve styles. The default setting is QwtPlotIntervalCurve::Tube. \sa setStyle(), style() */ enum CurveStyle { /*! Don't draw a curve. Note: This doesn't affect the symbols. */ NoCurve, /*! Build 2 curves from the upper and lower limits of the intervals and draw them with the pen(). The area between the curves is filled with the brush(). */ Tube, /*! Styles >= QwtPlotIntervalCurve::UserCurve are reserved for derived classes that overload drawSeries() with additional application specific curve types. */ UserCurve = 100 }; /*! Attributes to modify the drawing algorithm. \sa setPaintAttribute(), testPaintAttribute() */ enum PaintAttribute { /*! Clip polygons before painting them. In situations, where points are far outside the visible area (f.e when zooming deep) this might be a substantial improvement for the painting performance. */ ClipPolygons = 0x01, //! Check if a symbol is on the plot canvas before painting it. ClipSymbol = 0x02 }; //! Paint attributes typedef QFlags PaintAttributes; explicit QwtPlotIntervalCurve( const QString &title = QString::null ); explicit QwtPlotIntervalCurve( const QwtText &title ); virtual ~QwtPlotIntervalCurve(); virtual int rtti() const; void setPaintAttribute( PaintAttribute, bool on = true ); bool testPaintAttribute( PaintAttribute ) const; void setSamples( const QVector & ); void setSamples( QwtSeriesData * ); void setPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine ); void setPen( const QPen & ); const QPen &pen() const; void setBrush( const QBrush & ); const QBrush &brush() const; void setStyle( CurveStyle style ); CurveStyle style() const; void setSymbol( const QwtIntervalSymbol * ); const QwtIntervalSymbol *symbol() const; virtual void drawSeries( QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; virtual QRectF boundingRect() const; virtual QwtGraphic legendIcon( int index, const QSizeF & ) const; protected: void init(); virtual void drawTube( QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; virtual void drawSymbols( QPainter *, const QwtIntervalSymbol &, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, int from, int to ) const; private: class PrivateData; PrivateData *d_data; }; Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotIntervalCurve::PaintAttributes ) #endif connectome-workbench-1.4.2/src/Qwt/qwt_plot_item.cpp000066400000000000000000000371461360521144700226030ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_item.h" #include "qwt_text.h" #include "qwt_plot.h" #include "qwt_legend_data.h" #include "qwt_scale_div.h" #include "qwt_graphic.h" #include class QwtPlotItem::PrivateData { public: PrivateData(): plot( NULL ), isVisible( true ), attributes( 0 ), interests( 0 ), renderHints( 0 ), renderThreadCount( 1 ), z( 0.0 ), xAxis( QwtPlot::xBottom ), yAxis( QwtPlot::yLeft ), legendIconSize( 8, 8 ) { } mutable QwtPlot *plot; bool isVisible; QwtPlotItem::ItemAttributes attributes; QwtPlotItem::ItemInterests interests; QwtPlotItem::RenderHints renderHints; uint renderThreadCount; double z; int xAxis; int yAxis; QwtText title; QSize legendIconSize; }; /*! Constructor \param title Title of the item */ QwtPlotItem::QwtPlotItem( const QwtText &title ) { d_data = new PrivateData; d_data->title = title; } //! Destroy the QwtPlotItem QwtPlotItem::~QwtPlotItem() { attach( NULL ); delete d_data; } /*! \brief Attach the item to a plot. This method will attach a QwtPlotItem to the QwtPlot argument. It will first detach the QwtPlotItem from any plot from a previous call to attach (if necessary). If a NULL argument is passed, it will detach from any QwtPlot it was attached to. \param plot Plot widget \sa detach() */ void QwtPlotItem::attach( QwtPlot *plot ) { if ( plot == d_data->plot ) return; if ( d_data->plot ) d_data->plot->attachItem( this, false ); d_data->plot = plot; if ( d_data->plot ) d_data->plot->attachItem( this, true ); } /*! \brief This method detaches a QwtPlotItem from any QwtPlot it has been associated with. detach() is equivalent to calling attach( NULL ) \sa attach() */ void QwtPlotItem::detach() { attach( NULL ); } /*! Return rtti for the specific class represented. QwtPlotItem is simply a virtual interface class, and base classes will implement this method with specific rtti values so a user can differentiate them. The rtti value is useful for environments, where the runtime type information is disabled and it is not possible to do a dynamic_cast<...>. \return rtti value \sa RttiValues */ int QwtPlotItem::rtti() const { return Rtti_PlotItem; } //! Return attached plot QwtPlot *QwtPlotItem::plot() const { return d_data->plot; } /*! Plot items are painted in increasing z-order. \return setZ(), QwtPlotDict::itemList() */ double QwtPlotItem::z() const { return d_data->z; } /*! \brief Set the z value Plot items are painted in increasing z-order. \param z Z-value \sa z(), QwtPlotDict::itemList() */ void QwtPlotItem::setZ( double z ) { if ( d_data->z != z ) { if ( d_data->plot ) // update the z order d_data->plot->attachItem( this, false ); d_data->z = z; if ( d_data->plot ) d_data->plot->attachItem( this, true ); itemChanged(); } } /*! Set a new title \param title Title \sa title() */ void QwtPlotItem::setTitle( const QString &title ) { setTitle( QwtText( title ) ); } /*! Set a new title \param title Title \sa title() */ void QwtPlotItem::setTitle( const QwtText &title ) { if ( d_data->title != title ) { d_data->title = title; legendChanged(); #if 0 itemChanged(); #endif } } /*! \return Title of the item \sa setTitle() */ const QwtText &QwtPlotItem::title() const { return d_data->title; } /*! Toggle an item attribute \param attribute Attribute type \param on true/false \sa testItemAttribute(), ItemInterest */ void QwtPlotItem::setItemAttribute( ItemAttribute attribute, bool on ) { if ( d_data->attributes.testFlag( attribute ) != on ) { if ( on ) d_data->attributes |= attribute; else d_data->attributes &= ~attribute; if ( attribute == QwtPlotItem::Legend ) legendChanged(); itemChanged(); } } /*! Test an item attribute \param attribute Attribute type \return true/false \sa setItemAttribute(), ItemInterest */ bool QwtPlotItem::testItemAttribute( ItemAttribute attribute ) const { return d_data->attributes.testFlag( attribute ); } /*! Toggle an item interest \param interest Interest type \param on true/false \sa testItemInterest(), ItemAttribute */ void QwtPlotItem::setItemInterest( ItemInterest interest, bool on ) { if ( d_data->interests.testFlag( interest ) != on ) { if ( on ) d_data->interests |= interest; else d_data->interests &= ~interest; itemChanged(); } } /*! Test an item interest \param interest Interest type \return true/false \sa setItemInterest(), ItemAttribute */ bool QwtPlotItem::testItemInterest( ItemInterest interest ) const { return d_data->interests.testFlag( interest ); } /*! Toggle an render hint \param hint Render hint \param on true/false \sa testRenderHint(), RenderHint */ void QwtPlotItem::setRenderHint( RenderHint hint, bool on ) { if ( d_data->renderHints.testFlag( hint ) != on ) { if ( on ) d_data->renderHints |= hint; else d_data->renderHints &= ~hint; itemChanged(); } } /*! Test a render hint \param hint Render hint \return true/false \sa setRenderHint(), RenderHint */ bool QwtPlotItem::testRenderHint( RenderHint hint ) const { return d_data->renderHints.testFlag( hint ); } /*! On multi core systems rendering of certain plot item ( f.e QwtPlotRasterItem ) can be done in parallel in several threads. The default setting is set to 1. \param numThreads Number of threads to be used for rendering. If numThreads is set to 0, the system specific ideal thread count is used. The default thread count is 1 ( = no additional threads ) */ void QwtPlotItem::setRenderThreadCount( uint numThreads ) { d_data->renderThreadCount = numThreads; } /*! \return Number of threads to be used for rendering. If numThreads() is set to 0, the system specific ideal thread count is used. */ uint QwtPlotItem::renderThreadCount() const { return d_data->renderThreadCount; } /*! Set the size of the legend icon The default setting is 8x8 pixels \param size Size \sa legendIconSize(), legendIcon() */ void QwtPlotItem::setLegendIconSize( const QSize &size ) { if ( d_data->legendIconSize != size ) { d_data->legendIconSize = size; legendChanged(); } } /*! \return Legend icon size \sa setLegendIconSize(), legendIcon() */ QSize QwtPlotItem::legendIconSize() const { return d_data->legendIconSize; } /*! \return Icon representing the item on the legend The default implementation returns an invalid icon \param index Index of the legend entry ( usually there is only one ) \param size Icon size \sa setLegendIconSize(), legendData() */ QwtGraphic QwtPlotItem::legendIcon( int index, const QSizeF &size ) const { Q_UNUSED( index ) Q_UNUSED( size ) return QwtGraphic(); } /*! \brief Return a default icon from a brush The default icon is a filled rectangle used in several derived classes as legendIcon(). \param brush Fill brush \param size Icon size \return A filled rectangle */ QwtGraphic QwtPlotItem::defaultIcon( const QBrush &brush, const QSizeF &size ) const { QwtGraphic icon; if ( !size.isEmpty() ) { icon.setDefaultSize( size ); QRectF r( 0, 0, size.width(), size.height() ); QPainter painter( &icon ); painter.fillRect( r, brush ); } return icon; } //! Show the item void QwtPlotItem::show() { setVisible( true ); } //! Hide the item void QwtPlotItem::hide() { setVisible( false ); } /*! Show/Hide the item \param on Show if true, otherwise hide \sa isVisible(), show(), hide() */ void QwtPlotItem::setVisible( bool on ) { if ( on != d_data->isVisible ) { d_data->isVisible = on; itemChanged(); } } /*! \return true if visible \sa setVisible(), show(), hide() */ bool QwtPlotItem::isVisible() const { return d_data->isVisible; } /*! Update the legend and call QwtPlot::autoRefresh() for the parent plot. \sa QwtPlot::legendChanged(), QwtPlot::autoRefresh() */ void QwtPlotItem::itemChanged() { if ( d_data->plot ) d_data->plot->autoRefresh(); } /*! Update the legend of the parent plot. \sa QwtPlot::updateLegend(), itemChanged() */ void QwtPlotItem::legendChanged() { if ( testItemAttribute( QwtPlotItem::Legend ) && d_data->plot ) d_data->plot->updateLegend( this ); } /*! Set X and Y axis The item will painted according to the coordinates of its Axes. \param xAxis X Axis ( QwtPlot::xBottom or QwtPlot::xTop ) \param yAxis Y Axis ( QwtPlot::yLeft or QwtPlot::yRight ) \sa setXAxis(), setYAxis(), xAxis(), yAxis(), QwtPlot::Axis */ void QwtPlotItem::setAxes( int xAxis, int yAxis ) { if ( xAxis == QwtPlot::xBottom || xAxis == QwtPlot::xTop ) d_data->xAxis = xAxis; if ( yAxis == QwtPlot::yLeft || yAxis == QwtPlot::yRight ) d_data->yAxis = yAxis; itemChanged(); } /*! Set the X axis The item will painted according to the coordinates its Axes. \param axis X Axis ( QwtPlot::xBottom or QwtPlot::xTop ) \sa setAxes(), setYAxis(), xAxis(), QwtPlot::Axis */ void QwtPlotItem::setXAxis( int axis ) { if ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop ) { d_data->xAxis = axis; itemChanged(); } } /*! Set the Y axis The item will painted according to the coordinates its Axes. \param axis Y Axis ( QwtPlot::yLeft or QwtPlot::yRight ) \sa setAxes(), setXAxis(), yAxis(), QwtPlot::Axis */ void QwtPlotItem::setYAxis( int axis ) { if ( axis == QwtPlot::yLeft || axis == QwtPlot::yRight ) { d_data->yAxis = axis; itemChanged(); } } //! Return xAxis int QwtPlotItem::xAxis() const { return d_data->xAxis; } //! Return yAxis int QwtPlotItem::yAxis() const { return d_data->yAxis; } /*! \return An invalid bounding rect: QRectF(1.0, 1.0, -2.0, -2.0) \note A width or height < 0.0 is ignored by the autoscaler */ QRectF QwtPlotItem::boundingRect() const { return QRectF( 1.0, 1.0, -2.0, -2.0 ); // invalid } /*! \brief Calculate a hint for the canvas margin When the QwtPlotItem::Margins flag is enabled the plot item indicates, that it needs some margins at the borders of the canvas. This is f.e. used by bar charts to reserve space for displaying the bars. The margins are in target device coordinates ( pixels on screen ) \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rectangle of the canvas in painter coordinates \param left Returns the left margin \param top Returns the top margin \param right Returns the right margin \param bottom Returns the bottom margin \return The default implementation returns 0 for all margins \sa QwtPlot::getCanvasMarginsHint(), QwtPlot::updateCanvasMargins() */ void QwtPlotItem::getCanvasMarginHint( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect, double &left, double &top, double &right, double &bottom ) const { Q_UNUSED( xMap ); Q_UNUSED( yMap ); Q_UNUSED( canvasRect ); // use QMargins, when we don't need to support Qt < 4.6 anymore left = top = right = bottom = 0.0; } /*! \brief Return all information, that is needed to represent the item on the legend Most items are represented by one entry on the legend showing an icon and a text, but f.e. QwtPlotMultiBarChart displays one entry for each bar. QwtLegendData is basically a list of QVariants that makes it possible to overload and reimplement legendData() to return almost any type of information, that is understood by the receiver that acts as the legend. The default implementation returns one entry with the title() of the item and the legendIcon(). \return Data, that is needed to represent the item on the legend \sa title(), legendIcon(), QwtLegend, QwtPlotLegendItem */ QList QwtPlotItem::legendData() const { QwtLegendData data; QwtText label = title(); label.setRenderFlags( label.renderFlags() & Qt::AlignLeft ); QVariant titleValue; qVariantSetValue( titleValue, label ); data.setValue( QwtLegendData::TitleRole, titleValue ); const QwtGraphic graphic = legendIcon( 0, legendIconSize() ); if ( !graphic.isNull() ) { QVariant iconValue; qVariantSetValue( iconValue, graphic ); data.setValue( QwtLegendData::IconRole, iconValue ); } QList list; list += data; return list; } /*! \brief Update the item to changes of the axes scale division Update the item, when the axes of plot have changed. The default implementation does nothing, but items that depend on the scale division (like QwtPlotGrid()) have to reimplement updateScaleDiv() updateScaleDiv() is only called when the ScaleInterest interest is enabled. The default implementation does nothing. \param xScaleDiv Scale division of the x-axis \param yScaleDiv Scale division of the y-axis \sa QwtPlot::updateAxes(), ScaleInterest */ void QwtPlotItem::updateScaleDiv( const QwtScaleDiv &xScaleDiv, const QwtScaleDiv &yScaleDiv ) { Q_UNUSED( xScaleDiv ); Q_UNUSED( yScaleDiv ); } /*! \brief Update the item to changes of the legend info Plot items that want to display a legend ( not those, that want to be displayed on a legend ! ) will have to implement updateLegend(). updateLegend() is only called when the LegendInterest interest is enabled. The default implementation does nothing. \param item Plot item to be displayed on a legend \param data Attributes how to display item on the legend \sa QwtPlotLegendItem \note Plot items, that want to be displayed on a legend need to enable the QwtPlotItem::Legend flag and to implement legendData() and legendIcon() */ void QwtPlotItem::updateLegend( const QwtPlotItem *item, const QList &data ) { Q_UNUSED( item ); Q_UNUSED( data ); } /*! \brief Calculate the bounding scale rectangle of 2 maps \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \return Bounding scale rect of the scale maps, not normalized */ QRectF QwtPlotItem::scaleRect( const QwtScaleMap &xMap, const QwtScaleMap &yMap ) const { return QRectF( xMap.s1(), yMap.s1(), xMap.sDist(), yMap.sDist() ); } /*! \brief Calculate the bounding paint rectangle of 2 maps \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \return Bounding paint rectangle of the scale maps, not normalized */ QRectF QwtPlotItem::paintRect( const QwtScaleMap &xMap, const QwtScaleMap &yMap ) const { const QRectF rect( xMap.p1(), yMap.p1(), xMap.pDist(), yMap.pDist() ); return rect; } connectome-workbench-1.4.2/src/Qwt/qwt_plot_item.h000066400000000000000000000202331360521144700222350ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_ITEM_H #define QWT_PLOT_ITEM_H #include "qwt_global.h" #include "qwt_text.h" #include "qwt_legend_data.h" #include "qwt_graphic.h" #include #include #include class QPainter; class QwtScaleMap; class QwtScaleDiv; class QwtPlot; /*! \brief Base class for items on the plot canvas A plot item is "something", that can be painted on the plot canvas, or only affects the scales of the plot widget. They can be categorized as: - Representator\n A "Representator" is an item that represents some sort of data on the plot canvas. The different representator classes are organized according to the characteristics of the data: - QwtPlotMarker Represents a point or a horizontal/vertical coordinate - QwtPlotCurve Represents a series of points - QwtPlotSpectrogram ( QwtPlotRasterItem ) Represents raster data - ... - Decorators\n A "Decorator" is an item, that displays additional information, that is not related to any data: - QwtPlotGrid - QwtPlotScaleItem - QwtPlotSvgItem - ... Depending on the QwtPlotItem::ItemAttribute flags, an item is included into autoscaling or has an entry on the legend. Before misusing the existing item classes it might be better to implement a new type of plot item ( don't implement a watermark as spectrogram ). Deriving a new type of QwtPlotItem primarily means to implement the YourPlotItem::draw() method. \sa The cpuplot example shows the implementation of additional plot items. */ class QWT_EXPORT QwtPlotItem { public: /*! \brief Runtime type information RttiValues is used to cast plot items, without having to enable runtime type information of the compiler. */ enum RttiValues { //! Unspecific value, that can be used, when it doesn't matter Rtti_PlotItem = 0, //! For QwtPlotGrid Rtti_PlotGrid, //! For QwtPlotScaleItem Rtti_PlotScale, //! For QwtPlotLegendItem Rtti_PlotLegend, //! For QwtPlotMarker Rtti_PlotMarker, //! For QwtPlotCurve Rtti_PlotCurve, //! For QwtPlotSpectroCurve Rtti_PlotSpectroCurve, //! For QwtPlotIntervalCurve Rtti_PlotIntervalCurve, //! For QwtPlotHistogram Rtti_PlotHistogram, //! For QwtPlotSpectrogram Rtti_PlotSpectrogram, //! For QwtPlotSvgItem Rtti_PlotSVG, //! For QwtPlotTradingCurve Rtti_PlotTradingCurve, //! For QwtPlotBarChart Rtti_PlotBarChart, //! For QwtPlotMultiBarChart Rtti_PlotMultiBarChart, //! For QwtPlotShapeItem Rtti_PlotShape, //! For QwtPlotTextLabel Rtti_PlotTextLabel, //! For QwtPlotZoneItem Rtti_PlotZone, /*! Values >= Rtti_PlotUserItem are reserved for plot items not implemented in the Qwt library. */ Rtti_PlotUserItem = 1000 }; /*! \brief Plot Item Attributes Various aspects of a plot widget depend on the attributes of the attached plot items. If and how a single plot item participates in these updates depends on its attributes. \sa setItemAttribute(), testItemAttribute(), ItemInterest */ enum ItemAttribute { //! The item is represented on the legend. Legend = 0x01, /*! The boundingRect() of the item is included in the autoscaling calculation as long as its width or height is >= 0.0. */ AutoScale = 0x02, /*! The item needs extra space to display something outside its bounding rectangle. \sa getCanvasMarginHint() */ Margins = 0x04 }; //! Plot Item Attributes typedef QFlags ItemAttributes; /*! \brief Plot Item Interests Plot items might depend on the situation of the corresponding plot widget. By enabling an interest the plot item will be notified, when the corresponding attribute of the plot widgets has changed. \sa setItemAttribute(), testItemAttribute(), ItemInterest */ enum ItemInterest { /*! The item is interested in updates of the scales \sa updateScaleDiv() */ ScaleInterest = 0x01, /*! The item is interested in updates of the legend ( of other items ) This flag is intended for items, that want to implement a legend for displaying entries of other plot item. \note If the plot item wants to be represented on a legend enable QwtPlotItem::Legend instead. \sa updateLegend() */ LegendInterest = 0x02 }; //! Plot Item Interests typedef QFlags ItemInterests; //! Render hints enum RenderHint { //! Enable antialiasing RenderAntialiased = 0x1 }; //! Render hints typedef QFlags RenderHints; explicit QwtPlotItem( const QwtText &title = QwtText() ); virtual ~QwtPlotItem(); void attach( QwtPlot *plot ); void detach(); QwtPlot *plot() const; void setTitle( const QString &title ); void setTitle( const QwtText &title ); const QwtText &title() const; virtual int rtti() const; void setItemAttribute( ItemAttribute, bool on = true ); bool testItemAttribute( ItemAttribute ) const; void setItemInterest( ItemInterest, bool on = true ); bool testItemInterest( ItemInterest ) const; void setRenderHint( RenderHint, bool on = true ); bool testRenderHint( RenderHint ) const; void setRenderThreadCount( uint numThreads ); uint renderThreadCount() const; void setLegendIconSize( const QSize & ); QSize legendIconSize() const; double z() const; void setZ( double z ); void show(); void hide(); virtual void setVisible( bool ); bool isVisible () const; void setAxes( int xAxis, int yAxis ); void setXAxis( int axis ); int xAxis() const; void setYAxis( int axis ); int yAxis() const; virtual void itemChanged(); virtual void legendChanged(); /*! \brief Draw the item \param painter Painter \param xMap Maps x-values into pixel coordinates. \param yMap Maps y-values into pixel coordinates. \param canvasRect Contents rect of the canvas in painter coordinates */ virtual void draw( QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect ) const = 0; virtual QRectF boundingRect() const; virtual void getCanvasMarginHint( const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasSize, double &left, double &top, double &right, double &bottom) const; virtual void updateScaleDiv( const QwtScaleDiv&, const QwtScaleDiv& ); virtual void updateLegend( const QwtPlotItem *, const QList & ); QRectF scaleRect( const QwtScaleMap &, const QwtScaleMap & ) const; QRectF paintRect( const QwtScaleMap &, const QwtScaleMap & ) const; virtual QList legendData() const; virtual QwtGraphic legendIcon( int index, const QSizeF & ) const; protected: QwtGraphic defaultIcon( const QBrush &, const QSizeF & ) const; private: // Disabled copy constructor and operator= QwtPlotItem( const QwtPlotItem & ); QwtPlotItem &operator=( const QwtPlotItem & ); class PrivateData; PrivateData *d_data; }; Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotItem::ItemAttributes ) Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotItem::ItemInterests ) Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotItem::RenderHints ) Q_DECLARE_METATYPE( QwtPlotItem * ) #endif connectome-workbench-1.4.2/src/Qwt/qwt_plot_layout.cpp000066400000000000000000001256151360521144700231610ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_plot_layout.h" #include "qwt_text.h" #include "qwt_text_label.h" #include "qwt_scale_widget.h" #include "qwt_abstract_legend.h" #include #include class QwtPlotLayout::LayoutData { public: void init( const QwtPlot *, const QRectF &rect ); struct t_legendData { int frameWidth; int hScrollExtent; int vScrollExtent; QSize hint; } legend; struct t_titleData { QwtText text; int frameWidth; } title; struct t_footerData { QwtText text; int frameWidth; } footer; struct t_scaleData { bool isEnabled; const QwtScaleWidget *scaleWidget; QFont scaleFont; int start; int end; int baseLineOffset; double tickOffset; int dimWithoutTitle; } scale[QwtPlot::axisCnt]; struct t_canvasData { int contentsMargins[ QwtPlot::axisCnt ]; } canvas; }; /* Extract all layout relevant data from the plot components */ void QwtPlotLayout::LayoutData::init( const QwtPlot *plot, const QRectF &rect ) { // legend if ( plot->legend() ) { legend.frameWidth = plot->legend()->frameWidth(); legend.hScrollExtent = plot->legend()->scrollExtent( Qt::Horizontal ); legend.vScrollExtent = plot->legend()->scrollExtent( Qt::Vertical ); const QSize hint = plot->legend()->sizeHint(); int w = qMin( hint.width(), qFloor( rect.width() ) ); int h = plot->legend()->heightForWidth( w ); if ( h <= 0 ) h = hint.height(); if ( h > rect.height() ) w += legend.hScrollExtent; legend.hint = QSize( w, h ); } // title title.frameWidth = 0; title.text = QwtText(); if ( plot->titleLabel() ) { const QwtTextLabel *label = plot->titleLabel(); title.text = label->text(); if ( !( title.text.testPaintAttribute( QwtText::PaintUsingTextFont ) ) ) title.text.setFont( label->font() ); title.frameWidth = plot->titleLabel()->frameWidth(); } // footer footer.frameWidth = 0; footer.text = QwtText(); if ( plot->footerLabel() ) { const QwtTextLabel *label = plot->footerLabel(); footer.text = label->text(); if ( !( footer.text.testPaintAttribute( QwtText::PaintUsingTextFont ) ) ) footer.text.setFont( label->font() ); footer.frameWidth = plot->footerLabel()->frameWidth(); } // scales for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { if ( plot->axisEnabled( axis ) ) { const QwtScaleWidget *scaleWidget = plot->axisWidget( axis ); scale[axis].isEnabled = true; scale[axis].scaleWidget = scaleWidget; scale[axis].scaleFont = scaleWidget->font(); scale[axis].start = scaleWidget->startBorderDist(); scale[axis].end = scaleWidget->endBorderDist(); scale[axis].baseLineOffset = scaleWidget->margin(); scale[axis].tickOffset = scaleWidget->margin(); if ( scaleWidget->scaleDraw()->hasComponent( QwtAbstractScaleDraw::Ticks ) ) { scale[axis].tickOffset += scaleWidget->scaleDraw()->maxTickLength(); } scale[axis].dimWithoutTitle = scaleWidget->dimForLength( QWIDGETSIZE_MAX, scale[axis].scaleFont ); if ( !scaleWidget->title().isEmpty() ) { scale[axis].dimWithoutTitle -= scaleWidget->titleHeightForWidth( QWIDGETSIZE_MAX ); } } else { scale[axis].isEnabled = false; scale[axis].start = 0; scale[axis].end = 0; scale[axis].baseLineOffset = 0; scale[axis].tickOffset = 0.0; scale[axis].dimWithoutTitle = 0; } } // canvas plot->canvas()->getContentsMargins( &canvas.contentsMargins[ QwtPlot::yLeft ], &canvas.contentsMargins[ QwtPlot::xTop ], &canvas.contentsMargins[ QwtPlot::yRight ], &canvas.contentsMargins[ QwtPlot::xBottom ] ); } class QwtPlotLayout::PrivateData { public: PrivateData(): spacing( 5 ) { } QRectF titleRect; QRectF footerRect; QRectF legendRect; QRectF scaleRect[QwtPlot::axisCnt]; QRectF canvasRect; QwtPlotLayout::LayoutData layoutData; QwtPlot::LegendPosition legendPos; double legendRatio; unsigned int spacing; unsigned int canvasMargin[QwtPlot::axisCnt]; bool alignCanvasToScales[QwtPlot::axisCnt]; }; /*! \brief Constructor */ QwtPlotLayout::QwtPlotLayout() { d_data = new PrivateData; setLegendPosition( QwtPlot::BottomLegend ); setCanvasMargin( 4 ); setAlignCanvasToScales( false ); invalidate(); } //! Destructor QwtPlotLayout::~QwtPlotLayout() { delete d_data; } /*! Change a margin of the canvas. The margin is the space above/below the scale ticks. A negative margin will be set to -1, excluding the borders of the scales. \param margin New margin \param axis One of QwtPlot::Axis. Specifies where the position of the margin. -1 means margin at all borders. \sa canvasMargin() \warning The margin will have no effect when alignCanvasToScale() is true */ void QwtPlotLayout::setCanvasMargin( int margin, int axis ) { if ( margin < -1 ) margin = -1; if ( axis == -1 ) { for ( axis = 0; axis < QwtPlot::axisCnt; axis++ ) d_data->canvasMargin[axis] = margin; } else if ( axis >= 0 && axis < QwtPlot::axisCnt ) d_data->canvasMargin[axis] = margin; } /*! \param axisId Axis index \return Margin around the scale tick borders \sa setCanvasMargin() */ int QwtPlotLayout::canvasMargin( int axisId ) const { if ( axisId < 0 || axisId >= QwtPlot::axisCnt ) return 0; return d_data->canvasMargin[axisId]; } /*! \brief Set the align-canvas-to-axis-scales flag for all axes \param on True/False \sa setAlignCanvasToScale(), alignCanvasToScale() */ void QwtPlotLayout::setAlignCanvasToScales( bool on ) { for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) d_data->alignCanvasToScales[axis] = on; } /*! Change the align-canvas-to-axis-scales setting. The canvas may: - extend beyond the axis scale ends to maximize its size, - align with the axis scale ends to control its size. The axisId parameter is somehow confusing as it identifies a border of the plot and not the axes, that are aligned. F.e when QwtPlot::yLeft is set, the left end of the the x-axes ( QwtPlot::xTop, QwtPlot::xBottom ) is aligned. \param axisId Axis index \param on New align-canvas-to-axis-scales setting \sa setCanvasMargin(), alignCanvasToScale(), setAlignCanvasToScales() \warning In case of on == true canvasMargin() will have no effect */ void QwtPlotLayout::setAlignCanvasToScale( int axisId, bool on ) { if ( axisId >= 0 && axisId < QwtPlot::axisCnt ) d_data->alignCanvasToScales[axisId] = on; } /*! Return the align-canvas-to-axis-scales setting. The canvas may: - extend beyond the axis scale ends to maximize its size - align with the axis scale ends to control its size. \param axisId Axis index \return align-canvas-to-axis-scales setting \sa setAlignCanvasToScale(), setAlignCanvasToScale(), setCanvasMargin() */ bool QwtPlotLayout::alignCanvasToScale( int axisId ) const { if ( axisId < 0 || axisId >= QwtPlot::axisCnt ) return false; return d_data->alignCanvasToScales[ axisId ]; } /*! Change the spacing of the plot. The spacing is the distance between the plot components. \param spacing New spacing \sa setCanvasMargin(), spacing() */ void QwtPlotLayout::setSpacing( int spacing ) { d_data->spacing = qMax( 0, spacing ); } /*! \return Spacing \sa margin(), setSpacing() */ int QwtPlotLayout::spacing() const { return d_data->spacing; } /*! \brief Specify the position of the legend \param pos The legend's position. \param ratio Ratio between legend and the bounding rectangle of title, footer, canvas and axes. The legend will be shrunk if it would need more space than the given ratio. The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0 it will be reset to the default ratio. The default vertical/horizontal ratio is 0.33/0.5. \sa QwtPlot::setLegendPosition() */ void QwtPlotLayout::setLegendPosition( QwtPlot::LegendPosition pos, double ratio ) { if ( ratio > 1.0 ) ratio = 1.0; switch ( pos ) { case QwtPlot::TopLegend: case QwtPlot::BottomLegend: if ( ratio <= 0.0 ) ratio = 0.33; d_data->legendRatio = ratio; d_data->legendPos = pos; break; case QwtPlot::LeftLegend: case QwtPlot::RightLegend: if ( ratio <= 0.0 ) ratio = 0.5; d_data->legendRatio = ratio; d_data->legendPos = pos; break; default: break; } } /*! \brief Specify the position of the legend \param pos The legend's position. Valid values are \c QwtPlot::LeftLegend, \c QwtPlot::RightLegend, \c QwtPlot::TopLegend, \c QwtPlot::BottomLegend. \sa QwtPlot::setLegendPosition() */ void QwtPlotLayout::setLegendPosition( QwtPlot::LegendPosition pos ) { setLegendPosition( pos, 0.0 ); } /*! \return Position of the legend \sa setLegendPosition(), QwtPlot::setLegendPosition(), QwtPlot::legendPosition() */ QwtPlot::LegendPosition QwtPlotLayout::legendPosition() const { return d_data->legendPos; } /*! Specify the relative size of the legend in the plot \param ratio Ratio between legend and the bounding rectangle of title, footer, canvas and axes. The legend will be shrunk if it would need more space than the given ratio. The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0 it will be reset to the default ratio. The default vertical/horizontal ratio is 0.33/0.5. */ void QwtPlotLayout::setLegendRatio( double ratio ) { setLegendPosition( legendPosition(), ratio ); } /*! \return The relative size of the legend in the plot. \sa setLegendPosition() */ double QwtPlotLayout::legendRatio() const { return d_data->legendRatio; } /*! \brief Set the geometry for the title This method is intended to be used from derived layouts overloading activate() \sa titleRect(), activate() */ void QwtPlotLayout::setTitleRect( const QRectF &rect ) { d_data->titleRect = rect; } /*! \return Geometry for the title \sa activate(), invalidate() */ QRectF QwtPlotLayout::titleRect() const { return d_data->titleRect; } /*! \brief Set the geometry for the footer This method is intended to be used from derived layouts overloading activate() \sa footerRect(), activate() */ void QwtPlotLayout::setFooterRect( const QRectF &rect ) { d_data->footerRect = rect; } /*! \return Geometry for the footer \sa activate(), invalidate() */ QRectF QwtPlotLayout::footerRect() const { return d_data->footerRect; } /*! \brief Set the geometry for the legend This method is intended to be used from derived layouts overloading activate() \param rect Rectangle for the legend \sa legendRect(), activate() */ void QwtPlotLayout::setLegendRect( const QRectF &rect ) { d_data->legendRect = rect; } /*! \return Geometry for the legend \sa activate(), invalidate() */ QRectF QwtPlotLayout::legendRect() const { return d_data->legendRect; } /*! \brief Set the geometry for an axis This method is intended to be used from derived layouts overloading activate() \param axis Axis index \param rect Rectangle for the scale \sa scaleRect(), activate() */ void QwtPlotLayout::setScaleRect( int axis, const QRectF &rect ) { if ( axis >= 0 && axis < QwtPlot::axisCnt ) d_data->scaleRect[axis] = rect; } /*! \param axis Axis index \return Geometry for the scale \sa activate(), invalidate() */ QRectF QwtPlotLayout::scaleRect( int axis ) const { if ( axis < 0 || axis >= QwtPlot::axisCnt ) { static QRectF dummyRect; return dummyRect; } return d_data->scaleRect[axis]; } /*! \brief Set the geometry for the canvas This method is intended to be used from derived layouts overloading activate() \sa canvasRect(), activate() */ void QwtPlotLayout::setCanvasRect( const QRectF &rect ) { d_data->canvasRect = rect; } /*! \return Geometry for the canvas \sa activate(), invalidate() */ QRectF QwtPlotLayout::canvasRect() const { return d_data->canvasRect; } /*! Invalidate the geometry of all components. \sa activate() */ void QwtPlotLayout::invalidate() { d_data->titleRect = d_data->footerRect = d_data->legendRect = d_data->canvasRect = QRect(); for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) d_data->scaleRect[axis] = QRect(); } /*! \return Minimum size hint \param plot Plot widget \sa QwtPlot::minimumSizeHint() */ QSize QwtPlotLayout::minimumSizeHint( const QwtPlot *plot ) const { class ScaleData { public: ScaleData() { w = h = minLeft = minRight = tickOffset = 0; } int w; int h; int minLeft; int minRight; int tickOffset; } scaleData[QwtPlot::axisCnt]; int canvasBorder[QwtPlot::axisCnt]; int fw; plot->canvas()->getContentsMargins( &fw, NULL, NULL, NULL ); int axis; for ( axis = 0; axis < QwtPlot::axisCnt; axis++ ) { if ( plot->axisEnabled( axis ) ) { const QwtScaleWidget *scl = plot->axisWidget( axis ); ScaleData &sd = scaleData[axis]; const QSize hint = scl->minimumSizeHint(); sd.w = hint.width(); sd.h = hint.height(); scl->getBorderDistHint( sd.minLeft, sd.minRight ); sd.tickOffset = scl->margin(); if ( scl->scaleDraw()->hasComponent( QwtAbstractScaleDraw::Ticks ) ) sd.tickOffset += qCeil( scl->scaleDraw()->maxTickLength() ); } canvasBorder[axis] = fw + d_data->canvasMargin[axis] + 1; } for ( axis = 0; axis < QwtPlot::axisCnt; axis++ ) { ScaleData &sd = scaleData[axis]; if ( sd.w && ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop ) ) { if ( ( sd.minLeft > canvasBorder[QwtPlot::yLeft] ) && scaleData[QwtPlot::yLeft].w ) { int shiftLeft = sd.minLeft - canvasBorder[QwtPlot::yLeft]; if ( shiftLeft > scaleData[QwtPlot::yLeft].w ) shiftLeft = scaleData[QwtPlot::yLeft].w; sd.w -= shiftLeft; } if ( ( sd.minRight > canvasBorder[QwtPlot::yRight] ) && scaleData[QwtPlot::yRight].w ) { int shiftRight = sd.minRight - canvasBorder[QwtPlot::yRight]; if ( shiftRight > scaleData[QwtPlot::yRight].w ) shiftRight = scaleData[QwtPlot::yRight].w; sd.w -= shiftRight; } } if ( sd.h && ( axis == QwtPlot::yLeft || axis == QwtPlot::yRight ) ) { if ( ( sd.minLeft > canvasBorder[QwtPlot::xBottom] ) && scaleData[QwtPlot::xBottom].h ) { int shiftBottom = sd.minLeft - canvasBorder[QwtPlot::xBottom]; if ( shiftBottom > scaleData[QwtPlot::xBottom].tickOffset ) shiftBottom = scaleData[QwtPlot::xBottom].tickOffset; sd.h -= shiftBottom; } if ( ( sd.minLeft > canvasBorder[QwtPlot::xTop] ) && scaleData[QwtPlot::xTop].h ) { int shiftTop = sd.minRight - canvasBorder[QwtPlot::xTop]; if ( shiftTop > scaleData[QwtPlot::xTop].tickOffset ) shiftTop = scaleData[QwtPlot::xTop].tickOffset; sd.h -= shiftTop; } } } const QWidget *canvas = plot->canvas(); int left, top, right, bottom; canvas->getContentsMargins( &left, &top, &right, &bottom ); const QSize minCanvasSize = canvas->minimumSize(); int w = scaleData[QwtPlot::yLeft].w + scaleData[QwtPlot::yRight].w; int cw = qMax( scaleData[QwtPlot::xBottom].w, scaleData[QwtPlot::xTop].w ) + left + 1 + right + 1; w += qMax( cw, minCanvasSize.width() ); int h = scaleData[QwtPlot::xBottom].h + scaleData[QwtPlot::xTop].h; int ch = qMax( scaleData[QwtPlot::yLeft].h, scaleData[QwtPlot::yRight].h ) + top + 1 + bottom + 1; h += qMax( ch, minCanvasSize.height() ); const QwtTextLabel *labels[2]; labels[0] = plot->titleLabel(); labels[1] = plot->footerLabel(); for ( int i = 0; i < 2; i++ ) { const QwtTextLabel *label = labels[i]; if ( label && !label->text().isEmpty() ) { // If only QwtPlot::yLeft or QwtPlot::yRight is showing, // we center on the plot canvas. const bool centerOnCanvas = !( plot->axisEnabled( QwtPlot::yLeft ) && plot->axisEnabled( QwtPlot::yRight ) ); int labelW = w; if ( centerOnCanvas ) { labelW -= scaleData[QwtPlot::yLeft].w + scaleData[QwtPlot::yRight].w; } int labelH = label->heightForWidth( labelW ); if ( labelH > labelW ) // Compensate for a long title { w = labelW = labelH; if ( centerOnCanvas ) { w += scaleData[QwtPlot::yLeft].w + scaleData[QwtPlot::yRight].w; } labelH = label->heightForWidth( labelW ); } h += labelH + d_data->spacing; } } // Compute the legend contribution const QwtAbstractLegend *legend = plot->legend(); if ( legend && !legend->isEmpty() ) { if ( d_data->legendPos == QwtPlot::LeftLegend || d_data->legendPos == QwtPlot::RightLegend ) { int legendW = legend->sizeHint().width(); int legendH = legend->heightForWidth( legendW ); if ( legend->frameWidth() > 0 ) w += d_data->spacing; if ( legendH > h ) legendW += legend->scrollExtent( Qt::Horizontal ); if ( d_data->legendRatio < 1.0 ) legendW = qMin( legendW, int( w / ( 1.0 - d_data->legendRatio ) ) ); w += legendW + d_data->spacing; } else // QwtPlot::Top, QwtPlot::Bottom { int legendW = qMin( legend->sizeHint().width(), w ); int legendH = legend->heightForWidth( legendW ); if ( legend->frameWidth() > 0 ) h += d_data->spacing; if ( d_data->legendRatio < 1.0 ) legendH = qMin( legendH, int( h / ( 1.0 - d_data->legendRatio ) ) ); h += legendH + d_data->spacing; } } return QSize( w, h ); } /*! Find the geometry for the legend \param options Options how to layout the legend \param rect Rectangle where to place the legend \return Geometry for the legend \sa Options */ QRectF QwtPlotLayout::layoutLegend( Options options, const QRectF &rect ) const { const QSize hint( d_data->layoutData.legend.hint ); int dim; if ( d_data->legendPos == QwtPlot::LeftLegend || d_data->legendPos == QwtPlot::RightLegend ) { // We don't allow vertical legends to take more than // half of the available space. dim = qMin( hint.width(), int( rect.width() * d_data->legendRatio ) ); if ( !( options & IgnoreScrollbars ) ) { if ( hint.height() > rect.height() ) { // The legend will need additional // space for the vertical scrollbar. dim += d_data->layoutData.legend.hScrollExtent; } } } else { dim = qMin( hint.height(), int( rect.height() * d_data->legendRatio ) ); dim = qMax( dim, d_data->layoutData.legend.vScrollExtent ); } QRectF legendRect = rect; switch ( d_data->legendPos ) { case QwtPlot::LeftLegend: legendRect.setWidth( dim ); break; case QwtPlot::RightLegend: legendRect.setX( rect.right() - dim ); legendRect.setWidth( dim ); break; case QwtPlot::TopLegend: legendRect.setHeight( dim ); break; case QwtPlot::BottomLegend: legendRect.setY( rect.bottom() - dim ); legendRect.setHeight( dim ); break; } return legendRect; } /*! Align the legend to the canvas \param canvasRect Geometry of the canvas \param legendRect Maximum geometry for the legend \return Geometry for the aligned legend */ QRectF QwtPlotLayout::alignLegend( const QRectF &canvasRect, const QRectF &legendRect ) const { QRectF alignedRect = legendRect; if ( d_data->legendPos == QwtPlot::BottomLegend || d_data->legendPos == QwtPlot::TopLegend ) { if ( d_data->layoutData.legend.hint.width() < canvasRect.width() ) { alignedRect.setX( canvasRect.x() ); alignedRect.setWidth( canvasRect.width() ); } } else { if ( d_data->layoutData.legend.hint.height() < canvasRect.height() ) { alignedRect.setY( canvasRect.y() ); alignedRect.setHeight( canvasRect.height() ); } } return alignedRect; } /*! Expand all line breaks in text labels, and calculate the height of their widgets in orientation of the text. \param options Options how to layout the legend \param rect Bounding rectangle for title, footer, axes and canvas. \param dimTitle Expanded height of the title widget \param dimFooter Expanded height of the footer widget \param dimAxis Expanded heights of the axis in axis orientation. \sa Options */ void QwtPlotLayout::expandLineBreaks( Options options, const QRectF &rect, int &dimTitle, int &dimFooter, int dimAxis[QwtPlot::axisCnt] ) const { dimTitle = dimFooter = 0; for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) dimAxis[axis] = 0; int backboneOffset[QwtPlot::axisCnt]; for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { backboneOffset[axis] = 0; if ( !( options & IgnoreFrames ) ) backboneOffset[axis] += d_data->layoutData.canvas.contentsMargins[ axis ]; if ( !d_data->alignCanvasToScales[axis] ) backboneOffset[axis] += d_data->canvasMargin[axis]; } bool done = false; while ( !done ) { done = true; // the size for the 4 axis depend on each other. Expanding // the height of a horizontal axis will shrink the height // for the vertical axis, shrinking the height of a vertical // axis will result in a line break what will expand the // width and results in shrinking the width of a horizontal // axis what might result in a line break of a horizontal // axis ... . So we loop as long until no size changes. if ( !( ( options & IgnoreTitle ) || d_data->layoutData.title.text.isEmpty() ) ) { double w = rect.width(); if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled != d_data->layoutData.scale[QwtPlot::yRight].isEnabled ) { // center to the canvas w -= dimAxis[QwtPlot::yLeft] + dimAxis[QwtPlot::yRight]; } int d = qCeil( d_data->layoutData.title.text.heightForWidth( w ) ); if ( !( options & IgnoreFrames ) ) d += 2 * d_data->layoutData.title.frameWidth; if ( d > dimTitle ) { dimTitle = d; done = false; } } if ( !( ( options & IgnoreFooter ) || d_data->layoutData.footer.text.isEmpty() ) ) { double w = rect.width(); if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled != d_data->layoutData.scale[QwtPlot::yRight].isEnabled ) { // center to the canvas w -= dimAxis[QwtPlot::yLeft] + dimAxis[QwtPlot::yRight]; } int d = qCeil( d_data->layoutData.footer.text.heightForWidth( w ) ); if ( !( options & IgnoreFrames ) ) d += 2 * d_data->layoutData.footer.frameWidth; if ( d > dimFooter ) { dimFooter = d; done = false; } } for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { const struct LayoutData::t_scaleData &scaleData = d_data->layoutData.scale[axis]; if ( scaleData.isEnabled ) { double length; if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom ) { length = rect.width() - dimAxis[QwtPlot::yLeft] - dimAxis[QwtPlot::yRight]; length -= scaleData.start + scaleData.end; if ( dimAxis[QwtPlot::yRight] > 0 ) length -= 1; length += qMin( dimAxis[QwtPlot::yLeft], scaleData.start - backboneOffset[QwtPlot::yLeft] ); length += qMin( dimAxis[QwtPlot::yRight], scaleData.end - backboneOffset[QwtPlot::yRight] ); } else // QwtPlot::yLeft, QwtPlot::yRight { length = rect.height() - dimAxis[QwtPlot::xTop] - dimAxis[QwtPlot::xBottom]; length -= scaleData.start + scaleData.end; length -= 1; if ( dimAxis[QwtPlot::xBottom] <= 0 ) length -= 1; if ( dimAxis[QwtPlot::xTop] <= 0 ) length -= 1; if ( dimAxis[QwtPlot::xBottom] > 0 ) { length += qMin( d_data->layoutData.scale[QwtPlot::xBottom].tickOffset, double( scaleData.start - backboneOffset[QwtPlot::xBottom] ) ); } if ( dimAxis[QwtPlot::xTop] > 0 ) { length += qMin( d_data->layoutData.scale[QwtPlot::xTop].tickOffset, double( scaleData.end - backboneOffset[QwtPlot::xTop] ) ); } if ( dimTitle > 0 ) length -= dimTitle + d_data->spacing; } int d = scaleData.dimWithoutTitle; if ( !scaleData.scaleWidget->title().isEmpty() ) { d += scaleData.scaleWidget->titleHeightForWidth( qFloor( length ) ); } if ( d > dimAxis[axis] ) { dimAxis[axis] = d; done = false; } } } } } /*! Align the ticks of the axis to the canvas borders using the empty corners. \param options Layout options \param canvasRect Geometry of the canvas ( IN/OUT ) \param scaleRect Geometries of the scales ( IN/OUT ) \sa Options */ void QwtPlotLayout::alignScales( Options options, QRectF &canvasRect, QRectF scaleRect[QwtPlot::axisCnt] ) const { int backboneOffset[QwtPlot::axisCnt]; for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { backboneOffset[axis] = 0; if ( !d_data->alignCanvasToScales[axis] ) { backboneOffset[axis] += d_data->canvasMargin[axis]; } if ( !( options & IgnoreFrames ) ) { backboneOffset[axis] += d_data->layoutData.canvas.contentsMargins[axis]; } } for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { if ( !scaleRect[axis].isValid() ) continue; const int startDist = d_data->layoutData.scale[axis].start; const int endDist = d_data->layoutData.scale[axis].end; QRectF &axisRect = scaleRect[axis]; if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom ) { const QRectF &leftScaleRect = scaleRect[QwtPlot::yLeft]; const int leftOffset = backboneOffset[QwtPlot::yLeft] - startDist; if ( leftScaleRect.isValid() ) { const double dx = leftOffset + leftScaleRect.width(); if ( d_data->alignCanvasToScales[QwtPlot::yLeft] && dx < 0.0 ) { /* The axis needs more space than the width of the left scale. */ const double cLeft = canvasRect.left(); // qreal -> double canvasRect.setLeft( qMax( cLeft, axisRect.left() - dx ) ); } else { const double minLeft = leftScaleRect.left(); const double left = axisRect.left() + leftOffset; axisRect.setLeft( qMax( left, minLeft ) ); } } else { if ( d_data->alignCanvasToScales[QwtPlot::yLeft] && leftOffset < 0 ) { canvasRect.setLeft( qMax( canvasRect.left(), axisRect.left() - leftOffset ) ); } else { if ( leftOffset > 0 ) axisRect.setLeft( axisRect.left() + leftOffset ); } } const QRectF &rightScaleRect = scaleRect[QwtPlot::yRight]; const int rightOffset = backboneOffset[QwtPlot::yRight] - endDist + 1; if ( rightScaleRect.isValid() ) { const double dx = rightOffset + rightScaleRect.width(); if ( d_data->alignCanvasToScales[QwtPlot::yRight] && dx < 0 ) { /* The axis needs more space than the width of the right scale. */ const double cRight = canvasRect.right(); // qreal -> double canvasRect.setRight( qMin( cRight, axisRect.right() + dx ) ); } const double maxRight = rightScaleRect.right(); const double right = axisRect.right() - rightOffset; axisRect.setRight( qMin( right, maxRight ) ); } else { if ( d_data->alignCanvasToScales[QwtPlot::yRight] && rightOffset < 0 ) { canvasRect.setRight( qMin( canvasRect.right(), axisRect.right() + rightOffset ) ); } else { if ( rightOffset > 0 ) axisRect.setRight( axisRect.right() - rightOffset ); } } } else // QwtPlot::yLeft, QwtPlot::yRight { const QRectF &bottomScaleRect = scaleRect[QwtPlot::xBottom]; const int bottomOffset = backboneOffset[QwtPlot::xBottom] - endDist + 1; if ( bottomScaleRect.isValid() ) { const double dy = bottomOffset + bottomScaleRect.height(); if ( d_data->alignCanvasToScales[QwtPlot::xBottom] && dy < 0 ) { /* The axis needs more space than the height of the bottom scale. */ const double cBottom = canvasRect.bottom(); // qreal -> double canvasRect.setBottom( qMin( cBottom, axisRect.bottom() + dy ) ); } else { const double maxBottom = bottomScaleRect.top() + d_data->layoutData.scale[QwtPlot::xBottom].tickOffset; const double bottom = axisRect.bottom() - bottomOffset; axisRect.setBottom( qMin( bottom, maxBottom ) ); } } else { if ( d_data->alignCanvasToScales[QwtPlot::xBottom] && bottomOffset < 0 ) { canvasRect.setBottom( qMin( canvasRect.bottom(), axisRect.bottom() + bottomOffset ) ); } else { if ( bottomOffset > 0 ) axisRect.setBottom( axisRect.bottom() - bottomOffset ); } } const QRectF &topScaleRect = scaleRect[QwtPlot::xTop]; const int topOffset = backboneOffset[QwtPlot::xTop] - startDist; if ( topScaleRect.isValid() ) { const double dy = topOffset + topScaleRect.height(); if ( d_data->alignCanvasToScales[QwtPlot::xTop] && dy < 0 ) { /* The axis needs more space than the height of the top scale. */ const double cTop = canvasRect.top(); // qreal -> double canvasRect.setTop( qMax( cTop, axisRect.top() - dy ) ); } else { const double minTop = topScaleRect.bottom() - d_data->layoutData.scale[QwtPlot::xTop].tickOffset; const double top = axisRect.top() + topOffset; axisRect.setTop( qMax( top, minTop ) ); } } else { if ( d_data->alignCanvasToScales[QwtPlot::xTop] && topOffset < 0 ) { canvasRect.setTop( qMax( canvasRect.top(), axisRect.top() - topOffset ) ); } else { if ( topOffset > 0 ) axisRect.setTop( axisRect.top() + topOffset ); } } } } /* The canvas has been aligned to the scale with largest border distances. Now we have to realign the other scale. */ for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { QRectF &sRect = scaleRect[axis]; if ( !sRect.isValid() ) continue; if ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop ) { if ( d_data->alignCanvasToScales[QwtPlot::yLeft] ) { double y = canvasRect.left() - d_data->layoutData.scale[axis].start; if ( !( options & IgnoreFrames ) ) y += d_data->layoutData.canvas.contentsMargins[ QwtPlot::yLeft ]; sRect.setLeft( y ); } if ( d_data->alignCanvasToScales[QwtPlot::yRight] ) { double y = canvasRect.right() - 1 + d_data->layoutData.scale[axis].end; if ( !( options & IgnoreFrames ) ) y -= d_data->layoutData.canvas.contentsMargins[ QwtPlot::yRight ]; sRect.setRight( y ); } if ( d_data->alignCanvasToScales[ axis ] ) { if ( axis == QwtPlot::xTop ) sRect.setBottom( canvasRect.top() ); else sRect.setTop( canvasRect.bottom() ); } } else { if ( d_data->alignCanvasToScales[QwtPlot::xTop] ) { double x = canvasRect.top() - d_data->layoutData.scale[axis].start; if ( !( options & IgnoreFrames ) ) x += d_data->layoutData.canvas.contentsMargins[ QwtPlot::xTop ]; sRect.setTop( x ); } if ( d_data->alignCanvasToScales[QwtPlot::xBottom] ) { double x = canvasRect.bottom() - 1 + d_data->layoutData.scale[axis].end; if ( !( options & IgnoreFrames ) ) x -= d_data->layoutData.canvas.contentsMargins[ QwtPlot::xBottom ]; sRect.setBottom( x ); } if ( d_data->alignCanvasToScales[ axis ] ) { if ( axis == QwtPlot::yLeft ) sRect.setRight( canvasRect.left() ); else sRect.setLeft( canvasRect.right() ); } } } } /*! \brief Recalculate the geometry of all components. \param plot Plot to be layout \param plotRect Rectangle where to place the components \param options Layout options \sa invalidate(), titleRect(), footerRect() legendRect(), scaleRect(), canvasRect() */ void QwtPlotLayout::activate( const QwtPlot *plot, const QRectF &plotRect, Options options ) { invalidate(); QRectF rect( plotRect ); // undistributed rest of the plot rect // We extract all layout relevant parameters from the widgets, // and save them to d_data->layoutData. d_data->layoutData.init( plot, rect ); if ( !( options & IgnoreLegend ) && plot->legend() && !plot->legend()->isEmpty() ) { d_data->legendRect = layoutLegend( options, rect ); // subtract d_data->legendRect from rect const QRegion region( rect.toRect() ); rect = region.subtracted( d_data->legendRect.toRect() ).boundingRect(); switch ( d_data->legendPos ) { case QwtPlot::LeftLegend: rect.setLeft( rect.left() + d_data->spacing ); break; case QwtPlot::RightLegend: rect.setRight( rect.right() - d_data->spacing ); break; case QwtPlot::TopLegend: rect.setTop( rect.top() + d_data->spacing ); break; case QwtPlot::BottomLegend: rect.setBottom( rect.bottom() - d_data->spacing ); break; } } /* +---+-----------+---+ | Title | +---+-----------+---+ | | Axis | | +---+-----------+---+ | A | | A | | x | Canvas | x | | i | | i | | s | | s | +---+-----------+---+ | | Axis | | +---+-----------+---+ | Footer | +---+-----------+---+ */ // title, footer and axes include text labels. The height of each // label depends on its line breaks, that depend on the width // for the label. A line break in a horizontal text will reduce // the available width for vertical texts and vice versa. // expandLineBreaks finds the height/width for title, footer and axes // including all line breaks. int dimTitle, dimFooter, dimAxes[QwtPlot::axisCnt]; expandLineBreaks( options, rect, dimTitle, dimFooter, dimAxes ); if ( dimTitle > 0 ) { d_data->titleRect.setRect( rect.left(), rect.top(), rect.width(), dimTitle ); rect.setTop( d_data->titleRect.bottom() + d_data->spacing ); if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled != d_data->layoutData.scale[QwtPlot::yRight].isEnabled ) { // if only one of the y axes is missing we align // the title centered to the canvas d_data->titleRect.setX( rect.left() + dimAxes[QwtPlot::yLeft] ); d_data->titleRect.setWidth( rect.width() - dimAxes[QwtPlot::yLeft] - dimAxes[QwtPlot::yRight] ); } } if ( dimFooter > 0 ) { d_data->footerRect.setRect( rect.left(), rect.bottom() - dimFooter, rect.width(), dimFooter ); rect.setBottom( d_data->footerRect.top() - d_data->spacing ); if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled != d_data->layoutData.scale[QwtPlot::yRight].isEnabled ) { // if only one of the y axes is missing we align // the footer centered to the canvas d_data->footerRect.setX( rect.left() + dimAxes[QwtPlot::yLeft] ); d_data->footerRect.setWidth( rect.width() - dimAxes[QwtPlot::yLeft] - dimAxes[QwtPlot::yRight] ); } } d_data->canvasRect.setRect( rect.x() + dimAxes[QwtPlot::yLeft], rect.y() + dimAxes[QwtPlot::xTop], rect.width() - dimAxes[QwtPlot::yRight] - dimAxes[QwtPlot::yLeft], rect.height() - dimAxes[QwtPlot::xBottom] - dimAxes[QwtPlot::xTop] ); for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) { // set the rects for the axes if ( dimAxes[axis] ) { int dim = dimAxes[axis]; QRectF &scaleRect = d_data->scaleRect[axis]; scaleRect = d_data->canvasRect; switch ( axis ) { case QwtPlot::yLeft: scaleRect.setX( d_data->canvasRect.left() - dim ); scaleRect.setWidth( dim ); break; case QwtPlot::yRight: scaleRect.setX( d_data->canvasRect.right() ); scaleRect.setWidth( dim ); break; case QwtPlot::xBottom: scaleRect.setY( d_data->canvasRect.bottom() ); scaleRect.setHeight( dim ); break; case QwtPlot::xTop: scaleRect.setY( d_data->canvasRect.top() - dim ); scaleRect.setHeight( dim ); break; } scaleRect = scaleRect.normalized(); } } // +---+-----------+---+ // | <- Axis -> | // +-^-+-----------+-^-+ // | | | | | | // | | | | // | A | | A | // | x | Canvas | x | // | i | | i | // | s | | s | // | | | | // | | | | | | // +-V-+-----------+-V-+ // | <- Axis -> | // +---+-----------+---+ // The ticks of the axes - not the labels above - should // be aligned to the canvas. So we try to use the empty // corners to extend the axes, so that the label texts // left/right of the min/max ticks are moved into them. alignScales( options, d_data->canvasRect, d_data->scaleRect ); if ( !d_data->legendRect.isEmpty() ) { // We prefer to align the legend to the canvas - not to // the complete plot - if possible. d_data->legendRect = alignLegend( d_data->canvasRect, d_data->legendRect ); } } connectome-workbench-1.4.2/src/Qwt/qwt_plot_layout.h000066400000000000000000000062241360521144700226200ustar00rootroot00000000000000/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #ifndef QWT_PLOT_LAYOUT_H #define QWT_PLOT_LAYOUT_H #include "qwt_global.h" #include "qwt_plot.h" /*! \brief Layout engine for QwtPlot. It is used by the QwtPlot widget to organize its internal widgets or by QwtPlot::print() to render its content to a QPaintDevice like a QPrinter, QPixmap/QImage or QSvgRenderer. \sa QwtPlot::setPlotLayout() */ class QWT_EXPORT QwtPlotLayout { public: /*! Options to configure the plot layout engine \sa activate(), QwtPlotRenderer */ enum Option { //! Unused AlignScales = 0x01, /*! Ignore the dimension of the scrollbars. There are no scrollbars, when the plot is not rendered to widgets. */ IgnoreScrollbars = 0x02, //! Ignore all frames. IgnoreFrames = 0x04, //! Ignore the legend. IgnoreLegend = 0x08, //! Ignore the title. IgnoreTitle = 0x10, //! Ignore the footer. IgnoreFooter = 0x20 }; //! Layout options typedef QFlags